From c16fcc47bc427dd01ed3d1c17d6483bd388bc92f Mon Sep 17 00:00:00 2001 From: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Date: Thu, 7 Mar 2024 11:11:43 +0200 Subject: [PATCH 001/187] ParaInherent create: update `apply_weight_limit` wrt elastic scaling (#3573) Changes the way we perform the random selection of backed candidates when there isn't enough room for all of them. Instead of picking individual backed candidates `apply_weight` now operates on chains of candidates. This is fully backwards compatible and relies on the node side (provisioner/prospective parachains) doing the heavy lifting and providing the candidates in the order they form a chain. The same approach can be implemented for bitfields random selection once https://github.com/paritytech/polkadot-sdk/pull/3479 is merged. The approach taken in this PR aims for reduced additional complexity at the cost of being less fair wrt how many backed candidates from each chain are picked. It favors elastic scaling parachains vs parachains not using elastic scaling, but from my perspective it should be fine as this should happen under exceptional circumstances like dispute storms. Note: to make things more fair we can consider specializing `random_sel` such that it will try to pick candidates one by one in the order provided by the provisioner such that non elastic scaling parachains have the same chance of getting a candidate backed. --------- Signed-off-by: Andrei Sandu --- .../parachains/src/paras_inherent/mod.rs | 64 +++++++-- .../parachains/src/paras_inherent/tests.rs | 125 +++++++++++++++++- 2 files changed, 174 insertions(+), 15 deletions(-) diff --git a/polkadot/runtime/parachains/src/paras_inherent/mod.rs b/polkadot/runtime/parachains/src/paras_inherent/mod.rs index cebf858c24a..723a15bdba7 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/mod.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/mod.rs @@ -788,7 +788,7 @@ fn random_sel Weight>( /// Assumes disputes are already filtered by the time this is called. /// /// Returns the total weight consumed by `bitfields` and `candidates`. -fn apply_weight_limit( +pub(crate) fn apply_weight_limit( candidates: &mut Vec::Hash>>, bitfields: &mut UncheckedSignedAvailabilityBitfields, max_consumable_weight: Weight, @@ -805,35 +805,71 @@ fn apply_weight_limit( return total } - // Prefer code upgrades, they tend to be large and hence stand no chance to be picked - // late while maintaining the weight bounds. - let preferred_indices = candidates + // Invariant: block author provides candidate in the order in which they form a chain + // wrt elastic scaling. If the invariant is broken, we'd fail later when filtering candidates + // which are unchained. + + let mut chained_candidates: Vec> = Vec::new(); + let mut current_para_id = None; + + for candidate in sp_std::mem::take(candidates).into_iter() { + let candidate_para_id = candidate.descriptor().para_id; + if Some(candidate_para_id) == current_para_id { + let chain = chained_candidates + .last_mut() + .expect("if the current_para_id is Some, then vec is not empty; qed"); + chain.push(candidate); + } else { + current_para_id = Some(candidate_para_id); + chained_candidates.push(vec![candidate]); + } + } + + // Elastic scaling: we prefer chains that have a code upgrade among the candidates, + // as the candidates containing the upgrade tend to be large and hence stand no chance to + // be picked late while maintaining the weight bounds. + // + // Limitations: For simplicity if total weight of a chain of candidates is larger than + // the remaining weight, the chain will still not be included while it could still be possible + // to include part of that chain. + let preferred_chain_indices = chained_candidates .iter() .enumerate() - .filter_map(|(idx, candidate)| { - candidate.candidate().commitments.new_validation_code.as_ref().map(|_code| idx) + .filter_map(|(idx, candidates)| { + // Check if any of the candidate in chain contains a code upgrade. + if candidates + .iter() + .any(|candidate| candidate.candidate().commitments.new_validation_code.is_some()) + { + Some(idx) + } else { + None + } }) .collect::>(); - // There is weight remaining to be consumed by a subset of candidates + // There is weight remaining to be consumed by a subset of chained candidates // which are going to be picked now. if let Some(max_consumable_by_candidates) = max_consumable_weight.checked_sub(&total_bitfields_weight) { - let (acc_candidate_weight, indices) = - random_sel::::Hash>, _>( + let (acc_candidate_weight, chained_indices) = + random_sel::::Hash>>, _>( rng, - &candidates, - preferred_indices, - |c| backed_candidate_weight::(c), + &chained_candidates, + preferred_chain_indices, + |candidates| backed_candidates_weight::(&candidates), max_consumable_by_candidates, ); - log::debug!(target: LOG_TARGET, "Indices Candidates: {:?}, size: {}", indices, candidates.len()); - candidates.indexed_retain(|idx, _backed_candidate| indices.binary_search(&idx).is_ok()); + log::debug!(target: LOG_TARGET, "Indices Candidates: {:?}, size: {}", chained_indices, candidates.len()); + chained_candidates + .indexed_retain(|idx, _backed_candidates| chained_indices.binary_search(&idx).is_ok()); // pick all bitfields, and // fill the remaining space with candidates let total_consumed = acc_candidate_weight.saturating_add(total_bitfields_weight); + *candidates = chained_candidates.into_iter().flatten().collect::>(); + return total_consumed } diff --git a/polkadot/runtime/parachains/src/paras_inherent/tests.rs b/polkadot/runtime/parachains/src/paras_inherent/tests.rs index b7285ec884a..fb4d1bd2226 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/tests.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/tests.rs @@ -22,7 +22,7 @@ use super::*; #[cfg(not(feature = "runtime-benchmarks"))] mod enter { - use super::*; + use super::{inclusion::tests::TestCandidateBuilder, *}; use crate::{ builder::{Bench, BenchBuilder}, mock::{mock_assigner, new_test_ext, BlockLength, BlockWeights, MockGenesisConfig, Test}, @@ -925,6 +925,129 @@ mod enter { }); } + // Helper fn that builds chained dummy candidates for elastic scaling tests + fn build_backed_candidate_chain( + para_id: ParaId, + len: usize, + start_core_index: usize, + code_upgrade_index: Option, + ) -> Vec { + if let Some(code_upgrade_index) = code_upgrade_index { + assert!(code_upgrade_index < len, "Code upgrade index out of bounds"); + } + + (0..len) + .into_iter() + .map(|idx| { + let mut builder = TestCandidateBuilder::default(); + builder.para_id = para_id; + let mut ccr = builder.build(); + + if Some(idx) == code_upgrade_index { + ccr.commitments.new_validation_code = Some(vec![1, 2, 3, 4].into()); + } + + ccr.commitments.processed_downward_messages = idx as u32; + let core_index = start_core_index + idx; + + BackedCandidate::new( + ccr.into(), + Default::default(), + Default::default(), + Some(CoreIndex(core_index as u32)), + ) + }) + .collect::>() + } + + // Ensure that overweight parachain inherents are always rejected by the runtime. + // Runtime should panic and return `InherentOverweight` error. + #[test] + fn test_backed_candidates_apply_weight_works_for_elastic_scaling() { + new_test_ext(MockGenesisConfig::default()).execute_with(|| { + let seed = [ + 1, 0, 52, 0, 0, 0, 0, 0, 1, 0, 10, 0, 22, 32, 0, 0, 2, 0, 55, 49, 0, 11, 0, 0, 3, + 0, 0, 0, 0, 0, 2, 92, + ]; + let mut rng = rand_chacha::ChaChaRng::from_seed(seed); + + // Create an overweight inherent and oversized block + let mut backed_and_concluding = BTreeMap::new(); + + for i in 0..30 { + backed_and_concluding.insert(i, i); + } + + let scenario = make_inherent_data(TestConfig { + dispute_statements: Default::default(), + dispute_sessions: vec![], // 3 cores with disputes + backed_and_concluding, + num_validators_per_core: 5, + code_upgrade: None, + fill_claimqueue: false, + }); + + let mut para_inherent_data = scenario.data.clone(); + + // Check the para inherent data is as expected: + // * 1 bitfield per validator (5 validators per core, 30 backed candidates, 0 disputes + // => 5*30 = 150) + assert_eq!(para_inherent_data.bitfields.len(), 150); + // * 30 backed candidates + assert_eq!(para_inherent_data.backed_candidates.len(), 30); + + let mut input_candidates = + build_backed_candidate_chain(ParaId::from(1000), 3, 0, Some(1)); + let chained_candidates_weight = backed_candidates_weight::(&input_candidates); + + input_candidates.append(&mut para_inherent_data.backed_candidates); + let input_bitfields = para_inherent_data.bitfields; + + // Test if weight insufficient even for 1 candidate (which doesn't contain a code + // upgrade). + let max_weight = backed_candidate_weight::(&input_candidates[0]) + + signed_bitfields_weight::(&input_bitfields); + let mut backed_candidates = input_candidates.clone(); + let mut bitfields = input_bitfields.clone(); + apply_weight_limit::( + &mut backed_candidates, + &mut bitfields, + max_weight, + &mut rng, + ); + + // The chained candidates are not picked, instead a single other candidate is picked + assert_eq!(backed_candidates.len(), 1); + assert_ne!(backed_candidates[0].descriptor().para_id, ParaId::from(1000)); + + // All bitfields are kept. + assert_eq!(bitfields.len(), 150); + + // Test if para_id 1000 chained candidates make it if there is enough room for its 3 + // candidates. + let max_weight = + chained_candidates_weight + signed_bitfields_weight::(&input_bitfields); + let mut backed_candidates = input_candidates.clone(); + let mut bitfields = input_bitfields.clone(); + apply_weight_limit::( + &mut backed_candidates, + &mut bitfields, + max_weight, + &mut rng, + ); + + // Only the chained candidates should pass filter. + assert_eq!(backed_candidates.len(), 3); + // Check the actual candidates + assert_eq!(backed_candidates[0].descriptor().para_id, ParaId::from(1000)); + assert_eq!(backed_candidates[1].descriptor().para_id, ParaId::from(1000)); + assert_eq!(backed_candidates[2].descriptor().para_id, ParaId::from(1000)); + + // All bitfields are kept. + assert_eq!(bitfields.len(), 150); + }); + } + // Ensure that overweight parachain inherents are always rejected by the runtime. // Runtime should panic and return `InherentOverweight` error. #[test] -- GitLab From 11831df8e709061e9c6b3292facb5d7d9709f151 Mon Sep 17 00:00:00 2001 From: Dastan <88332432+dastansam@users.noreply.github.com> Date: Thu, 7 Mar 2024 11:36:30 +0100 Subject: [PATCH 002/187] `nomination-pools`: add permissionless condition to `chill` (#3453) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, pool member funds cannot be unbonded if the depositor's stake is less than `MinNominatorBond`. This usually happens after `T::MinNominatorBond` is increased. To fix this, the above mentioned condition is added as a case for permissionless dispatch of `chill`. After pool is chilled, pool members can unbond their funds since pool won't be nominating anymore. Consequently, same check is added to `nominate` call, i.e pool can not start nominating if it's depositor does not have `MinNominatorBond` cc @Ank4n @kianenigma closes #2350 Polkadot address: 16FqwPZ8GRC5U5D4Fu7W33nA55ZXzXGWHwmbnE1eT6pxuqcT --------- Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> Co-authored-by: Gonçalo Pestana Co-authored-by: command-bot <> --- prdoc/pr_3453.prdoc | 13 + substrate/frame/nomination-pools/src/lib.rs | 39 ++- substrate/frame/nomination-pools/src/tests.rs | 42 +++ .../frame/nomination-pools/src/weights.rs | 268 ++++++++++-------- .../nomination-pools/test-staking/src/lib.rs | 133 ++++++++- 5 files changed, 367 insertions(+), 128 deletions(-) create mode 100644 prdoc/pr_3453.prdoc diff --git a/prdoc/pr_3453.prdoc b/prdoc/pr_3453.prdoc new file mode 100644 index 00000000000..1f01440f722 --- /dev/null +++ b/prdoc/pr_3453.prdoc @@ -0,0 +1,13 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "[pallet-nomination-pools]: `chill` is permissionless if depositor's stake is less than `min_nominator_bond`" + +doc: + - audience: Runtime Dev + description: | + Nomination pools currently have an issue whereby member funds cannot be unbonded if the depositor bonded amount is less than `MinNominatorBond`. + This PR makes the `chill` function permissionless if this condition is met. + Consequently, `nominate` function also checks for `depositor` to have at least `MinNominatorBond`, and returns `MinimumBondNotMet` error if not. +crates: + - name: pallet-nomination-pools diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs index c64db9ed692..a0dbdb3aaa4 100644 --- a/substrate/frame/nomination-pools/src/lib.rs +++ b/substrate/frame/nomination-pools/src/lib.rs @@ -2401,6 +2401,11 @@ pub mod pallet { /// /// This directly forward the call to the staking pallet, on behalf of the pool bonded /// account. + /// + /// # Note + /// + /// In addition to a `root` or `nominator` role of `origin`, pool's depositor needs to have + /// at least `depositor_min_bond` in the pool to start nominating. #[pallet::call_index(8)] #[pallet::weight(T::WeightInfo::nominate(validators.len() as u32))] pub fn nominate( @@ -2411,6 +2416,16 @@ pub mod pallet { let who = ensure_signed(origin)?; let bonded_pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; ensure!(bonded_pool.can_nominate(&who), Error::::NotNominator); + + let depositor_points = PoolMembers::::get(&bonded_pool.roles.depositor) + .ok_or(Error::::PoolMemberNotFound)? + .active_points(); + + ensure!( + bonded_pool.points_to_balance(depositor_points) >= Self::depositor_min_bond(), + Error::::MinimumBondNotMet + ); + T::Staking::nominate(&bonded_pool.bonded_account(), validators) } @@ -2573,17 +2588,37 @@ pub mod pallet { /// Chill on behalf of the pool. /// - /// The dispatch origin of this call must be signed by the pool nominator or the pool + /// The dispatch origin of this call can be signed by the pool nominator or the pool /// root role, same as [`Pallet::nominate`]. /// + /// Under certain conditions, this call can be dispatched permissionlessly (i.e. by any + /// account). + /// + /// # Conditions for a permissionless dispatch: + /// * When pool depositor has less than `MinNominatorBond` staked, otherwise pool members + /// are unable to unbond. + /// + /// # Conditions for permissioned dispatch: + /// * The caller has a nominator or root role of the pool. /// This directly forward the call to the staking pallet, on behalf of the pool bonded /// account. #[pallet::call_index(13)] #[pallet::weight(T::WeightInfo::chill())] pub fn chill(origin: OriginFor, pool_id: PoolId) -> DispatchResult { let who = ensure_signed(origin)?; + let bonded_pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; - ensure!(bonded_pool.can_nominate(&who), Error::::NotNominator); + + let depositor_points = PoolMembers::::get(&bonded_pool.roles.depositor) + .ok_or(Error::::PoolMemberNotFound)? + .active_points(); + + if bonded_pool.points_to_balance(depositor_points) >= + T::Staking::minimum_nominator_bond() + { + ensure!(bonded_pool.can_nominate(&who), Error::::NotNominator); + } + T::Staking::chill(&bonded_pool.bonded_account()) } diff --git a/substrate/frame/nomination-pools/src/tests.rs b/substrate/frame/nomination-pools/src/tests.rs index 13298fa64f5..8fb2b41b88a 100644 --- a/substrate/frame/nomination-pools/src/tests.rs +++ b/substrate/frame/nomination-pools/src/tests.rs @@ -4848,6 +4848,18 @@ mod nominate { Error::::NotNominator ); + // if `depositor` stake is less than the `MinimumNominatorBond`, they can't nominate + StakingMinBond::set(20); + + // Can't nominate if depositor's stake is less than the `MinimumNominatorBond` + assert_noop!( + Pools::nominate(RuntimeOrigin::signed(900), 1, vec![21]), + Error::::MinimumBondNotMet + ); + + // restore `MinimumNominatorBond` + StakingMinBond::set(10); + // Root can nominate assert_ok!(Pools::nominate(RuntimeOrigin::signed(900), 1, vec![21])); assert_eq!(Nominations::get().unwrap(), vec![21]); @@ -7338,3 +7350,33 @@ mod slash { }); } } + +mod chill { + use super::*; + + #[test] + fn chill_works() { + ExtBuilder::default().build_and_execute(|| { + // only nominator or root can chill + assert_noop!( + Pools::chill(RuntimeOrigin::signed(10), 1), + Error::::NotNominator + ); + + // root can chill and re-nominate + assert_ok!(Pools::chill(RuntimeOrigin::signed(900), 1)); + assert_ok!(Pools::nominate(RuntimeOrigin::signed(900), 1, vec![31])); + + // nominator can chill and re-nominate + assert_ok!(Pools::chill(RuntimeOrigin::signed(901), 1)); + assert_ok!(Pools::nominate(RuntimeOrigin::signed(901), 1, vec![31])); + + // if `depositor` stake is less than the `MinimumNominatorBond`, then this call + // becomes permissionless; + StakingMinBond::set(20); + + // any account can chill + assert_ok!(Pools::chill(RuntimeOrigin::signed(10), 1)); + }) + } +} diff --git a/substrate/frame/nomination-pools/src/weights.rs b/substrate/frame/nomination-pools/src/weights.rs index 2749af7937f..987ddd71703 100644 --- a/substrate/frame/nomination-pools/src/weights.rs +++ b/substrate/frame/nomination-pools/src/weights.rs @@ -18,27 +18,25 @@ //! Autogenerated weights for `pallet_nomination_pools` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-03-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-p5qp1txx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/production/substrate-node +// target/production/substrate-node // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_nomination_pools -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/nomination-pools/src/weights.rs +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_nomination_pools +// --chain=dev // --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/nomination-pools/src/weights.rs // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -114,8 +112,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3425` // Estimated: `8877` - // Minimum execution time: 181_861_000 picoseconds. - Weight::from_parts(186_375_000, 8877) + // Minimum execution time: 182_643_000 picoseconds. + Weight::from_parts(186_106_000, 8877) .saturating_add(T::DbWeight::get().reads(20_u64)) .saturating_add(T::DbWeight::get().writes(13_u64)) } @@ -147,8 +145,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3435` // Estimated: `8877` - // Minimum execution time: 182_273_000 picoseconds. - Weight::from_parts(186_635_000, 8877) + // Minimum execution time: 181_464_000 picoseconds. + Weight::from_parts(184_672_000, 8877) .saturating_add(T::DbWeight::get().reads(17_u64)) .saturating_add(T::DbWeight::get().writes(13_u64)) } @@ -182,8 +180,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3500` // Estimated: `8877` - // Minimum execution time: 217_878_000 picoseconds. - Weight::from_parts(221_493_000, 8877) + // Minimum execution time: 216_182_000 picoseconds. + Weight::from_parts(218_448_000, 8877) .saturating_add(T::DbWeight::get().reads(18_u64)) .saturating_add(T::DbWeight::get().writes(14_u64)) } @@ -203,8 +201,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1172` // Estimated: `3719` - // Minimum execution time: 74_509_000 picoseconds. - Weight::from_parts(76_683_000, 3719) + // Minimum execution time: 73_830_000 picoseconds. + Weight::from_parts(75_271_000, 3719) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -244,8 +242,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3622` // Estimated: `27847` - // Minimum execution time: 166_424_000 picoseconds. - Weight::from_parts(169_698_000, 27847) + // Minimum execution time: 166_099_000 picoseconds. + Weight::from_parts(170_355_000, 27847) .saturating_add(T::DbWeight::get().reads(20_u64)) .saturating_add(T::DbWeight::get().writes(13_u64)) } @@ -270,10 +268,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1848` // Estimated: `4764` - // Minimum execution time: 66_110_000 picoseconds. - Weight::from_parts(68_620_141, 4764) - // Standard Error: 1_379 - .saturating_add(Weight::from_parts(54_961, 0).saturating_mul(s.into())) + // Minimum execution time: 64_787_000 picoseconds. + Weight::from_parts(67_920_914, 4764) + // Standard Error: 1_482 + .saturating_add(Weight::from_parts(43_264, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -308,10 +306,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2238` // Estimated: `27847` - // Minimum execution time: 125_669_000 picoseconds. - Weight::from_parts(130_907_641, 27847) - // Standard Error: 2_490 - .saturating_add(Weight::from_parts(75_219, 0).saturating_mul(s.into())) + // Minimum execution time: 124_990_000 picoseconds. + Weight::from_parts(129_041_398, 27847) + // Standard Error: 2_335 + .saturating_add(Weight::from_parts(67_889, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(9_u64)) } @@ -362,12 +360,14 @@ impl WeightInfo for SubstrateWeight { /// Storage: `NominationPools::ClaimPermissions` (r:0 w:1) /// Proof: `NominationPools::ClaimPermissions` (`max_values`: None, `max_size`: Some(41), added: 2516, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. - fn withdraw_unbonded_kill(_s: u32, ) -> Weight { + fn withdraw_unbonded_kill(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `2525` // Estimated: `27847` - // Minimum execution time: 225_700_000 picoseconds. - Weight::from_parts(234_390_990, 27847) + // Minimum execution time: 221_955_000 picoseconds. + Weight::from_parts(230_244_437, 27847) + // Standard Error: 4_059 + .saturating_add(Weight::from_parts(7_522, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(24_u64)) .saturating_add(T::DbWeight::get().writes(20_u64)) } @@ -419,19 +419,25 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1169` // Estimated: `8538` - // Minimum execution time: 167_171_000 picoseconds. - Weight::from_parts(170_531_000, 8538) + // Minimum execution time: 165_358_000 picoseconds. + Weight::from_parts(169_683_000, 8538) .saturating_add(T::DbWeight::get().reads(23_u64)) .saturating_add(T::DbWeight::get().writes(17_u64)) } /// Storage: `NominationPools::BondedPools` (r:1 w:0) /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::PoolMembers` (r:1 w:0) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::MinNominatorBond` (r:1 w:0) /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MinCreateBond` (r:1 w:0) + /// Proof: `NominationPools::MinCreateBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MinJoinBond` (r:1 w:0) + /// Proof: `NominationPools::MinJoinBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxNominatorsCount` (r:1 w:0) @@ -451,13 +457,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1808` + // Measured: `1976` // Estimated: `4556 + n * (2520 ±0)` - // Minimum execution time: 63_785_000 picoseconds. - Weight::from_parts(64_592_302, 4556) - // Standard Error: 9_416 - .saturating_add(Weight::from_parts(1_524_398, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(12_u64)) + // Minimum execution time: 74_483_000 picoseconds. + Weight::from_parts(76_611_288, 4556) + // Standard Error: 9_013 + .saturating_add(Weight::from_parts(1_475_128, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(15_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(5_u64)) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(n.into())) @@ -472,8 +478,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1434` // Estimated: `4556` - // Minimum execution time: 32_096_000 picoseconds. - Weight::from_parts(33_533_000, 4556) + // Minimum execution time: 32_598_000 picoseconds. + Weight::from_parts(33_350_000, 4556) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -488,10 +494,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `532` // Estimated: `3735` - // Minimum execution time: 13_914_000 picoseconds. - Weight::from_parts(14_800_402, 3735) - // Standard Error: 146 - .saturating_add(Weight::from_parts(940, 0).saturating_mul(n.into())) + // Minimum execution time: 13_705_000 picoseconds. + Weight::from_parts(14_594_211, 3735) + // Standard Error: 141 + .saturating_add(Weight::from_parts(2_119, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -511,8 +517,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_373_000 picoseconds. - Weight::from_parts(4_592_000, 0) + // Minimum execution time: 4_222_000 picoseconds. + Weight::from_parts(4_527_000, 0) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: `NominationPools::BondedPools` (r:1 w:1) @@ -521,17 +527,21 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `532` // Estimated: `3719` - // Minimum execution time: 16_662_000 picoseconds. - Weight::from_parts(17_531_000, 3719) + // Minimum execution time: 16_106_000 picoseconds. + Weight::from_parts(17_365_000, 3719) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `NominationPools::BondedPools` (r:1 w:0) /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::PoolMembers` (r:1 w:0) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::MinNominatorBond` (r:1 w:0) + /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) @@ -546,11 +556,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `1971` + // Measured: `2143` // Estimated: `4556` - // Minimum execution time: 61_348_000 picoseconds. - Weight::from_parts(63_712_000, 4556) - .saturating_add(T::DbWeight::get().reads(9_u64)) + // Minimum execution time: 71_301_000 picoseconds. + Weight::from_parts(73_626_000, 4556) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `NominationPools::BondedPools` (r:1 w:1) @@ -565,8 +575,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `804` // Estimated: `3719` - // Minimum execution time: 32_232_000 picoseconds. - Weight::from_parts(33_433_000, 3719) + // Minimum execution time: 32_363_000 picoseconds. + Weight::from_parts(33_400_000, 3719) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -578,8 +588,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `572` // Estimated: `3719` - // Minimum execution time: 16_774_000 picoseconds. - Weight::from_parts(17_671_000, 3719) + // Minimum execution time: 16_686_000 picoseconds. + Weight::from_parts(17_294_000, 3719) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -589,8 +599,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `532` // Estimated: `3719` - // Minimum execution time: 16_724_000 picoseconds. - Weight::from_parts(17_181_000, 3719) + // Minimum execution time: 16_417_000 picoseconds. + Weight::from_parts(17_028_000, 3719) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -600,8 +610,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `532` // Estimated: `3719` - // Minimum execution time: 16_362_000 picoseconds. - Weight::from_parts(17_135_000, 3719) + // Minimum execution time: 16_350_000 picoseconds. + Weight::from_parts(16_905_000, 3719) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -613,8 +623,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `542` // Estimated: `3702` - // Minimum execution time: 14_125_000 picoseconds. - Weight::from_parts(14_705_000, 3702) + // Minimum execution time: 14_081_000 picoseconds. + Weight::from_parts(14_608_000, 3702) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -630,8 +640,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1002` // Estimated: `3719` - // Minimum execution time: 61_699_000 picoseconds. - Weight::from_parts(63_605_000, 3719) + // Minimum execution time: 62_178_000 picoseconds. + Weight::from_parts(64_039_000, 3719) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -647,8 +657,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `901` // Estimated: `4764` - // Minimum execution time: 64_930_000 picoseconds. - Weight::from_parts(66_068_000, 4764) + // Minimum execution time: 64_880_000 picoseconds. + Weight::from_parts(66_541_000, 4764) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -692,8 +702,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3425` // Estimated: `8877` - // Minimum execution time: 181_861_000 picoseconds. - Weight::from_parts(186_375_000, 8877) + // Minimum execution time: 182_643_000 picoseconds. + Weight::from_parts(186_106_000, 8877) .saturating_add(RocksDbWeight::get().reads(20_u64)) .saturating_add(RocksDbWeight::get().writes(13_u64)) } @@ -725,8 +735,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3435` // Estimated: `8877` - // Minimum execution time: 182_273_000 picoseconds. - Weight::from_parts(186_635_000, 8877) + // Minimum execution time: 181_464_000 picoseconds. + Weight::from_parts(184_672_000, 8877) .saturating_add(RocksDbWeight::get().reads(17_u64)) .saturating_add(RocksDbWeight::get().writes(13_u64)) } @@ -760,8 +770,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3500` // Estimated: `8877` - // Minimum execution time: 217_878_000 picoseconds. - Weight::from_parts(221_493_000, 8877) + // Minimum execution time: 216_182_000 picoseconds. + Weight::from_parts(218_448_000, 8877) .saturating_add(RocksDbWeight::get().reads(18_u64)) .saturating_add(RocksDbWeight::get().writes(14_u64)) } @@ -781,8 +791,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1172` // Estimated: `3719` - // Minimum execution time: 74_509_000 picoseconds. - Weight::from_parts(76_683_000, 3719) + // Minimum execution time: 73_830_000 picoseconds. + Weight::from_parts(75_271_000, 3719) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -822,8 +832,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3622` // Estimated: `27847` - // Minimum execution time: 166_424_000 picoseconds. - Weight::from_parts(169_698_000, 27847) + // Minimum execution time: 166_099_000 picoseconds. + Weight::from_parts(170_355_000, 27847) .saturating_add(RocksDbWeight::get().reads(20_u64)) .saturating_add(RocksDbWeight::get().writes(13_u64)) } @@ -848,10 +858,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1848` // Estimated: `4764` - // Minimum execution time: 66_110_000 picoseconds. - Weight::from_parts(68_620_141, 4764) - // Standard Error: 1_379 - .saturating_add(Weight::from_parts(54_961, 0).saturating_mul(s.into())) + // Minimum execution time: 64_787_000 picoseconds. + Weight::from_parts(67_920_914, 4764) + // Standard Error: 1_482 + .saturating_add(Weight::from_parts(43_264, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -886,10 +896,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2238` // Estimated: `27847` - // Minimum execution time: 125_669_000 picoseconds. - Weight::from_parts(130_907_641, 27847) - // Standard Error: 2_490 - .saturating_add(Weight::from_parts(75_219, 0).saturating_mul(s.into())) + // Minimum execution time: 124_990_000 picoseconds. + Weight::from_parts(129_041_398, 27847) + // Standard Error: 2_335 + .saturating_add(Weight::from_parts(67_889, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(9_u64)) } @@ -940,12 +950,14 @@ impl WeightInfo for () { /// Storage: `NominationPools::ClaimPermissions` (r:0 w:1) /// Proof: `NominationPools::ClaimPermissions` (`max_values`: None, `max_size`: Some(41), added: 2516, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. - fn withdraw_unbonded_kill(_s: u32, ) -> Weight { + fn withdraw_unbonded_kill(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `2525` // Estimated: `27847` - // Minimum execution time: 225_700_000 picoseconds. - Weight::from_parts(234_390_990, 27847) + // Minimum execution time: 221_955_000 picoseconds. + Weight::from_parts(230_244_437, 27847) + // Standard Error: 4_059 + .saturating_add(Weight::from_parts(7_522, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(24_u64)) .saturating_add(RocksDbWeight::get().writes(20_u64)) } @@ -997,19 +1009,25 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1169` // Estimated: `8538` - // Minimum execution time: 167_171_000 picoseconds. - Weight::from_parts(170_531_000, 8538) + // Minimum execution time: 165_358_000 picoseconds. + Weight::from_parts(169_683_000, 8538) .saturating_add(RocksDbWeight::get().reads(23_u64)) .saturating_add(RocksDbWeight::get().writes(17_u64)) } /// Storage: `NominationPools::BondedPools` (r:1 w:0) /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::PoolMembers` (r:1 w:0) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::MinNominatorBond` (r:1 w:0) /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MinCreateBond` (r:1 w:0) + /// Proof: `NominationPools::MinCreateBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::MinJoinBond` (r:1 w:0) + /// Proof: `NominationPools::MinJoinBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxNominatorsCount` (r:1 w:0) @@ -1029,13 +1047,13 @@ impl WeightInfo for () { /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1808` + // Measured: `1976` // Estimated: `4556 + n * (2520 ±0)` - // Minimum execution time: 63_785_000 picoseconds. - Weight::from_parts(64_592_302, 4556) - // Standard Error: 9_416 - .saturating_add(Weight::from_parts(1_524_398, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(12_u64)) + // Minimum execution time: 74_483_000 picoseconds. + Weight::from_parts(76_611_288, 4556) + // Standard Error: 9_013 + .saturating_add(Weight::from_parts(1_475_128, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(15_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(5_u64)) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(n.into())) @@ -1050,8 +1068,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1434` // Estimated: `4556` - // Minimum execution time: 32_096_000 picoseconds. - Weight::from_parts(33_533_000, 4556) + // Minimum execution time: 32_598_000 picoseconds. + Weight::from_parts(33_350_000, 4556) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1066,10 +1084,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `532` // Estimated: `3735` - // Minimum execution time: 13_914_000 picoseconds. - Weight::from_parts(14_800_402, 3735) - // Standard Error: 146 - .saturating_add(Weight::from_parts(940, 0).saturating_mul(n.into())) + // Minimum execution time: 13_705_000 picoseconds. + Weight::from_parts(14_594_211, 3735) + // Standard Error: 141 + .saturating_add(Weight::from_parts(2_119, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1089,8 +1107,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_373_000 picoseconds. - Weight::from_parts(4_592_000, 0) + // Minimum execution time: 4_222_000 picoseconds. + Weight::from_parts(4_527_000, 0) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: `NominationPools::BondedPools` (r:1 w:1) @@ -1099,17 +1117,21 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `532` // Estimated: `3719` - // Minimum execution time: 16_662_000 picoseconds. - Weight::from_parts(17_531_000, 3719) + // Minimum execution time: 16_106_000 picoseconds. + Weight::from_parts(17_365_000, 3719) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `NominationPools::BondedPools` (r:1 w:0) /// Proof: `NominationPools::BondedPools` (`max_values`: None, `max_size`: Some(254), added: 2729, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::PoolMembers` (r:1 w:0) + /// Proof: `NominationPools::PoolMembers` (`max_values`: None, `max_size`: Some(237), added: 2712, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::MinNominatorBond` (r:1 w:0) + /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) @@ -1124,11 +1146,11 @@ impl WeightInfo for () { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `1971` + // Measured: `2143` // Estimated: `4556` - // Minimum execution time: 61_348_000 picoseconds. - Weight::from_parts(63_712_000, 4556) - .saturating_add(RocksDbWeight::get().reads(9_u64)) + // Minimum execution time: 71_301_000 picoseconds. + Weight::from_parts(73_626_000, 4556) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `NominationPools::BondedPools` (r:1 w:1) @@ -1143,8 +1165,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `804` // Estimated: `3719` - // Minimum execution time: 32_232_000 picoseconds. - Weight::from_parts(33_433_000, 3719) + // Minimum execution time: 32_363_000 picoseconds. + Weight::from_parts(33_400_000, 3719) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1156,8 +1178,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `572` // Estimated: `3719` - // Minimum execution time: 16_774_000 picoseconds. - Weight::from_parts(17_671_000, 3719) + // Minimum execution time: 16_686_000 picoseconds. + Weight::from_parts(17_294_000, 3719) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1167,8 +1189,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `532` // Estimated: `3719` - // Minimum execution time: 16_724_000 picoseconds. - Weight::from_parts(17_181_000, 3719) + // Minimum execution time: 16_417_000 picoseconds. + Weight::from_parts(17_028_000, 3719) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1178,8 +1200,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `532` // Estimated: `3719` - // Minimum execution time: 16_362_000 picoseconds. - Weight::from_parts(17_135_000, 3719) + // Minimum execution time: 16_350_000 picoseconds. + Weight::from_parts(16_905_000, 3719) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1191,8 +1213,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `542` // Estimated: `3702` - // Minimum execution time: 14_125_000 picoseconds. - Weight::from_parts(14_705_000, 3702) + // Minimum execution time: 14_081_000 picoseconds. + Weight::from_parts(14_608_000, 3702) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1208,8 +1230,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1002` // Estimated: `3719` - // Minimum execution time: 61_699_000 picoseconds. - Weight::from_parts(63_605_000, 3719) + // Minimum execution time: 62_178_000 picoseconds. + Weight::from_parts(64_039_000, 3719) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1225,8 +1247,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `901` // Estimated: `4764` - // Minimum execution time: 64_930_000 picoseconds. - Weight::from_parts(66_068_000, 4764) + // Minimum execution time: 64_880_000 picoseconds. + Weight::from_parts(66_541_000, 4764) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/substrate/frame/nomination-pools/test-staking/src/lib.rs b/substrate/frame/nomination-pools/test-staking/src/lib.rs index 865b7a71e68..98bff537c90 100644 --- a/substrate/frame/nomination-pools/test-staking/src/lib.rs +++ b/substrate/frame/nomination-pools/test-staking/src/lib.rs @@ -22,10 +22,12 @@ mod mock; use frame_support::{assert_noop, assert_ok, traits::Currency}; use mock::*; use pallet_nomination_pools::{ - BondedPools, Error as PoolsError, Event as PoolsEvent, LastPoolId, PoolMember, PoolMembers, - PoolState, + BondExtra, BondedPools, Error as PoolsError, Event as PoolsEvent, LastPoolId, PoolMember, + PoolMembers, PoolState, +}; +use pallet_staking::{ + CurrentEra, Error as StakingError, Event as StakingEvent, Payee, RewardDestination, }; -use pallet_staking::{CurrentEra, Event as StakingEvent, Payee, RewardDestination}; use sp_runtime::{bounded_btree_map, traits::Zero}; #[test] @@ -191,6 +193,131 @@ fn pool_lifecycle_e2e() { }) } +#[test] +fn pool_chill_e2e() { + new_test_ext().execute_with(|| { + assert_eq!(Balances::minimum_balance(), 5); + assert_eq!(Staking::current_era(), None); + + // create the pool, we know this has id 1. + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); + assert_eq!(LastPoolId::::get(), 1); + + // have the pool nominate. + assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Created { depositor: 10, pool_id: 1 }, + PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true }, + ] + ); + + // have two members join + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(21), 10, 1)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, + ] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true }, + PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 10, joined: true }, + ] + ); + + // in case depositor does not have more than `MinNominatorBond` staked, we can end up in + // situation where a member unbonding would cause pool balance to drop below + // `MinNominatorBond` and hence not allowed. This can happen if the `MinNominatorBond` is + // increased after the pool is created. + assert_ok!(Staking::set_staking_configs( + RuntimeOrigin::root(), + pallet_staking::ConfigOp::Set(55), // minimum nominator bond + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + )); + + // members can unbond as long as total stake of the pool is above min nominator bond + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10),); + assert_eq!(PoolMembers::::get(20).unwrap().unbonding_eras.len(), 1); + assert_eq!(PoolMembers::::get(20).unwrap().points, 0); + + // this member cannot unbond since it will cause `pool stake < MinNominatorBond` + assert_noop!( + Pools::unbond(RuntimeOrigin::signed(21), 21, 10), + StakingError::::InsufficientBond, + ); + + // members can call `chill` permissionlessly now + assert_ok!(Pools::chill(RuntimeOrigin::signed(20), 1)); + + // now another member can unbond. + assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); + assert_eq!(PoolMembers::::get(21).unwrap().unbonding_eras.len(), 1); + assert_eq!(PoolMembers::::get(21).unwrap().points, 0); + + // nominator can not resume nomination until depositor have enough stake + assert_noop!( + Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]), + PoolsError::::MinimumBondNotMet, + ); + + // other members joining pool does not affect the depositor's ability to resume nomination + assert_ok!(Pools::join(RuntimeOrigin::signed(22), 10, 1)); + + assert_noop!( + Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]), + PoolsError::::MinimumBondNotMet, + ); + + // depositor can bond extra stake + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10))); + + // `chill` can not be called permissionlessly anymore + assert_noop!( + Pools::chill(RuntimeOrigin::signed(20), 1), + PoolsError::::NotNominator, + ); + + // now nominator can resume nomination + assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); + + // skip to make the unbonding period end. + CurrentEra::::set(Some(BondingDuration::get())); + + // members can now withdraw. + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Chilled { stash: POOL1_BONDED }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, // other member bonding + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, // depositor bond extra + StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 20 }, + ] + ); + }) +} + #[test] fn pool_slash_e2e() { new_test_ext().execute_with(|| { -- GitLab From 30c32e3d8456984e19a7edf9e851b0db6135f376 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Thu, 7 Mar 2024 10:45:56 +0000 Subject: [PATCH 003/187] move substrate-bip39 into polkadot-sdk (#3579) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moves [substrate-bip39](https://github.com/paritytech/substrate-bip39) into substrate. All git history is preserved. Dependencies have been updated to use the same version as the rest of the repo. Fixes https://github.com/paritytech/polkadot-sdk/issues/1934. --------- Co-authored-by: Maciej Hirsz Co-authored-by: Maciej Hirsz <1096222+maciejhirsz@users.noreply.github.com> Co-authored-by: Gav Wood Co-authored-by: Stanislav Tkach Co-authored-by: Robert Habermeier Co-authored-by: Pierre Krieger Co-authored-by: Demi M. Obenour Co-authored-by: Bastian Köcher Co-authored-by: NikVolf Co-authored-by: Bastian Köcher Co-authored-by: Benjamin Kampmann Co-authored-by: Maciej Hirsz Co-authored-by: cheme Co-authored-by: adoerr <0xad@gmx.net> Co-authored-by: Jun Jiang Co-authored-by: Dan Shields <35669742+NukeManDan@users.noreply.github.com> Co-authored-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> --- Cargo.lock | 172 +++---------- Cargo.toml | 1 + polkadot/node/core/approval-voting/Cargo.toml | 2 +- polkadot/node/subsystem-bench/Cargo.toml | 5 +- substrate/primitives/core/Cargo.toml | 4 +- substrate/utils/substrate-bip39/Cargo.toml | 31 +++ substrate/utils/substrate-bip39/README.md | 55 +++++ substrate/utils/substrate-bip39/src/lib.rs | 232 ++++++++++++++++++ 8 files changed, 359 insertions(+), 143 deletions(-) create mode 100644 substrate/utils/substrate-bip39/Cargo.toml create mode 100644 substrate/utils/substrate-bip39/README.md create mode 100644 substrate/utils/substrate-bip39/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 177d76b8706..4815e976b5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -744,12 +744,6 @@ dependencies = [ "nodrop", ] -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - [[package]] name = "arrayvec" version = "0.7.4" @@ -1334,7 +1328,7 @@ dependencies = [ "ark-std 0.4.0", "dleq_vrf", "fflonk", - "merlin 3.0.0", + "merlin", "rand_chacha 0.3.1", "rand_core 0.6.4", "ring 0.1.0", @@ -1559,18 +1553,6 @@ dependencies = [ "constant_time_eq 0.3.0", ] -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -dependencies = [ - "block-padding", - "byte-tools", - "byteorder", - "generic-array 0.12.4", -] - [[package]] name = "block-buffer" version = "0.9.0" @@ -1589,15 +1571,6 @@ dependencies = [ "generic-array 0.14.7", ] -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -dependencies = [ - "byte-tools", -] - [[package]] name = "blocking" version = "1.3.1" @@ -2634,9 +2607,9 @@ dependencies = [ [[package]] name = "clap-num" -version = "1.0.2" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488557e97528174edaa2ee268b23a809e0c598213a4bbcb4f34575a46fda147e" +checksum = "0e063d263364859dc54fb064cedb7c122740cd4733644b14b176c097f51e8ab7" dependencies = [ "num-traits", ] @@ -2854,11 +2827,10 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "colored" -version = "2.0.4" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" dependencies = [ - "is-terminal", "lazy_static", "windows-sys 0.48.0", ] @@ -2886,7 +2858,7 @@ dependencies = [ "ark-std 0.4.0", "fflonk", "getrandom_or_panic", - "merlin 3.0.0", + "merlin", "rand_chacha 0.3.1", ] @@ -3526,16 +3498,6 @@ dependencies = [ "subtle 2.5.0", ] -[[package]] -name = "crypto-mac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25fab6889090c8133f3deb8f73ba3c65a7f456f66436fc012a1b1e272b1e103e" -dependencies = [ - "generic-array 0.14.7", - "subtle 2.5.0", -] - [[package]] name = "ctr" version = "0.7.0" @@ -4396,19 +4358,6 @@ dependencies = [ "url", ] -[[package]] -name = "curve25519-dalek" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9b85542f99a2dfa2a1b8e192662741c9859a846b296bef1c92ef9b58b5a216" -dependencies = [ - "byteorder", - "digest 0.8.1", - "rand_core 0.5.1", - "subtle 2.5.0", - "zeroize", -] - [[package]] name = "curve25519-dalek" version = "3.2.0" @@ -5238,12 +5187,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" - [[package]] name = "fallible-iterator" version = "0.2.0" @@ -5353,7 +5296,7 @@ dependencies = [ "ark-poly", "ark-serialize 0.4.2", "ark-std 0.4.0", - "merlin 3.0.0", + "merlin", ] [[package]] @@ -6428,16 +6371,6 @@ dependencies = [ "digest 0.9.0", ] -[[package]] -name = "hmac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" -dependencies = [ - "crypto-mac 0.11.0", - "digest 0.9.0", -] - [[package]] name = "hmac" version = "0.12.1" @@ -8124,18 +8057,6 @@ dependencies = [ "hash-db", ] -[[package]] -name = "merlin" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e261cf0f8b3c42ded9f7d2bb59dea03aa52bc8a1cbc7482f9fc3fd1229d3b42" -dependencies = [ - "byteorder", - "keccak", - "rand_core 0.5.1", - "zeroize", -] - [[package]] name = "merlin" version = "3.0.0" @@ -11642,19 +11563,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7924d1d0ad836f665c9065e26d016c673ece3993f30d340068b16f282afc1156" [[package]] -name = "paste" -version = "1.0.14" +name = "password-hash" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle 2.5.0", +] [[package]] -name = "pbkdf2" -version = "0.8.0" +name = "paste" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa" -dependencies = [ - "crypto-mac 0.11.0", -] +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "pbkdf2" @@ -11663,6 +11586,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ "digest 0.10.7", + "password-hash", ] [[package]] @@ -12454,7 +12378,7 @@ dependencies = [ "kvdb", "kvdb-memorydb", "log", - "merlin 3.0.0", + "merlin", "parity-scale-codec", "parking_lot 0.12.1", "polkadot-node-jaeger", @@ -13672,7 +13596,7 @@ dependencies = [ "sc-keystore", "sc-network", "sc-service", - "schnorrkel 0.9.1", + "schnorrkel 0.11.4", "serde", "serde_yaml", "sha1", @@ -14921,7 +14845,7 @@ dependencies = [ "blake2 0.10.6", "common", "fflonk", - "merlin 3.0.0", + "merlin", ] [[package]] @@ -17103,22 +17027,6 @@ dependencies = [ "hashbrown 0.13.2", ] -[[package]] -name = "schnorrkel" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "021b403afe70d81eea68f6ea12f6b3c9588e5d536a94c3bf80f15e7faa267862" -dependencies = [ - "arrayref", - "arrayvec 0.5.2", - "curve25519-dalek 2.1.3", - "merlin 2.0.1", - "rand_core 0.5.1", - "sha2 0.8.2", - "subtle 2.5.0", - "zeroize", -] - [[package]] name = "schnorrkel" version = "0.10.2" @@ -17128,7 +17036,7 @@ dependencies = [ "arrayref", "arrayvec 0.7.4", "curve25519-dalek-ng", - "merlin 3.0.0", + "merlin", "rand_core 0.6.4", "sha2 0.9.9", "subtle-ng", @@ -17146,7 +17054,7 @@ dependencies = [ "arrayvec 0.7.4", "curve25519-dalek 4.1.2", "getrandom_or_panic", - "merlin 3.0.0", + "merlin", "rand_core 0.6.4", "serde_bytes", "sha2 0.10.7", @@ -17510,18 +17418,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "sha2" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" -dependencies = [ - "block-buffer 0.7.3", - "digest 0.8.1", - "fake-simd", - "opaque-debug 0.2.3", -] - [[package]] name = "sha2" version = "0.9.9" @@ -17756,13 +17652,13 @@ dependencies = [ "hmac 0.12.1", "itertools 0.11.0", "libsecp256k1", - "merlin 3.0.0", + "merlin", "no-std-net", "nom", "num-bigint", "num-rational", "num-traits", - "pbkdf2 0.12.2", + "pbkdf2", "pin-project", "poly1305 0.8.0", "rand", @@ -18673,7 +18569,7 @@ dependencies = [ "lazy_static", "libsecp256k1", "log", - "merlin 3.0.0", + "merlin", "parity-scale-codec", "parking_lot 0.12.1", "paste", @@ -19829,14 +19725,14 @@ dependencies = [ [[package]] name = "substrate-bip39" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e620c7098893ba667438b47169c00aacdd9e7c10e042250ce2b60b087ec97328" +version = "0.4.7" dependencies = [ - "hmac 0.11.0", - "pbkdf2 0.8.0", - "schnorrkel 0.9.1", - "sha2 0.9.9", + "bip39", + "hmac 0.12.1", + "pbkdf2", + "rustc-hex", + "schnorrkel 0.11.4", + "sha2 0.10.7", "zeroize", ] diff --git a/Cargo.toml b/Cargo.toml index a2e22e0b927..80068596685 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -496,6 +496,7 @@ members = [ "substrate/utils/frame/rpc/system", "substrate/utils/frame/try-runtime/cli", "substrate/utils/prometheus", + "substrate/utils/substrate-bip39", "substrate/utils/wasm-builder", "templates/minimal/node", diff --git a/polkadot/node/core/approval-voting/Cargo.toml b/polkadot/node/core/approval-voting/Cargo.toml index f6d89dbc152..2a5b6198b9a 100644 --- a/polkadot/node/core/approval-voting/Cargo.toml +++ b/polkadot/node/core/approval-voting/Cargo.toml @@ -35,7 +35,7 @@ sp-consensus = { path = "../../../../substrate/primitives/consensus/common", def sp-consensus-slots = { path = "../../../../substrate/primitives/consensus/slots", default-features = false } sp-application-crypto = { path = "../../../../substrate/primitives/application-crypto", default-features = false, features = ["full_crypto"] } sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } -# should match schnorrkel +# rand_core should match schnorrkel rand_core = "0.6.2" rand_chacha = { version = "0.3.1" } rand = "0.8.5" diff --git a/polkadot/node/subsystem-bench/Cargo.toml b/polkadot/node/subsystem-bench/Cargo.toml index 726e7de4587..7c60ff48269 100644 --- a/polkadot/node/subsystem-bench/Cargo.toml +++ b/polkadot/node/subsystem-bench/Cargo.toml @@ -78,8 +78,9 @@ sp-consensus-babe = { path = "../../../substrate/primitives/consensus/babe" } sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } sp-timestamp = { path = "../../../substrate/primitives/timestamp" } -schnorrkel = { version = "0.9.1", default-features = false } -rand_core = "0.6.2" # should match schnorrkel +schnorrkel = { version = "0.11.4", default-features = false } +# rand_core should match schnorrkel +rand_core = "0.6.2" rand_chacha = { version = "0.3.1" } paste = "1.0.14" orchestra = { version = "0.3.5", default-features = false, features = ["futures_channel"] } diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 8fcabfeb238..70ca7be6a2d 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -27,7 +27,7 @@ hash-db = { version = "0.16.0", default-features = false } hash256-std-hasher = { version = "0.15.2", default-features = false } bs58 = { version = "0.5.0", default-features = false, optional = true } rand = { version = "0.8.5", features = ["small_rng"], optional = true } -substrate-bip39 = { version = "0.4.5", optional = true } +substrate-bip39 = { path = "../../utils/substrate-bip39", optional = true } bip39 = { version = "2.0.0", default-features = false } zeroize = { version = "1.4.3", default-features = false } secrecy = { version = "0.8.0", default-features = false } @@ -116,7 +116,7 @@ std = [ "sp-std/std", "sp-storage/std", "ss58-registry/std", - "substrate-bip39", + "substrate-bip39/std", "thiserror", "tracing", "w3f-bls?/std", diff --git a/substrate/utils/substrate-bip39/Cargo.toml b/substrate/utils/substrate-bip39/Cargo.toml new file mode 100644 index 00000000000..a46f81ee24d --- /dev/null +++ b/substrate/utils/substrate-bip39/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "substrate-bip39" +version = "0.4.7" +license = "Apache-2.0" +description = "Converting BIP39 entropy to valid Substrate (sr25519) SecretKeys" +documentation = "https://docs.rs/substrate-bip39" +authors.workspace = true +edition.workspace = true +repository.workspace = true + +[dependencies] +hmac = "0.12.1" +pbkdf2 = { version = "0.12.2", default-features = false } +schnorrkel = { version = "0.11.4", default-features = false } +sha2 = { version = "0.10.7", default-features = false } +zeroize = { version = "1.4.3", default-features = false } + +[dev-dependencies] +bip39 = "2.0.0" +rustc-hex = "2.1.0" + +[features] +default = ["std"] +std = [ + "hmac/std", + "pbkdf2/std", + "schnorrkel/std", + "sha2/std", + "zeroize/alloc", + "zeroize/std", +] diff --git a/substrate/utils/substrate-bip39/README.md b/substrate/utils/substrate-bip39/README.md new file mode 100644 index 00000000000..368d18f406b --- /dev/null +++ b/substrate/utils/substrate-bip39/README.md @@ -0,0 +1,55 @@ +# Substrate BIP39 + +This is a crate for deriving secret keys for Ristretto compressed Ed25519 (should be compatible with Ed25519 at this +time) from BIP39 phrases. + +## Why? + +The natural approach here would be to use the 64-byte seed generated from the BIP39 phrase, and use that to construct +the key. This approach, while reasonable and fairly straight forward to implement, also means we would have to inherit +all the characteristics of seed generation. Since we are breaking compatibility with both BIP32 and BIP44 anyway (which +we are free to do as we are no longer using the Secp256k1 curve), there is also no reason why we should adhere to BIP39 +seed generation from the mnemonic. + +BIP39 seed generation was designed to be compatible with user supplied brain wallet phrases as well as being extensible +to wallets providing their own dictionaries and checksum mechanism. Issues with those two points: + +1. Brain wallets are a horrible idea, simply because humans are bad entropy generators. It's next to impossible to + educate users on how to use that feature in a secure manner. The 2048 rounds of PBKDF2 is a mere inconvenience that + offers no real protection against dictionary attacks for anyone equipped with modern consumer hardware. Brain wallets + have given users false sense of security. _People have lost money_ this way and wallet providers today tend to stick + to CSPRNG supplied dictionary phrases. + +2. Providing own dictionaries felt into the _you ain't gonna need it_ anti-pattern category on day 1. Wallet providers + (be it hardware or software) typically want their products to be compatibile with other wallets so that users can + migrate to their product without having to migrate all their assets. + +To achieve the above phrases have to be precisely encoded in _The One True Canonical Encoding_, for which UTF-8 NFKD was +chosen. This is largely irrelevant (and even ignored) for English phrases, as they encode to basically just ASCII in +virtualy every character encoding known to mankind, but immedietly becomes a problem for dictionaries that do use +non-ASCII characters. Even if the right encoding is used and implemented correctly, there are still [other caveats +present for some non-english dictionaries](https://github.com/bitcoin/bips/blob/master/bip-0039/bip-0039-wordlists.md), +such as normalizing spaces to a canonical form, or making some latin based characters equivalent to their base in +dictionary lookups (eg. Spanish `ñ` and `n` are meant to be interchangeable). Thinking about all of this gives me a +headache, and opens doors for disagreements between buggy implementations, breaking compatibility. + +BIP39 does already provide a form of the mnemonic that is free from all of these issues: the entropy byte array. Since +veryfing the checksum requires that we recover the entropy from which the phrase was generated, no extra work is +actually needed here. Wallet implementators can encode the dictionaries in whatever encoding they find convenient (as +long as they are the standard BIP39 dictionaries), no harm in using UTF-16 string primitives that Java and JavaScript +provide. Since the dictionary is fixed and known, and the checksum is done on the entropy itself, the exact character +encoding used becomes irrelevant, as are the precise codepoints and amount of whitespace around the words. It is thus +much harder to create a buggy implementation. + +PBKDF2 was kept in place, along with the password. Using 24 words (with its 256 bits entropy) makes the extra hashing +redundant (if you could brute force 256 bit entropy, you can also just brute force secret keys), however some users +might be still using 12 word phrases from other applications. There is no good reason to prohibit users from recovering +their old wallets using 12 words that I can see, in which case the extra hashing does provide _some_ protection. +Passwords are also a feature that some power users find useful - particularly for creating a decoy address with a small +balance with empty password, while the funds proper are stored on an address that requires a password to be entered. + +## Why not ditch BIP39 altogether? + +Because there are hardware wallets that use a single phrase for the entire device, and operate multiple accounts on +multiple networks using that. A completely different wordlist would make their life much harder when it comes to +providing future Substrate support. diff --git a/substrate/utils/substrate-bip39/src/lib.rs b/substrate/utils/substrate-bip39/src/lib.rs new file mode 100644 index 00000000000..3673d20faed --- /dev/null +++ b/substrate/utils/substrate-bip39/src/lib.rs @@ -0,0 +1,232 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::string::String; + +use hmac::Hmac; +use pbkdf2::pbkdf2; +use schnorrkel::keys::MiniSecretKey; +use sha2::Sha512; +use zeroize::Zeroize; + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum Error { + InvalidEntropy, +} + +/// `entropy` should be a byte array from a correctly recovered and checksumed BIP39. +/// +/// This function accepts slices of different length for different word lengths: +/// +/// + 16 bytes for 12 words. +/// + 20 bytes for 15 words. +/// + 24 bytes for 18 words. +/// + 28 bytes for 21 words. +/// + 32 bytes for 24 words. +/// +/// Any other length will return an error. +/// +/// `password` is analog to BIP39 seed generation itself, with an empty string being defalt. +pub fn mini_secret_from_entropy(entropy: &[u8], password: &str) -> Result { + let seed = seed_from_entropy(entropy, password)?; + Ok(MiniSecretKey::from_bytes(&seed[..32]).expect("Length is always correct; qed")) +} + +/// Similar to `mini_secret_from_entropy`, except that it provides the 64-byte seed directly. +pub fn seed_from_entropy(entropy: &[u8], password: &str) -> Result<[u8; 64], Error> { + if entropy.len() < 16 || entropy.len() > 32 || entropy.len() % 4 != 0 { + return Err(Error::InvalidEntropy); + } + + let mut salt = String::with_capacity(8 + password.len()); + salt.push_str("mnemonic"); + salt.push_str(password); + + let mut seed = [0u8; 64]; + + pbkdf2::>(entropy, salt.as_bytes(), 2048, &mut seed) + .map_err(|_| Error::InvalidEntropy)?; + + salt.zeroize(); + + Ok(seed) +} + +#[cfg(test)] +mod test { + use super::*; + + #[cfg(not(feature = "std"))] + use alloc::vec::Vec; + + use bip39::{Language, Mnemonic}; + use rustc_hex::FromHex; + + // phrase, entropy, seed, expanded secret_key + // + // ALL SEEDS GENERATED USING "Substrate" PASSWORD! + static VECTORS: &[[&str; 3]] = &[ + [ + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", + "00000000000000000000000000000000", + "44e9d125f037ac1d51f0a7d3649689d422c2af8b1ec8e00d71db4d7bf6d127e33f50c3d5c84fa3e5399c72d6cbbbbc4a49bf76f76d952f479d74655a2ef2d453", + ], + [ + "legal winner thank year wave sausage worth useful legal winner thank yellow", + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "4313249608fe8ac10fd5886c92c4579007272cb77c21551ee5b8d60b780416850f1e26c1f4b8d88ece681cb058ab66d6182bc2ce5a03181f7b74c27576b5c8bf", + ], + [ + "letter advice cage absurd amount doctor acoustic avoid letter advice cage above", + "80808080808080808080808080808080", + "27f3eb595928c60d5bc91a4d747da40ed236328183046892ed6cd5aa9ae38122acd1183adf09a89839acb1e6eaa7fb563cc958a3f9161248d5a036e0d0af533d", + ], + [ + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", + "ffffffffffffffffffffffffffffffff", + "227d6256fd4f9ccaf06c45eaa4b2345969640462bbb00c5f51f43cb43418c7a753265f9b1e0c0822c155a9cabc769413ecc14553e135fe140fc50b6722c6b9df", + ], + [ + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent", + "000000000000000000000000000000000000000000000000", + "44e9d125f037ac1d51f0a7d3649689d422c2af8b1ec8e00d71db4d7bf6d127e33f50c3d5c84fa3e5399c72d6cbbbbc4a49bf76f76d952f479d74655a2ef2d453", + ], + [ + "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will", + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "cb1d50e14101024a88905a098feb1553d4306d072d7460e167a60ccb3439a6817a0afc59060f45d999ddebc05308714733c9e1e84f30feccddd4ad6f95c8a445", + ], + [ + "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always", + "808080808080808080808080808080808080808080808080", + "9ddecf32ce6bee77f867f3c4bb842d1f0151826a145cb4489598fe71ac29e3551b724f01052d1bc3f6d9514d6df6aa6d0291cfdf997a5afdb7b6a614c88ab36a", + ], + [ + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when", + "ffffffffffffffffffffffffffffffffffffffffffffffff", + "8971cb290e7117c64b63379c97ed3b5c6da488841bd9f95cdc2a5651ac89571e2c64d391d46e2475e8b043911885457cd23e99a28b5a18535fe53294dc8e1693", + ], + [ + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", + "0000000000000000000000000000000000000000000000000000000000000000", + "44e9d125f037ac1d51f0a7d3649689d422c2af8b1ec8e00d71db4d7bf6d127e33f50c3d5c84fa3e5399c72d6cbbbbc4a49bf76f76d952f479d74655a2ef2d453", + ], + [ + "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title", + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "3037276a5d05fcd7edf51869eb841bdde27c574dae01ac8cfb1ea476f6bea6ef57ab9afe14aea1df8a48f97ae25b37d7c8326e49289efb25af92ba5a25d09ed3", + ], + [ + "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless", + "8080808080808080808080808080808080808080808080808080808080808080", + "2c9c6144a06ae5a855453d98c3dea470e2a8ffb78179c2e9eb15208ccca7d831c97ddafe844ab933131e6eb895f675ede2f4e39837bb5769d4e2bc11df58ac42", + ], + [ + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "047e89ef7739cbfe30da0ad32eb1720d8f62441dd4f139b981b8e2d0bd412ed4eb14b89b5098c49db2301d4e7df4e89c21e53f345138e56a5e7d63fae21c5939", + ], + [ + "ozone drill grab fiber curtain grace pudding thank cruise elder eight picnic", + "9e885d952ad362caeb4efe34a8e91bd2", + "f4956be6960bc145cdab782e649a5056598fd07cd3f32ceb73421c3da27833241324dc2c8b0a4d847eee457e6d4c5429f5e625ece22abaa6a976e82f1ec5531d", + ], + [ + "gravity machine north sort system female filter attitude volume fold club stay feature office ecology stable narrow fog", + "6610b25967cdcca9d59875f5cb50b0ea75433311869e930b", + "fbcc5229ade0c0ff018cb7a329c5459f91876e4dde2a97ddf03c832eab7f26124366a543f1485479c31a9db0d421bda82d7e1fe562e57f3533cb1733b001d84d", + ], + [ + "hamster diagram private dutch cause delay private meat slide toddler razor book happy fancy gospel tennis maple dilemma loan word shrug inflict delay length", + "68a79eaca2324873eacc50cb9c6eca8cc68ea5d936f98787c60c7ebc74e6ce7c", + "7c60c555126c297deddddd59f8cdcdc9e3608944455824dd604897984b5cc369cad749803bb36eb8b786b570c9cdc8db275dbe841486676a6adf389f3be3f076", + ], + [ + "scheme spot photo card baby mountain device kick cradle pact join borrow", + "c0ba5a8e914111210f2bd131f3d5e08d", + "c12157bf2506526c4bd1b79a056453b071361538e9e2c19c28ba2cfa39b5f23034b974e0164a1e8acd30f5b4c4de7d424fdb52c0116bfc6a965ba8205e6cc121", + ], + [ + "horn tenant knee talent sponsor spell gate clip pulse soap slush warm silver nephew swap uncle crack brave", + "6d9be1ee6ebd27a258115aad99b7317b9c8d28b6d76431c3", + "23766723e970e6b79dec4d5e4fdd627fd27d1ee026eb898feb9f653af01ad22080c6f306d1061656d01c4fe9a14c05f991d2c7d8af8730780de4f94cd99bd819", + ], + [ + "panda eyebrow bullet gorilla call smoke muffin taste mesh discover soft ostrich alcohol speed nation flash devote level hobby quick inner drive ghost inside", + "9f6a2878b2520799a44ef18bc7df394e7061a224d2c33cd015b157d746869863", + "f4c83c86617cb014d35cd87d38b5ef1c5d5c3d58a73ab779114438a7b358f457e0462c92bddab5a406fe0e6b97c71905cf19f925f356bc673ceb0e49792f4340", + ], + [ + "cat swing flag economy stadium alone churn speed unique patch report train", + "23db8160a31d3e0dca3688ed941adbf3", + "719d4d4de0638a1705bf5237262458983da76933e718b2d64eb592c470f3c5d222e345cc795337bb3da393b94375ff4a56cfcd68d5ea25b577ee9384d35f4246", + ], + [ + "light rule cinnamon wrap drastic word pride squirrel upgrade then income fatal apart sustain crack supply proud access", + "8197a4a47f0425faeaa69deebc05ca29c0a5b5cc76ceacc0", + "7ae1291db32d16457c248567f2b101e62c5549d2a64cd2b7605d503ec876d58707a8d663641e99663bc4f6cc9746f4852e75e7e54de5bc1bd3c299c9a113409e", + ], + [ + "all hour make first leader extend hole alien behind guard gospel lava path output census museum junior mass reopen famous sing advance salt reform", + "066dca1a2bb7e8a1db2832148ce9933eea0f3ac9548d793112d9a95c9407efad", + "a911a5f4db0940b17ecb79c4dcf9392bf47dd18acaebdd4ef48799909ebb49672947cc15f4ef7e8ef47103a1a91a6732b821bda2c667e5b1d491c54788c69391", + ], + [ + "vessel ladder alter error federal sibling chat ability sun glass valve picture", + "f30f8c1da665478f49b001d94c5fc452", + "4e2314ca7d9eebac6fe5a05a5a8d3546bc891785414d82207ac987926380411e559c885190d641ff7e686ace8c57db6f6e4333c1081e3d88d7141a74cf339c8f", + ], + [ + "scissors invite lock maple supreme raw rapid void congress muscle digital elegant little brisk hair mango congress clump", + "c10ec20dc3cd9f652c7fac2f1230f7a3c828389a14392f05", + "7a83851102849edc5d2a3ca9d8044d0d4f00e5c4a292753ed3952e40808593251b0af1dd3c9ed9932d46e8608eb0b928216a6160bd4fc775a6e6fbd493d7c6b2", + ], + [ + "void come effort suffer camp survey warrior heavy shoot primary clutch crush open amazing screen patrol group space point ten exist slush involve unfold", + "f585c11aec520db57dd353c69554b21a89b20fb0650966fa0a9d6f74fd989d8f", + "938ba18c3f521f19bd4a399c8425b02c716844325b1a65106b9d1593fbafe5e0b85448f523f91c48e331995ff24ae406757cff47d11f240847352b348ff436ed", + ] + ]; + + #[test] + fn vectors_are_correct() { + for vector in VECTORS { + let phrase = vector[0]; + + let expected_entropy: Vec = vector[1].from_hex().unwrap(); + let expected_seed: Vec = vector[2].from_hex().unwrap(); + + let mnemonic = Mnemonic::parse_in(Language::English, phrase).unwrap(); + let seed = seed_from_entropy(&mnemonic.to_entropy(), "Substrate").unwrap(); + let secret = mini_secret_from_entropy(&mnemonic.to_entropy(), "Substrate") + .unwrap() + .to_bytes(); + + assert_eq!( + mnemonic.to_entropy(), + &expected_entropy[..], + "Entropy is incorrect for {}", + phrase + ); + assert_eq!(&seed[..], &expected_seed[..], "Seed is incorrect for {}", phrase); + assert_eq!(&secret[..], &expected_seed[..32], "Secret is incorrect for {}", phrase); + } + } +} -- GitLab From 50cc1c2f7efa0e61ac773b8e89171c9640315475 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Thu, 7 Mar 2024 11:40:30 +0000 Subject: [PATCH 004/187] Add documentation around pallet coupling (#3542) substrate.io deprecation companion: https://github.com/substrate-developer-hub/substrate-docs/pull/2139 pba-content companion: https://github.com/Polkadot-Blockchain-Academy/pba-content/pull/978 partially inspired by: https://github.com/paritytech/polkadot-sdk/issues/3535 --------- Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> --- Cargo.lock | 1 + docs/sdk/Cargo.toml | 1 + docs/sdk/src/polkadot_sdk/frame_runtime.rs | 144 +++++---- .../reference_docs/frame_pallet_coupling.rs | 296 ++++++++++++++++++ docs/sdk/src/reference_docs/mod.rs | 4 + substrate/frame/support/src/lib.rs | 5 +- 6 files changed, 374 insertions(+), 77 deletions(-) create mode 100644 docs/sdk/src/reference_docs/frame_pallet_coupling.rs diff --git a/Cargo.lock b/Cargo.lock index 4815e976b5d..e38f09db4d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13332,6 +13332,7 @@ dependencies = [ "frame-support", "frame-system", "kitchensink-runtime", + "pallet-assets", "pallet-aura", "pallet-authorship", "pallet-balances", diff --git a/docs/sdk/Cargo.toml b/docs/sdk/Cargo.toml index 735b3d7df61..8b498d407c0 100644 --- a/docs/sdk/Cargo.toml +++ b/docs/sdk/Cargo.toml @@ -65,6 +65,7 @@ pallet-aura = { path = "../../substrate/frame/aura", default-features = false } # Pallets and FRAME internals pallet-timestamp = { path = "../../substrate/frame/timestamp" } pallet-balances = { path = "../../substrate/frame/balances" } +pallet-assets = { path = "../../substrate/frame/assets" } pallet-transaction-payment = { path = "../../substrate/frame/transaction-payment" } pallet-utility = { path = "../../substrate/frame/utility" } pallet-multisig = { path = "../../substrate/frame/multisig" } diff --git a/docs/sdk/src/polkadot_sdk/frame_runtime.rs b/docs/sdk/src/polkadot_sdk/frame_runtime.rs index c9eba7d64bd..f178fc82bf4 100644 --- a/docs/sdk/src/polkadot_sdk/frame_runtime.rs +++ b/docs/sdk/src/polkadot_sdk/frame_runtime.rs @@ -87,93 +87,89 @@ //! * writing a runtime in pure Rust, as done in [this template](https://github.com/JoshOrndorff/frameless-node-template). //! * writing a runtime in AssemblyScript,as explored in [this project](https://github.com/LimeChain/subsembly). -#[cfg(test)] -mod tests { - use frame::prelude::*; +use frame::prelude::*; - /// A FRAME based pallet. This `mod` is the entry point for everything else. All - /// `#[pallet::xxx]` macros must be defined in this `mod`. Although, frame also provides an - /// experimental feature to break these parts into different `mod`s. See [`pallet_examples`] for - /// more. - #[docify::export] - #[frame::pallet(dev_mode)] - pub mod pallet { - use super::*; +/// A FRAME based pallet. This `mod` is the entry point for everything else. All +/// `#[pallet::xxx]` macros must be defined in this `mod`. Although, frame also provides an +/// experimental feature to break these parts into different `mod`s. See [`pallet_examples`] for +/// more. +#[docify::export] +#[frame::pallet(dev_mode)] +pub mod pallet { + use super::*; - /// The configuration trait of a pallet. Mandatory. Allows a pallet to receive types at a - /// later point from the runtime that wishes to contain it. It allows the pallet to be - /// parameterized over both types and values. - #[pallet::config] - pub trait Config: frame_system::Config { - /// A type that is not known now, but the runtime that will contain this pallet will - /// know it later, therefore we define it here as an associated type. - type RuntimeEvent: IsType<::RuntimeEvent> - + From>; + /// The configuration trait of a pallet. Mandatory. Allows a pallet to receive types at a + /// later point from the runtime that wishes to contain it. It allows the pallet to be + /// parameterized over both types and values. + #[pallet::config] + pub trait Config: frame_system::Config { + /// A type that is not known now, but the runtime that will contain this pallet will + /// know it later, therefore we define it here as an associated type. + type RuntimeEvent: IsType<::RuntimeEvent> + From>; - /// A parameterize-able value that we receive later via the `Get<_>` trait. - type ValueParameter: Get; + /// A parameterize-able value that we receive later via the `Get<_>` trait. + type ValueParameter: Get; - /// Similar to [`Config::ValueParameter`], but using `const`. Both are functionally - /// equal, but offer different tradeoffs. - const ANOTHER_VALUE_PARAMETER: u32; - } + /// Similar to [`Config::ValueParameter`], but using `const`. Both are functionally + /// equal, but offer different tradeoffs. + const ANOTHER_VALUE_PARAMETER: u32; + } - /// A mandatory struct in each pallet. All functions callable by external users (aka. - /// transactions) must be attached to this type (see [`frame::pallet_macros::call`]). For - /// convenience, internal (private) functions can also be attached to this type. - #[pallet::pallet] - pub struct Pallet(PhantomData); + /// A mandatory struct in each pallet. All functions callable by external users (aka. + /// transactions) must be attached to this type (see [`frame::pallet_macros::call`]). For + /// convenience, internal (private) functions can also be attached to this type. + #[pallet::pallet] + pub struct Pallet(PhantomData); - /// The events tha this pallet can emit. - #[pallet::event] - pub enum Event {} + /// The events tha this pallet can emit. + #[pallet::event] + pub enum Event {} - /// A storage item that this pallet contains. This will be part of the state root trie/root - /// of the blockchain. - #[pallet::storage] - pub type Value = StorageValue; + /// A storage item that this pallet contains. This will be part of the state root trie/root + /// of the blockchain. + #[pallet::storage] + pub type Value = StorageValue; - /// All *dispatchable* call functions (aka. transactions) are attached to `Pallet` in a - /// `impl` block. - #[pallet::call] - impl Pallet { - /// This will be callable by external users, and has two u32s as a parameter. - pub fn some_dispatchable( - _origin: OriginFor, - _param: u32, - _other_para: u32, - ) -> DispatchResult { - Ok(()) - } + /// All *dispatchable* call functions (aka. transactions) are attached to `Pallet` in a + /// `impl` block. + #[pallet::call] + impl Pallet { + /// This will be callable by external users, and has two u32s as a parameter. + pub fn some_dispatchable( + _origin: OriginFor, + _param: u32, + _other_para: u32, + ) -> DispatchResult { + Ok(()) } } +} - /// A simple runtime that contains the above pallet and `frame_system`, the mandatory pallet of - /// all runtimes. This runtime is for testing, but it shares a lot of similarities with a *real* - /// runtime. - #[docify::export] - pub mod runtime { - use super::pallet as pallet_example; - use frame::{prelude::*, testing_prelude::*}; - - // The major macro that amalgamates pallets into `enum Runtime` - construct_runtime!( - pub enum Runtime { - System: frame_system, - Example: pallet_example, - } - ); +/// A simple runtime that contains the above pallet and `frame_system`, the mandatory pallet of +/// all runtimes. This runtime is for testing, but it shares a lot of similarities with a *real* +/// runtime. +#[docify::export] +pub mod runtime { + use super::pallet as pallet_example; + use frame::{prelude::*, testing_prelude::*}; - // These `impl` blocks specify the parameters of each pallet's `trait Config`. - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] - impl frame_system::Config for Runtime { - type Block = MockBlock; + // The major macro that amalgamates pallets into `enum Runtime` + construct_runtime!( + pub enum Runtime { + System: frame_system, + Example: pallet_example, } + ); - impl pallet_example::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type ValueParameter = ConstU32<42>; - const ANOTHER_VALUE_PARAMETER: u32 = 42; - } + // These `impl` blocks specify the parameters of each pallet's `trait Config`. + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + impl frame_system::Config for Runtime { + type Block = MockBlock; + } + + impl pallet_example::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ValueParameter = ConstU32<42>; + const ANOTHER_VALUE_PARAMETER: u32 = 42; } } diff --git a/docs/sdk/src/reference_docs/frame_pallet_coupling.rs b/docs/sdk/src/reference_docs/frame_pallet_coupling.rs new file mode 100644 index 00000000000..942717ecfb2 --- /dev/null +++ b/docs/sdk/src/reference_docs/frame_pallet_coupling.rs @@ -0,0 +1,296 @@ +//! # FRAME Pallet Coupling +//! +//! This reference document explains how FRAME pallets can be combined to interact together. +//! +//! It is suggested to re-read [`crate::polkadot_sdk::frame_runtime`], notably the information +//! around [`frame::pallet_macros::config`]. Recall that: +//! +//! > Configuration trait of a pallet: It allows a pallet to receive types at a later +//! > point from the runtime that wishes to contain it. It allows the pallet to be parameterized +//! > over both types and values. +//! +//! ## Context, Background +//! +//! FRAME pallets, as per described in [`crate::polkadot_sdk::frame_runtime`] are: +//! +//! > A pallet is a unit of encapsulated logic. It has a clearly defined responsibility and can be +//! linked to other pallets. +//! +//! That is to say: +//! +//! * *encapsulated*: Ideally, a FRAME pallet contains encapsulated logic which has clear +//! boundaries. It is generally a bad idea to build a single monolithic pallet that does multiple +//! things, such as handling currencies, identities and staking all at the same time. +//! * *linked to other pallets*: But, adhering extensively to the above also hinders the ability to +//! write useful applications. Pallets often need to work with each other, communicate and use +//! each other's functionalities. +//! +//! The broad principle that allows pallets to be linked together is the same way through which a +//! pallet uses its `Config` trait to receive types and values from the runtime that contains it. +//! +//! There are generally two ways to achieve this: +//! +//! 1. Tight coupling pallets +//! 2. Loose coupling pallets +//! +//! To explain the difference between the two, consider two pallets, `A` and `B`. In both cases, `A` +//! wants to use some functionality exposed by `B`. +//! +//! When tightly coupling pallets, `A` can only exist in a runtime if `B` is also present in the +//! same runtime. That is, `A` is expressing that can only work if `B` is present. +//! +//! This translates to the following Rust code: +//! +//! ``` +//! trait Pallet_B_Config {} +//! trait Pallet_A_Config: Pallet_B_Config {} +//! ``` +//! +//! Contrary, when pallets are loosely coupled, `A` expresses that some functionality, expressed via +//! a trait `F`, needs to be fulfilled. This trait is then implemented by `B`, and the two pallets +//! are linked together at the runtime level. This means that `A` only relies on the implementation +//! of `F`, which may be `B`, or another implementation of `F`. +//! +//! This translates to the following Rust code: +//! +//! ``` +//! trait F {} +//! trait Pallet_A_Config { +//! type F: F; +//! } +//! // Pallet_B will implement and fulfill `F`. +//! ``` +//! +//! ## Example +//! +//! Consider the following example, in which `pallet-foo` needs another pallet to provide the block +//! author to it, and `pallet-author` which has access to this information. +#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", pallet_foo)] +#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", pallet_author)] +//! +//! ### Tight Coupling Pallets +//! +//! To tightly couple `pallet-foo` and `pallet-author`, we use Rust's supertrait system. When a +//! pallet makes its own `trait Config` be bounded by another pallet's `trait Config`, it is +//! expressing two things: +//! +//! 1. that it can only exist in a runtime if the other pallet is also present. +//! 2. that it can use the other pallet's functionality. +//! +//! `pallet-foo`'s `Config` would then look like: +#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", tight_config)] +//! +//! And `pallet-foo` can use the method exposed by `pallet_author::Pallet` directly: +#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", tight_usage)] +//! +//! +//! ### Loosely Coupling Pallets +//! +//! If `pallet-foo` wants to *not* rely on `pallet-author` directly, it can leverage its +//! `Config`'s associated types. First, we need a trait to express the functionality that +//! `pallet-foo` wants to obtain: +#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", AuthorProvider)] +//! +//! > We sometimes refer to such traits that help two pallets interact as "glue traits". +//! +//! Next, `pallet-foo` states that it needs this trait to be provided to it, at the runtime level, +//! via an associated type: +#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", loose_config)] +//! +//! Then, `pallet-foo` can use this trait to obtain the block author, without knowing where it comes +//! from: +#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", loose_usage)] +//! +//! Then, if `pallet-author` implements this glue-trait: +#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", pallet_author_provider)] +//! +//! And upon the creation of the runtime, the two pallets are linked together as such: +#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", runtime_author_provider)] +//! +//! Crucially, when using loose coupling, we gain the flexibility of providing different +//! implementations of `AuthorProvider`, such that different users of a `pallet-foo` can use +//! different ones, without any code change being needed. For example, in the code snippets of this +//! module, you can fund [`OtherAuthorProvider`] which is an alternative implementation of +//! [`AuthorProvider`]. +#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", other_author_provider)] +//! +//! A common pattern in polkadot-sdk is to provide an implementation of such glu traits for the unit +//! type as a "default/test behavior". +#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", unit_author_provider)] +//! +//! ## Frame System +//! +//! With the above information in context, we can conclude that **`frame_system` is a special pallet +//! that is tightly coupled with every other pallet**. This is because it provides the fundamental +//! system functionality that every pallet needs, such as some types like +//! [`frame::prelude::frame_system::Config::AccountId`], +//! [`frame::prelude::frame_system::Config::Hash`], and some functionality such as block number, +//! etc. +//! +//! ## Recap +//! +//! To recap, consider the following rules of thumb: +//! +//! * In all cases, try and break down big pallets apart with clear boundaries of responsibility. In +//! general, it is easier to argue about multiple pallet if they only communicate together via a +//! known trait, rather than having access to all of each others public items, such as storage and +//! dispatchables. +//! * If a group of pallets are meant to work together, and but are not foreseen to be generalized, +//! or used by others, consider tightly coupling pallets, *if it simplifies the development*. +//! * If a pallet needs a functionality provided by another pallet, but multiple implementations can +//! be foreseen, consider loosely coupling pallets. +//! +//! For example, all pallets in `polkadot-sdk` that needed to work with currencies could have been +//! tightly coupled with [`pallet_balances`]. But, `polkadot-sdk` also provides [`pallet_assets`] +//! (and more implementations by the community), therefore all pallets use traits to loosely couple +//! with balances or assets pallet. More on this in [`crate::reference_docs::frame_currency`]. +//! +//! ## Further References +//! +//! - +//! - +//! +//! [`AuthorProvider`]: crate::reference_docs::frame_pallet_coupling::AuthorProvider +//! [`OtherAuthorProvider`]: crate::reference_docs::frame_pallet_coupling::OtherAuthorProvider + +#![allow(unused)] + +use frame::prelude::*; + +#[docify::export] +#[frame::pallet] +pub mod pallet_foo { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + impl Pallet { + fn do_stuff_with_author() { + // needs block author here + } + } +} + +#[docify::export] +#[frame::pallet] +pub mod pallet_author { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + impl Pallet { + pub fn author() -> T::AccountId { + todo!("somehow has access to the block author and can return it here") + } + } +} + +#[frame::pallet] +pub mod pallet_foo_tight { + use super::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[docify::export(tight_config)] + /// This pallet can only live in a runtime that has both `frame_system` and `pallet_author`. + #[pallet::config] + pub trait Config: frame_system::Config + pallet_author::Config {} + + #[docify::export(tight_usage)] + impl Pallet { + // anywhere in `pallet-foo`, we can call into `pallet-author` directly, namely because + // `T: pallet_author::Config` + fn do_stuff_with_author() { + let _ = pallet_author::Pallet::::author(); + } + } +} + +#[docify::export] +/// Abstraction over "something that can provide the block author". +pub trait AuthorProvider { + fn author() -> AccountId; +} + +#[frame::pallet] +pub mod pallet_foo_loose { + use super::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[docify::export(loose_config)] + #[pallet::config] + pub trait Config: frame_system::Config { + /// This pallet relies on the existence of something that implements [`AuthorProvider`], + /// which may or may not be `pallet-author`. + type AuthorProvider: AuthorProvider; + } + + #[docify::export(loose_usage)] + impl Pallet { + fn do_stuff_with_author() { + let _ = T::AuthorProvider::author(); + } + } +} + +#[docify::export(pallet_author_provider)] +impl AuthorProvider for pallet_author::Pallet { + fn author() -> T::AccountId { + pallet_author::Pallet::::author() + } +} + +pub struct OtherAuthorProvider; + +#[docify::export(other_author_provider)] +impl AuthorProvider for OtherAuthorProvider { + fn author() -> AccountId { + todo!("somehow get the block author here") + } +} + +#[docify::export(unit_author_provider)] +impl AuthorProvider for () { + fn author() -> AccountId { + todo!("somehow get the block author here") + } +} + +pub mod runtime { + use super::*; + use cumulus_pallet_aura_ext::pallet; + use frame::{runtime::prelude::*, testing_prelude::*}; + + construct_runtime!( + pub struct Runtime { + System: frame_system, + PalletFoo: pallet_foo_loose, + PalletAuthor: pallet_author, + } + ); + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + impl frame_system::Config for Runtime { + type Block = MockBlock; + } + + impl pallet_author::Config for Runtime {} + + #[docify::export(runtime_author_provider)] + impl pallet_foo_loose::Config for Runtime { + type AuthorProvider = pallet_author::Pallet; + // which is also equivalent to + // type AuthorProvider = PalletAuthor; + } +} diff --git a/docs/sdk/src/reference_docs/mod.rs b/docs/sdk/src/reference_docs/mod.rs index 3fd815d2a15..f4b52208e2f 100644 --- a/docs/sdk/src/reference_docs/mod.rs +++ b/docs/sdk/src/reference_docs/mod.rs @@ -103,3 +103,7 @@ pub mod light_nodes; /// Learn about the offchain workers, how they function, and how to use them, as provided by the /// [`frame`] APIs. pub mod frame_offchain_workers; + +/// Learn about the different ways through which multiple [`frame`] pallets can be combined to work +/// together. +pub mod frame_pallet_coupling; diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index b5b1ac09c60..6ea7fa33e77 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -1531,9 +1531,8 @@ pub mod pallet_macros { /// The attribute currently only supports enum definitions, and identifiers that are named /// `FreezeReason`, `HoldReason`, `LockId` or `SlashReason`. Arbitrary identifiers for the /// enum are not supported. The aggregate enum generated by - /// [`frame_support::construct_runtime`](frame_support::construct_runtime) will have the - /// name of `RuntimeFreezeReason`, `RuntimeHoldReason`, `RuntimeLockId` and - /// `RuntimeSlashReason` respectively. + /// [`frame_support::construct_runtime`] will have the name of `RuntimeFreezeReason`, + /// `RuntimeHoldReason`, `RuntimeLockId` and `RuntimeSlashReason` respectively. /// /// NOTE: The aggregate enum generated by `construct_runtime` generates a conversion /// function from the pallet enum to the aggregate enum, and automatically derives the -- GitLab From c89b3997df47408a324e8870693e80ddc4a42b7d Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Thu, 7 Mar 2024 12:47:30 +0100 Subject: [PATCH 005/187] Contracts: Remove changelog (#3605) This is not maintained, and we should be able to get information from the release changelog --- substrate/frame/contracts/CHANGELOG.md | 116 ------------------------- 1 file changed, 116 deletions(-) delete mode 100644 substrate/frame/contracts/CHANGELOG.md diff --git a/substrate/frame/contracts/CHANGELOG.md b/substrate/frame/contracts/CHANGELOG.md deleted file mode 100644 index aca94e5b149..00000000000 --- a/substrate/frame/contracts/CHANGELOG.md +++ /dev/null @@ -1,116 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -The semantic versioning guarantees cover the interface to the Substrate runtime which -includes this pallet as a dependency. This module will also add storage migrations whenever -changes require it. Stability with regard to offchain tooling is explicitly excluded from -this guarantee: For example adding a new field to an in-storage data structure will require -changes to frontends to properly display it. However, those changes will still be regarded -as a minor version bump. - -The interface provided to smart contracts will adhere to semver with one exception: Even -major version bumps will be backwards compatible with regard to already deployed contracts. -In other words: Upgrading this pallet will not break pre-existing contracts. - -## [Unreleased] - -### Added - -- Forbid calling back to contracts after switching to runtime -[#13443](https://github.com/paritytech/substrate/pull/13443) - -- Allow contracts to dispatch calls into the runtime (**unstable**) -[#9276](https://github.com/paritytech/substrate/pull/9276) - -- New version of `seal_call` that offers more features. -[#8909](https://github.com/paritytech/substrate/pull/8909) - -- New `instantiate` RPC that allows clients to dry-run contract instantiation. -[#8451](https://github.com/paritytech/substrate/pull/8451) - -- New version of `seal_random` which exposes additional information. -[#8329](https://github.com/paritytech/substrate/pull/8329) - -### Changed - -- Replaced storage rent with automatic storage deposits -[#9669](https://github.com/paritytech/substrate/pull/9669) -[#10082](https://github.com/paritytech/substrate/pull/10082) - -- Replaced `seal_println` with the `seal_debug_message` API which allows outputting debug -messages to the console and RPC clients. -[#8773](https://github.com/paritytech/substrate/pull/8773) -[#9550](https://github.com/paritytech/substrate/pull/9550) - -- Make storage and fields of `Schedule` private to the crate. -[#8359](https://github.com/paritytech/substrate/pull/8359) - -### Fixed - -- Remove pre-charging which caused wrongly estimated weights -[#8976](https://github.com/paritytech/substrate/pull/8976) - -## [v3.0.0] 2021-02-25 - -This version constitutes the first release that brings any stability guarantees (see above). - -### Added - -- Emit an event when a contract terminates (self-destructs). -[#8014](https://github.com/paritytech/substrate/pull/8014) - -- Charge rent for code stored on the chain in addition to the already existing -rent that is paid for data storage. -[#7935](https://github.com/paritytech/substrate/pull/7935) - -- Allow the runtime to configure per storage item costs in addition -to the already existing per byte costs. -[#7819](https://github.com/paritytech/substrate/pull/7819) - -- Contracts are now deleted lazily so that the user who removes a contract -does not need to pay for the deletion of the contract storage. -[#7740](https://github.com/paritytech/substrate/pull/7740) - -- Allow runtime authors to define chain extensions in order to provide custom -functionality to contracts. -[#7548](https://github.com/paritytech/substrate/pull/7548) -[#8003](https://github.com/paritytech/substrate/pull/8003) - -- Proper weights which are fully automated by benchmarking. -[#6715](https://github.com/paritytech/substrate/pull/6715) -[#7017](https://github.com/paritytech/substrate/pull/7017) -[#7361](https://github.com/paritytech/substrate/pull/7361) - -### Changed - -- Collect the rent for one block during instantiation. -[#7847](https://github.com/paritytech/substrate/pull/7847) - -- Instantiation takes a `salt` argument to allow for easier instantion of the -same code by the same sender. -[#7482](https://github.com/paritytech/substrate/pull/7482) - -- Improve the information returned by the `contracts_call` RPC. -[#7468](https://github.com/paritytech/substrate/pull/7468) - -- Simplify the node configuration necessary to add this module. -[#7409](https://github.com/paritytech/substrate/pull/7409) - -### Fixed - -- Consider the code size of a contract in the weight that is charged for -loading a contract from storage. -[#8086](https://github.com/paritytech/substrate/pull/8086) - -- Fix possible overflow in storage size calculation -[#7885](https://github.com/paritytech/substrate/pull/7885) - -- Cap the surcharge reward that can be claimed. -[#7870](https://github.com/paritytech/substrate/pull/7870) - -- Fix a possible DoS vector where contracts could allocate too large buffers. -[#7818](https://github.com/paritytech/substrate/pull/7818) -- GitLab From 6792d4b5b84e80ab771aa32666ce08dbcca39b97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Thu, 7 Mar 2024 20:10:12 +0800 Subject: [PATCH 006/187] Disable flaky test (#3602) Unfortunately, the flakiness wasn't fixed by https://github.com/paritytech/polkadot-sdk/pull/3595. Let's disable the test in the meanwhile since it is hanging on the CI a lot. --------- Co-authored-by: Liam Aharon --- substrate/client/consensus/manual-seal/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/substrate/client/consensus/manual-seal/src/lib.rs b/substrate/client/consensus/manual-seal/src/lib.rs index f04c0d42d60..c3d360f0719 100644 --- a/substrate/client/consensus/manual-seal/src/lib.rs +++ b/substrate/client/consensus/manual-seal/src/lib.rs @@ -467,7 +467,10 @@ mod tests { assert_eq!(client.header(created_block.hash).unwrap().unwrap().number, 1) } - #[tokio::test] + // TODO: enable once the flakiness is fixed + // See https://github.com/paritytech/polkadot-sdk/issues/3603 + //#[tokio::test] + #[allow(unused)] async fn instant_seal_delayed_finalize() { let builder = TestClientBuilder::new(); let (client, select_chain) = builder.build_with_longest_chain(); -- GitLab From de9411aa4c29a28cb2c964cce8153bdaa1bdc7ea Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Thu, 7 Mar 2024 13:39:39 +0100 Subject: [PATCH 007/187] Contracts: Remove unstable on lock/unlock_delegate_dependency host fns (#3606) Oversight from PR https://github.com/paritytech/polkadot-sdk/pull/3384. These 2 functions should have been tagged as stable --- prdoc/pr_3606.prdoc | 9 +++++++++ substrate/frame/contracts/src/wasm/runtime.rs | 2 -- 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 prdoc/pr_3606.prdoc diff --git a/prdoc/pr_3606.prdoc b/prdoc/pr_3606.prdoc new file mode 100644 index 00000000000..18b71de9477 --- /dev/null +++ b/prdoc/pr_3606.prdoc @@ -0,0 +1,9 @@ +title: "[pallet_contracts] mark lock/unlock_delegate_dependency as stable" + +doc: + - audience: Runtime Dev + description: | + Lock and unlock delegate dependency are stable now, so we can mark them as such. + +crates: + - name: pallet-contracts diff --git a/substrate/frame/contracts/src/wasm/runtime.rs b/substrate/frame/contracts/src/wasm/runtime.rs index f440c818166..402ff78dcde 100644 --- a/substrate/frame/contracts/src/wasm/runtime.rs +++ b/substrate/frame/contracts/src/wasm/runtime.rs @@ -2305,7 +2305,6 @@ pub mod env { /// Adds a new delegate dependency to the contract. /// See [`pallet_contracts_uapi::HostFn::lock_delegate_dependency`]. - #[unstable] fn lock_delegate_dependency(ctx: _, memory: _, code_hash_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::LockDelegateDependency)?; let code_hash = ctx.read_sandbox_memory_as(memory, code_hash_ptr)?; @@ -2315,7 +2314,6 @@ pub mod env { /// Removes the delegate dependency from the contract. /// see [`pallet_contracts_uapi::HostFn::unlock_delegate_dependency`]. - #[unstable] fn unlock_delegate_dependency(ctx: _, memory: _, code_hash_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::UnlockDelegateDependency)?; let code_hash = ctx.read_sandbox_memory_as(memory, code_hash_ptr)?; -- GitLab From 629506ce061db76d31d4f7a81f4a497752b27259 Mon Sep 17 00:00:00 2001 From: Muharem Date: Thu, 7 Mar 2024 16:13:17 +0100 Subject: [PATCH 008/187] Deprecate xcm::body::TREASURER_INDEX constant, use standard Treasury varian instead (#3608) Deprecate the `xcm::body::TREASURER_INDEX` constant and use the standard Treasury variant from the `xcm::BodyId` type instead. To align with the production runtimes: https://github.com/polkadot-fellows/runtimes/pull/149 --- .../collectives/collectives-westend/src/xcm_config.rs | 2 +- polkadot/runtime/westend/constants/src/lib.rs | 2 ++ polkadot/runtime/westend/src/xcm_config.rs | 6 ++---- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs index cc25cbda0a4..87f637d5b59 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs @@ -59,7 +59,7 @@ parameter_types! { pub const GovernanceLocation: Location = Location::parent(); pub const FellowshipAdminBodyId: BodyId = BodyId::Index(xcm_constants::body::FELLOWSHIP_ADMIN_INDEX); pub AssetHub: Location = (Parent, Parachain(1000)).into(); - pub const TreasurerBodyId: BodyId = BodyId::Index(xcm_constants::body::TREASURER_INDEX); + pub const TreasurerBodyId: BodyId = BodyId::Treasury; pub AssetHubUsdtId: AssetId = (PalletInstance(50), GeneralIndex(1984)).into(); pub UsdtAssetHub: LocatableAssetId = LocatableAssetId { location: AssetHub::get(), diff --git a/polkadot/runtime/westend/constants/src/lib.rs b/polkadot/runtime/westend/constants/src/lib.rs index 3bc27177d7a..c98f4b114fd 100644 --- a/polkadot/runtime/westend/constants/src/lib.rs +++ b/polkadot/runtime/westend/constants/src/lib.rs @@ -130,6 +130,8 @@ pub mod xcm { const ROOT_INDEX: u32 = 0; // The bodies corresponding to the Polkadot OpenGov Origins. pub const FELLOWSHIP_ADMIN_INDEX: u32 = 1; + #[deprecated = "Will be removed after August 2024; Use `xcm::latest::BodyId::Treasury` \ + instead"] pub const TREASURER_INDEX: u32 = 2; } } diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index c3aa75a86a4..c57af987ca7 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -34,9 +34,7 @@ use runtime_common::{ }; use sp_core::ConstU32; use westend_runtime_constants::{ - currency::CENTS, - system_parachain::*, - xcm::body::{FELLOWSHIP_ADMIN_INDEX, TREASURER_INDEX}, + currency::CENTS, system_parachain::*, xcm::body::FELLOWSHIP_ADMIN_INDEX, }; use xcm::latest::prelude::*; use xcm_builder::{ @@ -231,7 +229,7 @@ parameter_types! { // FellowshipAdmin pluralistic body. pub const FellowshipAdminBodyId: BodyId = BodyId::Index(FELLOWSHIP_ADMIN_INDEX); // `Treasurer` pluralistic body. - pub const TreasurerBodyId: BodyId = BodyId::Index(TREASURER_INDEX); + pub const TreasurerBodyId: BodyId = BodyId::Treasury; } /// Type to convert the `GeneralAdmin` origin to a Plurality `Location` value. -- GitLab From f4fbddec420384e3550703ea7c9db3ea923f66e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Andr=C3=A9s=20Dorado=20Su=C3=A1rez?= Date: Thu, 7 Mar 2024 18:19:52 -0500 Subject: [PATCH 009/187] fix(pallet-benchmarking): split test functions in v2 (#3574) Closes #376 --------- Co-authored-by: command-bot <> --- .../collator-selection/src/benchmarking.rs | 4 +- .../collective-content/src/benchmarking.rs | 2 +- .../runtime/common/src/identity_migrator.rs | 2 +- .../parachains/src/hrmp/benchmarking.rs | 2 +- prdoc/pr_3574.prdoc | 23 +++++++++++ substrate/frame/alliance/src/benchmarking.rs | 2 +- substrate/frame/identity/src/benchmarking.rs | 4 +- substrate/frame/lottery/src/benchmarking.rs | 1 - .../frame/support/procedural/src/benchmark.rs | 38 ++++++++++++++++++- .../system/benchmarking/src/extensions.rs | 2 +- .../frame/system/benchmarking/src/lib.rs | 2 +- 11 files changed, 67 insertions(+), 15 deletions(-) create mode 100644 prdoc/pr_3574.prdoc diff --git a/cumulus/pallets/collator-selection/src/benchmarking.rs b/cumulus/pallets/collator-selection/src/benchmarking.rs index 2c40f4dd0ea..e2af74a6e60 100644 --- a/cumulus/pallets/collator-selection/src/benchmarking.rs +++ b/cumulus/pallets/collator-selection/src/benchmarking.rs @@ -22,9 +22,7 @@ use super::*; #[allow(unused)] use crate::Pallet as CollatorSelection; use codec::Decode; -use frame_benchmarking::{ - account, impl_benchmark_test_suite, v2::*, whitelisted_caller, BenchmarkError, -}; +use frame_benchmarking::{account, v2::*, whitelisted_caller, BenchmarkError}; use frame_support::traits::{Currency, EnsureOrigin, Get, ReservableCurrency}; use frame_system::{pallet_prelude::BlockNumberFor, EventRecord, RawOrigin}; use pallet_authorship::EventHandler; diff --git a/cumulus/parachains/pallets/collective-content/src/benchmarking.rs b/cumulus/parachains/pallets/collective-content/src/benchmarking.rs index 943386a8427..3d6bf073778 100644 --- a/cumulus/parachains/pallets/collective-content/src/benchmarking.rs +++ b/cumulus/parachains/pallets/collective-content/src/benchmarking.rs @@ -16,7 +16,7 @@ //! The pallet benchmarks. use super::{Pallet as CollectiveContent, *}; -use frame_benchmarking::{impl_benchmark_test_suite, v2::*}; +use frame_benchmarking::v2::*; use frame_support::traits::EnsureOrigin; fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { diff --git a/polkadot/runtime/common/src/identity_migrator.rs b/polkadot/runtime/common/src/identity_migrator.rs index 0dfb03b06ba..bf334a63e95 100644 --- a/polkadot/runtime/common/src/identity_migrator.rs +++ b/polkadot/runtime/common/src/identity_migrator.rs @@ -31,7 +31,7 @@ use pallet_identity; use sp_core::Get; #[cfg(feature = "runtime-benchmarks")] -use frame_benchmarking::{account, impl_benchmark_test_suite, v2::*, BenchmarkError}; +use frame_benchmarking::{account, v2::*, BenchmarkError}; pub trait WeightInfo { fn reap_identity(r: u32, s: u32) -> Weight; diff --git a/polkadot/runtime/parachains/src/hrmp/benchmarking.rs b/polkadot/runtime/parachains/src/hrmp/benchmarking.rs index 2cb49c88d43..c6baf2f30cf 100644 --- a/polkadot/runtime/parachains/src/hrmp/benchmarking.rs +++ b/polkadot/runtime/parachains/src/hrmp/benchmarking.rs @@ -22,7 +22,7 @@ use crate::{ paras::{Pallet as Paras, ParaKind, ParachainsCache}, shared::Pallet as Shared, }; -use frame_benchmarking::{impl_benchmark_test_suite, v2::*, whitelisted_caller}; +use frame_benchmarking::{v2::*, whitelisted_caller}; use frame_support::{assert_ok, traits::Currency}; type BalanceOf = diff --git a/prdoc/pr_3574.prdoc b/prdoc/pr_3574.prdoc new file mode 100644 index 00000000000..99868ea8a13 --- /dev/null +++ b/prdoc/pr_3574.prdoc @@ -0,0 +1,23 @@ +title: Generate test functions for each benchmark with benchmarking v2 + +doc: + - audience: Runtime Dev + description: | + This PR fixes an issue where using `impl_benchmark_test_suite` macro + within modules that use the benchmarking v2 macros (`#[benchmarks]` + and `#[instance_benchmarks]`) always produced a single test called + `test_benchmarks` instead of a separate benchmark test for every + benchmark (noted with the `#[benchmark]` macro). + + By using this macro from now on, new tests will be created named + `test_benchmark_{name}` where `name` is the name of the benchmark + function. Those tests will be nested inside the module intended for + benchmark functions. + + Also, when using `impl_benchmark_test_suite` inside the module, + the import of such marco will not be necessary, so any explicit + import of it will be marked as unused, the same way it works for + v1 macros so far. + +crates: + - name: frame-support-procedural diff --git a/substrate/frame/alliance/src/benchmarking.rs b/substrate/frame/alliance/src/benchmarking.rs index 9fe0e29b42c..4ccd0fc08f6 100644 --- a/substrate/frame/alliance/src/benchmarking.rs +++ b/substrate/frame/alliance/src/benchmarking.rs @@ -26,7 +26,7 @@ use core::{ }; use sp_runtime::traits::{Bounded, Hash, StaticLookup}; -use frame_benchmarking::{account, impl_benchmark_test_suite, v2::*, BenchmarkError}; +use frame_benchmarking::{account, v2::*, BenchmarkError}; use frame_support::traits::{EnsureOrigin, Get, UnfilteredDispatchable}; use frame_system::{pallet_prelude::BlockNumberFor, Pallet as System, RawOrigin as SystemOrigin}; diff --git a/substrate/frame/identity/src/benchmarking.rs b/substrate/frame/identity/src/benchmarking.rs index fe2fb0b0489..e0b45eeecd1 100644 --- a/substrate/frame/identity/src/benchmarking.rs +++ b/substrate/frame/identity/src/benchmarking.rs @@ -23,9 +23,7 @@ use super::*; use crate::Pallet as Identity; use codec::Encode; -use frame_benchmarking::{ - account, impl_benchmark_test_suite, v2::*, whitelisted_caller, BenchmarkError, -}; +use frame_benchmarking::{account, v2::*, whitelisted_caller, BenchmarkError}; use frame_support::{ assert_ok, ensure, traits::{EnsureOrigin, Get, OnFinalize, OnInitialize}, diff --git a/substrate/frame/lottery/src/benchmarking.rs b/substrate/frame/lottery/src/benchmarking.rs index 1510d250dbe..123b425b976 100644 --- a/substrate/frame/lottery/src/benchmarking.rs +++ b/substrate/frame/lottery/src/benchmarking.rs @@ -23,7 +23,6 @@ use super::*; use crate::Pallet as Lottery; use frame_benchmarking::{ - impl_benchmark_test_suite, v1::{account, whitelisted_caller, BenchmarkError}, v2::*, }; diff --git a/substrate/frame/support/procedural/src/benchmark.rs b/substrate/frame/support/procedural/src/benchmark.rs index 6ded82d91aa..d16ad2aaa51 100644 --- a/substrate/frame/support/procedural/src/benchmark.rs +++ b/substrate/frame/support/procedural/src/benchmark.rs @@ -431,7 +431,7 @@ pub fn benchmarks( let mut benchmarks_by_name_mappings: Vec = Vec::new(); let test_idents: Vec = benchmark_names_str .iter() - .map(|n| Ident::new(format!("test_{}", n).as_str(), Span::call_site())) + .map(|n| Ident::new(format!("test_benchmark_{}", n).as_str(), Span::call_site())) .collect(); for i in 0..benchmark_names.len() { let name_ident = &benchmark_names[i]; @@ -441,6 +441,37 @@ pub fn benchmarks( benchmarks_by_name_mappings.push(quote!(#name_str => Self::#test_ident())) } + let impl_test_function = content + .iter_mut() + .find_map(|item| { + let Item::Macro(item_macro) = item else { + return None; + }; + + if !item_macro + .mac + .path + .segments + .iter() + .any(|s| s.ident == "impl_benchmark_test_suite") + { + return None; + } + + let tokens = item_macro.mac.tokens.clone(); + *item = Item::Verbatim(quote! {}); + + Some(quote! { + impl_test_function!( + (#( {} #benchmark_names )*) + (#( #extra_benchmark_names )*) + (#( #skip_meta_benchmark_names )*) + #tokens + ); + }) + }) + .unwrap_or(quote! {}); + // emit final quoted tokens let res = quote! { #(#mod_attrs) @@ -676,6 +707,8 @@ pub fn benchmarks( } } } + + #impl_test_function } #mod_vis use #mod_name::*; }; @@ -733,7 +766,8 @@ fn expand_benchmark( let setup_stmts = benchmark_def.setup_stmts; let verify_stmts = benchmark_def.verify_stmts; let last_stmt = benchmark_def.last_stmt; - let test_ident = Ident::new(format!("test_{}", name.to_string()).as_str(), Span::call_site()); + let test_ident = + Ident::new(format!("test_benchmark_{}", name.to_string()).as_str(), Span::call_site()); // unroll params (prepare for quoting) let unrolled = UnrolledParams::from(&benchmark_def.params); diff --git a/substrate/frame/system/benchmarking/src/extensions.rs b/substrate/frame/system/benchmarking/src/extensions.rs index 1721501dead..bfc3b4343a6 100644 --- a/substrate/frame/system/benchmarking/src/extensions.rs +++ b/substrate/frame/system/benchmarking/src/extensions.rs @@ -19,7 +19,7 @@ #![cfg(feature = "runtime-benchmarks")] -use frame_benchmarking::{account, impl_benchmark_test_suite, v2::*, BenchmarkError}; +use frame_benchmarking::{account, v2::*, BenchmarkError}; use frame_support::{ dispatch::{DispatchClass, DispatchInfo, PostDispatchInfo}, weights::Weight, diff --git a/substrate/frame/system/benchmarking/src/lib.rs b/substrate/frame/system/benchmarking/src/lib.rs index ebd16275bcb..c9f0869d3bc 100644 --- a/substrate/frame/system/benchmarking/src/lib.rs +++ b/substrate/frame/system/benchmarking/src/lib.rs @@ -21,7 +21,7 @@ #![cfg(feature = "runtime-benchmarks")] use codec::Encode; -use frame_benchmarking::{impl_benchmark_test_suite, v2::*}; +use frame_benchmarking::v2::*; use frame_support::{dispatch::DispatchClass, storage, traits::Get}; use frame_system::{Call, Pallet as System, RawOrigin}; use sp_core::storage::well_known_keys; -- GitLab From 2aa006e094e248110af14a742d4e2f56b7931959 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Fri, 8 Mar 2024 00:31:59 +0100 Subject: [PATCH 010/187] Refactor polkadot-parachain service for more code reuse (#3511) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a refactoring, no changes to the logic are included (if you find some, report :D). ## Change Overview In https://github.com/paritytech/polkadot-sdk/issues/2455, dependency on actual runtimes was removed for the system parachains. This means that the trait bounds we have on various `start_node_xy` do not check anything anymore, since they all point to the same runtime. Exception is asset-hub-polkadot which uses a different key type. This PR unifies the different nodes as much as possible. `start_node_impl` is doing the heavy lifting and has been made a bit more flexible to support the rpc extension instantiation that was there before. The generics for `Runtime` and `AuraId` have been removed where possible. The fake runtime is imported as `FakeRuntime` to make it very clear to readers that it is not the generic parameter. Multiple nodes where using the same import queue/start_consensus closure, they have been unified. --------- Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Francisco Aguirre Co-authored-by: Adrian Catangiu Co-authored-by: Egor_P Co-authored-by: Dmitry Markin Co-authored-by: Xiliang Chen Co-authored-by: Andrei Eres Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Co-authored-by: Alin Dima Co-authored-by: gupnik Co-authored-by: Liam Aharon Co-authored-by: Dónal Murray --- cumulus/polkadot-parachain/src/command.rs | 84 +- cumulus/polkadot-parachain/src/service.rs | 2329 ++++++--------------- 2 files changed, 717 insertions(+), 1696 deletions(-) diff --git a/cumulus/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs index 4d44879af51..9ba7b7876b3 100644 --- a/cumulus/polkadot-parachain/src/command.rs +++ b/cumulus/polkadot-parachain/src/command.rs @@ -399,7 +399,7 @@ macro_rules! construct_partials { Runtime::AssetHubPolkadot => { let $partials = new_partial::( &$config, - crate::service::aura_build_import_queue::<_, AssetHubPolkadotAuraId>, + crate::service::build_relay_to_aura_import_queue::<_, AssetHubPolkadotAuraId>, )?; $code }, @@ -413,28 +413,21 @@ macro_rules! construct_partials { Runtime::People(_) => { let $partials = new_partial::( &$config, - crate::service::aura_build_import_queue::<_, AuraId>, + crate::service::build_relay_to_aura_import_queue::<_, AuraId>, )?; $code }, Runtime::GluttonWestend | Runtime::Glutton | Runtime::Shell | Runtime::Seedling => { let $partials = new_partial::( &$config, - crate::service::shell_build_import_queue, + crate::service::build_shell_import_queue, )?; $code }, - Runtime::ContractsRococo => { + Runtime::ContractsRococo | Runtime::Penpal(_) | Runtime::Default => { let $partials = new_partial::( &$config, - crate::service::contracts_rococo_build_import_queue, - )?; - $code - }, - Runtime::Penpal(_) | Runtime::Default => { - let $partials = new_partial::( - &$config, - crate::service::rococo_parachain_build_import_queue, + crate::service::build_aura_import_queue, )?; $code }, @@ -450,7 +443,7 @@ macro_rules! construct_async_run { runner.async_run(|$config| { let $components = new_partial::( &$config, - crate::service::aura_build_import_queue::<_, AssetHubPolkadotAuraId>, + crate::service::build_relay_to_aura_import_queue::<_, AssetHubPolkadotAuraId>, )?; let task_manager = $components.task_manager; { $( $code )* }.map(|v| (v, task_manager)) @@ -467,7 +460,7 @@ macro_rules! construct_async_run { runner.async_run(|$config| { let $components = new_partial::( &$config, - crate::service::aura_build_import_queue::<_, AuraId>, + crate::service::build_relay_to_aura_import_queue::<_, AuraId>, )?; let task_manager = $components.task_manager; { $( $code )* }.map(|v| (v, task_manager)) @@ -480,30 +473,20 @@ macro_rules! construct_async_run { runner.async_run(|$config| { let $components = new_partial::( &$config, - crate::service::shell_build_import_queue, + crate::service::build_shell_import_queue, )?; let task_manager = $components.task_manager; { $( $code )* }.map(|v| (v, task_manager)) }) } - Runtime::ContractsRococo => { - runner.async_run(|$config| { - let $components = new_partial::( - &$config, - crate::service::contracts_rococo_build_import_queue, - )?; - let task_manager = $components.task_manager; - { $( $code )* }.map(|v| (v, task_manager)) - }) - }, - Runtime::Penpal(_) | Runtime::Default => { + Runtime::ContractsRococo | Runtime::Penpal(_) | Runtime::Default => { runner.async_run(|$config| { let $components = new_partial::< RuntimeApi, _, >( &$config, - crate::service::rococo_parachain_build_import_queue, + crate::service::build_aura_import_queue, )?; let task_manager = $components.task_manager; { $( $code )* }.map(|v| (v, task_manager)) @@ -715,25 +698,19 @@ pub fn run() -> Result<()> { .map_err(Into::into), CollectivesPolkadot => - crate::service::start_generic_aura_node::< - RuntimeApi, - AuraId, - >(config, polkadot_config, collator_options, id, hwbench) + crate::service::start_generic_aura_node(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0) .map_err(Into::into), CollectivesWestend => - crate::service::start_generic_aura_lookahead_node::< - RuntimeApi, - AuraId, - >(config, polkadot_config, collator_options, id, hwbench) + crate::service::start_generic_aura_lookahead_node(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0) .map_err(Into::into), Seedling | Shell => - crate::service::start_shell_node::( + crate::service::start_shell_node( config, polkadot_config, collator_options, @@ -758,36 +735,24 @@ pub fn run() -> Result<()> { BridgeHub(bridge_hub_runtime_type) => match bridge_hub_runtime_type { chain_spec::bridge_hubs::BridgeHubRuntimeType::Polkadot | chain_spec::bridge_hubs::BridgeHubRuntimeType::PolkadotLocal => - crate::service::start_generic_aura_node::< - RuntimeApi, - AuraId, - >(config, polkadot_config, collator_options, id, hwbench) + crate::service::start_generic_aura_node(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0), chain_spec::bridge_hubs::BridgeHubRuntimeType::Kusama | chain_spec::bridge_hubs::BridgeHubRuntimeType::KusamaLocal => - crate::service::start_generic_aura_node::< - RuntimeApi, - AuraId, - >(config, polkadot_config, collator_options, id, hwbench) + crate::service::start_generic_aura_node(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0), chain_spec::bridge_hubs::BridgeHubRuntimeType::Westend | chain_spec::bridge_hubs::BridgeHubRuntimeType::WestendLocal | chain_spec::bridge_hubs::BridgeHubRuntimeType::WestendDevelopment => - crate::service::start_generic_aura_lookahead_node::< - RuntimeApi, - AuraId, - >(config, polkadot_config, collator_options, id, hwbench) + crate::service::start_generic_aura_lookahead_node(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0), chain_spec::bridge_hubs::BridgeHubRuntimeType::Rococo | chain_spec::bridge_hubs::BridgeHubRuntimeType::RococoLocal | chain_spec::bridge_hubs::BridgeHubRuntimeType::RococoDevelopment => - crate::service::start_generic_aura_lookahead_node::< - RuntimeApi, - AuraId, - >(config, polkadot_config, collator_options, id, hwbench) + crate::service::start_generic_aura_lookahead_node(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0), } @@ -800,10 +765,7 @@ pub fn run() -> Result<()> { chain_spec::coretime::CoretimeRuntimeType::Westend | chain_spec::coretime::CoretimeRuntimeType::WestendLocal | chain_spec::coretime::CoretimeRuntimeType::WestendDevelopment => - crate::service::start_generic_aura_lookahead_node::< - RuntimeApi, - AuraId, - >(config, polkadot_config, collator_options, id, hwbench) + crate::service::start_generic_aura_lookahead_node(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0), } @@ -822,10 +784,7 @@ pub fn run() -> Result<()> { .map_err(Into::into), Glutton | GluttonWestend => - crate::service::start_basic_lookahead_node::< - RuntimeApi, - AuraId, - >(config, polkadot_config, collator_options, id, hwbench) + crate::service::start_basic_lookahead_node(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0) .map_err(Into::into), @@ -837,10 +796,7 @@ pub fn run() -> Result<()> { chain_spec::people::PeopleRuntimeType::Westend | chain_spec::people::PeopleRuntimeType::WestendLocal | chain_spec::people::PeopleRuntimeType::WestendDevelopment => - crate::service::start_generic_aura_lookahead_node::< - RuntimeApi, - AuraId, - >(config, polkadot_config, collator_options, id, hwbench) + crate::service::start_generic_aura_lookahead_node(config, polkadot_config, collator_options, id, hwbench) .await .map(|r| r.0), } diff --git a/cumulus/polkadot-parachain/src/service.rs b/cumulus/polkadot-parachain/src/service.rs index 386551102e4..ddf595ca70c 100644 --- a/cumulus/polkadot-parachain/src/service.rs +++ b/cumulus/polkadot-parachain/src/service.rs @@ -36,12 +36,13 @@ use cumulus_primitives_core::{ ParaId, }; use cumulus_relay_chain_interface::{OverseerHandle, RelayChainInterface}; +use sc_rpc::DenyUnsafe; use sp_core::Pair; use jsonrpsee::RpcModule; -use crate::{fake_runtime_api::aura::RuntimeApi, rpc}; -pub use parachains_common::{AccountId, Balance, Block, Hash, Header, Nonce}; +use crate::{fake_runtime_api::aura::RuntimeApi as FakeRuntimeApi, rpc}; +pub use parachains_common::{AccountId, AuraId, Balance, Block, Hash, Header, Nonce}; use cumulus_client_consensus_relay_chain::Verifier as RelayChainVerifier; use futures::{lock::Mutex, prelude::*}; @@ -85,141 +86,6 @@ type ParachainBackend = TFullBackend; type ParachainBlockImport = TParachainBlockImport>, ParachainBackend>; -/// Native executor instance. -pub struct ShellRuntimeExecutor; - -impl sc_executor::NativeExecutionDispatch for ShellRuntimeExecutor { - type ExtendHostFunctions = (); - - fn dispatch(method: &str, data: &[u8]) -> Option> { - shell_runtime::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - shell_runtime::native_version() - } -} - -/// Native Asset Hub Westend (Westmint) executor instance. -pub struct AssetHubWestendExecutor; -impl sc_executor::NativeExecutionDispatch for AssetHubWestendExecutor { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - - fn dispatch(method: &str, data: &[u8]) -> Option> { - asset_hub_westend_runtime::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - asset_hub_westend_runtime::native_version() - } -} - -/// Native Westend Collectives executor instance. -pub struct CollectivesWestendRuntimeExecutor; - -impl sc_executor::NativeExecutionDispatch for CollectivesWestendRuntimeExecutor { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - - fn dispatch(method: &str, data: &[u8]) -> Option> { - collectives_westend_runtime::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - collectives_westend_runtime::native_version() - } -} - -/// Native BridgeHubRococo executor instance. -pub struct BridgeHubRococoRuntimeExecutor; -impl sc_executor::NativeExecutionDispatch for BridgeHubRococoRuntimeExecutor { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - - fn dispatch(method: &str, data: &[u8]) -> Option> { - bridge_hub_rococo_runtime::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - bridge_hub_rococo_runtime::native_version() - } -} - -/// Native `CoretimeRococo` executor instance. -pub struct CoretimeRococoRuntimeExecutor; -impl sc_executor::NativeExecutionDispatch for CoretimeRococoRuntimeExecutor { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - fn dispatch(method: &str, data: &[u8]) -> Option> { - coretime_rococo_runtime::api::dispatch(method, data) - } - fn native_version() -> sc_executor::NativeVersion { - coretime_rococo_runtime::native_version() - } -} - -/// Native `CoretimeWestend` executor instance. -pub struct CoretimeWestendRuntimeExecutor; -impl sc_executor::NativeExecutionDispatch for CoretimeWestendRuntimeExecutor { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - fn dispatch(method: &str, data: &[u8]) -> Option> { - coretime_westend_runtime::api::dispatch(method, data) - } - fn native_version() -> sc_executor::NativeVersion { - coretime_westend_runtime::native_version() - } -} - -/// Native contracts executor instance. -pub struct ContractsRococoRuntimeExecutor; -impl sc_executor::NativeExecutionDispatch for ContractsRococoRuntimeExecutor { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - - fn dispatch(method: &str, data: &[u8]) -> Option> { - contracts_rococo_runtime::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - contracts_rococo_runtime::native_version() - } -} - -/// Native Westend Glutton executor instance. -pub struct GluttonWestendRuntimeExecutor; - -impl sc_executor::NativeExecutionDispatch for GluttonWestendRuntimeExecutor { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - - fn dispatch(method: &str, data: &[u8]) -> Option> { - glutton_westend_runtime::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - glutton_westend_runtime::native_version() - } -} - -/// Native `PeopleWestend` executor instance. -pub struct PeopleWestendRuntimeExecutor; -impl sc_executor::NativeExecutionDispatch for PeopleWestendRuntimeExecutor { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - fn dispatch(method: &str, data: &[u8]) -> Option> { - people_westend_runtime::api::dispatch(method, data) - } - fn native_version() -> sc_executor::NativeVersion { - people_westend_runtime::native_version() - } -} - -/// Native `PeopleRococo` executor instance. -pub struct PeopleRococoRuntimeExecutor; -impl sc_executor::NativeExecutionDispatch for PeopleRococoRuntimeExecutor { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - fn dispatch(method: &str, data: &[u8]) -> Option> { - people_rococo_runtime::api::dispatch(method, data) - } - fn native_version() -> sc_executor::NativeVersion { - people_rococo_runtime::native_version() - } -} - /// Assembly of PartialComponents (enough to run chain ops subcommands) pub type Service = PartialComponents< ParachainClient, @@ -323,12 +189,11 @@ where }) } -/// Start a shell node with the given parachain `Configuration` and relay chain `Configuration`. +/// Start a node with the given parachain `Configuration` and relay chain `Configuration`. /// -/// This is the actual implementation that is abstract over the executor and the runtime api for -/// shell nodes. +/// This is the actual implementation that is abstract over the executor and the runtime api. #[sc_tracing::logging::prefix_logs_with("Parachain")] -async fn start_shell_node_impl( +async fn start_node_impl( parachain_config: Configuration, polkadot_config: Configuration, collator_options: CollatorOptions, @@ -347,8 +212,15 @@ where + sp_api::ApiExt + sp_offchain::OffchainWorkerApi + sp_block_builder::BlockBuilder - + cumulus_primitives_core::CollectCollationInfo, - RB: Fn(Arc>) -> Result, sc_service::Error> + + cumulus_primitives_core::CollectCollationInfo + + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + + frame_rpc_system::AccountNonceApi, + RB: Fn( + DenyUnsafe, + Arc>, + Arc, + Arc>>, + ) -> Result, sc_service::Error> + 'static, BIQ: FnOnce( Arc>, @@ -372,6 +244,7 @@ where CollatorPair, OverseerHandle, Arc>) + Send + Sync>, + Arc, ) -> Result<(), sc_service::Error>, { let parachain_config = prepare_node_config(parachain_config); @@ -383,7 +256,6 @@ where let backend = params.backend.clone(); let mut task_manager = params.task_manager; - let (relay_chain_interface, collator_key) = build_relay_chain_interface( polkadot_config, ¶chain_config, @@ -415,8 +287,20 @@ where }) .await?; - let rpc_client = client.clone(); - let rpc_builder = Box::new(move |_, _| rpc_ext_builder(rpc_client.clone())); + let rpc_builder = { + let client = client.clone(); + let transaction_pool = transaction_pool.clone(); + let backend_for_rpc = backend.clone(); + + Box::new(move |deny_unsafe, _| { + rpc_ext_builder( + deny_unsafe, + client.clone(), + backend_for_rpc.clone(), + transaction_pool.clone(), + ) + }) + }; sc_service::spawn_tasks(sc_service::SpawnTasksParams { rpc_builder, @@ -493,6 +377,7 @@ where collator_key.expect("Command line arguments do not allow this. qed"), overseer_handle, announce_block, + backend.clone(), )?; } @@ -501,676 +386,179 @@ where Ok((task_manager, client)) } -/// Start a node with the given parachain `Configuration` and relay chain `Configuration`. -/// -/// This is the actual implementation that is abstract over the executor and the runtime api. -#[sc_tracing::logging::prefix_logs_with("Parachain")] -async fn start_node_impl( +/// Build the import queue for Aura-based runtimes. +pub fn build_aura_import_queue( + client: Arc>, + block_import: ParachainBlockImport, + config: &Configuration, + telemetry: Option, + task_manager: &TaskManager, +) -> Result, sc_service::Error> { + let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; + + cumulus_client_consensus_aura::import_queue::< + sp_consensus_aura::sr25519::AuthorityPair, + _, + _, + _, + _, + _, + >(cumulus_client_consensus_aura::ImportQueueParams { + block_import, + client, + create_inherent_data_providers: move |_, _| async move { + let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); + + let slot = + sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( + *timestamp, + slot_duration, + ); + + Ok((slot, timestamp)) + }, + registry: config.prometheus_registry(), + spawner: &task_manager.spawn_essential_handle(), + telemetry, + }) + .map_err(Into::into) +} + +/// Start a rococo parachain node. +pub async fn start_rococo_parachain_node( parachain_config: Configuration, polkadot_config: Configuration, collator_options: CollatorOptions, - sybil_resistance_level: CollatorSybilResistance, para_id: ParaId, - _rpc_ext_builder: RB, - build_import_queue: BIQ, - start_consensus: SC, hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> +) -> sc_service::error::Result<(TaskManager, Arc>)> { + start_node_impl::( + parachain_config, + polkadot_config, + collator_options, + CollatorSybilResistance::Resistant, // Aura + para_id, + build_parachain_rpc_extensions::, + build_aura_import_queue, + start_lookahead_aura_consensus, + hwbench, + ) + .await +} + +/// Build the import queue for the shell runtime. +pub fn build_shell_import_queue( + client: Arc>, + block_import: ParachainBlockImport, + config: &Configuration, + _: Option, + task_manager: &TaskManager, +) -> Result, sc_service::Error> { + cumulus_client_consensus_relay_chain::import_queue( + client, + block_import, + |_, _| async { Ok(()) }, + &task_manager.spawn_essential_handle(), + config.prometheus_registry(), + ) + .map_err(Into::into) +} + +fn build_parachain_rpc_extensions( + deny_unsafe: sc_rpc::DenyUnsafe, + client: Arc>, + backend: Arc, + pool: Arc>>, +) -> Result, sc_service::Error> where RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue - + sp_api::Metadata - + sp_session::SessionKeys - + sp_api::ApiExt - + sp_offchain::OffchainWorkerApi + sp_block_builder::BlockBuilder - + cumulus_primitives_core::CollectCollationInfo + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + frame_rpc_system::AccountNonceApi, - RB: Fn(Arc>) -> Result, sc_service::Error>, - BIQ: FnOnce( - Arc>, - ParachainBlockImport, - &Configuration, - Option, - &TaskManager, - ) -> Result, sc_service::Error>, - SC: FnOnce( - Arc>, - ParachainBlockImport, - Option<&Registry>, - Option, - &TaskManager, - Arc, - Arc>>, - Arc>, - KeystorePtr, - Duration, - ParaId, - CollatorPair, - OverseerHandle, - Arc>) + Send + Sync>, - Arc, - ) -> Result<(), sc_service::Error>, { - let parachain_config = prepare_node_config(parachain_config); + let deps = rpc::FullDeps { client, pool, deny_unsafe }; - let params = new_partial::(¶chain_config, build_import_queue)?; - let (block_import, mut telemetry, telemetry_worker_handle) = params.other; + rpc::create_full(deps, backend).map_err(Into::into) +} - let client = params.client.clone(); - let backend = params.backend.clone(); +fn build_contracts_rpc_extensions( + deny_unsafe: sc_rpc::DenyUnsafe, + client: Arc>, + _backend: Arc, + pool: Arc>>, +) -> Result, sc_service::Error> { + let deps = crate::rpc::FullDeps { client: client.clone(), pool: pool.clone(), deny_unsafe }; - let mut task_manager = params.task_manager; - let (relay_chain_interface, collator_key) = build_relay_chain_interface( + crate::rpc::create_contracts_rococo(deps).map_err(Into::into) +} + +/// Start a polkadot-shell parachain node. +pub async fn start_shell_node( + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, +) -> sc_service::error::Result<(TaskManager, Arc>)> { + start_node_impl::( + parachain_config, polkadot_config, - ¶chain_config, - telemetry_worker_handle, - &mut task_manager, - collator_options.clone(), - hwbench.clone(), + collator_options, + CollatorSybilResistance::Unresistant, // free-for-all consensus + para_id, + |_, _, _, _| Ok(RpcModule::new(())), + build_shell_import_queue, + start_relay_chain_consensus, + hwbench, ) .await - .map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?; - - let validator = parachain_config.role.is_authority(); - let prometheus_registry = parachain_config.prometheus_registry().cloned(); - let transaction_pool = params.transaction_pool.clone(); - let import_queue_service = params.import_queue.service(); - let net_config = FullNetworkConfiguration::new(¶chain_config.network); - - let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = - build_network(BuildNetworkParams { - parachain_config: ¶chain_config, - net_config, - client: client.clone(), - transaction_pool: transaction_pool.clone(), - para_id, - spawn_handle: task_manager.spawn_handle(), - relay_chain_interface: relay_chain_interface.clone(), - import_queue: params.import_queue, - sybil_resistance_level, - }) - .await?; +} - let rpc_builder = { - let client = client.clone(); - let transaction_pool = transaction_pool.clone(); +enum BuildOnAccess { + Uninitialized(Option R + Send + Sync>>), + Initialized(R), +} - let backend_for_rpc = backend.clone(); - Box::new(move |deny_unsafe, _| { - let deps = rpc::FullDeps { - client: client.clone(), - pool: transaction_pool.clone(), - deny_unsafe, - }; +impl BuildOnAccess { + fn get_mut(&mut self) -> &mut R { + loop { + match self { + Self::Uninitialized(f) => { + *self = Self::Initialized((f.take().unwrap())()); + }, + Self::Initialized(ref mut r) => return r, + } + } + } +} - rpc::create_full(deps, backend_for_rpc.clone()).map_err(Into::into) - }) - }; +/// Special [`ParachainConsensus`] implementation that waits for the upgrade from +/// shell to a parachain runtime that implements Aura. +struct WaitForAuraConsensus { + client: Arc, + aura_consensus: Arc>>>>, + relay_chain_consensus: Arc>>>, + _phantom: PhantomData, +} - sc_service::spawn_tasks(sc_service::SpawnTasksParams { - rpc_builder, - client: client.clone(), - transaction_pool: transaction_pool.clone(), - task_manager: &mut task_manager, - config: parachain_config, - keystore: params.keystore_container.keystore(), - backend: backend.clone(), - network: network.clone(), - sync_service: sync_service.clone(), - system_rpc_tx, - tx_handler_controller, - telemetry: telemetry.as_mut(), - })?; - - if let Some(hwbench) = hwbench { - sc_sysinfo::print_hwbench(&hwbench); - if validator { - warn_if_slow_hardware(&hwbench); - } - - if let Some(ref mut telemetry) = telemetry { - let telemetry_handle = telemetry.handle(); - task_manager.spawn_handle().spawn( - "telemetry_hwbench", - None, - sc_sysinfo::initialize_hwbench_telemetry(telemetry_handle, hwbench), - ); +impl Clone for WaitForAuraConsensus { + fn clone(&self) -> Self { + Self { + client: self.client.clone(), + aura_consensus: self.aura_consensus.clone(), + relay_chain_consensus: self.relay_chain_consensus.clone(), + _phantom: PhantomData, } } - - let announce_block = { - let sync_service = sync_service.clone(); - Arc::new(move |hash, data| sync_service.announce_block(hash, data)) - }; - - let relay_chain_slot_duration = Duration::from_secs(6); - - let overseer_handle = relay_chain_interface - .overseer_handle() - .map_err(|e| sc_service::Error::Application(Box::new(e)))?; - - start_relay_chain_tasks(StartRelayChainTasksParams { - client: client.clone(), - announce_block: announce_block.clone(), - para_id, - relay_chain_interface: relay_chain_interface.clone(), - task_manager: &mut task_manager, - da_recovery_profile: if validator { - DARecoveryProfile::Collator - } else { - DARecoveryProfile::FullNode - }, - import_queue: import_queue_service, - relay_chain_slot_duration, - recovery_handle: Box::new(overseer_handle.clone()), - sync_service: sync_service.clone(), - })?; - - if validator { - start_consensus( - client.clone(), - block_import, - prometheus_registry.as_ref(), - telemetry.as_ref().map(|t| t.handle()), - &task_manager, - relay_chain_interface.clone(), - transaction_pool, - sync_service.clone(), - params.keystore_container.keystore(), - relay_chain_slot_duration, - para_id, - collator_key.expect("Command line arguments do not allow this. qed"), - overseer_handle, - announce_block, - backend.clone(), - )?; - } - - start_network.start_network(); - - Ok((task_manager, client)) } -/// Start a node with the given parachain `Configuration` and relay chain `Configuration`. -/// -/// This is the actual implementation that is abstract over the executor and the runtime api. -/// -/// This node is basic in the sense that it doesn't support functionality like transaction -/// payment. Intended to replace start_shell_node in use for glutton, shell, and seedling. -#[sc_tracing::logging::prefix_logs_with("Parachain")] -async fn start_basic_lookahead_node_impl( - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - sybil_resistance_level: CollatorSybilResistance, - para_id: ParaId, - rpc_ext_builder: RB, - build_import_queue: BIQ, - start_consensus: SC, - hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> +#[async_trait::async_trait] +impl ParachainConsensus for WaitForAuraConsensus where - RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, - RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue - + sp_api::Metadata - + sp_session::SessionKeys - + sp_api::ApiExt - + sp_offchain::OffchainWorkerApi - + sp_block_builder::BlockBuilder - + cumulus_primitives_core::CollectCollationInfo - + frame_rpc_system::AccountNonceApi, - RB: Fn(Arc>) -> Result, sc_service::Error> - + 'static, - BIQ: FnOnce( - Arc>, - ParachainBlockImport, - &Configuration, - Option, - &TaskManager, - ) -> Result, sc_service::Error>, - SC: FnOnce( - Arc>, - ParachainBlockImport, - Option<&Registry>, - Option, - &TaskManager, - Arc, - Arc>>, - Arc>, - KeystorePtr, - Duration, - ParaId, - CollatorPair, - OverseerHandle, - Arc>) + Send + Sync>, - Arc, - ) -> Result<(), sc_service::Error>, -{ - let parachain_config = prepare_node_config(parachain_config); - - let params = new_partial::(¶chain_config, build_import_queue)?; - let (block_import, mut telemetry, telemetry_worker_handle) = params.other; - - let client = params.client.clone(); - let backend = params.backend.clone(); - - let mut task_manager = params.task_manager; - let (relay_chain_interface, collator_key) = build_relay_chain_interface( - polkadot_config, - ¶chain_config, - telemetry_worker_handle, - &mut task_manager, - collator_options.clone(), - hwbench.clone(), - ) - .await - .map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?; - - let validator = parachain_config.role.is_authority(); - let prometheus_registry = parachain_config.prometheus_registry().cloned(); - let transaction_pool = params.transaction_pool.clone(); - let import_queue_service = params.import_queue.service(); - let net_config = FullNetworkConfiguration::new(¶chain_config.network); - - let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = - build_network(BuildNetworkParams { - parachain_config: ¶chain_config, - net_config, - client: client.clone(), - transaction_pool: transaction_pool.clone(), - para_id, - spawn_handle: task_manager.spawn_handle(), - relay_chain_interface: relay_chain_interface.clone(), - import_queue: params.import_queue, - sybil_resistance_level, - }) - .await?; - - let rpc_client = client.clone(); - let rpc_builder = Box::new(move |_, _| rpc_ext_builder(rpc_client.clone())); - - sc_service::spawn_tasks(sc_service::SpawnTasksParams { - rpc_builder, - client: client.clone(), - transaction_pool: transaction_pool.clone(), - task_manager: &mut task_manager, - config: parachain_config, - keystore: params.keystore_container.keystore(), - backend: backend.clone(), - network: network.clone(), - sync_service: sync_service.clone(), - system_rpc_tx, - tx_handler_controller, - telemetry: telemetry.as_mut(), - })?; - - if let Some(hwbench) = hwbench { - sc_sysinfo::print_hwbench(&hwbench); - if validator { - warn_if_slow_hardware(&hwbench); - } - - if let Some(ref mut telemetry) = telemetry { - let telemetry_handle = telemetry.handle(); - task_manager.spawn_handle().spawn( - "telemetry_hwbench", - None, - sc_sysinfo::initialize_hwbench_telemetry(telemetry_handle, hwbench), - ); - } - } - - let announce_block = { - let sync_service = sync_service.clone(); - Arc::new(move |hash, data| sync_service.announce_block(hash, data)) - }; - - let relay_chain_slot_duration = Duration::from_secs(6); - - let overseer_handle = relay_chain_interface - .overseer_handle() - .map_err(|e| sc_service::Error::Application(Box::new(e)))?; - - start_relay_chain_tasks(StartRelayChainTasksParams { - client: client.clone(), - announce_block: announce_block.clone(), - para_id, - relay_chain_interface: relay_chain_interface.clone(), - task_manager: &mut task_manager, - da_recovery_profile: if validator { - DARecoveryProfile::Collator - } else { - DARecoveryProfile::FullNode - }, - import_queue: import_queue_service, - relay_chain_slot_duration, - recovery_handle: Box::new(overseer_handle.clone()), - sync_service: sync_service.clone(), - })?; - - if validator { - start_consensus( - client.clone(), - block_import, - prometheus_registry.as_ref(), - telemetry.as_ref().map(|t| t.handle()), - &task_manager, - relay_chain_interface.clone(), - transaction_pool, - sync_service.clone(), - params.keystore_container.keystore(), - relay_chain_slot_duration, - para_id, - collator_key.expect("Command line arguments do not allow this. qed"), - overseer_handle, - announce_block, - backend.clone(), - )?; - } - - start_network.start_network(); - - Ok((task_manager, client)) -} - -/// Build the import queue for the rococo parachain runtime. -pub fn rococo_parachain_build_import_queue( - client: Arc>, - block_import: ParachainBlockImport, - config: &Configuration, - telemetry: Option, - task_manager: &TaskManager, -) -> Result, sc_service::Error> { - let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; - - cumulus_client_consensus_aura::import_queue::< - sp_consensus_aura::sr25519::AuthorityPair, - _, - _, - _, - _, - _, - >(cumulus_client_consensus_aura::ImportQueueParams { - block_import, - client, - create_inherent_data_providers: move |_, _| async move { - let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); - - let slot = - sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( - *timestamp, - slot_duration, - ); - - Ok((slot, timestamp)) - }, - registry: config.prometheus_registry(), - spawner: &task_manager.spawn_essential_handle(), - telemetry, - }) - .map_err(Into::into) -} - -/// Start a rococo parachain node. -pub async fn start_rococo_parachain_node( - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> { - start_node_impl::( - parachain_config, - polkadot_config, - collator_options, - CollatorSybilResistance::Resistant, // Aura - para_id, - |_| Ok(RpcModule::new(())), - rococo_parachain_build_import_queue, - |client, - block_import, - prometheus_registry, - telemetry, - task_manager, - relay_chain_interface, - transaction_pool, - sync_oracle, - keystore, - relay_chain_slot_duration, - para_id, - collator_key, - overseer_handle, - announce_block, - backend| { - let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( - task_manager.spawn_handle(), - client.clone(), - transaction_pool, - prometheus_registry, - telemetry.clone(), - ); - let proposer = Proposer::new(proposer_factory); - - let collator_service = CollatorService::new( - client.clone(), - Arc::new(task_manager.spawn_handle()), - announce_block, - client.clone(), - ); - - let params = AuraParams { - create_inherent_data_providers: move |_, ()| async move { Ok(()) }, - block_import, - para_client: client.clone(), - para_backend: backend.clone(), - relay_client: relay_chain_interface, - code_hash_provider: move |block_hash| { - client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) - }, - sync_oracle, - keystore, - collator_key, - para_id, - overseer_handle, - relay_chain_slot_duration, - proposer, - collator_service, - authoring_duration: Duration::from_millis(1500), - reinitialize: false, - }; - - let fut = aura::run::< - Block, - sp_consensus_aura::sr25519::AuthorityPair, - _, - _, - _, - _, - _, - _, - _, - _, - _, - >(params); - task_manager.spawn_essential_handle().spawn("aura", None, fut); - - Ok(()) - }, - hwbench, - ) - .await -} - -/// Build the import queue for the shell runtime. -pub fn shell_build_import_queue( - client: Arc>, - block_import: ParachainBlockImport, - config: &Configuration, - _: Option, - task_manager: &TaskManager, -) -> Result, sc_service::Error> -where - RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, - RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue - + sp_api::Metadata - + sp_session::SessionKeys - + sp_api::ApiExt - + sp_offchain::OffchainWorkerApi - + sp_block_builder::BlockBuilder, -{ - cumulus_client_consensus_relay_chain::import_queue( - client, - block_import, - |_, _| async { Ok(()) }, - &task_manager.spawn_essential_handle(), - config.prometheus_registry(), - ) - .map_err(Into::into) -} - -/// Start a polkadot-shell parachain node. -pub async fn start_shell_node( - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> -where - RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, - RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue - + sp_api::Metadata - + sp_session::SessionKeys - + sp_api::ApiExt - + sp_offchain::OffchainWorkerApi - + sp_block_builder::BlockBuilder - + cumulus_primitives_core::CollectCollationInfo, -{ - start_shell_node_impl::( - parachain_config, - polkadot_config, - collator_options, - CollatorSybilResistance::Unresistant, // free-for-all consensus - para_id, - |_| Ok(RpcModule::new(())), - shell_build_import_queue, - |client, - block_import, - prometheus_registry, - telemetry, - task_manager, - relay_chain_interface, - transaction_pool, - _sync_oracle, - _keystore, - _relay_chain_slot_duration, - para_id, - collator_key, - overseer_handle, - announce_block| { - let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( - task_manager.spawn_handle(), - client.clone(), - transaction_pool, - prometheus_registry, - telemetry, - ); - - let free_for_all = cumulus_client_consensus_relay_chain::build_relay_chain_consensus( - cumulus_client_consensus_relay_chain::BuildRelayChainConsensusParams { - para_id, - proposer_factory, - block_import, - relay_chain_interface: relay_chain_interface.clone(), - create_inherent_data_providers: move |_, (relay_parent, validation_data)| { - let relay_chain_interface = relay_chain_interface.clone(); - async move { - let parachain_inherent = - cumulus_client_parachain_inherent::ParachainInherentDataProvider::create_at( - relay_parent, - &relay_chain_interface, - &validation_data, - para_id, - ).await; - let parachain_inherent = parachain_inherent.ok_or_else(|| { - Box::::from( - "Failed to create parachain inherent", - ) - })?; - Ok(parachain_inherent) - } - }, - }, - ); - - let spawner = task_manager.spawn_handle(); - - // Required for free-for-all consensus - #[allow(deprecated)] - old_consensus::start_collator_sync(old_consensus::StartCollatorParams { - para_id, - block_status: client.clone(), - announce_block, - overseer_handle, - spawner, - key: collator_key, - parachain_consensus: free_for_all, - runtime_api: client.clone(), - }); - - Ok(()) - }, - hwbench, - ) - .await -} - -enum BuildOnAccess { - Uninitialized(Option R + Send + Sync>>), - Initialized(R), -} - -impl BuildOnAccess { - fn get_mut(&mut self) -> &mut R { - loop { - match self { - Self::Uninitialized(f) => { - *self = Self::Initialized((f.take().unwrap())()); - }, - Self::Initialized(ref mut r) => return r, - } - } - } -} - -/// Special [`ParachainConsensus`] implementation that waits for the upgrade from -/// shell to a parachain runtime that implements Aura. -struct WaitForAuraConsensus { - client: Arc, - aura_consensus: Arc>>>>, - relay_chain_consensus: Arc>>>, - _phantom: PhantomData, -} - -impl Clone for WaitForAuraConsensus { - fn clone(&self) -> Self { - Self { - client: self.client.clone(), - aura_consensus: self.aura_consensus.clone(), - relay_chain_consensus: self.relay_chain_consensus.clone(), - _phantom: PhantomData, - } - } -} - -#[async_trait::async_trait] -impl ParachainConsensus for WaitForAuraConsensus -where - Client: sp_api::ProvideRuntimeApi + Send + Sync, - Client::Api: AuraApi, - AuraId: Send + Codec + Sync, + Client: sp_api::ProvideRuntimeApi + Send + Sync, + Client::Api: AuraApi, + AuraId: Send + Codec + Sync, { async fn produce_candidate( &mut self, @@ -1190,464 +578,56 @@ where .get_mut() .produce_candidate(parent, relay_parent, validation_data) .await - } else { - self.relay_chain_consensus - .lock() - .await - .produce_candidate(parent, relay_parent, validation_data) - .await - } - } -} - -struct Verifier { - client: Arc, - aura_verifier: BuildOnAccess>>, - relay_chain_verifier: Box>, - _phantom: PhantomData, -} - -#[async_trait::async_trait] -impl VerifierT for Verifier -where - Client: sp_api::ProvideRuntimeApi + Send + Sync, - Client::Api: AuraApi, - AuraId: Send + Sync + Codec, -{ - async fn verify( - &mut self, - block_import: BlockImportParams, - ) -> Result, String> { - if self - .client - .runtime_api() - .has_api::>(*block_import.header.parent_hash()) - .unwrap_or(false) - { - self.aura_verifier.get_mut().verify(block_import).await - } else { - self.relay_chain_verifier.verify(block_import).await - } - } -} - -/// Build the import queue for Aura-based runtimes. -pub fn aura_build_import_queue( - client: Arc>, - block_import: ParachainBlockImport, - config: &Configuration, - telemetry_handle: Option, - task_manager: &TaskManager, -) -> Result, sc_service::Error> -where - RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, - RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue - + sp_api::Metadata - + sp_session::SessionKeys - + sp_api::ApiExt - + sp_offchain::OffchainWorkerApi - + sp_block_builder::BlockBuilder - + sp_consensus_aura::AuraApi::Pair as Pair>::Public>, - <::Pair as Pair>::Signature: - TryFrom> + std::hash::Hash + sp_runtime::traits::Member + Codec, -{ - let verifier_client = client.clone(); - - let aura_verifier = move || { - Box::new(cumulus_client_consensus_aura::build_verifier::< - ::Pair, - _, - _, - _, - >(cumulus_client_consensus_aura::BuildVerifierParams { - client: verifier_client.clone(), - create_inherent_data_providers: move |parent_hash, _| { - let cidp_client = verifier_client.clone(); - async move { - let slot_duration = cumulus_client_consensus_aura::slot_duration_at( - &*cidp_client, - parent_hash, - )?; - let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); - - let slot = - sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( - *timestamp, - slot_duration, - ); - - Ok((slot, timestamp)) - } - }, - telemetry: telemetry_handle, - })) as Box<_> - }; - - let relay_chain_verifier = - Box::new(RelayChainVerifier::new(client.clone(), |_, _| async { Ok(()) })) as Box<_>; - - let verifier = Verifier { - client, - relay_chain_verifier, - aura_verifier: BuildOnAccess::Uninitialized(Some(Box::new(aura_verifier))), - _phantom: PhantomData, - }; - - let registry = config.prometheus_registry(); - let spawner = task_manager.spawn_essential_handle(); - - Ok(BasicQueue::new(verifier, Box::new(block_import), None, &spawner, registry)) -} - -/// Start an aura powered parachain node. Some system chains use this. -pub async fn start_generic_aura_node( - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> -where - RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, - RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue - + sp_api::Metadata - + sp_session::SessionKeys - + sp_api::ApiExt - + sp_offchain::OffchainWorkerApi - + sp_block_builder::BlockBuilder - + cumulus_primitives_core::CollectCollationInfo - + sp_consensus_aura::AuraApi::Pair as Pair>::Public> - + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi - + frame_rpc_system::AccountNonceApi, - <::Pair as Pair>::Signature: - TryFrom> + std::hash::Hash + sp_runtime::traits::Member + Codec, -{ - start_node_impl::( - parachain_config, - polkadot_config, - collator_options, - CollatorSybilResistance::Resistant, // Aura - para_id, - |_| Ok(RpcModule::new(())), - aura_build_import_queue::<_, AuraId>, - |client, - block_import, - prometheus_registry, - telemetry, - task_manager, - relay_chain_interface, - transaction_pool, - sync_oracle, - keystore, - relay_chain_slot_duration, - para_id, - collator_key, - overseer_handle, - announce_block, - _backend| { - let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; - - let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( - task_manager.spawn_handle(), - client.clone(), - transaction_pool, - prometheus_registry, - telemetry.clone(), - ); - let proposer = Proposer::new(proposer_factory); - - let collator_service = CollatorService::new( - client.clone(), - Arc::new(task_manager.spawn_handle()), - announce_block, - client.clone(), - ); - - let params = BasicAuraParams { - create_inherent_data_providers: move |_, ()| async move { Ok(()) }, - block_import, - para_client: client, - relay_client: relay_chain_interface, - sync_oracle, - keystore, - collator_key, - para_id, - overseer_handle, - slot_duration, - relay_chain_slot_duration, - proposer, - collator_service, - // Very limited proposal time. - authoring_duration: Duration::from_millis(500), - collation_request_receiver: None, - }; - - let fut = - basic_aura::run::::Pair, _, _, _, _, _, _, _>(params); - task_manager.spawn_essential_handle().spawn("aura", None, fut); - - Ok(()) - }, - hwbench, - ) - .await -} - -/// Uses the lookahead collator to support async backing. -/// -/// Start an aura powered parachain node. Some system chains use this. -pub async fn start_generic_aura_lookahead_node( - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> -where - RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, - RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue - + sp_api::Metadata - + sp_session::SessionKeys - + sp_api::ApiExt - + sp_offchain::OffchainWorkerApi - + sp_block_builder::BlockBuilder - + cumulus_primitives_core::CollectCollationInfo - + sp_consensus_aura::AuraApi::Pair as Pair>::Public> - + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi - + frame_rpc_system::AccountNonceApi - + cumulus_primitives_aura::AuraUnincludedSegmentApi, - <::Pair as Pair>::Signature: - TryFrom> + std::hash::Hash + sp_runtime::traits::Member + Codec, -{ - start_node_impl::( - parachain_config, - polkadot_config, - collator_options, - CollatorSybilResistance::Resistant, // Aura - para_id, - |_| Ok(RpcModule::new(())), - aura_build_import_queue::<_, AuraId>, - |client, - block_import, - prometheus_registry, - telemetry, - task_manager, - relay_chain_interface, - transaction_pool, - sync_oracle, - keystore, - relay_chain_slot_duration, - para_id, - collator_key, - overseer_handle, - announce_block, - backend| { - let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( - task_manager.spawn_handle(), - client.clone(), - transaction_pool, - prometheus_registry, - telemetry.clone(), - ); - let proposer = Proposer::new(proposer_factory); - - let collator_service = CollatorService::new( - client.clone(), - Arc::new(task_manager.spawn_handle()), - announce_block, - client.clone(), - ); - - let params = AuraParams { - create_inherent_data_providers: move |_, ()| async move { Ok(()) }, - block_import, - para_client: client.clone(), - para_backend: backend, - relay_client: relay_chain_interface, - code_hash_provider: move |block_hash| { - client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) - }, - sync_oracle, - keystore, - collator_key, - para_id, - overseer_handle, - relay_chain_slot_duration, - proposer, - collator_service, - authoring_duration: Duration::from_millis(1500), - reinitialize: false, - }; - - let fut = - aura::run::::Pair, _, _, _, _, _, _, _, _, _>(params); - task_manager.spawn_essential_handle().spawn("aura", None, fut); - - Ok(()) - }, - hwbench, - ) - .await -} - -/// Start a shell node which should later transition into an Aura powered parachain node. Asset Hub -/// uses this because at genesis, Asset Hub was on the `shell` runtime which didn't have Aura and -/// needs to sync and upgrade before it can run `AuraApi` functions. -pub async fn start_asset_hub_node( - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> -where - RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, - RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue - + sp_api::Metadata - + sp_session::SessionKeys - + sp_api::ApiExt - + sp_offchain::OffchainWorkerApi - + sp_block_builder::BlockBuilder - + cumulus_primitives_core::CollectCollationInfo - + sp_consensus_aura::AuraApi::Pair as Pair>::Public> - + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi - + frame_rpc_system::AccountNonceApi, - <::Pair as Pair>::Signature: - TryFrom> + std::hash::Hash + sp_runtime::traits::Member + Codec, -{ - start_node_impl::( - parachain_config, - polkadot_config, - collator_options, - CollatorSybilResistance::Resistant, // Aura - para_id, - |_| Ok(RpcModule::new(())), - aura_build_import_queue::<_, AuraId>, - |client, - block_import, - prometheus_registry, - telemetry, - task_manager, - relay_chain_interface, - transaction_pool, - sync_oracle, - keystore, - relay_chain_slot_duration, - para_id, - collator_key, - overseer_handle, - announce_block, - _backend| { - let relay_chain_interface2 = relay_chain_interface.clone(); - - let collator_service = CollatorService::new( - client.clone(), - Arc::new(task_manager.spawn_handle()), - announce_block, - client.clone(), - ); - - let spawner = task_manager.spawn_handle(); - - let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( - spawner, - client.clone(), - transaction_pool, - prometheus_registry, - telemetry.clone(), - ); - - let collation_future = Box::pin(async move { - // Start collating with the `shell` runtime while waiting for an upgrade to an Aura - // compatible runtime. - let mut request_stream = cumulus_client_collator::relay_chain_driven::init( - collator_key.clone(), - para_id, - overseer_handle.clone(), - ) - .await; - while let Some(request) = request_stream.next().await { - let pvd = request.persisted_validation_data().clone(); - let last_head_hash = - match ::Header::decode(&mut &pvd.parent_head.0[..]) { - Ok(header) => header.hash(), - Err(e) => { - log::error!("Could not decode the head data: {e}"); - request.complete(None); - continue - }, - }; - - // Check if we have upgraded to an Aura compatible runtime and transition if - // necessary. - if client - .runtime_api() - .has_api::>(last_head_hash) - .unwrap_or(false) - { - // Respond to this request before transitioning to Aura. - request.complete(None); - break - } - } - - // Move to Aura consensus. - let slot_duration = match cumulus_client_consensus_aura::slot_duration(&*client) { - Ok(d) => d, - Err(e) => { - log::error!("Could not get Aura slot duration: {e}"); - return - }, - }; - - let proposer = Proposer::new(proposer_factory); - - let params = BasicAuraParams { - create_inherent_data_providers: move |_, ()| async move { Ok(()) }, - block_import, - para_client: client, - relay_client: relay_chain_interface2, - sync_oracle, - keystore, - collator_key, - para_id, - overseer_handle, - slot_duration, - relay_chain_slot_duration, - proposer, - collator_service, - // Very limited proposal time. - authoring_duration: Duration::from_millis(500), - collation_request_receiver: Some(request_stream), - }; - - basic_aura::run::::Pair, _, _, _, _, _, _, _>(params) - .await - }); + } else { + self.relay_chain_consensus + .lock() + .await + .produce_candidate(parent, relay_parent, validation_data) + .await + } + } +} - let spawner = task_manager.spawn_essential_handle(); - spawner.spawn_essential("cumulus-asset-hub-collator", None, collation_future); +struct Verifier { + client: Arc, + aura_verifier: BuildOnAccess>>, + relay_chain_verifier: Box>, + _phantom: PhantomData, +} - Ok(()) - }, - hwbench, - ) - .await +#[async_trait::async_trait] +impl VerifierT for Verifier +where + Client: sp_api::ProvideRuntimeApi + Send + Sync, + Client::Api: AuraApi, + AuraId: Send + Sync + Codec, +{ + async fn verify( + &mut self, + block_import: BlockImportParams, + ) -> Result, String> { + if self + .client + .runtime_api() + .has_api::>(*block_import.header.parent_hash()) + .unwrap_or(false) + { + self.aura_verifier.get_mut().verify(block_import).await + } else { + self.relay_chain_verifier.verify(block_import).await + } + } } -/// Start a shell node which should later transition into an Aura powered parachain node. Asset Hub -/// uses this because at genesis, Asset Hub was on the `shell` runtime which didn't have Aura and -/// needs to sync and upgrade before it can run `AuraApi` functions. -/// -/// Uses the lookahead collator to support async backing. -#[sc_tracing::logging::prefix_logs_with("Parachain")] -pub async fn start_asset_hub_lookahead_node( - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> +/// Build the import queue for parachain runtimes that started with relay chain consensus and +/// switched to aura. +pub fn build_relay_to_aura_import_queue( + client: Arc>, + block_import: ParachainBlockImport, + config: &Configuration, + telemetry_handle: Option, + task_manager: &TaskManager, +) -> Result, sc_service::Error> where RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue @@ -1656,162 +636,74 @@ where + sp_api::ApiExt + sp_offchain::OffchainWorkerApi + sp_block_builder::BlockBuilder - + cumulus_primitives_core::CollectCollationInfo - + sp_consensus_aura::AuraApi::Pair as Pair>::Public> - + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi - + frame_rpc_system::AccountNonceApi - + cumulus_primitives_aura::AuraUnincludedSegmentApi, + + sp_consensus_aura::AuraApi::Pair as Pair>::Public>, <::Pair as Pair>::Signature: TryFrom> + std::hash::Hash + sp_runtime::traits::Member + Codec, { - start_node_impl::( - parachain_config, - polkadot_config, - collator_options, - CollatorSybilResistance::Resistant, // Aura - para_id, - |_| Ok(RpcModule::new(())), - aura_build_import_queue::<_, AuraId>, - |client, - block_import, - prometheus_registry, - telemetry, - task_manager, - relay_chain_interface, - transaction_pool, - sync_oracle, - keystore, - relay_chain_slot_duration, - para_id, - collator_key, - overseer_handle, - announce_block, - backend| { - let relay_chain_interface2 = relay_chain_interface.clone(); - - let collator_service = CollatorService::new( - client.clone(), - Arc::new(task_manager.spawn_handle()), - announce_block, - client.clone(), - ); - - let spawner = task_manager.spawn_handle(); + let verifier_client = client.clone(); - let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( - spawner, - client.clone(), - transaction_pool, - prometheus_registry, - telemetry.clone(), - ); + let aura_verifier = move || { + Box::new(cumulus_client_consensus_aura::build_verifier::< + ::Pair, + _, + _, + _, + >(cumulus_client_consensus_aura::BuildVerifierParams { + client: verifier_client.clone(), + create_inherent_data_providers: move |parent_hash, _| { + let cidp_client = verifier_client.clone(); + async move { + let slot_duration = cumulus_client_consensus_aura::slot_duration_at( + &*cidp_client, + parent_hash, + )?; + let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); - let collation_future = Box::pin(async move { - // Start collating with the `shell` runtime while waiting for an upgrade to an Aura - // compatible runtime. - let mut request_stream = cumulus_client_collator::relay_chain_driven::init( - collator_key.clone(), - para_id, - overseer_handle.clone(), - ) - .await; - while let Some(request) = request_stream.next().await { - let pvd = request.persisted_validation_data().clone(); - let last_head_hash = - match ::Header::decode(&mut &pvd.parent_head.0[..]) { - Ok(header) => header.hash(), - Err(e) => { - log::error!("Could not decode the head data: {e}"); - request.complete(None); - continue - }, - }; + let slot = + sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( + *timestamp, + slot_duration, + ); - // Check if we have upgraded to an Aura compatible runtime and transition if - // necessary. - if client - .runtime_api() - .has_api::>(last_head_hash) - .unwrap_or(false) - { - // Respond to this request before transitioning to Aura. - request.complete(None); - break - } + Ok((slot, timestamp)) } + }, + telemetry: telemetry_handle, + })) as Box<_> + }; - // Move to Aura consensus. - let proposer = Proposer::new(proposer_factory); - - let params = AuraParams { - create_inherent_data_providers: move |_, ()| async move { Ok(()) }, - block_import, - para_client: client.clone(), - para_backend: backend, - relay_client: relay_chain_interface2, - code_hash_provider: move |block_hash| { - client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) - }, - sync_oracle, - keystore, - collator_key, - para_id, - overseer_handle, - relay_chain_slot_duration, - proposer, - collator_service, - authoring_duration: Duration::from_millis(1500), - reinitialize: true, /* we need to always re-initialize for asset-hub moving - * to aura */ - }; + let relay_chain_verifier = + Box::new(RelayChainVerifier::new(client.clone(), |_, _| async { Ok(()) })) as Box<_>; - aura::run::::Pair, _, _, _, _, _, _, _, _, _>(params) - .await - }); + let verifier = Verifier { + client, + relay_chain_verifier, + aura_verifier: BuildOnAccess::Uninitialized(Some(Box::new(aura_verifier))), + _phantom: PhantomData, + }; - let spawner = task_manager.spawn_essential_handle(); - spawner.spawn_essential("cumulus-asset-hub-collator", None, collation_future); + let registry = config.prometheus_registry(); + let spawner = task_manager.spawn_essential_handle(); - Ok(()) - }, - hwbench, - ) - .await + Ok(BasicQueue::new(verifier, Box::new(block_import), None, &spawner, registry)) } -/// Start an aura powered parachain node which uses the lookahead collator to support async backing. -/// This node is basic in the sense that its runtime api doesn't include common contents such as -/// transaction payment. Used for aura glutton. -pub async fn start_basic_lookahead_node( +/// Start an aura powered parachain node. Some system chains use this. +pub async fn start_generic_aura_node( parachain_config: Configuration, polkadot_config: Configuration, collator_options: CollatorOptions, para_id: ParaId, hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> -where - RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, - RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue - + sp_api::Metadata - + sp_session::SessionKeys - + sp_api::ApiExt - + sp_offchain::OffchainWorkerApi - + sp_block_builder::BlockBuilder - + cumulus_primitives_core::CollectCollationInfo - + sp_consensus_aura::AuraApi::Pair as Pair>::Public> - + frame_rpc_system::AccountNonceApi - + cumulus_primitives_aura::AuraUnincludedSegmentApi, - <::Pair as Pair>::Signature: - TryFrom> + std::hash::Hash + sp_runtime::traits::Member + Codec, -{ - start_basic_lookahead_node_impl::( +) -> sc_service::error::Result<(TaskManager, Arc>)> { + start_node_impl::( parachain_config, polkadot_config, collator_options, CollatorSybilResistance::Resistant, // Aura para_id, - |_| Ok(RpcModule::new(())), - aura_build_import_queue::<_, AuraId>, + build_parachain_rpc_extensions::, + build_relay_to_aura_import_queue::<_, AuraId>, |client, block_import, prometheus_registry, @@ -1826,7 +718,9 @@ where collator_key, overseer_handle, announce_block, - backend| { + _backend| { + let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; + let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( task_manager.spawn_handle(), client.clone(), @@ -1843,29 +737,27 @@ where client.clone(), ); - let params = AuraParams { + let params = BasicAuraParams { create_inherent_data_providers: move |_, ()| async move { Ok(()) }, block_import, - para_client: client.clone(), - para_backend: backend.clone(), + para_client: client, relay_client: relay_chain_interface, - code_hash_provider: move |block_hash| { - client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) - }, sync_oracle, keystore, collator_key, para_id, overseer_handle, + slot_duration, relay_chain_slot_duration, proposer, collator_service, - authoring_duration: Duration::from_millis(1500), - reinitialize: false, + // Very limited proposal time. + authoring_duration: Duration::from_millis(500), + collation_request_receiver: None, }; let fut = - aura::run::::Pair, _, _, _, _, _, _, _, _, _>(params); + basic_aura::run::::Pair, _, _, _, _, _, _, _>(params); task_manager.spawn_essential_handle().spawn("aura", None, fut); Ok(()) @@ -1875,16 +767,38 @@ where .await } -#[sc_tracing::logging::prefix_logs_with("Parachain")] -async fn start_contracts_rococo_node_impl( +/// Uses the lookahead collator to support async backing. +/// +/// Start an aura powered parachain node. Some system chains use this. +pub async fn start_generic_aura_lookahead_node( + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, +) -> sc_service::error::Result<(TaskManager, Arc>)> { + start_node_impl::( + parachain_config, + polkadot_config, + collator_options, + CollatorSybilResistance::Resistant, // Aura + para_id, + build_parachain_rpc_extensions::, + build_relay_to_aura_import_queue::<_, AuraId>, + start_lookahead_aura_consensus, + hwbench, + ) + .await +} + +/// Start a shell node which should later transition into an Aura powered parachain node. Asset Hub +/// uses this because at genesis, Asset Hub was on the `shell` runtime which didn't have Aura and +/// needs to sync and upgrade before it can run `AuraApi` functions. +pub async fn start_asset_hub_node( parachain_config: Configuration, polkadot_config: Configuration, collator_options: CollatorOptions, - sybil_resistance_level: CollatorSybilResistance, para_id: ParaId, - _rpc_ext_builder: RB, - build_import_queue: BIQ, - start_consensus: SC, hwbench: Option, ) -> sc_service::error::Result<(TaskManager, Arc>)> where @@ -1896,228 +810,169 @@ where + sp_offchain::OffchainWorkerApi + sp_block_builder::BlockBuilder + cumulus_primitives_core::CollectCollationInfo + + sp_consensus_aura::AuraApi::Pair as Pair>::Public> + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi - + frame_rpc_system::AccountNonceApi - + cumulus_primitives_aura::AuraUnincludedSegmentApi, - RB: Fn(Arc>) -> Result, sc_service::Error>, - BIQ: FnOnce( - Arc>, - ParachainBlockImport, - &Configuration, - Option, - &TaskManager, - ) -> Result, sc_service::Error>, - SC: FnOnce( - Arc>, - ParachainBlockImport, - Option<&Registry>, - Option, - &TaskManager, - Arc, - Arc>>, - Arc>, - KeystorePtr, - Duration, - ParaId, - CollatorPair, - OverseerHandle, - Arc>) + Send + Sync>, - Arc, - ) -> Result<(), sc_service::Error>, + + frame_rpc_system::AccountNonceApi, + <::Pair as Pair>::Signature: + TryFrom> + std::hash::Hash + sp_runtime::traits::Member + Codec, { - let parachain_config = prepare_node_config(parachain_config); - - let params = new_partial::(¶chain_config, build_import_queue)?; - let (block_import, mut telemetry, telemetry_worker_handle) = params.other; - - let client = params.client.clone(); - let backend = params.backend.clone(); - let mut task_manager = params.task_manager; - - let (relay_chain_interface, collator_key) = build_relay_chain_interface( + start_node_impl::( + parachain_config, polkadot_config, - ¶chain_config, - telemetry_worker_handle, - &mut task_manager, - collator_options.clone(), - hwbench.clone(), - ) - .await - .map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?; - - let validator = parachain_config.role.is_authority(); - let prometheus_registry = parachain_config.prometheus_registry().cloned(); - let transaction_pool = params.transaction_pool.clone(); - let import_queue_service = params.import_queue.service(); - let net_config = FullNetworkConfiguration::new(¶chain_config.network); - - let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = - build_network(BuildNetworkParams { - parachain_config: ¶chain_config, - net_config, - client: client.clone(), - transaction_pool: transaction_pool.clone(), - para_id, - spawn_handle: task_manager.spawn_handle(), - relay_chain_interface: relay_chain_interface.clone(), - import_queue: params.import_queue, - sybil_resistance_level, - }) - .await?; - - let rpc_builder = { - let client = client.clone(); - let transaction_pool = transaction_pool.clone(); - - Box::new(move |deny_unsafe, _| { - let deps = crate::rpc::FullDeps { - client: client.clone(), - pool: transaction_pool.clone(), - deny_unsafe, - }; - - crate::rpc::create_contracts_rococo(deps).map_err(Into::into) - }) - }; - - sc_service::spawn_tasks(sc_service::SpawnTasksParams { - rpc_builder, - client: client.clone(), - transaction_pool: transaction_pool.clone(), - task_manager: &mut task_manager, - config: parachain_config, - keystore: params.keystore_container.keystore(), - backend: backend.clone(), - network: network.clone(), - sync_service: sync_service.clone(), - system_rpc_tx, - tx_handler_controller, - telemetry: telemetry.as_mut(), - })?; - - if let Some(hwbench) = hwbench { - sc_sysinfo::print_hwbench(&hwbench); - if validator { - warn_if_slow_hardware(&hwbench); - } - - if let Some(ref mut telemetry) = telemetry { - let telemetry_handle = telemetry.handle(); - task_manager.spawn_handle().spawn( - "telemetry_hwbench", - None, - sc_sysinfo::initialize_hwbench_telemetry(telemetry_handle, hwbench), - ); - } - } - - let announce_block = { - let sync_service = sync_service.clone(); - Arc::new(move |hash, data| sync_service.announce_block(hash, data)) - }; - - let relay_chain_slot_duration = Duration::from_secs(6); - - let overseer_handle = relay_chain_interface - .overseer_handle() - .map_err(|e| sc_service::Error::Application(Box::new(e)))?; - - start_relay_chain_tasks(StartRelayChainTasksParams { - client: client.clone(), - announce_block: announce_block.clone(), + collator_options, + CollatorSybilResistance::Resistant, // Aura para_id, - relay_chain_interface: relay_chain_interface.clone(), - task_manager: &mut task_manager, - da_recovery_profile: if validator { - DARecoveryProfile::Collator - } else { - DARecoveryProfile::FullNode - }, - import_queue: import_queue_service, - relay_chain_slot_duration, - recovery_handle: Box::new(overseer_handle.clone()), - sync_service: sync_service.clone(), - })?; + build_parachain_rpc_extensions::, + build_relay_to_aura_import_queue::<_, AuraId>, + |client, + block_import, + prometheus_registry, + telemetry, + task_manager, + relay_chain_interface, + transaction_pool, + sync_oracle, + keystore, + relay_chain_slot_duration, + para_id, + collator_key, + overseer_handle, + announce_block, + _backend| { + let relay_chain_interface2 = relay_chain_interface.clone(); - if validator { - start_consensus( - client.clone(), - block_import, - prometheus_registry.as_ref(), - telemetry.as_ref().map(|t| t.handle()), - &task_manager, - relay_chain_interface.clone(), - transaction_pool, - sync_service.clone(), - params.keystore_container.keystore(), - relay_chain_slot_duration, - para_id, - collator_key.expect("Command line arguments do not allow this. qed"), - overseer_handle, - announce_block, - backend.clone(), - )?; - } + let collator_service = CollatorService::new( + client.clone(), + Arc::new(task_manager.spawn_handle()), + announce_block, + client.clone(), + ); - start_network.start_network(); + let spawner = task_manager.spawn_handle(); - Ok((task_manager, client)) -} + let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( + spawner, + client.clone(), + transaction_pool, + prometheus_registry, + telemetry.clone(), + ); -#[allow(clippy::type_complexity)] -pub fn contracts_rococo_build_import_queue( - client: Arc>, - block_import: ParachainBlockImport, - config: &Configuration, - telemetry: Option, - task_manager: &TaskManager, -) -> Result, sc_service::Error> { - let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; + let collation_future = Box::pin(async move { + // Start collating with the `shell` runtime while waiting for an upgrade to an Aura + // compatible runtime. + let mut request_stream = cumulus_client_collator::relay_chain_driven::init( + collator_key.clone(), + para_id, + overseer_handle.clone(), + ) + .await; + while let Some(request) = request_stream.next().await { + let pvd = request.persisted_validation_data().clone(); + let last_head_hash = + match ::Header::decode(&mut &pvd.parent_head.0[..]) { + Ok(header) => header.hash(), + Err(e) => { + log::error!("Could not decode the head data: {e}"); + request.complete(None); + continue + }, + }; - cumulus_client_consensus_aura::import_queue::< - sp_consensus_aura::sr25519::AuthorityPair, - _, - _, - _, - _, - _, - >(cumulus_client_consensus_aura::ImportQueueParams { - block_import, - client, - create_inherent_data_providers: move |_, _| async move { - let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); + // Check if we have upgraded to an Aura compatible runtime and transition if + // necessary. + if client + .runtime_api() + .has_api::>(last_head_hash) + .unwrap_or(false) + { + // Respond to this request before transitioning to Aura. + request.complete(None); + break + } + } - let slot = - sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( - *timestamp, + // Move to Aura consensus. + let slot_duration = match cumulus_client_consensus_aura::slot_duration(&*client) { + Ok(d) => d, + Err(e) => { + log::error!("Could not get Aura slot duration: {e}"); + return + }, + }; + + let proposer = Proposer::new(proposer_factory); + + let params = BasicAuraParams { + create_inherent_data_providers: move |_, ()| async move { Ok(()) }, + block_import, + para_client: client, + relay_client: relay_chain_interface2, + sync_oracle, + keystore, + collator_key, + para_id, + overseer_handle, slot_duration, - ); + relay_chain_slot_duration, + proposer, + collator_service, + // Very limited proposal time. + authoring_duration: Duration::from_millis(500), + collation_request_receiver: Some(request_stream), + }; - Ok((slot, timestamp)) + basic_aura::run::::Pair, _, _, _, _, _, _, _>(params) + .await + }); + + let spawner = task_manager.spawn_essential_handle(); + spawner.spawn_essential("cumulus-asset-hub-collator", None, collation_future); + + Ok(()) }, - registry: config.prometheus_registry(), - spawner: &task_manager.spawn_essential_handle(), - telemetry, - }) - .map_err(Into::into) + hwbench, + ) + .await } -/// Start a parachain node. -pub async fn start_contracts_rococo_node( +/// Start a shell node which should later transition into an Aura powered parachain node. Asset Hub +/// uses this because at genesis, Asset Hub was on the `shell` runtime which didn't have Aura and +/// needs to sync and upgrade before it can run `AuraApi` functions. +/// +/// Uses the lookahead collator to support async backing. +#[sc_tracing::logging::prefix_logs_with("Parachain")] +pub async fn start_asset_hub_lookahead_node( parachain_config: Configuration, polkadot_config: Configuration, collator_options: CollatorOptions, para_id: ParaId, hwbench: Option, -) -> sc_service::error::Result<(TaskManager, Arc>)> { - start_contracts_rococo_node_impl::( +) -> sc_service::error::Result<(TaskManager, Arc>)> +where + RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, + RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue + + sp_api::Metadata + + sp_session::SessionKeys + + sp_api::ApiExt + + sp_offchain::OffchainWorkerApi + + sp_block_builder::BlockBuilder + + cumulus_primitives_core::CollectCollationInfo + + sp_consensus_aura::AuraApi::Pair as Pair>::Public> + + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + + frame_rpc_system::AccountNonceApi + + cumulus_primitives_aura::AuraUnincludedSegmentApi, + <::Pair as Pair>::Signature: + TryFrom> + std::hash::Hash + sp_runtime::traits::Member + Codec, +{ + start_node_impl::( parachain_config, polkadot_config, collator_options, CollatorSybilResistance::Resistant, // Aura para_id, - |_| Ok(RpcModule::new(())), - contracts_rococo_build_import_queue, + build_parachain_rpc_extensions::, + build_relay_to_aura_import_queue::<_, AuraId>, |client, block_import, prometheus_registry, @@ -2133,14 +988,7 @@ pub async fn start_contracts_rococo_node( overseer_handle, announce_block, backend| { - let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( - task_manager.spawn_handle(), - client.clone(), - transaction_pool, - prometheus_registry, - telemetry.clone(), - ); - let proposer = Proposer::new(proposer_factory); + let relay_chain_interface2 = relay_chain_interface.clone(); let collator_service = CollatorService::new( client.clone(), @@ -2149,42 +997,81 @@ pub async fn start_contracts_rococo_node( client.clone(), ); - let params = AuraParams { - create_inherent_data_providers: move |_, ()| async move { Ok(()) }, - block_import, - para_client: client.clone(), - para_backend: backend.clone(), - relay_client: relay_chain_interface, - code_hash_provider: move |block_hash| { - client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) - }, - sync_oracle, - keystore, - collator_key, - para_id, - overseer_handle, - relay_chain_slot_duration, - proposer, - collator_service, - // Very limited proposal time. - authoring_duration: Duration::from_millis(1500), - reinitialize: false, - }; + let spawner = task_manager.spawn_handle(); - let fut = aura::run::< - Block, - sp_consensus_aura::sr25519::AuthorityPair, - _, - _, - _, - _, - _, - _, - _, - _, - _, - >(params); - task_manager.spawn_essential_handle().spawn("aura", None, fut); + let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( + spawner, + client.clone(), + transaction_pool, + prometheus_registry, + telemetry.clone(), + ); + + let collation_future = Box::pin(async move { + // Start collating with the `shell` runtime while waiting for an upgrade to an Aura + // compatible runtime. + let mut request_stream = cumulus_client_collator::relay_chain_driven::init( + collator_key.clone(), + para_id, + overseer_handle.clone(), + ) + .await; + while let Some(request) = request_stream.next().await { + let pvd = request.persisted_validation_data().clone(); + let last_head_hash = + match ::Header::decode(&mut &pvd.parent_head.0[..]) { + Ok(header) => header.hash(), + Err(e) => { + log::error!("Could not decode the head data: {e}"); + request.complete(None); + continue + }, + }; + + // Check if we have upgraded to an Aura compatible runtime and transition if + // necessary. + if client + .runtime_api() + .has_api::>(last_head_hash) + .unwrap_or(false) + { + // Respond to this request before transitioning to Aura. + request.complete(None); + break + } + } + + // Move to Aura consensus. + let proposer = Proposer::new(proposer_factory); + + let params = AuraParams { + create_inherent_data_providers: move |_, ()| async move { Ok(()) }, + block_import, + para_client: client.clone(), + para_backend: backend, + relay_client: relay_chain_interface2, + code_hash_provider: move |block_hash| { + client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) + }, + sync_oracle, + keystore, + collator_key, + para_id, + overseer_handle, + relay_chain_slot_duration, + proposer, + collator_service, + authoring_duration: Duration::from_millis(1500), + reinitialize: true, /* we need to always re-initialize for asset-hub moving + * to aura */ + }; + + aura::run::::Pair, _, _, _, _, _, _, _, _, _>(params) + .await + }); + + let spawner = task_manager.spawn_essential_handle(); + spawner.spawn_essential("cumulus-asset-hub-collator", None, collation_future); Ok(()) }, @@ -2193,6 +1080,184 @@ pub async fn start_contracts_rococo_node( .await } +/// Start relay-chain consensus that is free for all. Everyone can submit a block, the relay-chain +/// decides what is backed and included. +fn start_relay_chain_consensus( + client: Arc>, + block_import: ParachainBlockImport, + prometheus_registry: Option<&Registry>, + telemetry: Option, + task_manager: &TaskManager, + relay_chain_interface: Arc, + transaction_pool: Arc>>, + _sync_oracle: Arc>, + _keystore: KeystorePtr, + _relay_chain_slot_duration: Duration, + para_id: ParaId, + collator_key: CollatorPair, + overseer_handle: OverseerHandle, + announce_block: Arc>) + Send + Sync>, + _backend: Arc, +) -> Result<(), sc_service::Error> { + let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( + task_manager.spawn_handle(), + client.clone(), + transaction_pool, + prometheus_registry, + telemetry, + ); + + let free_for_all = cumulus_client_consensus_relay_chain::build_relay_chain_consensus( + cumulus_client_consensus_relay_chain::BuildRelayChainConsensusParams { + para_id, + proposer_factory, + block_import, + relay_chain_interface: relay_chain_interface.clone(), + create_inherent_data_providers: move |_, (relay_parent, validation_data)| { + let relay_chain_interface = relay_chain_interface.clone(); + async move { + let parachain_inherent = + cumulus_client_parachain_inherent::ParachainInherentDataProvider::create_at( + relay_parent, + &relay_chain_interface, + &validation_data, + para_id, + ).await; + let parachain_inherent = parachain_inherent.ok_or_else(|| { + Box::::from( + "Failed to create parachain inherent", + ) + })?; + Ok(parachain_inherent) + } + }, + }, + ); + + let spawner = task_manager.spawn_handle(); + + // Required for free-for-all consensus + #[allow(deprecated)] + old_consensus::start_collator_sync(old_consensus::StartCollatorParams { + para_id, + block_status: client.clone(), + announce_block, + overseer_handle, + spawner, + key: collator_key, + parachain_consensus: free_for_all, + runtime_api: client.clone(), + }); + + Ok(()) +} + +/// Start consensus using the lookahead aura collator. +fn start_lookahead_aura_consensus( + client: Arc>, + block_import: ParachainBlockImport, + prometheus_registry: Option<&Registry>, + telemetry: Option, + task_manager: &TaskManager, + relay_chain_interface: Arc, + transaction_pool: Arc>>, + sync_oracle: Arc>, + keystore: KeystorePtr, + relay_chain_slot_duration: Duration, + para_id: ParaId, + collator_key: CollatorPair, + overseer_handle: OverseerHandle, + announce_block: Arc>) + Send + Sync>, + backend: Arc, +) -> Result<(), sc_service::Error> { + let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( + task_manager.spawn_handle(), + client.clone(), + transaction_pool, + prometheus_registry, + telemetry.clone(), + ); + + let collator_service = CollatorService::new( + client.clone(), + Arc::new(task_manager.spawn_handle()), + announce_block, + client.clone(), + ); + + let params = AuraParams { + create_inherent_data_providers: move |_, ()| async move { Ok(()) }, + block_import, + para_client: client.clone(), + para_backend: backend, + relay_client: relay_chain_interface, + code_hash_provider: move |block_hash| { + client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) + }, + sync_oracle, + keystore, + collator_key, + para_id, + overseer_handle, + relay_chain_slot_duration, + proposer: Proposer::new(proposer_factory), + collator_service, + authoring_duration: Duration::from_millis(1500), + reinitialize: false, + }; + + let fut = aura::run::::Pair, _, _, _, _, _, _, _, _, _>(params); + task_manager.spawn_essential_handle().spawn("aura", None, fut); + + Ok(()) +} + +/// Start an aura powered parachain node which uses the lookahead collator to support async backing. +/// This node is basic in the sense that its runtime api doesn't include common contents such as +/// transaction payment. Used for aura glutton. +pub async fn start_basic_lookahead_node( + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, +) -> sc_service::error::Result<(TaskManager, Arc>)> { + start_node_impl::( + parachain_config, + polkadot_config, + collator_options, + CollatorSybilResistance::Resistant, // Aura + para_id, + |_, _, _, _| Ok(RpcModule::new(())), + build_relay_to_aura_import_queue::<_, AuraId>, + start_lookahead_aura_consensus, + hwbench, + ) + .await +} + +/// Start a parachain node for Rococo Contracts. +pub async fn start_contracts_rococo_node( + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, +) -> sc_service::error::Result<(TaskManager, Arc>)> { + start_node_impl::( + parachain_config, + polkadot_config, + collator_options, + CollatorSybilResistance::Resistant, // Aura + para_id, + build_contracts_rpc_extensions, + build_aura_import_queue, + start_lookahead_aura_consensus, + hwbench, + ) + .await +} + /// Checks that the hardware meets the requirements and print a warning otherwise. fn warn_if_slow_hardware(hwbench: &sc_sysinfo::HwBench) { // Polkadot para-chains should generally use these requirements to ensure that the relay-chain -- GitLab From f977c211573e65b9f89886e7211e9b3148ce7e05 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Fri, 8 Mar 2024 10:48:55 +0100 Subject: [PATCH 011/187] Contracts Bump ApiVersion and add test (#3619) ApiVersion should have been bumped with https://github.com/paritytech/polkadot-sdk/pull/3606 this does that and add a test so we don't forget to do that everytime --- substrate/frame/contracts/proc-macro/src/lib.rs | 5 +++++ substrate/frame/contracts/src/lib.rs | 11 ++++++++++- substrate/frame/contracts/src/wasm/mod.rs | 3 +++ substrate/frame/contracts/src/wasm/runtime.rs | 1 - 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/substrate/frame/contracts/proc-macro/src/lib.rs b/substrate/frame/contracts/proc-macro/src/lib.rs index de961776c32..1794d09d5ad 100644 --- a/substrate/frame/contracts/proc-macro/src/lib.rs +++ b/substrate/frame/contracts/proc-macro/src/lib.rs @@ -497,9 +497,14 @@ fn expand_docs(def: &EnvDef) -> TokenStream2 { fn expand_env(def: &EnvDef, docs: bool) -> TokenStream2 { let impls = expand_impls(def); let docs = docs.then_some(expand_docs(def)).unwrap_or(TokenStream2::new()); + let stable_api_count = def.host_funcs.iter().filter(|f| f.is_stable).count(); quote! { pub struct Env; + + #[cfg(test)] + pub const STABLE_API_COUNT: usize = #stable_api_count; + #impls /// Documentation of the API (host functions) available to contracts. /// diff --git a/substrate/frame/contracts/src/lib.rs b/substrate/frame/contracts/src/lib.rs index 0511bcf7f3f..de84d5220c5 100644 --- a/substrate/frame/contracts/src/lib.rs +++ b/substrate/frame/contracts/src/lib.rs @@ -222,10 +222,19 @@ pub struct Environment { pub struct ApiVersion(u16); impl Default for ApiVersion { fn default() -> Self { - Self(1) + Self(2) } } +#[test] +fn api_version_is_up_to_date() { + assert_eq!( + 109, + crate::wasm::STABLE_API_COUNT, + "Stable API count has changed. Bump the returned value of ApiVersion::default() and update the test." + ); +} + #[frame_support::pallet] pub mod pallet { use super::*; diff --git a/substrate/frame/contracts/src/wasm/mod.rs b/substrate/frame/contracts/src/wasm/mod.rs index 23363780b14..af287a6f2df 100644 --- a/substrate/frame/contracts/src/wasm/mod.rs +++ b/substrate/frame/contracts/src/wasm/mod.rs @@ -21,6 +21,9 @@ mod prepare; mod runtime; +#[cfg(test)] +pub use runtime::STABLE_API_COUNT; + #[cfg(doc)] pub use crate::wasm::runtime::api_doc; diff --git a/substrate/frame/contracts/src/wasm/runtime.rs b/substrate/frame/contracts/src/wasm/runtime.rs index 402ff78dcde..7d43d30ba58 100644 --- a/substrate/frame/contracts/src/wasm/runtime.rs +++ b/substrate/frame/contracts/src/wasm/runtime.rs @@ -987,7 +987,6 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { // for every function. #[define_env(doc)] pub mod env { - /// Set the value at the given key in the contract storage. /// See [`pallet_contracts_uapi::HostFn::set_storage`] #[prefixed_alias] -- GitLab From 6f3caac0517278f0fdd614545c9ef620200bc02f Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <49718502+alexggh@users.noreply.github.com> Date: Fri, 8 Mar 2024 14:10:47 +0200 Subject: [PATCH 012/187] collator-protocol: Always stay connected to validators in backing group (#3544) Looking at rococo-asset-hub https://github.com/paritytech/polkadot-sdk/issues/3519 there seems to be a lot of instances where collator did not advertise their collations, while there are multiple problems there, one of it is that we are connecting and disconnecting to our assigned validators every block, because on reconnect_timeout every 4s we call connect_to_validators and that will produce 0 validators when all went well, so set_reseverd_peers called from validator discovery will disconnect all our peers. More details here: https://github.com/paritytech/polkadot-sdk/issues/3519#issuecomment-1972667343 Now, this shouldn't be a problem, but it stacks with an existing bug in our network stack where if disconnect from a peer the peer might not notice it, so it won't detect the reconnect either and it won't send us the necessary view updates, so we won't advertise the collation to it more details here: https://github.com/paritytech/polkadot-sdk/issues/3519#issuecomment-1972958276 To avoid hitting this condition that often, let's keep the peers in the reserved set for the entire duration we are allocated to a backing group. Backing group sizes(1 rococo, 3 kusama, 5 polkadot) are really small, so this shouldn't lead to that many connections. Additionally, the validators would disconnect us any way if we don't advertise anything for 4 blocks. ## TODO - [x] More testing. - [x] Confirm on rococo that this is improving the situation. (It doesn't but just because other things are going wrong there). --------- Signed-off-by: Alexandru Gheorghe --- .../src/collator_side/validators_buffer.rs | 38 +++++++++++++++---- .../src/validator_side/mod.rs | 2 +- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/polkadot/node/network/collator-protocol/src/collator_side/validators_buffer.rs b/polkadot/node/network/collator-protocol/src/collator_side/validators_buffer.rs index 5b88efc99d8..1533f2eda5a 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/validators_buffer.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/validators_buffer.rs @@ -90,8 +90,7 @@ impl ValidatorGroupsBuffer { } } - /// Returns discovery ids of validators we have at least one advertised-but-not-fetched - /// collation for. + /// Returns discovery ids of validators we are assigned to in this backing group window. pub fn validators_to_connect(&self) -> Vec { let validators_num = self.validators.len(); let bits = self @@ -99,11 +98,22 @@ impl ValidatorGroupsBuffer { .values() .fold(bitvec![0; validators_num], |acc, next| acc | next); - self.validators + let mut should_be_connected: Vec = self + .validators .iter() .enumerate() .filter_map(|(idx, authority_id)| bits[idx].then_some(authority_id.clone())) - .collect() + .collect(); + + if let Some(last_group) = self.group_infos.iter().last() { + for validator in self.validators.iter().rev().take(last_group.len) { + if !should_be_connected.contains(validator) { + should_be_connected.push(validator.clone()); + } + } + } + + should_be_connected } /// Note a new advertisement, marking that we want to be connected to validators @@ -279,7 +289,7 @@ mod tests { assert_eq!(buf.validators_to_connect(), validators[..2].to_vec()); buf.reset_validator_interest(hash_a, &validators[1]); - assert_eq!(buf.validators_to_connect(), vec![validators[0].clone()]); + assert_eq!(buf.validators_to_connect(), validators[0..2].to_vec()); buf.note_collation_advertised(hash_b, 0, GroupIndex(1), &validators[2..]); assert_eq!(buf.validators_to_connect(), validators[2..].to_vec()); @@ -287,7 +297,11 @@ mod tests { for validator in &validators[2..] { buf.reset_validator_interest(hash_b, validator); } - assert!(buf.validators_to_connect().is_empty()); + let mut expected = validators[2..].to_vec(); + expected.sort(); + let mut result = buf.validators_to_connect(); + result.sort(); + assert_eq!(result, expected); } #[test] @@ -320,10 +334,18 @@ mod tests { } buf.reset_validator_interest(hashes[1], &validators[0]); - assert_eq!(buf.validators_to_connect(), validators[..2].to_vec()); + let mut expected: Vec<_> = validators[..4].iter().cloned().collect(); + let mut result = buf.validators_to_connect(); + expected.sort(); + result.sort(); + assert_eq!(result, expected); buf.reset_validator_interest(hashes[0], &validators[0]); - assert_eq!(buf.validators_to_connect(), vec![validators[1].clone()]); + let mut expected: Vec<_> = validators[1..4].iter().cloned().collect(); + expected.sort(); + let mut result = buf.validators_to_connect(); + result.sort(); + assert_eq!(result, expected); buf.note_collation_advertised(hashes[3], 0, GroupIndex(1), &validators[2..4]); buf.note_collation_advertised( diff --git a/polkadot/node/network/collator-protocol/src/validator_side/mod.rs b/polkadot/node/network/collator-protocol/src/validator_side/mod.rs index 48ad3c711a6..a1b93fff348 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/mod.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/mod.rs @@ -1883,7 +1883,7 @@ async fn disconnect_inactive_peers( ) { for (peer, peer_data) in peers { if peer_data.is_inactive(&eviction_policy) { - gum::trace!(target: LOG_TARGET, "Disconnecting inactive peer"); + gum::trace!(target: LOG_TARGET, ?peer, "Disconnecting inactive peer"); disconnect_peer(sender, *peer).await; } } -- GitLab From a0c9a3d65adb63d83afdf5b29d2e555dea0fa35e Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Fri, 8 Mar 2024 17:36:09 +0100 Subject: [PATCH 013/187] benchmark: allow range trailing comma in RangeArgs (#3598) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rustfmt will add a trailing comma for longer expression, this change will make sure that the Range parameters can still be parsed. --------- Co-authored-by: command-bot <> Co-authored-by: Alexander Theißen --- substrate/frame/support/procedural/src/benchmark.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/substrate/frame/support/procedural/src/benchmark.rs b/substrate/frame/support/procedural/src/benchmark.rs index d16ad2aaa51..27c75a7f054 100644 --- a/substrate/frame/support/procedural/src/benchmark.rs +++ b/substrate/frame/support/procedural/src/benchmark.rs @@ -65,6 +65,7 @@ struct RangeArgs { start: syn::GenericArgument, _comma: Comma, end: syn::GenericArgument, + _trailing_comma: Option, _gt_token: Gt, } -- GitLab From 1fe3c5f23b9c057a2ff1926daf4ecfd5b022da45 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Fri, 8 Mar 2024 19:13:31 +0100 Subject: [PATCH 014/187] Contracts: Fix terminate benchmark (#3558) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Alexander Theißen Co-authored-by: command-bot <> --- substrate/frame/contracts/src/benchmarking/mod.rs | 3 ++- substrate/frame/contracts/src/storage.rs | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/substrate/frame/contracts/src/benchmarking/mod.rs b/substrate/frame/contracts/src/benchmarking/mod.rs index 2ecd56b412d..794777ef05c 100644 --- a/substrate/frame/contracts/src/benchmarking/mod.rs +++ b/substrate/frame/contracts/src/benchmarking/mod.rs @@ -927,7 +927,7 @@ benchmarks! { value: code_hashes_bytes, }, ], - deploy_body: Some(body::repeated_dyn(r, vec![ + deploy_body: Some(body::repeated_dyn(T::MaxDelegateDependencies::get(), vec![ Counter(beneficiary_len as u32, code_hash_len as u32), // code_hash_ptr Regular(Instruction::Call(1)), ])), @@ -943,6 +943,7 @@ benchmarks! { assert_eq!(T::Currency::total_balance(&beneficiary), 0u32.into()); assert_eq!(T::Currency::balance(&instance.account_id), Pallet::::min_balance() * 2u32.into()); assert_ne!(T::Currency::balance_on_hold(&HoldReason::StorageDepositReserve.into(), &instance.account_id), 0u32.into()); + assert_eq!(ContractInfoOf::::get(&instance.account_id).unwrap().delegate_dependencies_count() as u32, T::MaxDelegateDependencies::get()); }: call(origin, instance.addr.clone(), 0u32.into(), Weight::MAX, None, vec![]) verify { if r > 0 { diff --git a/substrate/frame/contracts/src/storage.rs b/substrate/frame/contracts/src/storage.rs index 52c5150ca21..e99afd5d42e 100644 --- a/substrate/frame/contracts/src/storage.rs +++ b/substrate/frame/contracts/src/storage.rs @@ -108,6 +108,11 @@ impl ContractInfo { Ok(contract) } + /// Returns the number of locked delegate dependencies. + pub fn delegate_dependencies_count(&self) -> usize { + self.delegate_dependencies.len() + } + /// Associated child trie unique id is built from the hash part of the trie id. pub fn child_trie_info(&self) -> ChildInfo { ChildInfo::new_default(self.trie_id.as_ref()) -- GitLab From ea458d0b95d819d31683a8a09ca7973ae10b49be Mon Sep 17 00:00:00 2001 From: cuinix <65650185+cuinix@users.noreply.github.com> Date: Sat, 9 Mar 2024 05:28:04 +0800 Subject: [PATCH 015/187] fix some typos (#3587) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: cuinix <915115094@qq.com> Co-authored-by: Bastian Köcher --- bridges/primitives/test-utils/src/lib.rs | 2 +- cumulus/client/parachain-inherent/src/lib.rs | 4 ++-- .../parachains/integration-tests/emulated/common/src/impls.rs | 2 +- .../runtimes/coretime/coretime-rococo/src/xcm_config.rs | 2 +- .../runtimes/coretime/coretime-westend/src/xcm_config.rs | 2 +- .../runtimes/people/people-rococo/src/xcm_config.rs | 2 +- .../runtimes/people/people-westend/src/xcm_config.rs | 2 +- polkadot/cli/src/cli.rs | 2 +- polkadot/node/core/dispute-coordinator/src/initialized.rs | 2 +- polkadot/node/core/pvf-checker/src/lib.rs | 4 ++-- polkadot/node/subsystem-bench/README.md | 4 ++-- polkadot/node/subsystem-bench/src/lib/availability/mod.rs | 2 +- polkadot/node/subsystem-bench/src/lib/mock/av_store.rs | 2 +- polkadot/node/subsystem-bench/src/lib/network.rs | 4 ++-- polkadot/primitives/src/v6/slashing.rs | 2 +- polkadot/runtime/parachains/src/paras/mod.rs | 2 +- substrate/bin/node/cli/src/cli.rs | 2 +- templates/parachain/node/src/cli.rs | 2 +- templates/solochain/node/src/cli.rs | 2 +- 19 files changed, 23 insertions(+), 23 deletions(-) diff --git a/bridges/primitives/test-utils/src/lib.rs b/bridges/primitives/test-utils/src/lib.rs index f23ddd1a10d..1d80890779b 100644 --- a/bridges/primitives/test-utils/src/lib.rs +++ b/bridges/primitives/test-utils/src/lib.rs @@ -129,7 +129,7 @@ pub fn make_justification_for_header( votes_ancestries.push(child.clone()); } - // The header we need to use when pre-commiting is the one at the highest height + // The header we need to use when pre-committing is the one at the highest height // on our chain. let precommit_candidate = chain.last().map(|h| (h.hash(), *h.number())).unwrap(); unsigned_precommits.push(precommit_candidate); diff --git a/cumulus/client/parachain-inherent/src/lib.rs b/cumulus/client/parachain-inherent/src/lib.rs index 57353638e19..051eb6764c8 100644 --- a/cumulus/client/parachain-inherent/src/lib.rs +++ b/cumulus/client/parachain-inherent/src/lib.rs @@ -159,7 +159,7 @@ impl ParachainInherentDataProvider { target: LOG_TARGET, relay_parent = ?relay_parent, error = ?e, - "An error occured during requesting the downward messages.", + "An error occurred during requesting the downward messages.", ); }) .ok()?; @@ -171,7 +171,7 @@ impl ParachainInherentDataProvider { target: LOG_TARGET, relay_parent = ?relay_parent, error = ?e, - "An error occured during requesting the inbound HRMP messages.", + "An error occurred during requesting the inbound HRMP messages.", ); }) .ok()?; diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index 4bbb4701e43..c93484829fe 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -265,7 +265,7 @@ macro_rules! impl_assert_events_helpers_for_relay_chain { $crate::impls::assert_expected_events!( Self, vec![ - // XCM is succesfully received and proccessed + // XCM is successfully received and proccessed [<$chain RuntimeEvent>]::::MessageQueue($crate::impls::pallet_message_queue::Event::Processed { origin: $crate::impls::AggregateMessageOrigin::Ump($crate::impls::UmpQueueId::Para(id)), weight_used, diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs index 37bb8809dab..1722e1fcb31 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs @@ -192,7 +192,7 @@ pub type Barrier = TrailingSetTopicAsId< AllowKnownQueryResponses, WithComputedOrigin< ( - // If the message is one that immediately attemps to pay for execution, then + // If the message is one that immediately attempts to pay for execution, then // allow it. AllowTopLevelPaidExecutionFrom, // Parent and its pluralities (i.e. governance bodies) get free execution. diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs index 44049adf027..b03c7748fe0 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs @@ -198,7 +198,7 @@ pub type Barrier = TrailingSetTopicAsId< AllowKnownQueryResponses, WithComputedOrigin< ( - // If the message is one that immediately attemps to pay for execution, then + // If the message is one that immediately attempts to pay for execution, then // allow it. AllowTopLevelPaidExecutionFrom, // Parent, its pluralities (i.e. governance bodies), and the Fellows plurality diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs index 311128a17ca..534d6519086 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs @@ -207,7 +207,7 @@ pub type Barrier = TrailingSetTopicAsId< AllowKnownQueryResponses, WithComputedOrigin< ( - // If the message is one that immediately attemps to pay for execution, then + // If the message is one that immediately attempts to pay for execution, then // allow it. AllowTopLevelPaidExecutionFrom, // Parent and its pluralities (i.e. governance bodies) get free execution. diff --git a/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs index 4b7da91c17e..6353a581352 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs @@ -214,7 +214,7 @@ pub type Barrier = TrailingSetTopicAsId< AllowKnownQueryResponses, WithComputedOrigin< ( - // If the message is one that immediately attemps to pay for execution, then + // If the message is one that immediately attempts to pay for execution, then // allow it. AllowTopLevelPaidExecutionFrom, // Parent, its pluralities (i.e. governance bodies), and the Fellows plurality diff --git a/polkadot/cli/src/cli.rs b/polkadot/cli/src/cli.rs index 30f35ebcb6f..e1bc2309a94 100644 --- a/polkadot/cli/src/cli.rs +++ b/polkadot/cli/src/cli.rs @@ -52,7 +52,7 @@ pub enum Subcommand { /// Try-runtime has migrated to a standalone CLI /// (). The subcommand exists as a stub and - /// deprecation notice. It will be removed entirely some time after Janurary 2024. + /// deprecation notice. It will be removed entirely some time after January 2024. TryRuntime, /// Key management CLI utilities diff --git a/polkadot/node/core/dispute-coordinator/src/initialized.rs b/polkadot/node/core/dispute-coordinator/src/initialized.rs index 54e0410268f..5f86da87f21 100644 --- a/polkadot/node/core/dispute-coordinator/src/initialized.rs +++ b/polkadot/node/core/dispute-coordinator/src/initialized.rs @@ -99,7 +99,7 @@ pub(crate) struct Initialized { /// This is the highest `SessionIndex` seen via `ActiveLeavesUpdate`. It doesn't matter if it /// was cached successfully or not. It is used to detect ancient disputes. highest_session_seen: SessionIndex, - /// Will be set to `true` if an error occured during the last caching attempt + /// Will be set to `true` if an error occurred during the last caching attempt gaps_in_cache: bool, spam_slots: SpamSlots, participation: Participation, diff --git a/polkadot/node/core/pvf-checker/src/lib.rs b/polkadot/node/core/pvf-checker/src/lib.rs index ae0fae6b4f9..c00ec0d952f 100644 --- a/polkadot/node/core/pvf-checker/src/lib.rs +++ b/polkadot/node/core/pvf-checker/src/lib.rs @@ -415,7 +415,7 @@ async fn check_signing_credentials( gum::warn!( target: LOG_TARGET, relay_parent = ?leaf, - "error occured during requesting validators: {:?}", + "error occurred during requesting validators: {:?}", e ); return None @@ -508,7 +508,7 @@ async fn sign_and_submit_pvf_check_statement( target: LOG_TARGET, ?relay_parent, ?validation_code_hash, - "error occured during submitting a vote: {:?}", + "error occurred during submitting a vote: {:?}", e, ); }, diff --git a/polkadot/node/subsystem-bench/README.md b/polkadot/node/subsystem-bench/README.md index 3aac2810ad5..94a449ed0bb 100644 --- a/polkadot/node/subsystem-bench/README.md +++ b/polkadot/node/subsystem-bench/README.md @@ -45,7 +45,7 @@ docker compose up Please follow the [official installation guide](https://prometheus.io/docs/prometheus/latest/installation/) for your platform/OS. -After succesfully installing and starting up Prometheus, we need to alter it's configuration such that it +After successfully installing and starting up Prometheus, we need to alter it's configuration such that it will scrape the benchmark prometheus endpoint `127.0.0.1:9999`. Please check the prometheus official documentation regarding the location of `prometheus.yml`. On MacOS for example the full path `/opt/homebrew/etc/prometheus.yml` @@ -211,7 +211,7 @@ You can select log target, subtarget and verbosity just like with Polkadot node ### View test metrics -Assuming the Grafana/Prometheus stack installation steps completed succesfully, you should be able to +Assuming the Grafana/Prometheus stack installation steps completed successfully, you should be able to view the test progress in real time by accessing [this link](http://localhost:3000/goto/SM5B8pNSR?orgId=1). Now run diff --git a/polkadot/node/subsystem-bench/src/lib/availability/mod.rs b/polkadot/node/subsystem-bench/src/lib/availability/mod.rs index f012a5a907e..dc4e1e40310 100644 --- a/polkadot/node/subsystem-bench/src/lib/availability/mod.rs +++ b/polkadot/node/subsystem-bench/src/lib/availability/mod.rs @@ -598,7 +598,7 @@ pub async fn benchmark_availability_write( gum::info!(target: LOG_TARGET, "Waiting for all emulated peers to receive their chunk from us ..."); for receiver in receivers.into_iter() { - let response = receiver.await.expect("Chunk is always served succesfully"); + let response = receiver.await.expect("Chunk is always served successfully"); // TODO: check if chunk is the one the peer expects to receive. assert!(response.result.is_ok()); } diff --git a/polkadot/node/subsystem-bench/src/lib/mock/av_store.rs b/polkadot/node/subsystem-bench/src/lib/mock/av_store.rs index 41c4fe2cbad..9064f17940f 100644 --- a/polkadot/node/subsystem-bench/src/lib/mock/av_store.rs +++ b/polkadot/node/subsystem-bench/src/lib/mock/av_store.rs @@ -97,7 +97,7 @@ impl HandleNetworkMessage for NetworkAvailabilityState { outgoing_request .pending_response .send(response) - .expect("Response is always sent succesfully"); + .expect("Response is always sent successfully"); None }, _ => Some(NetworkMessage::RequestFromNode(peer, request)), diff --git a/polkadot/node/subsystem-bench/src/lib/network.rs b/polkadot/node/subsystem-bench/src/lib/network.rs index 1e09441792d..1bc35a014ff 100644 --- a/polkadot/node/subsystem-bench/src/lib/network.rs +++ b/polkadot/node/subsystem-bench/src/lib/network.rs @@ -219,7 +219,7 @@ impl Future for ProxiedRequest { Poll::Ready(response) => Poll::Ready(ProxiedResponse { sender: self.sender.take().expect("sender already used"), result: response - .expect("Response is always succesfully received.") + .expect("Response is always successfully received.") .result .map_err(|_| RequestFailure::Refused), }), @@ -761,7 +761,7 @@ pub fn new_network( gum::info!(target: LOG_TARGET, "{}",format!("connectivity {}%, latency {:?}", config.connectivity, config.latency).bright_black()); let metrics = - Metrics::new(&dependencies.registry).expect("Metrics always register succesfully"); + Metrics::new(&dependencies.registry).expect("Metrics always register successfully"); let mut validator_authority_id_mapping = HashMap::new(); // Create the channel from `peer` to `NetworkInterface` . diff --git a/polkadot/primitives/src/v6/slashing.rs b/polkadot/primitives/src/v6/slashing.rs index efffb932cdc..bcd7d0c2fc4 100644 --- a/polkadot/primitives/src/v6/slashing.rs +++ b/polkadot/primitives/src/v6/slashing.rs @@ -54,7 +54,7 @@ impl DisputesTimeSlot { /// is required to identify and verify it. #[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, Debug)] pub struct DisputeProof { - /// Time slot when the dispute occured. + /// Time slot when the dispute occurred. pub time_slot: DisputesTimeSlot, /// The dispute outcome. pub kind: SlashingOffenceKind, diff --git a/polkadot/runtime/parachains/src/paras/mod.rs b/polkadot/runtime/parachains/src/paras/mod.rs index 39371391b1f..5acdb9683bb 100644 --- a/polkadot/runtime/parachains/src/paras/mod.rs +++ b/polkadot/runtime/parachains/src/paras/mod.rs @@ -1374,7 +1374,7 @@ impl Pallet { outgoing } - // note replacement of the code of para with given `id`, which occured in the + // note replacement of the code of para with given `id`, which occurred in the // context of the given relay-chain block number. provide the replaced code. // // `at` for para-triggered replacement is the block number of the relay-chain diff --git a/substrate/bin/node/cli/src/cli.rs b/substrate/bin/node/cli/src/cli.rs index f3c0435fd32..3345afae4fd 100644 --- a/substrate/bin/node/cli/src/cli.rs +++ b/substrate/bin/node/cli/src/cli.rs @@ -63,7 +63,7 @@ pub enum Subcommand { /// Try-runtime has migrated to a standalone CLI /// (). The subcommand exists as a stub and - /// deprecation notice. It will be removed entirely some time after Janurary 2024. + /// deprecation notice. It will be removed entirely some time after January 2024. TryRuntime, /// Key management cli utilities diff --git a/templates/parachain/node/src/cli.rs b/templates/parachain/node/src/cli.rs index 73ef996b750..a5c55b8118a 100644 --- a/templates/parachain/node/src/cli.rs +++ b/templates/parachain/node/src/cli.rs @@ -40,7 +40,7 @@ pub enum Subcommand { /// Try-runtime has migrated to a standalone /// [CLI](). The subcommand exists as a stub and - /// deprecation notice. It will be removed entirely some time after Janurary 2024. + /// deprecation notice. It will be removed entirely some time after January 2024. TryRuntime, } diff --git a/templates/solochain/node/src/cli.rs b/templates/solochain/node/src/cli.rs index 98037eb886a..7f1b67b3696 100644 --- a/templates/solochain/node/src/cli.rs +++ b/templates/solochain/node/src/cli.rs @@ -43,7 +43,7 @@ pub enum Subcommand { /// Try-runtime has migrated to a standalone CLI /// (). The subcommand exists as a stub and - /// deprecation notice. It will be removed entirely some time after Janurary 2024. + /// deprecation notice. It will be removed entirely some time after January 2024. TryRuntime, /// Db meta columns information. -- GitLab From 9f5d9fa96f88007292c2d59810b7c3c855da58a7 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Sat, 9 Mar 2024 11:14:06 +0100 Subject: [PATCH 016/187] core: replace secp256k with k256 in crypto::ecdsa (#3525) This PR replaces the usage of [secp256k](https://crates.io/crates/secp256k1) crate with [k256](https://crates.io/crates/k256) in `core::crypto::ecdsa` for `non-std` environments as outcome of discussion in #3448. `secp256k1` is used in `std`, meaning that we should not affect host performance with this PR. `k256` is enabled in runtimes (`no-std`), and is required to proceed with #2044. If desirable, in future we can switch to `k256` also for `std`. That would require some performance evaluation (e.g. for EVM chains as per https://github.com/paritytech/polkadot-sdk/issues/3448#issuecomment-1976780391). Closes https://github.com/paritytech/polkadot-sdk/issues/3448 --------- Co-authored-by: command-bot <> Co-authored-by: Davide Galassi --- Cargo.lock | 27 ++++- substrate/primitives/core/Cargo.toml | 9 +- substrate/primitives/core/src/ecdsa.rs | 145 +++++++++++++++++-------- 3 files changed, 129 insertions(+), 52 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e38f09db4d3..0b7ea71a536 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4815,6 +4815,7 @@ dependencies = [ "digest 0.10.7", "elliptic-curve", "rfc6979", + "serdect", "signature", "spki", ] @@ -4881,9 +4882,9 @@ checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "elliptic-curve" -version = "0.13.5" +version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct", "crypto-bigint", @@ -4894,6 +4895,7 @@ dependencies = [ "pkcs8", "rand_core 0.6.4", "sec1", + "serdect", "subtle 2.5.0", "zeroize", ] @@ -6971,14 +6973,15 @@ dependencies = [ [[package]] name = "k256" -version = "0.13.1" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" dependencies = [ "cfg-if", "ecdsa", "elliptic-curve", "once_cell", + "serdect", "sha2 0.10.7", ] @@ -17101,6 +17104,7 @@ dependencies = [ "der", "generic-array 0.14.7", "pkcs8", + "serdect", "subtle 2.5.0", "zeroize", ] @@ -17359,6 +17363,16 @@ dependencies = [ "unsafe-libyaml", ] +[[package]] +name = "serdect" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" +dependencies = [ + "base16ct", + "serde", +] + [[package]] name = "serial_test" version = "2.0.0" @@ -18567,6 +18581,7 @@ dependencies = [ "hash256-std-hasher", "impl-serde", "itertools 0.10.5", + "k256", "lazy_static", "libsecp256k1", "log", @@ -22553,9 +22568,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" dependencies = [ "zeroize_derive", ] diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 70ca7be6a2d..f7cc2b4fcf7 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -52,9 +52,12 @@ blake2 = { version = "0.10.4", default-features = false, optional = true } libsecp256k1 = { version = "0.7", default-features = false, features = ["static-context"], optional = true } schnorrkel = { version = "0.11.4", features = ["preaudit_deprecated"], default-features = false } merlin = { version = "3.0", default-features = false } -secp256k1 = { version = "0.28.0", default-features = false, features = ["alloc", "recovery"], optional = true } sp-crypto-hashing = { path = "../crypto/hashing", default-features = false, optional = true } sp-runtime-interface = { path = "../runtime-interface", default-features = false } +# k256 crate, better portability, intended to be used in substrate-runtimes (no-std) +k256 = { version = "0.13.3", features = ["alloc", "ecdsa"], default-features = false } +# secp256k1 crate, better performance, intended to be used on host side (std) +secp256k1 = { version = "0.28.0", default-features = false, features = ["alloc", "recovery"], optional = true } # bls crypto w3f-bls = { version = "0.1.3", default-features = false, optional = true } @@ -76,6 +79,7 @@ bench = false [features] default = ["std"] + std = [ "array-bytes", "bandersnatch_vrfs?/std", @@ -94,6 +98,7 @@ std = [ "hash256-std-hasher/std", "impl-serde/std", "itertools", + "k256/std", "libsecp256k1/std", "log/std", "merlin/std", @@ -132,6 +137,7 @@ serde = [ "bs58/alloc", "dep:serde", "impl-serde", + "k256/serde", "primitive-types/serde_no_std", "scale-info/serde", "secrecy/alloc", @@ -147,7 +153,6 @@ full_crypto = [ "blake2", "ed25519-zebra", "libsecp256k1", - "secp256k1", "sp-crypto-hashing", "sp-runtime-interface/disable_target_static_assertions", ] diff --git a/substrate/primitives/core/src/ecdsa.rs b/substrate/primitives/core/src/ecdsa.rs index f172b3a7d02..e6bd2c7eb57 100644 --- a/substrate/primitives/core/src/ecdsa.rs +++ b/substrate/primitives/core/src/ecdsa.rs @@ -28,14 +28,15 @@ use crate::crypto::{ }; #[cfg(feature = "full_crypto")] use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError}; -#[cfg(all(feature = "full_crypto", not(feature = "std")))] -use secp256k1::Secp256k1; -#[cfg(feature = "std")] -use secp256k1::SECP256K1; -#[cfg(feature = "full_crypto")] + +#[cfg(all(not(feature = "std"), feature = "full_crypto"))] +use k256::ecdsa::SigningKey as SecretKey; +#[cfg(not(feature = "std"))] +use k256::ecdsa::VerifyingKey; +#[cfg(all(feature = "std", feature = "full_crypto"))] use secp256k1::{ ecdsa::{RecoverableSignature, RecoveryId}, - Message, PublicKey, SecretKey, + Message, PublicKey, SecretKey, SECP256K1, }; #[cfg(feature = "serde")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; @@ -53,9 +54,9 @@ pub const PUBLIC_KEY_SERIALIZED_SIZE: usize = 33; /// The byte length of signature pub const SIGNATURE_SERIALIZED_SIZE: usize = 65; -/// A secret seed (which is bytewise essentially equivalent to a SecretKey). +/// The secret seed. /// -/// We need it as a different type because `Seed` is expected to be AsRef<[u8]>. +/// The raw secret seed, which can be used to create the `Pair`. #[cfg(feature = "full_crypto")] type Seed = [u8; 32]; @@ -96,18 +97,21 @@ impl Public { /// Create a new instance from the given full public key. /// /// This will convert the full public key into the compressed format. - #[cfg(feature = "std")] pub fn from_full(full: &[u8]) -> Result { - let pubkey = if full.len() == 64 { + let mut tagged_full = [0u8; 65]; + let full = if full.len() == 64 { // Tag it as uncompressed public key. - let mut tagged_full = [0u8; 65]; tagged_full[0] = 0x04; tagged_full[1..].copy_from_slice(full); - secp256k1::PublicKey::from_slice(&tagged_full) + &tagged_full } else { - secp256k1::PublicKey::from_slice(full) + full }; - pubkey.map(|k| Self(k.serialize())).map_err(|_| ()) + #[cfg(feature = "std")] + let pubkey = PublicKey::from_slice(&full); + #[cfg(not(feature = "std"))] + let pubkey = VerifyingKey::from_sec1_bytes(&full); + pubkey.map(|k| k.into()).map_err(|_| ()) } } @@ -131,6 +135,24 @@ impl AsMut<[u8]> for Public { } } +#[cfg(feature = "std")] +impl From for Public { + fn from(pubkey: PublicKey) -> Self { + Self(pubkey.serialize()) + } +} + +#[cfg(not(feature = "std"))] +impl From for Public { + fn from(pubkey: VerifyingKey) -> Self { + Self::unchecked_from( + pubkey.to_sec1_bytes()[..] + .try_into() + .expect("valid key is serializable to [u8,33]. qed."), + ) + } +} + impl TryFrom<&[u8]> for Public { type Error = (); @@ -331,23 +353,34 @@ impl Signature { /// Recover the public key from this signature and a pre-hashed message. #[cfg(feature = "full_crypto")] pub fn recover_prehashed(&self, message: &[u8; 32]) -> Option { - let rid = RecoveryId::from_i32(self.0[64] as i32).ok()?; - let sig = RecoverableSignature::from_compact(&self.0[..64], rid).ok()?; - let message = Message::from_digest_slice(message).expect("Message is 32 bytes; qed"); - #[cfg(feature = "std")] - let context = SECP256K1; + { + let rid = RecoveryId::from_i32(self.0[64] as i32).ok()?; + let sig = RecoverableSignature::from_compact(&self.0[..64], rid).ok()?; + let message = Message::from_digest_slice(message).expect("Message is 32 bytes; qed"); + SECP256K1.recover_ecdsa(&message, &sig).ok().map(Public::from) + } + #[cfg(not(feature = "std"))] - let context = Secp256k1::verification_only(); + { + let rid = k256::ecdsa::RecoveryId::from_byte(self.0[64])?; + let sig = k256::ecdsa::Signature::from_bytes((&self.0[..64]).into()).ok()?; + VerifyingKey::recover_from_prehash(message, &sig, rid).map(Public::from).ok() + } + } +} - context - .recover_ecdsa(&message, &sig) - .ok() - .map(|pubkey| Public(pubkey.serialize())) +#[cfg(not(feature = "std"))] +impl From<(k256::ecdsa::Signature, k256::ecdsa::RecoveryId)> for Signature { + fn from(recsig: (k256::ecdsa::Signature, k256::ecdsa::RecoveryId)) -> Signature { + let mut r = Self::default(); + r.0[..64].copy_from_slice(&recsig.0.to_bytes()); + r.0[64] = recsig.1.to_byte(); + r } } -#[cfg(feature = "full_crypto")] +#[cfg(all(feature = "std", feature = "full_crypto"))] impl From for Signature { fn from(recsig: RecoverableSignature) -> Signature { let mut r = Self::default(); @@ -384,17 +417,19 @@ impl TraitPair for Pair { /// /// You should never need to use this; generate(), generate_with_phrase fn from_seed_slice(seed_slice: &[u8]) -> Result { - let secret = - SecretKey::from_slice(seed_slice).map_err(|_| SecretStringError::InvalidSeedLength)?; - #[cfg(feature = "std")] - let context = SECP256K1; - #[cfg(not(feature = "std"))] - let context = Secp256k1::signing_only(); + { + let secret = SecretKey::from_slice(seed_slice) + .map_err(|_| SecretStringError::InvalidSeedLength)?; + Ok(Pair { public: PublicKey::from_secret_key(&SECP256K1, &secret).into(), secret }) + } - let public = PublicKey::from_secret_key(&context, &secret); - let public = Public(public.serialize()); - Ok(Pair { public, secret }) + #[cfg(not(feature = "std"))] + { + let secret = SecretKey::from_slice(seed_slice) + .map_err(|_| SecretStringError::InvalidSeedLength)?; + Ok(Pair { public: VerifyingKey::from(&secret).into(), secret }) + } } /// Derive a child key from a series of given junctions. @@ -438,7 +473,14 @@ impl TraitPair for Pair { impl Pair { /// Get the seed for this key. pub fn seed(&self) -> Seed { - self.secret.secret_bytes() + #[cfg(feature = "std")] + { + self.secret.secret_bytes() + } + #[cfg(not(feature = "std"))] + { + self.secret.to_bytes().into() + } } /// Exactly as `from_string` except that if no matches are found then, the the first 32 @@ -455,14 +497,19 @@ impl Pair { /// Sign a pre-hashed message pub fn sign_prehashed(&self, message: &[u8; 32]) -> Signature { - let message = Message::from_digest_slice(message).expect("Message is 32 bytes; qed"); - #[cfg(feature = "std")] - let context = SECP256K1; - #[cfg(not(feature = "std"))] - let context = Secp256k1::signing_only(); + { + let message = Message::from_digest_slice(message).expect("Message is 32 bytes; qed"); + SECP256K1.sign_ecdsa_recoverable(&message, &self.secret).into() + } - context.sign_ecdsa_recoverable(&message, &self.secret).into() + #[cfg(not(feature = "std"))] + { + self.secret + .sign_prehash_recoverable(message) + .expect("signing may not fail (???). qed.") + .into() + } } /// Verify a signature on a pre-hashed message. Return `true` if the signature is valid @@ -503,7 +550,7 @@ impl Pair { // NOTE: this solution is not effective when `Pair` is moved around memory. // The very same problem affects other cryptographic backends that are just using // `zeroize`for their secrets. -#[cfg(feature = "full_crypto")] +#[cfg(all(feature = "std", feature = "full_crypto"))] impl Drop for Pair { fn drop(&mut self) { self.secret.non_secure_erase() @@ -770,8 +817,18 @@ mod test { let msg = [0u8; 32]; let sig1 = pair.sign_prehashed(&msg); let sig2: Signature = { - let message = Message::from_digest_slice(&msg).unwrap(); - SECP256K1.sign_ecdsa_recoverable(&message, &pair.secret).into() + #[cfg(feature = "std")] + { + let message = Message::from_digest_slice(&msg).unwrap(); + SECP256K1.sign_ecdsa_recoverable(&message, &pair.secret).into() + } + #[cfg(not(feature = "std"))] + { + pair.secret + .sign_prehash_recoverable(&msg) + .expect("signing may not fail (???). qed.") + .into() + } }; assert_eq!(sig1, sig2); -- GitLab From 1c435e91c117b877c803427a91c0ccd18c527382 Mon Sep 17 00:00:00 2001 From: Viki Val Date: Sat, 9 Mar 2024 07:32:53 -0800 Subject: [PATCH 017/187] :bug: Depositing PalletAttributeSet on incorrect nft (#2740) ## Context Implementing `HolderOf(collection_id)` we have observed a fancy glitch where pallet deposits event with incorrect values ### Test case [Observe following extrinsic](https://assethub-polkadot.subscan.io/extrinsic/0xdc72321b7674aa209c2f194ed49bd6bd12708af103f98b5b9196e0132dcba777) To mint in collection `51` user needs to be `HolderOf(50)`. Therefore current user is owner of item `394` `witness_data { owned_item: 394 }` All checking is done correctly, storage is updated correctly ![photo_2023-12-18 16 07 11](https://github.com/paritytech/polkadot-sdk/assets/22471030/ca991272-156d-4db1-97b2-1a2873fc5d3f) However the event which is emitted does not make semantic sense as we updated storage for `50-394` not for `51-114` ![photo_2023-12-18 16 07 17](https://github.com/paritytech/polkadot-sdk/assets/22471030/c998a92c-e306-4433-aad8-103078140e23) ## The fix This PR fixes that depositing `PalletAttributeSet` emits correct values. --------- Co-authored-by: Jegor Sidorenko Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> --- substrate/frame/nfts/src/lib.rs | 4 ++-- substrate/frame/nfts/src/tests.rs | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/substrate/frame/nfts/src/lib.rs b/substrate/frame/nfts/src/lib.rs index 7cf7cdc61a7..615720268fe 100644 --- a/substrate/frame/nfts/src/lib.rs +++ b/substrate/frame/nfts/src/lib.rs @@ -874,8 +874,8 @@ pub mod pallet { ), ); Self::deposit_event(Event::PalletAttributeSet { - collection, - item: Some(item), + collection: collection_id, + item: Some(owned_item), attribute: pallet_attribute, value: attribute_value, }); diff --git a/substrate/frame/nfts/src/tests.rs b/substrate/frame/nfts/src/tests.rs index 9e521537534..6bf9427f4e6 100644 --- a/substrate/frame/nfts/src/tests.rs +++ b/substrate/frame/nfts/src/tests.rs @@ -440,6 +440,12 @@ fn mint_should_work() { account(2), Some(MintWitness { owned_item: Some(43), ..Default::default() }) )); + assert!(events().contains(&Event::::PalletAttributeSet { + collection: 0, + item: Some(43), + attribute: PalletAttributes::<::CollectionId>::UsedToClaim(1), + value: Nfts::construct_attribute_value(vec![]).unwrap(), + })); // can't mint twice assert_noop!( -- GitLab From bbaa5a3bb5451fc0c51fd42fd91d765f5589c033 Mon Sep 17 00:00:00 2001 From: Muharem Date: Sun, 10 Mar 2024 22:24:41 +0100 Subject: [PATCH 018/187] Asset Conversion: doc guide to address incorrect exchange rate for non-withdrawable pool (#3275) This documentation guide to address an incorrect exchange rate for a non-withdrawable pool. --- substrate/frame/asset-conversion/src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index f13d40d3e7e..c9725f9d39d 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -413,6 +413,11 @@ pub mod pallet { /// Params `amount1_min`/`amount2_min` represent that. /// `mint_to` will be sent the liquidity tokens that represent this share of the pool. /// + /// NOTE: when encountering an incorrect exchange rate and non-withdrawable pool liquidity, + /// batch an atomic call with [`Pallet::add_liquidity`] and + /// [`Pallet::swap_exact_tokens_for_tokens`] or [`Pallet::swap_tokens_for_exact_tokens`] + /// calls to render the liquidity withdrawable and rectify the exchange rate. + /// /// Once liquidity is added, someone may successfully call /// [`Pallet::swap_exact_tokens_for_tokens`] successfully. #[pallet::call_index(1)] -- GitLab From a6713c55fd5082d333518c3ca13f2a4294726fcc Mon Sep 17 00:00:00 2001 From: Egor_P Date: Mon, 11 Mar 2024 16:37:22 +0700 Subject: [PATCH 019/187] Fix release docker image GHA (#3547) This PR add extra checks for the input fields in the GHA which does the docker image build and publishing. --- .github/scripts/common/lib.sh | 96 ++++++++++++++++++- .../workflows/release-50_publish-docker.yml | 16 +++- .../workflows/release-99_notif-published.yml | 10 +- 3 files changed, 107 insertions(+), 15 deletions(-) diff --git a/.github/scripts/common/lib.sh b/.github/scripts/common/lib.sh index bd12d9c6e6f..29dc269ffd2 100755 --- a/.github/scripts/common/lib.sh +++ b/.github/scripts/common/lib.sh @@ -237,6 +237,61 @@ fetch_release_artifacts() { popd > /dev/null } +# Fetch the release artifacts like binary and sigantures from S3. Assumes the ENV are set: +# - RELEASE_ID +# - GITHUB_TOKEN +# - REPO in the form paritytech/polkadot +fetch_release_artifacts_from_s3() { + echo "Version : $VERSION" + echo "Repo : $REPO" + echo "Binary : $BINARY" + OUTPUT_DIR=${OUTPUT_DIR:-"./release-artifacts/${BINARY}"} + echo "OUTPUT_DIR : $OUTPUT_DIR" + + URL_BASE=$(get_s3_url_base $BINARY) + echo "URL_BASE=$URL_BASE" + + URL_BINARY=$URL_BASE/$VERSION/$BINARY + URL_SHA=$URL_BASE/$VERSION/$BINARY.sha256 + URL_ASC=$URL_BASE/$VERSION/$BINARY.asc + + # Fetch artifacts + mkdir -p "$OUTPUT_DIR" + pushd "$OUTPUT_DIR" > /dev/null + + echo "Fetching artifacts..." + for URL in $URL_BINARY $URL_SHA $URL_ASC; do + echo "Fetching %s" "$URL" + curl --progress-bar -LO "$URL" || echo "Missing $URL" + done + + pwd + ls -al --color + popd > /dev/null + +} + +# Pass the name of the binary as input, it will +# return the s3 base url +function get_s3_url_base() { + name=$1 + case $name in + polkadot | polkadot-execute-worker | polkadot-prepare-worker | staking-miner) + printf "https://releases.parity.io/polkadot" + ;; + + polkadot-parachain) + printf "https://releases.parity.io/cumulus" + ;; + + *) + printf "UNSUPPORTED BINARY $name" + exit 1 + ;; + esac +} + + # Check the checksum for a given binary function check_sha256() { echo "Checking SHA256 for $1" @@ -248,13 +303,11 @@ function check_sha256() { function import_gpg_keys() { GPG_KEYSERVER=${GPG_KEYSERVER:-"keyserver.ubuntu.com"} SEC="9D4B2B6EB8F97156D19669A9FF0812D491B96798" - WILL="2835EAF92072BC01D188AF2C4A092B93E97CE1E2" EGOR="E6FC4D4782EB0FA64A4903CCDB7D3555DD3932D3" - MARA="533C920F40E73A21EEB7E9EBF27AEA7E7594C9CF" MORGAN="2E92A9D8B15D7891363D1AE8AF9E6C43F7F8C4CF" echo "Importing GPG keys from $GPG_KEYSERVER in parallel" - for key in $SEC $WILL $EGOR $MARA $MORGAN; do + for key in $SEC $EGOR $MORGAN; do ( echo "Importing GPG key $key" gpg --no-tty --quiet --keyserver $GPG_KEYSERVER --recv-keys $key @@ -344,3 +397,40 @@ function find_runtimes() { done echo $JSON } + +# Filter the version matches the particular pattern and return it. +# input: version (v1.8.0 or v1.8.0-rc1) +# output: none +filter_version_from_input() { + version=$1 + regex="(^v[0-9]+\.[0-9]+\.[0-9]+)$|(^v[0-9]+\.[0-9]+\.[0-9]+-rc[0-9]+)$" + + if [[ $version =~ $regex ]]; then + if [ -n "${BASH_REMATCH[1]}" ]; then + echo "${BASH_REMATCH[1]}" + elif [ -n "${BASH_REMATCH[2]}" ]; then + echo "${BASH_REMATCH[2]}" + fi + else + echo "Invalid version: $version" + exit 1 + fi + +} + +# Check if the release_id is valid number +# input: release_id +# output: release_id or exit 1 +check_release_id() { + input=$1 + + release_id=$(echo "$input" | sed 's/[^0-9]//g') + + if [[ $release_id =~ ^[0-9]+$ ]]; then + echo "$release_id" + else + echo "Invalid release_id from input: $input" + exit 1 + fi + +} diff --git a/.github/workflows/release-50_publish-docker.yml b/.github/workflows/release-50_publish-docker.yml index ecbac01cd3a..67e93ee9657 100644 --- a/.github/workflows/release-50_publish-docker.yml +++ b/.github/workflows/release-50_publish-docker.yml @@ -36,7 +36,7 @@ on: -H "Authorization: Bearer ${GITHUB_TOKEN}" https://api.github.com/repos/$OWNER/$REPO/releases | \ jq '.[] | { name: .name, id: .id }' required: true - type: string + type: number registry: description: Container registry @@ -61,7 +61,6 @@ permissions: contents: write env: - RELEASE_ID: ${{ inputs.release_id }} ENGINE: docker REGISTRY: ${{ inputs.registry }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -71,6 +70,7 @@ env: # EVENT_ACTION: ${{ github.event.action }} EVENT_NAME: ${{ github.event_name }} IMAGE_TYPE: ${{ inputs.image_type }} + VERSION: ${{ inputs.version }} jobs: fetch-artifacts: # this job will be triggered for the polkadot-parachain rc and release or polkadot rc image build @@ -95,13 +95,16 @@ jobs: # chmod a+x $BINARY # ls -al - - name: Fetch rc artifacts or release artifacts based on release id + - name: Fetch rc artifacts or release artifacts from s3 based on version #this step runs only if the workflow is triggered manually if: ${{ env.EVENT_NAME == 'workflow_dispatch' }} run: | . ./.github/scripts/common/lib.sh - fetch_release_artifacts + VERSION=$(filter_version_from_input "${{ inputs.version }}") + echo "VERSION=${VERSION}" >> $GITHUB_ENV + + fetch_release_artifacts_from_s3 - name: Cache the artifacts uses: actions/cache@e12d46a63a90f2fae62d114769bbf2a179198b5c # v3.3.3 @@ -147,7 +150,10 @@ jobs: if: ${{ env.IMAGE_TYPE == 'rc' }} id: fetch_rc_refs run: | - release=release-${{ inputs.release_id }} && \ + . ./.github/scripts/common/lib.sh + + RELEASE_ID=$(check_release_id "${{ inputs.release_id }}") + release=release-$RELEASE_ID && \ echo "release=${release}" >> $GITHUB_OUTPUT commit=$(git rev-parse --short HEAD) && \ diff --git a/.github/workflows/release-99_notif-published.yml b/.github/workflows/release-99_notif-published.yml index 732db15d9c0..05c9d6a47f5 100644 --- a/.github/workflows/release-99_notif-published.yml +++ b/.github/workflows/release-99_notif-published.yml @@ -16,12 +16,6 @@ jobs: - name: "RelEng: Polkadot Release Coordination" room: '!cqAmzdIcbOFwrdrubV:parity.io' pre-release: true - - name: 'General: Rust, Polkadot, Substrate' - room: '!aJymqQYtCjjqImFLSb:parity.io' - pre-release: false - - name: 'Team: DevOps' - room: '!lUslSijLMgNcEKcAiE:parity.io' - pre-release: true # External - name: 'Ledger <> Polkadot Coordination' @@ -48,7 +42,9 @@ jobs: access_token: ${{ secrets.RELEASENOTES_MATRIX_V2_ACCESS_TOKEN }} server: m.parity.io message: | - A (pre)release has been ${{github.event.action}} in **${{github.event.repository.full_name}}:**
+ @room + + A new node release has been ${{github.event.action}} in **${{github.event.repository.full_name}}:**
Release version: [${{github.event.release.tag_name}}](${{github.event.release.html_url}}) ----- -- GitLab From 8dc6048d5eb20886f5d0781d54e073441d3bd86c Mon Sep 17 00:00:00 2001 From: eskimor Date: Mon, 11 Mar 2024 15:11:55 +0100 Subject: [PATCH 020/187] Remove unused FullCandidateReceipt (#3641) Currently redesigning candidate data structures, noticed that this one seems dead. Co-authored-by: eskimor --- polkadot/primitives/src/v6/mod.rs | 12 --------- .../implementers-guide/src/types/README.md | 11 -------- .../implementers-guide/src/types/candidate.md | 26 ++----------------- 3 files changed, 2 insertions(+), 47 deletions(-) diff --git a/polkadot/primitives/src/v6/mod.rs b/polkadot/primitives/src/v6/mod.rs index 89431f7801f..cab34deeb50 100644 --- a/polkadot/primitives/src/v6/mod.rs +++ b/polkadot/primitives/src/v6/mod.rs @@ -533,18 +533,6 @@ impl CandidateReceipt { } } -/// All data pertaining to the execution of a para candidate. -#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)] -pub struct FullCandidateReceipt { - /// The inner candidate receipt. - pub inner: CandidateReceipt, - /// The validation data derived from the relay-chain state at that - /// point. The hash of the persisted validation data should - /// match the `persisted_validation_data_hash` in the descriptor - /// of the receipt. - pub validation_data: PersistedValidationData, -} - /// A candidate-receipt with commitments directly included. #[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)] #[cfg_attr(feature = "std", derive(Hash))] diff --git a/polkadot/roadmap/implementers-guide/src/types/README.md b/polkadot/roadmap/implementers-guide/src/types/README.md index 87092bf3a00..5fd3050f949 100644 --- a/polkadot/roadmap/implementers-guide/src/types/README.md +++ b/polkadot/roadmap/implementers-guide/src/types/README.md @@ -55,17 +55,6 @@ digraph { CandidateCommitmentsHash [label = "Hash", shape="doublecircle", fill="gray90"] CandidateCommitmentsHash -> CandidateCommitments:name - FullCandidateReceipt [label = < - - - - -
FullCandidateReceipt<H = Hash, N = BlockNumber>
innerCandidateReceipt<H>
validation_dataValidationData<N>
- >] - - FullCandidateReceipt:inner -> CandidateReceipt:name - FullCandidateReceipt:validation_data -> ValidationData:name - CommittedCandidateReceipt [label = < diff --git a/polkadot/roadmap/implementers-guide/src/types/candidate.md b/polkadot/roadmap/implementers-guide/src/types/candidate.md index 00176229e5a..399d7854ac4 100644 --- a/polkadot/roadmap/implementers-guide/src/types/candidate.md +++ b/polkadot/roadmap/implementers-guide/src/types/candidate.md @@ -20,12 +20,8 @@ struct ParaId(u32); ## Candidate Receipt -Much info in a [`FullCandidateReceipt`](#full-candidate-receipt) is duplicated from the relay-chain state. When the -corresponding relay-chain state is considered widely available, the Candidate Receipt should be favored over the -`FullCandidateReceipt`. - -Examples of situations where the state is readily available includes within the scope of work done by subsystems working -on a given relay-parent, or within the logic of the runtime importing a backed candidate. +Compact representation of the result of a validation. This is what validators +receive from collators, together with the PoV. ```rust /// A candidate-receipt. @@ -37,24 +33,6 @@ struct CandidateReceipt { } ``` -## Full Candidate Receipt - -This is the full receipt type. The `PersistedValidationData` are technically redundant with the `inner.relay_parent`, -which uniquely describes the block in the blockchain from whose state these values are derived. The -[`CandidateReceipt`](#candidate-receipt) variant is often used instead for this reason. - -However, the Full Candidate Receipt type is useful as a means of avoiding the implicit dependency on availability of old -blockchain state. In situations such as availability and approval, having the full description of the candidate within a -self-contained struct is convenient. - -```rust -/// All data pertaining to the execution of a para candidate. -struct FullCandidateReceipt { - inner: CandidateReceipt, - validation_data: PeristedValidationData, -} -``` - ## Committed Candidate Receipt This is a variant of the candidate receipt which includes the commitments of the candidate receipt alongside the -- GitLab From aa35328371d967e6af20c03e86db0b6e5c11cdf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=B3nal=20Murray?= Date: Mon, 11 Mar 2024 21:12:27 +0700 Subject: [PATCH 021/187] [pallet_broker] Fix `adapt_price` behaviour at zero (#3636) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the behaviour of `Linear` which is the default implementation of the `AdaptPrice` trait in the broker pallet. Previously if cores were offered but not sold in only one sale, the price would be set to zero and due to the logic being purely multiplicative, the price would stay at 0 indefinitely. This could be further paired with a configurable minimum in the broker pallet itself, which will be a future PR. This affects the Rococo and Westend Coretime chains, but Kusama has a different implementation so this isn't required for the Kusama launch. I actually thought I opened this a while ago. --------- Co-authored-by: Bastian Köcher --- prdoc/pr_3636.prdoc | 15 +++++++++ substrate/frame/broker/src/adapt_price.rs | 38 ++++++++++++++++++++--- 2 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 prdoc/pr_3636.prdoc diff --git a/prdoc/pr_3636.prdoc b/prdoc/pr_3636.prdoc new file mode 100644 index 00000000000..934158ac102 --- /dev/null +++ b/prdoc/pr_3636.prdoc @@ -0,0 +1,15 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "[pallet_broker] Fix `Linear::adapt_price` behavior at zero" + +doc: + - audience: Runtime Dev + description: | + This fixes the behaviour of `Linear` which is the default implementation of the `AdaptPrice` + trait in the broker pallet. Previously if cores were offered but not sold in only one sale, + the price would be set to zero and due to the logic being purely multiplicative, the price + would stay at 0 indefinitely. + +crates: + - name: pallet-broker diff --git a/substrate/frame/broker/src/adapt_price.rs b/substrate/frame/broker/src/adapt_price.rs index 8266625687a..fbcd7afdf0d 100644 --- a/substrate/frame/broker/src/adapt_price.rs +++ b/substrate/frame/broker/src/adapt_price.rs @@ -19,6 +19,7 @@ use crate::CoreIndex; use sp_arithmetic::{traits::One, FixedU64}; +use sp_runtime::Saturating; /// Type for determining how to set price. pub trait AdaptPrice { @@ -49,14 +50,24 @@ impl AdaptPrice for () { pub struct Linear; impl AdaptPrice for Linear { fn leadin_factor_at(when: FixedU64) -> FixedU64 { - FixedU64::from(2) - when + FixedU64::from(2).saturating_sub(when) } fn adapt_price(sold: CoreIndex, target: CoreIndex, limit: CoreIndex) -> FixedU64 { if sold <= target { - FixedU64::from_rational(sold.into(), target.into()) + // Range of [0.5, 1.0]. + FixedU64::from_rational(1, 2).saturating_add(FixedU64::from_rational( + sold.into(), + target.saturating_mul(2).into(), + )) } else { - FixedU64::one() + - FixedU64::from_rational((sold - target).into(), (limit - target).into()) + // Range of (1.0, 2]. + + // Unchecked math: In this branch we know that sold > target. The limit must be >= sold + // by construction, and thus target must be < limit. + FixedU64::one().saturating_add(FixedU64::from_rational( + (sold - target).into(), + (limit - target).into(), + )) } } } @@ -81,4 +92,23 @@ mod tests { } } } + + #[test] + fn linear_bound_check() { + // Using constraints from pallet implementation i.e. `limit >= sold`. + // Check extremes + let limit = 10; + let target = 5; + + // Maximally sold: `sold == limit` + assert_eq!(Linear::adapt_price(limit, target, limit), FixedU64::from_float(2.0)); + // Ideally sold: `sold == target` + assert_eq!(Linear::adapt_price(target, target, limit), FixedU64::one()); + // Minimally sold: `sold == 0` + assert_eq!(Linear::adapt_price(0, target, limit), FixedU64::from_float(0.5)); + // Optimistic target: `target == limit` + assert_eq!(Linear::adapt_price(limit, limit, limit), FixedU64::one()); + // Pessimistic target: `target == 0` + assert_eq!(Linear::adapt_price(limit, 0, limit), FixedU64::from_float(2.0)); + } } -- GitLab From 4249a3d6cbca1da2ee15237c05691005973502e9 Mon Sep 17 00:00:00 2001 From: s0me0ne-unkn0wn <48632512+s0me0ne-unkn0wn@users.noreply.github.com> Date: Mon, 11 Mar 2024 15:38:44 +0100 Subject: [PATCH 022/187] Remove getters from `im-online` pallet (#3589) As I've been dancing around this pallet for quite some time anyway, I decided to remove getters at once. There were only a few leftovers in tests. Related: #3326 CC @muraca --- prdoc/pr_3589.prdoc | 10 ++++++++++ substrate/frame/im-online/src/lib.rs | 12 ++++-------- substrate/frame/im-online/src/tests.rs | 9 +++------ 3 files changed, 17 insertions(+), 14 deletions(-) create mode 100644 prdoc/pr_3589.prdoc diff --git a/prdoc/pr_3589.prdoc b/prdoc/pr_3589.prdoc new file mode 100644 index 00000000000..98b9b1039ab --- /dev/null +++ b/prdoc/pr_3589.prdoc @@ -0,0 +1,10 @@ +title: Removed `pallet::getter` usage from `pallet-im-online` + +doc: + - audience: Runtime Dev + description: | + This PR removes `pallet::getter` usage from `pallet-im-online`, and updates dependant code accordingly. + The syntax `StorageItem::::get()` should be used instead. + +crates: + - name: pallet-im-online diff --git a/substrate/frame/im-online/src/lib.rs b/substrate/frame/im-online/src/lib.rs index f14093aa09a..239b47834d1 100644 --- a/substrate/frame/im-online/src/lib.rs +++ b/substrate/frame/im-online/src/lib.rs @@ -338,26 +338,22 @@ pub mod pallet { /// progress estimate from `NextSessionRotation`, as those estimates should be /// more accurate then the value we calculate for `HeartbeatAfter`. #[pallet::storage] - #[pallet::getter(fn heartbeat_after)] - pub(super) type HeartbeatAfter = StorageValue<_, BlockNumberFor, ValueQuery>; + pub type HeartbeatAfter = StorageValue<_, BlockNumberFor, ValueQuery>; /// The current set of keys that may issue a heartbeat. #[pallet::storage] - #[pallet::getter(fn keys)] - pub(super) type Keys = + pub type Keys = StorageValue<_, WeakBoundedVec, ValueQuery>; /// For each session index, we keep a mapping of `SessionIndex` and `AuthIndex`. #[pallet::storage] - #[pallet::getter(fn received_heartbeats)] - pub(super) type ReceivedHeartbeats = + pub type ReceivedHeartbeats = StorageDoubleMap<_, Twox64Concat, SessionIndex, Twox64Concat, AuthIndex, bool>; /// For each session index, we keep a mapping of `ValidatorId` to the /// number of blocks authored by the given authority. #[pallet::storage] - #[pallet::getter(fn authored_blocks)] - pub(super) type AuthoredBlocks = StorageDoubleMap< + pub type AuthoredBlocks = StorageDoubleMap< _, Twox64Concat, SessionIndex, diff --git a/substrate/frame/im-online/src/tests.rs b/substrate/frame/im-online/src/tests.rs index 7efca926eb0..6f5a14d7e7f 100644 --- a/substrate/frame/im-online/src/tests.rs +++ b/substrate/frame/im-online/src/tests.rs @@ -26,10 +26,7 @@ use sp_core::offchain::{ testing::{TestOffchainExt, TestTransactionPoolExt}, OffchainDbExt, OffchainWorkerExt, TransactionPoolExt, }; -use sp_runtime::{ - testing::UintAuthorityId, - transaction_validity::{InvalidTransaction, TransactionValidityError}, -}; +use sp_runtime::testing::UintAuthorityId; #[test] fn test_unresponsiveness_slash_fraction() { @@ -267,14 +264,14 @@ fn should_cleanup_received_heartbeats_on_session_end() { let _ = heartbeat(1, 2, 0, 1.into(), Session::validators()).unwrap(); // the heartbeat is stored - assert!(!ImOnline::received_heartbeats(&2, &0).is_none()); + assert!(!super::pallet::ReceivedHeartbeats::::get(2, 0).is_none()); advance_session(); // after the session has ended we have already processed the heartbeat // message, so any messages received on the previous session should have // been pruned. - assert!(ImOnline::received_heartbeats(&2, &0).is_none()); + assert!(super::pallet::ReceivedHeartbeats::::get(2, 0).is_none()); }); } -- GitLab From 02f1f2c47609483be04097e27fc52c06883a6540 Mon Sep 17 00:00:00 2001 From: Tsvetomir Dimitrov Date: Mon, 11 Mar 2024 18:00:52 +0200 Subject: [PATCH 023/187] Small fixes in para-scheduler pallet (#3524) Fixes some typos, outdated comments and test asserts. Also uses safe math and `defensive` for arithmetic operations. --- polkadot/runtime/parachains/src/scheduler.rs | 23 ++++++++++++------- .../runtime/parachains/src/scheduler/tests.rs | 11 +++++---- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/polkadot/runtime/parachains/src/scheduler.rs b/polkadot/runtime/parachains/src/scheduler.rs index 61ab36dbe96..f231864a85e 100644 --- a/polkadot/runtime/parachains/src/scheduler.rs +++ b/polkadot/runtime/parachains/src/scheduler.rs @@ -37,7 +37,7 @@ //! availability cores over time. use crate::{configuration, initializer::SessionChangeNotification, paras}; -use frame_support::pallet_prelude::*; +use frame_support::{pallet_prelude::*, traits::Defensive}; use frame_system::pallet_prelude::BlockNumberFor; pub use polkadot_core_primitives::v2::BlockNumber; use primitives::{ @@ -59,6 +59,7 @@ pub use pallet::*; mod tests; const LOG_TARGET: &str = "runtime::parachains::scheduler"; + pub mod migration; #[frame_support::pallet] @@ -88,10 +89,8 @@ pub mod pallet { #[pallet::getter(fn validator_groups)] pub(crate) type ValidatorGroups = StorageValue<_, Vec>, ValueQuery>; - /// One entry for each availability core. Entries are `None` if the core is not currently - /// occupied. Can be temporarily `Some` if scheduled but not occupied. - /// The i'th parachain belongs to the i'th core, with the remaining cores all being - /// parathread-multiplexers. + /// One entry for each availability core. The i'th parachain belongs to the i'th core, with the + /// remaining cores all being on demand parachain multiplexers. /// /// Bounded by the maximum of either of these two values: /// * The number of parachains and parathread multiplexers @@ -146,7 +145,7 @@ pub mod pallet { /// One entry for each availability core. The `VecDeque` represents the assignments to be /// scheduled on that core. The value contained here will not be valid after the end of - /// a block. Runtime APIs should be used to determine scheduled cores/ for the upcoming block. + /// a block. Runtime APIs should be used to determine scheduled cores for the upcoming block. #[pallet::storage] #[pallet::getter(fn claimqueue)] pub(crate) type ClaimQueue = @@ -236,8 +235,16 @@ impl Pallet { if n_cores == 0 || validators.is_empty() { ValidatorGroups::::set(Vec::new()); } else { - let group_base_size = validators.len() / n_cores as usize; - let n_larger_groups = validators.len() % n_cores as usize; + let group_base_size = validators + .len() + .checked_div(n_cores as usize) + .defensive_proof("n_cores should not be 0") + .unwrap_or(0); + let n_larger_groups = validators + .len() + .checked_rem(n_cores as usize) + .defensive_proof("n_cores should not be 0") + .unwrap_or(0); // Groups contain indices into the validators from the session change notification, // which are already shuffled. diff --git a/polkadot/runtime/parachains/src/scheduler/tests.rs b/polkadot/runtime/parachains/src/scheduler/tests.rs index 28b3a6b4f5d..e6a1e66b3a5 100644 --- a/polkadot/runtime/parachains/src/scheduler/tests.rs +++ b/polkadot/runtime/parachains/src/scheduler/tests.rs @@ -213,6 +213,7 @@ fn claimqueue_ttl_drop_fn_works() { // Drop expired claim. Scheduler::drop_expired_claims_from_claimqueue(); + assert!(!claimqueue_contains_para_ids::(vec![para_id])); // Add a claim on core 0 with a ttl == now (17) let paras_entry_non_expired = ParasEntry::new(Assignment::Bulk(para_id), now); @@ -222,7 +223,7 @@ fn claimqueue_ttl_drop_fn_works() { Scheduler::add_to_claimqueue(core_idx, paras_entry_expired.clone()); Scheduler::add_to_claimqueue(core_idx, paras_entry_non_expired.clone()); let cq = Scheduler::claimqueue(); - assert!(cq.get(&core_idx).unwrap().len() == 3); + assert_eq!(cq.get(&core_idx).unwrap().len(), 3); // Add a claim to the test assignment provider. let assignment = Assignment::Bulk(para_id); @@ -234,8 +235,9 @@ fn claimqueue_ttl_drop_fn_works() { let cq = Scheduler::claimqueue(); let cqc = cq.get(&core_idx).unwrap(); - // Same number of claims - assert!(cqc.len() == 3); + // Same number of claims, because a new claim is popped from `MockAssigner` instead of the + // expired one + assert_eq!(cqc.len(), 3); // The first 2 claims in the queue should have a ttl of 17, // being the ones set up prior in this test as claims 1 and 3. @@ -355,14 +357,13 @@ fn fill_claimqueue_fills() { schedule_blank_para(para_b); schedule_blank_para(para_c); - // start a new session to activate, 3 validators for 3 cores. + // start a new session to activate, 2 validators for 2 cores. run_to_block(1, |number| match number { 1 => Some(SessionChangeNotification { new_config: default_config(), validators: vec![ ValidatorId::from(Sr25519Keyring::Alice.public()), ValidatorId::from(Sr25519Keyring::Bob.public()), - ValidatorId::from(Sr25519Keyring::Charlie.public()), ], ..Default::default() }), -- GitLab From 05381afcb2e2015fe7f379ddba7522d595a5e8cc Mon Sep 17 00:00:00 2001 From: Andrei Eres Date: Mon, 11 Mar 2024 17:17:45 +0100 Subject: [PATCH 024/187] subsystem-bench: adjust test config to Kusama (#3583) Fixes https://github.com/paritytech/polkadot-sdk/issues/3528 ```rust latency: mean_latency_ms = 30 // common sense std_dev = 2.0 // common sense n_validators = 300 // max number of validators, from chain config n_cores = 60 // 300/5 max_validators_per_core = 5 // default min_pov_size = 5120 // max max_pov_size = 5120 // max peer_bandwidth = 44040192 // from the Parity's kusama validators bandwidth = 44040192 // from the Parity's kusama validators connectivity = 90 // we need to be connected to 90-95% of peers ``` --- ...ilability-distribution-regression-bench.rs | 19 +++------- .../availability-recovery-regression-bench.rs | 13 +------ .../subsystem-bench/src/lib/configuration.rs | 38 ++++++++++++++----- 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/polkadot/node/network/availability-distribution/tests/availability-distribution-regression-bench.rs b/polkadot/node/network/availability-distribution/tests/availability-distribution-regression-bench.rs index f2872f3c72b..7a490d5e47f 100644 --- a/polkadot/node/network/availability-distribution/tests/availability-distribution-regression-bench.rs +++ b/polkadot/node/network/availability-distribution/tests/availability-distribution-regression-bench.rs @@ -16,7 +16,7 @@ //! availability-read regression tests //! -//! TODO: Explain the test case after configuration adjusted to Kusama +//! Availability read benchmark based on Kusama parameters and scale. //! //! Subsystems involved: //! - availability-distribution @@ -25,28 +25,19 @@ use polkadot_subsystem_bench::{ availability::{benchmark_availability_write, prepare_test, TestDataAvailability, TestState}, - configuration::{PeerLatency, TestConfiguration}, + configuration::TestConfiguration, usage::BenchmarkUsage, }; const BENCH_COUNT: usize = 3; -const WARM_UP_COUNT: usize = 20; +const WARM_UP_COUNT: usize = 30; const WARM_UP_PRECISION: f64 = 0.01; fn main() -> Result<(), String> { let mut messages = vec![]; - - // TODO: Adjust the test configurations to Kusama values let mut config = TestConfiguration::default(); - config.latency = Some(PeerLatency { mean_latency_ms: 30, std_dev: 2.0 }); - config.n_validators = 1000; - config.n_cores = 200; - config.max_validators_per_core = 5; - config.min_pov_size = 5120; - config.max_pov_size = 5120; - config.peer_bandwidth = 52428800; - config.bandwidth = 52428800; - config.connectivity = 75; + // A single node effort roughly n_cores * needed_approvals / n_validators = 60 * 30 / 300 + config.n_cores = 6; config.num_blocks = 3; config.generate_pov_sizes(); diff --git a/polkadot/node/network/availability-recovery/tests/availability-recovery-regression-bench.rs b/polkadot/node/network/availability-recovery/tests/availability-recovery-regression-bench.rs index beb063e7ae0..30cc4d47ecc 100644 --- a/polkadot/node/network/availability-recovery/tests/availability-recovery-regression-bench.rs +++ b/polkadot/node/network/availability-recovery/tests/availability-recovery-regression-bench.rs @@ -16,7 +16,7 @@ //! availability-write regression tests //! -//! TODO: Explain the test case after configuration adjusted to Kusama +//! Availability write benchmark based on Kusama parameters and scale. //! //! Subsystems involved: //! - availability-recovery @@ -26,7 +26,7 @@ use polkadot_subsystem_bench::{ benchmark_availability_read, prepare_test, DataAvailabilityReadOptions, TestDataAvailability, TestState, }, - configuration::{PeerLatency, TestConfiguration}, + configuration::TestConfiguration, usage::BenchmarkUsage, }; @@ -37,18 +37,9 @@ const WARM_UP_PRECISION: f64 = 0.01; fn main() -> Result<(), String> { let mut messages = vec![]; - // TODO: Adjust the test configurations to Kusama values let options = DataAvailabilityReadOptions { fetch_from_backers: true }; let mut config = TestConfiguration::default(); - config.latency = Some(PeerLatency { mean_latency_ms: 100, std_dev: 1.0 }); - config.n_validators = 300; - config.n_cores = 20; - config.min_pov_size = 5120; - config.max_pov_size = 5120; - config.peer_bandwidth = 52428800; - config.bandwidth = 52428800; config.num_blocks = 3; - config.connectivity = 90; config.generate_pov_sizes(); warm_up(config.clone(), options.clone())?; diff --git a/polkadot/node/subsystem-bench/src/lib/configuration.rs b/polkadot/node/subsystem-bench/src/lib/configuration.rs index c7693308527..17c81c4fd35 100644 --- a/polkadot/node/subsystem-bench/src/lib/configuration.rs +++ b/polkadot/node/subsystem-bench/src/lib/configuration.rs @@ -35,19 +35,34 @@ pub struct PeerLatency { pub std_dev: f64, } +// Based on Kusama `max_validators` +fn default_n_validators() -> usize { + 300 +} + +// Based on Kusama cores +fn default_n_cores() -> usize { + 60 +} + // Default PoV size in KiB. fn default_pov_size() -> usize { - 5120 + 5 * 1024 } -// Default bandwidth in bytes +// Default bandwidth in bytes, based stats from Kusama validators fn default_bandwidth() -> usize { - 52428800 + 42 * 1024 * 1024 +} + +// Default peer latency +fn default_peer_latency() -> Option { + Some(PeerLatency { mean_latency_ms: 30, std_dev: 2.0 }) } // Default connectivity percentage fn default_connectivity() -> usize { - 100 + 90 } // Default backing group size @@ -63,6 +78,7 @@ fn default_needed_approvals() -> usize { fn default_zeroth_delay_tranche_width() -> usize { 0 } + fn default_relay_vrf_modulo_samples() -> usize { 6 } @@ -78,8 +94,10 @@ fn default_no_show_slots() -> usize { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct TestConfiguration { /// Number of validators + #[serde(default = "default_n_validators")] pub n_validators: usize, /// Number of cores + #[serde(default = "default_n_cores")] pub n_cores: usize, /// The number of needed votes to approve a candidate. #[serde(default = "default_needed_approvals")] @@ -111,10 +129,10 @@ pub struct TestConfiguration { #[serde(default = "default_bandwidth")] pub bandwidth: usize, /// Optional peer emulation latency (round trip time) wrt node under test - #[serde(default)] + #[serde(default = "default_peer_latency")] pub latency: Option, - /// Connectivity ratio, the percentage of peers we are not connected to, but ar part of - /// the topology. + /// Connectivity ratio, the percentage of peers we are connected to, but as part of the + /// topology. #[serde(default = "default_connectivity")] pub connectivity: usize, /// Number of blocks to run the test for @@ -124,8 +142,8 @@ pub struct TestConfiguration { impl Default for TestConfiguration { fn default() -> Self { Self { - n_validators: Default::default(), - n_cores: Default::default(), + n_validators: default_n_validators(), + n_cores: default_n_cores(), needed_approvals: default_needed_approvals(), zeroth_delay_tranche_width: default_zeroth_delay_tranche_width(), relay_vrf_modulo_samples: default_relay_vrf_modulo_samples(), @@ -137,7 +155,7 @@ impl Default for TestConfiguration { pov_sizes: Default::default(), peer_bandwidth: default_bandwidth(), bandwidth: default_bandwidth(), - latency: Default::default(), + latency: default_peer_latency(), connectivity: default_connectivity(), num_blocks: Default::default(), } -- GitLab From d3f81056ad1054731e711f2761673ef72686697f Mon Sep 17 00:00:00 2001 From: philoniare Date: Tue, 12 Mar 2024 04:39:21 +0800 Subject: [PATCH 025/187] [Deprecation] Remove the deprecated Store trait (#3532) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description *Removes the deprecated `trait Store` feature from the code base* Fixes #222 --------- Co-authored-by: Dónal Murray --- prdoc/pr_3532.prdoc | 15 +++++ substrate/frame/support/procedural/src/lib.rs | 10 --- .../procedural/src/pallet/expand/mod.rs | 3 - .../src/pallet/expand/store_trait.rs | 67 ------------------- .../procedural/src/pallet/parse/mod.rs | 2 - .../src/pallet/parse/pallet_struct.rs | 26 +------ substrate/frame/support/src/lib.rs | 24 +------ .../tests/pallet_ui/deprecated_store_attr.rs | 28 -------- .../pallet_ui/deprecated_store_attr.stderr | 10 --- .../tests/pallet_ui/duplicate_store_attr.rs | 42 ------------ .../pallet_ui/duplicate_store_attr.stderr | 5 -- .../pallet_struct_invalid_attr.stderr | 2 +- .../pallet_ui/store_trait_leak_private.rs | 42 ------------ .../pallet_ui/store_trait_leak_private.stderr | 19 ------ .../support/test/tests/storage_transaction.rs | 1 - 15 files changed, 20 insertions(+), 276 deletions(-) create mode 100644 prdoc/pr_3532.prdoc delete mode 100644 substrate/frame/support/procedural/src/pallet/expand/store_trait.rs delete mode 100644 substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.rs delete mode 100644 substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.stderr delete mode 100644 substrate/frame/support/test/tests/pallet_ui/duplicate_store_attr.rs delete mode 100644 substrate/frame/support/test/tests/pallet_ui/duplicate_store_attr.stderr delete mode 100644 substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.rs delete mode 100644 substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.stderr diff --git a/prdoc/pr_3532.prdoc b/prdoc/pr_3532.prdoc new file mode 100644 index 00000000000..d47c8d1d491 --- /dev/null +++ b/prdoc/pr_3532.prdoc @@ -0,0 +1,15 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Remove deprecated `trait Store` + +doc: + - audience: Runtime Dev + description: | + The deprecated `trait Store` feature has been removed from the codebase. Please remove usages of `generate_store` + macro from your pallets and access the storage through generics. For example, + `::StoredRange::mutate` will need to be updated to `StoredRange::::mutate`. + +crates: + - name: frame-support + - name: frame \ No newline at end of file diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index 036da52a7ba..89e39a5c9bb 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -858,16 +858,6 @@ pub fn disable_frame_system_supertrait_check(_: TokenStream, _: TokenStream) -> pallet_macro_stub() } -/// -/// --- -/// -/// Rust-Analyzer Users: Documentation for this macro can be found at -/// `frame_support::pallet_macros::generate_store`. -#[proc_macro_attribute] -pub fn generate_store(_: TokenStream, _: TokenStream) -> TokenStream { - pallet_macro_stub() -} - /// /// --- /// diff --git a/substrate/frame/support/procedural/src/pallet/expand/mod.rs b/substrate/frame/support/procedural/src/pallet/expand/mod.rs index 3da7d9293c7..067839c2846 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/mod.rs @@ -31,7 +31,6 @@ mod instances; mod origin; mod pallet_struct; mod storage; -mod store_trait; mod tasks; mod tt_default_parts; mod type_value; @@ -68,7 +67,6 @@ pub fn expand(mut def: Def) -> proc_macro2::TokenStream { let storages = storage::expand_storages(&mut def); let inherents = inherent::expand_inherents(&mut def); let instances = instances::expand_instances(&mut def); - let store_trait = store_trait::expand_store_trait(&mut def); let hooks = hooks::expand_hooks(&mut def); let genesis_build = genesis_build::expand_genesis_build(&mut def); let genesis_config = genesis_config::expand_genesis_config(&mut def); @@ -110,7 +108,6 @@ storage item. Otherwise, all storage items are listed among [*Type Definitions*] #storages #inherents #instances - #store_trait #hooks #genesis_build #genesis_config diff --git a/substrate/frame/support/procedural/src/pallet/expand/store_trait.rs b/substrate/frame/support/procedural/src/pallet/expand/store_trait.rs deleted file mode 100644 index 6635adc9881..00000000000 --- a/substrate/frame/support/procedural/src/pallet/expand/store_trait.rs +++ /dev/null @@ -1,67 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::pallet::Def; -use syn::spanned::Spanned; - -/// If attribute `#[pallet::generate_store(..)]` is defined then: -/// * generate Store trait with all storages, -/// * implement Store trait for Pallet. -pub fn expand_store_trait(def: &mut Def) -> proc_macro2::TokenStream { - let (trait_vis, trait_store, attribute_span) = - if let Some(store) = &def.pallet_struct.store { store } else { return Default::default() }; - - let type_impl_gen = &def.type_impl_generics(trait_store.span()); - let type_use_gen = &def.type_use_generics(trait_store.span()); - let pallet_ident = &def.pallet_struct.pallet; - - let mut where_clauses = vec![&def.config.where_clause]; - where_clauses.extend(def.storages.iter().map(|storage| &storage.where_clause)); - let completed_where_clause = super::merge_where_clauses(&where_clauses); - - let storage_names = &def.storages.iter().map(|storage| &storage.ident).collect::>(); - let storage_cfg_attrs = - &def.storages.iter().map(|storage| &storage.cfg_attrs).collect::>(); - let warnig_struct_name = syn::Ident::new("Store", *attribute_span); - let warning: syn::ItemStruct = syn::parse_quote!( - #[deprecated(note = r" - Use of `#[pallet::generate_store(pub(super) trait Store)]` will be removed after July 2023. - Check https://github.com/paritytech/substrate/pull/13535 for more details.")] - struct #warnig_struct_name; - ); - - quote::quote_spanned!(trait_store.span() => - const _:() = { - #warning - const _: Option<#warnig_struct_name> = None; - }; - #trait_vis trait #trait_store { - #( - #(#storage_cfg_attrs)* - type #storage_names; - )* - } - impl<#type_impl_gen> #trait_store for #pallet_ident<#type_use_gen> - #completed_where_clause - { - #( - #(#storage_cfg_attrs)* - type #storage_names = #storage_names<#type_use_gen>; - )* - } - ) -} diff --git a/substrate/frame/support/procedural/src/pallet/parse/mod.rs b/substrate/frame/support/procedural/src/pallet/parse/mod.rs index e1efdbcc202..b55f130a93a 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/mod.rs @@ -558,8 +558,6 @@ mod keyword { syn::custom_keyword!(validate_unsigned); syn::custom_keyword!(type_value); syn::custom_keyword!(pallet); - syn::custom_keyword!(generate_store); - syn::custom_keyword!(Store); syn::custom_keyword!(extra_constants); syn::custom_keyword!(composite_enum); } diff --git a/substrate/frame/support/procedural/src/pallet/parse/pallet_struct.rs b/substrate/frame/support/procedural/src/pallet/parse/pallet_struct.rs index c2855ae38ef..b645760998f 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/pallet_struct.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/pallet_struct.rs @@ -23,10 +23,8 @@ use syn::spanned::Spanned; mod keyword { syn::custom_keyword!(pallet); syn::custom_keyword!(Pallet); - syn::custom_keyword!(generate_store); syn::custom_keyword!(without_storage_info); syn::custom_keyword!(storage_version); - syn::custom_keyword!(Store); } /// Definition of the pallet pallet. @@ -37,8 +35,6 @@ pub struct PalletStructDef { pub instances: Vec, /// The keyword Pallet used (contains span). pub pallet: keyword::Pallet, - /// Whether the trait `Store` must be generated. - pub store: Option<(syn::Visibility, keyword::Store, proc_macro2::Span)>, /// The span of the pallet::pallet attribute. pub attr_span: proc_macro2::Span, /// Whether to specify the storages max encoded len when implementing `StorageInfoTrait`. @@ -49,11 +45,9 @@ pub struct PalletStructDef { } /// Parse for one variant of: -/// * `#[pallet::generate_store($vis trait Store)]` /// * `#[pallet::without_storage_info]` /// * `#[pallet::storage_version(STORAGE_VERSION)]` pub enum PalletStructAttr { - GenerateStore { span: proc_macro2::Span, vis: syn::Visibility, keyword: keyword::Store }, WithoutStorageInfoTrait(proc_macro2::Span), StorageVersion { storage_version: syn::Path, span: proc_macro2::Span }, } @@ -61,9 +55,7 @@ pub enum PalletStructAttr { impl PalletStructAttr { fn span(&self) -> proc_macro2::Span { match self { - Self::GenerateStore { span, .. } | - Self::WithoutStorageInfoTrait(span) | - Self::StorageVersion { span, .. } => *span, + Self::WithoutStorageInfoTrait(span) | Self::StorageVersion { span, .. } => *span, } } } @@ -77,16 +69,7 @@ impl syn::parse::Parse for PalletStructAttr { content.parse::()?; let lookahead = content.lookahead1(); - if lookahead.peek(keyword::generate_store) { - content.parse::()?; - let generate_content; - syn::parenthesized!(generate_content in content); - let vis = generate_content.parse::()?; - generate_content.parse::()?; - let keyword = generate_content.parse::()?; - let span = content.span(); - Ok(Self::GenerateStore { vis, keyword, span }) - } else if lookahead.peek(keyword::without_storage_info) { + if lookahead.peek(keyword::without_storage_info) { let span = content.parse::()?.span(); Ok(Self::WithoutStorageInfoTrait(span)) } else if lookahead.peek(keyword::storage_version) { @@ -116,16 +99,12 @@ impl PalletStructDef { return Err(syn::Error::new(item.span(), msg)) }; - let mut store = None; let mut without_storage_info = None; let mut storage_version_found = None; let struct_attrs: Vec = helper::take_item_pallet_attrs(&mut item.attrs)?; for attr in struct_attrs { match attr { - PalletStructAttr::GenerateStore { vis, keyword, span } if store.is_none() => { - store = Some((vis, keyword, span)); - }, PalletStructAttr::WithoutStorageInfoTrait(span) if without_storage_info.is_none() => { @@ -162,7 +141,6 @@ impl PalletStructDef { index, instances, pallet, - store, attr_span, without_storage_info, storage_version: storage_version_found, diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 6ea7fa33e77..07560abd935 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -702,7 +702,7 @@ pub use frame_support_procedural::crate_to_crate_version; #[macro_export] macro_rules! fail { ( $y:expr ) => {{ - return Err($y.into()) + return Err($y.into()); }}; } @@ -949,7 +949,7 @@ pub mod pallet_prelude { /// pub trait Config: frame_system::Config {} /// } /// ``` -/// +// /// I.e. a regular struct definition named `Pallet`, with generic T and no where clause. /// /// ## Macro expansion: @@ -1341,26 +1341,6 @@ pub mod pallet_macros { /// See [`pallet::storage`](`frame_support::pallet_macros::storage`) for more info. pub use frame_support_procedural::getter; - /// Allows generating the `Store` trait for all storages. - /// - /// DEPRECATED: Will be removed, do not use. - /// See for more details. - /// - /// To generate a `Store` trait associating all storages, annotate your `Pallet` struct - /// with the attribute `#[pallet::generate_store($vis trait Store)]`, e.g.: - /// - /// ```ignore - /// #[pallet::pallet] - /// #[pallet::generate_store(pub(super) trait Store)] - /// pub struct Pallet(_); - /// ``` - /// More precisely, the `Store` trait contains an associated type for each storage. It is - /// implemented for `Pallet` allowing access to the storage from pallet struct. - /// - /// Thus when defining a storage named `Foo`, it can later be accessed from `Pallet` using - /// `::Foo`. - pub use frame_support_procedural::generate_store; - /// Defines constants that are added to the constant field of /// [`PalletMetadata`](frame_metadata::v15::PalletMetadata) struct for this pallet. /// diff --git a/substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.rs b/substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.rs deleted file mode 100644 index 72ad7896dfe..00000000000 --- a/substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.rs +++ /dev/null @@ -1,28 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#[frame_support::pallet] -mod pallet { - #[pallet::config] - pub trait Config: frame_system::Config {} - - #[pallet::pallet] - #[pallet::generate_store(trait Store)] - pub struct Pallet(core::marker::PhantomData); -} - -fn main() {} diff --git a/substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.stderr b/substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.stderr deleted file mode 100644 index e227033d364..00000000000 --- a/substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: use of deprecated struct `pallet::_::Store`: - Use of `#[pallet::generate_store(pub(super) trait Store)]` will be removed after July 2023. - Check https://github.com/paritytech/substrate/pull/13535 for more details. - --> tests/pallet_ui/deprecated_store_attr.rs:24:3 - | -24 | #[pallet::generate_store(trait Store)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D deprecated` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(deprecated)]` diff --git a/substrate/frame/support/test/tests/pallet_ui/duplicate_store_attr.rs b/substrate/frame/support/test/tests/pallet_ui/duplicate_store_attr.rs deleted file mode 100644 index 334fd8a46af..00000000000 --- a/substrate/frame/support/test/tests/pallet_ui/duplicate_store_attr.rs +++ /dev/null @@ -1,42 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#[frame_support::pallet] -mod pallet { - use frame_support::pallet_prelude::Hooks; - use frame_system::pallet_prelude::BlockNumberFor; - use frame_support::pallet_prelude::StorageValue; - - #[pallet::config] - pub trait Config: frame_system::Config {} - - #[pallet::pallet] - #[pallet::generate_store(trait Store)] - #[pallet::generate_store(trait Store)] - pub struct Pallet(core::marker::PhantomData); - - #[pallet::hooks] - impl Hooks> for Pallet {} - - #[pallet::call] - impl Pallet {} - - #[pallet::storage] - type Foo = StorageValue<_, u8>; -} - -fn main() {} diff --git a/substrate/frame/support/test/tests/pallet_ui/duplicate_store_attr.stderr b/substrate/frame/support/test/tests/pallet_ui/duplicate_store_attr.stderr deleted file mode 100644 index 864b399326e..00000000000 --- a/substrate/frame/support/test/tests/pallet_ui/duplicate_store_attr.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: Unexpected duplicated attribute - --> tests/pallet_ui/duplicate_store_attr.rs:29:3 - | -29 | #[pallet::generate_store(trait Store)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/pallet_struct_invalid_attr.stderr b/substrate/frame/support/test/tests/pallet_ui/pallet_struct_invalid_attr.stderr index 33a2d1da786..6f7f5617f7e 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pallet_struct_invalid_attr.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/pallet_struct_invalid_attr.stderr @@ -1,4 +1,4 @@ -error: expected one of: `generate_store`, `without_storage_info`, `storage_version` +error: expected `without_storage_info` or `storage_version` --> tests/pallet_ui/pallet_struct_invalid_attr.rs:24:12 | 24 | #[pallet::generate_storage_info] // invalid diff --git a/substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.rs b/substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.rs deleted file mode 100644 index 55dd315fb29..00000000000 --- a/substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.rs +++ /dev/null @@ -1,42 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#[frame_support::pallet] -mod pallet { - use frame_support::pallet_prelude::Hooks; - use frame_system::pallet_prelude::BlockNumberFor; - use frame_support::pallet_prelude::StorageValue; - - #[pallet::config] - pub trait Config: frame_system::Config {} - - #[pallet::pallet] - #[pallet::generate_store(pub trait Store)] - pub struct Pallet(core::marker::PhantomData); - - #[pallet::hooks] - impl Hooks> for Pallet {} - - #[pallet::call] - impl Pallet {} - - #[pallet::storage] - type Foo = StorageValue<_, u8>; -} - -fn main() { -} diff --git a/substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.stderr b/substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.stderr deleted file mode 100644 index ccb55122e81..00000000000 --- a/substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error: use of deprecated struct `pallet::_::Store`: - Use of `#[pallet::generate_store(pub(super) trait Store)]` will be removed after July 2023. - Check https://github.com/paritytech/substrate/pull/13535 for more details. - --> tests/pallet_ui/store_trait_leak_private.rs:28:3 - | -28 | #[pallet::generate_store(pub trait Store)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D deprecated` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(deprecated)]` - -error[E0446]: private type `_GeneratedPrefixForStorageFoo` in public interface - --> tests/pallet_ui/store_trait_leak_private.rs:28:37 - | -28 | #[pallet::generate_store(pub trait Store)] - | ^^^^^ can't leak private type -... -37 | #[pallet::storage] - | ------- `_GeneratedPrefixForStorageFoo` declared as private diff --git a/substrate/frame/support/test/tests/storage_transaction.rs b/substrate/frame/support/test/tests/storage_transaction.rs index c4774330860..f1489a8b0a6 100644 --- a/substrate/frame/support/test/tests/storage_transaction.rs +++ b/substrate/frame/support/test/tests/storage_transaction.rs @@ -41,7 +41,6 @@ pub mod pallet { use frame_system::pallet_prelude::*; #[pallet::pallet] - #[pallet::generate_store(pub (super) trait Store)] pub struct Pallet(_); #[pallet::config] -- GitLab From 7839400f1203b1c1de2ff84db5f5ffcf31e20d87 Mon Sep 17 00:00:00 2001 From: georgepisaltu <52418509+georgepisaltu@users.noreply.github.com> Date: Tue, 12 Mar 2024 00:12:58 +0200 Subject: [PATCH 026/187] [Collator Selection] Fix weight refund for `set_candidacy_bond` (#3643) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #3642 This PR implements the weight refund of `pallet_collator_selection::set_candidacy_bond` to account for no iterations when the bond is decreased. --------- Signed-off-by: georgepisaltu Co-authored-by: Bastian Köcher --- cumulus/pallets/collator-selection/src/lib.rs | 6 +++++- prdoc/pr_3643.prdoc | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 prdoc/pr_3643.prdoc diff --git a/cumulus/pallets/collator-selection/src/lib.rs b/cumulus/pallets/collator-selection/src/lib.rs index fb4c4a445df..62c00737f91 100644 --- a/cumulus/pallets/collator-selection/src/lib.rs +++ b/cumulus/pallets/collator-selection/src/lib.rs @@ -495,7 +495,11 @@ pub mod pallet { }) .unwrap_or_default(); Self::deposit_event(Event::NewCandidacyBond { bond_amount: bond }); - Ok(Some(T::WeightInfo::set_candidacy_bond(initial_len as u32, kicked as u32)).into()) + Ok(Some(T::WeightInfo::set_candidacy_bond( + bond_increased.then(|| initial_len as u32).unwrap_or_default(), + kicked as u32, + )) + .into()) } /// Register this account as a collator candidate. The account must (a) already have diff --git a/prdoc/pr_3643.prdoc b/prdoc/pr_3643.prdoc new file mode 100644 index 00000000000..6e85af8d99a --- /dev/null +++ b/prdoc/pr_3643.prdoc @@ -0,0 +1,12 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Fix weight refund for `pallet_collator_selection::set_candidacy_bond` + +doc: + - audience: Runtime Dev + description: | + This PR implements the weight refund of `pallet_collator_selection::set_candidacy_bond` to + account for no iterations over the candidate list when the candidacy bond is decreased. +crates: + - name: pallet-collator-selection -- GitLab From 7a644fa082f09b557a8a198ed56412f02062bbcf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Mar 2024 23:20:48 +0100 Subject: [PATCH 027/187] Bump handlebars from 4.3.7 to 5.1.0 (#3248) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [handlebars](https://github.com/sunng87/handlebars-rust) from 4.3.7 to 5.1.0.
Release notes

Sourced from handlebars's releases.

v5.1.0

What's Changed

New Contributors

Full Changelog: https://github.com/sunng87/handlebars-rust/compare/v5.0.0...v5.1.0

v5.0.0

5.0.0

A semver major release that introduces some API breaking changes.

Highlights

  • RenderError has been rewritten for typed error reason. In previous versions we use string message for RenderError which is impossible to handle with code. This version introduces RenderErrorReason so you can use match to deal various error reasons.
  • Lifetime in Helper trait has been simplified.

Changes compared to 4.3

  • [Added] public mutable access to local variables in BlockContext #533
  • [Changed] Simplified lifetime specifiers for Helper, ScopedJson and some other related types and functions. #532
  • [Changed] Updated TemplateError to reduce its size. Direct field access is removed in favor of access methods
  • [Changed] Introducing RenderErrorReason for typed render error
  • [Changed] Changed register_template_directory api for more customizations #[610]
  • [Changed] Updated rust-embed to 8.0

Collaboration Wanted

I'm looking for collaborations to join the development with me on this project. Contact via email if your are interested in.

Auto-generated changelog

... (truncated)

Changelog

Sourced from handlebars's changelog.

5.1.0 - 2024-01-17

  • [Added] Chained else if block support #629

5.0.0 - 2023-12-31

  • [Added] public mutable access to local variables in BlockContext #533
  • [Changed] Simplified lifetime specifiers for Helper, ScopedJson and some other related types and functions. #532
  • [Changed] Updated TemplateError to reduce its size. Direct field access is removed in favor of access methods
  • [Changed] Introducing RenderErrorReason for typed render error
  • [Changed] Changed register_template_directory api for more customizations #[610]
  • [Changed] Updated rust-embed to 8.0

4.3.4 - 2022-09-11

  • [Added] New write_fmt function for Output #522
  • [Added] reason() method for TemplateError to access underlying reason, this replaces original direct .reason access.
  • [Changed] Direct access to TemplateError's reason field is depreacted will be removed in future.

4.3.3 - 2022-07-20

  • [Fixed] Disable partial expression indentation with {{~> partial}} to bring behavior closer in line with original javascript version. #518
  • [Fixed] Support for using partial context together with partial parameters #520

4.3.2 - 2022-07-14

  • [Added] Render functions that reuse Context for custom std::io::Write: render_with_context_to_write and render_template_with_context_to_write

4.3.1 - 2022-06-09

  • [Added] Added support for {{~{variable}~}} syntax #509

4.3.0 - 2022-05-18

  • [Changed] update MSRV to 1.57 as rhai requires
  • [Fixed] Reimplemented indent support for partial expression {{> partial}}, which is introduced in 4.2.0. The new implementation is aligned with original javascript version, that every text line generated from partial are indented as {{> partial}} does. prevent_indent will turn-off this feature. #505
  • [Changed] changed error support library from quick_error to thiserror

... (truncated)

Commits
  • d8d9a78 chore: Release handlebars version 5.1.0
  • 137bce5 chore: minor cleanup for chained else support in #629
  • e30d8ab Merge pull request #629 from progmboy/else_chain
  • 8f16353 format code
  • 786d132 add else chain support
  • 23672e8 Merge pull request #628 from sunng87/dependabot/npm_and_yarn/playground/www/f...
  • b849efd chore(deps-dev): bump follow-redirects in /playground/www
  • 7071c9d test: add test for error reason
  • 4664a34 (cargo-release) version 5.0.0
  • ca27748 Merge pull request #625 from sunng87/refactor/render-error-reason-2
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=handlebars&package-manager=cargo&previous-version=4.3.7&new-version=5.1.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) You can trigger a rebase of this PR by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
> **Note** > Automatic rebases have been disabled on this pull request as it has been open for over 30 days. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Bastian Köcher --- Cargo.lock | 4 ++-- substrate/utils/frame/benchmarking-cli/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0b7ea71a536..7eaf3e44a1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6256,9 +6256,9 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "handlebars" -version = "4.3.7" +version = "5.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c3372087601b532857d332f5957cbae686da52bb7810bf038c3e3c3cc2fa0d" +checksum = "ab283476b99e66691dee3f1640fea91487a8d81f50fb5ecc75538f8f8879a1e4" dependencies = [ "log", "pest", diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index a2db83052c5..a25ab3a8f5b 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -21,7 +21,7 @@ chrono = "0.4" clap = { version = "4.5.1", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1" } comfy-table = { version = "7.1.0", default-features = false } -handlebars = "4.2.2" +handlebars = "5.1.0" Inflector = "0.11.4" itertools = "0.10.3" lazy_static = "1.4.0" -- GitLab From 7315a9b8fdc18848025a83f18c643573d9be9e1e Mon Sep 17 00:00:00 2001 From: gupnik Date: Tue, 12 Mar 2024 10:12:58 +0530 Subject: [PATCH 028/187] Adds default config for assets pallet (#3637) Step in https://github.com/paritytech/polkadot-sdk/issues/171 --- substrate/frame/assets/src/lib.rs | 43 +++++++++++++++++++++++++++++- substrate/frame/assets/src/mock.rs | 16 +---------- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/substrate/frame/assets/src/lib.rs b/substrate/frame/assets/src/lib.rs index 60316f8cdcf..09d59ae1b8b 100644 --- a/substrate/frame/assets/src/lib.rs +++ b/substrate/frame/assets/src/lib.rs @@ -226,10 +226,42 @@ pub mod pallet { } } - #[pallet::config] + /// Default implementations of [`DefaultConfig`], which can be used to implement [`Config`]. + pub mod config_preludes { + use super::*; + use frame_support::{derive_impl, traits::ConstU64}; + pub struct TestDefaultConfig; + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig, no_aggregated_types)] + impl frame_system::DefaultConfig for TestDefaultConfig {} + + #[frame_support::register_default_impl(TestDefaultConfig)] + impl DefaultConfig for TestDefaultConfig { + #[inject_runtime_type] + type RuntimeEvent = (); + type Balance = u64; + type RemoveItemsLimit = ConstU32<5>; + type AssetId = u32; + type AssetIdParameter = u32; + type AssetDeposit = ConstU64<1>; + type AssetAccountDeposit = ConstU64<10>; + type MetadataDepositBase = ConstU64<1>; + type MetadataDepositPerByte = ConstU64<1>; + type ApprovalDeposit = ConstU64<1>; + type StringLimit = ConstU32<50>; + type Extra = (); + type CallbackHandle = (); + type WeightInfo = (); + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); + } + } + + #[pallet::config(with_default)] /// The module configuration trait. pub trait Config: frame_system::Config { /// The overarching event type. + #[pallet::no_default_bounds] type RuntimeEvent: From> + IsType<::RuntimeEvent>; @@ -262,10 +294,12 @@ pub mod pallet { type AssetIdParameter: Parameter + From + Into + MaxEncodedLen; /// The currency mechanism. + #[pallet::no_default] type Currency: ReservableCurrency; /// Standard asset class creation is only allowed if the origin attempting it and the /// asset class are in this set. + #[pallet::no_default] type CreateOrigin: EnsureOriginWithArg< Self::RuntimeOrigin, Self::AssetId, @@ -274,28 +308,34 @@ pub mod pallet { /// The origin which may forcibly create or destroy an asset or otherwise alter privileged /// attributes. + #[pallet::no_default] type ForceOrigin: EnsureOrigin; /// The basic amount of funds that must be reserved for an asset. #[pallet::constant] + #[pallet::no_default_bounds] type AssetDeposit: Get>; /// The amount of funds that must be reserved for a non-provider asset account to be /// maintained. #[pallet::constant] + #[pallet::no_default_bounds] type AssetAccountDeposit: Get>; /// The basic amount of funds that must be reserved when adding metadata to your asset. #[pallet::constant] + #[pallet::no_default_bounds] type MetadataDepositBase: Get>; /// The additional funds that must be reserved for the number of bytes you store in your /// metadata. #[pallet::constant] + #[pallet::no_default_bounds] type MetadataDepositPerByte: Get>; /// The amount of funds that must be reserved when creating a new approval. #[pallet::constant] + #[pallet::no_default_bounds] type ApprovalDeposit: Get>; /// The maximum length of a name or symbol stored on-chain. @@ -304,6 +344,7 @@ pub mod pallet { /// A hook to allow a per-asset, per-account minimum balance to be enforced. This must be /// respected in all permissionless operations. + #[pallet::no_default] type Freezer: FrozenBalance; /// Additional data to be stored with an account's asset balance. diff --git a/substrate/frame/assets/src/mock.rs b/substrate/frame/assets/src/mock.rs index e1722200c35..906febb0214 100644 --- a/substrate/frame/assets/src/mock.rs +++ b/substrate/frame/assets/src/mock.rs @@ -108,27 +108,13 @@ impl AssetsCallbackHandle { } } +#[derive_impl(crate::config_preludes::TestDefaultConfig)] impl Config for Test { - type RuntimeEvent = RuntimeEvent; - type Balance = u64; - type AssetId = u32; - type AssetIdParameter = u32; type Currency = Balances; type CreateOrigin = AsEnsureOriginWithArg>; type ForceOrigin = frame_system::EnsureRoot; - type AssetDeposit = ConstU64<1>; - type AssetAccountDeposit = ConstU64<10>; - type MetadataDepositBase = ConstU64<1>; - type MetadataDepositPerByte = ConstU64<1>; - type ApprovalDeposit = ConstU64<1>; - type StringLimit = ConstU32<50>; type Freezer = TestFreezer; - type WeightInfo = (); type CallbackHandle = AssetsCallbackHandle; - type Extra = (); - type RemoveItemsLimit = ConstU32<5>; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); } use std::collections::HashMap; -- GitLab From b0f34e4b2953f814254f92c8d151f22ffcf9c034 Mon Sep 17 00:00:00 2001 From: Koute Date: Tue, 12 Mar 2024 14:23:06 +0900 Subject: [PATCH 029/187] Add a PolkaVM-based executor (#3458) This PR adds a new PolkaVM-based executor to Substrate. - The executor can now be used to actually run a PolkaVM-based runtime, and successfully produces blocks. - The executor is always compiled-in, but is disabled by default. - The `SUBSTRATE_ENABLE_POLKAVM` environment variable must be set to `1` to enable the executor, in which case the node will accept both WASM and PolkaVM program blobs (otherwise it'll default to WASM-only). This is deliberately undocumented and not explicitly exposed anywhere (e.g. in the command line arguments, or in the API) to disincentivize anyone from enabling it in production. If/when we'll move this into production usage I'll remove the environment variable and do it "properly". - I did not use our legacy runtime allocator for the PolkaVM executor, so currently every allocation inside of the runtime will leak guest memory until that particular instance is destroyed. The idea here is that I will work on the https://github.com/polkadot-fellows/RFCs/pull/4 which will remove the need for the legacy allocator under WASM, and that will also allow us to use a proper non-leaking allocator under PolkaVM. - I also did some minor cleanups of the WASM executor and deleted some dead code. No prdocs included since this is not intended to be an end-user feature, but an unofficial experiment, and shouldn't affect any current production user. Once this is production-ready a full Polkadot Fellowship RFC will be necessary anyway. --- Cargo.lock | 74 ++++- Cargo.toml | 6 +- .../core/pvf/common/src/executor_interface.rs | 4 +- substrate/client/executor/Cargo.toml | 1 + substrate/client/executor/common/Cargo.toml | 1 + substrate/client/executor/common/src/error.rs | 18 ++ substrate/client/executor/common/src/lib.rs | 4 + .../common/src/runtime_blob/runtime_blob.rs | 153 +++++----- .../executor/common/src/wasm_runtime.rs | 50 +--- substrate/client/executor/polkavm/Cargo.toml | 23 ++ substrate/client/executor/polkavm/README.md | 1 + substrate/client/executor/polkavm/src/lib.rs | 261 ++++++++++++++++++ substrate/client/executor/src/wasm_runtime.rs | 4 + .../executor/wasmtime/src/instance_wrapper.rs | 148 ++-------- .../client/executor/wasmtime/src/runtime.rs | 19 +- substrate/primitives/io/Cargo.toml | 3 + .../primitives/io/src/global_alloc_riscv.rs | 19 ++ .../primitives/io/src/global_alloc_wasm.rs | 34 +++ substrate/primitives/io/src/lib.rs | 34 +-- .../utils/wasm-builder/src/wasm_project.rs | 2 +- 20 files changed, 559 insertions(+), 300 deletions(-) create mode 100644 substrate/client/executor/polkavm/Cargo.toml create mode 100644 substrate/client/executor/polkavm/README.md create mode 100644 substrate/client/executor/polkavm/src/lib.rs create mode 100644 substrate/primitives/io/src/global_alloc_riscv.rs create mode 100644 substrate/primitives/io/src/global_alloc_wasm.rs diff --git a/Cargo.lock b/Cargo.lock index 7eaf3e44a1b..5eab3cf7c24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13805,6 +13805,28 @@ dependencies = [ "westend-runtime", ] +[[package]] +name = "polkavm" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a3693e5efdb2bf74e449cd25fd777a28bd7ed87e41f5d5da75eb31b4de48b94" +dependencies = [ + "libc", + "log", + "polkavm-assembler", + "polkavm-common 0.9.0", + "polkavm-linux-raw", +] + +[[package]] +name = "polkavm-assembler" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa96d6d868243acc12de813dd48e756cbadcc8e13964c70d272753266deadc1" +dependencies = [ + "log", +] + [[package]] name = "polkavm-common" version = "0.5.0" @@ -13813,9 +13835,12 @@ checksum = "88b4e215c80fe876147f3d58158d5dfeae7dabdd6047e175af77095b78d0035c" [[package]] name = "polkavm-common" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92c99f7eee94e7be43ba37eef65ad0ee8cbaf89b7c00001c3f6d2be985cb1817" +checksum = "1d9428a5cfcc85c5d7b9fc4b6a18c4b802d0173d768182a51cc7751640f08b92" +dependencies = [ + "log", +] [[package]] name = "polkavm-derive" @@ -13829,9 +13854,9 @@ dependencies = [ [[package]] name = "polkavm-derive" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79fa916f7962348bd1bb1a65a83401675e6fc86c51a0fdbcf92a3108e58e6125" +checksum = "ae8c4bea6f3e11cd89bb18bcdddac10bd9a24015399bd1c485ad68a985a19606" dependencies = [ "polkavm-derive-impl-macro", ] @@ -13850,11 +13875,11 @@ dependencies = [ [[package]] name = "polkavm-derive-impl" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c10b2654a8a10a83c260bfb93e97b262cf0017494ab94a65d389e0eda6de6c9c" +checksum = "5c4fdfc49717fb9a196e74a5d28e0bc764eb394a2c803eb11133a31ac996c60c" dependencies = [ - "polkavm-common 0.8.0", + "polkavm-common 0.9.0", "proc-macro2", "quote", "syn 2.0.50", @@ -13862,11 +13887,11 @@ dependencies = [ [[package]] name = "polkavm-derive-impl-macro" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e85319a0d5129dc9f021c62607e0804f5fb777a05cdda44d750ac0732def66" +checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429" dependencies = [ - "polkavm-derive-impl 0.8.0", + "polkavm-derive-impl 0.9.0", "syn 2.0.50", ] @@ -13887,19 +13912,25 @@ dependencies = [ [[package]] name = "polkavm-linker" -version = "0.8.2" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdec1451cb18261d5d01de82acc15305e417fb59588cdcb3127d3dcc9672b925" +checksum = "9c7be503e60cf56c0eb785f90aaba4b583b36bff00e93997d93fef97f9553c39" dependencies = [ "gimli 0.28.0", "hashbrown 0.14.3", "log", "object 0.32.2", - "polkavm-common 0.8.0", + "polkavm-common 0.9.0", "regalloc2 0.9.3", "rustc-demangle", ] +[[package]] +name = "polkavm-linux-raw" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26e85d3456948e650dff0cfc85603915847faf893ed1e66b020bb82ef4557120" + [[package]] name = "polling" version = "2.8.0" @@ -16112,6 +16143,7 @@ dependencies = [ "paste", "regex", "sc-executor-common", + "sc-executor-polkavm", "sc-executor-wasmtime", "sc-runtime-test", "sc-tracing", @@ -16141,6 +16173,7 @@ dependencies = [ name = "sc-executor-common" version = "0.29.0" dependencies = [ + "polkavm", "sc-allocator", "sp-maybe-compressed-blob", "sp-wasm-interface 20.0.0", @@ -16148,6 +16181,16 @@ dependencies = [ "wasm-instrument", ] +[[package]] +name = "sc-executor-polkavm" +version = "0.29.0" +dependencies = [ + "log", + "polkavm", + "sc-executor-common", + "sp-wasm-interface 20.0.0", +] + [[package]] name = "sc-executor-wasmtime" version = "0.29.0" @@ -18781,6 +18824,7 @@ dependencies = [ "libsecp256k1", "log", "parity-scale-codec", + "polkavm-derive 0.9.1", "rustversion", "secp256k1", "sp-core", @@ -18973,7 +19017,7 @@ dependencies = [ "bytes", "impl-trait-for-tuples", "parity-scale-codec", - "polkavm-derive 0.8.0", + "polkavm-derive 0.9.1", "primitive-types", "rustversion", "sp-core", @@ -19995,7 +20039,7 @@ dependencies = [ "console", "filetime", "parity-wasm", - "polkavm-linker 0.8.2", + "polkavm-linker 0.9.2", "sp-maybe-compressed-blob", "strum 0.24.1", "tempfile", diff --git a/Cargo.toml b/Cargo.toml index 80068596685..f256d02808a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -249,6 +249,7 @@ members = [ "substrate/client/db", "substrate/client/executor", "substrate/client/executor/common", + "substrate/client/executor/polkavm", "substrate/client/executor/runtime-test", "substrate/client/executor/wasmtime", "substrate/client/informant", @@ -543,8 +544,9 @@ extra-unused-type-parameters = { level = "allow", priority = 2 } # stylistic default_constructed_unit_structs = { level = "allow", priority = 2 } # stylistic [workspace.dependencies] -polkavm-linker = "0.8.2" -polkavm-derive = "0.8.0" +polkavm = "0.9.3" +polkavm-linker = "0.9.2" +polkavm-derive = "0.9.1" log = { version = "0.4.20", default-features = false } quote = { version = "1.0.33" } serde = { version = "1.0.197", default-features = false } diff --git a/polkadot/node/core/pvf/common/src/executor_interface.rs b/polkadot/node/core/pvf/common/src/executor_interface.rs index b69a87890f6..252e611db8a 100644 --- a/polkadot/node/core/pvf/common/src/executor_interface.rs +++ b/polkadot/node/core/pvf/common/src/executor_interface.rs @@ -24,7 +24,7 @@ use polkadot_primitives::{ use sc_executor_common::{ error::WasmError, runtime_blob::RuntimeBlob, - wasm_runtime::{HeapAllocStrategy, InvokeMethod, WasmModule as _}, + wasm_runtime::{HeapAllocStrategy, WasmModule as _}, }; use sc_executor_wasmtime::{Config, DeterministicStackLimit, Semantics, WasmtimeRuntime}; use sp_core::storage::{ChildInfo, TrackedStorageKey}; @@ -119,7 +119,7 @@ pub unsafe fn execute_artifact( match sc_executor::with_externalities_safe(&mut ext, || { let runtime = create_runtime_from_artifact_bytes(compiled_artifact_blob, executor_params)?; - runtime.new_instance()?.call(InvokeMethod::Export("validate_block"), params) + runtime.new_instance()?.call("validate_block", params) }) { Ok(Ok(ok)) => Ok(ok), Ok(Err(err)) | Err(err) => Err(err), diff --git a/substrate/client/executor/Cargo.toml b/substrate/client/executor/Cargo.toml index 4e36de3c4f4..7fad7e3a2a0 100644 --- a/substrate/client/executor/Cargo.toml +++ b/substrate/client/executor/Cargo.toml @@ -23,6 +23,7 @@ tracing = "0.1.29" codec = { package = "parity-scale-codec", version = "3.6.1" } sc-executor-common = { path = "common" } +sc-executor-polkavm = { path = "polkavm" } sc-executor-wasmtime = { path = "wasmtime" } sp-api = { path = "../../primitives/api" } sp-core = { path = "../../primitives/core" } diff --git a/substrate/client/executor/common/Cargo.toml b/substrate/client/executor/common/Cargo.toml index bfd1fa6b740..8ff34c3709a 100644 --- a/substrate/client/executor/common/Cargo.toml +++ b/substrate/client/executor/common/Cargo.toml @@ -22,6 +22,7 @@ wasm-instrument = "0.4" sc-allocator = { path = "../../allocator" } sp-maybe-compressed-blob = { path = "../../../primitives/maybe-compressed-blob" } sp-wasm-interface = { path = "../../../primitives/wasm-interface" } +polkavm = { workspace = true } [features] default = [] diff --git a/substrate/client/executor/common/src/error.rs b/substrate/client/executor/common/src/error.rs index 2a0dc364b41..b7c7e2b7019 100644 --- a/substrate/client/executor/common/src/error.rs +++ b/substrate/client/executor/common/src/error.rs @@ -150,6 +150,24 @@ pub enum WasmError { Other(String), } +impl From for WasmError { + fn from(error: polkavm::ProgramParseError) -> Self { + WasmError::Other(error.to_string()) + } +} + +impl From for WasmError { + fn from(error: polkavm::Error) -> Self { + WasmError::Other(error.to_string()) + } +} + +impl From for Error { + fn from(error: polkavm::Error) -> Self { + Error::Other(error.to_string()) + } +} + /// An error message with an attached backtrace. #[derive(Debug)] pub struct MessageWithBacktrace { diff --git a/substrate/client/executor/common/src/lib.rs b/substrate/client/executor/common/src/lib.rs index 751801fb30d..ff9fab2c888 100644 --- a/substrate/client/executor/common/src/lib.rs +++ b/substrate/client/executor/common/src/lib.rs @@ -25,3 +25,7 @@ pub mod error; pub mod runtime_blob; pub mod util; pub mod wasm_runtime; + +pub(crate) fn is_polkavm_enabled() -> bool { + std::env::var_os("SUBSTRATE_ENABLE_POLKAVM").map_or(false, |value| value == "1") +} diff --git a/substrate/client/executor/common/src/runtime_blob/runtime_blob.rs b/substrate/client/executor/common/src/runtime_blob/runtime_blob.rs index becf9e219b0..d689083b2f8 100644 --- a/substrate/client/executor/common/src/runtime_blob/runtime_blob.rs +++ b/substrate/client/executor/common/src/runtime_blob/runtime_blob.rs @@ -17,23 +17,23 @@ // along with this program. If not, see . use crate::{error::WasmError, wasm_runtime::HeapAllocStrategy}; -use wasm_instrument::{ - export_mutable_globals, - parity_wasm::elements::{ - deserialize_buffer, serialize, ExportEntry, External, Internal, MemorySection, MemoryType, - Module, Section, - }, +use wasm_instrument::parity_wasm::elements::{ + deserialize_buffer, serialize, ExportEntry, External, Internal, MemorySection, MemoryType, + Module, Section, }; -/// A bunch of information collected from a WebAssembly module. +/// A program blob containing a Substrate runtime. #[derive(Clone)] -pub struct RuntimeBlob { - raw_module: Module, +pub struct RuntimeBlob(BlobKind); + +#[derive(Clone)] +enum BlobKind { + WebAssembly(Module), + PolkaVM(polkavm::ProgramBlob<'static>), } impl RuntimeBlob { - /// Create `RuntimeBlob` from the given wasm code. Will attempt to decompress the code before - /// deserializing it. + /// Create `RuntimeBlob` from the given WASM or PolkaVM compressed program blob. /// /// See [`sp_maybe_compressed_blob`] for details about decompression. pub fn uncompress_if_needed(wasm_code: &[u8]) -> Result { @@ -43,31 +43,26 @@ impl RuntimeBlob { Self::new(&wasm_code) } - /// Create `RuntimeBlob` from the given wasm code. + /// Create `RuntimeBlob` from the given WASM or PolkaVM program blob. /// - /// Returns `Err` if the wasm code cannot be deserialized. - pub fn new(wasm_code: &[u8]) -> Result { - let raw_module: Module = deserialize_buffer(wasm_code) - .map_err(|e| WasmError::Other(format!("cannot deserialize module: {:?}", e)))?; - Ok(Self { raw_module }) - } - - /// The number of globals defined in locally in this module. - pub fn declared_globals_count(&self) -> u32 { - self.raw_module - .global_section() - .map(|gs| gs.entries().len() as u32) - .unwrap_or(0) - } - - /// The number of imports of globals. - pub fn imported_globals_count(&self) -> u32 { - self.raw_module.import_section().map(|is| is.globals() as u32).unwrap_or(0) - } + /// Returns `Err` if the blob cannot be deserialized. + /// + /// Will only accept a PolkaVM program if the `SUBSTRATE_ENABLE_POLKAVM` environment + /// variable is set to `1`. + pub fn new(raw_blob: &[u8]) -> Result { + if raw_blob.starts_with(b"PVM\0") { + if crate::is_polkavm_enabled() { + return Ok(Self(BlobKind::PolkaVM( + polkavm::ProgramBlob::parse(raw_blob)?.into_owned(), + ))); + } else { + return Err(WasmError::Other("expected a WASM runtime blob, found a PolkaVM runtime blob; set the 'SUBSTRATE_ENABLE_POLKAVM' environment variable to enable the experimental PolkaVM-based executor".to_string())); + } + } - /// Perform an instrumentation that makes sure that the mutable globals are exported. - pub fn expose_mutable_globals(&mut self) { - export_mutable_globals(&mut self.raw_module, "exported_internal_global"); + let raw_module: Module = deserialize_buffer(raw_blob) + .map_err(|e| WasmError::Other(format!("cannot deserialize module: {:?}", e)))?; + Ok(Self(BlobKind::WebAssembly(raw_module))) } /// Run a pass that instrument this module so as to introduce a deterministic stack height @@ -80,26 +75,16 @@ impl RuntimeBlob { /// /// The stack cost of a function is computed based on how much locals there are and the maximum /// depth of the wasm operand stack. + /// + /// Only valid for WASM programs; will return an error if the blob is a PolkaVM program. pub fn inject_stack_depth_metering(self, stack_depth_limit: u32) -> Result { let injected_module = - wasm_instrument::inject_stack_limiter(self.raw_module, stack_depth_limit).map_err( - |e| WasmError::Other(format!("cannot inject the stack limiter: {:?}", e)), - )?; - - Ok(Self { raw_module: injected_module }) - } + wasm_instrument::inject_stack_limiter(self.into_webassembly_blob()?, stack_depth_limit) + .map_err(|e| { + WasmError::Other(format!("cannot inject the stack limiter: {:?}", e)) + })?; - /// Perform an instrumentation that makes sure that a specific function `entry_point` is - /// exported - pub fn entry_point_exists(&self, entry_point: &str) -> bool { - self.raw_module - .export_section() - .map(|e| { - e.entries().iter().any(|e| { - matches!(e.internal(), Internal::Function(_)) && e.field() == entry_point - }) - }) - .unwrap_or_default() + Ok(Self(BlobKind::WebAssembly(injected_module))) } /// Converts a WASM memory import into a memory section and exports it. @@ -107,8 +92,11 @@ impl RuntimeBlob { /// Does nothing if there's no memory import. /// /// May return an error in case the WASM module is invalid. + /// + /// Only valid for WASM programs; will return an error if the blob is a PolkaVM program. pub fn convert_memory_import_into_export(&mut self) -> Result<(), WasmError> { - let import_section = match self.raw_module.import_section_mut() { + let raw_module = self.as_webassembly_blob_mut()?; + let import_section = match raw_module.import_section_mut() { Some(import_section) => import_section, None => return Ok(()), }; @@ -124,7 +112,7 @@ impl RuntimeBlob { let memory_name = entry.field().to_owned(); import_entries.remove(index); - self.raw_module + raw_module .insert_section(Section::Memory(MemorySection::with_entries(vec![memory_ty]))) .map_err(|error| { WasmError::Other(format!( @@ -133,14 +121,14 @@ impl RuntimeBlob { )) })?; - if self.raw_module.export_section_mut().is_none() { + if raw_module.export_section_mut().is_none() { // A module without an export section is somewhat unrealistic, but let's do this // just in case to cover all of our bases. - self.raw_module + raw_module .insert_section(Section::Export(Default::default())) .expect("an export section can be always inserted if it doesn't exist; qed"); } - self.raw_module + raw_module .export_section_mut() .expect("export section already existed or we just added it above, so it always exists; qed") .entries_mut() @@ -156,12 +144,14 @@ impl RuntimeBlob { /// /// Will return an error in case there is no memory section present, /// or if the memory section is empty. + /// + /// Only valid for WASM programs; will return an error if the blob is a PolkaVM program. pub fn setup_memory_according_to_heap_alloc_strategy( &mut self, heap_alloc_strategy: HeapAllocStrategy, ) -> Result<(), WasmError> { - let memory_section = self - .raw_module + let raw_module = self.as_webassembly_blob_mut()?; + let memory_section = raw_module .memory_section_mut() .ok_or_else(|| WasmError::Other("no memory section found".into()))?; @@ -187,8 +177,11 @@ impl RuntimeBlob { /// Scans the wasm blob for the first section with the name that matches the given. Returns the /// contents of the custom section if found or `None` otherwise. + /// + /// Only valid for WASM programs; will return an error if the blob is a PolkaVM program. pub fn custom_section_contents(&self, section_name: &str) -> Option<&[u8]> { - self.raw_module + self.as_webassembly_blob() + .ok()? .custom_sections() .find(|cs| cs.name() == section_name) .map(|cs| cs.payload()) @@ -196,11 +189,45 @@ impl RuntimeBlob { /// Consumes this runtime blob and serializes it. pub fn serialize(self) -> Vec { - serialize(self.raw_module).expect("serializing into a vec should succeed; qed") + match self.0 { + BlobKind::WebAssembly(raw_module) => + serialize(raw_module).expect("serializing into a vec should succeed; qed"), + BlobKind::PolkaVM(ref blob) => blob.as_bytes().to_vec(), + } + } + + fn as_webassembly_blob(&self) -> Result<&Module, WasmError> { + match self.0 { + BlobKind::WebAssembly(ref raw_module) => Ok(raw_module), + BlobKind::PolkaVM(..) => Err(WasmError::Other( + "expected a WebAssembly program; found a PolkaVM program blob".into(), + )), + } } - /// Destructure this structure into the underlying parity-wasm Module. - pub fn into_inner(self) -> Module { - self.raw_module + fn as_webassembly_blob_mut(&mut self) -> Result<&mut Module, WasmError> { + match self.0 { + BlobKind::WebAssembly(ref mut raw_module) => Ok(raw_module), + BlobKind::PolkaVM(..) => Err(WasmError::Other( + "expected a WebAssembly program; found a PolkaVM program blob".into(), + )), + } + } + + fn into_webassembly_blob(self) -> Result { + match self.0 { + BlobKind::WebAssembly(raw_module) => Ok(raw_module), + BlobKind::PolkaVM(..) => Err(WasmError::Other( + "expected a WebAssembly program; found a PolkaVM program blob".into(), + )), + } + } + + /// Gets a reference to the inner PolkaVM program blob, if this is a PolkaVM program. + pub fn as_polkavm_blob(&self) -> Option<&polkavm::ProgramBlob> { + match self.0 { + BlobKind::WebAssembly(..) => None, + BlobKind::PolkaVM(ref blob) => Some(blob), + } } } diff --git a/substrate/client/executor/common/src/wasm_runtime.rs b/substrate/client/executor/common/src/wasm_runtime.rs index d8e142b9d55..e8f429a3dbb 100644 --- a/substrate/client/executor/common/src/wasm_runtime.rs +++ b/substrate/client/executor/common/src/wasm_runtime.rs @@ -19,7 +19,6 @@ //! Definitions for a wasm runtime. use crate::error::Error; -use sp_wasm_interface::Value; pub use sc_allocator::AllocationStats; @@ -30,46 +29,6 @@ pub const DEFAULT_HEAP_ALLOC_STRATEGY: HeapAllocStrategy = /// Default heap allocation pages. pub const DEFAULT_HEAP_ALLOC_PAGES: u32 = 2048; -/// A method to be used to find the entrypoint when calling into the runtime -/// -/// Contains variants on how to resolve wasm function that will be invoked. -pub enum InvokeMethod<'a> { - /// Call function exported with this name. - /// - /// Located function should have (u32, u32) -> u64 signature. - Export(&'a str), - /// Call a function found in the exported table found under the given index. - /// - /// Located function should have (u32, u32) -> u64 signature. - Table(u32), - /// Call function by reference from table through a wrapper. - /// - /// Invoked function (`dispatcher_ref`) function - /// should have (u32, u32, u32) -> u64 signature. - /// - /// `func` will be passed to the invoked function as a first argument. - TableWithWrapper { - /// Wrapper for the call. - /// - /// Function pointer, index into runtime exported table. - dispatcher_ref: u32, - /// Extra argument for dispatch. - /// - /// Common usage would be to use it as an actual wasm function pointer - /// that should be invoked, but can be used as any extra argument on the - /// callee side. - /// - /// This is typically generated and invoked by the runtime itself. - func: u32, - }, -} - -impl<'a> From<&'a str> for InvokeMethod<'a> { - fn from(val: &'a str) -> InvokeMethod<'a> { - InvokeMethod::Export(val) - } -} - /// A trait that defines an abstract WASM runtime module. /// /// This can be implemented by an execution engine. @@ -87,7 +46,7 @@ pub trait WasmInstance: Send { /// Before execution, instance is reset. /// /// Returns the encoded result on success. - fn call(&mut self, method: InvokeMethod, data: &[u8]) -> Result, Error> { + fn call(&mut self, method: &str, data: &[u8]) -> Result, Error> { self.call_with_allocation_stats(method, data).0 } @@ -98,7 +57,7 @@ pub trait WasmInstance: Send { /// Returns the encoded result on success. fn call_with_allocation_stats( &mut self, - method: InvokeMethod, + method: &str, data: &[u8], ) -> (Result, Error>, Option); @@ -110,11 +69,6 @@ pub trait WasmInstance: Send { fn call_export(&mut self, method: &str, data: &[u8]) -> Result, Error> { self.call(method.into(), data) } - - /// Get the value from a global with the given `name`. - /// - /// This method is only suitable for getting immutable globals. - fn get_global_const(&mut self, name: &str) -> Result, Error>; } /// Defines the heap pages allocation strategy the wasm runtime should use. diff --git a/substrate/client/executor/polkavm/Cargo.toml b/substrate/client/executor/polkavm/Cargo.toml new file mode 100644 index 00000000000..9d0eb8ccf0e --- /dev/null +++ b/substrate/client/executor/polkavm/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "sc-executor-polkavm" +version = "0.29.0" +authors.workspace = true +edition.workspace = true +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage = "https://substrate.io" +repository.workspace = true +description = "PolkaVM executor for Substrate" +readme = "README.md" + +[lints] +workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +log = { workspace = true } +polkavm = { workspace = true } + +sc-executor-common = { path = "../common" } +sp-wasm-interface = { path = "../../../primitives/wasm-interface" } diff --git a/substrate/client/executor/polkavm/README.md b/substrate/client/executor/polkavm/README.md new file mode 100644 index 00000000000..64fc2fa0c28 --- /dev/null +++ b/substrate/client/executor/polkavm/README.md @@ -0,0 +1 @@ +License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/executor/polkavm/src/lib.rs b/substrate/client/executor/polkavm/src/lib.rs new file mode 100644 index 00000000000..1bd72eb33d3 --- /dev/null +++ b/substrate/client/executor/polkavm/src/lib.rs @@ -0,0 +1,261 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use polkavm::{Caller, Reg}; +use sc_executor_common::{ + error::{Error, WasmError}, + wasm_runtime::{AllocationStats, WasmInstance, WasmModule}, +}; +use sp_wasm_interface::{ + Function, FunctionContext, HostFunctions, Pointer, Value, ValueType, WordSize, +}; + +#[repr(transparent)] +pub struct InstancePre(polkavm::InstancePre<()>); + +#[repr(transparent)] +pub struct Instance(polkavm::Instance<()>); + +impl WasmModule for InstancePre { + fn new_instance(&self) -> Result, Error> { + Ok(Box::new(Instance(self.0.instantiate()?))) + } +} + +impl WasmInstance for Instance { + fn call_with_allocation_stats( + &mut self, + name: &str, + raw_data: &[u8], + ) -> (Result, Error>, Option) { + let Some(method_index) = self.0.module().lookup_export(name) else { + return ( + Err(format!("cannot call into the runtime: export not found: '{name}'").into()), + None, + ); + }; + + let Ok(raw_data_length) = u32::try_from(raw_data.len()) else { + return ( + Err(format!("cannot call runtime method '{name}': input payload is too big").into()), + None, + ); + }; + + // TODO: This will leak guest memory; find a better solution. + let mut state_args = polkavm::StateArgs::new(); + + // Make sure the memory is cleared... + state_args.reset_memory(true); + // ...and allocate space for the input payload. + state_args.sbrk(raw_data_length); + + match self.0.update_state(state_args) { + Ok(()) => {}, + Err(polkavm::ExecutionError::Trap(trap)) => { + return (Err(format!("call into the runtime method '{name}' failed: failed to prepare the guest's memory: {trap}").into()), None); + }, + Err(polkavm::ExecutionError::Error(error)) => { + return (Err(format!("call into the runtime method '{name}' failed: failed to prepare the guest's memory: {error}").into()), None); + }, + Err(polkavm::ExecutionError::OutOfGas) => unreachable!("gas metering is never enabled"), + } + + // Grab the address of where the guest's heap starts; that's where we've just allocated + // the memory for the input payload. + let data_pointer = self.0.module().memory_map().heap_base(); + + if let Err(error) = self.0.write_memory(data_pointer, raw_data) { + return (Err(format!("call into the runtime method '{name}': failed to write the input payload into guest memory: {error}").into()), None); + } + + let mut state = (); + let mut call_args = polkavm::CallArgs::new(&mut state, method_index); + call_args.args_untyped(&[data_pointer, raw_data_length]); + + match self.0.call(Default::default(), call_args) { + Ok(()) => {}, + Err(polkavm::ExecutionError::Trap(trap)) => { + return ( + Err(format!("call into the runtime method '{name}' failed: {trap}").into()), + None, + ); + }, + Err(polkavm::ExecutionError::Error(error)) => { + return ( + Err(format!("call into the runtime method '{name}' failed: {error}").into()), + None, + ); + }, + Err(polkavm::ExecutionError::OutOfGas) => unreachable!("gas metering is never enabled"), + } + + let result_pointer = self.0.get_reg(Reg::A0); + let result_length = self.0.get_reg(Reg::A1); + let output = match self.0.read_memory_into_vec(result_pointer, result_length) { + Ok(output) => output, + Err(error) => { + return (Err(format!("call into the runtime method '{name}' failed: failed to read the return payload: {error}").into()), None) + }, + }; + + (Ok(output), None) + } +} + +struct Context<'r, 'a>(&'r mut polkavm::Caller<'a, ()>); + +impl<'r, 'a> FunctionContext for Context<'r, 'a> { + fn read_memory_into( + &self, + address: Pointer, + dest: &mut [u8], + ) -> sp_wasm_interface::Result<()> { + self.0 + .read_memory_into_slice(u32::from(address), dest) + .map_err(|error| error.to_string()) + .map(|_| ()) + } + + fn write_memory(&mut self, address: Pointer, data: &[u8]) -> sp_wasm_interface::Result<()> { + self.0.write_memory(u32::from(address), data).map_err(|error| error.to_string()) + } + + fn allocate_memory(&mut self, size: WordSize) -> sp_wasm_interface::Result> { + let pointer = self.0.sbrk(0).expect("fetching the current heap pointer never fails"); + + // TODO: This will leak guest memory; find a better solution. + self.0.sbrk(size).ok_or_else(|| String::from("allocation failed"))?; + + Ok(Pointer::new(pointer)) + } + + fn deallocate_memory(&mut self, _ptr: Pointer) -> sp_wasm_interface::Result<()> { + // This is only used by the allocator host function, which is unused under PolkaVM. + unimplemented!("'deallocate_memory' is never used when running under PolkaVM"); + } + + fn register_panic_error_message(&mut self, _message: &str) { + unimplemented!("'register_panic_error_message' is never used when running under PolkaVM"); + } +} + +fn call_host_function( + caller: &mut Caller<()>, + function: &dyn Function, +) -> Result<(), polkavm::Trap> { + let mut args = [Value::I64(0); Reg::ARG_REGS.len()]; + let mut nth_reg = 0; + for (nth_arg, kind) in function.signature().args.iter().enumerate() { + match kind { + ValueType::I32 => { + args[nth_arg] = Value::I32(caller.get_reg(Reg::ARG_REGS[nth_reg]) as i32); + nth_reg += 1; + }, + ValueType::F32 => { + args[nth_arg] = Value::F32(caller.get_reg(Reg::ARG_REGS[nth_reg])); + nth_reg += 1; + }, + ValueType::I64 => { + let value_lo = caller.get_reg(Reg::ARG_REGS[nth_reg]); + nth_reg += 1; + + let value_hi = caller.get_reg(Reg::ARG_REGS[nth_reg]); + nth_reg += 1; + + args[nth_arg] = + Value::I64((u64::from(value_lo) | (u64::from(value_hi) << 32)) as i64); + }, + ValueType::F64 => { + let value_lo = caller.get_reg(Reg::ARG_REGS[nth_reg]); + nth_reg += 1; + + let value_hi = caller.get_reg(Reg::ARG_REGS[nth_reg]); + nth_reg += 1; + + args[nth_arg] = Value::F64(u64::from(value_lo) | (u64::from(value_hi) << 32)); + }, + } + } + + log::trace!( + "Calling host function: '{}', args = {:?}", + function.name(), + &args[..function.signature().args.len()] + ); + + let value = match function + .execute(&mut Context(caller), &mut args.into_iter().take(function.signature().args.len())) + { + Ok(value) => value, + Err(error) => { + log::warn!("Call into the host function '{}' failed: {error}", function.name()); + return Err(polkavm::Trap::default()); + }, + }; + + if let Some(value) = value { + match value { + Value::I32(value) => { + caller.set_reg(Reg::A0, value as u32); + }, + Value::F32(value) => { + caller.set_reg(Reg::A0, value); + }, + Value::I64(value) => { + caller.set_reg(Reg::A0, value as u32); + caller.set_reg(Reg::A1, (value >> 32) as u32); + }, + Value::F64(value) => { + caller.set_reg(Reg::A0, value as u32); + caller.set_reg(Reg::A1, (value >> 32) as u32); + }, + } + } + + Ok(()) +} + +pub fn create_runtime(blob: &polkavm::ProgramBlob) -> Result, WasmError> +where + H: HostFunctions, +{ + static ENGINE: std::sync::OnceLock> = + std::sync::OnceLock::new(); + + let engine = ENGINE.get_or_init(|| { + let config = polkavm::Config::from_env()?; + polkavm::Engine::new(&config) + }); + + let engine = match engine { + Ok(ref engine) => engine, + Err(ref error) => { + return Err(WasmError::Other(error.to_string())); + }, + }; + + let module = polkavm::Module::from_blob(&engine, &polkavm::ModuleConfig::default(), blob)?; + let mut linker = polkavm::Linker::new(&engine); + for function in H::host_functions() { + linker.func_new(function.name(), |mut caller| call_host_function(&mut caller, function))?; + } + + let instance_pre = linker.instantiate_pre(&module)?; + Ok(Box::new(InstancePre(instance_pre))) +} diff --git a/substrate/client/executor/src/wasm_runtime.rs b/substrate/client/executor/src/wasm_runtime.rs index 501279a312c..be8344ba79b 100644 --- a/substrate/client/executor/src/wasm_runtime.rs +++ b/substrate/client/executor/src/wasm_runtime.rs @@ -297,6 +297,10 @@ pub fn create_wasm_runtime_with_code( where H: HostFunctions, { + if let Some(blob) = blob.as_polkavm_blob() { + return sc_executor_polkavm::create_runtime::(blob); + } + match wasm_method { WasmExecutionMethod::Compiled { instantiation_strategy } => sc_executor_wasmtime::create_runtime::( diff --git a/substrate/client/executor/wasmtime/src/instance_wrapper.rs b/substrate/client/executor/wasmtime/src/instance_wrapper.rs index 8852532adbc..4f67d1df9c5 100644 --- a/substrate/client/executor/wasmtime/src/instance_wrapper.rs +++ b/substrate/client/executor/wasmtime/src/instance_wrapper.rs @@ -22,36 +22,12 @@ use std::sync::Arc; use crate::runtime::{InstanceCounter, ReleaseInstanceHandle, Store, StoreData}; -use sc_executor_common::{ - error::{Backtrace, Error, MessageWithBacktrace, Result, WasmError}, - wasm_runtime::InvokeMethod, -}; -use sp_wasm_interface::{Pointer, Value, WordSize}; -use wasmtime::{ - AsContext, AsContextMut, Engine, Extern, Instance, InstancePre, Memory, Table, Val, -}; - -/// Invoked entrypoint format. -pub enum EntryPointType { - /// Direct call. - /// - /// Call is made by providing only payload reference and length. - Direct { entrypoint: wasmtime::TypedFunc<(u32, u32), u64> }, - /// Indirect call. - /// - /// Call is made by providing payload reference and length, and extra argument - /// for advanced routing. - Wrapped { - /// The extra argument passed to the runtime. It is typically a wasm function pointer. - func: u32, - dispatcher: wasmtime::TypedFunc<(u32, u32, u32), u64>, - }, -} +use sc_executor_common::error::{Backtrace, Error, MessageWithBacktrace, Result, WasmError}; +use sp_wasm_interface::{Pointer, WordSize}; +use wasmtime::{AsContext, AsContextMut, Engine, Instance, InstancePre, Memory}; /// Wasm blob entry point. -pub struct EntryPoint { - call_type: EntryPointType, -} +pub struct EntryPoint(wasmtime::TypedFunc<(u32, u32), u64>); impl EntryPoint { /// Call this entry point. @@ -64,13 +40,7 @@ impl EntryPoint { let data_ptr = u32::from(data_ptr); let data_len = u32::from(data_len); - match self.call_type { - EntryPointType::Direct { ref entrypoint } => - entrypoint.call(&mut *store, (data_ptr, data_len)), - EntryPointType::Wrapped { func, ref dispatcher } => - dispatcher.call(&mut *store, (func, data_ptr, data_len)), - } - .map_err(|trap| { + self.0.call(&mut *store, (data_ptr, data_len)).map_err(|trap| { let host_state = store .data_mut() .host_state @@ -99,18 +69,7 @@ impl EntryPoint { let entrypoint = func .typed::<(u32, u32), u64>(ctx) .map_err(|_| "Invalid signature for direct entry point")?; - Ok(Self { call_type: EntryPointType::Direct { entrypoint } }) - } - - pub fn wrapped( - dispatcher: wasmtime::Func, - func: u32, - ctx: impl AsContext, - ) -> std::result::Result { - let dispatcher = dispatcher - .typed::<(u32, u32, u32), u64>(ctx) - .map_err(|_| "Invalid signature for wrapped entry point")?; - Ok(Self { call_type: EntryPointType::Wrapped { func, dispatcher } }) + Ok(Self(entrypoint)) } } @@ -178,10 +137,8 @@ impl InstanceWrapper { })?; let memory = get_linear_memory(&instance, &mut store)?; - let table = get_table(&instance, &mut store); store.data_mut().memory = Some(memory); - store.data_mut().table = table; Ok(InstanceWrapper { instance, store, _release_instance_handle }) } @@ -190,61 +147,17 @@ impl InstanceWrapper { /// /// An entrypoint must have a signature `(i32, i32) -> i64`, otherwise this function will return /// an error. - pub fn resolve_entrypoint(&mut self, method: InvokeMethod) -> Result { - Ok(match method { - InvokeMethod::Export(method) => { - // Resolve the requested method and verify that it has a proper signature. - let export = - self.instance.get_export(&mut self.store, method).ok_or_else(|| { - Error::from(format!("Exported method {} is not found", method)) - })?; - let func = export - .into_func() - .ok_or_else(|| Error::from(format!("Export {} is not a function", method)))?; - EntryPoint::direct(func, &self.store).map_err(|_| { - Error::from(format!("Exported function '{}' has invalid signature.", method)) - })? - }, - InvokeMethod::Table(func_ref) => { - let table = self - .instance - .get_table(&mut self.store, "__indirect_function_table") - .ok_or(Error::NoTable)?; - let val = table - .get(&mut self.store, func_ref) - .ok_or(Error::NoTableEntryWithIndex(func_ref))?; - let func = val - .funcref() - .ok_or(Error::TableElementIsNotAFunction(func_ref))? - .ok_or(Error::FunctionRefIsNull(func_ref))?; - - EntryPoint::direct(*func, &self.store).map_err(|_| { - Error::from(format!( - "Function @{} in exported table has invalid signature for direct call.", - func_ref, - )) - })? - }, - InvokeMethod::TableWithWrapper { dispatcher_ref, func } => { - let table = self - .instance - .get_table(&mut self.store, "__indirect_function_table") - .ok_or(Error::NoTable)?; - let val = table - .get(&mut self.store, dispatcher_ref) - .ok_or(Error::NoTableEntryWithIndex(dispatcher_ref))?; - let dispatcher = val - .funcref() - .ok_or(Error::TableElementIsNotAFunction(dispatcher_ref))? - .ok_or(Error::FunctionRefIsNull(dispatcher_ref))?; - - EntryPoint::wrapped(*dispatcher, func, &self.store).map_err(|_| { - Error::from(format!( - "Function @{} in exported table has invalid signature for wrapped call.", - dispatcher_ref, - )) - })? - }, + pub fn resolve_entrypoint(&mut self, method: &str) -> Result { + // Resolve the requested method and verify that it has a proper signature. + let export = self + .instance + .get_export(&mut self.store, method) + .ok_or_else(|| Error::from(format!("Exported method {} is not found", method)))?; + let func = export + .into_func() + .ok_or_else(|| Error::from(format!("Export {} is not a function", method)))?; + EntryPoint::direct(func, &self.store).map_err(|_| { + Error::from(format!("Exported function '{}' has invalid signature.", method)) }) } @@ -268,24 +181,6 @@ impl InstanceWrapper { Ok(heap_base as u32) } - - /// Get the value from a global with the given `name`. - pub fn get_global_val(&mut self, name: &str) -> Result> { - let global = match self.instance.get_export(&mut self.store, name) { - Some(global) => global, - None => return Ok(None), - }; - - let global = global.into_global().ok_or_else(|| format!("`{}` is not a global", name))?; - - match global.get(&mut self.store) { - Val::I32(val) => Ok(Some(Value::I32(val))), - Val::I64(val) => Ok(Some(Value::I64(val))), - Val::F32(val) => Ok(Some(Value::F32(val))), - Val::F64(val) => Ok(Some(Value::F64(val))), - _ => Err("Unknown value type".into()), - } - } } /// Extract linear memory instance from the given instance. @@ -301,15 +196,6 @@ fn get_linear_memory(instance: &Instance, ctx: impl AsContextMut) -> Result Option
CommittedCandidateReceipt<H = Hash>
{ - instance - .get_export(ctx, "__indirect_function_table") - .as_ref() - .cloned() - .and_then(Extern::into_table) -} - /// Functions related to memory. impl InstanceWrapper { pub(crate) fn store(&self) -> &Store { diff --git a/substrate/client/executor/wasmtime/src/runtime.rs b/substrate/client/executor/wasmtime/src/runtime.rs index ac88663f4e7..595cc503272 100644 --- a/substrate/client/executor/wasmtime/src/runtime.rs +++ b/substrate/client/executor/wasmtime/src/runtime.rs @@ -30,10 +30,10 @@ use sc_executor_common::{ error::{Error, Result, WasmError}, runtime_blob::RuntimeBlob, util::checked_range, - wasm_runtime::{HeapAllocStrategy, InvokeMethod, WasmInstance, WasmModule}, + wasm_runtime::{HeapAllocStrategy, WasmInstance, WasmModule}, }; use sp_runtime_interface::unpack_ptr_and_len; -use sp_wasm_interface::{HostFunctions, Pointer, Value, WordSize}; +use sp_wasm_interface::{HostFunctions, Pointer, WordSize}; use std::{ path::{Path, PathBuf}, sync::{ @@ -41,7 +41,7 @@ use std::{ Arc, }, }; -use wasmtime::{AsContext, Engine, Memory, Table}; +use wasmtime::{AsContext, Engine, Memory}; const MAX_INSTANCE_COUNT: u32 = 64; @@ -51,8 +51,6 @@ pub(crate) struct StoreData { pub(crate) host_state: Option, /// This will be always set once the store is initialized. pub(crate) memory: Option, - /// This will be set only if the runtime actually contains a table. - pub(crate) table: Option
, } impl StoreData { @@ -164,7 +162,7 @@ pub struct WasmtimeInstance { impl WasmtimeInstance { fn call_impl( &mut self, - method: InvokeMethod, + method: &str, data: &[u8], allocation_stats: &mut Option, ) -> Result> { @@ -184,20 +182,13 @@ impl WasmtimeInstance { impl WasmInstance for WasmtimeInstance { fn call_with_allocation_stats( &mut self, - method: InvokeMethod, + method: &str, data: &[u8], ) -> (Result>, Option) { let mut allocation_stats = None; let result = self.call_impl(method, data, &mut allocation_stats); (result, allocation_stats) } - - fn get_global_const(&mut self, name: &str) -> Result> { - match &mut self.strategy { - Strategy::RecreateInstance(ref mut instance_creator) => - instance_creator.instantiate()?.get_global_val(name), - } - } } /// Prepare a directory structure and a config file to enable wasmtime caching. diff --git a/substrate/primitives/io/Cargo.toml b/substrate/primitives/io/Cargo.toml index c78def9bf44..e47775d56d9 100644 --- a/substrate/primitives/io/Cargo.toml +++ b/substrate/primitives/io/Cargo.toml @@ -38,6 +38,9 @@ tracing-core = { version = "0.1.32", default-features = false } # Required for backwards compatibility reason, but only used for verifying when `UseDalekExt` is set. ed25519-dalek = { version = "2.1", default-features = false, optional = true } +[target.'cfg(all(any(target_arch = "riscv32", target_arch = "riscv64"), substrate_runtime))'.dependencies] +polkavm-derive = { workspace = true } + [build-dependencies] rustversion = "1.0.6" diff --git a/substrate/primitives/io/src/global_alloc_riscv.rs b/substrate/primitives/io/src/global_alloc_riscv.rs new file mode 100644 index 00000000000..8d7c69c2094 --- /dev/null +++ b/substrate/primitives/io/src/global_alloc_riscv.rs @@ -0,0 +1,19 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[global_allocator] +static ALLOCATOR: polkavm_derive::LeakingAllocator = polkavm_derive::LeakingAllocator; diff --git a/substrate/primitives/io/src/global_alloc_wasm.rs b/substrate/primitives/io/src/global_alloc_wasm.rs new file mode 100644 index 00000000000..cf19a6e21a2 --- /dev/null +++ b/substrate/primitives/io/src/global_alloc_wasm.rs @@ -0,0 +1,34 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use core::alloc::{GlobalAlloc, Layout}; + +/// Allocator used by Substrate from within the runtime. +struct RuntimeAllocator; + +#[global_allocator] +static ALLOCATOR: RuntimeAllocator = RuntimeAllocator; + +unsafe impl GlobalAlloc for RuntimeAllocator { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + crate::allocator::malloc(layout.size() as u32) + } + + unsafe fn dealloc(&self, ptr: *mut u8, _: Layout) { + crate::allocator::free(ptr) + } +} diff --git a/substrate/primitives/io/src/lib.rs b/substrate/primitives/io/src/lib.rs index 6d34199416a..684854ea5c8 100644 --- a/substrate/primitives/io/src/lib.rs +++ b/substrate/primitives/io/src/lib.rs @@ -129,6 +129,16 @@ use sp_externalities::{Externalities, ExternalitiesExt}; pub use sp_externalities::MultiRemovalResults; +#[cfg(all(not(feature = "disable_allocator"), substrate_runtime, target_family = "wasm"))] +mod global_alloc_wasm; + +#[cfg(all( + not(feature = "disable_allocator"), + substrate_runtime, + any(target_arch = "riscv32", target_arch = "riscv64") +))] +mod global_alloc_riscv; + #[cfg(feature = "std")] const LOG_TARGET: &str = "runtime::io"; @@ -1737,30 +1747,6 @@ mod tracing_setup { pub use tracing_setup::init_tracing; -/// Allocator used by Substrate from within the runtime. -#[cfg(substrate_runtime)] -struct RuntimeAllocator; - -#[cfg(all(not(feature = "disable_allocator"), substrate_runtime))] -#[global_allocator] -static ALLOCATOR: RuntimeAllocator = RuntimeAllocator; - -#[cfg(substrate_runtime)] -mod allocator_impl { - use super::*; - use core::alloc::{GlobalAlloc, Layout}; - - unsafe impl GlobalAlloc for RuntimeAllocator { - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - allocator::malloc(layout.size() as u32) - } - - unsafe fn dealloc(&self, ptr: *mut u8, _: Layout) { - allocator::free(ptr) - } - } -} - /// Crashes the execution of the program. /// /// Equivalent to the WASM `unreachable` instruction, RISC-V `unimp` instruction, diff --git a/substrate/utils/wasm-builder/src/wasm_project.rs b/substrate/utils/wasm-builder/src/wasm_project.rs index 9ffb5c72fd9..13db9fce431 100644 --- a/substrate/utils/wasm-builder/src/wasm_project.rs +++ b/substrate/utils/wasm-builder/src/wasm_project.rs @@ -855,7 +855,7 @@ fn build_bloaty_blob( println!("{} {}", colorize_info_message("Using rustc version:"), cargo_cmd.rustc_version()); // Use `process::exit(1)` to have a clean error output. - if !matches!(build_cmd.status().map(|s| s.success()), Ok(true)) { + if !build_cmd.status().map_or(false, |s| s.success()) { process::exit(1); } -- GitLab From 1ead59773e2dab336d2b54295419bbc3fe7c687f Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <49718502+alexggh@users.noreply.github.com> Date: Tue, 12 Mar 2024 10:33:54 +0200 Subject: [PATCH 030/187] Add api-name in `cannot query the runtime API version` warning (#3653) Sometimes we see nodes printing this warning: ``` cannot query the runtime API version: Api called for an unknown Block: State already discarded for ``` The log is harmless, but let's print the api we got this for, so that we can track its call site and truly confirm it is harmless or fix it. Signed-off-by: Alexandru Gheorghe --- polkadot/node/core/runtime-api/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/polkadot/node/core/runtime-api/src/lib.rs b/polkadot/node/core/runtime-api/src/lib.rs index 4bedfd82734..3ff1a35d068 100644 --- a/polkadot/node/core/runtime-api/src/lib.rs +++ b/polkadot/node/core/runtime-api/src/lib.rs @@ -433,6 +433,7 @@ where .unwrap_or_else(|e| { gum::warn!( target: LOG_TARGET, + api = ?stringify!($api_name), "cannot query the runtime API version: {}", e, ); -- GitLab From a756baf3b211efc57ca4a0089b7ceba4c20b9f12 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Tue, 12 Mar 2024 12:43:31 +0100 Subject: [PATCH 031/187] Support for `keyring` in runtimes (#2044) This functionality is required for #1984. This PR enables [`sp-keyring`](https://github.com/paritytech/polkadot-sdk/blob/21d36b7b4229c4d5225944f197918cde23fda4ea/substrate/primitives/keyring/src/sr25519.rs#L31-L40) in `no-std` environments, allowing to generate the public key (e.g. `AccountKeyring::Alice.public().to_ss58check()`), which can be later used in the any of built-in [_runtime-genesis-config_ variant](https://github.com/paritytech/polkadot-sdk/blob/21d36b7b4229c4d5225944f197918cde23fda4ea/polkadot/node/service/src/chain_spec.rs#L1066-L1073). The proposal is as follows: - expose [`core::Pair` trait](https://github.com/paritytech/polkadot-sdk/blob/d6f15306282e3de848a09c9aa9cba6f95a7811f0/substrate/primitives/core/src/crypto.rs#L832) in `no-std`, - `full_crypto` feature enables `sign` method, - `std` feature enables `generate_with_phrase` and `generate` methods (randomness is required), - All other functionality, currently gated by `full_crypto` will be available unconditionally (`no-std`): -- `from_string` -- `from_string_with_seed` -- `from seed` -- `from_seed_slice` -- `from_phrase` -- `derive` -- `verify` --- Depends on https://github.com/rust-bitcoin/rust-bip39/pull/57 --------- Co-authored-by: command-bot <> Co-authored-by: Davide Galassi --- .gitlab/pipeline/check.yml | 16 +++++ Cargo.lock | 43 ++++++++++++-- substrate/client/cli/Cargo.toml | 3 +- substrate/client/cli/src/commands/generate.rs | 2 +- .../check-features-variants.sh | 12 ++++ .../application-crypto/src/bls377.rs | 5 +- .../application-crypto/src/ecdsa.rs | 4 +- .../application-crypto/src/ecdsa_bls377.rs | 1 + .../application-crypto/src/ed25519.rs | 4 +- .../primitives/application-crypto/src/lib.rs | 59 +++++++++++++------ .../application-crypto/src/sr25519.rs | 4 +- .../application-crypto/src/traits.rs | 14 +---- substrate/primitives/core/Cargo.toml | 24 +++----- .../core/check-features-variants.sh | 13 ++++ substrate/primitives/core/src/address_uri.rs | 2 +- substrate/primitives/core/src/bandersnatch.rs | 28 ++++----- substrate/primitives/core/src/bls.rs | 31 +++------- substrate/primitives/core/src/crypto.rs | 24 +------- substrate/primitives/core/src/ecdsa.rs | 34 ++++------- substrate/primitives/core/src/ed25519.rs | 21 ++----- substrate/primitives/core/src/lib.rs | 3 - .../primitives/core/src/paired_crypto.rs | 27 +++------ substrate/primitives/core/src/sr25519.rs | 30 +++------- substrate/primitives/keyring/Cargo.toml | 7 ++- .../keyring/check-features-variants.sh | 8 +++ .../primitives/keyring/src/bandersnatch.rs | 20 +++++-- substrate/primitives/keyring/src/ed25519.rs | 12 +++- substrate/primitives/keyring/src/lib.rs | 2 + substrate/primitives/keyring/src/sr25519.rs | 20 +++++-- substrate/test-utils/runtime/Cargo.toml | 6 +- 30 files changed, 247 insertions(+), 232 deletions(-) create mode 100755 substrate/primitives/application-crypto/check-features-variants.sh create mode 100755 substrate/primitives/core/check-features-variants.sh create mode 100755 substrate/primitives/keyring/check-features-variants.sh diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index 4d71a473372..52da3355050 100644 --- a/.gitlab/pipeline/check.yml +++ b/.gitlab/pipeline/check.yml @@ -259,3 +259,19 @@ find-fail-ci-phrase: echo "No $ASSERT_REGEX was found, exiting with 0"; exit 0; fi + +check-core-crypto-features: + stage: check + extends: + - .docker-env + - .common-refs + script: + - pushd substrate/primitives/core + - ./check-features-variants.sh + - popd + - pushd substrate/primitives/application-crypto + - ./check-features-variants.sh + - popd + - pushd substrate/primitives/keyring + - ./check-features-variants.sh + - popd diff --git a/Cargo.lock b/Cargo.lock index 5eab3cf7c24..37c5a5177c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1434,9 +1434,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" dependencies = [ - "bitcoin_hashes", - "rand", - "rand_core 0.6.4", + "bitcoin_hashes 0.11.0", "serde", "unicode-normalization", ] @@ -1456,12 +1454,28 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +[[package]] +name = "bitcoin-internals" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" + [[package]] name = "bitcoin_hashes" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" +[[package]] +name = "bitcoin_hashes" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" +dependencies = [ + "bitcoin-internals", + "hex-conservative", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -6348,6 +6362,12 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hex-conservative" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" + [[package]] name = "hex-literal" version = "0.4.1" @@ -11411,6 +11431,19 @@ dependencies = [ "substrate-wasm-builder", ] +[[package]] +name = "parity-bip39" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e69bf016dc406eff7d53a7d3f7cf1c2e72c82b9088aac1118591e36dd2cd3e9" +dependencies = [ + "bitcoin_hashes 0.13.0", + "rand", + "rand_core 0.6.4", + "serde", + "unicode-normalization", +] + [[package]] name = "parity-bytes" version = "0.1.2" @@ -15662,7 +15695,6 @@ name = "sc-cli" version = "0.36.0" dependencies = [ "array-bytes 6.1.0", - "bip39", "chrono", "clap 4.5.1", "fdlimit", @@ -15672,6 +15704,7 @@ dependencies = [ "libp2p-identity", "log", "names", + "parity-bip39", "parity-scale-codec", "rand", "regex", @@ -18611,7 +18644,6 @@ version = "28.0.0" dependencies = [ "array-bytes 6.1.0", "bandersnatch_vrfs", - "bip39", "bitflags 1.3.2", "blake2 0.10.6", "bounded-collections", @@ -18629,6 +18661,7 @@ dependencies = [ "libsecp256k1", "log", "merlin", + "parity-bip39", "parity-scale-codec", "parking_lot 0.12.1", "paste", diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index 0582018283c..c70a0893c72 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -32,7 +32,8 @@ rpassword = "7.0.0" serde = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } thiserror = { workspace = true } -bip39 = "2.0.0" +# personal fork here as workaround for: https://github.com/rust-bitcoin/rust-bip39/pull/64 +bip39 = { package = "parity-bip39", version = "2.0.1", features = ["rand"] } tokio = { version = "1.22.0", features = ["parking_lot", "rt-multi-thread", "signal"] } sc-client-api = { path = "../api" } sc-client-db = { path = "../db", default-features = false } diff --git a/substrate/client/cli/src/commands/generate.rs b/substrate/client/cli/src/commands/generate.rs index c465bcc85a4..94769279e21 100644 --- a/substrate/client/cli/src/commands/generate.rs +++ b/substrate/client/cli/src/commands/generate.rs @@ -64,7 +64,7 @@ impl GenerateCmd { let password = self.keystore_params.read_password()?; let output = self.output_scheme.output_type; - let phrase = mnemonic.word_iter().join(" "); + let phrase = mnemonic.words().join(" "); with_crypto_scheme!( self.crypto_scheme.scheme, diff --git a/substrate/primitives/application-crypto/check-features-variants.sh b/substrate/primitives/application-crypto/check-features-variants.sh new file mode 100755 index 00000000000..dd45a212bae --- /dev/null +++ b/substrate/primitives/application-crypto/check-features-variants.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env -S bash -eux + +export RUSTFLAGS="-Cdebug-assertions=y -Dwarnings" +T=wasm32-unknown-unknown +cargo check --release +cargo check --release --target=$T --no-default-features +cargo check --release --target=$T --no-default-features --features="full_crypto" +cargo check --release --target=$T --no-default-features --features="serde" +cargo check --release --target=$T --no-default-features --features="serde,full_crypto" +cargo check --release --target=$T --no-default-features --features="bandersnatch-experimental" +cargo check --release --target=$T --no-default-features --features="bls-experimental" +cargo check --release --target=$T --no-default-features --features="bls-experimental,full_crypto" diff --git a/substrate/primitives/application-crypto/src/bls377.rs b/substrate/primitives/application-crypto/src/bls377.rs index ee17060564f..3bd01de139c 100644 --- a/substrate/primitives/application-crypto/src/bls377.rs +++ b/substrate/primitives/application-crypto/src/bls377.rs @@ -19,14 +19,13 @@ use crate::{KeyTypeId, RuntimePublic}; pub use sp_core::bls::bls377::*; +use sp_std::vec::Vec; mod app { crate::app_crypto!(super, sp_core::testing::BLS377); } -#[cfg(feature = "full_crypto")] -pub use app::Pair as AppPair; -pub use app::{Public as AppPublic, Signature as AppSignature}; +pub use app::{Pair as AppPair, Public as AppPublic, Signature as AppSignature}; impl RuntimePublic for Public { type Signature = Signature; diff --git a/substrate/primitives/application-crypto/src/ecdsa.rs b/substrate/primitives/application-crypto/src/ecdsa.rs index 27ffe12579f..439b51dc604 100644 --- a/substrate/primitives/application-crypto/src/ecdsa.rs +++ b/substrate/primitives/application-crypto/src/ecdsa.rs @@ -27,9 +27,7 @@ mod app { crate::app_crypto!(super, sp_core::testing::ECDSA); } -#[cfg(feature = "full_crypto")] -pub use app::Pair as AppPair; -pub use app::{Public as AppPublic, Signature as AppSignature}; +pub use app::{Pair as AppPair, Public as AppPublic, Signature as AppSignature}; impl RuntimePublic for Public { type Signature = Signature; diff --git a/substrate/primitives/application-crypto/src/ecdsa_bls377.rs b/substrate/primitives/application-crypto/src/ecdsa_bls377.rs index 70940587ced..8dee73095fb 100644 --- a/substrate/primitives/application-crypto/src/ecdsa_bls377.rs +++ b/substrate/primitives/application-crypto/src/ecdsa_bls377.rs @@ -18,6 +18,7 @@ //! ECDSA and BLS12-377 paired crypto applications. use crate::{KeyTypeId, RuntimePublic}; +use sp_std::vec::Vec; pub use sp_core::paired_crypto::ecdsa_bls377::*; diff --git a/substrate/primitives/application-crypto/src/ed25519.rs b/substrate/primitives/application-crypto/src/ed25519.rs index bc05018370e..addefe7daf6 100644 --- a/substrate/primitives/application-crypto/src/ed25519.rs +++ b/substrate/primitives/application-crypto/src/ed25519.rs @@ -27,9 +27,7 @@ mod app { crate::app_crypto!(super, sp_core::testing::ED25519); } -#[cfg(feature = "full_crypto")] -pub use app::Pair as AppPair; -pub use app::{Public as AppPublic, Signature as AppSignature}; +pub use app::{Pair as AppPair, Public as AppPublic, Signature as AppSignature}; impl RuntimePublic for Public { type Signature = Signature; diff --git a/substrate/primitives/application-crypto/src/lib.rs b/substrate/primitives/application-crypto/src/lib.rs index 686b486f335..ea2e5a83127 100644 --- a/substrate/primitives/application-crypto/src/lib.rs +++ b/substrate/primitives/application-crypto/src/lib.rs @@ -20,12 +20,9 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] -pub use sp_core::crypto::{key_types, CryptoTypeId, KeyTypeId}; +pub use sp_core::crypto::{key_types, CryptoTypeId, DeriveJunction, KeyTypeId, Ss58Codec}; #[doc(hidden)] -#[cfg(feature = "full_crypto")] pub use sp_core::crypto::{DeriveError, Pair, SecretStringError}; -#[cfg(any(feature = "full_crypto", feature = "serde"))] -pub use sp_core::crypto::{DeriveJunction, Ss58Codec}; #[doc(hidden)] pub use sp_core::{ self, @@ -85,7 +82,7 @@ macro_rules! app_crypto { $module::CRYPTO_ID ); $crate::app_crypto_signature_common!($module::Signature, $key_type); - $crate::app_crypto_pair!($module::Pair, $key_type, $module::CRYPTO_ID); + $crate::app_crypto_pair_common!($module::Pair, $key_type, $module::CRYPTO_ID); }; } @@ -116,13 +113,15 @@ macro_rules! app_crypto { $module::CRYPTO_ID ); $crate::app_crypto_signature_common!($module::Signature, $key_type); + $crate::app_crypto_pair_common!($module::Pair, $key_type, $module::CRYPTO_ID); }; } /// Declares `Pair` type which is functionally equivalent to `$pair`, but is /// new application-specific type whose identifier is `$key_type`. +/// It is a common part shared between full_crypto and non full_crypto environments. #[macro_export] -macro_rules! app_crypto_pair { +macro_rules! app_crypto_pair_common { ($pair:ty, $key_type:expr, $crypto_type:expr) => { $crate::wrap! { /// A generic `AppPublic` wrapper type over $pair crypto; this has no specific App. @@ -140,7 +139,14 @@ macro_rules! app_crypto_pair { type Signature = Signature; $crate::app_crypto_pair_functions_if_std!($pair); + $crate::app_crypto_pair_functions_if_full_crypto!($pair); + fn from_phrase( + phrase: &str, + password: Option<&str>, + ) -> Result<(Self, Self::Seed), $crate::SecretStringError> { + <$pair>::from_phrase(phrase, password).map(|r| (Self(r.0), r.1)) + } fn derive>( &self, path: Iter, @@ -154,9 +160,6 @@ macro_rules! app_crypto_pair { fn from_seed_slice(seed: &[u8]) -> Result { <$pair>::from_seed_slice(seed).map(Self) } - fn sign(&self, msg: &[u8]) -> Self::Signature { - Signature(self.0.sign(msg)) - } fn verify>( sig: &Self::Signature, message: M, @@ -203,13 +206,6 @@ macro_rules! app_crypto_pair_functions_if_std { let r = <$pair>::generate_with_phrase(password); (Self(r.0), r.1, r.2) } - - fn from_phrase( - phrase: &str, - password: Option<&str>, - ) -> Result<(Self, Self::Seed), $crate::SecretStringError> { - <$pair>::from_phrase(phrase, password).map(|r| (Self(r.0), r.1)) - } }; } @@ -220,6 +216,25 @@ macro_rules! app_crypto_pair_functions_if_std { ($pair:ty) => {}; } +/// Implements functions for the `Pair` trait when `feature = "full_crypto"` is enabled. +#[doc(hidden)] +#[cfg(feature = "full_crypto")] +#[macro_export] +macro_rules! app_crypto_pair_functions_if_full_crypto { + ($pair:ty) => { + fn sign(&self, msg: &[u8]) -> Self::Signature { + Signature(self.0.sign(msg)) + } + }; +} + +#[doc(hidden)] +#[cfg(not(feature = "full_crypto"))] +#[macro_export] +macro_rules! app_crypto_pair_functions_if_full_crypto { + ($pair:ty) => {}; +} + /// Declares `Public` type which is functionally equivalent to `$public` but is /// new application-specific type whose identifier is `$key_type`. /// For full functionality, `app_crypto_public_common!` must be called too. @@ -267,7 +282,7 @@ macro_rules! app_crypto_public_not_full_crypto { $crate::wrap! { /// A generic `AppPublic` wrapper type over $public crypto; this has no specific App. #[derive( - Clone, Eq, PartialEq, Ord, PartialOrd, + Clone, Eq, Hash, PartialEq, Ord, PartialOrd, $crate::codec::Encode, $crate::codec::Decode, $crate::RuntimeDebug, @@ -277,10 +292,13 @@ macro_rules! app_crypto_public_not_full_crypto { pub struct Public($public); } - impl $crate::CryptoType for Public {} + impl $crate::CryptoType for Public { + type Pair = Pair; + } impl $crate::AppCrypto for Public { type Public = Public; + type Pair = Pair; type Signature = Signature; const ID: $crate::KeyTypeId = $key_type; const CRYPTO_ID: $crate::CryptoTypeId = $crypto_type; @@ -452,10 +470,13 @@ macro_rules! app_crypto_signature_not_full_crypto { pub struct Signature($sig); } - impl $crate::CryptoType for Signature {} + impl $crate::CryptoType for Signature { + type Pair = Pair; + } impl $crate::AppCrypto for Signature { type Public = Public; + type Pair = Pair; type Signature = Signature; const ID: $crate::KeyTypeId = $key_type; const CRYPTO_ID: $crate::CryptoTypeId = $crypto_type; diff --git a/substrate/primitives/application-crypto/src/sr25519.rs b/substrate/primitives/application-crypto/src/sr25519.rs index 7c91bfa7bb5..d411cc253c0 100644 --- a/substrate/primitives/application-crypto/src/sr25519.rs +++ b/substrate/primitives/application-crypto/src/sr25519.rs @@ -27,9 +27,7 @@ mod app { crate::app_crypto!(super, sp_core::testing::SR25519); } -#[cfg(feature = "full_crypto")] -pub use app::Pair as AppPair; -pub use app::{Public as AppPublic, Signature as AppSignature}; +pub use app::{Pair as AppPair, Public as AppPublic, Signature as AppSignature}; impl RuntimePublic for Public { type Signature = Signature; diff --git a/substrate/primitives/application-crypto/src/traits.rs b/substrate/primitives/application-crypto/src/traits.rs index e9b1080f63d..0b59abf272d 100644 --- a/substrate/primitives/application-crypto/src/traits.rs +++ b/substrate/primitives/application-crypto/src/traits.rs @@ -18,9 +18,7 @@ use codec::Codec; use scale_info::TypeInfo; -#[cfg(feature = "full_crypto")] -use sp_core::crypto::Pair; -use sp_core::crypto::{CryptoType, CryptoTypeId, IsWrappedBy, KeyTypeId, Public}; +use sp_core::crypto::{CryptoType, CryptoTypeId, IsWrappedBy, KeyTypeId, Pair, Public}; use sp_std::{fmt::Debug, vec::Vec}; /// Application-specific cryptographic object. @@ -45,24 +43,14 @@ pub trait AppCrypto: 'static + Sized + CryptoType { type Signature: AppSignature; /// The corresponding key pair type in this application scheme. - #[cfg(feature = "full_crypto")] type Pair: AppPair; } /// Type which implements Hash in std, not when no-std (std variant). -#[cfg(any(feature = "std", feature = "full_crypto"))] pub trait MaybeHash: sp_std::hash::Hash {} -#[cfg(any(feature = "std", feature = "full_crypto"))] impl MaybeHash for T {} -/// Type which implements Hash in std, not when no-std (no-std variant). -#[cfg(all(not(feature = "std"), not(feature = "full_crypto")))] -pub trait MaybeHash {} -#[cfg(all(not(feature = "std"), not(feature = "full_crypto")))] -impl MaybeHash for T {} - /// Application-specific key pair. -#[cfg(feature = "full_crypto")] pub trait AppPair: AppCrypto + Pair::Public, Signature = ::Signature> { diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index f7cc2b4fcf7..908f2498de5 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -27,10 +27,11 @@ hash-db = { version = "0.16.0", default-features = false } hash256-std-hasher = { version = "0.15.2", default-features = false } bs58 = { version = "0.5.0", default-features = false, optional = true } rand = { version = "0.8.5", features = ["small_rng"], optional = true } -substrate-bip39 = { path = "../../utils/substrate-bip39", optional = true } -bip39 = { version = "2.0.0", default-features = false } +substrate-bip39 = { path = "../../utils/substrate-bip39", default-features = false } +# personal fork here as workaround for: https://github.com/rust-bitcoin/rust-bip39/pull/64 +bip39 = { package = "parity-bip39", version = "2.0.1", default-features = false, features = ["alloc"] } zeroize = { version = "1.4.3", default-features = false } -secrecy = { version = "0.8.0", default-features = false } +secrecy = { version = "0.8.0", default-features = false, features = ["alloc"] } parking_lot = { version = "0.12.1", optional = true } ss58-registry = { version = "1.34.0", default-features = false } sp-std = { path = "../std", default-features = false } @@ -46,13 +47,13 @@ paste = "1.0.7" itertools = { version = "0.10.3", optional = true } # full crypto -array-bytes = { version = "6.1", optional = true } -ed25519-zebra = { version = "3.1.0", default-features = false, optional = true } +array-bytes = { version = "6.1" } +ed25519-zebra = { version = "3.1.0", default-features = false } blake2 = { version = "0.10.4", default-features = false, optional = true } -libsecp256k1 = { version = "0.7", default-features = false, features = ["static-context"], optional = true } +libsecp256k1 = { version = "0.7", default-features = false, features = ["static-context"] } schnorrkel = { version = "0.11.4", features = ["preaudit_deprecated"], default-features = false } merlin = { version = "3.0", default-features = false } -sp-crypto-hashing = { path = "../crypto/hashing", default-features = false, optional = true } +sp-crypto-hashing = { path = "../crypto/hashing", default-features = false } sp-runtime-interface = { path = "../runtime-interface", default-features = false } # k256 crate, better portability, intended to be used in substrate-runtimes (no-std) k256 = { version = "0.13.3", features = ["alloc", "ecdsa"], default-features = false } @@ -81,7 +82,6 @@ bench = false default = ["std"] std = [ - "array-bytes", "bandersnatch_vrfs?/std", "bip39/rand", "bip39/std", @@ -112,7 +112,6 @@ std = [ "schnorrkel/std", "secp256k1/global-context", "secp256k1/std", - "secrecy/alloc", "serde/std", "sp-crypto-hashing/std", "sp-debug-derive/std", @@ -131,7 +130,6 @@ std = [ # Serde support without relying on std features. serde = [ - "array-bytes", "blake2", "bounded-collections/serde", "bs58/alloc", @@ -140,8 +138,6 @@ serde = [ "k256/serde", "primitive-types/serde_no_std", "scale-info/serde", - "secrecy/alloc", - "sp-crypto-hashing", "sp-storage/serde", ] @@ -149,11 +145,7 @@ serde = [ # or Intel SGX. # For the regular wasm runtime builds this should not be used. full_crypto = [ - "array-bytes", "blake2", - "ed25519-zebra", - "libsecp256k1", - "sp-crypto-hashing", "sp-runtime-interface/disable_target_static_assertions", ] diff --git a/substrate/primitives/core/check-features-variants.sh b/substrate/primitives/core/check-features-variants.sh new file mode 100755 index 00000000000..6d28212065a --- /dev/null +++ b/substrate/primitives/core/check-features-variants.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env -S bash -eux + +export RUSTFLAGS="-Cdebug-assertions=y -Dwarnings" +T=wasm32-unknown-unknown + +cargo check --target=$T --release --no-default-features --features="bls-experimental" +cargo check --target=$T --release --no-default-features --features="full_crypto,bls-experimental" +cargo check --target=$T --release --no-default-features --features="bandersnatch-experimental" +cargo check --target=$T --release --no-default-features --features="full_crypto,serde,bandersnatch-experimental" +cargo check --target=$T --release --no-default-features --features="full_crypto,serde" +cargo check --target=$T --release --no-default-features --features="full_crypto" +cargo check --target=$T --release --no-default-features --features="serde" +cargo check --target=$T --release --no-default-features diff --git a/substrate/primitives/core/src/address_uri.rs b/substrate/primitives/core/src/address_uri.rs index 211d47c0093..2e32d0cd86d 100644 --- a/substrate/primitives/core/src/address_uri.rs +++ b/substrate/primitives/core/src/address_uri.rs @@ -17,7 +17,7 @@ //! Little util for parsing an address URI. Replaces regular expressions. -#[cfg(all(not(feature = "std"), any(feature = "serde", feature = "full_crypto")))] +#[cfg(not(feature = "std"))] use sp_std::{ alloc::string::{String, ToString}, vec::Vec, diff --git a/substrate/primitives/core/src/bandersnatch.rs b/substrate/primitives/core/src/bandersnatch.rs index 61e7162544a..5cae6047f16 100644 --- a/substrate/primitives/core/src/bandersnatch.rs +++ b/substrate/primitives/core/src/bandersnatch.rs @@ -22,19 +22,18 @@ #[cfg(feature = "serde")] use crate::crypto::Ss58Codec; +#[cfg(feature = "full_crypto")] +use crate::crypto::VrfSecret; use crate::crypto::{ - ByteArray, CryptoType, CryptoTypeId, Derive, Public as TraitPublic, UncheckedFrom, VrfPublic, + ByteArray, CryptoType, CryptoTypeId, Derive, DeriveError, DeriveJunction, Pair as TraitPair, + Public as TraitPublic, SecretStringError, UncheckedFrom, VrfPublic, }; -#[cfg(feature = "full_crypto")] -use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError, VrfSecret}; #[cfg(feature = "serde")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; #[cfg(all(not(feature = "std"), feature = "serde"))] use sp_std::alloc::{format, string::String}; -use bandersnatch_vrfs::CanonicalSerialize; -#[cfg(feature = "full_crypto")] -use bandersnatch_vrfs::SecretKey; +use bandersnatch_vrfs::{CanonicalSerialize, SecretKey}; use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; use scale_info::TypeInfo; @@ -45,10 +44,8 @@ use sp_std::{vec, vec::Vec}; pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"band"); /// Context used to produce a plain signature without any VRF input/output. -#[cfg(feature = "full_crypto")] pub const SIGNING_CTX: &[u8] = b"BandersnatchSigningContext"; -#[cfg(feature = "full_crypto")] const SEED_SERIALIZED_SIZE: usize = 32; const PUBLIC_SERIALIZED_SIZE: usize = 33; @@ -56,7 +53,6 @@ const SIGNATURE_SERIALIZED_SIZE: usize = 65; const PREOUT_SERIALIZED_SIZE: usize = 33; /// Bandersnatch public key. -#[cfg_attr(feature = "full_crypto", derive(Hash))] #[derive( Clone, Copy, @@ -69,6 +65,7 @@ const PREOUT_SERIALIZED_SIZE: usize = 33; PassByInner, MaxEncodedLen, TypeInfo, + Hash, )] pub struct Public(pub [u8; PUBLIC_SERIALIZED_SIZE]); @@ -116,7 +113,6 @@ impl ByteArray for Public { impl TraitPublic for Public {} impl CryptoType for Public { - #[cfg(feature = "full_crypto")] type Pair = Pair; } @@ -154,8 +150,9 @@ impl<'de> Deserialize<'de> for Public { /// /// The signature is created via the [`VrfSecret::vrf_sign`] using [`SIGNING_CTX`] as transcript /// `label`. -#[cfg_attr(feature = "full_crypto", derive(Hash))] -#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode, PassByInner, MaxEncodedLen, TypeInfo)] +#[derive( + Clone, Copy, PartialEq, Eq, Encode, Decode, PassByInner, MaxEncodedLen, TypeInfo, Hash, +)] pub struct Signature([u8; SIGNATURE_SERIALIZED_SIZE]); impl UncheckedFrom<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature { @@ -194,7 +191,6 @@ impl ByteArray for Signature { } impl CryptoType for Signature { - #[cfg(feature = "full_crypto")] type Pair = Pair; } @@ -211,18 +207,15 @@ impl sp_std::fmt::Debug for Signature { } /// The raw secret seed, which can be used to reconstruct the secret [`Pair`]. -#[cfg(feature = "full_crypto")] type Seed = [u8; SEED_SERIALIZED_SIZE]; /// Bandersnatch secret key. -#[cfg(feature = "full_crypto")] #[derive(Clone)] pub struct Pair { secret: SecretKey, seed: Seed, } -#[cfg(feature = "full_crypto")] impl Pair { /// Get the key seed. pub fn seed(&self) -> Seed { @@ -230,7 +223,6 @@ impl Pair { } } -#[cfg(feature = "full_crypto")] impl TraitPair for Pair { type Seed = Seed; type Public = Public; @@ -287,6 +279,7 @@ impl TraitPair for Pair { /// the constant label [`SIGNING_CTX`] and `data` without any additional data. /// /// See [`vrf::VrfSignData`] for additional details. + #[cfg(feature = "full_crypto")] fn sign(&self, data: &[u8]) -> Signature { let data = vrf::VrfSignData::new_unchecked(SIGNING_CTX, &[data], None); self.vrf_sign(&data).signature @@ -305,7 +298,6 @@ impl TraitPair for Pair { } } -#[cfg(feature = "full_crypto")] impl CryptoType for Pair { type Pair = Pair; } diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index 0c84d0ba8e6..2256e4cd823 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -25,11 +25,11 @@ #[cfg(feature = "serde")] use crate::crypto::Ss58Codec; -use crate::crypto::{ByteArray, CryptoType, Derive, Public as TraitPublic, UncheckedFrom}; -#[cfg(feature = "full_crypto")] -use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError}; +use crate::crypto::{ + ByteArray, CryptoType, Derive, DeriveError, DeriveJunction, Pair as TraitPair, + Public as TraitPublic, SecretStringError, UncheckedFrom, +}; -#[cfg(feature = "full_crypto")] use sp_std::vec::Vec; use codec::{Decode, Encode, MaxEncodedLen}; @@ -40,9 +40,10 @@ use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; #[cfg(all(not(feature = "std"), feature = "serde"))] use sp_std::alloc::{format, string::String}; -use w3f_bls::{DoublePublicKey, DoubleSignature, EngineBLS, SerializableToBytes, TinyBLS381}; -#[cfg(feature = "full_crypto")] -use w3f_bls::{DoublePublicKeyScheme, Keypair, Message, SecretKey}; +use w3f_bls::{ + DoublePublicKey, DoublePublicKeyScheme, DoubleSignature, EngineBLS, Keypair, Message, + SecretKey, SerializableToBytes, TinyBLS381, +}; use sp_runtime_interface::pass_by::{self, PassBy, PassByInner}; use sp_std::{convert::TryFrom, marker::PhantomData, ops::Deref}; @@ -57,7 +58,6 @@ pub mod bls377 { pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"bls7"); /// BLS12-377 key pair. - #[cfg(feature = "full_crypto")] pub type Pair = super::Pair; /// BLS12-377 public key. pub type Public = super::Public; @@ -79,7 +79,6 @@ pub mod bls381 { pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"bls8"); /// BLS12-381 key pair. - #[cfg(feature = "full_crypto")] pub type Pair = super::Pair; /// BLS12-381 public key. pub type Public = super::Public; @@ -96,7 +95,6 @@ trait BlsBound: EngineBLS + HardJunctionId + Send + Sync + 'static {} impl BlsBound for T {} /// Secret key serialized size -#[cfg(feature = "full_crypto")] const SECRET_KEY_SERIALIZED_SIZE: usize = as SerializableToBytes>::SERIALIZED_BYTES_SIZE; @@ -113,7 +111,6 @@ pub const SIGNATURE_SERIALIZED_SIZE: usize = /// It's not called a "secret key" because ring doesn't expose the secret keys /// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we /// will need it later (such as for HDKD). -#[cfg(feature = "full_crypto")] type Seed = [u8; SECRET_KEY_SERIALIZED_SIZE]; /// A public key. @@ -150,7 +147,6 @@ impl Ord for Public { } } -#[cfg(feature = "full_crypto")] impl sp_std::hash::Hash for Public { fn hash(&self, state: &mut H) { self.inner.hash(state) @@ -226,7 +222,6 @@ impl From> for [u8; PUBLIC_KEY_SERIALIZED_SIZE] { } } -#[cfg(feature = "full_crypto")] impl From> for Public { fn from(x: Pair) -> Self { x.public() @@ -296,7 +291,6 @@ impl TraitPublic for Public {} impl Derive for Public {} impl CryptoType for Public { - #[cfg(feature = "full_crypto")] type Pair = Pair; } @@ -322,7 +316,6 @@ impl PartialEq for Signature { impl Eq for Signature {} -#[cfg(feature = "full_crypto")] impl sp_std::hash::Hash for Signature { fn hash(&self, state: &mut H) { self.inner.hash(state) @@ -412,15 +405,12 @@ impl UncheckedFrom<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature { } impl CryptoType for Signature { - #[cfg(feature = "full_crypto")] type Pair = Pair; } /// A key pair. -#[cfg(feature = "full_crypto")] pub struct Pair(Keypair); -#[cfg(feature = "full_crypto")] impl Clone for Pair { fn clone(&self) -> Self { Pair(self.0.clone()) @@ -432,15 +422,12 @@ trait HardJunctionId { } /// Derive a single hard junction. -#[cfg(feature = "full_crypto")] fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed { (T::ID, secret_seed, cc).using_encoded(sp_crypto_hashing::blake2_256) } -#[cfg(feature = "full_crypto")] impl Pair {} -#[cfg(feature = "full_crypto")] impl TraitPair for Pair { type Seed = Seed; type Public = Public; @@ -480,6 +467,7 @@ impl TraitPair for Pair { Self::Public::unchecked_from(raw) } + #[cfg(feature = "full_crypto")] fn sign(&self, message: &[u8]) -> Self::Signature { let mut mutable_self = self.clone(); let r: [u8; SIGNATURE_SERIALIZED_SIZE] = @@ -523,7 +511,6 @@ impl TraitPair for Pair { } } -#[cfg(feature = "full_crypto")] impl CryptoType for Pair { type Pair = Pair; } diff --git a/substrate/primitives/core/src/crypto.rs b/substrate/primitives/core/src/crypto.rs index 2a8be2a2ba8..fab865d8c1f 100644 --- a/substrate/primitives/core/src/crypto.rs +++ b/substrate/primitives/core/src/crypto.rs @@ -18,7 +18,6 @@ //! Cryptographic utilities. use crate::{ed25519, sr25519}; -#[cfg(feature = "std")] use bip39::{Language, Mnemonic}; use codec::{Decode, Encode, MaxEncodedLen}; #[cfg(feature = "std")] @@ -26,7 +25,6 @@ use itertools::Itertools; #[cfg(feature = "std")] use rand::{rngs::OsRng, RngCore}; use scale_info::TypeInfo; -#[cfg(feature = "std")] pub use secrecy::{ExposeSecret, SecretString}; use sp_runtime_interface::pass_by::PassByInner; #[doc(hidden)] @@ -41,10 +39,7 @@ pub use ss58_registry::{from_known_address_format, Ss58AddressFormat, Ss58Addres /// Trait to zeroize a memory buffer. pub use zeroize::Zeroize; -#[cfg(feature = "std")] -pub use crate::address_uri::AddressUri; -#[cfg(any(feature = "std", feature = "full_crypto"))] -pub use crate::address_uri::Error as AddressUriError; +pub use crate::address_uri::{AddressUri, Error as AddressUriError}; /// The root phrase for our publicly known keys. pub const DEV_PHRASE: &str = @@ -82,7 +77,6 @@ impl> UncheckedInto for S { /// An error with the interpretation of a secret. #[cfg_attr(feature = "std", derive(thiserror::Error))] #[derive(Debug, Clone, PartialEq, Eq)] -#[cfg(feature = "full_crypto")] pub enum SecretStringError { /// The overall format was invalid (e.g. the seed phrase contained symbols). #[cfg_attr(feature = "std", error("Invalid format {0}"))] @@ -104,7 +98,6 @@ pub enum SecretStringError { InvalidPath, } -#[cfg(any(feature = "std", feature = "full_crypto"))] impl From for SecretStringError { fn from(e: AddressUriError) -> Self { Self::InvalidFormat(e) @@ -114,7 +107,6 @@ impl From for SecretStringError { /// An error when deriving a key. #[cfg_attr(feature = "std", derive(thiserror::Error))] #[derive(Debug, Clone, PartialEq, Eq)] -#[cfg(feature = "full_crypto")] pub enum DeriveError { /// A soft key was found in the path (and is unsupported). #[cfg_attr(feature = "std", error("Soft key in path"))] @@ -125,7 +117,6 @@ pub enum DeriveError { /// a new secret key from an existing secret key and, in the case of `SoftRaw` and `SoftIndex` /// a new public key from an existing public key. #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Encode, Decode)] -#[cfg(any(feature = "full_crypto", feature = "serde"))] pub enum DeriveJunction { /// Soft (vanilla) derivation. Public keys have a correspondent derivation. Soft([u8; JUNCTION_ID_LEN]), @@ -133,7 +124,6 @@ pub enum DeriveJunction { Hard([u8; JUNCTION_ID_LEN]), } -#[cfg(any(feature = "full_crypto", feature = "serde"))] impl DeriveJunction { /// Consume self to return a soft derive junction with the same chain code. pub fn soften(self) -> Self { @@ -192,7 +182,6 @@ impl DeriveJunction { } } -#[cfg(any(feature = "full_crypto", feature = "serde"))] impl> From for DeriveJunction { fn from(j: T) -> DeriveJunction { let j = j.as_ref(); @@ -812,7 +801,6 @@ mod dummy { /// assert_eq!("0xe5be9a5092b81bca64be81d212e7f2f9eba183bb7a90954f7b76361f6edb5c0a", suri.phrase.expose_secret()); /// assert!(suri.password.is_none()); /// ``` -#[cfg(feature = "std")] pub struct SecretUri { /// The phrase to derive the private key. /// @@ -824,7 +812,6 @@ pub struct SecretUri { pub junctions: Vec, } -#[cfg(feature = "std")] impl sp_std::str::FromStr for SecretUri { type Err = SecretStringError; @@ -845,7 +832,6 @@ impl sp_std::str::FromStr for SecretUri { /// Trait suitable for typical cryptographic PKI key pair type. /// /// For now it just specifies how to create a key from a phrase and derivation path. -#[cfg(feature = "full_crypto")] pub trait Pair: CryptoType + Sized { /// The type which is used to encode a public key. type Public: Public + Hash; @@ -878,21 +864,19 @@ pub trait Pair: CryptoType + Sized { #[cfg(feature = "std")] fn generate_with_phrase(password: Option<&str>) -> (Self, String, Self::Seed) { let mnemonic = Mnemonic::generate(12).expect("Mnemonic generation always works; qed"); - let phrase = mnemonic.word_iter().join(" "); + let phrase = mnemonic.words().join(" "); let (pair, seed) = Self::from_phrase(&phrase, password) .expect("All phrases generated by Mnemonic are valid; qed"); (pair, phrase.to_owned(), seed) } /// Returns the KeyPair from the English BIP39 seed `phrase`, or an error if it's invalid. - #[cfg(feature = "std")] fn from_phrase( phrase: &str, password: Option<&str>, ) -> Result<(Self, Self::Seed), SecretStringError> { let mnemonic = Mnemonic::parse_in(Language::English, phrase) .map_err(|_| SecretStringError::InvalidPhrase)?; - let (entropy, entropy_len) = mnemonic.to_entropy_array(); let big_seed = substrate_bip39::seed_from_entropy(&entropy[0..entropy_len], password.unwrap_or("")) @@ -928,6 +912,7 @@ pub trait Pair: CryptoType + Sized { fn from_seed_slice(seed: &[u8]) -> Result; /// Sign a message. + #[cfg(feature = "full_crypto")] fn sign(&self, message: &[u8]) -> Self::Signature; /// Verify a signature on a message. Returns true if the signature is good. @@ -962,7 +947,6 @@ pub trait Pair: CryptoType + Sized { /// Notably, integer junction indices may be legally prefixed with arbitrary number of zeros. /// Similarly an empty password (ending the SURI with `///`) is perfectly valid and will /// generally be equivalent to no password at all. - #[cfg(feature = "std")] fn from_string_with_seed( s: &str, password_override: Option<&str>, @@ -996,7 +980,6 @@ pub trait Pair: CryptoType + Sized { /// Interprets the string `s` in order to generate a key pair. /// /// See [`from_string_with_seed`](Pair::from_string_with_seed) for more extensive documentation. - #[cfg(feature = "std")] fn from_string(s: &str, password_override: Option<&str>) -> Result { Self::from_string_with_seed(s, password_override).map(|x| x.0) } @@ -1054,7 +1037,6 @@ where /// Type which has a particular kind of crypto associated with it. pub trait CryptoType { /// The pair key type of this crypto. - #[cfg(feature = "full_crypto")] type Pair: Pair; } diff --git a/substrate/primitives/core/src/ecdsa.rs b/substrate/primitives/core/src/ecdsa.rs index e6bd2c7eb57..fa071e1b03f 100644 --- a/substrate/primitives/core/src/ecdsa.rs +++ b/substrate/primitives/core/src/ecdsa.rs @@ -24,16 +24,13 @@ use sp_runtime_interface::pass_by::PassByInner; #[cfg(feature = "serde")] use crate::crypto::Ss58Codec; use crate::crypto::{ - ByteArray, CryptoType, CryptoTypeId, Derive, Public as TraitPublic, UncheckedFrom, + ByteArray, CryptoType, CryptoTypeId, Derive, DeriveError, DeriveJunction, Pair as TraitPair, + Public as TraitPublic, SecretStringError, UncheckedFrom, }; -#[cfg(feature = "full_crypto")] -use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError}; -#[cfg(all(not(feature = "std"), feature = "full_crypto"))] -use k256::ecdsa::SigningKey as SecretKey; #[cfg(not(feature = "std"))] -use k256::ecdsa::VerifyingKey; -#[cfg(all(feature = "std", feature = "full_crypto"))] +use k256::ecdsa::{SigningKey as SecretKey, VerifyingKey}; +#[cfg(feature = "std")] use secp256k1::{ ecdsa::{RecoverableSignature, RecoveryId}, Message, PublicKey, SecretKey, SECP256K1, @@ -42,7 +39,7 @@ use secp256k1::{ use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; #[cfg(all(not(feature = "std"), feature = "serde"))] use sp_std::alloc::{format, string::String}; -#[cfg(feature = "full_crypto")] +#[cfg(not(feature = "std"))] use sp_std::vec::Vec; /// An identifier used to match public keys against ecdsa keys @@ -57,11 +54,9 @@ pub const SIGNATURE_SERIALIZED_SIZE: usize = 65; /// The secret seed. /// /// The raw secret seed, which can be used to create the `Pair`. -#[cfg(feature = "full_crypto")] type Seed = [u8; 32]; /// The ECDSA compressed public key. -#[cfg_attr(feature = "full_crypto", derive(Hash))] #[derive( Clone, Copy, @@ -74,6 +69,7 @@ type Seed = [u8; 32]; PartialEq, PartialOrd, Ord, + Hash, )] pub struct Public(pub [u8; PUBLIC_KEY_SERIALIZED_SIZE]); @@ -221,8 +217,7 @@ impl<'de> Deserialize<'de> for Public { } /// A signature (a 512-bit value, plus 8 bits for recovery ID). -#[cfg_attr(feature = "full_crypto", derive(Hash))] -#[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)] +#[derive(Hash, Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)] pub struct Signature(pub [u8; SIGNATURE_SERIALIZED_SIZE]); impl ByteArray for Signature { @@ -345,13 +340,11 @@ impl Signature { } /// Recover the public key from this signature and a message. - #[cfg(feature = "full_crypto")] pub fn recover>(&self, message: M) -> Option { self.recover_prehashed(&sp_crypto_hashing::blake2_256(message.as_ref())) } /// Recover the public key from this signature and a pre-hashed message. - #[cfg(feature = "full_crypto")] pub fn recover_prehashed(&self, message: &[u8; 32]) -> Option { #[cfg(feature = "std")] { @@ -380,7 +373,7 @@ impl From<(k256::ecdsa::Signature, k256::ecdsa::RecoveryId)> for Signature { } } -#[cfg(all(feature = "std", feature = "full_crypto"))] +#[cfg(feature = "std")] impl From for Signature { fn from(recsig: RecoverableSignature) -> Signature { let mut r = Self::default(); @@ -393,20 +386,17 @@ impl From for Signature { } /// Derive a single hard junction. -#[cfg(feature = "full_crypto")] fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed { ("Secp256k1HDKD", secret_seed, cc).using_encoded(sp_crypto_hashing::blake2_256) } /// A key pair. -#[cfg(feature = "full_crypto")] #[derive(Clone)] pub struct Pair { public: Public, secret: SecretKey, } -#[cfg(feature = "full_crypto")] impl TraitPair for Pair { type Public = Public; type Seed = Seed; @@ -454,6 +444,7 @@ impl TraitPair for Pair { } /// Sign a message. + #[cfg(feature = "full_crypto")] fn sign(&self, message: &[u8]) -> Signature { self.sign_prehashed(&sp_crypto_hashing::blake2_256(message)) } @@ -469,7 +460,6 @@ impl TraitPair for Pair { } } -#[cfg(feature = "full_crypto")] impl Pair { /// Get the seed for this key. pub fn seed(&self) -> Seed { @@ -496,6 +486,7 @@ impl Pair { } /// Sign a pre-hashed message + #[cfg(feature = "full_crypto")] pub fn sign_prehashed(&self, message: &[u8; 32]) -> Signature { #[cfg(feature = "std")] { @@ -550,7 +541,7 @@ impl Pair { // NOTE: this solution is not effective when `Pair` is moved around memory. // The very same problem affects other cryptographic backends that are just using // `zeroize`for their secrets. -#[cfg(all(feature = "std", feature = "full_crypto"))] +#[cfg(feature = "std")] impl Drop for Pair { fn drop(&mut self) { self.secret.non_secure_erase() @@ -558,16 +549,13 @@ impl Drop for Pair { } impl CryptoType for Public { - #[cfg(feature = "full_crypto")] type Pair = Pair; } impl CryptoType for Signature { - #[cfg(feature = "full_crypto")] type Pair = Pair; } -#[cfg(feature = "full_crypto")] impl CryptoType for Pair { type Pair = Pair; } diff --git a/substrate/primitives/core/src/ed25519.rs b/substrate/primitives/core/src/ed25519.rs index 60ebd93e12d..9f42b36dc8b 100644 --- a/substrate/primitives/core/src/ed25519.rs +++ b/substrate/primitives/core/src/ed25519.rs @@ -19,7 +19,6 @@ //! Simple Ed25519 API. // end::description[] -#[cfg(feature = "full_crypto")] use sp_std::vec::Vec; use crate::{ @@ -32,13 +31,11 @@ use scale_info::TypeInfo; #[cfg(feature = "serde")] use crate::crypto::Ss58Codec; use crate::crypto::{ - CryptoType, CryptoTypeId, Derive, FromEntropy, Public as TraitPublic, UncheckedFrom, + CryptoType, CryptoTypeId, Derive, DeriveError, DeriveJunction, FromEntropy, Pair as TraitPair, + Public as TraitPublic, SecretStringError, UncheckedFrom, }; #[cfg(feature = "full_crypto")] -use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError}; -#[cfg(feature = "full_crypto")] use core::convert::TryFrom; -#[cfg(feature = "full_crypto")] use ed25519_zebra::{SigningKey, VerificationKey}; #[cfg(feature = "serde")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; @@ -53,11 +50,9 @@ pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ed25"); /// A secret seed. It's not called a "secret key" because ring doesn't expose the secret keys /// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we /// will need it later (such as for HDKD). -#[cfg(feature = "full_crypto")] type Seed = [u8; 32]; /// A public key. -#[cfg_attr(feature = "full_crypto", derive(Hash))] #[derive( PartialEq, Eq, @@ -70,11 +65,11 @@ type Seed = [u8; 32]; PassByInner, MaxEncodedLen, TypeInfo, + Hash, )] pub struct Public(pub [u8; 32]); /// A key pair. -#[cfg(feature = "full_crypto")] #[derive(Copy, Clone)] pub struct Pair { public: VerificationKey, @@ -210,8 +205,7 @@ impl<'de> Deserialize<'de> for Public { } /// A signature (a 512-bit value). -#[cfg_attr(feature = "full_crypto", derive(Hash))] -#[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)] +#[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq, Hash)] pub struct Signature(pub [u8; 64]); impl TryFrom<&[u8]> for Signature { @@ -370,12 +364,10 @@ impl TraitPublic for Public {} impl Derive for Public {} /// Derive a single hard junction. -#[cfg(feature = "full_crypto")] fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed { ("Ed25519HDKD", secret_seed, cc).using_encoded(sp_crypto_hashing::blake2_256) } -#[cfg(feature = "full_crypto")] impl TraitPair for Pair { type Public = Public; type Seed = Seed; @@ -414,6 +406,7 @@ impl TraitPair for Pair { } /// Sign a message. + #[cfg(feature = "full_crypto")] fn sign(&self, message: &[u8]) -> Signature { Signature::from_raw(self.secret.sign(message).into()) } @@ -433,7 +426,6 @@ impl TraitPair for Pair { } } -#[cfg(feature = "full_crypto")] impl Pair { /// Get the seed for this key. pub fn seed(&self) -> Seed { @@ -454,16 +446,13 @@ impl Pair { } impl CryptoType for Public { - #[cfg(feature = "full_crypto")] type Pair = Pair; } impl CryptoType for Signature { - #[cfg(feature = "full_crypto")] type Pair = Pair; } -#[cfg(feature = "full_crypto")] impl CryptoType for Pair { type Pair = Pair; } diff --git a/substrate/primitives/core/src/lib.rs b/substrate/primitives/core/src/lib.rs index 0d43eea9962..c0b41234460 100644 --- a/substrate/primitives/core/src/lib.rs +++ b/substrate/primitives/core/src/lib.rs @@ -46,7 +46,6 @@ pub use sp_debug_derive::RuntimeDebug; #[cfg(feature = "serde")] pub use impl_serde::serialize as bytes; -#[cfg(feature = "full_crypto")] #[deprecated( since = "27.0.0", note = "`sp-crypto-hashing` re-exports will be removed after June 2024. Use `sp-crypto-hashing` instead." @@ -58,7 +57,6 @@ pub mod crypto; pub mod hexdisplay; pub use paste; -#[cfg(any(feature = "full_crypto", feature = "std"))] mod address_uri; #[cfg(feature = "bandersnatch-experimental")] pub mod bandersnatch; @@ -87,7 +85,6 @@ pub use self::{ hash::{convert_hash, H160, H256, H512}, uint::{U256, U512}, }; -#[cfg(feature = "full_crypto")] pub use crypto::{ByteArray, DeriveJunction, Pair, Public}; #[cfg(feature = "std")] diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 20b32c339bd..6d2e6ddf334 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -19,11 +19,11 @@ #[cfg(feature = "serde")] use crate::crypto::Ss58Codec; -use crate::crypto::{ByteArray, CryptoType, Derive, Public as PublicT, UncheckedFrom}; -#[cfg(feature = "full_crypto")] -use crate::crypto::{DeriveError, DeriveJunction, Pair as PairT, SecretStringError}; +use crate::crypto::{ + ByteArray, CryptoType, Derive, DeriveError, DeriveJunction, Pair as PairT, Public as PublicT, + SecretStringError, UncheckedFrom, +}; -#[cfg(feature = "full_crypto")] use sp_std::vec::Vec; use codec::{Decode, Encode, MaxEncodedLen}; @@ -39,12 +39,11 @@ use sp_std::convert::TryFrom; /// ECDSA and BLS12-377 paired crypto scheme #[cfg(feature = "bls-experimental")] pub mod ecdsa_bls377 { + use crate::{bls377, crypto::CryptoTypeId, ecdsa}; #[cfg(feature = "full_crypto")] - use crate::Hasher; use crate::{ - bls377, - crypto::{CryptoTypeId, Pair as PairT, UncheckedFrom}, - ecdsa, + crypto::{Pair as PairT, UncheckedFrom}, + Hasher, }; /// An identifier used to match public keys against BLS12-377 keys @@ -56,7 +55,6 @@ pub mod ecdsa_bls377 { ecdsa::SIGNATURE_SERIALIZED_SIZE + bls377::SIGNATURE_SERIALIZED_SIZE; /// (ECDSA,BLS12-377) key-pair pair. - #[cfg(feature = "full_crypto")] pub type Pair = super::Pair; /// (ECDSA,BLS12-377) public key pair. pub type Public = super::Public; @@ -64,16 +62,13 @@ pub mod ecdsa_bls377 { pub type Signature = super::Signature; impl super::CryptoType for Public { - #[cfg(feature = "full_crypto")] type Pair = Pair; } impl super::CryptoType for Signature { - #[cfg(feature = "full_crypto")] type Pair = Pair; } - #[cfg(feature = "full_crypto")] impl super::CryptoType for Pair { type Pair = Pair; } @@ -136,7 +131,6 @@ pub mod ecdsa_bls377 { /// Secure seed length. /// /// Currently only supporting sub-schemes whose seed is a 32-bytes array. -#[cfg(feature = "full_crypto")] const SECURE_SEED_LEN: usize = 32; /// A secret seed. @@ -144,14 +138,12 @@ const SECURE_SEED_LEN: usize = 32; /// It's not called a "secret key" because ring doesn't expose the secret keys /// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we /// will need it later (such as for HDKD). -#[cfg(feature = "full_crypto")] type Seed = [u8; SECURE_SEED_LEN]; /// A public key. #[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] pub struct Public([u8; LEFT_PLUS_RIGHT_LEN]); -#[cfg(feature = "full_crypto")] impl sp_std::hash::Hash for Public { fn hash(&self, state: &mut H) { self.0.hash(state); @@ -215,7 +207,6 @@ impl PassBy for Public { type PassBy = pass_by::Inner; } -#[cfg(feature = "full_crypto")] impl< LeftPair: PairT, RightPair: PairT, @@ -311,7 +302,6 @@ impl SignatureBound for T {} #[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] pub struct Signature([u8; LEFT_PLUS_RIGHT_LEN]); -#[cfg(feature = "full_crypto")] impl sp_std::hash::Hash for Signature { fn hash(&self, state: &mut H) { self.0.hash(state); @@ -411,7 +401,6 @@ impl UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> } /// A key pair. -#[cfg(feature = "full_crypto")] #[derive(Clone)] pub struct Pair< LeftPair: PairT, @@ -423,7 +412,6 @@ pub struct Pair< right: RightPair, } -#[cfg(feature = "full_crypto")] impl< LeftPair: PairT, RightPair: PairT, @@ -483,6 +471,7 @@ where Self::Public::unchecked_from(raw) } + #[cfg(feature = "full_crypto")] fn sign(&self, message: &[u8]) -> Self::Signature { let mut raw: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN]; raw[..LeftPair::Signature::LEN].copy_from_slice(self.left.sign(message).as_ref()); diff --git a/substrate/primitives/core/src/sr25519.rs b/substrate/primitives/core/src/sr25519.rs index 7c02afc3cd5..6c04eb8def1 100644 --- a/substrate/primitives/core/src/sr25519.rs +++ b/substrate/primitives/core/src/sr25519.rs @@ -19,20 +19,14 @@ //! //! Note: `CHAIN_CODE_LENGTH` must be equal to `crate::crypto::JUNCTION_ID_LEN` //! for this to work. -#[cfg(any(feature = "full_crypto", feature = "serde"))] -use crate::crypto::DeriveJunction; #[cfg(feature = "serde")] use crate::crypto::Ss58Codec; +use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError}; #[cfg(feature = "full_crypto")] -use crate::crypto::{DeriveError, Pair as TraitPair, SecretStringError}; -#[cfg(feature = "full_crypto")] -use schnorrkel::{ - derive::CHAIN_CODE_LENGTH, signing_context, ExpansionMode, Keypair, MiniSecretKey, SecretKey, -}; -#[cfg(any(feature = "full_crypto", feature = "serde"))] +use schnorrkel::signing_context; use schnorrkel::{ - derive::{ChainCode, Derivation}, - PublicKey, + derive::{ChainCode, Derivation, CHAIN_CODE_LENGTH}, + ExpansionMode, Keypair, MiniSecretKey, PublicKey, SecretKey, }; use sp_std::vec::Vec; @@ -47,7 +41,6 @@ use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_std::ops::Deref; -#[cfg(feature = "full_crypto")] use schnorrkel::keys::{MINI_SECRET_KEY_LENGTH, SECRET_KEY_LENGTH}; #[cfg(feature = "serde")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; @@ -56,14 +49,12 @@ use sp_runtime_interface::pass_by::PassByInner; use sp_std::alloc::{format, string::String}; // signing context -#[cfg(feature = "full_crypto")] const SIGNING_CTX: &[u8] = b"substrate"; /// An identifier used to match public keys against sr25519 keys pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"sr25"); /// An Schnorrkel/Ristretto x25519 ("sr25519") public key. -#[cfg_attr(feature = "full_crypto", derive(Hash))] #[derive( PartialEq, Eq, @@ -76,14 +67,13 @@ pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"sr25"); PassByInner, MaxEncodedLen, TypeInfo, + Hash, )] pub struct Public(pub [u8; 32]); /// An Schnorrkel/Ristretto x25519 ("sr25519") key pair. -#[cfg(feature = "full_crypto")] pub struct Pair(Keypair); -#[cfg(feature = "full_crypto")] impl Clone for Pair { fn clone(&self) -> Self { Pair(schnorrkel::Keypair { @@ -216,8 +206,7 @@ impl<'de> Deserialize<'de> for Public { } /// An Schnorrkel/Ristretto x25519 ("sr25519") signature. -#[cfg_attr(feature = "full_crypto", derive(Hash))] -#[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)] +#[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq, Hash)] pub struct Signature(pub [u8; 64]); impl TryFrom<&[u8]> for Signature { @@ -435,16 +424,13 @@ impl AsRef for Pair { } /// Derive a single hard junction. -#[cfg(feature = "full_crypto")] fn derive_hard_junction(secret: &SecretKey, cc: &[u8; CHAIN_CODE_LENGTH]) -> MiniSecretKey { secret.hard_derive_mini_secret_key(Some(ChainCode(*cc)), b"").0 } /// The raw secret seed, which can be used to recreate the `Pair`. -#[cfg(feature = "full_crypto")] type Seed = [u8; MINI_SECRET_KEY_LENGTH]; -#[cfg(feature = "full_crypto")] impl TraitPair for Pair { type Public = Public; type Seed = Seed; @@ -499,6 +485,7 @@ impl TraitPair for Pair { Ok((Self(result.into()), seed.map(|s| MiniSecretKey::to_bytes(&s)))) } + #[cfg(feature = "full_crypto")] fn sign(&self, message: &[u8]) -> Signature { let context = signing_context(SIGNING_CTX); self.0.sign(context.bytes(message)).into() @@ -533,16 +520,13 @@ impl Pair { } impl CryptoType for Public { - #[cfg(feature = "full_crypto")] type Pair = Pair; } impl CryptoType for Signature { - #[cfg(feature = "full_crypto")] type Pair = Pair; } -#[cfg(feature = "full_crypto")] impl CryptoType for Pair { type Pair = Pair; } diff --git a/substrate/primitives/keyring/Cargo.toml b/substrate/primitives/keyring/Cargo.toml index 1c936b6685b..940fe90916d 100644 --- a/substrate/primitives/keyring/Cargo.toml +++ b/substrate/primitives/keyring/Cargo.toml @@ -18,10 +18,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] strum = { version = "0.24.1", features = ["derive"], default-features = false } -sp-core = { path = "../core" } -sp-runtime = { path = "../runtime" } +sp-core = { path = "../core", default-features = false } +sp-runtime = { path = "../runtime", default-features = false } [features] +default = ["std"] +std = ["sp-core/std", "sp-runtime/std", "strum/std"] + # This feature adds Bandersnatch crypto primitives. # It should not be used in production since the implementation and interface may still # be subject to significant changes. diff --git a/substrate/primitives/keyring/check-features-variants.sh b/substrate/primitives/keyring/check-features-variants.sh new file mode 100755 index 00000000000..9c28d835894 --- /dev/null +++ b/substrate/primitives/keyring/check-features-variants.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env -S bash -eux + +export RUSTFLAGS="-Cdebug-assertions=y -Dwarnings" +T=wasm32-unknown-unknown + +cargo check --release +cargo check --release --features="bandersnatch-experimental" +cargo check --release --target=$T --no-default-features diff --git a/substrate/primitives/keyring/src/bandersnatch.rs b/substrate/primitives/keyring/src/bandersnatch.rs index eb60f856327..67fc5c47df6 100644 --- a/substrate/primitives/keyring/src/bandersnatch.rs +++ b/substrate/primitives/keyring/src/bandersnatch.rs @@ -18,14 +18,21 @@ //! A set of well-known keys used for testing. pub use sp_core::bandersnatch; +#[cfg(feature = "std")] +use sp_core::bandersnatch::Signature; use sp_core::{ - bandersnatch::{Pair, Public, Signature}, + bandersnatch::{Pair, Public}, crypto::UncheckedFrom, hex2array, ByteArray, Pair as PairT, }; +extern crate alloc; +use alloc::{fmt, format, str::FromStr, string::String, vec::Vec}; + /// Set of test accounts. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter)] +#[derive( + Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter, Ord, PartialOrd, +)] pub enum Keyring { Alice, Bob, @@ -56,6 +63,7 @@ impl Keyring { Public::from(self).to_raw_vec() } + #[cfg(feature = "std")] pub fn sign(self, msg: &[u8]) -> Signature { Pair::from(self).sign(msg) } @@ -102,16 +110,16 @@ impl From for &'static str { #[derive(Debug)] pub struct ParseKeyringError; -impl std::fmt::Display for ParseKeyringError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Display for ParseKeyringError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "ParseKeyringError") } } -impl std::str::FromStr for Keyring { +impl FromStr for Keyring { type Err = ParseKeyringError; - fn from_str(s: &str) -> Result::Err> { + fn from_str(s: &str) -> Result::Err> { match s { "Alice" => Ok(Keyring::Alice), "Bob" => Ok(Keyring::Bob), diff --git a/substrate/primitives/keyring/src/ed25519.rs b/substrate/primitives/keyring/src/ed25519.rs index ade42b29494..98ca368e53c 100644 --- a/substrate/primitives/keyring/src/ed25519.rs +++ b/substrate/primitives/keyring/src/ed25519.rs @@ -18,14 +18,21 @@ //! Support code for the runtime. A set of test accounts. pub use sp_core::ed25519; +#[cfg(feature = "std")] +use sp_core::ed25519::Signature; use sp_core::{ - ed25519::{Pair, Public, Signature}, + ed25519::{Pair, Public}, hex2array, ByteArray, Pair as PairT, H256, }; use sp_runtime::AccountId32; +extern crate alloc; +use alloc::{format, string::String, vec::Vec}; + /// Set of test accounts. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter)] +#[derive( + Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter, Ord, PartialOrd, +)] pub enum Keyring { Alice, Bob, @@ -76,6 +83,7 @@ impl Keyring { self.to_raw_public().into() } + #[cfg(feature = "std")] pub fn sign(self, msg: &[u8]) -> Signature { Pair::from(self).sign(msg) } diff --git a/substrate/primitives/keyring/src/lib.rs b/substrate/primitives/keyring/src/lib.rs index ee7fd56ba11..f753bf4b0dd 100644 --- a/substrate/primitives/keyring/src/lib.rs +++ b/substrate/primitives/keyring/src/lib.rs @@ -17,6 +17,8 @@ //! Support code for the runtime. A set of test accounts. +#![cfg_attr(not(feature = "std"), no_std)] + /// Test account crypto for sr25519. pub mod sr25519; diff --git a/substrate/primitives/keyring/src/sr25519.rs b/substrate/primitives/keyring/src/sr25519.rs index 1c2a2526efb..a3a506152d7 100644 --- a/substrate/primitives/keyring/src/sr25519.rs +++ b/substrate/primitives/keyring/src/sr25519.rs @@ -18,15 +18,22 @@ //! Support code for the runtime. A set of test accounts. pub use sp_core::sr25519; +#[cfg(feature = "std")] +use sp_core::sr25519::Signature; use sp_core::{ hex2array, - sr25519::{Pair, Public, Signature}, + sr25519::{Pair, Public}, ByteArray, Pair as PairT, H256, }; use sp_runtime::AccountId32; +extern crate alloc; +use alloc::{fmt, format, str::FromStr, string::String, vec::Vec}; + /// Set of test accounts. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter)] +#[derive( + Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter, Ord, PartialOrd, +)] pub enum Keyring { Alice, Bob, @@ -77,6 +84,7 @@ impl Keyring { self.to_raw_public().into() } + #[cfg(feature = "std")] pub fn sign(self, msg: &[u8]) -> Signature { Pair::from(self).sign(msg) } @@ -140,16 +148,16 @@ impl From for sp_runtime::MultiSigner { #[derive(Debug)] pub struct ParseKeyringError; -impl std::fmt::Display for ParseKeyringError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Display for ParseKeyringError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "ParseKeyringError") } } -impl std::str::FromStr for Keyring { +impl FromStr for Keyring { type Err = ParseKeyringError; - fn from_str(s: &str) -> Result::Err> { + fn from_str(s: &str) -> Result::Err> { match s { "alice" => Ok(Keyring::Alice), "bob" => Ok(Keyring::Bob), diff --git a/substrate/test-utils/runtime/Cargo.toml b/substrate/test-utils/runtime/Cargo.toml index 3bba5cd5bf0..b6e6346e801 100644 --- a/substrate/test-utils/runtime/Cargo.toml +++ b/substrate/test-utils/runtime/Cargo.toml @@ -24,9 +24,9 @@ sp-block-builder = { path = "../../primitives/block-builder", default-features = codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } sp-inherents = { path = "../../primitives/inherents", default-features = false } -sp-keyring = { path = "../../primitives/keyring", optional = true } +sp-keyring = { path = "../../primitives/keyring", default-features = false } sp-offchain = { path = "../../primitives/offchain", default-features = false } -sp-core = { path = "../../primitives/core", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false, features = ["serde"] } sp-crypto-hashing = { path = "../../primitives/crypto/hashing", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } sp-io = { path = "../../primitives/io", default-features = false } @@ -99,7 +99,7 @@ std = [ "sp-genesis-builder/std", "sp-inherents/std", "sp-io/std", - "sp-keyring", + "sp-keyring/std", "sp-offchain/std", "sp-runtime/std", "sp-session/std", -- GitLab From 82f3c3e2e81d3ea4b9bc35a14432d3ab93fb5b52 Mon Sep 17 00:00:00 2001 From: gupnik Date: Wed, 13 Mar 2024 12:31:01 +0530 Subject: [PATCH 032/187] Construct Runtime v2 (#1378) Moved from https://github.com/paritytech/substrate/pull/14788 ---- Fixes https://github.com/paritytech/polkadot-sdk/issues/232 This PR introduces outer-macro approach for `construct_runtime` as discussed in the linked issue. It looks like the following: ```rust #[frame_support::runtime] mod runtime { #[runtime::runtime] #[runtime::derive( RuntimeCall, RuntimeEvent, RuntimeError, RuntimeOrigin, RuntimeFreezeReason, RuntimeHoldReason, RuntimeSlashReason, RuntimeLockId, RuntimeTask, )] pub struct Runtime; #[runtime::pallet_index(0)] pub type System = frame_system; #[runtime::pallet_index(1)] pub type Timestamp = pallet_timestamp; #[runtime::pallet_index(2)] pub type Aura = pallet_aura; #[runtime::pallet_index(3)] pub type Grandpa = pallet_grandpa; #[runtime::pallet_index(4)] pub type Balances = pallet_balances; #[runtime::pallet_index(5)] pub type TransactionPayment = pallet_transaction_payment; #[runtime::pallet_index(6)] pub type Sudo = pallet_sudo; // Include the custom logic from the pallet-template in the runtime. #[runtime::pallet_index(7)] pub type TemplateModule = pallet_template; } ``` ## Features - `#[runtime::runtime]` attached to a struct defines the main runtime - `#[runtime::derive]` attached to this struct defines the types generated by runtime - `#[runtime::pallet_index]` must be attached to a pallet to define its index - `#[runtime::disable_call]` can be optionally attached to a pallet to disable its calls - `#[runtime::disable_unsigned]` can be optionally attached to a pallet to disable unsigned calls - A pallet instance can be defined as `TemplateModule: pallet_template` - An optional attribute can be defined as `#[frame_support::runtime(legacy_ordering)]` to ensure that the order of hooks is same as the order of pallets (and not based on the pallet_index). This is to support legacy runtimes and should be avoided for new ones. ## Todo - [x] Update the latest syntax in kitchensink and tests - [x] Update UI tests - [x] Docs ## Extension - Abstract away the Executive similar to https://github.com/paritytech/substrate/pull/14742 - Optionally avoid the need to specify all runtime types (TBD) --------- Co-authored-by: Francisco Aguirre Co-authored-by: Nikhil Gupta <> --- prdoc/pr_1378.prdoc | 27 + substrate/bin/node/runtime/Cargo.toml | 2 +- substrate/bin/node/runtime/src/lib.rs | 342 ++++-- substrate/frame/support/Cargo.toml | 4 +- substrate/frame/support/procedural/Cargo.toml | 1 + .../procedural/src/construct_runtime/mod.rs | 15 +- substrate/frame/support/procedural/src/lib.rs | 68 ++ .../src/pallet/expand/tt_default_parts.rs | 74 ++ .../procedural/src/pallet/parse/helper.rs | 6 + .../procedural/src/runtime/expand/mod.rs | 320 ++++++ .../support/procedural/src/runtime/mod.rs | 236 +++++ .../procedural/src/runtime/parse/helper.rs | 37 + .../procedural/src/runtime/parse/mod.rs | 266 +++++ .../procedural/src/runtime/parse/pallet.rs | 99 ++ .../src/runtime/parse/pallet_decl.rs | 60 ++ .../src/runtime/parse/runtime_struct.rs | 35 + .../src/runtime/parse/runtime_types.rs | 76 ++ substrate/frame/support/src/lib.rs | 3 + substrate/frame/support/test/Cargo.toml | 2 +- .../{construct_runtime.rs => runtime.rs} | 282 +++-- .../test/tests/runtime_legacy_ordering.rs | 993 ++++++++++++++++++ .../frame/support/test/tests/runtime_ui.rs | 36 + .../runtime_ui/can_only_be_attached_to_mod.rs | 21 + .../can_only_be_attached_to_mod.stderr | 5 + .../runtime_ui/conflicting_pallet_index.rs | 43 + .../conflicting_pallet_index.stderr | 11 + .../runtime_ui/conflicting_pallet_name.rs | 43 + .../runtime_ui/conflicting_pallet_name.stderr | 11 + .../tests/runtime_ui/invalid_attribute.rs | 23 + .../tests/runtime_ui/invalid_attribute.stderr | 5 + .../tests/runtime_ui/invalid_pallet_index.rs | 28 + .../runtime_ui/invalid_pallet_index.stderr | 5 + .../runtime_ui/invalid_runtime_type_derive.rs | 25 + .../invalid_runtime_type_derive.stderr | 5 + .../test/tests/runtime_ui/missing_runtime.rs | 21 + .../tests/runtime_ui/missing_runtime.stderr | 5 + .../missing_runtime_types_derive.rs | 24 + .../missing_runtime_types_derive.stderr | 5 + .../tests/runtime_ui/missing_system_pallet.rs | 25 + .../runtime_ui/missing_system_pallet.stderr | 5 + .../test/tests/runtime_ui/pass/basic.rs | 37 + .../test/tests/runtime_ui/runtime_struct.rs | 24 + .../tests/runtime_ui/runtime_struct.stderr | 5 + templates/solochain/runtime/Cargo.toml | 2 +- templates/solochain/runtime/src/lib.rs | 55 +- 45 files changed, 3212 insertions(+), 205 deletions(-) create mode 100644 prdoc/pr_1378.prdoc create mode 100644 substrate/frame/support/procedural/src/runtime/expand/mod.rs create mode 100644 substrate/frame/support/procedural/src/runtime/mod.rs create mode 100644 substrate/frame/support/procedural/src/runtime/parse/helper.rs create mode 100644 substrate/frame/support/procedural/src/runtime/parse/mod.rs create mode 100644 substrate/frame/support/procedural/src/runtime/parse/pallet.rs create mode 100644 substrate/frame/support/procedural/src/runtime/parse/pallet_decl.rs create mode 100644 substrate/frame/support/procedural/src/runtime/parse/runtime_struct.rs create mode 100644 substrate/frame/support/procedural/src/runtime/parse/runtime_types.rs rename substrate/frame/support/test/tests/{construct_runtime.rs => runtime.rs} (89%) create mode 100644 substrate/frame/support/test/tests/runtime_legacy_ordering.rs create mode 100644 substrate/frame/support/test/tests/runtime_ui.rs create mode 100644 substrate/frame/support/test/tests/runtime_ui/can_only_be_attached_to_mod.rs create mode 100644 substrate/frame/support/test/tests/runtime_ui/can_only_be_attached_to_mod.stderr create mode 100644 substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_index.rs create mode 100644 substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_index.stderr create mode 100644 substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_name.rs create mode 100644 substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_name.stderr create mode 100644 substrate/frame/support/test/tests/runtime_ui/invalid_attribute.rs create mode 100644 substrate/frame/support/test/tests/runtime_ui/invalid_attribute.stderr create mode 100644 substrate/frame/support/test/tests/runtime_ui/invalid_pallet_index.rs create mode 100644 substrate/frame/support/test/tests/runtime_ui/invalid_pallet_index.stderr create mode 100644 substrate/frame/support/test/tests/runtime_ui/invalid_runtime_type_derive.rs create mode 100644 substrate/frame/support/test/tests/runtime_ui/invalid_runtime_type_derive.stderr create mode 100644 substrate/frame/support/test/tests/runtime_ui/missing_runtime.rs create mode 100644 substrate/frame/support/test/tests/runtime_ui/missing_runtime.stderr create mode 100644 substrate/frame/support/test/tests/runtime_ui/missing_runtime_types_derive.rs create mode 100644 substrate/frame/support/test/tests/runtime_ui/missing_runtime_types_derive.stderr create mode 100644 substrate/frame/support/test/tests/runtime_ui/missing_system_pallet.rs create mode 100644 substrate/frame/support/test/tests/runtime_ui/missing_system_pallet.stderr create mode 100644 substrate/frame/support/test/tests/runtime_ui/pass/basic.rs create mode 100644 substrate/frame/support/test/tests/runtime_ui/runtime_struct.rs create mode 100644 substrate/frame/support/test/tests/runtime_ui/runtime_struct.stderr diff --git a/prdoc/pr_1378.prdoc b/prdoc/pr_1378.prdoc new file mode 100644 index 00000000000..6533dcb6630 --- /dev/null +++ b/prdoc/pr_1378.prdoc @@ -0,0 +1,27 @@ +title: Construct Runtime V2 - An outer macro approach to define the runtime + +doc: + - audience: Runtime Dev + description: | + Introduces `#[frame_support::runtime]` that can be attached to a mod to define a runtime. The items + in this mod can be attached to the following attributes to define the key components of the runtime. + 1. `#[runtime::runtime]` attached to a struct defines the main runtime + 2. `#[runtime::derive]` attached to the runtime struct defines the types generated by the runtime + 3. `#[runtime::pallet_index]` must be attached to a pallet to define its index + 4. `#[runtime::disable_call]` can be optionally attached to a pallet to disable its calls + 5. `#[runtime::disable_unsigned]` can be optionally attached to a pallet to disable unsigned calls + 6. A pallet instance can be defined as `TemplateModule: pallet_template` + An optional attribute can be defined as `#[frame_support::runtime(legacy_ordering)]` to ensure that + the order of hooks is same as the order of pallets (and not based on the pallet_index). This is to support + legacy runtimes and should be avoided for new ones. + +migrations: + db: [] + + runtime: [] + +crates: + - name: frame-support + - name: frame-support-procedural + +host_functions: [] diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index bdef42474d0..09c8fb4ed3d 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -58,7 +58,7 @@ sp-io = { path = "../../../primitives/io", default-features = false } frame-executive = { path = "../../../frame/executive", default-features = false } frame-benchmarking = { path = "../../../frame/benchmarking", default-features = false } frame-benchmarking-pallet-pov = { path = "../../../frame/benchmarking/pov", default-features = false } -frame-support = { path = "../../../frame/support", default-features = false, features = ["tuples-96"] } +frame-support = { path = "../../../frame/support", default-features = false, features = ["experimental", "tuples-96"] } frame-system = { path = "../../../frame/system", default-features = false } frame-system-benchmarking = { path = "../../../frame/system/benchmarking", default-features = false, optional = true } frame-election-provider-support = { path = "../../../frame/election-provider-support", default-features = false } diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 18ce13cff80..96611f5a144 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -28,7 +28,7 @@ use frame_election_provider_support::{ onchain, BalancingConfig, ElectionDataProvider, SequentialPhragmen, VoteWeight, }; use frame_support::{ - construct_runtime, derive_impl, + derive_impl, dispatch::DispatchClass, dynamic_params::{dynamic_pallet_params, dynamic_params}, genesis_builder_helper::{build_config, create_default_config}, @@ -2196,92 +2196,260 @@ impl pallet_parameters::Config for Runtime { type WeightInfo = (); } -construct_runtime!( - pub enum Runtime { - System: frame_system, - Utility: pallet_utility, - Babe: pallet_babe, - Timestamp: pallet_timestamp, - // Authorship must be before session in order to note author in the correct session and era - // for im-online and staking. - Authorship: pallet_authorship, - Indices: pallet_indices, - Balances: pallet_balances, - TransactionPayment: pallet_transaction_payment, - AssetTxPayment: pallet_asset_tx_payment, - AssetConversionTxPayment: pallet_asset_conversion_tx_payment, - ElectionProviderMultiPhase: pallet_election_provider_multi_phase, - Staking: pallet_staking, - Session: pallet_session, - Democracy: pallet_democracy, - Council: pallet_collective::, - TechnicalCommittee: pallet_collective::, - Elections: pallet_elections_phragmen, - TechnicalMembership: pallet_membership::, - Grandpa: pallet_grandpa, - Treasury: pallet_treasury, - AssetRate: pallet_asset_rate, - Contracts: pallet_contracts, - Sudo: pallet_sudo, - ImOnline: pallet_im_online, - AuthorityDiscovery: pallet_authority_discovery, - Offences: pallet_offences, - Historical: pallet_session_historical, - RandomnessCollectiveFlip: pallet_insecure_randomness_collective_flip, - Identity: pallet_identity, - Society: pallet_society, - Recovery: pallet_recovery, - Vesting: pallet_vesting, - Scheduler: pallet_scheduler, - Glutton: pallet_glutton, - Preimage: pallet_preimage, - Proxy: pallet_proxy, - Multisig: pallet_multisig, - Bounties: pallet_bounties, - Tips: pallet_tips, - Assets: pallet_assets::, - PoolAssets: pallet_assets::, - Beefy: pallet_beefy, - // MMR leaf construction must be after session in order to have a leaf's next_auth_set - // refer to block. See issue polkadot-fellows/runtimes#160 for details. - Mmr: pallet_mmr, - MmrLeaf: pallet_beefy_mmr, - Lottery: pallet_lottery, - Nis: pallet_nis, - Uniques: pallet_uniques, - Nfts: pallet_nfts, - NftFractionalization: pallet_nft_fractionalization, - Salary: pallet_salary, - CoreFellowship: pallet_core_fellowship, - TransactionStorage: pallet_transaction_storage, - VoterList: pallet_bags_list::, - StateTrieMigration: pallet_state_trie_migration, - ChildBounties: pallet_child_bounties, - Referenda: pallet_referenda, - Remark: pallet_remark, - RootTesting: pallet_root_testing, - ConvictionVoting: pallet_conviction_voting, - Whitelist: pallet_whitelist, - AllianceMotion: pallet_collective::, - Alliance: pallet_alliance, - NominationPools: pallet_nomination_pools, - RankedPolls: pallet_referenda::, - RankedCollective: pallet_ranked_collective, - AssetConversion: pallet_asset_conversion, - FastUnstake: pallet_fast_unstake, - MessageQueue: pallet_message_queue, - Pov: frame_benchmarking_pallet_pov, - TxPause: pallet_tx_pause, - SafeMode: pallet_safe_mode, - Statement: pallet_statement, - MultiBlockMigrations: pallet_migrations, - Broker: pallet_broker, - TasksExample: pallet_example_tasks, - Mixnet: pallet_mixnet, - Parameters: pallet_parameters, - SkipFeelessPayment: pallet_skip_feeless_payment, - } -); +#[frame_support::runtime] +mod runtime { + #[runtime::runtime] + #[runtime::derive( + RuntimeCall, + RuntimeEvent, + RuntimeError, + RuntimeOrigin, + RuntimeFreezeReason, + RuntimeHoldReason, + RuntimeSlashReason, + RuntimeLockId, + RuntimeTask + )] + pub struct Runtime; + + #[runtime::pallet_index(0)] + pub type System = frame_system; + + #[runtime::pallet_index(1)] + pub type Utility = pallet_utility; + + #[runtime::pallet_index(2)] + pub type Babe = pallet_babe; + + #[runtime::pallet_index(3)] + pub type Timestamp = pallet_timestamp; + + // Authorship must be before session in order to note author in the correct session and era + // for im-online and staking. + #[runtime::pallet_index(4)] + pub type Authorship = pallet_authorship; + + #[runtime::pallet_index(5)] + pub type Indices = pallet_indices; + + #[runtime::pallet_index(6)] + pub type Balances = pallet_balances; + + #[runtime::pallet_index(7)] + pub type TransactionPayment = pallet_transaction_payment; + + #[runtime::pallet_index(8)] + pub type AssetTxPayment = pallet_asset_tx_payment; + + #[runtime::pallet_index(9)] + pub type AssetConversionTxPayment = pallet_asset_conversion_tx_payment; + + #[runtime::pallet_index(10)] + pub type ElectionProviderMultiPhase = pallet_election_provider_multi_phase; + + #[runtime::pallet_index(11)] + pub type Staking = pallet_staking; + + #[runtime::pallet_index(12)] + pub type Session = pallet_session; + + #[runtime::pallet_index(13)] + pub type Democracy = pallet_democracy; + + #[runtime::pallet_index(14)] + pub type Council = pallet_collective; + + #[runtime::pallet_index(15)] + pub type TechnicalCommittee = pallet_collective; + + #[runtime::pallet_index(16)] + pub type Elections = pallet_elections_phragmen; + + #[runtime::pallet_index(17)] + pub type TechnicalMembership = pallet_membership; + + #[runtime::pallet_index(18)] + pub type Grandpa = pallet_grandpa; + + #[runtime::pallet_index(19)] + pub type Treasury = pallet_treasury; + + #[runtime::pallet_index(20)] + pub type AssetRate = pallet_asset_rate; + + #[runtime::pallet_index(21)] + pub type Contracts = pallet_contracts; + + #[runtime::pallet_index(22)] + pub type Sudo = pallet_sudo; + + #[runtime::pallet_index(23)] + pub type ImOnline = pallet_im_online; + + #[runtime::pallet_index(24)] + pub type AuthorityDiscovery = pallet_authority_discovery; + + #[runtime::pallet_index(25)] + pub type Offences = pallet_offences; + + #[runtime::pallet_index(26)] + pub type Historical = pallet_session_historical; + + #[runtime::pallet_index(27)] + pub type RandomnessCollectiveFlip = pallet_insecure_randomness_collective_flip; + + #[runtime::pallet_index(28)] + pub type Identity = pallet_identity; + + #[runtime::pallet_index(29)] + pub type Society = pallet_society; + + #[runtime::pallet_index(30)] + pub type Recovery = pallet_recovery; + + #[runtime::pallet_index(31)] + pub type Vesting = pallet_vesting; + + #[runtime::pallet_index(32)] + pub type Scheduler = pallet_scheduler; + + #[runtime::pallet_index(33)] + pub type Glutton = pallet_glutton; + + #[runtime::pallet_index(34)] + pub type Preimage = pallet_preimage; + + #[runtime::pallet_index(35)] + pub type Proxy = pallet_proxy; + + #[runtime::pallet_index(36)] + pub type Multisig = pallet_multisig; + + #[runtime::pallet_index(37)] + pub type Bounties = pallet_bounties; + + #[runtime::pallet_index(38)] + pub type Tips = pallet_tips; + + #[runtime::pallet_index(39)] + pub type Assets = pallet_assets; + + #[runtime::pallet_index(40)] + pub type PoolAssets = pallet_assets; + + #[runtime::pallet_index(41)] + pub type Beefy = pallet_beefy; + + // MMR leaf construction must be after session in order to have a leaf's next_auth_set + // refer to block. See issue polkadot-fellows/runtimes#160 for details. + #[runtime::pallet_index(42)] + pub type Mmr = pallet_mmr; + + #[runtime::pallet_index(43)] + pub type MmrLeaf = pallet_beefy_mmr; + + #[runtime::pallet_index(44)] + pub type Lottery = pallet_lottery; + + #[runtime::pallet_index(45)] + pub type Nis = pallet_nis; + + #[runtime::pallet_index(46)] + pub type Uniques = pallet_uniques; + + #[runtime::pallet_index(47)] + pub type Nfts = pallet_nfts; + + #[runtime::pallet_index(48)] + pub type NftFractionalization = pallet_nft_fractionalization; + + #[runtime::pallet_index(49)] + pub type Salary = pallet_salary; + + #[runtime::pallet_index(50)] + pub type CoreFellowship = pallet_core_fellowship; + + #[runtime::pallet_index(51)] + pub type TransactionStorage = pallet_transaction_storage; + + #[runtime::pallet_index(52)] + pub type VoterList = pallet_bags_list; + + #[runtime::pallet_index(53)] + pub type StateTrieMigration = pallet_state_trie_migration; + + #[runtime::pallet_index(54)] + pub type ChildBounties = pallet_child_bounties; + + #[runtime::pallet_index(55)] + pub type Referenda = pallet_referenda; + + #[runtime::pallet_index(56)] + pub type Remark = pallet_remark; + + #[runtime::pallet_index(57)] + pub type RootTesting = pallet_root_testing; + + #[runtime::pallet_index(58)] + pub type ConvictionVoting = pallet_conviction_voting; + + #[runtime::pallet_index(59)] + pub type Whitelist = pallet_whitelist; + + #[runtime::pallet_index(60)] + pub type AllianceMotion = pallet_collective; + + #[runtime::pallet_index(61)] + pub type Alliance = pallet_alliance; + + #[runtime::pallet_index(62)] + pub type NominationPools = pallet_nomination_pools; + + #[runtime::pallet_index(63)] + pub type RankedPolls = pallet_referenda; + + #[runtime::pallet_index(64)] + pub type RankedCollective = pallet_ranked_collective; + + #[runtime::pallet_index(65)] + pub type AssetConversion = pallet_asset_conversion; + + #[runtime::pallet_index(66)] + pub type FastUnstake = pallet_fast_unstake; + + #[runtime::pallet_index(67)] + pub type MessageQueue = pallet_message_queue; + + #[runtime::pallet_index(68)] + pub type Pov = frame_benchmarking_pallet_pov; + + #[runtime::pallet_index(69)] + pub type TxPause = pallet_tx_pause; + + #[runtime::pallet_index(70)] + pub type SafeMode = pallet_safe_mode; + + #[runtime::pallet_index(71)] + pub type Statement = pallet_statement; + + #[runtime::pallet_index(72)] + pub type MultiBlockMigrations = pallet_migrations; + + #[runtime::pallet_index(73)] + pub type Broker = pallet_broker; + + #[runtime::pallet_index(74)] + pub type TasksExample = pallet_example_tasks; + + #[runtime::pallet_index(75)] + pub type Mixnet = pallet_mixnet; + + #[runtime::pallet_index(76)] + pub type Parameters = pallet_parameters; + + #[runtime::pallet_index(77)] + pub type SkipFeelessPayment = pallet_skip_feeless_payment; +} /// The address format for describing accounts. pub type Address = sp_runtime::MultiAddress; diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index 113af41751e..be60068f122 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -109,7 +109,9 @@ try-runtime = [ "sp-debug-derive/force-debug", "sp-runtime/try-runtime", ] -experimental = [] +experimental = [ + "frame-support-procedural/experimental", +] # By default some types have documentation, `no-metadata-docs` allows to reduce the documentation # in the metadata. no-metadata-docs = [ diff --git a/substrate/frame/support/procedural/Cargo.toml b/substrate/frame/support/procedural/Cargo.toml index 85947503802..dd0688f2ad0 100644 --- a/substrate/frame/support/procedural/Cargo.toml +++ b/substrate/frame/support/procedural/Cargo.toml @@ -38,6 +38,7 @@ regex = "1" default = ["std"] std = ["sp-crypto-hashing/std"] no-metadata-docs = [] +experimental = [] # Generate impl-trait for tuples with the given number of tuples. Will be needed as the number of # pallets in a runtime grows. Does increase the compile time! tuples-96 = [] diff --git a/substrate/frame/support/procedural/src/construct_runtime/mod.rs b/substrate/frame/support/procedural/src/construct_runtime/mod.rs index 6e95fdf116a..1937dfa9ca4 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/mod.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/mod.rs @@ -208,8 +208,8 @@ //! This macro returns the ` :: expanded { Error }` list of additional parts we would like to //! expose. -mod expand; -mod parse; +pub(crate) mod expand; +pub(crate) mod parse; use crate::pallet::parse::helper::two128_str; use cfg_expr::Predicate; @@ -515,7 +515,7 @@ fn construct_runtime_final_expansion( Ok(res) } -fn decl_all_pallets<'a>( +pub(crate) fn decl_all_pallets<'a>( runtime: &'a Ident, pallet_declarations: impl Iterator, features: &HashSet<&str>, @@ -624,7 +624,8 @@ fn decl_all_pallets<'a>( #( #all_pallets_without_system )* ) } -fn decl_pallet_runtime_setup( + +pub(crate) fn decl_pallet_runtime_setup( runtime: &Ident, pallet_declarations: &[Pallet], scrate: &TokenStream2, @@ -730,7 +731,7 @@ fn decl_pallet_runtime_setup( ) } -fn decl_integrity_test(scrate: &TokenStream2) -> TokenStream2 { +pub(crate) fn decl_integrity_test(scrate: &TokenStream2) -> TokenStream2 { quote!( #[cfg(test)] mod __construct_runtime_integrity_test { @@ -745,7 +746,7 @@ fn decl_integrity_test(scrate: &TokenStream2) -> TokenStream2 { ) } -fn decl_static_assertions( +pub(crate) fn decl_static_assertions( runtime: &Ident, pallet_decls: &[Pallet], scrate: &TokenStream2, @@ -776,7 +777,7 @@ fn decl_static_assertions( } } -fn check_pallet_number(input: TokenStream2, pallet_num: usize) -> Result<()> { +pub(crate) fn check_pallet_number(input: TokenStream2, pallet_num: usize) -> Result<()> { let max_pallet_num = { if cfg!(feature = "tuples-96") { 96 diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index 89e39a5c9bb..dee6d522d25 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -31,6 +31,7 @@ mod match_and_insert; mod no_bound; mod pallet; mod pallet_error; +mod runtime; mod storage_alias; mod transactional; mod tt_macro; @@ -1220,6 +1221,73 @@ pub fn import_section(attr: TokenStream, tokens: TokenStream) -> TokenStream { .into() } +/// Construct a runtime, with the given name and the given pallets. +/// +/// # Example: +/// +/// ```ignore +/// #[frame_support::runtime] +/// mod runtime { +/// // The main runtime +/// #[runtime::runtime] +/// // Runtime Types to be generated +/// #[runtime::derive( +/// RuntimeCall, +/// RuntimeEvent, +/// RuntimeError, +/// RuntimeOrigin, +/// RuntimeFreezeReason, +/// RuntimeHoldReason, +/// RuntimeSlashReason, +/// RuntimeLockId, +/// RuntimeTask, +/// )] +/// pub struct Runtime; +/// +/// #[runtime::pallet_index(0)] +/// pub type System = frame_system; +/// +/// #[runtime::pallet_index(1)] +/// pub type Test = path::to::test; +/// +/// // Pallet with instance. +/// #[runtime::pallet_index(2)] +/// pub type Test2_Instance1 = test2; +/// +/// // Pallet with calls disabled. +/// #[runtime::pallet_index(3)] +/// #[runtime::disable_call] +/// pub type Test3 = test3; +/// +/// // Pallet with unsigned extrinsics disabled. +/// #[runtime::pallet_index(4)] +/// #[runtime::disable_unsigned] +/// pub type Test4 = test4; +/// } +/// ``` +/// +/// # Legacy Ordering +/// +/// An optional attribute can be defined as #[frame_support::runtime(legacy_ordering)] to +/// ensure that the order of hooks is same as the order of pallets (and not based on the +/// pallet_index). This is to support legacy runtimes and should be avoided for new ones. +/// +/// # Note +/// +/// The population of the genesis storage depends on the order of pallets. So, if one of your +/// pallets depends on another pallet, the pallet that is depended upon needs to come before +/// the pallet depending on it. +/// +/// # Type definitions +/// +/// * The macro generates a type alias for each pallet to their `Pallet`. E.g. `type System = +/// frame_system::Pallet` +#[cfg(feature = "experimental")] +#[proc_macro_attribute] +pub fn runtime(attr: TokenStream, item: TokenStream) -> TokenStream { + runtime::runtime(attr, item) +} + /// Mark a module that contains dynamic parameters. /// /// See the `pallet_parameters` for a full example. diff --git a/substrate/frame/support/procedural/src/pallet/expand/tt_default_parts.rs b/substrate/frame/support/procedural/src/pallet/expand/tt_default_parts.rs index 7cc1415dfdd..99364aaa96c 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/tt_default_parts.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/tt_default_parts.rs @@ -28,6 +28,8 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { syn::Ident::new(&format!("__tt_default_parts_{}", count), def.item.span()); let extra_parts_unique_id = syn::Ident::new(&format!("__tt_extra_parts_{}", count), def.item.span()); + let default_parts_unique_id_v2 = + syn::Ident::new(&format!("__tt_default_parts_v2_{}", count), def.item.span()); let call_part = def.call.as_ref().map(|_| quote::quote!(Call,)); @@ -81,6 +83,58 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { .any(|c| matches!(c.composite_keyword, CompositeKeyword::SlashReason(_))) .then_some(quote::quote!(SlashReason,)); + let call_part_v2 = def.call.as_ref().map(|_| quote::quote!(+ Call)); + + let task_part_v2 = def.task_enum.as_ref().map(|_| quote::quote!(+ Task)); + + let storage_part_v2 = (!def.storages.is_empty()).then(|| quote::quote!(+ Storage)); + + let event_part_v2 = def.event.as_ref().map(|event| { + let gen = event.gen_kind.is_generic().then(|| quote::quote!()); + quote::quote!(+ Event #gen) + }); + + let error_part_v2 = def.error.as_ref().map(|_| quote::quote!(+ Error)); + + let origin_part_v2 = def.origin.as_ref().map(|origin| { + let gen = origin.is_generic.then(|| quote::quote!()); + quote::quote!(+ Origin #gen) + }); + + let config_part_v2 = def.genesis_config.as_ref().map(|genesis_config| { + let gen = genesis_config.gen_kind.is_generic().then(|| quote::quote!()); + quote::quote!(+ Config #gen) + }); + + let inherent_part_v2 = def.inherent.as_ref().map(|_| quote::quote!(+ Inherent)); + + let validate_unsigned_part_v2 = + def.validate_unsigned.as_ref().map(|_| quote::quote!(+ ValidateUnsigned)); + + let freeze_reason_part_v2 = def + .composites + .iter() + .any(|c| matches!(c.composite_keyword, CompositeKeyword::FreezeReason(_))) + .then_some(quote::quote!(+ FreezeReason)); + + let hold_reason_part_v2 = def + .composites + .iter() + .any(|c| matches!(c.composite_keyword, CompositeKeyword::HoldReason(_))) + .then_some(quote::quote!(+ HoldReason)); + + let lock_id_part_v2 = def + .composites + .iter() + .any(|c| matches!(c.composite_keyword, CompositeKeyword::LockId(_))) + .then_some(quote::quote!(+ LockId)); + + let slash_reason_part_v2 = def + .composites + .iter() + .any(|c| matches!(c.composite_keyword, CompositeKeyword::SlashReason(_))) + .then_some(quote::quote!(+ SlashReason)); + quote::quote!( // This macro follows the conventions as laid out by the `tt-call` crate. It does not // accept any arguments and simply returns the pallet parts, separated by commas, then @@ -138,5 +192,25 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { } pub use #extra_parts_unique_id as tt_extra_parts; + + #[macro_export] + #[doc(hidden)] + macro_rules! #default_parts_unique_id_v2 { + { + $caller:tt + frame_support = [{ $($frame_support:ident)::* }] + } => { + $($frame_support)*::__private::tt_return! { + $caller + tokens = [{ + + Pallet #call_part_v2 #storage_part_v2 #event_part_v2 #error_part_v2 #origin_part_v2 #config_part_v2 + #inherent_part_v2 #validate_unsigned_part_v2 #freeze_reason_part_v2 #task_part_v2 + #hold_reason_part_v2 #lock_id_part_v2 #slash_reason_part_v2 + }] + } + }; + } + + pub use #default_parts_unique_id_v2 as tt_default_parts_v2; ) } diff --git a/substrate/frame/support/procedural/src/pallet/parse/helper.rs b/substrate/frame/support/procedural/src/pallet/parse/helper.rs index 538226a8745..3187c9139c8 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/helper.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/helper.rs @@ -148,6 +148,12 @@ impl MutItemAttrs for syn::ImplItemFn { } } +impl MutItemAttrs for syn::ItemType { + fn mut_item_attrs(&mut self) -> Option<&mut Vec> { + Some(&mut self.attrs) + } +} + /// Parse for `()` struct Unit; impl syn::parse::Parse for Unit { diff --git a/substrate/frame/support/procedural/src/runtime/expand/mod.rs b/substrate/frame/support/procedural/src/runtime/expand/mod.rs new file mode 100644 index 00000000000..93c88fce94b --- /dev/null +++ b/substrate/frame/support/procedural/src/runtime/expand/mod.rs @@ -0,0 +1,320 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::parse::runtime_types::RuntimeType; +use crate::{ + construct_runtime::{ + check_pallet_number, decl_all_pallets, decl_integrity_test, decl_pallet_runtime_setup, + decl_static_assertions, expand, + }, + runtime::{ + parse::{ + AllPalletsDeclaration, ExplicitAllPalletsDeclaration, ImplicitAllPalletsDeclaration, + }, + Def, + }, +}; +use cfg_expr::Predicate; +use frame_support_procedural_tools::{ + generate_access_from_frame_or_crate, generate_crate_access, generate_hidden_includes, +}; +use proc_macro2::TokenStream as TokenStream2; +use quote::quote; +use std::collections::HashSet; +use syn::{Ident, Result}; + +/// The fixed name of the system pallet. +const SYSTEM_PALLET_NAME: &str = "System"; + +pub fn expand(def: Def, legacy_ordering: bool) -> TokenStream2 { + let input = def.input; + + let (check_pallet_number_res, res) = match def.pallets { + AllPalletsDeclaration::Implicit(ref decl) => ( + check_pallet_number(input.clone(), decl.pallet_count), + construct_runtime_implicit_to_explicit(input.into(), decl.clone(), legacy_ordering), + ), + AllPalletsDeclaration::Explicit(ref decl) => ( + check_pallet_number(input, decl.pallets.len()), + construct_runtime_final_expansion( + def.runtime_struct.ident.clone(), + decl.clone(), + def.runtime_types.clone(), + legacy_ordering, + ), + ), + }; + + let res = res.unwrap_or_else(|e| e.to_compile_error()); + + // We want to provide better error messages to the user and thus, handle the error here + // separately. If there is an error, we print the error and still generate all of the code to + // get in overall less errors for the user. + let res = if let Err(error) = check_pallet_number_res { + let error = error.to_compile_error(); + + quote! { + #error + + #res + } + } else { + res + }; + + let res = expander::Expander::new("construct_runtime") + .dry(std::env::var("FRAME_EXPAND").is_err()) + .verbose(true) + .write_to_out_dir(res) + .expect("Does not fail because of IO in OUT_DIR; qed"); + + res.into() +} + +fn construct_runtime_implicit_to_explicit( + input: TokenStream2, + definition: ImplicitAllPalletsDeclaration, + legacy_ordering: bool, +) -> Result { + let frame_support = generate_access_from_frame_or_crate("frame-support")?; + let attr = if legacy_ordering { quote!((legacy_ordering)) } else { quote!() }; + let mut expansion = quote::quote!( + #[frame_support::runtime #attr] + #input + ); + for pallet in definition.pallet_decls.iter() { + let pallet_path = &pallet.path; + let pallet_name = &pallet.name; + let pallet_instance = pallet.instance.as_ref().map(|instance| quote::quote!(<#instance>)); + expansion = quote::quote!( + #frame_support::__private::tt_call! { + macro = [{ #pallet_path::tt_default_parts_v2 }] + frame_support = [{ #frame_support }] + ~~> #frame_support::match_and_insert! { + target = [{ #expansion }] + pattern = [{ #pallet_name = #pallet_path #pallet_instance }] + } + } + ); + } + + Ok(expansion) +} + +fn construct_runtime_final_expansion( + name: Ident, + definition: ExplicitAllPalletsDeclaration, + runtime_types: Vec, + legacy_ordering: bool, +) -> Result { + let ExplicitAllPalletsDeclaration { mut pallets, name: pallets_name } = definition; + + if !legacy_ordering { + // Ensure that order of hooks is based on the pallet index + pallets.sort_by_key(|p| p.index); + } + + let system_pallet = + pallets.iter().find(|decl| decl.name == SYSTEM_PALLET_NAME).ok_or_else(|| { + syn::Error::new( + pallets_name.span(), + "`System` pallet declaration is missing. \ + Please add this line: `pub type System = frame_system;`", + ) + })?; + if !system_pallet.cfg_pattern.is_empty() { + return Err(syn::Error::new( + system_pallet.name.span(), + "`System` pallet declaration is feature gated, please remove any `#[cfg]` attributes", + )) + } + + let features = pallets + .iter() + .filter_map(|decl| { + (!decl.cfg_pattern.is_empty()).then(|| { + decl.cfg_pattern.iter().flat_map(|attr| { + attr.predicates().filter_map(|pred| match pred { + Predicate::Feature(feat) => Some(feat), + Predicate::Test => Some("test"), + _ => None, + }) + }) + }) + }) + .flatten() + .collect::>(); + + let hidden_crate_name = "construct_runtime"; + let scrate = generate_crate_access(hidden_crate_name, "frame-support"); + let scrate_decl = generate_hidden_includes(hidden_crate_name, "frame-support"); + + let frame_system = generate_access_from_frame_or_crate("frame-system")?; + let block = quote!(<#name as #frame_system::Config>::Block); + let unchecked_extrinsic = quote!(<#block as #scrate::sp_runtime::traits::Block>::Extrinsic); + + let mut dispatch = None; + let mut outer_event = None; + let mut outer_error = None; + let mut outer_origin = None; + let mut freeze_reason = None; + let mut hold_reason = None; + let mut slash_reason = None; + let mut lock_id = None; + let mut task = None; + + for runtime_type in runtime_types.iter() { + match runtime_type { + RuntimeType::RuntimeCall(_) => { + dispatch = + Some(expand::expand_outer_dispatch(&name, system_pallet, &pallets, &scrate)); + }, + RuntimeType::RuntimeEvent(_) => { + outer_event = Some(expand::expand_outer_enum( + &name, + &pallets, + &scrate, + expand::OuterEnumType::Event, + )?); + }, + RuntimeType::RuntimeError(_) => { + outer_error = Some(expand::expand_outer_enum( + &name, + &pallets, + &scrate, + expand::OuterEnumType::Error, + )?); + }, + RuntimeType::RuntimeOrigin(_) => { + outer_origin = + Some(expand::expand_outer_origin(&name, system_pallet, &pallets, &scrate)?); + }, + RuntimeType::RuntimeFreezeReason(_) => { + freeze_reason = Some(expand::expand_outer_freeze_reason(&pallets, &scrate)); + }, + RuntimeType::RuntimeHoldReason(_) => { + hold_reason = Some(expand::expand_outer_hold_reason(&pallets, &scrate)); + }, + RuntimeType::RuntimeSlashReason(_) => { + slash_reason = Some(expand::expand_outer_slash_reason(&pallets, &scrate)); + }, + RuntimeType::RuntimeLockId(_) => { + lock_id = Some(expand::expand_outer_lock_id(&pallets, &scrate)); + }, + RuntimeType::RuntimeTask(_) => { + task = Some(expand::expand_outer_task(&name, &pallets, &scrate)); + }, + } + } + + let all_pallets = decl_all_pallets(&name, pallets.iter(), &features); + let pallet_to_index = decl_pallet_runtime_setup(&name, &pallets, &scrate); + + let metadata = expand::expand_runtime_metadata( + &name, + &pallets, + &scrate, + &unchecked_extrinsic, + &system_pallet.path, + ); + let outer_config = expand::expand_outer_config(&name, &pallets, &scrate); + let inherent = + expand::expand_outer_inherent(&name, &block, &unchecked_extrinsic, &pallets, &scrate); + let validate_unsigned = expand::expand_outer_validate_unsigned(&name, &pallets, &scrate); + let integrity_test = decl_integrity_test(&scrate); + let static_assertions = decl_static_assertions(&name, &pallets, &scrate); + + let res = quote!( + #scrate_decl + + // Prevent UncheckedExtrinsic to print unused warning. + const _: () = { + #[allow(unused)] + type __hidden_use_of_unchecked_extrinsic = #unchecked_extrinsic; + }; + + #[derive( + Clone, Copy, PartialEq, Eq, #scrate::sp_runtime::RuntimeDebug, + #scrate::__private::scale_info::TypeInfo + )] + pub struct #name; + impl #scrate::sp_runtime::traits::GetRuntimeBlockType for #name { + type RuntimeBlock = #block; + } + + // Each runtime must expose the `runtime_metadata()` to fetch the runtime API metadata. + // The function is implemented by calling `impl_runtime_apis!`. + // + // However, the `runtime` may be used without calling `impl_runtime_apis!`. + // Rely on the `Deref` trait to differentiate between a runtime that implements + // APIs (by macro impl_runtime_apis!) and a runtime that is simply created (by macro runtime). + // + // Both `InternalConstructRuntime` and `InternalImplRuntimeApis` expose a `runtime_metadata()` function. + // `InternalConstructRuntime` is implemented by the `runtime` for Runtime references (`& Runtime`), + // while `InternalImplRuntimeApis` is implemented by the `impl_runtime_apis!` for Runtime (`Runtime`). + // + // Therefore, the `Deref` trait will resolve the `runtime_metadata` from `impl_runtime_apis!` + // when both macros are called; and will resolve an empty `runtime_metadata` when only the `runtime` + // is used. + + #[doc(hidden)] + trait InternalConstructRuntime { + #[inline(always)] + fn runtime_metadata(&self) -> #scrate::__private::sp_std::vec::Vec<#scrate::__private::metadata_ir::RuntimeApiMetadataIR> { + Default::default() + } + } + #[doc(hidden)] + impl InternalConstructRuntime for &#name {} + + #outer_event + + #outer_error + + #outer_origin + + #all_pallets + + #pallet_to_index + + #dispatch + + #task + + #metadata + + #outer_config + + #inherent + + #validate_unsigned + + #freeze_reason + + #hold_reason + + #lock_id + + #slash_reason + + #integrity_test + + #static_assertions + ); + + Ok(res) +} diff --git a/substrate/frame/support/procedural/src/runtime/mod.rs b/substrate/frame/support/procedural/src/runtime/mod.rs new file mode 100644 index 00000000000..aaae579eb08 --- /dev/null +++ b/substrate/frame/support/procedural/src/runtime/mod.rs @@ -0,0 +1,236 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Implementation of `runtime`. +//! +//! `runtime` implementation is recursive and can generate code which will call itself +//! in order to get all the pallet parts for each pallet. +//! +//! Pallets can define their parts: +//! - Implicitly: `pub type System = frame_system;` +//! - Explicitly: `pub type System = frame_system + Pallet + Call;` +//! +//! The `runtime` transitions from the implicit definition to the explicit one. +//! From the explicit state, Substrate expands the pallets with additional information +//! that is to be included in the runtime metadata. +//! +//! Pallets must provide the `tt_default_parts_v2` macro for these transitions. +//! These are automatically implemented by the `#[pallet::pallet]` macro. +//! +//! This macro also generates the following enums for ease of decoding if the respective type +//! is defined inside `#[runtime::derive]`: +//! - `enum RuntimeCall`: This type contains the information needed to decode extrinsics. +//! - `enum RuntimeEvent`: This type contains the information needed to decode events. +//! - `enum RuntimeError`: While this cannot be used directly to decode `sp_runtime::DispatchError` +//! from the chain, it contains the information needed to decode the +//! `sp_runtime::DispatchError::Module`. +//! +//! # State Transitions +//! +//! ```ignore +//! +----------+ +//! | Implicit | +//! +----------+ +//! | +//! v +//! +----------+ +//! | Explicit | +//! +----------+ +//! ``` +//! +//! The `runtime` macro transforms the implicit declaration of each pallet +//! `System: frame_system` to an explicit one `System: frame_system + Pallet + Call` using the +//! `tt_default_parts_v2` macro. +//! +//! The `tt_default_parts_v2` macro exposes a plus separated list of pallet parts. For example, the +//! `Event` part is exposed only if the pallet implements an event via `#[pallet::event]` macro. +//! The tokens generated by this macro are `+ Pallet + Call` for our example. +//! +//! The `match_and_insert` macro takes in 3 arguments: +//! - target: This is the `TokenStream` that contains the `runtime` macro. +//! - pattern: The pattern to match against in the target stream. +//! - tokens: The tokens to added after the pattern match. +//! +//! The `runtime` macro uses the `tt_call` to get the default pallet parts via +//! the `tt_default_parts_v2` macro defined by each pallet. The pallet parts are then returned as +//! input to the `match_and_replace` macro. +//! The `match_and_replace` then will modify the `runtime` to expand the implicit +//! definition to the explicit one. +//! +//! For example, +//! +//! ```ignore +//! #[frame_support::runtime] +//! mod runtime { +//! //... +//! +//! #[runtime::pallet_index(0)] +//! pub type System = frame_system; // Implicit definition of parts +//! +//! #[runtime::pallet_index(1)] +//! pub type Balances = pallet_balances; // Implicit definition of parts +//! } +//! ``` +//! This call has some implicit pallet parts, thus it will expand to: +//! ```ignore +//! frame_support::__private::tt_call! { +//! macro = [{ pallet_balances::tt_default_parts_v2 }] +//! ~~> frame_support::match_and_insert! { +//! target = [{ +//! frame_support::__private::tt_call! { +//! macro = [{ frame_system::tt_default_parts_v2 }] +//! ~~> frame_support::match_and_insert! { +//! target = [{ +//! #[frame_support::runtime] +//! mod runtime { +//! //... +//! +//! #[runtime::pallet_index(0)] +//! pub type System = frame_system; +//! +//! #[runtime::pallet_index(1)] +//! pub type Balances = pallet_balances; +//! } +//! }] +//! pattern = [{ System = frame_system }] +//! } +//! } +//! }] +//! pattern = [{ Balances = pallet_balances }] +//! } +//! } +//! ``` +//! `tt_default_parts_v2` must be defined. It returns the pallet parts inside some tokens, and +//! then `tt_call` will pipe the returned pallet parts into the input of `match_and_insert`. +//! Thus `match_and_insert` will initially receive the following inputs: +//! ```ignore +//! frame_support::match_and_insert! { +//! target = [{ +//! frame_support::match_and_insert! { +//! target = [{ +//! #[frame_support::runtime] +//! mod runtime { +//! //... +//! +//! #[runtime::pallet_index(0)] +//! pub type System = frame_system; +//! +//! #[runtime::pallet_index(1)] +//! pub type Balances = pallet_balances; +//! } +//! }] +//! pattern = [{ System = frame_system }] +//! tokens = [{ ::{+ Pallet + Call} }] +//! } +//! }] +//! pattern = [{ Balances = pallet_balances }] +//! tokens = [{ ::{+ Pallet + Call} }] +//! } +//! ``` +//! After dealing with `pallet_balances`, the inner `match_and_insert` will expand to: +//! ```ignore +//! frame_support::match_and_insert! { +//! target = [{ +//! #[frame_support::runtime] +//! mod runtime { +//! //... +//! +//! #[runtime::pallet_index(0)] +//! pub type System = frame_system; // Implicit definition of parts +//! +//! #[runtime::pallet_index(1)] +//! pub type Balances = pallet_balances + Pallet + Call; // Explicit definition of parts +//! } +//! }] +//! pattern = [{ System = frame_system }] +//! tokens = [{ ::{+ Pallet + Call} }] +//! } +//! ``` +//! +//! Which will then finally expand to the following: +//! ```ignore +//! #[frame_support::runtime] +//! mod runtime { +//! //... +//! +//! #[runtime::pallet_index(0)] +//! pub type System = frame_system + Pallet + Call; +//! +//! #[runtime::pallet_index(1)] +//! pub type Balances = pallet_balances + Pallet + Call; +//! } +//! ``` +//! +//! This call has no implicit pallet parts, thus it will expand to the runtime construction: +//! ```ignore +//! pub struct Runtime { ... } +//! pub struct Call { ... } +//! impl Call ... +//! pub enum Origin { ... } +//! ... +//! ``` +//! +//! Visualizing the entire flow of `#[frame_support::runtime]`, it would look like the following: +//! +//! ```ignore +//! +----------------------+ +------------------------+ +-------------------+ +//! | | | (defined in pallet) | | | +//! | runtime | --> | tt_default_parts_v2! | --> | match_and_insert! | +//! | w/ no pallet parts | | | | | +//! +----------------------+ +------------------------+ +-------------------+ +//! +//! +----------------------+ +//! | | +//! --> | runtime | +//! | w/ pallet parts | +//! +----------------------+ +//! ``` + +#![cfg(feature = "experimental")] + +pub use parse::Def; +use proc_macro::TokenStream; +use syn::spanned::Spanned; + +mod expand; +mod parse; + +mod keyword { + syn::custom_keyword!(legacy_ordering); +} + +pub fn runtime(attr: TokenStream, tokens: TokenStream) -> TokenStream { + let mut legacy_ordering = false; + if !attr.is_empty() { + if let Ok(_) = syn::parse::(attr.clone()) { + legacy_ordering = true; + } else { + let msg = "Invalid runtime macro call: unexpected attribute. Macro call must be \ + bare, such as `#[frame_support::runtime]` or `#[runtime]`, or must specify the \ + `legacy_ordering` attribute, such as `#[frame_support::runtime(legacy_ordering)]` or \ + #[runtime(legacy_ordering)]."; + let span = proc_macro2::TokenStream::from(attr).span(); + return syn::Error::new(span, msg).to_compile_error().into() + } + } + + let item = syn::parse_macro_input!(tokens as syn::ItemMod); + match parse::Def::try_from(item) { + Ok(def) => expand::expand(def, legacy_ordering).into(), + Err(e) => e.to_compile_error().into(), + } +} diff --git a/substrate/frame/support/procedural/src/runtime/parse/helper.rs b/substrate/frame/support/procedural/src/runtime/parse/helper.rs new file mode 100644 index 00000000000..f05395f9b7a --- /dev/null +++ b/substrate/frame/support/procedural/src/runtime/parse/helper.rs @@ -0,0 +1,37 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::pallet::parse::helper::MutItemAttrs; +use quote::ToTokens; + +pub(crate) fn take_first_item_runtime_attr( + item: &mut impl MutItemAttrs, +) -> syn::Result> +where + Attr: syn::parse::Parse, +{ + let attrs = if let Some(attrs) = item.mut_item_attrs() { attrs } else { return Ok(None) }; + + if let Some(index) = attrs.iter().position(|attr| { + attr.path().segments.first().map_or(false, |segment| segment.ident == "runtime") + }) { + let runtime_attr = attrs.remove(index); + Ok(Some(syn::parse2(runtime_attr.into_token_stream())?)) + } else { + Ok(None) + } +} diff --git a/substrate/frame/support/procedural/src/runtime/parse/mod.rs b/substrate/frame/support/procedural/src/runtime/parse/mod.rs new file mode 100644 index 00000000000..893cb4726e2 --- /dev/null +++ b/substrate/frame/support/procedural/src/runtime/parse/mod.rs @@ -0,0 +1,266 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +pub mod helper; +pub mod pallet; +pub mod pallet_decl; +pub mod runtime_struct; +pub mod runtime_types; + +use crate::construct_runtime::parse::Pallet; +use pallet_decl::PalletDeclaration; +use proc_macro2::TokenStream as TokenStream2; +use quote::ToTokens; +use std::collections::HashMap; +use syn::{spanned::Spanned, Ident, Token}; + +use frame_support_procedural_tools::syn_ext as ext; +use runtime_types::RuntimeType; + +mod keyword { + use syn::custom_keyword; + + custom_keyword!(runtime); + custom_keyword!(derive); + custom_keyword!(pallet_index); + custom_keyword!(disable_call); + custom_keyword!(disable_unsigned); +} + +enum RuntimeAttr { + Runtime(proc_macro2::Span), + Derive(proc_macro2::Span, Vec), + PalletIndex(proc_macro2::Span, u8), + DisableCall(proc_macro2::Span), + DisableUnsigned(proc_macro2::Span), +} + +impl RuntimeAttr { + fn span(&self) -> proc_macro2::Span { + match self { + Self::Runtime(span) => *span, + Self::Derive(span, _) => *span, + Self::PalletIndex(span, _) => *span, + Self::DisableCall(span) => *span, + Self::DisableUnsigned(span) => *span, + } + } +} + +impl syn::parse::Parse for RuntimeAttr { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + input.parse::()?; + let content; + syn::bracketed!(content in input); + content.parse::()?; + content.parse::()?; + + let lookahead = content.lookahead1(); + if lookahead.peek(keyword::runtime) { + Ok(RuntimeAttr::Runtime(content.parse::()?.span())) + } else if lookahead.peek(keyword::derive) { + let _ = content.parse::(); + let derive_content; + syn::parenthesized!(derive_content in content); + let runtime_types = + derive_content.parse::>()?; + let runtime_types = runtime_types.inner.into_iter().collect(); + Ok(RuntimeAttr::Derive(derive_content.span(), runtime_types)) + } else if lookahead.peek(keyword::pallet_index) { + let _ = content.parse::(); + let pallet_index_content; + syn::parenthesized!(pallet_index_content in content); + let pallet_index = pallet_index_content.parse::()?; + if !pallet_index.suffix().is_empty() { + let msg = "Number literal must not have a suffix"; + return Err(syn::Error::new(pallet_index.span(), msg)) + } + Ok(RuntimeAttr::PalletIndex(pallet_index.span(), pallet_index.base10_parse()?)) + } else if lookahead.peek(keyword::disable_call) { + Ok(RuntimeAttr::DisableCall(content.parse::()?.span())) + } else if lookahead.peek(keyword::disable_unsigned) { + Ok(RuntimeAttr::DisableUnsigned(content.parse::()?.span())) + } else { + Err(lookahead.error()) + } + } +} + +#[derive(Debug, Clone)] +pub enum AllPalletsDeclaration { + Implicit(ImplicitAllPalletsDeclaration), + Explicit(ExplicitAllPalletsDeclaration), +} + +/// Declaration of a runtime with some pallet with implicit declaration of parts. +#[derive(Debug, Clone)] +pub struct ImplicitAllPalletsDeclaration { + pub name: Ident, + pub pallet_decls: Vec, + pub pallet_count: usize, +} + +/// Declaration of a runtime with all pallet having explicit declaration of parts. +#[derive(Debug, Clone)] +pub struct ExplicitAllPalletsDeclaration { + pub name: Ident, + pub pallets: Vec, +} + +pub struct Def { + pub input: TokenStream2, + pub item: syn::ItemMod, + pub runtime_struct: runtime_struct::RuntimeStructDef, + pub pallets: AllPalletsDeclaration, + pub runtime_types: Vec, +} + +impl Def { + pub fn try_from(mut item: syn::ItemMod) -> syn::Result { + let input: TokenStream2 = item.to_token_stream().into(); + let item_span = item.span(); + let items = &mut item + .content + .as_mut() + .ok_or_else(|| { + let msg = "Invalid runtime definition, expected mod to be inlined."; + syn::Error::new(item_span, msg) + })? + .1; + + let mut runtime_struct = None; + let mut runtime_types = None; + + let mut indices = HashMap::new(); + let mut names = HashMap::new(); + + let mut pallet_decls = vec![]; + let mut pallets = vec![]; + + for item in items.iter_mut() { + let mut pallet_item = None; + let mut pallet_index = 0; + + let mut disable_call = false; + let mut disable_unsigned = false; + + while let Some(runtime_attr) = + helper::take_first_item_runtime_attr::(item)? + { + match runtime_attr { + RuntimeAttr::Runtime(span) if runtime_struct.is_none() => { + let p = runtime_struct::RuntimeStructDef::try_from(span, item)?; + runtime_struct = Some(p); + }, + RuntimeAttr::Derive(_, types) if runtime_types.is_none() => { + runtime_types = Some(types); + }, + RuntimeAttr::PalletIndex(span, index) => { + pallet_index = index; + pallet_item = if let syn::Item::Type(item) = item { + Some(item.clone()) + } else { + let msg = "Invalid runtime::pallet_index, expected type definition"; + return Err(syn::Error::new(span, msg)) + }; + }, + RuntimeAttr::DisableCall(_) => disable_call = true, + RuntimeAttr::DisableUnsigned(_) => disable_unsigned = true, + attr => { + let msg = "Invalid duplicated attribute"; + return Err(syn::Error::new(attr.span(), msg)) + }, + } + } + + if let Some(pallet_item) = pallet_item { + match *pallet_item.ty.clone() { + syn::Type::Path(ref path) => { + let pallet_decl = + PalletDeclaration::try_from(item.span(), &pallet_item, path)?; + + if let Some(used_pallet) = + names.insert(pallet_decl.name.clone(), pallet_decl.name.span()) + { + let msg = "Two pallets with the same name!"; + + let mut err = syn::Error::new(used_pallet, &msg); + err.combine(syn::Error::new(pallet_decl.name.span(), &msg)); + return Err(err) + } + + pallet_decls.push(pallet_decl); + }, + syn::Type::TraitObject(syn::TypeTraitObject { bounds, .. }) => { + let pallet = Pallet::try_from( + item.span(), + &pallet_item, + pallet_index, + disable_call, + disable_unsigned, + &bounds, + )?; + + if let Some(used_pallet) = indices.insert(pallet.index, pallet.name.clone()) + { + let msg = format!( + "Pallet indices are conflicting: Both pallets {} and {} are at index {}", + used_pallet, pallet.name, pallet.index, + ); + let mut err = syn::Error::new(used_pallet.span(), &msg); + err.combine(syn::Error::new(pallet.name.span(), msg)); + return Err(err) + } + + pallets.push(pallet); + }, + _ => continue, + } + } + } + + let name = item.ident.clone(); + let decl_count = pallet_decls.len(); + let pallets = if decl_count > 0 { + AllPalletsDeclaration::Implicit(ImplicitAllPalletsDeclaration { + name, + pallet_decls, + pallet_count: decl_count.saturating_add(pallets.len()), + }) + } else { + AllPalletsDeclaration::Explicit(ExplicitAllPalletsDeclaration { name, pallets }) + }; + + let def = Def { + input, + item, + runtime_struct: runtime_struct.ok_or_else(|| { + syn::Error::new(item_span, + "Missing Runtime. Please add a struct inside the module and annotate it with `#[runtime::runtime]`" + ) + })?, + pallets, + runtime_types: runtime_types.ok_or_else(|| { + syn::Error::new(item_span, + "Missing Runtime Types. Please annotate the runtime struct with `#[runtime::derive]`" + ) + })?, + }; + + Ok(def) + } +} diff --git a/substrate/frame/support/procedural/src/runtime/parse/pallet.rs b/substrate/frame/support/procedural/src/runtime/parse/pallet.rs new file mode 100644 index 00000000000..d2f1857fb2b --- /dev/null +++ b/substrate/frame/support/procedural/src/runtime/parse/pallet.rs @@ -0,0 +1,99 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::construct_runtime::parse::{Pallet, PalletPart, PalletPartKeyword, PalletPath}; +use quote::ToTokens; +use syn::{punctuated::Punctuated, spanned::Spanned, token, Error, Ident, PathArguments}; + +impl Pallet { + pub fn try_from( + attr_span: proc_macro2::Span, + item: &syn::ItemType, + pallet_index: u8, + disable_call: bool, + disable_unsigned: bool, + bounds: &Punctuated, + ) -> syn::Result { + let name = item.ident.clone(); + + let mut pallet_path = None; + let mut pallet_parts = vec![]; + + for (index, bound) in bounds.into_iter().enumerate() { + if let syn::TypeParamBound::Trait(syn::TraitBound { path, .. }) = bound { + if index == 0 { + pallet_path = Some(PalletPath { inner: path.clone() }); + } else { + let pallet_part = syn::parse2::(bound.into_token_stream())?; + pallet_parts.push(pallet_part); + } + } else { + return Err(Error::new( + attr_span, + "Invalid pallet declaration, expected a path or a trait object", + )) + }; + } + + let mut path = pallet_path.ok_or(Error::new( + attr_span, + "Invalid pallet declaration, expected a path or a trait object", + ))?; + + let mut instance = None; + if let Some(segment) = path.inner.segments.iter_mut().find(|seg| !seg.arguments.is_empty()) + { + if let PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { + args, .. + }) = segment.arguments.clone() + { + if let Some(syn::GenericArgument::Type(syn::Type::Path(arg_path))) = args.first() { + instance = + Some(Ident::new(&arg_path.to_token_stream().to_string(), arg_path.span())); + segment.arguments = PathArguments::None; + } + } + } + + pallet_parts = pallet_parts + .into_iter() + .filter(|part| { + if let (true, &PalletPartKeyword::Call(_)) = (disable_call, &part.keyword) { + false + } else if let (true, &PalletPartKeyword::ValidateUnsigned(_)) = + (disable_unsigned, &part.keyword) + { + false + } else { + true + } + }) + .collect(); + + let cfg_pattern = vec![]; + + Ok(Pallet { + is_expanded: true, + name, + index: pallet_index, + path, + instance, + cfg_pattern, + pallet_parts, + }) + } +} diff --git a/substrate/frame/support/procedural/src/runtime/parse/pallet_decl.rs b/substrate/frame/support/procedural/src/runtime/parse/pallet_decl.rs new file mode 100644 index 00000000000..437a163cfbc --- /dev/null +++ b/substrate/frame/support/procedural/src/runtime/parse/pallet_decl.rs @@ -0,0 +1,60 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use quote::ToTokens; +use syn::{spanned::Spanned, Attribute, Ident, PathArguments}; + +/// The declaration of a pallet. +#[derive(Debug, Clone)] +pub struct PalletDeclaration { + /// The name of the pallet, e.g.`System` in `System: frame_system`. + pub name: Ident, + /// Optional attributes tagged right above a pallet declaration. + pub attrs: Vec, + /// The path of the pallet, e.g. `frame_system` in `System: frame_system`. + pub path: syn::Path, + /// The instance of the pallet, e.g. `Instance1` in `Council: pallet_collective::`. + pub instance: Option, +} + +impl PalletDeclaration { + pub fn try_from( + _attr_span: proc_macro2::Span, + item: &syn::ItemType, + path: &syn::TypePath, + ) -> syn::Result { + let name = item.ident.clone(); + + let mut path = path.path.clone(); + + let mut instance = None; + if let Some(segment) = path.segments.iter_mut().find(|seg| !seg.arguments.is_empty()) { + if let PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { + args, .. + }) = segment.arguments.clone() + { + if let Some(syn::GenericArgument::Type(syn::Type::Path(arg_path))) = args.first() { + instance = + Some(Ident::new(&arg_path.to_token_stream().to_string(), arg_path.span())); + segment.arguments = PathArguments::None; + } + } + } + + Ok(Self { name, path, instance, attrs: item.attrs.clone() }) + } +} diff --git a/substrate/frame/support/procedural/src/runtime/parse/runtime_struct.rs b/substrate/frame/support/procedural/src/runtime/parse/runtime_struct.rs new file mode 100644 index 00000000000..8fa746ee807 --- /dev/null +++ b/substrate/frame/support/procedural/src/runtime/parse/runtime_struct.rs @@ -0,0 +1,35 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use syn::spanned::Spanned; +pub struct RuntimeStructDef { + pub ident: syn::Ident, + pub attr_span: proc_macro2::Span, +} + +impl RuntimeStructDef { + pub fn try_from(attr_span: proc_macro2::Span, item: &mut syn::Item) -> syn::Result { + let item = if let syn::Item::Struct(item) = item { + item + } else { + let msg = "Invalid runtime::runtime, expected struct definition"; + return Err(syn::Error::new(item.span(), msg)) + }; + + Ok(Self { ident: item.ident.clone(), attr_span }) + } +} diff --git a/substrate/frame/support/procedural/src/runtime/parse/runtime_types.rs b/substrate/frame/support/procedural/src/runtime/parse/runtime_types.rs new file mode 100644 index 00000000000..a4480e2a1fd --- /dev/null +++ b/substrate/frame/support/procedural/src/runtime/parse/runtime_types.rs @@ -0,0 +1,76 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use syn::{ + parse::{Parse, ParseStream}, + Result, +}; + +mod keyword { + use syn::custom_keyword; + + custom_keyword!(RuntimeCall); + custom_keyword!(RuntimeEvent); + custom_keyword!(RuntimeError); + custom_keyword!(RuntimeOrigin); + custom_keyword!(RuntimeFreezeReason); + custom_keyword!(RuntimeHoldReason); + custom_keyword!(RuntimeSlashReason); + custom_keyword!(RuntimeLockId); + custom_keyword!(RuntimeTask); +} + +#[derive(Debug, Clone, PartialEq)] +pub enum RuntimeType { + RuntimeCall(keyword::RuntimeCall), + RuntimeEvent(keyword::RuntimeEvent), + RuntimeError(keyword::RuntimeError), + RuntimeOrigin(keyword::RuntimeOrigin), + RuntimeFreezeReason(keyword::RuntimeFreezeReason), + RuntimeHoldReason(keyword::RuntimeHoldReason), + RuntimeSlashReason(keyword::RuntimeSlashReason), + RuntimeLockId(keyword::RuntimeLockId), + RuntimeTask(keyword::RuntimeTask), +} + +impl Parse for RuntimeType { + fn parse(input: ParseStream) -> Result { + let lookahead = input.lookahead1(); + + if lookahead.peek(keyword::RuntimeCall) { + Ok(Self::RuntimeCall(input.parse()?)) + } else if lookahead.peek(keyword::RuntimeEvent) { + Ok(Self::RuntimeEvent(input.parse()?)) + } else if lookahead.peek(keyword::RuntimeError) { + Ok(Self::RuntimeError(input.parse()?)) + } else if lookahead.peek(keyword::RuntimeOrigin) { + Ok(Self::RuntimeOrigin(input.parse()?)) + } else if lookahead.peek(keyword::RuntimeFreezeReason) { + Ok(Self::RuntimeFreezeReason(input.parse()?)) + } else if lookahead.peek(keyword::RuntimeHoldReason) { + Ok(Self::RuntimeHoldReason(input.parse()?)) + } else if lookahead.peek(keyword::RuntimeSlashReason) { + Ok(Self::RuntimeSlashReason(input.parse()?)) + } else if lookahead.peek(keyword::RuntimeLockId) { + Ok(Self::RuntimeLockId(input.parse()?)) + } else if lookahead.peek(keyword::RuntimeTask) { + Ok(Self::RuntimeTask(input.parse()?)) + } else { + Err(lookahead.error()) + } + } +} diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 07560abd935..af8449c9697 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -510,6 +510,9 @@ pub use frame_support_procedural::{ construct_runtime, match_and_insert, transactional, PalletError, RuntimeDebugNoBound, }; +#[cfg(feature = "experimental")] +pub use frame_support_procedural::runtime; + #[doc(hidden)] pub use frame_support_procedural::{__create_tt_macro, __generate_dummy_part_checker}; diff --git a/substrate/frame/support/test/Cargo.toml b/substrate/frame/support/test/Cargo.toml index ae2c56a531f..2f12cc00ed9 100644 --- a/substrate/frame/support/test/Cargo.toml +++ b/substrate/frame/support/test/Cargo.toml @@ -24,7 +24,7 @@ sp-api = { path = "../../../primitives/api", default-features = false } sp-arithmetic = { path = "../../../primitives/arithmetic", default-features = false } sp-io = { path = "../../../primitives/io", default-features = false } sp-state-machine = { path = "../../../primitives/state-machine", optional = true } -frame-support = { path = "..", default-features = false } +frame-support = { path = "..", default-features = false, features = ["experimental"] } frame-benchmarking = { path = "../../benchmarking", default-features = false } sp-runtime = { path = "../../../primitives/runtime", default-features = false } sp-core = { path = "../../../primitives/core", default-features = false } diff --git a/substrate/frame/support/test/tests/construct_runtime.rs b/substrate/frame/support/test/tests/runtime.rs similarity index 89% rename from substrate/frame/support/test/tests/construct_runtime.rs rename to substrate/frame/support/test/tests/runtime.rs index 83691451ccd..7e33ee46458 100644 --- a/substrate/frame/support/test/tests/construct_runtime.rs +++ b/substrate/frame/support/test/tests/runtime.rs @@ -30,7 +30,7 @@ use scale_info::TypeInfo; use sp_core::{sr25519, ConstU64}; use sp_runtime::{ generic, - traits::{BlakeTwo256, Verify}, + traits::{BlakeTwo256, ValidateUnsigned, Verify}, DispatchError, ModuleError, }; use sp_version::RuntimeVersion; @@ -176,6 +176,17 @@ mod nested { impl BuildGenesisConfig for GenesisConfig { fn build(&self) {} } + + #[pallet::validate_unsigned] + impl ValidateUnsigned for Pallet { + type Call = Call; + fn validate_unsigned( + _source: TransactionSource, + _call: &Self::Call, + ) -> TransactionValidity { + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) + } + } } } @@ -247,6 +258,20 @@ pub mod module3 { impl BuildGenesisConfig for GenesisConfig { fn build(&self) {} } + + #[pallet::storage] + pub type Storage = StorageValue<_, u32>; + + #[pallet::validate_unsigned] + impl ValidateUnsigned for Pallet { + type Call = Call; + fn validate_unsigned( + _source: TransactionSource, + _call: &Self::Call, + ) -> TransactionValidity { + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) + } + } } pub type BlockNumber = u64; @@ -256,24 +281,64 @@ pub type Header = generic::Header; pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; pub type Block = generic::Block; -frame_support::construct_runtime!( - pub struct Runtime - { - System: frame_system::{Pallet, Call, Event, Origin} = 30, - Module1_1: module1::::{Pallet, Call, Storage, Event, Origin}, - Module2: module2::{Pallet, Call, Storage, Event, Origin}, - Module1_2: module1::::{Pallet, Call, Storage, Event, Origin}, - NestedModule3: nested::module3::{Pallet, Call, Config, Storage, Event, Origin}, - Module3: self::module3::{Pallet, Call, Config, Storage, Event, Origin}, - Module1_3: module1::::{Pallet, Storage, Event } = 6, - Module1_4: module1::::{Pallet, Call, Event } = 3, - Module1_5: module1::::{Pallet, Event}, - Module1_6: module1::::{Pallet, Call, Storage, Event, Origin} = 1, - Module1_7: module1::::{Pallet, Call, Storage, Event, Origin}, - Module1_8: module1::::{Pallet, Call, Storage, Event, Origin} = 12, - Module1_9: module1::::{Pallet, Call, Storage, Event, Origin}, - } -); +#[frame_support::runtime] +mod runtime { + #[runtime::runtime] + #[runtime::derive( + RuntimeCall, + RuntimeEvent, + RuntimeError, + RuntimeOrigin, + RuntimeFreezeReason, + RuntimeHoldReason, + RuntimeSlashReason, + RuntimeLockId, + RuntimeTask + )] + pub struct Runtime; + + #[runtime::pallet_index(30)] + pub type System = frame_system + Pallet + Call + Event + Origin; + + #[runtime::pallet_index(31)] + pub type Module1_1 = module1; + + #[runtime::pallet_index(32)] + pub type Module2 = module2; + + #[runtime::pallet_index(33)] + pub type Module1_2 = module1; + + #[runtime::pallet_index(34)] + pub type NestedModule3 = nested::module3; + + #[runtime::pallet_index(35)] + #[runtime::disable_unsigned] + pub type Module3 = self::module3; + + #[runtime::pallet_index(6)] + #[runtime::disable_call] + pub type Module1_3 = module1; + + #[runtime::pallet_index(3)] + pub type Module1_4 = module1; + + #[runtime::pallet_index(4)] + #[runtime::disable_call] + pub type Module1_5 = module1; + + #[runtime::pallet_index(1)] + pub type Module1_6 = module1; + + #[runtime::pallet_index(2)] + pub type Module1_7 = module1; + + #[runtime::pallet_index(12)] + pub type Module1_8 = module1; + + #[runtime::pallet_index(13)] + pub type Module1_9 = module1; +} #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { @@ -605,17 +670,17 @@ fn get_module_names() { let module_names = RuntimeCall::get_module_names(); assert_eq!( [ + "Module1_6", + "Module1_7", + "Module1_4", + "Module1_8", + "Module1_9", "System", "Module1_1", "Module2", "Module1_2", "NestedModule3", "Module3", - "Module1_4", - "Module1_6", - "Module1_7", - "Module1_8", - "Module1_9", ], module_names ); @@ -636,9 +701,13 @@ fn call_subtype_conversion() { #[test] fn test_metadata() { - use frame_metadata::{v14::*, *}; + use frame_metadata::{ + v14::{StorageEntryType::Plain, *}, + *, + }; use scale_info::meta_type; use sp_core::Encode; + use sp_metadata_ir::StorageEntryModifierIR::Optional; fn maybe_docs(doc: Vec<&'static str>) -> Vec<&'static str> { if cfg!(feature = "no-metadata-docs") { @@ -649,6 +718,69 @@ fn test_metadata() { } let pallets = vec![ + PalletMetadata { + name: "Module1_6", + storage:None, + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 1, + }, + PalletMetadata { + name: "Module1_7", + storage: None, + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 2, + }, + PalletMetadata { + name: "Module1_4", + storage: None, + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 3, + }, + PalletMetadata { + name: "Module1_5", + storage: None, + calls: None, + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 4, + }, + PalletMetadata { + name: "Module1_3", + storage: None, + calls: None, + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 6, + }, + PalletMetadata { + name: "Module1_8", + storage: None, + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 12, + }, + PalletMetadata { + name: "Module1_9", + storage: None, + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 13, + }, PalletMetadata { name: "System", storage: None, @@ -703,7 +835,7 @@ fn test_metadata() { }, PalletMetadata { name: "Module1_1", - storage: Some(PalletStorageMetadata { prefix: "Module1_1", entries: vec![] }), + storage: None, calls: Some(meta_type::>().into()), event: Some(meta_type::>().into()), constants: vec![], @@ -712,7 +844,7 @@ fn test_metadata() { }, PalletMetadata { name: "Module2", - storage: Some(PalletStorageMetadata { prefix: "Module2", entries: vec![] }), + storage: None, calls: Some(meta_type::>().into()), event: Some(meta_type::>().into()), constants: vec![], @@ -721,7 +853,7 @@ fn test_metadata() { }, PalletMetadata { name: "Module1_2", - storage: Some(PalletStorageMetadata { prefix: "Module1_2", entries: vec![] }), + storage: None, calls: Some(meta_type::>().into()), event: Some(meta_type::>().into()), constants: vec![], @@ -730,7 +862,7 @@ fn test_metadata() { }, PalletMetadata { name: "NestedModule3", - storage: Some(PalletStorageMetadata { prefix: "NestedModule3", entries: vec![] }), + storage: None, calls: Some(meta_type::>().into()), event: Some(meta_type::>().into()), constants: vec![], @@ -739,76 +871,24 @@ fn test_metadata() { }, PalletMetadata { name: "Module3", - storage: Some(PalletStorageMetadata { prefix: "Module3", entries: vec![] }), + storage: Some(PalletStorageMetadata { + prefix: "Module3", + entries: vec![ + StorageEntryMetadata { + name: "Storage", + modifier: Optional.into(), + ty: Plain(meta_type::().into()), + default: vec![0], + docs: vec![], + }, + ] + }), calls: Some(meta_type::>().into()), event: Some(meta_type::>().into()), constants: vec![], error: Some(meta_type::>().into()), index: 35, }, - PalletMetadata { - name: "Module1_3", - storage: Some(PalletStorageMetadata { prefix: "Module1_3", entries: vec![] }), - calls: None, - event: Some(meta_type::>().into()), - constants: vec![], - error: Some(meta_type::>().into()), - index: 6, - }, - PalletMetadata { - name: "Module1_4", - storage: None, - calls: Some(meta_type::>().into()), - event: Some(meta_type::>().into()), - constants: vec![], - error: Some(meta_type::>().into()), - index: 3, - }, - PalletMetadata { - name: "Module1_5", - storage: None, - calls: None, - event: Some(meta_type::>().into()), - constants: vec![], - error: Some(meta_type::>().into()), - index: 4, - }, - PalletMetadata { - name: "Module1_6", - storage: Some(PalletStorageMetadata { prefix: "Module1_6", entries: vec![] }), - calls: Some(meta_type::>().into()), - event: Some(meta_type::>().into()), - constants: vec![], - error: Some(meta_type::>().into()), - index: 1, - }, - PalletMetadata { - name: "Module1_7", - storage: Some(PalletStorageMetadata { prefix: "Module1_7", entries: vec![] }), - calls: Some(meta_type::>().into()), - event: Some(meta_type::>().into()), - constants: vec![], - error: Some(meta_type::>().into()), - index: 2, - }, - PalletMetadata { - name: "Module1_8", - storage: Some(PalletStorageMetadata { prefix: "Module1_8", entries: vec![] }), - calls: Some(meta_type::>().into()), - event: Some(meta_type::>().into()), - constants: vec![], - error: Some(meta_type::>().into()), - index: 12, - }, - PalletMetadata { - name: "Module1_9", - storage: Some(PalletStorageMetadata { prefix: "Module1_9", entries: vec![] }), - calls: Some(meta_type::>().into()), - event: Some(meta_type::>().into()), - constants: vec![], - error: Some(meta_type::>().into()), - index: 13, - }, ]; let extrinsic = ExtrinsicMetadata { @@ -895,3 +975,19 @@ fn pallet_in_runtime_is_correct() { assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); assert!(PalletInfo::crate_version::().is_some()); } + +#[test] +fn test_validate_unsigned() { + use frame_support::pallet_prelude::*; + + let call = RuntimeCall::NestedModule3(nested::module3::Call::fail {}); + let validity = Runtime::validate_unsigned(TransactionSource::Local, &call).unwrap_err(); + assert_eq!(validity, TransactionValidityError::Invalid(InvalidTransaction::Call)); + + let call = RuntimeCall::Module3(module3::Call::fail {}); + let validity = Runtime::validate_unsigned(TransactionSource::Local, &call).unwrap_err(); + assert_eq!( + validity, + TransactionValidityError::Unknown(UnknownTransaction::NoUnsignedValidator) + ); +} diff --git a/substrate/frame/support/test/tests/runtime_legacy_ordering.rs b/substrate/frame/support/test/tests/runtime_legacy_ordering.rs new file mode 100644 index 00000000000..38875517018 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_legacy_ordering.rs @@ -0,0 +1,993 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! General tests for construct_runtime macro, test for: +//! * error declared with decl_error works +//! * integrity test is generated + +#![recursion_limit = "128"] + +use codec::MaxEncodedLen; +use frame_support::{ + derive_impl, parameter_types, traits::PalletInfo as _, weights::RuntimeDbWeight, +}; +use frame_system::limits::{BlockLength, BlockWeights}; +use scale_info::TypeInfo; +use sp_core::{sr25519, ConstU64}; +use sp_runtime::{ + generic, + traits::{BlakeTwo256, ValidateUnsigned, Verify}, + DispatchError, ModuleError, +}; +use sp_version::RuntimeVersion; + +parameter_types! { + pub static IntegrityTestExec: u32 = 0; +} + +#[frame_support::pallet(dev_mode)] +mod module1 { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; + } + + #[pallet::call] + impl, I: 'static> Pallet { + pub fn fail(_origin: OriginFor) -> DispatchResult { + Err(Error::::Something.into()) + } + } + + #[pallet::origin] + #[derive(Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)] + #[scale_info(skip_type_params(I))] + pub struct Origin(pub PhantomData<(T, I)>); + + #[pallet::event] + pub enum Event, I: 'static = ()> { + A(::AccountId), + } + + #[pallet::error] + pub enum Error { + Something, + } +} + +#[frame_support::pallet(dev_mode)] +mod module2 { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::hooks] + impl Hooks> for Pallet { + fn integrity_test() { + IntegrityTestExec::mutate(|i| *i += 1); + } + } + + #[pallet::call] + impl Pallet { + pub fn fail(_origin: OriginFor) -> DispatchResult { + Err(Error::::Something.into()) + } + } + + #[pallet::origin] + #[derive(Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)] + pub struct Origin; + + #[pallet::event] + pub enum Event { + A, + } + + #[pallet::error] + pub enum Error { + Something, + } +} + +mod nested { + use super::*; + + #[frame_support::pallet(dev_mode)] + pub mod module3 { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; + } + + #[pallet::hooks] + impl Hooks> for Pallet { + fn integrity_test() { + IntegrityTestExec::mutate(|i| *i += 1); + } + } + + #[pallet::call] + impl Pallet { + pub fn fail(_origin: OriginFor) -> DispatchResult { + Err(Error::::Something.into()) + } + } + + #[pallet::origin] + #[derive(Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)] + pub struct Origin; + + #[pallet::event] + pub enum Event { + A, + } + + #[pallet::error] + pub enum Error { + Something, + } + + #[pallet::genesis_config] + #[derive(frame_support::DefaultNoBound)] + pub struct GenesisConfig { + #[serde(skip)] + pub _config: sp_std::marker::PhantomData, + } + + #[pallet::genesis_build] + impl BuildGenesisConfig for GenesisConfig { + fn build(&self) {} + } + + #[pallet::validate_unsigned] + impl ValidateUnsigned for Pallet { + type Call = Call; + fn validate_unsigned( + _source: TransactionSource, + _call: &Self::Call, + ) -> TransactionValidity { + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) + } + } + } +} + +#[frame_support::pallet(dev_mode)] +pub mod module3 { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::call] + impl Pallet { + pub fn fail(_origin: OriginFor) -> DispatchResult { + Err(Error::::Something.into()) + } + pub fn aux_1(_origin: OriginFor, #[pallet::compact] _data: u32) -> DispatchResult { + unreachable!() + } + pub fn aux_2( + _origin: OriginFor, + _data: i32, + #[pallet::compact] _data2: u32, + ) -> DispatchResult { + unreachable!() + } + #[pallet::weight(0)] + pub fn aux_3(_origin: OriginFor, _data: i32, _data2: String) -> DispatchResult { + unreachable!() + } + #[pallet::weight(3)] + pub fn aux_4(_origin: OriginFor) -> DispatchResult { + unreachable!() + } + #[pallet::weight((5, DispatchClass::Operational))] + pub fn operational(_origin: OriginFor) -> DispatchResult { + unreachable!() + } + } + + #[pallet::origin] + #[derive(Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)] + pub struct Origin(pub PhantomData); + + #[pallet::event] + pub enum Event { + A, + } + + #[pallet::error] + pub enum Error { + Something, + } + + #[pallet::genesis_config] + #[derive(frame_support::DefaultNoBound)] + pub struct GenesisConfig { + #[serde(skip)] + pub _config: sp_std::marker::PhantomData, + } + + #[pallet::genesis_build] + impl BuildGenesisConfig for GenesisConfig { + fn build(&self) {} + } + + #[pallet::storage] + pub type Storage = StorageValue<_, u32>; + + #[pallet::validate_unsigned] + impl ValidateUnsigned for Pallet { + type Call = Call; + fn validate_unsigned( + _source: TransactionSource, + _call: &Self::Call, + ) -> TransactionValidity { + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) + } + } +} + +pub type BlockNumber = u64; +pub type Signature = sr25519::Signature; +pub type AccountId = ::Signer; +pub type Header = generic::Header; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type Block = generic::Block; + +#[frame_support::runtime(legacy_ordering)] +mod runtime { + #[runtime::runtime] + #[runtime::derive( + RuntimeCall, + RuntimeEvent, + RuntimeError, + RuntimeOrigin, + RuntimeFreezeReason, + RuntimeHoldReason, + RuntimeSlashReason, + RuntimeLockId, + RuntimeTask + )] + pub struct Runtime; + + #[runtime::pallet_index(30)] + pub type System = frame_system + Pallet + Call + Event + Origin; + + #[runtime::pallet_index(31)] + pub type Module1_1 = module1; + + #[runtime::pallet_index(32)] + pub type Module2 = module2; + + #[runtime::pallet_index(33)] + pub type Module1_2 = module1; + + #[runtime::pallet_index(34)] + pub type NestedModule3 = nested::module3; + + #[runtime::pallet_index(35)] + #[runtime::disable_unsigned] + pub type Module3 = self::module3; + + #[runtime::pallet_index(6)] + #[runtime::disable_call] + pub type Module1_3 = module1; + + #[runtime::pallet_index(3)] + pub type Module1_4 = module1; + + #[runtime::pallet_index(4)] + #[runtime::disable_call] + pub type Module1_5 = module1; + + #[runtime::pallet_index(1)] + pub type Module1_6 = module1; + + #[runtime::pallet_index(2)] + pub type Module1_7 = module1; + + #[runtime::pallet_index(12)] + pub type Module1_8 = module1; + + #[runtime::pallet_index(13)] + pub type Module1_9 = module1; +} + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Runtime { + type AccountId = AccountId; + type Lookup = sp_runtime::traits::IdentityLookup; + type BaseCallFilter = frame_support::traits::Everything; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type PalletInfo = PalletInfo; + type OnSetCode = (); + type Block = Block; + type BlockHashCount = ConstU64<10>; +} + +impl module1::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl module1::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl module1::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl module1::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl module1::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl module1::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl module1::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl module1::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl module1::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl module2::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl nested::module3::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl module3::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +fn test_pub() -> AccountId { + AccountId::from_raw([0; 32]) +} + +#[test] +fn check_modules_error_type() { + sp_io::TestExternalities::default().execute_with(|| { + assert_eq!( + Module1_1::fail(frame_system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 31, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module2::fail(frame_system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 32, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module1_2::fail(frame_system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 33, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + NestedModule3::fail(frame_system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 34, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module1_3::fail(frame_system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 6, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module1_4::fail(frame_system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 3, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module1_5::fail(frame_system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 4, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module1_6::fail(frame_system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 1, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module1_7::fail(frame_system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 2, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module1_8::fail(frame_system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 12, + error: [0; 4], + message: Some("Something") + })), + ); + assert_eq!( + Module1_9::fail(frame_system::Origin::::Root.into()), + Err(DispatchError::Module(ModuleError { + index: 13, + error: [0; 4], + message: Some("Something") + })), + ); + }) +} + +#[test] +fn integrity_test_works() { + __construct_runtime_integrity_test::runtime_integrity_tests(); + assert_eq!(IntegrityTestExec::get(), 2); +} + +#[test] +fn origin_codec() { + use codec::Encode; + + let origin = OriginCaller::system(frame_system::RawOrigin::None); + assert_eq!(origin.encode()[0], 30); + + let origin = OriginCaller::Module1_1(module1::Origin(Default::default())); + assert_eq!(origin.encode()[0], 31); + + let origin = OriginCaller::Module2(module2::Origin); + assert_eq!(origin.encode()[0], 32); + + let origin = OriginCaller::Module1_2(module1::Origin(Default::default())); + assert_eq!(origin.encode()[0], 33); + + let origin = OriginCaller::NestedModule3(nested::module3::Origin); + assert_eq!(origin.encode()[0], 34); + + let origin = OriginCaller::Module3(module3::Origin(Default::default())); + assert_eq!(origin.encode()[0], 35); + + let origin = OriginCaller::Module1_6(module1::Origin(Default::default())); + assert_eq!(origin.encode()[0], 1); + + let origin = OriginCaller::Module1_7(module1::Origin(Default::default())); + assert_eq!(origin.encode()[0], 2); + + let origin = OriginCaller::Module1_8(module1::Origin(Default::default())); + assert_eq!(origin.encode()[0], 12); + + let origin = OriginCaller::Module1_9(module1::Origin(Default::default())); + assert_eq!(origin.encode()[0], 13); +} + +#[test] +fn event_codec() { + use codec::Encode; + + let event = + frame_system::Event::::ExtrinsicSuccess { dispatch_info: Default::default() }; + assert_eq!(RuntimeEvent::from(event).encode()[0], 30); + + let event = module1::Event::::A(test_pub()); + assert_eq!(RuntimeEvent::from(event).encode()[0], 31); + + let event = module2::Event::A; + assert_eq!(RuntimeEvent::from(event).encode()[0], 32); + + let event = module1::Event::::A(test_pub()); + assert_eq!(RuntimeEvent::from(event).encode()[0], 33); + + let event = nested::module3::Event::A; + assert_eq!(RuntimeEvent::from(event).encode()[0], 34); + + let event = module3::Event::A; + assert_eq!(RuntimeEvent::from(event).encode()[0], 35); + + let event = module1::Event::::A(test_pub()); + assert_eq!(RuntimeEvent::from(event).encode()[0], 4); + + let event = module1::Event::::A(test_pub()); + assert_eq!(RuntimeEvent::from(event).encode()[0], 1); + + let event = module1::Event::::A(test_pub()); + assert_eq!(RuntimeEvent::from(event).encode()[0], 2); + + let event = module1::Event::::A(test_pub()); + assert_eq!(RuntimeEvent::from(event).encode()[0], 12); + + let event = module1::Event::::A(test_pub()); + assert_eq!(RuntimeEvent::from(event).encode()[0], 13); +} + +#[test] +fn call_codec() { + use codec::Encode; + assert_eq!(RuntimeCall::System(frame_system::Call::remark { remark: vec![1] }).encode()[0], 30); + assert_eq!(RuntimeCall::Module1_1(module1::Call::fail {}).encode()[0], 31); + assert_eq!(RuntimeCall::Module2(module2::Call::fail {}).encode()[0], 32); + assert_eq!(RuntimeCall::Module1_2(module1::Call::fail {}).encode()[0], 33); + assert_eq!(RuntimeCall::NestedModule3(nested::module3::Call::fail {}).encode()[0], 34); + assert_eq!(RuntimeCall::Module3(module3::Call::fail {}).encode()[0], 35); + assert_eq!(RuntimeCall::Module1_4(module1::Call::fail {}).encode()[0], 3); + assert_eq!(RuntimeCall::Module1_6(module1::Call::fail {}).encode()[0], 1); + assert_eq!(RuntimeCall::Module1_7(module1::Call::fail {}).encode()[0], 2); + assert_eq!(RuntimeCall::Module1_8(module1::Call::fail {}).encode()[0], 12); + assert_eq!(RuntimeCall::Module1_9(module1::Call::fail {}).encode()[0], 13); +} + +#[test] +fn call_compact_attr() { + use codec::Encode; + let call: module3::Call = module3::Call::aux_1 { data: 1 }; + let encoded = call.encode(); + assert_eq!(2, encoded.len()); + assert_eq!(vec![1, 4], encoded); + + let call: module3::Call = module3::Call::aux_2 { data: 1, data2: 2 }; + let encoded = call.encode(); + assert_eq!(6, encoded.len()); + assert_eq!(vec![2, 1, 0, 0, 0, 8], encoded); +} + +#[test] +fn call_encode_is_correct_and_decode_works() { + use codec::{Decode, Encode}; + let call: module3::Call = module3::Call::fail {}; + let encoded = call.encode(); + assert_eq!(vec![0], encoded); + let decoded = module3::Call::::decode(&mut &encoded[..]).unwrap(); + assert_eq!(decoded, call); + + let call: module3::Call = module3::Call::aux_3 { data: 32, data2: "hello".into() }; + let encoded = call.encode(); + assert_eq!(vec![3, 32, 0, 0, 0, 20, 104, 101, 108, 108, 111], encoded); + let decoded = module3::Call::::decode(&mut &encoded[..]).unwrap(); + assert_eq!(decoded, call); +} + +#[test] +fn call_weight_should_attach_to_call_enum() { + use frame_support::{ + dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays}, + weights::Weight, + }; + // operational. + assert_eq!( + module3::Call::::operational {}.get_dispatch_info(), + DispatchInfo { + weight: Weight::from_parts(5, 0), + class: DispatchClass::Operational, + pays_fee: Pays::Yes + }, + ); + // custom basic + assert_eq!( + module3::Call::::aux_4 {}.get_dispatch_info(), + DispatchInfo { + weight: Weight::from_parts(3, 0), + class: DispatchClass::Normal, + pays_fee: Pays::Yes + }, + ); +} + +#[test] +fn call_name() { + use frame_support::traits::GetCallName; + let name = module3::Call::::aux_4 {}.get_call_name(); + assert_eq!("aux_4", name); +} + +#[test] +fn call_metadata() { + use frame_support::traits::{CallMetadata, GetCallMetadata}; + let call = RuntimeCall::Module3(module3::Call::::aux_4 {}); + let metadata = call.get_call_metadata(); + let expected = CallMetadata { function_name: "aux_4".into(), pallet_name: "Module3".into() }; + assert_eq!(metadata, expected); +} + +#[test] +fn get_call_names() { + use frame_support::traits::GetCallName; + let call_names = module3::Call::::get_call_names(); + assert_eq!(["fail", "aux_1", "aux_2", "aux_3", "aux_4", "operational"], call_names); +} + +#[test] +fn get_module_names() { + use frame_support::traits::GetCallMetadata; + let module_names = RuntimeCall::get_module_names(); + assert_eq!( + [ + "System", + "Module1_1", + "Module2", + "Module1_2", + "NestedModule3", + "Module3", + "Module1_4", + "Module1_6", + "Module1_7", + "Module1_8", + "Module1_9", + ], + module_names + ); +} + +#[test] +fn call_subtype_conversion() { + use frame_support::{dispatch::CallableCallFor, traits::IsSubType}; + let call = RuntimeCall::Module3(module3::Call::::fail {}); + let subcall: Option<&CallableCallFor> = call.is_sub_type(); + let subcall_none: Option<&CallableCallFor> = call.is_sub_type(); + assert_eq!(Some(&module3::Call::::fail {}), subcall); + assert_eq!(None, subcall_none); + + let from = RuntimeCall::from(subcall.unwrap().clone()); + assert_eq!(from, call); +} + +#[test] +fn test_metadata() { + use frame_metadata::{ + v14::{StorageEntryType::Plain, *}, + *, + }; + use scale_info::meta_type; + use sp_core::Encode; + use sp_metadata_ir::StorageEntryModifierIR::Optional; + + fn maybe_docs(doc: Vec<&'static str>) -> Vec<&'static str> { + if cfg!(feature = "no-metadata-docs") { + vec![] + } else { + doc + } + } + + let pallets = vec![ + PalletMetadata { + name: "System", + storage: None, + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![ + PalletConstantMetadata { + name: "BlockWeights", + ty: meta_type::(), + value: BlockWeights::default().encode(), + docs: maybe_docs(vec![" Block & extrinsics weights: base values and limits."]), + }, + PalletConstantMetadata { + name: "BlockLength", + ty: meta_type::(), + value: BlockLength::default().encode(), + docs: maybe_docs(vec![" The maximum length of a block (in bytes)."]), + }, + PalletConstantMetadata { + name: "BlockHashCount", + ty: meta_type::(), + value: 10u64.encode(), + docs: maybe_docs(vec![" Maximum number of block number to block hash mappings to keep (oldest pruned first)."]), + }, + PalletConstantMetadata { + name: "DbWeight", + ty: meta_type::(), + value: RuntimeDbWeight::default().encode(), + docs: maybe_docs(vec![" The weight of runtime database operations the runtime can invoke.",]), + }, + PalletConstantMetadata { + name: "Version", + ty: meta_type::(), + value: RuntimeVersion::default().encode(), + docs: maybe_docs(vec![ " Get the chain's current version."]), + }, + PalletConstantMetadata { + name: "SS58Prefix", + ty: meta_type::(), + value: 0u16.encode(), + docs: maybe_docs(vec![ + " The designated SS58 prefix of this chain.", + "", + " This replaces the \"ss58Format\" property declared in the chain spec. Reason is", + " that the runtime should know about the prefix in order to make use of it as", + " an identifier of the chain.", + ]), + }, + ], + error: Some(meta_type::>().into()), + index: 30, + }, + PalletMetadata { + name: "Module1_1", + storage: None, + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 31, + }, + PalletMetadata { + name: "Module2", + storage: None, + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 32, + }, + PalletMetadata { + name: "Module1_2", + storage: None, + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 33, + }, + PalletMetadata { + name: "NestedModule3", + storage: None, + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 34, + }, + PalletMetadata { + name: "Module3", + storage: Some(PalletStorageMetadata { + prefix: "Module3", + entries: vec![ + StorageEntryMetadata { + name: "Storage", + modifier: Optional.into(), + ty: Plain(meta_type::().into()), + default: vec![0], + docs: vec![], + }, + ] + }), + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 35, + }, + PalletMetadata { + name: "Module1_3", + storage: None, + calls: None, + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 6, + }, + PalletMetadata { + name: "Module1_4", + storage: None, + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 3, + }, + PalletMetadata { + name: "Module1_5", + storage: None, + calls: None, + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 4, + }, + PalletMetadata { + name: "Module1_6", + storage:None, + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 1, + }, + PalletMetadata { + name: "Module1_7", + storage: None, + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 2, + }, + PalletMetadata { + name: "Module1_8", + storage: None, + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 12, + }, + PalletMetadata { + name: "Module1_9", + storage: None, + calls: Some(meta_type::>().into()), + event: Some(meta_type::>().into()), + constants: vec![], + error: Some(meta_type::>().into()), + index: 13, + }, + ]; + + let extrinsic = ExtrinsicMetadata { + ty: meta_type::(), + version: 4, + signed_extensions: vec![SignedExtensionMetadata { + identifier: "UnitTransactionExtension", + ty: meta_type::<()>(), + additional_signed: meta_type::<()>(), + }], + }; + + let expected_metadata: RuntimeMetadataPrefixed = + RuntimeMetadataLastVersion::new(pallets, extrinsic, meta_type::()).into(); + let actual_metadata = Runtime::metadata(); + + pretty_assertions::assert_eq!(actual_metadata, expected_metadata); +} + +#[test] +fn pallet_in_runtime_is_correct() { + assert_eq!(PalletInfo::index::().unwrap(), 30); + assert_eq!(PalletInfo::name::().unwrap(), "System"); + assert_eq!(PalletInfo::module_name::().unwrap(), "frame_system"); + assert!(PalletInfo::crate_version::().is_some()); + + assert_eq!(PalletInfo::index::().unwrap(), 31); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_1"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert!(PalletInfo::crate_version::().is_some()); + + assert_eq!(PalletInfo::index::().unwrap(), 32); + assert_eq!(PalletInfo::name::().unwrap(), "Module2"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module2"); + assert!(PalletInfo::crate_version::().is_some()); + + assert_eq!(PalletInfo::index::().unwrap(), 33); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_2"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert!(PalletInfo::crate_version::().is_some()); + + assert_eq!(PalletInfo::index::().unwrap(), 34); + assert_eq!(PalletInfo::name::().unwrap(), "NestedModule3"); + assert_eq!(PalletInfo::module_name::().unwrap(), "nested::module3"); + assert!(PalletInfo::crate_version::().is_some()); + + assert_eq!(PalletInfo::index::().unwrap(), 35); + assert_eq!(PalletInfo::name::().unwrap(), "Module3"); + assert_eq!(PalletInfo::module_name::().unwrap(), "self::module3"); + assert!(PalletInfo::crate_version::().is_some()); + + assert_eq!(PalletInfo::index::().unwrap(), 6); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_3"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert!(PalletInfo::crate_version::().is_some()); + + assert_eq!(PalletInfo::index::().unwrap(), 3); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_4"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert!(PalletInfo::crate_version::().is_some()); + + assert_eq!(PalletInfo::index::().unwrap(), 4); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_5"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert!(PalletInfo::crate_version::().is_some()); + + assert_eq!(PalletInfo::index::().unwrap(), 1); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_6"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert!(PalletInfo::crate_version::().is_some()); + + assert_eq!(PalletInfo::index::().unwrap(), 2); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_7"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert!(PalletInfo::crate_version::().is_some()); + + assert_eq!(PalletInfo::index::().unwrap(), 12); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_8"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert!(PalletInfo::crate_version::().is_some()); + + assert_eq!(PalletInfo::index::().unwrap(), 13); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_9"); + assert_eq!(PalletInfo::module_name::().unwrap(), "module1"); + assert!(PalletInfo::crate_version::().is_some()); +} + +#[test] +fn test_validate_unsigned() { + use frame_support::pallet_prelude::*; + + let call = RuntimeCall::NestedModule3(nested::module3::Call::fail {}); + let validity = Runtime::validate_unsigned(TransactionSource::Local, &call).unwrap_err(); + assert_eq!(validity, TransactionValidityError::Invalid(InvalidTransaction::Call)); + + let call = RuntimeCall::Module3(module3::Call::fail {}); + let validity = Runtime::validate_unsigned(TransactionSource::Local, &call).unwrap_err(); + assert_eq!( + validity, + TransactionValidityError::Unknown(UnknownTransaction::NoUnsignedValidator) + ); +} diff --git a/substrate/frame/support/test/tests/runtime_ui.rs b/substrate/frame/support/test/tests/runtime_ui.rs new file mode 100644 index 00000000000..dbe150f38ed --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui.rs @@ -0,0 +1,36 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[rustversion::attr(not(stable), ignore)] +#[cfg(not(feature = "disable-ui-tests"))] +#[test] +fn ui() { + // Only run the ui tests when `RUN_UI_TESTS` is set. + if std::env::var("RUN_UI_TESTS").is_err() { + return + } + + // As trybuild is using `cargo check`, we don't need the real WASM binaries. + std::env::set_var("SKIP_WASM_BUILD", "1"); + + // Deny all warnings since we emit warnings as part of a Runtime's UI. + std::env::set_var("RUSTFLAGS", "--deny warnings"); + + let t = trybuild::TestCases::new(); + t.compile_fail("tests/runtime_ui/*.rs"); + t.pass("tests/runtime_ui/pass/*.rs"); +} diff --git a/substrate/frame/support/test/tests/runtime_ui/can_only_be_attached_to_mod.rs b/substrate/frame/support/test/tests/runtime_ui/can_only_be_attached_to_mod.rs new file mode 100644 index 00000000000..eb586809041 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/can_only_be_attached_to_mod.rs @@ -0,0 +1,21 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[frame_support::runtime] +fn construct_runtime() {} + +fn main() {} diff --git a/substrate/frame/support/test/tests/runtime_ui/can_only_be_attached_to_mod.stderr b/substrate/frame/support/test/tests/runtime_ui/can_only_be_attached_to_mod.stderr new file mode 100644 index 00000000000..7c2f0d1f169 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/can_only_be_attached_to_mod.stderr @@ -0,0 +1,5 @@ +error: expected `mod` + --> tests/runtime_ui/can_only_be_attached_to_mod.rs:19:1 + | +19 | fn construct_runtime() {} + | ^^ diff --git a/substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_index.rs b/substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_index.rs new file mode 100644 index 00000000000..648812b52c4 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_index.rs @@ -0,0 +1,43 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[frame_support::pallet] +mod pallet { + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::call] + impl Pallet {} +} + +#[frame_support::runtime] +mod runtime { + #[runtime::runtime] + #[runtime::derive(RuntimeCall)] + pub struct Runtime; + + #[runtime::pallet_index(0)] + pub type System = frame_system; + + #[runtime::pallet_index(0)] + pub type Pallet = pallet; +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_index.stderr b/substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_index.stderr new file mode 100644 index 00000000000..8963c5d3f26 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_index.stderr @@ -0,0 +1,11 @@ +error: Pallet indices are conflicting: Both pallets System and Pallet are at index 0 + --> tests/runtime_ui/conflicting_pallet_index.rs:37:14 + | +37 | pub type System = frame_system; + | ^^^^^^ + +error: Pallet indices are conflicting: Both pallets System and Pallet are at index 0 + --> tests/runtime_ui/conflicting_pallet_index.rs:40:14 + | +40 | pub type Pallet = pallet; + | ^^^^^^ diff --git a/substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_name.rs b/substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_name.rs new file mode 100644 index 00000000000..c68f9a8082b --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_name.rs @@ -0,0 +1,43 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[frame_support::pallet] +mod pallet { + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::call] + impl Pallet {} +} + +#[frame_support::runtime] +mod runtime { + #[runtime::runtime] + #[runtime::derive(RuntimeCall)] + pub struct Runtime; + + #[runtime::pallet_index(0)] + pub type System = frame_system; + + #[runtime::pallet_index(1)] + pub type System = pallet; +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_name.stderr b/substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_name.stderr new file mode 100644 index 00000000000..c250c24e3e7 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/conflicting_pallet_name.stderr @@ -0,0 +1,11 @@ +error: Two pallets with the same name! + --> tests/runtime_ui/conflicting_pallet_name.rs:37:14 + | +37 | pub type System = frame_system; + | ^^^^^^ + +error: Two pallets with the same name! + --> tests/runtime_ui/conflicting_pallet_name.rs:40:14 + | +40 | pub type System = pallet; + | ^^^^^^ diff --git a/substrate/frame/support/test/tests/runtime_ui/invalid_attribute.rs b/substrate/frame/support/test/tests/runtime_ui/invalid_attribute.rs new file mode 100644 index 00000000000..5df2491cb24 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/invalid_attribute.rs @@ -0,0 +1,23 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[frame_support::runtime(dummy)] +mod runtime { + +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/runtime_ui/invalid_attribute.stderr b/substrate/frame/support/test/tests/runtime_ui/invalid_attribute.stderr new file mode 100644 index 00000000000..e13552413c0 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/invalid_attribute.stderr @@ -0,0 +1,5 @@ +error: Invalid runtime macro call: unexpected attribute. Macro call must be bare, such as `#[frame_support::runtime]` or `#[runtime]`, or must specify the `legacy_ordering` attribute, such as `#[frame_support::runtime(legacy_ordering)]` or #[runtime(legacy_ordering)]. + --> tests/runtime_ui/invalid_attribute.rs:18:26 + | +18 | #[frame_support::runtime(dummy)] + | ^^^^^ diff --git a/substrate/frame/support/test/tests/runtime_ui/invalid_pallet_index.rs b/substrate/frame/support/test/tests/runtime_ui/invalid_pallet_index.rs new file mode 100644 index 00000000000..de89bb60224 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/invalid_pallet_index.rs @@ -0,0 +1,28 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[frame_support::runtime] +mod runtime { + #[runtime::runtime] + #[runtime::derive(RuntimeCall)] + pub struct Runtime; + + #[runtime::pallet_index("0")] + pub type System = frame_system; +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/runtime_ui/invalid_pallet_index.stderr b/substrate/frame/support/test/tests/runtime_ui/invalid_pallet_index.stderr new file mode 100644 index 00000000000..1fbd086ddbe --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/invalid_pallet_index.stderr @@ -0,0 +1,5 @@ +error: expected integer literal + --> tests/runtime_ui/invalid_pallet_index.rs:24:29 + | +24 | #[runtime::pallet_index("0")] + | ^^^ diff --git a/substrate/frame/support/test/tests/runtime_ui/invalid_runtime_type_derive.rs b/substrate/frame/support/test/tests/runtime_ui/invalid_runtime_type_derive.rs new file mode 100644 index 00000000000..89ba2f23bb1 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/invalid_runtime_type_derive.rs @@ -0,0 +1,25 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[frame_support::runtime] +mod runtime { + #[runtime::runtime] + #[runtime::derive(RuntimeInfo)] + pub struct Runtime; +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/runtime_ui/invalid_runtime_type_derive.stderr b/substrate/frame/support/test/tests/runtime_ui/invalid_runtime_type_derive.stderr new file mode 100644 index 00000000000..0b128c3dd45 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/invalid_runtime_type_derive.stderr @@ -0,0 +1,5 @@ +error: expected one of: `RuntimeCall`, `RuntimeEvent`, `RuntimeError`, `RuntimeOrigin`, `RuntimeFreezeReason`, `RuntimeHoldReason`, `RuntimeSlashReason`, `RuntimeLockId`, `RuntimeTask` + --> tests/runtime_ui/invalid_runtime_type_derive.rs:21:23 + | +21 | #[runtime::derive(RuntimeInfo)] + | ^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/runtime_ui/missing_runtime.rs b/substrate/frame/support/test/tests/runtime_ui/missing_runtime.rs new file mode 100644 index 00000000000..c5febbe5287 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/missing_runtime.rs @@ -0,0 +1,21 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[frame_support::runtime] +mod runtime {} + +fn main() {} diff --git a/substrate/frame/support/test/tests/runtime_ui/missing_runtime.stderr b/substrate/frame/support/test/tests/runtime_ui/missing_runtime.stderr new file mode 100644 index 00000000000..9790c5dbc1a --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/missing_runtime.stderr @@ -0,0 +1,5 @@ +error: Missing Runtime. Please add a struct inside the module and annotate it with `#[runtime::runtime]` + --> tests/runtime_ui/missing_runtime.rs:19:1 + | +19 | mod runtime {} + | ^^^ diff --git a/substrate/frame/support/test/tests/runtime_ui/missing_runtime_types_derive.rs b/substrate/frame/support/test/tests/runtime_ui/missing_runtime_types_derive.rs new file mode 100644 index 00000000000..c3fb0fd454f --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/missing_runtime_types_derive.rs @@ -0,0 +1,24 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[frame_support::runtime] +mod runtime { + #[runtime::runtime] + pub struct Runtime; +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/runtime_ui/missing_runtime_types_derive.stderr b/substrate/frame/support/test/tests/runtime_ui/missing_runtime_types_derive.stderr new file mode 100644 index 00000000000..1a8deebe549 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/missing_runtime_types_derive.stderr @@ -0,0 +1,5 @@ +error: Missing Runtime Types. Please annotate the runtime struct with `#[runtime::derive]` + --> tests/runtime_ui/missing_runtime_types_derive.rs:19:1 + | +19 | mod runtime { + | ^^^ diff --git a/substrate/frame/support/test/tests/runtime_ui/missing_system_pallet.rs b/substrate/frame/support/test/tests/runtime_ui/missing_system_pallet.rs new file mode 100644 index 00000000000..f9a15fcf992 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/missing_system_pallet.rs @@ -0,0 +1,25 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[frame_support::runtime] +mod runtime { + #[runtime::runtime] + #[runtime::derive(RuntimeCall)] + pub struct Runtime; +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/runtime_ui/missing_system_pallet.stderr b/substrate/frame/support/test/tests/runtime_ui/missing_system_pallet.stderr new file mode 100644 index 00000000000..dc3ac4cd5d5 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/missing_system_pallet.stderr @@ -0,0 +1,5 @@ +error: `System` pallet declaration is missing. Please add this line: `pub type System = frame_system;` + --> tests/runtime_ui/missing_system_pallet.rs:19:5 + | +19 | mod runtime { + | ^^^^^^^ diff --git a/substrate/frame/support/test/tests/runtime_ui/pass/basic.rs b/substrate/frame/support/test/tests/runtime_ui/pass/basic.rs new file mode 100644 index 00000000000..514f1501801 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/pass/basic.rs @@ -0,0 +1,37 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use frame_support::derive_impl; + +pub type Block = frame_system::mocking::MockBlock; + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Runtime { + type Block = Block; +} + +#[frame_support::runtime] +mod runtime { + #[runtime::runtime] + #[runtime::derive(RuntimeCall, RuntimeEvent, RuntimeOrigin, RuntimeError, RuntimeTask)] + pub struct Runtime; + + #[runtime::pallet_index(0)] + pub type System = frame_system; +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/runtime_ui/runtime_struct.rs b/substrate/frame/support/test/tests/runtime_ui/runtime_struct.rs new file mode 100644 index 00000000000..bfa2fb75f04 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/runtime_struct.rs @@ -0,0 +1,24 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[frame_support::runtime] +mod runtime { + #[runtime::runtime] + pub enum Runtime {} +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/runtime_ui/runtime_struct.stderr b/substrate/frame/support/test/tests/runtime_ui/runtime_struct.stderr new file mode 100644 index 00000000000..04192bcf7f1 --- /dev/null +++ b/substrate/frame/support/test/tests/runtime_ui/runtime_struct.stderr @@ -0,0 +1,5 @@ +error: Invalid runtime::runtime, expected struct definition + --> tests/runtime_ui/runtime_struct.rs:21:5 + | +21 | pub enum Runtime {} + | ^^^ diff --git a/templates/solochain/runtime/Cargo.toml b/templates/solochain/runtime/Cargo.toml index 4f22e7ff6a3..706ea863d0f 100644 --- a/templates/solochain/runtime/Cargo.toml +++ b/templates/solochain/runtime/Cargo.toml @@ -25,7 +25,7 @@ scale-info = { version = "2.10.0", default-features = false, features = [ ] } # frame -frame-support = { path = "../../../substrate/frame/support", default-features = false } +frame-support = { path = "../../../substrate/frame/support", default-features = false, features = ["experimental"] } frame-system = { path = "../../../substrate/frame/system", default-features = false } frame-try-runtime = { path = "../../../substrate/frame/try-runtime", default-features = false, optional = true } frame-executive = { path = "../../../substrate/frame/executive", default-features = false } diff --git a/templates/solochain/runtime/src/lib.rs b/templates/solochain/runtime/src/lib.rs index 409b639f021..303122da564 100644 --- a/templates/solochain/runtime/src/lib.rs +++ b/templates/solochain/runtime/src/lib.rs @@ -253,20 +253,47 @@ impl pallet_template::Config for Runtime { } // Create the runtime by composing the FRAME pallets that were previously configured. -construct_runtime!( - pub enum Runtime { - System: frame_system, - Timestamp: pallet_timestamp, - Aura: pallet_aura, - Grandpa: pallet_grandpa, - Balances: pallet_balances, - TransactionPayment: pallet_transaction_payment, - Sudo: pallet_sudo, - - // Include the custom logic from the pallet-template in the runtime. - TemplateModule: pallet_template, - } -); +#[frame_support::runtime] +mod runtime { + #[runtime::runtime] + #[runtime::derive( + RuntimeCall, + RuntimeEvent, + RuntimeError, + RuntimeOrigin, + RuntimeFreezeReason, + RuntimeHoldReason, + RuntimeSlashReason, + RuntimeLockId, + RuntimeTask + )] + pub struct Runtime; + + #[runtime::pallet_index(0)] + pub type System = frame_system; + + #[runtime::pallet_index(1)] + pub type Timestamp = pallet_timestamp; + + #[runtime::pallet_index(2)] + pub type Aura = pallet_aura; + + #[runtime::pallet_index(3)] + pub type Grandpa = pallet_grandpa; + + #[runtime::pallet_index(4)] + pub type Balances = pallet_balances; + + #[runtime::pallet_index(5)] + pub type TransactionPayment = pallet_transaction_payment; + + #[runtime::pallet_index(6)] + pub type Sudo = pallet_sudo; + + // Include the custom logic from the pallet-template in the runtime. + #[runtime::pallet_index(7)] + pub type TemplateModule = pallet_template; +} /// The address format for describing accounts. pub type Address = sp_runtime::MultiAddress; -- GitLab From 60ac5a723c6c0eeef0e35a0788792378c8200ec5 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Wed, 13 Mar 2024 13:33:27 +0200 Subject: [PATCH 033/187] authority-discovery: Add log for debugging DHT authority records (#3668) This PR adds a debug log for displaying all the public addresses that will later be advertised in the DHT record of the authority. The Authority DHT record will contain the address ++ `/p2p/peerID` (if not already present). This log enables us to check if different nodes will advertise in the DHT record of the authority the same IP address, however with different peer IDs. Signed-off-by: Alexandru Vasile --- .../client/authority-discovery/src/worker.rs | 43 ++++++++++--------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/substrate/client/authority-discovery/src/worker.rs b/substrate/client/authority-discovery/src/worker.rs index 6db25416dee..9bccb96ff37 100644 --- a/substrate/client/authority-discovery/src/worker.rs +++ b/substrate/client/authority-discovery/src/worker.rs @@ -306,29 +306,30 @@ where fn addresses_to_publish(&self) -> impl Iterator { let peer_id: Multihash = self.network.local_peer_id().into(); let publish_non_global_ips = self.publish_non_global_ips; - self.network - .external_addresses() - .into_iter() - .filter(move |a| { - if publish_non_global_ips { - return true - } + let addresses = self.network.external_addresses().into_iter().filter(move |a| { + if publish_non_global_ips { + return true + } - a.iter().all(|p| match p { - // The `ip_network` library is used because its `is_global()` method is stable, - // while `is_global()` in the standard library currently isn't. - multiaddr::Protocol::Ip4(ip) if !IpNetwork::from(ip).is_global() => false, - multiaddr::Protocol::Ip6(ip) if !IpNetwork::from(ip).is_global() => false, - _ => true, - }) - }) - .map(move |a| { - if a.iter().any(|p| matches!(p, multiaddr::Protocol::P2p(_))) { - a - } else { - a.with(multiaddr::Protocol::P2p(peer_id)) - } + a.iter().all(|p| match p { + // The `ip_network` library is used because its `is_global()` method is stable, + // while `is_global()` in the standard library currently isn't. + multiaddr::Protocol::Ip4(ip) if !IpNetwork::from(ip).is_global() => false, + multiaddr::Protocol::Ip6(ip) if !IpNetwork::from(ip).is_global() => false, + _ => true, }) + }); + + debug!(target: LOG_TARGET, "Authority DHT record peer_id='{:?}' addresses='{:?}'", peer_id, addresses.clone().collect::>()); + + // The address must include the peer id if not already set. + addresses.map(move |a| { + if a.iter().any(|p| matches!(p, multiaddr::Protocol::P2p(_))) { + a + } else { + a.with(multiaddr::Protocol::P2p(peer_id)) + } + }) } /// Publish own public addresses. -- GitLab From bbd51ce867967f71657b901f1a956ad4f75d352e Mon Sep 17 00:00:00 2001 From: georgepisaltu <52418509+georgepisaltu@users.noreply.github.com> Date: Wed, 13 Mar 2024 16:10:59 +0200 Subject: [PATCH 034/187] Revert "FRAME: Create `TransactionExtension` as a replacement for `SignedExtension` (#2280)" (#3665) This PR reverts #2280 which introduced `TransactionExtension` to replace `SignedExtension`. As a result of the discussion [here](https://github.com/paritytech/polkadot-sdk/pull/3623#issuecomment-1986789700), the changes will be reverted for now with plans to reintroduce the concept in the future. --------- Signed-off-by: georgepisaltu --- Cargo.lock | 35 +- bridges/bin/runtime-common/Cargo.toml | 1 - bridges/bin/runtime-common/src/lib.rs | 72 +- bridges/bin/runtime-common/src/mock.rs | 2 +- .../runtime-common/src/priority_calculator.rs | 11 +- .../src/refund_relayer_extension.rs | 154 +- .../chain-bridge-hub-cumulus/src/lib.rs | 4 +- .../chain-bridge-hub-rococo/src/lib.rs | 2 +- bridges/primitives/chain-kusama/src/lib.rs | 4 +- .../chain-polkadot-bulletin/src/lib.rs | 51 +- bridges/primitives/chain-polkadot/src/lib.rs | 4 +- bridges/primitives/chain-rococo/src/lib.rs | 4 +- bridges/primitives/chain-westend/src/lib.rs | 4 +- bridges/primitives/polkadot-core/src/lib.rs | 37 +- bridges/primitives/runtime/src/extensions.rs | 135 +- .../snowbridge/runtime/test-common/Cargo.toml | 1 - .../assets/asset-hub-rococo/Cargo.toml | 2 - .../assets/asset-hub-rococo/src/lib.rs | 77 +- .../src/weights/frame_system_extensions.rs | 121 -- .../asset-hub-rococo/src/weights/mod.rs | 3 - .../pallet_asset_conversion_tx_payment.rs | 92 - .../src/weights/pallet_transaction_payment.rs | 67 - .../assets/asset-hub-westend/Cargo.toml | 2 - .../assets/asset-hub-westend/src/lib.rs | 77 +- .../src/weights/frame_system_extensions.rs | 121 -- .../asset-hub-westend/src/weights/mod.rs | 3 - .../pallet_asset_conversion_tx_payment.rs | 92 - .../src/weights/pallet_transaction_payment.rs | 67 - .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 1 - .../src/bridge_to_bulletin_config.rs | 4 +- .../src/bridge_to_westend_config.rs | 4 +- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 27 +- .../src/weights/frame_system_extensions.rs | 121 -- .../bridge-hub-rococo/src/weights/mod.rs | 2 - .../src/weights/pallet_transaction_payment.rs | 67 - .../bridge-hub-rococo/tests/snowbridge.rs | 8 +- .../bridge-hub-rococo/tests/tests.rs | 11 +- .../bridge-hubs/bridge-hub-westend/Cargo.toml | 1 - .../src/bridge_to_rococo_config.rs | 4 +- .../bridge-hubs/bridge-hub-westend/src/lib.rs | 25 +- .../src/weights/frame_system_extensions.rs | 121 -- .../bridge-hub-westend/src/weights/mod.rs | 2 - .../src/weights/pallet_transaction_payment.rs | 67 - .../bridge-hub-westend/tests/tests.rs | 11 +- .../collectives-westend/Cargo.toml | 1 - .../collectives-westend/src/lib.rs | 12 +- .../src/weights/frame_system_extensions.rs | 121 -- .../collectives-westend/src/weights/mod.rs | 2 - .../src/weights/pallet_transaction_payment.rs | 67 - .../contracts/contracts-rococo/Cargo.toml | 1 - .../contracts/contracts-rococo/src/lib.rs | 10 +- .../coretime/coretime-rococo/Cargo.toml | 1 - .../coretime/coretime-rococo/src/lib.rs | 9 +- .../src/weights/frame_system_extensions.rs | 121 -- .../coretime-rococo/src/weights/mod.rs | 2 - .../src/weights/pallet_transaction_payment.rs | 67 - .../coretime/coretime-westend/Cargo.toml | 1 - .../coretime/coretime-westend/src/lib.rs | 9 +- .../src/weights/frame_system_extensions.rs | 121 -- .../coretime-westend/src/weights/mod.rs | 2 - .../src/weights/pallet_transaction_payment.rs | 67 - .../glutton/glutton-westend/src/lib.rs | 9 +- .../src/weights/frame_system_extensions.rs | 119 -- .../runtimes/people/people-rococo/Cargo.toml | 1 - .../runtimes/people/people-rococo/src/lib.rs | 9 +- .../src/weights/frame_system_extensions.rs | 121 -- .../people/people-rococo/src/weights/mod.rs | 2 - .../src/weights/pallet_transaction_payment.rs | 67 - .../runtimes/people/people-westend/Cargo.toml | 1 - .../runtimes/people/people-westend/src/lib.rs | 8 +- .../src/weights/frame_system_extensions.rs | 121 -- .../people/people-westend/src/weights/mod.rs | 2 - .../src/weights/pallet_transaction_payment.rs | 67 - .../runtimes/starters/seedling/src/lib.rs | 6 +- .../runtimes/starters/shell/src/lib.rs | 64 +- .../runtimes/testing/penpal/Cargo.toml | 1 - .../runtimes/testing/penpal/src/lib.rs | 26 +- .../testing/rococo-parachain/Cargo.toml | 1 - .../testing/rococo-parachain/src/lib.rs | 7 +- cumulus/polkadot-parachain/Cargo.toml | 1 - .../storage-weight-reclaim/Cargo.toml | 13 +- .../src/benchmarking.rs | 70 - .../storage-weight-reclaim/src/lib.rs | 522 ++++- .../storage-weight-reclaim/src/tests.rs | 484 ----- cumulus/test/client/Cargo.toml | 2 - cumulus/test/client/src/lib.rs | 13 +- cumulus/test/runtime/src/lib.rs | 9 +- cumulus/test/service/Cargo.toml | 2 - cumulus/test/service/src/bench_utils.rs | 4 +- cumulus/test/service/src/lib.rs | 9 +- .../src/reference_docs/extrinsic_encoding.rs | 101 +- .../src/reference_docs/frame_runtime_types.rs | 2 +- docs/sdk/src/reference_docs/mod.rs | 4 +- .../src/reference_docs/signed_extensions.rs | 79 + .../reference_docs/transaction_extensions.rs | 57 - polkadot/node/service/Cargo.toml | 1 - polkadot/node/service/src/benchmarking.rs | 18 +- polkadot/node/test/service/Cargo.toml | 1 - polkadot/node/test/service/src/lib.rs | 11 +- polkadot/runtime/common/Cargo.toml | 1 - polkadot/runtime/common/src/claims.rs | 150 +- polkadot/runtime/rococo/Cargo.toml | 1 - .../constants/src/weights/block_weights.rs | 29 +- .../src/weights/extrinsic_weights.rs | 29 +- polkadot/runtime/rococo/src/lib.rs | 45 +- .../weights/frame_benchmarking_baseline.rs | 43 +- .../rococo/src/weights/frame_system.rs | 103 +- .../src/weights/frame_system_extensions.rs | 123 -- polkadot/runtime/rococo/src/weights/mod.rs | 2 - .../rococo/src/weights/pallet_asset_rate.rs | 63 +- .../src/weights/pallet_balances_balances.rs | 58 +- ...allet_balances_nis_counterpart_balances.rs | 58 +- .../rococo/src/weights/pallet_bounties.rs | 218 +-- .../src/weights/pallet_child_bounties.rs | 181 +- .../src/weights/pallet_conviction_voting.rs | 196 +- .../rococo/src/weights/pallet_identity.rs | 409 ++-- .../rococo/src/weights/pallet_indices.rs | 73 +- .../src/weights/pallet_message_queue.rs | 168 +- .../rococo/src/weights/pallet_multisig.rs | 123 +- .../runtime/rococo/src/weights/pallet_nis.rs | 243 +-- .../rococo/src/weights/pallet_preimage.rs | 252 ++- .../rococo/src/weights/pallet_proxy.rs | 195 +- .../src/weights/pallet_ranked_collective.rs | 66 +- .../rococo/src/weights/pallet_recovery.rs | 186 -- .../pallet_referenda_fellowship_referenda.rs | 235 ++- .../src/weights/pallet_referenda_referenda.rs | 283 +-- .../rococo/src/weights/pallet_scheduler.rs | 146 +- .../runtime/rococo/src/weights/pallet_sudo.rs | 45 +- .../rococo/src/weights/pallet_timestamp.rs | 35 +- .../src/weights/pallet_transaction_payment.rs | 68 - .../rococo/src/weights/pallet_treasury.rs | 233 +-- .../rococo/src/weights/pallet_utility.rs | 47 +- .../rococo/src/weights/pallet_vesting.rs | 254 ++- .../rococo/src/weights/pallet_whitelist.rs | 68 +- .../runtime/rococo/src/weights/pallet_xcm.rs | 90 +- .../weights/pallet_xcm_benchmarks_fungible.rs | 191 -- .../weights/pallet_xcm_benchmarks_generic.rs | 347 ---- .../weights/runtime_common_assigned_slots.rs | 70 +- .../src/weights/runtime_common_auctions.rs | 137 +- .../src/weights/runtime_common_claims.rs | 180 +- .../src/weights/runtime_common_coretime.rs | 86 - .../src/weights/runtime_common_crowdloan.rs | 239 +-- .../runtime_common_identity_migrator.rs | 83 +- .../weights/runtime_common_paras_registrar.rs | 281 +-- .../src/weights/runtime_common_slots.rs | 127 +- .../runtime_parachains_assigner_on_demand.rs | 50 +- .../runtime_parachains_configuration.rs | 48 +- .../weights/runtime_parachains_disputes.rs | 23 +- .../src/weights/runtime_parachains_hrmp.rs | 389 ++-- .../weights/runtime_parachains_inclusion.rs | 45 +- .../weights/runtime_parachains_initializer.rs | 27 +- .../src/weights/runtime_parachains_paras.rs | 368 ++-- .../runtime_parachains_paras_inherent.rs | 429 ++--- polkadot/runtime/test-runtime/Cargo.toml | 1 - polkadot/runtime/test-runtime/src/lib.rs | 40 +- polkadot/runtime/westend/Cargo.toml | 1 - polkadot/runtime/westend/src/lib.rs | 25 +- .../src/weights/frame_system_extensions.rs | 116 -- polkadot/runtime/westend/src/weights/mod.rs | 2 - .../westend/src/weights/pallet_sudo.rs | 11 - .../src/weights/pallet_transaction_payment.rs | 65 - polkadot/xcm/xcm-builder/Cargo.toml | 1 - .../xcm/xcm-builder/src/tests/pay/mock.rs | 12 +- .../xcm/xcm-simulator/fuzzer/src/parachain.rs | 4 +- .../xcm-simulator/fuzzer/src/relay_chain.rs | 4 +- prdoc/pr_2280.prdoc | 144 -- prdoc/pr_3665.prdoc | 11 + substrate/.maintain/frame-weight-template.hbs | 2 +- substrate/bin/node/cli/Cargo.toml | 2 - .../bin/node/cli/benches/block_production.rs | 2 +- substrate/bin/node/cli/benches/executor.rs | 6 +- substrate/bin/node/cli/src/service.rs | 77 +- substrate/bin/node/cli/tests/basic.rs | 26 +- substrate/bin/node/cli/tests/fees.rs | 24 +- .../bin/node/cli/tests/submit_transaction.rs | 10 +- substrate/bin/node/runtime/Cargo.toml | 2 - substrate/bin/node/runtime/src/lib.rs | 165 +- substrate/bin/node/testing/src/bench.rs | 26 +- substrate/bin/node/testing/src/keyring.rs | 44 +- .../client/api/src/notifications/tests.rs | 7 +- substrate/client/db/benches/state_access.rs | 5 +- substrate/client/db/src/lib.rs | 262 +-- substrate/client/db/src/utils.rs | 11 +- .../network-gossip/src/state_machine.rs | 5 +- substrate/client/network/sync/src/blocks.rs | 7 +- substrate/client/transaction-pool/src/lib.rs | 9 +- substrate/frame/alliance/src/weights.rs | 1033 +++++----- .../frame/asset-conversion/src/weights.rs | 126 +- substrate/frame/asset-rate/src/weights.rs | 73 +- substrate/frame/assets/src/weights.rs | 841 ++++---- substrate/frame/babe/src/mock.rs | 5 +- substrate/frame/bags-list/src/weights.rs | 165 +- substrate/frame/balances/Cargo.toml | 1 - .../balances/src/tests/currency_tests.rs | 17 +- substrate/frame/balances/src/tests/mod.rs | 4 +- substrate/frame/balances/src/weights.rs | 98 +- substrate/frame/beefy/src/mock.rs | 6 +- substrate/frame/benchmarking/src/weights.rs | 81 +- substrate/frame/bounties/src/weights.rs | 405 ++-- substrate/frame/broker/src/weights.rs | 357 ++-- substrate/frame/child-bounties/src/weights.rs | 381 ++-- substrate/frame/collective/src/tests.rs | 2 +- substrate/frame/collective/src/weights.rs | 677 ++++--- substrate/frame/contracts/src/weights.rs | 265 +-- .../frame/conviction-voting/src/weights.rs | 405 ++-- .../frame/core-fellowship/src/weights.rs | 429 ++--- substrate/frame/democracy/src/weights.rs | 1093 ++++++----- .../election-provider-multi-phase/src/mock.rs | 2 +- .../src/unsigned.rs | 4 +- .../src/weights.rs | 517 +++-- .../test-staking-e2e/src/mock.rs | 4 +- substrate/frame/elections-phragmen/src/lib.rs | 2 +- .../frame/elections-phragmen/src/weights.rs | 655 ++++--- substrate/frame/examples/basic/src/lib.rs | 76 +- substrate/frame/examples/basic/src/tests.rs | 9 +- .../examples/offchain-worker/src/tests.rs | 22 +- substrate/frame/examples/tasks/src/weights.rs | 78 +- substrate/frame/executive/src/tests.rs | 225 +-- substrate/frame/fast-unstake/src/weights.rs | 473 +++-- substrate/frame/glutton/src/weights.rs | 249 +-- substrate/frame/grandpa/src/mock.rs | 9 +- substrate/frame/identity/src/weights.rs | 825 ++++---- substrate/frame/im-online/src/mock.rs | 4 +- substrate/frame/im-online/src/tests.rs | 4 +- substrate/frame/im-online/src/weights.rs | 85 +- substrate/frame/indices/src/weights.rs | 121 +- substrate/frame/lottery/src/weights.rs | 301 ++- substrate/frame/membership/src/weights.rs | 385 ++-- substrate/frame/message-queue/src/weights.rs | 247 ++- substrate/frame/migrations/src/weights.rs | 183 +- substrate/frame/multisig/src/weights.rs | 243 ++- .../nft-fractionalization/src/weights.rs | 209 +- substrate/frame/nfts/src/weights.rs | 1692 ++++++++--------- substrate/frame/nis/src/weights.rs | 429 ++--- .../frame/nomination-pools/src/weights.rs | 29 +- .../frame/offences/benchmarking/src/mock.rs | 2 +- substrate/frame/parameters/src/weights.rs | 38 +- substrate/frame/preimage/src/weights.rs | 332 ++-- substrate/frame/proxy/src/weights.rs | 377 ++-- .../frame/ranked-collective/src/weights.rs | 353 ++-- substrate/frame/recovery/src/weights.rs | 305 ++- substrate/frame/referenda/src/weights.rs | 1037 +++++----- substrate/frame/remark/src/weights.rs | 37 +- substrate/frame/safe-mode/src/weights.rs | 142 +- substrate/frame/salary/src/weights.rs | 217 +-- substrate/frame/sassafras/src/mock.rs | 5 +- substrate/frame/scheduler/src/weights.rs | 266 ++- substrate/frame/session/src/weights.rs | 117 +- substrate/frame/society/src/weights.rs | 974 +++------- substrate/frame/src/lib.rs | 6 +- substrate/frame/staking/src/weights.rs | 422 ++-- .../frame/state-trie-migration/src/lib.rs | 2 +- .../frame/state-trie-migration/src/weights.rs | 118 +- substrate/frame/sudo/src/benchmarking.rs | 29 +- substrate/frame/sudo/src/extension.rs | 78 +- substrate/frame/sudo/src/lib.rs | 4 +- substrate/frame/sudo/src/weights.rs | 71 +- .../src/construct_runtime/expand/inherent.rs | 18 +- .../src/construct_runtime/expand/metadata.rs | 6 +- .../src/construct_runtime/expand/origin.rs | 14 - substrate/frame/support/src/dispatch.rs | 29 +- substrate/frame/support/src/lib.rs | 8 +- .../frame/support/src/traits/dispatch.rs | 21 +- substrate/frame/support/src/traits/misc.rs | 13 +- .../support/src/transaction_extensions.rs | 89 - .../support/src/weights/block_weights.rs | 31 +- .../support/src/weights/extrinsic_weights.rs | 31 +- .../deprecated_where_block.stderr | 4 +- substrate/frame/support/test/tests/pallet.rs | 143 +- .../support/test/tests/pallet_instance.rs | 2 +- substrate/frame/support/test/tests/runtime.rs | 2 +- .../test/tests/runtime_legacy_ordering.rs | 4 +- .../system/benchmarking/src/extensions.rs | 213 --- .../frame/system/benchmarking/src/lib.rs | 1 - .../frame/system/benchmarking/src/mock.rs | 1 - .../system/src/extensions/check_genesis.rs | 33 +- .../system/src/extensions/check_mortality.rs | 83 +- .../src/extensions/check_non_zero_sender.rs | 95 +- .../system/src/extensions/check_nonce.rs | 184 +- .../src/extensions/check_spec_version.rs | 33 +- .../system/src/extensions/check_tx_version.rs | 32 +- .../system/src/extensions/check_weight.rs | 228 +-- substrate/frame/system/src/extensions/mod.rs | 3 - .../frame/system/src/extensions/weights.rs | 196 -- substrate/frame/system/src/lib.rs | 10 +- substrate/frame/system/src/offchain.rs | 22 +- substrate/frame/system/src/weights.rs | 249 ++- substrate/frame/timestamp/src/weights.rs | 65 +- substrate/frame/tips/src/weights.rs | 241 +-- .../frame/transaction-payment/Cargo.toml | 9 - .../asset-conversion-tx-payment/Cargo.toml | 12 - .../asset-conversion-tx-payment/README.md | 2 +- .../src/benchmarking.rs | 125 -- .../asset-conversion-tx-payment/src/lib.rs | 233 +-- .../asset-conversion-tx-payment/src/mock.rs | 70 +- .../asset-conversion-tx-payment/src/tests.rs | 150 +- .../src/weights.rs | 150 -- .../asset-tx-payment/Cargo.toml | 1 - .../asset-tx-payment/README.md | 2 +- .../asset-tx-payment/src/benchmarking.rs | 123 -- .../asset-tx-payment/src/lib.rs | 199 +- .../asset-tx-payment/src/mock.rs | 54 +- .../asset-tx-payment/src/tests.rs | 184 +- .../asset-tx-payment/src/weights.rs | 146 -- .../skip-feeless-payment/src/lib.rs | 111 +- .../skip-feeless-payment/src/mock.rs | 30 +- .../skip-feeless-payment/src/tests.rs | 5 +- .../transaction-payment/src/benchmarking.rs | 81 - .../frame/transaction-payment/src/lib.rs | 146 +- .../frame/transaction-payment/src/mock.rs | 10 - .../frame/transaction-payment/src/payment.rs | 56 +- .../frame/transaction-payment/src/tests.rs | 444 +++-- .../frame/transaction-payment/src/types.rs | 2 +- .../frame/transaction-payment/src/weights.rs | 92 - .../frame/transaction-storage/src/weights.rs | 185 +- substrate/frame/treasury/src/weights.rs | 348 ++-- substrate/frame/tx-pause/src/weights.rs | 38 +- substrate/frame/uniques/src/weights.rs | 368 ++-- substrate/frame/utility/src/weights.rs | 161 +- substrate/frame/vesting/src/weights.rs | 234 ++- substrate/frame/whitelist/src/weights.rs | 193 +- substrate/primitives/inherents/src/lib.rs | 4 +- substrate/primitives/metadata-ir/src/lib.rs | 2 +- substrate/primitives/metadata-ir/src/types.rs | 19 +- substrate/primitives/metadata-ir/src/v14.rs | 10 +- substrate/primitives/metadata-ir/src/v15.rs | 8 +- substrate/primitives/runtime/Cargo.toml | 2 - .../runtime/src/generic/checked_extrinsic.rs | 112 +- .../primitives/runtime/src/generic/mod.rs | 4 +- .../src/generic/unchecked_extrinsic.rs | 730 +++---- substrate/primitives/runtime/src/lib.rs | 19 +- substrate/primitives/runtime/src/testing.rs | 195 +- .../runtime/src/{traits/mod.rs => traits.rs} | 244 ++- .../as_transaction_extension.rs | 133 -- .../dispatch_transaction.rs | 141 -- .../src/traits/transaction_extension/mod.rs | 526 ----- .../runtime/src/transaction_validity.rs | 6 +- substrate/scripts/run_all_benchmarks.sh | 13 - substrate/test-utils/runtime/src/extrinsic.rs | 17 +- substrate/test-utils/runtime/src/lib.rs | 93 +- .../benchmarking-cli/src/pallet/template.hbs | 4 - .../frame/remote-externalities/src/lib.rs | 5 +- substrate/utils/frame/rpc/client/src/lib.rs | 8 +- templates/minimal/runtime/src/lib.rs | 4 +- templates/parachain/runtime/Cargo.toml | 2 - templates/parachain/runtime/src/lib.rs | 10 +- templates/solochain/node/Cargo.toml | 1 - templates/solochain/node/src/benchmarking.rs | 9 +- templates/solochain/runtime/Cargo.toml | 1 - templates/solochain/runtime/src/lib.rs | 12 +- 350 files changed, 15770 insertions(+), 24248 deletions(-) delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/frame_system_extensions.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion_tx_payment.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_transaction_payment.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/frame_system_extensions.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion_tx_payment.rs delete mode 100644 cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_transaction_payment.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/frame_system_extensions.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_transaction_payment.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/frame_system_extensions.rs delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_transaction_payment.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/frame_system_extensions.rs delete mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_transaction_payment.rs delete mode 100644 cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/frame_system_extensions.rs delete mode 100644 cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_transaction_payment.rs delete mode 100644 cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/frame_system_extensions.rs delete mode 100644 cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_transaction_payment.rs delete mode 100644 cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/frame_system_extensions.rs delete mode 100644 cumulus/parachains/runtimes/people/people-rococo/src/weights/frame_system_extensions.rs delete mode 100644 cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_transaction_payment.rs delete mode 100644 cumulus/parachains/runtimes/people/people-westend/src/weights/frame_system_extensions.rs delete mode 100644 cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_transaction_payment.rs delete mode 100644 cumulus/primitives/storage-weight-reclaim/src/benchmarking.rs delete mode 100644 cumulus/primitives/storage-weight-reclaim/src/tests.rs create mode 100644 docs/sdk/src/reference_docs/signed_extensions.rs delete mode 100644 docs/sdk/src/reference_docs/transaction_extensions.rs delete mode 100644 polkadot/runtime/rococo/src/weights/frame_system_extensions.rs delete mode 100644 polkadot/runtime/rococo/src/weights/pallet_recovery.rs delete mode 100644 polkadot/runtime/rococo/src/weights/pallet_transaction_payment.rs delete mode 100644 polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_fungible.rs delete mode 100644 polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_generic.rs delete mode 100644 polkadot/runtime/rococo/src/weights/runtime_common_coretime.rs delete mode 100644 polkadot/runtime/westend/src/weights/frame_system_extensions.rs delete mode 100644 polkadot/runtime/westend/src/weights/pallet_transaction_payment.rs delete mode 100644 prdoc/pr_2280.prdoc create mode 100644 prdoc/pr_3665.prdoc delete mode 100644 substrate/frame/support/src/transaction_extensions.rs delete mode 100644 substrate/frame/system/benchmarking/src/extensions.rs delete mode 100644 substrate/frame/system/src/extensions/weights.rs delete mode 100644 substrate/frame/transaction-payment/asset-conversion-tx-payment/src/benchmarking.rs delete mode 100644 substrate/frame/transaction-payment/asset-conversion-tx-payment/src/weights.rs delete mode 100644 substrate/frame/transaction-payment/asset-tx-payment/src/benchmarking.rs delete mode 100644 substrate/frame/transaction-payment/asset-tx-payment/src/weights.rs delete mode 100644 substrate/frame/transaction-payment/src/benchmarking.rs delete mode 100644 substrate/frame/transaction-payment/src/weights.rs rename substrate/primitives/runtime/src/{traits/mod.rs => traits.rs} (94%) delete mode 100644 substrate/primitives/runtime/src/traits/transaction_extension/as_transaction_extension.rs delete mode 100644 substrate/primitives/runtime/src/traits/transaction_extension/dispatch_transaction.rs delete mode 100644 substrate/primitives/runtime/src/traits/transaction_extension/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 37c5a5177c0..8cbbbce209a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4046,13 +4046,11 @@ dependencies = [ "cumulus-primitives-proof-size-hostfunction", "cumulus-test-runtime", "docify 0.2.7", - "frame-benchmarking", "frame-support", "frame-system", "log", "parity-scale-codec", "scale-info", - "sp-core", "sp-io", "sp-runtime", "sp-std 14.0.0", @@ -5899,7 +5897,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29f9df8a11882c4e3335eb2d18a0137c505d9ca927470b0cac9c6f0ae07d28f7" dependencies = [ - "rustix 0.38.25", + "rustix 0.38.21", "windows-sys 0.48.0", ] @@ -6784,7 +6782,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi 0.3.2", - "rustix 0.38.25", + "rustix 0.38.21", "windows-sys 0.48.0", ] @@ -7792,9 +7790,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.11" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" +checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" [[package]] name = "lioness" @@ -9040,7 +9038,6 @@ dependencies = [ name = "pallet-asset-conversion-tx-payment" version = "10.0.0" dependencies = [ - "frame-benchmarking", "frame-support", "frame-system", "pallet-asset-conversion", @@ -10989,7 +10986,6 @@ dependencies = [ name = "pallet-transaction-payment" version = "28.0.0" dependencies = [ - "frame-benchmarking", "frame-support", "frame-system", "pallet-balances", @@ -14251,7 +14247,7 @@ dependencies = [ "hex", "lazy_static", "procfs-core", - "rustix 0.38.25", + "rustix 0.38.21", ] [[package]] @@ -15376,14 +15372,14 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.25" +version = "0.38.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" +checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" dependencies = [ "bitflags 2.4.0", "errno", "libc", - "linux-raw-sys 0.4.11", + "linux-raw-sys 0.4.10", "windows-sys 0.48.0", ] @@ -18715,7 +18711,7 @@ dependencies = [ [[package]] name = "sp-crypto-ec-utils" version = "0.4.1" -source = "git+https://github.com/paritytech/polkadot-sdk#838a534da874cf6071fba1df07643c6c5b033ae0" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "ark-bls12-377", "ark-bls12-377-ext", @@ -19021,7 +19017,6 @@ dependencies = [ "sp-tracing 16.0.0", "sp-weights", "substrate-test-runtime-client", - "tuplex", "zstd 0.12.4", ] @@ -19070,7 +19065,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "11.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#838a534da874cf6071fba1df07643c6c5b033ae0" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "Inflector", "proc-macro-crate 1.3.1", @@ -20289,7 +20284,7 @@ dependencies = [ "cfg-if", "fastrand 2.0.0", "redox_syscall 0.4.1", - "rustix 0.38.25", + "rustix 0.38.21", "windows-sys 0.48.0", ] @@ -20308,7 +20303,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" dependencies = [ - "rustix 0.38.25", + "rustix 0.38.21", "windows-sys 0.48.0", ] @@ -21154,12 +21149,6 @@ dependencies = [ "utf-8", ] -[[package]] -name = "tuplex" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "676ac81d5454c4dcf37955d34fa8626ede3490f744b86ca14a7b90168d2a08aa" - [[package]] name = "twox-hash" version = "1.6.3" diff --git a/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml index ee54f15f38b..fac88b20ca5 100644 --- a/bridges/bin/runtime-common/Cargo.toml +++ b/bridges/bin/runtime-common/Cargo.toml @@ -93,7 +93,6 @@ runtime-benchmarks = [ "pallet-bridge-messages/runtime-benchmarks", "pallet-bridge-parachains/runtime-benchmarks", "pallet-bridge-relayers/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", diff --git a/bridges/bin/runtime-common/src/lib.rs b/bridges/bin/runtime-common/src/lib.rs index 035077408c4..2722f6f1c6d 100644 --- a/bridges/bin/runtime-common/src/lib.rs +++ b/bridges/bin/runtime-common/src/lib.rs @@ -105,48 +105,43 @@ macro_rules! generate_bridge_reject_obsolete_headers_and_messages { ($call:ty, $account_id:ty, $($filter_call:ty),*) => { #[derive(Clone, codec::Decode, Default, codec::Encode, Eq, PartialEq, sp_runtime::RuntimeDebug, scale_info::TypeInfo)] pub struct BridgeRejectObsoleteHeadersAndMessages; - impl sp_runtime::traits::TransactionExtensionBase for BridgeRejectObsoleteHeadersAndMessages { + impl sp_runtime::traits::SignedExtension for BridgeRejectObsoleteHeadersAndMessages { const IDENTIFIER: &'static str = "BridgeRejectObsoleteHeadersAndMessages"; - type Implicit = (); - } - impl sp_runtime::traits::TransactionExtension<$call, Context> for BridgeRejectObsoleteHeadersAndMessages { + type AccountId = $account_id; + type Call = $call; + type AdditionalSigned = (); type Pre = (); - type Val = (); + + fn additional_signed(&self) -> sp_std::result::Result< + (), + sp_runtime::transaction_validity::TransactionValidityError, + > { + Ok(()) + } fn validate( &self, - origin: <$call as sp_runtime::traits::Dispatchable>::RuntimeOrigin, - call: &$call, - _info: &sp_runtime::traits::DispatchInfoOf<$call>, + _who: &Self::AccountId, + call: &Self::Call, + _info: &sp_runtime::traits::DispatchInfoOf, _len: usize, - _context: &mut Context, - _self_implicit: Self::Implicit, - _inherited_implication: &impl codec::Encode, - ) -> Result< - ( - sp_runtime::transaction_validity::ValidTransaction, - Self::Val, - <$call as sp_runtime::traits::Dispatchable>::RuntimeOrigin, - ), sp_runtime::transaction_validity::TransactionValidityError - > { - let tx_validity = sp_runtime::transaction_validity::ValidTransaction::default(); + ) -> sp_runtime::transaction_validity::TransactionValidity { + let valid = sp_runtime::transaction_validity::ValidTransaction::default(); $( - let call_filter_validity = <$filter_call as $crate::BridgeRuntimeFilterCall<$call>>::validate(call)?; - let tx_validity = tx_validity.combine_with(call_filter_validity); + let valid = valid + .combine_with(<$filter_call as $crate::BridgeRuntimeFilterCall<$call>>::validate(call)?); )* - Ok((tx_validity, (), origin)) + Ok(valid) } - fn prepare( + fn pre_dispatch( self, - _val: Self::Val, - _origin: &<$call as sp_runtime::traits::Dispatchable>::RuntimeOrigin, - _call: &$call, - _info: &sp_runtime::traits::DispatchInfoOf<$call>, - _len: usize, - _context: &Context, + who: &Self::AccountId, + call: &Self::Call, + info: &sp_runtime::traits::DispatchInfoOf, + len: usize, ) -> Result { - Ok(()) + self.validate(who, call, info, len).map(drop) } } }; @@ -155,14 +150,12 @@ macro_rules! generate_bridge_reject_obsolete_headers_and_messages { #[cfg(test)] mod tests { use crate::BridgeRuntimeFilterCall; - use codec::Encode; - use frame_support::assert_err; + use frame_support::{assert_err, assert_ok}; use sp_runtime::{ - traits::DispatchTransaction, + traits::SignedExtension, transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction}, }; - #[derive(Encode)] pub struct MockCall { data: u32, } @@ -213,20 +206,17 @@ mod tests { ); assert_err!( - BridgeRejectObsoleteHeadersAndMessages.validate_only((), &MockCall { data: 1 }, &(), 0), + BridgeRejectObsoleteHeadersAndMessages.validate(&(), &MockCall { data: 1 }, &(), 0), InvalidTransaction::Custom(1) ); assert_err!( - BridgeRejectObsoleteHeadersAndMessages.validate_only((), &MockCall { data: 2 }, &(), 0), + BridgeRejectObsoleteHeadersAndMessages.validate(&(), &MockCall { data: 2 }, &(), 0), InvalidTransaction::Custom(2) ); - assert_eq!( - BridgeRejectObsoleteHeadersAndMessages - .validate_only((), &MockCall { data: 3 }, &(), 0) - .unwrap() - .0, + assert_ok!( + BridgeRejectObsoleteHeadersAndMessages.validate(&(), &MockCall { data: 3 }, &(), 0), ValidTransaction { priority: 3, ..Default::default() } ) } diff --git a/bridges/bin/runtime-common/src/mock.rs b/bridges/bin/runtime-common/src/mock.rs index f147f1404f0..8877a4fd95c 100644 --- a/bridges/bin/runtime-common/src/mock.rs +++ b/bridges/bin/runtime-common/src/mock.rs @@ -164,7 +164,6 @@ impl pallet_balances::Config for TestRuntime { type AccountStore = System; } -#[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig as pallet_transaction_payment::DefaultConfig)] impl pallet_transaction_payment::Config for TestRuntime { type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; type OperationalFeeMultiplier = ConstU8<5>; @@ -177,6 +176,7 @@ impl pallet_transaction_payment::Config for TestRuntime { MinimumMultiplier, MaximumMultiplier, >; + type RuntimeEvent = RuntimeEvent; } impl pallet_bridge_grandpa::Config for TestRuntime { diff --git a/bridges/bin/runtime-common/src/priority_calculator.rs b/bridges/bin/runtime-common/src/priority_calculator.rs index 0c53018330e..a597fb9e2f4 100644 --- a/bridges/bin/runtime-common/src/priority_calculator.rs +++ b/bridges/bin/runtime-common/src/priority_calculator.rs @@ -169,15 +169,12 @@ mod integrity_tests { // nodes to the proof (x0.5 because we expect some nodes to be reused) let estimated_message_size = 512; // let's say all our messages have the same dispatch weight - let estimated_message_dispatch_weight = >::WeightInfo::message_dispatch_weight( - estimated_message_size - ); + let estimated_message_dispatch_weight = + Runtime::WeightInfo::message_dispatch_weight(estimated_message_size); // messages proof argument size is (for every message) messages size + some additional // trie nodes. Some of them are reused by different messages, so let's take 2/3 of default // "overhead" constant - let messages_proof_size = >::WeightInfo::expected_extra_storage_proof_size() + let messages_proof_size = Runtime::WeightInfo::expected_extra_storage_proof_size() .saturating_mul(2) .saturating_div(3) .saturating_add(estimated_message_size) @@ -185,7 +182,7 @@ mod integrity_tests { // finally we are able to estimate transaction size and weight let transaction_size = base_tx_size.saturating_add(messages_proof_size); - let transaction_weight = >::WeightInfo::receive_messages_proof_weight( + let transaction_weight = Runtime::WeightInfo::receive_messages_proof_weight( &PreComputedSize(transaction_size as _), messages as _, estimated_message_dispatch_weight.saturating_mul(messages), diff --git a/bridges/bin/runtime-common/src/refund_relayer_extension.rs b/bridges/bin/runtime-common/src/refund_relayer_extension.rs index b912f8445ac..bfcb82ad166 100644 --- a/bridges/bin/runtime-common/src/refund_relayer_extension.rs +++ b/bridges/bin/runtime-common/src/refund_relayer_extension.rs @@ -48,12 +48,9 @@ use pallet_transaction_payment::{Config as TransactionPaymentConfig, OnChargeTra use pallet_utility::{Call as UtilityCall, Config as UtilityConfig, Pallet as UtilityPallet}; use scale_info::TypeInfo; use sp_runtime::{ - traits::{ - AsSystemOriginSigner, DispatchInfoOf, Dispatchable, Get, PostDispatchInfoOf, - TransactionExtension, TransactionExtensionBase, ValidateResult, Zero, - }, + traits::{DispatchInfoOf, Dispatchable, Get, PostDispatchInfoOf, SignedExtension, Zero}, transaction_validity::{ - InvalidTransaction, TransactionPriority, TransactionValidityError, ValidTransactionBuilder, + TransactionPriority, TransactionValidity, TransactionValidityError, ValidTransactionBuilder, }, DispatchResult, FixedPointOperand, RuntimeDebug, }; @@ -242,8 +239,8 @@ pub enum RelayerAccountAction { Slash(AccountId, RewardsAccountParams), } -/// Everything common among our refund transaction extensions. -pub trait RefundTransactionExtension: +/// Everything common among our refund signed extensions. +pub trait RefundSignedExtension: 'static + Clone + Codec + sp_std::fmt::Debug + Default + Eq + PartialEq + Send + Sync + TypeInfo where >::BridgedChain: @@ -459,8 +456,8 @@ where } } -/// Adapter that allow implementing `sp_runtime::traits::TransactionExtension` for any -/// `RefundTransactionExtension`. +/// Adapter that allow implementing `sp_runtime::traits::SignedExtension` for any +/// `RefundSignedExtension`. #[derive( DefaultNoBound, CloneNoBound, @@ -471,13 +468,12 @@ where RuntimeDebugNoBound, TypeInfo, )] -pub struct RefundTransactionExtensionAdapter(T) +pub struct RefundSignedExtensionAdapter(T) where >::BridgedChain: Chain; -impl TransactionExtensionBase - for RefundTransactionExtensionAdapter +impl SignedExtension for RefundSignedExtensionAdapter where >::BridgedChain: Chain, @@ -487,35 +483,22 @@ where + MessagesCallSubType::Instance>, { const IDENTIFIER: &'static str = T::Id::STR; - type Implicit = (); -} - -impl TransactionExtension, Context> - for RefundTransactionExtensionAdapter -where - >::BridgedChain: - Chain, - CallOf: Dispatchable - + IsSubType, T::Runtime>> - + GrandpaCallSubType - + MessagesCallSubType::Instance>, - as Dispatchable>::RuntimeOrigin: - AsSystemOriginSigner> + Clone, -{ + type AccountId = AccountIdOf; + type Call = CallOf; + type AdditionalSigned = (); type Pre = Option>>; - type Val = Option; + + fn additional_signed(&self) -> Result<(), TransactionValidityError> { + Ok(()) + } fn validate( &self, - origin: as Dispatchable>::RuntimeOrigin, - call: &CallOf, - _info: &DispatchInfoOf>, + who: &Self::AccountId, + call: &Self::Call, + _info: &DispatchInfoOf, _len: usize, - _context: &mut Context, - _self_implicit: Self::Implicit, - _inherited_implication: &impl Encode, - ) -> ValidateResult> { - let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?; + ) -> TransactionValidity { // this is the only relevant line of code for the `pre_dispatch` // // we're not calling `validate` from `pre_dispatch` directly because of performance @@ -528,12 +511,12 @@ where // we only boost priority of presumably correct message delivery transactions let bundled_messages = match T::bundled_messages_for_priority_boost(parsed_call.as_ref()) { Some(bundled_messages) => bundled_messages, - None => return Ok((Default::default(), parsed_call, origin)), + None => return Ok(Default::default()), }; // we only boost priority if relayer has staked required balance if !RelayersPallet::::is_registration_active(who) { - return Ok((Default::default(), parsed_call, origin)) + return Ok(Default::default()) } // compute priority boost @@ -552,21 +535,20 @@ where priority_boost, ); - let validity = valid_transaction.build()?; - Ok((validity, parsed_call, origin)) + valid_transaction.build() } - fn prepare( + fn pre_dispatch( self, - val: Self::Val, - origin: & as Dispatchable>::RuntimeOrigin, - _call: &CallOf, - _info: &DispatchInfoOf>, + who: &Self::AccountId, + call: &Self::Call, + _info: &DispatchInfoOf, _len: usize, - _context: &Context, ) -> Result { - let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?; - Ok(val.map(|call_info| { + // this is a relevant piece of `validate` that we need here (in `pre_dispatch`) + let parsed_call = T::parse_and_check_for_obsolete_call(call)?; + + Ok(parsed_call.map(|call_info| { log::trace!( target: "runtime::bridge", "{} via {:?} parsed bridge transaction in pre-dispatch: {:?}", @@ -579,14 +561,13 @@ where } fn post_dispatch( - pre: Self::Pre, - info: &DispatchInfoOf>, - post_info: &PostDispatchInfoOf>, + pre: Option, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, len: usize, result: &DispatchResult, - _context: &Context, ) -> Result<(), TransactionValidityError> { - let call_result = T::analyze_call_result(Some(pre), info, post_info, len, result); + let call_result = T::analyze_call_result(pre, info, post_info, len, result); match call_result { RelayerAccountAction::None => (), @@ -614,7 +595,7 @@ where } } -/// Transaction extension that refunds a relayer for new messages coming from a parachain. +/// Signed extension that refunds a relayer for new messages coming from a parachain. /// /// Also refunds relayer for successful finality delivery if it comes in batch (`utility.batchAll`) /// with message delivery transaction. Batch may deliver either both relay chain header and @@ -655,7 +636,7 @@ pub struct RefundBridgedParachainMessages, ); -impl RefundTransactionExtension +impl RefundSignedExtension for RefundBridgedParachainMessages where Self: 'static + Send + Sync, @@ -749,13 +730,13 @@ where } } -/// Transaction extension that refunds a relayer for new messages coming from a standalone (GRANDPA) +/// Signed extension that refunds a relayer for new messages coming from a standalone (GRANDPA) /// chain. /// /// Also refunds relayer for successful finality delivery if it comes in batch (`utility.batchAll`) /// with message delivery transaction. Batch may deliver either both relay chain header and -/// parachain head, or just parachain head. Corresponding headers must be used in messages proof -/// verification. +/// parachain head, or just parachain head. Corresponding headers must be used in messages +/// proof verification. /// /// Extension does not refund transaction tip due to security reasons. #[derive( @@ -790,7 +771,7 @@ pub struct RefundBridgedGrandpaMessages, ); -impl RefundTransactionExtension +impl RefundSignedExtension for RefundBridgedGrandpaMessages where Self: 'static + Send + Sync, @@ -888,8 +869,8 @@ mod tests { Call as ParachainsCall, Pallet as ParachainsPallet, RelayBlockHash, }; use sp_runtime::{ - traits::{ConstU64, DispatchTransaction, Header as HeaderT}, - transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction}, + traits::{ConstU64, Header as HeaderT}, + transaction_validity::{InvalidTransaction, ValidTransaction}, DispatchError, }; @@ -918,7 +899,7 @@ mod tests { ConstU64<1>, StrTestExtension, >; - type TestGrandpaExtension = RefundTransactionExtensionAdapter; + type TestGrandpaExtension = RefundSignedExtensionAdapter; type TestExtensionProvider = RefundBridgedParachainMessages< TestRuntime, DefaultRefundableParachainId<(), TestParachain>, @@ -927,7 +908,7 @@ mod tests { ConstU64<1>, StrTestExtension, >; - type TestExtension = RefundTransactionExtensionAdapter; + type TestExtension = RefundSignedExtensionAdapter; fn initial_balance_of_relayer_account_at_this_chain() -> ThisChainBalance { let test_stake: ThisChainBalance = TestStake::get(); @@ -1426,28 +1407,14 @@ mod tests { fn run_validate(call: RuntimeCall) -> TransactionValidity { let extension: TestExtension = - RefundTransactionExtensionAdapter(RefundBridgedParachainMessages(PhantomData)); - extension - .validate_only( - Some(relayer_account_at_this_chain()).into(), - &call, - &DispatchInfo::default(), - 0, - ) - .map(|res| res.0) + RefundSignedExtensionAdapter(RefundBridgedParachainMessages(PhantomData)); + extension.validate(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) } fn run_grandpa_validate(call: RuntimeCall) -> TransactionValidity { let extension: TestGrandpaExtension = - RefundTransactionExtensionAdapter(RefundBridgedGrandpaMessages(PhantomData)); - extension - .validate_only( - Some(relayer_account_at_this_chain()).into(), - &call, - &DispatchInfo::default(), - 0, - ) - .map(|res| res.0) + RefundSignedExtensionAdapter(RefundBridgedGrandpaMessages(PhantomData)); + extension.validate(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) } fn run_validate_ignore_priority(call: RuntimeCall) -> TransactionValidity { @@ -1461,30 +1428,16 @@ mod tests { call: RuntimeCall, ) -> Result>, TransactionValidityError> { let extension: TestExtension = - RefundTransactionExtensionAdapter(RefundBridgedParachainMessages(PhantomData)); - extension - .validate_and_prepare( - Some(relayer_account_at_this_chain()).into(), - &call, - &DispatchInfo::default(), - 0, - ) - .map(|(pre, _)| pre) + RefundSignedExtensionAdapter(RefundBridgedParachainMessages(PhantomData)); + extension.pre_dispatch(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) } fn run_grandpa_pre_dispatch( call: RuntimeCall, ) -> Result>, TransactionValidityError> { let extension: TestGrandpaExtension = - RefundTransactionExtensionAdapter(RefundBridgedGrandpaMessages(PhantomData)); - extension - .validate_and_prepare( - Some(relayer_account_at_this_chain()).into(), - &call, - &DispatchInfo::default(), - 0, - ) - .map(|(pre, _)| pre) + RefundSignedExtensionAdapter(RefundBridgedGrandpaMessages(PhantomData)); + extension.pre_dispatch(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) } fn dispatch_info() -> DispatchInfo { @@ -1507,12 +1460,11 @@ mod tests { dispatch_result: DispatchResult, ) { let post_dispatch_result = TestExtension::post_dispatch( - pre_dispatch_data, + Some(pre_dispatch_data), &dispatch_info(), &post_dispatch_info(), 1024, &dispatch_result, - &(), ); assert_eq!(post_dispatch_result, Ok(())); } diff --git a/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs b/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs index f186f6427ae..c49aa4b8563 100644 --- a/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs +++ b/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs @@ -26,7 +26,7 @@ pub use bp_polkadot_core::{ }; use bp_messages::*; -use bp_polkadot_core::SuffixedCommonTransactionExtension; +use bp_polkadot_core::SuffixedCommonSignedExtension; use bp_runtime::extensions::{ BridgeRejectObsoleteHeadersAndMessages, RefundBridgedParachainMessagesSchema, }; @@ -164,7 +164,7 @@ pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 1024; pub const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 4096; /// Signed extension that is used by all bridge hubs. -pub type TransactionExtension = SuffixedCommonTransactionExtension<( +pub type SignedExtension = SuffixedCommonSignedExtension<( BridgeRejectObsoleteHeadersAndMessages, RefundBridgedParachainMessagesSchema, )>; diff --git a/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs b/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs index 992ef1bd7a1..c4e697fbe95 100644 --- a/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs +++ b/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs @@ -107,5 +107,5 @@ frame_support::parameter_types! { /// Transaction fee that is paid at the Rococo BridgeHub for delivering single outbound message confirmation. /// (initially was calculated by test `BridgeHubRococo::can_calculate_fee_for_complex_message_confirmation_transaction` + `33%`) - pub const BridgeHubRococoBaseConfirmationFeeInRocs: u128 = 5_380_904_835; + pub const BridgeHubRococoBaseConfirmationFeeInRocs: u128 = 5_380_829_647; } diff --git a/bridges/primitives/chain-kusama/src/lib.rs b/bridges/primitives/chain-kusama/src/lib.rs index 253a1010e83..e3b4d0520f6 100644 --- a/bridges/primitives/chain-kusama/src/lib.rs +++ b/bridges/primitives/chain-kusama/src/lib.rs @@ -59,8 +59,8 @@ impl ChainWithGrandpa for Kusama { const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } -// The TransactionExtension used by Kusama. -pub use bp_polkadot_core::CommonTransactionExtension as TransactionExtension; +// The SignedExtension used by Kusama. +pub use bp_polkadot_core::CommonSignedExtension as SignedExtension; /// Name of the parachains pallet in the Kusama runtime. pub const PARAS_PALLET_NAME: &str = "Paras"; diff --git a/bridges/primitives/chain-polkadot-bulletin/src/lib.rs b/bridges/primitives/chain-polkadot-bulletin/src/lib.rs index 73dd122bd15..f2eebf93124 100644 --- a/bridges/primitives/chain-polkadot-bulletin/src/lib.rs +++ b/bridges/primitives/chain-polkadot-bulletin/src/lib.rs @@ -25,7 +25,7 @@ use bp_runtime::{ decl_bridge_finality_runtime_apis, decl_bridge_messages_runtime_apis, extensions::{ CheckEra, CheckGenesis, CheckNonZeroSender, CheckNonce, CheckSpecVersion, CheckTxVersion, - CheckWeight, GenericTransactionExtension, GenericTransactionExtensionSchema, + CheckWeight, GenericSignedExtension, GenericSignedExtensionSchema, }, Chain, ChainId, TransactionEra, }; @@ -37,12 +37,7 @@ use frame_support::{ }; use frame_system::limits; use scale_info::TypeInfo; -use sp_runtime::{ - impl_tx_ext_default, - traits::{Dispatchable, TransactionExtensionBase}, - transaction_validity::TransactionValidityError, - Perbill, -}; +use sp_runtime::{traits::DispatchInfoOf, transaction_validity::TransactionValidityError, Perbill}; // This chain reuses most of Polkadot primitives. pub use bp_polkadot_core::{ @@ -76,10 +71,10 @@ pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 1024; pub const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 4096; /// This signed extension is used to ensure that the chain transactions are signed by proper -pub type ValidateSigned = GenericTransactionExtensionSchema<(), ()>; +pub type ValidateSigned = GenericSignedExtensionSchema<(), ()>; /// Signed extension schema, used by Polkadot Bulletin. -pub type TransactionExtensionSchema = GenericTransactionExtension<( +pub type SignedExtensionSchema = GenericSignedExtension<( ( CheckNonZeroSender, CheckSpecVersion, @@ -92,30 +87,34 @@ pub type TransactionExtensionSchema = GenericTransactionExtension<( ValidateSigned, )>; -/// Transaction extension, used by Polkadot Bulletin. +/// Signed extension, used by Polkadot Bulletin. #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -pub struct TransactionExtension(TransactionExtensionSchema); +pub struct SignedExtension(SignedExtensionSchema); -impl TransactionExtensionBase for TransactionExtension { +impl sp_runtime::traits::SignedExtension for SignedExtension { const IDENTIFIER: &'static str = "Not needed."; - type Implicit = ::Implicit; + type AccountId = (); + type Call = (); + type AdditionalSigned = + ::AdditionalSigned; + type Pre = (); - fn implicit(&self) -> Result { - ::implicit(&self.0) + fn additional_signed(&self) -> Result { + self.0.additional_signed() } -} -impl sp_runtime::traits::TransactionExtension for TransactionExtension -where - C: Dispatchable, -{ - type Pre = (); - type Val = (); - - impl_tx_ext_default!(C; Context; validate prepare); + fn pre_dispatch( + self, + _who: &Self::AccountId, + _call: &Self::Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> Result { + Ok(()) + } } -impl TransactionExtension { +impl SignedExtension { /// Create signed extension from its components. pub fn from_params( spec_version: u32, @@ -124,7 +123,7 @@ impl TransactionExtension { genesis_hash: Hash, nonce: Nonce, ) -> Self { - Self(GenericTransactionExtension::new( + Self(GenericSignedExtension::new( ( ( (), // non-zero sender diff --git a/bridges/primitives/chain-polkadot/src/lib.rs b/bridges/primitives/chain-polkadot/src/lib.rs index e5e2e7c3a04..fc5e10308a8 100644 --- a/bridges/primitives/chain-polkadot/src/lib.rs +++ b/bridges/primitives/chain-polkadot/src/lib.rs @@ -61,8 +61,8 @@ impl ChainWithGrandpa for Polkadot { const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } -/// The TransactionExtension used by Polkadot. -pub type TransactionExtension = SuffixedCommonTransactionExtension; +/// The SignedExtension used by Polkadot. +pub type SignedExtension = SuffixedCommonSignedExtension; /// Name of the parachains pallet in the Polkadot runtime. pub const PARAS_PALLET_NAME: &str = "Paras"; diff --git a/bridges/primitives/chain-rococo/src/lib.rs b/bridges/primitives/chain-rococo/src/lib.rs index 267c6b2b1f0..f1b256f0f09 100644 --- a/bridges/primitives/chain-rococo/src/lib.rs +++ b/bridges/primitives/chain-rococo/src/lib.rs @@ -59,8 +59,8 @@ impl ChainWithGrandpa for Rococo { const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } -// The TransactionExtension used by Rococo. -pub use bp_polkadot_core::CommonTransactionExtension as TransactionExtension; +// The SignedExtension used by Rococo. +pub use bp_polkadot_core::CommonSignedExtension as SignedExtension; /// Name of the parachains pallet in the Rococo runtime. pub const PARAS_PALLET_NAME: &str = "Paras"; diff --git a/bridges/primitives/chain-westend/src/lib.rs b/bridges/primitives/chain-westend/src/lib.rs index afa02e8ee54..f03fd2160a7 100644 --- a/bridges/primitives/chain-westend/src/lib.rs +++ b/bridges/primitives/chain-westend/src/lib.rs @@ -59,8 +59,8 @@ impl ChainWithGrandpa for Westend { const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } -// The TransactionExtension used by Westend. -pub use bp_polkadot_core::CommonTransactionExtension as TransactionExtension; +// The SignedExtension used by Westend. +pub use bp_polkadot_core::CommonSignedExtension as SignedExtension; /// Name of the parachains pallet in the Rococo runtime. pub const PARAS_PALLET_NAME: &str = "Paras"; diff --git a/bridges/primitives/polkadot-core/src/lib.rs b/bridges/primitives/polkadot-core/src/lib.rs index d59b99db4b5..df2836495bb 100644 --- a/bridges/primitives/polkadot-core/src/lib.rs +++ b/bridges/primitives/polkadot-core/src/lib.rs @@ -24,8 +24,8 @@ use bp_runtime::{ self, extensions::{ ChargeTransactionPayment, CheckEra, CheckGenesis, CheckNonZeroSender, CheckNonce, - CheckSpecVersion, CheckTxVersion, CheckWeight, GenericTransactionExtension, - TransactionExtensionSchema, + CheckSpecVersion, CheckTxVersion, CheckWeight, GenericSignedExtension, + SignedExtensionSchema, }, EncodedOrDecodedCall, StorageMapKeyProvider, TransactionEra, }; @@ -229,12 +229,8 @@ pub type SignedBlock = generic::SignedBlock; pub type Balance = u128; /// Unchecked Extrinsic type. -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic< - AccountAddress, - EncodedOrDecodedCall, - Signature, - TransactionExt, ->; +pub type UncheckedExtrinsic = + generic::UncheckedExtrinsic, Signature, SignedExt>; /// Account address, used by the Polkadot-like chain. pub type Address = MultiAddress; @@ -279,7 +275,7 @@ impl AccountInfoStorageMapKeyProvider { } /// Extra signed extension data that is used by most chains. -pub type CommonTransactionExtra = ( +pub type CommonSignedExtra = ( CheckNonZeroSender, CheckSpecVersion, CheckTxVersion, @@ -290,12 +286,12 @@ pub type CommonTransactionExtra = ( ChargeTransactionPayment, ); -/// Extra transaction extension data that starts with `CommonTransactionExtra`. -pub type SuffixedCommonTransactionExtension = - GenericTransactionExtension<(CommonTransactionExtra, Suffix)>; +/// Extra signed extension data that starts with `CommonSignedExtra`. +pub type SuffixedCommonSignedExtension = + GenericSignedExtension<(CommonSignedExtra, Suffix)>; -/// Helper trait to define some extra methods on `SuffixedCommonTransactionExtension`. -pub trait SuffixedCommonTransactionExtensionExt { +/// Helper trait to define some extra methods on `SuffixedCommonSignedExtension`. +pub trait SuffixedCommonSignedExtensionExt { /// Create signed extension from its components. fn from_params( spec_version: u32, @@ -304,7 +300,7 @@ pub trait SuffixedCommonTransactionExtensionExt Self; /// Return transaction nonce. @@ -314,10 +310,9 @@ pub trait SuffixedCommonTransactionExtensionExt Balance; } -impl SuffixedCommonTransactionExtensionExt - for SuffixedCommonTransactionExtension +impl SuffixedCommonSignedExtensionExt for SuffixedCommonSignedExtension where - Suffix: TransactionExtensionSchema, + Suffix: SignedExtensionSchema, { fn from_params( spec_version: u32, @@ -326,9 +321,9 @@ where genesis_hash: Hash, nonce: Nonce, tip: Balance, - extra: (Suffix::Payload, Suffix::Implicit), + extra: (Suffix::Payload, Suffix::AdditionalSigned), ) -> Self { - GenericTransactionExtension::new( + GenericSignedExtension::new( ( ( (), // non-zero sender @@ -370,7 +365,7 @@ where } /// Signed extension that is used by most chains. -pub type CommonTransactionExtension = SuffixedCommonTransactionExtension<()>; +pub type CommonSignedExtension = SuffixedCommonSignedExtension<()>; #[cfg(test)] mod tests { diff --git a/bridges/primitives/runtime/src/extensions.rs b/bridges/primitives/runtime/src/extensions.rs index a31e7b5bb47..d896bc92eff 100644 --- a/bridges/primitives/runtime/src/extensions.rs +++ b/bridges/primitives/runtime/src/extensions.rs @@ -20,138 +20,135 @@ use codec::{Compact, Decode, Encode}; use impl_trait_for_tuples::impl_for_tuples; use scale_info::{StaticTypeInfo, TypeInfo}; use sp_runtime::{ - impl_tx_ext_default, - traits::{Dispatchable, TransactionExtension, TransactionExtensionBase}, + traits::{DispatchInfoOf, SignedExtension}, transaction_validity::TransactionValidityError, }; use sp_std::{fmt::Debug, marker::PhantomData}; -/// Trait that describes some properties of a `TransactionExtension` that are needed in order to -/// send a transaction to the chain. -pub trait TransactionExtensionSchema: - Encode + Decode + Debug + Eq + Clone + StaticTypeInfo -{ +/// Trait that describes some properties of a `SignedExtension` that are needed in order to send a +/// transaction to the chain. +pub trait SignedExtensionSchema: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo { /// A type of the data encoded as part of the transaction. type Payload: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo; /// Parameters which are part of the payload used to produce transaction signature, /// but don't end up in the transaction itself (i.e. inherent part of the runtime). - type Implicit: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo; + type AdditionalSigned: Encode + Debug + Eq + Clone + StaticTypeInfo; } -impl TransactionExtensionSchema for () { +impl SignedExtensionSchema for () { type Payload = (); - type Implicit = (); + type AdditionalSigned = (); } -/// An implementation of `TransactionExtensionSchema` using generic params. +/// An implementation of `SignedExtensionSchema` using generic params. #[derive(Encode, Decode, Clone, Debug, PartialEq, Eq, TypeInfo)] -pub struct GenericTransactionExtensionSchema(PhantomData<(P, S)>); +pub struct GenericSignedExtensionSchema(PhantomData<(P, S)>); -impl TransactionExtensionSchema for GenericTransactionExtensionSchema +impl SignedExtensionSchema for GenericSignedExtensionSchema where P: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo, - S: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo, + S: Encode + Debug + Eq + Clone + StaticTypeInfo, { type Payload = P; - type Implicit = S; + type AdditionalSigned = S; } -/// The `TransactionExtensionSchema` for `frame_system::CheckNonZeroSender`. -pub type CheckNonZeroSender = GenericTransactionExtensionSchema<(), ()>; +/// The `SignedExtensionSchema` for `frame_system::CheckNonZeroSender`. +pub type CheckNonZeroSender = GenericSignedExtensionSchema<(), ()>; -/// The `TransactionExtensionSchema` for `frame_system::CheckSpecVersion`. -pub type CheckSpecVersion = GenericTransactionExtensionSchema<(), u32>; +/// The `SignedExtensionSchema` for `frame_system::CheckSpecVersion`. +pub type CheckSpecVersion = GenericSignedExtensionSchema<(), u32>; -/// The `TransactionExtensionSchema` for `frame_system::CheckTxVersion`. -pub type CheckTxVersion = GenericTransactionExtensionSchema<(), u32>; +/// The `SignedExtensionSchema` for `frame_system::CheckTxVersion`. +pub type CheckTxVersion = GenericSignedExtensionSchema<(), u32>; -/// The `TransactionExtensionSchema` for `frame_system::CheckGenesis`. -pub type CheckGenesis = GenericTransactionExtensionSchema<(), Hash>; +/// The `SignedExtensionSchema` for `frame_system::CheckGenesis`. +pub type CheckGenesis = GenericSignedExtensionSchema<(), Hash>; -/// The `TransactionExtensionSchema` for `frame_system::CheckEra`. -pub type CheckEra = GenericTransactionExtensionSchema; +/// The `SignedExtensionSchema` for `frame_system::CheckEra`. +pub type CheckEra = GenericSignedExtensionSchema; -/// The `TransactionExtensionSchema` for `frame_system::CheckNonce`. -pub type CheckNonce = GenericTransactionExtensionSchema, ()>; +/// The `SignedExtensionSchema` for `frame_system::CheckNonce`. +pub type CheckNonce = GenericSignedExtensionSchema, ()>; -/// The `TransactionExtensionSchema` for `frame_system::CheckWeight`. -pub type CheckWeight = GenericTransactionExtensionSchema<(), ()>; +/// The `SignedExtensionSchema` for `frame_system::CheckWeight`. +pub type CheckWeight = GenericSignedExtensionSchema<(), ()>; -/// The `TransactionExtensionSchema` for `pallet_transaction_payment::ChargeTransactionPayment`. -pub type ChargeTransactionPayment = - GenericTransactionExtensionSchema, ()>; +/// The `SignedExtensionSchema` for `pallet_transaction_payment::ChargeTransactionPayment`. +pub type ChargeTransactionPayment = GenericSignedExtensionSchema, ()>; -/// The `TransactionExtensionSchema` for `polkadot-runtime-common::PrevalidateAttests`. -pub type PrevalidateAttests = GenericTransactionExtensionSchema<(), ()>; +/// The `SignedExtensionSchema` for `polkadot-runtime-common::PrevalidateAttests`. +pub type PrevalidateAttests = GenericSignedExtensionSchema<(), ()>; -/// The `TransactionExtensionSchema` for `BridgeRejectObsoleteHeadersAndMessages`. -pub type BridgeRejectObsoleteHeadersAndMessages = GenericTransactionExtensionSchema<(), ()>; +/// The `SignedExtensionSchema` for `BridgeRejectObsoleteHeadersAndMessages`. +pub type BridgeRejectObsoleteHeadersAndMessages = GenericSignedExtensionSchema<(), ()>; -/// The `TransactionExtensionSchema` for `RefundBridgedParachainMessages`. +/// The `SignedExtensionSchema` for `RefundBridgedParachainMessages`. /// This schema is dedicated for `RefundBridgedParachainMessages` signed extension as /// wildcard/placeholder, which relies on the scale encoding for `()` or `((), ())`, or `((), (), /// ())` is the same. So runtime can contains any kind of tuple: /// `(BridgeRefundBridgeHubRococoMessages)` /// `(BridgeRefundBridgeHubRococoMessages, BridgeRefundBridgeHubWestendMessages)` /// `(BridgeRefundParachainMessages1, ..., BridgeRefundParachainMessagesN)` -pub type RefundBridgedParachainMessagesSchema = GenericTransactionExtensionSchema<(), ()>; +pub type RefundBridgedParachainMessagesSchema = GenericSignedExtensionSchema<(), ()>; #[impl_for_tuples(1, 12)] -impl TransactionExtensionSchema for Tuple { +impl SignedExtensionSchema for Tuple { for_tuples!( type Payload = ( #( Tuple::Payload ),* ); ); - for_tuples!( type Implicit = ( #( Tuple::Implicit ),* ); ); + for_tuples!( type AdditionalSigned = ( #( Tuple::AdditionalSigned ),* ); ); } /// A simplified version of signed extensions meant for producing signed transactions /// and signed payloads in the client code. #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -pub struct GenericTransactionExtension { +pub struct GenericSignedExtension { /// A payload that is included in the transaction. pub payload: S::Payload, #[codec(skip)] // It may be set to `None` if extensions are decoded. We are never reconstructing transactions - // (and it makes no sense to do that) => decoded version of `TransactionExtensions` is only - // used to read fields of the `payload`. And when resigning transaction, we're reconstructing - // `TransactionExtensions` from scratch. - implicit: Option, + // (and it makes no sense to do that) => decoded version of `SignedExtensions` is only used to + // read fields of the `payload`. And when resigning transaction, we're reconstructing + // `SignedExtensions` from scratch. + additional_signed: Option, } -impl GenericTransactionExtension { - /// Create new `GenericTransactionExtension` object. - pub fn new(payload: S::Payload, implicit: Option) -> Self { - Self { payload, implicit } +impl GenericSignedExtension { + /// Create new `GenericSignedExtension` object. + pub fn new(payload: S::Payload, additional_signed: Option) -> Self { + Self { payload, additional_signed } } } -impl TransactionExtensionBase for GenericTransactionExtension +impl SignedExtension for GenericSignedExtension where - S: TransactionExtensionSchema, + S: SignedExtensionSchema, S::Payload: Send + Sync, - S::Implicit: Send + Sync, + S::AdditionalSigned: Send + Sync, { const IDENTIFIER: &'static str = "Not needed."; - type Implicit = S::Implicit; + type AccountId = (); + type Call = (); + type AdditionalSigned = S::AdditionalSigned; + type Pre = (); - fn implicit(&self) -> Result { + fn additional_signed(&self) -> Result { // we shall not ever see this error in relay, because we are never signing decoded // transactions. Instead we're constructing and signing new transactions. So the error code // is kinda random here - self.implicit - .clone() - .ok_or(frame_support::unsigned::TransactionValidityError::Unknown( + self.additional_signed.clone().ok_or( + frame_support::unsigned::TransactionValidityError::Unknown( frame_support::unsigned::UnknownTransaction::Custom(0xFF), - )) + ), + ) } -} -impl TransactionExtension for GenericTransactionExtension -where - C: Dispatchable, - S: TransactionExtensionSchema, - S::Payload: Send + Sync, - S::Implicit: Send + Sync, -{ - type Pre = (); - type Val = (); - impl_tx_ext_default!(C; Context; validate prepare); + fn pre_dispatch( + self, + _who: &Self::AccountId, + _call: &Self::Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> Result { + Ok(()) + } } diff --git a/bridges/snowbridge/runtime/test-common/Cargo.toml b/bridges/snowbridge/runtime/test-common/Cargo.toml index 5f169e82f49..4e8b311cb97 100644 --- a/bridges/snowbridge/runtime/test-common/Cargo.toml +++ b/bridges/snowbridge/runtime/test-common/Cargo.toml @@ -181,7 +181,6 @@ runtime-benchmarks = [ "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index 3eb63a24b74..05936e93993 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -119,7 +119,6 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", - "pallet-asset-conversion-tx-payment/runtime-benchmarks", "pallet-asset-conversion/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", @@ -131,7 +130,6 @@ runtime-benchmarks = [ "pallet-proxy/runtime-benchmarks", "pallet-state-trie-migration/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "pallet-uniques/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 32966ab6341..17a12dd2f6f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -178,7 +178,6 @@ impl frame_system::Config for Runtime { type Version = Version; type AccountData = pallet_balances::AccountData; type SystemWeightInfo = weights::frame_system::WeightInfo; - type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; type MaxConsumers = frame_support::traits::ConstU32<16>; @@ -235,7 +234,6 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; type OperationalFeeMultiplier = ConstU8<5>; - type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -763,9 +761,6 @@ impl pallet_asset_conversion_tx_payment::Config for Runtime { type Fungibles = LocalAndForeignAssets; type OnChargeAssetTransaction = AssetConversionAdapter; - type WeightInfo = weights::pallet_asset_conversion_tx_payment::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = AssetConversionTxHelper; } parameter_types! { @@ -953,8 +948,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The extension to the basic transaction logic. -pub type TxExtension = ( +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -966,7 +961,7 @@ pub type TxExtension = ( ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( pallet_collator_selection::migration::v1::MigrateToV1, @@ -1039,77 +1034,14 @@ pub type Executive = frame_executive::Executive< Migrations, >; -#[cfg(feature = "runtime-benchmarks")] -pub struct AssetConversionTxHelper; - -#[cfg(feature = "runtime-benchmarks")] -impl - pallet_asset_conversion_tx_payment::BenchmarkHelperTrait< - AccountId, - xcm::v3::MultiLocation, - xcm::v3::MultiLocation, - > for AssetConversionTxHelper -{ - fn create_asset_id_parameter(seed: u32) -> (xcm::v3::MultiLocation, xcm::v3::MultiLocation) { - // Use a different parachain' foreign assets pallet so that the asset is indeed foreign. - let asset_id = xcm::v3::MultiLocation::new( - 1, - xcm::v3::Junctions::X3( - xcm::v3::Junction::Parachain(3000), - xcm::v3::Junction::PalletInstance(53), - xcm::v3::Junction::GeneralIndex(seed.into()), - ), - ); - (asset_id, asset_id) - } - - fn setup_balances_and_pool(asset_id: xcm::v3::MultiLocation, account: AccountId) { - use frame_support::{assert_ok, traits::fungibles::Mutate}; - assert_ok!(ForeignAssets::force_create( - RuntimeOrigin::root(), - asset_id.into(), - account.clone().into(), /* owner */ - true, /* is_sufficient */ - 1, - )); - - let lp_provider = account.clone(); - use frame_support::traits::Currency; - let _ = Balances::deposit_creating(&lp_provider, u64::MAX.into()); - assert_ok!(ForeignAssets::mint_into(asset_id.into(), &lp_provider, u64::MAX.into())); - - let token_native = Box::new(TokenLocationV3::get()); - let token_second = Box::new(asset_id); - - assert_ok!(AssetConversion::create_pool( - RuntimeOrigin::signed(lp_provider.clone()), - token_native.clone(), - token_second.clone() - )); - - assert_ok!(AssetConversion::add_liquidity( - RuntimeOrigin::signed(lp_provider.clone()), - token_native, - token_second, - (u32::MAX / 8).into(), // 1 desired - u32::MAX.into(), // 2 desired - 1, // 1 min - 1, // 2 min - lp_provider, - )); - } -} - #[cfg(feature = "runtime-benchmarks")] mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] - [frame_system_extensions, SystemExtensionsBench::] [pallet_assets, Local] [pallet_assets, Foreign] [pallet_assets, Pool] [pallet_asset_conversion, AssetConversion] - [pallet_asset_conversion_tx_payment, AssetTxPayment] [pallet_balances, Balances] [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] @@ -1120,7 +1052,6 @@ mod benches { [pallet_uniques, Uniques] [pallet_utility, Utility] [pallet_timestamp, Timestamp] - [pallet_transaction_payment, TransactionPayment] [pallet_collator_selection, CollatorSelection] [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] @@ -1371,7 +1302,6 @@ impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; use pallet_xcm_bridge_hub_router::benchmarking::Pallet as XcmBridgeHubRouterBench; @@ -1406,7 +1336,6 @@ impl_runtime_apis! { use sp_storage::TrackedStorageKey; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; impl frame_system_benchmarking::Config for Runtime { fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/frame_system_extensions.rs deleted file mode 100644 index ed2c5f3056e..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/frame_system_extensions.rs +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `frame_system_extensions` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --wasm-execution=compiled -// --pallet=frame_system_extensions -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=2 -// --repeat=2 -// --json -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/ -// --chain=asset-hub-rococo-dev - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `frame_system_extensions`. -pub struct WeightInfo(PhantomData); -impl frame_system::ExtensionsWeightInfo for WeightInfo { - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_genesis() -> Weight { - // Proof Size summary in bytes: - // Measured: `54` - // Estimated: `3509` - // Minimum execution time: 3_637_000 picoseconds. - Weight::from_parts(6_382_000, 0) - .saturating_add(Weight::from_parts(0, 3509)) - .saturating_add(T::DbWeight::get().reads(1)) - } - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_mortality() -> Weight { - // Proof Size summary in bytes: - // Measured: `92` - // Estimated: `3509` - // Minimum execution time: 5_841_000 picoseconds. - Weight::from_parts(8_776_000, 0) - .saturating_add(Weight::from_parts(0, 3509)) - .saturating_add(T::DbWeight::get().reads(1)) - } - fn check_non_zero_sender() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 561_000 picoseconds. - Weight::from_parts(2_705_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_nonce() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_316_000 picoseconds. - Weight::from_parts(5_771_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_spec_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 511_000 picoseconds. - Weight::from_parts(2_575_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_tx_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 501_000 picoseconds. - Weight::from_parts(2_595_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) - /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `System::BlockWeight` (r:1 w:1) - /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) - fn check_weight() -> Weight { - // Proof Size summary in bytes: - // Measured: `24` - // Estimated: `1533` - // Minimum execution time: 3_687_000 picoseconds. - Weight::from_parts(6_192_000, 0) - .saturating_add(Weight::from_parts(0, 1533)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs index 134b5341a40..fa9e86102c6 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs @@ -19,9 +19,7 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; -pub mod frame_system_extensions; pub mod pallet_asset_conversion; -pub mod pallet_asset_conversion_tx_payment; pub mod pallet_assets_foreign; pub mod pallet_assets_local; pub mod pallet_assets_pool; @@ -34,7 +32,6 @@ pub mod pallet_nfts; pub mod pallet_proxy; pub mod pallet_session; pub mod pallet_timestamp; -pub mod pallet_transaction_payment; pub mod pallet_uniques; pub mod pallet_utility; pub mod pallet_xcm; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion_tx_payment.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion_tx_payment.rs deleted file mode 100644 index 0a639b368af..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion_tx_payment.rs +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `pallet_asset_conversion_tx_payment` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2024-01-04, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `Georges-MacBook-Pro.local`, CPU: `` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/debug/polkadot-parachain -// benchmark -// pallet -// --wasm-execution=compiled -// --pallet=pallet_asset_conversion_tx_payment -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=2 -// --repeat=2 -// --json -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/ -// --chain=asset-hub-rococo-dev - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_asset_conversion_tx_payment`. -pub struct WeightInfo(PhantomData); -impl pallet_asset_conversion_tx_payment::WeightInfo for WeightInfo { - fn charge_asset_tx_payment_zero() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 7_000_000 picoseconds. - Weight::from_parts(10_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:0) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn charge_asset_tx_payment_native() -> Weight { - // Proof Size summary in bytes: - // Measured: `4` - // Estimated: `3593` - // Minimum execution time: 209_000_000 picoseconds. - Weight::from_parts(212_000_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(2)) - } - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Asset` (r:1 w:1) - /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Account` (r:2 w:2) - /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn charge_asset_tx_payment_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `631` - // Estimated: `7404` - // Minimum execution time: 1_228_000_000 picoseconds. - Weight::from_parts(1_268_000_000, 0) - .saturating_add(Weight::from_parts(0, 7404)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(4)) - } -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_transaction_payment.rs deleted file mode 100644 index 035f9a6dbe5..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_transaction_payment.rs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `pallet_transaction_payment` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --wasm-execution=compiled -// --pallet=pallet_transaction_payment -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=2 -// --repeat=2 -// --json -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/ -// --chain=asset-hub-rococo-dev - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_transaction_payment`. -pub struct WeightInfo(PhantomData); -impl pallet_transaction_payment::WeightInfo for WeightInfo { - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn charge_transaction_payment() -> Weight { - // Proof Size summary in bytes: - // Measured: `4` - // Estimated: `3593` - // Minimum execution time: 33_363_000 picoseconds. - Weight::from_parts(38_793_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index c10e02bd8a6..78c48507a7a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -110,7 +110,6 @@ runtime-benchmarks = [ "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", "hex-literal", - "pallet-asset-conversion-tx-payment/runtime-benchmarks", "pallet-asset-conversion/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", @@ -121,7 +120,6 @@ runtime-benchmarks = [ "pallet-nfts/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "pallet-uniques/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 5246828da31..1ead2897855 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -162,7 +162,6 @@ impl frame_system::Config for Runtime { type Version = Version; type AccountData = pallet_balances::AccountData; type SystemWeightInfo = weights::frame_system::WeightInfo; - type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; type MaxConsumers = frame_support::traits::ConstU32<16>; @@ -219,7 +218,6 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; type OperationalFeeMultiplier = ConstU8<5>; - type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -737,9 +735,6 @@ impl pallet_asset_conversion_tx_payment::Config for Runtime { type Fungibles = LocalAndForeignAssets; type OnChargeAssetTransaction = AssetConversionAdapter; - type WeightInfo = weights::pallet_asset_conversion_tx_payment::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = AssetConversionTxHelper; } parameter_types! { @@ -925,8 +920,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The extension to the basic transaction logic. -pub type TxExtension = ( +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -938,7 +933,7 @@ pub type TxExtension = ( ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( @@ -1070,77 +1065,14 @@ pub type Executive = frame_executive::Executive< Migrations, >; -#[cfg(feature = "runtime-benchmarks")] -pub struct AssetConversionTxHelper; - -#[cfg(feature = "runtime-benchmarks")] -impl - pallet_asset_conversion_tx_payment::BenchmarkHelperTrait< - AccountId, - xcm::v3::MultiLocation, - xcm::v3::MultiLocation, - > for AssetConversionTxHelper -{ - fn create_asset_id_parameter(seed: u32) -> (xcm::v3::MultiLocation, xcm::v3::MultiLocation) { - // Use a different parachain' foreign assets pallet so that the asset is indeed foreign. - let asset_id = xcm::v3::MultiLocation::new( - 1, - xcm::v3::Junctions::X3( - xcm::v3::Junction::Parachain(3000), - xcm::v3::Junction::PalletInstance(53), - xcm::v3::Junction::GeneralIndex(seed.into()), - ), - ); - (asset_id, asset_id) - } - - fn setup_balances_and_pool(asset_id: xcm::v3::MultiLocation, account: AccountId) { - use frame_support::{assert_ok, traits::fungibles::Mutate}; - assert_ok!(ForeignAssets::force_create( - RuntimeOrigin::root(), - asset_id.into(), - account.clone().into(), /* owner */ - true, /* is_sufficient */ - 1, - )); - - let lp_provider = account.clone(); - use frame_support::traits::Currency; - let _ = Balances::deposit_creating(&lp_provider, u64::MAX.into()); - assert_ok!(ForeignAssets::mint_into(asset_id.into(), &lp_provider, u64::MAX.into())); - - let token_native = Box::new(xcm::v3::MultiLocation::new(1, xcm::v3::Junctions::Here)); - let token_second = Box::new(asset_id); - - assert_ok!(AssetConversion::create_pool( - RuntimeOrigin::signed(lp_provider.clone()), - token_native.clone(), - token_second.clone() - )); - - assert_ok!(AssetConversion::add_liquidity( - RuntimeOrigin::signed(lp_provider.clone()), - token_native, - token_second, - (u32::MAX / 2).into(), // 1 desired - u32::MAX.into(), // 2 desired - 1, // 1 min - 1, // 2 min - lp_provider, - )); - } -} - #[cfg(feature = "runtime-benchmarks")] mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] - [frame_system_extensions, SystemExtensionsBench::] [pallet_assets, Local] [pallet_assets, Foreign] [pallet_assets, Pool] [pallet_asset_conversion, AssetConversion] - [pallet_asset_conversion_tx_payment, AssetTxPayment] [pallet_balances, Balances] [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] @@ -1151,7 +1083,6 @@ mod benches { [pallet_uniques, Uniques] [pallet_utility, Utility] [pallet_timestamp, Timestamp] - [pallet_transaction_payment, TransactionPayment] [pallet_collator_selection, CollatorSelection] [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] @@ -1448,7 +1379,6 @@ impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; use pallet_xcm_bridge_hub_router::benchmarking::Pallet as XcmBridgeHubRouterBench; @@ -1483,7 +1413,6 @@ impl_runtime_apis! { use sp_storage::TrackedStorageKey; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; impl frame_system_benchmarking::Config for Runtime { fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/frame_system_extensions.rs deleted file mode 100644 index 46f4f2bfd96..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/frame_system_extensions.rs +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `frame_system_extensions` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --wasm-execution=compiled -// --pallet=frame_system_extensions -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=2 -// --repeat=2 -// --json -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/ -// --chain=asset-hub-westend-dev - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `frame_system_extensions`. -pub struct WeightInfo(PhantomData); -impl frame_system::ExtensionsWeightInfo for WeightInfo { - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_genesis() -> Weight { - // Proof Size summary in bytes: - // Measured: `54` - // Estimated: `3509` - // Minimum execution time: 3_206_000 picoseconds. - Weight::from_parts(6_212_000, 0) - .saturating_add(Weight::from_parts(0, 3509)) - .saturating_add(T::DbWeight::get().reads(1)) - } - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_mortality() -> Weight { - // Proof Size summary in bytes: - // Measured: `92` - // Estimated: `3509` - // Minimum execution time: 5_851_000 picoseconds. - Weight::from_parts(8_847_000, 0) - .saturating_add(Weight::from_parts(0, 3509)) - .saturating_add(T::DbWeight::get().reads(1)) - } - fn check_non_zero_sender() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 631_000 picoseconds. - Weight::from_parts(3_086_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_nonce() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_446_000 picoseconds. - Weight::from_parts(5_911_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_spec_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 481_000 picoseconds. - Weight::from_parts(2_916_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_tx_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 501_000 picoseconds. - Weight::from_parts(2_595_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) - /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `System::BlockWeight` (r:1 w:1) - /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) - fn check_weight() -> Weight { - // Proof Size summary in bytes: - // Measured: `24` - // Estimated: `1533` - // Minimum execution time: 3_927_000 picoseconds. - Weight::from_parts(6_613_000, 0) - .saturating_add(Weight::from_parts(0, 1533)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs index 691ed2e5730..2f1fcfb05f3 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs @@ -18,9 +18,7 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; -pub mod frame_system_extensions; pub mod pallet_asset_conversion; -pub mod pallet_asset_conversion_tx_payment; pub mod pallet_assets_foreign; pub mod pallet_assets_local; pub mod pallet_assets_pool; @@ -33,7 +31,6 @@ pub mod pallet_nfts; pub mod pallet_proxy; pub mod pallet_session; pub mod pallet_timestamp; -pub mod pallet_transaction_payment; pub mod pallet_uniques; pub mod pallet_utility; pub mod pallet_xcm; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion_tx_payment.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion_tx_payment.rs deleted file mode 100644 index 8fe302630fb..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion_tx_payment.rs +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `pallet_asset_conversion_tx_payment` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2024-01-04, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `Georges-MacBook-Pro.local`, CPU: `` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/debug/polkadot-parachain -// benchmark -// pallet -// --wasm-execution=compiled -// --pallet=pallet_asset_conversion_tx_payment -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=2 -// --repeat=2 -// --json -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/ -// --chain=asset-hub-westend-dev - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_asset_conversion_tx_payment`. -pub struct WeightInfo(PhantomData); -impl pallet_asset_conversion_tx_payment::WeightInfo for WeightInfo { - fn charge_asset_tx_payment_zero() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_000_000 picoseconds. - Weight::from_parts(9_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:0) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn charge_asset_tx_payment_native() -> Weight { - // Proof Size summary in bytes: - // Measured: `4` - // Estimated: `3593` - // Minimum execution time: 214_000_000 picoseconds. - Weight::from_parts(219_000_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(2)) - } - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Asset` (r:1 w:1) - /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Account` (r:2 w:2) - /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn charge_asset_tx_payment_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `631` - // Estimated: `7404` - // Minimum execution time: 1_211_000_000 picoseconds. - Weight::from_parts(1_243_000_000, 0) - .saturating_add(Weight::from_parts(0, 7404)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(4)) - } -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_transaction_payment.rs deleted file mode 100644 index b4c78a78b48..00000000000 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_transaction_payment.rs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `pallet_transaction_payment` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --wasm-execution=compiled -// --pallet=pallet_transaction_payment -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=2 -// --repeat=2 -// --json -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/ -// --chain=asset-hub-westend-dev - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_transaction_payment`. -pub struct WeightInfo(PhantomData); -impl pallet_transaction_payment::WeightInfo for WeightInfo { - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn charge_transaction_payment() -> Weight { - // Proof Size summary in bytes: - // Measured: `4` - // Estimated: `3593` - // Minimum execution time: 40_847_000 picoseconds. - Weight::from_parts(49_674_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml index 242627815d3..7a1951fd24b 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -242,7 +242,6 @@ runtime-benchmarks = [ "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm-bridge-hub/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs index 323e6ed65e6..6dbf96edc2a 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs @@ -40,7 +40,7 @@ use bridge_runtime_common::{ XcmBlobMessageDispatch, XcmVersionOfDestAndRemoteBridge, }, refund_relayer_extension::{ - ActualFeeRefund, RefundBridgedGrandpaMessages, RefundTransactionExtensionAdapter, + ActualFeeRefund, RefundBridgedGrandpaMessages, RefundSignedExtensionAdapter, RefundableMessagesLane, }, }; @@ -168,7 +168,7 @@ impl messages::BridgedChainWithMessages for RococoBulletin {} /// Signed extension that refunds relayers that are delivering messages from the Rococo Bulletin /// chain. -pub type OnBridgeHubRococoRefundRococoBulletinMessages = RefundTransactionExtensionAdapter< +pub type OnBridgeHubRococoRefundRococoBulletinMessages = RefundSignedExtensionAdapter< RefundBridgedGrandpaMessages< Runtime, BridgeGrandpaRococoBulletinInstance, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs index 05d1aa188d2..5d55d7afbac 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs @@ -39,7 +39,7 @@ use bridge_runtime_common::{ XcmBlobMessageDispatch, XcmVersionOfDestAndRemoteBridge, }, refund_relayer_extension::{ - ActualFeeRefund, RefundBridgedParachainMessages, RefundTransactionExtensionAdapter, + ActualFeeRefund, RefundBridgedParachainMessages, RefundSignedExtensionAdapter, RefundableMessagesLane, RefundableParachain, }, }; @@ -173,7 +173,7 @@ impl UnderlyingChainProvider for BridgeHubWestend { impl messages::BridgedChainWithMessages for BridgeHubWestend {} /// Signed extension that refunds relayers that are delivering messages from the Westend parachain. -pub type OnBridgeHubRococoRefundBridgeHubWestendMessages = RefundTransactionExtensionAdapter< +pub type OnBridgeHubRococoRefundBridgeHubWestendMessages = RefundSignedExtensionAdapter< RefundBridgedParachainMessages< Runtime, RefundableParachain< diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 16e3b2e8600..0b48d1717fa 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -115,8 +115,8 @@ pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The TransactionExtension to the basic transaction logic. -pub type TxExtension = ( +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -134,7 +134,7 @@ pub type TxExtension = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( @@ -262,8 +262,6 @@ impl frame_system::Config for Runtime { type DbWeight = RocksDbWeight; /// Weight information for the extrinsics of this pallet. type SystemWeightInfo = weights::frame_system::WeightInfo; - /// Weight information for the extensions of this pallet. - type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; /// Block & extrinsics weights: base values and limits. type BlockWeights = RuntimeBlockWeights; /// The maximum length of a block (in bytes). @@ -326,7 +324,6 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; - type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -762,14 +759,12 @@ bridge_runtime_common::generate_bridge_reject_obsolete_headers_and_messages! { mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] - [frame_system_extensions, SystemExtensionsBench::] [pallet_balances, Balances] [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] [pallet_session, SessionBench::] [pallet_utility, Utility] [pallet_timestamp, Timestamp] - [pallet_transaction_payment, TransactionPayment] [pallet_collator_selection, CollatorSelection] [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] @@ -1070,7 +1065,6 @@ impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; @@ -1101,7 +1095,6 @@ impl_runtime_apis! { use sp_storage::TrackedStorageKey; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; impl frame_system_benchmarking::Config for Runtime { fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); @@ -1485,16 +1478,16 @@ mod tests { use codec::Encode; use sp_runtime::{ generic::Era, - traits::{TransactionExtensionBase, Zero}, + traits::{SignedExtension, Zero}, }; #[test] fn ensure_signed_extension_definition_is_compatible_with_relay() { - use bp_polkadot_core::SuffixedCommonTransactionExtensionExt; + use bp_polkadot_core::SuffixedCommonSignedExtensionExt; sp_io::TestExternalities::default().execute_with(|| { frame_system::BlockHash::::insert(BlockNumber::zero(), Hash::default()); - let payload: TxExtension = ( + let payload: SignedExtra = ( frame_system::CheckNonZeroSender::new(), frame_system::CheckSpecVersion::new(), frame_system::CheckTxVersion::new(), @@ -1508,11 +1501,11 @@ mod tests { bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages::default(), bridge_to_bulletin_config::OnBridgeHubRococoRefundRococoBulletinMessages::default(), ) - ).into(); + ); // for BridgeHubRococo { - let bhr_indirect_payload = bp_bridge_hub_rococo::TransactionExtension::from_params( + let bhr_indirect_payload = bp_bridge_hub_rococo::SignedExtension::from_params( VERSION.spec_version, VERSION.transaction_version, bp_runtime::TransactionEra::Immortal, @@ -1523,8 +1516,8 @@ mod tests { ); assert_eq!(payload.encode(), bhr_indirect_payload.encode()); assert_eq!( - payload.implicit().unwrap().encode(), - bhr_indirect_payload.implicit().unwrap().encode() + payload.additional_signed().unwrap().encode(), + bhr_indirect_payload.additional_signed().unwrap().encode() ) } }); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/frame_system_extensions.rs deleted file mode 100644 index 99e3d6aeba0..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/frame_system_extensions.rs +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `frame_system_extensions` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --wasm-execution=compiled -// --pallet=frame_system_extensions -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=2 -// --repeat=2 -// --json -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/ -// --chain=bridge-hub-rococo-dev - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `frame_system_extensions`. -pub struct WeightInfo(PhantomData); -impl frame_system::ExtensionsWeightInfo for WeightInfo { - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_genesis() -> Weight { - // Proof Size summary in bytes: - // Measured: `54` - // Estimated: `3509` - // Minimum execution time: 3_136_000 picoseconds. - Weight::from_parts(5_842_000, 0) - .saturating_add(Weight::from_parts(0, 3509)) - .saturating_add(T::DbWeight::get().reads(1)) - } - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_mortality() -> Weight { - // Proof Size summary in bytes: - // Measured: `92` - // Estimated: `3509` - // Minimum execution time: 5_771_000 picoseconds. - Weight::from_parts(8_857_000, 0) - .saturating_add(Weight::from_parts(0, 3509)) - .saturating_add(T::DbWeight::get().reads(1)) - } - fn check_non_zero_sender() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 732_000 picoseconds. - Weight::from_parts(2_875_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_nonce() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_627_000 picoseconds. - Weight::from_parts(6_322_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_spec_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 471_000 picoseconds. - Weight::from_parts(2_455_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_tx_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 491_000 picoseconds. - Weight::from_parts(2_916_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) - /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `System::BlockWeight` (r:1 w:1) - /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) - fn check_weight() -> Weight { - // Proof Size summary in bytes: - // Measured: `24` - // Estimated: `1533` - // Minimum execution time: 3_798_000 picoseconds. - Weight::from_parts(6_272_000, 0) - .saturating_add(Weight::from_parts(0, 1533)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs index d97a30db954..aac39a4564f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs @@ -25,7 +25,6 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; -pub mod frame_system_extensions; pub mod pallet_balances; pub mod pallet_bridge_grandpa; pub mod pallet_bridge_messages_rococo_to_rococo_bulletin; @@ -37,7 +36,6 @@ pub mod pallet_message_queue; pub mod pallet_multisig; pub mod pallet_session; pub mod pallet_timestamp; -pub mod pallet_transaction_payment; pub mod pallet_utility; pub mod pallet_xcm; pub mod paritydb_weights; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_transaction_payment.rs deleted file mode 100644 index 71d17e7259f..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_transaction_payment.rs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `pallet_transaction_payment` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --wasm-execution=compiled -// --pallet=pallet_transaction_payment -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=2 -// --repeat=2 -// --json -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/ -// --chain=bridge-hub-rococo-dev - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_transaction_payment`. -pub struct WeightInfo(PhantomData); -impl pallet_transaction_payment::WeightInfo for WeightInfo { - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn charge_transaction_payment() -> Weight { - // Proof Size summary in bytes: - // Measured: `3` - // Estimated: `3593` - // Minimum execution time: 34_956_000 picoseconds. - Weight::from_parts(40_788_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs index 46c5df18a15..239bd946e75 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs @@ -22,7 +22,7 @@ use bridge_hub_rococo_runtime::{ bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages, xcm_config::XcmConfig, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, MessageQueueServiceWeight, Runtime, RuntimeCall, RuntimeEvent, SessionKeys, - TxExtension, UncheckedExtrinsic, + SignedExtra, UncheckedExtrinsic, }; use codec::{Decode, Encode}; use cumulus_primitives_core::XcmError::{FailedToTransactAsset, NotHoldingFees}; @@ -171,7 +171,7 @@ fn construct_extrinsic( call: RuntimeCall, ) -> UncheckedExtrinsic { let account_id = AccountId32::from(sender.public()); - let tx_ext: TxExtension = ( + let extra: SignedExtra = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -188,13 +188,13 @@ fn construct_extrinsic( OnBridgeHubRococoRefundRococoBulletinMessages::default(), ), ); - let payload = SignedPayload::new(call.clone(), tx_ext.clone()).unwrap(); + let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); let signature = payload.using_encoded(|e| sender.sign(e)); UncheckedExtrinsic::new_signed( call, account_id.into(), Signature::Sr25519(signature.clone()), - tx_ext, + extra, ) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs index 565343c55a5..f11954cf165 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -22,7 +22,7 @@ use bridge_hub_rococo_runtime::{ xcm_config::{RelayNetwork, TokenLocation, XcmConfig}, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, EthereumGatewayAddress, Executive, ExistentialDeposit, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, - RuntimeEvent, RuntimeOrigin, SessionKeys, TransactionPayment, TxExtension, UncheckedExtrinsic, + RuntimeEvent, RuntimeOrigin, SessionKeys, SignedExtra, TransactionPayment, UncheckedExtrinsic, }; use bridge_hub_test_utils::SlotDurations; use codec::{Decode, Encode}; @@ -48,7 +48,7 @@ fn construct_extrinsic( call: RuntimeCall, ) -> UncheckedExtrinsic { let account_id = AccountId32::from(sender.public()); - let tx_ext: TxExtension = ( + let extra: SignedExtra = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -64,15 +64,14 @@ fn construct_extrinsic( bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages::default(), bridge_to_bulletin_config::OnBridgeHubRococoRefundRococoBulletinMessages::default(), ), - ) - .into(); - let payload = SignedPayload::new(call.clone(), tx_ext.clone()).unwrap(); + ); + let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); let signature = payload.using_encoded(|e| sender.sign(e)); UncheckedExtrinsic::new_signed( call, account_id.into(), Signature::Sr25519(signature.clone()), - tx_ext, + extra, ) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml index b5fe093b8be..8623f7cb366 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -204,7 +204,6 @@ runtime-benchmarks = [ "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm-bridge-hub/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs index 934dce5c2c4..bce722aa5f8 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs @@ -36,7 +36,7 @@ use bridge_runtime_common::{ XcmBlobMessageDispatch, XcmVersionOfDestAndRemoteBridge, }, refund_relayer_extension::{ - ActualFeeRefund, RefundBridgedParachainMessages, RefundTransactionExtensionAdapter, + ActualFeeRefund, RefundBridgedParachainMessages, RefundSignedExtensionAdapter, RefundableMessagesLane, RefundableParachain, }, }; @@ -190,7 +190,7 @@ impl ThisChainWithMessages for BridgeHubWestend { } /// Signed extension that refunds relayers that are delivering messages from the Rococo parachain. -pub type OnBridgeHubWestendRefundBridgeHubRococoMessages = RefundTransactionExtensionAdapter< +pub type OnBridgeHubWestendRefundBridgeHubRococoMessages = RefundSignedExtensionAdapter< RefundBridgedParachainMessages< Runtime, RefundableParachain, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index 86ed8b2f488..e1344fce63d 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -97,8 +97,8 @@ pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The TransactionExtension to the basic transaction logic. -pub type TxExtension = ( +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -113,7 +113,7 @@ pub type TxExtension = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( @@ -298,7 +298,6 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; - type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -516,14 +515,12 @@ bridge_runtime_common::generate_bridge_reject_obsolete_headers_and_messages! { mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] - [frame_system_extensions, SystemExtensionsBench::] [pallet_balances, Balances] [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] [pallet_session, SessionBench::] [pallet_utility, Utility] [pallet_timestamp, Timestamp] - [pallet_transaction_payment, TransactionPayment] [pallet_collator_selection, CollatorSelection] [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] @@ -764,7 +761,6 @@ impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; @@ -794,7 +790,6 @@ impl_runtime_apis! { use sp_storage::TrackedStorageKey; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; impl frame_system_benchmarking::Config for Runtime { fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); @@ -1140,16 +1135,16 @@ mod tests { use codec::Encode; use sp_runtime::{ generic::Era, - traits::{TransactionExtensionBase, Zero}, + traits::{SignedExtension, Zero}, }; #[test] fn ensure_signed_extension_definition_is_compatible_with_relay() { - use bp_polkadot_core::SuffixedCommonTransactionExtensionExt; + use bp_polkadot_core::SuffixedCommonSignedExtensionExt; sp_io::TestExternalities::default().execute_with(|| { frame_system::BlockHash::::insert(BlockNumber::zero(), Hash::default()); - let payload: TxExtension = ( + let payload: SignedExtra = ( frame_system::CheckNonZeroSender::new(), frame_system::CheckSpecVersion::new(), frame_system::CheckTxVersion::new(), @@ -1162,10 +1157,10 @@ mod tests { ( bridge_to_rococo_config::OnBridgeHubWestendRefundBridgeHubRococoMessages::default(), ), - ).into(); + ); { - let bh_indirect_payload = bp_bridge_hub_westend::TransactionExtension::from_params( + let bh_indirect_payload = bp_bridge_hub_westend::SignedExtension::from_params( VERSION.spec_version, VERSION.transaction_version, bp_runtime::TransactionEra::Immortal, @@ -1176,8 +1171,8 @@ mod tests { ); assert_eq!(payload.encode(), bh_indirect_payload.encode()); assert_eq!( - payload.implicit().unwrap().encode(), - bh_indirect_payload.implicit().unwrap().encode() + payload.additional_signed().unwrap().encode(), + bh_indirect_payload.additional_signed().unwrap().encode() ) } }); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/frame_system_extensions.rs deleted file mode 100644 index 06f1114b4de..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/frame_system_extensions.rs +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `frame_system_extensions` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --wasm-execution=compiled -// --pallet=frame_system_extensions -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=2 -// --repeat=2 -// --json -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/ -// --chain=bridge-hub-westend-dev - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `frame_system_extensions`. -pub struct WeightInfo(PhantomData); -impl frame_system::ExtensionsWeightInfo for WeightInfo { - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_genesis() -> Weight { - // Proof Size summary in bytes: - // Measured: `54` - // Estimated: `3509` - // Minimum execution time: 3_166_000 picoseconds. - Weight::from_parts(6_021_000, 0) - .saturating_add(Weight::from_parts(0, 3509)) - .saturating_add(T::DbWeight::get().reads(1)) - } - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_mortality() -> Weight { - // Proof Size summary in bytes: - // Measured: `92` - // Estimated: `3509` - // Minimum execution time: 5_651_000 picoseconds. - Weight::from_parts(9_177_000, 0) - .saturating_add(Weight::from_parts(0, 3509)) - .saturating_add(T::DbWeight::get().reads(1)) - } - fn check_non_zero_sender() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 601_000 picoseconds. - Weight::from_parts(2_805_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_nonce() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_727_000 picoseconds. - Weight::from_parts(6_051_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_spec_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 471_000 picoseconds. - Weight::from_parts(2_494_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_tx_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 521_000 picoseconds. - Weight::from_parts(2_655_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) - /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `System::BlockWeight` (r:1 w:1) - /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) - fn check_weight() -> Weight { - // Proof Size summary in bytes: - // Measured: `24` - // Estimated: `1533` - // Minimum execution time: 3_808_000 picoseconds. - Weight::from_parts(6_402_000, 0) - .saturating_add(Weight::from_parts(0, 1533)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs index e23033e0dfd..a65ee31d3e5 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs @@ -25,7 +25,6 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; -pub mod frame_system_extensions; pub mod pallet_balances; pub mod pallet_bridge_grandpa; pub mod pallet_bridge_messages; @@ -36,7 +35,6 @@ pub mod pallet_message_queue; pub mod pallet_multisig; pub mod pallet_session; pub mod pallet_timestamp; -pub mod pallet_transaction_payment; pub mod pallet_utility; pub mod pallet_xcm; pub mod paritydb_weights; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_transaction_payment.rs deleted file mode 100644 index 92c53b91879..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_transaction_payment.rs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `pallet_transaction_payment` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --wasm-execution=compiled -// --pallet=pallet_transaction_payment -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=2 -// --repeat=2 -// --json -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/ -// --chain=bridge-hub-westend-dev - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_transaction_payment`. -pub struct WeightInfo(PhantomData); -impl pallet_transaction_payment::WeightInfo for WeightInfo { - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn charge_transaction_payment() -> Weight { - // Proof Size summary in bytes: - // Measured: `3` - // Estimated: `3593` - // Minimum execution time: 40_286_000 picoseconds. - Weight::from_parts(45_816_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs index 7ea22befe95..149a3bbeb75 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs @@ -24,7 +24,7 @@ use bridge_hub_westend_runtime::{ xcm_config::{RelayNetwork, WestendLocation, XcmConfig}, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, ExistentialDeposit, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, SessionKeys, - TransactionPayment, TxExtension, UncheckedExtrinsic, + SignedExtra, TransactionPayment, UncheckedExtrinsic, }; use bridge_to_rococo_config::{ BridgeGrandpaRococoInstance, BridgeHubRococoChainId, BridgeHubRococoLocation, @@ -65,7 +65,7 @@ fn construct_extrinsic( call: RuntimeCall, ) -> UncheckedExtrinsic { let account_id = AccountId32::from(sender.public()); - let tx_ext: TxExtension = ( + let extra: SignedExtra = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -78,15 +78,14 @@ fn construct_extrinsic( pallet_transaction_payment::ChargeTransactionPayment::::from(0), BridgeRejectObsoleteHeadersAndMessages::default(), (bridge_to_rococo_config::OnBridgeHubWestendRefundBridgeHubRococoMessages::default(),), - ) - .into(); - let payload = SignedPayload::new(call.clone(), tx_ext.clone()).unwrap(); + ); + let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); let signature = payload.using_encoded(|e| sender.sign(e)); UncheckedExtrinsic::new_signed( call, account_id.into(), Signature::Sr25519(signature.clone()), - tx_ext, + extra, ) } diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml index 32d7e97bc45..ed264f28c26 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml @@ -117,7 +117,6 @@ runtime-benchmarks = [ "pallet-salary/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "pallet-treasury/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index 3887a1d74ec..6bcf98c428f 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -175,7 +175,6 @@ impl frame_system::Config for Runtime { type Version = Version; type AccountData = pallet_balances::AccountData; type SystemWeightInfo = weights::frame_system::WeightInfo; - type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; type SS58Prefix = ConstU16<0>; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; type MaxConsumers = frame_support::traits::ConstU32<16>; @@ -232,7 +231,6 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; type OperationalFeeMultiplier = ConstU8<5>; - type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -709,8 +707,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The extension to the basic transaction logic. -pub type TxExtension = ( +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -721,7 +719,7 @@ pub type TxExtension = ( ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// All migrations executed on runtime upgrade as a nested tuple of types implementing /// `OnRuntimeUpgrade`. Included migrations must be idempotent. type Migrations = ( @@ -747,7 +745,6 @@ pub type Executive = frame_executive::Executive< mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] - [frame_system_extensions, SystemExtensionsBench::] [pallet_balances, Balances] [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] @@ -755,7 +752,6 @@ mod benches { [pallet_session, SessionBench::] [pallet_utility, Utility] [pallet_timestamp, Timestamp] - [pallet_transaction_payment, TransactionPayment] [pallet_collator_selection, CollatorSelection] [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] @@ -959,7 +955,6 @@ impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; @@ -977,7 +972,6 @@ impl_runtime_apis! { use sp_storage::TrackedStorageKey; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; impl frame_system_benchmarking::Config for Runtime { fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/frame_system_extensions.rs deleted file mode 100644 index f3030cc4f6a..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/frame_system_extensions.rs +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `frame_system_extensions` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-westend-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --wasm-execution=compiled -// --pallet=frame_system_extensions -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=2 -// --repeat=2 -// --json -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/ -// --chain=collectives-westend-dev - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `frame_system_extensions`. -pub struct WeightInfo(PhantomData); -impl frame_system::ExtensionsWeightInfo for WeightInfo { - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_genesis() -> Weight { - // Proof Size summary in bytes: - // Measured: `54` - // Estimated: `3509` - // Minimum execution time: 3_497_000 picoseconds. - Weight::from_parts(5_961_000, 0) - .saturating_add(Weight::from_parts(0, 3509)) - .saturating_add(T::DbWeight::get().reads(1)) - } - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_mortality() -> Weight { - // Proof Size summary in bytes: - // Measured: `92` - // Estimated: `3509` - // Minimum execution time: 5_240_000 picoseconds. - Weight::from_parts(8_175_000, 0) - .saturating_add(Weight::from_parts(0, 3509)) - .saturating_add(T::DbWeight::get().reads(1)) - } - fn check_non_zero_sender() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 671_000 picoseconds. - Weight::from_parts(3_005_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_nonce() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_426_000 picoseconds. - Weight::from_parts(6_131_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_spec_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 501_000 picoseconds. - Weight::from_parts(2_715_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_tx_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 491_000 picoseconds. - Weight::from_parts(2_635_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) - /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `System::BlockWeight` (r:1 w:1) - /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) - fn check_weight() -> Weight { - // Proof Size summary in bytes: - // Measured: `24` - // Estimated: `1533` - // Minimum execution time: 3_958_000 picoseconds. - Weight::from_parts(6_753_000, 0) - .saturating_add(Weight::from_parts(0, 1533)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs index 00b3bd92d5e..a9a298e547e 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs @@ -18,7 +18,6 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; -pub mod frame_system_extensions; pub mod pallet_alliance; pub mod pallet_asset_rate; pub mod pallet_balances; @@ -40,7 +39,6 @@ pub mod pallet_salary_fellowship_salary; pub mod pallet_scheduler; pub mod pallet_session; pub mod pallet_timestamp; -pub mod pallet_transaction_payment; pub mod pallet_treasury; pub mod pallet_utility; pub mod pallet_xcm; diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_transaction_payment.rs deleted file mode 100644 index 5d077b89d56..00000000000 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_transaction_payment.rs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `pallet_transaction_payment` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-westend-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --wasm-execution=compiled -// --pallet=pallet_transaction_payment -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=2 -// --repeat=2 -// --json -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/ -// --chain=collectives-westend-dev - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_transaction_payment`. -pub struct WeightInfo(PhantomData); -impl pallet_transaction_payment::WeightInfo for WeightInfo { - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn charge_transaction_payment() -> Weight { - // Proof Size summary in bytes: - // Measured: `4` - // Estimated: `3593` - // Minimum execution time: 39_815_000 picoseconds. - Weight::from_parts(46_067_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index 747f75cf2e2..dcc6c4e853a 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -158,7 +158,6 @@ runtime-benchmarks = [ "pallet-multisig/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "parachains-common/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 8ce46ccd34f..0668b9a4c7d 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -80,8 +80,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The extension to the basic transaction logic. -pub type TxExtension = ( +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -93,7 +93,7 @@ pub type TxExtension = ( ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( @@ -240,7 +240,6 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; type OperationalFeeMultiplier = ConstU8<5>; - type WeightInfo = pallet_transaction_payment::weights::SubstrateWeight; } parameter_types! { @@ -424,7 +423,6 @@ construct_runtime!( mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] - [frame_system_extensions, SystemExtensionsBench::] [pallet_balances, Balances] [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] @@ -688,7 +686,6 @@ impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; @@ -706,7 +703,6 @@ impl_runtime_apis! { use sp_storage::TrackedStorageKey; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; impl frame_system_benchmarking::Config for Runtime { fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml b/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml index 70a6a81bdcf..0bc3b510ed5 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml @@ -156,7 +156,6 @@ runtime-benchmarks = [ "pallet-multisig/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs index 9913e47a93a..cdff371c505 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs @@ -89,8 +89,8 @@ pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The TransactionExtension to the basic transaction logic. -pub type TxExtension = ( +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -103,7 +103,7 @@ pub type TxExtension = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( @@ -192,8 +192,6 @@ impl frame_system::Config for Runtime { type DbWeight = RocksDbWeight; /// Weight information for the extrinsics of this pallet. type SystemWeightInfo = weights::frame_system::WeightInfo; - /// Weight information for the extensions of this pallet. - type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; /// Block & extrinsics weights: base values and limits. type BlockWeights = RuntimeBlockWeights; /// The maximum length of a block (in bytes). @@ -253,7 +251,6 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; - type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/frame_system_extensions.rs deleted file mode 100644 index aac73680ad1..00000000000 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/frame_system_extensions.rs +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `frame_system_extensions` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-rococo-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --wasm-execution=compiled -// --pallet=frame_system_extensions -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=2 -// --repeat=2 -// --json -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/ -// --chain=coretime-rococo-dev - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `frame_system_extensions`. -pub struct WeightInfo(PhantomData); -impl frame_system::ExtensionsWeightInfo for WeightInfo { - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_genesis() -> Weight { - // Proof Size summary in bytes: - // Measured: `54` - // Estimated: `3509` - // Minimum execution time: 3_637_000 picoseconds. - Weight::from_parts(6_382_000, 0) - .saturating_add(Weight::from_parts(0, 3509)) - .saturating_add(T::DbWeight::get().reads(1)) - } - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_mortality() -> Weight { - // Proof Size summary in bytes: - // Measured: `92` - // Estimated: `3509` - // Minimum execution time: 5_841_000 picoseconds. - Weight::from_parts(8_776_000, 0) - .saturating_add(Weight::from_parts(0, 3509)) - .saturating_add(T::DbWeight::get().reads(1)) - } - fn check_non_zero_sender() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 561_000 picoseconds. - Weight::from_parts(2_705_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_nonce() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_316_000 picoseconds. - Weight::from_parts(5_771_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_spec_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 511_000 picoseconds. - Weight::from_parts(2_575_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_tx_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 501_000 picoseconds. - Weight::from_parts(2_595_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) - /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `System::BlockWeight` (r:1 w:1) - /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) - fn check_weight() -> Weight { - // Proof Size summary in bytes: - // Measured: `24` - // Estimated: `1533` - // Minimum execution time: 3_687_000 picoseconds. - Weight::from_parts(6_192_000, 0) - .saturating_add(Weight::from_parts(0, 1533)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/mod.rs index 7b6ab611e6f..f1050b3ae63 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/mod.rs @@ -22,7 +22,6 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; -pub mod frame_system_extensions; pub mod pallet_balances; pub mod pallet_broker; pub mod pallet_collator_selection; @@ -30,7 +29,6 @@ pub mod pallet_message_queue; pub mod pallet_multisig; pub mod pallet_session; pub mod pallet_timestamp; -pub mod pallet_transaction_payment; pub mod pallet_utility; pub mod pallet_xcm; pub mod paritydb_weights; diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_transaction_payment.rs deleted file mode 100644 index 29d48abab89..00000000000 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_transaction_payment.rs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `pallet_transaction_payment` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-rococo-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --wasm-execution=compiled -// --pallet=pallet_transaction_payment -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=2 -// --repeat=2 -// --json -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/ -// --chain=coretime-rococo-dev - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_transaction_payment`. -pub struct WeightInfo(PhantomData); -impl pallet_transaction_payment::WeightInfo for WeightInfo { - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn charge_transaction_payment() -> Weight { - // Proof Size summary in bytes: - // Measured: `4` - // Estimated: `3593` - // Minimum execution time: 33_363_000 picoseconds. - Weight::from_parts(38_793_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml b/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml index 549ef7ce4d7..a7d52dfd784 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml @@ -153,7 +153,6 @@ runtime-benchmarks = [ "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs index 1a330821d3f..7fa70647992 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs @@ -89,8 +89,8 @@ pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The TransactionExtension to the basic transaction logic. -pub type TxExtension = ( +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -103,7 +103,7 @@ pub type TxExtension = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( @@ -192,8 +192,6 @@ impl frame_system::Config for Runtime { type DbWeight = RocksDbWeight; /// Weight information for the extrinsics of this pallet. type SystemWeightInfo = weights::frame_system::WeightInfo; - /// Weight information for the extensions of this pallet. - type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; /// Block & extrinsics weights: base values and limits. type BlockWeights = RuntimeBlockWeights; /// The maximum length of a block (in bytes). @@ -253,7 +251,6 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; - type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/frame_system_extensions.rs deleted file mode 100644 index 0683158a01a..00000000000 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/frame_system_extensions.rs +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `frame_system_extensions` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-westend-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --wasm-execution=compiled -// --pallet=frame_system_extensions -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=2 -// --repeat=2 -// --json -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/ -// --chain=coretime-westend-dev - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `frame_system_extensions`. -pub struct WeightInfo(PhantomData); -impl frame_system::ExtensionsWeightInfo for WeightInfo { - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_genesis() -> Weight { - // Proof Size summary in bytes: - // Measured: `54` - // Estimated: `3509` - // Minimum execution time: 3_637_000 picoseconds. - Weight::from_parts(6_382_000, 0) - .saturating_add(Weight::from_parts(0, 3509)) - .saturating_add(T::DbWeight::get().reads(1)) - } - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_mortality() -> Weight { - // Proof Size summary in bytes: - // Measured: `92` - // Estimated: `3509` - // Minimum execution time: 5_841_000 picoseconds. - Weight::from_parts(8_776_000, 0) - .saturating_add(Weight::from_parts(0, 3509)) - .saturating_add(T::DbWeight::get().reads(1)) - } - fn check_non_zero_sender() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 561_000 picoseconds. - Weight::from_parts(2_705_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_nonce() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_316_000 picoseconds. - Weight::from_parts(5_771_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_spec_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 511_000 picoseconds. - Weight::from_parts(2_575_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_tx_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 501_000 picoseconds. - Weight::from_parts(2_595_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) - /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `System::BlockWeight` (r:1 w:1) - /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) - fn check_weight() -> Weight { - // Proof Size summary in bytes: - // Measured: `24` - // Estimated: `1533` - // Minimum execution time: 3_687_000 picoseconds. - Weight::from_parts(6_192_000, 0) - .saturating_add(Weight::from_parts(0, 1533)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/mod.rs index 7b6ab611e6f..f1050b3ae63 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/mod.rs @@ -22,7 +22,6 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; -pub mod frame_system_extensions; pub mod pallet_balances; pub mod pallet_broker; pub mod pallet_collator_selection; @@ -30,7 +29,6 @@ pub mod pallet_message_queue; pub mod pallet_multisig; pub mod pallet_session; pub mod pallet_timestamp; -pub mod pallet_transaction_payment; pub mod pallet_utility; pub mod pallet_xcm; pub mod paritydb_weights; diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_transaction_payment.rs deleted file mode 100644 index f159f877afe..00000000000 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_transaction_payment.rs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `pallet_transaction_payment` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-westend-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --wasm-execution=compiled -// --pallet=pallet_transaction_payment -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=2 -// --repeat=2 -// --json -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/ -// --chain=coretime-westend-dev - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_transaction_payment`. -pub struct WeightInfo(PhantomData); -impl pallet_transaction_payment::WeightInfo for WeightInfo { - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn charge_transaction_payment() -> Weight { - // Proof Size summary in bytes: - // Measured: `4` - // Estimated: `3593` - // Minimum execution time: 33_363_000 picoseconds. - Weight::from_parts(38_793_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs index 199057c3764..232a82115a8 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs @@ -289,8 +289,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The extension to the basic transaction logic. -pub type TxExtension = ( +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( pallet_sudo::CheckOnlySudoAccount, frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, @@ -301,7 +301,7 @@ pub type TxExtension = ( ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, @@ -316,7 +316,6 @@ mod benches { frame_benchmarking::define_benchmarks!( [cumulus_pallet_parachain_system, ParachainSystem] [frame_system, SystemBench::] - [frame_system_extensions, SystemExtensionsBench::] [pallet_glutton, Glutton] [pallet_message_queue, MessageQueue] [pallet_timestamp, Timestamp] @@ -440,7 +439,6 @@ impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; let mut list = Vec::::new(); list_benchmarks!(list, extra); @@ -457,7 +455,6 @@ impl_runtime_apis! { use sp_storage::TrackedStorageKey; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; impl frame_system_benchmarking::Config for Runtime { fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/frame_system_extensions.rs deleted file mode 100644 index e6efa762308..00000000000 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/frame_system_extensions.rs +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `frame_system_extensions` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("glutton-westend-dev-1300")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --wasm-execution=compiled -// --pallet=frame_system_extensions -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=2 -// --repeat=2 -// --json -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/ -// --chain=glutton-westend-dev-1300 - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `frame_system_extensions`. -pub struct WeightInfo(PhantomData); -impl frame_system::ExtensionsWeightInfo for WeightInfo { - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_genesis() -> Weight { - // Proof Size summary in bytes: - // Measured: `54` - // Estimated: `3509` - // Minimum execution time: 3_908_000 picoseconds. - Weight::from_parts(4_007_000, 0) - .saturating_add(Weight::from_parts(0, 3509)) - .saturating_add(T::DbWeight::get().reads(1)) - } - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_mortality() -> Weight { - // Proof Size summary in bytes: - // Measured: `92` - // Estimated: `3509` - // Minimum execution time: 5_510_000 picoseconds. - Weight::from_parts(6_332_000, 0) - .saturating_add(Weight::from_parts(0, 3509)) - .saturating_add(T::DbWeight::get().reads(1)) - } - fn check_non_zero_sender() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 651_000 picoseconds. - Weight::from_parts(851_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_nonce() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_387_000 picoseconds. - Weight::from_parts(3_646_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_spec_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 491_000 picoseconds. - Weight::from_parts(651_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_tx_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 451_000 picoseconds. - Weight::from_parts(662_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) - /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn check_weight() -> Weight { - // Proof Size summary in bytes: - // Measured: `24` - // Estimated: `1489` - // Minimum execution time: 3_537_000 picoseconds. - Weight::from_parts(4_208_000, 0) - .saturating_add(Weight::from_parts(0, 1489)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml b/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml index c9781639c3e..c0b8fb7636b 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml @@ -152,7 +152,6 @@ runtime-benchmarks = [ "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs index c5e420785de..2b8cc32f67c 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs @@ -83,8 +83,8 @@ pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The TransactionExtension to the basic transaction logic. -pub type TxExtension = ( +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -97,7 +97,7 @@ pub type TxExtension = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( @@ -178,7 +178,6 @@ impl frame_system::Config for Runtime { type Version = Version; type AccountData = pallet_balances::AccountData; type SystemWeightInfo = weights::frame_system::WeightInfo; - type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; type MaxConsumers = ConstU32<16>; @@ -233,7 +232,6 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; - type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -455,7 +453,6 @@ mod benches { [pallet_session, SessionBench::] [pallet_utility, Utility] [pallet_timestamp, Timestamp] - [pallet_transaction_payment, TransactionPayment] // Polkadot [polkadot_runtime_common::identity_migrator, IdentityMigrator] // Cumulus diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/frame_system_extensions.rs deleted file mode 100644 index 1ba2010991f..00000000000 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/frame_system_extensions.rs +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `frame_system_extensions` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("people-rococo-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --wasm-execution=compiled -// --pallet=frame_system_extensions -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=2 -// --repeat=2 -// --json -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/people/people-rococo/src/weights/ -// --chain=people-rococo-dev - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `frame_system_extensions`. -pub struct WeightInfo(PhantomData); -impl frame_system::ExtensionsWeightInfo for WeightInfo { - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_genesis() -> Weight { - // Proof Size summary in bytes: - // Measured: `54` - // Estimated: `3509` - // Minimum execution time: 3_637_000 picoseconds. - Weight::from_parts(6_382_000, 0) - .saturating_add(Weight::from_parts(0, 3509)) - .saturating_add(T::DbWeight::get().reads(1)) - } - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_mortality() -> Weight { - // Proof Size summary in bytes: - // Measured: `92` - // Estimated: `3509` - // Minimum execution time: 5_841_000 picoseconds. - Weight::from_parts(8_776_000, 0) - .saturating_add(Weight::from_parts(0, 3509)) - .saturating_add(T::DbWeight::get().reads(1)) - } - fn check_non_zero_sender() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 561_000 picoseconds. - Weight::from_parts(2_705_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_nonce() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_316_000 picoseconds. - Weight::from_parts(5_771_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_spec_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 511_000 picoseconds. - Weight::from_parts(2_575_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_tx_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 501_000 picoseconds. - Weight::from_parts(2_595_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) - /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `System::BlockWeight` (r:1 w:1) - /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) - fn check_weight() -> Weight { - // Proof Size summary in bytes: - // Measured: `24` - // Estimated: `1533` - // Minimum execution time: 3_687_000 picoseconds. - Weight::from_parts(6_192_000, 0) - .saturating_add(Weight::from_parts(0, 1533)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/mod.rs index c4cea99ee5a..3396a8caea0 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/mod.rs @@ -20,7 +20,6 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; -pub mod frame_system_extensions; pub mod pallet_balances; pub mod pallet_collator_selection; pub mod pallet_identity; @@ -28,7 +27,6 @@ pub mod pallet_message_queue; pub mod pallet_multisig; pub mod pallet_session; pub mod pallet_timestamp; -pub mod pallet_transaction_payment; pub mod pallet_utility; pub mod pallet_xcm; pub mod paritydb_weights; diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_transaction_payment.rs deleted file mode 100644 index 555fd5a32fa..00000000000 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_transaction_payment.rs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `pallet_transaction_payment` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("people-rococo-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --wasm-execution=compiled -// --pallet=pallet_transaction_payment -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=2 -// --repeat=2 -// --json -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/people/people-rococo/src/weights/ -// --chain=people-rococo-dev - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_transaction_payment`. -pub struct WeightInfo(PhantomData); -impl pallet_transaction_payment::WeightInfo for WeightInfo { - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn charge_transaction_payment() -> Weight { - // Proof Size summary in bytes: - // Measured: `4` - // Estimated: `3593` - // Minimum execution time: 33_363_000 picoseconds. - Weight::from_parts(38_793_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/cumulus/parachains/runtimes/people/people-westend/Cargo.toml b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml index 8d8421332c1..e87e825a34e 100644 --- a/cumulus/parachains/runtimes/people/people-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml @@ -152,7 +152,6 @@ runtime-benchmarks = [ "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs index dea079a4a98..2dc2d06a66b 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs @@ -83,8 +83,8 @@ pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The transactionExtension to the basic transaction logic. -pub type TxExtension = ( +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -97,7 +97,7 @@ pub type TxExtension = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( @@ -178,7 +178,6 @@ impl frame_system::Config for Runtime { type Version = Version; type AccountData = pallet_balances::AccountData; type SystemWeightInfo = weights::frame_system::WeightInfo; - type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; type MaxConsumers = ConstU32<16>; @@ -233,7 +232,6 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; - type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/frame_system_extensions.rs deleted file mode 100644 index 7130a62ab6a..00000000000 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/frame_system_extensions.rs +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `frame_system_extensions` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("people-westend-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --wasm-execution=compiled -// --pallet=frame_system_extensions -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=2 -// --repeat=2 -// --json -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/people/people-westend/src/weights/ -// --chain=people-westend-dev - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `frame_system_extensions`. -pub struct WeightInfo(PhantomData); -impl frame_system::ExtensionsWeightInfo for WeightInfo { - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_genesis() -> Weight { - // Proof Size summary in bytes: - // Measured: `54` - // Estimated: `3509` - // Minimum execution time: 3_637_000 picoseconds. - Weight::from_parts(6_382_000, 0) - .saturating_add(Weight::from_parts(0, 3509)) - .saturating_add(T::DbWeight::get().reads(1)) - } - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_mortality() -> Weight { - // Proof Size summary in bytes: - // Measured: `92` - // Estimated: `3509` - // Minimum execution time: 5_841_000 picoseconds. - Weight::from_parts(8_776_000, 0) - .saturating_add(Weight::from_parts(0, 3509)) - .saturating_add(T::DbWeight::get().reads(1)) - } - fn check_non_zero_sender() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 561_000 picoseconds. - Weight::from_parts(2_705_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_nonce() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_316_000 picoseconds. - Weight::from_parts(5_771_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_spec_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 511_000 picoseconds. - Weight::from_parts(2_575_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_tx_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 501_000 picoseconds. - Weight::from_parts(2_595_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) - /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `System::BlockWeight` (r:1 w:1) - /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) - fn check_weight() -> Weight { - // Proof Size summary in bytes: - // Measured: `24` - // Estimated: `1533` - // Minimum execution time: 3_687_000 picoseconds. - Weight::from_parts(6_192_000, 0) - .saturating_add(Weight::from_parts(0, 1533)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/mod.rs index c4cea99ee5a..3396a8caea0 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/mod.rs @@ -20,7 +20,6 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; -pub mod frame_system_extensions; pub mod pallet_balances; pub mod pallet_collator_selection; pub mod pallet_identity; @@ -28,7 +27,6 @@ pub mod pallet_message_queue; pub mod pallet_multisig; pub mod pallet_session; pub mod pallet_timestamp; -pub mod pallet_transaction_payment; pub mod pallet_utility; pub mod pallet_xcm; pub mod paritydb_weights; diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_transaction_payment.rs deleted file mode 100644 index 30e4524e586..00000000000 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_transaction_payment.rs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Autogenerated weights for `pallet_transaction_payment` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("people-westend-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot-parachain -// benchmark -// pallet -// --wasm-execution=compiled -// --pallet=pallet_transaction_payment -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --steps=2 -// --repeat=2 -// --json -// --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/people/people-westend/src/weights/ -// --chain=people-westend-dev - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_transaction_payment`. -pub struct WeightInfo(PhantomData); -impl pallet_transaction_payment::WeightInfo for WeightInfo { - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn charge_transaction_payment() -> Weight { - // Proof Size summary in bytes: - // Measured: `4` - // Estimated: `3593` - // Minimum execution time: 33_363_000 picoseconds. - Weight::from_parts(38_793_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs index 023c9978302..4cc0a81ef49 100644 --- a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs @@ -258,8 +258,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The extension to the basic transaction logic. -pub type TxExtension = ( +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( frame_system::CheckSpecVersion, frame_system::CheckTxVersion, frame_system::CheckGenesis, @@ -269,7 +269,7 @@ pub type TxExtension = ( ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< diff --git a/cumulus/parachains/runtimes/starters/shell/src/lib.rs b/cumulus/parachains/runtimes/starters/shell/src/lib.rs index fedac36e48d..829754731a4 100644 --- a/cumulus/parachains/runtimes/starters/shell/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/shell/src/lib.rs @@ -34,19 +34,15 @@ pub mod xcm_config; use codec::{Decode, Encode}; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use cumulus_primitives_core::AggregateMessageOrigin; +use frame_support::unsigned::TransactionValidityError; use scale_info::TypeInfo; use sp_api::impl_runtime_apis; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, - traits::{ - AccountIdLookup, BlakeTwo256, Block as BlockT, DispatchInfoOf, OriginOf, - TransactionExtension, TransactionExtensionBase, ValidateResult, - }, - transaction_validity::{ - InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError, - }, + traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, DispatchInfoOf}, + transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, }; use sp_std::prelude::*; @@ -279,37 +275,35 @@ construct_runtime! { /// Simple implementation which fails any transaction which is signed. #[derive(Eq, PartialEq, Clone, Default, sp_core::RuntimeDebug, Encode, Decode, TypeInfo)] pub struct DisallowSigned; - -impl TransactionExtensionBase for DisallowSigned { +impl sp_runtime::traits::SignedExtension for DisallowSigned { const IDENTIFIER: &'static str = "DisallowSigned"; - type Implicit = (); -} - -impl TransactionExtension for DisallowSigned { - type Val = (); + type AccountId = AccountId; + type Call = RuntimeCall; + type AdditionalSigned = (); type Pre = (); - fn validate( + fn additional_signed( &self, - _origin: OriginOf, - _call: &RuntimeCall, - _info: &DispatchInfoOf, - _len: usize, - _context: &mut C, - _self_implicit: Self::Implicit, - _inherited_implication: &impl Encode, - ) -> ValidateResult { - Err(InvalidTransaction::BadProof.into()) + ) -> sp_std::result::Result<(), sp_runtime::transaction_validity::TransactionValidityError> { + Ok(()) } - fn prepare( + fn pre_dispatch( self, - _val: Self::Val, - _origin: &OriginOf, - _call: &RuntimeCall, - _info: &DispatchInfoOf, - _len: usize, - _context: &C, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, ) -> Result { - Err(InvalidTransaction::BadProof.into()) + self.validate(who, call, info, len).map(|_| ()) + } + fn validate( + &self, + _who: &Self::AccountId, + _call: &Self::Call, + _info: &sp_runtime::traits::DispatchInfoOf, + _len: usize, + ) -> TransactionValidity { + let i = sp_runtime::transaction_validity::InvalidTransaction::BadProof; + Err(sp_runtime::transaction_validity::TransactionValidityError::Invalid(i)) } } @@ -329,11 +323,11 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The extension to the basic transaction logic. -pub type TxExtension = DisallowSigned; +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = DisallowSigned; /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index 5a8b15740e4..7f3e898d923 100644 --- a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml @@ -156,7 +156,6 @@ runtime-benchmarks = [ "pallet-message-queue/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index 62065619e42..0030287edb3 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -114,8 +114,8 @@ pub type BlockId = generic::BlockId; // Id used for identifying assets. pub type AssetId = u32; -/// The extension to the basic transaction logic. -pub type TxExtension = ( +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -128,7 +128,7 @@ pub type TxExtension = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; pub type Migrations = ( pallet_balances::migration::MigrateToTrackInactive, @@ -419,7 +419,6 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; type OperationalFeeMultiplier = ConstU8<5>; - type WeightInfo = (); } parameter_types! { @@ -609,19 +608,6 @@ impl pallet_collator_selection::Config for Runtime { type WeightInfo = (); } -#[cfg(feature = "runtime-benchmarks")] -pub struct AssetTxHelper; - -#[cfg(feature = "runtime-benchmarks")] -impl pallet_asset_tx_payment::BenchmarkHelperTrait for AssetTxHelper { - fn create_asset_id_parameter(_id: u32) -> (u32, u32) { - unimplemented!("Penpal uses default weights"); - } - fn setup_balances_and_pool(_asset_id: u32, _account: AccountId) { - unimplemented!("Penpal uses default weights"); - } -} - impl pallet_asset_tx_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Fungibles = Assets; @@ -634,9 +620,6 @@ impl pallet_asset_tx_payment::Config for Runtime { >, AssetsToBlockAuthor, >; - type WeightInfo = (); - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = AssetTxHelper; } impl pallet_sudo::Config for Runtime { @@ -685,7 +668,6 @@ construct_runtime!( mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] - [frame_system_extensions, SystemExtensionsBench::] [pallet_balances, Balances] [pallet_message_queue, MessageQueue] [pallet_session, SessionBench::] @@ -869,7 +851,6 @@ impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; let mut list = Vec::::new(); @@ -886,7 +867,6 @@ impl_runtime_apis! { use sp_storage::TrackedStorageKey; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; impl frame_system_benchmarking::Config for Runtime {} use cumulus_pallet_session_benchmarking::Pallet as SessionBench; diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml index 2023d9abf5d..42169e8949f 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -126,7 +126,6 @@ runtime-benchmarks = [ "pallet-message-queue/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index 469f06a1aa6..2b21a12c3ca 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -267,7 +267,6 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = (); type OperationalFeeMultiplier = ConstU8<5>; - type WeightInfo = (); } impl pallet_sudo::Config for Runtime { @@ -645,8 +644,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The extension to the basic transaction logic. -pub type TxExtension = ( +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -658,7 +657,7 @@ pub type TxExtension = ( ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index a92e8a4c12a..84a232e954f 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -136,7 +136,6 @@ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "glutton-westend-runtime/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "parachains-common/runtime-benchmarks", "penpal-runtime/runtime-benchmarks", "people-rococo-runtime/runtime-benchmarks", diff --git a/cumulus/primitives/storage-weight-reclaim/Cargo.toml b/cumulus/primitives/storage-weight-reclaim/Cargo.toml index 9e8f60783d4..4835fb5192b 100644 --- a/cumulus/primitives/storage-weight-reclaim/Cargo.toml +++ b/cumulus/primitives/storage-weight-reclaim/Cargo.toml @@ -14,12 +14,9 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = log = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } frame-support = { path = "../../../substrate/frame/support", default-features = false } frame-system = { path = "../../../substrate/frame/system", default-features = false } -sp-core = { path = "../../../substrate/primitives/core", default-features = false } -sp-io = { path = "../../../substrate/primitives/io", default-features = false } sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } sp-std = { path = "../../../substrate/primitives/std", default-features = false } @@ -29,27 +26,19 @@ docify = "0.2.7" [dev-dependencies] sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } +sp-io = { path = "../../../substrate/primitives/io", default-features = false } cumulus-test-runtime = { path = "../../test/runtime" } [features] default = ["std"] -runtime-benchmarks = [ - "cumulus-primitives-core/runtime-benchmarks", - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", -] std = [ "codec/std", "cumulus-primitives-core/std", "cumulus-primitives-proof-size-hostfunction/std", - "frame-benchmarking/std", "frame-support/std", "frame-system/std", "log/std", "scale-info/std", - "sp-core/std", "sp-io/std", "sp-runtime/std", "sp-std/std", diff --git a/cumulus/primitives/storage-weight-reclaim/src/benchmarking.rs b/cumulus/primitives/storage-weight-reclaim/src/benchmarking.rs deleted file mode 100644 index 2980d08271a..00000000000 --- a/cumulus/primitives/storage-weight-reclaim/src/benchmarking.rs +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Benchmarking setup for cumulus-primitives-storage-weight-reclaim - -#![cfg(feature = "runtime-benchmarks")] - -use super::*; - -use frame_benchmarking::{account, v2::*, BenchmarkError}; -use frame_support::pallet_prelude::DispatchClass; -use frame_system::{BlockWeight, RawOrigin}; -use sp_runtime::traits::{DispatchTransaction, Get}; -use sp_std::{ - marker::{Send, Sync}, - prelude::*, -}; - -/// Pallet we're benchmarking here. -pub struct Pallet(frame_system::Pallet); - -#[benchmarks(where - T: Send + Sync, - T::RuntimeCall: Dispatchable -)] -mod benchmarks { - use super::*; - - #[benchmark] - fn storage_weight_reclaim() -> Result<(), BenchmarkError> { - let caller = account("caller", 0, 0); - BlockWeight::::mutate(|current_weight| { - current_weight.set(Weight::from_parts(0, 1000), DispatchClass::Normal); - }); - let base_extrinsic = ::BlockWeights::get() - .get(DispatchClass::Normal) - .base_extrinsic; - let info = DispatchInfo { weight: Weight::from_parts(0, 500), ..Default::default() }; - let call: T::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into(); - let post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_parts(0, 200)), - pays_fee: Default::default(), - }; - let len = 0_usize; - let ext = StorageWeightReclaim::::new(); - - #[block] - { - ext.test_run(RawOrigin::Signed(caller).into(), &call, &info, len, |_| Ok(post_info)) - .unwrap() - .unwrap(); - } - - assert_eq!(BlockWeight::::get().total().proof_size(), 700 + base_extrinsic.proof_size()); - - Ok(()) - } -} diff --git a/cumulus/primitives/storage-weight-reclaim/src/lib.rs b/cumulus/primitives/storage-weight-reclaim/src/lib.rs index 4bb40176b78..5dddc92e395 100644 --- a/cumulus/primitives/storage-weight-reclaim/src/lib.rs +++ b/cumulus/primitives/storage-weight-reclaim/src/lib.rs @@ -29,22 +29,12 @@ use frame_support::{ use frame_system::Config; use scale_info::TypeInfo; use sp_runtime::{ - impl_tx_ext_default, - traits::{ - DispatchInfoOf, Dispatchable, PostDispatchInfoOf, TransactionExtension, - TransactionExtensionBase, - }, + traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SignedExtension}, transaction_validity::TransactionValidityError, DispatchResult, }; use sp_std::marker::PhantomData; -#[cfg(test)] -mod tests; - -#[cfg(feature = "runtime-benchmarks")] -mod benchmarking; - const LOG_TARGET: &'static str = "runtime::storage_reclaim"; /// `StorageWeightReclaimer` is a mechanism for manually reclaiming storage weight. @@ -53,7 +43,7 @@ const LOG_TARGET: &'static str = "runtime::storage_reclaim"; /// reclaim it computes the real consumed storage weight and refunds excess weight. /// /// # Example -#[doc = docify::embed!("src/tests.rs", simple_reclaimer_example)] +#[doc = docify::embed!("src/lib.rs", simple_reclaimer_example)] pub struct StorageWeightReclaimer { previous_remaining_proof_size: u64, previous_reported_proof_size: Option, @@ -129,40 +119,42 @@ impl core::fmt::Debug for StorageWeightReclaim { } } -impl TransactionExtensionBase for StorageWeightReclaim { - const IDENTIFIER: &'static str = "StorageWeightReclaim"; - type Implicit = (); -} - -impl TransactionExtension - for StorageWeightReclaim +impl SignedExtension for StorageWeightReclaim where T::RuntimeCall: Dispatchable, { - type Val = (); + const IDENTIFIER: &'static str = "StorageWeightReclaim"; + + type AccountId = T::AccountId; + type Call = T::RuntimeCall; + type AdditionalSigned = (); type Pre = Option; - fn prepare( + fn additional_signed( + &self, + ) -> Result + { + Ok(()) + } + + fn pre_dispatch( self, - _val: Self::Val, - _origin: &T::RuntimeOrigin, - _call: &T::RuntimeCall, - _info: &DispatchInfoOf, + _who: &Self::AccountId, + _call: &Self::Call, + _info: &sp_runtime::traits::DispatchInfoOf, _len: usize, - _context: &Context, - ) -> Result { + ) -> Result { Ok(get_proof_size()) } fn post_dispatch( - pre: Self::Pre, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + pre: Option, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, _len: usize, _result: &DispatchResult, - _context: &Context, ) -> Result<(), TransactionValidityError> { - let Some(pre_dispatch_proof_size) = pre else { + let Some(Some(pre_dispatch_proof_size)) = pre else { return Ok(()); }; @@ -202,6 +194,470 @@ where }); Ok(()) } +} + +#[cfg(test)] +mod tests { + use super::*; + use frame_support::{ + assert_ok, + dispatch::DispatchClass, + weights::{Weight, WeightMeter}, + }; + use frame_system::{BlockWeight, CheckWeight}; + use sp_runtime::{AccountId32, BuildStorage}; + use sp_std::marker::PhantomData; + use sp_trie::proof_size_extension::ProofSizeExt; + + type Test = cumulus_test_runtime::Runtime; + const CALL: &::RuntimeCall = + &cumulus_test_runtime::RuntimeCall::System(frame_system::Call::set_heap_pages { + pages: 0u64, + }); + const ALICE: AccountId32 = AccountId32::new([1u8; 32]); + const LEN: usize = 0; + + pub fn new_test_ext() -> sp_io::TestExternalities { + let ext: sp_io::TestExternalities = cumulus_test_runtime::RuntimeGenesisConfig::default() + .build_storage() + .unwrap() + .into(); + ext + } + + struct TestRecorder { + return_values: Box<[usize]>, + counter: std::sync::atomic::AtomicUsize, + } + + impl TestRecorder { + fn new(values: &[usize]) -> Self { + TestRecorder { return_values: values.into(), counter: Default::default() } + } + } + + impl sp_trie::ProofSizeProvider for TestRecorder { + fn estimate_encoded_size(&self) -> usize { + let counter = self.counter.fetch_add(1, core::sync::atomic::Ordering::Relaxed); + self.return_values[counter] + } + } + + fn setup_test_externalities(proof_values: &[usize]) -> sp_io::TestExternalities { + let mut test_ext = new_test_ext(); + let test_recorder = TestRecorder::new(proof_values); + test_ext.register_extension(ProofSizeExt::new(test_recorder)); + test_ext + } + + fn set_current_storage_weight(new_weight: u64) { + BlockWeight::::mutate(|current_weight| { + current_weight.set(Weight::from_parts(0, new_weight), DispatchClass::Normal); + }); + } + + #[test] + fn basic_refund() { + // The real cost will be 100 bytes of storage size + let mut test_ext = setup_test_externalities(&[0, 100]); + + test_ext.execute_with(|| { + set_current_storage_weight(1000); + + // Benchmarked storage weight: 500 + let info = DispatchInfo { weight: Weight::from_parts(0, 500), ..Default::default() }; + let post_info = PostDispatchInfo::default(); + + let pre = StorageWeightReclaim::(PhantomData) + .pre_dispatch(&ALICE, CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(0)); + + assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); + // We expect a refund of 400 + assert_ok!(StorageWeightReclaim::::post_dispatch( + Some(pre), + &info, + &post_info, + LEN, + &Ok(()) + )); + + assert_eq!(BlockWeight::::get().total().proof_size(), 600); + }) + } + + #[test] + fn does_nothing_without_extension() { + let mut test_ext = new_test_ext(); + + // Proof size extension not registered + test_ext.execute_with(|| { + set_current_storage_weight(1000); + + // Benchmarked storage weight: 500 + let info = DispatchInfo { weight: Weight::from_parts(0, 500), ..Default::default() }; + let post_info = PostDispatchInfo::default(); + + let pre = StorageWeightReclaim::(PhantomData) + .pre_dispatch(&ALICE, CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, None); + + assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); + assert_ok!(StorageWeightReclaim::::post_dispatch( + Some(pre), + &info, + &post_info, + LEN, + &Ok(()) + )); + + assert_eq!(BlockWeight::::get().total().proof_size(), 1000); + }) + } + + #[test] + fn negative_refund_is_added_to_weight() { + let mut test_ext = setup_test_externalities(&[100, 300]); + + test_ext.execute_with(|| { + set_current_storage_weight(1000); + // Benchmarked storage weight: 100 + let info = DispatchInfo { weight: Weight::from_parts(0, 100), ..Default::default() }; + let post_info = PostDispatchInfo::default(); + + let pre = StorageWeightReclaim::(PhantomData) + .pre_dispatch(&ALICE, CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(100)); + + // We expect no refund + assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); + assert_ok!(StorageWeightReclaim::::post_dispatch( + Some(pre), + &info, + &post_info, + LEN, + &Ok(()) + )); + + assert_eq!(BlockWeight::::get().total().proof_size(), 1100); + }) + } + + #[test] + fn test_zero_proof_size() { + let mut test_ext = setup_test_externalities(&[0, 0]); + + test_ext.execute_with(|| { + let info = DispatchInfo { weight: Weight::from_parts(0, 500), ..Default::default() }; + let post_info = PostDispatchInfo::default(); + + let pre = StorageWeightReclaim::(PhantomData) + .pre_dispatch(&ALICE, CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(0)); + + assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); + assert_ok!(StorageWeightReclaim::::post_dispatch( + Some(pre), + &info, + &post_info, + LEN, + &Ok(()) + )); + + assert_eq!(BlockWeight::::get().total().proof_size(), 0); + }); + } + + #[test] + fn test_larger_pre_dispatch_proof_size() { + let mut test_ext = setup_test_externalities(&[300, 100]); + + test_ext.execute_with(|| { + set_current_storage_weight(1300); + + let info = DispatchInfo { weight: Weight::from_parts(0, 500), ..Default::default() }; + let post_info = PostDispatchInfo::default(); + + let pre = StorageWeightReclaim::(PhantomData) + .pre_dispatch(&ALICE, CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(300)); + + assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); + assert_ok!(StorageWeightReclaim::::post_dispatch( + Some(pre), + &info, + &post_info, + LEN, + &Ok(()) + )); + + assert_eq!(BlockWeight::::get().total().proof_size(), 800); + }); + } + + #[test] + fn test_incorporates_check_weight_unspent_weight() { + let mut test_ext = setup_test_externalities(&[100, 300]); + + test_ext.execute_with(|| { + set_current_storage_weight(1000); + + // Benchmarked storage weight: 300 + let info = DispatchInfo { weight: Weight::from_parts(100, 300), ..Default::default() }; + + // Actual weight is 50 + let post_info = PostDispatchInfo { + actual_weight: Some(Weight::from_parts(50, 250)), + pays_fee: Default::default(), + }; + + let pre = StorageWeightReclaim::(PhantomData) + .pre_dispatch(&ALICE, CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(100)); + + // The `CheckWeight` extension will refunt `actual_weight` from `PostDispatchInfo` + // we always need to call `post_dispatch` to verify that they interoperate correctly. + assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); + assert_ok!(StorageWeightReclaim::::post_dispatch( + Some(pre), + &info, + &post_info, + LEN, + &Ok(()) + )); + + assert_eq!(BlockWeight::::get().total().proof_size(), 900); + }) + } + + #[test] + fn test_incorporates_check_weight_unspent_weight_on_negative() { + let mut test_ext = setup_test_externalities(&[100, 300]); + + test_ext.execute_with(|| { + set_current_storage_weight(1000); + // Benchmarked storage weight: 50 + let info = DispatchInfo { weight: Weight::from_parts(100, 50), ..Default::default() }; + + // Actual weight is 25 + let post_info = PostDispatchInfo { + actual_weight: Some(Weight::from_parts(50, 25)), + pays_fee: Default::default(), + }; + + let pre = StorageWeightReclaim::(PhantomData) + .pre_dispatch(&ALICE, CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(100)); + + // The `CheckWeight` extension will refunt `actual_weight` from `PostDispatchInfo` + // we always need to call `post_dispatch` to verify that they interoperate correctly. + assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); + assert_ok!(StorageWeightReclaim::::post_dispatch( + Some(pre), + &info, + &post_info, + LEN, + &Ok(()) + )); + + assert_eq!(BlockWeight::::get().total().proof_size(), 1150); + }) + } + + #[test] + fn test_incorporates_check_weight_unspent_weight_reverse_order() { + let mut test_ext = setup_test_externalities(&[100, 300]); + + test_ext.execute_with(|| { + set_current_storage_weight(1000); + + // Benchmarked storage weight: 300 + let info = DispatchInfo { weight: Weight::from_parts(100, 300), ..Default::default() }; + + // Actual weight is 50 + let post_info = PostDispatchInfo { + actual_weight: Some(Weight::from_parts(50, 250)), + pays_fee: Default::default(), + }; + + let pre = StorageWeightReclaim::(PhantomData) + .pre_dispatch(&ALICE, CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(100)); + + assert_ok!(StorageWeightReclaim::::post_dispatch( + Some(pre), + &info, + &post_info, + LEN, + &Ok(()) + )); + // `CheckWeight` gets called after `StorageWeightReclaim` this time. + // The `CheckWeight` extension will refunt `actual_weight` from `PostDispatchInfo` + // we always need to call `post_dispatch` to verify that they interoperate correctly. + assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); + + assert_eq!(BlockWeight::::get().total().proof_size(), 900); + }) + } + + #[test] + fn test_incorporates_check_weight_unspent_weight_on_negative_reverse_order() { + let mut test_ext = setup_test_externalities(&[100, 300]); + + test_ext.execute_with(|| { + set_current_storage_weight(1000); + // Benchmarked storage weight: 50 + let info = DispatchInfo { weight: Weight::from_parts(100, 50), ..Default::default() }; - impl_tx_ext_default!(T::RuntimeCall; Context; validate); + // Actual weight is 25 + let post_info = PostDispatchInfo { + actual_weight: Some(Weight::from_parts(50, 25)), + pays_fee: Default::default(), + }; + + let pre = StorageWeightReclaim::(PhantomData) + .pre_dispatch(&ALICE, CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(100)); + + assert_ok!(StorageWeightReclaim::::post_dispatch( + Some(pre), + &info, + &post_info, + LEN, + &Ok(()) + )); + // `CheckWeight` gets called after `StorageWeightReclaim` this time. + // The `CheckWeight` extension will refunt `actual_weight` from `PostDispatchInfo` + // we always need to call `post_dispatch` to verify that they interoperate correctly. + assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); + + assert_eq!(BlockWeight::::get().total().proof_size(), 1150); + }) + } + + #[test] + fn storage_size_reported_correctly() { + let mut test_ext = setup_test_externalities(&[1000]); + test_ext.execute_with(|| { + assert_eq!(get_proof_size(), Some(1000)); + }); + + let mut test_ext = new_test_ext(); + + let test_recorder = TestRecorder::new(&[0]); + + test_ext.register_extension(ProofSizeExt::new(test_recorder)); + + test_ext.execute_with(|| { + assert_eq!(get_proof_size(), Some(0)); + }); + } + + #[test] + fn storage_size_disabled_reported_correctly() { + let mut test_ext = setup_test_externalities(&[PROOF_RECORDING_DISABLED as usize]); + + test_ext.execute_with(|| { + assert_eq!(get_proof_size(), None); + }); + } + + #[test] + fn test_reclaim_helper() { + let mut test_ext = setup_test_externalities(&[1000, 1300, 1800]); + + test_ext.execute_with(|| { + let mut remaining_weight_meter = WeightMeter::with_limit(Weight::from_parts(0, 2000)); + let mut reclaim_helper = StorageWeightReclaimer::new(&remaining_weight_meter); + remaining_weight_meter.consume(Weight::from_parts(0, 500)); + let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); + + assert_eq!(reclaimed, Some(Weight::from_parts(0, 200))); + + remaining_weight_meter.consume(Weight::from_parts(0, 800)); + let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); + assert_eq!(reclaimed, Some(Weight::from_parts(0, 300))); + assert_eq!(remaining_weight_meter.remaining(), Weight::from_parts(0, 1200)); + }); + } + + #[test] + fn test_reclaim_helper_does_not_reclaim_negative() { + // Benchmarked weight does not change at all + let mut test_ext = setup_test_externalities(&[1000, 1300]); + + test_ext.execute_with(|| { + let mut remaining_weight_meter = WeightMeter::with_limit(Weight::from_parts(0, 1000)); + let mut reclaim_helper = StorageWeightReclaimer::new(&remaining_weight_meter); + let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); + + assert_eq!(reclaimed, Some(Weight::from_parts(0, 0))); + assert_eq!(remaining_weight_meter.remaining(), Weight::from_parts(0, 1000)); + }); + + // Benchmarked weight increases less than storage proof consumes + let mut test_ext = setup_test_externalities(&[1000, 1300]); + + test_ext.execute_with(|| { + let mut remaining_weight_meter = WeightMeter::with_limit(Weight::from_parts(0, 1000)); + let mut reclaim_helper = StorageWeightReclaimer::new(&remaining_weight_meter); + remaining_weight_meter.consume(Weight::from_parts(0, 0)); + let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); + + assert_eq!(reclaimed, Some(Weight::from_parts(0, 0))); + }); + } + + /// Just here for doc purposes + fn get_benched_weight() -> Weight { + Weight::from_parts(0, 5) + } + + /// Just here for doc purposes + fn do_work() {} + + #[docify::export_content(simple_reclaimer_example)] + fn reclaim_with_weight_meter() { + let mut remaining_weight_meter = WeightMeter::with_limit(Weight::from_parts(10, 10)); + + let benched_weight = get_benched_weight(); + + // It is important to instantiate the `StorageWeightReclaimer` before we consume the weight + // for a piece of work from the weight meter. + let mut reclaim_helper = StorageWeightReclaimer::new(&remaining_weight_meter); + + if remaining_weight_meter.try_consume(benched_weight).is_ok() { + // Perform some work that takes has `benched_weight` storage weight. + do_work(); + + // Reclaimer will detect that we only consumed 2 bytes, so 3 bytes are reclaimed. + let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); + + // We reclaimed 3 bytes of storage size! + assert_eq!(reclaimed, Some(Weight::from_parts(0, 3))); + assert_eq!(BlockWeight::::get().total().proof_size(), 10); + assert_eq!(remaining_weight_meter.remaining(), Weight::from_parts(10, 8)); + } + } + + #[test] + fn test_reclaim_helper_works_with_meter() { + // The node will report 12 - 10 = 2 consumed storage size between the calls. + let mut test_ext = setup_test_externalities(&[10, 12]); + + test_ext.execute_with(|| { + // Initial storage size is 10. + set_current_storage_weight(10); + reclaim_with_weight_meter(); + }); + } } diff --git a/cumulus/primitives/storage-weight-reclaim/src/tests.rs b/cumulus/primitives/storage-weight-reclaim/src/tests.rs deleted file mode 100644 index 631827cf442..00000000000 --- a/cumulus/primitives/storage-weight-reclaim/src/tests.rs +++ /dev/null @@ -1,484 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use super::*; -use frame_support::{ - assert_ok, - dispatch::DispatchClass, - weights::{Weight, WeightMeter}, -}; -use frame_system::{BlockWeight, CheckWeight}; -use sp_runtime::{traits::DispatchTransaction, AccountId32, BuildStorage}; -use sp_std::marker::PhantomData; -use sp_trie::proof_size_extension::ProofSizeExt; - -type Test = cumulus_test_runtime::Runtime; -const CALL: &::RuntimeCall = - &cumulus_test_runtime::RuntimeCall::System(frame_system::Call::set_heap_pages { pages: 0u64 }); -const ALICE: AccountId32 = AccountId32::new([1u8; 32]); -const LEN: usize = 0; - -fn new_test_ext() -> sp_io::TestExternalities { - let ext: sp_io::TestExternalities = cumulus_test_runtime::RuntimeGenesisConfig::default() - .build_storage() - .unwrap() - .into(); - ext -} - -struct TestRecorder { - return_values: Box<[usize]>, - counter: std::sync::atomic::AtomicUsize, -} - -impl TestRecorder { - fn new(values: &[usize]) -> Self { - TestRecorder { return_values: values.into(), counter: Default::default() } - } -} - -impl sp_trie::ProofSizeProvider for TestRecorder { - fn estimate_encoded_size(&self) -> usize { - let counter = self.counter.fetch_add(1, core::sync::atomic::Ordering::Relaxed); - self.return_values[counter] - } -} - -fn setup_test_externalities(proof_values: &[usize]) -> sp_io::TestExternalities { - let mut test_ext = new_test_ext(); - let test_recorder = TestRecorder::new(proof_values); - test_ext.register_extension(ProofSizeExt::new(test_recorder)); - test_ext -} - -fn set_current_storage_weight(new_weight: u64) { - BlockWeight::::mutate(|current_weight| { - current_weight.set(Weight::from_parts(0, new_weight), DispatchClass::Normal); - }); -} - -#[test] -fn basic_refund() { - // The real cost will be 100 bytes of storage size - let mut test_ext = setup_test_externalities(&[0, 100]); - - test_ext.execute_with(|| { - set_current_storage_weight(1000); - - // Benchmarked storage weight: 500 - let info = DispatchInfo { weight: Weight::from_parts(0, 500), ..Default::default() }; - let post_info = PostDispatchInfo::default(); - - let (pre, _) = StorageWeightReclaim::(PhantomData) - .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, Some(0)); - - assert_ok!(CheckWeight::::post_dispatch((), &info, &post_info, 0, &Ok(()), &())); - // We expect a refund of 400 - assert_ok!(StorageWeightReclaim::::post_dispatch( - pre, - &info, - &post_info, - LEN, - &Ok(()), - &() - )); - - assert_eq!(BlockWeight::::get().total().proof_size(), 600); - }) -} - -#[test] -fn does_nothing_without_extension() { - let mut test_ext = new_test_ext(); - - // Proof size extension not registered - test_ext.execute_with(|| { - set_current_storage_weight(1000); - - // Benchmarked storage weight: 500 - let info = DispatchInfo { weight: Weight::from_parts(0, 500), ..Default::default() }; - let post_info = PostDispatchInfo::default(); - - let (pre, _) = StorageWeightReclaim::(PhantomData) - .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, None); - - assert_ok!(CheckWeight::::post_dispatch((), &info, &post_info, 0, &Ok(()), &())); - assert_ok!(StorageWeightReclaim::::post_dispatch( - pre, - &info, - &post_info, - LEN, - &Ok(()), - &() - )); - - assert_eq!(BlockWeight::::get().total().proof_size(), 1000); - }) -} - -#[test] -fn negative_refund_is_added_to_weight() { - let mut test_ext = setup_test_externalities(&[100, 300]); - - test_ext.execute_with(|| { - set_current_storage_weight(1000); - // Benchmarked storage weight: 100 - let info = DispatchInfo { weight: Weight::from_parts(0, 100), ..Default::default() }; - let post_info = PostDispatchInfo::default(); - - let (pre, _) = StorageWeightReclaim::(PhantomData) - .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, Some(100)); - - // We expect no refund - assert_ok!(CheckWeight::::post_dispatch((), &info, &post_info, 0, &Ok(()), &())); - assert_ok!(StorageWeightReclaim::::post_dispatch( - pre, - &info, - &post_info, - LEN, - &Ok(()), - &() - )); - - assert_eq!(BlockWeight::::get().total().proof_size(), 1100); - }) -} - -#[test] -fn test_zero_proof_size() { - let mut test_ext = setup_test_externalities(&[0, 0]); - - test_ext.execute_with(|| { - let info = DispatchInfo { weight: Weight::from_parts(0, 500), ..Default::default() }; - let post_info = PostDispatchInfo::default(); - - let (pre, _) = StorageWeightReclaim::(PhantomData) - .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, Some(0)); - - assert_ok!(CheckWeight::::post_dispatch((), &info, &post_info, 0, &Ok(()), &())); - assert_ok!(StorageWeightReclaim::::post_dispatch( - pre, - &info, - &post_info, - LEN, - &Ok(()), - &() - )); - - assert_eq!(BlockWeight::::get().total().proof_size(), 0); - }); -} - -#[test] -fn test_larger_pre_dispatch_proof_size() { - let mut test_ext = setup_test_externalities(&[300, 100]); - - test_ext.execute_with(|| { - set_current_storage_weight(1300); - - let info = DispatchInfo { weight: Weight::from_parts(0, 500), ..Default::default() }; - let post_info = PostDispatchInfo::default(); - - let (pre, _) = StorageWeightReclaim::(PhantomData) - .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, Some(300)); - - assert_ok!(CheckWeight::::post_dispatch((), &info, &post_info, 0, &Ok(()), &())); - assert_ok!(StorageWeightReclaim::::post_dispatch( - pre, - &info, - &post_info, - LEN, - &Ok(()), - &() - )); - - assert_eq!(BlockWeight::::get().total().proof_size(), 800); - }); -} - -#[test] -fn test_incorporates_check_weight_unspent_weight() { - let mut test_ext = setup_test_externalities(&[100, 300]); - - test_ext.execute_with(|| { - set_current_storage_weight(1000); - - // Benchmarked storage weight: 300 - let info = DispatchInfo { weight: Weight::from_parts(100, 300), ..Default::default() }; - - // Actual weight is 50 - let post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_parts(50, 250)), - pays_fee: Default::default(), - }; - - let (pre, _) = StorageWeightReclaim::(PhantomData) - .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, Some(100)); - - // The `CheckWeight` extension will refunt `actual_weight` from `PostDispatchInfo` - // we always need to call `post_dispatch` to verify that they interoperate correctly. - assert_ok!(CheckWeight::::post_dispatch((), &info, &post_info, 0, &Ok(()), &())); - assert_ok!(StorageWeightReclaim::::post_dispatch( - pre, - &info, - &post_info, - LEN, - &Ok(()), - &() - )); - - assert_eq!(BlockWeight::::get().total().proof_size(), 900); - }) -} - -#[test] -fn test_incorporates_check_weight_unspent_weight_on_negative() { - let mut test_ext = setup_test_externalities(&[100, 300]); - - test_ext.execute_with(|| { - set_current_storage_weight(1000); - // Benchmarked storage weight: 50 - let info = DispatchInfo { weight: Weight::from_parts(100, 50), ..Default::default() }; - - // Actual weight is 25 - let post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_parts(50, 25)), - pays_fee: Default::default(), - }; - - let (pre, _) = StorageWeightReclaim::(PhantomData) - .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, Some(100)); - - // The `CheckWeight` extension will refunt `actual_weight` from `PostDispatchInfo` - // we always need to call `post_dispatch` to verify that they interoperate correctly. - assert_ok!(CheckWeight::::post_dispatch((), &info, &post_info, 0, &Ok(()), &())); - assert_ok!(StorageWeightReclaim::::post_dispatch( - pre, - &info, - &post_info, - LEN, - &Ok(()), - &() - )); - - assert_eq!(BlockWeight::::get().total().proof_size(), 1150); - }) -} - -#[test] -fn test_incorporates_check_weight_unspent_weight_reverse_order() { - let mut test_ext = setup_test_externalities(&[100, 300]); - - test_ext.execute_with(|| { - set_current_storage_weight(1000); - - // Benchmarked storage weight: 300 - let info = DispatchInfo { weight: Weight::from_parts(100, 300), ..Default::default() }; - - // Actual weight is 50 - let post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_parts(50, 250)), - pays_fee: Default::default(), - }; - - let (pre, _) = StorageWeightReclaim::(PhantomData) - .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, Some(100)); - - assert_ok!(StorageWeightReclaim::::post_dispatch( - pre, - &info, - &post_info, - LEN, - &Ok(()), - &() - )); - // `CheckWeight` gets called after `StorageWeightReclaim` this time. - // The `CheckWeight` extension will refunt `actual_weight` from `PostDispatchInfo` - // we always need to call `post_dispatch` to verify that they interoperate correctly. - assert_ok!(CheckWeight::::post_dispatch((), &info, &post_info, 0, &Ok(()), &())); - - assert_eq!(BlockWeight::::get().total().proof_size(), 900); - }) -} - -#[test] -fn test_incorporates_check_weight_unspent_weight_on_negative_reverse_order() { - let mut test_ext = setup_test_externalities(&[100, 300]); - - test_ext.execute_with(|| { - set_current_storage_weight(1000); - // Benchmarked storage weight: 50 - let info = DispatchInfo { weight: Weight::from_parts(100, 50), ..Default::default() }; - - // Actual weight is 25 - let post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_parts(50, 25)), - pays_fee: Default::default(), - }; - - let (pre, _) = StorageWeightReclaim::(PhantomData) - .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, Some(100)); - - assert_ok!(StorageWeightReclaim::::post_dispatch( - pre, - &info, - &post_info, - LEN, - &Ok(()), - &() - )); - // `CheckWeight` gets called after `StorageWeightReclaim` this time. - // The `CheckWeight` extension will refunt `actual_weight` from `PostDispatchInfo` - // we always need to call `post_dispatch` to verify that they interoperate correctly. - assert_ok!(CheckWeight::::post_dispatch((), &info, &post_info, 0, &Ok(()), &())); - - assert_eq!(BlockWeight::::get().total().proof_size(), 1150); - }) -} - -#[test] -fn storage_size_reported_correctly() { - let mut test_ext = setup_test_externalities(&[1000]); - test_ext.execute_with(|| { - assert_eq!(get_proof_size(), Some(1000)); - }); - - let mut test_ext = new_test_ext(); - - let test_recorder = TestRecorder::new(&[0]); - - test_ext.register_extension(ProofSizeExt::new(test_recorder)); - - test_ext.execute_with(|| { - assert_eq!(get_proof_size(), Some(0)); - }); -} - -#[test] -fn storage_size_disabled_reported_correctly() { - let mut test_ext = setup_test_externalities(&[PROOF_RECORDING_DISABLED as usize]); - - test_ext.execute_with(|| { - assert_eq!(get_proof_size(), None); - }); -} - -#[test] -fn test_reclaim_helper() { - let mut test_ext = setup_test_externalities(&[1000, 1300, 1800]); - - test_ext.execute_with(|| { - let mut remaining_weight_meter = WeightMeter::with_limit(Weight::from_parts(0, 2000)); - let mut reclaim_helper = StorageWeightReclaimer::new(&remaining_weight_meter); - remaining_weight_meter.consume(Weight::from_parts(0, 500)); - let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); - - assert_eq!(reclaimed, Some(Weight::from_parts(0, 200))); - - remaining_weight_meter.consume(Weight::from_parts(0, 800)); - let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); - assert_eq!(reclaimed, Some(Weight::from_parts(0, 300))); - assert_eq!(remaining_weight_meter.remaining(), Weight::from_parts(0, 1200)); - }); -} - -#[test] -fn test_reclaim_helper_does_not_reclaim_negative() { - // Benchmarked weight does not change at all - let mut test_ext = setup_test_externalities(&[1000, 1300]); - - test_ext.execute_with(|| { - let mut remaining_weight_meter = WeightMeter::with_limit(Weight::from_parts(0, 1000)); - let mut reclaim_helper = StorageWeightReclaimer::new(&remaining_weight_meter); - let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); - - assert_eq!(reclaimed, Some(Weight::from_parts(0, 0))); - assert_eq!(remaining_weight_meter.remaining(), Weight::from_parts(0, 1000)); - }); - - // Benchmarked weight increases less than storage proof consumes - let mut test_ext = setup_test_externalities(&[1000, 1300]); - - test_ext.execute_with(|| { - let mut remaining_weight_meter = WeightMeter::with_limit(Weight::from_parts(0, 1000)); - let mut reclaim_helper = StorageWeightReclaimer::new(&remaining_weight_meter); - remaining_weight_meter.consume(Weight::from_parts(0, 0)); - let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); - - assert_eq!(reclaimed, Some(Weight::from_parts(0, 0))); - }); -} - -/// Just here for doc purposes -fn get_benched_weight() -> Weight { - Weight::from_parts(0, 5) -} - -/// Just here for doc purposes -fn do_work() {} - -#[docify::export_content(simple_reclaimer_example)] -fn reclaim_with_weight_meter() { - let mut remaining_weight_meter = WeightMeter::with_limit(Weight::from_parts(10, 10)); - - let benched_weight = get_benched_weight(); - - // It is important to instantiate the `StorageWeightReclaimer` before we consume the weight - // for a piece of work from the weight meter. - let mut reclaim_helper = StorageWeightReclaimer::new(&remaining_weight_meter); - - if remaining_weight_meter.try_consume(benched_weight).is_ok() { - // Perform some work that takes has `benched_weight` storage weight. - do_work(); - - // Reclaimer will detect that we only consumed 2 bytes, so 3 bytes are reclaimed. - let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); - - // We reclaimed 3 bytes of storage size! - assert_eq!(reclaimed, Some(Weight::from_parts(0, 3))); - assert_eq!(BlockWeight::::get().total().proof_size(), 10); - assert_eq!(remaining_weight_meter.remaining(), Weight::from_parts(10, 8)); - } -} - -#[test] -fn test_reclaim_helper_works_with_meter() { - // The node will report 12 - 10 = 2 consumed storage size between the calls. - let mut test_ext = setup_test_externalities(&[10, 12]); - - test_ext.execute_with(|| { - // Initial storage size is 10. - set_current_storage_weight(10); - reclaim_with_weight_meter(); - }); -} diff --git a/cumulus/test/client/Cargo.toml b/cumulus/test/client/Cargo.toml index 9dfa6ecb351..028733ce235 100644 --- a/cumulus/test/client/Cargo.toml +++ b/cumulus/test/client/Cargo.toml @@ -46,11 +46,9 @@ cumulus-primitives-storage-weight-reclaim = { path = "../../primitives/storage-w [features] runtime-benchmarks = [ "cumulus-primitives-core/runtime-benchmarks", - "cumulus-primitives-storage-weight-reclaim/runtime-benchmarks", "cumulus-test-service/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", "sc-service/runtime-benchmarks", diff --git a/cumulus/test/client/src/lib.rs b/cumulus/test/client/src/lib.rs index 9239ff0f23e..c46f4da7f67 100644 --- a/cumulus/test/client/src/lib.rs +++ b/cumulus/test/client/src/lib.rs @@ -19,7 +19,7 @@ mod block_builder; use codec::{Decode, Encode}; use runtime::{ - Balance, Block, BlockHashCount, Runtime, RuntimeCall, Signature, SignedPayload, TxExtension, + Balance, Block, BlockHashCount, Runtime, RuntimeCall, Signature, SignedExtra, SignedPayload, UncheckedExtrinsic, VERSION, }; use sc_executor::HeapAllocStrategy; @@ -125,7 +125,7 @@ impl DefaultTestClientBuilderExt for TestClientBuilder { /// Create an unsigned extrinsic from a runtime call. pub fn generate_unsigned(function: impl Into) -> UncheckedExtrinsic { - UncheckedExtrinsic::new_bare(function.into()) + UncheckedExtrinsic::new_unsigned(function.into()) } /// Create a signed extrinsic from a runtime call and sign @@ -143,7 +143,7 @@ pub fn generate_extrinsic_with_pair( let period = BlockHashCount::get().checked_next_power_of_two().map(|c| c / 2).unwrap_or(2) as u64; let tip = 0; - let tx_ext: TxExtension = ( + let extra: SignedExtra = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckGenesis::::new(), @@ -152,14 +152,13 @@ pub fn generate_extrinsic_with_pair( frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(tip), cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::::new(), - ) - .into(); + ); let function = function.into(); let raw_payload = SignedPayload::from_raw( function.clone(), - tx_ext.clone(), + extra.clone(), ((), VERSION.spec_version, genesis_block, current_block_hash, (), (), (), ()), ); let signature = raw_payload.using_encoded(|e| origin.sign(e)); @@ -168,7 +167,7 @@ pub fn generate_extrinsic_with_pair( function, origin.public().into(), Signature::Sr25519(signature), - tx_ext, + extra, ) } diff --git a/cumulus/test/runtime/src/lib.rs b/cumulus/test/runtime/src/lib.rs index 154948a24b4..5ccec8983e9 100644 --- a/cumulus/test/runtime/src/lib.rs +++ b/cumulus/test/runtime/src/lib.rs @@ -246,7 +246,6 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = (); type OperationalFeeMultiplier = ConstU8<5>; - type WeightInfo = pallet_transaction_payment::weights::SubstrateWeight; } impl pallet_sudo::Config for Runtime { @@ -323,8 +322,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The extension to the basic transaction logic. -pub type TxExtension = ( +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckGenesis, @@ -336,7 +335,7 @@ pub type TxExtension = ( ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, @@ -347,7 +346,7 @@ pub type Executive = frame_executive::Executive< TestOnRuntimeUpgrade, >; /// The payload being signed in transactions. -pub type SignedPayload = generic::SignedPayload; +pub type SignedPayload = generic::SignedPayload; pub struct TestOnRuntimeUpgrade; diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index 39e8aeba433..27273f4e0a8 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -104,12 +104,10 @@ substrate-test-utils = { path = "../../../substrate/test-utils" } runtime-benchmarks = [ "cumulus-pallet-parachain-system/runtime-benchmarks", "cumulus-primitives-core/runtime-benchmarks", - "cumulus-primitives-storage-weight-reclaim/runtime-benchmarks", "cumulus-test-client/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-im-online/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "parachains-common/runtime-benchmarks", "polkadot-cli/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", diff --git a/cumulus/test/service/src/bench_utils.rs b/cumulus/test/service/src/bench_utils.rs index 15128b23787..4ace894b392 100644 --- a/cumulus/test/service/src/bench_utils.rs +++ b/cumulus/test/service/src/bench_utils.rs @@ -69,7 +69,7 @@ pub fn extrinsic_set_time(client: &TestClient) -> OpaqueExtrinsic { let timestamp = best_number as u64 * cumulus_test_runtime::MinimumPeriod::get(); cumulus_test_runtime::UncheckedExtrinsic { - preamble: sp_runtime::generic::Preamble::Bare, + signature: None, function: cumulus_test_runtime::RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: timestamp, }), @@ -102,7 +102,7 @@ pub fn extrinsic_set_validation_data( }; cumulus_test_runtime::UncheckedExtrinsic { - preamble: sp_runtime::generic::Preamble::Bare, + signature: None, function: cumulus_test_runtime::RuntimeCall::ParachainSystem( cumulus_pallet_parachain_system::Call::set_validation_data { data }, ), diff --git a/cumulus/test/service/src/lib.rs b/cumulus/test/service/src/lib.rs index f05dc5f180f..3554a383f21 100644 --- a/cumulus/test/service/src/lib.rs +++ b/cumulus/test/service/src/lib.rs @@ -883,7 +883,7 @@ pub fn construct_extrinsic( .map(|c| c / 2) .unwrap_or(2) as u64; let tip = 0; - let tx_ext: runtime::TxExtension = ( + let extra: runtime::SignedExtra = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckGenesis::::new(), @@ -895,11 +895,10 @@ pub fn construct_extrinsic( frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(tip), cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::::new(), - ) - .into(); + ); let raw_payload = runtime::SignedPayload::from_raw( function.clone(), - tx_ext.clone(), + extra.clone(), ((), runtime::VERSION.spec_version, genesis_block, current_block_hash, (), (), (), ()), ); let signature = raw_payload.using_encoded(|e| caller.sign(e)); @@ -907,7 +906,7 @@ pub fn construct_extrinsic( function, caller.public().into(), runtime::Signature::Sr25519(signature), - tx_ext, + extra, ) } diff --git a/docs/sdk/src/reference_docs/extrinsic_encoding.rs b/docs/sdk/src/reference_docs/extrinsic_encoding.rs index be1af500038..8c8568a228f 100644 --- a/docs/sdk/src/reference_docs/extrinsic_encoding.rs +++ b/docs/sdk/src/reference_docs/extrinsic_encoding.rs @@ -56,7 +56,7 @@ //! version_and_signed, //! from_address, //! signature, -//! transaction_extensions_extra, +//! signed_extensions_extra, //! ) //! ``` //! @@ -90,31 +90,31 @@ //! The signature type used on the Polkadot relay chain is [`sp_runtime::MultiSignature`]; the //! variants there are the types of signature that can be provided. //! -//! ### transaction_extensions_extra +//! ### signed_extensions_extra //! //! This is the concatenation of the [SCALE encoded][frame::deps::codec] bytes representing each of -//! the [_transaction extensions_][sp_runtime::traits::TransactionExtension], and are configured by -//! the fourth generic parameter of [`sp_runtime::generic::UncheckedExtrinsic`]. Learn more about -//! transaction extensions [here][crate::reference_docs::transaction_extensions]. +//! the [_signed extensions_][sp_runtime::traits::SignedExtension], and are configured by the +//! fourth generic parameter of [`sp_runtime::generic::UncheckedExtrinsic`]. Learn more about +//! signed extensions [here][crate::reference_docs::signed_extensions]. //! -//! When it comes to constructing an extrinsic, each transaction extension has two things that we -//! are interested in here: +//! When it comes to constructing an extrinsic, each signed extension has two things that we are +//! interested in here: //! -//! - The actual SCALE encoding of the transaction extension type itself; this is what will form our -//! `transaction_extensions_extra` bytes. -//! - An `Implicit` type. This is SCALE encoded into the `transaction_extensions_implicit` data of -//! the _signed payload_ (see below). +//! - The actual SCALE encoding of the signed extension type itself; this is what will form our +//! `signed_extensions_extra` bytes. +//! - An `AdditionalSigned` type. This is SCALE encoded into the `signed_extensions_additional` data +//! of the _signed payload_ (see below). //! //! Either (or both) of these can encode to zero bytes. //! -//! Each chain configures the set of transaction extensions that it uses in its runtime -//! configuration. At the time of writing, Polkadot configures them +//! Each chain configures the set of signed extensions that it uses in its runtime configuration. +//! At the time of writing, Polkadot configures them //! [here](https://github.com/polkadot-fellows/runtimes/blob/1dc04eb954eadf8aadb5d83990b89662dbb5a074/relay/polkadot/src/lib.rs#L1432C25-L1432C25). -//! Some of the common transaction extensions are defined -//! [here][frame::deps::frame_system#transaction-extensions]. +//! Some of the common signed extensions are defined +//! [here][frame::deps::frame_system#signed-extensions]. //! -//! Information about exactly which transaction extensions are present on a chain and in what order -//! is also a part of the metadata for the chain. For V15 metadata, it can be +//! Information about exactly which signed extensions are present on a chain and in what order is +//! also a part of the metadata for the chain. For V15 metadata, it can be //! [found here][frame::deps::frame_support::__private::metadata::v15::ExtrinsicMetadata]. //! //! ## call_data @@ -163,8 +163,8 @@ //! ```text //! signed_payload = concat( //! call_data, -//! transaction_extensions_extra, -//! transaction_extensions_implicit, +//! signed_extensions_extra, +//! signed_extensions_additional, //! ) //! //! if length(signed_payload) > 256 { @@ -172,16 +172,16 @@ //! } //! ``` //! -//! The bytes representing `call_data` and `transaction_extensions_extra` can be obtained as -//! descibed above. `transaction_extensions_implicit` is constructed by SCALE encoding the -//! ["implicit" data][sp_runtime::traits::TransactionExtensionBase::Implicit] for each -//! transaction extension that the chain is using, in order. +//! The bytes representing `call_data` and `signed_extensions_extra` can be obtained as described +//! above. `signed_extensions_additional` is constructed by SCALE encoding the +//! ["additional signed" data][sp_runtime::traits::SignedExtension::AdditionalSigned] for each +//! signed extension that the chain is using, in order. //! //! Once we've concatenated those together, we hash the result if it's greater than 256 bytes in //! length using a Blake2 256bit hasher. //! //! The [`sp_runtime::generic::SignedPayload`] type takes care of assembling the correct payload -//! for us, given `call_data` and a tuple of transaction extensions. +//! for us, given `call_data` and a tuple of signed extensions. //! //! # Example Encoding //! @@ -192,12 +192,11 @@ #[docify::export] pub mod call_data { use parity_scale_codec::{Decode, Encode}; - use sp_runtime::{traits::Dispatchable, DispatchResultWithInfo}; // The outer enum composes calls within // different pallets together. We have two // pallets, "PalletA" and "PalletB". - #[derive(Encode, Decode, Clone)] + #[derive(Encode, Decode)] pub enum Call { #[codec(index = 0)] PalletA(PalletACall), @@ -208,33 +207,23 @@ pub mod call_data { // An inner enum represents the calls within // a specific pallet. "PalletA" has one call, // "Foo". - #[derive(Encode, Decode, Clone)] + #[derive(Encode, Decode)] pub enum PalletACall { #[codec(index = 0)] Foo(String), } - #[derive(Encode, Decode, Clone)] + #[derive(Encode, Decode)] pub enum PalletBCall { #[codec(index = 0)] Bar(String), } - - impl Dispatchable for Call { - type RuntimeOrigin = (); - type Config = (); - type Info = (); - type PostInfo = (); - fn dispatch(self, _origin: Self::RuntimeOrigin) -> DispatchResultWithInfo { - Ok(()) - } - } } #[docify::export] pub mod encoding_example { use super::call_data::{Call, PalletACall}; - use crate::reference_docs::transaction_extensions::transaction_extensions_example; + use crate::reference_docs::signed_extensions::signed_extensions_example; use parity_scale_codec::Encode; use sp_core::crypto::AccountId32; use sp_keyring::sr25519::Keyring; @@ -243,40 +232,34 @@ pub mod encoding_example { MultiAddress, MultiSignature, }; - // Define some transaction extensions to use. We'll use a couple of examples - // from the transaction extensions reference doc. - type TransactionExtensions = ( - transaction_extensions_example::AddToPayload, - transaction_extensions_example::AddToSignaturePayload, - ); + // Define some signed extensions to use. We'll use a couple of examples + // from the signed extensions reference doc. + type SignedExtensions = + (signed_extensions_example::AddToPayload, signed_extensions_example::AddToSignaturePayload); // We'll use `UncheckedExtrinsic` to encode our extrinsic for us. We set // the address and signature type to those used on Polkadot, use our custom - // `Call` type, and use our custom set of `TransactionExtensions`. - type Extrinsic = UncheckedExtrinsic< - MultiAddress, - Call, - MultiSignature, - TransactionExtensions, - >; + // `Call` type, and use our custom set of `SignedExtensions`. + type Extrinsic = + UncheckedExtrinsic, Call, MultiSignature, SignedExtensions>; pub fn encode_demo_extrinsic() -> Vec { // The "from" address will be our Alice dev account. let from_address = MultiAddress::::Id(Keyring::Alice.to_account_id()); - // We provide some values for our expected transaction extensions. - let transaction_extensions = ( - transaction_extensions_example::AddToPayload(1), - transaction_extensions_example::AddToSignaturePayload, + // We provide some values for our expected signed extensions. + let signed_extensions = ( + signed_extensions_example::AddToPayload(1), + signed_extensions_example::AddToSignaturePayload, ); // Construct our call data: let call_data = Call::PalletA(PalletACall::Foo("Hello".to_string())); // The signed payload. This takes care of encoding the call_data, - // transaction_extensions_extra and transaction_extensions_implicit, and hashing + // signed_extensions_extra and signed_extensions_additional, and hashing // the result if it's > 256 bytes: - let signed_payload = SignedPayload::new(call_data.clone(), transaction_extensions.clone()); + let signed_payload = SignedPayload::new(&call_data, signed_extensions.clone()); // Sign the signed payload with our Alice dev account's private key, // and wrap the signature into the expected type: @@ -286,7 +269,7 @@ pub mod encoding_example { }; // Now, we can build and encode our extrinsic: - let ext = Extrinsic::new_signed(call_data, from_address, signature, transaction_extensions); + let ext = Extrinsic::new_signed(call_data, from_address, signature, signed_extensions); let encoded_ext = ext.encode(); encoded_ext diff --git a/docs/sdk/src/reference_docs/frame_runtime_types.rs b/docs/sdk/src/reference_docs/frame_runtime_types.rs index 883892729d1..b5838b79e51 100644 --- a/docs/sdk/src/reference_docs/frame_runtime_types.rs +++ b/docs/sdk/src/reference_docs/frame_runtime_types.rs @@ -130,7 +130,7 @@ //! * [`crate::reference_docs::frame_origin`] explores further details about the usage of //! `RuntimeOrigin`. //! * [`RuntimeCall`] is a particularly interesting composite enum as it dictates the encoding of an -//! extrinsic. See [`crate::reference_docs::transaction_extensions`] for more information. +//! extrinsic. See [`crate::reference_docs::signed_extensions`] for more information. //! * See the documentation of [`construct_runtime`]. //! * See the corresponding lecture in the [pba-book](https://polkadot-blockchain-academy.github.io/pba-book/frame/outer-enum/page.html). //! diff --git a/docs/sdk/src/reference_docs/mod.rs b/docs/sdk/src/reference_docs/mod.rs index f4b52208e2f..de0b012bb12 100644 --- a/docs/sdk/src/reference_docs/mod.rs +++ b/docs/sdk/src/reference_docs/mod.rs @@ -39,9 +39,9 @@ pub mod runtime_vs_smart_contract; /// Learn about how extrinsics are encoded to be transmitted to a node and stored in blocks. pub mod extrinsic_encoding; -/// Learn about the transaction extensions that form a part of extrinsics. +/// Learn about the signed extensions that form a part of extrinsics. // TODO: @jsdw https://github.com/paritytech/polkadot-sdk-docs/issues/42 -pub mod transaction_extensions; +pub mod signed_extensions; /// Learn about *Origins*, a topic in FRAME that enables complex account abstractions to be built. pub mod frame_origin; diff --git a/docs/sdk/src/reference_docs/signed_extensions.rs b/docs/sdk/src/reference_docs/signed_extensions.rs new file mode 100644 index 00000000000..28b1426536b --- /dev/null +++ b/docs/sdk/src/reference_docs/signed_extensions.rs @@ -0,0 +1,79 @@ +//! Signed extensions are, briefly, a means for different chains to extend the "basic" extrinsic +//! format with custom data that can be checked by the runtime. +//! +//! # Example +//! +//! Defining a couple of very simple signed extensions looks like the following: +#![doc = docify::embed!("./src/reference_docs/signed_extensions.rs", signed_extensions_example)] + +#[docify::export] +pub mod signed_extensions_example { + use parity_scale_codec::{Decode, Encode}; + use scale_info::TypeInfo; + use sp_runtime::traits::SignedExtension; + + // This doesn't actually check anything, but simply allows + // some arbitrary `u32` to be added to the extrinsic payload + #[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] + pub struct AddToPayload(pub u32); + + impl SignedExtension for AddToPayload { + const IDENTIFIER: &'static str = "AddToPayload"; + type AccountId = (); + type Call = (); + type AdditionalSigned = (); + type Pre = (); + + fn additional_signed( + &self, + ) -> Result< + Self::AdditionalSigned, + sp_runtime::transaction_validity::TransactionValidityError, + > { + Ok(()) + } + + fn pre_dispatch( + self, + _who: &Self::AccountId, + _call: &Self::Call, + _info: &sp_runtime::traits::DispatchInfoOf, + _len: usize, + ) -> Result { + Ok(()) + } + } + + // This is the opposite; nothing will be added to the extrinsic payload, + // but the AdditionalSigned type (`1234u32`) will be added to the + // payload to be signed. + #[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] + pub struct AddToSignaturePayload; + + impl SignedExtension for AddToSignaturePayload { + const IDENTIFIER: &'static str = "AddToSignaturePayload"; + type AccountId = (); + type Call = (); + type AdditionalSigned = u32; + type Pre = (); + + fn additional_signed( + &self, + ) -> Result< + Self::AdditionalSigned, + sp_runtime::transaction_validity::TransactionValidityError, + > { + Ok(1234) + } + + fn pre_dispatch( + self, + _who: &Self::AccountId, + _call: &Self::Call, + _info: &sp_runtime::traits::DispatchInfoOf, + _len: usize, + ) -> Result { + Ok(()) + } + } +} diff --git a/docs/sdk/src/reference_docs/transaction_extensions.rs b/docs/sdk/src/reference_docs/transaction_extensions.rs deleted file mode 100644 index 4f96d665d9b..00000000000 --- a/docs/sdk/src/reference_docs/transaction_extensions.rs +++ /dev/null @@ -1,57 +0,0 @@ -//! Transaction extensions are, briefly, a means for different chains to extend the "basic" -//! extrinsic format with custom data that can be checked by the runtime. -//! -//! # Example -//! -//! Defining a couple of very simple transaction extensions looks like the following: -#![doc = docify::embed!("./src/reference_docs/transaction_extensions.rs", transaction_extensions_example)] - -#[docify::export] -pub mod transaction_extensions_example { - use parity_scale_codec::{Decode, Encode}; - use scale_info::TypeInfo; - use sp_runtime::{ - impl_tx_ext_default, - traits::{Dispatchable, TransactionExtension, TransactionExtensionBase}, - TransactionValidityError, - }; - - // This doesn't actually check anything, but simply allows - // some arbitrary `u32` to be added to the extrinsic payload - #[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] - pub struct AddToPayload(pub u32); - - impl TransactionExtensionBase for AddToPayload { - const IDENTIFIER: &'static str = "AddToPayload"; - type Implicit = (); - } - - impl TransactionExtension for AddToPayload { - type Pre = (); - type Val = (); - - impl_tx_ext_default!(Call; (); validate prepare); - } - - // This is the opposite; nothing will be added to the extrinsic payload, - // but the Implicit type (`1234u32`) will be added to the - // payload to be signed. - #[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] - pub struct AddToSignaturePayload; - - impl TransactionExtensionBase for AddToSignaturePayload { - const IDENTIFIER: &'static str = "AddToSignaturePayload"; - type Implicit = u32; - - fn implicit(&self) -> Result { - Ok(1234) - } - } - - impl TransactionExtension for AddToSignaturePayload { - type Pre = (); - type Val = (); - - impl_tx_ext_default!(Call; (); validate prepare); - } -} diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 180de70ad6c..734dcbdeb44 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -196,7 +196,6 @@ runtime-benchmarks = [ "pallet-babe/runtime-benchmarks", "pallet-im-online/runtime-benchmarks", "pallet-staking/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", diff --git a/polkadot/node/service/src/benchmarking.rs b/polkadot/node/service/src/benchmarking.rs index 29acc5c3ca8..400daf1aee3 100644 --- a/polkadot/node/service/src/benchmarking.rs +++ b/polkadot/node/service/src/benchmarking.rs @@ -189,7 +189,7 @@ fn westend_sign_call( use sp_core::Pair; use westend_runtime as runtime; - let tx_ext: runtime::TxExtension = ( + let extra: runtime::SignedExtra = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -201,12 +201,11 @@ fn westend_sign_call( frame_system::CheckNonce::::from(nonce), frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(0), - ) - .into(); + ); let payload = runtime::SignedPayload::from_raw( call.clone(), - tx_ext.clone(), + extra.clone(), ( (), runtime::VERSION.spec_version, @@ -224,7 +223,7 @@ fn westend_sign_call( call, sp_runtime::AccountId32::from(acc.public()).into(), polkadot_core_primitives::Signature::Sr25519(signature.clone()), - tx_ext, + extra, ) .into() } @@ -242,7 +241,7 @@ fn rococo_sign_call( use rococo_runtime as runtime; use sp_core::Pair; - let tx_ext: runtime::TxExtension = ( + let extra: runtime::SignedExtra = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -254,12 +253,11 @@ fn rococo_sign_call( frame_system::CheckNonce::::from(nonce), frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(0), - ) - .into(); + ); let payload = runtime::SignedPayload::from_raw( call.clone(), - tx_ext.clone(), + extra.clone(), ( (), runtime::VERSION.spec_version, @@ -277,7 +275,7 @@ fn rococo_sign_call( call, sp_runtime::AccountId32::from(acc.public()).into(), polkadot_core_primitives::Signature::Sr25519(signature.clone()), - tx_ext, + extra, ) .into() } diff --git a/polkadot/node/test/service/Cargo.toml b/polkadot/node/test/service/Cargo.toml index 02b227e6f34..e7892abcd87 100644 --- a/polkadot/node/test/service/Cargo.toml +++ b/polkadot/node/test/service/Cargo.toml @@ -71,7 +71,6 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-staking/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", diff --git a/polkadot/node/test/service/src/lib.rs b/polkadot/node/test/service/src/lib.rs index 1876595c7b4..ca904bae28d 100644 --- a/polkadot/node/test/service/src/lib.rs +++ b/polkadot/node/test/service/src/lib.rs @@ -32,7 +32,7 @@ use polkadot_service::{ Error, FullClient, IsParachainNode, NewFull, OverseerGen, PrometheusConfig, }; use polkadot_test_runtime::{ - ParasCall, ParasSudoWrapperCall, Runtime, SignedPayload, SudoCall, TxExtension, + ParasCall, ParasSudoWrapperCall, Runtime, SignedExtra, SignedPayload, SudoCall, UncheckedExtrinsic, VERSION, }; @@ -382,7 +382,7 @@ pub fn construct_extrinsic( let period = BlockHashCount::get().checked_next_power_of_two().map(|c| c / 2).unwrap_or(2) as u64; let tip = 0; - let tx_ext: TxExtension = ( + let extra: SignedExtra = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -391,11 +391,10 @@ pub fn construct_extrinsic( frame_system::CheckNonce::::from(nonce), frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(tip), - ) - .into(); + ); let raw_payload = SignedPayload::from_raw( function.clone(), - tx_ext.clone(), + extra.clone(), ( (), VERSION.spec_version, @@ -412,7 +411,7 @@ pub fn construct_extrinsic( function.clone(), polkadot_test_runtime::Address::Id(caller.public().into()), polkadot_primitives::Signature::Sr25519(signature.clone()), - tx_ext.clone(), + extra.clone(), ) } diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index c2205938295..eae5d4fb2ef 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -132,7 +132,6 @@ runtime-benchmarks = [ "pallet-identity/runtime-benchmarks", "pallet-staking/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "pallet-treasury/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", "primitives/runtime-benchmarks", diff --git a/polkadot/runtime/common/src/claims.rs b/polkadot/runtime/common/src/claims.rs index 57a95b22af3..68f42914e44 100644 --- a/polkadot/runtime/common/src/claims.rs +++ b/polkadot/runtime/common/src/claims.rs @@ -29,11 +29,7 @@ use scale_info::TypeInfo; use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; use sp_io::{crypto::secp256k1_ecdsa_recover, hashing::keccak_256}; use sp_runtime::{ - impl_tx_ext_default, - traits::{ - AsSystemOriginSigner, CheckedSub, DispatchInfoOf, Dispatchable, TransactionExtension, - TransactionExtensionBase, Zero, - }, + traits::{CheckedSub, DispatchInfoOf, SignedExtension, Zero}, transaction_validity::{ InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction, }, @@ -54,7 +50,6 @@ pub trait WeightInfo { fn claim_attest() -> Weight; fn attest() -> Weight; fn move_claim() -> Weight; - fn prevalidate_attests() -> Weight; } pub struct TestWeightInfo; @@ -74,9 +69,6 @@ impl WeightInfo for TestWeightInfo { fn move_claim() -> Weight { Weight::zero() } - fn prevalidate_attests() -> Weight { - Weight::zero() - } } /// The kind of statement an account needs to make for a claim to be valid. @@ -92,7 +84,7 @@ pub enum StatementKind { impl StatementKind { /// Convert this to the (English) statement it represents. - pub fn to_text(self) -> &'static [u8] { + fn to_text(self) -> &'static [u8] { match self { StatementKind::Regular => &b"I hereby agree to the terms of the statement whose SHA-256 multihash is \ @@ -174,13 +166,6 @@ pub mod pallet { #[pallet::without_storage_info] pub struct Pallet(_); - #[cfg(feature = "runtime-benchmarks")] - /// Helper trait to benchmark the `PrevalidateAttests` transaction extension. - pub trait BenchmarkHelperTrait { - /// `Call` to be used when benchmarking the transaction extension. - fn default_call_and_info() -> (RuntimeCall, DispatchInfo); - } - /// Configuration trait. #[pallet::config] pub trait Config: frame_system::Config { @@ -191,12 +176,6 @@ pub mod pallet { type Prefix: Get<&'static [u8]>; type MoveClaimOrigin: EnsureOrigin; type WeightInfo: WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - /// Benchmark helper - type BenchmarkHelper: BenchmarkHelperTrait< - Self::RuntimeCall, - DispatchInfoOf, - >; } #[pallet::event] @@ -423,7 +402,7 @@ pub mod pallet { /// Attest to a statement, needed to finalize the claims process. /// /// WARNING: Insecure unless your chain includes `PrevalidateAttests` as a - /// `TransactionExtension`. + /// `SignedExtension`. /// /// Unsigned Validation: /// A call to attest is deemed valid if the sender has a `Preclaim` registered @@ -633,46 +612,46 @@ impl PrevalidateAttests where ::RuntimeCall: IsSubType>, { - /// Create new `TransactionExtension` to check runtime version. + /// Create new `SignedExtension` to check runtime version. pub fn new() -> Self { Self(sp_std::marker::PhantomData) } } -impl TransactionExtensionBase for PrevalidateAttests +impl SignedExtension for PrevalidateAttests where ::RuntimeCall: IsSubType>, { + type AccountId = T::AccountId; + type Call = ::RuntimeCall; + type AdditionalSigned = (); + type Pre = (); const IDENTIFIER: &'static str = "PrevalidateAttests"; - type Implicit = (); -} -impl TransactionExtension for PrevalidateAttests -where - ::RuntimeCall: IsSubType>, - <::RuntimeCall as Dispatchable>::RuntimeOrigin: - AsSystemOriginSigner + Clone, -{ - type Pre = (); - type Val = (); + fn additional_signed(&self) -> Result { + Ok(()) + } + + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + self.validate(who, call, info, len).map(|_| ()) + } // // The weight of this logic is included in the `attest` dispatchable. // fn validate( &self, - origin: ::RuntimeOrigin, - call: &T::RuntimeCall, - _info: &DispatchInfoOf, + who: &Self::AccountId, + call: &Self::Call, + _info: &DispatchInfoOf, _len: usize, - _context: &mut Context, - _self_implicit: Self::Implicit, - _inherited_implication: &impl Encode, - ) -> Result< - (ValidTransaction, Self::Val, ::RuntimeOrigin), - TransactionValidityError, - > { - let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?; + ) -> TransactionValidity { if let Some(local_call) = call.is_sub_type() { if let Call::attest { statement: attested_statement } = local_call { let signer = Preclaims::::get(who) @@ -683,9 +662,8 @@ where } } } - Ok((ValidTransaction::default(), (), origin)) + Ok(ValidTransaction::default()) } - impl_tx_ext_default!(T::RuntimeCall; Context; prepare); } #[cfg(any(test, feature = "runtime-benchmarks"))] @@ -718,7 +696,7 @@ mod secp_utils { } #[cfg(test)] -pub(super) mod tests { +mod tests { use super::*; use hex_literal::hex; use secp_utils::*; @@ -736,11 +714,8 @@ pub(super) mod tests { }; use pallet_balances; use sp_runtime::{ - traits::{DispatchTransaction, Identity}, - transaction_validity::TransactionLongevity, - BuildStorage, - DispatchError::BadOrigin, - TokenError, + traits::Identity, transaction_validity::TransactionLongevity, BuildStorage, + DispatchError::BadOrigin, TokenError, }; type Block = frame_system::mocking::MockBlock; @@ -815,19 +790,6 @@ pub(super) mod tests { type Prefix = Prefix; type MoveClaimOrigin = frame_system::EnsureSignedBy; type WeightInfo = TestWeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); - } - - #[cfg(feature = "runtime-benchmarks")] - impl BenchmarkHelperTrait> for () { - fn default_call_and_info() -> (RuntimeCall, DispatchInfoOf) { - let call = RuntimeCall::Claims(crate::claims::Call::attest { - statement: StatementKind::Regular.to_text().to_vec(), - }); - let info = call.get_dispatch_info(); - (call, info) - } } fn alice() -> libsecp256k1::SecretKey { @@ -1109,8 +1071,8 @@ pub(super) mod tests { }); let di = c.get_dispatch_info(); assert_eq!(di.pays_fee, Pays::No); - let r = p.validate_only(Some(42).into(), &c, &di, 20); - assert_eq!(r.unwrap().0, ValidTransaction::default()); + let r = p.validate(&42, &c, &di, 20); + assert_eq!(r, TransactionValidity::Ok(ValidTransaction::default())); }); } @@ -1122,13 +1084,13 @@ pub(super) mod tests { statement: StatementKind::Regular.to_text().to_vec(), }); let di = c.get_dispatch_info(); - let r = p.validate_only(Some(42).into(), &c, &di, 20); + let r = p.validate(&42, &c, &di, 20); assert!(r.is_err()); let c = RuntimeCall::Claims(ClaimsCall::attest { statement: StatementKind::Saft.to_text().to_vec(), }); let di = c.get_dispatch_info(); - let r = p.validate_only(Some(69).into(), &c, &di, 20); + let r = p.validate(&69, &c, &di, 20); assert!(r.is_err()); }); } @@ -1482,17 +1444,14 @@ pub(super) mod tests { } #[cfg(feature = "runtime-benchmarks")] -pub(super) mod benchmarking { +mod benchmarking { use super::*; use crate::claims::Call; use frame_benchmarking::{account, benchmarks}; use frame_support::traits::UnfilteredDispatchable; use frame_system::RawOrigin; use secp_utils::*; - use sp_runtime::{ - traits::{DispatchTransaction, ValidateUnsigned}, - DispatchResult, - }; + use sp_runtime::{traits::ValidateUnsigned, DispatchResult}; const SEED: u32 = 0; @@ -1528,11 +1487,6 @@ pub(super) mod benchmarking { } benchmarks! { - where_clause { where ::RuntimeCall: IsSubType>, - <::RuntimeCall as Dispatchable>::RuntimeOrigin: AsSystemOriginSigner + Clone, - <::RuntimeCall as Dispatchable>::PostInfo: Default, - } - // Benchmark `claim` including `validate_unsigned` logic. claim { let c = MAX_CLAIMS; @@ -1711,38 +1665,6 @@ pub(super) mod benchmarking { } } - prevalidate_attests { - let c = MAX_CLAIMS; - - for i in 0 .. c / 2 { - create_claim::(c)?; - create_claim_attest::(u32::MAX - c)?; - } - - let ext = PrevalidateAttests::::new(); - let (call, info) = T::BenchmarkHelper::default_call_and_info(); - let attest_c = u32::MAX - c; - let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&attest_c.encode())).unwrap(); - let eth_address = eth(&secret_key); - let account: T::AccountId = account("user", c, SEED); - let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into())); - let statement = StatementKind::Regular; - let signature = sig::(&secret_key, &account.encode(), statement.to_text()); - super::Pallet::::mint_claim(RawOrigin::Root.into(), eth_address, VALUE.into(), vesting, Some(statement))?; - Preclaims::::insert(&account, eth_address); - assert_eq!(Claims::::get(eth_address), Some(VALUE.into())); - }: { - assert!(ext.test_run( - RawOrigin::Signed(account).into(), - &call, - &info, - 0, - |_| { - Ok(Default::default()) - } - ).unwrap().is_ok()); - } - impl_benchmark_test_suite!( Pallet, crate::claims::tests::new_test_ext(), diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 61ca1635ac9..3dc59cc1728 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -246,7 +246,6 @@ runtime-benchmarks = [ "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-tips/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "pallet-treasury/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", diff --git a/polkadot/runtime/rococo/constants/src/weights/block_weights.rs b/polkadot/runtime/rococo/constants/src/weights/block_weights.rs index f7dc2f19316..e2aa4a6cab7 100644 --- a/polkadot/runtime/rococo/constants/src/weights/block_weights.rs +++ b/polkadot/runtime/rococo/constants/src/weights/block_weights.rs @@ -14,13 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29 (Y/M/D) -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26 (Y/M/D) +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! //! SHORT-NAME: `block`, LONG-NAME: `BlockExecution`, RUNTIME: `Development` //! WARMUPS: `10`, REPEAT: `100` -//! WEIGHT-PATH: `./polkadot/runtime/rococo/constants/src/weights/` +//! WEIGHT-PATH: `runtime/rococo/constants/src/weights/` //! WEIGHT-METRIC: `Average`, WEIGHT-MUL: `1.0`, WEIGHT-ADD: `0` // Executed Command: @@ -28,11 +28,12 @@ // benchmark // overhead // --chain=rococo-dev +// --execution=wasm // --wasm-execution=compiled -// --weight-path=./polkadot/runtime/rococo/constants/src/weights/ +// --weight-path=runtime/rococo/constants/src/weights/ // --warmup=10 // --repeat=100 -// --header=./polkadot/file_header.txt +// --header=./file_header.txt use sp_core::parameter_types; use sp_weights::{constants::WEIGHT_REF_TIME_PER_NANOS, Weight}; @@ -42,17 +43,17 @@ parameter_types! { /// Calculated by multiplying the *Average* with `1.0` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 440_142, 476_907 - /// Average: 450_240 - /// Median: 448_633 - /// Std-Dev: 7301.18 + /// Min, Max: 408_659, 450_716 + /// Average: 417_412 + /// Median: 411_177 + /// Std-Dev: 12242.31 /// /// Percentiles nanoseconds: - /// 99th: 470_733 - /// 95th: 465_082 - /// 75th: 452_536 + /// 99th: 445_142 + /// 95th: 442_275 + /// 75th: 414_217 pub const BlockExecutionWeight: Weight = - Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(450_240), 0); + Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(417_412), 0); } #[cfg(test)] diff --git a/polkadot/runtime/rococo/constants/src/weights/extrinsic_weights.rs b/polkadot/runtime/rococo/constants/src/weights/extrinsic_weights.rs index 000cee8a237..adce840ebbc 100644 --- a/polkadot/runtime/rococo/constants/src/weights/extrinsic_weights.rs +++ b/polkadot/runtime/rococo/constants/src/weights/extrinsic_weights.rs @@ -14,13 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29 (Y/M/D) -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26 (Y/M/D) +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! //! SHORT-NAME: `extrinsic`, LONG-NAME: `ExtrinsicBase`, RUNTIME: `Development` //! WARMUPS: `10`, REPEAT: `100` -//! WEIGHT-PATH: `./polkadot/runtime/rococo/constants/src/weights/` +//! WEIGHT-PATH: `runtime/rococo/constants/src/weights/` //! WEIGHT-METRIC: `Average`, WEIGHT-MUL: `1.0`, WEIGHT-ADD: `0` // Executed Command: @@ -28,11 +28,12 @@ // benchmark // overhead // --chain=rococo-dev +// --execution=wasm // --wasm-execution=compiled -// --weight-path=./polkadot/runtime/rococo/constants/src/weights/ +// --weight-path=runtime/rococo/constants/src/weights/ // --warmup=10 // --repeat=100 -// --header=./polkadot/file_header.txt +// --header=./file_header.txt use sp_core::parameter_types; use sp_weights::{constants::WEIGHT_REF_TIME_PER_NANOS, Weight}; @@ -42,17 +43,17 @@ parameter_types! { /// Calculated by multiplying the *Average* with `1.0` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 92_961, 94_143 - /// Average: 93_369 - /// Median: 93_331 - /// Std-Dev: 217.39 + /// Min, Max: 97_574, 100_119 + /// Average: 98_236 + /// Median: 98_179 + /// Std-Dev: 394.9 /// /// Percentiles nanoseconds: - /// 99th: 93_848 - /// 95th: 93_691 - /// 75th: 93_514 + /// 99th: 99_893 + /// 95th: 98_850 + /// 75th: 98_318 pub const ExtrinsicBaseWeight: Weight = - Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(93_369), 0); + Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(98_236), 0); } #[cfg(test)] diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index ff54c777670..96e8c4e0979 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -199,7 +199,6 @@ impl frame_system::Config for Runtime { type Version = Version; type AccountData = pallet_balances::AccountData; type SystemWeightInfo = weights::frame_system::WeightInfo; - type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; type SS58Prefix = SS58Prefix; type MaxConsumers = frame_support::traits::ConstU32<16>; } @@ -330,7 +329,6 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; - type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -593,7 +591,7 @@ where // so the actual block number is `n`. .saturating_sub(1); let tip = 0; - let tx_ext: TxExtension = ( + let extra: SignedExtra = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -605,17 +603,16 @@ where frame_system::CheckNonce::::from(nonce), frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(tip), - ) - .into(); - let raw_payload = SignedPayload::new(call, tx_ext) + ); + let raw_payload = SignedPayload::new(call, extra) .map_err(|e| { log::warn!("Unable to create signed payload: {:?}", e); }) .ok()?; let signature = raw_payload.using_encoded(|payload| C::sign(payload, public))?; - let (call, tx_ext, _) = raw_payload.deconstruct(); + let (call, extra, _) = raw_payload.deconstruct(); let address = ::Lookup::unlookup(account); - Some((call, (address, signature, tx_ext))) + Some((call, (address, signature, extra))) } } @@ -636,32 +633,12 @@ parameter_types! { pub Prefix: &'static [u8] = b"Pay ROCs to the Rococo account:"; } -#[cfg(feature = "runtime-benchmarks")] -pub struct ClaimsHelper; - -#[cfg(feature = "runtime-benchmarks")] -use frame_support::dispatch::DispatchInfo; - -#[cfg(feature = "runtime-benchmarks")] -impl claims::BenchmarkHelperTrait for ClaimsHelper { - fn default_call_and_info() -> (RuntimeCall, DispatchInfo) { - use frame_support::dispatch::GetDispatchInfo; - let call = RuntimeCall::Claims(claims::Call::attest { - statement: claims::StatementKind::Regular.to_text().to_vec(), - }); - let info = call.get_dispatch_info(); - (call, info) - } -} - impl claims::Config for Runtime { type RuntimeEvent = RuntimeEvent; type VestingSchedule = Vesting; type Prefix = Prefix; type MoveClaimOrigin = EnsureRoot; type WeightInfo = weights::runtime_common_claims::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = ClaimsHelper; } parameter_types! { @@ -1470,8 +1447,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// `BlockId` type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The extension to the basic transaction logic. -pub type TxExtension = ( +/// The `SignedExtension` to the basic transaction logic. +pub type SignedExtra = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -1484,7 +1461,7 @@ pub type TxExtension = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// All migrations that will run on the next runtime upgrade. /// @@ -1698,7 +1675,7 @@ pub type Executive = frame_executive::Executive< Migrations, >; /// The payload being signed in transactions. -pub type SignedPayload = generic::SignedPayload; +pub type SignedPayload = generic::SignedPayload; parameter_types! { // The deposit configuration for the singed migration. Specially if you want to allow any signed account to do the migration (see `SignedFilter`, these deposits should be high) @@ -1769,9 +1746,7 @@ mod benches { [pallet_scheduler, Scheduler] [pallet_sudo, Sudo] [frame_system, SystemBench::] - [frame_system_extensions, SystemExtensionsBench::] [pallet_timestamp, Timestamp] - [pallet_transaction_payment, TransactionPayment] [pallet_treasury, Treasury] [pallet_utility, Utility] [pallet_vesting, Vesting] @@ -2265,7 +2240,6 @@ sp_api::impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use frame_benchmarking::baseline::Pallet as Baseline; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; @@ -2286,7 +2260,6 @@ sp_api::impl_runtime_apis! { use frame_support::traits::WhitelistedStorageKeys; use frame_benchmarking::{Benchmarking, BenchmarkBatch, BenchmarkError}; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use frame_benchmarking::baseline::Pallet as Baseline; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; use sp_storage::TrackedStorageKey; diff --git a/polkadot/runtime/rococo/src/weights/frame_benchmarking_baseline.rs b/polkadot/runtime/rococo/src/weights/frame_benchmarking_baseline.rs index 0f68a5c6fb3..dfba0cfc4aa 100644 --- a/polkadot/runtime/rococo/src/weights/frame_benchmarking_baseline.rs +++ b/polkadot/runtime/rococo/src/weights/frame_benchmarking_baseline.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `frame_benchmarking::baseline` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: // ./target/production/polkadot @@ -29,15 +29,12 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --pallet=frame_benchmarking::baseline // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/frame_benchmarking_baseline.rs +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/frame_benchmarking_baseline.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -55,8 +52,8 @@ impl frame_benchmarking::baseline::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 172_000 picoseconds. - Weight::from_parts(199_481, 0) + // Minimum execution time: 157_000 picoseconds. + Weight::from_parts(175_233, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `i` is `[0, 1000000]`. @@ -64,8 +61,8 @@ impl frame_benchmarking::baseline::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 171_000 picoseconds. - Weight::from_parts(197_821, 0) + // Minimum execution time: 149_000 picoseconds. + Weight::from_parts(183_285, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `i` is `[0, 1000000]`. @@ -73,8 +70,8 @@ impl frame_benchmarking::baseline::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 172_000 picoseconds. - Weight::from_parts(200_942, 0) + // Minimum execution time: 158_000 picoseconds. + Weight::from_parts(184_720, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `i` is `[0, 1000000]`. @@ -82,16 +79,16 @@ impl frame_benchmarking::baseline::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 170_000 picoseconds. - Weight::from_parts(196_906, 0) + // Minimum execution time: 152_000 picoseconds. + Weight::from_parts(177_496, 0) .saturating_add(Weight::from_parts(0, 0)) } fn hashing() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 23_346_876_000 picoseconds. - Weight::from_parts(23_363_744_000, 0) + // Minimum execution time: 19_907_376_000 picoseconds. + Weight::from_parts(19_988_727_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `i` is `[0, 100]`. @@ -99,10 +96,10 @@ impl frame_benchmarking::baseline::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 201_000 picoseconds. - Weight::from_parts(219_000, 0) + // Minimum execution time: 198_000 picoseconds. + Weight::from_parts(228_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 14_372 - .saturating_add(Weight::from_parts(45_375_800, 0).saturating_mul(i.into())) + // Standard Error: 20_467 + .saturating_add(Weight::from_parts(47_443_635, 0).saturating_mul(i.into())) } } diff --git a/polkadot/runtime/rococo/src/weights/frame_system.rs b/polkadot/runtime/rococo/src/weights/frame_system.rs index 1742a761ca7..2e49483dcc6 100644 --- a/polkadot/runtime/rococo/src/weights/frame_system.rs +++ b/polkadot/runtime/rococo/src/weights/frame_system.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `frame_system` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: // ./target/production/polkadot @@ -29,15 +29,12 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --pallet=frame_system // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -55,91 +52,91 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_541_000 picoseconds. - Weight::from_parts(2_581_470, 0) + // Minimum execution time: 2_283_000 picoseconds. + Weight::from_parts(2_305_000, 0) .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 0 - .saturating_add(Weight::from_parts(387, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(366, 0).saturating_mul(b.into())) } /// The range of component `b` is `[0, 3932160]`. fn remark_with_event(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_060_000 picoseconds. - Weight::from_parts(5_167_000, 0) + // Minimum execution time: 7_435_000 picoseconds. + Weight::from_parts(7_581_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_696, 0).saturating_mul(b.into())) + // Standard Error: 0 + .saturating_add(Weight::from_parts(1_408, 0).saturating_mul(b.into())) } - /// Storage: `System::Digest` (r:1 w:1) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: UNKNOWN KEY `0x3a686561707061676573` (r:0 w:1) - /// Proof: UNKNOWN KEY `0x3a686561707061676573` (r:0 w:1) + /// Storage: System Digest (r:1 w:1) + /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: unknown `0x3a686561707061676573` (r:0 w:1) + /// Proof Skipped: unknown `0x3a686561707061676573` (r:0 w:1) fn set_heap_pages() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1485` - // Minimum execution time: 2_649_000 picoseconds. - Weight::from_parts(2_909_000, 0) + // Minimum execution time: 4_010_000 picoseconds. + Weight::from_parts(4_112_000, 0) .saturating_add(Weight::from_parts(0, 1485)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `System::Digest` (r:1 w:1) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: UNKNOWN KEY `0x3a636f6465` (r:0 w:1) - /// Proof: UNKNOWN KEY `0x3a636f6465` (r:0 w:1) + /// Storage: System Digest (r:1 w:1) + /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: unknown `0x3a636f6465` (r:0 w:1) + /// Proof Skipped: unknown `0x3a636f6465` (r:0 w:1) fn set_code() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1485` - // Minimum execution time: 88_417_540_000 picoseconds. - Weight::from_parts(91_809_291_000, 0) + // Minimum execution time: 80_405_511_000 picoseconds. + Weight::from_parts(83_066_478_000, 0) .saturating_add(Weight::from_parts(0, 1485)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Skipped::Metadata` (r:0 w:0) - /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `i` is `[0, 1000]`. fn set_storage(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_538_000 picoseconds. - Weight::from_parts(1_589_000, 0) + // Minimum execution time: 2_210_000 picoseconds. + Weight::from_parts(2_247_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_740 - .saturating_add(Weight::from_parts(730_941, 0).saturating_mul(i.into())) + // Standard Error: 2_058 + .saturating_add(Weight::from_parts(673_943, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } - /// Storage: `Skipped::Metadata` (r:0 w:0) - /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `i` is `[0, 1000]`. fn kill_storage(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_567_000 picoseconds. - Weight::from_parts(1_750_000, 0) + // Minimum execution time: 2_125_000 picoseconds. + Weight::from_parts(2_154_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 835 - .saturating_add(Weight::from_parts(543_218, 0).saturating_mul(i.into())) + // Standard Error: 816 + .saturating_add(Weight::from_parts(491_194, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } - /// Storage: `Skipped::Metadata` (r:0 w:0) - /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `p` is `[0, 1000]`. fn kill_prefix(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `80 + p * (69 ±0)` - // Estimated: `83 + p * (70 ±0)` - // Minimum execution time: 3_412_000 picoseconds. - Weight::from_parts(3_448_000, 0) - .saturating_add(Weight::from_parts(0, 83)) - // Standard Error: 1_395 - .saturating_add(Weight::from_parts(1_142_347, 0).saturating_mul(p.into())) + // Measured: `129 + p * (69 ±0)` + // Estimated: `125 + p * (70 ±0)` + // Minimum execution time: 4_002_000 picoseconds. + Weight::from_parts(4_145_000, 0) + .saturating_add(Weight::from_parts(0, 125)) + // Standard Error: 1_108 + .saturating_add(Weight::from_parts(1_014_971, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) .saturating_add(Weight::from_parts(0, 70).saturating_mul(p.into())) @@ -150,8 +147,8 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_178_000 picoseconds. - Weight::from_parts(9_780_000, 0) + // Minimum execution time: 33_027_000 picoseconds. + Weight::from_parts(33_027_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -165,8 +162,8 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `22` // Estimated: `1518` - // Minimum execution time: 94_523_563_000 picoseconds. - Weight::from_parts(96_983_131_000, 0) + // Minimum execution time: 118_101_992_000 picoseconds. + Weight::from_parts(118_101_992_000, 0) .saturating_add(Weight::from_parts(0, 1518)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(3)) diff --git a/polkadot/runtime/rococo/src/weights/frame_system_extensions.rs b/polkadot/runtime/rococo/src/weights/frame_system_extensions.rs deleted file mode 100644 index 40520591f53..00000000000 --- a/polkadot/runtime/rococo/src/weights/frame_system_extensions.rs +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `frame_system_extensions` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=rococo-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=frame_system_extensions -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `frame_system_extensions`. -pub struct WeightInfo(PhantomData); -impl frame_system::ExtensionsWeightInfo for WeightInfo { - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_genesis() -> Weight { - // Proof Size summary in bytes: - // Measured: `54` - // Estimated: `3509` - // Minimum execution time: 3_262_000 picoseconds. - Weight::from_parts(3_497_000, 0) - .saturating_add(Weight::from_parts(0, 3509)) - .saturating_add(T::DbWeight::get().reads(1)) - } - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_mortality() -> Weight { - // Proof Size summary in bytes: - // Measured: `92` - // Estimated: `3509` - // Minimum execution time: 5_416_000 picoseconds. - Weight::from_parts(5_690_000, 0) - .saturating_add(Weight::from_parts(0, 3509)) - .saturating_add(T::DbWeight::get().reads(1)) - } - fn check_non_zero_sender() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 471_000 picoseconds. - Weight::from_parts(552_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn check_nonce() -> Weight { - // Proof Size summary in bytes: - // Measured: `101` - // Estimated: `3593` - // Minimum execution time: 4_847_000 picoseconds. - Weight::from_parts(5_091_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - fn check_spec_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 388_000 picoseconds. - Weight::from_parts(421_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_tx_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 378_000 picoseconds. - Weight::from_parts(440_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) - /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn check_weight() -> Weight { - // Proof Size summary in bytes: - // Measured: `24` - // Estimated: `1489` - // Minimum execution time: 3_402_000 picoseconds. - Weight::from_parts(3_627_000, 0) - .saturating_add(Weight::from_parts(0, 1489)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/rococo/src/weights/mod.rs b/polkadot/runtime/rococo/src/weights/mod.rs index 128a3083a9c..7328dca9393 100644 --- a/polkadot/runtime/rococo/src/weights/mod.rs +++ b/polkadot/runtime/rococo/src/weights/mod.rs @@ -16,7 +16,6 @@ //! A list of the different weight modules for our runtime. pub mod frame_system; -pub mod frame_system_extensions; pub mod pallet_asset_rate; pub mod pallet_balances_balances; pub mod pallet_balances_nis_counterpart_balances; @@ -37,7 +36,6 @@ pub mod pallet_scheduler; pub mod pallet_session; pub mod pallet_sudo; pub mod pallet_timestamp; -pub mod pallet_transaction_payment; pub mod pallet_treasury; pub mod pallet_utility; pub mod pallet_vesting; diff --git a/polkadot/runtime/rococo/src/weights/pallet_asset_rate.rs b/polkadot/runtime/rococo/src/weights/pallet_asset_rate.rs index 56b1e2cbc57..da2d1958cef 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_asset_rate.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_asset_rate.rs @@ -16,28 +16,25 @@ //! Autogenerated weights for `pallet_asset_rate` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-03, STEPS: `50`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `cob`, CPU: `` +//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// ./target/debug/polkadot // benchmark // pallet // --chain=rococo-dev // --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares +// --repeat=2 // --pallet=pallet_asset_rate // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ +// --heap-pages=4096 +// --output=./runtime/rococo/src/weights/ +// --header=./file_header.txt #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,39 +47,39 @@ use core::marker::PhantomData; /// Weight functions for `pallet_asset_rate`. pub struct WeightInfo(PhantomData); impl pallet_asset_rate::WeightInfo for WeightInfo { - /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) - /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(1238), added: 3713, mode: `MaxEncodedLen`) + /// Storage: AssetRate ConversionRateToNative (r:1 w:1) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(1237), added: 3712, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `142` - // Estimated: `4703` - // Minimum execution time: 10_277_000 picoseconds. - Weight::from_parts(10_487_000, 0) - .saturating_add(Weight::from_parts(0, 4703)) + // Measured: `42` + // Estimated: `4702` + // Minimum execution time: 143_000_000 picoseconds. + Weight::from_parts(155_000_000, 0) + .saturating_add(Weight::from_parts(0, 4702)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) - /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(1238), added: 3713, mode: `MaxEncodedLen`) + /// Storage: AssetRate ConversionRateToNative (r:1 w:1) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(1237), added: 3712, mode: MaxEncodedLen) fn update() -> Weight { // Proof Size summary in bytes: - // Measured: `210` - // Estimated: `4703` - // Minimum execution time: 10_917_000 picoseconds. - Weight::from_parts(11_249_000, 0) - .saturating_add(Weight::from_parts(0, 4703)) + // Measured: `110` + // Estimated: `4702` + // Minimum execution time: 156_000_000 picoseconds. + Weight::from_parts(172_000_000, 0) + .saturating_add(Weight::from_parts(0, 4702)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) - /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(1238), added: 3713, mode: `MaxEncodedLen`) + /// Storage: AssetRate ConversionRateToNative (r:1 w:1) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(1237), added: 3712, mode: MaxEncodedLen) fn remove() -> Weight { // Proof Size summary in bytes: - // Measured: `210` - // Estimated: `4703` - // Minimum execution time: 11_332_000 picoseconds. - Weight::from_parts(11_866_000, 0) - .saturating_add(Weight::from_parts(0, 4703)) + // Measured: `110` + // Estimated: `4702` + // Minimum execution time: 150_000_000 picoseconds. + Weight::from_parts(160_000_000, 0) + .saturating_add(Weight::from_parts(0, 4702)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/rococo/src/weights/pallet_balances_balances.rs b/polkadot/runtime/rococo/src/weights/pallet_balances_balances.rs index 3fa54f2c369..1b0ae1eeece 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_balances_balances.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_balances_balances.rs @@ -16,26 +16,24 @@ //! Autogenerated weights for `pallet_balances` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2024-01-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-j8vvqcjr-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet -// --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_balances // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_balances +// --chain=rococo-dev // --header=./polkadot/file_header.txt // --output=./polkadot/runtime/rococo/src/weights/ @@ -56,8 +54,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 45_336_000 picoseconds. - Weight::from_parts(46_189_000, 0) + // Minimum execution time: 44_127_000 picoseconds. + Weight::from_parts(45_099_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -68,8 +66,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 34_880_000 picoseconds. - Weight::from_parts(35_770_000, 0) + // Minimum execution time: 34_265_000 picoseconds. + Weight::from_parts(35_083_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -80,8 +78,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 12_904_000 picoseconds. - Weight::from_parts(13_260_000, 0) + // Minimum execution time: 12_189_000 picoseconds. + Weight::from_parts(12_655_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -92,8 +90,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 17_669_000 picoseconds. - Weight::from_parts(18_228_000, 0) + // Minimum execution time: 16_910_000 picoseconds. + Weight::from_parts(17_474_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -104,8 +102,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6196` - // Minimum execution time: 46_492_000 picoseconds. - Weight::from_parts(47_639_000, 0) + // Minimum execution time: 45_212_000 picoseconds. + Weight::from_parts(46_320_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -116,8 +114,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 44_342_000 picoseconds. - Weight::from_parts(45_144_000, 0) + // Minimum execution time: 42_500_000 picoseconds. + Weight::from_parts(43_991_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -128,8 +126,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 15_260_000 picoseconds. - Weight::from_parts(15_775_000, 0) + // Minimum execution time: 15_197_000 picoseconds. + Weight::from_parts(15_749_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -142,11 +140,11 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0 + u * (135 ±0)` // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 14_703_000 picoseconds. - Weight::from_parts(14_950_000, 0) + // Minimum execution time: 14_414_000 picoseconds. + Weight::from_parts(14_685_000, 0) .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 7_665 - .saturating_add(Weight::from_parts(13_335_803, 0).saturating_mul(u.into())) + // Standard Error: 7_918 + .saturating_add(Weight::from_parts(13_095_420, 0).saturating_mul(u.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(u.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(u.into()))) .saturating_add(Weight::from_parts(0, 2603).saturating_mul(u.into())) @@ -155,8 +153,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_506_000 picoseconds. - Weight::from_parts(5_753_000, 0) + // Minimum execution time: 5_239_000 picoseconds. + Weight::from_parts(5_617_000, 0) .saturating_add(Weight::from_parts(0, 0)) } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_balances_nis_counterpart_balances.rs b/polkadot/runtime/rococo/src/weights/pallet_balances_nis_counterpart_balances.rs index 1852ba6c2c4..6cca9b9320a 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_balances_nis_counterpart_balances.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_balances_nis_counterpart_balances.rs @@ -16,26 +16,24 @@ //! Autogenerated weights for `pallet_balances` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2024-01-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-j8vvqcjr-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet -// --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_balances // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_balances +// --chain=rococo-dev // --header=./polkadot/file_header.txt // --output=./polkadot/runtime/rococo/src/weights/ @@ -58,8 +56,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6164` - // Minimum execution time: 42_443_000 picoseconds. - Weight::from_parts(43_250_000, 0) + // Minimum execution time: 41_978_000 picoseconds. + Weight::from_parts(42_989_000, 0) .saturating_add(Weight::from_parts(0, 6164)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) @@ -72,8 +70,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6164` - // Minimum execution time: 32_417_000 picoseconds. - Weight::from_parts(33_247_000, 0) + // Minimum execution time: 32_250_000 picoseconds. + Weight::from_parts(33_074_000, 0) .saturating_add(Weight::from_parts(0, 6164)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) @@ -84,8 +82,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3577` - // Minimum execution time: 10_091_000 picoseconds. - Weight::from_parts(10_426_000, 0) + // Minimum execution time: 9_906_000 picoseconds. + Weight::from_parts(10_397_000, 0) .saturating_add(Weight::from_parts(0, 3577)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -98,8 +96,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `277` // Estimated: `3593` - // Minimum execution time: 16_546_000 picoseconds. - Weight::from_parts(17_259_000, 0) + // Minimum execution time: 16_298_000 picoseconds. + Weight::from_parts(17_115_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -112,8 +110,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `206` // Estimated: `6196` - // Minimum execution time: 44_322_000 picoseconds. - Weight::from_parts(45_319_000, 0) + // Minimum execution time: 43_283_000 picoseconds. + Weight::from_parts(44_033_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) @@ -126,8 +124,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6164` - // Minimum execution time: 40_852_000 picoseconds. - Weight::from_parts(42_205_000, 0) + // Minimum execution time: 40_564_000 picoseconds. + Weight::from_parts(41_597_000, 0) .saturating_add(Weight::from_parts(0, 6164)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) @@ -140,8 +138,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `277` // Estimated: `3593` - // Minimum execution time: 15_050_000 picoseconds. - Weight::from_parts(15_813_000, 0) + // Minimum execution time: 15_018_000 picoseconds. + Weight::from_parts(15_532_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -156,11 +154,11 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0 + u * (256 ±0)` // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 14_830_000 picoseconds. - Weight::from_parts(15_061_000, 0) + // Minimum execution time: 14_470_000 picoseconds. + Weight::from_parts(14_828_000, 0) .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 16_072 - .saturating_add(Weight::from_parts(14_981_430, 0).saturating_mul(u.into())) + // Standard Error: 15_515 + .saturating_add(Weight::from_parts(14_505_553, 0).saturating_mul(u.into())) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(u.into()))) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(u.into()))) .saturating_add(Weight::from_parts(0, 2603).saturating_mul(u.into())) @@ -169,8 +167,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_344_000 picoseconds. - Weight::from_parts(5_735_000, 0) + // Minimum execution time: 5_277_000 picoseconds. + Weight::from_parts(5_628_000, 0) .saturating_add(Weight::from_parts(0, 0)) } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_bounties.rs b/polkadot/runtime/rococo/src/weights/pallet_bounties.rs index 8f8be5f2386..38d3645316f 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_bounties.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_bounties.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_bounties` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: // ./target/production/polkadot @@ -29,15 +29,12 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --pallet=pallet_bounties // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,181 +47,118 @@ use core::marker::PhantomData; /// Weight functions for `pallet_bounties`. pub struct WeightInfo(PhantomData); impl pallet_bounties::WeightInfo for WeightInfo { - /// Storage: `Bounties::BountyCount` (r:1 w:1) - /// Proof: `Bounties::BountyCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Bounties::BountyDescriptions` (r:0 w:1) - /// Proof: `Bounties::BountyDescriptions` (`max_values`: None, `max_size`: Some(16400), added: 18875, mode: `MaxEncodedLen`) - /// Storage: `Bounties::Bounties` (r:0 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: Bounties BountyCount (r:1 w:1) + /// Proof: Bounties BountyCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Bounties BountyDescriptions (r:0 w:1) + /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(16400), added: 18875, mode: MaxEncodedLen) + /// Storage: Bounties Bounties (r:0 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) /// The range of component `d` is `[0, 16384]`. fn propose_bounty(d: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `210` // Estimated: `3593` - // Minimum execution time: 21_772_000 picoseconds. - Weight::from_parts(22_861_341, 0) + // Minimum execution time: 28_907_000 picoseconds. + Weight::from_parts(31_356_074, 0) .saturating_add(Weight::from_parts(0, 3593)) - // Standard Error: 3 - .saturating_add(Weight::from_parts(721, 0).saturating_mul(d.into())) + // Standard Error: 18 + .saturating_add(Weight::from_parts(606, 0).saturating_mul(d.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `Bounties::BountyApprovals` (r:1 w:1) - /// Proof: `Bounties::BountyApprovals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) fn approve_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `302` - // Estimated: `3642` - // Minimum execution time: 11_218_000 picoseconds. - Weight::from_parts(11_796_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(0, 0) + .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) fn propose_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `322` - // Estimated: `3642` - // Minimum execution time: 10_959_000 picoseconds. - Weight::from_parts(11_658_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(0, 0) + .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn unassign_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `498` - // Estimated: `3642` - // Minimum execution time: 37_419_000 picoseconds. - Weight::from_parts(38_362_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(0, 0) + .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn accept_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `494` - // Estimated: `3642` - // Minimum execution time: 27_328_000 picoseconds. - Weight::from_parts(27_661_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(0, 0) + .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:0) - /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) fn award_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `400` - // Estimated: `3642` - // Minimum execution time: 16_067_000 picoseconds. - Weight::from_parts(16_865_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(0, 0) + .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:3 w:3) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1) - /// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `Bounties::BountyDescriptions` (r:0 w:1) - /// Proof: `Bounties::BountyDescriptions` (`max_values`: None, `max_size`: Some(16400), added: 18875, mode: `MaxEncodedLen`) fn claim_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `764` - // Estimated: `8799` - // Minimum execution time: 101_153_000 picoseconds. - Weight::from_parts(102_480_000, 0) - .saturating_add(Weight::from_parts(0, 8799)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(6)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(0, 0) + .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:0) - /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Bounties::BountyDescriptions` (r:0 w:1) - /// Proof: `Bounties::BountyDescriptions` (`max_values`: None, `max_size`: Some(16400), added: 18875, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ParentChildBounties (r:1 w:0) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Bounties BountyDescriptions (r:0 w:1) + /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(16400), added: 18875, mode: MaxEncodedLen) fn close_bounty_proposed() -> Weight { // Proof Size summary in bytes: - // Measured: `444` + // Measured: `482` // Estimated: `3642` - // Minimum execution time: 38_838_000 picoseconds. - Weight::from_parts(39_549_000, 0) + // Minimum execution time: 46_020_000 picoseconds. + Weight::from_parts(46_711_000, 0) .saturating_add(Weight::from_parts(0, 3642)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:0) - /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Bounties::BountyDescriptions` (r:0 w:1) - /// Proof: `Bounties::BountyDescriptions` (`max_values`: None, `max_size`: Some(16400), added: 18875, mode: `MaxEncodedLen`) fn close_bounty_active() -> Weight { // Proof Size summary in bytes: - // Measured: `680` - // Estimated: `6196` - // Minimum execution time: 68_592_000 picoseconds. - Weight::from_parts(70_727_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(0, 0) + .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) fn extend_bounty_expiry() -> Weight { // Proof Size summary in bytes: - // Measured: `358` - // Estimated: `3642` - // Minimum execution time: 11_272_000 picoseconds. - Weight::from_parts(11_592_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(0, 0) + .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: `Bounties::BountyApprovals` (r:1 w:1) - /// Proof: `Bounties::BountyApprovals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) - /// Storage: `Bounties::Bounties` (r:100 w:100) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:200 w:200) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Bounties BountyApprovals (r:1 w:1) + /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) /// The range of component `b` is `[0, 100]`. - fn spend_funds(b: u32, ) -> Weight { + fn spend_funds(_b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + b * (297 ±0)` - // Estimated: `1887 + b * (5206 ±0)` - // Minimum execution time: 2_844_000 picoseconds. - Weight::from_parts(2_900_000, 0) + // Measured: `0` + // Estimated: `1887` + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(2_405_233, 0) .saturating_add(Weight::from_parts(0, 1887)) - // Standard Error: 9_467 - .saturating_add(Weight::from_parts(32_326_595, 0).saturating_mul(b.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(b.into()))) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(b.into()))) - .saturating_add(Weight::from_parts(0, 5206).saturating_mul(b.into())) } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_child_bounties.rs b/polkadot/runtime/rococo/src/weights/pallet_child_bounties.rs index 47ae3a5c90d..e8c798d45e7 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_child_bounties.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_child_bounties.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_child_bounties` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: // ./target/production/polkadot @@ -29,15 +29,12 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --pallet=pallet_child_bounties // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,153 +47,69 @@ use core::marker::PhantomData; /// Weight functions for `pallet_child_bounties`. pub struct WeightInfo(PhantomData); impl pallet_child_bounties::WeightInfo for WeightInfo { - /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) - /// Storage: `Bounties::Bounties` (r:1 w:0) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBountyCount` (r:1 w:1) - /// Proof: `ChildBounties::ChildBountyCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBountyDescriptions` (r:0 w:1) - /// Proof: `ChildBounties::ChildBountyDescriptions` (`max_values`: None, `max_size`: Some(16400), added: 18875, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBounties` (r:0 w:1) - /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) /// The range of component `d` is `[0, 16384]`. - fn add_child_bounty(d: u32, ) -> Weight { + fn add_child_bounty(_d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `540` - // Estimated: `6196` - // Minimum execution time: 57_964_000 picoseconds. - Weight::from_parts(59_559_565, 0) - .saturating_add(Weight::from_parts(0, 6196)) - // Standard Error: 11 - .saturating_add(Weight::from_parts(697, 0).saturating_mul(d.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(6)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(0, 0) + .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: `Bounties::Bounties` (r:1 w:0) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1) - /// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) fn propose_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `594` - // Estimated: `3642` - // Minimum execution time: 17_527_000 picoseconds. - Weight::from_parts(18_257_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(0, 0) + .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: `Bounties::Bounties` (r:1 w:0) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn accept_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `740` - // Estimated: `3642` - // Minimum execution time: 29_354_000 picoseconds. - Weight::from_parts(30_629_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(0, 0) + .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) - /// Storage: `Bounties::Bounties` (r:1 w:0) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn unassign_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `740` - // Estimated: `3642` - // Minimum execution time: 40_643_000 picoseconds. - Weight::from_parts(42_072_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(0, 0) + .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: `Bounties::Bounties` (r:1 w:0) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) fn award_child_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `637` - // Estimated: `3642` - // Minimum execution time: 18_616_000 picoseconds. - Weight::from_parts(19_316_000, 0) - .saturating_add(Weight::from_parts(0, 3642)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(0, 0) + .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:3 w:3) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBountyDescriptions` (r:0 w:1) - /// Proof: `ChildBounties::ChildBountyDescriptions` (`max_values`: None, `max_size`: Some(16400), added: 18875, mode: `MaxEncodedLen`) fn claim_child_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `576` - // Estimated: `8799` - // Minimum execution time: 96_376_000 picoseconds. - Weight::from_parts(98_476_000, 0) - .saturating_add(Weight::from_parts(0, 8799)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(6)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(0, 0) + .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: `Bounties::Bounties` (r:1 w:0) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1) - /// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBountyDescriptions` (r:0 w:1) - /// Proof: `ChildBounties::ChildBountyDescriptions` (`max_values`: None, `max_size`: Some(16400), added: 18875, mode: `MaxEncodedLen`) fn close_child_bounty_added() -> Weight { // Proof Size summary in bytes: - // Measured: `840` - // Estimated: `6196` - // Minimum execution time: 64_640_000 picoseconds. - Weight::from_parts(66_174_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(6)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(0, 0) + .saturating_add(Weight::from_parts(0, 0)) } - /// Storage: `Bounties::Bounties` (r:1 w:0) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:3 w:3) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1) - /// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBountyDescriptions` (r:0 w:1) - /// Proof: `ChildBounties::ChildBountyDescriptions` (`max_values`: None, `max_size`: Some(16400), added: 18875, mode: `MaxEncodedLen`) fn close_child_bounty_active() -> Weight { // Proof Size summary in bytes: - // Measured: `1027` - // Estimated: `8799` - // Minimum execution time: 78_159_000 picoseconds. - Weight::from_parts(79_820_000, 0) - .saturating_add(Weight::from_parts(0, 8799)) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(7)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(0, 0) + .saturating_add(Weight::from_parts(0, 0)) } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_conviction_voting.rs b/polkadot/runtime/rococo/src/weights/pallet_conviction_voting.rs index 5d92c158df4..ba505737f1b 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_conviction_voting.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_conviction_voting.rs @@ -16,17 +16,17 @@ //! Autogenerated weights for `pallet_conviction_voting` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 // Executed Command: // ./target/production/polkadot // benchmark // pallet -// --chain=rococo-dev +// --chain=kusama-dev // --steps=50 // --repeat=20 // --no-storage-info @@ -36,8 +36,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ +// --header=./file_header.txt +// --output=./runtime/kusama/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,152 +50,144 @@ use core::marker::PhantomData; /// Weight functions for `pallet_conviction_voting`. pub struct WeightInfo(PhantomData); impl pallet_conviction_voting::WeightInfo for WeightInfo { - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) - /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) - /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) - /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) - /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(311), added: 2786, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) + /// Storage: ConvictionVoting VotingFor (r:1 w:1) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(311), added: 2786, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) fn vote_new() -> Weight { // Proof Size summary in bytes: - // Measured: `13407` + // Measured: `13445` // Estimated: `42428` - // Minimum execution time: 128_378_000 picoseconds. - Weight::from_parts(131_028_000, 0) + // Minimum execution time: 151_077_000 picoseconds. + Weight::from_parts(165_283_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) - /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) - /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) - /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) - /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(311), added: 2786, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) + /// Storage: ConvictionVoting VotingFor (r:1 w:1) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(311), added: 2786, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) fn vote_existing() -> Weight { // Proof Size summary in bytes: - // Measured: `14128` + // Measured: `14166` // Estimated: `83866` - // Minimum execution time: 155_379_000 picoseconds. - Weight::from_parts(161_597_000, 0) + // Minimum execution time: 232_420_000 picoseconds. + Weight::from_parts(244_439_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(7)) + .saturating_add(T::DbWeight::get().writes(6)) } - /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) - /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: ConvictionVoting VotingFor (r:1 w:1) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) fn remove_vote() -> Weight { // Proof Size summary in bytes: // Measured: `13918` // Estimated: `83866` - // Minimum execution time: 130_885_000 picoseconds. - Weight::from_parts(138_080_000, 0) + // Minimum execution time: 205_017_000 picoseconds. + Weight::from_parts(216_594_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) - /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: ConvictionVoting VotingFor (r:1 w:1) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) fn remove_other_vote() -> Weight { // Proof Size summary in bytes: - // Measured: `13005` + // Measured: `13004` // Estimated: `30706` - // Minimum execution time: 71_743_000 picoseconds. - Weight::from_parts(75_170_000, 0) + // Minimum execution time: 84_226_000 picoseconds. + Weight::from_parts(91_255_000, 0) .saturating_add(Weight::from_parts(0, 30706)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `ConvictionVoting::VotingFor` (r:2 w:2) - /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) - /// Storage: `Referenda::ReferendumInfoFor` (r:512 w:512) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) - /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) - /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(311), added: 2786, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:50) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: ConvictionVoting VotingFor (r:2 w:2) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:512 w:512) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) + /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(311), added: 2786, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `r` is `[0, 512]`. fn delegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `29602 + r * (365 ±0)` + // Measured: `29640 + r * (365 ±0)` // Estimated: `83866 + r * (3411 ±0)` - // Minimum execution time: 58_504_000 picoseconds. - Weight::from_parts(814_301_018, 0) + // Minimum execution time: 78_708_000 picoseconds. + Weight::from_parts(2_053_488_615, 0) .saturating_add(Weight::from_parts(0, 83866)) - // Standard Error: 59_961 - .saturating_add(Weight::from_parts(20_002_833, 0).saturating_mul(r.into())) + // Standard Error: 179_271 + .saturating_add(Weight::from_parts(47_806_482, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) - .saturating_add(T::DbWeight::get().writes(45)) + .saturating_add(T::DbWeight::get().writes(6)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 3411).saturating_mul(r.into())) } - /// Storage: `ConvictionVoting::VotingFor` (r:2 w:2) - /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) - /// Storage: `Referenda::ReferendumInfoFor` (r:512 w:512) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:50) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: ConvictionVoting VotingFor (r:2 w:2) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:512 w:512) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) /// The range of component `r` is `[0, 512]`. fn undelegate(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `29555 + r * (365 ±0)` // Estimated: `83866 + r * (3411 ±0)` - // Minimum execution time: 34_970_000 picoseconds. - Weight::from_parts(771_155_804, 0) + // Minimum execution time: 45_232_000 picoseconds. + Weight::from_parts(2_045_021_014, 0) .saturating_add(Weight::from_parts(0, 83866)) - // Standard Error: 57_795 - .saturating_add(Weight::from_parts(19_781_645, 0).saturating_mul(r.into())) + // Standard Error: 185_130 + .saturating_add(Weight::from_parts(47_896_011, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) - .saturating_add(T::DbWeight::get().writes(43)) + .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 3411).saturating_mul(r.into())) } - /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) - /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) - /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) - /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(311), added: 2786, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: ConvictionVoting VotingFor (r:1 w:1) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(311), added: 2786, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn unlock() -> Weight { // Proof Size summary in bytes: - // Measured: `12180` + // Measured: `12218` // Estimated: `30706` - // Minimum execution time: 89_648_000 picoseconds. - Weight::from_parts(97_144_000, 0) + // Minimum execution time: 116_446_000 picoseconds. + Weight::from_parts(124_043_000, 0) .saturating_add(Weight::from_parts(0, 30706)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) diff --git a/polkadot/runtime/rococo/src/weights/pallet_identity.rs b/polkadot/runtime/rococo/src/weights/pallet_identity.rs index 6df16351f2c..b334e21ea03 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_identity.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_identity.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_identity` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: // ./target/production/polkadot @@ -29,15 +29,12 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --pallet=pallet_identity // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,291 +47,290 @@ use core::marker::PhantomData; /// Weight functions for `pallet_identity`. pub struct WeightInfo(PhantomData); impl pallet_identity::WeightInfo for WeightInfo { - /// Storage: `Identity::Registrars` (r:1 w:1) - /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn add_registrar(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `32 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 7_673_000 picoseconds. - Weight::from_parts(8_351_866, 0) + // Minimum execution time: 12_290_000 picoseconds. + Weight::from_parts(12_664_362, 0) .saturating_add(Weight::from_parts(0, 2626)) - // Standard Error: 1_302 - .saturating_add(Weight::from_parts(79_198, 0).saturating_mul(r.into())) + // Standard Error: 1_347 + .saturating_add(Weight::from_parts(88_179, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. fn set_identity(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `6978 + r * (5 ±0)` - // Estimated: `11037` - // Minimum execution time: 111_646_000 picoseconds. - Weight::from_parts(113_254_991, 0) - .saturating_add(Weight::from_parts(0, 11037)) - // Standard Error: 6_611 - .saturating_add(Weight::from_parts(162_119, 0).saturating_mul(r.into())) + // Measured: `442 + r * (5 ±0)` + // Estimated: `11003` + // Minimum execution time: 31_373_000 picoseconds. + Weight::from_parts(30_435_545, 0) + .saturating_add(Weight::from_parts(0, 11003)) + // Standard Error: 2_307 + .saturating_add(Weight::from_parts(92_753, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - /// Storage: `Identity::SubsOf` (r:1 w:1) - /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) - /// Storage: `Identity::SuperOf` (r:100 w:100) - /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:100 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn set_subs_new(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `101` - // Estimated: `11037 + s * (2589 ±0)` - // Minimum execution time: 8_010_000 picoseconds. - Weight::from_parts(19_868_412, 0) - .saturating_add(Weight::from_parts(0, 11037)) - // Standard Error: 5_018 - .saturating_add(Weight::from_parts(3_115_007, 0).saturating_mul(s.into())) + // Estimated: `11003 + s * (2589 ±0)` + // Minimum execution time: 9_251_000 picoseconds. + Weight::from_parts(22_039_210, 0) + .saturating_add(Weight::from_parts(0, 11003)) + // Standard Error: 40_779 + .saturating_add(Weight::from_parts(2_898_525, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(s.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 2589).saturating_mul(s.into())) } - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - /// Storage: `Identity::SubsOf` (r:1 w:1) - /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) - /// Storage: `Identity::SuperOf` (r:0 w:100) - /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:0 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `p` is `[0, 100]`. fn set_subs_old(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `194 + p * (32 ±0)` - // Estimated: `11037` - // Minimum execution time: 8_111_000 picoseconds. - Weight::from_parts(19_482_392, 0) - .saturating_add(Weight::from_parts(0, 11037)) - // Standard Error: 3_156 - .saturating_add(Weight::from_parts(1_305_890, 0).saturating_mul(p.into())) + // Estimated: `11003` + // Minimum execution time: 9_329_000 picoseconds. + Weight::from_parts(24_055_061, 0) + .saturating_add(Weight::from_parts(0, 11003)) + // Standard Error: 3_428 + .saturating_add(Weight::from_parts(1_130_604, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) } - /// Storage: `Identity::SubsOf` (r:1 w:1) - /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - /// Storage: `Identity::SuperOf` (r:0 w:100) - /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:0 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `s` is `[0, 100]`. - fn clear_identity(r: u32, s: u32, ) -> Weight { + fn clear_identity(_r: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `7070 + r * (5 ±0) + s * (32 ±0)` - // Estimated: `11037` - // Minimum execution time: 54_107_000 picoseconds. - Weight::from_parts(56_347_715, 0) - .saturating_add(Weight::from_parts(0, 11037)) - // Standard Error: 10_944 - .saturating_add(Weight::from_parts(191_321, 0).saturating_mul(r.into())) - // Standard Error: 2_135 - .saturating_add(Weight::from_parts(1_295_872, 0).saturating_mul(s.into())) + // Measured: `469 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` + // Estimated: `11003` + // Minimum execution time: 53_365_000 picoseconds. + Weight::from_parts(35_391_422, 0) + .saturating_add(Weight::from_parts(0, 11003)) + // Standard Error: 1_353 + .saturating_add(Weight::from_parts(1_074_019, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) } - /// Storage: `Identity::Registrars` (r:1 w:0) - /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Storage: Identity Registrars (r:1 w:0) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. fn request_judgement(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `6968 + r * (57 ±0)` - // Estimated: `11037` - // Minimum execution time: 75_780_000 picoseconds. - Weight::from_parts(76_869_773, 0) - .saturating_add(Weight::from_parts(0, 11037)) - // Standard Error: 5_456 - .saturating_add(Weight::from_parts(135_316, 0).saturating_mul(r.into())) + // Measured: `367 + r * (57 ±0) + x * (66 ±0)` + // Estimated: `11003` + // Minimum execution time: 32_509_000 picoseconds. + Weight::from_parts(31_745_585, 0) + .saturating_add(Weight::from_parts(0, 11003)) + // Standard Error: 2_214 + .saturating_add(Weight::from_parts(83_822, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. fn cancel_request(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `6999` - // Estimated: `11037` - // Minimum execution time: 75_769_000 picoseconds. - Weight::from_parts(76_805_143, 0) - .saturating_add(Weight::from_parts(0, 11037)) - // Standard Error: 3_598 - .saturating_add(Weight::from_parts(84_593, 0).saturating_mul(r.into())) + // Measured: `398 + x * (66 ±0)` + // Estimated: `11003` + // Minimum execution time: 29_609_000 picoseconds. + Weight::from_parts(28_572_602, 0) + .saturating_add(Weight::from_parts(0, 11003)) + // Standard Error: 2_528 + .saturating_add(Weight::from_parts(85_593, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Identity::Registrars` (r:1 w:1) - /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn set_fee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 5_357_000 picoseconds. - Weight::from_parts(5_732_132, 0) + // Minimum execution time: 7_793_000 picoseconds. + Weight::from_parts(8_173_888, 0) .saturating_add(Weight::from_parts(0, 2626)) - // Standard Error: 927 - .saturating_add(Weight::from_parts(70_832, 0).saturating_mul(r.into())) + // Standard Error: 1_569 + .saturating_add(Weight::from_parts(72_367, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Identity::Registrars` (r:1 w:1) - /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn set_account_id(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 5_484_000 picoseconds. - Weight::from_parts(5_892_704, 0) + // Minimum execution time: 7_708_000 picoseconds. + Weight::from_parts(8_091_149, 0) .saturating_add(Weight::from_parts(0, 2626)) - // Standard Error: 947 - .saturating_add(Weight::from_parts(71_231, 0).saturating_mul(r.into())) + // Standard Error: 869 + .saturating_add(Weight::from_parts(87_993, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Identity::Registrars` (r:1 w:1) - /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn set_fields(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 5_310_000 picoseconds. - Weight::from_parts(5_766_651, 0) + // Minimum execution time: 7_601_000 picoseconds. + Weight::from_parts(8_038_414, 0) .saturating_add(Weight::from_parts(0, 2626)) - // Standard Error: 916 - .saturating_add(Weight::from_parts(74_776, 0).saturating_mul(r.into())) + // Standard Error: 1_041 + .saturating_add(Weight::from_parts(82_588, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Identity::Registrars` (r:1 w:0) - /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Storage: Identity Registrars (r:1 w:0) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn provide_judgement(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `7046 + r * (57 ±0)` - // Estimated: `11037` - // Minimum execution time: 98_200_000 picoseconds. - Weight::from_parts(100_105_482, 0) - .saturating_add(Weight::from_parts(0, 11037)) - // Standard Error: 6_152 - .saturating_add(Weight::from_parts(58_906, 0).saturating_mul(r.into())) + // Measured: `445 + r * (57 ±0) + x * (66 ±0)` + // Estimated: `11003` + // Minimum execution time: 23_114_000 picoseconds. + Weight::from_parts(22_076_548, 0) + .saturating_add(Weight::from_parts(0, 11003)) + // Standard Error: 2_881 + .saturating_add(Weight::from_parts(109_812, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Identity::SubsOf` (r:1 w:1) - /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Identity::SuperOf` (r:0 w:100) - /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:0 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `s` is `[0, 100]`. fn kill_identity(r: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `7277 + r * (5 ±0) + s * (32 ±0)` - // Estimated: `11037` - // Minimum execution time: 64_647_000 picoseconds. - Weight::from_parts(68_877_027, 0) - .saturating_add(Weight::from_parts(0, 11037)) - // Standard Error: 9_965 - .saturating_add(Weight::from_parts(135_044, 0).saturating_mul(r.into())) - // Standard Error: 1_944 - .saturating_add(Weight::from_parts(1_388_151, 0).saturating_mul(s.into())) + // Measured: `676 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` + // Estimated: `11003` + // Minimum execution time: 70_007_000 picoseconds. + Weight::from_parts(50_186_495, 0) + .saturating_add(Weight::from_parts(0, 11003)) + // Standard Error: 6_533 + .saturating_add(Weight::from_parts(15_486, 0).saturating_mul(r.into())) + // Standard Error: 1_275 + .saturating_add(Weight::from_parts(1_085_117, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) } - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - /// Storage: `Identity::SuperOf` (r:1 w:1) - /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) - /// Storage: `Identity::SubsOf` (r:1 w:1) - /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) /// The range of component `s` is `[0, 99]`. fn add_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `475 + s * (36 ±0)` - // Estimated: `11037` - // Minimum execution time: 23_550_000 picoseconds. - Weight::from_parts(29_439_842, 0) - .saturating_add(Weight::from_parts(0, 11037)) - // Standard Error: 1_453 - .saturating_add(Weight::from_parts(96_324, 0).saturating_mul(s.into())) + // Estimated: `11003` + // Minimum execution time: 28_453_000 picoseconds. + Weight::from_parts(33_165_934, 0) + .saturating_add(Weight::from_parts(0, 11003)) + // Standard Error: 1_217 + .saturating_add(Weight::from_parts(65_401, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - /// Storage: `Identity::SuperOf` (r:1 w:1) - /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `s` is `[1, 100]`. fn rename_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `591 + s * (3 ±0)` - // Estimated: `11037` - // Minimum execution time: 13_704_000 picoseconds. - Weight::from_parts(15_241_441, 0) - .saturating_add(Weight::from_parts(0, 11037)) - // Standard Error: 498 - .saturating_add(Weight::from_parts(40_973, 0).saturating_mul(s.into())) + // Estimated: `11003` + // Minimum execution time: 12_846_000 picoseconds. + Weight::from_parts(14_710_284, 0) + .saturating_add(Weight::from_parts(0, 11003)) + // Standard Error: 496 + .saturating_add(Weight::from_parts(19_539, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - /// Storage: `Identity::SuperOf` (r:1 w:1) - /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) - /// Storage: `Identity::SubsOf` (r:1 w:1) - /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) /// The range of component `s` is `[1, 100]`. fn remove_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `638 + s * (35 ±0)` - // Estimated: `11037` - // Minimum execution time: 29_310_000 picoseconds. - Weight::from_parts(31_712_666, 0) - .saturating_add(Weight::from_parts(0, 11037)) - // Standard Error: 967 - .saturating_add(Weight::from_parts(81_250, 0).saturating_mul(s.into())) + // Estimated: `11003` + // Minimum execution time: 32_183_000 picoseconds. + Weight::from_parts(35_296_731, 0) + .saturating_add(Weight::from_parts(0, 11003)) + // Standard Error: 854 + .saturating_add(Weight::from_parts(52_028, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Identity::SuperOf` (r:1 w:1) - /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) - /// Storage: `Identity::SubsOf` (r:1 w:1) - /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:0) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `s` is `[0, 99]`. fn quit_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `704 + s * (37 ±0)` // Estimated: `6723` - // Minimum execution time: 22_906_000 picoseconds. - Weight::from_parts(24_638_729, 0) + // Minimum execution time: 24_941_000 picoseconds. + Weight::from_parts(27_433_059, 0) .saturating_add(Weight::from_parts(0, 6723)) - // Standard Error: 645 - .saturating_add(Weight::from_parts(75_121, 0).saturating_mul(s.into())) + // Standard Error: 856 + .saturating_add(Weight::from_parts(57_463, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -344,93 +340,90 @@ impl pallet_identity::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_056_000 picoseconds. - Weight::from_parts(6_349_000, 0) + // Minimum execution time: 13_873_000 picoseconds. + Weight::from_parts(13_873_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Identity::UsernameAuthorities` (r:1 w:1) + /// Storage: `Identity::UsernameAuthorities` (r:0 w:1) /// Proof: `Identity::UsernameAuthorities` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn remove_username_authority() -> Weight { // Proof Size summary in bytes: - // Measured: `80` - // Estimated: `3517` - // Minimum execution time: 9_003_000 picoseconds. - Weight::from_parts(9_276_000, 0) - .saturating_add(Weight::from_parts(0, 3517)) - .saturating_add(T::DbWeight::get().reads(1)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_653_000 picoseconds. + Weight::from_parts(10_653_000, 0) + .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Identity::UsernameAuthorities` (r:1 w:1) /// Proof: `Identity::UsernameAuthorities` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) - /// Storage: `Identity::PendingUsernames` (r:1 w:0) - /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) fn set_username_for() -> Weight { // Proof Size summary in bytes: // Measured: `80` // Estimated: `11037` - // Minimum execution time: 64_724_000 picoseconds. - Weight::from_parts(66_597_000, 0) + // Minimum execution time: 75_928_000 picoseconds. + Weight::from_parts(75_928_000, 0) .saturating_add(Weight::from_parts(0, 11037)) - .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Identity::PendingUsernames` (r:1 w:1) - /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(77), added: 2552, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) /// Storage: `Identity::AccountOfUsername` (r:0 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn accept_username() -> Weight { // Proof Size summary in bytes: - // Measured: `115` + // Measured: `106` // Estimated: `11037` - // Minimum execution time: 19_538_000 picoseconds. - Weight::from_parts(20_204_000, 0) + // Minimum execution time: 38_157_000 picoseconds. + Weight::from_parts(38_157_000, 0) .saturating_add(Weight::from_parts(0, 11037)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Identity::PendingUsernames` (r:1 w:1) - /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(77), added: 2552, mode: `MaxEncodedLen`) fn remove_expired_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `115` - // Estimated: `3550` - // Minimum execution time: 16_000_000 picoseconds. - Weight::from_parts(19_354_000, 0) - .saturating_add(Weight::from_parts(0, 3550)) + // Measured: `106` + // Estimated: `3542` + // Minimum execution time: 46_821_000 picoseconds. + Weight::from_parts(46_821_000, 0) + .saturating_add(Weight::from_parts(0, 3542)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Identity::AccountOfUsername` (r:1 w:0) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) fn set_primary_username() -> Weight { // Proof Size summary in bytes: - // Measured: `257` + // Measured: `247` // Estimated: `11037` - // Minimum execution time: 15_298_000 picoseconds. - Weight::from_parts(15_760_000, 0) + // Minimum execution time: 22_515_000 picoseconds. + Weight::from_parts(22_515_000, 0) .saturating_add(Weight::from_parts(0, 11037)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:0) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) fn remove_dangling_username() -> Weight { // Proof Size summary in bytes: - // Measured: `98` + // Measured: `126` // Estimated: `11037` - // Minimum execution time: 10_829_000 picoseconds. - Weight::from_parts(11_113_000, 0) + // Minimum execution time: 15_997_000 picoseconds. + Weight::from_parts(15_997_000, 0) .saturating_add(Weight::from_parts(0, 11037)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/polkadot/runtime/rococo/src/weights/pallet_indices.rs b/polkadot/runtime/rococo/src/weights/pallet_indices.rs index 434db97d4a7..99ffd3210ed 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_indices.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_indices.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_indices` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: // ./target/production/polkadot @@ -29,15 +29,12 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --pallet=pallet_indices // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,66 +47,66 @@ use core::marker::PhantomData; /// Weight functions for `pallet_indices`. pub struct WeightInfo(PhantomData); impl pallet_indices::WeightInfo for WeightInfo { - /// Storage: `Indices::Accounts` (r:1 w:1) - /// Proof: `Indices::Accounts` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: Indices Accounts (r:1 w:1) + /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn claim() -> Weight { // Proof Size summary in bytes: - // Measured: `4` + // Measured: `142` // Estimated: `3534` - // Minimum execution time: 18_092_000 picoseconds. - Weight::from_parts(18_533_000, 0) + // Minimum execution time: 25_107_000 picoseconds. + Weight::from_parts(25_655_000, 0) .saturating_add(Weight::from_parts(0, 3534)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Indices::Accounts` (r:1 w:1) - /// Proof: `Indices::Accounts` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Indices Accounts (r:1 w:1) + /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `203` + // Measured: `341` // Estimated: `3593` - // Minimum execution time: 31_616_000 picoseconds. - Weight::from_parts(32_556_000, 0) + // Minimum execution time: 36_208_000 picoseconds. + Weight::from_parts(36_521_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Indices::Accounts` (r:1 w:1) - /// Proof: `Indices::Accounts` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: Indices Accounts (r:1 w:1) + /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn free() -> Weight { // Proof Size summary in bytes: - // Measured: `100` + // Measured: `238` // Estimated: `3534` - // Minimum execution time: 19_593_000 picoseconds. - Weight::from_parts(20_100_000, 0) + // Minimum execution time: 25_915_000 picoseconds. + Weight::from_parts(26_220_000, 0) .saturating_add(Weight::from_parts(0, 3534)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Indices::Accounts` (r:1 w:1) - /// Proof: `Indices::Accounts` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Indices Accounts (r:1 w:1) + /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `203` + // Measured: `341` // Estimated: `3593` - // Minimum execution time: 21_429_000 picoseconds. - Weight::from_parts(22_146_000, 0) + // Minimum execution time: 28_232_000 picoseconds. + Weight::from_parts(28_845_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Indices::Accounts` (r:1 w:1) - /// Proof: `Indices::Accounts` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: Indices Accounts (r:1 w:1) + /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn freeze() -> Weight { // Proof Size summary in bytes: - // Measured: `100` + // Measured: `238` // Estimated: `3534` - // Minimum execution time: 20_425_000 picoseconds. - Weight::from_parts(21_023_000, 0) + // Minimum execution time: 27_282_000 picoseconds. + Weight::from_parts(27_754_000, 0) .saturating_add(Weight::from_parts(0, 3534)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/polkadot/runtime/rococo/src/weights/pallet_message_queue.rs b/polkadot/runtime/rococo/src/weights/pallet_message_queue.rs index 6ebfcd060b6..e1e360d374a 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_message_queue.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_message_queue.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_message_queue` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: // ./target/production/polkadot @@ -29,15 +29,12 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --pallet=pallet_message_queue // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,149 +47,150 @@ use core::marker::PhantomData; /// Weight functions for `pallet_message_queue`. pub struct WeightInfo(PhantomData); impl pallet_message_queue::WeightInfo for WeightInfo { - /// Storage: `MessageQueue::ServiceHead` (r:1 w:0) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(6), added: 501, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::BookStateFor` (r:2 w:2) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(6), added: 501, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) fn ready_ring_knit() -> Weight { // Proof Size summary in bytes: - // Measured: `281` + // Measured: `248` // Estimated: `6050` - // Minimum execution time: 12_830_000 picoseconds. - Weight::from_parts(13_476_000, 0) + // Minimum execution time: 12_106_000 picoseconds. + Weight::from_parts(12_387_000, 0) .saturating_add(Weight::from_parts(0, 6050)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `MessageQueue::BookStateFor` (r:2 w:2) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(6), added: 501, mode: `MaxEncodedLen`) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(6), added: 501, mode: MaxEncodedLen) fn ready_ring_unknit() -> Weight { // Proof Size summary in bytes: - // Measured: `281` + // Measured: `248` // Estimated: `6050` - // Minimum execution time: 11_583_000 picoseconds. - Weight::from_parts(11_902_000, 0) + // Minimum execution time: 11_227_000 picoseconds. + Weight::from_parts(11_616_000, 0) .saturating_add(Weight::from_parts(0, 6050)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) fn service_queue_base() -> Weight { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3520` - // Minimum execution time: 3_801_000 picoseconds. - Weight::from_parts(3_943_000, 0) + // Minimum execution time: 5_052_000 picoseconds. + Weight::from_parts(5_216_000, 0) .saturating_add(Weight::from_parts(0, 3520)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `MessageQueue::Pages` (r:1 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(32818), added: 35293, mode: `MaxEncodedLen`) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(32818), added: 35293, mode: MaxEncodedLen) fn service_page_base_completion() -> Weight { // Proof Size summary in bytes: // Measured: `115` // Estimated: `36283` - // Minimum execution time: 5_517_000 picoseconds. - Weight::from_parts(5_861_000, 0) + // Minimum execution time: 6_522_000 picoseconds. + Weight::from_parts(6_794_000, 0) .saturating_add(Weight::from_parts(0, 36283)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `MessageQueue::Pages` (r:1 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(32818), added: 35293, mode: `MaxEncodedLen`) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(32818), added: 35293, mode: MaxEncodedLen) fn service_page_base_no_completion() -> Weight { // Proof Size summary in bytes: // Measured: `115` // Estimated: `36283` - // Minimum execution time: 5_870_000 picoseconds. - Weight::from_parts(6_028_000, 0) + // Minimum execution time: 6_918_000 picoseconds. + Weight::from_parts(7_083_000, 0) .saturating_add(Weight::from_parts(0, 36283)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `MessageQueue::BookStateFor` (r:0 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(32818), added: 35293, mode: `MaxEncodedLen`) fn service_page_item() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 80_681_000 picoseconds. - Weight::from_parts(81_818_000, 0) + // Minimum execution time: 28_445_000 picoseconds. + Weight::from_parts(28_659_000, 0) .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(6), added: 501, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:0) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(6), added: 501, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:1 w:0) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) fn bump_service_head() -> Weight { // Proof Size summary in bytes: - // Measured: `220` + // Measured: `149` // Estimated: `3520` - // Minimum execution time: 8_641_000 picoseconds. - Weight::from_parts(8_995_000, 0) + // Minimum execution time: 7_224_000 picoseconds. + Weight::from_parts(7_441_000, 0) .saturating_add(Weight::from_parts(0, 3520)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:1 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(32818), added: 35293, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Proof: UNKNOWN KEY `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Storage: UNKNOWN KEY `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - /// Proof: UNKNOWN KEY `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(32818), added: 35293, mode: MaxEncodedLen) + /// Storage: Configuration ActiveConfig (r:1 w:0) + /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) + /// Proof Skipped: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) + /// Storage: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) + /// Proof Skipped: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) fn reap_page() -> Weight { // Proof Size summary in bytes: - // Measured: `32945` + // Measured: `33232` // Estimated: `36283` - // Minimum execution time: 38_473_000 picoseconds. - Weight::from_parts(39_831_000, 0) + // Minimum execution time: 45_211_000 picoseconds. + Weight::from_parts(45_505_000, 0) .saturating_add(Weight::from_parts(0, 36283)) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:1 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(32818), added: 35293, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Proof: UNKNOWN KEY `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Storage: UNKNOWN KEY `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - /// Proof: UNKNOWN KEY `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(32818), added: 35293, mode: MaxEncodedLen) + /// Storage: Configuration ActiveConfig (r:1 w:0) + /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) + /// Proof Skipped: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) + /// Storage: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) + /// Proof Skipped: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) fn execute_overweight_page_removed() -> Weight { // Proof Size summary in bytes: - // Measured: `32945` + // Measured: `33232` // Estimated: `36283` - // Minimum execution time: 48_717_000 picoseconds. - Weight::from_parts(49_724_000, 0) + // Minimum execution time: 52_346_000 picoseconds. + Weight::from_parts(52_745_000, 0) .saturating_add(Weight::from_parts(0, 36283)) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:1 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(32818), added: 35293, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Proof: UNKNOWN KEY `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Storage: UNKNOWN KEY `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - /// Proof: UNKNOWN KEY `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(32818), added: 35293, mode: MaxEncodedLen) + /// Storage: Configuration ActiveConfig (r:1 w:0) + /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) + /// Proof Skipped: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) + /// Storage: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) + /// Proof Skipped: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) fn execute_overweight_page_updated() -> Weight { // Proof Size summary in bytes: - // Measured: `32945` + // Measured: `33232` // Estimated: `36283` - // Minimum execution time: 72_718_000 picoseconds. - Weight::from_parts(74_081_000, 0) + // Minimum execution time: 72_567_000 picoseconds. + Weight::from_parts(73_300_000, 0) .saturating_add(Weight::from_parts(0, 36283)) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_multisig.rs b/polkadot/runtime/rococo/src/weights/pallet_multisig.rs index f1b81759ece..a4f33fe198c 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_multisig.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_multisig.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_multisig` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: // ./target/production/polkadot @@ -29,15 +29,12 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --pallet=pallet_multisig // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -55,110 +52,110 @@ impl pallet_multisig::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 12_023_000 picoseconds. - Weight::from_parts(12_643_116, 0) + // Minimum execution time: 11_475_000 picoseconds. + Weight::from_parts(11_904_745, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 3 - .saturating_add(Weight::from_parts(582, 0).saturating_mul(z.into())) + // Standard Error: 1 + .saturating_add(Weight::from_parts(492, 0).saturating_mul(z.into())) } - /// Storage: `Multisig::Multisigs` (r:1 w:1) - /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_create(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `229 + s * (2 ±0)` + // Measured: `193 + s * (2 ±0)` // Estimated: `6811` - // Minimum execution time: 39_339_000 picoseconds. - Weight::from_parts(27_243_033, 0) + // Minimum execution time: 38_857_000 picoseconds. + Weight::from_parts(33_611_791, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_319 - .saturating_add(Weight::from_parts(142_212, 0).saturating_mul(s.into())) - // Standard Error: 12 - .saturating_add(Weight::from_parts(1_592, 0).saturating_mul(z.into())) + // Standard Error: 400 + .saturating_add(Weight::from_parts(59_263, 0).saturating_mul(s.into())) + // Standard Error: 3 + .saturating_add(Weight::from_parts(1_211, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Multisig::Multisigs` (r:1 w:1) - /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[3, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_approve(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `248` + // Measured: `211` // Estimated: `6811` - // Minimum execution time: 27_647_000 picoseconds. - Weight::from_parts(15_828_725, 0) + // Minimum execution time: 25_715_000 picoseconds. + Weight::from_parts(20_607_294, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 908 - .saturating_add(Weight::from_parts(130_880, 0).saturating_mul(s.into())) - // Standard Error: 8 - .saturating_add(Weight::from_parts(1_532, 0).saturating_mul(z.into())) + // Standard Error: 285 + .saturating_add(Weight::from_parts(58_225, 0).saturating_mul(s.into())) + // Standard Error: 2 + .saturating_add(Weight::from_parts(1_160, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Multisig::Multisigs` (r:1 w:1) - /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_complete(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `354 + s * (33 ±0)` + // Measured: `317 + s * (33 ±0)` // Estimated: `6811` - // Minimum execution time: 46_971_000 picoseconds. - Weight::from_parts(32_150_393, 0) + // Minimum execution time: 43_751_000 picoseconds. + Weight::from_parts(37_398_513, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_129 - .saturating_add(Weight::from_parts(154_796, 0).saturating_mul(s.into())) - // Standard Error: 11 - .saturating_add(Weight::from_parts(1_603, 0).saturating_mul(z.into())) + // Standard Error: 426 + .saturating_add(Weight::from_parts(70_904, 0).saturating_mul(s.into())) + // Standard Error: 4 + .saturating_add(Weight::from_parts(1_235, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Multisig::Multisigs` (r:1 w:1) - /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. fn approve_as_multi_create(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `229 + s * (2 ±0)` + // Measured: `193 + s * (2 ±0)` // Estimated: `6811` - // Minimum execution time: 24_947_000 picoseconds. - Weight::from_parts(26_497_183, 0) + // Minimum execution time: 31_278_000 picoseconds. + Weight::from_parts(32_075_573, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_615 - .saturating_add(Weight::from_parts(147_071, 0).saturating_mul(s.into())) + // Standard Error: 452 + .saturating_add(Weight::from_parts(62_018, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Multisig::Multisigs` (r:1 w:1) - /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. fn approve_as_multi_approve(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `248` + // Measured: `211` // Estimated: `6811` - // Minimum execution time: 13_897_000 picoseconds. - Weight::from_parts(14_828_339, 0) + // Minimum execution time: 18_178_000 picoseconds. + Weight::from_parts(18_649_867, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 1_136 - .saturating_add(Weight::from_parts(133_925, 0).saturating_mul(s.into())) + // Standard Error: 293 + .saturating_add(Weight::from_parts(56_475, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Multisig::Multisigs` (r:1 w:1) - /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. fn cancel_as_multi(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `420 + s * (1 ±0)` + // Measured: `383 + s * (1 ±0)` // Estimated: `6811` - // Minimum execution time: 28_984_000 picoseconds. - Weight::from_parts(29_853_232, 0) + // Minimum execution time: 32_265_000 picoseconds. + Weight::from_parts(32_984_014, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 650 - .saturating_add(Weight::from_parts(113_440, 0).saturating_mul(s.into())) + // Standard Error: 452 + .saturating_add(Weight::from_parts(59_934, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/rococo/src/weights/pallet_nis.rs b/polkadot/runtime/rococo/src/weights/pallet_nis.rs index 38b41f3a8e2..35dad482129 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_nis.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_nis.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_nis` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: // ./target/production/polkadot @@ -29,15 +29,12 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --pallet=pallet_nis // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,186 +47,202 @@ use core::marker::PhantomData; /// Weight functions for `pallet_nis`. pub struct WeightInfo(PhantomData); impl pallet_nis::WeightInfo for WeightInfo { - /// Storage: `Nis::Queues` (r:1 w:1) - /// Proof: `Nis::Queues` (`max_values`: None, `max_size`: Some(48022), added: 50497, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) - /// Storage: `Nis::QueueTotals` (r:1 w:1) - /// Proof: `Nis::QueueTotals` (`max_values`: Some(1), `max_size`: Some(6002), added: 6497, mode: `MaxEncodedLen`) + /// Storage: Nis Queues (r:1 w:1) + /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(67), added: 2542, mode: MaxEncodedLen) + /// Storage: Nis QueueTotals (r:1 w:1) + /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) /// The range of component `l` is `[0, 999]`. fn place_bid(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `6209 + l * (48 ±0)` // Estimated: `51487` - // Minimum execution time: 39_592_000 picoseconds. - Weight::from_parts(38_234_037, 0) + // Minimum execution time: 44_704_000 picoseconds. + Weight::from_parts(44_933_886, 0) .saturating_add(Weight::from_parts(0, 51487)) - // Standard Error: 1_237 - .saturating_add(Weight::from_parts(88_816, 0).saturating_mul(l.into())) + // Standard Error: 712 + .saturating_add(Weight::from_parts(71_570, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `Nis::Queues` (r:1 w:1) - /// Proof: `Nis::Queues` (`max_values`: None, `max_size`: Some(48022), added: 50497, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) - /// Storage: `Nis::QueueTotals` (r:1 w:1) - /// Proof: `Nis::QueueTotals` (`max_values`: Some(1), `max_size`: Some(6002), added: 6497, mode: `MaxEncodedLen`) + /// Storage: Nis Queues (r:1 w:1) + /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(67), added: 2542, mode: MaxEncodedLen) + /// Storage: Nis QueueTotals (r:1 w:1) + /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) fn place_bid_max() -> Weight { // Proof Size summary in bytes: // Measured: `54211` // Estimated: `51487` - // Minimum execution time: 134_847_000 picoseconds. - Weight::from_parts(139_510_000, 0) + // Minimum execution time: 126_544_000 picoseconds. + Weight::from_parts(128_271_000, 0) .saturating_add(Weight::from_parts(0, 51487)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `Nis::Queues` (r:1 w:1) - /// Proof: `Nis::Queues` (`max_values`: None, `max_size`: Some(48022), added: 50497, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) - /// Storage: `Nis::QueueTotals` (r:1 w:1) - /// Proof: `Nis::QueueTotals` (`max_values`: Some(1), `max_size`: Some(6002), added: 6497, mode: `MaxEncodedLen`) + /// Storage: Nis Queues (r:1 w:1) + /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(67), added: 2542, mode: MaxEncodedLen) + /// Storage: Nis QueueTotals (r:1 w:1) + /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) /// The range of component `l` is `[1, 1000]`. fn retract_bid(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `6209 + l * (48 ±0)` // Estimated: `51487` - // Minimum execution time: 43_330_000 picoseconds. - Weight::from_parts(35_097_881, 0) + // Minimum execution time: 47_640_000 picoseconds. + Weight::from_parts(42_214_261, 0) .saturating_add(Weight::from_parts(0, 51487)) - // Standard Error: 1_119 - .saturating_add(Weight::from_parts(73_640, 0).saturating_mul(l.into())) + // Standard Error: 732 + .saturating_add(Weight::from_parts(87_277, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `Nis::Summary` (r:1 w:0) - /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Nis Summary (r:1 w:0) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: Balances InactiveIssuance (r:1 w:0) + /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn fund_deficit() -> Weight { // Proof Size summary in bytes: // Measured: `225` // Estimated: `3593` - // Minimum execution time: 29_989_000 picoseconds. - Weight::from_parts(30_865_000, 0) + // Minimum execution time: 38_031_000 picoseconds. + Weight::from_parts(38_441_000, 0) .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Nis::Receipts` (r:1 w:1) - /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Nis::Summary` (r:1 w:1) - /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) - /// Storage: `NisCounterpartBalances::Account` (r:1 w:1) - /// Proof: `NisCounterpartBalances::Account` (`max_values`: None, `max_size`: Some(112), added: 2587, mode: `MaxEncodedLen`) + /// Storage: Nis Receipts (r:1 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(67), added: 2542, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: NisCounterpartBalances TotalIssuance (r:1 w:1) + /// Proof: NisCounterpartBalances TotalIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: NisCounterpartBalances Account (r:1 w:1) + /// Proof: NisCounterpartBalances Account (max_values: None, max_size: Some(112), added: 2587, mode: MaxEncodedLen) fn communify() -> Weight { // Proof Size summary in bytes: - // Measured: `387` + // Measured: `469` // Estimated: `3593` - // Minimum execution time: 58_114_000 picoseconds. - Weight::from_parts(59_540_000, 0) + // Minimum execution time: 69_269_000 picoseconds. + Weight::from_parts(70_000_000, 0) .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(6)) } - /// Storage: `Nis::Receipts` (r:1 w:1) - /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) - /// Storage: `Nis::Summary` (r:1 w:1) - /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `NisCounterpartBalances::Account` (r:1 w:1) - /// Proof: `NisCounterpartBalances::Account` (`max_values`: None, `max_size`: Some(112), added: 2587, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) + /// Storage: Nis Receipts (r:1 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: Balances InactiveIssuance (r:1 w:0) + /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: NisCounterpartBalances Account (r:1 w:1) + /// Proof: NisCounterpartBalances Account (max_values: None, max_size: Some(112), added: 2587, mode: MaxEncodedLen) + /// Storage: NisCounterpartBalances TotalIssuance (r:1 w:1) + /// Proof: NisCounterpartBalances TotalIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(67), added: 2542, mode: MaxEncodedLen) fn privatize() -> Weight { // Proof Size summary in bytes: - // Measured: `543` + // Measured: `659` // Estimated: `3593` - // Minimum execution time: 75_780_000 picoseconds. - Weight::from_parts(77_097_000, 0) + // Minimum execution time: 85_763_000 picoseconds. + Weight::from_parts(86_707_000, 0) .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(6)) } - /// Storage: `Nis::Receipts` (r:1 w:1) - /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) - /// Storage: `Nis::Summary` (r:1 w:1) - /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:0) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) + /// Storage: Nis Receipts (r:1 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: Balances InactiveIssuance (r:1 w:0) + /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(67), added: 2542, mode: MaxEncodedLen) fn thaw_private() -> Weight { // Proof Size summary in bytes: // Measured: `387` // Estimated: `3593` - // Minimum execution time: 46_133_000 picoseconds. - Weight::from_parts(47_250_000, 0) + // Minimum execution time: 47_336_000 picoseconds. + Weight::from_parts(47_623_000, 0) .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `Nis::Receipts` (r:1 w:1) - /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) - /// Storage: `Nis::Summary` (r:1 w:1) - /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) - /// Storage: `NisCounterpartBalances::Account` (r:1 w:1) - /// Proof: `NisCounterpartBalances::Account` (`max_values`: None, `max_size`: Some(112), added: 2587, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Nis Receipts (r:1 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: NisCounterpartBalances Account (r:1 w:1) + /// Proof: NisCounterpartBalances Account (max_values: None, max_size: Some(112), added: 2587, mode: MaxEncodedLen) + /// Storage: NisCounterpartBalances TotalIssuance (r:1 w:1) + /// Proof: NisCounterpartBalances TotalIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Balances InactiveIssuance (r:1 w:0) + /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn thaw_communal() -> Weight { // Proof Size summary in bytes: - // Measured: `488` + // Measured: `604` // Estimated: `3593` - // Minimum execution time: 77_916_000 picoseconds. - Weight::from_parts(79_427_000, 0) + // Minimum execution time: 90_972_000 picoseconds. + Weight::from_parts(92_074_000, 0) .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(5)) } - /// Storage: `Nis::Summary` (r:1 w:1) - /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:0) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Nis::QueueTotals` (r:1 w:1) - /// Proof: `Nis::QueueTotals` (`max_values`: Some(1), `max_size`: Some(6002), added: 6497, mode: `MaxEncodedLen`) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: Balances InactiveIssuance (r:1 w:0) + /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Nis QueueTotals (r:1 w:1) + /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) fn process_queues() -> Weight { // Proof Size summary in bytes: // Measured: `6658` // Estimated: `7487` - // Minimum execution time: 22_992_000 picoseconds. - Weight::from_parts(24_112_000, 0) + // Minimum execution time: 21_469_000 picoseconds. + Weight::from_parts(21_983_000, 0) .saturating_add(Weight::from_parts(0, 7487)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Nis::Queues` (r:1 w:1) - /// Proof: `Nis::Queues` (`max_values`: None, `max_size`: Some(48022), added: 50497, mode: `MaxEncodedLen`) + /// Storage: Nis Queues (r:1 w:1) + /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) fn process_queue() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `51487` - // Minimum execution time: 3_856_000 picoseconds. - Weight::from_parts(4_125_000, 0) + // Minimum execution time: 4_912_000 picoseconds. + Weight::from_parts(5_013_000, 0) .saturating_add(Weight::from_parts(0, 51487)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Nis::Receipts` (r:0 w:1) - /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Storage: Nis Receipts (r:0 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) fn process_bid() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_344_000 picoseconds. - Weight::from_parts(4_545_000, 0) + // Minimum execution time: 7_048_000 picoseconds. + Weight::from_parts(7_278_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/rococo/src/weights/pallet_preimage.rs b/polkadot/runtime/rococo/src/weights/pallet_preimage.rs index 7a2b77b84d8..e051ebd5bba 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_preimage.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_preimage.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_preimage` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: // ./target/production/polkadot @@ -29,15 +29,12 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --pallet=pallet_preimage // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,219 +47,184 @@ use core::marker::PhantomData; /// Weight functions for `pallet_preimage`. pub struct WeightInfo(PhantomData); impl pallet_preimage::WeightInfo for WeightInfo { - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) - /// Storage: `Preimage::PreimageFor` (r:0 w:1) - /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) + fn ensure_updated(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `193 + n * (91 ±0)` + // Estimated: `3593 + n * (2566 ±0)` + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 3593) + // Standard Error: 13_720 + .saturating_add(Weight::from_parts(17_309_199, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2566).saturating_mul(n.into())) + } + + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) /// The range of component `s` is `[0, 4194304]`. fn note_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `114` - // Estimated: `3568` - // Minimum execution time: 40_363_000 picoseconds. - Weight::from_parts(41_052_000, 0) - .saturating_add(Weight::from_parts(0, 3568)) - // Standard Error: 6 - .saturating_add(Weight::from_parts(2_298, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) + // Measured: `215` + // Estimated: `3556` + // Minimum execution time: 31_040_000 picoseconds. + Weight::from_parts(31_236_000, 0) + .saturating_add(Weight::from_parts(0, 3556)) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_974, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::PreimageFor` (r:0 w:1) - /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) /// The range of component `s` is `[0, 4194304]`. fn note_requested_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `178` // Estimated: `3556` - // Minimum execution time: 14_570_000 picoseconds. - Weight::from_parts(14_890_000, 0) + // Minimum execution time: 18_025_000 picoseconds. + Weight::from_parts(18_264_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - // Standard Error: 2 - .saturating_add(Weight::from_parts(2_364, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2)) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_974, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::PreimageFor` (r:0 w:1) - /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) /// The range of component `s` is `[0, 4194304]`. fn note_no_deposit_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `178` // Estimated: `3556` - // Minimum execution time: 13_933_000 picoseconds. - Weight::from_parts(14_290_000, 0) + // Minimum execution time: 17_122_000 picoseconds. + Weight::from_parts(17_332_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - // Standard Error: 2 - .saturating_add(Weight::from_parts(2_349, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2)) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_968, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) - /// Storage: `Preimage::PreimageFor` (r:0 w:1) - /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) fn unnote_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `315` - // Estimated: `3568` - // Minimum execution time: 54_373_000 picoseconds. - Weight::from_parts(58_205_000, 0) - .saturating_add(Weight::from_parts(0, 3568)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) + // Measured: `361` + // Estimated: `3556` + // Minimum execution time: 38_218_000 picoseconds. + Weight::from_parts(39_841_000, 0) + .saturating_add(Weight::from_parts(0, 3556)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::PreimageFor` (r:0 w:1) - /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) fn unnote_no_deposit_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `216` // Estimated: `3556` - // Minimum execution time: 24_267_000 picoseconds. - Weight::from_parts(27_063_000, 0) + // Minimum execution time: 23_217_000 picoseconds. + Weight::from_parts(24_246_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn request_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `260` // Estimated: `3556` - // Minimum execution time: 25_569_000 picoseconds. - Weight::from_parts(27_895_000, 0) + // Minimum execution time: 21_032_000 picoseconds. + Weight::from_parts(21_844_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn request_no_deposit_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `216` // Estimated: `3556` - // Minimum execution time: 14_182_000 picoseconds. - Weight::from_parts(16_098_000, 0) + // Minimum execution time: 13_954_000 picoseconds. + Weight::from_parts(14_501_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn request_unnoted_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `114` // Estimated: `3556` - // Minimum execution time: 14_681_000 picoseconds. - Weight::from_parts(15_549_000, 0) + // Minimum execution time: 14_874_000 picoseconds. + Weight::from_parts(15_380_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn request_requested_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `178` // Estimated: `3556` - // Minimum execution time: 9_577_000 picoseconds. - Weight::from_parts(10_146_000, 0) + // Minimum execution time: 10_199_000 picoseconds. + Weight::from_parts(10_493_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::PreimageFor` (r:0 w:1) - /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:0 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) fn unrequest_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `216` // Estimated: `3556` - // Minimum execution time: 21_003_000 picoseconds. - Weight::from_parts(23_549_000, 0) + // Minimum execution time: 21_772_000 picoseconds. + Weight::from_parts(22_554_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn unrequest_unnoted_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `178` // Estimated: `3556` - // Minimum execution time: 9_507_000 picoseconds. - Weight::from_parts(10_013_000, 0) + // Minimum execution time: 10_115_000 picoseconds. + Weight::from_parts(10_452_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn unrequest_multi_referenced_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `178` // Estimated: `3556` - // Minimum execution time: 9_293_000 picoseconds. - Weight::from_parts(10_055_000, 0) + // Minimum execution time: 10_031_000 picoseconds. + Weight::from_parts(10_310_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Preimage::StatusFor` (r:1023 w:1023) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1023 w:1023) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1023 w:1023) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:0 w:1023) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// The range of component `n` is `[1, 1024]`. - fn ensure_updated(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + n * (227 ±0)` - // Estimated: `990 + n * (2603 ±0)` - // Minimum execution time: 48_846_000 picoseconds. - Weight::from_parts(49_378_000, 0) - .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 38_493 - .saturating_add(Weight::from_parts(47_418_285, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes((4_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2603).saturating_mul(n.into())) - } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_proxy.rs b/polkadot/runtime/rococo/src/weights/pallet_proxy.rs index c9202593095..d9737a85c05 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_proxy.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_proxy.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_proxy` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: // ./target/production/polkadot @@ -29,15 +29,12 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --pallet=pallet_proxy // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,176 +47,172 @@ use core::marker::PhantomData; /// Weight functions for `pallet_proxy`. pub struct WeightInfo(PhantomData); impl pallet_proxy::WeightInfo for WeightInfo { - /// Storage: `Proxy::Proxies` (r:1 w:0) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: Proxy Proxies (r:1 w:0) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `89 + p * (37 ±0)` + // Measured: `227 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 11_267_000 picoseconds. - Weight::from_parts(11_798_007, 0) + // Minimum execution time: 15_956_000 picoseconds. + Weight::from_parts(16_300_358, 0) .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 858 - .saturating_add(Weight::from_parts(43_735, 0).saturating_mul(p.into())) + // Standard Error: 652 + .saturating_add(Weight::from_parts(30_807, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) } - /// Storage: `Proxy::Proxies` (r:1 w:0) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) - /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Proxy Proxies (r:1 w:0) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn proxy_announced(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `416 + a * (68 ±0) + p * (37 ±0)` + // Measured: `554 + a * (68 ±0) + p * (37 ±0)` // Estimated: `5698` - // Minimum execution time: 32_791_000 picoseconds. - Weight::from_parts(32_776_904, 0) + // Minimum execution time: 37_584_000 picoseconds. + Weight::from_parts(37_858_207, 0) .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 2_382 - .saturating_add(Weight::from_parts(143_857, 0).saturating_mul(a.into())) - // Standard Error: 2_461 - .saturating_add(Weight::from_parts(40_024, 0).saturating_mul(p.into())) + // Standard Error: 1_868 + .saturating_add(Weight::from_parts(148_967, 0).saturating_mul(a.into())) + // Standard Error: 1_930 + .saturating_add(Weight::from_parts(13_017, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. - fn remove_announcement(a: u32, p: u32, ) -> Weight { + fn remove_announcement(a: u32, _p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `331 + a * (68 ±0)` + // Measured: `469 + a * (68 ±0)` // Estimated: `5698` - // Minimum execution time: 21_831_000 picoseconds. - Weight::from_parts(22_479_938, 0) + // Minimum execution time: 24_642_000 picoseconds. + Weight::from_parts(25_526_588, 0) .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 1_738 - .saturating_add(Weight::from_parts(146_532, 0).saturating_mul(a.into())) - // Standard Error: 1_796 - .saturating_add(Weight::from_parts(7_499, 0).saturating_mul(p.into())) + // Standard Error: 1_138 + .saturating_add(Weight::from_parts(131_157, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. - fn reject_announcement(a: u32, p: u32, ) -> Weight { + fn reject_announcement(a: u32, _p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `331 + a * (68 ±0)` + // Measured: `469 + a * (68 ±0)` // Estimated: `5698` - // Minimum execution time: 21_776_000 picoseconds. - Weight::from_parts(22_762_843, 0) + // Minimum execution time: 24_377_000 picoseconds. + Weight::from_parts(25_464_033, 0) .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 1_402 - .saturating_add(Weight::from_parts(137_512, 0).saturating_mul(a.into())) - // Standard Error: 1_449 - .saturating_add(Weight::from_parts(3_645, 0).saturating_mul(p.into())) + // Standard Error: 1_116 + .saturating_add(Weight::from_parts(130_722, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Proxy::Proxies` (r:1 w:0) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) - /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Proxy Proxies (r:1 w:0) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn announce(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `348 + a * (68 ±0) + p * (37 ±0)` + // Measured: `486 + a * (68 ±0) + p * (37 ±0)` // Estimated: `5698` - // Minimum execution time: 29_108_000 picoseconds. - Weight::from_parts(29_508_910, 0) + // Minimum execution time: 34_202_000 picoseconds. + Weight::from_parts(34_610_079, 0) .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 2_268 - .saturating_add(Weight::from_parts(144_770, 0).saturating_mul(a.into())) - // Standard Error: 2_343 - .saturating_add(Weight::from_parts(25_851, 0).saturating_mul(p.into())) + // Standard Error: 1_234 + .saturating_add(Weight::from_parts(134_197, 0).saturating_mul(a.into())) + // Standard Error: 1_275 + .saturating_add(Weight::from_parts(15_970, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn add_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `89 + p * (37 ±0)` + // Measured: `227 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 18_942_000 picoseconds. - Weight::from_parts(19_518_812, 0) + // Minimum execution time: 25_492_000 picoseconds. + Weight::from_parts(25_984_867, 0) .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 1_078 - .saturating_add(Weight::from_parts(46_147, 0).saturating_mul(p.into())) + // Standard Error: 893 + .saturating_add(Weight::from_parts(51_868, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn remove_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `89 + p * (37 ±0)` + // Measured: `227 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 18_993_000 picoseconds. - Weight::from_parts(19_871_741, 0) + // Minimum execution time: 25_492_000 picoseconds. + Weight::from_parts(26_283_445, 0) .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 1_883 - .saturating_add(Weight::from_parts(46_033, 0).saturating_mul(p.into())) + // Standard Error: 1_442 + .saturating_add(Weight::from_parts(53_504, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn remove_proxies(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `89 + p * (37 ±0)` + // Measured: `227 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 17_849_000 picoseconds. - Weight::from_parts(18_776_170, 0) + // Minimum execution time: 22_083_000 picoseconds. + Weight::from_parts(22_688_835, 0) .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 1_239 - .saturating_add(Weight::from_parts(27_960, 0).saturating_mul(p.into())) + // Standard Error: 994 + .saturating_add(Weight::from_parts(32_994, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn create_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `101` + // Measured: `239` // Estimated: `4706` - // Minimum execution time: 20_049_000 picoseconds. - Weight::from_parts(20_881_515, 0) + // Minimum execution time: 27_042_000 picoseconds. + Weight::from_parts(27_624_587, 0) .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 952 - .saturating_add(Weight::from_parts(5_970, 0).saturating_mul(p.into())) + // Standard Error: 671 + .saturating_add(Weight::from_parts(5_888, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[0, 30]`. fn kill_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `126 + p * (37 ±0)` + // Measured: `264 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 18_528_000 picoseconds. - Weight::from_parts(19_384_189, 0) + // Minimum execution time: 23_396_000 picoseconds. + Weight::from_parts(24_003_080, 0) .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 1_106 - .saturating_add(Weight::from_parts(35_698, 0).saturating_mul(p.into())) + // Standard Error: 684 + .saturating_add(Weight::from_parts(29_878, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/rococo/src/weights/pallet_ranked_collective.rs b/polkadot/runtime/rococo/src/weights/pallet_ranked_collective.rs index fa2decb1671..ce9d5fcc0c7 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_ranked_collective.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_ranked_collective.rs @@ -16,26 +16,24 @@ //! Autogenerated weights for `pallet_ranked_collective` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2024-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-grjcggob-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet -// --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_ranked_collective // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_ranked_collective +// --chain=rococo-dev // --header=./polkadot/file_header.txt // --output=./polkadot/runtime/rococo/src/weights/ @@ -62,8 +60,8 @@ impl pallet_ranked_collective::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `42` // Estimated: `3507` - // Minimum execution time: 13_428_000 picoseconds. - Weight::from_parts(14_019_000, 0) + // Minimum execution time: 13_480_000 picoseconds. + Weight::from_parts(13_786_000, 0) .saturating_add(Weight::from_parts(0, 3507)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) @@ -81,11 +79,11 @@ impl pallet_ranked_collective::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `516 + r * (281 ±0)` // Estimated: `3519 + r * (2529 ±0)` - // Minimum execution time: 28_566_000 picoseconds. - Weight::from_parts(29_346_952, 0) + // Minimum execution time: 28_771_000 picoseconds. + Weight::from_parts(29_256_825, 0) .saturating_add(Weight::from_parts(0, 3519)) - // Standard Error: 21_068 - .saturating_add(Weight::from_parts(14_471_237, 0).saturating_mul(r.into())) + // Standard Error: 21_594 + .saturating_add(Weight::from_parts(14_649_527, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(6)) @@ -105,11 +103,11 @@ impl pallet_ranked_collective::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `214 + r * (17 ±0)` // Estimated: `3507` - // Minimum execution time: 16_161_000 picoseconds. - Weight::from_parts(16_981_334, 0) + // Minimum execution time: 16_117_000 picoseconds. + Weight::from_parts(16_978_453, 0) .saturating_add(Weight::from_parts(0, 3507)) - // Standard Error: 4_596 - .saturating_add(Weight::from_parts(313_386, 0).saturating_mul(r.into())) + // Standard Error: 4_511 + .saturating_add(Weight::from_parts(324_261, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -126,11 +124,11 @@ impl pallet_ranked_collective::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `532 + r * (72 ±0)` // Estimated: `3519` - // Minimum execution time: 28_406_000 picoseconds. - Weight::from_parts(31_178_557, 0) + // Minimum execution time: 28_995_000 picoseconds. + Weight::from_parts(31_343_215, 0) .saturating_add(Weight::from_parts(0, 3519)) - // Standard Error: 17_737 - .saturating_add(Weight::from_parts(627_757, 0).saturating_mul(r.into())) + // Standard Error: 16_438 + .saturating_add(Weight::from_parts(637_462, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(6)) } @@ -142,17 +140,15 @@ impl pallet_ranked_collective::WeightInfo for WeightInf /// Proof: `FellowshipCollective::Voting` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn vote() -> Weight { // Proof Size summary in bytes: // Measured: `603` // Estimated: `83866` - // Minimum execution time: 41_164_000 picoseconds. - Weight::from_parts(42_163_000, 0) + // Minimum execution time: 38_820_000 picoseconds. + Weight::from_parts(40_240_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:0) /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) @@ -165,11 +161,11 @@ impl pallet_ranked_collective::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `400 + n * (50 ±0)` // Estimated: `4365 + n * (2540 ±0)` - // Minimum execution time: 13_183_000 picoseconds. - Weight::from_parts(15_604_064, 0) + // Minimum execution time: 12_972_000 picoseconds. + Weight::from_parts(15_829_333, 0) .saturating_add(Weight::from_parts(0, 4365)) - // Standard Error: 2_018 - .saturating_add(Weight::from_parts(1_101_088, 0).saturating_mul(n.into())) + // Standard Error: 1_754 + .saturating_add(Weight::from_parts(1_116_520, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -187,8 +183,8 @@ impl pallet_ranked_collective::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `337` // Estimated: `6048` - // Minimum execution time: 43_603_000 picoseconds. - Weight::from_parts(44_809_000, 0) + // Minimum execution time: 44_601_000 picoseconds. + Weight::from_parts(45_714_000, 0) .saturating_add(Weight::from_parts(0, 6048)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(10)) diff --git a/polkadot/runtime/rococo/src/weights/pallet_recovery.rs b/polkadot/runtime/rococo/src/weights/pallet_recovery.rs deleted file mode 100644 index ed79aa2b1f1..00000000000 --- a/polkadot/runtime/rococo/src/weights/pallet_recovery.rs +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_recovery` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=rococo-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_recovery -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_recovery`. -pub struct WeightInfo(PhantomData); -impl pallet_recovery::WeightInfo for WeightInfo { - /// Storage: `Recovery::Proxy` (r:1 w:0) - /// Proof: `Recovery::Proxy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) - fn as_recovered() -> Weight { - // Proof Size summary in bytes: - // Measured: `215` - // Estimated: `3545` - // Minimum execution time: 7_899_000 picoseconds. - Weight::from_parts(8_205_000, 0) - .saturating_add(Weight::from_parts(0, 3545)) - .saturating_add(T::DbWeight::get().reads(1)) - } - /// Storage: `Recovery::Proxy` (r:0 w:1) - /// Proof: `Recovery::Proxy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) - fn set_recovered() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_258_000 picoseconds. - Weight::from_parts(6_494_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Recovery::Recoverable` (r:1 w:1) - /// Proof: `Recovery::Recoverable` (`max_values`: None, `max_size`: Some(351), added: 2826, mode: `MaxEncodedLen`) - /// The range of component `n` is `[1, 9]`. - fn create_recovery(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `109` - // Estimated: `3816` - // Minimum execution time: 19_369_000 picoseconds. - Weight::from_parts(20_185_132, 0) - .saturating_add(Weight::from_parts(0, 3816)) - // Standard Error: 4_275 - .saturating_add(Weight::from_parts(78_024, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Recovery::Recoverable` (r:1 w:0) - /// Proof: `Recovery::Recoverable` (`max_values`: None, `max_size`: Some(351), added: 2826, mode: `MaxEncodedLen`) - /// Storage: `Recovery::ActiveRecoveries` (r:1 w:1) - /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) - fn initiate_recovery() -> Weight { - // Proof Size summary in bytes: - // Measured: `206` - // Estimated: `3854` - // Minimum execution time: 22_425_000 picoseconds. - Weight::from_parts(23_171_000, 0) - .saturating_add(Weight::from_parts(0, 3854)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Recovery::Recoverable` (r:1 w:0) - /// Proof: `Recovery::Recoverable` (`max_values`: None, `max_size`: Some(351), added: 2826, mode: `MaxEncodedLen`) - /// Storage: `Recovery::ActiveRecoveries` (r:1 w:1) - /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) - /// The range of component `n` is `[1, 9]`. - fn vouch_recovery(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `294 + n * (64 ±0)` - // Estimated: `3854` - // Minimum execution time: 17_308_000 picoseconds. - Weight::from_parts(18_118_782, 0) - .saturating_add(Weight::from_parts(0, 3854)) - // Standard Error: 4_309 - .saturating_add(Weight::from_parts(126_278, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Recovery::Recoverable` (r:1 w:0) - /// Proof: `Recovery::Recoverable` (`max_values`: None, `max_size`: Some(351), added: 2826, mode: `MaxEncodedLen`) - /// Storage: `Recovery::ActiveRecoveries` (r:1 w:0) - /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) - /// Storage: `Recovery::Proxy` (r:1 w:1) - /// Proof: `Recovery::Proxy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) - /// The range of component `n` is `[1, 9]`. - fn claim_recovery(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `326 + n * (64 ±0)` - // Estimated: `3854` - // Minimum execution time: 20_755_000 picoseconds. - Weight::from_parts(21_821_713, 0) - .saturating_add(Weight::from_parts(0, 3854)) - // Standard Error: 4_550 - .saturating_add(Weight::from_parts(101_916, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Recovery::ActiveRecoveries` (r:1 w:1) - /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// The range of component `n` is `[1, 9]`. - fn close_recovery(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `447 + n * (32 ±0)` - // Estimated: `3854` - // Minimum execution time: 29_957_000 picoseconds. - Weight::from_parts(31_010_309, 0) - .saturating_add(Weight::from_parts(0, 3854)) - // Standard Error: 5_913 - .saturating_add(Weight::from_parts(110_070, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `Recovery::ActiveRecoveries` (r:1 w:0) - /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) - /// Storage: `Recovery::Recoverable` (r:1 w:1) - /// Proof: `Recovery::Recoverable` (`max_values`: None, `max_size`: Some(351), added: 2826, mode: `MaxEncodedLen`) - /// The range of component `n` is `[1, 9]`. - fn remove_recovery(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `204 + n * (32 ±0)` - // Estimated: `3854` - // Minimum execution time: 24_430_000 picoseconds. - Weight::from_parts(24_462_856, 0) - .saturating_add(Weight::from_parts(0, 3854)) - // Standard Error: 13_646 - .saturating_add(Weight::from_parts(507_715, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Recovery::Proxy` (r:1 w:1) - /// Proof: `Recovery::Proxy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) - fn cancel_recovered() -> Weight { - // Proof Size summary in bytes: - // Measured: `215` - // Estimated: `3545` - // Minimum execution time: 9_686_000 picoseconds. - Weight::from_parts(10_071_000, 0) - .saturating_add(Weight::from_parts(0, 3545)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/rococo/src/weights/pallet_referenda_fellowship_referenda.rs b/polkadot/runtime/rococo/src/weights/pallet_referenda_fellowship_referenda.rs index 6dfcea2b832..96f172230e1 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_referenda_fellowship_referenda.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_referenda_fellowship_referenda.rs @@ -16,28 +16,27 @@ //! Autogenerated weights for `pallet_referenda` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `runner-xerhrdyb-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: `Some(Wasm)`, WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet -// --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_referenda // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --pallet=pallet_referenda +// --chain=rococo-dev +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -60,10 +59,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) fn submit() -> Weight { // Proof Size summary in bytes: - // Measured: `292` + // Measured: `327` // Estimated: `42428` - // Minimum execution time: 24_053_000 picoseconds. - Weight::from_parts(25_121_000, 0) + // Minimum execution time: 29_909_000 picoseconds. + Weight::from_parts(30_645_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) @@ -72,17 +71,15 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_preparing() -> Weight { // Proof Size summary in bytes: - // Measured: `403` + // Measured: `438` // Estimated: `83866` - // Minimum execution time: 45_064_000 picoseconds. - Weight::from_parts(46_112_000, 0) + // Minimum execution time: 54_405_000 picoseconds. + Weight::from_parts(55_583_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) @@ -92,17 +89,15 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `2041` + // Measured: `2076` // Estimated: `42428` - // Minimum execution time: 94_146_000 picoseconds. - Weight::from_parts(98_587_000, 0) + // Minimum execution time: 110_477_000 picoseconds. + Weight::from_parts(119_187_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) @@ -112,17 +107,15 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_not_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `2082` + // Measured: `2117` // Estimated: `42428` - // Minimum execution time: 93_002_000 picoseconds. - Weight::from_parts(96_924_000, 0) + // Minimum execution time: 111_467_000 picoseconds. + Weight::from_parts(117_758_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) @@ -132,17 +125,15 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `739` + // Measured: `774` // Estimated: `83866` - // Minimum execution time: 160_918_000 picoseconds. - Weight::from_parts(175_603_000, 0) + // Minimum execution time: 191_135_000 picoseconds. + Weight::from_parts(210_535_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) @@ -152,26 +143,24 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `604` + // Measured: `639` // Estimated: `83866` - // Minimum execution time: 55_253_000 picoseconds. - Weight::from_parts(56_488_000, 0) + // Minimum execution time: 67_168_000 picoseconds. + Weight::from_parts(68_895_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) fn refund_decision_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `317` + // Measured: `351` // Estimated: `4365` - // Minimum execution time: 24_497_000 picoseconds. - Weight::from_parts(25_280_000, 0) + // Minimum execution time: 31_298_000 picoseconds. + Weight::from_parts(32_570_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -180,10 +169,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) fn refund_submission_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `167` + // Measured: `201` // Estimated: `4365` - // Minimum execution time: 11_374_000 picoseconds. - Weight::from_parts(11_817_000, 0) + // Minimum execution time: 15_674_000 picoseconds. + Weight::from_parts(16_190_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -192,17 +181,15 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn cancel() -> Weight { // Proof Size summary in bytes: - // Measured: `348` + // Measured: `383` // Estimated: `83866` - // Minimum execution time: 31_805_000 picoseconds. - Weight::from_parts(32_622_000, 0) + // Minimum execution time: 38_927_000 picoseconds. + Weight::from_parts(40_545_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) @@ -210,17 +197,15 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) /// Storage: `FellowshipReferenda::MetadataOf` (r:1 w:0) /// Proof: `FellowshipReferenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn kill() -> Weight { // Proof Size summary in bytes: - // Measured: `449` + // Measured: `484` // Estimated: `83866` - // Minimum execution time: 62_364_000 picoseconds. - Weight::from_parts(63_798_000, 0) + // Minimum execution time: 80_209_000 picoseconds. + Weight::from_parts(82_084_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `FellowshipReferenda::TrackQueue` (r:1 w:0) /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) @@ -228,10 +213,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) fn one_fewer_deciding_queue_empty() -> Weight { // Proof Size summary in bytes: - // Measured: `140` + // Measured: `174` // Estimated: `4277` - // Minimum execution time: 8_811_000 picoseconds. - Weight::from_parts(9_224_000, 0) + // Minimum execution time: 9_520_000 picoseconds. + Weight::from_parts(10_088_000, 0) .saturating_add(Weight::from_parts(0, 4277)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -246,10 +231,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn one_fewer_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `2341` + // Measured: `2376` // Estimated: `42428` - // Minimum execution time: 83_292_000 picoseconds. - Weight::from_parts(89_114_000, 0) + // Minimum execution time: 93_893_000 picoseconds. + Weight::from_parts(101_065_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -264,10 +249,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn one_fewer_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `2327` + // Measured: `2362` // Estimated: `42428` - // Minimum execution time: 84_648_000 picoseconds. - Weight::from_parts(89_332_000, 0) + // Minimum execution time: 98_811_000 picoseconds. + Weight::from_parts(103_590_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -278,10 +263,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) fn nudge_referendum_requeued_insertion() -> Weight { // Proof Size summary in bytes: - // Measured: `1807` + // Measured: `1841` // Estimated: `4365` - // Minimum execution time: 40_529_000 picoseconds. - Weight::from_parts(45_217_000, 0) + // Minimum execution time: 43_230_000 picoseconds. + Weight::from_parts(46_120_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -292,10 +277,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) fn nudge_referendum_requeued_slide() -> Weight { // Proof Size summary in bytes: - // Measured: `1774` + // Measured: `1808` // Estimated: `4365` - // Minimum execution time: 40_894_000 picoseconds. - Weight::from_parts(45_726_000, 0) + // Minimum execution time: 43_092_000 picoseconds. + Weight::from_parts(46_018_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -308,10 +293,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) fn nudge_referendum_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `1790` + // Measured: `1824` // Estimated: `4365` - // Minimum execution time: 48_187_000 picoseconds. - Weight::from_parts(52_655_000, 0) + // Minimum execution time: 49_697_000 picoseconds. + Weight::from_parts(53_795_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -324,10 +309,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) fn nudge_referendum_not_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `1831` + // Measured: `1865` // Estimated: `4365` - // Minimum execution time: 47_548_000 picoseconds. - Weight::from_parts(51_547_000, 0) + // Minimum execution time: 50_417_000 picoseconds. + Weight::from_parts(53_214_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -338,10 +323,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_no_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `300` + // Measured: `335` // Estimated: `42428` - // Minimum execution time: 20_959_000 picoseconds. - Weight::from_parts(21_837_000, 0) + // Minimum execution time: 25_688_000 picoseconds. + Weight::from_parts(26_575_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -352,10 +337,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_preparing() -> Weight { // Proof Size summary in bytes: - // Measured: `348` + // Measured: `383` // Estimated: `42428` - // Minimum execution time: 21_628_000 picoseconds. - Weight::from_parts(22_192_000, 0) + // Minimum execution time: 26_230_000 picoseconds. + Weight::from_parts(27_235_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -364,10 +349,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) fn nudge_referendum_timed_out() -> Weight { // Proof Size summary in bytes: - // Measured: `208` + // Measured: `242` // Estimated: `4365` - // Minimum execution time: 12_309_000 picoseconds. - Weight::from_parts(12_644_000, 0) + // Minimum execution time: 17_585_000 picoseconds. + Weight::from_parts(18_225_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -382,10 +367,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_begin_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `549` + // Measured: `584` // Estimated: `42428` - // Minimum execution time: 31_871_000 picoseconds. - Weight::from_parts(33_123_000, 0) + // Minimum execution time: 38_243_000 picoseconds. + Weight::from_parts(39_959_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -400,10 +385,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_begin_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `684` + // Measured: `719` // Estimated: `42428` - // Minimum execution time: 73_715_000 picoseconds. - Weight::from_parts(79_980_000, 0) + // Minimum execution time: 88_424_000 picoseconds. + Weight::from_parts(92_969_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -416,10 +401,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_begin_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `735` + // Measured: `770` // Estimated: `42428` - // Minimum execution time: 128_564_000 picoseconds. - Weight::from_parts(138_536_000, 0) + // Minimum execution time: 138_207_000 picoseconds. + Weight::from_parts(151_726_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -432,10 +417,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_end_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `720` + // Measured: `755` // Estimated: `42428` - // Minimum execution time: 129_775_000 picoseconds. - Weight::from_parts(139_001_000, 0) + // Minimum execution time: 131_001_000 picoseconds. + Weight::from_parts(148_651_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -448,10 +433,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_continue_not_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `735` + // Measured: `770` // Estimated: `42428` - // Minimum execution time: 128_233_000 picoseconds. - Weight::from_parts(135_796_000, 0) + // Minimum execution time: 109_612_000 picoseconds. + Weight::from_parts(143_626_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -464,10 +449,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_continue_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `741` + // Measured: `776` // Estimated: `42428` - // Minimum execution time: 66_995_000 picoseconds. - Weight::from_parts(72_678_000, 0) + // Minimum execution time: 71_754_000 picoseconds. + Weight::from_parts(77_329_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -482,10 +467,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn nudge_referendum_approved() -> Weight { // Proof Size summary in bytes: - // Measured: `741` + // Measured: `776` // Estimated: `83866` - // Minimum execution time: 137_764_000 picoseconds. - Weight::from_parts(152_260_000, 0) + // Minimum execution time: 153_244_000 picoseconds. + Weight::from_parts(169_961_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) @@ -498,10 +483,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_rejected() -> Weight { // Proof Size summary in bytes: - // Measured: `737` + // Measured: `772` // Estimated: `42428` - // Minimum execution time: 119_992_000 picoseconds. - Weight::from_parts(134_805_000, 0) + // Minimum execution time: 137_997_000 picoseconds. + Weight::from_parts(157_862_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -510,18 +495,16 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:0) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `FellowshipReferenda::MetadataOf` (r:0 w:1) /// Proof: `FellowshipReferenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn set_some_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `424` + // Measured: `458` // Estimated: `4365` - // Minimum execution time: 20_927_000 picoseconds. - Weight::from_parts(21_802_000, 0) + // Minimum execution time: 21_794_000 picoseconds. + Weight::from_parts(22_341_000, 0) .saturating_add(Weight::from_parts(0, 4365)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:0) @@ -530,10 +513,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `285` + // Measured: `319` // Estimated: `4365` - // Minimum execution time: 14_253_000 picoseconds. - Weight::from_parts(15_031_000, 0) + // Minimum execution time: 18_458_000 picoseconds. + Weight::from_parts(19_097_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/polkadot/runtime/rococo/src/weights/pallet_referenda_referenda.rs b/polkadot/runtime/rococo/src/weights/pallet_referenda_referenda.rs index c35925198f9..b7cc5df28b9 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_referenda_referenda.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_referenda_referenda.rs @@ -16,28 +16,27 @@ //! Autogenerated weights for `pallet_referenda` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `runner-xerhrdyb-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: `Some(Wasm)`, WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet -// --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_referenda // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --pallet=pallet_referenda +// --chain=rococo-dev +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -58,10 +57,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) fn submit() -> Weight { // Proof Size summary in bytes: - // Measured: `185` + // Measured: `324` // Estimated: `42428` - // Minimum execution time: 28_612_000 picoseconds. - Weight::from_parts(30_060_000, 0) + // Minimum execution time: 39_852_000 picoseconds. + Weight::from_parts(41_610_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(3)) @@ -70,17 +69,15 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_preparing() -> Weight { // Proof Size summary in bytes: - // Measured: `438` + // Measured: `577` // Estimated: `83866` - // Minimum execution time: 42_827_000 picoseconds. - Weight::from_parts(44_072_000, 0) + // Minimum execution time: 52_588_000 picoseconds. + Weight::from_parts(54_154_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) @@ -90,17 +87,15 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `3225` + // Measured: `3334` // Estimated: `42428` - // Minimum execution time: 56_475_000 picoseconds. - Weight::from_parts(58_888_000, 0) + // Minimum execution time: 70_483_000 picoseconds. + Weight::from_parts(72_731_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) @@ -110,62 +105,60 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_not_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `3245` + // Measured: `3354` // Estimated: `42428` - // Minimum execution time: 56_542_000 picoseconds. - Weight::from_parts(58_616_000, 0) + // Minimum execution time: 68_099_000 picoseconds. + Weight::from_parts(71_560_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) /// Storage: `Referenda::DecidingCount` (r:1 w:1) /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `438` + // Measured: `577` // Estimated: `83866` - // Minimum execution time: 51_218_000 picoseconds. - Weight::from_parts(53_148_000, 0) + // Minimum execution time: 64_357_000 picoseconds. + Weight::from_parts(66_081_000, 0) .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) /// Storage: `Referenda::DecidingCount` (r:1 w:1) /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `438` + // Measured: `577` // Estimated: `83866` - // Minimum execution time: 49_097_000 picoseconds. - Weight::from_parts(50_796_000, 0) + // Minimum execution time: 62_709_000 picoseconds. + Weight::from_parts(64_534_000, 0) .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) fn refund_decision_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `279` + // Measured: `417` // Estimated: `4401` - // Minimum execution time: 23_720_000 picoseconds. - Weight::from_parts(24_327_000, 0) + // Minimum execution time: 31_296_000 picoseconds. + Weight::from_parts(32_221_000, 0) .saturating_add(Weight::from_parts(0, 4401)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -174,10 +167,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) fn refund_submission_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `269` + // Measured: `407` // Estimated: `4401` - // Minimum execution time: 24_089_000 picoseconds. - Weight::from_parts(24_556_000, 0) + // Minimum execution time: 31_209_000 picoseconds. + Weight::from_parts(32_168_000, 0) .saturating_add(Weight::from_parts(0, 4401)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -186,17 +179,15 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn cancel() -> Weight { // Proof Size summary in bytes: - // Measured: `346` + // Measured: `485` // Estimated: `83866` - // Minimum execution time: 29_022_000 picoseconds. - Weight::from_parts(29_590_000, 0) + // Minimum execution time: 38_887_000 picoseconds. + Weight::from_parts(40_193_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) @@ -204,17 +195,15 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) /// Storage: `Referenda::MetadataOf` (r:1 w:0) /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn kill() -> Weight { // Proof Size summary in bytes: - // Measured: `587` + // Measured: `726` // Estimated: `83866` - // Minimum execution time: 81_920_000 picoseconds. - Weight::from_parts(84_492_000, 0) + // Minimum execution time: 106_054_000 picoseconds. + Weight::from_parts(108_318_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Referenda::TrackQueue` (r:1 w:0) /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) @@ -222,10 +211,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) fn one_fewer_deciding_queue_empty() -> Weight { // Proof Size summary in bytes: - // Measured: `102` + // Measured: `240` // Estimated: `5477` - // Minimum execution time: 8_134_000 picoseconds. - Weight::from_parts(8_574_000, 0) + // Minimum execution time: 9_263_000 picoseconds. + Weight::from_parts(9_763_000, 0) .saturating_add(Weight::from_parts(0, 5477)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -234,32 +223,36 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn one_fewer_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `3115` + // Measured: `3254` // Estimated: `42428` - // Minimum execution time: 39_932_000 picoseconds. - Weight::from_parts(42_086_000, 0) + // Minimum execution time: 50_080_000 picoseconds. + Weight::from_parts(51_858_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Referenda::TrackQueue` (r:1 w:1) /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn one_fewer_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `3115` + // Measured: `3254` // Estimated: `42428` - // Minimum execution time: 42_727_000 picoseconds. - Weight::from_parts(44_280_000, 0) + // Minimum execution time: 53_889_000 picoseconds. + Weight::from_parts(55_959_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) @@ -268,10 +261,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) fn nudge_referendum_requeued_insertion() -> Weight { // Proof Size summary in bytes: - // Measured: `2939` + // Measured: `3077` // Estimated: `5477` - // Minimum execution time: 20_918_000 picoseconds. - Weight::from_parts(22_180_000, 0) + // Minimum execution time: 23_266_000 picoseconds. + Weight::from_parts(24_624_000, 0) .saturating_add(Weight::from_parts(0, 5477)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -282,10 +275,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) fn nudge_referendum_requeued_slide() -> Weight { // Proof Size summary in bytes: - // Measured: `2939` + // Measured: `3077` // Estimated: `5477` - // Minimum execution time: 20_943_000 picoseconds. - Weight::from_parts(21_932_000, 0) + // Minimum execution time: 22_846_000 picoseconds. + Weight::from_parts(24_793_000, 0) .saturating_add(Weight::from_parts(0, 5477)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -298,10 +291,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) fn nudge_referendum_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `2943` + // Measured: `3081` // Estimated: `5477` - // Minimum execution time: 25_197_000 picoseconds. - Weight::from_parts(26_083_000, 0) + // Minimum execution time: 28_284_000 picoseconds. + Weight::from_parts(29_940_000, 0) .saturating_add(Weight::from_parts(0, 5477)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -314,10 +307,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) fn nudge_referendum_not_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `2963` + // Measured: `3101` // Estimated: `5477` - // Minimum execution time: 24_969_000 picoseconds. - Weight::from_parts(26_096_000, 0) + // Minimum execution time: 28_133_000 picoseconds. + Weight::from_parts(29_638_000, 0) .saturating_add(Weight::from_parts(0, 5477)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -328,10 +321,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_no_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `298` + // Measured: `437` // Estimated: `42428` - // Minimum execution time: 18_050_000 picoseconds. - Weight::from_parts(18_790_000, 0) + // Minimum execution time: 25_710_000 picoseconds. + Weight::from_parts(26_500_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -342,10 +335,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_preparing() -> Weight { // Proof Size summary in bytes: - // Measured: `346` + // Measured: `485` // Estimated: `42428` - // Minimum execution time: 18_357_000 picoseconds. - Weight::from_parts(18_957_000, 0) + // Minimum execution time: 25_935_000 picoseconds. + Weight::from_parts(26_803_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -354,10 +347,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) fn nudge_referendum_timed_out() -> Weight { // Proof Size summary in bytes: - // Measured: `206` + // Measured: `344` // Estimated: `4401` - // Minimum execution time: 11_479_000 picoseconds. - Weight::from_parts(11_968_000, 0) + // Minimum execution time: 17_390_000 picoseconds. + Weight::from_parts(18_042_000, 0) .saturating_add(Weight::from_parts(0, 4401)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -366,136 +359,150 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) /// Storage: `Referenda::DecidingCount` (r:1 w:1) /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_begin_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `346` + // Measured: `485` // Estimated: `42428` - // Minimum execution time: 24_471_000 picoseconds. - Weight::from_parts(25_440_000, 0) + // Minimum execution time: 35_141_000 picoseconds. + Weight::from_parts(36_318_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) /// Storage: `Referenda::DecidingCount` (r:1 w:1) /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_begin_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `346` + // Measured: `485` // Estimated: `42428` - // Minimum execution time: 26_580_000 picoseconds. - Weight::from_parts(27_570_000, 0) + // Minimum execution time: 37_815_000 picoseconds. + Weight::from_parts(39_243_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_begin_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `399` + // Measured: `538` // Estimated: `42428` - // Minimum execution time: 24_331_000 picoseconds. - Weight::from_parts(25_291_000, 0) + // Minimum execution time: 30_779_000 picoseconds. + Weight::from_parts(31_845_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_end_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `382` + // Measured: `521` // Estimated: `42428` - // Minimum execution time: 24_768_000 picoseconds. - Weight::from_parts(25_746_000, 0) + // Minimum execution time: 31_908_000 picoseconds. + Weight::from_parts(33_253_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_continue_not_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `399` + // Measured: `538` // Estimated: `42428` - // Minimum execution time: 23_171_000 picoseconds. - Weight::from_parts(24_161_000, 0) + // Minimum execution time: 28_951_000 picoseconds. + Weight::from_parts(30_004_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_continue_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `403` + // Measured: `542` // Estimated: `42428` - // Minimum execution time: 22_263_000 picoseconds. - Weight::from_parts(23_062_000, 0) + // Minimum execution time: 27_750_000 picoseconds. + Weight::from_parts(28_588_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Lookup` (r:1 w:1) /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn nudge_referendum_approved() -> Weight { // Proof Size summary in bytes: - // Measured: `403` + // Measured: `542` // Estimated: `83866` - // Minimum execution time: 33_710_000 picoseconds. - Weight::from_parts(34_871_000, 0) + // Minimum execution time: 43_950_000 picoseconds. + Weight::from_parts(46_164_000, 0) .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_rejected() -> Weight { // Proof Size summary in bytes: - // Measured: `399` + // Measured: `538` // Estimated: `42428` - // Minimum execution time: 24_260_000 picoseconds. - Weight::from_parts(25_104_000, 0) + // Minimum execution time: 31_050_000 picoseconds. + Weight::from_parts(32_169_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:0) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Referenda::MetadataOf` (r:0 w:1) /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn set_some_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `422` + // Measured: `560` // Estimated: `4401` - // Minimum execution time: 19_821_000 picoseconds. - Weight::from_parts(20_641_000, 0) + // Minimum execution time: 21_193_000 picoseconds. + Weight::from_parts(22_116_000, 0) .saturating_add(Weight::from_parts(0, 4401)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) @@ -504,10 +511,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `283` + // Measured: `421` // Estimated: `4401` - // Minimum execution time: 13_411_000 picoseconds. - Weight::from_parts(14_070_000, 0) + // Minimum execution time: 18_065_000 picoseconds. + Weight::from_parts(18_781_000, 0) .saturating_add(Weight::from_parts(0, 4401)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/polkadot/runtime/rococo/src/weights/pallet_scheduler.rs b/polkadot/runtime/rococo/src/weights/pallet_scheduler.rs index 5f6b41d2b54..0f36dbd384d 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_scheduler.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_scheduler.rs @@ -16,26 +16,24 @@ //! Autogenerated weights for `pallet_scheduler` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2024-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-grjcggob-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet -// --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_scheduler // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_scheduler +// --chain=rococo-dev // --header=./polkadot/file_header.txt // --output=./polkadot/runtime/rococo/src/weights/ @@ -56,8 +54,8 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `68` // Estimated: `1489` - // Minimum execution time: 3_114_000 picoseconds. - Weight::from_parts(3_245_000, 0) + // Minimum execution time: 2_869_000 picoseconds. + Weight::from_parts(3_109_000, 0) .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -69,11 +67,11 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `115 + s * (177 ±0)` // Estimated: `42428` - // Minimum execution time: 3_430_000 picoseconds. - Weight::from_parts(6_250_920, 0) + // Minimum execution time: 3_326_000 picoseconds. + Weight::from_parts(5_818_563, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 1_350 - .saturating_add(Weight::from_parts(333_245, 0).saturating_mul(s.into())) + // Standard Error: 1_261 + .saturating_add(Weight::from_parts(336_446, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -81,8 +79,8 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_166_000 picoseconds. - Weight::from_parts(3_295_000, 0) + // Minimum execution time: 3_007_000 picoseconds. + Weight::from_parts(3_197_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `Preimage::PreimageFor` (r:1 w:1) @@ -96,11 +94,11 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `251 + s * (1 ±0)` // Estimated: `3716 + s * (1 ±0)` - // Minimum execution time: 17_072_000 picoseconds. - Weight::from_parts(17_393_000, 0) + // Minimum execution time: 16_590_000 picoseconds. + Weight::from_parts(16_869_000, 0) .saturating_add(Weight::from_parts(0, 3716)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_204, 0).saturating_mul(s.into())) + // Standard Error: 9 + .saturating_add(Weight::from_parts(1_308, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(s.into())) @@ -111,8 +109,8 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_566_000 picoseconds. - Weight::from_parts(4_775_000, 0) + // Minimum execution time: 4_320_000 picoseconds. + Weight::from_parts(4_594_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -120,24 +118,24 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_180_000 picoseconds. - Weight::from_parts(3_339_000, 0) + // Minimum execution time: 2_956_000 picoseconds. + Weight::from_parts(3_216_000, 0) .saturating_add(Weight::from_parts(0, 0)) } fn execute_dispatch_signed() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_656_000 picoseconds. - Weight::from_parts(1_829_000, 0) + // Minimum execution time: 1_824_000 picoseconds. + Weight::from_parts(1_929_000, 0) .saturating_add(Weight::from_parts(0, 0)) } fn execute_dispatch_unsigned() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_628_000 picoseconds. - Weight::from_parts(1_840_000, 0) + // Minimum execution time: 1_749_000 picoseconds. + Weight::from_parts(1_916_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `Scheduler::Agenda` (r:1 w:1) @@ -147,18 +145,16 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `115 + s * (177 ±0)` // Estimated: `42428` - // Minimum execution time: 9_523_000 picoseconds. - Weight::from_parts(12_482_434, 0) + // Minimum execution time: 9_086_000 picoseconds. + Weight::from_parts(11_733_696, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 1_663 - .saturating_add(Weight::from_parts(370_122, 0).saturating_mul(s.into())) + // Standard Error: 1_362 + .saturating_add(Weight::from_parts(375_266, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Lookup` (r:0 w:1) /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// The range of component `s` is `[1, 50]`. @@ -166,13 +162,13 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `115 + s * (177 ±0)` // Estimated: `42428` - // Minimum execution time: 14_649_000 picoseconds. - Weight::from_parts(14_705_132, 0) + // Minimum execution time: 12_716_000 picoseconds. + Weight::from_parts(12_529_180, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 1_126 - .saturating_add(Weight::from_parts(547_438, 0).saturating_mul(s.into())) + // Standard Error: 867 + .saturating_add(Weight::from_parts(548_188, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Scheduler::Lookup` (r:1 w:1) /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) @@ -183,11 +179,11 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `292 + s * (185 ±0)` // Estimated: `42428` - // Minimum execution time: 12_335_000 picoseconds. - Weight::from_parts(16_144_217, 0) + // Minimum execution time: 12_053_000 picoseconds. + Weight::from_parts(15_358_056, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 3_533 - .saturating_add(Weight::from_parts(413_823, 0).saturating_mul(s.into())) + // Standard Error: 3_176 + .saturating_add(Weight::from_parts(421_589, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -195,48 +191,49 @@ impl pallet_scheduler::WeightInfo for WeightInfo { /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) /// The range of component `s` is `[1, 50]`. fn cancel_named(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `318 + s * (185 ±0)` // Estimated: `42428` - // Minimum execution time: 16_906_000 picoseconds. - Weight::from_parts(17_846_662, 0) + // Minimum execution time: 14_803_000 picoseconds. + Weight::from_parts(15_805_714, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 2_687 - .saturating_add(Weight::from_parts(613_356, 0).saturating_mul(s.into())) + // Standard Error: 2_597 + .saturating_add(Weight::from_parts(611_053, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(2)) } + /// Storage: `Scheduler::Retries` (r:1 w:2) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Lookup` (r:0 w:1) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// The range of component `s` is `[1, 50]`. fn schedule_retry(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `155` + // Measured: `196` // Estimated: `42428` - // Minimum execution time: 8_988_000 picoseconds. - Weight::from_parts(9_527_838, 0) + // Minimum execution time: 13_156_000 picoseconds. + Weight::from_parts(13_801_287, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 523 - .saturating_add(Weight::from_parts(25_453, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) + // Standard Error: 568 + .saturating_add(Weight::from_parts(35_441, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `Scheduler::Agenda` (r:1 w:0) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Retries` (r:0 w:1) /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// The range of component `s` is `[1, 50]`. fn set_retry() -> Weight { // Proof Size summary in bytes: - // Measured: `8965` + // Measured: `115 + s * (177 ±0)` // Estimated: `42428` - // Minimum execution time: 23_337_000 picoseconds. - Weight::from_parts(24_255_000, 0) + // Minimum execution time: 7_912_000 picoseconds. + Weight::from_parts(8_081_460, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -247,12 +244,13 @@ impl pallet_scheduler::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Retries` (r:0 w:1) /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// The range of component `s` is `[1, 50]`. fn set_retry_named() -> Weight { // Proof Size summary in bytes: - // Measured: `9643` + // Measured: `324 + s * (185 ±0)` // Estimated: `42428` - // Minimum execution time: 30_704_000 picoseconds. - Weight::from_parts(31_646_000, 0) + // Minimum execution time: 10_673_000 picoseconds. + Weight::from_parts(12_212_185, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -261,12 +259,13 @@ impl pallet_scheduler::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Retries` (r:0 w:1) /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// The range of component `s` is `[1, 50]`. fn cancel_retry() -> Weight { // Proof Size summary in bytes: - // Measured: `8977` + // Measured: `115 + s * (177 ±0)` // Estimated: `42428` - // Minimum execution time: 22_279_000 picoseconds. - Weight::from_parts(23_106_000, 0) + // Minimum execution time: 7_912_000 picoseconds. + Weight::from_parts(8_081_460, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -277,12 +276,13 @@ impl pallet_scheduler::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Retries` (r:0 w:1) /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// The range of component `s` is `[1, 50]`. fn cancel_retry_named() -> Weight { // Proof Size summary in bytes: - // Measured: `9655` + // Measured: `324 + s * (185 ±0)` // Estimated: `42428` - // Minimum execution time: 29_649_000 picoseconds. - Weight::from_parts(30_472_000, 0) + // Minimum execution time: 10_673_000 picoseconds. + Weight::from_parts(12_212_185, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/polkadot/runtime/rococo/src/weights/pallet_sudo.rs b/polkadot/runtime/rococo/src/weights/pallet_sudo.rs index ecc31dc3fa9..694174954fc 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_sudo.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_sudo.rs @@ -16,26 +16,24 @@ //! Autogenerated weights for `pallet_sudo` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-11-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet -// --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_sudo // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_sudo +// --chain=rococo-dev // --header=./polkadot/file_header.txt // --output=./polkadot/runtime/rococo/src/weights/ @@ -56,8 +54,8 @@ impl pallet_sudo::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `132` // Estimated: `1517` - // Minimum execution time: 8_336_000 picoseconds. - Weight::from_parts(8_569_000, 0) + // Minimum execution time: 8_432_000 picoseconds. + Weight::from_parts(8_757_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -68,8 +66,8 @@ impl pallet_sudo::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `132` // Estimated: `1517` - // Minimum execution time: 8_858_000 picoseconds. - Weight::from_parts(9_238_000, 0) + // Minimum execution time: 9_167_000 picoseconds. + Weight::from_parts(9_397_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) } @@ -79,8 +77,8 @@ impl pallet_sudo::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `132` // Estimated: `1517` - // Minimum execution time: 8_921_000 picoseconds. - Weight::from_parts(9_324_000, 0) + // Minimum execution time: 9_133_000 picoseconds. + Weight::from_parts(9_573_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) } @@ -90,21 +88,10 @@ impl pallet_sudo::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `132` // Estimated: `1517` - // Minimum execution time: 7_398_000 picoseconds. - Weight::from_parts(7_869_000, 0) + // Minimum execution time: 7_374_000 picoseconds. + Weight::from_parts(7_702_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Sudo::Key` (r:1 w:0) - /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - fn check_only_sudo_account() -> Weight { - // Proof Size summary in bytes: - // Measured: `132` - // Estimated: `1517` - // Minimum execution time: 3_146_000 picoseconds. - Weight::from_parts(3_314_000, 0) - .saturating_add(Weight::from_parts(0, 1517)) - .saturating_add(T::DbWeight::get().reads(1)) - } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_timestamp.rs b/polkadot/runtime/rococo/src/weights/pallet_timestamp.rs index 7d79621b9e6..1bb2e227ab7 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_timestamp.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_timestamp.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_timestamp` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: // ./target/production/polkadot @@ -29,15 +29,12 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --pallet=pallet_timestamp // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,26 +47,26 @@ use core::marker::PhantomData; /// Weight functions for `pallet_timestamp`. pub struct WeightInfo(PhantomData); impl pallet_timestamp::WeightInfo for WeightInfo { - /// Storage: `Timestamp::Now` (r:1 w:1) - /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Babe::CurrentSlot` (r:1 w:0) - /// Proof: `Babe::CurrentSlot` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: Timestamp Now (r:1 w:1) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Babe CurrentSlot (r:1 w:0) + /// Proof: Babe CurrentSlot (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) fn set() -> Weight { // Proof Size summary in bytes: - // Measured: `137` + // Measured: `311` // Estimated: `1493` - // Minimum execution time: 5_596_000 picoseconds. - Weight::from_parts(5_823_000, 0) + // Minimum execution time: 10_103_000 picoseconds. + Weight::from_parts(10_597_000, 0) .saturating_add(Weight::from_parts(0, 1493)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } fn on_finalize() -> Weight { // Proof Size summary in bytes: - // Measured: `57` + // Measured: `94` // Estimated: `0` - // Minimum execution time: 2_777_000 picoseconds. - Weight::from_parts(2_900_000, 0) + // Minimum execution time: 4_718_000 picoseconds. + Weight::from_parts(4_839_000, 0) .saturating_add(Weight::from_parts(0, 0)) } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_transaction_payment.rs b/polkadot/runtime/rococo/src/weights/pallet_transaction_payment.rs deleted file mode 100644 index 44dfab289fb..00000000000 --- a/polkadot/runtime/rococo/src/weights/pallet_transaction_payment.rs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_transaction_payment` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=rococo-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_transaction_payment -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_transaction_payment`. -pub struct WeightInfo(PhantomData); -impl pallet_transaction_payment::WeightInfo for WeightInfo { - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn charge_transaction_payment() -> Weight { - // Proof Size summary in bytes: - // Measured: `252` - // Estimated: `1737` - // Minimum execution time: 33_070_000 picoseconds. - Weight::from_parts(33_730_000, 0) - .saturating_add(Weight::from_parts(0, 1737)) - .saturating_add(T::DbWeight::get().reads(3)) - } -} diff --git a/polkadot/runtime/rococo/src/weights/pallet_treasury.rs b/polkadot/runtime/rococo/src/weights/pallet_treasury.rs index acf09989afc..144e9d5b872 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_treasury.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_treasury.rs @@ -16,28 +16,25 @@ //! Autogenerated weights for `pallet_treasury` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-07, STEPS: `50`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `cob`, CPU: `` +//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// ./target/debug/polkadot // benchmark // pallet // --chain=rococo-dev // --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares +// --repeat=2 // --pallet=pallet_treasury // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ +// --heap-pages=4096 +// --output=./runtime/rococo/src/weights/ +// --header=./file_header.txt #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,168 +47,176 @@ use core::marker::PhantomData; /// Weight functions for `pallet_treasury`. pub struct WeightInfo(PhantomData); impl pallet_treasury::WeightInfo for WeightInfo { - /// Storage: `Treasury::ProposalCount` (r:1 w:1) - /// Proof: `Treasury::ProposalCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Approvals` (r:1 w:1) - /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Proposals` (r:0 w:1) - /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Storage: Treasury ProposalCount (r:1 w:1) + /// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + /// Storage: Treasury Proposals (r:0 w:1) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) fn spend_local() -> Weight { // Proof Size summary in bytes: - // Measured: `142` + // Measured: `42` // Estimated: `1887` - // Minimum execution time: 9_928_000 picoseconds. - Weight::from_parts(10_560_000, 0) + // Minimum execution time: 177_000_000 picoseconds. + Weight::from_parts(191_000_000, 0) .saturating_add(Weight::from_parts(0, 1887)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `Treasury::ProposalCount` (r:1 w:1) - /// Proof: `Treasury::ProposalCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Proposals` (r:0 w:1) - /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Storage: Treasury ProposalCount (r:1 w:1) + /// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Treasury Proposals (r:0 w:1) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) fn propose_spend() -> Weight { // Proof Size summary in bytes: - // Measured: `243` + // Measured: `143` // Estimated: `1489` - // Minimum execution time: 20_714_000 picoseconds. - Weight::from_parts(21_137_000, 0) + // Minimum execution time: 354_000_000 picoseconds. + Weight::from_parts(376_000_000, 0) .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Treasury::Proposals` (r:1 w:1) - /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Treasury Proposals (r:1 w:1) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn reject_proposal() -> Weight { // Proof Size summary in bytes: - // Measured: `401` + // Measured: `301` // Estimated: `3593` - // Minimum execution time: 31_665_000 picoseconds. - Weight::from_parts(32_442_000, 0) + // Minimum execution time: 547_000_000 picoseconds. + Weight::from_parts(550_000_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Treasury::Proposals` (r:1 w:0) - /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Approvals` (r:1 w:1) - /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: Treasury Proposals (r:1 w:0) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) /// The range of component `p` is `[0, 99]`. fn approve_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `570 + p * (8 ±0)` + // Measured: `470 + p * (8 ±0)` // Estimated: `3573` - // Minimum execution time: 6_988_000 picoseconds. - Weight::from_parts(11_464_972, 0) + // Minimum execution time: 104_000_000 picoseconds. + Weight::from_parts(121_184_402, 0) .saturating_add(Weight::from_parts(0, 3573)) - // Standard Error: 1_722 - .saturating_add(Weight::from_parts(84_536, 0).saturating_mul(p.into())) + // Standard Error: 42_854 + .saturating_add(Weight::from_parts(153_112, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Treasury::Approvals` (r:1 w:1) - /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) fn remove_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `227` + // Measured: `127` // Estimated: `1887` - // Minimum execution time: 5_386_000 picoseconds. - Weight::from_parts(5_585_000, 0) + // Minimum execution time: 80_000_000 picoseconds. + Weight::from_parts(82_000_000, 0) .saturating_add(Weight::from_parts(0, 1887)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Treasury::Deactivated` (r:1 w:1) - /// Proof: `Treasury::Deactivated` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Approvals` (r:1 w:1) - /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Proposals` (r:99 w:99) - /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:199 w:199) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Bounties::BountyApprovals` (r:1 w:1) - /// Proof: `Bounties::BountyApprovals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: Treasury Deactivated (r:1 w:1) + /// Proof: Treasury Deactivated (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Balances InactiveIssuance (r:1 w:1) + /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + /// Storage: Treasury Proposals (r:99 w:99) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: System Account (r:199 w:199) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Bounties BountyApprovals (r:1 w:1) + /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) /// The range of component `p` is `[0, 99]`. fn on_initialize_proposals(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `431 + p * (251 ±0)` + // Measured: `331 + p * (251 ±0)` // Estimated: `3593 + p * (5206 ±0)` - // Minimum execution time: 43_737_000 picoseconds. - Weight::from_parts(39_883_021, 0) + // Minimum execution time: 887_000_000 picoseconds. + Weight::from_parts(828_616_021, 0) .saturating_add(Weight::from_parts(0, 3593)) - // Standard Error: 12_917 - .saturating_add(Weight::from_parts(31_796_205, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(4)) + // Standard Error: 695_351 + .saturating_add(Weight::from_parts(566_114_524, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(p.into()))) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(5)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(p.into()))) .saturating_add(Weight::from_parts(0, 5206).saturating_mul(p.into())) } - /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:0) - /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(1238), added: 3713, mode: `MaxEncodedLen`) - /// Storage: `Treasury::SpendCount` (r:1 w:1) - /// Proof: `Treasury::SpendCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Spends` (r:0 w:1) - /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(1853), added: 4328, mode: `MaxEncodedLen`) + /// Storage: AssetRate ConversionRateToNative (r:1 w:0) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(1237), added: 3712, mode: MaxEncodedLen) + /// Storage: Treasury SpendCount (r:1 w:1) + /// Proof: Treasury SpendCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Treasury Spends (r:0 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen) fn spend() -> Weight { // Proof Size summary in bytes: - // Measured: `215` - // Estimated: `4703` - // Minimum execution time: 16_829_000 picoseconds. - Weight::from_parts(17_251_000, 0) - .saturating_add(Weight::from_parts(0, 4703)) + // Measured: `114` + // Estimated: `4702` + // Minimum execution time: 208_000_000 picoseconds. + Weight::from_parts(222_000_000, 0) + .saturating_add(Weight::from_parts(0, 4702)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Treasury::Spends` (r:1 w:1) - /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(1853), added: 4328, mode: `MaxEncodedLen`) - /// Storage: `XcmPallet::QueryCounter` (r:1 w:1) - /// Proof: `XcmPallet::QueryCounter` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) - /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `XcmPallet::Queries` (r:0 w:1) - /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Treasury Spends (r:1 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen) + /// Storage: XcmPallet QueryCounter (r:1 w:1) + /// Proof Skipped: XcmPallet QueryCounter (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Configuration ActiveConfig (r:1 w:0) + /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) + /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) + /// Storage: XcmPallet SupportedVersion (r:1 w:0) + /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) + /// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) + /// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: XcmPallet SafeXcmVersion (r:1 w:0) + /// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Dmp DownwardMessageQueues (r:1 w:1) + /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) + /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) + /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) + /// Storage: XcmPallet Queries (r:0 w:1) + /// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured) fn payout() -> Weight { // Proof Size summary in bytes: - // Measured: `458` - // Estimated: `5318` - // Minimum execution time: 41_554_000 picoseconds. - Weight::from_parts(42_451_000, 0) - .saturating_add(Weight::from_parts(0, 5318)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(5)) + // Measured: `737` + // Estimated: `5313` + // Minimum execution time: 551_000_000 picoseconds. + Weight::from_parts(569_000_000, 0) + .saturating_add(Weight::from_parts(0, 5313)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(6)) } - /// Storage: `Treasury::Spends` (r:1 w:1) - /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(1853), added: 4328, mode: `MaxEncodedLen`) - /// Storage: `XcmPallet::Queries` (r:1 w:1) - /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Treasury Spends (r:1 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen) + /// Storage: XcmPallet Queries (r:1 w:1) + /// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured) fn check_status() -> Weight { // Proof Size summary in bytes: - // Measured: `306` - // Estimated: `5318` - // Minimum execution time: 22_546_000 picoseconds. - Weight::from_parts(23_151_000, 0) - .saturating_add(Weight::from_parts(0, 5318)) + // Measured: `442` + // Estimated: `5313` + // Minimum execution time: 245_000_000 picoseconds. + Weight::from_parts(281_000_000, 0) + .saturating_add(Weight::from_parts(0, 5313)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Treasury::Spends` (r:1 w:1) - /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(1853), added: 4328, mode: `MaxEncodedLen`) + /// Storage: Treasury Spends (r:1 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen) fn void_spend() -> Weight { // Proof Size summary in bytes: - // Measured: `278` - // Estimated: `5318` - // Minimum execution time: 12_169_000 picoseconds. - Weight::from_parts(12_484_000, 0) - .saturating_add(Weight::from_parts(0, 5318)) + // Measured: `172` + // Estimated: `5313` + // Minimum execution time: 147_000_000 picoseconds. + Weight::from_parts(160_000_000, 0) + .saturating_add(Weight::from_parts(0, 5313)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/rococo/src/weights/pallet_utility.rs b/polkadot/runtime/rococo/src/weights/pallet_utility.rs index 6f2a374247f..f50f60eaad7 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_utility.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_utility.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_utility` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: // ./target/production/polkadot @@ -29,15 +29,12 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --pallet=pallet_utility // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -55,18 +52,18 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_041_000 picoseconds. - Weight::from_parts(5_685_496, 0) + // Minimum execution time: 6_738_000 picoseconds. + Weight::from_parts(2_704_821, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 810 - .saturating_add(Weight::from_parts(3_177_197, 0).saturating_mul(c.into())) + // Standard Error: 2_999 + .saturating_add(Weight::from_parts(4_627_278, 0).saturating_mul(c.into())) } fn as_derivative() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_667_000 picoseconds. - Weight::from_parts(3_871_000, 0) + // Minimum execution time: 5_294_000 picoseconds. + Weight::from_parts(5_467_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `c` is `[0, 1000]`. @@ -74,18 +71,18 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_116_000 picoseconds. - Weight::from_parts(6_453_932, 0) + // Minimum execution time: 6_828_000 picoseconds. + Weight::from_parts(4_650_678, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 825 - .saturating_add(Weight::from_parts(3_366_112, 0).saturating_mul(c.into())) + // Standard Error: 2_789 + .saturating_add(Weight::from_parts(4_885_004, 0).saturating_mul(c.into())) } fn dispatch_as() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_630_000 picoseconds. - Weight::from_parts(5_956_000, 0) + // Minimum execution time: 9_020_000 picoseconds. + Weight::from_parts(9_205_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `c` is `[0, 1000]`. @@ -93,10 +90,10 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_165_000 picoseconds. - Weight::from_parts(5_442_561, 0) + // Minimum execution time: 6_852_000 picoseconds. + Weight::from_parts(20_703_134, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 460 - .saturating_add(Weight::from_parts(3_173_577, 0).saturating_mul(c.into())) + // Standard Error: 3_924 + .saturating_add(Weight::from_parts(4_604_529, 0).saturating_mul(c.into())) } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_vesting.rs b/polkadot/runtime/rococo/src/weights/pallet_vesting.rs index c21ab087774..2596207d583 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_vesting.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_vesting.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_vesting` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: // ./target/production/polkadot @@ -29,15 +29,12 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --pallet=pallet_vesting // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,143 +47,143 @@ use core::marker::PhantomData; /// Weight functions for `pallet_vesting`. pub struct WeightInfo(PhantomData); impl pallet_vesting::WeightInfo for WeightInfo { - /// Storage: `Vesting::Vesting` (r:1 w:1) - /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_locked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `277 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 29_288_000 picoseconds. - Weight::from_parts(29_095_507, 0) + // Minimum execution time: 32_820_000 picoseconds. + Weight::from_parts(31_640_992, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 1_679 - .saturating_add(Weight::from_parts(33_164, 0).saturating_mul(l.into())) - // Standard Error: 2_988 - .saturating_add(Weight::from_parts(67_092, 0).saturating_mul(s.into())) + // Standard Error: 449 + .saturating_add(Weight::from_parts(45_254, 0).saturating_mul(l.into())) + // Standard Error: 800 + .saturating_add(Weight::from_parts(72_178, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Vesting::Vesting` (r:1 w:1) - /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_unlocked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `277 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 31_003_000 picoseconds. - Weight::from_parts(30_528_438, 0) + // Minimum execution time: 36_054_000 picoseconds. + Weight::from_parts(35_825_428, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 1_586 - .saturating_add(Weight::from_parts(35_429, 0).saturating_mul(l.into())) - // Standard Error: 2_823 - .saturating_add(Weight::from_parts(76_505, 0).saturating_mul(s.into())) + // Standard Error: 749 + .saturating_add(Weight::from_parts(31_738, 0).saturating_mul(l.into())) + // Standard Error: 1_333 + .saturating_add(Weight::from_parts(40_580, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Vesting::Vesting` (r:1 w:1) - /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_other_locked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `380 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 31_269_000 picoseconds. - Weight::from_parts(30_661_898, 0) + // Minimum execution time: 35_440_000 picoseconds. + Weight::from_parts(34_652_647, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 1_394 - .saturating_add(Weight::from_parts(39_300, 0).saturating_mul(l.into())) - // Standard Error: 2_480 - .saturating_add(Weight::from_parts(78_849, 0).saturating_mul(s.into())) + // Standard Error: 517 + .saturating_add(Weight::from_parts(41_942, 0).saturating_mul(l.into())) + // Standard Error: 920 + .saturating_add(Weight::from_parts(66_074, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `Vesting::Vesting` (r:1 w:1) - /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `380 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 33_040_000 picoseconds. - Weight::from_parts(32_469_674, 0) + // Minimum execution time: 38_880_000 picoseconds. + Weight::from_parts(39_625_819, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 1_418 - .saturating_add(Weight::from_parts(44_206, 0).saturating_mul(l.into())) - // Standard Error: 2_523 - .saturating_add(Weight::from_parts(74_224, 0).saturating_mul(s.into())) + // Standard Error: 1_032 + .saturating_add(Weight::from_parts(29_856, 0).saturating_mul(l.into())) + // Standard Error: 1_837 + .saturating_add(Weight::from_parts(6_210, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `Vesting::Vesting` (r:1 w:1) - /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[0, 27]`. fn vested_transfer(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `451 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 62_032_000 picoseconds. - Weight::from_parts(63_305_621, 0) + // Minimum execution time: 68_294_000 picoseconds. + Weight::from_parts(68_313_394, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 2_277 - .saturating_add(Weight::from_parts(42_767, 0).saturating_mul(l.into())) - // Standard Error: 4_051 - .saturating_add(Weight::from_parts(65_487, 0).saturating_mul(s.into())) + // Standard Error: 983 + .saturating_add(Weight::from_parts(48_156, 0).saturating_mul(l.into())) + // Standard Error: 1_750 + .saturating_add(Weight::from_parts(87_719, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `Vesting::Vesting` (r:1 w:1) - /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[0, 27]`. fn force_vested_transfer(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `554 + l * (25 ±0) + s * (36 ±0)` // Estimated: `6196` - // Minimum execution time: 63_303_000 picoseconds. - Weight::from_parts(65_180_847, 0) + // Minimum execution time: 70_529_000 picoseconds. + Weight::from_parts(70_619_962, 0) .saturating_add(Weight::from_parts(0, 6196)) - // Standard Error: 2_220 - .saturating_add(Weight::from_parts(28_829, 0).saturating_mul(l.into())) - // Standard Error: 3_951 - .saturating_add(Weight::from_parts(84_970, 0).saturating_mul(s.into())) + // Standard Error: 1_259 + .saturating_add(Weight::from_parts(50_685, 0).saturating_mul(l.into())) + // Standard Error: 2_241 + .saturating_add(Weight::from_parts(91_444, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -195,70 +192,59 @@ impl pallet_vesting::WeightInfo for WeightInfo { /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[2, 28]`. - fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { + fn force_remove_vesting_schedule(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `378 + l * (25 ±0) + s * (36 ±0)` + // Measured: `555 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 31_440_000 picoseconds. - Weight::from_parts(30_773_053, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 1_474 - .saturating_add(Weight::from_parts(43_019, 0).saturating_mul(l.into())) - // Standard Error: 2_723 - .saturating_add(Weight::from_parts(73_360, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) + // Minimum execution time: 41_497_000 picoseconds. + Weight::from_parts(38_763_834, 4764) + // Standard Error: 2_030 + .saturating_add(Weight::from_parts(99_580, 0).saturating_mul(l.into())) + // Standard Error: 3_750 + .saturating_add(Weight::from_parts(132_188, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Vesting::Vesting` (r:1 w:1) - /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// The range of component `l` is `[0, 49]`. - /// The range of component `s` is `[2, 28]`. - fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { + fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `378 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 34_221_000 picoseconds. - Weight::from_parts(33_201_125, 0) + // Minimum execution time: 36_428_000 picoseconds. + Weight::from_parts(35_604_430, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 1_751 - .saturating_add(Weight::from_parts(44_088, 0).saturating_mul(l.into())) - // Standard Error: 3_234 - .saturating_add(Weight::from_parts(86_228, 0).saturating_mul(s.into())) + // Standard Error: 504 + .saturating_add(Weight::from_parts(43_191, 0).saturating_mul(l.into())) + // Standard Error: 931 + .saturating_add(Weight::from_parts(66_795, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `Vesting::Vesting` (r:1 w:1) - /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[2, 28]`. - fn force_remove_vesting_schedule(l: u32, s: u32, ) -> Weight { + fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `451 + l * (25 ±0) + s * (36 ±0)` + // Measured: `378 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 35_553_000 picoseconds. - Weight::from_parts(34_974_083, 0) + // Minimum execution time: 40_696_000 picoseconds. + Weight::from_parts(39_741_284, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 1_560 - .saturating_add(Weight::from_parts(34_615, 0).saturating_mul(l.into())) - // Standard Error: 2_882 - .saturating_add(Weight::from_parts(83_419, 0).saturating_mul(s.into())) + // Standard Error: 478 + .saturating_add(Weight::from_parts(43_792, 0).saturating_mul(l.into())) + // Standard Error: 883 + .saturating_add(Weight::from_parts(66_540, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } diff --git a/polkadot/runtime/rococo/src/weights/pallet_whitelist.rs b/polkadot/runtime/rococo/src/weights/pallet_whitelist.rs index ec67268d144..7c307deec4c 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_whitelist.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_whitelist.rs @@ -16,28 +16,26 @@ //! Autogenerated weights for `pallet_whitelist` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-08-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-aahe6cbd-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet -// --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_whitelist // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --pallet=pallet_whitelist +// --chain=rococo-dev +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -52,75 +50,67 @@ pub struct WeightInfo(PhantomData); impl pallet_whitelist::WeightInfo for WeightInfo { /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) - /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Storage: `Preimage::StatusFor` (r:1 w:1) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn whitelist_call() -> Weight { // Proof Size summary in bytes: // Measured: `223` // Estimated: `3556` - // Minimum execution time: 16_686_000 picoseconds. - Weight::from_parts(17_042_000, 0) + // Minimum execution time: 20_035_000 picoseconds. + Weight::from_parts(20_452_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) - /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Storage: `Preimage::StatusFor` (r:1 w:1) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn remove_whitelisted_call() -> Weight { // Proof Size summary in bytes: // Measured: `352` // Estimated: `3556` - // Minimum execution time: 18_250_000 picoseconds. - Weight::from_parts(19_026_000, 0) + // Minimum execution time: 20_247_000 picoseconds. + Weight::from_parts(20_808_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Preimage::PreimageFor` (r:1 w:1) /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `Measured`) - /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Storage: `Preimage::StatusFor` (r:1 w:1) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 4194294]`. fn dispatch_whitelisted_call(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `428 + n * (1 ±0)` // Estimated: `3892 + n * (1 ±0)` - // Minimum execution time: 28_741_000 picoseconds. - Weight::from_parts(29_024_000, 0) + // Minimum execution time: 32_633_000 picoseconds. + Weight::from_parts(32_855_000, 0) .saturating_add(Weight::from_parts(0, 3892)) - // Standard Error: 7 - .saturating_add(Weight::from_parts(1_305, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(4)) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_223, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) - /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Storage: `Preimage::StatusFor` (r:1 w:1) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 10000]`. fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `352` // Estimated: `3556` - // Minimum execution time: 21_670_000 picoseconds. - Weight::from_parts(22_561_364, 0) + // Minimum execution time: 23_833_000 picoseconds. + Weight::from_parts(24_698_994, 0) .saturating_add(Weight::from_parts(0, 3556)) // Standard Error: 4 - .saturating_add(Weight::from_parts(1_468, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(Weight::from_parts(1_454, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs index d5cf33515e6..5544ca44658 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs @@ -17,25 +17,23 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet -// --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_xcm // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm +// --chain=rococo-dev // --header=./polkadot/file_header.txt // --output=./polkadot/runtime/rococo/src/weights/ @@ -62,8 +60,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3645` - // Minimum execution time: 25_521_000 picoseconds. - Weight::from_parts(25_922_000, 0) + // Minimum execution time: 25_043_000 picoseconds. + Weight::from_parts(25_682_000, 0) .saturating_add(Weight::from_parts(0, 3645)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -82,8 +80,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3645` - // Minimum execution time: 112_185_000 picoseconds. - Weight::from_parts(115_991_000, 0) + // Minimum execution time: 107_570_000 picoseconds. + Weight::from_parts(109_878_000, 0) .saturating_add(Weight::from_parts(0, 3645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) @@ -102,8 +100,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `232` // Estimated: `3697` - // Minimum execution time: 108_693_000 picoseconds. - Weight::from_parts(111_853_000, 0) + // Minimum execution time: 106_341_000 picoseconds. + Weight::from_parts(109_135_000, 0) .saturating_add(Weight::from_parts(0, 3697)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) @@ -122,8 +120,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3645` - // Minimum execution time: 113_040_000 picoseconds. - Weight::from_parts(115_635_000, 0) + // Minimum execution time: 108_372_000 picoseconds. + Weight::from_parts(112_890_000, 0) .saturating_add(Weight::from_parts(0, 3645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) @@ -132,8 +130,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_979_000 picoseconds. - Weight::from_parts(7_342_000, 0) + // Minimum execution time: 6_957_000 picoseconds. + Weight::from_parts(7_417_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `XcmPallet::SupportedVersion` (r:0 w:1) @@ -142,8 +140,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_144_000 picoseconds. - Weight::from_parts(7_297_000, 0) + // Minimum execution time: 7_053_000 picoseconds. + Weight::from_parts(7_462_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -151,8 +149,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_886_000 picoseconds. - Weight::from_parts(1_995_000, 0) + // Minimum execution time: 1_918_000 picoseconds. + Weight::from_parts(2_037_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `XcmPallet::VersionNotifiers` (r:1 w:1) @@ -173,8 +171,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3645` - // Minimum execution time: 31_238_000 picoseconds. - Weight::from_parts(31_955_000, 0) + // Minimum execution time: 30_417_000 picoseconds. + Weight::from_parts(31_191_000, 0) .saturating_add(Weight::from_parts(0, 3645)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) @@ -195,8 +193,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `360` // Estimated: `3825` - // Minimum execution time: 37_237_000 picoseconds. - Weight::from_parts(38_569_000, 0) + // Minimum execution time: 36_666_000 picoseconds. + Weight::from_parts(37_779_000, 0) .saturating_add(Weight::from_parts(0, 3825)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) @@ -207,8 +205,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_884_000 picoseconds. - Weight::from_parts(2_028_000, 0) + // Minimum execution time: 1_869_000 picoseconds. + Weight::from_parts(2_003_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -218,8 +216,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `22` // Estimated: `13387` - // Minimum execution time: 16_048_000 picoseconds. - Weight::from_parts(16_617_000, 0) + // Minimum execution time: 16_188_000 picoseconds. + Weight::from_parts(16_435_000, 0) .saturating_add(Weight::from_parts(0, 13387)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -230,8 +228,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `26` // Estimated: `13391` - // Minimum execution time: 16_073_000 picoseconds. - Weight::from_parts(16_672_000, 0) + // Minimum execution time: 16_431_000 picoseconds. + Weight::from_parts(16_935_000, 0) .saturating_add(Weight::from_parts(0, 13391)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -242,8 +240,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `40` // Estimated: `15880` - // Minimum execution time: 18_422_000 picoseconds. - Weight::from_parts(18_900_000, 0) + // Minimum execution time: 18_460_000 picoseconds. + Weight::from_parts(18_885_000, 0) .saturating_add(Weight::from_parts(0, 15880)) .saturating_add(T::DbWeight::get().reads(6)) } @@ -261,8 +259,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `216` // Estimated: `6156` - // Minimum execution time: 30_373_000 picoseconds. - Weight::from_parts(30_972_000, 0) + // Minimum execution time: 29_623_000 picoseconds. + Weight::from_parts(30_661_000, 0) .saturating_add(Weight::from_parts(0, 6156)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) @@ -273,8 +271,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `69` // Estimated: `10959` - // Minimum execution time: 11_863_000 picoseconds. - Weight::from_parts(12_270_000, 0) + // Minimum execution time: 12_043_000 picoseconds. + Weight::from_parts(12_360_000, 0) .saturating_add(Weight::from_parts(0, 10959)) .saturating_add(T::DbWeight::get().reads(4)) } @@ -284,8 +282,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `33` // Estimated: `13398` - // Minimum execution time: 16_733_000 picoseconds. - Weight::from_parts(17_094_000, 0) + // Minimum execution time: 16_511_000 picoseconds. + Weight::from_parts(17_011_000, 0) .saturating_add(Weight::from_parts(0, 13398)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -304,8 +302,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `216` // Estimated: `13581` - // Minimum execution time: 39_236_000 picoseconds. - Weight::from_parts(40_587_000, 0) + // Minimum execution time: 39_041_000 picoseconds. + Weight::from_parts(39_883_000, 0) .saturating_add(Weight::from_parts(0, 13581)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) @@ -318,8 +316,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1485` - // Minimum execution time: 2_145_000 picoseconds. - Weight::from_parts(2_255_000, 0) + // Minimum execution time: 2_030_000 picoseconds. + Weight::from_parts(2_150_000, 0) .saturating_add(Weight::from_parts(0, 1485)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -330,8 +328,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7576` // Estimated: `11041` - // Minimum execution time: 22_518_000 picoseconds. - Weight::from_parts(22_926_000, 0) + // Minimum execution time: 22_615_000 picoseconds. + Weight::from_parts(23_008_000, 0) .saturating_add(Weight::from_parts(0, 11041)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_fungible.rs b/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_fungible.rs deleted file mode 100644 index dc5e5d8ca4b..00000000000 --- a/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_fungible.rs +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_xcm_benchmarks::fungible` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=rococo-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_xcm_benchmarks::fungible -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_fungible.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_xcm_benchmarks::fungible`. -pub struct WeightInfo(PhantomData); -impl pallet_xcm_benchmarks::fungible::WeightInfo for WeightInfo { - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn withdraw_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `101` - // Estimated: `3593` - // Minimum execution time: 27_223_000 picoseconds. - Weight::from_parts(27_947_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn transfer_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `101` - // Estimated: `6196` - // Minimum execution time: 36_502_000 picoseconds. - Weight::from_parts(37_023_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) - /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn transfer_reserve_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `281` - // Estimated: `6196` - // Minimum execution time: 85_152_000 picoseconds. - Weight::from_parts(86_442_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: `Benchmark::Override` (r:0 w:0) - /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn reserve_asset_deposited() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. - Weight::from_parts(18_446_744_073_709_551_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) - /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn initiate_reserve_withdraw() -> Weight { - // Proof Size summary in bytes: - // Measured: `281` - // Estimated: `3746` - // Minimum execution time: 56_571_000 picoseconds. - Weight::from_parts(58_163_000, 0) - .saturating_add(Weight::from_parts(0, 3746)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn receive_teleported_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `103` - // Estimated: `3593` - // Minimum execution time: 27_411_000 picoseconds. - Weight::from_parts(27_953_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn deposit_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `3593` - // Minimum execution time: 20_776_000 picoseconds. - Weight::from_parts(21_145_000, 0) - .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) - /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn deposit_reserve_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `180` - // Estimated: `3645` - // Minimum execution time: 51_738_000 picoseconds. - Weight::from_parts(53_251_000, 0) - .saturating_add(Weight::from_parts(0, 3645)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) - /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn initiate_teleport() -> Weight { - // Proof Size summary in bytes: - // Measured: `180` - // Estimated: `3645` - // Minimum execution time: 39_333_000 picoseconds. - Weight::from_parts(40_515_000, 0) - .saturating_add(Weight::from_parts(0, 3645)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } -} diff --git a/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_generic.rs b/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_generic.rs deleted file mode 100644 index b62f36172ba..00000000000 --- a/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_generic.rs +++ /dev/null @@ -1,347 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_xcm_benchmarks::generic` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=rococo-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_xcm_benchmarks::generic -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_generic.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_xcm_benchmarks::generic`. -pub struct WeightInfo(PhantomData); -impl pallet_xcm_benchmarks::generic::WeightInfo for WeightInfo { - /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) - /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn report_holding() -> Weight { - // Proof Size summary in bytes: - // Measured: `281` - // Estimated: `3746` - // Minimum execution time: 55_210_000 picoseconds. - Weight::from_parts(56_613_000, 0) - .saturating_add(Weight::from_parts(0, 3746)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } - fn buy_execution() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 1_246_000 picoseconds. - Weight::from_parts(1_339_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `XcmPallet::Queries` (r:1 w:0) - /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn query_response() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `3465` - // Minimum execution time: 5_377_000 picoseconds. - Weight::from_parts(5_549_000, 0) - .saturating_add(Weight::from_parts(0, 3465)) - .saturating_add(T::DbWeight::get().reads(1)) - } - fn transact() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 7_008_000 picoseconds. - Weight::from_parts(7_361_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn refund_surplus() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 1_700_000 picoseconds. - Weight::from_parts(1_848_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn set_error_handler() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 1_198_000 picoseconds. - Weight::from_parts(1_265_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn set_appendix() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 1_197_000 picoseconds. - Weight::from_parts(1_267_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn clear_error() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 1_193_000 picoseconds. - Weight::from_parts(1_258_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn descend_origin() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 1_268_000 picoseconds. - Weight::from_parts(1_342_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn clear_origin() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 1_173_000 picoseconds. - Weight::from_parts(1_248_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) - /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn report_error() -> Weight { - // Proof Size summary in bytes: - // Measured: `281` - // Estimated: `3746` - // Minimum execution time: 53_715_000 picoseconds. - Weight::from_parts(54_860_000, 0) - .saturating_add(Weight::from_parts(0, 3746)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `XcmPallet::AssetTraps` (r:1 w:1) - /// Proof: `XcmPallet::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn claim_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `23` - // Estimated: `3488` - // Minimum execution time: 8_621_000 picoseconds. - Weight::from_parts(8_903_000, 0) - .saturating_add(Weight::from_parts(0, 3488)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - fn trap() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 1_211_000 picoseconds. - Weight::from_parts(1_281_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `XcmPallet::VersionNotifyTargets` (r:1 w:1) - /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) - /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn subscribe_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `180` - // Estimated: `3645` - // Minimum execution time: 26_448_000 picoseconds. - Weight::from_parts(27_057_000, 0) - .saturating_add(Weight::from_parts(0, 3645)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `XcmPallet::VersionNotifyTargets` (r:0 w:1) - /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn unsubscribe_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_498_000 picoseconds. - Weight::from_parts(3_614_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - fn burn_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 1_575_000 picoseconds. - Weight::from_parts(1_698_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn expect_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 1_334_000 picoseconds. - Weight::from_parts(1_435_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn expect_origin() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 1_244_000 picoseconds. - Weight::from_parts(1_337_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn expect_error() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 1_244_000 picoseconds. - Weight::from_parts(1_331_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn expect_transact_status() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 1_407_000 picoseconds. - Weight::from_parts(1_522_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) - /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn query_pallet() -> Weight { - // Proof Size summary in bytes: - // Measured: `281` - // Estimated: `3746` - // Minimum execution time: 62_963_000 picoseconds. - Weight::from_parts(64_556_000, 0) - .saturating_add(Weight::from_parts(0, 3746)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } - fn expect_pallet() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_458_000 picoseconds. - Weight::from_parts(8_741_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) - /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn report_transact_status() -> Weight { - // Proof Size summary in bytes: - // Measured: `281` - // Estimated: `3746` - // Minimum execution time: 54_068_000 picoseconds. - Weight::from_parts(55_665_000, 0) - .saturating_add(Weight::from_parts(0, 3746)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } - fn clear_transact_status() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 1_290_000 picoseconds. - Weight::from_parts(1_348_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn set_topic() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 1_189_000 picoseconds. - Weight::from_parts(1_268_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn clear_topic() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 1_197_000 picoseconds. - Weight::from_parts(1_276_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn set_fees_mode() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 1_197_000 picoseconds. - Weight::from_parts(1_253_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn unpaid_execution() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 1_250_000 picoseconds. - Weight::from_parts(1_354_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } -} diff --git a/polkadot/runtime/rococo/src/weights/runtime_common_assigned_slots.rs b/polkadot/runtime/rococo/src/weights/runtime_common_assigned_slots.rs index f41a5d4ebf8..a6beeded428 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_common_assigned_slots.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_common_assigned_slots.rs @@ -16,28 +16,26 @@ //! Autogenerated weights for `runtime_common::assigned_slots` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-08-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `runner-ynta1nyy-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet -// --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_common::assigned_slots // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/runtime_common_assigned_slots.rs +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --pallet=runtime_common::assigned_slots +// --chain=rococo-dev +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +48,7 @@ use core::marker::PhantomData; /// Weight functions for `runtime_common::assigned_slots`. pub struct WeightInfo(PhantomData); impl runtime_common::assigned_slots::WeightInfo for WeightInfo { - /// Storage: `Registrar::Paras` (r:1 w:0) + /// Storage: `Registrar::Paras` (r:1 w:1) /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Paras::ParaLifecycles` (r:1 w:1) /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -70,15 +68,15 @@ impl runtime_common::assigned_slots::WeightInfo for Wei /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) fn assign_perm_parachain_slot() -> Weight { // Proof Size summary in bytes: - // Measured: `730` - // Estimated: `4195` - // Minimum execution time: 71_337_000 picoseconds. - Weight::from_parts(80_807_000, 0) - .saturating_add(Weight::from_parts(0, 4195)) + // Measured: `673` + // Estimated: `4138` + // Minimum execution time: 84_646_000 picoseconds. + Weight::from_parts(91_791_000, 0) + .saturating_add(Weight::from_parts(0, 4138)) .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().writes(6)) } - /// Storage: `Registrar::Paras` (r:1 w:0) + /// Storage: `Registrar::Paras` (r:1 w:1) /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Paras::ParaLifecycles` (r:1 w:1) /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -100,13 +98,13 @@ impl runtime_common::assigned_slots::WeightInfo for Wei /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) fn assign_temp_parachain_slot() -> Weight { // Proof Size summary in bytes: - // Measured: `730` - // Estimated: `4195` - // Minimum execution time: 60_188_000 picoseconds. - Weight::from_parts(63_932_000, 0) - .saturating_add(Weight::from_parts(0, 4195)) + // Measured: `673` + // Estimated: `4138` + // Minimum execution time: 68_091_000 picoseconds. + Weight::from_parts(77_310_000, 0) + .saturating_add(Weight::from_parts(0, 4138)) .saturating_add(T::DbWeight::get().reads(10)) - .saturating_add(T::DbWeight::get().writes(6)) + .saturating_add(T::DbWeight::get().writes(7)) } /// Storage: `AssignedSlots::PermanentSlots` (r:1 w:0) /// Proof: `AssignedSlots::PermanentSlots` (`max_values`: None, `max_size`: Some(20), added: 2495, mode: `MaxEncodedLen`) @@ -120,11 +118,11 @@ impl runtime_common::assigned_slots::WeightInfo for Wei /// Proof: `AssignedSlots::TemporarySlotCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn unassign_parachain_slot() -> Weight { // Proof Size summary in bytes: - // Measured: `856` - // Estimated: `4321` - // Minimum execution time: 35_764_000 picoseconds. - Weight::from_parts(38_355_000, 0) - .saturating_add(Weight::from_parts(0, 4321)) + // Measured: `823` + // Estimated: `4288` + // Minimum execution time: 38_081_000 picoseconds. + Weight::from_parts(40_987_000, 0) + .saturating_add(Weight::from_parts(0, 4288)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -134,8 +132,8 @@ impl runtime_common::assigned_slots::WeightInfo for Wei // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_634_000 picoseconds. - Weight::from_parts(4_852_000, 0) + // Minimum execution time: 7_182_000 picoseconds. + Weight::from_parts(7_437_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -145,8 +143,8 @@ impl runtime_common::assigned_slots::WeightInfo for Wei // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_563_000 picoseconds. - Weight::from_parts(4_829_000, 0) + // Minimum execution time: 7_153_000 picoseconds. + Weight::from_parts(7_456_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/rococo/src/weights/runtime_common_auctions.rs b/polkadot/runtime/rococo/src/weights/runtime_common_auctions.rs index 2b756802289..3cd7c7a47e9 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_common_auctions.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_common_auctions.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `runtime_common::auctions` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: // ./target/production/polkadot @@ -29,15 +29,12 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --pallet=runtime_common::auctions // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/runtime_common_auctions.rs +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/runtime_common_auctions.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,90 +47,92 @@ use core::marker::PhantomData; /// Weight functions for `runtime_common::auctions`. pub struct WeightInfo(PhantomData); impl runtime_common::auctions::WeightInfo for WeightInfo { - /// Storage: `Auctions::AuctionInfo` (r:1 w:1) - /// Proof: `Auctions::AuctionInfo` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Auctions::AuctionCounter` (r:1 w:1) - /// Proof: `Auctions::AuctionCounter` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: Auctions AuctionInfo (r:1 w:1) + /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Auctions AuctionCounter (r:1 w:1) + /// Proof: Auctions AuctionCounter (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn new_auction() -> Weight { // Proof Size summary in bytes: // Measured: `4` // Estimated: `1493` - // Minimum execution time: 7_307_000 picoseconds. - Weight::from_parts(7_680_000, 0) + // Minimum execution time: 12_805_000 picoseconds. + Weight::from_parts(13_153_000, 0) .saturating_add(Weight::from_parts(0, 1493)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Paras::ParaLifecycles` (r:1 w:0) - /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Auctions::AuctionCounter` (r:1 w:0) - /// Proof: `Auctions::AuctionCounter` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Auctions::AuctionInfo` (r:1 w:0) - /// Proof: `Auctions::AuctionInfo` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Slots::Leases` (r:1 w:0) - /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Auctions::Winning` (r:1 w:1) - /// Proof: `Auctions::Winning` (`max_values`: None, `max_size`: Some(1920), added: 4395, mode: `MaxEncodedLen`) - /// Storage: `Auctions::ReservedAmounts` (r:2 w:2) - /// Proof: `Auctions::ReservedAmounts` (`max_values`: None, `max_size`: Some(60), added: 2535, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Paras ParaLifecycles (r:1 w:0) + /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) + /// Storage: Auctions AuctionCounter (r:1 w:0) + /// Proof: Auctions AuctionCounter (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Auctions AuctionInfo (r:1 w:0) + /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Slots Leases (r:1 w:0) + /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) + /// Storage: Auctions Winning (r:1 w:1) + /// Proof: Auctions Winning (max_values: None, max_size: Some(1920), added: 4395, mode: MaxEncodedLen) + /// Storage: Auctions ReservedAmounts (r:2 w:2) + /// Proof: Auctions ReservedAmounts (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn bid() -> Weight { // Proof Size summary in bytes: - // Measured: `761` + // Measured: `728` // Estimated: `6060` - // Minimum execution time: 75_448_000 picoseconds. - Weight::from_parts(78_716_000, 0) + // Minimum execution time: 77_380_000 picoseconds. + Weight::from_parts(80_503_000, 0) .saturating_add(Weight::from_parts(0, 6060)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: `Auctions::AuctionInfo` (r:1 w:1) - /// Proof: `Auctions::AuctionInfo` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Babe::NextRandomness` (r:1 w:0) - /// Proof: `Babe::NextRandomness` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `Babe::EpochStart` (r:1 w:0) - /// Proof: `Babe::EpochStart` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Auctions::AuctionCounter` (r:1 w:0) - /// Proof: `Auctions::AuctionCounter` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Auctions::Winning` (r:3600 w:3600) - /// Proof: `Auctions::Winning` (`max_values`: None, `max_size`: Some(1920), added: 4395, mode: `MaxEncodedLen`) - /// Storage: `Auctions::ReservedAmounts` (r:37 w:36) - /// Proof: `Auctions::ReservedAmounts` (`max_values`: None, `max_size`: Some(60), added: 2535, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:36 w:36) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Slots::Leases` (r:2 w:2) - /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::ParaLifecycles` (r:1 w:1) - /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::ActionsQueue` (r:1 w:1) - /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Auctions AuctionInfo (r:1 w:1) + /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Babe NextRandomness (r:1 w:0) + /// Proof: Babe NextRandomness (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: Babe EpochStart (r:1 w:0) + /// Proof: Babe EpochStart (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Auctions AuctionCounter (r:1 w:0) + /// Proof: Auctions AuctionCounter (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Auctions Winning (r:3600 w:3600) + /// Proof: Auctions Winning (max_values: None, max_size: Some(1920), added: 4395, mode: MaxEncodedLen) + /// Storage: Auctions ReservedAmounts (r:37 w:36) + /// Proof: Auctions ReservedAmounts (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Storage: System Account (r:36 w:36) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Slots Leases (r:2 w:2) + /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras ParaLifecycles (r:1 w:1) + /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) + /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) + /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras ActionsQueue (r:1 w:1) + /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) + /// Storage: Registrar Paras (r:1 w:1) + /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) fn on_initialize() -> Weight { // Proof Size summary in bytes: - // Measured: `6947017` + // Measured: `6947789` // Estimated: `15822990` - // Minimum execution time: 7_120_207_000 picoseconds. - Weight::from_parts(7_273_496_000, 0) + // Minimum execution time: 6_311_055_000 picoseconds. + Weight::from_parts(6_409_142_000, 0) .saturating_add(Weight::from_parts(0, 15822990)) - .saturating_add(T::DbWeight::get().reads(3682)) - .saturating_add(T::DbWeight::get().writes(3677)) + .saturating_add(T::DbWeight::get().reads(3683)) + .saturating_add(T::DbWeight::get().writes(3678)) } - /// Storage: `Auctions::ReservedAmounts` (r:37 w:36) - /// Proof: `Auctions::ReservedAmounts` (`max_values`: None, `max_size`: Some(60), added: 2535, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:36 w:36) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Auctions::Winning` (r:3600 w:3600) - /// Proof: `Auctions::Winning` (`max_values`: None, `max_size`: Some(1920), added: 4395, mode: `MaxEncodedLen`) - /// Storage: `Auctions::AuctionInfo` (r:0 w:1) - /// Proof: `Auctions::AuctionInfo` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: Auctions ReservedAmounts (r:37 w:36) + /// Proof: Auctions ReservedAmounts (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Storage: System Account (r:36 w:36) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Auctions Winning (r:3600 w:3600) + /// Proof: Auctions Winning (max_values: None, max_size: Some(1920), added: 4395, mode: MaxEncodedLen) + /// Storage: Auctions AuctionInfo (r:0 w:1) + /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) fn cancel_auction() -> Weight { // Proof Size summary in bytes: // Measured: `177732` // Estimated: `15822990` - // Minimum execution time: 5_536_281_000 picoseconds. - Weight::from_parts(5_675_163_000, 0) + // Minimum execution time: 4_849_561_000 picoseconds. + Weight::from_parts(4_955_226_000, 0) .saturating_add(Weight::from_parts(0, 15822990)) .saturating_add(T::DbWeight::get().reads(3673)) .saturating_add(T::DbWeight::get().writes(3673)) diff --git a/polkadot/runtime/rococo/src/weights/runtime_common_claims.rs b/polkadot/runtime/rococo/src/weights/runtime_common_claims.rs index de2bb71933b..52e0dd24afa 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_common_claims.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_common_claims.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `runtime_common::claims` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: // ./target/production/polkadot @@ -29,15 +29,12 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --pallet=runtime_common::claims // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/runtime_common_claims.rs +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/runtime_common_claims.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,133 +47,120 @@ use core::marker::PhantomData; /// Weight functions for `runtime_common::claims`. pub struct WeightInfo(PhantomData); impl runtime_common::claims::WeightInfo for WeightInfo { - /// Storage: `Claims::Claims` (r:1 w:1) - /// Proof: `Claims::Claims` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Claims::Signing` (r:1 w:1) - /// Proof: `Claims::Signing` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Claims::Total` (r:1 w:1) - /// Proof: `Claims::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Claims::Vesting` (r:1 w:1) - /// Proof: `Claims::Vesting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Vesting::Vesting` (r:1 w:1) - /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:0) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: Claims Claims (r:1 w:1) + /// Proof Skipped: Claims Claims (max_values: None, max_size: None, mode: Measured) + /// Storage: Claims Signing (r:1 w:1) + /// Proof Skipped: Claims Signing (max_values: None, max_size: None, mode: Measured) + /// Storage: Claims Total (r:1 w:1) + /// Proof Skipped: Claims Total (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Claims Vesting (r:1 w:1) + /// Proof Skipped: Claims Vesting (max_values: None, max_size: None, mode: Measured) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) fn claim() -> Weight { // Proof Size summary in bytes: // Measured: `558` // Estimated: `4764` - // Minimum execution time: 181_028_000 picoseconds. - Weight::from_parts(194_590_000, 0) + // Minimum execution time: 144_931_000 picoseconds. + Weight::from_parts(156_550_000, 0) .saturating_add(Weight::from_parts(0, 4764)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(6)) } - /// Storage: `Claims::Total` (r:1 w:1) - /// Proof: `Claims::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Claims::Vesting` (r:0 w:1) - /// Proof: `Claims::Vesting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Claims::Claims` (r:0 w:1) - /// Proof: `Claims::Claims` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Claims::Signing` (r:0 w:1) - /// Proof: `Claims::Signing` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Claims Total (r:1 w:1) + /// Proof Skipped: Claims Total (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Claims Vesting (r:0 w:1) + /// Proof Skipped: Claims Vesting (max_values: None, max_size: None, mode: Measured) + /// Storage: Claims Claims (r:0 w:1) + /// Proof Skipped: Claims Claims (max_values: None, max_size: None, mode: Measured) + /// Storage: Claims Signing (r:0 w:1) + /// Proof Skipped: Claims Signing (max_values: None, max_size: None, mode: Measured) fn mint_claim() -> Weight { // Proof Size summary in bytes: // Measured: `216` // Estimated: `1701` - // Minimum execution time: 11_224_000 picoseconds. - Weight::from_parts(13_342_000, 0) + // Minimum execution time: 11_300_000 picoseconds. + Weight::from_parts(11_642_000, 0) .saturating_add(Weight::from_parts(0, 1701)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: `Claims::Claims` (r:1 w:1) - /// Proof: `Claims::Claims` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Claims::Signing` (r:1 w:1) - /// Proof: `Claims::Signing` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Claims::Total` (r:1 w:1) - /// Proof: `Claims::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Claims::Vesting` (r:1 w:1) - /// Proof: `Claims::Vesting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Vesting::Vesting` (r:1 w:1) - /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:0) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: Claims Claims (r:1 w:1) + /// Proof Skipped: Claims Claims (max_values: None, max_size: None, mode: Measured) + /// Storage: Claims Signing (r:1 w:1) + /// Proof Skipped: Claims Signing (max_values: None, max_size: None, mode: Measured) + /// Storage: Claims Total (r:1 w:1) + /// Proof Skipped: Claims Total (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Claims Vesting (r:1 w:1) + /// Proof Skipped: Claims Vesting (max_values: None, max_size: None, mode: Measured) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) fn claim_attest() -> Weight { // Proof Size summary in bytes: // Measured: `558` // Estimated: `4764` - // Minimum execution time: 187_964_000 picoseconds. - Weight::from_parts(202_553_000, 0) + // Minimum execution time: 149_112_000 picoseconds. + Weight::from_parts(153_872_000, 0) .saturating_add(Weight::from_parts(0, 4764)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(6)) } - /// Storage: `Claims::Preclaims` (r:1 w:1) - /// Proof: `Claims::Preclaims` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Claims::Signing` (r:1 w:1) - /// Proof: `Claims::Signing` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Claims::Claims` (r:1 w:1) - /// Proof: `Claims::Claims` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Claims::Total` (r:1 w:1) - /// Proof: `Claims::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Claims::Vesting` (r:1 w:1) - /// Proof: `Claims::Vesting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Vesting::Vesting` (r:1 w:1) - /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:0) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: Claims Preclaims (r:1 w:1) + /// Proof Skipped: Claims Preclaims (max_values: None, max_size: None, mode: Measured) + /// Storage: Claims Signing (r:1 w:1) + /// Proof Skipped: Claims Signing (max_values: None, max_size: None, mode: Measured) + /// Storage: Claims Claims (r:1 w:1) + /// Proof Skipped: Claims Claims (max_values: None, max_size: None, mode: Measured) + /// Storage: Claims Total (r:1 w:1) + /// Proof Skipped: Claims Total (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Claims Vesting (r:1 w:1) + /// Proof Skipped: Claims Vesting (max_values: None, max_size: None, mode: Measured) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) fn attest() -> Weight { // Proof Size summary in bytes: // Measured: `632` // Estimated: `4764` - // Minimum execution time: 78_210_000 picoseconds. - Weight::from_parts(84_581_000, 0) + // Minimum execution time: 69_619_000 picoseconds. + Weight::from_parts(79_242_000, 0) .saturating_add(Weight::from_parts(0, 4764)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(7)) } - /// Storage: `Claims::Claims` (r:1 w:2) - /// Proof: `Claims::Claims` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Claims::Vesting` (r:1 w:2) - /// Proof: `Claims::Vesting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Claims::Signing` (r:1 w:2) - /// Proof: `Claims::Signing` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Claims::Preclaims` (r:1 w:1) - /// Proof: `Claims::Preclaims` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Claims Claims (r:1 w:2) + /// Proof Skipped: Claims Claims (max_values: None, max_size: None, mode: Measured) + /// Storage: Claims Vesting (r:1 w:2) + /// Proof Skipped: Claims Vesting (max_values: None, max_size: None, mode: Measured) + /// Storage: Claims Signing (r:1 w:2) + /// Proof Skipped: Claims Signing (max_values: None, max_size: None, mode: Measured) + /// Storage: Claims Preclaims (r:1 w:1) + /// Proof Skipped: Claims Preclaims (max_values: None, max_size: None, mode: Measured) fn move_claim() -> Weight { // Proof Size summary in bytes: // Measured: `440` // Estimated: `3905` - // Minimum execution time: 33_940_000 picoseconds. - Weight::from_parts(48_438_000, 0) + // Minimum execution time: 22_066_000 picoseconds. + Weight::from_parts(22_483_000, 0) .saturating_add(Weight::from_parts(0, 3905)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(7)) } - /// Storage: `Claims::Preclaims` (r:1 w:0) - /// Proof: `Claims::Preclaims` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Claims::Signing` (r:1 w:0) - /// Proof: `Claims::Signing` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn prevalidate_attests() -> Weight { - // Proof Size summary in bytes: - // Measured: `296` - // Estimated: `3761` - // Minimum execution time: 9_025_000 picoseconds. - Weight::from_parts(10_563_000, 0) - .saturating_add(Weight::from_parts(0, 3761)) - .saturating_add(T::DbWeight::get().reads(2)) - } } diff --git a/polkadot/runtime/rococo/src/weights/runtime_common_coretime.rs b/polkadot/runtime/rococo/src/weights/runtime_common_coretime.rs deleted file mode 100644 index d068f07e759..00000000000 --- a/polkadot/runtime/rococo/src/weights/runtime_common_coretime.rs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `runtime_common::coretime` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=rococo-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_common::coretime -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/runtime_common_coretime.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `runtime_common::coretime`. -pub struct WeightInfo(PhantomData); -impl runtime_common::coretime::WeightInfo for WeightInfo { - /// Storage: `Configuration::PendingConfigs` (r:1 w:1) - /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) - /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn request_core_count() -> Weight { - // Proof Size summary in bytes: - // Measured: `151` - // Estimated: `1636` - // Minimum execution time: 7_543_000 picoseconds. - Weight::from_parts(7_745_000, 0) - .saturating_add(Weight::from_parts(0, 1636)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) - /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `CoretimeAssignmentProvider::CoreSchedules` (r:0 w:1) - /// Proof: `CoretimeAssignmentProvider::CoreSchedules` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `s` is `[1, 100]`. - fn assign_core(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `180` - // Estimated: `3645` - // Minimum execution time: 9_367_000 picoseconds. - Weight::from_parts(9_932_305, 0) - .saturating_add(Weight::from_parts(0, 3645)) - // Standard Error: 231 - .saturating_add(Weight::from_parts(12_947, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} diff --git a/polkadot/runtime/rococo/src/weights/runtime_common_crowdloan.rs b/polkadot/runtime/rococo/src/weights/runtime_common_crowdloan.rs index 8ebab3d551e..0e7420cba2e 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_common_crowdloan.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_common_crowdloan.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `runtime_common::crowdloan` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: // ./target/production/polkadot @@ -29,15 +29,12 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --pallet=runtime_common::crowdloan // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/runtime_common_crowdloan.rs +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/runtime_common_crowdloan.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,168 +47,172 @@ use core::marker::PhantomData; /// Weight functions for `runtime_common::crowdloan`. pub struct WeightInfo(PhantomData); impl runtime_common::crowdloan::WeightInfo for WeightInfo { - /// Storage: `Crowdloan::Funds` (r:1 w:1) - /// Proof: `Crowdloan::Funds` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Registrar::Paras` (r:1 w:0) - /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::ParaLifecycles` (r:1 w:0) - /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Crowdloan::NextFundIndex` (r:1 w:1) - /// Proof: `Crowdloan::NextFundIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Crowdloan Funds (r:1 w:1) + /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) + /// Storage: Registrar Paras (r:1 w:1) + /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras ParaLifecycles (r:1 w:0) + /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) + /// Storage: Crowdloan NextFundIndex (r:1 w:1) + /// Proof Skipped: Crowdloan NextFundIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: // Measured: `438` // Estimated: `3903` - // Minimum execution time: 46_095_000 picoseconds. - Weight::from_parts(48_111_000, 0) + // Minimum execution time: 50_399_000 picoseconds. + Weight::from_parts(51_641_000, 0) .saturating_add(Weight::from_parts(0, 3903)) .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: `Crowdloan::Funds` (r:1 w:1) - /// Proof: `Crowdloan::Funds` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Slots::Leases` (r:1 w:0) - /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Auctions::AuctionInfo` (r:1 w:0) - /// Proof: `Auctions::AuctionInfo` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Crowdloan::EndingsCount` (r:1 w:0) - /// Proof: `Crowdloan::EndingsCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Crowdloan::NewRaise` (r:1 w:1) - /// Proof: `Crowdloan::NewRaise` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: UNKNOWN KEY `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) + /// Storage: Crowdloan Funds (r:1 w:1) + /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) + /// Storage: Slots Leases (r:1 w:0) + /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) + /// Storage: Auctions AuctionInfo (r:1 w:0) + /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances InactiveIssuance (r:1 w:1) + /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Crowdloan EndingsCount (r:1 w:0) + /// Proof Skipped: Crowdloan EndingsCount (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Crowdloan NewRaise (r:1 w:1) + /// Proof Skipped: Crowdloan NewRaise (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) + /// Proof Skipped: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) fn contribute() -> Weight { // Proof Size summary in bytes: - // Measured: `563` - // Estimated: `4028` - // Minimum execution time: 133_059_000 picoseconds. - Weight::from_parts(136_515_000, 0) - .saturating_add(Weight::from_parts(0, 4028)) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(4)) + // Measured: `530` + // Estimated: `3995` + // Minimum execution time: 128_898_000 picoseconds. + Weight::from_parts(130_277_000, 0) + .saturating_add(Weight::from_parts(0, 3995)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(5)) } - /// Storage: `Crowdloan::Funds` (r:1 w:1) - /// Proof: `Crowdloan::Funds` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0xc85982571aa615c788ef9b2c16f54f25773fd439e8ee1ed2aa3ae43d48e880f0` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xc85982571aa615c788ef9b2c16f54f25773fd439e8ee1ed2aa3ae43d48e880f0` (r:1 w:1) + /// Storage: Crowdloan Funds (r:1 w:1) + /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances InactiveIssuance (r:1 w:1) + /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: unknown `0xc85982571aa615c788ef9b2c16f54f25773fd439e8ee1ed2aa3ae43d48e880f0` (r:1 w:1) + /// Proof Skipped: unknown `0xc85982571aa615c788ef9b2c16f54f25773fd439e8ee1ed2aa3ae43d48e880f0` (r:1 w:1) fn withdraw() -> Weight { // Proof Size summary in bytes: - // Measured: `687` + // Measured: `689` // Estimated: `6196` - // Minimum execution time: 71_733_000 picoseconds. - Weight::from_parts(74_034_000, 0) + // Minimum execution time: 69_543_000 picoseconds. + Weight::from_parts(71_522_000, 0) .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) } - /// Storage: `Skipped::Metadata` (r:0 w:0) - /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `k` is `[0, 1000]`. fn refund(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `125 + k * (189 ±0)` - // Estimated: `138 + k * (189 ±0)` - // Minimum execution time: 46_016_000 picoseconds. - Weight::from_parts(48_260_000, 0) - .saturating_add(Weight::from_parts(0, 138)) - // Standard Error: 21_140 - .saturating_add(Weight::from_parts(39_141_925, 0).saturating_mul(k.into())) - .saturating_add(T::DbWeight::get().reads(3)) + // Measured: `127 + k * (189 ±0)` + // Estimated: `140 + k * (189 ±0)` + // Minimum execution time: 50_735_000 picoseconds. + Weight::from_parts(52_282_000, 0) + .saturating_add(Weight::from_parts(0, 140)) + // Standard Error: 21_607 + .saturating_add(Weight::from_parts(38_955_985, 0).saturating_mul(k.into())) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(k.into()))) - .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes(3)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(k.into()))) .saturating_add(Weight::from_parts(0, 189).saturating_mul(k.into())) } - /// Storage: `Crowdloan::Funds` (r:1 w:1) - /// Proof: `Crowdloan::Funds` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Crowdloan Funds (r:1 w:1) + /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn dissolve() -> Weight { // Proof Size summary in bytes: - // Measured: `514` + // Measured: `515` // Estimated: `6196` - // Minimum execution time: 44_724_000 picoseconds. - Weight::from_parts(47_931_000, 0) + // Minimum execution time: 43_100_000 picoseconds. + Weight::from_parts(44_272_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `Crowdloan::Funds` (r:1 w:1) - /// Proof: `Crowdloan::Funds` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Crowdloan Funds (r:1 w:1) + /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) fn edit() -> Weight { // Proof Size summary in bytes: - // Measured: `234` - // Estimated: `3699` - // Minimum execution time: 19_512_000 picoseconds. - Weight::from_parts(21_129_000, 0) - .saturating_add(Weight::from_parts(0, 3699)) + // Measured: `235` + // Estimated: `3700` + // Minimum execution time: 18_702_000 picoseconds. + Weight::from_parts(19_408_000, 0) + .saturating_add(Weight::from_parts(0, 3700)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Crowdloan::Funds` (r:1 w:0) - /// Proof: `Crowdloan::Funds` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: UNKNOWN KEY `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) - /// Proof: UNKNOWN KEY `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) + /// Storage: Crowdloan Funds (r:1 w:0) + /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) + /// Storage: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) + /// Proof Skipped: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) fn add_memo() -> Weight { // Proof Size summary in bytes: // Measured: `412` // Estimated: `3877` - // Minimum execution time: 33_529_000 picoseconds. - Weight::from_parts(37_082_000, 0) + // Minimum execution time: 25_568_000 picoseconds. + Weight::from_parts(26_203_000, 0) .saturating_add(Weight::from_parts(0, 3877)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Crowdloan::Funds` (r:1 w:0) - /// Proof: `Crowdloan::Funds` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Crowdloan::NewRaise` (r:1 w:1) - /// Proof: `Crowdloan::NewRaise` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Crowdloan Funds (r:1 w:0) + /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) + /// Storage: Crowdloan NewRaise (r:1 w:1) + /// Proof Skipped: Crowdloan NewRaise (max_values: Some(1), max_size: None, mode: Measured) fn poke() -> Weight { // Proof Size summary in bytes: - // Measured: `238` - // Estimated: `3703` - // Minimum execution time: 23_153_000 picoseconds. - Weight::from_parts(24_181_000, 0) - .saturating_add(Weight::from_parts(0, 3703)) + // Measured: `239` + // Estimated: `3704` + // Minimum execution time: 17_832_000 picoseconds. + Weight::from_parts(18_769_000, 0) + .saturating_add(Weight::from_parts(0, 3704)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Auctions::AuctionInfo` (r:1 w:0) - /// Proof: `Auctions::AuctionInfo` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Crowdloan::EndingsCount` (r:1 w:1) - /// Proof: `Crowdloan::EndingsCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Crowdloan::NewRaise` (r:1 w:1) - /// Proof: `Crowdloan::NewRaise` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Crowdloan::Funds` (r:100 w:0) - /// Proof: `Crowdloan::Funds` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Auctions::AuctionCounter` (r:1 w:0) - /// Proof: `Auctions::AuctionCounter` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Paras::ParaLifecycles` (r:100 w:0) - /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Slots::Leases` (r:100 w:0) - /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Auctions::Winning` (r:1 w:1) - /// Proof: `Auctions::Winning` (`max_values`: None, `max_size`: Some(1920), added: 4395, mode: `MaxEncodedLen`) - /// Storage: `Auctions::ReservedAmounts` (r:100 w:100) - /// Proof: `Auctions::ReservedAmounts` (`max_values`: None, `max_size`: Some(60), added: 2535, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:100 w:100) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Auctions AuctionInfo (r:1 w:0) + /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Crowdloan EndingsCount (r:1 w:1) + /// Proof Skipped: Crowdloan EndingsCount (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Crowdloan NewRaise (r:1 w:1) + /// Proof Skipped: Crowdloan NewRaise (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Crowdloan Funds (r:100 w:0) + /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) + /// Storage: Auctions AuctionCounter (r:1 w:0) + /// Proof: Auctions AuctionCounter (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Paras ParaLifecycles (r:100 w:0) + /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) + /// Storage: Slots Leases (r:100 w:0) + /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) + /// Storage: Auctions Winning (r:1 w:1) + /// Proof: Auctions Winning (max_values: None, max_size: Some(1920), added: 4395, mode: MaxEncodedLen) + /// Storage: Auctions ReservedAmounts (r:100 w:100) + /// Proof: Auctions ReservedAmounts (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) + /// Storage: System Account (r:100 w:100) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `n` is `[2, 100]`. fn on_initialize(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `229 + n * (356 ±0)` + // Measured: `197 + n * (356 ±0)` // Estimated: `5385 + n * (2832 ±0)` - // Minimum execution time: 120_164_000 picoseconds. - Weight::from_parts(3_390_119, 0) + // Minimum execution time: 128_319_000 picoseconds. + Weight::from_parts(130_877_000, 0) .saturating_add(Weight::from_parts(0, 5385)) - // Standard Error: 41_727 - .saturating_add(Weight::from_parts(54_453_016, 0).saturating_mul(n.into())) + // Standard Error: 61_381 + .saturating_add(Weight::from_parts(60_209_202, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(3)) diff --git a/polkadot/runtime/rococo/src/weights/runtime_common_identity_migrator.rs b/polkadot/runtime/rococo/src/weights/runtime_common_identity_migrator.rs index 9b0cb98e6c0..cec357453b6 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_common_identity_migrator.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_common_identity_migrator.rs @@ -1,43 +1,36 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. +// SPDX-License-Identifier: Apache-2.0 -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! Autogenerated weights for `runtime_common::identity_migrator` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-11-07, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `sbtb`, CPU: `13th Gen Intel(R) Core(TM) i7-1365U` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// ./target/release/polkadot // benchmark // pallet // --chain=rococo-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares +// --steps=2 +// --repeat=1 // --pallet=runtime_common::identity_migrator // --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/runtime_common_identity_migrator.rs +// --output=./migrator-release.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -51,7 +44,7 @@ use core::marker::PhantomData; pub struct WeightInfo(PhantomData); impl runtime_common::identity_migrator::WeightInfo for WeightInfo { /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) /// Storage: `Identity::SubsOf` (r:1 w:1) /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:2 w:2) @@ -70,34 +63,34 @@ impl runtime_common::identity_migrator::WeightInfo for /// The range of component `s` is `[0, 100]`. fn reap_identity(r: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `7457 + r * (5 ±0) + s * (32 ±0)` - // Estimated: `11037 + r * (7 ±0) + s * (32 ±0)` - // Minimum execution time: 157_343_000 picoseconds. - Weight::from_parts(159_289_236, 0) - .saturating_add(Weight::from_parts(0, 11037)) - // Standard Error: 16_439 - .saturating_add(Weight::from_parts(224_293, 0).saturating_mul(r.into())) - // Standard Error: 3_367 - .saturating_add(Weight::from_parts(1_383_637, 0).saturating_mul(s.into())) + // Measured: `7292 + r * (8 ±0) + s * (32 ±0)` + // Estimated: `11003 + r * (8 ±0) + s * (33 ±0)` + // Minimum execution time: 163_756_000 picoseconds. + Weight::from_parts(158_982_500, 0) + .saturating_add(Weight::from_parts(0, 11003)) + // Standard Error: 1_143_629 + .saturating_add(Weight::from_parts(238_675, 0).saturating_mul(r.into())) + // Standard Error: 228_725 + .saturating_add(Weight::from_parts(1_529_645, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(6)) + .saturating_add(T::DbWeight::get().writes(5)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) - .saturating_add(Weight::from_parts(0, 7).saturating_mul(r.into())) - .saturating_add(Weight::from_parts(0, 32).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 33).saturating_mul(s.into())) } /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Identity::SubsOf` (r:1 w:1) /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) fn poke_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `7242` - // Estimated: `11037` - // Minimum execution time: 114_384_000 picoseconds. - Weight::from_parts(115_741_000, 0) - .saturating_add(Weight::from_parts(0, 11037)) + // Measured: `7229` + // Estimated: `11003` + // Minimum execution time: 137_570_000 picoseconds. + Weight::from_parts(137_570_000, 0) + .saturating_add(Weight::from_parts(0, 11003)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } diff --git a/polkadot/runtime/rococo/src/weights/runtime_common_paras_registrar.rs b/polkadot/runtime/rococo/src/weights/runtime_common_paras_registrar.rs index e066106e134..0a56562a1a9 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_common_paras_registrar.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_common_paras_registrar.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `runtime_common::paras_registrar` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: // ./target/production/polkadot @@ -29,15 +29,12 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --pallet=runtime_common::paras_registrar // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/runtime_common_paras_registrar.rs +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/runtime_common_paras_registrar.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,169 +47,175 @@ use core::marker::PhantomData; /// Weight functions for `runtime_common::paras_registrar`. pub struct WeightInfo(PhantomData); impl runtime_common::paras_registrar::WeightInfo for WeightInfo { - /// Storage: `Registrar::NextFreeParaId` (r:1 w:1) - /// Proof: `Registrar::NextFreeParaId` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Registrar::Paras` (r:1 w:1) - /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::ParaLifecycles` (r:1 w:0) - /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Registrar NextFreeParaId (r:1 w:1) + /// Proof Skipped: Registrar NextFreeParaId (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Registrar Paras (r:1 w:1) + /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras ParaLifecycles (r:1 w:0) + /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) fn reserve() -> Weight { // Proof Size summary in bytes: - // Measured: `96` - // Estimated: `3561` - // Minimum execution time: 24_109_000 picoseconds. - Weight::from_parts(24_922_000, 0) - .saturating_add(Weight::from_parts(0, 3561)) + // Measured: `97` + // Estimated: `3562` + // Minimum execution time: 29_948_000 picoseconds. + Weight::from_parts(30_433_000, 0) + .saturating_add(Weight::from_parts(0, 3562)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Registrar::Paras` (r:1 w:1) - /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::ParaLifecycles` (r:1 w:1) - /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) - /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::CodeByHash` (r:1 w:1) - /// Proof: `Paras::CodeByHash` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) - /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::PvfActiveVoteList` (r:1 w:1) - /// Proof: `Paras::PvfActiveVoteList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::CodeByHashRefs` (r:1 w:1) - /// Proof: `Paras::CodeByHashRefs` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::CurrentCodeHash` (r:0 w:1) - /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::UpcomingParasGenesis` (r:0 w:1) - /// Proof: `Paras::UpcomingParasGenesis` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Registrar Paras (r:1 w:1) + /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras ParaLifecycles (r:1 w:1) + /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) + /// Storage: Configuration ActiveConfig (r:1 w:0) + /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras PvfActiveVoteMap (r:1 w:1) + /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras CodeByHash (r:1 w:1) + /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) + /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) + /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras PvfActiveVoteList (r:1 w:1) + /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras CodeByHashRefs (r:1 w:1) + /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras CurrentCodeHash (r:0 w:1) + /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras UpcomingParasGenesis (r:0 w:1) + /// Proof Skipped: Paras UpcomingParasGenesis (max_values: None, max_size: None, mode: Measured) fn register() -> Weight { // Proof Size summary in bytes: - // Measured: `352` - // Estimated: `3817` - // Minimum execution time: 7_207_580_000 picoseconds. - Weight::from_parts(7_298_567_000, 0) - .saturating_add(Weight::from_parts(0, 3817)) - .saturating_add(T::DbWeight::get().reads(7)) + // Measured: `616` + // Estimated: `4081` + // Minimum execution time: 6_332_113_000 picoseconds. + Weight::from_parts(6_407_158_000, 0) + .saturating_add(Weight::from_parts(0, 4081)) + .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(8)) } - /// Storage: `Registrar::Paras` (r:1 w:1) - /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::ParaLifecycles` (r:1 w:1) - /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) - /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::CodeByHash` (r:1 w:1) - /// Proof: `Paras::CodeByHash` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) - /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::PvfActiveVoteList` (r:1 w:1) - /// Proof: `Paras::PvfActiveVoteList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::CodeByHashRefs` (r:1 w:1) - /// Proof: `Paras::CodeByHashRefs` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::CurrentCodeHash` (r:0 w:1) - /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::UpcomingParasGenesis` (r:0 w:1) - /// Proof: `Paras::UpcomingParasGenesis` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Registrar Paras (r:1 w:1) + /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras ParaLifecycles (r:1 w:1) + /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) + /// Storage: Configuration ActiveConfig (r:1 w:0) + /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras PvfActiveVoteMap (r:1 w:1) + /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras CodeByHash (r:1 w:1) + /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) + /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) + /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras PvfActiveVoteList (r:1 w:1) + /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras CodeByHashRefs (r:1 w:1) + /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras CurrentCodeHash (r:0 w:1) + /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras UpcomingParasGenesis (r:0 w:1) + /// Proof Skipped: Paras UpcomingParasGenesis (max_values: None, max_size: None, mode: Measured) fn force_register() -> Weight { // Proof Size summary in bytes: - // Measured: `269` - // Estimated: `3734` - // Minimum execution time: 7_196_460_000 picoseconds. - Weight::from_parts(7_385_729_000, 0) - .saturating_add(Weight::from_parts(0, 3734)) - .saturating_add(T::DbWeight::get().reads(7)) + // Measured: `533` + // Estimated: `3998` + // Minimum execution time: 6_245_403_000 picoseconds. + Weight::from_parts(6_289_575_000, 0) + .saturating_add(Weight::from_parts(0, 3998)) + .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(8)) } - /// Storage: `Registrar::Paras` (r:1 w:1) - /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::ParaLifecycles` (r:1 w:1) - /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::FutureCodeHash` (r:1 w:0) - /// Proof: `Paras::FutureCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::ActionsQueue` (r:1 w:1) - /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:0) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) - /// Storage: `Registrar::PendingSwap` (r:0 w:1) - /// Proof: `Registrar::PendingSwap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Registrar Paras (r:1 w:1) + /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras ParaLifecycles (r:1 w:1) + /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras FutureCodeHash (r:1 w:0) + /// Proof Skipped: Paras FutureCodeHash (max_values: None, max_size: None, mode: Measured) + /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) + /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras ActionsQueue (r:1 w:1) + /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) + /// Storage: MessageQueue BookStateFor (r:1 w:0) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) + /// Storage: Registrar PendingSwap (r:0 w:1) + /// Proof Skipped: Registrar PendingSwap (max_values: None, max_size: None, mode: Measured) fn deregister() -> Weight { // Proof Size summary in bytes: - // Measured: `499` - // Estimated: `3964` - // Minimum execution time: 54_761_000 picoseconds. - Weight::from_parts(57_931_000, 0) - .saturating_add(Weight::from_parts(0, 3964)) + // Measured: `476` + // Estimated: `3941` + // Minimum execution time: 49_822_000 picoseconds. + Weight::from_parts(50_604_000, 0) + .saturating_add(Weight::from_parts(0, 3941)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: `Registrar::Paras` (r:1 w:0) - /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::ParaLifecycles` (r:2 w:2) - /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Registrar::PendingSwap` (r:1 w:1) - /// Proof: `Registrar::PendingSwap` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::ActionsQueue` (r:1 w:1) - /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Crowdloan::Funds` (r:2 w:2) - /// Proof: `Crowdloan::Funds` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Slots::Leases` (r:2 w:2) - /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Registrar Paras (r:1 w:0) + /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras ParaLifecycles (r:2 w:2) + /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) + /// Storage: Registrar PendingSwap (r:1 w:1) + /// Proof Skipped: Registrar PendingSwap (max_values: None, max_size: None, mode: Measured) + /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) + /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras ActionsQueue (r:1 w:1) + /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) + /// Storage: Crowdloan Funds (r:2 w:2) + /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) + /// Storage: Slots Leases (r:2 w:2) + /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) fn swap() -> Weight { // Proof Size summary in bytes: - // Measured: `837` - // Estimated: `6777` - // Minimum execution time: 59_564_000 picoseconds. - Weight::from_parts(62_910_000, 0) - .saturating_add(Weight::from_parts(0, 6777)) + // Measured: `780` + // Estimated: `6720` + // Minimum execution time: 55_166_000 picoseconds. + Weight::from_parts(56_913_000, 0) + .saturating_add(Weight::from_parts(0, 6720)) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(8)) } - /// Storage: `Paras::FutureCodeHash` (r:1 w:1) - /// Proof: `Paras::FutureCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::UpgradeRestrictionSignal` (r:1 w:1) - /// Proof: `Paras::UpgradeRestrictionSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::CurrentCodeHash` (r:1 w:0) - /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::UpgradeCooldowns` (r:1 w:1) - /// Proof: `Paras::UpgradeCooldowns` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) - /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::CodeByHash` (r:1 w:1) - /// Proof: `Paras::CodeByHash` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) - /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::PvfActiveVoteList` (r:1 w:1) - /// Proof: `Paras::PvfActiveVoteList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::CodeByHashRefs` (r:1 w:1) - /// Proof: `Paras::CodeByHashRefs` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `b` is `[9, 3145728]`. + /// Storage: Paras FutureCodeHash (r:1 w:1) + /// Proof Skipped: Paras FutureCodeHash (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras UpgradeRestrictionSignal (r:1 w:1) + /// Proof Skipped: Paras UpgradeRestrictionSignal (max_values: None, max_size: None, mode: Measured) + /// Storage: Configuration ActiveConfig (r:1 w:0) + /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras CurrentCodeHash (r:1 w:0) + /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras UpgradeCooldowns (r:1 w:1) + /// Proof Skipped: Paras UpgradeCooldowns (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras PvfActiveVoteMap (r:1 w:1) + /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras CodeByHash (r:1 w:1) + /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) + /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) + /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras PvfActiveVoteList (r:1 w:1) + /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras CodeByHashRefs (r:1 w:1) + /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) + /// The range of component `b` is `[1, 3145728]`. fn schedule_code_upgrade(b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `201` - // Estimated: `3666` - // Minimum execution time: 33_106_000 picoseconds. - Weight::from_parts(33_526_000, 0) - .saturating_add(Weight::from_parts(0, 3666)) - // Standard Error: 2 - .saturating_add(Weight::from_parts(2_334, 0).saturating_mul(b.into())) - .saturating_add(T::DbWeight::get().reads(9)) + // Measured: `464` + // Estimated: `3929` + // Minimum execution time: 43_650_000 picoseconds. + Weight::from_parts(43_918_000, 0) + .saturating_add(Weight::from_parts(0, 3929)) + // Standard Error: 6 + .saturating_add(Weight::from_parts(2_041, 0).saturating_mul(b.into())) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(7)) } - /// Storage: `Paras::Heads` (r:0 w:1) - /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Paras Heads (r:0 w:1) + /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) /// The range of component `b` is `[1, 1048576]`. fn set_current_head(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_992_000 picoseconds. - Weight::from_parts(12_059_689, 0) + // Minimum execution time: 8_666_000 picoseconds. + Weight::from_parts(8_893_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 0 - .saturating_add(Weight::from_parts(959, 0).saturating_mul(b.into())) + // Standard Error: 2 + .saturating_add(Weight::from_parts(855, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/polkadot/runtime/rococo/src/weights/runtime_common_slots.rs b/polkadot/runtime/rococo/src/weights/runtime_common_slots.rs index dd10dbbf1f1..23ab1ed3ee0 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_common_slots.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_common_slots.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `runtime_common::slots` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: // ./target/production/polkadot @@ -29,15 +29,12 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --pallet=runtime_common::slots // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/runtime_common_slots.rs +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/runtime_common_slots.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,82 +47,86 @@ use core::marker::PhantomData; /// Weight functions for `runtime_common::slots`. pub struct WeightInfo(PhantomData); impl runtime_common::slots::WeightInfo for WeightInfo { - /// Storage: `Slots::Leases` (r:1 w:1) - /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Slots Leases (r:1 w:1) + /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_lease() -> Weight { // Proof Size summary in bytes: - // Measured: `320` - // Estimated: `3785` - // Minimum execution time: 26_570_000 picoseconds. - Weight::from_parts(27_619_000, 0) - .saturating_add(Weight::from_parts(0, 3785)) + // Measured: `287` + // Estimated: `3752` + // Minimum execution time: 29_932_000 picoseconds. + Weight::from_parts(30_334_000, 0) + .saturating_add(Weight::from_parts(0, 3752)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `Paras::Parachains` (r:1 w:0) - /// Proof: `Paras::Parachains` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Slots::Leases` (r:101 w:100) - /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::ParaLifecycles` (r:200 w:200) - /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::ActionsQueue` (r:1 w:1) - /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Paras Parachains (r:1 w:0) + /// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Slots Leases (r:101 w:100) + /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras ParaLifecycles (r:200 w:200) + /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) + /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) + /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras ActionsQueue (r:1 w:1) + /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) + /// Storage: Registrar Paras (r:100 w:100) + /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) /// The range of component `c` is `[0, 100]`. /// The range of component `t` is `[0, 100]`. fn manage_lease_period_start(c: u32, t: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `594 + c * (20 ±0) + t * (234 ±0)` - // Estimated: `4065 + c * (2496 ±0) + t * (2709 ±0)` - // Minimum execution time: 729_793_000 picoseconds. - Weight::from_parts(740_820_000, 0) - .saturating_add(Weight::from_parts(0, 4065)) - // Standard Error: 88_206 - .saturating_add(Weight::from_parts(2_793_142, 0).saturating_mul(c.into())) - // Standard Error: 88_206 - .saturating_add(Weight::from_parts(8_933_065, 0).saturating_mul(t.into())) + // Measured: `26 + c * (47 ±0) + t * (308 ±0)` + // Estimated: `2800 + c * (2526 ±0) + t * (2789 ±0)` + // Minimum execution time: 634_547_000 picoseconds. + Weight::from_parts(643_045_000, 0) + .saturating_add(Weight::from_parts(0, 2800)) + // Standard Error: 81_521 + .saturating_add(Weight::from_parts(2_705_219, 0).saturating_mul(c.into())) + // Standard Error: 81_521 + .saturating_add(Weight::from_parts(11_464_132, 0).saturating_mul(t.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) - .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(t.into()))) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) - .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_parts(0, 2496).saturating_mul(c.into())) - .saturating_add(Weight::from_parts(0, 2709).saturating_mul(t.into())) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(t.into()))) + .saturating_add(Weight::from_parts(0, 2526).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 2789).saturating_mul(t.into())) } - /// Storage: `Slots::Leases` (r:1 w:1) - /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:8 w:8) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Slots Leases (r:1 w:1) + /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) + /// Storage: System Account (r:8 w:8) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn clear_all_leases() -> Weight { // Proof Size summary in bytes: - // Measured: `2792` + // Measured: `2759` // Estimated: `21814` - // Minimum execution time: 123_888_000 picoseconds. - Weight::from_parts(131_245_000, 0) + // Minimum execution time: 129_756_000 picoseconds. + Weight::from_parts(131_810_000, 0) .saturating_add(Weight::from_parts(0, 21814)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(9)) } - /// Storage: `Slots::Leases` (r:1 w:0) - /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::ParaLifecycles` (r:1 w:1) - /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::ActionsQueue` (r:1 w:1) - /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Slots Leases (r:1 w:0) + /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras ParaLifecycles (r:1 w:1) + /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) + /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) + /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras ActionsQueue (r:1 w:1) + /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) + /// Storage: Registrar Paras (r:1 w:1) + /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) fn trigger_onboard() -> Weight { // Proof Size summary in bytes: - // Measured: `612` - // Estimated: `4077` - // Minimum execution time: 27_341_000 picoseconds. - Weight::from_parts(28_697_000, 0) - .saturating_add(Weight::from_parts(0, 4077)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `707` + // Estimated: `4172` + // Minimum execution time: 29_527_000 picoseconds. + Weight::from_parts(30_055_000, 0) + .saturating_add(Weight::from_parts(0, 4172)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) } } diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_assigner_on_demand.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_assigner_on_demand.rs index 653e1009f31..ac0f05301b4 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_assigner_on_demand.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_parachains_assigner_on_demand.rs @@ -16,28 +16,26 @@ //! Autogenerated weights for `runtime_parachains::assigner_on_demand` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-08-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-fljshgub-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet -// --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_parachains::assigner_on_demand // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/runtime_parachains_assigner_on_demand.rs +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --pallet=runtime_parachains::assigner_on_demand +// --chain=rococo-dev +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -59,13 +57,13 @@ impl runtime_parachains::assigner_on_demand::WeightInfo /// The range of component `s` is `[1, 9999]`. fn place_order_keep_alive(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `363 + s * (4 ±0)` - // Estimated: `3828 + s * (4 ±0)` - // Minimum execution time: 25_298_000 picoseconds. - Weight::from_parts(21_486_098, 0) - .saturating_add(Weight::from_parts(0, 3828)) - // Standard Error: 136 - .saturating_add(Weight::from_parts(13_943, 0).saturating_mul(s.into())) + // Measured: `297 + s * (4 ±0)` + // Estimated: `3762 + s * (4 ±0)` + // Minimum execution time: 33_522_000 picoseconds. + Weight::from_parts(35_436_835, 0) + .saturating_add(Weight::from_parts(0, 3762)) + // Standard Error: 129 + .saturating_add(Weight::from_parts(14_041, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) @@ -79,13 +77,13 @@ impl runtime_parachains::assigner_on_demand::WeightInfo /// The range of component `s` is `[1, 9999]`. fn place_order_allow_death(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `363 + s * (4 ±0)` - // Estimated: `3828 + s * (4 ±0)` - // Minimum execution time: 25_421_000 picoseconds. - Weight::from_parts(21_828_043, 0) - .saturating_add(Weight::from_parts(0, 3828)) - // Standard Error: 133 - .saturating_add(Weight::from_parts(13_831, 0).saturating_mul(s.into())) + // Measured: `297 + s * (4 ±0)` + // Estimated: `3762 + s * (4 ±0)` + // Minimum execution time: 33_488_000 picoseconds. + Weight::from_parts(34_848_934, 0) + .saturating_add(Weight::from_parts(0, 3762)) + // Standard Error: 143 + .saturating_add(Weight::from_parts(14_215, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_configuration.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_configuration.rs index caad090ae15..ca0575cb1b6 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_configuration.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_parachains_configuration.rs @@ -17,27 +17,25 @@ //! Autogenerated weights for `runtime_parachains::configuration` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-02-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet -// --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_parachains::configuration // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=runtime_parachains::configuration +// --chain=rococo-dev // --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/runtime_parachains_configuration.rs +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -60,8 +58,8 @@ impl runtime_parachains::configuration::WeightInfo for // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_689_000 picoseconds. - Weight::from_parts(8_089_000, 0) + // Minimum execution time: 7_789_000 picoseconds. + Weight::from_parts(8_269_000, 0) .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -76,8 +74,8 @@ impl runtime_parachains::configuration::WeightInfo for // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_735_000 picoseconds. - Weight::from_parts(8_150_000, 0) + // Minimum execution time: 7_851_000 picoseconds. + Weight::from_parts(8_152_000, 0) .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -92,8 +90,8 @@ impl runtime_parachains::configuration::WeightInfo for // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_902_000 picoseconds. - Weight::from_parts(8_196_000, 0) + // Minimum execution time: 7_960_000 picoseconds. + Weight::from_parts(8_276_000, 0) .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -118,8 +116,8 @@ impl runtime_parachains::configuration::WeightInfo for // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_634_000 picoseconds. - Weight::from_parts(7_983_000, 0) + // Minimum execution time: 7_912_000 picoseconds. + Weight::from_parts(8_164_000, 0) .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -134,8 +132,8 @@ impl runtime_parachains::configuration::WeightInfo for // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 9_580_000 picoseconds. - Weight::from_parts(9_989_000, 0) + // Minimum execution time: 9_782_000 picoseconds. + Weight::from_parts(10_373_000, 0) .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -150,8 +148,8 @@ impl runtime_parachains::configuration::WeightInfo for // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_787_000 picoseconds. - Weight::from_parts(8_008_000, 0) + // Minimum execution time: 7_870_000 picoseconds. + Weight::from_parts(8_274_000, 0) .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -166,8 +164,8 @@ impl runtime_parachains::configuration::WeightInfo for // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 9_557_000 picoseconds. - Weight::from_parts(9_994_000, 0) + // Minimum execution time: 9_960_000 picoseconds. + Weight::from_parts(10_514_000, 0) .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -182,8 +180,8 @@ impl runtime_parachains::configuration::WeightInfo for // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_775_000 picoseconds. - Weight::from_parts(7_989_000, 0) + // Minimum execution time: 7_913_000 picoseconds. + Weight::from_parts(8_338_000, 0) .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_disputes.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_disputes.rs index cf1aa36e10e..63a8c3addc7 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_disputes.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_parachains_disputes.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `runtime_parachains::disputes` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: // ./target/production/polkadot @@ -29,15 +29,12 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --pallet=runtime_parachains::disputes // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/runtime_parachains_disputes.rs +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/runtime_parachains_disputes.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,14 +47,14 @@ use core::marker::PhantomData; /// Weight functions for `runtime_parachains::disputes`. pub struct WeightInfo(PhantomData); impl runtime_parachains::disputes::WeightInfo for WeightInfo { - /// Storage: `ParasDisputes::Frozen` (r:0 w:1) - /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: ParasDisputes Frozen (r:0 w:1) + /// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured) fn force_unfreeze() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_855_000 picoseconds. - Weight::from_parts(2_015_000, 0) + // Minimum execution time: 2_937_000 picoseconds. + Weight::from_parts(3_082_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_hrmp.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_hrmp.rs index a3b912491e5..417820e6627 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_hrmp.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_parachains_hrmp.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `runtime_parachains::hrmp` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: // ./target/production/polkadot @@ -29,15 +29,12 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --pallet=runtime_parachains::hrmp // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/runtime_parachains_hrmp.rs +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/runtime_parachains_hrmp.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,97 +47,105 @@ use core::marker::PhantomData; /// Weight functions for `runtime_parachains::hrmp`. pub struct WeightInfo(PhantomData); impl runtime_parachains::hrmp::WeightInfo for WeightInfo { - /// Storage: `Paras::ParaLifecycles` (r:1 w:0) - /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpOpenChannelRequests` (r:1 w:1) - /// Proof: `Hrmp::HrmpOpenChannelRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpChannels` (r:1 w:0) - /// Proof: `Hrmp::HrmpChannels` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpEgressChannelsIndex` (r:1 w:0) - /// Proof: `Hrmp::HrmpEgressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpOpenChannelRequestCount` (r:1 w:1) - /// Proof: `Hrmp::HrmpOpenChannelRequestCount` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpOpenChannelRequestsList` (r:1 w:1) - /// Proof: `Hrmp::HrmpOpenChannelRequestsList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Paras ParaLifecycles (r:2 w:0) + /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) + /// Storage: Configuration ActiveConfig (r:1 w:0) + /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Hrmp HrmpOpenChannelRequests (r:1 w:1) + /// Proof Skipped: Hrmp HrmpOpenChannelRequests (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpChannels (r:1 w:0) + /// Proof Skipped: Hrmp HrmpChannels (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpEgressChannelsIndex (r:1 w:0) + /// Proof Skipped: Hrmp HrmpEgressChannelsIndex (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpOpenChannelRequestCount (r:1 w:1) + /// Proof Skipped: Hrmp HrmpOpenChannelRequestCount (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpOpenChannelRequestsList (r:1 w:1) + /// Proof Skipped: Hrmp HrmpOpenChannelRequestsList (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Dmp DownwardMessageQueues (r:1 w:1) + /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) + /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) + /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) fn hrmp_init_open_channel() -> Weight { // Proof Size summary in bytes: - // Measured: `488` - // Estimated: `3953` - // Minimum execution time: 34_911_000 picoseconds. - Weight::from_parts(35_762_000, 0) - .saturating_add(Weight::from_parts(0, 3953)) - .saturating_add(T::DbWeight::get().reads(8)) + // Measured: `704` + // Estimated: `6644` + // Minimum execution time: 41_564_000 picoseconds. + Weight::from_parts(42_048_000, 0) + .saturating_add(Weight::from_parts(0, 6644)) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(5)) } - /// Storage: `Hrmp::HrmpOpenChannelRequests` (r:1 w:1) - /// Proof: `Hrmp::HrmpOpenChannelRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpIngressChannelsIndex` (r:1 w:0) - /// Proof: `Hrmp::HrmpIngressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpAcceptedChannelRequestCount` (r:1 w:1) - /// Proof: `Hrmp::HrmpAcceptedChannelRequestCount` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Hrmp HrmpOpenChannelRequests (r:1 w:1) + /// Proof Skipped: Hrmp HrmpOpenChannelRequests (max_values: None, max_size: None, mode: Measured) + /// Storage: Configuration ActiveConfig (r:1 w:0) + /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras ParaLifecycles (r:1 w:0) + /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpIngressChannelsIndex (r:1 w:0) + /// Proof Skipped: Hrmp HrmpIngressChannelsIndex (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpAcceptedChannelRequestCount (r:1 w:1) + /// Proof Skipped: Hrmp HrmpAcceptedChannelRequestCount (max_values: None, max_size: None, mode: Measured) + /// Storage: Dmp DownwardMessageQueues (r:1 w:1) + /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) + /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) + /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) fn hrmp_accept_open_channel() -> Weight { // Proof Size summary in bytes: - // Measured: `478` - // Estimated: `3943` - // Minimum execution time: 31_483_000 picoseconds. - Weight::from_parts(32_230_000, 0) - .saturating_add(Weight::from_parts(0, 3943)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `936` + // Estimated: `4401` + // Minimum execution time: 43_570_000 picoseconds. + Weight::from_parts(44_089_000, 0) + .saturating_add(Weight::from_parts(0, 4401)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: `Hrmp::HrmpChannels` (r:1 w:0) - /// Proof: `Hrmp::HrmpChannels` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpCloseChannelRequests` (r:1 w:1) - /// Proof: `Hrmp::HrmpCloseChannelRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpCloseChannelRequestsList` (r:1 w:1) - /// Proof: `Hrmp::HrmpCloseChannelRequestsList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Hrmp HrmpChannels (r:1 w:0) + /// Proof Skipped: Hrmp HrmpChannels (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpCloseChannelRequests (r:1 w:1) + /// Proof Skipped: Hrmp HrmpCloseChannelRequests (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpCloseChannelRequestsList (r:1 w:1) + /// Proof Skipped: Hrmp HrmpCloseChannelRequestsList (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Configuration ActiveConfig (r:1 w:0) + /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Dmp DownwardMessageQueues (r:1 w:1) + /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) + /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) + /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) fn hrmp_close_channel() -> Weight { // Proof Size summary in bytes: - // Measured: `591` - // Estimated: `4056` - // Minimum execution time: 32_153_000 picoseconds. - Weight::from_parts(32_982_000, 0) - .saturating_add(Weight::from_parts(0, 4056)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `807` + // Estimated: `4272` + // Minimum execution time: 36_594_000 picoseconds. + Weight::from_parts(37_090_000, 0) + .saturating_add(Weight::from_parts(0, 4272)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: `Hrmp::HrmpIngressChannelsIndex` (r:128 w:128) - /// Proof: `Hrmp::HrmpIngressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpEgressChannelsIndex` (r:128 w:128) - /// Proof: `Hrmp::HrmpEgressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpChannels` (r:254 w:254) - /// Proof: `Hrmp::HrmpChannels` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpAcceptedChannelRequestCount` (r:0 w:1) - /// Proof: `Hrmp::HrmpAcceptedChannelRequestCount` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpChannelContents` (r:0 w:254) - /// Proof: `Hrmp::HrmpChannelContents` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpOpenChannelRequestCount` (r:0 w:1) - /// Proof: `Hrmp::HrmpOpenChannelRequestCount` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Hrmp HrmpIngressChannelsIndex (r:128 w:128) + /// Proof Skipped: Hrmp HrmpIngressChannelsIndex (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpEgressChannelsIndex (r:128 w:128) + /// Proof Skipped: Hrmp HrmpEgressChannelsIndex (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpChannels (r:254 w:254) + /// Proof Skipped: Hrmp HrmpChannels (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpAcceptedChannelRequestCount (r:0 w:1) + /// Proof Skipped: Hrmp HrmpAcceptedChannelRequestCount (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpChannelContents (r:0 w:254) + /// Proof Skipped: Hrmp HrmpChannelContents (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpOpenChannelRequestCount (r:0 w:1) + /// Proof Skipped: Hrmp HrmpOpenChannelRequestCount (max_values: None, max_size: None, mode: Measured) /// The range of component `i` is `[0, 127]`. /// The range of component `e` is `[0, 127]`. fn force_clean_hrmp(i: u32, e: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `297 + e * (100 ±0) + i * (100 ±0)` - // Estimated: `3759 + e * (2575 ±0) + i * (2575 ±0)` - // Minimum execution time: 1_240_769_000 picoseconds. - Weight::from_parts(1_249_285_000, 0) - .saturating_add(Weight::from_parts(0, 3759)) - // Standard Error: 112_346 - .saturating_add(Weight::from_parts(3_449_114, 0).saturating_mul(i.into())) - // Standard Error: 112_346 - .saturating_add(Weight::from_parts(3_569_184, 0).saturating_mul(e.into())) + // Measured: `264 + e * (100 ±0) + i * (100 ±0)` + // Estimated: `3726 + e * (2575 ±0) + i * (2575 ±0)` + // Minimum execution time: 1_085_140_000 picoseconds. + Weight::from_parts(1_100_901_000, 0) + .saturating_add(Weight::from_parts(0, 3726)) + // Standard Error: 98_982 + .saturating_add(Weight::from_parts(3_229_112, 0).saturating_mul(i.into())) + // Standard Error: 98_982 + .saturating_add(Weight::from_parts(3_210_944, 0).saturating_mul(e.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(e.into()))) @@ -150,139 +155,139 @@ impl runtime_parachains::hrmp::WeightInfo for WeightInf .saturating_add(Weight::from_parts(0, 2575).saturating_mul(e.into())) .saturating_add(Weight::from_parts(0, 2575).saturating_mul(i.into())) } - /// Storage: `Hrmp::HrmpOpenChannelRequestsList` (r:1 w:1) - /// Proof: `Hrmp::HrmpOpenChannelRequestsList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpOpenChannelRequests` (r:128 w:128) - /// Proof: `Hrmp::HrmpOpenChannelRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::ParaLifecycles` (r:256 w:0) - /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpIngressChannelsIndex` (r:128 w:128) - /// Proof: `Hrmp::HrmpIngressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpEgressChannelsIndex` (r:128 w:128) - /// Proof: `Hrmp::HrmpEgressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpOpenChannelRequestCount` (r:128 w:128) - /// Proof: `Hrmp::HrmpOpenChannelRequestCount` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpAcceptedChannelRequestCount` (r:128 w:128) - /// Proof: `Hrmp::HrmpAcceptedChannelRequestCount` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpChannels` (r:0 w:128) - /// Proof: `Hrmp::HrmpChannels` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Configuration ActiveConfig (r:1 w:0) + /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Hrmp HrmpOpenChannelRequestsList (r:1 w:1) + /// Proof Skipped: Hrmp HrmpOpenChannelRequestsList (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Hrmp HrmpOpenChannelRequests (r:128 w:128) + /// Proof Skipped: Hrmp HrmpOpenChannelRequests (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras ParaLifecycles (r:256 w:0) + /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpIngressChannelsIndex (r:128 w:128) + /// Proof Skipped: Hrmp HrmpIngressChannelsIndex (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpEgressChannelsIndex (r:128 w:128) + /// Proof Skipped: Hrmp HrmpEgressChannelsIndex (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpOpenChannelRequestCount (r:128 w:128) + /// Proof Skipped: Hrmp HrmpOpenChannelRequestCount (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpAcceptedChannelRequestCount (r:128 w:128) + /// Proof Skipped: Hrmp HrmpAcceptedChannelRequestCount (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpChannels (r:0 w:128) + /// Proof Skipped: Hrmp HrmpChannels (max_values: None, max_size: None, mode: Measured) /// The range of component `c` is `[0, 128]`. fn force_process_hrmp_open(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `525 + c * (136 ±0)` - // Estimated: `1980 + c * (5086 ±0)` - // Minimum execution time: 6_026_000 picoseconds. - Weight::from_parts(6_257_000, 0) - .saturating_add(Weight::from_parts(0, 1980)) - // Standard Error: 9_732 - .saturating_add(Weight::from_parts(21_049_890, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(1)) + // Measured: `779 + c * (136 ±0)` + // Estimated: `2234 + c * (5086 ±0)` + // Minimum execution time: 10_497_000 picoseconds. + Weight::from_parts(6_987_455, 0) + .saturating_add(Weight::from_parts(0, 2234)) + // Standard Error: 18_540 + .saturating_add(Weight::from_parts(18_788_534, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(c.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((6_u64).saturating_mul(c.into()))) .saturating_add(Weight::from_parts(0, 5086).saturating_mul(c.into())) } - /// Storage: `Hrmp::HrmpCloseChannelRequestsList` (r:1 w:1) - /// Proof: `Hrmp::HrmpCloseChannelRequestsList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpChannels` (r:128 w:128) - /// Proof: `Hrmp::HrmpChannels` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpEgressChannelsIndex` (r:128 w:128) - /// Proof: `Hrmp::HrmpEgressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpIngressChannelsIndex` (r:128 w:128) - /// Proof: `Hrmp::HrmpIngressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpCloseChannelRequests` (r:0 w:128) - /// Proof: `Hrmp::HrmpCloseChannelRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpChannelContents` (r:0 w:128) - /// Proof: `Hrmp::HrmpChannelContents` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Hrmp HrmpCloseChannelRequestsList (r:1 w:1) + /// Proof Skipped: Hrmp HrmpCloseChannelRequestsList (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Hrmp HrmpChannels (r:128 w:128) + /// Proof Skipped: Hrmp HrmpChannels (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpEgressChannelsIndex (r:128 w:128) + /// Proof Skipped: Hrmp HrmpEgressChannelsIndex (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpIngressChannelsIndex (r:128 w:128) + /// Proof Skipped: Hrmp HrmpIngressChannelsIndex (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpCloseChannelRequests (r:0 w:128) + /// Proof Skipped: Hrmp HrmpCloseChannelRequests (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpChannelContents (r:0 w:128) + /// Proof Skipped: Hrmp HrmpChannelContents (max_values: None, max_size: None, mode: Measured) /// The range of component `c` is `[0, 128]`. fn force_process_hrmp_close(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `368 + c * (124 ±0)` - // Estimated: `1828 + c * (2600 ±0)` - // Minimum execution time: 4_991_000 picoseconds. - Weight::from_parts(984_758, 0) - .saturating_add(Weight::from_parts(0, 1828)) - // Standard Error: 11_918 - .saturating_add(Weight::from_parts(13_018_813, 0).saturating_mul(c.into())) + // Measured: `335 + c * (124 ±0)` + // Estimated: `1795 + c * (2600 ±0)` + // Minimum execution time: 6_575_000 picoseconds. + Weight::from_parts(1_228_642, 0) + .saturating_add(Weight::from_parts(0, 1795)) + // Standard Error: 14_826 + .saturating_add(Weight::from_parts(11_604_038, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(c.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((5_u64).saturating_mul(c.into()))) .saturating_add(Weight::from_parts(0, 2600).saturating_mul(c.into())) } - /// Storage: `Hrmp::HrmpOpenChannelRequestsList` (r:1 w:1) - /// Proof: `Hrmp::HrmpOpenChannelRequestsList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpOpenChannelRequests` (r:1 w:1) - /// Proof: `Hrmp::HrmpOpenChannelRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpOpenChannelRequestCount` (r:1 w:1) - /// Proof: `Hrmp::HrmpOpenChannelRequestCount` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Hrmp HrmpOpenChannelRequestsList (r:1 w:1) + /// Proof Skipped: Hrmp HrmpOpenChannelRequestsList (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Hrmp HrmpOpenChannelRequests (r:1 w:1) + /// Proof Skipped: Hrmp HrmpOpenChannelRequests (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpOpenChannelRequestCount (r:1 w:1) + /// Proof Skipped: Hrmp HrmpOpenChannelRequestCount (max_values: None, max_size: None, mode: Measured) /// The range of component `c` is `[0, 128]`. fn hrmp_cancel_open_request(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1059 + c * (13 ±0)` - // Estimated: `4328 + c * (15 ±0)` - // Minimum execution time: 17_299_000 picoseconds. - Weight::from_parts(27_621_478, 0) - .saturating_add(Weight::from_parts(0, 4328)) - // Standard Error: 2_527 - .saturating_add(Weight::from_parts(121_149, 0).saturating_mul(c.into())) + // Measured: `1026 + c * (13 ±0)` + // Estimated: `4295 + c * (15 ±0)` + // Minimum execution time: 22_301_000 picoseconds. + Weight::from_parts(26_131_473, 0) + .saturating_add(Weight::from_parts(0, 4295)) + // Standard Error: 830 + .saturating_add(Weight::from_parts(49_448, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) .saturating_add(Weight::from_parts(0, 15).saturating_mul(c.into())) } - /// Storage: `Hrmp::HrmpOpenChannelRequestsList` (r:1 w:1) - /// Proof: `Hrmp::HrmpOpenChannelRequestsList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpOpenChannelRequests` (r:128 w:128) - /// Proof: `Hrmp::HrmpOpenChannelRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Hrmp HrmpOpenChannelRequestsList (r:1 w:1) + /// Proof Skipped: Hrmp HrmpOpenChannelRequestsList (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Hrmp HrmpOpenChannelRequests (r:128 w:128) + /// Proof Skipped: Hrmp HrmpOpenChannelRequests (max_values: None, max_size: None, mode: Measured) /// The range of component `c` is `[0, 128]`. fn clean_open_channel_requests(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `276 + c * (63 ±0)` - // Estimated: `1755 + c * (2538 ±0)` - // Minimum execution time: 3_764_000 picoseconds. - Weight::from_parts(5_935_301, 0) - .saturating_add(Weight::from_parts(0, 1755)) - // Standard Error: 3_761 - .saturating_add(Weight::from_parts(3_290_277, 0).saturating_mul(c.into())) + // Measured: `243 + c * (63 ±0)` + // Estimated: `1722 + c * (2538 ±0)` + // Minimum execution time: 5_234_000 picoseconds. + Weight::from_parts(7_350_270, 0) + .saturating_add(Weight::from_parts(0, 1722)) + // Standard Error: 3_105 + .saturating_add(Weight::from_parts(2_981_935, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) .saturating_add(Weight::from_parts(0, 2538).saturating_mul(c.into())) } - /// Storage: `Hrmp::HrmpOpenChannelRequests` (r:1 w:1) - /// Proof: `Hrmp::HrmpOpenChannelRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpOpenChannelRequestsList` (r:1 w:1) - /// Proof: `Hrmp::HrmpOpenChannelRequestsList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpOpenChannelRequestCount` (r:1 w:1) - /// Proof: `Hrmp::HrmpOpenChannelRequestCount` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::ParaLifecycles` (r:1 w:0) - /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpChannels` (r:1 w:0) - /// Proof: `Hrmp::HrmpChannels` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpEgressChannelsIndex` (r:1 w:0) - /// Proof: `Hrmp::HrmpEgressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:2 w:2) - /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueueHeads` (r:2 w:2) - /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpIngressChannelsIndex` (r:1 w:0) - /// Proof: `Hrmp::HrmpIngressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpAcceptedChannelRequestCount` (r:1 w:1) - /// Proof: `Hrmp::HrmpAcceptedChannelRequestCount` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `c` is `[0, 1]`. - fn force_open_hrmp_channel(c: u32, ) -> Weight { + /// Storage: Paras ParaLifecycles (r:2 w:0) + /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) + /// Storage: Configuration ActiveConfig (r:1 w:0) + /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Hrmp HrmpOpenChannelRequests (r:1 w:1) + /// Proof Skipped: Hrmp HrmpOpenChannelRequests (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpChannels (r:1 w:0) + /// Proof Skipped: Hrmp HrmpChannels (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpEgressChannelsIndex (r:1 w:0) + /// Proof Skipped: Hrmp HrmpEgressChannelsIndex (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpOpenChannelRequestCount (r:1 w:1) + /// Proof Skipped: Hrmp HrmpOpenChannelRequestCount (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpOpenChannelRequestsList (r:1 w:1) + /// Proof Skipped: Hrmp HrmpOpenChannelRequestsList (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Dmp DownwardMessageQueues (r:2 w:2) + /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) + /// Storage: Dmp DownwardMessageQueueHeads (r:2 w:2) + /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpIngressChannelsIndex (r:1 w:0) + /// Proof Skipped: Hrmp HrmpIngressChannelsIndex (max_values: None, max_size: None, mode: Measured) + /// Storage: Hrmp HrmpAcceptedChannelRequestCount (r:1 w:1) + /// Proof Skipped: Hrmp HrmpAcceptedChannelRequestCount (max_values: None, max_size: None, mode: Measured) + fn force_open_hrmp_channel(_c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `488 + c * (235 ±0)` - // Estimated: `6428 + c * (235 ±0)` - // Minimum execution time: 49_506_000 picoseconds. - Weight::from_parts(51_253_075, 0) - .saturating_add(Weight::from_parts(0, 6428)) - // Standard Error: 144_082 - .saturating_add(Weight::from_parts(12_862_224, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(12)) + // Measured: `704` + // Estimated: `6644` + // Minimum execution time: 55_611_000 picoseconds. + Weight::from_parts(56_488_000, 0) + .saturating_add(Weight::from_parts(0, 6644)) + .saturating_add(T::DbWeight::get().reads(14)) .saturating_add(T::DbWeight::get().writes(8)) - .saturating_add(Weight::from_parts(0, 235).saturating_mul(c.into())) } /// Storage: `Paras::ParaLifecycles` (r:1 w:0) /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -306,11 +311,11 @@ impl runtime_parachains::hrmp::WeightInfo for WeightInf /// Proof: `Hrmp::HrmpAcceptedChannelRequestCount` (`max_values`: None, `max_size`: None, mode: `Measured`) fn establish_system_channel() -> Weight { // Proof Size summary in bytes: - // Measured: `488` - // Estimated: `6428` - // Minimum execution time: 50_016_000 picoseconds. - Weight::from_parts(50_933_000, 0) - .saturating_add(Weight::from_parts(0, 6428)) + // Measured: `417` + // Estimated: `6357` + // Minimum execution time: 629_674_000 picoseconds. + Weight::from_parts(640_174_000, 0) + .saturating_add(Weight::from_parts(0, 6357)) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(8)) } @@ -318,11 +323,11 @@ impl runtime_parachains::hrmp::WeightInfo for WeightInf /// Proof: `Hrmp::HrmpChannels` (`max_values`: None, `max_size`: None, mode: `Measured`) fn poke_channel_deposits() -> Weight { // Proof Size summary in bytes: - // Measured: `296` - // Estimated: `3761` - // Minimum execution time: 12_280_000 picoseconds. - Weight::from_parts(12_863_000, 0) - .saturating_add(Weight::from_parts(0, 3761)) + // Measured: `263` + // Estimated: `3728` + // Minimum execution time: 173_371_000 picoseconds. + Weight::from_parts(175_860_000, 0) + .saturating_add(Weight::from_parts(0, 3728)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_inclusion.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_inclusion.rs index b9ec7565bd5..a121ad774ce 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_inclusion.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_parachains_inclusion.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `runtime_parachains::inclusion` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: // ./target/production/polkadot @@ -29,15 +29,12 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --pallet=runtime_parachains::inclusion // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/runtime_parachains_inclusion.rs +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/runtime_parachains_inclusion.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,25 +47,27 @@ use core::marker::PhantomData; /// Weight functions for `runtime_parachains::inclusion`. pub struct WeightInfo(PhantomData); impl runtime_parachains::inclusion::WeightInfo for WeightInfo { - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:1 w:999) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(32818), added: 35293, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Proof: UNKNOWN KEY `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Storage: UNKNOWN KEY `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - /// Proof: UNKNOWN KEY `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:999) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(32818), added: 35293, mode: MaxEncodedLen) + /// Storage: Configuration ActiveConfig (r:1 w:0) + /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) + /// Proof Skipped: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) + /// Storage: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) + /// Proof Skipped: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) /// The range of component `i` is `[1, 1000]`. fn receive_upward_messages(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32993` + // Measured: `33280` // Estimated: `36283` - // Minimum execution time: 72_675_000 picoseconds. - Weight::from_parts(73_290_000, 0) + // Minimum execution time: 71_094_000 picoseconds. + Weight::from_parts(71_436_000, 0) .saturating_add(Weight::from_parts(0, 36283)) - // Standard Error: 16_067 - .saturating_add(Weight::from_parts(57_735_739, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().reads(2)) + // Standard Error: 22_149 + .saturating_add(Weight::from_parts(51_495_472, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_initializer.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_initializer.rs index e8c554610c9..5c627507dfb 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_initializer.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_parachains_initializer.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `runtime_parachains::initializer` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: // ./target/production/polkadot @@ -29,15 +29,12 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --pallet=runtime_parachains::initializer // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/runtime_parachains_initializer.rs +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/runtime_parachains_initializer.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,18 +47,18 @@ use core::marker::PhantomData; /// Weight functions for `runtime_parachains::initializer`. pub struct WeightInfo(PhantomData); impl runtime_parachains::initializer::WeightInfo for WeightInfo { - /// Storage: `System::Digest` (r:1 w:1) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: System Digest (r:1 w:1) + /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `d` is `[0, 65536]`. fn force_approve(d: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + d * (11 ±0)` // Estimated: `1480 + d * (11 ±0)` - // Minimum execution time: 2_634_000 picoseconds. - Weight::from_parts(2_728_000, 0) + // Minimum execution time: 3_771_000 picoseconds. + Weight::from_parts(6_491_437, 0) .saturating_add(Weight::from_parts(0, 1480)) - // Standard Error: 19 - .saturating_add(Weight::from_parts(2_499, 0).saturating_mul(d.into())) + // Standard Error: 9 + .saturating_add(Weight::from_parts(1_356, 0).saturating_mul(d.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(Weight::from_parts(0, 11).saturating_mul(d.into())) diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_paras.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_paras.rs index af26bfc9ae9..dfd95006dc7 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_paras.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_parachains_paras.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `runtime_parachains::paras` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: // ./target/production/polkadot @@ -29,15 +29,12 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --pallet=runtime_parachains::paras // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/runtime_parachains_paras.rs +// --header=./file_header.txt +// --output=./runtime/rococo/src/weights/runtime_parachains_paras.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,248 +47,247 @@ use core::marker::PhantomData; /// Weight functions for `runtime_parachains::paras`. pub struct WeightInfo(PhantomData); impl runtime_parachains::paras::WeightInfo for WeightInfo { - /// Storage: `Paras::CurrentCodeHash` (r:1 w:1) - /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::CodeByHashRefs` (r:1 w:1) - /// Proof: `Paras::CodeByHashRefs` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::PastCodeMeta` (r:1 w:1) - /// Proof: `Paras::PastCodeMeta` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::PastCodePruning` (r:1 w:1) - /// Proof: `Paras::PastCodePruning` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::PastCodeHash` (r:0 w:1) - /// Proof: `Paras::PastCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::CodeByHash` (r:0 w:1) - /// Proof: `Paras::CodeByHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Paras CurrentCodeHash (r:1 w:1) + /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras CodeByHashRefs (r:1 w:1) + /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras PastCodeMeta (r:1 w:1) + /// Proof Skipped: Paras PastCodeMeta (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras PastCodePruning (r:1 w:1) + /// Proof Skipped: Paras PastCodePruning (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras PastCodeHash (r:0 w:1) + /// Proof Skipped: Paras PastCodeHash (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras CodeByHash (r:0 w:1) + /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) /// The range of component `c` is `[1, 3145728]`. fn force_set_current_code(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `8309` // Estimated: `11774` - // Minimum execution time: 27_488_000 picoseconds. - Weight::from_parts(27_810_000, 0) + // Minimum execution time: 31_941_000 picoseconds. + Weight::from_parts(32_139_000, 0) .saturating_add(Weight::from_parts(0, 11774)) - // Standard Error: 8 - .saturating_add(Weight::from_parts(2_189, 0).saturating_mul(c.into())) + // Standard Error: 5 + .saturating_add(Weight::from_parts(2_011, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(6)) } - /// Storage: `Paras::Heads` (r:0 w:1) - /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Paras Heads (r:0 w:1) + /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) /// The range of component `s` is `[1, 1048576]`. fn force_set_current_head(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_793_000 picoseconds. - Weight::from_parts(7_987_606, 0) + // Minimum execution time: 8_275_000 picoseconds. + Weight::from_parts(8_321_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(971, 0).saturating_mul(s.into())) + // Standard Error: 2 + .saturating_add(Weight::from_parts(858, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Paras::MostRecentContext` (r:0 w:1) - /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: Paras Heads (r:0 w:1) fn force_set_most_recent_context() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_733_000 picoseconds. - Weight::from_parts(2_954_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) + Weight::from_parts(10_155_000, 0) + // Standard Error: 0 + .saturating_add(T::DbWeight::get().writes(1 as u64)) } - /// Storage: `Paras::FutureCodeHash` (r:1 w:1) - /// Proof: `Paras::FutureCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::CurrentCodeHash` (r:1 w:0) - /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::UpgradeCooldowns` (r:1 w:1) - /// Proof: `Paras::UpgradeCooldowns` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) - /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::CodeByHash` (r:1 w:1) - /// Proof: `Paras::CodeByHash` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) - /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::PvfActiveVoteList` (r:1 w:1) - /// Proof: `Paras::PvfActiveVoteList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::CodeByHashRefs` (r:1 w:1) - /// Proof: `Paras::CodeByHashRefs` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::UpgradeRestrictionSignal` (r:0 w:1) - /// Proof: `Paras::UpgradeRestrictionSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Configuration ActiveConfig (r:1 w:0) + /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras FutureCodeHash (r:1 w:1) + /// Proof Skipped: Paras FutureCodeHash (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras CurrentCodeHash (r:1 w:0) + /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras UpgradeCooldowns (r:1 w:1) + /// Proof Skipped: Paras UpgradeCooldowns (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras PvfActiveVoteMap (r:1 w:1) + /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras CodeByHash (r:1 w:1) + /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) + /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) + /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras PvfActiveVoteList (r:1 w:1) + /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras CodeByHashRefs (r:1 w:1) + /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras UpgradeRestrictionSignal (r:0 w:1) + /// Proof Skipped: Paras UpgradeRestrictionSignal (max_values: None, max_size: None, mode: Measured) /// The range of component `c` is `[1, 3145728]`. fn force_schedule_code_upgrade(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `8452` - // Estimated: `11917` - // Minimum execution time: 6_072_000 picoseconds. - Weight::from_parts(6_128_000, 0) - .saturating_add(Weight::from_parts(0, 11917)) - // Standard Error: 2 - .saturating_add(Weight::from_parts(2_334, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(6)) + // Measured: `8715` + // Estimated: `12180` + // Minimum execution time: 49_923_000 picoseconds. + Weight::from_parts(50_688_000, 0) + .saturating_add(Weight::from_parts(0, 12180)) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_976, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(7)) } - /// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0) - /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Registrar::Paras` (r:1 w:0) - /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::Heads` (r:0 w:1) - /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1) - /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::MostRecentContext` (r:0 w:1) - /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Paras FutureCodeUpgrades (r:1 w:0) + /// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras Heads (r:0 w:1) + /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras UpgradeGoAheadSignal (r:0 w:1) + /// Proof Skipped: Paras UpgradeGoAheadSignal (max_values: None, max_size: None, mode: Measured) /// The range of component `s` is `[1, 1048576]`. fn force_note_new_head(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `163` - // Estimated: `3628` - // Minimum execution time: 15_166_000 picoseconds. - Weight::from_parts(21_398_053, 0) - .saturating_add(Weight::from_parts(0, 3628)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(976, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(3)) + // Measured: `95` + // Estimated: `3560` + // Minimum execution time: 14_408_000 picoseconds. + Weight::from_parts(14_647_000, 0) + .saturating_add(Weight::from_parts(0, 3560)) + // Standard Error: 2 + .saturating_add(Weight::from_parts(858, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::ActionsQueue` (r:1 w:1) - /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) + /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras ActionsQueue (r:1 w:1) + /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) fn force_queue_action() -> Weight { // Proof Size summary in bytes: - // Measured: `4312` - // Estimated: `7777` - // Minimum execution time: 16_345_000 picoseconds. - Weight::from_parts(16_712_000, 0) - .saturating_add(Weight::from_parts(0, 7777)) + // Measured: `4288` + // Estimated: `7753` + // Minimum execution time: 20_009_000 picoseconds. + Weight::from_parts(20_518_000, 0) + .saturating_add(Weight::from_parts(0, 7753)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) - /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::PvfActiveVoteList` (r:1 w:1) - /// Proof: `Paras::PvfActiveVoteList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::ActionsQueue` (r:1 w:1) - /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Paras PvfActiveVoteMap (r:1 w:1) + /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras PvfActiveVoteList (r:1 w:1) + /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Configuration ActiveConfig (r:1 w:0) + /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) + /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras ActionsQueue (r:1 w:1) + /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) /// The range of component `c` is `[1, 3145728]`. fn add_trusted_validation_code(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `683` - // Estimated: `4148` - // Minimum execution time: 78_076_000 picoseconds. - Weight::from_parts(123_193_814, 0) - .saturating_add(Weight::from_parts(0, 4148)) - // Standard Error: 5 - .saturating_add(Weight::from_parts(1_770, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `946` + // Estimated: `4411` + // Minimum execution time: 80_626_000 picoseconds. + Weight::from_parts(52_721_755, 0) + .saturating_add(Weight::from_parts(0, 4411)) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_443, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `Paras::CodeByHashRefs` (r:1 w:0) - /// Proof: `Paras::CodeByHashRefs` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::CodeByHash` (r:0 w:1) - /// Proof: `Paras::CodeByHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Paras CodeByHashRefs (r:1 w:0) + /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras CodeByHash (r:0 w:1) + /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) fn poke_unused_validation_code() -> Weight { // Proof Size summary in bytes: // Measured: `28` // Estimated: `3493` - // Minimum execution time: 5_184_000 picoseconds. - Weight::from_parts(5_430_000, 0) + // Minimum execution time: 6_692_000 picoseconds. + Weight::from_parts(7_009_000, 0) .saturating_add(Weight::from_parts(0, 3493)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) - /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) - /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) + /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) + /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras PvfActiveVoteMap (r:1 w:1) + /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) fn include_pvf_check_statement() -> Weight { // Proof Size summary in bytes: - // Measured: `26706` - // Estimated: `30171` - // Minimum execution time: 102_995_000 picoseconds. - Weight::from_parts(108_977_000, 0) - .saturating_add(Weight::from_parts(0, 30171)) + // Measured: `26682` + // Estimated: `30147` + // Minimum execution time: 87_994_000 picoseconds. + Weight::from_parts(89_933_000, 0) + .saturating_add(Weight::from_parts(0, 30147)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) - /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) - /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::PvfActiveVoteList` (r:1 w:1) - /// Proof: `Paras::PvfActiveVoteList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::UpcomingUpgrades` (r:1 w:1) - /// Proof: `Paras::UpcomingUpgrades` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `System::Digest` (r:1 w:1) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::FutureCodeUpgrades` (r:0 w:100) - /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) + /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) + /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras PvfActiveVoteMap (r:1 w:1) + /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras PvfActiveVoteList (r:1 w:1) + /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Configuration ActiveConfig (r:1 w:0) + /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras UpcomingUpgrades (r:1 w:1) + /// Proof Skipped: Paras UpcomingUpgrades (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Digest (r:1 w:1) + /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras FutureCodeUpgrades (r:0 w:100) + /// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) fn include_pvf_check_statement_finalize_upgrade_accept() -> Weight { // Proof Size summary in bytes: - // Measured: `27360` - // Estimated: `30825` - // Minimum execution time: 709_433_000 picoseconds. - Weight::from_parts(725_074_000, 0) - .saturating_add(Weight::from_parts(0, 30825)) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `27523` + // Estimated: `30988` + // Minimum execution time: 783_222_000 picoseconds. + Weight::from_parts(794_959_000, 0) + .saturating_add(Weight::from_parts(0, 30988)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(104)) } - /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) - /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) - /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) + /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) + /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras PvfActiveVoteMap (r:1 w:1) + /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) fn include_pvf_check_statement_finalize_upgrade_reject() -> Weight { // Proof Size summary in bytes: - // Measured: `27338` - // Estimated: `30803` - // Minimum execution time: 98_973_000 picoseconds. - Weight::from_parts(104_715_000, 0) - .saturating_add(Weight::from_parts(0, 30803)) + // Measured: `27214` + // Estimated: `30679` + // Minimum execution time: 87_424_000 picoseconds. + Weight::from_parts(88_737_000, 0) + .saturating_add(Weight::from_parts(0, 30679)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) - /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) - /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::PvfActiveVoteList` (r:1 w:1) - /// Proof: `Paras::PvfActiveVoteList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::ActionsQueue` (r:1 w:1) - /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) + /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) + /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras PvfActiveVoteMap (r:1 w:1) + /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras PvfActiveVoteList (r:1 w:1) + /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Configuration ActiveConfig (r:1 w:0) + /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras ActionsQueue (r:1 w:1) + /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) fn include_pvf_check_statement_finalize_onboarding_accept() -> Weight { // Proof Size summary in bytes: - // Measured: `26728` - // Estimated: `30193` - // Minimum execution time: 550_958_000 picoseconds. - Weight::from_parts(564_497_000, 0) - .saturating_add(Weight::from_parts(0, 30193)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `26991` + // Estimated: `30456` + // Minimum execution time: 612_485_000 picoseconds. + Weight::from_parts(621_670_000, 0) + .saturating_add(Weight::from_parts(0, 30456)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) - /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) - /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) + /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) + /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras PvfActiveVoteMap (r:1 w:1) + /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) fn include_pvf_check_statement_finalize_onboarding_reject() -> Weight { // Proof Size summary in bytes: - // Measured: `26706` - // Estimated: `30171` - // Minimum execution time: 97_088_000 picoseconds. - Weight::from_parts(103_617_000, 0) - .saturating_add(Weight::from_parts(0, 30171)) + // Measured: `26682` + // Estimated: `30147` + // Minimum execution time: 86_673_000 picoseconds. + Weight::from_parts(87_424_000, 0) + .saturating_add(Weight::from_parts(0, 30147)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_paras_inherent.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_paras_inherent.rs index 374927f8470..a102d1903b2 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_paras_inherent.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_parachains_paras_inherent.rs @@ -13,334 +13,161 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . - //! Autogenerated weights for `runtime_parachains::paras_inherent` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-11-20, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 128 // Executed Command: -// ./target/production/polkadot +// target/release/polkadot // benchmark -// pallet // --chain=rococo-dev // --steps=50 // --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --pallet=runtime_parachains::paras_inherent // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/runtime_parachains_paras_inherent.rs +// --heap-pages=4096 +// --output=./runtime/rococo/src/weights/runtime_parachains_paras_inherent.rs +// --header=./file_header.txt #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] -#![allow(missing_docs)] use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; +use sp_std::marker::PhantomData; /// Weight functions for `runtime_parachains::paras_inherent`. pub struct WeightInfo(PhantomData); impl runtime_parachains::paras_inherent::WeightInfo for WeightInfo { - /// Storage: `ParaInherent::Included` (r:1 w:1) - /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `System::ParentHash` (r:1 w:0) - /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) - /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) - /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) - /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) - /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) - /// Storage: `ParaSessionInfo::Sessions` (r:1 w:0) - /// Proof: `ParaSessionInfo::Sessions` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParasDisputes::Disputes` (r:1 w:1) - /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParasDisputes::BackersOnDisputes` (r:1 w:1) - /// Proof: `ParasDisputes::BackersOnDisputes` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParasDisputes::Included` (r:1 w:1) - /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1) - /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasDisputes::Frozen` (r:1 w:0) - /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaInclusion::PendingAvailability` (r:2 w:1) - /// Proof: `ParaInclusion::PendingAvailability` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParaInclusion::PendingAvailabilityCommitments` (r:1 w:1) - /// Proof: `ParaInclusion::PendingAvailabilityCommitments` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:1) - /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1) - /// Proof: `Hrmp::HrmpChannelDigests` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0) - /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Registrar::Paras` (r:1 w:0) - /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) - /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) - /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) - /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) - /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0) - /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Session::DisabledValidators` (r:1 w:0) - /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) - /// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::Heads` (r:0 w:1) - /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1) - /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::MostRecentContext` (r:0 w:1) - /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `v` is `[10, 200]`. + // Storage: ParaInherent Included (r:1 w:1) + // Storage: System ParentHash (r:1 w:0) + // Storage: ParaScheduler AvailabilityCores (r:1 w:1) + // Storage: ParasShared CurrentSessionIndex (r:1 w:0) + // Storage: Configuration ActiveConfig (r:1 w:0) + // Storage: ParaSessionInfo Sessions (r:1 w:0) + // Storage: ParasDisputes Disputes (r:1 w:1) + // Storage: ParasDisputes Included (r:1 w:1) + // Storage: ParasDisputes SpamSlots (r:1 w:1) + // Storage: ParasDisputes Frozen (r:1 w:0) + // Storage: ParaInclusion PendingAvailability (r:2 w:1) + // Storage: ParasShared ActiveValidatorKeys (r:1 w:0) + // Storage: Paras Parachains (r:1 w:0) + // Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) + // Storage: Dmp DownwardMessageQueues (r:1 w:1) + // Storage: Hrmp HrmpChannelDigests (r:1 w:1) + // Storage: Paras FutureCodeUpgrades (r:1 w:0) + // Storage: ParaScheduler SessionStartBlock (r:1 w:0) + // Storage: ParaScheduler ParathreadQueue (r:1 w:1) + // Storage: ParaScheduler Scheduled (r:1 w:1) + // Storage: ParaScheduler ValidatorGroups (r:1 w:0) + // Storage: Ump NeedsDispatch (r:1 w:1) + // Storage: Ump NextDispatchRoundStartWith (r:1 w:1) + // Storage: ParaInherent OnChainVotes (r:0 w:1) + // Storage: Hrmp HrmpWatermarks (r:0 w:1) + // Storage: Paras Heads (r:0 w:1) fn enter_variable_disputes(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `67819` - // Estimated: `73759 + v * (23 ±0)` - // Minimum execution time: 874_229_000 picoseconds. - Weight::from_parts(486_359_072, 0) - .saturating_add(Weight::from_parts(0, 73759)) - // Standard Error: 19_197 - .saturating_add(Weight::from_parts(41_842_161, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(26)) - .saturating_add(T::DbWeight::get().writes(16)) - .saturating_add(Weight::from_parts(0, 23).saturating_mul(v.into())) + Weight::from_parts(352_590_000 as u64, 0) + // Standard Error: 13_000 + .saturating_add(Weight::from_parts(49_254_000 as u64, 0).saturating_mul(v as u64)) + .saturating_add(T::DbWeight::get().reads(24 as u64)) + .saturating_add(T::DbWeight::get().writes(16 as u64)) } - /// Storage: `ParaInherent::Included` (r:1 w:1) - /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `System::ParentHash` (r:1 w:0) - /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) - /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) - /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) - /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) - /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) - /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1) - /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasDisputes::Frozen` (r:1 w:0) - /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaInclusion::PendingAvailability` (r:2 w:1) - /// Proof: `ParaInclusion::PendingAvailability` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParaInclusion::PendingAvailabilityCommitments` (r:1 w:1) - /// Proof: `ParaInclusion::PendingAvailabilityCommitments` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:1) - /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1) - /// Proof: `Hrmp::HrmpChannelDigests` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0) - /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Registrar::Paras` (r:1 w:0) - /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParasDisputes::Disputes` (r:1 w:0) - /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) - /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) - /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) - /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) - /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0) - /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Session::DisabledValidators` (r:1 w:0) - /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaInclusion::AvailabilityBitfields` (r:0 w:1) - /// Proof: `ParaInclusion::AvailabilityBitfields` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParasDisputes::Included` (r:0 w:1) - /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) - /// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::Heads` (r:0 w:1) - /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1) - /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::MostRecentContext` (r:0 w:1) - /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: ParaInherent Included (r:1 w:1) + // Storage: System ParentHash (r:1 w:0) + // Storage: ParaScheduler AvailabilityCores (r:1 w:1) + // Storage: ParasShared CurrentSessionIndex (r:1 w:0) + // Storage: Configuration ActiveConfig (r:1 w:0) + // Storage: ParasDisputes Frozen (r:1 w:0) + // Storage: ParasShared ActiveValidatorKeys (r:1 w:0) + // Storage: Paras Parachains (r:1 w:0) + // Storage: ParaInclusion PendingAvailability (r:2 w:1) + // Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) + // Storage: Dmp DownwardMessageQueues (r:1 w:1) + // Storage: Hrmp HrmpChannelDigests (r:1 w:1) + // Storage: Paras FutureCodeUpgrades (r:1 w:0) + // Storage: ParasDisputes Disputes (r:1 w:0) + // Storage: ParaScheduler SessionStartBlock (r:1 w:0) + // Storage: ParaScheduler ParathreadQueue (r:1 w:1) + // Storage: ParaScheduler Scheduled (r:1 w:1) + // Storage: ParaScheduler ValidatorGroups (r:1 w:0) + // Storage: Ump NeedsDispatch (r:1 w:1) + // Storage: Ump NextDispatchRoundStartWith (r:1 w:1) + // Storage: ParaInclusion AvailabilityBitfields (r:0 w:1) + // Storage: ParaInherent OnChainVotes (r:0 w:1) + // Storage: ParasDisputes Included (r:0 w:1) + // Storage: Hrmp HrmpWatermarks (r:0 w:1) + // Storage: Paras Heads (r:0 w:1) fn enter_bitfields() -> Weight { - // Proof Size summary in bytes: - // Measured: `42791` - // Estimated: `48731` - // Minimum execution time: 428_757_000 picoseconds. - Weight::from_parts(449_681_000, 0) - .saturating_add(Weight::from_parts(0, 48731)) - .saturating_add(T::DbWeight::get().reads(24)) - .saturating_add(T::DbWeight::get().writes(17)) + Weight::from_parts(299_878_000 as u64, 0) + .saturating_add(T::DbWeight::get().reads(21 as u64)) + .saturating_add(T::DbWeight::get().writes(15 as u64)) } - /// Storage: `ParaInherent::Included` (r:1 w:1) - /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `System::ParentHash` (r:1 w:0) - /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) - /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) - /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) - /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) - /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) - /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1) - /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasDisputes::Frozen` (r:1 w:0) - /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaInclusion::PendingAvailability` (r:2 w:1) - /// Proof: `ParaInclusion::PendingAvailability` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParaInclusion::PendingAvailabilityCommitments` (r:1 w:1) - /// Proof: `ParaInclusion::PendingAvailabilityCommitments` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:1) - /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1) - /// Proof: `Hrmp::HrmpChannelDigests` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0) - /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Registrar::Paras` (r:1 w:0) - /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParasDisputes::Disputes` (r:1 w:0) - /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) - /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) - /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) - /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) - /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::CurrentCodeHash` (r:1 w:0) - /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::ParaLifecycles` (r:1 w:0) - /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:0) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) - /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0) - /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Session::DisabledValidators` (r:1 w:0) - /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasDisputes::Included` (r:0 w:1) - /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) - /// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::Heads` (r:0 w:1) - /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1) - /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::MostRecentContext` (r:0 w:1) - /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `v` is `[101, 200]`. - fn enter_backed_candidates_variable(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `42863` - // Estimated: `48803` - // Minimum execution time: 1_276_079_000 picoseconds. - Weight::from_parts(1_313_585_212, 0) - .saturating_add(Weight::from_parts(0, 48803)) - // Standard Error: 18_279 - .saturating_add(Weight::from_parts(43_528, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(27)) - .saturating_add(T::DbWeight::get().writes(16)) + // Storage: ParaInherent Included (r:1 w:1) + // Storage: System ParentHash (r:1 w:0) + // Storage: ParaScheduler AvailabilityCores (r:1 w:1) + // Storage: ParasShared CurrentSessionIndex (r:1 w:0) + // Storage: Configuration ActiveConfig (r:1 w:0) + // Storage: ParasDisputes Frozen (r:1 w:0) + // Storage: ParasShared ActiveValidatorKeys (r:1 w:0) + // Storage: Paras Parachains (r:1 w:0) + // Storage: ParaInclusion PendingAvailability (r:2 w:1) + // Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) + // Storage: Dmp DownwardMessageQueues (r:1 w:1) + // Storage: Hrmp HrmpChannelDigests (r:1 w:1) + // Storage: Paras FutureCodeUpgrades (r:1 w:0) + // Storage: ParasDisputes Disputes (r:2 w:0) + // Storage: ParaScheduler SessionStartBlock (r:1 w:0) + // Storage: ParaScheduler ParathreadQueue (r:1 w:1) + // Storage: ParaScheduler Scheduled (r:1 w:1) + // Storage: ParaScheduler ValidatorGroups (r:1 w:0) + // Storage: Paras PastCodeMeta (r:1 w:0) + // Storage: Paras CurrentCodeHash (r:1 w:0) + // Storage: Ump RelayDispatchQueueSize (r:1 w:0) + // Storage: Ump NeedsDispatch (r:1 w:1) + // Storage: Ump NextDispatchRoundStartWith (r:1 w:1) + // Storage: ParaInherent OnChainVotes (r:0 w:1) + // Storage: ParasDisputes Included (r:0 w:1) + // Storage: Hrmp HrmpWatermarks (r:0 w:1) + // Storage: Paras Heads (r:0 w:1) + fn enter_backed_candidates_variable(_v: u32) -> Weight { + Weight::from_parts(442_472_000 as u64, 0) + .saturating_add(T::DbWeight::get().reads(25 as u64)) + .saturating_add(T::DbWeight::get().writes(14 as u64)) } - /// Storage: `ParaInherent::Included` (r:1 w:1) - /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `System::ParentHash` (r:1 w:0) - /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) - /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) - /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) - /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) - /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) - /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) - /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1) - /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasDisputes::Frozen` (r:1 w:0) - /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaInclusion::PendingAvailability` (r:2 w:1) - /// Proof: `ParaInclusion::PendingAvailability` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParaInclusion::PendingAvailabilityCommitments` (r:1 w:1) - /// Proof: `ParaInclusion::PendingAvailabilityCommitments` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:1) - /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1) - /// Proof: `Hrmp::HrmpChannelDigests` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0) - /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Registrar::Paras` (r:1 w:0) - /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParasDisputes::Disputes` (r:1 w:0) - /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) - /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) - /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) - /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) - /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::CurrentCodeHash` (r:1 w:0) - /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::FutureCodeHash` (r:1 w:0) - /// Proof: `Paras::FutureCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::UpgradeRestrictionSignal` (r:1 w:0) - /// Proof: `Paras::UpgradeRestrictionSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::ParaLifecycles` (r:1 w:0) - /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:0) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) - /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0) - /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Session::DisabledValidators` (r:1 w:0) - /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasDisputes::Included` (r:0 w:1) - /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) - /// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::Heads` (r:0 w:1) - /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1) - /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::MostRecentContext` (r:0 w:1) - /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: ParaInherent Included (r:1 w:1) + // Storage: System ParentHash (r:1 w:0) + // Storage: ParaScheduler AvailabilityCores (r:1 w:1) + // Storage: ParasShared CurrentSessionIndex (r:1 w:0) + // Storage: Configuration ActiveConfig (r:1 w:0) + // Storage: ParasDisputes Frozen (r:1 w:0) + // Storage: ParasShared ActiveValidatorKeys (r:1 w:0) + // Storage: Paras Parachains (r:1 w:0) + // Storage: ParaInclusion PendingAvailability (r:2 w:1) + // Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) + // Storage: Dmp DownwardMessageQueues (r:1 w:1) + // Storage: Hrmp HrmpChannelDigests (r:1 w:1) + // Storage: Paras FutureCodeUpgrades (r:1 w:0) + // Storage: ParasDisputes Disputes (r:2 w:0) + // Storage: ParaScheduler SessionStartBlock (r:1 w:0) + // Storage: ParaScheduler ParathreadQueue (r:1 w:1) + // Storage: ParaScheduler Scheduled (r:1 w:1) + // Storage: ParaScheduler ValidatorGroups (r:1 w:0) + // Storage: Paras PastCodeMeta (r:1 w:0) + // Storage: Paras CurrentCodeHash (r:1 w:0) + // Storage: Ump RelayDispatchQueueSize (r:1 w:0) + // Storage: Ump NeedsDispatch (r:1 w:1) + // Storage: Ump NextDispatchRoundStartWith (r:1 w:1) + // Storage: ParaInherent OnChainVotes (r:0 w:1) + // Storage: ParasDisputes Included (r:0 w:1) + // Storage: Hrmp HrmpWatermarks (r:0 w:1) + // Storage: Paras Heads (r:0 w:1) fn enter_backed_candidate_code_upgrade() -> Weight { - // Proof Size summary in bytes: - // Measured: `42876` - // Estimated: `48816` - // Minimum execution time: 34_352_245_000 picoseconds. - Weight::from_parts(34_587_559_000, 0) - .saturating_add(Weight::from_parts(0, 48816)) - .saturating_add(T::DbWeight::get().reads(29)) - .saturating_add(T::DbWeight::get().writes(16)) + Weight::from_parts(36_903_411_000 as u64, 0) + .saturating_add(T::DbWeight::get().reads(25 as u64)) + .saturating_add(T::DbWeight::get().writes(14 as u64)) } } diff --git a/polkadot/runtime/test-runtime/Cargo.toml b/polkadot/runtime/test-runtime/Cargo.toml index bdf68864605..9753a409304 100644 --- a/polkadot/runtime/test-runtime/Cargo.toml +++ b/polkadot/runtime/test-runtime/Cargo.toml @@ -155,7 +155,6 @@ runtime-benchmarks = [ "pallet-staking/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index a0617b3108f..6c899c52701 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -238,7 +238,6 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = frame_support::weights::ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; - type WeightInfo = (); } parameter_types! { @@ -394,7 +393,7 @@ where let current_block = System::block_number().saturated_into::().saturating_sub(1); let tip = 0; - let tx_ext: TxExtension = ( + let extra: SignedExtra = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -406,17 +405,16 @@ where frame_system::CheckNonce::::from(nonce), frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(tip), - ) - .into(); - let raw_payload = SignedPayload::new(call, tx_ext) + ); + let raw_payload = SignedPayload::new(call, extra) .map_err(|e| { log::warn!("Unable to create signed payload: {:?}", e); }) .ok()?; let signature = raw_payload.using_encoded(|payload| C::sign(payload, public))?; - let (call, tx_ext, _) = raw_payload.deconstruct(); + let (call, extra, _) = raw_payload.deconstruct(); let address = Indices::unlookup(account); - Some((call, (address, signature, tx_ext))) + Some((call, (address, signature, extra))) } } @@ -444,32 +442,12 @@ parameter_types! { pub Prefix: &'static [u8] = b"Pay KSMs to the Kusama account:"; } -#[cfg(feature = "runtime-benchmarks")] -pub struct ClaimsHelper; - -#[cfg(feature = "runtime-benchmarks")] -use frame_support::dispatch::DispatchInfo; - -#[cfg(feature = "runtime-benchmarks")] -impl claims::BenchmarkHelperTrait for ClaimsHelper { - fn default_call_and_info() -> (RuntimeCall, DispatchInfo) { - use frame_support::dispatch::GetDispatchInfo; - let call = RuntimeCall::Claims(claims::Call::attest { - statement: claims::StatementKind::Regular.to_text().to_vec(), - }); - let info = call.get_dispatch_info(); - (call, info) - } -} - impl claims::Config for Runtime { type RuntimeEvent = RuntimeEvent; type VestingSchedule = Vesting; type Prefix = Prefix; type MoveClaimOrigin = frame_system::EnsureRoot; type WeightInfo = claims::TestWeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = ClaimsHelper; } parameter_types! { @@ -750,8 +728,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// `BlockId` type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The extension to the basic transaction logic. -pub type TxExtension = ( +/// The `SignedExtension` to the basic transaction logic. +pub type SignedExtra = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -763,7 +741,7 @@ pub type TxExtension = ( ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< @@ -774,7 +752,7 @@ pub type Executive = frame_executive::Executive< AllPalletsWithSystem, >; /// The payload being signed in transactions. -pub type SignedPayload = generic::SignedPayload; +pub type SignedPayload = generic::SignedPayload; pub type Hash = ::Hash; pub type Extrinsic = ::Extrinsic; diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index 6899edeeaeb..4180828bcfb 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -270,7 +270,6 @@ runtime-benchmarks = [ "pallet-state-trie-migration/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "pallet-treasury/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 45bbd0260e5..b55d68ee0f6 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -200,7 +200,6 @@ impl frame_system::Config for Runtime { type Version = Version; type AccountData = pallet_balances::AccountData; type SystemWeightInfo = weights::frame_system::WeightInfo; - type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; type SS58Prefix = SS58Prefix; type MaxConsumers = frame_support::traits::ConstU32<16>; } @@ -386,7 +385,6 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; - type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -822,7 +820,7 @@ where // so the actual block number is `n`. .saturating_sub(1); let tip = 0; - let tx_ext: TxExtension = ( + let extra: SignedExtra = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -834,17 +832,16 @@ where frame_system::CheckNonce::::from(nonce), frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(tip), - ) - .into(); - let raw_payload = SignedPayload::new(call, tx_ext) + ); + let raw_payload = SignedPayload::new(call, extra) .map_err(|e| { log::warn!("Unable to create signed payload: {:?}", e); }) .ok()?; let signature = raw_payload.using_encoded(|payload| C::sign(payload, public))?; - let (call, tx_ext, _) = raw_payload.deconstruct(); + let (call, extra, _) = raw_payload.deconstruct(); let address = ::Lookup::unlookup(account); - Some((call, (address, signature, tx_ext))) + Some((call, (address, signature, extra))) } } @@ -1551,8 +1548,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// `BlockId` type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The extension to the basic transaction logic. -pub type TxExtension = ( +/// The `SignedExtension` to the basic transaction logic. +pub type SignedExtra = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -1716,7 +1713,7 @@ pub mod migrations { /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, @@ -1727,7 +1724,7 @@ pub type Executive = frame_executive::Executive< Migrations, >; /// The payload being signed in transactions. -pub type SignedPayload = generic::SignedPayload; +pub type SignedPayload = generic::SignedPayload; #[cfg(feature = "runtime-benchmarks")] mod benches { @@ -1773,9 +1770,7 @@ mod benches { [pallet_staking, Staking] [pallet_sudo, Sudo] [frame_system, SystemBench::] - [frame_system_extensions, SystemExtensionsBench::] [pallet_timestamp, Timestamp] - [pallet_transaction_payment, TransactionPayment] [pallet_treasury, Treasury] [pallet_utility, Utility] [pallet_vesting, Vesting] @@ -2317,7 +2312,6 @@ sp_api::impl_runtime_apis! { use pallet_election_provider_support_benchmarking::Pallet as ElectionProviderBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; type XcmBalances = pallet_xcm_benchmarks::fungible::Pallet::; @@ -2346,7 +2340,6 @@ sp_api::impl_runtime_apis! { use pallet_election_provider_support_benchmarking::Pallet as ElectionProviderBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; impl pallet_session_benchmarking::Config for Runtime {} diff --git a/polkadot/runtime/westend/src/weights/frame_system_extensions.rs b/polkadot/runtime/westend/src/weights/frame_system_extensions.rs deleted file mode 100644 index e4e1a799ec6..00000000000 --- a/polkadot/runtime/westend/src/weights/frame_system_extensions.rs +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `frame_system_extensions` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-20, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot -// benchmark -// pallet -// --steps=2 -// --repeat=2 -// --extrinsic=* -// --wasm-execution=compiled -// --heap-pages=4096 -// --pallet=frame-system-extensions -// --chain=westend-dev -// --output=./polkadot/runtime/westend/src/weights/ -// --header=./polkadot/file_header.txt - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `frame_system_extensions`. -pub struct WeightInfo(PhantomData); -impl frame_system::ExtensionsWeightInfo for WeightInfo { - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_genesis() -> Weight { - // Proof Size summary in bytes: - // Measured: `54` - // Estimated: `3509` - // Minimum execution time: 3_356_000 picoseconds. - Weight::from_parts(7_805_000, 0) - .saturating_add(Weight::from_parts(0, 3509)) - .saturating_add(T::DbWeight::get().reads(1)) - } - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_mortality() -> Weight { - // Proof Size summary in bytes: - // Measured: `92` - // Estimated: `3509` - // Minimum execution time: 5_510_000 picoseconds. - Weight::from_parts(10_009_000, 0) - .saturating_add(Weight::from_parts(0, 3509)) - .saturating_add(T::DbWeight::get().reads(1)) - } - fn check_non_zero_sender() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 761_000 picoseconds. - Weight::from_parts(4_308_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_nonce() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_396_000 picoseconds. - Weight::from_parts(7_585_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_spec_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 521_000 picoseconds. - Weight::from_parts(4_168_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn check_tx_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 541_000 picoseconds. - Weight::from_parts(4_228_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) - /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn check_weight() -> Weight { - // Proof Size summary in bytes: - // Measured: `24` - // Estimated: `1489` - // Minimum execution time: 3_807_000 picoseconds. - Weight::from_parts(8_025_000, 0) - .saturating_add(Weight::from_parts(0, 1489)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/westend/src/weights/mod.rs b/polkadot/runtime/westend/src/weights/mod.rs index 8aeb4216550..f6a9008d718 100644 --- a/polkadot/runtime/westend/src/weights/mod.rs +++ b/polkadot/runtime/westend/src/weights/mod.rs @@ -17,7 +17,6 @@ pub mod frame_election_provider_support; pub mod frame_system; -pub mod frame_system_extensions; pub mod pallet_asset_rate; pub mod pallet_bags_list; pub mod pallet_balances; @@ -38,7 +37,6 @@ pub mod pallet_session; pub mod pallet_staking; pub mod pallet_sudo; pub mod pallet_timestamp; -pub mod pallet_transaction_payment; pub mod pallet_treasury; pub mod pallet_utility; pub mod pallet_vesting; diff --git a/polkadot/runtime/westend/src/weights/pallet_sudo.rs b/polkadot/runtime/westend/src/weights/pallet_sudo.rs index 649c43e031d..e9ab3ad37a4 100644 --- a/polkadot/runtime/westend/src/weights/pallet_sudo.rs +++ b/polkadot/runtime/westend/src/weights/pallet_sudo.rs @@ -94,15 +94,4 @@ impl pallet_sudo::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Sudo::Key` (r:1 w:0) - /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - fn check_only_sudo_account() -> Weight { - // Proof Size summary in bytes: - // Measured: `132` - // Estimated: `1517` - // Minimum execution time: 2_875_000 picoseconds. - Weight::from_parts(6_803_000, 0) - .saturating_add(Weight::from_parts(0, 1517)) - .saturating_add(T::DbWeight::get().reads(1)) - } } diff --git a/polkadot/runtime/westend/src/weights/pallet_transaction_payment.rs b/polkadot/runtime/westend/src/weights/pallet_transaction_payment.rs deleted file mode 100644 index 001a09f103d..00000000000 --- a/polkadot/runtime/westend/src/weights/pallet_transaction_payment.rs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Autogenerated weights for `pallet_transaction_payment` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/polkadot -// benchmark -// pallet -// --steps=2 -// --repeat=2 -// --extrinsic=* -// --wasm-execution=compiled -// --heap-pages=4096 -// --pallet=pallet_transaction_payment -// --chain=westend-dev -// --output=./polkadot/runtime/westend/src/weights/ -// --header=./polkadot/file_header.txt - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_transaction_payment`. -pub struct WeightInfo(PhantomData); -impl pallet_transaction_payment::WeightInfo for WeightInfo { - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn charge_transaction_payment() -> Weight { - // Proof Size summary in bytes: - // Measured: `156` - // Estimated: `1641` - // Minimum execution time: 30_888_000 picoseconds. - Weight::from_parts(41_308_000, 0) - .saturating_add(Weight::from_parts(0, 1641)) - .saturating_add(T::DbWeight::get().reads(3)) - } -} diff --git a/polkadot/xcm/xcm-builder/Cargo.toml b/polkadot/xcm/xcm-builder/Cargo.toml index 660a30605e5..10726b0f511 100644 --- a/polkadot/xcm/xcm-builder/Cargo.toml +++ b/polkadot/xcm/xcm-builder/Cargo.toml @@ -47,7 +47,6 @@ runtime-benchmarks = [ "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-salary/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", diff --git a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs index 3bd2fa4b4f5..9892c500f2e 100644 --- a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs @@ -25,22 +25,14 @@ use frame_support::{ traits::{ConstU32, Everything}, }; use frame_system::{EnsureRoot, EnsureSigned}; +use polkadot_test_runtime::SignedExtra; use primitives::{AccountIndex, BlakeTwo256, Signature}; use sp_runtime::{generic, traits::MaybeEquivalence, AccountId32, BuildStorage}; use xcm_executor::{traits::ConvertLocation, XcmExecutor}; -pub type TxExtension = ( - frame_system::CheckNonZeroSender, - frame_system::CheckSpecVersion, - frame_system::CheckTxVersion, - frame_system::CheckGenesis, - frame_system::CheckMortality, - frame_system::CheckNonce, - frame_system::CheckWeight, -); pub type Address = sp_runtime::MultiAddress; pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; pub type Header = generic::Header; pub type Block = generic::Block; diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs index f953e54111c..a20390b64f9 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs @@ -46,13 +46,13 @@ use xcm_builder::{ }; use xcm_executor::{Config, XcmExecutor}; -pub type TxExtension = (frame_system::CheckNonZeroSender,); +pub type SignedExtra = (frame_system::CheckNonZeroSender,); pub type BlockNumber = u64; pub type Address = MultiAddress; pub type Header = generic::Header; pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; pub type Block = generic::Block; pub type Signature = MultiSignature; diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs index a11e535492c..5bf65fa9f9a 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs @@ -45,13 +45,13 @@ use xcm_builder::{ }; use xcm_executor::{Config, XcmExecutor}; -pub type TxExtension = (frame_system::CheckNonZeroSender,); +pub type SignedExtra = (frame_system::CheckNonZeroSender,); pub type BlockNumber = u64; pub type Address = MultiAddress; pub type Header = generic::Header; pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; pub type Block = generic::Block; pub type Signature = MultiSignature; diff --git a/prdoc/pr_2280.prdoc b/prdoc/pr_2280.prdoc deleted file mode 100644 index 3026dc254e6..00000000000 --- a/prdoc/pr_2280.prdoc +++ /dev/null @@ -1,144 +0,0 @@ -# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 -# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json - -title: FRAME Create `TransactionExtension` as a replacement for `SignedExtension` - -doc: - - audience: Runtime User - description: | - Introduces a new trait `TransactionExtension` to replace `SignedExtension`. Introduce the - idea of transactions which obey the runtime's extensions and have according Extension data - (né Extra data) yet do not have hard-coded signatures. - - Deprecate the terminology of "Unsigned" when used for transactions/extrinsics owing to there - now being "proper" unsigned transactions which obey the extension framework and "old-style" - unsigned which do not. Instead we have `General` for the former and `Bare` for the latter. - Unsigned will be phased out as a type of transaction, and `Bare` will only be used for - Inherents. - - Types of extrinsic are now therefore - - Bare (no hardcoded signature, no Extra data; used to be known as "Unsigned") - - Bare transactions (deprecated) - Gossiped, validated with `ValidateUnsigned` - (deprecated) and the `_bare_compat` bits of `TransactionExtension` (deprecated). - - Inherents - Not gossiped, validated with `ProvideInherent`. - - Extended (Extra data) - Gossiped, validated via `TransactionExtension`. - - Signed transactions (with a hardcoded signature). - - General transactions (without a hardcoded signature). - - Notable information on `TransactionExtension` and the differences from `SignedExtension` - - `AdditionalSigned`/`additional_signed` is renamed to `Implicit`/`implicit`. It is encoded - for the entire transaction and passed in to each extension as a new argument to validate. - - `pre_dispatch` is renamed to `prepare`. - - `validate` runs transaction validation logic both off-chain and on-chain, and is - non-mutating. - - `prepare` runs on-chain pre-execution logic using information extracted during validation - and is mutating. - - `validate` and `prepare` are now passed an `Origin` rather than an `AccountId`. If the - extension logic presumes an `AccountId`, consider using the trait function - `AsSystemOriginSigner::as_system_origin_signer`. - - A signature on the underlying transaction may validly not be present. - - The origin may be altered during validation. - - Validation functionality present in `validate` should not be repeated in `prepare`. - Useful information obtained during `validate` should now be passsed in to `prepare` using - the new user-specifiable type `Val`. - - Unsigned logic should be migrated from the old `*_unsigned` functions into the regular - versions of the new functions where the `Origin` is `None`. - - The `Call` type defining the runtime call is now a type parameter. - - `TransactionExtension` now takes a `Context` type parameter. This defines some arbitrary - contextual data that is injected into the transaction extension logic. It is unused in - instances migrated from `SignedExtension`. - - Extensions now track the weight they consume during valdiation, preparation and - post-dispatch through the `TransactionExtensionBase::weight` function. - - `TestXt` was removed and its usage in tests was replaced with `UncheckedExtrinsic` - instances. - - To fix the build issues introduced by this change, use the `AsTransactionExtension` adapter - to wrap existing `SignedExtension`s by converting them using the `From` - generic implementation for `AsTransactionExtension`. More details on migrating existing - `SignedExtension` implementations to `TransactionExtension` in the PR description. - -crates: - - name: bridge-runtime-common - - name: bp-bridge-hub-cumulus - - name: bp-kusama - - name: bp-polkadot-bulletin - - name: bp-polkadot - - name: bp-rococo - - name: bp-westend - - name: bp-polkadot-core - - name: bp-runtime - - name: snowbridge-pallet-inbound-queue - - name: snowbridge-pallet-outbound-queue - - name: snowbridge-pallet-system - - name: snowbridge-runtime-test-common - - name: parachain-template-runtime - - name: asset-hub-rococo-runtime - - name: asset-hub-westend-runtime - - name: bridge-hub-rococo-runtime - - name: bridge-hub-westend-runtime - - name: collectives-westend-runtime - - name: contracts-rococo-runtime - - name: coretime-rococo-runtime - - name: coretime-westend-runtime - - name: glutton-westend-runtime - - name: people-rococo-runtime - - name: people-westend-runtime - - name: seedling-runtime - - name: shell-runtime - - name: penpal-runtime - - name: rococo-parachain-runtime - - name: polkadot-parachain-bin - - name: cumulus-primitives-storage-weight-reclaim - - name: cumulus-test-client - - name: cumulus-test-runtime - - name: cumulus-test-service - - name: polkadot-sdk-docs - - name: polkadot-service - - name: polkadot-test-service - - name: polkadot-runtime-common - - name: rococo-runtime - - name: polkadot-test-runtime - - name: westend-runtime - - name: staging-xcm-builder - - name: minimal-runtime - - name: node-template - - name: node-template-runtime - - name: staging-node-cli - - name: kitchensink-runtime - - name: node-testing - - name: sc-client-api - - name: sc-client-db - - name: sc-network-gossip - - name: sc-network-sync - - name: sc-transaction-pool - - name: frame - - name: pallet-babe - - name: pallet-balances - - name: pallet-beefy - - name: pallet-collective - - name: pallet-election-provider-multi-phase - - name: pallet-elections-phragmen - - name: pallet-example-basic - - name: pallet-example-offchain-worker - - name: frame-executive - - name: pallet-grandpa - - name: pallet-im-online - - name: pallet-offences - - name: pallet-sassafras - - name: pallet-state-trie-migration - - name: pallet-sudo - - name: frame-support-procedural - - name: frame-support - - name: frame-system - - name: frame-system-benchmarking - - name: pallet-transaction-payment - - name: pallet-asset-conversion-tx-payment - - name: pallet-asset-tx-payment - - name: pallet-skip-feeless-payment - - name: sp-inherents - - name: sp-metadata-ir - - name: sp-runtime - - name: substrate-test-runtime - - name: frame-benchmarking-cli - - name: frame-remote-externalities - - name: substrate-rpc-client diff --git a/prdoc/pr_3665.prdoc b/prdoc/pr_3665.prdoc new file mode 100644 index 00000000000..67725d24d18 --- /dev/null +++ b/prdoc/pr_3665.prdoc @@ -0,0 +1,11 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Revert "FRAME Create TransactionExtension as a replacement for SignedExtension (#2280)" + +doc: + - audience: Runtime Dev + description: | + This PR reverts the PR which introduced `TransactionExtension` to replace `SignedExtension`. + +crates: [ ] diff --git a/substrate/.maintain/frame-weight-template.hbs b/substrate/.maintain/frame-weight-template.hbs index ec9eee205ce..ecd384a5145 100644 --- a/substrate/.maintain/frame-weight-template.hbs +++ b/substrate/.maintain/frame-weight-template.hbs @@ -33,7 +33,7 @@ pub trait WeightInfo { /// Weights for `{{pallet}}` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); -{{#if (or (eq pallet "frame_system") (eq pallet "frame_system_extensions"))}} +{{#if (eq pallet "frame_system")}} impl WeightInfo for SubstrateWeight { {{else}} impl WeightInfo for SubstrateWeight { diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index c91a83e6d6e..abe284c41da 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -196,7 +196,6 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "kitchensink-runtime/runtime-benchmarks", "node-inspect?/runtime-benchmarks", - "pallet-asset-conversion-tx-payment/runtime-benchmarks", "pallet-asset-tx-payment/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", @@ -206,7 +205,6 @@ runtime-benchmarks = [ "pallet-skip-feeless-payment/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "pallet-treasury/runtime-benchmarks", "sc-client-db/runtime-benchmarks", "sc-service/runtime-benchmarks", diff --git a/substrate/bin/node/cli/benches/block_production.rs b/substrate/bin/node/cli/benches/block_production.rs index b98a321c338..23a62cc0bd2 100644 --- a/substrate/bin/node/cli/benches/block_production.rs +++ b/substrate/bin/node/cli/benches/block_production.rs @@ -110,7 +110,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { fn extrinsic_set_time(now: u64) -> OpaqueExtrinsic { kitchensink_runtime::UncheckedExtrinsic { - preamble: sp_runtime::generic::Preamble::Bare, + signature: None, function: kitchensink_runtime::RuntimeCall::Timestamp(pallet_timestamp::Call::set { now }), } .into() diff --git a/substrate/bin/node/cli/benches/executor.rs b/substrate/bin/node/cli/benches/executor.rs index e13d34f9657..a326e1a79ea 100644 --- a/substrate/bin/node/cli/benches/executor.rs +++ b/substrate/bin/node/cli/benches/executor.rs @@ -29,7 +29,7 @@ use sp_core::{ storage::well_known_keys, traits::{CallContext, CodeExecutor, RuntimeCode}, }; -use sp_runtime::{generic::ExtrinsicFormat, traits::BlakeTwo256}; +use sp_runtime::traits::BlakeTwo256; use sp_state_machine::TestExternalities as CoreTestExternalities; use staging_node_cli::service::RuntimeExecutor; @@ -144,11 +144,11 @@ fn test_blocks( ) -> Vec<(Vec, Hash)> { let mut test_ext = new_test_ext(genesis_config); let mut block1_extrinsics = vec![CheckedExtrinsic { - format: ExtrinsicFormat::Bare, + signed: None, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: 0 }), }]; block1_extrinsics.extend((0..20).map(|i| CheckedExtrinsic { - format: ExtrinsicFormat::Signed(alice(), tx_ext(i, 0)), + signed: Some((alice(), signed_extra(i, 0))), function: RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest: bob().into(), value: 1 * DOLLARS, diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index 157f278fb53..8f2aba6b44c 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -107,21 +107,18 @@ pub fn create_extrinsic( .map(|c| c / 2) .unwrap_or(2) as u64; let tip = 0; - let tx_ext: kitchensink_runtime::TxExtension = + let extra: kitchensink_runtime::SignedExtra = ( - ( - frame_system::CheckNonZeroSender::::new(), - frame_system::CheckSpecVersion::::new(), - frame_system::CheckTxVersion::::new(), - frame_system::CheckGenesis::::new(), - frame_system::CheckEra::::from(generic::Era::mortal( - period, - best_block.saturated_into(), - )), - frame_system::CheckNonce::::from(nonce), - frame_system::CheckWeight::::new(), - ) - .into(), + frame_system::CheckNonZeroSender::::new(), + frame_system::CheckSpecVersion::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckGenesis::::new(), + frame_system::CheckEra::::from(generic::Era::mortal( + period, + best_block.saturated_into(), + )), + frame_system::CheckNonce::::from(nonce), + frame_system::CheckWeight::::new(), pallet_skip_feeless_payment::SkipCheckIfFeeless::from( pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::< kitchensink_runtime::Runtime, @@ -131,17 +128,15 @@ pub fn create_extrinsic( let raw_payload = kitchensink_runtime::SignedPayload::from_raw( function.clone(), - tx_ext.clone(), + extra.clone(), ( - ( - (), - kitchensink_runtime::VERSION.spec_version, - kitchensink_runtime::VERSION.transaction_version, - genesis_hash, - best_hash, - (), - (), - ), + (), + kitchensink_runtime::VERSION.spec_version, + kitchensink_runtime::VERSION.transaction_version, + genesis_hash, + best_hash, + (), + (), (), ), ); @@ -151,7 +146,7 @@ pub fn create_extrinsic( function, sp_runtime::AccountId32::from(sender.public()).into(), kitchensink_runtime::Signature::Sr25519(signature), - tx_ext, + extra, ) } @@ -796,7 +791,7 @@ mod tests { use codec::Encode; use kitchensink_runtime::{ constants::{currency::CENTS, time::SLOT_DURATION}, - Address, BalancesCall, RuntimeCall, TxExtension, UncheckedExtrinsic, + Address, BalancesCall, RuntimeCall, UncheckedExtrinsic, }; use node_primitives::{Block, DigestItem, Signature}; use sc_client_api::BlockBackend; @@ -998,31 +993,25 @@ mod tests { let tx_payment = pallet_skip_feeless_payment::SkipCheckIfFeeless::from( pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::from(0, None), ); - let tx_ext: TxExtension = ( - ( - check_non_zero_sender, - check_spec_version, - check_tx_version, - check_genesis, - check_era, - check_nonce, - check_weight, - ) - .into(), + let extra = ( + check_non_zero_sender, + check_spec_version, + check_tx_version, + check_genesis, + check_era, + check_nonce, + check_weight, tx_payment, ); let raw_payload = SignedPayload::from_raw( function, - tx_ext, - ( - ((), spec_version, transaction_version, genesis_hash, genesis_hash, (), ()), - (), - ), + extra, + ((), spec_version, transaction_version, genesis_hash, genesis_hash, (), (), ()), ); let signature = raw_payload.using_encoded(|payload| signer.sign(payload)); - let (function, tx_ext, _) = raw_payload.deconstruct(); + let (function, extra, _) = raw_payload.deconstruct(); index += 1; - UncheckedExtrinsic::new_signed(function, from.into(), signature.into(), tx_ext) + UncheckedExtrinsic::new_signed(function, from.into(), signature.into(), extra) .into() }, ); diff --git a/substrate/bin/node/cli/tests/basic.rs b/substrate/bin/node/cli/tests/basic.rs index 5fcb2295ef0..525ab2e39c1 100644 --- a/substrate/bin/node/cli/tests/basic.rs +++ b/substrate/bin/node/cli/tests/basic.rs @@ -67,7 +67,7 @@ fn transfer_fee(extrinsic: &E) -> Balance { fn xt() -> UncheckedExtrinsic { sign(CheckedExtrinsic { - format: sp_runtime::generic::ExtrinsicFormat::Signed(alice(), tx_ext(0, 0)), + signed: Some((alice(), signed_extra(0, 0))), function: RuntimeCall::Balances(default_transfer_call()), }) } @@ -84,11 +84,11 @@ fn changes_trie_block() -> (Vec, Hash) { GENESIS_HASH.into(), vec![ CheckedExtrinsic { - format: sp_runtime::generic::ExtrinsicFormat::Bare, + signed: None, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time }), }, CheckedExtrinsic { - format: sp_runtime::generic::ExtrinsicFormat::Signed(alice(), tx_ext(0, 0)), + signed: Some((alice(), signed_extra(0, 0))), function: RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest: bob().into(), value: 69 * DOLLARS, @@ -111,11 +111,11 @@ fn blocks() -> ((Vec, Hash), (Vec, Hash)) { GENESIS_HASH.into(), vec![ CheckedExtrinsic { - format: sp_runtime::generic::ExtrinsicFormat::Bare, + signed: None, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time1 }), }, CheckedExtrinsic { - format: sp_runtime::generic::ExtrinsicFormat::Signed(alice(), tx_ext(0, 0)), + signed: Some((alice(), signed_extra(0, 0))), function: RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest: bob().into(), value: 69 * DOLLARS, @@ -131,18 +131,18 @@ fn blocks() -> ((Vec, Hash), (Vec, Hash)) { block1.1, vec![ CheckedExtrinsic { - format: sp_runtime::generic::ExtrinsicFormat::Bare, + signed: None, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time2 }), }, CheckedExtrinsic { - format: sp_runtime::generic::ExtrinsicFormat::Signed(bob(), tx_ext(0, 0)), + signed: Some((bob(), signed_extra(0, 0))), function: RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest: alice().into(), value: 5 * DOLLARS, }), }, CheckedExtrinsic { - format: sp_runtime::generic::ExtrinsicFormat::Signed(alice(), tx_ext(1, 0)), + signed: Some((alice(), signed_extra(1, 0))), function: RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest: bob().into(), value: 15 * DOLLARS, @@ -166,11 +166,11 @@ fn block_with_size(time: u64, nonce: u32, size: usize) -> (Vec, Hash) { GENESIS_HASH.into(), vec![ CheckedExtrinsic { - format: sp_runtime::generic::ExtrinsicFormat::Bare, + signed: None, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time * 1000 }), }, CheckedExtrinsic { - format: sp_runtime::generic::ExtrinsicFormat::Signed(alice(), tx_ext(nonce, 0)), + signed: Some((alice(), signed_extra(nonce, 0))), function: RuntimeCall::System(frame_system::Call::remark { remark: vec![0; size] }), }, ], @@ -677,11 +677,11 @@ fn deploying_wasm_contract_should_work() { GENESIS_HASH.into(), vec![ CheckedExtrinsic { - format: sp_runtime::generic::ExtrinsicFormat::Bare, + signed: None, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time }), }, CheckedExtrinsic { - format: sp_runtime::generic::ExtrinsicFormat::Signed(charlie(), tx_ext(0, 0)), + signed: Some((charlie(), signed_extra(0, 0))), function: RuntimeCall::Contracts(pallet_contracts::Call::instantiate_with_code::< Runtime, > { @@ -694,7 +694,7 @@ fn deploying_wasm_contract_should_work() { }), }, CheckedExtrinsic { - format: sp_runtime::generic::ExtrinsicFormat::Signed(charlie(), tx_ext(1, 0)), + signed: Some((charlie(), signed_extra(1, 0))), function: RuntimeCall::Contracts(pallet_contracts::Call::call:: { dest: sp_runtime::MultiAddress::Id(addr.clone()), value: 10, diff --git a/substrate/bin/node/cli/tests/fees.rs b/substrate/bin/node/cli/tests/fees.rs index 9d6407067a3..8c7b3c87315 100644 --- a/substrate/bin/node/cli/tests/fees.rs +++ b/substrate/bin/node/cli/tests/fees.rs @@ -54,11 +54,11 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() { GENESIS_HASH.into(), vec![ CheckedExtrinsic { - format: sp_runtime::generic::ExtrinsicFormat::Bare, + signed: None, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time1 }), }, CheckedExtrinsic { - format: sp_runtime::generic::ExtrinsicFormat::Signed(charlie(), tx_ext(0, 0)), + signed: Some((charlie(), signed_extra(0, 0))), function: RuntimeCall::Sudo(pallet_sudo::Call::sudo { call: Box::new(RuntimeCall::RootTesting( pallet_root_testing::Call::fill_block { ratio: Perbill::from_percent(60) }, @@ -77,11 +77,11 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() { block1.1, vec![ CheckedExtrinsic { - format: sp_runtime::generic::ExtrinsicFormat::Bare, + signed: None, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time2 }), }, CheckedExtrinsic { - format: sp_runtime::generic::ExtrinsicFormat::Signed(charlie(), tx_ext(1, 0)), + signed: Some((charlie(), signed_extra(1, 0))), function: RuntimeCall::System(frame_system::Call::remark { remark: vec![0; 1] }), }, ], @@ -147,7 +147,7 @@ fn transaction_fee_is_correct() { let tip = 1_000_000; let xt = sign(CheckedExtrinsic { - format: sp_runtime::generic::ExtrinsicFormat::Signed(alice(), tx_ext(0, tip)), + signed: Some((alice(), signed_extra(0, tip))), function: RuntimeCall::Balances(default_transfer_call()), }); @@ -211,10 +211,7 @@ fn block_weight_capacity_report() { let num_transfers = block_number * factor; let mut xts = (0..num_transfers) .map(|i| CheckedExtrinsic { - format: sp_runtime::generic::ExtrinsicFormat::Signed( - charlie(), - tx_ext(nonce + i as Nonce, 0), - ), + signed: Some((charlie(), signed_extra(nonce + i as Nonce, 0))), function: RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest: bob().into(), value: 0, @@ -225,7 +222,7 @@ fn block_weight_capacity_report() { xts.insert( 0, CheckedExtrinsic { - format: sp_runtime::generic::ExtrinsicFormat::Bare, + signed: None, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time * 1000 }), }, ); @@ -288,16 +285,13 @@ fn block_length_capacity_report() { previous_hash, vec![ CheckedExtrinsic { - format: sp_runtime::generic::ExtrinsicFormat::Bare, + signed: None, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time * 1000, }), }, CheckedExtrinsic { - format: sp_runtime::generic::ExtrinsicFormat::Signed( - charlie(), - tx_ext(nonce, 0), - ), + signed: Some((charlie(), signed_extra(nonce, 0))), function: RuntimeCall::System(frame_system::Call::remark { remark: vec![0u8; (block_number * factor) as usize], }), diff --git a/substrate/bin/node/cli/tests/submit_transaction.rs b/substrate/bin/node/cli/tests/submit_transaction.rs index f3a5bac8fb5..5cbb0103d47 100644 --- a/substrate/bin/node/cli/tests/submit_transaction.rs +++ b/substrate/bin/node/cli/tests/submit_transaction.rs @@ -130,8 +130,8 @@ fn should_submit_signed_twice_from_the_same_account() { // now check that the transaction nonces are not equal let s = state.read(); fn nonce(tx: UncheckedExtrinsic) -> frame_system::CheckNonce { - let extra = tx.preamble.to_signed().unwrap().2; - (extra.0).5 + let extra = tx.signature.unwrap().2; + extra.5 } let nonce1 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[0]).unwrap()); let nonce2 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[1]).unwrap()); @@ -179,8 +179,8 @@ fn should_submit_signed_twice_from_all_accounts() { // now check that the transaction nonces are not equal let s = state.read(); fn nonce(tx: UncheckedExtrinsic) -> frame_system::CheckNonce { - let extra = tx.preamble.to_signed().unwrap().2; - (extra.0).5 + let extra = tx.signature.unwrap().2; + extra.5 } let nonce1 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[0]).unwrap()); let nonce2 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[1]).unwrap()); @@ -236,7 +236,7 @@ fn submitted_transaction_should_be_valid() { let source = TransactionSource::External; let extrinsic = UncheckedExtrinsic::decode(&mut &*tx0).unwrap(); // add balance to the account - let author = extrinsic.preamble.clone().to_signed().clone().unwrap().0; + let author = extrinsic.signature.clone().unwrap().0; let address = Indices::lookup(author).unwrap(); let data = pallet_balances::AccountData { free: 5_000_000_000_000, ..Default::default() }; let account = frame_system::AccountInfo { providers: 1, data, ..Default::default() }; diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index 09c8fb4ed3d..4d342ceb460 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -276,7 +276,6 @@ runtime-benchmarks = [ "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-alliance/runtime-benchmarks", - "pallet-asset-conversion-tx-payment/runtime-benchmarks", "pallet-asset-conversion/runtime-benchmarks", "pallet-asset-rate/runtime-benchmarks", "pallet-asset-tx-payment/runtime-benchmarks", @@ -334,7 +333,6 @@ runtime-benchmarks = [ "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-tips/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "pallet-transaction-storage/runtime-benchmarks", "pallet-treasury/runtime-benchmarks", "pallet-tx-pause/runtime-benchmarks", diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 96611f5a144..437f76c9d5f 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -560,7 +560,6 @@ impl pallet_transaction_payment::Config for Runtime { MinimumMultiplier, MaximumMultiplier, >; - type WeightInfo = pallet_transaction_payment::weights::SubstrateWeight; } impl pallet_asset_tx_payment::Config for Runtime { @@ -570,9 +569,6 @@ impl pallet_asset_tx_payment::Config for Runtime { pallet_assets::BalanceToAssetBalance, CreditToBlockAuthor, >; - type WeightInfo = pallet_asset_tx_payment::weights::SubstrateWeight; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = AssetTxHelper; } impl pallet_asset_conversion_tx_payment::Config for Runtime { @@ -583,9 +579,6 @@ impl pallet_asset_conversion_tx_payment::Config for Runtime { AssetConversion, Native, >; - type WeightInfo = pallet_asset_conversion_tx_payment::weights::SubstrateWeight; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = AssetConversionTxHelper; } impl pallet_skip_feeless_payment::Config for Runtime { @@ -1416,33 +1409,29 @@ where // so the actual block number is `n`. .saturating_sub(1); let era = Era::mortal(period, current_block); - let tx_ext: TxExtension = ( - ( - frame_system::CheckNonZeroSender::::new(), - frame_system::CheckSpecVersion::::new(), - frame_system::CheckTxVersion::::new(), - frame_system::CheckGenesis::::new(), - frame_system::CheckEra::::from(era), - frame_system::CheckNonce::::from(nonce), - frame_system::CheckWeight::::new(), - ) - .into(), + let extra = ( + frame_system::CheckNonZeroSender::::new(), + frame_system::CheckSpecVersion::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckGenesis::::new(), + frame_system::CheckEra::::from(era), + frame_system::CheckNonce::::from(nonce), + frame_system::CheckWeight::::new(), pallet_skip_feeless_payment::SkipCheckIfFeeless::from( pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::::from( tip, None, ), ), ); - - let raw_payload = SignedPayload::new(call, tx_ext) + let raw_payload = SignedPayload::new(call, extra) .map_err(|e| { log::warn!("Unable to create signed payload: {:?}", e); }) .ok()?; let signature = raw_payload.using_encoded(|payload| C::sign(payload, public))?; let address = Indices::unlookup(account); - let (call, tx_ext, _) = raw_payload.deconstruct(); - Some((call, (address, signature, tx_ext))) + let (call, extra, _) = raw_payload.deconstruct(); + Some((call, (address, signature, extra))) } } @@ -2461,21 +2450,19 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The TransactionExtension to the basic transaction logic. +/// The SignedExtension to the basic transaction logic. /// /// When you change this, you **MUST** modify [`sign`] in `bin/node/testing/src/keyring.rs`! /// /// [`sign`]: <../../testing/src/keyring.rs.html> -pub type TxExtension = ( - ( - frame_system::CheckNonZeroSender, - frame_system::CheckSpecVersion, - frame_system::CheckTxVersion, - frame_system::CheckGenesis, - frame_system::CheckEra, - frame_system::CheckNonce, - frame_system::CheckWeight, - ), +pub type SignedExtra = ( + frame_system::CheckNonZeroSender, + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, pallet_skip_feeless_payment::SkipCheckIfFeeless< Runtime, pallet_asset_conversion_tx_payment::ChargeAssetTxPayment, @@ -2484,11 +2471,11 @@ pub type TxExtension = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// The payload being signed in transactions. -pub type SignedPayload = generic::SignedPayload; +pub type SignedPayload = generic::SignedPayload; /// Extrinsic type that has already been checked. -pub type CheckedExtrinsic = generic::CheckedExtrinsic; +pub type CheckedExtrinsic = generic::CheckedExtrinsic; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, @@ -2543,106 +2530,6 @@ mod mmr { pub type Hashing = ::Hashing; } -#[cfg(feature = "runtime-benchmarks")] -pub struct AssetConversionTxHelper; - -#[cfg(feature = "runtime-benchmarks")] -impl pallet_asset_conversion_tx_payment::BenchmarkHelperTrait - for AssetConversionTxHelper -{ - fn create_asset_id_parameter(seed: u32) -> (u32, u32) { - (seed, seed) - } - - fn setup_balances_and_pool(asset_id: u32, account: AccountId) { - use frame_support::{assert_ok, traits::fungibles::Mutate}; - assert_ok!(Assets::force_create( - RuntimeOrigin::root(), - asset_id.into(), - account.clone().into(), /* owner */ - true, /* is_sufficient */ - 1, - )); - - let lp_provider = account.clone(); - let _ = Balances::deposit_creating(&lp_provider, ((u64::MAX as u128) * 100).into()); - assert_ok!(Assets::mint_into( - asset_id.into(), - &lp_provider, - ((u64::MAX as u128) * 100).into() - )); - - let token_native = Box::new(NativeOrWithId::Native); - let token_second = Box::new(NativeOrWithId::WithId(asset_id)); - - assert_ok!(AssetConversion::create_pool( - RuntimeOrigin::signed(lp_provider.clone()), - token_native.clone(), - token_second.clone() - )); - - assert_ok!(AssetConversion::add_liquidity( - RuntimeOrigin::signed(lp_provider.clone()), - token_native, - token_second, - u64::MAX.into(), // 1 desired - u64::MAX.into(), // 2 desired - 1, // 1 min - 1, // 2 min - lp_provider, - )); - } -} - -#[cfg(feature = "runtime-benchmarks")] -pub struct AssetTxHelper; - -#[cfg(feature = "runtime-benchmarks")] -impl pallet_asset_tx_payment::BenchmarkHelperTrait for AssetTxHelper { - fn create_asset_id_parameter(seed: u32) -> (u32, u32) { - (seed, seed) - } - - fn setup_balances_and_pool(asset_id: u32, account: AccountId) { - use frame_support::{assert_ok, traits::fungibles::Mutate}; - assert_ok!(Assets::force_create( - RuntimeOrigin::root(), - asset_id.into(), - account.clone().into(), /* owner */ - true, /* is_sufficient */ - 1, - )); - - let lp_provider = account.clone(); - let _ = Balances::deposit_creating(&lp_provider, ((u64::MAX as u128) * 100).into()); - assert_ok!(Assets::mint_into( - asset_id.into(), - &lp_provider, - ((u64::MAX as u128) * 100).into() - )); - - let token_native = Box::new(NativeOrWithId::Native); - let token_second = Box::new(NativeOrWithId::WithId(asset_id)); - - assert_ok!(AssetConversion::create_pool( - RuntimeOrigin::signed(lp_provider.clone()), - token_native.clone(), - token_second.clone() - )); - - assert_ok!(AssetConversion::add_liquidity( - RuntimeOrigin::signed(lp_provider.clone()), - token_native, - token_second, - u64::MAX.into(), // 1 desired - u64::MAX.into(), // 2 desired - 1, // 1 min - 1, // 2 min - lp_provider, - )); - } -} - #[cfg(feature = "runtime-benchmarks")] mod benches { frame_benchmarking::define_benchmarks!( @@ -2663,9 +2550,6 @@ mod benches { [tasks_example, TasksExample] [pallet_democracy, Democracy] [pallet_asset_conversion, AssetConversion] - [pallet_asset_conversion_tx_payment, AssetConversionTxPayment] - [pallet_asset_tx_payment, AssetTxPayment] - [pallet_transaction_payment, TransactionPayment] [pallet_election_provider_multi_phase, ElectionProviderMultiPhase] [pallet_election_provider_support_benchmarking, EPSBench::] [pallet_elections_phragmen, Elections] @@ -2699,7 +2583,6 @@ mod benches { [pallet_state_trie_migration, StateTrieMigration] [pallet_sudo, Sudo] [frame_system, SystemBench::] - [frame_system_extensions, SystemExtensionsBench::] [pallet_timestamp, Timestamp] [pallet_tips, Tips] [pallet_transaction_storage, TransactionStorage] @@ -3247,7 +3130,6 @@ impl_runtime_apis! { use pallet_offences_benchmarking::Pallet as OffencesBench; use pallet_election_provider_support_benchmarking::Pallet as EPSBench; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use baseline::Pallet as BaselineBench; use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; @@ -3272,7 +3154,6 @@ impl_runtime_apis! { use pallet_offences_benchmarking::Pallet as OffencesBench; use pallet_election_provider_support_benchmarking::Pallet as EPSBench; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use baseline::Pallet as BaselineBench; use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; diff --git a/substrate/bin/node/testing/src/bench.rs b/substrate/bin/node/testing/src/bench.rs index ccf79eed884..df302a6453b 100644 --- a/substrate/bin/node/testing/src/bench.rs +++ b/substrate/bin/node/testing/src/bench.rs @@ -51,7 +51,6 @@ use sp_core::{ed25519, sr25519, traits::SpawnNamed, Pair, Public}; use sp_crypto_hashing::blake2_256; use sp_inherents::InherentData; use sp_runtime::{ - generic::{ExtrinsicFormat, Preamble}, traits::{Block as BlockT, IdentifyAccount, Verify}, OpaqueExtrinsic, }; @@ -296,10 +295,10 @@ impl<'a> Iterator for BlockContentIterator<'a> { let signed = self.keyring.sign( CheckedExtrinsic { - format: ExtrinsicFormat::Signed( + signed: Some(( sender, - tx_ext(0, kitchensink_runtime::ExistentialDeposit::get() + 1), - ), + signed_extra(0, kitchensink_runtime::ExistentialDeposit::get() + 1), + )), function: match self.content.block_type { BlockType::RandomTransfersKeepAlive => RuntimeCall::Balances(BalancesCall::transfer_keep_alive { @@ -563,11 +562,11 @@ impl BenchKeyring { tx_version: u32, genesis_hash: [u8; 32], ) -> UncheckedExtrinsic { - match xt.format { - ExtrinsicFormat::Signed(signed, tx_ext) => { + match xt.signed { + Some((signed, extra)) => { let payload = ( xt.function, - tx_ext.clone(), + extra.clone(), spec_version, tx_version, genesis_hash, @@ -582,20 +581,11 @@ impl BenchKeyring { } }); UncheckedExtrinsic { - preamble: Preamble::Signed( - sp_runtime::MultiAddress::Id(signed), - signature, - tx_ext, - ), + signature: Some((sp_runtime::MultiAddress::Id(signed), signature, extra)), function: payload.0, } }, - ExtrinsicFormat::Bare => - UncheckedExtrinsic { preamble: Preamble::Bare, function: xt.function }, - ExtrinsicFormat::General(tx_ext) => UncheckedExtrinsic { - preamble: sp_runtime::generic::Preamble::General(tx_ext), - function: xt.function, - }, + None => UncheckedExtrinsic { signature: None, function: xt.function }, } } diff --git a/substrate/bin/node/testing/src/keyring.rs b/substrate/bin/node/testing/src/keyring.rs index 13daf915325..f712191bed6 100644 --- a/substrate/bin/node/testing/src/keyring.rs +++ b/substrate/bin/node/testing/src/keyring.rs @@ -19,13 +19,13 @@ //! Test accounts. use codec::Encode; -use kitchensink_runtime::{CheckedExtrinsic, SessionKeys, TxExtension, UncheckedExtrinsic}; +use kitchensink_runtime::{CheckedExtrinsic, SessionKeys, SignedExtra, UncheckedExtrinsic}; use node_cli::chain_spec::get_from_seed; use node_primitives::{AccountId, Balance, Nonce}; use sp_core::{ecdsa, ed25519, sr25519}; use sp_crypto_hashing::blake2_256; use sp_keyring::AccountKeyring; -use sp_runtime::generic::{Era, ExtrinsicFormat}; +use sp_runtime::generic::Era; /// Alice's account id. pub fn alice() -> AccountId { @@ -70,18 +70,15 @@ pub fn session_keys_from_seed(seed: &str) -> SessionKeys { } /// Returns transaction extra. -pub fn tx_ext(nonce: Nonce, extra_fee: Balance) -> TxExtension { +pub fn signed_extra(nonce: Nonce, extra_fee: Balance) -> SignedExtra { ( - ( - frame_system::CheckNonZeroSender::new(), - frame_system::CheckSpecVersion::new(), - frame_system::CheckTxVersion::new(), - frame_system::CheckGenesis::new(), - frame_system::CheckEra::from(Era::mortal(256, 0)), - frame_system::CheckNonce::from(nonce), - frame_system::CheckWeight::new(), - ) - .into(), + frame_system::CheckNonZeroSender::new(), + frame_system::CheckSpecVersion::new(), + frame_system::CheckTxVersion::new(), + frame_system::CheckGenesis::new(), + frame_system::CheckEra::from(Era::mortal(256, 0)), + frame_system::CheckNonce::from(nonce), + frame_system::CheckWeight::new(), pallet_skip_feeless_payment::SkipCheckIfFeeless::from( pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::from(extra_fee, None), ), @@ -95,10 +92,10 @@ pub fn sign( tx_version: u32, genesis_hash: [u8; 32], ) -> UncheckedExtrinsic { - match xt.format { - ExtrinsicFormat::Signed(signed, tx_ext) => { + match xt.signed { + Some((signed, extra)) => { let payload = - (xt.function, tx_ext.clone(), spec_version, tx_version, genesis_hash, genesis_hash); + (xt.function, extra.clone(), spec_version, tx_version, genesis_hash, genesis_hash); let key = AccountKeyring::from_account_id(&signed).unwrap(); let signature = payload @@ -111,21 +108,10 @@ pub fn sign( }) .into(); UncheckedExtrinsic { - preamble: sp_runtime::generic::Preamble::Signed( - sp_runtime::MultiAddress::Id(signed), - signature, - tx_ext, - ), + signature: Some((sp_runtime::MultiAddress::Id(signed), signature, extra)), function: payload.0, } }, - ExtrinsicFormat::Bare => UncheckedExtrinsic { - preamble: sp_runtime::generic::Preamble::Bare, - function: xt.function, - }, - ExtrinsicFormat::General(tx_ext) => UncheckedExtrinsic { - preamble: sp_runtime::generic::Preamble::General(tx_ext), - function: xt.function, - }, + None => UncheckedExtrinsic { signature: None, function: xt.function }, } } diff --git a/substrate/client/api/src/notifications/tests.rs b/substrate/client/api/src/notifications/tests.rs index 7afdcbd9543..fba829b1cf9 100644 --- a/substrate/client/api/src/notifications/tests.rs +++ b/substrate/client/api/src/notifications/tests.rs @@ -18,10 +18,7 @@ use super::*; -use sp_runtime::{ - generic::UncheckedExtrinsic, - testing::{Block as RawBlock, H256 as Hash}, -}; +use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper, H256 as Hash}; use std::iter::{empty, Empty}; type TestChangeSet = ( @@ -53,7 +50,7 @@ impl PartialEq for StorageChangeSet { } } -type Block = RawBlock>; +type Block = RawBlock>; #[test] fn triggering_change_should_notify_wildcard_listeners() { diff --git a/substrate/client/db/benches/state_access.rs b/substrate/client/db/benches/state_access.rs index 9f3b8ca77c2..e47559e710d 100644 --- a/substrate/client/db/benches/state_access.rs +++ b/substrate/client/db/benches/state_access.rs @@ -22,13 +22,12 @@ use sc_client_api::{Backend as _, BlockImportOperation, NewBlockState, StateBack use sc_client_db::{Backend, BlocksPruning, DatabaseSettings, DatabaseSource, PruningMode}; use sp_core::H256; use sp_runtime::{ - generic::UncheckedExtrinsic, - testing::{Block as RawBlock, Header, MockCallU64}, + testing::{Block as RawBlock, ExtrinsicWrapper, Header}, StateVersion, Storage, }; use tempfile::TempDir; -pub(crate) type Block = RawBlock>; +pub(crate) type Block = RawBlock>; fn insert_blocks(db: &Backend, storage: Vec<(Vec, Vec)>) -> H256 { let mut op = db.begin_operation().unwrap(); diff --git a/substrate/client/db/src/lib.rs b/substrate/client/db/src/lib.rs index f22022ef29a..0faa90dfc4f 100644 --- a/substrate/client/db/src/lib.rs +++ b/substrate/client/db/src/lib.rs @@ -2573,8 +2573,7 @@ pub(crate) mod tests { use sp_blockchain::{lowest_common_ancestor, tree_route}; use sp_core::H256; use sp_runtime::{ - generic::UncheckedExtrinsic, - testing::{Block as RawBlock, Header, MockCallU64}, + testing::{Block as RawBlock, ExtrinsicWrapper, Header}, traits::{BlakeTwo256, Hash}, ConsensusEngineId, StateVersion, }; @@ -2582,8 +2581,7 @@ pub(crate) mod tests { const CONS0_ENGINE_ID: ConsensusEngineId = *b"CON0"; const CONS1_ENGINE_ID: ConsensusEngineId = *b"CON1"; - type UncheckedXt = UncheckedExtrinsic; - pub(crate) type Block = RawBlock; + pub(crate) type Block = RawBlock>; pub fn insert_header( backend: &Backend, @@ -2602,7 +2600,7 @@ pub(crate) mod tests { parent_hash: H256, _changes: Option, Vec)>>, extrinsics_root: H256, - body: Vec, + body: Vec>, transaction_index: Option>, ) -> Result { use sp_runtime::testing::Digest; @@ -3416,7 +3414,7 @@ pub(crate) mod tests { prev_hash, None, Default::default(), - vec![UncheckedXt::new_transaction(i.into(), ())], + vec![i.into()], None, ) .unwrap(); @@ -3438,20 +3436,11 @@ pub(crate) mod tests { assert_eq!(None, bc.body(blocks[0]).unwrap()); assert_eq!(None, bc.body(blocks[1]).unwrap()); assert_eq!(None, bc.body(blocks[2]).unwrap()); - assert_eq!( - Some(vec![UncheckedXt::new_transaction(3.into(), ())]), - bc.body(blocks[3]).unwrap() - ); - assert_eq!( - Some(vec![UncheckedXt::new_transaction(4.into(), ())]), - bc.body(blocks[4]).unwrap() - ); + assert_eq!(Some(vec![3.into()]), bc.body(blocks[3]).unwrap()); + assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); } else { for i in 0..5 { - assert_eq!( - Some(vec![UncheckedXt::new_transaction((i as u64).into(), ())]), - bc.body(blocks[i]).unwrap() - ); + assert_eq!(Some(vec![(i as u64).into()]), bc.body(blocks[i]).unwrap()); } } } @@ -3475,7 +3464,7 @@ pub(crate) mod tests { prev_hash, None, Default::default(), - vec![UncheckedXt::new_transaction(i.into(), ())], + vec![i.into()], None, ) .unwrap(); @@ -3484,26 +3473,16 @@ pub(crate) mod tests { } // insert a fork at block 2 - let fork_hash_root = insert_block( - &backend, - 2, - blocks[1], - None, - H256::random(), - vec![UncheckedXt::new_transaction(2.into(), ())], - None, - ) - .unwrap(); + let fork_hash_root = + insert_block(&backend, 2, blocks[1], None, H256::random(), vec![2.into()], None) + .unwrap(); insert_block( &backend, 3, fork_hash_root, None, H256::random(), - vec![ - UncheckedXt::new_transaction(3.into(), ()), - UncheckedXt::new_transaction(11.into(), ()), - ], + vec![3.into(), 11.into()], None, ) .unwrap(); @@ -3513,10 +3492,7 @@ pub(crate) mod tests { backend.commit_operation(op).unwrap(); let bc = backend.blockchain(); - assert_eq!( - Some(vec![UncheckedXt::new_transaction(2.into(), ())]), - bc.body(fork_hash_root).unwrap() - ); + assert_eq!(Some(vec![2.into()]), bc.body(fork_hash_root).unwrap()); for i in 1..5 { let mut op = backend.begin_operation().unwrap(); @@ -3530,28 +3506,16 @@ pub(crate) mod tests { assert_eq!(None, bc.body(blocks[1]).unwrap()); assert_eq!(None, bc.body(blocks[2]).unwrap()); - assert_eq!( - Some(vec![UncheckedXt::new_transaction(3.into(), ())]), - bc.body(blocks[3]).unwrap() - ); - assert_eq!( - Some(vec![UncheckedXt::new_transaction(4.into(), ())]), - bc.body(blocks[4]).unwrap() - ); + assert_eq!(Some(vec![3.into()]), bc.body(blocks[3]).unwrap()); + assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); } else { for i in 0..5 { - assert_eq!( - Some(vec![UncheckedXt::new_transaction((i as u64).into(), ())]), - bc.body(blocks[i]).unwrap() - ); + assert_eq!(Some(vec![(i as u64).into()]), bc.body(blocks[i]).unwrap()); } } if matches!(pruning, BlocksPruning::KeepAll) { - assert_eq!( - Some(vec![UncheckedXt::new_transaction(2.into(), ())]), - bc.body(fork_hash_root).unwrap() - ); + assert_eq!(Some(vec![2.into()]), bc.body(fork_hash_root).unwrap()); } else { assert_eq!(None, bc.body(fork_hash_root).unwrap()); } @@ -3572,16 +3536,8 @@ pub(crate) mod tests { let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(10), 10); let make_block = |index, parent, val: u64| { - insert_block( - &backend, - index, - parent, - None, - H256::random(), - vec![UncheckedXt::new_transaction(val.into(), ())], - None, - ) - .unwrap() + insert_block(&backend, index, parent, None, H256::random(), vec![val.into()], None) + .unwrap() }; let block_0 = make_block(0, Default::default(), 0x00); @@ -3609,30 +3565,18 @@ pub(crate) mod tests { let bc = backend.blockchain(); assert_eq!(None, bc.body(block_1b).unwrap()); assert_eq!(None, bc.body(block_2b).unwrap()); - assert_eq!( - Some(vec![UncheckedXt::new_transaction(0x00.into(), ())]), - bc.body(block_0).unwrap() - ); - assert_eq!( - Some(vec![UncheckedXt::new_transaction(0x1a.into(), ())]), - bc.body(block_1a).unwrap() - ); - assert_eq!( - Some(vec![UncheckedXt::new_transaction(0x2a.into(), ())]), - bc.body(block_2a).unwrap() - ); - assert_eq!( - Some(vec![UncheckedXt::new_transaction(0x3a.into(), ())]), - bc.body(block_3a).unwrap() - ); + assert_eq!(Some(vec![0x00.into()]), bc.body(block_0).unwrap()); + assert_eq!(Some(vec![0x1a.into()]), bc.body(block_1a).unwrap()); + assert_eq!(Some(vec![0x2a.into()]), bc.body(block_2a).unwrap()); + assert_eq!(Some(vec![0x3a.into()]), bc.body(block_3a).unwrap()); } #[test] fn indexed_data_block_body() { let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(1), 10); - let x0 = UncheckedXt::new_transaction(0.into(), ()).encode(); - let x1 = UncheckedXt::new_transaction(1.into(), ()).encode(); + let x0 = ExtrinsicWrapper::from(0u64).encode(); + let x1 = ExtrinsicWrapper::from(1u64).encode(); let x0_hash = as sp_core::Hasher>::hash(&x0[1..]); let x1_hash = as sp_core::Hasher>::hash(&x1[1..]); let index = vec![ @@ -3653,10 +3597,7 @@ pub(crate) mod tests { Default::default(), None, Default::default(), - vec![ - UncheckedXt::new_transaction(0.into(), ()), - UncheckedXt::new_transaction(1.into(), ()), - ], + vec![0u64.into(), 1u64.into()], Some(index), ) .unwrap(); @@ -3678,9 +3619,8 @@ pub(crate) mod tests { fn index_invalid_size() { let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(1), 10); - let x0 = UncheckedXt::new_transaction(0.into(), ()).encode(); - let x1 = UncheckedXt::new_transaction(1.into(), ()).encode(); - + let x0 = ExtrinsicWrapper::from(0u64).encode(); + let x1 = ExtrinsicWrapper::from(1u64).encode(); let x0_hash = as sp_core::Hasher>::hash(&x0[..]); let x1_hash = as sp_core::Hasher>::hash(&x1[..]); let index = vec![ @@ -3701,10 +3641,7 @@ pub(crate) mod tests { Default::default(), None, Default::default(), - vec![ - UncheckedXt::new_transaction(0.into(), ()), - UncheckedXt::new_transaction(1.into(), ()), - ], + vec![0u64.into(), 1u64.into()], Some(index), ) .unwrap(); @@ -3718,7 +3655,7 @@ pub(crate) mod tests { let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(2), 10); let mut blocks = Vec::new(); let mut prev_hash = Default::default(); - let x1 = UncheckedXt::new_transaction(0.into(), ()).encode(); + let x1 = ExtrinsicWrapper::from(0u64).encode(); let x1_hash = as sp_core::Hasher>::hash(&x1[1..]); for i in 0..10 { let mut index = Vec::new(); @@ -3738,7 +3675,7 @@ pub(crate) mod tests { prev_hash, None, Default::default(), - vec![UncheckedXt::new_transaction(i.into(), ())], + vec![i.into()], Some(index), ) .unwrap(); @@ -3772,7 +3709,7 @@ pub(crate) mod tests { prev_hash, None, Default::default(), - vec![UncheckedXt::new_transaction(i.into(), ())], + vec![i.into()], None, ) .unwrap(); @@ -3787,7 +3724,7 @@ pub(crate) mod tests { blocks[1], None, sp_core::H256::random(), - vec![UncheckedXt::new_transaction(i.into(), ())], + vec![i.into()], None, ) .unwrap(); @@ -3801,7 +3738,7 @@ pub(crate) mod tests { blocks[0], None, sp_core::H256::random(), - vec![UncheckedXt::new_transaction(42.into(), ())], + vec![42.into()], None, ) .unwrap(); @@ -4274,7 +4211,7 @@ pub(crate) mod tests { prev_hash, None, Default::default(), - vec![UncheckedXt::new_transaction(i.into(), ())], + vec![i.into()], None, ) .unwrap(); @@ -4289,10 +4226,7 @@ pub(crate) mod tests { // Check that we can properly access values when there is reference count // but no value. - assert_eq!( - Some(vec![UncheckedXt::new_transaction(1.into(), ())]), - bc.body(blocks[1]).unwrap() - ); + assert_eq!(Some(vec![1.into()]), bc.body(blocks[1]).unwrap()); // Block 1 gets pinned three times backend.pin_block(blocks[1]).unwrap(); @@ -4309,42 +4243,27 @@ pub(crate) mod tests { // Block 0, 1, 2, 3 are pinned, so all values should be cached. // Block 4 is inside the pruning window, its value is in db. - assert_eq!( - Some(vec![UncheckedXt::new_transaction(0.into(), ())]), - bc.body(blocks[0]).unwrap() - ); + assert_eq!(Some(vec![0.into()]), bc.body(blocks[0]).unwrap()); - assert_eq!( - Some(vec![UncheckedXt::new_transaction(1.into(), ())]), - bc.body(blocks[1]).unwrap() - ); + assert_eq!(Some(vec![1.into()]), bc.body(blocks[1]).unwrap()); assert_eq!( Some(Justifications::from(build_justification(1))), bc.justifications(blocks[1]).unwrap() ); - assert_eq!( - Some(vec![UncheckedXt::new_transaction(2.into(), ())]), - bc.body(blocks[2]).unwrap() - ); + assert_eq!(Some(vec![2.into()]), bc.body(blocks[2]).unwrap()); assert_eq!( Some(Justifications::from(build_justification(2))), bc.justifications(blocks[2]).unwrap() ); - assert_eq!( - Some(vec![UncheckedXt::new_transaction(3.into(), ())]), - bc.body(blocks[3]).unwrap() - ); + assert_eq!(Some(vec![3.into()]), bc.body(blocks[3]).unwrap()); assert_eq!( Some(Justifications::from(build_justification(3))), bc.justifications(blocks[3]).unwrap() ); - assert_eq!( - Some(vec![UncheckedXt::new_transaction(4.into(), ())]), - bc.body(blocks[4]).unwrap() - ); + assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); assert_eq!( Some(Justifications::from(build_justification(4))), bc.justifications(blocks[4]).unwrap() @@ -4375,10 +4294,7 @@ pub(crate) mod tests { assert!(bc.justifications(blocks[1]).unwrap().is_none()); // Block 4 is inside the pruning window and still kept - assert_eq!( - Some(vec![UncheckedXt::new_transaction(4.into(), ())]), - bc.body(blocks[4]).unwrap() - ); + assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); assert_eq!( Some(Justifications::from(build_justification(4))), bc.justifications(blocks[4]).unwrap() @@ -4386,16 +4302,9 @@ pub(crate) mod tests { // Block tree: // 0 -> 1 -> 2 -> 3 -> 4 -> 5 - let hash = insert_block( - &backend, - 5, - prev_hash, - None, - Default::default(), - vec![UncheckedXt::new_transaction(5.into(), ())], - None, - ) - .unwrap(); + let hash = + insert_block(&backend, 5, prev_hash, None, Default::default(), vec![5.into()], None) + .unwrap(); blocks.push(hash); backend.pin_block(blocks[4]).unwrap(); @@ -4410,18 +4319,12 @@ pub(crate) mod tests { assert!(bc.body(blocks[2]).unwrap().is_none()); assert!(bc.body(blocks[3]).unwrap().is_none()); - assert_eq!( - Some(vec![UncheckedXt::new_transaction(4.into(), ())]), - bc.body(blocks[4]).unwrap() - ); + assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); assert_eq!( Some(Justifications::from(build_justification(4))), bc.justifications(blocks[4]).unwrap() ); - assert_eq!( - Some(vec![UncheckedXt::new_transaction(5.into(), ())]), - bc.body(blocks[5]).unwrap() - ); + assert_eq!(Some(vec![5.into()]), bc.body(blocks[5]).unwrap()); assert!(bc.header(blocks[5]).ok().flatten().is_some()); backend.unpin_block(blocks[4]); @@ -4431,16 +4334,9 @@ pub(crate) mod tests { // Append a justification to block 5. backend.append_justification(blocks[5], ([0, 0, 0, 1], vec![42])).unwrap(); - let hash = insert_block( - &backend, - 6, - blocks[5], - None, - Default::default(), - vec![UncheckedXt::new_transaction(6.into(), ())], - None, - ) - .unwrap(); + let hash = + insert_block(&backend, 6, blocks[5], None, Default::default(), vec![6.into()], None) + .unwrap(); blocks.push(hash); // Pin block 5 so it gets loaded into the cache on prune @@ -4453,10 +4349,7 @@ pub(crate) mod tests { op.mark_finalized(blocks[6], None).unwrap(); backend.commit_operation(op).unwrap(); - assert_eq!( - Some(vec![UncheckedXt::new_transaction(5.into(), ())]), - bc.body(blocks[5]).unwrap() - ); + assert_eq!(Some(vec![5.into()]), bc.body(blocks[5]).unwrap()); assert!(bc.header(blocks[5]).ok().flatten().is_some()); let mut expected = Justifications::from(build_justification(5)); expected.append(([0, 0, 0, 1], vec![42])); @@ -4478,7 +4371,7 @@ pub(crate) mod tests { prev_hash, None, Default::default(), - vec![UncheckedXt::new_transaction(i.into(), ())], + vec![i.into()], None, ) .unwrap(); @@ -4494,26 +4387,16 @@ pub(crate) mod tests { // Block tree: // 0 -> 1 -> 2 -> 3 -> 4 // \ -> 2 -> 3 - let fork_hash_root = insert_block( - &backend, - 2, - blocks[1], - None, - H256::random(), - vec![UncheckedXt::new_transaction(2.into(), ())], - None, - ) - .unwrap(); + let fork_hash_root = + insert_block(&backend, 2, blocks[1], None, H256::random(), vec![2.into()], None) + .unwrap(); let fork_hash_3 = insert_block( &backend, 3, fork_hash_root, None, H256::random(), - vec![ - UncheckedXt::new_transaction(3.into(), ()), - UncheckedXt::new_transaction(11.into(), ()), - ], + vec![3.into(), 11.into()], None, ) .unwrap(); @@ -4534,35 +4417,14 @@ pub(crate) mod tests { } let bc = backend.blockchain(); - assert_eq!( - Some(vec![UncheckedXt::new_transaction(0.into(), ())]), - bc.body(blocks[0]).unwrap() - ); - assert_eq!( - Some(vec![UncheckedXt::new_transaction(1.into(), ())]), - bc.body(blocks[1]).unwrap() - ); - assert_eq!( - Some(vec![UncheckedXt::new_transaction(2.into(), ())]), - bc.body(blocks[2]).unwrap() - ); - assert_eq!( - Some(vec![UncheckedXt::new_transaction(3.into(), ())]), - bc.body(blocks[3]).unwrap() - ); - assert_eq!( - Some(vec![UncheckedXt::new_transaction(4.into(), ())]), - bc.body(blocks[4]).unwrap() - ); + assert_eq!(Some(vec![0.into()]), bc.body(blocks[0]).unwrap()); + assert_eq!(Some(vec![1.into()]), bc.body(blocks[1]).unwrap()); + assert_eq!(Some(vec![2.into()]), bc.body(blocks[2]).unwrap()); + assert_eq!(Some(vec![3.into()]), bc.body(blocks[3]).unwrap()); + assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); // Check the fork hashes. assert_eq!(None, bc.body(fork_hash_root).unwrap()); - assert_eq!( - Some(vec![ - UncheckedXt::new_transaction(3.into(), ()), - UncheckedXt::new_transaction(11.into(), ()) - ]), - bc.body(fork_hash_3).unwrap() - ); + assert_eq!(Some(vec![3.into(), 11.into()]), bc.body(fork_hash_3).unwrap()); // Unpin all blocks, except the forked one. for block in &blocks { diff --git a/substrate/client/db/src/utils.rs b/substrate/client/db/src/utils.rs index d2a5f7e718a..abf9c4629ce 100644 --- a/substrate/client/db/src/utils.rs +++ b/substrate/client/db/src/utils.rs @@ -582,19 +582,14 @@ impl<'a, 'b> codec::Input for JoinInput<'a, 'b> { mod tests { use super::*; use codec::Input; - use sp_runtime::{ - generic::UncheckedExtrinsic, - testing::{Block as RawBlock, MockCallU64}, - }; - - pub type UncheckedXt = UncheckedExtrinsic; - type Block = RawBlock; + use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper}; + type Block = RawBlock>; #[cfg(feature = "rocksdb")] #[test] fn database_type_subdir_migration() { use std::path::PathBuf; - type Block = RawBlock; + type Block = RawBlock>; fn check_dir_for_db_type( db_type: DatabaseType, diff --git a/substrate/client/network-gossip/src/state_machine.rs b/substrate/client/network-gossip/src/state_machine.rs index f1c830341ea..069d7cdba16 100644 --- a/substrate/client/network-gossip/src/state_machine.rs +++ b/substrate/client/network-gossip/src/state_machine.rs @@ -550,8 +550,7 @@ mod tests { NotificationSenderError, NotificationSenderT as NotificationSender, ReputationChange, }; use sp_runtime::{ - generic::UncheckedExtrinsic, - testing::{Block as RawBlock, MockCallU64, H256}, + testing::{Block as RawBlock, ExtrinsicWrapper, H256}, traits::NumberFor, }; use std::{ @@ -560,7 +559,7 @@ mod tests { sync::{Arc, Mutex}, }; - type Block = RawBlock>; + type Block = RawBlock>; macro_rules! push_msg { ($consensus:expr, $topic:expr, $hash: expr, $m:expr) => { diff --git a/substrate/client/network/sync/src/blocks.rs b/substrate/client/network/sync/src/blocks.rs index a115ee94767..4988045a478 100644 --- a/substrate/client/network/sync/src/blocks.rs +++ b/substrate/client/network/sync/src/blocks.rs @@ -265,12 +265,9 @@ mod test { use libp2p::PeerId; use sc_network_common::sync::message; use sp_core::H256; - use sp_runtime::{ - generic::UncheckedExtrinsic, - testing::{Block as RawBlock, MockCallU64}, - }; + use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper}; - type Block = RawBlock>; + type Block = RawBlock>; fn is_empty(bc: &BlockCollection) -> bool { bc.blocks.is_empty() && bc.peer_requests.is_empty() diff --git a/substrate/client/transaction-pool/src/lib.rs b/substrate/client/transaction-pool/src/lib.rs index 730cfe36712..64b301e6bf3 100644 --- a/substrate/client/transaction-pool/src/lib.rs +++ b/substrate/client/transaction-pool/src/lib.rs @@ -659,13 +659,8 @@ where }) .unwrap_or_default() .into_iter() - // TODO [#2415]: This isn't really what we mean - we really want a - // `tx.is_transaction`, since bare transactions may be gossipped as in the case - // of Frontier txs or claims. This will be sorted once we dispense with the - // concept of bare transactions and make inherents the only possible type of - // extrinsics which are bare. At this point we can change this to - // `tx.is_transaction()`. - .filter(|tx| !tx.is_bare()); + .filter(|tx| tx.is_signed().unwrap_or(true)); + let mut resubmitted_to_report = 0; resubmit_transactions.extend(block_transactions.into_iter().filter(|tx| { diff --git a/substrate/frame/alliance/src/weights.rs b/substrate/frame/alliance/src/weights.rs index 0b2d1fca43c..b5bb5095720 100644 --- a/substrate/frame/alliance/src/weights.rs +++ b/substrate/frame/alliance/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_alliance` +//! Autogenerated weights for pallet_alliance //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/alliance/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/alliance/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_alliance`. +/// Weight functions needed for pallet_alliance. pub trait WeightInfo { fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight; fn vote(m: u32, ) -> Weight; @@ -73,209 +74,205 @@ pub trait WeightInfo { fn abdicate_fellow_status() -> Weight; } -/// Weights for `pallet_alliance` using the Substrate node and recommended hardware. +/// Weights for pallet_alliance using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Alliance::Members` (r:1 w:0) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::ProposalOf` (r:1 w:1) - /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:1) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::ProposalCount` (r:1 w:1) - /// Proof: `AllianceMotion::ProposalCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Voting` (r:0 w:1) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Alliance Members (r:1 w:0) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion ProposalOf (r:1 w:1) + /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: AllianceMotion Proposals (r:1 w:1) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion ProposalCount (r:1 w:1) + /// Proof Skipped: AllianceMotion ProposalCount (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Voting (r:0 w:1) + /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) /// The range of component `b` is `[1, 1024]`. /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `654 + m * (32 ±0) + p * (36 ±0)` + // Measured: `653 + m * (32 ±0) + p * (35 ±0)` // Estimated: `6676 + m * (32 ±0) + p * (36 ±0)` - // Minimum execution time: 30_801_000 picoseconds. - Weight::from_parts(32_942_969, 6676) - // Standard Error: 112 - .saturating_add(Weight::from_parts(614, 0).saturating_mul(b.into())) - // Standard Error: 1_177 - .saturating_add(Weight::from_parts(45_758, 0).saturating_mul(m.into())) - // Standard Error: 1_162 - .saturating_add(Weight::from_parts(136_600, 0).saturating_mul(p.into())) + // Minimum execution time: 36_908_000 picoseconds. + Weight::from_parts(39_040_304, 6676) + // Standard Error: 131 + .saturating_add(Weight::from_parts(781, 0).saturating_mul(b.into())) + // Standard Error: 1_375 + .saturating_add(Weight::from_parts(48_745, 0).saturating_mul(m.into())) + // Standard Error: 1_358 + .saturating_add(Weight::from_parts(148_047, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: `Alliance::Members` (r:1 w:0) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Voting` (r:1 w:1) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Alliance Members (r:1 w:0) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Voting (r:1 w:1) + /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1113 + m * (64 ±0)` + // Measured: `1042 + m * (64 ±0)` // Estimated: `6676 + m * (64 ±0)` - // Minimum execution time: 29_705_000 picoseconds. - Weight::from_parts(30_274_070, 6676) - // Standard Error: 884 - .saturating_add(Weight::from_parts(71_178, 0).saturating_mul(m.into())) + // Minimum execution time: 30_166_000 picoseconds. + Weight::from_parts(32_798_454, 6676) + // Standard Error: 1_432 + .saturating_add(Weight::from_parts(83_001, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } - /// Storage: `Alliance::Members` (r:1 w:0) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Voting` (r:1 w:1) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Members` (r:1 w:0) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:1) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::ProposalOf` (r:0 w:1) - /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Alliance Members (r:1 w:0) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Voting (r:1 w:1) + /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:1 w:0) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Proposals (r:1 w:1) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion ProposalOf (r:0 w:1) + /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `640 + m * (96 ±0) + p * (36 ±0)` + // Measured: `576 + m * (96 ±0) + p * (36 ±0)` // Estimated: `6676 + m * (97 ±0) + p * (36 ±0)` - // Minimum execution time: 38_596_000 picoseconds. - Weight::from_parts(36_445_536, 6676) - // Standard Error: 1_217 - .saturating_add(Weight::from_parts(69_976, 0).saturating_mul(m.into())) - // Standard Error: 1_187 - .saturating_add(Weight::from_parts(149_706, 0).saturating_mul(p.into())) + // Minimum execution time: 45_173_000 picoseconds. + Weight::from_parts(42_192_020, 6676) + // Standard Error: 1_456 + .saturating_add(Weight::from_parts(66_751, 0).saturating_mul(m.into())) + // Standard Error: 1_420 + .saturating_add(Weight::from_parts(158_161, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 97).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: `Alliance::Members` (r:1 w:0) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Voting` (r:1 w:1) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Members` (r:1 w:0) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::ProposalOf` (r:1 w:1) - /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:1) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Alliance Members (r:1 w:0) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Voting (r:1 w:1) + /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:1 w:0) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion ProposalOf (r:1 w:1) + /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: AllianceMotion Proposals (r:1 w:1) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `b` is `[1, 1024]`. /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1220 + m * (96 ±0) + p * (39 ±0)` + // Measured: `1087 + m * (96 ±0) + p * (39 ±0)` // Estimated: `6676 + m * (97 ±0) + p * (40 ±0)` - // Minimum execution time: 57_602_000 picoseconds. - Weight::from_parts(55_147_214, 6676) - // Standard Error: 127 - .saturating_add(Weight::from_parts(1_650, 0).saturating_mul(b.into())) - // Standard Error: 1_346 - .saturating_add(Weight::from_parts(56_056, 0).saturating_mul(m.into())) - // Standard Error: 1_312 - .saturating_add(Weight::from_parts(168_247, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(7_u64)) + // Minimum execution time: 58_290_000 picoseconds. + Weight::from_parts(54_924_919, 6676) + // Standard Error: 157 + .saturating_add(Weight::from_parts(464, 0).saturating_mul(b.into())) + // Standard Error: 1_665 + .saturating_add(Weight::from_parts(73_183, 0).saturating_mul(m.into())) + // Standard Error: 1_623 + .saturating_add(Weight::from_parts(168_318, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 97).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) } - /// Storage: `Alliance::Members` (r:1 w:0) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Voting` (r:1 w:1) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Members` (r:1 w:0) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Prime` (r:1 w:0) - /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:1) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::ProposalOf` (r:0 w:1) - /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Alliance Members (r:1 w:0) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Voting (r:1 w:1) + /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:1 w:0) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:1 w:0) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Proposals (r:1 w:1) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion ProposalOf (r:0 w:1) + /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `641 + m * (96 ±0) + p * (36 ±0)` + // Measured: `577 + m * (96 ±0) + p * (36 ±0)` // Estimated: `6676 + m * (97 ±0) + p * (36 ±0)` - // Minimum execution time: 40_755_000 picoseconds. - Weight::from_parts(36_953_935, 6676) - // Standard Error: 1_177 - .saturating_add(Weight::from_parts(73_240, 0).saturating_mul(m.into())) - // Standard Error: 1_162 - .saturating_add(Weight::from_parts(149_412, 0).saturating_mul(p.into())) + // Minimum execution time: 46_794_000 picoseconds. + Weight::from_parts(43_092_958, 6676) + // Standard Error: 1_273 + .saturating_add(Weight::from_parts(71_054, 0).saturating_mul(m.into())) + // Standard Error: 1_257 + .saturating_add(Weight::from_parts(152_820, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 97).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: `Alliance::Members` (r:1 w:0) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Voting` (r:1 w:1) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Members` (r:1 w:0) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Prime` (r:1 w:0) - /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:1) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::ProposalOf` (r:0 w:1) - /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Alliance Members (r:1 w:0) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Voting (r:1 w:1) + /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:1 w:0) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:1 w:0) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Proposals (r:1 w:1) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion ProposalOf (r:0 w:1) + /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `b` is `[1, 1024]`. /// The range of component `m` is `[5, 100]`. /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `694 + m * (96 ±0) + p * (35 ±0)` + // Measured: `684 + m * (96 ±0) + p * (35 ±0)` // Estimated: `6676 + m * (97 ±0) + p * (36 ±0)` - // Minimum execution time: 41_113_000 picoseconds. - Weight::from_parts(36_610_116, 6676) - // Standard Error: 92 - .saturating_add(Weight::from_parts(1_157, 0).saturating_mul(b.into())) - // Standard Error: 984 - .saturating_add(Weight::from_parts(63_050, 0).saturating_mul(m.into())) - // Standard Error: 949 - .saturating_add(Weight::from_parts(150_420, 0).saturating_mul(p.into())) + // Minimum execution time: 47_338_000 picoseconds. + Weight::from_parts(41_257_479, 6676) + // Standard Error: 119 + .saturating_add(Weight::from_parts(1_019, 0).saturating_mul(b.into())) + // Standard Error: 1_277 + .saturating_add(Weight::from_parts(78_453, 0).saturating_mul(m.into())) + // Standard Error: 1_231 + .saturating_add(Weight::from_parts(150_991, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 97).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: `Alliance::Members` (r:2 w:2) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Members` (r:1 w:1) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Alliance Members (r:2 w:2) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Members (r:1 w:1) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[1, 100]`. /// The range of component `z` is `[0, 100]`. fn init_members(m: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `250` + // Measured: `217` // Estimated: `12362` - // Minimum execution time: 30_249_000 picoseconds. - Weight::from_parts(21_364_868, 12362) - // Standard Error: 887 - .saturating_add(Weight::from_parts(131_624, 0).saturating_mul(m.into())) - // Standard Error: 877 - .saturating_add(Weight::from_parts(105_379, 0).saturating_mul(z.into())) + // Minimum execution time: 35_012_000 picoseconds. + Weight::from_parts(24_288_079, 12362) + // Standard Error: 878 + .saturating_add(Weight::from_parts(153_615, 0).saturating_mul(m.into())) + // Standard Error: 867 + .saturating_add(Weight::from_parts(129_307, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Alliance::Members` (r:2 w:2) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:0) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Alliance::DepositOf` (r:200 w:50) - /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:50 w:50) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Members` (r:0 w:1) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Prime` (r:0 w:1) - /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Alliance Members (r:2 w:2) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Proposals (r:1 w:0) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Alliance DepositOf (r:200 w:50) + /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: System Account (r:50 w:50) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: AllianceMotion Members (r:0 w:1) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:0 w:1) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `x` is `[1, 100]`. /// The range of component `y` is `[0, 100]`. /// The range of component `z` is `[0, 50]`. @@ -283,14 +280,14 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0 + x * (50 ±0) + y * (51 ±0) + z * (251 ±0)` // Estimated: `12362 + x * (2539 ±0) + y * (2539 ±0) + z * (2603 ±1)` - // Minimum execution time: 307_414_000 picoseconds. - Weight::from_parts(309_960_000, 12362) - // Standard Error: 29_278 - .saturating_add(Weight::from_parts(588_774, 0).saturating_mul(x.into())) - // Standard Error: 29_137 - .saturating_add(Weight::from_parts(563_245, 0).saturating_mul(y.into())) - // Standard Error: 58_221 - .saturating_add(Weight::from_parts(13_947_604, 0).saturating_mul(z.into())) + // Minimum execution time: 309_235_000 picoseconds. + Weight::from_parts(311_279_000, 12362) + // Standard Error: 26_510 + .saturating_add(Weight::from_parts(543_475, 0).saturating_mul(x.into())) + // Standard Error: 26_382 + .saturating_add(Weight::from_parts(603_169, 0).saturating_mul(y.into())) + // Standard Error: 52_716 + .saturating_add(Weight::from_parts(16_264_836, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(x.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(y.into()))) @@ -301,401 +298,397 @@ impl WeightInfo for SubstrateWeight { .saturating_add(Weight::from_parts(0, 2539).saturating_mul(y.into())) .saturating_add(Weight::from_parts(0, 2603).saturating_mul(z.into())) } - /// Storage: `Alliance::Rule` (r:0 w:1) - /// Proof: `Alliance::Rule` (`max_values`: Some(1), `max_size`: Some(87), added: 582, mode: `MaxEncodedLen`) + /// Storage: Alliance Rule (r:0 w:1) + /// Proof: Alliance Rule (max_values: Some(1), max_size: Some(87), added: 582, mode: MaxEncodedLen) fn set_rule() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_156_000 picoseconds. - Weight::from_parts(6_560_000, 0) + // Minimum execution time: 8_833_000 picoseconds. + Weight::from_parts(9_313_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Alliance::Announcements` (r:1 w:1) - /// Proof: `Alliance::Announcements` (`max_values`: Some(1), `max_size`: Some(8702), added: 9197, mode: `MaxEncodedLen`) + /// Storage: Alliance Announcements (r:1 w:1) + /// Proof: Alliance Announcements (max_values: Some(1), max_size: Some(8702), added: 9197, mode: MaxEncodedLen) fn announce() -> Weight { // Proof Size summary in bytes: - // Measured: `279` + // Measured: `246` // Estimated: `10187` - // Minimum execution time: 8_988_000 picoseconds. - Weight::from_parts(9_476_000, 10187) + // Minimum execution time: 12_231_000 picoseconds. + Weight::from_parts(12_761_000, 10187) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Alliance::Announcements` (r:1 w:1) - /// Proof: `Alliance::Announcements` (`max_values`: Some(1), `max_size`: Some(8702), added: 9197, mode: `MaxEncodedLen`) + /// Storage: Alliance Announcements (r:1 w:1) + /// Proof: Alliance Announcements (max_values: Some(1), max_size: Some(8702), added: 9197, mode: MaxEncodedLen) fn remove_announcement() -> Weight { // Proof Size summary in bytes: - // Measured: `352` + // Measured: `319` // Estimated: `10187` - // Minimum execution time: 10_126_000 picoseconds. - Weight::from_parts(10_755_000, 10187) + // Minimum execution time: 13_079_000 picoseconds. + Weight::from_parts(13_612_000, 10187) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Alliance::Members` (r:3 w:1) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `Alliance::UnscrupulousAccounts` (r:1 w:0) - /// Proof: `Alliance::UnscrupulousAccounts` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Alliance::DepositOf` (r:0 w:1) - /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: Alliance Members (r:3 w:1) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: Alliance UnscrupulousAccounts (r:1 w:0) + /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Alliance DepositOf (r:0 w:1) + /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) fn join_alliance() -> Weight { // Proof Size summary in bytes: - // Measured: `501` + // Measured: `468` // Estimated: `18048` - // Minimum execution time: 38_878_000 picoseconds. - Weight::from_parts(40_493_000, 18048) + // Minimum execution time: 44_574_000 picoseconds. + Weight::from_parts(46_157_000, 18048) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Alliance::Members` (r:3 w:1) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `Alliance::UnscrupulousAccounts` (r:1 w:0) - /// Proof: `Alliance::UnscrupulousAccounts` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) + /// Storage: Alliance Members (r:3 w:1) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: Alliance UnscrupulousAccounts (r:1 w:0) + /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) fn nominate_ally() -> Weight { // Proof Size summary in bytes: - // Measured: `400` + // Measured: `367` // Estimated: `18048` - // Minimum execution time: 23_265_000 picoseconds. - Weight::from_parts(24_703_000, 18048) + // Minimum execution time: 26_114_000 picoseconds. + Weight::from_parts(27_069_000, 18048) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Alliance::Members` (r:2 w:2) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:0) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Members` (r:0 w:1) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Prime` (r:0 w:1) - /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Alliance Members (r:2 w:2) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Proposals (r:1 w:0) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:0 w:1) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:0 w:1) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) fn elevate_ally() -> Weight { // Proof Size summary in bytes: - // Measured: `476` + // Measured: `443` // Estimated: `12362` - // Minimum execution time: 23_049_000 picoseconds. - Weight::from_parts(23_875_000, 12362) + // Minimum execution time: 25_882_000 picoseconds. + Weight::from_parts(26_923_000, 12362) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: `Alliance::Members` (r:4 w:2) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:0) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Members` (r:0 w:1) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Prime` (r:0 w:1) - /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Alliance::RetiringMembers` (r:0 w:1) - /// Proof: `Alliance::RetiringMembers` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: Alliance Members (r:4 w:2) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Proposals (r:1 w:0) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:0 w:1) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:0 w:1) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Alliance RetiringMembers (r:0 w:1) + /// Proof: Alliance RetiringMembers (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn give_retirement_notice() -> Weight { // Proof Size summary in bytes: - // Measured: `476` + // Measured: `443` // Estimated: `23734` - // Minimum execution time: 29_124_000 picoseconds. - Weight::from_parts(30_369_000, 23734) + // Minimum execution time: 34_112_000 picoseconds. + Weight::from_parts(35_499_000, 23734) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: `Alliance::RetiringMembers` (r:1 w:1) - /// Proof: `Alliance::RetiringMembers` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `Alliance::Members` (r:1 w:1) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `Alliance::DepositOf` (r:1 w:1) - /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Alliance RetiringMembers (r:1 w:1) + /// Proof: Alliance RetiringMembers (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: Alliance Members (r:1 w:1) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: Alliance DepositOf (r:1 w:1) + /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn retire() -> Weight { // Proof Size summary in bytes: - // Measured: `720` + // Measured: `687` // Estimated: `6676` - // Minimum execution time: 36_376_000 picoseconds. - Weight::from_parts(38_221_000, 6676) + // Minimum execution time: 41_239_000 picoseconds. + Weight::from_parts(42_764_000, 6676) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: `Alliance::Members` (r:3 w:1) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:0) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Alliance::DepositOf` (r:1 w:1) - /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Members` (r:0 w:1) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Prime` (r:0 w:1) - /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Alliance Members (r:3 w:1) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Proposals (r:1 w:0) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Alliance DepositOf (r:1 w:1) + /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: AllianceMotion Members (r:0 w:1) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:0 w:1) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) fn kick_member() -> Weight { // Proof Size summary in bytes: - // Measured: `740` + // Measured: `707` // Estimated: `18048` - // Minimum execution time: 56_560_000 picoseconds. - Weight::from_parts(58_621_000, 18048) + // Minimum execution time: 68_071_000 picoseconds. + Weight::from_parts(71_808_000, 18048) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: `Alliance::UnscrupulousAccounts` (r:1 w:1) - /// Proof: `Alliance::UnscrupulousAccounts` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) - /// Storage: `Alliance::UnscrupulousWebsites` (r:1 w:1) - /// Proof: `Alliance::UnscrupulousWebsites` (`max_values`: Some(1), `max_size`: Some(25702), added: 26197, mode: `MaxEncodedLen`) + /// Storage: Alliance UnscrupulousAccounts (r:1 w:1) + /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: Alliance UnscrupulousWebsites (r:1 w:1) + /// Proof: Alliance UnscrupulousWebsites (max_values: Some(1), max_size: Some(25702), added: 26197, mode: MaxEncodedLen) /// The range of component `n` is `[0, 100]`. /// The range of component `l` is `[0, 255]`. fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `279` + // Measured: `246` // Estimated: `27187` - // Minimum execution time: 5_191_000 picoseconds. - Weight::from_parts(5_410_000, 27187) - // Standard Error: 3_215 - .saturating_add(Weight::from_parts(1_018_569, 0).saturating_mul(n.into())) - // Standard Error: 1_259 - .saturating_add(Weight::from_parts(68_712, 0).saturating_mul(l.into())) + // Minimum execution time: 7_006_000 picoseconds. + Weight::from_parts(7_253_000, 27187) + // Standard Error: 3_403 + .saturating_add(Weight::from_parts(1_680_082, 0).saturating_mul(n.into())) + // Standard Error: 1_333 + .saturating_add(Weight::from_parts(72_943, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Alliance::UnscrupulousAccounts` (r:1 w:1) - /// Proof: `Alliance::UnscrupulousAccounts` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) - /// Storage: `Alliance::UnscrupulousWebsites` (r:1 w:1) - /// Proof: `Alliance::UnscrupulousWebsites` (`max_values`: Some(1), `max_size`: Some(25702), added: 26197, mode: `MaxEncodedLen`) + /// Storage: Alliance UnscrupulousAccounts (r:1 w:1) + /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: Alliance UnscrupulousWebsites (r:1 w:1) + /// Proof: Alliance UnscrupulousWebsites (max_values: Some(1), max_size: Some(25702), added: 26197, mode: MaxEncodedLen) /// The range of component `n` is `[0, 100]`. /// The range of component `l` is `[0, 255]`. fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + l * (100 ±0) + n * (289 ±0)` // Estimated: `27187` - // Minimum execution time: 5_361_000 picoseconds. - Weight::from_parts(5_494_000, 27187) - // Standard Error: 181_133 - .saturating_add(Weight::from_parts(16_322_982, 0).saturating_mul(n.into())) - // Standard Error: 70_940 - .saturating_add(Weight::from_parts(343_581, 0).saturating_mul(l.into())) + // Minimum execution time: 7_292_000 picoseconds. + Weight::from_parts(7_629_000, 27187) + // Standard Error: 176_225 + .saturating_add(Weight::from_parts(16_646_429, 0).saturating_mul(n.into())) + // Standard Error: 69_017 + .saturating_add(Weight::from_parts(310_978, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Alliance::Members` (r:3 w:2) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:0) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Members` (r:0 w:1) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Prime` (r:0 w:1) - /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Alliance Members (r:3 w:2) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Proposals (r:1 w:0) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:0 w:1) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:0 w:1) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) fn abdicate_fellow_status() -> Weight { // Proof Size summary in bytes: - // Measured: `476` + // Measured: `443` // Estimated: `18048` - // Minimum execution time: 28_856_000 picoseconds. - Weight::from_parts(29_875_000, 18048) + // Minimum execution time: 31_798_000 picoseconds. + Weight::from_parts(33_463_000, 18048) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Alliance::Members` (r:1 w:0) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::ProposalOf` (r:1 w:1) - /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:1) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::ProposalCount` (r:1 w:1) - /// Proof: `AllianceMotion::ProposalCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Voting` (r:0 w:1) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Alliance Members (r:1 w:0) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion ProposalOf (r:1 w:1) + /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: AllianceMotion Proposals (r:1 w:1) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion ProposalCount (r:1 w:1) + /// Proof Skipped: AllianceMotion ProposalCount (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Voting (r:0 w:1) + /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) /// The range of component `b` is `[1, 1024]`. /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `654 + m * (32 ±0) + p * (36 ±0)` + // Measured: `653 + m * (32 ±0) + p * (35 ±0)` // Estimated: `6676 + m * (32 ±0) + p * (36 ±0)` - // Minimum execution time: 30_801_000 picoseconds. - Weight::from_parts(32_942_969, 6676) - // Standard Error: 112 - .saturating_add(Weight::from_parts(614, 0).saturating_mul(b.into())) - // Standard Error: 1_177 - .saturating_add(Weight::from_parts(45_758, 0).saturating_mul(m.into())) - // Standard Error: 1_162 - .saturating_add(Weight::from_parts(136_600, 0).saturating_mul(p.into())) + // Minimum execution time: 36_908_000 picoseconds. + Weight::from_parts(39_040_304, 6676) + // Standard Error: 131 + .saturating_add(Weight::from_parts(781, 0).saturating_mul(b.into())) + // Standard Error: 1_375 + .saturating_add(Weight::from_parts(48_745, 0).saturating_mul(m.into())) + // Standard Error: 1_358 + .saturating_add(Weight::from_parts(148_047, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: `Alliance::Members` (r:1 w:0) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Voting` (r:1 w:1) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Alliance Members (r:1 w:0) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Voting (r:1 w:1) + /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1113 + m * (64 ±0)` + // Measured: `1042 + m * (64 ±0)` // Estimated: `6676 + m * (64 ±0)` - // Minimum execution time: 29_705_000 picoseconds. - Weight::from_parts(30_274_070, 6676) - // Standard Error: 884 - .saturating_add(Weight::from_parts(71_178, 0).saturating_mul(m.into())) + // Minimum execution time: 30_166_000 picoseconds. + Weight::from_parts(32_798_454, 6676) + // Standard Error: 1_432 + .saturating_add(Weight::from_parts(83_001, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } - /// Storage: `Alliance::Members` (r:1 w:0) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Voting` (r:1 w:1) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Members` (r:1 w:0) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:1) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::ProposalOf` (r:0 w:1) - /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Alliance Members (r:1 w:0) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Voting (r:1 w:1) + /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:1 w:0) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Proposals (r:1 w:1) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion ProposalOf (r:0 w:1) + /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `640 + m * (96 ±0) + p * (36 ±0)` + // Measured: `576 + m * (96 ±0) + p * (36 ±0)` // Estimated: `6676 + m * (97 ±0) + p * (36 ±0)` - // Minimum execution time: 38_596_000 picoseconds. - Weight::from_parts(36_445_536, 6676) - // Standard Error: 1_217 - .saturating_add(Weight::from_parts(69_976, 0).saturating_mul(m.into())) - // Standard Error: 1_187 - .saturating_add(Weight::from_parts(149_706, 0).saturating_mul(p.into())) + // Minimum execution time: 45_173_000 picoseconds. + Weight::from_parts(42_192_020, 6676) + // Standard Error: 1_456 + .saturating_add(Weight::from_parts(66_751, 0).saturating_mul(m.into())) + // Standard Error: 1_420 + .saturating_add(Weight::from_parts(158_161, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 97).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: `Alliance::Members` (r:1 w:0) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Voting` (r:1 w:1) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Members` (r:1 w:0) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::ProposalOf` (r:1 w:1) - /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:1) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Alliance Members (r:1 w:0) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Voting (r:1 w:1) + /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:1 w:0) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion ProposalOf (r:1 w:1) + /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: AllianceMotion Proposals (r:1 w:1) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `b` is `[1, 1024]`. /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1220 + m * (96 ±0) + p * (39 ±0)` + // Measured: `1087 + m * (96 ±0) + p * (39 ±0)` // Estimated: `6676 + m * (97 ±0) + p * (40 ±0)` - // Minimum execution time: 57_602_000 picoseconds. - Weight::from_parts(55_147_214, 6676) - // Standard Error: 127 - .saturating_add(Weight::from_parts(1_650, 0).saturating_mul(b.into())) - // Standard Error: 1_346 - .saturating_add(Weight::from_parts(56_056, 0).saturating_mul(m.into())) - // Standard Error: 1_312 - .saturating_add(Weight::from_parts(168_247, 0).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(7_u64)) + // Minimum execution time: 58_290_000 picoseconds. + Weight::from_parts(54_924_919, 6676) + // Standard Error: 157 + .saturating_add(Weight::from_parts(464, 0).saturating_mul(b.into())) + // Standard Error: 1_665 + .saturating_add(Weight::from_parts(73_183, 0).saturating_mul(m.into())) + // Standard Error: 1_623 + .saturating_add(Weight::from_parts(168_318, 0).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 97).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) } - /// Storage: `Alliance::Members` (r:1 w:0) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Voting` (r:1 w:1) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Members` (r:1 w:0) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Prime` (r:1 w:0) - /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:1) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::ProposalOf` (r:0 w:1) - /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Alliance Members (r:1 w:0) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Voting (r:1 w:1) + /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:1 w:0) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:1 w:0) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Proposals (r:1 w:1) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion ProposalOf (r:0 w:1) + /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `641 + m * (96 ±0) + p * (36 ±0)` + // Measured: `577 + m * (96 ±0) + p * (36 ±0)` // Estimated: `6676 + m * (97 ±0) + p * (36 ±0)` - // Minimum execution time: 40_755_000 picoseconds. - Weight::from_parts(36_953_935, 6676) - // Standard Error: 1_177 - .saturating_add(Weight::from_parts(73_240, 0).saturating_mul(m.into())) - // Standard Error: 1_162 - .saturating_add(Weight::from_parts(149_412, 0).saturating_mul(p.into())) + // Minimum execution time: 46_794_000 picoseconds. + Weight::from_parts(43_092_958, 6676) + // Standard Error: 1_273 + .saturating_add(Weight::from_parts(71_054, 0).saturating_mul(m.into())) + // Standard Error: 1_257 + .saturating_add(Weight::from_parts(152_820, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 97).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: `Alliance::Members` (r:1 w:0) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Voting` (r:1 w:1) - /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Members` (r:1 w:0) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Prime` (r:1 w:0) - /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:1) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::ProposalOf` (r:0 w:1) - /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Alliance Members (r:1 w:0) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Voting (r:1 w:1) + /// Proof Skipped: AllianceMotion Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:1 w:0) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:1 w:0) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Proposals (r:1 w:1) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion ProposalOf (r:0 w:1) + /// Proof Skipped: AllianceMotion ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `b` is `[1, 1024]`. /// The range of component `m` is `[5, 100]`. /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `694 + m * (96 ±0) + p * (35 ±0)` + // Measured: `684 + m * (96 ±0) + p * (35 ±0)` // Estimated: `6676 + m * (97 ±0) + p * (36 ±0)` - // Minimum execution time: 41_113_000 picoseconds. - Weight::from_parts(36_610_116, 6676) - // Standard Error: 92 - .saturating_add(Weight::from_parts(1_157, 0).saturating_mul(b.into())) - // Standard Error: 984 - .saturating_add(Weight::from_parts(63_050, 0).saturating_mul(m.into())) - // Standard Error: 949 - .saturating_add(Weight::from_parts(150_420, 0).saturating_mul(p.into())) + // Minimum execution time: 47_338_000 picoseconds. + Weight::from_parts(41_257_479, 6676) + // Standard Error: 119 + .saturating_add(Weight::from_parts(1_019, 0).saturating_mul(b.into())) + // Standard Error: 1_277 + .saturating_add(Weight::from_parts(78_453, 0).saturating_mul(m.into())) + // Standard Error: 1_231 + .saturating_add(Weight::from_parts(150_991, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 97).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: `Alliance::Members` (r:2 w:2) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Members` (r:1 w:1) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Alliance Members (r:2 w:2) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Members (r:1 w:1) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[1, 100]`. /// The range of component `z` is `[0, 100]`. fn init_members(m: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `250` + // Measured: `217` // Estimated: `12362` - // Minimum execution time: 30_249_000 picoseconds. - Weight::from_parts(21_364_868, 12362) - // Standard Error: 887 - .saturating_add(Weight::from_parts(131_624, 0).saturating_mul(m.into())) - // Standard Error: 877 - .saturating_add(Weight::from_parts(105_379, 0).saturating_mul(z.into())) + // Minimum execution time: 35_012_000 picoseconds. + Weight::from_parts(24_288_079, 12362) + // Standard Error: 878 + .saturating_add(Weight::from_parts(153_615, 0).saturating_mul(m.into())) + // Standard Error: 867 + .saturating_add(Weight::from_parts(129_307, 0).saturating_mul(z.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Alliance::Members` (r:2 w:2) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:0) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Alliance::DepositOf` (r:200 w:50) - /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:50 w:50) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Members` (r:0 w:1) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Prime` (r:0 w:1) - /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Alliance Members (r:2 w:2) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Proposals (r:1 w:0) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Alliance DepositOf (r:200 w:50) + /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: System Account (r:50 w:50) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: AllianceMotion Members (r:0 w:1) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:0 w:1) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `x` is `[1, 100]`. /// The range of component `y` is `[0, 100]`. /// The range of component `z` is `[0, 50]`. @@ -703,14 +696,14 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0 + x * (50 ±0) + y * (51 ±0) + z * (251 ±0)` // Estimated: `12362 + x * (2539 ±0) + y * (2539 ±0) + z * (2603 ±1)` - // Minimum execution time: 307_414_000 picoseconds. - Weight::from_parts(309_960_000, 12362) - // Standard Error: 29_278 - .saturating_add(Weight::from_parts(588_774, 0).saturating_mul(x.into())) - // Standard Error: 29_137 - .saturating_add(Weight::from_parts(563_245, 0).saturating_mul(y.into())) - // Standard Error: 58_221 - .saturating_add(Weight::from_parts(13_947_604, 0).saturating_mul(z.into())) + // Minimum execution time: 309_235_000 picoseconds. + Weight::from_parts(311_279_000, 12362) + // Standard Error: 26_510 + .saturating_add(Weight::from_parts(543_475, 0).saturating_mul(x.into())) + // Standard Error: 26_382 + .saturating_add(Weight::from_parts(603_169, 0).saturating_mul(y.into())) + // Standard Error: 52_716 + .saturating_add(Weight::from_parts(16_264_836, 0).saturating_mul(z.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(x.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(y.into()))) @@ -721,194 +714,194 @@ impl WeightInfo for () { .saturating_add(Weight::from_parts(0, 2539).saturating_mul(y.into())) .saturating_add(Weight::from_parts(0, 2603).saturating_mul(z.into())) } - /// Storage: `Alliance::Rule` (r:0 w:1) - /// Proof: `Alliance::Rule` (`max_values`: Some(1), `max_size`: Some(87), added: 582, mode: `MaxEncodedLen`) + /// Storage: Alliance Rule (r:0 w:1) + /// Proof: Alliance Rule (max_values: Some(1), max_size: Some(87), added: 582, mode: MaxEncodedLen) fn set_rule() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_156_000 picoseconds. - Weight::from_parts(6_560_000, 0) + // Minimum execution time: 8_833_000 picoseconds. + Weight::from_parts(9_313_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Alliance::Announcements` (r:1 w:1) - /// Proof: `Alliance::Announcements` (`max_values`: Some(1), `max_size`: Some(8702), added: 9197, mode: `MaxEncodedLen`) + /// Storage: Alliance Announcements (r:1 w:1) + /// Proof: Alliance Announcements (max_values: Some(1), max_size: Some(8702), added: 9197, mode: MaxEncodedLen) fn announce() -> Weight { // Proof Size summary in bytes: - // Measured: `279` + // Measured: `246` // Estimated: `10187` - // Minimum execution time: 8_988_000 picoseconds. - Weight::from_parts(9_476_000, 10187) + // Minimum execution time: 12_231_000 picoseconds. + Weight::from_parts(12_761_000, 10187) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Alliance::Announcements` (r:1 w:1) - /// Proof: `Alliance::Announcements` (`max_values`: Some(1), `max_size`: Some(8702), added: 9197, mode: `MaxEncodedLen`) + /// Storage: Alliance Announcements (r:1 w:1) + /// Proof: Alliance Announcements (max_values: Some(1), max_size: Some(8702), added: 9197, mode: MaxEncodedLen) fn remove_announcement() -> Weight { // Proof Size summary in bytes: - // Measured: `352` + // Measured: `319` // Estimated: `10187` - // Minimum execution time: 10_126_000 picoseconds. - Weight::from_parts(10_755_000, 10187) + // Minimum execution time: 13_079_000 picoseconds. + Weight::from_parts(13_612_000, 10187) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Alliance::Members` (r:3 w:1) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `Alliance::UnscrupulousAccounts` (r:1 w:0) - /// Proof: `Alliance::UnscrupulousAccounts` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Alliance::DepositOf` (r:0 w:1) - /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) + /// Storage: Alliance Members (r:3 w:1) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: Alliance UnscrupulousAccounts (r:1 w:0) + /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Alliance DepositOf (r:0 w:1) + /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) fn join_alliance() -> Weight { // Proof Size summary in bytes: - // Measured: `501` + // Measured: `468` // Estimated: `18048` - // Minimum execution time: 38_878_000 picoseconds. - Weight::from_parts(40_493_000, 18048) + // Minimum execution time: 44_574_000 picoseconds. + Weight::from_parts(46_157_000, 18048) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Alliance::Members` (r:3 w:1) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `Alliance::UnscrupulousAccounts` (r:1 w:0) - /// Proof: `Alliance::UnscrupulousAccounts` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) + /// Storage: Alliance Members (r:3 w:1) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: Alliance UnscrupulousAccounts (r:1 w:0) + /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) fn nominate_ally() -> Weight { // Proof Size summary in bytes: - // Measured: `400` + // Measured: `367` // Estimated: `18048` - // Minimum execution time: 23_265_000 picoseconds. - Weight::from_parts(24_703_000, 18048) + // Minimum execution time: 26_114_000 picoseconds. + Weight::from_parts(27_069_000, 18048) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Alliance::Members` (r:2 w:2) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:0) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Members` (r:0 w:1) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Prime` (r:0 w:1) - /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Alliance Members (r:2 w:2) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Proposals (r:1 w:0) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:0 w:1) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:0 w:1) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) fn elevate_ally() -> Weight { // Proof Size summary in bytes: - // Measured: `476` + // Measured: `443` // Estimated: `12362` - // Minimum execution time: 23_049_000 picoseconds. - Weight::from_parts(23_875_000, 12362) + // Minimum execution time: 25_882_000 picoseconds. + Weight::from_parts(26_923_000, 12362) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: `Alliance::Members` (r:4 w:2) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:0) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Members` (r:0 w:1) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Prime` (r:0 w:1) - /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Alliance::RetiringMembers` (r:0 w:1) - /// Proof: `Alliance::RetiringMembers` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: Alliance Members (r:4 w:2) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Proposals (r:1 w:0) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:0 w:1) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:0 w:1) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Alliance RetiringMembers (r:0 w:1) + /// Proof: Alliance RetiringMembers (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn give_retirement_notice() -> Weight { // Proof Size summary in bytes: - // Measured: `476` + // Measured: `443` // Estimated: `23734` - // Minimum execution time: 29_124_000 picoseconds. - Weight::from_parts(30_369_000, 23734) + // Minimum execution time: 34_112_000 picoseconds. + Weight::from_parts(35_499_000, 23734) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: `Alliance::RetiringMembers` (r:1 w:1) - /// Proof: `Alliance::RetiringMembers` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `Alliance::Members` (r:1 w:1) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `Alliance::DepositOf` (r:1 w:1) - /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Alliance RetiringMembers (r:1 w:1) + /// Proof: Alliance RetiringMembers (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: Alliance Members (r:1 w:1) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: Alliance DepositOf (r:1 w:1) + /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn retire() -> Weight { // Proof Size summary in bytes: - // Measured: `720` + // Measured: `687` // Estimated: `6676` - // Minimum execution time: 36_376_000 picoseconds. - Weight::from_parts(38_221_000, 6676) + // Minimum execution time: 41_239_000 picoseconds. + Weight::from_parts(42_764_000, 6676) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: `Alliance::Members` (r:3 w:1) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:0) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Alliance::DepositOf` (r:1 w:1) - /// Proof: `Alliance::DepositOf` (`max_values`: None, `max_size`: Some(64), added: 2539, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Members` (r:0 w:1) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Prime` (r:0 w:1) - /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Alliance Members (r:3 w:1) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Proposals (r:1 w:0) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Alliance DepositOf (r:1 w:1) + /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: AllianceMotion Members (r:0 w:1) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:0 w:1) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) fn kick_member() -> Weight { // Proof Size summary in bytes: - // Measured: `740` + // Measured: `707` // Estimated: `18048` - // Minimum execution time: 56_560_000 picoseconds. - Weight::from_parts(58_621_000, 18048) + // Minimum execution time: 68_071_000 picoseconds. + Weight::from_parts(71_808_000, 18048) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: `Alliance::UnscrupulousAccounts` (r:1 w:1) - /// Proof: `Alliance::UnscrupulousAccounts` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) - /// Storage: `Alliance::UnscrupulousWebsites` (r:1 w:1) - /// Proof: `Alliance::UnscrupulousWebsites` (`max_values`: Some(1), `max_size`: Some(25702), added: 26197, mode: `MaxEncodedLen`) + /// Storage: Alliance UnscrupulousAccounts (r:1 w:1) + /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: Alliance UnscrupulousWebsites (r:1 w:1) + /// Proof: Alliance UnscrupulousWebsites (max_values: Some(1), max_size: Some(25702), added: 26197, mode: MaxEncodedLen) /// The range of component `n` is `[0, 100]`. /// The range of component `l` is `[0, 255]`. fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `279` + // Measured: `246` // Estimated: `27187` - // Minimum execution time: 5_191_000 picoseconds. - Weight::from_parts(5_410_000, 27187) - // Standard Error: 3_215 - .saturating_add(Weight::from_parts(1_018_569, 0).saturating_mul(n.into())) - // Standard Error: 1_259 - .saturating_add(Weight::from_parts(68_712, 0).saturating_mul(l.into())) + // Minimum execution time: 7_006_000 picoseconds. + Weight::from_parts(7_253_000, 27187) + // Standard Error: 3_403 + .saturating_add(Weight::from_parts(1_680_082, 0).saturating_mul(n.into())) + // Standard Error: 1_333 + .saturating_add(Weight::from_parts(72_943, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Alliance::UnscrupulousAccounts` (r:1 w:1) - /// Proof: `Alliance::UnscrupulousAccounts` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) - /// Storage: `Alliance::UnscrupulousWebsites` (r:1 w:1) - /// Proof: `Alliance::UnscrupulousWebsites` (`max_values`: Some(1), `max_size`: Some(25702), added: 26197, mode: `MaxEncodedLen`) + /// Storage: Alliance UnscrupulousAccounts (r:1 w:1) + /// Proof: Alliance UnscrupulousAccounts (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: Alliance UnscrupulousWebsites (r:1 w:1) + /// Proof: Alliance UnscrupulousWebsites (max_values: Some(1), max_size: Some(25702), added: 26197, mode: MaxEncodedLen) /// The range of component `n` is `[0, 100]`. /// The range of component `l` is `[0, 255]`. fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + l * (100 ±0) + n * (289 ±0)` // Estimated: `27187` - // Minimum execution time: 5_361_000 picoseconds. - Weight::from_parts(5_494_000, 27187) - // Standard Error: 181_133 - .saturating_add(Weight::from_parts(16_322_982, 0).saturating_mul(n.into())) - // Standard Error: 70_940 - .saturating_add(Weight::from_parts(343_581, 0).saturating_mul(l.into())) + // Minimum execution time: 7_292_000 picoseconds. + Weight::from_parts(7_629_000, 27187) + // Standard Error: 176_225 + .saturating_add(Weight::from_parts(16_646_429, 0).saturating_mul(n.into())) + // Standard Error: 69_017 + .saturating_add(Weight::from_parts(310_978, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Alliance::Members` (r:3 w:2) - /// Proof: `Alliance::Members` (`max_values`: None, `max_size`: Some(3211), added: 5686, mode: `MaxEncodedLen`) - /// Storage: `AllianceMotion::Proposals` (r:1 w:0) - /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Members` (r:0 w:1) - /// Proof: `AllianceMotion::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `AllianceMotion::Prime` (r:0 w:1) - /// Proof: `AllianceMotion::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Alliance Members (r:3 w:2) + /// Proof: Alliance Members (max_values: None, max_size: Some(3211), added: 5686, mode: MaxEncodedLen) + /// Storage: AllianceMotion Proposals (r:1 w:0) + /// Proof Skipped: AllianceMotion Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Members (r:0 w:1) + /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: AllianceMotion Prime (r:0 w:1) + /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) fn abdicate_fellow_status() -> Weight { // Proof Size summary in bytes: - // Measured: `476` + // Measured: `443` // Estimated: `18048` - // Minimum execution time: 28_856_000 picoseconds. - Weight::from_parts(29_875_000, 18048) + // Minimum execution time: 31_798_000 picoseconds. + Weight::from_parts(33_463_000, 18048) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } diff --git a/substrate/frame/asset-conversion/src/weights.rs b/substrate/frame/asset-conversion/src/weights.rs index 4eaa115c694..a0e687f7a41 100644 --- a/substrate/frame/asset-conversion/src/weights.rs +++ b/substrate/frame/asset-conversion/src/weights.rs @@ -17,28 +17,24 @@ //! Autogenerated weights for `pallet_asset_conversion` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-10-30, STEPS: `5`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `cob`, CPU: `` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/production/substrate-node +// ./target/debug/substrate-node // benchmark // pallet // --chain=dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_asset_conversion -// --no-storage-info -// --no-median-slopes -// --no-min-squares +// --steps=5 +// --repeat=2 +// --pallet=pallet-asset-conversion // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 // --output=./substrate/frame/asset-conversion/src/weights.rs -// --header=./substrate/HEADER-APACHE2 // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -63,9 +59,11 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// Storage: `AssetConversion::Pools` (r:1 w:1) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) + /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:2 w:0) + /// Storage: `Assets::Account` (r:2 w:2) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:2 w:2) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) /// Storage: `AssetConversion::NextPoolAssetId` (r:1 w:1) /// Proof: `AssetConversion::NextPoolAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -75,12 +73,12 @@ impl WeightInfo for SubstrateWeight { /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) fn create_pool() -> Weight { // Proof Size summary in bytes: - // Measured: `910` + // Measured: `1081` // Estimated: `6360` - // Minimum execution time: 82_941_000 picoseconds. - Weight::from_parts(85_526_000, 6360) - .saturating_add(T::DbWeight::get().reads(7_u64)) - .saturating_add(T::DbWeight::get().writes(5_u64)) + // Minimum execution time: 1_576_000_000 picoseconds. + Weight::from_parts(1_668_000_000, 6360) + .saturating_add(T::DbWeight::get().reads(10_u64)) + .saturating_add(T::DbWeight::get().writes(10_u64)) } /// Storage: `AssetConversion::Pools` (r:1 w:0) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) @@ -88,20 +86,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) /// Storage: `Assets::Account` (r:4 w:4) /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `PoolAssets::Asset` (r:1 w:1) /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) /// Storage: `PoolAssets::Account` (r:2 w:2) /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) fn add_liquidity() -> Weight { // Proof Size summary in bytes: - // Measured: `1507` + // Measured: `1761` // Estimated: `11426` - // Minimum execution time: 138_424_000 picoseconds. - Weight::from_parts(142_083_000, 11426) - .saturating_add(T::DbWeight::get().reads(11_u64)) - .saturating_add(T::DbWeight::get().writes(10_u64)) + // Minimum execution time: 1_636_000_000 picoseconds. + Weight::from_parts(1_894_000_000, 11426) + .saturating_add(T::DbWeight::get().reads(10_u64)) + .saturating_add(T::DbWeight::get().writes(9_u64)) } /// Storage: `AssetConversion::Pools` (r:1 w:0) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) @@ -115,10 +111,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) fn remove_liquidity() -> Weight { // Proof Size summary in bytes: - // Measured: `1650` + // Measured: `1750` // Estimated: `11426` - // Minimum execution time: 122_132_000 picoseconds. - Weight::from_parts(125_143_000, 11426) + // Minimum execution time: 1_507_000_000 picoseconds. + Weight::from_parts(1_524_000_000, 11426) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } @@ -129,12 +125,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[2, 4]`. fn swap_exact_tokens_for_tokens(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `89 + n * (419 ±0)` + // Measured: `0 + n * (522 ±0)` // Estimated: `990 + n * (5218 ±0)` - // Minimum execution time: 77_183_000 picoseconds. - Weight::from_parts(78_581_000, 990) - // Standard Error: 306_918 - .saturating_add(Weight::from_parts(10_581_054, 0).saturating_mul(n.into())) + // Minimum execution time: 937_000_000 picoseconds. + Weight::from_parts(941_000_000, 990) + // Standard Error: 40_863_477 + .saturating_add(Weight::from_parts(205_862_068, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 5218).saturating_mul(n.into())) @@ -146,12 +142,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[2, 4]`. fn swap_tokens_for_exact_tokens(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `89 + n * (419 ±0)` + // Measured: `0 + n * (522 ±0)` // Estimated: `990 + n * (5218 ±0)` - // Minimum execution time: 76_962_000 picoseconds. - Weight::from_parts(78_315_000, 990) - // Standard Error: 311_204 - .saturating_add(Weight::from_parts(10_702_400, 0).saturating_mul(n.into())) + // Minimum execution time: 935_000_000 picoseconds. + Weight::from_parts(947_000_000, 990) + // Standard Error: 46_904_620 + .saturating_add(Weight::from_parts(218_275_862, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 5218).saturating_mul(n.into())) @@ -162,9 +158,11 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { /// Storage: `AssetConversion::Pools` (r:1 w:1) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) + /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:2 w:0) + /// Storage: `Assets::Account` (r:2 w:2) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:2 w:2) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) /// Storage: `AssetConversion::NextPoolAssetId` (r:1 w:1) /// Proof: `AssetConversion::NextPoolAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -174,12 +172,12 @@ impl WeightInfo for () { /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) fn create_pool() -> Weight { // Proof Size summary in bytes: - // Measured: `910` + // Measured: `1081` // Estimated: `6360` - // Minimum execution time: 82_941_000 picoseconds. - Weight::from_parts(85_526_000, 6360) - .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().writes(5_u64)) + // Minimum execution time: 1_576_000_000 picoseconds. + Weight::from_parts(1_668_000_000, 6360) + .saturating_add(RocksDbWeight::get().reads(10_u64)) + .saturating_add(RocksDbWeight::get().writes(10_u64)) } /// Storage: `AssetConversion::Pools` (r:1 w:0) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) @@ -187,20 +185,18 @@ impl WeightInfo for () { /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) /// Storage: `Assets::Account` (r:4 w:4) /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `PoolAssets::Asset` (r:1 w:1) /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) /// Storage: `PoolAssets::Account` (r:2 w:2) /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) fn add_liquidity() -> Weight { // Proof Size summary in bytes: - // Measured: `1507` + // Measured: `1761` // Estimated: `11426` - // Minimum execution time: 138_424_000 picoseconds. - Weight::from_parts(142_083_000, 11426) - .saturating_add(RocksDbWeight::get().reads(11_u64)) - .saturating_add(RocksDbWeight::get().writes(10_u64)) + // Minimum execution time: 1_636_000_000 picoseconds. + Weight::from_parts(1_894_000_000, 11426) + .saturating_add(RocksDbWeight::get().reads(10_u64)) + .saturating_add(RocksDbWeight::get().writes(9_u64)) } /// Storage: `AssetConversion::Pools` (r:1 w:0) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) @@ -214,10 +210,10 @@ impl WeightInfo for () { /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) fn remove_liquidity() -> Weight { // Proof Size summary in bytes: - // Measured: `1650` + // Measured: `1750` // Estimated: `11426` - // Minimum execution time: 122_132_000 picoseconds. - Weight::from_parts(125_143_000, 11426) + // Minimum execution time: 1_507_000_000 picoseconds. + Weight::from_parts(1_524_000_000, 11426) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } @@ -228,12 +224,12 @@ impl WeightInfo for () { /// The range of component `n` is `[2, 4]`. fn swap_exact_tokens_for_tokens(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `89 + n * (419 ±0)` + // Measured: `0 + n * (522 ±0)` // Estimated: `990 + n * (5218 ±0)` - // Minimum execution time: 77_183_000 picoseconds. - Weight::from_parts(78_581_000, 990) - // Standard Error: 306_918 - .saturating_add(Weight::from_parts(10_581_054, 0).saturating_mul(n.into())) + // Minimum execution time: 937_000_000 picoseconds. + Weight::from_parts(941_000_000, 990) + // Standard Error: 40_863_477 + .saturating_add(Weight::from_parts(205_862_068, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 5218).saturating_mul(n.into())) @@ -245,12 +241,12 @@ impl WeightInfo for () { /// The range of component `n` is `[2, 4]`. fn swap_tokens_for_exact_tokens(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `89 + n * (419 ±0)` + // Measured: `0 + n * (522 ±0)` // Estimated: `990 + n * (5218 ±0)` - // Minimum execution time: 76_962_000 picoseconds. - Weight::from_parts(78_315_000, 990) - // Standard Error: 311_204 - .saturating_add(Weight::from_parts(10_702_400, 0).saturating_mul(n.into())) + // Minimum execution time: 935_000_000 picoseconds. + Weight::from_parts(947_000_000, 990) + // Standard Error: 46_904_620 + .saturating_add(Weight::from_parts(218_275_862, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 5218).saturating_mul(n.into())) diff --git a/substrate/frame/asset-rate/src/weights.rs b/substrate/frame/asset-rate/src/weights.rs index b8723ee3bed..582e20e56d7 100644 --- a/substrate/frame/asset-rate/src/weights.rs +++ b/substrate/frame/asset-rate/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_asset_rate` +//! Autogenerated weights for pallet_asset_rate //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/asset-rate/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/asset-rate/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,83 +50,83 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_asset_rate`. +/// Weight functions needed for pallet_asset_rate. pub trait WeightInfo { fn create() -> Weight; fn update() -> Weight; fn remove() -> Weight; } -/// Weights for `pallet_asset_rate` using the Substrate node and recommended hardware. +/// Weights for pallet_asset_rate using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) - /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + /// Storage: AssetRate ConversionRateToNative (r:1 w:1) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3501` - // Minimum execution time: 9_447_000 picoseconds. - Weight::from_parts(10_078_000, 3501) + // Minimum execution time: 11_700_000 picoseconds. + Weight::from_parts(12_158_000, 3501) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) - /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + /// Storage: AssetRate ConversionRateToNative (r:1 w:1) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) fn update() -> Weight { // Proof Size summary in bytes: // Measured: `137` // Estimated: `3501` - // Minimum execution time: 9_844_000 picoseconds. - Weight::from_parts(10_240_000, 3501) + // Minimum execution time: 12_119_000 picoseconds. + Weight::from_parts(12_548_000, 3501) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) - /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + /// Storage: AssetRate ConversionRateToNative (r:1 w:1) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) fn remove() -> Weight { // Proof Size summary in bytes: // Measured: `137` // Estimated: `3501` - // Minimum execution time: 10_411_000 picoseconds. - Weight::from_parts(10_686_000, 3501) + // Minimum execution time: 12_541_000 picoseconds. + Weight::from_parts(12_956_000, 3501) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) - /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + /// Storage: AssetRate ConversionRateToNative (r:1 w:1) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3501` - // Minimum execution time: 9_447_000 picoseconds. - Weight::from_parts(10_078_000, 3501) + // Minimum execution time: 11_700_000 picoseconds. + Weight::from_parts(12_158_000, 3501) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) - /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + /// Storage: AssetRate ConversionRateToNative (r:1 w:1) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) fn update() -> Weight { // Proof Size summary in bytes: // Measured: `137` // Estimated: `3501` - // Minimum execution time: 9_844_000 picoseconds. - Weight::from_parts(10_240_000, 3501) + // Minimum execution time: 12_119_000 picoseconds. + Weight::from_parts(12_548_000, 3501) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) - /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + /// Storage: AssetRate ConversionRateToNative (r:1 w:1) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) fn remove() -> Weight { // Proof Size summary in bytes: // Measured: `137` // Estimated: `3501` - // Minimum execution time: 10_411_000 picoseconds. - Weight::from_parts(10_686_000, 3501) + // Minimum execution time: 12_541_000 picoseconds. + Weight::from_parts(12_956_000, 3501) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/assets/src/weights.rs b/substrate/frame/assets/src/weights.rs index f5199105fe3..f20f7e317cf 100644 --- a/substrate/frame/assets/src/weights.rs +++ b/substrate/frame/assets/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_assets` +//! Autogenerated weights for pallet_assets //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/assets/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/assets/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_assets`. +/// Weight functions needed for pallet_assets. pub trait WeightInfo { fn create() -> Weight; fn force_create() -> Weight; @@ -85,890 +86,882 @@ pub trait WeightInfo { fn block() -> Weight; } -/// Weights for `pallet_assets` using the Substrate node and recommended hardware. +/// Weights for pallet_assets using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: // Measured: `293` // Estimated: `3675` - // Minimum execution time: 24_690_000 picoseconds. - Weight::from_parts(25_878_000, 3675) + // Minimum execution time: 31_340_000 picoseconds. + Weight::from_parts(31_977_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `153` // Estimated: `3675` - // Minimum execution time: 10_997_000 picoseconds. - Weight::from_parts(11_369_000, 3675) + // Minimum execution time: 13_342_000 picoseconds. + Weight::from_parts(13_782_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn start_destroy() -> Weight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 11_536_000 picoseconds. - Weight::from_parts(12_309_000, 3675) + // Minimum execution time: 14_437_000 picoseconds. + Weight::from_parts(14_833_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1001 w:1000) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1000 w:1000) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1001 w:1000) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: System Account (r:1000 w:1000) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `c` is `[0, 1000]`. fn destroy_accounts(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + c * (208 ±0)` // Estimated: `3675 + c * (2609 ±0)` - // Minimum execution time: 15_798_000 picoseconds. - Weight::from_parts(16_005_000, 3675) - // Standard Error: 7_818 - .saturating_add(Weight::from_parts(12_826_278, 0).saturating_mul(c.into())) + // Minimum execution time: 18_728_000 picoseconds. + Weight::from_parts(18_982_000, 3675) + // Standard Error: 11_708 + .saturating_add(Weight::from_parts(14_363_570, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(c.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(c.into()))) .saturating_add(Weight::from_parts(0, 2609).saturating_mul(c.into())) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Approvals` (r:1001 w:1000) - /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Approvals (r:1001 w:1000) + /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) /// The range of component `a` is `[0, 1000]`. fn destroy_approvals(a: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `522 + a * (86 ±0)` // Estimated: `3675 + a * (2623 ±0)` - // Minimum execution time: 16_334_000 picoseconds. - Weight::from_parts(16_616_000, 3675) - // Standard Error: 6_402 - .saturating_add(Weight::from_parts(13_502_238, 0).saturating_mul(a.into())) + // Minimum execution time: 18_611_000 picoseconds. + Weight::from_parts(18_970_000, 3675) + // Standard Error: 13_224 + .saturating_add(Weight::from_parts(16_397_299, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) .saturating_add(Weight::from_parts(0, 2623).saturating_mul(a.into())) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Metadata` (r:1 w:0) - /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:0) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn finish_destroy() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 12_278_000 picoseconds. - Weight::from_parts(12_834_000, 3675) + // Minimum execution time: 14_504_000 picoseconds. + Weight::from_parts(14_906_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) fn mint() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 21_793_000 picoseconds. - Weight::from_parts(22_284_000, 3675) + // Minimum execution time: 26_653_000 picoseconds. + Weight::from_parts(27_260_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) fn burn() -> Weight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 28_712_000 picoseconds. - Weight::from_parts(29_710_000, 3675) + // Minimum execution time: 33_625_000 picoseconds. + Weight::from_parts(34_474_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:2 w:2) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:2 w:2) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: // Measured: `498` // Estimated: `6208` - // Minimum execution time: 41_331_000 picoseconds. - Weight::from_parts(42_362_000, 6208) + // Minimum execution time: 47_609_000 picoseconds. + Weight::from_parts(48_476_000, 6208) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:2 w:2) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:2 w:2) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_keep_alive() -> Weight { // Proof Size summary in bytes: // Measured: `498` // Estimated: `6208` - // Minimum execution time: 37_316_000 picoseconds. - Weight::from_parts(38_200_000, 6208) + // Minimum execution time: 41_625_000 picoseconds. + Weight::from_parts(43_030_000, 6208) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:2 w:2) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:2 w:2) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `498` // Estimated: `6208` - // Minimum execution time: 41_347_000 picoseconds. - Weight::from_parts(42_625_000, 6208) + // Minimum execution time: 47_661_000 picoseconds. + Weight::from_parts(48_469_000, 6208) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: `Assets::Asset` (r:1 w:0) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) fn freeze() -> Weight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 15_072_000 picoseconds. - Weight::from_parts(15_925_000, 3675) + // Minimum execution time: 17_727_000 picoseconds. + Weight::from_parts(18_384_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:0) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) fn thaw() -> Weight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 14_991_000 picoseconds. - Weight::from_parts(15_987_000, 3675) + // Minimum execution time: 17_657_000 picoseconds. + Weight::from_parts(18_282_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn freeze_asset() -> Weight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 11_296_000 picoseconds. - Weight::from_parts(12_052_000, 3675) + // Minimum execution time: 13_743_000 picoseconds. + Weight::from_parts(14_193_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn thaw_asset() -> Weight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 11_446_000 picoseconds. - Weight::from_parts(11_791_000, 3675) + // Minimum execution time: 13_653_000 picoseconds. + Weight::from_parts(14_263_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Metadata` (r:1 w:0) - /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:0) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 13_134_000 picoseconds. - Weight::from_parts(13_401_000, 3675) + // Minimum execution time: 15_328_000 picoseconds. + Weight::from_parts(16_042_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn set_team() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 11_395_000 picoseconds. - Weight::from_parts(11_718_000, 3675) + // Minimum execution time: 14_097_000 picoseconds. + Weight::from_parts(14_641_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:0) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Metadata` (r:1 w:1) - /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:1) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn set_metadata(n: u32, _s: u32, ) -> Weight { + fn set_metadata(_n: u32, _s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 25_147_000 picoseconds. - Weight::from_parts(26_614_272, 3675) - // Standard Error: 959 - .saturating_add(Weight::from_parts(2_300, 0).saturating_mul(n.into())) + // Minimum execution time: 29_535_000 picoseconds. + Weight::from_parts(31_456_892, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:0) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Metadata` (r:1 w:1) - /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:1) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn clear_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `515` // Estimated: `3675` - // Minimum execution time: 26_094_000 picoseconds. - Weight::from_parts(27_199_000, 3675) + // Minimum execution time: 30_680_000 picoseconds. + Weight::from_parts(31_930_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:0) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Metadata` (r:1 w:1) - /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:1) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn force_set_metadata(n: u32, s: u32, ) -> Weight { + fn force_set_metadata(_n: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `190` // Estimated: `3675` - // Minimum execution time: 11_977_000 picoseconds. - Weight::from_parts(12_719_933, 3675) - // Standard Error: 429 - .saturating_add(Weight::from_parts(3_239, 0).saturating_mul(n.into())) - // Standard Error: 429 - .saturating_add(Weight::from_parts(3_941, 0).saturating_mul(s.into())) + // Minimum execution time: 14_660_000 picoseconds. + Weight::from_parts(15_718_387, 3675) + // Standard Error: 622 + .saturating_add(Weight::from_parts(2_640, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:0) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Metadata` (r:1 w:1) - /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:1) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn force_clear_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `515` // Estimated: `3675` - // Minimum execution time: 25_859_000 picoseconds. - Weight::from_parts(26_654_000, 3675) + // Minimum execution time: 30_853_000 picoseconds. + Weight::from_parts(31_483_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn force_asset_status() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 10_965_000 picoseconds. - Weight::from_parts(11_595_000, 3675) + // Minimum execution time: 13_632_000 picoseconds. + Weight::from_parts(14_077_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Approvals` (r:1 w:1) - /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Approvals (r:1 w:1) + /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) fn approve_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 28_427_000 picoseconds. - Weight::from_parts(29_150_000, 3675) + // Minimum execution time: 33_780_000 picoseconds. + Weight::from_parts(34_533_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Approvals` (r:1 w:1) - /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:2 w:2) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Approvals (r:1 w:1) + /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) + /// Storage: Assets Account (r:2 w:2) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_approved() -> Weight { // Proof Size summary in bytes: // Measured: `668` // Estimated: `6208` - // Minimum execution time: 60_227_000 picoseconds. - Weight::from_parts(61_839_000, 6208) + // Minimum execution time: 67_712_000 picoseconds. + Weight::from_parts(69_946_000, 6208) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Approvals` (r:1 w:1) - /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Approvals (r:1 w:1) + /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) fn cancel_approval() -> Weight { // Proof Size summary in bytes: // Measured: `555` // Estimated: `3675` - // Minimum execution time: 30_738_000 picoseconds. - Weight::from_parts(31_988_000, 3675) + // Minimum execution time: 36_668_000 picoseconds. + Weight::from_parts(37_637_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Approvals` (r:1 w:1) - /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Approvals (r:1 w:1) + /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) fn force_cancel_approval() -> Weight { // Proof Size summary in bytes: // Measured: `555` // Estimated: `3675` - // Minimum execution time: 31_444_000 picoseconds. - Weight::from_parts(32_126_000, 3675) + // Minimum execution time: 36_685_000 picoseconds. + Weight::from_parts(37_950_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn set_min_balance() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 11_890_000 picoseconds. - Weight::from_parts(12_462_000, 3675) + // Minimum execution time: 14_466_000 picoseconds. + Weight::from_parts(14_924_000, 3675) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn touch() -> Weight { // Proof Size summary in bytes: // Measured: `453` // Estimated: `3675` - // Minimum execution time: 30_675_000 picoseconds. - Weight::from_parts(31_749_000, 3675) + // Minimum execution time: 34_874_000 picoseconds. + Weight::from_parts(36_330_000, 3675) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn touch_other() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 28_290_000 picoseconds. - Weight::from_parts(29_405_000, 3675) + // Minimum execution time: 33_278_000 picoseconds. + Weight::from_parts(34_104_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn refund() -> Weight { // Proof Size summary in bytes: // Measured: `579` // Estimated: `3675` - // Minimum execution time: 30_195_000 picoseconds. - Weight::from_parts(31_105_000, 3675) + // Minimum execution time: 32_898_000 picoseconds. + Weight::from_parts(33_489_000, 3675) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn refund_other() -> Weight { // Proof Size summary in bytes: // Measured: `510` // Estimated: `3675` - // Minimum execution time: 27_785_000 picoseconds. - Weight::from_parts(28_783_000, 3675) + // Minimum execution time: 31_243_000 picoseconds. + Weight::from_parts(31_909_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Assets::Asset` (r:1 w:0) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) fn block() -> Weight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 15_318_000 picoseconds. - Weight::from_parts(16_113_000, 3675) + // Minimum execution time: 17_692_000 picoseconds. + Weight::from_parts(18_253_000, 3675) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: // Measured: `293` // Estimated: `3675` - // Minimum execution time: 24_690_000 picoseconds. - Weight::from_parts(25_878_000, 3675) + // Minimum execution time: 31_340_000 picoseconds. + Weight::from_parts(31_977_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `153` // Estimated: `3675` - // Minimum execution time: 10_997_000 picoseconds. - Weight::from_parts(11_369_000, 3675) + // Minimum execution time: 13_342_000 picoseconds. + Weight::from_parts(13_782_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn start_destroy() -> Weight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 11_536_000 picoseconds. - Weight::from_parts(12_309_000, 3675) + // Minimum execution time: 14_437_000 picoseconds. + Weight::from_parts(14_833_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1001 w:1000) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1000 w:1000) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1001 w:1000) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: System Account (r:1000 w:1000) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `c` is `[0, 1000]`. fn destroy_accounts(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + c * (208 ±0)` // Estimated: `3675 + c * (2609 ±0)` - // Minimum execution time: 15_798_000 picoseconds. - Weight::from_parts(16_005_000, 3675) - // Standard Error: 7_818 - .saturating_add(Weight::from_parts(12_826_278, 0).saturating_mul(c.into())) + // Minimum execution time: 18_728_000 picoseconds. + Weight::from_parts(18_982_000, 3675) + // Standard Error: 11_708 + .saturating_add(Weight::from_parts(14_363_570, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(c.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(c.into()))) .saturating_add(Weight::from_parts(0, 2609).saturating_mul(c.into())) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Approvals` (r:1001 w:1000) - /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Approvals (r:1001 w:1000) + /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) /// The range of component `a` is `[0, 1000]`. fn destroy_approvals(a: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `522 + a * (86 ±0)` // Estimated: `3675 + a * (2623 ±0)` - // Minimum execution time: 16_334_000 picoseconds. - Weight::from_parts(16_616_000, 3675) - // Standard Error: 6_402 - .saturating_add(Weight::from_parts(13_502_238, 0).saturating_mul(a.into())) + // Minimum execution time: 18_611_000 picoseconds. + Weight::from_parts(18_970_000, 3675) + // Standard Error: 13_224 + .saturating_add(Weight::from_parts(16_397_299, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(a.into()))) .saturating_add(Weight::from_parts(0, 2623).saturating_mul(a.into())) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Metadata` (r:1 w:0) - /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:0) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn finish_destroy() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 12_278_000 picoseconds. - Weight::from_parts(12_834_000, 3675) + // Minimum execution time: 14_504_000 picoseconds. + Weight::from_parts(14_906_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) fn mint() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 21_793_000 picoseconds. - Weight::from_parts(22_284_000, 3675) + // Minimum execution time: 26_653_000 picoseconds. + Weight::from_parts(27_260_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) fn burn() -> Weight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 28_712_000 picoseconds. - Weight::from_parts(29_710_000, 3675) + // Minimum execution time: 33_625_000 picoseconds. + Weight::from_parts(34_474_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:2 w:2) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:2 w:2) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: // Measured: `498` // Estimated: `6208` - // Minimum execution time: 41_331_000 picoseconds. - Weight::from_parts(42_362_000, 6208) + // Minimum execution time: 47_609_000 picoseconds. + Weight::from_parts(48_476_000, 6208) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:2 w:2) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:2 w:2) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_keep_alive() -> Weight { // Proof Size summary in bytes: // Measured: `498` // Estimated: `6208` - // Minimum execution time: 37_316_000 picoseconds. - Weight::from_parts(38_200_000, 6208) + // Minimum execution time: 41_625_000 picoseconds. + Weight::from_parts(43_030_000, 6208) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:2 w:2) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:2 w:2) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `498` // Estimated: `6208` - // Minimum execution time: 41_347_000 picoseconds. - Weight::from_parts(42_625_000, 6208) + // Minimum execution time: 47_661_000 picoseconds. + Weight::from_parts(48_469_000, 6208) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: `Assets::Asset` (r:1 w:0) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) fn freeze() -> Weight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 15_072_000 picoseconds. - Weight::from_parts(15_925_000, 3675) + // Minimum execution time: 17_727_000 picoseconds. + Weight::from_parts(18_384_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:0) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) fn thaw() -> Weight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 14_991_000 picoseconds. - Weight::from_parts(15_987_000, 3675) + // Minimum execution time: 17_657_000 picoseconds. + Weight::from_parts(18_282_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn freeze_asset() -> Weight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 11_296_000 picoseconds. - Weight::from_parts(12_052_000, 3675) + // Minimum execution time: 13_743_000 picoseconds. + Weight::from_parts(14_193_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn thaw_asset() -> Weight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 11_446_000 picoseconds. - Weight::from_parts(11_791_000, 3675) + // Minimum execution time: 13_653_000 picoseconds. + Weight::from_parts(14_263_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Metadata` (r:1 w:0) - /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:0) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 13_134_000 picoseconds. - Weight::from_parts(13_401_000, 3675) + // Minimum execution time: 15_328_000 picoseconds. + Weight::from_parts(16_042_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn set_team() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 11_395_000 picoseconds. - Weight::from_parts(11_718_000, 3675) + // Minimum execution time: 14_097_000 picoseconds. + Weight::from_parts(14_641_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:0) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Metadata` (r:1 w:1) - /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:1) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn set_metadata(n: u32, _s: u32, ) -> Weight { + fn set_metadata(_n: u32, _s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 25_147_000 picoseconds. - Weight::from_parts(26_614_272, 3675) - // Standard Error: 959 - .saturating_add(Weight::from_parts(2_300, 0).saturating_mul(n.into())) + // Minimum execution time: 29_535_000 picoseconds. + Weight::from_parts(31_456_892, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:0) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Metadata` (r:1 w:1) - /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:1) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn clear_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `515` // Estimated: `3675` - // Minimum execution time: 26_094_000 picoseconds. - Weight::from_parts(27_199_000, 3675) + // Minimum execution time: 30_680_000 picoseconds. + Weight::from_parts(31_930_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:0) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Metadata` (r:1 w:1) - /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:1) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn force_set_metadata(n: u32, s: u32, ) -> Weight { + fn force_set_metadata(_n: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `190` // Estimated: `3675` - // Minimum execution time: 11_977_000 picoseconds. - Weight::from_parts(12_719_933, 3675) - // Standard Error: 429 - .saturating_add(Weight::from_parts(3_239, 0).saturating_mul(n.into())) - // Standard Error: 429 - .saturating_add(Weight::from_parts(3_941, 0).saturating_mul(s.into())) + // Minimum execution time: 14_660_000 picoseconds. + Weight::from_parts(15_718_387, 3675) + // Standard Error: 622 + .saturating_add(Weight::from_parts(2_640, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:0) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Metadata` (r:1 w:1) - /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:1) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn force_clear_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `515` // Estimated: `3675` - // Minimum execution time: 25_859_000 picoseconds. - Weight::from_parts(26_654_000, 3675) + // Minimum execution time: 30_853_000 picoseconds. + Weight::from_parts(31_483_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn force_asset_status() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 10_965_000 picoseconds. - Weight::from_parts(11_595_000, 3675) + // Minimum execution time: 13_632_000 picoseconds. + Weight::from_parts(14_077_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Approvals` (r:1 w:1) - /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Approvals (r:1 w:1) + /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) fn approve_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3675` - // Minimum execution time: 28_427_000 picoseconds. - Weight::from_parts(29_150_000, 3675) + // Minimum execution time: 33_780_000 picoseconds. + Weight::from_parts(34_533_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Approvals` (r:1 w:1) - /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:2 w:2) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Approvals (r:1 w:1) + /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) + /// Storage: Assets Account (r:2 w:2) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_approved() -> Weight { // Proof Size summary in bytes: // Measured: `668` // Estimated: `6208` - // Minimum execution time: 60_227_000 picoseconds. - Weight::from_parts(61_839_000, 6208) + // Minimum execution time: 67_712_000 picoseconds. + Weight::from_parts(69_946_000, 6208) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Approvals` (r:1 w:1) - /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Approvals (r:1 w:1) + /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) fn cancel_approval() -> Weight { // Proof Size summary in bytes: // Measured: `555` // Estimated: `3675` - // Minimum execution time: 30_738_000 picoseconds. - Weight::from_parts(31_988_000, 3675) + // Minimum execution time: 36_668_000 picoseconds. + Weight::from_parts(37_637_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Approvals` (r:1 w:1) - /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(148), added: 2623, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Approvals (r:1 w:1) + /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) fn force_cancel_approval() -> Weight { // Proof Size summary in bytes: // Measured: `555` // Estimated: `3675` - // Minimum execution time: 31_444_000 picoseconds. - Weight::from_parts(32_126_000, 3675) + // Minimum execution time: 36_685_000 picoseconds. + Weight::from_parts(37_950_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn set_min_balance() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 11_890_000 picoseconds. - Weight::from_parts(12_462_000, 3675) + // Minimum execution time: 14_466_000 picoseconds. + Weight::from_parts(14_924_000, 3675) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn touch() -> Weight { // Proof Size summary in bytes: // Measured: `453` // Estimated: `3675` - // Minimum execution time: 30_675_000 picoseconds. - Weight::from_parts(31_749_000, 3675) + // Minimum execution time: 34_874_000 picoseconds. + Weight::from_parts(36_330_000, 3675) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn touch_other() -> Weight { // Proof Size summary in bytes: // Measured: `351` // Estimated: `3675` - // Minimum execution time: 28_290_000 picoseconds. - Weight::from_parts(29_405_000, 3675) + // Minimum execution time: 33_278_000 picoseconds. + Weight::from_parts(34_104_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn refund() -> Weight { // Proof Size summary in bytes: // Measured: `579` // Estimated: `3675` - // Minimum execution time: 30_195_000 picoseconds. - Weight::from_parts(31_105_000, 3675) + // Minimum execution time: 32_898_000 picoseconds. + Weight::from_parts(33_489_000, 3675) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn refund_other() -> Weight { // Proof Size summary in bytes: // Measured: `510` // Estimated: `3675` - // Minimum execution time: 27_785_000 picoseconds. - Weight::from_parts(28_783_000, 3675) + // Minimum execution time: 31_243_000 picoseconds. + Weight::from_parts(31_909_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Assets::Asset` (r:1 w:0) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: Assets Asset (r:1 w:0) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) fn block() -> Weight { // Proof Size summary in bytes: // Measured: `459` // Estimated: `3675` - // Minimum execution time: 15_318_000 picoseconds. - Weight::from_parts(16_113_000, 3675) + // Minimum execution time: 17_692_000 picoseconds. + Weight::from_parts(18_253_000, 3675) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/babe/src/mock.rs b/substrate/frame/babe/src/mock.rs index 1ba0cdd0cc1..b693f4fce9b 100644 --- a/substrate/frame/babe/src/mock.rs +++ b/substrate/frame/babe/src/mock.rs @@ -37,9 +37,8 @@ use sp_core::{ use sp_io; use sp_runtime::{ curve::PiecewiseLinear, - generic::UncheckedExtrinsic, impl_opaque_keys, - testing::{Digest, DigestItem, Header}, + testing::{Digest, DigestItem, Header, TestXt}, traits::{Header as _, OpaqueKeys}, BuildStorage, Perbill, }; @@ -75,7 +74,7 @@ where RuntimeCall: From, { type OverarchingCall = RuntimeCall; - type Extrinsic = UncheckedExtrinsic; + type Extrinsic = TestXt; } impl_opaque_keys! { diff --git a/substrate/frame/bags-list/src/weights.rs b/substrate/frame/bags-list/src/weights.rs index 804b702cc9a..d929c6bb959 100644 --- a/substrate/frame/bags-list/src/weights.rs +++ b/substrate/frame/bags-list/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_bags_list` +//! Autogenerated weights for pallet_bags_list //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/bags-list/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/bags-list/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,123 +50,123 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_bags_list`. +/// Weight functions needed for pallet_bags_list. pub trait WeightInfo { fn rebag_non_terminal() -> Weight; fn rebag_terminal() -> Weight; fn put_in_front_of() -> Weight; } -/// Weights for `pallet_bags_list` using the Substrate node and recommended hardware. +/// Weights for pallet_bags_list using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Staking::Bonded` (r:1 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:1 w:0) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListNodes` (r:4 w:4) - /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListBags` (r:1 w:1) - /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:4 w:4) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn rebag_non_terminal() -> Weight { // Proof Size summary in bytes: - // Measured: `1719` + // Measured: `1724` // Estimated: `11506` - // Minimum execution time: 55_856_000 picoseconds. - Weight::from_parts(59_022_000, 11506) + // Minimum execution time: 62_137_000 picoseconds. + Weight::from_parts(64_050_000, 11506) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: `Staking::Bonded` (r:1 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:1 w:0) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListNodes` (r:3 w:3) - /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListBags` (r:2 w:2) - /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:3 w:3) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:2 w:2) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn rebag_terminal() -> Weight { // Proof Size summary in bytes: - // Measured: `1613` + // Measured: `1618` // Estimated: `8877` - // Minimum execution time: 55_418_000 picoseconds. - Weight::from_parts(57_352_000, 8877) + // Minimum execution time: 60_880_000 picoseconds. + Weight::from_parts(62_078_000, 8877) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: `VoterList::ListNodes` (r:4 w:4) - /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:2 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:2 w:0) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) - /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListBags` (r:1 w:1) - /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: VoterList ListNodes (r:4 w:4) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:2 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:2 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn put_in_front_of() -> Weight { // Proof Size summary in bytes: - // Measured: `1925` + // Measured: `1930` // Estimated: `11506` - // Minimum execution time: 63_820_000 picoseconds. - Weight::from_parts(65_530_000, 11506) + // Minimum execution time: 68_911_000 picoseconds. + Weight::from_parts(70_592_000, 11506) .saturating_add(T::DbWeight::get().reads(10_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Staking::Bonded` (r:1 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:1 w:0) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListNodes` (r:4 w:4) - /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListBags` (r:1 w:1) - /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:4 w:4) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn rebag_non_terminal() -> Weight { // Proof Size summary in bytes: - // Measured: `1719` + // Measured: `1724` // Estimated: `11506` - // Minimum execution time: 55_856_000 picoseconds. - Weight::from_parts(59_022_000, 11506) + // Minimum execution time: 62_137_000 picoseconds. + Weight::from_parts(64_050_000, 11506) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: `Staking::Bonded` (r:1 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:1 w:0) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListNodes` (r:3 w:3) - /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListBags` (r:2 w:2) - /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:3 w:3) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:2 w:2) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn rebag_terminal() -> Weight { // Proof Size summary in bytes: - // Measured: `1613` + // Measured: `1618` // Estimated: `8877` - // Minimum execution time: 55_418_000 picoseconds. - Weight::from_parts(57_352_000, 8877) + // Minimum execution time: 60_880_000 picoseconds. + Weight::from_parts(62_078_000, 8877) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: `VoterList::ListNodes` (r:4 w:4) - /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:2 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:2 w:0) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) - /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListBags` (r:1 w:1) - /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: VoterList ListNodes (r:4 w:4) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:2 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:2 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn put_in_front_of() -> Weight { // Proof Size summary in bytes: - // Measured: `1925` + // Measured: `1930` // Estimated: `11506` - // Minimum execution time: 63_820_000 picoseconds. - Weight::from_parts(65_530_000, 11506) + // Minimum execution time: 68_911_000 picoseconds. + Weight::from_parts(70_592_000, 11506) .saturating_add(RocksDbWeight::get().reads(10_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } diff --git a/substrate/frame/balances/Cargo.toml b/substrate/frame/balances/Cargo.toml index db114290ed8..64ae90c6757 100644 --- a/substrate/frame/balances/Cargo.toml +++ b/substrate/frame/balances/Cargo.toml @@ -53,7 +53,6 @@ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] try-runtime = [ diff --git a/substrate/frame/balances/src/tests/currency_tests.rs b/substrate/frame/balances/src/tests/currency_tests.rs index 10bb79901f8..46a4c4caefc 100644 --- a/substrate/frame/balances/src/tests/currency_tests.rs +++ b/substrate/frame/balances/src/tests/currency_tests.rs @@ -30,7 +30,6 @@ use frame_support::{ StorageNoopGuard, }; use frame_system::Event as SysEvent; -use sp_runtime::traits::DispatchTransaction; const ID_1: LockIdentifier = *b"1 "; const ID_2: LockIdentifier = *b"2 "; @@ -241,17 +240,17 @@ fn lock_should_work_reserve() { TokenError::Frozen ); assert_noop!(Balances::reserve(&1, 1), Error::::LiquidityRestrictions,); - assert!(ChargeTransactionPayment::::validate_and_prepare( + assert!( as SignedExtension>::pre_dispatch( ChargeTransactionPayment::from(1), - Some(1).into(), + &1, CALL, &info_from_weight(Weight::from_parts(1, 0)), 1, ) .is_err()); - assert!(ChargeTransactionPayment::::validate_and_prepare( + assert!( as SignedExtension>::pre_dispatch( ChargeTransactionPayment::from(0), - Some(1).into(), + &1, CALL, &info_from_weight(Weight::from_parts(1, 0)), 1, @@ -272,17 +271,17 @@ fn lock_should_work_tx_fee() { TokenError::Frozen ); assert_noop!(Balances::reserve(&1, 1), Error::::LiquidityRestrictions,); - assert!(ChargeTransactionPayment::::validate_and_prepare( + assert!( as SignedExtension>::pre_dispatch( ChargeTransactionPayment::from(1), - Some(1).into(), + &1, CALL, &info_from_weight(Weight::from_parts(1, 0)), 1, ) .is_err()); - assert!(ChargeTransactionPayment::::validate_and_prepare( + assert!( as SignedExtension>::pre_dispatch( ChargeTransactionPayment::from(0), - Some(1).into(), + &1, CALL, &info_from_weight(Weight::from_parts(1, 0)), 1, diff --git a/substrate/frame/balances/src/tests/mod.rs b/substrate/frame/balances/src/tests/mod.rs index ee076a10fd1..599909fa943 100644 --- a/substrate/frame/balances/src/tests/mod.rs +++ b/substrate/frame/balances/src/tests/mod.rs @@ -37,7 +37,7 @@ use scale_info::TypeInfo; use sp_core::hexdisplay::HexDisplay; use sp_io; use sp_runtime::{ - traits::{BadOrigin, Zero}, + traits::{BadOrigin, SignedExtension, Zero}, ArithmeticError, BuildStorage, DispatchError, DispatchResult, FixedPointNumber, RuntimeDebug, TokenError, }; @@ -96,13 +96,13 @@ impl frame_system::Config for Test { type AccountData = super::AccountData; } -#[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig as pallet_transaction_payment::DefaultConfig)] impl pallet_transaction_payment::Config for Test { type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = CurrencyAdapter, ()>; type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; type LengthToFee = IdentityFee; + type FeeMultiplierUpdate = (); } pub(crate) type Balance = u64; diff --git a/substrate/frame/balances/src/weights.rs b/substrate/frame/balances/src/weights.rs index 6bcfe050af7..f875ea189ba 100644 --- a/substrate/frame/balances/src/weights.rs +++ b/substrate/frame/balances/src/weights.rs @@ -17,28 +17,26 @@ //! Autogenerated weights for `pallet_balances` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2024-01-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-j8vvqcjr-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/production/substrate-node +// target/production/substrate-node // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_balances -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/balances/src/weights.rs +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_balances +// --chain=dev // --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/balances/src/weights.rs // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -71,8 +69,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 46_407_000 picoseconds. - Weight::from_parts(47_561_000, 3593) + // Minimum execution time: 46_329_000 picoseconds. + Weight::from_parts(47_297_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -82,8 +80,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 36_574_000 picoseconds. - Weight::from_parts(37_682_000, 3593) + // Minimum execution time: 36_187_000 picoseconds. + Weight::from_parts(36_900_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -93,8 +91,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 13_990_000 picoseconds. - Weight::from_parts(14_568_000, 3593) + // Minimum execution time: 13_498_000 picoseconds. + Weight::from_parts(14_143_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -104,8 +102,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 19_594_000 picoseconds. - Weight::from_parts(20_148_000, 3593) + // Minimum execution time: 18_756_000 picoseconds. + Weight::from_parts(19_553_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -115,8 +113,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6196` - // Minimum execution time: 47_945_000 picoseconds. - Weight::from_parts(49_363_000, 6196) + // Minimum execution time: 47_826_000 picoseconds. + Weight::from_parts(48_834_000, 6196) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -126,8 +124,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 45_205_000 picoseconds. - Weight::from_parts(45_952_000, 3593) + // Minimum execution time: 44_621_000 picoseconds. + Weight::from_parts(45_151_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -137,8 +135,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 16_593_000 picoseconds. - Weight::from_parts(17_123_000, 3593) + // Minimum execution time: 16_194_000 picoseconds. + Weight::from_parts(16_945_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -149,10 +147,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0 + u * (135 ±0)` // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 16_182_000 picoseconds. - Weight::from_parts(16_412_000, 990) - // Standard Error: 10_148 - .saturating_add(Weight::from_parts(13_382_459, 0).saturating_mul(u.into())) + // Minimum execution time: 15_782_000 picoseconds. + Weight::from_parts(16_118_000, 990) + // Standard Error: 10_499 + .saturating_add(Weight::from_parts(13_327_660, 0).saturating_mul(u.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(u.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(u.into()))) .saturating_add(Weight::from_parts(0, 2603).saturating_mul(u.into())) @@ -161,8 +159,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_478_000 picoseconds. - Weight::from_parts(6_830_000, 0) + // Minimum execution time: 6_157_000 picoseconds. + Weight::from_parts(6_507_000, 0) } } @@ -174,8 +172,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 46_407_000 picoseconds. - Weight::from_parts(47_561_000, 3593) + // Minimum execution time: 46_329_000 picoseconds. + Weight::from_parts(47_297_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -185,8 +183,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 36_574_000 picoseconds. - Weight::from_parts(37_682_000, 3593) + // Minimum execution time: 36_187_000 picoseconds. + Weight::from_parts(36_900_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -196,8 +194,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 13_990_000 picoseconds. - Weight::from_parts(14_568_000, 3593) + // Minimum execution time: 13_498_000 picoseconds. + Weight::from_parts(14_143_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -207,8 +205,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 19_594_000 picoseconds. - Weight::from_parts(20_148_000, 3593) + // Minimum execution time: 18_756_000 picoseconds. + Weight::from_parts(19_553_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -218,8 +216,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6196` - // Minimum execution time: 47_945_000 picoseconds. - Weight::from_parts(49_363_000, 6196) + // Minimum execution time: 47_826_000 picoseconds. + Weight::from_parts(48_834_000, 6196) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -229,8 +227,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 45_205_000 picoseconds. - Weight::from_parts(45_952_000, 3593) + // Minimum execution time: 44_621_000 picoseconds. + Weight::from_parts(45_151_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -240,8 +238,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 16_593_000 picoseconds. - Weight::from_parts(17_123_000, 3593) + // Minimum execution time: 16_194_000 picoseconds. + Weight::from_parts(16_945_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -252,10 +250,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0 + u * (135 ±0)` // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 16_182_000 picoseconds. - Weight::from_parts(16_412_000, 990) - // Standard Error: 10_148 - .saturating_add(Weight::from_parts(13_382_459, 0).saturating_mul(u.into())) + // Minimum execution time: 15_782_000 picoseconds. + Weight::from_parts(16_118_000, 990) + // Standard Error: 10_499 + .saturating_add(Weight::from_parts(13_327_660, 0).saturating_mul(u.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(u.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(u.into()))) .saturating_add(Weight::from_parts(0, 2603).saturating_mul(u.into())) @@ -264,7 +262,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_478_000 picoseconds. - Weight::from_parts(6_830_000, 0) + // Minimum execution time: 6_157_000 picoseconds. + Weight::from_parts(6_507_000, 0) } } diff --git a/substrate/frame/beefy/src/mock.rs b/substrate/frame/beefy/src/mock.rs index 5d963d309a4..9cce479890a 100644 --- a/substrate/frame/beefy/src/mock.rs +++ b/substrate/frame/beefy/src/mock.rs @@ -29,8 +29,8 @@ use pallet_session::historical as pallet_session_historical; use sp_core::{crypto::KeyTypeId, ConstU128}; use sp_io::TestExternalities; use sp_runtime::{ - app_crypto::ecdsa::Public, curve::PiecewiseLinear, generic::UncheckedExtrinsic, - impl_opaque_keys, traits::OpaqueKeys, BuildStorage, Perbill, + app_crypto::ecdsa::Public, curve::PiecewiseLinear, impl_opaque_keys, testing::TestXt, + traits::OpaqueKeys, BuildStorage, Perbill, }; use sp_staking::{EraIndex, SessionIndex}; use sp_state_machine::BasicExternalities; @@ -73,7 +73,7 @@ where RuntimeCall: From, { type OverarchingCall = RuntimeCall; - type Extrinsic = UncheckedExtrinsic; + type Extrinsic = TestXt; } parameter_types! { diff --git a/substrate/frame/benchmarking/src/weights.rs b/substrate/frame/benchmarking/src/weights.rs index 76f9a3fe52b..13d73e420cc 100644 --- a/substrate/frame/benchmarking/src/weights.rs +++ b/substrate/frame/benchmarking/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `frame_benchmarking` +//! Autogenerated weights for frame_benchmarking //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/benchmarking/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/benchmarking/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `frame_benchmarking`. +/// Weight functions needed for frame_benchmarking. pub trait WeightInfo { fn addition(i: u32, ) -> Weight; fn subtraction(i: u32, ) -> Weight; @@ -59,7 +60,7 @@ pub trait WeightInfo { fn sr25519_verification(i: u32, ) -> Weight; } -/// Weights for `frame_benchmarking` using the Substrate node and recommended hardware. +/// Weights for frame_benchmarking using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 1000000]`. @@ -67,101 +68,101 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 150_000 picoseconds. - Weight::from_parts(190_440, 0) + // Minimum execution time: 147_000 picoseconds. + Weight::from_parts(185_656, 0) } /// The range of component `i` is `[0, 1000000]`. fn subtraction(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 151_000 picoseconds. - Weight::from_parts(201_397, 0) + // Minimum execution time: 146_000 picoseconds. + Weight::from_parts(189_816, 0) } /// The range of component `i` is `[0, 1000000]`. fn multiplication(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 152_000 picoseconds. - Weight::from_parts(187_862, 0) + // Minimum execution time: 148_000 picoseconds. + Weight::from_parts(202_367, 0) } /// The range of component `i` is `[0, 1000000]`. fn division(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 146_000 picoseconds. - Weight::from_parts(215_191, 0) + // Minimum execution time: 143_000 picoseconds. + Weight::from_parts(189_693, 0) } fn hashing() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 25_432_823_000 picoseconds. - Weight::from_parts(25_568_846_000, 0) + // Minimum execution time: 24_167_071_000 picoseconds. + Weight::from_parts(24_391_749_000, 0) } /// The range of component `i` is `[0, 100]`. fn sr25519_verification(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 193_000 picoseconds. - Weight::from_parts(3_846_690, 0) - // Standard Error: 6_694 - .saturating_add(Weight::from_parts(40_647_582, 0).saturating_mul(i.into())) + // Minimum execution time: 231_000 picoseconds. + Weight::from_parts(2_998_013, 0) + // Standard Error: 6_256 + .saturating_add(Weight::from_parts(55_456_705, 0).saturating_mul(i.into())) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { /// The range of component `i` is `[0, 1000000]`. fn addition(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 150_000 picoseconds. - Weight::from_parts(190_440, 0) + // Minimum execution time: 147_000 picoseconds. + Weight::from_parts(185_656, 0) } /// The range of component `i` is `[0, 1000000]`. fn subtraction(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 151_000 picoseconds. - Weight::from_parts(201_397, 0) + // Minimum execution time: 146_000 picoseconds. + Weight::from_parts(189_816, 0) } /// The range of component `i` is `[0, 1000000]`. fn multiplication(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 152_000 picoseconds. - Weight::from_parts(187_862, 0) + // Minimum execution time: 148_000 picoseconds. + Weight::from_parts(202_367, 0) } /// The range of component `i` is `[0, 1000000]`. fn division(_i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 146_000 picoseconds. - Weight::from_parts(215_191, 0) + // Minimum execution time: 143_000 picoseconds. + Weight::from_parts(189_693, 0) } fn hashing() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 25_432_823_000 picoseconds. - Weight::from_parts(25_568_846_000, 0) + // Minimum execution time: 24_167_071_000 picoseconds. + Weight::from_parts(24_391_749_000, 0) } /// The range of component `i` is `[0, 100]`. fn sr25519_verification(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 193_000 picoseconds. - Weight::from_parts(3_846_690, 0) - // Standard Error: 6_694 - .saturating_add(Weight::from_parts(40_647_582, 0).saturating_mul(i.into())) + // Minimum execution time: 231_000 picoseconds. + Weight::from_parts(2_998_013, 0) + // Standard Error: 6_256 + .saturating_add(Weight::from_parts(55_456_705, 0).saturating_mul(i.into())) } } diff --git a/substrate/frame/bounties/src/weights.rs b/substrate/frame/bounties/src/weights.rs index 1f0e38b6702..a172d15b56c 100644 --- a/substrate/frame/bounties/src/weights.rs +++ b/substrate/frame/bounties/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_bounties` +//! Autogenerated weights for pallet_bounties //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/bounties/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/bounties/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_bounties`. +/// Weight functions needed for pallet_bounties. pub trait WeightInfo { fn propose_bounty(d: u32, ) -> Weight; fn approve_bounty() -> Weight; @@ -64,169 +65,169 @@ pub trait WeightInfo { fn spend_funds(b: u32, ) -> Weight; } -/// Weights for `pallet_bounties` using the Substrate node and recommended hardware. +/// Weights for pallet_bounties using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Bounties::BountyCount` (r:1 w:1) - /// Proof: `Bounties::BountyCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Bounties::BountyDescriptions` (r:0 w:1) - /// Proof: `Bounties::BountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) - /// Storage: `Bounties::Bounties` (r:0 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: Bounties BountyCount (r:1 w:1) + /// Proof: Bounties BountyCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Bounties BountyDescriptions (r:0 w:1) + /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) + /// Storage: Bounties Bounties (r:0 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) /// The range of component `d` is `[0, 300]`. fn propose_bounty(d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `309` + // Measured: `276` // Estimated: `3593` - // Minimum execution time: 24_286_000 picoseconds. - Weight::from_parts(25_657_314, 3593) - // Standard Error: 215 - .saturating_add(Weight::from_parts(1_116, 0).saturating_mul(d.into())) + // Minimum execution time: 29_384_000 picoseconds. + Weight::from_parts(30_820_018, 3593) + // Standard Error: 298 + .saturating_add(Weight::from_parts(2_920, 0).saturating_mul(d.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `Bounties::BountyApprovals` (r:1 w:1) - /// Proof: `Bounties::BountyApprovals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: Bounties BountyApprovals (r:1 w:1) + /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) fn approve_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `401` + // Measured: `368` // Estimated: `3642` - // Minimum execution time: 12_526_000 picoseconds. - Weight::from_parts(13_373_000, 3642) + // Minimum execution time: 10_873_000 picoseconds. + Weight::from_parts(11_421_000, 3642) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) fn propose_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `421` + // Measured: `388` // Estimated: `3642` - // Minimum execution time: 11_807_000 picoseconds. - Weight::from_parts(12_340_000, 3642) + // Minimum execution time: 9_181_000 picoseconds. + Weight::from_parts(9_726_000, 3642) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn unassign_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `597` + // Measured: `564` // Estimated: `3642` - // Minimum execution time: 27_183_000 picoseconds. - Weight::from_parts(28_250_000, 3642) + // Minimum execution time: 30_257_000 picoseconds. + Weight::from_parts(30_751_000, 3642) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn accept_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `593` + // Measured: `560` // Estimated: `3642` - // Minimum execution time: 26_775_000 picoseconds. - Weight::from_parts(27_667_000, 3642) + // Minimum execution time: 27_850_000 picoseconds. + Weight::from_parts(28_821_000, 3642) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:0) - /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ParentChildBounties (r:1 w:0) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) fn award_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `605` + // Measured: `572` // Estimated: `3642` - // Minimum execution time: 16_089_000 picoseconds. - Weight::from_parts(16_909_000, 3642) + // Minimum execution time: 19_164_000 picoseconds. + Weight::from_parts(20_136_000, 3642) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:3 w:3) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1) - /// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `Bounties::BountyDescriptions` (r:0 w:1) - /// Proof: `Bounties::BountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: System Account (r:3 w:3) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: Bounties BountyDescriptions (r:0 w:1) + /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn claim_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `969` + // Measured: `936` // Estimated: `8799` - // Minimum execution time: 104_973_000 picoseconds. - Weight::from_parts(107_696_000, 8799) + // Minimum execution time: 120_235_000 picoseconds. + Weight::from_parts(121_673_000, 8799) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:0) - /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Bounties::BountyDescriptions` (r:0 w:1) - /// Proof: `Bounties::BountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ParentChildBounties (r:1 w:0) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Bounties BountyDescriptions (r:0 w:1) + /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn close_bounty_proposed() -> Weight { // Proof Size summary in bytes: - // Measured: `649` + // Measured: `616` // Estimated: `3642` - // Minimum execution time: 30_702_000 picoseconds. - Weight::from_parts(32_615_000, 3642) + // Minimum execution time: 35_713_000 picoseconds. + Weight::from_parts(37_174_000, 3642) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:0) - /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Bounties::BountyDescriptions` (r:0 w:1) - /// Proof: `Bounties::BountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ParentChildBounties (r:1 w:0) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Bounties BountyDescriptions (r:0 w:1) + /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn close_bounty_active() -> Weight { // Proof Size summary in bytes: - // Measured: `885` + // Measured: `852` // Estimated: `6196` - // Minimum execution time: 72_055_000 picoseconds. - Weight::from_parts(73_900_000, 6196) + // Minimum execution time: 81_037_000 picoseconds. + Weight::from_parts(83_294_000, 6196) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) fn extend_bounty_expiry() -> Weight { // Proof Size summary in bytes: - // Measured: `457` + // Measured: `424` // Estimated: `3642` - // Minimum execution time: 12_057_000 picoseconds. - Weight::from_parts(12_744_000, 3642) + // Minimum execution time: 15_348_000 picoseconds. + Weight::from_parts(15_776_000, 3642) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Bounties::BountyApprovals` (r:1 w:1) - /// Proof: `Bounties::BountyApprovals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) - /// Storage: `Bounties::Bounties` (r:100 w:100) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:200 w:200) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Bounties BountyApprovals (r:1 w:1) + /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + /// Storage: Bounties Bounties (r:100 w:100) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: System Account (r:200 w:200) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `b` is `[0, 100]`. fn spend_funds(b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `37 + b * (297 ±0)` + // Measured: `4 + b * (297 ±0)` // Estimated: `1887 + b * (5206 ±0)` - // Minimum execution time: 3_489_000 picoseconds. - Weight::from_parts(8_384_129, 1887) - // Standard Error: 18_066 - .saturating_add(Weight::from_parts(31_612_331, 0).saturating_mul(b.into())) + // Minimum execution time: 5_082_000 picoseconds. + Weight::from_parts(5_126_000, 1887) + // Standard Error: 21_949 + .saturating_add(Weight::from_parts(42_635_308, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -235,168 +236,168 @@ impl WeightInfo for SubstrateWeight { } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Bounties::BountyCount` (r:1 w:1) - /// Proof: `Bounties::BountyCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Bounties::BountyDescriptions` (r:0 w:1) - /// Proof: `Bounties::BountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) - /// Storage: `Bounties::Bounties` (r:0 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: Bounties BountyCount (r:1 w:1) + /// Proof: Bounties BountyCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Bounties BountyDescriptions (r:0 w:1) + /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) + /// Storage: Bounties Bounties (r:0 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) /// The range of component `d` is `[0, 300]`. fn propose_bounty(d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `309` + // Measured: `276` // Estimated: `3593` - // Minimum execution time: 24_286_000 picoseconds. - Weight::from_parts(25_657_314, 3593) - // Standard Error: 215 - .saturating_add(Weight::from_parts(1_116, 0).saturating_mul(d.into())) + // Minimum execution time: 29_384_000 picoseconds. + Weight::from_parts(30_820_018, 3593) + // Standard Error: 298 + .saturating_add(Weight::from_parts(2_920, 0).saturating_mul(d.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `Bounties::BountyApprovals` (r:1 w:1) - /// Proof: `Bounties::BountyApprovals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: Bounties BountyApprovals (r:1 w:1) + /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) fn approve_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `401` + // Measured: `368` // Estimated: `3642` - // Minimum execution time: 12_526_000 picoseconds. - Weight::from_parts(13_373_000, 3642) + // Minimum execution time: 10_873_000 picoseconds. + Weight::from_parts(11_421_000, 3642) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) fn propose_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `421` + // Measured: `388` // Estimated: `3642` - // Minimum execution time: 11_807_000 picoseconds. - Weight::from_parts(12_340_000, 3642) + // Minimum execution time: 9_181_000 picoseconds. + Weight::from_parts(9_726_000, 3642) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn unassign_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `597` + // Measured: `564` // Estimated: `3642` - // Minimum execution time: 27_183_000 picoseconds. - Weight::from_parts(28_250_000, 3642) + // Minimum execution time: 30_257_000 picoseconds. + Weight::from_parts(30_751_000, 3642) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn accept_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `593` + // Measured: `560` // Estimated: `3642` - // Minimum execution time: 26_775_000 picoseconds. - Weight::from_parts(27_667_000, 3642) + // Minimum execution time: 27_850_000 picoseconds. + Weight::from_parts(28_821_000, 3642) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:0) - /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ParentChildBounties (r:1 w:0) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) fn award_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `605` + // Measured: `572` // Estimated: `3642` - // Minimum execution time: 16_089_000 picoseconds. - Weight::from_parts(16_909_000, 3642) + // Minimum execution time: 19_164_000 picoseconds. + Weight::from_parts(20_136_000, 3642) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:3 w:3) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1) - /// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `Bounties::BountyDescriptions` (r:0 w:1) - /// Proof: `Bounties::BountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: System Account (r:3 w:3) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: Bounties BountyDescriptions (r:0 w:1) + /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn claim_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `969` + // Measured: `936` // Estimated: `8799` - // Minimum execution time: 104_973_000 picoseconds. - Weight::from_parts(107_696_000, 8799) + // Minimum execution time: 120_235_000 picoseconds. + Weight::from_parts(121_673_000, 8799) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:0) - /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Bounties::BountyDescriptions` (r:0 w:1) - /// Proof: `Bounties::BountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ParentChildBounties (r:1 w:0) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Bounties BountyDescriptions (r:0 w:1) + /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn close_bounty_proposed() -> Weight { // Proof Size summary in bytes: - // Measured: `649` + // Measured: `616` // Estimated: `3642` - // Minimum execution time: 30_702_000 picoseconds. - Weight::from_parts(32_615_000, 3642) + // Minimum execution time: 35_713_000 picoseconds. + Weight::from_parts(37_174_000, 3642) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:0) - /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Bounties::BountyDescriptions` (r:0 w:1) - /// Proof: `Bounties::BountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ParentChildBounties (r:1 w:0) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Bounties BountyDescriptions (r:0 w:1) + /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn close_bounty_active() -> Weight { // Proof Size summary in bytes: - // Measured: `885` + // Measured: `852` // Estimated: `6196` - // Minimum execution time: 72_055_000 picoseconds. - Weight::from_parts(73_900_000, 6196) + // Minimum execution time: 81_037_000 picoseconds. + Weight::from_parts(83_294_000, 6196) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:1) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:1) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) fn extend_bounty_expiry() -> Weight { // Proof Size summary in bytes: - // Measured: `457` + // Measured: `424` // Estimated: `3642` - // Minimum execution time: 12_057_000 picoseconds. - Weight::from_parts(12_744_000, 3642) + // Minimum execution time: 15_348_000 picoseconds. + Weight::from_parts(15_776_000, 3642) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Bounties::BountyApprovals` (r:1 w:1) - /// Proof: `Bounties::BountyApprovals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) - /// Storage: `Bounties::Bounties` (r:100 w:100) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:200 w:200) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Bounties BountyApprovals (r:1 w:1) + /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + /// Storage: Bounties Bounties (r:100 w:100) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: System Account (r:200 w:200) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `b` is `[0, 100]`. fn spend_funds(b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `37 + b * (297 ±0)` + // Measured: `4 + b * (297 ±0)` // Estimated: `1887 + b * (5206 ±0)` - // Minimum execution time: 3_489_000 picoseconds. - Weight::from_parts(8_384_129, 1887) - // Standard Error: 18_066 - .saturating_add(Weight::from_parts(31_612_331, 0).saturating_mul(b.into())) + // Minimum execution time: 5_082_000 picoseconds. + Weight::from_parts(5_126_000, 1887) + // Standard Error: 21_949 + .saturating_add(Weight::from_parts(42_635_308, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(b.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) diff --git a/substrate/frame/broker/src/weights.rs b/substrate/frame/broker/src/weights.rs index 133ea63e35f..a8f50eeee6e 100644 --- a/substrate/frame/broker/src/weights.rs +++ b/substrate/frame/broker/src/weights.rs @@ -17,28 +17,26 @@ //! Autogenerated weights for `pallet_broker` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-pzhd7p6z-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/production/substrate-node +// target/production/substrate-node // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_broker -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/broker/src/weights.rs +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_broker +// --chain=dev // --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/broker/src/weights.rs // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -89,8 +87,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_701_000 picoseconds. - Weight::from_parts(2_902_000, 0) + // Minimum execution time: 3_040_000 picoseconds. + Weight::from_parts(3_344_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Broker::Reservations` (r:1 w:1) @@ -99,8 +97,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `5016` // Estimated: `7496` - // Minimum execution time: 18_056_000 picoseconds. - Weight::from_parts(19_093_000, 7496) + // Minimum execution time: 21_259_000 picoseconds. + Weight::from_parts(22_110_000, 7496) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -110,8 +108,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `6218` // Estimated: `7496` - // Minimum execution time: 17_233_000 picoseconds. - Weight::from_parts(17_788_000, 7496) + // Minimum execution time: 20_330_000 picoseconds. + Weight::from_parts(20_826_000, 7496) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -121,8 +119,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `239` // Estimated: `1526` - // Minimum execution time: 9_740_000 picoseconds. - Weight::from_parts(10_504_000, 1526) + // Minimum execution time: 13_411_000 picoseconds. + Weight::from_parts(13_960_000, 1526) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -141,12 +139,14 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Broker::Workplan` (r:0 w:10) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. - fn start_sales(_n: u32, ) -> Weight { + fn start_sales(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `6330` // Estimated: `8499` - // Minimum execution time: 49_728_000 picoseconds. - Weight::from_parts(52_765_861, 8499) + // Minimum execution time: 57_770_000 picoseconds. + Weight::from_parts(61_047_512, 8499) + // Standard Error: 165 + .saturating_add(Weight::from_parts(3, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(16_u64)) } @@ -162,10 +162,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) fn purchase() -> Weight { // Proof Size summary in bytes: - // Measured: `635` - // Estimated: `2120` - // Minimum execution time: 41_986_000 picoseconds. - Weight::from_parts(43_465_000, 2120) + // Measured: `568` + // Estimated: `2053` + // Minimum execution time: 51_196_000 picoseconds. + Weight::from_parts(52_382_000, 2053) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -185,10 +185,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) fn renew() -> Weight { // Proof Size summary in bytes: - // Measured: `753` + // Measured: `686` // Estimated: `4698` - // Minimum execution time: 61_779_000 picoseconds. - Weight::from_parts(62_563_000, 4698) + // Minimum execution time: 71_636_000 picoseconds. + Weight::from_parts(73_679_000, 4698) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -198,8 +198,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3550` - // Minimum execution time: 16_962_000 picoseconds. - Weight::from_parts(17_733_000, 3550) + // Minimum execution time: 19_182_000 picoseconds. + Weight::from_parts(19_775_000, 3550) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -209,21 +209,21 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3550` - // Minimum execution time: 18_380_000 picoseconds. - Weight::from_parts(19_105_000, 3550) + // Minimum execution time: 20_688_000 picoseconds. + Weight::from_parts(21_557_000, 3550) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Broker::Regions` (r:1 w:3) + /// Storage: `Broker::Regions` (r:1 w:2) /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) fn interlace() -> Weight { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3550` - // Minimum execution time: 20_115_000 picoseconds. - Weight::from_parts(20_741_000, 3550) + // Minimum execution time: 21_190_000 picoseconds. + Weight::from_parts(22_215_000, 3550) .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Broker::Configuration` (r:1 w:0) /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) @@ -237,8 +237,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `740` // Estimated: `4681` - // Minimum execution time: 31_339_000 picoseconds. - Weight::from_parts(32_639_000, 4681) + // Minimum execution time: 34_591_000 picoseconds. + Weight::from_parts(36_227_000, 4681) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -256,8 +256,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `775` // Estimated: `5996` - // Minimum execution time: 37_542_000 picoseconds. - Weight::from_parts(38_521_000, 5996) + // Minimum execution time: 40_346_000 picoseconds. + Weight::from_parts(41_951_000, 5996) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -272,10 +272,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `859` // Estimated: `6196 + m * (2520 ±0)` - // Minimum execution time: 66_176_000 picoseconds. - Weight::from_parts(68_356_745, 6196) - // Standard Error: 68_008 - .saturating_add(Weight::from_parts(1_558_419, 0).saturating_mul(m.into())) + // Minimum execution time: 75_734_000 picoseconds. + Weight::from_parts(78_168_395, 6196) + // Standard Error: 63_180 + .saturating_add(Weight::from_parts(1_076_259, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(T::DbWeight::get().writes(5_u64)) @@ -287,8 +287,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 41_130_000 picoseconds. - Weight::from_parts(41_914_000, 3593) + // Minimum execution time: 46_383_000 picoseconds. + Weight::from_parts(47_405_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -300,8 +300,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `603` // Estimated: `3550` - // Minimum execution time: 31_042_000 picoseconds. - Weight::from_parts(34_087_000, 3550) + // Minimum execution time: 30_994_000 picoseconds. + Weight::from_parts(31_979_000, 3550) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -315,8 +315,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `601` // Estimated: `3533` - // Minimum execution time: 39_116_000 picoseconds. - Weight::from_parts(39_990_000, 3533) + // Minimum execution time: 37_584_000 picoseconds. + Weight::from_parts(44_010_000, 3533) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -330,10 +330,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn drop_history() -> Weight { // Proof Size summary in bytes: - // Measured: `995` + // Measured: `830` // Estimated: `3593` - // Minimum execution time: 47_547_000 picoseconds. - Weight::from_parts(50_274_000, 3593) + // Minimum execution time: 45_266_000 picoseconds. + Weight::from_parts(48_000_000, 3593) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -343,32 +343,34 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Broker::AllowedRenewals` (`max_values`: None, `max_size`: Some(1233), added: 3708, mode: `MaxEncodedLen`) fn drop_renewal() -> Weight { // Proof Size summary in bytes: - // Measured: `661` + // Measured: `525` // Estimated: `4698` - // Minimum execution time: 26_707_000 picoseconds. - Weight::from_parts(27_217_000, 4698) + // Minimum execution time: 25_365_000 picoseconds. + Weight::from_parts(26_920_000, 4698) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// The range of component `n` is `[0, 1000]`. - fn request_core_count(_n: u32, ) -> Weight { + fn request_core_count(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_651_000 picoseconds. - Weight::from_parts(5_231_385, 0) + // Minimum execution time: 6_519_000 picoseconds. + Weight::from_parts(7_098_698, 0) + // Standard Error: 20 + .saturating_add(Weight::from_parts(8, 0).saturating_mul(n.into())) } - /// Storage: `Broker::CoreCountInbox` (r:1 w:1) - /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) /// The range of component `n` is `[0, 1000]`. fn process_core_count(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `404` - // Estimated: `1487` - // Minimum execution time: 6_806_000 picoseconds. - Weight::from_parts(7_264_002, 1487) - // Standard Error: 21 - .saturating_add(Weight::from_parts(31, 0).saturating_mul(n.into())) + // Measured: `98` + // Estimated: `3563` + // Minimum execution time: 7_608_000 picoseconds. + Weight::from_parts(8_157_815, 3563) + // Standard Error: 26 + .saturating_add(Weight::from_parts(48, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -384,10 +386,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn process_revenue() -> Weight { // Proof Size summary in bytes: - // Measured: `972` - // Estimated: `4437` - // Minimum execution time: 48_297_000 picoseconds. - Weight::from_parts(49_613_000, 4437) + // Measured: `905` + // Estimated: `4370` + // Minimum execution time: 59_993_000 picoseconds. + Weight::from_parts(61_752_000, 4370) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -406,10 +408,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `6281` // Estimated: `8499` - // Minimum execution time: 36_715_000 picoseconds. - Weight::from_parts(38_580_380, 8499) - // Standard Error: 91 - .saturating_add(Weight::from_parts(1_163, 0).saturating_mul(n.into())) + // Minimum execution time: 41_863_000 picoseconds. + Weight::from_parts(44_033_031, 8499) + // Standard Error: 116 + .saturating_add(Weight::from_parts(764, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(15_u64)) } @@ -421,8 +423,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3493` - // Minimum execution time: 7_564_000 picoseconds. - Weight::from_parts(7_932_000, 3493) + // Minimum execution time: 9_588_000 picoseconds. + Weight::from_parts(9_925_000, 3493) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -434,8 +436,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1423` // Estimated: `4681` - // Minimum execution time: 17_082_000 picoseconds. - Weight::from_parts(17_662_000, 4681) + // Minimum execution time: 19_308_000 picoseconds. + Weight::from_parts(20_482_000, 4681) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -443,35 +445,28 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 175_000 picoseconds. - Weight::from_parts(223_000, 0) + // Minimum execution time: 147_000 picoseconds. + Weight::from_parts(184_000, 0) } - /// Storage: `Broker::CoreCountInbox` (r:0 w:1) - /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) fn notify_core_count() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_432_000 picoseconds. - Weight::from_parts(2_536_000, 0) - .saturating_add(T::DbWeight::get().writes(1_u64)) + T::DbWeight::get().reads_writes(1, 1) } /// Storage: `Broker::Status` (r:1 w:1) /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) /// Storage: `Broker::Configuration` (r:1 w:0) /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) - /// Storage: `Broker::CoreCountInbox` (r:1 w:0) - /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) /// Storage: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) /// Proof: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) fn do_tick_base() -> Weight { // Proof Size summary in bytes: - // Measured: `603` - // Estimated: `4068` - // Minimum execution time: 13_080_000 picoseconds. - Weight::from_parts(13_937_000, 4068) + // Measured: `699` + // Estimated: `4164` + // Minimum execution time: 19_824_000 picoseconds. + Weight::from_parts(20_983_000, 4164) .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } } @@ -483,8 +478,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_701_000 picoseconds. - Weight::from_parts(2_902_000, 0) + // Minimum execution time: 3_040_000 picoseconds. + Weight::from_parts(3_344_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Broker::Reservations` (r:1 w:1) @@ -493,8 +488,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `5016` // Estimated: `7496` - // Minimum execution time: 18_056_000 picoseconds. - Weight::from_parts(19_093_000, 7496) + // Minimum execution time: 21_259_000 picoseconds. + Weight::from_parts(22_110_000, 7496) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -504,8 +499,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `6218` // Estimated: `7496` - // Minimum execution time: 17_233_000 picoseconds. - Weight::from_parts(17_788_000, 7496) + // Minimum execution time: 20_330_000 picoseconds. + Weight::from_parts(20_826_000, 7496) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -515,8 +510,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `239` // Estimated: `1526` - // Minimum execution time: 9_740_000 picoseconds. - Weight::from_parts(10_504_000, 1526) + // Minimum execution time: 13_411_000 picoseconds. + Weight::from_parts(13_960_000, 1526) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -535,12 +530,14 @@ impl WeightInfo for () { /// Storage: `Broker::Workplan` (r:0 w:10) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. - fn start_sales(_n: u32, ) -> Weight { + fn start_sales(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `6330` // Estimated: `8499` - // Minimum execution time: 49_728_000 picoseconds. - Weight::from_parts(52_765_861, 8499) + // Minimum execution time: 57_770_000 picoseconds. + Weight::from_parts(61_047_512, 8499) + // Standard Error: 165 + .saturating_add(Weight::from_parts(3, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(16_u64)) } @@ -556,10 +553,10 @@ impl WeightInfo for () { /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) fn purchase() -> Weight { // Proof Size summary in bytes: - // Measured: `635` - // Estimated: `2120` - // Minimum execution time: 41_986_000 picoseconds. - Weight::from_parts(43_465_000, 2120) + // Measured: `568` + // Estimated: `2053` + // Minimum execution time: 51_196_000 picoseconds. + Weight::from_parts(52_382_000, 2053) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -579,10 +576,10 @@ impl WeightInfo for () { /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) fn renew() -> Weight { // Proof Size summary in bytes: - // Measured: `753` + // Measured: `686` // Estimated: `4698` - // Minimum execution time: 61_779_000 picoseconds. - Weight::from_parts(62_563_000, 4698) + // Minimum execution time: 71_636_000 picoseconds. + Weight::from_parts(73_679_000, 4698) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -592,8 +589,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3550` - // Minimum execution time: 16_962_000 picoseconds. - Weight::from_parts(17_733_000, 3550) + // Minimum execution time: 19_182_000 picoseconds. + Weight::from_parts(19_775_000, 3550) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -603,21 +600,21 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3550` - // Minimum execution time: 18_380_000 picoseconds. - Weight::from_parts(19_105_000, 3550) + // Minimum execution time: 20_688_000 picoseconds. + Weight::from_parts(21_557_000, 3550) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Broker::Regions` (r:1 w:3) + /// Storage: `Broker::Regions` (r:1 w:2) /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) fn interlace() -> Weight { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3550` - // Minimum execution time: 20_115_000 picoseconds. - Weight::from_parts(20_741_000, 3550) + // Minimum execution time: 21_190_000 picoseconds. + Weight::from_parts(22_215_000, 3550) .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Broker::Configuration` (r:1 w:0) /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) @@ -631,8 +628,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `740` // Estimated: `4681` - // Minimum execution time: 31_339_000 picoseconds. - Weight::from_parts(32_639_000, 4681) + // Minimum execution time: 34_591_000 picoseconds. + Weight::from_parts(36_227_000, 4681) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -650,8 +647,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `775` // Estimated: `5996` - // Minimum execution time: 37_542_000 picoseconds. - Weight::from_parts(38_521_000, 5996) + // Minimum execution time: 40_346_000 picoseconds. + Weight::from_parts(41_951_000, 5996) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -666,10 +663,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `859` // Estimated: `6196 + m * (2520 ±0)` - // Minimum execution time: 66_176_000 picoseconds. - Weight::from_parts(68_356_745, 6196) - // Standard Error: 68_008 - .saturating_add(Weight::from_parts(1_558_419, 0).saturating_mul(m.into())) + // Minimum execution time: 75_734_000 picoseconds. + Weight::from_parts(78_168_395, 6196) + // Standard Error: 63_180 + .saturating_add(Weight::from_parts(1_076_259, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(RocksDbWeight::get().writes(5_u64)) @@ -681,8 +678,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 41_130_000 picoseconds. - Weight::from_parts(41_914_000, 3593) + // Minimum execution time: 46_383_000 picoseconds. + Weight::from_parts(47_405_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -694,8 +691,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `603` // Estimated: `3550` - // Minimum execution time: 31_042_000 picoseconds. - Weight::from_parts(34_087_000, 3550) + // Minimum execution time: 30_994_000 picoseconds. + Weight::from_parts(31_979_000, 3550) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -709,8 +706,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `601` // Estimated: `3533` - // Minimum execution time: 39_116_000 picoseconds. - Weight::from_parts(39_990_000, 3533) + // Minimum execution time: 37_584_000 picoseconds. + Weight::from_parts(44_010_000, 3533) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -724,10 +721,10 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn drop_history() -> Weight { // Proof Size summary in bytes: - // Measured: `995` + // Measured: `830` // Estimated: `3593` - // Minimum execution time: 47_547_000 picoseconds. - Weight::from_parts(50_274_000, 3593) + // Minimum execution time: 45_266_000 picoseconds. + Weight::from_parts(48_000_000, 3593) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -737,32 +734,34 @@ impl WeightInfo for () { /// Proof: `Broker::AllowedRenewals` (`max_values`: None, `max_size`: Some(1233), added: 3708, mode: `MaxEncodedLen`) fn drop_renewal() -> Weight { // Proof Size summary in bytes: - // Measured: `661` + // Measured: `525` // Estimated: `4698` - // Minimum execution time: 26_707_000 picoseconds. - Weight::from_parts(27_217_000, 4698) + // Minimum execution time: 25_365_000 picoseconds. + Weight::from_parts(26_920_000, 4698) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// The range of component `n` is `[0, 1000]`. - fn request_core_count(_n: u32, ) -> Weight { + fn request_core_count(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_651_000 picoseconds. - Weight::from_parts(5_231_385, 0) + // Minimum execution time: 6_519_000 picoseconds. + Weight::from_parts(7_098_698, 0) + // Standard Error: 20 + .saturating_add(Weight::from_parts(8, 0).saturating_mul(n.into())) } - /// Storage: `Broker::CoreCountInbox` (r:1 w:1) - /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) /// The range of component `n` is `[0, 1000]`. fn process_core_count(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `404` - // Estimated: `1487` - // Minimum execution time: 6_806_000 picoseconds. - Weight::from_parts(7_264_002, 1487) - // Standard Error: 21 - .saturating_add(Weight::from_parts(31, 0).saturating_mul(n.into())) + // Measured: `98` + // Estimated: `3563` + // Minimum execution time: 7_608_000 picoseconds. + Weight::from_parts(8_157_815, 3563) + // Standard Error: 26 + .saturating_add(Weight::from_parts(48, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -778,10 +777,10 @@ impl WeightInfo for () { /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn process_revenue() -> Weight { // Proof Size summary in bytes: - // Measured: `972` - // Estimated: `4437` - // Minimum execution time: 48_297_000 picoseconds. - Weight::from_parts(49_613_000, 4437) + // Measured: `905` + // Estimated: `4370` + // Minimum execution time: 59_993_000 picoseconds. + Weight::from_parts(61_752_000, 4370) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -800,10 +799,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `6281` // Estimated: `8499` - // Minimum execution time: 36_715_000 picoseconds. - Weight::from_parts(38_580_380, 8499) - // Standard Error: 91 - .saturating_add(Weight::from_parts(1_163, 0).saturating_mul(n.into())) + // Minimum execution time: 41_863_000 picoseconds. + Weight::from_parts(44_033_031, 8499) + // Standard Error: 116 + .saturating_add(Weight::from_parts(764, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(15_u64)) } @@ -815,8 +814,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3493` - // Minimum execution time: 7_564_000 picoseconds. - Weight::from_parts(7_932_000, 3493) + // Minimum execution time: 9_588_000 picoseconds. + Weight::from_parts(9_925_000, 3493) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -828,8 +827,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1423` // Estimated: `4681` - // Minimum execution time: 17_082_000 picoseconds. - Weight::from_parts(17_662_000, 4681) + // Minimum execution time: 19_308_000 picoseconds. + Weight::from_parts(20_482_000, 4681) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -837,34 +836,28 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 175_000 picoseconds. - Weight::from_parts(223_000, 0) + // Minimum execution time: 147_000 picoseconds. + Weight::from_parts(184_000, 0) } - /// Storage: `Broker::CoreCountInbox` (r:0 w:1) - /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) fn notify_core_count() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 2_432_000 picoseconds. - Weight::from_parts(2_536_000, 0) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + RocksDbWeight::get().reads(1) + .saturating_add(RocksDbWeight::get().writes(1)) } /// Storage: `Broker::Status` (r:1 w:1) /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) /// Storage: `Broker::Configuration` (r:1 w:0) /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) - /// Storage: `Broker::CoreCountInbox` (r:1 w:0) - /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) /// Storage: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) /// Proof: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) fn do_tick_base() -> Weight { // Proof Size summary in bytes: - // Measured: `603` - // Estimated: `4068` - // Minimum execution time: 13_080_000 picoseconds. - Weight::from_parts(13_937_000, 4068) + // Measured: `699` + // Estimated: `4164` + // Minimum execution time: 19_824_000 picoseconds. + Weight::from_parts(20_983_000, 4164) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } } diff --git a/substrate/frame/child-bounties/src/weights.rs b/substrate/frame/child-bounties/src/weights.rs index 6427517b45b..e4c1f238e88 100644 --- a/substrate/frame/child-bounties/src/weights.rs +++ b/substrate/frame/child-bounties/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_child_bounties` +//! Autogenerated weights for pallet_child_bounties //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/child-bounties/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/child-bounties/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_child_bounties`. +/// Weight functions needed for pallet_child_bounties. pub trait WeightInfo { fn add_child_bounty(d: u32, ) -> Weight; fn propose_curator() -> Weight; @@ -61,288 +62,288 @@ pub trait WeightInfo { fn close_child_bounty_active() -> Weight; } -/// Weights for `pallet_child_bounties` using the Substrate node and recommended hardware. +/// Weights for pallet_child_bounties using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) - /// Storage: `Bounties::Bounties` (r:1 w:0) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBountyCount` (r:1 w:1) - /// Proof: `ChildBounties::ChildBountyCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBountyDescriptions` (r:0 w:1) - /// Proof: `ChildBounties::ChildBountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBounties` (r:0 w:1) - /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) + /// Storage: ChildBounties ParentChildBounties (r:1 w:1) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBountyCount (r:1 w:1) + /// Proof: ChildBounties ChildBountyCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) + /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBounties (r:0 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) /// The range of component `d` is `[0, 300]`. fn add_child_bounty(_d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `745` + // Measured: `712` // Estimated: `6196` - // Minimum execution time: 60_674_000 picoseconds. - Weight::from_parts(63_477_428, 6196) + // Minimum execution time: 69_805_000 picoseconds. + Weight::from_parts(73_216_717, 6196) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:0) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1) - /// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) fn propose_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `799` + // Measured: `766` // Estimated: `3642` - // Minimum execution time: 17_754_000 picoseconds. - Weight::from_parts(18_655_000, 3642) + // Minimum execution time: 18_190_000 picoseconds. + Weight::from_parts(18_932_000, 3642) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:0) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn accept_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `945` + // Measured: `912` // Estimated: `3642` - // Minimum execution time: 31_580_000 picoseconds. - Weight::from_parts(32_499_000, 3642) + // Minimum execution time: 35_035_000 picoseconds. + Weight::from_parts(35_975_000, 3642) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) - /// Storage: `Bounties::Bounties` (r:1 w:0) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn unassign_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `945` + // Measured: `912` // Estimated: `3642` - // Minimum execution time: 33_536_000 picoseconds. - Weight::from_parts(34_102_000, 3642) + // Minimum execution time: 37_636_000 picoseconds. + Weight::from_parts(38_610_000, 3642) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:0) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) fn award_child_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `842` + // Measured: `809` // Estimated: `3642` - // Minimum execution time: 18_295_000 picoseconds. - Weight::from_parts(19_496_000, 3642) + // Minimum execution time: 22_457_000 picoseconds. + Weight::from_parts(23_691_000, 3642) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:3 w:3) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBountyDescriptions` (r:0 w:1) - /// Proof: `ChildBounties::ChildBountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// Storage: System Account (r:3 w:3) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ChildBounties ParentChildBounties (r:1 w:1) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) + /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn claim_child_bounty() -> Weight { // Proof Size summary in bytes: // Measured: `682` // Estimated: `8799` - // Minimum execution time: 102_367_000 picoseconds. - Weight::from_parts(104_352_000, 8799) + // Minimum execution time: 118_272_000 picoseconds. + Weight::from_parts(121_646_000, 8799) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:0) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1) - /// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBountyDescriptions` (r:0 w:1) - /// Proof: `ChildBounties::ChildBountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: ChildBounties ParentChildBounties (r:1 w:1) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) + /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn close_child_bounty_added() -> Weight { // Proof Size summary in bytes: - // Measured: `1045` + // Measured: `1012` // Estimated: `6196` - // Minimum execution time: 69_051_000 picoseconds. - Weight::from_parts(71_297_000, 6196) + // Minimum execution time: 75_717_000 picoseconds. + Weight::from_parts(77_837_000, 6196) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:0) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:3 w:3) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1) - /// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBountyDescriptions` (r:0 w:1) - /// Proof: `ChildBounties::ChildBountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// Storage: System Account (r:3 w:3) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: ChildBounties ParentChildBounties (r:1 w:1) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) + /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn close_child_bounty_active() -> Weight { // Proof Size summary in bytes: - // Measured: `1232` + // Measured: `1199` // Estimated: `8799` - // Minimum execution time: 84_053_000 picoseconds. - Weight::from_parts(86_072_000, 8799) + // Minimum execution time: 94_215_000 picoseconds. + Weight::from_parts(97_017_000, 8799) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) - /// Storage: `Bounties::Bounties` (r:1 w:0) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBountyCount` (r:1 w:1) - /// Proof: `ChildBounties::ChildBountyCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBountyDescriptions` (r:0 w:1) - /// Proof: `ChildBounties::ChildBountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBounties` (r:0 w:1) - /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) + /// Storage: ChildBounties ParentChildBounties (r:1 w:1) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBountyCount (r:1 w:1) + /// Proof: ChildBounties ChildBountyCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) + /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBounties (r:0 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) /// The range of component `d` is `[0, 300]`. fn add_child_bounty(_d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `745` + // Measured: `712` // Estimated: `6196` - // Minimum execution time: 60_674_000 picoseconds. - Weight::from_parts(63_477_428, 6196) + // Minimum execution time: 69_805_000 picoseconds. + Weight::from_parts(73_216_717, 6196) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:0) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1) - /// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) fn propose_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `799` + // Measured: `766` // Estimated: `3642` - // Minimum execution time: 17_754_000 picoseconds. - Weight::from_parts(18_655_000, 3642) + // Minimum execution time: 18_190_000 picoseconds. + Weight::from_parts(18_932_000, 3642) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:0) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn accept_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `945` + // Measured: `912` // Estimated: `3642` - // Minimum execution time: 31_580_000 picoseconds. - Weight::from_parts(32_499_000, 3642) + // Minimum execution time: 35_035_000 picoseconds. + Weight::from_parts(35_975_000, 3642) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) - /// Storage: `Bounties::Bounties` (r:1 w:0) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn unassign_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `945` + // Measured: `912` // Estimated: `3642` - // Minimum execution time: 33_536_000 picoseconds. - Weight::from_parts(34_102_000, 3642) + // Minimum execution time: 37_636_000 picoseconds. + Weight::from_parts(38_610_000, 3642) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:0) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) fn award_child_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `842` + // Measured: `809` // Estimated: `3642` - // Minimum execution time: 18_295_000 picoseconds. - Weight::from_parts(19_496_000, 3642) + // Minimum execution time: 22_457_000 picoseconds. + Weight::from_parts(23_691_000, 3642) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:3 w:3) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBountyDescriptions` (r:0 w:1) - /// Proof: `ChildBounties::ChildBountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// Storage: System Account (r:3 w:3) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ChildBounties ParentChildBounties (r:1 w:1) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) + /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn claim_child_bounty() -> Weight { // Proof Size summary in bytes: // Measured: `682` // Estimated: `8799` - // Minimum execution time: 102_367_000 picoseconds. - Weight::from_parts(104_352_000, 8799) + // Minimum execution time: 118_272_000 picoseconds. + Weight::from_parts(121_646_000, 8799) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:0) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1) - /// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBountyDescriptions` (r:0 w:1) - /// Proof: `ChildBounties::ChildBountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: ChildBounties ParentChildBounties (r:1 w:1) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) + /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn close_child_bounty_added() -> Weight { // Proof Size summary in bytes: - // Measured: `1045` + // Measured: `1012` // Estimated: `6196` - // Minimum execution time: 69_051_000 picoseconds. - Weight::from_parts(71_297_000, 6196) + // Minimum execution time: 75_717_000 picoseconds. + Weight::from_parts(77_837_000, 6196) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } - /// Storage: `Bounties::Bounties` (r:1 w:0) - /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:3 w:3) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1) - /// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1) - /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) - /// Storage: `ChildBounties::ChildBountyDescriptions` (r:0 w:1) - /// Proof: `ChildBounties::ChildBountyDescriptions` (`max_values`: None, `max_size`: Some(314), added: 2789, mode: `MaxEncodedLen`) + /// Storage: Bounties Bounties (r:1 w:0) + /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBounties (r:1 w:1) + /// Proof: ChildBounties ChildBounties (max_values: None, max_size: Some(145), added: 2620, mode: MaxEncodedLen) + /// Storage: System Account (r:3 w:3) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildrenCuratorFees (r:1 w:1) + /// Proof: ChildBounties ChildrenCuratorFees (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: ChildBounties ParentChildBounties (r:1 w:1) + /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: ChildBounties ChildBountyDescriptions (r:0 w:1) + /// Proof: ChildBounties ChildBountyDescriptions (max_values: None, max_size: Some(314), added: 2789, mode: MaxEncodedLen) fn close_child_bounty_active() -> Weight { // Proof Size summary in bytes: - // Measured: `1232` + // Measured: `1199` // Estimated: `8799` - // Minimum execution time: 84_053_000 picoseconds. - Weight::from_parts(86_072_000, 8799) + // Minimum execution time: 94_215_000 picoseconds. + Weight::from_parts(97_017_000, 8799) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } diff --git a/substrate/frame/collective/src/tests.rs b/substrate/frame/collective/src/tests.rs index 92418794c5f..02c3377515c 100644 --- a/substrate/frame/collective/src/tests.rs +++ b/substrate/frame/collective/src/tests.rs @@ -29,7 +29,7 @@ use sp_core::H256; use sp_runtime::{testing::Header, traits::BlakeTwo256, BuildStorage}; pub type Block = sp_runtime::generic::Block; -pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( pub enum Test diff --git a/substrate/frame/collective/src/weights.rs b/substrate/frame/collective/src/weights.rs index 85744b4de9d..eece6a006b8 100644 --- a/substrate/frame/collective/src/weights.rs +++ b/substrate/frame/collective/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_collective` +//! Autogenerated weights for pallet_collective //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/collective/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/collective/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_collective`. +/// Weight functions needed for pallet_collective. pub trait WeightInfo { fn set_members(m: u32, n: u32, p: u32, ) -> Weight; fn execute(b: u32, m: u32, ) -> Weight; @@ -63,30 +64,30 @@ pub trait WeightInfo { fn disapprove_proposal(p: u32, ) -> Weight; } -/// Weights for `pallet_collective` using the Substrate node and recommended hardware. +/// Weights for pallet_collective using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Council::Members` (r:1 w:1) - /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Proposals` (r:1 w:0) - /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Voting` (r:100 w:100) - /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Council::Prime` (r:0 w:1) - /// Proof: `Council::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Council Members (r:1 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:100 w:100) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Prime (r:0 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[0, 100]`. /// The range of component `n` is `[0, 100]`. /// The range of component `p` is `[0, 100]`. fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + m * (3232 ±0) + p * (3190 ±0)` - // Estimated: `15894 + m * (1967 ±23) + p * (4332 ±23)` - // Minimum execution time: 15_559_000 picoseconds. - Weight::from_parts(15_870_000, 15894) - // Standard Error: 54_310 - .saturating_add(Weight::from_parts(4_117_753, 0).saturating_mul(m.into())) - // Standard Error: 54_310 - .saturating_add(Weight::from_parts(7_677_627, 0).saturating_mul(p.into())) + // Estimated: `15861 + m * (1967 ±24) + p * (4332 ±24)` + // Minimum execution time: 17_506_000 picoseconds. + Weight::from_parts(17_767_000, 15861) + // Standard Error: 60_220 + .saturating_add(Weight::from_parts(4_374_805, 0).saturating_mul(m.into())) + // Standard Error: 60_220 + .saturating_add(Weight::from_parts(8_398_316, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -94,261 +95,245 @@ impl WeightInfo for SubstrateWeight { .saturating_add(Weight::from_parts(0, 1967).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 4332).saturating_mul(p.into())) } - /// Storage: `Council::Members` (r:1 w:0) - /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[1, 100]`. fn execute(b: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `380 + m * (32 ±0)` - // Estimated: `3997 + m * (32 ±0)` - // Minimum execution time: 19_024_000 picoseconds. - Weight::from_parts(18_153_872, 3997) - // Standard Error: 46 - .saturating_add(Weight::from_parts(1_933, 0).saturating_mul(b.into())) - // Standard Error: 478 - .saturating_add(Weight::from_parts(18_872, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Measured: `202 + m * (32 ±0)` + // Estimated: `1688 + m * (32 ±0)` + // Minimum execution time: 16_203_000 picoseconds. + Weight::from_parts(15_348_267, 1688) + // Standard Error: 37 + .saturating_add(Weight::from_parts(1_766, 0).saturating_mul(b.into())) + // Standard Error: 382 + .saturating_add(Weight::from_parts(15_765, 0).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } - /// Storage: `Council::Members` (r:1 w:0) - /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::ProposalOf` (r:1 w:0) - /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:0) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[1, 100]`. fn propose_execute(b: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `380 + m * (32 ±0)` - // Estimated: `3997 + m * (32 ±0)` - // Minimum execution time: 20_895_000 picoseconds. - Weight::from_parts(20_081_761, 3997) - // Standard Error: 57 - .saturating_add(Weight::from_parts(1_982, 0).saturating_mul(b.into())) - // Standard Error: 594 - .saturating_add(Weight::from_parts(32_085, 0).saturating_mul(m.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) + // Measured: `202 + m * (32 ±0)` + // Estimated: `3668 + m * (32 ±0)` + // Minimum execution time: 18_642_000 picoseconds. + Weight::from_parts(17_708_609, 3668) + // Standard Error: 58 + .saturating_add(Weight::from_parts(2_285, 0).saturating_mul(b.into())) + // Standard Error: 598 + .saturating_add(Weight::from_parts(30_454, 0).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } - /// Storage: `Council::Members` (r:1 w:0) - /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::ProposalOf` (r:1 w:1) - /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Council::Proposals` (r:1 w:1) - /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::ProposalCount` (r:1 w:1) - /// Proof: `Council::ProposalCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Voting` (r:0 w:1) - /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalCount (r:1 w:1) + /// Proof Skipped: Council ProposalCount (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:0 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `525 + m * (32 ±0) + p * (36 ±0)` - // Estimated: `3917 + m * (33 ±0) + p * (36 ±0)` - // Minimum execution time: 22_068_000 picoseconds. - Weight::from_parts(19_639_088, 3917) - // Standard Error: 104 - .saturating_add(Weight::from_parts(3_896, 0).saturating_mul(b.into())) - // Standard Error: 1_095 - .saturating_add(Weight::from_parts(31_634, 0).saturating_mul(m.into())) - // Standard Error: 1_081 - .saturating_add(Weight::from_parts(178_702, 0).saturating_mul(p.into())) + // Measured: `492 + m * (32 ±0) + p * (36 ±0)` + // Estimated: `3884 + m * (33 ±0) + p * (36 ±0)` + // Minimum execution time: 27_067_000 picoseconds. + Weight::from_parts(25_456_964, 3884) + // Standard Error: 112 + .saturating_add(Weight::from_parts(3_773, 0).saturating_mul(b.into())) + // Standard Error: 1_177 + .saturating_add(Weight::from_parts(32_783, 0).saturating_mul(m.into())) + // Standard Error: 1_162 + .saturating_add(Weight::from_parts(194_388, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 33).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: `Council::Members` (r:1 w:0) - /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Voting` (r:1 w:1) - /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `974 + m * (64 ±0)` - // Estimated: `4438 + m * (64 ±0)` - // Minimum execution time: 22_395_000 picoseconds. - Weight::from_parts(23_025_217, 4438) - // Standard Error: 842 - .saturating_add(Weight::from_parts(58_102, 0).saturating_mul(m.into())) + // Measured: `941 + m * (64 ±0)` + // Estimated: `4405 + m * (64 ±0)` + // Minimum execution time: 26_055_000 picoseconds. + Weight::from_parts(27_251_907, 4405) + // Standard Error: 1_008 + .saturating_add(Weight::from_parts(65_947, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } - /// Storage: `Council::Voting` (r:1 w:1) - /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Council::Members` (r:1 w:0) - /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Proposals` (r:1 w:1) - /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::ProposalOf` (r:0 w:1) - /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:0 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `563 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `4008 + m * (65 ±0) + p * (36 ±0)` - // Minimum execution time: 24_179_000 picoseconds. - Weight::from_parts(23_846_394, 4008) - // Standard Error: 1_052 - .saturating_add(Weight::from_parts(40_418, 0).saturating_mul(m.into())) - // Standard Error: 1_026 - .saturating_add(Weight::from_parts(171_653, 0).saturating_mul(p.into())) + // Measured: `530 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `3975 + m * (65 ±0) + p * (36 ±0)` + // Minimum execution time: 28_363_000 picoseconds. + Weight::from_parts(28_733_464, 3975) + // Standard Error: 1_275 + .saturating_add(Weight::from_parts(43_236, 0).saturating_mul(m.into())) + // Standard Error: 1_244 + .saturating_add(Weight::from_parts(180_187, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 65).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: `Council::Voting` (r:1 w:1) - /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Council::Members` (r:1 w:0) - /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::ProposalOf` (r:1 w:1) - /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) - /// Storage: `Council::Proposals` (r:1 w:1) - /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1010 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `4327 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` - // Minimum execution time: 42_129_000 picoseconds. - Weight::from_parts(40_808_957, 4327) - // Standard Error: 134 - .saturating_add(Weight::from_parts(3_579, 0).saturating_mul(b.into())) - // Standard Error: 1_425 - .saturating_add(Weight::from_parts(37_166, 0).saturating_mul(m.into())) - // Standard Error: 1_389 - .saturating_add(Weight::from_parts(200_986, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(6_u64)) + // Measured: `832 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `4149 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` + // Minimum execution time: 40_391_000 picoseconds. + Weight::from_parts(42_695_215, 4149) + // Standard Error: 167 + .saturating_add(Weight::from_parts(3_622, 0).saturating_mul(b.into())) + // Standard Error: 1_772 + .saturating_add(Weight::from_parts(33_830, 0).saturating_mul(m.into())) + // Standard Error: 1_727 + .saturating_add(Weight::from_parts(205_374, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) .saturating_add(Weight::from_parts(0, 66).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) } - /// Storage: `Council::Voting` (r:1 w:1) - /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Council::Members` (r:1 w:0) - /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Prime` (r:1 w:0) - /// Proof: `Council::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Proposals` (r:1 w:1) - /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::ProposalOf` (r:0 w:1) - /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:0) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:0 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `583 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `4028 + m * (65 ±0) + p * (36 ±0)` - // Minimum execution time: 26_385_000 picoseconds. - Weight::from_parts(25_713_839, 4028) - // Standard Error: 1_254 - .saturating_add(Weight::from_parts(36_206, 0).saturating_mul(m.into())) - // Standard Error: 1_223 - .saturating_add(Weight::from_parts(195_114, 0).saturating_mul(p.into())) + // Measured: `550 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `3995 + m * (65 ±0) + p * (36 ±0)` + // Minimum execution time: 31_368_000 picoseconds. + Weight::from_parts(32_141_835, 3995) + // Standard Error: 1_451 + .saturating_add(Weight::from_parts(36_372, 0).saturating_mul(m.into())) + // Standard Error: 1_415 + .saturating_add(Weight::from_parts(210_635, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 65).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: `Council::Voting` (r:1 w:1) - /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Council::Members` (r:1 w:0) - /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Prime` (r:1 w:0) - /// Proof: `Council::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::ProposalOf` (r:1 w:1) - /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) - /// Storage: `Council::Proposals` (r:1 w:1) - /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:0) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1030 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `4347 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` - // Minimum execution time: 42_903_000 picoseconds. - Weight::from_parts(43_152_907, 4347) - // Standard Error: 146 - .saturating_add(Weight::from_parts(3_459, 0).saturating_mul(b.into())) - // Standard Error: 1_548 - .saturating_add(Weight::from_parts(35_321, 0).saturating_mul(m.into())) - // Standard Error: 1_509 - .saturating_add(Weight::from_parts(202_541, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(7_u64)) + // Measured: `852 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `4169 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` + // Minimum execution time: 43_271_000 picoseconds. + Weight::from_parts(45_495_648, 4169) + // Standard Error: 174 + .saturating_add(Weight::from_parts(3_034, 0).saturating_mul(b.into())) + // Standard Error: 1_840 + .saturating_add(Weight::from_parts(42_209, 0).saturating_mul(m.into())) + // Standard Error: 1_793 + .saturating_add(Weight::from_parts(207_525, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) .saturating_add(Weight::from_parts(0, 66).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) } - /// Storage: `Council::Proposals` (r:1 w:1) - /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Voting` (r:0 w:1) - /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Council::ProposalOf` (r:0 w:1) - /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:0 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:0 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `p` is `[1, 100]`. fn disapprove_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `392 + p * (32 ±0)` - // Estimated: `1877 + p * (32 ±0)` - // Minimum execution time: 12_656_000 picoseconds. - Weight::from_parts(14_032_951, 1877) - // Standard Error: 1_025 - .saturating_add(Weight::from_parts(159_143, 0).saturating_mul(p.into())) + // Measured: `359 + p * (32 ±0)` + // Estimated: `1844 + p * (32 ±0)` + // Minimum execution time: 15_170_000 picoseconds. + Weight::from_parts(17_567_243, 1844) + // Standard Error: 1_430 + .saturating_add(Weight::from_parts(169_040, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(p.into())) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Council::Members` (r:1 w:1) - /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Proposals` (r:1 w:0) - /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Voting` (r:100 w:100) - /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Council::Prime` (r:0 w:1) - /// Proof: `Council::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Council Members (r:1 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:100 w:100) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Prime (r:0 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[0, 100]`. /// The range of component `n` is `[0, 100]`. /// The range of component `p` is `[0, 100]`. fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + m * (3232 ±0) + p * (3190 ±0)` - // Estimated: `15894 + m * (1967 ±23) + p * (4332 ±23)` - // Minimum execution time: 15_559_000 picoseconds. - Weight::from_parts(15_870_000, 15894) - // Standard Error: 54_310 - .saturating_add(Weight::from_parts(4_117_753, 0).saturating_mul(m.into())) - // Standard Error: 54_310 - .saturating_add(Weight::from_parts(7_677_627, 0).saturating_mul(p.into())) + // Estimated: `15861 + m * (1967 ±24) + p * (4332 ±24)` + // Minimum execution time: 17_506_000 picoseconds. + Weight::from_parts(17_767_000, 15861) + // Standard Error: 60_220 + .saturating_add(Weight::from_parts(4_374_805, 0).saturating_mul(m.into())) + // Standard Error: 60_220 + .saturating_add(Weight::from_parts(8_398_316, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(p.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -356,232 +341,216 @@ impl WeightInfo for () { .saturating_add(Weight::from_parts(0, 1967).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 4332).saturating_mul(p.into())) } - /// Storage: `Council::Members` (r:1 w:0) - /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[1, 100]`. fn execute(b: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `380 + m * (32 ±0)` - // Estimated: `3997 + m * (32 ±0)` - // Minimum execution time: 19_024_000 picoseconds. - Weight::from_parts(18_153_872, 3997) - // Standard Error: 46 - .saturating_add(Weight::from_parts(1_933, 0).saturating_mul(b.into())) - // Standard Error: 478 - .saturating_add(Weight::from_parts(18_872, 0).saturating_mul(m.into())) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Measured: `202 + m * (32 ±0)` + // Estimated: `1688 + m * (32 ±0)` + // Minimum execution time: 16_203_000 picoseconds. + Weight::from_parts(15_348_267, 1688) + // Standard Error: 37 + .saturating_add(Weight::from_parts(1_766, 0).saturating_mul(b.into())) + // Standard Error: 382 + .saturating_add(Weight::from_parts(15_765, 0).saturating_mul(m.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } - /// Storage: `Council::Members` (r:1 w:0) - /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::ProposalOf` (r:1 w:0) - /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:0) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[1, 100]`. fn propose_execute(b: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `380 + m * (32 ±0)` - // Estimated: `3997 + m * (32 ±0)` - // Minimum execution time: 20_895_000 picoseconds. - Weight::from_parts(20_081_761, 3997) - // Standard Error: 57 - .saturating_add(Weight::from_parts(1_982, 0).saturating_mul(b.into())) - // Standard Error: 594 - .saturating_add(Weight::from_parts(32_085, 0).saturating_mul(m.into())) - .saturating_add(RocksDbWeight::get().reads(4_u64)) + // Measured: `202 + m * (32 ±0)` + // Estimated: `3668 + m * (32 ±0)` + // Minimum execution time: 18_642_000 picoseconds. + Weight::from_parts(17_708_609, 3668) + // Standard Error: 58 + .saturating_add(Weight::from_parts(2_285, 0).saturating_mul(b.into())) + // Standard Error: 598 + .saturating_add(Weight::from_parts(30_454, 0).saturating_mul(m.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } - /// Storage: `Council::Members` (r:1 w:0) - /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::ProposalOf` (r:1 w:1) - /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Council::Proposals` (r:1 w:1) - /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::ProposalCount` (r:1 w:1) - /// Proof: `Council::ProposalCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Voting` (r:0 w:1) - /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalCount (r:1 w:1) + /// Proof Skipped: Council ProposalCount (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:0 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[2, 100]`. /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `525 + m * (32 ±0) + p * (36 ±0)` - // Estimated: `3917 + m * (33 ±0) + p * (36 ±0)` - // Minimum execution time: 22_068_000 picoseconds. - Weight::from_parts(19_639_088, 3917) - // Standard Error: 104 - .saturating_add(Weight::from_parts(3_896, 0).saturating_mul(b.into())) - // Standard Error: 1_095 - .saturating_add(Weight::from_parts(31_634, 0).saturating_mul(m.into())) - // Standard Error: 1_081 - .saturating_add(Weight::from_parts(178_702, 0).saturating_mul(p.into())) + // Measured: `492 + m * (32 ±0) + p * (36 ±0)` + // Estimated: `3884 + m * (33 ±0) + p * (36 ±0)` + // Minimum execution time: 27_067_000 picoseconds. + Weight::from_parts(25_456_964, 3884) + // Standard Error: 112 + .saturating_add(Weight::from_parts(3_773, 0).saturating_mul(b.into())) + // Standard Error: 1_177 + .saturating_add(Weight::from_parts(32_783, 0).saturating_mul(m.into())) + // Standard Error: 1_162 + .saturating_add(Weight::from_parts(194_388, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 33).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: `Council::Members` (r:1 w:0) - /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Voting` (r:1 w:1) - /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `974 + m * (64 ±0)` - // Estimated: `4438 + m * (64 ±0)` - // Minimum execution time: 22_395_000 picoseconds. - Weight::from_parts(23_025_217, 4438) - // Standard Error: 842 - .saturating_add(Weight::from_parts(58_102, 0).saturating_mul(m.into())) + // Measured: `941 + m * (64 ±0)` + // Estimated: `4405 + m * (64 ±0)` + // Minimum execution time: 26_055_000 picoseconds. + Weight::from_parts(27_251_907, 4405) + // Standard Error: 1_008 + .saturating_add(Weight::from_parts(65_947, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } - /// Storage: `Council::Voting` (r:1 w:1) - /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Council::Members` (r:1 w:0) - /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Proposals` (r:1 w:1) - /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::ProposalOf` (r:0 w:1) - /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:0 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `563 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `4008 + m * (65 ±0) + p * (36 ±0)` - // Minimum execution time: 24_179_000 picoseconds. - Weight::from_parts(23_846_394, 4008) - // Standard Error: 1_052 - .saturating_add(Weight::from_parts(40_418, 0).saturating_mul(m.into())) - // Standard Error: 1_026 - .saturating_add(Weight::from_parts(171_653, 0).saturating_mul(p.into())) + // Measured: `530 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `3975 + m * (65 ±0) + p * (36 ±0)` + // Minimum execution time: 28_363_000 picoseconds. + Weight::from_parts(28_733_464, 3975) + // Standard Error: 1_275 + .saturating_add(Weight::from_parts(43_236, 0).saturating_mul(m.into())) + // Standard Error: 1_244 + .saturating_add(Weight::from_parts(180_187, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 65).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: `Council::Voting` (r:1 w:1) - /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Council::Members` (r:1 w:0) - /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::ProposalOf` (r:1 w:1) - /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) - /// Storage: `Council::Proposals` (r:1 w:1) - /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1010 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `4327 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` - // Minimum execution time: 42_129_000 picoseconds. - Weight::from_parts(40_808_957, 4327) - // Standard Error: 134 - .saturating_add(Weight::from_parts(3_579, 0).saturating_mul(b.into())) - // Standard Error: 1_425 - .saturating_add(Weight::from_parts(37_166, 0).saturating_mul(m.into())) - // Standard Error: 1_389 - .saturating_add(Weight::from_parts(200_986, 0).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(6_u64)) + // Measured: `832 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `4149 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` + // Minimum execution time: 40_391_000 picoseconds. + Weight::from_parts(42_695_215, 4149) + // Standard Error: 167 + .saturating_add(Weight::from_parts(3_622, 0).saturating_mul(b.into())) + // Standard Error: 1_772 + .saturating_add(Weight::from_parts(33_830, 0).saturating_mul(m.into())) + // Standard Error: 1_727 + .saturating_add(Weight::from_parts(205_374, 0).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) .saturating_add(Weight::from_parts(0, 66).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) } - /// Storage: `Council::Voting` (r:1 w:1) - /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Council::Members` (r:1 w:0) - /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Prime` (r:1 w:0) - /// Proof: `Council::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Proposals` (r:1 w:1) - /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::ProposalOf` (r:0 w:1) - /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:0) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:0 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `583 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `4028 + m * (65 ±0) + p * (36 ±0)` - // Minimum execution time: 26_385_000 picoseconds. - Weight::from_parts(25_713_839, 4028) - // Standard Error: 1_254 - .saturating_add(Weight::from_parts(36_206, 0).saturating_mul(m.into())) - // Standard Error: 1_223 - .saturating_add(Weight::from_parts(195_114, 0).saturating_mul(p.into())) + // Measured: `550 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `3995 + m * (65 ±0) + p * (36 ±0)` + // Minimum execution time: 31_368_000 picoseconds. + Weight::from_parts(32_141_835, 3995) + // Standard Error: 1_451 + .saturating_add(Weight::from_parts(36_372, 0).saturating_mul(m.into())) + // Standard Error: 1_415 + .saturating_add(Weight::from_parts(210_635, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 65).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) } - /// Storage: `Council::Voting` (r:1 w:1) - /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Council::Members` (r:1 w:0) - /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Prime` (r:1 w:0) - /// Proof: `Council::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::ProposalOf` (r:1 w:1) - /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) - /// Storage: `Council::Proposals` (r:1 w:1) - /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Council Voting (r:1 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Members (r:1 w:0) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:0) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:1 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `b` is `[2, 1024]`. /// The range of component `m` is `[4, 100]`. /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1030 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `4347 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` - // Minimum execution time: 42_903_000 picoseconds. - Weight::from_parts(43_152_907, 4347) - // Standard Error: 146 - .saturating_add(Weight::from_parts(3_459, 0).saturating_mul(b.into())) - // Standard Error: 1_548 - .saturating_add(Weight::from_parts(35_321, 0).saturating_mul(m.into())) - // Standard Error: 1_509 - .saturating_add(Weight::from_parts(202_541, 0).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(7_u64)) + // Measured: `852 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `4169 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` + // Minimum execution time: 43_271_000 picoseconds. + Weight::from_parts(45_495_648, 4169) + // Standard Error: 174 + .saturating_add(Weight::from_parts(3_034, 0).saturating_mul(b.into())) + // Standard Error: 1_840 + .saturating_add(Weight::from_parts(42_209, 0).saturating_mul(m.into())) + // Standard Error: 1_793 + .saturating_add(Weight::from_parts(207_525, 0).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) .saturating_add(Weight::from_parts(0, 66).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) } - /// Storage: `Council::Proposals` (r:1 w:1) - /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Voting` (r:0 w:1) - /// Proof: `Council::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Council::ProposalOf` (r:0 w:1) - /// Proof: `Council::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Council Proposals (r:1 w:1) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Voting (r:0 w:1) + /// Proof Skipped: Council Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council ProposalOf (r:0 w:1) + /// Proof Skipped: Council ProposalOf (max_values: None, max_size: None, mode: Measured) /// The range of component `p` is `[1, 100]`. fn disapprove_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `392 + p * (32 ±0)` - // Estimated: `1877 + p * (32 ±0)` - // Minimum execution time: 12_656_000 picoseconds. - Weight::from_parts(14_032_951, 1877) - // Standard Error: 1_025 - .saturating_add(Weight::from_parts(159_143, 0).saturating_mul(p.into())) + // Measured: `359 + p * (32 ±0)` + // Estimated: `1844 + p * (32 ±0)` + // Minimum execution time: 15_170_000 picoseconds. + Weight::from_parts(17_567_243, 1844) + // Standard Error: 1_430 + .saturating_add(Weight::from_parts(169_040, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(p.into())) diff --git a/substrate/frame/contracts/src/weights.rs b/substrate/frame/contracts/src/weights.rs index 6e09120c141..99bc4d8d3eb 100644 --- a/substrate/frame/contracts/src/weights.rs +++ b/substrate/frame/contracts/src/weights.rs @@ -25,6 +25,7 @@ // Executed Command: // target/production/substrate-node +// target/production/substrate-node // benchmark // pallet // --steps=50 @@ -35,8 +36,12 @@ // --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json // --pallet=pallet_contracts // --chain=dev +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_contracts +// --chain=dev // --header=./substrate/HEADER-APACHE2 // --output=./substrate/frame/contracts/src/weights.rs +// --output=./substrate/frame/contracts/src/weights.rs // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -213,8 +218,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc553053f13fd319a03c211337c76e0fe776df` (r:2 w:0) /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc553022fca90611ba8b7942f8bdb3b97f6580` (r:1 w:1) /// Proof: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc553022fca90611ba8b7942f8bdb3b97f6580` (r:1 w:1) - /// Storage: `Parameters::Parameters` (r:2 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:0 w:1) @@ -248,7 +251,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:0) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) fn v14_migration_step() -> Weight { // Proof Size summary in bytes: // Measured: `352` @@ -332,8 +335,6 @@ impl WeightInfo for SubstrateWeight { } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -361,12 +362,10 @@ impl WeightInfo for SubstrateWeight { } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:1) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Balances::Holds` (r:2 w:2) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) /// Storage: `System::EventTopics` (r:3 w:3) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Contracts::Nonce` (r:1 w:1) @@ -403,8 +402,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Contracts::PristineCode` (r:1 w:0) /// Proof: `Contracts::PristineCode` (`max_values`: None, `max_size`: Some(125988), added: 128463, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::Nonce` (r:1 w:1) /// Proof: `Contracts::Nonce` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) @@ -416,7 +413,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `System::EventTopics` (r:2 w:2) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) /// The range of component `i` is `[0, 1048576]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate(i: u32, s: u32, ) -> Weight { @@ -434,8 +431,6 @@ impl WeightInfo for SubstrateWeight { } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -459,12 +454,10 @@ impl WeightInfo for SubstrateWeight { } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:2 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:1) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) /// Storage: `System::EventTopics` (r:1 w:1) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Contracts::PristineCode` (r:0 w:1) @@ -510,7 +503,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Contracts::CodeInfoOf` (r:1 w:1) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) /// Storage: `System::EventTopics` (r:1 w:1) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Contracts::PristineCode` (r:0 w:1) @@ -545,8 +538,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -574,8 +565,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1601 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -604,8 +593,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1601 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -634,8 +621,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -663,8 +648,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -690,8 +673,6 @@ impl WeightInfo for SubstrateWeight { } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -719,8 +700,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -748,8 +727,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -777,8 +754,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:2 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -806,8 +781,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -835,8 +808,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -864,8 +835,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -893,8 +862,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -922,8 +889,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -953,8 +918,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -982,8 +945,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1010,8 +971,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1039,8 +998,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1067,8 +1024,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:3 w:3) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:1 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:2 w:2) @@ -1082,7 +1037,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `System::EventTopics` (r:4 w:4) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) /// Storage: `Contracts::DeletionQueue` (r:0 w:1) /// Proof: `Contracts::DeletionQueue` (`max_values`: None, `max_size`: Some(142), added: 2617, mode: `Measured`) /// The range of component `r` is `[0, 1]`. @@ -1098,14 +1053,12 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((10_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 5479).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 5266).saturating_mul(r.into())) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1135,8 +1088,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1164,8 +1115,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1198,8 +1147,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1227,8 +1174,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `MaxEncodedLen`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1423,8 +1368,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1602 w:1601) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1454,8 +1397,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:801 w:801) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:2 w:0) @@ -1485,8 +1426,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:736 w:0) @@ -1516,8 +1455,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:3 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:2 w:2) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:2 w:0) @@ -1550,8 +1487,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:802 w:802) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:801 w:801) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:801 w:800) @@ -1565,7 +1500,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `System::EventTopics` (r:803 w:803) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:800 w:800) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) /// The range of component `r` is `[1, 800]`. fn seal_instantiate(r: u32, ) -> Weight { // Proof Size summary in bytes: @@ -1585,8 +1520,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:3 w:3) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:2 w:2) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:2 w:1) @@ -1600,7 +1533,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `System::EventTopics` (r:4 w:4) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) /// The range of component `t` is `[0, 1]`. /// The range of component `i` is `[0, 983040]`. /// The range of component `s` is `[0, 983040]`. @@ -1624,8 +1557,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1653,8 +1584,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1681,8 +1610,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1710,8 +1637,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1738,8 +1663,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1767,8 +1690,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1795,8 +1716,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1824,8 +1743,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1852,8 +1769,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1881,8 +1796,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1910,8 +1823,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1939,8 +1850,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1968,8 +1877,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1536 w:1536) @@ -1999,8 +1906,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:33 w:32) @@ -2024,14 +1929,12 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 2607).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2606).saturating_mul(r.into())) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `MaxEncodedLen`) /// Storage: `Contracts::CodeInfoOf` (r:33 w:32) @@ -2045,7 +1948,7 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 32]`. fn unlock_delegate_dependency(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `972 + r * (184 ±0)` + // Measured: `969 + r * (183 ±0)` // Estimated: `129453 + r * (2568 ±0)` // Minimum execution time: 270_652_000 picoseconds. Weight::from_parts(293_369_452, 129453) @@ -2061,8 +1964,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2090,8 +1991,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2119,8 +2018,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2237,8 +2134,6 @@ impl WeightInfo for () { /// Proof: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc553053f13fd319a03c211337c76e0fe776df` (r:2 w:0) /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc553022fca90611ba8b7942f8bdb3b97f6580` (r:1 w:1) /// Proof: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc553022fca90611ba8b7942f8bdb3b97f6580` (r:1 w:1) - /// Storage: `Parameters::Parameters` (r:2 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:0 w:1) @@ -2272,7 +2167,7 @@ impl WeightInfo for () { /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:0) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) fn v14_migration_step() -> Weight { // Proof Size summary in bytes: // Measured: `352` @@ -2356,8 +2251,6 @@ impl WeightInfo for () { } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2385,12 +2278,10 @@ impl WeightInfo for () { } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:1) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Balances::Holds` (r:2 w:2) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) /// Storage: `System::EventTopics` (r:3 w:3) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Contracts::Nonce` (r:1 w:1) @@ -2427,8 +2318,6 @@ impl WeightInfo for () { /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Contracts::PristineCode` (r:1 w:0) /// Proof: `Contracts::PristineCode` (`max_values`: None, `max_size`: Some(125988), added: 128463, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::Nonce` (r:1 w:1) /// Proof: `Contracts::Nonce` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) @@ -2440,7 +2329,7 @@ impl WeightInfo for () { /// Storage: `System::EventTopics` (r:2 w:2) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) /// The range of component `i` is `[0, 1048576]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate(i: u32, s: u32, ) -> Weight { @@ -2458,8 +2347,6 @@ impl WeightInfo for () { } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2483,12 +2370,10 @@ impl WeightInfo for () { } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:2 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:1) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) /// Storage: `System::EventTopics` (r:1 w:1) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Contracts::PristineCode` (r:0 w:1) @@ -2534,7 +2419,7 @@ impl WeightInfo for () { /// Storage: `Contracts::CodeInfoOf` (r:1 w:1) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) /// Storage: `System::EventTopics` (r:1 w:1) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Contracts::PristineCode` (r:0 w:1) @@ -2569,8 +2454,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2598,8 +2481,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1601 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2628,8 +2509,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1601 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2658,8 +2537,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2687,8 +2564,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2714,8 +2589,6 @@ impl WeightInfo for () { } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2743,8 +2616,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2772,8 +2643,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2801,8 +2670,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:2 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2830,8 +2697,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2859,8 +2724,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2888,8 +2751,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2917,8 +2778,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2946,8 +2805,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2977,8 +2834,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3006,8 +2861,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3034,8 +2887,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3063,8 +2914,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3091,8 +2940,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:3 w:3) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:1 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:2 w:2) @@ -3106,7 +2953,7 @@ impl WeightInfo for () { /// Storage: `System::EventTopics` (r:4 w:4) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) /// Storage: `Contracts::DeletionQueue` (r:0 w:1) /// Proof: `Contracts::DeletionQueue` (`max_values`: None, `max_size`: Some(142), added: 2617, mode: `Measured`) /// The range of component `r` is `[0, 1]`. @@ -3122,14 +2969,12 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((10_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 5479).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 5266).saturating_mul(r.into())) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3159,8 +3004,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3188,8 +3031,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3222,8 +3063,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3251,8 +3090,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `MaxEncodedLen`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3447,8 +3284,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1602 w:1601) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3478,8 +3313,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:801 w:801) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:2 w:0) @@ -3509,8 +3342,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:736 w:0) @@ -3540,8 +3371,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:3 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:2 w:2) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:2 w:0) @@ -3574,8 +3403,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:802 w:802) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:801 w:801) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:801 w:800) @@ -3589,7 +3416,7 @@ impl WeightInfo for () { /// Storage: `System::EventTopics` (r:803 w:803) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:800 w:800) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) /// The range of component `r` is `[1, 800]`. fn seal_instantiate(r: u32, ) -> Weight { // Proof Size summary in bytes: @@ -3609,8 +3436,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:3 w:3) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:2 w:2) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:2 w:1) @@ -3624,7 +3449,7 @@ impl WeightInfo for () { /// Storage: `System::EventTopics` (r:4 w:4) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) /// The range of component `t` is `[0, 1]`. /// The range of component `i` is `[0, 983040]`. /// The range of component `s` is `[0, 983040]`. @@ -3648,8 +3473,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3677,8 +3500,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3705,8 +3526,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3734,8 +3553,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3762,8 +3579,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3791,8 +3606,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3819,8 +3632,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3848,8 +3659,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3876,8 +3685,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3905,8 +3712,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3934,8 +3739,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3963,8 +3766,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3992,8 +3793,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1536 w:1536) @@ -4023,8 +3822,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:33 w:32) @@ -4048,14 +3845,12 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 2607).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2606).saturating_mul(r.into())) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `MaxEncodedLen`) /// Storage: `Contracts::CodeInfoOf` (r:33 w:32) @@ -4069,7 +3864,7 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 32]`. fn unlock_delegate_dependency(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `972 + r * (184 ±0)` + // Measured: `969 + r * (183 ±0)` // Estimated: `129453 + r * (2568 ±0)` // Minimum execution time: 270_652_000 picoseconds. Weight::from_parts(293_369_452, 129453) @@ -4085,8 +3880,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -4114,8 +3907,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -4143,8 +3934,6 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) - /// Storage: `Parameters::Parameters` (r:3 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) diff --git a/substrate/frame/conviction-voting/src/weights.rs b/substrate/frame/conviction-voting/src/weights.rs index 75d9e8499ed..225f5c2cadd 100644 --- a/substrate/frame/conviction-voting/src/weights.rs +++ b/substrate/frame/conviction-voting/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_conviction_voting` +//! Autogenerated weights for pallet_conviction_voting //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/conviction-voting/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/conviction-voting/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_conviction_voting`. +/// Weight functions needed for pallet_conviction_voting. pub trait WeightInfo { fn vote_new() -> Weight; fn vote_existing() -> Weight; @@ -60,300 +61,280 @@ pub trait WeightInfo { fn unlock() -> Weight; } -/// Weights for `pallet_conviction_voting` using the Substrate node and recommended hardware. +/// Weights for pallet_conviction_voting using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) - /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) - /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) - /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(59), added: 2534, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: ConvictionVoting VotingFor (r:1 w:1) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn vote_new() -> Weight { // Proof Size summary in bytes: - // Measured: `13141` + // Measured: `13074` // Estimated: `219984` - // Minimum execution time: 102_539_000 picoseconds. - Weight::from_parts(105_873_000, 219984) + // Minimum execution time: 112_936_000 picoseconds. + Weight::from_parts(116_972_000, 219984) .saturating_add(T::DbWeight::get().reads(7_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) - /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) - /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) - /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(59), added: 2534, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: ConvictionVoting VotingFor (r:1 w:1) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn vote_existing() -> Weight { // Proof Size summary in bytes: - // Measured: `20283` + // Measured: `20216` // Estimated: `219984` - // Minimum execution time: 275_424_000 picoseconds. - Weight::from_parts(283_690_000, 219984) + // Minimum execution time: 291_971_000 picoseconds. + Weight::from_parts(301_738_000, 219984) .saturating_add(T::DbWeight::get().reads(7_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) } - /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) - /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: ConvictionVoting VotingFor (r:1 w:1) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn remove_vote() -> Weight { // Proof Size summary in bytes: - // Measured: `20035` + // Measured: `19968` // Estimated: `219984` - // Minimum execution time: 275_109_000 picoseconds. - Weight::from_parts(281_315_000, 219984) + // Minimum execution time: 262_582_000 picoseconds. + Weight::from_parts(270_955_000, 219984) .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(5_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) - /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: ConvictionVoting VotingFor (r:1 w:1) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn remove_other_vote() -> Weight { // Proof Size summary in bytes: - // Measured: `12742` + // Measured: `12675` // Estimated: `30706` - // Minimum execution time: 49_629_000 picoseconds. - Weight::from_parts(51_300_000, 30706) + // Minimum execution time: 52_909_000 picoseconds. + Weight::from_parts(56_365_000, 30706) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `ConvictionVoting::VotingFor` (r:2 w:2) - /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) - /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(59), added: 2534, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: ConvictionVoting VotingFor (r:2 w:2) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `r` is `[0, 1]`. fn delegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `306 + r * (1628 ±0)` + // Measured: `240 + r * (1627 ±0)` // Estimated: `109992 + r * (109992 ±0)` - // Minimum execution time: 45_776_000 picoseconds. - Weight::from_parts(47_917_822, 109992) - // Standard Error: 124_174 - .saturating_add(Weight::from_parts(43_171_077, 0).saturating_mul(r.into())) + // Minimum execution time: 54_640_000 picoseconds. + Weight::from_parts(57_185_281, 109992) + // Standard Error: 193_362 + .saturating_add(Weight::from_parts(44_897_418, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) - .saturating_add(T::DbWeight::get().writes((4_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 109992).saturating_mul(r.into())) } - /// Storage: `ConvictionVoting::VotingFor` (r:2 w:2) - /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: ConvictionVoting VotingFor (r:2 w:2) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) /// The range of component `r` is `[0, 1]`. fn undelegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `472 + r * (1377 ±0)` + // Measured: `406 + r * (1376 ±0)` // Estimated: `109992 + r * (109992 ±0)` - // Minimum execution time: 23_600_000 picoseconds. - Weight::from_parts(25_001_426, 109992) - // Standard Error: 72_034 - .saturating_add(Weight::from_parts(37_851_873, 0).saturating_mul(r.into())) + // Minimum execution time: 26_514_000 picoseconds. + Weight::from_parts(28_083_732, 109992) + // Standard Error: 104_905 + .saturating_add(Weight::from_parts(40_722_467, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) - .saturating_add(T::DbWeight::get().writes((4_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 109992).saturating_mul(r.into())) } - /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) - /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) - /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) - /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(59), added: 2534, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: ConvictionVoting VotingFor (r:1 w:1) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn unlock() -> Weight { // Proof Size summary in bytes: - // Measured: `11800` + // Measured: `11734` // Estimated: `30706` - // Minimum execution time: 66_247_000 picoseconds. - Weight::from_parts(67_552_000, 30706) + // Minimum execution time: 71_140_000 picoseconds. + Weight::from_parts(77_388_000, 30706) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) - /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) - /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) - /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(59), added: 2534, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: ConvictionVoting VotingFor (r:1 w:1) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn vote_new() -> Weight { // Proof Size summary in bytes: - // Measured: `13141` + // Measured: `13074` // Estimated: `219984` - // Minimum execution time: 102_539_000 picoseconds. - Weight::from_parts(105_873_000, 219984) + // Minimum execution time: 112_936_000 picoseconds. + Weight::from_parts(116_972_000, 219984) .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) - /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) - /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) - /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(59), added: 2534, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: ConvictionVoting VotingFor (r:1 w:1) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn vote_existing() -> Weight { // Proof Size summary in bytes: - // Measured: `20283` + // Measured: `20216` // Estimated: `219984` - // Minimum execution time: 275_424_000 picoseconds. - Weight::from_parts(283_690_000, 219984) + // Minimum execution time: 291_971_000 picoseconds. + Weight::from_parts(301_738_000, 219984) .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } - /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) - /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: ConvictionVoting VotingFor (r:1 w:1) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn remove_vote() -> Weight { // Proof Size summary in bytes: - // Measured: `20035` + // Measured: `19968` // Estimated: `219984` - // Minimum execution time: 275_109_000 picoseconds. - Weight::from_parts(281_315_000, 219984) + // Minimum execution time: 262_582_000 picoseconds. + Weight::from_parts(270_955_000, 219984) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(5_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) - /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: ConvictionVoting VotingFor (r:1 w:1) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn remove_other_vote() -> Weight { // Proof Size summary in bytes: - // Measured: `12742` + // Measured: `12675` // Estimated: `30706` - // Minimum execution time: 49_629_000 picoseconds. - Weight::from_parts(51_300_000, 30706) + // Minimum execution time: 52_909_000 picoseconds. + Weight::from_parts(56_365_000, 30706) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `ConvictionVoting::VotingFor` (r:2 w:2) - /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) - /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(59), added: 2534, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: ConvictionVoting VotingFor (r:2 w:2) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `r` is `[0, 1]`. fn delegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `306 + r * (1628 ±0)` + // Measured: `240 + r * (1627 ±0)` // Estimated: `109992 + r * (109992 ±0)` - // Minimum execution time: 45_776_000 picoseconds. - Weight::from_parts(47_917_822, 109992) - // Standard Error: 124_174 - .saturating_add(Weight::from_parts(43_171_077, 0).saturating_mul(r.into())) + // Minimum execution time: 54_640_000 picoseconds. + Weight::from_parts(57_185_281, 109992) + // Standard Error: 193_362 + .saturating_add(Weight::from_parts(44_897_418, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) - .saturating_add(RocksDbWeight::get().writes((4_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 109992).saturating_mul(r.into())) } - /// Storage: `ConvictionVoting::VotingFor` (r:2 w:2) - /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: ConvictionVoting VotingFor (r:2 w:2) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) /// The range of component `r` is `[0, 1]`. fn undelegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `472 + r * (1377 ±0)` + // Measured: `406 + r * (1376 ±0)` // Estimated: `109992 + r * (109992 ±0)` - // Minimum execution time: 23_600_000 picoseconds. - Weight::from_parts(25_001_426, 109992) - // Standard Error: 72_034 - .saturating_add(Weight::from_parts(37_851_873, 0).saturating_mul(r.into())) + // Minimum execution time: 26_514_000 picoseconds. + Weight::from_parts(28_083_732, 109992) + // Standard Error: 104_905 + .saturating_add(Weight::from_parts(40_722_467, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) - .saturating_add(RocksDbWeight::get().writes((4_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 109992).saturating_mul(r.into())) } - /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) - /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) - /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) - /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(59), added: 2534, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: ConvictionVoting VotingFor (r:1 w:1) + /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) + /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) + /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(59), added: 2534, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn unlock() -> Weight { // Proof Size summary in bytes: - // Measured: `11800` + // Measured: `11734` // Estimated: `30706` - // Minimum execution time: 66_247_000 picoseconds. - Weight::from_parts(67_552_000, 30706) + // Minimum execution time: 71_140_000 picoseconds. + Weight::from_parts(77_388_000, 30706) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } diff --git a/substrate/frame/core-fellowship/src/weights.rs b/substrate/frame/core-fellowship/src/weights.rs index fce1d3747a8..8bbfd1a4dd8 100644 --- a/substrate/frame/core-fellowship/src/weights.rs +++ b/substrate/frame/core-fellowship/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_core_fellowship` +//! Autogenerated weights for pallet_core_fellowship //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/core-fellowship/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/core-fellowship/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_core_fellowship`. +/// Weight functions needed for pallet_core_fellowship. pub trait WeightInfo { fn set_params() -> Weight; fn bump_offboard() -> Weight; @@ -63,344 +64,336 @@ pub trait WeightInfo { fn submit_evidence() -> Weight; } -/// Weights for `pallet_core_fellowship` using the Substrate node and recommended hardware. +/// Weights for pallet_core_fellowship using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `CoreFellowship::Params` (r:0 w:1) - /// Proof: `CoreFellowship::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, mode: `MaxEncodedLen`) + /// Storage: CoreFellowship Params (r:0 w:1) + /// Proof: CoreFellowship Params (max_values: Some(1), max_size: Some(364), added: 859, mode: MaxEncodedLen) fn set_params() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_146_000 picoseconds. - Weight::from_parts(7_426_000, 0) + // Minimum execution time: 9_454_000 picoseconds. + Weight::from_parts(9_804_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `CoreFellowship::Member` (r:1 w:1) - /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::Members` (r:1 w:1) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::Params` (r:1 w:0) - /// Proof: `CoreFellowship::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::MemberCount` (r:1 w:1) - /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IdToIndex` (r:1 w:1) - /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::MemberEvidence` (r:1 w:1) - /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IndexToId` (r:0 w:1) - /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: CoreFellowship Params (r:1 w:0) + /// Proof: CoreFellowship Params (max_values: Some(1), max_size: Some(364), added: 859, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:1 w:0) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: CoreFellowship MemberEvidence (r:1 w:1) + /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) fn bump_offboard() -> Weight { // Proof Size summary in bytes: - // Measured: `17274` + // Measured: `16887` // Estimated: `19894` - // Minimum execution time: 54_511_000 picoseconds. - Weight::from_parts(56_995_000, 19894) + // Minimum execution time: 58_489_000 picoseconds. + Weight::from_parts(60_202_000, 19894) .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().writes(6_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: `CoreFellowship::Member` (r:1 w:1) - /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::Members` (r:1 w:1) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::Params` (r:1 w:0) - /// Proof: `CoreFellowship::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::MemberCount` (r:1 w:1) - /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IdToIndex` (r:1 w:1) - /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::MemberEvidence` (r:1 w:1) - /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IndexToId` (r:0 w:1) - /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: CoreFellowship Params (r:1 w:0) + /// Proof: CoreFellowship Params (max_values: Some(1), max_size: Some(364), added: 859, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:1 w:0) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: CoreFellowship MemberEvidence (r:1 w:1) + /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) fn bump_demote() -> Weight { // Proof Size summary in bytes: - // Measured: `17384` + // Measured: `16997` // Estimated: `19894` - // Minimum execution time: 56_453_000 picoseconds. - Weight::from_parts(59_030_000, 19894) + // Minimum execution time: 60_605_000 picoseconds. + Weight::from_parts(63_957_000, 19894) .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().writes(6_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: `RankedCollective::Members` (r:1 w:0) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::Member` (r:1 w:1) - /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn set_active() -> Weight { // Proof Size summary in bytes: // Measured: `388` // Estimated: `3514` - // Minimum execution time: 15_940_000 picoseconds. - Weight::from_parts(16_381_000, 3514) + // Minimum execution time: 17_816_000 picoseconds. + Weight::from_parts(18_524_000, 3514) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `CoreFellowship::Member` (r:1 w:1) - /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::Members` (r:1 w:1) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::MemberCount` (r:1 w:1) - /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IndexToId` (r:0 w:1) - /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IdToIndex` (r:0 w:1) - /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IndexToId (r:0 w:1) + /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:0 w:1) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) fn induct() -> Weight { // Proof Size summary in bytes: // Measured: `146` // Estimated: `3514` - // Minimum execution time: 24_193_000 picoseconds. - Weight::from_parts(24_963_000, 3514) + // Minimum execution time: 27_249_000 picoseconds. + Weight::from_parts(28_049_000, 3514) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: `RankedCollective::Members` (r:1 w:1) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::Member` (r:1 w:1) - /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::Params` (r:1 w:0) - /// Proof: `CoreFellowship::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::MemberCount` (r:1 w:1) - /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::MemberEvidence` (r:1 w:1) - /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IndexToId` (r:0 w:1) - /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IdToIndex` (r:0 w:1) - /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: CoreFellowship Params (r:1 w:0) + /// Proof: CoreFellowship Params (max_values: Some(1), max_size: Some(364), added: 859, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: CoreFellowship MemberEvidence (r:1 w:1) + /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) + /// Storage: RankedCollective IndexToId (r:0 w:1) + /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:0 w:1) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) fn promote() -> Weight { // Proof Size summary in bytes: // Measured: `16865` // Estimated: `19894` - // Minimum execution time: 48_138_000 picoseconds. - Weight::from_parts(50_007_000, 19894) + // Minimum execution time: 56_642_000 picoseconds. + Weight::from_parts(59_353_000, 19894) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } - /// Storage: `RankedCollective::Members` (r:1 w:0) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::Member` (r:1 w:1) - /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::MemberEvidence` (r:0 w:1) - /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: CoreFellowship MemberEvidence (r:0 w:1) + /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) fn offboard() -> Weight { // Proof Size summary in bytes: - // Measured: `293` + // Measured: `359` // Estimated: `3514` - // Minimum execution time: 15_225_000 picoseconds. - Weight::from_parts(15_730_000, 3514) + // Minimum execution time: 17_459_000 picoseconds. + Weight::from_parts(18_033_000, 3514) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `CoreFellowship::Member` (r:1 w:1) - /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::Members` (r:1 w:0) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) fn import() -> Weight { // Proof Size summary in bytes: // Measured: `313` // Estimated: `3514` - // Minimum execution time: 14_507_000 picoseconds. - Weight::from_parts(14_935_000, 3514) + // Minimum execution time: 16_728_000 picoseconds. + Weight::from_parts(17_263_000, 3514) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `RankedCollective::Members` (r:1 w:0) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::Member` (r:1 w:1) - /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::MemberEvidence` (r:1 w:1) - /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: CoreFellowship MemberEvidence (r:1 w:1) + /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) fn approve() -> Weight { // Proof Size summary in bytes: // Measured: `16843` // Estimated: `19894` - // Minimum execution time: 34_050_000 picoseconds. - Weight::from_parts(36_323_000, 19894) + // Minimum execution time: 41_487_000 picoseconds. + Weight::from_parts(43_459_000, 19894) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `CoreFellowship::Member` (r:1 w:0) - /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::MemberEvidence` (r:1 w:1) - /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) + /// Storage: CoreFellowship Member (r:1 w:0) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: CoreFellowship MemberEvidence (r:1 w:1) + /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) fn submit_evidence() -> Weight { // Proof Size summary in bytes: // Measured: `79` // Estimated: `19894` - // Minimum execution time: 24_016_000 picoseconds. - Weight::from_parts(24_607_000, 19894) + // Minimum execution time: 26_033_000 picoseconds. + Weight::from_parts(26_612_000, 19894) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `CoreFellowship::Params` (r:0 w:1) - /// Proof: `CoreFellowship::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, mode: `MaxEncodedLen`) + /// Storage: CoreFellowship Params (r:0 w:1) + /// Proof: CoreFellowship Params (max_values: Some(1), max_size: Some(364), added: 859, mode: MaxEncodedLen) fn set_params() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_146_000 picoseconds. - Weight::from_parts(7_426_000, 0) + // Minimum execution time: 9_454_000 picoseconds. + Weight::from_parts(9_804_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `CoreFellowship::Member` (r:1 w:1) - /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::Members` (r:1 w:1) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::Params` (r:1 w:0) - /// Proof: `CoreFellowship::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::MemberCount` (r:1 w:1) - /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IdToIndex` (r:1 w:1) - /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::MemberEvidence` (r:1 w:1) - /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IndexToId` (r:0 w:1) - /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: CoreFellowship Params (r:1 w:0) + /// Proof: CoreFellowship Params (max_values: Some(1), max_size: Some(364), added: 859, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:1 w:0) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: CoreFellowship MemberEvidence (r:1 w:1) + /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) fn bump_offboard() -> Weight { // Proof Size summary in bytes: - // Measured: `17274` + // Measured: `16887` // Estimated: `19894` - // Minimum execution time: 54_511_000 picoseconds. - Weight::from_parts(56_995_000, 19894) + // Minimum execution time: 58_489_000 picoseconds. + Weight::from_parts(60_202_000, 19894) .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: `CoreFellowship::Member` (r:1 w:1) - /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::Members` (r:1 w:1) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::Params` (r:1 w:0) - /// Proof: `CoreFellowship::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::MemberCount` (r:1 w:1) - /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IdToIndex` (r:1 w:1) - /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::MemberEvidence` (r:1 w:1) - /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IndexToId` (r:0 w:1) - /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: CoreFellowship Params (r:1 w:0) + /// Proof: CoreFellowship Params (max_values: Some(1), max_size: Some(364), added: 859, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:1 w:0) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: CoreFellowship MemberEvidence (r:1 w:1) + /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) fn bump_demote() -> Weight { // Proof Size summary in bytes: - // Measured: `17384` + // Measured: `16997` // Estimated: `19894` - // Minimum execution time: 56_453_000 picoseconds. - Weight::from_parts(59_030_000, 19894) + // Minimum execution time: 60_605_000 picoseconds. + Weight::from_parts(63_957_000, 19894) .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: `RankedCollective::Members` (r:1 w:0) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::Member` (r:1 w:1) - /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn set_active() -> Weight { // Proof Size summary in bytes: // Measured: `388` // Estimated: `3514` - // Minimum execution time: 15_940_000 picoseconds. - Weight::from_parts(16_381_000, 3514) + // Minimum execution time: 17_816_000 picoseconds. + Weight::from_parts(18_524_000, 3514) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `CoreFellowship::Member` (r:1 w:1) - /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::Members` (r:1 w:1) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::MemberCount` (r:1 w:1) - /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IndexToId` (r:0 w:1) - /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IdToIndex` (r:0 w:1) - /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IndexToId (r:0 w:1) + /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:0 w:1) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) fn induct() -> Weight { // Proof Size summary in bytes: // Measured: `146` // Estimated: `3514` - // Minimum execution time: 24_193_000 picoseconds. - Weight::from_parts(24_963_000, 3514) + // Minimum execution time: 27_249_000 picoseconds. + Weight::from_parts(28_049_000, 3514) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: `RankedCollective::Members` (r:1 w:1) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::Member` (r:1 w:1) - /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::Params` (r:1 w:0) - /// Proof: `CoreFellowship::Params` (`max_values`: Some(1), `max_size`: Some(364), added: 859, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::MemberCount` (r:1 w:1) - /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::MemberEvidence` (r:1 w:1) - /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IndexToId` (r:0 w:1) - /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IdToIndex` (r:0 w:1) - /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: CoreFellowship Params (r:1 w:0) + /// Proof: CoreFellowship Params (max_values: Some(1), max_size: Some(364), added: 859, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: CoreFellowship MemberEvidence (r:1 w:1) + /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) + /// Storage: RankedCollective IndexToId (r:0 w:1) + /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:0 w:1) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) fn promote() -> Weight { // Proof Size summary in bytes: // Measured: `16865` // Estimated: `19894` - // Minimum execution time: 48_138_000 picoseconds. - Weight::from_parts(50_007_000, 19894) + // Minimum execution time: 56_642_000 picoseconds. + Weight::from_parts(59_353_000, 19894) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } - /// Storage: `RankedCollective::Members` (r:1 w:0) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::Member` (r:1 w:1) - /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::MemberEvidence` (r:0 w:1) - /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: CoreFellowship MemberEvidence (r:0 w:1) + /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) fn offboard() -> Weight { // Proof Size summary in bytes: - // Measured: `293` + // Measured: `359` // Estimated: `3514` - // Minimum execution time: 15_225_000 picoseconds. - Weight::from_parts(15_730_000, 3514) + // Minimum execution time: 17_459_000 picoseconds. + Weight::from_parts(18_033_000, 3514) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `CoreFellowship::Member` (r:1 w:1) - /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::Members` (r:1 w:0) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) fn import() -> Weight { // Proof Size summary in bytes: // Measured: `313` // Estimated: `3514` - // Minimum execution time: 14_507_000 picoseconds. - Weight::from_parts(14_935_000, 3514) + // Minimum execution time: 16_728_000 picoseconds. + Weight::from_parts(17_263_000, 3514) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `RankedCollective::Members` (r:1 w:0) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::Member` (r:1 w:1) - /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::MemberEvidence` (r:1 w:1) - /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: CoreFellowship Member (r:1 w:1) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: CoreFellowship MemberEvidence (r:1 w:1) + /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) fn approve() -> Weight { // Proof Size summary in bytes: // Measured: `16843` // Estimated: `19894` - // Minimum execution time: 34_050_000 picoseconds. - Weight::from_parts(36_323_000, 19894) + // Minimum execution time: 41_487_000 picoseconds. + Weight::from_parts(43_459_000, 19894) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `CoreFellowship::Member` (r:1 w:0) - /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::MemberEvidence` (r:1 w:1) - /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) + /// Storage: CoreFellowship Member (r:1 w:0) + /// Proof: CoreFellowship Member (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: CoreFellowship MemberEvidence (r:1 w:1) + /// Proof: CoreFellowship MemberEvidence (max_values: None, max_size: Some(16429), added: 18904, mode: MaxEncodedLen) fn submit_evidence() -> Weight { // Proof Size summary in bytes: // Measured: `79` // Estimated: `19894` - // Minimum execution time: 24_016_000 picoseconds. - Weight::from_parts(24_607_000, 19894) + // Minimum execution time: 26_033_000 picoseconds. + Weight::from_parts(26_612_000, 19894) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/democracy/src/weights.rs b/substrate/frame/democracy/src/weights.rs index d6097922a82..241f6c3cb38 100644 --- a/substrate/frame/democracy/src/weights.rs +++ b/substrate/frame/democracy/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_democracy` +//! Autogenerated weights for pallet_democracy //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/democracy/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/democracy/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_democracy`. +/// Weight functions needed for pallet_democracy. pub trait WeightInfo { fn propose() -> Weight; fn second() -> Weight; @@ -81,916 +82,904 @@ pub trait WeightInfo { fn clear_referendum_metadata() -> Weight; } -/// Weights for `pallet_democracy` using the Substrate node and recommended hardware. +/// Weights for pallet_democracy using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Democracy::PublicPropCount` (r:1 w:1) - /// Proof: `Democracy::PublicPropCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Democracy::PublicProps` (r:1 w:1) - /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) - /// Storage: `Democracy::Blacklist` (r:1 w:0) - /// Proof: `Democracy::Blacklist` (`max_values`: None, `max_size`: Some(3238), added: 5713, mode: `MaxEncodedLen`) - /// Storage: `Democracy::DepositOf` (r:0 w:1) - /// Proof: `Democracy::DepositOf` (`max_values`: None, `max_size`: Some(3230), added: 5705, mode: `MaxEncodedLen`) + /// Storage: Democracy PublicPropCount (r:1 w:1) + /// Proof: Democracy PublicPropCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy PublicProps (r:1 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:1 w:0) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) + /// Storage: Democracy DepositOf (r:0 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) fn propose() -> Weight { // Proof Size summary in bytes: - // Measured: `4834` + // Measured: `4801` // Estimated: `18187` - // Minimum execution time: 39_930_000 picoseconds. - Weight::from_parts(41_746_000, 18187) + // Minimum execution time: 49_339_000 picoseconds. + Weight::from_parts(50_942_000, 18187) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Democracy::DepositOf` (r:1 w:1) - /// Proof: `Democracy::DepositOf` (`max_values`: None, `max_size`: Some(3230), added: 5705, mode: `MaxEncodedLen`) + /// Storage: Democracy DepositOf (r:1 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) fn second() -> Weight { // Proof Size summary in bytes: - // Measured: `3589` + // Measured: `3556` // Estimated: `6695` - // Minimum execution time: 36_490_000 picoseconds. - Weight::from_parts(37_615_000, 6695) + // Minimum execution time: 43_291_000 picoseconds. + Weight::from_parts(44_856_000, 6695) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Democracy::ReferendumInfoOf` (r:1 w:1) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) - /// Storage: `Democracy::VotingOf` (r:1 w:1) - /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn vote_new() -> Weight { // Proof Size summary in bytes: - // Measured: `3503` + // Measured: `3470` // Estimated: `7260` - // Minimum execution time: 54_257_000 picoseconds. - Weight::from_parts(55_912_000, 7260) + // Minimum execution time: 61_890_000 picoseconds. + Weight::from_parts(63_626_000, 7260) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Democracy::ReferendumInfoOf` (r:1 w:1) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) - /// Storage: `Democracy::VotingOf` (r:1 w:1) - /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn vote_existing() -> Weight { // Proof Size summary in bytes: - // Measured: `3525` + // Measured: `3492` // Estimated: `7260` - // Minimum execution time: 56_878_000 picoseconds. - Weight::from_parts(58_796_000, 7260) + // Minimum execution time: 67_802_000 picoseconds. + Weight::from_parts(69_132_000, 7260) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Democracy::ReferendumInfoOf` (r:1 w:1) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) - /// Storage: `Democracy::Cancellations` (r:1 w:1) - /// Proof: `Democracy::Cancellations` (`max_values`: None, `max_size`: Some(33), added: 2508, mode: `MaxEncodedLen`) - /// Storage: `Democracy::MetadataOf` (r:1 w:1) - /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy Cancellations (r:1 w:1) + /// Proof: Democracy Cancellations (max_values: None, max_size: Some(33), added: 2508, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn emergency_cancel() -> Weight { // Proof Size summary in bytes: - // Measured: `399` + // Measured: `366` // Estimated: `3666` - // Minimum execution time: 22_700_000 picoseconds. - Weight::from_parts(23_539_000, 3666) + // Minimum execution time: 25_757_000 picoseconds. + Weight::from_parts(27_226_000, 3666) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Democracy::PublicProps` (r:1 w:1) - /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) - /// Storage: `Democracy::DepositOf` (r:1 w:1) - /// Proof: `Democracy::DepositOf` (`max_values`: None, `max_size`: Some(3230), added: 5705, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Democracy::MetadataOf` (r:3 w:1) - /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) - /// Storage: `Democracy::NextExternal` (r:1 w:1) - /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) - /// Storage: `Democracy::ReferendumInfoOf` (r:1 w:1) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) - /// Storage: `Democracy::Blacklist` (r:0 w:1) - /// Proof: `Democracy::Blacklist` (`max_values`: None, `max_size`: Some(3238), added: 5713, mode: `MaxEncodedLen`) + /// Storage: Democracy PublicProps (r:1 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy DepositOf (r:1 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:3 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:0 w:1) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn blacklist() -> Weight { // Proof Size summary in bytes: - // Measured: `5943` + // Measured: `5910` // Estimated: `18187` - // Minimum execution time: 95_398_000 picoseconds. - Weight::from_parts(97_261_000, 18187) + // Minimum execution time: 113_060_000 picoseconds. + Weight::from_parts(114_813_000, 18187) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } - /// Storage: `Democracy::NextExternal` (r:1 w:1) - /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) - /// Storage: `Democracy::Blacklist` (r:1 w:0) - /// Proof: `Democracy::Blacklist` (`max_values`: None, `max_size`: Some(3238), added: 5713, mode: `MaxEncodedLen`) + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:1 w:0) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn external_propose() -> Weight { // Proof Size summary in bytes: - // Measured: `3449` + // Measured: `3416` // Estimated: `6703` - // Minimum execution time: 11_745_000 picoseconds. - Weight::from_parts(12_304_000, 6703) + // Minimum execution time: 13_413_000 picoseconds. + Weight::from_parts(13_794_000, 6703) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Democracy::NextExternal` (r:0 w:1) - /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) + /// Storage: Democracy NextExternal (r:0 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) fn external_propose_majority() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_710_000 picoseconds. - Weight::from_parts(2_918_000, 0) + // Minimum execution time: 3_213_000 picoseconds. + Weight::from_parts(3_429_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Democracy::NextExternal` (r:0 w:1) - /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) + /// Storage: Democracy NextExternal (r:0 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) fn external_propose_default() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_664_000 picoseconds. - Weight::from_parts(2_776_000, 0) + // Minimum execution time: 3_280_000 picoseconds. + Weight::from_parts(3_389_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Democracy::NextExternal` (r:1 w:1) - /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) - /// Storage: `Democracy::ReferendumCount` (r:1 w:1) - /// Proof: `Democracy::ReferendumCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Democracy::MetadataOf` (r:1 w:2) - /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) - /// Storage: `Democracy::ReferendumInfoOf` (r:0 w:1) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumCount (r:1 w:1) + /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:2) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:0 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn fast_track() -> Weight { // Proof Size summary in bytes: - // Measured: `319` + // Measured: `286` // Estimated: `3518` - // Minimum execution time: 22_585_000 picoseconds. - Weight::from_parts(23_689_000, 3518) + // Minimum execution time: 28_142_000 picoseconds. + Weight::from_parts(28_862_000, 3518) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: `Democracy::NextExternal` (r:1 w:1) - /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) - /// Storage: `Democracy::Blacklist` (r:1 w:1) - /// Proof: `Democracy::Blacklist` (`max_values`: None, `max_size`: Some(3238), added: 5713, mode: `MaxEncodedLen`) - /// Storage: `Democracy::MetadataOf` (r:1 w:1) - /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:1 w:1) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn veto_external() -> Weight { // Proof Size summary in bytes: - // Measured: `3552` + // Measured: `3519` // Estimated: `6703` - // Minimum execution time: 26_391_000 picoseconds. - Weight::from_parts(27_141_000, 6703) + // Minimum execution time: 32_395_000 picoseconds. + Weight::from_parts(33_617_000, 6703) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Democracy::PublicProps` (r:1 w:1) - /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) - /// Storage: `Democracy::DepositOf` (r:1 w:1) - /// Proof: `Democracy::DepositOf` (`max_values`: None, `max_size`: Some(3230), added: 5705, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Democracy::MetadataOf` (r:1 w:1) - /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: Democracy PublicProps (r:1 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy DepositOf (r:1 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn cancel_proposal() -> Weight { // Proof Size summary in bytes: - // Measured: `5854` + // Measured: `5821` // Estimated: `18187` - // Minimum execution time: 77_905_000 picoseconds. - Weight::from_parts(79_628_000, 18187) + // Minimum execution time: 92_255_000 picoseconds. + Weight::from_parts(93_704_000, 18187) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: `Democracy::MetadataOf` (r:1 w:1) - /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) - /// Storage: `Democracy::ReferendumInfoOf` (r:0 w:1) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:0 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn cancel_referendum() -> Weight { // Proof Size summary in bytes: - // Measured: `304` + // Measured: `271` // Estimated: `3518` - // Minimum execution time: 15_735_000 picoseconds. - Weight::from_parts(16_525_000, 3518) + // Minimum execution time: 19_623_000 picoseconds. + Weight::from_parts(20_545_000, 3518) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Democracy::LowestUnbaked` (r:1 w:1) - /// Proof: `Democracy::LowestUnbaked` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Democracy::ReferendumCount` (r:1 w:0) - /// Proof: `Democracy::ReferendumCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Democracy::ReferendumInfoOf` (r:99 w:0) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) + /// Storage: Democracy LowestUnbaked (r:1 w:1) + /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumCount (r:1 w:0) + /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:0) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn on_initialize_base(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `277 + r * (86 ±0)` + // Measured: `244 + r * (86 ±0)` // Estimated: `1489 + r * (2676 ±0)` - // Minimum execution time: 5_274_000 picoseconds. - Weight::from_parts(6_162_399, 1489) - // Standard Error: 6_924 - .saturating_add(Weight::from_parts(3_186_702, 0).saturating_mul(r.into())) + // Minimum execution time: 7_032_000 picoseconds. + Weight::from_parts(7_931_421, 1489) + // Standard Error: 7_395 + .saturating_add(Weight::from_parts(3_236_964, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) } - /// Storage: `Democracy::LowestUnbaked` (r:1 w:1) - /// Proof: `Democracy::LowestUnbaked` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Democracy::ReferendumCount` (r:1 w:0) - /// Proof: `Democracy::ReferendumCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Democracy::LastTabledWasExternal` (r:1 w:0) - /// Proof: `Democracy::LastTabledWasExternal` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) - /// Storage: `Democracy::NextExternal` (r:1 w:0) - /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) - /// Storage: `Democracy::PublicProps` (r:1 w:0) - /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) - /// Storage: `Democracy::ReferendumInfoOf` (r:99 w:0) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) + /// Storage: Democracy LowestUnbaked (r:1 w:1) + /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumCount (r:1 w:0) + /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy LastTabledWasExternal (r:1 w:0) + /// Proof: Democracy LastTabledWasExternal (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: Democracy NextExternal (r:1 w:0) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy PublicProps (r:1 w:0) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:0) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `277 + r * (86 ±0)` + // Measured: `244 + r * (86 ±0)` // Estimated: `18187 + r * (2676 ±0)` - // Minimum execution time: 7_950_000 picoseconds. - Weight::from_parts(7_381_228, 18187) - // Standard Error: 6_650 - .saturating_add(Weight::from_parts(3_198_515, 0).saturating_mul(r.into())) + // Minimum execution time: 10_524_000 picoseconds. + Weight::from_parts(10_369_064, 18187) + // Standard Error: 8_385 + .saturating_add(Weight::from_parts(3_242_334, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) } - /// Storage: `Democracy::VotingOf` (r:3 w:3) - /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, mode: `MaxEncodedLen`) - /// Storage: `Democracy::ReferendumInfoOf` (r:99 w:99) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: Democracy VotingOf (r:3 w:3) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:99) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn delegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `863 + r * (108 ±0)` + // Measured: `830 + r * (108 ±0)` // Estimated: `19800 + r * (2676 ±0)` - // Minimum execution time: 40_109_000 picoseconds. - Weight::from_parts(43_164_384, 19800) - // Standard Error: 7_267 - .saturating_add(Weight::from_parts(4_161_526, 0).saturating_mul(r.into())) + // Minimum execution time: 46_106_000 picoseconds. + Weight::from_parts(48_936_654, 19800) + // Standard Error: 8_879 + .saturating_add(Weight::from_parts(4_708_141, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) } - /// Storage: `Democracy::VotingOf` (r:2 w:2) - /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, mode: `MaxEncodedLen`) - /// Storage: `Democracy::ReferendumInfoOf` (r:99 w:99) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) + /// Storage: Democracy VotingOf (r:2 w:2) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:99) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn undelegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `526 + r * (108 ±0)` + // Measured: `493 + r * (108 ±0)` // Estimated: `13530 + r * (2676 ±0)` - // Minimum execution time: 17_466_000 picoseconds. - Weight::from_parts(18_004_456, 13530) - // Standard Error: 6_327 - .saturating_add(Weight::from_parts(4_194_583, 0).saturating_mul(r.into())) + // Minimum execution time: 21_078_000 picoseconds. + Weight::from_parts(22_732_737, 13530) + // Standard Error: 7_969 + .saturating_add(Weight::from_parts(4_626_458, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) } - /// Storage: `Democracy::PublicProps` (r:0 w:1) - /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) + /// Storage: Democracy PublicProps (r:0 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) fn clear_public_proposals() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_824_000 picoseconds. - Weight::from_parts(2_948_000, 0) + // Minimum execution time: 3_229_000 picoseconds. + Weight::from_parts(3_415_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Democracy::VotingOf` (r:1 w:1) - /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn unlock_remove(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `596` + // Measured: `563` // Estimated: `7260` - // Minimum execution time: 23_373_000 picoseconds. - Weight::from_parts(34_306_582, 7260) - // Standard Error: 2_849 - .saturating_add(Weight::from_parts(85_027, 0).saturating_mul(r.into())) + // Minimum execution time: 25_735_000 picoseconds. + Weight::from_parts(41_341_468, 7260) + // Standard Error: 3_727 + .saturating_add(Weight::from_parts(94_755, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Democracy::VotingOf` (r:1 w:1) - /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn unlock_set(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `597 + r * (22 ±0)` + // Measured: `564 + r * (22 ±0)` // Estimated: `7260` - // Minimum execution time: 31_574_000 picoseconds. - Weight::from_parts(33_906_658, 7260) - // Standard Error: 1_514 - .saturating_add(Weight::from_parts(124_471, 0).saturating_mul(r.into())) + // Minimum execution time: 36_233_000 picoseconds. + Weight::from_parts(39_836_017, 7260) + // Standard Error: 1_791 + .saturating_add(Weight::from_parts(132_158, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Democracy::ReferendumInfoOf` (r:1 w:1) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) - /// Storage: `Democracy::VotingOf` (r:1 w:1) - /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, mode: `MaxEncodedLen`) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) /// The range of component `r` is `[1, 100]`. fn remove_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `761 + r * (26 ±0)` + // Measured: `728 + r * (26 ±0)` // Estimated: `7260` - // Minimum execution time: 15_204_000 picoseconds. - Weight::from_parts(18_405_879, 7260) - // Standard Error: 1_851 - .saturating_add(Weight::from_parts(119_018, 0).saturating_mul(r.into())) + // Minimum execution time: 16_081_000 picoseconds. + Weight::from_parts(19_624_101, 7260) + // Standard Error: 1_639 + .saturating_add(Weight::from_parts(133_630, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Democracy::ReferendumInfoOf` (r:1 w:1) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) - /// Storage: `Democracy::VotingOf` (r:1 w:1) - /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, mode: `MaxEncodedLen`) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) /// The range of component `r` is `[1, 100]`. fn remove_other_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `761 + r * (26 ±0)` + // Measured: `728 + r * (26 ±0)` // Estimated: `7260` - // Minimum execution time: 15_120_000 picoseconds. - Weight::from_parts(18_282_222, 7260) - // Standard Error: 1_669 - .saturating_add(Weight::from_parts(127_649, 0).saturating_mul(r.into())) + // Minimum execution time: 15_634_000 picoseconds. + Weight::from_parts(19_573_407, 7260) + // Standard Error: 1_790 + .saturating_add(Weight::from_parts(139_707, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Democracy::NextExternal` (r:1 w:0) - /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:0) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Democracy::MetadataOf` (r:0 w:1) - /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: Democracy NextExternal (r:1 w:0) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:0 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn set_external_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `456` + // Measured: `356` // Estimated: `3556` - // Minimum execution time: 17_351_000 picoseconds. - Weight::from_parts(17_964_000, 3556) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Minimum execution time: 18_344_000 picoseconds. + Weight::from_parts(18_727_000, 3556) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Democracy::NextExternal` (r:1 w:0) - /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) - /// Storage: `Democracy::MetadataOf` (r:1 w:1) - /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: Democracy NextExternal (r:1 w:0) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn clear_external_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `319` + // Measured: `286` // Estimated: `3518` - // Minimum execution time: 13_669_000 picoseconds. - Weight::from_parts(14_410_000, 3518) + // Minimum execution time: 16_497_000 picoseconds. + Weight::from_parts(16_892_000, 3518) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Democracy::PublicProps` (r:1 w:0) - /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:0) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Democracy::MetadataOf` (r:0 w:1) - /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: Democracy PublicProps (r:1 w:0) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:0 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn set_proposal_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `4988` + // Measured: `4888` // Estimated: `18187` - // Minimum execution time: 39_162_000 picoseconds. - Weight::from_parts(40_109_000, 18187) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Minimum execution time: 39_517_000 picoseconds. + Weight::from_parts(40_632_000, 18187) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Democracy::PublicProps` (r:1 w:0) - /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) - /// Storage: `Democracy::MetadataOf` (r:1 w:1) - /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: Democracy PublicProps (r:1 w:0) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn clear_proposal_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `4855` + // Measured: `4822` // Estimated: `18187` - // Minimum execution time: 34_141_000 picoseconds. - Weight::from_parts(34_732_000, 18187) + // Minimum execution time: 37_108_000 picoseconds. + Weight::from_parts(37_599_000, 18187) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:0) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Democracy::MetadataOf` (r:0 w:1) - /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:0 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn set_referendum_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `211` + // Measured: `144` // Estimated: `3556` - // Minimum execution time: 13_413_000 picoseconds. - Weight::from_parts(14_039_000, 3556) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Minimum execution time: 13_997_000 picoseconds. + Weight::from_parts(14_298_000, 3556) + .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Democracy::ReferendumInfoOf` (r:1 w:0) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) - /// Storage: `Democracy::MetadataOf` (r:1 w:1) - /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: Democracy ReferendumInfoOf (r:1 w:0) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn clear_referendum_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `335` + // Measured: `302` // Estimated: `3666` - // Minimum execution time: 16_010_000 picoseconds. - Weight::from_parts(16_474_000, 3666) + // Minimum execution time: 18_122_000 picoseconds. + Weight::from_parts(18_655_000, 3666) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Democracy::PublicPropCount` (r:1 w:1) - /// Proof: `Democracy::PublicPropCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Democracy::PublicProps` (r:1 w:1) - /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) - /// Storage: `Democracy::Blacklist` (r:1 w:0) - /// Proof: `Democracy::Blacklist` (`max_values`: None, `max_size`: Some(3238), added: 5713, mode: `MaxEncodedLen`) - /// Storage: `Democracy::DepositOf` (r:0 w:1) - /// Proof: `Democracy::DepositOf` (`max_values`: None, `max_size`: Some(3230), added: 5705, mode: `MaxEncodedLen`) + /// Storage: Democracy PublicPropCount (r:1 w:1) + /// Proof: Democracy PublicPropCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy PublicProps (r:1 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:1 w:0) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) + /// Storage: Democracy DepositOf (r:0 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) fn propose() -> Weight { // Proof Size summary in bytes: - // Measured: `4834` + // Measured: `4801` // Estimated: `18187` - // Minimum execution time: 39_930_000 picoseconds. - Weight::from_parts(41_746_000, 18187) + // Minimum execution time: 49_339_000 picoseconds. + Weight::from_parts(50_942_000, 18187) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Democracy::DepositOf` (r:1 w:1) - /// Proof: `Democracy::DepositOf` (`max_values`: None, `max_size`: Some(3230), added: 5705, mode: `MaxEncodedLen`) + /// Storage: Democracy DepositOf (r:1 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) fn second() -> Weight { // Proof Size summary in bytes: - // Measured: `3589` + // Measured: `3556` // Estimated: `6695` - // Minimum execution time: 36_490_000 picoseconds. - Weight::from_parts(37_615_000, 6695) + // Minimum execution time: 43_291_000 picoseconds. + Weight::from_parts(44_856_000, 6695) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Democracy::ReferendumInfoOf` (r:1 w:1) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) - /// Storage: `Democracy::VotingOf` (r:1 w:1) - /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn vote_new() -> Weight { // Proof Size summary in bytes: - // Measured: `3503` + // Measured: `3470` // Estimated: `7260` - // Minimum execution time: 54_257_000 picoseconds. - Weight::from_parts(55_912_000, 7260) + // Minimum execution time: 61_890_000 picoseconds. + Weight::from_parts(63_626_000, 7260) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Democracy::ReferendumInfoOf` (r:1 w:1) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) - /// Storage: `Democracy::VotingOf` (r:1 w:1) - /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn vote_existing() -> Weight { // Proof Size summary in bytes: - // Measured: `3525` + // Measured: `3492` // Estimated: `7260` - // Minimum execution time: 56_878_000 picoseconds. - Weight::from_parts(58_796_000, 7260) + // Minimum execution time: 67_802_000 picoseconds. + Weight::from_parts(69_132_000, 7260) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Democracy::ReferendumInfoOf` (r:1 w:1) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) - /// Storage: `Democracy::Cancellations` (r:1 w:1) - /// Proof: `Democracy::Cancellations` (`max_values`: None, `max_size`: Some(33), added: 2508, mode: `MaxEncodedLen`) - /// Storage: `Democracy::MetadataOf` (r:1 w:1) - /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy Cancellations (r:1 w:1) + /// Proof: Democracy Cancellations (max_values: None, max_size: Some(33), added: 2508, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn emergency_cancel() -> Weight { // Proof Size summary in bytes: - // Measured: `399` + // Measured: `366` // Estimated: `3666` - // Minimum execution time: 22_700_000 picoseconds. - Weight::from_parts(23_539_000, 3666) + // Minimum execution time: 25_757_000 picoseconds. + Weight::from_parts(27_226_000, 3666) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Democracy::PublicProps` (r:1 w:1) - /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) - /// Storage: `Democracy::DepositOf` (r:1 w:1) - /// Proof: `Democracy::DepositOf` (`max_values`: None, `max_size`: Some(3230), added: 5705, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Democracy::MetadataOf` (r:3 w:1) - /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) - /// Storage: `Democracy::NextExternal` (r:1 w:1) - /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) - /// Storage: `Democracy::ReferendumInfoOf` (r:1 w:1) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) - /// Storage: `Democracy::Blacklist` (r:0 w:1) - /// Proof: `Democracy::Blacklist` (`max_values`: None, `max_size`: Some(3238), added: 5713, mode: `MaxEncodedLen`) + /// Storage: Democracy PublicProps (r:1 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy DepositOf (r:1 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:3 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:0 w:1) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn blacklist() -> Weight { // Proof Size summary in bytes: - // Measured: `5943` + // Measured: `5910` // Estimated: `18187` - // Minimum execution time: 95_398_000 picoseconds. - Weight::from_parts(97_261_000, 18187) + // Minimum execution time: 113_060_000 picoseconds. + Weight::from_parts(114_813_000, 18187) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } - /// Storage: `Democracy::NextExternal` (r:1 w:1) - /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) - /// Storage: `Democracy::Blacklist` (r:1 w:0) - /// Proof: `Democracy::Blacklist` (`max_values`: None, `max_size`: Some(3238), added: 5713, mode: `MaxEncodedLen`) + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:1 w:0) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn external_propose() -> Weight { // Proof Size summary in bytes: - // Measured: `3449` + // Measured: `3416` // Estimated: `6703` - // Minimum execution time: 11_745_000 picoseconds. - Weight::from_parts(12_304_000, 6703) + // Minimum execution time: 13_413_000 picoseconds. + Weight::from_parts(13_794_000, 6703) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Democracy::NextExternal` (r:0 w:1) - /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) + /// Storage: Democracy NextExternal (r:0 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) fn external_propose_majority() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_710_000 picoseconds. - Weight::from_parts(2_918_000, 0) + // Minimum execution time: 3_213_000 picoseconds. + Weight::from_parts(3_429_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Democracy::NextExternal` (r:0 w:1) - /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) + /// Storage: Democracy NextExternal (r:0 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) fn external_propose_default() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_664_000 picoseconds. - Weight::from_parts(2_776_000, 0) + // Minimum execution time: 3_280_000 picoseconds. + Weight::from_parts(3_389_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Democracy::NextExternal` (r:1 w:1) - /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) - /// Storage: `Democracy::ReferendumCount` (r:1 w:1) - /// Proof: `Democracy::ReferendumCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Democracy::MetadataOf` (r:1 w:2) - /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) - /// Storage: `Democracy::ReferendumInfoOf` (r:0 w:1) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumCount (r:1 w:1) + /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:2) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:0 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn fast_track() -> Weight { // Proof Size summary in bytes: - // Measured: `319` + // Measured: `286` // Estimated: `3518` - // Minimum execution time: 22_585_000 picoseconds. - Weight::from_parts(23_689_000, 3518) + // Minimum execution time: 28_142_000 picoseconds. + Weight::from_parts(28_862_000, 3518) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: `Democracy::NextExternal` (r:1 w:1) - /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) - /// Storage: `Democracy::Blacklist` (r:1 w:1) - /// Proof: `Democracy::Blacklist` (`max_values`: None, `max_size`: Some(3238), added: 5713, mode: `MaxEncodedLen`) - /// Storage: `Democracy::MetadataOf` (r:1 w:1) - /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: Democracy NextExternal (r:1 w:1) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy Blacklist (r:1 w:1) + /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn veto_external() -> Weight { // Proof Size summary in bytes: - // Measured: `3552` + // Measured: `3519` // Estimated: `6703` - // Minimum execution time: 26_391_000 picoseconds. - Weight::from_parts(27_141_000, 6703) + // Minimum execution time: 32_395_000 picoseconds. + Weight::from_parts(33_617_000, 6703) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Democracy::PublicProps` (r:1 w:1) - /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) - /// Storage: `Democracy::DepositOf` (r:1 w:1) - /// Proof: `Democracy::DepositOf` (`max_values`: None, `max_size`: Some(3230), added: 5705, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Democracy::MetadataOf` (r:1 w:1) - /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: Democracy PublicProps (r:1 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy DepositOf (r:1 w:1) + /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn cancel_proposal() -> Weight { // Proof Size summary in bytes: - // Measured: `5854` + // Measured: `5821` // Estimated: `18187` - // Minimum execution time: 77_905_000 picoseconds. - Weight::from_parts(79_628_000, 18187) + // Minimum execution time: 92_255_000 picoseconds. + Weight::from_parts(93_704_000, 18187) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: `Democracy::MetadataOf` (r:1 w:1) - /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) - /// Storage: `Democracy::ReferendumInfoOf` (r:0 w:1) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:0 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn cancel_referendum() -> Weight { // Proof Size summary in bytes: - // Measured: `304` + // Measured: `271` // Estimated: `3518` - // Minimum execution time: 15_735_000 picoseconds. - Weight::from_parts(16_525_000, 3518) + // Minimum execution time: 19_623_000 picoseconds. + Weight::from_parts(20_545_000, 3518) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Democracy::LowestUnbaked` (r:1 w:1) - /// Proof: `Democracy::LowestUnbaked` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Democracy::ReferendumCount` (r:1 w:0) - /// Proof: `Democracy::ReferendumCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Democracy::ReferendumInfoOf` (r:99 w:0) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) + /// Storage: Democracy LowestUnbaked (r:1 w:1) + /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumCount (r:1 w:0) + /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:0) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn on_initialize_base(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `277 + r * (86 ±0)` + // Measured: `244 + r * (86 ±0)` // Estimated: `1489 + r * (2676 ±0)` - // Minimum execution time: 5_274_000 picoseconds. - Weight::from_parts(6_162_399, 1489) - // Standard Error: 6_924 - .saturating_add(Weight::from_parts(3_186_702, 0).saturating_mul(r.into())) + // Minimum execution time: 7_032_000 picoseconds. + Weight::from_parts(7_931_421, 1489) + // Standard Error: 7_395 + .saturating_add(Weight::from_parts(3_236_964, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) } - /// Storage: `Democracy::LowestUnbaked` (r:1 w:1) - /// Proof: `Democracy::LowestUnbaked` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Democracy::ReferendumCount` (r:1 w:0) - /// Proof: `Democracy::ReferendumCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Democracy::LastTabledWasExternal` (r:1 w:0) - /// Proof: `Democracy::LastTabledWasExternal` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) - /// Storage: `Democracy::NextExternal` (r:1 w:0) - /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) - /// Storage: `Democracy::PublicProps` (r:1 w:0) - /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) - /// Storage: `Democracy::ReferendumInfoOf` (r:99 w:0) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) + /// Storage: Democracy LowestUnbaked (r:1 w:1) + /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumCount (r:1 w:0) + /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy LastTabledWasExternal (r:1 w:0) + /// Proof: Democracy LastTabledWasExternal (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: Democracy NextExternal (r:1 w:0) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy PublicProps (r:1 w:0) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:0) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `277 + r * (86 ±0)` + // Measured: `244 + r * (86 ±0)` // Estimated: `18187 + r * (2676 ±0)` - // Minimum execution time: 7_950_000 picoseconds. - Weight::from_parts(7_381_228, 18187) - // Standard Error: 6_650 - .saturating_add(Weight::from_parts(3_198_515, 0).saturating_mul(r.into())) + // Minimum execution time: 10_524_000 picoseconds. + Weight::from_parts(10_369_064, 18187) + // Standard Error: 8_385 + .saturating_add(Weight::from_parts(3_242_334, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) } - /// Storage: `Democracy::VotingOf` (r:3 w:3) - /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, mode: `MaxEncodedLen`) - /// Storage: `Democracy::ReferendumInfoOf` (r:99 w:99) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: Democracy VotingOf (r:3 w:3) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:99) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn delegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `863 + r * (108 ±0)` + // Measured: `830 + r * (108 ±0)` // Estimated: `19800 + r * (2676 ±0)` - // Minimum execution time: 40_109_000 picoseconds. - Weight::from_parts(43_164_384, 19800) - // Standard Error: 7_267 - .saturating_add(Weight::from_parts(4_161_526, 0).saturating_mul(r.into())) + // Minimum execution time: 46_106_000 picoseconds. + Weight::from_parts(48_936_654, 19800) + // Standard Error: 8_879 + .saturating_add(Weight::from_parts(4_708_141, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) } - /// Storage: `Democracy::VotingOf` (r:2 w:2) - /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, mode: `MaxEncodedLen`) - /// Storage: `Democracy::ReferendumInfoOf` (r:99 w:99) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) + /// Storage: Democracy VotingOf (r:2 w:2) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Democracy ReferendumInfoOf (r:99 w:99) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn undelegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `526 + r * (108 ±0)` + // Measured: `493 + r * (108 ±0)` // Estimated: `13530 + r * (2676 ±0)` - // Minimum execution time: 17_466_000 picoseconds. - Weight::from_parts(18_004_456, 13530) - // Standard Error: 6_327 - .saturating_add(Weight::from_parts(4_194_583, 0).saturating_mul(r.into())) + // Minimum execution time: 21_078_000 picoseconds. + Weight::from_parts(22_732_737, 13530) + // Standard Error: 7_969 + .saturating_add(Weight::from_parts(4_626_458, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 2676).saturating_mul(r.into())) } - /// Storage: `Democracy::PublicProps` (r:0 w:1) - /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) + /// Storage: Democracy PublicProps (r:0 w:1) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) fn clear_public_proposals() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_824_000 picoseconds. - Weight::from_parts(2_948_000, 0) + // Minimum execution time: 3_229_000 picoseconds. + Weight::from_parts(3_415_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Democracy::VotingOf` (r:1 w:1) - /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn unlock_remove(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `596` + // Measured: `563` // Estimated: `7260` - // Minimum execution time: 23_373_000 picoseconds. - Weight::from_parts(34_306_582, 7260) - // Standard Error: 2_849 - .saturating_add(Weight::from_parts(85_027, 0).saturating_mul(r.into())) + // Minimum execution time: 25_735_000 picoseconds. + Weight::from_parts(41_341_468, 7260) + // Standard Error: 3_727 + .saturating_add(Weight::from_parts(94_755, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Democracy::VotingOf` (r:1 w:1) - /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `r` is `[0, 99]`. fn unlock_set(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `597 + r * (22 ±0)` + // Measured: `564 + r * (22 ±0)` // Estimated: `7260` - // Minimum execution time: 31_574_000 picoseconds. - Weight::from_parts(33_906_658, 7260) - // Standard Error: 1_514 - .saturating_add(Weight::from_parts(124_471, 0).saturating_mul(r.into())) + // Minimum execution time: 36_233_000 picoseconds. + Weight::from_parts(39_836_017, 7260) + // Standard Error: 1_791 + .saturating_add(Weight::from_parts(132_158, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Democracy::ReferendumInfoOf` (r:1 w:1) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) - /// Storage: `Democracy::VotingOf` (r:1 w:1) - /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, mode: `MaxEncodedLen`) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) /// The range of component `r` is `[1, 100]`. fn remove_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `761 + r * (26 ±0)` + // Measured: `728 + r * (26 ±0)` // Estimated: `7260` - // Minimum execution time: 15_204_000 picoseconds. - Weight::from_parts(18_405_879, 7260) - // Standard Error: 1_851 - .saturating_add(Weight::from_parts(119_018, 0).saturating_mul(r.into())) + // Minimum execution time: 16_081_000 picoseconds. + Weight::from_parts(19_624_101, 7260) + // Standard Error: 1_639 + .saturating_add(Weight::from_parts(133_630, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Democracy::ReferendumInfoOf` (r:1 w:1) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) - /// Storage: `Democracy::VotingOf` (r:1 w:1) - /// Proof: `Democracy::VotingOf` (`max_values`: None, `max_size`: Some(3795), added: 6270, mode: `MaxEncodedLen`) + /// Storage: Democracy ReferendumInfoOf (r:1 w:1) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy VotingOf (r:1 w:1) + /// Proof: Democracy VotingOf (max_values: None, max_size: Some(3795), added: 6270, mode: MaxEncodedLen) /// The range of component `r` is `[1, 100]`. fn remove_other_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `761 + r * (26 ±0)` + // Measured: `728 + r * (26 ±0)` // Estimated: `7260` - // Minimum execution time: 15_120_000 picoseconds. - Weight::from_parts(18_282_222, 7260) - // Standard Error: 1_669 - .saturating_add(Weight::from_parts(127_649, 0).saturating_mul(r.into())) + // Minimum execution time: 15_634_000 picoseconds. + Weight::from_parts(19_573_407, 7260) + // Standard Error: 1_790 + .saturating_add(Weight::from_parts(139_707, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Democracy::NextExternal` (r:1 w:0) - /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:0) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Democracy::MetadataOf` (r:0 w:1) - /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: Democracy NextExternal (r:1 w:0) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:0 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn set_external_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `456` + // Measured: `356` // Estimated: `3556` - // Minimum execution time: 17_351_000 picoseconds. - Weight::from_parts(17_964_000, 3556) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Minimum execution time: 18_344_000 picoseconds. + Weight::from_parts(18_727_000, 3556) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Democracy::NextExternal` (r:1 w:0) - /// Proof: `Democracy::NextExternal` (`max_values`: Some(1), `max_size`: Some(132), added: 627, mode: `MaxEncodedLen`) - /// Storage: `Democracy::MetadataOf` (r:1 w:1) - /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: Democracy NextExternal (r:1 w:0) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn clear_external_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `319` + // Measured: `286` // Estimated: `3518` - // Minimum execution time: 13_669_000 picoseconds. - Weight::from_parts(14_410_000, 3518) + // Minimum execution time: 16_497_000 picoseconds. + Weight::from_parts(16_892_000, 3518) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Democracy::PublicProps` (r:1 w:0) - /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:0) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Democracy::MetadataOf` (r:0 w:1) - /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: Democracy PublicProps (r:1 w:0) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:0 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn set_proposal_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `4988` + // Measured: `4888` // Estimated: `18187` - // Minimum execution time: 39_162_000 picoseconds. - Weight::from_parts(40_109_000, 18187) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Minimum execution time: 39_517_000 picoseconds. + Weight::from_parts(40_632_000, 18187) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Democracy::PublicProps` (r:1 w:0) - /// Proof: `Democracy::PublicProps` (`max_values`: Some(1), `max_size`: Some(16702), added: 17197, mode: `MaxEncodedLen`) - /// Storage: `Democracy::MetadataOf` (r:1 w:1) - /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: Democracy PublicProps (r:1 w:0) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn clear_proposal_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `4855` + // Measured: `4822` // Estimated: `18187` - // Minimum execution time: 34_141_000 picoseconds. - Weight::from_parts(34_732_000, 18187) + // Minimum execution time: 37_108_000 picoseconds. + Weight::from_parts(37_599_000, 18187) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:0) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Democracy::MetadataOf` (r:0 w:1) - /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:0 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn set_referendum_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `211` + // Measured: `144` // Estimated: `3556` - // Minimum execution time: 13_413_000 picoseconds. - Weight::from_parts(14_039_000, 3556) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Minimum execution time: 13_997_000 picoseconds. + Weight::from_parts(14_298_000, 3556) + .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Democracy::ReferendumInfoOf` (r:1 w:0) - /// Proof: `Democracy::ReferendumInfoOf` (`max_values`: None, `max_size`: Some(201), added: 2676, mode: `MaxEncodedLen`) - /// Storage: `Democracy::MetadataOf` (r:1 w:1) - /// Proof: `Democracy::MetadataOf` (`max_values`: None, `max_size`: Some(53), added: 2528, mode: `MaxEncodedLen`) + /// Storage: Democracy ReferendumInfoOf (r:1 w:0) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn clear_referendum_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `335` + // Measured: `302` // Estimated: `3666` - // Minimum execution time: 16_010_000 picoseconds. - Weight::from_parts(16_474_000, 3666) + // Minimum execution time: 18_122_000 picoseconds. + Weight::from_parts(18_655_000, 3666) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/election-provider-multi-phase/src/mock.rs b/substrate/frame/election-provider-multi-phase/src/mock.rs index 312dc557090..18dcd7061c1 100644 --- a/substrate/frame/election-provider-multi-phase/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/src/mock.rs @@ -441,7 +441,7 @@ where type Extrinsic = Extrinsic; } -pub type Extrinsic = sp_runtime::generic::UncheckedExtrinsic; +pub type Extrinsic = sp_runtime::testing::TestXt; parameter_types! { pub MaxNominations: u32 = ::LIMIT as u32; diff --git a/substrate/frame/election-provider-multi-phase/src/unsigned.rs b/substrate/frame/election-provider-multi-phase/src/unsigned.rs index 94cfd059b6c..94348181334 100644 --- a/substrate/frame/election-provider-multi-phase/src/unsigned.rs +++ b/substrate/frame/election-provider-multi-phase/src/unsigned.rs @@ -1813,7 +1813,7 @@ mod tests { let encoded = pool.read().transactions[0].clone(); let extrinsic: Extrinsic = codec::Decode::decode(&mut &*encoded).unwrap(); - let call = extrinsic.function; + let call = extrinsic.call; assert!(matches!(call, RuntimeCall::MultiPhase(Call::submit_unsigned { .. }))); }) } @@ -1830,7 +1830,7 @@ mod tests { let encoded = pool.read().transactions[0].clone(); let extrinsic = Extrinsic::decode(&mut &*encoded).unwrap(); - let call = match extrinsic.function { + let call = match extrinsic.call { RuntimeCall::MultiPhase(call @ Call::submit_unsigned { .. }) => call, _ => panic!("bad call: unexpected submission"), }; diff --git a/substrate/frame/election-provider-multi-phase/src/weights.rs b/substrate/frame/election-provider-multi-phase/src/weights.rs index ed3e942716e..be578fac8c4 100644 --- a/substrate/frame/election-provider-multi-phase/src/weights.rs +++ b/substrate/frame/election-provider-multi-phase/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_election_provider_multi_phase` +//! Autogenerated weights for pallet_election_provider_multi_phase //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/election-provider-multi-phase/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/election-provider-multi-phase/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_election_provider_multi_phase`. +/// Weight functions needed for pallet_election_provider_multi_phase. pub trait WeightInfo { fn on_initialize_nothing() -> Weight; fn on_initialize_open_signed() -> Weight; @@ -63,171 +64,169 @@ pub trait WeightInfo { fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight; } -/// Weights for `pallet_election_provider_multi_phase` using the Substrate node and recommended hardware. +/// Weights for pallet_election_provider_multi_phase using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Staking::CurrentEra` (r:1 w:0) - /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::CurrentPlannedSession` (r:1 w:0) - /// Proof: `Staking::CurrentPlannedSession` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::ErasStartSessionIndex` (r:1 w:0) - /// Proof: `Staking::ErasStartSessionIndex` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) - /// Storage: `Babe::EpochIndex` (r:1 w:0) - /// Proof: `Babe::EpochIndex` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Babe::GenesisSlot` (r:1 w:0) - /// Proof: `Babe::GenesisSlot` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Babe::CurrentSlot` (r:1 w:0) - /// Proof: `Babe::CurrentSlot` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Staking::ForceEra` (r:1 w:0) - /// Proof: `Staking::ForceEra` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) - /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CurrentPlannedSession (r:1 w:0) + /// Proof: Staking CurrentPlannedSession (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ErasStartSessionIndex (r:1 w:0) + /// Proof: Staking ErasStartSessionIndex (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: Babe EpochIndex (r:1 w:0) + /// Proof: Babe EpochIndex (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Babe GenesisSlot (r:1 w:0) + /// Proof: Babe GenesisSlot (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Babe CurrentSlot (r:1 w:0) + /// Proof: Babe CurrentSlot (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Staking ForceEra (r:1 w:0) + /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) fn on_initialize_nothing() -> Weight { // Proof Size summary in bytes: - // Measured: `1061` + // Measured: `1028` // Estimated: `3481` - // Minimum execution time: 19_340_000 picoseconds. - Weight::from_parts(19_886_000, 3481) + // Minimum execution time: 22_089_000 picoseconds. + Weight::from_parts(22_677_000, 3481) .saturating_add(T::DbWeight::get().reads(8_u64)) } - /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:1) - /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) fn on_initialize_open_signed() -> Weight { // Proof Size summary in bytes: // Measured: `148` // Estimated: `1633` - // Minimum execution time: 8_067_000 picoseconds. - Weight::from_parts(8_508_000, 1633) + // Minimum execution time: 11_986_000 picoseconds. + Weight::from_parts(12_445_000, 1633) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:1) - /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) fn on_initialize_open_unsigned() -> Weight { // Proof Size summary in bytes: // Measured: `148` // Estimated: `1633` - // Minimum execution time: 8_810_000 picoseconds. - Weight::from_parts(9_061_000, 1633) + // Minimum execution time: 12_988_000 picoseconds. + Weight::from_parts(13_281_000, 1633) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ElectionProviderMultiPhase::QueuedSolution` (r:0 w:1) - /// Proof: `ElectionProviderMultiPhase::QueuedSolution` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) fn finalize_signed_phase_accept_solution() -> Weight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 24_339_000 picoseconds. - Weight::from_parts(25_322_000, 3593) + // Minimum execution time: 32_659_000 picoseconds. + Weight::from_parts(33_281_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn finalize_signed_phase_reject_solution() -> Weight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 16_635_000 picoseconds. - Weight::from_parts(17_497_000, 3593) + // Minimum execution time: 22_471_000 picoseconds. + Weight::from_parts(23_046_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `ElectionProviderMultiPhase::SnapshotMetadata` (r:0 w:1) - /// Proof: `ElectionProviderMultiPhase::SnapshotMetadata` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::DesiredTargets` (r:0 w:1) - /// Proof: `ElectionProviderMultiPhase::DesiredTargets` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::Snapshot` (r:0 w:1) - /// Proof: `ElectionProviderMultiPhase::Snapshot` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `v` is `[1000, 2000]`. /// The range of component `t` is `[500, 1000]`. fn create_snapshot_internal(v: u32, _t: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 170_730_000 picoseconds. - Weight::from_parts(175_009_000, 0) - // Standard Error: 2_010 - .saturating_add(Weight::from_parts(224_974, 0).saturating_mul(v.into())) + // Minimum execution time: 262_360_000 picoseconds. + Weight::from_parts(279_313_000, 0) + // Standard Error: 2_384 + .saturating_add(Weight::from_parts(176_415, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `ElectionProviderMultiPhase::SignedSubmissionIndices` (r:1 w:1) - /// Proof: `ElectionProviderMultiPhase::SignedSubmissionIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::SignedSubmissionNextIndex` (r:1 w:1) - /// Proof: `ElectionProviderMultiPhase::SignedSubmissionNextIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::SnapshotMetadata` (r:1 w:1) - /// Proof: `ElectionProviderMultiPhase::SnapshotMetadata` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::SignedSubmissionsMap` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::SignedSubmissionsMap` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::QueuedSolution` (r:1 w:1) - /// Proof: `ElectionProviderMultiPhase::QueuedSolution` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:1) - /// Proof: `ElectionProviderMultiPhase::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:1) - /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::DesiredTargets` (r:0 w:1) - /// Proof: `ElectionProviderMultiPhase::DesiredTargets` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::Snapshot` (r:0 w:1) - /// Proof: `ElectionProviderMultiPhase::Snapshot` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionIndices (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionNextIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionsMap (max_values: None, max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase QueuedSolution (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Round (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `a` is `[500, 800]`. /// The range of component `d` is `[200, 400]`. fn elect_queued(a: u32, d: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `371 + a * (768 ±0) + d * (48 ±0)` // Estimated: `3923 + a * (768 ±0) + d * (49 ±0)` - // Minimum execution time: 280_705_000 picoseconds. - Weight::from_parts(303_018_000, 3923) - // Standard Error: 4_633 - .saturating_add(Weight::from_parts(307_274, 0).saturating_mul(a.into())) + // Minimum execution time: 301_283_000 picoseconds. + Weight::from_parts(324_586_000, 3923) + // Standard Error: 4_763 + .saturating_add(Weight::from_parts(279_812, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) .saturating_add(Weight::from_parts(0, 768).saturating_mul(a.into())) .saturating_add(Weight::from_parts(0, 49).saturating_mul(d.into())) } - /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::SnapshotMetadata` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::SnapshotMetadata` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::SignedSubmissionIndices` (r:1 w:1) - /// Proof: `ElectionProviderMultiPhase::SignedSubmissionIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::SignedSubmissionNextIndex` (r:1 w:1) - /// Proof: `ElectionProviderMultiPhase::SignedSubmissionNextIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `ElectionProviderMultiPhase::SignedSubmissionsMap` (r:0 w:1) - /// Proof: `ElectionProviderMultiPhase::SignedSubmissionsMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) + /// Proof: TransactionPayment NextFeeMultiplier (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionIndices (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionNextIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionsMap (max_values: None, max_size: None, mode: Measured) fn submit() -> Weight { // Proof Size summary in bytes: // Measured: `927` // Estimated: `2412` - // Minimum execution time: 43_405_000 picoseconds. - Weight::from_parts(45_734_000, 2412) - .saturating_add(T::DbWeight::get().reads(6_u64)) + // Minimum execution time: 52_276_000 picoseconds. + Weight::from_parts(53_846_000, 2412) + .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::DesiredTargets` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::DesiredTargets` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::QueuedSolution` (r:1 w:1) - /// Proof: `ElectionProviderMultiPhase::QueuedSolution` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::SnapshotMetadata` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::SnapshotMetadata` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::Snapshot` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::Snapshot` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::MinimumUntrustedScore` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::MinimumUntrustedScore` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase QueuedSolution (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase MinimumUntrustedScore (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `v` is `[1000, 2000]`. /// The range of component `t` is `[500, 1000]`. /// The range of component `a` is `[500, 800]`. @@ -236,25 +235,25 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `253 + t * (32 ±0) + v * (553 ±0)` // Estimated: `1738 + t * (32 ±0) + v * (553 ±0)` - // Minimum execution time: 5_059_092_000 picoseconds. - Weight::from_parts(5_263_076_000, 1738) - // Standard Error: 17_317 - .saturating_add(Weight::from_parts(384_051, 0).saturating_mul(v.into())) - // Standard Error: 51_319 - .saturating_add(Weight::from_parts(4_095_128, 0).saturating_mul(a.into())) + // Minimum execution time: 5_448_459_000 picoseconds. + Weight::from_parts(5_525_622_000, 1738) + // Standard Error: 21_478 + .saturating_add(Weight::from_parts(256_345, 0).saturating_mul(v.into())) + // Standard Error: 63_648 + .saturating_add(Weight::from_parts(5_103_224, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(t.into())) .saturating_add(Weight::from_parts(0, 553).saturating_mul(v.into())) } - /// Storage: `ElectionProviderMultiPhase::DesiredTargets` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::DesiredTargets` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::Snapshot` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::Snapshot` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::MinimumUntrustedScore` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::MinimumUntrustedScore` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase MinimumUntrustedScore (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `v` is `[1000, 2000]`. /// The range of component `t` is `[500, 1000]`. /// The range of component `a` is `[500, 800]`. @@ -263,182 +262,180 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `228 + t * (32 ±0) + v * (553 ±0)` // Estimated: `1713 + t * (32 ±0) + v * (553 ±0)` - // Minimum execution time: 4_426_416_000 picoseconds. - Weight::from_parts(4_466_923_000, 1713) - // Standard Error: 15_415 - .saturating_add(Weight::from_parts(334_047, 0).saturating_mul(v.into())) - // Standard Error: 45_682 - .saturating_add(Weight::from_parts(3_097_318, 0).saturating_mul(a.into())) + // Minimum execution time: 4_724_399_000 picoseconds. + Weight::from_parts(4_886_472_000, 1713) + // Standard Error: 15_220 + .saturating_add(Weight::from_parts(365_569, 0).saturating_mul(v.into())) + // Standard Error: 45_104 + .saturating_add(Weight::from_parts(3_176_675, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(t.into())) .saturating_add(Weight::from_parts(0, 553).saturating_mul(v.into())) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Staking::CurrentEra` (r:1 w:0) - /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::CurrentPlannedSession` (r:1 w:0) - /// Proof: `Staking::CurrentPlannedSession` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::ErasStartSessionIndex` (r:1 w:0) - /// Proof: `Staking::ErasStartSessionIndex` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) - /// Storage: `Babe::EpochIndex` (r:1 w:0) - /// Proof: `Babe::EpochIndex` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Babe::GenesisSlot` (r:1 w:0) - /// Proof: `Babe::GenesisSlot` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Babe::CurrentSlot` (r:1 w:0) - /// Proof: `Babe::CurrentSlot` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Staking::ForceEra` (r:1 w:0) - /// Proof: `Staking::ForceEra` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) - /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CurrentPlannedSession (r:1 w:0) + /// Proof: Staking CurrentPlannedSession (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ErasStartSessionIndex (r:1 w:0) + /// Proof: Staking ErasStartSessionIndex (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: Babe EpochIndex (r:1 w:0) + /// Proof: Babe EpochIndex (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Babe GenesisSlot (r:1 w:0) + /// Proof: Babe GenesisSlot (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Babe CurrentSlot (r:1 w:0) + /// Proof: Babe CurrentSlot (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Staking ForceEra (r:1 w:0) + /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) fn on_initialize_nothing() -> Weight { // Proof Size summary in bytes: - // Measured: `1061` + // Measured: `1028` // Estimated: `3481` - // Minimum execution time: 19_340_000 picoseconds. - Weight::from_parts(19_886_000, 3481) + // Minimum execution time: 22_089_000 picoseconds. + Weight::from_parts(22_677_000, 3481) .saturating_add(RocksDbWeight::get().reads(8_u64)) } - /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:1) - /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) fn on_initialize_open_signed() -> Weight { // Proof Size summary in bytes: // Measured: `148` // Estimated: `1633` - // Minimum execution time: 8_067_000 picoseconds. - Weight::from_parts(8_508_000, 1633) + // Minimum execution time: 11_986_000 picoseconds. + Weight::from_parts(12_445_000, 1633) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:1) - /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) fn on_initialize_open_unsigned() -> Weight { // Proof Size summary in bytes: // Measured: `148` // Estimated: `1633` - // Minimum execution time: 8_810_000 picoseconds. - Weight::from_parts(9_061_000, 1633) + // Minimum execution time: 12_988_000 picoseconds. + Weight::from_parts(13_281_000, 1633) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ElectionProviderMultiPhase::QueuedSolution` (r:0 w:1) - /// Proof: `ElectionProviderMultiPhase::QueuedSolution` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: ElectionProviderMultiPhase QueuedSolution (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) fn finalize_signed_phase_accept_solution() -> Weight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 24_339_000 picoseconds. - Weight::from_parts(25_322_000, 3593) + // Minimum execution time: 32_659_000 picoseconds. + Weight::from_parts(33_281_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn finalize_signed_phase_reject_solution() -> Weight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 16_635_000 picoseconds. - Weight::from_parts(17_497_000, 3593) + // Minimum execution time: 22_471_000 picoseconds. + Weight::from_parts(23_046_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `ElectionProviderMultiPhase::SnapshotMetadata` (r:0 w:1) - /// Proof: `ElectionProviderMultiPhase::SnapshotMetadata` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::DesiredTargets` (r:0 w:1) - /// Proof: `ElectionProviderMultiPhase::DesiredTargets` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::Snapshot` (r:0 w:1) - /// Proof: `ElectionProviderMultiPhase::Snapshot` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `v` is `[1000, 2000]`. /// The range of component `t` is `[500, 1000]`. fn create_snapshot_internal(v: u32, _t: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 170_730_000 picoseconds. - Weight::from_parts(175_009_000, 0) - // Standard Error: 2_010 - .saturating_add(Weight::from_parts(224_974, 0).saturating_mul(v.into())) + // Minimum execution time: 262_360_000 picoseconds. + Weight::from_parts(279_313_000, 0) + // Standard Error: 2_384 + .saturating_add(Weight::from_parts(176_415, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `ElectionProviderMultiPhase::SignedSubmissionIndices` (r:1 w:1) - /// Proof: `ElectionProviderMultiPhase::SignedSubmissionIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::SignedSubmissionNextIndex` (r:1 w:1) - /// Proof: `ElectionProviderMultiPhase::SignedSubmissionNextIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::SnapshotMetadata` (r:1 w:1) - /// Proof: `ElectionProviderMultiPhase::SnapshotMetadata` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::SignedSubmissionsMap` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::SignedSubmissionsMap` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::QueuedSolution` (r:1 w:1) - /// Proof: `ElectionProviderMultiPhase::QueuedSolution` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:1) - /// Proof: `ElectionProviderMultiPhase::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:1) - /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::DesiredTargets` (r:0 w:1) - /// Proof: `ElectionProviderMultiPhase::DesiredTargets` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::Snapshot` (r:0 w:1) - /// Proof: `ElectionProviderMultiPhase::Snapshot` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionIndices (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionNextIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionsMap (max_values: None, max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase QueuedSolution (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Round (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase DesiredTargets (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Snapshot (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `a` is `[500, 800]`. /// The range of component `d` is `[200, 400]`. fn elect_queued(a: u32, d: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `371 + a * (768 ±0) + d * (48 ±0)` // Estimated: `3923 + a * (768 ±0) + d * (49 ±0)` - // Minimum execution time: 280_705_000 picoseconds. - Weight::from_parts(303_018_000, 3923) - // Standard Error: 4_633 - .saturating_add(Weight::from_parts(307_274, 0).saturating_mul(a.into())) + // Minimum execution time: 301_283_000 picoseconds. + Weight::from_parts(324_586_000, 3923) + // Standard Error: 4_763 + .saturating_add(Weight::from_parts(279_812, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) .saturating_add(Weight::from_parts(0, 768).saturating_mul(a.into())) .saturating_add(Weight::from_parts(0, 49).saturating_mul(d.into())) } - /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::SnapshotMetadata` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::SnapshotMetadata` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::SignedSubmissionIndices` (r:1 w:1) - /// Proof: `ElectionProviderMultiPhase::SignedSubmissionIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::SignedSubmissionNextIndex` (r:1 w:1) - /// Proof: `ElectionProviderMultiPhase::SignedSubmissionNextIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `ElectionProviderMultiPhase::SignedSubmissionsMap` (r:0 w:1) - /// Proof: `ElectionProviderMultiPhase::SignedSubmissionsMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) + /// Proof: TransactionPayment NextFeeMultiplier (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: ElectionProviderMultiPhase SignedSubmissionIndices (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionIndices (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SignedSubmissionNextIndex (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionNextIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SignedSubmissionsMap (r:0 w:1) + /// Proof Skipped: ElectionProviderMultiPhase SignedSubmissionsMap (max_values: None, max_size: None, mode: Measured) fn submit() -> Weight { // Proof Size summary in bytes: // Measured: `927` // Estimated: `2412` - // Minimum execution time: 43_405_000 picoseconds. - Weight::from_parts(45_734_000, 2412) - .saturating_add(RocksDbWeight::get().reads(6_u64)) + // Minimum execution time: 52_276_000 picoseconds. + Weight::from_parts(53_846_000, 2412) + .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::DesiredTargets` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::DesiredTargets` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::QueuedSolution` (r:1 w:1) - /// Proof: `ElectionProviderMultiPhase::QueuedSolution` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::SnapshotMetadata` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::SnapshotMetadata` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::Snapshot` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::Snapshot` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::MinimumUntrustedScore` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::MinimumUntrustedScore` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase QueuedSolution (r:1 w:1) + /// Proof Skipped: ElectionProviderMultiPhase QueuedSolution (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase SnapshotMetadata (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase SnapshotMetadata (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase MinimumUntrustedScore (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `v` is `[1000, 2000]`. /// The range of component `t` is `[500, 1000]`. /// The range of component `a` is `[500, 800]`. @@ -447,25 +444,25 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `253 + t * (32 ±0) + v * (553 ±0)` // Estimated: `1738 + t * (32 ±0) + v * (553 ±0)` - // Minimum execution time: 5_059_092_000 picoseconds. - Weight::from_parts(5_263_076_000, 1738) - // Standard Error: 17_317 - .saturating_add(Weight::from_parts(384_051, 0).saturating_mul(v.into())) - // Standard Error: 51_319 - .saturating_add(Weight::from_parts(4_095_128, 0).saturating_mul(a.into())) + // Minimum execution time: 5_448_459_000 picoseconds. + Weight::from_parts(5_525_622_000, 1738) + // Standard Error: 21_478 + .saturating_add(Weight::from_parts(256_345, 0).saturating_mul(v.into())) + // Standard Error: 63_648 + .saturating_add(Weight::from_parts(5_103_224, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(t.into())) .saturating_add(Weight::from_parts(0, 553).saturating_mul(v.into())) } - /// Storage: `ElectionProviderMultiPhase::DesiredTargets` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::DesiredTargets` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::Snapshot` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::Snapshot` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::Round` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiPhase::MinimumUntrustedScore` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::MinimumUntrustedScore` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: ElectionProviderMultiPhase DesiredTargets (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase DesiredTargets (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Snapshot (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Snapshot (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase Round (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase Round (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ElectionProviderMultiPhase MinimumUntrustedScore (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase MinimumUntrustedScore (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `v` is `[1000, 2000]`. /// The range of component `t` is `[500, 1000]`. /// The range of component `a` is `[500, 800]`. @@ -474,12 +471,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `228 + t * (32 ±0) + v * (553 ±0)` // Estimated: `1713 + t * (32 ±0) + v * (553 ±0)` - // Minimum execution time: 4_426_416_000 picoseconds. - Weight::from_parts(4_466_923_000, 1713) - // Standard Error: 15_415 - .saturating_add(Weight::from_parts(334_047, 0).saturating_mul(v.into())) - // Standard Error: 45_682 - .saturating_add(Weight::from_parts(3_097_318, 0).saturating_mul(a.into())) + // Minimum execution time: 4_724_399_000 picoseconds. + Weight::from_parts(4_886_472_000, 1713) + // Standard Error: 15_220 + .saturating_add(Weight::from_parts(365_569, 0).saturating_mul(v.into())) + // Standard Error: 45_104 + .saturating_add(Weight::from_parts(3_176_675, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(t.into())) .saturating_add(Weight::from_parts(0, 553).saturating_mul(v.into())) diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs index 7fade251e6d..882b894bb22 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs @@ -62,7 +62,7 @@ pub const INIT_TIMESTAMP: BlockNumber = 30_000; pub const BLOCK_TIME: BlockNumber = 1000; type Block = frame_system::mocking::MockBlockU32; -type Extrinsic = sp_runtime::generic::UncheckedExtrinsic; +type Extrinsic = testing::TestXt; frame_support::construct_runtime!( pub enum Runtime { @@ -699,7 +699,7 @@ pub fn roll_to_with_ocw(n: BlockNumber, pool: Arc>, delay_solu for encoded in &pool.read().transactions { let extrinsic = Extrinsic::decode(&mut &encoded[..]).unwrap(); - let _ = match extrinsic.function { + let _ = match extrinsic.call { RuntimeCall::ElectionProviderMultiPhase( call @ Call::submit_unsigned { .. }, ) => { diff --git a/substrate/frame/elections-phragmen/src/lib.rs b/substrate/frame/elections-phragmen/src/lib.rs index e08412a6e87..308f2cdc1aa 100644 --- a/substrate/frame/elections-phragmen/src/lib.rs +++ b/substrate/frame/elections-phragmen/src/lib.rs @@ -1422,7 +1422,7 @@ mod tests { pub type Block = sp_runtime::generic::Block; pub type UncheckedExtrinsic = - sp_runtime::generic::UncheckedExtrinsic; + sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( pub enum Test diff --git a/substrate/frame/elections-phragmen/src/weights.rs b/substrate/frame/elections-phragmen/src/weights.rs index cd67918e85b..b7ed13dae9f 100644 --- a/substrate/frame/elections-phragmen/src/weights.rs +++ b/substrate/frame/elections-phragmen/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_elections_phragmen` +//! Autogenerated weights for pallet_elections_phragmen //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/elections-phragmen/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/elections-phragmen/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_elections_phragmen`. +/// Weight functions needed for pallet_elections_phragmen. pub trait WeightInfo { fn vote_equal(v: u32, ) -> Weight; fn vote_more(v: u32, ) -> Weight; @@ -65,165 +66,165 @@ pub trait WeightInfo { fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight; } -/// Weights for `pallet_elections_phragmen` using the Substrate node and recommended hardware. +/// Weights for pallet_elections_phragmen using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Elections::Candidates` (r:1 w:0) - /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::Members` (r:1 w:0) - /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::RunnersUp` (r:1 w:0) - /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::Voting` (r:1 w:1) - /// Proof: `Elections::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `v` is `[1, 16]`. fn vote_equal(v: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `403 + v * (80 ±0)` // Estimated: `4764 + v * (80 ±0)` - // Minimum execution time: 29_390_000 picoseconds. - Weight::from_parts(30_525_476, 4764) - // Standard Error: 3_185 - .saturating_add(Weight::from_parts(143_073, 0).saturating_mul(v.into())) + // Minimum execution time: 33_028_000 picoseconds. + Weight::from_parts(34_073_914, 4764) + // Standard Error: 3_474 + .saturating_add(Weight::from_parts(205_252, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) } - /// Storage: `Elections::Candidates` (r:1 w:0) - /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::Members` (r:1 w:0) - /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::RunnersUp` (r:1 w:0) - /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::Voting` (r:1 w:1) - /// Proof: `Elections::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `v` is `[2, 16]`. fn vote_more(v: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `371 + v * (80 ±0)` // Estimated: `4764 + v * (80 ±0)` - // Minimum execution time: 39_765_000 picoseconds. - Weight::from_parts(41_374_102, 4764) - // Standard Error: 4_310 - .saturating_add(Weight::from_parts(153_015, 0).saturating_mul(v.into())) + // Minimum execution time: 45_725_000 picoseconds. + Weight::from_parts(47_169_586, 4764) + // Standard Error: 5_148 + .saturating_add(Weight::from_parts(213_742, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) } - /// Storage: `Elections::Candidates` (r:1 w:0) - /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::Members` (r:1 w:0) - /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::RunnersUp` (r:1 w:0) - /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::Voting` (r:1 w:1) - /// Proof: `Elections::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `v` is `[2, 16]`. fn vote_less(v: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `403 + v * (80 ±0)` // Estimated: `4764 + v * (80 ±0)` - // Minimum execution time: 39_647_000 picoseconds. - Weight::from_parts(41_474_523, 4764) - // Standard Error: 5_503 - .saturating_add(Weight::from_parts(149_029, 0).saturating_mul(v.into())) + // Minimum execution time: 45_519_000 picoseconds. + Weight::from_parts(47_339_108, 4764) + // Standard Error: 5_501 + .saturating_add(Weight::from_parts(195_247, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) } - /// Storage: `Elections::Voting` (r:1 w:1) - /// Proof: `Elections::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn remove_voter() -> Weight { // Proof Size summary in bytes: // Measured: `925` // Estimated: `4764` - // Minimum execution time: 41_882_000 picoseconds. - Weight::from_parts(42_794_000, 4764) + // Minimum execution time: 50_386_000 picoseconds. + Weight::from_parts(51_378_000, 4764) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Elections::Candidates` (r:1 w:1) - /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::Members` (r:1 w:0) - /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::RunnersUp` (r:1 w:0) - /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Elections Candidates (r:1 w:1) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `c` is `[1, 64]`. fn submit_candidacy(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1570 + c * (48 ±0)` // Estimated: `3055 + c * (48 ±0)` - // Minimum execution time: 33_719_000 picoseconds. - Weight::from_parts(35_017_073, 3055) - // Standard Error: 1_587 - .saturating_add(Weight::from_parts(121_130, 0).saturating_mul(c.into())) + // Minimum execution time: 38_987_000 picoseconds. + Weight::from_parts(41_302_276, 3055) + // Standard Error: 2_047 + .saturating_add(Weight::from_parts(125_200, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 48).saturating_mul(c.into())) } - /// Storage: `Elections::Candidates` (r:1 w:1) - /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Elections Candidates (r:1 w:1) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `c` is `[1, 64]`. fn renounce_candidacy_candidate(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `285 + c * (48 ±0)` // Estimated: `1770 + c * (48 ±0)` - // Minimum execution time: 27_263_000 picoseconds. - Weight::from_parts(28_215_666, 1770) - // Standard Error: 1_196 - .saturating_add(Weight::from_parts(86_804, 0).saturating_mul(c.into())) + // Minimum execution time: 33_510_000 picoseconds. + Weight::from_parts(34_947_760, 1770) + // Standard Error: 1_781 + .saturating_add(Weight::from_parts(78_851, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 48).saturating_mul(c.into())) } - /// Storage: `Elections::Members` (r:1 w:1) - /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::RunnersUp` (r:1 w:1) - /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Prime` (r:1 w:1) - /// Proof: `Council::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Proposals` (r:1 w:0) - /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Members` (r:0 w:1) - /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Elections Members (r:1 w:1) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Members (r:0 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) fn renounce_candidacy_members() -> Weight { // Proof Size summary in bytes: - // Measured: `1933` - // Estimated: `3418` - // Minimum execution time: 41_531_000 picoseconds. - Weight::from_parts(42_937_000, 3418) + // Measured: `1900` + // Estimated: `3385` + // Minimum execution time: 50_603_000 picoseconds. + Weight::from_parts(51_715_000, 3385) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: `Elections::RunnersUp` (r:1 w:1) - /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) fn renounce_candidacy_runners_up() -> Weight { // Proof Size summary in bytes: // Measured: `880` // Estimated: `2365` - // Minimum execution time: 27_680_000 picoseconds. - Weight::from_parts(28_810_000, 2365) + // Minimum execution time: 33_441_000 picoseconds. + Weight::from_parts(34_812_000, 2365) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Benchmark::Override` (r:0 w:0) - /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Benchmark Override (r:0 w:0) + /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) fn remove_member_without_replacement() -> Weight { // Proof Size summary in bytes: // Measured: `0` @@ -231,90 +232,87 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 2_000_000_000_000 picoseconds. Weight::from_parts(2_000_000_000_000, 0) } - /// Storage: `Elections::Members` (r:1 w:1) - /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Elections::RunnersUp` (r:1 w:1) - /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Prime` (r:1 w:1) - /// Proof: `Council::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Proposals` (r:1 w:0) - /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Members` (r:0 w:1) - /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Elections Members (r:1 w:1) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Members (r:0 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) fn remove_member_with_replacement() -> Weight { // Proof Size summary in bytes: - // Measured: `1933` + // Measured: `1900` // Estimated: `3593` - // Minimum execution time: 45_333_000 picoseconds. - Weight::from_parts(46_523_000, 3593) + // Minimum execution time: 57_289_000 picoseconds. + Weight::from_parts(58_328_000, 3593) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: `Elections::Voting` (r:257 w:256) - /// Proof: `Elections::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Elections::Members` (r:1 w:0) - /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::RunnersUp` (r:1 w:0) - /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::Candidates` (r:1 w:0) - /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Balances::Locks` (r:256 w:256) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:256 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:256 w:256) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Elections Voting (r:513 w:512) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Balances Locks (r:512 w:512) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:512 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: System Account (r:512 w:512) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `v` is `[256, 512]`. /// The range of component `d` is `[0, 256]`. - fn clean_defunct_voters(v: u32, d: u32, ) -> Weight { + fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + d * (818 ±0) + v * (57 ±0)` - // Estimated: `24906 + d * (3774 ±1) + v * (24 ±0)` - // Minimum execution time: 5_620_000 picoseconds. - Weight::from_parts(5_817_000, 24906) - // Standard Error: 18_357 - .saturating_add(Weight::from_parts(106_164, 0).saturating_mul(v.into())) - // Standard Error: 39_980 - .saturating_add(Weight::from_parts(52_456_337, 0).saturating_mul(d.into())) + // Measured: `1149 + v * (811 ±0)` + // Estimated: `4621 + v * (3774 ±0)` + // Minimum execution time: 18_774_231_000 picoseconds. + Weight::from_parts(18_933_040_000, 4621) + // Standard Error: 301_534 + .saturating_add(Weight::from_parts(44_306_903, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(d.into()))) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(d.into()))) - .saturating_add(Weight::from_parts(0, 3774).saturating_mul(d.into())) - .saturating_add(Weight::from_parts(0, 24).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(v.into()))) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) + .saturating_add(Weight::from_parts(0, 3774).saturating_mul(v.into())) } - /// Storage: `Elections::Candidates` (r:1 w:1) - /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::Members` (r:1 w:1) - /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::RunnersUp` (r:1 w:1) - /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::Voting` (r:513 w:0) - /// Proof: `Elections::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Council::Proposals` (r:1 w:0) - /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:44 w:44) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Elections::ElectionRounds` (r:1 w:1) - /// Proof: `Elections::ElectionRounds` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Members` (r:0 w:1) - /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Prime` (r:0 w:1) - /// Proof: `Council::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Elections Candidates (r:1 w:1) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:1) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:513 w:0) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Account (r:44 w:44) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Elections ElectionRounds (r:1 w:1) + /// Proof Skipped: Elections ElectionRounds (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Members (r:0 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:0 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `c` is `[1, 64]`. /// The range of component `v` is `[1, 512]`. /// The range of component `e` is `[512, 8192]`. fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + e * (28 ±0) + v * (606 ±0)` - // Estimated: `178920 + c * (2135 ±7) + e * (12 ±0) + v * (2653 ±6)` - // Minimum execution time: 1_082_582_000 picoseconds. - Weight::from_parts(1_084_730_000, 178920) - // Standard Error: 594_096 - .saturating_add(Weight::from_parts(19_096_288, 0).saturating_mul(v.into())) - // Standard Error: 38_118 - .saturating_add(Weight::from_parts(792_945, 0).saturating_mul(e.into())) + // Estimated: `178887 + c * (2135 ±7) + e * (12 ±0) + v * (2653 ±6)` + // Minimum execution time: 1_281_877_000 picoseconds. + Weight::from_parts(1_288_147_000, 178887) + // Standard Error: 528_851 + .saturating_add(Weight::from_parts(17_761_407, 0).saturating_mul(v.into())) + // Standard Error: 33_932 + .saturating_add(Weight::from_parts(698_277, 0).saturating_mul(e.into())) .saturating_add(T::DbWeight::get().reads(21_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) @@ -326,164 +324,164 @@ impl WeightInfo for SubstrateWeight { } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Elections::Candidates` (r:1 w:0) - /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::Members` (r:1 w:0) - /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::RunnersUp` (r:1 w:0) - /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::Voting` (r:1 w:1) - /// Proof: `Elections::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `v` is `[1, 16]`. fn vote_equal(v: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `403 + v * (80 ±0)` // Estimated: `4764 + v * (80 ±0)` - // Minimum execution time: 29_390_000 picoseconds. - Weight::from_parts(30_525_476, 4764) - // Standard Error: 3_185 - .saturating_add(Weight::from_parts(143_073, 0).saturating_mul(v.into())) + // Minimum execution time: 33_028_000 picoseconds. + Weight::from_parts(34_073_914, 4764) + // Standard Error: 3_474 + .saturating_add(Weight::from_parts(205_252, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) } - /// Storage: `Elections::Candidates` (r:1 w:0) - /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::Members` (r:1 w:0) - /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::RunnersUp` (r:1 w:0) - /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::Voting` (r:1 w:1) - /// Proof: `Elections::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `v` is `[2, 16]`. fn vote_more(v: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `371 + v * (80 ±0)` // Estimated: `4764 + v * (80 ±0)` - // Minimum execution time: 39_765_000 picoseconds. - Weight::from_parts(41_374_102, 4764) - // Standard Error: 4_310 - .saturating_add(Weight::from_parts(153_015, 0).saturating_mul(v.into())) + // Minimum execution time: 45_725_000 picoseconds. + Weight::from_parts(47_169_586, 4764) + // Standard Error: 5_148 + .saturating_add(Weight::from_parts(213_742, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) } - /// Storage: `Elections::Candidates` (r:1 w:0) - /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::Members` (r:1 w:0) - /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::RunnersUp` (r:1 w:0) - /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::Voting` (r:1 w:1) - /// Proof: `Elections::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) /// The range of component `v` is `[2, 16]`. fn vote_less(v: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `403 + v * (80 ±0)` // Estimated: `4764 + v * (80 ±0)` - // Minimum execution time: 39_647_000 picoseconds. - Weight::from_parts(41_474_523, 4764) - // Standard Error: 5_503 - .saturating_add(Weight::from_parts(149_029, 0).saturating_mul(v.into())) + // Minimum execution time: 45_519_000 picoseconds. + Weight::from_parts(47_339_108, 4764) + // Standard Error: 5_501 + .saturating_add(Weight::from_parts(195_247, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) } - /// Storage: `Elections::Voting` (r:1 w:1) - /// Proof: `Elections::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: Elections Voting (r:1 w:1) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn remove_voter() -> Weight { // Proof Size summary in bytes: // Measured: `925` // Estimated: `4764` - // Minimum execution time: 41_882_000 picoseconds. - Weight::from_parts(42_794_000, 4764) + // Minimum execution time: 50_386_000 picoseconds. + Weight::from_parts(51_378_000, 4764) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Elections::Candidates` (r:1 w:1) - /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::Members` (r:1 w:0) - /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::RunnersUp` (r:1 w:0) - /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Elections Candidates (r:1 w:1) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `c` is `[1, 64]`. fn submit_candidacy(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1570 + c * (48 ±0)` // Estimated: `3055 + c * (48 ±0)` - // Minimum execution time: 33_719_000 picoseconds. - Weight::from_parts(35_017_073, 3055) - // Standard Error: 1_587 - .saturating_add(Weight::from_parts(121_130, 0).saturating_mul(c.into())) + // Minimum execution time: 38_987_000 picoseconds. + Weight::from_parts(41_302_276, 3055) + // Standard Error: 2_047 + .saturating_add(Weight::from_parts(125_200, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 48).saturating_mul(c.into())) } - /// Storage: `Elections::Candidates` (r:1 w:1) - /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Elections Candidates (r:1 w:1) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `c` is `[1, 64]`. fn renounce_candidacy_candidate(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `285 + c * (48 ±0)` // Estimated: `1770 + c * (48 ±0)` - // Minimum execution time: 27_263_000 picoseconds. - Weight::from_parts(28_215_666, 1770) - // Standard Error: 1_196 - .saturating_add(Weight::from_parts(86_804, 0).saturating_mul(c.into())) + // Minimum execution time: 33_510_000 picoseconds. + Weight::from_parts(34_947_760, 1770) + // Standard Error: 1_781 + .saturating_add(Weight::from_parts(78_851, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 48).saturating_mul(c.into())) } - /// Storage: `Elections::Members` (r:1 w:1) - /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::RunnersUp` (r:1 w:1) - /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Prime` (r:1 w:1) - /// Proof: `Council::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Proposals` (r:1 w:0) - /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Members` (r:0 w:1) - /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Elections Members (r:1 w:1) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Members (r:0 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) fn renounce_candidacy_members() -> Weight { // Proof Size summary in bytes: - // Measured: `1933` - // Estimated: `3418` - // Minimum execution time: 41_531_000 picoseconds. - Weight::from_parts(42_937_000, 3418) + // Measured: `1900` + // Estimated: `3385` + // Minimum execution time: 50_603_000 picoseconds. + Weight::from_parts(51_715_000, 3385) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: `Elections::RunnersUp` (r:1 w:1) - /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) fn renounce_candidacy_runners_up() -> Weight { // Proof Size summary in bytes: // Measured: `880` // Estimated: `2365` - // Minimum execution time: 27_680_000 picoseconds. - Weight::from_parts(28_810_000, 2365) + // Minimum execution time: 33_441_000 picoseconds. + Weight::from_parts(34_812_000, 2365) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Benchmark::Override` (r:0 w:0) - /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Benchmark Override (r:0 w:0) + /// Proof Skipped: Benchmark Override (max_values: None, max_size: None, mode: Measured) fn remove_member_without_replacement() -> Weight { // Proof Size summary in bytes: // Measured: `0` @@ -491,90 +489,87 @@ impl WeightInfo for () { // Minimum execution time: 2_000_000_000_000 picoseconds. Weight::from_parts(2_000_000_000_000, 0) } - /// Storage: `Elections::Members` (r:1 w:1) - /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Elections::RunnersUp` (r:1 w:1) - /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Prime` (r:1 w:1) - /// Proof: `Council::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Proposals` (r:1 w:0) - /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Members` (r:0 w:1) - /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Elections Members (r:1 w:1) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:1 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Members (r:0 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) fn remove_member_with_replacement() -> Weight { // Proof Size summary in bytes: - // Measured: `1933` + // Measured: `1900` // Estimated: `3593` - // Minimum execution time: 45_333_000 picoseconds. - Weight::from_parts(46_523_000, 3593) + // Minimum execution time: 57_289_000 picoseconds. + Weight::from_parts(58_328_000, 3593) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: `Elections::Voting` (r:257 w:256) - /// Proof: `Elections::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Elections::Members` (r:1 w:0) - /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::RunnersUp` (r:1 w:0) - /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::Candidates` (r:1 w:0) - /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Balances::Locks` (r:256 w:256) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:256 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:256 w:256) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Elections Voting (r:513 w:512) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:0) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Candidates (r:1 w:0) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Balances Locks (r:512 w:512) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:512 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: System Account (r:512 w:512) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `v` is `[256, 512]`. /// The range of component `d` is `[0, 256]`. - fn clean_defunct_voters(v: u32, d: u32, ) -> Weight { + fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + d * (818 ±0) + v * (57 ±0)` - // Estimated: `24906 + d * (3774 ±1) + v * (24 ±0)` - // Minimum execution time: 5_620_000 picoseconds. - Weight::from_parts(5_817_000, 24906) - // Standard Error: 18_357 - .saturating_add(Weight::from_parts(106_164, 0).saturating_mul(v.into())) - // Standard Error: 39_980 - .saturating_add(Weight::from_parts(52_456_337, 0).saturating_mul(d.into())) + // Measured: `1149 + v * (811 ±0)` + // Estimated: `4621 + v * (3774 ±0)` + // Minimum execution time: 18_774_231_000 picoseconds. + Weight::from_parts(18_933_040_000, 4621) + // Standard Error: 301_534 + .saturating_add(Weight::from_parts(44_306_903, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(d.into()))) - .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(d.into()))) - .saturating_add(Weight::from_parts(0, 3774).saturating_mul(d.into())) - .saturating_add(Weight::from_parts(0, 24).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(v.into()))) + .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(v.into()))) + .saturating_add(Weight::from_parts(0, 3774).saturating_mul(v.into())) } - /// Storage: `Elections::Candidates` (r:1 w:1) - /// Proof: `Elections::Candidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::Members` (r:1 w:1) - /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::RunnersUp` (r:1 w:1) - /// Proof: `Elections::RunnersUp` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Elections::Voting` (r:513 w:0) - /// Proof: `Elections::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Council::Proposals` (r:1 w:0) - /// Proof: `Council::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:44 w:44) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Elections::ElectionRounds` (r:1 w:1) - /// Proof: `Elections::ElectionRounds` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Members` (r:0 w:1) - /// Proof: `Council::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Council::Prime` (r:0 w:1) - /// Proof: `Council::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Elections Candidates (r:1 w:1) + /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:1) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections RunnersUp (r:1 w:1) + /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Elections Voting (r:513 w:0) + /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: Council Proposals (r:1 w:0) + /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Account (r:44 w:44) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Elections ElectionRounds (r:1 w:1) + /// Proof Skipped: Elections ElectionRounds (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Members (r:0 w:1) + /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Council Prime (r:0 w:1) + /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `c` is `[1, 64]`. /// The range of component `v` is `[1, 512]`. /// The range of component `e` is `[512, 8192]`. fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + e * (28 ±0) + v * (606 ±0)` - // Estimated: `178920 + c * (2135 ±7) + e * (12 ±0) + v * (2653 ±6)` - // Minimum execution time: 1_082_582_000 picoseconds. - Weight::from_parts(1_084_730_000, 178920) - // Standard Error: 594_096 - .saturating_add(Weight::from_parts(19_096_288, 0).saturating_mul(v.into())) - // Standard Error: 38_118 - .saturating_add(Weight::from_parts(792_945, 0).saturating_mul(e.into())) + // Estimated: `178887 + c * (2135 ±7) + e * (12 ±0) + v * (2653 ±6)` + // Minimum execution time: 1_281_877_000 picoseconds. + Weight::from_parts(1_288_147_000, 178887) + // Standard Error: 528_851 + .saturating_add(Weight::from_parts(17_761_407, 0).saturating_mul(v.into())) + // Standard Error: 33_932 + .saturating_add(Weight::from_parts(698_277, 0).saturating_mul(e.into())) .saturating_add(RocksDbWeight::get().reads(21_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(c.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) diff --git a/substrate/frame/examples/basic/src/lib.rs b/substrate/frame/examples/basic/src/lib.rs index 94b2f276e00..12cadc969fd 100644 --- a/substrate/frame/examples/basic/src/lib.rs +++ b/substrate/frame/examples/basic/src/lib.rs @@ -46,10 +46,9 @@ //! use the [`Config::WeightInfo`] trait to calculate call weights. This can also be overridden, //! as demonstrated by [`Call::set_dummy`]. //! - A private function that performs a storage update. -//! - A simple transaction extension implementation (see: -//! [`sp_runtime::traits::TransactionExtension`]) which increases the priority of the -//! [`Call::set_dummy`] if it's present and drops any transaction with an encoded length higher -//! than 200 bytes. +//! - A simple signed extension implementation (see: [`sp_runtime::traits::SignedExtension`]) which +//! increases the priority of the [`Call::set_dummy`] if it's present and drops any transaction +//! with an encoded length higher than 200 bytes. // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] @@ -65,12 +64,10 @@ use frame_system::ensure_signed; use log::info; use scale_info::TypeInfo; use sp_runtime::{ - impl_tx_ext_default, - traits::{ - Bounded, DispatchInfoOf, OriginOf, SaturatedConversion, Saturating, TransactionExtension, - TransactionExtensionBase, ValidateResult, + traits::{Bounded, DispatchInfoOf, SaturatedConversion, Saturating, SignedExtension}, + transaction_validity::{ + InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction, }, - transaction_validity::{InvalidTransaction, ValidTransaction}, }; use sp_std::vec::Vec; @@ -443,8 +440,8 @@ impl Pallet { // Similar to other FRAME pallets, your pallet can also define a signed extension and perform some // checks and [pre/post]processing [before/after] the transaction. A signed extension can be any -// decodable type that implements `TransactionExtension`. See the trait definition for the full list -// of bounds. As a convention, you can follow this approach to create an extension for your pallet: +// decodable type that implements `SignedExtension`. See the trait definition for the full list of +// bounds. As a convention, you can follow this approach to create an extension for your pallet: // - If the extension does not carry any data, then use a tuple struct with just a `marker` // (needed for the compiler to accept `T: Config`) will suffice. // - Otherwise, create a tuple struct which contains the external data. Of course, for the entire @@ -458,18 +455,18 @@ impl Pallet { // // Using the extension, you can add some hooks to the life cycle of each transaction. Note that by // default, an extension is applied to all `Call` functions (i.e. all transactions). the `Call` enum -// variant is given to each function of `TransactionExtension`. Hence, you can filter based on -// pallet or a particular call if needed. +// variant is given to each function of `SignedExtension`. Hence, you can filter based on pallet or +// a particular call if needed. // // Some extra information, such as encoded length, some static dispatch info like weight and the // sender of the transaction (if signed) are also provided. // // The full list of hooks that can be added to a signed extension can be found -// [here](https://paritytech.github.io/polkadot-sdk/master/sp_runtime/traits/trait.TransactionExtension.html). +// [here](https://paritytech.github.io/polkadot-sdk/master/sp_runtime/traits/trait.SignedExtension.html). // // The signed extensions are aggregated in the runtime file of a substrate chain. All extensions // should be aggregated in a tuple and passed to the `CheckedExtrinsic` and `UncheckedExtrinsic` -// types defined in the runtime. Lookup `pub type TxExtension = (...)` in `node/runtime` and +// types defined in the runtime. Lookup `pub type SignedExtra = (...)` in `node/runtime` and // `node-template` for an example of this. /// A simple signed extension that checks for the `set_dummy` call. In that case, it increases the @@ -487,45 +484,52 @@ impl core::fmt::Debug for WatchDummy { } } -impl TransactionExtensionBase for WatchDummy { - const IDENTIFIER: &'static str = "WatchDummy"; - type Implicit = (); -} -impl - TransactionExtension<::RuntimeCall, Context> for WatchDummy +impl SignedExtension for WatchDummy where ::RuntimeCall: IsSubType>, { + const IDENTIFIER: &'static str = "WatchDummy"; + type AccountId = T::AccountId; + type Call = ::RuntimeCall; + type AdditionalSigned = (); type Pre = (); - type Val = (); + + fn additional_signed(&self) -> core::result::Result<(), TransactionValidityError> { + Ok(()) + } + + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + self.validate(who, call, info, len).map(|_| ()) + } fn validate( &self, - origin: OriginOf<::RuntimeCall>, - call: &::RuntimeCall, - _info: &DispatchInfoOf<::RuntimeCall>, + _who: &Self::AccountId, + call: &Self::Call, + _info: &DispatchInfoOf, len: usize, - _context: &mut Context, - _self_implicit: Self::Implicit, - _inherited_implication: &impl Encode, - ) -> ValidateResult::RuntimeCall> { + ) -> TransactionValidity { // if the transaction is too big, just drop it. if len > 200 { - return Err(InvalidTransaction::ExhaustsResources.into()) + return InvalidTransaction::ExhaustsResources.into() } // check for `set_dummy` - let validity = match call.is_sub_type() { + match call.is_sub_type() { Some(Call::set_dummy { .. }) => { sp_runtime::print("set_dummy was received."); let valid_tx = ValidTransaction { priority: Bounded::max_value(), ..Default::default() }; - valid_tx + Ok(valid_tx) }, - _ => Default::default(), - }; - Ok((validity, (), origin)) + _ => Ok(Default::default()), + } } - impl_tx_ext_default!(::RuntimeCall; Context; prepare); } diff --git a/substrate/frame/examples/basic/src/tests.rs b/substrate/frame/examples/basic/src/tests.rs index e460ad0992f..207e46e428d 100644 --- a/substrate/frame/examples/basic/src/tests.rs +++ b/substrate/frame/examples/basic/src/tests.rs @@ -27,7 +27,7 @@ use sp_core::H256; // The testing primitives are very useful for avoiding having to work with signatures // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. use sp_runtime::{ - traits::{BlakeTwo256, DispatchTransaction, IdentityLookup}, + traits::{BlakeTwo256, IdentityLookup}, BuildStorage, }; // Reexport crate as its pallet name for construct_runtime. @@ -158,16 +158,13 @@ fn signed_ext_watch_dummy_works() { assert_eq!( WatchDummy::(PhantomData) - .validate_only(Some(1).into(), &call, &info, 150) + .validate(&1, &call, &info, 150) .unwrap() - .0 .priority, u64::MAX, ); assert_eq!( - WatchDummy::(PhantomData) - .validate_only(Some(1).into(), &call, &info, 250) - .unwrap_err(), + WatchDummy::(PhantomData).validate(&1, &call, &info, 250), InvalidTransaction::ExhaustsResources.into(), ); }) diff --git a/substrate/frame/examples/offchain-worker/src/tests.rs b/substrate/frame/examples/offchain-worker/src/tests.rs index 81f2a40840b..ea37a2da493 100644 --- a/substrate/frame/examples/offchain-worker/src/tests.rs +++ b/substrate/frame/examples/offchain-worker/src/tests.rs @@ -30,7 +30,7 @@ use sp_core::{ use sp_keystore::{testing::MemoryKeystore, Keystore, KeystoreExt}; use sp_runtime::{ - generic::UncheckedExtrinsic, + testing::TestXt, traits::{BlakeTwo256, Extrinsic as ExtrinsicT, IdentifyAccount, IdentityLookup, Verify}, RuntimeAppPublic, }; @@ -73,7 +73,7 @@ impl frame_system::Config for Test { type MaxConsumers = ConstU32<16>; } -type Extrinsic = UncheckedExtrinsic; +type Extrinsic = TestXt; type AccountId = <::Signer as IdentifyAccount>::AccountId; impl frame_system::offchain::SigningTypes for Test { @@ -99,7 +99,7 @@ where _account: AccountId, nonce: u64, ) -> Option<(RuntimeCall, ::SignaturePayload)> { - Some((call, (nonce, (), ()))) + Some((call, (nonce, ()))) } } @@ -219,8 +219,8 @@ fn should_submit_signed_transaction_on_chain() { let tx = pool_state.write().transactions.pop().unwrap(); assert!(pool_state.read().transactions.is_empty()); let tx = Extrinsic::decode(&mut &*tx).unwrap(); - assert!(matches!(tx.preamble, sp_runtime::generic::Preamble::Signed(0, (), ()))); - assert_eq!(tx.function, RuntimeCall::Example(crate::Call::submit_price { price: 15523 })); + assert_eq!(tx.signature.unwrap().0, 0); + assert_eq!(tx.call, RuntimeCall::Example(crate::Call::submit_price { price: 15523 })); }); } @@ -259,11 +259,11 @@ fn should_submit_unsigned_transaction_on_chain_for_any_account() { // then let tx = pool_state.write().transactions.pop().unwrap(); let tx = Extrinsic::decode(&mut &*tx).unwrap(); - assert!(tx.is_inherent()); + assert_eq!(tx.signature, None); if let RuntimeCall::Example(crate::Call::submit_price_unsigned_with_signed_payload { price_payload: body, signature, - }) = tx.function + }) = tx.call { assert_eq!(body, price_payload); @@ -313,11 +313,11 @@ fn should_submit_unsigned_transaction_on_chain_for_all_accounts() { // then let tx = pool_state.write().transactions.pop().unwrap(); let tx = Extrinsic::decode(&mut &*tx).unwrap(); - assert!(tx.is_inherent()); + assert_eq!(tx.signature, None); if let RuntimeCall::Example(crate::Call::submit_price_unsigned_with_signed_payload { price_payload: body, signature, - }) = tx.function + }) = tx.call { assert_eq!(body, price_payload); @@ -353,9 +353,9 @@ fn should_submit_raw_unsigned_transaction_on_chain() { let tx = pool_state.write().transactions.pop().unwrap(); assert!(pool_state.read().transactions.is_empty()); let tx = Extrinsic::decode(&mut &*tx).unwrap(); - assert!(tx.is_inherent()); + assert_eq!(tx.signature, None); assert_eq!( - tx.function, + tx.call, RuntimeCall::Example(crate::Call::submit_price_unsigned { block_number: 1, price: 15523 diff --git a/substrate/frame/examples/tasks/src/weights.rs b/substrate/frame/examples/tasks/src/weights.rs index c9ddea6f9a8..793af6e9622 100644 --- a/substrate/frame/examples/tasks/src/weights.rs +++ b/substrate/frame/examples/tasks/src/weights.rs @@ -15,31 +15,30 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `tasks_example` +//! Autogenerated weights for `pallet_example_tasks` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-02, STEPS: `20`, REPEAT: `10`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `MacBook.local`, CPU: `` +//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/release/node-template // benchmark // pallet -// --chain=dev -// --steps=50 -// --repeat=20 -// --pallet=tasks_example -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --wasm-execution=compiled -// --heap-pages=4096 -// --output=./substrate/frame/examples/tasks/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --chain +// dev +// --pallet +// pallet_example_tasks +// --extrinsic +// * +// --steps +// 20 +// --repeat +// 10 +// --output +// frame/examples/tasks/src/weights.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,42 +48,37 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `tasks_example`. +/// Weight functions needed for pallet_template. pub trait WeightInfo { fn add_number_into_total() -> Weight; } -/// Weights for `tasks_example` using the Substrate node and recommended hardware. +/// Weight functions for `pallet_example_kitchensink`. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `TasksExample::Numbers` (r:1 w:1) - /// Proof: `TasksExample::Numbers` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `TasksExample::Total` (r:1 w:1) - /// Proof: `TasksExample::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Kitchensink OtherFoo (r:0 w:1) + /// Proof Skipped: Kitchensink OtherFoo (max_values: Some(1), max_size: None, mode: Measured) fn add_number_into_total() -> Weight { // Proof Size summary in bytes: - // Measured: `149` - // Estimated: `3614` - // Minimum execution time: 5_776_000 picoseconds. - Weight::from_parts(6_178_000, 3614) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_000_000 picoseconds. + Weight::from_parts(1_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) } } -// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: `TasksExample::Numbers` (r:1 w:1) - /// Proof: `TasksExample::Numbers` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `TasksExample::Total` (r:1 w:1) - /// Proof: `TasksExample::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: Kitchensink OtherFoo (r:0 w:1) + /// Proof Skipped: Kitchensink OtherFoo (max_values: Some(1), max_size: None, mode: Measured) fn add_number_into_total() -> Weight { // Proof Size summary in bytes: - // Measured: `149` - // Estimated: `3614` - // Minimum execution time: 5_776_000 picoseconds. - Weight::from_parts(6_178_000, 3614) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_000_000 picoseconds. + Weight::from_parts(1_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(RocksDbWeight::get().writes(1)) } } diff --git a/substrate/frame/executive/src/tests.rs b/substrate/frame/executive/src/tests.rs index a3f70a9fc3c..70b55f6e855 100644 --- a/substrate/frame/executive/src/tests.rs +++ b/substrate/frame/executive/src/tests.rs @@ -327,42 +327,10 @@ impl frame_system::Config for Runtime { type Balance = u64; -pub struct BalancesWeights; -impl pallet_balances::WeightInfo for BalancesWeights { - fn transfer_allow_death() -> Weight { - Weight::from_parts(25, 0) - } - fn transfer_keep_alive() -> Weight { - Weight::zero() - } - fn force_set_balance_creating() -> Weight { - Weight::zero() - } - fn force_set_balance_killing() -> Weight { - Weight::zero() - } - fn force_transfer() -> Weight { - Weight::zero() - } - fn transfer_all() -> Weight { - Weight::zero() - } - fn force_unreserve() -> Weight { - Weight::zero() - } - fn upgrade_accounts(_u: u32) -> Weight { - Weight::zero() - } - fn force_adjust_total_issuance() -> Weight { - Weight::zero() - } -} - #[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] impl pallet_balances::Config for Runtime { type Balance = Balance; type AccountStore = System; - type WeightInfo = BalancesWeights; } parameter_types! { @@ -375,7 +343,6 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = IdentityFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = (); - type WeightInfo = (); } impl custom::Config for Runtime {} @@ -388,46 +355,19 @@ impl frame_support::traits::Get for RuntimeVersion { } } -#[derive(Clone, Debug, Encode, codec::Decode, PartialEq, Eq, scale_info::TypeInfo)] -pub struct AccountU64(u64); -impl sp_runtime::traits::IdentifyAccount for AccountU64 { - type AccountId = u64; - fn into_account(self) -> u64 { - self.0 - } -} - -impl sp_runtime::traits::Verify for AccountU64 { - type Signer = AccountU64; - fn verify>( - &self, - _msg: L, - _signer: &::AccountId, - ) -> bool { - true - } -} - -impl From for AccountU64 { - fn from(value: u64) -> Self { - Self(value) - } -} - parameter_types! { pub static RuntimeVersionTestValues: sp_version::RuntimeVersion = Default::default(); } -type TxExtension = ( +type SignedExtra = ( frame_system::CheckEra, frame_system::CheckNonce, frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, ); -type UncheckedXt = - sp_runtime::generic::UncheckedExtrinsic; -type TestBlock = Block; +type TestXt = sp_runtime::testing::TestXt; +type TestBlock = Block; // Will contain `true` when the custom runtime logic was called. const CUSTOM_ON_RUNTIME_KEY: &[u8] = b":custom:on_runtime"; @@ -447,7 +387,7 @@ impl OnRuntimeUpgrade for CustomOnRuntimeUpgrade { type Executive = super::Executive< Runtime, - Block, + Block, ChainContext, Runtime, AllPalletsWithSystem, @@ -522,14 +462,17 @@ impl MultiStepMigrator for MockedModeGetter { } } -fn tx_ext(nonce: u64, fee: Balance) -> TxExtension { +fn extra(nonce: u64, fee: Balance) -> SignedExtra { ( frame_system::CheckEra::from(Era::Immortal), frame_system::CheckNonce::from(nonce), frame_system::CheckWeight::new(), pallet_transaction_payment::ChargeTransactionPayment::from(fee), ) - .into() +} + +fn sign_extra(who: u64, nonce: u64, fee: Balance) -> Option<(u64, SignedExtra)> { + Some((who, extra(nonce, fee))) } fn call_transfer(dest: u64, value: u64) -> RuntimeCall { @@ -542,7 +485,7 @@ fn balance_transfer_dispatch_works() { pallet_balances::GenesisConfig:: { balances: vec![(1, 211)] } .assimilate_storage(&mut t) .unwrap(); - let xt = UncheckedXt::new_signed(call_transfer(2, 69), 1, 1.into(), tx_ext(0, 0)); + let xt = TestXt::new(call_transfer(2, 69), sign_extra(1, 0, 0)); let weight = xt.get_dispatch_info().weight + ::BlockWeights::get() .get(DispatchClass::Normal) @@ -653,7 +596,7 @@ fn block_import_of_bad_extrinsic_root_fails() { fn bad_extrinsic_not_inserted() { let mut t = new_test_ext(1); // bad nonce check! - let xt = UncheckedXt::new_signed(call_transfer(33, 69), 1, 1.into(), tx_ext(30, 0)); + let xt = TestXt::new(call_transfer(33, 69), sign_extra(1, 30, 0)); t.execute_with(|| { Executive::initialize_block(&Header::new_from_number(1)); assert_err!( @@ -667,24 +610,27 @@ fn bad_extrinsic_not_inserted() { #[test] fn block_weight_limit_enforced() { let mut t = new_test_ext(10000); - let transfer_weight = - <::WeightInfo as pallet_balances::WeightInfo>::transfer_allow_death(); + // given: TestXt uses the encoded len as fixed Len: + let xt = TestXt::new( + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), + sign_extra(1, 0, 0), + ); + let encoded = xt.encode(); + let encoded_len = encoded.len() as u64; // on_initialize weight + base block execution weight let block_weights = ::BlockWeights::get(); let base_block_weight = Weight::from_parts(175, 0) + block_weights.base_block; let limit = block_weights.get(DispatchClass::Normal).max_total.unwrap() - base_block_weight; - let num_to_exhaust_block = limit.ref_time() / (transfer_weight.ref_time() + 5); + let num_to_exhaust_block = limit.ref_time() / (encoded_len + 5); t.execute_with(|| { Executive::initialize_block(&Header::new_from_number(1)); // Base block execution weight + `on_initialize` weight from the custom module. assert_eq!(>::block_weight().total(), base_block_weight); for nonce in 0..=num_to_exhaust_block { - let xt = UncheckedXt::new_signed( + let xt = TestXt::new( RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), - 1, - 1.into(), - tx_ext(nonce.into(), 0), + sign_extra(1, nonce.into(), 0), ); let res = Executive::apply_extrinsic(xt); if nonce != num_to_exhaust_block { @@ -692,8 +638,7 @@ fn block_weight_limit_enforced() { assert_eq!( >::block_weight().total(), //--------------------- on_initialize + block_execution + extrinsic_base weight - Weight::from_parts((transfer_weight.ref_time() + 5) * (nonce + 1), 0) + - base_block_weight, + Weight::from_parts((encoded_len + 5) * (nonce + 1), 0) + base_block_weight, ); assert_eq!( >::extrinsic_index(), @@ -708,26 +653,19 @@ fn block_weight_limit_enforced() { #[test] fn block_weight_and_size_is_stored_per_tx() { - let xt = UncheckedXt::new_signed( + let xt = TestXt::new( RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), - 1, - 1.into(), - tx_ext(0, 0), + sign_extra(1, 0, 0), ); - let x1 = UncheckedXt::new_signed( + let x1 = TestXt::new( RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), - 1, - 1.into(), - tx_ext(1, 0), + sign_extra(1, 1, 0), ); - let x2 = UncheckedXt::new_signed( + let x2 = TestXt::new( RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), - 1, - 1.into(), - tx_ext(2, 0), + sign_extra(1, 2, 0), ); let len = xt.clone().encode().len() as u32; - let transfer_weight = <::WeightInfo as pallet_balances::WeightInfo>::transfer_allow_death(); let mut t = new_test_ext(1); t.execute_with(|| { // Block execution weight + on_initialize weight from custom module @@ -743,7 +681,8 @@ fn block_weight_and_size_is_stored_per_tx() { assert!(Executive::apply_extrinsic(x1.clone()).unwrap().is_ok()); assert!(Executive::apply_extrinsic(x2.clone()).unwrap().is_ok()); - let extrinsic_weight = transfer_weight + + // default weight for `TestXt` == encoded length. + let extrinsic_weight = Weight::from_parts(len as u64, 0) + ::BlockWeights::get() .get(DispatchClass::Normal) .base_extrinsic; @@ -768,8 +707,8 @@ fn block_weight_and_size_is_stored_per_tx() { #[test] fn validate_unsigned() { - let valid = UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::allowed_unsigned {})); - let invalid = UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::unallowed_unsigned {})); + let valid = TestXt::new(RuntimeCall::Custom(custom::Call::allowed_unsigned {}), None); + let invalid = TestXt::new(RuntimeCall::Custom(custom::Call::unallowed_unsigned {}), None); let mut t = new_test_ext(1); t.execute_with(|| { @@ -806,11 +745,9 @@ fn can_not_pay_for_tx_fee_on_full_lock() { t.execute_with(|| { as fungible::MutateFreeze>::set_freeze(&(), &1, 110) .unwrap(); - let xt = UncheckedXt::new_signed( + let xt = TestXt::new( RuntimeCall::System(frame_system::Call::remark { remark: vec![1u8] }), - 1, - 1.into(), - tx_ext(0, 0), + sign_extra(1, 0, 0), ); Executive::initialize_block(&Header::new_from_number(1)); @@ -935,11 +872,9 @@ fn event_from_runtime_upgrade_is_included() { /// used through the `ExecuteBlock` trait. #[test] fn custom_runtime_upgrade_is_called_when_using_execute_block_trait() { - let xt = UncheckedXt::new_signed( + let xt = TestXt::new( RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), - 1, - 1.into(), - tx_ext(0, 0), + sign_extra(1, 0, 0), ); let header = new_test_ext(1).execute_with(|| { @@ -967,10 +902,7 @@ fn custom_runtime_upgrade_is_called_when_using_execute_block_trait() { *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } }); - >>::execute_block(Block::new( - header, - vec![xt], - )); + >>::execute_block(Block::new(header, vec![xt])); assert_eq!(&sp_io::storage::get(TEST_KEY).unwrap()[..], *b"module"); assert_eq!(sp_io::storage::get(CUSTOM_ON_RUNTIME_KEY).unwrap(), true.encode()); @@ -1036,7 +968,7 @@ fn offchain_worker_works_as_expected() { #[test] fn calculating_storage_root_twice_works() { let call = RuntimeCall::Custom(custom::Call::calculate_storage_root {}); - let xt = UncheckedXt::new_signed(call, 1, 1.into(), tx_ext(0, 0)); + let xt = TestXt::new(call, sign_extra(1, 0, 0)); let header = new_test_ext(1).execute_with(|| { // Let's build some fake block. @@ -1055,13 +987,11 @@ fn calculating_storage_root_twice_works() { #[test] #[should_panic(expected = "Invalid inherent position for extrinsic at index 1")] fn invalid_inherent_position_fail() { - let xt1 = UncheckedXt::new_signed( + let xt1 = TestXt::new( RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), - 1, - 1.into(), - tx_ext(0, 0), + sign_extra(1, 0, 0), ); - let xt2 = UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::inherent {})); + let xt2 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent {}), None); let header = new_test_ext(1).execute_with(|| { // Let's build some fake block. @@ -1080,8 +1010,8 @@ fn invalid_inherent_position_fail() { #[test] fn valid_inherents_position_works() { - let xt1 = UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::inherent {})); - let xt2 = UncheckedXt::new_signed(call_transfer(33, 0), 1, 1.into(), tx_ext(0, 0)); + let xt1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent {}), None); + let xt2 = TestXt::new(call_transfer(33, 0), sign_extra(1, 0, 0)); let header = new_test_ext(1).execute_with(|| { // Let's build some fake block. @@ -1101,12 +1031,7 @@ fn valid_inherents_position_works() { #[test] #[should_panic(expected = "A call was labelled as mandatory, but resulted in an Error.")] fn invalid_inherents_fail_block_execution() { - let xt1 = UncheckedXt::new_signed( - RuntimeCall::Custom(custom::Call::inherent {}), - 1, - 1.into(), - tx_ext(0, 0), - ); + let xt1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent {}), sign_extra(1, 0, 0)); new_test_ext(1).execute_with(|| { Executive::execute_block(Block::new( @@ -1119,7 +1044,7 @@ fn invalid_inherents_fail_block_execution() { // Inherents are created by the runtime and don't need to be validated. #[test] fn inherents_fail_validate_block() { - let xt1 = UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::inherent {})); + let xt1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent {}), None); new_test_ext(1).execute_with(|| { assert_eq!( @@ -1133,7 +1058,7 @@ fn inherents_fail_validate_block() { /// Inherents still work while `initialize_block` forbids transactions. #[test] fn inherents_ok_while_exts_forbidden_works() { - let xt1 = UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::inherent {})); + let xt1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent {}), None); let header = new_test_ext(1).execute_with(|| { Executive::initialize_block(&Header::new_from_number(1)); @@ -1153,8 +1078,8 @@ fn inherents_ok_while_exts_forbidden_works() { #[test] #[should_panic = "Only inherents are allowed in this block"] fn transactions_in_only_inherents_block_errors() { - let xt1 = UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::inherent {})); - let xt2 = UncheckedXt::new_signed(call_transfer(33, 0), 1, 1.into(), tx_ext(0, 0)); + let xt1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent {}), None); + let xt2 = TestXt::new(call_transfer(33, 0), sign_extra(1, 0, 0)); let header = new_test_ext(1).execute_with(|| { Executive::initialize_block(&Header::new_from_number(1)); @@ -1174,8 +1099,8 @@ fn transactions_in_only_inherents_block_errors() { /// Same as above but no error. #[test] fn transactions_in_normal_block_works() { - let xt1 = UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::inherent {})); - let xt2 = UncheckedXt::new_signed(call_transfer(33, 0), 1, 1.into(), tx_ext(0, 0)); + let xt1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent {}), None); + let xt2 = TestXt::new(call_transfer(33, 0), sign_extra(1, 0, 0)); let header = new_test_ext(1).execute_with(|| { Executive::initialize_block(&Header::new_from_number(1)); @@ -1195,8 +1120,8 @@ fn transactions_in_normal_block_works() { #[test] #[cfg(feature = "try-runtime")] fn try_execute_block_works() { - let xt1 = UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::inherent {})); - let xt2 = UncheckedXt::new_signed(call_transfer(33, 0), 1, 1.into(), tx_ext(0, 0)); + let xt1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent {}), None); + let xt2 = TestXt::new(call_transfer(33, 0), sign_extra(1, 0, 0)); let header = new_test_ext(1).execute_with(|| { Executive::initialize_block(&Header::new_from_number(1)); @@ -1223,8 +1148,8 @@ fn try_execute_block_works() { #[cfg(feature = "try-runtime")] #[should_panic = "Only inherents allowed"] fn try_execute_tx_forbidden_errors() { - let xt1 = UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::inherent {})); - let xt2 = UncheckedXt::new_signed(call_transfer(33, 0), 1, 1.into(), tx_ext(0, 0)); + let xt1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent {}), None); + let xt2 = TestXt::new(call_transfer(33, 0), sign_extra(1, 0, 0)); let header = new_test_ext(1).execute_with(|| { // Let's build some fake block. @@ -1251,9 +1176,9 @@ fn try_execute_tx_forbidden_errors() { /// Check that `ensure_inherents_are_first` reports the correct indices. #[test] fn ensure_inherents_are_first_works() { - let in1 = UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::inherent {})); - let in2 = UncheckedXt::new_bare(RuntimeCall::Custom2(custom2::Call::inherent {})); - let xt2 = UncheckedXt::new_signed(call_transfer(33, 0), 1, 1.into(), tx_ext(0, 0)); + let in1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent {}), None); + let in2 = TestXt::new(RuntimeCall::Custom2(custom2::Call::inherent {}), None); + let xt2 = TestXt::new(call_transfer(33, 0), sign_extra(1, 0, 0)); // Mocked empty header: let header = new_test_ext(1).execute_with(|| { @@ -1331,20 +1256,18 @@ fn callbacks_in_block_execution_works_inner(mbms_active: bool) { for i in 0..n_in { let xt = if i % 2 == 0 { - UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::inherent {})) + TestXt::new(RuntimeCall::Custom(custom::Call::inherent {}), None) } else { - UncheckedXt::new_bare(RuntimeCall::Custom2(custom2::Call::optional_inherent {})) + TestXt::new(RuntimeCall::Custom2(custom2::Call::optional_inherent {}), None) }; Executive::apply_extrinsic(xt.clone()).unwrap().unwrap(); extrinsics.push(xt); } for t in 0..n_tx { - let xt = UncheckedXt::new_signed( + let xt = TestXt::new( RuntimeCall::Custom2(custom2::Call::some_call {}), - 1, - 1.into(), - tx_ext(t as u64, 0), + sign_extra(1, t as u64, 0), ); // Extrinsics can be applied even when MBMs are active. Only the `execute_block` // will reject it. @@ -1384,13 +1307,8 @@ fn callbacks_in_block_execution_works_inner(mbms_active: bool) { #[test] fn post_inherent_called_after_all_inherents() { - let in1 = UncheckedXt::new_bare(RuntimeCall::Custom2(custom2::Call::inherent {})); - let xt1 = UncheckedXt::new_signed( - RuntimeCall::Custom2(custom2::Call::some_call {}), - 1, - 1.into(), - tx_ext(0, 0), - ); + let in1 = TestXt::new(RuntimeCall::Custom2(custom2::Call::inherent {}), None); + let xt1 = TestXt::new(RuntimeCall::Custom2(custom2::Call::some_call {}), sign_extra(1, 0, 0)); let header = new_test_ext(1).execute_with(|| { // Let's build some fake block. @@ -1424,13 +1342,8 @@ fn post_inherent_called_after_all_inherents() { /// Regression test for AppSec finding #40. #[test] fn post_inherent_called_after_all_optional_inherents() { - let in1 = UncheckedXt::new_bare(RuntimeCall::Custom2(custom2::Call::optional_inherent {})); - let xt1 = UncheckedXt::new_signed( - RuntimeCall::Custom2(custom2::Call::some_call {}), - 1, - 1.into(), - tx_ext(0, 0), - ); + let in1 = TestXt::new(RuntimeCall::Custom2(custom2::Call::optional_inherent {}), None); + let xt1 = TestXt::new(RuntimeCall::Custom2(custom2::Call::some_call {}), sign_extra(1, 0, 0)); let header = new_test_ext(1).execute_with(|| { // Let's build some fake block. @@ -1463,14 +1376,14 @@ fn post_inherent_called_after_all_optional_inherents() { #[test] fn is_inherent_works() { - let ext = UncheckedXt::new_bare(RuntimeCall::Custom2(custom2::Call::inherent {})); + let ext = TestXt::new(RuntimeCall::Custom2(custom2::Call::inherent {}), None); assert!(Runtime::is_inherent(&ext)); - let ext = UncheckedXt::new_bare(RuntimeCall::Custom2(custom2::Call::optional_inherent {})); + let ext = TestXt::new(RuntimeCall::Custom2(custom2::Call::optional_inherent {}), None); assert!(Runtime::is_inherent(&ext)); - let ext = UncheckedXt::new_signed(call_transfer(33, 0), 1, 1.into(), tx_ext(0, 0)); + let ext = TestXt::new(call_transfer(33, 0), sign_extra(1, 0, 0)); assert!(!Runtime::is_inherent(&ext)); - let ext = UncheckedXt::new_bare(RuntimeCall::Custom2(custom2::Call::allowed_unsigned {})); + let ext = TestXt::new(RuntimeCall::Custom2(custom2::Call::allowed_unsigned {}), None); assert!(!Runtime::is_inherent(&ext), "Unsigned ext are not automatically inherents"); } diff --git a/substrate/frame/fast-unstake/src/weights.rs b/substrate/frame/fast-unstake/src/weights.rs index d783ba921bf..9c25a409f74 100644 --- a/substrate/frame/fast-unstake/src/weights.rs +++ b/substrate/frame/fast-unstake/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_fast_unstake` +//! Autogenerated weights for pallet_fast_unstake //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/fast-unstake/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/fast-unstake/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_fast_unstake`. +/// Weight functions needed for pallet_fast_unstake. pub trait WeightInfo { fn on_idle_unstake(b: u32, ) -> Weight; fn on_idle_check(v: u32, b: u32, ) -> Weight; @@ -58,305 +59,301 @@ pub trait WeightInfo { fn control() -> Weight; } -/// Weights for `pallet_fast_unstake` using the Substrate node and recommended hardware. +/// Weights for pallet_fast_unstake using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0) - /// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::ValidatorCount` (r:1 w:0) - /// Proof: `Staking::ValidatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `FastUnstake::Head` (r:1 w:1) - /// Proof: `FastUnstake::Head` (`max_values`: Some(1), `max_size`: Some(5768), added: 6263, mode: `MaxEncodedLen`) - /// Storage: `FastUnstake::CounterForQueue` (r:1 w:0) - /// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Staking::CurrentEra` (r:1 w:0) - /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::SlashingSpans` (r:64 w:0) - /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Staking::Bonded` (r:64 w:64) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:64 w:64) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:64 w:64) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:64 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:64 w:64) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Staking::Validators` (r:64 w:0) - /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) - /// Storage: `Staking::Nominators` (r:64 w:0) - /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) - /// Storage: `Staking::Payee` (r:0 w:64) - /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) + /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ValidatorCount (r:1 w:0) + /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: FastUnstake Head (r:1 w:1) + /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(5768), added: 6263, mode: MaxEncodedLen) + /// Storage: FastUnstake CounterForQueue (r:1 w:0) + /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking SlashingSpans (r:64 w:0) + /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking Bonded (r:64 w:64) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:64 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:64 w:0) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: System Account (r:64 w:64) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:64 w:64) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:64 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:0 w:64) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:64) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// The range of component `b` is `[1, 64]`. fn on_idle_unstake(b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1475 + b * (452 ±0)` + // Measured: `1378 + b * (343 ±0)` // Estimated: `7253 + b * (3774 ±0)` - // Minimum execution time: 89_005_000 picoseconds. - Weight::from_parts(50_257_055, 7253) - // Standard Error: 68_836 - .saturating_add(Weight::from_parts(57_329_950, 0).saturating_mul(b.into())) + // Minimum execution time: 92_847_000 picoseconds. + Weight::from_parts(42_300_813, 7253) + // Standard Error: 40_514 + .saturating_add(Weight::from_parts(58_412_402, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().reads((8_u64).saturating_mul(b.into()))) + .saturating_add(T::DbWeight::get().reads((7_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((5_u64).saturating_mul(b.into()))) .saturating_add(Weight::from_parts(0, 3774).saturating_mul(b.into())) } - /// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0) - /// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::ValidatorCount` (r:1 w:0) - /// Proof: `Staking::ValidatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `FastUnstake::Head` (r:1 w:1) - /// Proof: `FastUnstake::Head` (`max_values`: Some(1), `max_size`: Some(5768), added: 6263, mode: `MaxEncodedLen`) - /// Storage: `FastUnstake::CounterForQueue` (r:1 w:0) - /// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Staking::CurrentEra` (r:1 w:0) - /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::ErasStakers` (r:1 w:0) - /// Proof: `Staking::ErasStakers` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Staking::ErasStakersPaged` (r:257 w:0) - /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) + /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ValidatorCount (r:1 w:0) + /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: FastUnstake Head (r:1 w:1) + /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(5768), added: 6263, mode: MaxEncodedLen) + /// Storage: FastUnstake CounterForQueue (r:1 w:0) + /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ErasStakers (r:257 w:0) + /// Proof Skipped: Staking ErasStakers (max_values: None, max_size: None, mode: Measured) /// The range of component `v` is `[1, 256]`. /// The range of component `b` is `[1, 64]`. fn on_idle_check(v: u32, b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1879 + b * (55 ±0) + v * (10055 ±0)` - // Estimated: `7253 + b * (56 ±0) + v * (12531 ±0)` - // Minimum execution time: 1_737_131_000 picoseconds. - Weight::from_parts(1_746_770_000, 7253) - // Standard Error: 13_401_143 - .saturating_add(Weight::from_parts(426_946_450, 0).saturating_mul(v.into())) - // Standard Error: 53_619_501 - .saturating_add(Weight::from_parts(1_664_681_508, 0).saturating_mul(b.into())) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `1546 + b * (48 ±0) + v * (10037 ±0)` + // Estimated: `7253 + b * (49 ±0) + v * (12513 ±0)` + // Minimum execution time: 1_685_784_000 picoseconds. + Weight::from_parts(1_693_370_000, 7253) + // Standard Error: 13_295_842 + .saturating_add(Weight::from_parts(425_349_148, 0).saturating_mul(v.into())) + // Standard Error: 53_198_180 + .saturating_add(Weight::from_parts(1_673_328_444, 0).saturating_mul(b.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_parts(0, 56).saturating_mul(b.into())) - .saturating_add(Weight::from_parts(0, 12531).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 49).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 12513).saturating_mul(v.into())) } - /// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0) - /// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:1 w:1) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `FastUnstake::Queue` (r:1 w:1) - /// Proof: `FastUnstake::Queue` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`) - /// Storage: `FastUnstake::Head` (r:1 w:0) - /// Proof: `FastUnstake::Head` (`max_values`: Some(1), `max_size`: Some(5768), added: 6263, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Staking::Validators` (r:1 w:0) - /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) - /// Storage: `Staking::Nominators` (r:1 w:1) - /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) - /// Storage: `Staking::CounterForNominators` (r:1 w:1) - /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListNodes` (r:1 w:1) - /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListBags` (r:1 w:1) - /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) - /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) - /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::CurrentEra` (r:1 w:0) - /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `FastUnstake::CounterForQueue` (r:1 w:1) - /// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) + /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: FastUnstake Queue (r:1 w:1) + /// Proof: FastUnstake Queue (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: FastUnstake Head (r:1 w:0) + /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(5768), added: 6263, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:1 w:1) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: FastUnstake CounterForQueue (r:1 w:1) + /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn register_fast_unstake() -> Weight { // Proof Size summary in bytes: - // Measured: `1955` + // Measured: `1964` // Estimated: `7253` - // Minimum execution time: 112_632_000 picoseconds. - Weight::from_parts(117_267_000, 7253) + // Minimum execution time: 125_512_000 picoseconds. + Weight::from_parts(129_562_000, 7253) .saturating_add(T::DbWeight::get().reads(15_u64)) .saturating_add(T::DbWeight::get().writes(9_u64)) } - /// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0) - /// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:1 w:0) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `FastUnstake::Queue` (r:1 w:1) - /// Proof: `FastUnstake::Queue` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`) - /// Storage: `FastUnstake::Head` (r:1 w:0) - /// Proof: `FastUnstake::Head` (`max_values`: Some(1), `max_size`: Some(5768), added: 6263, mode: `MaxEncodedLen`) - /// Storage: `FastUnstake::CounterForQueue` (r:1 w:1) - /// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) + /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: FastUnstake Queue (r:1 w:1) + /// Proof: FastUnstake Queue (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: FastUnstake Head (r:1 w:0) + /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(5768), added: 6263, mode: MaxEncodedLen) + /// Storage: FastUnstake CounterForQueue (r:1 w:1) + /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn deregister() -> Weight { // Proof Size summary in bytes: - // Measured: `1251` + // Measured: `1223` // Estimated: `7253` - // Minimum execution time: 39_253_000 picoseconds. - Weight::from_parts(40_053_000, 7253) + // Minimum execution time: 43_943_000 picoseconds. + Weight::from_parts(45_842_000, 7253) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `FastUnstake::ErasToCheckPerBlock` (r:0 w:1) - /// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: FastUnstake ErasToCheckPerBlock (r:0 w:1) + /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn control() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_386_000 picoseconds. - Weight::from_parts(2_508_000, 0) + // Minimum execution time: 2_677_000 picoseconds. + Weight::from_parts(2_849_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0) - /// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::ValidatorCount` (r:1 w:0) - /// Proof: `Staking::ValidatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `FastUnstake::Head` (r:1 w:1) - /// Proof: `FastUnstake::Head` (`max_values`: Some(1), `max_size`: Some(5768), added: 6263, mode: `MaxEncodedLen`) - /// Storage: `FastUnstake::CounterForQueue` (r:1 w:0) - /// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Staking::CurrentEra` (r:1 w:0) - /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::SlashingSpans` (r:64 w:0) - /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Staking::Bonded` (r:64 w:64) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:64 w:64) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:64 w:64) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:64 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:64 w:64) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Staking::Validators` (r:64 w:0) - /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) - /// Storage: `Staking::Nominators` (r:64 w:0) - /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) - /// Storage: `Staking::Payee` (r:0 w:64) - /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) + /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ValidatorCount (r:1 w:0) + /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: FastUnstake Head (r:1 w:1) + /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(5768), added: 6263, mode: MaxEncodedLen) + /// Storage: FastUnstake CounterForQueue (r:1 w:0) + /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking SlashingSpans (r:64 w:0) + /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking Bonded (r:64 w:64) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:64 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:64 w:0) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: System Account (r:64 w:64) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:64 w:64) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:64 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:0 w:64) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:64) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// The range of component `b` is `[1, 64]`. fn on_idle_unstake(b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1475 + b * (452 ±0)` + // Measured: `1378 + b * (343 ±0)` // Estimated: `7253 + b * (3774 ±0)` - // Minimum execution time: 89_005_000 picoseconds. - Weight::from_parts(50_257_055, 7253) - // Standard Error: 68_836 - .saturating_add(Weight::from_parts(57_329_950, 0).saturating_mul(b.into())) + // Minimum execution time: 92_847_000 picoseconds. + Weight::from_parts(42_300_813, 7253) + // Standard Error: 40_514 + .saturating_add(Weight::from_parts(58_412_402, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().reads((8_u64).saturating_mul(b.into()))) + .saturating_add(RocksDbWeight::get().reads((7_u64).saturating_mul(b.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((5_u64).saturating_mul(b.into()))) .saturating_add(Weight::from_parts(0, 3774).saturating_mul(b.into())) } - /// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0) - /// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::ValidatorCount` (r:1 w:0) - /// Proof: `Staking::ValidatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `FastUnstake::Head` (r:1 w:1) - /// Proof: `FastUnstake::Head` (`max_values`: Some(1), `max_size`: Some(5768), added: 6263, mode: `MaxEncodedLen`) - /// Storage: `FastUnstake::CounterForQueue` (r:1 w:0) - /// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `ElectionProviderMultiPhase::CurrentPhase` (r:1 w:0) - /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Staking::CurrentEra` (r:1 w:0) - /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::ErasStakers` (r:1 w:0) - /// Proof: `Staking::ErasStakers` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Staking::ErasStakersPaged` (r:257 w:0) - /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) + /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ValidatorCount (r:1 w:0) + /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: FastUnstake Head (r:1 w:1) + /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(5768), added: 6263, mode: MaxEncodedLen) + /// Storage: FastUnstake CounterForQueue (r:1 w:0) + /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ErasStakers (r:257 w:0) + /// Proof Skipped: Staking ErasStakers (max_values: None, max_size: None, mode: Measured) /// The range of component `v` is `[1, 256]`. /// The range of component `b` is `[1, 64]`. fn on_idle_check(v: u32, b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1879 + b * (55 ±0) + v * (10055 ±0)` - // Estimated: `7253 + b * (56 ±0) + v * (12531 ±0)` - // Minimum execution time: 1_737_131_000 picoseconds. - Weight::from_parts(1_746_770_000, 7253) - // Standard Error: 13_401_143 - .saturating_add(Weight::from_parts(426_946_450, 0).saturating_mul(v.into())) - // Standard Error: 53_619_501 - .saturating_add(Weight::from_parts(1_664_681_508, 0).saturating_mul(b.into())) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `1546 + b * (48 ±0) + v * (10037 ±0)` + // Estimated: `7253 + b * (49 ±0) + v * (12513 ±0)` + // Minimum execution time: 1_685_784_000 picoseconds. + Weight::from_parts(1_693_370_000, 7253) + // Standard Error: 13_295_842 + .saturating_add(Weight::from_parts(425_349_148, 0).saturating_mul(v.into())) + // Standard Error: 53_198_180 + .saturating_add(Weight::from_parts(1_673_328_444, 0).saturating_mul(b.into())) + .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_parts(0, 56).saturating_mul(b.into())) - .saturating_add(Weight::from_parts(0, 12531).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(0, 49).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 12513).saturating_mul(v.into())) } - /// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0) - /// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:1 w:1) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `FastUnstake::Queue` (r:1 w:1) - /// Proof: `FastUnstake::Queue` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`) - /// Storage: `FastUnstake::Head` (r:1 w:0) - /// Proof: `FastUnstake::Head` (`max_values`: Some(1), `max_size`: Some(5768), added: 6263, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Staking::Validators` (r:1 w:0) - /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) - /// Storage: `Staking::Nominators` (r:1 w:1) - /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) - /// Storage: `Staking::CounterForNominators` (r:1 w:1) - /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListNodes` (r:1 w:1) - /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListBags` (r:1 w:1) - /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) - /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) - /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::CurrentEra` (r:1 w:0) - /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `FastUnstake::CounterForQueue` (r:1 w:1) - /// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) + /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: FastUnstake Queue (r:1 w:1) + /// Proof: FastUnstake Queue (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: FastUnstake Head (r:1 w:0) + /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(5768), added: 6263, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:1 w:1) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: FastUnstake CounterForQueue (r:1 w:1) + /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn register_fast_unstake() -> Weight { // Proof Size summary in bytes: - // Measured: `1955` + // Measured: `1964` // Estimated: `7253` - // Minimum execution time: 112_632_000 picoseconds. - Weight::from_parts(117_267_000, 7253) + // Minimum execution time: 125_512_000 picoseconds. + Weight::from_parts(129_562_000, 7253) .saturating_add(RocksDbWeight::get().reads(15_u64)) .saturating_add(RocksDbWeight::get().writes(9_u64)) } - /// Storage: `FastUnstake::ErasToCheckPerBlock` (r:1 w:0) - /// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:1 w:0) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `FastUnstake::Queue` (r:1 w:1) - /// Proof: `FastUnstake::Queue` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`) - /// Storage: `FastUnstake::Head` (r:1 w:0) - /// Proof: `FastUnstake::Head` (`max_values`: Some(1), `max_size`: Some(5768), added: 6263, mode: `MaxEncodedLen`) - /// Storage: `FastUnstake::CounterForQueue` (r:1 w:1) - /// Proof: `FastUnstake::CounterForQueue` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) + /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: FastUnstake Queue (r:1 w:1) + /// Proof: FastUnstake Queue (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) + /// Storage: FastUnstake Head (r:1 w:0) + /// Proof: FastUnstake Head (max_values: Some(1), max_size: Some(5768), added: 6263, mode: MaxEncodedLen) + /// Storage: FastUnstake CounterForQueue (r:1 w:1) + /// Proof: FastUnstake CounterForQueue (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn deregister() -> Weight { // Proof Size summary in bytes: - // Measured: `1251` + // Measured: `1223` // Estimated: `7253` - // Minimum execution time: 39_253_000 picoseconds. - Weight::from_parts(40_053_000, 7253) + // Minimum execution time: 43_943_000 picoseconds. + Weight::from_parts(45_842_000, 7253) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `FastUnstake::ErasToCheckPerBlock` (r:0 w:1) - /// Proof: `FastUnstake::ErasToCheckPerBlock` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: FastUnstake ErasToCheckPerBlock (r:0 w:1) + /// Proof: FastUnstake ErasToCheckPerBlock (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn control() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_386_000 picoseconds. - Weight::from_parts(2_508_000, 0) + // Minimum execution time: 2_677_000 picoseconds. + Weight::from_parts(2_849_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/substrate/frame/glutton/src/weights.rs b/substrate/frame/glutton/src/weights.rs index b2e28dc488a..cbc0fb022f5 100644 --- a/substrate/frame/glutton/src/weights.rs +++ b/substrate/frame/glutton/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_glutton` +//! Autogenerated weights for pallet_glutton //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/glutton/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/glutton/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_glutton`. +/// Weight functions needed for pallet_glutton. pub trait WeightInfo { fn initialize_pallet_grow(n: u32, ) -> Weight; fn initialize_pallet_shrink(n: u32, ) -> Weight; @@ -62,39 +63,39 @@ pub trait WeightInfo { fn set_storage() -> Weight; } -/// Weights for `pallet_glutton` using the Substrate node and recommended hardware. +/// Weights for pallet_glutton using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Glutton::TrashDataCount` (r:1 w:1) - /// Proof: `Glutton::TrashDataCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Glutton::TrashData` (r:0 w:1000) - /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) + /// Storage: Glutton TrashDataCount (r:1 w:1) + /// Proof: Glutton TrashDataCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Glutton TrashData (r:0 w:1000) + /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) /// The range of component `n` is `[0, 1000]`. fn initialize_pallet_grow(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `86` // Estimated: `1489` - // Minimum execution time: 8_443_000 picoseconds. - Weight::from_parts(103_698_651, 1489) - // Standard Error: 21_777 - .saturating_add(Weight::from_parts(9_529_476, 0).saturating_mul(n.into())) + // Minimum execution time: 11_488_000 picoseconds. + Weight::from_parts(93_073_710, 1489) + // Standard Error: 22_390 + .saturating_add(Weight::from_parts(9_572_012, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) } - /// Storage: `Glutton::TrashDataCount` (r:1 w:1) - /// Proof: `Glutton::TrashDataCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Glutton::TrashData` (r:0 w:1000) - /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) + /// Storage: Glutton TrashDataCount (r:1 w:1) + /// Proof: Glutton TrashDataCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Glutton TrashData (r:0 w:1000) + /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) /// The range of component `n` is `[0, 1000]`. fn initialize_pallet_shrink(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `119` // Estimated: `1489` - // Minimum execution time: 8_343_000 picoseconds. - Weight::from_parts(304_498, 1489) - // Standard Error: 1_568 - .saturating_add(Weight::from_parts(1_146_553, 0).saturating_mul(n.into())) + // Minimum execution time: 11_378_000 picoseconds. + Weight::from_parts(5_591_508, 1489) + // Standard Error: 1_592 + .saturating_add(Weight::from_parts(1_163_758, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -104,119 +105,119 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 656_000 picoseconds. - Weight::from_parts(1_875_128, 0) - // Standard Error: 8 - .saturating_add(Weight::from_parts(103_381, 0).saturating_mul(i.into())) + // Minimum execution time: 669_000 picoseconds. + Weight::from_parts(990_745, 0) + // Standard Error: 10 + .saturating_add(Weight::from_parts(105_224, 0).saturating_mul(i.into())) } - /// Storage: `Glutton::TrashData` (r:5000 w:0) - /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) + /// Storage: Glutton TrashData (r:5000 w:0) + /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) /// The range of component `i` is `[0, 5000]`. fn waste_proof_size_some(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `119114 + i * (1022 ±0)` // Estimated: `990 + i * (3016 ±0)` - // Minimum execution time: 454_000 picoseconds. - Weight::from_parts(521_000, 990) - // Standard Error: 1_940 - .saturating_add(Weight::from_parts(5_729_831, 0).saturating_mul(i.into())) + // Minimum execution time: 435_000 picoseconds. + Weight::from_parts(66_547_542, 990) + // Standard Error: 4_557 + .saturating_add(Weight::from_parts(5_851_324, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_parts(0, 3016).saturating_mul(i.into())) } - /// Storage: `Glutton::Storage` (r:1 w:0) - /// Proof: `Glutton::Storage` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Glutton::Compute` (r:1 w:0) - /// Proof: `Glutton::Compute` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Glutton::TrashData` (r:1737 w:0) - /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) + /// Storage: Glutton Storage (r:1 w:0) + /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Glutton Compute (r:1 w:0) + /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Glutton TrashData (r:1737 w:0) + /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) fn on_idle_high_proof_waste() -> Weight { // Proof Size summary in bytes: // Measured: `1900497` // Estimated: `5239782` - // Minimum execution time: 55_403_909_000 picoseconds. - Weight::from_parts(55_472_412_000, 5239782) + // Minimum execution time: 67_699_845_000 picoseconds. + Weight::from_parts(67_893_204_000, 5239782) .saturating_add(T::DbWeight::get().reads(1739_u64)) } - /// Storage: `Glutton::Storage` (r:1 w:0) - /// Proof: `Glutton::Storage` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Glutton::Compute` (r:1 w:0) - /// Proof: `Glutton::Compute` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Glutton::TrashData` (r:5 w:0) - /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) + /// Storage: Glutton Storage (r:1 w:0) + /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Glutton Compute (r:1 w:0) + /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Glutton TrashData (r:5 w:0) + /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) fn on_idle_low_proof_waste() -> Weight { // Proof Size summary in bytes: // Measured: `9547` // Estimated: `16070` - // Minimum execution time: 97_959_007_000 picoseconds. - Weight::from_parts(98_030_476_000, 16070) + // Minimum execution time: 122_297_527_000 picoseconds. + Weight::from_parts(122_394_818_000, 16070) .saturating_add(T::DbWeight::get().reads(7_u64)) } - /// Storage: `Glutton::Storage` (r:1 w:0) - /// Proof: `Glutton::Storage` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Glutton::Compute` (r:1 w:0) - /// Proof: `Glutton::Compute` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: Glutton Storage (r:1 w:0) + /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Glutton Compute (r:1 w:0) + /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) fn empty_on_idle() -> Weight { // Proof Size summary in bytes: // Measured: `86` // Estimated: `1493` - // Minimum execution time: 5_011_000 picoseconds. - Weight::from_parts(5_183_000, 1493) + // Minimum execution time: 5_882_000 picoseconds. + Weight::from_parts(6_138_000, 1493) .saturating_add(T::DbWeight::get().reads(2_u64)) } - /// Storage: `Glutton::Compute` (r:0 w:1) - /// Proof: `Glutton::Compute` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: Glutton Compute (r:0 w:1) + /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) fn set_compute() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_591_000 picoseconds. - Weight::from_parts(5_970_000, 0) + // Minimum execution time: 7_830_000 picoseconds. + Weight::from_parts(8_366_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Glutton::Storage` (r:0 w:1) - /// Proof: `Glutton::Storage` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: Glutton Storage (r:0 w:1) + /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) fn set_storage() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_689_000 picoseconds. - Weight::from_parts(6_038_000, 0) + // Minimum execution time: 7_933_000 picoseconds. + Weight::from_parts(8_213_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Glutton::TrashDataCount` (r:1 w:1) - /// Proof: `Glutton::TrashDataCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Glutton::TrashData` (r:0 w:1000) - /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) + /// Storage: Glutton TrashDataCount (r:1 w:1) + /// Proof: Glutton TrashDataCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Glutton TrashData (r:0 w:1000) + /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) /// The range of component `n` is `[0, 1000]`. fn initialize_pallet_grow(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `86` // Estimated: `1489` - // Minimum execution time: 8_443_000 picoseconds. - Weight::from_parts(103_698_651, 1489) - // Standard Error: 21_777 - .saturating_add(Weight::from_parts(9_529_476, 0).saturating_mul(n.into())) + // Minimum execution time: 11_488_000 picoseconds. + Weight::from_parts(93_073_710, 1489) + // Standard Error: 22_390 + .saturating_add(Weight::from_parts(9_572_012, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) } - /// Storage: `Glutton::TrashDataCount` (r:1 w:1) - /// Proof: `Glutton::TrashDataCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Glutton::TrashData` (r:0 w:1000) - /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) + /// Storage: Glutton TrashDataCount (r:1 w:1) + /// Proof: Glutton TrashDataCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Glutton TrashData (r:0 w:1000) + /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) /// The range of component `n` is `[0, 1000]`. fn initialize_pallet_shrink(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `119` // Estimated: `1489` - // Minimum execution time: 8_343_000 picoseconds. - Weight::from_parts(304_498, 1489) - // Standard Error: 1_568 - .saturating_add(Weight::from_parts(1_146_553, 0).saturating_mul(n.into())) + // Minimum execution time: 11_378_000 picoseconds. + Weight::from_parts(5_591_508, 1489) + // Standard Error: 1_592 + .saturating_add(Weight::from_parts(1_163_758, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -226,83 +227,83 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 656_000 picoseconds. - Weight::from_parts(1_875_128, 0) - // Standard Error: 8 - .saturating_add(Weight::from_parts(103_381, 0).saturating_mul(i.into())) + // Minimum execution time: 669_000 picoseconds. + Weight::from_parts(990_745, 0) + // Standard Error: 10 + .saturating_add(Weight::from_parts(105_224, 0).saturating_mul(i.into())) } - /// Storage: `Glutton::TrashData` (r:5000 w:0) - /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) + /// Storage: Glutton TrashData (r:5000 w:0) + /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) /// The range of component `i` is `[0, 5000]`. fn waste_proof_size_some(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `119114 + i * (1022 ±0)` // Estimated: `990 + i * (3016 ±0)` - // Minimum execution time: 454_000 picoseconds. - Weight::from_parts(521_000, 990) - // Standard Error: 1_940 - .saturating_add(Weight::from_parts(5_729_831, 0).saturating_mul(i.into())) + // Minimum execution time: 435_000 picoseconds. + Weight::from_parts(66_547_542, 990) + // Standard Error: 4_557 + .saturating_add(Weight::from_parts(5_851_324, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_parts(0, 3016).saturating_mul(i.into())) } - /// Storage: `Glutton::Storage` (r:1 w:0) - /// Proof: `Glutton::Storage` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Glutton::Compute` (r:1 w:0) - /// Proof: `Glutton::Compute` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Glutton::TrashData` (r:1737 w:0) - /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) + /// Storage: Glutton Storage (r:1 w:0) + /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Glutton Compute (r:1 w:0) + /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Glutton TrashData (r:1737 w:0) + /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) fn on_idle_high_proof_waste() -> Weight { // Proof Size summary in bytes: // Measured: `1900497` // Estimated: `5239782` - // Minimum execution time: 55_403_909_000 picoseconds. - Weight::from_parts(55_472_412_000, 5239782) + // Minimum execution time: 67_699_845_000 picoseconds. + Weight::from_parts(67_893_204_000, 5239782) .saturating_add(RocksDbWeight::get().reads(1739_u64)) } - /// Storage: `Glutton::Storage` (r:1 w:0) - /// Proof: `Glutton::Storage` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Glutton::Compute` (r:1 w:0) - /// Proof: `Glutton::Compute` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Glutton::TrashData` (r:5 w:0) - /// Proof: `Glutton::TrashData` (`max_values`: Some(65000), `max_size`: Some(1036), added: 3016, mode: `MaxEncodedLen`) + /// Storage: Glutton Storage (r:1 w:0) + /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Glutton Compute (r:1 w:0) + /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Glutton TrashData (r:5 w:0) + /// Proof: Glutton TrashData (max_values: Some(65000), max_size: Some(1036), added: 3016, mode: MaxEncodedLen) fn on_idle_low_proof_waste() -> Weight { // Proof Size summary in bytes: // Measured: `9547` // Estimated: `16070` - // Minimum execution time: 97_959_007_000 picoseconds. - Weight::from_parts(98_030_476_000, 16070) + // Minimum execution time: 122_297_527_000 picoseconds. + Weight::from_parts(122_394_818_000, 16070) .saturating_add(RocksDbWeight::get().reads(7_u64)) } - /// Storage: `Glutton::Storage` (r:1 w:0) - /// Proof: `Glutton::Storage` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Glutton::Compute` (r:1 w:0) - /// Proof: `Glutton::Compute` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: Glutton Storage (r:1 w:0) + /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Glutton Compute (r:1 w:0) + /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) fn empty_on_idle() -> Weight { // Proof Size summary in bytes: // Measured: `86` // Estimated: `1493` - // Minimum execution time: 5_011_000 picoseconds. - Weight::from_parts(5_183_000, 1493) + // Minimum execution time: 5_882_000 picoseconds. + Weight::from_parts(6_138_000, 1493) .saturating_add(RocksDbWeight::get().reads(2_u64)) } - /// Storage: `Glutton::Compute` (r:0 w:1) - /// Proof: `Glutton::Compute` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: Glutton Compute (r:0 w:1) + /// Proof: Glutton Compute (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) fn set_compute() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_591_000 picoseconds. - Weight::from_parts(5_970_000, 0) + // Minimum execution time: 7_830_000 picoseconds. + Weight::from_parts(8_366_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Glutton::Storage` (r:0 w:1) - /// Proof: `Glutton::Storage` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: Glutton Storage (r:0 w:1) + /// Proof: Glutton Storage (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) fn set_storage() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_689_000 picoseconds. - Weight::from_parts(6_038_000, 0) + // Minimum execution time: 7_933_000 picoseconds. + Weight::from_parts(8_213_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/substrate/frame/grandpa/src/mock.rs b/substrate/frame/grandpa/src/mock.rs index e1be487dbb7..5d48f974c31 100644 --- a/substrate/frame/grandpa/src/mock.rs +++ b/substrate/frame/grandpa/src/mock.rs @@ -35,8 +35,11 @@ use sp_consensus_grandpa::{RoundNumber, SetId, GRANDPA_ENGINE_ID}; use sp_core::{crypto::KeyTypeId, H256}; use sp_keyring::Ed25519Keyring; use sp_runtime::{ - curve::PiecewiseLinear, generic::UncheckedExtrinsic, impl_opaque_keys, - testing::UintAuthorityId, traits::OpaqueKeys, BuildStorage, DigestItem, Perbill, + curve::PiecewiseLinear, + impl_opaque_keys, + testing::{TestXt, UintAuthorityId}, + traits::OpaqueKeys, + BuildStorage, DigestItem, Perbill, }; use sp_staking::{EraIndex, SessionIndex}; @@ -74,7 +77,7 @@ where RuntimeCall: From, { type OverarchingCall = RuntimeCall; - type Extrinsic = UncheckedExtrinsic; + type Extrinsic = TestXt; } parameter_types! { diff --git a/substrate/frame/identity/src/weights.rs b/substrate/frame/identity/src/weights.rs index 81de520d7f2..1feb8252c84 100644 --- a/substrate/frame/identity/src/weights.rs +++ b/substrate/frame/identity/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_identity` +//! Autogenerated weights for pallet_identity //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/identity/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/identity/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_identity`. +/// Weight functions needed for pallet_identity. pub trait WeightInfo { fn add_registrar(r: u32, ) -> Weight; fn set_identity(r: u32, ) -> Weight; @@ -76,274 +77,278 @@ pub trait WeightInfo { fn remove_dangling_username() -> Weight; } -/// Weights for `pallet_identity` using the Substrate node and recommended hardware. +/// Weights for pallet_identity using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Identity::Registrars` (r:1 w:1) - /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn add_registrar(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `32 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 8_857_000 picoseconds. - Weight::from_parts(9_331_464, 2626) - // Standard Error: 1_745 - .saturating_add(Weight::from_parts(94_096, 0).saturating_mul(r.into())) + // Minimum execution time: 11_683_000 picoseconds. + Weight::from_parts(12_515_830, 2626) + // Standard Error: 2_154 + .saturating_add(Weight::from_parts(147_919, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. - fn set_identity(_r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `6978 + r * (5 ±0)` - // Estimated: `11037` - // Minimum execution time: 96_522_000 picoseconds. - Weight::from_parts(102_738_605, 11037) + fn set_identity(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `442 + r * (5 ±0)` + // Estimated: `11003` + // Minimum execution time: 32_949_000 picoseconds. + Weight::from_parts(31_329_634, 11003) + // Standard Error: 4_496 + .saturating_add(Weight::from_parts(203_570, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - /// Storage: `Identity::SubsOf` (r:1 w:1) - /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) - /// Storage: `Identity::SuperOf` (r:100 w:100) - /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:100 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn set_subs_new(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `101` - // Estimated: `11037 + s * (2589 ±0)` - // Minimum execution time: 9_112_000 picoseconds. - Weight::from_parts(22_676_873, 11037) - // Standard Error: 6_494 - .saturating_add(Weight::from_parts(3_279_196, 0).saturating_mul(s.into())) + // Estimated: `11003 + s * (2589 ±0)` + // Minimum execution time: 9_157_000 picoseconds. + Weight::from_parts(24_917_444, 11003) + // Standard Error: 4_554 + .saturating_add(Weight::from_parts(3_279_868, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(s.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 2589).saturating_mul(s.into())) } - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - /// Storage: `Identity::SubsOf` (r:1 w:1) - /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) - /// Storage: `Identity::SuperOf` (r:0 w:100) - /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:0 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `p` is `[0, 100]`. fn set_subs_old(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `194 + p * (32 ±0)` - // Estimated: `11037` - // Minimum execution time: 8_902_000 picoseconds. - Weight::from_parts(21_168_031, 11037) - // Standard Error: 3_576 - .saturating_add(Weight::from_parts(1_431_542, 0).saturating_mul(p.into())) + // Estimated: `11003` + // Minimum execution time: 9_240_000 picoseconds. + Weight::from_parts(23_326_035, 11003) + // Standard Error: 3_664 + .saturating_add(Weight::from_parts(1_439_873, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) } - /// Storage: `Identity::SubsOf` (r:1 w:1) - /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - /// Storage: `Identity::SuperOf` (r:0 w:100) - /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:0 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `s` is `[0, 100]`. - fn clear_identity(_r: u32, s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `7070 + r * (5 ±0) + s * (32 ±0)` - // Estimated: `11037` - // Minimum execution time: 52_468_000 picoseconds. - Weight::from_parts(56_065_452, 11037) - // Standard Error: 2_274 - .saturating_add(Weight::from_parts(1_399_051, 0).saturating_mul(s.into())) + fn clear_identity(r: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `469 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` + // Estimated: `11003` + // Minimum execution time: 55_687_000 picoseconds. + Weight::from_parts(30_695_182, 11003) + // Standard Error: 9_921 + .saturating_add(Weight::from_parts(162_357, 0).saturating_mul(r.into())) + // Standard Error: 1_937 + .saturating_add(Weight::from_parts(1_427_998, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) } - /// Storage: `Identity::Registrars` (r:1 w:0) - /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Storage: Identity Registrars (r:1 w:0) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. fn request_judgement(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `6968 + r * (57 ±0)` - // Estimated: `11037` - // Minimum execution time: 67_951_000 picoseconds. - Weight::from_parts(69_591_058, 11037) - // Standard Error: 4_420 - .saturating_add(Weight::from_parts(209_239, 0).saturating_mul(r.into())) + // Measured: `367 + r * (57 ±0) + x * (66 ±0)` + // Estimated: `11003` + // Minimum execution time: 34_876_000 picoseconds. + Weight::from_parts(32_207_018, 11003) + // Standard Error: 5_247 + .saturating_add(Weight::from_parts(249_156, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. fn cancel_request(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `6999` - // Estimated: `11037` - // Minimum execution time: 67_818_000 picoseconds. - Weight::from_parts(70_356_319, 11037) - // Standard Error: 5_116 - .saturating_add(Weight::from_parts(4_264, 0).saturating_mul(r.into())) + // Measured: `398 + x * (66 ±0)` + // Estimated: `11003` + // Minimum execution time: 30_689_000 picoseconds. + Weight::from_parts(31_967_170, 11003) + // Standard Error: 5_387 + .saturating_add(Weight::from_parts(42_676, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Identity::Registrars` (r:1 w:1) - /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn set_fee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 6_096_000 picoseconds. - Weight::from_parts(6_470_752, 2626) - // Standard Error: 1_328 - .saturating_add(Weight::from_parts(94_764, 0).saturating_mul(r.into())) + // Minimum execution time: 7_357_000 picoseconds. + Weight::from_parts(7_932_950, 2626) + // Standard Error: 1_804 + .saturating_add(Weight::from_parts(132_653, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Identity::Registrars` (r:1 w:1) - /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn set_account_id(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 6_278_000 picoseconds. - Weight::from_parts(6_678_997, 2626) - // Standard Error: 1_396 - .saturating_add(Weight::from_parts(87_207, 0).saturating_mul(r.into())) + // Minimum execution time: 7_437_000 picoseconds. + Weight::from_parts(8_051_889, 2626) + // Standard Error: 1_997 + .saturating_add(Weight::from_parts(129_592, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Identity::Registrars` (r:1 w:1) - /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn set_fields(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 6_130_000 picoseconds. - Weight::from_parts(6_516_146, 2626) - // Standard Error: 1_356 - .saturating_add(Weight::from_parts(88_455, 0).saturating_mul(r.into())) + // Minimum execution time: 7_385_000 picoseconds. + Weight::from_parts(7_911_589, 2626) + // Standard Error: 1_791 + .saturating_add(Weight::from_parts(125_788, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Identity::Registrars` (r:1 w:0) - /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Storage: Identity Registrars (r:1 w:0) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn provide_judgement(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `7046 + r * (57 ±0)` - // Estimated: `11037` - // Minimum execution time: 87_100_000 picoseconds. - Weight::from_parts(87_601_945, 11037) - // Standard Error: 22_724 - .saturating_add(Weight::from_parts(458_296, 0).saturating_mul(r.into())) + // Measured: `445 + r * (57 ±0) + x * (66 ±0)` + // Estimated: `11003` + // Minimum execution time: 24_073_000 picoseconds. + Weight::from_parts(17_817_684, 11003) + // Standard Error: 8_612 + .saturating_add(Weight::from_parts(406_251, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Identity::SubsOf` (r:1 w:1) - /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Identity::SuperOf` (r:0 w:100) - /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:0 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `s` is `[0, 100]`. fn kill_identity(r: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `7277 + r * (5 ±0) + s * (32 ±0)` - // Estimated: `11037` - // Minimum execution time: 65_925_000 picoseconds. - Weight::from_parts(70_786_250, 11037) - // Standard Error: 19_680 - .saturating_add(Weight::from_parts(29_782, 0).saturating_mul(r.into())) - // Standard Error: 3_839 - .saturating_add(Weight::from_parts(1_377_604, 0).saturating_mul(s.into())) + // Measured: `676 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` + // Estimated: `11003` + // Minimum execution time: 73_981_000 picoseconds. + Weight::from_parts(51_684_057, 11003) + // Standard Error: 12_662 + .saturating_add(Weight::from_parts(145_285, 0).saturating_mul(r.into())) + // Standard Error: 2_472 + .saturating_add(Weight::from_parts(1_421_039, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) } - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - /// Storage: `Identity::SuperOf` (r:1 w:1) - /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) - /// Storage: `Identity::SubsOf` (r:1 w:1) - /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) /// The range of component `s` is `[0, 99]`. fn add_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `475 + s * (36 ±0)` - // Estimated: `11037` - // Minimum execution time: 25_916_000 picoseconds. - Weight::from_parts(29_781_270, 11037) - // Standard Error: 1_326 - .saturating_add(Weight::from_parts(101_515, 0).saturating_mul(s.into())) + // Estimated: `11003` + // Minimum execution time: 29_367_000 picoseconds. + Weight::from_parts(34_214_998, 11003) + // Standard Error: 1_522 + .saturating_add(Weight::from_parts(114_551, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - /// Storage: `Identity::SuperOf` (r:1 w:1) - /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `s` is `[1, 100]`. fn rename_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `591 + s * (3 ±0)` - // Estimated: `11037` - // Minimum execution time: 12_142_000 picoseconds. - Weight::from_parts(14_179_741, 11037) - // Standard Error: 538 - .saturating_add(Weight::from_parts(38_847, 0).saturating_mul(s.into())) + // Estimated: `11003` + // Minimum execution time: 12_384_000 picoseconds. + Weight::from_parts(14_417_903, 11003) + // Standard Error: 539 + .saturating_add(Weight::from_parts(38_371, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - /// Storage: `Identity::SuperOf` (r:1 w:1) - /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) - /// Storage: `Identity::SubsOf` (r:1 w:1) - /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) /// The range of component `s` is `[1, 100]`. fn remove_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `638 + s * (35 ±0)` - // Estimated: `11037` - // Minimum execution time: 29_327_000 picoseconds. - Weight::from_parts(32_163_402, 11037) - // Standard Error: 1_047 - .saturating_add(Weight::from_parts(87_159, 0).saturating_mul(s.into())) + // Estimated: `11003` + // Minimum execution time: 33_327_000 picoseconds. + Weight::from_parts(36_208_941, 11003) + // Standard Error: 1_240 + .saturating_add(Weight::from_parts(105_805, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Identity::SuperOf` (r:1 w:1) - /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) - /// Storage: `Identity::SubsOf` (r:1 w:1) - /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:0) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `s` is `[0, 99]`. fn quit_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `704 + s * (37 ±0)` // Estimated: `6723` - // Minimum execution time: 22_380_000 picoseconds. - Weight::from_parts(24_557_574, 6723) - // Standard Error: 1_131 - .saturating_add(Weight::from_parts(86_358, 0).saturating_mul(s.into())) + // Minimum execution time: 23_764_000 picoseconds. + Weight::from_parts(26_407_731, 6723) + // Standard Error: 1_025 + .saturating_add(Weight::from_parts(101_112, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -353,359 +358,367 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_791_000 picoseconds. - Weight::from_parts(7_126_000, 0) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Minimum execution time: 13_873_000 picoseconds. + Weight::from_parts(13_873_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Identity::UsernameAuthorities` (r:1 w:1) + /// Storage: `Identity::UsernameAuthorities` (r:0 w:1) /// Proof: `Identity::UsernameAuthorities` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn remove_username_authority() -> Weight { // Proof Size summary in bytes: - // Measured: `80` - // Estimated: `3517` - // Minimum execution time: 9_657_000 picoseconds. - Weight::from_parts(9_922_000, 3517) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_653_000 picoseconds. + Weight::from_parts(10_653_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Identity::UsernameAuthorities` (r:1 w:1) /// Proof: `Identity::UsernameAuthorities` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) - /// Storage: `Identity::PendingUsernames` (r:1 w:0) - /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) fn set_username_for() -> Weight { // Proof Size summary in bytes: // Measured: `80` // Estimated: `11037` - // Minimum execution time: 67_928_000 picoseconds. - Weight::from_parts(69_993_000, 11037) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + // Minimum execution time: 75_928_000 picoseconds. + Weight::from_parts(75_928_000, 0) + .saturating_add(Weight::from_parts(0, 11037)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Identity::PendingUsernames` (r:1 w:1) - /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(77), added: 2552, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) /// Storage: `Identity::AccountOfUsername` (r:0 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn accept_username() -> Weight { // Proof Size summary in bytes: - // Measured: `115` + // Measured: `106` // Estimated: `11037` - // Minimum execution time: 20_496_000 picoseconds. - Weight::from_parts(20_971_000, 11037) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + // Minimum execution time: 38_157_000 picoseconds. + Weight::from_parts(38_157_000, 0) + .saturating_add(Weight::from_parts(0, 11037)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Identity::PendingUsernames` (r:1 w:1) - /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(77), added: 2552, mode: `MaxEncodedLen`) fn remove_expired_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `115` - // Estimated: `3550` - // Minimum execution time: 13_845_000 picoseconds. - Weight::from_parts(16_201_000, 3550) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Measured: `106` + // Estimated: `3542` + // Minimum execution time: 46_821_000 picoseconds. + Weight::from_parts(46_821_000, 0) + .saturating_add(Weight::from_parts(0, 3542)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Identity::AccountOfUsername` (r:1 w:0) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) fn set_primary_username() -> Weight { // Proof Size summary in bytes: - // Measured: `257` + // Measured: `247` // Estimated: `11037` - // Minimum execution time: 15_900_000 picoseconds. - Weight::from_parts(16_716_000, 11037) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Minimum execution time: 22_515_000 picoseconds. + Weight::from_parts(22_515_000, 0) + .saturating_add(Weight::from_parts(0, 11037)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:0) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) fn remove_dangling_username() -> Weight { // Proof Size summary in bytes: - // Measured: `98` + // Measured: `126` // Estimated: `11037` - // Minimum execution time: 11_538_000 picoseconds. - Weight::from_parts(11_898_000, 11037) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Minimum execution time: 15_997_000 picoseconds. + Weight::from_parts(15_997_000, 0) + .saturating_add(Weight::from_parts(0, 11037)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Identity::Registrars` (r:1 w:1) - /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn add_registrar(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `32 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 8_857_000 picoseconds. - Weight::from_parts(9_331_464, 2626) - // Standard Error: 1_745 - .saturating_add(Weight::from_parts(94_096, 0).saturating_mul(r.into())) + // Minimum execution time: 11_683_000 picoseconds. + Weight::from_parts(12_515_830, 2626) + // Standard Error: 2_154 + .saturating_add(Weight::from_parts(147_919, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. - fn set_identity(_r: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `6978 + r * (5 ±0)` - // Estimated: `11037` - // Minimum execution time: 96_522_000 picoseconds. - Weight::from_parts(102_738_605, 11037) + fn set_identity(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `442 + r * (5 ±0)` + // Estimated: `11003` + // Minimum execution time: 32_949_000 picoseconds. + Weight::from_parts(31_329_634, 11003) + // Standard Error: 4_496 + .saturating_add(Weight::from_parts(203_570, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - /// Storage: `Identity::SubsOf` (r:1 w:1) - /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) - /// Storage: `Identity::SuperOf` (r:100 w:100) - /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:100 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn set_subs_new(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `101` - // Estimated: `11037 + s * (2589 ±0)` - // Minimum execution time: 9_112_000 picoseconds. - Weight::from_parts(22_676_873, 11037) - // Standard Error: 6_494 - .saturating_add(Weight::from_parts(3_279_196, 0).saturating_mul(s.into())) + // Estimated: `11003 + s * (2589 ±0)` + // Minimum execution time: 9_157_000 picoseconds. + Weight::from_parts(24_917_444, 11003) + // Standard Error: 4_554 + .saturating_add(Weight::from_parts(3_279_868, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(s.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 2589).saturating_mul(s.into())) } - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - /// Storage: `Identity::SubsOf` (r:1 w:1) - /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) - /// Storage: `Identity::SuperOf` (r:0 w:100) - /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:0 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `p` is `[0, 100]`. fn set_subs_old(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `194 + p * (32 ±0)` - // Estimated: `11037` - // Minimum execution time: 8_902_000 picoseconds. - Weight::from_parts(21_168_031, 11037) - // Standard Error: 3_576 - .saturating_add(Weight::from_parts(1_431_542, 0).saturating_mul(p.into())) + // Estimated: `11003` + // Minimum execution time: 9_240_000 picoseconds. + Weight::from_parts(23_326_035, 11003) + // Standard Error: 3_664 + .saturating_add(Weight::from_parts(1_439_873, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(p.into()))) } - /// Storage: `Identity::SubsOf` (r:1 w:1) - /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - /// Storage: `Identity::SuperOf` (r:0 w:100) - /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:0 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `s` is `[0, 100]`. - fn clear_identity(_r: u32, s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `7070 + r * (5 ±0) + s * (32 ±0)` - // Estimated: `11037` - // Minimum execution time: 52_468_000 picoseconds. - Weight::from_parts(56_065_452, 11037) - // Standard Error: 2_274 - .saturating_add(Weight::from_parts(1_399_051, 0).saturating_mul(s.into())) + fn clear_identity(r: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `469 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` + // Estimated: `11003` + // Minimum execution time: 55_687_000 picoseconds. + Weight::from_parts(30_695_182, 11003) + // Standard Error: 9_921 + .saturating_add(Weight::from_parts(162_357, 0).saturating_mul(r.into())) + // Standard Error: 1_937 + .saturating_add(Weight::from_parts(1_427_998, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) } - /// Storage: `Identity::Registrars` (r:1 w:0) - /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Storage: Identity Registrars (r:1 w:0) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. fn request_judgement(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `6968 + r * (57 ±0)` - // Estimated: `11037` - // Minimum execution time: 67_951_000 picoseconds. - Weight::from_parts(69_591_058, 11037) - // Standard Error: 4_420 - .saturating_add(Weight::from_parts(209_239, 0).saturating_mul(r.into())) + // Measured: `367 + r * (57 ±0) + x * (66 ±0)` + // Estimated: `11003` + // Minimum execution time: 34_876_000 picoseconds. + Weight::from_parts(32_207_018, 11003) + // Standard Error: 5_247 + .saturating_add(Weight::from_parts(249_156, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. fn cancel_request(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `6999` - // Estimated: `11037` - // Minimum execution time: 67_818_000 picoseconds. - Weight::from_parts(70_356_319, 11037) - // Standard Error: 5_116 - .saturating_add(Weight::from_parts(4_264, 0).saturating_mul(r.into())) + // Measured: `398 + x * (66 ±0)` + // Estimated: `11003` + // Minimum execution time: 30_689_000 picoseconds. + Weight::from_parts(31_967_170, 11003) + // Standard Error: 5_387 + .saturating_add(Weight::from_parts(42_676, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Identity::Registrars` (r:1 w:1) - /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn set_fee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 6_096_000 picoseconds. - Weight::from_parts(6_470_752, 2626) - // Standard Error: 1_328 - .saturating_add(Weight::from_parts(94_764, 0).saturating_mul(r.into())) + // Minimum execution time: 7_357_000 picoseconds. + Weight::from_parts(7_932_950, 2626) + // Standard Error: 1_804 + .saturating_add(Weight::from_parts(132_653, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Identity::Registrars` (r:1 w:1) - /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn set_account_id(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 6_278_000 picoseconds. - Weight::from_parts(6_678_997, 2626) - // Standard Error: 1_396 - .saturating_add(Weight::from_parts(87_207, 0).saturating_mul(r.into())) + // Minimum execution time: 7_437_000 picoseconds. + Weight::from_parts(8_051_889, 2626) + // Standard Error: 1_997 + .saturating_add(Weight::from_parts(129_592, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Identity::Registrars` (r:1 w:1) - /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) + /// Storage: Identity Registrars (r:1 w:1) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn set_fields(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 6_130_000 picoseconds. - Weight::from_parts(6_516_146, 2626) - // Standard Error: 1_356 - .saturating_add(Weight::from_parts(88_455, 0).saturating_mul(r.into())) + // Minimum execution time: 7_385_000 picoseconds. + Weight::from_parts(7_911_589, 2626) + // Standard Error: 1_791 + .saturating_add(Weight::from_parts(125_788, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Identity::Registrars` (r:1 w:0) - /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Storage: Identity Registrars (r:1 w:0) + /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) /// The range of component `r` is `[1, 19]`. fn provide_judgement(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `7046 + r * (57 ±0)` - // Estimated: `11037` - // Minimum execution time: 87_100_000 picoseconds. - Weight::from_parts(87_601_945, 11037) - // Standard Error: 22_724 - .saturating_add(Weight::from_parts(458_296, 0).saturating_mul(r.into())) + // Measured: `445 + r * (57 ±0) + x * (66 ±0)` + // Estimated: `11003` + // Minimum execution time: 24_073_000 picoseconds. + Weight::from_parts(17_817_684, 11003) + // Standard Error: 8_612 + .saturating_add(Weight::from_parts(406_251, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Identity::SubsOf` (r:1 w:1) - /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Identity::SuperOf` (r:0 w:100) - /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: Identity IdentityOf (r:1 w:1) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:0 w:100) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `r` is `[1, 20]`. /// The range of component `s` is `[0, 100]`. fn kill_identity(r: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `7277 + r * (5 ±0) + s * (32 ±0)` - // Estimated: `11037` - // Minimum execution time: 65_925_000 picoseconds. - Weight::from_parts(70_786_250, 11037) - // Standard Error: 19_680 - .saturating_add(Weight::from_parts(29_782, 0).saturating_mul(r.into())) - // Standard Error: 3_839 - .saturating_add(Weight::from_parts(1_377_604, 0).saturating_mul(s.into())) + // Measured: `676 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` + // Estimated: `11003` + // Minimum execution time: 73_981_000 picoseconds. + Weight::from_parts(51_684_057, 11003) + // Standard Error: 12_662 + .saturating_add(Weight::from_parts(145_285, 0).saturating_mul(r.into())) + // Standard Error: 2_472 + .saturating_add(Weight::from_parts(1_421_039, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) } - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - /// Storage: `Identity::SuperOf` (r:1 w:1) - /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) - /// Storage: `Identity::SubsOf` (r:1 w:1) - /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) /// The range of component `s` is `[0, 99]`. fn add_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `475 + s * (36 ±0)` - // Estimated: `11037` - // Minimum execution time: 25_916_000 picoseconds. - Weight::from_parts(29_781_270, 11037) - // Standard Error: 1_326 - .saturating_add(Weight::from_parts(101_515, 0).saturating_mul(s.into())) + // Estimated: `11003` + // Minimum execution time: 29_367_000 picoseconds. + Weight::from_parts(34_214_998, 11003) + // Standard Error: 1_522 + .saturating_add(Weight::from_parts(114_551, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - /// Storage: `Identity::SuperOf` (r:1 w:1) - /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) /// The range of component `s` is `[1, 100]`. fn rename_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `591 + s * (3 ±0)` - // Estimated: `11037` - // Minimum execution time: 12_142_000 picoseconds. - Weight::from_parts(14_179_741, 11037) - // Standard Error: 538 - .saturating_add(Weight::from_parts(38_847, 0).saturating_mul(s.into())) + // Estimated: `11003` + // Minimum execution time: 12_384_000 picoseconds. + Weight::from_parts(14_417_903, 11003) + // Standard Error: 539 + .saturating_add(Weight::from_parts(38_371, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - /// Storage: `Identity::SuperOf` (r:1 w:1) - /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) - /// Storage: `Identity::SubsOf` (r:1 w:1) - /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) + /// Storage: Identity IdentityOf (r:1 w:0) + /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) /// The range of component `s` is `[1, 100]`. fn remove_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `638 + s * (35 ±0)` - // Estimated: `11037` - // Minimum execution time: 29_327_000 picoseconds. - Weight::from_parts(32_163_402, 11037) - // Standard Error: 1_047 - .saturating_add(Weight::from_parts(87_159, 0).saturating_mul(s.into())) + // Estimated: `11003` + // Minimum execution time: 33_327_000 picoseconds. + Weight::from_parts(36_208_941, 11003) + // Standard Error: 1_240 + .saturating_add(Weight::from_parts(105_805, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Identity::SuperOf` (r:1 w:1) - /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) - /// Storage: `Identity::SubsOf` (r:1 w:1) - /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:0) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Identity SuperOf (r:1 w:1) + /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: Identity SubsOf (r:1 w:1) + /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `s` is `[0, 99]`. fn quit_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `704 + s * (37 ±0)` // Estimated: `6723` - // Minimum execution time: 22_380_000 picoseconds. - Weight::from_parts(24_557_574, 6723) - // Standard Error: 1_131 - .saturating_add(Weight::from_parts(86_358, 0).saturating_mul(s.into())) + // Minimum execution time: 23_764_000 picoseconds. + Weight::from_parts(26_407_731, 6723) + // Standard Error: 1_025 + .saturating_add(Weight::from_parts(101_112, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -715,88 +728,92 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_791_000 picoseconds. - Weight::from_parts(7_126_000, 0) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Minimum execution time: 13_873_000 picoseconds. + Weight::from_parts(13_873_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(RocksDbWeight::get().writes(1)) } - /// Storage: `Identity::UsernameAuthorities` (r:1 w:1) + /// Storage: `Identity::UsernameAuthorities` (r:0 w:1) /// Proof: `Identity::UsernameAuthorities` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn remove_username_authority() -> Weight { // Proof Size summary in bytes: - // Measured: `80` - // Estimated: `3517` - // Minimum execution time: 9_657_000 picoseconds. - Weight::from_parts(9_922_000, 3517) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_653_000 picoseconds. + Weight::from_parts(10_653_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(RocksDbWeight::get().writes(1)) } /// Storage: `Identity::UsernameAuthorities` (r:1 w:1) /// Proof: `Identity::UsernameAuthorities` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) - /// Storage: `Identity::PendingUsernames` (r:1 w:0) - /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) fn set_username_for() -> Weight { // Proof Size summary in bytes: // Measured: `80` // Estimated: `11037` - // Minimum execution time: 67_928_000 picoseconds. - Weight::from_parts(69_993_000, 11037) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + // Minimum execution time: 75_928_000 picoseconds. + Weight::from_parts(75_928_000, 0) + .saturating_add(Weight::from_parts(0, 11037)) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(3)) } /// Storage: `Identity::PendingUsernames` (r:1 w:1) - /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(77), added: 2552, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) /// Storage: `Identity::AccountOfUsername` (r:0 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn accept_username() -> Weight { // Proof Size summary in bytes: - // Measured: `115` + // Measured: `106` // Estimated: `11037` - // Minimum execution time: 20_496_000 picoseconds. - Weight::from_parts(20_971_000, 11037) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + // Minimum execution time: 38_157_000 picoseconds. + Weight::from_parts(38_157_000, 0) + .saturating_add(Weight::from_parts(0, 11037)) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(3)) } /// Storage: `Identity::PendingUsernames` (r:1 w:1) - /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(77), added: 2552, mode: `MaxEncodedLen`) fn remove_expired_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `115` - // Estimated: `3550` - // Minimum execution time: 13_845_000 picoseconds. - Weight::from_parts(16_201_000, 3550) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Measured: `106` + // Estimated: `3542` + // Minimum execution time: 46_821_000 picoseconds. + Weight::from_parts(46_821_000, 0) + .saturating_add(Weight::from_parts(0, 3542)) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) } /// Storage: `Identity::AccountOfUsername` (r:1 w:0) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) fn set_primary_username() -> Weight { // Proof Size summary in bytes: - // Measured: `257` + // Measured: `247` // Estimated: `11037` - // Minimum execution time: 15_900_000 picoseconds. - Weight::from_parts(16_716_000, 11037) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Minimum execution time: 22_515_000 picoseconds. + Weight::from_parts(22_515_000, 0) + .saturating_add(Weight::from_parts(0, 11037)) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) } /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:0) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) fn remove_dangling_username() -> Weight { // Proof Size summary in bytes: - // Measured: `98` + // Measured: `126` // Estimated: `11037` - // Minimum execution time: 11_538_000 picoseconds. - Weight::from_parts(11_898_000, 11037) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Minimum execution time: 15_997_000 picoseconds. + Weight::from_parts(15_997_000, 0) + .saturating_add(Weight::from_parts(0, 11037)) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) } } diff --git a/substrate/frame/im-online/src/mock.rs b/substrate/frame/im-online/src/mock.rs index c0ba9143e13..9dad148b10f 100644 --- a/substrate/frame/im-online/src/mock.rs +++ b/substrate/frame/im-online/src/mock.rs @@ -27,7 +27,7 @@ use frame_support::{ use pallet_session::historical as pallet_session_historical; use sp_core::H256; use sp_runtime::{ - testing::UintAuthorityId, + testing::{TestXt, UintAuthorityId}, traits::{BlakeTwo256, ConvertInto, IdentityLookup}, BuildStorage, Permill, }; @@ -78,7 +78,7 @@ impl pallet_session::historical::SessionManager for TestSessionManager } /// An extrinsic type used for tests. -pub type Extrinsic = sp_runtime::generic::UncheckedExtrinsic; +pub type Extrinsic = TestXt; type IdentificationTuple = (u64, u64); type Offence = crate::UnresponsivenessOffence; diff --git a/substrate/frame/im-online/src/tests.rs b/substrate/frame/im-online/src/tests.rs index 6f5a14d7e7f..5e5212e1d56 100644 --- a/substrate/frame/im-online/src/tests.rs +++ b/substrate/frame/im-online/src/tests.rs @@ -228,7 +228,7 @@ fn should_generate_heartbeats() { // check stuff about the transaction. let ex: Extrinsic = Decode::decode(&mut &*transaction).unwrap(); - let heartbeat = match ex.function { + let heartbeat = match ex.call { crate::mock::RuntimeCall::ImOnline(crate::Call::heartbeat { heartbeat, .. }) => heartbeat, e => panic!("Unexpected call: {:?}", e), @@ -342,7 +342,7 @@ fn should_not_send_a_report_if_already_online() { assert_eq!(pool_state.read().transactions.len(), 0); // check stuff about the transaction. let ex: Extrinsic = Decode::decode(&mut &*transaction).unwrap(); - let heartbeat = match ex.function { + let heartbeat = match ex.call { crate::mock::RuntimeCall::ImOnline(crate::Call::heartbeat { heartbeat, .. }) => heartbeat, e => panic!("Unexpected call: {:?}", e), diff --git a/substrate/frame/im-online/src/weights.rs b/substrate/frame/im-online/src/weights.rs index 11357b1e7b7..c3db02af257 100644 --- a/substrate/frame/im-online/src/weights.rs +++ b/substrate/frame/im-online/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_im_online` +//! Autogenerated weights for pallet_im_online //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/im-online/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/im-online/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,60 +50,60 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_im_online`. +/// Weight functions needed for pallet_im_online. pub trait WeightInfo { fn validate_unsigned_and_then_heartbeat(k: u32, ) -> Weight; } -/// Weights for `pallet_im_online` using the Substrate node and recommended hardware. +/// Weights for pallet_im_online using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Session::Validators` (r:1 w:0) - /// Proof: `Session::Validators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Session::CurrentIndex` (r:1 w:0) - /// Proof: `Session::CurrentIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ImOnline::Keys` (r:1 w:0) - /// Proof: `ImOnline::Keys` (`max_values`: Some(1), `max_size`: Some(320002), added: 320497, mode: `MaxEncodedLen`) - /// Storage: `ImOnline::ReceivedHeartbeats` (r:1 w:1) - /// Proof: `ImOnline::ReceivedHeartbeats` (`max_values`: None, `max_size`: Some(25), added: 2500, mode: `MaxEncodedLen`) - /// Storage: `ImOnline::AuthoredBlocks` (r:1 w:0) - /// Proof: `ImOnline::AuthoredBlocks` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`) + /// Storage: Session Validators (r:1 w:0) + /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Session CurrentIndex (r:1 w:0) + /// Proof Skipped: Session CurrentIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ImOnline Keys (r:1 w:0) + /// Proof: ImOnline Keys (max_values: Some(1), max_size: Some(320002), added: 320497, mode: MaxEncodedLen) + /// Storage: ImOnline ReceivedHeartbeats (r:1 w:1) + /// Proof: ImOnline ReceivedHeartbeats (max_values: None, max_size: Some(25), added: 2500, mode: MaxEncodedLen) + /// Storage: ImOnline AuthoredBlocks (r:1 w:0) + /// Proof: ImOnline AuthoredBlocks (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) /// The range of component `k` is `[1, 1000]`. fn validate_unsigned_and_then_heartbeat(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `327 + k * (32 ±0)` + // Measured: `295 + k * (32 ±0)` // Estimated: `321487 + k * (1761 ±0)` - // Minimum execution time: 65_515_000 picoseconds. - Weight::from_parts(74_765_329, 321487) - // Standard Error: 500 - .saturating_add(Weight::from_parts(39_171, 0).saturating_mul(k.into())) + // Minimum execution time: 80_568_000 picoseconds. + Weight::from_parts(95_175_595, 321487) + // Standard Error: 627 + .saturating_add(Weight::from_parts(39_094, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1761).saturating_mul(k.into())) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Session::Validators` (r:1 w:0) - /// Proof: `Session::Validators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Session::CurrentIndex` (r:1 w:0) - /// Proof: `Session::CurrentIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ImOnline::Keys` (r:1 w:0) - /// Proof: `ImOnline::Keys` (`max_values`: Some(1), `max_size`: Some(320002), added: 320497, mode: `MaxEncodedLen`) - /// Storage: `ImOnline::ReceivedHeartbeats` (r:1 w:1) - /// Proof: `ImOnline::ReceivedHeartbeats` (`max_values`: None, `max_size`: Some(25), added: 2500, mode: `MaxEncodedLen`) - /// Storage: `ImOnline::AuthoredBlocks` (r:1 w:0) - /// Proof: `ImOnline::AuthoredBlocks` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`) + /// Storage: Session Validators (r:1 w:0) + /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Session CurrentIndex (r:1 w:0) + /// Proof Skipped: Session CurrentIndex (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ImOnline Keys (r:1 w:0) + /// Proof: ImOnline Keys (max_values: Some(1), max_size: Some(320002), added: 320497, mode: MaxEncodedLen) + /// Storage: ImOnline ReceivedHeartbeats (r:1 w:1) + /// Proof: ImOnline ReceivedHeartbeats (max_values: None, max_size: Some(25), added: 2500, mode: MaxEncodedLen) + /// Storage: ImOnline AuthoredBlocks (r:1 w:0) + /// Proof: ImOnline AuthoredBlocks (max_values: None, max_size: Some(56), added: 2531, mode: MaxEncodedLen) /// The range of component `k` is `[1, 1000]`. fn validate_unsigned_and_then_heartbeat(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `327 + k * (32 ±0)` + // Measured: `295 + k * (32 ±0)` // Estimated: `321487 + k * (1761 ±0)` - // Minimum execution time: 65_515_000 picoseconds. - Weight::from_parts(74_765_329, 321487) - // Standard Error: 500 - .saturating_add(Weight::from_parts(39_171, 0).saturating_mul(k.into())) + // Minimum execution time: 80_568_000 picoseconds. + Weight::from_parts(95_175_595, 321487) + // Standard Error: 627 + .saturating_add(Weight::from_parts(39_094, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1761).saturating_mul(k.into())) diff --git a/substrate/frame/indices/src/weights.rs b/substrate/frame/indices/src/weights.rs index 6b571164eb6..d081cc738b1 100644 --- a/substrate/frame/indices/src/weights.rs +++ b/substrate/frame/indices/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_indices` +//! Autogenerated weights for pallet_indices //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/indices/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/indices/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_indices`. +/// Weight functions needed for pallet_indices. pub trait WeightInfo { fn claim() -> Weight; fn transfer() -> Weight; @@ -58,128 +59,128 @@ pub trait WeightInfo { fn freeze() -> Weight; } -/// Weights for `pallet_indices` using the Substrate node and recommended hardware. +/// Weights for pallet_indices using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Indices::Accounts` (r:1 w:1) - /// Proof: `Indices::Accounts` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: Indices Accounts (r:1 w:1) + /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn claim() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3534` - // Minimum execution time: 20_825_000 picoseconds. - Weight::from_parts(21_507_000, 3534) + // Minimum execution time: 25_491_000 picoseconds. + Weight::from_parts(26_456_000, 3534) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Indices::Accounts` (r:1 w:1) - /// Proof: `Indices::Accounts` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Indices Accounts (r:1 w:1) + /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: // Measured: `275` // Estimated: `3593` - // Minimum execution time: 31_091_000 picoseconds. - Weight::from_parts(31_923_000, 3593) + // Minimum execution time: 38_027_000 picoseconds. + Weight::from_parts(38_749_000, 3593) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Indices::Accounts` (r:1 w:1) - /// Proof: `Indices::Accounts` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: Indices Accounts (r:1 w:1) + /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn free() -> Weight { // Proof Size summary in bytes: // Measured: `172` // Estimated: `3534` - // Minimum execution time: 21_832_000 picoseconds. - Weight::from_parts(22_436_000, 3534) + // Minimum execution time: 26_652_000 picoseconds. + Weight::from_parts(27_273_000, 3534) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Indices::Accounts` (r:1 w:1) - /// Proof: `Indices::Accounts` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Indices Accounts (r:1 w:1) + /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `275` // Estimated: `3593` - // Minimum execution time: 23_876_000 picoseconds. - Weight::from_parts(24_954_000, 3593) + // Minimum execution time: 29_464_000 picoseconds. + Weight::from_parts(30_959_000, 3593) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Indices::Accounts` (r:1 w:1) - /// Proof: `Indices::Accounts` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: Indices Accounts (r:1 w:1) + /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn freeze() -> Weight { // Proof Size summary in bytes: // Measured: `172` // Estimated: `3534` - // Minimum execution time: 22_954_000 picoseconds. - Weight::from_parts(23_792_000, 3534) + // Minimum execution time: 29_015_000 picoseconds. + Weight::from_parts(29_714_000, 3534) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Indices::Accounts` (r:1 w:1) - /// Proof: `Indices::Accounts` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: Indices Accounts (r:1 w:1) + /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn claim() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3534` - // Minimum execution time: 20_825_000 picoseconds. - Weight::from_parts(21_507_000, 3534) + // Minimum execution time: 25_491_000 picoseconds. + Weight::from_parts(26_456_000, 3534) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Indices::Accounts` (r:1 w:1) - /// Proof: `Indices::Accounts` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Indices Accounts (r:1 w:1) + /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: // Measured: `275` // Estimated: `3593` - // Minimum execution time: 31_091_000 picoseconds. - Weight::from_parts(31_923_000, 3593) + // Minimum execution time: 38_027_000 picoseconds. + Weight::from_parts(38_749_000, 3593) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Indices::Accounts` (r:1 w:1) - /// Proof: `Indices::Accounts` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: Indices Accounts (r:1 w:1) + /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn free() -> Weight { // Proof Size summary in bytes: // Measured: `172` // Estimated: `3534` - // Minimum execution time: 21_832_000 picoseconds. - Weight::from_parts(22_436_000, 3534) + // Minimum execution time: 26_652_000 picoseconds. + Weight::from_parts(27_273_000, 3534) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Indices::Accounts` (r:1 w:1) - /// Proof: `Indices::Accounts` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Indices Accounts (r:1 w:1) + /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `275` // Estimated: `3593` - // Minimum execution time: 23_876_000 picoseconds. - Weight::from_parts(24_954_000, 3593) + // Minimum execution time: 29_464_000 picoseconds. + Weight::from_parts(30_959_000, 3593) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Indices::Accounts` (r:1 w:1) - /// Proof: `Indices::Accounts` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: Indices Accounts (r:1 w:1) + /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn freeze() -> Weight { // Proof Size summary in bytes: // Measured: `172` // Estimated: `3534` - // Minimum execution time: 22_954_000 picoseconds. - Weight::from_parts(23_792_000, 3534) + // Minimum execution time: 29_015_000 picoseconds. + Weight::from_parts(29_714_000, 3534) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/lottery/src/weights.rs b/substrate/frame/lottery/src/weights.rs index 7e56cdf90db..3b4e5623753 100644 --- a/substrate/frame/lottery/src/weights.rs +++ b/substrate/frame/lottery/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_lottery` +//! Autogenerated weights for pallet_lottery //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/lottery/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/lottery/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_lottery`. +/// Weight functions needed for pallet_lottery. pub trait WeightInfo { fn buy_ticket() -> Weight; fn set_calls(n: u32, ) -> Weight; @@ -59,222 +60,214 @@ pub trait WeightInfo { fn on_initialize_repeat() -> Weight; } -/// Weights for `pallet_lottery` using the Substrate node and recommended hardware. +/// Weights for pallet_lottery using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) - /// Storage: `Lottery::Lottery` (r:1 w:0) - /// Proof: `Lottery::Lottery` (`max_values`: Some(1), `max_size`: Some(29), added: 524, mode: `MaxEncodedLen`) - /// Storage: `Lottery::CallIndices` (r:1 w:0) - /// Proof: `Lottery::CallIndices` (`max_values`: Some(1), `max_size`: Some(21), added: 516, mode: `MaxEncodedLen`) - /// Storage: `Lottery::TicketsCount` (r:1 w:1) - /// Proof: `Lottery::TicketsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Lottery::Participants` (r:1 w:1) - /// Proof: `Lottery::Participants` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) - /// Storage: `Lottery::LotteryIndex` (r:1 w:0) - /// Proof: `Lottery::LotteryIndex` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Lottery::Tickets` (r:0 w:1) - /// Proof: `Lottery::Tickets` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// Storage: Lottery Lottery (r:1 w:0) + /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) + /// Storage: Lottery CallIndices (r:1 w:0) + /// Proof: Lottery CallIndices (max_values: Some(1), max_size: Some(21), added: 516, mode: MaxEncodedLen) + /// Storage: Lottery TicketsCount (r:1 w:1) + /// Proof: Lottery TicketsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Lottery Participants (r:1 w:1) + /// Proof: Lottery Participants (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: Lottery LotteryIndex (r:1 w:0) + /// Proof: Lottery LotteryIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Lottery Tickets (r:0 w:1) + /// Proof: Lottery Tickets (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) fn buy_ticket() -> Weight { // Proof Size summary in bytes: - // Measured: `492` - // Estimated: `3997` - // Minimum execution time: 57_891_000 picoseconds. - Weight::from_parts(59_508_000, 3997) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Measured: `452` + // Estimated: `3593` + // Minimum execution time: 60_298_000 picoseconds. + Weight::from_parts(62_058_000, 3593) + .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: `Lottery::CallIndices` (r:0 w:1) - /// Proof: `Lottery::CallIndices` (`max_values`: Some(1), `max_size`: Some(21), added: 516, mode: `MaxEncodedLen`) + /// Storage: Lottery CallIndices (r:0 w:1) + /// Proof: Lottery CallIndices (max_values: Some(1), max_size: Some(21), added: 516, mode: MaxEncodedLen) /// The range of component `n` is `[0, 10]`. fn set_calls(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_026_000 picoseconds. - Weight::from_parts(5_854_666, 0) - // Standard Error: 3_233 - .saturating_add(Weight::from_parts(334_818, 0).saturating_mul(n.into())) + // Minimum execution time: 7_291_000 picoseconds. + Weight::from_parts(8_178_186, 0) + // Standard Error: 3_048 + .saturating_add(Weight::from_parts(330_871, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Lottery::Lottery` (r:1 w:1) - /// Proof: `Lottery::Lottery` (`max_values`: Some(1), `max_size`: Some(29), added: 524, mode: `MaxEncodedLen`) - /// Storage: `Lottery::LotteryIndex` (r:1 w:1) - /// Proof: `Lottery::LotteryIndex` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Lottery Lottery (r:1 w:1) + /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) + /// Storage: Lottery LotteryIndex (r:1 w:1) + /// Proof: Lottery LotteryIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn start_lottery() -> Weight { // Proof Size summary in bytes: - // Measured: `194` + // Measured: `161` // Estimated: `3593` - // Minimum execution time: 26_216_000 picoseconds. - Weight::from_parts(27_216_000, 3593) + // Minimum execution time: 36_741_000 picoseconds. + Weight::from_parts(38_288_000, 3593) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Lottery::Lottery` (r:1 w:1) - /// Proof: `Lottery::Lottery` (`max_values`: Some(1), `max_size`: Some(29), added: 524, mode: `MaxEncodedLen`) + /// Storage: Lottery Lottery (r:1 w:1) + /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) fn stop_repeat() -> Weight { // Proof Size summary in bytes: - // Measured: `252` + // Measured: `219` // Estimated: `1514` - // Minimum execution time: 6_208_000 picoseconds. - Weight::from_parts(6_427_000, 1514) + // Minimum execution time: 7_270_000 picoseconds. + Weight::from_parts(7_578_000, 1514) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `RandomnessCollectiveFlip::RandomMaterial` (r:1 w:0) - /// Proof: `RandomnessCollectiveFlip::RandomMaterial` (`max_values`: Some(1), `max_size`: Some(2594), added: 3089, mode: `MaxEncodedLen`) - /// Storage: `Lottery::Lottery` (r:1 w:1) - /// Proof: `Lottery::Lottery` (`max_values`: Some(1), `max_size`: Some(29), added: 524, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Lottery::TicketsCount` (r:1 w:1) - /// Proof: `Lottery::TicketsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Lottery::Tickets` (r:1 w:0) - /// Proof: `Lottery::Tickets` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) + /// Proof: RandomnessCollectiveFlip RandomMaterial (max_values: Some(1), max_size: Some(2594), added: 3089, mode: MaxEncodedLen) + /// Storage: Lottery Lottery (r:1 w:1) + /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Lottery TicketsCount (r:1 w:1) + /// Proof: Lottery TicketsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Lottery Tickets (r:1 w:0) + /// Proof: Lottery Tickets (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) fn on_initialize_end() -> Weight { // Proof Size summary in bytes: - // Measured: `591` + // Measured: `558` // Estimated: `6196` - // Minimum execution time: 58_660_000 picoseconds. - Weight::from_parts(59_358_000, 6196) + // Minimum execution time: 76_611_000 picoseconds. + Weight::from_parts(78_107_000, 6196) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: `RandomnessCollectiveFlip::RandomMaterial` (r:1 w:0) - /// Proof: `RandomnessCollectiveFlip::RandomMaterial` (`max_values`: Some(1), `max_size`: Some(2594), added: 3089, mode: `MaxEncodedLen`) - /// Storage: `Lottery::Lottery` (r:1 w:1) - /// Proof: `Lottery::Lottery` (`max_values`: Some(1), `max_size`: Some(29), added: 524, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Lottery::TicketsCount` (r:1 w:1) - /// Proof: `Lottery::TicketsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Lottery::Tickets` (r:1 w:0) - /// Proof: `Lottery::Tickets` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - /// Storage: `Lottery::LotteryIndex` (r:1 w:1) - /// Proof: `Lottery::LotteryIndex` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) + /// Proof: RandomnessCollectiveFlip RandomMaterial (max_values: Some(1), max_size: Some(2594), added: 3089, mode: MaxEncodedLen) + /// Storage: Lottery Lottery (r:1 w:1) + /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Lottery TicketsCount (r:1 w:1) + /// Proof: Lottery TicketsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Lottery Tickets (r:1 w:0) + /// Proof: Lottery Tickets (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) + /// Storage: Lottery LotteryIndex (r:1 w:1) + /// Proof: Lottery LotteryIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn on_initialize_repeat() -> Weight { // Proof Size summary in bytes: - // Measured: `591` + // Measured: `558` // Estimated: `6196` - // Minimum execution time: 59_376_000 picoseconds. - Weight::from_parts(60_598_000, 6196) + // Minimum execution time: 78_731_000 picoseconds. + Weight::from_parts(80_248_000, 6196) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) - /// Storage: `Lottery::Lottery` (r:1 w:0) - /// Proof: `Lottery::Lottery` (`max_values`: Some(1), `max_size`: Some(29), added: 524, mode: `MaxEncodedLen`) - /// Storage: `Lottery::CallIndices` (r:1 w:0) - /// Proof: `Lottery::CallIndices` (`max_values`: Some(1), `max_size`: Some(21), added: 516, mode: `MaxEncodedLen`) - /// Storage: `Lottery::TicketsCount` (r:1 w:1) - /// Proof: `Lottery::TicketsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Lottery::Participants` (r:1 w:1) - /// Proof: `Lottery::Participants` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) - /// Storage: `Lottery::LotteryIndex` (r:1 w:0) - /// Proof: `Lottery::LotteryIndex` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Lottery::Tickets` (r:0 w:1) - /// Proof: `Lottery::Tickets` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// Storage: Lottery Lottery (r:1 w:0) + /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) + /// Storage: Lottery CallIndices (r:1 w:0) + /// Proof: Lottery CallIndices (max_values: Some(1), max_size: Some(21), added: 516, mode: MaxEncodedLen) + /// Storage: Lottery TicketsCount (r:1 w:1) + /// Proof: Lottery TicketsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Lottery Participants (r:1 w:1) + /// Proof: Lottery Participants (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: Lottery LotteryIndex (r:1 w:0) + /// Proof: Lottery LotteryIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Lottery Tickets (r:0 w:1) + /// Proof: Lottery Tickets (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) fn buy_ticket() -> Weight { // Proof Size summary in bytes: - // Measured: `492` - // Estimated: `3997` - // Minimum execution time: 57_891_000 picoseconds. - Weight::from_parts(59_508_000, 3997) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Measured: `452` + // Estimated: `3593` + // Minimum execution time: 60_298_000 picoseconds. + Weight::from_parts(62_058_000, 3593) + .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: `Lottery::CallIndices` (r:0 w:1) - /// Proof: `Lottery::CallIndices` (`max_values`: Some(1), `max_size`: Some(21), added: 516, mode: `MaxEncodedLen`) + /// Storage: Lottery CallIndices (r:0 w:1) + /// Proof: Lottery CallIndices (max_values: Some(1), max_size: Some(21), added: 516, mode: MaxEncodedLen) /// The range of component `n` is `[0, 10]`. fn set_calls(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_026_000 picoseconds. - Weight::from_parts(5_854_666, 0) - // Standard Error: 3_233 - .saturating_add(Weight::from_parts(334_818, 0).saturating_mul(n.into())) + // Minimum execution time: 7_291_000 picoseconds. + Weight::from_parts(8_178_186, 0) + // Standard Error: 3_048 + .saturating_add(Weight::from_parts(330_871, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Lottery::Lottery` (r:1 w:1) - /// Proof: `Lottery::Lottery` (`max_values`: Some(1), `max_size`: Some(29), added: 524, mode: `MaxEncodedLen`) - /// Storage: `Lottery::LotteryIndex` (r:1 w:1) - /// Proof: `Lottery::LotteryIndex` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Lottery Lottery (r:1 w:1) + /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) + /// Storage: Lottery LotteryIndex (r:1 w:1) + /// Proof: Lottery LotteryIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn start_lottery() -> Weight { // Proof Size summary in bytes: - // Measured: `194` + // Measured: `161` // Estimated: `3593` - // Minimum execution time: 26_216_000 picoseconds. - Weight::from_parts(27_216_000, 3593) + // Minimum execution time: 36_741_000 picoseconds. + Weight::from_parts(38_288_000, 3593) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Lottery::Lottery` (r:1 w:1) - /// Proof: `Lottery::Lottery` (`max_values`: Some(1), `max_size`: Some(29), added: 524, mode: `MaxEncodedLen`) + /// Storage: Lottery Lottery (r:1 w:1) + /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) fn stop_repeat() -> Weight { // Proof Size summary in bytes: - // Measured: `252` + // Measured: `219` // Estimated: `1514` - // Minimum execution time: 6_208_000 picoseconds. - Weight::from_parts(6_427_000, 1514) + // Minimum execution time: 7_270_000 picoseconds. + Weight::from_parts(7_578_000, 1514) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `RandomnessCollectiveFlip::RandomMaterial` (r:1 w:0) - /// Proof: `RandomnessCollectiveFlip::RandomMaterial` (`max_values`: Some(1), `max_size`: Some(2594), added: 3089, mode: `MaxEncodedLen`) - /// Storage: `Lottery::Lottery` (r:1 w:1) - /// Proof: `Lottery::Lottery` (`max_values`: Some(1), `max_size`: Some(29), added: 524, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Lottery::TicketsCount` (r:1 w:1) - /// Proof: `Lottery::TicketsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Lottery::Tickets` (r:1 w:0) - /// Proof: `Lottery::Tickets` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) + /// Proof: RandomnessCollectiveFlip RandomMaterial (max_values: Some(1), max_size: Some(2594), added: 3089, mode: MaxEncodedLen) + /// Storage: Lottery Lottery (r:1 w:1) + /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Lottery TicketsCount (r:1 w:1) + /// Proof: Lottery TicketsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Lottery Tickets (r:1 w:0) + /// Proof: Lottery Tickets (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) fn on_initialize_end() -> Weight { // Proof Size summary in bytes: - // Measured: `591` + // Measured: `558` // Estimated: `6196` - // Minimum execution time: 58_660_000 picoseconds. - Weight::from_parts(59_358_000, 6196) + // Minimum execution time: 76_611_000 picoseconds. + Weight::from_parts(78_107_000, 6196) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: `RandomnessCollectiveFlip::RandomMaterial` (r:1 w:0) - /// Proof: `RandomnessCollectiveFlip::RandomMaterial` (`max_values`: Some(1), `max_size`: Some(2594), added: 3089, mode: `MaxEncodedLen`) - /// Storage: `Lottery::Lottery` (r:1 w:1) - /// Proof: `Lottery::Lottery` (`max_values`: Some(1), `max_size`: Some(29), added: 524, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Lottery::TicketsCount` (r:1 w:1) - /// Proof: `Lottery::TicketsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Lottery::Tickets` (r:1 w:0) - /// Proof: `Lottery::Tickets` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - /// Storage: `Lottery::LotteryIndex` (r:1 w:1) - /// Proof: `Lottery::LotteryIndex` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) + /// Proof: RandomnessCollectiveFlip RandomMaterial (max_values: Some(1), max_size: Some(2594), added: 3089, mode: MaxEncodedLen) + /// Storage: Lottery Lottery (r:1 w:1) + /// Proof: Lottery Lottery (max_values: Some(1), max_size: Some(29), added: 524, mode: MaxEncodedLen) + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Lottery TicketsCount (r:1 w:1) + /// Proof: Lottery TicketsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Lottery Tickets (r:1 w:0) + /// Proof: Lottery Tickets (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) + /// Storage: Lottery LotteryIndex (r:1 w:1) + /// Proof: Lottery LotteryIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn on_initialize_repeat() -> Weight { // Proof Size summary in bytes: - // Measured: `591` + // Measured: `558` // Estimated: `6196` - // Minimum execution time: 59_376_000 picoseconds. - Weight::from_parts(60_598_000, 6196) + // Minimum execution time: 78_731_000 picoseconds. + Weight::from_parts(80_248_000, 6196) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } diff --git a/substrate/frame/membership/src/weights.rs b/substrate/frame/membership/src/weights.rs index f21867d6870..2d18848b89a 100644 --- a/substrate/frame/membership/src/weights.rs +++ b/substrate/frame/membership/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_membership` +//! Autogenerated weights for pallet_membership //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/membership/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/membership/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_membership`. +/// Weight functions needed for pallet_membership. pub trait WeightInfo { fn add_member(m: u32, ) -> Weight; fn remove_member(m: u32, ) -> Weight; @@ -60,299 +61,299 @@ pub trait WeightInfo { fn clear_prime() -> Weight; } -/// Weights for `pallet_membership` using the Substrate node and recommended hardware. +/// Weights for pallet_membership using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `TechnicalMembership::Members` (r:1 w:1) - /// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) - /// Storage: `TechnicalCommittee::Proposals` (r:1 w:0) - /// Proof: `TechnicalCommittee::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `TechnicalCommittee::Members` (r:0 w:1) - /// Proof: `TechnicalCommittee::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) - /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: TechnicalMembership Members (r:1 w:1) + /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Proposals (r:1 w:0) + /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalCommittee Members (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[1, 99]`. fn add_member(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `207 + m * (64 ±0)` + // Measured: `208 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 12_126_000 picoseconds. - Weight::from_parts(13_085_583, 4687) - // Standard Error: 659 - .saturating_add(Weight::from_parts(36_103, 0).saturating_mul(m.into())) + // Minimum execution time: 17_040_000 picoseconds. + Weight::from_parts(18_344_571, 4687) + // Standard Error: 847 + .saturating_add(Weight::from_parts(50_842, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } - /// Storage: `TechnicalMembership::Members` (r:1 w:1) - /// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) - /// Storage: `TechnicalCommittee::Proposals` (r:1 w:0) - /// Proof: `TechnicalCommittee::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `TechnicalMembership::Prime` (r:1 w:0) - /// Proof: `TechnicalMembership::Prime` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `TechnicalCommittee::Members` (r:0 w:1) - /// Proof: `TechnicalCommittee::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) - /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: TechnicalMembership Members (r:1 w:1) + /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Proposals (r:1 w:0) + /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalMembership Prime (r:1 w:0) + /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Members (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[2, 100]`. fn remove_member(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `311 + m * (64 ±0)` + // Measured: `312 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 14_571_000 picoseconds. - Weight::from_parts(15_532_232, 4687) - // Standard Error: 531 - .saturating_add(Weight::from_parts(35_757, 0).saturating_mul(m.into())) + // Minimum execution time: 20_088_000 picoseconds. + Weight::from_parts(21_271_384, 4687) + // Standard Error: 786 + .saturating_add(Weight::from_parts(44_806, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } - /// Storage: `TechnicalMembership::Members` (r:1 w:1) - /// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) - /// Storage: `TechnicalCommittee::Proposals` (r:1 w:0) - /// Proof: `TechnicalCommittee::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `TechnicalMembership::Prime` (r:1 w:0) - /// Proof: `TechnicalMembership::Prime` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `TechnicalCommittee::Members` (r:0 w:1) - /// Proof: `TechnicalCommittee::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) - /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: TechnicalMembership Members (r:1 w:1) + /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Proposals (r:1 w:0) + /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalMembership Prime (r:1 w:0) + /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Members (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[2, 100]`. fn swap_member(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `311 + m * (64 ±0)` + // Measured: `312 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 14_833_000 picoseconds. - Weight::from_parts(15_657_084, 4687) - // Standard Error: 650 - .saturating_add(Weight::from_parts(44_467, 0).saturating_mul(m.into())) + // Minimum execution time: 20_308_000 picoseconds. + Weight::from_parts(21_469_843, 4687) + // Standard Error: 782 + .saturating_add(Weight::from_parts(56_893, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } - /// Storage: `TechnicalMembership::Members` (r:1 w:1) - /// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) - /// Storage: `TechnicalCommittee::Proposals` (r:1 w:0) - /// Proof: `TechnicalCommittee::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `TechnicalMembership::Prime` (r:1 w:0) - /// Proof: `TechnicalMembership::Prime` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `TechnicalCommittee::Members` (r:0 w:1) - /// Proof: `TechnicalCommittee::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) - /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: TechnicalMembership Members (r:1 w:1) + /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Proposals (r:1 w:0) + /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalMembership Prime (r:1 w:0) + /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Members (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[1, 100]`. fn reset_members(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `311 + m * (64 ±0)` + // Measured: `312 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 14_629_000 picoseconds. - Weight::from_parts(15_578_203, 4687) - // Standard Error: 910 - .saturating_add(Weight::from_parts(145_101, 0).saturating_mul(m.into())) + // Minimum execution time: 19_464_000 picoseconds. + Weight::from_parts(21_223_702, 4687) + // Standard Error: 1_068 + .saturating_add(Weight::from_parts(165_438, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } - /// Storage: `TechnicalMembership::Members` (r:1 w:1) - /// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) - /// Storage: `TechnicalCommittee::Proposals` (r:1 w:0) - /// Proof: `TechnicalCommittee::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `TechnicalMembership::Prime` (r:1 w:1) - /// Proof: `TechnicalMembership::Prime` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `TechnicalCommittee::Members` (r:0 w:1) - /// Proof: `TechnicalCommittee::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) - /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: TechnicalMembership Members (r:1 w:1) + /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Proposals (r:1 w:0) + /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalMembership Prime (r:1 w:1) + /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Members (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[1, 100]`. fn change_key(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `311 + m * (64 ±0)` + // Measured: `312 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 15_218_000 picoseconds. - Weight::from_parts(16_388_690, 4687) - // Standard Error: 626 - .saturating_add(Weight::from_parts(46_204, 0).saturating_mul(m.into())) + // Minimum execution time: 20_965_000 picoseconds. + Weight::from_parts(22_551_007, 4687) + // Standard Error: 860 + .saturating_add(Weight::from_parts(52_397, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } - /// Storage: `TechnicalMembership::Members` (r:1 w:0) - /// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) - /// Storage: `TechnicalMembership::Prime` (r:0 w:1) - /// Proof: `TechnicalMembership::Prime` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) - /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: TechnicalMembership Members (r:1 w:0) + /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: TechnicalMembership Prime (r:0 w:1) + /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[1, 100]`. fn set_prime(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `31 + m * (32 ±0)` + // Measured: `32 + m * (32 ±0)` // Estimated: `4687 + m * (32 ±0)` - // Minimum execution time: 5_954_000 picoseconds. - Weight::from_parts(6_544_638, 4687) - // Standard Error: 346 - .saturating_add(Weight::from_parts(17_638, 0).saturating_mul(m.into())) + // Minimum execution time: 7_481_000 picoseconds. + Weight::from_parts(7_959_053, 4687) + // Standard Error: 364 + .saturating_add(Weight::from_parts(18_653, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } - /// Storage: `TechnicalMembership::Prime` (r:0 w:1) - /// Proof: `TechnicalMembership::Prime` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) - /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: TechnicalMembership Prime (r:0 w:1) + /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) fn clear_prime() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_569_000 picoseconds. - Weight::from_parts(2_776_000, 0) + // Minimum execution time: 3_373_000 picoseconds. + Weight::from_parts(3_750_452, 0) .saturating_add(T::DbWeight::get().writes(2_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `TechnicalMembership::Members` (r:1 w:1) - /// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) - /// Storage: `TechnicalCommittee::Proposals` (r:1 w:0) - /// Proof: `TechnicalCommittee::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `TechnicalCommittee::Members` (r:0 w:1) - /// Proof: `TechnicalCommittee::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) - /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: TechnicalMembership Members (r:1 w:1) + /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Proposals (r:1 w:0) + /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalCommittee Members (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[1, 99]`. fn add_member(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `207 + m * (64 ±0)` + // Measured: `208 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 12_126_000 picoseconds. - Weight::from_parts(13_085_583, 4687) - // Standard Error: 659 - .saturating_add(Weight::from_parts(36_103, 0).saturating_mul(m.into())) + // Minimum execution time: 17_040_000 picoseconds. + Weight::from_parts(18_344_571, 4687) + // Standard Error: 847 + .saturating_add(Weight::from_parts(50_842, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } - /// Storage: `TechnicalMembership::Members` (r:1 w:1) - /// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) - /// Storage: `TechnicalCommittee::Proposals` (r:1 w:0) - /// Proof: `TechnicalCommittee::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `TechnicalMembership::Prime` (r:1 w:0) - /// Proof: `TechnicalMembership::Prime` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `TechnicalCommittee::Members` (r:0 w:1) - /// Proof: `TechnicalCommittee::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) - /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: TechnicalMembership Members (r:1 w:1) + /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Proposals (r:1 w:0) + /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalMembership Prime (r:1 w:0) + /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Members (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[2, 100]`. fn remove_member(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `311 + m * (64 ±0)` + // Measured: `312 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 14_571_000 picoseconds. - Weight::from_parts(15_532_232, 4687) - // Standard Error: 531 - .saturating_add(Weight::from_parts(35_757, 0).saturating_mul(m.into())) + // Minimum execution time: 20_088_000 picoseconds. + Weight::from_parts(21_271_384, 4687) + // Standard Error: 786 + .saturating_add(Weight::from_parts(44_806, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } - /// Storage: `TechnicalMembership::Members` (r:1 w:1) - /// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) - /// Storage: `TechnicalCommittee::Proposals` (r:1 w:0) - /// Proof: `TechnicalCommittee::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `TechnicalMembership::Prime` (r:1 w:0) - /// Proof: `TechnicalMembership::Prime` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `TechnicalCommittee::Members` (r:0 w:1) - /// Proof: `TechnicalCommittee::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) - /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: TechnicalMembership Members (r:1 w:1) + /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Proposals (r:1 w:0) + /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalMembership Prime (r:1 w:0) + /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Members (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[2, 100]`. fn swap_member(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `311 + m * (64 ±0)` + // Measured: `312 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 14_833_000 picoseconds. - Weight::from_parts(15_657_084, 4687) - // Standard Error: 650 - .saturating_add(Weight::from_parts(44_467, 0).saturating_mul(m.into())) + // Minimum execution time: 20_308_000 picoseconds. + Weight::from_parts(21_469_843, 4687) + // Standard Error: 782 + .saturating_add(Weight::from_parts(56_893, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } - /// Storage: `TechnicalMembership::Members` (r:1 w:1) - /// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) - /// Storage: `TechnicalCommittee::Proposals` (r:1 w:0) - /// Proof: `TechnicalCommittee::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `TechnicalMembership::Prime` (r:1 w:0) - /// Proof: `TechnicalMembership::Prime` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `TechnicalCommittee::Members` (r:0 w:1) - /// Proof: `TechnicalCommittee::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) - /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: TechnicalMembership Members (r:1 w:1) + /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Proposals (r:1 w:0) + /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalMembership Prime (r:1 w:0) + /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Members (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[1, 100]`. fn reset_members(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `311 + m * (64 ±0)` + // Measured: `312 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 14_629_000 picoseconds. - Weight::from_parts(15_578_203, 4687) - // Standard Error: 910 - .saturating_add(Weight::from_parts(145_101, 0).saturating_mul(m.into())) + // Minimum execution time: 19_464_000 picoseconds. + Weight::from_parts(21_223_702, 4687) + // Standard Error: 1_068 + .saturating_add(Weight::from_parts(165_438, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } - /// Storage: `TechnicalMembership::Members` (r:1 w:1) - /// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) - /// Storage: `TechnicalCommittee::Proposals` (r:1 w:0) - /// Proof: `TechnicalCommittee::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `TechnicalMembership::Prime` (r:1 w:1) - /// Proof: `TechnicalMembership::Prime` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `TechnicalCommittee::Members` (r:0 w:1) - /// Proof: `TechnicalCommittee::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) - /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: TechnicalMembership Members (r:1 w:1) + /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Proposals (r:1 w:0) + /// Proof Skipped: TechnicalCommittee Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalMembership Prime (r:1 w:1) + /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Members (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[1, 100]`. fn change_key(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `311 + m * (64 ±0)` + // Measured: `312 + m * (64 ±0)` // Estimated: `4687 + m * (64 ±0)` - // Minimum execution time: 15_218_000 picoseconds. - Weight::from_parts(16_388_690, 4687) - // Standard Error: 626 - .saturating_add(Weight::from_parts(46_204, 0).saturating_mul(m.into())) + // Minimum execution time: 20_965_000 picoseconds. + Weight::from_parts(22_551_007, 4687) + // Standard Error: 860 + .saturating_add(Weight::from_parts(52_397, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } - /// Storage: `TechnicalMembership::Members` (r:1 w:0) - /// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`) - /// Storage: `TechnicalMembership::Prime` (r:0 w:1) - /// Proof: `TechnicalMembership::Prime` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) - /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: TechnicalMembership Members (r:1 w:0) + /// Proof: TechnicalMembership Members (max_values: Some(1), max_size: Some(3202), added: 3697, mode: MaxEncodedLen) + /// Storage: TechnicalMembership Prime (r:0 w:1) + /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `m` is `[1, 100]`. fn set_prime(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `31 + m * (32 ±0)` + // Measured: `32 + m * (32 ±0)` // Estimated: `4687 + m * (32 ±0)` - // Minimum execution time: 5_954_000 picoseconds. - Weight::from_parts(6_544_638, 4687) - // Standard Error: 346 - .saturating_add(Weight::from_parts(17_638, 0).saturating_mul(m.into())) + // Minimum execution time: 7_481_000 picoseconds. + Weight::from_parts(7_959_053, 4687) + // Standard Error: 364 + .saturating_add(Weight::from_parts(18_653, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } - /// Storage: `TechnicalMembership::Prime` (r:0 w:1) - /// Proof: `TechnicalMembership::Prime` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `TechnicalCommittee::Prime` (r:0 w:1) - /// Proof: `TechnicalCommittee::Prime` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: TechnicalMembership Prime (r:0 w:1) + /// Proof: TechnicalMembership Prime (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TechnicalCommittee Prime (r:0 w:1) + /// Proof Skipped: TechnicalCommittee Prime (max_values: Some(1), max_size: None, mode: Measured) fn clear_prime() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_569_000 picoseconds. - Weight::from_parts(2_776_000, 0) + // Minimum execution time: 3_373_000 picoseconds. + Weight::from_parts(3_750_452, 0) .saturating_add(RocksDbWeight::get().writes(2_u64)) } } diff --git a/substrate/frame/message-queue/src/weights.rs b/substrate/frame/message-queue/src/weights.rs index 001e2834e1c..e86f23e274f 100644 --- a/substrate/frame/message-queue/src/weights.rs +++ b/substrate/frame/message-queue/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_message_queue` +//! Autogenerated weights for pallet_message_queue //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/message-queue/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/message-queue/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_message_queue`. +/// Weight functions needed for pallet_message_queue. pub trait WeightInfo { fn ready_ring_knit() -> Weight; fn ready_ring_unknit() -> Weight; @@ -63,256 +64,246 @@ pub trait WeightInfo { fn execute_overweight_page_updated() -> Weight; } -/// Weights for `pallet_message_queue` using the Substrate node and recommended hardware. +/// Weights for pallet_message_queue using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `MessageQueue::ServiceHead` (r:1 w:0) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::BookStateFor` (r:2 w:2) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn ready_ring_knit() -> Weight { // Proof Size summary in bytes: - // Measured: `301` + // Measured: `267` // Estimated: `6038` - // Minimum execution time: 11_563_000 picoseconds. - Weight::from_parts(11_956_000, 6038) + // Minimum execution time: 12_025_000 picoseconds. + Weight::from_parts(12_597_000, 6038) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `MessageQueue::BookStateFor` (r:2 w:2) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn ready_ring_unknit() -> Weight { // Proof Size summary in bytes: - // Measured: `301` + // Measured: `267` // Estimated: `6038` - // Minimum execution time: 10_263_000 picoseconds. - Weight::from_parts(10_638_000, 6038) + // Minimum execution time: 11_563_000 picoseconds. + Weight::from_parts(11_785_000, 6038) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn service_queue_base() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3514` - // Minimum execution time: 4_335_000 picoseconds. - Weight::from_parts(4_552_000, 3514) + // Minimum execution time: 4_467_000 picoseconds. + Weight::from_parts(4_655_000, 3514) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `MessageQueue::Pages` (r:1 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65584), added: 68059, mode: `MaxEncodedLen`) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn service_page_base_completion() -> Weight { // Proof Size summary in bytes: // Measured: `147` // Estimated: `69049` - // Minimum execution time: 6_016_000 picoseconds. - Weight::from_parts(6_224_000, 69049) + // Minimum execution time: 6_103_000 picoseconds. + Weight::from_parts(6_254_000, 69049) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `MessageQueue::Pages` (r:1 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65584), added: 68059, mode: `MaxEncodedLen`) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn service_page_base_no_completion() -> Weight { // Proof Size summary in bytes: // Measured: `147` // Estimated: `69049` - // Minimum execution time: 6_183_000 picoseconds. - Weight::from_parts(6_348_000, 69049) + // Minimum execution time: 6_320_000 picoseconds. + Weight::from_parts(6_565_000, 69049) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `MessageQueue::BookStateFor` (r:0 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65584), added: 68059, mode: `MaxEncodedLen`) fn service_page_item() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 112_864_000 picoseconds. - Weight::from_parts(114_269_000, 0) - .saturating_add(T::DbWeight::get().writes(2_u64)) + // Minimum execution time: 66_062_000 picoseconds. + Weight::from_parts(66_371_000, 0) } - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:0) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:1 w:0) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn bump_service_head() -> Weight { // Proof Size summary in bytes: - // Measured: `246` + // Measured: `174` // Estimated: `3514` - // Minimum execution time: 6_665_000 picoseconds. - Weight::from_parts(7_108_000, 3514) + // Minimum execution time: 6_788_000 picoseconds. + Weight::from_parts(7_176_000, 3514) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:1 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65584), added: 68059, mode: `MaxEncodedLen`) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn reap_page() -> Weight { // Proof Size summary in bytes: // Measured: `65744` // Estimated: `69049` - // Minimum execution time: 51_420_000 picoseconds. - Weight::from_parts(52_252_000, 69049) + // Minimum execution time: 52_865_000 picoseconds. + Weight::from_parts(54_398_000, 69049) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:1 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65584), added: 68059, mode: `MaxEncodedLen`) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn execute_overweight_page_removed() -> Weight { // Proof Size summary in bytes: // Measured: `65744` // Estimated: `69049` - // Minimum execution time: 71_195_000 picoseconds. - Weight::from_parts(72_981_000, 69049) + // Minimum execution time: 69_168_000 picoseconds. + Weight::from_parts(70_560_000, 69049) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:1 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65584), added: 68059, mode: `MaxEncodedLen`) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn execute_overweight_page_updated() -> Weight { // Proof Size summary in bytes: // Measured: `65744` // Estimated: `69049` - // Minimum execution time: 83_238_000 picoseconds. - Weight::from_parts(84_422_000, 69049) + // Minimum execution time: 80_947_000 picoseconds. + Weight::from_parts(82_715_000, 69049) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `MessageQueue::ServiceHead` (r:1 w:0) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::BookStateFor` (r:2 w:2) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn ready_ring_knit() -> Weight { // Proof Size summary in bytes: - // Measured: `301` + // Measured: `267` // Estimated: `6038` - // Minimum execution time: 11_563_000 picoseconds. - Weight::from_parts(11_956_000, 6038) + // Minimum execution time: 12_025_000 picoseconds. + Weight::from_parts(12_597_000, 6038) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `MessageQueue::BookStateFor` (r:2 w:2) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn ready_ring_unknit() -> Weight { // Proof Size summary in bytes: - // Measured: `301` + // Measured: `267` // Estimated: `6038` - // Minimum execution time: 10_263_000 picoseconds. - Weight::from_parts(10_638_000, 6038) + // Minimum execution time: 11_563_000 picoseconds. + Weight::from_parts(11_785_000, 6038) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn service_queue_base() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3514` - // Minimum execution time: 4_335_000 picoseconds. - Weight::from_parts(4_552_000, 3514) + // Minimum execution time: 4_467_000 picoseconds. + Weight::from_parts(4_655_000, 3514) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `MessageQueue::Pages` (r:1 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65584), added: 68059, mode: `MaxEncodedLen`) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn service_page_base_completion() -> Weight { // Proof Size summary in bytes: // Measured: `147` // Estimated: `69049` - // Minimum execution time: 6_016_000 picoseconds. - Weight::from_parts(6_224_000, 69049) + // Minimum execution time: 6_103_000 picoseconds. + Weight::from_parts(6_254_000, 69049) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `MessageQueue::Pages` (r:1 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65584), added: 68059, mode: `MaxEncodedLen`) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn service_page_base_no_completion() -> Weight { // Proof Size summary in bytes: // Measured: `147` // Estimated: `69049` - // Minimum execution time: 6_183_000 picoseconds. - Weight::from_parts(6_348_000, 69049) + // Minimum execution time: 6_320_000 picoseconds. + Weight::from_parts(6_565_000, 69049) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `MessageQueue::BookStateFor` (r:0 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:0 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65584), added: 68059, mode: `MaxEncodedLen`) fn service_page_item() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 112_864_000 picoseconds. - Weight::from_parts(114_269_000, 0) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + // Minimum execution time: 66_062_000 picoseconds. + Weight::from_parts(66_371_000, 0) } - /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) - /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::BookStateFor` (r:1 w:0) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:1 w:0) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) fn bump_service_head() -> Weight { // Proof Size summary in bytes: - // Measured: `246` + // Measured: `174` // Estimated: `3514` - // Minimum execution time: 6_665_000 picoseconds. - Weight::from_parts(7_108_000, 3514) + // Minimum execution time: 6_788_000 picoseconds. + Weight::from_parts(7_176_000, 3514) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:1 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65584), added: 68059, mode: `MaxEncodedLen`) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn reap_page() -> Weight { // Proof Size summary in bytes: // Measured: `65744` // Estimated: `69049` - // Minimum execution time: 51_420_000 picoseconds. - Weight::from_parts(52_252_000, 69049) + // Minimum execution time: 52_865_000 picoseconds. + Weight::from_parts(54_398_000, 69049) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:1 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65584), added: 68059, mode: `MaxEncodedLen`) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn execute_overweight_page_removed() -> Weight { // Proof Size summary in bytes: // Measured: `65744` // Estimated: `69049` - // Minimum execution time: 71_195_000 picoseconds. - Weight::from_parts(72_981_000, 69049) + // Minimum execution time: 69_168_000 picoseconds. + Weight::from_parts(70_560_000, 69049) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) - /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `MessageQueue::Pages` (r:1 w:1) - /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(65584), added: 68059, mode: `MaxEncodedLen`) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:1 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65584), added: 68059, mode: MaxEncodedLen) fn execute_overweight_page_updated() -> Weight { // Proof Size summary in bytes: // Measured: `65744` // Estimated: `69049` - // Minimum execution time: 83_238_000 picoseconds. - Weight::from_parts(84_422_000, 69049) + // Minimum execution time: 80_947_000 picoseconds. + Weight::from_parts(82_715_000, 69049) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/substrate/frame/migrations/src/weights.rs b/substrate/frame/migrations/src/weights.rs index 9eca48ac3fd..c9b63258c44 100644 --- a/substrate/frame/migrations/src/weights.rs +++ b/substrate/frame/migrations/src/weights.rs @@ -17,29 +17,26 @@ //! Autogenerated weights for `pallet_migrations` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `loud1`, CPU: `AMD EPYC 7282 16-Core Processor` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/production/substrate-node +// target/release/substrate-node // benchmark // pallet -// --chain=dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_migrations -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --wasm-execution=compiled -// --heap-pages=4096 -// --output=./substrate/frame/migrations/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --chain +// dev +// --pallet +// pallet-migrations +// --extrinsic +// +// --output +// weight.rs +// --template +// ../../polkadot-sdk/substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -74,10 +71,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) fn onboard_new_mbms() -> Weight { // Proof Size summary in bytes: - // Measured: `276` + // Measured: `243` // Estimated: `67035` - // Minimum execution time: 7_932_000 picoseconds. - Weight::from_parts(8_428_000, 67035) + // Minimum execution time: 13_980_000 picoseconds. + Weight::from_parts(14_290_000, 67035) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -85,10 +82,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) fn progress_mbms_none() -> Weight { // Proof Size summary in bytes: - // Measured: `142` + // Measured: `109` // Estimated: `67035` - // Minimum execution time: 2_229_000 picoseconds. - Weight::from_parts(2_329_000, 67035) + // Minimum execution time: 3_770_000 picoseconds. + Weight::from_parts(4_001_000, 67035) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) @@ -99,8 +96,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `134` // Estimated: `3599` - // Minimum execution time: 6_051_000 picoseconds. - Weight::from_parts(6_483_000, 3599) + // Minimum execution time: 10_900_000 picoseconds. + Weight::from_parts(11_251_000, 3599) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -110,10 +107,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) fn exec_migration_skipped_historic() -> Weight { // Proof Size summary in bytes: - // Measured: `330` - // Estimated: `3795` - // Minimum execution time: 10_066_000 picoseconds. - Weight::from_parts(10_713_000, 3795) + // Measured: `297` + // Estimated: `3762` + // Minimum execution time: 17_891_000 picoseconds. + Weight::from_parts(18_501_000, 3762) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) @@ -122,10 +119,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) fn exec_migration_advance() -> Weight { // Proof Size summary in bytes: - // Measured: `276` - // Estimated: `3741` - // Minimum execution time: 10_026_000 picoseconds. - Weight::from_parts(10_379_000, 3741) + // Measured: `243` + // Estimated: `3731` + // Minimum execution time: 18_271_000 picoseconds. + Weight::from_parts(18_740_000, 3731) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) @@ -134,10 +131,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) fn exec_migration_complete() -> Weight { // Proof Size summary in bytes: - // Measured: `276` - // Estimated: `3741` - // Minimum execution time: 11_680_000 picoseconds. - Weight::from_parts(12_184_000, 3741) + // Measured: `243` + // Estimated: `3731` + // Minimum execution time: 21_241_000 picoseconds. + Weight::from_parts(21_911_000, 3731) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -149,10 +146,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) fn exec_migration_fail() -> Weight { // Proof Size summary in bytes: - // Measured: `276` - // Estimated: `3741` - // Minimum execution time: 12_334_000 picoseconds. - Weight::from_parts(12_899_000, 3741) + // Measured: `243` + // Estimated: `3731` + // Minimum execution time: 22_740_000 picoseconds. + Weight::from_parts(23_231_000, 3731) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -160,8 +157,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 187_000 picoseconds. - Weight::from_parts(209_000, 0) + // Minimum execution time: 440_000 picoseconds. + Weight::from_parts(500_000, 0) } /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) @@ -169,8 +166,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_688_000 picoseconds. - Weight::from_parts(2_874_000, 0) + // Minimum execution time: 5_751_000 picoseconds. + Weight::from_parts(5_950_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) @@ -179,8 +176,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_108_000 picoseconds. - Weight::from_parts(3_263_000, 0) + // Minimum execution time: 6_350_000 picoseconds. + Weight::from_parts(6_560_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) @@ -189,10 +186,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) fn force_onboard_mbms() -> Weight { // Proof Size summary in bytes: - // Measured: `251` + // Measured: `218` // Estimated: `67035` - // Minimum execution time: 5_993_000 picoseconds. - Weight::from_parts(6_359_000, 67035) + // Minimum execution time: 11_121_000 picoseconds. + Weight::from_parts(11_530_000, 67035) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: `MultiBlockMigrations::Historic` (r:256 w:256) @@ -200,12 +197,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 256]`. fn clear_historic(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1122 + n * (271 ±0)` + // Measured: `1089 + n * (271 ±0)` // Estimated: `3834 + n * (2740 ±0)` - // Minimum execution time: 16_003_000 picoseconds. - Weight::from_parts(14_453_014, 3834) - // Standard Error: 3_305 - .saturating_add(Weight::from_parts(1_325_026, 0).saturating_mul(n.into())) + // Minimum execution time: 21_891_000 picoseconds. + Weight::from_parts(18_572_306, 3834) + // Standard Error: 3_236 + .saturating_add(Weight::from_parts(1_648_429, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -221,10 +218,10 @@ impl WeightInfo for () { /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) fn onboard_new_mbms() -> Weight { // Proof Size summary in bytes: - // Measured: `276` + // Measured: `243` // Estimated: `67035` - // Minimum execution time: 7_932_000 picoseconds. - Weight::from_parts(8_428_000, 67035) + // Minimum execution time: 13_980_000 picoseconds. + Weight::from_parts(14_290_000, 67035) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -232,10 +229,10 @@ impl WeightInfo for () { /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) fn progress_mbms_none() -> Weight { // Proof Size summary in bytes: - // Measured: `142` + // Measured: `109` // Estimated: `67035` - // Minimum execution time: 2_229_000 picoseconds. - Weight::from_parts(2_329_000, 67035) + // Minimum execution time: 3_770_000 picoseconds. + Weight::from_parts(4_001_000, 67035) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) @@ -246,8 +243,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `134` // Estimated: `3599` - // Minimum execution time: 6_051_000 picoseconds. - Weight::from_parts(6_483_000, 3599) + // Minimum execution time: 10_900_000 picoseconds. + Weight::from_parts(11_251_000, 3599) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -257,10 +254,10 @@ impl WeightInfo for () { /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) fn exec_migration_skipped_historic() -> Weight { // Proof Size summary in bytes: - // Measured: `330` - // Estimated: `3795` - // Minimum execution time: 10_066_000 picoseconds. - Weight::from_parts(10_713_000, 3795) + // Measured: `297` + // Estimated: `3762` + // Minimum execution time: 17_891_000 picoseconds. + Weight::from_parts(18_501_000, 3762) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) @@ -269,10 +266,10 @@ impl WeightInfo for () { /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) fn exec_migration_advance() -> Weight { // Proof Size summary in bytes: - // Measured: `276` - // Estimated: `3741` - // Minimum execution time: 10_026_000 picoseconds. - Weight::from_parts(10_379_000, 3741) + // Measured: `243` + // Estimated: `3731` + // Minimum execution time: 18_271_000 picoseconds. + Weight::from_parts(18_740_000, 3731) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) @@ -281,10 +278,10 @@ impl WeightInfo for () { /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) fn exec_migration_complete() -> Weight { // Proof Size summary in bytes: - // Measured: `276` - // Estimated: `3741` - // Minimum execution time: 11_680_000 picoseconds. - Weight::from_parts(12_184_000, 3741) + // Measured: `243` + // Estimated: `3731` + // Minimum execution time: 21_241_000 picoseconds. + Weight::from_parts(21_911_000, 3731) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -296,10 +293,10 @@ impl WeightInfo for () { /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) fn exec_migration_fail() -> Weight { // Proof Size summary in bytes: - // Measured: `276` - // Estimated: `3741` - // Minimum execution time: 12_334_000 picoseconds. - Weight::from_parts(12_899_000, 3741) + // Measured: `243` + // Estimated: `3731` + // Minimum execution time: 22_740_000 picoseconds. + Weight::from_parts(23_231_000, 3731) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -307,8 +304,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 187_000 picoseconds. - Weight::from_parts(209_000, 0) + // Minimum execution time: 440_000 picoseconds. + Weight::from_parts(500_000, 0) } /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) @@ -316,8 +313,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_688_000 picoseconds. - Weight::from_parts(2_874_000, 0) + // Minimum execution time: 5_751_000 picoseconds. + Weight::from_parts(5_950_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) @@ -326,8 +323,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_108_000 picoseconds. - Weight::from_parts(3_263_000, 0) + // Minimum execution time: 6_350_000 picoseconds. + Weight::from_parts(6_560_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) @@ -336,10 +333,10 @@ impl WeightInfo for () { /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) fn force_onboard_mbms() -> Weight { // Proof Size summary in bytes: - // Measured: `251` + // Measured: `218` // Estimated: `67035` - // Minimum execution time: 5_993_000 picoseconds. - Weight::from_parts(6_359_000, 67035) + // Minimum execution time: 11_121_000 picoseconds. + Weight::from_parts(11_530_000, 67035) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: `MultiBlockMigrations::Historic` (r:256 w:256) @@ -347,12 +344,12 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 256]`. fn clear_historic(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1122 + n * (271 ±0)` + // Measured: `1089 + n * (271 ±0)` // Estimated: `3834 + n * (2740 ±0)` - // Minimum execution time: 16_003_000 picoseconds. - Weight::from_parts(14_453_014, 3834) - // Standard Error: 3_305 - .saturating_add(Weight::from_parts(1_325_026, 0).saturating_mul(n.into())) + // Minimum execution time: 21_891_000 picoseconds. + Weight::from_parts(18_572_306, 3834) + // Standard Error: 3_236 + .saturating_add(Weight::from_parts(1_648_429, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) diff --git a/substrate/frame/multisig/src/weights.rs b/substrate/frame/multisig/src/weights.rs index 4cbe7bb03b7..7b87d258d38 100644 --- a/substrate/frame/multisig/src/weights.rs +++ b/substrate/frame/multisig/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_multisig` +//! Autogenerated weights for pallet_multisig //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/multisig/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/multisig/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_multisig`. +/// Weight functions needed for pallet_multisig. pub trait WeightInfo { fn as_multi_threshold_1(z: u32, ) -> Weight; fn as_multi_create(s: u32, z: u32, ) -> Weight; @@ -60,238 +61,220 @@ pub trait WeightInfo { fn cancel_as_multi(s: u32, ) -> Weight; } -/// Weights for `pallet_multisig` using the Substrate node and recommended hardware. +/// Weights for pallet_multisig using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) /// The range of component `z` is `[0, 10000]`. fn as_multi_threshold_1(z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `145` - // Estimated: `3997` - // Minimum execution time: 18_893_000 picoseconds. - Weight::from_parts(20_278_307, 3997) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 13_452_000 picoseconds. + Weight::from_parts(14_425_869, 0) // Standard Error: 4 - .saturating_add(Weight::from_parts(488, 0).saturating_mul(z.into())) - .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(Weight::from_parts(493, 0).saturating_mul(z.into())) } - /// Storage: `Multisig::Multisigs` (r:1 w:1) - /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_create(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `301 + s * (2 ±0)` // Estimated: `6811` - // Minimum execution time: 39_478_000 picoseconds. - Weight::from_parts(29_195_487, 6811) - // Standard Error: 739 - .saturating_add(Weight::from_parts(118_766, 0).saturating_mul(s.into())) - // Standard Error: 7 - .saturating_add(Weight::from_parts(1_511, 0).saturating_mul(z.into())) + // Minimum execution time: 46_012_000 picoseconds. + Weight::from_parts(34_797_344, 6811) + // Standard Error: 833 + .saturating_add(Weight::from_parts(127_671, 0).saturating_mul(s.into())) + // Standard Error: 8 + .saturating_add(Weight::from_parts(1_498, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Multisig::Multisigs` (r:1 w:1) - /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[3, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_approve(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `320` // Estimated: `6811` - // Minimum execution time: 26_401_000 picoseconds. - Weight::from_parts(17_277_296, 6811) - // Standard Error: 492 - .saturating_add(Weight::from_parts(101_763, 0).saturating_mul(s.into())) - // Standard Error: 4 - .saturating_add(Weight::from_parts(1_486, 0).saturating_mul(z.into())) + // Minimum execution time: 29_834_000 picoseconds. + Weight::from_parts(20_189_154, 6811) + // Standard Error: 637 + .saturating_add(Weight::from_parts(110_080, 0).saturating_mul(s.into())) + // Standard Error: 6 + .saturating_add(Weight::from_parts(1_483, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Multisig::Multisigs` (r:1 w:1) - /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_complete(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `571 + s * (33 ±0)` + // Measured: `426 + s * (33 ±0)` // Estimated: `6811` - // Minimum execution time: 52_430_000 picoseconds. - Weight::from_parts(40_585_478, 6811) - // Standard Error: 1_240 - .saturating_add(Weight::from_parts(161_405, 0).saturating_mul(s.into())) + // Minimum execution time: 51_464_000 picoseconds. + Weight::from_parts(39_246_644, 6811) + // Standard Error: 1_251 + .saturating_add(Weight::from_parts(143_313, 0).saturating_mul(s.into())) // Standard Error: 12 - .saturating_add(Weight::from_parts(1_547, 0).saturating_mul(z.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(Weight::from_parts(1_523, 0).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Multisig::Multisigs` (r:1 w:1) - /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. fn approve_as_multi_create(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `301 + s * (2 ±0)` // Estimated: `6811` - // Minimum execution time: 27_797_000 picoseconds. - Weight::from_parts(29_064_584, 6811) - // Standard Error: 817 - .saturating_add(Weight::from_parts(108_179, 0).saturating_mul(s.into())) + // Minimum execution time: 33_275_000 picoseconds. + Weight::from_parts(34_073_221, 6811) + // Standard Error: 1_163 + .saturating_add(Weight::from_parts(124_815, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Multisig::Multisigs` (r:1 w:1) - /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. fn approve_as_multi_approve(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `320` // Estimated: `6811` - // Minimum execution time: 15_236_000 picoseconds. - Weight::from_parts(16_360_247, 6811) - // Standard Error: 584 - .saturating_add(Weight::from_parts(94_917, 0).saturating_mul(s.into())) + // Minimum execution time: 18_411_000 picoseconds. + Weight::from_parts(19_431_787, 6811) + // Standard Error: 694 + .saturating_add(Weight::from_parts(107_220, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Multisig::Multisigs` (r:1 w:1) - /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. fn cancel_as_multi(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `492 + s * (1 ±0)` // Estimated: `6811` - // Minimum execution time: 28_730_000 picoseconds. - Weight::from_parts(30_056_661, 6811) - // Standard Error: 792 - .saturating_add(Weight::from_parts(108_212, 0).saturating_mul(s.into())) + // Minimum execution time: 33_985_000 picoseconds. + Weight::from_parts(35_547_970, 6811) + // Standard Error: 1_135 + .saturating_add(Weight::from_parts(116_537, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) /// The range of component `z` is `[0, 10000]`. fn as_multi_threshold_1(z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `145` - // Estimated: `3997` - // Minimum execution time: 18_893_000 picoseconds. - Weight::from_parts(20_278_307, 3997) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 13_452_000 picoseconds. + Weight::from_parts(14_425_869, 0) // Standard Error: 4 - .saturating_add(Weight::from_parts(488, 0).saturating_mul(z.into())) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(Weight::from_parts(493, 0).saturating_mul(z.into())) } - /// Storage: `Multisig::Multisigs` (r:1 w:1) - /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_create(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `301 + s * (2 ±0)` // Estimated: `6811` - // Minimum execution time: 39_478_000 picoseconds. - Weight::from_parts(29_195_487, 6811) - // Standard Error: 739 - .saturating_add(Weight::from_parts(118_766, 0).saturating_mul(s.into())) - // Standard Error: 7 - .saturating_add(Weight::from_parts(1_511, 0).saturating_mul(z.into())) + // Minimum execution time: 46_012_000 picoseconds. + Weight::from_parts(34_797_344, 6811) + // Standard Error: 833 + .saturating_add(Weight::from_parts(127_671, 0).saturating_mul(s.into())) + // Standard Error: 8 + .saturating_add(Weight::from_parts(1_498, 0).saturating_mul(z.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Multisig::Multisigs` (r:1 w:1) - /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[3, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_approve(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `320` // Estimated: `6811` - // Minimum execution time: 26_401_000 picoseconds. - Weight::from_parts(17_277_296, 6811) - // Standard Error: 492 - .saturating_add(Weight::from_parts(101_763, 0).saturating_mul(s.into())) - // Standard Error: 4 - .saturating_add(Weight::from_parts(1_486, 0).saturating_mul(z.into())) + // Minimum execution time: 29_834_000 picoseconds. + Weight::from_parts(20_189_154, 6811) + // Standard Error: 637 + .saturating_add(Weight::from_parts(110_080, 0).saturating_mul(s.into())) + // Standard Error: 6 + .saturating_add(Weight::from_parts(1_483, 0).saturating_mul(z.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Multisig::Multisigs` (r:1 w:1) - /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_complete(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `571 + s * (33 ±0)` + // Measured: `426 + s * (33 ±0)` // Estimated: `6811` - // Minimum execution time: 52_430_000 picoseconds. - Weight::from_parts(40_585_478, 6811) - // Standard Error: 1_240 - .saturating_add(Weight::from_parts(161_405, 0).saturating_mul(s.into())) + // Minimum execution time: 51_464_000 picoseconds. + Weight::from_parts(39_246_644, 6811) + // Standard Error: 1_251 + .saturating_add(Weight::from_parts(143_313, 0).saturating_mul(s.into())) // Standard Error: 12 - .saturating_add(Weight::from_parts(1_547, 0).saturating_mul(z.into())) - .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(Weight::from_parts(1_523, 0).saturating_mul(z.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Multisig::Multisigs` (r:1 w:1) - /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. fn approve_as_multi_create(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `301 + s * (2 ±0)` // Estimated: `6811` - // Minimum execution time: 27_797_000 picoseconds. - Weight::from_parts(29_064_584, 6811) - // Standard Error: 817 - .saturating_add(Weight::from_parts(108_179, 0).saturating_mul(s.into())) + // Minimum execution time: 33_275_000 picoseconds. + Weight::from_parts(34_073_221, 6811) + // Standard Error: 1_163 + .saturating_add(Weight::from_parts(124_815, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Multisig::Multisigs` (r:1 w:1) - /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. fn approve_as_multi_approve(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `320` // Estimated: `6811` - // Minimum execution time: 15_236_000 picoseconds. - Weight::from_parts(16_360_247, 6811) - // Standard Error: 584 - .saturating_add(Weight::from_parts(94_917, 0).saturating_mul(s.into())) + // Minimum execution time: 18_411_000 picoseconds. + Weight::from_parts(19_431_787, 6811) + // Standard Error: 694 + .saturating_add(Weight::from_parts(107_220, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Multisig::Multisigs` (r:1 w:1) - /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) + /// Storage: Multisig Multisigs (r:1 w:1) + /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) /// The range of component `s` is `[2, 100]`. fn cancel_as_multi(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `492 + s * (1 ±0)` // Estimated: `6811` - // Minimum execution time: 28_730_000 picoseconds. - Weight::from_parts(30_056_661, 6811) - // Standard Error: 792 - .saturating_add(Weight::from_parts(108_212, 0).saturating_mul(s.into())) + // Minimum execution time: 33_985_000 picoseconds. + Weight::from_parts(35_547_970, 6811) + // Standard Error: 1_135 + .saturating_add(Weight::from_parts(116_537, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/nft-fractionalization/src/weights.rs b/substrate/frame/nft-fractionalization/src/weights.rs index 07872ebaea9..ebb4aa0fbcf 100644 --- a/substrate/frame/nft-fractionalization/src/weights.rs +++ b/substrate/frame/nft-fractionalization/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_nft_fractionalization` +//! Autogenerated weights for pallet_nft_fractionalization //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/nft-fractionalization/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/nft-fractionalization/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,136 +50,136 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_nft_fractionalization`. +/// Weight functions needed for pallet_nft_fractionalization. pub trait WeightInfo { fn fractionalize() -> Weight; fn unify() -> Weight; } -/// Weights for `pallet_nft_fractionalization` using the Substrate node and recommended hardware. +/// Weights for pallet_nft_fractionalization using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Nfts::Item` (r:1 w:0) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Attribute` (r:1 w:1) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Assets::Metadata` (r:1 w:1) - /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) - /// Storage: `NftFractionalization::NftToAsset` (r:0 w:1) - /// Proof: `NftFractionalization::NftToAsset` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: Nfts Item (r:1 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(85), added: 2560, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:1 w:1) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:1) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: NftFractionalization NftToAsset (r:0 w:1) + /// Proof: NftFractionalization NftToAsset (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) fn fractionalize() -> Weight { // Proof Size summary in bytes: // Measured: `609` // Estimated: `4326` - // Minimum execution time: 164_764_000 picoseconds. - Weight::from_parts(168_243_000, 4326) + // Minimum execution time: 187_416_000 picoseconds. + Weight::from_parts(191_131_000, 4326) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } - /// Storage: `NftFractionalization::NftToAsset` (r:1 w:1) - /// Proof: `NftFractionalization::NftToAsset` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Attribute` (r:1 w:1) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Item` (r:1 w:1) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Account` (r:0 w:1) - /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) - /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) - /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) - /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) + /// Storage: NftFractionalization NftToAsset (r:1 w:1) + /// Proof: NftFractionalization NftToAsset (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:1 w:1) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(85), added: 2560, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:1) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Nfts ItemPriceOf (r:0 w:1) + /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) + /// Storage: Nfts PendingSwapOf (r:0 w:1) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn unify() -> Weight { // Proof Size summary in bytes: // Measured: `1422` // Estimated: `4326` - // Minimum execution time: 120_036_000 picoseconds. - Weight::from_parts(123_550_000, 4326) + // Minimum execution time: 134_159_000 picoseconds. + Weight::from_parts(136_621_000, 4326) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(10_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Nfts::Item` (r:1 w:0) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Attribute` (r:1 w:1) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Assets::Metadata` (r:1 w:1) - /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(140), added: 2615, mode: `MaxEncodedLen`) - /// Storage: `NftFractionalization::NftToAsset` (r:0 w:1) - /// Proof: `NftFractionalization::NftToAsset` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) + /// Storage: Nfts Item (r:1 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(85), added: 2560, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:1 w:1) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Assets Metadata (r:1 w:1) + /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: NftFractionalization NftToAsset (r:0 w:1) + /// Proof: NftFractionalization NftToAsset (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) fn fractionalize() -> Weight { // Proof Size summary in bytes: // Measured: `609` // Estimated: `4326` - // Minimum execution time: 164_764_000 picoseconds. - Weight::from_parts(168_243_000, 4326) + // Minimum execution time: 187_416_000 picoseconds. + Weight::from_parts(191_131_000, 4326) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } - /// Storage: `NftFractionalization::NftToAsset` (r:1 w:1) - /// Proof: `NftFractionalization::NftToAsset` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Attribute` (r:1 w:1) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Item` (r:1 w:1) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Account` (r:0 w:1) - /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) - /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) - /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) - /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) + /// Storage: NftFractionalization NftToAsset (r:1 w:1) + /// Proof: NftFractionalization NftToAsset (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:1 w:1) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(85), added: 2560, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:1) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Nfts ItemPriceOf (r:0 w:1) + /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) + /// Storage: Nfts PendingSwapOf (r:0 w:1) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn unify() -> Weight { // Proof Size summary in bytes: // Measured: `1422` // Estimated: `4326` - // Minimum execution time: 120_036_000 picoseconds. - Weight::from_parts(123_550_000, 4326) + // Minimum execution time: 134_159_000 picoseconds. + Weight::from_parts(136_621_000, 4326) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(10_u64)) } diff --git a/substrate/frame/nfts/src/weights.rs b/substrate/frame/nfts/src/weights.rs index 4fcc1e601f4..6b8c577bb12 100644 --- a/substrate/frame/nfts/src/weights.rs +++ b/substrate/frame/nfts/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_nfts` +//! Autogenerated weights for pallet_nfts //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -37,9 +37,9 @@ // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/nfts/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/nfts/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +49,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_nfts`. +/// Weight functions needed for pallet_nfts. pub trait WeightInfo { fn create() -> Weight; fn force_create() -> Weight; @@ -92,568 +92,564 @@ pub trait WeightInfo { fn set_attributes_pre_signed(n: u32, ) -> Weight; } -/// Weights for `pallet_nfts` using the Substrate node and recommended hardware. +/// Weights for pallet_nfts using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Nfts::NextCollectionId` (r:1 w:1) - /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionRoleOf` (r:0 w:1) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionAccount` (r:0 w:1) - /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + /// Storage: Nfts NextCollectionId (r:1 w:1) + /// Proof: Nfts NextCollectionId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:0 w:1) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:0 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts CollectionAccount (r:0 w:1) + /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: // Measured: `216` // Estimated: `3549` - // Minimum execution time: 34_035_000 picoseconds. - Weight::from_parts(35_228_000, 3549) + // Minimum execution time: 40_489_000 picoseconds. + Weight::from_parts(41_320_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: `Nfts::NextCollectionId` (r:1 w:1) - /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionRoleOf` (r:0 w:1) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionAccount` (r:0 w:1) - /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + /// Storage: Nfts NextCollectionId (r:1 w:1) + /// Proof: Nfts NextCollectionId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:0 w:1) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:0 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts CollectionAccount (r:0 w:1) + /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3549` - // Minimum execution time: 19_430_000 picoseconds. - Weight::from_parts(20_054_000, 3549) + // Minimum execution time: 23_257_000 picoseconds. + Weight::from_parts(23_770_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) - /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:1) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Attribute` (r:1001 w:1000) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1000 w:1000) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionMetadataOf` (r:0 w:1) - /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionAccount` (r:0 w:1) - /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts ItemMetadataOf (r:1 w:0) + /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:1) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:1001 w:1000) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1000 w:1000) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts CollectionMetadataOf (r:0 w:1) + /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:0 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts CollectionAccount (r:0 w:1) + /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) /// The range of component `m` is `[0, 1000]`. /// The range of component `c` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. fn destroy(_m: u32, _c: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32204 + a * (366 ±0)` - // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 1_249_733_000 picoseconds. - Weight::from_parts(1_293_703_849, 2523990) - // Standard Error: 4_764 - .saturating_add(Weight::from_parts(6_433_523, 0).saturating_mul(a.into())) + // Measured: `32220 + a * (332 ±0)` + // Estimated: `2523990 + a * (2921 ±0)` + // Minimum execution time: 1_310_198_000 picoseconds. + Weight::from_parts(1_479_261_043, 2523990) + // Standard Error: 4_415 + .saturating_add(Weight::from_parts(6_016_212, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(1004_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(T::DbWeight::get().writes(1005_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) - .saturating_add(Weight::from_parts(0, 2954).saturating_mul(a.into())) - } - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Item` (r:1 w:1) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Account` (r:0 w:1) - /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + .saturating_add(Weight::from_parts(0, 2921).saturating_mul(a.into())) + } + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:1) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn mint() -> Weight { // Proof Size summary in bytes: // Measured: `455` // Estimated: `4326` - // Minimum execution time: 48_645_000 picoseconds. - Weight::from_parts(50_287_000, 4326) + // Minimum execution time: 51_910_000 picoseconds. + Weight::from_parts(53_441_000, 4326) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Item` (r:1 w:1) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Account` (r:0 w:1) - /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:1) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn force_mint() -> Weight { // Proof Size summary in bytes: // Measured: `455` // Estimated: `4326` - // Minimum execution time: 46_688_000 picoseconds. - Weight::from_parts(47_680_000, 4326) + // Minimum execution time: 50_168_000 picoseconds. + Weight::from_parts(51_380_000, 4326) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: `Nfts::Attribute` (r:1 w:0) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Item` (r:1 w:1) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) - /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Account` (r:0 w:1) - /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) - /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:0 w:1) - /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) - /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) - /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts ItemMetadataOf (r:1 w:0) + /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:1) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Nfts ItemPriceOf (r:0 w:1) + /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) + /// Storage: Nfts ItemAttributesApprovalsOf (r:0 w:1) + /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) + /// Storage: Nfts PendingSwapOf (r:0 w:1) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn burn() -> Weight { // Proof Size summary in bytes: // Measured: `564` // Estimated: `4326` - // Minimum execution time: 51_771_000 picoseconds. - Weight::from_parts(53_492_000, 4326) - .saturating_add(T::DbWeight::get().reads(5_u64)) + // Minimum execution time: 50_738_000 picoseconds. + Weight::from_parts(51_850_000, 4326) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Attribute` (r:1 w:0) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Item` (r:1 w:1) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Account` (r:0 w:2) - /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) - /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) - /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) - /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:1 w:0) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:2) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Nfts ItemPriceOf (r:0 w:1) + /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) + /// Storage: Nfts PendingSwapOf (r:0 w:1) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: // Measured: `593` // Estimated: `4326` - // Minimum execution time: 39_166_000 picoseconds. - Weight::from_parts(40_128_000, 4326) + // Minimum execution time: 41_055_000 picoseconds. + Weight::from_parts(42_336_000, 4326) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Item` (r:5000 w:5000) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:5000 w:5000) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `763 + i * (108 ±0)` // Estimated: `3549 + i * (3336 ±0)` - // Minimum execution time: 13_804_000 picoseconds. - Weight::from_parts(14_159_000, 3549) - // Standard Error: 13_812 - .saturating_add(Weight::from_parts(14_661_284, 0).saturating_mul(i.into())) + // Minimum execution time: 15_688_000 picoseconds. + Weight::from_parts(15_921_000, 3549) + // Standard Error: 14_827 + .saturating_add(Weight::from_parts(17_105_395, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_parts(0, 3336).saturating_mul(i.into())) } - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn lock_item_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `435` // Estimated: `3534` - // Minimum execution time: 17_485_000 picoseconds. - Weight::from_parts(18_412_000, 3534) + // Minimum execution time: 19_981_000 picoseconds. + Weight::from_parts(20_676_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn unlock_item_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `435` // Estimated: `3534` - // Minimum execution time: 17_335_000 picoseconds. - Weight::from_parts(18_543_000, 3534) + // Minimum execution time: 19_911_000 picoseconds. + Weight::from_parts(20_612_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn lock_collection() -> Weight { // Proof Size summary in bytes: // Measured: `340` // Estimated: `3549` - // Minimum execution time: 14_608_000 picoseconds. - Weight::from_parts(15_696_000, 3549) + // Minimum execution time: 16_441_000 picoseconds. + Weight::from_parts(16_890_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) - /// Proof: `Nfts::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionAccount` (r:0 w:2) - /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + /// Storage: Nfts OwnershipAcceptance (r:1 w:1) + /// Proof: Nfts OwnershipAcceptance (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionAccount (r:0 w:2) + /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `562` - // Estimated: `3593` - // Minimum execution time: 25_686_000 picoseconds. - Weight::from_parts(26_433_000, 3593) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(5_u64)) + // Measured: `388` + // Estimated: `3549` + // Minimum execution time: 22_610_000 picoseconds. + Weight::from_parts(23_422_000, 3549) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionRoleOf` (r:2 w:4) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:2 w:4) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn set_team() -> Weight { // Proof Size summary in bytes: // Measured: `369` // Estimated: `6078` - // Minimum execution time: 37_192_000 picoseconds. - Weight::from_parts(38_561_000, 6078) + // Minimum execution time: 39_739_000 picoseconds. + Weight::from_parts(41_306_000, 6078) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionAccount` (r:0 w:2) - /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionAccount (r:0 w:2) + /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn force_collection_owner() -> Weight { // Proof Size summary in bytes: // Measured: `311` // Estimated: `3549` - // Minimum execution time: 15_401_000 picoseconds. - Weight::from_parts(15_826_000, 3549) + // Minimum execution time: 17_685_000 picoseconds. + Weight::from_parts(18_258_000, 3549) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:0 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn force_collection_config() -> Weight { // Proof Size summary in bytes: // Measured: `276` // Estimated: `3549` - // Minimum execution time: 11_683_000 picoseconds. - Weight::from_parts(12_255_000, 3549) + // Minimum execution time: 13_734_000 picoseconds. + Weight::from_parts(14_337_000, 3549) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn lock_item_properties() -> Weight { // Proof Size summary in bytes: // Measured: `435` // Estimated: `3534` - // Minimum execution time: 16_899_000 picoseconds. - Weight::from_parts(17_404_000, 3534) + // Minimum execution time: 19_269_000 picoseconds. + Weight::from_parts(19_859_000, 3534) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Attribute` (r:1 w:1) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:1 w:1) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) fn set_attribute() -> Weight { // Proof Size summary in bytes: // Measured: `539` - // Estimated: `3944` - // Minimum execution time: 46_768_000 picoseconds. - Weight::from_parts(47_834_000, 3944) + // Estimated: `3911` + // Minimum execution time: 51_540_000 picoseconds. + Weight::from_parts(52_663_000, 3911) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Attribute` (r:1 w:1) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:1 w:1) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) fn force_set_attribute() -> Weight { // Proof Size summary in bytes: // Measured: `344` - // Estimated: `3944` - // Minimum execution time: 23_356_000 picoseconds. - Weight::from_parts(24_528_000, 3944) + // Estimated: `3911` + // Minimum execution time: 26_529_000 picoseconds. + Weight::from_parts(27_305_000, 3911) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Nfts::Attribute` (r:1 w:1) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: Nfts Attribute (r:1 w:1) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `983` - // Estimated: `3944` - // Minimum execution time: 43_061_000 picoseconds. - Weight::from_parts(44_024_000, 3944) + // Measured: `950` + // Estimated: `3911` + // Minimum execution time: 46_951_000 picoseconds. + Weight::from_parts(48_481_000, 3911) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Nfts::Item` (r:1 w:0) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) - /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) + /// Storage: Nfts Item (r:1 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) + /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) fn approve_item_attributes() -> Weight { // Proof Size summary in bytes: // Measured: `381` // Estimated: `4326` - // Minimum execution time: 14_929_000 picoseconds. - Weight::from_parts(15_344_000, 4326) + // Minimum execution time: 17_222_000 picoseconds. + Weight::from_parts(17_819_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::Item` (r:1 w:0) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) - /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Attribute` (r:1001 w:1000) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Nfts Item (r:1 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) + /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:1001 w:1000) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `n` is `[0, 1000]`. fn cancel_item_attributes_approval(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `831 + n * (398 ±0)` - // Estimated: `4326 + n * (2954 ±0)` - // Minimum execution time: 23_707_000 picoseconds. - Weight::from_parts(24_688_000, 4326) - // Standard Error: 3_813 - .saturating_add(Weight::from_parts(6_422_256, 0).saturating_mul(n.into())) + // Measured: `837 + n * (364 ±0)` + // Estimated: `4326 + n * (2921 ±0)` + // Minimum execution time: 26_185_000 picoseconds. + Weight::from_parts(27_038_000, 4326) + // Standard Error: 2_378 + .saturating_add(Weight::from_parts(6_067_888, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) - } - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) - /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) + .saturating_add(Weight::from_parts(0, 2921).saturating_mul(n.into())) + } + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemMetadataOf (r:1 w:1) + /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn set_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `539` - // Estimated: `3812` - // Minimum execution time: 37_882_000 picoseconds. - Weight::from_parts(39_222_000, 3812) + // Estimated: `3605` + // Minimum execution time: 42_120_000 picoseconds. + Weight::from_parts(43_627_000, 3605) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) - /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts ItemMetadataOf (r:1 w:1) + /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `849` - // Estimated: `3812` - // Minimum execution time: 36_629_000 picoseconds. - Weight::from_parts(37_351_000, 3812) + // Measured: `642` + // Estimated: `3605` + // Minimum execution time: 40_732_000 picoseconds. + Weight::from_parts(42_760_000, 3605) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionMetadataOf` (r:1 w:1) - /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionMetadataOf (r:1 w:1) + /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `398` - // Estimated: `3759` - // Minimum execution time: 34_853_000 picoseconds. - Weight::from_parts(35_914_000, 3759) + // Estimated: `3552` + // Minimum execution time: 39_443_000 picoseconds. + Weight::from_parts(40_482_000, 3552) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionMetadataOf` (r:1 w:1) - /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts CollectionMetadataOf (r:1 w:1) + /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `716` - // Estimated: `3759` - // Minimum execution time: 33_759_000 picoseconds. - Weight::from_parts(34_729_000, 3759) + // Measured: `509` + // Estimated: `3552` + // Minimum execution time: 37_676_000 picoseconds. + Weight::from_parts(39_527_000, 3552) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::Item` (r:1 w:1) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn approve_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `410` // Estimated: `4326` - // Minimum execution time: 17_583_000 picoseconds. - Weight::from_parts(18_675_000, 4326) + // Minimum execution time: 20_787_000 picoseconds. + Weight::from_parts(21_315_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::Item` (r:1 w:1) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) fn cancel_approval() -> Weight { // Proof Size summary in bytes: // Measured: `418` // Estimated: `4326` - // Minimum execution time: 15_036_000 picoseconds. - Weight::from_parts(15_995_000, 4326) + // Minimum execution time: 18_200_000 picoseconds. + Weight::from_parts(19_064_000, 4326) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::Item` (r:1 w:1) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) fn clear_all_transfer_approvals() -> Weight { // Proof Size summary in bytes: // Measured: `418` // Estimated: `4326` - // Minimum execution time: 14_666_000 picoseconds. - Weight::from_parts(15_152_000, 4326) + // Minimum execution time: 17_128_000 picoseconds. + Weight::from_parts(17_952_000, 4326) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) - /// Proof: `Nfts::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: Nfts OwnershipAcceptance (r:1 w:1) + /// Proof: Nfts OwnershipAcceptance (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn set_accept_ownership() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3517` - // Minimum execution time: 12_393_000 picoseconds. - Weight::from_parts(12_895_000, 3517) + // Minimum execution time: 14_667_000 picoseconds. + Weight::from_parts(15_262_000, 3517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: Nfts CollectionConfigOf (r:1 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: // Measured: `340` // Estimated: `3549` - // Minimum execution time: 16_034_000 picoseconds. - Weight::from_parts(16_617_000, 3549) + // Minimum execution time: 18_435_000 picoseconds. + Weight::from_parts(18_775_000, 3549) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn update_mint_settings() -> Weight { // Proof Size summary in bytes: // Measured: `323` // Estimated: `3538` - // Minimum execution time: 15_812_000 picoseconds. - Weight::from_parts(16_644_000, 3538) + // Minimum execution time: 18_125_000 picoseconds. + Weight::from_parts(18_415_000, 3538) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::Item` (r:1 w:0) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) - /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + /// Storage: Nfts Item (r:1 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts ItemPriceOf (r:0 w:1) + /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn set_price() -> Weight { // Proof Size summary in bytes: // Measured: `518` // Estimated: `4326` - // Minimum execution time: 21_650_000 picoseconds. - Weight::from_parts(22_443_000, 4326) + // Minimum execution time: 23_237_000 picoseconds. + Weight::from_parts(24_128_000, 4326) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::Item` (r:1 w:1) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemPriceOf` (r:1 w:1) - /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Attribute` (r:1 w:0) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Account` (r:0 w:2) - /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) - /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) - /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts ItemPriceOf (r:1 w:1) + /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:1 w:0) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:2) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Nfts PendingSwapOf (r:0 w:1) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn buy_item() -> Weight { // Proof Size summary in bytes: // Measured: `705` // Estimated: `4326` - // Minimum execution time: 49_463_000 picoseconds. - Weight::from_parts(50_937_000, 4326) + // Minimum execution time: 53_291_000 picoseconds. + Weight::from_parts(54_614_000, 4326) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -662,685 +658,681 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_029_000 picoseconds. - Weight::from_parts(3_749_829, 0) - // Standard Error: 8_497 - .saturating_add(Weight::from_parts(1_913_514, 0).saturating_mul(n.into())) - } - /// Storage: `Nfts::Item` (r:2 w:0) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) - /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) + // Minimum execution time: 2_192_000 picoseconds. + Weight::from_parts(4_039_901, 0) + // Standard Error: 10_309 + .saturating_add(Weight::from_parts(3_934_017, 0).saturating_mul(n.into())) + } + /// Storage: Nfts Item (r:2 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts PendingSwapOf (r:0 w:1) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn create_swap() -> Weight { // Proof Size summary in bytes: // Measured: `494` // Estimated: `7662` - // Minimum execution time: 18_181_000 picoseconds. - Weight::from_parts(18_698_000, 7662) + // Minimum execution time: 21_011_000 picoseconds. + Weight::from_parts(22_065_000, 7662) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::PendingSwapOf` (r:1 w:1) - /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Item` (r:1 w:0) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: Nfts PendingSwapOf (r:1 w:1) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) fn cancel_swap() -> Weight { // Proof Size summary in bytes: // Measured: `513` // Estimated: `4326` - // Minimum execution time: 18_228_000 picoseconds. - Weight::from_parts(18_940_000, 4326) + // Minimum execution time: 21_423_000 picoseconds. + Weight::from_parts(21_743_000, 4326) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::Item` (r:2 w:2) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::PendingSwapOf` (r:1 w:2) - /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Attribute` (r:2 w:0) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:2 w:0) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Account` (r:0 w:4) - /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemPriceOf` (r:0 w:2) - /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + /// Storage: Nfts Item (r:2 w:2) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts PendingSwapOf (r:1 w:2) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:2 w:0) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:2 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:4) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Nfts ItemPriceOf (r:0 w:2) + /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn claim_swap() -> Weight { // Proof Size summary in bytes: // Measured: `834` // Estimated: `7662` - // Minimum execution time: 77_983_000 picoseconds. - Weight::from_parts(79_887_000, 7662) + // Minimum execution time: 86_059_000 picoseconds. + Weight::from_parts(88_401_000, 7662) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(10_u64)) } - /// Storage: `Nfts::CollectionRoleOf` (r:2 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Item` (r:1 w:1) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Attribute` (r:10 w:10) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) - /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Account` (r:0 w:1) - /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Storage: Nfts CollectionRoleOf (r:2 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:10 w:10) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: Nfts ItemMetadataOf (r:1 w:1) + /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:1) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) /// The range of component `n` is `[0, 10]`. fn mint_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `629` - // Estimated: `6078 + n * (2954 ±0)` - // Minimum execution time: 126_998_000 picoseconds. - Weight::from_parts(134_149_389, 6078) - // Standard Error: 33_180 - .saturating_add(Weight::from_parts(30_711_206, 0).saturating_mul(n.into())) + // Estimated: `6078 + n * (2921 ±0)` + // Minimum execution time: 146_746_000 picoseconds. + Weight::from_parts(152_885_862, 6078) + // Standard Error: 40_442 + .saturating_add(Weight::from_parts(32_887_800, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) - } - /// Storage: `Nfts::Item` (r:1 w:0) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) - /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Attribute` (r:10 w:10) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + .saturating_add(Weight::from_parts(0, 2921).saturating_mul(n.into())) + } + /// Storage: Nfts Item (r:1 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) + /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:10 w:10) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `n` is `[0, 10]`. fn set_attributes_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `659` - // Estimated: `4326 + n * (2954 ±0)` - // Minimum execution time: 66_213_000 picoseconds. - Weight::from_parts(81_661_819, 4326) - // Standard Error: 87_003 - .saturating_add(Weight::from_parts(29_550_476, 0).saturating_mul(n.into())) + // Estimated: `4326 + n * (2921 ±0)` + // Minimum execution time: 83_960_000 picoseconds. + Weight::from_parts(98_609_885, 4326) + // Standard Error: 85_991 + .saturating_add(Weight::from_parts(32_633_495, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2921).saturating_mul(n.into())) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Nfts::NextCollectionId` (r:1 w:1) - /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionRoleOf` (r:0 w:1) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionAccount` (r:0 w:1) - /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + /// Storage: Nfts NextCollectionId (r:1 w:1) + /// Proof: Nfts NextCollectionId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:0 w:1) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:0 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts CollectionAccount (r:0 w:1) + /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: // Measured: `216` // Estimated: `3549` - // Minimum execution time: 34_035_000 picoseconds. - Weight::from_parts(35_228_000, 3549) + // Minimum execution time: 40_489_000 picoseconds. + Weight::from_parts(41_320_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: `Nfts::NextCollectionId` (r:1 w:1) - /// Proof: `Nfts::NextCollectionId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionRoleOf` (r:0 w:1) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionAccount` (r:0 w:1) - /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + /// Storage: Nfts NextCollectionId (r:1 w:1) + /// Proof: Nfts NextCollectionId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:0 w:1) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:0 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts CollectionAccount (r:0 w:1) + /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3549` - // Minimum execution time: 19_430_000 picoseconds. - Weight::from_parts(20_054_000, 3549) + // Minimum execution time: 23_257_000 picoseconds. + Weight::from_parts(23_770_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) - /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:1) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Attribute` (r:1001 w:1000) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1000 w:1000) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionMetadataOf` (r:0 w:1) - /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionAccount` (r:0 w:1) - /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts ItemMetadataOf (r:1 w:0) + /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:1) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:1001 w:1000) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1000 w:1000) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts CollectionMetadataOf (r:0 w:1) + /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:0 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts CollectionAccount (r:0 w:1) + /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) /// The range of component `m` is `[0, 1000]`. /// The range of component `c` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. fn destroy(_m: u32, _c: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32204 + a * (366 ±0)` - // Estimated: `2523990 + a * (2954 ±0)` - // Minimum execution time: 1_249_733_000 picoseconds. - Weight::from_parts(1_293_703_849, 2523990) - // Standard Error: 4_764 - .saturating_add(Weight::from_parts(6_433_523, 0).saturating_mul(a.into())) + // Measured: `32220 + a * (332 ±0)` + // Estimated: `2523990 + a * (2921 ±0)` + // Minimum execution time: 1_310_198_000 picoseconds. + Weight::from_parts(1_479_261_043, 2523990) + // Standard Error: 4_415 + .saturating_add(Weight::from_parts(6_016_212, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(1004_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(a.into()))) .saturating_add(RocksDbWeight::get().writes(1005_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(a.into()))) - .saturating_add(Weight::from_parts(0, 2954).saturating_mul(a.into())) - } - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Item` (r:1 w:1) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Account` (r:0 w:1) - /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + .saturating_add(Weight::from_parts(0, 2921).saturating_mul(a.into())) + } + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:1) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn mint() -> Weight { // Proof Size summary in bytes: // Measured: `455` // Estimated: `4326` - // Minimum execution time: 48_645_000 picoseconds. - Weight::from_parts(50_287_000, 4326) + // Minimum execution time: 51_910_000 picoseconds. + Weight::from_parts(53_441_000, 4326) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Item` (r:1 w:1) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Account` (r:0 w:1) - /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:1) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn force_mint() -> Weight { // Proof Size summary in bytes: // Measured: `455` // Estimated: `4326` - // Minimum execution time: 46_688_000 picoseconds. - Weight::from_parts(47_680_000, 4326) + // Minimum execution time: 50_168_000 picoseconds. + Weight::from_parts(51_380_000, 4326) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: `Nfts::Attribute` (r:1 w:0) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Item` (r:1 w:1) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemMetadataOf` (r:1 w:0) - /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Account` (r:0 w:1) - /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) - /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:0 w:1) - /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) - /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) - /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts ItemMetadataOf (r:1 w:0) + /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:1) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Nfts ItemPriceOf (r:0 w:1) + /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) + /// Storage: Nfts ItemAttributesApprovalsOf (r:0 w:1) + /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) + /// Storage: Nfts PendingSwapOf (r:0 w:1) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn burn() -> Weight { // Proof Size summary in bytes: // Measured: `564` // Estimated: `4326` - // Minimum execution time: 51_771_000 picoseconds. - Weight::from_parts(53_492_000, 4326) - .saturating_add(RocksDbWeight::get().reads(5_u64)) + // Minimum execution time: 50_738_000 picoseconds. + Weight::from_parts(51_850_000, 4326) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Attribute` (r:1 w:0) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Item` (r:1 w:1) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Account` (r:0 w:2) - /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) - /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) - /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) - /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:1 w:0) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:2) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Nfts ItemPriceOf (r:0 w:1) + /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) + /// Storage: Nfts PendingSwapOf (r:0 w:1) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: // Measured: `593` // Estimated: `4326` - // Minimum execution time: 39_166_000 picoseconds. - Weight::from_parts(40_128_000, 4326) + // Minimum execution time: 41_055_000 picoseconds. + Weight::from_parts(42_336_000, 4326) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Item` (r:5000 w:5000) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:5000 w:5000) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `763 + i * (108 ±0)` // Estimated: `3549 + i * (3336 ±0)` - // Minimum execution time: 13_804_000 picoseconds. - Weight::from_parts(14_159_000, 3549) - // Standard Error: 13_812 - .saturating_add(Weight::from_parts(14_661_284, 0).saturating_mul(i.into())) + // Minimum execution time: 15_688_000 picoseconds. + Weight::from_parts(15_921_000, 3549) + // Standard Error: 14_827 + .saturating_add(Weight::from_parts(17_105_395, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_parts(0, 3336).saturating_mul(i.into())) } - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn lock_item_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `435` // Estimated: `3534` - // Minimum execution time: 17_485_000 picoseconds. - Weight::from_parts(18_412_000, 3534) + // Minimum execution time: 19_981_000 picoseconds. + Weight::from_parts(20_676_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn unlock_item_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `435` // Estimated: `3534` - // Minimum execution time: 17_335_000 picoseconds. - Weight::from_parts(18_543_000, 3534) + // Minimum execution time: 19_911_000 picoseconds. + Weight::from_parts(20_612_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn lock_collection() -> Weight { // Proof Size summary in bytes: // Measured: `340` // Estimated: `3549` - // Minimum execution time: 14_608_000 picoseconds. - Weight::from_parts(15_696_000, 3549) + // Minimum execution time: 16_441_000 picoseconds. + Weight::from_parts(16_890_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) - /// Proof: `Nfts::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionAccount` (r:0 w:2) - /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + /// Storage: Nfts OwnershipAcceptance (r:1 w:1) + /// Proof: Nfts OwnershipAcceptance (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionAccount (r:0 w:2) + /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `562` - // Estimated: `3593` - // Minimum execution time: 25_686_000 picoseconds. - Weight::from_parts(26_433_000, 3593) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(5_u64)) + // Measured: `388` + // Estimated: `3549` + // Minimum execution time: 22_610_000 picoseconds. + Weight::from_parts(23_422_000, 3549) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionRoleOf` (r:2 w:4) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:2 w:4) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn set_team() -> Weight { // Proof Size summary in bytes: // Measured: `369` // Estimated: `6078` - // Minimum execution time: 37_192_000 picoseconds. - Weight::from_parts(38_561_000, 6078) + // Minimum execution time: 39_739_000 picoseconds. + Weight::from_parts(41_306_000, 6078) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionAccount` (r:0 w:2) - /// Proof: `Nfts::CollectionAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionAccount (r:0 w:2) + /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn force_collection_owner() -> Weight { // Proof Size summary in bytes: // Measured: `311` // Estimated: `3549` - // Minimum execution time: 15_401_000 picoseconds. - Weight::from_parts(15_826_000, 3549) + // Minimum execution time: 17_685_000 picoseconds. + Weight::from_parts(18_258_000, 3549) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:0 w:1) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:0 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn force_collection_config() -> Weight { // Proof Size summary in bytes: // Measured: `276` // Estimated: `3549` - // Minimum execution time: 11_683_000 picoseconds. - Weight::from_parts(12_255_000, 3549) + // Minimum execution time: 13_734_000 picoseconds. + Weight::from_parts(14_337_000, 3549) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn lock_item_properties() -> Weight { // Proof Size summary in bytes: // Measured: `435` // Estimated: `3534` - // Minimum execution time: 16_899_000 picoseconds. - Weight::from_parts(17_404_000, 3534) + // Minimum execution time: 19_269_000 picoseconds. + Weight::from_parts(19_859_000, 3534) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Attribute` (r:1 w:1) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:1 w:1) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) fn set_attribute() -> Weight { // Proof Size summary in bytes: // Measured: `539` - // Estimated: `3944` - // Minimum execution time: 46_768_000 picoseconds. - Weight::from_parts(47_834_000, 3944) + // Estimated: `3911` + // Minimum execution time: 51_540_000 picoseconds. + Weight::from_parts(52_663_000, 3911) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Attribute` (r:1 w:1) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:1 w:1) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) fn force_set_attribute() -> Weight { // Proof Size summary in bytes: // Measured: `344` - // Estimated: `3944` - // Minimum execution time: 23_356_000 picoseconds. - Weight::from_parts(24_528_000, 3944) + // Estimated: `3911` + // Minimum execution time: 26_529_000 picoseconds. + Weight::from_parts(27_305_000, 3911) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Nfts::Attribute` (r:1 w:1) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: Nfts Attribute (r:1 w:1) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `983` - // Estimated: `3944` - // Minimum execution time: 43_061_000 picoseconds. - Weight::from_parts(44_024_000, 3944) + // Measured: `950` + // Estimated: `3911` + // Minimum execution time: 46_951_000 picoseconds. + Weight::from_parts(48_481_000, 3911) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Nfts::Item` (r:1 w:0) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) - /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) + /// Storage: Nfts Item (r:1 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) + /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) fn approve_item_attributes() -> Weight { // Proof Size summary in bytes: // Measured: `381` // Estimated: `4326` - // Minimum execution time: 14_929_000 picoseconds. - Weight::from_parts(15_344_000, 4326) + // Minimum execution time: 17_222_000 picoseconds. + Weight::from_parts(17_819_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::Item` (r:1 w:0) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) - /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Attribute` (r:1001 w:1000) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Nfts Item (r:1 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) + /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:1001 w:1000) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `n` is `[0, 1000]`. fn cancel_item_attributes_approval(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `831 + n * (398 ±0)` - // Estimated: `4326 + n * (2954 ±0)` - // Minimum execution time: 23_707_000 picoseconds. - Weight::from_parts(24_688_000, 4326) - // Standard Error: 3_813 - .saturating_add(Weight::from_parts(6_422_256, 0).saturating_mul(n.into())) + // Measured: `837 + n * (364 ±0)` + // Estimated: `4326 + n * (2921 ±0)` + // Minimum execution time: 26_185_000 picoseconds. + Weight::from_parts(27_038_000, 4326) + // Standard Error: 2_378 + .saturating_add(Weight::from_parts(6_067_888, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) - } - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) - /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) + .saturating_add(Weight::from_parts(0, 2921).saturating_mul(n.into())) + } + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemMetadataOf (r:1 w:1) + /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn set_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `539` - // Estimated: `3812` - // Minimum execution time: 37_882_000 picoseconds. - Weight::from_parts(39_222_000, 3812) + // Estimated: `3605` + // Minimum execution time: 42_120_000 picoseconds. + Weight::from_parts(43_627_000, 3605) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) - /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts ItemMetadataOf (r:1 w:1) + /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `849` - // Estimated: `3812` - // Minimum execution time: 36_629_000 picoseconds. - Weight::from_parts(37_351_000, 3812) + // Measured: `642` + // Estimated: `3605` + // Minimum execution time: 40_732_000 picoseconds. + Weight::from_parts(42_760_000, 3605) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionMetadataOf` (r:1 w:1) - /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionMetadataOf (r:1 w:1) + /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `398` - // Estimated: `3759` - // Minimum execution time: 34_853_000 picoseconds. - Weight::from_parts(35_914_000, 3759) + // Estimated: `3552` + // Minimum execution time: 39_443_000 picoseconds. + Weight::from_parts(40_482_000, 3552) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionMetadataOf` (r:1 w:1) - /// Proof: `Nfts::CollectionMetadataOf` (`max_values`: None, `max_size`: Some(294), added: 2769, mode: `MaxEncodedLen`) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts CollectionMetadataOf (r:1 w:1) + /// Proof: Nfts CollectionMetadataOf (max_values: None, max_size: Some(87), added: 2562, mode: MaxEncodedLen) fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `716` - // Estimated: `3759` - // Minimum execution time: 33_759_000 picoseconds. - Weight::from_parts(34_729_000, 3759) + // Measured: `509` + // Estimated: `3552` + // Minimum execution time: 37_676_000 picoseconds. + Weight::from_parts(39_527_000, 3552) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::Item` (r:1 w:1) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn approve_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `410` // Estimated: `4326` - // Minimum execution time: 17_583_000 picoseconds. - Weight::from_parts(18_675_000, 4326) + // Minimum execution time: 20_787_000 picoseconds. + Weight::from_parts(21_315_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::Item` (r:1 w:1) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) fn cancel_approval() -> Weight { // Proof Size summary in bytes: // Measured: `418` // Estimated: `4326` - // Minimum execution time: 15_036_000 picoseconds. - Weight::from_parts(15_995_000, 4326) + // Minimum execution time: 18_200_000 picoseconds. + Weight::from_parts(19_064_000, 4326) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::Item` (r:1 w:1) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) fn clear_all_transfer_approvals() -> Weight { // Proof Size summary in bytes: // Measured: `418` // Estimated: `4326` - // Minimum execution time: 14_666_000 picoseconds. - Weight::from_parts(15_152_000, 4326) + // Minimum execution time: 17_128_000 picoseconds. + Weight::from_parts(17_952_000, 4326) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::OwnershipAcceptance` (r:1 w:1) - /// Proof: `Nfts::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: Nfts OwnershipAcceptance (r:1 w:1) + /// Proof: Nfts OwnershipAcceptance (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn set_accept_ownership() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `3517` - // Minimum execution time: 12_393_000 picoseconds. - Weight::from_parts(12_895_000, 3517) + // Minimum execution time: 14_667_000 picoseconds. + Weight::from_parts(15_262_000, 3517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: Nfts CollectionConfigOf (r:1 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) fn set_collection_max_supply() -> Weight { // Proof Size summary in bytes: // Measured: `340` // Estimated: `3549` - // Minimum execution time: 16_034_000 picoseconds. - Weight::from_parts(16_617_000, 3549) + // Minimum execution time: 18_435_000 picoseconds. + Weight::from_parts(18_775_000, 3549) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::CollectionRoleOf` (r:1 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:1) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:1) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn update_mint_settings() -> Weight { // Proof Size summary in bytes: // Measured: `323` // Estimated: `3538` - // Minimum execution time: 15_812_000 picoseconds. - Weight::from_parts(16_644_000, 3538) + // Minimum execution time: 18_125_000 picoseconds. + Weight::from_parts(18_415_000, 3538) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::Item` (r:1 w:0) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) - /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + /// Storage: Nfts Item (r:1 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts ItemPriceOf (r:0 w:1) + /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn set_price() -> Weight { // Proof Size summary in bytes: // Measured: `518` // Estimated: `4326` - // Minimum execution time: 21_650_000 picoseconds. - Weight::from_parts(22_443_000, 4326) + // Minimum execution time: 23_237_000 picoseconds. + Weight::from_parts(24_128_000, 4326) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::Item` (r:1 w:1) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemPriceOf` (r:1 w:1) - /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Attribute` (r:1 w:0) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Account` (r:0 w:2) - /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) - /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) - /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts ItemPriceOf (r:1 w:1) + /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:1 w:0) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:2) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Nfts PendingSwapOf (r:0 w:1) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn buy_item() -> Weight { // Proof Size summary in bytes: // Measured: `705` // Estimated: `4326` - // Minimum execution time: 49_463_000 picoseconds. - Weight::from_parts(50_937_000, 4326) + // Minimum execution time: 53_291_000 picoseconds. + Weight::from_parts(54_614_000, 4326) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -1349,120 +1341,120 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_029_000 picoseconds. - Weight::from_parts(3_749_829, 0) - // Standard Error: 8_497 - .saturating_add(Weight::from_parts(1_913_514, 0).saturating_mul(n.into())) - } - /// Storage: `Nfts::Item` (r:2 w:0) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) - /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) + // Minimum execution time: 2_192_000 picoseconds. + Weight::from_parts(4_039_901, 0) + // Standard Error: 10_309 + .saturating_add(Weight::from_parts(3_934_017, 0).saturating_mul(n.into())) + } + /// Storage: Nfts Item (r:2 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts PendingSwapOf (r:0 w:1) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn create_swap() -> Weight { // Proof Size summary in bytes: // Measured: `494` // Estimated: `7662` - // Minimum execution time: 18_181_000 picoseconds. - Weight::from_parts(18_698_000, 7662) + // Minimum execution time: 21_011_000 picoseconds. + Weight::from_parts(22_065_000, 7662) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::PendingSwapOf` (r:1 w:1) - /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Item` (r:1 w:0) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) + /// Storage: Nfts PendingSwapOf (r:1 w:1) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) fn cancel_swap() -> Weight { // Proof Size summary in bytes: // Measured: `513` // Estimated: `4326` - // Minimum execution time: 18_228_000 picoseconds. - Weight::from_parts(18_940_000, 4326) + // Minimum execution time: 21_423_000 picoseconds. + Weight::from_parts(21_743_000, 4326) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Nfts::Item` (r:2 w:2) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::PendingSwapOf` (r:1 w:2) - /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(71), added: 2546, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Attribute` (r:2 w:0) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:2 w:0) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Account` (r:0 w:4) - /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemPriceOf` (r:0 w:2) - /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(89), added: 2564, mode: `MaxEncodedLen`) + /// Storage: Nfts Item (r:2 w:2) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts PendingSwapOf (r:1 w:2) + /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:0) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:2 w:0) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:2 w:0) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:4) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) + /// Storage: Nfts ItemPriceOf (r:0 w:2) + /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn claim_swap() -> Weight { // Proof Size summary in bytes: // Measured: `834` // Estimated: `7662` - // Minimum execution time: 77_983_000 picoseconds. - Weight::from_parts(79_887_000, 7662) + // Minimum execution time: 86_059_000 picoseconds. + Weight::from_parts(88_401_000, 7662) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(10_u64)) } - /// Storage: `Nfts::CollectionRoleOf` (r:2 w:0) - /// Proof: `Nfts::CollectionRoleOf` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Item` (r:1 w:1) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:1) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Attribute` (r:10 w:10) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemMetadataOf` (r:1 w:1) - /// Proof: `Nfts::ItemMetadataOf` (`max_values`: None, `max_size`: Some(347), added: 2822, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Account` (r:0 w:1) - /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) + /// Storage: Nfts CollectionRoleOf (r:2 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Item (r:1 w:1) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts ItemConfigOf (r:1 w:1) + /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:10 w:10) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: Nfts ItemMetadataOf (r:1 w:1) + /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) + /// Storage: Nfts Account (r:0 w:1) + /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) /// The range of component `n` is `[0, 10]`. fn mint_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `629` - // Estimated: `6078 + n * (2954 ±0)` - // Minimum execution time: 126_998_000 picoseconds. - Weight::from_parts(134_149_389, 6078) - // Standard Error: 33_180 - .saturating_add(Weight::from_parts(30_711_206, 0).saturating_mul(n.into())) + // Estimated: `6078 + n * (2921 ±0)` + // Minimum execution time: 146_746_000 picoseconds. + Weight::from_parts(152_885_862, 6078) + // Standard Error: 40_442 + .saturating_add(Weight::from_parts(32_887_800, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) - } - /// Storage: `Nfts::Item` (r:1 w:0) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(861), added: 3336, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemAttributesApprovalsOf` (r:1 w:1) - /// Proof: `Nfts::ItemAttributesApprovalsOf` (`max_values`: None, `max_size`: Some(681), added: 3156, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:1) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Attribute` (r:10 w:10) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(479), added: 2954, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + .saturating_add(Weight::from_parts(0, 2921).saturating_mul(n.into())) + } + /// Storage: Nfts Item (r:1 w:0) + /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts ItemAttributesApprovalsOf (r:1 w:1) + /// Proof: Nfts ItemAttributesApprovalsOf (max_values: None, max_size: Some(681), added: 3156, mode: MaxEncodedLen) + /// Storage: Nfts CollectionConfigOf (r:1 w:0) + /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) + /// Storage: Nfts Attribute (r:10 w:10) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(446), added: 2921, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `n` is `[0, 10]`. fn set_attributes_pre_signed(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `659` - // Estimated: `4326 + n * (2954 ±0)` - // Minimum execution time: 66_213_000 picoseconds. - Weight::from_parts(81_661_819, 4326) - // Standard Error: 87_003 - .saturating_add(Weight::from_parts(29_550_476, 0).saturating_mul(n.into())) + // Estimated: `4326 + n * (2921 ±0)` + // Minimum execution time: 83_960_000 picoseconds. + Weight::from_parts(98_609_885, 4326) + // Standard Error: 85_991 + .saturating_add(Weight::from_parts(32_633_495, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2921).saturating_mul(n.into())) } } diff --git a/substrate/frame/nis/src/weights.rs b/substrate/frame/nis/src/weights.rs index 63908271391..cba2f004905 100644 --- a/substrate/frame/nis/src/weights.rs +++ b/substrate/frame/nis/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_nis` +//! Autogenerated weights for pallet_nis //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/nis/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/nis/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_nis`. +/// Weight functions needed for pallet_nis. pub trait WeightInfo { fn place_bid(l: u32, ) -> Weight; fn place_bid_max() -> Weight; @@ -64,367 +65,367 @@ pub trait WeightInfo { fn process_bid() -> Weight; } -/// Weights for `pallet_nis` using the Substrate node and recommended hardware. +/// Weights for pallet_nis using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Nis::Queues` (r:1 w:1) - /// Proof: `Nis::Queues` (`max_values`: None, `max_size`: Some(48022), added: 50497, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) - /// Storage: `Nis::QueueTotals` (r:1 w:1) - /// Proof: `Nis::QueueTotals` (`max_values`: Some(1), `max_size`: Some(6002), added: 6497, mode: `MaxEncodedLen`) + /// Storage: Nis Queues (r:1 w:1) + /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(85), added: 2560, mode: MaxEncodedLen) + /// Storage: Nis QueueTotals (r:1 w:1) + /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) /// The range of component `l` is `[0, 999]`. fn place_bid(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `6176 + l * (48 ±0)` // Estimated: `51487` - // Minimum execution time: 47_908_000 picoseconds. - Weight::from_parts(50_096_676, 51487) - // Standard Error: 208 - .saturating_add(Weight::from_parts(41_318, 0).saturating_mul(l.into())) + // Minimum execution time: 49_410_000 picoseconds. + Weight::from_parts(57_832_282, 51487) + // Standard Error: 288 + .saturating_add(Weight::from_parts(51_621, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Nis::Queues` (r:1 w:1) - /// Proof: `Nis::Queues` (`max_values`: None, `max_size`: Some(48022), added: 50497, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) - /// Storage: `Nis::QueueTotals` (r:1 w:1) - /// Proof: `Nis::QueueTotals` (`max_values`: Some(1), `max_size`: Some(6002), added: 6497, mode: `MaxEncodedLen`) + /// Storage: Nis Queues (r:1 w:1) + /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(85), added: 2560, mode: MaxEncodedLen) + /// Storage: Nis QueueTotals (r:1 w:1) + /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) fn place_bid_max() -> Weight { // Proof Size summary in bytes: // Measured: `54178` // Estimated: `51487` - // Minimum execution time: 100_836_000 picoseconds. - Weight::from_parts(102_497_000, 51487) + // Minimum execution time: 119_696_000 picoseconds. + Weight::from_parts(121_838_000, 51487) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Nis::Queues` (r:1 w:1) - /// Proof: `Nis::Queues` (`max_values`: None, `max_size`: Some(48022), added: 50497, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) - /// Storage: `Nis::QueueTotals` (r:1 w:1) - /// Proof: `Nis::QueueTotals` (`max_values`: Some(1), `max_size`: Some(6002), added: 6497, mode: `MaxEncodedLen`) + /// Storage: Nis Queues (r:1 w:1) + /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(85), added: 2560, mode: MaxEncodedLen) + /// Storage: Nis QueueTotals (r:1 w:1) + /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) /// The range of component `l` is `[1, 1000]`. fn retract_bid(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `6176 + l * (48 ±0)` // Estimated: `51487` - // Minimum execution time: 45_830_000 picoseconds. - Weight::from_parts(46_667_676, 51487) - // Standard Error: 130 - .saturating_add(Weight::from_parts(33_007, 0).saturating_mul(l.into())) + // Minimum execution time: 50_843_000 picoseconds. + Weight::from_parts(54_237_365, 51487) + // Standard Error: 243 + .saturating_add(Weight::from_parts(67_732, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Nis::Summary` (r:1 w:0) - /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Nis Summary (r:1 w:0) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn fund_deficit() -> Weight { // Proof Size summary in bytes: // Measured: `191` // Estimated: `3593` - // Minimum execution time: 30_440_000 picoseconds. - Weight::from_parts(31_240_000, 3593) + // Minimum execution time: 40_752_000 picoseconds. + Weight::from_parts(41_899_000, 3593) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Nis::Receipts` (r:1 w:1) - /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Nis::Summary` (r:1 w:1) - /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: Nis Receipts (r:1 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(85), added: 2560, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) fn communify() -> Weight { // Proof Size summary in bytes: // Measured: `668` // Estimated: `3675` - // Minimum execution time: 71_017_000 picoseconds. - Weight::from_parts(72_504_000, 3675) + // Minimum execution time: 79_779_000 picoseconds. + Weight::from_parts(82_478_000, 3675) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } - /// Storage: `Nis::Receipts` (r:1 w:1) - /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) - /// Storage: `Nis::Summary` (r:1 w:1) - /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Storage: Nis Receipts (r:1 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(85), added: 2560, mode: MaxEncodedLen) fn privatize() -> Weight { // Proof Size summary in bytes: // Measured: `829` // Estimated: `3675` - // Minimum execution time: 89_138_000 picoseconds. - Weight::from_parts(91_290_000, 3675) + // Minimum execution time: 99_588_000 picoseconds. + Weight::from_parts(102_340_000, 3675) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } - /// Storage: `Nis::Receipts` (r:1 w:1) - /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) - /// Storage: `Nis::Summary` (r:1 w:1) - /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:0) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Storage: Nis Receipts (r:1 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(85), added: 2560, mode: MaxEncodedLen) fn thaw_private() -> Weight { // Proof Size summary in bytes: // Measured: `354` - // Estimated: `3658` - // Minimum execution time: 47_917_000 picoseconds. - Weight::from_parts(49_121_000, 3658) + // Estimated: `3593` + // Minimum execution time: 53_094_000 picoseconds. + Weight::from_parts(54_543_000, 3593) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Nis::Receipts` (r:1 w:1) - /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) - /// Storage: `Nis::Summary` (r:1 w:1) - /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Nis Receipts (r:1 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn thaw_communal() -> Weight { // Proof Size summary in bytes: // Measured: `773` // Estimated: `3675` - // Minimum execution time: 91_320_000 picoseconds. - Weight::from_parts(93_080_000, 3675) + // Minimum execution time: 107_248_000 picoseconds. + Weight::from_parts(109_923_000, 3675) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: `Nis::Summary` (r:1 w:1) - /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:0) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Nis::QueueTotals` (r:1 w:1) - /// Proof: `Nis::QueueTotals` (`max_values`: Some(1), `max_size`: Some(6002), added: 6497, mode: `MaxEncodedLen`) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Nis QueueTotals (r:1 w:1) + /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) fn process_queues() -> Weight { // Proof Size summary in bytes: // Measured: `6624` // Estimated: `7487` - // Minimum execution time: 20_117_000 picoseconds. - Weight::from_parts(20_829_000, 7487) + // Minimum execution time: 27_169_000 picoseconds. + Weight::from_parts(29_201_000, 7487) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Nis::Queues` (r:1 w:1) - /// Proof: `Nis::Queues` (`max_values`: None, `max_size`: Some(48022), added: 50497, mode: `MaxEncodedLen`) + /// Storage: Nis Queues (r:1 w:1) + /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) fn process_queue() -> Weight { // Proof Size summary in bytes: // Measured: `42` // Estimated: `51487` - // Minimum execution time: 4_460_000 picoseconds. - Weight::from_parts(4_797_000, 51487) + // Minimum execution time: 4_540_000 picoseconds. + Weight::from_parts(4_699_000, 51487) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Nis::Receipts` (r:0 w:1) - /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Storage: Nis Receipts (r:0 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) fn process_bid() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_609_000 picoseconds. - Weight::from_parts(4_834_000, 0) + // Minimum execution time: 7_085_000 picoseconds. + Weight::from_parts(7_336_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Nis::Queues` (r:1 w:1) - /// Proof: `Nis::Queues` (`max_values`: None, `max_size`: Some(48022), added: 50497, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) - /// Storage: `Nis::QueueTotals` (r:1 w:1) - /// Proof: `Nis::QueueTotals` (`max_values`: Some(1), `max_size`: Some(6002), added: 6497, mode: `MaxEncodedLen`) + /// Storage: Nis Queues (r:1 w:1) + /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(85), added: 2560, mode: MaxEncodedLen) + /// Storage: Nis QueueTotals (r:1 w:1) + /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) /// The range of component `l` is `[0, 999]`. fn place_bid(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `6176 + l * (48 ±0)` // Estimated: `51487` - // Minimum execution time: 47_908_000 picoseconds. - Weight::from_parts(50_096_676, 51487) - // Standard Error: 208 - .saturating_add(Weight::from_parts(41_318, 0).saturating_mul(l.into())) + // Minimum execution time: 49_410_000 picoseconds. + Weight::from_parts(57_832_282, 51487) + // Standard Error: 288 + .saturating_add(Weight::from_parts(51_621, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Nis::Queues` (r:1 w:1) - /// Proof: `Nis::Queues` (`max_values`: None, `max_size`: Some(48022), added: 50497, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) - /// Storage: `Nis::QueueTotals` (r:1 w:1) - /// Proof: `Nis::QueueTotals` (`max_values`: Some(1), `max_size`: Some(6002), added: 6497, mode: `MaxEncodedLen`) + /// Storage: Nis Queues (r:1 w:1) + /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(85), added: 2560, mode: MaxEncodedLen) + /// Storage: Nis QueueTotals (r:1 w:1) + /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) fn place_bid_max() -> Weight { // Proof Size summary in bytes: // Measured: `54178` // Estimated: `51487` - // Minimum execution time: 100_836_000 picoseconds. - Weight::from_parts(102_497_000, 51487) + // Minimum execution time: 119_696_000 picoseconds. + Weight::from_parts(121_838_000, 51487) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Nis::Queues` (r:1 w:1) - /// Proof: `Nis::Queues` (`max_values`: None, `max_size`: Some(48022), added: 50497, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) - /// Storage: `Nis::QueueTotals` (r:1 w:1) - /// Proof: `Nis::QueueTotals` (`max_values`: Some(1), `max_size`: Some(6002), added: 6497, mode: `MaxEncodedLen`) + /// Storage: Nis Queues (r:1 w:1) + /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(85), added: 2560, mode: MaxEncodedLen) + /// Storage: Nis QueueTotals (r:1 w:1) + /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) /// The range of component `l` is `[1, 1000]`. fn retract_bid(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `6176 + l * (48 ±0)` // Estimated: `51487` - // Minimum execution time: 45_830_000 picoseconds. - Weight::from_parts(46_667_676, 51487) - // Standard Error: 130 - .saturating_add(Weight::from_parts(33_007, 0).saturating_mul(l.into())) + // Minimum execution time: 50_843_000 picoseconds. + Weight::from_parts(54_237_365, 51487) + // Standard Error: 243 + .saturating_add(Weight::from_parts(67_732, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Nis::Summary` (r:1 w:0) - /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Nis Summary (r:1 w:0) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn fund_deficit() -> Weight { // Proof Size summary in bytes: // Measured: `191` // Estimated: `3593` - // Minimum execution time: 30_440_000 picoseconds. - Weight::from_parts(31_240_000, 3593) + // Minimum execution time: 40_752_000 picoseconds. + Weight::from_parts(41_899_000, 3593) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Nis::Receipts` (r:1 w:1) - /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Nis::Summary` (r:1 w:1) - /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: Nis Receipts (r:1 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(85), added: 2560, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) fn communify() -> Weight { // Proof Size summary in bytes: // Measured: `668` // Estimated: `3675` - // Minimum execution time: 71_017_000 picoseconds. - Weight::from_parts(72_504_000, 3675) + // Minimum execution time: 79_779_000 picoseconds. + Weight::from_parts(82_478_000, 3675) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } - /// Storage: `Nis::Receipts` (r:1 w:1) - /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) - /// Storage: `Nis::Summary` (r:1 w:1) - /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Storage: Nis Receipts (r:1 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(85), added: 2560, mode: MaxEncodedLen) fn privatize() -> Weight { // Proof Size summary in bytes: // Measured: `829` // Estimated: `3675` - // Minimum execution time: 89_138_000 picoseconds. - Weight::from_parts(91_290_000, 3675) + // Minimum execution time: 99_588_000 picoseconds. + Weight::from_parts(102_340_000, 3675) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } - /// Storage: `Nis::Receipts` (r:1 w:1) - /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) - /// Storage: `Nis::Summary` (r:1 w:1) - /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:0) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Storage: Nis Receipts (r:1 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Holds (r:1 w:1) + /// Proof: Balances Holds (max_values: None, max_size: Some(85), added: 2560, mode: MaxEncodedLen) fn thaw_private() -> Weight { // Proof Size summary in bytes: // Measured: `354` - // Estimated: `3658` - // Minimum execution time: 47_917_000 picoseconds. - Weight::from_parts(49_121_000, 3658) + // Estimated: `3593` + // Minimum execution time: 53_094_000 picoseconds. + Weight::from_parts(54_543_000, 3593) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Nis::Receipts` (r:1 w:1) - /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) - /// Storage: `Nis::Summary` (r:1 w:1) - /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Nis Receipts (r:1 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:1 w:1) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn thaw_communal() -> Weight { // Proof Size summary in bytes: // Measured: `773` // Estimated: `3675` - // Minimum execution time: 91_320_000 picoseconds. - Weight::from_parts(93_080_000, 3675) + // Minimum execution time: 107_248_000 picoseconds. + Weight::from_parts(109_923_000, 3675) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: `Nis::Summary` (r:1 w:1) - /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:0) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Nis::QueueTotals` (r:1 w:1) - /// Proof: `Nis::QueueTotals` (`max_values`: Some(1), `max_size`: Some(6002), added: 6497, mode: `MaxEncodedLen`) + /// Storage: Nis Summary (r:1 w:1) + /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Nis QueueTotals (r:1 w:1) + /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) fn process_queues() -> Weight { // Proof Size summary in bytes: // Measured: `6624` // Estimated: `7487` - // Minimum execution time: 20_117_000 picoseconds. - Weight::from_parts(20_829_000, 7487) + // Minimum execution time: 27_169_000 picoseconds. + Weight::from_parts(29_201_000, 7487) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Nis::Queues` (r:1 w:1) - /// Proof: `Nis::Queues` (`max_values`: None, `max_size`: Some(48022), added: 50497, mode: `MaxEncodedLen`) + /// Storage: Nis Queues (r:1 w:1) + /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) fn process_queue() -> Weight { // Proof Size summary in bytes: // Measured: `42` // Estimated: `51487` - // Minimum execution time: 4_460_000 picoseconds. - Weight::from_parts(4_797_000, 51487) + // Minimum execution time: 4_540_000 picoseconds. + Weight::from_parts(4_699_000, 51487) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Nis::Receipts` (r:0 w:1) - /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Storage: Nis Receipts (r:0 w:1) + /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) fn process_bid() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_609_000 picoseconds. - Weight::from_parts(4_834_000, 0) + // Minimum execution time: 7_085_000 picoseconds. + Weight::from_parts(7_336_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/substrate/frame/nomination-pools/src/weights.rs b/substrate/frame/nomination-pools/src/weights.rs index 987ddd71703..0b8c1d22fa1 100644 --- a/substrate/frame/nomination-pools/src/weights.rs +++ b/substrate/frame/nomination-pools/src/weights.rs @@ -25,6 +25,7 @@ // Executed Command: // target/production/substrate-node +// target/production/substrate-node // benchmark // pallet // --steps=50 @@ -35,8 +36,12 @@ // --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json // --pallet=pallet_nomination_pools // --chain=dev +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_nomination_pools +// --chain=dev // --header=./substrate/HEADER-APACHE2 // --output=./substrate/frame/nomination-pools/src/weights.rs +// --output=./substrate/frame/nomination-pools/src/weights.rs // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -259,14 +264,12 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:0) - /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// Storage: `NominationPools::TotalValueLocked` (r:1 w:1) /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1848` + // Measured: `1817` // Estimated: `4764` // Minimum execution time: 64_787_000 picoseconds. Weight::from_parts(67_920_914, 4764) @@ -293,8 +296,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:0) - /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// Storage: `NominationPools::TotalValueLocked` (r:1 w:1) /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) @@ -304,7 +305,7 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2238` + // Measured: `2207` // Estimated: `27847` // Minimum execution time: 124_990_000 picoseconds. Weight::from_parts(129_041_398, 27847) @@ -337,12 +338,12 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:0) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) - /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:1) - /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// Storage: `NominationPools::TotalValueLocked` (r:1 w:1) /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) /// Proof: `NominationPools::CounterForPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:1) + /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// Storage: `NominationPools::CounterForReversePoolIdLookup` (r:1 w:1) /// Proof: `NominationPools::CounterForReversePoolIdLookup` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `NominationPools::RewardPools` (r:1 w:1) @@ -849,14 +850,12 @@ impl WeightInfo for () { /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:0) - /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// Storage: `NominationPools::TotalValueLocked` (r:1 w:1) /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn pool_withdraw_unbonded(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1848` + // Measured: `1817` // Estimated: `4764` // Minimum execution time: 64_787_000 picoseconds. Weight::from_parts(67_920_914, 4764) @@ -883,8 +882,6 @@ impl WeightInfo for () { /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:0) - /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// Storage: `NominationPools::TotalValueLocked` (r:1 w:1) /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) @@ -894,7 +891,7 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2238` + // Measured: `2207` // Estimated: `27847` // Minimum execution time: 124_990_000 picoseconds. Weight::from_parts(129_041_398, 27847) @@ -927,12 +924,12 @@ impl WeightInfo for () { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:0) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) - /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:1) - /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// Storage: `NominationPools::TotalValueLocked` (r:1 w:1) /// Proof: `NominationPools::TotalValueLocked` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `NominationPools::CounterForPoolMembers` (r:1 w:1) /// Proof: `NominationPools::CounterForPoolMembers` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:1) + /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// Storage: `NominationPools::CounterForReversePoolIdLookup` (r:1 w:1) /// Proof: `NominationPools::CounterForReversePoolIdLookup` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `NominationPools::RewardPools` (r:1 w:1) diff --git a/substrate/frame/offences/benchmarking/src/mock.rs b/substrate/frame/offences/benchmarking/src/mock.rs index b3260f0841f..01ad8d64f10 100644 --- a/substrate/frame/offences/benchmarking/src/mock.rs +++ b/substrate/frame/offences/benchmarking/src/mock.rs @@ -148,7 +148,7 @@ parameter_types! { pub static ElectionsBounds: ElectionBounds = ElectionBoundsBuilder::default().build(); } -pub type Extrinsic = sp_runtime::generic::UncheckedExtrinsic; +pub type Extrinsic = sp_runtime::testing::TestXt; pub struct OnChainSeqPhragmen; impl onchain::Config for OnChainSeqPhragmen { diff --git a/substrate/frame/parameters/src/weights.rs b/substrate/frame/parameters/src/weights.rs index 340eb9e31b7..6746960b1b7 100644 --- a/substrate/frame/parameters/src/weights.rs +++ b/substrate/frame/parameters/src/weights.rs @@ -18,27 +18,25 @@ //! Autogenerated weights for `pallet_parameters` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-02-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/production/substrate-node +// target/production/substrate-node // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_parameters -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/parameters/src/weights.rs +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_parameters +// --chain=dev // --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/parameters/src/weights.rs // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -57,30 +55,22 @@ pub trait WeightInfo { /// Weights for `pallet_parameters` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Parameters::Parameters` (r:1 w:1) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) fn set_parameter() -> Weight { // Proof Size summary in bytes: - // Measured: `3` - // Estimated: `3501` - // Minimum execution time: 8_400_000 picoseconds. - Weight::from_parts(8_682_000, 3501) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(0, 0) } } // For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: `Parameters::Parameters` (r:1 w:1) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) fn set_parameter() -> Weight { // Proof Size summary in bytes: - // Measured: `3` - // Estimated: `3501` - // Minimum execution time: 8_400_000 picoseconds. - Weight::from_parts(8_682_000, 3501) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(0, 0) } } diff --git a/substrate/frame/preimage/src/weights.rs b/substrate/frame/preimage/src/weights.rs index 6167cd53029..c11ab74c1e5 100644 --- a/substrate/frame/preimage/src/weights.rs +++ b/substrate/frame/preimage/src/weights.rs @@ -17,28 +17,26 @@ //! Autogenerated weights for `pallet_preimage` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-mia4uyug-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/production/substrate-node +// target/production/substrate-node // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_preimage -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/preimage/src/weights.rs +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_preimage +// --chain=dev // --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/preimage/src/weights.rs // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -72,209 +70,200 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Parameters::Parameters` (r:2 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) /// Storage: `Preimage::PreimageFor` (r:0 w:1) /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 4194304]`. fn note_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `112` - // Estimated: `6012` - // Minimum execution time: 48_893_000 picoseconds. - Weight::from_parts(44_072_327, 6012) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_684, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + // Measured: `42` + // Estimated: `3556` + // Minimum execution time: 15_936_000 picoseconds. + Weight::from_parts(16_271_000, 3556) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_916, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) /// Storage: `Preimage::PreimageFor` (r:0 w:1) /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 4194304]`. fn note_requested_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `173` + // Measured: `106` // Estimated: `3556` - // Minimum execution time: 15_675_000 picoseconds. - Weight::from_parts(4_564_145, 3556) + // Minimum execution time: 16_468_000 picoseconds. + Weight::from_parts(17_031_000, 3556) // Standard Error: 2 - .saturating_add(Weight::from_parts(1_678, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_948, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) /// Storage: `Preimage::PreimageFor` (r:0 w:1) /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 4194304]`. fn note_no_deposit_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `173` + // Measured: `106` // Estimated: `3556` - // Minimum execution time: 14_959_000 picoseconds. - Weight::from_parts(15_335_000, 3556) + // Minimum execution time: 16_342_000 picoseconds. + Weight::from_parts(16_535_000, 3556) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_687, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_906, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) /// Storage: `Preimage::PreimageFor` (r:0 w:1) /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) fn unnote_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `311` - // Estimated: `3658` - // Minimum execution time: 47_378_000 picoseconds. - Weight::from_parts(48_776_000, 3658) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + // Measured: `172` + // Estimated: `3556` + // Minimum execution time: 31_047_000 picoseconds. + Weight::from_parts(34_099_000, 3556) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) /// Storage: `Preimage::PreimageFor` (r:0 w:1) /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) fn unnote_no_deposit_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `211` + // Measured: `144` // Estimated: `3556` - // Minimum execution time: 20_939_000 picoseconds. - Weight::from_parts(21_577_000, 3556) + // Minimum execution time: 32_559_000 picoseconds. + Weight::from_parts(36_677_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) fn request_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `255` + // Measured: `172` // Estimated: `3556` - // Minimum execution time: 17_945_000 picoseconds. - Weight::from_parts(18_448_000, 3556) + // Minimum execution time: 27_887_000 picoseconds. + Weight::from_parts(30_303_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) fn request_no_deposit_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `211` + // Measured: `144` // Estimated: `3556` - // Minimum execution time: 12_132_000 picoseconds. - Weight::from_parts(12_710_000, 3556) + // Minimum execution time: 17_256_000 picoseconds. + Weight::from_parts(19_481_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) fn request_unnoted_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `109` + // Measured: `42` // Estimated: `3556` - // Minimum execution time: 13_014_000 picoseconds. - Weight::from_parts(13_726_000, 3556) + // Minimum execution time: 22_344_000 picoseconds. + Weight::from_parts(23_868_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) fn request_requested_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `173` + // Measured: `106` // Estimated: `3556` - // Minimum execution time: 9_785_000 picoseconds. - Weight::from_parts(10_266_000, 3556) + // Minimum execution time: 10_542_000 picoseconds. + Weight::from_parts(11_571_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) /// Storage: `Preimage::PreimageFor` (r:0 w:1) /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) fn unrequest_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `211` + // Measured: `144` // Estimated: `3556` - // Minimum execution time: 18_764_000 picoseconds. - Weight::from_parts(19_635_000, 3556) + // Minimum execution time: 29_054_000 picoseconds. + Weight::from_parts(32_996_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) fn unrequest_unnoted_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `173` + // Measured: `106` // Estimated: `3556` - // Minimum execution time: 9_624_000 picoseconds. - Weight::from_parts(10_044_000, 3556) + // Minimum execution time: 10_775_000 picoseconds. + Weight::from_parts(11_937_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) fn unrequest_multi_referenced_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `173` + // Measured: `106` // Estimated: `3556` - // Minimum execution time: 9_432_000 picoseconds. - Weight::from_parts(9_991_000, 3556) + // Minimum execution time: 10_696_000 picoseconds. + Weight::from_parts(11_717_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Preimage::StatusFor` (r:1023 w:1023) + /// Storage: `Preimage::StatusFor` (r:1024 w:1024) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1023 w:1023) + /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Parameters::Parameters` (r:2 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1023 w:1023) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:0 w:1023) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// The range of component `n` is `[1, 1024]`. + /// Storage: `Preimage::RequestStatusFor` (r:0 w:1024) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 1024]`. fn ensure_updated(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + n * (227 ±0)` - // Estimated: `6012 + n * (2668 ±0)` - // Minimum execution time: 54_056_000 picoseconds. - Weight::from_parts(54_912_000, 6012) - // Standard Error: 42_469 - .saturating_add(Weight::from_parts(50_710_258, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes((4_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2668).saturating_mul(n.into())) + // Measured: `193 + n * (91 ±0)` + // Estimated: `3593 + n * (2566 ±0)` + // Minimum execution time: 2_452_000 picoseconds. + Weight::from_parts(2_641_000, 3593) + // Standard Error: 19_797 + .saturating_add(Weight::from_parts(15_620_946, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2566).saturating_mul(n.into())) } } @@ -283,208 +272,199 @@ impl WeightInfo for () { /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Parameters::Parameters` (r:2 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) /// Storage: `Preimage::PreimageFor` (r:0 w:1) /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 4194304]`. fn note_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `112` - // Estimated: `6012` - // Minimum execution time: 48_893_000 picoseconds. - Weight::from_parts(44_072_327, 6012) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_684, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + // Measured: `42` + // Estimated: `3556` + // Minimum execution time: 15_936_000 picoseconds. + Weight::from_parts(16_271_000, 3556) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_916, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) /// Storage: `Preimage::PreimageFor` (r:0 w:1) /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 4194304]`. fn note_requested_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `173` + // Measured: `106` // Estimated: `3556` - // Minimum execution time: 15_675_000 picoseconds. - Weight::from_parts(4_564_145, 3556) + // Minimum execution time: 16_468_000 picoseconds. + Weight::from_parts(17_031_000, 3556) // Standard Error: 2 - .saturating_add(Weight::from_parts(1_678, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_948, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) /// Storage: `Preimage::PreimageFor` (r:0 w:1) /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 4194304]`. fn note_no_deposit_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `173` + // Measured: `106` // Estimated: `3556` - // Minimum execution time: 14_959_000 picoseconds. - Weight::from_parts(15_335_000, 3556) + // Minimum execution time: 16_342_000 picoseconds. + Weight::from_parts(16_535_000, 3556) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_687, 0).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(1_906, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) /// Storage: `Preimage::PreimageFor` (r:0 w:1) /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) fn unnote_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `311` - // Estimated: `3658` - // Minimum execution time: 47_378_000 picoseconds. - Weight::from_parts(48_776_000, 3658) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + // Measured: `172` + // Estimated: `3556` + // Minimum execution time: 31_047_000 picoseconds. + Weight::from_parts(34_099_000, 3556) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) /// Storage: `Preimage::PreimageFor` (r:0 w:1) /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) fn unnote_no_deposit_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `211` + // Measured: `144` // Estimated: `3556` - // Minimum execution time: 20_939_000 picoseconds. - Weight::from_parts(21_577_000, 3556) + // Minimum execution time: 32_559_000 picoseconds. + Weight::from_parts(36_677_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) fn request_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `255` + // Measured: `172` // Estimated: `3556` - // Minimum execution time: 17_945_000 picoseconds. - Weight::from_parts(18_448_000, 3556) + // Minimum execution time: 27_887_000 picoseconds. + Weight::from_parts(30_303_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) fn request_no_deposit_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `211` + // Measured: `144` // Estimated: `3556` - // Minimum execution time: 12_132_000 picoseconds. - Weight::from_parts(12_710_000, 3556) + // Minimum execution time: 17_256_000 picoseconds. + Weight::from_parts(19_481_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) fn request_unnoted_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `109` + // Measured: `42` // Estimated: `3556` - // Minimum execution time: 13_014_000 picoseconds. - Weight::from_parts(13_726_000, 3556) + // Minimum execution time: 22_344_000 picoseconds. + Weight::from_parts(23_868_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) fn request_requested_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `173` + // Measured: `106` // Estimated: `3556` - // Minimum execution time: 9_785_000 picoseconds. - Weight::from_parts(10_266_000, 3556) + // Minimum execution time: 10_542_000 picoseconds. + Weight::from_parts(11_571_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) /// Storage: `Preimage::PreimageFor` (r:0 w:1) /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) fn unrequest_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `211` + // Measured: `144` // Estimated: `3556` - // Minimum execution time: 18_764_000 picoseconds. - Weight::from_parts(19_635_000, 3556) + // Minimum execution time: 29_054_000 picoseconds. + Weight::from_parts(32_996_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) fn unrequest_unnoted_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `173` + // Measured: `106` // Estimated: `3556` - // Minimum execution time: 9_624_000 picoseconds. - Weight::from_parts(10_044_000, 3556) + // Minimum execution time: 10_775_000 picoseconds. + Weight::from_parts(11_937_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) fn unrequest_multi_referenced_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `173` + // Measured: `106` // Estimated: `3556` - // Minimum execution time: 9_432_000 picoseconds. - Weight::from_parts(9_991_000, 3556) + // Minimum execution time: 10_696_000 picoseconds. + Weight::from_parts(11_717_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Preimage::StatusFor` (r:1023 w:1023) + /// Storage: `Preimage::StatusFor` (r:1024 w:1024) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1023 w:1023) + /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Parameters::Parameters` (r:2 w:0) - /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1023 w:1023) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:0 w:1023) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// The range of component `n` is `[1, 1024]`. + /// Storage: `Preimage::RequestStatusFor` (r:0 w:1024) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(75), added: 2550, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 1024]`. fn ensure_updated(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + n * (227 ±0)` - // Estimated: `6012 + n * (2668 ±0)` - // Minimum execution time: 54_056_000 picoseconds. - Weight::from_parts(54_912_000, 6012) - // Standard Error: 42_469 - .saturating_add(Weight::from_parts(50_710_258, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes((4_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2668).saturating_mul(n.into())) + // Measured: `193 + n * (91 ±0)` + // Estimated: `3593 + n * (2566 ±0)` + // Minimum execution time: 2_452_000 picoseconds. + Weight::from_parts(2_641_000, 3593) + // Standard Error: 19_797 + .saturating_add(Weight::from_parts(15_620_946, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2566).saturating_mul(n.into())) } } diff --git a/substrate/frame/proxy/src/weights.rs b/substrate/frame/proxy/src/weights.rs index 3c37c91d500..f30fe73d27a 100644 --- a/substrate/frame/proxy/src/weights.rs +++ b/substrate/frame/proxy/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_proxy` +//! Autogenerated weights for pallet_proxy //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/proxy/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/proxy/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_proxy`. +/// Weight functions needed for pallet_proxy. pub trait WeightInfo { fn proxy(p: u32, ) -> Weight; fn proxy_announced(a: u32, p: u32, ) -> Weight; @@ -63,352 +64,336 @@ pub trait WeightInfo { fn kill_pure(p: u32, ) -> Weight; } -/// Weights for `pallet_proxy` using the Substrate node and recommended hardware. +/// Weights for pallet_proxy using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Proxy::Proxies` (r:1 w:0) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) + /// Storage: Proxy Proxies (r:1 w:0) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `306 + p * (37 ±0)` + // Measured: `161 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 18_437_000 picoseconds. - Weight::from_parts(19_610_577, 4706) - // Standard Error: 2_531 - .saturating_add(Weight::from_parts(26_001, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Minimum execution time: 15_182_000 picoseconds. + Weight::from_parts(15_919_146, 4706) + // Standard Error: 1_586 + .saturating_add(Weight::from_parts(31_768, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) } - /// Storage: `Proxy::Proxies` (r:1 w:0) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) - /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) + /// Storage: Proxy Proxies (r:1 w:0) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn proxy_announced(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `633 + a * (68 ±0) + p * (37 ±0)` + // Measured: `488 + a * (68 ±0) + p * (37 ±0)` // Estimated: `5698` - // Minimum execution time: 40_426_000 picoseconds. - Weight::from_parts(40_200_295, 5698) - // Standard Error: 2_922 - .saturating_add(Weight::from_parts(161_885, 0).saturating_mul(a.into())) - // Standard Error: 3_019 - .saturating_add(Weight::from_parts(69_710, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(5_u64)) + // Minimum execution time: 40_256_000 picoseconds. + Weight::from_parts(40_373_648, 5698) + // Standard Error: 3_978 + .saturating_add(Weight::from_parts(166_936, 0).saturating_mul(a.into())) + // Standard Error: 4_110 + .saturating_add(Weight::from_parts(54_329, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn remove_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `403 + a * (68 ±0)` // Estimated: `5698` - // Minimum execution time: 21_905_000 picoseconds. - Weight::from_parts(22_717_430, 5698) - // Standard Error: 2_004 - .saturating_add(Weight::from_parts(153_390, 0).saturating_mul(a.into())) - // Standard Error: 2_071 - .saturating_add(Weight::from_parts(5_676, 0).saturating_mul(p.into())) + // Minimum execution time: 25_040_000 picoseconds. + Weight::from_parts(25_112_188, 5698) + // Standard Error: 2_143 + .saturating_add(Weight::from_parts(189_027, 0).saturating_mul(a.into())) + // Standard Error: 2_214 + .saturating_add(Weight::from_parts(26_683, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn reject_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `403 + a * (68 ±0)` // Estimated: `5698` - // Minimum execution time: 21_974_000 picoseconds. - Weight::from_parts(22_484_324, 5698) - // Standard Error: 1_846 - .saturating_add(Weight::from_parts(153_904, 0).saturating_mul(a.into())) - // Standard Error: 1_907 - .saturating_add(Weight::from_parts(9_616, 0).saturating_mul(p.into())) + // Minimum execution time: 24_884_000 picoseconds. + Weight::from_parts(25_359_291, 5698) + // Standard Error: 2_019 + .saturating_add(Weight::from_parts(181_470, 0).saturating_mul(a.into())) + // Standard Error: 2_086 + .saturating_add(Weight::from_parts(17_725, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Proxy::Proxies` (r:1 w:0) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) - /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Proxy Proxies (r:1 w:0) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn announce(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `420 + a * (68 ±0) + p * (37 ±0)` // Estimated: `5698` - // Minimum execution time: 30_454_000 picoseconds. - Weight::from_parts(32_128_158, 5698) - // Standard Error: 3_778 - .saturating_add(Weight::from_parts(137_366, 0).saturating_mul(a.into())) - // Standard Error: 3_904 - .saturating_add(Weight::from_parts(53_040, 0).saturating_mul(p.into())) + // Minimum execution time: 35_039_000 picoseconds. + Weight::from_parts(36_727_868, 5698) + // Standard Error: 4_463 + .saturating_add(Weight::from_parts(167_060, 0).saturating_mul(a.into())) + // Standard Error: 4_611 + .saturating_add(Weight::from_parts(59_836, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn add_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `161 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 21_391_000 picoseconds. - Weight::from_parts(22_202_614, 4706) - // Standard Error: 1_750 - .saturating_add(Weight::from_parts(49_639, 0).saturating_mul(p.into())) + // Minimum execution time: 25_697_000 picoseconds. + Weight::from_parts(26_611_090, 4706) + // Standard Error: 2_306 + .saturating_add(Weight::from_parts(85_165, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn remove_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `161 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 21_375_000 picoseconds. - Weight::from_parts(22_392_601, 4706) - // Standard Error: 2_415 - .saturating_add(Weight::from_parts(40_345, 0).saturating_mul(p.into())) + // Minimum execution time: 25_638_000 picoseconds. + Weight::from_parts(26_904_510, 4706) + // Standard Error: 2_669 + .saturating_add(Weight::from_parts(61_668, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn remove_proxies(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `161 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 19_833_000 picoseconds. - Weight::from_parts(20_839_747, 4706) - // Standard Error: 1_742 - .saturating_add(Weight::from_parts(40_874, 0).saturating_mul(p.into())) + // Minimum execution time: 22_737_000 picoseconds. + Weight::from_parts(23_618_441, 4706) + // Standard Error: 1_729 + .saturating_add(Weight::from_parts(44_009, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn create_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `173` // Estimated: `4706` - // Minimum execution time: 22_231_000 picoseconds. - Weight::from_parts(23_370_995, 4706) - // Standard Error: 1_521 - .saturating_add(Weight::from_parts(4_892, 0).saturating_mul(p.into())) + // Minimum execution time: 27_364_000 picoseconds. + Weight::from_parts(28_632_271, 4706) + // Standard Error: 1_613 + .saturating_add(Weight::from_parts(2_453, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[0, 30]`. fn kill_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `198 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 20_614_000 picoseconds. - Weight::from_parts(21_845_970, 4706) - // Standard Error: 1_636 - .saturating_add(Weight::from_parts(34_480, 0).saturating_mul(p.into())) + // Minimum execution time: 23_552_000 picoseconds. + Weight::from_parts(24_874_553, 4706) + // Standard Error: 1_919 + .saturating_add(Weight::from_parts(38_799, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Proxy::Proxies` (r:1 w:0) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) + /// Storage: Proxy Proxies (r:1 w:0) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `306 + p * (37 ±0)` + // Measured: `161 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 18_437_000 picoseconds. - Weight::from_parts(19_610_577, 4706) - // Standard Error: 2_531 - .saturating_add(Weight::from_parts(26_001, 0).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Minimum execution time: 15_182_000 picoseconds. + Weight::from_parts(15_919_146, 4706) + // Standard Error: 1_586 + .saturating_add(Weight::from_parts(31_768, 0).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) } - /// Storage: `Proxy::Proxies` (r:1 w:0) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) - /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) + /// Storage: Proxy Proxies (r:1 w:0) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn proxy_announced(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `633 + a * (68 ±0) + p * (37 ±0)` + // Measured: `488 + a * (68 ±0) + p * (37 ±0)` // Estimated: `5698` - // Minimum execution time: 40_426_000 picoseconds. - Weight::from_parts(40_200_295, 5698) - // Standard Error: 2_922 - .saturating_add(Weight::from_parts(161_885, 0).saturating_mul(a.into())) - // Standard Error: 3_019 - .saturating_add(Weight::from_parts(69_710, 0).saturating_mul(p.into())) - .saturating_add(RocksDbWeight::get().reads(5_u64)) + // Minimum execution time: 40_256_000 picoseconds. + Weight::from_parts(40_373_648, 5698) + // Standard Error: 3_978 + .saturating_add(Weight::from_parts(166_936, 0).saturating_mul(a.into())) + // Standard Error: 4_110 + .saturating_add(Weight::from_parts(54_329, 0).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn remove_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `403 + a * (68 ±0)` // Estimated: `5698` - // Minimum execution time: 21_905_000 picoseconds. - Weight::from_parts(22_717_430, 5698) - // Standard Error: 2_004 - .saturating_add(Weight::from_parts(153_390, 0).saturating_mul(a.into())) - // Standard Error: 2_071 - .saturating_add(Weight::from_parts(5_676, 0).saturating_mul(p.into())) + // Minimum execution time: 25_040_000 picoseconds. + Weight::from_parts(25_112_188, 5698) + // Standard Error: 2_143 + .saturating_add(Weight::from_parts(189_027, 0).saturating_mul(a.into())) + // Standard Error: 2_214 + .saturating_add(Weight::from_parts(26_683, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn reject_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `403 + a * (68 ±0)` // Estimated: `5698` - // Minimum execution time: 21_974_000 picoseconds. - Weight::from_parts(22_484_324, 5698) - // Standard Error: 1_846 - .saturating_add(Weight::from_parts(153_904, 0).saturating_mul(a.into())) - // Standard Error: 1_907 - .saturating_add(Weight::from_parts(9_616, 0).saturating_mul(p.into())) + // Minimum execution time: 24_884_000 picoseconds. + Weight::from_parts(25_359_291, 5698) + // Standard Error: 2_019 + .saturating_add(Weight::from_parts(181_470, 0).saturating_mul(a.into())) + // Standard Error: 2_086 + .saturating_add(Weight::from_parts(17_725, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Proxy::Proxies` (r:1 w:0) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) - /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Proxy Proxies (r:1 w:0) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: Proxy Announcements (r:1 w:1) + /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn announce(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `420 + a * (68 ±0) + p * (37 ±0)` // Estimated: `5698` - // Minimum execution time: 30_454_000 picoseconds. - Weight::from_parts(32_128_158, 5698) - // Standard Error: 3_778 - .saturating_add(Weight::from_parts(137_366, 0).saturating_mul(a.into())) - // Standard Error: 3_904 - .saturating_add(Weight::from_parts(53_040, 0).saturating_mul(p.into())) + // Minimum execution time: 35_039_000 picoseconds. + Weight::from_parts(36_727_868, 5698) + // Standard Error: 4_463 + .saturating_add(Weight::from_parts(167_060, 0).saturating_mul(a.into())) + // Standard Error: 4_611 + .saturating_add(Weight::from_parts(59_836, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn add_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `161 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 21_391_000 picoseconds. - Weight::from_parts(22_202_614, 4706) - // Standard Error: 1_750 - .saturating_add(Weight::from_parts(49_639, 0).saturating_mul(p.into())) + // Minimum execution time: 25_697_000 picoseconds. + Weight::from_parts(26_611_090, 4706) + // Standard Error: 2_306 + .saturating_add(Weight::from_parts(85_165, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn remove_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `161 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 21_375_000 picoseconds. - Weight::from_parts(22_392_601, 4706) - // Standard Error: 2_415 - .saturating_add(Weight::from_parts(40_345, 0).saturating_mul(p.into())) + // Minimum execution time: 25_638_000 picoseconds. + Weight::from_parts(26_904_510, 4706) + // Standard Error: 2_669 + .saturating_add(Weight::from_parts(61_668, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn remove_proxies(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `161 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 19_833_000 picoseconds. - Weight::from_parts(20_839_747, 4706) - // Standard Error: 1_742 - .saturating_add(Weight::from_parts(40_874, 0).saturating_mul(p.into())) + // Minimum execution time: 22_737_000 picoseconds. + Weight::from_parts(23_618_441, 4706) + // Standard Error: 1_729 + .saturating_add(Weight::from_parts(44_009, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[1, 31]`. fn create_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `173` // Estimated: `4706` - // Minimum execution time: 22_231_000 picoseconds. - Weight::from_parts(23_370_995, 4706) - // Standard Error: 1_521 - .saturating_add(Weight::from_parts(4_892, 0).saturating_mul(p.into())) + // Minimum execution time: 27_364_000 picoseconds. + Weight::from_parts(28_632_271, 4706) + // Standard Error: 1_613 + .saturating_add(Weight::from_parts(2_453, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: Proxy Proxies (r:1 w:1) + /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) /// The range of component `p` is `[0, 30]`. fn kill_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `198 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 20_614_000 picoseconds. - Weight::from_parts(21_845_970, 4706) - // Standard Error: 1_636 - .saturating_add(Weight::from_parts(34_480, 0).saturating_mul(p.into())) + // Minimum execution time: 23_552_000 picoseconds. + Weight::from_parts(24_874_553, 4706) + // Standard Error: 1_919 + .saturating_add(Weight::from_parts(38_799, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/ranked-collective/src/weights.rs b/substrate/frame/ranked-collective/src/weights.rs index 5721858f7e2..4ff0c3337d5 100644 --- a/substrate/frame/ranked-collective/src/weights.rs +++ b/substrate/frame/ranked-collective/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_ranked_collective` +//! Autogenerated weights for pallet_ranked_collective //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/ranked-collective/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/ranked-collective/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_ranked_collective`. +/// Weight functions needed for pallet_ranked_collective. pub trait WeightInfo { fn add_member() -> Weight; fn remove_member(r: u32, ) -> Weight; @@ -60,295 +61,283 @@ pub trait WeightInfo { fn exchange_member() -> Weight; } -/// Weights for `pallet_ranked_collective` using the Substrate node and recommended hardware. +/// Weights for pallet_ranked_collective using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `RankedCollective::Members` (r:1 w:1) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::MemberCount` (r:1 w:1) - /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IndexToId` (r:0 w:1) - /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IdToIndex` (r:0 w:1) - /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IndexToId (r:0 w:1) + /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:0 w:1) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) fn add_member() -> Weight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3507` - // Minimum execution time: 15_389_000 picoseconds. - Weight::from_parts(15_901_000, 3507) + // Minimum execution time: 17_245_000 picoseconds. + Weight::from_parts(17_930_000, 3507) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: `RankedCollective::Members` (r:1 w:1) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::MemberCount` (r:11 w:11) - /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IdToIndex` (r:11 w:22) - /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IndexToId` (r:11 w:22) - /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:11 w:11) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:11 w:11) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: RankedCollective IndexToId (r:11 w:11) + /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) /// The range of component `r` is `[0, 10]`. fn remove_member(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `616 + r * (281 ±0)` // Estimated: `3519 + r * (2529 ±0)` - // Minimum execution time: 29_541_000 picoseconds. - Weight::from_parts(32_239_358, 3519) - // Standard Error: 23_406 - .saturating_add(Weight::from_parts(16_030_191, 0).saturating_mul(r.into())) + // Minimum execution time: 29_534_000 picoseconds. + Weight::from_parts(32_847_495, 3519) + // Standard Error: 24_211 + .saturating_add(Weight::from_parts(13_949_639, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) - .saturating_add(T::DbWeight::get().writes(6_u64)) - .saturating_add(T::DbWeight::get().writes((5_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 2529).saturating_mul(r.into())) } - /// Storage: `RankedCollective::Members` (r:1 w:1) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::MemberCount` (r:1 w:1) - /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IndexToId` (r:0 w:1) - /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IdToIndex` (r:0 w:1) - /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IndexToId (r:0 w:1) + /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:0 w:1) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) /// The range of component `r` is `[0, 10]`. fn promote_member(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `314 + r * (17 ±0)` // Estimated: `3507` - // Minimum execution time: 17_939_000 picoseconds. - Weight::from_parts(19_290_416, 3507) - // Standard Error: 5_710 - .saturating_add(Weight::from_parts(374_399, 0).saturating_mul(r.into())) + // Minimum execution time: 20_333_000 picoseconds. + Weight::from_parts(21_592_224, 3507) + // Standard Error: 6_423 + .saturating_add(Weight::from_parts(321_314, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: `RankedCollective::Members` (r:1 w:1) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::MemberCount` (r:1 w:1) - /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IdToIndex` (r:1 w:2) - /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IndexToId` (r:1 w:2) - /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:1 w:1) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: RankedCollective IndexToId (r:1 w:1) + /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) /// The range of component `r` is `[0, 10]`. fn demote_member(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `632 + r * (72 ±0)` // Estimated: `3519` - // Minimum execution time: 29_609_000 picoseconds. - Weight::from_parts(32_686_167, 3519) - // Standard Error: 27_588 - .saturating_add(Weight::from_parts(789_212, 0).saturating_mul(r.into())) + // Minimum execution time: 29_446_000 picoseconds. + Weight::from_parts(32_447_715, 3519) + // Standard Error: 28_791 + .saturating_add(Weight::from_parts(822_890, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(6_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: `RankedCollective::Members` (r:1 w:0) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `RankedPolls::ReferendumInfoFor` (r:1 w:1) - /// Proof: `RankedPolls::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(330), added: 2805, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::Voting` (r:1 w:1) - /// Proof: `RankedCollective::Voting` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: RankedPolls ReferendumInfoFor (r:1 w:1) + /// Proof: RankedPolls ReferendumInfoFor (max_values: None, max_size: Some(330), added: 2805, mode: MaxEncodedLen) + /// Storage: RankedCollective Voting (r:1 w:1) + /// Proof: RankedCollective Voting (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn vote() -> Weight { // Proof Size summary in bytes: // Measured: `628` // Estimated: `219984` - // Minimum execution time: 41_151_000 picoseconds. - Weight::from_parts(42_435_000, 219984) + // Minimum execution time: 45_474_000 picoseconds. + Weight::from_parts(47_228_000, 219984) .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(5_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: `RankedPolls::ReferendumInfoFor` (r:1 w:0) - /// Proof: `RankedPolls::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(330), added: 2805, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::VotingCleanup` (r:1 w:0) - /// Proof: `RankedCollective::VotingCleanup` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::Voting` (r:100 w:100) - /// Proof: `RankedCollective::Voting` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: RankedPolls ReferendumInfoFor (r:1 w:0) + /// Proof: RankedPolls ReferendumInfoFor (max_values: None, max_size: Some(330), added: 2805, mode: MaxEncodedLen) + /// Storage: RankedCollective VotingCleanup (r:1 w:0) + /// Proof: RankedCollective VotingCleanup (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: RankedCollective Voting (r:100 w:100) + /// Proof: RankedCollective Voting (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) /// The range of component `n` is `[0, 100]`. fn cleanup_poll(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `462 + n * (50 ±0)` // Estimated: `3795 + n * (2540 ±0)` - // Minimum execution time: 13_563_000 picoseconds. - Weight::from_parts(17_495_215, 3795) - // Standard Error: 2_294 - .saturating_add(Weight::from_parts(1_207_393, 0).saturating_mul(n.into())) + // Minimum execution time: 13_903_000 picoseconds. + Weight::from_parts(18_209_102, 3795) + // Standard Error: 2_556 + .saturating_add(Weight::from_parts(1_237_454, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2540).saturating_mul(n.into())) } + /// Storage: `RankedCollective::Members` (r:2 w:2) /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) /// Storage: `RankedCollective::MemberCount` (r:2 w:2) /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IdToIndex` (r:2 w:4) + /// Storage: `RankedCollective::IdToIndex` (r:2 w:2) /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::Member` (r:2 w:2) - /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::MemberEvidence` (r:1 w:0) - /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) - /// Storage: `Salary::Claimant` (r:2 w:2) - /// Proof: `Salary::Claimant` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) /// Storage: `RankedCollective::IndexToId` (r:0 w:2) /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) fn exchange_member() -> Weight { // Proof Size summary in bytes: - // Measured: `625` - // Estimated: `19894` - // Minimum execution time: 70_713_000 picoseconds. - Weight::from_parts(72_831_000, 19894) - .saturating_add(T::DbWeight::get().reads(11_u64)) - .saturating_add(T::DbWeight::get().writes(14_u64)) + // Measured: `437` + // Estimated: `6048` + // Minimum execution time: 138_000_000 picoseconds. + Weight::from_parts(141_000_000, 0) + .saturating_add(Weight::from_parts(0, 6048)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(8)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `RankedCollective::Members` (r:1 w:1) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::MemberCount` (r:1 w:1) - /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IndexToId` (r:0 w:1) - /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IdToIndex` (r:0 w:1) - /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IndexToId (r:0 w:1) + /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:0 w:1) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) fn add_member() -> Weight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3507` - // Minimum execution time: 15_389_000 picoseconds. - Weight::from_parts(15_901_000, 3507) + // Minimum execution time: 17_245_000 picoseconds. + Weight::from_parts(17_930_000, 3507) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: `RankedCollective::Members` (r:1 w:1) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::MemberCount` (r:11 w:11) - /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IdToIndex` (r:11 w:22) - /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IndexToId` (r:11 w:22) - /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:11 w:11) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:11 w:11) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: RankedCollective IndexToId (r:11 w:11) + /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) /// The range of component `r` is `[0, 10]`. fn remove_member(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `616 + r * (281 ±0)` // Estimated: `3519 + r * (2529 ±0)` - // Minimum execution time: 29_541_000 picoseconds. - Weight::from_parts(32_239_358, 3519) - // Standard Error: 23_406 - .saturating_add(Weight::from_parts(16_030_191, 0).saturating_mul(r.into())) + // Minimum execution time: 29_534_000 picoseconds. + Weight::from_parts(32_847_495, 3519) + // Standard Error: 24_211 + .saturating_add(Weight::from_parts(13_949_639, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) - .saturating_add(RocksDbWeight::get().writes(6_u64)) - .saturating_add(RocksDbWeight::get().writes((5_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 2529).saturating_mul(r.into())) } - /// Storage: `RankedCollective::Members` (r:1 w:1) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::MemberCount` (r:1 w:1) - /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IndexToId` (r:0 w:1) - /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IdToIndex` (r:0 w:1) - /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IndexToId (r:0 w:1) + /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:0 w:1) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) /// The range of component `r` is `[0, 10]`. fn promote_member(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `314 + r * (17 ±0)` // Estimated: `3507` - // Minimum execution time: 17_939_000 picoseconds. - Weight::from_parts(19_290_416, 3507) - // Standard Error: 5_710 - .saturating_add(Weight::from_parts(374_399, 0).saturating_mul(r.into())) + // Minimum execution time: 20_333_000 picoseconds. + Weight::from_parts(21_592_224, 3507) + // Standard Error: 6_423 + .saturating_add(Weight::from_parts(321_314, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: `RankedCollective::Members` (r:1 w:1) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::MemberCount` (r:1 w:1) - /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IdToIndex` (r:1 w:2) - /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IndexToId` (r:1 w:2) - /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) + /// Storage: RankedCollective Members (r:1 w:1) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: RankedCollective MemberCount (r:1 w:1) + /// Proof: RankedCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: RankedCollective IdToIndex (r:1 w:1) + /// Proof: RankedCollective IdToIndex (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) + /// Storage: RankedCollective IndexToId (r:1 w:1) + /// Proof: RankedCollective IndexToId (max_values: None, max_size: Some(54), added: 2529, mode: MaxEncodedLen) /// The range of component `r` is `[0, 10]`. fn demote_member(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `632 + r * (72 ±0)` // Estimated: `3519` - // Minimum execution time: 29_609_000 picoseconds. - Weight::from_parts(32_686_167, 3519) - // Standard Error: 27_588 - .saturating_add(Weight::from_parts(789_212, 0).saturating_mul(r.into())) + // Minimum execution time: 29_446_000 picoseconds. + Weight::from_parts(32_447_715, 3519) + // Standard Error: 28_791 + .saturating_add(Weight::from_parts(822_890, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: `RankedCollective::Members` (r:1 w:0) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `RankedPolls::ReferendumInfoFor` (r:1 w:1) - /// Proof: `RankedPolls::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(330), added: 2805, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::Voting` (r:1 w:1) - /// Proof: `RankedCollective::Voting` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: RankedPolls ReferendumInfoFor (r:1 w:1) + /// Proof: RankedPolls ReferendumInfoFor (max_values: None, max_size: Some(330), added: 2805, mode: MaxEncodedLen) + /// Storage: RankedCollective Voting (r:1 w:1) + /// Proof: RankedCollective Voting (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn vote() -> Weight { // Proof Size summary in bytes: // Measured: `628` // Estimated: `219984` - // Minimum execution time: 41_151_000 picoseconds. - Weight::from_parts(42_435_000, 219984) + // Minimum execution time: 45_474_000 picoseconds. + Weight::from_parts(47_228_000, 219984) .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(5_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: `RankedPolls::ReferendumInfoFor` (r:1 w:0) - /// Proof: `RankedPolls::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(330), added: 2805, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::VotingCleanup` (r:1 w:0) - /// Proof: `RankedCollective::VotingCleanup` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::Voting` (r:100 w:100) - /// Proof: `RankedCollective::Voting` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: RankedPolls ReferendumInfoFor (r:1 w:0) + /// Proof: RankedPolls ReferendumInfoFor (max_values: None, max_size: Some(330), added: 2805, mode: MaxEncodedLen) + /// Storage: RankedCollective VotingCleanup (r:1 w:0) + /// Proof: RankedCollective VotingCleanup (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: RankedCollective Voting (r:100 w:100) + /// Proof: RankedCollective Voting (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) /// The range of component `n` is `[0, 100]`. fn cleanup_poll(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `462 + n * (50 ±0)` // Estimated: `3795 + n * (2540 ±0)` - // Minimum execution time: 13_563_000 picoseconds. - Weight::from_parts(17_495_215, 3795) - // Standard Error: 2_294 - .saturating_add(Weight::from_parts(1_207_393, 0).saturating_mul(n.into())) + // Minimum execution time: 13_903_000 picoseconds. + Weight::from_parts(18_209_102, 3795) + // Standard Error: 2_556 + .saturating_add(Weight::from_parts(1_237_454, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2540).saturating_mul(n.into())) } + /// Storage: `RankedCollective::Members` (r:2 w:2) /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) /// Storage: `RankedCollective::MemberCount` (r:2 w:2) /// Proof: `RankedCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::IdToIndex` (r:2 w:4) + /// Storage: `RankedCollective::IdToIndex` (r:2 w:2) /// Proof: `RankedCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::Member` (r:2 w:2) - /// Proof: `CoreFellowship::Member` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) - /// Storage: `CoreFellowship::MemberEvidence` (r:1 w:0) - /// Proof: `CoreFellowship::MemberEvidence` (`max_values`: None, `max_size`: Some(16429), added: 18904, mode: `MaxEncodedLen`) - /// Storage: `Salary::Claimant` (r:2 w:2) - /// Proof: `Salary::Claimant` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) /// Storage: `RankedCollective::IndexToId` (r:0 w:2) /// Proof: `RankedCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`) fn exchange_member() -> Weight { // Proof Size summary in bytes: - // Measured: `625` - // Estimated: `19894` - // Minimum execution time: 70_713_000 picoseconds. - Weight::from_parts(72_831_000, 19894) - .saturating_add(RocksDbWeight::get().reads(11_u64)) - .saturating_add(RocksDbWeight::get().writes(14_u64)) + // Measured: `437` + // Estimated: `6048` + // Minimum execution time: 138_000_000 picoseconds. + Weight::from_parts(141_000_000, 0) + .saturating_add(Weight::from_parts(0, 6048)) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(8)) } } diff --git a/substrate/frame/recovery/src/weights.rs b/substrate/frame/recovery/src/weights.rs index fe5dbcfc222..84b19ae694e 100644 --- a/substrate/frame/recovery/src/weights.rs +++ b/substrate/frame/recovery/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_recovery` +//! Autogenerated weights for pallet_recovery //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/recovery/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/recovery/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_recovery`. +/// Weight functions needed for pallet_recovery. pub trait WeightInfo { fn as_recovered() -> Weight; fn set_recovered() -> Weight; @@ -62,266 +63,258 @@ pub trait WeightInfo { fn cancel_recovered() -> Weight; } -/// Weights for `pallet_recovery` using the Substrate node and recommended hardware. +/// Weights for pallet_recovery using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Recovery::Proxy` (r:1 w:0) - /// Proof: `Recovery::Proxy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) + /// Storage: Recovery Proxy (r:1 w:0) + /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) fn as_recovered() -> Weight { // Proof Size summary in bytes: - // Measured: `497` - // Estimated: `3997` - // Minimum execution time: 14_898_000 picoseconds. - Weight::from_parts(15_464_000, 3997) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Measured: `281` + // Estimated: `3545` + // Minimum execution time: 9_360_000 picoseconds. + Weight::from_parts(9_773_000, 3545) + .saturating_add(T::DbWeight::get().reads(1_u64)) } - /// Storage: `Recovery::Proxy` (r:0 w:1) - /// Proof: `Recovery::Proxy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) + /// Storage: Recovery Proxy (r:0 w:1) + /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) fn set_recovered() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_424_000 picoseconds. - Weight::from_parts(7_830_000, 0) + // Minimum execution time: 9_146_000 picoseconds. + Weight::from_parts(9_507_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Recovery::Recoverable` (r:1 w:1) - /// Proof: `Recovery::Recoverable` (`max_values`: None, `max_size`: Some(351), added: 2826, mode: `MaxEncodedLen`) + /// Storage: Recovery Recoverable (r:1 w:1) + /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) /// The range of component `n` is `[1, 9]`. fn create_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `246` + // Measured: `175` // Estimated: `3816` - // Minimum execution time: 21_968_000 picoseconds. - Weight::from_parts(23_594_232, 3816) - // Standard Error: 5_848 - .saturating_add(Weight::from_parts(24_843, 0).saturating_mul(n.into())) + // Minimum execution time: 26_472_000 picoseconds. + Weight::from_parts(27_917_651, 3816) + // Standard Error: 7_129 + .saturating_add(Weight::from_parts(59_239, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Recovery::Recoverable` (r:1 w:0) - /// Proof: `Recovery::Recoverable` (`max_values`: None, `max_size`: Some(351), added: 2826, mode: `MaxEncodedLen`) - /// Storage: `Recovery::ActiveRecoveries` (r:1 w:1) - /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) + /// Storage: Recovery Recoverable (r:1 w:0) + /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) + /// Storage: Recovery ActiveRecoveries (r:1 w:1) + /// Proof: Recovery ActiveRecoveries (max_values: None, max_size: Some(389), added: 2864, mode: MaxEncodedLen) fn initiate_recovery() -> Weight { // Proof Size summary in bytes: - // Measured: `343` + // Measured: `272` // Estimated: `3854` - // Minimum execution time: 25_494_000 picoseconds. - Weight::from_parts(26_290_000, 3854) + // Minimum execution time: 29_618_000 picoseconds. + Weight::from_parts(30_192_000, 3854) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Recovery::Recoverable` (r:1 w:0) - /// Proof: `Recovery::Recoverable` (`max_values`: None, `max_size`: Some(351), added: 2826, mode: `MaxEncodedLen`) - /// Storage: `Recovery::ActiveRecoveries` (r:1 w:1) - /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) + /// Storage: Recovery Recoverable (r:1 w:0) + /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) + /// Storage: Recovery ActiveRecoveries (r:1 w:1) + /// Proof: Recovery ActiveRecoveries (max_values: None, max_size: Some(389), added: 2864, mode: MaxEncodedLen) /// The range of component `n` is `[1, 9]`. fn vouch_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `431 + n * (64 ±0)` + // Measured: `360 + n * (64 ±0)` // Estimated: `3854` - // Minimum execution time: 17_044_000 picoseconds. - Weight::from_parts(18_299_617, 3854) - // Standard Error: 5_580 - .saturating_add(Weight::from_parts(187_568, 0).saturating_mul(n.into())) + // Minimum execution time: 19_464_000 picoseconds. + Weight::from_parts(20_642_522, 3854) + // Standard Error: 5_974 + .saturating_add(Weight::from_parts(142_308, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Recovery::Recoverable` (r:1 w:0) - /// Proof: `Recovery::Recoverable` (`max_values`: None, `max_size`: Some(351), added: 2826, mode: `MaxEncodedLen`) - /// Storage: `Recovery::ActiveRecoveries` (r:1 w:0) - /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) - /// Storage: `Recovery::Proxy` (r:1 w:1) - /// Proof: `Recovery::Proxy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) + /// Storage: Recovery Recoverable (r:1 w:0) + /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) + /// Storage: Recovery ActiveRecoveries (r:1 w:0) + /// Proof: Recovery ActiveRecoveries (max_values: None, max_size: Some(389), added: 2864, mode: MaxEncodedLen) + /// Storage: Recovery Proxy (r:1 w:1) + /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) /// The range of component `n` is `[1, 9]`. fn claim_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `463 + n * (64 ±0)` + // Measured: `392 + n * (64 ±0)` // Estimated: `3854` - // Minimum execution time: 22_186_000 picoseconds. - Weight::from_parts(23_476_807, 3854) - // Standard Error: 6_392 - .saturating_add(Weight::from_parts(89_770, 0).saturating_mul(n.into())) + // Minimum execution time: 23_656_000 picoseconds. + Weight::from_parts(24_903_269, 3854) + // Standard Error: 5_771 + .saturating_add(Weight::from_parts(117_343, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Recovery::ActiveRecoveries` (r:1 w:1) - /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Recovery ActiveRecoveries (r:1 w:1) + /// Proof: Recovery ActiveRecoveries (max_values: None, max_size: Some(389), added: 2864, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `n` is `[1, 9]`. fn close_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `584 + n * (32 ±0)` + // Measured: `513 + n * (32 ±0)` // Estimated: `3854` - // Minimum execution time: 31_045_000 picoseconds. - Weight::from_parts(32_623_578, 3854) - // Standard Error: 7_203 - .saturating_add(Weight::from_parts(61_466, 0).saturating_mul(n.into())) + // Minimum execution time: 34_866_000 picoseconds. + Weight::from_parts(36_368_748, 3854) + // Standard Error: 6_600 + .saturating_add(Weight::from_parts(118_610, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Recovery::ActiveRecoveries` (r:1 w:0) - /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) - /// Storage: `Recovery::Recoverable` (r:1 w:1) - /// Proof: `Recovery::Recoverable` (`max_values`: None, `max_size`: Some(351), added: 2826, mode: `MaxEncodedLen`) + /// Storage: Recovery ActiveRecoveries (r:1 w:0) + /// Proof: Recovery ActiveRecoveries (max_values: None, max_size: Some(389), added: 2864, mode: MaxEncodedLen) + /// Storage: Recovery Recoverable (r:1 w:1) + /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) /// The range of component `n` is `[1, 9]`. fn remove_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `341 + n * (32 ±0)` + // Measured: `270 + n * (32 ±0)` // Estimated: `3854` - // Minimum execution time: 27_925_000 picoseconds. - Weight::from_parts(29_258_264, 3854) - // Standard Error: 8_192 - .saturating_add(Weight::from_parts(128_124, 0).saturating_mul(n.into())) + // Minimum execution time: 31_405_000 picoseconds. + Weight::from_parts(32_552_838, 3854) + // Standard Error: 8_043 + .saturating_add(Weight::from_parts(171_605, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Recovery::Proxy` (r:1 w:1) - /// Proof: `Recovery::Proxy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) + /// Storage: Recovery Proxy (r:1 w:1) + /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) fn cancel_recovered() -> Weight { // Proof Size summary in bytes: - // Measured: `352` + // Measured: `281` // Estimated: `3545` - // Minimum execution time: 11_623_000 picoseconds. - Weight::from_parts(12_043_000, 3545) + // Minimum execution time: 11_530_000 picoseconds. + Weight::from_parts(11_851_000, 3545) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Recovery::Proxy` (r:1 w:0) - /// Proof: `Recovery::Proxy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) + /// Storage: Recovery Proxy (r:1 w:0) + /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) fn as_recovered() -> Weight { // Proof Size summary in bytes: - // Measured: `497` - // Estimated: `3997` - // Minimum execution time: 14_898_000 picoseconds. - Weight::from_parts(15_464_000, 3997) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Measured: `281` + // Estimated: `3545` + // Minimum execution time: 9_360_000 picoseconds. + Weight::from_parts(9_773_000, 3545) + .saturating_add(RocksDbWeight::get().reads(1_u64)) } - /// Storage: `Recovery::Proxy` (r:0 w:1) - /// Proof: `Recovery::Proxy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) + /// Storage: Recovery Proxy (r:0 w:1) + /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) fn set_recovered() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_424_000 picoseconds. - Weight::from_parts(7_830_000, 0) + // Minimum execution time: 9_146_000 picoseconds. + Weight::from_parts(9_507_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Recovery::Recoverable` (r:1 w:1) - /// Proof: `Recovery::Recoverable` (`max_values`: None, `max_size`: Some(351), added: 2826, mode: `MaxEncodedLen`) + /// Storage: Recovery Recoverable (r:1 w:1) + /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) /// The range of component `n` is `[1, 9]`. fn create_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `246` + // Measured: `175` // Estimated: `3816` - // Minimum execution time: 21_968_000 picoseconds. - Weight::from_parts(23_594_232, 3816) - // Standard Error: 5_848 - .saturating_add(Weight::from_parts(24_843, 0).saturating_mul(n.into())) + // Minimum execution time: 26_472_000 picoseconds. + Weight::from_parts(27_917_651, 3816) + // Standard Error: 7_129 + .saturating_add(Weight::from_parts(59_239, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Recovery::Recoverable` (r:1 w:0) - /// Proof: `Recovery::Recoverable` (`max_values`: None, `max_size`: Some(351), added: 2826, mode: `MaxEncodedLen`) - /// Storage: `Recovery::ActiveRecoveries` (r:1 w:1) - /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) + /// Storage: Recovery Recoverable (r:1 w:0) + /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) + /// Storage: Recovery ActiveRecoveries (r:1 w:1) + /// Proof: Recovery ActiveRecoveries (max_values: None, max_size: Some(389), added: 2864, mode: MaxEncodedLen) fn initiate_recovery() -> Weight { // Proof Size summary in bytes: - // Measured: `343` + // Measured: `272` // Estimated: `3854` - // Minimum execution time: 25_494_000 picoseconds. - Weight::from_parts(26_290_000, 3854) + // Minimum execution time: 29_618_000 picoseconds. + Weight::from_parts(30_192_000, 3854) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Recovery::Recoverable` (r:1 w:0) - /// Proof: `Recovery::Recoverable` (`max_values`: None, `max_size`: Some(351), added: 2826, mode: `MaxEncodedLen`) - /// Storage: `Recovery::ActiveRecoveries` (r:1 w:1) - /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) + /// Storage: Recovery Recoverable (r:1 w:0) + /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) + /// Storage: Recovery ActiveRecoveries (r:1 w:1) + /// Proof: Recovery ActiveRecoveries (max_values: None, max_size: Some(389), added: 2864, mode: MaxEncodedLen) /// The range of component `n` is `[1, 9]`. fn vouch_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `431 + n * (64 ±0)` + // Measured: `360 + n * (64 ±0)` // Estimated: `3854` - // Minimum execution time: 17_044_000 picoseconds. - Weight::from_parts(18_299_617, 3854) - // Standard Error: 5_580 - .saturating_add(Weight::from_parts(187_568, 0).saturating_mul(n.into())) + // Minimum execution time: 19_464_000 picoseconds. + Weight::from_parts(20_642_522, 3854) + // Standard Error: 5_974 + .saturating_add(Weight::from_parts(142_308, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Recovery::Recoverable` (r:1 w:0) - /// Proof: `Recovery::Recoverable` (`max_values`: None, `max_size`: Some(351), added: 2826, mode: `MaxEncodedLen`) - /// Storage: `Recovery::ActiveRecoveries` (r:1 w:0) - /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) - /// Storage: `Recovery::Proxy` (r:1 w:1) - /// Proof: `Recovery::Proxy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) + /// Storage: Recovery Recoverable (r:1 w:0) + /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) + /// Storage: Recovery ActiveRecoveries (r:1 w:0) + /// Proof: Recovery ActiveRecoveries (max_values: None, max_size: Some(389), added: 2864, mode: MaxEncodedLen) + /// Storage: Recovery Proxy (r:1 w:1) + /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) /// The range of component `n` is `[1, 9]`. fn claim_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `463 + n * (64 ±0)` + // Measured: `392 + n * (64 ±0)` // Estimated: `3854` - // Minimum execution time: 22_186_000 picoseconds. - Weight::from_parts(23_476_807, 3854) - // Standard Error: 6_392 - .saturating_add(Weight::from_parts(89_770, 0).saturating_mul(n.into())) + // Minimum execution time: 23_656_000 picoseconds. + Weight::from_parts(24_903_269, 3854) + // Standard Error: 5_771 + .saturating_add(Weight::from_parts(117_343, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Recovery::ActiveRecoveries` (r:1 w:1) - /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Recovery ActiveRecoveries (r:1 w:1) + /// Proof: Recovery ActiveRecoveries (max_values: None, max_size: Some(389), added: 2864, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `n` is `[1, 9]`. fn close_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `584 + n * (32 ±0)` + // Measured: `513 + n * (32 ±0)` // Estimated: `3854` - // Minimum execution time: 31_045_000 picoseconds. - Weight::from_parts(32_623_578, 3854) - // Standard Error: 7_203 - .saturating_add(Weight::from_parts(61_466, 0).saturating_mul(n.into())) + // Minimum execution time: 34_866_000 picoseconds. + Weight::from_parts(36_368_748, 3854) + // Standard Error: 6_600 + .saturating_add(Weight::from_parts(118_610, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Recovery::ActiveRecoveries` (r:1 w:0) - /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) - /// Storage: `Recovery::Recoverable` (r:1 w:1) - /// Proof: `Recovery::Recoverable` (`max_values`: None, `max_size`: Some(351), added: 2826, mode: `MaxEncodedLen`) + /// Storage: Recovery ActiveRecoveries (r:1 w:0) + /// Proof: Recovery ActiveRecoveries (max_values: None, max_size: Some(389), added: 2864, mode: MaxEncodedLen) + /// Storage: Recovery Recoverable (r:1 w:1) + /// Proof: Recovery Recoverable (max_values: None, max_size: Some(351), added: 2826, mode: MaxEncodedLen) /// The range of component `n` is `[1, 9]`. fn remove_recovery(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `341 + n * (32 ±0)` + // Measured: `270 + n * (32 ±0)` // Estimated: `3854` - // Minimum execution time: 27_925_000 picoseconds. - Weight::from_parts(29_258_264, 3854) - // Standard Error: 8_192 - .saturating_add(Weight::from_parts(128_124, 0).saturating_mul(n.into())) + // Minimum execution time: 31_405_000 picoseconds. + Weight::from_parts(32_552_838, 3854) + // Standard Error: 8_043 + .saturating_add(Weight::from_parts(171_605, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Recovery::Proxy` (r:1 w:1) - /// Proof: `Recovery::Proxy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) + /// Storage: Recovery Proxy (r:1 w:1) + /// Proof: Recovery Proxy (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) fn cancel_recovered() -> Weight { // Proof Size summary in bytes: - // Measured: `352` + // Measured: `281` // Estimated: `3545` - // Minimum execution time: 11_623_000 picoseconds. - Weight::from_parts(12_043_000, 3545) + // Minimum execution time: 11_530_000 picoseconds. + Weight::from_parts(11_851_000, 3545) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/referenda/src/weights.rs b/substrate/frame/referenda/src/weights.rs index 1f1b69873eb..4b89379b311 100644 --- a/substrate/frame/referenda/src/weights.rs +++ b/substrate/frame/referenda/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_referenda` +//! Autogenerated weights for pallet_referenda //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/referenda/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/referenda/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_referenda`. +/// Weight functions needed for pallet_referenda. pub trait WeightInfo { fn submit() -> Weight; fn place_decision_deposit_preparing() -> Weight; @@ -83,874 +84,842 @@ pub trait WeightInfo { fn clear_metadata() -> Weight; } -/// Weights for `pallet_referenda` using the Substrate node and recommended hardware. +/// Weights for pallet_referenda using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Referenda::ReferendumCount` (r:1 w:1) - /// Proof: `Referenda::ReferendumCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Referenda::ReferendumInfoFor` (r:0 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumCount (r:1 w:1) + /// Proof: Referenda ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:0 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn submit() -> Weight { // Proof Size summary in bytes: - // Measured: `286` + // Measured: `220` // Estimated: `110487` - // Minimum execution time: 31_536_000 picoseconds. - Weight::from_parts(32_797_000, 110487) + // Minimum execution time: 40_175_000 picoseconds. + Weight::from_parts(41_107_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn place_decision_deposit_preparing() -> Weight { // Proof Size summary in bytes: - // Measured: `539` + // Measured: `473` // Estimated: `219984` - // Minimum execution time: 42_579_000 picoseconds. - Weight::from_parts(43_877_000, 219984) + // Minimum execution time: 50_922_000 picoseconds. + Weight::from_parts(52_179_000, 219984) .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Referenda::DecidingCount` (r:1 w:0) - /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `Referenda::TrackQueue` (r:1 w:1) - /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:0) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn place_decision_deposit_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `3326` + // Measured: `3260` // Estimated: `110487` - // Minimum execution time: 61_439_000 picoseconds. - Weight::from_parts(63_681_000, 110487) + // Minimum execution time: 69_559_000 picoseconds. + Weight::from_parts(72_143_000, 110487) .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Referenda::DecidingCount` (r:1 w:0) - /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `Referenda::TrackQueue` (r:1 w:1) - /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:0) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn place_decision_deposit_not_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `3346` + // Measured: `3280` // Estimated: `110487` - // Minimum execution time: 60_136_000 picoseconds. - Weight::from_parts(61_841_000, 110487) + // Minimum execution time: 68_833_000 picoseconds. + Weight::from_parts(70_987_000, 110487) .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Referenda::DecidingCount` (r:1 w:1) - /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:1) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn place_decision_deposit_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `539` + // Measured: `473` // Estimated: `219984` - // Minimum execution time: 49_865_000 picoseconds. - Weight::from_parts(51_347_000, 219984) + // Minimum execution time: 61_794_000 picoseconds. + Weight::from_parts(62_846_000, 219984) .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(5_u64)) - } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Referenda::DecidingCount` (r:1 w:1) - /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:1) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn place_decision_deposit_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `539` + // Measured: `473` // Estimated: `219984` - // Minimum execution time: 47_887_000 picoseconds. - Weight::from_parts(49_927_000, 219984) + // Minimum execution time: 58_664_000 picoseconds. + Weight::from_parts(60_195_000, 219984) .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(5_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn refund_decision_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `417` + // Measured: `351` // Estimated: `3831` - // Minimum execution time: 25_721_000 picoseconds. - Weight::from_parts(26_922_000, 3831) + // Minimum execution time: 30_850_000 picoseconds. + Weight::from_parts(32_130_000, 3831) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn refund_submission_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `407` + // Measured: `341` // Estimated: `3831` - // Minimum execution time: 25_840_000 picoseconds. - Weight::from_parts(26_498_000, 3831) + // Minimum execution time: 30_747_000 picoseconds. + Weight::from_parts(32_196_000, 3831) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn cancel() -> Weight { // Proof Size summary in bytes: - // Measured: `447` + // Measured: `381` // Estimated: `219984` - // Minimum execution time: 30_530_000 picoseconds. - Weight::from_parts(31_547_000, 219984) + // Minimum execution time: 36_139_000 picoseconds. + Weight::from_parts(37_252_000, 219984) .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Referenda::MetadataOf` (r:1 w:0) - /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: Referenda MetadataOf (r:1 w:0) + /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn kill() -> Weight { // Proof Size summary in bytes: - // Measured: `688` + // Measured: `622` // Estimated: `219984` - // Minimum execution time: 64_011_000 picoseconds. - Weight::from_parts(65_240_000, 219984) + // Minimum execution time: 80_862_000 picoseconds. + Weight::from_parts(83_045_000, 219984) .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Referenda::TrackQueue` (r:1 w:0) - /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) - /// Storage: `Referenda::DecidingCount` (r:1 w:1) - /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: Referenda TrackQueue (r:1 w:0) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:1) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) fn one_fewer_deciding_queue_empty() -> Weight { // Proof Size summary in bytes: - // Measured: `240` + // Measured: `174` // Estimated: `5477` - // Minimum execution time: 9_568_000 picoseconds. - Weight::from_parts(10_004_000, 5477) + // Minimum execution time: 10_136_000 picoseconds. + Weight::from_parts(10_638_000, 5477) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Referenda::TrackQueue` (r:1 w:1) - /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn one_fewer_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `3216` + // Measured: `3150` // Estimated: `110487` - // Minimum execution time: 43_325_000 picoseconds. - Weight::from_parts(45_335_000, 110487) + // Minimum execution time: 52_022_000 picoseconds. + Weight::from_parts(53_910_000, 110487) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Referenda::TrackQueue` (r:1 w:1) - /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn one_fewer_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `3216` + // Measured: `3150` // Estimated: `110487` - // Minimum execution time: 44_287_000 picoseconds. - Weight::from_parts(45_164_000, 110487) + // Minimum execution time: 53_683_000 picoseconds. + Weight::from_parts(55_707_000, 110487) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Referenda::TrackQueue` (r:1 w:1) - /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) fn nudge_referendum_requeued_insertion() -> Weight { // Proof Size summary in bytes: - // Measured: `3077` + // Measured: `3011` // Estimated: `5477` - // Minimum execution time: 21_909_000 picoseconds. - Weight::from_parts(22_641_000, 5477) + // Minimum execution time: 24_043_000 picoseconds. + Weight::from_parts(24_512_000, 5477) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Referenda::TrackQueue` (r:1 w:1) - /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) fn nudge_referendum_requeued_slide() -> Weight { // Proof Size summary in bytes: - // Measured: `3077` + // Measured: `3011` // Estimated: `5477` - // Minimum execution time: 21_626_000 picoseconds. - Weight::from_parts(22_338_000, 5477) + // Minimum execution time: 23_588_000 picoseconds. + Weight::from_parts(24_422_000, 5477) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Referenda::DecidingCount` (r:1 w:0) - /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `Referenda::TrackQueue` (r:1 w:1) - /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:0) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) fn nudge_referendum_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `3081` + // Measured: `3015` // Estimated: `5477` - // Minimum execution time: 29_245_000 picoseconds. - Weight::from_parts(30_147_000, 5477) + // Minimum execution time: 31_443_000 picoseconds. + Weight::from_parts(32_725_000, 5477) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Referenda::DecidingCount` (r:1 w:0) - /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `Referenda::TrackQueue` (r:1 w:1) - /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:0) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) fn nudge_referendum_not_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `3101` + // Measured: `3035` // Estimated: `5477` - // Minimum execution time: 28_512_000 picoseconds. - Weight::from_parts(29_781_000, 5477) + // Minimum execution time: 30_319_000 picoseconds. + Weight::from_parts(31_652_000, 5477) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_no_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `399` + // Measured: `333` // Estimated: `110487` - // Minimum execution time: 19_208_000 picoseconds. - Weight::from_parts(19_947_000, 110487) + // Minimum execution time: 23_062_000 picoseconds. + Weight::from_parts(23_614_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_preparing() -> Weight { // Proof Size summary in bytes: - // Measured: `447` + // Measured: `381` // Estimated: `110487` - // Minimum execution time: 19_708_000 picoseconds. - Weight::from_parts(20_783_000, 110487) + // Minimum execution time: 23_537_000 picoseconds. + Weight::from_parts(24_267_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn nudge_referendum_timed_out() -> Weight { // Proof Size summary in bytes: - // Measured: `344` + // Measured: `278` // Estimated: `3831` - // Minimum execution time: 12_947_000 picoseconds. - Weight::from_parts(13_582_000, 3831) + // Minimum execution time: 16_388_000 picoseconds. + Weight::from_parts(16_676_000, 3831) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Referenda::DecidingCount` (r:1 w:1) - /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:1) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_begin_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `447` + // Measured: `381` // Estimated: `110487` - // Minimum execution time: 26_699_000 picoseconds. - Weight::from_parts(28_048_000, 110487) + // Minimum execution time: 32_801_000 picoseconds. + Weight::from_parts(34_053_000, 110487) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Referenda::DecidingCount` (r:1 w:1) - /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:1) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_begin_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `447` + // Measured: `381` // Estimated: `110487` - // Minimum execution time: 28_132_000 picoseconds. - Weight::from_parts(29_520_000, 110487) + // Minimum execution time: 35_704_000 picoseconds. + Weight::from_parts(36_451_000, 110487) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_begin_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `500` + // Measured: `434` // Estimated: `110487` - // Minimum execution time: 23_212_000 picoseconds. - Weight::from_parts(24_200_000, 110487) + // Minimum execution time: 29_151_000 picoseconds. + Weight::from_parts(30_055_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_end_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `483` + // Measured: `417` // Estimated: `110487` - // Minimum execution time: 22_807_000 picoseconds. - Weight::from_parts(23_858_000, 110487) + // Minimum execution time: 29_265_000 picoseconds. + Weight::from_parts(30_213_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_continue_not_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `500` + // Measured: `434` // Estimated: `110487` - // Minimum execution time: 22_862_000 picoseconds. - Weight::from_parts(23_627_000, 110487) + // Minimum execution time: 27_760_000 picoseconds. + Weight::from_parts(28_381_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_continue_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `504` + // Measured: `438` // Estimated: `110487` - // Minimum execution time: 21_030_000 picoseconds. - Weight::from_parts(21_710_000, 110487) + // Minimum execution time: 25_464_000 picoseconds. + Weight::from_parts(26_348_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Lookup` (r:1 w:1) - /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: Scheduler Lookup (r:1 w:1) + /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn nudge_referendum_approved() -> Weight { // Proof Size summary in bytes: - // Measured: `504` + // Measured: `438` // Estimated: `219984` - // Minimum execution time: 33_031_000 picoseconds. - Weight::from_parts(34_518_000, 219984) + // Minimum execution time: 42_629_000 picoseconds. + Weight::from_parts(43_732_000, 219984) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_rejected() -> Weight { // Proof Size summary in bytes: - // Measured: `500` + // Measured: `434` // Estimated: `110487` - // Minimum execution time: 23_198_000 picoseconds. - Weight::from_parts(24_238_000, 110487) + // Minimum execution time: 30_015_000 picoseconds. + Weight::from_parts(30_827_000, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:0) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Referenda::MetadataOf` (r:0 w:1) - /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Referenda MetadataOf (r:0 w:1) + /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn set_some_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `555` + // Measured: `422` // Estimated: `3831` - // Minimum execution time: 19_502_000 picoseconds. - Weight::from_parts(20_105_000, 3831) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Minimum execution time: 19_901_000 picoseconds. + Weight::from_parts(20_681_000, 3831) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Referenda::MetadataOf` (r:1 w:1) - /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda MetadataOf (r:1 w:1) + /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `421` + // Measured: `355` // Estimated: `3831` - // Minimum execution time: 15_417_000 picoseconds. - Weight::from_parts(15_916_000, 3831) + // Minimum execution time: 17_323_000 picoseconds. + Weight::from_parts(18_227_000, 3831) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Referenda::ReferendumCount` (r:1 w:1) - /// Proof: `Referenda::ReferendumCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Referenda::ReferendumInfoFor` (r:0 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumCount (r:1 w:1) + /// Proof: Referenda ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:0 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn submit() -> Weight { // Proof Size summary in bytes: - // Measured: `286` + // Measured: `220` // Estimated: `110487` - // Minimum execution time: 31_536_000 picoseconds. - Weight::from_parts(32_797_000, 110487) + // Minimum execution time: 40_175_000 picoseconds. + Weight::from_parts(41_107_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn place_decision_deposit_preparing() -> Weight { // Proof Size summary in bytes: - // Measured: `539` + // Measured: `473` // Estimated: `219984` - // Minimum execution time: 42_579_000 picoseconds. - Weight::from_parts(43_877_000, 219984) + // Minimum execution time: 50_922_000 picoseconds. + Weight::from_parts(52_179_000, 219984) .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Referenda::DecidingCount` (r:1 w:0) - /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `Referenda::TrackQueue` (r:1 w:1) - /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:0) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn place_decision_deposit_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `3326` + // Measured: `3260` // Estimated: `110487` - // Minimum execution time: 61_439_000 picoseconds. - Weight::from_parts(63_681_000, 110487) + // Minimum execution time: 69_559_000 picoseconds. + Weight::from_parts(72_143_000, 110487) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Referenda::DecidingCount` (r:1 w:0) - /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `Referenda::TrackQueue` (r:1 w:1) - /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:0) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn place_decision_deposit_not_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `3346` + // Measured: `3280` // Estimated: `110487` - // Minimum execution time: 60_136_000 picoseconds. - Weight::from_parts(61_841_000, 110487) + // Minimum execution time: 68_833_000 picoseconds. + Weight::from_parts(70_987_000, 110487) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Referenda::DecidingCount` (r:1 w:1) - /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:1) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn place_decision_deposit_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `539` + // Measured: `473` // Estimated: `219984` - // Minimum execution time: 49_865_000 picoseconds. - Weight::from_parts(51_347_000, 219984) + // Minimum execution time: 61_794_000 picoseconds. + Weight::from_parts(62_846_000, 219984) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(5_u64)) - } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Referenda::DecidingCount` (r:1 w:1) - /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:1) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn place_decision_deposit_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `539` + // Measured: `473` // Estimated: `219984` - // Minimum execution time: 47_887_000 picoseconds. - Weight::from_parts(49_927_000, 219984) + // Minimum execution time: 58_664_000 picoseconds. + Weight::from_parts(60_195_000, 219984) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(5_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn refund_decision_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `417` + // Measured: `351` // Estimated: `3831` - // Minimum execution time: 25_721_000 picoseconds. - Weight::from_parts(26_922_000, 3831) + // Minimum execution time: 30_850_000 picoseconds. + Weight::from_parts(32_130_000, 3831) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn refund_submission_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `407` + // Measured: `341` // Estimated: `3831` - // Minimum execution time: 25_840_000 picoseconds. - Weight::from_parts(26_498_000, 3831) + // Minimum execution time: 30_747_000 picoseconds. + Weight::from_parts(32_196_000, 3831) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn cancel() -> Weight { // Proof Size summary in bytes: - // Measured: `447` + // Measured: `381` // Estimated: `219984` - // Minimum execution time: 30_530_000 picoseconds. - Weight::from_parts(31_547_000, 219984) + // Minimum execution time: 36_139_000 picoseconds. + Weight::from_parts(37_252_000, 219984) .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Referenda::MetadataOf` (r:1 w:0) - /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: Referenda MetadataOf (r:1 w:0) + /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn kill() -> Weight { // Proof Size summary in bytes: - // Measured: `688` + // Measured: `622` // Estimated: `219984` - // Minimum execution time: 64_011_000 picoseconds. - Weight::from_parts(65_240_000, 219984) + // Minimum execution time: 80_862_000 picoseconds. + Weight::from_parts(83_045_000, 219984) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Referenda::TrackQueue` (r:1 w:0) - /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) - /// Storage: `Referenda::DecidingCount` (r:1 w:1) - /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: Referenda TrackQueue (r:1 w:0) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:1) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) fn one_fewer_deciding_queue_empty() -> Weight { // Proof Size summary in bytes: - // Measured: `240` + // Measured: `174` // Estimated: `5477` - // Minimum execution time: 9_568_000 picoseconds. - Weight::from_parts(10_004_000, 5477) + // Minimum execution time: 10_136_000 picoseconds. + Weight::from_parts(10_638_000, 5477) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Referenda::TrackQueue` (r:1 w:1) - /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn one_fewer_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `3216` + // Measured: `3150` // Estimated: `110487` - // Minimum execution time: 43_325_000 picoseconds. - Weight::from_parts(45_335_000, 110487) + // Minimum execution time: 52_022_000 picoseconds. + Weight::from_parts(53_910_000, 110487) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Referenda::TrackQueue` (r:1 w:1) - /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn one_fewer_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `3216` + // Measured: `3150` // Estimated: `110487` - // Minimum execution time: 44_287_000 picoseconds. - Weight::from_parts(45_164_000, 110487) + // Minimum execution time: 53_683_000 picoseconds. + Weight::from_parts(55_707_000, 110487) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Referenda::TrackQueue` (r:1 w:1) - /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) fn nudge_referendum_requeued_insertion() -> Weight { // Proof Size summary in bytes: - // Measured: `3077` + // Measured: `3011` // Estimated: `5477` - // Minimum execution time: 21_909_000 picoseconds. - Weight::from_parts(22_641_000, 5477) + // Minimum execution time: 24_043_000 picoseconds. + Weight::from_parts(24_512_000, 5477) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Referenda::TrackQueue` (r:1 w:1) - /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) fn nudge_referendum_requeued_slide() -> Weight { // Proof Size summary in bytes: - // Measured: `3077` + // Measured: `3011` // Estimated: `5477` - // Minimum execution time: 21_626_000 picoseconds. - Weight::from_parts(22_338_000, 5477) + // Minimum execution time: 23_588_000 picoseconds. + Weight::from_parts(24_422_000, 5477) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Referenda::DecidingCount` (r:1 w:0) - /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `Referenda::TrackQueue` (r:1 w:1) - /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:0) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) fn nudge_referendum_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `3081` + // Measured: `3015` // Estimated: `5477` - // Minimum execution time: 29_245_000 picoseconds. - Weight::from_parts(30_147_000, 5477) + // Minimum execution time: 31_443_000 picoseconds. + Weight::from_parts(32_725_000, 5477) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Referenda::DecidingCount` (r:1 w:0) - /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `Referenda::TrackQueue` (r:1 w:1) - /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:0) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Referenda TrackQueue (r:1 w:1) + /// Proof: Referenda TrackQueue (max_values: None, max_size: Some(2012), added: 4487, mode: MaxEncodedLen) fn nudge_referendum_not_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `3101` + // Measured: `3035` // Estimated: `5477` - // Minimum execution time: 28_512_000 picoseconds. - Weight::from_parts(29_781_000, 5477) + // Minimum execution time: 30_319_000 picoseconds. + Weight::from_parts(31_652_000, 5477) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_no_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `399` + // Measured: `333` // Estimated: `110487` - // Minimum execution time: 19_208_000 picoseconds. - Weight::from_parts(19_947_000, 110487) + // Minimum execution time: 23_062_000 picoseconds. + Weight::from_parts(23_614_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_preparing() -> Weight { // Proof Size summary in bytes: - // Measured: `447` + // Measured: `381` // Estimated: `110487` - // Minimum execution time: 19_708_000 picoseconds. - Weight::from_parts(20_783_000, 110487) + // Minimum execution time: 23_537_000 picoseconds. + Weight::from_parts(24_267_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) fn nudge_referendum_timed_out() -> Weight { // Proof Size summary in bytes: - // Measured: `344` + // Measured: `278` // Estimated: `3831` - // Minimum execution time: 12_947_000 picoseconds. - Weight::from_parts(13_582_000, 3831) + // Minimum execution time: 16_388_000 picoseconds. + Weight::from_parts(16_676_000, 3831) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Referenda::DecidingCount` (r:1 w:1) - /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:1) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_begin_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `447` + // Measured: `381` // Estimated: `110487` - // Minimum execution time: 26_699_000 picoseconds. - Weight::from_parts(28_048_000, 110487) + // Minimum execution time: 32_801_000 picoseconds. + Weight::from_parts(34_053_000, 110487) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Referenda::DecidingCount` (r:1 w:1) - /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda DecidingCount (r:1 w:1) + /// Proof: Referenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_begin_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `447` + // Measured: `381` // Estimated: `110487` - // Minimum execution time: 28_132_000 picoseconds. - Weight::from_parts(29_520_000, 110487) + // Minimum execution time: 35_704_000 picoseconds. + Weight::from_parts(36_451_000, 110487) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_begin_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `500` + // Measured: `434` // Estimated: `110487` - // Minimum execution time: 23_212_000 picoseconds. - Weight::from_parts(24_200_000, 110487) + // Minimum execution time: 29_151_000 picoseconds. + Weight::from_parts(30_055_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_end_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `483` + // Measured: `417` // Estimated: `110487` - // Minimum execution time: 22_807_000 picoseconds. - Weight::from_parts(23_858_000, 110487) + // Minimum execution time: 29_265_000 picoseconds. + Weight::from_parts(30_213_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_continue_not_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `500` + // Measured: `434` // Estimated: `110487` - // Minimum execution time: 22_862_000 picoseconds. - Weight::from_parts(23_627_000, 110487) + // Minimum execution time: 27_760_000 picoseconds. + Weight::from_parts(28_381_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_continue_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `504` + // Measured: `438` // Estimated: `110487` - // Minimum execution time: 21_030_000 picoseconds. - Weight::from_parts(21_710_000, 110487) + // Minimum execution time: 25_464_000 picoseconds. + Weight::from_parts(26_348_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:2 w:2) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Lookup` (r:1 w:1) - /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:2 w:2) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: Scheduler Lookup (r:1 w:1) + /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn nudge_referendum_approved() -> Weight { // Proof Size summary in bytes: - // Measured: `504` + // Measured: `438` // Estimated: `219984` - // Minimum execution time: 33_031_000 picoseconds. - Weight::from_parts(34_518_000, 219984) + // Minimum execution time: 42_629_000 picoseconds. + Weight::from_parts(43_732_000, 219984) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Agenda` (r:1 w:1) - /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:1) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Scheduler Agenda (r:1 w:1) + /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) fn nudge_referendum_rejected() -> Weight { // Proof Size summary in bytes: - // Measured: `500` + // Measured: `434` // Estimated: `110487` - // Minimum execution time: 23_198_000 picoseconds. - Weight::from_parts(24_238_000, 110487) + // Minimum execution time: 30_015_000 picoseconds. + Weight::from_parts(30_827_000, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:0) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Referenda::MetadataOf` (r:0 w:1) - /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Referenda MetadataOf (r:0 w:1) + /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn set_some_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `555` + // Measured: `422` // Estimated: `3831` - // Minimum execution time: 19_502_000 picoseconds. - Weight::from_parts(20_105_000, 3831) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Minimum execution time: 19_901_000 picoseconds. + Weight::from_parts(20_681_000, 3831) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) - /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(366), added: 2841, mode: `MaxEncodedLen`) - /// Storage: `Referenda::MetadataOf` (r:1 w:1) - /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda MetadataOf (r:1 w:1) + /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `421` + // Measured: `355` // Estimated: `3831` - // Minimum execution time: 15_417_000 picoseconds. - Weight::from_parts(15_916_000, 3831) + // Minimum execution time: 17_323_000 picoseconds. + Weight::from_parts(18_227_000, 3831) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/remark/src/weights.rs b/substrate/frame/remark/src/weights.rs index 61cca5b7d05..46475db163f 100644 --- a/substrate/frame/remark/src/weights.rs +++ b/substrate/frame/remark/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_remark` +//! Autogenerated weights for pallet_remark //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/remark/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/remark/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,12 +50,12 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_remark`. +/// Weight functions needed for pallet_remark. pub trait WeightInfo { fn store(l: u32, ) -> Weight; } -/// Weights for `pallet_remark` using the Substrate node and recommended hardware. +/// Weights for pallet_remark using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// The range of component `l` is `[1, 1048576]`. @@ -62,23 +63,23 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_623_000 picoseconds. - Weight::from_parts(6_757_000, 0) + // Minimum execution time: 8_471_000 picoseconds. + Weight::from_parts(8_586_000, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_368, 0).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(1_359, 0).saturating_mul(l.into())) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { /// The range of component `l` is `[1, 1048576]`. fn store(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_623_000 picoseconds. - Weight::from_parts(6_757_000, 0) + // Minimum execution time: 8_471_000 picoseconds. + Weight::from_parts(8_586_000, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_368, 0).saturating_mul(l.into())) + .saturating_add(Weight::from_parts(1_359, 0).saturating_mul(l.into())) } } diff --git a/substrate/frame/safe-mode/src/weights.rs b/substrate/frame/safe-mode/src/weights.rs index d326fab0f0f..f72bebcab9a 100644 --- a/substrate/frame/safe-mode/src/weights.rs +++ b/substrate/frame/safe-mode/src/weights.rs @@ -17,29 +17,27 @@ //! Autogenerated weights for `pallet_safe_mode` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-08-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-aahe6cbd-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/production/substrate-node +// target/production/substrate-node // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_safe_mode -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/safe-mode/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_safe_mode +// --chain=dev +// --header=./HEADER-APACHE2 +// --output=./frame/safe-mode/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -72,8 +70,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1489` - // Minimum execution time: 2_216_000 picoseconds. - Weight::from_parts(2_309_000, 1489) + // Minimum execution time: 2_500_000 picoseconds. + Weight::from_parts(2_594_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `SafeMode::EnteredUntil` (r:1 w:1) @@ -82,23 +80,23 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `169` // Estimated: `1489` - // Minimum execution time: 6_124_000 picoseconds. - Weight::from_parts(6_601_000, 1489) + // Minimum execution time: 8_868_000 picoseconds. + Weight::from_parts(9_415_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `SafeMode::EnteredUntil` (r:1 w:1) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) /// Storage: `SafeMode::Deposits` (r:0 w:1) /// Proof: `SafeMode::Deposits` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn enter() -> Weight { // Proof Size summary in bytes: // Measured: `142` - // Estimated: `3658` - // Minimum execution time: 44_825_000 picoseconds. - Weight::from_parts(45_845_000, 3658) + // Estimated: `3550` + // Minimum execution time: 50_541_000 picoseconds. + Weight::from_parts(51_558_000, 3550) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -108,23 +106,23 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1489` - // Minimum execution time: 7_603_000 picoseconds. - Weight::from_parts(7_954_000, 1489) + // Minimum execution time: 10_489_000 picoseconds. + Weight::from_parts(10_833_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `SafeMode::EnteredUntil` (r:1 w:1) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) /// Storage: `SafeMode::Deposits` (r:0 w:1) /// Proof: `SafeMode::Deposits` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn extend() -> Weight { // Proof Size summary in bytes: // Measured: `169` - // Estimated: `3658` - // Minimum execution time: 44_716_000 picoseconds. - Weight::from_parts(46_039_000, 3658) + // Estimated: `3550` + // Minimum execution time: 50_818_000 picoseconds. + Weight::from_parts(51_873_000, 3550) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -134,8 +132,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `169` // Estimated: `1489` - // Minimum execution time: 8_231_000 picoseconds. - Weight::from_parts(8_731_000, 1489) + // Minimum execution time: 10_843_000 picoseconds. + Weight::from_parts(11_314_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -145,8 +143,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `169` // Estimated: `1489` - // Minimum execution time: 8_015_000 picoseconds. - Weight::from_parts(8_247_000, 1489) + // Minimum execution time: 10_382_000 picoseconds. + Weight::from_parts(10_814_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -155,39 +153,39 @@ impl WeightInfo for SubstrateWeight { /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) fn release_deposit() -> Weight { // Proof Size summary in bytes: // Measured: `292` - // Estimated: `3658` - // Minimum execution time: 39_149_000 picoseconds. - Weight::from_parts(40_005_000, 3658) + // Estimated: `3550` + // Minimum execution time: 42_828_000 picoseconds. + Weight::from_parts(43_752_000, 3550) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `SafeMode::Deposits` (r:1 w:1) /// Proof: `SafeMode::Deposits` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) fn force_release_deposit() -> Weight { // Proof Size summary in bytes: // Measured: `292` - // Estimated: `3658` - // Minimum execution time: 37_528_000 picoseconds. - Weight::from_parts(38_473_000, 3658) + // Estimated: `3550` + // Minimum execution time: 40_196_000 picoseconds. + Weight::from_parts(41_298_000, 3550) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `SafeMode::Deposits` (r:1 w:1) /// Proof: `SafeMode::Deposits` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) fn force_slash_deposit() -> Weight { // Proof Size summary in bytes: // Measured: `292` - // Estimated: `3658` - // Minimum execution time: 29_417_000 picoseconds. - Weight::from_parts(30_195_000, 3658) + // Estimated: `3550` + // Minimum execution time: 33_660_000 picoseconds. + Weight::from_parts(34_426_000, 3550) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -201,8 +199,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1489` - // Minimum execution time: 2_216_000 picoseconds. - Weight::from_parts(2_309_000, 1489) + // Minimum execution time: 2_500_000 picoseconds. + Weight::from_parts(2_594_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `SafeMode::EnteredUntil` (r:1 w:1) @@ -211,23 +209,23 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `169` // Estimated: `1489` - // Minimum execution time: 6_124_000 picoseconds. - Weight::from_parts(6_601_000, 1489) + // Minimum execution time: 8_868_000 picoseconds. + Weight::from_parts(9_415_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `SafeMode::EnteredUntil` (r:1 w:1) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) /// Storage: `SafeMode::Deposits` (r:0 w:1) /// Proof: `SafeMode::Deposits` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn enter() -> Weight { // Proof Size summary in bytes: // Measured: `142` - // Estimated: `3658` - // Minimum execution time: 44_825_000 picoseconds. - Weight::from_parts(45_845_000, 3658) + // Estimated: `3550` + // Minimum execution time: 50_541_000 picoseconds. + Weight::from_parts(51_558_000, 3550) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -237,23 +235,23 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1489` - // Minimum execution time: 7_603_000 picoseconds. - Weight::from_parts(7_954_000, 1489) + // Minimum execution time: 10_489_000 picoseconds. + Weight::from_parts(10_833_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `SafeMode::EnteredUntil` (r:1 w:1) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) /// Storage: `SafeMode::Deposits` (r:0 w:1) /// Proof: `SafeMode::Deposits` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn extend() -> Weight { // Proof Size summary in bytes: // Measured: `169` - // Estimated: `3658` - // Minimum execution time: 44_716_000 picoseconds. - Weight::from_parts(46_039_000, 3658) + // Estimated: `3550` + // Minimum execution time: 50_818_000 picoseconds. + Weight::from_parts(51_873_000, 3550) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -263,8 +261,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `169` // Estimated: `1489` - // Minimum execution time: 8_231_000 picoseconds. - Weight::from_parts(8_731_000, 1489) + // Minimum execution time: 10_843_000 picoseconds. + Weight::from_parts(11_314_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -274,8 +272,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `169` // Estimated: `1489` - // Minimum execution time: 8_015_000 picoseconds. - Weight::from_parts(8_247_000, 1489) + // Minimum execution time: 10_382_000 picoseconds. + Weight::from_parts(10_814_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -284,39 +282,39 @@ impl WeightInfo for () { /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) fn release_deposit() -> Weight { // Proof Size summary in bytes: // Measured: `292` - // Estimated: `3658` - // Minimum execution time: 39_149_000 picoseconds. - Weight::from_parts(40_005_000, 3658) + // Estimated: `3550` + // Minimum execution time: 42_828_000 picoseconds. + Weight::from_parts(43_752_000, 3550) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `SafeMode::Deposits` (r:1 w:1) /// Proof: `SafeMode::Deposits` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) fn force_release_deposit() -> Weight { // Proof Size summary in bytes: // Measured: `292` - // Estimated: `3658` - // Minimum execution time: 37_528_000 picoseconds. - Weight::from_parts(38_473_000, 3658) + // Estimated: `3550` + // Minimum execution time: 40_196_000 picoseconds. + Weight::from_parts(41_298_000, 3550) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `SafeMode::Deposits` (r:1 w:1) /// Proof: `SafeMode::Deposits` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) fn force_slash_deposit() -> Weight { // Proof Size summary in bytes: // Measured: `292` - // Estimated: `3658` - // Minimum execution time: 29_417_000 picoseconds. - Weight::from_parts(30_195_000, 3658) + // Estimated: `3550` + // Minimum execution time: 33_660_000 picoseconds. + Weight::from_parts(34_426_000, 3550) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/substrate/frame/salary/src/weights.rs b/substrate/frame/salary/src/weights.rs index c4f22a027eb..3d3b9e31595 100644 --- a/substrate/frame/salary/src/weights.rs +++ b/substrate/frame/salary/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_salary` +//! Autogenerated weights for pallet_salary //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/salary/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/salary/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_salary`. +/// Weight functions needed for pallet_salary. pub trait WeightInfo { fn init() -> Weight; fn bump() -> Weight; @@ -60,204 +61,204 @@ pub trait WeightInfo { fn check_payment() -> Weight; } -/// Weights for `pallet_salary` using the Substrate node and recommended hardware. +/// Weights for pallet_salary using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Salary::Status` (r:1 w:1) - /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + /// Storage: Salary Status (r:1 w:1) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) fn init() -> Weight { // Proof Size summary in bytes: // Measured: `4` // Estimated: `1541` - // Minimum execution time: 7_421_000 picoseconds. - Weight::from_parts(7_819_000, 1541) + // Minimum execution time: 10_778_000 picoseconds. + Weight::from_parts(11_084_000, 1541) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Salary::Status` (r:1 w:1) - /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + /// Storage: Salary Status (r:1 w:1) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) fn bump() -> Weight { // Proof Size summary in bytes: // Measured: `86` // Estimated: `1541` - // Minimum execution time: 8_651_000 picoseconds. - Weight::from_parts(9_056_000, 1541) + // Minimum execution time: 12_042_000 picoseconds. + Weight::from_parts(12_645_000, 1541) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Salary::Status` (r:1 w:0) - /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::Members` (r:1 w:0) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `Salary::Claimant` (r:1 w:1) - /// Proof: `Salary::Claimant` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) + /// Storage: Salary Status (r:1 w:0) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: Salary Claimant (r:1 w:1) + /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) fn induct() -> Weight { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3543` - // Minimum execution time: 16_513_000 picoseconds. - Weight::from_parts(17_305_000, 3543) + // Minimum execution time: 18_374_000 picoseconds. + Weight::from_parts(19_200_000, 3543) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `RankedCollective::Members` (r:1 w:0) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `Salary::Status` (r:1 w:1) - /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) - /// Storage: `Salary::Claimant` (r:1 w:1) - /// Proof: `Salary::Claimant` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: Salary Status (r:1 w:1) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + /// Storage: Salary Claimant (r:1 w:1) + /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) fn register() -> Weight { // Proof Size summary in bytes: // Measured: `462` // Estimated: `3543` - // Minimum execution time: 18_913_000 picoseconds. - Weight::from_parts(19_867_000, 3543) + // Minimum execution time: 22_696_000 picoseconds. + Weight::from_parts(23_275_000, 3543) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Salary::Status` (r:1 w:1) - /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) - /// Storage: `Salary::Claimant` (r:1 w:1) - /// Proof: `Salary::Claimant` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::Members` (r:1 w:0) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: Salary Status (r:1 w:1) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + /// Storage: Salary Claimant (r:1 w:1) + /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) fn payout() -> Weight { // Proof Size summary in bytes: // Measured: `462` // Estimated: `3543` - // Minimum execution time: 53_297_000 picoseconds. - Weight::from_parts(55_144_000, 3543) + // Minimum execution time: 63_660_000 picoseconds. + Weight::from_parts(65_006_000, 3543) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Salary::Status` (r:1 w:1) - /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) - /// Storage: `Salary::Claimant` (r:1 w:1) - /// Proof: `Salary::Claimant` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::Members` (r:1 w:0) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Salary Status (r:1 w:1) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + /// Storage: Salary Claimant (r:1 w:1) + /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn payout_other() -> Weight { // Proof Size summary in bytes: // Measured: `462` // Estimated: `3593` - // Minimum execution time: 53_638_000 picoseconds. - Weight::from_parts(55_328_000, 3593) + // Minimum execution time: 64_706_000 picoseconds. + Weight::from_parts(65_763_000, 3593) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Salary::Status` (r:1 w:1) - /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) - /// Storage: `Salary::Claimant` (r:1 w:1) - /// Proof: `Salary::Claimant` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) + /// Storage: Salary Status (r:1 w:1) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + /// Storage: Salary Claimant (r:1 w:1) + /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) fn check_payment() -> Weight { // Proof Size summary in bytes: // Measured: `170` // Estimated: `3543` - // Minimum execution time: 10_557_000 picoseconds. - Weight::from_parts(11_145_000, 3543) + // Minimum execution time: 11_838_000 picoseconds. + Weight::from_parts(12_323_000, 3543) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Salary::Status` (r:1 w:1) - /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + /// Storage: Salary Status (r:1 w:1) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) fn init() -> Weight { // Proof Size summary in bytes: // Measured: `4` // Estimated: `1541` - // Minimum execution time: 7_421_000 picoseconds. - Weight::from_parts(7_819_000, 1541) + // Minimum execution time: 10_778_000 picoseconds. + Weight::from_parts(11_084_000, 1541) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Salary::Status` (r:1 w:1) - /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) + /// Storage: Salary Status (r:1 w:1) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) fn bump() -> Weight { // Proof Size summary in bytes: // Measured: `86` // Estimated: `1541` - // Minimum execution time: 8_651_000 picoseconds. - Weight::from_parts(9_056_000, 1541) + // Minimum execution time: 12_042_000 picoseconds. + Weight::from_parts(12_645_000, 1541) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Salary::Status` (r:1 w:0) - /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::Members` (r:1 w:0) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `Salary::Claimant` (r:1 w:1) - /// Proof: `Salary::Claimant` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) + /// Storage: Salary Status (r:1 w:0) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: Salary Claimant (r:1 w:1) + /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) fn induct() -> Weight { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3543` - // Minimum execution time: 16_513_000 picoseconds. - Weight::from_parts(17_305_000, 3543) + // Minimum execution time: 18_374_000 picoseconds. + Weight::from_parts(19_200_000, 3543) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `RankedCollective::Members` (r:1 w:0) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `Salary::Status` (r:1 w:1) - /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) - /// Storage: `Salary::Claimant` (r:1 w:1) - /// Proof: `Salary::Claimant` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: Salary Status (r:1 w:1) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + /// Storage: Salary Claimant (r:1 w:1) + /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) fn register() -> Weight { // Proof Size summary in bytes: // Measured: `462` // Estimated: `3543` - // Minimum execution time: 18_913_000 picoseconds. - Weight::from_parts(19_867_000, 3543) + // Minimum execution time: 22_696_000 picoseconds. + Weight::from_parts(23_275_000, 3543) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Salary::Status` (r:1 w:1) - /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) - /// Storage: `Salary::Claimant` (r:1 w:1) - /// Proof: `Salary::Claimant` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::Members` (r:1 w:0) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) + /// Storage: Salary Status (r:1 w:1) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + /// Storage: Salary Claimant (r:1 w:1) + /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) fn payout() -> Weight { // Proof Size summary in bytes: // Measured: `462` // Estimated: `3543` - // Minimum execution time: 53_297_000 picoseconds. - Weight::from_parts(55_144_000, 3543) + // Minimum execution time: 63_660_000 picoseconds. + Weight::from_parts(65_006_000, 3543) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Salary::Status` (r:1 w:1) - /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) - /// Storage: `Salary::Claimant` (r:1 w:1) - /// Proof: `Salary::Claimant` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) - /// Storage: `RankedCollective::Members` (r:1 w:0) - /// Proof: `RankedCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Salary Status (r:1 w:1) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + /// Storage: Salary Claimant (r:1 w:1) + /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) + /// Storage: RankedCollective Members (r:1 w:0) + /// Proof: RankedCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn payout_other() -> Weight { // Proof Size summary in bytes: // Measured: `462` // Estimated: `3593` - // Minimum execution time: 53_638_000 picoseconds. - Weight::from_parts(55_328_000, 3593) + // Minimum execution time: 64_706_000 picoseconds. + Weight::from_parts(65_763_000, 3593) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Salary::Status` (r:1 w:1) - /// Proof: `Salary::Status` (`max_values`: Some(1), `max_size`: Some(56), added: 551, mode: `MaxEncodedLen`) - /// Storage: `Salary::Claimant` (r:1 w:1) - /// Proof: `Salary::Claimant` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) + /// Storage: Salary Status (r:1 w:1) + /// Proof: Salary Status (max_values: Some(1), max_size: Some(56), added: 551, mode: MaxEncodedLen) + /// Storage: Salary Claimant (r:1 w:1) + /// Proof: Salary Claimant (max_values: None, max_size: Some(78), added: 2553, mode: MaxEncodedLen) fn check_payment() -> Weight { // Proof Size summary in bytes: // Measured: `170` // Estimated: `3543` - // Minimum execution time: 10_557_000 picoseconds. - Weight::from_parts(11_145_000, 3543) + // Minimum execution time: 11_838_000 picoseconds. + Weight::from_parts(12_323_000, 3543) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/substrate/frame/sassafras/src/mock.rs b/substrate/frame/sassafras/src/mock.rs index 4c6efaa63a9..5e5909fcb0d 100644 --- a/substrate/frame/sassafras/src/mock.rs +++ b/substrate/frame/sassafras/src/mock.rs @@ -34,8 +34,7 @@ use sp_core::{ H256, U256, }; use sp_runtime::{ - generic::UncheckedExtrinsic, - testing::{Digest, DigestItem, Header}, + testing::{Digest, DigestItem, Header, TestXt}, BuildStorage, }; @@ -54,7 +53,7 @@ where RuntimeCall: From, { type OverarchingCall = RuntimeCall; - type Extrinsic = UncheckedExtrinsic; + type Extrinsic = TestXt; } impl pallet_sassafras::Config for Test { diff --git a/substrate/frame/scheduler/src/weights.rs b/substrate/frame/scheduler/src/weights.rs index 6c98145d266..9b7e5405a1b 100644 --- a/substrate/frame/scheduler/src/weights.rs +++ b/substrate/frame/scheduler/src/weights.rs @@ -17,28 +17,26 @@ //! Autogenerated weights for `pallet_scheduler` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2024-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-grjcggob-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/production/substrate-node +// target/production/substrate-node // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_scheduler -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/scheduler/src/weights.rs +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_scheduler +// --chain=dev // --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/scheduler/src/weights.rs // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -79,8 +77,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `31` // Estimated: `1489` - // Minimum execution time: 3_128_000 picoseconds. - Weight::from_parts(3_372_000, 1489) + // Minimum execution time: 3_040_000 picoseconds. + Weight::from_parts(3_202_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -91,10 +89,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 3_560_000 picoseconds. - Weight::from_parts(6_356_795, 110487) - // Standard Error: 493 - .saturating_add(Weight::from_parts(315_098, 0).saturating_mul(s.into())) + // Minimum execution time: 3_462_000 picoseconds. + Weight::from_parts(6_262_125, 110487) + // Standard Error: 536 + .saturating_add(Weight::from_parts(332_570, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -102,8 +100,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_501_000 picoseconds. - Weight::from_parts(3_722_000, 0) + // Minimum execution time: 3_425_000 picoseconds. + Weight::from_parts(3_680_000, 0) } /// Storage: `Preimage::PreimageFor` (r:1 w:1) /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `Measured`) @@ -116,10 +114,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `246 + s * (1 ±0)` // Estimated: `3711 + s * (1 ±0)` - // Minimum execution time: 17_976_000 picoseconds. - Weight::from_parts(18_137_000, 3711) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_173, 0).saturating_mul(s.into())) + // Minimum execution time: 17_564_000 picoseconds. + Weight::from_parts(17_887_000, 3711) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_253, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(s.into())) @@ -130,16 +128,16 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_935_000 picoseconds. - Weight::from_parts(5_133_000, 0) + // Minimum execution time: 4_934_000 picoseconds. + Weight::from_parts(5_275_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn service_task_periodic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_467_000 picoseconds. - Weight::from_parts(3_654_000, 0) + // Minimum execution time: 3_348_000 picoseconds. + Weight::from_parts(3_561_000, 0) } /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -149,16 +147,16 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3997` - // Minimum execution time: 6_528_000 picoseconds. - Weight::from_parts(6_820_000, 3997) + // Minimum execution time: 6_395_000 picoseconds. + Weight::from_parts(6_642_000, 3997) .saturating_add(T::DbWeight::get().reads(2_u64)) } fn execute_dispatch_unsigned() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_202_000 picoseconds. - Weight::from_parts(2_360_000, 0) + // Minimum execution time: 2_167_000 picoseconds. + Weight::from_parts(2_266_000, 0) } /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) @@ -167,17 +165,15 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 10_222_000 picoseconds. - Weight::from_parts(13_654_958, 110487) - // Standard Error: 676 - .saturating_add(Weight::from_parts(338_633, 0).saturating_mul(s.into())) + // Minimum execution time: 10_009_000 picoseconds. + Weight::from_parts(13_565_985, 110487) + // Standard Error: 575 + .saturating_add(Weight::from_parts(354_760, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Lookup` (r:0 w:1) /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// The range of component `s` is `[1, 512]`. @@ -185,12 +181,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 15_517_000 picoseconds. - Weight::from_parts(17_464_075, 110487) - // Standard Error: 952 - .saturating_add(Weight::from_parts(495_806, 0).saturating_mul(s.into())) + // Minimum execution time: 14_048_000 picoseconds. + Weight::from_parts(15_141_696, 110487) + // Standard Error: 1_082 + .saturating_add(Weight::from_parts(533_390, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Scheduler::Lookup` (r:1 w:1) /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) @@ -201,10 +197,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `596 + s * (178 ±0)` // Estimated: `110487` - // Minimum execution time: 13_091_000 picoseconds. - Weight::from_parts(19_101_313, 110487) - // Standard Error: 662 - .saturating_add(Weight::from_parts(342_468, 0).saturating_mul(s.into())) + // Minimum execution time: 12_902_000 picoseconds. + Weight::from_parts(18_957_156, 110487) + // Standard Error: 792 + .saturating_add(Weight::from_parts(361_909, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -212,35 +208,35 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) /// The range of component `s` is `[1, 512]`. fn cancel_named(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `709 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 17_579_000 picoseconds. - Weight::from_parts(20_561_921, 110487) - // Standard Error: 792 - .saturating_add(Weight::from_parts(500_463, 0).saturating_mul(s.into())) + // Minimum execution time: 15_933_000 picoseconds. + Weight::from_parts(18_091_415, 110487) + // Standard Error: 779 + .saturating_add(Weight::from_parts(534_402, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } + /// Storage: `Scheduler::Retries` (r:1 w:2) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Lookup` (r:0 w:1) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// The range of component `s` is `[1, 512]`. fn schedule_retry(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `118` + // Measured: `159` // Estimated: `110487` - // Minimum execution time: 8_996_000 picoseconds. - Weight::from_parts(11_393_234, 110487) - // Standard Error: 190 - .saturating_add(Weight::from_parts(6_714, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + // Minimum execution time: 14_155_000 picoseconds. + Weight::from_parts(16_447_031, 110487) + // Standard Error: 233 + .saturating_add(Weight::from_parts(8_424, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: `Scheduler::Agenda` (r:1 w:0) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) @@ -248,10 +244,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn set_retry() -> Weight { // Proof Size summary in bytes: - // Measured: `90705` + // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 121_505_000 picoseconds. - Weight::from_parts(124_306_000, 110487) + // Minimum execution time: 8_130_000 picoseconds. + Weight::from_parts(9_047_554, 110487) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -263,10 +259,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn set_retry_named() -> Weight { // Proof Size summary in bytes: - // Measured: `91747` + // Measured: `647 + s * (178 ±0)` // Estimated: `110487` - // Minimum execution time: 128_070_000 picoseconds. - Weight::from_parts(132_683_000, 110487) + // Minimum execution time: 10_838_000 picoseconds. + Weight::from_parts(12_804_076, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -276,10 +272,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn cancel_retry() -> Weight { // Proof Size summary in bytes: - // Measured: `90717` + // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 118_260_000 picoseconds. - Weight::from_parts(119_722_000, 110487) + // Minimum execution time: 8_130_000 picoseconds. + Weight::from_parts(9_047_554, 110487) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -291,10 +287,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn cancel_retry_named() -> Weight { // Proof Size summary in bytes: - // Measured: `91759` + // Measured: `647 + s * (178 ±0)` // Estimated: `110487` - // Minimum execution time: 129_036_000 picoseconds. - Weight::from_parts(133_975_000, 110487) + // Minimum execution time: 10_838_000 picoseconds. + Weight::from_parts(12_804_076, 110487) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -308,8 +304,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `31` // Estimated: `1489` - // Minimum execution time: 3_128_000 picoseconds. - Weight::from_parts(3_372_000, 1489) + // Minimum execution time: 3_040_000 picoseconds. + Weight::from_parts(3_202_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -320,10 +316,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 3_560_000 picoseconds. - Weight::from_parts(6_356_795, 110487) - // Standard Error: 493 - .saturating_add(Weight::from_parts(315_098, 0).saturating_mul(s.into())) + // Minimum execution time: 3_462_000 picoseconds. + Weight::from_parts(6_262_125, 110487) + // Standard Error: 536 + .saturating_add(Weight::from_parts(332_570, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -331,8 +327,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_501_000 picoseconds. - Weight::from_parts(3_722_000, 0) + // Minimum execution time: 3_425_000 picoseconds. + Weight::from_parts(3_680_000, 0) } /// Storage: `Preimage::PreimageFor` (r:1 w:1) /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `Measured`) @@ -345,10 +341,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `246 + s * (1 ±0)` // Estimated: `3711 + s * (1 ±0)` - // Minimum execution time: 17_976_000 picoseconds. - Weight::from_parts(18_137_000, 3711) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_173, 0).saturating_mul(s.into())) + // Minimum execution time: 17_564_000 picoseconds. + Weight::from_parts(17_887_000, 3711) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_253, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(s.into())) @@ -359,16 +355,16 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_935_000 picoseconds. - Weight::from_parts(5_133_000, 0) + // Minimum execution time: 4_934_000 picoseconds. + Weight::from_parts(5_275_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn service_task_periodic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_467_000 picoseconds. - Weight::from_parts(3_654_000, 0) + // Minimum execution time: 3_348_000 picoseconds. + Weight::from_parts(3_561_000, 0) } /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -378,16 +374,16 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3997` - // Minimum execution time: 6_528_000 picoseconds. - Weight::from_parts(6_820_000, 3997) + // Minimum execution time: 6_395_000 picoseconds. + Weight::from_parts(6_642_000, 3997) .saturating_add(RocksDbWeight::get().reads(2_u64)) } fn execute_dispatch_unsigned() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_202_000 picoseconds. - Weight::from_parts(2_360_000, 0) + // Minimum execution time: 2_167_000 picoseconds. + Weight::from_parts(2_266_000, 0) } /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) @@ -396,17 +392,15 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 10_222_000 picoseconds. - Weight::from_parts(13_654_958, 110487) - // Standard Error: 676 - .saturating_add(Weight::from_parts(338_633, 0).saturating_mul(s.into())) + // Minimum execution time: 10_009_000 picoseconds. + Weight::from_parts(13_565_985, 110487) + // Standard Error: 575 + .saturating_add(Weight::from_parts(354_760, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Lookup` (r:0 w:1) /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// The range of component `s` is `[1, 512]`. @@ -414,12 +408,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 15_517_000 picoseconds. - Weight::from_parts(17_464_075, 110487) - // Standard Error: 952 - .saturating_add(Weight::from_parts(495_806, 0).saturating_mul(s.into())) + // Minimum execution time: 14_048_000 picoseconds. + Weight::from_parts(15_141_696, 110487) + // Standard Error: 1_082 + .saturating_add(Weight::from_parts(533_390, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Scheduler::Lookup` (r:1 w:1) /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) @@ -430,10 +424,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `596 + s * (178 ±0)` // Estimated: `110487` - // Minimum execution time: 13_091_000 picoseconds. - Weight::from_parts(19_101_313, 110487) - // Standard Error: 662 - .saturating_add(Weight::from_parts(342_468, 0).saturating_mul(s.into())) + // Minimum execution time: 12_902_000 picoseconds. + Weight::from_parts(18_957_156, 110487) + // Standard Error: 792 + .saturating_add(Weight::from_parts(361_909, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -441,35 +435,35 @@ impl WeightInfo for () { /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) /// The range of component `s` is `[1, 512]`. fn cancel_named(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `709 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 17_579_000 picoseconds. - Weight::from_parts(20_561_921, 110487) - // Standard Error: 792 - .saturating_add(Weight::from_parts(500_463, 0).saturating_mul(s.into())) + // Minimum execution time: 15_933_000 picoseconds. + Weight::from_parts(18_091_415, 110487) + // Standard Error: 779 + .saturating_add(Weight::from_parts(534_402, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } + /// Storage: `Scheduler::Retries` (r:1 w:2) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Retries` (r:0 w:1) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Lookup` (r:0 w:1) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// The range of component `s` is `[1, 512]`. fn schedule_retry(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `118` + // Measured: `159` // Estimated: `110487` - // Minimum execution time: 8_996_000 picoseconds. - Weight::from_parts(11_393_234, 110487) - // Standard Error: 190 - .saturating_add(Weight::from_parts(6_714, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + // Minimum execution time: 14_155_000 picoseconds. + Weight::from_parts(16_447_031, 110487) + // Standard Error: 233 + .saturating_add(Weight::from_parts(8_424, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: `Scheduler::Agenda` (r:1 w:0) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(107022), added: 109497, mode: `MaxEncodedLen`) @@ -477,10 +471,10 @@ impl WeightInfo for () { /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn set_retry() -> Weight { // Proof Size summary in bytes: - // Measured: `90705` + // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 121_505_000 picoseconds. - Weight::from_parts(124_306_000, 110487) + // Minimum execution time: 8_130_000 picoseconds. + Weight::from_parts(9_047_554, 110487) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -492,10 +486,10 @@ impl WeightInfo for () { /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn set_retry_named() -> Weight { // Proof Size summary in bytes: - // Measured: `91747` + // Measured: `647 + s * (178 ±0)` // Estimated: `110487` - // Minimum execution time: 128_070_000 picoseconds. - Weight::from_parts(132_683_000, 110487) + // Minimum execution time: 10_838_000 picoseconds. + Weight::from_parts(12_804_076, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -505,10 +499,10 @@ impl WeightInfo for () { /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn cancel_retry() -> Weight { // Proof Size summary in bytes: - // Measured: `90717` + // Measured: `81 + s * (177 ±0)` // Estimated: `110487` - // Minimum execution time: 118_260_000 picoseconds. - Weight::from_parts(119_722_000, 110487) + // Minimum execution time: 8_130_000 picoseconds. + Weight::from_parts(9_047_554, 110487) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -520,10 +514,10 @@ impl WeightInfo for () { /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn cancel_retry_named() -> Weight { // Proof Size summary in bytes: - // Measured: `91759` + // Measured: `647 + s * (178 ±0)` // Estimated: `110487` - // Minimum execution time: 129_036_000 picoseconds. - Weight::from_parts(133_975_000, 110487) + // Minimum execution time: 10_838_000 picoseconds. + Weight::from_parts(12_804_076, 110487) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/session/src/weights.rs b/substrate/frame/session/src/weights.rs index 09eb665ff3d..dd9848fd2c1 100644 --- a/substrate/frame/session/src/weights.rs +++ b/substrate/frame/session/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_session` +//! Autogenerated weights for pallet_session //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/session/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/session/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,77 +50,77 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_session`. +/// Weight functions needed for pallet_session. pub trait WeightInfo { fn set_keys() -> Weight; fn purge_keys() -> Weight; } -/// Weights for `pallet_session` using the Substrate node and recommended hardware. +/// Weights for pallet_session using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Staking::Ledger` (r:1 w:0) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Session::NextKeys` (r:1 w:1) - /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Session::KeyOwner` (r:6 w:6) - /// Proof: `Session::KeyOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Session NextKeys (r:1 w:1) + /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) + /// Storage: Session KeyOwner (r:4 w:4) + /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) fn set_keys() -> Weight { // Proof Size summary in bytes: - // Measured: `1919` - // Estimated: `17759` - // Minimum execution time: 57_921_000 picoseconds. - Weight::from_parts(58_960_000, 17759) - .saturating_add(T::DbWeight::get().reads(8_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + // Measured: `1924` + // Estimated: `12814` + // Minimum execution time: 55_459_000 picoseconds. + Weight::from_parts(56_180_000, 12814) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: `Staking::Ledger` (r:1 w:0) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Session::NextKeys` (r:1 w:1) - /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Session::KeyOwner` (r:0 w:6) - /// Proof: `Session::KeyOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Session NextKeys (r:1 w:1) + /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) + /// Storage: Session KeyOwner (r:0 w:4) + /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) fn purge_keys() -> Weight { // Proof Size summary in bytes: - // Measured: `1817` - // Estimated: `5282` - // Minimum execution time: 40_983_000 picoseconds. - Weight::from_parts(42_700_000, 5282) + // Measured: `1791` + // Estimated: `5256` + // Minimum execution time: 40_194_000 picoseconds. + Weight::from_parts(41_313_000, 5256) .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Staking::Ledger` (r:1 w:0) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Session::NextKeys` (r:1 w:1) - /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Session::KeyOwner` (r:6 w:6) - /// Proof: `Session::KeyOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Session NextKeys (r:1 w:1) + /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) + /// Storage: Session KeyOwner (r:4 w:4) + /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) fn set_keys() -> Weight { // Proof Size summary in bytes: - // Measured: `1919` - // Estimated: `17759` - // Minimum execution time: 57_921_000 picoseconds. - Weight::from_parts(58_960_000, 17759) - .saturating_add(RocksDbWeight::get().reads(8_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + // Measured: `1924` + // Estimated: `12814` + // Minimum execution time: 55_459_000 picoseconds. + Weight::from_parts(56_180_000, 12814) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: `Staking::Ledger` (r:1 w:0) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Session::NextKeys` (r:1 w:1) - /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Session::KeyOwner` (r:0 w:6) - /// Proof: `Session::KeyOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Session NextKeys (r:1 w:1) + /// Proof Skipped: Session NextKeys (max_values: None, max_size: None, mode: Measured) + /// Storage: Session KeyOwner (r:0 w:4) + /// Proof Skipped: Session KeyOwner (max_values: None, max_size: None, mode: Measured) fn purge_keys() -> Weight { // Proof Size summary in bytes: - // Measured: `1817` - // Estimated: `5282` - // Minimum execution time: 40_983_000 picoseconds. - Weight::from_parts(42_700_000, 5282) + // Measured: `1791` + // Estimated: `5256` + // Minimum execution time: 40_194_000 picoseconds. + Weight::from_parts(41_313_000, 5256) .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } } diff --git a/substrate/frame/society/src/weights.rs b/substrate/frame/society/src/weights.rs index 1245f762972..c32c2383ac9 100644 --- a/substrate/frame/society/src/weights.rs +++ b/substrate/frame/society/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -15,41 +15,35 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_society` +//! Autogenerated weights for pallet_society //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-09-13, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev // --steps=50 // --repeat=20 // --pallet=pallet_society -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --output=./substrate/frame/society/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --template=./.maintain/frame-weight-template.hbs +// --header=./HEADER-APACHE2 +// --output=./frame/society/src/weights.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] -#![allow(missing_docs)] use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_society`. +/// Weight functions needed for pallet_society. pub trait WeightInfo { fn bid() -> Weight; fn unbid() -> Weight; @@ -73,739 +67,309 @@ pub trait WeightInfo { fn cleanup_challenge() -> Weight; } -/// Weights for `pallet_society` using the Substrate node and recommended hardware. +/// Weights for pallet_society using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Society::Bids` (r:1 w:1) - /// Proof: `Society::Bids` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Candidates` (r:1 w:0) - /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Members` (r:1 w:0) - /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::SuspendedMembers` (r:1 w:0) - /// Proof: `Society::SuspendedMembers` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Parameters` (r:1 w:0) - /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: Society Bids (r:1 w:1) + // Storage: Society Candidates (r:1 w:0) + // Storage: Society Members (r:1 w:0) + // Storage: Society SuspendedMembers (r:1 w:0) + // Storage: Society Parameters (r:1 w:0) fn bid() -> Weight { - // Proof Size summary in bytes: - // Measured: `444` - // Estimated: `3909` - // Minimum execution time: 29_905_000 picoseconds. - Weight::from_parts(31_031_000, 3909) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - /// Storage: `Society::Bids` (r:1 w:1) - /// Proof: `Society::Bids` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Bids (r:1 w:1) fn unbid() -> Weight { - // Proof Size summary in bytes: - // Measured: `461` - // Estimated: `1946` - // Minimum execution time: 23_038_000 picoseconds. - Weight::from_parts(23_904_000, 1946) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - /// Storage: `Society::Bids` (r:1 w:1) - /// Proof: `Society::Bids` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Candidates` (r:1 w:0) - /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Members` (r:2 w:1) - /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::SuspendedMembers` (r:1 w:0) - /// Proof: `Society::SuspendedMembers` (`max_values`: None, `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Bids (r:1 w:1) + // Storage: Society Candidates (r:1 w:0) + // Storage: Society Members (r:2 w:1) + // Storage: Society SuspendedMembers (r:1 w:0) fn vouch() -> Weight { - // Proof Size summary in bytes: - // Measured: `481` - // Estimated: `6421` - // Minimum execution time: 21_197_000 picoseconds. - Weight::from_parts(22_043_000, 6421) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) - } - /// Storage: `Society::Bids` (r:1 w:1) - /// Proof: `Society::Bids` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Members` (r:1 w:1) - /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Bids (r:1 w:1) + // Storage: Society Members (r:1 w:1) fn unvouch() -> Weight { - // Proof Size summary in bytes: - // Measured: `535` - // Estimated: `4000` - // Minimum execution time: 14_402_000 picoseconds. - Weight::from_parts(15_171_000, 4000) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) - } - /// Storage: `Society::Candidates` (r:1 w:1) - /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Members` (r:1 w:0) - /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Votes` (r:1 w:1) - /// Proof: `Society::Votes` (`max_values`: None, `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Candidates (r:1 w:1) + // Storage: Society Members (r:1 w:0) + // Storage: Society Votes (r:1 w:1) fn vote() -> Weight { - // Proof Size summary in bytes: - // Measured: `569` - // Estimated: `4034` - // Minimum execution time: 21_930_000 picoseconds. - Weight::from_parts(22_666_000, 4034) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) - } - /// Storage: `Society::Defending` (r:1 w:1) - /// Proof: `Society::Defending` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Members` (r:1 w:0) - /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::ChallengeRoundCount` (r:1 w:0) - /// Proof: `Society::ChallengeRoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::DefenderVotes` (r:1 w:1) - /// Proof: `Society::DefenderVotes` (`max_values`: None, `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Defending (r:1 w:1) + // Storage: Society Members (r:1 w:0) + // Storage: Society ChallengeRoundCount (r:1 w:0) + // Storage: Society DefenderVotes (r:1 w:1) fn defender_vote() -> Weight { - // Proof Size summary in bytes: - // Measured: `561` - // Estimated: `4026` - // Minimum execution time: 18_821_000 picoseconds. - Weight::from_parts(19_633_000, 4026) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) - } - /// Storage: `Society::Members` (r:1 w:0) - /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Payouts` (r:1 w:1) - /// Proof: `Society::Payouts` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + Weight::zero() + } + // Storage: Society Members (r:1 w:0) + // Storage: Society Payouts (r:1 w:1) + // Storage: System Account (r:1 w:1) fn payout() -> Weight { - // Proof Size summary in bytes: - // Measured: `650` - // Estimated: `4115` - // Minimum execution time: 47_262_000 picoseconds. - Weight::from_parts(48_313_000, 4115) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) - } - /// Storage: `Society::Members` (r:1 w:1) - /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Payouts` (r:1 w:1) - /// Proof: `Society::Payouts` (`max_values`: None, `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Members (r:1 w:1) + // Storage: Society Payouts (r:1 w:1) fn waive_repay() -> Weight { - // Proof Size summary in bytes: - // Measured: `547` - // Estimated: `4012` - // Minimum execution time: 18_189_000 picoseconds. - Weight::from_parts(19_038_000, 4012) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) - } - /// Storage: `Society::Head` (r:1 w:1) - /// Proof: `Society::Head` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::MemberCount` (r:1 w:1) - /// Proof: `Society::MemberCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::MemberByIndex` (r:0 w:1) - /// Proof: `Society::MemberByIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Founder` (r:0 w:1) - /// Proof: `Society::Founder` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Rules` (r:0 w:1) - /// Proof: `Society::Rules` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Members` (r:0 w:1) - /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Parameters` (r:0 w:1) - /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Head (r:1 w:1) + // Storage: Society MemberCount (r:1 w:1) + // Storage: Society MemberByIndex (r:0 w:1) + // Storage: Society Founder (r:0 w:1) + // Storage: Society Rules (r:0 w:1) + // Storage: Society Members (r:0 w:1) + // Storage: Society Parameters (r:0 w:1) fn found_society() -> Weight { - // Proof Size summary in bytes: - // Measured: `180` - // Estimated: `1665` - // Minimum execution time: 14_815_000 picoseconds. - Weight::from_parts(15_426_000, 1665) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) - } - /// Storage: `Society::Founder` (r:1 w:1) - /// Proof: `Society::Founder` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::MemberCount` (r:1 w:1) - /// Proof: `Society::MemberCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Members` (r:5 w:5) - /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::MemberByIndex` (r:5 w:5) - /// Proof: `Society::MemberByIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Votes` (r:4 w:4) - /// Proof: `Society::Votes` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Candidates` (r:4 w:4) - /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Head` (r:0 w:1) - /// Proof: `Society::Head` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Defending` (r:0 w:1) - /// Proof: `Society::Defending` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::ChallengeRoundCount` (r:0 w:1) - /// Proof: `Society::ChallengeRoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Skeptic` (r:0 w:1) - /// Proof: `Society::Skeptic` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Pot` (r:0 w:1) - /// Proof: `Society::Pot` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Rules` (r:0 w:1) - /// Proof: `Society::Rules` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::RoundCount` (r:0 w:1) - /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Bids` (r:0 w:1) - /// Proof: `Society::Bids` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Parameters` (r:0 w:1) - /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::NextHead` (r:0 w:1) - /// Proof: `Society::NextHead` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Founder (r:1 w:1) + // Storage: Society MemberCount (r:1 w:1) + // Storage: Society Head (r:0 w:1) + // Storage: Society Defending (r:0 w:1) + // Storage: Society ChallengeRoundCount (r:0 w:1) + // Storage: Society MemberByIndex (r:0 w:5) + // Storage: Society Skeptic (r:0 w:1) + // Storage: Society Candidates (r:0 w:4) + // Storage: Society Pot (r:0 w:1) + // Storage: Society Rules (r:0 w:1) + // Storage: Society Votes (r:0 w:4) + // Storage: Society Members (r:0 w:5) + // Storage: Society RoundCount (r:0 w:1) + // Storage: Society Bids (r:0 w:1) + // Storage: Society Parameters (r:0 w:1) + // Storage: Society NextHead (r:0 w:1) fn dissolve() -> Weight { - // Proof Size summary in bytes: - // Measured: `1654` - // Estimated: `15019` - // Minimum execution time: 57_787_000 picoseconds. - Weight::from_parts(59_489_000, 15019) - .saturating_add(T::DbWeight::get().reads(20_u64)) - .saturating_add(T::DbWeight::get().writes(30_u64)) - } - /// Storage: `Society::Founder` (r:1 w:0) - /// Proof: `Society::Founder` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::SuspendedMembers` (r:1 w:1) - /// Proof: `Society::SuspendedMembers` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Payouts` (r:1 w:0) - /// Proof: `Society::Payouts` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Pot` (r:1 w:1) - /// Proof: `Society::Pot` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Founder (r:1 w:0) + // Storage: Society SuspendedMembers (r:1 w:1) + // Storage: Society Payouts (r:1 w:0) + // Storage: Society Pot (r:1 w:1) fn judge_suspended_member() -> Weight { - // Proof Size summary in bytes: - // Measured: `505` - // Estimated: `3970` - // Minimum execution time: 19_262_000 picoseconds. - Weight::from_parts(19_752_000, 3970) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) - } - /// Storage: `Society::Founder` (r:1 w:0) - /// Proof: `Society::Founder` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::MemberCount` (r:1 w:0) - /// Proof: `Society::MemberCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Parameters` (r:0 w:1) - /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Founder (r:1 w:0) + // Storage: Society MemberCount (r:1 w:0) + // Storage: Society Parameters (r:0 w:1) fn set_parameters() -> Weight { - // Proof Size summary in bytes: - // Measured: `387` - // Estimated: `1872` - // Minimum execution time: 10_656_000 picoseconds. - Weight::from_parts(11_063_000, 1872) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - /// Storage: `Society::Candidates` (r:1 w:1) - /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::RoundCount` (r:1 w:0) - /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Skeptic` (r:1 w:0) - /// Proof: `Society::Skeptic` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Votes` (r:1 w:0) - /// Proof: `Society::Votes` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Members` (r:1 w:1) - /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Parameters` (r:1 w:0) - /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Candidates (r:1 w:1) + // Storage: Society RoundCount (r:1 w:0) + // Storage: Society Skeptic (r:1 w:0) + // Storage: Society Votes (r:1 w:0) + // Storage: Society Members (r:1 w:1) + // Storage: Society Parameters (r:1 w:0) fn punish_skeptic() -> Weight { - // Proof Size summary in bytes: - // Measured: `636` - // Estimated: `4101` - // Minimum execution time: 22_837_000 picoseconds. - Weight::from_parts(23_738_000, 4101) - .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) - } - /// Storage: `Society::Candidates` (r:1 w:1) - /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::RoundCount` (r:1 w:0) - /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Parameters` (r:1 w:0) - /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::MemberCount` (r:1 w:1) - /// Proof: `Society::MemberCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::NextHead` (r:1 w:1) - /// Proof: `Society::NextHead` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Society::MemberByIndex` (r:0 w:1) - /// Proof: `Society::MemberByIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Members` (r:0 w:1) - /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Candidates (r:1 w:1) + // Storage: Society RoundCount (r:1 w:0) + // Storage: Society Parameters (r:1 w:0) + // Storage: Society MemberCount (r:1 w:1) + // Storage: Society NextHead (r:1 w:1) + // Storage: System Account (r:1 w:1) + // Storage: Society MemberByIndex (r:0 w:1) + // Storage: Society Members (r:0 w:1) fn claim_membership() -> Weight { - // Proof Size summary in bytes: - // Measured: `632` - // Estimated: `4097` - // Minimum execution time: 35_142_000 picoseconds. - Weight::from_parts(36_811_000, 4097) - .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().writes(6_u64)) - } - /// Storage: `Society::Founder` (r:1 w:0) - /// Proof: `Society::Founder` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Candidates` (r:1 w:1) - /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::RoundCount` (r:1 w:0) - /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Parameters` (r:1 w:0) - /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::MemberCount` (r:1 w:1) - /// Proof: `Society::MemberCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::NextHead` (r:1 w:1) - /// Proof: `Society::NextHead` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Society::MemberByIndex` (r:0 w:1) - /// Proof: `Society::MemberByIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Members` (r:0 w:1) - /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Founder (r:1 w:0) + // Storage: Society Candidates (r:1 w:1) + // Storage: Society RoundCount (r:1 w:0) + // Storage: Society Parameters (r:1 w:0) + // Storage: Society MemberCount (r:1 w:1) + // Storage: Society NextHead (r:1 w:1) + // Storage: System Account (r:1 w:1) + // Storage: Society MemberByIndex (r:0 w:1) + // Storage: Society Members (r:0 w:1) fn bestow_membership() -> Weight { - // Proof Size summary in bytes: - // Measured: `650` - // Estimated: `4115` - // Minimum execution time: 37_133_000 picoseconds. - Weight::from_parts(38_366_000, 4115) - .saturating_add(T::DbWeight::get().reads(7_u64)) - .saturating_add(T::DbWeight::get().writes(6_u64)) - } - /// Storage: `Society::Founder` (r:1 w:0) - /// Proof: `Society::Founder` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Candidates` (r:1 w:1) - /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::RoundCount` (r:1 w:0) - /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + Weight::zero() + } + // Storage: Society Founder (r:1 w:0) + // Storage: Society Candidates (r:1 w:1) + // Storage: Society RoundCount (r:1 w:0) fn kick_candidate() -> Weight { - // Proof Size summary in bytes: - // Measured: `776` - // Estimated: `6196` - // Minimum execution time: 37_033_000 picoseconds. - Weight::from_parts(38_293_000, 6196) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) - } - /// Storage: `Society::Candidates` (r:1 w:1) - /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::RoundCount` (r:1 w:0) - /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + Weight::zero() + } + // Storage: Society Candidates (r:1 w:1) + // Storage: Society RoundCount (r:1 w:0) fn resign_candidacy() -> Weight { - // Proof Size summary in bytes: - // Measured: `746` - // Estimated: `6196` - // Minimum execution time: 35_203_000 picoseconds. - Weight::from_parts(36_252_000, 6196) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) - } - /// Storage: `Society::Candidates` (r:1 w:1) - /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::RoundCount` (r:1 w:0) - /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + Weight::zero() + } + // Storage: Society Candidates (r:1 w:1) + // Storage: Society RoundCount (r:1 w:0) fn drop_candidate() -> Weight { - // Proof Size summary in bytes: - // Measured: `758` - // Estimated: `6196` - // Minimum execution time: 35_518_000 picoseconds. - Weight::from_parts(36_508_000, 6196) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) - } - /// Storage: `Society::Candidates` (r:1 w:0) - /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::VoteClearCursor` (r:1 w:0) - /// Proof: `Society::VoteClearCursor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Votes` (r:2 w:2) - /// Proof: `Society::Votes` (`max_values`: None, `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Candidates (r:1 w:0) + // Storage: Society VoteClearCursor (r:1 w:0) + // Storage: Society Votes (r:0 w:2) fn cleanup_candidacy() -> Weight { - // Proof Size summary in bytes: - // Measured: `552` - // Estimated: `6492` - // Minimum execution time: 17_001_000 picoseconds. - Weight::from_parts(17_845_000, 6492) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) - } - /// Storage: `Society::ChallengeRoundCount` (r:1 w:0) - /// Proof: `Society::ChallengeRoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::DefenderVotes` (r:1 w:1) - /// Proof: `Society::DefenderVotes` (`max_values`: None, `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society ChallengeRoundCount (r:1 w:0) + // Storage: Society DefenderVotes (r:0 w:1) fn cleanup_challenge() -> Weight { - // Proof Size summary in bytes: - // Measured: `510` - // Estimated: `3975` - // Minimum execution time: 11_583_000 picoseconds. - Weight::from_parts(12_134_000, 3975) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + Weight::zero() } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Society::Bids` (r:1 w:1) - /// Proof: `Society::Bids` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Candidates` (r:1 w:0) - /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Members` (r:1 w:0) - /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::SuspendedMembers` (r:1 w:0) - /// Proof: `Society::SuspendedMembers` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Parameters` (r:1 w:0) - /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: Society Bids (r:1 w:1) + // Storage: Society Candidates (r:1 w:0) + // Storage: Society Members (r:1 w:0) + // Storage: Society SuspendedMembers (r:1 w:0) + // Storage: Society Parameters (r:1 w:0) fn bid() -> Weight { - // Proof Size summary in bytes: - // Measured: `444` - // Estimated: `3909` - // Minimum execution time: 29_905_000 picoseconds. - Weight::from_parts(31_031_000, 3909) - .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - /// Storage: `Society::Bids` (r:1 w:1) - /// Proof: `Society::Bids` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Bids (r:1 w:1) fn unbid() -> Weight { - // Proof Size summary in bytes: - // Measured: `461` - // Estimated: `1946` - // Minimum execution time: 23_038_000 picoseconds. - Weight::from_parts(23_904_000, 1946) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - /// Storage: `Society::Bids` (r:1 w:1) - /// Proof: `Society::Bids` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Candidates` (r:1 w:0) - /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Members` (r:2 w:1) - /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::SuspendedMembers` (r:1 w:0) - /// Proof: `Society::SuspendedMembers` (`max_values`: None, `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Bids (r:1 w:1) + // Storage: Society Candidates (r:1 w:0) + // Storage: Society Members (r:2 w:1) + // Storage: Society SuspendedMembers (r:1 w:0) fn vouch() -> Weight { - // Proof Size summary in bytes: - // Measured: `481` - // Estimated: `6421` - // Minimum execution time: 21_197_000 picoseconds. - Weight::from_parts(22_043_000, 6421) - .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) - } - /// Storage: `Society::Bids` (r:1 w:1) - /// Proof: `Society::Bids` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Members` (r:1 w:1) - /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Bids (r:1 w:1) + // Storage: Society Members (r:1 w:1) fn unvouch() -> Weight { - // Proof Size summary in bytes: - // Measured: `535` - // Estimated: `4000` - // Minimum execution time: 14_402_000 picoseconds. - Weight::from_parts(15_171_000, 4000) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) - } - /// Storage: `Society::Candidates` (r:1 w:1) - /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Members` (r:1 w:0) - /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Votes` (r:1 w:1) - /// Proof: `Society::Votes` (`max_values`: None, `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Candidates (r:1 w:1) + // Storage: Society Members (r:1 w:0) + // Storage: Society Votes (r:1 w:1) fn vote() -> Weight { - // Proof Size summary in bytes: - // Measured: `569` - // Estimated: `4034` - // Minimum execution time: 21_930_000 picoseconds. - Weight::from_parts(22_666_000, 4034) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) - } - /// Storage: `Society::Defending` (r:1 w:1) - /// Proof: `Society::Defending` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Members` (r:1 w:0) - /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::ChallengeRoundCount` (r:1 w:0) - /// Proof: `Society::ChallengeRoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::DefenderVotes` (r:1 w:1) - /// Proof: `Society::DefenderVotes` (`max_values`: None, `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Defending (r:1 w:1) + // Storage: Society Members (r:1 w:0) + // Storage: Society ChallengeRoundCount (r:1 w:0) + // Storage: Society DefenderVotes (r:1 w:1) fn defender_vote() -> Weight { - // Proof Size summary in bytes: - // Measured: `561` - // Estimated: `4026` - // Minimum execution time: 18_821_000 picoseconds. - Weight::from_parts(19_633_000, 4026) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) - } - /// Storage: `Society::Members` (r:1 w:0) - /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Payouts` (r:1 w:1) - /// Proof: `Society::Payouts` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + Weight::zero() + } + // Storage: Society Members (r:1 w:0) + // Storage: Society Payouts (r:1 w:1) + // Storage: System Account (r:1 w:1) fn payout() -> Weight { - // Proof Size summary in bytes: - // Measured: `650` - // Estimated: `4115` - // Minimum execution time: 47_262_000 picoseconds. - Weight::from_parts(48_313_000, 4115) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) - } - /// Storage: `Society::Members` (r:1 w:1) - /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Payouts` (r:1 w:1) - /// Proof: `Society::Payouts` (`max_values`: None, `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Members (r:1 w:1) + // Storage: Society Payouts (r:1 w:1) fn waive_repay() -> Weight { - // Proof Size summary in bytes: - // Measured: `547` - // Estimated: `4012` - // Minimum execution time: 18_189_000 picoseconds. - Weight::from_parts(19_038_000, 4012) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) - } - /// Storage: `Society::Head` (r:1 w:1) - /// Proof: `Society::Head` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::MemberCount` (r:1 w:1) - /// Proof: `Society::MemberCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::MemberByIndex` (r:0 w:1) - /// Proof: `Society::MemberByIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Founder` (r:0 w:1) - /// Proof: `Society::Founder` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Rules` (r:0 w:1) - /// Proof: `Society::Rules` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Members` (r:0 w:1) - /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Parameters` (r:0 w:1) - /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Head (r:1 w:1) + // Storage: Society MemberCount (r:1 w:1) + // Storage: Society MemberByIndex (r:0 w:1) + // Storage: Society Founder (r:0 w:1) + // Storage: Society Rules (r:0 w:1) + // Storage: Society Members (r:0 w:1) + // Storage: Society Parameters (r:0 w:1) fn found_society() -> Weight { - // Proof Size summary in bytes: - // Measured: `180` - // Estimated: `1665` - // Minimum execution time: 14_815_000 picoseconds. - Weight::from_parts(15_426_000, 1665) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) - } - /// Storage: `Society::Founder` (r:1 w:1) - /// Proof: `Society::Founder` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::MemberCount` (r:1 w:1) - /// Proof: `Society::MemberCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Members` (r:5 w:5) - /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::MemberByIndex` (r:5 w:5) - /// Proof: `Society::MemberByIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Votes` (r:4 w:4) - /// Proof: `Society::Votes` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Candidates` (r:4 w:4) - /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Head` (r:0 w:1) - /// Proof: `Society::Head` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Defending` (r:0 w:1) - /// Proof: `Society::Defending` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::ChallengeRoundCount` (r:0 w:1) - /// Proof: `Society::ChallengeRoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Skeptic` (r:0 w:1) - /// Proof: `Society::Skeptic` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Pot` (r:0 w:1) - /// Proof: `Society::Pot` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Rules` (r:0 w:1) - /// Proof: `Society::Rules` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::RoundCount` (r:0 w:1) - /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Bids` (r:0 w:1) - /// Proof: `Society::Bids` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Parameters` (r:0 w:1) - /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::NextHead` (r:0 w:1) - /// Proof: `Society::NextHead` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Founder (r:1 w:1) + // Storage: Society MemberCount (r:1 w:1) + // Storage: Society Head (r:0 w:1) + // Storage: Society Defending (r:0 w:1) + // Storage: Society ChallengeRoundCount (r:0 w:1) + // Storage: Society MemberByIndex (r:0 w:5) + // Storage: Society Skeptic (r:0 w:1) + // Storage: Society Candidates (r:0 w:4) + // Storage: Society Pot (r:0 w:1) + // Storage: Society Rules (r:0 w:1) + // Storage: Society Votes (r:0 w:4) + // Storage: Society Members (r:0 w:5) + // Storage: Society RoundCount (r:0 w:1) + // Storage: Society Bids (r:0 w:1) + // Storage: Society Parameters (r:0 w:1) + // Storage: Society NextHead (r:0 w:1) fn dissolve() -> Weight { - // Proof Size summary in bytes: - // Measured: `1654` - // Estimated: `15019` - // Minimum execution time: 57_787_000 picoseconds. - Weight::from_parts(59_489_000, 15019) - .saturating_add(RocksDbWeight::get().reads(20_u64)) - .saturating_add(RocksDbWeight::get().writes(30_u64)) - } - /// Storage: `Society::Founder` (r:1 w:0) - /// Proof: `Society::Founder` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::SuspendedMembers` (r:1 w:1) - /// Proof: `Society::SuspendedMembers` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Payouts` (r:1 w:0) - /// Proof: `Society::Payouts` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Pot` (r:1 w:1) - /// Proof: `Society::Pot` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Founder (r:1 w:0) + // Storage: Society SuspendedMembers (r:1 w:1) + // Storage: Society Payouts (r:1 w:0) + // Storage: Society Pot (r:1 w:1) fn judge_suspended_member() -> Weight { - // Proof Size summary in bytes: - // Measured: `505` - // Estimated: `3970` - // Minimum execution time: 19_262_000 picoseconds. - Weight::from_parts(19_752_000, 3970) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) - } - /// Storage: `Society::Founder` (r:1 w:0) - /// Proof: `Society::Founder` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::MemberCount` (r:1 w:0) - /// Proof: `Society::MemberCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Parameters` (r:0 w:1) - /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Founder (r:1 w:0) + // Storage: Society MemberCount (r:1 w:0) + // Storage: Society Parameters (r:0 w:1) fn set_parameters() -> Weight { - // Proof Size summary in bytes: - // Measured: `387` - // Estimated: `1872` - // Minimum execution time: 10_656_000 picoseconds. - Weight::from_parts(11_063_000, 1872) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - /// Storage: `Society::Candidates` (r:1 w:1) - /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::RoundCount` (r:1 w:0) - /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Skeptic` (r:1 w:0) - /// Proof: `Society::Skeptic` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Votes` (r:1 w:0) - /// Proof: `Society::Votes` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Members` (r:1 w:1) - /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Parameters` (r:1 w:0) - /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Candidates (r:1 w:1) + // Storage: Society RoundCount (r:1 w:0) + // Storage: Society Skeptic (r:1 w:0) + // Storage: Society Votes (r:1 w:0) + // Storage: Society Members (r:1 w:1) + // Storage: Society Parameters (r:1 w:0) fn punish_skeptic() -> Weight { - // Proof Size summary in bytes: - // Measured: `636` - // Estimated: `4101` - // Minimum execution time: 22_837_000 picoseconds. - Weight::from_parts(23_738_000, 4101) - .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) - } - /// Storage: `Society::Candidates` (r:1 w:1) - /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::RoundCount` (r:1 w:0) - /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Parameters` (r:1 w:0) - /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::MemberCount` (r:1 w:1) - /// Proof: `Society::MemberCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::NextHead` (r:1 w:1) - /// Proof: `Society::NextHead` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Society::MemberByIndex` (r:0 w:1) - /// Proof: `Society::MemberByIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Members` (r:0 w:1) - /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Candidates (r:1 w:1) + // Storage: Society RoundCount (r:1 w:0) + // Storage: Society Parameters (r:1 w:0) + // Storage: Society MemberCount (r:1 w:1) + // Storage: Society NextHead (r:1 w:1) + // Storage: System Account (r:1 w:1) + // Storage: Society MemberByIndex (r:0 w:1) + // Storage: Society Members (r:0 w:1) fn claim_membership() -> Weight { - // Proof Size summary in bytes: - // Measured: `632` - // Estimated: `4097` - // Minimum execution time: 35_142_000 picoseconds. - Weight::from_parts(36_811_000, 4097) - .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().writes(6_u64)) - } - /// Storage: `Society::Founder` (r:1 w:0) - /// Proof: `Society::Founder` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Candidates` (r:1 w:1) - /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::RoundCount` (r:1 w:0) - /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Parameters` (r:1 w:0) - /// Proof: `Society::Parameters` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::MemberCount` (r:1 w:1) - /// Proof: `Society::MemberCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::NextHead` (r:1 w:1) - /// Proof: `Society::NextHead` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Society::MemberByIndex` (r:0 w:1) - /// Proof: `Society::MemberByIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Members` (r:0 w:1) - /// Proof: `Society::Members` (`max_values`: None, `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Founder (r:1 w:0) + // Storage: Society Candidates (r:1 w:1) + // Storage: Society RoundCount (r:1 w:0) + // Storage: Society Parameters (r:1 w:0) + // Storage: Society MemberCount (r:1 w:1) + // Storage: Society NextHead (r:1 w:1) + // Storage: System Account (r:1 w:1) + // Storage: Society MemberByIndex (r:0 w:1) + // Storage: Society Members (r:0 w:1) fn bestow_membership() -> Weight { - // Proof Size summary in bytes: - // Measured: `650` - // Estimated: `4115` - // Minimum execution time: 37_133_000 picoseconds. - Weight::from_parts(38_366_000, 4115) - .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().writes(6_u64)) - } - /// Storage: `Society::Founder` (r:1 w:0) - /// Proof: `Society::Founder` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::Candidates` (r:1 w:1) - /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::RoundCount` (r:1 w:0) - /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + Weight::zero() + } + // Storage: Society Founder (r:1 w:0) + // Storage: Society Candidates (r:1 w:1) + // Storage: Society RoundCount (r:1 w:0) fn kick_candidate() -> Weight { - // Proof Size summary in bytes: - // Measured: `776` - // Estimated: `6196` - // Minimum execution time: 37_033_000 picoseconds. - Weight::from_parts(38_293_000, 6196) - .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) - } - /// Storage: `Society::Candidates` (r:1 w:1) - /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::RoundCount` (r:1 w:0) - /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + Weight::zero() + } + // Storage: Society Candidates (r:1 w:1) + // Storage: Society RoundCount (r:1 w:0) fn resign_candidacy() -> Weight { - // Proof Size summary in bytes: - // Measured: `746` - // Estimated: `6196` - // Minimum execution time: 35_203_000 picoseconds. - Weight::from_parts(36_252_000, 6196) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) - } - /// Storage: `Society::Candidates` (r:1 w:1) - /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::RoundCount` (r:1 w:0) - /// Proof: `Society::RoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + Weight::zero() + } + // Storage: Society Candidates (r:1 w:1) + // Storage: Society RoundCount (r:1 w:0) fn drop_candidate() -> Weight { - // Proof Size summary in bytes: - // Measured: `758` - // Estimated: `6196` - // Minimum execution time: 35_518_000 picoseconds. - Weight::from_parts(36_508_000, 6196) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) - } - /// Storage: `Society::Candidates` (r:1 w:0) - /// Proof: `Society::Candidates` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::VoteClearCursor` (r:1 w:0) - /// Proof: `Society::VoteClearCursor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Society::Votes` (r:2 w:2) - /// Proof: `Society::Votes` (`max_values`: None, `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society Candidates (r:1 w:0) + // Storage: Society VoteClearCursor (r:1 w:0) + // Storage: Society Votes (r:0 w:2) fn cleanup_candidacy() -> Weight { - // Proof Size summary in bytes: - // Measured: `552` - // Estimated: `6492` - // Minimum execution time: 17_001_000 picoseconds. - Weight::from_parts(17_845_000, 6492) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) - } - /// Storage: `Society::ChallengeRoundCount` (r:1 w:0) - /// Proof: `Society::ChallengeRoundCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Society::DefenderVotes` (r:1 w:1) - /// Proof: `Society::DefenderVotes` (`max_values`: None, `max_size`: None, mode: `Measured`) + Weight::zero() + } + // Storage: Society ChallengeRoundCount (r:1 w:0) + // Storage: Society DefenderVotes (r:0 w:1) fn cleanup_challenge() -> Weight { - // Proof Size summary in bytes: - // Measured: `510` - // Estimated: `3975` - // Minimum execution time: 11_583_000 picoseconds. - Weight::from_parts(12_134_000, 3975) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + Weight::zero() } } diff --git a/substrate/frame/src/lib.rs b/substrate/frame/src/lib.rs index 549e177491d..52db7c34bfd 100644 --- a/substrate/frame/src/lib.rs +++ b/substrate/frame/src/lib.rs @@ -249,8 +249,8 @@ pub mod runtime { /// The block type, which should be fed into [`frame_system::Config`]. /// - /// Should be parameterized with `T: frame_system::Config` and a tuple of - /// `TransactionExtension`. When in doubt, use [`SystemTransactionExtensionsOf`]. + /// Should be parameterized with `T: frame_system::Config` and a tuple of `SignedExtension`. + /// When in doubt, use [`SystemSignedExtensionsOf`]. // Note that this cannot be dependent on `T` for block-number because it would lead to a // circular dependency (self-referential generics). pub type BlockOf = generic::Block>; @@ -264,7 +264,7 @@ pub mod runtime { /// Default set of signed extensions exposed from the `frame_system`. /// /// crucially, this does NOT contain any tx-payment extension. - pub type SystemTransactionExtensionsOf = ( + pub type SystemSignedExtensionsOf = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, diff --git a/substrate/frame/staking/src/weights.rs b/substrate/frame/staking/src/weights.rs index 8288591a787..6f729e08ba5 100644 --- a/substrate/frame/staking/src/weights.rs +++ b/substrate/frame/staking/src/weights.rs @@ -17,28 +17,26 @@ //! Autogenerated weights for `pallet_staking` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2024-01-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-q7z7ruxr-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/production/substrate-node +// target/production/substrate-node // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_staking -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/staking/src/weights.rs +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_staking +// --chain=dev // --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/staking/src/weights.rs // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -101,8 +99,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `927` // Estimated: `4764` - // Minimum execution time: 41_318_000 picoseconds. - Weight::from_parts(43_268_000, 4764) + // Minimum execution time: 42_042_000 picoseconds. + Weight::from_parts(43_292_000, 4764) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -122,8 +120,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1990` // Estimated: `8877` - // Minimum execution time: 85_666_000 picoseconds. - Weight::from_parts(88_749_000, 8877) + // Minimum execution time: 85_050_000 picoseconds. + Weight::from_parts(87_567_000, 8877) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -149,8 +147,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2195` // Estimated: `8877` - // Minimum execution time: 90_282_000 picoseconds. - Weight::from_parts(92_332_000, 8877) + // Minimum execution time: 89_076_000 picoseconds. + Weight::from_parts(92_715_000, 8877) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -164,18 +162,16 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:0) - /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1297` + // Measured: `1115` // Estimated: `4764` - // Minimum execution time: 44_626_000 picoseconds. - Weight::from_parts(47_254_657, 4764) - // Standard Error: 1_179 - .saturating_add(Weight::from_parts(57_657, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(6_u64)) + // Minimum execution time: 42_067_000 picoseconds. + Weight::from_parts(43_239_807, 4764) + // Standard Error: 831 + .saturating_add(Weight::from_parts(46_257, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) @@ -211,10 +207,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 86_769_000 picoseconds. - Weight::from_parts(95_212_867, 6248) - // Standard Error: 3_706 - .saturating_add(Weight::from_parts(1_320_752, 0).saturating_mul(s.into())) + // Minimum execution time: 86_490_000 picoseconds. + Weight::from_parts(95_358_751, 6248) + // Standard Error: 3_952 + .saturating_add(Weight::from_parts(1_294_907, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(11_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -246,8 +242,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1372` // Estimated: `4556` - // Minimum execution time: 50_410_000 picoseconds. - Weight::from_parts(52_576_000, 4556) + // Minimum execution time: 50_326_000 picoseconds. + Weight::from_parts(52_253_000, 4556) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -260,10 +256,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1280 + k * (569 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 29_017_000 picoseconds. - Weight::from_parts(33_019_206, 4556) - // Standard Error: 6_368 - .saturating_add(Weight::from_parts(6_158_681, 0).saturating_mul(k.into())) + // Minimum execution time: 29_305_000 picoseconds. + Weight::from_parts(32_199_604, 4556) + // Standard Error: 7_150 + .saturating_add(Weight::from_parts(6_437_124, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -296,10 +292,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1866 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 63_452_000 picoseconds. - Weight::from_parts(60_924_066, 6248) - // Standard Error: 14_416 - .saturating_add(Weight::from_parts(3_921_589, 0).saturating_mul(n.into())) + // Minimum execution time: 63_267_000 picoseconds. + Weight::from_parts(61_741_404, 6248) + // Standard Error: 12_955 + .saturating_add(Weight::from_parts(3_811_743, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) @@ -323,8 +319,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1650` // Estimated: `6248` - // Minimum execution time: 54_253_000 picoseconds. - Weight::from_parts(55_286_000, 6248) + // Minimum execution time: 52_862_000 picoseconds. + Weight::from_parts(54_108_000, 6248) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -338,8 +334,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `902` // Estimated: `4556` - // Minimum execution time: 16_812_000 picoseconds. - Weight::from_parts(17_380_000, 4556) + // Minimum execution time: 16_350_000 picoseconds. + Weight::from_parts(16_802_000, 4556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -353,8 +349,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `969` // Estimated: `4556` - // Minimum execution time: 20_590_000 picoseconds. - Weight::from_parts(21_096_000, 4556) + // Minimum execution time: 19_981_000 picoseconds. + Weight::from_parts(20_539_000, 4556) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -366,8 +362,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `902` // Estimated: `4556` - // Minimum execution time: 19_923_000 picoseconds. - Weight::from_parts(20_880_000, 4556) + // Minimum execution time: 19_304_000 picoseconds. + Weight::from_parts(20_000_000, 4556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -377,8 +373,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_599_000 picoseconds. - Weight::from_parts(2_751_000, 0) + // Minimum execution time: 2_568_000 picoseconds. + Weight::from_parts(2_708_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -387,8 +383,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_941_000 picoseconds. - Weight::from_parts(7_288_000, 0) + // Minimum execution time: 7_950_000 picoseconds. + Weight::from_parts(8_348_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -397,8 +393,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_757_000 picoseconds. - Weight::from_parts(7_200_000, 0) + // Minimum execution time: 7_967_000 picoseconds. + Weight::from_parts(8_222_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -407,8 +403,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_028_000 picoseconds. - Weight::from_parts(7_366_000, 0) + // Minimum execution time: 8_006_000 picoseconds. + Weight::from_parts(8_440_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::Invulnerables` (r:0 w:1) @@ -418,10 +414,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_741_000 picoseconds. - Weight::from_parts(3_212_598, 0) - // Standard Error: 68 - .saturating_add(Weight::from_parts(11_695, 0).saturating_mul(v.into())) + // Minimum execution time: 2_524_000 picoseconds. + Weight::from_parts(3_123_608, 0) + // Standard Error: 59 + .saturating_add(Weight::from_parts(11_596, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::Ledger` (r:5900 w:11800) @@ -435,10 +431,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1356 + i * (151 ±0)` // Estimated: `990 + i * (3566 ±0)` - // Minimum execution time: 2_132_000 picoseconds. - Weight::from_parts(2_289_000, 990) - // Standard Error: 34_227 - .saturating_add(Weight::from_parts(17_006_583, 0).saturating_mul(i.into())) + // Minimum execution time: 2_092_000 picoseconds. + Weight::from_parts(2_258_000, 990) + // Standard Error: 32_695 + .saturating_add(Weight::from_parts(16_669_219, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_parts(0, 3566).saturating_mul(i.into())) @@ -476,10 +472,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 85_308_000 picoseconds. - Weight::from_parts(93_689_468, 6248) - // Standard Error: 5_425 - .saturating_add(Weight::from_parts(1_307_604, 0).saturating_mul(s.into())) + // Minimum execution time: 84_275_000 picoseconds. + Weight::from_parts(92_512_416, 6248) + // Standard Error: 3_633 + .saturating_add(Weight::from_parts(1_315_923, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -492,10 +488,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `66672` // Estimated: `70137` - // Minimum execution time: 103_242_000 picoseconds. - Weight::from_parts(1_162_296_080, 70137) - // Standard Error: 76_741 - .saturating_add(Weight::from_parts(6_487_522, 0).saturating_mul(s.into())) + // Minimum execution time: 101_707_000 picoseconds. + Weight::from_parts(912_819_462, 70137) + // Standard Error: 57_547 + .saturating_add(Weight::from_parts(4_856_799, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -532,10 +528,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `33297 + n * (377 ±0)` // Estimated: `30944 + n * (3774 ±0)` - // Minimum execution time: 140_740_000 picoseconds. - Weight::from_parts(182_886_963, 30944) - // Standard Error: 39_852 - .saturating_add(Weight::from_parts(43_140_752, 0).saturating_mul(n.into())) + // Minimum execution time: 138_657_000 picoseconds. + Weight::from_parts(167_173_445, 30944) + // Standard Error: 25_130 + .saturating_add(Weight::from_parts(44_566_012, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(14_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -559,10 +555,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1991 + l * (7 ±0)` // Estimated: `8877` - // Minimum execution time: 80_372_000 picoseconds. - Weight::from_parts(83_335_027, 8877) - // Standard Error: 4_780 - .saturating_add(Weight::from_parts(72_180, 0).saturating_mul(l.into())) + // Minimum execution time: 80_061_000 picoseconds. + Weight::from_parts(82_836_434, 8877) + // Standard Error: 4_348 + .saturating_add(Weight::from_parts(75_744, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -597,10 +593,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 93_920_000 picoseconds. - Weight::from_parts(98_022_911, 6248) - // Standard Error: 4_096 - .saturating_add(Weight::from_parts(1_287_745, 0).saturating_mul(s.into())) + // Minimum execution time: 92_560_000 picoseconds. + Weight::from_parts(97_684_741, 6248) + // Standard Error: 3_361 + .saturating_add(Weight::from_parts(1_292_732, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(11_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -646,12 +642,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0 + n * (720 ±0) + v * (3598 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 556_012_000 picoseconds. - Weight::from_parts(560_339_000, 512390) - // Standard Error: 2_115_076 - .saturating_add(Weight::from_parts(69_456_497, 0).saturating_mul(v.into())) - // Standard Error: 210_755 - .saturating_add(Weight::from_parts(17_974_873, 0).saturating_mul(n.into())) + // Minimum execution time: 564_963_000 picoseconds. + Weight::from_parts(569_206_000, 512390) + // Standard Error: 2_033_235 + .saturating_add(Weight::from_parts(68_025_841, 0).saturating_mul(v.into())) + // Standard Error: 202_600 + .saturating_add(Weight::from_parts(17_916_770, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(206_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -682,12 +678,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3175 + n * (911 ±0) + v * (395 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 32_792_819_000 picoseconds. - Weight::from_parts(32_986_606_000, 512390) - // Standard Error: 360_905 - .saturating_add(Weight::from_parts(5_260_151, 0).saturating_mul(v.into())) - // Standard Error: 360_905 - .saturating_add(Weight::from_parts(3_599_219, 0).saturating_mul(n.into())) + // Minimum execution time: 32_196_540_000 picoseconds. + Weight::from_parts(32_341_871_000, 512390) + // Standard Error: 354_657 + .saturating_add(Weight::from_parts(5_143_440, 0).saturating_mul(v.into())) + // Standard Error: 354_657 + .saturating_add(Weight::from_parts(3_328_189, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(201_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -704,10 +700,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `979 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_434_755_000 picoseconds. - Weight::from_parts(38_574_764, 3510) - // Standard Error: 14_467 - .saturating_add(Weight::from_parts(4_821_702, 0).saturating_mul(v.into())) + // Minimum execution time: 2_381_903_000 picoseconds. + Weight::from_parts(32_693_059, 3510) + // Standard Error: 10_000 + .saturating_add(Weight::from_parts(4_736_173, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -718,8 +714,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxValidatorsCount` (r:0 w:1) /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::MaxStakedRewards` (r:0 w:1) - /// Proof: `Staking::MaxStakedRewards` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::ChillThreshold` (r:0 w:1) /// Proof: `Staking::ChillThreshold` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxNominatorsCount` (r:0 w:1) @@ -730,9 +724,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_765_000 picoseconds. - Weight::from_parts(6_140_000, 0) - .saturating_add(T::DbWeight::get().writes(7_u64)) + // Minimum execution time: 5_434_000 picoseconds. + Weight::from_parts(5_742_000, 0) + .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: `Staking::MinCommission` (r:0 w:1) /// Proof: `Staking::MinCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -740,8 +734,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxValidatorsCount` (r:0 w:1) /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::MaxStakedRewards` (r:0 w:1) - /// Proof: `Staking::MaxStakedRewards` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::ChillThreshold` (r:0 w:1) /// Proof: `Staking::ChillThreshold` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxNominatorsCount` (r:0 w:1) @@ -752,9 +744,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_025_000 picoseconds. - Weight::from_parts(5_354_000, 0) - .saturating_add(T::DbWeight::get().writes(7_u64)) + // Minimum execution time: 4_588_000 picoseconds. + Weight::from_parts(4_854_000, 0) + .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) @@ -782,8 +774,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1939` // Estimated: `6248` - // Minimum execution time: 69_656_000 picoseconds. - Weight::from_parts(71_574_000, 6248) + // Minimum execution time: 68_780_000 picoseconds. + Weight::from_parts(71_479_000, 6248) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -795,8 +787,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `691` // Estimated: `3510` - // Minimum execution time: 12_523_000 picoseconds. - Weight::from_parts(13_315_000, 3510) + // Minimum execution time: 12_268_000 picoseconds. + Weight::from_parts(12_661_000, 3510) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -806,8 +798,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_125_000 picoseconds. - Weight::from_parts(3_300_000, 0) + // Minimum execution time: 3_071_000 picoseconds. + Weight::from_parts(3_334_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } } @@ -828,8 +820,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `927` // Estimated: `4764` - // Minimum execution time: 41_318_000 picoseconds. - Weight::from_parts(43_268_000, 4764) + // Minimum execution time: 42_042_000 picoseconds. + Weight::from_parts(43_292_000, 4764) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -849,8 +841,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1990` // Estimated: `8877` - // Minimum execution time: 85_666_000 picoseconds. - Weight::from_parts(88_749_000, 8877) + // Minimum execution time: 85_050_000 picoseconds. + Weight::from_parts(87_567_000, 8877) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -876,8 +868,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2195` // Estimated: `8877` - // Minimum execution time: 90_282_000 picoseconds. - Weight::from_parts(92_332_000, 8877) + // Minimum execution time: 89_076_000 picoseconds. + Weight::from_parts(92_715_000, 8877) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -891,18 +883,16 @@ impl WeightInfo for () { /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:0) - /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1297` + // Measured: `1115` // Estimated: `4764` - // Minimum execution time: 44_626_000 picoseconds. - Weight::from_parts(47_254_657, 4764) - // Standard Error: 1_179 - .saturating_add(Weight::from_parts(57_657, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(6_u64)) + // Minimum execution time: 42_067_000 picoseconds. + Weight::from_parts(43_239_807, 4764) + // Standard Error: 831 + .saturating_add(Weight::from_parts(46_257, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) @@ -938,10 +928,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 86_769_000 picoseconds. - Weight::from_parts(95_212_867, 6248) - // Standard Error: 3_706 - .saturating_add(Weight::from_parts(1_320_752, 0).saturating_mul(s.into())) + // Minimum execution time: 86_490_000 picoseconds. + Weight::from_parts(95_358_751, 6248) + // Standard Error: 3_952 + .saturating_add(Weight::from_parts(1_294_907, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(11_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -973,8 +963,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1372` // Estimated: `4556` - // Minimum execution time: 50_410_000 picoseconds. - Weight::from_parts(52_576_000, 4556) + // Minimum execution time: 50_326_000 picoseconds. + Weight::from_parts(52_253_000, 4556) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -987,10 +977,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1280 + k * (569 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 29_017_000 picoseconds. - Weight::from_parts(33_019_206, 4556) - // Standard Error: 6_368 - .saturating_add(Weight::from_parts(6_158_681, 0).saturating_mul(k.into())) + // Minimum execution time: 29_305_000 picoseconds. + Weight::from_parts(32_199_604, 4556) + // Standard Error: 7_150 + .saturating_add(Weight::from_parts(6_437_124, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -1023,10 +1013,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1866 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 63_452_000 picoseconds. - Weight::from_parts(60_924_066, 6248) - // Standard Error: 14_416 - .saturating_add(Weight::from_parts(3_921_589, 0).saturating_mul(n.into())) + // Minimum execution time: 63_267_000 picoseconds. + Weight::from_parts(61_741_404, 6248) + // Standard Error: 12_955 + .saturating_add(Weight::from_parts(3_811_743, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) @@ -1050,8 +1040,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1650` // Estimated: `6248` - // Minimum execution time: 54_253_000 picoseconds. - Weight::from_parts(55_286_000, 6248) + // Minimum execution time: 52_862_000 picoseconds. + Weight::from_parts(54_108_000, 6248) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1065,8 +1055,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `902` // Estimated: `4556` - // Minimum execution time: 16_812_000 picoseconds. - Weight::from_parts(17_380_000, 4556) + // Minimum execution time: 16_350_000 picoseconds. + Weight::from_parts(16_802_000, 4556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1080,8 +1070,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `969` // Estimated: `4556` - // Minimum execution time: 20_590_000 picoseconds. - Weight::from_parts(21_096_000, 4556) + // Minimum execution time: 19_981_000 picoseconds. + Weight::from_parts(20_539_000, 4556) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1093,8 +1083,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `902` // Estimated: `4556` - // Minimum execution time: 19_923_000 picoseconds. - Weight::from_parts(20_880_000, 4556) + // Minimum execution time: 19_304_000 picoseconds. + Weight::from_parts(20_000_000, 4556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1104,8 +1094,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_599_000 picoseconds. - Weight::from_parts(2_751_000, 0) + // Minimum execution time: 2_568_000 picoseconds. + Weight::from_parts(2_708_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1114,8 +1104,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_941_000 picoseconds. - Weight::from_parts(7_288_000, 0) + // Minimum execution time: 7_950_000 picoseconds. + Weight::from_parts(8_348_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1124,8 +1114,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_757_000 picoseconds. - Weight::from_parts(7_200_000, 0) + // Minimum execution time: 7_967_000 picoseconds. + Weight::from_parts(8_222_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1134,8 +1124,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_028_000 picoseconds. - Weight::from_parts(7_366_000, 0) + // Minimum execution time: 8_006_000 picoseconds. + Weight::from_parts(8_440_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::Invulnerables` (r:0 w:1) @@ -1145,10 +1135,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_741_000 picoseconds. - Weight::from_parts(3_212_598, 0) - // Standard Error: 68 - .saturating_add(Weight::from_parts(11_695, 0).saturating_mul(v.into())) + // Minimum execution time: 2_524_000 picoseconds. + Weight::from_parts(3_123_608, 0) + // Standard Error: 59 + .saturating_add(Weight::from_parts(11_596, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::Ledger` (r:5900 w:11800) @@ -1162,10 +1152,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1356 + i * (151 ±0)` // Estimated: `990 + i * (3566 ±0)` - // Minimum execution time: 2_132_000 picoseconds. - Weight::from_parts(2_289_000, 990) - // Standard Error: 34_227 - .saturating_add(Weight::from_parts(17_006_583, 0).saturating_mul(i.into())) + // Minimum execution time: 2_092_000 picoseconds. + Weight::from_parts(2_258_000, 990) + // Standard Error: 32_695 + .saturating_add(Weight::from_parts(16_669_219, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_parts(0, 3566).saturating_mul(i.into())) @@ -1203,10 +1193,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 85_308_000 picoseconds. - Weight::from_parts(93_689_468, 6248) - // Standard Error: 5_425 - .saturating_add(Weight::from_parts(1_307_604, 0).saturating_mul(s.into())) + // Minimum execution time: 84_275_000 picoseconds. + Weight::from_parts(92_512_416, 6248) + // Standard Error: 3_633 + .saturating_add(Weight::from_parts(1_315_923, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -1219,10 +1209,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `66672` // Estimated: `70137` - // Minimum execution time: 103_242_000 picoseconds. - Weight::from_parts(1_162_296_080, 70137) - // Standard Error: 76_741 - .saturating_add(Weight::from_parts(6_487_522, 0).saturating_mul(s.into())) + // Minimum execution time: 101_707_000 picoseconds. + Weight::from_parts(912_819_462, 70137) + // Standard Error: 57_547 + .saturating_add(Weight::from_parts(4_856_799, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1259,10 +1249,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `33297 + n * (377 ±0)` // Estimated: `30944 + n * (3774 ±0)` - // Minimum execution time: 140_740_000 picoseconds. - Weight::from_parts(182_886_963, 30944) - // Standard Error: 39_852 - .saturating_add(Weight::from_parts(43_140_752, 0).saturating_mul(n.into())) + // Minimum execution time: 138_657_000 picoseconds. + Weight::from_parts(167_173_445, 30944) + // Standard Error: 25_130 + .saturating_add(Weight::from_parts(44_566_012, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(14_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -1286,10 +1276,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1991 + l * (7 ±0)` // Estimated: `8877` - // Minimum execution time: 80_372_000 picoseconds. - Weight::from_parts(83_335_027, 8877) - // Standard Error: 4_780 - .saturating_add(Weight::from_parts(72_180, 0).saturating_mul(l.into())) + // Minimum execution time: 80_061_000 picoseconds. + Weight::from_parts(82_836_434, 8877) + // Standard Error: 4_348 + .saturating_add(Weight::from_parts(75_744, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -1324,10 +1314,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 93_920_000 picoseconds. - Weight::from_parts(98_022_911, 6248) - // Standard Error: 4_096 - .saturating_add(Weight::from_parts(1_287_745, 0).saturating_mul(s.into())) + // Minimum execution time: 92_560_000 picoseconds. + Weight::from_parts(97_684_741, 6248) + // Standard Error: 3_361 + .saturating_add(Weight::from_parts(1_292_732, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(11_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -1373,12 +1363,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0 + n * (720 ±0) + v * (3598 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 556_012_000 picoseconds. - Weight::from_parts(560_339_000, 512390) - // Standard Error: 2_115_076 - .saturating_add(Weight::from_parts(69_456_497, 0).saturating_mul(v.into())) - // Standard Error: 210_755 - .saturating_add(Weight::from_parts(17_974_873, 0).saturating_mul(n.into())) + // Minimum execution time: 564_963_000 picoseconds. + Weight::from_parts(569_206_000, 512390) + // Standard Error: 2_033_235 + .saturating_add(Weight::from_parts(68_025_841, 0).saturating_mul(v.into())) + // Standard Error: 202_600 + .saturating_add(Weight::from_parts(17_916_770, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(206_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -1409,12 +1399,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3175 + n * (911 ±0) + v * (395 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 32_792_819_000 picoseconds. - Weight::from_parts(32_986_606_000, 512390) - // Standard Error: 360_905 - .saturating_add(Weight::from_parts(5_260_151, 0).saturating_mul(v.into())) - // Standard Error: 360_905 - .saturating_add(Weight::from_parts(3_599_219, 0).saturating_mul(n.into())) + // Minimum execution time: 32_196_540_000 picoseconds. + Weight::from_parts(32_341_871_000, 512390) + // Standard Error: 354_657 + .saturating_add(Weight::from_parts(5_143_440, 0).saturating_mul(v.into())) + // Standard Error: 354_657 + .saturating_add(Weight::from_parts(3_328_189, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(201_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -1431,10 +1421,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `979 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_434_755_000 picoseconds. - Weight::from_parts(38_574_764, 3510) - // Standard Error: 14_467 - .saturating_add(Weight::from_parts(4_821_702, 0).saturating_mul(v.into())) + // Minimum execution time: 2_381_903_000 picoseconds. + Weight::from_parts(32_693_059, 3510) + // Standard Error: 10_000 + .saturating_add(Weight::from_parts(4_736_173, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -1445,8 +1435,6 @@ impl WeightInfo for () { /// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxValidatorsCount` (r:0 w:1) /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::MaxStakedRewards` (r:0 w:1) - /// Proof: `Staking::MaxStakedRewards` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::ChillThreshold` (r:0 w:1) /// Proof: `Staking::ChillThreshold` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxNominatorsCount` (r:0 w:1) @@ -1457,9 +1445,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_765_000 picoseconds. - Weight::from_parts(6_140_000, 0) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + // Minimum execution time: 5_434_000 picoseconds. + Weight::from_parts(5_742_000, 0) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: `Staking::MinCommission` (r:0 w:1) /// Proof: `Staking::MinCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -1467,8 +1455,6 @@ impl WeightInfo for () { /// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxValidatorsCount` (r:0 w:1) /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::MaxStakedRewards` (r:0 w:1) - /// Proof: `Staking::MaxStakedRewards` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::ChillThreshold` (r:0 w:1) /// Proof: `Staking::ChillThreshold` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxNominatorsCount` (r:0 w:1) @@ -1479,9 +1465,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_025_000 picoseconds. - Weight::from_parts(5_354_000, 0) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + // Minimum execution time: 4_588_000 picoseconds. + Weight::from_parts(4_854_000, 0) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) @@ -1509,8 +1495,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1939` // Estimated: `6248` - // Minimum execution time: 69_656_000 picoseconds. - Weight::from_parts(71_574_000, 6248) + // Minimum execution time: 68_780_000 picoseconds. + Weight::from_parts(71_479_000, 6248) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1522,8 +1508,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `691` // Estimated: `3510` - // Minimum execution time: 12_523_000 picoseconds. - Weight::from_parts(13_315_000, 3510) + // Minimum execution time: 12_268_000 picoseconds. + Weight::from_parts(12_661_000, 3510) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1533,8 +1519,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_125_000 picoseconds. - Weight::from_parts(3_300_000, 0) + // Minimum execution time: 3_071_000 picoseconds. + Weight::from_parts(3_334_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } diff --git a/substrate/frame/state-trie-migration/src/lib.rs b/substrate/frame/state-trie-migration/src/lib.rs index b89159ef3ec..6b3aa9934e0 100644 --- a/substrate/frame/state-trie-migration/src/lib.rs +++ b/substrate/frame/state-trie-migration/src/lib.rs @@ -1801,7 +1801,7 @@ mod remote_tests_local { use std::env::var as env_var; // we only use the hash type from this, so using the mock should be fine. - type Extrinsic = sp_runtime::generic::UncheckedExtrinsic; + type Extrinsic = sp_runtime::testing::TestXt; type Block = sp_runtime::testing::Block; #[tokio::test] diff --git a/substrate/frame/state-trie-migration/src/weights.rs b/substrate/frame/state-trie-migration/src/weights.rs index 23dad9e3380..8fa80b38957 100644 --- a/substrate/frame/state-trie-migration/src/weights.rs +++ b/substrate/frame/state-trie-migration/src/weights.rs @@ -17,28 +17,26 @@ //! Autogenerated weights for `pallet_state_trie_migration` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2024-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-grjcggob-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/production/substrate-node +// target/production/substrate-node // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_state_trie_migration -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/state-trie-migration/src/weights.rs +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_state_trie_migration +// --chain=dev // --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/state-trie-migration/src/weights.rs // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -66,15 +64,15 @@ impl WeightInfo for SubstrateWeight { /// Storage: `StateTrieMigration::SignedMigrationMaxLimits` (r:1 w:0) /// Proof: `StateTrieMigration::SignedMigrationMaxLimits` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:0) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(175), added: 2650, mode: `MaxEncodedLen`) /// Storage: `StateTrieMigration::MigrationProcess` (r:1 w:1) /// Proof: `StateTrieMigration::MigrationProcess` (`max_values`: Some(1), `max_size`: Some(1042), added: 1537, mode: `MaxEncodedLen`) fn continue_migrate() -> Weight { // Proof Size summary in bytes: // Measured: `108` - // Estimated: `3658` - // Minimum execution time: 17_661_000 picoseconds. - Weight::from_parts(18_077_000, 3658) + // Estimated: `3640` + // Minimum execution time: 18_520_000 picoseconds. + Weight::from_parts(19_171_000, 3640) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -84,53 +82,53 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1493` - // Minimum execution time: 4_036_000 picoseconds. - Weight::from_parts(4_267_000, 1493) + // Minimum execution time: 3_786_000 picoseconds. + Weight::from_parts(4_038_000, 1493) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Balances::Holds` (r:1 w:0) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(175), added: 2650, mode: `MaxEncodedLen`) fn migrate_custom_top_success() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `3658` - // Minimum execution time: 11_348_000 picoseconds. - Weight::from_parts(11_899_000, 3658) + // Estimated: `3640` + // Minimum execution time: 11_144_000 picoseconds. + Weight::from_parts(11_556_000, 3640) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(175), added: 2650, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x666f6f` (r:1 w:1) /// Proof: UNKNOWN KEY `0x666f6f` (r:1 w:1) fn migrate_custom_top_fail() -> Weight { // Proof Size summary in bytes: // Measured: `113` - // Estimated: `3658` - // Minimum execution time: 59_819_000 picoseconds. - Weight::from_parts(61_066_000, 3658) + // Estimated: `3640` + // Minimum execution time: 59_288_000 picoseconds. + Weight::from_parts(60_276_000, 3640) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Balances::Holds` (r:1 w:0) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(175), added: 2650, mode: `MaxEncodedLen`) fn migrate_custom_child_success() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `3658` - // Minimum execution time: 11_424_000 picoseconds. - Weight::from_parts(11_765_000, 3658) + // Estimated: `3640` + // Minimum execution time: 11_258_000 picoseconds. + Weight::from_parts(11_626_000, 3640) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(175), added: 2650, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x666f6f` (r:1 w:1) /// Proof: UNKNOWN KEY `0x666f6f` (r:1 w:1) fn migrate_custom_child_fail() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `3658` - // Minimum execution time: 61_086_000 picoseconds. - Weight::from_parts(62_546_000, 3658) + // Estimated: `3640` + // Minimum execution time: 61_575_000 picoseconds. + Weight::from_parts(63_454_000, 3640) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -141,10 +139,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `197 + v * (1 ±0)` // Estimated: `3662 + v * (1 ±0)` - // Minimum execution time: 5_375_000 picoseconds. - Weight::from_parts(5_552_000, 3662) + // Minimum execution time: 5_259_000 picoseconds. + Weight::from_parts(5_433_000, 3662) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_146, 0).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(1_159, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(v.into())) @@ -156,15 +154,15 @@ impl WeightInfo for () { /// Storage: `StateTrieMigration::SignedMigrationMaxLimits` (r:1 w:0) /// Proof: `StateTrieMigration::SignedMigrationMaxLimits` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) /// Storage: `Balances::Holds` (r:1 w:0) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(175), added: 2650, mode: `MaxEncodedLen`) /// Storage: `StateTrieMigration::MigrationProcess` (r:1 w:1) /// Proof: `StateTrieMigration::MigrationProcess` (`max_values`: Some(1), `max_size`: Some(1042), added: 1537, mode: `MaxEncodedLen`) fn continue_migrate() -> Weight { // Proof Size summary in bytes: // Measured: `108` - // Estimated: `3658` - // Minimum execution time: 17_661_000 picoseconds. - Weight::from_parts(18_077_000, 3658) + // Estimated: `3640` + // Minimum execution time: 18_520_000 picoseconds. + Weight::from_parts(19_171_000, 3640) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -174,53 +172,53 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1493` - // Minimum execution time: 4_036_000 picoseconds. - Weight::from_parts(4_267_000, 1493) + // Minimum execution time: 3_786_000 picoseconds. + Weight::from_parts(4_038_000, 1493) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Balances::Holds` (r:1 w:0) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(175), added: 2650, mode: `MaxEncodedLen`) fn migrate_custom_top_success() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `3658` - // Minimum execution time: 11_348_000 picoseconds. - Weight::from_parts(11_899_000, 3658) + // Estimated: `3640` + // Minimum execution time: 11_144_000 picoseconds. + Weight::from_parts(11_556_000, 3640) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(175), added: 2650, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x666f6f` (r:1 w:1) /// Proof: UNKNOWN KEY `0x666f6f` (r:1 w:1) fn migrate_custom_top_fail() -> Weight { // Proof Size summary in bytes: // Measured: `113` - // Estimated: `3658` - // Minimum execution time: 59_819_000 picoseconds. - Weight::from_parts(61_066_000, 3658) + // Estimated: `3640` + // Minimum execution time: 59_288_000 picoseconds. + Weight::from_parts(60_276_000, 3640) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Balances::Holds` (r:1 w:0) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(175), added: 2650, mode: `MaxEncodedLen`) fn migrate_custom_child_success() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `3658` - // Minimum execution time: 11_424_000 picoseconds. - Weight::from_parts(11_765_000, 3658) + // Estimated: `3640` + // Minimum execution time: 11_258_000 picoseconds. + Weight::from_parts(11_626_000, 3640) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(175), added: 2650, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x666f6f` (r:1 w:1) /// Proof: UNKNOWN KEY `0x666f6f` (r:1 w:1) fn migrate_custom_child_fail() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `3658` - // Minimum execution time: 61_086_000 picoseconds. - Weight::from_parts(62_546_000, 3658) + // Estimated: `3640` + // Minimum execution time: 61_575_000 picoseconds. + Weight::from_parts(63_454_000, 3640) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -231,10 +229,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `197 + v * (1 ±0)` // Estimated: `3662 + v * (1 ±0)` - // Minimum execution time: 5_375_000 picoseconds. - Weight::from_parts(5_552_000, 3662) + // Minimum execution time: 5_259_000 picoseconds. + Weight::from_parts(5_433_000, 3662) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_146, 0).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(1_159, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(v.into())) diff --git a/substrate/frame/sudo/src/benchmarking.rs b/substrate/frame/sudo/src/benchmarking.rs index cdd7d707600..e64233fe748 100644 --- a/substrate/frame/sudo/src/benchmarking.rs +++ b/substrate/frame/sudo/src/benchmarking.rs @@ -20,23 +20,14 @@ use super::*; use crate::Pallet; use frame_benchmarking::v2::*; -use frame_support::dispatch::DispatchInfo; use frame_system::RawOrigin; -use sp_runtime::traits::{AsSystemOriginSigner, DispatchTransaction, Dispatchable}; fn assert_last_event(generic_event: crate::Event) { let re: ::RuntimeEvent = generic_event.into(); frame_system::Pallet::::assert_last_event(re.into()); } -#[benchmarks(where - T: Send + Sync, - ::RuntimeCall: From>, - ::RuntimeCall: Dispatchable, - <::RuntimeCall as Dispatchable>::PostInfo: From<()>, - <::RuntimeCall as Dispatchable>::RuntimeOrigin: - AsSystemOriginSigner + Clone, -)] +#[benchmarks(where ::RuntimeCall: From>)] mod benchmarks { use super::*; @@ -94,23 +85,5 @@ mod benchmarks { assert_last_event::(Event::KeyRemoved {}); } - #[benchmark] - fn check_only_sudo_account() { - let caller: T::AccountId = whitelisted_caller(); - Key::::put(&caller); - - let call = frame_system::Call::remark { remark: vec![] }.into(); - let info = DispatchInfo { ..Default::default() }; - let ext = CheckOnlySudoAccount::::new(); - - #[block] - { - assert!(ext - .test_run(RawOrigin::Signed(caller).into(), &call, &info, 0, |_| Ok(().into())) - .unwrap() - .is_ok()); - } - } - impl_benchmark_test_suite!(Pallet, crate::mock::new_bench_ext(), crate::mock::Test); } diff --git a/substrate/frame/sudo/src/extension.rs b/substrate/frame/sudo/src/extension.rs index 2cd8f945edd..e90286e5a7c 100644 --- a/substrate/frame/sudo/src/extension.rs +++ b/substrate/frame/sudo/src/extension.rs @@ -20,14 +20,10 @@ use codec::{Decode, Encode}; use frame_support::{dispatch::DispatchInfo, ensure}; use scale_info::TypeInfo; use sp_runtime::{ - impl_tx_ext_default, - traits::{ - AsSystemOriginSigner, DispatchInfoOf, Dispatchable, TransactionExtension, - TransactionExtensionBase, - }, + traits::{DispatchInfoOf, Dispatchable, SignedExtension}, transaction_validity::{ - InvalidTransaction, TransactionPriority, TransactionValidityError, UnknownTransaction, - ValidTransaction, + InvalidTransaction, TransactionPriority, TransactionValidity, TransactionValidityError, + UnknownTransaction, ValidTransaction, }, }; use sp_std::{fmt, marker::PhantomData}; @@ -63,61 +59,49 @@ impl fmt::Debug for CheckOnlySudoAccount { } impl CheckOnlySudoAccount { - /// Creates new `TransactionExtension` to check sudo key. + /// Creates new `SignedExtension` to check sudo key. pub fn new() -> Self { Self::default() } } -impl TransactionExtensionBase for CheckOnlySudoAccount { - const IDENTIFIER: &'static str = "CheckOnlySudoAccount"; - type Implicit = (); - - fn weight(&self) -> frame_support::weights::Weight { - use crate::weights::WeightInfo; - T::WeightInfo::check_only_sudo_account() - } -} -impl - TransactionExtension<::RuntimeCall, Context> for CheckOnlySudoAccount +impl SignedExtension for CheckOnlySudoAccount where - ::RuntimeCall: Dispatchable, - <::RuntimeCall as Dispatchable>::RuntimeOrigin: - AsSystemOriginSigner + Clone, + ::RuntimeCall: Dispatchable, { + const IDENTIFIER: &'static str = "CheckOnlySudoAccount"; + type AccountId = T::AccountId; + type Call = ::RuntimeCall; + type AdditionalSigned = (); type Pre = (); - type Val = (); + + fn additional_signed(&self) -> Result { + Ok(()) + } fn validate( &self, - origin: <::RuntimeCall as Dispatchable>::RuntimeOrigin, - _call: &::RuntimeCall, - info: &DispatchInfoOf<::RuntimeCall>, + who: &Self::AccountId, + _call: &Self::Call, + info: &DispatchInfoOf, _len: usize, - _context: &mut Context, - _self_implicit: Self::Implicit, - _inherited_implication: &impl Encode, - ) -> Result< - ( - ValidTransaction, - Self::Val, - <::RuntimeCall as Dispatchable>::RuntimeOrigin, - ), - TransactionValidityError, - > { - let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?; + ) -> TransactionValidity { let sudo_key: T::AccountId = Key::::get().ok_or(UnknownTransaction::CannotLookup)?; ensure!(*who == sudo_key, InvalidTransaction::BadSigner); - Ok(( - ValidTransaction { - priority: info.weight.ref_time() as TransactionPriority, - ..Default::default() - }, - (), - origin, - )) + Ok(ValidTransaction { + priority: info.weight.ref_time() as TransactionPriority, + ..Default::default() + }) } - impl_tx_ext_default!(::RuntimeCall; Context; prepare); + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + self.validate(who, call, info, len).map(|_| ()) + } } diff --git a/substrate/frame/sudo/src/lib.rs b/substrate/frame/sudo/src/lib.rs index 2c953368b22..2ebe4cb0157 100644 --- a/substrate/frame/sudo/src/lib.rs +++ b/substrate/frame/sudo/src/lib.rs @@ -85,8 +85,8 @@ //! meant to be used by constructing runtime calls from outside the runtime. //! //! -//! This pallet also defines a [`TransactionExtension`](sp_runtime::traits::TransactionExtension) -//! called [`CheckOnlySudoAccount`] to ensure that only signed transactions by the sudo account are +//! This pallet also defines a [`SignedExtension`](sp_runtime::traits::SignedExtension) called +//! [`CheckOnlySudoAccount`] to ensure that only signed transactions by the sudo account are //! accepted by the transaction pool. The intended use of this signed extension is to prevent other //! accounts from spamming the transaction pool for the initial phase of a chain, during which //! developers may only want a sudo account to be able to make transactions. diff --git a/substrate/frame/sudo/src/weights.rs b/substrate/frame/sudo/src/weights.rs index aa8f69fd4e6..10d1a9f7a51 100644 --- a/substrate/frame/sudo/src/weights.rs +++ b/substrate/frame/sudo/src/weights.rs @@ -17,28 +17,26 @@ //! Autogenerated weights for `pallet_sudo` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-11-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/production/substrate-node +// target/production/substrate-node // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_sudo -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/sudo/src/weights.rs +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_sudo +// --chain=dev // --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/sudo/src/weights.rs // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -55,7 +53,6 @@ pub trait WeightInfo { fn sudo() -> Weight; fn sudo_as() -> Weight; fn remove_key() -> Weight; - fn check_only_sudo_account() -> Weight; } /// Weights for `pallet_sudo` using the Substrate node and recommended hardware. @@ -67,8 +64,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `165` // Estimated: `1517` - // Minimum execution time: 9_590_000 picoseconds. - Weight::from_parts(9_924_000, 1517) + // Minimum execution time: 9_600_000 picoseconds. + Weight::from_parts(10_076_000, 1517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -78,8 +75,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `165` // Estimated: `1517` - // Minimum execution time: 9_825_000 picoseconds. - Weight::from_parts(10_373_000, 1517) + // Minimum execution time: 10_453_000 picoseconds. + Weight::from_parts(10_931_000, 1517) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Sudo::Key` (r:1 w:0) @@ -88,8 +85,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `165` // Estimated: `1517` - // Minimum execution time: 10_140_000 picoseconds. - Weight::from_parts(10_382_000, 1517) + // Minimum execution time: 10_202_000 picoseconds. + Weight::from_parts(10_800_000, 1517) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Sudo::Key` (r:1 w:1) @@ -98,21 +95,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `165` // Estimated: `1517` - // Minimum execution time: 8_610_000 picoseconds. - Weight::from_parts(8_975_000, 1517) + // Minimum execution time: 8_555_000 picoseconds. + Weight::from_parts(8_846_000, 1517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Sudo::Key` (r:1 w:0) - /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - fn check_only_sudo_account() -> Weight { - // Proof Size summary in bytes: - // Measured: `165` - // Estimated: `1517` - // Minimum execution time: 3_416_000 picoseconds. - Weight::from_parts(3_645_000, 1517) - .saturating_add(T::DbWeight::get().reads(1_u64)) - } } // For backwards compatibility and tests. @@ -123,8 +110,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `165` // Estimated: `1517` - // Minimum execution time: 9_590_000 picoseconds. - Weight::from_parts(9_924_000, 1517) + // Minimum execution time: 9_600_000 picoseconds. + Weight::from_parts(10_076_000, 1517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -134,8 +121,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `165` // Estimated: `1517` - // Minimum execution time: 9_825_000 picoseconds. - Weight::from_parts(10_373_000, 1517) + // Minimum execution time: 10_453_000 picoseconds. + Weight::from_parts(10_931_000, 1517) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Sudo::Key` (r:1 w:0) @@ -144,8 +131,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `165` // Estimated: `1517` - // Minimum execution time: 10_140_000 picoseconds. - Weight::from_parts(10_382_000, 1517) + // Minimum execution time: 10_202_000 picoseconds. + Weight::from_parts(10_800_000, 1517) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Sudo::Key` (r:1 w:1) @@ -154,19 +141,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `165` // Estimated: `1517` - // Minimum execution time: 8_610_000 picoseconds. - Weight::from_parts(8_975_000, 1517) + // Minimum execution time: 8_555_000 picoseconds. + Weight::from_parts(8_846_000, 1517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Sudo::Key` (r:1 w:0) - /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - fn check_only_sudo_account() -> Weight { - // Proof Size summary in bytes: - // Measured: `165` - // Estimated: `1517` - // Minimum execution time: 3_416_000 picoseconds. - Weight::from_parts(3_645_000, 1517) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - } } diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/inherent.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/inherent.rs index d21cfef4a92..da483fa6cf0 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/inherent.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/inherent.rs @@ -73,9 +73,11 @@ pub fn expand_outer_inherent( #( #pallet_attrs if let Some(inherent) = #pallet_names::create_inherent(self) { - let inherent = <#unchecked_extrinsic as #scrate::sp_runtime::traits::Extrinsic>::new_inherent( + let inherent = <#unchecked_extrinsic as #scrate::sp_runtime::traits::Extrinsic>::new( inherent.into(), - ); + None, + ).expect("Runtime UncheckedExtrinsic is not Opaque, so it has to return \ + `Some`; qed"); inherents.push(inherent); } @@ -121,7 +123,7 @@ pub fn expand_outer_inherent( for xt in block.extrinsics() { // Inherents are before any other extrinsics. // And signed extrinsics are not inherents. - if !(#scrate::sp_runtime::traits::Extrinsic::is_bare(xt)) { + if #scrate::sp_runtime::traits::Extrinsic::is_signed(xt).unwrap_or(false) { break } @@ -159,9 +161,10 @@ pub fn expand_outer_inherent( match #pallet_names::is_inherent_required(self) { Ok(Some(e)) => { let found = block.extrinsics().iter().any(|xt| { - let is_bare = #scrate::sp_runtime::traits::Extrinsic::is_bare(xt); + let is_signed = #scrate::sp_runtime::traits::Extrinsic::is_signed(xt) + .unwrap_or(false); - if is_bare { + if !is_signed { let call = < #unchecked_extrinsic as ExtrinsicCall >::call(xt); @@ -206,9 +209,8 @@ pub fn expand_outer_inherent( use #scrate::inherent::ProvideInherent; use #scrate::traits::{IsSubType, ExtrinsicCall}; - let is_bare = #scrate::sp_runtime::traits::Extrinsic::is_bare(ext); - if !is_bare { - // Signed extrinsics are not inherents. + if #scrate::sp_runtime::traits::Extrinsic::is_signed(ext).unwrap_or(false) { + // Signed extrinsics are never inherents. return false } diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs index f55ca677d89..0e76f9a9246 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs @@ -119,13 +119,13 @@ pub fn expand_runtime_metadata( call_ty, signature_ty, extra_ty, - extensions: < + signed_extensions: < < #extrinsic as #scrate::sp_runtime::traits::ExtrinsicMetadata - >::Extra as #scrate::sp_runtime::traits::TransactionExtensionBase + >::SignedExtensions as #scrate::sp_runtime::traits::SignedExtension >::metadata() .into_iter() - .map(|meta| #scrate::__private::metadata_ir::TransactionExtensionMetadataIR { + .map(|meta| #scrate::__private::metadata_ir::SignedExtensionMetadataIR { identifier: meta.identifier, ty: meta.ty, additional_signed: meta.additional_signed, diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/origin.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/origin.rs index 341621deb09..83049919d01 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/origin.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/origin.rs @@ -153,10 +153,6 @@ pub fn expand_outer_origin( self.filter = #scrate::__private::sp_std::rc::Rc::new(Box::new(filter)); } - fn set_caller(&mut self, caller: OriginCaller) { - self.caller = caller; - } - fn set_caller_from(&mut self, other: impl Into) { self.caller = other.into().caller; } @@ -305,16 +301,6 @@ pub fn expand_outer_origin( } } - impl #scrate::__private::AsSystemOriginSigner<<#runtime as #system_path::Config>::AccountId> for RuntimeOrigin { - fn as_system_origin_signer(&self) -> Option<&<#runtime as #system_path::Config>::AccountId> { - if let OriginCaller::system(#system_path::Origin::<#runtime>::Signed(ref signed)) = &self.caller { - Some(signed) - } else { - None - } - } - } - #pallet_conversions }) } diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs index 61787a74012..4a313551aca 100644 --- a/substrate/frame/support/src/dispatch.rs +++ b/substrate/frame/support/src/dispatch.rs @@ -25,7 +25,7 @@ use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; use sp_runtime::{ generic::{CheckedExtrinsic, UncheckedExtrinsic}, - traits::Dispatchable, + traits::SignedExtension, DispatchError, RuntimeDebug, }; use sp_std::fmt; @@ -268,8 +268,7 @@ pub fn extract_actual_weight(result: &DispatchResultWithPostInfo, info: &Dispatc .calc_actual_weight(info) } -/// Extract the actual pays_fee from a dispatch result if any or fall back to the default -/// weight. +/// Extract the actual pays_fee from a dispatch result if any or fall back to the default weight. pub fn extract_actual_pays_fee(result: &DispatchResultWithPostInfo, info: &DispatchInfo) -> Pays { match result { Ok(post_info) => post_info, @@ -369,10 +368,11 @@ where } /// Implementation for unchecked extrinsic. -impl GetDispatchInfo - for UncheckedExtrinsic +impl GetDispatchInfo + for UncheckedExtrinsic where - Call: GetDispatchInfo + Dispatchable, + Call: GetDispatchInfo, + Extra: SignedExtension, { fn get_dispatch_info(&self) -> DispatchInfo { self.function.get_dispatch_info() @@ -380,7 +380,7 @@ where } /// Implementation for checked extrinsic. -impl GetDispatchInfo for CheckedExtrinsic +impl GetDispatchInfo for CheckedExtrinsic where Call: GetDispatchInfo, { @@ -389,6 +389,21 @@ where } } +/// Implementation for test extrinsic. +#[cfg(feature = "std")] +impl GetDispatchInfo + for sp_runtime::testing::TestXt +{ + fn get_dispatch_info(&self) -> DispatchInfo { + // for testing: weight == size. + DispatchInfo { + weight: Weight::from_parts(self.encode().len() as _, 0), + pays_fee: Pays::Yes, + class: self.call.get_dispatch_info().class, + } + } +} + /// A struct holding value for each `DispatchClass`. #[derive(Clone, Eq, PartialEq, Default, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] pub struct PerDispatchClass { diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index af8449c9697..4eadd85a9e0 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -54,8 +54,7 @@ pub mod __private { #[cfg(feature = "std")] pub use sp_runtime::{bounded_btree_map, bounded_vec}; pub use sp_runtime::{ - traits::{AsSystemOriginSigner, Dispatchable}, - DispatchError, RuntimeDebug, StateVersion, TransactionOutcome, + traits::Dispatchable, DispatchError, RuntimeDebug, StateVersion, TransactionOutcome, }; #[cfg(feature = "std")] pub use sp_state_machine::BasicExternalities; @@ -76,7 +75,6 @@ pub mod storage; #[cfg(test)] mod tests; pub mod traits; -pub mod transaction_extensions; pub mod weights; #[doc(hidden)] pub mod unsigned { @@ -1586,8 +1584,8 @@ pub mod pallet_macros { /// [`ValidateUnsigned`](frame_support::pallet_prelude::ValidateUnsigned) for /// type `Pallet`, and some optional where clause. /// - /// NOTE: There is also the [`sp_runtime::traits::TransactionExtension`] trait that can be - /// used to add some specific logic for transaction validation. + /// NOTE: There is also the [`sp_runtime::traits::SignedExtension`] trait that can be used + /// to add some specific logic for transaction validation. /// /// ## Macro expansion /// diff --git a/substrate/frame/support/src/traits/dispatch.rs b/substrate/frame/support/src/traits/dispatch.rs index 212c3080352..de50ce7a26c 100644 --- a/substrate/frame/support/src/traits/dispatch.rs +++ b/substrate/frame/support/src/traits/dispatch.rs @@ -482,7 +482,7 @@ pub trait OriginTrait: Sized { type Call; /// The caller origin, overarching type of all pallets origins. - type PalletsOrigin: Send + Sync + Into + CallerTrait + MaxEncodedLen; + type PalletsOrigin: Into + CallerTrait + MaxEncodedLen; /// The AccountId used across the system. type AccountId; @@ -496,14 +496,6 @@ pub trait OriginTrait: Sized { /// Replace the caller with caller from the other origin fn set_caller_from(&mut self, other: impl Into); - /// Replace the caller with caller from the other origin - fn set_caller(&mut self, caller: Self::PalletsOrigin); - - /// Replace the caller with caller from the other origin - fn set_caller_from_signed(&mut self, caller_account: Self::AccountId) { - self.set_caller(Self::PalletsOrigin::from(RawOrigin::Signed(caller_account))) - } - /// Filter the call if caller is not root, if false is returned then the call must be filtered /// out. /// @@ -552,17 +544,6 @@ pub trait OriginTrait: Sized { fn as_system_ref(&self) -> Option<&RawOrigin> { self.caller().as_system_ref() } - - /// Extract a reference to the sytsem signer, if that's what the caller is. - fn as_system_signer(&self) -> Option<&Self::AccountId> { - self.caller().as_system_ref().and_then(|s| { - if let RawOrigin::Signed(ref who) = s { - Some(who) - } else { - None - } - }) - } } #[cfg(test)] diff --git a/substrate/frame/support/src/traits/misc.rs b/substrate/frame/support/src/traits/misc.rs index fba546ce21b..1f634a64282 100644 --- a/substrate/frame/support/src/traits/misc.rs +++ b/substrate/frame/support/src/traits/misc.rs @@ -919,13 +919,24 @@ pub trait ExtrinsicCall: sp_runtime::traits::Extrinsic { fn call(&self) -> &Self::Call; } +#[cfg(feature = "std")] +impl ExtrinsicCall for sp_runtime::testing::TestXt +where + Call: codec::Codec + Sync + Send + TypeInfo, + Extra: TypeInfo, +{ + fn call(&self) -> &Self::Call { + &self.call + } +} + impl ExtrinsicCall for sp_runtime::generic::UncheckedExtrinsic where Address: TypeInfo, Call: TypeInfo, Signature: TypeInfo, - Extra: TypeInfo, + Extra: sp_runtime::traits::SignedExtension + TypeInfo, { fn call(&self) -> &Self::Call { &self.function diff --git a/substrate/frame/support/src/transaction_extensions.rs b/substrate/frame/support/src/transaction_extensions.rs deleted file mode 100644 index 98d78b9b4e4..00000000000 --- a/substrate/frame/support/src/transaction_extensions.rs +++ /dev/null @@ -1,89 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Transaction extensions. - -use crate::{CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound}; -use codec::{Decode, Encode}; -use scale_info::TypeInfo; -use sp_io::hashing::blake2_256; -use sp_runtime::{ - impl_tx_ext_default, - traits::{ - transaction_extension::{TransactionExtensionBase, TransactionExtensionInterior}, - DispatchInfoOf, Dispatchable, IdentifyAccount, TransactionExtension, Verify, - }, - transaction_validity::{InvalidTransaction, TransactionValidityError, ValidTransaction}, -}; - -#[derive( - CloneNoBound, EqNoBound, PartialEqNoBound, Encode, Decode, RuntimeDebugNoBound, TypeInfo, -)] -#[codec(encode_bound())] -#[codec(decode_bound())] -pub struct VerifyMultiSignature -where - V: TransactionExtensionInterior, - ::AccountId: TransactionExtensionInterior, -{ - signature: V, - account: ::AccountId, -} - -impl TransactionExtensionBase for VerifyMultiSignature -where - V: TransactionExtensionInterior, - ::AccountId: TransactionExtensionInterior, -{ - const IDENTIFIER: &'static str = "VerifyMultiSignature"; - type Implicit = (); -} - -impl TransactionExtension - for VerifyMultiSignature -where - V: TransactionExtensionInterior, - ::AccountId: TransactionExtensionInterior, - ::RuntimeOrigin: From::AccountId>>, -{ - type Val = (); - type Pre = (); - impl_tx_ext_default!(Call; Context; prepare); - - fn validate( - &self, - _origin: ::RuntimeOrigin, - _call: &Call, - _info: &DispatchInfoOf, - _len: usize, - _: &mut Context, - _: (), - inherited_implication: &impl Encode, - ) -> Result< - (ValidTransaction, Self::Val, ::RuntimeOrigin), - TransactionValidityError, - > { - let msg = inherited_implication.using_encoded(blake2_256); - - if !self.signature.verify(&msg[..], &self.account) { - Err(InvalidTransaction::BadProof)? - } - // We clobber the original origin. Maybe we shuld check that it's none? - let origin = Some(self.account.clone()).into(); - Ok((ValidTransaction::default(), (), origin)) - } -} diff --git a/substrate/frame/support/src/weights/block_weights.rs b/substrate/frame/support/src/weights/block_weights.rs index 647b6198357..57a68554755 100644 --- a/substrate/frame/support/src/weights/block_weights.rs +++ b/substrate/frame/support/src/weights/block_weights.rs @@ -15,23 +15,24 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01 (Y/M/D) -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16 (Y/M/D) +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! //! SHORT-NAME: `block`, LONG-NAME: `BlockExecution`, RUNTIME: `Development` //! WARMUPS: `10`, REPEAT: `100` -//! WEIGHT-PATH: `./substrate/frame/support/src/weights/` +//! WEIGHT-PATH: `./frame/support/src/weights/` //! WEIGHT-METRIC: `Average`, WEIGHT-MUL: `1.0`, WEIGHT-ADD: `0` // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // overhead // --chain=dev +// --execution=wasm // --wasm-execution=compiled -// --weight-path=./substrate/frame/support/src/weights/ -// --header=./substrate/HEADER-APACHE2 +// --weight-path=./frame/support/src/weights/ +// --header=./HEADER-APACHE2 // --warmup=10 // --repeat=100 @@ -43,17 +44,17 @@ parameter_types! { /// Calculated by multiplying the *Average* with `1.0` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 424_332, 493_017 - /// Average: 437_118 - /// Median: 434_920 - /// Std-Dev: 8798.01 + /// Min, Max: 376_949, 622_462 + /// Average: 390_584 + /// Median: 386_322 + /// Std-Dev: 24792.0 /// /// Percentiles nanoseconds: - /// 99th: 460_074 - /// 95th: 451_580 - /// 75th: 440_307 + /// 99th: 433_299 + /// 95th: 402_688 + /// 75th: 391_645 pub const BlockExecutionWeight: Weight = - Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(437_118), 0); + Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(390_584), 0); } #[cfg(test)] diff --git a/substrate/frame/support/src/weights/extrinsic_weights.rs b/substrate/frame/support/src/weights/extrinsic_weights.rs index 99b392c4369..a304f089ff7 100644 --- a/substrate/frame/support/src/weights/extrinsic_weights.rs +++ b/substrate/frame/support/src/weights/extrinsic_weights.rs @@ -15,23 +15,24 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01 (Y/M/D) -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16 (Y/M/D) +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! //! SHORT-NAME: `extrinsic`, LONG-NAME: `ExtrinsicBase`, RUNTIME: `Development` //! WARMUPS: `10`, REPEAT: `100` -//! WEIGHT-PATH: `./substrate/frame/support/src/weights/` +//! WEIGHT-PATH: `./frame/support/src/weights/` //! WEIGHT-METRIC: `Average`, WEIGHT-MUL: `1.0`, WEIGHT-ADD: `0` // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // overhead // --chain=dev +// --execution=wasm // --wasm-execution=compiled -// --weight-path=./substrate/frame/support/src/weights/ -// --header=./substrate/HEADER-APACHE2 +// --weight-path=./frame/support/src/weights/ +// --header=./HEADER-APACHE2 // --warmup=10 // --repeat=100 @@ -43,17 +44,17 @@ parameter_types! { /// Calculated by multiplying the *Average* with `1.0` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 106_053, 107_403 - /// Average: 106_446 - /// Median: 106_415 - /// Std-Dev: 216.17 + /// Min, Max: 123_875, 128_419 + /// Average: 124_414 + /// Median: 124_332 + /// Std-Dev: 497.74 /// /// Percentiles nanoseconds: - /// 99th: 107_042 - /// 95th: 106_841 - /// 75th: 106_544 + /// 99th: 125_245 + /// 95th: 124_989 + /// 75th: 124_498 pub const ExtrinsicBaseWeight: Weight = - Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(106_446), 0); + Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(124_414), 0); } #[cfg(test)] diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr index c677ddcd672..09c4d290ef5 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr @@ -477,7 +477,7 @@ note: required because it appears within the type `RuntimeCall` | ||_- in this macro invocation ... | note: required by a bound in `frame_support::sp_runtime::traits::Dispatchable::Config` - --> $WORKSPACE/substrate/primitives/runtime/src/traits/mod.rs + --> $WORKSPACE/substrate/primitives/runtime/src/traits.rs | | type Config; | ^^^^^^^^^^^^ required by this bound in `Dispatchable::Config` @@ -510,7 +510,7 @@ note: required because it appears within the type `RuntimeCall` | ||_- in this macro invocation ... | note: required by a bound in `frame_support::pallet_prelude::ValidateUnsigned::Call` - --> $WORKSPACE/substrate/primitives/runtime/src/traits/mod.rs + --> $WORKSPACE/substrate/primitives/runtime/src/traits.rs | | type Call; | ^^^^^^^^^^ required by this bound in `ValidateUnsigned::Call` diff --git a/substrate/frame/support/test/tests/pallet.rs b/substrate/frame/support/test/tests/pallet.rs index 4d2737d411e..607f54ccc13 100644 --- a/substrate/frame/support/test/tests/pallet.rs +++ b/substrate/frame/support/test/tests/pallet.rs @@ -743,40 +743,10 @@ impl pallet5::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; } -#[derive(Clone, Debug, codec::Encode, codec::Decode, PartialEq, Eq, scale_info::TypeInfo)] -pub struct AccountU64(u64); -impl sp_runtime::traits::IdentifyAccount for AccountU64 { - type AccountId = u64; - fn into_account(self) -> u64 { - self.0 - } -} - -impl sp_runtime::traits::Verify for AccountU64 { - type Signer = AccountU64; - fn verify>( - &self, - _msg: L, - _signer: &::AccountId, - ) -> bool { - true - } -} - -impl From for AccountU64 { - fn from(value: u64) -> Self { - Self(value) - } -} - pub type Header = sp_runtime::generic::Header; pub type Block = sp_runtime::generic::Block; -pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic< - u64, - RuntimeCall, - AccountU64, - frame_system::CheckNonZeroSender, ->; +pub type UncheckedExtrinsic = + sp_runtime::testing::TestXt>; frame_support::construct_runtime!( pub struct Runtime { @@ -926,8 +896,10 @@ fn inherent_expand() { let inherents = InherentData::new().create_extrinsics(); - let expected = - vec![UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo_no_post_info {}))]; + let expected = vec![UncheckedExtrinsic { + call: RuntimeCall::Example(pallet::Call::foo_no_post_info {}), + signature: None, + }]; assert_eq!(expected, inherents); let block = Block::new( @@ -939,11 +911,14 @@ fn inherent_expand() { Digest::default(), ), vec![ - UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo_no_post_info {})), - UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo { - foo: 1, - bar: 0, - })), + UncheckedExtrinsic { + call: RuntimeCall::Example(pallet::Call::foo_no_post_info {}), + signature: None, + }, + UncheckedExtrinsic { + call: RuntimeCall::Example(pallet::Call::foo { foo: 1, bar: 0 }), + signature: None, + }, ], ); @@ -958,11 +933,14 @@ fn inherent_expand() { Digest::default(), ), vec![ - UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo_no_post_info {})), - UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo { - foo: 0, - bar: 0, - })), + UncheckedExtrinsic { + call: RuntimeCall::Example(pallet::Call::foo_no_post_info {}), + signature: None, + }, + UncheckedExtrinsic { + call: RuntimeCall::Example(pallet::Call::foo { foo: 0, bar: 0 }), + signature: None, + }, ], ); @@ -976,9 +954,10 @@ fn inherent_expand() { BlakeTwo256::hash(b"test"), Digest::default(), ), - vec![UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo_storage_layer { - foo: 0, - }))], + vec![UncheckedExtrinsic { + call: RuntimeCall::Example(pallet::Call::foo_storage_layer { foo: 0 }), + signature: None, + }], ); let mut inherent = InherentData::new(); @@ -993,12 +972,10 @@ fn inherent_expand() { BlakeTwo256::hash(b"test"), Digest::default(), ), - vec![UncheckedExtrinsic::new_signed( - RuntimeCall::Example(pallet::Call::foo_no_post_info {}), - 1, - 1.into(), - Default::default(), - )], + vec![UncheckedExtrinsic { + call: RuntimeCall::Example(pallet::Call::foo_no_post_info {}), + signature: Some((1, Default::default())), + }], ); let mut inherent = InherentData::new(); @@ -1014,13 +991,14 @@ fn inherent_expand() { Digest::default(), ), vec![ - UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo { - foo: 1, - bar: 1, - })), - UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo_storage_layer { - foo: 0, - })), + UncheckedExtrinsic { + call: RuntimeCall::Example(pallet::Call::foo { foo: 1, bar: 1 }), + signature: None, + }, + UncheckedExtrinsic { + call: RuntimeCall::Example(pallet::Call::foo_storage_layer { foo: 0 }), + signature: None, + }, ], ); @@ -1035,14 +1013,18 @@ fn inherent_expand() { Digest::default(), ), vec![ - UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo { - foo: 1, - bar: 1, - })), - UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo_storage_layer { - foo: 0, - })), - UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo_no_post_info {})), + UncheckedExtrinsic { + call: RuntimeCall::Example(pallet::Call::foo { foo: 1, bar: 1 }), + signature: None, + }, + UncheckedExtrinsic { + call: RuntimeCall::Example(pallet::Call::foo_storage_layer { foo: 0 }), + signature: None, + }, + UncheckedExtrinsic { + call: RuntimeCall::Example(pallet::Call::foo_no_post_info {}), + signature: None, + }, ], ); @@ -1057,17 +1039,18 @@ fn inherent_expand() { Digest::default(), ), vec![ - UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo { - foo: 1, - bar: 1, - })), - UncheckedExtrinsic::new_signed( - RuntimeCall::Example(pallet::Call::foo { foo: 1, bar: 0 }), - 1, - 1.into(), - Default::default(), - ), - UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo_no_post_info {})), + UncheckedExtrinsic { + call: RuntimeCall::Example(pallet::Call::foo { foo: 1, bar: 1 }), + signature: None, + }, + UncheckedExtrinsic { + call: RuntimeCall::Example(pallet::Call::foo { foo: 1, bar: 0 }), + signature: Some((1, Default::default())), + }, + UncheckedExtrinsic { + call: RuntimeCall::Example(pallet::Call::foo_no_post_info {}), + signature: None, + }, ], ); @@ -1950,7 +1933,7 @@ fn extrinsic_metadata_ir_types() { >(), ir.signature_ty ); - assert_eq!(meta_type::(), ir.signature_ty); + assert_eq!(meta_type::<()>(), ir.signature_ty); assert_eq!(meta_type::<<::SignaturePayload as SignaturePayloadT>::SignatureExtra>(), ir.extra_ty); assert_eq!(meta_type::>(), ir.extra_ty); diff --git a/substrate/frame/support/test/tests/pallet_instance.rs b/substrate/frame/support/test/tests/pallet_instance.rs index 505400a7c21..f8cc97623b8 100644 --- a/substrate/frame/support/test/tests/pallet_instance.rs +++ b/substrate/frame/support/test/tests/pallet_instance.rs @@ -943,7 +943,7 @@ fn metadata() { ty: scale_info::meta_type::(), version: 4, signed_extensions: vec![SignedExtensionMetadata { - identifier: "UnitTransactionExtension", + identifier: "UnitSignedExtension", ty: scale_info::meta_type::<()>(), additional_signed: scale_info::meta_type::<()>(), }], diff --git a/substrate/frame/support/test/tests/runtime.rs b/substrate/frame/support/test/tests/runtime.rs index 7e33ee46458..115e3aa4c8a 100644 --- a/substrate/frame/support/test/tests/runtime.rs +++ b/substrate/frame/support/test/tests/runtime.rs @@ -895,7 +895,7 @@ fn test_metadata() { ty: meta_type::(), version: 4, signed_extensions: vec![SignedExtensionMetadata { - identifier: "UnitTransactionExtension", + identifier: "UnitSignedExtension", ty: meta_type::<()>(), additional_signed: meta_type::<()>(), }], diff --git a/substrate/frame/support/test/tests/runtime_legacy_ordering.rs b/substrate/frame/support/test/tests/runtime_legacy_ordering.rs index 38875517018..4c7012dca14 100644 --- a/substrate/frame/support/test/tests/runtime_legacy_ordering.rs +++ b/substrate/frame/support/test/tests/runtime_legacy_ordering.rs @@ -752,7 +752,7 @@ fn test_metadata() { name: "Version", ty: meta_type::(), value: RuntimeVersion::default().encode(), - docs: maybe_docs(vec![ " Get the chain's current version."]), + docs: maybe_docs(vec![ " Get the chain's in-code version."]), }, PalletConstantMetadata { name: "SS58Prefix", @@ -895,7 +895,7 @@ fn test_metadata() { ty: meta_type::(), version: 4, signed_extensions: vec![SignedExtensionMetadata { - identifier: "UnitTransactionExtension", + identifier: "UnitSignedExtension", ty: meta_type::<()>(), additional_signed: meta_type::<()>(), }], diff --git a/substrate/frame/system/benchmarking/src/extensions.rs b/substrate/frame/system/benchmarking/src/extensions.rs deleted file mode 100644 index bfc3b4343a6..00000000000 --- a/substrate/frame/system/benchmarking/src/extensions.rs +++ /dev/null @@ -1,213 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Benchmarks for System Extensions - -#![cfg(feature = "runtime-benchmarks")] - -use frame_benchmarking::{account, v2::*, BenchmarkError}; -use frame_support::{ - dispatch::{DispatchClass, DispatchInfo, PostDispatchInfo}, - weights::Weight, -}; -use frame_system::{ - pallet_prelude::*, CheckGenesis, CheckMortality, CheckNonZeroSender, CheckNonce, - CheckSpecVersion, CheckTxVersion, CheckWeight, Config, Pallet as System, RawOrigin, -}; -use sp_runtime::{ - generic::Era, - traits::{AsSystemOriginSigner, DispatchTransaction, Dispatchable, Get}, -}; -use sp_std::prelude::*; - -pub struct Pallet(System); - -#[benchmarks(where - T: Send + Sync, - T::RuntimeCall: Dispatchable, - ::RuntimeOrigin: AsSystemOriginSigner + Clone) -] -mod benchmarks { - use super::*; - - #[benchmark] - fn check_genesis() -> Result<(), BenchmarkError> { - let len = 0_usize; - let caller = account("caller", 0, 0); - let info = DispatchInfo { weight: Weight::zero(), ..Default::default() }; - let call: T::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into(); - - #[block] - { - CheckGenesis::::new() - .test_run(RawOrigin::Signed(caller).into(), &call, &info, len, |_| Ok(().into())) - .unwrap() - .unwrap(); - } - - Ok(()) - } - - #[benchmark] - fn check_mortality() -> Result<(), BenchmarkError> { - let len = 0_usize; - let ext = CheckMortality::::from(Era::mortal(16, 256)); - let block_number: BlockNumberFor = 17u32.into(); - System::::set_block_number(block_number); - let prev_block: BlockNumberFor = 16u32.into(); - let default_hash: T::Hash = Default::default(); - frame_system::BlockHash::::insert(prev_block, default_hash); - let caller = account("caller", 0, 0); - let info = DispatchInfo { - weight: Weight::from_parts(100, 0), - class: DispatchClass::Normal, - ..Default::default() - }; - let call: T::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into(); - - #[block] - { - ext.test_run(RawOrigin::Signed(caller).into(), &call, &info, len, |_| Ok(().into())) - .unwrap() - .unwrap(); - } - Ok(()) - } - - #[benchmark] - fn check_non_zero_sender() -> Result<(), BenchmarkError> { - let len = 0_usize; - let ext = CheckNonZeroSender::::new(); - let caller = account("caller", 0, 0); - let info = DispatchInfo { weight: Weight::zero(), ..Default::default() }; - let call: T::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into(); - - #[block] - { - ext.test_run(RawOrigin::Signed(caller).into(), &call, &info, len, |_| Ok(().into())) - .unwrap() - .unwrap(); - } - Ok(()) - } - - #[benchmark] - fn check_nonce() -> Result<(), BenchmarkError> { - let caller: T::AccountId = account("caller", 0, 0); - let mut info = frame_system::AccountInfo::default(); - info.nonce = 1u32.into(); - info.providers = 1; - let expected_nonce = info.nonce + 1u32.into(); - frame_system::Account::::insert(caller.clone(), info); - let len = 0_usize; - let ext = CheckNonce::::from(1u32.into()); - let info = DispatchInfo { weight: Weight::zero(), ..Default::default() }; - let call: T::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into(); - - #[block] - { - ext.test_run(RawOrigin::Signed(caller.clone()).into(), &call, &info, len, |_| { - Ok(().into()) - }) - .unwrap() - .unwrap(); - } - - let updated_info = frame_system::Account::::get(caller.clone()); - assert_eq!(updated_info.nonce, expected_nonce); - Ok(()) - } - - #[benchmark] - fn check_spec_version() -> Result<(), BenchmarkError> { - let len = 0_usize; - let caller = account("caller", 0, 0); - let info = DispatchInfo { weight: Weight::zero(), ..Default::default() }; - let call: T::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into(); - - #[block] - { - CheckSpecVersion::::new() - .test_run(RawOrigin::Signed(caller).into(), &call, &info, len, |_| Ok(().into())) - .unwrap() - .unwrap(); - } - Ok(()) - } - - #[benchmark] - fn check_tx_version() -> Result<(), BenchmarkError> { - let len = 0_usize; - let caller = account("caller", 0, 0); - let info = DispatchInfo { weight: Weight::zero(), ..Default::default() }; - let call: T::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into(); - - #[block] - { - CheckTxVersion::::new() - .test_run(RawOrigin::Signed(caller).into(), &call, &info, len, |_| Ok(().into())) - .unwrap() - .unwrap(); - } - Ok(()) - } - - #[benchmark] - fn check_weight() -> Result<(), BenchmarkError> { - let caller = account("caller", 0, 0); - let base_extrinsic = ::BlockWeights::get() - .get(DispatchClass::Normal) - .base_extrinsic; - let info = DispatchInfo { - weight: Weight::from_parts(base_extrinsic.ref_time() * 5, 0), - class: DispatchClass::Normal, - ..Default::default() - }; - let call: T::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into(); - let post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_parts(base_extrinsic.ref_time() * 2, 0)), - pays_fee: Default::default(), - }; - let len = 0_usize; - let base_extrinsic = ::BlockWeights::get() - .get(DispatchClass::Normal) - .base_extrinsic; - - let ext = CheckWeight::::new(); - - let initial_block_weight = Weight::from_parts(base_extrinsic.ref_time() * 2, 0); - frame_system::BlockWeight::::mutate(|current_weight| { - current_weight.set(Weight::zero(), DispatchClass::Mandatory); - current_weight.set(initial_block_weight, DispatchClass::Normal); - }); - - #[block] - { - ext.test_run(RawOrigin::Signed(caller).into(), &call, &info, len, |_| Ok(post_info)) - .unwrap() - .unwrap(); - } - - assert_eq!( - System::::block_weight().total(), - initial_block_weight + base_extrinsic + post_info.actual_weight.unwrap(), - ); - Ok(()) - } - - impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test,); -} diff --git a/substrate/frame/system/benchmarking/src/lib.rs b/substrate/frame/system/benchmarking/src/lib.rs index c9f0869d3bc..29100faa751 100644 --- a/substrate/frame/system/benchmarking/src/lib.rs +++ b/substrate/frame/system/benchmarking/src/lib.rs @@ -28,7 +28,6 @@ use sp_core::storage::well_known_keys; use sp_runtime::traits::Hash; use sp_std::{prelude::*, vec}; -pub mod extensions; mod mock; pub struct Pallet(System); diff --git a/substrate/frame/system/benchmarking/src/mock.rs b/substrate/frame/system/benchmarking/src/mock.rs index 1f84dd53004..edbf74a9a51 100644 --- a/substrate/frame/system/benchmarking/src/mock.rs +++ b/substrate/frame/system/benchmarking/src/mock.rs @@ -57,7 +57,6 @@ impl frame_system::Config for Test { type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = (); - type ExtensionsWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); type MaxConsumers = frame_support::traits::ConstU32<16>; diff --git a/substrate/frame/system/src/extensions/check_genesis.rs b/substrate/frame/system/src/extensions/check_genesis.rs index 3f11f745cd9..76a711a823e 100644 --- a/substrate/frame/system/src/extensions/check_genesis.rs +++ b/substrate/frame/system/src/extensions/check_genesis.rs @@ -19,8 +19,7 @@ use crate::{pallet_prelude::BlockNumberFor, Config, Pallet}; use codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_runtime::{ - impl_tx_ext_default, - traits::{TransactionExtension, TransactionExtensionBase, Zero}, + traits::{DispatchInfoOf, SignedExtension, Zero}, transaction_validity::TransactionValidityError, }; @@ -47,26 +46,30 @@ impl sp_std::fmt::Debug for CheckGenesis { } impl CheckGenesis { - /// Creates new `TransactionExtension` to check genesis hash. + /// Creates new `SignedExtension` to check genesis hash. pub fn new() -> Self { Self(sp_std::marker::PhantomData) } } -impl TransactionExtensionBase for CheckGenesis { +impl SignedExtension for CheckGenesis { + type AccountId = T::AccountId; + type Call = ::RuntimeCall; + type AdditionalSigned = T::Hash; + type Pre = (); const IDENTIFIER: &'static str = "CheckGenesis"; - type Implicit = T::Hash; - fn implicit(&self) -> Result { + + fn additional_signed(&self) -> Result { Ok(>::block_hash(BlockNumberFor::::zero())) } - fn weight(&self) -> sp_weights::Weight { - ::check_genesis() + + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + self.validate(who, call, info, len).map(|_| ()) } } -impl TransactionExtension - for CheckGenesis -{ - type Val = (); - type Pre = (); - impl_tx_ext_default!(T::RuntimeCall; Context; validate prepare); -} diff --git a/substrate/frame/system/src/extensions/check_mortality.rs b/substrate/frame/system/src/extensions/check_mortality.rs index deb44880d64..148dfd4aad4 100644 --- a/substrate/frame/system/src/extensions/check_mortality.rs +++ b/substrate/frame/system/src/extensions/check_mortality.rs @@ -20,12 +20,10 @@ use codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_runtime::{ generic::Era, - impl_tx_ext_default, - traits::{ - DispatchInfoOf, SaturatedConversion, TransactionExtension, TransactionExtensionBase, - ValidateResult, + traits::{DispatchInfoOf, SaturatedConversion, SignedExtension}, + transaction_validity::{ + InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction, }, - transaction_validity::{InvalidTransaction, TransactionValidityError, ValidTransaction}, }; /// Check for transaction mortality. @@ -56,11 +54,29 @@ impl sp_std::fmt::Debug for CheckMortality { } } -impl TransactionExtensionBase for CheckMortality { +impl SignedExtension for CheckMortality { + type AccountId = T::AccountId; + type Call = T::RuntimeCall; + type AdditionalSigned = T::Hash; + type Pre = (); const IDENTIFIER: &'static str = "CheckMortality"; - type Implicit = T::Hash; - fn implicit(&self) -> Result { + fn validate( + &self, + _who: &Self::AccountId, + _call: &Self::Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> TransactionValidity { + let current_u64 = >::block_number().saturated_into::(); + let valid_till = self.0.death(current_u64); + Ok(ValidTransaction { + longevity: valid_till.saturating_sub(current_u64), + ..Default::default() + }) + } + + fn additional_signed(&self) -> Result { let current_u64 = >::block_number().saturated_into::(); let n = self.0.birth(current_u64).saturated_into::>(); if !>::contains_key(n) { @@ -69,38 +85,16 @@ impl TransactionExtensionBase for CheckMortality { Ok(>::block_hash(n)) } } - fn weight(&self) -> sp_weights::Weight { - ::check_mortality() - } -} -impl TransactionExtension - for CheckMortality -{ - type Pre = (); - type Val = (); - fn validate( - &self, - origin: ::RuntimeOrigin, - _call: &T::RuntimeCall, - _info: &DispatchInfoOf, - _len: usize, - _context: &mut Context, - _self_implicit: Self::Implicit, - _inherited_implication: &impl Encode, - ) -> ValidateResult { - let current_u64 = >::block_number().saturated_into::(); - let valid_till = self.0.death(current_u64); - Ok(( - ValidTransaction { - longevity: valid_till.saturating_sub(current_u64), - ..Default::default() - }, - (), - origin, - )) + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + self.validate(who, call, info, len).map(|_| ()) } - impl_tx_ext_default!(T::RuntimeCall; Context; prepare); } #[cfg(test)] @@ -112,21 +106,23 @@ mod tests { weights::Weight, }; use sp_core::H256; - use sp_runtime::traits::DispatchTransaction; #[test] fn signed_ext_check_era_should_work() { new_test_ext().execute_with(|| { // future assert_eq!( - CheckMortality::::from(Era::mortal(4, 2)).implicit().err().unwrap(), + CheckMortality::::from(Era::mortal(4, 2)) + .additional_signed() + .err() + .unwrap(), InvalidTransaction::AncientBirthBlock.into(), ); // correct System::set_block_number(13); >::insert(12, H256::repeat_byte(1)); - assert!(CheckMortality::::from(Era::mortal(4, 12)).implicit().is_ok()); + assert!(CheckMortality::::from(Era::mortal(4, 12)).additional_signed().is_ok()); }) } @@ -146,10 +142,7 @@ mod tests { System::set_block_number(17); >::insert(16, H256::repeat_byte(1)); - assert_eq!( - ext.validate_only(Some(1).into(), CALL, &normal, len).unwrap().0.longevity, - 15 - ); + assert_eq!(ext.validate(&1, CALL, &normal, len).unwrap().longevity, 15); }) } } diff --git a/substrate/frame/system/src/extensions/check_non_zero_sender.rs b/substrate/frame/system/src/extensions/check_non_zero_sender.rs index 115ffac9b03..92eed60fc66 100644 --- a/substrate/frame/system/src/extensions/check_non_zero_sender.rs +++ b/substrate/frame/system/src/extensions/check_non_zero_sender.rs @@ -17,14 +17,13 @@ use crate::Config; use codec::{Decode, Encode}; -use frame_support::{traits::OriginTrait, DefaultNoBound}; +use frame_support::{dispatch::DispatchInfo, DefaultNoBound}; use scale_info::TypeInfo; use sp_runtime::{ - impl_tx_ext_default, - traits::{ - transaction_extension::TransactionExtensionBase, DispatchInfoOf, TransactionExtension, + traits::{DispatchInfoOf, Dispatchable, SignedExtension}, + transaction_validity::{ + InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction, }, - transaction_validity::InvalidTransaction, }; use sp_std::{marker::PhantomData, prelude::*}; @@ -46,82 +45,66 @@ impl sp_std::fmt::Debug for CheckNonZeroSender { } impl CheckNonZeroSender { - /// Create new `TransactionExtension` to check runtime version. + /// Create new `SignedExtension` to check runtime version. pub fn new() -> Self { Self(sp_std::marker::PhantomData) } } -impl TransactionExtensionBase for CheckNonZeroSender { - const IDENTIFIER: &'static str = "CheckNonZeroSender"; - type Implicit = (); - fn weight(&self) -> sp_weights::Weight { - ::check_non_zero_sender() - } -} -impl TransactionExtension - for CheckNonZeroSender +impl SignedExtension for CheckNonZeroSender +where + T::RuntimeCall: Dispatchable, { - type Val = (); + type AccountId = T::AccountId; + type Call = T::RuntimeCall; + type AdditionalSigned = (); type Pre = (); + const IDENTIFIER: &'static str = "CheckNonZeroSender"; + + fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { + Ok(()) + } + + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + self.validate(who, call, info, len).map(|_| ()) + } + fn validate( &self, - origin: ::RuntimeOrigin, - _call: &T::RuntimeCall, - _info: &DispatchInfoOf, + who: &Self::AccountId, + _call: &Self::Call, + _info: &DispatchInfoOf, _len: usize, - _context: &mut Context, - _self_implicit: Self::Implicit, - _inherited_implication: &impl Encode, - ) -> sp_runtime::traits::ValidateResult { - if let Some(who) = origin.as_system_signer() { - if who.using_encoded(|d| d.iter().all(|x| *x == 0)) { - return Err(InvalidTransaction::BadSigner.into()) - } + ) -> TransactionValidity { + if who.using_encoded(|d| d.iter().all(|x| *x == 0)) { + return Err(TransactionValidityError::Invalid(InvalidTransaction::BadSigner)) } - Ok((Default::default(), (), origin)) + Ok(ValidTransaction::default()) } - impl_tx_ext_default!(T::RuntimeCall; Context; prepare); } #[cfg(test)] mod tests { use super::*; use crate::mock::{new_test_ext, Test, CALL}; - use frame_support::{assert_ok, dispatch::DispatchInfo}; - use sp_runtime::{traits::DispatchTransaction, TransactionValidityError}; + use frame_support::{assert_noop, assert_ok}; #[test] fn zero_account_ban_works() { new_test_ext().execute_with(|| { let info = DispatchInfo::default(); let len = 0_usize; - assert_eq!( - CheckNonZeroSender::::new() - .validate_only(Some(0).into(), CALL, &info, len) - .unwrap_err(), - TransactionValidityError::from(InvalidTransaction::BadSigner) + assert_noop!( + CheckNonZeroSender::::new().validate(&0, CALL, &info, len), + InvalidTransaction::BadSigner ); - assert_ok!(CheckNonZeroSender::::new().validate_only( - Some(1).into(), - CALL, - &info, - len - )); - }) - } - - #[test] - fn unsigned_origin_works() { - new_test_ext().execute_with(|| { - let info = DispatchInfo::default(); - let len = 0_usize; - assert_ok!(CheckNonZeroSender::::new().validate_only( - None.into(), - CALL, - &info, - len - )); + assert_ok!(CheckNonZeroSender::::new().validate(&1, CALL, &info, len)); }) } } diff --git a/substrate/frame/system/src/extensions/check_nonce.rs b/substrate/frame/system/src/extensions/check_nonce.rs index ead9d9f7c81..7504a814aef 100644 --- a/substrate/frame/system/src/extensions/check_nonce.rs +++ b/substrate/frame/system/src/extensions/check_nonce.rs @@ -15,19 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{AccountInfo, Config}; +use crate::Config; use codec::{Decode, Encode}; use frame_support::dispatch::DispatchInfo; use scale_info::TypeInfo; use sp_runtime::{ - traits::{ - AsSystemOriginSigner, DispatchInfoOf, Dispatchable, One, TransactionExtension, - TransactionExtensionBase, ValidateResult, Zero, - }, + traits::{DispatchInfoOf, Dispatchable, One, SignedExtension, Zero}, transaction_validity::{ - InvalidTransaction, TransactionLongevity, TransactionValidityError, ValidTransaction, + InvalidTransaction, TransactionLongevity, TransactionValidity, TransactionValidityError, + ValidTransaction, }, - Saturating, }; use sp_std::vec; @@ -61,78 +58,75 @@ impl sp_std::fmt::Debug for CheckNonce { } } -impl TransactionExtensionBase for CheckNonce { - const IDENTIFIER: &'static str = "CheckNonce"; - type Implicit = (); - fn weight(&self) -> sp_weights::Weight { - ::check_nonce() - } -} -impl TransactionExtension for CheckNonce +impl SignedExtension for CheckNonce where T::RuntimeCall: Dispatchable, - ::RuntimeOrigin: AsSystemOriginSigner + Clone, { - type Val = Option<(T::AccountId, AccountInfo)>; + type AccountId = T::AccountId; + type Call = T::RuntimeCall; + type AdditionalSigned = (); type Pre = (); + const IDENTIFIER: &'static str = "CheckNonce"; + + fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { + Ok(()) + } + + fn pre_dispatch( + self, + who: &Self::AccountId, + _call: &Self::Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> Result<(), TransactionValidityError> { + let mut account = crate::Account::::get(who); + if account.providers.is_zero() && account.sufficients.is_zero() { + // Nonce storage not paid for + return Err(InvalidTransaction::Payment.into()) + } + if self.0 != account.nonce { + return Err(if self.0 < account.nonce { + InvalidTransaction::Stale + } else { + InvalidTransaction::Future + } + .into()) + } + account.nonce += T::Nonce::one(); + crate::Account::::insert(who, account); + Ok(()) + } fn validate( &self, - origin: ::RuntimeOrigin, - _call: &T::RuntimeCall, - _info: &DispatchInfoOf, + who: &Self::AccountId, + _call: &Self::Call, + _info: &DispatchInfoOf, _len: usize, - _context: &mut Context, - _self_implicit: Self::Implicit, - _inherited_implication: &impl Encode, - ) -> ValidateResult { - let Some(who) = origin.as_system_origin_signer() else { - return Ok((Default::default(), None, origin)) - }; + ) -> TransactionValidity { let account = crate::Account::::get(who); if account.providers.is_zero() && account.sufficients.is_zero() { // Nonce storage not paid for - return Err(InvalidTransaction::Payment.into()) + return InvalidTransaction::Payment.into() } if self.0 < account.nonce { - return Err(InvalidTransaction::Stale.into()) + return InvalidTransaction::Stale.into() } - let provides = vec![Encode::encode(&(who.clone(), self.0))]; + let provides = vec![Encode::encode(&(who, self.0))]; let requires = if account.nonce < self.0 { - vec![Encode::encode(&(who.clone(), self.0.saturating_sub(One::one())))] + vec![Encode::encode(&(who, self.0 - One::one()))] } else { vec![] }; - let validity = ValidTransaction { + Ok(ValidTransaction { priority: 0, requires, provides, longevity: TransactionLongevity::max_value(), propagate: true, - }; - - Ok((validity, Some((who.clone(), account)), origin)) - } - - fn prepare( - self, - val: Self::Val, - _origin: &T::RuntimeOrigin, - _call: &T::RuntimeCall, - _info: &DispatchInfoOf, - _len: usize, - _context: &Context, - ) -> Result { - let Some((who, mut account)) = val else { return Ok(()) }; - // `self.0 < account.nonce` already checked in `validate`. - if self.0 > account.nonce { - return Err(InvalidTransaction::Future.into()) - } - account.nonce.saturating_inc(); - crate::Account::::insert(who, account); - Ok(()) + }) } } @@ -140,8 +134,7 @@ where mod tests { use super::*; use crate::mock::{new_test_ext, Test, CALL}; - use frame_support::assert_ok; - use sp_runtime::traits::DispatchTransaction; + use frame_support::{assert_noop, assert_ok}; #[test] fn signed_ext_check_nonce_works() { @@ -159,33 +152,22 @@ mod tests { let info = DispatchInfo::default(); let len = 0_usize; // stale - assert_eq!( - CheckNonce::(0) - .validate_only(Some(1).into(), CALL, &info, len,) - .unwrap_err(), - TransactionValidityError::Invalid(InvalidTransaction::Stale) + assert_noop!( + CheckNonce::(0).validate(&1, CALL, &info, len), + InvalidTransaction::Stale ); - assert_eq!( - CheckNonce::(0) - .validate_and_prepare(Some(1).into(), CALL, &info, len) - .unwrap_err(), - InvalidTransaction::Stale.into() + assert_noop!( + CheckNonce::(0).pre_dispatch(&1, CALL, &info, len), + InvalidTransaction::Stale ); // correct - assert_ok!(CheckNonce::(1).validate_only(Some(1).into(), CALL, &info, len)); - assert_ok!(CheckNonce::(1).validate_and_prepare( - Some(1).into(), - CALL, - &info, - len - )); + assert_ok!(CheckNonce::(1).validate(&1, CALL, &info, len)); + assert_ok!(CheckNonce::(1).pre_dispatch(&1, CALL, &info, len)); // future - assert_ok!(CheckNonce::(5).validate_only(Some(1).into(), CALL, &info, len)); - assert_eq!( - CheckNonce::(5) - .validate_and_prepare(Some(1).into(), CALL, &info, len) - .unwrap_err(), - InvalidTransaction::Future.into() + assert_ok!(CheckNonce::(5).validate(&1, CALL, &info, len)); + assert_noop!( + CheckNonce::(5).pre_dispatch(&1, CALL, &info, len), + InvalidTransaction::Future ); }) } @@ -216,44 +198,20 @@ mod tests { let info = DispatchInfo::default(); let len = 0_usize; // Both providers and sufficients zero - assert_eq!( - CheckNonce::(1) - .validate_only(Some(1).into(), CALL, &info, len) - .unwrap_err(), - TransactionValidityError::Invalid(InvalidTransaction::Payment) + assert_noop!( + CheckNonce::(1).validate(&1, CALL, &info, len), + InvalidTransaction::Payment ); - assert_eq!( - CheckNonce::(1) - .validate_and_prepare(Some(1).into(), CALL, &info, len) - .unwrap_err(), - TransactionValidityError::Invalid(InvalidTransaction::Payment) + assert_noop!( + CheckNonce::(1).pre_dispatch(&1, CALL, &info, len), + InvalidTransaction::Payment ); // Non-zero providers - assert_ok!(CheckNonce::(1).validate_only(Some(2).into(), CALL, &info, len)); - assert_ok!(CheckNonce::(1).validate_and_prepare( - Some(2).into(), - CALL, - &info, - len - )); + assert_ok!(CheckNonce::(1).validate(&2, CALL, &info, len)); + assert_ok!(CheckNonce::(1).pre_dispatch(&2, CALL, &info, len)); // Non-zero sufficients - assert_ok!(CheckNonce::(1).validate_only(Some(3).into(), CALL, &info, len)); - assert_ok!(CheckNonce::(1).validate_and_prepare( - Some(3).into(), - CALL, - &info, - len - )); - }) - } - - #[test] - fn unsigned_check_nonce_works() { - new_test_ext().execute_with(|| { - let info = DispatchInfo::default(); - let len = 0_usize; - assert_ok!(CheckNonce::(1).validate_only(None.into(), CALL, &info, len)); - assert_ok!(CheckNonce::(1).validate_and_prepare(None.into(), CALL, &info, len)); + assert_ok!(CheckNonce::(1).validate(&3, CALL, &info, len)); + assert_ok!(CheckNonce::(1).pre_dispatch(&3, CALL, &info, len)); }) } } diff --git a/substrate/frame/system/src/extensions/check_spec_version.rs b/substrate/frame/system/src/extensions/check_spec_version.rs index 3109708f48e..24d5ef9cafb 100644 --- a/substrate/frame/system/src/extensions/check_spec_version.rs +++ b/substrate/frame/system/src/extensions/check_spec_version.rs @@ -19,8 +19,7 @@ use crate::{Config, Pallet}; use codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_runtime::{ - impl_tx_ext_default, - traits::{transaction_extension::TransactionExtensionBase, TransactionExtension}, + traits::{DispatchInfoOf, SignedExtension}, transaction_validity::TransactionValidityError, }; @@ -47,26 +46,30 @@ impl sp_std::fmt::Debug for CheckSpecVersion { } impl CheckSpecVersion { - /// Create new `TransactionExtension` to check runtime version. + /// Create new `SignedExtension` to check runtime version. pub fn new() -> Self { Self(sp_std::marker::PhantomData) } } -impl TransactionExtensionBase for CheckSpecVersion { +impl SignedExtension for CheckSpecVersion { + type AccountId = T::AccountId; + type Call = ::RuntimeCall; + type AdditionalSigned = u32; + type Pre = (); const IDENTIFIER: &'static str = "CheckSpecVersion"; - type Implicit = u32; - fn implicit(&self) -> Result { + + fn additional_signed(&self) -> Result { Ok(>::runtime_version().spec_version) } - fn weight(&self) -> sp_weights::Weight { - ::check_spec_version() + + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + self.validate(who, call, info, len).map(|_| ()) } } -impl TransactionExtension<::RuntimeCall, Context> - for CheckSpecVersion -{ - type Val = (); - type Pre = (); - impl_tx_ext_default!(::RuntimeCall; Context; validate prepare); -} diff --git a/substrate/frame/system/src/extensions/check_tx_version.rs b/substrate/frame/system/src/extensions/check_tx_version.rs index ee1d507e7bc..3f9d6a1903f 100644 --- a/substrate/frame/system/src/extensions/check_tx_version.rs +++ b/substrate/frame/system/src/extensions/check_tx_version.rs @@ -19,8 +19,7 @@ use crate::{Config, Pallet}; use codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_runtime::{ - impl_tx_ext_default, - traits::{transaction_extension::TransactionExtensionBase, TransactionExtension}, + traits::{DispatchInfoOf, SignedExtension}, transaction_validity::TransactionValidityError, }; @@ -47,26 +46,29 @@ impl sp_std::fmt::Debug for CheckTxVersion { } impl CheckTxVersion { - /// Create new `TransactionExtension` to check transaction version. + /// Create new `SignedExtension` to check transaction version. pub fn new() -> Self { Self(sp_std::marker::PhantomData) } } -impl TransactionExtensionBase for CheckTxVersion { +impl SignedExtension for CheckTxVersion { + type AccountId = T::AccountId; + type Call = ::RuntimeCall; + type AdditionalSigned = u32; + type Pre = (); const IDENTIFIER: &'static str = "CheckTxVersion"; - type Implicit = u32; - fn implicit(&self) -> Result { + + fn additional_signed(&self) -> Result { Ok(>::runtime_version().transaction_version) } - fn weight(&self) -> sp_weights::Weight { - ::check_tx_version() + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + self.validate(who, call, info, len).map(|_| ()) } } -impl TransactionExtension<::RuntimeCall, Context> - for CheckTxVersion -{ - type Val = (); - type Pre = (); - impl_tx_ext_default!(::RuntimeCall; Context; validate prepare); -} diff --git a/substrate/frame/system/src/extensions/check_weight.rs b/substrate/frame/system/src/extensions/check_weight.rs index 5c35acfb3f3..70d1e756332 100644 --- a/substrate/frame/system/src/extensions/check_weight.rs +++ b/substrate/frame/system/src/extensions/check_weight.rs @@ -23,12 +23,9 @@ use frame_support::{ }; use scale_info::TypeInfo; use sp_runtime::{ - traits::{ - DispatchInfoOf, Dispatchable, PostDispatchInfoOf, TransactionExtension, - TransactionExtensionBase, ValidateResult, - }, - transaction_validity::{InvalidTransaction, TransactionValidityError}, - DispatchResult, ValidTransaction, + traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SignedExtension}, + transaction_validity::{InvalidTransaction, TransactionValidity, TransactionValidityError}, + DispatchResult, }; use sp_weights::Weight; @@ -103,44 +100,40 @@ where } } - /// Creates new `TransactionExtension` to check weight of the extrinsic. + /// Creates new `SignedExtension` to check weight of the extrinsic. pub fn new() -> Self { Self(Default::default()) } - /// Do the validate checks. This can be applied to both signed and unsigned. - /// - /// It only checks that the block weight and length limit will not exceed. - /// - /// Returns the transaction validity and the next block length, to be used in `prepare`. - pub fn do_validate( - info: &DispatchInfoOf, - len: usize, - ) -> Result<(ValidTransaction, u32), TransactionValidityError> { - // ignore the next length. If they return `Ok`, then it is below the limit. - let next_len = Self::check_block_length(info, len)?; - // during validation we skip block limit check. Since the `validate_transaction` - // call runs on an empty block anyway, by this we prevent `on_initialize` weight - // consumption from causing false negatives. - Self::check_extrinsic_weight(info)?; - - Ok((Default::default(), next_len)) - } - /// Do the pre-dispatch checks. This can be applied to both signed and unsigned. /// /// It checks and notes the new weight and length. - pub fn do_prepare( + pub fn do_pre_dispatch( info: &DispatchInfoOf, - next_len: u32, + len: usize, ) -> Result<(), TransactionValidityError> { + let next_len = Self::check_block_length(info, len)?; let next_weight = Self::check_block_weight(info)?; - // Extrinsic weight already checked in `validate`. + Self::check_extrinsic_weight(info)?; crate::AllExtrinsicsLen::::put(next_len); crate::BlockWeight::::put(next_weight); Ok(()) } + + /// Do the validate checks. This can be applied to both signed and unsigned. + /// + /// It only checks that the block weight and length limit will not exceed. + pub fn do_validate(info: &DispatchInfoOf, len: usize) -> TransactionValidity { + // ignore the next length. If they return `Ok`, then it is below the limit. + let _ = Self::check_block_length(info, len)?; + // during validation we skip block limit check. Since the `validate_transaction` + // call runs on an empty block anyway, by this we prevent `on_initialize` weight + // consumption from causing false negatives. + Self::check_extrinsic_weight(info)?; + + Ok(Default::default()) + } } pub fn calculate_consumed_weight( @@ -208,55 +201,62 @@ where Ok(all_weight) } -impl TransactionExtensionBase for CheckWeight { - const IDENTIFIER: &'static str = "CheckWeight"; - type Implicit = (); - - fn weight(&self) -> Weight { - ::check_weight() - } -} -impl TransactionExtension - for CheckWeight +impl SignedExtension for CheckWeight where T::RuntimeCall: Dispatchable, { + type AccountId = T::AccountId; + type Call = T::RuntimeCall; + type AdditionalSigned = (); type Pre = (); - type Val = u32; /* next block length */ + const IDENTIFIER: &'static str = "CheckWeight"; + + fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { + Ok(()) + } + + fn pre_dispatch( + self, + _who: &Self::AccountId, + _call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result<(), TransactionValidityError> { + Self::do_pre_dispatch(info, len) + } fn validate( &self, - origin: T::RuntimeOrigin, - _call: &T::RuntimeCall, - info: &DispatchInfoOf, + _who: &Self::AccountId, + _call: &Self::Call, + info: &DispatchInfoOf, len: usize, - _context: &mut Context, - _self_implicit: Self::Implicit, - _inherited_implication: &impl Encode, - ) -> ValidateResult { - let (validity, next_len) = Self::do_validate(info, len)?; - Ok((validity, next_len, origin)) + ) -> TransactionValidity { + Self::do_validate(info, len) } - fn prepare( - self, - val: Self::Val, - _origin: &T::RuntimeOrigin, - _call: &T::RuntimeCall, - info: &DispatchInfoOf, - _len: usize, - _context: &Context, - ) -> Result { - Self::do_prepare(info, val) + fn pre_dispatch_unsigned( + _call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result<(), TransactionValidityError> { + Self::do_pre_dispatch(info, len) + } + + fn validate_unsigned( + _call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> TransactionValidity { + Self::do_validate(info, len) } fn post_dispatch( - _pre: Self::Pre, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + _pre: Option, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, _len: usize, _result: &DispatchResult, - _context: &Context, ) -> Result<(), TransactionValidityError> { let unspent = post_info.calc_unspent(info); if unspent.any_gt(Weight::zero()) { @@ -301,7 +301,6 @@ mod tests { AllExtrinsicsLen, BlockWeight, DispatchClass, }; use frame_support::{assert_err, assert_ok, dispatch::Pays, weights::Weight}; - use sp_runtime::traits::DispatchTransaction; use sp_std::marker::PhantomData; fn block_weights() -> crate::limits::BlockWeights { @@ -339,8 +338,7 @@ mod tests { } check(|max, len| { - let next_len = CheckWeight::::check_block_length(max, len).unwrap(); - assert_ok!(CheckWeight::::do_prepare(max, next_len)); + assert_ok!(CheckWeight::::do_pre_dispatch(max, len)); assert_eq!(System::block_weight().total(), Weight::MAX); assert!(System::block_weight().total().ref_time() > block_weight_limit().ref_time()); }); @@ -421,11 +419,9 @@ mod tests { let len = 0_usize; - let next_len = CheckWeight::::check_block_length(&max_normal, len).unwrap(); - assert_ok!(CheckWeight::::do_prepare(&max_normal, next_len)); + assert_ok!(CheckWeight::::do_pre_dispatch(&max_normal, len)); assert_eq!(System::block_weight().total(), Weight::from_parts(768, 0)); - let next_len = CheckWeight::::check_block_length(&rest_operational, len).unwrap(); - assert_ok!(CheckWeight::::do_prepare(&rest_operational, next_len)); + assert_ok!(CheckWeight::::do_pre_dispatch(&rest_operational, len)); assert_eq!(block_weight_limit(), Weight::from_parts(1024, u64::MAX)); assert_eq!(System::block_weight().total(), block_weight_limit().set_proof_size(0)); // Checking single extrinsic should not take current block weight into account. @@ -447,12 +443,10 @@ mod tests { let len = 0_usize; - let next_len = CheckWeight::::check_block_length(&rest_operational, len).unwrap(); - assert_ok!(CheckWeight::::do_prepare(&rest_operational, next_len)); + assert_ok!(CheckWeight::::do_pre_dispatch(&rest_operational, len)); // Extra 20 here from block execution + base extrinsic weight assert_eq!(System::block_weight().total(), Weight::from_parts(266, 0)); - let next_len = CheckWeight::::check_block_length(&max_normal, len).unwrap(); - assert_ok!(CheckWeight::::do_prepare(&max_normal, next_len)); + assert_ok!(CheckWeight::::do_pre_dispatch(&max_normal, len)); assert_eq!(block_weight_limit(), Weight::from_parts(1024, u64::MAX)); assert_eq!(System::block_weight().total(), block_weight_limit().set_proof_size(0)); }); @@ -475,19 +469,16 @@ mod tests { }; let len = 0_usize; - let next_len = CheckWeight::::check_block_length(&dispatch_normal, len).unwrap(); assert_err!( - CheckWeight::::do_prepare(&dispatch_normal, next_len), + CheckWeight::::do_pre_dispatch(&dispatch_normal, len), InvalidTransaction::ExhaustsResources ); - let next_len = - CheckWeight::::check_block_length(&dispatch_operational, len).unwrap(); // Thank goodness we can still do an operational transaction to possibly save the // blockchain. - assert_ok!(CheckWeight::::do_prepare(&dispatch_operational, next_len)); + assert_ok!(CheckWeight::::do_pre_dispatch(&dispatch_operational, len)); // Not too much though assert_err!( - CheckWeight::::do_prepare(&dispatch_operational, next_len), + CheckWeight::::do_pre_dispatch(&dispatch_operational, len), InvalidTransaction::ExhaustsResources ); // Even with full block, validity of single transaction should be correct. @@ -512,35 +503,21 @@ mod tests { current_weight.set(normal_limit, DispatchClass::Normal) }); // will not fit. - assert_eq!( - CheckWeight::(PhantomData) - .validate_and_prepare(Some(1).into(), CALL, &normal, len) - .unwrap_err(), - InvalidTransaction::ExhaustsResources.into() + assert_err!( + CheckWeight::(PhantomData).pre_dispatch(&1, CALL, &normal, len), + InvalidTransaction::ExhaustsResources ); // will fit. - assert_ok!(CheckWeight::(PhantomData).validate_and_prepare( - Some(1).into(), - CALL, - &op, - len - )); + assert_ok!(CheckWeight::(PhantomData).pre_dispatch(&1, CALL, &op, len)); // likewise for length limit. let len = 100_usize; AllExtrinsicsLen::::put(normal_length_limit()); - assert_eq!( - CheckWeight::(PhantomData) - .validate_and_prepare(Some(1).into(), CALL, &normal, len) - .unwrap_err(), - InvalidTransaction::ExhaustsResources.into() + assert_err!( + CheckWeight::(PhantomData).pre_dispatch(&1, CALL, &normal, len), + InvalidTransaction::ExhaustsResources ); - assert_ok!(CheckWeight::(PhantomData).validate_and_prepare( - Some(1).into(), - CALL, - &op, - len - )); + assert_ok!(CheckWeight::(PhantomData).pre_dispatch(&1, CALL, &op, len)); }) } @@ -551,12 +528,7 @@ mod tests { let normal_limit = normal_weight_limit().ref_time() as usize; let reset_check_weight = |tx, s, f| { AllExtrinsicsLen::::put(0); - let r = CheckWeight::(PhantomData).validate_and_prepare( - Some(1).into(), - CALL, - tx, - s, - ); + let r = CheckWeight::(PhantomData).pre_dispatch(&1, CALL, tx, s); if f { assert!(r.is_err()) } else { @@ -599,12 +571,7 @@ mod tests { BlockWeight::::mutate(|current_weight| { current_weight.set(s, DispatchClass::Normal) }); - let r = CheckWeight::(PhantomData).validate_and_prepare( - Some(1).into(), - CALL, - i, - len, - ); + let r = CheckWeight::(PhantomData).pre_dispatch(&1, CALL, i, len); if f { assert!(r.is_err()) } else { @@ -637,22 +604,18 @@ mod tests { .set(Weight::from_parts(256, 0) - base_extrinsic, DispatchClass::Normal); }); - let pre = CheckWeight::(PhantomData) - .validate_and_prepare(Some(1).into(), CALL, &info, len) - .unwrap() - .0; + let pre = CheckWeight::(PhantomData).pre_dispatch(&1, CALL, &info, len).unwrap(); assert_eq!( BlockWeight::::get().total(), info.weight + Weight::from_parts(256, 0) ); assert_ok!(CheckWeight::::post_dispatch( - pre, + Some(pre), &info, &post_info, len, - &Ok(()), - &() + &Ok(()) )); assert_eq!( BlockWeight::::get().total(), @@ -676,10 +639,7 @@ mod tests { current_weight.set(Weight::from_parts(128, 0), DispatchClass::Normal); }); - let pre = CheckWeight::(PhantomData) - .validate_and_prepare(Some(1).into(), CALL, &info, len) - .unwrap() - .0; + let pre = CheckWeight::(PhantomData).pre_dispatch(&1, CALL, &info, len).unwrap(); assert_eq!( BlockWeight::::get().total(), info.weight + @@ -688,12 +648,11 @@ mod tests { ); assert_ok!(CheckWeight::::post_dispatch( - pre, + Some(pre), &info, &post_info, len, - &Ok(()), - &() + &Ok(()) )); assert_eq!( BlockWeight::::get().total(), @@ -713,12 +672,7 @@ mod tests { // Initial weight from `weights.base_block` assert_eq!(System::block_weight().total(), weights.base_block); - assert_ok!(CheckWeight::(PhantomData).validate_and_prepare( - Some(1).into(), - CALL, - &free, - len - )); + assert_ok!(CheckWeight::(PhantomData).pre_dispatch(&1, CALL, &free, len)); assert_eq!( System::block_weight().total(), weights.get(DispatchClass::Normal).base_extrinsic + weights.base_block @@ -742,11 +696,9 @@ mod tests { let len = 0_usize; - let next_len = CheckWeight::::check_block_length(&max_normal, len).unwrap(); - assert_ok!(CheckWeight::::do_prepare(&max_normal, next_len)); + assert_ok!(CheckWeight::::do_pre_dispatch(&max_normal, len)); assert_eq!(System::block_weight().total(), Weight::from_parts(768, 0)); - let next_len = CheckWeight::::check_block_length(&mandatory, len).unwrap(); - assert_ok!(CheckWeight::::do_prepare(&mandatory, next_len)); + assert_ok!(CheckWeight::::do_pre_dispatch(&mandatory, len)); assert_eq!(block_weight_limit(), Weight::from_parts(1024, u64::MAX)); assert_eq!(System::block_weight().total(), Weight::from_parts(1024 + 768, 0)); assert_eq!(CheckWeight::::check_extrinsic_weight(&mandatory), Ok(())); diff --git a/substrate/frame/system/src/extensions/mod.rs b/substrate/frame/system/src/extensions/mod.rs index d79104d2240..a88c9fbf96e 100644 --- a/substrate/frame/system/src/extensions/mod.rs +++ b/substrate/frame/system/src/extensions/mod.rs @@ -22,6 +22,3 @@ pub mod check_nonce; pub mod check_spec_version; pub mod check_tx_version; pub mod check_weight; -pub mod weights; - -pub use weights::WeightInfo; diff --git a/substrate/frame/system/src/extensions/weights.rs b/substrate/frame/system/src/extensions/weights.rs deleted file mode 100644 index 0d2fcb15ee6..00000000000 --- a/substrate/frame/system/src/extensions/weights.rs +++ /dev/null @@ -1,196 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Autogenerated weights for `frame_system_extensions` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` - -// Executed Command: -// ./target/production/substrate-node -// benchmark -// pallet -// --chain=dev -// --steps=50 -// --repeat=20 -// --pallet=frame_system_extensions -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --wasm-execution=compiled -// --heap-pages=4096 -// --output=./substrate/frame/system/src/extensions/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; -use core::marker::PhantomData; - -/// Weight functions needed for `frame_system_extensions`. -pub trait WeightInfo { - fn check_genesis() -> Weight; - fn check_mortality() -> Weight; - fn check_non_zero_sender() -> Weight; - fn check_nonce() -> Weight; - fn check_spec_version() -> Weight; - fn check_tx_version() -> Weight; - fn check_weight() -> Weight; -} - -/// Weights for `frame_system_extensions` using the Substrate node and recommended hardware. -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_genesis() -> Weight { - // Proof Size summary in bytes: - // Measured: `54` - // Estimated: `3509` - // Minimum execution time: 3_876_000 picoseconds. - Weight::from_parts(4_160_000, 3509) - .saturating_add(T::DbWeight::get().reads(1_u64)) - } - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_mortality() -> Weight { - // Proof Size summary in bytes: - // Measured: `92` - // Estimated: `3509` - // Minimum execution time: 6_296_000 picoseconds. - Weight::from_parts(6_523_000, 3509) - .saturating_add(T::DbWeight::get().reads(1_u64)) - } - fn check_non_zero_sender() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 449_000 picoseconds. - Weight::from_parts(527_000, 0) - } - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn check_nonce() -> Weight { - // Proof Size summary in bytes: - // Measured: `101` - // Estimated: `3593` - // Minimum execution time: 5_689_000 picoseconds. - Weight::from_parts(6_000_000, 3593) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - fn check_spec_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 399_000 picoseconds. - Weight::from_parts(461_000, 0) - } - fn check_tx_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 390_000 picoseconds. - Weight::from_parts(439_000, 0) - } - /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) - /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn check_weight() -> Weight { - // Proof Size summary in bytes: - // Measured: `24` - // Estimated: `1489` - // Minimum execution time: 4_375_000 picoseconds. - Weight::from_parts(4_747_000, 1489) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } -} - -// For backwards compatibility and tests. -impl WeightInfo for () { - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_genesis() -> Weight { - // Proof Size summary in bytes: - // Measured: `54` - // Estimated: `3509` - // Minimum execution time: 3_876_000 picoseconds. - Weight::from_parts(4_160_000, 3509) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - } - /// Storage: `System::BlockHash` (r:1 w:0) - /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) - fn check_mortality() -> Weight { - // Proof Size summary in bytes: - // Measured: `92` - // Estimated: `3509` - // Minimum execution time: 6_296_000 picoseconds. - Weight::from_parts(6_523_000, 3509) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - } - fn check_non_zero_sender() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 449_000 picoseconds. - Weight::from_parts(527_000, 0) - } - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn check_nonce() -> Weight { - // Proof Size summary in bytes: - // Measured: `101` - // Estimated: `3593` - // Minimum execution time: 5_689_000 picoseconds. - Weight::from_parts(6_000_000, 3593) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - fn check_spec_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 399_000 picoseconds. - Weight::from_parts(461_000, 0) - } - fn check_tx_version() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 390_000 picoseconds. - Weight::from_parts(439_000, 0) - } - /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) - /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn check_weight() -> Weight { - // Proof Size summary in bytes: - // Measured: `24` - // Estimated: `1489` - // Minimum execution time: 4_375_000 picoseconds. - Weight::from_parts(4_747_000, 1489) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } -} diff --git a/substrate/frame/system/src/lib.rs b/substrate/frame/system/src/lib.rs index 0318f77342e..184f27b61ed 100644 --- a/substrate/frame/system/src/lib.rs +++ b/substrate/frame/system/src/lib.rs @@ -166,7 +166,7 @@ pub use extensions::{ check_genesis::CheckGenesis, check_mortality::CheckMortality, check_non_zero_sender::CheckNonZeroSender, check_nonce::CheckNonce, check_spec_version::CheckSpecVersion, check_tx_version::CheckTxVersion, - check_weight::CheckWeight, WeightInfo as ExtensionsWeightInfo, + check_weight::CheckWeight, }; // Backward compatible re-export. pub use extensions::check_mortality::CheckMortality as CheckEra; @@ -284,7 +284,6 @@ pub mod pallet { type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = (); - type ExtensionsWeightInfo = (); type SS58Prefix = (); type Version = (); type BlockWeights = (); @@ -357,9 +356,6 @@ pub mod pallet { /// Weight information for the extrinsics of this pallet. type SystemWeightInfo = (); - /// Weight information for the extensions of this pallet. - type ExtensionsWeightInfo = (); - /// This is used as an identifier of the chain. type SS58Prefix = (); @@ -567,12 +563,8 @@ pub mod pallet { /// All resources should be cleaned up associated with the given account. type OnKilledAccount: OnKilledAccount; - /// Weight information for the extrinsics of this pallet. type SystemWeightInfo: WeightInfo; - /// Weight information for the transaction extensions of this pallet. - type ExtensionsWeightInfo: extensions::WeightInfo; - /// The designated SS58 prefix of this chain. /// /// This replaces the "ss58Format" property declared in the chain spec. Reason is diff --git a/substrate/frame/system/src/offchain.rs b/substrate/frame/system/src/offchain.rs index ee73e33fe31..a019cfd666e 100644 --- a/substrate/frame/system/src/offchain.rs +++ b/substrate/frame/system/src/offchain.rs @@ -79,9 +79,6 @@ pub struct SubmitTransaction, Overarchi _phantom: sp_std::marker::PhantomData<(T, OverarchingCall)>, } -// TODO [#2415]: Avoid splitting call and the totally opaque `signature`; `CreateTransaction` trait -// should provide something which impls `Encode`, which can be sent onwards to -// `sp_io::offchain::submit_transaction`. There's no great need to split things up as in here. impl SubmitTransaction where T: SendTransactionTypes, @@ -91,8 +88,6 @@ where call: >::OverarchingCall, signature: Option<::SignaturePayload>, ) -> Result<(), ()> { - // TODO: Use regular transaction API instead. - #[allow(deprecated)] let xt = T::Extrinsic::new(call, signature).ok_or(())?; sp_io::offchain::submit_transaction(xt.encode()) } @@ -476,7 +471,7 @@ pub trait SendTransactionTypes { /// /// This trait is meant to be implemented by the runtime and is responsible for constructing /// a payload to be signed and contained within the extrinsic. -/// This will most likely include creation of `TxExtension` (a tuple of `TransactionExtension`s). +/// This will most likely include creation of `SignedExtra` (a set of `SignedExtensions`). /// Note that the result can be altered by inspecting the `Call` (for instance adjusting /// fees, or mortality depending on the `pallet` being called). pub trait CreateSignedTransaction: @@ -626,17 +621,14 @@ mod tests { use crate::mock::{RuntimeCall, Test as TestRuntime, CALL}; use codec::Decode; use sp_core::offchain::{testing, TransactionPoolExt}; - use sp_runtime::{ - generic::UncheckedExtrinsic, - testing::{TestSignature, UintAuthorityId}, - }; + use sp_runtime::testing::{TestSignature, TestXt, UintAuthorityId}; impl SigningTypes for TestRuntime { type Public = UintAuthorityId; type Signature = TestSignature; } - type Extrinsic = UncheckedExtrinsic; + type Extrinsic = TestXt; impl SendTransactionTypes for TestRuntime { type Extrinsic = Extrinsic; @@ -701,7 +693,7 @@ mod tests { let _tx3 = pool_state.write().transactions.pop().unwrap(); assert!(pool_state.read().transactions.is_empty()); let tx1 = Extrinsic::decode(&mut &*tx1).unwrap(); - assert!(tx1.is_inherent()); + assert_eq!(tx1.signature, None); }); } @@ -732,7 +724,7 @@ mod tests { let tx1 = pool_state.write().transactions.pop().unwrap(); assert!(pool_state.read().transactions.is_empty()); let tx1 = Extrinsic::decode(&mut &*tx1).unwrap(); - assert!(tx1.is_inherent()); + assert_eq!(tx1.signature, None); }); } @@ -766,7 +758,7 @@ mod tests { let _tx2 = pool_state.write().transactions.pop().unwrap(); assert!(pool_state.read().transactions.is_empty()); let tx1 = Extrinsic::decode(&mut &*tx1).unwrap(); - assert!(tx1.is_inherent()); + assert_eq!(tx1.signature, None); }); } @@ -798,7 +790,7 @@ mod tests { let tx1 = pool_state.write().transactions.pop().unwrap(); assert!(pool_state.read().transactions.is_empty()); let tx1 = Extrinsic::decode(&mut &*tx1).unwrap(); - assert!(tx1.is_inherent()); + assert_eq!(tx1.signature, None); }); } } diff --git a/substrate/frame/system/src/weights.rs b/substrate/frame/system/src/weights.rs index bd64bbf3763..41807dea1c5 100644 --- a/substrate/frame/system/src/weights.rs +++ b/substrate/frame/system/src/weights.rs @@ -15,31 +15,30 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `frame_system` +//! Autogenerated weights for frame_system //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-s7kdgajz-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// target/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=frame_system -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/system/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=frame-system +// --chain=dev +// --header=./HEADER-APACHE2 +// --output=./frame/system/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +48,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `frame_system`. +/// Weight functions needed for frame_system. pub trait WeightInfo { fn remark(b: u32, ) -> Weight; fn remark_with_event(b: u32, ) -> Weight; @@ -62,7 +61,7 @@ pub trait WeightInfo { fn apply_authorized_upgrade() -> Weight; } -/// Weights for `frame_system` using the Substrate node and recommended hardware. +/// Weights for frame_system using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// The range of component `b` is `[0, 3932160]`. @@ -70,86 +69,84 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_130_000 picoseconds. - Weight::from_parts(2_976_430, 0) + // Minimum execution time: 2_004_000 picoseconds. + Weight::from_parts(2_119_000, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(386, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(390, 0).saturating_mul(b.into())) } /// The range of component `b` is `[0, 3932160]`. fn remark_with_event(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_690_000 picoseconds. - Weight::from_parts(15_071_416, 0) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_387, 0).saturating_mul(b.into())) + // Minimum execution time: 8_032_000 picoseconds. + Weight::from_parts(8_097_000, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(1_455, 0).saturating_mul(b.into())) } - /// Storage: `System::Digest` (r:1 w:1) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: UNKNOWN KEY `0x3a686561707061676573` (r:0 w:1) - /// Proof: UNKNOWN KEY `0x3a686561707061676573` (r:0 w:1) + /// Storage: System Digest (r:1 w:1) + /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: unknown `0x3a686561707061676573` (r:0 w:1) + /// Proof Skipped: unknown `0x3a686561707061676573` (r:0 w:1) fn set_heap_pages() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1485` - // Minimum execution time: 3_822_000 picoseconds. - Weight::from_parts(4_099_000, 1485) + // Minimum execution time: 4_446_000 picoseconds. + Weight::from_parts(4_782_000, 1485) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) - /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:1) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: UNKNOWN KEY `0x3a636f6465` (r:0 w:1) - /// Proof: UNKNOWN KEY `0x3a636f6465` (r:0 w:1) + /// Storage: System Digest (r:1 w:1) + /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: unknown `0x3a636f6465` (r:0 w:1) + /// Proof Skipped: unknown `0x3a636f6465` (r:0 w:1) fn set_code() -> Weight { // Proof Size summary in bytes: - // Measured: `142` - // Estimated: `67035` - // Minimum execution time: 81_512_045_000 picoseconds. - Weight::from_parts(82_321_281_000, 67035) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Measured: `0` + // Estimated: `1485` + // Minimum execution time: 84_000_503_000 picoseconds. + Weight::from_parts(87_586_619_000, 1485) + .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Skipped::Metadata` (r:0 w:0) - /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `i` is `[0, 1000]`. fn set_storage(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_074_000 picoseconds. - Weight::from_parts(2_137_000, 0) - // Standard Error: 879 - .saturating_add(Weight::from_parts(797_224, 0).saturating_mul(i.into())) + // Minimum execution time: 2_086_000 picoseconds. + Weight::from_parts(2_175_000, 0) + // Standard Error: 1_056 + .saturating_add(Weight::from_parts(841_511, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } - /// Storage: `Skipped::Metadata` (r:0 w:0) - /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `i` is `[0, 1000]`. fn kill_storage(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_122_000 picoseconds. - Weight::from_parts(2_208_000, 0) - // Standard Error: 855 - .saturating_add(Weight::from_parts(594_034, 0).saturating_mul(i.into())) + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_255_000, 0) + // Standard Error: 1_425 + .saturating_add(Weight::from_parts(662_473, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } - /// Storage: `Skipped::Metadata` (r:0 w:0) - /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `p` is `[0, 1000]`. fn kill_prefix(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `129 + p * (69 ±0)` - // Estimated: `135 + p * (70 ±0)` - // Minimum execution time: 3_992_000 picoseconds. - Weight::from_parts(4_170_000, 135) - // Standard Error: 1_377 - .saturating_add(Weight::from_parts(1_267_892, 0).saturating_mul(p.into())) + // Measured: `115 + p * (69 ±0)` + // Estimated: `128 + p * (70 ±0)` + // Minimum execution time: 4_189_000 picoseconds. + Weight::from_parts(4_270_000, 128) + // Standard Error: 2_296 + .saturating_add(Weight::from_parts(1_389_650, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) .saturating_add(Weight::from_parts(0, 70).saturating_mul(p.into())) @@ -160,116 +157,114 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_872_000 picoseconds. - Weight::from_parts(9_513_000, 0) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Minimum execution time: 33_027_000 picoseconds. + Weight::from_parts(33_027_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `System::AuthorizedUpgrade` (r:1 w:1) /// Proof: `System::AuthorizedUpgrade` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) - /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) - /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) /// Storage: `System::Digest` (r:1 w:1) /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: UNKNOWN KEY `0x3a636f6465` (r:0 w:1) /// Proof: UNKNOWN KEY `0x3a636f6465` (r:0 w:1) fn apply_authorized_upgrade() -> Weight { // Proof Size summary in bytes: - // Measured: `164` - // Estimated: `67035` - // Minimum execution time: 85_037_546_000 picoseconds. - Weight::from_parts(85_819_414_000, 67035) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + // Measured: `22` + // Estimated: `1518` + // Minimum execution time: 118_101_992_000 picoseconds. + Weight::from_parts(118_101_992_000, 0) + .saturating_add(Weight::from_parts(0, 1518)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(3)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { /// The range of component `b` is `[0, 3932160]`. fn remark(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_130_000 picoseconds. - Weight::from_parts(2_976_430, 0) + // Minimum execution time: 2_004_000 picoseconds. + Weight::from_parts(2_119_000, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(386, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(390, 0).saturating_mul(b.into())) } /// The range of component `b` is `[0, 3932160]`. fn remark_with_event(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_690_000 picoseconds. - Weight::from_parts(15_071_416, 0) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_387, 0).saturating_mul(b.into())) + // Minimum execution time: 8_032_000 picoseconds. + Weight::from_parts(8_097_000, 0) + // Standard Error: 2 + .saturating_add(Weight::from_parts(1_455, 0).saturating_mul(b.into())) } - /// Storage: `System::Digest` (r:1 w:1) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: UNKNOWN KEY `0x3a686561707061676573` (r:0 w:1) - /// Proof: UNKNOWN KEY `0x3a686561707061676573` (r:0 w:1) + /// Storage: System Digest (r:1 w:1) + /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: unknown `0x3a686561707061676573` (r:0 w:1) + /// Proof Skipped: unknown `0x3a686561707061676573` (r:0 w:1) fn set_heap_pages() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1485` - // Minimum execution time: 3_822_000 picoseconds. - Weight::from_parts(4_099_000, 1485) + // Minimum execution time: 4_446_000 picoseconds. + Weight::from_parts(4_782_000, 1485) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) - /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:1) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: UNKNOWN KEY `0x3a636f6465` (r:0 w:1) - /// Proof: UNKNOWN KEY `0x3a636f6465` (r:0 w:1) + /// Storage: System Digest (r:1 w:1) + /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: unknown `0x3a636f6465` (r:0 w:1) + /// Proof Skipped: unknown `0x3a636f6465` (r:0 w:1) fn set_code() -> Weight { // Proof Size summary in bytes: - // Measured: `142` - // Estimated: `67035` - // Minimum execution time: 81_512_045_000 picoseconds. - Weight::from_parts(82_321_281_000, 67035) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Measured: `0` + // Estimated: `1485` + // Minimum execution time: 84_000_503_000 picoseconds. + Weight::from_parts(87_586_619_000, 1485) + .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Skipped::Metadata` (r:0 w:0) - /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `i` is `[0, 1000]`. fn set_storage(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_074_000 picoseconds. - Weight::from_parts(2_137_000, 0) - // Standard Error: 879 - .saturating_add(Weight::from_parts(797_224, 0).saturating_mul(i.into())) + // Minimum execution time: 2_086_000 picoseconds. + Weight::from_parts(2_175_000, 0) + // Standard Error: 1_056 + .saturating_add(Weight::from_parts(841_511, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) } - /// Storage: `Skipped::Metadata` (r:0 w:0) - /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `i` is `[0, 1000]`. fn kill_storage(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_122_000 picoseconds. - Weight::from_parts(2_208_000, 0) - // Standard Error: 855 - .saturating_add(Weight::from_parts(594_034, 0).saturating_mul(i.into())) + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_255_000, 0) + // Standard Error: 1_425 + .saturating_add(Weight::from_parts(662_473, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(i.into()))) } - /// Storage: `Skipped::Metadata` (r:0 w:0) - /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Skipped Metadata (r:0 w:0) + /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) /// The range of component `p` is `[0, 1000]`. fn kill_prefix(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `129 + p * (69 ±0)` - // Estimated: `135 + p * (70 ±0)` - // Minimum execution time: 3_992_000 picoseconds. - Weight::from_parts(4_170_000, 135) - // Standard Error: 1_377 - .saturating_add(Weight::from_parts(1_267_892, 0).saturating_mul(p.into())) + // Measured: `115 + p * (69 ±0)` + // Estimated: `128 + p * (70 ±0)` + // Minimum execution time: 4_189_000 picoseconds. + Weight::from_parts(4_270_000, 128) + // Standard Error: 2_296 + .saturating_add(Weight::from_parts(1_389_650, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(p.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(p.into()))) .saturating_add(Weight::from_parts(0, 70).saturating_mul(p.into())) @@ -280,25 +275,25 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_872_000 picoseconds. - Weight::from_parts(9_513_000, 0) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Minimum execution time: 33_027_000 picoseconds. + Weight::from_parts(33_027_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(RocksDbWeight::get().writes(1)) } /// Storage: `System::AuthorizedUpgrade` (r:1 w:1) /// Proof: `System::AuthorizedUpgrade` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) - /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) - /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) /// Storage: `System::Digest` (r:1 w:1) /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: UNKNOWN KEY `0x3a636f6465` (r:0 w:1) /// Proof: UNKNOWN KEY `0x3a636f6465` (r:0 w:1) fn apply_authorized_upgrade() -> Weight { // Proof Size summary in bytes: - // Measured: `164` - // Estimated: `67035` - // Minimum execution time: 85_037_546_000 picoseconds. - Weight::from_parts(85_819_414_000, 67035) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + // Measured: `22` + // Estimated: `1518` + // Minimum execution time: 118_101_992_000 picoseconds. + Weight::from_parts(118_101_992_000, 0) + .saturating_add(Weight::from_parts(0, 1518)) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(3)) } } diff --git a/substrate/frame/timestamp/src/weights.rs b/substrate/frame/timestamp/src/weights.rs index 2df68ba0f1e..46c54473486 100644 --- a/substrate/frame/timestamp/src/weights.rs +++ b/substrate/frame/timestamp/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_timestamp` +//! Autogenerated weights for pallet_timestamp //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/timestamp/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/timestamp/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,57 +50,57 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_timestamp`. +/// Weight functions needed for pallet_timestamp. pub trait WeightInfo { fn set() -> Weight; fn on_finalize() -> Weight; } -/// Weights for `pallet_timestamp` using the Substrate node and recommended hardware. +/// Weights for pallet_timestamp using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Timestamp::Now` (r:1 w:1) - /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Babe::CurrentSlot` (r:1 w:0) - /// Proof: `Babe::CurrentSlot` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: Timestamp Now (r:1 w:1) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Babe CurrentSlot (r:1 w:0) + /// Proof: Babe CurrentSlot (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) fn set() -> Weight { // Proof Size summary in bytes: - // Measured: `345` + // Measured: `312` // Estimated: `1493` - // Minimum execution time: 8_417_000 picoseconds. - Weight::from_parts(8_932_000, 1493) + // Minimum execution time: 9_857_000 picoseconds. + Weight::from_parts(10_492_000, 1493) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn on_finalize() -> Weight { // Proof Size summary in bytes: - // Measured: `194` + // Measured: `161` // Estimated: `0` - // Minimum execution time: 3_911_000 picoseconds. - Weight::from_parts(4_092_000, 0) + // Minimum execution time: 4_175_000 picoseconds. + Weight::from_parts(4_334_000, 0) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Timestamp::Now` (r:1 w:1) - /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `Babe::CurrentSlot` (r:1 w:0) - /// Proof: `Babe::CurrentSlot` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: Timestamp Now (r:1 w:1) + /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Babe CurrentSlot (r:1 w:0) + /// Proof: Babe CurrentSlot (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) fn set() -> Weight { // Proof Size summary in bytes: - // Measured: `345` + // Measured: `312` // Estimated: `1493` - // Minimum execution time: 8_417_000 picoseconds. - Weight::from_parts(8_932_000, 1493) + // Minimum execution time: 9_857_000 picoseconds. + Weight::from_parts(10_492_000, 1493) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn on_finalize() -> Weight { // Proof Size summary in bytes: - // Measured: `194` + // Measured: `161` // Estimated: `0` - // Minimum execution time: 3_911_000 picoseconds. - Weight::from_parts(4_092_000, 0) + // Minimum execution time: 4_175_000 picoseconds. + Weight::from_parts(4_334_000, 0) } } diff --git a/substrate/frame/tips/src/weights.rs b/substrate/frame/tips/src/weights.rs index dbe1ed246ff..ec622866715 100644 --- a/substrate/frame/tips/src/weights.rs +++ b/substrate/frame/tips/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_tips` +//! Autogenerated weights for pallet_tips //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/tips/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/tips/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_tips`. +/// Weight functions needed for pallet_tips. pub trait WeightInfo { fn report_awesome(r: u32, ) -> Weight; fn retract_tip() -> Weight; @@ -59,220 +60,220 @@ pub trait WeightInfo { fn slash_tip(t: u32, ) -> Weight; } -/// Weights for `pallet_tips` using the Substrate node and recommended hardware. +/// Weights for pallet_tips using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Tips::Reasons` (r:1 w:1) - /// Proof: `Tips::Reasons` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Tips::Tips` (r:1 w:1) - /// Proof: `Tips::Tips` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Tips Reasons (r:1 w:1) + /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) + /// Storage: Tips Tips (r:1 w:1) + /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 300]`. fn report_awesome(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `4` // Estimated: `3469` - // Minimum execution time: 25_145_000 picoseconds. - Weight::from_parts(26_085_800, 3469) - // Standard Error: 216 - .saturating_add(Weight::from_parts(5_121, 0).saturating_mul(r.into())) + // Minimum execution time: 29_576_000 picoseconds. + Weight::from_parts(30_722_650, 3469) + // Standard Error: 192 + .saturating_add(Weight::from_parts(2_601, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Tips::Tips` (r:1 w:1) - /// Proof: `Tips::Tips` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Tips::Reasons` (r:0 w:1) - /// Proof: `Tips::Reasons` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Tips Tips (r:1 w:1) + /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) + /// Storage: Tips Reasons (r:0 w:1) + /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) fn retract_tip() -> Weight { // Proof Size summary in bytes: // Measured: `221` // Estimated: `3686` - // Minimum execution time: 25_302_000 picoseconds. - Weight::from_parts(26_229_000, 3686) + // Minimum execution time: 28_522_000 picoseconds. + Weight::from_parts(29_323_000, 3686) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Elections::Members` (r:1 w:0) - /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Tips::Reasons` (r:1 w:1) - /// Proof: `Tips::Reasons` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Tips::Tips` (r:0 w:1) - /// Proof: `Tips::Tips` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Tips Reasons (r:1 w:1) + /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) + /// Storage: Tips Tips (r:0 w:1) + /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 300]`. /// The range of component `t` is `[1, 13]`. fn tip_new(r: u32, t: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `526 + t * (64 ±0)` // Estimated: `3991 + t * (64 ±0)` - // Minimum execution time: 16_600_000 picoseconds. - Weight::from_parts(17_071_638, 3991) - // Standard Error: 131 - .saturating_add(Weight::from_parts(1_138, 0).saturating_mul(r.into())) - // Standard Error: 3_125 - .saturating_add(Weight::from_parts(82_996, 0).saturating_mul(t.into())) + // Minimum execution time: 19_650_000 picoseconds. + Weight::from_parts(19_837_982, 3991) + // Standard Error: 151 + .saturating_add(Weight::from_parts(1_746, 0).saturating_mul(r.into())) + // Standard Error: 3_588 + .saturating_add(Weight::from_parts(102_359, 0).saturating_mul(t.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(t.into())) } - /// Storage: `Elections::Members` (r:1 w:0) - /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Tips::Tips` (r:1 w:1) - /// Proof: `Tips::Tips` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Tips Tips (r:1 w:1) + /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) /// The range of component `t` is `[1, 13]`. fn tip(t: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `747 + t * (112 ±0)` // Estimated: `4212 + t * (112 ±0)` - // Minimum execution time: 13_972_000 picoseconds. - Weight::from_parts(14_269_356, 4212) - // Standard Error: 4_695 - .saturating_add(Weight::from_parts(205_433, 0).saturating_mul(t.into())) + // Minimum execution time: 15_641_000 picoseconds. + Weight::from_parts(15_745_460, 4212) + // Standard Error: 5_106 + .saturating_add(Weight::from_parts(229_475, 0).saturating_mul(t.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 112).saturating_mul(t.into())) } - /// Storage: `Tips::Tips` (r:1 w:1) - /// Proof: `Tips::Tips` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Elections::Members` (r:1 w:0) - /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Tips::Reasons` (r:0 w:1) - /// Proof: `Tips::Reasons` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Tips Tips (r:1 w:1) + /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Tips Reasons (r:0 w:1) + /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) /// The range of component `t` is `[1, 13]`. fn close_tip(t: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `786 + t * (112 ±0)` // Estimated: `4242 + t * (112 ±0)` - // Minimum execution time: 51_878_000 picoseconds. - Weight::from_parts(54_513_477, 4242) - // Standard Error: 12_281 - .saturating_add(Weight::from_parts(126_605, 0).saturating_mul(t.into())) + // Minimum execution time: 62_059_000 picoseconds. + Weight::from_parts(64_604_554, 4242) + // Standard Error: 11_818 + .saturating_add(Weight::from_parts(116_297, 0).saturating_mul(t.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 112).saturating_mul(t.into())) } - /// Storage: `Tips::Tips` (r:1 w:1) - /// Proof: `Tips::Tips` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Tips::Reasons` (r:0 w:1) - /// Proof: `Tips::Reasons` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Tips Tips (r:1 w:1) + /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) + /// Storage: Tips Reasons (r:0 w:1) + /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) /// The range of component `t` is `[1, 13]`. fn slash_tip(t: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `269` // Estimated: `3734` - // Minimum execution time: 11_800_000 picoseconds. - Weight::from_parts(12_520_984, 3734) - // Standard Error: 2_360 - .saturating_add(Weight::from_parts(28_777, 0).saturating_mul(t.into())) + // Minimum execution time: 14_133_000 picoseconds. + Weight::from_parts(14_957_547, 3734) + // Standard Error: 2_765 + .saturating_add(Weight::from_parts(22_138, 0).saturating_mul(t.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Tips::Reasons` (r:1 w:1) - /// Proof: `Tips::Reasons` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Tips::Tips` (r:1 w:1) - /// Proof: `Tips::Tips` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Tips Reasons (r:1 w:1) + /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) + /// Storage: Tips Tips (r:1 w:1) + /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 300]`. fn report_awesome(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `4` // Estimated: `3469` - // Minimum execution time: 25_145_000 picoseconds. - Weight::from_parts(26_085_800, 3469) - // Standard Error: 216 - .saturating_add(Weight::from_parts(5_121, 0).saturating_mul(r.into())) + // Minimum execution time: 29_576_000 picoseconds. + Weight::from_parts(30_722_650, 3469) + // Standard Error: 192 + .saturating_add(Weight::from_parts(2_601, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Tips::Tips` (r:1 w:1) - /// Proof: `Tips::Tips` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Tips::Reasons` (r:0 w:1) - /// Proof: `Tips::Reasons` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Tips Tips (r:1 w:1) + /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) + /// Storage: Tips Reasons (r:0 w:1) + /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) fn retract_tip() -> Weight { // Proof Size summary in bytes: // Measured: `221` // Estimated: `3686` - // Minimum execution time: 25_302_000 picoseconds. - Weight::from_parts(26_229_000, 3686) + // Minimum execution time: 28_522_000 picoseconds. + Weight::from_parts(29_323_000, 3686) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Elections::Members` (r:1 w:0) - /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Tips::Reasons` (r:1 w:1) - /// Proof: `Tips::Reasons` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Tips::Tips` (r:0 w:1) - /// Proof: `Tips::Tips` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Tips Reasons (r:1 w:1) + /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) + /// Storage: Tips Tips (r:0 w:1) + /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) /// The range of component `r` is `[0, 300]`. /// The range of component `t` is `[1, 13]`. fn tip_new(r: u32, t: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `526 + t * (64 ±0)` // Estimated: `3991 + t * (64 ±0)` - // Minimum execution time: 16_600_000 picoseconds. - Weight::from_parts(17_071_638, 3991) - // Standard Error: 131 - .saturating_add(Weight::from_parts(1_138, 0).saturating_mul(r.into())) - // Standard Error: 3_125 - .saturating_add(Weight::from_parts(82_996, 0).saturating_mul(t.into())) + // Minimum execution time: 19_650_000 picoseconds. + Weight::from_parts(19_837_982, 3991) + // Standard Error: 151 + .saturating_add(Weight::from_parts(1_746, 0).saturating_mul(r.into())) + // Standard Error: 3_588 + .saturating_add(Weight::from_parts(102_359, 0).saturating_mul(t.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(t.into())) } - /// Storage: `Elections::Members` (r:1 w:0) - /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Tips::Tips` (r:1 w:1) - /// Proof: `Tips::Tips` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Tips Tips (r:1 w:1) + /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) /// The range of component `t` is `[1, 13]`. fn tip(t: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `747 + t * (112 ±0)` // Estimated: `4212 + t * (112 ±0)` - // Minimum execution time: 13_972_000 picoseconds. - Weight::from_parts(14_269_356, 4212) - // Standard Error: 4_695 - .saturating_add(Weight::from_parts(205_433, 0).saturating_mul(t.into())) + // Minimum execution time: 15_641_000 picoseconds. + Weight::from_parts(15_745_460, 4212) + // Standard Error: 5_106 + .saturating_add(Weight::from_parts(229_475, 0).saturating_mul(t.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 112).saturating_mul(t.into())) } - /// Storage: `Tips::Tips` (r:1 w:1) - /// Proof: `Tips::Tips` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Elections::Members` (r:1 w:0) - /// Proof: `Elections::Members` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Tips::Reasons` (r:0 w:1) - /// Proof: `Tips::Reasons` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Tips Tips (r:1 w:1) + /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) + /// Storage: Elections Members (r:1 w:0) + /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Tips Reasons (r:0 w:1) + /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) /// The range of component `t` is `[1, 13]`. fn close_tip(t: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `786 + t * (112 ±0)` // Estimated: `4242 + t * (112 ±0)` - // Minimum execution time: 51_878_000 picoseconds. - Weight::from_parts(54_513_477, 4242) - // Standard Error: 12_281 - .saturating_add(Weight::from_parts(126_605, 0).saturating_mul(t.into())) + // Minimum execution time: 62_059_000 picoseconds. + Weight::from_parts(64_604_554, 4242) + // Standard Error: 11_818 + .saturating_add(Weight::from_parts(116_297, 0).saturating_mul(t.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 112).saturating_mul(t.into())) } - /// Storage: `Tips::Tips` (r:1 w:1) - /// Proof: `Tips::Tips` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Tips::Reasons` (r:0 w:1) - /// Proof: `Tips::Reasons` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: Tips Tips (r:1 w:1) + /// Proof Skipped: Tips Tips (max_values: None, max_size: None, mode: Measured) + /// Storage: Tips Reasons (r:0 w:1) + /// Proof Skipped: Tips Reasons (max_values: None, max_size: None, mode: Measured) /// The range of component `t` is `[1, 13]`. fn slash_tip(t: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `269` // Estimated: `3734` - // Minimum execution time: 11_800_000 picoseconds. - Weight::from_parts(12_520_984, 3734) - // Standard Error: 2_360 - .saturating_add(Weight::from_parts(28_777, 0).saturating_mul(t.into())) + // Minimum execution time: 14_133_000 picoseconds. + Weight::from_parts(14_957_547, 3734) + // Standard Error: 2_765 + .saturating_add(Weight::from_parts(22_138, 0).saturating_mul(t.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/substrate/frame/transaction-payment/Cargo.toml b/substrate/frame/transaction-payment/Cargo.toml index 66e0bef1436..275e1c01f92 100644 --- a/substrate/frame/transaction-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/Cargo.toml @@ -21,7 +21,6 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = ] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { optional = true, workspace = true, default-features = true } -frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } sp-core = { path = "../../primitives/core", default-features = false } @@ -37,7 +36,6 @@ pallet-balances = { path = "../balances" } default = ["std"] std = [ "codec/std", - "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "pallet-balances/std", @@ -48,13 +46,6 @@ std = [ "sp-runtime/std", "sp-std/std", ] -runtime-benchmarks = [ - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "pallet-balances/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", -] try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml b/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml index 528f29e8e4a..7640cc815e5 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml @@ -19,7 +19,6 @@ targets = ["x86_64-unknown-linux-gnu"] # Substrate dependencies sp-runtime = { path = "../../../primitives/runtime", default-features = false } sp-std = { path = "../../../primitives/std", default-features = false } -frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true } frame-support = { path = "../../support", default-features = false } frame-system = { path = "../../system", default-features = false } pallet-asset-conversion = { path = "../../asset-conversion", default-features = false } @@ -38,7 +37,6 @@ pallet-balances = { path = "../../balances" } default = ["std"] std = [ "codec/std", - "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "pallet-asset-conversion/std", @@ -52,16 +50,6 @@ std = [ "sp-std/std", "sp-storage/std", ] -runtime-benchmarks = [ - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "pallet-asset-conversion/runtime-benchmarks", - "pallet-assets/runtime-benchmarks", - "pallet-balances/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", -] try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/README.md b/substrate/frame/transaction-payment/asset-conversion-tx-payment/README.md index fcd1527526e..eccba773673 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/README.md +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/README.md @@ -16,6 +16,6 @@ asset. ### Integration This pallet wraps FRAME's transaction payment pallet and functions as a replacement. This means you should include both pallets in your `construct_runtime` macro, but only include this -pallet's [`TransactionExtension`] ([`ChargeAssetTxPayment`]). +pallet's [`SignedExtension`] ([`ChargeAssetTxPayment`]). License: Apache-2.0 diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/benchmarking.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/benchmarking.rs deleted file mode 100644 index 0bffb991e4a..00000000000 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/benchmarking.rs +++ /dev/null @@ -1,125 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Benchmarks for Asset Conversion Tx Payment Pallet's transaction extension - -use super::*; -use crate::Pallet; -use frame_benchmarking::v2::*; -use frame_support::{ - dispatch::{DispatchInfo, PostDispatchInfo}, - pallet_prelude::*, -}; -use frame_system::RawOrigin; -use sp_runtime::traits::{AsSystemOriginSigner, DispatchTransaction, Dispatchable}; - -#[benchmarks(where - T::RuntimeCall: Dispatchable, - AssetBalanceOf: Send + Sync, - BalanceOf: Send - + Sync - + From - + Into> - + Into> - + From>, - ChargeAssetIdOf: Send + Sync + Default, - ::RuntimeOrigin: AsSystemOriginSigner + Clone, -)] -mod benchmarks { - use super::*; - - #[benchmark] - fn charge_asset_tx_payment_zero() { - let caller: T::AccountId = whitelisted_caller(); - let ext: ChargeAssetTxPayment = ChargeAssetTxPayment::from(0u64.into(), None); - let inner = frame_system::Call::remark { remark: vec![] }; - let call = T::RuntimeCall::from(inner); - let info = DispatchInfo { - weight: Weight::zero(), - class: DispatchClass::Normal, - pays_fee: Pays::No, - }; - let post_info = PostDispatchInfo { actual_weight: None, pays_fee: Pays::No }; - #[block] - { - assert!(ext - .test_run(RawOrigin::Signed(caller).into(), &call, &info, 0, |_| Ok(post_info)) - .unwrap() - .is_ok()); - } - } - - #[benchmark] - fn charge_asset_tx_payment_native() { - let caller: T::AccountId = whitelisted_caller(); - let (fun_asset_id, _) = ::BenchmarkHelper::create_asset_id_parameter(1); - ::BenchmarkHelper::setup_balances_and_pool(fun_asset_id, caller.clone()); - let ext: ChargeAssetTxPayment = ChargeAssetTxPayment::from(10u64.into(), None); - let inner = frame_system::Call::remark { remark: vec![] }; - let call = T::RuntimeCall::from(inner); - let info = DispatchInfo { - weight: Weight::from_parts(10, 0), - class: DispatchClass::Operational, - pays_fee: Pays::Yes, - }; - let post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_parts(10, 0)), - pays_fee: Pays::Yes, - }; - - #[block] - { - assert!(ext - .test_run(RawOrigin::Signed(caller).into(), &call, &info, 0, |_| Ok(post_info)) - .unwrap() - .is_ok()); - } - } - - #[benchmark] - fn charge_asset_tx_payment_asset() { - let caller: T::AccountId = whitelisted_caller(); - let (fun_asset_id, asset_id) = ::BenchmarkHelper::create_asset_id_parameter(1); - ::BenchmarkHelper::setup_balances_and_pool(fun_asset_id, caller.clone()); - - let tip = 10u64.into(); - let ext: ChargeAssetTxPayment = ChargeAssetTxPayment::from(tip, Some(asset_id)); - let inner = frame_system::Call::remark { remark: vec![] }; - let call = T::RuntimeCall::from(inner); - let info = DispatchInfo { - weight: Weight::from_parts(10, 0), - class: DispatchClass::Operational, - pays_fee: Pays::Yes, - }; - let post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_parts(10, 0)), - pays_fee: Pays::Yes, - }; - - #[block] - { - assert!(ext - .test_run(RawOrigin::Signed(caller.clone()).into(), &call, &info, 0, |_| Ok( - post_info - )) - .unwrap() - .is_ok()); - } - } - - impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Runtime); -} diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/lib.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/lib.rs index 8ef7c2ba38e..ed0ed56e6e0 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/lib.rs +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/lib.rs @@ -20,8 +20,8 @@ //! //! ## Overview //! -//! This pallet provides a `TransactionExtension` with an optional `AssetId` that specifies the -//! asset to be used for payment (defaulting to the native token on `None`). It expects an +//! This pallet provides a `SignedExtension` with an optional `AssetId` that specifies the asset +//! to be used for payment (defaulting to the native token on `None`). It expects an //! [`OnChargeAssetTransaction`] implementation analogous to [`pallet-transaction-payment`]. The //! included [`AssetConversionAdapter`] (implementing [`OnChargeAssetTransaction`]) determines the //! fee amount by converting the fee calculated by [`pallet-transaction-payment`] in the native @@ -31,7 +31,7 @@ //! //! This pallet does not have any dispatchable calls or storage. It wraps FRAME's Transaction //! Payment pallet and functions as a replacement. This means you should include both pallets in -//! your `construct_runtime` macro, but only include this pallet's [`TransactionExtension`] +//! your `construct_runtime` macro, but only include this pallet's [`SignedExtension`] //! ([`ChargeAssetTxPayment`]). //! //! ## Terminology @@ -53,29 +53,23 @@ use frame_support::{ }, DefaultNoBound, }; -use pallet_transaction_payment::{ChargeTransactionPayment, OnChargeTransaction}; +use pallet_transaction_payment::OnChargeTransaction; use scale_info::TypeInfo; use sp_runtime::{ - traits::{ - AsSystemOriginSigner, DispatchInfoOf, Dispatchable, PostDispatchInfoOf, - TransactionExtension, TransactionExtensionBase, ValidateResult, Zero, + traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SignedExtension, Zero}, + transaction_validity::{ + InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction, }, - transaction_validity::{InvalidTransaction, TransactionValidityError, ValidTransaction}, }; #[cfg(test)] mod mock; #[cfg(test)] mod tests; -pub mod weights; - -#[cfg(feature = "runtime-benchmarks")] -mod benchmarking; mod payment; -use frame_support::{pallet_prelude::Weight, traits::tokens::AssetId}; +use frame_support::traits::tokens::AssetId; pub use payment::*; -pub use weights::WeightInfo; /// Type aliases used for interaction with `OnChargeTransaction`. pub(crate) type OnChargeTransactionOf = @@ -131,30 +125,11 @@ pub mod pallet { type Fungibles: Balanced; /// The actual transaction charging logic that charges the fees. type OnChargeAssetTransaction: OnChargeAssetTransaction; - /// The weight information of this pallet. - type WeightInfo: WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - /// Benchmark helper - type BenchmarkHelper: BenchmarkHelperTrait< - Self::AccountId, - <::Fungibles as Inspect>::AssetId, - <::OnChargeAssetTransaction as OnChargeAssetTransaction>::AssetId, - >; } #[pallet::pallet] pub struct Pallet(_); - #[cfg(feature = "runtime-benchmarks")] - /// Helper trait to benchmark the `ChargeAssetTxPayment` transaction extension. - pub trait BenchmarkHelperTrait { - /// Returns the `AssetId` to be used in the liquidity pool by the benchmarking code. - fn create_asset_id_parameter(id: u32) -> (FunAssetIdParameter, AssetIdParameter); - /// Create a liquidity pool for a given asset and sufficiently endow accounts to benchmark - /// the extension. - fn setup_balances_and_pool(asset_id: FunAssetIdParameter, account: AccountId); - } - #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { @@ -204,8 +179,9 @@ where who: &T::AccountId, call: &T::RuntimeCall, info: &DispatchInfoOf, - fee: BalanceOf, + len: usize, ) -> Result<(BalanceOf, InitialPayment), TransactionValidityError> { + let fee = pallet_transaction_payment::Pallet::::compute_fee(len as u32, info, self.tip); debug_assert!(self.tip <= fee, "tip should be included in the computed fee"); if fee.is_zero() { Ok((fee, InitialPayment::Nothing)) @@ -249,30 +225,7 @@ impl sp_std::fmt::Debug for ChargeAssetTxPayment { } } -impl TransactionExtensionBase for ChargeAssetTxPayment -where - AssetBalanceOf: Send + Sync, - BalanceOf: Send - + Sync - + From - + Into> - + Into> - + From>, - ChargeAssetIdOf: Send + Sync, -{ - const IDENTIFIER: &'static str = "ChargeAssetTxPayment"; - type Implicit = (); - - fn weight(&self) -> Weight { - if self.asset_id.is_some() { - ::WeightInfo::charge_asset_tx_payment_asset() - } else { - ::WeightInfo::charge_asset_tx_payment_native() - } - } -} - -impl TransactionExtension for ChargeAssetTxPayment +impl SignedExtension for ChargeAssetTxPayment where T::RuntimeCall: Dispatchable, AssetBalanceOf: Send + Sync, @@ -283,123 +236,111 @@ where + Into> + From>, ChargeAssetIdOf: Send + Sync, - ::RuntimeOrigin: AsSystemOriginSigner + Clone, { - type Val = ( - // tip - BalanceOf, - // who paid the fee - T::AccountId, - // transaction fee - BalanceOf, - ); + const IDENTIFIER: &'static str = "ChargeAssetTxPayment"; + type AccountId = T::AccountId; + type Call = T::RuntimeCall; + type AdditionalSigned = (); type Pre = ( // tip BalanceOf, // who paid the fee - T::AccountId, + Self::AccountId, // imbalance resulting from withdrawing the fee InitialPayment, // asset_id for the transaction payment Option>, ); + fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { + Ok(()) + } + fn validate( &self, - origin: ::RuntimeOrigin, - _call: &T::RuntimeCall, - info: &DispatchInfoOf, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, len: usize, - _context: &mut Context, - _self_implicit: Self::Implicit, - _inherited_implication: &impl Encode, - ) -> ValidateResult { - let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?; - // Non-mutating call of `compute_fee` to calculate the fee used in the transaction priority. - let fee = pallet_transaction_payment::Pallet::::compute_fee(len as u32, info, self.tip); + ) -> TransactionValidity { + use pallet_transaction_payment::ChargeTransactionPayment; + let (fee, _) = self.withdraw_fee(who, call, info, len)?; let priority = ChargeTransactionPayment::::get_priority(info, len, self.tip, fee); - let validity = ValidTransaction { priority, ..Default::default() }; - let val = (self.tip, who.clone(), fee); - Ok((validity, val, origin)) + Ok(ValidTransaction { priority, ..Default::default() }) } - fn prepare( + fn pre_dispatch( self, - val: Self::Val, - _origin: &::RuntimeOrigin, - call: &T::RuntimeCall, - info: &DispatchInfoOf, - _len: usize, - _context: &Context, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, ) -> Result { - let (tip, who, fee) = val; - // Mutating call of `withdraw_fee` to actually charge for the transaction. - let (_fee, initial_payment) = self.withdraw_fee(&who, call, info, fee)?; - Ok((tip, who, initial_payment, self.asset_id.clone())) + let (_fee, initial_payment) = self.withdraw_fee(who, call, info, len)?; + Ok((self.tip, who.clone(), initial_payment, self.asset_id)) } fn post_dispatch( - pre: Self::Pre, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + pre: Option, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, len: usize, result: &DispatchResult, - _context: &Context, ) -> Result<(), TransactionValidityError> { - let (tip, who, initial_payment, asset_id) = pre; - match initial_payment { - InitialPayment::Native(already_withdrawn) => { - debug_assert!( - asset_id.is_none(), - "For that payment type the `asset_id` should be None" - ); - pallet_transaction_payment::ChargeTransactionPayment::::post_dispatch( - (tip, who, already_withdrawn), - info, - post_info, - len, - result, - &(), - )?; - }, - InitialPayment::Asset(already_withdrawn) => { - debug_assert!( - asset_id.is_some(), - "For that payment type the `asset_id` should be set" - ); - let actual_fee = pallet_transaction_payment::Pallet::::compute_actual_fee( - len as u32, info, post_info, tip, - ); - - if let Some(asset_id) = asset_id { - let (used_for_fee, received_exchanged, asset_consumed) = already_withdrawn; - let converted_fee = T::OnChargeAssetTransaction::correct_and_deposit_fee( - &who, + if let Some((tip, who, initial_payment, asset_id)) = pre { + match initial_payment { + InitialPayment::Native(already_withdrawn) => { + debug_assert!( + asset_id.is_none(), + "For that payment type the `asset_id` should be None" + ); + pallet_transaction_payment::ChargeTransactionPayment::::post_dispatch( + Some((tip, who, already_withdrawn)), info, post_info, - actual_fee.into(), - tip.into(), - used_for_fee.into(), - received_exchanged.into(), - asset_id.clone(), - asset_consumed.into(), + len, + result, )?; + }, + InitialPayment::Asset(already_withdrawn) => { + debug_assert!( + asset_id.is_some(), + "For that payment type the `asset_id` should be set" + ); + let actual_fee = pallet_transaction_payment::Pallet::::compute_actual_fee( + len as u32, info, post_info, tip, + ); + + if let Some(asset_id) = asset_id { + let (used_for_fee, received_exchanged, asset_consumed) = already_withdrawn; + let converted_fee = T::OnChargeAssetTransaction::correct_and_deposit_fee( + &who, + info, + post_info, + actual_fee.into(), + tip.into(), + used_for_fee.into(), + received_exchanged.into(), + asset_id.clone(), + asset_consumed.into(), + )?; - Pallet::::deposit_event(Event::::AssetTxFeePaid { - who, - actual_fee: converted_fee, - tip, - asset_id, - }); - } - }, - InitialPayment::Nothing => { - // `actual_fee` should be zero here for any signed extrinsic. It would be - // non-zero here in case of unsigned extrinsics as they don't pay fees but - // `compute_actual_fee` is not aware of them. In both cases it's fine to just - // move ahead without adjusting the fee, though, so we do nothing. - debug_assert!(tip.is_zero(), "tip should be zero if initial fee was zero."); - }, + Pallet::::deposit_event(Event::::AssetTxFeePaid { + who, + actual_fee: converted_fee, + tip, + asset_id, + }); + } + }, + InitialPayment::Nothing => { + // `actual_fee` should be zero here for any signed extrinsic. It would be + // non-zero here in case of unsigned extrinsics as they don't pay fees but + // `compute_actual_fee` is not aware of them. In both cases it's fine to just + // move ahead without adjusting the fee, though, so we do nothing. + debug_assert!(tip.is_zero(), "tip should be zero if initial fee was zero."); + }, + } } Ok(()) diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs index 853753d41cf..c8bf2eb8f44 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs @@ -168,12 +168,12 @@ impl OnUnbalanced> for DealWithFees } } -#[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig as pallet_transaction_payment::DefaultConfig)] impl pallet_transaction_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = CurrencyAdapter; type WeightToFee = WeightToFee; type LengthToFee = TransactionByteFee; + type FeeMultiplierUpdate = (); type OperationalFeeMultiplier = ConstU8<5>; } @@ -269,72 +269,4 @@ impl Config for Runtime { type RuntimeEvent = RuntimeEvent; type Fungibles = Assets; type OnChargeAssetTransaction = AssetConversionAdapter; - type WeightInfo = (); - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = Helper; -} - -#[cfg(feature = "runtime-benchmarks")] -pub fn new_test_ext() -> sp_io::TestExternalities { - let base_weight = 5; - let balance_factor = 100; - crate::tests::ExtBuilder::default() - .balance_factor(balance_factor) - .base_weight(Weight::from_parts(base_weight, 0)) - .build() -} - -#[cfg(feature = "runtime-benchmarks")] -pub struct Helper; - -#[cfg(feature = "runtime-benchmarks")] -impl BenchmarkHelperTrait for Helper { - fn create_asset_id_parameter(id: u32) -> (u32, u32) { - (id, id) - } - - fn setup_balances_and_pool(asset_id: u32, account: u64) { - use frame_support::{assert_ok, traits::fungibles::Mutate}; - use sp_runtime::traits::StaticLookup; - assert_ok!(Assets::force_create( - RuntimeOrigin::root(), - asset_id.into(), - 42, /* owner */ - true, /* is_sufficient */ - 1, - )); - - let lp_provider = 12; - assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), lp_provider, u64::MAX / 2)); - let lp_provider_account = ::Lookup::unlookup(lp_provider); - assert_ok!(Assets::mint_into(asset_id.into(), &lp_provider_account, u64::MAX / 2)); - - let token_1 = Box::new(NativeOrWithId::Native); - let token_2 = Box::new(NativeOrWithId::WithId(asset_id)); - assert_ok!(AssetConversion::create_pool( - RuntimeOrigin::signed(lp_provider), - token_1.clone(), - token_2.clone() - )); - - assert_ok!(AssetConversion::add_liquidity( - RuntimeOrigin::signed(lp_provider), - token_1, - token_2, - (u32::MAX / 8).into(), // 1 desired - u32::MAX.into(), // 2 desired - 1, // 1 min - 1, // 2 min - lp_provider_account, - )); - - use frame_support::traits::Currency; - let _ = Balances::deposit_creating(&account, u32::MAX.into()); - - let beneficiary = ::Lookup::unlookup(account); - let balance = 1000; - - assert_ok!(Assets::mint_into(asset_id.into(), &beneficiary, balance)); - assert_eq!(Assets::balance(asset_id, account), balance); - } } diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/tests.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/tests.rs index 619077c0a5e..62faed269d3 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/tests.rs +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/tests.rs @@ -28,10 +28,7 @@ use frame_support::{ use frame_system as system; use mock::{ExtrinsicBaseWeight, *}; use pallet_balances::Call as BalancesCall; -use sp_runtime::{ - traits::{DispatchTransaction, StaticLookup}, - BuildStorage, -}; +use sp_runtime::{traits::StaticLookup, BuildStorage}; const CALL: &::RuntimeCall = &RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 2, value: 69 }); @@ -163,35 +160,33 @@ fn transaction_payment_in_native_possible() { .build() .execute_with(|| { let len = 10; - let (pre, _) = ChargeAssetTxPayment::::from(0, None) - .validate_and_prepare(Some(1).into(), CALL, &info_from_weight(WEIGHT_5), len) + let pre = ChargeAssetTxPayment::::from(0, None) + .pre_dispatch(&1, CALL, &info_from_weight(WEIGHT_5), len) .unwrap(); let initial_balance = 10 * balance_factor; assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 10); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(WEIGHT_5), &default_post_info(), len, - &Ok(()), - &() + &Ok(()) )); assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 10); - let (pre, _) = ChargeAssetTxPayment::::from(5 /* tipped */, None) - .validate_and_prepare(Some(2).into(), CALL, &info_from_weight(WEIGHT_100), len) + let pre = ChargeAssetTxPayment::::from(5 /* tipped */, None) + .pre_dispatch(&2, CALL, &info_from_weight(WEIGHT_100), len) .unwrap(); let initial_balance_for_2 = 20 * balance_factor; assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 100 - 5); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(WEIGHT_100), &post_info_from_weight(WEIGHT_50), len, - &Ok(()), - &() + &Ok(()) )); assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 50 - 5); }); @@ -242,8 +237,8 @@ fn transaction_payment_in_asset_possible() { let fee_in_asset = input_quote.unwrap(); assert_eq!(Assets::balance(asset_id, caller), balance); - let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .validate_and_prepare(Some(caller).into(), CALL, &info_from_weight(WEIGHT_5), len) + let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .pre_dispatch(&caller, CALL, &info_from_weight(WEIGHT_5), len) .unwrap(); // assert that native balance is not used assert_eq!(Balances::free_balance(caller), 10 * balance_factor); @@ -252,12 +247,11 @@ fn transaction_payment_in_asset_possible() { assert_eq!(Assets::balance(asset_id, caller), balance - fee_in_asset); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(WEIGHT_5), // estimated tx weight &default_post_info(), // weight actually used == estimated len, - &Ok(()), - &() + &Ok(()) )); assert_eq!(Assets::balance(asset_id, caller), balance - fee_in_asset); @@ -295,8 +289,12 @@ fn transaction_payment_in_asset_fails_if_no_pool_for_that_asset() { assert_eq!(Assets::balance(asset_id, caller), balance); let len = 10; - let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .validate_and_prepare(Some(caller).into(), CALL, &info_from_weight(WEIGHT_5), len); + let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)).pre_dispatch( + &caller, + CALL, + &info_from_weight(WEIGHT_5), + len, + ); // As there is no pool in the dex set up for this asset, conversion should fail. assert!(pre.is_err()); @@ -346,8 +344,8 @@ fn transaction_payment_without_fee() { assert_eq!(input_quote, Some(201)); let fee_in_asset = input_quote.unwrap(); - let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .validate_and_prepare(Some(caller).into(), CALL, &info_from_weight(WEIGHT_5), len) + let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .pre_dispatch(&caller, CALL, &info_from_weight(WEIGHT_5), len) .unwrap(); // assert that native balance is not used @@ -365,12 +363,11 @@ fn transaction_payment_without_fee() { assert_eq!(refund, 199); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(WEIGHT_5), &post_info_from_pays(Pays::No), len, - &Ok(()), - &() + &Ok(()) )); // caller should get refunded @@ -422,8 +419,8 @@ fn asset_transaction_payment_with_tip_and_refund() { assert_eq!(input_quote, Some(1206)); let fee_in_asset = input_quote.unwrap(); - let (pre, _) = ChargeAssetTxPayment::::from(tip, Some(asset_id)) - .validate_and_prepare(Some(caller).into(), CALL, &info_from_weight(WEIGHT_100), len) + let pre = ChargeAssetTxPayment::::from(tip, Some(asset_id)) + .pre_dispatch(&caller, CALL, &info_from_weight(WEIGHT_100), len) .unwrap(); assert_eq!(Assets::balance(asset_id, caller), balance - fee_in_asset); @@ -438,12 +435,11 @@ fn asset_transaction_payment_with_tip_and_refund() { .unwrap(); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(WEIGHT_100), &post_info_from_weight(WEIGHT_50), len, - &Ok(()), - &() + &Ok(()) )); assert_eq!(TipUnbalancedAmount::get(), tip); @@ -504,8 +500,8 @@ fn payment_from_account_with_only_assets() { .unwrap(); assert_eq!(fee_in_asset, 301); - let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .validate_and_prepare(Some(caller).into(), CALL, &info_from_weight(WEIGHT_5), len) + let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .pre_dispatch(&caller, CALL, &info_from_weight(WEIGHT_5), len) .unwrap(); assert_eq!(Balances::free_balance(caller), ed); // check that fee was charged in the given asset @@ -520,12 +516,11 @@ fn payment_from_account_with_only_assets() { .unwrap(); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(WEIGHT_5), &default_post_info(), len, - &Ok(()), - &() + &Ok(()) )); assert_eq!(Assets::balance(asset_id, caller), balance - fee_in_asset + refund); assert_eq!(Balances::free_balance(caller), 0); @@ -570,19 +565,18 @@ fn converted_fee_is_never_zero_if_input_fee_is_not() { // there will be no conversion when the fee is zero { - let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .validate_and_prepare(Some(caller).into(), CALL, &info_from_pays(Pays::No), len) + let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .pre_dispatch(&caller, CALL, &info_from_pays(Pays::No), len) .unwrap(); // `Pays::No` implies there are no fees assert_eq!(Assets::balance(asset_id, caller), balance); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_pays(Pays::No), &post_info_from_pays(Pays::No), len, - &Ok(()), - &() + &Ok(()) )); assert_eq!(Assets::balance(asset_id, caller), balance); } @@ -597,23 +591,17 @@ fn converted_fee_is_never_zero_if_input_fee_is_not() { ) .unwrap(); - let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .validate_and_prepare( - Some(caller).into(), - CALL, - &info_from_weight(Weight::from_parts(weight, 0)), - len, - ) + let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_parts(weight, 0)), len) .unwrap(); assert_eq!(Assets::balance(asset_id, caller), balance - fee_in_asset); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(Weight::from_parts(weight, 0)), &default_post_info(), len, - &Ok(()), - &() + &Ok(()) )); assert_eq!(Assets::balance(asset_id, caller), balance - fee_in_asset); }); @@ -653,8 +641,8 @@ fn post_dispatch_fee_is_zero_if_pre_dispatch_fee_is_zero() { // calculated fee is greater than 0 assert!(fee > 0); - let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .validate_and_prepare(Some(caller).into(), CALL, &info_from_pays(Pays::No), len) + let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .pre_dispatch(&caller, CALL, &info_from_pays(Pays::No), len) .unwrap(); // `Pays::No` implies no pre-dispatch fees @@ -670,12 +658,62 @@ fn post_dispatch_fee_is_zero_if_pre_dispatch_fee_is_zero() { // `Pays::Yes` on post-dispatch does not mean we pay (we never charge more than the // initial fee) assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_pays(Pays::No), &post_info_from_pays(Pays::Yes), len, - &Ok(()), - &() + &Ok(()) + )); + assert_eq!(Assets::balance(asset_id, caller), balance); + }); +} + +#[test] +fn post_dispatch_fee_is_zero_if_unsigned_pre_dispatch_fee_is_zero() { + let base_weight = 1; + ExtBuilder::default() + .balance_factor(100) + .base_weight(Weight::from_parts(base_weight, 0)) + .build() + .execute_with(|| { + // create the asset + let asset_id = 1; + let min_balance = 100; + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + asset_id.into(), + 42, /* owner */ + true, /* is_sufficient */ + min_balance + )); + + // mint into the caller account + let caller = 333; + let beneficiary = ::Lookup::unlookup(caller); + let balance = 1000; + + assert_ok!(Assets::mint_into(asset_id.into(), &beneficiary, balance)); + assert_eq!(Assets::balance(asset_id, caller), balance); + + let weight = 1; + let len = 1; + ChargeAssetTxPayment::::pre_dispatch_unsigned( + CALL, + &info_from_weight(Weight::from_parts(weight, 0)), + len, + ) + .unwrap(); + + assert_eq!(Assets::balance(asset_id, caller), balance); + + // `Pays::Yes` on post-dispatch does not mean we pay (we never charge more than the + // initial fee) + assert_ok!(ChargeAssetTxPayment::::post_dispatch( + None, + &info_from_weight(Weight::from_parts(weight, 0)), + &post_info_from_pays(Pays::Yes), + len, + &Ok(()) )); assert_eq!(Assets::balance(asset_id, caller), balance); }); diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/weights.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/weights.rs deleted file mode 100644 index f95e49f8073..00000000000 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/weights.rs +++ /dev/null @@ -1,150 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Autogenerated weights for `pallet_asset_conversion_tx_payment` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` - -// Executed Command: -// ./target/production/substrate-node -// benchmark -// pallet -// --chain=dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_asset_conversion_tx_payment -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --wasm-execution=compiled -// --heap-pages=4096 -// --output=./substrate/frame/transaction-payment/asset-conversion-tx-payment/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; -use core::marker::PhantomData; - -/// Weight functions needed for `pallet_asset_conversion_tx_payment`. -pub trait WeightInfo { - fn charge_asset_tx_payment_zero() -> Weight; - fn charge_asset_tx_payment_native() -> Weight; - fn charge_asset_tx_payment_asset() -> Weight; -} - -/// Weights for `pallet_asset_conversion_tx_payment` using the Substrate node and recommended hardware. -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { - fn charge_asset_tx_payment_zero() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 628_000 picoseconds. - Weight::from_parts(694_000, 0) - } - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn charge_asset_tx_payment_native() -> Weight { - // Proof Size summary in bytes: - // Measured: `248` - // Estimated: `1733` - // Minimum execution time: 34_410_000 picoseconds. - Weight::from_parts(35_263_000, 1733) - .saturating_add(T::DbWeight::get().reads(3_u64)) - } - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:2 w:2) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn charge_asset_tx_payment_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `888` - // Estimated: `6208` - // Minimum execution time: 112_432_000 picoseconds. - Weight::from_parts(113_992_000, 6208) - .saturating_add(T::DbWeight::get().reads(7_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) - } -} - -// For backwards compatibility and tests. -impl WeightInfo for () { - fn charge_asset_tx_payment_zero() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 628_000 picoseconds. - Weight::from_parts(694_000, 0) - } - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn charge_asset_tx_payment_native() -> Weight { - // Proof Size summary in bytes: - // Measured: `248` - // Estimated: `1733` - // Minimum execution time: 34_410_000 picoseconds. - Weight::from_parts(35_263_000, 1733) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - } - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:2 w:2) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn charge_asset_tx_payment_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `888` - // Estimated: `6208` - // Minimum execution time: 112_432_000 picoseconds. - Weight::from_parts(113_992_000, 6208) - .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) - } -} diff --git a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml index 06d9c30792e..1da3237df08 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -66,7 +66,6 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] try-runtime = [ diff --git a/substrate/frame/transaction-payment/asset-tx-payment/README.md b/substrate/frame/transaction-payment/asset-tx-payment/README.md index 933ce13b0ee..fc860347d85 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/README.md +++ b/substrate/frame/transaction-payment/asset-tx-payment/README.md @@ -16,6 +16,6 @@ asset. ### Integration This pallet wraps FRAME's transaction payment pallet and functions as a replacement. This means you should include both pallets in your `construct_runtime` macro, but only include this -pallet's [`TransactionExtension`] ([`ChargeAssetTxPayment`]). +pallet's [`SignedExtension`] ([`ChargeAssetTxPayment`]). License: Apache-2.0 diff --git a/substrate/frame/transaction-payment/asset-tx-payment/src/benchmarking.rs b/substrate/frame/transaction-payment/asset-tx-payment/src/benchmarking.rs deleted file mode 100644 index 17e96e2b025..00000000000 --- a/substrate/frame/transaction-payment/asset-tx-payment/src/benchmarking.rs +++ /dev/null @@ -1,123 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Benchmarks for Asset Tx Payment Pallet's transaction extension - -use super::*; -use crate::Pallet; -use frame_benchmarking::v2::*; -use frame_support::{ - dispatch::{DispatchInfo, PostDispatchInfo}, - pallet_prelude::*, -}; -use frame_system::RawOrigin; -use sp_runtime::traits::{AsSystemOriginSigner, DispatchTransaction, Dispatchable}; - -#[benchmarks(where - T::RuntimeCall: Dispatchable, - AssetBalanceOf: Send + Sync, - BalanceOf: Send + Sync + From + IsType>, - ChargeAssetIdOf: Send + Sync, - ::RuntimeOrigin: AsSystemOriginSigner + Clone, - Credit: IsType>, -)] -mod benchmarks { - use super::*; - - #[benchmark] - fn charge_asset_tx_payment_zero() { - let caller: T::AccountId = whitelisted_caller(); - let ext: ChargeAssetTxPayment = ChargeAssetTxPayment::from(0u32.into(), None); - let inner = frame_system::Call::remark { remark: vec![] }; - let call = T::RuntimeCall::from(inner); - let info = DispatchInfo { - weight: Weight::zero(), - class: DispatchClass::Normal, - pays_fee: Pays::No, - }; - let post_info = PostDispatchInfo { actual_weight: None, pays_fee: Pays::No }; - #[block] - { - assert!(ext - .test_run(RawOrigin::Signed(caller).into(), &call, &info, 0, |_| Ok(post_info)) - .unwrap() - .is_ok()); - } - } - - #[benchmark] - fn charge_asset_tx_payment_native() { - let caller: T::AccountId = whitelisted_caller(); - let (fun_asset_id, _) = ::BenchmarkHelper::create_asset_id_parameter(1); - ::BenchmarkHelper::setup_balances_and_pool(fun_asset_id, caller.clone()); - let ext: ChargeAssetTxPayment = ChargeAssetTxPayment::from(10u32.into(), None); - let inner = frame_system::Call::remark { remark: vec![] }; - let call = T::RuntimeCall::from(inner); - let info = DispatchInfo { - weight: Weight::from_parts(10, 0), - class: DispatchClass::Operational, - pays_fee: Pays::Yes, - }; - let post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_parts(10, 0)), - pays_fee: Pays::Yes, - }; - - #[block] - { - assert!(ext - .test_run(RawOrigin::Signed(caller).into(), &call, &info, 0, |_| Ok(post_info)) - .unwrap() - .is_ok()); - } - } - - #[benchmark] - fn charge_asset_tx_payment_asset() { - let caller: T::AccountId = whitelisted_caller(); - let (fun_asset_id, asset_id) = ::BenchmarkHelper::create_asset_id_parameter(1); - ::BenchmarkHelper::setup_balances_and_pool( - fun_asset_id.clone(), - caller.clone(), - ); - let tip = 10u32.into(); - let ext: ChargeAssetTxPayment = ChargeAssetTxPayment::from(tip, Some(asset_id)); - let inner = frame_system::Call::remark { remark: vec![] }; - let call = T::RuntimeCall::from(inner); - let info = DispatchInfo { - weight: Weight::from_parts(10, 0), - class: DispatchClass::Operational, - pays_fee: Pays::Yes, - }; - let post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_parts(10, 0)), - pays_fee: Pays::Yes, - }; - - #[block] - { - assert!(ext - .test_run(RawOrigin::Signed(caller.clone()).into(), &call, &info, 0, |_| Ok( - post_info - )) - .unwrap() - .is_ok()); - } - } - - impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Runtime); -} diff --git a/substrate/frame/transaction-payment/asset-tx-payment/src/lib.rs b/substrate/frame/transaction-payment/asset-tx-payment/src/lib.rs index 991b5f31406..753fae747a3 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/src/lib.rs +++ b/substrate/frame/transaction-payment/asset-tx-payment/src/lib.rs @@ -31,7 +31,7 @@ //! This pallet wraps FRAME's transaction payment pallet and functions as a replacement. This means //! you should include both pallets in your `construct_runtime` macro, but only include this -//! pallet's [`TransactionExtension`] ([`ChargeAssetTxPayment`]). +//! pallet's [`SignedExtension`] ([`ChargeAssetTxPayment`]). #![cfg_attr(not(feature = "std"), no_std)] @@ -40,7 +40,6 @@ use sp_std::prelude::*; use codec::{Decode, Encode}; use frame_support::{ dispatch::{DispatchInfo, DispatchResult, PostDispatchInfo}, - pallet_prelude::Weight, traits::{ tokens::{ fungibles::{Balanced, Credit, Inspect}, @@ -53,11 +52,10 @@ use frame_support::{ use pallet_transaction_payment::OnChargeTransaction; use scale_info::TypeInfo; use sp_runtime::{ - traits::{ - AsSystemOriginSigner, DispatchInfoOf, Dispatchable, PostDispatchInfoOf, - TransactionExtension, TransactionExtensionBase, Zero, + traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SignedExtension, Zero}, + transaction_validity::{ + InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction, }, - transaction_validity::{InvalidTransaction, TransactionValidityError, ValidTransaction}, }; #[cfg(test)] @@ -65,14 +63,8 @@ mod mock; #[cfg(test)] mod tests; -#[cfg(feature = "runtime-benchmarks")] -mod benchmarking; - mod payment; -pub mod weights; - pub use payment::*; -pub use weights::WeightInfo; /// Type aliases used for interaction with `OnChargeTransaction`. pub(crate) type OnChargeTransactionOf = @@ -128,30 +120,11 @@ pub mod pallet { type Fungibles: Balanced; /// The actual transaction charging logic that charges the fees. type OnChargeAssetTransaction: OnChargeAssetTransaction; - /// The weight information of this pallet. - type WeightInfo: WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - /// Benchmark helper - type BenchmarkHelper: BenchmarkHelperTrait< - Self::AccountId, - <::Fungibles as Inspect>::AssetId, - <::OnChargeAssetTransaction as OnChargeAssetTransaction>::AssetId, - >; } #[pallet::pallet] pub struct Pallet(_); - #[cfg(feature = "runtime-benchmarks")] - /// Helper trait to benchmark the `ChargeAssetTxPayment` transaction extension. - pub trait BenchmarkHelperTrait { - /// Returns the `AssetId` to be used in the liquidity pool by the benchmarking code. - fn create_asset_id_parameter(id: u32) -> (FunAssetIdParameter, AssetIdParameter); - /// Create a liquidity pool for a given asset and sufficiently endow accounts to benchmark - /// the extension. - fn setup_balances_and_pool(asset_id: FunAssetIdParameter, account: AccountId); - } - #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { @@ -199,8 +172,9 @@ where who: &T::AccountId, call: &T::RuntimeCall, info: &DispatchInfoOf, - fee: BalanceOf, + len: usize, ) -> Result<(BalanceOf, InitialPayment), TransactionValidityError> { + let fee = pallet_transaction_payment::Pallet::::compute_fee(len as u32, info, self.tip); debug_assert!(self.tip <= fee, "tip should be included in the computed fee"); if fee.is_zero() { Ok((fee, InitialPayment::Nothing)) @@ -235,139 +209,104 @@ impl sp_std::fmt::Debug for ChargeAssetTxPayment { } } -impl TransactionExtensionBase for ChargeAssetTxPayment -where - AssetBalanceOf: Send + Sync, - BalanceOf: Send + Sync + From + IsType>, - ChargeAssetIdOf: Send + Sync, - Credit: IsType>, -{ - const IDENTIFIER: &'static str = "ChargeAssetTxPayment"; - type Implicit = (); - - fn weight(&self) -> Weight { - if self.asset_id.is_some() { - ::WeightInfo::charge_asset_tx_payment_asset() - } else { - ::WeightInfo::charge_asset_tx_payment_native() - } - } -} - -impl TransactionExtension for ChargeAssetTxPayment +impl SignedExtension for ChargeAssetTxPayment where T::RuntimeCall: Dispatchable, AssetBalanceOf: Send + Sync, BalanceOf: Send + Sync + From + IsType>, ChargeAssetIdOf: Send + Sync, Credit: IsType>, - ::RuntimeOrigin: AsSystemOriginSigner + Clone, { - type Val = ( - // tip - BalanceOf, - // who paid the fee - T::AccountId, - // transaction fee - BalanceOf, - ); + const IDENTIFIER: &'static str = "ChargeAssetTxPayment"; + type AccountId = T::AccountId; + type Call = T::RuntimeCall; + type AdditionalSigned = (); type Pre = ( // tip BalanceOf, // who paid the fee - T::AccountId, + Self::AccountId, // imbalance resulting from withdrawing the fee InitialPayment, // asset_id for the transaction payment Option>, ); + fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { + Ok(()) + } + fn validate( &self, - origin: ::RuntimeOrigin, - _call: &T::RuntimeCall, - info: &DispatchInfoOf, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, len: usize, - _context: &mut Context, - _self_implicit: Self::Implicit, - _inherited_implication: &impl Encode, - ) -> Result< - (ValidTransaction, Self::Val, ::RuntimeOrigin), - TransactionValidityError, - > { + ) -> TransactionValidity { use pallet_transaction_payment::ChargeTransactionPayment; - let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?; - // Non-mutating call of `compute_fee` to calculate the fee used in the transaction priority. - let fee = pallet_transaction_payment::Pallet::::compute_fee(len as u32, info, self.tip); + let (fee, _) = self.withdraw_fee(who, call, info, len)?; let priority = ChargeTransactionPayment::::get_priority(info, len, self.tip, fee); - let val = (self.tip, who.clone(), fee); - let validity = ValidTransaction { priority, ..Default::default() }; - Ok((validity, val, origin)) + Ok(ValidTransaction { priority, ..Default::default() }) } - fn prepare( + fn pre_dispatch( self, - val: Self::Val, - _origin: &::RuntimeOrigin, - call: &T::RuntimeCall, - info: &DispatchInfoOf, - _len: usize, - _context: &Context, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, ) -> Result { - let (tip, who, fee) = val; - // Mutating call of `withdraw_fee` to actually charge for the transaction. - let (_fee, initial_payment) = self.withdraw_fee(&who, call, info, fee)?; - Ok((tip, who, initial_payment, self.asset_id)) + let (_fee, initial_payment) = self.withdraw_fee(who, call, info, len)?; + Ok((self.tip, who.clone(), initial_payment, self.asset_id)) } fn post_dispatch( - pre: Self::Pre, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + pre: Option, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, len: usize, result: &DispatchResult, - _context: &Context, ) -> Result<(), TransactionValidityError> { - let (tip, who, initial_payment, asset_id) = pre; - match initial_payment { - InitialPayment::Native(already_withdrawn) => { - pallet_transaction_payment::ChargeTransactionPayment::::post_dispatch( - (tip, who, already_withdrawn), - info, - post_info, - len, - result, - &(), - )?; - }, - InitialPayment::Asset(already_withdrawn) => { - let actual_fee = pallet_transaction_payment::Pallet::::compute_actual_fee( - len as u32, info, post_info, tip, - ); - - let (converted_fee, converted_tip) = - T::OnChargeAssetTransaction::correct_and_deposit_fee( - &who, + if let Some((tip, who, initial_payment, asset_id)) = pre { + match initial_payment { + InitialPayment::Native(already_withdrawn) => { + pallet_transaction_payment::ChargeTransactionPayment::::post_dispatch( + Some((tip, who, already_withdrawn)), info, post_info, - actual_fee.into(), - tip.into(), - already_withdrawn.into(), + len, + result, )?; - Pallet::::deposit_event(Event::::AssetTxFeePaid { - who, - actual_fee: converted_fee, - tip: converted_tip, - asset_id, - }); - }, - InitialPayment::Nothing => { - // `actual_fee` should be zero here for any signed extrinsic. It would be - // non-zero here in case of unsigned extrinsics as they don't pay fees but - // `compute_actual_fee` is not aware of them. In both cases it's fine to just - // move ahead without adjusting the fee, though, so we do nothing. - debug_assert!(tip.is_zero(), "tip should be zero if initial fee was zero."); - }, + }, + InitialPayment::Asset(already_withdrawn) => { + let actual_fee = pallet_transaction_payment::Pallet::::compute_actual_fee( + len as u32, info, post_info, tip, + ); + + let (converted_fee, converted_tip) = + T::OnChargeAssetTransaction::correct_and_deposit_fee( + &who, + info, + post_info, + actual_fee.into(), + tip.into(), + already_withdrawn.into(), + )?; + Pallet::::deposit_event(Event::::AssetTxFeePaid { + who, + actual_fee: converted_fee, + tip: converted_tip, + asset_id, + }); + }, + InitialPayment::Nothing => { + // `actual_fee` should be zero here for any signed extrinsic. It would be + // non-zero here in case of unsigned extrinsics as they don't pay fees but + // `compute_actual_fee` is not aware of them. In both cases it's fine to just + // move ahead without adjusting the fee, though, so we do nothing. + debug_assert!(tip.is_zero(), "tip should be zero if initial fee was zero."); + }, + } } Ok(()) diff --git a/substrate/frame/transaction-payment/asset-tx-payment/src/mock.rs b/substrate/frame/transaction-payment/asset-tx-payment/src/mock.rs index bb484795e82..1f335b4f6c4 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/src/mock.rs +++ b/substrate/frame/transaction-payment/asset-tx-payment/src/mock.rs @@ -136,12 +136,12 @@ impl WeightToFeeT for TransactionByteFee { } } -#[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig as pallet_transaction_payment::DefaultConfig)] impl pallet_transaction_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = CurrencyAdapter; type WeightToFee = WeightToFee; type LengthToFee = TransactionByteFee; + type FeeMultiplierUpdate = (); type OperationalFeeMultiplier = ConstU8<5>; } @@ -205,56 +205,4 @@ impl Config for Runtime { pallet_assets::BalanceToAssetBalance, CreditToBlockAuthor, >; - type WeightInfo = (); - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = Helper; -} - -#[cfg(feature = "runtime-benchmarks")] -pub fn new_test_ext() -> sp_io::TestExternalities { - let base_weight = 5; - let balance_factor = 100; - crate::tests::ExtBuilder::default() - .balance_factor(balance_factor) - .base_weight(Weight::from_parts(base_weight, 0)) - .build() -} - -#[cfg(feature = "runtime-benchmarks")] -pub struct Helper; - -#[cfg(feature = "runtime-benchmarks")] -impl BenchmarkHelperTrait for Helper { - fn create_asset_id_parameter(id: u32) -> (u32, u32) { - (id.into(), id.into()) - } - - fn setup_balances_and_pool(asset_id: u32, account: u64) { - use frame_support::{assert_ok, traits::fungibles::Mutate}; - use sp_runtime::traits::StaticLookup; - let min_balance = 1; - assert_ok!(Assets::force_create( - RuntimeOrigin::root(), - asset_id.into(), - 42, /* owner */ - true, /* is_sufficient */ - min_balance - )); - - // mint into the caller account - let caller = 2; - let beneficiary = ::Lookup::unlookup(caller); - let balance = 1000; - assert_ok!(Assets::mint_into(asset_id.into(), &beneficiary, balance)); - assert_eq!(Assets::balance(asset_id, caller), balance); - - use frame_support::traits::Currency; - let _ = Balances::deposit_creating(&account, u32::MAX.into()); - - let beneficiary = ::Lookup::unlookup(account); - let balance = 1000; - - assert_ok!(Assets::mint_into(asset_id.into(), &beneficiary, balance)); - assert_eq!(Assets::balance(asset_id, account), balance); - } } diff --git a/substrate/frame/transaction-payment/asset-tx-payment/src/tests.rs b/substrate/frame/transaction-payment/asset-tx-payment/src/tests.rs index 42b8f2cf5fa..8df98ceda99 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/substrate/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -25,10 +25,7 @@ use frame_support::{ use frame_system as system; use mock::{ExtrinsicBaseWeight, *}; use pallet_balances::Call as BalancesCall; -use sp_runtime::{ - traits::{DispatchTransaction, StaticLookup}, - BuildStorage, -}; +use sp_runtime::{traits::StaticLookup, BuildStorage}; const CALL: &::RuntimeCall = &RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 2, value: 69 }); @@ -119,45 +116,33 @@ fn transaction_payment_in_native_possible() { .build() .execute_with(|| { let len = 10; - let (pre, _) = ChargeAssetTxPayment::::from(0, None) - .validate_and_prepare( - Some(1).into(), - CALL, - &info_from_weight(Weight::from_parts(5, 0)), - len, - ) + let pre = ChargeAssetTxPayment::::from(0, None) + .pre_dispatch(&1, CALL, &info_from_weight(Weight::from_parts(5, 0)), len) .unwrap(); let initial_balance = 10 * balance_factor; assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 10); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(Weight::from_parts(5, 0)), &default_post_info(), len, - &Ok(()), - &() + &Ok(()) )); assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 10); - let (pre, _) = ChargeAssetTxPayment::::from(5 /* tipped */, None) - .validate_and_prepare( - Some(2).into(), - CALL, - &info_from_weight(Weight::from_parts(100, 0)), - len, - ) + let pre = ChargeAssetTxPayment::::from(5 /* tipped */, None) + .pre_dispatch(&2, CALL, &info_from_weight(Weight::from_parts(100, 0)), len) .unwrap(); let initial_balance_for_2 = 20 * balance_factor; assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 100 - 5); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(Weight::from_parts(100, 0)), &post_info_from_weight(Weight::from_parts(50, 0)), len, - &Ok(()), - &() + &Ok(()) )); assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 50 - 5); }); @@ -194,13 +179,8 @@ fn transaction_payment_in_asset_possible() { // we convert the from weight to fee based on the ratio between asset min balance and // existential deposit let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get(); - let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .validate_and_prepare( - Some(caller).into(), - CALL, - &info_from_weight(Weight::from_parts(weight, 0)), - len, - ) + let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_parts(weight, 0)), len) .unwrap(); // assert that native balance is not used assert_eq!(Balances::free_balance(caller), 10 * balance_factor); @@ -209,12 +189,11 @@ fn transaction_payment_in_asset_possible() { assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), 0); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(Weight::from_parts(weight, 0)), &default_post_info(), len, - &Ok(()), - &() + &Ok(()) )); assert_eq!(Assets::balance(asset_id, caller), balance - fee); // check that the block author gets rewarded @@ -253,13 +232,8 @@ fn transaction_payment_without_fee() { // we convert the from weight to fee based on the ratio between asset min balance and // existential deposit let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get(); - let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .validate_and_prepare( - Some(caller).into(), - CALL, - &info_from_weight(Weight::from_parts(weight, 0)), - len, - ) + let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_parts(weight, 0)), len) .unwrap(); // assert that native balance is not used assert_eq!(Balances::free_balance(caller), 10 * balance_factor); @@ -268,12 +242,11 @@ fn transaction_payment_without_fee() { assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), 0); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(Weight::from_parts(weight, 0)), &post_info_from_pays(Pays::No), len, - &Ok(()), - &() + &Ok(()) )); // caller should be refunded assert_eq!(Assets::balance(asset_id, caller), balance); @@ -314,24 +287,18 @@ fn asset_transaction_payment_with_tip_and_refund() { // existential deposit let fee_with_tip = (base_weight + weight + len as u64 + tip) * min_balance / ExistentialDeposit::get(); - let (pre, _) = ChargeAssetTxPayment::::from(tip, Some(asset_id)) - .validate_and_prepare( - Some(caller).into(), - CALL, - &info_from_weight(Weight::from_parts(weight, 0)), - len, - ) + let pre = ChargeAssetTxPayment::::from(tip, Some(asset_id)) + .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_parts(weight, 0)), len) .unwrap(); assert_eq!(Assets::balance(asset_id, caller), balance - fee_with_tip); let final_weight = 50; assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(Weight::from_parts(weight, 0)), &post_info_from_weight(Weight::from_parts(final_weight, 0)), len, - &Ok(()), - &() + &Ok(()) )); let final_fee = fee_with_tip - (weight - final_weight) * min_balance / ExistentialDeposit::get(); @@ -372,25 +339,19 @@ fn payment_from_account_with_only_assets() { // we convert the from weight to fee based on the ratio between asset min balance and // existential deposit let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get(); - let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .validate_and_prepare( - Some(caller).into(), - CALL, - &info_from_weight(Weight::from_parts(weight, 0)), - len, - ) + let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_parts(weight, 0)), len) .unwrap(); assert_eq!(Balances::free_balance(caller), 0); // check that fee was charged in the given asset assert_eq!(Assets::balance(asset_id, caller), balance - fee); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(Weight::from_parts(weight, 0)), &default_post_info(), len, - &Ok(()), - &() + &Ok(()) )); assert_eq!(Assets::balance(asset_id, caller), balance - fee); assert_eq!(Balances::free_balance(caller), 0); @@ -411,12 +372,7 @@ fn payment_only_with_existing_sufficient_asset() { let len = 10; // pre_dispatch fails for non-existent asset assert!(ChargeAssetTxPayment::::from(0, Some(asset_id)) - .validate_and_prepare( - Some(caller).into(), - CALL, - &info_from_weight(Weight::from_parts(weight, 0)), - len - ) + .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_parts(weight, 0)), len) .is_err()); // create the non-sufficient asset @@ -430,12 +386,7 @@ fn payment_only_with_existing_sufficient_asset() { )); // pre_dispatch fails for non-sufficient asset assert!(ChargeAssetTxPayment::::from(0, Some(asset_id)) - .validate_and_prepare( - Some(caller).into(), - CALL, - &info_from_weight(Weight::from_parts(weight, 0)), - len - ) + .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_parts(weight, 0)), len) .is_err()); }); } @@ -473,40 +424,33 @@ fn converted_fee_is_never_zero_if_input_fee_is_not() { // naive fee calculation would round down to zero assert_eq!(fee, 0); { - let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .validate_and_prepare(Some(caller).into(), CALL, &info_from_pays(Pays::No), len) + let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .pre_dispatch(&caller, CALL, &info_from_pays(Pays::No), len) .unwrap(); // `Pays::No` still implies no fees assert_eq!(Assets::balance(asset_id, caller), balance); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_pays(Pays::No), &post_info_from_pays(Pays::No), len, - &Ok(()), - &() + &Ok(()) )); assert_eq!(Assets::balance(asset_id, caller), balance); } - let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .validate_and_prepare( - Some(caller).into(), - CALL, - &info_from_weight(Weight::from_parts(weight, 0)), - len, - ) + let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_parts(weight, 0)), len) .unwrap(); // check that at least one coin was charged in the given asset assert_eq!(Assets::balance(asset_id, caller), balance - 1); assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_weight(Weight::from_parts(weight, 0)), &default_post_info(), len, - &Ok(()), - &() + &Ok(()) )); assert_eq!(Assets::balance(asset_id, caller), balance - 1); }); @@ -544,8 +488,8 @@ fn post_dispatch_fee_is_zero_if_pre_dispatch_fee_is_zero() { let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get(); // calculated fee is greater than 0 assert!(fee > 0); - let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .validate_and_prepare(Some(caller).into(), CALL, &info_from_pays(Pays::No), len) + let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .pre_dispatch(&caller, CALL, &info_from_pays(Pays::No), len) .unwrap(); // `Pays::No` implies no pre-dispatch fees assert_eq!(Assets::balance(asset_id, caller), balance); @@ -559,12 +503,60 @@ fn post_dispatch_fee_is_zero_if_pre_dispatch_fee_is_zero() { // `Pays::Yes` on post-dispatch does not mean we pay (we never charge more than the // initial fee) assert_ok!(ChargeAssetTxPayment::::post_dispatch( - pre, + Some(pre), &info_from_pays(Pays::No), &post_info_from_pays(Pays::Yes), len, - &Ok(()), - &() + &Ok(()) + )); + assert_eq!(Assets::balance(asset_id, caller), balance); + }); +} + +#[test] +fn post_dispatch_fee_is_zero_if_unsigned_pre_dispatch_fee_is_zero() { + let base_weight = 1; + ExtBuilder::default() + .balance_factor(100) + .base_weight(Weight::from_parts(base_weight, 0)) + .build() + .execute_with(|| { + // create the asset + let asset_id = 1; + let min_balance = 100; + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + asset_id.into(), + 42, /* owner */ + true, /* is_sufficient */ + min_balance + )); + + // mint into the caller account + let caller = 333; + let beneficiary = ::Lookup::unlookup(caller); + let balance = 100; + assert_ok!(Assets::mint_into(asset_id.into(), &beneficiary, balance)); + assert_eq!(Assets::balance(asset_id, caller), balance); + let weight = 1; + let len = 1; + ChargeAssetTxPayment::::pre_dispatch_unsigned( + CALL, + &info_from_weight(Weight::from_parts(weight, 0)), + len, + ) + .unwrap(); + + assert_eq!(Assets::balance(asset_id, caller), balance); + + // `Pays::Yes` on post-dispatch does not mean we pay (we never charge more than the + // initial fee) + assert_ok!(ChargeAssetTxPayment::::post_dispatch( + None, + &info_from_weight(Weight::from_parts(weight, 0)), + &post_info_from_pays(Pays::Yes), + len, + &Ok(()) )); assert_eq!(Assets::balance(asset_id, caller), balance); }); diff --git a/substrate/frame/transaction-payment/asset-tx-payment/src/weights.rs b/substrate/frame/transaction-payment/asset-tx-payment/src/weights.rs deleted file mode 100644 index 1af1c94177d..00000000000 --- a/substrate/frame/transaction-payment/asset-tx-payment/src/weights.rs +++ /dev/null @@ -1,146 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Autogenerated weights for `pallet_asset_tx_payment` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` - -// Executed Command: -// ./target/production/substrate-node -// benchmark -// pallet -// --chain=dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_asset_tx_payment -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --wasm-execution=compiled -// --heap-pages=4096 -// --output=./substrate/frame/transaction-payment/asset-tx-payment/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; -use core::marker::PhantomData; - -/// Weight functions needed for `pallet_asset_tx_payment`. -pub trait WeightInfo { - fn charge_asset_tx_payment_zero() -> Weight; - fn charge_asset_tx_payment_native() -> Weight; - fn charge_asset_tx_payment_asset() -> Weight; -} - -/// Weights for `pallet_asset_tx_payment` using the Substrate node and recommended hardware. -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { - fn charge_asset_tx_payment_zero() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 542_000 picoseconds. - Weight::from_parts(597_000, 0) - } - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn charge_asset_tx_payment_native() -> Weight { - // Proof Size summary in bytes: - // Measured: `248` - // Estimated: `1733` - // Minimum execution time: 33_162_000 picoseconds. - Weight::from_parts(34_716_000, 1733) - .saturating_add(T::DbWeight::get().reads(3_u64)) - } - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn charge_asset_tx_payment_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `747` - // Estimated: `3675` - // Minimum execution time: 44_230_000 picoseconds. - Weight::from_parts(45_297_000, 3675) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) - } -} - -// For backwards compatibility and tests. -impl WeightInfo for () { - fn charge_asset_tx_payment_zero() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 542_000 picoseconds. - Weight::from_parts(597_000, 0) - } - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn charge_asset_tx_payment_native() -> Weight { - // Proof Size summary in bytes: - // Measured: `248` - // Estimated: `1733` - // Minimum execution time: 33_162_000 picoseconds. - Weight::from_parts(34_716_000, 1733) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - } - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1 w:1) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn charge_asset_tx_payment_asset() -> Weight { - // Proof Size summary in bytes: - // Measured: `747` - // Estimated: `3675` - // Minimum execution time: 44_230_000 picoseconds. - Weight::from_parts(45_297_000, 3675) - .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) - } -} diff --git a/substrate/frame/transaction-payment/skip-feeless-payment/src/lib.rs b/substrate/frame/transaction-payment/skip-feeless-payment/src/lib.rs index 9810ea08c79..6c34c26ce92 100644 --- a/substrate/frame/transaction-payment/skip-feeless-payment/src/lib.rs +++ b/substrate/frame/transaction-payment/skip-feeless-payment/src/lib.rs @@ -21,7 +21,7 @@ //! //! ## Overview //! -//! It does this by wrapping an existing [`TransactionExtension`] implementation (e.g. +//! It does this by wrapping an existing [`SignedExtension`] implementation (e.g. //! [`pallet-transaction-payment`]) and checking if the dispatchable is feeless before applying the //! wrapped extension. If the dispatchable is indeed feeless, the extension is skipped and a custom //! event is emitted instead. Otherwise, the extension is applied as usual. @@ -31,8 +31,7 @@ //! //! This pallet wraps an existing transaction payment pallet. This means you should both pallets //! in your `construct_runtime` macro and include this pallet's -//! [`TransactionExtension`] ([`SkipCheckIfFeeless`]) that would accept the existing one as an -//! argument. +//! [`SignedExtension`] ([`SkipCheckIfFeeless`]) that would accept the existing one as an argument. #![cfg_attr(not(feature = "std"), no_std)] @@ -43,10 +42,7 @@ use frame_support::{ }; use scale_info::{StaticTypeInfo, TypeInfo}; use sp_runtime::{ - traits::{ - DispatchInfoOf, OriginOf, PostDispatchInfoOf, TransactionExtension, - TransactionExtensionBase, ValidateResult, - }, + traits::{DispatchInfoOf, PostDispatchInfoOf, SignedExtension}, transaction_validity::TransactionValidityError, }; @@ -74,11 +70,11 @@ pub mod pallet { #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { /// A transaction fee was skipped. - FeeSkipped { origin: ::PalletsOrigin }, + FeeSkipped { who: T::AccountId }, } } -/// A [`TransactionExtension`] that skips the wrapped extension if the dispatchable is feeless. +/// A [`SignedExtension`] that skips the wrapped extension if the dispatchable is feeless. #[derive(Encode, Decode, Clone, Eq, PartialEq)] pub struct SkipCheckIfFeeless(pub S, sp_std::marker::PhantomData); @@ -107,96 +103,53 @@ impl From for SkipCheckIfFeeless { } } -pub enum Intermediate { - /// The wrapped extension should be applied. - Apply(T), - /// The wrapped extension should be skipped. - Skip(O), -} -use Intermediate::*; - -impl TransactionExtensionBase +impl> SignedExtension for SkipCheckIfFeeless +where + S::Call: CheckIfFeeless>, { + type AccountId = T::AccountId; + type Call = S::Call; + type AdditionalSigned = S::AdditionalSigned; + type Pre = (Self::AccountId, Option<::Pre>); // From the outside this extension should be "invisible", because it just extends the wrapped // extension with an extra check in `pre_dispatch` and `post_dispatch`. Thus, we should forward // the identifier of the wrapped extension to let wallets see this extension as it would only be // the wrapped extension itself. const IDENTIFIER: &'static str = S::IDENTIFIER; - type Implicit = S::Implicit; - - fn implicit(&self) -> Result { - self.0.implicit() - } - fn weight(&self) -> frame_support::weights::Weight { - self.0.weight() + fn additional_signed(&self) -> Result { + self.0.additional_signed() } -} -impl> - TransactionExtension for SkipCheckIfFeeless -where - T::RuntimeCall: CheckIfFeeless>, -{ - type Val = Intermediate as OriginTrait>::PalletsOrigin>; - type Pre = Intermediate as OriginTrait>::PalletsOrigin>; - - fn validate( - &self, - origin: OriginOf, - call: &T::RuntimeCall, - info: &DispatchInfoOf, - len: usize, - context: &mut Context, - self_implicit: S::Implicit, - inherited_implication: &impl Encode, - ) -> ValidateResult { - if call.is_feeless(&origin) { - Ok((Default::default(), Skip(origin.caller().clone()), origin)) - } else { - let (x, y, z) = self.0.validate( - origin, - call, - info, - len, - context, - self_implicit, - inherited_implication, - )?; - Ok((x, Apply(y), z)) - } - } - - fn prepare( + fn pre_dispatch( self, - val: Self::Val, - origin: &OriginOf, - call: &T::RuntimeCall, - info: &DispatchInfoOf, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, len: usize, - context: &Context, ) -> Result { - match val { - Apply(val) => self.0.prepare(val, origin, call, info, len, context).map(Apply), - Skip(origin) => Ok(Skip(origin)), + if call.is_feeless(&::RuntimeOrigin::signed(who.clone())) { + Ok((who.clone(), None)) + } else { + Ok((who.clone(), Some(self.0.pre_dispatch(who, call, info, len)?))) } } fn post_dispatch( - pre: Self::Pre, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + pre: Option, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, len: usize, result: &DispatchResult, - context: &Context, ) -> Result<(), TransactionValidityError> { - match pre { - Apply(pre) => S::post_dispatch(pre, info, post_info, len, result, context), - Skip(origin) => { - Pallet::::deposit_event(Event::::FeeSkipped { origin }); - Ok(()) - }, + if let Some(pre) = pre { + if let Some(pre) = pre.1 { + S::post_dispatch(Some(pre), info, post_info, len, result)?; + } else { + Pallet::::deposit_event(Event::::FeeSkipped { who: pre.0 }); + } } + Ok(()) } } diff --git a/substrate/frame/transaction-payment/skip-feeless-payment/src/mock.rs b/substrate/frame/transaction-payment/skip-feeless-payment/src/mock.rs index 06948de4c3c..17c4c773997 100644 --- a/substrate/frame/transaction-payment/skip-feeless-payment/src/mock.rs +++ b/substrate/frame/transaction-payment/skip-feeless-payment/src/mock.rs @@ -18,12 +18,9 @@ use crate as pallet_skip_feeless_payment; use frame_support::{derive_impl, parameter_types}; use frame_system as system; -use sp_runtime::{ - impl_tx_ext_default, - traits::{OriginOf, TransactionExtension}, -}; type Block = frame_system::mocking::MockBlock; +type AccountId = u64; #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { @@ -41,22 +38,21 @@ parameter_types! { #[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, TypeInfo)] pub struct DummyExtension; -impl TransactionExtensionBase for DummyExtension { - const IDENTIFIER: &'static str = "DummyExtension"; - type Implicit = (); -} -impl TransactionExtension for DummyExtension { - type Val = (); +impl SignedExtension for DummyExtension { + type AccountId = AccountId; + type Call = RuntimeCall; + type AdditionalSigned = (); type Pre = (); - impl_tx_ext_default!(RuntimeCall; C; validate); - fn prepare( + const IDENTIFIER: &'static str = "DummyExtension"; + fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { + Ok(()) + } + fn pre_dispatch( self, - _val: Self::Val, - _origin: &OriginOf, - _call: &RuntimeCall, - _info: &DispatchInfoOf, + _who: &Self::AccountId, + _call: &Self::Call, + _info: &DispatchInfoOf, _len: usize, - _context: &C, ) -> Result { PreDispatchCount::mutate(|c| *c += 1); Ok(()) diff --git a/substrate/frame/transaction-payment/skip-feeless-payment/src/tests.rs b/substrate/frame/transaction-payment/skip-feeless-payment/src/tests.rs index 96b4af7e203..4b4dd699741 100644 --- a/substrate/frame/transaction-payment/skip-feeless-payment/src/tests.rs +++ b/substrate/frame/transaction-payment/skip-feeless-payment/src/tests.rs @@ -16,19 +16,18 @@ use super::*; use crate::mock::{pallet_dummy::Call, DummyExtension, PreDispatchCount, Runtime, RuntimeCall}; use frame_support::dispatch::DispatchInfo; -use sp_runtime::traits::DispatchTransaction; #[test] fn skip_feeless_payment_works() { let call = RuntimeCall::DummyPallet(Call::::aux { data: 1 }); SkipCheckIfFeeless::::from(DummyExtension) - .validate_and_prepare(Some(0).into(), &call, &DispatchInfo::default(), 0) + .pre_dispatch(&0, &call, &DispatchInfo::default(), 0) .unwrap(); assert_eq!(PreDispatchCount::get(), 1); let call = RuntimeCall::DummyPallet(Call::::aux { data: 0 }); SkipCheckIfFeeless::::from(DummyExtension) - .validate_and_prepare(Some(0).into(), &call, &DispatchInfo::default(), 0) + .pre_dispatch(&0, &call, &DispatchInfo::default(), 0) .unwrap(); assert_eq!(PreDispatchCount::get(), 1); } diff --git a/substrate/frame/transaction-payment/src/benchmarking.rs b/substrate/frame/transaction-payment/src/benchmarking.rs deleted file mode 100644 index d63c5a7d746..00000000000 --- a/substrate/frame/transaction-payment/src/benchmarking.rs +++ /dev/null @@ -1,81 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Benchmarks for Transaction Payment Pallet's transaction extension - -use super::*; -use crate::Pallet; -use frame_benchmarking::v2::*; -use frame_support::dispatch::{DispatchInfo, PostDispatchInfo}; -use frame_system::{EventRecord, RawOrigin}; -use sp_runtime::traits::{DispatchTransaction, Dispatchable}; - -fn assert_last_event(generic_event: ::RuntimeEvent) { - let events = frame_system::Pallet::::events(); - let system_event: ::RuntimeEvent = generic_event.into(); - // compare to the last event record - let EventRecord { event, .. } = &events[events.len() - 1]; - assert_eq!(event, &system_event); -} - -#[benchmarks(where - T: Config, - T::RuntimeCall: Dispatchable, - BalanceOf: Send + Sync + From, -)] -mod benchmarks { - use super::*; - - #[benchmark] - fn charge_transaction_payment() { - let caller: T::AccountId = whitelisted_caller(); - >::endow_account( - &caller, - >::minimum_balance() * 1000.into(), - ); - let tip = >::minimum_balance(); - let ext: ChargeTransactionPayment = ChargeTransactionPayment::from(tip); - let inner = frame_system::Call::remark { remark: vec![] }; - let call = T::RuntimeCall::from(inner); - let info = DispatchInfo { - weight: Weight::from_parts(100, 0), - class: DispatchClass::Operational, - pays_fee: Pays::Yes, - }; - let post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_parts(10, 0)), - pays_fee: Pays::Yes, - }; - - #[block] - { - assert!(ext - .test_run(RawOrigin::Signed(caller.clone()).into(), &call, &info, 10, |_| Ok( - post_info - )) - .unwrap() - .is_ok()); - } - - let actual_fee = Pallet::::compute_actual_fee(10, &info, &post_info, tip); - assert_last_event::( - Event::::TransactionFeePaid { who: caller, actual_fee, tip }.into(), - ); - } - - impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Runtime); -} diff --git a/substrate/frame/transaction-payment/src/lib.rs b/substrate/frame/transaction-payment/src/lib.rs index 6b17616bdc7..efadfd60bdd 100644 --- a/substrate/frame/transaction-payment/src/lib.rs +++ b/substrate/frame/transaction-payment/src/lib.rs @@ -62,28 +62,23 @@ pub use payment::*; use sp_runtime::{ traits::{ Convert, DispatchInfoOf, Dispatchable, One, PostDispatchInfoOf, SaturatedConversion, - Saturating, TransactionExtension, TransactionExtensionBase, Zero, + Saturating, SignedExtension, Zero, }, transaction_validity::{ - InvalidTransaction, TransactionPriority, TransactionValidityError, ValidTransaction, + TransactionPriority, TransactionValidity, TransactionValidityError, ValidTransaction, }, FixedPointNumber, FixedU128, Perbill, Perquintill, RuntimeDebug, }; use sp_std::prelude::*; pub use types::{FeeDetails, InclusionFee, RuntimeDispatchInfo}; -pub use weights::WeightInfo; #[cfg(test)] mod mock; #[cfg(test)] mod tests; -#[cfg(feature = "runtime-benchmarks")] -mod benchmarking; - mod payment; mod types; -pub mod weights; /// Fee multiplier. pub type Multiplier = FixedU128; @@ -340,7 +335,6 @@ pub mod pallet { type RuntimeEvent = (); type FeeMultiplierUpdate = (); type OperationalFeeMultiplier = (); - type WeightInfo = (); } } @@ -393,9 +387,6 @@ pub mod pallet { /// transactions. #[pallet::constant] type OperationalFeeMultiplier: Get; - - /// The weight information of this pallet. - type WeightInfo: WeightInfo; } #[pallet::type_value] @@ -516,11 +507,11 @@ impl Pallet { // a very very little potential gain in the future. let dispatch_info = ::get_dispatch_info(&unchecked_extrinsic); - let partial_fee = if unchecked_extrinsic.is_bare() { - // Bare extrinsics have no partial fee. - 0u32.into() - } else { + let partial_fee = if unchecked_extrinsic.is_signed().unwrap_or(false) { Self::compute_fee(len, &dispatch_info, 0u32.into()) + } else { + // Unsigned extrinsics have no partial fee. + 0u32.into() }; let DispatchInfo { weight, class, .. } = dispatch_info; @@ -540,11 +531,11 @@ impl Pallet { let tip = 0u32.into(); - if unchecked_extrinsic.is_bare() { - // Bare extrinsics have no inclusion fee. - FeeDetails { inclusion_fee: None, tip } - } else { + if unchecked_extrinsic.is_signed().unwrap_or(false) { Self::compute_fee_details(len, &dispatch_info, tip) + } else { + // Unsigned extrinsics have no inclusion fee. + FeeDetails { inclusion_fee: None, tip } } } @@ -723,7 +714,7 @@ where who: &T::AccountId, call: &T::RuntimeCall, info: &DispatchInfoOf, - fee: BalanceOf, + len: usize, ) -> Result< ( BalanceOf, @@ -732,6 +723,7 @@ where TransactionValidityError, > { let tip = self.0; + let fee = Pallet::::compute_fee(len as u32, info, tip); <::OnChargeTransaction as OnChargeTransaction>::withdraw_fee( who, call, info, fee, tip, @@ -739,22 +731,6 @@ where .map(|i| (fee, i)) } - fn can_withdraw_fee( - &self, - who: &T::AccountId, - call: &T::RuntimeCall, - info: &DispatchInfoOf, - len: usize, - ) -> Result, TransactionValidityError> { - let tip = self.0; - let fee = Pallet::::compute_fee(len as u32, info, tip); - - <::OnChargeTransaction as OnChargeTransaction>::can_withdraw_fee( - who, call, info, fee, tip, - )?; - Ok(fee) - } - /// Get an appropriate priority for a transaction with the given `DispatchInfo`, encoded length /// and user-included tip. /// @@ -841,93 +817,67 @@ impl sp_std::fmt::Debug for ChargeTransactionPayment { } } -impl TransactionExtensionBase for ChargeTransactionPayment { - const IDENTIFIER: &'static str = "ChargeTransactionPayment"; - type Implicit = (); - - fn weight(&self) -> Weight { - T::WeightInfo::charge_transaction_payment() - } -} - -impl TransactionExtension - for ChargeTransactionPayment +impl SignedExtension for ChargeTransactionPayment where BalanceOf: Send + Sync + From, T::RuntimeCall: Dispatchable, { - type Val = ( - // tip - BalanceOf, - // who paid the fee - T::AccountId, - // computed fee - BalanceOf, - ); + const IDENTIFIER: &'static str = "ChargeTransactionPayment"; + type AccountId = T::AccountId; + type Call = T::RuntimeCall; + type AdditionalSigned = (); type Pre = ( // tip BalanceOf, - // who paid the fee - T::AccountId, + // who paid the fee - this is an option to allow for a Default impl. + Self::AccountId, // imbalance resulting from withdrawing the fee <::OnChargeTransaction as OnChargeTransaction>::LiquidityInfo, ); + fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { + Ok(()) + } fn validate( &self, - origin: ::RuntimeOrigin, - call: &T::RuntimeCall, - info: &DispatchInfoOf, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, len: usize, - _context: &mut Context, - _: (), - _implication: &impl Encode, - ) -> Result< - (ValidTransaction, Self::Val, ::RuntimeOrigin), - TransactionValidityError, - > { - let who = frame_system::ensure_signed(origin.clone()) - .map_err(|_| InvalidTransaction::BadSigner)?; - let final_fee = self.can_withdraw_fee(&who, call, info, len)?; + ) -> TransactionValidity { + let (final_fee, _) = self.withdraw_fee(who, call, info, len)?; let tip = self.0; - Ok(( - ValidTransaction { - priority: Self::get_priority(info, len, tip, final_fee), - ..Default::default() - }, - (self.0, who, final_fee), - origin, - )) + Ok(ValidTransaction { + priority: Self::get_priority(info, len, tip, final_fee), + ..Default::default() + }) } - fn prepare( + fn pre_dispatch( self, - val: Self::Val, - _origin: &::RuntimeOrigin, - call: &T::RuntimeCall, - info: &DispatchInfoOf, - _len: usize, - _context: &Context, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, ) -> Result { - let (tip, who, fee) = val; - // Mutating call to `withdraw_fee` to actually charge for the transaction. - let (_final_fee, imbalance) = self.withdraw_fee(&who, call, info, fee)?; - Ok((tip, who, imbalance)) + let (_fee, imbalance) = self.withdraw_fee(who, call, info, len)?; + Ok((self.0, who.clone(), imbalance)) } fn post_dispatch( - (tip, who, imbalance): Self::Pre, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + maybe_pre: Option, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, len: usize, _result: &DispatchResult, - _context: &Context, ) -> Result<(), TransactionValidityError> { - let actual_fee = Pallet::::compute_actual_fee(len as u32, info, post_info, tip); - T::OnChargeTransaction::correct_and_deposit_fee( - &who, info, post_info, actual_fee, tip, imbalance, - )?; - Pallet::::deposit_event(Event::::TransactionFeePaid { who, actual_fee, tip }); + if let Some((tip, who, imbalance)) = maybe_pre { + let actual_fee = Pallet::::compute_actual_fee(len as u32, info, post_info, tip); + T::OnChargeTransaction::correct_and_deposit_fee( + &who, info, post_info, actual_fee, tip, imbalance, + )?; + Pallet::::deposit_event(Event::::TransactionFeePaid { who, actual_fee, tip }); + } Ok(()) } } diff --git a/substrate/frame/transaction-payment/src/mock.rs b/substrate/frame/transaction-payment/src/mock.rs index eda234ffcae..1ca2e3d7347 100644 --- a/substrate/frame/transaction-payment/src/mock.rs +++ b/substrate/frame/transaction-payment/src/mock.rs @@ -157,14 +157,4 @@ impl Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = TransactionByteFee; type FeeMultiplierUpdate = (); - type WeightInfo = (); -} - -#[cfg(feature = "runtime-benchmarks")] -pub fn new_test_ext() -> sp_io::TestExternalities { - crate::tests::ExtBuilder::default() - .base_weight(Weight::from_parts(100, 0)) - .byte_fee(10) - .balance_factor(0) - .build() } diff --git a/substrate/frame/transaction-payment/src/payment.rs b/substrate/frame/transaction-payment/src/payment.rs index a13e73b50b0..886683f2e0b 100644 --- a/substrate/frame/transaction-payment/src/payment.rs +++ b/substrate/frame/transaction-payment/src/payment.rs @@ -20,7 +20,7 @@ use crate::Config; use core::marker::PhantomData; use sp_runtime::{ - traits::{CheckedSub, DispatchInfoOf, PostDispatchInfoOf, Saturating, Zero}, + traits::{DispatchInfoOf, PostDispatchInfoOf, Saturating, Zero}, transaction_validity::InvalidTransaction, }; @@ -51,17 +51,6 @@ pub trait OnChargeTransaction { tip: Self::Balance, ) -> Result; - /// Check if the predicted fee from the transaction origin can be withdrawn. - /// - /// Note: The `fee` already includes the `tip`. - fn can_withdraw_fee( - who: &T::AccountId, - call: &T::RuntimeCall, - dispatch_info: &DispatchInfoOf, - fee: Self::Balance, - tip: Self::Balance, - ) -> Result<(), TransactionValidityError>; - /// After the transaction was executed the actual fee can be calculated. /// This function should refund any overpaid fees and optionally deposit /// the corrected amount. @@ -75,12 +64,6 @@ pub trait OnChargeTransaction { tip: Self::Balance, already_withdrawn: Self::LiquidityInfo, ) -> Result<(), TransactionValidityError>; - - #[cfg(feature = "runtime-benchmarks")] - fn endow_account(who: &T::AccountId, amount: Self::Balance); - - #[cfg(feature = "runtime-benchmarks")] - fn minimum_balance() -> Self::Balance; } /// Implements the transaction payment for a pallet implementing the `Currency` @@ -138,33 +121,6 @@ where } } - /// Check if the predicted fee from the transaction origin can be withdrawn. - /// - /// Note: The `fee` already includes the `tip`. - fn can_withdraw_fee( - who: &T::AccountId, - _call: &T::RuntimeCall, - _info: &DispatchInfoOf, - fee: Self::Balance, - tip: Self::Balance, - ) -> Result<(), TransactionValidityError> { - if fee.is_zero() { - return Ok(()) - } - - let withdraw_reason = if tip.is_zero() { - WithdrawReasons::TRANSACTION_PAYMENT - } else { - WithdrawReasons::TRANSACTION_PAYMENT | WithdrawReasons::TIP - }; - - let new_balance = - C::free_balance(who).checked_sub(&fee).ok_or(InvalidTransaction::Payment)?; - C::ensure_can_withdraw(who, fee, withdraw_reason, new_balance) - .map(|_| ()) - .map_err(|_| InvalidTransaction::Payment.into()) - } - /// Hand the fee and the tip over to the `[OnUnbalanced]` implementation. /// Since the predicted fee might have been too high, parts of the fee may /// be refunded. @@ -197,14 +153,4 @@ where } Ok(()) } - - #[cfg(feature = "runtime-benchmarks")] - fn endow_account(who: &T::AccountId, amount: Self::Balance) { - let _ = C::deposit_creating(who, amount); - } - - #[cfg(feature = "runtime-benchmarks")] - fn minimum_balance() -> Self::Balance { - C::minimum_balance() - } } diff --git a/substrate/frame/transaction-payment/src/tests.rs b/substrate/frame/transaction-payment/src/tests.rs index 7a49f8111e2..d3a1721ccb9 100644 --- a/substrate/frame/transaction-payment/src/tests.rs +++ b/substrate/frame/transaction-payment/src/tests.rs @@ -21,14 +21,11 @@ use crate as pallet_transaction_payment; use codec::Encode; use sp_runtime::{ - generic::UncheckedExtrinsic, - traits::{DispatchTransaction, One}, - transaction_validity::InvalidTransaction, - BuildStorage, + testing::TestXt, traits::One, transaction_validity::InvalidTransaction, BuildStorage, }; use frame_support::{ - assert_ok, + assert_noop, assert_ok, dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, PostDispatchInfo}, traits::Currency, weights::Weight, @@ -131,37 +128,44 @@ fn default_post_info() -> PostDispatchInfo { PostDispatchInfo { actual_weight: None, pays_fee: Default::default() } } -type Ext = ChargeTransactionPayment; - #[test] -fn transaction_extension_transaction_payment_work() { +fn signed_extension_transaction_payment_work() { ExtBuilder::default() .balance_factor(10) .base_weight(Weight::from_parts(5, 0)) .build() .execute_with(|| { - let info = info_from_weight(Weight::from_parts(5, 0)); - Ext::from(0) - .test_run(Some(1).into(), CALL, &info, 10, |_| { - assert_eq!(Balances::free_balance(1), 100 - 5 - 5 - 10); - Ok(default_post_info()) - }) - .unwrap() + let len = 10; + let pre = ChargeTransactionPayment::::from(0) + .pre_dispatch(&1, CALL, &info_from_weight(Weight::from_parts(5, 0)), len) .unwrap(); assert_eq!(Balances::free_balance(1), 100 - 5 - 5 - 10); + + assert_ok!(ChargeTransactionPayment::::post_dispatch( + Some(pre), + &info_from_weight(Weight::from_parts(5, 0)), + &default_post_info(), + len, + &Ok(()) + )); + assert_eq!(Balances::free_balance(1), 100 - 5 - 5 - 10); assert_eq!(FeeUnbalancedAmount::get(), 5 + 5 + 10); assert_eq!(TipUnbalancedAmount::get(), 0); FeeUnbalancedAmount::mutate(|a| *a = 0); - let info = info_from_weight(Weight::from_parts(100, 0)); - Ext::from(5 /* tipped */) - .test_run(Some(2).into(), CALL, &info, 10, |_| { - assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); - Ok(post_info_from_weight(Weight::from_parts(50, 0))) - }) - .unwrap() + let pre = ChargeTransactionPayment::::from(5 /* tipped */) + .pre_dispatch(&2, CALL, &info_from_weight(Weight::from_parts(100, 0)), len) .unwrap(); + assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); + + assert_ok!(ChargeTransactionPayment::::post_dispatch( + Some(pre), + &info_from_weight(Weight::from_parts(100, 0)), + &post_info_from_weight(Weight::from_parts(50, 0)), + len, + &Ok(()) + )); assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 50 - 5); assert_eq!(FeeUnbalancedAmount::get(), 5 + 10 + 50); assert_eq!(TipUnbalancedAmount::get(), 5); @@ -169,37 +173,43 @@ fn transaction_extension_transaction_payment_work() { } #[test] -fn transaction_extension_transaction_payment_multiplied_refund_works() { +fn signed_extension_transaction_payment_multiplied_refund_works() { ExtBuilder::default() .balance_factor(10) .base_weight(Weight::from_parts(5, 0)) .build() .execute_with(|| { + let len = 10; >::put(Multiplier::saturating_from_rational(3, 2)); - let len = 10; - let origin = Some(2).into(); - let info = info_from_weight(Weight::from_parts(100, 0)); - Ext::from(5 /* tipped */) - .test_run(origin, CALL, &info, len, |_| { - // 5 base fee, 10 byte fee, 3/2 * 100 weight fee, 5 tip - assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 150 - 5); - Ok(post_info_from_weight(Weight::from_parts(50, 0))) - }) - .unwrap() + let pre = ChargeTransactionPayment::::from(5 /* tipped */) + .pre_dispatch(&2, CALL, &info_from_weight(Weight::from_parts(100, 0)), len) .unwrap(); - + // 5 base fee, 10 byte fee, 3/2 * 100 weight fee, 5 tip + assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 150 - 5); + + assert_ok!(ChargeTransactionPayment::::post_dispatch( + Some(pre), + &info_from_weight(Weight::from_parts(100, 0)), + &post_info_from_weight(Weight::from_parts(50, 0)), + len, + &Ok(()) + )); // 75 (3/2 of the returned 50 units of weight) is refunded assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 75 - 5); }); } #[test] -fn transaction_extension_transaction_payment_is_bounded() { +fn signed_extension_transaction_payment_is_bounded() { ExtBuilder::default().balance_factor(1000).byte_fee(0).build().execute_with(|| { // maximum weight possible - let info = info_from_weight(Weight::MAX); - assert_ok!(Ext::from(0).validate_and_prepare(Some(1).into(), CALL, &info, 10)); + assert_ok!(ChargeTransactionPayment::::from(0).pre_dispatch( + &1, + CALL, + &info_from_weight(Weight::MAX), + 10 + )); // fee will be proportional to what is the actual maximum weight in the runtime. assert_eq!( Balances::free_balance(&1), @@ -210,7 +220,7 @@ fn transaction_extension_transaction_payment_is_bounded() { } #[test] -fn transaction_extension_allows_free_transactions() { +fn signed_extension_allows_free_transactions() { ExtBuilder::default() .base_weight(Weight::from_parts(100, 0)) .balance_factor(0) @@ -222,28 +232,38 @@ fn transaction_extension_allows_free_transactions() { let len = 100; // This is a completely free (and thus wholly insecure/DoS-ridden) transaction. - let op_tx = DispatchInfo { + let operational_transaction = DispatchInfo { weight: Weight::from_parts(0, 0), class: DispatchClass::Operational, pays_fee: Pays::No, }; - assert_ok!(Ext::from(0).validate_only(Some(1).into(), CALL, &op_tx, len)); + assert_ok!(ChargeTransactionPayment::::from(0).validate( + &1, + CALL, + &operational_transaction, + len + )); // like a InsecureFreeNormal - let free_tx = DispatchInfo { + let free_transaction = DispatchInfo { weight: Weight::from_parts(0, 0), class: DispatchClass::Normal, pays_fee: Pays::Yes, }; - assert_eq!( - Ext::from(0).validate_only(Some(1).into(), CALL, &free_tx, len).unwrap_err(), + assert_noop!( + ChargeTransactionPayment::::from(0).validate( + &1, + CALL, + &free_transaction, + len + ), TransactionValidityError::Invalid(InvalidTransaction::Payment), ); }); } #[test] -fn transaction_ext_length_fee_is_also_updated_per_congestion() { +fn signed_ext_length_fee_is_also_updated_per_congestion() { ExtBuilder::default() .base_weight(Weight::from_parts(5, 0)) .balance_factor(10) @@ -252,15 +272,16 @@ fn transaction_ext_length_fee_is_also_updated_per_congestion() { // all fees should be x1.5 >::put(Multiplier::saturating_from_rational(3, 2)); let len = 10; - let info = &info_from_weight(Weight::from_parts(3, 0)); - assert_ok!(Ext::from(10).validate_and_prepare(Some(1).into(), CALL, info, len)); + + assert_ok!(ChargeTransactionPayment::::from(10) // tipped + .pre_dispatch(&1, CALL, &info_from_weight(Weight::from_parts(3, 0)), len)); assert_eq!( Balances::free_balance(1), 100 // original - - 10 // tip - - 5 // base - - 10 // len - - (3 * 3 / 2) // adjusted weight + - 10 // tip + - 5 // base + - 10 // len + - (3 * 3 / 2) // adjusted weight ); }) } @@ -270,62 +291,62 @@ fn query_info_and_fee_details_works() { let call = RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 2, value: 69 }); let origin = 111111; let extra = (); - let xt = UncheckedExtrinsic::new_signed(call.clone(), origin, (), extra); + let xt = TestXt::new(call.clone(), Some((origin, extra))); let info = xt.get_dispatch_info(); let ext = xt.encode(); let len = ext.len() as u32; - let unsigned_xt = UncheckedExtrinsic::::new_bare(call); + let unsigned_xt = TestXt::<_, ()>::new(call, None); let unsigned_xt_info = unsigned_xt.get_dispatch_info(); ExtBuilder::default() - .base_weight(Weight::from_parts(5, 0)) - .weight_fee(2) - .build() - .execute_with(|| { - // all fees should be x1.5 - >::put(Multiplier::saturating_from_rational(3, 2)); - - assert_eq!( - TransactionPayment::query_info(xt.clone(), len), - RuntimeDispatchInfo { - weight: info.weight, - class: info.class, - partial_fee: 5 * 2 /* base * weight_fee */ - + len as u64 /* len * 1 */ - + info.weight.min(BlockWeights::get().max_block).ref_time() as u64 * 2 * 3 / 2 /* weight */ - }, - ); - - assert_eq!( - TransactionPayment::query_info(unsigned_xt.clone(), len), - RuntimeDispatchInfo { - weight: unsigned_xt_info.weight, - class: unsigned_xt_info.class, - partial_fee: 0, - }, - ); - - assert_eq!( - TransactionPayment::query_fee_details(xt, len), - FeeDetails { - inclusion_fee: Some(InclusionFee { - base_fee: 5 * 2, - len_fee: len as u64, - adjusted_weight_fee: info - .weight - .min(BlockWeights::get().max_block) - .ref_time() as u64 * 2 * 3 / 2 - }), - tip: 0, - }, - ); - - assert_eq!( - TransactionPayment::query_fee_details(unsigned_xt, len), - FeeDetails { inclusion_fee: None, tip: 0 }, - ); - }); + .base_weight(Weight::from_parts(5, 0)) + .weight_fee(2) + .build() + .execute_with(|| { + // all fees should be x1.5 + >::put(Multiplier::saturating_from_rational(3, 2)); + + assert_eq!( + TransactionPayment::query_info(xt.clone(), len), + RuntimeDispatchInfo { + weight: info.weight, + class: info.class, + partial_fee: 5 * 2 /* base * weight_fee */ + + len as u64 /* len * 1 */ + + info.weight.min(BlockWeights::get().max_block).ref_time() as u64 * 2 * 3 / 2 /* weight */ + }, + ); + + assert_eq!( + TransactionPayment::query_info(unsigned_xt.clone(), len), + RuntimeDispatchInfo { + weight: unsigned_xt_info.weight, + class: unsigned_xt_info.class, + partial_fee: 0, + }, + ); + + assert_eq!( + TransactionPayment::query_fee_details(xt, len), + FeeDetails { + inclusion_fee: Some(InclusionFee { + base_fee: 5 * 2, + len_fee: len as u64, + adjusted_weight_fee: info + .weight + .min(BlockWeights::get().max_block) + .ref_time() as u64 * 2 * 3 / 2 + }), + tip: 0, + }, + ); + + assert_eq!( + TransactionPayment::query_fee_details(unsigned_xt, len), + FeeDetails { inclusion_fee: None, tip: 0 }, + ); + }); } #[test] @@ -336,39 +357,39 @@ fn query_call_info_and_fee_details_works() { let len = encoded_call.len() as u32; ExtBuilder::default() - .base_weight(Weight::from_parts(5, 0)) - .weight_fee(2) - .build() - .execute_with(|| { - // all fees should be x1.5 - >::put(Multiplier::saturating_from_rational(3, 2)); - - assert_eq!( - TransactionPayment::query_call_info(call.clone(), len), - RuntimeDispatchInfo { - weight: info.weight, - class: info.class, - partial_fee: 5 * 2 /* base * weight_fee */ - + len as u64 /* len * 1 */ - + info.weight.min(BlockWeights::get().max_block).ref_time() as u64 * 2 * 3 / 2 /* weight */ - }, - ); - - assert_eq!( - TransactionPayment::query_call_fee_details(call, len), - FeeDetails { - inclusion_fee: Some(InclusionFee { - base_fee: 5 * 2, /* base * weight_fee */ - len_fee: len as u64, /* len * 1 */ - adjusted_weight_fee: info - .weight - .min(BlockWeights::get().max_block) - .ref_time() as u64 * 2 * 3 / 2 /* weight * weight_fee * multipler */ - }), - tip: 0, - }, - ); - }); + .base_weight(Weight::from_parts(5, 0)) + .weight_fee(2) + .build() + .execute_with(|| { + // all fees should be x1.5 + >::put(Multiplier::saturating_from_rational(3, 2)); + + assert_eq!( + TransactionPayment::query_call_info(call.clone(), len), + RuntimeDispatchInfo { + weight: info.weight, + class: info.class, + partial_fee: 5 * 2 /* base * weight_fee */ + + len as u64 /* len * 1 */ + + info.weight.min(BlockWeights::get().max_block).ref_time() as u64 * 2 * 3 / 2 /* weight */ + }, + ); + + assert_eq!( + TransactionPayment::query_call_fee_details(call, len), + FeeDetails { + inclusion_fee: Some(InclusionFee { + base_fee: 5 * 2, /* base * weight_fee */ + len_fee: len as u64, /* len * 1 */ + adjusted_weight_fee: info + .weight + .min(BlockWeights::get().max_block) + .ref_time() as u64 * 2 * 3 / 2 /* weight * weight_fee * multipler */ + }), + tip: 0, + }, + ); + }); } #[test] @@ -505,23 +526,27 @@ fn refund_does_not_recreate_account() { .execute_with(|| { // So events are emitted System::set_block_number(10); - let info = info_from_weight(Weight::from_parts(100, 0)); - Ext::from(5 /* tipped */) - .test_run(Some(2).into(), CALL, &info, 10, |origin| { - assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); - - // kill the account between pre and post dispatch - assert_ok!(Balances::transfer_allow_death( - origin, - 3, - Balances::free_balance(2) - )); - assert_eq!(Balances::free_balance(2), 0); - - Ok(post_info_from_weight(Weight::from_parts(50, 0))) - }) - .unwrap() + let len = 10; + let pre = ChargeTransactionPayment::::from(5 /* tipped */) + .pre_dispatch(&2, CALL, &info_from_weight(Weight::from_parts(100, 0)), len) .unwrap(); + assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); + + // kill the account between pre and post dispatch + assert_ok!(Balances::transfer_allow_death( + Some(2).into(), + 3, + Balances::free_balance(2) + )); + assert_eq!(Balances::free_balance(2), 0); + + assert_ok!(ChargeTransactionPayment::::post_dispatch( + Some(pre), + &info_from_weight(Weight::from_parts(100, 0)), + &post_info_from_weight(Weight::from_parts(50, 0)), + len, + &Ok(()) + )); assert_eq!(Balances::free_balance(2), 0); // Transfer Event System::assert_has_event(RuntimeEvent::Balances(pallet_balances::Event::Transfer { @@ -543,15 +568,20 @@ fn actual_weight_higher_than_max_refunds_nothing() { .base_weight(Weight::from_parts(5, 0)) .build() .execute_with(|| { - let info = info_from_weight(Weight::from_parts(100, 0)); - Ext::from(5 /* tipped */) - .test_run(Some(2).into(), CALL, &info, 10, |_| { - assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); - Ok(post_info_from_weight(Weight::from_parts(101, 0))) - }) - .unwrap() + let len = 10; + let pre = ChargeTransactionPayment::::from(5 /* tipped */) + .pre_dispatch(&2, CALL, &info_from_weight(Weight::from_parts(100, 0)), len) .unwrap(); assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); + + assert_ok!(ChargeTransactionPayment::::post_dispatch( + Some(pre), + &info_from_weight(Weight::from_parts(100, 0)), + &post_info_from_weight(Weight::from_parts(101, 0)), + len, + &Ok(()) + )); + assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); }); } @@ -564,20 +594,25 @@ fn zero_transfer_on_free_transaction() { .execute_with(|| { // So events are emitted System::set_block_number(10); - let info = DispatchInfo { + let len = 10; + let dispatch_info = DispatchInfo { weight: Weight::from_parts(100, 0), pays_fee: Pays::No, class: DispatchClass::Normal, }; let user = 69; - Ext::from(0) - .test_run(Some(user).into(), CALL, &info, 10, |_| { - assert_eq!(Balances::total_balance(&user), 0); - Ok(default_post_info()) - }) - .unwrap() + let pre = ChargeTransactionPayment::::from(0) + .pre_dispatch(&user, CALL, &dispatch_info, len) .unwrap(); assert_eq!(Balances::total_balance(&user), 0); + assert_ok!(ChargeTransactionPayment::::post_dispatch( + Some(pre), + &dispatch_info, + &default_post_info(), + len, + &Ok(()) + )); + assert_eq!(Balances::total_balance(&user), 0); // TransactionFeePaid Event System::assert_has_event(RuntimeEvent::TransactionPayment( pallet_transaction_payment::Event::TransactionFeePaid { @@ -604,11 +639,19 @@ fn refund_consistent_with_actual_weight() { >::put(Multiplier::saturating_from_rational(5, 4)); - Ext::from(tip) - .test_run(Some(2).into(), CALL, &info, len, |_| Ok(post_info)) - .unwrap() + let pre = ChargeTransactionPayment::::from(tip) + .pre_dispatch(&2, CALL, &info, len) .unwrap(); + ChargeTransactionPayment::::post_dispatch( + Some(pre), + &info, + &post_info, + len, + &Ok(()), + ) + .unwrap(); + let refund_based_fee = prev_balance - Balances::free_balance(2); let actual_fee = Pallet::::compute_actual_fee(len as u32, &info, &post_info, tip); @@ -630,13 +673,18 @@ fn should_alter_operational_priority() { class: DispatchClass::Normal, pays_fee: Pays::Yes, }; + let priority = ChargeTransactionPayment::(tip) + .validate(&2, CALL, &normal, len) + .unwrap() + .priority; - let ext = Ext::from(tip); - let priority = ext.validate_only(Some(2).into(), CALL, &normal, len).unwrap().0.priority; assert_eq!(priority, 60); - let ext = Ext::from(2 * tip); - let priority = ext.validate_only(Some(2).into(), CALL, &normal, len).unwrap().0.priority; + let priority = ChargeTransactionPayment::(2 * tip) + .validate(&2, CALL, &normal, len) + .unwrap() + .priority; + assert_eq!(priority, 110); }); @@ -646,13 +694,16 @@ fn should_alter_operational_priority() { class: DispatchClass::Operational, pays_fee: Pays::Yes, }; - - let ext = Ext::from(tip); - let priority = ext.validate_only(Some(2).into(), CALL, &op, len).unwrap().0.priority; + let priority = ChargeTransactionPayment::(tip) + .validate(&2, CALL, &op, len) + .unwrap() + .priority; assert_eq!(priority, 5810); - let ext = Ext::from(2 * tip); - let priority = ext.validate_only(Some(2).into(), CALL, &op, len).unwrap().0.priority; + let priority = ChargeTransactionPayment::(2 * tip) + .validate(&2, CALL, &op, len) + .unwrap() + .priority; assert_eq!(priority, 6110); }); } @@ -668,8 +719,11 @@ fn no_tip_has_some_priority() { class: DispatchClass::Normal, pays_fee: Pays::Yes, }; - let ext = Ext::from(tip); - let priority = ext.validate_only(Some(2).into(), CALL, &normal, len).unwrap().0.priority; + let priority = ChargeTransactionPayment::(tip) + .validate(&2, CALL, &normal, len) + .unwrap() + .priority; + assert_eq!(priority, 10); }); @@ -679,8 +733,10 @@ fn no_tip_has_some_priority() { class: DispatchClass::Operational, pays_fee: Pays::Yes, }; - let ext = Ext::from(tip); - let priority = ext.validate_only(Some(2).into(), CALL, &op, len).unwrap().0.priority; + let priority = ChargeTransactionPayment::(tip) + .validate(&2, CALL, &op, len) + .unwrap() + .priority; assert_eq!(priority, 5510); }); } @@ -688,8 +744,8 @@ fn no_tip_has_some_priority() { #[test] fn higher_tip_have_higher_priority() { let get_priorities = |tip: u64| { - let mut pri1 = 0; - let mut pri2 = 0; + let mut priority1 = 0; + let mut priority2 = 0; let len = 10; ExtBuilder::default().balance_factor(100).build().execute_with(|| { let normal = DispatchInfo { @@ -697,8 +753,10 @@ fn higher_tip_have_higher_priority() { class: DispatchClass::Normal, pays_fee: Pays::Yes, }; - let ext = Ext::from(tip); - pri1 = ext.validate_only(Some(2).into(), CALL, &normal, len).unwrap().0.priority; + priority1 = ChargeTransactionPayment::(tip) + .validate(&2, CALL, &normal, len) + .unwrap() + .priority; }); ExtBuilder::default().balance_factor(100).build().execute_with(|| { @@ -707,11 +765,13 @@ fn higher_tip_have_higher_priority() { class: DispatchClass::Operational, pays_fee: Pays::Yes, }; - let ext = Ext::from(tip); - pri2 = ext.validate_only(Some(2).into(), CALL, &op, len).unwrap().0.priority; + priority2 = ChargeTransactionPayment::(tip) + .validate(&2, CALL, &op, len) + .unwrap() + .priority; }); - (pri1, pri2) + (priority1, priority2) }; let mut prev_priorities = get_priorities(0); @@ -739,11 +799,19 @@ fn post_info_can_change_pays_fee() { >::put(Multiplier::saturating_from_rational(5, 4)); - let post_info = ChargeTransactionPayment::::from(tip) - .test_run(Some(2).into(), CALL, &info, len, |_| Ok(post_info)) - .unwrap() + let pre = ChargeTransactionPayment::::from(tip) + .pre_dispatch(&2, CALL, &info, len) .unwrap(); + ChargeTransactionPayment::::post_dispatch( + Some(pre), + &info, + &post_info, + len, + &Ok(()), + ) + .unwrap(); + let refund_based_fee = prev_balance - Balances::free_balance(2); let actual_fee = Pallet::::compute_actual_fee(len as u32, &info, &post_info, tip); diff --git a/substrate/frame/transaction-payment/src/types.rs b/substrate/frame/transaction-payment/src/types.rs index bfb3012fef0..25cecc58a63 100644 --- a/substrate/frame/transaction-payment/src/types.rs +++ b/substrate/frame/transaction-payment/src/types.rs @@ -112,7 +112,7 @@ pub struct RuntimeDispatchInfo /// The inclusion fee of this dispatch. /// /// This does not include a tip or anything else that - /// depends on the signature (i.e. depends on a `TransactionExtension`). + /// depends on the signature (i.e. depends on a `SignedExtension`). #[cfg_attr(feature = "std", serde(with = "serde_balance"))] pub partial_fee: Balance, } diff --git a/substrate/frame/transaction-payment/src/weights.rs b/substrate/frame/transaction-payment/src/weights.rs deleted file mode 100644 index bcffb2eb331..00000000000 --- a/substrate/frame/transaction-payment/src/weights.rs +++ /dev/null @@ -1,92 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Autogenerated weights for `pallet_transaction_payment` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` - -// Executed Command: -// ./target/production/substrate-node -// benchmark -// pallet -// --chain=dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_transaction_payment -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* -// --wasm-execution=compiled -// --heap-pages=4096 -// --output=./substrate/frame/transaction-payment/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; -use core::marker::PhantomData; - -/// Weight functions needed for `pallet_transaction_payment`. -pub trait WeightInfo { - fn charge_transaction_payment() -> Weight; -} - -/// Weights for `pallet_transaction_payment` using the Substrate node and recommended hardware. -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn charge_transaction_payment() -> Weight { - // Proof Size summary in bytes: - // Measured: `248` - // Estimated: `1733` - // Minimum execution time: 40_506_000 picoseconds. - Weight::from_parts(41_647_000, 1733) - .saturating_add(T::DbWeight::get().reads(3_u64)) - } -} - -// For backwards compatibility and tests. -impl WeightInfo for () { - /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) - /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Authorship::Author` (r:1 w:0) - /// Proof: `Authorship::Author` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `System::Digest` (r:1 w:0) - /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn charge_transaction_payment() -> Weight { - // Proof Size summary in bytes: - // Measured: `248` - // Estimated: `1733` - // Minimum execution time: 40_506_000 picoseconds. - Weight::from_parts(41_647_000, 1733) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - } -} diff --git a/substrate/frame/transaction-storage/src/weights.rs b/substrate/frame/transaction-storage/src/weights.rs index bfbed62c5a3..519317177c4 100644 --- a/substrate/frame/transaction-storage/src/weights.rs +++ b/substrate/frame/transaction-storage/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_transaction_storage` +//! Autogenerated weights for pallet_transaction_storage //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/transaction-storage/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/transaction-storage/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,133 +50,125 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_transaction_storage`. +/// Weight functions needed for pallet_transaction_storage. pub trait WeightInfo { fn store(l: u32, ) -> Weight; fn renew() -> Weight; fn check_proof_max() -> Weight; } -/// Weights for `pallet_transaction_storage` using the Substrate node and recommended hardware. +/// Weights for pallet_transaction_storage using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `TransactionStorage::ByteFee` (r:1 w:0) - /// Proof: `TransactionStorage::ByteFee` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `TransactionStorage::EntryFee` (r:1 w:0) - /// Proof: `TransactionStorage::EntryFee` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) - /// Storage: `TransactionStorage::BlockTransactions` (r:1 w:1) - /// Proof: `TransactionStorage::BlockTransactions` (`max_values`: Some(1), `max_size`: Some(36866), added: 37361, mode: `MaxEncodedLen`) + /// Storage: TransactionStorage ByteFee (r:1 w:0) + /// Proof: TransactionStorage ByteFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: TransactionStorage EntryFee (r:1 w:0) + /// Proof: TransactionStorage EntryFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: TransactionStorage BlockTransactions (r:1 w:1) + /// Proof: TransactionStorage BlockTransactions (max_values: Some(1), max_size: Some(36866), added: 37361, mode: MaxEncodedLen) /// The range of component `l` is `[1, 8388608]`. fn store(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `242` + // Measured: `176` // Estimated: `38351` - // Minimum execution time: 57_912_000 picoseconds. - Weight::from_parts(58_642_000, 38351) + // Minimum execution time: 34_844_000 picoseconds. + Weight::from_parts(35_489_000, 38351) // Standard Error: 11 - .saturating_add(Weight::from_parts(6_778, 0).saturating_mul(l.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(6_912, 0).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `TransactionStorage::Transactions` (r:1 w:0) - /// Proof: `TransactionStorage::Transactions` (`max_values`: None, `max_size`: Some(36886), added: 39361, mode: `MaxEncodedLen`) - /// Storage: `TransactionStorage::ByteFee` (r:1 w:0) - /// Proof: `TransactionStorage::ByteFee` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `TransactionStorage::EntryFee` (r:1 w:0) - /// Proof: `TransactionStorage::EntryFee` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) - /// Storage: `TransactionStorage::BlockTransactions` (r:1 w:1) - /// Proof: `TransactionStorage::BlockTransactions` (`max_values`: Some(1), `max_size`: Some(36866), added: 37361, mode: `MaxEncodedLen`) + /// Storage: TransactionStorage Transactions (r:1 w:0) + /// Proof: TransactionStorage Transactions (max_values: None, max_size: Some(36886), added: 39361, mode: MaxEncodedLen) + /// Storage: TransactionStorage ByteFee (r:1 w:0) + /// Proof: TransactionStorage ByteFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: TransactionStorage EntryFee (r:1 w:0) + /// Proof: TransactionStorage EntryFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: TransactionStorage BlockTransactions (r:1 w:1) + /// Proof: TransactionStorage BlockTransactions (max_values: Some(1), max_size: Some(36866), added: 37361, mode: MaxEncodedLen) fn renew() -> Weight { // Proof Size summary in bytes: - // Measured: `430` + // Measured: `326` // Estimated: `40351` - // Minimum execution time: 72_571_000 picoseconds. - Weight::from_parts(74_832_000, 40351) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + // Minimum execution time: 48_244_000 picoseconds. + Weight::from_parts(50_939_000, 40351) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `TransactionStorage::ProofChecked` (r:1 w:1) - /// Proof: `TransactionStorage::ProofChecked` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) - /// Storage: `TransactionStorage::StoragePeriod` (r:1 w:0) - /// Proof: `TransactionStorage::StoragePeriod` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TransactionStorage::ChunkCount` (r:1 w:0) - /// Proof: `TransactionStorage::ChunkCount` (`max_values`: None, `max_size`: Some(24), added: 2499, mode: `MaxEncodedLen`) - /// Storage: `System::ParentHash` (r:1 w:0) - /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `TransactionStorage::Transactions` (r:1 w:0) - /// Proof: `TransactionStorage::Transactions` (`max_values`: None, `max_size`: Some(36886), added: 39361, mode: `MaxEncodedLen`) + /// Storage: TransactionStorage ProofChecked (r:1 w:1) + /// Proof: TransactionStorage ProofChecked (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: TransactionStorage StoragePeriod (r:1 w:0) + /// Proof: TransactionStorage StoragePeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: TransactionStorage ChunkCount (r:1 w:0) + /// Proof: TransactionStorage ChunkCount (max_values: None, max_size: Some(24), added: 2499, mode: MaxEncodedLen) + /// Storage: System ParentHash (r:1 w:0) + /// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TransactionStorage Transactions (r:1 w:0) + /// Proof: TransactionStorage Transactions (max_values: None, max_size: Some(36886), added: 39361, mode: MaxEncodedLen) fn check_proof_max() -> Weight { // Proof Size summary in bytes: - // Measured: `37211` + // Measured: `37145` // Estimated: `40351` - // Minimum execution time: 65_985_000 picoseconds. - Weight::from_parts(72_960_000, 40351) + // Minimum execution time: 80_913_000 picoseconds. + Weight::from_parts(84_812_000, 40351) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `TransactionStorage::ByteFee` (r:1 w:0) - /// Proof: `TransactionStorage::ByteFee` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `TransactionStorage::EntryFee` (r:1 w:0) - /// Proof: `TransactionStorage::EntryFee` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) - /// Storage: `TransactionStorage::BlockTransactions` (r:1 w:1) - /// Proof: `TransactionStorage::BlockTransactions` (`max_values`: Some(1), `max_size`: Some(36866), added: 37361, mode: `MaxEncodedLen`) + /// Storage: TransactionStorage ByteFee (r:1 w:0) + /// Proof: TransactionStorage ByteFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: TransactionStorage EntryFee (r:1 w:0) + /// Proof: TransactionStorage EntryFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: TransactionStorage BlockTransactions (r:1 w:1) + /// Proof: TransactionStorage BlockTransactions (max_values: Some(1), max_size: Some(36866), added: 37361, mode: MaxEncodedLen) /// The range of component `l` is `[1, 8388608]`. fn store(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `242` + // Measured: `176` // Estimated: `38351` - // Minimum execution time: 57_912_000 picoseconds. - Weight::from_parts(58_642_000, 38351) + // Minimum execution time: 34_844_000 picoseconds. + Weight::from_parts(35_489_000, 38351) // Standard Error: 11 - .saturating_add(Weight::from_parts(6_778, 0).saturating_mul(l.into())) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(6_912, 0).saturating_mul(l.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `TransactionStorage::Transactions` (r:1 w:0) - /// Proof: `TransactionStorage::Transactions` (`max_values`: None, `max_size`: Some(36886), added: 39361, mode: `MaxEncodedLen`) - /// Storage: `TransactionStorage::ByteFee` (r:1 w:0) - /// Proof: `TransactionStorage::ByteFee` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `TransactionStorage::EntryFee` (r:1 w:0) - /// Proof: `TransactionStorage::EntryFee` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) - /// Storage: `TransactionStorage::BlockTransactions` (r:1 w:1) - /// Proof: `TransactionStorage::BlockTransactions` (`max_values`: Some(1), `max_size`: Some(36866), added: 37361, mode: `MaxEncodedLen`) + /// Storage: TransactionStorage Transactions (r:1 w:0) + /// Proof: TransactionStorage Transactions (max_values: None, max_size: Some(36886), added: 39361, mode: MaxEncodedLen) + /// Storage: TransactionStorage ByteFee (r:1 w:0) + /// Proof: TransactionStorage ByteFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: TransactionStorage EntryFee (r:1 w:0) + /// Proof: TransactionStorage EntryFee (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: TransactionStorage BlockTransactions (r:1 w:1) + /// Proof: TransactionStorage BlockTransactions (max_values: Some(1), max_size: Some(36866), added: 37361, mode: MaxEncodedLen) fn renew() -> Weight { // Proof Size summary in bytes: - // Measured: `430` + // Measured: `326` // Estimated: `40351` - // Minimum execution time: 72_571_000 picoseconds. - Weight::from_parts(74_832_000, 40351) - .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + // Minimum execution time: 48_244_000 picoseconds. + Weight::from_parts(50_939_000, 40351) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `TransactionStorage::ProofChecked` (r:1 w:1) - /// Proof: `TransactionStorage::ProofChecked` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) - /// Storage: `TransactionStorage::StoragePeriod` (r:1 w:0) - /// Proof: `TransactionStorage::StoragePeriod` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TransactionStorage::ChunkCount` (r:1 w:0) - /// Proof: `TransactionStorage::ChunkCount` (`max_values`: None, `max_size`: Some(24), added: 2499, mode: `MaxEncodedLen`) - /// Storage: `System::ParentHash` (r:1 w:0) - /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `TransactionStorage::Transactions` (r:1 w:0) - /// Proof: `TransactionStorage::Transactions` (`max_values`: None, `max_size`: Some(36886), added: 39361, mode: `MaxEncodedLen`) + /// Storage: TransactionStorage ProofChecked (r:1 w:1) + /// Proof: TransactionStorage ProofChecked (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: TransactionStorage StoragePeriod (r:1 w:0) + /// Proof: TransactionStorage StoragePeriod (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: TransactionStorage ChunkCount (r:1 w:0) + /// Proof: TransactionStorage ChunkCount (max_values: None, max_size: Some(24), added: 2499, mode: MaxEncodedLen) + /// Storage: System ParentHash (r:1 w:0) + /// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) + /// Storage: TransactionStorage Transactions (r:1 w:0) + /// Proof: TransactionStorage Transactions (max_values: None, max_size: Some(36886), added: 39361, mode: MaxEncodedLen) fn check_proof_max() -> Weight { // Proof Size summary in bytes: - // Measured: `37211` + // Measured: `37145` // Estimated: `40351` - // Minimum execution time: 65_985_000 picoseconds. - Weight::from_parts(72_960_000, 40351) + // Minimum execution time: 80_913_000 picoseconds. + Weight::from_parts(84_812_000, 40351) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/treasury/src/weights.rs b/substrate/frame/treasury/src/weights.rs index 8ef4f89fd65..030e18980eb 100644 --- a/substrate/frame/treasury/src/weights.rs +++ b/substrate/frame/treasury/src/weights.rs @@ -15,31 +15,27 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_treasury` +//! Autogenerated weights for pallet_treasury //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-07, STEPS: `20`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `cob`, CPU: `` +//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/debug/substrate // benchmark // pallet // --chain=dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_treasury -// --no-storage-info -// --no-median-slopes -// --no-min-squares +// --steps=20 +// --repeat=2 +// --pallet=pallet-treasury // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/treasury/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/treasury/src/._weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +45,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_treasury`. +/// Weight functions needed for pallet_treasury. pub trait WeightInfo { fn spend_local() -> Weight; fn propose_spend() -> Weight; @@ -63,304 +59,304 @@ pub trait WeightInfo { fn void_spend() -> Weight; } -/// Weights for `pallet_treasury` using the Substrate node and recommended hardware. +/// Weights for pallet_treasury using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Treasury::ProposalCount` (r:1 w:1) - /// Proof: `Treasury::ProposalCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Approvals` (r:1 w:1) - /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Proposals` (r:0 w:1) - /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Storage: Treasury ProposalCount (r:1 w:1) + /// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + /// Storage: Treasury Proposals (r:0 w:1) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) fn spend_local() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1887` - // Minimum execution time: 11_686_000 picoseconds. - Weight::from_parts(12_138_000, 1887) + // Minimum execution time: 179_000_000 picoseconds. + Weight::from_parts(190_000_000, 1887) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } - /// Storage: `Treasury::ProposalCount` (r:1 w:1) - /// Proof: `Treasury::ProposalCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Proposals` (r:0 w:1) - /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Storage: Treasury ProposalCount (r:1 w:1) + /// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Treasury Proposals (r:0 w:1) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) fn propose_spend() -> Weight { // Proof Size summary in bytes: // Measured: `177` // Estimated: `1489` - // Minimum execution time: 23_773_000 picoseconds. - Weight::from_parts(24_801_000, 1489) + // Minimum execution time: 349_000_000 picoseconds. + Weight::from_parts(398_000_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Treasury::Proposals` (r:1 w:1) - /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Treasury Proposals (r:1 w:1) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn reject_proposal() -> Weight { // Proof Size summary in bytes: // Measured: `335` // Estimated: `3593` - // Minimum execution time: 24_533_000 picoseconds. - Weight::from_parts(25_731_000, 3593) + // Minimum execution time: 367_000_000 picoseconds. + Weight::from_parts(388_000_000, 3593) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Treasury::Proposals` (r:1 w:0) - /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Approvals` (r:1 w:1) - /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: Treasury Proposals (r:1 w:0) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) /// The range of component `p` is `[0, 99]`. fn approve_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `504 + p * (8 ±0)` + // Measured: `483 + p * (9 ±0)` // Estimated: `3573` - // Minimum execution time: 8_245_000 picoseconds. - Weight::from_parts(11_300_222, 3573) - // Standard Error: 1_080 - .saturating_add(Weight::from_parts(71_375, 0).saturating_mul(p.into())) + // Minimum execution time: 111_000_000 picoseconds. + Weight::from_parts(108_813_243, 3573) + // Standard Error: 147_887 + .saturating_add(Weight::from_parts(683_216, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Treasury::Approvals` (r:1 w:1) - /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) fn remove_approval() -> Weight { // Proof Size summary in bytes: // Measured: `161` // Estimated: `1887` - // Minimum execution time: 6_231_000 picoseconds. - Weight::from_parts(6_517_000, 1887) + // Minimum execution time: 71_000_000 picoseconds. + Weight::from_parts(78_000_000, 1887) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Treasury::Deactivated` (r:1 w:1) - /// Proof: `Treasury::Deactivated` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Approvals` (r:1 w:1) - /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Proposals` (r:99 w:99) - /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:198 w:198) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Bounties::BountyApprovals` (r:1 w:1) - /// Proof: `Bounties::BountyApprovals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: Treasury Deactivated (r:1 w:1) + /// Proof: Treasury Deactivated (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + /// Storage: Treasury Proposals (r:99 w:99) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: System Account (r:198 w:198) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Bounties BountyApprovals (r:1 w:1) + /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) /// The range of component `p` is `[0, 99]`. fn on_initialize_proposals(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `451 + p * (251 ±0)` + // Measured: `427 + p * (251 ±0)` // Estimated: `1887 + p * (5206 ±0)` - // Minimum execution time: 30_729_000 picoseconds. - Weight::from_parts(37_861_389, 1887) - // Standard Error: 18_741 - .saturating_add(Weight::from_parts(31_377_118, 0).saturating_mul(p.into())) + // Minimum execution time: 614_000_000 picoseconds. + Weight::from_parts(498_501_558, 1887) + // Standard Error: 1_070_260 + .saturating_add(Weight::from_parts(599_011_690, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(p.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(p.into()))) .saturating_add(Weight::from_parts(0, 5206).saturating_mul(p.into())) } - /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:0) - /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) - /// Storage: `Treasury::SpendCount` (r:1 w:1) - /// Proof: `Treasury::SpendCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Spends` (r:0 w:1) - /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: AssetRate ConversionRateToNative (r:1 w:0) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// Storage: Treasury SpendCount (r:1 w:1) + /// Proof: Treasury SpendCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Treasury Spends (r:0 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn spend() -> Weight { // Proof Size summary in bytes: // Measured: `140` // Estimated: `3501` - // Minimum execution time: 13_700_000 picoseconds. - Weight::from_parts(14_519_000, 3501) + // Minimum execution time: 214_000_000 picoseconds. + Weight::from_parts(216_000_000, 3501) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Treasury::Spends` (r:1 w:1) - /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:2 w:2) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Treasury Spends (r:1 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:2 w:2) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn payout() -> Weight { // Proof Size summary in bytes: - // Measured: `709` + // Measured: `705` // Estimated: `6208` - // Minimum execution time: 54_888_000 picoseconds. - Weight::from_parts(55_966_000, 6208) + // Minimum execution time: 760_000_000 picoseconds. + Weight::from_parts(822_000_000, 6208) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: `Treasury::Spends` (r:1 w:1) - /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: Treasury Spends (r:1 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn check_status() -> Weight { // Proof Size summary in bytes: - // Measured: `198` - // Estimated: `3538` - // Minimum execution time: 11_802_000 picoseconds. - Weight::from_parts(12_421_000, 3538) + // Measured: `194` + // Estimated: `3534` + // Minimum execution time: 153_000_000 picoseconds. + Weight::from_parts(160_000_000, 3534) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Treasury::Spends` (r:1 w:1) - /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: Treasury Spends (r:1 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn void_spend() -> Weight { // Proof Size summary in bytes: - // Measured: `198` - // Estimated: `3538` - // Minimum execution time: 10_571_000 picoseconds. - Weight::from_parts(11_052_000, 3538) + // Measured: `194` + // Estimated: `3534` + // Minimum execution time: 147_000_000 picoseconds. + Weight::from_parts(181_000_000, 3534) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Treasury::ProposalCount` (r:1 w:1) - /// Proof: `Treasury::ProposalCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Approvals` (r:1 w:1) - /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Proposals` (r:0 w:1) - /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Storage: Treasury ProposalCount (r:1 w:1) + /// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + /// Storage: Treasury Proposals (r:0 w:1) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) fn spend_local() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1887` - // Minimum execution time: 11_686_000 picoseconds. - Weight::from_parts(12_138_000, 1887) + // Minimum execution time: 179_000_000 picoseconds. + Weight::from_parts(190_000_000, 1887) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } - /// Storage: `Treasury::ProposalCount` (r:1 w:1) - /// Proof: `Treasury::ProposalCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Proposals` (r:0 w:1) - /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Storage: Treasury ProposalCount (r:1 w:1) + /// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Treasury Proposals (r:0 w:1) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) fn propose_spend() -> Weight { // Proof Size summary in bytes: // Measured: `177` // Estimated: `1489` - // Minimum execution time: 23_773_000 picoseconds. - Weight::from_parts(24_801_000, 1489) + // Minimum execution time: 349_000_000 picoseconds. + Weight::from_parts(398_000_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Treasury::Proposals` (r:1 w:1) - /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Treasury Proposals (r:1 w:1) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn reject_proposal() -> Weight { // Proof Size summary in bytes: // Measured: `335` // Estimated: `3593` - // Minimum execution time: 24_533_000 picoseconds. - Weight::from_parts(25_731_000, 3593) + // Minimum execution time: 367_000_000 picoseconds. + Weight::from_parts(388_000_000, 3593) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Treasury::Proposals` (r:1 w:0) - /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Approvals` (r:1 w:1) - /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: Treasury Proposals (r:1 w:0) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) /// The range of component `p` is `[0, 99]`. fn approve_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `504 + p * (8 ±0)` + // Measured: `483 + p * (9 ±0)` // Estimated: `3573` - // Minimum execution time: 8_245_000 picoseconds. - Weight::from_parts(11_300_222, 3573) - // Standard Error: 1_080 - .saturating_add(Weight::from_parts(71_375, 0).saturating_mul(p.into())) + // Minimum execution time: 111_000_000 picoseconds. + Weight::from_parts(108_813_243, 3573) + // Standard Error: 147_887 + .saturating_add(Weight::from_parts(683_216, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Treasury::Approvals` (r:1 w:1) - /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) fn remove_approval() -> Weight { // Proof Size summary in bytes: // Measured: `161` // Estimated: `1887` - // Minimum execution time: 6_231_000 picoseconds. - Weight::from_parts(6_517_000, 1887) + // Minimum execution time: 71_000_000 picoseconds. + Weight::from_parts(78_000_000, 1887) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Treasury::Deactivated` (r:1 w:1) - /// Proof: `Treasury::Deactivated` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Approvals` (r:1 w:1) - /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Proposals` (r:99 w:99) - /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:198 w:198) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Bounties::BountyApprovals` (r:1 w:1) - /// Proof: `Bounties::BountyApprovals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: Treasury Deactivated (r:1 w:1) + /// Proof: Treasury Deactivated (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Treasury Approvals (r:1 w:1) + /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + /// Storage: Treasury Proposals (r:99 w:99) + /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: System Account (r:198 w:198) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Bounties BountyApprovals (r:1 w:1) + /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) /// The range of component `p` is `[0, 99]`. fn on_initialize_proposals(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `451 + p * (251 ±0)` + // Measured: `427 + p * (251 ±0)` // Estimated: `1887 + p * (5206 ±0)` - // Minimum execution time: 30_729_000 picoseconds. - Weight::from_parts(37_861_389, 1887) - // Standard Error: 18_741 - .saturating_add(Weight::from_parts(31_377_118, 0).saturating_mul(p.into())) + // Minimum execution time: 614_000_000 picoseconds. + Weight::from_parts(498_501_558, 1887) + // Standard Error: 1_070_260 + .saturating_add(Weight::from_parts(599_011_690, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(p.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(p.into()))) .saturating_add(Weight::from_parts(0, 5206).saturating_mul(p.into())) } - /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:0) - /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) - /// Storage: `Treasury::SpendCount` (r:1 w:1) - /// Proof: `Treasury::SpendCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Spends` (r:0 w:1) - /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: AssetRate ConversionRateToNative (r:1 w:0) + /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// Storage: Treasury SpendCount (r:1 w:1) + /// Proof: Treasury SpendCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Treasury Spends (r:0 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn spend() -> Weight { // Proof Size summary in bytes: // Measured: `140` // Estimated: `3501` - // Minimum execution time: 13_700_000 picoseconds. - Weight::from_parts(14_519_000, 3501) + // Minimum execution time: 214_000_000 picoseconds. + Weight::from_parts(216_000_000, 3501) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Treasury::Spends` (r:1 w:1) - /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:2 w:2) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: Treasury Spends (r:1 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: Assets Asset (r:1 w:1) + /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) + /// Storage: Assets Account (r:2 w:2) + /// Proof: Assets Account (max_values: None, max_size: Some(134), added: 2609, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn payout() -> Weight { // Proof Size summary in bytes: - // Measured: `709` + // Measured: `705` // Estimated: `6208` - // Minimum execution time: 54_888_000 picoseconds. - Weight::from_parts(55_966_000, 6208) + // Minimum execution time: 760_000_000 picoseconds. + Weight::from_parts(822_000_000, 6208) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: `Treasury::Spends` (r:1 w:1) - /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: Treasury Spends (r:1 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn check_status() -> Weight { // Proof Size summary in bytes: - // Measured: `198` - // Estimated: `3538` - // Minimum execution time: 11_802_000 picoseconds. - Weight::from_parts(12_421_000, 3538) + // Measured: `194` + // Estimated: `3534` + // Minimum execution time: 153_000_000 picoseconds. + Weight::from_parts(160_000_000, 3534) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Treasury::Spends` (r:1 w:1) - /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: Treasury Spends (r:1 w:1) + /// Proof: Treasury Spends (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn void_spend() -> Weight { // Proof Size summary in bytes: - // Measured: `198` - // Estimated: `3538` - // Minimum execution time: 10_571_000 picoseconds. - Weight::from_parts(11_052_000, 3538) + // Measured: `194` + // Estimated: `3534` + // Minimum execution time: 147_000_000 picoseconds. + Weight::from_parts(181_000_000, 3534) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/tx-pause/src/weights.rs b/substrate/frame/tx-pause/src/weights.rs index 14fead12a8e..b733e64b159 100644 --- a/substrate/frame/tx-pause/src/weights.rs +++ b/substrate/frame/tx-pause/src/weights.rs @@ -17,29 +17,27 @@ //! Autogenerated weights for `pallet_tx_pause` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-08-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-aahe6cbd-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/production/substrate-node +// target/production/substrate-node // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_tx_pause -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/tx-pause/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_tx_pause +// --chain=dev +// --header=./HEADER-APACHE2 +// --output=./frame/tx-pause/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -64,8 +62,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3` // Estimated: `3997` - // Minimum execution time: 12_014_000 picoseconds. - Weight::from_parts(12_980_000, 3997) + // Minimum execution time: 15_096_000 picoseconds. + Weight::from_parts(15_437_000, 3997) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -75,8 +73,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `565` // Estimated: `3997` - // Minimum execution time: 17_955_000 picoseconds. - Weight::from_parts(18_348_000, 3997) + // Minimum execution time: 21_546_000 picoseconds. + Weight::from_parts(22_178_000, 3997) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -90,8 +88,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3` // Estimated: `3997` - // Minimum execution time: 12_014_000 picoseconds. - Weight::from_parts(12_980_000, 3997) + // Minimum execution time: 15_096_000 picoseconds. + Weight::from_parts(15_437_000, 3997) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -101,8 +99,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `565` // Estimated: `3997` - // Minimum execution time: 17_955_000 picoseconds. - Weight::from_parts(18_348_000, 3997) + // Minimum execution time: 21_546_000 picoseconds. + Weight::from_parts(22_178_000, 3997) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate/frame/uniques/src/weights.rs b/substrate/frame/uniques/src/weights.rs index 6c7b60b82e5..eb80ee550a1 100644 --- a/substrate/frame/uniques/src/weights.rs +++ b/substrate/frame/uniques/src/weights.rs @@ -17,29 +17,27 @@ //! Autogenerated weights for `pallet_uniques` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-gghbxkbs-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/production/substrate-node +// target/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_uniques -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/uniques/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_uniques +// --chain=dev +// --header=./HEADER-APACHE2 +// --output=./frame/uniques/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -90,8 +88,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `249` // Estimated: `3643` - // Minimum execution time: 27_960_000 picoseconds. - Weight::from_parts(28_781_000, 3643) + // Minimum execution time: 31_393_000 picoseconds. + Weight::from_parts(32_933_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -103,8 +101,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3643` - // Minimum execution time: 11_970_000 picoseconds. - Weight::from_parts(12_512_000, 3643) + // Minimum execution time: 14_827_000 picoseconds. + Weight::from_parts(15_273_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -113,13 +111,13 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Uniques::Asset` (r:1001 w:1000) /// Proof: `Uniques::Asset` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) /// Storage: `Uniques::InstanceMetadataOf` (r:1000 w:1000) - /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) + /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) /// Storage: `Uniques::Attribute` (r:1000 w:1000) - /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(172), added: 2647, mode: `MaxEncodedLen`) + /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(364), added: 2839, mode: `MaxEncodedLen`) /// Storage: `Uniques::ClassAccount` (r:0 w:1) /// Proof: `Uniques::ClassAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) /// Storage: `Uniques::ClassMetadataOf` (r:0 w:1) - /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(167), added: 2642, mode: `MaxEncodedLen`) + /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Uniques::Account` (r:0 w:1000) /// Proof: `Uniques::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Uniques::CollectionMaxSupply` (r:0 w:1) @@ -130,15 +128,15 @@ impl WeightInfo for SubstrateWeight { fn destroy(n: u32, m: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `418 + a * (107 ±0) + m * (56 ±0) + n * (76 ±0)` - // Estimated: `3643 + a * (2647 ±0) + m * (2662 ±0) + n * (2597 ±0)` - // Minimum execution time: 2_979_858_000 picoseconds. - Weight::from_parts(3_007_268_000, 3643) - // Standard Error: 29_899 - .saturating_add(Weight::from_parts(6_943_612, 0).saturating_mul(n.into())) - // Standard Error: 29_899 - .saturating_add(Weight::from_parts(398_114, 0).saturating_mul(m.into())) - // Standard Error: 29_899 - .saturating_add(Weight::from_parts(369_941, 0).saturating_mul(a.into())) + // Estimated: `3643 + a * (2839 ±0) + m * (2583 ±0) + n * (2597 ±0)` + // Minimum execution time: 3_281_673_000 picoseconds. + Weight::from_parts(3_443_387_000, 3643) + // Standard Error: 41_937 + .saturating_add(Weight::from_parts(7_914_842, 0).saturating_mul(n.into())) + // Standard Error: 41_937 + .saturating_add(Weight::from_parts(519_960, 0).saturating_mul(m.into())) + // Standard Error: 41_937 + .saturating_add(Weight::from_parts(462_690, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) @@ -147,8 +145,8 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(m.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) - .saturating_add(Weight::from_parts(0, 2647).saturating_mul(a.into())) - .saturating_add(Weight::from_parts(0, 2662).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 2839).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(0, 2583).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 2597).saturating_mul(n.into())) } /// Storage: `Uniques::Asset` (r:1 w:1) @@ -163,8 +161,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 32_733_000 picoseconds. - Weight::from_parts(33_487_000, 3643) + // Minimum execution time: 38_122_000 picoseconds. + Weight::from_parts(38_924_000, 3643) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -180,8 +178,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3643` - // Minimum execution time: 34_202_000 picoseconds. - Weight::from_parts(35_146_000, 3643) + // Minimum execution time: 38_835_000 picoseconds. + Weight::from_parts(39_754_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -197,8 +195,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3643` - // Minimum execution time: 24_285_000 picoseconds. - Weight::from_parts(25_300_000, 3643) + // Minimum execution time: 27_032_000 picoseconds. + Weight::from_parts(27_793_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -211,10 +209,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `805 + i * (76 ±0)` // Estimated: `3643 + i * (2597 ±0)` - // Minimum execution time: 11_641_000 picoseconds. - Weight::from_parts(12_261_000, 3643) - // Standard Error: 18_897 - .saturating_add(Weight::from_parts(15_263_570, 0).saturating_mul(i.into())) + // Minimum execution time: 14_737_000 picoseconds. + Weight::from_parts(15_070_000, 3643) + // Standard Error: 22_500 + .saturating_add(Weight::from_parts(18_855_468, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -229,8 +227,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3643` - // Minimum execution time: 16_122_000 picoseconds. - Weight::from_parts(16_627_000, 3643) + // Minimum execution time: 18_664_000 picoseconds. + Weight::from_parts(19_455_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -242,8 +240,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3643` - // Minimum execution time: 15_824_000 picoseconds. - Weight::from_parts(16_522_000, 3643) + // Minimum execution time: 18_247_000 picoseconds. + Weight::from_parts(18_763_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -253,8 +251,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 10_802_000 picoseconds. - Weight::from_parts(11_206_000, 3643) + // Minimum execution time: 13_219_000 picoseconds. + Weight::from_parts(13_923_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -264,8 +262,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 10_805_000 picoseconds. - Weight::from_parts(11_340_000, 3643) + // Minimum execution time: 13_376_000 picoseconds. + Weight::from_parts(13_904_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -273,18 +271,16 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Uniques::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Uniques::ClassAccount` (r:0 w:2) /// Proof: `Uniques::ClassAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `597` + // Measured: `423` // Estimated: `3643` - // Minimum execution time: 24_213_000 picoseconds. - Weight::from_parts(25_547_000, 3643) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(5_u64)) + // Minimum execution time: 22_353_000 picoseconds. + Weight::from_parts(23_222_000, 3643) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) @@ -292,8 +288,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 11_256_000 picoseconds. - Weight::from_parts(11_585_000, 3643) + // Minimum execution time: 14_072_000 picoseconds. + Weight::from_parts(14_619_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -305,90 +301,90 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 14_616_000 picoseconds. - Weight::from_parts(15_064_000, 3643) + // Minimum execution time: 17_081_000 picoseconds. + Weight::from_parts(17_698_000, 3643) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) /// Storage: `Uniques::InstanceMetadataOf` (r:1 w:0) - /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) + /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) /// Storage: `Uniques::Attribute` (r:1 w:1) - /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(172), added: 2647, mode: `MaxEncodedLen`) + /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(364), added: 2839, mode: `MaxEncodedLen`) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `626` - // Estimated: `3652` - // Minimum execution time: 35_640_000 picoseconds. - Weight::from_parts(37_007_000, 3652) + // Measured: `547` + // Estimated: `3829` + // Minimum execution time: 41_501_000 picoseconds. + Weight::from_parts(43_101_000, 3829) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) /// Storage: `Uniques::InstanceMetadataOf` (r:1 w:0) - /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) + /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) /// Storage: `Uniques::Attribute` (r:1 w:1) - /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(172), added: 2647, mode: `MaxEncodedLen`) + /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(364), added: 2839, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `823` - // Estimated: `3652` - // Minimum execution time: 34_410_000 picoseconds. - Weight::from_parts(35_431_000, 3652) + // Measured: `936` + // Estimated: `3829` + // Minimum execution time: 39_722_000 picoseconds. + Weight::from_parts(40_390_000, 3829) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) /// Storage: `Uniques::InstanceMetadataOf` (r:1 w:1) - /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) + /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) fn set_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `415` - // Estimated: `3652` - // Minimum execution time: 26_187_000 picoseconds. - Weight::from_parts(27_837_000, 3652) + // Estimated: `3643` + // Minimum execution time: 30_726_000 picoseconds. + Weight::from_parts(31_557_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) /// Storage: `Uniques::InstanceMetadataOf` (r:1 w:1) - /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) + /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `626` - // Estimated: `3652` - // Minimum execution time: 26_640_000 picoseconds. - Weight::from_parts(27_688_000, 3652) + // Measured: `547` + // Estimated: `3643` + // Minimum execution time: 31_303_000 picoseconds. + Weight::from_parts(32_389_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) /// Storage: `Uniques::ClassMetadataOf` (r:1 w:1) - /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(167), added: 2642, mode: `MaxEncodedLen`) + /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 26_781_000 picoseconds. - Weight::from_parts(27_628_000, 3643) + // Minimum execution time: 32_155_000 picoseconds. + Weight::from_parts(32_885_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Uniques::Class` (r:1 w:0) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) /// Storage: `Uniques::ClassMetadataOf` (r:1 w:1) - /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(167), added: 2642, mode: `MaxEncodedLen`) + /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `540` + // Measured: `461` // Estimated: `3643` - // Minimum execution time: 26_295_000 picoseconds. - Weight::from_parts(26_903_000, 3643) + // Minimum execution time: 30_044_000 picoseconds. + Weight::from_parts(31_405_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -400,8 +396,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3643` - // Minimum execution time: 16_678_000 picoseconds. - Weight::from_parts(17_548_000, 3643) + // Minimum execution time: 18_904_000 picoseconds. + Weight::from_parts(19_687_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -413,8 +409,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `528` // Estimated: `3643` - // Minimum execution time: 16_408_000 picoseconds. - Weight::from_parts(16_957_000, 3643) + // Minimum execution time: 19_144_000 picoseconds. + Weight::from_parts(19_706_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -424,8 +420,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3517` - // Minimum execution time: 12_568_000 picoseconds. - Weight::from_parts(12_960_000, 3517) + // Minimum execution time: 15_339_000 picoseconds. + Weight::from_parts(15_918_000, 3517) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -437,8 +433,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 13_110_000 picoseconds. - Weight::from_parts(13_620_000, 3643) + // Minimum execution time: 15_387_000 picoseconds. + Weight::from_parts(15_726_000, 3643) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -450,8 +446,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `326` // Estimated: `3587` - // Minimum execution time: 13_568_000 picoseconds. - Weight::from_parts(14_211_000, 3587) + // Minimum execution time: 15_873_000 picoseconds. + Weight::from_parts(16_860_000, 3587) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -467,8 +463,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `607` // Estimated: `3643` - // Minimum execution time: 32_660_000 picoseconds. - Weight::from_parts(33_734_000, 3643) + // Minimum execution time: 37_245_000 picoseconds. + Weight::from_parts(38_383_000, 3643) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -484,8 +480,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `249` // Estimated: `3643` - // Minimum execution time: 27_960_000 picoseconds. - Weight::from_parts(28_781_000, 3643) + // Minimum execution time: 31_393_000 picoseconds. + Weight::from_parts(32_933_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -497,8 +493,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3643` - // Minimum execution time: 11_970_000 picoseconds. - Weight::from_parts(12_512_000, 3643) + // Minimum execution time: 14_827_000 picoseconds. + Weight::from_parts(15_273_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -507,13 +503,13 @@ impl WeightInfo for () { /// Storage: `Uniques::Asset` (r:1001 w:1000) /// Proof: `Uniques::Asset` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) /// Storage: `Uniques::InstanceMetadataOf` (r:1000 w:1000) - /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) + /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) /// Storage: `Uniques::Attribute` (r:1000 w:1000) - /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(172), added: 2647, mode: `MaxEncodedLen`) + /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(364), added: 2839, mode: `MaxEncodedLen`) /// Storage: `Uniques::ClassAccount` (r:0 w:1) /// Proof: `Uniques::ClassAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) /// Storage: `Uniques::ClassMetadataOf` (r:0 w:1) - /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(167), added: 2642, mode: `MaxEncodedLen`) + /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Uniques::Account` (r:0 w:1000) /// Proof: `Uniques::Account` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) /// Storage: `Uniques::CollectionMaxSupply` (r:0 w:1) @@ -524,15 +520,15 @@ impl WeightInfo for () { fn destroy(n: u32, m: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `418 + a * (107 ±0) + m * (56 ±0) + n * (76 ±0)` - // Estimated: `3643 + a * (2647 ±0) + m * (2662 ±0) + n * (2597 ±0)` - // Minimum execution time: 2_979_858_000 picoseconds. - Weight::from_parts(3_007_268_000, 3643) - // Standard Error: 29_899 - .saturating_add(Weight::from_parts(6_943_612, 0).saturating_mul(n.into())) - // Standard Error: 29_899 - .saturating_add(Weight::from_parts(398_114, 0).saturating_mul(m.into())) - // Standard Error: 29_899 - .saturating_add(Weight::from_parts(369_941, 0).saturating_mul(a.into())) + // Estimated: `3643 + a * (2839 ±0) + m * (2583 ±0) + n * (2597 ±0)` + // Minimum execution time: 3_281_673_000 picoseconds. + Weight::from_parts(3_443_387_000, 3643) + // Standard Error: 41_937 + .saturating_add(Weight::from_parts(7_914_842, 0).saturating_mul(n.into())) + // Standard Error: 41_937 + .saturating_add(Weight::from_parts(519_960, 0).saturating_mul(m.into())) + // Standard Error: 41_937 + .saturating_add(Weight::from_parts(462_690, 0).saturating_mul(a.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(m.into()))) @@ -541,8 +537,8 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(m.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(a.into()))) - .saturating_add(Weight::from_parts(0, 2647).saturating_mul(a.into())) - .saturating_add(Weight::from_parts(0, 2662).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 2839).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(0, 2583).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 2597).saturating_mul(n.into())) } /// Storage: `Uniques::Asset` (r:1 w:1) @@ -557,8 +553,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 32_733_000 picoseconds. - Weight::from_parts(33_487_000, 3643) + // Minimum execution time: 38_122_000 picoseconds. + Weight::from_parts(38_924_000, 3643) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -574,8 +570,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3643` - // Minimum execution time: 34_202_000 picoseconds. - Weight::from_parts(35_146_000, 3643) + // Minimum execution time: 38_835_000 picoseconds. + Weight::from_parts(39_754_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -591,8 +587,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3643` - // Minimum execution time: 24_285_000 picoseconds. - Weight::from_parts(25_300_000, 3643) + // Minimum execution time: 27_032_000 picoseconds. + Weight::from_parts(27_793_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -605,10 +601,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `805 + i * (76 ±0)` // Estimated: `3643 + i * (2597 ±0)` - // Minimum execution time: 11_641_000 picoseconds. - Weight::from_parts(12_261_000, 3643) - // Standard Error: 18_897 - .saturating_add(Weight::from_parts(15_263_570, 0).saturating_mul(i.into())) + // Minimum execution time: 14_737_000 picoseconds. + Weight::from_parts(15_070_000, 3643) + // Standard Error: 22_500 + .saturating_add(Weight::from_parts(18_855_468, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -623,8 +619,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3643` - // Minimum execution time: 16_122_000 picoseconds. - Weight::from_parts(16_627_000, 3643) + // Minimum execution time: 18_664_000 picoseconds. + Weight::from_parts(19_455_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -636,8 +632,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3643` - // Minimum execution time: 15_824_000 picoseconds. - Weight::from_parts(16_522_000, 3643) + // Minimum execution time: 18_247_000 picoseconds. + Weight::from_parts(18_763_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -647,8 +643,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 10_802_000 picoseconds. - Weight::from_parts(11_206_000, 3643) + // Minimum execution time: 13_219_000 picoseconds. + Weight::from_parts(13_923_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -658,8 +654,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 10_805_000 picoseconds. - Weight::from_parts(11_340_000, 3643) + // Minimum execution time: 13_376_000 picoseconds. + Weight::from_parts(13_904_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -667,18 +663,16 @@ impl WeightInfo for () { /// Proof: `Uniques::OwnershipAcceptance` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Uniques::ClassAccount` (r:0 w:2) /// Proof: `Uniques::ClassAccount` (`max_values`: None, `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `597` + // Measured: `423` // Estimated: `3643` - // Minimum execution time: 24_213_000 picoseconds. - Weight::from_parts(25_547_000, 3643) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(5_u64)) + // Minimum execution time: 22_353_000 picoseconds. + Weight::from_parts(23_222_000, 3643) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) @@ -686,8 +680,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 11_256_000 picoseconds. - Weight::from_parts(11_585_000, 3643) + // Minimum execution time: 14_072_000 picoseconds. + Weight::from_parts(14_619_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -699,90 +693,90 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 14_616_000 picoseconds. - Weight::from_parts(15_064_000, 3643) + // Minimum execution time: 17_081_000 picoseconds. + Weight::from_parts(17_698_000, 3643) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) /// Storage: `Uniques::InstanceMetadataOf` (r:1 w:0) - /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) + /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) /// Storage: `Uniques::Attribute` (r:1 w:1) - /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(172), added: 2647, mode: `MaxEncodedLen`) + /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(364), added: 2839, mode: `MaxEncodedLen`) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `626` - // Estimated: `3652` - // Minimum execution time: 35_640_000 picoseconds. - Weight::from_parts(37_007_000, 3652) + // Measured: `547` + // Estimated: `3829` + // Minimum execution time: 41_501_000 picoseconds. + Weight::from_parts(43_101_000, 3829) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) /// Storage: `Uniques::InstanceMetadataOf` (r:1 w:0) - /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) + /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) /// Storage: `Uniques::Attribute` (r:1 w:1) - /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(172), added: 2647, mode: `MaxEncodedLen`) + /// Proof: `Uniques::Attribute` (`max_values`: None, `max_size`: Some(364), added: 2839, mode: `MaxEncodedLen`) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `823` - // Estimated: `3652` - // Minimum execution time: 34_410_000 picoseconds. - Weight::from_parts(35_431_000, 3652) + // Measured: `936` + // Estimated: `3829` + // Minimum execution time: 39_722_000 picoseconds. + Weight::from_parts(40_390_000, 3829) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) /// Storage: `Uniques::InstanceMetadataOf` (r:1 w:1) - /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) + /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) fn set_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `415` - // Estimated: `3652` - // Minimum execution time: 26_187_000 picoseconds. - Weight::from_parts(27_837_000, 3652) + // Estimated: `3643` + // Minimum execution time: 30_726_000 picoseconds. + Weight::from_parts(31_557_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) /// Storage: `Uniques::InstanceMetadataOf` (r:1 w:1) - /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(187), added: 2662, mode: `MaxEncodedLen`) + /// Proof: `Uniques::InstanceMetadataOf` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `626` - // Estimated: `3652` - // Minimum execution time: 26_640_000 picoseconds. - Weight::from_parts(27_688_000, 3652) + // Measured: `547` + // Estimated: `3643` + // Minimum execution time: 31_303_000 picoseconds. + Weight::from_parts(32_389_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Uniques::Class` (r:1 w:1) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) /// Storage: `Uniques::ClassMetadataOf` (r:1 w:1) - /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(167), added: 2642, mode: `MaxEncodedLen`) + /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn set_collection_metadata() -> Weight { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 26_781_000 picoseconds. - Weight::from_parts(27_628_000, 3643) + // Minimum execution time: 32_155_000 picoseconds. + Weight::from_parts(32_885_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Uniques::Class` (r:1 w:0) /// Proof: `Uniques::Class` (`max_values`: None, `max_size`: Some(178), added: 2653, mode: `MaxEncodedLen`) /// Storage: `Uniques::ClassMetadataOf` (r:1 w:1) - /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(167), added: 2642, mode: `MaxEncodedLen`) + /// Proof: `Uniques::ClassMetadataOf` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) fn clear_collection_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `540` + // Measured: `461` // Estimated: `3643` - // Minimum execution time: 26_295_000 picoseconds. - Weight::from_parts(26_903_000, 3643) + // Minimum execution time: 30_044_000 picoseconds. + Weight::from_parts(31_405_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -794,8 +788,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3643` - // Minimum execution time: 16_678_000 picoseconds. - Weight::from_parts(17_548_000, 3643) + // Minimum execution time: 18_904_000 picoseconds. + Weight::from_parts(19_687_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -807,8 +801,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `528` // Estimated: `3643` - // Minimum execution time: 16_408_000 picoseconds. - Weight::from_parts(16_957_000, 3643) + // Minimum execution time: 19_144_000 picoseconds. + Weight::from_parts(19_706_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -818,8 +812,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3517` - // Minimum execution time: 12_568_000 picoseconds. - Weight::from_parts(12_960_000, 3517) + // Minimum execution time: 15_339_000 picoseconds. + Weight::from_parts(15_918_000, 3517) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -831,8 +825,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `349` // Estimated: `3643` - // Minimum execution time: 13_110_000 picoseconds. - Weight::from_parts(13_620_000, 3643) + // Minimum execution time: 15_387_000 picoseconds. + Weight::from_parts(15_726_000, 3643) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -844,8 +838,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `326` // Estimated: `3587` - // Minimum execution time: 13_568_000 picoseconds. - Weight::from_parts(14_211_000, 3587) + // Minimum execution time: 15_873_000 picoseconds. + Weight::from_parts(16_860_000, 3587) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -861,8 +855,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `607` // Estimated: `3643` - // Minimum execution time: 32_660_000 picoseconds. - Weight::from_parts(33_734_000, 3643) + // Minimum execution time: 37_245_000 picoseconds. + Weight::from_parts(38_383_000, 3643) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } diff --git a/substrate/frame/utility/src/weights.rs b/substrate/frame/utility/src/weights.rs index 60b1c48f086..1a3ea6c1f7f 100644 --- a/substrate/frame/utility/src/weights.rs +++ b/substrate/frame/utility/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_utility` +//! Autogenerated weights for pallet_utility //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/utility/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/utility/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_utility`. +/// Weight functions needed for pallet_utility. pub trait WeightInfo { fn batch(c: u32, ) -> Weight; fn as_derivative() -> Weight; @@ -58,139 +59,99 @@ pub trait WeightInfo { fn force_batch(c: u32, ) -> Weight; } -/// Weights for `pallet_utility` using the Substrate node and recommended hardware. +/// Weights for pallet_utility using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) /// The range of component `c` is `[0, 1000]`. fn batch(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `145` - // Estimated: `3997` - // Minimum execution time: 5_143_000 picoseconds. - Weight::from_parts(11_552_299, 3997) - // Standard Error: 2_325 - .saturating_add(Weight::from_parts(4_708_951, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_763_000 picoseconds. + Weight::from_parts(16_943_157, 0) + // Standard Error: 1_904 + .saturating_add(Weight::from_parts(4_653_855, 0).saturating_mul(c.into())) } - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) fn as_derivative() -> Weight { // Proof Size summary in bytes: - // Measured: `145` - // Estimated: `3997` - // Minimum execution time: 9_103_000 picoseconds. - Weight::from_parts(9_549_000, 3997) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_149_000 picoseconds. + Weight::from_parts(5_268_000, 0) } - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) /// The range of component `c` is `[0, 1000]`. fn batch_all(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `145` - // Estimated: `3997` - // Minimum execution time: 5_147_000 picoseconds. - Weight::from_parts(15_698_086, 3997) - // Standard Error: 3_066 - .saturating_add(Weight::from_parts(4_809_412, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_976_000 picoseconds. + Weight::from_parts(16_448_433, 0) + // Standard Error: 1_834 + .saturating_add(Weight::from_parts(4_796_983, 0).saturating_mul(c.into())) } fn dispatch_as() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_683_000 picoseconds. - Weight::from_parts(7_047_000, 0) + // Minimum execution time: 9_102_000 picoseconds. + Weight::from_parts(9_353_000, 0) } - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) /// The range of component `c` is `[0, 1000]`. fn force_batch(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `145` - // Estimated: `3997` - // Minimum execution time: 4_982_000 picoseconds. - Weight::from_parts(14_474_780, 3997) - // Standard Error: 2_291 - .saturating_add(Weight::from_parts(4_632_643, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_840_000 picoseconds. + Weight::from_parts(17_748_474, 0) + // Standard Error: 2_059 + .saturating_add(Weight::from_parts(4_630_079, 0).saturating_mul(c.into())) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) /// The range of component `c` is `[0, 1000]`. fn batch(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `145` - // Estimated: `3997` - // Minimum execution time: 5_143_000 picoseconds. - Weight::from_parts(11_552_299, 3997) - // Standard Error: 2_325 - .saturating_add(Weight::from_parts(4_708_951, 0).saturating_mul(c.into())) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_763_000 picoseconds. + Weight::from_parts(16_943_157, 0) + // Standard Error: 1_904 + .saturating_add(Weight::from_parts(4_653_855, 0).saturating_mul(c.into())) } - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) fn as_derivative() -> Weight { // Proof Size summary in bytes: - // Measured: `145` - // Estimated: `3997` - // Minimum execution time: 9_103_000 picoseconds. - Weight::from_parts(9_549_000, 3997) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_149_000 picoseconds. + Weight::from_parts(5_268_000, 0) } - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) /// The range of component `c` is `[0, 1000]`. fn batch_all(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `145` - // Estimated: `3997` - // Minimum execution time: 5_147_000 picoseconds. - Weight::from_parts(15_698_086, 3997) - // Standard Error: 3_066 - .saturating_add(Weight::from_parts(4_809_412, 0).saturating_mul(c.into())) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_976_000 picoseconds. + Weight::from_parts(16_448_433, 0) + // Standard Error: 1_834 + .saturating_add(Weight::from_parts(4_796_983, 0).saturating_mul(c.into())) } fn dispatch_as() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_683_000 picoseconds. - Weight::from_parts(7_047_000, 0) + // Minimum execution time: 9_102_000 picoseconds. + Weight::from_parts(9_353_000, 0) } - /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) - /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) /// The range of component `c` is `[0, 1000]`. fn force_batch(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `145` - // Estimated: `3997` - // Minimum execution time: 4_982_000 picoseconds. - Weight::from_parts(14_474_780, 3997) - // Standard Error: 2_291 - .saturating_add(Weight::from_parts(4_632_643, 0).saturating_mul(c.into())) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_840_000 picoseconds. + Weight::from_parts(17_748_474, 0) + // Standard Error: 2_059 + .saturating_add(Weight::from_parts(4_630_079, 0).saturating_mul(c.into())) } } diff --git a/substrate/frame/vesting/src/weights.rs b/substrate/frame/vesting/src/weights.rs index d91c47ae195..ddc7db8fa61 100644 --- a/substrate/frame/vesting/src/weights.rs +++ b/substrate/frame/vesting/src/weights.rs @@ -17,28 +17,26 @@ //! Autogenerated weights for `pallet_vesting` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-10-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/production/substrate-node +// target/production/substrate-node // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_vesting -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/vesting/src/weights.rs +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_vesting +// --chain=dev // --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/vesting/src/weights.rs // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -77,12 +75,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `381 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 31_890_000 picoseconds. - Weight::from_parts(31_128_476, 4764) - // Standard Error: 1_193 - .saturating_add(Weight::from_parts(63_760, 0).saturating_mul(l.into())) - // Standard Error: 2_124 - .saturating_add(Weight::from_parts(57_247, 0).saturating_mul(s.into())) + // Minimum execution time: 32_846_000 picoseconds. + Weight::from_parts(30_974_459, 4764) + // Standard Error: 1_755 + .saturating_add(Weight::from_parts(73_138, 0).saturating_mul(l.into())) + // Standard Error: 3_123 + .saturating_add(Weight::from_parts(82_417, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -98,12 +96,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `381 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 33_958_000 picoseconds. - Weight::from_parts(33_537_005, 4764) - // Standard Error: 1_354 - .saturating_add(Weight::from_parts(60_604, 0).saturating_mul(l.into())) - // Standard Error: 2_410 - .saturating_add(Weight::from_parts(51_378, 0).saturating_mul(s.into())) + // Minimum execution time: 34_360_000 picoseconds. + Weight::from_parts(34_964_080, 4764) + // Standard Error: 1_996 + .saturating_add(Weight::from_parts(48_024, 0).saturating_mul(l.into())) + // Standard Error: 3_552 + .saturating_add(Weight::from_parts(34_411, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -121,12 +119,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `484 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 33_243_000 picoseconds. - Weight::from_parts(32_552_805, 4764) - // Standard Error: 1_413 - .saturating_add(Weight::from_parts(67_137, 0).saturating_mul(l.into())) - // Standard Error: 2_515 - .saturating_add(Weight::from_parts(70_000, 0).saturating_mul(s.into())) + // Minimum execution time: 33_859_000 picoseconds. + Weight::from_parts(32_950_681, 4764) + // Standard Error: 1_745 + .saturating_add(Weight::from_parts(69_323, 0).saturating_mul(l.into())) + // Standard Error: 3_105 + .saturating_add(Weight::from_parts(86_370, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -144,12 +142,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `484 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 35_396_000 picoseconds. - Weight::from_parts(35_774_949, 4764) - // Standard Error: 1_404 - .saturating_add(Weight::from_parts(55_349, 0).saturating_mul(l.into())) - // Standard Error: 2_497 - .saturating_add(Weight::from_parts(39_228, 0).saturating_mul(s.into())) + // Minimum execution time: 36_239_000 picoseconds. + Weight::from_parts(36_459_756, 4764) + // Standard Error: 2_051 + .saturating_add(Weight::from_parts(56_670, 0).saturating_mul(l.into())) + // Standard Error: 3_650 + .saturating_add(Weight::from_parts(49_663, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -167,12 +165,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `555 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 68_441_000 picoseconds. - Weight::from_parts(68_961_970, 4764) - // Standard Error: 2_509 - .saturating_add(Weight::from_parts(83_345, 0).saturating_mul(l.into())) - // Standard Error: 4_464 - .saturating_add(Weight::from_parts(124_158, 0).saturating_mul(s.into())) + // Minimum execution time: 70_330_000 picoseconds. + Weight::from_parts(71_196_328, 4764) + // Standard Error: 2_923 + .saturating_add(Weight::from_parts(67_238, 0).saturating_mul(l.into())) + // Standard Error: 5_201 + .saturating_add(Weight::from_parts(89_102, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -190,12 +188,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `658 + l * (25 ±0) + s * (36 ±0)` // Estimated: `6196` - // Minimum execution time: 70_190_000 picoseconds. - Weight::from_parts(72_355_984, 6196) - // Standard Error: 2_295 - .saturating_add(Weight::from_parts(59_968, 0).saturating_mul(l.into())) - // Standard Error: 4_084 - .saturating_add(Weight::from_parts(87_090, 0).saturating_mul(s.into())) + // Minimum execution time: 70_235_000 picoseconds. + Weight::from_parts(71_960_020, 6196) + // Standard Error: 2_493 + .saturating_add(Weight::from_parts(64_835, 0).saturating_mul(l.into())) + // Standard Error: 4_436 + .saturating_add(Weight::from_parts(102_159, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -213,12 +211,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `482 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 33_911_000 picoseconds. - Weight::from_parts(33_243_006, 4764) - // Standard Error: 1_199 - .saturating_add(Weight::from_parts(70_586, 0).saturating_mul(l.into())) - // Standard Error: 2_214 - .saturating_add(Weight::from_parts(60_985, 0).saturating_mul(s.into())) + // Minimum execution time: 34_352_000 picoseconds. + Weight::from_parts(33_697_027, 4764) + // Standard Error: 2_008 + .saturating_add(Weight::from_parts(79_270, 0).saturating_mul(l.into())) + // Standard Error: 3_710 + .saturating_add(Weight::from_parts(60_691, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -236,12 +234,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `482 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 36_242_000 picoseconds. - Weight::from_parts(35_812_994, 4764) - // Standard Error: 1_351 - .saturating_add(Weight::from_parts(68_256, 0).saturating_mul(l.into())) - // Standard Error: 2_496 - .saturating_add(Weight::from_parts(66_171, 0).saturating_mul(s.into())) + // Minimum execution time: 37_467_000 picoseconds. + Weight::from_parts(36_866_847, 4764) + // Standard Error: 1_692 + .saturating_add(Weight::from_parts(57_882, 0).saturating_mul(l.into())) + // Standard Error: 3_124 + .saturating_add(Weight::from_parts(80_266, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -259,12 +257,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `555 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 37_817_000 picoseconds. - Weight::from_parts(37_397_127, 4764) - // Standard Error: 1_665 - .saturating_add(Weight::from_parts(72_049, 0).saturating_mul(l.into())) - // Standard Error: 3_075 - .saturating_add(Weight::from_parts(60_973, 0).saturating_mul(s.into())) + // Minimum execution time: 41_497_000 picoseconds. + Weight::from_parts(38_763_834, 4764) + // Standard Error: 2_030 + .saturating_add(Weight::from_parts(99_580, 0).saturating_mul(l.into())) + // Standard Error: 3_750 + .saturating_add(Weight::from_parts(132_188, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -284,12 +282,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `381 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 31_890_000 picoseconds. - Weight::from_parts(31_128_476, 4764) - // Standard Error: 1_193 - .saturating_add(Weight::from_parts(63_760, 0).saturating_mul(l.into())) - // Standard Error: 2_124 - .saturating_add(Weight::from_parts(57_247, 0).saturating_mul(s.into())) + // Minimum execution time: 32_846_000 picoseconds. + Weight::from_parts(30_974_459, 4764) + // Standard Error: 1_755 + .saturating_add(Weight::from_parts(73_138, 0).saturating_mul(l.into())) + // Standard Error: 3_123 + .saturating_add(Weight::from_parts(82_417, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -305,12 +303,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `381 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 33_958_000 picoseconds. - Weight::from_parts(33_537_005, 4764) - // Standard Error: 1_354 - .saturating_add(Weight::from_parts(60_604, 0).saturating_mul(l.into())) - // Standard Error: 2_410 - .saturating_add(Weight::from_parts(51_378, 0).saturating_mul(s.into())) + // Minimum execution time: 34_360_000 picoseconds. + Weight::from_parts(34_964_080, 4764) + // Standard Error: 1_996 + .saturating_add(Weight::from_parts(48_024, 0).saturating_mul(l.into())) + // Standard Error: 3_552 + .saturating_add(Weight::from_parts(34_411, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -328,12 +326,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `484 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 33_243_000 picoseconds. - Weight::from_parts(32_552_805, 4764) - // Standard Error: 1_413 - .saturating_add(Weight::from_parts(67_137, 0).saturating_mul(l.into())) - // Standard Error: 2_515 - .saturating_add(Weight::from_parts(70_000, 0).saturating_mul(s.into())) + // Minimum execution time: 33_859_000 picoseconds. + Weight::from_parts(32_950_681, 4764) + // Standard Error: 1_745 + .saturating_add(Weight::from_parts(69_323, 0).saturating_mul(l.into())) + // Standard Error: 3_105 + .saturating_add(Weight::from_parts(86_370, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -351,12 +349,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `484 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 35_396_000 picoseconds. - Weight::from_parts(35_774_949, 4764) - // Standard Error: 1_404 - .saturating_add(Weight::from_parts(55_349, 0).saturating_mul(l.into())) - // Standard Error: 2_497 - .saturating_add(Weight::from_parts(39_228, 0).saturating_mul(s.into())) + // Minimum execution time: 36_239_000 picoseconds. + Weight::from_parts(36_459_756, 4764) + // Standard Error: 2_051 + .saturating_add(Weight::from_parts(56_670, 0).saturating_mul(l.into())) + // Standard Error: 3_650 + .saturating_add(Weight::from_parts(49_663, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -374,12 +372,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `555 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 68_441_000 picoseconds. - Weight::from_parts(68_961_970, 4764) - // Standard Error: 2_509 - .saturating_add(Weight::from_parts(83_345, 0).saturating_mul(l.into())) - // Standard Error: 4_464 - .saturating_add(Weight::from_parts(124_158, 0).saturating_mul(s.into())) + // Minimum execution time: 70_330_000 picoseconds. + Weight::from_parts(71_196_328, 4764) + // Standard Error: 2_923 + .saturating_add(Weight::from_parts(67_238, 0).saturating_mul(l.into())) + // Standard Error: 5_201 + .saturating_add(Weight::from_parts(89_102, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -397,12 +395,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `658 + l * (25 ±0) + s * (36 ±0)` // Estimated: `6196` - // Minimum execution time: 70_190_000 picoseconds. - Weight::from_parts(72_355_984, 6196) - // Standard Error: 2_295 - .saturating_add(Weight::from_parts(59_968, 0).saturating_mul(l.into())) - // Standard Error: 4_084 - .saturating_add(Weight::from_parts(87_090, 0).saturating_mul(s.into())) + // Minimum execution time: 70_235_000 picoseconds. + Weight::from_parts(71_960_020, 6196) + // Standard Error: 2_493 + .saturating_add(Weight::from_parts(64_835, 0).saturating_mul(l.into())) + // Standard Error: 4_436 + .saturating_add(Weight::from_parts(102_159, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -420,12 +418,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `482 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 33_911_000 picoseconds. - Weight::from_parts(33_243_006, 4764) - // Standard Error: 1_199 - .saturating_add(Weight::from_parts(70_586, 0).saturating_mul(l.into())) - // Standard Error: 2_214 - .saturating_add(Weight::from_parts(60_985, 0).saturating_mul(s.into())) + // Minimum execution time: 34_352_000 picoseconds. + Weight::from_parts(33_697_027, 4764) + // Standard Error: 2_008 + .saturating_add(Weight::from_parts(79_270, 0).saturating_mul(l.into())) + // Standard Error: 3_710 + .saturating_add(Weight::from_parts(60_691, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -443,12 +441,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `482 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 36_242_000 picoseconds. - Weight::from_parts(35_812_994, 4764) - // Standard Error: 1_351 - .saturating_add(Weight::from_parts(68_256, 0).saturating_mul(l.into())) - // Standard Error: 2_496 - .saturating_add(Weight::from_parts(66_171, 0).saturating_mul(s.into())) + // Minimum execution time: 37_467_000 picoseconds. + Weight::from_parts(36_866_847, 4764) + // Standard Error: 1_692 + .saturating_add(Weight::from_parts(57_882, 0).saturating_mul(l.into())) + // Standard Error: 3_124 + .saturating_add(Weight::from_parts(80_266, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -466,12 +464,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `555 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 37_817_000 picoseconds. - Weight::from_parts(37_397_127, 4764) - // Standard Error: 1_665 - .saturating_add(Weight::from_parts(72_049, 0).saturating_mul(l.into())) - // Standard Error: 3_075 - .saturating_add(Weight::from_parts(60_973, 0).saturating_mul(s.into())) + // Minimum execution time: 41_497_000 picoseconds. + Weight::from_parts(38_763_834, 4764) + // Standard Error: 2_030 + .saturating_add(Weight::from_parts(99_580, 0).saturating_mul(l.into())) + // Standard Error: 3_750 + .saturating_add(Weight::from_parts(132_188, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } diff --git a/substrate/frame/whitelist/src/weights.rs b/substrate/frame/whitelist/src/weights.rs index 13b653f6ca7..de42c5a5841 100644 --- a/substrate/frame/whitelist/src/weights.rs +++ b/substrate/frame/whitelist/src/weights.rs @@ -15,16 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_whitelist` +//! Autogenerated weights for pallet_whitelist //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `runner-e8ezs4ez-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate-node +// ./target/production/substrate // benchmark // pallet // --chain=dev @@ -35,11 +35,12 @@ // --no-median-slopes // --no-min-squares // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/whitelist/src/weights.rs -// --header=./substrate/HEADER-APACHE2 -// --template=./substrate/.maintain/frame-weight-template.hbs +// --output=./frame/whitelist/src/weights.rs +// --header=./HEADER-APACHE2 +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_whitelist`. +/// Weight functions needed for pallet_whitelist. pub trait WeightInfo { fn whitelist_call() -> Weight; fn remove_whitelisted_call() -> Weight; @@ -57,149 +58,133 @@ pub trait WeightInfo { fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight; } -/// Weights for `pallet_whitelist` using the Substrate node and recommended hardware. +/// Weights for pallet_whitelist using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) - /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: Whitelist WhitelistedCall (r:1 w:1) + /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn whitelist_call() -> Weight { // Proof Size summary in bytes: - // Measured: `317` + // Measured: `217` // Estimated: `3556` - // Minimum execution time: 18_503_000 picoseconds. - Weight::from_parts(19_497_000, 3556) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Minimum execution time: 19_914_000 picoseconds. + Weight::from_parts(20_892_000, 3556) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) - /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: Whitelist WhitelistedCall (r:1 w:1) + /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn remove_whitelisted_call() -> Weight { // Proof Size summary in bytes: - // Measured: `446` + // Measured: `346` // Estimated: `3556` - // Minimum execution time: 17_633_000 picoseconds. - Weight::from_parts(18_196_000, 3556) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Minimum execution time: 18_142_000 picoseconds. + Weight::from_parts(18_529_000, 3556) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) - /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) - /// Storage: `Preimage::PreimageFor` (r:1 w:1) - /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `Measured`) - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: Whitelist WhitelistedCall (r:1 w:1) + /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:1 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: Measured) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) /// The range of component `n` is `[1, 4194294]`. fn dispatch_whitelisted_call(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `522 + n * (1 ±0)` - // Estimated: `3986 + n * (1 ±0)` - // Minimum execution time: 28_020_000 picoseconds. - Weight::from_parts(28_991_000, 3986) + // Measured: `422 + n * (1 ±0)` + // Estimated: `3886 + n * (1 ±0)` + // Minimum execution time: 30_671_000 picoseconds. + Weight::from_parts(31_197_000, 3886) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_171, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(Weight::from_parts(1_163, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } - /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) - /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: Whitelist WhitelistedCall (r:1 w:1) + /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) /// The range of component `n` is `[1, 10000]`. fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `446` + // Measured: `346` // Estimated: `3556` - // Minimum execution time: 21_916_000 picoseconds. - Weight::from_parts(23_082_065, 3556) - // Standard Error: 6 - .saturating_add(Weight::from_parts(1_388, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Minimum execution time: 22_099_000 picoseconds. + Weight::from_parts(23_145_477, 3556) + // Standard Error: 5 + .saturating_add(Weight::from_parts(1_422, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } } -// For backwards compatibility and tests. +// For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) - /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: Whitelist WhitelistedCall (r:1 w:1) + /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn whitelist_call() -> Weight { // Proof Size summary in bytes: - // Measured: `317` + // Measured: `217` // Estimated: `3556` - // Minimum execution time: 18_503_000 picoseconds. - Weight::from_parts(19_497_000, 3556) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Minimum execution time: 19_914_000 picoseconds. + Weight::from_parts(20_892_000, 3556) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) - /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: Whitelist WhitelistedCall (r:1 w:1) + /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) fn remove_whitelisted_call() -> Weight { // Proof Size summary in bytes: - // Measured: `446` + // Measured: `346` // Estimated: `3556` - // Minimum execution time: 17_633_000 picoseconds. - Weight::from_parts(18_196_000, 3556) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Minimum execution time: 18_142_000 picoseconds. + Weight::from_parts(18_529_000, 3556) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) - /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) - /// Storage: `Preimage::PreimageFor` (r:1 w:1) - /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `Measured`) - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: Whitelist WhitelistedCall (r:1 w:1) + /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) + /// Storage: Preimage PreimageFor (r:1 w:1) + /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: Measured) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) /// The range of component `n` is `[1, 4194294]`. fn dispatch_whitelisted_call(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `522 + n * (1 ±0)` - // Estimated: `3986 + n * (1 ±0)` - // Minimum execution time: 28_020_000 picoseconds. - Weight::from_parts(28_991_000, 3986) + // Measured: `422 + n * (1 ±0)` + // Estimated: `3886 + n * (1 ±0)` + // Minimum execution time: 30_671_000 picoseconds. + Weight::from_parts(31_197_000, 3886) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_171, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(Weight::from_parts(1_163, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } - /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) - /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) - /// Storage: `Preimage::StatusFor` (r:1 w:0) - /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) - /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) - /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: Whitelist WhitelistedCall (r:1 w:1) + /// Proof: Whitelist WhitelistedCall (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:1) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) /// The range of component `n` is `[1, 10000]`. fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `446` + // Measured: `346` // Estimated: `3556` - // Minimum execution time: 21_916_000 picoseconds. - Weight::from_parts(23_082_065, 3556) - // Standard Error: 6 - .saturating_add(Weight::from_parts(1_388, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Minimum execution time: 22_099_000 picoseconds. + Weight::from_parts(23_145_477, 3556) + // Standard Error: 5 + .saturating_add(Weight::from_parts(1_422, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } } diff --git a/substrate/primitives/inherents/src/lib.rs b/substrate/primitives/inherents/src/lib.rs index 415319a6849..dd7c294f1e2 100644 --- a/substrate/primitives/inherents/src/lib.rs +++ b/substrate/primitives/inherents/src/lib.rs @@ -98,10 +98,10 @@ //! and production. //! //! ``` -//! # use sp_runtime::{generic::UncheckedExtrinsic, testing::MockCallU64}; +//! # use sp_runtime::testing::ExtrinsicWrapper; //! # use sp_inherents::{InherentIdentifier, InherentData}; //! # use futures::FutureExt; -//! # type Block = sp_runtime::testing::Block>; +//! # type Block = sp_runtime::testing::Block>; //! # const INHERENT_IDENTIFIER: InherentIdentifier = *b"testinh0"; //! # struct InherentDataProvider; //! # #[async_trait::async_trait] diff --git a/substrate/primitives/metadata-ir/src/lib.rs b/substrate/primitives/metadata-ir/src/lib.rs index 66aff2c599f..edfa58f8618 100644 --- a/substrate/primitives/metadata-ir/src/lib.rs +++ b/substrate/primitives/metadata-ir/src/lib.rs @@ -84,7 +84,7 @@ mod test { call_ty: meta_type::<()>(), signature_ty: meta_type::<()>(), extra_ty: meta_type::<()>(), - extensions: vec![], + signed_extensions: vec![], }, ty: meta_type::<()>(), apis: vec![], diff --git a/substrate/primitives/metadata-ir/src/types.rs b/substrate/primitives/metadata-ir/src/types.rs index e60881ed6b8..b107d20a8e2 100644 --- a/substrate/primitives/metadata-ir/src/types.rs +++ b/substrate/primitives/metadata-ir/src/types.rs @@ -166,11 +166,10 @@ pub struct ExtrinsicMetadataIR { pub call_ty: T::Type, /// The type of the extrinsic's signature. pub signature_ty: T::Type, - /// The type of the outermost Extra/Extensions enum. - // TODO: metadata-v16: rename this to `extension_ty`. + /// The type of the outermost Extra enum. pub extra_ty: T::Type, - /// The transaction extensions in the order they appear in the extrinsic. - pub extensions: Vec>, + /// The signed extensions in the order they appear in the extrinsic. + pub signed_extensions: Vec>, } impl IntoPortable for ExtrinsicMetadataIR { @@ -184,27 +183,27 @@ impl IntoPortable for ExtrinsicMetadataIR { call_ty: registry.register_type(&self.call_ty), signature_ty: registry.register_type(&self.signature_ty), extra_ty: registry.register_type(&self.extra_ty), - extensions: registry.map_into_portable(self.extensions), + signed_extensions: registry.map_into_portable(self.signed_extensions), } } } /// Metadata of an extrinsic's signed extension. #[derive(Clone, PartialEq, Eq, Encode, Debug)] -pub struct TransactionExtensionMetadataIR { +pub struct SignedExtensionMetadataIR { /// The unique signed extension identifier, which may be different from the type name. pub identifier: T::String, /// The type of the signed extension, with the data to be included in the extrinsic. pub ty: T::Type, - /// The type of the additional signed data, with the data to be included in the signed payload. + /// The type of the additional signed data, with the data to be included in the signed payload pub additional_signed: T::Type, } -impl IntoPortable for TransactionExtensionMetadataIR { - type Output = TransactionExtensionMetadataIR; +impl IntoPortable for SignedExtensionMetadataIR { + type Output = SignedExtensionMetadataIR; fn into_portable(self, registry: &mut Registry) -> Self::Output { - TransactionExtensionMetadataIR { + SignedExtensionMetadataIR { identifier: self.identifier.into_portable(registry), ty: registry.register_type(&self.ty), additional_signed: registry.register_type(&self.additional_signed), diff --git a/substrate/primitives/metadata-ir/src/v14.rs b/substrate/primitives/metadata-ir/src/v14.rs index ec08de34786..e1b7a24f765 100644 --- a/substrate/primitives/metadata-ir/src/v14.rs +++ b/substrate/primitives/metadata-ir/src/v14.rs @@ -20,8 +20,8 @@ use super::types::{ ExtrinsicMetadataIR, MetadataIR, PalletCallMetadataIR, PalletConstantMetadataIR, PalletErrorMetadataIR, PalletEventMetadataIR, PalletMetadataIR, PalletStorageMetadataIR, - StorageEntryMetadataIR, StorageEntryModifierIR, StorageEntryTypeIR, StorageHasherIR, - TransactionExtensionMetadataIR, + SignedExtensionMetadataIR, StorageEntryMetadataIR, StorageEntryModifierIR, StorageEntryTypeIR, + StorageHasherIR, }; use frame_metadata::v14::{ @@ -137,8 +137,8 @@ impl From for PalletErrorMetadata { } } -impl From for SignedExtensionMetadata { - fn from(ir: TransactionExtensionMetadataIR) -> Self { +impl From for SignedExtensionMetadata { + fn from(ir: SignedExtensionMetadataIR) -> Self { SignedExtensionMetadata { identifier: ir.identifier, ty: ir.ty, @@ -152,7 +152,7 @@ impl From for ExtrinsicMetadata { ExtrinsicMetadata { ty: ir.ty, version: ir.version, - signed_extensions: ir.extensions.into_iter().map(Into::into).collect(), + signed_extensions: ir.signed_extensions.into_iter().map(Into::into).collect(), } } } diff --git a/substrate/primitives/metadata-ir/src/v15.rs b/substrate/primitives/metadata-ir/src/v15.rs index dc5ce1c88fd..a942eb73223 100644 --- a/substrate/primitives/metadata-ir/src/v15.rs +++ b/substrate/primitives/metadata-ir/src/v15.rs @@ -21,7 +21,7 @@ use crate::OuterEnumsIR; use super::types::{ ExtrinsicMetadataIR, MetadataIR, PalletMetadataIR, RuntimeApiMetadataIR, - RuntimeApiMethodMetadataIR, RuntimeApiMethodParamMetadataIR, TransactionExtensionMetadataIR, + RuntimeApiMethodMetadataIR, RuntimeApiMethodParamMetadataIR, SignedExtensionMetadataIR, }; use frame_metadata::v15::{ @@ -87,8 +87,8 @@ impl From for PalletMetadata { } } -impl From for SignedExtensionMetadata { - fn from(ir: TransactionExtensionMetadataIR) -> Self { +impl From for SignedExtensionMetadata { + fn from(ir: SignedExtensionMetadataIR) -> Self { SignedExtensionMetadata { identifier: ir.identifier, ty: ir.ty, @@ -105,7 +105,7 @@ impl From for ExtrinsicMetadata { call_ty: ir.call_ty, signature_ty: ir.signature_ty, extra_ty: ir.extra_ty, - signed_extensions: ir.extensions.into_iter().map(Into::into).collect(), + signed_extensions: ir.signed_extensions.into_iter().map(Into::into).collect(), } } } diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml index 758cd8944fd..cacfc059722 100644 --- a/substrate/primitives/runtime/Cargo.toml +++ b/substrate/primitives/runtime/Cargo.toml @@ -17,7 +17,6 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -tuplex = { version = "0.1.2", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } either = { version = "1.5", default-features = false } hash256-std-hasher = { version = "0.15.2", default-features = false } @@ -68,7 +67,6 @@ std = [ "sp-std/std", "sp-tracing/std", "sp-weights/std", - "tuplex/std", ] # Serde support without relying on std features. diff --git a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs index e28c8fe424a..44325920bee 100644 --- a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs @@ -18,115 +18,81 @@ //! Generic implementation of an extrinsic that has passed the verification //! stage. -use codec::Encode; - use crate::{ traits::{ - self, transaction_extension::TransactionExtension, DispatchInfoOf, DispatchTransaction, - Dispatchable, MaybeDisplay, Member, PostDispatchInfoOf, ValidateUnsigned, + self, DispatchInfoOf, Dispatchable, MaybeDisplay, Member, PostDispatchInfoOf, + SignedExtension, ValidateUnsigned, }, transaction_validity::{TransactionSource, TransactionValidity}, }; -/// The kind of extrinsic this is, including any fields required of that kind. This is basically -/// the full extrinsic except the `Call`. -#[derive(PartialEq, Eq, Clone, sp_core::RuntimeDebug)] -pub enum ExtrinsicFormat { - /// Extrinsic is bare; it must pass either the bare forms of `TransactionExtension` or - /// `ValidateUnsigned`, both deprecated, or alternatively a `ProvideInherent`. - Bare, - /// Extrinsic has a default `Origin` of `Signed(AccountId)` and must pass all - /// `TransactionExtension`s regular checks and includes all extension data. - Signed(AccountId, Extension), - /// Extrinsic has a default `Origin` of `None` and must pass all `TransactionExtension`s. - /// regular checks and includes all extension data. - General(Extension), -} - -// TODO: Rename ValidateUnsigned to ValidateInherent -// TODO: Consider changing ValidateInherent API to avoid need for duplicating validate -// code into pre_dispatch (rename that to `prepare`). -// TODO: New extrinsic type corresponding to `ExtrinsicFormat::General`, which is -// unsigned but includes extension data. -// TODO: Move usage of `signed` to `format`: -// - Inherent instead of None. -// - Signed(id, extension) instead of Some((id, extra)). -// - Introduce General(extension) for one without a signature. - /// Definition of something that the external world might want to say; its existence implies that it /// has been checked and is good, particularly with regards to the signature. /// /// This is typically passed into [`traits::Applyable::apply`], which should execute /// [`CheckedExtrinsic::function`], alongside all other bits and bobs. #[derive(PartialEq, Eq, Clone, sp_core::RuntimeDebug)] -pub struct CheckedExtrinsic { +pub struct CheckedExtrinsic { /// Who this purports to be from and the number of extrinsics have come before /// from the same signer, if anyone (note this is not a signature). - pub format: ExtrinsicFormat, + pub signed: Option<(AccountId, Extra)>, /// The function that should be called. pub function: Call, } -impl traits::Applyable - for CheckedExtrinsic +impl traits::Applyable + for CheckedExtrinsic where AccountId: Member + MaybeDisplay, - Call: Member + Dispatchable + Encode, - Extension: TransactionExtension, + Call: Member + Dispatchable, + Extra: SignedExtension, RuntimeOrigin: From>, { type Call = Call; - fn validate>( + fn validate>( &self, + // TODO [#5006;ToDr] should source be passed to `SignedExtension`s? + // Perhaps a change for 2.0 to avoid breaking too much APIs? source: TransactionSource, info: &DispatchInfoOf, len: usize, ) -> TransactionValidity { - match self.format { - ExtrinsicFormat::Bare => { - let inherent_validation = I::validate_unsigned(source, &self.function)?; - #[allow(deprecated)] - let legacy_validation = Extension::validate_bare_compat(&self.function, info, len)?; - Ok(legacy_validation.combine_with(inherent_validation)) - }, - ExtrinsicFormat::Signed(ref signer, ref extension) => { - let origin = Some(signer.clone()).into(); - extension.validate_only(origin, &self.function, info, len).map(|x| x.0) - }, - ExtrinsicFormat::General(ref extension) => - extension.validate_only(None.into(), &self.function, info, len).map(|x| x.0), + if let Some((ref id, ref extra)) = self.signed { + Extra::validate(extra, id, &self.function, info, len) + } else { + let valid = Extra::validate_unsigned(&self.function, info, len)?; + let unsigned_validation = U::validate_unsigned(source, &self.function)?; + Ok(valid.combine_with(unsigned_validation)) } } - fn apply>( + fn apply>( self, info: &DispatchInfoOf, len: usize, ) -> crate::ApplyExtrinsicResultWithInfo> { - match self.format { - ExtrinsicFormat::Bare => { - I::pre_dispatch(&self.function)?; - // TODO: Remove below once `pre_dispatch_unsigned` is removed from `LegacyExtension` - // or `LegacyExtension` is removed. - #[allow(deprecated)] - Extension::validate_bare_compat(&self.function, info, len)?; - #[allow(deprecated)] - Extension::pre_dispatch_bare_compat(&self.function, info, len)?; - let res = self.function.dispatch(None.into()); - let post_info = res.unwrap_or_else(|err| err.post_info); - let pd_res = res.map(|_| ()).map_err(|e| e.error); - // TODO: Remove below once `pre_dispatch_unsigned` is removed from `LegacyExtension` - // or `LegacyExtension` is removed. - #[allow(deprecated)] - Extension::post_dispatch_bare_compat(info, &post_info, len, &pd_res)?; - Ok(res) - }, - ExtrinsicFormat::Signed(signer, extension) => - extension.dispatch_transaction(Some(signer).into(), self.function, info, len), - ExtrinsicFormat::General(extension) => - extension.dispatch_transaction(None.into(), self.function, info, len), - } + let (maybe_who, maybe_pre) = if let Some((id, extra)) = self.signed { + let pre = Extra::pre_dispatch(extra, &id, &self.function, info, len)?; + (Some(id), Some(pre)) + } else { + Extra::pre_dispatch_unsigned(&self.function, info, len)?; + U::pre_dispatch(&self.function)?; + (None, None) + }; + let res = self.function.dispatch(RuntimeOrigin::from(maybe_who)); + let post_info = match res { + Ok(info) => info, + Err(err) => err.post_info, + }; + Extra::post_dispatch( + maybe_pre, + info, + &post_info, + len, + &res.map(|_| ()).map_err(|e| e.error), + )?; + Ok(res) } } diff --git a/substrate/primitives/runtime/src/generic/mod.rs b/substrate/primitives/runtime/src/generic/mod.rs index 5713c166b04..3687f7cdb3b 100644 --- a/substrate/primitives/runtime/src/generic/mod.rs +++ b/substrate/primitives/runtime/src/generic/mod.rs @@ -29,9 +29,9 @@ mod unchecked_extrinsic; pub use self::{ block::{Block, BlockId, SignedBlock}, - checked_extrinsic::{CheckedExtrinsic, ExtrinsicFormat}, + checked_extrinsic::CheckedExtrinsic, digest::{Digest, DigestItem, DigestItemRef, OpaqueDigestItemId}, era::{Era, Phase}, header::Header, - unchecked_extrinsic::{Preamble, SignedPayload, UncheckedExtrinsic}, + unchecked_extrinsic::{SignedPayload, UncheckedExtrinsic}, }; diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index 44dfda13d94..5b54caf597b 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -18,11 +18,10 @@ //! Generic implementation of an unchecked (pre-verification) extrinsic. use crate::{ - generic::{CheckedExtrinsic, ExtrinsicFormat}, + generic::CheckedExtrinsic, traits::{ - self, transaction_extension::TransactionExtensionBase, Checkable, Dispatchable, Extrinsic, - ExtrinsicMetadata, IdentifyAccount, MaybeDisplay, Member, SignaturePayload, - TransactionExtension, + self, Checkable, Extrinsic, ExtrinsicMetadata, IdentifyAccount, MaybeDisplay, Member, + SignaturePayload, SignedExtension, }, transaction_validity::{InvalidTransaction, TransactionValidityError}, OpaqueExtrinsic, @@ -41,60 +40,8 @@ use sp_std::{fmt, prelude::*}; /// the decoding fails. const EXTRINSIC_FORMAT_VERSION: u8 = 4; -/// The `SignaturePayload` of `UncheckedExtrinsic`. -type UncheckedSignaturePayload = (Address, Signature, Extension); - -impl SignaturePayload - for UncheckedSignaturePayload -{ - type SignatureAddress = Address; - type Signature = Signature; - type SignatureExtra = Extension; -} - -/// A "header" for extrinsics leading up to the call itself. Determines the type of extrinsic and -/// holds any necessary specialized data. -#[derive(Eq, PartialEq, Clone, Encode, Decode)] -pub enum Preamble { - /// An extrinsic without a signature or any extension. This means it's either an inherent or - /// an old-school "Unsigned" (we don't use that terminology any more since it's confusable with - /// the general transaction which is without a signature but does have an extension). - /// - /// NOTE: In the future, once we remove `ValidateUnsigned`, this will only serve Inherent - /// extrinsics and thus can be renamed to `Inherent`. - #[codec(index = 0b00000100)] - Bare, - /// An old-school transaction extrinsic which includes a signature of some hard-coded crypto. - #[codec(index = 0b10000100)] - Signed(Address, Signature, Extension), - /// A new-school transaction extrinsic which does not include a signature. - #[codec(index = 0b01000100)] - General(Extension), -} - -impl Preamble { - /// Returns `Some` if this is a signed extrinsic, together with the relevant inner fields. - pub fn to_signed(self) -> Option<(Address, Signature, Extension)> { - match self { - Self::Signed(a, s, e) => Some((a, s, e)), - _ => None, - } - } -} - -impl fmt::Debug for Preamble -where - Address: fmt::Debug, - Extension: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::Bare => write!(f, "Bare"), - Self::Signed(address, _, tx_ext) => write!(f, "Signed({:?}, {:?})", address, tx_ext), - Self::General(tx_ext) => write!(f, "General({:?})", tx_ext), - } - } -} +/// The `SingaturePayload` of `UncheckedExtrinsic`. +type UncheckedSignaturePayload = (Address, Signature, Extra); /// An extrinsic right from the external world. This is unchecked and so can contain a signature. /// @@ -118,28 +65,41 @@ where /// This can be checked using [`Checkable`], yielding a [`CheckedExtrinsic`], which is the /// counterpart of this type after its signature (and other non-negotiable validity checks) have /// passed. -#[derive(PartialEq, Eq, Clone, Debug)] -pub struct UncheckedExtrinsic { - /// Information regarding the type of extrinsic this is (inherent or transaction) as well as - /// associated extension (`Extension`) data if it's a transaction and a possible signature. - pub preamble: Preamble, +#[derive(PartialEq, Eq, Clone)] +pub struct UncheckedExtrinsic +where + Extra: SignedExtension, +{ + /// The signature, address, number of extrinsics have come before from the same signer and an + /// era describing the longevity of this transaction, if this is a signed extrinsic. + /// + /// `None` if it is unsigned or an inherent. + pub signature: Option>, /// The function that should be called. pub function: Call, } +impl SignaturePayload + for UncheckedSignaturePayload +{ + type SignatureAddress = Address; + type Signature = Signature; + type SignatureExtra = Extra; +} + /// Manual [`TypeInfo`] implementation because of custom encoding. The data is a valid encoded /// `Vec`, but requires some logic to extract the signature and payload. /// /// See [`UncheckedExtrinsic::encode`] and [`UncheckedExtrinsic::decode`]. -impl TypeInfo - for UncheckedExtrinsic +impl TypeInfo + for UncheckedExtrinsic where Address: StaticTypeInfo, Call: StaticTypeInfo, Signature: StaticTypeInfo, - Extension: StaticTypeInfo, + Extra: SignedExtension + StaticTypeInfo, { - type Identity = UncheckedExtrinsic; + type Identity = UncheckedExtrinsic; fn type_info() -> Type { Type::builder() @@ -151,7 +111,7 @@ where TypeParameter::new("Address", Some(meta_type::
())), TypeParameter::new("Call", Some(meta_type::())), TypeParameter::new("Signature", Some(meta_type::())), - TypeParameter::new("Extra", Some(meta_type::())), + TypeParameter::new("Extra", Some(meta_type::())), ]) .docs(&["UncheckedExtrinsic raw bytes, requires custom decoding routine"]) // Because of the custom encoding, we can only accurately describe the encoding as an @@ -161,113 +121,66 @@ where } } -impl UncheckedExtrinsic { - /// New instance of a bare (ne unsigned) extrinsic. This could be used for an inherent or an - /// old-school "unsigned transaction" (which are new being deprecated in favour of general - /// transactions). - #[deprecated = "Use new_bare instead"] - pub fn new_unsigned(function: Call) -> Self { - Self::new_bare(function) - } - - /// Returns `true` if this extrinsic instance is an inherent, `false`` otherwise. - pub fn is_inherent(&self) -> bool { - matches!(self.preamble, Preamble::Bare) - } - - /// Returns `true` if this extrinsic instance is an old-school signed transaction, `false` - /// otherwise. - pub fn is_signed(&self) -> bool { - matches!(self.preamble, Preamble::Signed(..)) - } - - /// Create an `UncheckedExtrinsic` from a `Preamble` and the actual `Call`. - pub fn from_parts(function: Call, preamble: Preamble) -> Self { - Self { preamble, function } - } - - /// New instance of a bare (ne unsigned) extrinsic. - pub fn new_bare(function: Call) -> Self { - Self { preamble: Preamble::Bare, function } - } - - /// New instance of an old-school signed transaction. - pub fn new_signed( - function: Call, - signed: Address, - signature: Signature, - tx_ext: Extension, - ) -> Self { - Self { preamble: Preamble::Signed(signed, signature, tx_ext), function } +impl + UncheckedExtrinsic +{ + /// New instance of a signed extrinsic aka "transaction". + pub fn new_signed(function: Call, signed: Address, signature: Signature, extra: Extra) -> Self { + Self { signature: Some((signed, signature, extra)), function } } - /// New instance of an new-school unsigned transaction. - pub fn new_transaction(function: Call, tx_ext: Extension) -> Self { - Self { preamble: Preamble::General(tx_ext), function } + /// New instance of an unsigned extrinsic aka "inherent". + pub fn new_unsigned(function: Call) -> Self { + Self { signature: None, function } } } -// TODO: We can get rid of this trait and just use UncheckedExtrinsic directly. - -impl Extrinsic - for UncheckedExtrinsic +impl + Extrinsic for UncheckedExtrinsic { type Call = Call; - type SignaturePayload = UncheckedSignaturePayload; - - fn is_bare(&self) -> bool { - matches!(self.preamble, Preamble::Bare) - } + type SignaturePayload = UncheckedSignaturePayload; fn is_signed(&self) -> Option { - Some(matches!(self.preamble, Preamble::Signed(..))) + Some(self.signature.is_some()) } fn new(function: Call, signed_data: Option) -> Option { Some(if let Some((address, signature, extra)) = signed_data { Self::new_signed(function, address, signature, extra) } else { - Self::new_bare(function) + Self::new_unsigned(function) }) } - - fn new_inherent(function: Call) -> Self { - Self::new_bare(function) - } } -impl Checkable - for UncheckedExtrinsic +impl Checkable + for UncheckedExtrinsic where LookupSource: Member + MaybeDisplay, - Call: Encode + Member + Dispatchable, + Call: Encode + Member, Signature: Member + traits::Verify, ::Signer: IdentifyAccount, - Extension: Encode + TransactionExtension, + Extra: SignedExtension, AccountId: Member + MaybeDisplay, Lookup: traits::Lookup, { - type Checked = CheckedExtrinsic; + type Checked = CheckedExtrinsic; fn check(self, lookup: &Lookup) -> Result { - Ok(match self.preamble { - Preamble::Signed(signed, signature, tx_ext) => { + Ok(match self.signature { + Some((signed, signature, extra)) => { let signed = lookup.lookup(signed)?; - // CHECK! Should this not contain implicit? - let raw_payload = SignedPayload::new(self.function, tx_ext)?; + let raw_payload = SignedPayload::new(self.function, extra)?; if !raw_payload.using_encoded(|payload| signature.verify(payload, &signed)) { return Err(InvalidTransaction::BadProof.into()) } - let (function, tx_ext, _) = raw_payload.deconstruct(); - CheckedExtrinsic { format: ExtrinsicFormat::Signed(signed, tx_ext), function } - }, - Preamble::General(tx_ext) => CheckedExtrinsic { - format: ExtrinsicFormat::General(tx_ext), - function: self.function, + + let (function, extra, _) = raw_payload.deconstruct(); + CheckedExtrinsic { signed: Some((signed, extra)), function } }, - Preamble::Bare => - CheckedExtrinsic { format: ExtrinsicFormat::Bare, function: self.function }, + None => CheckedExtrinsic { signed: None, function: self.function }, }) } @@ -276,38 +189,91 @@ where self, lookup: &Lookup, ) -> Result { - Ok(match self.preamble { - Preamble::Signed(signed, _, extra) => { + Ok(match self.signature { + Some((signed, _, extra)) => { let signed = lookup.lookup(signed)?; - CheckedExtrinsic { - format: ExtrinsicFormat::Signed(signed, extra), - function: self.function, - } + let raw_payload = SignedPayload::new(self.function, extra)?; + let (function, extra, _) = raw_payload.deconstruct(); + CheckedExtrinsic { signed: Some((signed, extra)), function } }, - Preamble::General(extra) => CheckedExtrinsic { - format: ExtrinsicFormat::General(extra), - function: self.function, - }, - Preamble::Bare => - CheckedExtrinsic { format: ExtrinsicFormat::Bare, function: self.function }, + None => CheckedExtrinsic { signed: None, function: self.function }, }) } } -impl> - ExtrinsicMetadata for UncheckedExtrinsic +impl ExtrinsicMetadata + for UncheckedExtrinsic +where + Extra: SignedExtension, { const VERSION: u8 = EXTRINSIC_FORMAT_VERSION; - type Extra = Extension; + type SignedExtensions = Extra; +} + +/// A payload that has been signed for an unchecked extrinsics. +/// +/// Note that the payload that we sign to produce unchecked extrinsic signature +/// is going to be different than the `SignaturePayload` - so the thing the extrinsic +/// actually contains. +pub struct SignedPayload((Call, Extra, Extra::AdditionalSigned)); + +impl SignedPayload +where + Call: Encode, + Extra: SignedExtension, +{ + /// Create new `SignedPayload`. + /// + /// This function may fail if `additional_signed` of `Extra` is not available. + pub fn new(call: Call, extra: Extra) -> Result { + let additional_signed = extra.additional_signed()?; + let raw_payload = (call, extra, additional_signed); + Ok(Self(raw_payload)) + } + + /// Create new `SignedPayload` from raw components. + pub fn from_raw(call: Call, extra: Extra, additional_signed: Extra::AdditionalSigned) -> Self { + Self((call, extra, additional_signed)) + } + + /// Deconstruct the payload into it's components. + pub fn deconstruct(self) -> (Call, Extra, Extra::AdditionalSigned) { + self.0 + } } -impl Decode - for UncheckedExtrinsic +impl Encode for SignedPayload +where + Call: Encode, + Extra: SignedExtension, +{ + /// Get an encoded version of this payload. + /// + /// Payloads longer than 256 bytes are going to be `blake2_256`-hashed. + fn using_encoded R>(&self, f: F) -> R { + self.0.using_encoded(|payload| { + if payload.len() > 256 { + f(&blake2_256(payload)[..]) + } else { + f(payload) + } + }) + } +} + +impl EncodeLike for SignedPayload +where + Call: Encode, + Extra: SignedExtension, +{ +} + +impl Decode for UncheckedExtrinsic where Address: Decode, Signature: Decode, Call: Decode, - Extension: Decode, + Extra: SignedExtension, { fn decode(input: &mut I) -> Result { // This is a little more complicated than usual since the binary format must be compatible @@ -316,7 +282,15 @@ where let expected_length: Compact = Decode::decode(input)?; let before_length = input.remaining_len()?; - let preamble = Decode::decode(input)?; + let version = input.read_byte()?; + + let is_signed = version & 0b1000_0000 != 0; + let version = version & 0b0111_1111; + if version != EXTRINSIC_FORMAT_VERSION { + return Err("Invalid transaction version".into()) + } + + let signature = is_signed.then(|| Decode::decode(input)).transpose()?; let function = Decode::decode(input)?; if let Some((before_length, after_length)) = @@ -329,20 +303,31 @@ where } } - Ok(Self { preamble, function }) + Ok(Self { signature, function }) } } #[docify::export(unchecked_extrinsic_encode_impl)] -impl Encode - for UncheckedExtrinsic +impl Encode for UncheckedExtrinsic where - Preamble: Encode, + Address: Encode, + Signature: Encode, Call: Encode, - Extension: Encode, + Extra: SignedExtension, { fn encode(&self) -> Vec { - let mut tmp = self.preamble.encode(); + let mut tmp = Vec::with_capacity(sp_std::mem::size_of::()); + + // 1 byte version id. + match self.signature.as_ref() { + Some(s) => { + tmp.push(EXTRINSIC_FORMAT_VERSION | 0b1000_0000); + s.encode_to(&mut tmp); + }, + None => { + tmp.push(EXTRINSIC_FORMAT_VERSION & 0b0111_1111); + }, + } self.function.encode_to(&mut tmp); let compact_len = codec::Compact::(tmp.len() as u32); @@ -357,19 +342,19 @@ where } } -impl EncodeLike - for UncheckedExtrinsic +impl EncodeLike + for UncheckedExtrinsic where Address: Encode, Signature: Encode, - Call: Encode + Dispatchable, - Extension: TransactionExtension, + Call: Encode, + Extra: SignedExtension, { } #[cfg(feature = "serde")] -impl serde::Serialize - for UncheckedExtrinsic +impl serde::Serialize + for UncheckedExtrinsic { fn serialize(&self, seq: S) -> Result where @@ -380,88 +365,45 @@ impl serde: } #[cfg(feature = "serde")] -impl<'a, Address: Decode, Signature: Decode, Call: Decode, Extension: Decode> serde::Deserialize<'a> - for UncheckedExtrinsic +impl<'a, Address: Decode, Signature: Decode, Call: Decode, Extra: SignedExtension> + serde::Deserialize<'a> for UncheckedExtrinsic { fn deserialize(de: D) -> Result where D: serde::Deserializer<'a>, { let r = sp_core::bytes::deserialize(de)?; - Self::decode(&mut &r[..]) + Decode::decode(&mut &r[..]) .map_err(|e| serde::de::Error::custom(format!("Decode error: {}", e))) } } -/// A payload that has been signed for an unchecked extrinsics. -/// -/// Note that the payload that we sign to produce unchecked extrinsic signature -/// is going to be different than the `SignaturePayload` - so the thing the extrinsic -/// actually contains. -pub struct SignedPayload( - (Call, Extension, Extension::Implicit), -); - -impl SignedPayload -where - Call: Encode + Dispatchable, - Extension: TransactionExtensionBase, -{ - /// Create new `SignedPayload`. - /// - /// This function may fail if `implicit` of `Extension` is not available. - pub fn new(call: Call, tx_ext: Extension) -> Result { - let implicit = Extension::implicit(&tx_ext)?; - let raw_payload = (call, tx_ext, implicit); - Ok(Self(raw_payload)) - } - - /// Create new `SignedPayload` from raw components. - pub fn from_raw(call: Call, tx_ext: Extension, implicit: Extension::Implicit) -> Self { - Self((call, tx_ext, implicit)) - } - - /// Deconstruct the payload into it's components. - pub fn deconstruct(self) -> (Call, Extension, Extension::Implicit) { - self.0 - } -} - -impl Encode for SignedPayload +impl fmt::Debug + for UncheckedExtrinsic where - Call: Encode + Dispatchable, - Extension: TransactionExtensionBase, + Address: fmt::Debug, + Call: fmt::Debug, + Extra: SignedExtension, { - /// Get an encoded version of this payload. - /// - /// Payloads longer than 256 bytes are going to be `blake2_256`-hashed. - fn using_encoded R>(&self, f: F) -> R { - self.0.using_encoded(|payload| { - if payload.len() > 256 { - f(&blake2_256(payload)[..]) - } else { - f(payload) - } - }) + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "UncheckedExtrinsic({:?}, {:?})", + self.signature.as_ref().map(|x| (&x.0, &x.2)), + self.function, + ) } } -impl EncodeLike for SignedPayload -where - Call: Encode + Dispatchable, - Extension: TransactionExtensionBase, -{ -} - -impl - From> for OpaqueExtrinsic +impl From> + for OpaqueExtrinsic where Address: Encode, Signature: Encode, Call: Encode, - Extension: Encode, + Extra: SignedExtension, { - fn from(extrinsic: UncheckedExtrinsic) -> Self { + fn from(extrinsic: UncheckedExtrinsic) -> Self { Self::from_bytes(extrinsic.encode().as_slice()).expect( "both OpaqueExtrinsic and UncheckedExtrinsic have encoding that is compatible with \ raw Vec encoding; qed", @@ -469,198 +411,60 @@ where } } -#[cfg(test)] -mod legacy { - use codec::{Compact, Decode, Encode, EncodeLike, Error, Input}; - use scale_info::{ - build::Fields, meta_type, Path, StaticTypeInfo, Type, TypeInfo, TypeParameter, - }; - - pub type OldUncheckedSignaturePayload = (Address, Signature, Extra); - - #[derive(PartialEq, Eq, Clone, Debug)] - pub struct OldUncheckedExtrinsic { - pub signature: Option>, - pub function: Call, - } - - impl TypeInfo - for OldUncheckedExtrinsic - where - Address: StaticTypeInfo, - Call: StaticTypeInfo, - Signature: StaticTypeInfo, - Extra: StaticTypeInfo, - { - type Identity = OldUncheckedExtrinsic; - - fn type_info() -> Type { - Type::builder() - .path(Path::new("UncheckedExtrinsic", module_path!())) - // Include the type parameter types, even though they are not used directly in any - // of the described fields. These type definitions can be used by downstream - // consumers to help construct the custom decoding from the opaque bytes (see - // below). - .type_params(vec![ - TypeParameter::new("Address", Some(meta_type::
())), - TypeParameter::new("Call", Some(meta_type::())), - TypeParameter::new("Signature", Some(meta_type::())), - TypeParameter::new("Extra", Some(meta_type::())), - ]) - .docs(&["OldUncheckedExtrinsic raw bytes, requires custom decoding routine"]) - // Because of the custom encoding, we can only accurately describe the encoding as - // an opaque `Vec`. Downstream consumers will need to manually implement the - // codec to encode/decode the `signature` and `function` fields. - .composite(Fields::unnamed().field(|f| f.ty::>())) - } - } - - impl OldUncheckedExtrinsic { - pub fn new_signed( - function: Call, - signed: Address, - signature: Signature, - extra: Extra, - ) -> Self { - Self { signature: Some((signed, signature, extra)), function } - } - - pub fn new_unsigned(function: Call) -> Self { - Self { signature: None, function } - } - } - - impl Decode - for OldUncheckedExtrinsic - where - Address: Decode, - Signature: Decode, - Call: Decode, - Extra: Decode, - { - fn decode(input: &mut I) -> Result { - // This is a little more complicated than usual since the binary format must be - // compatible with SCALE's generic `Vec` type. Basically this just means accepting - // that there will be a prefix of vector length. - let expected_length: Compact = Decode::decode(input)?; - let before_length = input.remaining_len()?; - - let version = input.read_byte()?; - - let is_signed = version & 0b1000_0000 != 0; - let version = version & 0b0111_1111; - if version != 4u8 { - return Err("Invalid transaction version".into()) - } - - let signature = is_signed.then(|| Decode::decode(input)).transpose()?; - let function = Decode::decode(input)?; - - if let Some((before_length, after_length)) = - input.remaining_len()?.and_then(|a| before_length.map(|b| (b, a))) - { - let length = before_length.saturating_sub(after_length); - - if length != expected_length.0 as usize { - return Err("Invalid length prefix".into()) - } - } - - Ok(Self { signature, function }) - } - } - - #[docify::export(unchecked_extrinsic_encode_impl)] - impl Encode - for OldUncheckedExtrinsic - where - Address: Encode, - Signature: Encode, - Call: Encode, - Extra: Encode, - { - fn encode(&self) -> Vec { - let mut tmp = Vec::with_capacity(sp_std::mem::size_of::()); - - // 1 byte version id. - match self.signature.as_ref() { - Some(s) => { - tmp.push(4u8 | 0b1000_0000); - s.encode_to(&mut tmp); - }, - None => { - tmp.push(4u8 & 0b0111_1111); - }, - } - self.function.encode_to(&mut tmp); - - let compact_len = codec::Compact::(tmp.len() as u32); - - // Allocate the output buffer with the correct length - let mut output = Vec::with_capacity(compact_len.size_hint() + tmp.len()); - - compact_len.encode_to(&mut output); - output.extend(tmp); - - output - } - } - - impl EncodeLike - for OldUncheckedExtrinsic - where - Address: Encode, - Signature: Encode, - Call: Encode, - Extra: Encode, - { - } -} - #[cfg(test)] mod tests { - use super::{legacy::OldUncheckedExtrinsic, *}; + use super::*; use crate::{ codec::{Decode, Encode}, - impl_tx_ext_default, testing::TestSignature as TestSig, - traits::{FakeDispatchable, IdentityLookup, TransactionExtension}, + traits::{DispatchInfoOf, IdentityLookup, SignedExtension}, }; use sp_io::hashing::blake2_256; type TestContext = IdentityLookup; type TestAccountId = u64; - type TestCall = FakeDispatchable>; + type TestCall = Vec; const TEST_ACCOUNT: TestAccountId = 0; // NOTE: this is demonstration. One can simply use `()` for testing. #[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, Ord, PartialOrd, TypeInfo)] - struct DummyExtension; - impl TransactionExtensionBase for DummyExtension { - const IDENTIFIER: &'static str = "DummyExtension"; - type Implicit = (); - } - impl TransactionExtension for DummyExtension { - type Val = (); + struct TestExtra; + impl SignedExtension for TestExtra { + const IDENTIFIER: &'static str = "TestExtra"; + type AccountId = u64; + type Call = (); + type AdditionalSigned = (); type Pre = (); - impl_tx_ext_default!(TestCall; Context; validate prepare); + + fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { + Ok(()) + } + + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + self.validate(who, call, info, len).map(|_| ()) + } } - type Ex = UncheckedExtrinsic; - type CEx = CheckedExtrinsic; + type Ex = UncheckedExtrinsic; + type CEx = CheckedExtrinsic; #[test] fn unsigned_codec_should_work() { - let call: TestCall = vec![0u8; 0].into(); - let ux = Ex::new_inherent(call); + let ux = Ex::new_unsigned(vec![0u8; 0]); let encoded = ux.encode(); assert_eq!(Ex::decode(&mut &encoded[..]), Ok(ux)); } #[test] fn invalid_length_prefix_is_detected() { - let ux = Ex::new_inherent(vec![0u8; 0].into()); + let ux = Ex::new_unsigned(vec![0u8; 0]); let mut encoded = ux.encode(); let length = Compact::::decode(&mut &encoded[..]).unwrap(); @@ -669,20 +473,13 @@ mod tests { assert_eq!(Ex::decode(&mut &encoded[..]), Err("Invalid length prefix".into())); } - #[test] - fn transaction_codec_should_work() { - let ux = Ex::new_transaction(vec![0u8; 0].into(), DummyExtension); - let encoded = ux.encode(); - assert_eq!(Ex::decode(&mut &encoded[..]), Ok(ux)); - } - #[test] fn signed_codec_should_work() { let ux = Ex::new_signed( - vec![0u8; 0].into(), + vec![0u8; 0], TEST_ACCOUNT, - TestSig(TEST_ACCOUNT, (vec![0u8; 0], DummyExtension).encode()), - DummyExtension, + TestSig(TEST_ACCOUNT, (vec![0u8; 0], TestExtra).encode()), + TestExtra, ); let encoded = ux.encode(); assert_eq!(Ex::decode(&mut &encoded[..]), Ok(ux)); @@ -691,13 +488,13 @@ mod tests { #[test] fn large_signed_codec_should_work() { let ux = Ex::new_signed( - vec![0u8; 0].into(), + vec![0u8; 0], TEST_ACCOUNT, TestSig( TEST_ACCOUNT, - (vec![0u8; 257], DummyExtension).using_encoded(blake2_256)[..].to_owned(), + (vec![0u8; 257], TestExtra).using_encoded(blake2_256)[..].to_owned(), ), - DummyExtension, + TestExtra, ); let encoded = ux.encode(); assert_eq!(Ex::decode(&mut &encoded[..]), Ok(ux)); @@ -705,63 +502,44 @@ mod tests { #[test] fn unsigned_check_should_work() { - let ux = Ex::new_inherent(vec![0u8; 0].into()); - assert!(ux.is_inherent()); - assert_eq!( - >::check(ux, &Default::default()), - Ok(CEx { format: ExtrinsicFormat::Bare, function: vec![0u8; 0].into() }), - ); + let ux = Ex::new_unsigned(vec![0u8; 0]); + assert!(!ux.is_signed().unwrap_or(false)); + assert!(>::check(ux, &Default::default()).is_ok()); } #[test] fn badly_signed_check_should_fail() { let ux = Ex::new_signed( - vec![0u8; 0].into(), + vec![0u8; 0], TEST_ACCOUNT, - TestSig(TEST_ACCOUNT, vec![0u8; 0].into()), - DummyExtension, + TestSig(TEST_ACCOUNT, vec![0u8; 0]), + TestExtra, ); - assert!(!ux.is_inherent()); + assert!(ux.is_signed().unwrap_or(false)); assert_eq!( >::check(ux, &Default::default()), Err(InvalidTransaction::BadProof.into()), ); } - #[test] - fn transaction_check_should_work() { - let ux = Ex::new_transaction(vec![0u8; 0].into(), DummyExtension); - assert!(!ux.is_inherent()); - assert_eq!( - >::check(ux, &Default::default()), - Ok(CEx { - format: ExtrinsicFormat::General(DummyExtension), - function: vec![0u8; 0].into() - }), - ); - } - #[test] fn signed_check_should_work() { let ux = Ex::new_signed( - vec![0u8; 0].into(), + vec![0u8; 0], TEST_ACCOUNT, - TestSig(TEST_ACCOUNT, (vec![0u8; 0], DummyExtension).encode()), - DummyExtension, + TestSig(TEST_ACCOUNT, (vec![0u8; 0], TestExtra).encode()), + TestExtra, ); - assert!(!ux.is_inherent()); + assert!(ux.is_signed().unwrap_or(false)); assert_eq!( >::check(ux, &Default::default()), - Ok(CEx { - format: ExtrinsicFormat::Signed(TEST_ACCOUNT, DummyExtension), - function: vec![0u8; 0].into() - }), + Ok(CEx { signed: Some((TEST_ACCOUNT, TestExtra)), function: vec![0u8; 0] }), ); } #[test] fn encoding_matches_vec() { - let ex = Ex::new_inherent(vec![0u8; 0].into()); + let ex = Ex::new_unsigned(vec![0u8; 0]); let encoded = ex.encode(); let decoded = Ex::decode(&mut encoded.as_slice()).unwrap(); assert_eq!(decoded, ex); @@ -771,7 +549,7 @@ mod tests { #[test] fn conversion_to_opaque() { - let ux = Ex::new_inherent(vec![0u8; 0].into()); + let ux = Ex::new_unsigned(vec![0u8; 0]); let encoded = ux.encode(); let opaque: OpaqueExtrinsic = ux.into(); let opaque_encoded = opaque.encode(); @@ -780,62 +558,10 @@ mod tests { #[test] fn large_bad_prefix_should_work() { - let encoded = (Compact::::from(u32::MAX), Preamble::<(), (), ()>::Bare).encode(); - assert!(Ex::decode(&mut &encoded[..]).is_err()); - } - - #[test] - fn legacy_signed_encode_decode() { - let call: TestCall = vec![0u8; 0].into(); - let signed = TEST_ACCOUNT; - let signature = TestSig(TEST_ACCOUNT, (vec![0u8; 0], DummyExtension).encode()); - let extension = DummyExtension; - - let new_ux = Ex::new_signed(call.clone(), signed, signature.clone(), extension.clone()); - let old_ux = - OldUncheckedExtrinsic::::new_signed( - call, signed, signature, extension, - ); - - let encoded_new_ux = new_ux.encode(); - let encoded_old_ux = old_ux.encode(); - - assert_eq!(encoded_new_ux, encoded_old_ux); - - let decoded_new_ux = Ex::decode(&mut &encoded_new_ux[..]).unwrap(); - let decoded_old_ux = - OldUncheckedExtrinsic::::decode( - &mut &encoded_old_ux[..], - ) - .unwrap(); - - assert_eq!(new_ux, decoded_new_ux); - assert_eq!(old_ux, decoded_old_ux); - } - - #[test] - fn legacy_unsigned_encode_decode() { - let call: TestCall = vec![0u8; 0].into(); - - let new_ux = Ex::new_bare(call.clone()); - let old_ux = - OldUncheckedExtrinsic::::new_unsigned( - call, - ); - - let encoded_new_ux = new_ux.encode(); - let encoded_old_ux = old_ux.encode(); - - assert_eq!(encoded_new_ux, encoded_old_ux); - - let decoded_new_ux = Ex::decode(&mut &encoded_new_ux[..]).unwrap(); - let decoded_old_ux = - OldUncheckedExtrinsic::::decode( - &mut &encoded_old_ux[..], - ) - .unwrap(); - - assert_eq!(new_ux, decoded_new_ux); - assert_eq!(old_ux, decoded_old_ux); + let encoded = Compact::::from(u32::MAX).encode(); + assert_eq!( + Ex::decode(&mut &encoded[..]), + Err(Error::from("Not enough data to fill buffer")) + ); } } diff --git a/substrate/primitives/runtime/src/lib.rs b/substrate/primitives/runtime/src/lib.rs index 70605970b4e..44bf3c969e5 100644 --- a/substrate/primitives/runtime/src/lib.rs +++ b/substrate/primitives/runtime/src/lib.rs @@ -125,11 +125,6 @@ pub use sp_arithmetic::{ Perquintill, Rational128, Rounding, UpperOf, }; -pub use transaction_validity::{ - InvalidTransaction, TransactionSource, TransactionValidityError, UnknownTransaction, - ValidTransaction, -}; - pub use either::Either; /// The number of bytes of the module-specific `error` field defined in [`ModuleError`]. @@ -448,21 +443,21 @@ impl std::fmt::Display for MultiSigner { impl Verify for MultiSignature { type Signer = MultiSigner; fn verify>(&self, mut msg: L, signer: &AccountId32) -> bool { - match self { - Self::Ed25519(ref sig) => match ed25519::Public::from_slice(signer.as_ref()) { + match (self, signer) { + (Self::Ed25519(ref sig), who) => match ed25519::Public::from_slice(who.as_ref()) { Ok(signer) => sig.verify(msg, &signer), Err(()) => false, }, - Self::Sr25519(ref sig) => match sr25519::Public::from_slice(signer.as_ref()) { + (Self::Sr25519(ref sig), who) => match sr25519::Public::from_slice(who.as_ref()) { Ok(signer) => sig.verify(msg, &signer), Err(()) => false, }, - Self::Ecdsa(ref sig) => { + (Self::Ecdsa(ref sig), who) => { let m = sp_io::hashing::blake2_256(msg.get()); match sp_io::crypto::secp256k1_ecdsa_recover_compressed(sig.as_ref(), &m) { Ok(pubkey) => &sp_io::hashing::blake2_256(pubkey.as_ref()) == - >::as_ref(signer), + >::as_ref(who), _ => false, } }, @@ -949,13 +944,9 @@ impl<'a> ::serde::Deserialize<'a> for OpaqueExtrinsic { } } -// TODO: OpaqueExtrinsics cannot act like regular extrinsics, right?! impl traits::Extrinsic for OpaqueExtrinsic { type Call = (); type SignaturePayload = (); - fn is_bare(&self) -> bool { - false - } } /// Print something that implements `Printable` from the runtime. diff --git a/substrate/primitives/runtime/src/testing.rs b/substrate/primitives/runtime/src/testing.rs index 3d6e0b5ab8b..5f94c834a8f 100644 --- a/substrate/primitives/runtime/src/testing.rs +++ b/substrate/primitives/runtime/src/testing.rs @@ -21,16 +21,24 @@ use crate::{ codec::{Codec, Decode, Encode, MaxEncodedLen}, generic, scale_info::TypeInfo, - traits::{self, BlakeTwo256, Dispatchable, OpaqueKeys}, - DispatchResultWithInfo, KeyTypeId, + traits::{ + self, Applyable, BlakeTwo256, Checkable, DispatchInfoOf, Dispatchable, OpaqueKeys, + PostDispatchInfoOf, SignaturePayload, SignedExtension, ValidateUnsigned, + }, + transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError}, + ApplyExtrinsicResultWithInfo, KeyTypeId, }; -use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize}; +use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize, Serializer}; use sp_core::{ crypto::{key_types, ByteArray, CryptoType, Dummy}, U256, }; pub use sp_core::{sr25519, H256}; -use std::{cell::RefCell, fmt::Debug}; +use std::{ + cell::RefCell, + fmt::{self, Debug}, + ops::Deref, +}; /// A dummy type which can be used instead of regular cryptographic primitives. /// @@ -190,6 +198,42 @@ impl Header { } } +/// An opaque extrinsic wrapper type. +#[derive(PartialEq, Eq, Clone, Debug, Encode, Decode)] +pub struct ExtrinsicWrapper(Xt); + +impl traits::Extrinsic for ExtrinsicWrapper { + type Call = (); + type SignaturePayload = (); + + fn is_signed(&self) -> Option { + None + } +} + +impl serde::Serialize for ExtrinsicWrapper { + fn serialize(&self, seq: S) -> Result + where + S: ::serde::Serializer, + { + self.using_encoded(|bytes| seq.serialize_bytes(bytes)) + } +} + +impl From for ExtrinsicWrapper { + fn from(xt: Xt) -> Self { + ExtrinsicWrapper(xt) + } +} + +impl Deref for ExtrinsicWrapper { + type Target = Xt; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + /// Testing block #[derive(PartialEq, Eq, Clone, Serialize, Debug, Encode, Decode, TypeInfo)] pub struct Block { @@ -239,22 +283,139 @@ where } } -/// Wrapper over a `u64` that can be used as a `RuntimeCall`. -#[derive(PartialEq, Eq, Debug, Clone, Encode, Decode, TypeInfo)] -pub struct MockCallU64(pub u64); +/// The signature payload of a `TestXt`. +type TxSingaturePayload = (u64, Extra); + +impl SignaturePayload for TxSingaturePayload { + type SignatureAddress = u64; + type Signature = (); + type SignatureExtra = Extra; +} + +/// Test transaction, tuple of (sender, call, signed_extra) +/// with index only used if sender is some. +/// +/// If sender is some then the transaction is signed otherwise it is unsigned. +#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo)] +pub struct TestXt { + /// Signature of the extrinsic. + pub signature: Option>, + /// Call of the extrinsic. + pub call: Call, +} + +impl TestXt { + /// Create a new `TextXt`. + pub fn new(call: Call, signature: Option<(u64, Extra)>) -> Self { + Self { call, signature } + } +} + +impl Serialize for TestXt +where + TestXt: Encode, +{ + fn serialize(&self, seq: S) -> Result + where + S: Serializer, + { + self.using_encoded(|bytes| seq.serialize_bytes(bytes)) + } +} -impl Dispatchable for MockCallU64 { - type RuntimeOrigin = u64; - type Config = (); - type Info = (); - type PostInfo = (); - fn dispatch(self, _origin: Self::RuntimeOrigin) -> DispatchResultWithInfo { - Ok(()) +impl Debug for TestXt { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "TestXt({:?}, ...)", self.signature.as_ref().map(|x| &x.0)) } } -impl From for MockCallU64 { - fn from(value: u64) -> Self { - Self(value) +impl Checkable for TestXt { + type Checked = Self; + fn check(self, _: &Context) -> Result { + Ok(self) + } + + #[cfg(feature = "try-runtime")] + fn unchecked_into_checked_i_know_what_i_am_doing( + self, + _: &Context, + ) -> Result { + unreachable!() + } +} + +impl traits::Extrinsic + for TestXt +{ + type Call = Call; + type SignaturePayload = TxSingaturePayload; + + fn is_signed(&self) -> Option { + Some(self.signature.is_some()) + } + + fn new(c: Call, sig: Option) -> Option { + Some(TestXt { signature: sig, call: c }) + } +} + +impl traits::ExtrinsicMetadata for TestXt +where + Call: Codec + Sync + Send, + Extra: SignedExtension, +{ + type SignedExtensions = Extra; + const VERSION: u8 = 0u8; +} + +impl Applyable for TestXt +where + Call: 'static + + Sized + + Send + + Sync + + Clone + + Eq + + Codec + + Debug + + Dispatchable, + Extra: SignedExtension, + Origin: From>, +{ + type Call = Call; + + /// Checks to see if this is a valid *transaction*. It returns information on it if so. + fn validate>( + &self, + source: TransactionSource, + info: &DispatchInfoOf, + len: usize, + ) -> TransactionValidity { + if let Some((ref id, ref extra)) = self.signature { + Extra::validate(extra, id, &self.call, info, len) + } else { + let valid = Extra::validate_unsigned(&self.call, info, len)?; + let unsigned_validation = U::validate_unsigned(source, &self.call)?; + Ok(valid.combine_with(unsigned_validation)) + } + } + + /// Executes all necessary logic needed prior to dispatch and deconstructs into function call, + /// index and sender. + fn apply>( + self, + info: &DispatchInfoOf, + len: usize, + ) -> ApplyExtrinsicResultWithInfo> { + let maybe_who = if let Some((who, extra)) = self.signature { + Extra::pre_dispatch(extra, &who, &self.call, info, len)?; + Some(who) + } else { + Extra::pre_dispatch_unsigned(&self.call, info, len)?; + U::pre_dispatch(&self.call)?; + None + }; + + Ok(self.call.dispatch(maybe_who.into())) } } diff --git a/substrate/primitives/runtime/src/traits/mod.rs b/substrate/primitives/runtime/src/traits.rs similarity index 94% rename from substrate/primitives/runtime/src/traits/mod.rs rename to substrate/primitives/runtime/src/traits.rs index b217166d8de..caede5e2b59 100644 --- a/substrate/primitives/runtime/src/traits/mod.rs +++ b/substrate/primitives/runtime/src/traits.rs @@ -19,7 +19,7 @@ use crate::{ generic::Digest, - scale_info::{StaticTypeInfo, TypeInfo}, + scale_info::{MetaType, StaticTypeInfo, TypeInfo}, transaction_validity::{ TransactionSource, TransactionValidity, TransactionValidityError, UnknownTransaction, ValidTransaction, @@ -52,12 +52,6 @@ use std::fmt::Display; #[cfg(feature = "std")] use std::str::FromStr; -pub mod transaction_extension; -pub use transaction_extension::{ - DispatchTransaction, TransactionExtension, TransactionExtensionBase, - TransactionExtensionInterior, TransactionExtensionMetadata, ValidateResult, -}; - /// A lazy value. pub trait Lazy { /// Get a reference to the underlying value. @@ -1259,7 +1253,7 @@ pub trait Header: // that is then used to define `UncheckedExtrinsic`. // ```ignore // pub type UncheckedExtrinsic = -// generic::UncheckedExtrinsic; +// generic::UncheckedExtrinsic; // ``` // This `UncheckedExtrinsic` is supplied to the `Block`. // ```ignore @@ -1329,31 +1323,19 @@ pub trait Extrinsic: Sized { /// Is this `Extrinsic` signed? /// If no information are available about signed/unsigned, `None` should be returned. - #[deprecated = "Use and implement `!is_bare()` instead"] fn is_signed(&self) -> Option { None } - /// Returns `true` if this `Extrinsic` is bare. - fn is_bare(&self) -> bool { - #[allow(deprecated)] - !self - .is_signed() - .expect("`is_signed` must return `Some` on production extrinsics; qed") - } - - /// Create a new old-school extrinsic, either a bare extrinsic if `_signed_data` is `None` or - /// a signed transaction is it is `Some`. - #[deprecated = "Use `new_inherent` or the `CreateTransaction` trait instead"] + /// Create new instance of the extrinsic. + /// + /// Extrinsics can be split into: + /// 1. Inherents (no signature; created by validators during block production) + /// 2. Unsigned Transactions (no signature; represent "system calls" or other special kinds of + /// calls) 3. Signed Transactions (with signature; a regular transactions with known origin) fn new(_call: Self::Call, _signed_data: Option) -> Option { None } - - /// Create a new inherent extrinsic. - fn new_inherent(function: Self::Call) -> Self { - #[allow(deprecated)] - Self::new(function, None).expect("Extrinsic must provide inherents; qed") - } } /// Something that acts like a [`SignaturePayload`](Extrinsic::SignaturePayload) of an @@ -1389,8 +1371,7 @@ pub trait ExtrinsicMetadata { const VERSION: u8; /// Signed extensions attached to this `Extrinsic`. - // TODO: metadata-v16: rename to `Extension`. - type Extra; + type SignedExtensions: SignedExtension; } /// Extract the hashing type for a block. @@ -1475,8 +1456,6 @@ pub trait Dispatchable { -> crate::DispatchResultWithInfo; } -/// Shortcut to reference the `Origin` type of a `Dispatchable`. -pub type OriginOf = ::RuntimeOrigin; /// Shortcut to reference the `Info` type of a `Dispatchable`. pub type DispatchInfoOf = ::Info; /// Shortcut to reference the `PostInfo` type of a `Dispatchable`. @@ -1495,49 +1474,8 @@ impl Dispatchable for () { } } -/// Dispatchable impl containing an arbitrary value which panics if it actually is dispatched. -#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct FakeDispatchable(pub Inner); -impl From for FakeDispatchable { - fn from(inner: Inner) -> Self { - Self(inner) - } -} -impl FakeDispatchable { - /// Take `self` and return the underlying inner value. - pub fn deconstruct(self) -> Inner { - self.0 - } -} -impl AsRef for FakeDispatchable { - fn as_ref(&self) -> &Inner { - &self.0 - } -} - -impl Dispatchable for FakeDispatchable { - type RuntimeOrigin = (); - type Config = (); - type Info = (); - type PostInfo = (); - fn dispatch( - self, - _origin: Self::RuntimeOrigin, - ) -> crate::DispatchResultWithInfo { - panic!("This implementation should not be used for actual dispatch."); - } -} - -/// Runtime Origin which includes a System Origin variant whose `AccountId` is the parameter. -pub trait AsSystemOriginSigner { - /// Extract a reference of the inner value of the System `Origin::Signed` variant, if self has - /// that variant. - fn as_system_origin_signer(&self) -> Option<&AccountId>; -} - /// Means by which a transaction may be extended. This type embodies both the data and the logic /// that should be additionally associated with the transaction. It should be plain old data. -#[deprecated = "Use `TransactionExtension` instead."] pub trait SignedExtension: Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo { @@ -1555,7 +1493,7 @@ pub trait SignedExtension: /// Any additional data that will go into the signed payload. This may be created dynamically /// from the transaction using the `additional_signed` function. - type AdditionalSigned: Codec + TypeInfo; + type AdditionalSigned: Encode + TypeInfo; /// The type that encodes information that can be passed from pre_dispatch to post-dispatch. type Pre; @@ -1594,6 +1532,38 @@ pub trait SignedExtension: len: usize, ) -> Result; + /// Validate an unsigned transaction for the transaction queue. + /// + /// This function can be called frequently by the transaction queue + /// to obtain transaction validity against current state. + /// It should perform all checks that determine a valid unsigned transaction, + /// and quickly eliminate ones that are stale or incorrect. + /// + /// Make sure to perform the same checks in `pre_dispatch_unsigned` function. + fn validate_unsigned( + _call: &Self::Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> TransactionValidity { + Ok(ValidTransaction::default()) + } + + /// Do any pre-flight stuff for a unsigned transaction. + /// + /// Note this function by default delegates to `validate_unsigned`, so that + /// all checks performed for the transaction queue are also performed during + /// the dispatch phase (applying the extrinsic). + /// + /// If you ever override this function, you need to make sure to always + /// perform the same validation as in `validate_unsigned`. + fn pre_dispatch_unsigned( + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result<(), TransactionValidityError> { + Self::validate_unsigned(call, info, len).map(|_| ()).map_err(Into::into) + } + /// Do any post-flight stuff for an extrinsic. /// /// If the transaction is signed, then `_pre` will contain the output of `pre_dispatch`, @@ -1624,47 +1594,126 @@ pub trait SignedExtension: /// /// As a [`SignedExtension`] can be a tuple of [`SignedExtension`]s we need to return a `Vec` /// that holds the metadata of each one. Each individual `SignedExtension` must return - /// *exactly* one [`TransactionExtensionMetadata`]. + /// *exactly* one [`SignedExtensionMetadata`]. /// /// This method provides a default implementation that returns a vec containing a single - /// [`TransactionExtensionMetadata`]. - fn metadata() -> Vec { - sp_std::vec![TransactionExtensionMetadata { + /// [`SignedExtensionMetadata`]. + fn metadata() -> Vec { + sp_std::vec![SignedExtensionMetadata { identifier: Self::IDENTIFIER, ty: scale_info::meta_type::(), additional_signed: scale_info::meta_type::() }] } +} + +/// Information about a [`SignedExtension`] for the runtime metadata. +pub struct SignedExtensionMetadata { + /// The unique identifier of the [`SignedExtension`]. + pub identifier: &'static str, + /// The type of the [`SignedExtension`]. + pub ty: MetaType, + /// The type of the [`SignedExtension`] additional signed data for the payload. + pub additional_signed: MetaType, +} + +#[impl_for_tuples(1, 12)] +impl SignedExtension for Tuple { + for_tuples!( where #( Tuple: SignedExtension )* ); + type AccountId = AccountId; + type Call = Call; + const IDENTIFIER: &'static str = "You should call `identifier()`!"; + for_tuples!( type AdditionalSigned = ( #( Tuple::AdditionalSigned ),* ); ); + for_tuples!( type Pre = ( #( Tuple::Pre ),* ); ); + + fn additional_signed(&self) -> Result { + Ok(for_tuples!( ( #( Tuple.additional_signed()? ),* ) )) + } + + fn validate( + &self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> TransactionValidity { + let valid = ValidTransaction::default(); + for_tuples!( #( let valid = valid.combine_with(Tuple.validate(who, call, info, len)?); )* ); + Ok(valid) + } + + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + Ok(for_tuples!( ( #( Tuple.pre_dispatch(who, call, info, len)? ),* ) )) + } - /// Validate an unsigned transaction for the transaction queue. - /// - /// This function can be called frequently by the transaction queue - /// to obtain transaction validity against current state. - /// It should perform all checks that determine a valid unsigned transaction, - /// and quickly eliminate ones that are stale or incorrect. fn validate_unsigned( - _call: &Self::Call, - _info: &DispatchInfoOf, - _len: usize, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, ) -> TransactionValidity { - Ok(ValidTransaction::default()) + let valid = ValidTransaction::default(); + for_tuples!( #( let valid = valid.combine_with(Tuple::validate_unsigned(call, info, len)?); )* ); + Ok(valid) } - /// Do any pre-flight stuff for an unsigned transaction. - /// - /// Note this function by default delegates to `validate_unsigned`, so that - /// all checks performed for the transaction queue are also performed during - /// the dispatch phase (applying the extrinsic). - /// - /// If you ever override this function, you need not perform the same validation as in - /// `validate_unsigned`. fn pre_dispatch_unsigned( - _call: &Self::Call, - _info: &DispatchInfoOf, - _len: usize, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, ) -> Result<(), TransactionValidityError> { + for_tuples!( #( Tuple::pre_dispatch_unsigned(call, info, len)?; )* ); Ok(()) } + + fn post_dispatch( + pre: Option, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, + len: usize, + result: &DispatchResult, + ) -> Result<(), TransactionValidityError> { + match pre { + Some(x) => { + for_tuples!( #( Tuple::post_dispatch(Some(x.Tuple), info, post_info, len, result)?; )* ); + }, + None => { + for_tuples!( #( Tuple::post_dispatch(None, info, post_info, len, result)?; )* ); + }, + } + Ok(()) + } + + fn metadata() -> Vec { + let mut ids = Vec::new(); + for_tuples!( #( ids.extend(Tuple::metadata()); )* ); + ids + } +} + +impl SignedExtension for () { + type AccountId = u64; + type AdditionalSigned = (); + type Call = (); + type Pre = (); + const IDENTIFIER: &'static str = "UnitSignedExtension"; + fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { + Ok(()) + } + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + self.validate(who, call, info, len).map(|_| ()) + } } /// An "executable" piece of information, used by the standard Substrate Executive in order to @@ -1713,7 +1762,6 @@ pub trait GetNodeBlockType { /// function is called right before dispatching the call wrapped by an unsigned extrinsic. The /// [`validate_unsigned`](Self::validate_unsigned) function is mainly being used in the context of /// the transaction pool to check the validity of the call wrapped by an unsigned extrinsic. -// TODO: Rename to ValidateBareTransaction (or just remove). pub trait ValidateUnsigned { /// The call to validate type Call; diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/as_transaction_extension.rs b/substrate/primitives/runtime/src/traits/transaction_extension/as_transaction_extension.rs deleted file mode 100644 index a834e88c0b4..00000000000 --- a/substrate/primitives/runtime/src/traits/transaction_extension/as_transaction_extension.rs +++ /dev/null @@ -1,133 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! The [AsTransactionExtension] adapter struct for adapting [SignedExtension]s to -//! [TransactionExtension]s. - -#![allow(deprecated)] - -use scale_info::TypeInfo; -use sp_core::RuntimeDebug; - -use crate::{ - traits::{AsSystemOriginSigner, SignedExtension, ValidateResult}, - InvalidTransaction, -}; - -use super::*; - -/// Adapter to use a `SignedExtension` in the place of a `TransactionExtension`. -#[derive(TypeInfo, Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)] -#[deprecated = "Convert your SignedExtension to a TransactionExtension."] -pub struct AsTransactionExtension(pub SE); - -impl Default for AsTransactionExtension { - fn default() -> Self { - Self(SE::default()) - } -} - -impl From for AsTransactionExtension { - fn from(value: SE) -> Self { - Self(value) - } -} - -impl TransactionExtensionBase for AsTransactionExtension { - const IDENTIFIER: &'static str = SE::IDENTIFIER; - type Implicit = SE::AdditionalSigned; - - fn implicit(&self) -> Result { - self.0.additional_signed() - } - fn metadata() -> Vec { - SE::metadata() - } -} - -impl TransactionExtension - for AsTransactionExtension -where - ::RuntimeOrigin: AsSystemOriginSigner + Clone, -{ - type Val = (); - type Pre = SE::Pre; - - fn validate( - &self, - origin: ::RuntimeOrigin, - call: &SE::Call, - info: &DispatchInfoOf, - len: usize, - _context: &mut Context, - _self_implicit: Self::Implicit, - _inherited_implication: &impl Encode, - ) -> ValidateResult { - let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?; - let r = self.0.validate(who, call, info, len)?; - Ok((r, (), origin)) - } - - fn prepare( - self, - _: (), - origin: &::RuntimeOrigin, - call: &SE::Call, - info: &DispatchInfoOf, - len: usize, - _context: &Context, - ) -> Result { - let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?; - self.0.pre_dispatch(who, call, info, len) - } - - fn post_dispatch( - pre: Self::Pre, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, - len: usize, - result: &DispatchResult, - _context: &Context, - ) -> Result<(), TransactionValidityError> { - SE::post_dispatch(Some(pre), info, post_info, len, result) - } - - fn validate_bare_compat( - call: &SE::Call, - info: &DispatchInfoOf, - len: usize, - ) -> TransactionValidity { - SE::validate_unsigned(call, info, len) - } - - fn pre_dispatch_bare_compat( - call: &SE::Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result<(), TransactionValidityError> { - SE::pre_dispatch_unsigned(call, info, len) - } - - fn post_dispatch_bare_compat( - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, - len: usize, - result: &DispatchResult, - ) -> Result<(), TransactionValidityError> { - SE::post_dispatch(None, info, post_info, len, result) - } -} diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/dispatch_transaction.rs b/substrate/primitives/runtime/src/traits/transaction_extension/dispatch_transaction.rs deleted file mode 100644 index 8efa586aa0e..00000000000 --- a/substrate/primitives/runtime/src/traits/transaction_extension/dispatch_transaction.rs +++ /dev/null @@ -1,141 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! The [DispatchTransaction] trait. - -use super::*; - -/// Single-function utility trait with a blanket impl over [TransactionExtension] in order to -/// provide transaction dispatching functionality. We avoid implementing this directly on the trait -/// since we never want it to be overriden by the trait implementation. -pub trait DispatchTransaction { - /// The origin type of the transaction. - type Origin; - /// The info type. - type Info; - /// The resultant type. - type Result; - /// The `Val` of the extension. - type Val; - /// The `Pre` of the extension. - type Pre; - /// Just validate a transaction. - /// - /// The is basically the same as [validate](TransactionExtension::validate), except that there - /// is no need to supply the bond data. - fn validate_only( - &self, - origin: Self::Origin, - call: &Call, - info: &Self::Info, - len: usize, - ) -> Result<(ValidTransaction, Self::Val, Self::Origin), TransactionValidityError>; - /// Prepare and validate a transaction, ready for dispatch. - fn validate_and_prepare( - self, - origin: Self::Origin, - call: &Call, - info: &Self::Info, - len: usize, - ) -> Result<(Self::Pre, Self::Origin), TransactionValidityError>; - /// Dispatch a transaction with the given base origin and call. - fn dispatch_transaction( - self, - origin: Self::Origin, - call: Call, - info: &Self::Info, - len: usize, - ) -> Self::Result; - /// Do everything which would be done in a [dispatch_transaction](Self::dispatch_transaction), - /// but instead of executing the call, execute `substitute` instead. Since this doesn't actually - /// dispatch the call, it doesn't need to consume it and so `call` can be passed as a reference. - fn test_run( - self, - origin: Self::Origin, - call: &Call, - info: &Self::Info, - len: usize, - substitute: impl FnOnce( - Self::Origin, - ) -> crate::DispatchResultWithInfo<::PostInfo>, - ) -> Self::Result; -} - -impl, Call: Dispatchable + Encode> DispatchTransaction - for T -{ - type Origin = ::RuntimeOrigin; - type Info = DispatchInfoOf; - type Result = crate::ApplyExtrinsicResultWithInfo>; - type Val = T::Val; - type Pre = T::Pre; - - fn validate_only( - &self, - origin: Self::Origin, - call: &Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result<(ValidTransaction, T::Val, Self::Origin), TransactionValidityError> { - self.validate(origin, call, info, len, &mut (), self.implicit()?, call) - } - fn validate_and_prepare( - self, - origin: Self::Origin, - call: &Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result<(T::Pre, Self::Origin), TransactionValidityError> { - let (_, val, origin) = self.validate_only(origin, call, info, len)?; - let pre = self.prepare(val, &origin, &call, info, len, &())?; - Ok((pre, origin)) - } - fn dispatch_transaction( - self, - origin: ::RuntimeOrigin, - call: Call, - info: &DispatchInfoOf, - len: usize, - ) -> Self::Result { - let (pre, origin) = self.validate_and_prepare(origin, &call, info, len)?; - let res = call.dispatch(origin); - let post_info = res.unwrap_or_else(|err| err.post_info); - let pd_res = res.map(|_| ()).map_err(|e| e.error); - T::post_dispatch(pre, info, &post_info, len, &pd_res, &())?; - Ok(res) - } - fn test_run( - self, - origin: Self::Origin, - call: &Call, - info: &Self::Info, - len: usize, - substitute: impl FnOnce( - Self::Origin, - ) -> crate::DispatchResultWithInfo<::PostInfo>, - ) -> Self::Result { - let (pre, origin) = self.validate_and_prepare(origin, &call, info, len)?; - let res = substitute(origin); - let post_info = match res { - Ok(info) => info, - Err(err) => err.post_info, - }; - let pd_res = res.map(|_| ()).map_err(|e| e.error); - T::post_dispatch(pre, info, &post_info, len, &pd_res, &())?; - Ok(res) - } -} diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs deleted file mode 100644 index 69a0ba18adb..00000000000 --- a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs +++ /dev/null @@ -1,526 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! The transaction extension trait. - -use crate::{ - scale_info::{MetaType, StaticTypeInfo}, - transaction_validity::{TransactionValidity, TransactionValidityError, ValidTransaction}, - DispatchResult, -}; -use codec::{Codec, Decode, Encode}; -use impl_trait_for_tuples::impl_for_tuples; -#[doc(hidden)] -pub use sp_std::marker::PhantomData; -use sp_std::{self, fmt::Debug, prelude::*}; -use sp_weights::Weight; -use tuplex::{PopFront, PushBack}; - -use super::{DispatchInfoOf, Dispatchable, OriginOf, PostDispatchInfoOf}; - -mod as_transaction_extension; -mod dispatch_transaction; -#[allow(deprecated)] -pub use as_transaction_extension::AsTransactionExtension; -pub use dispatch_transaction::DispatchTransaction; - -/// Shortcut for the result value of the `validate` function. -pub type ValidateResult = - Result<(ValidTransaction, Val, OriginOf), TransactionValidityError>; - -/// Simple blanket implementation trait to denote the bounds of a type which can be contained within -/// a [`TransactionExtension`]. -pub trait TransactionExtensionInterior: - Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo -{ -} -impl - TransactionExtensionInterior for T -{ -} - -/// Base for [TransactionExtension]s; this contains the associated types and does not require any -/// generic parameterization. -pub trait TransactionExtensionBase: TransactionExtensionInterior { - /// Unique identifier of this signed extension. - /// - /// This will be exposed in the metadata to identify the signed extension used in an extrinsic. - const IDENTIFIER: &'static str; - - /// Any additional data which was known at the time of transaction construction and can be - /// useful in authenticating the transaction. This is determined dynamically in part from the - /// on-chain environment using the `implicit` function and not directly contained in the - /// transaction itself and therefore is considered "implicit". - type Implicit: Codec + StaticTypeInfo; - - /// Determine any additional data which was known at the time of transaction construction and - /// can be useful in authenticating the transaction. The expected usage of this is to include in - /// any data which is signed and verified as part of transactiob validation. Also perform any - /// pre-signature-verification checks and return an error if needed. - fn implicit(&self) -> Result { - use crate::InvalidTransaction::IndeterminateImplicit; - Ok(Self::Implicit::decode(&mut &[][..]).map_err(|_| IndeterminateImplicit)?) - } - - /// The weight consumed by executing this extension instance fully during transaction dispatch. - fn weight(&self) -> Weight { - Weight::zero() - } - - /// Returns the metadata for this extension. - /// - /// As a [`TransactionExtension`] can be a tuple of [`TransactionExtension`]s we need to return - /// a `Vec` that holds the metadata of each one. Each individual `TransactionExtension` must - /// return *exactly* one [`TransactionExtensionMetadata`]. - /// - /// This method provides a default implementation that returns a vec containing a single - /// [`TransactionExtensionMetadata`]. - fn metadata() -> Vec { - sp_std::vec![TransactionExtensionMetadata { - identifier: Self::IDENTIFIER, - ty: scale_info::meta_type::(), - // TODO: Metadata-v16: Rename to "implicit" - additional_signed: scale_info::meta_type::() - }] - } -} - -/// Means by which a transaction may be extended. This type embodies both the data and the logic -/// that should be additionally associated with the transaction. It should be plain old data. -/// -/// The simplest transaction extension would be the Unit type (and empty pipeline) `()`. This -/// executes no additional logic and implies a dispatch of the transaction's call using the -/// inherited origin (either `None` or `Signed`, depending on whether this is a signed or general -/// transaction). -/// -/// Transaction extensions are capable of altering certain associated semantics: -/// -/// - They may define the origin with which the transaction's call should be dispatched. -/// - They may define various parameters used by the transction queue to determine under what -/// conditions the transaction should be retained and introduced on-chain. -/// - They may define whether this transaction is acceptable for introduction on-chain at all. -/// -/// Each of these semantics are defined by the `validate` function. -/// -/// **NOTE: Transaction extensions cannot under any circumctances alter the call itself.** -/// -/// Transaction extensions are capable of defining logic which is executed additionally to the -/// dispatch of the call: -/// -/// - They may define logic which must be executed prior to the dispatch of the call. -/// - They may also define logic which must be executed after the dispatch of the call. -/// -/// Each of these semantics are defined by the `prepare` and `post_dispatch` functions respectively. -/// -/// Finally, transaction extensions may define additional data to help define the implications of -/// the logic they introduce. This additional data may be explicitly defined by the transaction -/// author (in which case it is included as part of the transaction body), or it may be implicitly -/// defined by the transaction extension based around the on-chain state (which the transaction -/// author is assumed to know). This data may be utilized by the above logic to alter how a node's -/// transaction queue treats this transaction. -/// -/// ## Default implementations -/// -/// Of the 5 functions in this trait, 3 of them must return a value of an associated type on -/// success, and none of these types implement [Default] or anything like it. This means that -/// default implementations cannot be provided for these functions. However, a macro is provided -/// [impl_tx_ext_default](crate::impl_tx_ext_default) which is capable of generating default -/// implementations for each of these 3 functions. If you do not wish to introduce additional logic -/// into the transaction pipeline, then it is recommended that you use this macro to implement these -/// functions. -/// -/// ## Pipelines, Inherited Implications, and Authorized Origins -/// -/// Requiring a single transaction extension to define all of the above semantics would be -/// cumbersome and would lead to a lot of boilerplate. Instead, transaction extensions are -/// aggregated into pipelines, which are tuples of transaction extensions. Each extension in the -/// pipeline is executed in order, and the output of each extension is aggregated and/or relayed as -/// the input to the next extension in the pipeline. -/// -/// This ordered composition happens with all datatypes ([Val](TransactionExtension::Val), -/// [Pre](TransactionExtension::Pre) and [Implicit](TransactionExtensionBase::Implicit)) as well as -/// all functions. There are important consequences stemming from how the composition affects the -/// meaning of the `origin` and `implication` parameters as well as the results. Whereas the -/// [prepare](TransactionExtension::prepare) and -/// [post_dispatch](TransactionExtension::post_dispatch) functions are clear in their meaning, the -/// [validate](TransactionExtension::validate) function is fairly sophisticated and warrants -/// further explanation. -/// -/// Firstly, the `origin` parameter. The `origin` passed into the first item in a pipeline is simply -/// that passed into the tuple itself. It represents an authority who has authorized the implication -/// of the transaction, as of the extension it has been passed into *and any further extensions it -/// may pass though, all the way to, and including, the transaction's dispatch call itself. Each -/// following item in the pipeline is passed the origin which the previous item returned. The origin -/// returned from the final item in the pipeline is the origin which is returned by the tuple -/// itself. -/// -/// This means that if a constituent extension returns a different origin to the one it was called -/// with, then (assuming no other extension changes it further) *this new origin will be used for -/// all extensions following it in the pipeline, and will be returned from the pipeline to be used -/// as the origin for the call's dispatch*. The call itself as well as all these extensions -/// following may each imply consequence for this origin. We call this the *inherited implication*. -/// -/// The *inherited implication* is the cumulated on-chain effects born by whatever origin is -/// returned. It is expressed to the [validate](TransactionExtension::validate) function only as the -/// `implication` argument which implements the [Encode] trait. A transaction extension may define -/// its own implications through its own fields and the -/// [implicit](TransactionExtensionBase::implicit) function. This is only utilized by extensions -/// which preceed it in a pipeline or, if the transaction is an old-school signed trasnaction, the -/// underlying transaction verification logic. -/// -/// **The inherited implication passed as the `implication` parameter to -/// [validate](TransactionExtension::validate) does not include the extension's inner data itself -/// nor does it include the result of the extension's `implicit` function.** If you both provide an -/// implication and rely on the implication, then you need to manually aggregate your extensions -/// implication with the aggregated implication passed in. -pub trait TransactionExtension: TransactionExtensionBase { - /// The type that encodes information that can be passed from validate to prepare. - type Val; - - /// The type that encodes information that can be passed from prepare to post-dispatch. - type Pre; - - /// Validate a transaction for the transaction queue. - /// - /// This function can be called frequently by the transaction queue to obtain transaction - /// validity against current state. It should perform all checks that determine a valid - /// transaction, that can pay for its execution and quickly eliminate ones that are stale or - /// incorrect. - /// - /// Parameters: - /// - `origin`: The origin of the transaction which this extension inherited; coming from an - /// "old-school" *signed transaction*, this will be a system `RawOrigin::Signed` value. If the - /// transaction is a "new-school" *General Transaction*, then this will be a system - /// `RawOrigin::None` value. If this extension is an item in a composite, then it could be - /// anything which was previously returned as an `origin` value in the result of a `validate` - /// call. - /// - `call`: The `Call` wrapped by this extension. - /// - `info`: Information concerning, and inherent to, the transaction's call. - /// - `len`: The total length of the encoded transaction. - /// - `inherited_implication`: The *implication* which this extension inherits. This is a tuple - /// of the transaction's call and some additional opaque-but-encodable data. Coming directly - /// from a transaction, the latter is [()]. However, if this extension is expressed as part of - /// a composite type, then the latter component is equal to any further implications to which - /// the returned `origin` could potentially apply. See Pipelines, Inherited Implications, and - /// Authorized Origins for more information. - /// - `context`: Some opaque mutable context, as yet unused. - /// - /// Returns a [ValidateResult], which is a [Result] whose success type is a tuple of - /// [ValidTransaction] (defining useful metadata for the transaction queue), the [Self::Val] - /// token of this transaction, which gets passed into [prepare](TransactionExtension::prepare), - /// and the origin of the transaction, which gets passed into - /// [prepare](TransactionExtension::prepare) and is ultimately used for dispatch. - fn validate( - &self, - origin: OriginOf, - call: &Call, - info: &DispatchInfoOf, - len: usize, - context: &mut Context, - self_implicit: Self::Implicit, - inherited_implication: &impl Encode, - ) -> ValidateResult; - - /// Do any pre-flight stuff for a transaction after validation. - /// - /// This is for actions which do not happen in the transaction queue but only immediately prior - /// to the point of dispatch on-chain. This should not return an error, since errors should - /// already have been identified during the [validate](TransactionExtension::validate) call. If - /// an error is returned, the transaction will be considered invalid but no state changes will - /// happen and therefore work done in [validate](TransactionExtension::validate) will not be - /// paid for. - /// - /// Unlike `validate`, this function may consume `self`. - /// - /// Parameters: - /// - `val`: `Self::Val` returned by the result of the `validate` call. - /// - `origin`: The origin returned by the result of the `validate` call. - /// - `call`: The `Call` wrapped by this extension. - /// - `info`: Information concerning, and inherent to, the transaction's call. - /// - `len`: The total length of the encoded transaction. - /// - `context`: Some opaque mutable context, as yet unused. - /// - /// Returns a [Self::Pre] value on success, which gets passed into - /// [post_dispatch](TransactionExtension::post_dispatch) and after the call is dispatched. - /// - /// IMPORTANT: **Checks made in validation need not be repeated here.** - fn prepare( - self, - val: Self::Val, - origin: &OriginOf, - call: &Call, - info: &DispatchInfoOf, - len: usize, - context: &Context, - ) -> Result; - - /// Do any post-flight stuff for an extrinsic. - /// - /// `_pre` contains the output of `prepare`. - /// - /// This gets given the `DispatchResult` `_result` from the extrinsic and can, if desired, - /// introduce a `TransactionValidityError`, causing the block to become invalid for including - /// it. - /// - /// Parameters: - /// - `pre`: `Self::Pre` returned by the result of the `prepare` call prior to dispatch. - /// - `info`: Information concerning, and inherent to, the transaction's call. - /// - `post_info`: Information concerning the dispatch of the transaction's call. - /// - `len`: The total length of the encoded transaction. - /// - `result`: The result of the dispatch. - /// - `context`: Some opaque mutable context, as yet unused. - /// - /// WARNING: It is dangerous to return an error here. To do so will fundamentally invalidate the - /// transaction and any block that it is included in, causing the block author to not be - /// compensated for their work in validating the transaction or producing the block so far. It - /// can only be used safely when you *know* that the transaction is one that would only be - /// introduced by the current block author. - fn post_dispatch( - _pre: Self::Pre, - _info: &DispatchInfoOf, - _post_info: &PostDispatchInfoOf, - _len: usize, - _result: &DispatchResult, - _context: &Context, - ) -> Result<(), TransactionValidityError> { - Ok(()) - } - - /// Compatibility function for supporting the `SignedExtension::validate_unsigned` function. - /// - /// DO NOT USE! THIS MAY BE REMOVED AT ANY TIME! - #[deprecated = "Only for compatibility. DO NOT USE."] - fn validate_bare_compat( - _call: &Call, - _info: &DispatchInfoOf, - _len: usize, - ) -> TransactionValidity { - Ok(ValidTransaction::default()) - } - - /// Compatibility function for supporting the `SignedExtension::pre_dispatch_unsigned` function. - /// - /// DO NOT USE! THIS MAY BE REMOVED AT ANY TIME! - #[deprecated = "Only for compatibility. DO NOT USE."] - fn pre_dispatch_bare_compat( - _call: &Call, - _info: &DispatchInfoOf, - _len: usize, - ) -> Result<(), TransactionValidityError> { - Ok(()) - } - - /// Compatibility function for supporting the `SignedExtension::post_dispatch` function where - /// `pre` is `None`. - /// - /// DO NOT USE! THIS MAY BE REMOVED AT ANY TIME! - #[deprecated = "Only for compatibility. DO NOT USE."] - fn post_dispatch_bare_compat( - _info: &DispatchInfoOf, - _post_info: &PostDispatchInfoOf, - _len: usize, - _result: &DispatchResult, - ) -> Result<(), TransactionValidityError> { - Ok(()) - } -} - -/// Implict -#[macro_export] -macro_rules! impl_tx_ext_default { - ($call:ty ; $context:ty ; , $( $rest:tt )*) => { - impl_tx_ext_default!{$call ; $context ; $( $rest )*} - }; - ($call:ty ; $context:ty ; validate $( $rest:tt )*) => { - fn validate( - &self, - origin: $crate::traits::OriginOf<$call>, - _call: &$call, - _info: &$crate::traits::DispatchInfoOf<$call>, - _len: usize, - _context: &mut $context, - _self_implicit: Self::Implicit, - _inherited_implication: &impl $crate::codec::Encode, - ) -> $crate::traits::ValidateResult { - Ok((Default::default(), Default::default(), origin)) - } - impl_tx_ext_default!{$call ; $context ; $( $rest )*} - }; - ($call:ty ; $context:ty ; prepare $( $rest:tt )*) => { - fn prepare( - self, - _val: Self::Val, - _origin: &$crate::traits::OriginOf<$call>, - _call: &$call, - _info: &$crate::traits::DispatchInfoOf<$call>, - _len: usize, - _context: & $context, - ) -> Result { - Ok(Default::default()) - } - impl_tx_ext_default!{$call ; $context ; $( $rest )*} - }; - ($call:ty ; $context:ty ;) => {}; -} - -/// Information about a [`TransactionExtension`] for the runtime metadata. -pub struct TransactionExtensionMetadata { - /// The unique identifier of the [`TransactionExtension`]. - pub identifier: &'static str, - /// The type of the [`TransactionExtension`]. - pub ty: MetaType, - /// The type of the [`TransactionExtension`] additional signed data for the payload. - // TODO: Rename "implicit" - pub additional_signed: MetaType, -} - -#[impl_for_tuples(1, 12)] -impl TransactionExtensionBase for Tuple { - for_tuples!( where #( Tuple: TransactionExtensionBase )* ); - const IDENTIFIER: &'static str = "Use `metadata()`!"; - for_tuples!( type Implicit = ( #( Tuple::Implicit ),* ); ); - fn implicit(&self) -> Result { - Ok(for_tuples!( ( #( Tuple.implicit()? ),* ) )) - } - fn weight(&self) -> Weight { - let mut weight = Weight::zero(); - for_tuples!( #( weight += Tuple.weight(); )* ); - weight - } - fn metadata() -> Vec { - let mut ids = Vec::new(); - for_tuples!( #( ids.extend(Tuple::metadata()); )* ); - ids - } -} - -#[impl_for_tuples(1, 12)] -impl TransactionExtension for Tuple { - for_tuples!( where #( Tuple: TransactionExtension )* ); - for_tuples!( type Val = ( #( Tuple::Val ),* ); ); - for_tuples!( type Pre = ( #( Tuple::Pre ),* ); ); - - fn validate( - &self, - origin: ::RuntimeOrigin, - call: &Call, - info: &DispatchInfoOf, - len: usize, - context: &mut Context, - self_implicit: Self::Implicit, - inherited_implication: &impl Encode, - ) -> Result< - (ValidTransaction, Self::Val, ::RuntimeOrigin), - TransactionValidityError, - > { - let valid = ValidTransaction::default(); - let val = (); - let following_explicit_implications = for_tuples!( ( #( &self.Tuple ),* ) ); - let following_implicit_implications = self_implicit; - - for_tuples!(#( - // Implication of this pipeline element not relevant for later items, so we pop it. - let (_item, following_explicit_implications) = following_explicit_implications.pop_front(); - let (item_implicit, following_implicit_implications) = following_implicit_implications.pop_front(); - let (item_valid, item_val, origin) = { - let implications = ( - // The first is the implications born of the fact we return the mutated - // origin. - inherited_implication, - // This is the explicitly made implication born of the fact the new origin is - // passed into the next items in this pipeline-tuple. - &following_explicit_implications, - // This is the implicitly made implication born of the fact the new origin is - // passed into the next items in this pipeline-tuple. - &following_implicit_implications, - ); - Tuple.validate(origin, call, info, len, context, item_implicit, &implications)? - }; - let valid = valid.combine_with(item_valid); - let val = val.push_back(item_val); - )* ); - Ok((valid, val, origin)) - } - - fn prepare( - self, - val: Self::Val, - origin: &::RuntimeOrigin, - call: &Call, - info: &DispatchInfoOf, - len: usize, - context: &Context, - ) -> Result { - Ok(for_tuples!( ( #( - Tuple::prepare(self.Tuple, val.Tuple, origin, call, info, len, context)? - ),* ) )) - } - - fn post_dispatch( - pre: Self::Pre, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, - len: usize, - result: &DispatchResult, - context: &Context, - ) -> Result<(), TransactionValidityError> { - for_tuples!( #( Tuple::post_dispatch(pre.Tuple, info, post_info, len, result, context)?; )* ); - Ok(()) - } -} - -impl TransactionExtensionBase for () { - const IDENTIFIER: &'static str = "UnitTransactionExtension"; - type Implicit = (); - fn implicit(&self) -> sp_std::result::Result { - Ok(()) - } - fn weight(&self) -> Weight { - Weight::zero() - } -} - -impl TransactionExtension for () { - type Val = (); - type Pre = (); - fn validate( - &self, - origin: ::RuntimeOrigin, - _call: &Call, - _info: &DispatchInfoOf, - _len: usize, - _context: &mut Context, - _self_implicit: Self::Implicit, - _inherited_implication: &impl Encode, - ) -> Result< - (ValidTransaction, (), ::RuntimeOrigin), - TransactionValidityError, - > { - Ok((ValidTransaction::default(), (), origin)) - } - fn prepare( - self, - _val: (), - _origin: &::RuntimeOrigin, - _call: &Call, - _info: &DispatchInfoOf, - _len: usize, - _context: &Context, - ) -> Result<(), TransactionValidityError> { - Ok(()) - } -} diff --git a/substrate/primitives/runtime/src/transaction_validity.rs b/substrate/primitives/runtime/src/transaction_validity.rs index 24124128083..83694849382 100644 --- a/substrate/primitives/runtime/src/transaction_validity.rs +++ b/substrate/primitives/runtime/src/transaction_validity.rs @@ -82,8 +82,6 @@ pub enum InvalidTransaction { MandatoryValidation, /// The sending address is disabled or known to be invalid. BadSigner, - /// The implicit data was unable to be calculated. - IndeterminateImplicit, } impl InvalidTransaction { @@ -115,8 +113,6 @@ impl From for &'static str { "Transaction dispatch is mandatory; transactions must not be validated.", InvalidTransaction::Custom(_) => "InvalidTransaction custom error", InvalidTransaction::BadSigner => "Invalid signing address", - InvalidTransaction::IndeterminateImplicit => - "The implicit data was unable to be calculated", } } } @@ -342,7 +338,7 @@ pub struct ValidTransactionBuilder { impl ValidTransactionBuilder { /// Set the priority of a transaction. /// - /// Note that the final priority for `FRAME` is combined from all `TransactionExtension`s. + /// Note that the final priority for `FRAME` is combined from all `SignedExtension`s. /// Most likely for unsigned transactions you want the priority to be higher /// than for regular transactions. We recommend exposing a base priority for unsigned /// transactions as a runtime module parameter, so that the runtime can tune inter-module diff --git a/substrate/scripts/run_all_benchmarks.sh b/substrate/scripts/run_all_benchmarks.sh index fe5f89a5b56..6dd7cede319 100755 --- a/substrate/scripts/run_all_benchmarks.sh +++ b/substrate/scripts/run_all_benchmarks.sh @@ -107,19 +107,6 @@ for PALLET in "${PALLETS[@]}"; do FOLDER="$(echo "${PALLET#*_}" | tr '_' '-')"; WEIGHT_FILE="./frame/${FOLDER}/src/weights.rs" - - # Special handling of custom weight paths. - if [ "$PALLET" == "frame_system_extensions" ] || [ "$PALLET" == "frame-system-extensions" ] - then - WEIGHT_FILE="./frame/system/src/extensions/weights.rs" - elif [ "$PALLET" == "pallet_asset_conversion_tx_payment" ] || [ "$PALLET" == "pallet-asset-conversion-tx-payment" ] - then - WEIGHT_FILE="./frame/transaction-payment/asset-conversion-tx-payment/src/weights.rs" - elif [ "$PALLET" == "pallet_asset_tx_payment" ] || [ "$PALLET" == "pallet-asset-tx-payment" ] - then - WEIGHT_FILE="./frame/transaction-payment/asset-tx-payment/src/weights.rs" - fi - echo "[+] Benchmarking $PALLET with weight file $WEIGHT_FILE"; OUTPUT=$( diff --git a/substrate/test-utils/runtime/src/extrinsic.rs b/substrate/test-utils/runtime/src/extrinsic.rs index 7eb1839e97b..05ffb7db5d5 100644 --- a/substrate/test-utils/runtime/src/extrinsic.rs +++ b/substrate/test-utils/runtime/src/extrinsic.rs @@ -25,7 +25,7 @@ use codec::Encode; use frame_system::{CheckNonce, CheckWeight}; use sp_core::crypto::Pair as TraitPair; use sp_keyring::AccountKeyring; -use sp_runtime::{generic::Preamble, transaction_validity::TransactionPriority, Perbill}; +use sp_runtime::{transaction_validity::TransactionPriority, Perbill}; use sp_std::prelude::*; /// Transfer used in test substrate pallet. Extrinsic is created and signed using this data. @@ -66,11 +66,11 @@ impl TryFrom<&Extrinsic> for TransferData { match uxt { Extrinsic { function: RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest, value }), - preamble: Preamble::Signed(from, _, ((CheckNonce(nonce), ..), ..)), + signature: Some((from, _, (CheckNonce(nonce), ..))), } => Ok(TransferData { from: *from, to: *dest, amount: *value, nonce: *nonce }), Extrinsic { function: RuntimeCall::SubstrateTest(PalletCall::bench_call { transfer }), - preamble: Preamble::Bare, + signature: None, } => Ok(transfer.clone()), _ => Err(()), } @@ -190,17 +190,18 @@ impl ExtrinsicBuilder { /// Build `Extrinsic` using embedded parameters pub fn build(self) -> Extrinsic { if let Some(signer) = self.signer { - let tx_ext = ( - (CheckNonce::from(self.nonce.unwrap_or(0)), CheckWeight::new()), + let extra = ( + CheckNonce::from(self.nonce.unwrap_or(0)), + CheckWeight::new(), CheckSubstrateCall {}, ); let raw_payload = - SignedPayload::from_raw(self.function.clone(), tx_ext.clone(), (((), ()), ())); + SignedPayload::from_raw(self.function.clone(), extra.clone(), ((), (), ())); let signature = raw_payload.using_encoded(|e| signer.sign(e)); - Extrinsic::new_signed(self.function, signer.public(), signature, tx_ext) + Extrinsic::new_signed(self.function, signer.public(), signature, extra) } else { - Extrinsic::new_bare(self.function) + Extrinsic::new_unsigned(self.function) } } } diff --git a/substrate/test-utils/runtime/src/lib.rs b/substrate/test-utils/runtime/src/lib.rs index 7ec5f6722c4..63e0aa6e137 100644 --- a/substrate/test-utils/runtime/src/lib.rs +++ b/substrate/test-utils/runtime/src/lib.rs @@ -58,11 +58,9 @@ use sp_api::{decl_runtime_apis, impl_runtime_apis}; pub use sp_core::hash::H256; use sp_inherents::{CheckInherentsResult, InherentData}; use sp_runtime::{ - create_runtime_str, impl_opaque_keys, impl_tx_ext_default, - traits::{BlakeTwo256, Block as BlockT, DispatchInfoOf, Dispatchable, NumberFor, Verify}, - transaction_validity::{ - TransactionSource, TransactionValidity, TransactionValidityError, ValidTransaction, - }, + create_runtime_str, impl_opaque_keys, + traits::{BlakeTwo256, Block as BlockT, DispatchInfoOf, NumberFor, Verify}, + transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError}, ApplyExtrinsicResult, ExtrinsicInclusionMode, Perbill, }; #[cfg(any(feature = "std", test))] @@ -144,14 +142,13 @@ pub type Signature = sr25519::Signature; #[cfg(feature = "std")] pub type Pair = sp_core::sr25519::Pair; -// TODO: Remove after the Checks are migrated to TxExtension. -/// The extension to the basic transaction logic. -pub type TxExtension = ((CheckNonce, CheckWeight), CheckSubstrateCall); +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = (CheckNonce, CheckWeight, CheckSubstrateCall); /// The payload being signed in transactions. -pub type SignedPayload = sp_runtime::generic::SignedPayload; +pub type SignedPayload = sp_runtime::generic::SignedPayload; /// Unchecked extrinsic type as expected by this runtime. pub type Extrinsic = - sp_runtime::generic::UncheckedExtrinsic; + sp_runtime::generic::UncheckedExtrinsic; /// An identifier for an account on this system. pub type AccountId = ::Signer; @@ -246,7 +243,7 @@ impl sp_runtime::traits::Printable for CheckSubstrateCall { } impl sp_runtime::traits::Dispatchable for CheckSubstrateCall { - type RuntimeOrigin = RuntimeOrigin; + type RuntimeOrigin = CheckSubstrateCall; type Config = CheckSubstrateCall; type Info = CheckSubstrateCall; type PostInfo = CheckSubstrateCall; @@ -259,37 +256,42 @@ impl sp_runtime::traits::Dispatchable for CheckSubstrateCall { } } -impl sp_runtime::traits::TransactionExtensionBase for CheckSubstrateCall { - const IDENTIFIER: &'static str = "CheckSubstrateCall"; - type Implicit = (); -} -impl sp_runtime::traits::TransactionExtension - for CheckSubstrateCall -{ +impl sp_runtime::traits::SignedExtension for CheckSubstrateCall { + type AccountId = AccountId; + type Call = RuntimeCall; + type AdditionalSigned = (); type Pre = (); - type Val = (); - impl_tx_ext_default!(RuntimeCall; Context; prepare); + const IDENTIFIER: &'static str = "CheckSubstrateCall"; + + fn additional_signed( + &self, + ) -> sp_std::result::Result { + Ok(()) + } fn validate( &self, - origin: ::RuntimeOrigin, - call: &RuntimeCall, - _info: &DispatchInfoOf, + _who: &Self::AccountId, + call: &Self::Call, + _info: &DispatchInfoOf, _len: usize, - _context: &mut Context, - _self_implicit: Self::Implicit, - _inherited_implication: &impl Encode, - ) -> Result< - (ValidTransaction, Self::Val, ::RuntimeOrigin), - TransactionValidityError, - > { + ) -> TransactionValidity { log::trace!(target: LOG_TARGET, "validate"); - let v = match call { + match call { RuntimeCall::SubstrateTest(ref substrate_test_call) => - substrate_test_pallet::validate_runtime_call(substrate_test_call)?, - _ => Default::default(), - }; - Ok((v, (), origin)) + substrate_test_pallet::validate_runtime_call(substrate_test_call), + _ => Ok(Default::default()), + } + } + + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &sp_runtime::traits::DispatchInfoOf, + len: usize, + ) -> Result { + self.validate(who, call, info, len).map(drop) } } @@ -362,7 +364,6 @@ impl frame_system::pallet::Config for Runtime { type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = (); - type ExtensionsWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); type MaxConsumers = ConstU32<16>; @@ -671,7 +672,7 @@ impl_runtime_apis! { impl sp_offchain::OffchainWorkerApi for Runtime { fn offchain_worker(header: &::Header) { - let ext = Extrinsic::new_bare( + let ext = Extrinsic::new_unsigned( substrate_test_pallet::pallet::Call::storage_change{ key:b"some_key".encode(), value:Some(header.number.encode()) @@ -1024,7 +1025,7 @@ mod tests { use sp_core::{storage::well_known_keys::HEAP_PAGES, traits::CallContext}; use sp_keyring::AccountKeyring; use sp_runtime::{ - traits::{DispatchTransaction, Hash as _}, + traits::{Hash as _, SignedExtension}, transaction_validity::{InvalidTransaction, ValidTransaction}, }; use substrate_test_runtime_client::{ @@ -1173,33 +1174,31 @@ mod tests { fn check_substrate_check_signed_extension_works() { sp_tracing::try_init_simple(); new_test_ext().execute_with(|| { - let x: AccountId = sp_keyring::AccountKeyring::Alice.into(); + let x = sp_keyring::AccountKeyring::Alice.into(); let info = DispatchInfo::default(); let len = 0_usize; assert_eq!( CheckSubstrateCall {} - .validate_only( - Some(x).into(), + .validate( + &x, &ExtrinsicBuilder::new_call_with_priority(16).build().function, &info, - len, + len ) .unwrap() - .0 .priority, 16 ); assert_eq!( CheckSubstrateCall {} - .validate_only( - Some(x).into(), + .validate( + &x, &ExtrinsicBuilder::new_call_do_not_propagate().build().function, &info, - len, + len ) .unwrap() - .0 .propagate, false ); diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/template.hbs b/substrate/utils/frame/benchmarking-cli/src/pallet/template.hbs index a044049a0d6..1e5e294acba 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/template.hbs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/template.hbs @@ -22,11 +22,7 @@ use core::marker::PhantomData; /// Weight functions for `{{pallet}}`. pub struct WeightInfo(PhantomData); -{{#if (eq pallet "frame_system_extensions")}} -impl frame_system::ExtensionsWeightInfo for WeightInfo { -{{else}} impl {{pallet}}::WeightInfo for WeightInfo { -{{/if}} {{#each benchmarks as |benchmark|}} {{#each benchmark.comments as |comment|}} /// {{comment}} diff --git a/substrate/utils/frame/remote-externalities/src/lib.rs b/substrate/utils/frame/remote-externalities/src/lib.rs index d49479d9cda..c7399468da9 100644 --- a/substrate/utils/frame/remote-externalities/src/lib.rs +++ b/substrate/utils/frame/remote-externalities/src/lib.rs @@ -1204,9 +1204,8 @@ where #[cfg(test)] mod test_prelude { pub(crate) use super::*; - pub(crate) use sp_runtime::testing::{Block as RawBlock, MockCallU64}; - pub(crate) type UncheckedXt = sp_runtime::generic::UncheckedExtrinsic; - pub(crate) type Block = RawBlock; + pub(crate) use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper, H256 as Hash}; + pub(crate) type Block = RawBlock>; pub(crate) fn init_logger() { sp_tracing::try_init_simple(); diff --git a/substrate/utils/frame/rpc/client/src/lib.rs b/substrate/utils/frame/rpc/client/src/lib.rs index 4f4f4bbef56..221f260b156 100644 --- a/substrate/utils/frame/rpc/client/src/lib.rs +++ b/substrate/utils/frame/rpc/client/src/lib.rs @@ -199,15 +199,11 @@ where #[cfg(test)] mod tests { use super::*; - use sp_runtime::{ - generic::UncheckedExtrinsic, - testing::{Block as TBlock, Header, MockCallU64, H256}, - }; + use sp_runtime::testing::{Block as TBlock, ExtrinsicWrapper, Header, H256}; use std::sync::Arc; use tokio::sync::Mutex; - type UncheckedXt = UncheckedExtrinsic; - type Block = TBlock; + type Block = TBlock>; type BlockNumber = u64; type Hash = H256; diff --git a/templates/minimal/runtime/src/lib.rs b/templates/minimal/runtime/src/lib.rs index 6920511e276..91859cf4a2f 100644 --- a/templates/minimal/runtime/src/lib.rs +++ b/templates/minimal/runtime/src/lib.rs @@ -54,7 +54,7 @@ pub fn native_version() -> NativeVersion { NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } } -type TxExtension = ( +type SignedExtra = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -111,7 +111,7 @@ impl pallet_transaction_payment::Config for Runtime { impl pallet_minimal_template::Config for Runtime {} -type Block = frame::runtime::types_common::BlockOf; +type Block = frame::runtime::types_common::BlockOf; type Header = HeaderFor; type RuntimeExecutive = diff --git a/templates/parachain/runtime/Cargo.toml b/templates/parachain/runtime/Cargo.toml index 44e9341b568..9d9da2b4b97 100644 --- a/templates/parachain/runtime/Cargo.toml +++ b/templates/parachain/runtime/Cargo.toml @@ -149,7 +149,6 @@ runtime-benchmarks = [ "cumulus-pallet-session-benchmarking/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", "cumulus-primitives-core/runtime-benchmarks", - "cumulus-primitives-storage-weight-reclaim/runtime-benchmarks", "cumulus-primitives-utility/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", @@ -162,7 +161,6 @@ runtime-benchmarks = [ "pallet-parachain-template/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", diff --git a/templates/parachain/runtime/src/lib.rs b/templates/parachain/runtime/src/lib.rs index 74ecd751f67..89899d286bb 100644 --- a/templates/parachain/runtime/src/lib.rs +++ b/templates/parachain/runtime/src/lib.rs @@ -97,8 +97,8 @@ pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The extension to the basic transaction logic. -pub type TxExtension = ( +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -112,7 +112,7 @@ pub type TxExtension = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< @@ -353,7 +353,6 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; type OperationalFeeMultiplier = ConstU8<5>; - type WeightInfo = (); } impl pallet_sudo::Config for Runtime { @@ -531,7 +530,6 @@ construct_runtime!( mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] - [frame_system_extensions, SystemExtensionsBench::] [pallet_balances, Balances] [pallet_session, SessionBench::] [pallet_timestamp, Timestamp] @@ -715,7 +713,6 @@ impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; let mut list = Vec::::new(); @@ -731,7 +728,6 @@ impl_runtime_apis! { use frame_benchmarking::{BenchmarkError, Benchmarking, BenchmarkBatch}; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; impl frame_system_benchmarking::Config for Runtime { fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); diff --git a/templates/solochain/node/Cargo.toml b/templates/solochain/node/Cargo.toml index 5e50e6106c1..48bb511bfd1 100644 --- a/templates/solochain/node/Cargo.toml +++ b/templates/solochain/node/Cargo.toml @@ -76,7 +76,6 @@ default = [] runtime-benchmarks = [ "frame-benchmarking-cli/runtime-benchmarks", "frame-system/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "sc-service/runtime-benchmarks", "solochain-template-runtime/runtime-benchmarks", "sp-runtime/runtime-benchmarks", diff --git a/templates/solochain/node/src/benchmarking.rs b/templates/solochain/node/src/benchmarking.rs index 8710f303e1f..d1d8c2ccaba 100644 --- a/templates/solochain/node/src/benchmarking.rs +++ b/templates/solochain/node/src/benchmarking.rs @@ -109,7 +109,7 @@ pub fn create_benchmark_extrinsic( .checked_next_power_of_two() .map(|c| c / 2) .unwrap_or(2) as u64; - let tx_ext: runtime::TxExtension = ( + let extra: runtime::SignedExtra = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -121,12 +121,11 @@ pub fn create_benchmark_extrinsic( frame_system::CheckNonce::::from(nonce), frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(0), - ) - .into(); + ); let raw_payload = runtime::SignedPayload::from_raw( call.clone(), - tx_ext.clone(), + extra.clone(), ( (), runtime::VERSION.spec_version, @@ -144,7 +143,7 @@ pub fn create_benchmark_extrinsic( call, sp_runtime::AccountId32::from(sender.public()).into(), runtime::Signature::Sr25519(signature), - tx_ext, + extra, ) } diff --git a/templates/solochain/runtime/Cargo.toml b/templates/solochain/runtime/Cargo.toml index 706ea863d0f..a7fc0519ba2 100644 --- a/templates/solochain/runtime/Cargo.toml +++ b/templates/solochain/runtime/Cargo.toml @@ -130,7 +130,6 @@ runtime-benchmarks = [ "pallet-sudo/runtime-benchmarks", "pallet-template/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] diff --git a/templates/solochain/runtime/src/lib.rs b/templates/solochain/runtime/src/lib.rs index 303122da564..a8a5b7857e1 100644 --- a/templates/solochain/runtime/src/lib.rs +++ b/templates/solochain/runtime/src/lib.rs @@ -237,7 +237,6 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = IdentityFee; type LengthToFee = IdentityFee; type FeeMultiplierUpdate = ConstFeeMultiplier; - type WeightInfo = pallet_transaction_payment::weights::SubstrateWeight; } impl pallet_sudo::Config for Runtime { @@ -301,8 +300,8 @@ pub type Address = sp_runtime::MultiAddress; pub type Header = generic::Header; /// Block type as expected by this runtime. pub type Block = generic::Block; -/// The extension to the basic transaction logic. -pub type TxExtension = ( +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -321,9 +320,9 @@ type Migrations = (); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// The payload being signed in transactions. -pub type SignedPayload = generic::SignedPayload; +pub type SignedPayload = generic::SignedPayload; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, @@ -339,7 +338,6 @@ mod benches { frame_benchmarking::define_benchmarks!( [frame_benchmarking, BaselineBench::] [frame_system, SystemBench::] - [frame_system_extensions, SystemExtensionsBench::] [pallet_balances, Balances] [pallet_timestamp, Timestamp] [pallet_sudo, Sudo] @@ -524,7 +522,6 @@ impl_runtime_apis! { use frame_benchmarking::{baseline, Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use baseline::Pallet as BaselineBench; let mut list = Vec::::new(); @@ -541,7 +538,6 @@ impl_runtime_apis! { use frame_benchmarking::{baseline, Benchmarking, BenchmarkBatch}; use sp_storage::TrackedStorageKey; use frame_system_benchmarking::Pallet as SystemBench; - use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use baseline::Pallet as BaselineBench; impl frame_system_benchmarking::Config for Runtime {} -- GitLab From 878b5dd010d4b4dfc7927018cce249ff51e13f33 Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <49718502+alexggh@users.noreply.github.com> Date: Wed, 13 Mar 2024 16:28:14 +0200 Subject: [PATCH 035/187] Always print connectivity report (#3677) This is printed every 10 minutes, I see no reason why it shouldn't be in all the logs, it would give us valuable information about what is going on with node connectivity when validators come-back to us to report issues. Signed-off-by: Alexandru Gheorghe --- polkadot/node/network/gossip-support/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/node/network/gossip-support/src/lib.rs b/polkadot/node/network/gossip-support/src/lib.rs index 4dfdd1f7208..9f33cd5d8a3 100644 --- a/polkadot/node/network/gossip-support/src/lib.rs +++ b/polkadot/node/network/gossip-support/src/lib.rs @@ -508,7 +508,7 @@ where ); } let pretty = PrettyAuthorities(unconnected_authorities); - gum::debug!( + gum::info!( target: LOG_TARGET, ?connected_ratio, ?absolute_connected, -- GitLab From 256546b7b9033ea99eb22b92c1d4cdec64c56516 Mon Sep 17 00:00:00 2001 From: Andrei Eres Date: Wed, 13 Mar 2024 17:54:41 +0100 Subject: [PATCH 036/187] Add subsystems regression tests to CI (#3527) Fixes https://github.com/paritytech/polkadot-sdk/issues/3530 --- .gitlab/pipeline/test.yml | 12 +++ ...ilability-distribution-regression-bench.rs | 77 ++++++------------- .../availability-recovery-regression-bench.rs | 63 +++++---------- polkadot/node/subsystem-bench/src/lib/lib.rs | 1 + .../node/subsystem-bench/src/lib/usage.rs | 4 +- .../node/subsystem-bench/src/lib/utils.rs | 76 ++++++++++++++++++ 6 files changed, 134 insertions(+), 99 deletions(-) create mode 100644 polkadot/node/subsystem-bench/src/lib/utils.rs diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index 5c41a3e6e08..26e55e9385f 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -494,3 +494,15 @@ test-syscalls: printf "The x86_64 syscalls used by the worker binaries have changed. Please review if this is expected and update polkadot/scripts/list-syscalls/*-worker-syscalls as needed.\n"; fi allow_failure: false # this rarely triggers in practice + +subsystem-regression-tests: + stage: test + extends: + - .docker-env + - .common-refs + - .run-immediately + script: + - cargo test --profile=testnet -p polkadot-availability-recovery --test availability-recovery-regression-bench --features subsystem-benchmarks + tags: + - benchmark + allow_failure: true diff --git a/polkadot/node/network/availability-distribution/tests/availability-distribution-regression-bench.rs b/polkadot/node/network/availability-distribution/tests/availability-distribution-regression-bench.rs index 7a490d5e47f..bdab11298d5 100644 --- a/polkadot/node/network/availability-distribution/tests/availability-distribution-regression-bench.rs +++ b/polkadot/node/network/availability-distribution/tests/availability-distribution-regression-bench.rs @@ -26,13 +26,9 @@ use polkadot_subsystem_bench::{ availability::{benchmark_availability_write, prepare_test, TestDataAvailability, TestState}, configuration::TestConfiguration, - usage::BenchmarkUsage, + utils::{warm_up_and_benchmark, WarmUpOptions}, }; -const BENCH_COUNT: usize = 3; -const WARM_UP_COUNT: usize = 30; -const WARM_UP_PRECISION: f64 = 0.01; - fn main() -> Result<(), String> { let mut messages = vec![]; let mut config = TestConfiguration::default(); @@ -41,17 +37,33 @@ fn main() -> Result<(), String> { config.num_blocks = 3; config.generate_pov_sizes(); - warm_up(config.clone())?; - let usage = benchmark(config.clone()); + let usage = warm_up_and_benchmark( + WarmUpOptions::new(&[ + "availability-distribution", + "bitfield-distribution", + "availability-store", + ]), + || { + let mut state = TestState::new(&config); + let (mut env, _protocol_config) = + prepare_test(config.clone(), &mut state, TestDataAvailability::Write, false); + env.runtime().block_on(benchmark_availability_write( + "data_availability_write", + &mut env, + state, + )) + }, + )?; + println!("{}", usage); messages.extend(usage.check_network_usage(&[ - ("Received from peers", 4330.0, 0.05), - ("Sent to peers", 15900.0, 0.05), + ("Received from peers", 443.333, 0.05), + ("Sent to peers", 21818.555, 0.05), ])); messages.extend(usage.check_cpu_usage(&[ - ("availability-distribution", 0.025, 0.05), - ("bitfield-distribution", 0.085, 0.05), - ("availability-store", 0.180, 0.05), + ("availability-distribution", 0.011, 0.05), + ("bitfield-distribution", 0.029, 0.05), + ("availability-store", 0.232, 0.05), ])); if messages.is_empty() { @@ -61,44 +73,3 @@ fn main() -> Result<(), String> { Err("Regressions found".to_string()) } } - -fn warm_up(config: TestConfiguration) -> Result<(), String> { - println!("Warming up..."); - let mut prev_run: Option = None; - for _ in 0..WARM_UP_COUNT { - let curr = run(config.clone()); - if let Some(ref prev) = prev_run { - let av_distr_diff = - curr.cpu_usage_diff(prev, "availability-distribution").expect("Must exist"); - let bitf_distr_diff = - curr.cpu_usage_diff(prev, "bitfield-distribution").expect("Must exist"); - let av_store_diff = - curr.cpu_usage_diff(prev, "availability-store").expect("Must exist"); - if av_distr_diff < WARM_UP_PRECISION && - bitf_distr_diff < WARM_UP_PRECISION && - av_store_diff < WARM_UP_PRECISION - { - return Ok(()) - } - } - prev_run = Some(curr); - } - - Err("Can't warm up".to_string()) -} - -fn benchmark(config: TestConfiguration) -> BenchmarkUsage { - println!("Benchmarking..."); - let usages: Vec = (0..BENCH_COUNT).map(|_| run(config.clone())).collect(); - let usage = BenchmarkUsage::average(&usages); - println!("{}", usage); - usage -} - -fn run(config: TestConfiguration) -> BenchmarkUsage { - let mut state = TestState::new(&config); - let (mut env, _protocol_config) = - prepare_test(config.clone(), &mut state, TestDataAvailability::Write, false); - env.runtime() - .block_on(benchmark_availability_write("data_availability_write", &mut env, state)) -} diff --git a/polkadot/node/network/availability-recovery/tests/availability-recovery-regression-bench.rs b/polkadot/node/network/availability-recovery/tests/availability-recovery-regression-bench.rs index 30cc4d47ecc..42b1787e045 100644 --- a/polkadot/node/network/availability-recovery/tests/availability-recovery-regression-bench.rs +++ b/polkadot/node/network/availability-recovery/tests/availability-recovery-regression-bench.rs @@ -27,13 +27,9 @@ use polkadot_subsystem_bench::{ TestDataAvailability, TestState, }, configuration::TestConfiguration, - usage::BenchmarkUsage, + utils::{warm_up_and_benchmark, WarmUpOptions}, }; -const BENCH_COUNT: usize = 3; -const WARM_UP_COUNT: usize = 10; -const WARM_UP_PRECISION: f64 = 0.01; - fn main() -> Result<(), String> { let mut messages = vec![]; @@ -42,14 +38,27 @@ fn main() -> Result<(), String> { config.num_blocks = 3; config.generate_pov_sizes(); - warm_up(config.clone(), options.clone())?; - let usage = benchmark(config.clone(), options.clone()); + let usage = warm_up_and_benchmark(WarmUpOptions::new(&["availability-recovery"]), || { + let mut state = TestState::new(&config); + let (mut env, _protocol_config) = prepare_test( + config.clone(), + &mut state, + TestDataAvailability::Read(options.clone()), + false, + ); + env.runtime().block_on(benchmark_availability_read( + "data_availability_read", + &mut env, + state, + )) + })?; + println!("{}", usage); messages.extend(usage.check_network_usage(&[ - ("Received from peers", 102400.000, 0.05), - ("Sent to peers", 0.335, 0.05), + ("Received from peers", 307200.000, 0.05), + ("Sent to peers", 1.667, 0.05), ])); - messages.extend(usage.check_cpu_usage(&[("availability-recovery", 3.850, 0.05)])); + messages.extend(usage.check_cpu_usage(&[("availability-recovery", 11.500, 0.05)])); if messages.is_empty() { Ok(()) @@ -58,37 +67,3 @@ fn main() -> Result<(), String> { Err("Regressions found".to_string()) } } - -fn warm_up(config: TestConfiguration, options: DataAvailabilityReadOptions) -> Result<(), String> { - println!("Warming up..."); - let mut prev_run: Option = None; - for _ in 0..WARM_UP_COUNT { - let curr = run(config.clone(), options.clone()); - if let Some(ref prev) = prev_run { - let diff = curr.cpu_usage_diff(prev, "availability-recovery").expect("Must exist"); - if diff < WARM_UP_PRECISION { - return Ok(()) - } - } - prev_run = Some(curr); - } - - Err("Can't warm up".to_string()) -} - -fn benchmark(config: TestConfiguration, options: DataAvailabilityReadOptions) -> BenchmarkUsage { - println!("Benchmarking..."); - let usages: Vec = - (0..BENCH_COUNT).map(|_| run(config.clone(), options.clone())).collect(); - let usage = BenchmarkUsage::average(&usages); - println!("{}", usage); - usage -} - -fn run(config: TestConfiguration, options: DataAvailabilityReadOptions) -> BenchmarkUsage { - let mut state = TestState::new(&config); - let (mut env, _protocol_config) = - prepare_test(config.clone(), &mut state, TestDataAvailability::Read(options), false); - env.runtime() - .block_on(benchmark_availability_read("data_availability_read", &mut env, state)) -} diff --git a/polkadot/node/subsystem-bench/src/lib/lib.rs b/polkadot/node/subsystem-bench/src/lib/lib.rs index d06f2822a89..ef2724abc98 100644 --- a/polkadot/node/subsystem-bench/src/lib/lib.rs +++ b/polkadot/node/subsystem-bench/src/lib/lib.rs @@ -26,3 +26,4 @@ pub(crate) mod keyring; pub(crate) mod mock; pub(crate) mod network; pub mod usage; +pub mod utils; diff --git a/polkadot/node/subsystem-bench/src/lib/usage.rs b/polkadot/node/subsystem-bench/src/lib/usage.rs index b83ef7d98d9..ef60d67372a 100644 --- a/polkadot/node/subsystem-bench/src/lib/usage.rs +++ b/polkadot/node/subsystem-bench/src/lib/usage.rs @@ -20,7 +20,7 @@ use colored::Colorize; use serde::{Deserialize, Serialize}; use std::collections::HashMap; -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct BenchmarkUsage { pub benchmark_name: String, pub network_usage: Vec, @@ -110,7 +110,7 @@ fn check_resource_usage( } } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct ResourceUsage { pub resource_name: String, pub total: f64, diff --git a/polkadot/node/subsystem-bench/src/lib/utils.rs b/polkadot/node/subsystem-bench/src/lib/utils.rs new file mode 100644 index 00000000000..75b72cc11b9 --- /dev/null +++ b/polkadot/node/subsystem-bench/src/lib/utils.rs @@ -0,0 +1,76 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Test utils + +use crate::usage::BenchmarkUsage; +use std::io::{stdout, Write}; + +pub struct WarmUpOptions<'a> { + /// The maximum number of runs considered for marming up. + pub warm_up: usize, + /// The number of runs considered for benchmarking. + pub bench: usize, + /// The difference in CPU usage between runs considered as normal + pub precision: f64, + /// The subsystems whose CPU usage is checked during warm-up cycles + pub subsystems: &'a [&'a str], +} + +impl<'a> WarmUpOptions<'a> { + pub fn new(subsystems: &'a [&'a str]) -> Self { + Self { warm_up: 100, bench: 3, precision: 0.02, subsystems } + } +} + +pub fn warm_up_and_benchmark( + options: WarmUpOptions, + run: impl Fn() -> BenchmarkUsage, +) -> Result { + println!("Warming up..."); + let mut usages = Vec::with_capacity(options.bench); + + for n in 1..=options.warm_up { + let curr = run(); + if let Some(prev) = usages.last() { + let diffs = options + .subsystems + .iter() + .map(|&v| { + curr.cpu_usage_diff(prev, v) + .ok_or(format!("{} not found in benchmark {:?}", v, prev)) + }) + .collect::, String>>()?; + if !diffs.iter().all(|&v| v < options.precision) { + usages.clear(); + } + } + usages.push(curr); + print!("\r{}%", n * 100 / options.warm_up); + if usages.len() == options.bench { + println!("\rTook {} runs to warm up", n.saturating_sub(options.bench)); + break; + } + stdout().flush().unwrap(); + } + + if usages.len() != options.bench { + println!("Didn't warm up after {} runs", options.warm_up); + return Err("Can't warm up".to_string()) + } + + Ok(BenchmarkUsage::average(&usages)) +} -- GitLab From c4c9257386036a9e27e7ee001fe8eadb80958cc0 Mon Sep 17 00:00:00 2001 From: Javier Viola <363911+pepoviola@users.noreply.github.com> Date: Thu, 14 Mar 2024 04:41:44 -0300 Subject: [PATCH 037/187] Increase timeout for assertions (#3680) Prevents timeouts in ci like https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/5516019 --- .../testing/tests/0001-asset-transfer/roc-reaches-westend.zndsl | 2 +- .../testing/tests/0001-asset-transfer/wnd-reaches-rococo.zndsl | 2 +- .../testing/tests/0001-asset-transfer/wroc-reaches-rococo.zndsl | 2 +- .../tests/0001-asset-transfer/wwnd-reaches-westend.zndsl | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bridges/testing/tests/0001-asset-transfer/roc-reaches-westend.zndsl b/bridges/testing/tests/0001-asset-transfer/roc-reaches-westend.zndsl index a58520ccea6..cdb7d28e940 100644 --- a/bridges/testing/tests/0001-asset-transfer/roc-reaches-westend.zndsl +++ b/bridges/testing/tests/0001-asset-transfer/roc-reaches-westend.zndsl @@ -6,7 +6,7 @@ Creds: config asset-hub-westend-collator1: run {{ENV_PATH}}/helper.sh with "reserve-transfer-assets-from-asset-hub-rococo-local 5000000000000" within 120 seconds # check that //Alice received at least 4.8 ROC on Westend AH -asset-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/wrapped-assets-balance.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,4800000000000,Rococo" within 300 seconds +asset-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/wrapped-assets-balance.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,4800000000000,Rococo" within 600 seconds # check that the relayer //Charlie is rewarded by Westend AH bridge-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000002,0x6268726F,ThisChain,0" within 30 seconds diff --git a/bridges/testing/tests/0001-asset-transfer/wnd-reaches-rococo.zndsl b/bridges/testing/tests/0001-asset-transfer/wnd-reaches-rococo.zndsl index fedb78cc210..dbc03864e2b 100644 --- a/bridges/testing/tests/0001-asset-transfer/wnd-reaches-rococo.zndsl +++ b/bridges/testing/tests/0001-asset-transfer/wnd-reaches-rococo.zndsl @@ -6,7 +6,7 @@ Creds: config asset-hub-rococo-collator1: run {{ENV_PATH}}/helper.sh with "reserve-transfer-assets-from-asset-hub-westend-local 5000000000000" within 120 seconds # check that //Alice received at least 4.8 WND on Rococo AH -asset-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/wrapped-assets-balance.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,4800000000000,Westend" within 300 seconds +asset-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/wrapped-assets-balance.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,4800000000000,Westend" within 600 seconds # check that the relayer //Charlie is rewarded by Rococo AH bridge-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000002,0x62687764,ThisChain,0" within 30 seconds diff --git a/bridges/testing/tests/0001-asset-transfer/wroc-reaches-rococo.zndsl b/bridges/testing/tests/0001-asset-transfer/wroc-reaches-rococo.zndsl index 68b888b6858..9967732cabe 100644 --- a/bridges/testing/tests/0001-asset-transfer/wroc-reaches-rococo.zndsl +++ b/bridges/testing/tests/0001-asset-transfer/wroc-reaches-rococo.zndsl @@ -7,4 +7,4 @@ asset-hub-rococo-collator1: run {{ENV_PATH}}/helper.sh with "withdraw-reserve-as # check that //Alice received at least 2.8 wROC on Rococo AH # (we wait until //Alice account increases here - there are no other transactions that may increase it) -asset-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/native-assets-balance-increased.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,2800000000000" within 300 seconds +asset-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/native-assets-balance-increased.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,2800000000000" within 600 seconds diff --git a/bridges/testing/tests/0001-asset-transfer/wwnd-reaches-westend.zndsl b/bridges/testing/tests/0001-asset-transfer/wwnd-reaches-westend.zndsl index 1a8a1618195..2037b0baf3c 100644 --- a/bridges/testing/tests/0001-asset-transfer/wwnd-reaches-westend.zndsl +++ b/bridges/testing/tests/0001-asset-transfer/wwnd-reaches-westend.zndsl @@ -7,4 +7,4 @@ asset-hub-westend-collator1: run {{ENV_PATH}}/helper.sh with "withdraw-reserve-a # check that //Alice received at least 2.8 wWND on Westend AH # (we wait until //Alice account increases here - there are no other transactions that may increase it) -asset-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/native-assets-balance-increased.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,2800000000000" within 300 seconds +asset-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/native-assets-balance-increased.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,2800000000000" within 600 seconds -- GitLab From d55d4f64b50c858bce6fa1a429f50d486cc67d49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Pa=C4=8Dandi?= <3002868+Dinonard@users.noreply.github.com> Date: Thu, 14 Mar 2024 10:16:02 +0100 Subject: [PATCH 038/187] DescribeAllTerminal for HashedDescription (#3349) Make Rococo & Westend XCM's location converter `HashedDescription` more in line with Polkadot/Kusama runtimes. Co-authored-by: Muharem --- polkadot/runtime/rococo/src/xcm_config.rs | 6 +++--- polkadot/runtime/westend/src/xcm_config.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/polkadot/runtime/rococo/src/xcm_config.rs b/polkadot/runtime/rococo/src/xcm_config.rs index af8981ddcc1..67f34916fe7 100644 --- a/polkadot/runtime/rococo/src/xcm_config.rs +++ b/polkadot/runtime/rococo/src/xcm_config.rs @@ -39,7 +39,7 @@ use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, - ChildParachainConvertsVia, DescribeBodyTerminal, DescribeFamily, FixedWeightBounds, + ChildParachainConvertsVia, DescribeAllTerminal, DescribeFamily, FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, HashedDescription, IsChildSystemParachain, IsConcrete, MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, @@ -63,8 +63,8 @@ pub type LocationConverter = ( ChildParachainConvertsVia, // We can directly alias an `AccountId32` into a local account. AccountId32Aliases, - // Allow governance body to be used as a sovereign account. - HashedDescription>, + // Foreign locations alias into accounts according to a hash of their standard description. + HashedDescription>, ); /// Our asset transactor. This is what allows us to interest with the runtime facilities from the diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index c57af987ca7..7281007f006 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -40,7 +40,7 @@ use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, - ChildParachainConvertsVia, DescribeBodyTerminal, DescribeFamily, FrameTransactionalProcessor, + ChildParachainConvertsVia, DescribeAllTerminal, DescribeFamily, FrameTransactionalProcessor, FungibleAdapter, HashedDescription, IsConcrete, MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, @@ -67,8 +67,8 @@ pub type LocationConverter = ( ChildParachainConvertsVia, // We can directly alias an `AccountId32` into a local account. AccountId32Aliases, - // Allow governance body to be used as a sovereign account. - HashedDescription>, + // Foreign locations alias into accounts according to a hash of their standard description. + HashedDescription>, ); pub type LocalAssetTransactor = FungibleAdapter< -- GitLab From 606664e1bd70ebe25adbf53b2547d8b10d4803c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 14 Mar 2024 10:49:46 +0100 Subject: [PATCH 039/187] Staking ledger bonding fixes (#3639) Currently, the staking logic does not prevent a controller from becoming a stash of *another* ledger (introduced by [removing this check](https://github.com/paritytech/polkadot-sdk/pull/1484/files#diff-3aa6ceab5aa4e0ab2ed73a7245e0f5b42e0832d8ca5b1ed85d7b2a52fb196524L850)). Given that the remaining of the code expects that never happens, bonding a ledger with a stash that is a controller of another ledger may lead to data inconsistencies and data losses in bonded ledgers. For more detailed explanation of this issue: https://hackmd.io/@gpestana/HJoBm2tqo/%2FTPdi28H7Qc2mNUqLSMn15w In a nutshell, when fetching a ledger with a given controller, we may be end up getting the wrong ledger which can lead to unexpected ledger states. This PR also ensures that `set_controller` does not lead to data inconsistencies in the staking ledger and bonded storage in the case when a controller of a stash is a stash of *another* ledger. and improves the staking `try-runtime` checks to catch potential issues with the storage preemptively. In summary, there are two important cases here: 1. **"Sane" double bonded ledger** When a controller of a ledger is a stash of *another* ledger. In this case, we have: ``` > Bonded(stash, controller) (A, B) // stash A with controller B (B, C) // B is also a stash of another ledger (C, D) > Ledger(controller) Ledger(B) = L_a (stash = A) Ledger(C) = L_b (stash = B) Ledger(D) = L_c (stash = C) ``` In this case, the ledgers can be mutated and all operations are OK. However, we should not allow `set_controller` to be called if it means it results in a "corrupt" double bonded ledger (see below). 3. **"Corrupt" double bonded ledger** ``` > Bonded(stash, controller) (A, B) // stash A with controller B (B, B) (C, D) ``` In this case, B is a stash and controller AND is corrupted, since B is responsible for 2 ledgers which is not correct and will lead to inconsistent states. Thus, in this case, in this PR we are preventing these ledgers from mutating (i.e. operations like bonding extra etc) until the ledger is brought back to a consistent state. --- **Changes**: - Checks if stash is already a controller when calling `Call::bond` (fixes the regression introduced by [removing this check](https://github.com/paritytech/polkadot-sdk/pull/1484/files#diff-3aa6ceab5aa4e0ab2ed73a7245e0f5b42e0832d8ca5b1ed85d7b2a52fb196524L850)); - Ensures that all fetching ledgers from storage are done through the `StakingLedger` API; - Ensures that -- when fetching a ledger from storage using the `StakingLedger` API --, a `Error::BadState` is returned if the ledger bonding is in a bad state. This prevents bad ledgers from mutating (e.g. `bond_extra`, `set_controller`, etc) its state and avoid further data inconsistencies. - Prevents stashes which are controllers or another ledger from calling `set_controller`, since that may lead to a bad state. - Adds further try-state runtime checks that check if there are ledgers in a bad state based on their bonded metadata. Related to https://github.com/paritytech/polkadot-sdk/issues/3245 --------- Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: kianenigma --- prdoc/pr_3639.prdoc | 19 +++ substrate/frame/staking/src/ledger.rs | 61 +++++++- substrate/frame/staking/src/mock.rs | 51 +++++++ substrate/frame/staking/src/pallet/impls.rs | 84 ++++++++++- substrate/frame/staking/src/pallet/mod.rs | 28 ++-- substrate/frame/staking/src/tests.rs | 159 ++++++++++++++++++++ 6 files changed, 378 insertions(+), 24 deletions(-) create mode 100644 prdoc/pr_3639.prdoc diff --git a/prdoc/pr_3639.prdoc b/prdoc/pr_3639.prdoc new file mode 100644 index 00000000000..46e3f6f4d76 --- /dev/null +++ b/prdoc/pr_3639.prdoc @@ -0,0 +1,19 @@ +title: Prevents staking controllers from becoming stashes of different ledgers; Ensures that no ledger in bad state is mutated. + +doc: + - audience: Runtime User + description: | + This PR introduces a fix to the staking logic which prevents an existing controller from bonding as a stash of another ledger, which + lead to staking ledger inconsistencies down the line. In addition, it adds a few (temporary) gates to prevent ledgers that are already + in a bad state from mutating its state. + + In summary: + * Checks if stash is already a controller when calling `Call::bond` and fails if that's the case; + * Ensures that all fetching ledgers from storage are done through the `StakingLedger` API; + * Ensures that a `Error::BadState` is returned if the ledger bonding is in a bad state. This prevents bad ledgers from mutating (e.g. + `bond_extra`, `set_controller`, etc) its state and avoid further data inconsistencies. + * Prevents stashes which are controllers or another ledger from calling `set_controller`, since that may lead to a bad state. + * Adds further try-state runtime checks that check if there are ledgers in a bad state based on their bonded metadata. + +crates: +- name: pallet-staking diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index 5947adb9028..67be1e15bc6 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -32,8 +32,8 @@ //! state consistency. use frame_support::{ - defensive, - traits::{LockableCurrency, WithdrawReasons}, + defensive, ensure, + traits::{Defensive, LockableCurrency, WithdrawReasons}, }; use sp_staking::StakingAccount; use sp_std::prelude::*; @@ -106,18 +106,39 @@ impl StakingLedger { /// This getter can be called with either a controller or stash account, provided that the /// account is properly wrapped in the respective [`StakingAccount`] variant. This is meant to /// abstract the concept of controller/stash accounts from the caller. + /// + /// Returns [`Error::BadState`] when a bond is in "bad state". A bond is in a bad state when a + /// stash has a controller which is bonding a ledger associated with another stash. pub(crate) fn get(account: StakingAccount) -> Result, Error> { - let controller = match account { - StakingAccount::Stash(stash) => >::get(stash).ok_or(Error::::NotStash), - StakingAccount::Controller(controller) => Ok(controller), - }?; + let (stash, controller) = match account.clone() { + StakingAccount::Stash(stash) => + (stash.clone(), >::get(&stash).ok_or(Error::::NotStash)?), + StakingAccount::Controller(controller) => ( + Ledger::::get(&controller) + .map(|l| l.stash) + .ok_or(Error::::NotController)?, + controller, + ), + }; - >::get(&controller) + let ledger = >::get(&controller) .map(|mut ledger| { ledger.controller = Some(controller.clone()); ledger }) - .ok_or(Error::::NotController) + .ok_or(Error::::NotController)?; + + // if ledger bond is in a bad state, return error to prevent applying operations that may + // further spoil the ledger's state. A bond is in bad state when the bonded controller is + // associted with a different ledger (i.e. a ledger with a different stash). + // + // See for more details. + ensure!( + Bonded::::get(&stash) == Some(controller) && ledger.stash == stash, + Error::::BadState + ); + + Ok(ledger) } /// Returns the reward destination of a staking ledger, stored in [`Payee`]. @@ -201,6 +222,30 @@ impl StakingLedger { } } + /// Sets the ledger controller to its stash. + pub(crate) fn set_controller_to_stash(self) -> Result<(), Error> { + let controller = self.controller.as_ref() + .defensive_proof("Ledger's controller field didn't exist. The controller should have been fetched using StakingLedger.") + .ok_or(Error::::NotController)?; + + ensure!(self.stash != *controller, Error::::AlreadyPaired); + + // check if the ledger's stash is a controller of another ledger. + if let Some(bonded_ledger) = Ledger::::get(&self.stash) { + // there is a ledger bonded by the stash. In this case, the stash of the bonded ledger + // should be the same as the ledger's stash. Otherwise fail to prevent data + // inconsistencies. See for more + // details. + ensure!(bonded_ledger.stash == self.stash, Error::::BadState); + } + + >::remove(&controller); + >::insert(&self.stash, &self); + >::insert(&self.stash, &self.stash); + + Ok(()) + } + /// Clears all data related to a staking ledger and its bond in both [`Ledger`] and [`Bonded`] /// storage items and updates the stash staking lock. pub(crate) fn kill(stash: &T::AccountId) -> Result<(), Error> { diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 24311cb9e78..65e660f248d 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -786,6 +786,57 @@ pub(crate) fn bond_controller_stash(controller: AccountId, stash: AccountId) -> Ok(()) } +pub(crate) fn setup_double_bonded_ledgers() { + assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 10, RewardDestination::Staked)); + assert_ok!(Staking::bond(RuntimeOrigin::signed(2), 20, RewardDestination::Staked)); + assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 20, RewardDestination::Staked)); + // not relevant to the test case, but ensures try-runtime checks pass. + [1, 2, 3] + .iter() + .for_each(|s| Payee::::insert(s, RewardDestination::Staked)); + + // we want to test the case where a controller can also be a stash of another ledger. + // for that, we change the controller/stash bonding so that: + // * 2 becomes controller of 1. + // * 3 becomes controller of 2. + // * 4 becomes controller of 3. + let ledger_1 = Ledger::::get(1).unwrap(); + let ledger_2 = Ledger::::get(2).unwrap(); + let ledger_3 = Ledger::::get(3).unwrap(); + + // 4 becomes controller of 3. + Bonded::::mutate(3, |controller| *controller = Some(4)); + Ledger::::insert(4, ledger_3); + + // 3 becomes controller of 2. + Bonded::::mutate(2, |controller| *controller = Some(3)); + Ledger::::insert(3, ledger_2); + + // 2 becomes controller of 1 + Bonded::::mutate(1, |controller| *controller = Some(2)); + Ledger::::insert(2, ledger_1); + // 1 is not controller anymore. + Ledger::::remove(1); + + // checks. now we have: + // * 3 ledgers + assert_eq!(Ledger::::iter().count(), 3); + // * stash 1 has controller 2. + assert_eq!(Bonded::::get(1), Some(2)); + assert_eq!(StakingLedger::::paired_account(StakingAccount::Stash(1)), Some(2)); + assert_eq!(Ledger::::get(2).unwrap().stash, 1); + + // * stash 2 has controller 3. + assert_eq!(Bonded::::get(2), Some(3)); + assert_eq!(StakingLedger::::paired_account(StakingAccount::Stash(2)), Some(3)); + assert_eq!(Ledger::::get(3).unwrap().stash, 2); + + // * stash 3 has controller 4. + assert_eq!(Bonded::::get(3), Some(4)); + assert_eq!(StakingLedger::::paired_account(StakingAccount::Stash(3)), Some(4)); + assert_eq!(Ledger::::get(4).unwrap().stash, 3); +} + #[macro_export] macro_rules! assert_session_era { ($session:expr, $era:expr) => { diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 757c46f4faf..d42456e53b1 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -165,7 +165,8 @@ impl Pallet { let controller = Self::bonded(&validator_stash).ok_or_else(|| { Error::::NotStash.with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) })?; - let ledger = >::get(&controller).ok_or(Error::::NotController)?; + + let ledger = Self::ledger(StakingAccount::Controller(controller))?; let page = EraInfo::::get_next_claimable_page(era, &validator_stash, &ledger) .ok_or_else(|| { Error::::AlreadyClaimed @@ -1728,7 +1729,7 @@ impl StakingInterface for Pallet { ) -> Result { let ctrl = Self::bonded(&who).ok_or(Error::::NotStash)?; Self::withdraw_unbonded(RawOrigin::Signed(ctrl.clone()).into(), num_slashing_spans) - .map(|_| !Ledger::::contains_key(&ctrl)) + .map(|_| !StakingLedger::::is_bonded(StakingAccount::Controller(ctrl))) .map_err(|with_post| with_post.error) } @@ -1836,6 +1837,7 @@ impl Pallet { "VoterList contains non-staker" ); + Self::check_bonded_consistency()?; Self::check_payees()?; Self::check_nominators()?; Self::check_exposures()?; @@ -1844,9 +1846,67 @@ impl Pallet { Self::check_count() } + /// Invariants: + /// * A controller should not be associated with more than one ledger. + /// * A bonded (stash, controller) pair should have only one associated ledger. I.e. if the + /// ledger is bonded by stash, the controller account must not bond a different ledger. + /// * A bonded (stash, controller) pair must have an associated ledger. + /// NOTE: these checks result in warnings only. Once + /// is resolved, turn warns into check + /// failures. + fn check_bonded_consistency() -> Result<(), TryRuntimeError> { + use sp_std::collections::btree_set::BTreeSet; + + let mut count_controller_double = 0; + let mut count_double = 0; + let mut count_none = 0; + // sanity check to ensure that each controller in Bonded storage is associated with only one + // ledger. + let mut controllers = BTreeSet::new(); + + for (stash, controller) in >::iter() { + if !controllers.insert(controller.clone()) { + count_controller_double += 1; + } + + match (>::get(&stash), >::get(&controller)) { + (Some(_), Some(_)) => + // if stash == controller, it means that the ledger has migrated to + // post-controller. If no migration happened, we expect that the (stash, + // controller) pair has only one associated ledger. + if stash != controller { + count_double += 1; + }, + (None, None) => { + count_none += 1; + }, + _ => {}, + }; + } + + if count_controller_double != 0 { + log!( + warn, + "a controller is associated with more than one ledger ({} occurrences)", + count_controller_double + ); + }; + + if count_double != 0 { + log!(warn, "single tuple of (stash, controller) pair bonds more than one ledger ({} occurrences)", count_double); + } + + if count_none != 0 { + log!(warn, "inconsistent bonded state: (stash, controller) pair missing associated ledger ({} occurrences)", count_none); + } + + Ok(()) + } + /// Invariants: /// * A bonded ledger should always have an assigned `Payee`. /// * The number of entries in `Payee` and of bonded staking ledgers *must* match. + /// * The stash account in the ledger must match that of the bonded acount. fn check_payees() -> Result<(), TryRuntimeError> { for (stash, _) in Bonded::::iter() { ensure!(Payee::::get(&stash).is_some(), "bonded ledger does not have payee set"); @@ -1861,6 +1921,11 @@ impl Pallet { Ok(()) } + /// Invariants: + /// * Number of voters in `VoterList` match that of the number of Nominators and Validators in + /// the system (validator is both voter and target). + /// * Number of targets in `TargetList` matches the number of validators in the system. + /// * Current validator count is bounded by the election provider's max winners. fn check_count() -> Result<(), TryRuntimeError> { ensure!( ::VoterList::count() == @@ -1879,6 +1944,11 @@ impl Pallet { Ok(()) } + /// Invariants: + /// * `ledger.controller` is not stored in the storage (but populated at retrieval). + /// * Stake consistency: ledger.total == ledger.active + sum(ledger.unlocking). + /// * The controller keyeing the ledger and the ledger stash matches the state of the `Bonded` + /// storage. fn check_ledgers() -> Result<(), TryRuntimeError> { Bonded::::iter() .map(|(stash, ctrl)| { @@ -1896,8 +1966,10 @@ impl Pallet { Ok(()) } + /// Invariants: + /// * For each era exposed validator, check if the exposure total is sane (exposure.total = + /// exposure.own + exposure.own). fn check_exposures() -> Result<(), TryRuntimeError> { - // a check per validator to ensure the exposure struct is always sane. let era = Self::active_era().unwrap().index; ErasStakers::::iter_prefix_values(era) .map(|expo| { @@ -1915,6 +1987,10 @@ impl Pallet { .collect::>() } + /// Invariants: + /// * For each paged era exposed validator, check if the exposure total is sane (exposure.total + /// = exposure.own + exposure.own). + /// * Paged exposures metadata (`ErasStakersOverview`) matches the paged exposures state. fn check_paged_exposures() -> Result<(), TryRuntimeError> { use sp_staking::PagedExposureMetadata; use sp_std::collections::btree_map::BTreeMap; @@ -1979,6 +2055,8 @@ impl Pallet { .collect::>() } + /// Invariants: + /// * Checks that each nominator has its entire stake correctly distributed. fn check_nominators() -> Result<(), TryRuntimeError> { // a check per nominator to ensure their entire stake is correctly distributed. Will only // kick-in if the nomination was submitted before the current era. diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 992a7fe2c9c..1bf8bd8b09c 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -791,6 +791,8 @@ pub mod pallet { SnapshotTargetsSizeExceeded { size: u32 }, /// A new force era mode was set. ForceEra { mode: Forcing }, + /// Report of a controller batch deprecation. + ControllerBatchDeprecated { failures: u32 }, } #[pallet::error] @@ -935,6 +937,11 @@ pub mod pallet { return Err(Error::::AlreadyBonded.into()) } + // An existing controller cannot become a stash. + if StakingLedger::::is_bonded(StakingAccount::Controller(stash.clone())) { + return Err(Error::::AlreadyPaired.into()) + } + // Reject a bond which is considered to be _dust_. if value < T::Currency::minimum_balance() { return Err(Error::::InsufficientBond.into()) @@ -975,7 +982,6 @@ pub mod pallet { #[pallet::compact] max_additional: BalanceOf, ) -> DispatchResult { let stash = ensure_signed(origin)?; - let mut ledger = Self::ledger(StakingAccount::Stash(stash.clone()))?; let stash_balance = T::Currency::free_balance(&stash); @@ -1332,8 +1338,6 @@ pub mod pallet { pub fn set_controller(origin: OriginFor) -> DispatchResult { let stash = ensure_signed(origin)?; - // The bonded map and ledger are mutated directly as this extrinsic is related to a - // (temporary) passive migration. Self::ledger(StakingAccount::Stash(stash.clone())).map(|ledger| { let controller = ledger.controller() .defensive_proof("Ledger's controller field didn't exist. The controller should have been fetched using StakingLedger.") @@ -1343,9 +1347,8 @@ pub mod pallet { // Stash is already its own controller. return Err(Error::::AlreadyPaired.into()) } - >::remove(controller); - >::insert(&stash, &stash); - >::insert(&stash, ledger); + + let _ = ledger.set_controller_to_stash()?; Ok(()) })? } @@ -1960,7 +1963,7 @@ pub mod pallet { }; if ledger.stash != *controller && !payee_deprecated { - Some((controller.clone(), ledger)) + Some(ledger) } else { None } @@ -1969,13 +1972,12 @@ pub mod pallet { .collect(); // Update unique pairs. - for (controller, ledger) in filtered_batch_with_ledger { - let stash = ledger.stash.clone(); - - >::insert(&stash, &stash); - >::remove(controller); - >::insert(stash, ledger); + let mut failures = 0; + for ledger in filtered_batch_with_ledger { + let _ = ledger.clone().set_controller_to_stash().map_err(|_| failures += 1); } + Self::deposit_event(Event::::ControllerBatchDeprecated { failures }); + Ok(Some(T::WeightInfo::deprecate_controller_batch(controllers.len() as u32)).into()) } } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 3f4e28b1f6a..3725c9e3c2c 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -1248,6 +1248,23 @@ fn bond_extra_works() { }); } +#[test] +fn bond_extra_controller_bad_state_works() { + ExtBuilder::default().try_state(false).build_and_execute(|| { + assert_eq!(StakingLedger::::get(StakingAccount::Stash(31)).unwrap().stash, 31); + + // simulate ledger in bad state: the controller 41 is associated to the stash 31 and 41. + Bonded::::insert(31, 41); + + // we confirm that the ledger is in bad state: 31 has 41 as controller and when fetching + // the ledger associated with the controler 41, its stash is 41 (and not 31). + assert_eq!(Ledger::::get(41).unwrap().stash, 41); + + // if the ledger is in this bad state, the `bond_extra` should fail. + assert_noop!(Staking::bond_extra(RuntimeOrigin::signed(31), 10), Error::::BadState); + }) +} + #[test] fn bond_extra_and_withdraw_unbonded_works() { // @@ -6910,6 +6927,49 @@ mod ledger { }) } + #[test] + fn get_ledger_bad_state_fails() { + ExtBuilder::default().has_stakers(false).try_state(false).build_and_execute(|| { + setup_double_bonded_ledgers(); + + // Case 1: double bonded but not corrupted: + // stash 2 has controller 3: + assert_eq!(Bonded::::get(2), Some(3)); + assert_eq!(Ledger::::get(3).unwrap().stash, 2); + + // stash 2 is also a controller of 1: + assert_eq!(Bonded::::get(1), Some(2)); + assert_eq!(StakingLedger::::paired_account(StakingAccount::Stash(1)), Some(2)); + assert_eq!(Ledger::::get(2).unwrap().stash, 1); + + // although 2 is double bonded (it is a controller and a stash of different ledgers), + // we can safely retrieve the ledger and mutate it since the correct ledger is + // returned. + let ledger_result = StakingLedger::::get(StakingAccount::Stash(2)); + assert_eq!(ledger_result.unwrap().stash, 2); // correct ledger. + + let ledger_result = StakingLedger::::get(StakingAccount::Controller(2)); + assert_eq!(ledger_result.unwrap().stash, 1); // correct ledger. + + // fetching ledger 1 by its stash works. + let ledger_result = StakingLedger::::get(StakingAccount::Stash(1)); + assert_eq!(ledger_result.unwrap().stash, 1); + + // Case 2: corrupted ledger bonding. + // in this case, we simulate what happens when fetching a ledger by stash returns a + // ledger with a different stash. when this happens, we return an error instead of the + // ledger to prevent ledger mutations. + let mut ledger = Ledger::::get(2).unwrap(); + assert_eq!(ledger.stash, 1); + ledger.stash = 2; + Ledger::::insert(2, ledger); + + // now, we are prevented from fetching the ledger by stash from 1. It's associated + // controller (2) is now bonding a ledger with a different stash (2, not 1). + assert!(StakingLedger::::get(StakingAccount::Stash(1)).is_err()); + }) + } + #[test] fn bond_works() { ExtBuilder::default().build_and_execute(|| { @@ -6933,6 +6993,28 @@ mod ledger { }) } + #[test] + fn bond_controller_cannot_be_stash_works() { + ExtBuilder::default().build_and_execute(|| { + let (stash, controller) = testing_utils::create_unique_stash_controller::( + 0, + 10, + RewardDestination::Staked, + false, + ) + .unwrap(); + + assert_eq!(Bonded::::get(stash), Some(controller)); + assert_eq!(Ledger::::get(controller).map(|l| l.stash), Some(stash)); + + // existing controller should not be able become a stash. + assert_noop!( + Staking::bond(RuntimeOrigin::signed(controller), 10, RewardDestination::Staked), + Error::::AlreadyPaired, + ); + }) + } + #[test] fn is_bonded_works() { ExtBuilder::default().build_and_execute(|| { @@ -7161,4 +7243,81 @@ mod ledger { assert_eq!(ledger_updated.stash, stash); }) } + + #[test] + fn deprecate_controller_batch_with_bad_state_ok() { + ExtBuilder::default().has_stakers(false).nominate(false).build_and_execute(|| { + setup_double_bonded_ledgers(); + + // now let's deprecate all the controllers for all the existing ledgers. + let bounded_controllers: BoundedVec< + _, + ::MaxControllersInDeprecationBatch, + > = BoundedVec::try_from(vec![1, 2, 3, 4]).unwrap(); + + assert_ok!(Staking::deprecate_controller_batch( + RuntimeOrigin::root(), + bounded_controllers + )); + + assert_eq!( + *staking_events().last().unwrap(), + Event::ControllerBatchDeprecated { failures: 0 } + ); + }) + } + + #[test] + fn deprecate_controller_batch_with_bad_state_failures() { + ExtBuilder::default().has_stakers(false).try_state(false).build_and_execute(|| { + setup_double_bonded_ledgers(); + + // now let's deprecate all the controllers for all the existing ledgers. + let bounded_controllers: BoundedVec< + _, + ::MaxControllersInDeprecationBatch, + > = BoundedVec::try_from(vec![4, 3, 2, 1]).unwrap(); + + assert_ok!(Staking::deprecate_controller_batch( + RuntimeOrigin::root(), + bounded_controllers + )); + + assert_eq!( + *staking_events().last().unwrap(), + Event::ControllerBatchDeprecated { failures: 2 } + ); + }) + } + + #[test] + fn set_controller_with_bad_state_ok() { + ExtBuilder::default().has_stakers(false).nominate(false).build_and_execute(|| { + setup_double_bonded_ledgers(); + + // in this case, setting controller works due to the ordering of the calls. + assert_ok!(Staking::set_controller(RuntimeOrigin::signed(1))); + assert_ok!(Staking::set_controller(RuntimeOrigin::signed(2))); + assert_ok!(Staking::set_controller(RuntimeOrigin::signed(3))); + }) + } + + #[test] + fn set_controller_with_bad_state_fails() { + ExtBuilder::default().has_stakers(false).try_state(false).build_and_execute(|| { + setup_double_bonded_ledgers(); + + // setting the controller of ledger associated with stash 3 fails since its stash is a + // controller of another ledger. + assert_noop!( + Staking::set_controller(RuntimeOrigin::signed(3)), + Error::::BadState + ); + assert_noop!( + Staking::set_controller(RuntimeOrigin::signed(2)), + Error::::BadState + ); + assert_ok!(Staking::set_controller(RuntimeOrigin::signed(1))); + }) + } } -- GitLab From cfc4050d6b95619b969a92d32e71a874aa5ef38a Mon Sep 17 00:00:00 2001 From: Ignacio Palacios Date: Thu, 14 Mar 2024 11:29:24 +0100 Subject: [PATCH 040/187] Improve Penpal runtime + emulated tests (#3543) Issues addressed in this PR: - Improve *Penpal* runtime: - Properly handled received assets. Previously, it treated `(1, Here)` as the local native currency, whereas it should be treated as a `ForeignAsset`. This wasn't a great example of standard Parachain behaviour, as no Parachain treats the system asset as the local currency. - Remove `AllowExplicitUnpaidExecutionFrom` the system. Again, this wasn't a great example of standard Parachain behaviour. - Move duplicated `ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger` to `assets_common` crate. - Improve emulated tests: - Update *Penpal* tests to new runtime. - To simplify tests, register the reserve transferred, teleported, and system assets in *Penpal* and *AssetHub* genesis. This saves us from having to create the assets repeatedly for each test - Add missing test case: `reserve_transfer_assets_from_para_to_system_para`. - Cleanup. - Prevent integration tests crates imports from being re-exported, as they were polluting the `polkadot-sdk` docs. There is still a test case missing for reserve transfers: - Reserve transfer of system asset from *Parachain* to *Parachain* trough *AssetHub*. - This is not yet possible with `pallet-xcm` due to the reasons explained in https://github.com/paritytech/polkadot-sdk/pull/3339 --------- Co-authored-by: command-bot <> --- Cargo.lock | 6 +- .../assets/asset-hub-rococo/src/genesis.rs | 29 +- .../assets/asset-hub-rococo/src/lib.rs | 6 +- .../assets/asset-hub-westend/src/genesis.rs | 29 +- .../assets/asset-hub-westend/src/lib.rs | 6 +- .../parachains/testing/penpal/Cargo.toml | 5 +- .../parachains/testing/penpal/src/genesis.rs | 43 +- .../parachains/testing/penpal/src/lib.rs | 11 +- .../emulated/common/Cargo.toml | 1 + .../emulated/common/src/impls.rs | 150 ++- .../emulated/common/src/lib.rs | 23 +- .../emulated/common/src/macros.rs | 111 +-- .../tests/assets/asset-hub-rococo/Cargo.toml | 1 + .../tests/assets/asset-hub-rococo/src/lib.rs | 116 ++- .../assets/asset-hub-rococo/src/tests/mod.rs | 8 - .../src/tests/reserve_transfer.rs | 829 +++++++++++++--- .../assets/asset-hub-rococo/src/tests/send.rs | 129 ++- .../src/tests/set_xcm_versions.rs | 2 +- .../assets/asset-hub-rococo/src/tests/swap.rs | 58 +- .../asset-hub-rococo/src/tests/teleport.rs | 135 ++- .../tests/assets/asset-hub-westend/Cargo.toml | 1 + .../tests/assets/asset-hub-westend/src/lib.rs | 128 +-- .../src/tests/fellowship_treasury.rs | 2 +- .../assets/asset-hub-westend/src/tests/mod.rs | 8 - .../src/tests/reserve_transfer.rs | 903 ++++++++++++++---- .../asset-hub-westend/src/tests/send.rs | 143 ++- .../src/tests/set_xcm_versions.rs | 2 +- .../asset-hub-westend/src/tests/swap.rs | 107 +-- .../asset-hub-westend/src/tests/teleport.rs | 226 +++-- .../asset-hub-westend/src/tests/treasury.rs | 2 +- .../bridges/bridge-hub-rococo/src/lib.rs | 97 +- .../bridge-hub-rococo/src/tests/mod.rs | 2 +- .../bridge-hub-rococo/src/tests/snowbridge.rs | 2 +- .../bridge-hub-rococo/src/tests/teleport.rs | 2 +- .../bridges/bridge-hub-westend/src/lib.rs | 93 +- .../bridge-hub-westend/src/tests/mod.rs | 2 +- .../bridge-hub-westend/src/tests/teleport.rs | 2 +- .../tests/people/people-rococo/src/lib.rs | 73 +- .../people-rococo/src/tests/reap_identity.rs | 2 +- .../people-rococo/src/tests/teleport.rs | 2 +- .../tests/people/people-westend/src/lib.rs | 74 +- .../people-westend/src/tests/reap_identity.rs | 2 +- .../people-westend/src/tests/teleport.rs | 2 +- .../assets/asset-hub-rococo/tests/tests.rs | 8 +- .../assets/asset-hub-westend/tests/tests.rs | 8 +- .../runtimes/testing/penpal/src/lib.rs | 9 +- .../runtimes/testing/penpal/src/xcm_config.rs | 139 ++- 47 files changed, 2560 insertions(+), 1179 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8cbbbce209a..e1bd596a7a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -841,6 +841,7 @@ dependencies = [ "pallet-xcm", "parachains-common", "parity-scale-codec", + "penpal-runtime", "rococo-runtime", "rococo-system-emulated-network", "sp-runtime", @@ -962,6 +963,7 @@ dependencies = [ "pallet-xcm", "parachains-common", "parity-scale-codec", + "penpal-runtime", "polkadot-runtime-common", "sp-runtime", "staging-xcm", @@ -4931,6 +4933,7 @@ dependencies = [ "parachains-common", "parity-scale-codec", "paste", + "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-runtime-parachains", "sc-consensus-grandpa", @@ -11645,9 +11648,8 @@ dependencies = [ "frame-support", "parachains-common", "penpal-runtime", - "rococo-emulated-chain", "sp-core", - "westend-emulated-chain", + "staging-xcm", ] [[package]] diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs index 80db5644469..2acccb9649b 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs @@ -14,17 +14,24 @@ // limitations under the License. // Substrate -use sp_core::storage::Storage; +use frame_support::parameter_types; +use sp_core::{sr25519, storage::Storage}; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage, collators, SAFE_XCM_VERSION, + accounts, build_genesis_storage, collators, get_account_id_from_seed, + PenpalSiblingSovereigAccount, PenpalTeleportableAssetLocation, RESERVABLE_ASSET_ID, + SAFE_XCM_VERSION, }; -use parachains_common::Balance; +use parachains_common::{AccountId, Balance}; pub const PARA_ID: u32 = 1000; pub const ED: Balance = testnet_parachains_constants::rococo::currency::EXISTENTIAL_DEPOSIT; +parameter_types! { + pub AssetHubRococoAssetOwner: AccountId = get_account_id_from_seed::("Alice"); +} + pub fn genesis() -> Storage { let genesis_config = asset_hub_rococo_runtime::RuntimeGenesisConfig { system: asset_hub_rococo_runtime::SystemConfig::default(), @@ -60,6 +67,22 @@ pub fn genesis() -> Storage { safe_xcm_version: Some(SAFE_XCM_VERSION), ..Default::default() }, + assets: asset_hub_rococo_runtime::AssetsConfig { + assets: vec![(RESERVABLE_ASSET_ID, AssetHubRococoAssetOwner::get(), true, ED)], + ..Default::default() + }, + foreign_assets: asset_hub_rococo_runtime::ForeignAssetsConfig { + assets: vec![ + // Penpal's teleportable asset representation + ( + PenpalTeleportableAssetLocation::get(), + PenpalSiblingSovereigAccount::get(), + true, + ED, + ), + ], + ..Default::default() + }, ..Default::default() }; diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs index 00f41256420..f1e972e869d 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs @@ -21,7 +21,7 @@ use frame_support::traits::OnInitialize; // Cumulus use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impl_assets_helpers_for_parachain, impl_foreign_assets_helpers_for_parachain, + impl_assets_helpers_for_parachain, impl_assets_helpers_for_system_parachain, impl_xcm_helpers_for_parachain, impls::Parachain, xcm_emulator::decl_test_parachains, }; use rococo_emulated_chain::Rococo; @@ -54,6 +54,6 @@ decl_test_parachains! { // AssetHubRococo implementation impl_accounts_helpers_for_parachain!(AssetHubRococo); impl_assert_events_helpers_for_parachain!(AssetHubRococo); -impl_assets_helpers_for_parachain!(AssetHubRococo, Rococo); -impl_foreign_assets_helpers_for_parachain!(AssetHubRococo, Rococo); +impl_assets_helpers_for_system_parachain!(AssetHubRococo, Rococo); +impl_assets_helpers_for_parachain!(AssetHubRococo); impl_xcm_helpers_for_parachain!(AssetHubRococo); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs index b2e4645ee07..e30529aff42 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs @@ -14,17 +14,24 @@ // limitations under the License. // Substrate -use sp_core::storage::Storage; +use frame_support::parameter_types; +use sp_core::{sr25519, storage::Storage}; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage, collators, SAFE_XCM_VERSION, + accounts, build_genesis_storage, collators, get_account_id_from_seed, + PenpalSiblingSovereigAccount, PenpalTeleportableAssetLocation, RESERVABLE_ASSET_ID, + SAFE_XCM_VERSION, }; -use parachains_common::Balance; +use parachains_common::{AccountId, Balance}; pub const PARA_ID: u32 = 1000; pub const ED: Balance = testnet_parachains_constants::westend::currency::EXISTENTIAL_DEPOSIT; +parameter_types! { + pub AssetHubWestendAssetOwner: AccountId = get_account_id_from_seed::("Alice"); +} + pub fn genesis() -> Storage { let genesis_config = asset_hub_westend_runtime::RuntimeGenesisConfig { system: asset_hub_westend_runtime::SystemConfig::default(), @@ -56,6 +63,22 @@ pub fn genesis() -> Storage { safe_xcm_version: Some(SAFE_XCM_VERSION), ..Default::default() }, + assets: asset_hub_westend_runtime::AssetsConfig { + assets: vec![(RESERVABLE_ASSET_ID, AssetHubWestendAssetOwner::get(), true, ED)], + ..Default::default() + }, + foreign_assets: asset_hub_westend_runtime::ForeignAssetsConfig { + assets: vec![ + // Penpal's teleportable asset representation + ( + PenpalTeleportableAssetLocation::get(), + PenpalSiblingSovereigAccount::get(), + true, + ED, + ), + ], + ..Default::default() + }, ..Default::default() }; diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs index 25d7c1079b4..7f05eefb4c2 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs @@ -21,7 +21,7 @@ use frame_support::traits::OnInitialize; // Cumulus use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impl_assets_helpers_for_parachain, impl_foreign_assets_helpers_for_parachain, + impl_assets_helpers_for_parachain, impl_assets_helpers_for_system_parachain, impl_xcm_helpers_for_parachain, impls::Parachain, xcm_emulator::decl_test_parachains, }; use westend_emulated_chain::Westend; @@ -54,6 +54,6 @@ decl_test_parachains! { // AssetHubWestend implementation impl_accounts_helpers_for_parachain!(AssetHubWestend); impl_assert_events_helpers_for_parachain!(AssetHubWestend); -impl_assets_helpers_for_parachain!(AssetHubWestend, Westend); -impl_foreign_assets_helpers_for_parachain!(AssetHubWestend, Westend); +impl_assets_helpers_for_system_parachain!(AssetHubWestend, Westend); +impl_assets_helpers_for_parachain!(AssetHubWestend); impl_xcm_helpers_for_parachain!(AssetHubWestend); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml index a853825d8ef..f47350b00eb 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml @@ -16,10 +16,11 @@ workspace = true sp-core = { path = "../../../../../../../../substrate/primitives/core", default-features = false } frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } +# Polkadot +xcm = { package = "staging-xcm", path = "../../../../../../../../polkadot/xcm", default-features = false } + # Cumulus parachains-common = { path = "../../../../../../../parachains/common" } cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } emulated-integration-tests-common = { path = "../../../../common", default-features = false } penpal-runtime = { path = "../../../../../../runtimes/testing/penpal" } -rococo-emulated-chain = { path = "../../../relays/rococo" } -westend-emulated-chain = { path = "../../../relays/westend" } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs index 9ab32a977d7..48901647fd0 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs @@ -14,19 +14,27 @@ // limitations under the License. // Substrate +use frame_support::parameter_types; use sp_core::{sr25519, storage::Storage}; +// Polkadot +use xcm::v3::Location; // Cumulus use emulated_integration_tests_common::{ accounts, build_genesis_storage, collators, get_account_id_from_seed, SAFE_XCM_VERSION, }; -use parachains_common::Balance; - +use parachains_common::{AccountId, Balance}; +use penpal_runtime::xcm_config::{LocalReservableFromAssetHub, RelayLocation}; // Penpal pub const PARA_ID_A: u32 = 2000; pub const PARA_ID_B: u32 = 2001; pub const ED: Balance = penpal_runtime::EXISTENTIAL_DEPOSIT; +parameter_types! { + pub PenpalSudoAcccount: AccountId = get_account_id_from_seed::("Alice"); + pub PenpalAssetOwner: AccountId = PenpalSudoAcccount::get(); +} + pub fn genesis(para_id: u32) -> Storage { let genesis_config = penpal_runtime::RuntimeGenesisConfig { system: penpal_runtime::SystemConfig::default(), @@ -58,8 +66,35 @@ pub fn genesis(para_id: u32) -> Storage { safe_xcm_version: Some(SAFE_XCM_VERSION), ..Default::default() }, - sudo: penpal_runtime::SudoConfig { - key: Some(get_account_id_from_seed::("Alice")), + sudo: penpal_runtime::SudoConfig { key: Some(PenpalSudoAcccount::get()) }, + assets: penpal_runtime::AssetsConfig { + assets: vec![( + penpal_runtime::xcm_config::TELEPORTABLE_ASSET_ID, + PenpalAssetOwner::get(), + false, + ED, + )], + ..Default::default() + }, + foreign_assets: penpal_runtime::ForeignAssetsConfig { + assets: vec![ + // Relay Native asset representation + ( + Location::try_from(RelayLocation::get()).expect("conversion works"), + PenpalAssetOwner::get(), + true, + ED, + ), + // Sufficient AssetHub asset representation + ( + Location::try_from(LocalReservableFromAssetHub::get()) + .expect("conversion works"), + PenpalAssetOwner::get(), + true, + ED, + ), + ], + ..Default::default() }, ..Default::default() }; diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs index c1e03046655..651b3a52306 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs @@ -14,10 +14,9 @@ // limitations under the License. mod genesis; -pub use genesis::{genesis, ED, PARA_ID_A, PARA_ID_B}; +pub use genesis::{genesis, PenpalAssetOwner, PenpalSudoAcccount, ED, PARA_ID_A, PARA_ID_B}; pub use penpal_runtime::xcm_config::{ - CustomizableAssetFromSystemAssetHub, LocalTeleportableToAssetHub, - LocalTeleportableToAssetHubV3, XcmConfig, + CustomizableAssetFromSystemAssetHub, LocalTeleportableToAssetHub, XcmConfig, }; // Substrate @@ -28,8 +27,6 @@ use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, impl_assets_helpers_for_parachain, impls::Parachain, xcm_emulator::decl_test_parachains, }; -use rococo_emulated_chain::Rococo; -use westend_emulated_chain::Westend; // Penpal Parachain declaration decl_test_parachains! { @@ -76,7 +73,7 @@ decl_test_parachains! { // Penpal implementation impl_accounts_helpers_for_parachain!(PenpalA); impl_accounts_helpers_for_parachain!(PenpalB); -impl_assets_helpers_for_parachain!(PenpalA, Rococo); -impl_assets_helpers_for_parachain!(PenpalB, Westend); impl_assert_events_helpers_for_parachain!(PenpalA); impl_assert_events_helpers_for_parachain!(PenpalB); +impl_assets_helpers_for_parachain!(PenpalA); +impl_assets_helpers_for_parachain!(PenpalB); diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index 721c58fd864..8c44cce7d92 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -27,6 +27,7 @@ pallet-message-queue = { path = "../../../../../substrate/frame/message-queue" } # Polkadot polkadot-primitives = { path = "../../../../../polkadot/primitives" } +polkadot-parachain-primitives = { path = "../../../../../polkadot/parachain" } polkadot-runtime-parachains = { path = "../../../../../polkadot/runtime/parachains" } xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm" } pallet-xcm = { path = "../../../../../polkadot/xcm/pallet-xcm" } diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index c93484829fe..5fc08dff32c 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -592,7 +592,7 @@ macro_rules! impl_assert_events_helpers_for_parachain { } #[macro_export] -macro_rules! impl_assets_helpers_for_parachain { +macro_rules! impl_assets_helpers_for_system_parachain { ( $chain:ident, $relay_chain:ident ) => { $crate::impls::paste::paste! { impl $chain { @@ -630,38 +630,6 @@ macro_rules! impl_assets_helpers_for_parachain { $crate::impls::xcm_transact_unpaid_execution(call, origin_kind) } - /// Mint assets making use of the assets pallet - pub fn mint_asset( - signed_origin: ::RuntimeOrigin, - id: u32, - beneficiary: $crate::impls::AccountId, - amount_to_mint: u128, - ) { - ::execute_with(|| { - $crate::impls::assert_ok!(]>::Assets::mint( - signed_origin, - id.clone().into(), - beneficiary.clone().into(), - amount_to_mint - )); - - type RuntimeEvent = <$chain as $crate::impls::Chain>::RuntimeEvent; - - $crate::impls::assert_expected_events!( - Self, - vec![ - RuntimeEvent::::Assets( - $crate::impls::pallet_assets::Event::Issued { asset_id, owner, amount } - ) => { - asset_id: *asset_id == id, - owner: *owner == beneficiary.clone().into(), - amount: *amount == amount_to_mint, - }, - ] - ); - }); - } - /// Force create and mint assets making use of the assets pallet pub fn force_create_and_mint_asset( id: u32, @@ -727,8 +695,8 @@ macro_rules! impl_assets_helpers_for_parachain { } #[macro_export] -macro_rules! impl_foreign_assets_helpers_for_parachain { - ( $chain:ident, $relay_chain:ident ) => { +macro_rules! impl_assets_helpers_for_parachain { + ( $chain:ident) => { $crate::impls::paste::paste! { impl $chain { /// Create foreign assets using sudo `ForeignAssets::force_create()` @@ -803,6 +771,118 @@ macro_rules! impl_foreign_assets_helpers_for_parachain { ); }); } + /// Create assets using sudo `Assets::force_create()` + pub fn force_create_asset( + id: u32, + owner: $crate::impls::AccountId, + is_sufficient: bool, + min_balance: u128, + prefund_accounts: Vec<($crate::impls::AccountId, u128)>, + ) { + use $crate::impls::Inspect; + let sudo_origin = <$chain as $crate::impls::Chain>::RuntimeOrigin::root(); + ::execute_with(|| { + $crate::impls::assert_ok!( + ]>::Assets::force_create( + sudo_origin, + id.clone().into(), + owner.clone().into(), + is_sufficient, + min_balance, + ) + ); + assert!(]>::Assets::asset_exists(id.clone())); + type RuntimeEvent = <$chain as $crate::impls::Chain>::RuntimeEvent; + $crate::impls::assert_expected_events!( + Self, + vec![ + RuntimeEvent::::Assets( + $crate::impls::pallet_assets::Event::ForceCreated { + asset_id, + .. + } + ) => { asset_id: *asset_id == id, }, + ] + ); + }); + for (beneficiary, amount) in prefund_accounts.into_iter() { + let signed_origin = + <$chain as $crate::impls::Chain>::RuntimeOrigin::signed(owner.clone()); + Self::mint_asset(signed_origin, id.clone(), beneficiary, amount); + } + } + + /// Mint assets making use of the assets pallet + pub fn mint_asset( + signed_origin: ::RuntimeOrigin, + id: u32, + beneficiary: $crate::impls::AccountId, + amount_to_mint: u128, + ) { + ::execute_with(|| { + $crate::impls::assert_ok!(]>::Assets::mint( + signed_origin, + id.clone().into(), + beneficiary.clone().into(), + amount_to_mint + )); + + type RuntimeEvent = <$chain as $crate::impls::Chain>::RuntimeEvent; + + $crate::impls::assert_expected_events!( + Self, + vec![ + RuntimeEvent::::Assets( + $crate::impls::pallet_assets::Event::Issued { asset_id, owner, amount } + ) => { + asset_id: *asset_id == id, + owner: *owner == beneficiary.clone().into(), + amount: *amount == amount_to_mint, + }, + ] + ); + }); + } + + /// Returns the encoded call for `create` from the assets pallet + pub fn create_asset_call( + asset_id: u32, + min_balance: $crate::impls::Balance, + admin: $crate::impls::AccountId, + ) -> $crate::impls::DoubleEncoded<()> { + use $crate::impls::{Chain, Encode}; + + ::RuntimeCall::Assets($crate::impls::pallet_assets::Call::< + ::Runtime, + $crate::impls::pallet_assets::Instance1, + >::create { + id: asset_id.into(), + min_balance, + admin: admin.into(), + }) + .encode() + .into() + } + + /// Returns the encoded call for `create` from the foreign assets pallet + pub fn create_foreign_asset_call( + asset_id: $crate::impls::v3::Location, + min_balance: $crate::impls::Balance, + admin: $crate::impls::AccountId, + ) -> $crate::impls::DoubleEncoded<()> { + use $crate::impls::{Chain, Encode}; + + ::RuntimeCall::ForeignAssets($crate::impls::pallet_assets::Call::< + ::Runtime, + $crate::impls::pallet_assets::Instance2, + >::create { + id: asset_id.into(), + min_balance, + admin: admin.into(), + }) + .encode() + .into() + } } } }; diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index 1a5cc1f6fea..40204ca297a 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -21,17 +21,19 @@ pub use xcm_emulator; // Substrate use beefy_primitives::ecdsa_crypto::AuthorityId as BeefyId; +use frame_support::parameter_types; use grandpa::AuthorityId as GrandpaId; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_babe::AuthorityId as BabeId; use sp_core::{sr25519, storage::Storage, Pair, Public}; use sp_runtime::{ - traits::{IdentifyAccount, Verify}, + traits::{AccountIdConversion, IdentifyAccount, Verify}, BuildStorage, MultiSignature, }; // Polakdot use parachains_common::BlockNumber; +use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_parachains::configuration::HostConfiguration; // Cumulus @@ -49,6 +51,25 @@ pub const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION; type AccountPublic = ::Signer; +// This asset is added to AH as Asset and reserved transfer between Parachain and AH +pub const RESERVABLE_ASSET_ID: u32 = 1; +// This asset is added to AH as ForeignAsset and teleported between Penpal and AH +pub const TELEPORTABLE_ASSET_ID: u32 = 2; + +pub const PENPAL_ID: u32 = 2000; +pub const ASSETS_PALLET_ID: u8 = 50; + +parameter_types! { + pub PenpalTeleportableAssetLocation: xcm::v3::Location + = xcm::v3::Location::new(1, [ + xcm::v3::Junction::Parachain(PENPAL_ID), + xcm::v3::Junction::PalletInstance(ASSETS_PALLET_ID), + xcm::v3::Junction::GeneralIndex(TELEPORTABLE_ASSET_ID.into()), + ] + ); + pub PenpalSiblingSovereigAccount: AccountId = Sibling::from(PENPAL_ID).into_account_truncating(); +} + /// Helper function to generate a crypto pair from seed pub fn get_from_seed(seed: &str) -> ::Public { TPublic::Pair::from_string(&format!("//{}", seed), None) diff --git a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs index d3bb3238a3b..6951de6faa7 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs @@ -16,16 +16,26 @@ pub use paste; // Substrate +pub use frame_support::{pallet_prelude::Weight, weights::WeightToFee}; +pub use pallet_assets; pub use pallet_balances; pub use pallet_message_queue; pub use pallet_xcm; // Polkadot -pub use xcm::prelude::{AccountId32, WeightLimit}; +pub use xcm::{ + prelude::{ + AccountId32, All, Asset, AssetId, BuyExecution, DepositAsset, ExpectTransactStatus, + Fungible, Here, Location, MaybeErrorCode, OriginKind, RefundSurplus, Transact, Unlimited, + VersionedXcm, WeightLimit, WithdrawAsset, Xcm, + }, + v3::Location as V3Location, +}; // Cumulus pub use asset_test_utils; pub use cumulus_pallet_xcmp_queue; +pub use parachains_common::AccountId; pub use xcm_emulator::Chain; #[macro_export] @@ -120,102 +130,3 @@ macro_rules! test_parachain_is_trusted_teleporter { } }; } - -#[macro_export] -macro_rules! include_penpal_create_foreign_asset_on_asset_hub { - ( $penpal:ident, $asset_hub:ident, $relay_ed:expr, $weight_to_fee:expr) => { - $crate::impls::paste::paste! { - pub fn penpal_create_foreign_asset_on_asset_hub( - asset_id_on_penpal: u32, - foreign_asset_at_asset_hub: v3::Location, - ah_as_seen_by_penpal: Location, - is_sufficient: bool, - asset_owner: AccountId, - prefund_amount: u128, - ) { - use frame_support::weights::WeightToFee; - let ah_check_account = $asset_hub::execute_with(|| { - <$asset_hub as [<$asset_hub Pallet>]>::PolkadotXcm::check_account() - }); - let penpal_check_account = - $penpal::execute_with(|| <$penpal as [<$penpal Pallet>]>::PolkadotXcm::check_account()); - let penpal_as_seen_by_ah = $asset_hub::sibling_location_of($penpal::para_id()); - - // prefund SA of Penpal on AssetHub with enough native tokens to pay for creating - // new foreign asset, also prefund CheckingAccount with ED, because teleported asset - // itself might not be sufficient and CheckingAccount cannot be created otherwise - let sov_penpal_on_ah = $asset_hub::sovereign_account_id_of(penpal_as_seen_by_ah.clone()); - $asset_hub::fund_accounts(vec![ - (sov_penpal_on_ah.clone().into(), $relay_ed * 100_000_000_000), - (ah_check_account.clone().into(), $relay_ed * 1000), - ]); - - // prefund SA of AssetHub on Penpal with native asset - let sov_ah_on_penpal = $penpal::sovereign_account_id_of(ah_as_seen_by_penpal.clone()); - $penpal::fund_accounts(vec![ - (sov_ah_on_penpal.into(), $relay_ed * 1_000_000_000), - (penpal_check_account.clone().into(), $relay_ed * 1000), - ]); - - // Force create asset on $penpal and prefund [<$penpal Sender>] - $penpal::force_create_and_mint_asset( - asset_id_on_penpal, - ASSET_MIN_BALANCE, - is_sufficient, - asset_owner, - None, - prefund_amount, - ); - - let require_weight_at_most = Weight::from_parts(1_100_000_000_000, 30_000); - // `OriginKind::Xcm` required by ForeignCreators pallet-assets origin filter - let origin_kind = OriginKind::Xcm; - let call_create_foreign_assets = - <$asset_hub as Chain>::RuntimeCall::ForeignAssets(pallet_assets::Call::< - <$asset_hub as Chain>::Runtime, - pallet_assets::Instance2, - >::create { - id: foreign_asset_at_asset_hub, - min_balance: ASSET_MIN_BALANCE, - admin: sov_penpal_on_ah.into(), - }) - .encode(); - let buy_execution_fee_amount = $weight_to_fee::weight_to_fee( - &Weight::from_parts(10_100_000_000_000, 300_000), - ); - let buy_execution_fee = Asset { - id: AssetId(Location { parents: 1, interior: Here }), - fun: Fungible(buy_execution_fee_amount), - }; - let xcm = VersionedXcm::from(Xcm(vec![ - WithdrawAsset { 0: vec![buy_execution_fee.clone()].into() }, - BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited }, - Transact { require_weight_at_most, origin_kind, call: call_create_foreign_assets.into() }, - ExpectTransactStatus(MaybeErrorCode::Success), - RefundSurplus, - DepositAsset { assets: All.into(), beneficiary: penpal_as_seen_by_ah }, - ])); - // Send XCM message from penpal => asset_hub - let sudo_penpal_origin = <$penpal as Chain>::RuntimeOrigin::root(); - $penpal::execute_with(|| { - assert_ok!(<$penpal as [<$penpal Pallet>]>::PolkadotXcm::send( - sudo_penpal_origin.clone(), - bx!(ah_as_seen_by_penpal.into()), - bx!(xcm), - )); - type RuntimeEvent = <$penpal as Chain>::RuntimeEvent; - assert_expected_events!( - $penpal, - vec![ - RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - $asset_hub::execute_with(|| { - type ForeignAssets = <$asset_hub as [<$asset_hub Pallet>]>::ForeignAssets; - assert!(ForeignAssets::asset_exists(foreign_asset_at_asset_hub)); - }); - } - } - }; -} diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml index 0a397c2617b..13eb7d8dfc4 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml @@ -34,5 +34,6 @@ parachains-common = { path = "../../../../../../parachains/common" } cumulus-pallet-parachain-system = { path = "../../../../../../pallets/parachain-system", default-features = false } testnet-parachains-constants = { path = "../../../../../runtimes/constants", features = ["rococo"] } asset-hub-rococo-runtime = { path = "../../../../../runtimes/assets/asset-hub-rococo" } +penpal-runtime = { path = "../../../../../runtimes/testing/penpal" } emulated-integration-tests-common = { path = "../../../common", default-features = false } rococo-system-emulated-network = { path = "../../../networks/rococo-system" } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs index 1cc25cb54a1..21d858f1fe5 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs @@ -13,59 +13,79 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub use codec::Encode; +#[cfg(test)] +mod imports { + pub use codec::Encode; + + // Substrate + pub use frame_support::{ + assert_err, assert_ok, + pallet_prelude::Weight, + sp_runtime::{DispatchError, DispatchResult, ModuleError}, + traits::fungibles::Inspect, + }; -// Substrate -pub use frame_support::{ - assert_err, assert_ok, - pallet_prelude::Weight, - sp_runtime::{AccountId32, DispatchError, DispatchResult}, - traits::fungibles::Inspect, -}; + // Polkadot + pub use xcm::{ + prelude::{AccountId32 as AccountId32Junction, *}, + v3, + }; -// Polkadot -pub use xcm::{ - prelude::{AccountId32 as AccountId32Junction, *}, - v3::{self, Error, NetworkId::Rococo as RococoId}, -}; + // Cumulus + pub use asset_test_utils::xcm_helpers; + pub use emulated_integration_tests_common::{ + test_parachain_is_trusted_teleporter, + xcm_emulator::{ + assert_expected_events, bx, Chain, Parachain as Para, RelayChain as Relay, Test, + TestArgs, TestContext, TestExt, + }, + xcm_helpers::{non_fee_asset, xcm_transact_paid_execution}, + ASSETS_PALLET_ID, RESERVABLE_ASSET_ID, XCM_V3, + }; + pub use parachains_common::Balance; + pub use rococo_system_emulated_network::{ + asset_hub_rococo_emulated_chain::{ + genesis::{AssetHubRococoAssetOwner, ED as ASSET_HUB_ROCOCO_ED}, + AssetHubRococoParaPallet as AssetHubRococoPallet, + }, + penpal_emulated_chain::{ + PenpalAParaPallet as PenpalAPallet, PenpalAssetOwner, + PenpalBParaPallet as PenpalBPallet, ED as PENPAL_ED, + }, + rococo_emulated_chain::{genesis::ED as ROCOCO_ED, RococoRelayPallet as RococoPallet}, + AssetHubRococoPara as AssetHubRococo, AssetHubRococoParaReceiver as AssetHubRococoReceiver, + AssetHubRococoParaSender as AssetHubRococoSender, BridgeHubRococoPara as BridgeHubRococo, + BridgeHubRococoParaReceiver as BridgeHubRococoReceiver, PenpalAPara as PenpalA, + PenpalAParaReceiver as PenpalAReceiver, PenpalAParaSender as PenpalASender, + PenpalBPara as PenpalB, PenpalBParaReceiver as PenpalBReceiver, RococoRelay as Rococo, + RococoRelayReceiver as RococoReceiver, RococoRelaySender as RococoSender, + }; -// Cumulus -pub use asset_test_utils::xcm_helpers; -pub use emulated_integration_tests_common::{ - test_parachain_is_trusted_teleporter, - xcm_emulator::{ - assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, - RelayChain as Relay, Test, TestArgs, TestContext, TestExt, - }, - xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, - PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, -}; -pub use parachains_common::{AccountId, Balance}; -pub use rococo_system_emulated_network::{ - asset_hub_rococo_emulated_chain::{ - genesis::ED as ASSET_HUB_ROCOCO_ED, AssetHubRococoParaPallet as AssetHubRococoPallet, - }, - penpal_emulated_chain::PenpalAParaPallet as PenpalAPallet, - rococo_emulated_chain::{genesis::ED as ROCOCO_ED, RococoRelayPallet as RococoPallet}, - AssetHubRococoPara as AssetHubRococo, AssetHubRococoParaReceiver as AssetHubRococoReceiver, - AssetHubRococoParaSender as AssetHubRococoSender, BridgeHubRococoPara as BridgeHubRococo, - BridgeHubRococoParaReceiver as BridgeHubRococoReceiver, PenpalAPara as PenpalA, - PenpalAParaReceiver as PenpalAReceiver, PenpalAParaSender as PenpalASender, - PenpalBPara as PenpalB, PenpalBParaReceiver as PenpalBReceiver, RococoRelay as Rococo, - RococoRelayReceiver as RococoReceiver, RococoRelaySender as RococoSender, -}; + // Runtimes + pub use asset_hub_rococo_runtime::xcm_config::{ + TokenLocation as RelayLocation, UniversalLocation as AssetHubRococoUniversalLocation, + XcmConfig as AssetHubRococoXcmConfig, + }; + pub use penpal_runtime::xcm_config::{ + LocalReservableFromAssetHub as PenpalLocalReservableFromAssetHub, + LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub, + UniversalLocation as PenpalUniversalLocation, XcmConfig as PenpalRococoXcmConfig, + }; + pub use rococo_runtime::xcm_config::{ + UniversalLocation as RococoUniversalLocation, XcmConfig as RococoXcmConfig, + }; -pub const ASSET_ID: u32 = 1; -pub const ASSET_MIN_BALANCE: u128 = 1000; -// `Assets` pallet index -pub const ASSETS_PALLET_ID: u8 = 50; + pub const ASSET_ID: u32 = 3; + pub const ASSET_MIN_BALANCE: u128 = 1000; -pub type RelayToSystemParaTest = Test; -pub type RelayToParaTest = Test; -pub type SystemParaToRelayTest = Test; -pub type SystemParaToParaTest = Test; -pub type ParaToSystemParaTest = Test; -pub type ParaToParaTest = Test; + pub type RelayToSystemParaTest = Test; + pub type RelayToParaTest = Test; + pub type ParaToRelayTest = Test; + pub type SystemParaToRelayTest = Test; + pub type SystemParaToParaTest = Test; + pub type ParaToSystemParaTest = Test; + pub type ParaToParaThroughRelayTest = Test; +} #[cfg(test)] mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs index 21bed234304..b3841af0e6c 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs @@ -18,11 +18,3 @@ mod send; mod set_xcm_versions; mod swap; mod teleport; - -use crate::*; -emulated_integration_tests_common::include_penpal_create_foreign_asset_on_asset_hub!( - PenpalA, - AssetHubRococo, - ROCOCO_ED, - testnet_parachains_constants::rococo::fee::WeightToFee -); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index d2c3a323256..705c9613b64 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -13,14 +13,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; -use asset_hub_rococo_runtime::xcm_config::XcmConfig as AssetHubRococoXcmConfig; -use rococo_runtime::xcm_config::XcmConfig as RococoXcmConfig; -use rococo_system_emulated_network::penpal_emulated_chain::XcmConfig as PenpalRococoXcmConfig; +use crate::imports::*; fn relay_to_para_sender_assertions(t: RelayToParaTest) { type RuntimeEvent = ::RuntimeEvent; + Rococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8_799))); + assert_expected_events!( Rococo, vec![ @@ -38,12 +37,32 @@ fn relay_to_para_sender_assertions(t: RelayToParaTest) { ); } +fn para_to_relay_sender_assertions(t: ParaToRelayTest) { + type RuntimeEvent = ::RuntimeEvent; + PenpalA::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8_799))); + assert_expected_events!( + PenpalA, + vec![ + // Amount to reserve transfer is transferred to Parachain's Sovereign account + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Burned { asset_id, owner, balance, .. } + ) => { + asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).expect("conversion works"), + owner: *owner == t.sender.account_id, + balance: *balance == t.args.amount, + }, + ] + ); +} + fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; + AssetHubRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( 864_610_000, 8_799, ))); + assert_expected_events!( AssetHubRococo, vec![ @@ -57,19 +76,29 @@ fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { ), amount: *amount == t.args.amount, }, + // Transport fees are paid + RuntimeEvent::PolkadotXcm( + pallet_xcm::Event::FeesPaid { .. } + ) => {}, ] ); + AssetHubRococo::assert_xcm_pallet_sent(); } -fn para_receiver_assertions(_: Test) { +fn system_para_to_para_receiver_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; + let system_para_native_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + + PenpalA::assert_xcmp_queue_success(None); + assert_expected_events!( PenpalA, vec![ - RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == system_para_native_asset_location, + owner: *owner == t.receiver.account_id, + }, ] ); } @@ -81,12 +110,42 @@ fn para_to_system_para_sender_assertions(t: ParaToSystemParaTest) { PenpalA, vec![ // Amount to reserve transfer is transferred to Parachain's Sovereign account + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Burned { asset_id, owner, balance, .. } + ) => { + asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).expect("conversion works"), + owner: *owner == t.sender.account_id, + balance: *balance == t.args.amount, + }, + ] + ); +} + +fn para_to_relay_receiver_assertions(t: ParaToRelayTest) { + type RuntimeEvent = ::RuntimeEvent; + let sov_penpal_on_relay = + Rococo::sovereign_account_id_of(Rococo::child_location_of(PenpalA::para_id())); + + Rococo::assert_ump_queue_processed( + true, + Some(PenpalA::para_id()), + Some(Weight::from_parts(306305000, 7_186)), + ); + + assert_expected_events!( + Rococo, + vec![ + // Amount to reserve transfer is withdrawn from Parachain's Sovereign account RuntimeEvent::Balances( pallet_balances::Event::Burned { who, amount } ) => { - who: *who == t.sender.account_id, + who: *who == sov_penpal_on_relay.clone().into(), amount: *amount == t.args.amount, }, + RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, ] ); } @@ -96,6 +155,9 @@ fn para_to_system_para_receiver_assertions(t: ParaToSystemParaTest) { let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of( AssetHubRococo::sibling_location_of(PenpalA::para_id()), ); + + AssetHubRococo::assert_xcmp_queue_success(None); + assert_expected_events!( AssetHubRococo, vec![ @@ -127,24 +189,124 @@ fn system_para_to_para_assets_sender_assertions(t: SystemParaToParaTest) { RuntimeEvent::Assets( pallet_assets::Event::Transferred { asset_id, from, to, amount } ) => { - asset_id: *asset_id == ASSET_ID, + asset_id: *asset_id == RESERVABLE_ASSET_ID, from: *from == t.sender.account_id, to: *to == AssetHubRococo::sovereign_account_id_of( t.args.dest.clone() ), amount: *amount == t.args.amount, }, + // Native asset to pay for fees is transferred to Parachain's Sovereign account + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { + who: *who == AssetHubRococo::sovereign_account_id_of( + t.args.dest.clone() + ), + }, + // Transport fees are paid + RuntimeEvent::PolkadotXcm( + pallet_xcm::Event::FeesPaid { .. } + ) => {}, ] ); } -fn system_para_to_para_assets_receiver_assertions(_: Test) { +fn para_to_system_para_assets_sender_assertions(t: ParaToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; + let system_para_native_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let reservable_asset_location = + v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).expect("conversion works"); + PenpalA::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8799))); assert_expected_events!( PenpalA, vec![ - RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, - RuntimeEvent::Assets(pallet_assets::Event::Issued { .. }) => {}, + // Fees amount to reserve transfer is burned from Parachains's sender account + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Burned { asset_id, owner, .. } + ) => { + asset_id: *asset_id == system_para_native_asset_location, + owner: *owner == t.sender.account_id, + }, + // Amount to reserve transfer is burned from Parachains's sender account + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Burned { asset_id, owner, balance } + ) => { + asset_id: *asset_id == reservable_asset_location, + owner: *owner == t.sender.account_id, + balance: *balance == t.args.amount, + }, + // Transport fees are paid + RuntimeEvent::PolkadotXcm( + pallet_xcm::Event::FeesPaid { .. } + ) => {}, + ] + ); +} + +fn system_para_to_para_assets_receiver_assertions(t: SystemParaToParaTest) { + type RuntimeEvent = ::RuntimeEvent; + let system_para_asset_location = + v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).expect("conversion works"); + PenpalA::assert_xcmp_queue_success(None); + assert_expected_events!( + PenpalA, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).expect("conversion works"), + owner: *owner == t.receiver.account_id, + }, + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { + asset_id: *asset_id == system_para_asset_location, + owner: *owner == t.receiver.account_id, + amount: *amount == t.args.amount, + }, + ] + ); +} + +fn para_to_system_para_assets_receiver_assertions(t: ParaToSystemParaTest) { + type RuntimeEvent = ::RuntimeEvent; + let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of( + AssetHubRococo::sibling_location_of(PenpalA::para_id()), + ); + AssetHubRococo::assert_xcmp_queue_success(None); + assert_expected_events!( + AssetHubRococo, + vec![ + // Amount to reserve transfer is burned from Parachain's Sovereign account + RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { + asset_id: *asset_id == RESERVABLE_ASSET_ID, + owner: *owner == sov_penpal_on_ahr, + balance: *balance == t.args.amount, + }, + // Fee amount is burned from Parachain's Sovereign account + RuntimeEvent::Balances(pallet_balances::Event::Burned { who, .. }) => { + who: *who == sov_penpal_on_ahr, + }, + // Amount to reserve transfer is issued for beneficiary + RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { + asset_id: *asset_id == RESERVABLE_ASSET_ID, + owner: *owner == t.receiver.account_id, + amount: *amount == t.args.amount, + }, + // Remaining fee amount is minted for for beneficiary + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { + who: *who == t.receiver.account_id, + }, + ] + ); +} + +fn relay_to_para_assets_receiver_assertions(t: RelayToParaTest) { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + PenpalA, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).expect("conversion works"), + owner: *owner == t.receiver.account_id, + }, RuntimeEvent::MessageQueue( pallet_message_queue::Event::Processed { success: true, .. } ) => {}, @@ -152,33 +314,38 @@ fn system_para_to_para_assets_receiver_assertions(_: Test) { ); } -fn para_to_para_sender_assertions(t: ParaToParaTest) { +fn para_to_para_through_relay_sender_assertions(t: ParaToParaThroughRelayTest) { type RuntimeEvent = ::RuntimeEvent; + + let relay_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + PenpalA::assert_xcm_pallet_attempted_complete(None); + // XCM sent to relay reserve + PenpalA::assert_parachain_system_ump_sent(); + assert_expected_events!( PenpalA, vec![ // Amount to reserve transfer is transferred to Parachain's Sovereign account - RuntimeEvent::Balances( - pallet_balances::Event::Burned { who, amount } + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Burned { asset_id, owner, balance }, ) => { - who: *who == t.sender.account_id, - amount: *amount == t.args.amount, + asset_id: *asset_id == relay_asset_location, + owner: *owner == t.sender.account_id, + balance: *balance == t.args.amount, }, - // XCM sent to relay reserve - RuntimeEvent::ParachainSystem( - cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } - ) => {}, ] ); } -fn para_to_para_relay_hop_assertions(t: ParaToParaTest) { +fn para_to_para_relay_hop_assertions(t: ParaToParaThroughRelayTest) { type RuntimeEvent = ::RuntimeEvent; let sov_penpal_a_on_rococo = Rococo::sovereign_account_id_of(Rococo::child_location_of(PenpalA::para_id())); let sov_penpal_b_on_rococo = Rococo::sovereign_account_id_of(Rococo::child_location_of(PenpalB::para_id())); + assert_expected_events!( Rococo, vec![ @@ -202,15 +369,20 @@ fn para_to_para_relay_hop_assertions(t: ParaToParaTest) { ); } -fn para_to_para_receiver_assertions(_: ParaToParaTest) { +fn para_to_para_through_relay_receiver_assertions(t: ParaToParaThroughRelayTest) { type RuntimeEvent = ::RuntimeEvent; + let relay_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + + PenpalB::assert_xcmp_queue_success(None); + assert_expected_events!( PenpalB, vec![ - RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == relay_asset_location, + owner: *owner == t.receiver.account_id, + }, ] ); } @@ -226,6 +398,17 @@ fn relay_to_para_reserve_transfer_assets(t: RelayToParaTest) -> DispatchResult { ) } +fn para_to_relay_reserve_transfer_assets(t: ParaToRelayTest) -> DispatchResult { + ::PolkadotXcm::limited_reserve_transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + t.args.weight_limit, + ) +} + fn system_para_to_para_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { ::PolkadotXcm::limited_reserve_transfer_assets( t.signed_origin, @@ -248,7 +431,9 @@ fn para_to_system_para_reserve_transfer_assets(t: ParaToSystemParaTest) -> Dispa ) } -fn para_to_para_limited_reserve_transfer_assets(t: ParaToParaTest) -> DispatchResult { +fn para_to_para_through_relay_limited_reserve_transfer_assets( + t: ParaToParaThroughRelayTest, +) -> DispatchResult { ::PolkadotXcm::limited_reserve_transfer_assets( t.signed_origin, bx!(t.args.dest.into()), @@ -262,6 +447,7 @@ fn para_to_para_limited_reserve_transfer_assets(t: ParaToParaTest) -> DispatchRe /// Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't work #[test] fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { + // Init values for Relay Chain let signed_origin = ::RuntimeOrigin::signed(RococoSender::get().into()); let destination = Rococo::child_location_of(AssetHubRococo::para_id()); let beneficiary: Location = @@ -328,135 +514,298 @@ fn reserve_transfer_native_asset_from_system_para_to_relay_fails() { }); } +// ========================================================================= +// ========= Reserve Transfers - Native Asset - Relay<>Parachain =========== +// ========================================================================= /// Reserve Transfers of native asset from Relay to Parachain should work #[test] fn reserve_transfer_native_asset_from_relay_to_para() { // Init values for Relay let destination = Rococo::child_location_of(PenpalA::para_id()); - let beneficiary_id = PenpalAReceiver::get(); + let sender = RococoSender::get(); let amount_to_send: Balance = ROCOCO_ED * 1000; + let assets: Assets = (Here, amount_to_send).into(); + + // Init values fot Parachain + let relay_native_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let receiver = PenpalAReceiver::get(); + // Init Test let test_args = TestContext { - sender: RococoSender::get(), - receiver: PenpalAReceiver::get(), - args: TestArgs::new_relay(destination, beneficiary_id, amount_to_send), + sender, + receiver: receiver.clone(), + args: TestArgs::new_relay(destination.clone(), receiver.clone(), amount_to_send), }; - let mut test = RelayToParaTest::new(test_args); + // Query initial balances let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; + let receiver_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.into(), &receiver) + }); + // Set assertions and dispatchables test.set_assertion::(relay_to_para_sender_assertions); - test.set_assertion::(para_receiver_assertions); + test.set_assertion::(relay_to_para_assets_receiver_assertions); test.set_dispatchable::(relay_to_para_reserve_transfer_assets); test.assert(); + // Calculate delivery fees let delivery_fees = Rococo::execute_with(|| { + let reanchored_assets = + assets.reanchored(&destination, &RococoUniversalLocation::get()).unwrap(); xcm_helpers::transfer_assets_delivery_fees::< ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); + // Query final balances let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; + let receiver_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.into(), &receiver) + }); // Sender's balance is reduced assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased + // Receiver's asset balance is increased + assert!(receiver_assets_after > receiver_assets_before); + // Receiver's asset balance increased by `amount_to_send - delivery_fees - bought_execution`; + // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but + // should be non-zero + assert!(receiver_assets_after < receiver_assets_before + amount_to_send); +} + +/// Reserve Transfers of native asset from Parachain to Relay should work +#[test] +fn reserve_transfer_native_asset_from_para_to_relay() { + // Init values for Parachain + let destination = PenpalA::parent_location(); + let sender = PenpalASender::get(); + let amount_to_send: Balance = ROCOCO_ED * 1000; + let assets: Assets = (Parent, amount_to_send).into(); + let asset_owner = PenpalAssetOwner::get(); + let relay_native_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + + // fund Parachain's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner), + relay_native_asset_location, + sender.clone(), + amount_to_send, + ); + + // Init values for Relay + let receiver = RococoReceiver::get(); + let penpal_location_as_seen_by_relay = Rococo::child_location_of(PenpalA::para_id()); + let sov_penpal_on_relay = Rococo::sovereign_account_id_of(penpal_location_as_seen_by_relay); + + // fund Parachain's SA on Relay with the native tokens held in reserve + Rococo::fund_accounts(vec![(sov_penpal_on_relay.into(), amount_to_send * 2)]); + + // Init Test + let test_args = TestContext { + sender: sender.clone(), + receiver: receiver.clone(), + args: TestArgs::new_para( + destination.clone(), + receiver, + amount_to_send, + assets.clone(), + None, + 0, + ), + }; + let mut test = ParaToRelayTest::new(test_args); + + // Query initial balances + let sender_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.into(), &sender) + }); + let receiver_balance_before = test.receiver.balance; + + // Set assertions and dispatchables + test.set_assertion::(para_to_relay_sender_assertions); + test.set_assertion::(para_to_relay_receiver_assertions); + test.set_dispatchable::(para_to_relay_reserve_transfer_assets); + test.assert(); + + // Calculate delivery fees + let delivery_fees = PenpalA::execute_with(|| { + let reanchored_assets = + assets.reanchored(&destination, &PenpalUniversalLocation::get()).unwrap(); + xcm_helpers::transfer_assets_delivery_fees::< + ::XcmSender, + >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + + // Query final balances + let sender_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.into(), &sender) + }); + let receiver_balance_after = test.receiver.balance; + + // Sender's balance is reduced + assert_eq!(sender_assets_before - amount_to_send - delivery_fees, sender_assets_after); + // Receiver's asset balance is increased assert!(receiver_balance_after > receiver_balance_before); - // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; + // Receiver's asset balance increased by `amount_to_send - delivery_fees - bought_execution`; // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but // should be non-zero assert!(receiver_balance_after < receiver_balance_before + amount_to_send); } +// ========================================================================= +// ======= Reserve Transfers - Native Asset - AssetHub<>Parachain ========== +// ========================================================================= /// Reserve Transfers of native asset from System Parachain to Parachain should work #[test] fn reserve_transfer_native_asset_from_system_para_to_para() { // Init values for System Parachain let destination = AssetHubRococo::sibling_location_of(PenpalA::para_id()); - let beneficiary_id = PenpalAReceiver::get(); - let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; - let assets = (Parent, amount_to_send).into(); + let sender = AssetHubRococoSender::get(); + let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 10000; + let assets: Assets = (Parent, amount_to_send).into(); + + // Init values for Parachain + let system_para_native_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let receiver = PenpalAReceiver::get(); + // Init Test let test_args = TestContext { - sender: AssetHubRococoSender::get(), - receiver: PenpalAReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), + sender, + receiver: receiver.clone(), + args: TestArgs::new_para( + destination.clone(), + receiver.clone(), + amount_to_send, + assets.clone(), + None, + 0, + ), }; - let mut test = SystemParaToParaTest::new(test_args); + // Query initial balances let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; + let receiver_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location.into(), &receiver) + }); + // Set assertions and dispatchables test.set_assertion::(system_para_to_para_sender_assertions); - test.set_assertion::(para_receiver_assertions); + test.set_assertion::(system_para_to_para_receiver_assertions); test.set_dispatchable::(system_para_to_para_reserve_transfer_assets); test.assert(); - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - + // Calculate delivery fees let delivery_fees = AssetHubRococo::execute_with(|| { + let reanchored_assets = assets + .reanchored(&destination, &AssetHubRococoUniversalLocation::get()) + .unwrap(); xcm_helpers::transfer_assets_delivery_fees::< ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + + // Query final balances + let sender_balance_after = test.sender.balance; + let receiver_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location, &receiver) }); // Sender's balance is reduced assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); - // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; + // Receiver's assets is increased + assert!(receiver_assets_after > receiver_assets_before); + // Receiver's assets increased by `amount_to_send - delivery_fees - bought_execution`; // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but // should be non-zero - assert!(receiver_balance_after < receiver_balance_before + amount_to_send); + assert!(receiver_assets_after < receiver_assets_before + amount_to_send); } /// Reserve Transfers of native asset from Parachain to System Parachain should work #[test] fn reserve_transfer_native_asset_from_para_to_system_para() { - // Init values for Penpal Parachain + // Init values for Parachain let destination = PenpalA::sibling_location_of(AssetHubRococo::para_id()); - let beneficiary_id = AssetHubRococoReceiver::get(); + let sender = PenpalASender::get(); let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; - let assets = (Parent, amount_to_send).into(); + let assets: Assets = (Parent, amount_to_send).into(); + let system_para_native_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let asset_owner = PenpalAssetOwner::get(); + + // fund Parachain's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner), + system_para_native_asset_location, + sender.clone(), + amount_to_send, + ); + // Init values for System Parachain + let receiver = AssetHubRococoReceiver::get(); + let penpal_location_as_seen_by_ahr = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location_as_seen_by_ahr); + + // fund Parachain's SA on System Parachain with the native tokens held in reserve + AssetHubRococo::fund_accounts(vec![(sov_penpal_on_ahr.into(), amount_to_send * 2)]); + + // Init Test let test_args = TestContext { - sender: PenpalASender::get(), - receiver: AssetHubRococoReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), + sender: sender.clone(), + receiver: receiver.clone(), + args: TestArgs::new_para( + destination.clone(), + receiver.clone(), + amount_to_send, + assets.clone(), + None, + 0, + ), }; - let mut test = ParaToSystemParaTest::new(test_args); - let sender_balance_before = test.sender.balance; + // Query initial balances + let sender_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location, &sender) + }); let receiver_balance_before = test.receiver.balance; - let penpal_location_as_seen_by_ahr = AssetHubRococo::sibling_location_of(PenpalA::para_id()); - let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location_as_seen_by_ahr); - - // fund the Penpal's SA on AHR with the native tokens held in reserve - AssetHubRococo::fund_accounts(vec![(sov_penpal_on_ahr.into(), amount_to_send * 2)]); - + // Set assertions and dispatchables test.set_assertion::(para_to_system_para_sender_assertions); test.set_assertion::(para_to_system_para_receiver_assertions); test.set_dispatchable::(para_to_system_para_reserve_transfer_assets); test.assert(); - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - + // Calculate delivery fees let delivery_fees = PenpalA::execute_with(|| { + let reanchored_assets = + assets.reanchored(&destination, &PenpalUniversalLocation::get()).unwrap(); xcm_helpers::transfer_assets_delivery_fees::< ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); + // Query final balances + let sender_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location, &sender) + }); + let receiver_balance_after = test.receiver.balance; + // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); + assert_eq!(sender_assets_before - amount_to_send - delivery_fees, sender_assets_after); // Receiver's balance is increased assert!(receiver_balance_after > receiver_balance_before); // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; @@ -465,36 +814,27 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { assert!(receiver_balance_after < receiver_balance_before + amount_to_send); } +// ========================================================================= +// ======= Reserve Transfers - Non-system Asset - AssetHub<>Parachain ====== +// ========================================================================= /// Reserve Transfers of a local asset and native asset from System Parachain to Parachain should /// work #[test] fn reserve_transfer_assets_from_system_para_to_para() { - // Force create asset on AssetHubRococo and PenpalA from Relay Chain - AssetHubRococo::force_create_and_mint_asset( - ASSET_ID, - ASSET_MIN_BALANCE, - false, - AssetHubRococoSender::get(), - Some(Weight::from_parts(1_019_445_000, 200_000)), - ASSET_MIN_BALANCE * 1_000_000, - ); - PenpalA::force_create_and_mint_asset( - ASSET_ID, - ASSET_MIN_BALANCE, - false, - PenpalASender::get(), - None, - 0, - ); - // Init values for System Parachain let destination = AssetHubRococo::sibling_location_of(PenpalA::para_id()); - let beneficiary_id = PenpalAReceiver::get(); - let fee_amount_to_send = ASSET_HUB_ROCOCO_ED * 1000; - let asset_amount_to_send = ASSET_MIN_BALANCE * 1000; + let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(destination.clone()); + let sender = AssetHubRococoSender::get(); + let fee_amount_to_send = ASSET_HUB_ROCOCO_ED * 10000; + let asset_amount_to_send = PENPAL_ED * 10000; + let asset_owner = AssetHubRococoAssetOwner::get(); + let asset_owner_signer = ::RuntimeOrigin::signed(asset_owner.clone()); let assets: Assets = vec![ (Parent, fee_amount_to_send).into(), - ([PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())], asset_amount_to_send) + ( + [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(RESERVABLE_ASSET_ID.into())], + asset_amount_to_send, + ) .into(), ] .into(); @@ -503,49 +843,211 @@ fn reserve_transfer_assets_from_system_para_to_para() { .iter() .position(|r| r == &(Parent, fee_amount_to_send).into()) .unwrap() as u32; + AssetHubRococo::mint_asset( + asset_owner_signer, + RESERVABLE_ASSET_ID, + asset_owner, + asset_amount_to_send * 2, + ); + // Create SA-of-Penpal-on-AHR with ED. + AssetHubRococo::fund_accounts(vec![(sov_penpal_on_ahr.into(), ASSET_HUB_ROCOCO_ED)]); + + // Init values for Parachain + let receiver = PenpalAReceiver::get(); + let system_para_native_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let system_para_foreign_asset_location = + v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).expect("conversion works"); + + // Init Test let para_test_args = TestContext { - sender: AssetHubRococoSender::get(), - receiver: PenpalAReceiver::get(), + sender: sender.clone(), + receiver: receiver.clone(), args: TestArgs::new_para( destination, - beneficiary_id, + receiver.clone(), asset_amount_to_send, assets, None, fee_asset_index, ), }; - let mut test = SystemParaToParaTest::new(para_test_args); - // Create SA-of-Penpal-on-AHR with ED. - let penpal_location = AssetHubRococo::sibling_location_of(PenpalA::para_id()); - let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location); - AssetHubRococo::fund_accounts(vec![(sov_penpal_on_ahr.into(), ROCOCO_ED)]); - + // Query initial balances let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - let sender_assets_before = AssetHubRococo::execute_with(|| { type Assets = ::Assets; - >::balance(ASSET_ID, &AssetHubRococoSender::get()) + >::balance(RESERVABLE_ASSET_ID, &sender) }); - let receiver_assets_before = PenpalA::execute_with(|| { - type Assets = ::Assets; - >::balance(ASSET_ID, &PenpalAReceiver::get()) + let receiver_system_native_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location, &receiver) + }); + let receiver_foreign_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_foreign_asset_location, &receiver) }); + // Set assertions and dispatchables test.set_assertion::(system_para_to_para_assets_sender_assertions); test.set_assertion::(system_para_to_para_assets_receiver_assertions); test.set_dispatchable::(system_para_to_para_reserve_transfer_assets); test.assert(); + // Query final balances let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - + let sender_assets_after = AssetHubRococo::execute_with(|| { + type Assets = ::Assets; + >::balance(RESERVABLE_ASSET_ID, &sender) + }); + let receiver_system_native_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location, &receiver) + }); + let receiver_foreign_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_foreign_asset_location, &receiver) + }); // Sender's balance is reduced assert!(sender_balance_after < sender_balance_before); + // Receiver's foreign asset balance is increased + assert!(receiver_foreign_assets_after > receiver_foreign_assets_before); + // Receiver's system asset balance increased by `amount_to_send - delivery_fees - + // bought_execution`; `delivery_fees` might be paid from transfer or JIT, also + // `bought_execution` is unknown but should be non-zero + assert!( + receiver_system_native_assets_after < + receiver_system_native_assets_before + fee_amount_to_send + ); + + // Sender's asset balance is reduced by exact amount + assert_eq!(sender_assets_before - asset_amount_to_send, sender_assets_after); + // Receiver's foreign asset balance is increased by exact amount + assert_eq!( + receiver_foreign_assets_after, + receiver_foreign_assets_before + asset_amount_to_send + ); +} + +/// Reserve Transfers of a foreign asset and native asset from Parachain to System Para should +/// work +#[test] +fn reserve_transfer_assets_from_para_to_system_para() { + // Init values for Parachain + let destination = PenpalA::sibling_location_of(AssetHubRococo::para_id()); + let sender = PenpalASender::get(); + let fee_amount_to_send = ASSET_HUB_ROCOCO_ED * 10000; + let asset_amount_to_send = ASSET_HUB_ROCOCO_ED * 10000; + let penpal_asset_owner = PenpalAssetOwner::get(); + let penpal_asset_owner_signer = ::RuntimeOrigin::signed(penpal_asset_owner); + let asset_location_on_penpal = + v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).expect("conversion works"); + let asset_location_on_penpal_latest: Location = asset_location_on_penpal.try_into().unwrap(); + let system_asset_location_on_penpal = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let assets: Assets = vec![ + (Parent, fee_amount_to_send).into(), + (asset_location_on_penpal_latest, asset_amount_to_send).into(), + ] + .into(); + let fee_asset_index = assets + .inner() + .iter() + .position(|r| r == &(Parent, fee_amount_to_send).into()) + .unwrap() as u32; + // Fund Parachain's sender account with some foreign assets + PenpalA::mint_foreign_asset( + penpal_asset_owner_signer.clone(), + asset_location_on_penpal, + sender.clone(), + asset_amount_to_send * 2, + ); + // Fund Parachain's sender account with some system assets + PenpalA::mint_foreign_asset( + penpal_asset_owner_signer, + system_asset_location_on_penpal, + sender.clone(), + fee_amount_to_send * 2, + ); + + // Init values for System Parachain + let receiver = AssetHubRococoReceiver::get(); + let penpal_location_as_seen_by_ahr = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location_as_seen_by_ahr); + let system_para_native_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let system_para_foreign_asset_location = + v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).expect("conversion works"); + let ah_asset_owner = AssetHubRococoAssetOwner::get(); + let ah_asset_owner_signer = ::RuntimeOrigin::signed(ah_asset_owner); + + // Fund SA-of-Penpal-on-AHR to be able to pay for the fees. + AssetHubRococo::fund_accounts(vec![( + sov_penpal_on_ahr.clone().into(), + ASSET_HUB_ROCOCO_ED * 10000000, + )]); + // Fund SA-of-Penpal-on-AHR to be able to pay for the sent amount. + AssetHubRococo::mint_asset( + ah_asset_owner_signer, + RESERVABLE_ASSET_ID, + sov_penpal_on_ahr, + asset_amount_to_send * 2, + ); + + // Init Test + let para_test_args = TestContext { + sender: sender.clone(), + receiver: receiver.clone(), + args: TestArgs::new_para( + destination, + receiver.clone(), + asset_amount_to_send, + assets, + None, + fee_asset_index, + ), + }; + let mut test = ParaToSystemParaTest::new(para_test_args); + + // Query initial balances + let sender_system_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location, &sender) + }); + let sender_foreign_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_foreign_asset_location, &sender) + }); + let receiver_balance_before = test.receiver.balance; + let receiver_assets_before = AssetHubRococo::execute_with(|| { + type Assets = ::Assets; + >::balance(RESERVABLE_ASSET_ID, &receiver) + }); + + // Set assertions and dispatchables + test.set_assertion::(para_to_system_para_assets_sender_assertions); + test.set_assertion::(para_to_system_para_assets_receiver_assertions); + test.set_dispatchable::(para_to_system_para_reserve_transfer_assets); + test.assert(); + + // Query final balances + let sender_system_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location, &sender) + }); + let sender_foreign_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_foreign_asset_location, &sender) + }); + let receiver_balance_after = test.receiver.balance; + let receiver_assets_after = AssetHubRococo::execute_with(|| { + type Assets = ::Assets; + >::balance(RESERVABLE_ASSET_ID, &receiver) + }); + // Sender's system asset balance is reduced + assert!(sender_system_assets_after < sender_system_assets_before); // Receiver's balance is increased assert!(receiver_balance_after > receiver_balance_before); // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; @@ -553,65 +1055,88 @@ fn reserve_transfer_assets_from_system_para_to_para() { // should be non-zero assert!(receiver_balance_after < receiver_balance_before + fee_amount_to_send); - let sender_assets_after = AssetHubRococo::execute_with(|| { - type Assets = ::Assets; - >::balance(ASSET_ID, &AssetHubRococoSender::get()) - }); - let receiver_assets_after = PenpalA::execute_with(|| { - type Assets = ::Assets; - >::balance(ASSET_ID, &PenpalAReceiver::get()) - }); - - // Sender's balance is reduced by exact amount - assert_eq!(sender_assets_before - asset_amount_to_send, sender_assets_after); - // Receiver's balance is increased by exact amount + // Sender's asset balance is reduced by exact amount + assert_eq!(sender_foreign_assets_before - asset_amount_to_send, sender_foreign_assets_after); + // Receiver's foreign asset balance is increased by exact amount assert_eq!(receiver_assets_after, receiver_assets_before + asset_amount_to_send); } +// ========================================================================= +// ===== Reserve Transfers - Native Asset - Parachain<>Relay<>Parachain ==== +// ========================================================================= /// Reserve Transfers of native asset from Parachain to Parachain (through Relay reserve) should /// work #[test] -fn reserve_transfer_native_asset_from_para_to_para() { - // Init values for Penpal Parachain +fn reserve_transfer_native_asset_from_para_to_para_trough_relay() { + // Init values for Parachain Origin let destination = PenpalA::sibling_location_of(PenpalB::para_id()); - let beneficiary_id = PenpalBReceiver::get(); - let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 10000; + let sender = PenpalASender::get(); + let amount_to_send: Balance = ROCOCO_ED * 10000; + let asset_owner = PenpalAssetOwner::get(); let assets = (Parent, amount_to_send).into(); + let relay_native_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let sender_as_seen_by_relay = Rococo::child_location_of(PenpalA::para_id()); + let sov_of_sender_on_relay = Rococo::sovereign_account_id_of(sender_as_seen_by_relay); - let test_args = TestContext { - sender: PenpalASender::get(), - receiver: PenpalBReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; + // fund Parachain's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner), + relay_native_asset_location, + sender.clone(), + amount_to_send, + ); - let mut test = ParaToParaTest::new(test_args); + // fund the Parachain Origin's SA on Relay Chain with the native tokens held in reserve + Rococo::fund_accounts(vec![(sov_of_sender_on_relay.into(), amount_to_send * 2)]); - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; + // Init values for Parachain Desitnation + let receiver = PenpalBReceiver::get(); - let sender_as_seen_by_relay = Rococo::child_location_of(PenpalA::para_id()); - let sov_of_sender_on_relay = Rococo::sovereign_account_id_of(sender_as_seen_by_relay); + // Init Test + let test_args = TestContext { + sender: sender.clone(), + receiver: receiver.clone(), + args: TestArgs::new_para(destination, receiver.clone(), amount_to_send, assets, None, 0), + }; + let mut test = ParaToParaThroughRelayTest::new(test_args); - // fund the PenpalA's SA on Rococo with the native tokens held in reserve - Rococo::fund_accounts(vec![(sov_of_sender_on_relay.into(), amount_to_send * 2)]); + // Query initial balances + let sender_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location, &sender) + }); + let receiver_assets_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location, &receiver) + }); - test.set_assertion::(para_to_para_sender_assertions); + // Set assertions and dispatchables + test.set_assertion::(para_to_para_through_relay_sender_assertions); test.set_assertion::(para_to_para_relay_hop_assertions); - test.set_assertion::(para_to_para_receiver_assertions); - test.set_dispatchable::(para_to_para_limited_reserve_transfer_assets); + test.set_assertion::(para_to_para_through_relay_receiver_assertions); + test.set_dispatchable::(para_to_para_through_relay_limited_reserve_transfer_assets); test.assert(); - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - + // Calculate delivery fees let delivery_fees = PenpalA::execute_with(|| { xcm_helpers::transfer_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); + // Query final balances + let sender_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location, &sender) + }); + let receiver_assets_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location, &receiver) + }); + // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); + assert_eq!(sender_assets_before - amount_to_send - delivery_fees, sender_assets_after); // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); + assert!(receiver_assets_after > receiver_assets_before); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs index 3c9e76a34e3..364fbd0d439 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; +use crate::imports::*; /// Relay Chain should be able to execute `Transact` instructions in System Parachain /// when `OriginKind::Superuser`. @@ -28,8 +28,95 @@ fn send_transact_as_superuser_from_relay_to_system_para_works() { ) } -/// Parachain should be able to send XCM paying its fee with sufficient asset -/// in the System Parachain +/// We tests two things here: +/// - Parachain should be able to send XCM paying its fee with system asset in the System Parachain +/// - Parachain should be able to create a new Foreign Asset in the System Parachain +#[test] +fn send_xcm_from_para_to_system_para_paying_fee_with_system_assets_works() { + let para_sovereign_account = AssetHubRococo::sovereign_account_id_of( + AssetHubRococo::sibling_location_of(PenpalA::para_id()), + ); + let asset_location_on_penpal = v3::Location::new( + 0, + [ + v3::Junction::PalletInstance(ASSETS_PALLET_ID), + v3::Junction::GeneralIndex(ASSET_ID.into()), + ], + ); + let foreign_asset_at_asset_hub = + v3::Location::new(1, [v3::Junction::Parachain(PenpalA::para_id().into())]) + .appended_with(asset_location_on_penpal) + .unwrap(); + + // Encoded `create_asset` call to be executed in AssetHub + let call = AssetHubRococo::create_foreign_asset_call( + foreign_asset_at_asset_hub, + ASSET_MIN_BALANCE, + para_sovereign_account.clone(), + ); + + let origin_kind = OriginKind::Xcm; + let fee_amount = ASSET_HUB_ROCOCO_ED * 1000000; + let system_asset = (Parent, fee_amount).into(); + + let root_origin = ::RuntimeOrigin::root(); + let system_para_destination = PenpalA::sibling_location_of(AssetHubRococo::para_id()).into(); + let xcm = xcm_transact_paid_execution( + call, + origin_kind, + system_asset, + para_sovereign_account.clone(), + ); + + // SA-of-Penpal-on-AHR needs to have balance to pay for fees and asset creation deposit + AssetHubRococo::fund_accounts(vec![( + para_sovereign_account.clone().into(), + ASSET_HUB_ROCOCO_ED * 10000000000, + )]); + + PenpalA::execute_with(|| { + assert_ok!(::PolkadotXcm::send( + root_origin, + bx!(system_para_destination), + bx!(xcm), + )); + + PenpalA::assert_xcm_pallet_sent(); + }); + + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + AssetHubRococo::assert_xcmp_queue_success(Some(Weight::from_parts( + 15_594_564_000, + 562_893, + ))); + + assert_expected_events!( + AssetHubRococo, + vec![ + // Burned the fee + RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { + who: *who == para_sovereign_account, + amount: *amount == fee_amount, + }, + // Foreign Asset created + RuntimeEvent::ForeignAssets(pallet_assets::Event::Created { asset_id, creator, owner }) => { + asset_id: *asset_id == foreign_asset_at_asset_hub, + creator: *creator == para_sovereign_account.clone(), + owner: *owner == para_sovereign_account, + }, + ] + ); + + type ForeignAssets = ::ForeignAssets; + assert!(ForeignAssets::asset_exists(foreign_asset_at_asset_hub)); + }); +} + +/// We tests two things here: +/// - Parachain should be able to send XCM paying its fee with system assets in the System Parachain +/// - Parachain should be able to create a new Asset in the System Parachain #[test] fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { let para_sovereign_account = AssetHubRococo::sovereign_account_id_of( @@ -46,28 +133,30 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { ASSET_MIN_BALANCE * 1000000000, ); - // We just need a call that can pass the `SafeCallFilter` - // Call values are not relevant - let call = AssetHubRococo::force_create_asset_call( - ASSET_ID, - para_sovereign_account.clone(), - true, + // Just a different `asset_id`` that does not exist yet + let new_asset_id = ASSET_ID + 1; + + // Encoded `create_asset` call to be executed in AssetHub + let call = AssetHubRococo::create_asset_call( + new_asset_id, ASSET_MIN_BALANCE, + para_sovereign_account.clone(), ); let origin_kind = OriginKind::SovereignAccount; let fee_amount = ASSET_MIN_BALANCE * 1000000; - let native_asset = + let asset = ([PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())], fee_amount).into(); let root_origin = ::RuntimeOrigin::root(); let system_para_destination = PenpalA::sibling_location_of(AssetHubRococo::para_id()).into(); - let xcm = xcm_transact_paid_execution( - call, - origin_kind, - native_asset, - para_sovereign_account.clone(), - ); + let xcm = xcm_transact_paid_execution(call, origin_kind, asset, para_sovereign_account.clone()); + + // SA-of-Penpal-on-AHR needs to have balance to pay for asset creation deposit + AssetHubRococo::fund_accounts(vec![( + para_sovereign_account.clone().into(), + ASSET_HUB_ROCOCO_ED * 10000000000, + )]); PenpalA::execute_with(|| { assert_ok!(::PolkadotXcm::send( @@ -90,13 +179,17 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { assert_expected_events!( AssetHubRococo, vec![ + // Burned the fee RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { asset_id: *asset_id == ASSET_ID, owner: *owner == para_sovereign_account, balance: *balance == fee_amount, }, - RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, .. }) => { - asset_id: *asset_id == ASSET_ID, + // Asset created + RuntimeEvent::Assets(pallet_assets::Event::Created { asset_id, creator, owner }) => { + asset_id: *asset_id == new_asset_id, + creator: *creator == para_sovereign_account.clone(), + owner: *owner == para_sovereign_account, }, ] ); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs index 7d630d36805..5662a78ab67 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/set_xcm_versions.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; +use crate::imports::*; #[test] fn relay_sets_system_para_xcm_supported_version() { diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs index c6a10b25290..87f0b3d9f90 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs @@ -13,9 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; -use rococo_system_emulated_network::penpal_emulated_chain::LocalTeleportableToAssetHubV3 as PenpalLocalTeleportableToAssetHubV3; -use sp_runtime::ModuleError; +use crate::imports::*; #[test] fn swap_locally_on_chain_using_local_assets() { @@ -114,49 +112,39 @@ fn swap_locally_on_chain_using_local_assets() { #[test] fn swap_locally_on_chain_using_foreign_assets() { - let asset_native = Box::new(asset_hub_rococo_runtime::xcm_config::TokenLocationV3::get()); - let ah_as_seen_by_penpal = PenpalA::sibling_location_of(AssetHubRococo::para_id()); - let asset_location_on_penpal = PenpalLocalTeleportableToAssetHubV3::get(); - let asset_id_on_penpal = match asset_location_on_penpal.last() { - Some(v3::Junction::GeneralIndex(id)) => *id as u32, - _ => unreachable!(), - }; - let asset_owner_on_penpal = PenpalASender::get(); + let asset_native = + Box::new(v3::Location::try_from(RelayLocation::get()).expect("conversion works")); + let asset_location_on_penpal = + v3::Location::try_from(PenpalLocalTeleportableToAssetHub::get()).expect("conversion works"); let foreign_asset_at_asset_hub_rococo = v3::Location::new(1, [v3::Junction::Parachain(PenpalA::para_id().into())]) .appended_with(asset_location_on_penpal) .unwrap(); - // 1. Create asset on penpal and, 2. Create foreign asset on asset_hub_rococo - super::penpal_create_foreign_asset_on_asset_hub( - asset_id_on_penpal, - foreign_asset_at_asset_hub_rococo, - ah_as_seen_by_penpal, - true, - asset_owner_on_penpal, - ASSET_MIN_BALANCE * 1_000_000, - ); - let penpal_as_seen_by_ah = AssetHubRococo::sibling_location_of(PenpalA::para_id()); let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_as_seen_by_ah); AssetHubRococo::fund_accounts(vec![ - (AssetHubRococoSender::get().into(), 5_000_000 * ROCOCO_ED), /* An account to swap dot - * for something else. */ + // An account to swap dot for something else. + (AssetHubRococoSender::get().into(), 5_000_000 * ASSET_HUB_ROCOCO_ED), + // Penpal's sovereign account in AH should have some balance + (sov_penpal_on_ahr.clone().into(), 100_000_000 * ASSET_HUB_ROCOCO_ED), ]); AssetHubRococo::execute_with(|| { - // 3: Mint foreign asset on asset_hub_rococo: + // 0: No need to create foreign asset as it exists in genesis. + // + // 1: Mint foreign asset on asset_hub_rococo: // // (While it might be nice to use batch, // currently that's disabled due to safe call filters.) type RuntimeEvent = ::RuntimeEvent; - // 3. Mint foreign asset (in reality this should be a teleport or some such) + // 1. Mint foreign asset (in reality this should be a teleport or some such) assert_ok!(::ForeignAssets::mint( ::RuntimeOrigin::signed(sov_penpal_on_ahr.clone().into()), foreign_asset_at_asset_hub_rococo, sov_penpal_on_ahr.clone().into(), - 3_000_000_000_000, + ASSET_HUB_ROCOCO_ED * 3_000_000_000_000, )); assert_expected_events!( @@ -166,7 +154,7 @@ fn swap_locally_on_chain_using_foreign_assets() { ] ); - // 4. Create pool: + // 2. Create pool: assert_ok!(::AssetConversion::create_pool( ::RuntimeOrigin::signed(AssetHubRococoSender::get()), asset_native.clone(), @@ -180,7 +168,7 @@ fn swap_locally_on_chain_using_foreign_assets() { ] ); - // 5. Add liquidity: + // 3. Add liquidity: assert_ok!(::AssetConversion::add_liquidity( ::RuntimeOrigin::signed(sov_penpal_on_ahr.clone()), asset_native.clone(), @@ -201,15 +189,15 @@ fn swap_locally_on_chain_using_foreign_assets() { ] ); - // 6. Swap! + // 4. Swap! let path = vec![asset_native.clone(), Box::new(foreign_asset_at_asset_hub_rococo)]; assert_ok!( ::AssetConversion::swap_exact_tokens_for_tokens( ::RuntimeOrigin::signed(AssetHubRococoSender::get()), path, - 100000, - 1000, + 100000 * ASSET_HUB_ROCOCO_ED, + 1000 * ASSET_HUB_ROCOCO_ED, AssetHubRococoSender::get().into(), true ) @@ -219,18 +207,18 @@ fn swap_locally_on_chain_using_foreign_assets() { AssetHubRococo, vec![ RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::SwapExecuted { amount_in, amount_out, .. },) => { - amount_in: *amount_in == 100000, - amount_out: *amount_out == 199399, + amount_in: *amount_in == 333333300000, + amount_out: *amount_out == 498874118173, }, ] ); - // 7. Remove liquidity + // 5. Remove liquidity assert_ok!(::AssetConversion::remove_liquidity( ::RuntimeOrigin::signed(sov_penpal_on_ahr.clone()), asset_native.clone(), Box::new(foreign_asset_at_asset_hub_rococo), - 1414213562273 - 2_000_000_000, // all but the 2 EDs can't be retrieved. + 1414213562273 - ASSET_HUB_ROCOCO_ED * 2, // all but the 2 EDs can't be retrieved. 0, 0, sov_penpal_on_ahr.clone().into(), diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs index dfb5061b55f..0cc5ddb9f64 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs @@ -13,11 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; -use asset_hub_rococo_runtime::xcm_config::XcmConfig as AssetHubRococoXcmConfig; -use emulated_integration_tests_common::xcm_helpers::non_fee_asset; -use rococo_runtime::xcm_config::XcmConfig as RococoXcmConfig; -use rococo_system_emulated_network::penpal_emulated_chain::LocalTeleportableToAssetHubV3 as PenpalLocalTeleportableToAssetHubV3; +use crate::imports::*; fn relay_origin_assertions(t: RelayToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -114,18 +110,21 @@ fn para_dest_assertions(t: RelayToSystemParaTest) { fn penpal_to_ah_foreign_assets_sender_assertions(t: ParaToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; - PenpalA::assert_xcm_pallet_attempted_complete(None); + let system_para_native_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); let expected_asset_id = t.args.asset_id.unwrap(); let (_, expected_asset_amount) = non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); + + PenpalA::assert_xcm_pallet_attempted_complete(None); assert_expected_events!( PenpalA, vec![ - RuntimeEvent::Balances( - pallet_balances::Event::Burned { who, amount } + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Burned { asset_id, owner, .. } ) => { - who: *who == t.sender.account_id, - amount: *amount == t.args.amount, + asset_id: *asset_id == system_para_native_asset_location, + owner: *owner == t.sender.account_id, }, RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { asset_id: *asset_id == expected_asset_id, @@ -144,6 +143,9 @@ fn penpal_to_ah_foreign_assets_receiver_assertions(t: ParaToSystemParaTest) { let (expected_foreign_asset_id, expected_foreign_asset_amount) = non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); let expected_foreign_asset_id_v3: v3::Location = expected_foreign_asset_id.try_into().unwrap(); + + AssetHubRococo::assert_xcmp_queue_success(None); + assert_expected_events!( AssetHubRococo, vec![ @@ -163,9 +165,6 @@ fn penpal_to_ah_foreign_assets_receiver_assertions(t: ParaToSystemParaTest) { amount: *amount == expected_foreign_asset_amount, }, RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, ] ); } @@ -205,6 +204,11 @@ fn ah_to_penpal_foreign_assets_receiver_assertions(t: SystemParaToParaTest) { let (_, expected_asset_amount) = non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); let checking_account = ::PolkadotXcm::check_account(); + let system_para_native_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + + PenpalA::assert_xcmp_queue_success(None); + assert_expected_events!( PenpalA, vec![ @@ -221,12 +225,11 @@ fn ah_to_penpal_foreign_assets_receiver_assertions(t: SystemParaToParaTest) { amount: *amount == expected_asset_amount, }, // native asset for fee is deposited to receiver - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == t.receiver.account_id, + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { + asset_id: *asset_id == system_para_native_asset_location, + owner: *owner == t.receiver.account_id, + amount: *amount == expected_asset_amount, }, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, ] ); } @@ -558,30 +561,21 @@ fn teleport_to_other_system_parachains_works() { /// (using native reserve-based transfer for fees) #[test] fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { - let ah_as_seen_by_penpal = PenpalA::sibling_location_of(AssetHubRococo::para_id()); - let asset_location_on_penpal = PenpalLocalTeleportableToAssetHubV3::get(); + // Init values for Parachain + let fee_amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 10000; + let asset_location_on_penpal = + v3::Location::try_from(PenpalLocalTeleportableToAssetHub::get()).expect("conversion works"); let asset_id_on_penpal = match asset_location_on_penpal.last() { Some(v3::Junction::GeneralIndex(id)) => *id as u32, _ => unreachable!(), }; - let asset_owner_on_penpal = PenpalASender::get(); - let foreign_asset_at_asset_hub_rococo = - v3::Location::new(1, [v3::Junction::Parachain(PenpalA::para_id().into())]) - .appended_with(asset_location_on_penpal) - .unwrap(); - super::penpal_create_foreign_asset_on_asset_hub( - asset_id_on_penpal, - foreign_asset_at_asset_hub_rococo, - ah_as_seen_by_penpal.clone(), - false, - asset_owner_on_penpal, - ASSET_MIN_BALANCE * 1_000_000, - ); - let penpal_to_ah_beneficiary_id = AssetHubRococoReceiver::get(); - - let fee_amount_to_send = ASSET_HUB_ROCOCO_ED * 10_000; - let asset_amount_to_send = ASSET_MIN_BALANCE * 1000; - + let asset_amount_to_send = ASSET_HUB_ROCOCO_ED * 1000; + let asset_owner = PenpalAssetOwner::get(); + let system_para_native_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let sender = PenpalASender::get(); + let penpal_check_account = ::PolkadotXcm::check_account(); + let ah_as_seen_by_penpal = PenpalA::sibling_location_of(AssetHubRococo::para_id()); let asset_location_on_penpal_latest: Location = asset_location_on_penpal.try_into().unwrap(); let penpal_assets: Assets = vec![ (Parent, fee_amount_to_send).into(), @@ -594,6 +588,38 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { .position(|r| r == &(Parent, fee_amount_to_send).into()) .unwrap() as u32; + // fund Parachain's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner.clone()), + system_para_native_asset_location, + sender.clone(), + fee_amount_to_send, + ); + // No need to create the asset (only mint) as it exists in genesis. + PenpalA::mint_asset( + ::RuntimeOrigin::signed(asset_owner.clone()), + asset_id_on_penpal, + sender.clone(), + asset_amount_to_send, + ); + // fund Parachain's check account to be able to teleport + PenpalA::fund_accounts(vec![(penpal_check_account.clone().into(), ASSET_HUB_ROCOCO_ED * 1000)]); + + // prefund SA of Penpal on AssetHub with enough native tokens to pay for fees + let penpal_as_seen_by_ah = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let sov_penpal_on_ah = AssetHubRococo::sovereign_account_id_of(penpal_as_seen_by_ah); + AssetHubRococo::fund_accounts(vec![( + sov_penpal_on_ah.clone().into(), + ASSET_HUB_ROCOCO_ED * 100_000_000_000, + )]); + + // Init values for System Parachain + let foreign_asset_at_asset_hub_rococo = + v3::Location::new(1, [v3::Junction::Parachain(PenpalA::para_id().into())]) + .appended_with(asset_location_on_penpal) + .unwrap(); + let penpal_to_ah_beneficiary_id = AssetHubRococoReceiver::get(); + // Penpal to AH test args let penpal_to_ah_test_args = TestContext { sender: PenpalASender::get(), @@ -608,8 +634,14 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { ), }; let mut penpal_to_ah = ParaToSystemParaTest::new(penpal_to_ah_test_args); + let penpal_sender_balance_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + system_para_native_asset_location, + &PenpalASender::get(), + ) + }); - let penpal_sender_balance_before = penpal_to_ah.sender.balance; let ah_receiver_balance_before = penpal_to_ah.receiver.balance; let penpal_sender_assets_before = PenpalA::execute_with(|| { @@ -629,7 +661,14 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { penpal_to_ah.set_dispatchable::(para_to_system_para_transfer_assets); penpal_to_ah.assert(); - let penpal_sender_balance_after = penpal_to_ah.sender.balance; + let penpal_sender_balance_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + system_para_native_asset_location, + &PenpalASender::get(), + ) + }); + let ah_receiver_balance_after = penpal_to_ah.receiver.balance; let penpal_sender_assets_after = PenpalA::execute_with(|| { @@ -704,7 +743,13 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { let mut ah_to_penpal = SystemParaToParaTest::new(ah_to_penpal_test_args); let ah_sender_balance_before = ah_to_penpal.sender.balance; - let penpal_receiver_balance_before = ah_to_penpal.receiver.balance; + let penpal_receiver_balance_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + system_para_native_asset_location, + &PenpalAReceiver::get(), + ) + }); let ah_sender_assets_before = AssetHubRococo::execute_with(|| { type ForeignAssets = ::ForeignAssets; @@ -724,7 +769,13 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { ah_to_penpal.assert(); let ah_sender_balance_after = ah_to_penpal.sender.balance; - let penpal_receiver_balance_after = ah_to_penpal.receiver.balance; + let penpal_receiver_balance_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + system_para_native_asset_location, + &PenpalAReceiver::get(), + ) + }); let ah_sender_assets_after = AssetHubRococo::execute_with(|| { type ForeignAssets = ::ForeignAssets; diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml index 0c920730d0f..8ac8efb5218 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml @@ -33,6 +33,7 @@ westend-runtime = { path = "../../../../../../../polkadot/runtime/westend" } # Cumulus parachains-common = { path = "../../../../../../parachains/common" } testnet-parachains-constants = { path = "../../../../../runtimes/constants", features = ["westend"] } +penpal-runtime = { path = "../../../../../runtimes/testing/penpal" } asset-hub-westend-runtime = { path = "../../../../../runtimes/assets/asset-hub-westend" } asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" } cumulus-pallet-xcmp-queue = { default-features = false, path = "../../../../../../pallets/xcmp-queue" } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs index 409369df7bb..3f899d1dbdb 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs @@ -13,67 +13,83 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub use codec::Encode; +#[cfg(test)] +mod imports { + pub use codec::Encode; + + // Substrate + pub use frame_support::{ + assert_err, assert_ok, + pallet_prelude::Weight, + sp_runtime::{DispatchError, DispatchResult, ModuleError}, + traits::fungibles::Inspect, + }; -// Substrate -pub use frame_support::{ - assert_err, assert_ok, - instances::Instance2, - pallet_prelude::Weight, - sp_runtime::{AccountId32, DispatchError, DispatchResult, ModuleError}, - traits::fungibles::Inspect, - BoundedVec, -}; + // Polkadot + pub use xcm::{ + prelude::{AccountId32 as AccountId32Junction, *}, + v3, + }; -// Polkadot -pub use xcm::{ - prelude::{AccountId32 as AccountId32Junction, *}, - v3::{self, Error, NetworkId::Westend as WestendId}, -}; + // Cumulus + pub use asset_test_utils::xcm_helpers; + pub use emulated_integration_tests_common::{ + test_parachain_is_trusted_teleporter, + xcm_emulator::{ + assert_expected_events, bx, Chain, Parachain as Para, RelayChain as Relay, Test, + TestArgs, TestContext, TestExt, + }, + xcm_helpers::{non_fee_asset, xcm_transact_paid_execution}, + ASSETS_PALLET_ID, RESERVABLE_ASSET_ID, XCM_V3, + }; + pub use parachains_common::{AccountId, Balance}; + pub use westend_system_emulated_network::{ + asset_hub_westend_emulated_chain::{ + genesis::{AssetHubWestendAssetOwner, ED as ASSET_HUB_WESTEND_ED}, + AssetHubWestendParaPallet as AssetHubWestendPallet, + }, + collectives_westend_emulated_chain::CollectivesWestendParaPallet as CollectivesWestendPallet, + penpal_emulated_chain::{ + PenpalAParaPallet as PenpalAPallet, PenpalAssetOwner, + PenpalBParaPallet as PenpalBPallet, + }, + westend_emulated_chain::{genesis::ED as WESTEND_ED, WestendRelayPallet as WestendPallet}, + AssetHubWestendPara as AssetHubWestend, + AssetHubWestendParaReceiver as AssetHubWestendReceiver, + AssetHubWestendParaSender as AssetHubWestendSender, + BridgeHubWestendPara as BridgeHubWestend, + BridgeHubWestendParaReceiver as BridgeHubWestendReceiver, + CollectivesWestendPara as CollectivesWestend, PenpalAPara as PenpalA, + PenpalAParaReceiver as PenpalAReceiver, PenpalAParaSender as PenpalASender, + PenpalBPara as PenpalB, PenpalBParaReceiver as PenpalBReceiver, WestendRelay as Westend, + WestendRelayReceiver as WestendReceiver, WestendRelaySender as WestendSender, + }; -// Cumulus -pub use asset_test_utils::xcm_helpers; -pub use emulated_integration_tests_common::{ - test_parachain_is_trusted_teleporter, - xcm_emulator::{ - assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, - RelayChain as Relay, Test, TestArgs, TestContext, TestExt, - }, - xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, - PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, -}; -pub use parachains_common::{AccountId, Balance}; -pub use westend_system_emulated_network::{ - asset_hub_westend_emulated_chain::{ - genesis::ED as ASSET_HUB_WESTEND_ED, AssetHubWestendParaPallet as AssetHubWestendPallet, - }, - collectives_westend_emulated_chain::{ - genesis::ED as COLLECTIVES_WESTEND_ED, - CollectivesWestendParaPallet as CollectivesWestendPallet, - }, - penpal_emulated_chain::PenpalBParaPallet as PenpalBPallet, - westend_emulated_chain::{genesis::ED as WESTEND_ED, WestendRelayPallet as WestendPallet}, - AssetHubWestendPara as AssetHubWestend, AssetHubWestendParaReceiver as AssetHubWestendReceiver, - AssetHubWestendParaSender as AssetHubWestendSender, BridgeHubWestendPara as BridgeHubWestend, - BridgeHubWestendParaReceiver as BridgeHubWestendReceiver, - CollectivesWestendPara as CollectivesWestend, PenpalAPara as PenpalA, - PenpalAParaReceiver as PenpalAReceiver, PenpalBPara as PenpalB, - PenpalBParaReceiver as PenpalBReceiver, PenpalBParaSender as PenpalBSender, - WestendRelay as Westend, WestendRelayReceiver as WestendReceiver, - WestendRelaySender as WestendSender, -}; + // Runtimes + pub use asset_hub_westend_runtime::xcm_config::{ + UniversalLocation as AssetHubWestendUniversalLocation, WestendLocation as RelayLocation, + XcmConfig as AssetHubWestendXcmConfig, + }; + pub use penpal_runtime::xcm_config::{ + LocalReservableFromAssetHub as PenpalLocalReservableFromAssetHub, + LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub, + UniversalLocation as PenpalUniversalLocation, XcmConfig as PenpalWestendXcmConfig, + }; + pub use westend_runtime::xcm_config::{ + UniversalLocation as WestendUniversalLocation, XcmConfig as WestendXcmConfig, + }; -pub const ASSET_ID: u32 = 1; -pub const ASSET_MIN_BALANCE: u128 = 1000; -// `Assets` pallet index -pub const ASSETS_PALLET_ID: u8 = 50; + pub const ASSET_ID: u32 = 3; + pub const ASSET_MIN_BALANCE: u128 = 1000; -pub type RelayToSystemParaTest = Test; -pub type RelayToParaTest = Test; -pub type SystemParaToRelayTest = Test; -pub type SystemParaToParaTest = Test; -pub type ParaToSystemParaTest = Test; -pub type ParaToParaTest = Test; + pub type RelayToSystemParaTest = Test; + pub type RelayToParaTest = Test; + pub type ParaToRelayTest = Test; + pub type SystemParaToRelayTest = Test; + pub type SystemParaToParaTest = Test; + pub type ParaToSystemParaTest = Test; + pub type ParaToParaThroughRelayTest = Test; +} #[cfg(test)] mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/fellowship_treasury.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/fellowship_treasury.rs index 11e1e1762db..2d02e90f47f 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/fellowship_treasury.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/fellowship_treasury.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; +use crate::imports::*; use emulated_integration_tests_common::accounts::{ALICE, BOB}; use frame_support::traits::fungibles::{Create, Inspect, Mutate}; use polkadot_runtime_common::impls::VersionedLocatableAsset; diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs index a56cde8f2a2..3cd7c9c46d6 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs @@ -20,11 +20,3 @@ mod set_xcm_versions; mod swap; mod teleport; mod treasury; - -use crate::*; -emulated_integration_tests_common::include_penpal_create_foreign_asset_on_asset_hub!( - PenpalB, - AssetHubWestend, - WESTEND_ED, - testnet_parachains_constants::westend::fee::WeightToFee -); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs index a29cd10ba83..8c836132b54 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs @@ -13,10 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; -use asset_hub_westend_runtime::xcm_config::XcmConfig as AssetHubWestendXcmConfig; -use westend_runtime::xcm_config::XcmConfig as WestendXcmConfig; -use westend_system_emulated_network::penpal_emulated_chain::XcmConfig as PenpalWestendXcmConfig; +use crate::imports::*; fn relay_to_para_sender_assertions(t: RelayToParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -40,12 +37,30 @@ fn relay_to_para_sender_assertions(t: RelayToParaTest) { ); } +fn para_to_relay_sender_assertions(t: ParaToRelayTest) { + type RuntimeEvent = ::RuntimeEvent; + PenpalA::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8_799))); + assert_expected_events!( + PenpalA, + vec![ + // Amount to reserve transfer is transferred to Parachain's Sovereign account + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Burned { asset_id, owner, balance, .. } + ) => { + asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).expect("conversion works"), + owner: *owner == t.sender.account_id, + balance: *balance == t.args.amount, + }, + ] + ); +} + fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; AssetHubWestend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( - 676_119_000, - 6196, + 864_610_000, + 8_799, ))); assert_expected_events!( @@ -61,57 +76,96 @@ fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { ), amount: *amount == t.args.amount, }, + // Transport fees are paid + RuntimeEvent::PolkadotXcm( + pallet_xcm::Event::FeesPaid { .. } + ) => {}, ] ); + AssetHubWestend::assert_xcm_pallet_sent(); } -fn para_receiver_assertions(_: Test) { - type RuntimeEvent = ::RuntimeEvent; +fn system_para_to_para_receiver_assertions(t: SystemParaToParaTest) { + type RuntimeEvent = ::RuntimeEvent; + let system_para_native_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + + PenpalA::assert_xcmp_queue_success(None); + assert_expected_events!( - PenpalB, + PenpalA, vec![ - RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == system_para_native_asset_location, + owner: *owner == t.receiver.account_id, + }, ] ); } fn para_to_system_para_sender_assertions(t: ParaToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; + type RuntimeEvent = ::RuntimeEvent; + PenpalA::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8_799))); + assert_expected_events!( + PenpalA, + vec![ + // Amount to reserve transfer is transferred to Parachain's Sovereign account + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Burned { asset_id, owner, balance, .. } + ) => { + asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).expect("conversion works"), + owner: *owner == t.sender.account_id, + balance: *balance == t.args.amount, + }, + ] + ); +} + +fn para_to_relay_receiver_assertions(t: ParaToRelayTest) { + type RuntimeEvent = ::RuntimeEvent; + let sov_penpal_on_relay = + Westend::sovereign_account_id_of(Westend::child_location_of(PenpalA::para_id())); - PenpalB::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8_799))); + Westend::assert_ump_queue_processed( + true, + Some(PenpalA::para_id()), + Some(Weight::from_parts(306305000, 7_186)), + ); assert_expected_events!( - PenpalB, + Westend, vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereign account + // Amount to reserve transfer is withdrawn from Parachain's Sovereign account RuntimeEvent::Balances( pallet_balances::Event::Burned { who, amount } ) => { - who: *who == t.sender.account_id, + who: *who == sov_penpal_on_relay.clone().into(), amount: *amount == t.args.amount, }, + RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, ] ); } fn para_to_system_para_receiver_assertions(t: ParaToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; - - let sov_penpal_on_ahw = AssetHubWestend::sovereign_account_id_of( - AssetHubWestend::sibling_location_of(PenpalB::para_id()), + let sov_penpal_on_ahr = AssetHubWestend::sovereign_account_id_of( + AssetHubWestend::sibling_location_of(PenpalA::para_id()), ); + AssetHubWestend::assert_xcmp_queue_success(None); + assert_expected_events!( AssetHubWestend, vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereign account + // Amount to reserve transfer is withdrawn from Parachain's Sovereign account RuntimeEvent::Balances( pallet_balances::Event::Burned { who, amount } ) => { - who: *who == sov_penpal_on_ahw.clone().into(), + who: *who == sov_penpal_on_ahr.clone().into(), amount: *amount == t.args.amount, }, RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, @@ -124,12 +178,10 @@ fn para_to_system_para_receiver_assertions(t: ParaToSystemParaTest) { fn system_para_to_para_assets_sender_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; - AssetHubWestend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( - 676_119_000, - 6196, + 864_610_000, + 8799, ))); - assert_expected_events!( AssetHubWestend, vec![ @@ -137,24 +189,124 @@ fn system_para_to_para_assets_sender_assertions(t: SystemParaToParaTest) { RuntimeEvent::Assets( pallet_assets::Event::Transferred { asset_id, from, to, amount } ) => { - asset_id: *asset_id == ASSET_ID, + asset_id: *asset_id == RESERVABLE_ASSET_ID, from: *from == t.sender.account_id, to: *to == AssetHubWestend::sovereign_account_id_of( t.args.dest.clone() ), amount: *amount == t.args.amount, }, + // Native asset to pay for fees is transferred to Parachain's Sovereign account + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { + who: *who == AssetHubWestend::sovereign_account_id_of( + t.args.dest.clone() + ), + }, + // Transport fees are paid + RuntimeEvent::PolkadotXcm( + pallet_xcm::Event::FeesPaid { .. } + ) => {}, ] ); } -fn system_para_to_para_assets_receiver_assertions(_: Test) { - type RuntimeEvent = ::RuntimeEvent; +fn para_to_system_para_assets_sender_assertions(t: ParaToSystemParaTest) { + type RuntimeEvent = ::RuntimeEvent; + let system_para_native_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let reservable_asset_location = + v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).expect("coversion works"); + PenpalA::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8799))); assert_expected_events!( - PenpalB, + PenpalA, vec![ - RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, - RuntimeEvent::Assets(pallet_assets::Event::Issued { .. }) => {}, + // Fees amount to reserve transfer is burned from Parachains's sender account + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Burned { asset_id, owner, .. } + ) => { + asset_id: *asset_id == system_para_native_asset_location, + owner: *owner == t.sender.account_id, + }, + // Amount to reserve transfer is burned from Parachains's sender account + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Burned { asset_id, owner, balance } + ) => { + asset_id: *asset_id == reservable_asset_location, + owner: *owner == t.sender.account_id, + balance: *balance == t.args.amount, + }, + // Transport fees are paid + RuntimeEvent::PolkadotXcm( + pallet_xcm::Event::FeesPaid { .. } + ) => {}, + ] + ); +} + +fn system_para_to_para_assets_receiver_assertions(t: SystemParaToParaTest) { + type RuntimeEvent = ::RuntimeEvent; + let system_para_asset_location = + v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).expect("coversion works"); + PenpalA::assert_xcmp_queue_success(None); + assert_expected_events!( + PenpalA, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).expect("conversion works"), + owner: *owner == t.receiver.account_id, + }, + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { + asset_id: *asset_id == system_para_asset_location, + owner: *owner == t.receiver.account_id, + amount: *amount == t.args.amount, + }, + ] + ); +} + +fn para_to_system_para_assets_receiver_assertions(t: ParaToSystemParaTest) { + type RuntimeEvent = ::RuntimeEvent; + let sov_penpal_on_ahr = AssetHubWestend::sovereign_account_id_of( + AssetHubWestend::sibling_location_of(PenpalA::para_id()), + ); + AssetHubWestend::assert_xcmp_queue_success(None); + assert_expected_events!( + AssetHubWestend, + vec![ + // Amount to reserve transfer is burned from Parachain's Sovereign account + RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { + asset_id: *asset_id == RESERVABLE_ASSET_ID, + owner: *owner == sov_penpal_on_ahr, + balance: *balance == t.args.amount, + }, + // Fee amount is burned from Parachain's Sovereign account + RuntimeEvent::Balances(pallet_balances::Event::Burned { who, .. }) => { + who: *who == sov_penpal_on_ahr, + }, + // Amount to reserve transfer is issued for beneficiary + RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { + asset_id: *asset_id == RESERVABLE_ASSET_ID, + owner: *owner == t.receiver.account_id, + amount: *amount == t.args.amount, + }, + // Remaining fee amount is minted for for beneficiary + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { + who: *who == t.receiver.account_id, + }, + ] + ); +} + +fn relay_to_para_assets_receiver_assertions(t: RelayToParaTest) { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + PenpalA, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == v3::Location::try_from(RelayLocation::get()).expect("conversion works"), + owner: *owner == t.receiver.account_id, + }, RuntimeEvent::MessageQueue( pallet_message_queue::Event::Processed { success: true, .. } ) => {}, @@ -162,33 +314,38 @@ fn system_para_to_para_assets_receiver_assertions(_: Test) { ); } -fn para_to_para_sender_assertions(t: ParaToParaTest) { - type RuntimeEvent = ::RuntimeEvent; - PenpalB::assert_xcm_pallet_attempted_complete(None); +fn para_to_para_through_relay_sender_assertions(t: ParaToParaThroughRelayTest) { + type RuntimeEvent = ::RuntimeEvent; + + let relay_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + + PenpalA::assert_xcm_pallet_attempted_complete(None); + // XCM sent to relay reserve + PenpalA::assert_parachain_system_ump_sent(); + assert_expected_events!( - PenpalB, + PenpalA, vec![ // Amount to reserve transfer is transferred to Parachain's Sovereign account - RuntimeEvent::Balances( - pallet_balances::Event::Burned { who, amount } + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Burned { asset_id, owner, balance }, ) => { - who: *who == t.sender.account_id, - amount: *amount == t.args.amount, + asset_id: *asset_id == relay_asset_location, + owner: *owner == t.sender.account_id, + balance: *balance == t.args.amount, }, - // XCM sent to relay reserve - RuntimeEvent::ParachainSystem( - cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } - ) => {}, ] ); } -fn para_to_para_relay_hop_assertions(t: ParaToParaTest) { +fn para_to_para_relay_hop_assertions(t: ParaToParaThroughRelayTest) { type RuntimeEvent = ::RuntimeEvent; - let sov_penpal_b_on_westend = - Westend::sovereign_account_id_of(Westend::child_location_of(PenpalB::para_id())); let sov_penpal_a_on_westend = Westend::sovereign_account_id_of(Westend::child_location_of(PenpalA::para_id())); + let sov_penpal_b_on_westend = + Westend::sovereign_account_id_of(Westend::child_location_of(PenpalB::para_id())); + assert_expected_events!( Westend, vec![ @@ -196,14 +353,14 @@ fn para_to_para_relay_hop_assertions(t: ParaToParaTest) { RuntimeEvent::Balances( pallet_balances::Event::Burned { who, amount } ) => { - who: *who == sov_penpal_b_on_westend, + who: *who == sov_penpal_a_on_westend, amount: *amount == t.args.amount, }, // Deposited to receiver parachain SA RuntimeEvent::Balances( pallet_balances::Event::Minted { who, .. } ) => { - who: *who == sov_penpal_a_on_westend, + who: *who == sov_penpal_b_on_westend, }, RuntimeEvent::MessageQueue( pallet_message_queue::Event::Processed { success: true, .. } @@ -212,15 +369,20 @@ fn para_to_para_relay_hop_assertions(t: ParaToParaTest) { ); } -fn para_to_para_receiver_assertions(_: ParaToParaTest) { - type RuntimeEvent = ::RuntimeEvent; +fn para_to_para_through_relay_receiver_assertions(t: ParaToParaThroughRelayTest) { + type RuntimeEvent = ::RuntimeEvent; + let relay_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + + PenpalB::assert_xcmp_queue_success(None); + assert_expected_events!( - PenpalA, + PenpalB, vec![ - RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == relay_asset_location, + owner: *owner == t.receiver.account_id, + }, ] ); } @@ -236,6 +398,17 @@ fn relay_to_para_reserve_transfer_assets(t: RelayToParaTest) -> DispatchResult { ) } +fn para_to_relay_reserve_transfer_assets(t: ParaToRelayTest) -> DispatchResult { + ::PolkadotXcm::limited_reserve_transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + t.args.weight_limit, + ) +} + fn system_para_to_para_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { ::PolkadotXcm::limited_reserve_transfer_assets( t.signed_origin, @@ -248,7 +421,7 @@ fn system_para_to_para_reserve_transfer_assets(t: SystemParaToParaTest) -> Dispa } fn para_to_system_para_reserve_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { - ::PolkadotXcm::limited_reserve_transfer_assets( + ::PolkadotXcm::limited_reserve_transfer_assets( t.signed_origin, bx!(t.args.dest.into()), bx!(t.args.beneficiary.into()), @@ -258,8 +431,10 @@ fn para_to_system_para_reserve_transfer_assets(t: ParaToSystemParaTest) -> Dispa ) } -fn para_to_para_limited_reserve_transfer_assets(t: ParaToParaTest) -> DispatchResult { - ::PolkadotXcm::limited_reserve_transfer_assets( +fn para_to_para_through_relay_limited_reserve_transfer_assets( + t: ParaToParaThroughRelayTest, +) -> DispatchResult { + ::PolkadotXcm::limited_reserve_transfer_assets( t.signed_origin, bx!(t.args.dest.into()), bx!(t.args.beneficiary.into()), @@ -272,6 +447,7 @@ fn para_to_para_limited_reserve_transfer_assets(t: ParaToParaTest) -> DispatchRe /// Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't work #[test] fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { + // Init values for Relay Chain let signed_origin = ::RuntimeOrigin::signed(WestendSender::get().into()); let destination = Westend::child_location_of(AssetHubWestend::para_id()); let beneficiary: Location = @@ -312,6 +488,7 @@ fn reserve_transfer_native_asset_from_system_para_to_relay_fails() { let beneficiary: Location = AccountId32Junction { network: None, id: beneficiary_id.into() }.into(); let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; + let assets: Assets = (Parent, amount_to_send).into(); let fee_asset_item = 0; @@ -337,136 +514,299 @@ fn reserve_transfer_native_asset_from_system_para_to_relay_fails() { }); } +// ========================================================================= +// ========= Reserve Transfers - Native Asset - Relay<>Parachain =========== +// ========================================================================= /// Reserve Transfers of native asset from Relay to Parachain should work #[test] fn reserve_transfer_native_asset_from_relay_to_para() { // Init values for Relay - let destination = Westend::child_location_of(PenpalB::para_id()); - let beneficiary_id = PenpalBReceiver::get(); + let destination = Westend::child_location_of(PenpalA::para_id()); + let sender = WestendSender::get(); let amount_to_send: Balance = WESTEND_ED * 1000; + let assets: Assets = (Here, amount_to_send).into(); + // Init values fot Parachain + let relay_native_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let receiver = PenpalAReceiver::get(); + + // Init Test let test_args = TestContext { - sender: WestendSender::get(), - receiver: PenpalBReceiver::get(), - args: TestArgs::new_relay(destination, beneficiary_id, amount_to_send), + sender, + receiver: receiver.clone(), + args: TestArgs::new_relay(destination.clone(), receiver.clone(), amount_to_send), }; - let mut test = RelayToParaTest::new(test_args); + // Query initial balances let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; + let receiver_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.into(), &receiver) + }); + // Set assertions and dispatchables test.set_assertion::(relay_to_para_sender_assertions); - test.set_assertion::(para_receiver_assertions); + test.set_assertion::(relay_to_para_assets_receiver_assertions); test.set_dispatchable::(relay_to_para_reserve_transfer_assets); test.assert(); + // Calculate delivery fees let delivery_fees = Westend::execute_with(|| { + let reanchored_assets = + assets.reanchored(&destination, &WestendUniversalLocation::get()).unwrap(); xcm_helpers::transfer_assets_delivery_fees::< ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); + // Query final balances let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; + let receiver_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.into(), &receiver) + }); // Sender's balance is reduced assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased + // Receiver's asset balance is increased + assert!(receiver_assets_after > receiver_assets_before); + // Receiver's asset balance increased by `amount_to_send - delivery_fees - bought_execution`; + // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but + // should be non-zero + assert!(receiver_assets_after < receiver_assets_before + amount_to_send); +} + +/// Reserve Transfers of native asset from Parachain to Relay should work +#[test] +fn reserve_transfer_native_asset_from_para_to_relay() { + // Init values for Parachain + let destination = PenpalA::parent_location(); + let sender = PenpalASender::get(); + let amount_to_send: Balance = WESTEND_ED * 1000; + let assets: Assets = (Parent, amount_to_send).into(); + let asset_owner = PenpalAssetOwner::get(); + let relay_native_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + + // fund Parachain's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner), + relay_native_asset_location, + sender.clone(), + amount_to_send, + ); + + // Init values for Relay + let receiver = WestendReceiver::get(); + let penpal_location_as_seen_by_relay = Westend::child_location_of(PenpalA::para_id()); + let sov_penpal_on_relay = Westend::sovereign_account_id_of(penpal_location_as_seen_by_relay); + + // fund Parachain's SA on Relay with the native tokens held in reserve + Westend::fund_accounts(vec![(sov_penpal_on_relay.into(), amount_to_send * 2)]); + + // Init Test + let test_args = TestContext { + sender: sender.clone(), + receiver: receiver.clone(), + args: TestArgs::new_para( + destination.clone(), + receiver, + amount_to_send, + assets.clone(), + None, + 0, + ), + }; + let mut test = ParaToRelayTest::new(test_args); + + // Query initial balances + let sender_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.into(), &sender) + }); + let receiver_balance_before = test.receiver.balance; + + // Set assertions and dispatchables + test.set_assertion::(para_to_relay_sender_assertions); + test.set_assertion::(para_to_relay_receiver_assertions); + test.set_dispatchable::(para_to_relay_reserve_transfer_assets); + test.assert(); + + // Calculate delivery fees + let delivery_fees = PenpalA::execute_with(|| { + let reanchored_assets = + assets.reanchored(&destination, &PenpalUniversalLocation::get()).unwrap(); + xcm_helpers::transfer_assets_delivery_fees::< + ::XcmSender, + >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + + // Query final balances + let sender_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.into(), &sender) + }); + let receiver_balance_after = test.receiver.balance; + + // Sender's balance is reduced + assert_eq!(sender_assets_before - amount_to_send - delivery_fees, sender_assets_after); + // Receiver's asset balance is increased assert!(receiver_balance_after > receiver_balance_before); - // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; + // Receiver's asset balance increased by `amount_to_send - delivery_fees - bought_execution`; // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but // should be non-zero assert!(receiver_balance_after < receiver_balance_before + amount_to_send); } +// ========================================================================= +// ======= Reserve Transfers - Native Asset - AssetHub<>Parachain ========== +// ========================================================================= /// Reserve Transfers of native asset from System Parachain to Parachain should work #[test] fn reserve_transfer_native_asset_from_system_para_to_para() { // Init values for System Parachain - let destination = AssetHubWestend::sibling_location_of(PenpalB::para_id()); - let beneficiary_id = PenpalBReceiver::get(); - let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; - let assets = (Parent, amount_to_send).into(); + let destination = AssetHubWestend::sibling_location_of(PenpalA::para_id()); + let sender = AssetHubWestendSender::get(); + let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 2000; + let assets: Assets = (Parent, amount_to_send).into(); + + // Init values for Parachain + let system_para_native_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let receiver = PenpalAReceiver::get(); + // Init Test let test_args = TestContext { - sender: AssetHubWestendSender::get(), - receiver: PenpalBReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), + sender, + receiver: receiver.clone(), + args: TestArgs::new_para( + destination.clone(), + receiver.clone(), + amount_to_send, + assets.clone(), + None, + 0, + ), }; - let mut test = SystemParaToParaTest::new(test_args); + // Query initial balances let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; + let receiver_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location.into(), &receiver) + }); + // Set assertions and dispatchables test.set_assertion::(system_para_to_para_sender_assertions); - test.set_assertion::(para_receiver_assertions); + test.set_assertion::(system_para_to_para_receiver_assertions); test.set_dispatchable::(system_para_to_para_reserve_transfer_assets); test.assert(); - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - + // Calculate delivery fees let delivery_fees = AssetHubWestend::execute_with(|| { + let reanchored_assets = assets + .reanchored(&destination, &AssetHubWestendUniversalLocation::get()) + .unwrap(); xcm_helpers::transfer_assets_delivery_fees::< ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + + // Query final balances + let sender_balance_after = test.sender.balance; + let receiver_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location, &receiver) }); // Sender's balance is reduced assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); - // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; + // Receiver's assets is increased + assert!(receiver_assets_after > receiver_assets_before); + // Receiver's assets increased by `amount_to_send - delivery_fees - bought_execution`; // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but // should be non-zero - assert!(receiver_balance_after < receiver_balance_before + amount_to_send); + assert!(receiver_assets_after < receiver_assets_before + amount_to_send); } /// Reserve Transfers of native asset from Parachain to System Parachain should work #[test] fn reserve_transfer_native_asset_from_para_to_system_para() { - // Init values for Penpal Parachain - let destination = PenpalB::sibling_location_of(AssetHubWestend::para_id()); - let beneficiary_id = AssetHubWestendReceiver::get(); + // Init values for Parachain + let destination = PenpalA::sibling_location_of(AssetHubWestend::para_id()); + let sender = PenpalASender::get(); let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; - let assets = (Parent, amount_to_send).into(); + let assets: Assets = (Parent, amount_to_send).into(); + let system_para_native_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let asset_owner = PenpalAssetOwner::get(); + + // fund Parachain's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner), + system_para_native_asset_location, + sender.clone(), + amount_to_send, + ); + + // Init values for System Parachain + let receiver = AssetHubWestendReceiver::get(); + let penpal_location_as_seen_by_ahr = AssetHubWestend::sibling_location_of(PenpalA::para_id()); + let sov_penpal_on_ahr = + AssetHubWestend::sovereign_account_id_of(penpal_location_as_seen_by_ahr); + // fund Parachain's SA on System Parachain with the native tokens held in reserve + AssetHubWestend::fund_accounts(vec![(sov_penpal_on_ahr.into(), amount_to_send * 2)]); + + // Init Test let test_args = TestContext { - sender: PenpalBSender::get(), - receiver: AssetHubWestendReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), + sender: sender.clone(), + receiver: receiver.clone(), + args: TestArgs::new_para( + destination.clone(), + receiver.clone(), + amount_to_send, + assets.clone(), + None, + 0, + ), }; - let mut test = ParaToSystemParaTest::new(test_args); - let sender_balance_before = test.sender.balance; + // Query initial balances + let sender_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location, &sender) + }); let receiver_balance_before = test.receiver.balance; - let penpal_location_as_seen_by_ahw = AssetHubWestend::sibling_location_of(PenpalB::para_id()); - let sov_penpal_on_ahw = - AssetHubWestend::sovereign_account_id_of(penpal_location_as_seen_by_ahw); - - // fund the Penpal's SA on AHW with the native tokens held in reserve - AssetHubWestend::fund_accounts(vec![(sov_penpal_on_ahw.into(), amount_to_send * 2)]); - - test.set_assertion::(para_to_system_para_sender_assertions); + // Set assertions and dispatchables + test.set_assertion::(para_to_system_para_sender_assertions); test.set_assertion::(para_to_system_para_receiver_assertions); - test.set_dispatchable::(para_to_system_para_reserve_transfer_assets); + test.set_dispatchable::(para_to_system_para_reserve_transfer_assets); test.assert(); - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - let delivery_fees = PenpalB::execute_with(|| { + // Calculate delivery fees + let delivery_fees = PenpalA::execute_with(|| { + let reanchored_assets = + assets.reanchored(&destination, &PenpalUniversalLocation::get()).unwrap(); xcm_helpers::transfer_assets_delivery_fees::< ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + }); + + // Query final balances + let sender_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location, &sender) }); + let receiver_balance_after = test.receiver.balance; // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); + assert_eq!(sender_assets_before - amount_to_send - delivery_fees, sender_assets_after); // Receiver's balance is increased assert!(receiver_balance_after > receiver_balance_before); // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; @@ -475,36 +815,27 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { assert!(receiver_balance_after < receiver_balance_before + amount_to_send); } +// ========================================================================= +// ======= Reserve Transfers - Non-system Asset - AssetHub<>Parachain ====== +// ========================================================================= /// Reserve Transfers of a local asset and native asset from System Parachain to Parachain should /// work #[test] fn reserve_transfer_assets_from_system_para_to_para() { - // Force create asset on AssetHubWestend and PenpalB from Relay Chain - AssetHubWestend::force_create_and_mint_asset( - ASSET_ID, - ASSET_MIN_BALANCE, - true, - AssetHubWestendSender::get(), - Some(Weight::from_parts(1_019_445_000, 200_000)), - ASSET_MIN_BALANCE * 1_000_000, - ); - PenpalB::force_create_and_mint_asset( - ASSET_ID, - ASSET_MIN_BALANCE, - false, - PenpalBSender::get(), - None, - 0, - ); - // Init values for System Parachain - let destination = AssetHubWestend::sibling_location_of(PenpalB::para_id()); - let beneficiary_id = PenpalBReceiver::get(); - let fee_amount_to_send = ASSET_HUB_WESTEND_ED * 1000; - let asset_amount_to_send = ASSET_MIN_BALANCE * 1000; + let destination = AssetHubWestend::sibling_location_of(PenpalA::para_id()); + let sov_penpal_on_ahr = AssetHubWestend::sovereign_account_id_of(destination.clone()); + let sender = AssetHubWestendSender::get(); + let fee_amount_to_send = ASSET_HUB_WESTEND_ED * 100; + let asset_amount_to_send = ASSET_HUB_WESTEND_ED * 100; + let asset_owner = AssetHubWestendAssetOwner::get(); + let asset_owner_signer = ::RuntimeOrigin::signed(asset_owner.clone()); let assets: Assets = vec![ (Parent, fee_amount_to_send).into(), - ([PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())], asset_amount_to_send) + ( + [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(RESERVABLE_ASSET_ID.into())], + asset_amount_to_send, + ) .into(), ] .into(); @@ -513,49 +844,212 @@ fn reserve_transfer_assets_from_system_para_to_para() { .iter() .position(|r| r == &(Parent, fee_amount_to_send).into()) .unwrap() as u32; + AssetHubWestend::mint_asset( + asset_owner_signer, + RESERVABLE_ASSET_ID, + asset_owner, + asset_amount_to_send * 2, + ); + + // Create SA-of-Penpal-on-AHR with ED. + AssetHubWestend::fund_accounts(vec![(sov_penpal_on_ahr.into(), ASSET_HUB_WESTEND_ED)]); + + // Init values for Parachain + let receiver = PenpalAReceiver::get(); + let system_para_native_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let system_para_foreign_asset_location = + v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).expect("conversion works"); + // Init Test let para_test_args = TestContext { - sender: AssetHubWestendSender::get(), - receiver: PenpalBReceiver::get(), + sender: sender.clone(), + receiver: receiver.clone(), args: TestArgs::new_para( destination, - beneficiary_id, + receiver.clone(), asset_amount_to_send, assets, None, fee_asset_index, ), }; - let mut test = SystemParaToParaTest::new(para_test_args); - // Create SA-of-Penpal-on-AHW with ED. - let penpal_location = AssetHubWestend::sibling_location_of(PenpalB::para_id()); - let sov_penpal_on_ahw = AssetHubWestend::sovereign_account_id_of(penpal_location); - AssetHubWestend::fund_accounts(vec![(sov_penpal_on_ahw.into(), WESTEND_ED)]); - + // Query initial balances let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - let sender_assets_before = AssetHubWestend::execute_with(|| { type Assets = ::Assets; - >::balance(ASSET_ID, &AssetHubWestendSender::get()) + >::balance(RESERVABLE_ASSET_ID, &sender) }); - let receiver_assets_before = PenpalB::execute_with(|| { - type Assets = ::Assets; - >::balance(ASSET_ID, &PenpalBReceiver::get()) + let receiver_system_native_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location, &receiver) + }); + let receiver_foreign_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_foreign_asset_location, &receiver) }); + // Set assertions and dispatchables test.set_assertion::(system_para_to_para_assets_sender_assertions); - test.set_assertion::(system_para_to_para_assets_receiver_assertions); + test.set_assertion::(system_para_to_para_assets_receiver_assertions); test.set_dispatchable::(system_para_to_para_reserve_transfer_assets); test.assert(); + // Query final balances let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - + let sender_assets_after = AssetHubWestend::execute_with(|| { + type Assets = ::Assets; + >::balance(RESERVABLE_ASSET_ID, &sender) + }); + let receiver_system_native_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location, &receiver) + }); + let receiver_foreign_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_foreign_asset_location, &receiver) + }); // Sender's balance is reduced assert!(sender_balance_after < sender_balance_before); + // Receiver's foreign asset balance is increased + assert!(receiver_foreign_assets_after > receiver_foreign_assets_before); + // Receiver's system asset balance increased by `amount_to_send - delivery_fees - + // bought_execution`; `delivery_fees` might be paid from transfer or JIT, also + // `bought_execution` is unknown but should be non-zero + assert!( + receiver_system_native_assets_after < + receiver_system_native_assets_before + fee_amount_to_send + ); + + // Sender's asset balance is reduced by exact amount + assert_eq!(sender_assets_before - asset_amount_to_send, sender_assets_after); + // Receiver's foreign asset balance is increased by exact amount + assert_eq!( + receiver_foreign_assets_after, + receiver_foreign_assets_before + asset_amount_to_send + ); +} + +/// Reserve Transfers of a foreign asset and native asset from Parachain to System Para should +/// work +#[test] +fn reserve_transfer_assets_from_para_to_system_para() { + // Init values for Parachain + let destination = PenpalA::sibling_location_of(AssetHubWestend::para_id()); + let sender = PenpalASender::get(); + let fee_amount_to_send = ASSET_HUB_WESTEND_ED * 100; + let asset_amount_to_send = ASSET_HUB_WESTEND_ED * 100; + let penpal_asset_owner = PenpalAssetOwner::get(); + let penpal_asset_owner_signer = ::RuntimeOrigin::signed(penpal_asset_owner); + let asset_location_on_penpal = + v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).expect("conversion works"); + let asset_location_on_penpal_latest: Location = asset_location_on_penpal.try_into().unwrap(); + let system_asset_location_on_penpal = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let assets: Assets = vec![ + (Parent, fee_amount_to_send).into(), + (asset_location_on_penpal_latest, asset_amount_to_send).into(), + ] + .into(); + let fee_asset_index = assets + .inner() + .iter() + .position(|r| r == &(Parent, fee_amount_to_send).into()) + .unwrap() as u32; + // Fund Parachain's sender account with some foreign assets + PenpalA::mint_foreign_asset( + penpal_asset_owner_signer.clone(), + asset_location_on_penpal, + sender.clone(), + asset_amount_to_send * 2, + ); + // Fund Parachain's sender account with some system assets + PenpalA::mint_foreign_asset( + penpal_asset_owner_signer, + system_asset_location_on_penpal, + sender.clone(), + fee_amount_to_send * 2, + ); + + // Init values for System Parachain + let receiver = AssetHubWestendReceiver::get(); + let penpal_location_as_seen_by_ahr = AssetHubWestend::sibling_location_of(PenpalA::para_id()); + let sov_penpal_on_ahr = + AssetHubWestend::sovereign_account_id_of(penpal_location_as_seen_by_ahr); + let system_para_native_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let system_para_foreign_asset_location = + v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).expect("conversion works"); + let ah_asset_owner = AssetHubWestendAssetOwner::get(); + let ah_asset_owner_signer = ::RuntimeOrigin::signed(ah_asset_owner); + + // Fund SA-of-Penpal-on-AHR to be able to pay for the fees. + AssetHubWestend::fund_accounts(vec![( + sov_penpal_on_ahr.clone().into(), + ASSET_HUB_WESTEND_ED * 1000, + )]); + // Fund SA-of-Penpal-on-AHR to be able to pay for the sent amount. + AssetHubWestend::mint_asset( + ah_asset_owner_signer, + RESERVABLE_ASSET_ID, + sov_penpal_on_ahr, + asset_amount_to_send * 2, + ); + + // Init Test + let para_test_args = TestContext { + sender: sender.clone(), + receiver: receiver.clone(), + args: TestArgs::new_para( + destination, + receiver.clone(), + asset_amount_to_send, + assets, + None, + fee_asset_index, + ), + }; + let mut test = ParaToSystemParaTest::new(para_test_args); + + // Query initial balances + let sender_system_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location, &sender) + }); + let sender_foreign_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_foreign_asset_location, &sender) + }); + let receiver_balance_before = test.receiver.balance; + let receiver_assets_before = AssetHubWestend::execute_with(|| { + type Assets = ::Assets; + >::balance(RESERVABLE_ASSET_ID, &receiver) + }); + + // Set assertions and dispatchables + test.set_assertion::(para_to_system_para_assets_sender_assertions); + test.set_assertion::(para_to_system_para_assets_receiver_assertions); + test.set_dispatchable::(para_to_system_para_reserve_transfer_assets); + test.assert(); + + // Query final balances + let sender_system_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_native_asset_location, &sender) + }); + let sender_foreign_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(system_para_foreign_asset_location, &sender) + }); + let receiver_balance_after = test.receiver.balance; + let receiver_assets_after = AssetHubWestend::execute_with(|| { + type Assets = ::Assets; + >::balance(RESERVABLE_ASSET_ID, &receiver) + }); + // Sender's system asset balance is reduced + assert!(sender_system_assets_after < sender_system_assets_before); // Receiver's balance is increased assert!(receiver_balance_after > receiver_balance_before); // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; @@ -563,65 +1057,88 @@ fn reserve_transfer_assets_from_system_para_to_para() { // should be non-zero assert!(receiver_balance_after < receiver_balance_before + fee_amount_to_send); - let sender_assets_after = AssetHubWestend::execute_with(|| { - type Assets = ::Assets; - >::balance(ASSET_ID, &AssetHubWestendSender::get()) - }); - let receiver_assets_after = PenpalB::execute_with(|| { - type Assets = ::Assets; - >::balance(ASSET_ID, &PenpalBReceiver::get()) - }); - - // Sender's balance is reduced by exact amount - assert_eq!(sender_assets_before - asset_amount_to_send, sender_assets_after); - // Receiver's balance is increased by exact amount + // Sender's asset balance is reduced by exact amount + assert_eq!(sender_foreign_assets_before - asset_amount_to_send, sender_foreign_assets_after); + // Receiver's foreign asset balance is increased by exact amount assert_eq!(receiver_assets_after, receiver_assets_before + asset_amount_to_send); } +// ========================================================================= +// ===== Reserve Transfers - Native Asset - Parachain<>Relay<>Parachain ==== +// ========================================================================= /// Reserve Transfers of native asset from Parachain to Parachain (through Relay reserve) should /// work #[test] -fn reserve_transfer_native_asset_from_para_to_para() { - // Init values for Penpal Parachain - let destination = PenpalB::sibling_location_of(PenpalA::para_id()); - let beneficiary_id = PenpalAReceiver::get(); - let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; +fn reserve_transfer_native_asset_from_para_to_para_trough_relay() { + // Init values for Parachain Origin + let destination = PenpalA::sibling_location_of(PenpalB::para_id()); + let sender = PenpalASender::get(); + let amount_to_send: Balance = WESTEND_ED * 10000; + let asset_owner = PenpalAssetOwner::get(); let assets = (Parent, amount_to_send).into(); + let relay_native_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let sender_as_seen_by_relay = Westend::child_location_of(PenpalA::para_id()); + let sov_of_sender_on_relay = Westend::sovereign_account_id_of(sender_as_seen_by_relay); - let test_args = TestContext { - sender: PenpalBSender::get(), - receiver: PenpalAReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; + // fund Parachain's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner), + relay_native_asset_location, + sender.clone(), + amount_to_send, + ); - let mut test = ParaToParaTest::new(test_args); + // fund the Parachain Origin's SA on Relay Chain with the native tokens held in reserve + Westend::fund_accounts(vec![(sov_of_sender_on_relay.into(), amount_to_send * 2)]); - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; + // Init values for Parachain Desitnation + let receiver = PenpalBReceiver::get(); - let sender_as_seen_by_relay = Westend::child_location_of(PenpalB::para_id()); - let sov_of_sender_on_relay = Westend::sovereign_account_id_of(sender_as_seen_by_relay); + // Init Test + let test_args = TestContext { + sender: sender.clone(), + receiver: receiver.clone(), + args: TestArgs::new_para(destination, receiver.clone(), amount_to_send, assets, None, 0), + }; + let mut test = ParaToParaThroughRelayTest::new(test_args); - // fund the PenpalB's SA on Westend with the native tokens held in reserve - Westend::fund_accounts(vec![(sov_of_sender_on_relay.into(), amount_to_send * 2)]); + // Query initial balances + let sender_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location, &sender) + }); + let receiver_assets_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location, &receiver) + }); - test.set_assertion::(para_to_para_sender_assertions); + // Set assertions and dispatchables + test.set_assertion::(para_to_para_through_relay_sender_assertions); test.set_assertion::(para_to_para_relay_hop_assertions); - test.set_assertion::(para_to_para_receiver_assertions); - test.set_dispatchable::(para_to_para_limited_reserve_transfer_assets); + test.set_assertion::(para_to_para_through_relay_receiver_assertions); + test.set_dispatchable::(para_to_para_through_relay_limited_reserve_transfer_assets); test.assert(); - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - let delivery_fees = PenpalB::execute_with(|| { + // Calculate delivery fees + let delivery_fees = PenpalA::execute_with(|| { xcm_helpers::transfer_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); + // Query final balances + let sender_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location, &sender) + }); + let receiver_assets_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location, &receiver) + }); + // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); + assert_eq!(sender_assets_before - amount_to_send - delivery_fees, sender_assets_after); // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); + assert!(receiver_assets_after > receiver_assets_before); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs index a3cd5c5803e..eb0e985cc0c 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; +use crate::imports::*; /// Relay Chain should be able to execute `Transact` instructions in System Parachain /// when `OriginKind::Superuser`. @@ -28,12 +28,99 @@ fn send_transact_as_superuser_from_relay_to_system_para_works() { ) } -/// Parachain should be able to send XCM paying its fee with sufficient asset -/// in the System Parachain +/// We tests two things here: +/// - Parachain should be able to send XCM paying its fee with system asset in the System Parachain +/// - Parachain should be able to create a new Foreign Asset in the System Parachain +#[test] +fn send_xcm_from_para_to_system_para_paying_fee_with_system_assets_works() { + let para_sovereign_account = AssetHubWestend::sovereign_account_id_of( + AssetHubWestend::sibling_location_of(PenpalA::para_id()), + ); + let asset_location_on_penpal = v3::Location::new( + 0, + [ + v3::Junction::PalletInstance(ASSETS_PALLET_ID), + v3::Junction::GeneralIndex(ASSET_ID.into()), + ], + ); + let foreign_asset_at_asset_hub = + v3::Location::new(1, [v3::Junction::Parachain(PenpalA::para_id().into())]) + .appended_with(asset_location_on_penpal) + .unwrap(); + + // Encoded `create_asset` call to be executed in AssetHub + let call = AssetHubWestend::create_foreign_asset_call( + foreign_asset_at_asset_hub, + ASSET_MIN_BALANCE, + para_sovereign_account.clone(), + ); + + let origin_kind = OriginKind::Xcm; + let fee_amount = ASSET_HUB_WESTEND_ED * 1000000; + let system_asset = (Parent, fee_amount).into(); + + let root_origin = ::RuntimeOrigin::root(); + let system_para_destination = PenpalA::sibling_location_of(AssetHubWestend::para_id()).into(); + let xcm = xcm_transact_paid_execution( + call, + origin_kind, + system_asset, + para_sovereign_account.clone(), + ); + + // SA-of-Penpal-on-AHR needs to have balance to pay for fees and asset creation deposit + AssetHubWestend::fund_accounts(vec![( + para_sovereign_account.clone().into(), + ASSET_HUB_WESTEND_ED * 10000000000, + )]); + + PenpalA::execute_with(|| { + assert_ok!(::PolkadotXcm::send( + root_origin, + bx!(system_para_destination), + bx!(xcm), + )); + + PenpalA::assert_xcm_pallet_sent(); + }); + + AssetHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + AssetHubWestend::assert_xcmp_queue_success(Some(Weight::from_parts( + 15_594_564_000, + 562_893, + ))); + + assert_expected_events!( + AssetHubWestend, + vec![ + // Burned the fee + RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { + who: *who == para_sovereign_account, + amount: *amount == fee_amount, + }, + // Foreign Asset created + RuntimeEvent::ForeignAssets(pallet_assets::Event::Created { asset_id, creator, owner }) => { + asset_id: *asset_id == foreign_asset_at_asset_hub, + creator: *creator == para_sovereign_account.clone(), + owner: *owner == para_sovereign_account, + }, + ] + ); + + type ForeignAssets = ::ForeignAssets; + assert!(ForeignAssets::asset_exists(foreign_asset_at_asset_hub)); + }); +} + +/// We tests two things here: +/// - Parachain should be able to send XCM paying its fee with system assets in the System Parachain +/// - Parachain should be able to create a new Asset in the System Parachain #[test] fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { let para_sovereign_account = AssetHubWestend::sovereign_account_id_of( - AssetHubWestend::sibling_location_of(PenpalB::para_id()), + AssetHubWestend::sibling_location_of(PenpalA::para_id()), ); // Force create and mint assets for Parachain's sovereign account @@ -46,57 +133,63 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { ASSET_MIN_BALANCE * 1000000000, ); - // We just need a call that can pass the `SafeCallFilter` - // Call values are not relevant - let call = AssetHubWestend::force_create_asset_call( - ASSET_ID, - para_sovereign_account.clone(), - true, + // Just a different `asset_id`` that does not exist yet + let new_asset_id = ASSET_ID + 1; + + // Encoded `create_asset` call to be executed in AssetHub + let call = AssetHubWestend::create_asset_call( + new_asset_id, ASSET_MIN_BALANCE, + para_sovereign_account.clone(), ); let origin_kind = OriginKind::SovereignAccount; let fee_amount = ASSET_MIN_BALANCE * 1000000; - let native_asset = + let asset = ([PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())], fee_amount).into(); - let root_origin = ::RuntimeOrigin::root(); - let system_para_destination = PenpalB::sibling_location_of(AssetHubWestend::para_id()).into(); - let xcm = xcm_transact_paid_execution( - call, - origin_kind, - native_asset, - para_sovereign_account.clone(), - ); + let root_origin = ::RuntimeOrigin::root(); + let system_para_destination = PenpalA::sibling_location_of(AssetHubWestend::para_id()).into(); + let xcm = xcm_transact_paid_execution(call, origin_kind, asset, para_sovereign_account.clone()); - PenpalB::execute_with(|| { - assert_ok!(::PolkadotXcm::send( + // SA-of-Penpal-on-AHR needs to have balance to pay for asset creation deposit + AssetHubWestend::fund_accounts(vec![( + para_sovereign_account.clone().into(), + ASSET_HUB_WESTEND_ED * 10000000000, + )]); + + PenpalA::execute_with(|| { + assert_ok!(::PolkadotXcm::send( root_origin, bx!(system_para_destination), bx!(xcm), )); - PenpalB::assert_xcm_pallet_sent(); + PenpalA::assert_xcm_pallet_sent(); }); AssetHubWestend::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; AssetHubWestend::assert_xcmp_queue_success(Some(Weight::from_parts( - 16_290_336_000, + 15_594_564_000, 562_893, ))); assert_expected_events!( AssetHubWestend, vec![ + // Burned the fee RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { asset_id: *asset_id == ASSET_ID, owner: *owner == para_sovereign_account, balance: *balance == fee_amount, }, - RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, .. }) => { - asset_id: *asset_id == ASSET_ID, + // Asset created + RuntimeEvent::Assets(pallet_assets::Event::Created { asset_id, creator, owner }) => { + asset_id: *asset_id == new_asset_id, + creator: *creator == para_sovereign_account.clone(), + owner: *owner == para_sovereign_account, }, ] ); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/set_xcm_versions.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/set_xcm_versions.rs index 130454551d2..474e9a86ccc 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/set_xcm_versions.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/set_xcm_versions.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; +use crate::imports::*; #[test] fn relay_sets_system_para_xcm_supported_version() { diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs index b39cc2159de..04740d31158 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs @@ -13,8 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; -use westend_system_emulated_network::penpal_emulated_chain::LocalTeleportableToAssetHubV3 as PenpalLocalTeleportableToAssetHubV3; +use crate::imports::*; #[test] fn swap_locally_on_chain_using_local_assets() { @@ -112,49 +111,39 @@ fn swap_locally_on_chain_using_local_assets() { #[test] fn swap_locally_on_chain_using_foreign_assets() { - let asset_native = Box::new(asset_hub_westend_runtime::xcm_config::WestendLocationV3::get()); - let ah_as_seen_by_penpal = PenpalB::sibling_location_of(AssetHubWestend::para_id()); - let asset_location_on_penpal = PenpalLocalTeleportableToAssetHubV3::get(); - let asset_id_on_penpal = match asset_location_on_penpal.last() { - Some(v3::Junction::GeneralIndex(id)) => *id as u32, - _ => unreachable!(), - }; - let asset_owner_on_penpal = PenpalBSender::get(); + let asset_native = + Box::new(v3::Location::try_from(RelayLocation::get()).expect("conversion works")); + let asset_location_on_penpal = + v3::Location::try_from(PenpalLocalTeleportableToAssetHub::get()).expect("conversion_works"); let foreign_asset_at_asset_hub_westend = - v3::Location::new(1, [v3::Junction::Parachain(PenpalB::para_id().into())]) + v3::Location::new(1, [v3::Junction::Parachain(PenpalA::para_id().into())]) .appended_with(asset_location_on_penpal) .unwrap(); - // 1. Create asset on penpal and, 2. Create foreign asset on asset_hub_westend - super::penpal_create_foreign_asset_on_asset_hub( - asset_id_on_penpal, - foreign_asset_at_asset_hub_westend, - ah_as_seen_by_penpal, - true, - asset_owner_on_penpal, - ASSET_MIN_BALANCE * 1_000_000, - ); - - let penpal_as_seen_by_ah = AssetHubWestend::sibling_location_of(PenpalB::para_id()); - let sov_penpal_on_ahw = AssetHubWestend::sovereign_account_id_of(penpal_as_seen_by_ah); + let penpal_as_seen_by_ah = AssetHubWestend::sibling_location_of(PenpalA::para_id()); + let sov_penpal_on_ahr = AssetHubWestend::sovereign_account_id_of(penpal_as_seen_by_ah); AssetHubWestend::fund_accounts(vec![ - (AssetHubWestendSender::get().into(), 5_000_000 * WESTEND_ED), /* An account to swap dot - * for something else. */ + // An account to swap dot for something else. + (AssetHubWestendSender::get().into(), 5_000_000 * ASSET_HUB_WESTEND_ED), + // Penpal's sovereign account in AH should have some balance + (sov_penpal_on_ahr.clone().into(), 100_000_000 * ASSET_HUB_WESTEND_ED), ]); AssetHubWestend::execute_with(|| { - // 3: Mint foreign asset on asset_hub_westend: + // 0: No need to create foreign asset as it exists in genesis. + // + // 1: Mint foreign asset on asset_hub_westend: // // (While it might be nice to use batch, // currently that's disabled due to safe call filters.) type RuntimeEvent = ::RuntimeEvent; - // 3. Mint foreign asset (in reality this should be a teleport or some such) + // 1. Mint foreign asset (in reality this should be a teleport or some such) assert_ok!(::ForeignAssets::mint( - ::RuntimeOrigin::signed(sov_penpal_on_ahw.clone().into()), + ::RuntimeOrigin::signed(sov_penpal_on_ahr.clone().into()), foreign_asset_at_asset_hub_westend, - sov_penpal_on_ahw.clone().into(), - 3_000_000_000_000, + sov_penpal_on_ahr.clone().into(), + ASSET_HUB_WESTEND_ED * 3_000_000_000_000, )); assert_expected_events!( @@ -164,7 +153,7 @@ fn swap_locally_on_chain_using_foreign_assets() { ] ); - // 4. Create pool: + // 2. Create pool: assert_ok!(::AssetConversion::create_pool( ::RuntimeOrigin::signed(AssetHubWestendSender::get()), asset_native.clone(), @@ -178,58 +167,60 @@ fn swap_locally_on_chain_using_foreign_assets() { ] ); - // 5. Add liquidity: + // 3. Add liquidity: assert_ok!(::AssetConversion::add_liquidity( - ::RuntimeOrigin::signed(sov_penpal_on_ahw.clone()), + ::RuntimeOrigin::signed(sov_penpal_on_ahr.clone()), asset_native.clone(), Box::new(foreign_asset_at_asset_hub_westend), - 1_000_000_000_000, - 2_000_000_000_000, + 1_000_000_000_000_000, + 2_000_000_000_000_000, 0, 0, - sov_penpal_on_ahw.clone().into() + sov_penpal_on_ahr.clone().into() )); assert_expected_events!( AssetHubWestend, vec![ RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {lp_token_minted, .. }) => { - lp_token_minted: *lp_token_minted == 1414213562273, + lp_token_minted: *lp_token_minted == 1414213562372995, }, ] ); - // 6. Swap! + // 4. Swap! let path = vec![asset_native.clone(), Box::new(foreign_asset_at_asset_hub_westend)]; - assert_ok!(::AssetConversion::swap_exact_tokens_for_tokens( - ::RuntimeOrigin::signed(AssetHubWestendSender::get()), - path, - 100000, - 1000, - AssetHubWestendSender::get().into(), - true - )); + assert_ok!( + ::AssetConversion::swap_exact_tokens_for_tokens( + ::RuntimeOrigin::signed(AssetHubWestendSender::get()), + path, + 100000 * ASSET_HUB_WESTEND_ED, + 1000 * ASSET_HUB_WESTEND_ED, + AssetHubWestendSender::get().into(), + true + ) + ); assert_expected_events!( AssetHubWestend, vec![ RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::SwapExecuted { amount_in, amount_out, .. },) => { - amount_in: *amount_in == 100000, - amount_out: *amount_out == 199399, + amount_in: *amount_in == 100000000000000, + amount_out: *amount_out == 181322178776029, }, ] ); - // 7. Remove liquidity + // 5. Remove liquidity assert_ok!(::AssetConversion::remove_liquidity( - ::RuntimeOrigin::signed(sov_penpal_on_ahw.clone()), + ::RuntimeOrigin::signed(sov_penpal_on_ahr.clone()), asset_native.clone(), Box::new(foreign_asset_at_asset_hub_westend), - 1414213562273 - 2_000_000_000, // all but the 2 EDs can't be retrieved. + 1414213562372995 - ASSET_HUB_WESTEND_ED * 2, // all but the 2 EDs can't be retrieved. 0, 0, - sov_penpal_on_ahw.into(), + sov_penpal_on_ahr.clone().into(), )); }); } @@ -283,7 +274,7 @@ fn pay_xcm_fee_with_some_asset_swapped_for_native() { .into(), }; let penpal = AssetHubWestend::sovereign_account_id_of(AssetHubWestend::sibling_location_of( - PenpalB::para_id(), + PenpalA::para_id(), )); AssetHubWestend::execute_with(|| { @@ -356,7 +347,7 @@ fn pay_xcm_fee_with_some_asset_swapped_for_native() { )); }); - PenpalB::execute_with(|| { + PenpalA::execute_with(|| { // send xcm transact from `penpal` account which as only `ASSET_ID` tokens on // `AssetHubWestend` let call = AssetHubWestend::force_create_asset_call( @@ -366,11 +357,11 @@ fn pay_xcm_fee_with_some_asset_swapped_for_native() { ASSET_MIN_BALANCE, ); - let penpal_root = ::RuntimeOrigin::root(); + let penpal_root = ::RuntimeOrigin::root(); let fee_amount = 4_000_000_000_000u128; let asset_one = ([PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())], fee_amount).into(); - let asset_hub_location = PenpalB::sibling_location_of(AssetHubWestend::para_id()).into(); + let asset_hub_location = PenpalA::sibling_location_of(AssetHubWestend::para_id()).into(); let xcm = xcm_transact_paid_execution( call, OriginKind::SovereignAccount, @@ -378,13 +369,13 @@ fn pay_xcm_fee_with_some_asset_swapped_for_native() { penpal.clone(), ); - assert_ok!(::PolkadotXcm::send( + assert_ok!(::PolkadotXcm::send( penpal_root, bx!(asset_hub_location), bx!(xcm), )); - PenpalB::assert_xcm_pallet_sent(); + PenpalA::assert_xcm_pallet_sent(); }); AssetHubWestend::execute_with(|| { diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs index 0dd1a1533b5..61f547fe7c5 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs @@ -13,16 +13,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; -use asset_hub_westend_runtime::xcm_config::XcmConfig as AssetHubWestendXcmConfig; -use emulated_integration_tests_common::xcm_helpers::non_fee_asset; -use westend_runtime::xcm_config::XcmConfig as WestendXcmConfig; -use westend_system_emulated_network::penpal_emulated_chain::LocalTeleportableToAssetHubV3 as PenpalLocalTeleportableToAssetHubV3; +use crate::imports::*; fn relay_origin_assertions(t: RelayToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; - Westend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(632_207_000, 7_186))); + Westend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(631_531_000, 7_186))); assert_expected_events!( Westend, @@ -47,7 +43,7 @@ fn relay_dest_assertions(t: SystemParaToRelayTest) { Westend::assert_ump_queue_processed( true, Some(AssetHubWestend::para_id()), - Some(Weight::from_parts(308_222_000, 7_186)), + Some(Weight::from_parts(307_225_000, 7_186)), ); assert_expected_events!( @@ -70,7 +66,7 @@ fn relay_dest_assertions_fail(_t: SystemParaToRelayTest) { Westend::assert_ump_queue_processed( false, Some(AssetHubWestend::para_id()), - Some(Weight::from_parts(148_705_000, 3_593)), + Some(Weight::from_parts(157_718_000, 3_593)), ); } @@ -78,8 +74,8 @@ fn para_origin_assertions(t: SystemParaToRelayTest) { type RuntimeEvent = ::RuntimeEvent; AssetHubWestend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( - 533_910_000, - 7167, + 720_053_000, + 7_203, ))); AssetHubWestend::assert_parachain_system_ump_sent(); @@ -99,7 +95,7 @@ fn para_origin_assertions(t: SystemParaToRelayTest) { fn para_dest_assertions(t: RelayToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; - AssetHubWestend::assert_dmp_queue_complete(Some(Weight::from_parts(164_793_000, 3593))); + AssetHubWestend::assert_dmp_queue_complete(Some(Weight::from_parts(157_718_000, 3593))); assert_expected_events!( AssetHubWestend, @@ -113,19 +109,22 @@ fn para_dest_assertions(t: RelayToSystemParaTest) { } fn penpal_to_ah_foreign_assets_sender_assertions(t: ParaToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - PenpalB::assert_xcm_pallet_attempted_complete(None); + type RuntimeEvent = ::RuntimeEvent; + let system_para_native_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); let expected_asset_id = t.args.asset_id.unwrap(); let (_, expected_asset_amount) = non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); + + PenpalA::assert_xcm_pallet_attempted_complete(None); assert_expected_events!( - PenpalB, + PenpalA, vec![ - RuntimeEvent::Balances( - pallet_balances::Event::Burned { who, amount } + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Burned { asset_id, owner, .. } ) => { - who: *who == t.sender.account_id, - amount: *amount == t.args.amount, + asset_id: *asset_id == system_para_native_asset_location, + owner: *owner == t.sender.account_id, }, RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { asset_id: *asset_id == expected_asset_id, @@ -139,11 +138,14 @@ fn penpal_to_ah_foreign_assets_sender_assertions(t: ParaToSystemParaTest) { fn penpal_to_ah_foreign_assets_receiver_assertions(t: ParaToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; let sov_penpal_on_ahr = AssetHubWestend::sovereign_account_id_of( - AssetHubWestend::sibling_location_of(PenpalB::para_id()), + AssetHubWestend::sibling_location_of(PenpalA::para_id()), ); let (expected_foreign_asset_id, expected_foreign_asset_amount) = non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); let expected_foreign_asset_id_v3: v3::Location = expected_foreign_asset_id.try_into().unwrap(); + + AssetHubWestend::assert_xcmp_queue_success(None); + assert_expected_events!( AssetHubWestend, vec![ @@ -163,9 +165,6 @@ fn penpal_to_ah_foreign_assets_receiver_assertions(t: ParaToSystemParaTest) { amount: *amount == expected_foreign_asset_amount, }, RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, ] ); } @@ -200,13 +199,18 @@ fn ah_to_penpal_foreign_assets_sender_assertions(t: SystemParaToParaTest) { } fn ah_to_penpal_foreign_assets_receiver_assertions(t: SystemParaToParaTest) { - type RuntimeEvent = ::RuntimeEvent; + type RuntimeEvent = ::RuntimeEvent; let expected_asset_id = t.args.asset_id.unwrap(); let (_, expected_asset_amount) = non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); - let checking_account = ::PolkadotXcm::check_account(); + let checking_account = ::PolkadotXcm::check_account(); + let system_para_native_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + + PenpalA::assert_xcmp_queue_success(None); + assert_expected_events!( - PenpalB, + PenpalA, vec![ // checking account burns local asset as part of incoming teleport RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { @@ -221,12 +225,11 @@ fn ah_to_penpal_foreign_assets_receiver_assertions(t: SystemParaToParaTest) { amount: *amount == expected_asset_amount, }, // native asset for fee is deposited to receiver - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == t.receiver.account_id, + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { + asset_id: *asset_id == system_para_native_asset_location, + owner: *owner == t.receiver.account_id, + amount: *amount == expected_asset_amount, }, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, ] ); } @@ -273,8 +276,8 @@ fn system_para_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { ) } -fn system_para_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { - ::PolkadotXcm::transfer_assets( +fn para_to_system_para_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { + ::PolkadotXcm::transfer_assets( t.signed_origin, bx!(t.args.dest.into()), bx!(t.args.beneficiary.into()), @@ -284,8 +287,8 @@ fn system_para_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResul ) } -fn para_to_system_para_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { - ::PolkadotXcm::transfer_assets( +fn system_para_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { + ::PolkadotXcm::transfer_assets( t.signed_origin, bx!(t.args.dest.into()), bx!(t.args.beneficiary.into()), @@ -301,11 +304,11 @@ fn limited_teleport_native_assets_from_relay_to_system_para_works() { // Init values for Relay Chain let amount_to_send: Balance = WESTEND_ED * 1000; let dest = Westend::child_location_of(AssetHubWestend::para_id()); - let beneficiary = AssetHubWestendReceiver::get(); + let beneficiary_id = AssetHubWestendReceiver::get(); let test_args = TestContext { sender: WestendSender::get(), - receiver: beneficiary.clone(), - args: TestArgs::new_relay(dest, beneficiary, amount_to_send), + receiver: AssetHubWestendReceiver::get(), + args: TestArgs::new_relay(dest, beneficiary_id, amount_to_send), }; let mut test = RelayToSystemParaTest::new(test_args); @@ -424,11 +427,11 @@ fn teleport_native_assets_from_relay_to_system_para_works() { // Init values for Relay Chain let amount_to_send: Balance = WESTEND_ED * 1000; let dest = Westend::child_location_of(AssetHubWestend::para_id()); - let beneficiary = AssetHubWestendReceiver::get(); + let beneficiary_id = AssetHubWestendReceiver::get(); let test_args = TestContext { sender: WestendSender::get(), - receiver: beneficiary.clone(), - args: TestArgs::new_relay(dest, beneficiary, amount_to_send), + receiver: AssetHubWestendReceiver::get(), + args: TestArgs::new_relay(dest, beneficiary_id, amount_to_send), }; let mut test = RelayToSystemParaTest::new(test_args); @@ -485,15 +488,15 @@ fn teleport_native_assets_back_from_system_para_to_relay_works() { test.set_dispatchable::(system_para_teleport_assets); test.assert(); + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + let delivery_fees = AssetHubWestend::execute_with(|| { xcm_helpers::transfer_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - // Sender's balance is reduced assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); // Receiver's balance is increased @@ -558,30 +561,21 @@ fn teleport_to_other_system_parachains_works() { /// (using native reserve-based transfer for fees) #[test] fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { - let ah_as_seen_by_penpal = PenpalB::sibling_location_of(AssetHubWestend::para_id()); - let asset_location_on_penpal = PenpalLocalTeleportableToAssetHubV3::get(); + // Init values for Parachain + let fee_amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 100; + let asset_location_on_penpal = + v3::Location::try_from(PenpalLocalTeleportableToAssetHub::get()).expect("conversion works"); let asset_id_on_penpal = match asset_location_on_penpal.last() { Some(v3::Junction::GeneralIndex(id)) => *id as u32, _ => unreachable!(), }; - let asset_owner_on_penpal = PenpalBSender::get(); - let foreign_asset_at_asset_hub_westend = - v3::Location::new(1, [v3::Junction::Parachain(PenpalB::para_id().into())]) - .appended_with(asset_location_on_penpal) - .unwrap(); - super::penpal_create_foreign_asset_on_asset_hub( - asset_id_on_penpal, - foreign_asset_at_asset_hub_westend, - ah_as_seen_by_penpal.clone(), - false, - asset_owner_on_penpal, - ASSET_MIN_BALANCE * 1_000_000, - ); - let penpal_to_ah_beneficiary_id = AssetHubWestendReceiver::get(); - - let fee_amount_to_send = ASSET_HUB_WESTEND_ED * 1000; - let asset_amount_to_send = ASSET_MIN_BALANCE * 1000; - + let asset_amount_to_send = ASSET_HUB_WESTEND_ED * 100; + let asset_owner = PenpalAssetOwner::get(); + let system_para_native_asset_location = + v3::Location::try_from(RelayLocation::get()).expect("conversion works"); + let sender = PenpalASender::get(); + let penpal_check_account = ::PolkadotXcm::check_account(); + let ah_as_seen_by_penpal = PenpalA::sibling_location_of(AssetHubWestend::para_id()); let asset_location_on_penpal_latest: Location = asset_location_on_penpal.try_into().unwrap(); let penpal_assets: Assets = vec![ (Parent, fee_amount_to_send).into(), @@ -594,9 +588,44 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { .position(|r| r == &(Parent, fee_amount_to_send).into()) .unwrap() as u32; + // fund Parachain's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner.clone()), + system_para_native_asset_location, + sender.clone(), + fee_amount_to_send, + ); + // No need to create the asset (only mint) as it exists in genesis. + PenpalA::mint_asset( + ::RuntimeOrigin::signed(asset_owner.clone()), + asset_id_on_penpal, + sender.clone(), + asset_amount_to_send, + ); + // fund Parachain's check account to be able to teleport + PenpalA::fund_accounts(vec![( + penpal_check_account.clone().into(), + ASSET_HUB_WESTEND_ED * 1000, + )]); + + // prefund SA of Penpal on AssetHub with enough native tokens to pay for fees + let penpal_as_seen_by_ah = AssetHubWestend::sibling_location_of(PenpalA::para_id()); + let sov_penpal_on_ah = AssetHubWestend::sovereign_account_id_of(penpal_as_seen_by_ah); + AssetHubWestend::fund_accounts(vec![( + sov_penpal_on_ah.clone().into(), + ASSET_HUB_WESTEND_ED * 100_000_000_000, + )]); + + // Init values for System Parachain + let foreign_asset_at_asset_hub_westend = + v3::Location::new(1, [v3::Junction::Parachain(PenpalA::para_id().into())]) + .appended_with(asset_location_on_penpal) + .unwrap(); + let penpal_to_ah_beneficiary_id = AssetHubWestendReceiver::get(); + // Penpal to AH test args let penpal_to_ah_test_args = TestContext { - sender: PenpalBSender::get(), + sender: PenpalASender::get(), receiver: AssetHubWestendReceiver::get(), args: TestArgs::new_para( ah_as_seen_by_penpal, @@ -608,13 +637,19 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { ), }; let mut penpal_to_ah = ParaToSystemParaTest::new(penpal_to_ah_test_args); + let penpal_sender_balance_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + system_para_native_asset_location, + &PenpalASender::get(), + ) + }); - let penpal_sender_balance_before = penpal_to_ah.sender.balance; let ah_receiver_balance_before = penpal_to_ah.receiver.balance; - let penpal_sender_assets_before = PenpalB::execute_with(|| { - type Assets = ::Assets; - >::balance(asset_id_on_penpal, &PenpalBSender::get()) + let penpal_sender_assets_before = PenpalA::execute_with(|| { + type Assets = ::Assets; + >::balance(asset_id_on_penpal, &PenpalASender::get()) }); let ah_receiver_assets_before = AssetHubWestend::execute_with(|| { type Assets = ::ForeignAssets; @@ -624,17 +659,24 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { ) }); - penpal_to_ah.set_assertion::(penpal_to_ah_foreign_assets_sender_assertions); + penpal_to_ah.set_assertion::(penpal_to_ah_foreign_assets_sender_assertions); penpal_to_ah.set_assertion::(penpal_to_ah_foreign_assets_receiver_assertions); - penpal_to_ah.set_dispatchable::(para_to_system_para_transfer_assets); + penpal_to_ah.set_dispatchable::(para_to_system_para_transfer_assets); penpal_to_ah.assert(); - let penpal_sender_balance_after = penpal_to_ah.sender.balance; + let penpal_sender_balance_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + system_para_native_asset_location, + &PenpalASender::get(), + ) + }); + let ah_receiver_balance_after = penpal_to_ah.receiver.balance; - let penpal_sender_assets_after = PenpalB::execute_with(|| { - type Assets = ::Assets; - >::balance(asset_id_on_penpal, &PenpalBSender::get()) + let penpal_sender_assets_after = PenpalA::execute_with(|| { + type Assets = ::Assets; + >::balance(asset_id_on_penpal, &PenpalASender::get()) }); let ah_receiver_assets_after = AssetHubWestend::execute_with(|| { type Assets = ::ForeignAssets; @@ -675,8 +717,8 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { let foreign_asset_at_asset_hub_westend_latest: Location = foreign_asset_at_asset_hub_westend.try_into().unwrap(); - let ah_to_penpal_beneficiary_id = PenpalBReceiver::get(); - let penpal_as_seen_by_ah = AssetHubWestend::sibling_location_of(PenpalB::para_id()); + let ah_to_penpal_beneficiary_id = PenpalAReceiver::get(); + let penpal_as_seen_by_ah = AssetHubWestend::sibling_location_of(PenpalA::para_id()); let ah_assets: Assets = vec![ (Parent, fee_amount_to_send).into(), (foreign_asset_at_asset_hub_westend_latest, asset_amount_to_send).into(), @@ -691,7 +733,7 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { // AH to Penpal test args let ah_to_penpal_test_args = TestContext { sender: AssetHubWestendSender::get(), - receiver: PenpalBReceiver::get(), + receiver: PenpalAReceiver::get(), args: TestArgs::new_para( penpal_as_seen_by_ah, ah_to_penpal_beneficiary_id, @@ -704,7 +746,13 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { let mut ah_to_penpal = SystemParaToParaTest::new(ah_to_penpal_test_args); let ah_sender_balance_before = ah_to_penpal.sender.balance; - let penpal_receiver_balance_before = ah_to_penpal.receiver.balance; + let penpal_receiver_balance_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + system_para_native_asset_location, + &PenpalAReceiver::get(), + ) + }); let ah_sender_assets_before = AssetHubWestend::execute_with(|| { type ForeignAssets = ::ForeignAssets; @@ -713,18 +761,24 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { &AssetHubWestendSender::get(), ) }); - let penpal_receiver_assets_before = PenpalB::execute_with(|| { - type Assets = ::Assets; - >::balance(asset_id_on_penpal, &PenpalBReceiver::get()) + let penpal_receiver_assets_before = PenpalA::execute_with(|| { + type Assets = ::Assets; + >::balance(asset_id_on_penpal, &PenpalAReceiver::get()) }); ah_to_penpal.set_assertion::(ah_to_penpal_foreign_assets_sender_assertions); - ah_to_penpal.set_assertion::(ah_to_penpal_foreign_assets_receiver_assertions); + ah_to_penpal.set_assertion::(ah_to_penpal_foreign_assets_receiver_assertions); ah_to_penpal.set_dispatchable::(system_para_to_para_transfer_assets); ah_to_penpal.assert(); let ah_sender_balance_after = ah_to_penpal.sender.balance; - let penpal_receiver_balance_after = ah_to_penpal.receiver.balance; + let penpal_receiver_balance_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + system_para_native_asset_location, + &PenpalAReceiver::get(), + ) + }); let ah_sender_assets_after = AssetHubWestend::execute_with(|| { type ForeignAssets = ::ForeignAssets; @@ -733,9 +787,9 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { &AssetHubWestendSender::get(), ) }); - let penpal_receiver_assets_after = PenpalB::execute_with(|| { - type Assets = ::Assets; - >::balance(asset_id_on_penpal, &PenpalBReceiver::get()) + let penpal_receiver_assets_after = PenpalA::execute_with(|| { + type Assets = ::Assets; + >::balance(asset_id_on_penpal, &PenpalAReceiver::get()) }); // Sender's balance is reduced diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/treasury.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/treasury.rs index 8e82059a32d..6d8c0f5e5de 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/treasury.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/treasury.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; +use crate::imports::*; use emulated_integration_tests_common::accounts::{ALICE, BOB}; use frame_support::traits::fungibles::{Create, Inspect, Mutate}; use polkadot_runtime_common::impls::VersionedLocatableAsset; diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs index 9ce981b074c..b5e19cf3fa3 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs @@ -13,62 +13,53 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Substrate -pub use frame_support::{assert_err, assert_ok, pallet_prelude::DispatchResult}; -pub use sp_runtime::DispatchError; - -// Polkadot -pub use xcm::{ - latest::ParentThen, - prelude::{AccountId32 as AccountId32Junction, *}, - v3::{ - self, Error, - NetworkId::{Rococo as RococoId, Westend as WestendId}, - }, -}; +#[cfg(test)] +mod imports { + // Substrate + pub use frame_support::{assert_err, assert_ok, pallet_prelude::DispatchResult}; + pub use sp_runtime::DispatchError; -// Bridges -pub use bp_messages::LaneId; + // Polkadot + pub use xcm::{ + latest::ParentThen, + prelude::{AccountId32 as AccountId32Junction, *}, + v3::{self, NetworkId::Westend as WestendId}, + }; -// Cumulus -pub use emulated_integration_tests_common::{ - accounts::ALICE, - impls::Inspect, - test_parachain_is_trusted_teleporter, - xcm_emulator::{ - assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, - RelayChain as Relay, Test, TestArgs, TestContext, TestExt, - }, - xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, - PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, -}; -pub use parachains_common::{AccountId, Balance}; -pub use rococo_westend_system_emulated_network::{ - asset_hub_rococo_emulated_chain::{ - genesis::ED as ASSET_HUB_ROCOCO_ED, AssetHubRococoParaPallet as AssetHubRococoPallet, - }, - asset_hub_westend_emulated_chain::{ - genesis::ED as ASSET_HUB_WESTEND_ED, AssetHubWestendParaPallet as AssetHubWestendPallet, - }, - bridge_hub_rococo_emulated_chain::{ - genesis::ED as BRIDGE_HUB_ROCOCO_ED, BridgeHubRococoParaPallet as BridgeHubRococoPallet, - }, - penpal_emulated_chain::PenpalAParaPallet as PenpalAPallet, - rococo_emulated_chain::{genesis::ED as ROCOCO_ED, RococoRelayPallet as RococoPallet}, - AssetHubRococoPara as AssetHubRococo, AssetHubRococoParaReceiver as AssetHubRococoReceiver, - AssetHubRococoParaSender as AssetHubRococoSender, AssetHubWestendPara as AssetHubWestend, - AssetHubWestendParaReceiver as AssetHubWestendReceiver, - AssetHubWestendParaSender as AssetHubWestendSender, BridgeHubRococoPara as BridgeHubRococo, - BridgeHubRococoParaReceiver as BridgeHubRococoReceiver, - BridgeHubRococoParaSender as BridgeHubRococoSender, BridgeHubWestendPara as BridgeHubWestend, - PenpalAPara as PenpalA, PenpalAParaReceiver as PenpalAReceiver, - PenpalAParaSender as PenpalASender, RococoRelay as Rococo, - RococoRelayReceiver as RococoReceiver, RococoRelaySender as RococoSender, -}; + // Cumulus + pub use emulated_integration_tests_common::{ + accounts::ALICE, + impls::Inspect, + test_parachain_is_trusted_teleporter, + xcm_emulator::{ + assert_expected_events, bx, Chain, Parachain as Para, RelayChain as Relay, TestExt, + }, + }; + pub use parachains_common::AccountId; + pub use rococo_westend_system_emulated_network::{ + asset_hub_rococo_emulated_chain::{ + genesis::ED as ASSET_HUB_ROCOCO_ED, AssetHubRococoParaPallet as AssetHubRococoPallet, + }, + asset_hub_westend_emulated_chain::{ + genesis::ED as ASSET_HUB_WESTEND_ED, AssetHubWestendParaPallet as AssetHubWestendPallet, + }, + bridge_hub_rococo_emulated_chain::{ + genesis::ED as BRIDGE_HUB_ROCOCO_ED, BridgeHubRococoParaPallet as BridgeHubRococoPallet, + }, + penpal_emulated_chain::PenpalAParaPallet as PenpalAPallet, + rococo_emulated_chain::{genesis::ED as ROCOCO_ED, RococoRelayPallet as RococoPallet}, + AssetHubRococoPara as AssetHubRococo, AssetHubRococoParaReceiver as AssetHubRococoReceiver, + AssetHubRococoParaSender as AssetHubRococoSender, AssetHubWestendPara as AssetHubWestend, + AssetHubWestendParaReceiver as AssetHubWestendReceiver, + AssetHubWestendParaSender as AssetHubWestendSender, BridgeHubRococoPara as BridgeHubRococo, + BridgeHubRococoParaSender as BridgeHubRococoSender, + BridgeHubWestendPara as BridgeHubWestend, PenpalAPara as PenpalA, + PenpalAParaReceiver as PenpalAReceiver, PenpalAParaSender as PenpalASender, + RococoRelay as Rococo, + }; -pub const ASSET_ID: u32 = 1; -pub const ASSET_MIN_BALANCE: u128 = 1000; -pub const ASSETS_PALLET_ID: u8 = 50; + pub const ASSET_MIN_BALANCE: u128 = 1000; +} #[cfg(test)] mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs index 6d7b53c8fdf..88dad06434b 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; +use crate::imports::*; mod asset_transfers; mod send_xcm; diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs index ff069e2d344..1e74d63e1d5 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs @@ -12,7 +12,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; +use crate::imports::*; use bridge_hub_rococo_runtime::{EthereumBeaconClient, EthereumInboundQueue, RuntimeOrigin}; use codec::{Decode, Encode}; use emulated_integration_tests_common::xcm_emulator::ConvertLocation; diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/teleport.rs index 43f8af9244f..8f51f5b1800 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/teleport.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; +use crate::tests::*; use bridge_hub_rococo_runtime::xcm_config::XcmConfig; #[test] diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs index 223979cc9c9..60c31ce5a4a 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs @@ -13,59 +13,52 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Substrate -pub use frame_support::{assert_err, assert_ok, pallet_prelude::DispatchResult}; -pub use sp_runtime::DispatchError; - -// Polkadot -pub use xcm::{ - latest::ParentThen, - prelude::{AccountId32 as AccountId32Junction, *}, - v3, - v4::{ - Error, - NetworkId::{Rococo as RococoId, Westend as WestendId}, - }, -}; +#[cfg(test)] +mod imports { + // Substrate + pub use frame_support::{assert_err, assert_ok, pallet_prelude::DispatchResult}; + pub use sp_runtime::DispatchError; -// Bridges -pub use bp_messages::LaneId; + // Polkadot + pub use xcm::{ + latest::ParentThen, + prelude::{AccountId32 as AccountId32Junction, *}, + v3, + v4::NetworkId::Rococo as RococoId, + }; -// Cumulus -pub use emulated_integration_tests_common::{ - accounts::ALICE, - impls::Inspect, - test_parachain_is_trusted_teleporter, - xcm_emulator::{ - assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, - RelayChain as Relay, Test, TestArgs, TestContext, TestExt, - }, - xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, - PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, -}; -pub use parachains_common::{AccountId, Balance}; -pub use rococo_westend_system_emulated_network::{ - asset_hub_rococo_emulated_chain::{ - genesis::ED as ASSET_HUB_ROCOCO_ED, AssetHubRococoParaPallet as AssetHubRococoPallet, - }, - asset_hub_westend_emulated_chain::{ - genesis::ED as ASSET_HUB_WESTEND_ED, AssetHubWestendParaPallet as AssetHubWestendPallet, - }, - bridge_hub_westend_emulated_chain::{ - genesis::ED as BRIDGE_HUB_WESTEND_ED, BridgeHubWestendParaPallet as BridgeHubWestendPallet, - }, - westend_emulated_chain::WestendRelayPallet as WestendPallet, - AssetHubRococoPara as AssetHubRococo, AssetHubRococoParaReceiver as AssetHubRococoReceiver, - AssetHubRococoParaSender as AssetHubRococoSender, AssetHubWestendPara as AssetHubWestend, - AssetHubWestendParaReceiver as AssetHubWestendReceiver, - AssetHubWestendParaSender as AssetHubWestendSender, BridgeHubRococoPara as BridgeHubRococo, - BridgeHubWestendPara as BridgeHubWestend, BridgeHubWestendParaSender as BridgeHubWestendSender, - WestendRelay as Westend, -}; + // Cumulus + pub use emulated_integration_tests_common::{ + accounts::ALICE, + impls::Inspect, + test_parachain_is_trusted_teleporter, + xcm_emulator::{ + assert_expected_events, bx, Chain, Parachain as Para, RelayChain as Relay, TestExt, + }, + }; + pub use parachains_common::AccountId; + pub use rococo_westend_system_emulated_network::{ + asset_hub_rococo_emulated_chain::{ + genesis::ED as ASSET_HUB_ROCOCO_ED, AssetHubRococoParaPallet as AssetHubRococoPallet, + }, + asset_hub_westend_emulated_chain::{ + genesis::ED as ASSET_HUB_WESTEND_ED, AssetHubWestendParaPallet as AssetHubWestendPallet, + }, + bridge_hub_westend_emulated_chain::{ + genesis::ED as BRIDGE_HUB_WESTEND_ED, + BridgeHubWestendParaPallet as BridgeHubWestendPallet, + }, + westend_emulated_chain::WestendRelayPallet as WestendPallet, + AssetHubRococoPara as AssetHubRococo, AssetHubRococoParaReceiver as AssetHubRococoReceiver, + AssetHubRococoParaSender as AssetHubRococoSender, AssetHubWestendPara as AssetHubWestend, + AssetHubWestendParaReceiver as AssetHubWestendReceiver, + AssetHubWestendParaSender as AssetHubWestendSender, BridgeHubRococoPara as BridgeHubRococo, + BridgeHubWestendPara as BridgeHubWestend, + BridgeHubWestendParaSender as BridgeHubWestendSender, WestendRelay as Westend, + }; -pub const ASSET_ID: u32 = 1; -pub const ASSET_MIN_BALANCE: u128 = 1000; -pub const ASSETS_PALLET_ID: u8 = 50; + pub const ASSET_MIN_BALANCE: u128 = 1000; +} #[cfg(test)] mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs index 3074435e8e4..b781d6e987c 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; +use crate::imports::*; mod asset_transfers; mod send_xcm; diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/teleport.rs index edffaf16596..c960233c08b 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/teleport.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; +use crate::tests::*; use bridge_hub_westend_runtime::xcm_config::XcmConfig; #[test] diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/lib.rs index 6f2f1409135..38ff08b486d 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/lib.rs @@ -13,52 +13,41 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub use codec::Encode; +#[cfg(test)] +mod imports { + pub use codec::Encode; -// Substrate -pub use frame_support::{ - assert_err, assert_ok, - pallet_prelude::Weight, - sp_runtime::{AccountId32, DispatchError, DispatchResult}, - traits::fungibles::Inspect, -}; + // Substrate + pub use frame_support::{ + assert_ok, + pallet_prelude::Weight, + sp_runtime::{AccountId32, DispatchResult}, + traits::fungibles::Inspect, + }; -// Polkadot -pub use xcm::{ - prelude::{AccountId32 as AccountId32Junction, *}, - v3::{Error, NetworkId::Rococo as RococoId}, -}; + // Polkadot + pub use xcm::prelude::*; -// Cumulus -pub use asset_test_utils::xcm_helpers; -pub use emulated_integration_tests_common::{ - test_parachain_is_trusted_teleporter, - xcm_emulator::{ - assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, - RelayChain as Relay, Test, TestArgs, TestContext, TestExt, - }, - xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, - PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, -}; -pub use parachains_common::{AccountId, Balance}; -pub use rococo_system_emulated_network::{ - people_rococo_emulated_chain::{ - genesis::ED as PEOPLE_ROCOCO_ED, PeopleRococoParaPallet as PeopleRococoPallet, - }, - rococo_emulated_chain::{genesis::ED as ROCOCO_ED, RococoRelayPallet as RococoPallet}, - PenpalAPara as PenpalA, PeopleRococoPara as PeopleRococo, - PeopleRococoParaReceiver as PeopleRococoReceiver, PeopleRococoParaSender as PeopleRococoSender, - RococoRelay as Rococo, RococoRelayReceiver as RococoReceiver, - RococoRelaySender as RococoSender, -}; + // Cumulus + pub use asset_test_utils::xcm_helpers; + pub use emulated_integration_tests_common::xcm_emulator::{ + assert_expected_events, bx, Chain, Parachain as Para, RelayChain as Relay, Test, TestArgs, + TestContext, TestExt, + }; + pub use parachains_common::Balance; + pub use rococo_system_emulated_network::{ + people_rococo_emulated_chain::{ + genesis::ED as PEOPLE_ROCOCO_ED, PeopleRococoParaPallet as PeopleRococoPallet, + }, + rococo_emulated_chain::{genesis::ED as ROCOCO_ED, RococoRelayPallet as RococoPallet}, + PeopleRococoPara as PeopleRococo, PeopleRococoParaReceiver as PeopleRococoReceiver, + PeopleRococoParaSender as PeopleRococoSender, RococoRelay as Rococo, + RococoRelayReceiver as RococoReceiver, RococoRelaySender as RococoSender, + }; -// pub const ASSET_ID: u32 = 1; -// pub const ASSET_MIN_BALANCE: u128 = 1000; -pub type RelayToSystemParaTest = Test; -pub type RelayToParaTest = Test; -pub type SystemParaToRelayTest = Test; -pub type SystemParaToParaTest = Test; -pub type ParaToSystemParaTest = Test; + pub type RelayToSystemParaTest = Test; + pub type SystemParaToRelayTest = Test; +} #[cfg(test)] mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/reap_identity.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/reap_identity.rs index 87adb363e02..3f1f8638d6f 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/reap_identity.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/reap_identity.rs @@ -38,7 +38,7 @@ //! - The freed deposit from the Relay Chain is sufficient for the parachain deposit; and //! - The account will exist on the parachain. -use crate::*; +use crate::imports::*; use frame_support::BoundedVec; use pallet_balances::Event as BalancesEvent; use pallet_identity::{legacy::IdentityInfo, Data, Event as IdentityEvent}; diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/teleport.rs index 0a12277395d..3abe5c6cf66 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/teleport.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; +use crate::imports::*; use people_rococo_runtime::xcm_config::XcmConfig as PeopleRococoXcmConfig; use rococo_runtime::xcm_config::XcmConfig as RococoXcmConfig; diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/lib.rs index 59cec36030b..77ac7cfc78c 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/lib.rs @@ -13,52 +13,40 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub use codec::Encode; - -// Substrate -pub use frame_support::{ - assert_err, assert_ok, - pallet_prelude::Weight, - sp_runtime::{AccountId32, DispatchError, DispatchResult}, - traits::fungibles::Inspect, -}; +#[cfg(test)] +mod imports { + pub use codec::Encode; + // Substrate + pub use frame_support::{ + assert_ok, + pallet_prelude::Weight, + sp_runtime::{AccountId32, DispatchResult}, + traits::fungibles::Inspect, + }; -// Polkadot -pub use xcm::{ - prelude::{AccountId32 as AccountId32Junction, *}, - v3::{Error, NetworkId::Westend as WestendId}, -}; + // Polkadot + pub use xcm::prelude::*; -// Cumulus -pub use asset_test_utils::xcm_helpers; -pub use emulated_integration_tests_common::{ - test_parachain_is_trusted_teleporter, - xcm_emulator::{ - assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, - RelayChain as Relay, Test, TestArgs, TestContext, TestExt, - }, - xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, - PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, -}; -pub use parachains_common::{AccountId, Balance}; -pub use westend_system_emulated_network::{ - people_westend_emulated_chain::{ - genesis::ED as PEOPLE_WESTEND_ED, PeopleWestendParaPallet as PeopleWestendPallet, - }, - westend_emulated_chain::{genesis::ED as WESTEND_ED, WestendRelayPallet as WestendPallet}, - PenpalAPara as PenpalA, PeopleWestendPara as PeopleWestend, - PeopleWestendParaReceiver as PeopleWestendReceiver, - PeopleWestendParaSender as PeopleWestendSender, WestendRelay as Westend, - WestendRelayReceiver as WestendReceiver, WestendRelaySender as WestendSender, -}; + // Cumulus + pub use asset_test_utils::xcm_helpers; + pub use emulated_integration_tests_common::xcm_emulator::{ + assert_expected_events, bx, Chain, Parachain as Para, RelayChain as Relay, Test, TestArgs, + TestContext, TestExt, + }; + pub use parachains_common::Balance; + pub use westend_system_emulated_network::{ + people_westend_emulated_chain::{ + genesis::ED as PEOPLE_WESTEND_ED, PeopleWestendParaPallet as PeopleWestendPallet, + }, + westend_emulated_chain::{genesis::ED as WESTEND_ED, WestendRelayPallet as WestendPallet}, + PeopleWestendPara as PeopleWestend, PeopleWestendParaReceiver as PeopleWestendReceiver, + PeopleWestendParaSender as PeopleWestendSender, WestendRelay as Westend, + WestendRelayReceiver as WestendReceiver, WestendRelaySender as WestendSender, + }; -// pub const ASSET_ID: u32 = 1; -// pub const ASSET_MIN_BALANCE: u128 = 1000; -pub type RelayToSystemParaTest = Test; -pub type RelayToParaTest = Test; -pub type SystemParaToRelayTest = Test; -pub type SystemParaToParaTest = Test; -pub type ParaToSystemParaTest = Test; + pub type RelayToSystemParaTest = Test; + pub type SystemParaToRelayTest = Test; +} #[cfg(test)] mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/reap_identity.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/reap_identity.rs index 8d63c8ceff6..3ed8592918d 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/reap_identity.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/reap_identity.rs @@ -38,7 +38,7 @@ //! - The freed deposit from the Relay Chain is sufficient for the parachain deposit; and //! - The account will exist on the parachain. -use crate::*; +use crate::imports::*; use frame_support::BoundedVec; use pallet_balances::Event as BalancesEvent; use pallet_identity::{legacy::IdentityInfo, Data, Event as IdentityEvent}; diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/teleport.rs index 345663be99b..eef35a99a83 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/teleport.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; +use crate::imports::*; use people_westend_runtime::xcm_config::XcmConfig as PeopleWestendXcmConfig; use westend_runtime::xcm_config::XcmConfig as WestendXcmConfig; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs index 38c118dbb4b..5fa7455ad2a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs @@ -527,12 +527,12 @@ fn test_foreign_asset_xcm_take_first_trader() { let bought = Weight::from_parts(4_000_000_000u64, 0); // Lets calculate amount needed - let asset_amount_needed = - ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger::charge_weight_in_fungibles( + let asset_amount_needed + = ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger::charge_weight_in_fungibles( foreign_location, - bought, + bought ) - .expect("failed to compute"); + .expect("failed to compute"); // Lets pay with: asset_amount_needed + asset_amount_extra let asset_amount_extra = 100_u128; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs index aa8c3cf2f14..3ba9b9587d8 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -527,12 +527,8 @@ fn test_foreign_asset_xcm_take_first_trader() { let bought = Weight::from_parts(4_000_000_000u64, 0); // Lets calculate amount needed - let asset_amount_needed = - ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger::charge_weight_in_fungibles( - foreign_location, - bought, - ) - .expect("failed to compute"); + let asset_amount_needed = ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger::charge_weight_in_fungibles(foreign_location, bought) + .expect("failed to compute"); // Lets pay with: asset_amount_needed + asset_amount_extra let asset_amount_extra = 100_u128; diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index 0030287edb3..bea78e14520 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -53,7 +53,10 @@ use frame_system::{ limits::{BlockLength, BlockWeights}, EnsureRoot, EnsureSigned, }; -use parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling}; +use parachains_common::{ + impls::{AssetsToBlockAuthor, NonZeroIssuance}, + message_queue::{NarrowOriginToSibling, ParaIdToSibling}, +}; use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; use smallvec::smallvec; use sp_api::impl_runtime_apis; @@ -70,7 +73,7 @@ use sp_std::prelude::*; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use xcm_config::{AssetsToBlockAuthor, XcmOriginToTransactDispatchOrigin}; +use xcm_config::XcmOriginToTransactDispatchOrigin; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; @@ -618,7 +621,7 @@ impl pallet_asset_tx_payment::Config for Runtime { ConvertInto, pallet_assets::Instance1, >, - AssetsToBlockAuthor, + AssetsToBlockAuthor, >; } diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index 84b8fd9bb0a..bc1aa05a617 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -23,41 +23,39 @@ //! `ReserveAssetTransferDeposited` message but that will but the intension will be to support this //! soon. use super::{ - AccountId, AllPalletsWithSystem, AssetId as AssetIdPalletAssets, Assets, Balance, Balances, - ForeignAssets, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, - RuntimeOrigin, WeightToFee, XcmpQueue, + AccountId, AllPalletsWithSystem, AssetId as AssetIdPalletAssets, Assets, Authorship, Balance, + Balances, ForeignAssets, ForeignAssetsInstance, NonZeroIssuance, ParachainInfo, + ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, + XcmpQueue, }; use core::marker::PhantomData; use frame_support::{ parameter_types, - traits::{ - fungibles::{self, Balanced, Credit}, - ConstU32, Contains, ContainsPair, Everything, Get, Nothing, - }, + traits::{ConstU32, Contains, ContainsPair, Everything, EverythingBut, Get, Nothing}, weights::Weight, }; use frame_system::EnsureRoot; -use pallet_asset_tx_payment::HandleCredit; -use pallet_assets::Instance1; use pallet_xcm::XcmPassthrough; +use parachains_common::xcm_config::AssetFeeAsExistentialDepositMultiplier; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::impls::ToAuthor; -use sp_runtime::traits::Zero; +use sp_runtime::traits::ConvertInto; use xcm::latest::prelude::*; use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, - AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, AsPrefixedGeneralIndex, - ConvertedConcreteId, EnsureXcmOrigin, FixedWeightBounds, FrameTransactionalProcessor, - FungibleAdapter, FungiblesAdapter, IsConcrete, LocalMint, NativeAsset, NoChecking, - ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, - SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, StartsWith, TakeWeightCredit, TrailingSetTopicAsId, - UsingComponents, WithComputedOrigin, WithUniqueTopic, + AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, AsPrefixedGeneralIndex, ConvertedConcreteId, EnsureXcmOrigin, + FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, IsConcrete, + LocalMint, NativeAsset, NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, + SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, + SignedToAccountId32, SovereignSignedViaLocation, StartsWith, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::{traits::JustTry, XcmExecutor}; parameter_types! { pub const RelayLocation: Location = Location::parent(); + // Local native currency which is stored in `pallet_balances`` + pub const PenpalNativeCurrency: Location = Location::here(); pub const RelayNetwork: Option = None; pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorLocation = [Parachain(ParachainInfo::parachain_id().into())].into(); @@ -80,7 +78,7 @@ pub type CurrencyTransactor = FungibleAdapter< // Use this currency: Balances, // Use this currency when it is a fungible asset matching the given location or name: - IsConcrete, + IsConcrete, // Do a simple punn to convert an AccountId32 Location into a native chain account ID: LocationToAccountId, // Our chain's account ID type (we can't get away without mentioning it explicitly): @@ -123,9 +121,16 @@ pub type FungiblesTransactor = FungiblesAdapter< CheckingAccount, >; -/// `AssetId/Balance` converter for `TrustBackedAssets` -pub type ForeignAssetsConvertedConcreteId = - assets_common::ForeignAssetsConvertedConcreteId, Balance>; +pub type ForeignAssetsConvertedConcreteId = assets_common::LocationConvertedConcreteId< + EverythingBut<( + // Here we rely on fact that something like this works: + // assert!(Location::new(1, + // [Parachain(100)]).starts_with(&Location::parent())); + // assert!([Parachain(100)].into().starts_with(&Here)); + StartsWith, + )>, + Balance, +>; /// Means for transacting foreign assets from different global consensus. pub type ForeignFungiblesTransactor = FungiblesAdapter< @@ -175,6 +180,7 @@ parameter_types! { pub UnitWeightCost: Weight = Weight::from_parts(1_000_000_000, 64 * 1024); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; + pub XcmAssetFeesReceiver: Option = Authorship::author(); } pub struct ParentOrParentsExecutivePlurality; @@ -184,13 +190,6 @@ impl Contains for ParentOrParentsExecutivePlurality { } } -pub struct CommonGoodAssetsParachain; -impl Contains for CommonGoodAssetsParachain { - fn contains(location: &Location) -> bool { - matches!(location.unpack(), (1, [Parachain(1000)])) - } -} - pub type Barrier = TrailingSetTopicAsId<( TakeWeightCredit, // Expected responses are OK. @@ -201,12 +200,6 @@ pub type Barrier = TrailingSetTopicAsId<( // If the message is one that immediately attempts to pay for execution, then // allow it. AllowTopLevelPaidExecutionFrom, - // System Assets parachain, parent and its exec plurality get free - // execution - AllowExplicitUnpaidExecutionFrom<( - CommonGoodAssetsParachain, - ParentOrParentsExecutivePlurality, - )>, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, ), @@ -246,53 +239,30 @@ impl> ContainsPair for NativeAssetFrom { } } -/// Allow checking in assets that have issuance > 0. -pub struct NonZeroIssuance(PhantomData<(AccountId, Assets)>); -impl Contains<>::AssetId> - for NonZeroIssuance -where - Assets: fungibles::Inspect, -{ - fn contains(id: &>::AssetId) -> bool { - !Assets::total_issuance(id.clone()).is_zero() - } -} - -/// A `HandleCredit` implementation that naively transfers the fees to the block author. -/// Will drop and burn the assets in case the transfer fails. -pub struct AssetsToBlockAuthor(PhantomData); -impl HandleCredit, pallet_assets::Pallet> for AssetsToBlockAuthor -where - R: pallet_authorship::Config + pallet_assets::Config, - AccountIdOf: From + Into, -{ - fn handle_credit(credit: Credit, pallet_assets::Pallet>) { - if let Some(author) = pallet_authorship::Pallet::::author() { - // In case of error: Will drop the result triggering the `OnDrop` of the imbalance. - let _ = pallet_assets::Pallet::::resolve(&author, credit); - } - } -} - +// This asset can be added to AH as Asset and reserved transfer between Penpal and AH +pub const RESERVABLE_ASSET_ID: u32 = 1; // This asset can be added to AH as ForeignAsset and teleported between Penpal and AH pub const TELEPORTABLE_ASSET_ID: u32 = 2; + +pub const ASSETS_PALLET_ID: u8 = 50; +pub const ASSET_HUB_ID: u32 = 1000; + parameter_types! { /// The location that this chain recognizes as the Relay network's Asset Hub. - pub SystemAssetHubLocation: Location = Location::new(1, [Parachain(1000)]); - // ALWAYS ensure that the index in PalletInstance stays up-to-date with + pub SystemAssetHubLocation: Location = Location::new(1, [Parachain(ASSET_HUB_ID)]); // the Relay Chain's Asset Hub's Assets pallet index pub SystemAssetHubAssetsPalletLocation: Location = - Location::new(1, [Parachain(1000), PalletInstance(50)]); + Location::new(1, [Parachain(ASSET_HUB_ID), PalletInstance(ASSETS_PALLET_ID)]); pub AssetsPalletLocation: Location = - Location::new(0, [PalletInstance(50)]); + Location::new(0, [PalletInstance(ASSETS_PALLET_ID)]); pub CheckingAccount: AccountId = PolkadotXcm::check_account(); pub LocalTeleportableToAssetHub: Location = Location::new( 0, - [PalletInstance(50), GeneralIndex(TELEPORTABLE_ASSET_ID.into())] + [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(TELEPORTABLE_ASSET_ID.into())] ); - pub LocalTeleportableToAssetHubV3: xcm::v3::Location = xcm::v3::Location::new( - 0, - [xcm::v3::Junction::PalletInstance(50), xcm::v3::Junction::GeneralIndex(TELEPORTABLE_ASSET_ID.into())] + pub LocalReservableFromAssetHub: Location = Location::new( + 1, + [Parachain(ASSET_HUB_ID), PalletInstance(ASSETS_PALLET_ID), GeneralIndex(RESERVABLE_ASSET_ID.into())] ); /// The Penpal runtime is utilized for testing with various environment setups. @@ -337,8 +307,22 @@ impl xcm_executor::Config for XcmConfig { type UniversalLocation = UniversalLocation; type Barrier = Barrier; type Weigher = FixedWeightBounds; - type Trader = - UsingComponents>; + type Trader = ( + UsingComponents>, + // This trader allows to pay with `is_sufficient=true` "Foreign" assets from dedicated + // `pallet_assets` instance - `ForeignAssets`. + cumulus_primitives_utility::TakeFirstAssetTrader< + AccountId, + ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger, + ForeignAssetsConvertedConcreteId, + ForeignAssets, + cumulus_primitives_utility::XcmFeesTo32ByteAccount< + ForeignFungiblesTransactor, + AccountId, + XcmAssetFeesReceiver, + >, + >, + ); type ResponseHandler = PolkadotXcm; type AssetTrap = PolkadotXcm; type AssetClaims = PolkadotXcm; @@ -356,6 +340,15 @@ impl xcm_executor::Config for XcmConfig { type TransactionalProcessor = FrameTransactionalProcessor; } +/// Multiplier used for dedicated `TakeFirstAssetTrader` with `ForeignAssets` instance. +pub type ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger = + AssetFeeAsExistentialDepositMultiplier< + Runtime, + WeightToFee, + pallet_assets::BalanceToAssetBalance, + ForeignAssetsInstance, + >; + /// No local origins on this chain are allowed to dispatch XCM sends/executions. pub type LocalOriginToLocation = SignedToAccountId32; -- GitLab From 3c6ebd9e9bfda58f199cba6ec3023e0d12d6b506 Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Thu, 14 Mar 2024 11:44:55 +0100 Subject: [PATCH 041/187] fix(paseo-spec): New Paseo Bootnodes (#3674) This change includes new bootnodes for Paseo. _This is meant to be a silent PR_ --- polkadot/node/service/chain-specs/paseo.json | 287 ++++++++++++++++--- 1 file changed, 240 insertions(+), 47 deletions(-) diff --git a/polkadot/node/service/chain-specs/paseo.json b/polkadot/node/service/chain-specs/paseo.json index 8db75ff137b..2e659716766 100644 --- a/polkadot/node/service/chain-specs/paseo.json +++ b/polkadot/node/service/chain-specs/paseo.json @@ -5,23 +5,20 @@ "bootNodes": [ "/dns/paseo.bootnode.amforc.com/tcp/30333/wss/p2p/12D3KooWFD81HC9memUwuGMLvhDDEfmXjn6jC4n7zyNs3vToXapS", "/dns/paseo.bootnode.amforc.com/tcp/30344/p2p/12D3KooWFD81HC9memUwuGMLvhDDEfmXjn6jC4n7zyNs3vToXapS", - "/dns/paseo-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWADeayZC8zag4Qrb4GosSn65MmfVZztRPMaBdgZnQqXRo", - "/dns/paseo-bootnode.radiumblock.com/tcp/30335/wss/p2p/12D3KooWADeayZC8zag4Qrb4GosSn65MmfVZztRPMaBdgZnQqXRo", - "/dns/boot.gatotech.network/tcp/33400/p2p/12D3KooWEvz5Ygv3MhCUNTVQbUTVhzhvf4KKcNoe5M5YbVLPBeeW", - "/dns/boot.gatotech.network/tcp/35400/wss/p2p/12D3KooWEvz5Ygv3MhCUNTVQbUTVhzhvf4KKcNoe5M5YbVLPBeeW", + "/dns/boot.stake.plus/tcp/43334/wss/p2p/12D3KooWNhgAC3hjZHxaT52EpPFZohkCL1AHFAijqcN8xB9Rwud2", + "/dns/boot.stake.plus/tcp/43333/p2p/12D3KooWNhgAC3hjZHxaT52EpPFZohkCL1AHFAijqcN8xB9Rwud2", + "/dns/boot.metaspan.io/tcp/36017/wss/p2p/12D3KooWSW6nDfM3SS8rUtjMyjdszivK31bu4a1sRngGa2hFETz7", + "/dns/boot.metaspan.io/tcp/36018/p2p/12D3KooWSW6nDfM3SS8rUtjMyjdszivK31bu4a1sRngGa2hFETz7", + "/dns/paseo.bootnodes.polkadotters.com/tcp/30538/p2p/12D3KooWPbbFy4TefEGTRF5eTYhq8LEzc4VAHdNUVCbY4nAnhqPP", + "/dns/paseo.bootnodes.polkadotters.com/tcp/30540/wss/p2p/12D3KooWPbbFy4TefEGTRF5eTYhq8LEzc4VAHdNUVCbY4nAnhqPP", "/dns/boot-node.helikon.io/tcp/10020/p2p/12D3KooWBetfzZpf6tGihKrqCo5z854Ub4ZNAUUTRT6eYHNh7FYi", "/dns/boot-node.helikon.io/tcp/10022/wss/p2p/12D3KooWBetfzZpf6tGihKrqCo5z854Ub4ZNAUUTRT6eYHNh7FYi", - "/dns/pso16.rotko.net/tcp/33246/p2p/12D3KooWRH8eBMhw8c7bucy6pJfy94q4dKpLkF3pmeGohHmemdRu", - "/dns/pso16.rotko.net/tcp/35246/wss/p2p/12D3KooWRH8eBMhw8c7bucy6pJfy94q4dKpLkF3pmeGohHmemdRu", - "/dns/paseo.bootnodes.polkadotters.com/tcp/30538/p2p/12D3KooWPbbFy4TefEGTRF5eTYhq8LEzc4VAHdNUVCbY4nAnhqPP", - "/dns/paseo.bootnodes.polkadotters.com/tcp/30540/wss/p2p/12D3KooWPbbFy4TefEGTRF5eTYhq8LEzc4VAHdNUVCbY4nAnhqPP" - ], - "telemetryEndpoints": [ - [ - "wss://telemetry.polkadot.io/submit/", - 0 - ] + "/dns/boot.gatotech.network/tcp/33400/p2p/12D3KooWEvz5Ygv3MhCUNTVQbUTVhzhvf4KKcNoe5M5YbVLPBeeW", + "/dns/boot.gatotech.network/tcp/35400/wss/p2p/12D3KooWEvz5Ygv3MhCUNTVQbUTVhzhvf4KKcNoe5M5YbVLPBeeW", + "/dns/paseo-bootnode.turboflakes.io/tcp/30630/p2p/12D3KooWMjCN2CrnN71hAdehn6M2iYKeGdGbZ1A3SKhf4hxrgG9e", + "/dns/paseo-bootnode.turboflakes.io/tcp/30730/wss/p2p/12D3KooWMjCN2CrnN71hAdehn6M2iYKeGdGbZ1A3SKhf4hxrgG9e" ], + "telemetryEndpoints": null, "protocolId": "pas", "properties": { "ss58Format": 42, @@ -36,6 +33,12 @@ "0x06de3d8a54d27e44a9d5ce189618f22d4e7b9012096b41c4eb3aaf947f6ea429": "0x0900", "0x06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385": "0x0000300000800000080000000000100000c8000005000000050000000200000002000000000000000000000000005000000010000400000000000000000000000000000000000000000000000000000000000000000000000800000000200000040000000000100000b004000000000000000000001027000080b2e60e80c3c9018096980000000000000000000000000005000000140000000400000001000000000006000000640000000200000019000000000000000200000002000000020000000500000002000000", "0x074b65e262fcd5bd9c785caf7f42e00a4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x08c41974a97dbf15cfbec28365bea2da4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x08c41974a97dbf15cfbec28365bea2da5e0621c4869aa60c02be9adcc98a0d1d": "0x380325fc2095902f5fe394f244bce38b0dc3d631cbc05f0b64d5620a71bbf2514f0f03f045328f504c13dac9ddd9b1186098aee7c46cb8d55289dbbf2433bab7a2623903a0af06322d100056125fac1df39d161089b07ae279505aae8731c4d110a54ad703aec8e80ea0375f8669d6e55d7abb6a3117678d7bb851a1bd100a01e52a4fed9003d46c454f9b620603feef8c3a2a5d7098205b8566500fda0fa0b456d6ded54538030e901c390fa37d101ff25d70594acd2df67b4493ee77a73684f25d39313536d702f4f4d0eccb899bf2d611b56e0afec7c740efba404f8d0e82a545f988c45316c402182879ec92e811e2a8cc117f3cde1f61d3cba0093134cfb1ed17a4ef74915d4a03e843f200e30bc5b951c73a96d968db1c0cd05e357d910fce159fc59c40e9d6e20203d51bba2124f480e3507eb1764fc3019ac7abae8ee215683a285078bda7f51d029338ece1c6bc6439dc4d16bfe33f28c9f0af31626bb8142849742b7a624f68070333022898140662dfea847e3cbfe5e989845ac6766e83472f8b0c650d85e77bae03586dafcdab3d4647d4dc68732a9cab8aa34c00c5edd04e65d9dd44c2a1fd21e2029a1eb2e31dcaf468dbb516f9b620fdd7c3f090d58a88e02b51b25255b2182dd1", + "0x08c41974a97dbf15cfbec28365bea2da8f05bccc2f70ec66a32999c5761156be": "0x0000000000000000", + "0x08c41974a97dbf15cfbec28365bea2daaacf00b9b41fda7a9268821c2a2b3e4c": "0x380325fc2095902f5fe394f244bce38b0dc3d631cbc05f0b64d5620a71bbf2514f0f03f045328f504c13dac9ddd9b1186098aee7c46cb8d55289dbbf2433bab7a2623903a0af06322d100056125fac1df39d161089b07ae279505aae8731c4d110a54ad703aec8e80ea0375f8669d6e55d7abb6a3117678d7bb851a1bd100a01e52a4fed9003d46c454f9b620603feef8c3a2a5d7098205b8566500fda0fa0b456d6ded54538030e901c390fa37d101ff25d70594acd2df67b4493ee77a73684f25d39313536d702f4f4d0eccb899bf2d611b56e0afec7c740efba404f8d0e82a545f988c45316c402182879ec92e811e2a8cc117f3cde1f61d3cba0093134cfb1ed17a4ef74915d4a03e843f200e30bc5b951c73a96d968db1c0cd05e357d910fce159fc59c40e9d6e20203d51bba2124f480e3507eb1764fc3019ac7abae8ee215683a285078bda7f51d029338ece1c6bc6439dc4d16bfe33f28c9f0af31626bb8142849742b7a624f68070333022898140662dfea847e3cbfe5e989845ac6766e83472f8b0c650d85e77bae03586dafcdab3d4647d4dc68732a9cab8aa34c00c5edd04e65d9dd44c2a1fd21e2029a1eb2e31dcaf468dbb516f9b620fdd7c3f090d58a88e02b51b25255b2182dd1", + "0x08c41974a97dbf15cfbec28365bea2dac713b7f8b14e2815d297585d3581e774": "0x0101000000", + "0x08c41974a97dbf15cfbec28365bea2dad47cb8f5328af743ddfb361e7180e7fcbb1bdbcacd6ac9340000000000000000": "0x00000000", "0x0f6738a0ee80c8e74cd2c7417c1e25564e7b9012096b41c4eb3aaf947f6ea429": "0x0100", "0x1405f2411d0af5a7ff397e7c9dc68d194e7b9012096b41c4eb3aaf947f6ea429": "0x0100", "0x1405f2411d0af5a7ff397e7c9dc68d196323ae84c43568be0d1394d5d0d522c4": "0x03000000", @@ -43,45 +46,59 @@ "0x196e027349017067f9eb56e2c4d9ded54e7b9012096b41c4eb3aaf947f6ea429": "0x0000", "0x1a736d37504c2e3fb73dad160c55b2914e7b9012096b41c4eb3aaf947f6ea429": "0x0000", "0x1cb6f36e027abb2091cfb5110ab5087f4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x1cb6f36e027abb2091cfb5110ab5087f5e0621c4869aa60c02be9adcc98a0d1d": "0x10b07d600e3487e2712dcc3879c7b17c9b29cd2243b45f0d9343c591b89cf82a65010000000000000058108e1651614afc6a535c426fc013945e93533faa33819fe4e69423fe3233020100000000000000facb2f987caac6c1290a9784b1efdba78343d39aed805addb12945efbe4440000100000000000000ae240842b74e5dd778972e451558134f434c7a1d8a52bc70519f38054e2455330100000000000000", + "0x1cb6f36e027abb2091cfb5110ab5087f5e0621c4869aa60c02be9adcc98a0d1d": "0x38b07d600e3487e2712dcc3879c7b17c9b29cd2243b45f0d9343c591b89cf82a6501000000000000005440add43e5388a81aef665c9086d386c0be0ce75e4f8a4a3d8168e976ea821f010000000000000074dacbca0cdb5099afef67e622c147614198e669931cebc605629da332632473010000000000000058108e1651614afc6a535c426fc013945e93533faa33819fe4e69423fe323302010000000000000050412bd7d3f1075e8f8e3b682d05ea20b391c287d8c849a0e49a78f568553e690100000000000000c44b3e8efe854419ccd5801a82ada22d39cfccdbcece382304cdfeac81ebe4020100000000000000b2efe7e70daf44b3466c63ccbf4487f42c6a9f6fbb7050b849691e36ce92e3470100000000000000facb2f987caac6c1290a9784b1efdba78343d39aed805addb12945efbe444000010000000000000068a9ec74fa35b3425eaf503dd36294ba8e758e7b8084c4d6bfd547f8c6b5827401000000000000007c8348ec95a0faad6a638ef74864761028c53221bde07e9ff7c81a3f427abf3f0100000000000000ae240842b74e5dd778972e451558134f434c7a1d8a52bc70519f38054e245533010000000000000018bd0f67d77f04f1a92400421813d8927fad109b40a8689254a5f0c8b346857c01000000000000006248d87bd2a640ffe26d6b831735887c24e2076a3a0f3a74f7ae7568c276040801000000000000001ab03b1b3277edfedd24ef3d3359b449b64bd95ed82a04e7f9fbaab7b71dc0150100000000000000", "0x1cb6f36e027abb2091cfb5110ab5087f66e8f035c8adbe7f1547b43c51e6f8a4": "0x00000000", - "0x1cb6f36e027abb2091cfb5110ab5087faacf00b9b41fda7a9268821c2a2b3e4c": "0x10b07d600e3487e2712dcc3879c7b17c9b29cd2243b45f0d9343c591b89cf82a65010000000000000058108e1651614afc6a535c426fc013945e93533faa33819fe4e69423fe3233020100000000000000facb2f987caac6c1290a9784b1efdba78343d39aed805addb12945efbe4440000100000000000000ae240842b74e5dd778972e451558134f434c7a1d8a52bc70519f38054e2455330100000000000000", + "0x1cb6f36e027abb2091cfb5110ab5087faacf00b9b41fda7a9268821c2a2b3e4c": "0x38b07d600e3487e2712dcc3879c7b17c9b29cd2243b45f0d9343c591b89cf82a6501000000000000005440add43e5388a81aef665c9086d386c0be0ce75e4f8a4a3d8168e976ea821f010000000000000074dacbca0cdb5099afef67e622c147614198e669931cebc605629da332632473010000000000000058108e1651614afc6a535c426fc013945e93533faa33819fe4e69423fe323302010000000000000050412bd7d3f1075e8f8e3b682d05ea20b391c287d8c849a0e49a78f568553e690100000000000000c44b3e8efe854419ccd5801a82ada22d39cfccdbcece382304cdfeac81ebe4020100000000000000b2efe7e70daf44b3466c63ccbf4487f42c6a9f6fbb7050b849691e36ce92e3470100000000000000facb2f987caac6c1290a9784b1efdba78343d39aed805addb12945efbe444000010000000000000068a9ec74fa35b3425eaf503dd36294ba8e758e7b8084c4d6bfd547f8c6b5827401000000000000007c8348ec95a0faad6a638ef74864761028c53221bde07e9ff7c81a3f427abf3f0100000000000000ae240842b74e5dd778972e451558134f434c7a1d8a52bc70519f38054e245533010000000000000018bd0f67d77f04f1a92400421813d8927fad109b40a8689254a5f0c8b346857c01000000000000006248d87bd2a640ffe26d6b831735887c24e2076a3a0f3a74f7ae7568c276040801000000000000001ab03b1b3277edfedd24ef3d3359b449b64bd95ed82a04e7f9fbaab7b71dc0150100000000000000", "0x1cb6f36e027abb2091cfb5110ab5087fdc6b171b77304263c292cc3ea5ed31ef": "0x0100000000000000040000000000000002", - "0x2099d7f109d6e535fb000bba623fd4404c014e6bf8b8c2c011e7290b85696bb3": "0x10f89c97bf5b2c07c05c84eebce4ffc7b28766946c03741fd1a71fdae0942e876892cb05c48fc643f057626c669604675c5ad5a836266f260ae7030c6fdc17a54326e2fc857945d01520797a75388c58e710c9fefedd28387af70880f1682be41e763d070989ead31f265b40cc7a0cd29d47799b766d6a7f084e44c82baedfc01e", + "0x2099d7f109d6e535fb000bba623fd4404c014e6bf8b8c2c011e7290b85696bb3": "0x38f89c97bf5b2c07c05c84eebce4ffc7b28766946c03741fd1a71fdae0942e8768cce3ec06252cf7cdad47fe1265047a9bbddb9059ee4bdc6dec83b67249b4a9342ada042fb4bbfd9b6d8c48293ffc4a7722632c843a67e608554c41d06aabc41392cb05c48fc643f057626c669604675c5ad5a836266f260ae7030c6fdc17a5438c15606f4c121376097ff0e96c2a33ea7b024d812b42fe2c741c8b8cee17e63d729053f28155071474b4686323db5f7a318cb3f088b76660cc8ff5e3e11ec32eaa3955187f755708cd6a8104314b962ff5043e36efa3ec5d84df40c58b44222126e2fc857945d01520797a75388c58e710c9fefedd28387af70880f1682be41e64ffc83f4f86cc595e607a00b977eeb6641e02a4e6e556c24ab163aecd7d146c7aeb767131602e6612e607a9eb8e26b4ce4fa4765593d032bc923ce8acadda42763d070989ead31f265b40cc7a0cd29d47799b766d6a7f084e44c82baedfc01e629f9fd0dd7279c7af7470472d1208a13e33239b484974d47cffce4ad4785644047277f22b9ef92a8b99618f4c86c2412f0e3b08a4f965f842775672043d1e259a86227e204a2d003399c2a3b50c2c869c4380c195a014a02f6d2e7048941237", "0x2099d7f109d6e535fb000bba623fd4404e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x2099d7f109d6e535fb000bba623fd4409f99a2ce711f3a31b2fc05604c93f179": "0x10f89c97bf5b2c07c05c84eebce4ffc7b28766946c03741fd1a71fdae0942e876892cb05c48fc643f057626c669604675c5ad5a836266f260ae7030c6fdc17a54326e2fc857945d01520797a75388c58e710c9fefedd28387af70880f1682be41e763d070989ead31f265b40cc7a0cd29d47799b766d6a7f084e44c82baedfc01e", - "0x26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96": "0x00000000070d8aa99f1452f92000", + "0x2099d7f109d6e535fb000bba623fd4409f99a2ce711f3a31b2fc05604c93f179": "0x38f89c97bf5b2c07c05c84eebce4ffc7b28766946c03741fd1a71fdae0942e8768cce3ec06252cf7cdad47fe1265047a9bbddb9059ee4bdc6dec83b67249b4a9342ada042fb4bbfd9b6d8c48293ffc4a7722632c843a67e608554c41d06aabc41392cb05c48fc643f057626c669604675c5ad5a836266f260ae7030c6fdc17a5438c15606f4c121376097ff0e96c2a33ea7b024d812b42fe2c741c8b8cee17e63d729053f28155071474b4686323db5f7a318cb3f088b76660cc8ff5e3e11ec32eaa3955187f755708cd6a8104314b962ff5043e36efa3ec5d84df40c58b44222126e2fc857945d01520797a75388c58e710c9fefedd28387af70880f1682be41e64ffc83f4f86cc595e607a00b977eeb6641e02a4e6e556c24ab163aecd7d146c7aeb767131602e6612e607a9eb8e26b4ce4fa4765593d032bc923ce8acadda42763d070989ead31f265b40cc7a0cd29d47799b766d6a7f084e44c82baedfc01e629f9fd0dd7279c7af7470472d1208a13e33239b484974d47cffce4ad4785644047277f22b9ef92a8b99618f4c86c2412f0e3b08a4f965f842775672043d1e259a86227e204a2d003399c2a3b50c2c869c4380c195a014a02f6d2e7048941237", + "0x26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96": "0x0000000007def964eb114a412100", "0x26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429": "0x0000", "0x26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710": "0x01", "0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc": "0x4545454545454545454545454545454545454545454545454545454545454545", "0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746b4def25cfda6ef3a00000000": "0x4545454545454545454545454545454545454545454545454545454545454545", "0x26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da902d496d20c019d22397accfc42b7635d94c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b10": "0x000000000400000001000000000000000000c16ff28623000000000000000000000000000000000000000000000000000080c6a47e8d0300000000000000000000000000000000000000000000000080", "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da90ffdb9747f7a8bfa200ea2291eea6bdf9492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f": "0x000000000400000001000000000000000000c16ff28623000000000000000000000000000000000000000000000000000080c6a47e8d0300000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da911fcf3e922de10898cb04273301735e65270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c": "0x000000000400000001000000000000000000c16ff28623000000000000000000000000000000000000000000000000000080c6a47e8d0300000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da915fbc5d9b44885a2dce0fbaa3834ba211e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c413": "0x000000000400000001000000000000000000c16ff28623000000000000000000000000000000000000000000000000000080c6a47e8d0300000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9279effc2672354478fb5e3f7e65726b668728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c69": "0x000000000400000001000000000000000000c16ff28623000000000000000000000000000000000000000000000000000080c6a47e8d0300000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da92ffe7c0dd7d3d8d8485c403a33fb7adb6ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a2259627": "0x000000000400000001000000000000000000c16ff28623000000000000000000000000000000000000000000000000000080c6a47e8d0300000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9350ea875b4c0459b3527d475e9825c99d41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d": "0x000000000400000001000000000000000000c16ff28623000000000000000000000000000000000000000000000000000080c6a47e8d0300000000000000000000000000000000000000000000000080", "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94d176c4abc6d2410c43423c2714b909c32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e1152": "0x000000000400000001000000000000000000c16ff28623000000000000000000000000000000000000000000000000000080c6a47e8d0300000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9585bd5ccc1af6cf60c19d791bb091b750efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f76108": "0x000000000400000001000000000000000000c16ff28623000000000000000000000000000000000000000000000000000080c6a47e8d0300000000000000000000000000000000000000000000000080", "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da95ecffd7b6c0f78751baa9d281e0bfa3a6d6f646c70792f74727372790000000000000000000000000000000000000000": "0x0000000000000000010000000000000000e40b54020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da965bb58c29c9825c1f6727fe8c41650ac82c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c": "0x000000000400000001000000000000000000c16ff28623000000000000000000000000000000000000000000000000000080c6a47e8d0300000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da96deaa967a94fa09152be01a253511479d0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327c": "0x000000000400000001000000000000000000c16ff28623000000000000000000000000000000000000000000000000000080c6a47e8d0300000000000000000000000000000000000000000000000080", "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9829f3f4d6d7c991993e0c044ae97410b043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d": "0x000000000400000001000000000000000000c16ff28623000000000000000000000000000000000000000000000000000080c6a47e8d0300000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9a00c6f5358fa04d76ce7cf995bce2eabe21bb02f2a82cb1113ff10693093377672925b23f047624c0cfa7a24a8609841": "0x000000000000000001000000000000000000c16ff28623000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9ba2db252d1b8c64ec51b04d0f50d7d2b9037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af74": "0x000000000400000001000000000000000000c16ff28623000000000000000000000000000000000000000000000000000080c6a47e8d0300000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9dfc40f350cc4563ad9ddff5ad92944278eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964": "0x000000000400000001000000000000000000c16ff28623000000000000000000000000000000000000000000000000000080c6a47e8d0300000000000000000000000000000000000000000000000080", "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9e6fb488a1496189393ed0a95dcf5577e7e939ef17e229e9a29210d95cb0b607e0030d54899c05f791a62d5c6f4557659": "0x00000000000000000100000000000000000064a7b3b6e00d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", - "0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0x02093d0014706173656f", + "0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0xaa183d0014706173656f", "0x2762c81376aaa894b6f64c67e58cc6504e7b9012096b41c4eb3aaf947f6ea429": "0x0000", "0x2aeddc77fe58c98d50bd37f1b90840f94e7b9012096b41c4eb3aaf947f6ea429": "0x0000", "0x2b06af9719ac64d755623cda8ddd9b944e7b9012096b41c4eb3aaf947f6ea429": "0x0100", - "0x2b06af9719ac64d755623cda8ddd9b949f99a2ce711f3a31b2fc05604c93f179": "0x100edf2a41cb81178704560b02c35f5e01a5a97a568ebc10c025ade18b6ab2fa1d74bd654c470ed9b94972c1f997593fab7bdd4d6b85e3cf49401265668142584eca3c2703db1633a27eff681d979967988c3a6752c669fd41f1abde10f3b0544606bd8fd81e50cda2bd67bf6893d921d1aae5cb08409ae43e0bff4d54e1830e58", + "0x2b06af9719ac64d755623cda8ddd9b949f99a2ce711f3a31b2fc05604c93f179": "0x380edf2a41cb81178704560b02c35f5e01a5a97a568ebc10c025ade18b6ab2fa1d98aab6f52520022d011a6eba2dca1c6327edbbcd753c170dcf0e9118b5f0f25bb414aa148096a92a1831309f758f944725653363ccbaeb21817b7df5784b8d4674bd654c470ed9b94972c1f997593fab7bdd4d6b85e3cf49401265668142584e94848b8cf2cbc9e6fd72db8d80676591b5be4d1ec68972ada48cf6fd01228712a8a03d86e6c0dbe180cadfc7994121f462b28f7a8cb1be7e0e354147624be734bef47a9e4b47ed57461e1d28cac7da327a52ebcd64d74080d31deb3ac7a7645eca3c2703db1633a27eff681d979967988c3a6752c669fd41f1abde10f3b0544660fcc9d094d21fe17cfb7426501f50cb3d75c4c9395a3140e0f255443f660d3b30c40adee5476157ef3c2a26e10cab95ec7d54b62dd220738f5a474d5f86874e06bd8fd81e50cda2bd67bf6893d921d1aae5cb08409ae43e0bff4d54e1830e58d28145a7cde195a4c834276730d30f074b212a150e770931ee9470e853e7d2247c03ca47a3201455f8f89defda4aa909cb1d25dd9ddb7fd62a940606f79b56632cd12c731d91441f0114b08d314cd3f9a9f7fd0240d467fe54adefbee4d90762", + "0x2ecf93be7260df120a495bd3855c0e600c98535b82c72faf3c64974094af4643": "0x01000000000000000e00000063e7f4c4028d97f9e69689cea528e2d0155ea2b202be0a42381c642ace2e4cf4", + "0x2ecf93be7260df120a495bd3855c0e604e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x2ecf93be7260df120a495bd3855c0e60c52aa943bf0908860a3eea0fad707cdc": "0x00000000000000000e00000063e7f4c4028d97f9e69689cea528e2d0155ea2b202be0a42381c642ace2e4cf4", "0x2f85f1e1378cb2d7b83adbaf0b5869c24e7b9012096b41c4eb3aaf947f6ea429": "0x0100", - "0x2f85f1e1378cb2d7b83adbaf0b5869c298ef7dc060436e4ed803af07632b89b65153cb1f00942ff401000000": "0xcee7559d1a7431ad9a589c49d42b6e5da57d8208d290516347b21415449fbf4c04000000", - "0x2f85f1e1378cb2d7b83adbaf0b5869c298ef7dc060436e4ed803af07632b89b6b4def25cfda6ef3a00000000": "0xcee7559d1a7431ad9a589c49d42b6e5da57d8208d290516347b21415449fbf4c04000000", + "0x2f85f1e1378cb2d7b83adbaf0b5869c298ef7dc060436e4ed803af07632b89b65153cb1f00942ff401000000": "0xe68919a7ceff5bcca24e5051b9ab34b9c9f9e74a925cde4c49570cfed7bf14180e000000", + "0x2f85f1e1378cb2d7b83adbaf0b5869c298ef7dc060436e4ed803af07632b89b6b4def25cfda6ef3a00000000": "0xe68919a7ceff5bcca24e5051b9ab34b9c9f9e74a925cde4c49570cfed7bf14180e000000", "0x2f85f1e1378cb2d7b83adbaf0b5869c2ff3ae12770bea2e48d9bde7385e7a25f": "0x0000000002000000", "0x31a3a2ce3603138b8b352e8f192ca55a4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x3a636f6465": "0x52bc537646db8e0528b52ffd00580c6105dee2866016521030cf2a1d73eebb153057df9bb472cc0a860361c473d10e8f9f75d9071693fda90415453adee41bf641bf24fc4306beefa61e5e18c0cbb36d9bec46d011d098dc9c6d2bd360511bf97b6f42f6de5ba6245368194d145f153c9d801bc50970a58c7bc312c497e3b3cbd8a80c636c54ca9e9d7d081bcd672c609e1dc646fceccb479356fa3cfb8a0bd032c606ed2b7128347d00b7c8b83ea38c7bb361fdf8e5d73f36da9badccaf876c348f9656c27e07006ed2387d7d5be0b2d1dcf9ebe06bd968d9cbefd7291b4d5f0727cf02b488b141fbe05c911de470f76601596460d97e536f9fdea2925977de2c200b1896edb337097638c9f92cb2af48ab12afa8844ef100b567259e7380fb1f1b95ecedeb3c497618d9277355e2da9c4bc0e9fb53fab34ff201e3cd66fb923e3b65a375f66ffaf7f5d1f2ac1c7f7a397ef93dbbff0aa9cd3942b7cf3979b62bf1ec7676eaddddd37b32fbf75c7b98b053e7599765e292e95c4bf6e94aacc4fbd395c97f85d478ce2ec0fd29fdd9c1cd600417695c9695dfb3b7afa8a47d8a1a9860b3d9b07c3bc8e1b2d1f492fefab251fbfa8acb3276256e92b28cfd682cc7679f4e9d1d84b1d13e3b38c3918d9665ebec30369acf1e63a376f61595b42bb11253f24a9087aafdac3d4cbe9ffefdac3d4ca6539f4e6bd4fcaecbb292fefa8a4a662de74f576225de1fae4cfe2ba4d6736e01eeef4f393e3bf8b15139bd7d9d27c90ee3f4327cf6b27d59b60e36f9b16c9d689cdebebe6207d399ba7e2c5ba72c5b57627092fce1263dcddb5fe97e3abbb8494fd3f64e03f8e9ec2087bb49d3cbf665d9fac746e5fcf675b0c98f65eb4363fbfa8a1b5096ad77fd58b6aec4208793a41f6ed2d3cc7a27efafe0fc747671939ea6ed9d06f057c29fce6eb3494fd3f64e03f82bdd4f677f6dd2d3b4bdd3007e3a3bd8e124fbc54d7a9ab6771ac05fe97e3a7bb8494f13cd5f097f3abbcd263d4ddb3b0de0a7b3afd801b5d97eba124f71c968fbe9211bedb3afb864da7eba122bb1122bf192cbb2f5fde1ca34fe0aa9f1e435c06570195c24e3f4f56d21a9833fd0c20aae2431246101490a90e881040f2470202101923790c481e40e2423409207123248be404205121790d480e405243224dd92c4400203921890cc80848624169074414285644b520b48b824a5901443920992ea484241d214198c49a222e904495924e1911446d218495e248191b405922c495720d182448524aca42e92ca40b242920792be482a419215495524199184449298a41990b0904443929924aa0cd264c044064a64f04506502449914112495d3258228330327022898e0c8e48d222894c1216495c2495c9e089242d196065104712144944240991810892de487223294b0623c8c08da4393200230331322823292be90348c020b1010996a42592a2487222498e0cbc4842930482a438924490f444120990a48074061218485f20758184855406e90a242a9064404a026909241a9036808404120f483d206900290c120e483e20fd8054051219242b907440ba42ca01e906242590c0208d412a02e909a40e20058104051211483320d940d4a5888ea23a8a4a506482a2111499513444911045411475a00888220e148529faa1c887a20d14f550c44351154556149129a2a2c889a2268aa62852a3288da2334568149d51d4451117455b1469519445111645658aae28f240511145628a88a041143151b444d19822258a922842a2e88822238acc1495514446d118453814dd50344351068a5e28a2a1a8aaa84b119722ab22188a64209283680ea23a884c400407d11b4423208a830804446a88ec204201d10988c220fa82080ca232888e2082820809a214105d41f4049114445310dd88b420c261480d1116a21486483024c7501b43730c610d5d31c4c51013434a0c093164c5d00d43381c61e3481e432c0cb97024cd912b8eec71248b23681c01c191368e9c397282232138f2c611111c71636885237a1cd1e24899211586aa86b80c6519a21ad232b4e5481947d63862e6089a2363fc8b913b8ce0c16e7811302af80c2328e037a606aa1e312b8c9461640c223378822022c3c80e4379f8e0e1a30696858d169b148aa4a0481945ee2862a6089a221ff02b86ae8672e830806cd0690156850c861f2e300b48e420d246921a4e44d211b132404b00c901c80d449c00028648134498008283634164892176780d18b041240c110e10010288ed87123213f8d8414409227a08b11141027606d01940b4ec906007053c48ecdcc1c3028f179e1676460084ca070f46acd81141bfc10326280515580d3511c487236414c962e78c991b3c43f86061288a9c2c76e2086a8327892010f06c095a63c7044167621ce0e11234c69013b33678c6047921a3baa08bec043e2008a2da39418e16413610a4875816205d7cd6e460c9628871d9b12308882258fca8198262f6c60f167cf6f08165678d217a046de191418786217bc4b0c0000418a0c1400d0cceec7c609666e7cc4c04332966b71919b3286669ccceccd698a9319b022803332b6664664c245161162676c5ec87990fb30de874a958b013c84a20cb92c531244bf682cc4aa605680fa03c80f00052038402a03a804a0094054402a03880e0004a032402a03580d820aa01080d901a41ee08a207ac07d80678b400c221e601201d6262807278cde12900ed102b02e80bd00d312378b6e0e102e80a0808202284c4003484101980c408a101a80821330009212403401e000a42480d42be008501a2828f1bf58c111788b04044059e1c76e0a868f01441c4cb8f16580344b220a245055a783ac033034f161e2d414a50dd702d5504158e223b764240c4852174d430aa173b20e0a1e25921c81e3a566e457d23c8098a80112405414c00c44310140451e359bc0aa88620790081098287db7ccb8b04be826c0659065c059812b024dc05242db80c0e83bf50a4825bf938011ba248999d3d865ad89183c8871f2ffc8041e78b4e0c415408d2a582121cf1020916500f3fac2af85241063823d80b5808182b698f24362ac0c2360021118b0289890c52907303c2e293029f3b6cb010e1425b00d20050123c63141183a70b1e2f7474a8800b101a3f9a187a02e88d1c2980eef8a103e80c902c312d4026c899c28605a035b0334072bc6e365b7eec006407902d406efc946036021b1580da8099817551d7f8e4f183099819156c81810113434808848000e804b00f00d15141085e3bc0d0009aa302157456001ac18e183b5fc0d6f8b104d00772b6105205a407500a8042b003c68b8a236600e1a25326b66516c76b0a205874b0289a63c78c970f455b606e106591404c892261d4361c4b4d03a4444f0e31276250c49e804d019322c604511eb1266249502086dc51cd50332ea60787980fb10d101902c9cc10131c7161878cd80b31ab1d343c61743cc0a343ab21f24264851f46042902c606cc0e58160f0f3f74f82103112b2330f8e861c46a670e2010f0882172044f0a15500d29814e0674b87029c0c8806d3184044350e06476bcd84183c8061d1ca89620297484f0598347033fae606d0cbdf092029606ac8c5e0366056c0c2234302e605a201d11ebc1081a447e9825012443912e5e560461e20799fa058c0ae6015811303130236044c090801d01fb813f000b0303a247075810b00e04b10396c34b8e23627894b0e9b21306ec0a1d1988ec9113460e183d6062591879814815912d33387862e0d940cfd52b8ea23b869c00830c14b9721bd8082433780c03c11dd019036803f388514d9035ce05690c6f82a80c4c8e1e0d38d578c4ab8e318908bc4af0caeab9e145c75016af375e6986d431448df3e04038073c8cffe03ef80686ccb183c74e0a8e8041e405225d76d8e0b94107cc113c8edc6124061e23a612445a401222481d3c553c30341c1d87cd15938b5a066b51e48b222d3644f834e1c3c410962367bc7ae079c1cbd850f1a86093e5081642b4bc7878fda053354405c3a14386102ebc42067a50178e8c11a44383f10389203c10ed4124890a7ca86420f9c253032c052dc705b62369c04af02309202b34968f1d8e8461b3820f1d6061e86800481e485208f940520e5c065115dd848f1e92e0481a41066fbca2c8a0043c030c0d9b119265a70c215886c8bcc8c0b082b0c0d498d1f0da001d434817d81c47d604d921880e41ae74b6e8500d65402705242d8450250d61e4899d12e86881e9b193467f61e345074b911a581a1e2ba22f3a2c2435e155ecd0314443901b908080e161840c9baa991c49587e4620c44b521a19c8c15b6460068897231e602f3f70c0f2c879024855066b9a8b1c366cb6b0e9c2860b1b2f86be04a9222243640d521442561092c2d014478480ad11a202ec8e0bb2f01c21048d8e0b3c38086101884c8fa0282b033a3280e38214605ed0333a579c86c7079d1d605f004981870347be388265c3250332807020a98d234820c1218331846c81c501a48566020647121a1760493a936446100f00d162a80e98088e14c12a00a53154050c043013d02cca048d82de681afa049582be419da070d026e81440476010020cdaa078d03ba81a226390380044066ac7eccb6c06581d3b583a30f06021b282280b1d1b88b020520791087868d0f142f401d90880c000c40a880b4062a8573b667466808d0046079119a2338c98b1b366678c1d35746ed05141e7859d36783c60a4059d1a602480a9e1c9804e0e3b593a5976f480bd0143818e6dc83604c390d5900c47d43862c42bcc11318e1c01e485a12d906e455440588061c1d3a5c84bd10a394d10e901db83a707242f606580ec8081160cb660409583821c353976f8bce133021f38646a6478c8eef8f1c30f0efc0853ada865ea1545c61461a2c812332266625e59bcb6786911c48b205f04c19add007361680898158c0bacea05c64b8c571841e0f871c58f323f6ef891c30f1c8a1051a488226288a041240d22678cc061240e2323a8515429ea4d670f1f369d354134047d09cac08d0c3734dccc60b3e685e565cb39d37be4a4a12387ce1c3a24c8d123674dce1e152451c1980a94a82c54176a0bb3aa990ab32e168cc002392c88a382ab0a76a840070bd4e01258b00699d52120e968326ccab031c3c6cc0f296ceab039818d0980d001c404404a504110231863183e6af0a1011f365430f586aa811baa1b2e375b76f2e0b1edd4c1e302cfd58e1b3b6a786ce0f9c243c44e9a9d37787ee0118267071e20883a7024054331f416445bd01b280e3487a435b48a72e93c908618ba63a8049da6dd681310ad4004a6c7683188f020baa39de824faaa8968311da677e80eb412cd43ebd041b407fa4b83691c7a8846a26fe81fda87d64017d1363410cd81eea18fe81a7a4ce7d01b68235a88211410adc174701ccc06b7c122603518048c86d7e010b01943763019ae6286e129580abe71147c048be130ec0373006907fe8193183a016f807be01a9806fe326402de81abb80bf3403b8054c6cc626a31b7984ccc25a6969965a630b14c9b950640e083f9030833070750214184a50a78b00005342140070940c0010cc0c1061a28a14d27e6182345478c844600d500e7effca1438b7b090a4a059c5881b224c5891370760854969c38710505ed7421b4c345531394284d4d5008b08594a811a82c3569b14b4b2238a912e5244aca0853962c30dbc962a19aa640895a0ac1c9d2920817ec60b15544a032c5c9094f4b2538399962e5a3a82c9170029426be536697a250a942c509942854aa2420ca03d9b922842a51964208b263c5429db0c40475c2121306903b55404d29c0094fee9029daa1e267678a3561890ace8e147b5b2951aa5859ead989629f4a18618a0854aa447132c5ca2f55000a4d67078a0b769e40da71624398e2246a09eaa984283b3b4d2cd4d294a8294f55a4449500c5c9084ea65879285642a002e569830a76985828a8a526203b4be4ec8c5162a3a89450258a1311a02c35e9ec24b14f24904002025e3b4858b073c486b04465842950544a7012a5ca952925382d19ed18b1514b504e3cb05053a04e106169a9024ea658f91344585aa2f9d82962a3a0aa343979aa6265e949cc8a50a5ca93152756a648817a5aa262812a4e4e586222778858a8252950509aa09c84b034a5c98a1528544a08b233c4422d459560056a4a083e768458295050a4d49d2076e9c98a93a5a72925382d3d398112e18a15213b1dd8282a4b242c4541898212e18a15d90e100bb51455e58a132754aaf8ec70604fa8809330504d4b54a8409112c58915129ea43809814a09552a4065ca0f5154aa4471e24442083e2c1409509ea05871f25465035b45049e9d1e162a8acad295251e76290a4a085342a00225ca909d1d7629842a5180ece8b04f5544805a82ba5aa8a812ac44955005682707124a80828262c10e0e0b250a4a084ea8549912c25214d414a8a7252b17ecdcb0504b4f55a23839216a4ad3940a40699a02e50a14df01b350564aa8f23482930a7634b0504f55a2a0aa7000e5094a93d88e0d6b812956fe6989e9a98a033a20776ad8a5a512964a508007212c8d3002140f00b0f365a1445529c1c90914152753acfc0854a63041896280cf4e06b64a94131a76290a15284d502ae0a44a9413a8282a53aafcecccb050213c41b1c0d2939311a84c0981ca92152753ac3c5453952a4da85499120585ca1412aa24a0eec8b0504c5196a4448961a1a2a82c3d2d49a132c57760a03245849e9d1736ca14282a539ea24c5872724293152b509c3c2d85d034a5041a53942a4d349f1dab85e2d97161a138f1d96961497002250a4a0850a2961070b3c3c205a6344199123585ca149d1d2fcb14a54a53059c2c45951065c984259c9d15f6a90a01c29d4b4d15801245a504119c4445597a9a120295294e9cec2c81c9e081a105cd6f0ddc9bcdf6b3d63b1db806b8c6b4323dfaf578cfe75f4fcff77ddfd7bbcc54ecee6e6ef7833bca4cc7edb6b9ebe6eeecdeaeebe672efecbaddae97776eb7bbdd757f1dedba6e7767d7f4ebbaedeeba053d8f76f7d72d7acdcc226fd7f2e8f2ccf5a80f6e71e734479b03993bce6bdeed3aee9a365dba1d04887437a9ef8f8e865e2fb38db74bbb026f9b7638bc61d7d1deae9b9b2eb7d7f570d731d38e763f28bda0a3dd32dd6daec3deee7e703fa0bbfb477773cefd3ceffbe852dae0521b1bda607b1ef53aca0c720882d7dc0ec0a09b3fe80e3b6e224cbd6ec0fa6ec774b9bbee6370bfa58d036eb75e8c7a33c85c0f3aee2006f402767977bbf0dbddde95b1b79333bbeeb8fbb883bac9dbcddd75d3dd21ddfd7a756f0f69cabdb3e3791d8436a5ed75b7473dcff33c4a3da6de647675dd1ed80a601d1d9dd993276dd2ed76c8b3bbfb075b30f67a1e0540f7a4cd1dcc2e01ddbb949bbfba4166d760d39b9b1b6646c0d7cd9383508f7976b72165a6947aaffd983deea9d3cb71dddcea5e6e77b6ba5bdbda566bb7d56a6df74d77377bbbbddddcd2b6e9eeedb6bbebf0e38e59c0b46da82732337f7c00cacc5dd73177dc0c8add819dc71de8713779765de7791ef5769b72bd74297b9477bd8fbb9be93237ef2ea5bdbb5e874cbaebe69cbbe16800ee70c9641a7608807e31dd6eca1caba0b7db6e829cd7bddb2d07dd9eb7dd8b7bceee39a74777b71bc4d9607976cf9d5f476d6c30605148a7016d9edd3173b7bdaed9ec66dd4a9a520ff428a5cccddc71b7bbdd36dd5eda5d1736c7ade59876d3d975ddecb83b2cc0d72debbd809b3673d3a64d9979f2f6f77dccccfb639b0094f9a7797bb7bbebfd68f7c7d4a31defecc066baa1b7bcdccdbccdfdb3db4dd7029ad7b4bbb7db66973d5e5e66ba5cd7cb2d33c37876bb777a3c419edbdb8cd371b7ccb3bdee9a32e5ee3aef6bf6b6692fb8ddafed9e61d38f6977b737bb67f786e118766c0cc39f7d333b3a2773f7722c0c976d7ab9576776d7e20de9584105aff0d51c762f2b51a69e3752cf1b80e779d4f37e3c01785e00c6eeee26a594b97bf2ecbaaeebddee769777777227e99682fbf5ecd9755df7c74cb9bb9b524abb6753eee56e4ab79b6ed751daccb4b997f2d2edb6dbaeeb3adad16ebadb743bcfe3a6db81dbddf6ce9ddd766f37a5db75dfb7dd323377d36ebba674b767ef5266ee8984c7eee6e6eeddedee66cadd761d737777ddcdccdd2575403c8f99bbeef3beae1b27032024203814c81110103ae7ecbe0fa7ebbaafeb7c187545f3fb70e6c7f39b389fd77536ccdc5dd775dd31cfc95dd75fd7ed761c534a41ca94f276dccddddd5cd3afe3ee761b491d4850d03acb273c55216189848ec8088809552c1055011394285196988c8a8e38ec889111a84c910205458a1385b0f4b414c25315274645479c1c596282d25401274b539ea23018ba801c425e701342d31429519c443595004584a51066478e8c30058ad4396189c94994294d1528c18aecc90228a8a5272b24548972e4da234b57aa44597a7202052a84284b4e8c3019151db11265096a881011a63c2d5d1152a3a03c2d51591ac14906468a8a8e84b0e4a44a9495139ea258d06a5abab2d4e4c404282404798d50a5c9c90854a68c304295a69d1b139642a032c52709bb46969e448852a5a9098a0f8f1512a044412d913025ca7d2a5002d4acb5b404e584842a215081f2545f50322332a110a84071b2f404c50a095588769aa044a9d28441ab4a149410a63441b9e2046a8a132a53a0488922820855842c9130258a4a094f35074984a81280905002159f1c1396a43889a232e5c98a93285053487882120575c10dd48ece1ea952e58987290a940a34355579c2a00894a5279e1396989c4499b044a5029fa8a5117660505150534c58f2e1d608952a53a2a24081a202e529ca49d4141248a82223f788095344587ab252739ea02c3545e9b94265a96fd688132a55a6403d2d5d71120295252b56a038591a01ca539528282751262cf95ca1b2d4422f23786b53535fd8a235afc64d4d4df554ed7b529bae27b5393535353555eb5a2d3ea9cd5aeb496dd65e5353cdfd646a4ecda9a9a9599b9aea273b35e5d5a6f8c94e4d6d6d6a0aac7d53535353357e32356bb57eb2b5ee496d4e4d4d4dd5b82753739fec546d3ea9cda9f964a7e693dadca9297eb2b5a9a95aadd675cd7b529b5353dd93a959abf193dadc27b559abd5bac63da9cdadd1275babf193add56afda4366bf3c9d6e69308742cccdd9d244041d9ffb573f77b03c2853a8462335675e6d97d7ef888612c833d692465dd9f6b902fc31840104690fbbdf110c434c2889ead06a8fd3a0a41ac2f4d88ad1b049c43eb6bb34628bde0cbdf5b5598dda452a8c695b496534fbd6c216043e04b7ece9194e4ba882cda576ddb8515f5b2f57d81af08810b5e68827174e4853aa5e4c4f2eb3d9daf96aa8ff679cb3db2eaa379be6439e501db689fb7c82d4834ef0a7dce7b96ccabe7b8aee5544f579b78beefc148fbbaae3abd9eab3f7cb56f57ea69fbcf23bbc631b77004c60c25ab288d7a931e8c34eabbddd5e9f53f504a6ecf9679de50830d1a9845c01cd96066a4db1ad83da37b3be02bf369fb92eb34bf7d7783d6a715b8208cd3cb9065000041a8f9dcaa4cd35b3498f9929fe606711ef5bdd3ae79d057d4207497cb57e4601fac25c43e2af6b3ba949a5be4ea403df4341f7acbc10e995c97b79804b99039f4292e6979286ee039e89304bd45864e45269f4f9f753768965c5b0e9225fff4d695ef9d7a0f5b19359f7d7aad9b3c02ead3a903e069b8facebb090833c4d1b1eee9dc7f644fa4c89086ab00481c1c37e79c9d37072108b12d7300369acfb9101bed6d86239e3eb765ce3ce7cb46b12f978de7ba0eac3cfb4e8fea989cffc3464e73cdd370924feb511d1327cfdeb1ef74aebb43a612a6962b9ca206dd9e831e5962e03b974281bf29d680bd5bb56467fa6ad9be5e765d272ee9dac3a444e1d9f7d9d99d8d986c07273b93d95526d339c6469e73eee3917bab0a33c26e32f4f01dc975cee9b1c71ebfe29a1db2de9173cdaf68db21cbb65f710963e1662b09b04cf2fb72d1d7616ce4f2f5181b81beeee33f6cf4f9ba8c8d3aafbd8b14fd236b20e8025d8943b2e7f3968b6c3c755086a7ee9241cb536f8901eedc61dc5b0c62fc4e1dc6bdc540e6a98b0eb6c28ea40e82b5d99125e761ab4572e00c39703f045fe4d256049da98789e79c7b9ec8843ae89e8dc7e4f33c1b0ff4cfc196cbf75baeaac1e72d6f3171deaaa17fe4fcd614357079cb257640dd5599382fa943d5be734eec00aaf6a133751d50f76ad979585bdc82ae70c5b096521f7a4796f43b7f91cd5b768d4c9a96976fd935d2f9a4297548baa87764fb8b5c1ae80a5fe4d25cfd658d746a26adca243a75d1575492a48651f476256691095d027a574bd1c1da03bae79cafc884ba587bc0cae4f3ae235dcef4799fc7e4f3be562d3b071d6472959d8731d4f1d441073904c932f49e96ef83de913dadaa01e7a083b59cdff93ed8a18b0cbd9c1f82de72b0ee0695a0b7b7ea06952d77b0962eef48d0959a23e777f35de47e6b7e5712fd9649be7022612cbf6e238434356b2e0e7788c14b3bf10443d59cd3bbae73cfeb3acfeb9cdd878d9ee8773ee795cd66c3429bbe22f58e7cfa9ea3cfb9127724577dba39e3b8e029ef06754e7d929e7764399dbd450da67bb59c5f0f93e99e4ff7ea74d74f70c10e39707b929465dcb1776207ae5f776d123b153b00ab6b83d8f3c869fb8e2cbf67c6f2ec5c1d2f18590a707219a783e0ce0dc8f0d329599f9be064f100a133393d24997803f6c9f386716f2ff4f02ecfe35d1f3a087638c50d3e6fb98b2c5bce04bacbe5ec20933d4ba8cdf6a2d3ef5fd199e417bd90ee06bd9c73266dfc45964c450dd86d6a3959d4807d74a51ec91e26ec36ce6e53c91e26ae67773d579e0d6a6feca3a5b533f9721b4fecc0f5a1f36c523b2776d0b341ed61e5b1711b72da7ec50da6ed871b57e2b18f6eeaf6acfdd53913bbcb4b57e203d4a270b99418a422074a3e450da6b333bb12b7b884ddc5e4daa0767083daf6bb413d8191dab0bce8ed600b14ebcb77835a2fb76991653fe836a04d0b74917cb27985aec4afd06d4031f41618d6dd21606db9cb79fa32d9dd7875645957eb731566c3de0ce0e432d2dfdb0b2c4c2e23f77b7ba16a37c80246b2bf5e6c48c24c7691a2bb77d6dd5a9af0cb24543bc72b88a228860eba288aa2e8fb23e60182e0b72414088220e8fb03a2a0d56ab53ef7bcd56ab55abe3fad2ccff3be25a13ccff3e000976476708acc5196713ebf0de27c4928ce3976cee9b7496c80dbda2425ed4b042ed3483d075fedddddddbddd9d83b30357a4b5ac951fe934eecd2acd73ae84761db941e73977e0f57ad9b8e8a183fe7abd5e2f108020e8390882206806dcdd395fdc202fdc20cf27e93476ce95df7bee79b849ec9e8b9bb4ef39935e17e0f6b20b8157b87772fa4ee3157e27fa3e0b0b01dc1d7089e71e75ef5b9d7faec4b4e59f77947e5d0bf4c82bf3297965fef7b9c7be41fb55a6cf3ba708f8bc6bd5b2f62da7dfe74a4dc992fa6c39f8cd39a97f73cee91f65ffe69cff718b3ffed827fb6b9deca14cf650a724074abf3b8486d3f3dc69ae798a0aad2c7962801db2817b64f9391375cf41ea5d9f9c36cb66fb289cffbc3b2afcaf032bdf722576914f4e0378de20ea51ddbbf8a9b7c827974775fff98a4c9c7ccb837ccb5da4d3007e6e10a5adba3b848a1a704e7d8a4aba5ad6be734a7e1f39bd9cbfce91253b7da2f5abb56f7e599a739023f7a7d80e4e7172e4244303fbab65edbf59b2b7e779ee797375925a6f72bfa7934e3d3d77f2f11cfcb8f428cb3cd2f3eab2ecab5ed764d97e65fc266ac3f2e5e74e5e1e58d6fc95ef3f9f64d962a2ce0eba573f32f4bcfc3ecfcbcf9d3e2d2960f9a72bdd4fbfe23d54ed3d9fa212cf95da233bffca287e9777aeea34f378da22a3f8a9d79e25f3f6ec2c2a61efc8597ade399357f8f38ecbce9dbca747bab73e4926f69dd5239bcbf99f7fb59cbeeef992fe12aaf61a2c7d5a99984cefcab4cedb9a1ed5087a80564616adb0bea44f9f8c564626e98759efe4fd151cf135c34d9acefde2952e44f357429be9ec2c76406db69f3ec525a3eda7ed270ac0d792ce3befa6ebf3f5cf57d4a0e5dfe822a7831d79657e39bfe593bc32bfd50279e732b599d537a8235b95e9737064a3ce435f9fa26b3eb8a292ed6e4696b95c48c9ac65ed27d3e7a0cb376986a46fd0fac8464223cbf6fb8ec9e760a52c7b39e7d45b3ec5b9656cafadea13fcc8f2f39683e08aae5ad6dee5932ce7f4962bf524cbe9721074b5beefa7b748afdb21ec1cdd21ec2d5f5103fab34536ef10f6d200b5287eee107603d4a2f8dd21ec2da7fef66d91936a6c1fbff73d32e8d7bf197e64c9f9748fec99d5697e577dc8d86c0f80f76687066caba7de646d64e2fc822fb93abdb06cbf1d9c5ed8689ffad2263d09fd0febb515814fdfad5dd5b22588d679550e6d3af5e9858d604f9d270998b16cfae98565d485be847db96d2860695a3a9faec4526339bd3cf572db78ea52eb63cf4e0046891c941083c666a3754e6993b4d10eb4c0430a3b3c41d3b2258836bd2a87b6ae650bd33caf12006d7a4756098026258407d3a59af48cfac47aea9d4b09e181e75d9552ea1975af4a09e141e7b34a79cfa87755687b567e5feeed36bd5cac4501172c7e90e30c203e00863ff524398c4babcdb0c51338e02085190f9880b6b4f552c803b7d968d30b1b5df0d4f78756a669f52b648a6bccf40a9cea59cfd6570714aabdd6459dd2a96f9f21785ab9b2a3ee552a5d2d3b6fea22b29eab9d97d4a777de24f515996c172e7c577ff840cecba92f39b2e4bca906e63d2adb85d5735e5ee03baf5259369eeba80440cbedb98a15068a22654c514b13ac6eeff37bb3eae1410e39f207a9f5a9d79a356bc0d05a4ebd66cdff6003c2c20664b87ab2e08a8832b6282bcbc6ff602b52c614b62b01d07233c1b65d58d1d6cb0b3c97c2b2416b55dbb2415b2fa59eabe5f4de22e5de5a38f351f37fb0f950a3882c6fd86cb4ad52eb535470d0c10c2c79d86cb4afdab4d86cb4f5921ad15a5a59a7643b8b1f1429438a351fdc7c400d1ff6c8b2660d0df63cc5358e3b215a00f3e36c41869f9361d8da519e544d37697f9d525189182c6cd1751cc7712255d2cc5280ebdf6dd29c62c7227b3e2cf37ebd4d9abf2dce1a58f0f21ef3c2c6b7fbfc7c835d4829d7715d8b012f70c208ae061e569bb3085c2f61640fc1a694e47c4e8fe33a6ff7388e033bd287659cb3386be09057e09c2a719a6b9e7a577d58c6d5a5949c4f99c300a77f9b346bd5190f6359fbb749ed4abe4c926ed0725d967d3de711ebdf2671be0e723dfbf3eebc3b6f27fabaf6eebcbb9df36159e7208794dce794300dd49598a7d8790ff5f9fc3d7486ce39affab0ace3c8f91fc701b2d34d6272c2403769d618de7d36c869aee10df69de61a6e83b6c6737601d739a79bd4f93ab74993146219e7c5ea87b08cf3157b452b43627de4da24dfa0cf3997b1d1c8b2afe59cbbc8e5d9e7de47df8faf8f603cfb9cf38de37f6cd27cce3b1f967dde2c74a47fdebe82998fb1ec9be2e73d9ef7f3f778d569ae79cff7e6a5eaf7e6658587b1ecf3ce897eabfab0ecf3486e83d657a41bb4aec41d397f6ad6386e21c0f9203845252e0f9dba478abe9b043ae720486a50fb1535f0983c5f0fc9d2f3e9e06ca7bf372f5a9e6e90a801c92e929eb7c8f9ecdfe722f9798b9ceb4afc91e5fcade5e7eb20871fc9a0cfcf9518ecf02339ace5fcd0c1d057dc20741748c38f645f7183d04104881ed6f2fbb0e5537432414b0a586cef545a20057aac79a8c50a23830abf0e55fbad1b8221b92f92a5090f2240aca5090f7ab8b59cbf1e3a276ae07a77b952af92b032b93470f95627a92ffb5d0f56a6cfd94596df8a4cd83fa7b9e65baed44adcda27c91a382915e04619a997b1e7bed1d9887322ce63679e731f36e2e7849e8b3de7231bb1730e63a3768ee37c7fb8cab4372de003c61c70bb9b906514d6848d4a1fe3f3e58a419d73efe3fcbdce91d8a88c29b151f971c046e5f8848d3c4fc246b1f71c84156478cf25c046f4bd5e33eff520bde7cb463d5fee16ef71aec43e20939e18138cf79c3f86f59e83cb73dbc669aef91dd9a8dd73181b51f7fc63a3e99e7bbe3f5e65daac0e036ed3b8372b355f7e7be301ccb7efb33777393e7526191ba9702b63319f76dae106bb36e0e432d27dc0e8036cdf9f72b1c874d338f62cc444cfced3440b150a6a506159515da1061bb4ed19d57fe18118b64873871d52d0bebee16af94da4679f4e5d09a94b1ccf9ea4007c3469a5cfceb3fbb011e75cc315670d7f6f5dce3cad3096cdc5ea17c02dd2612cbf9fce1edba4308f67874d2e2365d9baefcd17fbf671ccb77f1178210d4f1f4626e2f7964315cf39fcde6ef0e165bf373064bc83935c129525ebcb9a13dd9725bc60c5afbfa60f634ff17bab41869f647e6f19c0fa21bf371ad44c7103171768dee9c9af6fe0cac2e19da66cbe8c02811ab11cbe8c0a930308822fa3560001f725941948008009ac2fa1c660fd2ef96c367109b5ed9a5f27e7832fffe5198278ae8c9f0ebe9ce6530729c939b8e206b496738a4cdab9963d8c79eaec2c6a407dba5233b9cf9193ec61c295f1d4b932be84aa3d75ce9974da356bd670edd9b931e5b8b71dc03cf9e4831c3219e439922be3a7b8813f3b25afe8cc1ac54cfcd9959809c9c44e1d64b29ccf398b1bcc35ef34d7705d7b964c6fdf607ad728706f3c1cf151fc5c2dd9afcc6faf7d2bb1125392fc26c9494681bf5ee326ab017748f3ae9f0eb26b93925c48761629bf3deae66c939476c06383f6cb45a2b4839a2db2cfb59c3ec50ec09fb59cfa2bfc233ccd9fde82b946300c3ff10ab5d9db0e4ebcd3ebb549abc7b77713c9ee97fc65f7ed200d7793a6cdc9381d9c220546066717cc64a6a8c489da6c8b868ee1ce746cec4432d39cf9759eae8984da7e1df4c21635d833def77d5fc7dfd7f3fb3e4e6633bd5b63f303f87beb02e6613ee0f6d19679a18938de00428a321aa0ad7f7d54ab41032eac81822c2cde9081b6be5528a4dc01dda0aba57fe7df76379465b58cea9feef2918d40f740afd5aa65cb5ddef23c6f0fd9a8e5eda047ce075b64e853dce0c7539685b50cdde51eb91f9251fd2d0727ef6c1b8fdc07c97d578bfc61a3dda0d2e7a7b7c7c69fb5ec9cf376b0e7ecc8fd014cffc828ee61cf5d2d4df8ce972cbf16b7bb01a9b8df4dc8326759bbe73e2c6b5f5189a7c44acd4ec972bed35cb366cd9a2f6bbfde9151fdeb93fc58c63e45255bb93ab28c7df4f961a3fd181bf9b7cb36a9bfdddf35391ec0f5fd29a7edd941b23632b5ef97d3c6bfb716ccfc7c32eead85323f6d4b2696df5a4edb1f2dc8e18a4aa82f7985fe3a25978cbfde6459fbf6dda4927acf12d7d3eaf4faf52de385bedc355fb6f3fe92cbb225a711e3f4f9cb45eb537472a7f1bbfa4c9b1760834d82308a0f18a9735d64789e5f15e66869ec1c0963d92c633f7d45109ece2870195c06c10d6bcdb322b853c6bd557d79eef7c665ccef0d98495d8969fdaa05402663cb5ee064c0b8a2016a4f69adcd59802540260470d25e96979dc375160f507ba6ad4e53bf5eb24f28b880f9bd6dc9836ec17a0a82533c40ed976525fdda77156c5109c7aec4e00c3bce49bac1fcce7b3498df7957bf9fce91f3f787f6e41e4026d399a697ed3cc92438ccb91a2cd2183e7df0c5f563597b3be5ba0dd8d9a84703f6f6ee7c72ced44ebdebfc6323eec2576225aecd39cb80cb80117c7109821ea0f6b151397fd68f65d4a983af25633bbbd3d453a7aec4693ead150097fbd54c26d961a4dd0ece90f612f88524b83fe5debe1dac73faf2fa96302dc4466592246c44bd5bdf5bbe7cf7f8dd927d3bc821a51f1b31b17f2c9b3e7df968ec593bade5f74b6f9665d429cba697e166fd3aa592e16869eb2bb22bf1143560a7f50bd988f7c66480cbe014620e31be4618a79771ce15c621e04619bbbddbbb5b4b1edfdddd4e7ffac98c969b162def6cc44e47362afd270b563f7b197ee94c2bc32f218bd5ef2d05361e00bfb714c63cf8da1fca46b52fd9a733619ab58709fde9f4a79b60b3d96c4ba8732dd9a9afb8a434e1a9d3eac4347dbff4f6a72bd3f82ba4c6736a01f7a714fa6559f9f58c7d1d5ca4b1f3f955c6bda510e6f79682ed877e6f58b67816953c602cc7710cd9889d7dd9e8f3ced93f16957c5de7e00ce78353ec1cecc8a8e9a484b28cfa92f13b9f2207fb9dafa8645956863fb95ad69efb3e57ea8f2ce997d4a3fa3d5f5109e74a0c822b762da5befd234bffcf3bb25c9699f09f97cbb2d2ca7f5e76be2c2ba5fce74adda4579da4bebd23f73fb2f479eae00c3d72bf23f757ec807e73a4537f3b259765d35754d295b2cc9b5d062cbf76e69aec9ec9f9932c4ff8e9e04e669b1203dfe4f41597703f5d899ba4cfe47e2d2d17ea231dd1d9657de4c375433ed920cf4752022cf3fc4582c032cf6d480f58e6b948c658e679482ab1cc73902c00cb3cf7417e3cf35c875c9e6d1f71c0334f037e9747f46513d2770e736b3cfca53613e603ce902c630fd627da14ba389906907ab5449ae3e8257579eb861cca1a416ff9487edef4a6e736def45cf43cf47c2ab50d2992e1fcbed2cb28faed2d7264d9573dee364e9e83e3386e0d8ee3d26db9bbdb1dc7110d390012d2779502317eb1989ff808a2382496ed929111fd8ac182038b2601f62c89a25f7e5e56ee419fd5e7f459cb9e2551f45d3e6bc979c95efb56ed096b493ff4567da2df84f42daf3df8899f8845bac8254312ecc2d0bb708b5f17d922cbaf847d9f7b5fe5603e48690158c6759d73ddce675eee2953ee9e7b5bff8a4bf6f65c27c95f13278705e4e077a6314ea74d48bfbbe34e2ca50d5a18c771dc2881e79c92538d713a6dfa798e0b3f3add18a7734362dd1b43ba18a77f4dbba98c6b4e2c19112c1958932107d304e3f46e427afaa1e17c143bc026496dd02c89f636848f24c0b389a4268eac3aa43c01ee0f8c8f864ca3a1acb1fcbe29c7580ab9f65b3ece461cc7fe79bbaacbe9afd872d5a6f0bf4fe6f39bfc03b848e38dd36f957be6d73de016076cd4f9ee1637056023aed5721bbee5e51192f9658bb4bc2cfafdf952f6365e0e11226ab5bc56abe543672cf31890c9f9ae16bb7ea0ad56cb6bb9b0f4b839e17279cbe718d0f5b1ec6b81b99a414c31df8d57c686b246cf27186314f7d3f90b18ae2dbf2129cbbaceb956eb76d36ab56ebcd56ab55aa3b75a2d9f64d888bde5f3c646d35b37b575f38465ec23fbab8c8d9018fb10249b4ed06ab55a2da46fb9abd59aadd98a6133185d5eca5e6993ac6cd074d8bfbc0c7fdbe785fec6d79d8f62a2dbf8aec7868037e47cfe905c3536c77843ee831dba9a90cc3421c5f8f99279cf4472be8decdbe538de2ed48e437e3d9bfbf591d22441b77b0082ccf3febc91d888bdbd006ce4f27625d0bb09e95dde22932939d05042896fda34ef727086a06b7e6cfc742f8d045886c603e3f46fdff990127664c2cf6f8c8f947ad6f90ea519436fc2320f58d6b9120fbd31967be63b1f3a632ce7972f6ce4cd316ce4657de7b38723d8288eeff68398627ea0aec44cee37e9a358cf3affbeb11c6becbb490e658d9df7d1acea59d7f98ca3ebbc091b85deb90720b05198ee0b18367279e7f38a8d7ae0e9858daad8687a58abbe9b358ad25f91ebcf06b173648c652c6b91435923cf3ac6e965ecbb8ed6b9f7103e5a5ae7714dbdf3fde92ad3bc71536c77bb7b669cbe7c46b7ceadb7971cb7cead3371dbddee2e377b085acbe6dcf3b29bf376ce999a8ceae79c7275418e2c857eddf30de27ac8afefa4be2ce3b8eaf36912e7259d4f7d7224d1066d4929a54d765cc2dfa6900b703f96351e61a5edd44bce979bed9ccf76266ecef2eb4a9dd63dc0fde948ea5afe82df1b11677e8b97fdde88e8e1c588f99ddf9b18191eec90eb815e3518fef29ef75d95e12b5bb1cce3aea41fc525d7287ef6ce7b17ccbb5adae078f9b9d875be7c94e39dc36a1945bf3ecaf15e1f3d875c9ebd1c875c9e8d65543fe8ddabe59c4726d961b4a951f4bd502493ec307e35aadf0b7d39177d8a1b304da7ef55a6b07ab48ca23c497018a3faa78b5e46f514c37dab32b17bee7160e59c2bd374ee5bec80fb59f93de76ac956db2ceb1f96b52c8cbde779e794df7329dff4748fd23ff6a5142ab1a795693aadedb4321132bcffde86a0e1b99bde4d51ece066f5f4c1451af9f6f4411a2e1f75b58ca2ef390dbd9c47fcac252de77be0865c477a5e3ccfd98a8a4abc9b525351c9ecbaceea978daad8cb44b2556cd4c244b24f9dadd8c873ea2c2aa1b7f7c825e96f0720c755e07b955b984592b0acbd89cb5dde5517d9482cdb632cbf6f9f73fa574bd94bbde794ac4bd8eacb287e6e6116a14edd23cbda7b9c533f272ae196d66c7844022c6372534e5492c29844c90da41ca55de7799c472793f1f9e93032c639c718b796b4e368f3f46c4a137e4dad9b9c14e066307e0ebef607e42c63393ec79efac7465de5402f3fa432eab9b2e9b9d20ad628c42c63a4767e1711cbd84de803b06c3e2587fc24cbaf1cc72ef6732c7de9b75afef1d1d872ca46adeef315bb8f73ae4d3126188c01c418cf714e9fab3d9cd7de59367deca3a1acb15c35b2e9268cdf9629b7ab65ecb9557300967196716e570e58c6338f2d33afba3792100d21834548897f7e77a362ef2ca3b2a7ce710e8235a4df2813362c61bf2ce3caeced9158466bd9b458de6c1e401094b18c0e795ace6fd0e59e1253d146b411c96559b8ddf75d2d9b7ede73d095da25d2ddcf3b07c15d727f3eeffc739afafd9ce6af8cab2147cee56c7683a8fbb0cc4796d15a36217df357b3995c1968ee98b669c3c26203cd933cd0604989c0881ad65cf1d090012e1a57cbd73fa794524a5d89859e52417ad02959223552f9f313fcbe394330865eca64e1071b7d623f4fbdf4e7ca214fddc697e8a98b3ca3cebd26e9721bb2943de722590a3d579fe88364c9c173dea212171882b5e9e73b679189d4183a42b0c6739dbb48fa2d729ff448ca322434bf426a36937a015ee19ea973cfbb978b0e7b97afa8242692e57cd1c6575462e34a1c9225d287bea2122506c3a80f43b214fa8f65ae6a4396dfbb6a19c5bd285ee19e8973ea477bb3d96c5a68dff40fbdf4cf731f36b2f97ac622e7375ec6de73d70cc3e532366abd9c5d888d5ace4ec4466513d28fde029d7d24479685de223f9685fe224396857e43c678163a475296856e43c294887559e6a08b2c3f6f7d3fbbca91b4be983ac1399d58ef7d53cdc80e96abe6db29e5c872c97c921dc625f3e5f81f183f07818d5cce75bcab2ecba82bb5e72df289bec77de4c8b2c9d5a62533e502172ae6788efe24f7b78f40a7ce1eb693cb5456cd7395a96bc8b239b15acc654c2fa8734db19fdedfce9151fc4b30180308329a6273fa1910f47670722d2ae9269b9cce93b7805bcbf137ece95c476e609cde39535729cbf018d9c3dace9551f4a7efb402dc2567d568f37b1ba24acd97e1b31071fcf4908d989c318c7b13e28cf87b13a28b9ffef52ce12f4ff80b7c8fcce0ac1a5fbf587a94f909669cceb21d13fa88ae2f159d96cb715db7be9e67e9267d2445eb9649a31ce7619d61cc749d83758a41b365d23c77d53926cd96499b69e62d6b92d30c39b1c85986e346d05d31aee51fe7794739a7be2e6b6242cfa6cd5541109a555f7d82f4eb3bada4f4ac777eb1d2b332b34bd9aa91f5919410a5ce21852e2ab91ce4a08f3e6f75eeb918d66fec2329d025d58a791f49795cbb6a933f26c0fd29f9f6ddec94d6726b29fbe6762cc6725ebd10b62f578d1a3366d0a04993a69c655acac65fde52a18bde522e07bda53e97e2bcf3f61d5f75653db3f152c846acdff6ac440ac13a6ecfcabdb56a8c3d4b77d5cb79c5618d992a018e5aaa64342d5b9084689e6f91d13adf12a36979b9962d1f8dba962da3962cdecde634976bd922a3b55c4b15114dcb16245ae860dd2244036d7ccb109aa8a5ca87a6658bd36efc55b7c468a36ff9a1bdb46c91d182ac91e95a78b668fa16a755b07e43c2b668fa48e6ac91e92f32b643d36dc86f8ba68b64b846a687a4b746a68364b746a6bb48ba46a6b7486e8d4cffc8dda2e91e69b346a677a4b846a673e46b8d4ca7e4cd1a99de24ce1a99cee4b846a64f8d937b003bea5b288d139adc94f3be968bab1ad2dd2dfbd9e11aeb990f900a82d0a693d180fb5372568c2517e6cb485511d1a84bb567a15539b4be55118da1a267d9309eb8434c15118d73a92c5e16eaec5c983ecae265a195cb00685da5a4a4b80cc0e332009a58a56a414cc1a555a54ea062a2aa882c8e584393e232001a57a5a6dc0073c697306662a065f13c8b97c5d3b225a47540fcab82d15a1dd755e02e7a8586fbe11406e35c072b88e360512b5abd459712c203d22b933d0e52bfc59cc73d766b5188fff8f0711f395c05a35131cf9db5e336ecfc53a5441752bd56a991ac524a20e83d558ade78aa148d55a9f6dab71f556a6130d7a95214abb182546a7513735795a215544a81d42d43689fb77c6c7d3e554a080f78bcc7a5c41fce2ebfb972b9d4a7e3ad9e2a253a4f7dd233761f552aa74a0955a92d43689e87558a8ae92c313b95b31c4ba88b893f6a9733ba14bf5c8adda6ad9eadb06c3faa54e73e2a4e95b2d233f69b2a35afaad455cff88ad12c9aac2b0ed6e55429213cb8711c976ab9541511cdc5dd70aa54cb6fea1cabd47c55a96955a5daaa671c56c6b24d311bc613775851b055a5b46c0969ae4aab8868b44ab5ea44d355a98955a5d856f9363b3caab0a30b24b4c032b1e697106cc08d327ec8e24df115471401c31779688046ebcccabab2c2a2376abbf51515d35962b25a4c57b92f68fa0acd155739abb6a25e3296b766cd1e6694918506ac68e5aaf8364940c61921c8a1cc19b4a53518192063092e5cc8415b5a57ce36b39e7d5e314e2f391b87f52b64aad626fb8061a279f6d9be6a16eb77d69274da39e74fd9ede795d3a5b594752d658fc68b9896abf1cfcbc5fabce5a5ecd755f22d0d2c0b87d5e4947d330656f9cbcdc19838bed0f055cf98394ccf580cd6f3989eb1992f67d6623dadb2b2f9125eb9aeb26e46353726a0b9b9b1a5b9a9baa9cabab1bab152337ee9190751f525ad2aa38717349d1bac9b9b1c3339398ee33e7c549d2a631d9dba1cc0603855090727a722e5789671e6dc54a1e9f36a5e95e199e69b685c4e7533cd78be34aa9b89e59148f61867f57c9619613858b38c192caa2ca3df54cff11caa1bcf32c22a0a39f5e6a6ce3450b5e75b99e9e5bc2af3fcaae528d6323682b574572d63ad5acafeaba5b37b24df560d1a35612ca1830d6dd0c183d4c24195c5cc18693c4193e23beaf0c1c6c5c6019a547731460437d8ee688226c565b6c461870a72aca1717093a64a0f27b2acbe501bbda261a89883260322cd97b40acdb3f34d56a68f84b0fa08c94c1f29319a3ee2a067ecb76797ddc4f46cc774b5fc6e5c2dc7323ddba7b58c290581d5b37d31368c03c5edd7a77268377e33060736460cccc5f48c711c965351b8a9f40b0ebd9a586a5e63d5100e9a1dff9126c76f6e2a0a3caee3b057a5caf272aa988fdff88df3d8e3e3f1f0f47cbe7d9453739ca7e5db473b75fad26215859b9c8ac2e82e9f5633745a158a4e6da28db79a9ea9613559dc37eff31ef3b5bcc5b45cde615c2e24d433f6efe334dd68a873dedce8595ea02f8daaeb1c24e99789f5c5cb8935e64bb6650975c0eacbefead9594d1f71989eb17f36b5fc46b196632cac658cab1a066bb96a7e7ac961a62dccaf99b73d87995833ccc49a61a69a325f26d697ab2f5fb2ca3c673d632d561f8d2f33398e134383e33f7ea4b9711f3e1c85d17574bca2f072589582393bfdd24752b1daa467d373aefa48ea87999f8ee3523ed0fcf41b97d249f3d347978265fdf497b30bf5514e95f56c3a8ed04f77d5f2bb41fae9ad5a8ee3eda77f42afba3d2bb7cc4ff784ba5a7e5c2d475acbd897df772dfdcbef6d6a22dfb401ee4f49b39e1ddc3e5293f5eb6926ad5c33bffe9193b6687e17ebcb3643c3f4ccf6558d56b12fbfebd4d6472da667ec7e15fb325a557ddfd8666849b19edb8c18ac3e5a9a193434cd330d2386d16c5657f5115516cea93cf7c2b4c0305760ebea8b5349550dd15a0e7eb1ea23aaceb3705eedaa8a42e75d6dabaee2315ff5ec6d66d17c69c6ac58abe9a32d93e63d636f33568c26cd17ab31cfce567dd4cc5f9ec73613a3b667b682622c5bcc5c9ac7be1cbfa46196366f334d9a8ecb4261dec44c3565c6d8b06e3d63aeea2333657ac652284c343d636fac9e7149c33c7bd9629e69983ee220ac50a30d1b5ac882c64ec5f451cf80471e3f00b1c31434763aa68fe69615cc58a3660d1934767aeb232357d40082355bc8d0d869993e9a4adc1143d50960b0d1f8cbb3975ffa486a5ef551cb993d67ced9adf491d4540e8ddd843e72550ef4f8c2d647addaa467cc3eabfaa882e0ecd3aa8fa4aa86685f45c1ab4f50e0aa949e316f9967256d6683d8dbccb377f76c2f65cfcdfe35ad1b3b5a189bb41caf0a69b19dcdddd9a45ead79a4a3ada446eaa2deb6ef1bdb38dbba530f590c78f3af4ab5edc6b65795fadc43f3cd7997f5edd4a5c22ac5592cc68ad0d8b2b9fafe1c1c5d58df225b7d87236349b195d4c492da69d5448aafc01b46d371556a66f914f3da5bd8b6d68d6db65b28d4ca129325a6e51ea301475f1ae8255f89ae79c57939da78b9e3abba4dfdb0c4b0c6c03ab255ab8e5f8d614de5d0bc4aebaaf76cd6a5d1ba3deb576db28b0b707fca99f5b9e7eb631f75be1eeb23ced7bd8fa8c8b5ac71a45392ba474ae9f8474afdf0a91c9a962d228dba94101e84eeb954077ae75256943a67e3f4f689feb9d4f6ec8a6bb9cba584f060f4d6a2e17ccb7c3987f5edca711d9712c2031ccf41e3ba71974b6d964e95d2b245f4e13fb4540d80a6e35b264d4a080f60aee3523faa948fba65d274da6175da7ad69e53a5269a9eb5e3d42d93e6aa524237d54acfda5b55ea49cfdac7ba65d2b82a35b17ad6feaa2e6553b74cda57a5c43aafa4c2ba65d2ba2ad5a467ed609d563de3b0a8d5772377d5f272de2856e78b46c8db2c9797138d8bf3a5755eeead55a77268d497e6f9e74bfbbc9c62be3db223c79e4de7c858cfa653d27b3627ac36d9c302f7a7f4b2befdeba372a45ec64a2f6548f6189f38ef7cdd65e3dd6ab92a0a22e8ec7281158556e8d4b78fc28a82ebe5d3b78fa842247b8c4ef3bd321bd4be34aad0a5aa8668af8a0268535108bd4e4da7a68fc44a258ab553d3b3f6b05285a1e7b38c574b072b1508cedbac65cc55a95c9ee5732a57dd313d6ba7b51cbfecd4b42a55cbb37c15852c730d4d08ea4ba36ad529a6679e0dc91ee353e7ecf336729832ddde80b8bdb7771dd60c13a68fbe2af589e92371f5c01ad347e177eb23706c79fb2cd347ae564521f655140690456be748247b8cd4c1ade574a28e648f5183dda032a8642fbd32f389713e3196de55a766cdcc30fca557c62bd347334ccfdabf6f1c63b12fbd32df3d2bfdfd6dde9557c6bb5a36beecb03a351dd6912f3b5b17a6b3716238339c18d897140d5745d1b8bea456744c49adb82ffbd669fa4bdf38abbf94c9e22b5b99307ca5264c39d5084d5bf9956b46a8fcbee76d8c629ccf5ece305ed6af90a9afc6b18d1770a7082d4ba3a1413649d5105a96ce83679354511a27a90a7d3649150cc826a9f2a9609354fd7839476859d8c6be65c2364995a7b349aa5e3e3649d58f1f9ba42a486c93545d40eb2ad579d5106d9368a90aa2656935365afb964edc24556cb349aa5caf4d5285336e922a9e9b4d5255713649150634ae529c570d759b444b168f56254463dfd2de26a9e2689da44a6c6d922a1dd726a90242eb245516d0ba4ab5570dcd4d52f5f126a91a7b9354c5689ca4ca6949aa64344ec2558afa540ecdf3b8ebbc1ae3b8ae8e5da5aa8668ed5cfd7a36bd6a88269543a3552a4bafa175dd9e4d9fcaa1550dd1b87a4f7593de8010337b4e71c97083d81b882b206a78a7716f3c78f992fe0231435878b1e546939a9a50a85165a309c13ee52ae30b4d881e266cfc3c5233020d31676c208f2b20e8e05f324e58638f2d779c200d37dea0adef08e0228ddfd3efcaf03bdf8eb2118c8d5adeb96fd27ed775738c5da78406ab67fbadd6f74afc9194655446fba87b638c1ba8c8b0210533df3945d3c6775d11697ce1820d304570f101da18df755fd6b84fddeb588c57009a460d6994f9e2bbbb9ef93c9ac585716f698c4943ccef2d8dabdf346a48230b02a8fc7cf9f3dbcda67ce60b1a3b9ca9a2cb4f1a4fb41207b5fcce205195c61922b6a471260c9734ba336bfcebf77606ab1b438d3cd6b01a1ad56043e7f7a68617b0df9b1a4d10c143f87b53230321f87b53c38b97461e6990e0671a68a4a185cbc64ff8652a903f80244488c60f1a488ef37b43c36ac67e6f67a8217f6f6794d1678cf1f9bd9d01e6a783dc195ec63c3a33e2f8f17b33430ccf0c32427e6f66e4007efe7b33b3e6a783ad30c8efcd0c9a9f0ebac225a346a8716f66b06018777e6f668ef8b9aed607f62c01bfbf6bf9f4dc3380cb9d379be33252e8bac658e6830757020a47930182aaaef3ae23e38c2aa5f91c4706558c655ce531bc9fdf1b1949901104d65704b83fb309d712f6d399722411cba6195b192afc8ab43aa545b422552132c615429ad387e0182bf8bd91c102195d3e5e420c31be40fa82fba8d79b821460f130061466b8bc415b32b07cd769f15de7423e2cc300982e6000a20b174400025ac7550fe373fddec6b0e3c65978cc678c9b185b8c51471630c6c8d202c618726401638c32defbbd8d8145b1e0829b948302848105061a6bfaa70b1378f9e9e20d15681794d230d03ca53f5d503166f8d6ef4d0c2f5f80b36a0ce2d7c570e2b746f1ef0659d060a6f76e50194f8eace7ba9bf26f6cbcf23d5d30c87cf93de7eb312124a53e721ae71c1c6093fa396f02c611cf79f89c6f5fd12817c7739e67f1eb5c992df3e590e9b376bd01cecf2c709e73b0ebbadda0d9d5ae6ed697a6afbe9d070beff7068618df35c90ee3c47a21224650e02478238e12cc0dda00a91d6cc706b52741750d1bd4ce28d8a0e6b84abf6c12fdb25cfc6e906fed2f1b74c588f3fd6522d96f6f1b3669bf198a3176a484856667d348092bcdcaf64b9bef99c4ef9738af8475c6ca2612252c35b6c8fe55d8461e5871fc2cf3ede0ab7dfe404edb7f8b1dcc322f32995774759a6b9c7e7e6af9e9c3cf2fbcfc2cf3e0b215e3debea8e3cbef8b20bef49ebf88c38b3cca4c28c61f36096a6af9f9c306ad2741f9407d785a6693ba96f3a1a8f715df3eb1d8a4727ed7596683d6b1d8a0f599c5264ddfa4ae4edf4fa75dc06d1adbcb6f6f5ec4f194522a055cfe61ea3d5c35e0ffdc73a2f5cec3ce471f19cfd6cb2423cfb6837de7a59743be731739f28cbd457e1ef5e2ccef18bfa2929fae798a005cfea5e0321771fc4af17be3a2030fbec0ed231e20bece81953ea2be3ebe0c1eb97c5d4a1f5de01bc4b7a791fae8e5eb4ffaa8fa8abea4afaf0bf511ccd741e8a31c5f20df1dfff17513fae887af10af31f2a702c089f810f7410aa9543f42dc02c721812ad50cc8656e43d64a4524c87d78489295ca82eaa4b7c80b2a55900f1fe21f19a452c92e700cdc237b2a5525fdc73b1248a5eae9bc499f4a758167a1aaf1905440bcf320d37582b88f77b5cb105a053e9254416a1700d0a86c3c888ff7384852f9d42e3a34aacf7d6a171b9a3b904ac5e3a3ef9054608feb388ca4ead17120fe22a9746a97a651c57c04e22f77bd1c7420b54b108d0ac781384752bd6a9700d0a8420f02d62e3e342ad07dbca77681d1a838eff11c920a00446a971d1a55cb7d3ca876f96854ed3d4e492a1fb50b0e8dca878f436a9749a3d271200e80daa5a351bd3c88ff20a930a85d7a68549df7cc6a971f1ad58e8f0ee4a2ac7679d1a8440fe217d42e48342acf7d1ca87671d1a8721c88df9054423c0b558d6641ed72018d8a7a8fd7da6546a3fae163a5aade65d25cce245516aa1aeda77611008d6af42041dc55a9749c0ae654394e75e3382ea47639a251b9dca756aacea938a7a24ec5deeee364edc234aa1b07e24e52b1f754aa20950a742a9753b59ccaf3cfbb4c5a8f574052c11c48a5ea32693e956a74aa9753d93855e8a2f7542a1ea7da71aa9853f9f01faed43ce40e29ebd97a8c6cd2b3f51fa4093d5bf7b1ae437e3d5b87913924083d5bc759bf591fc9b167eb2f12a967eb36e4939ead8be4acead97ab80e92b19eadbb48a59eadb748293d5bffc869b5de91deb3758ea4a4959ead3739bff46c9df7b605d6977bd3c2eaa3fa99a6c73ef641f35363892596405ae2c727e66b460b4378c1021b19f0e10320647121051fce88414b0e5984414a6185142d2b9470856a7041f42c99627a96302331726524c6f5dad77ed6da83dd7d4529fd32e7729c3357b90a8bae0ba0c401cb26119f0f2d4a29a59436a556acf0945af1e529e5aab0c3c60aaaae4837f175e745470658ae972573de39d8b56847b28b6b247e7086aba48990ccc535d91deb19e720d7a21cc91c757194ecafc9f79cdb33a62bfd3f9ce079eb57f480da6c1e4c9b8de6397bb0379a5739e8d9ba12f37c8a85c55548635d4322072dc69ce9020572fca08019a608e209335cd0a8a38a35ba0a10e80ce0f37a84fddeb068e2c1df1b16626e9c06b83f5cc458ae99ac3e12e23f5eb2159005cece6358d633eef101227376fed24717383b5ff511e9ec1ca68faab3b3983e729f693a2fa715e7e5fc323adf38e338e738c39c7f784c07843e7a39fb933eb27176297d24eef0f870dedb22811790415c4656e0e00c81909326238138908a0250ad1790163800dc410e8190aec4401cbc8084c11c5651f0d1d1c9e989c570c8495b51c90f3f1c875c5a0e2973187981afa8c4e005a4587b3eb8c045172b0a377e41edf9c00700dc878cb4a93d1fc8fc02bfa0a230baacf67cc0e33297551466cee34b5bda8b9c3470863fec7893972bf14c880b71009052427c3049804416361a063e73a929995fe018ccea94ac2e17951cc44f4761ea826aeb332390c146fbf19f3040e4546301c93f644fe83d1fb8fb4fed01bde703d7f19fdae3f29e0fdc87ff5421644f589b90def3815717527bc0dae487f77ce03117527b5cb5c98ef77ce03c2ea456557262f56c3a49ce323d9beee434d3b3e941c879ebd9f40ac839a667d38190534ccfa6fb90334ccfa6f790f3aa67134dcfe6cc1a3bd9f3903b648c34a167d37f90567a36dd07a9434e5bcfa6c34829e4131c128491e4c04654ea23a146ea2035905d5080df3af80af313674510a43c1fbb1b11051c177d695de879e84bbbc1f1a6989b39e6a777f3a6f3c395fce0e3a6c371d1f350f4500c6d26d6741cb6fd74b135cbfcf4cf4c169a344fed62e8398e7bbe34d141e8f900c7733ca7a2d0398e2f2df40df629cc736e1cd6790e082c9b0e237ba8c39ed8a1e63b3d3981f0f2cf4170b98d2bf9a1e54e1f48850efacb3f90127d74106edcf32982d0398e37d1e2390ee89ee3d41ece7fd4eeeaa7df8479ae36f1a1536d30f2cb4fcf217b686d52f5d3ad9abf907cd5b3e920934f4e50f39d9c16b034cf17b0341c7702a1e70397bffc5551a0790e42cf072fefbcab2888fef2a5e1f8067be39d8337be2208a2773c1f87fc6ec81e76cf6b34b017b0342d2e7f798753fc207497b30882e82f6f10407755aeead9f457ed69b77191e4a067d343727bc6563d5d9bb4be2af3c81eae4d847a36bd469bc2a951fe8800979f7082892698b0a28ef79034516669535a953868b2007b850f46b881841c586031070da38c1968e680420d140441a357d0f0945e91c3d39da702784a29a594d2fe01230524a0018b14742083b6a18716476859638d0f1fa0512bec781a3ebd22cbd39ca701784a6937b13e7e6f64c27c1ae0646e8ba38fc644d09f1f4afab0cc8616f88789afc9b4f0ed85d60ee31f262a074190b17d197bca3115753cf77ba3628e2f85e80d091224489ee8f0984b3dea3c4473dd1c19ad987364401907dd751558df557891e4bb5da8964d485c131fe7d15993f840470b7150c1250d99309ea842081f4c2046961c768ca1c20c15653af65200a7cd89214270c3aad2920609a509008d0c7821850b5a6051066d7d97aa38820c1444083105144c3ca1c4ec4010484c0e007104910546e6b922c3ac61ac80fff7e00b4d9329e4c7023461c7a29456252a2a8cf872b19a78158b524a05114f29a53e692d325231c4b3bf122bf10f0fc53176bf372ac2a0a150b4a670828a2f2cc5996729c47866de329642426ce4394f073972fcc8ef85d1e5fbe5f72e6f39272ee1dc554ba666a23e99da3b063951c9d7a2e2016a2bb6bcc5259fb76af931b5833cc5f68f64a23edf2349da91e1c87db7313f3f3250fa4305a90909062a48cb463d419e24388c5d7b187afe393b0ff596835f0ca3e7fbcc7dbf7df4d1be0eaecc9f955ee1beab4cd4b93a99579042ccbfbe8fdc77cfeb9cd6929c7fcbfa0e3f92c178e47eccd56950526f39e730cf5db56749e72defbeae3279cee212cfbf24388c5e65f2c2259e77de2202baea7dd5ab4fac7d003b8fadbb14574f9d93c22a0a331eec18e7b0986b50561f96852cebff58d60bde2c204b1c3556993a67ff1c966487b1f392738e097b5799b8eab5bd2f63dc71de4dbbfbbe6d030a2c3280c5195daea0c20122f8d2431a458461871734ef04de910bad8ea3cd350a32fffddea2f8825e457144143dfcf490c18dd19b0568d1f2dfcd02b238c1b27d9043cade43e9b76ca30f51d64fd84f2c286ef8d29f50f3e590b76022fd34f36592a7cd60f3b36fc0cf20cf651baecc65ccf9bd39b1e69578f21a45fffd7a13a43ea2b45d2e86c0e18529c678a10c3468ab85102f6c91020b72888086c3b81f0b4d605535b185964fc8efad090e340186a338b7d96c511c12b7e0c58fcf183ad8f8e1eedd169899f97beefe25383d6011c34f9f67dc96c06a42062aeae32cd332ba7e6f4da8f06b56f8b162420d971f2b26e6e8f2634583fcde98c0fa9c273c0f7c4a1c14a08b8f0c3a84e44290102748a14c16aa1768d82e7088018b3437ace1001267886ed81021b9f0c5c6df1b13429cb1392021d5a000d342078c480209aa10d48270238b092ca2c0a14c07baf8c8a043482e2c194d9031441d6770d8c20a09b8e1461d37b8616606369ce0a4108f20b920e63d2417bef0f7c6840e2768c5dc87892f5d38e6319f581f2931c1c20a5f6582cb969688c7c75d0c47bbb332c8dca3d81e292de75e261142e697c6d888dba18c7b53e2ea6f7e6f4904f12b72aec47c35c67c3c9f3f5f7a5589838e2c00cbe69a14684a1c14e028363da79c85e6fdc436d65b8978369d2385dc878cf5d10fcfa6330ea312077d346d369bad8a36e76dfad008c6fdbd2991c7fff8bd2d1182a7bfb725d6f8c965801d5cd9bcf958e65e0ee91b18cb7aaabebd87ab1af073beb72e7a78ea4a7dd437760e3c78d2f4e559a88ed7426f5f866f23c4dec6a0f9db1831ffe5a679665ab96a16a0c50cb9002c60c80560b962d9bed0ac7a3622f46558fbae3d4ce6b72f404bed7feb0f9d2bf1f43e1abbba3d1b59c6370bc87266d90a0d08524a414a3b57e7ea5c9dcb455d61975476eeb95273d9de39d8ea662ee753572d6bd92ed579b743d59e3f26d6805d9376994f50cfabe557fabc0763dfa47ecf975a8d9ecfb167d43fa3aec6820b2770a30b1075c861076deca32d811966505185135c8c6983e6f92a91c47befb9b35191f75cd64794e6b950574796516717c6fdb18f3e1aad7e05d8dddd5eb7d7852c5b4e9c5cb75fed76ef5b5d73f2fe9b7acf5954f2d5b03d9023dbc1f6ce39b2ddeb38e7ce3b36a26cc4b909df1cc7b183dd91ec9ea884b24fb1ebcfd988c9ee06b06a4edf65dff649eecfc94d7189f7de926cd5753ef5fbebd35774ce27c95e7e3acfe91c37274f8e9d921f5d4e0360b94e29a594b26c7da71d60397fd38c25fdf9d41e459ff3ad3d4b76d99b96cc539f3b97235ddff2ca30c64db92ee426cff1c6ab8dd18664b1430a72aeaee585637bd731f4f93236e9f7e5c8327efa21cb98d2df350a611ea0d64e9dd6927e57b68dd36bffc3ae36c06523fec2918f465f5a8b64f748eaee52c2ded280f965d37e43fec494fa45da902d4eac2e722437490d63e7ad0d3a675149abcef6bacf458e20255dceadf0878d5cb58ccdb01c9b9ce29a0dd33d7ee81963f9f3ecb202707080a618fb4fcc872343148ca5ec59c646cc5d47969919658c07b87dd47235bbb1dfaf964db2a74e2ecfb8e99ef7757b5e4f35d32f9d73ce7907668b1697501a66118ef326679192caf0ec5354c255a6611661a7fb733a8b4a3866925a99f09c33d9f40bcb6acf75fb8afd5196cde9ceb2e971f78122ce88b93df86a34a698ff3e67f7deb53ef594fb3e6f55ef2339075b9845d6bdbab388e71cc95e9e732a2ad9ca55eef93e25f74df8de632b96714aede43de9d124bc2061fb2972aec474837dea1cc96138521dc05d234a9b91b097cbbfcbbf3e9de9697e127bb9938ce235622fd77777d769dde5b9deb3b9706ab2a444794faf78cfc41a9801822092d037611967869b73ce39e79c6b66d99000cbb8aa013713d759f3662f91f5447e6f47dc1e7ccdce39b28cb1f8b96ca4bcf7b53c977fde22cb980d39bf8f5e0ebec8e59957cbef3db1e55e4f1882ee72d025e53dffb8c997eb4db1b23682dc3e88f19a768c1301f327190e29d8aae35b6e041b0f80df9b115f9ec99cffc36ddca6f4e13b1ee361c271188843e6f80dc9d3718ca87a1c17d578204d7ba0eadb03b6ef06bb70c52539ce5782fc0be638a1e3dcdcbc70701cc773c872f47503f8f02ec421717cc504ccf7e14a8ce3379d88801c87390e594a791cef4404dc387fdfe8e5f838be7cd4133a9710e4c7b227ac06a8fd587b5ece14fae8afd0470feb38fab22caca5941feb4b7998e394a37738ce891cccf7e130b284794e4db2c308ab1df8709ccae4c3c3ca243a8e2bf1483259c26a53ec7dd41bd1d779c8927ecc5b64222e112b65994d75ce716ab953976531a72c8b3102b896f37f20e0c70fb29c1297b0df3878432ee977894c4a1cbf79f2b07621a064c7f19bdaffa396287ca18b649c0aab25e751fd2e2f29cb6e5ca7ea38c7e2127e1d77913ab59cefba71ca46a1dfd4f2c66fc8243b8c51fd2ee7fcc641326abecba7a8e4c665c7f8790f93f9383e1fc7b9daf8ac3dae0ffd08314768610ac525aec7d9d05baec42d12c4215fd35b1e30f32d0f1d5c900b577cd5b2f62f1fc932f6a3c3c852cac360ffc3633737ceb1ea43e6a396e3df78ce8d2f1ff5b80f1fb5fcfea6963a0ef31cef21976739b5fc9e6b29aec3c8ce75c8b229f6382efa8bbc321fc7a9b8841fc7a7c864e278ab96a1e3380ef99aa2016aabc438243f8b1ae0d4723e8ebf7c24739c4998df9065ec6fbc47676287f9c80e7376581d3da7deb852e390fc376429baf72fc721f97b709ce9c6d9716a921ac69e2537ce7e53b9daf8586d96f0bf2a53e8626d8a7d585bbeaed420397a6449544af9f5169570d3f64a6853ecaf4c9d18bf861023ca9300b83f5f944dabc63f72493a0121d09bdddc208e8652f4bb290d3fa3fe7ea66e2ea4fc257d4f023f2568fa79eadd04bf900e4f544243dabd9f8d95318b3efde1dcebbcf43ccfa35dd90ca2f10d7ae27444715774775dd72d772fef8705c65866d69225dd92d2f0e316b0908490907ea472c6b19652c61b980fb2003cd3a95c9765383e2c1be76b7c91b158cc7fb07298de3c2f2a0831efd5c2bc4765d33c93e79f979b66d3203d09e1a5e078d9644500554ef3e16514cc4b1372bc94fa1b5f1d076be9c101402f9bfcbaac8f746a2d3f91fcc187e7c0c8a1acb1e58afdd0113dc79d659eb3e3903487f47191483152f6430867286b0ca4f8a8442a144ba4899e04a153088dd0cc06010dc31460404028168d07240251d5d40714800e9cb64e54a14ae424c8711032c818630c310600008008c0c088b4011baf7c02a02fa1fbe1b4d32f99d7b62afa7fc898fe216df96c1755fda153a462695579f9549042bf752c4cdf1a464bcf8197f6a81e2f02f64c79f312f8f6b33778daf93e9f1525e570f7b648736655a8c5500a32b7c94479e040faf4b24159a64483487f20872d03693850197c8bd432289043476c5404ef57d1af89a2615e4b70bd7ab5a20f3341842816368b8b1adba3fe817f8e13f592d5b9e0c1fb251eadaa7cf96ead5a1ed3fe2061230dba61a80703c0513be8426d6778c535a744b8e2dae994a3195a018ee2da7edc753a170744dd57c4487d7378aec6701581d14c6f1b4af5481745494383a65bb700b770b8de3008c1fe13f3bd73b40a4228de0ac1fb0b029ec83a31b1a022562a5af60580c774a0ba5e183d165e8c8b6eeebf47b58352a943542e8f4ce7567aa111e6a56a5fa17313ab8184f43bd68ecb2e2a2b3851eb84a3084cffe90c135656238de56f5b4da7e5dde85ceffd2357ed623497f49f634218c25bce0ddc478a3f32c5992c25d8ef90350f10757008ba510da1bc3656d52d9cdc20708a953a006810f8a2084f8674832cd98b1aa35d87a3a8c15e4b4c6170b062d3e7425f3263eef65e9a0dbdbc6e61b71e2d87ad16019d1d1db6edcc590bc39eccdceca528aa2a69a8b6d0deaad868162b44c7432db57a93ed6bf94d3c628d032f9d5723c56fbec400a8cadf00dd6b12457c8a6c5fba3195026be1c57c76282c03e0986a83473d40c827baeb3422619c14b5009fd7ef3c2d02443b5cb97e12ff8fd7706ef009b8994fc01bd4c7bffb7322d19f3f3fa8e19d71b09be2770a68e1c10ea417b05f3f8aefb701440aac78792752d7e46f4e72f7db68f6f4040e8065681c6d2c16adf482ac4254a78c59759f2c6ca89de73a5a991252d5e87f86e3448c60aa80b39934c04a24f5debebbc791d45ba714e9233573b9d69749417c471996c178a9ddf1b74ab541d4bf5547d832c24a5d9458d26dfbea58886bd8e0a2a40c1bd4f016577e7fe1dd5645e87e801edc50cec969d834ebc5d1c513ce2db67b15396c7b59dca586d80fc4de8f94b2a13fd22fb17fde9cf5ab55a63c1583fefacca68abf01389f6a236a6aa385fa5f9adc4c3ae28b4eaaab6295d66bd4d71833a564dfd76fff1f9cd46951654d3be5ff9fcca22bc384d8d30858775c75b1accc89d9a9402279dcd0a6ea12ae4c3744eafaf6cb3f4aeeee2f03440eb30217919845b215177db5e8c30f642f484ed0090688382a27e7f7c48a85478904644f79a06833465c8f10baa982f8a4068bfab79a5fe28c38f18de4b041dd5d1d5ae934abef2fe697b54fa2512c874c30e494f9eb3550f64880d9acbff4eb88b4ae27c1064c5cb90dafbe6f9660b2863e8f0463393cabe89d4cc59395a89dbae72c9f7b854b039d0013b5b0c2e643047e26968c3f4ee89803293e6b5f4a24f2b30fbe708bbc2678d55a642c2a5d47a50a1f76fe9e4385a403550622038524edeee8cecf77b1e3bbe80f9541f95b2ec95138819f61a77394a3a727417e468261ba66e6e887b76a9b4343ab9117b9d8a21bf01c898441234329d92eb68eeecdf7fa955e342051e9f72bfe5508fe19f4be0e6eb0196494f65077fc3997232a80f429f2c3f2145fe8a780fddf20dcccb5b4648f4676917ceb2afb60e7947d0d2b0c5792c484a2e8144452259d46753fdcf00d7cc3d56863e399adfa866f04dc0ba07700bd01a2f781c98379d376a2c89b212f1f4bf9e19e84f00c143b2775095549d5599a986eb080a62f7c16b772006fd63d18e2d8a26957648530f3ceb30b785eec719d854b868bb803757a8286d8ef1ed0ffb66b24b7ba60767141007c3788b0504b16c9a28dd9f7adbea23ee54fe8bd15c9fc899681b6ba72d34b9e84012e20e30e32183df021da4fb48e714b6b8d0a9546d226fb2c5878b9fc22cd77e97be8a5d60e5750d72f07262f3e831d8bf19d8594367203c5144f3d07015cd1aa15abafdfc1e694ecaf5516108f59f23f8069cbf5d64b206ddce2322622894838454f8511c4460dd919a62b877987766a50a8cdfa7e976d932de014665d46c53796e6652d1aea77a325473b20ff1c80836a13d56fa16bb47fd7ea0cebf8119207ac18d5500f2f7b01f080f5cb76a79a1f36b0992fabe957f1f500ee113939e61d06c501a8fcf371adef04422891b6f9c7a80bc0f30af3638af7302217e1ee585dc6f352b0c81c449bc49df60a8ac754c1202fb6c1701b21173e9ae400473fd8980a2d3c6b23b1c4d203bd2b3502a2eb9923ac97d346364844dac3c8fd78720d13f70eebb4993d266f99c002c9b0584c960f518e4c18071b67d2bd0eb12af8e0c78736def06c39e71b0adf80da0b68d1ebddd0a706e07f207ad183e167e734b64706c752b9eea98a012732bd87507a414864a71f7e0fcbc3e329e08da9f5c263424b6d06012b46646fa1787413370ef74e7a1f7a7f09835e241858b26ee1914cc4d08b34285aaceeb75737a1a2e2cf7e9960998fe03f9fa2875ce96b2f85e7a6840d2d53ef4760e3e680be703145b0db25bbd8bd3934de5cfbb328e3ae04d5c6e0653b061ff4f7580107c1b5f98289c3d7af68f822aa201f61c03b99aebbc55b730553a5f63d92443b6a41ebf1b935f6c08f23bf3bb0680f711e29f306444ffca262fb740a5059a784426b92f2599f2ed2548204ede3ededdd980f62405f01f4ec935fdcd644c56cfda65d02bf9e87000d4c28138e4ac4540e181b4c19c0b6e5dce1eb9a26731f47b49f957fc3ff79ae72c8be7b66e9c396f8eaa4f49d344afaa00e90a242d730c734649cabb26ab2159580f3728a20c45343361ed152f6892a372771d12c40b6022809a50b032c2447b51ea89cf2094be1b8a4845aea263e9732c8add004aa09113d26a6755c161371cbff143bae25a63af1ef331a0423ac5e17c180d431e457c6dde6f5eb202ead50c4b6a914005f22ddb099e4c23270f2a9a6219453430c2ad048b16d4d87f388e2fec1391351709b62c2c34e0fd2eeb064a6cc37b7829705ab313da5fe80037595e77caf14f6f9d5de8d84b67270634b91528552b4f740331b194a8cbce623fb50394f232cb5ec456dcbfeeb0965fac77d3d823dd7827de0067b6b69202c0695e4db2d6b8d1d100198ca08b073668b98aeb65902b759c66eb30cdf668de06671ee092e6bb67b87a0fda076cf4515663715766714bb5f27d9dd824440acf1c3d37f24d611e1812eda5c2fe77114e149dad5b6a8a19280e4375d7ad4e7a89ac2ea45703150483a85ca69381a511a61330c1bcf1893d55c33ec222e81f0c30ef962d715c746e86eebbcb42473c8e1426381a6d1a6e4582a0de68a49a76a91c39e187ac08bfaf2acea53df28c67ae5b43f61cb05c97f0fde26e6fe19a7c3ed2738b91a542a6eb5185bb35a0deb915f9727a7d81cf9d6593dc2c3f92b72d540588d7691df35895fec4007a3c4d7e37f9a3c955d4eb149adee33d865671a6e3a373a132095d1b79dc04617e88f2330b5b3200c949aa80a7857edaf5678cc5269a2857755159a2ec8bbe02c1d897957a5eed5745669500173de88e7620a20668d5bae6295e763e1d53d62b23112c85dfb116e4386d9b52c203a018e4c6c9dc99c43bb2bd82bf65c4926e0442626e8a0fd60cad45fc94d57cc4a67fdfdb773dfd6cf1928d2e6e5f3b14d2fd795db2c50a35d3192b8b79212454eaa472a6982a88b76b53cd9671bdfe5f3102a31af56c96a292c078ca0c0e42ea7ab32f8d5081e9e8c030ecf3edd201977885ea48ea3ab135a62458b5df9a1a660f49a80f63b1a949edf0d467a7dd7fc63c42c6e532464332f5a45ebe3f7919a17f98cd1e1c4e8afe682250248a81f8dbbcce37b971874807b834f483d4cc5c2ab3b0bfcd627acd5a4d0323268600bd28bd34fa50649ab71904e71a68252cb800795384628c5e11ba9f690a8c042e6588aa0319c6dedd1ee8b9828892ab5d6c8dca33825caec0cea2dd5db37b7a9364da678a704cb7ccfad9cf1cd596a64d44dfb5d9e2dda4836ed27051b2c16814fc7c7f90c6d4bc465c2d52bed066068c6064eb5907380938e0543c781e86c16e9bf55af1dfaaff97c6072d3e9fe57fe73b0c40fc913ae712af8a8f9486154064679f00f46801e259a4a00a0d0873956fb26f4b5164bae6cceede07bd895fb666bbce376e387b3d36e9dc50c7ea4a36268c3e5d087d39e3644310575b0a727042574a57c62ac7cc65b874810f8577b63a513fc4da0a9258881c114fe2842db24749256910d4c99610558a48188f271e1866f700cc6ca0cceff3666dea683b21c6090c29db9203299381956bc68b5198414dbff80985903c3bc0b2838076d8a93bdfe9adaa0d2e9f0da6133cfc62404a9560c75b2c736be45c206bd56a98beb06564f6f77af14e2bae6f009c7371eca13a5bf4114d5450fce119ab3572d6040dc28761a9ab8ca399f67a380a0cc4f78862fd6f81efd5689732a49ce54df24731c462ed9a1855966220d380b32bebb2d53f55d85c98e4b6d46261820f6a4ddf634e9f46e02d66d01a145b6b918746324175159f3eebe5e128c8699ff96c92205cfea63b74476705c13d934aba3bc7cc6bc1cc6262d6ff17f94718c08e2b2767ec6e962450833d4c882d3cd8b8f286c7b1c45bdc74d92a3ce9303a47c4679ec1c8530079eaa354db0909015ada4229ba8a98866da128e95e490d9ff97fcc0c4bca26fda53e5c5d109a6a1103b4640b04f5c7526c98bbb15339de2092f4c6c3db0f29338c562764100491993ea7c6b1f1fd4dbfa304cd1af1be83de83a684e714290f5ca2f7787b003933e8b0e922284e34eee299c651f1d451a359369a7c85578123c198d22e35070abddd6c1156081fd6159519adc90c45f2cbaaae89b56a1188750c9b766a1fdeaf8f1619b53e0af943e93bb8f87ce8892805fd203ffbc2a93aaaef12818436bd5cace61eb43da626fece284452e059dab60ba9c10099d3d324a144c41f5a74e0cad520acb355f7551ee6171276e1ba76ae882f8ca50c23caaf4c2eb312da84c367b0540f4322ebc1f93e8d455dbfaa17e9829346e051066e135cb7d4bf14e697707dd18881a12b370975be93be3142da9219906bbed24a6f18a860560260abf0b22a6ceb71b50239196921643bdee33a3f308c55d282557dcc2983aa44882d1da6597e22aa6e4e865954459dd8873020c6dbc4a65d5da57251bb177f340796bd8da63947c6ee219b58daff93bd53103c57144ecba24fa10d72c7f8df442a84d97fbf44043319f091581e010529b2178920148ddf522c90c99a48aa1625544068c9134bfed707d9152538568a5b2ac296d8a2fd3c90f6e876a02585a2a9d265258cd83c631db8638981ffe150fbaf5b1aeeeb346877d925179dacfea07e7cd3a05cccb311465b66f131fe2ad251f0b4dbed1b87105b0fb46aa16f90a53c294b06acc2cf6d4a34dfc928665261ab77c00be0222362d8baac6dc6a40d7bca78e697390844f779d2c7c81e995ae7eaed4e7bc8cf365458d2a6d60f01c9563e9d48822952ef92223c1b7959e204e95b93e85699aba5083cb8cbf287549c65573280a1abedd45df52f9ac45862b8e1775645d4ab1795f51f7562dac283b58b140743b63783d19a629db97708e889d6f4dd0ffefe56baf939860ff9ed02f33fc2c317da209c0ac21b9ca57c4b7ef67269747dc46a5d9bdf49a291f61f59e02655bd61d2d758277ae74890b4f71e899e450b8a17eca5d642d48496981b5661f94379aac5f51e7420b7a0b621ea4c6687e63cdb8fb89d8002f352125851717137eb5d31e994d3fe3e8d044feefc96787e7d2155548532f92269afcf27efda70545134c0c4529646d45762c697c05a1b06250b68bc8d8ddd5caa031fd4d1fdb1aca5b6043b3d65aa835a3a82cc40d1031c08007c189d837ce74e4c711b0d100049f7ea907c35a396e93d8891a5b18f15ba30ea1ce1336898bc12248ca454d645e3193f1f17080c71782405215ac04ba485daa0ae3a284af7525835e32914aaf22b3673f60629409f1e891032e88c33aa31f4cba1a2d0e8ec67f0a5d3d97ffe6b060e807cf6cb5e516a7b1616431515657b4124fbdf9308b3da1766324fc63c9b62c86d1e80dda3206e78fc8df2431f8ef49f4ae0c3f4aac455ac22527f87ffcf6bd6b7e55a5b53f206c4120f808b37c23470e8299c571bbdb95cb96864bdabebea2930e42120bd8c64b927192b226748e408c181f308bb7667f9384c95ce6e0f0457ff3e1503b05ba4c6653619c012f2419791c0eb5534cd87f7d417fb32fd87703d70bdccff054db10c3df2d5f307f2a11bd5e0ad20e408144b60ed1aee124984c525f40bcb8016430faf36ef2c1fe9dd2392f3d06e9d8cde7dd0bb739a4ad44153e52c9c7033853fdceb77d106151175e2268b26a7b3dc86025c9722cb877538e2a104d54ac215bb1b9f823aeca42a796d1ab9739d09ad0cc1591cf0aed54a5e848e0ffeb6e654b3e08a18b81ee621f28cc05ebf700f525d53beb2bfed0aff83c3cc2de08dc58198cb3c2bf58ce6db1ee5d5ef010a806390455afaad3c9e144eadfcdf7073c04333f147a19a1e90aa913fce2be349183b242ee523cf19713a43f961a7f28bd58b1ad1e688db48c1c16856e3e6377b8a727f71f0c038ad05c201284b19fd012b54274e2c91141a0922154dcc4cc76406b2cb40580600905032db142d7bef036970a3de9ef3c43b2af511b2a69362a15cb4cbe6850d8a7a82c02b8e1b6c4a9d19a6bf22c907fc3e65be6f384ee9cc3cc8d12b338d0522c91de558ae2869d04995846dc69d68beda0b179be7f7b0efa887740c307ce38c2d5beb9990849af8529f2cb99a05c441f322b43f495682372cfee9ff25706e292e4b666e2c0313585d7cfb2c97019cea0949a1355c484ec5708b27539f0d2870be4edfcfd76149ff8bda09b6d555458cce62b7089d48b9fac02384f909658c9937f6694a6b637bf7fd8b66cc1b46d04eb1f610c5069cf747cd04c76139584adfe83a688aa8bc1eee59184b274002ac16c88a31dfd5059827516e1d446107001c5a4efd043565aeba5ecec433ecf7517c63ac965e94d2c684ba45185722f838cbbe7ac9b45491c900ebb3e41097467d1aa3e6388e324ca98b41a61747775c18c6ef35d36a44fa823f25bde957387213d0192a2da7c2c4987a36210baa224d423117432037e6ec3ebdf6427d05f1c1dc8390d40987b2dd60f6fca02544d2ef847d2ec17a1c8ba2fe91f1dacc4411300746ef95f720fe730e26dd37b851a8bc1a6f26bb9e121ca4f980d28922323f5ae7926e6a9b7d2285d43307e843b6d28bda5a1717f663dc9da4a8c675bae683ef53d5b205c17f2267def5f7c53143f9ca230dbc63b07a107fa59a635c2961364486352041e09536b418eb89653e513d0940952c1f508e8a940849d767dfe1d7366b176737977267285bb00e67c519f127eb19a67239dc64d481cf7988f681c43ea2493b27fc412f2037327c30f119cf6119842fb28a3ba6d95415ac83074d41aeadb419a33d945fefd902f6bda3734d1ad524fe3e24513891d2202641ea4f6ca62d2f51ae349597907f44ee910218f0349cea14bc7ef424d73c0dcd77a1dab61e426404bdc28703071c68512b4753c32573c593ee3bc0a0b1af338de17d9a11eefee8a511a4a4c4c47040a44b3743b1ec3b9dac711943b8c272791089566bea429f56322e8604227d66e10fdd96d7f643053c68512b3d00f26a4d95382bf2e919623dcf9cfb6bad386036fd3a5d9c3953e1d03a0d0667447631eeb6e3e6eda4dcb8deec671afddbcdc75bbe961c8d71e4e7957c1f34dc0bea877b7370fef9761d9809d32cdd620abede66e456f32b8f75c15ee88f45472119d1bf7404468d1d920894640d6cdae5217e746d0b67f02b89e76480df1e22e6ab7f0f989e75b3f311c6405a42d0ba45a68d4083f144cec124fa26b22d3152fcd152d3b108a72faea2375748973e21c445edaf9c1fea33e5105ea9a488e353cfdeafe7ff2c0884983858c0af31c34848a6b013ca901fb186903ff36008f90de91c6456f0685022c39ec1400f35904808e934498a6b9eb8898c2a834cc0031332752102a2da97c3779f2eb6453a48008cbccce73b396c941cccaea538df7448cb1125a51fa343156972674d863d182b2fcd24932f26641cd8fac7be568b7967b72b4e8e09b60912ad23a77e30f86fe8c3ddc446f8ea34fa5fc8f3de4f935533f522b694a262368087efb3ead00b41bbc31707738b0a9ffacbd048af586d8360abe11d33df5ad8c767663364a0d6f19eb5144b525d532da304539d7d08f5485ed17cdd0524657addf6f4a89c90d2a8fa24ca7c33ec03f993710f4cb8f4cab643da394a26e966bafea06497c3630c7359aa323b1ab7e359dc74c51494a021cb73433f6f7cf20a35cacdb549a8f9d9a2b92425bc83cf952c6f39c54fee6e133441bec06ab36c161fdb49c0d873c11610c95cd8895761f3ba8e02a7c23ff59888d0050754252421cb43be5641d742477ef4db2e8193dfa1e6c370df547747ee4d718be5a5cd189ce747bb8ad1ade8fab820c46002940e94168b6b986718e2e358da9330f86db5327aaed9803424f6b887f415451f45b7b7101c7c29d3bb4e3e4e5013a1fbc8349bc86cbba571c2dffb583ad39cd469187bfb73dba622612700ef5db9247c02eae2fb0c2bc9b5b9e86a876bcea9e4418a55a3f23b6147aa1bbd06a9b7e71eda11f0c3df93254c6490b5b757d0e58b1518b1ac6e7b6375cc1fbe0cb1b6efe94a087e0acf1d344b3102f06291ba12e072a12275de15adc6b91c101ff71f2903356e87f14113f6a84db524aad5eb6a5dbd1e837f024c3c62ec701b6333ae17e57620f6852bde9d9a94570273254350229afeccd8f5fa13c7cace8665423e825e9b64c6b72201e03e26d631291838bda51bcd58441f79142116b536bc58a046275df4cd03952e6f301e163c03510acb7ac3c41d4a613841b7b5237924bee5d72383bc8b766dfe847dc83cc702013c36552d0913b766f98ef168a37d08f08c56edcd9005f6dfd07c920c4c63be3dd8d764fc1646f0c38c8352dc64dafd77894dd711b836d94bcc6af9aa30111a22e48b210a0ea7db0597ae49ef70d37f90dc76034170686c994c383c3d122e612d6b0c94d97a7e7c8c84df06519c081d89ab3f13e52c81d47e13d9e62c6889a597fba2792e6614851b06d500bb09bf87d24c9c6fb0602b1d074886357a5bd390409878b93169a1a909fe76e96fc2c27bad6395b647d26a0d2f458dda041a1df9d3d35ed519f12c1a421e9483b1a5dffd98a0057cab66c7e4bd8ef53df5aceaca96022d7a29ff31abdbb9945516bf228e21ca59ac18ce8a55ebe6fe722313b1d1465f542f8465f07210518c48190837e4b07ecdace3cf3b58531b2d9ca8bc0face6180cb762a56a1141e5198e264ab4815f1f51ebf66c59199869d2a85f7ee14bef8569145936259e77f47b3df611691d39a2ae844af00ea91bd1c5c3fd8f7147c3e46f6148fb0d7951410030560baafb1d5404ab219e8ec0c44f2815a3ca0cf2862b05918d2b777fa517b07e0e1548dc3b5d7f082321ce9fe86eb199496efa0a5dc3c9553bac8d9937975466862290e7f044856993ae88596df22d1caf2cdd98724e0fe637dd57d43433bd6b010a4cc599930d40e53b0feb6793a28b0ea33bf06809f292f10808f4866b58da8b455865b63edb06ff45f32838a9428a4ae6a79dce62acd946d49f43a52dc583fdf389c5958addacecc847cb13a608678439a85d97c39a6a87a07207ea13b50d128a7629d8b69866e2c9521130194ce6f5c84fa5f60b9441f15cbd4e22029394510f78d842a75010bd87faf40609f16a5f07142272f5c0e197a4a5e9729f93b184b31f12687c2c403143c1aae6daadbca1a202ba251de382a4e02d7d90f2154f40d1692dbdd9a012c9044a67cf1cce746500b98cd2b42b61bea8a40049958aaf58e5d0ab3ae17db0d725677f9283d1c8a2cab632edf3a5deb14ae78b86edf0108a2b7f64dc00faecd93367301957597ba94a24ca0bedcf5d6c36e5af656e078fbc9302d830b764720db1abfb76606710afd2875be909148801ce08dfc7f643799b3aca5b81692168338815d8f6125253f2981f8b9dd693a3e1577060e52c6408b531198835a000bc70b2b502b81b5d274828b23c66eaad03e161679ac5c83cdb77b36b17bbcef540d0a0d851a4e244a05bf8c45de0ad7d9f7afeb9556645d4374efae9f913a839d0f5b1dc8a0e1a0b65a3d8831354be6e336e9ecbd6989644b763ac632d84e739f9682dbde4c6458fc9b430156624e6bf838f2326fa15cc5160b75203d77168461d33dbb20ca0577c1bbd17ea447f9d7e12e2f3645311ca0b70b2a7744394af663df86293463144dca158de1a996f33c018e105b945ac325479e8608ba91b301105204ac08235ed0b1aa7598b69d5edee918791e8ea7d77537a356e4083acaf9dc7aa4128ec8072cdf72a33b0210bfc514f0549f22d335cbe8d0cfd07c06253738bb74c60835c58f8294fe22caae51bec904a7a744b2ae1c50823ee776b918e7294c351ccf110cb47eb765f4f4e0b6f0bd3714bb270f8176bcd88c3b3559b79113c10e36e24e39882081860b5556bccffea4468ad586ad43e32138962ed520393973118011ea72da5cdc10ee56701aacf59b95db19a84b7e24f20094371abbda7acffb6a9cbfbdd8fef07fedc5d7c34892ac2b475ec39053a5df21c8a59007695b25a9f741ea59085c16fb5fee68dde659ee4118df4913a9a47120c581387ac5502661d2a9d5ce8343bb825a7fecd96411da2f63c9765e740f33505f44eb435c984e61b242ac62b822e017e65808cb2828ba65baadce5a2d966fd4b84f212ebaa12267bbb95d197fde2ca7f36d39a1c8eab896e32c2fe381db3b39e9d73fdf85927344a7ff0dc0b9687f2fddf34516cbf4fb2c1bd07f3a300beff2f297652089bf83f232de3d256fa9951a5954d7ea2f653a2fc6e87762d3ea8578f1df64d5866d08d527916c821aa3397e6ee10bf9a5c09ea923c8b2e06dabf1a5ff0f37f80b6a558130d9af1af5c5d259df1b6a13f6d19a17a4fae6c4b79484c26e2e0e8fd6b9353ea84917e060c62b5827c556948d2d9d0bf5b38e10a5b8ff94a63b37ee7c0c3f5900867059ff83c993011164020ae9d40d1080a199fae10275c8860bd8a18a60a29aadcb0576c792cf9d3b42adb02d1702f1e806cda89b77a1a45c6c478812475a3750d84e14f26c4a109ad61ae0ea1dd4eebced3bfa2e54d998cac44eb87e56f8426582aafa8535fcc3415419ff4db51cd4d9019bd92030d49def76e801473763f33b23899d7885a1f0d0d15b0d8ce8d004bb4b5b8a1a5b76bbeadf6b66f01c4623b3e8d20a89b1f13036db2d5c414ff3ab66290511990c1b59e9b8fe4da158bf0eea57098322c0ad0c08cd0991d84c38b1e249257b23c54a2e5ca25876602977b9eb21a5a443403c59c49102cb7492272c6fb678dbc285130d6d9322c6bf57ee5b39899570c1124f5d034705d78046f116944f6d955221792cc43867778022675e92ae111871f503cc6c598c0ba3714a61ae8e046c2a64212addc1f971f308ae2e91f12fb70f8cc14846c19f1d28268ddd324094819620af220875d53b89421fd2025761d7655285a596f32b856031b839a76e3a491f5f2281c3fbaec1b351114e056c50dd0566ed6ba9988061930fe3ec222fc6a8bf4d5c63aec87c959f472e38276c6a54ebc94a60899507951181da3f49d4ad688b6aa1ec2b42bc398664cdfbcb7a44b83e726a3b4e3d4ca1c5fa46cf40ea3b8556561e563a16c2450fd6068a34f712f8943ed60d9666c25e4d296093cfec2922e21228d936a0d1760adf16163bef1f3318906d00147c33cbdb525a274d7883d3394308916445eca5a141cad84cf9d5ef6e6a01fe0b9649e00f517fe94b250e3273b8f7766c2c7f8eeca1c687647d816d9efc640dcf2ed240b6228330e080c1dc28bf85f3399a410efe99c8d1c36ae2f37ca335d3cce4f8b66542971f82bc327e7d3183f38596adef1c6058160073f4ad071034c3dce1bda361608751b76dcb9d5c06816225a7eaf941dd8b9e1de35da3afbe604e13a56a162f6e9fe0afcd6a2adb6121230b4f805abe394d8c122ab03ac24121b1071d33e5bde4e00d14d2d5f133bfbfb5dd2f16bd6ada7821af6948d55206f242bf6b2c0b29832f7965162e537e6e90393785c2232accfae34cc72223ccaca13e8f03b3bed01bdc01a24cddd19220557ca2f35f5bb9fe3faa387450cbd768919bb700d6355613fd0849c7350a02e25bf6821b02a08a0abd53a5f0f55e5c62716e6d0272b63679e334939a2a996d3a8f9f0e5a7efe7401eb40029926d510c66f8ea9214dfa93d9b94532b827fe722f8a242c7ca00d396bfb698a19209ddf157c09a058f11267ff3b63679ec77ff33272612b85f3a22c4891080bd5acaea6612da89eed4961d3d729263f2b1c2a223ca36f2a2abaa25b1b2554f29eba5232617ebb5b667535ec41d6c2ac566417ed9eacc5021126a2ab68e4b42f0e3e03732f3309aa426ee3b735a51c1044f6abd0ea578846a4008acb51f0c9740acb36f193dae9203dccec3845835f3a23f83ff13995b2a1d8b5288642d86c438f7b55290448e027155da101eac9cb3930c921722f757257ac98423a2e416f0f6188fa7cf60de063374a230186ebdf14c8d9748ed0844953d617a51d18afa89f145a5cbee8bf1c3d3971967cdbf1c8fed9565b27c13ef16965f308102f3bd17d6c22dc17e0042523aa25d4156c129a5c08ef8c2e1d7ac3b9f7180ebd1ab507ea46b779a1444067b5366ab8049465866588aa51e86e9509f875e52b0bc14caa2fddf014da58b812621e824664aa22453e71cafd1f8300a51129ab5477c2335c5371c9c0d512bb675ffdf53941b0ea691976dc0655c0f6f22dae7c99459e5b8b4fc2c477a508b942df87e2525f18b0a0bedb1d99192ae452164666f1a6f32e5a1ac5c06db2feaf87b6911da179dbd6a7f1ad28425eb668933c7cc4d8a4581fa5647e3e59fc4e9e3e4ee3374183ed760f24155fd1eadfe4a6333e77338ffdada383a01ef30dd33b9c2eb05b0780732f51c518c652528874b11101ab8055a4d09ce65d951b28f0a4f008aae09998f2cfdc52ec15ca9e53cf745b4a7ae0d43c43e7f5520600addcdfe7359f5ba2e87606c2a5165ac07124b8c1338edc6828c9243acbab14344e46ae8f6c14aa573cfcb76ed122de1023ff1b47b68c5fb1e76bd0d35193342953f22b2f263fab63f185cb32ae9d6501c5b019d03682ecc4ec6408a7ae7eff0064ed68c7241fe8cce7ca2a7f62ec84e8a0683a70f4623682b1cde07c0884a67871981de5c4d1c2d04275eb2154b8113e2bae438bf80aaab5078cae4fc4a883e5c59274c153923b2612b00a4b98fbf91370deee72a8f5cfcca4e2908e56cb2a22f3343cabf28a96aac9d66e783654861fd885ca4504eaea752b8999d40cb7718fb8248abe00300f7064f8c99c316ce225c1835030dbc04cc84e14b51d465e2530241ed554f3d1e7d2c4a6cd26afedc0183ed2ae9a6897063d16b84acd0660604567e9422ae446b72fb5a1a36c3faaca089a1835fa46a9ef8afc79e7be3952a6ca85af2480db54de196ec2d298d0e3c9327ef8413e1fbcb61119b08560f9abb76d2991a5e9f67b65ae674c3d6c7b018620910f2378f44a0ac124f501fcac6e2ebd05ce848ff4c859f6304987669a457c49bc33fd832a7d9e051edcefaddcb69fe6626792a080f4cf48887dcea4920571a5c20d5dd4bb0b8730b29a3e863128e8c1c2c9285af15086b136b7fcf1ae3e92b81a383eaa790482ed94b9a4b206bb6e144fefa62532e613261c4b0b4b90bf963f1931e61fd51e2b160e914a3577c817e8d3b8d43b9d12395b37841d0b0c1abba432917fe56f28cebc2e1cec800e84c30b55a2cbeac96e82e62a9ff5ed034ff3e6d9f24f9accf0c33193c1960d8a3b3c091b73f22cded9b25a0cb6fe2c0c74e8a534b2c1c1ab2f8ebb59600bbf20c6a6a1998ef111ef1e54c3c0c057af7693632ec85e84fc57dc0a6da7510836a032d8329eea382bdfec8aba8e860a8299b91f77cdd9634a3f6ba4e4f2e0d02ee2e9771487a46bc774e004b9bfa5a8f395633d8e0225ac295bebf62da1ff6d1985df0371b7c92c9b2b6d9262ba60c1c6cf442f16777e262a598dfa9936021a21bbc0c00790be5c0106d237bbb9b018786745d498a1826114b0575d75e54a2b0754afd83282f53a3ac8a369e0ccb9486a74c21494c40696e08d2af555409de89d4b8ea5e0ca95fe0428e79e3906f9d61e7443c48e6bcc73c93945df5c161062c2ac426a7e816c333393850d5a6a4a5907cbbbb01f6ac86f1e37ac3175f0f41fbabfae80cad8c05a415ffc48dcc79e64ba5edb3e388261c4ce1bd9337e498769576057da935aa59d180b529882711a4d406d990875023650d1a50ad95ac42b184ac0ce3c641e29ae4d807f07b090d4a6cbee5d6261e922a92c395483f0b5a02c853f1e961e3f4be44fd6289193ab506332c51d69e117eb2ec4519634585bc4d1b8fd79118440a7efae3debfec402eb06e1f45089d03b1c1c339e1f47569b7b494027e96b3e5cd17ada2471c8d59442b213c613ab0dd7a78fdb9f9171d50cac28957d7e0e033477182b0cafde449f6a848a9c9cc0a654211f7a854f5dbde31e18feeb23a3a7c99d89e1a57185875a93ca7783917719dbea5ffc7a910bfe4b795980a54dd4880040278105a54d0ec2e681a5a0a2cea7d536f5c2e3969344c4e8483072809fabfed7b10b7ca023e6c4276aba07f52efdd7f5b6f2d158004922269903b7f761159f42fe8ff0840b66361b1a587ddabb5521123a4866025f02efb1fddf630eb3c20b2cc09c790cc8d2616cfb7329ce27f5272bd24c4c0bcb5e5d1183848bb9b5f116870f818ff4ef63052a8aa17366bb4bcc86ccae389caf37a0a3e351fae2c4e5d87a9641ef791f226692f1b2ae618e57f8f1a7c5105bd173400da6819338fb21c5ed49678c68bfa54a5ffbf90acf970834aaeb34b4fd70be5ce21671f1db6d8b3b232916e44c8efe69290c118729946aa3ad45a076e1e2139c97e4c4b101ae1a40a91cd2062fa323d9eac3468f07589bb5d35eb349b261abbfa0d4dfd3ad2f8b2150f1ce85bb916e05e1ef7970041c6656e730ee282cffb0cc2290361324deb631e8b09986842e28ea120c6e22be2fa9a00c5959a9e43d198f1666d40f26c867c2b9833d3ee8262533571590f8b65c3e1abe20ac665d3de079aa2858088d8adebeef9fd67e7e70474267dbcbb392985d54723562a5d7ae14bbffe730c642a96d752f71e39913ca24e015bf902c0caea90bd16e96ba3a5dcce41c1ac48dfbceb36bbf51b66da90ea66b85e35c4e7694864e8925ce3cabaa580c8f1f0135b50a8b7d50b10e55302c53fb4bfdab70f004d435b4652bac91fb6eb4745fad2b28b458824dd6ab834535acc72f0f0682b5b8e3f1120a1656cdb7f8839e595b620b9aff99704888f746288414abdc93ad24034c4eca3e354cb129713321dc360d1cef032bbf5f5342edc2fbaca6555327c8652123ae728481c08a3d08b4564211a1fcbbab90aa027b88d698ba426ec31bd38d471b41e4414e12708d353f3c216014f991d44288d642adda9ffb7dfbe23810b92c7333c8c3b9536c9dc15fc7599843b3a95bf40242b303234b4bcf5a262a989c719b56aec27ac26f781634796d037a4fcb2695794171b5866cc95820e6433119a5d6d80d1dd9831e6c84936a6491ddd59cc8b5b5ac5be6f3322292754fe8a3184c4e5d9c1d06afbbeae2186e5c2bba68d85d3777a9fb21858d4ba6e3d3d38ce2f8f6286be45b86ac6482606e9aa1ea11e281bf211721f5ee520853aad06ba75105e58cbc87ebc83869a98b53df83cf5efb1c2506d38081ed5f58585b0542587808e57d960f88b00868ef52582c8d0c3ddc9bb00460b808bf0ea502a200d43951875e4f5e30cd374c1e9583275a4246ef945ecc80251407c6db439ead0b4ab15ccca6855a52c95f1956c633a0b4e3d81867363df81c9da8124d84f6605cafae7cc882e5a82316559d7e7eb30aa424a8f2d9d2ace04924cc904b91f09ac7130e4c35593ee207b03274777f0874959977c48be8693dda01a23243d8ecb218500399c2273284e48b8fa48c0da67748d1418d35b92ae87abd8ba873a589b3a3cf4bfcf8a1e2b595b01cef5a87517938950851f7883dc4bfa5459e3be73d4cbcd54bb271103161d2198649922923927c7743928129493ebc139b7948195b9081b95767030e71ce5decb93dd8f374e08bc54db8682a7e05b54bdce51a3130f9d3f3fa2d64d510aa083584d7f689b1ca48d62bf220796d287d0895ec9010f3c435aafc7f08fdae7589e55b2e5fd1bcc0b172263efba217923525856525d7d70acb422192daccbba6628b6966f947f86c9022d7f55e506c67b25f200be291a0b769df303edd8eb26362057a70b20ae76874a513dd9a40b32490b6dd74621b80948c847423fd061cff206746bcf3954415af77b9061c5d8abe6452179e098d24231e9e25067997a5d4ff5705942282f91232b93f19fa27c6ad0370a2cd07d2e5159eaa9bdecfe2067d66675f90d2267efab7e9f9363cacd2d248db60559224025096bbd435de84a48c139e2349af0cea30283608d458a2a385dc43e74fb03c3040fe687a5fd573e9d0192f309a233b0054283e959c41e0c60f538dd0589cc15e5afbd4da26bb88388b9b2a954ff008905871943b115a28a8871478e616125c38e46afc5b8654dab5b5fdcfedd7f0b753b0d5b67b0b940b81edda0867efc61bd15b8c0f929b8a17bcfba94c087302247ad6c617917f26ceff6a74e6ffda3e113ae60e97cc0bc49d9b8ac8503c57985da5cdb5b917acaea8250ec7f3f900f97b7fca882da48c713306c1c4512532fccf326b593a46a05aa9e01b9d30c9c245d71ac4201a064a1e4e7575cf9c900b296389e6698178c4c6a678f4394e50a000ff4f0165b54c21875383cde7435334e0b88d3b763381a213ae2101d04c53ff62f828f91d7337902c52511e0ac0ed1c83694f6330014cfc8d95184c294aba1345806c3667b41ac47ef2b29fdf8d5bce78fa84af518ea7e2cf329dba195f51a89a3612a75930806807bbe0cb80ba6897728ac94eda834124b9720e3443e1d37c991be621c3afffcbd4a9b58688a75f6067be93f0af0d9152c90fe2753da8b8b43d5767ac75da282d6c3fd1b71a1a9489c1bd71711cab4f090e459ecbdcc45cf8007e174ba4c5453fad1a12bc8b58a724c9eecb4e9098691e49c274df2d4b92474bdcafe447728d397aafeb627eba455ec080bf830f95279fc38cd9431755f7050d4cf23491a8122929e31b7bc228d2a2ca273598c48dc13cd941985e1231e2f0ef927e8200934d83fd0ff316409bf94d6c60943ce244d2ce9b8fe652737fd67c53b0099dd10ddb46e0cf2b6c756a75d3baafadbe4a8155fac1ff97c8dd2a312563d25095f254693ce182fadbf93bdbc1d5b54399b0d43b4bce59199683770e5ace855b39a517c35115d6f10863777aa30032b5929ed50955a75cabdcdb081fba7942e929a3af10ae5afbf77c7eb4233c0e08a7369fd2a42023748801dd99d6d9b84414894c8dd42cc2ecd225ec8fe52b13fc092170c3c39be1774137cf614e7d3e117e05e95d648765763b604c143b572c560a741aa96c93cfce9549c875d05e999c34658d54a130cdf863126f24639e08e8d96ba0822b364401fdbac559ee330d81b14a427f3820baa50c145f2efd091cb560d626632730380a63ccf70ef9437092458508394712885d61421d2214da206f9d5f672d206d6d6e3413056d34412eb5a52b0b7c37ffdcd75f3e22fd36825d7897b0b93eb3b554924ac42970eb684e8c1347e98f442a5d044dbb3f56e31e4b1bde268e28f2414882c46c1a0b65a2adea8a5f21d27aa07823bc1aa8c7026b03d56dbb0be649bf2320efcfa21d88d112021f9e262e52c811b1cc61b2d78ffd89382adc9a668cc2510ee53267c95b210a2b6610c6759b9d3c40e90900a4e04987233baf39eb18fbc1513b84d54df85fe28bbda20ae555058f7a6e13ce1519a91f78d24d49f67663e01be2f6b6eba86f93cb2c9f8142fcc1e2aaaad677636af5190574ae9ae7cf4817afe9f2f0b75139b035c70780fa4aa015ce21623559395ab7388e8ecc1763018dc783ce308d1eda0ad44437b4e58fef345608784117675615b8a2db95fb8fcea4ab979d4fbe08a621118af024a1a915246da6c0529c06f92028c553f001c2a03a9f5d0f0bc6eb5cbf712404763a02d5c894742b3601c0c1e93d08adb178de32df03cd95be63343881703955fe50f398c7a72c5548d23a7261927562ad0c212619ea106e8c9613fba38ffebf2684ae42a6d040851b31473bc48efc335cd000a6a15c62f6cdc667b755d0430f768e8b0247f36b2df8610ff969156057b43dc4f6c0bdc910121b659c79265a883b55663155aff06c7a7e5b33e81c157210222a23bae30dd157ae530bd74cc3523b38a582039fe058b53277814cc7ad9bc76e1c65c1932ea76c8d34dcc7584a5cf2ba9e576c22c4e9245a44ba71df510c503ff1005fc9a02d5b4490a5ff94d78226f03ad545a68767cfd4f191e7b1e1a33be873f5a206415200c761da02c066b99298e1714c5178282888bf2d8098fd27ca4bda6a5d3f221e547b75e2bd96652207e9f0740e327e847419a1b241afb3764d6da8b870dd292c4f30d3d454ac0c84e1689941a78c39252cee78cf574a5318eb8706f7cafa373ec469a998b366bfafc91d4174ecb63320689b7f932db380492525070e62612712658908b5c508b9b763a6e61127c8df619e3817eb1073c67da233cd4e870ad97ff2ad43ec007b53f90a0e20d5651e6bd5781169eeb0f6b24263ec4261cdde0c6b6408b458d6139cfd1dd85d4e861844e9dd36f4339bcbb08ccf931abaa74291c715278a53169248d914d6108b91fc8e6196e6ec7f5c2496df3d6955110e420a2a60dd042b80355da97d27978e5902bb5c52e82a049c8f691644b5b78c3d74a85c10a21afcddfd31af244e6d30e14e0cc41f734fcacaf9a091188184693294928adde3b2817c2796db1e05248b1e2ba858eec795817368db7a7c01e18d8208e6197fabbb1443dd6804256dd3ce000fb413aedae5cdcd7c857c78fde2adf47f361bb8bed915aa2d75dfe039ce71c75b559c35c413495c834509930c3a7d1c4567fabee8700de6b9e037c331dd331db5ed94a8b849d0aa7cdea4a167257647ddfee53b1e3e799b164df6b6cf8940e8535f7915fc4941ed328a15049a6bf3b20c6921a6d758ad8a9ab246a184bc9b6b458336656d87739e16b3f7c4395abd36da726028b1800067cc6803e516b8ee0118a4a094b70a9c67ff7178db297af12a60a3cb45c1ca3fe722562b0be942803cc68be0569e4e6690c45f112db041913dd012a50accab971475591b328705e21398d98447eaa288f05c8014128ff10d0cc94252e31a5c0652012457d288220eff51c4b4f37e6cfe624d37c7ef6e9e54c1c21a79c4fe41f4aa1b6b21cbd738e8d29502abb89e5e8f6017b27579a9bf12466c22c41440f700a54dae58d963439f7578ccc4bb2d252ddf22aef1ea7597fb7304eccd43fa02aa91e2bce67b06e7225866fc31cc0dbf6ce18d5ac49eedf32372efd350b368bed7c00668e9102eefdc77efa353ca6c2346931f360315145c5a1814a953dde44b836876d0e115b028f598d0ca5db361615be32ddd2b435d4c7966018872b4b59ce655b07f4b724c7b7e9efc1c36c4c7ce347ce05f22152079ef7800584b9888fe76ca6059aaae34da70216053e2c4e05c31ec1394fc0a5639544bc985f60ef25968136f70035c1060df929fc396bf17a01c36f976c538f5206fbc6e8a4150fc6df0f0bcf3605c7965a96d5478c749f4d0ef8184a429fb6e7e7eda0b2fa7b5b4a610ae09193ad14b7eafd355612116a1a860af494e57f95d4adba5daea4b8600d9955ce2932eab751d155f547f43688d047cb2f52297085c427f63b89a385a61a12442c2acb3c2cf39d39dd5db7492af67ac467c54d945c4b5ede0ed64f6b8bf60769c2210bc2de89f071c4c92584b8dc87229ebd2525c55aecddfea46d4149297410e962527593b096df6539b5022f66fa0dea1d06a2b328efb54f5b77afa866b8a3a08eca964739cbb1993d883b511353cf4c4082484efc2af4473eb49371d4d3e62e4df5440a20104891ec1bf2d59d5d4ef7a28306fa3de97156da72c9560487b3390b2bcb9b0bccbc48059c5fb6606b8e8936fd28c731b2cf4f793b85e44b0035749fc56230db45bf41b1611b891ddb8e74117ca60d078b449b3ecd88e613d8856c6954cf462de8fd809154d0e0e3b58d634a818e91731a6f75749846465110d8ab63ad4b258096a9c9d25a75f42d61a0fef31730fa3001a2c431396413e6c84e94a0af485fb896216e968172c73525fe3effafe00632c6388b94afce032f35813e5790450833d03423f758828bd8ec496c8c4d06c51cec1de474504498927454b3584f02522a8a087a371a8a9167341a849e392febde547ae8f15a186207ba137d7992753789e47960fbd1c644aa5fc1343967830646f4c043faedf2662c0f257198907cee40336ffbe10befec215f367528f082e4f92b9e9435d7313e922a18d581afe5168ceac051a7bf54f0819e5fb3d9ab99103c9c35f4f27f9c08f1b333febe71050d0622340c5e7cdb992b332274245f107267594cbf29c62cc5a51bba591cd1e462d0ce13b51861e710cc9b3d46c3755176f752096852ab8c5da6a4928250f2f0e58a39e31dd0f5ad7a2c15970fa1672f7431c89e6162f81d969d463ed655ed2c91375fc166c1f9560f35485b7972ff2be4855e57dae89a4b5c0f83aa139a6fd2bc4fb41dae61d8b512ed6f84ad6f553836f710a4bd7072fa76de3499ebd8158d559880602ea2959ce154109c60450c861158635a9b713c40ffc259350593ea4d0690c540d37db29bb166b96099104f8b42625f732fe64b4875fe559d2a97cb112aee966edb3c17db99cc8ed3d1cd62b0db7b857fdbc185c9510b7c6e74689abc599d84b7ec3dd3d4543b9288d1a1c92721be961f0355648272c40f04ff2152131a0ca11485933239d5d61d94159c5f8c3426ca579f48e1d7b001c8827fdad92243567900de6c44b9ecb299f3c6d90a8a1468859dca673ae3d4e622df8bdb1a98115e4136ee241ecc9fe5ffa1eb04e13703648d626e6984232be47084d8b8129774aef4be852c475df158b366808a2fe0d809f0a7670bbb2430db6a1333ec375d842c3d04e7a1e9f1fb828fea0edb58e14394eb3735b0ee096b3801371072638558d5e97ea2998720dd3813f1aa2c0cf4fe6267e67405277579c507b6c3d0be72ed44c95a1e0322a7c8e70f97d97e2648cbddb0c11f12edb97c37a52fc7d54a71457b49ebde0cad0e375826ea5e0d563c9b521bf7f1a63e75197724cd5bfc4654983a0aa1b602b3242e6f4887a338896130431a28cbff1a1d6524b5d66dfa219ae426209fa2f2eb24ac563494f148d1c3ee6a5c888543226b399b4f04592222717dcc66083709cf74810b1f75d2acaad3b2ed2f39c2e6a271eff473bb28c710ad80a0c3feec8dcfbc18d5e062a2d89162d15d342aae24ba42e412b1ca5c1e7201a7bb6c9c28c7f4e662f6a3e506e60735732b8ef27def67dbc095336402b7437d97fabbd2aea13907ad5e440340870d272bf00ffa550e65720391695f18048c1ca078765c756b297db6aa02891ec54f923460306639f34464a49cd852669d3934c2e58893972a2714dd96b6ed9cb4ab280c3ed09733ae2f1d10550940577341909caea9fd1017f43953e6af3ba1731822657b9b7e61f7b9cdd6a26e3804e630e68896484a5e63714009cdbdb5201846093048ca86e3aa8c26d0c2fc9c51ec467cc7503508f1f33d1779af8f745bb9d6b21c4825ad7e7c6651587867ac990c2f1d18bacb48d8e971d96c784eeb4e2068d33031e93b40dc5c10e419a2341b988582aad415527199105107436f4e7c36ae33d29cb312cbc2cde6309c0055353d183395898085f6a53756a6d69e012f933df3aebadfff73dfd20c4134ea60cffb8a75dbb3e4f626007020296f63cc545ffbc6b192ef244b38264a0ce542f66f0f923e093843db689ea8819bec1bd0047587f75971b887ac6bf1d72234d7477017b82800a14cb42e599b7c8c00d9179e003b296ab1c42caf089faaa7023a037b0435d3e981e39399a01348b29450f128dc4bf738e01f2fe315d20e9f4f059595f1dccd47e4907093cb017408eeb0dc58e8c880dd0edb56a87c4dc6c2a401041b1920cedcd7046b3470da422c9a0ce7c8e4031255365eb7d4c216c5af1f27414149b64f46e90c1c34de39fcff676dab104356b0245e809ef0991e326e37ce47124141870968c90c9f2c20eb01d313059c927e81f22f0f1e2efde2831944a02136f230424426ae4b89cdddbc3b161f09234fe0b8beb075564a32267cde42d061bcde8a97102a4b4aaca41ad7d56bbe26ca501081577d792dd5b0e73e620cbae45df56d41bd3617ca38a3c4037523e920a2cd434b1f104881fc8cadbb89cf9b7a73f9fc072de521d925df5d352a8e4554c5818d314a9d5dd88893c2a01b7c24fac6760dc9ee024c6eb592c0961611857689184c10c85034c56e82565ec06c84a99d0696fe5156b30b4138aeee8d79163ebd3c569cd3a846fcece037da1a61922347d7d0a96d6e61dfa6c9640142ab6d7cda2a1841af9a2b87eb41187c7d032fe0f0d9aa998d094835063308838fbc5cfd98fa1454695bdd2e7348bb3e789b15f78d9de9c384608a6f2c275d9c2628ea1d973e020bdce13782cfd506197674345a0a820990a6061cd98447580997a1c86aefc511bd34d9369f5a8e1a5d62afaa008ec7a832bb1b416820f11bb16a598bcb44a682696837832159ac0a7b887b56eb2e7d1e4950475e1b9613380509a99a650f80cffd21e6eddd84750288521f8e79dacf4ed14b8e364fec7b9ada27689cb28e9c730d020b1b37c0e4647383cd4e136c202b3c966142606c4903d5d384fba4c4e29951be84a501bea4d941cb1713152b00adf6d216654a2d7cadf3501d631f9aa73c5744eab1b6f9ae6064c9b387c9ce8a90341f5c424a129d6a7515e76eda5a08b71ba25f2ac25e4969be471f8844df1ac48eb29f8390332661357bcd4408063a08ef3544187ba03cfd85d8a13692aa50da61924721f9336a2c2d015ae940e85fed8f4174ac8eda8ac08434bca2881fa47118ddd67930fb014de2894f60f643d30aaef5f0e0087aa44e50113e5af7263e17183193c644a72ba147847cca26f4b944288bcb52c5c0b66cc95f0ac96b768193902108131e838f457fce6d430e3b4bbf3beca269eb0fac9b52719b2f29ea3a2394ea4ce892f937194c1dc846651cecd4acbc3cd5f3604065490896f6142c05e1abbcece1344b5d18b317d996ad4e6e38594db2153b85b28327f5ccf33995dc7808e530dfd9b1e33c68c556bf8f80315e0a102494341c807e67fd8414d335ee2625d82e9dac5a69a22ee289b1479ce74160de59ba31357ab564c270e05753b9394c8958133c7f56de960d64175bacd6bb9928d4c9ebce9db44b51ee4d4613964686eed7ce23c39e351b5d2fd43bfa9c27af7f7ce699859e8819b4c6a847ac791b57cae334efaa152bb62fd67743f57a2bc5b65b0c68358827b206aa5f80aae7176fa170a357afc9ea445cc1b5ff700ec8d7f73eefc97557c54775a518925eea0fb5417c458bc7add07e518dab7bb1660c592eb52461ef555e7de6e5badf06f761433bdb3431f546866cf950e4842944bfb0dfb2b403cf92e282c8d084cae5b3abbaff972fd7f1f3988e6ae66c05daf59d482a3cb776fedac534afe3f5c2cc9eec4792346e69f1ea56fff1de92bddfd481977719619db26ecaaedcec95d58ddd609ddb58865a44b4e687736a1520d2d5337513747b67b7f6ff1cb922d48e77479e536e1b6dd10dac40f62366ca2125be581166205d63aa9dd463f59cef1742e56d58221dfc6ea59d29ce54170d9b3086e40f70fd4836063ea081356a38868694c103031d928449c5f41eca47804534e0fe1dd5b36a5f33ecaff65ffdaa03e6bb4feb5ab77a04d0edae1602e69a3aea3e88039c04aceaad82bff4f79c2782c8bd7917d50eb8d268a7f2069a64552bf2d3c71402081941d12e195ff3ec4b488f34ce1956c0bd4f9b9638ca16bdf10c8f10c6e0a1e96556573b863d4347c798e0617f737bf6db1b1f0552bef43602a81b56511eaf5beb8efff647222f916a74602e6812c2ef4cad15305dd21b0503c4aa3678c5e4232c37a13963ac3a0167942d102e754c6897d97fe910628478f958812f58ada66f147a216f08cb3d4d9d605a0b2d5f0aafa0b5bc9e2c79584d229576994fc4b8cb98ca3cf233b8083ffcef2ec16382c93c5419f8a10f9ca67a15fa517de8a1a87af420aa0d99f3c3851788e9bd76bda0a40429b740b360cc419831c33589b99932a39dacfcee9c1316f6ce4ba7163ca986111efddd2d05c345709b58cadddb963196f5e347cd52c44d00f0a5adeae0504549d543b4c17d4802b1d6155b302a7bd0868da1d7ab8907ed08cef127e991d9205aeeb2f5fad1f13946efd9c0cc2d716da49bb4064f902b7fd25be6d5b5b6b44bc7f7b49b6245ff5101a6ac80f45aed038d2e40ca71783d5e15b7fdc7895122458505f39707a4b48116080202c4ffa659df1d2639a0611d01421462b8d41427d918d39048600a0ea0ca69fd8fc3994316ddb44da49870e5f7ae7b7a674f9615ae2291ba70d05bb59ab01683fab97d5514057acbf8cc2c4d95c7781ace5d7d701f1913f7d13b894055b525ba43e967b74634c302273000fffe80d986ca5758e59e07fba5c5ab6e9e0597b6158eaf059f099f5dac64d2ca2dc6eca1da5056a8f8d7cf1026f1521ce65ade53fed44fdf234880d7364ca0f77aa8426f9334733eb7287d4bbc4c648595946dbbebac8f63be8e928e7a022a346b7fa1cbe472b61a598ca8866f9f9eab70a03f65dd73db75aa4ec3ea5f9dc598b8f28a5e161d94513886722f5a358dd65d20f091d3d84c41cb48dcacdd239802e48453da052154535138f9f63ea8b212c13d5c21e4dcdfb87062162e6665fcdec9ca5c5ccca8a90f57aa03aa32e547570a2ac08f850ba0d48d19eb8129eb9f0c303f60a0f074015890be1fff7ef2e31963a6ca97b75c67a061d22fdf0af0a96af4d9813d1788c9002474ad24cf62c2defbeb305279d632ec9b645e643b20ff3f18617c2e481eac308372de9461c559447bad51babe3206f4831b863b68ccffa767663075236985dfcc74b7c2578891614890caac95d96ea8cec97511a8b422c5da9aaef3a04f2082773f9d312b856e035982e96fe4fd86fe217eb825b13dde4863cebe08505eaa3bc86f84c92702b8ce58308e54ecbdb817fc0561ae6094a50e698da0769f657f68fafaeebe65d3238934d98cd9e3097597a3e8a5295b3a2c39cc92ad5c4b25ad4331f254a7b8f376171cbf4592ba3f6740947284201a11d403fa42ff0fa16377c1059386fb548640c48428cc13591e5f3bc9b3836505ec3eeb09372b227a339c98ae9e3da10d87f0454fc6e0d84386a4648f41dd6f6bb61776376933f40b32568252a870d236d36fd7beb7aa09689317dbf945f6aaaaad5d0965259dc8b3ae16e7011d957d1a09e4c9744b6a49088637c848d4904ff820e6655dbfdca5675e444101d1d84d5b62ae60aae5de4e59853564caf9c5cc5102927bd68f02f86e86036952754b557094881aed786013fd8949e0f533c4221aaeef790b89c06b9856047d287de2f7edfe35fb821003c0941a0b0805f7d7e76eb437ec8b9b5c429815bb7e043b94716b73632ec93c9939986b35aeceef1e8844f27e9bd874dd5ef30a520a4ad32c47d50da8e12217d7cfac93388fff4d8d6e810935ee82c723b258fa32839b5dca28a0916222471285a75a55d23327c58ad2e812918b5828dbea38cb9e437d346f3685e322ec9915011aad59ec14a7d8052e9a8b328faccf983e533b46b40fe37907f2790fce50d27b83bbc0475899f967b07c98145821e714c7c14750c071b3b84299bb66a1127643ae30b8cd096b3b2ff78cb43a951b370b49b39d83a4c94b3157349af264b313090bb0cea754737f1c02f3b6ca0b94581c60805cc21a727f79431d5edca3e0930cd2c293cd2957c38925e11927f0510223dd9f68d1af45c1160f3c964c762408d92436ef4b0ad54a8238165afb1bc55f955c97558d39ba4b1ff78e3f33b436be0bbffbd87359dd1954f65b2ce1091ca2092312f6923fcac1cbcdfacb3f194dabb95f0ee102c1789a58bc0959e9c480aafb76331525b7643e821ff84a8088e610f66c7c3da318b7f79eb70dfd59b18275b42d9de230ff9cd7c2b5db2340e6c97b8c95c7629d943f01d6b6db3a30d575ed40de52139ab1746dfb016fe338ad6be7c3bf9662c276c818a804e65ca4262a2c7dcf20f845c07e5a5e041c1abad7a5d89a1f02ac1b522f88fcb42fc394f3fe799e92a3c90de2a3c9483e23a1d28f48f435df1c0a06141ffe7d1ef8d811226e18816c6e1dc171475f4cea1ac240309ecee067de71f09cc1c4fe8aafe20eb8b38b97fb73af8d54856a052548dc2b3f441b01e9a491474c334440aed0336e33e551a8cddc041cde8fc177b21bbb1eeb998c30fb5bc788103201f2be3ed5b1c5946cfbea1034a925d7918d08b940886a76298a43fe71ac0dad45bd1863160bb3623e31750b14e27a1175cb1241d3eaf2854c353a9394ad861990a8c2484ce3fb3bbd0991d847a615d8de180d0d61122dc1442200796f4035be26547f74f2793b4d139e2162f417dfba9c5acc4fecd4c8a29276784a08abb1c934bebcedf60b1d9bd956232f3f43ffb1e7c92c46fc0e3e2faf928c862dc5e3e9e85a29ca44cf8e1c90b465826245988671f1fa5c1152031632098c3b9fb5276378ab349760fbd1c94684b9bb776bccf5464d380ce0615dfcb6bb7866eeece129168a28ff2a6f42fc617fd3c4d959d2b6d6a5a8c269560a0b26a1c860a17e2493d27e7a955baf48bcabda85474864aa417dbe7878be236f31604a138e0bae5005714e9550810cc00ae8bf2c1e42132d2606ced79b220be67abc2b2ab651d62e0659583d3257a7109f54f2107f72724739182c7a25e2b4e793098f3a8ecd79019a9a4b25827854bd869a1a9d4921edfe85326fa6d21bd120b884ae0547420031ab50679c8fe0d204e36c24328db1c93cb23d4a90a00eeac121cf49ee2d3c72bd6170917b5580cf80030142ac3d208c298d7bd96b9b686a7406d29e74060f5e9cde94ae35f071017665abfde276af7d849148caf77bad0f02e8b0af2914cc2c20c07c6dfa608cc28b7e5e14719f6aebb649a8b8a67c2448f73cd6592ab038970ff7e95d1f0ad52d4244507dfa9afc580e3bd5240ce6f0007b742614824c631b6ab27f16b2774d65dd94cd586729d15b8d3d23d137dcd10f7dc58b0cb26c0c177e5f6f46bff4e041e4830d0b61ccb991094a3c37830e77b0ec9ffc1ba45938f010367a164697b133ddf6b11f0035598760e31d807f2cf257915e3ed334a56ec837c75ee26c3a27876b41ac39f6471d0d38f3ae5de1c5aee64411a62413102d080f267d0a1f48891b89c0dbf15438248dd01f3f20c4b2d071c0cbcbc530562488017c68c587e41354b717828c36fe748611fff3a609333d9034af05706481f8674baf95606cf7cdcf2543f599622df73e85a3e6cedcbce10798e082833b10cbcd26d5ce459b4ecd1abc68744cdfbbc0c0f27b0c307d5b0f132c91f75f08b1eb3d44c256f2563d74f086d4120d189e9a24f4f8d9a94f689f53819e319e987e72ea56f040b23a6cac63ce0ac8f86e6031ccde6b9a8208835812daa944425b58cea11e759172398a153c321d6db503c362d3947032804f9dd44aec42d7f059e190aa922e6520b158d47ed134cdc491fff2482518d688c51c28af6b184b4c2c2ebb456841d02c13a4a2e86d693fd0775c7d5890ab6def00830951908c5a2d84829c5c55f5d5c418a3050ac9ff02551057a38e87a8034068796f76a1cf7a1aded96761b8ee0a81f61df8074a47a1b98587cf9cbe2792be5d903f2fbf94378a20ef84226b146f61d27e9f2476d7971e9ca40e4243871bab6cc465e702b83728c43b0695db5260ebd0e7881ee1064694d3fdbea1ff546c947a100d351abf0a6bbb75131fdd80a1db10d1289665a90375a824e6606d0d3b3822f76be196d087eee472042e46cd323f354d0819cc5a86e0d6002e64bee03c60f8860420466e566b804dabf9a4fe9b14c6b2ed50640abeedb64797c7114a7f4cd3b536539617cf32afa52e3f1a66cd6895fa38226db6abf3f320f089d4941a82003e78f703aadd8a9dabc320fedb729cf5e67e870704b6249a3156863e6b663c7b8567703beb900d81e40d18dd88d0dd7e8dff3d15d28c2912c3a222b6544f1c8218d8a123dd997a0b9785440ae8c2d78653d5513f10dba02d4f8b7c428fc16a196a846003e44c18883b9b3dd03a4426cc4c5062bc6929971146aa1fd27a0292e45085588c7e240d64e51c854a082c9bbcd1e42f701c2a3ac23b309c8700c74b13ac39000077d86b4b1499d09f4c80c7aedc3d29cc140801f4479524955347a24e441897df77cb2d1d7366c07791dc24f78aed86a0c8df944217af9f23aa4fc2c7fea3650794515bf3d1833101e67a30b27de32a451b04f5e4d5f554465a16f6cec0486eadba05c58629af47fdf5c7f3b057bd624dda6cc2a4bd251adecaffe21af3fb5c71703462f10bda32d39c4d9b39788b7be8a16f913d87390a1cc5fc741c17ea0e87f1be1191db8c3e573703b73606c7d1209b5c34773e12c4c397822c1b332805271084d2c0ffe2538a2bfff08ff0284dedd1cd00d11bbdc914ab3210ce003f57204b820e1cf29da35a110a41f4dfb6e161034b53f15b5016ce078cfd74a9242fc71356177c3c73f6a790ff1cfc28a46d113783f39f1a6197b095bb2ba83c35d429cb7155df07665ea65e39c1fc3c39ce3e9f9772354f2f93df8b25a27025abb10f6ab16d9a98da67a44d689e2732cdc2b153c8305124bce193775da12e57f69810fb58acc97f4258adbf7372a37d1e2890a762d0fb9c2a399329d040dc9195a72eb9ae3769f8203f2ff1f445ef84916e460f108cb11e8b4b4fad48a3ea172704225f85b7795f02641168ff9e8c8ae47a2a5486e4195cdc17b0566636ed9dec297c6a2ce9d6c76f55e49151bbfb73cf642ddc5ba81c799e391c2b6c53920aeb1dea6801f206da5eb0e6c5486c4696ca544b006ccb2e5c1b9942c7ed958a0d9f634c58567f219ee4ea7676e57aa9f2dcd187d2e333f2ef2c188190cd2d4e8249667b3e7bc02d7f7d657d965d641f0a07814adf21af807991254f2cf5aa6e5de9ab0cb04b7486474c8e4c537bbb34b96f1f510f8c1ab2392dc69d1f272c0e20aa959d3f321791f6d586fd9f604545a2ad7e5e7a1559104b460beebe964e08fd34cc2c1f0562812234a8156cc7171d929767e96910e555392b02d276321e454d4220b0b29f4536c1a76c54dbd024c1003eac5769459204cd29a0e893213309d6a0407e4ef54cc887b90edfc5ddcb544b64ea506f04f8dd72c20cd06fbfb85d54fcf1a183028f03b83e0f78d15f3dd442157c5b63e1c3b8770897bfc7eaf9734273034d442dade6d4dee2d65923205430ae408c9081946b364fcf58da070cf53a559937bde7eace69ac1ff3a103b9292cf8330330ccb28e9f34655aa4ce67d7d1b2ed5ff6a6765df6ac9fef3405cdfa80aa68e846906b1eff9af431cb11e2bf688a5fd9f8f89a5fdceb1ffb1fff3f767a8e38e1ddc977d6cecc07ecfdb5087fd9e9f2150eceb38abe8fd950105fdf723dfaf6153b2fe7ce720eff91ea09e71f623e2d0839941b80ffbaf962fd0157a3033ac2bbbd107cdb2f7c62bb3d1d6f3623f25896c8ee4d3331a51c17e077b0bf87e69cb4d231670f999da8c92ec178bb96627d6fc3d11a531b113932849fff5f46533aa825bafe4727d1fdaef5dae9af12bb912c5e2ccb00f6a0e45d77fa20f9a5d8f6533dbbdf79f272e75ff75b6b3d7f34173ad5d494481e88b0a4ac7dddd07cdf3dd27c5e170381f340d9d243a44f3ea4c1d3b6b8e0ba8a0a284e88a8a2748aea820e1c815154e49ee60e1a38a12a925aa94e014a5c906ac2b701021ea0b09b2c043c5c3f34275b2738838fd40278c151c1a8e1049d4809b020725a6f090e08ae20d79d121a182a8393be820468e172c7cd20c0922cf111870b0c3039e219f1029ebc37d3d5146c9054a3966a4b9c3252b4a0a239a10010c72a6b400b5244b0bb75a459d5cebdf2aa8c8f5411192ea38d1935407091f6e529db1561184ab8a1b5ad946529d7b072acf72e7eed070270c115d561554c420c6eb3c712634a3b8332577278a5f9db903e50e132abfb366cd144ea4a08273f5da7aaded29acb2b5d6da3676ac68aded5c5d9c3d11bc94b476f0647b870898ed636bad65833b97f74e5135050c5358b9b91caaaa92baaa54077795243b13529c905b02c772e7a470ca65e7d0d4b153bd3a69ea9cc9a58dca85cfbba7e91883446da0dfa3aa8dd6dfd9bd4eb05202f477ddf8236a83be0109e2fdfdeeef88f3c6a8f9dde8efb383faf6dd5fc77c2b7e14f4aebbd2752310d23b03995daf75d35969e704d51262728bdc544be0f2079b2fd236e81b8db6c3fe067db32307b02b164b5b0e2c04fa66c71f33aff595178d92e0997fd07638796d477badb3b2683c3a2babb3b2948cb0d4a8ed5b140d83f18e738e340cbc03da95237fb34fd331c72b760c12b581faf3ed13a031255b6c4a5ec105e9de12a0f441330674eca0df2f25bf19f2c076c445d50f1245d351ff6b5587eb58a82ad827bba4a343c83a30778a28b288c8b9592344ca03f058c1258815b260e5b8743cdc89b34826763535747deb0c15cf64d891dacae0b563ea5e79823852a74c104bb2883a220acf0b35e48172449d17b257e749963fd1b960c6cd24cd392367cd8ceab66cbd6212258d2839bd8a64c3e170436a145172adf53b8992f36d4ae02e436b8d86d62e9d35b4d6b9c4f9fe0c97ee2c7be2054a949c1620224e5494253830e1722b67998e9d4b078bc89439533081927273cb22e98ca523a7d2b9caf5412c72adf59ec1b7da92a268cd9933c7eada3a04700c6038b9385fa6d4385b9ee2b0d024ce932570b0527803274d7ee5cec121e206383824a170683002470627382c50e960bdd9c92913a7eacd1b26eea31225e79b239eb498375e9e38116fb42c7122bc377094bcc1b2370c4124be19014a0f3ac44922829b1e2c0ba8c218918b838788245ab9736fb07816df745dd064acc4b829e341782deffefc9696232d48a902cf9123f75a9dc917966f9e7cefdbd6a011410a0957a8c8dd70bbef605c0ec404b9736f84e42e77ce0aabe25c8c8ff1301e86c8739eebda5811b9f9d2e6481b9c9d65ebed8f2e774acb99bb3a766339ffba3a3be783d094dd03cf1d0efba57defbf9e3dfd552f761f70abd59aad2bb6bac8ebbcaef33afbdd5876e06fbf03ef446b45a6ce55ec3c43cf75bc5d64b3392425f9977b938888fc875a89664744c4c68d111c1b35443a5786842782080ec2e9b21133a44eb1f1810865d3c5c8ac6343432e6d2e183ae7c1bfa1e092ddffdddd7bb8dd151240c38412244da47470c2668606d44055420f6cd4ac3086cd0b2f54b5991d0c682425af5f35ca935228b0a8b12177e8a38d925e308f0748801e953d8832be94880650ee1c9b273638362290805b78dc097752b809f87343b1d4e4b27344d2b89033221c41f10ce148c640f942a728819f40022537d02aa49c890cbee4853b55ae9842ad8042b368d264047f5a73c4c89a2176b23882ad15940a6ced3cb91a22a704ab11d678912a4f8286669dc1a28c3ba1ca6553d13cb8e6ce414126ef707728c46477dfd17947cb879967fe60369b51d2b4d140cc7f2272da683122645a025ce28c65b369a3c18890690930fdf9a598e7d3bfd3467f1121d33fb23fb31d6f4cc1fefef6bb70c9cecffe9ffdc1f9fd5db834f3d7dd2b0f90e7622806563c67b645d0eb1b06e3854f4ff7236bb9c2fb3915a2650dd09a8c0841a20e940d73aeb0304a5125e74411615a786385cbce0b45a4d182854a490a405b6840a10bee0a0d60f0786941b740b9e224a584942c12c80186276d6418038554155d28087ec0e1c81635509e7e682aa1aa08122728389899438597518d179cd58212639c46103215150128a2a8304215284f577780605b4a68d3830d7060582197470d156c84786ae2881d1898e6082d4370c161c509d96091d2040b3a6b9a98a2cbed291daa729042c91238364eb480040c4e767ac06223050f446abc2229264cccc0e608291886c889e2a44505304da2a8e3e5c7822758c860c3130c56cc6460250a33499a844921cf55979997ac1e6e7841891fccf00081293cb91fa8701802083a968514980823b5c3973959a820c40a3924c166072756a2e0410804236200e382972b989062a38a13524c218182133ecce902f699302ea051e34688245a34887a21053934cc412245ce0b099420a284c821024c1a02e04820030a4d9c50e285385d94551b2d261c59f226eb872c459e903283912e60e0f0f01218a2c4942b3dac61738491932655d8a0a509161edec450e3a565353473010b56191c114be0b020c490275688b83387891b183cdc50c31029ea3c5161a504ae0c1b304ad2a8d0c68b8c6ac49815f294b162ca98322db4907067843448b090b0893571830b6a88a062450a1e5a40cd906b824e0f3a5059e3c55d3881fad2831d2d72a40690c4142a52a428c2ce1c28ba886cb2a24832449e144a3083810d3db46113c52a8a1435d3cc972c69aa18d26488150d0891a33a722797e7c9133e63c26831620a8e0857301871c495094caa5068e3a68a871e9f1db494b0029ca9115c683a4ab08c8952020a4820e1c48b11082104578218e0ac51a2853064ae2011a7081fa69af012d46b6498010e9c30504478b2c08c096bdac81993c298345ebe2052d01182053449c440a6863a4c4439e3c50a2c54a0f1227b40922167a0a060bdc9228323ee9c806b0288222630114e12881099c2a9cb1d2b0ab040220a1636dc90c4cb125d5cf814054cc4f044d41b16b2e234a550248d192b155c70424a09efa12a8a1356a6572657bb831ef95f9092348b117af105b1187a1dc976ad55f342b6f62d119964bfb465233b263d11c56b348e9a28f94e25354f7e9f88d6e600e2e07e028927a872f9b91ac5995c9279ae20070c16484a5872c4845bf9486f660053345144144640d981865b9313192482b0e1aaea09226e34d0a4d0640519a078e3c26ddaf2cd1d4e5b0e1345521444335099e6f63ee89f778eb3c96a731d41eeb75d54eb52fbcdc305bc728fddf4e6e207ddffe4f22797f7031f37cfae61dfc72cdbb74f8e54bb665bb8505a28305bfb4e815c7588b3a7dbea41105c76eb944b3bc546a1247d1b6a406fde689fbc465f480eeeb7fe34c42180ce765d37835e3e42f9f03551e9c265fadf3c3275c8fd954b53cd792322972d2d994abdc8736c497511fd1714da45d681e4aede2e3da24ddaef4e04d9bff3c076244ff4db6d0be687798eb38b6edf8d223eb5681b43b238afd18aeb7e362b2daeb3b84c7f9c40f61fc7e948f6d6ff79b6d2d70d991a8adcbd87380490bbffda5bae56ab45835edda8445d383c356891a26186a82c35ccf108775fc1842473ca30a7a31003123060b9f2421417acb4c04215225054545862ce0a2ac471f718a6387122a5c69ca4302d0a78da28787e43c1f3ed133cdf9e80e75b27b715a3a6a5e51abbc8beeb039b1e893630493664c4f7b9d223224a3e256b54f0fcf2c321395f9e4f5de4247c814d8f604c3c4ef2c493a90cc90bd6f66790ec8f416b029e60d32317b9df45a19ea02878be6de2239b89c90a004019cbe407b44f40a02d2108b424cc5a804d8f7cc81c83d202b423b800ed121a6895088136c90bd022813114e270e5b1c810688f3c688d8823d8f4c80563ca18a325cb09515206133188c02693494a8a511081b6880cd0129980022b2486888ac60b39145c47c257aed7666418325c12b44eb50aa8182220132a9801363d9a3630499613124344831c4fc0f3678076080db0e9d10c1a332aa8cd20299840c60ca21833c61933c49f3104e385d00c9a8ba016b319403366ccf891f9cce88961d88c5708cef85cde9a7167789dad7452dcabbbc8fe8cb0738fed4fd8aa7a59ff521253d2bf7680050bb9add4ca3085c452b0ebbe297f16b42289e991f5b7ef210623c836d7b7a18e9a3be8fef3402b8e2025afe00ad2236fbe176630b3f21cc1b05ec1344f1b6ddb82fb34d451f3fd5aa0fdc074daf5e5811775dfbdcfec5155eafb94925cf6b75fb5981eb9fd4ac91083aac3be7d1aeaa0df811df1ad6d41570ae52bdd854f80950a9504454483540e5a6a00d2725d5b57cda7dc1585a29a9d7bb7e5b5aee7148a76eeddee56cda7dc95bb67bdaaf994abb5b475d57cb2ddbb2d775567bf224182e9d34b8fecdf6ca928399f524a2b755c17cd597fd62498beb5df75e37811e27891bdfbceb59c9956bf29d7b1142d580117e00acff7b14a75d17cd71ca7eeeed589d4e94fd467ed6e8b9b977ade556b6b77e7dd5ea557b4a0bb3b2840cc23938e950b3fec30459612663c284fc8a0f0830d4ec0981026a10390ba43022c39986087cd12515646e0ac1015e6e67953489cb2e721a92c18c9d9b16344ca46f53321222733a127a2edb8df9907c5ddbec78ed47a574b3c726ff75da25391a4dbfd23f7f67da3ebafd87a2577892db10303c81d62d06e728f57681bf4adf53f3a770bc1fd10b42a0ec763d27adcd11a6d1db555a68a90c9e59d3ab2e6dea7bc81cf06a5731ef9d70f68f641f395fb5346a6e4f24e197192296d82cf4c11a9aa210f8abbb5be1da9c36e2ce7917b6b795f7fade295d678cb10721dbbebba0e7cd05cc70f78eef7c91d624041eef14a08ee2bd13b7e47eb109dcf84be3ec137f7149123350af6dc53448854afcb3de59465029b14bcd613b02cf79453114a4e248052c5a90528b527f7941393fc937b6a08969af9d342654a5b98239d0925c1d6ce39d2e6cf6cc10ab88e235367fa72aee4d8b9928385a74baecb975c173262b84c4add6bb55eabb55de7dd7aafd3792b68bbcef3ee6d75a0776fabe5727d600541a7136cb95cdf0782a1d5abbe5e4ee7eb8c0bfc40300c5f2f580ef0d5e5f525d387e5605d327d8cc964fa31313db5a7c7e9ece14249faf4892ea14ee8135d42a7d02368aad0aca94223c7eacc949a59e6962935b374c9f42d973cb1604d1cd6749a38acb9641e09810c2d43a6d1f4372975afd576b5eb9cce6e52f75aadedbcea794ea7576dd779debd2d5775b99c4e97775b2d97ebfbc030743a43d7078261f87ac170c5d8e9c4e10b06c33816ebf1a93e3e4ea74f8f8f4cf6f303041434abb399d3398b7d3da08b3e423ea08bb297812e7e507fbe1fd045a0906966b2836a5090d31974ebf8735f341032b5a2247da617b98ae9a229b89c55316dc14fa66fa3b4050d15803b5feb56265eb777d5dada79b747bbaf23d52ffd7ab9037777f7cc2c6955ea4f4ff4c9da576b5eea7957adadd9337da2b9be806b2e632db0be80672e41b02de84cf1adb5bbd65afdc55a6badb5da5a6badb3d65a6bed64329f24afb556af4cbc9d26d57abbbbdddd7d09936b5adbaad5e5f2008d55f9aaedbcdbba2da82b9af3a7aa2a653bef7a17ea8ae6fcc9abaaedbcaea926d415cdf953671bea8ae6aaad16eaaa7aa56239a168d95455497790ab94c5dd79bd7c4d944245e1e2ea757be9eefed4b573af26d8fba5bbbbd72eaadd47ddddee2ecbee933bf0ea4caa143cbf96dddd2d96b319beff43b98396826bbd607deaeef6d68ba6a395fd7fe45b67ea489929235515cad4903b756a9579e46a6a089c4a84686a486e4a0819aba9216d84d422afdc5343ce4c0da1c26fadbd9d6d75df7ab3ceb4b2aab0b5d65a6badbdc22a5b9b35275b6bbfaa509fb2ae6cd69d22726c1622852405892b5430792187874beeba29213ce4ae6301082b4fa0aa48299946f2cc2257d83c93c815b90b82987e150183b9735837e4d2568560c980b5c2082e42ce6d8e742f5691285779f090e079328e8bd786e4b1ca53e5e571210f542e3f27c537ff9b6288e3957dac5d94a9d8392cb6e46f8258d9c58fce7ed174d85c73fd20fbd839ac2fb9ce10645185859cced95a71d873e7f248c9c234772e0f0a958828d322b94cca14872b686083e526874310b71a56704a204788196060e156925d9ae49ea8b02297e5875b69cb4324d3ff280008c2ca095094206705a71bed5c1e26b9b40d61059115495758d1449e1284105591a748152e72e7ae9073c51a21a8f0dad5a805dc8d0095bfd9814dc199905f232a240d2316704966276978192256e070d78892ee3468cd494afa1b59c1ed33b7a0510b787e4fd22d150e8713e16fe4e04195dd7146d9c32a3c57f98cf7193c59dcd639eb788da8e02bcf8a4a243beafb15ac141b51c1017992a23879ea11fb656485cbf9f414658a13da93361a0db269182d994e3d3637b89cb8899b4e343c7b1a24259de62e1ce3d9ec1f8f0d2b048fc61a5cf6550742f8e163367bb2ebf842331978897239a95ef489869dab1efd44c9ea8492f5bfc9d4bd8f2599fdab184aa5057ff25afdbed7777fa1eb63ff8a7d8719b83e0ca64d4ce8236f124a23795d0ba9d4b4014253c6b81b09d6b59e077b7ac29e3a4326cfcaca78549a35ea0efcde482becf158e30d2ebb2ad7af40067a5c801eb5bebe928b6ff1e59d11cd1afe2ef129e92ec6a635ffdab416e42db19c571f542ab97e4c7c89259d92eb7f624965c8f56fd983b45a5381eb6118866118866118866118866118866118866118866118866118866118e6300b9a85e2cf1afe9f0bcddc95dc7e499f7a10a139c3837e55555555559590115cd2aaab923e59c959d3e283bebc42334a862d8228161f968a4c0e1fb15b4828063ceb3a865f625096cb49d542376462f713cd5ca00376cc60c0b2d9e748ef0249d2057ab1d68e279f886cc544109a726cc710e88120181b61cc1af5df9176f4db946af5a79c3fd1b0da9f2655d0d797cd1ae17f22a664183476f87752359a599291ed476c990c06140c1878d608df916663a5b5f06b796b0f190d92e8476c3cc305cb3bd1f8a82f34039a21d054a264adf4ebc01932f97cf8b3d98c18d34cd7ea975ef6a7c1daa79166eeee5e33fe1ef6f89b1ef57c874bb0ef30832f470eb00c6a794f9fbc5663b3f7ef696352cd1af57d2c7b8cd95fc9c51c3160af638ed8cfea4faa690374ffd8b7c692e6725281d0f4b1110c71785656768d3f6b54aa9ef135cebe67e30efffa938a92b5cc0e47a25595560945c1148a1e95b628f4a8fc29f4a83e7542abde468f2a25c3afffb978678dd03e28d6bff561625312ec7cc4b207e840a24dc263a6b9fb1f71669938b38f38735f71e69638b337f36be66fe60fe971dc07c7d98c92b59c9143fc658c1c36e9a2fae52b874f6b245ae5b5fae1c3fae8f5e1fb3452d0870f4e1bfe346bd40f3f0cc3d006030ec371466995234d2aafd5c7e3f7305a95eb7b93d8d7f7a76963c7ffb4e15959d9cb21a4d9c31aa9c5fb7b1ff5bcbfd7482ec2f777217a5d0bbf47f426c36f21c2ba16fe4c0c1f870f0b614fc325d8d894843d0d33081f368294f431ef9836605ff1c7c6927eae8f0d657f4cb3ff4c8475cd1f2676d7f00f12bdaef9bf446fd2fb50ccc041d1fe2796d82596b77e4b2ced52a524ced5a17ce844e28546b6fd143d08423f537a01253ba4ee59d3adc4ef483d2399bbd9f3dd235e406bdd7f0edaba5cbfc564dfd2ac94ed05d94ed18320d975955bdf1ecc2517f8250e5f5f92f84b5beebe9f1228d2e6831ffb50a4f94ba4f948d3e0f53dcfe3f53defdf33fe88f29147f83ee38f9e0fff47ec5fdf74fb449a06e0c79e36471ee0c7683cbeeff9ef7b1e26d2e6fb7cd30d8bb439d234c00f7b1ef8613f1f36fe889a230fd8fb8c3f68f3b1d7ba6fbac1fe076d8e1ff0f079d96fd037a7ebb5ee632f1b7ffc90bdcca7e986bfe9f67debe919fb161bed773798d8b797d8b750ec1b2836dd3eb1e966c5f27d74d9f5345c728d3928d97d4b949105b67fc70b28093403f6a76f73a40b28a844c9ee75c0ae264bef16afb47e49df3bcf9fd51cf0fc9b7fbad075df445ffba4be740305fc4fa27f061c2977cd7fcc5511ad8498adb2ff0c95ba28b68190ff289a30b681902c94eca77f2fc61497ed988392ae245e4049ffb14a3f00dadc80eb2b5d906396dd77aed687c0f5b1fa9d5bdfd1eeb8c3d5b95b6b9c91750bae6369cb2dd592a1022533cb478a3542575090588c09ca22660c224c0d1e3098ee9a0d78be23e01e2097dddd43656ef45157bbd6afb6001f287b92544150a6e428e8880104a54056185803060a300880246404808aa8071c7798e0e78ab1a8098c580a2f5e79847c9470f1f3a6854cc80c8696a0f1c84f6d04990c373e49493904f840d1151c0265a4f9443aadd711de2b0afb624e9da088f6ea2e03c44950a027ae3a3ec1f39d046349ba678d1c452132df9129d907ad60498b8af567b97d72c772cff097bf3a9b0a49416605cd80cb3babe04cea88bcce56ef1200f760042bfba0b95232df1e5373bde077bdeeea68e5f93748cbc9fdf37bc8b20eef61cbf47dfca0e61e3da89decd6da310809cf95923564c0e505c0194cb3f9839a7d7499b6c3fb00e459523a2b404e3a2240feda2b9d4de3616fddd35cce7ca51b7f04b979a3511ebbfce4c1e52d3221260597f585e5c3042eef0f1c5a77511980dc5fcb3d2697b5d9e42ec76419998683e67e9a67ee27f267eb160c8e4949e012d3fa2a9bf2880497b556029661d545e429fb21f7d8d44ec9f925771e0a97eacc6570795f747079bf69e94f16ed4ccc5f753a6bdb57763a6953fb2a9b7277efca316c8e11f298a2e718dd78bd86cfe0f2d270cc9c4b9bc728b8ac65597594b5c7a6fc51b00738c50f6aee31934dd9944d59df57d994f3d7dfa46002194431c851acfd108c17dd4234172d6641403f329f9e1886bd42f073b566bc82d0264b7dc2047533578b0c42530ebf7aef41cd1f7091abb7ee675f301cebf191fd0005cd5ab8a009bd8031f4e277b834be1205bb7c0902ec40286046b6f4972e792a65574e08b11b4535af89a593bae0466ee8c60fad096d9872c34a8ea42f2f9260bc7002bcf29434a328c0080ccd488896e693329d8ce6921d361f5ad85cb460e32a21045bf6461e34c204d198053dd132a1070d3b0f207bf821817ed05c2a1520ad244024c68748e6f3c62b8107119a0afc98d8bb441fb627e6a67bd7bb40b00b97c00ef461a92e2004044c28899230d1d606bb1e7c30e9821c36a370a9f3946457e77d0fa1ec656046e635235fe2d3f2e0b2c72cc946c91eb2ec3d3985e9bbc41eb2ec799ed009b8ec21cbde7b6307f010dfbb441f3587e105c12ffc1a2e7d3e6a0e67e128d6ec03fca1f52eb10798ef75fd9d36eeace175df0a3db19c654f262bc1ec2a6f768163e9fdf72d7bc3fb1e2eb5400c42c0e17043b2174276bd27922abc4bf4e1d927a0c2470fbef7d503bbb73477dff26e06b3eb4b3083ff892ef07bdac8ae2f6b06c7722cbdb79e67f76066f7461f9ebdebbc35895374fafae7b501f71fc015f3cb5995e74faa2bafcd9f3fb1484d2e197024e792e7977d75638427626ef31f5001cac591fae64f7dbbcd4f72a4796b2e74e472a7185b55d550d13cfaf339a8ef23901148140ffffa405e4fc75a7f83bed507d24e6d38dabc762b67afb1c71f3fa2683bfc37e89bc7c2e7a0c3f3248e0a2a88c1e16e4062a392d7bad7d881fe1b54e6886f48a1631d1fd78f7df923ce757bbd8dca8edc5801afd51148140ffbfe403e3602b1e3c479d9f4e748c7f9e4b5aebe77ff1961c1f4e7849a50330735a5625fce1c7dfb11a06f47da2d02f36323cd1b691ad4b7cf417d3b0289e231df1f08fdfa1c38909b12a5ea7e5651bdbe6f55341e218d2d323cb14392a65be8c3330748e138af1c8b23e1e6d524a2c2102b5a5618d201f7192b333d50e10487bb856fbfa438970a979c4beebedb1dca6bdd1b61893d7e3bfe88a269603ff63cecc7c61f515ef7d61b79d8c7e30ffae4b5eeed48a5bcd63d6cecbe74a827fa25859a5f52299a06f5e973e03b9c421108cd79ad7bd71616a0e2c8c982c3dd68963354391a8f1bb7f06fdcc2eebf9748abbcd6fd0d29b86f7872f7f4ca6bdd97b4aaa4571cf49d30718ae06ef695e84b0cafa29220c10e4f38dc2d14a35cf57389e02d318011e18197959585955df75dde57ceec8d9e373a9696e85628d9dd3abca34351b2fb27fc8e732487ea5af7f77a5f629c2bb710608e646f2cb1cd3d75472a970ee5b6c9a330aa8fb6a33ecdb4db45fdcdb0976a1078fe91dc4fdffe15fa1fbd5dd41574ef3b266fbcdd5fe9c62b75a4f1f09bbfdf7cfc11e446c72095522a05c0d55297e7f25caeb1a44fbffb699f7a74f461f350565656b69d1d49224acef9949c2f32c1dfb5f9ddfd2dc4172f998e138b929d7b724f556195cb774d27c174ea94c9abd790a9da5a6d67aded42a6aeebbaceab40e0b24ae5f96595cafdb72acff6277fa2b9abab0935a180c061065e6ef57cd5b1ec20fbd811f9e87fd51632b932657265ef0dbc9bd3dd5f83a4a4eab6b35e95e55a432657c7e4651ae62edc8086b5d65a67df57c8649fd2f176d1eda2d945f3e70e272244a6d845f3c52eba2d4a521c60d954c77a4326b28cb542a6f91fed495f6553f642268c611a78b9fe06ae90a96ce5f965abfe075210044170f67d55a6db45f3eb785d3d5dd4abedbceb7ad9ef463b36d9d90aa2fb59bfacee5f7d94596fe6796fbdd1d301e6fa5fd97dd6ba7f6f00cc752c7d646fec61cb2e22dbaf20c904464c60c4cc6753a13ad703c92cee0c8a6ad5f0725de1523f95eb886cfffbc04e2cbb4ceb5e8cc3257f110469080e21315f200c949d503108d31254a6072c7dc01a31c8400098c173fe80011002081c497083c01f2bee0c2c62d2028ca1505d80af2b2e0df4594208fcb1ba2f2ac8a508c3cabea17693bb4daf81227f3f412e65e4995d8422bb8501c2a8e10e81a391076b2488a08c36776c23628032d0d0c0e4f9830f0df690ab28037c193101f89a7329005f4441821318416b2036732b00814e98018e502a0d30a604631a68c0f0e4bbf7624c3ff744ea599ba32d064cbf8e7716f9be3e53064deef733b4cc1a5af5d42994bbbbbbbbdbaaedbccebbaddb727dedfac0b0c1b06160f7bfacbcb2e47e18166a25f763ba25b7546e0a45c97e3b78ec60e1b1439d705762be9011f3a50c556e467132a744994ea615a8f944d7b8d51a3b571530ba91dbc8f64d4add6bb593bad76a6d576dd779debd2defb65a2ed7f78114a4217dc1422a9697698214d3580ca43db77f808226157d2849451915cbcaf403524cc99e998ee58fec2508798e948a922dd545fd00b0f37ddd1d02568feeced1362322722604b6abf97cf860b229a35e6de7c16ec8d4e59a296d81d8152e4d593b0c0683c1e8173279f97611a51804837b34c24511b8e704bfba440302d39e4d57ce09da49e57e1755b84330988e3fd7ebeccf87e5a573767dcdafffb6aeb219513b4b4ceb76141d5c7a854c14e4db4530188ef524dd303ab3e4534626fbf901ea8080802c50753a811a7c953f2e16632113edb960a593d24cdf710f9df3026bedacfe807b94d129ebdad3a28f2cfca13f3fb3ad0f7ec95a2c7150900705d1a0290b976e5072565f341d359741327dcf6553fe01a2b114349be1162d5cb8304ab2bd78e174b68080828292966636ea6ed1e2024af6bb70d1399a50184cc712a3a93ac3a5cb968e329faeecf4a0ca418388521c2d084cc77262e51e61844b43d7eb6c1df2a1a1a1213afb05bb75ef0a6a410b975c98c1d4826d678d7e1fb0c599acc58f0b1a9d97923f608b25d8e2479b4d5f25907c5d7451b824639ab41083996b0ba1165fb408030fd1a139645f80b410078ca13934d415068611e2f0a17069285c7a1c430ca6a31311115122a249d4b1572902511c63c42022922163820928a080246bb5bee0186312b5bfca20b97e31c018b2d91c693f603ac6087178be4b4421130dafd1da9c205c825130963dc03cdfc57296299d94fadb4ad2c0603a9660ad8219e1128d7009174d0f8697280899687ef00b2e697830b3b27b394790e748d28448f2050c9224875c90640b926c5dafb364753a2b7819c007da44e97f301cad0f70b4f2157f0e5e371f7f84e076610bf07c29d945546c20b20d17e0e51e938e0cc1e52e5c00cd83993fd0ef48ae70d90b1710947b842d7900825c7220e320ca1edcc8edba1e7d951cc8f6bbf77ed7bb5f77ef772ff9ea2fac0ed2eeec0c5baf20b36952aa837badee62e501cf07a9530a7a584326b1b38738ec8fb38bfa3d5c0a32d270f8e4fece3eb9c5ce176c0bea58bb68c8074c9eefac319f29969b92583efa1d1bbf0478be8c92734ef966eefad59f3506da42c9c7920536050a3f5152893abd42c0eae971e555604d8bc7999ba36d463e44a46cf643c90e3f99edc207dfdd43fb60e8c1c42eefe74b47bf7b51592c168bbde2e09252512a7a064d197ae4f3f5956eec4b5cce7a9294daff8e65526b2c6dde58923de36b8c8d78f411cb1bb493592e5bb0d8b0ceb1c1e5cce5c490f9f242887623e985d0c57836fb27499b2d2997f4c9472795054be31b6d7039a5a4b874d9429f485b92918d469faae854ddb00235a563495574a6a8aaaa5203859b2ac755c1a93fa1b064b1224473f1a4914d88e6a2c5a4222715cd55d191139c0aa8642b594b8a9a444aa21100000000c316003028180e8ac4a22489e24cf50314000d7090425e5030164963811c48311407310cc43080106008300818659ca22439f006d235f4e42018eb63110d50aee9340d7f8161cfa29a8831cf1f0fd1bcaba05e1849d4a0a3861c6cdfcb708a891e6d65a05aec2e84ca34c93d9dde9c42ea39d237cb018b75a14debed289c44b19780e090b50e7ca46164d5fe29642fc302c8d86498673fa13c08761fc57d40548f93de19828a3617b2477a7349a10242798c5e20a795394aeb85eea2eb1e074e0b012b8eeb7387bee2dd8eca378670ff03b3817c7008854871f932ec3f11492d0dbe12988f5d782fbb644239cfebeb9bf9d2fc85f3a83ab306f5d31e2f7c9d8818ee152dadbd87e476600397cf40aa5a6be7903c946cceb5a71e3a457833d06909fd0025cab195e8e48f7c1376d82a8f54f010787c73c53abb434984780d3c901b819a9db633229bb178e52b05dafbe815c4ee8a350d6517e9189a6de57768b396f5ffcf09b07d667005a213b986cae91341f3342748272f90237fcf9950cbafd67bc0f3e63224bea686a78051b28f0316675bc16c4c66d864314a809d9f53604fa81befa79a189c6c4be07e78b8cf5969fcfc0ca37550743d5a1bdd4494da23214f9f82d0aba024bce2afa37223fbf16cb6e90c6607e78f4d604eb6f6f55cd7f06e9a615420dd9cf3517afd7a9b90e564427174e4b84b122d140bb1f8628d2a9ba0a6d354ca2e7ef3cd95894938623cb081255be68b4b93dc9511a940e4eac17dc92087d8fc9b75f31dc05bb87b7702f6e74c505dd8d2b58a186f662a90f34f54081cc82a643425059d567ee09c35dc3cc8d712c2cb0bcd12323cdeb48f68e3c576242a0df9bf1721fc29da2ff46c1f362af06a4371e7bc116606fb72e640f63d4d5038bd722e58faa11d95e4607e614c26ab90e0f0a90bf362d6100f1258bcfb041f45653a28f6b8e7cb5ff71c211f90208b22ffcf5853e7ea945ecfca1778c29f0e702d58f0735a1f885d21097d0327da6ccde95548d51a557b8a1cbfba81f6397b4a34b4ae8b71a01c0cfec48f8c10116b24eea14751334fc3e26761e0d900cc817888205a689b65be607a5cbed142dddfae21a39aee34288f82f534887b8a046d55f8bd44dac5620d72ffe76719f468385d8bc69e51077f1e1a6db09036fe1883a483c6f1413db043a9907e1f76bc8f45d171a28dc8d8a5a7261c3cecb707f753495719ed5dd5a714847f71e5deef91012b12adf214fdeba8cbf09a4cccbaf47a918247cb47b3aee35ad5ede689294c582b8e7c9f57bc496fc8d0c277e87bb512c1727771785f73d5e7e25419656641ea970500c7e3e1566485892f86f3ba7b039231c98324676891eec97b4d6f45b416ef8fdf3581b5a47d91951a027e8ea0db6e8df091c242d1eacb0c49e9e4865c9bcc10b3a44196f0bee22f7b9df62245190af2d1c6bdb02690f849622d69407bbf51ca95160d03d6e91660bcc2a9a95693decf7de15d4c3e70d9b8facd39f49a5636f9f5d3e6a2a5383c403412b1548c5b476151bd2221a77670d48aa1c52b42ce2bf0f744b0df0bfafbc24a46d4ac6bc48583d46f3715facb207a1e41c829e9b7a29bffcd1f6eb32b8a4a594fe08dde2779282662df42e8e42424d1dad670803b9f73286b8a2b7edfe20188763f8f0e63d74ee8e8e3d585d5201c4d1abe6cca52de773fcba76413f8b6f07af4aa42f42fb450ea6b3105988b1ec23376b2f52b8780ffb74384b20a0493bfb81edde2040f35e5feab3c648f30a1f3122d62dfd7a425a5924c83f89c40be1c4c8166ba486979809153f11a662d4498821f82b9682fa9d5c285ba4f1013bf81a4d7d0e00f9a60e457af2ca44f9909cd28e7eb8900d84c10777ba55702605bff7cd60234675ff846fdcfabeebf6370788209cc7a581a1b17659857f482cf2665645f4273244ebe81be38209e86fc05e3ff9d831235e0810e7a0319acef41f71f12a0432147e00eaf04ef3799aef4d6ee3387a2b6713067b15a914070f425b3df5c54b0b7c2c4a8e47d84adfaca66f60c89def8c0df2b87d7337ccf5648e87084cdd955edb1b4a5b8e2a302c6ccbd5206872af1affc491aae85f5906ff6f0a5845cb1998f4a9a2283b05dfa7ce2ec5dc6a29f672a58e4e6c2ae4aa2c0d41fc6d1c9f3a5ec5c3a0ec991d82e37ba3dfd12f312534e2039c527f5b082ab52c3f7f8ca8c9fdef8080bbfcdcd1cdf9bd377c8b91284ee3364142bed14a0b4e0cc23d5b75dd268665d74b51f8a74e034bce827f3794342b89370e56ce1127bf3b99822d76e31904f764bdc4dbf0c3bc81be669f6115a6406b74ca88f8ad4d748bc777de62f9fa5fa82cc309914da11537e374087be55cc35ea3ac7148ffda82de4b2e6bc200a322d0d6be9315b424e52126737f22c58a6df52efdb25a4933e9fbf46a57b718e3a97cc2b2a211b41aa20601eaa47eb943e77bb9c0d89db8ee47cd2027e8304454a2d7fd90670cf338dd93836d2d035099956e07a5bd985e3f1ff08b6b0d6026cc5901977c5348e06d9310ebc47f6018e4be32e4c425a1b545b657dd6827353fa39db29c1aa7eeda3ab2d789a5d5aa17be8082990b32435185ca3e0fc9a7aaaa112833ef9607c97e7326ec83c42b3efafbc58e25d56fee2dd98cf884364b473bd956baae15eaf55a4f7e3dbae18ba0719a3c1245eae0943f1351d604b63b612dc36ec436671eba8782af3868e71debb98f6a7fd3d3b51a130a0b0208c643fde81a54f7ebfe9a4505ec4a2a8a68b59558127bc550668ef30ef02041be9b5b6ecf665226e460b48a8df7e135232e237b91243f4f3eeaf8ab6c3468646d54c28f13fc769bf9da78d32e7465b88b4fa8f3f700fbf8003274674cbde63d5ff3fcfc069365adeda0a208a69a4e6c1adbd801163d46b067f41d897d5978ab7107b16a9ae9a049a20ddbf2cf829f211bdd876a07ea2893b6450aa18b75d801d4e6a2100a171706ca6e660c51ccad8a438e366148cedb06f8fb89cd66940153d0e6df161605c280d5ba55aae1e567498b0775a8b5185d1a9474b4cd0feefda6bcfc3a076098a31d2f825a16b635663795a01a6498bcd1d752026fb38fa8b454ba57995cd8f30f736ba1495030c56fc129863727d0c3713521c1501222687c47e6342cee7e8c26b227e7593e6130ef39eeaf5b5743563e7c19d959daab8c28c76365f10015f547974012de4de32909b4777c39353a0d6ce3b7aa41571b2616009090ccfa9588a0ecc4c6330259fc05c33c8cb230cfa1e729447a79c2c8ca5e528cc76aee11c29a74a8c4a96a898488fb3b0ed36b37ea431b04a057e82361e5b0558768d716c8da76cc580c1f5d4e01c4f0f21a78895182d58ad270144d1c824335993fcaae33bbda38e07d1da15484a8cafaa779abd94bde040824afb141338882a28e51c190eabd36c7988d9f72efcaa77b82ed368bc499dedbac06902d3af1d365859724bd9ff6660e54adcbfa8db7148c498697e6c62581cf830cf1a6326c5bd3ce32b73759321f3113b3933ae796cfb3b3da644bbe64871f16e68438ba7e635ce8c65c381705be7760a16da6ddb85d34d6e529632bc6a0aed9cfce162fb77afb18fd5271f061199858ca10336eea4ef52a108ac84863b497564040be246b304958a4cb5e68a54cf3a7cb7942a824d0d571e610d7b8562774c1bb90f0ac5cff493077a6242a498ccdf2182ae9dd64746076a07364806b4c3c6650b6294e4563e0d7541f5708d6416af21319d920aa8906a96ea895a8f4e1368123331037e71eca2e94ba8158d32de5c6d3fa3f6b52f390e04429094182047986c1977fb55b45435894c0e6156c13d94ce3cee803ca838b71fcd71a83e93093c3ac0f207440977b62ab62179041b470f91b4108431f1116bd403f8d967e363874438d9a219e96d84a139d146344855cbf1032153c29caf8ecb994ff4e53a347d16dba473e88d59936a69d69dd13eaf3067c4ec0c0eaceb3ff9908e7baa2794522921ee06280034cb5ccbe34d249c7c3612a5beb1df8a8624b89dcc6b07f394cf9097fe32bc7df3607abdd8c9c3c4bf80b7881bf430bc3b561cf07fe26014ee96d98053bcddb1df79c4d75c7a353f1c94c5c5537906cfaec1bfc2efb147ac407747813873f8e1382e9acf3587f1411a4ba00f02f466cbdf9d6e4d53c2cadabadfc5cd19e7f7540ebf4b3c36488b4ba07624ca774ed7edc3b7d186efc7063a44dcaf5ef846c30c87e9cfd49be0a38f10c6e9cb59f8401b5d132bad5f61978e65a55fece5c8346318c67dd364132e4966fccc9bdf5456ccf5b4f5e3b91e0161e0f282634660ee293c76e8c1a561cb4905a52c4e314531fc772eb056eacf3fd064315ef4d73e1581e0b78b7c2e518003b05de86af9587b746c614e2b836acbd4c17b52f00d7faf55a428a299f937007e4f50dd15de571cc601f842eb9e5b0a9908111314183d8b5ad069ac2f9d28465620d1e098361360f0ff282adb886c4a003fb110edbab70ae0c517687381aa1606d5acbfc88b1fa6c709ae7b740f33c0873bc7b7f962cd6979075286f2e4dd023c92886b4a0456c461ddaadbe545dc2707dfec37f965ae8c396ade30ebbf227e6f87b58bbf5c59ba9e2375552a5a58fbb480a927cf532f04d44e63d273afcc1b3f5adc65d5316bb3dfbeaaa57b8e60dadc23239549c8f25b0fc191cdad6141e72cbb9eada00a91349d7f9932b78e34db3da00f8593fb2e0c7626ba71a80b2497ae139028ab0e2fb97c0a0216e5f6c6c9a2d4bc36392cbb5389d7c6fa37cf66710524f0946d71cfe03ca328632ea35f47a6ff9914959d1b2d0d99d2f0b55cd7e6f4c82ee7b87f14c0bea9388726af93ad52bfabcd13a5b117dfa8011c5062f41ddb3b28c57263b4588b8d1e10ad7ecc98ea25e62aecbd4732952f8e7cb668fdea9fc50251fa5b6793e8cde9d9b84ecf523944493e068b09498e2cc86ff73307df9d5a16dd88db88ffed21d071d9cd7af0d6198ed4ce320bc0582d1e452682405e6368a6429af5064827dac63f649d221b88e2d3e8aba867cd5c4dc6cc1a221251cea2ff846f3601538bd4bd24dff3f3e9b6434e93459bdf4e2e3a516066f221cb6c12998f911c7cb79b4fbfcb45f04990aa545b22a1b40517735d023c20bb0f3a745dbfb2905332ed12e38fe10fed68aa83beffa98343378028c9324c90f4977c10342c23f46759b8996cfe9441aa7741236972951c1a90cf7cbab1fcbf56f02195d0de4f1b451e36de5031f1dc665db007bed532fff4bca1ed199a56d174d67e07824200f42f1c9a96225cee0fe4dd2786d64fb70407ca82bc49fa0c5cd3530ab0705f0ea18972681ebc8998984b900c272647fce1ab2f043e159aaf47b0e9bdbe0d0f246f5ee0e104032af451faae3879dc572346d54ea053a808a919518279aae0f873ccd4231128cba21be6449165bc6e355d310944b3e763a3e2740e7c467d10a60c4a5f86351274171aaee934efec61b6d1f4d39bc97a363b230df64c031fe357eb7e7aa1d4455912945fca038de943f8ce29775b8b48adb30bb60ab5830d770d08d9e375260513f63fb5b7a7626d87afe9be2496e939954e32ecb098d10c926bb02fdb3c8098af60bc883b8ffcb751783a557b7763b4b4b2694e5dd67072fef52102c50724de77991f6c92c87e90ceba5c30bb38ba652c24f3eb7a8debd193b10f4960bc0c3503d8414ff77bc2b518c3224a55b03698da260710e8f9a84fcadfd681bb6019d7ff02097fd23e3b7842ba0334f0e045c8b62d6900088392632267336bd203a2253f4e16b8b1e7ff79f775982c910da9eb0a272eb34149e8a89ba9177328ec6a3656834746222e4b2e668348a8dea5c0daf96e9499217a469a422e90ab1d37caa2975a1b04a11df5c8fb801368fada3b70d2a768d31914a1489be799ba3b11243d06eea310fc43354fb37540f9dbbabacdf2fbe78fdcba568486f9130b3cd8fd5eb6eb59ddca3d49cfce3ed38c13e2f5eb1a91812d40015967c2d7ade9edde1a00f1f40e7e07000a827d860b38e211fe735be6bf018c37c027c00702ea0217e8f7eba78f87222640d0f90a30a14fd7d546b0e6c6c781f08cafb6b85defb75fac0f77cadd5c6e6e008820e1f7c2d6f9e86f1d0b5408cd31d477f77ec936a1fd809950d9eff28361531d6756f2a7844e4c208078fe90204037c1b747182d7699a5afe879e0aea255255d76519d0ad0a70782c802614cbe66e978696bb7bbf7eeefc379a8ba51eef7a1b2f4aedbf074956eef11cab7fc610c11a1eeeb4edff13b443d988e64a041e8a14bc3d9ecad9ec6205074520678417e8581501efb0cb73a8a2ceb1c33e137c4b1027caae9d8ca1f93a381a0e3fefee9b25b51150446dda7db771cbeb514efb8c516583f231cd75b0ff3a6a7e51c2fa53125b0b15a3bc268de007c761855cfb70a92c084557d3fed60c3b43bdf861998bf6d56012b46b7d69e7da8e083e0995ae99f5efc49a08628cceece5bd0be064ca667ef9fbc910993fc76b68335a7695881b1db41b65e765914144869aed2870a874591745cd8497248abfe4c575f18e5a3d0a3a67bc105d316e3b65a06f6bb311544803e5d3e98093e022dc30206364af4cd16b005b99fc89679dcac5bcc8b9bb0b900118b87ffc7620319653b8658960ef38c64bcc5b6d20cbe27a138349435cb2cc5eb40dfb53ad1d0dbe56ac0d0b81f1f6b542a784305731760864ddca1afaad34344d2c4286ad5c4365f869a72ba0351b81035d4bb17738654241a9f6d664d08f2db7d33da1ba2ac9b1a2eb6474bddf62755bbc8b3bd76e28120512ec1c67c26d6b057591382ceace1eaac1393e07c0f9235940935c953110ba1829a88831bbf573e427eedc209d1517a36000004003b87914a12954c47e93cf415ea8ad135eb738ae8069565832e3a7332eec5c41989e26c56e6fc999338c23cd49266a4496cb2721d470232610571806253d8e89c5123014932e3d8c40d49b9f48523834493506634f3c80d5f660ac60fb938c702c8d9ec39b133928a3fb65abdb4595d948e8efed35c4524e3e10a72455e4481704854d1e071c648551392525620c67ddb0bf587fc7d4195021aee2196dc77f4618b96368814653e0e9aeb9c5633ea0722c9814a36dacb854b38c1b871b17ea6b9f780b4e172afd257a4f85e534656a6b64d5a0770d25aa0f4fd180163bb34f0c63528651b0b62e4e603b5c45b4a3f4e8b552a6ceb1b6ba58f24e9634afa2687ef64fa48ad47f0678e1acfd33c1d61de8a89ee3ad2981826a9395149f56f67d20a465a70d5994aa5ae7f4f8a27a5a2bd7f6b0f23a714aff649fe993710a0fb999bd10fb75b3caf368ad6dc7dc186be5c148aeb2248d9b1a7b8f23928f0a2e763e456b3f80936eca387fb646fe0729ceab8901b00628d8569b05339484dd2ab287959a3c95b59448f57341292fac3342e02bca444f72b99d5a6a03fd58958d647d4ee9f2c77a8e70b85fc5182b4d6fcf1d037b1da81e2326315ea3a25c0872e5b490d81422d03f849aa29686f4218afcd1f5cbb5920bb645f60d34e9df122708602e530a8da428ca00f9b535d8a89026359c7a38304fc2570c0e7b121423974553e02391c8b54241505155802bd326f939acf821faa1ca8e98929909c704d715aad6d97f0f1800b9936a51413ff1fecc50864a58f5ecc0c2c22f8c372f42707c3bd3c22e476f7affac852b8398cdb38104da26caa18137ab47389925931a04b353822862f595172ad2d6e3dc3a3f03364140a506d9bb4ab9aeb21f734e1e6cf87442b770ec1d6613894892fc07421409e8e012e3ee23bccfc83d94c5fc0bb5f4ca12af5bf5a7518a23a2ede4041abaf1cc0da1c5a98b3db68ee368a86a96cd45d1181c3fb0dc833f127cc91fe3402f60ac02a16828d0faa937cc9ef1d758088cb16e99eb3932346d53d230c92889fb4b8810862717ff7169ebaf08d46c4dd6943ce5571a866f1f3e61c6e7f21a61a3e170acf439c992ade2db92ed7e6620c5fbd11064551e13a855771f4f98494d8f9e880a02fbdc0a8ff51447b32d454c42ccb26ca90ba7f557a02b8609cf00f673572bde1e7912333835f33544597e89b159c9cab85f0bc022a10c97d30edfae61bcdbb3855e374f786532e4803d5b2e64c2b521f3240cf9a20778d3265efd7f9ec6726cea3170b78c53602ccad0c08a55f77f15111bc625ea2c221f447c7bdbfd303721fc5865d5958026b20cba392d3aebfbb3a0ab416bb579c85c064b624a049a889842f8081b9ebef572751d0a9b2286bdc84c42dc3a48d2d1a32de7d7007f8e953ab534d97028c0aa5780d98449109209409520d0f1bddf860727532dc22d1d5193cb5cc4b28b84804c62588350a9315737adb855c09e7b8938f962cf6764be0ca36a64e8a2a03a0522003d550a8c7d6579fbdce58d90e2a702f47eed847a4e051a9ce5f152536906006a13ac5b692a7b0ee260456a79446f80748874feba1900fed3f4ea2d1cf1a1ea074466a0dc8533c90bdbf2af482b73a840a726cca7437f10a10fcc1bb29f2f7b88a4fa047f739dce1e1064a8f9a1a14c52c62bf5502897986ccf2b7916519c0b45bc27a315ff9e6ed040d33502109d65104b491ca0e397447ab3091ebf684507000ba2f5a00077d5461c7b00e9a21b6a8420099fda630afb240d34079f2f6ae7d0854c36e2d00b6b6aa84bf381dc31d3ff230a8e6a20061b11cd8e9dd757d21560ba5f4ac56d095b132589b83ba19c200d36f7480dc4ca1f68a4249302c06bda4dc68502552038e9e0461fd86aa8a24de716363e1961e8aeddbd8e62d3ce14df49128485e1d493255821681011837dc762a44d2e47f55ee19f22f569a7525d102f19ec3dee9f15e328e7c2ced0f6c753162227e0034933a7fa5051c8362ca196b1fb9c0a16ca2f2be5d17114174cfde8d97065c86478883db8c803d44190b8a11b505f432071a60b4d35403ec245f255a0201c74165fa077bcd535b14a45a9cddd4b610e12801698a611e29d92c921c979520d9fa26d352a24a0d4c2f319f390b5336a2f234cc570e2475c4fdc570566613ab9297c848573fbaa9012148c2c5583aeab27204de3967365a103580b546d8d4c86a5421cfb180bed898da6321741712b0e5ff4c4d82bb68bf95339ab6230a78780f6b50c8508be9a4b69fd09d1c8469bb569d1c71f19a5d54fe9649f585e3b4d492ec3533a58ac7e2ff46155aedfcebb002a310775322ffd5a2a0202a9300f55c243f17ac25d814ff251d6359c5de31d82a0ddfdf0ae6f0a3d3154bc11d7f1351470a81905ff477a084f9780e6d8e9360bbbd89c26182c0ed0973d14698d4b381188312fa005327b1933fbfc2b943af0a058bda70065452b67ed56cb819046114988758dbc437a6c77c4386fef6e5f016760ce1bf7cf97f066edf444d8620e0feb056222130eedc381d0543639cb01054da438790f41684aa14eff21816ded6be5edc6f3b8e3b162fd1949f90d3edc357333f48baf7923418df83f78b0d8398da28f1352ce10f7ef2c1602080c2e7248aa293bcb87d679917e72ee0957e2e09feb786f6aadd6c043451ea5c0d0bce3becbf569c5714e89e8f1e6b841da7454e71af3dbf6088b43cdc765015b6ac5372391b0e0538e4aabcb054cc2510a98eddb9d840f57aca960470198fe31cdcf7d2a39647b58820f3e06ac526a1e2aae91933f79b4f7df9a0731ba71bc9d09aaca51070bc644e77cd97fdc5bad04d4d87a4d482064bde52ca4b3edc60f9dfd53cb6517a975b69da868bac43e46f8c8682da70be1e43bb1d160e52f97c279dc2cbfb430dcc6dd73585b74f692148e3c95da483271db92998bdc01a9cf0cea6531b3de089ff729adcd268030d22bfd9a697cc6338853ad3ae442a2b4ecacc6333f05dcc50ba521962d87069f7628a04fd8d90f3bf618d47d4079d410f60dbbab1f51784c58906d635090805b30ac1b491430ac91c7815c649d51f0bf840d34a4910cef10168732d644f8c8825fc9809cae1cdc4c61ece428424bfbd2ddb36a108ce5bde10cdaea9b495bf3a0f70d54497c96cab80234920287fc822acb426a917237451dd6d74794f00698393b0f82132bd3e7a46d25065c27f56caeef2eed667a51b83c1f1b33f5072067c25bd75abc274eb60e7665f21184d91ee076c6ed067fc020c09e08b79d6f3da97ef13441004508d431a0c246c414419030aa2fc780cacc9f687cc48cca51d86b6eaa02077763ef286c5f9dd036f5096f50c28b5f4b560e5469d9fcb13c20f0e113048dbb727b4968316f62de1159b87eee7fb580e29771891872f7cffc30277ac266463c5b215ace0c5925887782b7b6bbe03c212e10a0cde9ee1d420f1c9559cfda6489cb66d9e9a482dc5b68216a945a145d0566821b515b1b63915e4cd8dd5e8b54d1a732b25137e9d127e50c989d5f9deaa539272608a0359fa5f5afb82a1bdf4de1532c749d23012cc3336df63f63baa579fba82f852a3e5092cae94752a8892620fe8f91a06c394c6fa28f0a6a47622a2d59609c9782e5d216356fc5ec410c041038cc0c2415903b78a99b06c848b4db32ea64318a8501681ab2282a860783b1623d2d65becf7db56f77d3a09a011581020abc05531139d4145cb6f437608801b171ee7b159f338dcda7d796481c505a78a88130768cf76f7f1951d9f8a2a619c9d715d7a953ddad9927c933f0b855a3bbf6096072f24cd643e4d6c9e84ea38880ea513b8705cd0423008e9c831aa4dea9bff9d1b0ce4fba863a147bd32ba48c975916fc31f75219f0a78c9822d8f72c52f44838b10c74cb276ce16ee365bacbfc9e3d84c26d99f312c445ddc2ff6ae51d044e6ddc69580ac247f550bde4172cbc0b0addc2910360c832475b8179b8aafda44e99fef22a47050c36e7566f0fb91c7532e7372a628802eb3b52d3a0f8445dfc48062c2bedee05825fed81e61c9227c648b00461a3705cf833510af2a8be1064465d6c4b91db9d66dde4988acc53cf5144e14afd5193bf1fcba6ce7a298480773967b6fb78157a1c64600fef08524698162e3ee7bd472631c71f08a36ac04ae8a3cc1737443b35637f7850a5a63dc42754834a1612b42a00fa5436b159268452d09e17ecf50364d6c3f2c0aacf5bafc02d5a71b44fe822e9abc0f41a40e7268a05d215ae31fac9e6788c4a12513de736272d3c97c296a883749c6ecdde3664fa0ab722024e1a61eab9dbbb09f6d1311a10ac64ff446c5c7b9aaaafdd6b885ca5b5279b6cf3597fbe09856582368a96d0894a185745522d2c5c172e583c0a3eecb4bab49c5542a940783eefd51e89d6a15950644bd23a0c9aa18b438650e582bda18eb3dfb9173dd13f34206ba59b0fb55905152815f94cab5b7cd9834667883ad4922bcc091f5c09b87f7a565f9f2ab7840504a3886de817e9d38ea9bd67f7681cf1db429e6e094d80056f2fb39200e3bf1638ef29a54ca672ed73f2af5356df709d8e914b5c7c7300743cf76e4b47330279dbb4fcaf11ca1fa89769347814e51555a48950b215bbe86f046a18bd6b1c93a41840199b01b3484ec882f5fab54ea0b370527922f56c0d879b71145e5d7f138ff434512be1e4f3c7d3b5713430ab186d432157378b7d63ae48e513497331efb10e9fa1a75901a3ce08777d631d8239278b27bd215108c225ac80aaddcb75f46cd48f43e606f1a4089c06d69a050d4cf13d97d3edd0b38a85fc002dc045c6a1b4738f1d1a037f5db1acbc410f5a6c2c0650510507f560c9174ce0b72848d22408dadbdd68731bf4ed7bb916e0c88e1e0364cb65b41b5400a606cec5d617dd664631f41ebb152da2fe3323d6e9ee3e42f4cab6bb342e21223856d38a41370f76d20564335544b4bda21a2204ea40d52b1145959311302eccfa4b576eabb4e98690a48a8ce1bf38586e6d431dd2a6994a05e2c8c7dbbe3b4104ce0fd92f916265d3dc733fe85e0f0230bb85fb3252eec7e9f13b622fad64638856dd9e733384ed1297a44d91a355230ece99ef70befc208e43a091d37752d65e16578b61117f5d622b8cef2ea12707a828026078bcac7e4e230223839a3dba09a198711bc98569c4b869f5e736692fcc6f2eb77decb892542816ebc37a5b368ec0af38a7186053266a7075033e4942d95960d50926361149cee5ea33e341ec37d763bc075930d64664fa13602ad289da1697453d278a43b788c61b1a9da66437724486ccc1b4dfe3471cd4e6524a4044e57bce486ed46feeb86cb54bdcc91beb12c214f93924659f81bece4de2e77b1d245deecdbb8f7a88caf01284919866794e05fea807fcbd82303c3836906dd81c09eeda26c7f4dc685b637f3d4c38d35cd32f623080c13172e690bcac49094ae457a51c4df7fb3f3cf07a202868c79f2b01cce4f378c692d25a97eeef7b1ae1bb9df9ad01a7dc76431ed1fc69301e2ca2de0435ab9027553c351f2593768c88ee9998e1752e0f2bb97720a3a711523469bb43d6cf41ec9c4c4e0baf20900f1251c27bfb1f90b565ccf0029497d0796727eb81c25c971b840f6a703d2688ab3854d11ace3f075c510092e7bdb1433b5226725636bdc04cc710a220babacbc1aafba6d03728f078a373487987642d7483719f1809a71bb5a1bba42ef6d5a068e03bcc9c4ca002c02e0206c346ae0e6c384d175cec94c39142c5cbacba931c34fdb90d420e8695d48409701b28b69e1257a023d3c89804272aae3e09d439d908dd1f0f4cf5e8fb439212e6f2d3ece071a445b2218449fb310b752dfb227f2615ecb7446abf0fffb6e7a795bfa032a602da0cf6ec45891ec149346d0c01aaded28d9c087a15cea77a0d9294ab5e48c3f534540ce6714837be81c39701f583f1df2fa369f7111fb67d8f4c5c8d54dd94cfcad498f8e83e2fe2ab1ec857c4f5de33ae4da91a78aa24f305aea033b983b60723ae9bf7b55b0cdd7bd4fe6dd53525a3e353442648c580ba0ba6d46cd20138d0235b2732c0ea59bafafcd4cb28d822b3fadc96b6660c4f5c608608be89d7a5635e13ca3c1c6d91ebb7c2a1f0167a6da16397ec0cebffa0390bf70e48bad90b3fff6f2b42f713ad0bc4591134749986721ce686c8d5fb9e71318b5967e5dd4bce83b94d15ea048dd244cd3e0827be122b09692c0d8072a94f007b933b3c1265a7e61a039ba9fab3ef6481415b57640f76894078cdbeef21a8c068c28705554ea05eda9a0f8be71bacda64ec61c9c2c810f41a7a9696dd65f7accb0e22125cc6e6f168831731ae2110c2d4c5a823ae41e7e518cc84e4802ac93f149490c69f41545fe86afde41b6760450060d80d429a06c812b8285f02011f8378cd4a94d8e02479748e0718d2430182cce2aa7add2456594833453022df6f2736049e4a3cd8100e51a0707588f69da2fe0b109603b0b5b6e6dffe8949564ad1daefc6db6ee5c2978b6e4fd97bdd6868c8cc3d871b922036d478959e58289a11d7be2e0fd4e30fbe030302bc1f0791623a6c82c77ff0f4d16a91f61ff6068632bbbaf5520f0d5f533504cabf152bb9c222e19d5a72b62a688cfaa6e2d54057c2a00a5fe737960dc33726e5494c0cfb1f6553dfe59f29bb33a26aa5b7166701f2ccd0f15cff910fae4b1c755624f887213a2057bdb4ff8c0d6939865a4b7fbabaae3152ee58ede9cf6657dacc74bfc7e690fb5c26e912e5826d53011b3f1a35e7de8e8823c3f1a7546e6048ba49e20fe66e1cc5fc9f30a724841e491e7ebb45250b0529e11010ccbbe2b1537ae289f7555d911b09d23a34577c8fd12dfbce2be68c68a9b750d3d1571bc880907f5ca24602c655c746bc2a5d25bf733e63d47981bc9f5c438ad1e58af68239c67cd79bfb7a72d7cc64c9976146a780581130805aaf099b1d7b0f2e8e45ad58b5a835947e6dbc6c0f46cb3c30f6f3e954fa837ddd0d42a90e09893aa435d40e6c3c4701234f5f6c1436becb6826f2c0d760431744f49357a9091ec68649668fdf4c1b4556894e1f8a97981033a15c84cc5234c810eb0a5efe6f7253cab66dbd24849111069b2d88d5ebb906ae12dcb939a2457f2b2f3aaccfa2a0edd55366887cea29fc58e8c5fb34a5c9ff8f82e6b1ad079f30323e12ac30fdc4992add79c2566a250dc032ec3236427fb90d81b4365403b39e4a71ba26bb9c77aca7546e88199bf07ff0e24cb10efff8a286122b2bdae84016da93a0cf988105e3f57c13d9f90c0684984d58b16df506fb4ddffe1c5921056fe76cee46ba12962652f660504b6940422e578c3d389700c44e90020e1c9a990d90883ad7338023eddb53220fb8cb6fe1784cf3988e439897e1f065bad668f2f33a2cdeb1a3d54455e6d35ce2fe56338f1f01210cb06b41e5c9e3806237d30d2201c19b04d801ab291431a4cf51d6914fa77f8b2712da68ee6f0bb7bb898b720c6786b1fa6dfd9106d8834bf67c6a70d28132a7d707faf862905c79800a27d66793559efb612a6a4a13678d5667a9dfa0cd06ae213e3228037dbec4d9b1a2daeb7aca71478c07efb19fe0607588188f8c4db6688294c5184a96106a8ffca6f944e029b28219aad65b2b431245623baa2c1f83e9cf55cdd3d01eb483f1c16e4c21ad68a9b76f12ae904bfb23d14691a9457e9a6459b25a3e8cd5a12676b5619b7e8b6ab24d59805963a0328387d653765239b861115225fb21d12d156c70285fddb53916eb64912b8e80c6039f195dd348b6c1a0d54887ca96d4844371d0b2c0cf451d0fbc89893f80f0dd7b9eac1a8443818bd72ad9d6fec40644c0733d41791177dea2c1a15dff0e67159c8f3870304191b3a5b90ecff9fa071222b7121d29cf9c853fc0dd01fe14e4a89005d945d3dfb81a3dad0980addb0cb18a49ed538da782457c7fb7f52b03963a1cf6ed3a596041b449acd84107dde660a56c014b738fc54456a7e6487e2d5f955605bbbbb259f13d5a14d4fdc61c04276b714710ca8ddb0644de72f71dfc4c3f8f5413826f5a860cb7bde0b73f866bae86c39d35870ec67c51c43b7fddb165cda23cb93bcf182800a067463cb6cc6406bda7877eb5604ab0656aad275f3906c83fdfa4303b817a02f06506aa9df72a49a3dfca13ba3ac8a0a779bf95b8d0268f21ac262f88f93c8501d5b4b7348aa30e41d9c169b370ec1929117ca3044af96d1ca2a2ee3c8f9810143bf7eb8a2540b44811ef3027d72e263546e2ee2180a5d88b021258b31acf86af95101ed60dff1b0941dd1a991c855a11d6d7a77489831217ae4cade2bac440e4d2fdfec0c5f9634f99d86f684fdb276b2d9bc8a0f55ab7ae8fbb91d63db9fe2782ff669a1a28ac5a18c60c875e3ddcfb46bde2c31aa7f46f264e151270766000f2d0710d6e2203c5a69b624557d6797300f7da3f0d372667e201206f2627c96e99cbd55db0fcaa3f89a2d30d375a70fa00822674351a6b34574038e10f956c5c2c8d2ac6cfff6a459a5f08867a2d0a20bd9efbb042a77e9d0ba248cc21ef690a4a0601325c9f00c1d89ca52c9d95c0c3c057d35992c91d69ad0d66addf42a60a5a8d44be719e3db5e4b7f22ef72154262687dc7fd1bc28bb9111329a396a7227320e7a50af6169416f059dc2608dd2a19d34e17ff0b55a821069b6856392a4529aa4a91fbf1aa60e8f62e4ed6883a254a0e1907004fbff2d3cdf61c14ba666ae3d3fc0458d9d0bd06d1953ccc799dbce98b3095f74ce320e66eb5e8a789296a57af7d458193b1ff821849bb7c0f4135ff4c4e111853211de68285dbc29c881d846bd9bfa182ef19658fccd30107da42b2ac0e82fe0895e976e04089eadbc86e7f7ecda79684f9c5ca51d1e4ab08ef9fe8091ec9eebf9b9f6b45f75f2304ecd595d4ecb636d9fdfad62197b189135e4370ffec550a3db1923f5aaf081c4bc89293ba6ade67ef59c713e0b667c6949dedc0076e8860f5af92e822ce974bf0a5269b9ed8022aa996c5aa0b846901d26a7c7246bed4da1b456759d9d384a96c5c457e8a0ff4970adea44cf2675740dec1d138166b36d7790f6b123c8865d199a6231d8cb7e8fe785a0ec340ea06ca873662863d1d8827e3d04c3f086931c15be6747c89c26664faa7018e7ee9694e40570c85661742b19d2e3c6827b4c827dfa518e80854cca6bc4e31e0b23d12694548ac71d6ee81ec6039b438e57fb3faad22ae4c38dbb58b872a35c0aec4255636f3a96c975f4bc18b07b83edda5dbaeb71d1be6e7c85f50e130b29c474367e0fb95ccf01e45cc9f4c81ffc5cd939a9f6befff658ecc8bb8c45988f935ed5b8bbb60567de857d9419f622c9a3eea06a028b19f75c6d7e367c6e36d448949f9f35eb619b30a015670e5927bf99303a6057c3de22cec8dabb52184c49c3f6159a3f6a067f4e0203aab2f6633b4494390cd8076695986398479cd0cc172a6d3f8ec3a97f8be2d01e940c47d238e21af5da53a752e448f994515a03996798d7a77f8e39c2ed1ffe9c12414fb88438a797dd6bc8df8b6e112ec792f0a3b2fceb2fdc59ac42db9588d10f51b2f0f510a65fe8c1c198593c86947393c7ce68340ef8120e2fe696b5f871a844af54004737fc420f84f5f6041f248cc8000f36ed1afb811e9a75ea823d84712d13e40a0abda53cec532ed77699d660ad90309e41e326cac44814e89accb88e7332552b2bed322dbadf7b651163ade2431d0f07ebf750c62551c60a2aca4ac94897326c30fd42fa3c9a362a46cfabf06237398fb14b9f7af9cd0037bfe8c1f51c818feec37dd3c0f5c1353d1891580a362dbd9bb489833329b68047ba0a6d8c0b6cb7cceeb7b494ce20992329f9272b3e5f665702e74b306592198282cff24d8a8e6aa8cf57c507484f9bb1d390c1dca12d2855c071272309288ad138c8f3c82e618a1b32e6565db5528c5e1ca594695dc596cf0397badde8684ed988de094880ff53931cfba8309d8292cdb5be841f3de82e9eff737c14c2cf3ac5f1fec80fdf9bd231586d99d755aee2c6292b865c6e27f9b648c4136f2e673061720db82dcccb1cb2451d2817ce7395b677ccc5632fd183b433f880cab5ca5a49edf0e0881c58132a1d1ae4232d23386ca5c3830c5da01a3c2609ea41f19e9933cc95becd56b7cecc4308608c4e2989d6b1a52cf9248962be64c6ed8b7e7ffe982fc733b54f92416b81a1ffb5020d01b085a391ed61ca36583fa85cd546dc8d1fc4b1ab3e107583a854dac281b990b046df140b35b23263cb1a6271232f84ed6c16cf5e1cc7d58d978eeb0c2a2fc8a6e0cb1c01f9e447eb5cca109830542ca53fff10c32e8c24d10c7af28830bbd4fecd9e04fb5a5279b3169445e2c7ce095780cae16257171215fa64fb153e9fe24e8efd95050247cfc265a705bf337fb152a50d1ce7ac4c988ac36393b89298cd59aa703c936a881a29862c2e1bddc251b9bb02a3a2744ac1b9e2532cd596856dc8f6a45521f50047e3cabbda5bcc8ef304a82c7c78742e56a218c7a85c0a310ad0e56164a0c91790058cd53c33551614164e7f09e6083242801943b28d271dd7e6b96b08631f553b6e3858c31380d5d9ebc32bb4a0f3e66de48fd861d65284083d5213219a0a47b8203ab2881f2f508293e18da4589e1d2763ef1701f831198ce99761233bcf5b498f22fdbe4d2e4632fb2885c42bc06116b98b64084b42e5543a40f4ac7c88047bac01094201b7ca003d4005ae9d4f44730750269bd7ed36210268bb5b7d958e56a1fa057b9304a2ea6c531485929d6e0561b8d20bc5d08f096429bd6febaf525ab467e964539e8e30083baa8725fd631a13546e333709545739e09ccb845ac3917ab2e5015626d13712a6134c45a9978e369e960252026d4b9a784d40fb09d691fd8e5eb267592054fffacd957e61644fb2ee78beb36362c408dd1298636546d39760dc1b07b48b048b5f6bf0fecd0a5cb12b43fc31ca48bf5cddee43ab8cf845181db0a5cf64f62900239a64ef09137dfb6d69c3c26164ce67b5da10b78744fc684836e491851881014a02c67dcdc9686fe3cd50f8097080897ac274b4c1d0470991f44d19790edf3c33709216ff5dc041e06552b6104719a8f13154068fda512a86a53ae1ffe99eae19190c41468ad3a40d053fcddf96b05efc4cbd01c58e31e0f2a9173c4be95f3427e370f8c1684845147b643687a70d3434acf7fb0b6d32ebb1fb3c3a8941180b090508d677f7b8d642a9b852415f3ec8d0eedde27ff6dc192c961a3d52b1fcb98bf4b937ce41acde6e0b3abc1ae39caec8272f3098af83a77e7d27ad37edc0fd951d52c630181f188e3fc0764990168d181cce8684380dd0492b4bcb1e806a23b9c9eebbc00af3cd89d5f2f00c3981a00eed45a1715da5b506a885da4e047eb0a076ad72c935c6e858dbe9723c35126555a73c5574e0caf19f007177cdf244cc18e8a6a29ed7186cd93568fe1e5950e1e5bacbce62895d3ee762a74a7129a474312062d8a1a1174f7c8cf0a0b4fdddfaef4c1a1cb6cd0349306206cd834b4dde162b54fe552813cc6ec104b68a451b878300221d4741575f216bcb3f1fd2aa0746355dc59a66635c4a5b0a804100c21dc2c34294660f0517c66e21f1e32b64ebccb7ca2b3eb807608ed75ace8ad0be196d6eaaad759b968b431be73afd5e2ef698144c40d894d00944f4558ac62e64a422957d77a40a4b0161b3ad71761028573c7cdc84e1fc6913c5354079d36b06deb03733437d7991c078972e001abb735d3852ef6af57e52c35ca74b0d05a85e6d2ed96d38c511b85a5d9c55b5e7e1f4ffc131520c60fbb4238958001508c59cbf038d34c399e806dbf5a27a244ae5c45b245f1531486f9325bf9142170d79c580c9cd005fb25947dce12a1f92ab8d66e80230a54c773afd1ff22116113950bcf0a884c952282d70a7abb59e5870546acc0256e2229c9fe3da6753f19ab8448de781293b8353c4548c78431858ddd7797be16ce0c3ff0bb6b67b61740032fdcd3e52699b47d663aa46594bf99edd0bfe8a86c8ff12ec4e9aa12fd7efab5db754ca76547548a92af8583f694156182fa06333b3fe34226e100146c4724ed6737723abe574c5367c85cf224b838979b78c0ffd78b058e7fa50e96853f30e4233602902d0a04af42ae5fbef101426af41260b09a244018f2e95d753e392252143c574b9b51227603f5684791ab2b85d932879a050a68e99a05061a162a471a2b477330048363060a5e06c2300294fa23fa9d566a1cc41f8108a7c3a7528c632498746c4a096c2d70528df611fcd02aef9a32ff350b35665329dfc2320533d551057019f3791e6e42b571f04b1211e18f095f0d05514371cc03b71c752e0fa892ec08a11002b76c7280ebc26953e5b01e5fb30b9299f1425c5b72b40acf5c07f2424232d4e4e4663c3b39dc03e32e73a920076aa3c328db0ed1311a71f0326614d0d1c1fedb8365f315e04b3c316c31f7a74517a6849345e7dde0bf0ee4df1b85f33085a6748d1c51fd4dcd7a2ae6a173ec5a3dc69bd9346bb399c19878af728e9891c19786093e86cf3ec4167527aa4345f675ff16ed23da3c648463fe015741c699ecee8fba85902c365580886cd3375800ec80cc04dd6b2c1dacbacde69d5a9cadaa28ab1108150089d7d3c209dbc2201eae15f68ed483bb9b9506ddde585948ad864377acabc830c82ad14296dbef58efb9520c265328d1c3470cf8f0b56b4a88dd2b1340e57942d7b4269388794afb3a452db1ef25b71eb5f643dd05f4288b5dc262d474a67a2e78726e8d0933c99bc8e797d73c1896613e14cef89ab36c771379275e7a00d775a4a7aa085a2a73c4643020273e55d61400adb0a113476537fd8805e4ee2ee46bfee6d7f87434b668904081fa5e0f18701834fa3cb099e5d1f0c90ce5077cb097e9415bdc132f281711a9ed188da63ef84431735a5a7e74750ce9b146dd05e318bd0a3b602c81918892c02856ce6e6a01906a07f4e7b7396aafe005ff9fbdd0b9e2477065820617617abe2c607d75a1a44ab4b4e3b0444dabaee7b583b3695bde2599402533a3b20ef5d5d89264e799be7a89e65eb57dc2214b47036bd99c6c204771a1b453e49333a13de3c5cd21789fd94a0ceac3adac0e8f37e3aaa0d1b81b0b408ba25fc0a21e976f024d6bade56226125831a11ee174653fb68f8eaabfbf02f17a37235329dd73b972b493789197c8ff9a3172e40948c9e057d3ef35f0bec051c269eec734ad0353d532bb81fa0e0710fa54ad85ab317326e86a5543c7cf183587f48fed52ff3f394036d8413bd110b2891e45f681b1b4aa75cec9db3c64ba37259501a31b99efe8192435402a91ef44b0867ee30919fa6dbc4c21b84589d8dc781fa95134fa8eb333e1861cd9e50178d8dbf1d1df7c2688f21530c0d328730130bac02b2a8771b6c0f85e6764595f14407e5b5bf73e9822a0fc71ebdba3e3dbef7c6959ca01ccdb76516c9ecc4462a93c2d01f31f065f7a302ab783cf1c4ae16b35f79a4a98e5195b1d5457521ee49a533f6e93400f772565a59dfda43dcdb09adf099bd207c2cf37148cf1a8e8b1aca1f56745a9882493915cbca373875ef6335b18d271535e3ffb4a0d45818679a5e215b939b243812e8019d32e555c6746c6c5696bac350051d7ec33b3b02c62ac93f3735bc4537c42a262a29c6c876dbd5caa0a28db465575a4b0c1f2cbb0cc65b3b55437983b95ba8383b8caef0fbdad1e9790f644aa5e598d6b17bf55037d641adeada684f36a483821826cb707bb3fbeaf8c72c116fadbd694e6711205b3422abd30dad5bb061bb3e9b6dd2fe1b255395a22b423ea7b4f6783424eab7377ad5e67ebd021797ecf2ec031e91580837c94624c43e404f82b38504625748209c914f41b87b056be5e5fd9dbe4ec29231c923053eb5645b36ce3d5d13194a654a50e0be21a113b2bcb8679f6177b5f15af16c6fccc9d4e0b94d74cf7458e0cc66684aacea0abdf7bb75672825f59b4d4aaab0657f3ec6c96399846b4bfa1b2706a25971aa711b62755d57f0747159037ec30d392a058fbc7f85c193f48980a216a1337928e4988f7f4e31f00c09660dda47f92b5ab673907aa11fb6d762e809c6ce7d3bf837e7217cb9f678ceb6155ca558eb256c415e8ea577553cb4a8eb2a2881574e5a7e256ca0aa772a58815f4ca57e9564a15aeb2528a2a68ca97e25296142ea556883d27b0962b02884a8e95a0c28c1091f70e4af6b7d268d1d4eaf4cc5893fc714b1c6a8378a29428085a74522bc4bb52a240a3950eda82fc5192e0e35bfde6fb87cae9f7f917643c5acfa24f24249718e86f5d4f8ded08b897e2a52de85768a8a058678ab8d6c9ffc6043c8eb1ce63690b0985f501ffa75ffc9fa12b0af24f7c7a857eca9ae257575a0fd267fae72e513ffcd66fff19b446805e14177a439f5287a0ab0e1a0f1a486c51211cddf5f46d261fafaf3580faf4867ea547e34a775a4fa327e867cc57fbfc81487d505b987bd7f34d22e25c1eaba111fe723f09d45c9ce6ccb08a5cfdad5fbc0fcd4efd4cf1a30bade7e933f9f38a38dd17f1af55a3204b545bbffc175a2717c545eb91de13de5208d75d9e71872938ffaa476fe8afaca8e147884eb43c6911b16505faabdb9ee7d032faedf4b8a81bfa951535c4f95ee0ba4c7fb322cc2919d783630d0aa25bbbf8b84523a1f9e1fe004f57195319685d055506d994097cc07b137651605cd8814acab51176a7c68aabb90a91ef5b24fbd5782d0e79e940820f3e26f43906f00a907cc1e9c0d7414c6d28607c7c21352ae5b5c2dd8e6cc8ef7bfd3c4c49ec516c702adb205d1b5a0ccce18c8fda56e418b66972ec0f560f0725f960f70628ea69ef092dff873b66f6579df76d0b119a71f05b6f4dd9f2e1150c372edb745734d6f9f2ee7a973c71b35b5a4dfb4e48d1bd0a6eda3f49ee3444acf1c1261b558713d2526f2b37884f4567ad6caf9b7db7de803c7eb7413154b2a135635b850c4fb2585145cbd935647ad8092f5b7a178436047ece441f11501040c2923a468ffb199af514a9cbf5e765d571a71abd21bc9316e70b0ef541cbd584a547aa549fc7421583fe249432dde7304cf7391898b7dc4043fdf31f3aa14e4ac0dcfeadb5ba8dca6df7de52ee1df510c211aa105dafd9677f91af92df6f92dfafd7eff7f92de87a44c9b225c32adeef159690345eb0c4b0a6e2fd9228c3c46a4957588c78bfcb0c5862a4b13ad3020e47bc5f2c35665c41986a5b56f17e9b52561c61209912622adeaf46912e691475df9bfbece9eeb97deee9644feeb3f7e492bdaedf3d24bf7b477ef77abd1e5990b31460da1881d215ef5ed5979345142346b61c89772ff9d9ca45db0f156f60bec4bbb79481102d36d1aaa91e21e2dd635a3181d166e564c75bbc7bcdcf4de70e28560d1b56e2dd736636bccc8627fccd9b9bcb47aa6fdedbcff1e23e3bef052f4ac9e3f178519e5b9674294bdde74473a239d19c1c1a39515cbf7372727272a25ae6426885f151a726de39cb33272bdeb8b99938c63b8749245d2252f7384d9c264e13070707a7acccecb3e31c71a29abf7194467ee314f98df3fce20345520773ccd59678e3fce4c8a164e1e6e6c957bc71dacef8206bcbf1e20b8d78e32c4b9c388bebd292252cde3841d0844c8d607194638b370e8b2e56584a444c9d88378e33cb4897b28cba77f3d275f352eeb3bb3a3efb76a3945a9f5d379a664797a6eefdf76e4e6e27b79393dba9b57df65d597eca53f948f5bd337bd23e69e9a02db485ca7df6b6ad355b91c695b5250d9a0a34f1de318d634ebe52849541a123debb2591df3badddeff76e37e4dbb956cdabce8ba57b166eb3723e65545e5260deb45011ef367d7344a9c6a2468c2942e2dd7ad98811f684c71ba928f16e971f80d9ba32958666cb8d78b74c0c9c41316122c79b1bcf78b7cd058c3031e3ecf9542325dead73eb77fb1cf2bb15f2bb55b6519fbd3d3e9f9dfbecec312ac86f56a9f59b05f29b7d7e7616ca9ab16a6c9b1cf437ebb6fbcdbe6d386ec900532404da9278b348b3105c6e6c41ba3189379b7c4184068c1b2198c859c59b5d7e964135e479a64cdc5cbcd9b21923c44c88f1a0938a37dbac00444b103837636f5de2cd3a3f57a54b6a55ddcf295755b9aaca755dd71e3dd635bafef8bd2ab5d6a72a624594352da4e06011ef15c9620b9b35415484897989f79a3c41ba34a6ee35081a4ec3c969b5b2fca446e523d5d5286df6d9f5dbfa5b47f9f8ad959f758fdffab9b31cb2e304720e4d8c786ba4037cd09032f38508902ef1d6491488a9522356c28bdc8e78eba605945021c360a12166156fed9440ba44979ed57dce739fddd2729a26f7497549e992ea5ba52bbac115d32f39b8df398ac7efacdcf13bebf89d9f6e9c3da7e5a804a2a6d8980873c2868978676408596a598e5934acb8c43b675131e25942078b3430e29d975bb9a349c694a224de99a9041343c5aacbca5c9378e7265286133146b8acb525e39d9dafce7d8eb76af624807cb4d957b3d720edc0a64baae7a595335ae2c4ccccc450309080a003a3a4cc491c77846a4d9b1c3d8e6cf156995f82275c3fd284d01931136f75c9c30a0b6d69b60549166fd5f931b08478b91961a2b68cb7da64fe569f59bf55ad1cd9d5e3f1b3d3c07513909f829e81fcb4c6d941909dd22f36c916c78d576d7cb6a2b2046d0b6d8c9129713e62e5cacc57979b3566e20dff09ba963ae2aa760c898214238c9b17346b405489a1f453015a34b9546809f3c42dce52ea5e8095613ae98a2f888079c8bc51af3acf1838c806ef5edaab4e5cd30b7bd5896ae0ddd37ad58172f4ae5e75201cf0ee21c57861f0e6455ff52523bcb2577da908bc79cd57fde807bc79c8577d870cde3970af3a052f78e7a4bdea14a0c03bc7f9aa536802ef1ce6ab7e7405ef9ce4ab64448a3cec449975a4fcb4c6ac37b9ecd308f1ce735ee3cec5798d2c54cf14bc71e45e75a012de38d157bd8704bc719eaffa8e1478e368bdea14c0c01b47f9aa038dc11be7f86aef77f0db263bb6be5dfbd65d16df928d697ddb84c78c6fdd7d8dad03b9487bd581aae0ed3a5ff5a51c3d5ef5251cf07695afba121537ea55579a02ef1ddcabcef445ed5567f202efddf3551f1ad97ad5874554f751b39b7ad57de2544f4ad1f6aa27a180770b7dd57dc9b6eb55f7a98077cb7cd575d6b454afba8e1af5a9c6c5af4e1d7e75275a572faeeeaecf346f179ef59d537ab6e35b6fff35ae503e5dd25e751f2ef0669daf3a8f1bb6c7abced306deacf2556791faa9c722c1de650f6e1815f7aa0f45c07b8dbeea4725ca5ef52312f05e9bafba052eeb8d57ddc21678afc9577d2886dbab3e64056f0d7dd52d58d15dafba8534786be6ab2e7c837f4ca8aee3a4ec55d76902efdc7cd5878ec0404e78af0fa404d6716b7bd575bea84efe29196b472aea2758bbab1d7e9d64c4b3189ef5f535b2e9538e5b82057a8c5777d3a7345e5dbfc615ce504efdd483ebc17d521078f75ee5abfe2adf2bd58917971fbed63db89edc908e1eaffa101386a5c051af3a0c857f580c5bc07bfd210bd87784f7faf01b78bbbfe1f8afd6a71546e040cd603fb41ed64004bd86589d063e50c07ed63a5c5d84540b90a863cce6cc8a519510114555c44423a894d83da55a23bf231aa1f53ba211cbdf118da8fa1dd188af332c8846ac389f7e9d31c1cbe2a50e2622ccfd3cdc4991544f85388ff3e96bcc3260f5f7ceab9eeea41c5209f052a2ad56186e10be82abc20dbfca0b40fc193e3001a0d8c112074a1e923a2071c0b0c105a8a327a293d106cfce41ed50d4e4d93bf8a076d090866d759980b3f79a5d01885fb8ba3db8071874222252b109ca4306269ddf4fd0d0b0e8825206270eeb7f60ea80030f1d386c00f5e4b4a1c909ca83da218333b586c0d9df1e5aff0100c2d5edc13dc0a01311918a4d504c459ddf4fd0d0b0e8825206271d0074c041d1c35207250e491b20416178bae074b481d864a4c1b367503b1465f0ec4e6a070b4c1eae6e0081b3ef2c6f00a0030e84abdb837b8041272222159b8a4b3abf9fa0a161d105a50c2c071e96386c00f5e4b4a1494306a56293daa1089554aa80b3c3544a0e3c7410ae6e0fee01069d8888545c52d2f9fd040d0d8b2e28f93a70d840092ae909c909c3860b4d471a88198c983cfb05b54351d1b32b15d50e4b4d9f5d8d9ab282b3ff90531d386c205cdd1edc030c3a1111492949e7f71334342cbad06e0095e4b4a1494306a66211116908834cd4c71470761e1aa8c70da09e84abdb837b804127222621e9fc7e8286864559d8f3e4b401a90983860b198e988845a325cf3e543b142979f622b58385a40f42d00167f701218427a70dc2d5edc13dc0a0132161d0f9fd040d0db370b7a1094306a6e292d2901365f780044c38fb0f0848b0a1498370757b700f30e8182ee8fc7e828684401a32305d281e2d11958c923c7b90daa108c9b30fb9da01c307449f3d0219180167075620031a32300957b707f70083178e747e3f4159e832158f9492907e80c1ec0568c012ce2e21010d602a2e0957b707f7008f883abf9fa025a52422921106cffe533b1479f69e1fb58385a3e067f72000197076a10f0258524a12ae6e0fee211ae9fc7092908c2e1cf514a1a8e0ecc126a824240cc2d5edc146453a3f01c305cfeee6a81d8a889e5dc761b583d1073d9f9d080909671f222261b870245cdd5e514e8ea76a8723cf9ed50e440b4445403f0167a710f423a2917075db7723cfdeaa1d8a2cf454c1d985708f91305597b21709b3ba94dd82705597f270e8697622f2ecabdac182e7e10e210b8b25e09c87ae0561aa2ea5c2550cd6c79f4f27cdc40ac2a1d02908878413841be9b5078542c220e19620dce9f3b503b50369ff11fa68efd1ce23fc09b71ab5d5a91de156afd41baffd15f6b4f3845bed4a9dc062013c80415265eaa735867370861bca99b61bc26df588dcaa721d6e554b6daace57919e4126cccb6bfac35e266acda64e0f50455515aa5bbacb43318496a9e5e1576fa19a3cbcd6379a8030949a54b645a4a6d77a0a89c88b30508f48bf7a4b2472a40f741c11f003a2076e1e248a809abf0ec221b0056833fc41f035f0758fbbaeae57a80f7a5ed300061f0251cf6bf8754f5d3d84dea6c1f732b1f7ba675d8398dec0a9baa47dbb21e887250c61f2210d40fa54d4c3942d3af9500056983a3f08a00009284235115913a2450c163088704df5d002a3498e36b8b9b45d0d109cdd80a291e27a7205490ea499184a3265a4d020d6800162ca5c8b12333a10240cd616313b489435d92d556431733e4db8f0e1230d43420e8e39468683cd12ac74c90c37665654903abca08abc6963458559d447d70c0e9078a21c2283ce0c8c14501271635a48aa2d44763246a06acb02724339630a97a11c1cd8b22e8999f3c7ee4a4ad898b132ab31e6981172a4c92a71d5050c1d0b668c1ad09d0d6162f522461a138cd87ae226e608983735acb28499bd3519a22441868993a926ea15c743c4158c76075ab30c0815254f00c831cbb26ac0a07bba508e10a4ca0a855b11164bc856266457369634718e255fc02348c88511c10389a388973354dc9a785102559e703164a256230574c8893637d2254bd6943bd89c8d5929a3aa8a3b2367a0209330b1e165ea39972684d4982457de50bd2e662254b1a9b80ed32c57565c60390b83c21801479b3151da8030a912126b4f5fc8bdf6353fb5b16ee1ba30b04bd2ed11731645b37265ed4b89279a67cfedf9e2c973f3ecb579f6ac9ebcb9679667ef6d400440082149a5b5958939e7b575737a3af0afe707089789d9dfd7a8c665629a526562f6a19e76d34f39a9d5f2930aa78fb2ab6dffa442c3f293aad5d44f6ab2477e02019aa655a6269d705b50e667cfce1c969dd65c969dd8ecb4c3f1ec192ecf69a4a6ca4e3ecf501fdfd9ccf59dd57234c7777603f29ddf3ee738a0ef2c27c1771af67a2a286b6516d26321dffaeab30b55c13b6bc57df6dc15a67af6bc953b086a6527353ba9aa191dbcf3f27b64a71d427b83474d6303ef7cfc3ce52147e50e8219b9834508096f350a7d836a8bbae954099a83b7ead42a6b0a733edf2d2ae0ad2e7b146f2c993d362978ab47750a292a77103c66271e9e901458a8050cdd1f103f0be971d0793c3b08720741cfee0109b2138f670fe6bc461e21702fe7fd09b384bc884c08e735fa7a54e01e1816660505b9af718757060e027584591224ec5ee3cb0513ed5e176601bd880cd8be465e2f0c466a5f621690179101b1af11470ddc54ccfaf9e1bd813d4065f9f8e8d7c89a81059089d93f64f5788f3087e5a39c9d6f7002de026462f622b2e71167845ff645013bd2038cab1994e443010490828d9896e4338a8cb712e04832828514a713292f72f0bce002000b0d35b27a4891b8d1f5266563828b962b38aab495b9c0b2e3228c87155e43cacbc59a2c176046d8d2f1e6268a6c88153017553a2e6c402553316c44d0805b21638d8811ba4094a09b92c56c0d4b159ce8061531985b43e40a4d6acc589a2125e452a448b37cabaab156e560525340b9c39da75f7e374645a6e97755a08a395c9c20afafa9b77f3ffddad2e2799f7ea5380384e688e1a544e951bb480f5ccffe21bb03e55cd777ea064c83a1e99308c5b2694e814da6d399b314217a74d911963bf68307fe7ab8aa6378699abade39859c739b87bbddb16debecbaaebb765dd9b555d7acb566873e74476855d6cb8eaaaaaaaaaa4cade69245aa495855aac7d50d4ece03fd74d33ee4752516a15cd54feb71754fc0e9675555b55eb3389f073c1e8f209c71da5499acab48f5e881a76e70c39d46d7357d02a1d24d74fd43ea749ce1eafca37ecacef428e7657a941da884934e15e9bac1cb0ffa291fd3a3ec6a34559de95176605a4e9f4028b8b889407837dc70f6d6c98a306ccb686ecb4e6e6e148d0c2f6cbfb37327450606f73b2f5b345e57c0fcce47368c8709b02dbfd5e87aa34533a2edcbaf2b4fe79ce1de1d29abb56b6f9d751aacdeb24311325d57f218afabaf43364d1fb1507da4e6ccb2e1a5449b8dbeea5b3b59f2532793e6a7d14f9d4f1faf932907ed4c93d407e458377316e244fd8481ca9a35ad63ac7a513f8da044751870b06ac2741e637584587535a92af593ced89426c963acbaba54d3321cd0bcd44fb9998f480d4672b8d18a55cfca0c85cab9a5e9a71c0dfa99730d76c79fe9f1a683eec943457c348b8195654bcc1b3171aa9fe02f307e9860e162f926de2954c7b3ee489ef50f4cbc9e8d2165cd1c8e64122c2562960991675de935b2d1a4d708e4fb9f1fed3f3f3f5efcf911f33f6759cf863deb48af913d5bbe760caf51fb85d7f8d3c1fb58997a1f3f7a8d3e55c8bea7c7813d3d4e84949d7adee3c51e874aabf13d1e7a7a3c03704f4f9a9befe9e9e97195aaa7a7a7a7a7a7c7d3ae07c0fb9cf81a7d382ccbb22ccba60d799665dde835b21c3cec699787bde835c2ed267eb143152dafaba4bd760b4fbe8736f73d277a8dbd295832a0359a4a52b869a690239a5b58149692241a9b6fbdc2f035f630795a80781e17be469e249aacdfb913edbcb85b71f53b9d5dceb1f30ae82737deb907f06ec702c4ef787619c7aee7bb9d6fb77395c9e2ccef76377eab4e57cb76bbb4df95e50893453906bd428b772bd2c69c55dc8480897735b68e2ab69c993961b32b71c5668adc0c2127e2ad1e1b00460acd985609a913f156b57e374304da1b2cacb934f1569b2c64fccfd79ffb6bfca51beab5a7458741e135ea28ef13f23e1f7a8d3e2a5c646c754b46f47a36be97467f5c9161e6c708b9b0b8b762c7f77cc26bec053dece98a100f7bf035c26e0a8587157a964db27836197d56c59a675de835b2331041664819189116ceb6c6b7289ec059b9b9aa2a638b5b1564bef5a0d7d8ba84d7b88beeb039f91d07bec69db5bad7d1a1f13aee441d9d2894d7e1d1c94b9dd67574b48e0edb91d7f1e9642c1d5793fac98d755c5566a7f475581d1d77f5130755564bc450a188b2893f9c914aceb59965d1999be286450b246d55749aa8a1359f69b07ce978aae33ace46d99e6559b6132cb0f75a1fbd7658ebb503cdbc9612affda76ddbd65bf7798d6d85dfada9fdce7b5ee38ee735eabc9e26fff5df6b7c753c8f37e379eefac98d794e44ca4eadf3bc089585ec791e783ccf40dac67310b253fab5767c5edcf346fc5691cf7335999d58e7b94ac5bb7a1ecf5dfdc400e6162b492026c68cc43c4ff55304583411336506848813f1869d3c4f772af73cf5f83cb4eff5dcf71a7b566bd844682193e258176ff8595606084c7489ca5813e24ccca6a07bd6e1d7c84af89dd6ef7ce735eec6ac7dbd09f14241e2eab572ee4c0b122e2f5448c49a05d56bd7798ddab38cf8d6dfd7d8be46de6b5c9739c2f70a47b87a015e7fd0384277f8c1bbc411bac3579989aa2bb981f7abecf056a54b6f55dde7a657d9f42a9b5e6553139ab9a618bf9bac7e376518bf9b9a9a9ac6a4d0f0a2448b8d2b2bde4dc81038bc8089127b0316efa6e4afc61ba60e31687472f16e5aee3871d616458e9588771313c5dc0e1d5d6a101111ef261b5658615248668978378dd1304643db6f0d701ae034f4e03468d0a0a12c3fbd516f9406b3cfae21eea841f95bc38bdf1a5cfcd6e05c6362466c2b0795ab786b40028049862bcb91182068c45b43520ab94679a6c6dc58bc352c73e45052e5a51c5226de1a985b9a88c0b116840734de1a2e34a966648995b129e3ade12cc359062ebf33a46548cb909641eeb3674866a8fa9d81ea778616bf3364c890211ae6055b8c2c232b56c43b03528673478e1b544892c43b03b4860c23716c72dc2811ef0c2ad20a44101441a6dec43bc308512db2ce5a18c172a42cde193e60264a9c16882033b4e29dc147bae4a3ee33534f8ba9a7c5d4d3626262622acb4fbdb05e1813d39289c56fa615bf9992bf999e474ed4889c51d13d298b371392a9dc0143a943ae2cde4c492a2b9e6042e8904122de4ccb1a43c8c67278599b8b37530aedf1c479054b0d1434f1664a40f48845049116489ec49ba937a2d81b517cfe2ef690c51eb2d843168bc562597eea5df5ae8ac538ada28adfc514bf8b287e179f3bd06c31c3a54bed4b19efe2545b883219459a5125f12efa940c1b4c80b8a04222dec5dd91a89c192eac2b63f12efebc69a3824794333514f12e761933d6e50ada5bd44bbc8b59d2a52c759f97a24bd1a5e8d2d2d2525cdc92d9675f8a6b2e4dfd5e92fabd74e2f7d2335d2325e42b8a8e124810f15e4a2205240c182a2268e2bd94b43056a48eca11ba286bf15e5a0241d9a4c9128488f249bc97986c8e2b6b64d4e0d060c47ba9698204151738ce9031e2bd44245d2252f75989d754e23595784d252525a5b2fcc42be3952929c53995b289df4a19f95b2997f8adb41c51e3870d363e7254c55b093982b6a418161d0d3722e2ad942cbab1b6848eecc9d58cb7d2726a19834c4d19922ade4a4c658a195c6054b9e226de4a3f5371584c9c69dae6e2adc4a391c4a391b493783792de9e772329eeb32791fdfc4e8a526a2525254593dc7823d225de88bacf483c24120f89c4432221459148fc46527e1ef11b09090929cab5e244931b724faf782321bfea4d324c0a3134af7823253f5f95498226ab8891b3782335bf0ca932a34637264bbc91c6a44b63ea3e63c881c390038721070e038638380c51bf3188f88d412bc46f0c183060887e2983a5cb8b36b078634022717103cb12af3264bc31c420c814158da6d80e2ef1c6e044e5c9c5e549143174f1c6b0e6a3c8549a2a6ff1c640a3485d082155985b6ce28dc17976e1ec0207bf2fa45d48bb907641eeb35f88a3bb70e1c2850b172e44bd8ebc8e3cfc3e721e398f9c47729ffd28cdd45106f1fb281f7f1fd5fd3e3a3a3a7a81922f7225ce9a707589f7919a193e7e640119239622de47c9216b6ef8101345c62dde474b1bd1252e740441ab118df711b34c8db5b0a91d5f67e27dd42c03e39a1195e34a955abc8f9c3938883938881c7e137398c41c2631874924268951442291488ce6a048977250d47d36ca491ae5248d729246464ba337bf8d8c8c8c8c8ca21e9c6e65a6d0b0a26449bc8d9022bc7a64e9814cb122de46c934e9529abacf45724572457245729fbd288d5611ddefa2b9df456e7e173d3f7b11b4a848ada82d65d3723b729961317fc4bb0839033568acbac8526049c6bb2839648b0d29244c191cf12e5a7a9935bb7c509d1d81c4bb8839024c13ad263f966f92f12e62f65881c6ca9a921a51f12eca62218b85a7df16a216a216a2162c10b11065c182050b16a262e99258dd67a227d193e8494404fd4cd4e63711119bdf444444445ec68e3458901d4b9489375154c9151b7260d48644c59b28c9854b8c166acc66803de34dd4a480c646268697b62868bc899c383e2ae0f8a8b0e17705ad0a5a15b42a544813ad20f7bbc29adf15d4fcae50a14285b02029e2d0c4a80a8115ef0ac8205abc346173a5e54a34de159235d80a8bf206e5869a57bc2b2cc73899f1c556b58249bc2b30cb30a7509cb1ea32c54dbc2b342740a7c6c59912501a68f1aee0c4a91ae2540d9b7e0f9543e5503994fbecc33470c334bf874aade170388ca24922069d2a63a2ad19ef211209879613356132c0c2c47b9874e9842e9d50c36f21ce51887314e21c85729f5d7814c6fd162a85687e0b85426154889aaa1a7358626c52c45b88dc9202c609178bb8b5780b9327cc74b1952953232ddec2a609c2d40561f2189366196fa1138c83f10cbf7deef35b7e7bf7cde33ebbab41e1514a2df7b4ec94beab7df674bbbb79a54b5e759f29b84e0aae9382eba440810285b2fce4a6b96914282c79bf299cf94dc1cc6f0a70bf29c46004734df387da1793785318001a29ada794999832de145228556eb6d07dd568e2883705635cdcf32b4a881e63f1a67081341f5f6b5b275a7cc59bc29b12335f669e45c268c49b825b952eb955759f875ce590ab1c72954343434365f9c9edb187cc3efbd071e7f75099df43647e0f8df93df414246e850832cb296ae23dd486eb468e206a90439cc47b28a900265ecb3231559a0489f79007e5982d3367991997780fa9799932e2c344d40733de43cdcf46a2a460296205778cf7d09874694cdde7097013e026c04d98306142597e72a3dca80913b426bcfd9e20e6f78430bf273c776c54ca34bd80e19115ef094804b8e83a61428c8b122be23d21996a512eb18859ab2a0322de13963c14695748d8a0d2844dbc2730b9dc504c1529836623de13a8509993922379046312ef0962e99258dde7e0ee19dc3d83bb6730180c96e5a79dda4e2d18747ef61d04f33be8f63bf8e577f059811a6639c4b06895618b77106900325d6044ab68a90b8b773029c6e6e5edad8a7923dec12509ba9a566d55d01366f10e2ec0ad0b8a1864cd3828f10eae8d01f1d17cc3a2e319efe04e86d04e8650d16fa1dd5268b714da2d85848484caf2d36e6bb72524147d7f0b79f92dd4e5b750db6fa123ca1c595e26927161e22d8464b2044995922c2b76c45b2884922e45ba9c804b33126f21362147404c793177166f21260f279922614f960889b750b3056a39acce54e1911c126fa13441698286bf83e482e482e482828282caf2d36e6a3715140417c4e577d096df416cbf839e1c588226244814971428f10e421ec0cc102e5d6fc4c0a0f10e4a8e00240ecd5493c68eaf13f10e5a4ea152c26a8c978cb7780731353ca7b860d0d8aa3b13efa01b6662c8c94033f18615efa0f68984f68984a1df12a012a012a012244890d0d62641821a3909d1df12b4fc96b0f65bc27304233a78b0117931e58b32de1290259c54a9e0f2450b48bc2524ab9a106163c1e64c46bc252c7f581179ae5d45a9c55b0202e8967ca112236dcd4abc2584797116c6865bb3c996784b70a61d5a1ce9528ba3ee33b065025b26b06502814060597e6abbda2e20f0f8d93730cb6fa0da6f2096dfc0332236dc285d24d15126dec0392597e657162533bce20dfc99a3d14288538b5558bc812100190364aec9991861f106b2a12215034c8fe40e30f10636a17429d2e42b4b49166f204b07c4d201057f03b547a0f608d41e81808080caf2534bd55201012181aefc06b2f21b28ed37d0b3032b3a1a3bb4e4c49c88379013145b536440c8c15d8937d00bbc58980852a7638923de402048aee9e1a5c30dc65bbc81cc90995a9679b1226c45bc819a64c68e37beb8b0498b37100be68705f313f4fb877dfb79fbb79fb8cffe93fca9f2fb07edf7cfd9ef9fe767ff81fefca8fdb4810089d2470b1f43a698c4fb0709050bf40817163a5ac4fb07090b29145ad6403953c6fb676974a644cdc79536376ef1fe612660ee8b9bba1f55d81089f74f33ad42457786d603c7159378ff38592f1fd6cb47c26f1fd6e9c33a7d58a78f8f8f4f597e62d3d8341f9f354a1fb3df3e547efb4cf9edf3a4fa2197a4cad8941f26e2ed83f460cb152f6c516aa492c4db27b905ec899aa4162755bc7daeb6c4b8116469022bde3e5e6bde906186884a1b126f9f17f878cb2a0356e6a64dbc7daad2a5aabacf3dacb28755f6b0ca9e9e9e9eb2fcc4f6607bf4f42cdbdf3d527ef7407ff744f9dd6336a5c89b1c4faeb667bc7b90616d8cb49569f18811ef1e1b6588b0593d81b2d012ef9e0f5ecc48c32204859733f1eeb9e2834d92a935439af1ee693a712cadd848b13113ef1e273b8287ee47d47de69963913c3c729f9d478b07ca6f9e27bf79ca7ef3f0f0f044d768fde671e379938391bc4262854d4c57bc79909fc5cc705ea16b033326de3c3f545964715f6c8841c69b8758a516c7a50d9932ae78f3f4a08bf332048baac99878f33437c0345247e388122360f1e6c9922e65a9fbfc5ba3bfdf1afdfd7ebfb2fcb4c6ad71bfdf1ae7cfc9ef5f93df3fb2dfbf2758d48c1a38a874c4fb87bc3211c7e522c7d59278ff929fa7d2c6d48d7842c42ddebf011cc76449128408579a78ff9e6296cc7066a5507ec5fb976e41f3e58994284a2fc878ff88a44b44ea3efb9abea6afe9f3f97c65653e1fd4f7fced63f2db37f6dbf75443e143080db2113ce2ed438aaded784b9323cc33debee4e7126b492320a6582889b7ef499a176b5cd8ac09b3116f1fd3054d9a44a4acb5e1d2156f1f0a1e4e92b4c09292ac126fdf8a225d5a51d47d86d7240caf491886e1b2fcb4de586fc0f09a282cf61b0efb0d2ff90dd79968e1a6840c1d5d6df1863340f6c3069a32143bc8c41bee809227559c9a123ba0c41b9ea12c31428690326546e20d33e33222736d659623b0e20d373f7b9888a65b911c6586c41b66932eb1a9fb1dbdf3f6733b719f7d678ddbcececececece4e74c7ed49baf4a4eeb30e5407aa03d5d1d1d17173d331fbec3a471db0df3a5fbf759cbf759e1ddcd4b4a93bb1068d9178eb2057d0e5c559a7038c8b10f1d6497ab8422b42e6c856978e78eb2cc7ac884bf214732123de3a4c9c202f629c8d798e51126f9de6e71756702071e3854a2ade3a38d2251c759f5fcd7c35f3d5ccf7557bdb3efb5b969f74573e525d07ce645b52a5b6e62a4a1c8606092b502e6e537171ea6a140aa0de04aee378ea34800108d929bb7dea15c84ef9cba7fe21f5f2a9c3690b3d1e8f445257ddb2535c72ab729f7eada5f17cf5deea3dd9e9f5d581be45ea57a25f8948be9b3e64f9b5b73ed3b25f53330fac34f9b5edd7f56d953b9b53a37e7cab48aa5faf9cacfd7a03c8b7caecf12bd0b7baf5ebeaaa5345965fd53009bed567d9af41ebea6a9409f357b5edd775b9d5b75fd5b895079a5f57e4d4af994ac9acfa35dff895f96b1efaceab672715e5af39ecd7672efb75f574f51c5da6f935b7fdba7aba5a58e57e3d93fad567d5c8a95f3595f257d7cbecb4ea1bbfae3d8c7cebad152dccaf3bab7e96fdbaeab45f5d47af00f955b7fdaadd7e7dfb356ef5f5a8f6f6eb1af5ebba4efd4af5ebd5af9e5afdcf7fbf9f1321652724ff79110bdaff7e7e5c7e3fcfc04fc3eff7fbfd94a89c7ebfdfefb7e4bf5f87dfeff7fbfd7ebfdf4fadc777f00eaece788d1d96969696965c95f11a979cdedec9d5abd7e8e42a292929c5487a0d5874bc0657ad5ea3866030180c0683c160d05518af3138e591ae3c1fc955e56b44d21dd22652d680592be3c5e2cadae504244a10394237824d542cbc12f642575fbc46a18bd7f8b3b2e57dbeb6f7b9cf897cefb3f2f63e9f8f8b4fe8beb4ed7d3e0741842f487575e37d57aedec7e373e273f5999d94dce76a99cf4c557b9f98162259633c94308e3473742989b0f18a7d209aa82092850a13343eb83066c6803979689df97c3e9fa73e57bae2e2959494945cad7a8d4aedd207dd0d5aa1fba0ab54af3128140a8542a1502814badae2350a7507fd3f2b5afef7b3a2f63f5759bcc6df8ad7e83b6af247ae265fe391ebeeee44ee4577d7ddeb1d0d45f17faeaa788d3f9f8f440a47f11add2845da1bb93af51a8d50943d94cf4341b96727a14339119417a152883d140fd41628af40760a3a946700ea070505e5500d10432307168b1949a4a0dc266bc860a559395902953ea170fbdfcf5d38c5ff5c957a8d3f6030c8f641778328d83ee8ea89d71804db414a9b569fbb30dee73096f739d0893e14caf799bdcf5513afd107258cbed05da114f485ae225fa3d04bbc462838b3e0844f4a324b7e92591b15349fe42a89d798e4bc1fd2f24343438e949d7c3ee4c5a1322aa2b4c80203cd8c190f399db860127921862cdeb0db0ff917951aeff3d5e7ea88d7e873a35ee390054f99bc055745bc460b5453cfb26bcfb2ec90b32c559367594f2be0010b42558a67d338645299c4b255679ecd6173169675151a645957a36c905563a1a27c6c4e3eeb59c926b1acd059f6c7b223c454ede87aa202c8593ca58d96175b2aa046d2672ad74c8185220c8796367116185bc8889182438b95a302a30c0f2e6610160b1417744a1a6a2b5896f5dfeff7fbfd7ebfdfeff7fbfd7e3f5743bcc69f10cb6fa8176a35194266449525c878c32f8ca2824d0a33625b421667706c4ae8d4a8110aafbc5068a479c3c48e66142c2ab150e82a88d728ec2d09035be203f335f97c3e1750dee7f3f99456dee7f3592ddf67a5f63e6fc08cf7b97a7c8dbe9e9a820466669c50d68101c266cd5682644aa8a13942c7e62686aa9a7b281fe13542f59c55583e5815e3832ec26b0cc249593ec96bf01a9398dea960bc3b0d5ea30f81f9219fc16b1c92418616c596a41be98bbf9bbe580440b1e82ef4ea8b0e03a1655f7497b2e28b4e9462f6452f2ebfe8501fa658f9a2a751d4bee831788d4528680fc3690fc330ecc5fc94468fc7238918762838092e027b05b253d161cf800f861d0438085781a11c8661380a948775e0340d7663d85568764a1f16c2b0bbb0c3f0541234d132618aa088772a3734c60799256a567e48c19ec26a330af385be66a7a2173a0c5ea3100a9817a455a0a0a0a0a0a0dc05af11cae7f3f97c3e9fcfe7f3f97c3e9fcf5bf01a7d3b6858709cc0214702ca5a0ab320576158c87529b2a94127a58d14311065c5e2d9178b3b44d028b3be82881913178b1ec26b2c32f9ddfbdfff3cddc12848fff35fd992fffd1c78e27f4faafcef0b4a0e2771ff73161457f01a61e10fb3e27ee82a788d431a58dfb666dfb6add0db96c6d9b73a2d95b66d836d6b43c8b73aed94d64705d5b63996dff65a29edcfdbb6d8ae7dfbd34af9ad1e73540bb7703b2777683142a64ec81a15713b25c4878e37487a7445d5681bd2648bcb494c47228d972d3366c0c53b7d6e90e34b045b1b243eb8e29dca8d8023cc0b3a316f8654a1c55b3d6ab5cd2894e41965d3479be24a16091a4eea66c45b85fb168683480f373deca9d6c3309c03eee12c200fbbc34e84bd083b08af116ea3b0d075478e1ecf7a0a8a9eee9e2f7aba836cc5a2c3c82f3af046db17dd7128f9a20d275f7414bcc62291851ea0c798b412636c881511c12a0a139a850b048a0c67baa4a0492365c49adf2f47f99f8db1ff71c045d693311d3bae90887f369cfff313bcc65fefa1a06ab03d548d120fe51fbc462820286fc6a201f73e777d34b8bccf4df01a7d411a591ff4fd1a83ae7039f7422fc16b1492e035b659b9010f2abf818fe0356ec054fb5e0fcaf77abd9ff77a3a5e7cefed3de9f5dc8362afb7b4fa5e52af0753b53d4f7b31a67c2fd82bebf9bcd7637baad6f17894eac17121e391852e7adc8a7b49cac47c5c997863126ff87b2a5c40b37a24e9e1a517c5aa8b738853889c8d5eafb7e6e60bd5962764607a1dc49082d222851b332c7a6c70233ddbe4416ca765a9990bd65d1d3b9e7578c5b30e7c31e5597765d5b34ed401e6592fc678d6a1606479d63ff848bf769c79d61bc083c8b32e82d7c8a6f59cc09041620518166b255ab850aae94a53f339d0e7e2f83e9f8e1beff310bc465f0700f8dd13dc4460bf919abef5f06d7b45e55b192bbe9501fd76c68a6f67a07d8ba5fc16cbcab7572abe7510bcc676a7c96fa814a85d499150c1a2465b08a858585561751d298226434cca8bdb94b61430d9c357c787ddd54f1ba8c275c4871b191a91188e41e661ffc06b848b4c305f740fbcc6a2fb63c6f89f77e035fe3c788dbd28d3989967720ebc46a61e2f5ebb906b2ffe20f11ad64cb40efa4edb400022e4753af65b55d509bed52b550da226e1b72af65b7dea56438fc7e308ed6a744b861af6ba1735e43b4f65e5315fbd8ed2b06bcf5d147ce7b00c2d82cc66d9edb567b82c979dd277df794e238bc4bdd6539a999d7cae5df7106a4fb56b67d3860e5bf25ba7bd761dcd4e43d7aedb2af8d66f1aeeb56b39aea9d71a4cfbaa5c977bbda1c515b76e7d695fa1d9c9826b5fcd8a7caf6a6bf4b5af6e74af7daf6fcedfec11999d8ca688be592a56f9dad9259231f68692df6cf3b5b3ceec74e4dad9b00bbed93216fadad9b42e1daf59b524bf59b8d7cecab5470cbedba816f9dadba417d7eb96caeb5badec84e4dadbad24df6d97f6f69984455bf6ba8dbef6d62db76f4abedbb8dd5189885d54d7ef9df2b5ef963b66764a7fc9f7ae87d66bdf3595b0e9f9bdeb42f27b077dedbbb4ec5474ed3b3526dfbbb69ddb6bdfc13979bcdec51df9ed225fbb9b7495d929fd0cbeddab25d34906e8b7db834bbbfbcc4e1a5cbb5bd6e4db3573d35ebb1b05a3f1da6d6bfe76e55e3bce1107999dd2dfe01b672af9da7194da71ae8c68c769662727d78ed3f5e41b270ce7f9da71a04bdae09815f98de3f6da71e0b213946bc789dbc037cedceb9c2392cae777ce5487df39cbd79ec3ccd1ca4ee973f09db3d57ced394e312eaf73c28868cf8966a70eae3da72dfbce797bede9ce817bed3972d929fd1a3b0bfece997bbdf59b977ced3ca57e7263edbc2507be79375ef398afd78e30b97a16119324d6587e3c71f1c4c613c50835484e6c51231317efd4998a318165c64710ace556bcd3a7049c309e9465c1eaaa11ef542e4b09dd191869d694d4c55b3d86e03924440d2051392bb19499724e45522b196f754d172a296098751d118bb7ea86810857dd0e125959667166e6b41cd549ad7c7d029af5850b982773f1d6cf1e713e44b8c10246ea2cde1a6a850556d890126ea09c88f77a8c3241fce8d21126cb4bbc57a40b204848346db0e1a122de6b338cd408233f54b06589f7ead614f1d6e6879a1821f15ee186b05822055d96692315ef55ee751af2e99c61f675424dbc59e6eb305ba4f8c86ac1c22bdeacd6eb1140c02812044513cb8c59bcd9e86baab52c3ed89a4c25f166dd5e60c6ca121a68d6643c8977ab7c9d62a173322584181a3121ba85be6ed35e47795302a66685ee48bc77c8b43164b6906f66bee2bd4bbef6401632ae8ec4173211f1de395f1f95c815311263c559bc774fa38d19586459456c8488f74e4e0139e0dcd810d1e68954bcdd23d00c4b6bc6992e5da0c4dbd5cac0d75b5813372ed88cc4db6d0a5db46d6933a7264b8a78bb6e43196e4e4ce9a145ea4abc5db8d746545421d364449b2cba4413354da28c399222de38ccd7eea52b2d880da6179278e3a4bdaea18c2239ee28a323de38d1d79eee9ce46bcf51befeb22c52c406599127f1ce79bed6f2724be243069c8a78e74055f022c4da1521483729f1e61d5f57f991b64cb3e2622ede3ca418dd73e02b07be81d7c881ebc1d7ecb4c17bf020b6e33db8065ea3870e1d3a7410d3f11d3c03afb18373f0bbf71c963c0777ab3c8730aae7e018788d1c600a1b6ce0eb06ee62f90d1cde60c98adfc02ff01a3700123d541ef21beaa1945e3190544dbd60c61b7e2819236a44db447cf9ea8a37f1a1be485c9d8181842bc59778171f0a4ac843b99b79a83740ea72405f64d9d126865a12f5506e81d708f5e46b76d2f04f4f49fec92bf01a9f602727073ab9eb0426e49d9c02afd1c97bbfc1d70dee62f90d5f237e834fe0356e8095bec9e9fc2697c06b6c723568d0a0c139e43578045ea386a1cfe044f1191c02af31031393af4c4c4c4a94cfe40f788d4cc062b1582c168bc562d11df01a8b4b4b4b4b4b497afc9237e0352e2929b9929292d794577206bc46259c5f90df50ff9312c5f1a20c9d9325f186ff17570309056ec696977813ff97f565849c15315b28e25dfcdf4feb7f5e64ff7b912cadbcb698412b13ffbcc4fee70b788dbfb1a4a74f4a72b80bcd2775757d922be035260191909090ba8c3c9227e03522953d0624591e8323e03562708dfe0212acbfe007788d175460c5ea4d08972336d8e20dffd111903f72573f3d8099462dcc2bec8d89f808498c3f7203bcc6232722ba569e78e4f8442fc06b24c246464646464e80d76854c485e38b7c00afb1c8b560c18205aeabb7e0c6d768c1899a5f4fe402788d4464bf7b5fc1d70a46ae7c052322be8207e03556180e87c3a1c7af71e8c29e17065f287457e8b0d081c222582ff47f8d42f7f97c3e9fcfe7f3f9fcc36bf4b97b787787cdde8928df1d00afd181624f610bc953f00e5e23057707ff80611172b0b9c84ad2a66d071c00234e1e62a8ae64f101c3f0d6d6c330ec1cbc46b8d7e477cf0f0db92b44cd0f393c84ca0f09b9fa21f7f01a878046bd1d3de2f77abd5e9034dfebf5bcc36bec394929fa4df4ed152d20df3adc3a50abcbb7ee418a7c0be4ec5be7f01a5b628e0f11486efca012c7867601e517a913cb325422a6b0b479a1e4058e303d9e7507e2e40260c49a64c160922644cc02097bd637788d6cba7b3fc127b8cbe527fc70f1131cea354e8077ef834dbf7b3ee86bd0dd361f74d8c7940f7ada83c607fde93506832fc4c3cd0bb9d36b14daf01af5502b4845d80779d36b0c722538508204091224b82b81c84b5021e2d90ccfba86d7c86aadb5f60caf513bd36b9400057422f5402fbe46a0dbf3403c1e08c889801c293b6907f2627e5293c7e3d1440ce4ae7eba3016a38d0dcad88a223190d85514555bda3144bce107f274cd03b995df3d5428fc467a9d6e0f7ff43b0d63c2248809db6b073e8fbc7627937aedc4b5d75e24a37bed1f9a4079ed4baf31732e89a8dd6e37429226488e146903b6034b541b1d65e2c2ea6890858de8d21983414fed4ab8b15560849588eeb400af72fca8d035c85b90940cdab64c388f1972c9edb49412358608312bb9dfed58966505e09616f644eac86979d67b30cbb2ac12e64e0990145d526f5582c0c2ccf0b44b637ace36112dc0e8e2b404b1f294b21e01b26ea802d5e2c3098d2e6efa44fa1c5bb201e6147ab792d9ea12c7e5a50412006ba245dc4819031df134b15bfa68134315617262291b5b56247182c3acac6a4bd79b2899b30672cde59a723552a88d1810146d685d44a07989f2454a0c8dd4d2081117cc88972e718382114c4b8385f1b1abb0eb00892252278c94110135031345c78c317328c6c4f83489319e226ac6a8626e34028999630e2c30423459630548143659dc803d9b3a7ac4ce09521fa52e92ac5d5999b5c7048bfa9daf3d1e753cea847e07e379c25dd500bc51ae3c56603deba0d11a6dacc072dcf8e203069c93301151376ac452bb3db8b0e182ae69f258c058f349133323744e44b869a0f088e80146b965583fa546122ca4a4c19955e530737c963043d7836b8919154bd494d021527775d354188c498cdf2d49a364076908ccc4550021e45816e8e2e00d61ea30ac0cb8134b37faacf7d82f375a0212ac3733b54316138bea4dc1bbdd6eecc8b62ccbb22ccbb26c0082a4a5edb06c58f30bef4d06126277a40b670a4fd8138c85d6eb9127bfd320c652a30ea8988e341649250cdcb66dcbb66ddbb66ddbb66dab7506c70d6fdd8dd560330484492f0028906b7ceca86159966559966559f5637675367d966559d6d825b9ae60da8825e9a2adc51a104ad694e18a37f0c53ccb86d5907b76832b6ebcb2bc89ee90d347b0b0b7ae67bde72cbb26e1dd6eb73b21978fd200481df351fadb857be0155ae076b7e2062cc6cd0a341c315c3ab045b44b0509ebee3c5d3bfb9daf606b56bfeb00a60d401b52cc8c6fdb2542d2be6d1d4e9da86c3cc5c9a54d163336c68e3441116fe03fcf9e6553341c4c2c38a6e0a2b66236d73dcbb253d8748eacd830f6e477675439b2b66ddb3626d3c4c17177ad83c979f9b60dfbb6cd6f5896655996655996650380958683e3ee96609d6159966559984db1e6ebcdb3decb4e3dcfbab32cbbaa10c0d613f8c91d988920f02e8cc80b1e988ab876a9bd1292b5e2c953471b1e4b5e90f520b214e2430b18b2471be683c78feeaa2e1f1173e796ec86383b27d6d5d4dd05204dc9b23842570846c5449a15778ead9df0c655656d859316565232373457d07858cd7d4561b1244a8ce0efb29bdfed763b4f83fe6e073645cdef76eebbddae98a30de3a51d805330115bdfc1a76021d2bcd004863448c0d34a1434d69ec6faa99daf03d258eb217ba52a597d6d5125cc9499e3d1040994ac315c722ad8a47d01a135d5458a18339f890bc534e98209b3231e380d63d9ebf57abd1e0c82eead3db6d7f676bd1d5c0bc7c2ad701a8ef8e96bfc1024e35cb223a859afc849a3544d6da6d1a6074437d1a47a2caa4091e8f7faebcaaeeddaa6b1696b9af6b422d00e58f55d3cae23a8394fb1404694894b5dd1630c84d224203209ea5456aac9649ab4c44cea25900376f1077dc454e6c9cfb0e9f399e8b3a64b8f7a958949491afc7e6210f491dc0c7cea124f950c07bfdc2a2797893e5ee0a23b7170eab1e7084765a093260d0181863de906a4cfd40955243a4eef53fd849374a16a720755932d544db249a89a4ca15b4d36e0480a565dcdd94de5bd87b569af7b5dd7757561f0a1e9f78af47b250aee5cd7757730dc0281acfb4a24fe4ee5762af7c1421bacf5690511da11d4ac9d1c7766aa561ad5f2001a3db61fe4a1462f5d838c20a449d975de60d5770a976300a791887abd5e0f6e4031f8bbf76b8fed655d8416e1b3229c9a330c1e86356bd743f7ddf37bddebeabaa93e721f12567dbb9ad5b50a3975f0fa2958883367d2a5538302c61a2e1e12b0105196fc2e46b178c1315a6bad596f59b66559b76533a4493f5a5fc9128a808eb3eb380f6920422c829ab59bd667e7a956f40514704ed35a6badb576801bc3fa88078d5e77964daf93962605d1ac2cdad1916dcf764040da9dd9c39f87653b97cabaa4c4c599a2779ee0e448c970ce440a68393c68ce3967f7e14cec59c1eb45790f35e0acf61bfe9db3de0b85058af1ea3c71fb0dffce520f9d9d32d7856120d09d482c16617da464650776d232c1c1be26ba58d450503a13875ebe1fd9eee14cf499fbf13ce77892a8787a98b4b13e163d3e63393a743e3f62d975330c671e9eb51fa0301f3140c025c0ef110194009606eba3a1211282be1e7ef8617569782248c8f9958f92424100b830d089458df370265a00139cd0010c0381ee7a68c684210e5cd742748882ce33e5e0a1e766a2f08c4bc13b6437c34038137f4eb890c3007c0fa7493a67c2e106dad5b0066ad7445dd440581f01810d2b403dfc3e0fa7493a7015889e72ce3913279421b2e094a6a9a7fae78585a20dae0bc340a03b71c3c50d7f1ec2286afaf6e110b0514fe7997248af181559202aaa30147a1185a2a1a2a2a2094545c1a2a29fa2b6c8a787a7e8e783778a74de5e91bb2b62d7a222384dca5ef4a69fbe70ca6147ab4213de8514753c6dc1382e4720c880b49ec3274c9cf0d80e940e2854f1d0c3026a076d03d01571c98791d2150b4c668886498a7ce886495543be161374de0479b404f9bc49e889020e6d010da57c8e56f45808c33384d5b3c0c67362736673f63565f33afc917275d076404b5cc70c3b016efd51e60cad549f889c73ce41a12009abeac346228e44da88e8f143508b82b66b9a24a4fed0c5c92a4f9a601a3875e2a743b644b2e7b61be09cd5f4c9b785ad8ff366a60e5df643c8cf4462ea47241c3e8f675dfad180a367fa9da6ece77cce0b21407f76a10164111e6ebffd229350fe0a7955d35667ee43c80f6604f343c89fdde71d804e1a060cdbf3803aabe9ba7efe74b8553096863d3f84fca903539e04ade998c47e88c8700a4ebf56c0fe072974481d4ab5d00ad8ff80f83d6ff4453f24fa2151050b4226f688c9c2f330e4e0e0b8bb1603bbae2b069d5535f5e9a45f7f064e5d8d527e0859e7d321529a24a4a649a9e3fcd1bb69ab93665f149c3a2f1d9a1014220a92506108ef08dddd51b0a0a645455fe1f37027e0759e6952ea597dd5784744e02f78af4c34e024f07627d0b08006ef151e83b7fb2931e590eed8345d739aa669aa0a75760d542dde0a42703f6bbdeabca32d78af9fae60f721b82f3400fda9a7df4b935402e87c3a4c9996f0fb803416b1c3e60aac319b612f78bb7ac212deabc780b3eba7ac44de488576c0bbf7e99a8faf87454d78bb6beee95ddd9be3e7212c066f976d75dbb66d4e853abb069f3f6b8df152a29d86b8525515849bbad3b29c6655d5a990d6d981fa49fd01773c1e4120bdea02c84e29d831ee5555856ea25777703ed2af2dcb0711f5dbc3abcf9cc2d969bb3dd9299379d5d3347502ac9fbaa9abcecb6a4eb54ed69fbfd828ad17342f2b69dc4e30e7e0750a07c58e6d06fc2ecdc4a1d1f1244b1bb12f234d286225945a7859b07bdcb941e6688177492c3c20b0fb64bfe01d9427840796239713ed1909c153924273aec0bd23cf2dd95ac1384b160d76b55a1a30dbdc4181719cbc143970f03ac56bc2ac560e91b629a45d71a35dc2f3e1727173b45fad989d1a1b6dd1ecbe7867ed16db65f782cc140d26bc35f837640bec3edb27bc83ee7c20e179e9f1c049837e487db7fb142cc40d5d22aab638bf817ad5adbb735d015ca199c3d98a3bb6492697ee9538ad1c2f714d1cb438674e142c0366cbc0eb148e17cc5bb66330abe506f7a02c579aa8581a381c37f07b746bc0bce56e06bcf3e9d799e82e0ae3686d81833efd52e3a402bf4ce070e4d4c8f1cc60f698e306bb48d60abc4bb24de09d928705b7cb9c30308e561b8ce3c45902c39f7ead814e59137502bb47164e0e996305ef92386c67b4784560f7c96a8177d09c1e304e340abbc9c1b94a609cdf2914678d4d12bae2401b5001b010567e17a3cef78be96caa51964daddc45eb496c169dda99c6c2a565b8828dd0deb4379aba30d0592dd03689bb03536a31ddb634b7349c2a3d3964d2dad2da7857de7a62afb2d55adf324c1d32de0e9717b95491f098271b5d7d67cfdf1b94478a330dda33e63365fd410304556a318169e49272bf5da58433702d12eeb7ab0cda426c169d504f212c4d285113c9d9f40cc639d3a09ebc096a9a5062f139c4844299968779dbbd0aa3503757395412958bfe769515c4683d7944bd0c57b076a3357dec21b56b7fd37816d8964dad22334c2751d3684913bae623d57bcb1e66508ba889e47cfd7ced3c622fc3156c1406a753401c3ff59e323bedb7ed552db757fd6dcb4efb4d7bd5557fd3de68764a5f1d2a59a57e72d9e50b5774c14b89760bf7da79eb1258f5755d57e0042eb8fded9faa81b79af6ac328d4dba6992500474ccba8ed9210d4488537d945bb89cf395871a309b7c557d13a5b5d63ae79c8112de5d35cbb22dcbb62cbbaeebaaaaaaaa9fd4f448e3689f561d8ba77eba02dd6502144af8547dadb5ce39e7246ecedecb5955553547f152a2bdb3fc9ca6411e6ac0adab9e1dc0c6ad1a076521d6d9380e5ad787d324364de2e006de39ca67cae1e7b3e728530ebccf9e73959d76603efb8e32e590a671eb1f726e27a0aa3b4bab9dacd39c8729f0d377554f63367bd9efde6b1556d1b4fdee3d3cc2aaea1dbcccc4cb2907bc3509bc9375d669d2ab5f02a80318aa6992f6d55756b35aab2f0178decd443dd4aaeae6ea35abebaaa67aeb359c72507d5d5d4de28ab7c326b556573d421af5f09a874336b9aa6a9d1210552802acb76fbcc690310b5c85421158d71848e215adcada325e856b0c2471fa0e20bb97ee192d7d827813a5afdd1aa573d3168b005437953e63c422a85c47626b98f1841c4643e0bdf27af0921eebac1078d403867dc6a22ff7ea3004fd3b3da5216022a01f827e2103e4573dbf6ae54ccce3d7f3253d614a5a3d48602ea05e4f1209236067502fc8e560462c267060851baca070d32a8b3a20ca7815ea6889532649b8b08857a1509a98a77bac306d23030a8d5761d044cc6359372c5a6ef12ae449897943bd543fd14025c1a54c9b5804b58e8e274a945884972d5e8769dee0fa2a74c7c0ebf15921538a28ce7825807e9ef752fd24a47a06cb4236634dc24cce4d48bd50225651ac1ddfba0a3d4f42d4e30ac23bcb9feaa715563bac421ab42082b800738c87594db5ba5405ec18f38a7a124818f5dc09f71c8173dcf0544f895a1076cfab5a6badaa7a755615b2ac5015b240fd23329889fcd4b7e7ad9d7b7c76f513513eca9eb31b9180fdf3d0cd4435af3a7280ae0417af6971eab07eea39b5cee46ef0aa6ff8f3d7ab47e991dacbc42c44d1130a65efb91aeb0885b2bfbec65a28948703d0ef389edfd54f44e2d71322f157adf55047e87a00abef729c15babe7e407cd7b31686a0df0012cabc6cbdebea074409655e86bceb2265628ed07d9efb2e71cb77eefac89acf45a23e521d47089526a9ee5c60ffed12d323d55de2b3c37548e47dfa648c057113797967e4c818f8532855a04483b8e0edafbebdea4ee421ebac737677c3da37d06587eb30859245c56fd720786a9a6637b3cf699f55a803729cea231032514de5d4344d7df50f5aa83269c1d933f42873815070ee4c83be5b848a12b332ed5737eac2b00b7461778144d8d57a46a15c66ea7c37faaebbabcc7797eebaaa50efbefb1b8eefbe5aafba3a22edf02ad325d5d3d7ea55df6a894f533458217260c9525596234e63b810e164c5159522b1baec81b65655e6c493144554340bc60d272fd21f41cc34b172e343199bc18212b704e3034abcd53431690e93e62e29984f3d4da3508015318324da166fff1e1d998be7110dd588382d3ec0459421534a365130e202e8a7a2d75a17241b0cbaa9380da19ea874275b6ca379986256290867040008000318003028180c85591625415072fc1480165aae5a5e589749e47918c330630c00061803000000001802223445350177dcf17c5bd743951ad4b1bdff03051a70ccb0a6308c2d9027f822fb8f7cba32d409d5e4767d4a7dcfe0593c62fd4e903f5514c334ca63a67095d62333a5b1dece423db8274569142c81be022c432ad914ab934fb8264c4481e0c357530bd5f7ea03e64bcdfb97f1339089ff5b4cca43d622985e288dd1d2baeec65b03bc4ccd336f488123d7c1f3245f2ac4e01856003580fa16f27f0309ba1bfa127f73f8bf3503f8b81877069a0b2a1607d93f9731eeff24fba0a8e077a69a92cf54f4ca7cec117839b525330b457909973625d21b145585994c51bbaf496e4948a4527ecb52286ff6c50d172735c4890e32dacd468bc91bc6f53b86708120c963efc48fa0d72ececd0392376e9bfa9f1fceb3fc4aea3f53711671caa89d6ef86bca12776ed48cb43f6539e62e8fbe6f8c4ae19ecc408ec50a5217a35ad941c58f4d8c3e34378f5843e51789b414da345e67619526ab3f1a35577232d37e31f9019739aed261ca68e22ae72c079f556e3d8844e90b715d99b825914de5a4012d774d7e85f05efe16d7a5a09528b047a4c12d5b4c2b0d0265687a9029ebbe2b748415f60c2ec09a07eb341dee168175fd14d715a8c5d6263e7772aaad39875a4d58de7f20bb8cff99adfa939885f5c83ea23ef372dc639dd2b6e46f3428cfb2fef79134adab3d6d2c198fd32cbc54bd3870170f85eb5b252dceecd09819f42c159c6d58669db1d15925ee20622f04b204e5939dfe832455ea8c820dfff4a8c4259bd59a239ed8b49dd7dc84acd4a98b12b635342d71e445b7f4d7c19664ce63eb4c25712feace4d8eb5be0c147229badb11a12a7151f0318978607db308d70adc409e8f2adbdb2c6e2f48689fc77b1dee80a58f1be997ad30969161fa588a9890ee84e46ae1b8928ed67da8ad55ca356b2df35671e6581069f2107aa7aa9a49ecf233b1e1291bd1d0a52b91a38bdd3c08aee2ed6ce3dcaa45fc9385b877497e689ac95b4d145217f4888d41a9c617995b1a3ace0952ea9702c6160d25be345742bf48c422e7622e2fc09db595ba88b900979db93666b6f57f98a9c73a36d459ee15409431540630c8c6f908639ac7ac872667918b09aa3fb7c58c8f0ca429c64250a516a93e05dc62101a930d477d9d725a18f03e23390fc61a8c04f78d92ff3952ff9dbea9771d0e89644edb582195a11d397e132a44103556d0b33065edcbe121733994cfc9b18a02b6429d0ac409a167d9c283bd5669ac0f2d051d7c3dfe2c31ebd3d7d616380834bdb95c0266a8ae9fe6946cd7d34f09d2a122ca594402674d3f7522705a4657747dfb8f611bd4ad48397056165ca80337aee88c6f339172c71ebc6ca575e02df707dd8d4f1c4c035a8029a69aee16b1c7ed9351c622ccea69de4c104f8f635fffb6d6dd08111b4340d846ac6a844faaf1d6e48720098079718863752afa9cde96b90e0b2bf122e5b1724b95c1fca32e665339858522bcbc51e0564441412444447b9e29b972c7f7617952188a5e61d519d3aee6d0fc37dc2ccfd063071353faa85b613890a5db57018ecdc47463ab7fff6de20436911d85f8f8f18e1c290d9857bf890193219980c653a23188851e74e516a0a652a2496b256e2a9cb6bc0b32924c6ad18c78a0a1b91993584ca07d2b7a63ec5725e3a52a7c6f48ed3a4ec3d527e8df30811b583efbae85c4e116cff51d36f8c8126407613a06bffb4ab271236ce0ad3440c93c7afba8a65834704bf2c33a9c407d5e624739332e3ead2c1890312f691805a748febd9edcb39e88eced610202484f4e6c2b80f4ff77649f7d0526a5fbc65d8dc4ccdad7c708d9f5d6094b290f97d6451c4ceabe1fa6e8945baab22ea6383fcdd88e9b81c5a40a59da89d2b5ddd3a0e48668a77be93bff31a2c6912b82c5fd24aead749d183ca348bc4bf7b833edc8f9372881eacaadcda5b56b3ebbf199ecb04185b605462f092bb065b5f42c0a7b3f80dfdafec377d66f6d720cc0224c01f4f7873403b408401b41028d749b61fd7d60f06124329f77d521d8046cc6acaa698289386699298afb82547417d6a0aa2f0cbd28900dd73da97438136078c8fa65df8515ec1ca5ef06108eaab8a92c8857f80395ffdd71a1f34db6b163dfbfcfa21d7e9f7ae8618aeefae6d5833f728a6a63a1fe381dfadaf9902f819d8d6a1fbf49e11c9faea8a6597242bf7a920997ecd97470cd19e12d3a11aca7179056e2d1b5005b339653e13774cad65a083548f2da36c02e352c53a9ecb77917946d1ce8a0278596fd576079510de65efc9f37d2e7c2375a9e42527a45d5bf49d3eb79b9b34373e9f693c5aac7f2e72cc2de4e5f4d7bc123f29634d3b505c5594407481c880acfee7cfcd4e5926ada233da797030873f18d6bb02516a34b96a73be8e9267045084a096121b4d6e67e4ab0d1ff0138c92ec33851e36e3a4baee473bfb98ed3c5c34ad474b0dad543546a7fd119a921054fd0818425dd62e216c478479949aabf09d0229f00ced55bfa4fddda5b6cf1943f33010c30cc658a726e1eb15ad1fcdaec59fb932c5b3b2d1c5c350d03e09d7442e36fc88f1a59faceba0fcc0a916f48ca4cff97a317177a71d493d3e3a4d7627a327a5ab7999b90f53aa6d731bd1c5d8c9ed66de676b9c1582f667a4dd693d15bf4a840bd54e1d0ce423ffcfef3bd0e81cc92f10fadff3f98c86af1ba7f9438dc596d9d881f853988963847539011502b4c7298ba2286913e8e40682bda2ab4cf4252f5ed8931843dd71bcfae3c260e934692f343520251d94eb7bca0ddc7133cd72f6e6417209f45d7787e030c98bc5f2852af834a634b43e02e83a21d69e2ce467f8f0becd5a1ac302b87e4dbfb8a3cdefba1629980b5f6e744aab68ae6a6b751ea2bdb91a06584528ff2a4172ec2aa4b34d5d226d8f67ebd6f4bf5aa86c0c016ef435d431130df076622dc3c267482fbb1f76cbdbd8c15ef0bffcd7b327d7e41fee7ba62f4fff1ee4ff9589a1ddb7cf56138fbf422654fc09b7aab7e95f6fad34099f3014c73c1ceef5090e78f990d1cc7e5cde4e652b36105c60356b3b8ff09e804e6599bc1855bced6839b830653448c39d4a88e36defde487a837833f973e6133e9d3f8c709b72050a4e32c91bcff7ed4fbbfbc5dd8e91502d55186a6ef6d04619160e9b2092ed81bdccf91cbe376c030284ad22cf2adbfa671c88a4eb1bcac379edf4b0cf93b6a824268b94f21e82cfe768bae2a629ab00d7fe7ebd13382be0a1908f6148cacf6a0eb85f42a0574769b91308fbd084e15ed33106ed59eaf875d4fb0633ef3f046c09e88b3c2f58479d7d6662e29a64096f92d0d49dc4770b0be83ab0f4781c78d3391fa54a5149fd6639836f302b433117158e0076ef8b3e1246051db7bdb0238d39b29032b62dbd2e45885bc389a11e151f1b4b18d13d8cebbe061e610176b20b6f91051b7bec15072991db9801f2dfb9699b2b0c608f0f7ae8bc7891d5ccc88d7e85688edc9a6b348042054e9b6f6a45ea51ef772ab071f8e420438fdca9afbf16811ac6fc4be1f3216ddd79078fbc52a362808630ab1515c1bf6b3c3f6e69b8d04a88f30981e43613bf0e7062079eef9a17ac9ff2eccc41080a20c448ff15e055127cb47c6e34e6192acdec2221aa04f930142cdbafc91bd7fe2266ad8b005cd92b9fed089de0d44df92fd9f349affccd1f2f3d3b6315c6910928451a3fd45eef68ace41044e4d5b2e58ee144511a2653eb3094acfdad2a4a63692661e918f5e770d0bddb47003c2db445e4574b12ed763164061b75592ff9dc3a4a71eaef149eb7cc81f56823bd5a18c0c207571f0875478b5fa8810a4238ea2958880b40192f4dfdcff7b5458bfcc620c79ab823dd2bcce6e027d6b67f357ef1ed9892aa5591002939696d595c891b2f01dab3115b92ec63d9c3100057c2a497557a29e2971890283406ccb41e52f71e375d53840e5d2904798bfe69a6043be473c94cbfc4021acdcbc49bf652f60c8e53893ddeca9da77082485f7387ffa464373d3682b56451697b1c1f0f6d9152d5973b834a27673ac4599254ed1b67685347e90bff1a1db1bddee69406eaa021306ae8388fc8c6fc5c0d444564ca0b45566c4b961dc690aa23a47403dd4c8e43f5241a624560d87406b27deb44d3697da14d33ba4b46d066ccf1cb53640488d238623c081b481c8ec246ab57d4c580ca17871501d82402890c3c113d885e188b3a87a500d34364fa4635b8a0ec900999e0e844c97a57bf86fad132b55b71082451366fc20711132ac24cbd7465cbbbb4727213a520fdaa75b2adf0258242e2cab1414992892d8ea8251195542ebb1d4fb038c44f9068f6512eddc1df88b6572e86d61c400a0ecabfe65f624127bb8b0b210006373d6b3225a5c80871ebfa4bc93481b04dc42c627cd724ad69a48fd6f744d494a53a9fc8dbe294849e304bf1dce212b9aa5f657f4a62145f3d4fe88ceb4a44d034ffc629c53ac3543c5dfe94d899466a9fd011d9ab68e1e1e57c21ac79cf476b5b802ab2a9410e46645158bfb1d2c75f5100d101e33475e78c7d3cd118eb1da24f77fe63f2dd69be1f2effcf73416c4253e46e299547c60a6c2e4ed579899ca8a7fbeb4836deb4c533c2675db96effb035bb01f7403c2486ae8dabe3d29d8e3f7794c62146434df6b7437ee77380197d2bd80dae3c192b5f39ff2ca6ddd9836ed03dfd20357384012dc9df5f74df9f6305ed7bad6038023210b5b9f6e712b12402596e30ded09fb872321df858e85f5fbd3f64531c1bac018a302cde70dc5a2034677b024e951e8f673215f705b672a2146f8dba0e490657f72617356389ec33a04eb22b3224b2208dab3bef06ea0ac025f15ecc6fde943a59d8ade6eae3d48a5109720abb9558f0b5b7c6400901e5459e0f41c30d996e05dbf7588b5eda277732d2e365cc18b833c866192da5e73eb0bc193548ff3b87dc4ee0f4f0b14f4010dbdbd1ad8a2fb1c4ae27aa70d2fc8868802b42bbe508dd800a5f90428188dc215d93b704f0302761328207900be35d47f4f194a0d0c42c236585d290636f922e002bd74278660ebe34f2d88a2ef836c7232981d839280033ff0ca6101269e29a0823c0a88ae2a41d9a12b9b0b092cd5f7831afb61eeecf83dc2a2c698400f7f8311a6361d64051155fc014e3dfa6606c2a3882a79c9901b77570a88545c0aa31bc9fa72ee3aff963ba8d4c505d077bd7e67e9b2830ed2fa3b45b706a678192d7e1811c4e923b4ef6992f48b2d33936c081cd3fb5a11543681dd22d45e92fa88f187b61653328ff938f3104e6f999709d9979cc2061aded002086ec38776aabab7df09022864222f09e734da21d387893d6e3c5960edc4405007a22a8e03634584d06cf8d66d219b91a595d40557f26fad2aa6ab6a2653d3c535acc3d86921481316025713b9d793602b0437ba0fd1fad7b9631a46535c182afb7f6932b2850385ee17210bf545d55bba7f0b1d0b4ed75a30f47e28efd29d428d8894eb5f3b499db20f2afe8a2a2259599dc4a79d721ac2891ba68cb4b78477e3970fcfcbe7e072c04b55c18e811162a0cbc10b94824e68b81c3c74afb99d194f559890a5273230cc54a1d86d2693951fe741f6376b7e72a1dd4ccb7055701f072ca1749a2d4474bfd316c2be8ee5c9de48d3a9f2e4b7c9d366f0c0a92b297860cc2179015a1a029946032f2a588d12236079248972106b953d9a556e7aee9d2711b445fecf26e41c225b4e0e936b890facc9666170d04d7666f3214c0b8b32280d6599539251e7dff2546126774d12623795411d820265b407c095a5e7670238aec60e2615b1117635655d8532288d32501ee5a20c4aa30c9447b92883d22803655d0ef49b275ae55c83ff495111a930115917a024f38e249c852635eb6594003e485c6bee8a9b482f71ad791e234d66289f3314c3fe20c3c66ca14049912ccb9602c0936b0d41d9b41634381aa78fa94ddc844676139bc4a33f0be0180e52df5d4ad62e345ce2a90a99c68e5823114d0b50fb19686b2bad9966ea247c03059abe176dd56c9e4280c6eea38ea0f5eda92bd50ecc5c285cff723e3376b66d6dd83468dd9055d0dc80a5323c88bbdd4f6cdf03246d140fcaba2e449b7dd4c55eacab7b8048bb38e009bb3800509b3416d1497b91782245764f94444d0926418dce0d01aad036e855cc6efbc928f12a7edd6b728f7411428d9a7de7d3a1434964005a4f7653f0c00d32704b4a109c7c44b8134e55732741970dbcf6b316ab54b209f7590d1304f6db34f7a102095135af174a2f9c2210cb41576748b881d2f41249820149cd2525f21fe99b0149e20449147bc2f83f1a6351789d4d4cf275e838ce353efa9c680922044a617420702ba443b48ae5189b78696d1e0f3edf86a851e81959a7891f63d2b2778c68cde55632b66ff8c6792e6ba96c0c01dd827ae56c40d32ecee6362aceb8226d03352a73d086c11840237b54b0a05ca88d34a32a7b091e19c7f4b6f46204cb1ccca803fb9b8bab26a9bd0b0193a8000c9215c3279204948abd832105810e65d820e3886c4a28c94610bff0a6c27dce41fcf1a7941454a19d545c42e4a8ede1049f5da1bc4f60d0e08af13bb9ca55c1ceaf10981d6195631809450c2ca322b9d1649431dde5c51f50b7113e2a1ac26009f1034ff086b0f0fcf9e3b50767578023381c70ba861fc7262f53c45f301bef2436060969cc8ff577348079cb3896501595cb19f1473eae97f0f67e8f0876640ef7a24944bc37f1b21537f3ef86964ab51ac2bc56aa30540670ca97bc7b13850e95ee431485d04c568ed3687ad938b5cbf74bf0d1361c51fab353d5e006632e94186ee1238a0f2a58f27c6563c0e276029551fee13e7e61d75a42f61dae5ed52474275940d9078049ee634e45333cb0fd9f1f3ba04ef54906f377acbf80f530b92e97804483de6f37da13a881b67440c3118235c0a478bacc1d9a476e063e43073511af04cf1101dd7fd37fd4e55045e2e828bee4a8c99674c90948c611eec87543d70548e8908468b9f2064e7ce8f01109b9b191c10ad365710fca43ede1f4faa5a22e1f55ec219bb81e8b7cfa8a234f8da3f5358debd7bcf77c3cc7c920c47ed6656f47e3a8bf1a27436e00294169fc6ed427c58bd69ca7dc7bf3a781418ca075cd7db33ad51c135f45a9106bf5b2f62e88947c410aaf9a028d49bb8c9b7415342c1799c57f788c3a463e97df0d89f29abd0918b4a092b73c3f5d88372bcf126068c0092144951b9b86469e38c79429b42501ec29b52b9f5ac55c730405ea972e14b25afd0cd6d1035795c426b5f83bed80f6db52fc11b1aa049ba3613991f9a7fa6cef227759c52cda5a38c95a0cb20cee766c3d6287d4f4fecbc5f92c89b625957a45d686cc42d2833694935cfc0b782b913cbed174f9ed9be4d9e532fc0531581fbe74e23db11aedf77642abaec68530192a0033f2b154b647d0786164ddcca4a77dd4c47c005e3613ccb0a398ba725e37f035e889d249e2e8f1f6a0f15d3af66e6a52530c7340210d7e0ecbd0e88742b47464e038c15d1e1c57ca5752afed88d3c218cd85875d5e58821c455071284eb472f801385a489edc2fa811a1844b500204f6f04a519cb6e507e4631a9cee7ad4ec56884bc42798b98a11e52c74ec3bb8b6a3348ebb6143f49613133cdfb6213bdd96102c25e8352c4eb6e06149a99c5df11d52509decbf6e05944ec5cbea5819d97b75dd462167057c3e900b376c347dee637ecc6a003e9c059b727006f8e61ae62083d48ed3adb154c170817e8dbc52ed1e66ad109b95c1cb5d3b653445191ce20b330d44ca05d259a5a79626db6720f1d40d5a71520f274095381819441c59fd359bd9949b90cf60cd7364a77d58dbb0120fd08c86788174e0702b1d6a9737d343a1ec8ffa4380051bc0c55abe90e48564f32e31f09a4d83f8b622b75b8f48b10c7c710aa023a4d5b87583b186c571c26e7abfdb1030a973d0e285e23e656bd3cbfdc08a627bce527940db9e70c7c08c58431c1b91e008bff1a451c974aec77fa2a19c29ddcf7530e8dbc121755eee11079e9b56c54281bec884ebeab6d651431d37056f9c44248626c07b26bb4b910431f3201374a9a03ca33167fbc1c0282b87b1b96954d408437daf18eab9ddd9d294801dfb815b92381d9aaf765fb998cf75447cf858efe7eaee4375a2b321bda91854e2bc35992573b186c0156f6c375787786c20f346c8cbf8998d2f57e810cd15b492ee6f2fc3f04a8e055eeea40287dbb43c220543253b95199b6b3cf061f94d24e8cfc21244a1605e0857d109efe9bd610dcd499c49200c7fbac96915ed9f5c8155dfc51e64d8f9c23e11ff16ee963f7f530ab309b7d4f6a5b9a825d86a3528ccafd21fdc72ff8aa2a90e402cddd41602505b60bdee89d7e4eaf52174c8ac0227ae8e16caca5d0b4818bc48c1e41fdedb7ca539c483d507cea0e5618bf2bd0d88211227cbe5f269c82575d9ab8b5c807c14811bbd3f7f252d1103e95583c2876271adf0735ca8c031edad056056d2e13635d9ff85a5ccdedcff8f67a00448ea95371cdd9702296431d8f0c660c1088e96a09e6e15767730ff184c1505ac6e391754792af0c10818c8a73cd419b66da285bbd265f8f55d945056ce2b32e2dfe726c9ba471a62637e12ce55317c183390c74d57deea7f94c9d14162c5d9ee6357750de9cd2864a8c3180eba461babd3751e9a7e6fec4226bd6197522a25bf4b6b9e45f8c9853abd8dd4d56e449f38ee12a45b48e15fc17da9bf77b832d8f30d8468c249f6e95984a99988c92de139271a202c3c53a2cc38a45bced1e7377489ff0844f647e096b2eaeec41c336b7ab4b50f9601fe11a43f4f6b4e7d7549c7886ab269b3493cd0fc44e1adc458117e02d7896157f69f23bda7442511a204790eb23b0a37cf06871f04f8891aacf0a3327239655a20950458d541ace8f1015ba15efa9d95172eddf3d576417d10b7de75889402193b311d720436b30bf73a243d824b5b0c2fac95d1048eb833b77f97dfca3ad4286a5a9a10bd0f6b867dccb87d2d0172da6aaf4fb8b7b4db97c5889d3fda8bdabefaba1ff765588def33a07952e89969bf8e4744c5c090feaa167be86c3f0528cc6d643d80cd4831ad0d1515e3d72bb8c42ffd05910788f32ebb206aca16c47ec73c27a6683bf65910427c20cca211975f2d9d0f6e45dbda9c74654b4cbc54d37693d44b6ef3f4b4c7a161a17ac0ba8bd33d136b483cc1a17169d337772ac41d9a435bc0bc02fa0544b4e3c1232a7fe7c7f21e56065592820aebb6b6461ec50856346533e3a0328a0721933ec52447ccf9ef85d4fc6ed719d058d9612fe87c67330fec30aac5a37d1dbb0bde4df5d44121db69030ac3ec9c89520964eaf4a746d69b225cbd6a719ca20c8aa84b905949b26a25f521e23b6f0f84aaecfe2a783971b4f858613c458629933a5fe66a2274ee742d4e715123533cadb83881cdc8ad6bc40ca72ac9e52787ebc9bc7909746001f80ad085e0c65e4daf2b76f207fea6a32c88b7d53ec8e0a99e42d1e84a630fbf5d7de5d9db198b4147bb569eef363872d0bb10aa6e82334293d83b6bde51f1c8e5d91382f28623ac5d7eb91dc484b4e9fd4956324f7f3d6bffe166188126b20b43d4f9806b312ef7f6a96555be4d8ff4495033306e3ce9082b9262acc4c131eb505ce6819704f564633a21a4d7d42a3569b6f0aa7ca0aced32e9d02e97630d987f47314611e3be2260749c8a9f8d8fb1b8155ac2993e928bf72b68cd18fac157cc4b31a2ef25b8b1afb2ba9daaa3f8a6b8b01112e2cd822827fde0ea27611b39ae7d9ddd2983a955bca7e88ebbf049bb8296c3188d9474eec33c9b1505265994e0e5bce6af02474f4cb8d2383b23d39fc87c74ea70ceabdb6d4c3d89c089856e093bf7706fc5fa5a1ce049409d1179866c155acfc12b12a1f41c6e99565a0ef8e709c664acceede5b06b214641103cc0044272620e6c5123f67fdf9e5608c26dafed1267a0a9d55023ea2f6d1c2fc35db80e4b1c8275949a2ac9226ef3c6d99bcfe9ae4df0d2cdb3c663e28a2e58fea753e1b4164556ea6f599a5e08b90b000b7f64a96defa1d78cefe28a18d6f23462d99bc413f5a4914c2bcad00329a3308d84b1c281220b608e57ea8e098d775feb60a3e221b15cf2866f40424b914715d9ddba87e205b0061411fcec3cf92d4dab2311b7638d0af2c49840c64a1da0bc332e7368f6cb0fcdec225cf7c7cf9b6c9c84580ac0a37eafd90c7163859eb6432102c527149799ac441681d27053f4c3a6a37bb16376720a5bdf862a91a79db2160d24c089aa751a76d30870a086a22c44a3a0c639184250aac11d0ef1c9bf6d34fc340419f7521f2a00a0416d88166ce1a86d40ac08d0b117e17b037e8f7de39bb47f6d0a527be6c67a4ec55ac7218725b0a3e874fc29d3c9fec0405ba2284469ab325da9cb1c9d8325e9399c0fcd2affd336638e081b580f7f8aba94e5a038391199d9ec9380df3c73b7f85f3e87a270ac5b39b60bd77c8597f5bd4c393e4826c9e0f5fe2fc07bb0c340147729e16ce4b9862de4454d1f6e811ae3010c41f97b866e4f5eb5f56af9e831802da89ecfb14d7e7437e1305ebfa9095f18a593fd9dc0c246b4a176cdfe452b9000734d7766f10ae766c41c3350a260248e8137a42bd85604c18f86c155fbfc0b5e1340b659663e30c040e978ba7c0101174449610f7cf527078005d0d5831ac22df4cc0ebc65357f15d132701476fb8771145d303fed3acc1a9e1f5f69c4add531fc37d5eea9aa7bc1730bb42b3570942abee35e995f603a81f80d3b92d541fca58d81d1d705b9022b2d0b16ce3f9b70f813a9724ce163ce6b2ae3cf217a2bfa78e755ab66feaa90bb0f2da802acf5d97ab78f3bb0d4ef5e2b72328cb4e948c82b483049a501edff4580ae5ec3a620b7c2a1b4ae8ec7086284928397bbd10c506d8535063fd619b0ec3407bd8b97c9ae0e7d41121457ba8bdfe240d050d687182b3d909c59264df630aa6a53d277c2087935cb97db49d23753c3807ae277f75be59d8f743a7f53a7ce56b0886ac656b082747ff038060411cc6cb57922124fde4e348b692db5ec136346b720c048bb309e4694e886336575382f3a02aaa2cfc3ba889f7e61920f98c0a205882a5659a081a1f743ca7a52a72e1a54b951b0e0f585190912506661f7850c7d60a317be921978e2465f63b8ab06d768ad0aa641960639aa873b112b7d439543b97b41acfb7d13f59f6f90d1645f0b3a1a68b2cce23e374403bfe1f33d1db705561d9a478c1800a41f9aa8ba3386670c3c01aa05560573a6d0c81d1c666a88c0f265c6830daacc930685548c48012db7b92816cfc7439a6a9822280998465778195738c29ad55b6c4fe05a8c9870e206d1739790dbc06b1dd4f1032a9224e295ced223710638a72572f78fa4f7e80a2f436a11b5b7d3b54fd0784fd77098e418e217f244a247634e0c1dda61df72be28c607c2a82b2f0fd2d4c414562f1d3475f089f993aefb0accc919bc6426a77b0ed7c3a01da5aafdb8bc3b0489848eef561572af6cddb232204ceae747c8a7853af688f1b8d0f6fef12623cd82697b442e242982e10cc22add3e55963677dd602589849203b817b9ccffe5440aef1b270552c7cfd2722a7896687cf21325dcd5f43b0e54f1f801d3ae24830224227ae94e2fe1885fa79781bf5799cdeecaf05a53db5022fbb5a6649f24049b0f6fe868bd3a75e7aef1bc721b76e8d5e39dc376481574e2e858b901c729269f829ad16834e02dd084eeee493490216b079373d3d426814a84d57382633231b51e29c7100faca480585ff329b7462a2eb96fce3212e19a478edd276094dac166cfc3ef98cf43dc753234e351b1ee243cae74163085c1271c88f3767d192c6e76604b3578541fd13331aed8c838cc51556df3e61e657754f37f508f1ee95b3d9bdbe205032d82a2bd075278f97ec53cbacdf4abab8049ed3c127324144cc2b1c1eb3cbea1513d7094bcfa4f9ece013d1bc4d4146c326d345c42818f5591fc328e8ded33b88be68f5f225165617f454f91ec0a492bba4610f61cbbd3748a21463484e75a352d9270daf706b43ad225ed68b4d4f7aa5cdad083490e095451a224985cd5b9c063350ef89c3ee0d45ef7301e091033e65452842c101b9cfa8c29d9bb33d63b58f6c408d46cc9ee62bbf635bba2c2caa27be976b38ce9afa1e4d8a627db7cfb3847c16d786f212a8420a2144745eeac357d244abb65d32169da1c78205cd24be470f768f84d1b3a73349ccb5352b903757eadd6784a3a2d2513274882fd744a258d24213040aeb280b63bf13f0c07febba78423e3bfc805d70d6b583a9b23a64670422becbf9d3530ad0501e65d06e94ccac80394e64d9cf8ae88fb06fd236a93d7dfe868f20238b8b1cd89ad62240bf8cd69c322b8777414eeb1bd78406c3b8680933ab19dc1f89d23b376e39f85a92d3880b07457b14e595ec02ce7d909e6565b44bca67b1e925c618347402227ddf76812db54fcacc8a22996d44d92eeae9c61bf8a2593e59eaf21d7ac1c00ee10a290d7cf1648ccff59a51c58c9bde5456ddfb40a9f60342006e3905ec833160fc6ecdf89a83e3a7231ee7c1acba0d2d12e97ecaf437f31786431698d54325cf8b2372f81a362e1dc2c2c9a84168104ceb3db07159e893283e5ebb9a9069b6538a1504d935406d7e2479d7be764943fa2409ec205de93e95057704b4372cdb9c2d6ca0dbe64156a7931990b8c6ef30ef55b44d0c3f3ed9efa4ed91ce3b4ba6756a9790908e35f6edd1de4e63adbc717f8bc4ded451dbb979983f80a4e59a2ff1498efcf1fc17d78d481f1b334816cc5ab521fa86d3a06241c6758f9d13f9a2f34c00bba8a399a60bca38f04ebb762e4c61398bf68c38a63e804690c9fa99e29de1a3c9745b1bccdf4b2e0e783c5ccd7f890905ebc639fedc119a13e2afc3d3d51aefd0d0aab93ad2397f7d442172be0306c90e2e313298abf9f9b1a4fa6aa748bd2f9e3c95c2446f3a6ab32b9f593b0d19e7b8b743aecd1b8caa6c5f971ebccdd18832f4d0f81ec6e3b694cc7afe4267c3d6af2d0fbbecabb8f3503cb04b1359eb74792d8d2569cfca63d471d65806e32297fd27e31a63c02ade72b9dbc6388a0ca7625048168398b186e4fb1c779da27d8c1973a531284572df56b9f8c2ece8f9f4e23a6401d5b664a4c61fdc64cdca96e2815dc87ec5a8808005a7560c6560477d6aa61391707da8aa6c6781b3e9afe8ccb9dfc18090eb7a8c41cadbbc4ff7117e8b6e2a7174f0fcf486c223d32c2361181fe1b642b0b2b7a10cad1233ae1019b0375f49677689125a5735c574446e75bfae7047e56b275ed15db9be11a4f8f2952d4f514d12fdd918b719a697f6156496340d7c97078e8f388f9cfd17c36954f2ca529eff5ffbb4d90ee0d9b794f54702c9fad097c9a6bd6f0dba435a4181c177f733ff3debb7614a81ae1c8279daa58c1e3b1d42eed4b2705fa9858e30253bcab0b8d84242ca22e67ae51e445260aacf5738f89a5a35da961d16d7f652961465a793097234531fabbac357485bfb1037fc61fa5ec78209012096eff061b4880223def9b896d160af185f891b683184b78ce77432c84fd778cb711091ef81528f1495a30815e969f07b78c50892afdf2de5321a388ccb9d9f21b271b3c57e64e746be5695fdf41c8a6631732d4096324a120dc87951f430ffe5eda6ce48a151e2b93d0f83bb5d447294ce12439d191413b7d93434a90a102ff070e01119f41664bd6ad748f3d6736c7ea05b9100d5e4babfac36d1b4f847c62f3da47fa9a71581a890233924bc7432862e7e67265be6c18ae3589fe406756702159319f05c30f85e8f3b8ee75761f96c440142bda0c4a2938aab294469fb9ad8e4cef76bccf02fdea3c51f22faf128caf300290e504754445733be80aec875f5d5cc4bfc2043fa2964400cf294c1b148320dfc1e8f7a741274feaaca78ccd481c6a00022ef4430a11a42cf97af62ea05171ff8adffba679a91c7565ef01e92542a0db0d9d496a61743718e33c8d65345ca0d371c4b70bc302945a78805a08fd75e93f59bede1c95f5be0b1b1349ecbe23b14d3f6288d140b16418e71bd39729ebc82fb9ebdb83b494b5c8bfbfb7088a9425c5a070a3378a67865f7a2ef2eb07eebd257c234cb9ec2c5ece3b970f0cf4c806bb0b7da27dd4b9f9e686a86ab5572446f9fd69047657840bfc5eec0af03c58927df568f863fbef7a6eeee3cb788bf3906cfe4486c4d038c6c1e15747a3c0bcbbab7c2a292bdbfbc4b950db8fb867d71fd611763741586beb7b3c1968d20d5b68eab919bdb73ea5cfcc80e03942033ac093179e370c6d58810a4d92d2b9b0afef0e3650814e4dd093dbcc9e0f01d08fa4aaf65ba0791bfc63614bc6a0e2a60c43c84aae1453e30e7873db027404248a3da76b967cc27c4e9416a1b9f31395006a4e41bfd747f0d8eab36538383daa2125e3fdf33cc3bed766e7c67bdfea30e18fa44d8167c7ce395bc964d1bfd3aa114b0780d83a918c4d3ea2ef33abe4bae88be492c92994cce77c98963d4a9cfe7c9848bd62d88d48f5c59ecfb87886c9bbf114d849b316da6bff12d95ab872a76ef4a4fd2049663ec073fc95b09f71efa2d2cad5121edd631add3779813ab72978b14add0f80de03735beed8c50b05778d203319dd1fe730612f553d57290984a16ac1db12cc82e5c90d10bf00dad3f6013b66afa1c5078106bf4bd6430638542f30cb62199493368804e671d3ec95adc9d80aca10424933171c3054565b61e1674455ed1bfcf35ec1422e430502333a75cec4b73c662fb55d01da2e52e0d88600951cd310bc420a4fd844982a040c344b55b656ec7a8c5025928c7f4ddee5f0504f1af3457f4b833af8f22ae93e79af513e0421f1ba467feeeebed82d76ff3f9ba600ba7bf9d86078f6dc11690846f8ae840e7f03b369600ccc6a7f1430e70c6d7007b0d0796c802718f1556a2d605c71b89e2569207d8573a54b0cbfaaec60ef4cb721e0236422e1bbb6497d5dac28eba29acc9f07fa9969b9484316bc027a0136660cd6960a42ea49a533482ca7daa0e7fcb4a8b4cae21c169a33c7787482c4f24c343041e840dd63df9af1019de8233c1d2806a6e8a4198b42d26073e3b95cf8e66031784ab93e8168c24f4acd0be2adb37b152af9744ac9bc8bf32072ddf1ab63a08fad82e6e414901b6527048070ec7dcb80a83d0f230144ccce32a24233a9dad9068394c99f74f1b5896c32808898f3f57b25042c86ecdd214347bd808a2bf9dfc6ff11ff53f13b43a08ff1afa781f1c2f62dc6a0efd9bd01ebe92e910c6dcb6865e6871ef8bf23e34c0c0c8f39667dc54e0b4cac3c82311dd2cf7227c18e9f9bff5998599351dffde9d9188b83fd1a25fc32dba7658465a1532ad40551fc843c7085f08595844c6e0512107ff2cd702c29c7954097b45b7b327151460670a0fe1a838541f716ef762cb27f38156995bb030d6d97676312f1992a69e01c6785d268a2062f8c424013177d494c5ab8ee1c8679a1ce31e519b27b7d1f6956543f9d6abb66497193abb989b56aa775e53466daa1f71835e524aa3183e67599a26b18cf6fbf21a34f0a3c7087e787454d9f2ae3e3a2b29b4521dbc43a3c4982f74fb36d8bdb104e5189de740048f893451365e3d68f8958523e17b4ca105e568a017fa9389aa2bd915882b2ba8094082613c4a7df77108cc0864c74f0d141fdd24d2fafaac6247077ffda4b14c66bb31e0f146f7ba4ca7725f3403db7b5bed88e3bc02140bae5391b4cad8eac5bd2088a938b498eaa98aebac09cc8d722cc6b83015d57511b83ea0609da006ac86e7f10a51960172a4bd9413726c48063fa93ac9969b48430c313308e4454c3d8930dfe320617f44ad6a6ed62f1054d12953410a50c832e0fff3739b5bddcc4a4c366a52decd84b9e84495277a85e86fd71bd1d62d2c7b262f3f0ef031cbc853a2e4711d7ed0691f0cae477f8681b5ad04b739453cb2f8422a3b8b289d0118a91ea1e859368c3e9f0e42c8bc3bcdee2719eeaf29675d10ef5b083d052d7315052cf7415f8e0a0c1a25f25ae02aeaa801ba102785262190c79e3588e4126ee5024ce82d0f71212a653ee64371d5085490cf810e98595c984ccafef465b90bda1e263e201acb1372c9748e941cd5367aaac1c85246a4280f9897892529d82c48b695a9da753137d703033505132239a7da43bc5c80c99fbb1bbe61424f18040224386304a0fa1f9bff1ef3476abc9f7bb52e67301080ad1f7864ae58969aa0c61f5f83265c0fb77f53777c76fc54956d7b78c8838dcb12e1808438448b3c1dea9e5f3246c13fbc5d56efc612c1435c447db7cbac0b4aa63cd488a355db0d421970b79392472972df2ec0a654c7cb60cc499dd926ac701f5096eda78a4b6bb2a33a19a0b81ea7859a79ca71b390e2f72bd68e824470145a2440d180c9c6250f79125ddacc79b9c18ad199449c9bae23baf0938f69528d54a9764c54db6ae31b8c15f4596a6771c876191e47af9b3e99909a5d2370a53da280ac4a3e29014fed6f1aa4c3a384aef995fba773d517dfab329f4ea8e8a211cae2486ef430de79f33281b855083a014dbce81caa49e7fe6b133f90273b653ec59596dbb0184f2798287ef67b3ae4a7c93c0d49071df0e9ab9a6e53958414a4a7492cb294d53834e40d4088e9f64dd77da05fe93a68538270d5fbf4e852e402f69d261d82cce21604e14a03790044b3d1365637ce6164d8fc9959291434da0be8269bd718363ed6d9b6731760888aec9a055dda0323898765f26e58722945c34907f285777808032e2f25274b9c66f927afe9e86ce310b98f2ce2b6731cbda3938c815d38c72929939425950ced27f16e58a496922d78b128220415402eb30d33f764490df3d086cc04c2e357387062bca6b4945471ab0718d69ad76645abb3f0926105e7b26b601389ecd2b6a7550318dccf6b981aece8feabb165c86db1861331ef118c31821c3b5ba6d570aa8f8166f6e6d3b2415967c2d8bf310ece56c422843300a8a40d4f09612ba63d41a133951f3b9fc7bd72aacb3055bc374e2245959a57fedad0f0a19b487cae13974464f354a824922e51bb2619ac71ae55e009ff4ec739d173f4d8c1bea35a43c03f5f4cbd2bbbbd6be658e9d7f967d83f32c4729524f38d69e06524a4a7fa16f62dba99c5795f172b86e44af762920f5a129b79b279f71ae8b025f6a6258d774c0e7f0b2b72205f55dc7503d96559fbb1c122344a00e1e18fc7c2709854d064347c2d2cd543666ed378de78b0be89fce9b585ead6cb5ca1039504ee88d8a2fa510790b6b65b6d2d31cac0307f918cf9b7351390674004a0968ca9d507574ac02094a31b377a64b3411b0cc188e1f59a420639a8d88fc01342a81239d748851eebc3b10b1a2f9ce7aaacbe2c99df2919696b90bf8879a277180143c9d5ef58d2256d6f67c323d9cd4d512c43b5ca0052e7d1e9b681b85f87c143849ac1a2c4654b4788412c1639c0ed287a1ef3057c7b35845a606926e6412cdec5038d4de2a2147a9da2e91f045a0ee482e518b1a4625d28437ad84f8d14aeeed1eb51d6ff086a1efab35843f4843ce8e6cdcb9e5de33ec1648e7d29bc4687ead6a2a820cbdd6322dac17eebdae4f93828179676e8ea466594e1eca689fbaad4d756690b2446afee138f7f7d29f83c5053aebcaf12f95e57264c1c1e2a8ed32090d99a5c63293725fbe9a3f2d059b7f0ca9a625ea22768ee051397c68def06110cc014c4fd64e2bdd52a108fdfffb138150bf7f554bcea616fab79fb01df2714f5ac076139d9a0ff080b000149bb058f6b5c02b214ad380989ec1fc6d2d7b1c01cdd0efc65a24a2255a445113d4bc1387cb578d355b0c6650bb60ed84c3b49debf91380f4a92dd63fd99a000d300248953a355d2892cb497668220bede1affe787b8d3d4ecf9e9b09e421d7d0e5740119ad50f8750680cb85b4ad67dc82116ac5f7a9ed3d1a6e8e9795394bac582bca50939eaff43fb1e4352081b327984157712be71dd4ee51a5a6ed443471ec058ee94236606b6ff28e83f172d1cc29ed74eac52fd8deec7a7ea5cde9a2a84c380240508995c8ccaf95ae142d753d2848b8886da3bf18fbd7da7fc935b8d087b4c9edafd3de4bf48096c4e02863a50615a5db2525fdba1258d97aa43ca26a2cae12a14c1a69451e57867b4d2d47c3bca4c51973958e887ef19a3772c7ea735064d4aa0cf9346da21f1247bb0895c0115de0b911b5f80f553d75057a4cd25bda9424c2b7c71dfdb103d9c6b9e7cca33dd31a6266f008037a6c418517d22e88f48f6fd1c674205f79eeab54737cdcc32f9221e3244aa29fbf50c250de81e668ca4228e09a2f38ff959f143c69197f852ea7ee8f0ce6ba08d79475e4564ee3dcb77226b1777d0aae77d2ac6208baba59ff05a3333e49d95ff54c26ed6d9a96aca0445a1656a7f2c6c03a9bab65df0b97f1d28d26f1559d1847ce4e672c580271da4d695b7bb7771f4fc7140590fd9feeafc6e13485bc64521d76bcb9247af28da6688742161b71bc0373ecb5092959cab8f743e01216f3605b1378f180cb0dc2f6515b310064734382f2141aa24124cdeee28c5ae0c6fc98713a5ba194da466a326a375886dc06c785972cd7c15fb06d4f72a66d258a37e27bde5e2436905ef5ea5e848b83c05ebb4d107c8c4a3bd70b5e2fa21e9c2d83db1708340e6497e819a1bbb7e241170e08483cb8225064e33816f0302e9f728009b0ccbdf26bb741e741809872234bf82913d6c9b09e6220f88dd9d93eee82e6f5f7bd1736a17ec33784f4e2e08daabe56e4ec0c7dd277088f3d56abf4aefeec04526629b47bd5e6481b63fd46438deb01933ca0e62fc2f651254b62c0c9a4ad91d30500c84c4afd630ae47ce46c604e1f6b5294194d1ff7b96d0307e636d64577c80169868459ecf816099f26953d5d804235ae3c9f43e8bf066525a8d812632fc4c0f10e1b70f2cd63b542dd0e597a9056621f6c20b1c0d49fdd2d58957f427a8044c0c2f5397c1dfd5e60f5a8ed6453755a9397cc5d5fafbe4345309e76c7a1cca63b5b410904b0ff1bae83796367232e45bbe343b5e0c39675c62ddbcc4314a6401c23dd7eaa812ab37c28530cb54161ac35d961a5c0079f848ecebd977cafe7377f8e9f087f772260da84aed11f5f0a3bcfcfda243f11fe3a38023e81e34deb5eab53c64fb9f945fbe0ac3749083a0439c2ee24e24c6572651c8340af25060e20f0c6734f7e326c79ce8d474d7cd1529a561e60e39366854d06404facf1f6b775ca648fd622d88e11cefcbf6f08de744765a3cb7c15ef55f81021eca46175c18201c38dbb961011627051e2bb862cc7625b03b227e33e414889dcc1787c1259ed1918e3e6c12b256b21a362e6da1cc03ac3918296205dafdb1ff2d4849902e6d4b42309d0a3c0fffdedaeda3d6262621798b704a9e56f6b87371e3b7cdfb5fffb1a4fb64154ae76ae77bf665a975117f3160328564959b61e2da34968661d5bc146310e6659dceca2dd0334822dbcf3ec67b7cdefcb3692518683051b6dbb0ab0e7578b98677110ef114730cc1ceb8584adb2a0571d614a019863676eed845e498ca63b489458c0727459b2979824b440bfe8e07101e4ba51d1450a50405268dafb785b4b25728670126a61d550b5ce5279bde96d3cbe1e4fa0e8945f7da6e2abc22f7f9e8ec719f7b628121b60c0248516e0bde1498138b8c429f0110df643838d2c70afc375f21c8d9b845c037623a45562029197f4959d7be1c7bbe18ce814be36aa9fb9dc73db9a3b7e22ba4801ea5881c5380fd81eec921b650cc82cb8e44e5b8fc502f7ee52190267c680f00bd3939566d1a8f5d00e4bb5c1dc197e04ac719820ebd9c3ed92d0432a47c3721c8297a032dbac0a4754c673ff5b01851c99bf2c9c109f02da05be9c3713bba005f0f3351d4ef39cbc7657957990dc8b65832754a2ee0e180b86587edec39de02bbe1a4e54742191c2e097aff9b3694a42a7095af6b7210e36a00d1510f9525e94fdd2020a04fd5c8d07e7d98865f6e99524a395ae872145ade10f30903dae140d0840b6c761dd378ed3b5ddaa47429e8b6a602716e8189060246667c992dd04571b90e17cfdbb7bce9420d1ebb67129f91cf0bd7c23520a4e2987dad66185ee2f9eec6e36d0c9387c5fd312e1aa255eebe27aebb13715a58d75c5b3a0514619000dc4a84a08e6d5a6a80c2606bf2cee6fec5bd3762e38bf1275747d002d83a2dd09a1758d4363ce9f077d450a2040f504066e9ec47f40395c2ae6cfa1f42ec70cd5339b40e28241d9bf9668263b7bdcf795237a30199def28180c952a0247e6c33df6d84c7042cc3af33cb95845d6a48d761e92cefaaa14ddf70f0450da535943b54c9ba5e149ca8f4aab6a9933056afed8356a6c0057d21f258ec1f774c015746e6611e5715b676610e731e3d7e353d386e9edbd5cd76e014bd23528c0dbef0247e751d2f2d8c64e254fa0026f6b4b25030279bb67d19888e5a058855d50d1c93ad67eb08d62abfb1b7179fff214453a9d6425b4da704c4dd08ed428d85ce553615586e81599ba2073bdb02d00e958e55b066a785f1215f2326d84f739eb834bbebce831f69487772b749b500ca4f4b1ef955e58ccad4a084cc9234211811a1045f0b732cc8820238079f1c263e1b475466bc4c383c76bdc6dae3ab111e492a11ed24577382a712c67c3bef4ef99f765382b84da8bbb797ba4a506540e4f2a98e9e74a48a07bb89835a8fa5b9b2e93202d6509a96ed650533d57cb5daa8547385dde388659d3514db4af330ac9b2d88c24d69519e2e13397332ae4262fe2e83dd4dd6e4d3d0b178f0a19533a8012887d011239eba1b35db66424138cc7d120924f9a09e1cfa1886c9555dd0917be4ab892e13b474f3c759eb4b73543885466934591718597800b6b4a61d4cbe8a1b24558f135c18e32c2748f80968b3d4a64c36dcd35dff6dac4e7f4c5aaeaa8308043602c49e925091b0e6561618bb4209e5a049b939ce6acb2d0d1dff767f25e18ec6aca11cea37431e24459a3dbb1c85af414ee5998d77f57468025f45e66c11d4c6bee192c8a8b4955142b56740a084a271a22de41ac424084b159ddb50827d0107bce0736521153d818ace2e7c622c22718049fc0271cd8ccf0c080490b96aa855782ecc0ac07bb33960efcf6677c1dcfefaa3cde667a158145cec7d9464a494808062aa4dcb1bb59de23ad72a4f9c664e53291e9c2aa2516952734c39062d38ecd9783b4d26b3eb3846f2ab3ae29c02e953b52e94d3f5382be3ab232f675bc3be532a1bba5c6303af356d4b1d0c95015d04076738d55c231824643dd2e164ef0488c7b88d68ae8baeb558c1a95d9cb0d6126393f6a0f8730c05278d7f8f2a9d83452cbdd68acd6d20d00fc6e9952573e3ee9da0c2c07a4e8a87dbe460c30c9bb89d22f97d2b9cbd9b38861923861b9fe661825cbf14b5c8d8277ee98602e64191dca3b4a27ba593ad19ba513fd672ed3fccaa48c32cbbfccca5c066594f132cab4cc32b9f72df3d4a0751934601168dbc13c5fd1a14f4265c99f88f2311144c2fd7b3e169a886c620f47169063a103f24f23b31d4d86b3280ecc0df9401d8fd687425980b9862718c1dded008c9930d44c35e4ab4cc818e8bbfde839a6aade99d5702ecad589b5fa922d98c4b177db92aafab6af7f0589f2061fab751a9124da83d5ba11fdaea73bfdec9a878cc85920b67eb2a07c4c4be5bc57b87020d10d17e7df5c1add28301059c96039cddc8ac4a71e5bf286625b3cbcaaa44986912dccc27bcbce313202b307a8fb593d69fb75b1ec1922601599dacc83c0f5f82343fb6b732508d80fff819cb69e656bc565226dff164d7cbf156c7bf06404674dd20884133f21bc46be205c0eab98140daf835a184bc8a828ad794653fd46eaf52a4c1ce7d11fb26af4e71f8ebbfffebd3e4334529174ffc79e702874b3da41f2485adcec2f3f1d896722352a8bc037af540b73c4c82a11fb8a6df69ae2d8ae8cfdb607e4622257814203594267a2e4c9d92cab8c929c110aa8cef720fc752c32fff3c55258677959091c8c7d4c87298d423916ae1b5f97be0e786fb539e6a5e8645d39cec28bbf2ef8d9f813bdb95f578a2e11ef39dc9be87f57b5e8e850945f18e7d71d60d68d877837675e6891bcf4351aa79cb08b748eeadf73a31b8a246ee89e54254a90d6049f7ccca4c8c91a9df5d94944966efb9a5277abfb1567e28109ad5325d1836b6211c9bcd3ec1b8514ed1be34557730a12237bdb7b400e0069f47cccc6f15b1ad6342a7add388cc62cde53e11a39e9a7b25b54ae1b2896305370430328d4f8bf8017df13162065d507862a573f0dae063321c663ea7d54cf3b046fe2f08a0a41333f76e61d8d813e6dbf3101de91aa6cbf118253e7cb7ec515256c6a28a5f2e866af5a18d4c2144b6d851504e2b2d9f4d400f322c528799d8b4767bd0e3504107b892b608e458a477d6f738dfa5eb9893e2d3042738c6a73f284e3cfe4f8d4bd5f62f6b4fb5db66953d9148f857ddbb43ba6f403051e0d00d4a1ea140ce67b2eb4b330dcaad8c11a99fe4876d223b6c82139f0e2a29eee2c3a09ed3a17a5bfe9af52eef3ad617ddbd2d7e73ce0e013d74de47d1e42faf5ef23f221f4eb31f68cd0d848b59d47ca9f638fd6eff2fa12aa8fe2a2090c86f782dd0e7270281472db569d54138f00e24f091673e27d4b8957559c92eb11ab873a0766f5c9f323386de3334d954cc9089f685aa1afaf28fc3b6167917068d2d6928d4eae34285ed0b9474cd7b00124e77df1a14c403fc7ccb21b9a112084c0db73d41c9b018679d6968477a7af3a73ba1ddb51a87cc0a30f52fc152a9a08564c61d463e034847f0a0a0c51d3ea20185f28d0eeda6638d71d936dabdd20a42cfb88034cab0b2c146639ab9cfcc47c019904cf19fd120e9da2e941632922b046768a613abbb1e023974d48b27d17db8c58f0bdc40bbea13dcd017a6141c767e08b7a1a8ab045403d10c94167a96edca6892a9cf4b806e95b2a41af42d28fb2675da7b47f57b20829699f2168bea93172f63944659fb3373c74c091c7d1902409f835ccebbf4e320d3059bd5cb351d9dad000b3ac6258259fdc8ab7665d5dc4fe83d398dcf5cf938106871efb5368b7cca143ddd18d88be5d4cfca439ee7f0f9ecdc185e6a381f95fc7baa5d1464d99b3ca90f455049a8f201119f54df879806c1e43855d22275b6e54f448d485dc9414586c184f7124e3553cfcc1c29df1c51cd461676d98670ef7c79a0292aefe0467d4e20ac2a8b23bc5c27c4da0bef846338f6cde58828cbeb9de547bfb12fda37d29d7b9ed32f09f30d79d70c08b289f189e2ec9a5652098ec95c114822e281b0624f39e6989504c4d22bf885c8a311ba4a271f78b23e41e7430983e03026dddb8450d4295fe6ee74a19e2e69f0938ed6502d7c94e2678bf0c7856c1ca1912d229eb432459dac8edcf0ae23e619cc36e9819cee18aee33a56e0b2070009ecb6968367a7722e55ba87e67852db36fbf3c7f05962a2ea29cce2847a5a41b434b060825a28141c9072eadd5d7ff8c03c5b234cc14192169d24aca042e9481d290103a9cd08617b9f2ae0efa9f974f5c19a36898b6328d70630d62f4eb382e6e384bb98da60a2ad23a9aa33e07543b4856d2d745d2696de951c714517e15569d48d14bbec673d579fe8b3f8bcef923982c3842a2298214044c016af3dc374f50d030d301d4ebbfa2188286a5daa6d0bcac3b085bfc4376adba2cebf55a8164dd35394ca100a2bbdbf407a7a0fa9754c54cb58a0198e77d71350344f476035a08ba547b365412290ed952a6a9880470036003680333c6ff1ed243bd97f23fd36ce3dc964cf2213c73fd9ca8451dcfae5915c67ca049931d9fa351b873d676c094633a21b9169ff1490a5b99b6cad853448a1dc78d733e021ad9991495893b2b0a81974f2a585e6d152acb1f0337511bfcd89effffffffffffc7ccf6ffff4d6a1c94e273219f710c8e73ce4de68f9223d1ae8aab34569573f6629e40ded855ca4c8952d77e8afc3c6ab643f1d3ab70ce79b7b9397c74d75ae41b330759a0261140e5009d06b1477aef233eee980c34ed7b8624a39ab99b870ac0a16e137b41e47a8eb6f3587c670946ef506ba2dc5d7c5f2cae5d2b12be8e17adc6ff3f9216c8e1db068d485c8dff8dffffe74c2544401ba993e6b1ce27d258269d7d18e47acd06cbb28c82616c6c86b59203d3d405ad0803baa9a5cabe41299ff16b452b5fbc47385a819115038320fddd370672f856f0e824f144a365a3c681122c3b408ede31c8f80488d5214dd3341df4a16ea1a24f5ee40721475e18202cd8562ec386e7a49b661266864de6549f61325c9f1ca1e4b46793d71a9ee49cf30e96e3ce9eb2c4896c79e7d472bcb6288b1c019836b1d399a7c444033c29375dc74cf8d25a1ef2081a76a291c209f9c516fe928147e2cc08db9648eae3f20d9b90224b455a2a53596136992d076c19e88f85aed6d69e1865a449c4890a160cba04038ee9a866a041c725ce2e28a9ab75ef1a1552e41c256dad591d3f4de918398c780804fedfbf197a4c6cc598e4f1f5e975c2b9557ac6d54eb98a17102d7f072cc10e4b6747a4e964268b7c22313a31b36553f3ec6d17de7bef0e28c764587492405c449494c8ccd4ac8c45ea9e25889639fcffdf9102faff7fc582626ccc27064030222766d171625e45c8c2595a7dcdac5a6db16f96b498253167d768a5248e68e75b53979f8c33f66c80bd826d02a0ee225be5da6a134768472198a9a5d8de79e1dd1809b3d38aad02f4b0894ae7da66ea6463c0676c83f077afdf1de27e72bd75a1920d945683aa92352088004b50b1a8d20c1923967635aa067918329595da3191a4af2617da7809d053e362c7129b2d7f7bbff7906e890cc0a07c9e9543787498642b255557d979429daad23ba5f7deadac9bc3471f69ecd589dd7befbdf7de9f8773be5d86337b1b5121a45cb79f15075d42c33457ecc8a8181fb637a4b4308b146253a826ac95a6a997c71655a0d0d1ee95937f756ff03d44ba19c428ee1c458640b16f10993c23169b69fe8e26e1f3fffffffffff7a89b6f2f632b2c69482d59c617348a2ad997004ad0297d6d8174dd2c15ffbfceaaf18cefc571ae40080c241a765565167427d63b6115576f945cb6fc831ab37f58b13d1240b6de7b27d7400edfd57b90bd34665fceb02e2f877cec56cf950cc77624ea3198f71e74f975d034b7475d4c5da70d66147befbd43df08256610d32adc3a67aa67218b142964ea4b301f3e5fa6ecbf7ae15735db8b72430c1df4284d223bd1706d878aa4a82749345cc796948bbdf7de7befbdf73e84023dd0686505e6b38cd301d1cd135303365760a08d867f7901f0c06c5c5518a3709c771fb781ac0d98819f1a906af97d58c01b023fb1dfffff1f41ffbf41a1de4f43cf2a96c2ca49a1c23b866db5ecccd0483752df4cd21d067e453388c39b27ddd37bef4666cc7f905eea5d488ac8dac376e58aea4893cc1e132e21fc641fdd09add2bc5cc8a51454d704dad8a24dcb2daeeb8c6225601bcd3260079c3c22e27c1f62b80ec47033e59f276b0db64d090048518acc5c9de3347eb4f8ff288084cd9a3a55291f1fa326341e1460644cc6772e7928da77ffff462fee07c1b84f2ba9344e047e75d008069d7dbdab6973bee2e4eaacc6041461f3f654bc5f5e606a44b039a297b9f7def5e4d69f76cf4e7a42868a84f7f644aee128f2222c13c8c99bcf1e0a4685c4071c497f25941638b54f138f4a8fd294981db90ae14194556b48076ac6c4167afeffffffffff57e9e6f0d1dca75557ddd1cb8ac26c7d59cbb82fb014d5a6d5b883527c1e28d1609d7c0e2b3aa0ca534dceb90457ae8591eec896adc1526922c35a95e13c94f33006c01129e31edf489480689fee069a6981fa47ccb10bbd45d4900998e93af38d426d45a13f71656c7337ddfcf027cf429cdf0772c9f930bc9fcf9f870bd4e741231d42a79e6921802653bb438cdb949cbb901d0844cb6d579876fd2c9d8195d1bd54d03dcb40d5aa6aadc4d9d0ffffff9f996f4cb1ac09c933f1babca824d974ba92c858500c19abe8b87d2c3a50a02acff9ff7ffbffffffff466466c89d14aba0ea3fd196b222395d242d3bc196a110bbe7a970540400aa0000d3d525efdc5de590983863b6ece5d5083119b0798c71d61f336acc247bd251a2a37b29ba3b8b1d4c44b4ecccb2a6dba6bdf35b9166859eaad07a6caf2cee84738e0d66eb5493e28fe498180629fe46541534c5fe03ca029943152c0711e59b25280c42fb34085dc0c7821f8aa97d26bd687ae83515bd9f404d22a139b12e6d01dcd445604ebca89516e811f5cae89e5290a857aee043ec48cd87d08d6e66d5adbd73ceedbd7795a48c6f3d859b7befbc0c88f401c78aa31532f93ac0702500a138cb727457cc2bb81c6c414968e8cd076915b5a78840ef0e83ae558cb88e8c7f6f334b10db13e45896a0cf46fb4119df1fb14b61eb3a319bb1a3e540563813ae6635e0c0179c736ebc6aaf6bbcf7dea59bc39741e4d8655db17fccbda8c8937a20214b3c9737d67b3beb692a59f17a6aeb4878ed25664764f1e82faa4051714222e16a8971a07735c9eb572eba5283f520c4a5c547b6e3cc85883448cccf47cff436fa01ab1e6a1bd5158cc25a5839e7fc275a21fe2003d73b4820b85312d5eafc9a7a598b8188eaf22405f1ee88b3b438ab9e7bdf789f9f1c34ecf3402a671049828e544b3865f589f1058da27428292f0c64888bb594c46b325e69bc2d8302e6b3ad86d0bd100d739b9a6c1da528195b0ac3430afc91e51367f415ef91eb29128b9acab6c4ab8e690db1b4ed28ae40cf925d6c3dae6d6e3d21577e8ffa9539bff8ff2f230b96a505cbc41a9c6fcc4316c70f4bdc3d6b39bf08fb985ae696d955e47ca4bf716d483a02ca3b4a59ddc2e4b7286a5756af6569cc0a14e9fcfb07b9e3e6f0d1526dca4d5fa470ce3955f90a8773cea552a18613dc5e0af59a01886c60ed40e46285449113bf15b900c5f25a33d2995ad950c4ffffffffffff2490c3073da189cb230076d5b9b1fcab9b9577efffff072583c6a013620a8f50058a94feffef086f8341bab7c0933443b9d37bc9097383616ff12528be5ccd9ed0f208c6cbf8d4e2ff7b20da116311493b3a022d9da86d7366e411b6269b4c01d31413217e60b3712bda47a6b2c011ed0f494d0b1a5b00f8f22b81e46643b602b4f098de7bef64d1cde1ebbd77efcf109439e73eb32750efbdcf3dff83b40a5c98744eae9ce534bea0512ca358946b1ec0865c456f9a2d63e3d38c9ed78a8374927cd141465c67435ebe422ee86030b6537968256e2e46399df29c40e1ad250cdeb1190223578120973591693ee0bc6758de6c567869c474359df2c478e9b23ed0750190da018d6747a9332702301ec44e14816b46d5ba835b209d4cc6f83490406b3087bd269559954a565bd776c64e480cac075737f7c12e20df5165fdb718427b1f7a6d70ce39cd916649d38cd9983771c7fc70c84c2f9254f30eac8531135c4d7b0b412aa30ad79ad4b42ed4494145db96b8015d2a8c26d0143bdf18ef8374ef3c7b6a8b38fcffaf667c35b222fc4783322b8d73aa85ad5e4e29593a58d837a14d461d1133e2d7668c8a3237040e40a144c0f93c9ea4f5535928fc172ef03105efff7ff0e6f0d1c227613113b33eaae652006c88de7bef3c61c78fb025f1bfc9854c7e1f3e4b28daff7fc748f3ffff7f9811fdb0ffffff4ba4449bdaa99c28b5b33c37e30b1ac52b8a970fc1fb3161e9322133b219da63ff5fb312f440c11d5aa1fc529e4331563afba6dee35ad0d71ab74e8cf65230ad73b9cb79a9d1336e1375901a065f9a087b1f0f89dbcd9fdb88b67d9a964a1be19b26e9769080897cf8bc20fb4354ec750c48c988a7760994eef79806a09da4f9c28e26f8a707fcba5e00e3184edbd400327f820fa828e79c73ce8d555da71ff2940e9218d26aa5375f216910b4cd961331cac856ccd7240cdf8db3a462aa4bf48e68666b19d5f942697f9bebe3ced097edbec2c8ec8db6b272f1ffff243c4abaf3c9afe36d28304b6ce449c296a08c9ed1126557f9c7e6d9f32265ecfd2a765240d813bbd472abf255d762d76bdedee37c1f65daffdad8534e208947896ba7e295958a49bb385a6ecd96a5b3c262e46062ac13c6484d678c6e85e7a88ccae59be7a5fca23fb87db55add693e85f2da3a56ec7dd8794febd00b35e59588f24bd62d9ae99a20f91c81c4c16d2f19ba6d383b4c21aa34b3b3eb4d98cd943aeef2519b5fb65f4f61eb4a2983f5f596e5827350602121b96d6dae1034df8daa0e92ac9c25bb212c17778b215b4101052edb9ace1c846a1ed78b15b9096c84b2a6c68806acfa757d2b12b1b7245044e0a16403d8b177dc17215ce01e864035c40a385a5ee4d0a1a81e71799335e8d4155d81d790c45b6b8a2135677f1840c977e1232ebd280d40944e44da232c79674de78e29d85aeec3ffffb7d01b8087ed80af6007b53bfb7acf08fa3e73529cc0724dc0a34cc3eb82c9c691a9153b56ef1642a373c9a53257bcf7b969f91362881ca42513e20dab51e8b0ac19cd80e92c6969b6d586d3a286707f9c50af5a72d884c0c357f78c49826424b5ab46dce88d70a320a9b939e7bc5cbf1ce98eb425a0a7b84305925c504a90f5562b03328f89b2a4221324cd90a1543345b8038db8a8446eb8358d01307b040319040001005114c8c24c925c3d14000417ba9ca47c34483038281207426120181006838380000000000381807030180612c3a2d6c03d4c6d7dd0c9832619b11eb0ac4cce745e11bd9739ba2086e0a3e154a9915f26b861dd54573a9e70debe2d88342357061b1b7c670363f9a11b6e0885cb4eb763888f96fd2d9790e77a92094f6d8ded5c52891777879af879094377864c0ca958ab1597730867879c4285593be7831501874836c79f537a00c6a9f7297cc7140c8c5a16499d789bdae48023b1c10246b7bd47de2274afd17abdbd1e1cd8c806fb4af009e14d46f69aa1a76ef1702879c7539c1c83a02c8a83a68b2b0f15ffea10db60183ba696cf8a8c6671275248799099eea6f001636d68078ab302a85a4c456ae28f1f7a66b634ce5232df592e497aac3d13f44e9241496ce8c031f6723a18fc68a6f9174fe69ee029deb47cf5932bd4600b61e85792a5386c2635a9c56b417ca4e0c4559d59a05a3d38508f2320e9917afb08cc594008d3aff5221153a2d39d151da7b8eb36abc3640a1326c35dcbc79add52fd70ddf60ffb74539d43c40c02e57b85803391bf4d777c9699b4ff4bec8479b34f8d5b27e8da782ad465e9cc76c26a30cca5e7962fa97d186c8a82570ea20fb78df4d23195e00ce0396036d64e8e2a12da8b804584a73488d01f1e5df04e32371d8092c9dfbee61c6cc8afe37f773f2b33beff6571d7a618207d0ded80b8ef1ebafa9ffe366dc29bc1ebaba635ee3e121a6ae289943b0292c3d9b536606f680881eaf927ba4ed468d2671dfa692572d2f543d318b4b92794b1e6079dd8dd1be8423d79e2b4a7425fd8c48605e5c66469697d0a1209dc114ca9f721e39c8b5ea1c42566725c2611ec90b6419145e8a4baac6eb62cab81744cb44dd3ec38bfdb0e019570e53aaab3d05d50f953ba02d19c73bb00a242f4cd99f7de9ac084c7226844a6a0d5b71f62a515d02476816bacd56711624bbd92d44a2b8424fe67ca3776bc413f7a28ed21c910a77374018b5b4aa27ccf0ad338da94bfb451b09a2b55ab653b4bd1bbfa45977d00296afc8d224f21e691b1f89de51ce589237b93c5c33a5c02fa75cac43e88b32b660717dd7261f5cb413a251205393be5c25c530a150a42f6375704e673f4a553e603167f23b11c480989eb7a6491375df1265feca7689ba91523aaa5f1851ce5f8523802e6255c8c03813d7458665003abfc64697541851ae05afe5fb474e3471f54c4a39530654d2096b1486c13d460f9b062bb1305696db0343393ff7a088f1da64f66e91e758025f3ddab26e4326c45cda5151ea7759da05f8eaab8ccbd8957cbe8b00460b810007481659eb274ea4f9b6bc6d6a0abd7cae9e316803f526b2f4cb9093140f3736dee1b256933d4a8c729818e9bce7d3c9618284ba6dfb4bc6bd14a783472467d804b422e963c4751aba88922b9835156b90e83a03ee25ba3d1b968d1efb4a0187d0f0cddab30ef45b70aa670b48ffd26df16845d6a896d8aa7026d8c6cb8eae9f9cf2d7dfab847e484562245661d269c3b3c4d26b1085df783e0540997e4634906f92fd4735738438452568023da1e63415ba9f22c49a46aac095bcd2f915e2ee893e20921a4138b4e581485c4bdb456a56c203d7e0eb4045df60b53846477461e3814b938936936ccc06e79b32eb68e0d248be3e2a8bdcdebbd2fc39915530bee6b5d6a9889aa03c18caa7b5fcd270d3ffdfdb7d4da1cee9f1e32a7e0d45ce7ede3e951a6e3a3bde2cf32dde0da38a6854158e99b0804cbac5298880ffce8b50acebb1df4062b1c3a7d053259a00489ef1d337993a3bc95244618ac00419cabdcf265b7ea9aa9a4ef596e71d112a56e150d3cbeb05cb93b39ddd0c6492b6cce805edd24598ef6572edafeea87a6182260c12ac13ed5fbb54e75628fe5feb111d7d1455a9a6277eedae36345e5eb46122428667bbcd06c292f838579d63521ae5ca9bbfd4aa8045d61cc8c3579a5f402cb47094ecb8817ad1f94e0207f58267f648135b11f66b9f4c0223b48633a4d224eeb7ea7f16b1e4d678862cf730b4edf1ab328c282f3d3499556f246dcd3d9f3f245613b30faa91ee1f486b71e608f8169278ade0c3b00ae6b81f5f10a57b7a8f9f69f7bd7c13e01905f5dfdeab382d9c3189473ae77ea94052b1d7d5c7261fe396e02e4b5ee73e13147aaba2ac214a7f9365107808726badb0ed1f514b19cc061ee12ce25dd3c77953f82ffa489902df79d910e0e457915b4b0cb17ce6c8886ef8857e3bb7c234b2c8bb42ee018f998e06fb1a03f6a820a75d0fcd0ccd2cdb87f247e820799c944bbbbacf42bc2964201c9085c33abc18cb1a375abe723e8363a95a132fc02359908e3532ec7aed2cc1a49d5501cb5159ba7e25acb14f05b4f746b89d7f2cd77fcb853b7bc2e3fce3b1f7ae2012899d42660c119557355a88a1a115f85dd078e620bb83e94978f90a2b675afaac669adf6d35d2806db7aabbf534faa981849c18e6bd893682bfb258e10232d171379883c1efbbded23c6f7b808883cfec543bff72adbb4a34e622e0f2aace4fbf0459a36be5555687187bef98305e0b6ef81ae10ae1c65c2a22ca6c9264db164b9d5c2023580cbc0fbbbe10ac6d915707e82553b3a7c02939ba5c0ba3ea0f001b447c0498eca6917bf60a2dc2c3405792eec52f9a79c0f63f9fe026beaf14217db6559389362691eb363f5e00579807fcc0b02eea07934db9b725fc5a6b7c23d2dfe48680455caa5af203178126bee22681afd01c5a8dffed5b493a0fe28541ef10543f876c3e238f7f6a693d93849913564e6fb6a50cb1cdb8693fbbd7d772075d86fc5b846e42f4192c7dcf0f42fe87b20f7b6f5e0249ed00b92b270ebe76e24d4aaa66084249680e1238082aa532eda9efa01517185af981a5c69f2ebe8f8af08d6ba44ecf7dccd58bf20378feed8465448f7abd923c0430b6c95406e1da3f429367beb3f010b4e2f10c80b1104dc343d7de2e3c8006c21ffde51158dea7ec92abd64687c1b56f3f31c5a79bd2889cf8f28a8755c31873dfcc3c094b299f138b8b3cd1d2e3f7504f75ee577adcc4a748f752d32a813c52b5d48a738909afbbc01c9f071a4af8e2eb0f3e178590856a83bc17dc1034a593af0f1b4e8798bfe2488ad83d764baf9e70e0f065731aea5316803ff5012396ebdf0153c9b0fe4c921350bc9d822e6f6184d85d72882a2d740a3ca40ea433dc687bdcfd133328b6500ca833e1ddec88a4434bbea14388c16bbe1763ec95e86b4ace27f6fb333234a7683536d3cb106885c07f0c91ac142cd68ae8f248289734017de9361285392fd6ebadab15ffc1f5b5ee5eb66af05472d4894372a09419986183ae29af9c4c46c89ae4cbb37db360c69f53afa13a0a258fc7df008bb115ca4ca682615b76838c642281440affca1218c068be1a67a8080fa0f2f6fab4ba20c5eae3e5cefd831599eab2b0fe9d52c3ffc52387e6b66651d8b47735b0dbc5b557aca4b4d6163f422d8df39a42d39bf162d98c5bca3e7fd4e6abe1e99821c88b0a5dd90897685654bc2c0a95beba5e9036064f95e5a37d75924c9375a61a147b9a061d4c02deb96adbb9f14a5256e805f6a52d1cacb5256ddfc1a7610f72bee27e63cfbb38c30d9caa1c1aeaa7432b5170cf0aa36e2a406ff8624b778e14c2c4addb2552a31abaa5a1bf4f32b3d9ec51ae32a8099d10d56bd536650394acfeb57a9c02ae08d2b8a7d23aba0f9f35c15510a722a15f046e58b604d96b0f81902eb4b6bb4d58a0aabc77ebb74c13acbca308f9c4b36e71ede7e9e920cd92b1524a24f2e85a9a4c74d6e3566fc9bd7ed8a1f5fa60ebacf0341c556ea4f3aa612365c31ce408f191f03b5e9b203cba76b8287c73412bc120441e6c04a28663e5f61b6a8996a69e6699673fa35ae2d1a4f88e1274a583cea1dd34fff360a34106bca0888b20289d21a512320b24d903c44a00cce4cdd40fe2aafefb1e299257ecba8439a967888b9ee4c81058121fc8d186813947568124c62bb198192e4560e39b22bea132108745416713d10f5890ab7a6844138f5085f39ac98621cf973c8b661ac0bbb69742a25562ec2ba7f15e51ad1f51ef944729ec9f545c310d5dcd642391cb4c57a20c8777917b8fb9e4d432158f222ce86df8973934af3cb3a5a408e87954d771686804b6ef47c3737816403a27155ec9b7a55a8ceacfc338fa25fd5a73a1313c1bd577a217c69cb2af0f1a5ac6b780237d57ac20df625c74f90d4c914aa8bdeaa99998447fb46e4fdcab279ff331a56cc8c6accf81031c810364d6eda58e3a75a7b51d443304fcad926646d447a4d92ef94a8d06945f772e8ebd69c362ddf5886586355ac2bc041260ef41eca233815e50a66a54cce9d4720d9e30134945346926d4f174da076349421bd9e96a05845978c0b8a8d00786230faedbce169a58fb089f1d4d9839b26bd852f945b02858e59fe947216ac00332a44d1643bec6fce9bf6ba63f9e73a89a67141f9d6256f43734c59c0786f59bb321d2ef448e3477617cab081f13dc0eb93b7c96777c854ae5da0dea0a38eab91971e2d84db8d385e57b9af1688b3e5cee60d923b74a5a82dd18765d1e07d1ea5f80a82861a1c60b08c2818ea28898485833306213ee3cb4442c15cb4bbe209a8f165a424577b040c41e9c3f362b52eb3b532051038f98a602e41887dfa902afd43d1563450b1e74dbb3b8c7c8a097d5de2f5946cdc1d17bfe0d5c8feef9c308284cf80be37a4af2e27b714741d6fe1d39fdebd24ceb7d1567976f89788cacccfe48b203fc48ea0cc241902b753fd35eb4354b65e8ba12b495f4d0cd3e2bcad2ad6e91a9a99cb965511fd3f3ac3b95a69fdc57fbd97a84be1ac3bc2693737e01eb2c8c4c2f91681b9b98528b0d376737d356851ef864b8a82b9932adcb3e8e2ab6700fa8b1ed7235b422466b727d2a314175a3224d4fb65e8a0ab937e55685816ca40e067e4bea8288afd77123fe1ae6642f566f70f8b1285979989f8599b7fbc886184a8544901e051dce6b87f8f97cf36e791c5a4c35dde05d20b4b19dd988b024e30f2710e77b3543dd9dc3da34b8b6d2d0746009904b627419f9dae8c9ea0d4cc08f3249b4dae222f94b120e0eff159da29d6fe355a5a2ff4559b7c3834ec2078308d7146ace6988ca0fff6b9936c521956dca6ea4d4ff67dca59e137cf711f33fbbe9aae8d81359416d4a1b978b5e341e85dce83090573107a0b41dc42f6d54358ff1e7b9452141786b5f4a0318f7c4e65b301383999125430065a0d0e6f14245264d51c5798d1ad95234ed01d96cca8e862ed8890413b260468e552e5c79f3a4b336bd18381b55c6a4c1240d460c76c66343082550324f429942a766c7e3648d206ee334cac41afaa3e65c1813c857a7184dbf08b0fdcc015e7aa488d4170c63ec025004e74fb08009c58f0697c377002b9fe96561bc68609d763b541c9f9ced82364b7fab611aa7859aa9752a00a3507bd1c0c1a0d1fbd8d2ebe7acddd03036dcda1500a013b5be6138f15691b96ecdf2968fcc3c9fef6a22fe8448faf1aadf15cc489b091e22400b769647980a29a48822b4deffb2d952f6b5eea062534d7309863340500c312ad505815317bb976b465174bd9c0bfd092e48205816ab8aafe34ae192ac6c8b7104009db05ff50f56f11c159721df017c20a86ffc266ab8605b32c6b3a8a494a5906cb47d66ab856c29c3a257b0d2a7f2fb6eb789f00188b8cede55fb44ad189b402a3759415931084eb34b0dcbf6503d0026083b4b28c1af4ab1823799acb1eadc5a04599784d685797d570a7be4d3037dfed542674b07825caa104a994c03003d826387205e616dd6a2f6bb5f89e9cf31c4205d2010d5e4ed56232880c13ffb31e8689d6cc5558d294eb5980ad3655117a95eddc7fbec7c4049f36895faa0be4c43833c76ce852ca387b9a0eb6dbace9c1393f47c680b9a8ba14c5645b471bb70e3c9b6e33f9845acab7f16279e6edecd9e68f072eb1a0370d46956da19761983f72c8481d62e32775fb1e5dadcb5c423893648838176d048cf6ff5ce3a5df113a10ca7ecbdf600516a3acd66969ff160e42faa192f641c3ec29d0950691d77c98ab92a5ca1403bbedf50fd23c78125c413be12ec5f09613e6bc71e6fd1aef2fa48ba750942ef603a85535c32a59373fa93c8e32d0c5acfcfd1490ae647b546bd8ec96bc03664c68a8659b74b43374d046bb19bdd4b0f2dc4e22fa6338b2a94a53158bca91719936ca3290f3f06033ec3b240cab1d3c27263c0127e98fc35ffd7ec0a0284cb2fd5746604b749c5765dafa607b0f9254fc57706513af645778d2c38b69e6c1cd06f521d1d5df8a1994592b56eb298cb3ae4017e14c19ec873aefb46117024038b81e7b7bc6d3887f134d9c7988fc20c803e2cd8770d5a11c93c17d04a70f1eda600b073e52df54b1af48e6bf7942202257b8e8161d203cf97f42f7cb78297b8ce4c58024fe8edf3f2ebeaf51fee529489079efc5866ef8ccae6b727a3e386c5c07e31544753bf35bbecffcb822da72fd9c0ae72d371aeb487260c1a79a702ad07c184fb12f8c1d2b824bf5be0f9b7fa7b503246d317e767ac91b3dc4fce102ccef703401a29f9a8ba287cb0b05a7874cbd4c54ed41ea786ebe9297c2b5c1d18eca23551f25da20030681222e96b2a93a552cee7fe972d2105d97758d0d2bb0e58e0f29516ed97cb4a5c4b75e06c7775ada7d6061223ee134b014653f76408e07f5b69e0458928e56f58f7200c6ef5da25554911740bacc75ed5b8064bfb4c899e29a7a6af4583a4783d04919f314d9891fba406a43dc60989c48ed82bf0998c8e366ef2a5797003435209fa64fb0ea31ce1a3e6501d3570d7e73087441b9655cd915cf7d391fae9ef7f80d2bcb6382be28bb5afd42258a3db9f9992b9540b7e64f820162b3956d7ed0f9744c2b3a3931723decd0c776f6e46ca4b7389fc64d39fc060caf5d4ae5795a6506140c2844e53985151cab439da4d9c90eb586230b147c3b7a031c3ae0c459441f7ba7fb5860a856f90187ab2b9bfcaafcd697870e03c08d23ed92f84d338c77fabc35885365eba1872a707256945f80143c8d476ff24174830d958331fcea75c990917bad425952772b45e546a01f9ecff29ba76478bb74d896892e9041e4c0fb1d44064a4edda296d5c952328a44c8d4d68e7e55632d4c431e8ca6f4e25b0de82dfa5758850036589b6f94c17dcf3f2e1e33c60e3793d43c46a989718227e2b85a9df20fbd06f2a91531930bdea59f8869cc12260a7af99f03cebadac3562900108920838964e201e702e120a27c84b40dadad6dd396a6e288d8ba626a3309e9bdf13d35940e0fd882a077200adb1902299c83c354e47f7f7f942eb46f286333b9b7e35d6522662f0394e7372503481c71fecc71c07e20fc2c8e59d4fd75e68c322297c9cf7f5c1a2d236fb2ed2098f8ea2477141fa0d9dc46b37f59b0ee1a2860afb44d0d410bee6fec2ad62a5365da0439ee1e5306aaed35aa7af006b103e8ba37ca9d31ab92fbfa63ff918c307caefe405cf847823dbbd10a4577ae11ba1426729751e62cf58260df5ab6b866d8145fd721255351307fd7422f4285d04e3a870728f2803a5b924d7c2a11276685563828fa8a0ddc943bf8b951220480964958049d89f04aaf38726e4a0fd2f9a87aacc47a06111179a7420233153bc96ad7256b165c226a6b576094d8f25e49cc0c4c5e9850b83598c9ecaece40d2fd7ee63042e92c9ec99d7daf4b4ad29480ec3c99795d1b4b00fdb9cf05a7e1f313c50eaf066ccbeaeab4fe642c7b14acad53d3f55e713c6d951d5169eda1325357ae5eb03dbccc56bdfe5221651cdc9e91bcb6d4ec5935add36dba4f7b82f885d6a380ca3467fc96bbf22a7639523c42643cdff1e6e4d0d34ae477f2cfbd7cd8159b3c125ed6d7476e8ccb2132c7f8faa1306464d52f84ef9522e8047158d97f74e67ed8b1745c76dce26c2eec8e7184425ee476bc6452d8cf9b12e3d925e25ab2a14f29348b2942763c54d8dfa02ee06a9a898e32557cd4c2eefd2d960d9928ddae6b1bf94dce39cd8aefaf3952be837d0bab80292177dd34e61867a5e85974b98ccf62eeaeda11aa2399e78bebf1338573170300e87f7a09ca1220228bf7cbcfec8c9c44d77f6b0bea5ba1bfd9ada29131562ec4b23ac038550cde17f3d3977efbf3e973d89b2ad944737c52cbc2c68d30fe806a13c26b76103e182b00b3227956e70f46057623883f90bb20df7e6430afd09e8cbeafa05974a24318c5f68e8e2242d914b2d6ee8e6a24fa079e70e9741199839fbaa2f2921c9d06c548773e6bca2cc9538f0168b2dbc24d96886f807a978c30d4984964a99b51e0a5ec2d12d0113010492e71740c8ddc04df194827236273572872efcbf7851c4a5730b33c2667afe1f8f31a1ea43370438bb76e96c5c6fcafa71468ee3479fab21d24dc2cceb1fdf9ea38da014a5815bf5e837f3c60b53e51470e797f8e8fca1a27e5d082780e290ddbb07f195c4f20e47ffd00cb4be4d0cae9b3d891b8708a9131652a5aa5adf6931c2912978af5c605c2683568fd15d9e64e3379f295ad91929d2ff8b0008b088b5b285f38e8ee6102a54c24961c30f21196f729039d29df4ddadb9975c83c132c7e72a20aa3131e4ad84a2ed88621eda3fcb0cf560ac05228224d39cc6ce0d0c5190d2830e0d39d23bb3138b8b33685e840944c4764e9da232bc54cd8ebf3fab7fd89216565c06d428d15dc001419df1f26cb74e98cf8bdc88ad68d9d01e6e12d56f3c48796073dacff78b7b7c346e35afb731fd18194772989590714e110b80fe45e0cced015f9301c4323c89470418c7ba36ef6d13a809ca495d44518c5ff5e58321b7acbc3d9250a4d0786f4a817c047bbf2c3a155dd79efa7c8b734721234d44971b4483b06975ce2c5f5390b2614848ed57b45e50c5947ffbb400700eede7a54dbfa65091eedeb6dd39bc967147b1254718fd2df7453e88060acbe82cddff371a57df99d7a60b76208d922b755561cf23b99048b5ed4392228917747ceca7e20ecade451ecdda85b27c075bb03e4459e13618e68099ea66969d8616145fc5a056f9813172f8fa43e59b12664a2bab2554ea9f5c19696b4a76981257a92c9507df17f8efad2bab5e9e11d77a354e1566695c256d1b25e05566b643f878123621237f859e9efac70790dc56086c288852d030d2b4de97b74f2711369fcf371d98de184a011b879ec9bd1617548df0cd3eab2f15b348a120715e02344274b9167fa43ed914422432b051f12abe0d628013d514d813e31aed71e998c887a04ccdfe41de2a09f937941a102b1735cb7c23bc4d5fafdb447d77edd1cfd349891ab66f35fddf6bbdd56d20b459107644a2b257a6a7aec6cf814ed6b06c314ea8f84ae95ba14d4d36a5288658c2569d2c02b0bb3589efff41471a5885693a00d57db65f3d45cc0fc7efa7902aaacab591e98b228127a84b29ebe85d773d8d9810d5866d23e13896b54675321a1e1b15742f7580addb55db02d1cb48f919a1d69458c907a24d80269562cd8a5db6c935f72f08e4f44d42d94027a63f0507463e27a92bd31d1c511d4b7a1f6726a44d35f2acd94ab8195faf979d38d785768609ad22f6bd6f5dab81dbb3a60db12008222a60042a0243825aca5ebfc372627bdb065e154098075ed352195248bad0f55c29435a58d84b294dbbf46036127cb76d2bd61d292c7651e8a8cfe917587b3cacd04e8652cf0ca25db392b60f261b1a4a9bbc782cbff92a677a5e907da54317a987ee10b73f78876302eb9e1517163d493f60e96681f6d8ad7ea96f3700d5438a3d7be151741374aa700c0873b711d30e6cb893396f9195c5cfbd8a00b2c20010aad942751600eb1ea545b1497655c847ac9d390f4cc649973f38056c549d550ab64697146a22eeb19d7157ff1c63b28e18d17487e92732ce0d35f800f2c2e8b9909136a49a142fa43a4a7d0b1342dd949a6bdf7de016102610261023278454ae35ad48a660c2f88a6ca48c8857bf245176d76b5d819b66856a0c2ff4b98cba2997b6ad3a2c9b009654596525de3cf755ae1bcfdff0f21b574efd5c3ffddfbdf4d3199b24d96e2103336c64847d0d5f6cd74cd956300d0bcdb594a425bf144e19962d75627c3066374b7aab9bb6fbdd0a0b7cadd6b8fe8da7603939c174ee50c8c3db25c1a4ea1c2ba37f6d385373632715b982e383a5a4f27aee752f8441a1e0045332d714271e16a9f5119644810735a3d63654c9570879977efa01c02c9f519b80c2a5dda3454f4a8b2a2bb77992e0aa05121400c8662ecbd37ca95cc0177a05ceb215c90e50b1cca757befcd9d39e07a6fe1da0276dc9845d4de7b8f1d9788265264c8426fb6f5fd10b5c168765b4dd063e2812ebefeff0d51bb83a542462a061bfaf98f86640ed8e9c6232887149f12f0a5f83ffdff27e2ba91c83b74ba31c2abfb111341e644517c2ccd176a1a2dab9b33a26d67ed49700b435ac81a9b235458727833c176c4a8f905c5313bfbffb932e11c974e22e174859921b59244a6da7c0a8e83564b4de268d1b118b7591b102f1bbddafb4423dbebd5efe2494a77f71967af63063aacd69f62a6e54bb04678884066aa80f0b230cc568ac248a62c732547c092a7e15cb68346322e65745a542a642832e54416ba5387ec6a3099b3c5ff7f64754393cede7befa59b9903aee7f9f3bcb2d285a590293249326542a5a68e0c6d7880a56be2c244337a9bc9841d7755da2704cac141f6de7bb9f7de7b0b37b5fa21c5d2432af2b9f7de59ad9170f6605b564fb8bb7bd27f2348bea9079505e166aa5b673d9aaa620a72a6a29e0235725c2a792b4e248d6d04d3e58723cf568ac5f992a5a7d3210f332ce9a888adc475516ce7ee4cb5145eb803578475d7b01a435d144bf6e173fd12013a9282fac462f99ce998e8115e05e8bac467a76112972c7b1b9adcddc3aa3c3a45df000e89c6a0d33129863c140c5e813e301e578ae71d029733d2518ef595062efd4ac0561c93eead4bc7f4020b56d6cb88a888c9dcbcf7de7b5310e504d7c29a418937af252a09b51a2b570aedebe8482937f7feff89dc7bf5fffffc55f8fffffbf694df0e3e06c464d598fbb4b1ce3d952865b87e51cc80e0cc9ae24cd062537ada9069312975ed583849c0359574b2c59f59c843246226f03548b566922efdffff1b8686e4de89d37b2d6f25e4b6b2f7de1d6e50b73520941bddd6104dce1e274e77f70e30f1b20a835495f04f162a880ee8838ddbe456e96b2a6b5a228494567626d04665bd5a60a5c68c4e6f691e0eeeb0e25a798bbe4163f8246714a85349c0908489fc887005b9b4b1d4dc889d29857d32e6c3cc757747bafb8c5474777777d8badd65f1f1d7f3f77abbbb1f650e185927650eb8b877af06feffbfbbbb6fd04ebd272fc60cb75ce5b985368004abeed17b252245fb8a98788640516d19bf9a33af40c069c9edeceeadd9643d9167ddc1abea2e8b52dcde249862b9f1dc1e122a02ba5f7c67a5ecefe7eebfdf36252e470a33d635e265d2b08bb2f25916c559b94db9c4a8975fb0cd6a6524020f4a2c09d885b2639b92b93962f6826d514c211b05652358dcdc8eb06031981c154e8d66454890adae8bb12ed89921b68ae8d5ac99a1b4d6ec2c0b52dad9eebd9adef252061a2a63a51dcfffbf87f7cabd579f056531b1284db91e56c853935330453b5c33c7b09f6888d512d1d405abf2a345cc90c422c98e60242d7223bce48d6082c6e4189fa63feaa187b9c01a137fab2f1bd5a04b77e14a72fb68d8430e090402b74e5587acdac48bc2eed7a5c77e68ef9f8b7fafbcb2d2aa01e846761f5d826c13b5cbd89984f7c294924a61e1ec5bde08154a9731249c207dfc690022230287a86ba9ec6045d75a0787fcbaa3cee4fd989c73034a4e0c776e8ca65cf30e29848651884eb9e126938943e113b5bddfd76b98640e58eac61a2a0e4eaa86249de07e20c587076f1187c420daad55b07afeff7f669b7730e5862d8e543827492eba2ae30a1c8a631941dcad7d82d9c4fcd8cd458ddfedbbca60f4560831cd97a710e40a170cdd33ae3c9c32ad14cf0874fcff8ffefeff933307dc26f62f1d82ebbde59fdfec43affebdf72693ca1c30d596189a0759db7fa0e1edeeeeffffff1b9f526fdf7befcd362373c0394021d88c363086b34afc51ad85b6425c212f07ade2976ceaffbfd7bd57bff09f05b8e45d7605dbd44e0a2a696e2e53d96cd6956f2a0376177495ffffa1b2c797bb81545c48cd0d717807f4d9acfdff13b50b74b8d128f1f12469aeaf4e4a65cc762a748f4bcfcc70caa336f7e4f8feffff1fb8516ef6de71d211a3b7bc32604262fb5476c71c52485fdbae7209302de706a2428016f4786dd8556ba72420c6c8f7ccf8e661f5441c338f1c8aff0f38b304062dd21f310c983417dba96754d91728ec7e031075e931dfd93ee07321895a0dd59903ae7f183dc36a70bbf7a6d990340428dca4ae20936b9b4e1dcd4e165457b70534e3f9e561ae4bca7155106c2750a49833a677e663e6982545f2b11580170e1131d0cf0ed7e8a4e849c513f5fa34f68343c322482763ee8f0eeb453f70e2b2eabaa9c114fdd0a8aa63cd2cac11bd72edc92a47fac2eed7a5e797c66537d0855223a76bdd5c772fdb40c96f9e504f95894f33048e73b6345561619973d2a68c15adc2c1549a3c52b59d39e09a867bf5ddfffb94f466247083902a41a4ed2dbcc84299587c19f474f3aa1148d9e4ac1da83bd2e28fc904b821d91c7d814076226853fba0c95ab7372a7c291d9aace26cb536a99e804279b5d5245d63ea99dc6df820240b67e2ac6e7d689421d5dd1d2eebeeee3e1fab7244d0e0beb4416975093707dc68bcaa943e7c7a48e893bde5abf94975178235f2ba46b1a25926792d576a923679d2783bce6eb25c16081ea2e114fab3748cc1920447dcd9dd3d28d90b520edddddddddddd6d68b2ec2fa8a18293a508cd9b56a305439897cb8f0817526d9a624897f88496f1cff3c643dd9f6c61e74ff8031fbd258a7b0f3d3e444c4ab840a2bc9c78583ce958a47a3468e45cb3dceeeeee5e348d9db551152356e36e97c5bdb554660ab65887eaa3e413cde686aa8cf4d944c8ff19509ebc723c509bb4320f5aa0b0ca29f960e98c4fc7e4d13409974ae5f556426778dd7deeee0e5cb2d04ee13f93532ea46a0515534c6eeb89b79b40886d2c3925825ea6a886e891019e90f33cb3107a7d557e8d1561cfd4ae8c46ec2598356d94841d13ef8e16f18baf195266461933b39cc126fac5b63001e6d695754687502920228118cd8d5a59af644f2b06e3eb5e25ffffffd92d1b2d69d8881b44faeabb8f9ddea6f0634c2039d276f609c006cdb3ab7e90884a8bdbd22e25618d7c6b1a048023e74c443a9babc6312d759d35d470578c5da8f40ff8443310d08e00a318080400c4401c09e34813cc071400040eb2909c8040302c442c281286c20020180c080ac000000010068341e140280c220745ee615d070d0ca45aeed304d6a2ca8b6926b4d36ee5721865d94b577cba5ada1efe02c85ce3288a7b59c7dec983e6d8038458efbd2a81d9bbc70d717d3ee2d17dd7d19a0a3d2a56dcedf4bef690fb77ecff7b944122dc3d3e2fdab19244208ba2f87369da6f50a230a607fd1f44dde52cf0ccdbbf6f3070f6204b189387cbf681b38bcdf629ea80f8c31aeb38e40bb95c2e3ac4600d00811f0e35762e05816673adb44e0a0cdb4591313b9610e22336d0db4f341a9c8f6c374e0d8b3f39193a068b292f115aa3b9054a51905b96981f2e4365c950e04fae7866db6869aede51568ac2322d54a74f25c7cc1ad94aa70ee18dec76dbcf3cfbf450ff8e32b13530fdba6454a1da5deaaa6fbbde72a9874caa80cb13cf45975d2db86c65a36604ff2795e7b558ba18c3a610d02b48c4170968a89baae10a9b063c583e5543eb4e26e5a8a0c04409a1e1184d2a4b65a895f54a8345d8112e1b3761daaf06f8ab44045fa147d6376c84576da35327abcffa2ea9ad9cb916bc4011a3c9cd17f051ebbf0089d207fcadc924f6ea510efb376d7040ebd5955ca63f118fbfc1191ec4f21169531aa0cec08930420350c4497dc933d7f0de254e04946a942049824699b32b36b3d96d9ec30813d9913d45b349b0e1f3d43db3c77e61b5d58176a6f2f831d1461f3fe6b35d42443d1189712153f40fefd37d3175c19cf01a0b2b699e075c0944690db7860ee59f94c69244989da3857ea3568a48c5537c36478ae6ac14e9f038b4a5aa94a0cd060ab97950b50996b5ab613b57217ba48863fca4e32b39318601e98b29ecb4d34cdfdf24cecb0945ec25c2372043627b53bfd0db58f56d5339126b9858d8c08abda9a77722d78b1c10d50d21d849bb20e05ccece3d28129632e8471c0675975f2ef4dfb810fde6152eaae16ea4c8ebfa42a9fb7ef87e58a268dce9e3dd91c180a3763ceed2def19354ba37c42f9e4a681dd132049390846fb3c50b0235ef219e882b39941e78ed16c5aaea5262bb8f091b865963b75ef6967c3990c1a7c58a665790e132ad267e6b24d56eafaa5e9433ed1ee2cd3efb266a2f61630c94561e5c1bd6231acf0d93ce85c44242a00b41181afe48871d265d79e190f2f4619eecfe76d1a2ad5c6c6f134ac271ef45a26d7783c2f5db4085cb7c1ec0b1e9ac9f0883b45deaf0b711e2452ea5368ba911b25a580976071fe4ff72a6f991e5c11c7df7b9b5f9a31ede42d62aaf6c3f3b51bce751c7542b93d8441c38edd89abd370fbb61eb72321c17b60cb9b92c59eba65e5a1871027db0aebad830b5a498de1775138e0b563860812601e36e4a90b82a9c5a35616710755f28e6cfbf15dd6cda87039cf6095fc070a85390e2243894bba147fd6cfb9c6287952ad7c37d8291b782f24201344c52e0ec0c9c682edf2e8af99ba2252b63f2031f3bc56a8256ce7ccc5f482fe00c9ad987c33ac3eadd9c04218dc7377d4272f7fa1e2270de0e75c3e2ef8991e1ec9e649f6513e9cfebb680e99ec7f447b7ad47242d4819e9bde405922d90ad788e66b7b1f2a51cb4c991a4ec8c3483a9121d104cddb5b84d28263e5ce1bbb3b4f3c2efa879a33e1b8c8370d4e2bd381bae7b7028341fb7d2824360e2dfebf1eb9831a5630d7cab4b09be7d0b531d33907ab625dfcb8aa2f0d5f109ce3631b26e8e0d434c3aa3f0cf6868727f70e7d53fcc21383462cc6d2aef2037c6274d20fdb6ed1c5a48f67f5e445d5273f99475ef12afa4fdfde3a10f7a54b39eb63fe77a4e3dced42c979c744f703f7dfd3be7a01aba782623925cf0601e9d7fd0fb9aed9d0abb02cc5ad0073f2f00acb46298306e89dad930ab3ac59be8c67cf7bd0d1a677eaeddbfd2e8e4c806638407bf094d111016dd5ab1cf86a23a755eba03b1b6569893c308bb65081994c2341db9e61bcaaa5715ce14af4f57650f3b8ae8008098cf48185ebbc8aa89861a05ea8932109feed278e3c896e3ad8aa052f03004b52fe38a71ad66286de852acb2d014aad50a4b73bbc2a780bb455bb415f410d2a5297dcc654855b2db42ba1d3af9a0b8ef4c0b27289a118087cb12d1554edcc9003026d124485f1d24e4951b26a22d6b9c0fb3e778ae03c97075c543c9b5b156b68ce45e5ade585e72c7060ee3dbd640b70e676414e9cd07baf1614665895bbbad08828c563e6f68ecf6a0eb214d687a9a608f0327656971ea64c057edabaeff02aa25ed35e99ea0e8ed029cd6c54fe588576d7400975170499bb848c0a5e4053acdebdfe843023f94d8d133ee34cbf34760b5f9b385f47c005a28cab61d56f1c69e1ee84eb7839b7efd0186e5ffb3adb95d60b44a0b1f19997b97f196932ee0e8422569a740ffd98f249195d7d6fb9039b4b05062f7295dfe3b0705c962947f62d0c60aac5e3dcc7f3cdace496da115287014865c810c28e503ae98594f00ae28788211cde50813b834ec7bb12aca5585e6bec2f264c3087effcf0d1b8e6fb8db8c39b5a2abdfc67934fa39133a16ff3b1bdafe5810999b4d68b45ade46b72d905644ee61171aaf7df4fe6909d5e37e0db9944ecdd496afda1bb7cb26bd88a26043c509598064a422dc151f644583c291fa048641c75065b11139747dda2473c3a378de3d85eb28552861195c3daa1d08b763b762d447e12452d119bf532038079df1fb87594a018c57695215a4e2dcb519e7f989d3ba2c6a33c737f5d7276d41d9ac588523995fcf7beaafb4b51cc623e41988319defff66bd5a4a675f24eaf2602e8deabfed541379ca56ee3e6665866d13f8947755c23b935e52e9c6171c25926a453cd0162d87b66c99a5f1f9263c97a94ddc98783172afa933859264a925b593dbee32062491982416e5caec1c7eae1b6f8c0523e3ec433ca901abff2f4802e1a194f4f02007529a671cf2c9a07523e984e09ecad0078eb5d28dc5da378582242cd59bd2477fc1d1c6e2d5405320f7e668f59635c8a29e717eacd591f8d776bd46c36f36993f253d4bf4a1f5d0a921da07e0504e0c10209be1b596dcbc6401c0615cc18a596558d70e9c03d5b3bb76cbdf72960cb807761771eb8e69916b4c34bec8ac2c013240d517d413184282cf48753ca833d18fd8bbd15a11c7b256e8dbe8f06e9e3984e023228d2337ac19cf6557ddaf4fc72ef50dfd59fa544334b030c2479bad5de6ddf36a8d480c5742c5b2b1bc33d7aa2e80adf978041489aec2eb821ab9ebec98343cb254d6c08a256886a2d5073efe9d6939ae2584dae4c08b2980f5be102c2b2c1e4e834b2a103f8041da1073ffe5ea21341b82503bbc9da30d72ca3cbbf7bb7309c9ae3bc685b3ce9b5dadb372c119caf0918f6047bc190996da57b0e6f2bb92121663b994598790eb5572cae3329251f11a8e372c2947623db33fdd238803853e14c1c8bf9bf7ad3f3e852138b03fd43b0836e59ed68f0b76c37bc5726bd8462f20605681ebf260c501447d89aba12e0728631d5492c2c0a57c564ca626c9776208ab0b5a87d54ee2603ff0199092e1c3be0e05aac5bf457c3d710f612667aa4706bbcac54e12b0adf41bf2c17e8425c0cc3f9337e25c772f957fd5a0889ec20e628812d932b47bc20a756ce96d7f5c1a532a6f45d2146d88b9ccacd64c0d741c2b4444290d12e164e1acfea9fd3b4b6317924f705637034e117df47f5d058cceb8671bd88d29154b4edc1a380ad56abacaea33b1d3f493bedafe67a3305c96fa699fda68435c286585ddb1c8a0581362a32a27f397d9f86c92824ba2fdbbff67ef9ae85009ae55f8a6249541828d4d45da32037f2c7281c001e80b935404781e70bd76f5414397374399174194a82fc9c6562564b5934742ea707671dd39c49080d8c1ba82727c5fc8f240340211034f16d14bca7f45138a15caa7735d6889586d3146890c2b0592480ef2dfd49eace22b9520cd942f6a816ea57cf6eab6290ce6ac91d4f90334c7dd08195081520ea77fc39cb7976d3814e6f8e2ad2a2fa8ef2c54a06a3f891e196c810b0ed6f11d9719eb1072d7abc30698a1d11c0ebc22d6d11d6741e2644ad05c224296ae5899c3e07be59780f4ce68c13a50e240b212a17b0f7a5baa48fc44e936f112295a36bd265968f7b64f48e008cb17b12ec7a7a6ef762be0ceb349f620cb8d79e632c14774e4f636a56d87e9d8ca084e87fbcb68807d1864e35c1eb00745291654eb0e214d1d1727d73bf7ca9c0f90826720824e76f0e6a597771d75b0bc8824bf51e49f639fd10155b26a18daf298666c169e29fb4cafa11631d3cd41d1145ef9723ffee0338b4f47cf0f44f716d375200b67e1f567d222e2709c7f3de272178ee22b60ae7fb711a663a40109960dfa47faa50a59b4903b9c19581a9f2141190d8f40495da44394147e5029a937617dadea3dc03d4662115f393e38173d2e8a0dd151842cb098939f1ab9647c54dfb007477c5f56b5d5e0ed616e6773d5b26bba1ff0fd6c1f1df0974939f13c509980355925580cc7609f98f3232b51b3d19c9685c5ab2ab26015673b3e76aacba37c86c98bdc9e1408d82ca1741ffb92747c27b356c46194c63f4a919a322b52422891f094221d7a9b8a72cfe7b3f4558162233133bee7274e34aac4c8faa867cbe30c9204437731ba53679acac02d8441de30e296994cd2ea0b5f1b476527e3bad1377c103ae6d323bde535ad53aff6649634ba5eb43c044ee914a801c28561730af15c3e991e0a3ad1abfcd108e02e46fb08ce4a118ed5ac9e1520d6747cf8fb6429033a166596f77278137cb66a5b3d4062ee9fc206dd5c5686e928475333356ea6aa86a9c4edf987c78282031943db8b997d7b518a98b0ed56e7e058d1eb846d1987f56d703f3ce4ace613b68dc0145724c011006df741018eb26d3a90e4256be98f876ced0235a25600fd8b4aa3c9fa19b483eb83662651adee001d345e69c6199874979ba9b8e3c12a200b355e0d8825fd6502ebf4c29f0ccaa6a9c5f6a27ac8bfb56436e13f14d9e8801ff3b751c19994eb0753499fa12490d27a3dc8b33b0fb8cb6e1905bf0a140b1b0fd4d62cd58ca2cb7b706eec4ad2bee14454502f46db72d403bc7d9012483f40d78eb3f6364686deef3faef8b8502deda960dce505f87fc8576fab64965c6b41a18622a2f4d0a14d85e221fc1c3c50c0fe334406e56545cc3341756a7be4c1e4ae326cccaf0ddccd599893591b88f841ee2bf5daab39a2412b1ea1a97dad2cc38611531063ae78dfc0b2f823a3f185f1e2a3c0f5e6e2c1155090d73b1105873d803badfb59677b554996c2f0bc1f443fc266a200715184fdb375313f077c5ab4c3b6ba4aab038c2691a3069b2eedaca20ff3d23e286d81b0f134a35d79f5c8c48348a3a57719366a0b237ed724842cc393f674f41a7add14d075951c1d17fabd91cb19c6b2e38d278af2f89f6b63d9ca4d23e15a8dec637e57f5347ee12c1512e0f1557e9ddc3d5a8876ee18120d76f1e8e3c7f1ef8d9a605ed24d02a272de2ae89988b8bb55a12b0a860614b2c1dbcc10b052c0f89d638c88e2278c517db0b05e7c4e8cff1ba0c226882f18598bba1dda5656e286f9d4e152deea4030a7ba3df174f20079493cdc636c458aa84f0cb34640aa41cd1cf39f9aa1a1f06356ed6077a009286102b8b48f46a32cf6ac68864c24aba18b2cba7e61aab172d81fe4c8ca5ee8ce26d2fbbc406e8034482a6b7cb1c4911e45cb5e8113d1728cb38c84fa2c5113244b090f7d56e245e2e4cc216b6c59dd1fc2c0ed89b82ca88ed8d14438c60445c003e238b47cd90ea0c1586498cdb787d1d0fab298b2beed5469cdca5198b93bddd36e479e7966a25c03f065387884e7fb699d3f64b167c2413f5f2730f595ae70f5ea33cb3e83ac97efe5c79e3229e29eb3ad9c111f91de4f4619ccb19213dd4fce36efd4f6c66a3c2616cbb90094cfa705fc96c4b458990ed1aba8af4578368386235899a98dc4d8c2954ea2d497c03f0e1b714c6d842c5643a49e39b1cae22133f6c4e89a38f679b313cef8627fb3c2999b3239ba07c7c3611d9c532f63271cd876c48cf0df6685480d570a5f978f5297d3485dbe2cecd3bab699e6d5db777e46a16cb612eac8fcc1046c422caca3a28553e26ca349cb52ba23b89527cc288f4e06e0231657887a1734a8f430ff9a126d4bc670fc6a1d4325d3222bff9cf029ba18a82db76b42e7b558e8460f5c1c437d2a1a9d287831901a3657e372ed681df847ad4840b47e2f98b23b6ca1a08f48cc0cd2634dd6caf5200c7b4bdf67de499289a96f0108b3293a5f97c394a597a1d59c793a5641f6929fd633b42b201cc1f29a877bb2479c483bb642a55d4a7ca6471338e976b32f1e8bf01001e85835146792c97349c93342c23e0d20aad0a038ded2015b1c2e264dbfd3b5300c9ef2915d87e1caa91b44150e3050439c3d2a19d4242f3db722f7af3a246945c93b4250a5c1d2aaf7a7d5805cd43e873e2a7371735c81fdbf481291e92b3e05d0aa7cbfca57690b35322fd17eb54c58afcab81b411c08d5ad057cd8350d3fe5ee1665f50df4e94073d273e369784d1734359f65be9829bf48d8f9dd9ffcaeb93f8e0833966922158ad741e52c13bf6b202e8db773f13511565fdffcbd9d97f016f87d8b623d0b47a1577f7f16291cf5993b20063d9957277411361a8bcd1d86e20930b1069bfe21016be478f0033e8e04a60ee4cb22e800f049ed078b0406d9d2aa1bbb1d075a556275d61f29c18b93cd98da9e6bf74276c96f8249072c55fbfb6e3af297493a8e36d0226a456e40b6acee6761c0d1eda24c73857dcb5d6dd09b39abf76e12c9414cb5f9bbcd9db12bce75128fd04411c462c801349075c5647339eb1ab30b5bfc3ae3595b3a3af97565d3c717cd7134550ac043016eeafdbc38885f7e2456b7df942bfe65c5d1b7aaecfd8ed19a1046c9e9ecf5cbe50fa74543b3508707b8a55f727f0847e6be9e27823f9b7103767e8e0720ebf67840fce2560008b80c6cd696962994ac076330de23052a75511efe1bf339b33474b93d492f3c94b59de27d438617653fc6d41829e70808aad7a32439019febe8f077191e38b31785f6fabc3e999e97028e0105a6b6f91337034c1df47f14f9c932ef0178d72c3e009556cf7c3d901c0a6ff67023972373718418e07330bcb7870fcc3c96d355795f8ee799a7607ce96ea7aaa3bce9321fccd1d0231ab259a8a9fdcb9072e86e29d6fe0c24d09f7b43d6543f87e4b2d9389d60075b0575ec30d9b5a13a3c78ed0666928439669b01f75a4a1bf7c116a75f8a266ba63139cd72e8d03bffb09ba44129f02ffdb38bb3e9a65d446b0ee6acf3e90d1d613f91d8fde09a7137eef7ead14a6c5887327c603f45c6b47d5dc50966efd7cb1825d8b3c96f46bc9bb8d907aaf9078798b44f5bc35c785da84e389c2afa262429e9b142582ec97038964ccf0268472e526e168179971479c110bd975bc64ccf126ad0c801ba9d6c1f79fb42693ae8103900bb048d188d53cb020037b813e4f13002355a98ff3e7b10b38496dd6268ed6121ab138d62e03e7a1707d5f9643b0fdb6066b4e090b01a95cd9365dfe55c9f77a55983be74a42fec61b7d21aced0e13f31cfa60244015ef5a4d371564056965843b0ef721cc06b0937269bfa5dddfd7738cdc7c7ca422716bdc12b08775668d13c52d1e4c193991e5f7b923fdd0f8ae8e04fe0a7a0ab5de7a0a2e5043148c6451c75c045b2bb5d88a628c42b6f2b8397eb81c8e486af0119d36eee1cc836466741b04de22e42e91c1c79b144f540c3aae95614751c99ac89cd66fb8dd224341af4a237eb34733ea8a087898069f832950d14817ce2019b1381dcf23c0cad45844b4f7be3438796deb015c5878eed36536f69542705263bef8dd9e02559b6ad65db1a1cffe154fc62b22792698aa39b7d4f62abe14d220fc19b7fc4cee3699aa1e101d93a49d3b4d8e7e4dc56cc91fab8e032dca73a09a616613b56215edb1b1a909f4f490c6a60467754366f97bd3722f3caa85d8349f2c8fc71730a3e6682a8ea46e3c33bc32532801f2cc9d18eb0ac41192eb22e47178e33ff75d7db3377f4adbc0cdd82f0100470f5daff73b04786e28b813328d5ab132344b4d003ee5df49828c7f6b88fd2f867851e4a3d4689690393a4882e785e6e562c8f5df0a3ccf52dd76c4d4f6257fb60092a4afad1231cc292e8f084abc90f725eb168e5019fa2a3f0fa20ef383a2d8b9741f081493792529fb6c38d63e4224ed4a3ca65e320bc5c18c44d14c1c404db275fbc55d95084bd8b67808c9901702cd2d3bc23540a2b311b0353d97716a10d9d085879270ca8fc359bb043a2c7831160c35dc09f56a656c8a2525f001b4ca9c759bc02d7f2b39956b2bef296cbfdd9ecc5bd94f47785725cfef1dfdb1c29b41a55d931c21f75997d35c297900dbcbe70fd2cd6f0f62f86cb666d76c4b55c4a418b9b6476a8e134841ee171179a9a19e59ab78b6eaae0ae89a9fa7c8c9dd5e87147f0cfbc51e88af4af929983b3c75f09ae282538f2f211b36eb571c98bd1345c7c28cd602bc2636d54226199ad599509bbba6a572c4bf2f57224a858f55a9215d3ef1bcb5fe25eed5d60d3cefd9153cdf7bde0e82e4cb01568bd9e0c00505c3161f9353aba75d97c3b7b2fc0ec251cbae66867664dc830fac61dc0e0734235e51783443842bb825fe1d61a795af92cc96b13dd2e2e9e9c20c7203b3ab3d4b8899b2290c5c561e017054dd88d5bf0157cce862f98bd4643783854d51be06c4cd4347c5da2c45f6d16f347bcfbff4a4fd674ccd5626c0c0b04d0ead4cabb43507077d7192207e7844758eca5f3ceb8b82d4ec07d30fa66ebe47c0d56ec1d1717b2fe6a7e7b95dd7ac36eb9097c0cd8631116da273b688b21f41fefd29f613953b453311ea97fced2c915f68ef182f4868cb16d2b8b0d566e49d41f941db6c5176a752a5635f70b8a608d2399d393954f93df632f4f9f03b68bed75cf972b3721686d04651f3f0116053fe08b880516fb129e9f79c209833251a401c7faab62758809564c0401027839add4f4447c31a934459904db885bec3c2c76d11ebd43a7245f7d979cde08b69577048bb5ca005184f14c1020a2804e2881015a30b08a9f5dd9572789abc9474545cdee87ba7951725bfa957c31f758a62769b7691ba9936020b7892fb112f453f0e4f50bf7f9180d24c317c726f5c32932176a499752fb5771774cd383849f8262c049e551d4324847eb68878be0accd87edd2afaff8743e4389c89db83f6320ca5b21155ed13c4e6d25828a20553199040e75b874de287414ece8c02ee7cbc7c5e54c3b46d66ee501a4b401ca0905395d408c519b0e8a205e38af5c17d68a17f6bb355aaad015f04ccdc19ce03bc4e11e7015705d4a37404795b8826461d300f8678233c84fed5b9a0e70c0588114fbbb4c623b2a31af02c8dd87e26a1b1902df0b14a18e64b73529654a524a19eb039d0328033c600da1a0a307ab8d53d49420ac1b8268d951a9c192a34241acc834c384648dcc18f960adb539f05e1fe4d0cb12d011e5c4eaa90a8f1254979d08542b84d9aa91c5a8698525b2058403135f950d4c587ea040162e476cc00295b59503017c8874c2097f2ea58880bd176234a71e3634b47489d206033acad4e881ca19a62c5158388acb859c9ce7b33bb7d6dadccea241626709b6a89cb1633123c9069c0e94d020eb2011910a56497a54f899c009905ca192eaa282561b210e82cf8e0b07873012cb07452d92d185b2ab376cac97df18decb8509b4ab327c6ace30e94961fd6068f570e64a8b8fcf2e864944c86e16257956e087f7d21a3fff327578f2f58632c1bcf0dc9a426806e511a164eba525c4745273347237ae5e61700ea7cb231401cb01801aa2260e3d0c96789ad24c2e61915251531154a6b904b21d8054374c21436fac7123bb1c22dec78f0670068959e4952500b3c9bdf776fdf3b8f7aa2952c5a2302526186bad4db2f6286beaec1028da63b646490f26c861c90a2b03266bcc70656101071e416e93cc0caffebcb7cb13c9a6f7e3ffbfcd111c367257b5dd2200deae8c18cbf55736fe47a5f48429d325c5c98a09571215ad204e5b9c87e640604bf06462e1377780cab38b002a04b2b0d2fc08e9116255250743d6128f141ecef070a5b05efe23bc4b6c684591aa31f81ee60670a2390f332505390c095ad343ef5e19916543072818a640f9a2e4304819a9408494102c87d7782f24c0a163071532415236f03285ca490f3c62bcb88f0138a9aaf227854b95b560e8eeffffdf92b05162fe3e60b275effdc9eebdf782f44ae85e25b938eebd37cb2cffc5c94ca25597a629a92524a8a1ca951380bc9063d32385cbc783b03460920ba706504d35784d807c59238124453f45607e80f2d1c4cbbede23440f0d275662b0e2ebf1e3c2e40a0e68aeca6479f282ff6437e14ec4eb7d3f52383f101c08e999485381cbdeee6564f260f7de7b350f5c4567800cf14133c34e8c160f21565a4c6451269c07d5d51c69010bf7de9bab3912efa07e9cd47b435a43a946d38dbd9103e84ad4161a32e820b343325a12c60894a22940840ee03baacc5b93d820c93fadae6691ae2808d680a317688fd4ff3f14100e18880a722f460407890756c10f7884e80945a68a7e7234d07019a3e45463cb162740565ca81cbe0b1ca85efdffffff236007dbe4baf75e211dcd91424138530f9a088153e8def0056373af8309b5aa6653ae2c9997d20cb3890a0910887651a60be50bd0ab53904cd9f9a48bc2c3feeb3093161c973d2589f9c1c29a3339a0352b44598145e920db75ed6ea8b2a4644483ebd8e0e8694696225351b0542c3d8039c150960e304b557c9e43e827fbff7f90cd64baf7de7b3ff3b93e4bff7fedb66b2fae4969b3bead0828bdb6eec8366ddaccf05a71440bfd220a753bf50174daf6706729f59882adba766cfb0ba4e47982b3903109606a9bd55fd034d072a4c5041a6f09a4a9a831de96ff5dbf30bd228ddaaab619e57982efb7628cdf2981c26f975555c93728ab39535b9550a01e53847a4cc078623b09991e67db6b8eab085f7a7405603de21b3dd6eddaf5941d90300df042f6f60d487e4028666aab9a84ab6b2e4b9eac5e7d238e748fd20b8e8923ce395767aeda4e8c26a44b8902535bcd0fb07be6248aaa5fb50c6c80daaa154b38e1439e5a45bdb513e61e6595f842f6b66b1fd102b7a9c6ed9b696fa04155306c45c34ae9dedfbdd7ef5da2d65ac942aba7e58b6951e178121959be78f945916187930bdc30e3888da62527132019724477f49aae4ce065079a22412d4c09f3442a089519178e3c09fa32e4d55a6b6d0fa61ebcbc46aee05599786a33a60368764678d63851218a48d5db19698a72438d23fdff67650de5185680c8f4c02a23464d56578c042e63ae5c18e25b410537c2429d3c3d2a73fc9b52bf8f4ea3c15c929249d92591bd2530314e15e4f7de9bab39f2de7b63cfa493533a6bdb1879ba8002f5663f9e484961e0c4c3a49a4d14ca15ce6ba88b88872847a4230a221222da610140a705a635c7308de9faffffa71131117165fecb6a425522f960373fbe93611374b500ca784025be7f3032e9c198ad1f75ab1f38dc1d61b02331bb485e0f1629179058e9f1b510e573830811b8b4acf87e4192fc1cfdbfce7d9a58f840597baf452202a5c4347a187233e96a0485a12775d7c8ce02aaab415f85d8fc50fdf4183965d9a1378306d696aede0e183030a25d3f6c1753acbe0e97e5c3edd9ac57f253d273a2b404232652140d7269c17b9f5a7d911e2594442a25e60e3fd5f57f6d95ba7fcbf5faf11bbfff7f5ecd9118dc41873435e87260ac2e8e1d429c40c1150f128cc112e5e3bbff7048a727afe6acb5266270e10a0be1c17526c606dd0d8faeb5d65aa42aa42ba4ad2e9edcaf38a2fbc7f7de7b1d8bd644694ea1e0bd5ef8d629494c2094b02c6024840b11263d348ce9f2abb26404c74f942f2ec3ccc807abf7dedb7b0f7ad9efbd61133a15c25318326c928e0cb1e9e04a19ae2d696ee07066c5c53931385e4466fa5485e12ec7f3586badb559319e50b53af86662b207435bb0295914fd7fb863337739803b9d05a08e74e1d2b5e48a56d32f8635638238a541d202e144bd3aeb3520033a43831f5050a6c9488fa5200dfc7035b504074f39e7b1eaa8199f30d3ad6df558654a68341c666aa60a6905a766787cb227791477b36dd70f7b491d59268eb8db2d268e36d7a1dbb74d30e9d85f94f5c260f1d220cc7d3548633b0ed83017c17e3d5ff40a8c406dd5c50658f2d4321443830f97bed8b434e09a74c1964cab1e7dfbf42df14080fda223b1d3e768807ed3b76b920ee3d80defb5ed7b6fb494316c8f99b6d96e371c0e880a60e2a85d549d9928d270448ca58e02ee4b8f1a5b99d5ddd02bf10d2b0f90868f5ef19283d7af0f6cafb1166e5bfc764b634a0e5ecff0c08760fb4f496fa44431dffeb5f7be9e6fdf84706bea7f599d5fb3a2045f7bad9602489e5aee4aa7ef6caae719a15b439c82936d7596b247da7e2d5d3200ebbff7e268981e31a8c74c8be951db6eb812aa0e8e987138d9ed7663b3c5b40e693450ac9252c5b63b0ed856632951e0e9af9a9436d71e0321856ddda902c6e9ef6308b6e3305fd9bb01c2940297bded224ee1d227c3b3f7c6c2cd8a4afe74cc8ff7b79215eb9a53350fabf32e67e998cee9d3b530c4385f8cb338871987c3d196d0709869be3a65e2a7e5bff746be57aba0ffaff7fbbdf36b13ae49dbfdb6b09b76c99456a4ed75687b0542eb0e5a6f50ea03d5a9bc4abbc4dab5ab1e5fd4a4a4ca0bc51183e29869af6ab3edb1f26eb7dab5c7dc25625bb1e63288a1ded855bfd7249a444907ae49b069895c8deb8b55579d98be3ad764b59b9aac39af1b886bb8268332c6612d5f5d41517cfdf2c0be795fed25bcb635b9edbde28b5b88232d47b686b78c9970db2ede5ed47f788e6d2f66b9ec943f4bc72f6608f06145cc6c7bb5f1afff7d66f5ab8635c63a2fed235ebb7ed546bc7e692cd26a4ed5339ebffb8e03dcb76f019dea504debdc533bd52ea60092a996bbeaa947ec7060c48e8f1c90d4a6695524a182ce1e98433abd66f5acc190316d2d8bb4fbd22e8e99da68aec7bc67b4574dc6111f5d63cd01bf1f8ae0daba96bbbaeb162e5ad1a9ed451913402fc682ea1adbc13acf689386db358ded482d475a8e9e4a152841290210d0fd1a1c61bb96246cd7b202fb61c8184f6c0b636eaa2d95188fda828db3fda58373c7559cbf44893de240f86dc52c51548d018f698204530ac298c0012108d33731f15e18f529fc8281e108b89f308f10fec01fecf7fae1dffdd19668341c66772ca06bed557bd5b48a31e8f6aa46ce39e7e7fc185f7bedd33ca385be85c2070a1fded37249a1a8efe90bb98f2069cf1128ede9e3ef780a457b54076b1769d4e783563d12fd5d9b2ca9e40935deaddfd5f177bffbddd474e86ec1826041b0a05dc7dff9aacf8d20df769eb5c183439ce9e3170c74710bb38d768446c361f61b8f9aecb65b02a84e2c86058ac168f896801876f2a8f8600b4c93436aab2158bbb9c85666f796ad826dfb61f665b1b5369dccb1b097c5186f6bdfb65df47a02b73effff61e8e897f8fd02a0493a762a50e27e563df55bd1eaaaa96bea5574a901c89caa471cc3870c405e7d03f0e5fd1da3e04478ffb8090e330ee1ae2ff8929d8eb029186f061814d8d4cd440b13c69360a4f8c07821741377b37d187391625b6db56317315fe8037d36dbed769fa4c0c9411149b1c1e94df08bc4b63ac8eba6c44998a0a26388840f0c48679452ea4e5f5f7d4559f32c2793edd136ab61524a84c32de936a94ae2d13eedaa6dd2119b645b3dda2712fb33189a36690af976d826855b56a86c8966eb9c502fa9f69a446b23dd54c64e06d29e14860c1aa482ca1a8c1a065dccdae76f28cc745b7156058097a71e6795e4c0dddf7f25b822faadc1f98a34d75507d4ae6d27a84e882bd2af6c7506684ecd738ae30b1c7d3da7760f61cf08ece9b24a05bdb7468bbd5802b5551de6c8aea71e65d54ede4e25d7b4cc71db08785bad42c232b63fdf5ac7985a5e5dc006dbe66c5bdbd6826d71b67d6dab2d9108ed8b893a1435288e1a268eb65908eda228e2a4cdb42c3eedab1fcaf6508416f269bb7ed1ab9f5eecf4695b4d633bb22a282a98209fb62ea47649951ce50f5632e0af8a64d78e65981f767d712651542dc391e709bfc77cf5ca926186ab595577415e5b6ddf7738066548f1756b4111f6d25fc2b6faf5bedaedc57eafb59a6a2ba2f07b67f9a463fd35ab69f55fe35a047bdd44d7606dae88d56a39fb75ae1b889037ae61a0e6728235b94262f1e2400c51d18171db454c7fc796d5f48543b01adb5ab63604cf3d5a4ff79c380eb3dbb6dc0550e2aaa6fa45a9dd7dce266e797048cd70c1019182a8048f37d596191904800023170000180804038241d190222749e93e1400093daa90b87c5038228f86e280300c0603c280601884410080410008831880a438c693ad01328aaf397620091664207f82c8ffb94c94ca28f2a22186b8faccc921abb45221e07f36c2b4ae35d6075e817f7cd1d7d5ed3462c30e02f432630371434ed80f71e138ad96722dc99a042cde33cfb032b8df92f685ea1dd8e62dc586836f38f0019b9bcd32db88e44f0e274d264f0d21baa0465e136f67efcb5b2a3a585f3c936e80d5fce88afb44f630c9e488b16f56ac8d6a7037952b640bbea520cb2d677917217ab1f4466f6fc1afbb66719be1519965bbf7aa6fdc1ee0660d8c2c632f97ebcd738946b4fc2bdacd00af9d069c1b36467cb8cc7b563768065360989ce863c19b78899c4cce121cbdf9c4c2f201ed318f087f59d4a61b795d1d1d98a5bccfd4f5d45d04d27dc75a8eb9f7e7ac433184f1a9405d29e22671a93d954c47ee3d7487c12561fa74c0c3b183b408f8db10cd64c56ad8d12ac0ffa52a30064f2bee7185992c4d6645f1f96b048d49f25bd79f47093bbc8932f0bd4ff42955c78e25d5e8ecec10187c5fe22f9f93810eb97201aa55732db3595ecfc6f5c530a0707c1a3fdf7c029c7509fabc611e09f721eb827ecf13102b362fd64985c89ffe03253bd4a8c3064d8c68c81748cf6bcbf3de041d29f779c7f39d35caf1fddd0bdcf625d77f1346f3541a4801d6cb098d212fc7af044b0cd7dfe6bf29f14226299654e33380e9da40743f09aeee05a31f884fb260e0c1703a4cb95db670a050997290410927a38b372aac51b29d2df8ea94daaf3429e68c5b99f496ca53baa8760dce0fb643abf0e80855765b850f43ba013fecc220939941594c7221cd500066b7f5811153f634c79e89a4a73d158da084072923c93eaf0dfe1b0508f90a6d65f10d7232dae76b90f6d3dd288c148863470f32a4810c255908d57669b4014efe425e08b03995304449fcacaacd1ebf3ce9f1635d4dd9035841a5450718d61dc0dee679baf7b18eec316b0944aee2c40c72a59b1e276098225f5fd13bfa26676bfd6df65536e7ddfe83f212a8c8e1b3fc1ea2afe5f4f79daa680e6b30a4401d1ce92300f12e2789e0e7869069633beb3aa9381300ad6f5df8faae2eed5e0256f53d138d67f156a4aa29d1d201fac7db55e5c61e8aae11048034e184f8bf174d3f4c72978969b47175bb9a32484a6a68f6f386041636ac748094e56be01077ff23008e62cf1095e22f52c5cf23f5c63811fc2460863128ce05a1bf80a11d9991fd0428b96d878f1cfbcae64e2eeb770b38033b7c5a57c3e61fb8024798589afb5342f8e1fc235e2b7f9608aef26e53eefc49823ef02690348ca1086f9e2fd48a34f2cce1d866d919b698d801c7fc180915d6eba48d1c623b8251c4951de9c198d4a4fe56dbe0526205427f384fdf44e430f6aa09afa84210a75771a59b7fbf398248240ca5af1c22f6f82fe391f1373dcf50d07fb84540480ea8b8dbf0508814fce04244a9726e6f5664d1132edd91c6272c22e5fe06249ac4746a7c1759a0b7afbadcd1fdd7fb2edb439e30ba1f3dfa80e38f6302e0f3fc4a284e37d9e663d1b28725cad04f9130b144f1563c9498a89b9c2ea81c088295d87199954a988b1dc718228b1cf5044c08428e09abe2d9a5fa9d48be79fa871c430052b268b41383f6c4a31edf76ce800aebb03635ab1c553ad6e35e05cba81a783ad25785a194a733182cd70b76aea02349e3a44e6d9a8ca03da5c80ee8b93bfabf45945d8bbf178461f5ed29644cbe16e1fbbd1da45a509e43992cb14c3cb6208db1059f657bc92c64b0762cc081b5912136885d1f7cf0eca27fb19498f6c7cb9eeab7f0a2f0f99c3c9b96afa3875202f7b7186e443592104dc565c52cba5a0a46f5678ade27f7df7e3608a2051b11f84db4fc74ea16d5228860fe7e63e0f78a06722b004e396441957ce8c41d71479347a710715018002e6c3e52cb15851666b40ec8d663e96ebd02995d54160aea95b415c9751c5e9a381ad742f5014e0037702404fc936a723aa8afe2f8901eaa085c147c8604ad090a228ee88f8ca5ba584ee9418766218dc0dc08e1ca08c285810074e0b528a3eda68820b94e4c3fdfae325973ba9d35890e39a734784399e2acf562822a37918cdd15bbbccccd229d53c22df6cb89597901e7ad88f9d89014dc12cddd35c2364675cf36a0376cba1a19f7f3d451a5a7cc1d9b19d059117f930ae6bed8168ac35d4dcc82c990d882a13ecec1ea30813310fda9f896d00c796827c8f6a8abbce87ad27abbef8415b035cd2d4dafdb47fa28661237ea13133512ab5528158143f2c98d192221fa797a1057c56ae27630585cebb9879c45efd051dc2226798619c0fb5183865ea14ab6b14493ae99c047be64380d4aa93b8d937edd347b49f35a52b29d792bd03aba71acde3f72d8aae259e6ad6802b9c652d488470afe027349fba9c8501b7d145ae0c8060c49a27f6f1e8e469813c9114a05dd5ef2b0f5e819a13bdf7b55cbd09df6de38d44d6b0e65deb1a4a0e4896370c3984bb294948e4c759343cd6721b059239ea8db752511495f6afef090cc6808b968af86e52f32592764e1ece95bef78a2901c2f8087f602a935e51deff865400af364b63ddb96c413cea3a1b0aed04199fe019b95770c407d546a19b37a77f9f892990abb6305a248631dc2aca362f2c1ab7da6090d4ad92eeaedc4fa2efdfa78f1d6f0714c3d7c6a3093758ab9eb66ec764f325993e0f9ac1272935f17fb0596f077b8495a9b69ef61ff877c9218321caae66e370ba96ea88c5bb1d37f41adae41172d190c8d43d743d0a06bac476aa64e89181ab9273d8bdcd7a29b963634e92ddfac13d2f53760f3939b8b70508dadd85b91c2fec4649e471afb7cd8b3231c98794985d6c0c56549b05d31be1111757d4fa778c7e65111720a3ef8f8fa1f6b94c0a62881977f86468a170233d7ed64229276ac57943301c9a89400a791b6a7b1a47e62339f52fc5ef4e7392c50e96af9f2ce54e2e08c7f73386b79cdbcdd41580a797a7221ea46bc3dc6f4c88ab94201d5e363141db5c57882ba095abdf86cfced2218300ad66af020034859221532c665c96a3a1e318e1b491af6a6d15ab43ea92311d3df857b614537553f9c38cbc517122f5945cca1b09816b72012e84489c8267f5347f5c9d25f9e93efbc0e1287f41be474497fac89341c26037655dec10bfd020e7b3d992c91c83a9828ab9c4139f8d4d23db3d44a4b669e3cc1e4c2347ed9c9834aca89f30f07dee019e5049a3bb80fb89746475f10076810ab7c914222a1fa1fc7ecd2c51fa224d8a7e922c4e0857f1f75dc553851ea8fd52912df3b5f853646320ec46907143d320f19b0693f0a24878f515c4f6db0064a5307d908154a97165af06dbb33739f060084f8070611628aaefacc11326cd62040c0311e2132c3cfc43f9888ea5321e01f62f36153afa6424558b831f824aef414b2338baca78c25ba12775ca0258092f7d4ac5e8d7046f98c7fcf8ca6e9dd6339ca97329ce13b8f0c57c54f913149392c07a6fca8a68dedf3275c601ff373f58ef970894cd718731b15cf7695380e2dcc6601d53b8d00fc166620e344efa1aee634efb72b85be6577a2d02745f58170ceeb96bc849647fae47f1bc71bbddc9c6e7432c0c40e24515d943d5a49519d13c879db8a9aa03b2760555830dffdefc5c09e859d9f77fb9a94003ab16fe52b10eb0b68b794279fe6178578489445d71b45fbc4143cc0466e9ba64e906d51cb0534a460f599a043b20986e5d6013355c6f96803510a41b7b23909befc076b68f9717a0e62d1fba28fae413fb963ebc7acf0bb208476d5b2a20ab671e7d14055f73b92da8bc0ff8c1dd2403a7bc17eae46381116b91aacdda11b7b457d4a5d5478337d4c42292642b0f3b60e7fff3c63375784b1b01102876831d9ef60e790baa1ed0428f35983aa4013507302d9918cbed8eec48c6de212e0ea621190385e0616529639548508b4d557753f8b8360f84e46b887f3e9cf9dc79126a4da56db92b521647ce8a5ef2ad93c2c56bd850a18bb1a4bed1e37c2ce4a7350facec3fb3f42dfbd9bcba98a3016de14fe91f8adae815d20b2d3335527e33ccb461d2f5fd269ed883a07760e0c55a97737aaecbf9a80ad7011768fc2bf9a94b9f5fe1eff408e0288463c22a71f5ebf7486b927d392fb14ef2b6d5cb3c48e78070199e4b5eb79bab1791090d7139884155624a5a1f51314b38e3813eb4a230c0382f0aa583dc720705b7b670b4f0038241c509cf94e46254041deb893f890947414600209902fa500b02c1fa82f4a37e471f17cc1def5d60897f4ae7f7b72c4a5de99ba90f6febab6bdeabf1389586144a85a515fcc1e8d4994d59457c6fba34beb541515b1f30f129fcab0ba482b2942a864c5fb101432851099b6072bb88370bd1bda82007214b4c04da8a2408ff33bfa49ae8ffeaadffb6261ddde4303ca44015745a819e2abefac1670e771d607bc0443449ba0603846df818e6e8e4e2621139344ae6950f78f674a0dc51e51ce70ebef4511045ebe0e08818b1cf0f2ed0f4af8c4bc468046ccc440e12843f2cce110ac9f39d6210dbe4367f91217a3f5ab4b29af76bdd114c558dc1cf807ddf70552f17b1458ea929f30aa187c21a6c7991bd0f01e316b03841f800980393197e090b6b966ca3bba3d06d6d6a8164f7a0fb739db04ddbaf3aae9060b445b9f1c108da25448872a6d5d31ea5bb424b0ae9f1a4247d5b93892b1d48740e55d87499c52092a5a13bc3ceb0697b319524a371b795763744be76b6694e075c96120a11b6028d0a068b41d2ac5429da64e47df90f5decac5e0c2d73ceb0986d5a30639e7e8fecc50acbaec856bbdf78156c1c728a82eb89a02b59e8617d1d3ddad0aa91e2fd0a2bdf0f69c6e8b66231a0a7e94174d17c90fe586a1b83b09cbb4fc7410a1c4a559dfede27279f37c8cf9b62182997069b3a030b2c6751e28bfa11d205866ccf9431bd3e893f5d13568f8f91d7447e94032e545db9a8df5f8b6c5bac85948eb4e84acd148f59c58b706fc6d9ea0b25368853eefdb242a81456e813ef93cf6ac76aed1a1193aeefb22823f4f67e82a14c7ceee637152cb30614bb9a36f52226f9033ce608b8d21a800c55926a29d8559ce59d3868f53f9827a01160a30a12fb7947ad05900741251366d18dd31bdd7e0370eca3f65e7c281292701a9ea1cbfa2aa593c6ca9c2795e0eb1146e7fed9535c52545280d2f349700efcf9f9480626ff9df067eef44ca44e28a9bb4435255fbb0678fe9fc1e80edd8ce83fd16446139469f60eb30c4966414cd1c954fddb228f724c1ab993ebccf00422f51f3cf383bd35fe5f3c0324d46b3766a94bde369c0c27c6227662fba5a84511528ff210e0886211dfe777f13a572c24414296978f893144e99c709425dbde890023865f78c02d9683e31526b6efb8b6268a0bd5d3ff042fba895cccf2b4297c32fe725dde910dd9ce4c40e8c78d47b957cb01f2097bc8e3432cf77e62c5f90864c1cb20ba7462d71392f751a9b651c21b3a38d33952236baf851ba88f16707d01a65eb50c6331e6f725194f3170b849eb67c70ae0246be27898362f9bd75bb7aa836fe2d2207a811e83d525be6bb04297644e18b383988e57bd06671d4c887a4a417e611a07204f67be7d7e221408001e2fdbbd802481b3509672c8e1735627694257f342424f833f822cab30d5d0ed2d600812921ab460ad107c57c1d5170053d27121f62423e5451171fb06bb14028e939f5cb8238b2fb03fb5a90f33c7dd406c309c95a450f3a8886df73ed49d2c8e4bc9598a2390054a2830fd4fbede8b9c6493b2ea082a81d41d2b41c96b25504d4a381813ebb623ccebd1041fb34b3799a34348f9696e65e26fc7265f0020ff15990c1f4936b5df656b4d1eb8c82dd111f9347c734c284c68a5f1816e1281ae6142ab2a0433cdd477bdff121181c11d4a902aad3624ed435ba805c98b8ce62f244a5f18f4cd8e39302759aae7f5084621f998a4f3b0323203d01b8b83811341b659e7046f40b496d077b61403a639ae8345f5c2b563d691a150fa3b8372a7afe658cc9ef8fe76a1ee1faaa65b350324606fb939e83be898cd22c2dd9f182d5c83a5023f763f94aa429b0185c535af19b06be46dc8ba93a7a0ffbac931768ce7273ca014b95266c643b42fa81ef81936990549d0b1280d243f95b570570e5105067f18f7c5761351b05f1b45288e7c807e10436a680fe665da6cc9d7c9255a327f0ca2fad39b36fbe7843d1f2d80f3a71543ddfe27dfa1291f6edd60746e18112df0e1ac1260c5da93b9ed2cfc67a47b5f17fe18e0adc8a62880906165d082e0639fec5ff69cf6b8a89eb11371852ff3cde3984acc9f0ff0ded7a281df6dc5dc73f0075c24cad4852ce8b7c44b99e4cc537a2f23589bd2b3653d105214ec010903d60e1f5df8e488e150f036157c58dc7510d6c5ddbafcd65a4741db1283e5c718e3144ff44789c8ec06a6ee293d2c88bfd6cff393cd1a105e40e8e495a0d7d6a8e561b3cd99173958833acc1b626797f81bbd83aa02e3aa19fe313e9bdf534d8c256feb02a3c80c3ce7477bcab7d5059d0cf283c703efb50f171d6a2c0f73b2e1ab0e18dcf694bffa52689e1706e8973852a165ed73cb4427f43cd76c5145287be94df3a2c08fdab864889064f42d6aea1f09d44adff70aab232418839415dca01d18eabfd7a3f108877b9e7bb02973b5991ef3a77410fa86a395289afeedc82ea779453747b5316f2d484f1a4e0200b03e2aa925b5fbf36fafb8db8b9375e1a5b863c3fe7f1109aea1022806d55e5455b041c69b1e5004940fdbbd57f6440ddebe8ecc3060a67f07e8e0f1da83979abe9810e6db6c980785e2a2b480abee610eb3a6610577dde4c5aff87f99953a99a6099fe584c2eb05cca058d42734eb4a0ef4f9e47a5c58179f1c3ce1342550f381941ad50ac12b8dd57ed4d3301c94f2fe085cf9ca03c903fe6515142134dea6740a74d788ee0e0322c86ae99780f55c3e430ad637210f0ec3c045dc5f5121b758cc8344620eb70c7e14d718c1c9032b9ab0a746b424ab814422a64b21c3556b5b8f5e98eae6a482b100d9e9b15b00e22c084a1a07bebb71ec2e3aa80ed8827b54f9d84d1fff19d0a38fb7cb8e892db4f78ff7344074755dd282b0c3433fa93014265f6c86c87215e6e574f717f92eaf513de41a1cf34991defa724c813df3c37a92235872cef766d7d19f30ef901d580b04e63175102ccc105d33fe434345436879eb2a67098cca443209875294482444062672d78ba5c8dbc515f400648ddcc7174eb36115b5fac25d91c1d1c530b163deafc5e8e80b6ef5d4bdb9f2f5132897b3a7f3829d339dd8dd7765d3a61a762486840648e530d893117e3e5afb721220b3007d6966b7c8d5966072bd2a2715e00f39052f41c9d48eb176766ea7fa52883b7d25507a65ab652d763624857916afdc6980acfedbe6ea8bb8c3537b8b87bd966f454659bb33ee31c221742e1eea303d281127693380c08ea0cd422e0613d634f881c83fdf025def8b6bc7d584305d0771c81d919ac971518aa59fec9799966f56a0832161988c67094f481f9f954b5f5e345f29c967520bdaeac58c9530280415c7ead61f2546d696d0af67a7e20c4e3371ad15de84743d7749e65010861ec3155b45bb770df901591c56bed4862dbe5d76ff4a08efabd4e1069b63ccf4f54f549586d86313cbbe1baf95bb2f35dec7dac356d5246fe4261e49f48291195b13d124c751b0c637d8a4923d5c9c0aa231c186e8a8c39a66881059a439dc1978698e53495dcf923f7b7b75ffd0efcb32dfa4780bc3e7720fb4cd0a3beedb1a3f120f5c5f8bdd7ca5377b7dc44db7dc3dd9a411917dccb976aa3b92f6dcc288f38a0fb02a20dd9eeef3b483b97ef0bc8d25597fbafc64d744a569a634db9b81dc081bb535862e80201cc4c1e5cb7555e91f71843fb83428311140cb87461531dc6bfeb3609a34a1236a9620c5414c398caf28475aa1d57c78d3684dd8105ebd9ac96f805ee403b3f26c4ba94a6f01f67a275ccd8ae4898ea2cccabe69a0ae5e495a10804dde43d8630e1342f5c38dd54b8d61059f9a7b6eefc77224e050db996eb53dfda6505fa383b09c9e7493861801aac120cabfe91042b053bf149ceaf37d853b6e58f5b38531aef3e7fc045cf78bc8d5d4f14d1243d37d78738bce0db85618b6c8a6a96dd4800752dc8abb6231202307821af9260036071c764e46d05faf59049224ccef2e20d4250a8b48f347bd2067298f8b8202075d80b37c6fb061fd1bf95caa60d7a53ccc4f9cdb445996cecb01f6e871a1bb138a3a2c386dce9e093adcada350562ccde0f31d5ac40fb541eda1f605e63efa97683650cb65a86ec6f32cb347ba5bf957605dedf0adc6882dc8ecbd158ba4e5541f39e9a49e1ca3c445f08ad9d9e35b9039f7c0714786f3fd0df24c8c221b470cb1d08a395aebc45c1de45e5b293fa7404eccc40ea11b193d692e5bb20ecbd6635d37a461056eaf71bc4c1f4c643d4ad5622509d5b39bf389d8d083d868ecfaa70f26c507a4fae027ebc48432fb0550f0b92a1d189bc6ada460033c66b07caa80d54e34cdd5d34d93a7e7e59c81088beb22378deeed8bb3299b3ff6a1dbb4ce8d3b6799e404f1abb791c0075da5c109a306edbe6c712b48c18a95db7fca39404e38ee4b2d7bcae4d400f88c4ac1eba96aa8796fd6cf22df08491d042711a032b65790298050a42881067d453407bcdff4810edcffef83c83268bdc9a72cda4f46f0b110e20d71f07f06ef64f1168ac700c278f9310b405054f7689e58d74a9dd32d274b4cb0565f2bd6bb27164d11fd9a451003865705ed2273034eaf8d85850728275ff92de70654baa0f30a4945180d26442aca004527b2ff7d86feb0c604ac816996364c454da6467debffe2cf417bdc68b8f8372972df4882e131a5a3b3fd115321af3e28e906053a655f8728f3d49d86c43d0fd1ad74e576dddecaa11d214881f5763a1e66a4e390006606b1bf7f983ec529d67e96356ac56a52cd57794638c711b1cbce65d2e9a151a1599a67e6e03ab0400fd2ff24021ae5a015fb89e70bf92229ddba87043784b53e229cf88b897e8c8cf01c5c56f6d71ccc9135f074dd035349a1ccc51b87d4eaa6cdc6a302336b0b7556bd44df6fbac509b371495f4fb671fdfe29925aacb62243619b45e4c58535949642592261dd8c3552f44d6c5f39f4b8ce03c83b72e90614cced29b0a9811dd6a62468c17eb3951d7ef2609f6b7ea590fbb55d553adc6009d2b905a5923fd192990df7afc4d4c2e3f6924fdf2a414e8bb4c54e76cd1cad86b0dfc3d515e38064fe67f132d40c0b6c51df2df819f8471b592412c0fc16a83012c037bb4229143177258528a297ff35bd72f0ed93910d0f92793a5796f25c9a9440b844dc17a1c2e9795868bf36760b6569ffdbfb86424f86e666b26918df0df129bf1573277a9041fd288106f5ceca00f90f414305dfb2bbff484bf788a2f1511e13cd05cbb8e530b093f7b56c581660fd8e8636b61b37ac97952e9ea318fd7712c76bdaf5b9d02dc75c0b690bac70791587d82aade91de5782ea8d03ca6a01b1a495ff62b3ede97becc5e80916bd9c37bd527743bac64ac2e2b5bacccfc8e1086807722efbbbf1e152cc7e0db00348557c1cce740f3bee8e072f3c6b86e69853c38bd008cf7bb4c7f9b2f75ed1bff79779094484a87c5c279062723334312d8a5940879cbe5a90803bc0ba5cd9349e6351f257268d77d0c541fd446583be874c162e7959a657b05ed630f0869c2acda7d0429e7a795c65b0f70492a9d563c7e38181fce6f33a7f811d5355a8e9605e9e9cbd0530c36dfdf90abdf8da5dcdf86d8ba52582d0d84eaabbf5768d7b16669eadab31a7d13ab1279580cf564b32804ab6d3b61c770510693360f3d6329ed282df407b076856dbe7086dd48bfb4f8728e47fcf21b219a0d06b32048df2f97d7ad8df7da0b969962eff51cb578c115e18a69fa4ef186b6c7a36d1f6b33568f5efe59dff06230dc582113f17deba752f2f398ea453026ec8a454a087126dc72bae4bfede56c940f66c8d83e1e030f069c494af47efb6e5e1ffd7503179cc9655707d100ada4c21fa3182f4bf57584ff02862d350a54a593870627924433eaa1b4e78372a454853bddc14863537d8d5b145ecfb4949fc7b944a163197393a963533bd6d510f6962e7e53481fb18b8979ba0fe1ddced0ca05ab2f05acdab0a3d76c53932505144b0d6034612d1c4c0a4642289f6f325f9c84647bbcbbca6aac76eadc28dcb9ba6cd8dab0d680abae56d5fd9761e4c6e546fe2357f9fda784c1fa513ff007319afc0bea97ef447e0e57b2ea2970f51d26015af89d7a1ebc3e6840aff92b54906de85f83f48435b23da256be2e804170d422de0a2d67850b7eed39096891621c667d05a270cff897452b970aee4e9acebd23eed85d32619338b2062664265bfc5320f116b14f68ccda4f2f4cd0bbfc1e2547d878ba741ec83016a5251b2159215e6491ac41beb36c2889aa52bdc57fde109df7e5840d2841a936ee9b3afa861edc9aff6c87e5295ce1cf062031bfa622a9fcc267e327bc88598b5e6a3d4e262a4c964eeb0b4c085b20fd8c89f0f92e4ce64aaeed3693ba11dc84192433ecf3547cc7f34bed5d2f2133cf5a710f9cee67f50ee4fff45af9c6e824b6a0983d9778d9a9878739a8cfff3e70f8b2105c14209c3f2be88548f55c6c9dbeb2697805378130efa511096b552b37470d1ef41fcdf56042529b721c2653f74b1462849769c14eb20fe400c8e39cddc79383ac8960c5302e0817a90248af05ad1bdec443f604725f0610b401dc316dd3a3aa39e8591d609dc25b39d25addbe3831f5b00297dd7d1664558020adb0b456fc1d6ac833956554305a5abf49e346af2185009587cf47dc41dba855194b96ee005c446a09432548252a29b1fab685cc4a0db2f5818f02f5696db3f68ae3d74a747e17790a7cbc97d32e89700079f488edd6e06e8a19997c80793cc7ff05b51f5907b3045fa1767c7df6f4a9dc3b23ee3b73854474c9b16b2965f42ea24b06ed9eb5d9de3efbfdcb6a44105e26bc5e7da9133e20d710940ad363658138c12ca8c5528e994ed2a4caa3cc156e544848aab42ea5681138266fde494ffdf166286541081f8672c32efafa144051127d71ad6261ba7e4234170c718ef42423585b1603eb046fc5b905c0e899eb0a3537542e50f429f6460324743fcad51eb1fa469bb8c160d3642c8324a393a15321e8ca767a12376c2109736d9e4e35ae5201d8b47a729495c0a52fdc4023e6e1d45390c1a6773ad726f7194e91ef18e03634c1af7d6e6c66425e3a32da2bf847060a4574deb30dcc0037eba8a7ac21cbdb2ff83e56810ea5522de44ea0e7f9f247fe424976643119f0c235a1998880d2f146dbdb8ab6ba3ceb8dbbedf12ec093a22ad98cfac21ae2b530d079db60799b2392169b6a0ad2214f1b0797803363f172a1e53209165163ac5efebc95be47009268d7e2074ef2dcdb9148a7d9f0a0623babe77c8cf940315efa7b7b8b6585d62b1b8d9ca26547b263347ad980d6e3172de7b82fbadf471eda74c347991cd7c16262522d2499d29ff9a60cdc7cfa8f8fd3abe6c2aeb9edfad46c245fc7c527b1fc51da4ac219674c61ef1d95b21ecca8e483cb59f7f066629bdedf2b4c2e6802338872b896dc25438281435bb54800b8a9a46512699b59cc1bcf52f25992fea43c387a47f8e7e862d1895bd0c55d8f213ed5ce9a0607df7f5d2fb4b94122b0263a4ac6a763a84568ce550c9c6adb2aae8bc56ec9bf12a30f0dd9c4b386e150463c7011a183a1e8d3cf528484d5218b89ac08641af049e723651330a46ea6f6b923eacba3d4b4d6f25c6eb32a0ca45eb49ecf318e3657fb8ea65336af723c9bb7b107598c10de2de30a6af0a069710a20e96bc7daf45f2c857ff02784ce6fe249c76998e31269cf748c09b57e87346ce96427c0a82c53004368fa61a84352bfe59a5a77aed67f8de841177b533090be0752fc6b7419a86d1216a22b4b882881677549794bb562de056c3d7bea3589f8462421e15fae46c2da7e8dccb19199f8802a7004a161d1e715f94b8d5ef023009c5928ccf9f82b9a3830dd8929eb85126de4d6d0dcb5594ab1f329eb674ac7d5e2af4e6f3ba179fc4d3080644f9461ac2e48b4eaec28ea752c348bbcc704a54bae61f175ab56452bd78d166ded98b506352e71da23dbc15a5ca4a71b6e0c7c691c28e5434be6c77157ace465b403dc019fb628e33fc3c36a45a0f03b640222b34bca82654890cd6a54028b8b0aa8f1abd612a4afaa5d25a40b4beb86422186df25826c5bf0bb10add2982a45caebc886bd3e4fb3679e2436cf20475d60f14c2dc410e8c0d66b9c0f4c5de74d5c376f8e4fbcf50a57c4ea47f95f4ea0825f8ae8d3770d223f89e1c645d3bad92c3cbaa312ac295d87e54dd0192e55bffd417bca0c3161af5d14418970bae597097a7a6ddcf8ec482c2b67cd25c35ed7e2b1cbd8bd5965367c154b74ee3222f77b7d60d04948acf772f1c37e6df968a67edc617067a2ccb2d7d4069a586e1119b78ac7388acf088bd25788748d199963e704dc8f14e179446be97f7b959721981d93c86f663acf9c5301b16ad54a13b8fb548ec39308020ab1171e421094cd6c54378472b16b0c0b007b0d6f5d346d8fbaa3a931231c6ae07e6e810e595425d232420aad3184c3523fa2365d91968104350d823a4e4a2d855fc204f7cd8a9ac5283be583815588e4e2f55484f6b6bf1f4578f5721b64bb572cebeb04fcdf2e2c4872cb535e2bd55c7d1f97aff3e7652d0803b99449371aff5abf55ad75ee6d2be9dbb062c926c148b168befa8d8ad195157e8b54a6082a3800346eac612e7e49b204b45fa45715f5aafd8f2a34f596398185bce5f998ddb74d1889e351e66de7b52d7d65620d8081c727bda68a0014c34880776ebe917fb7e4fb83d0f44fb3ec0a5910ff352df034ace49dccb53e83ce3e13e636b81e07c41adc5b633f4f64a14680804fc996c0248077b2cd0d05719c9758999aaecfbd95e8b095c239ac0b92e9a4c193bc386840d2b9f626c9a53999a802cc47bfca004867b6dcbfec9b599e26d3e99494551caf9c9d75f46c98d7024b7954eba28bdb9850bca53533dc42741c09f20cc1e2156884f72798e2a72d8ca65ffbfeccf909ae45dd42a74ca7709c0cad3752d8c9caf8c535241984db1e2063d92f9cdbfb681d6830051dd48a7344a57efa028823a98183abd846fb77398cda67900e01b944f05cd511fbc4a015abe8038b62f00e3ec057bb24499d5c7af69f845cb0ac997f4e259fdba66981c3d07df33ae9fad4a2099aaa7dc98193a962388ceb925d62247ef7a954fbd26ce5391b1a80f3d0416d76c5023336ab47479f6a1d117104f0de5f073c116c26102eb895b94448048fd625c516e0be75934924be1b04b3f56122ba47cd518840dc20095b55b623f22114dafebe2ceb523e023b638af0ea6789957f0e7d6ab3574eba68cdecf0bcca22060c20a6851c6fe86dfdf782377755f6ef285bba84e517d7fae02fc7189aa1cca4c6626280351e13a4cf49b75ac9f6ca9a38640a8d8706e6b016c9e9cf571ba54908e4bb52bc459caa9b408df125d2b14ae176584f80c08c7e805cdceebaa55cb265894b9a7d8c0d818d44ecc37191e0ea2e658ecf20310b58c659c72e4b09c26cd8726f4da983ffc913360b9417bb387e928f3c3a0c21572bcfcdd11f05e6bdd81753c38b672c93de6788e0cd9eead776730d09ba4c234db2c3ca0997b973b53d8c97baaa06279b611397b6274e2023426cca5fbb513918992543903e570ce2722e15946ee5f424470b3841b7bcde0767736f6e44337523960dc4c5d9fe4e4c01f8a1dbc5603c30156fb7e0ca1be04cbe183030dcf158da9b668ebc1a6157ff17e380e27d8b370d1279a58043dc9da1c20be56add5e4294f399179f98485e76cf3da29c1074a4361eabcbf732deea27d93a229825c8bafd183cde12fe055f5de88a869f2679c4ad4d1fc3d8c4cb6c88852e9d53bc8ff19393585826fb6c399bb99121cca9abffeea7fd54084351c0a301fa1471c16fc6beb3104a3ee61e11d345aeb42822f004a97412b9db0581e57abe5a7fc33ab469448b6b5670e4389cd4010349555659d41ba9044382f8930e390619af26b42c3d3b5b09bd384186ae104802c3f1220529e79d2009a0de158349bd589dfa5ce390fc59d3b338a52778991b6b7ab6eb38e1867ca6d8ee75b55bf7c36067e5478bc0406ddd1eec63f6ad18e2017c1473a414833dd8292ef8d0361555ffc02902c64f12e4c5bc1fab3d60921a2bdc1328ad279e9161e29b28e61850192ae1328d077c28fbcba10ead32f298ecc373d72b01d58dd2e311d199da0deb58a13a4ba030adeea8556505ad5a4399e04e87e448152e7aa7a3848b0089182a854558b806ce508a24e94086935f219ffa6c1808d32e6158aa3a8a6075d40fa6f17086fdc31678cb07f60d6e177433236f4f6ffbfb5b675a326d444444812d902dd0804081308fd9c7bae3131b88831d61e62ede9ee561b0b8ddd880cc4da64b9d618638c09811d7c7313011020213a1fd6dbbe555b3010e37b188831d7b71880651f00c8b28ff99e880a51597e0b7683ff1c00c439b62836aa3296b0a26807ad1d16ec2d6aadb5f6f0931731bbf7de9bacd6b268ac06bf2258c239e75a6bd79a6bac190fde7b7bce3dc7746837d6302b7c546fe41f1a47b546d7b84e11a69d0f33d68db6b56037f893d59e8369cb0c8b18364ad1dfa5477fd1bb2b82156b33f319df45553cd18c198b6028623baa97551bbdb5d680d8e87df5886a2c5bc177ce3dc4982d3ec33bd71b29b134a6582e3c3d7c06c800961160b95e77f9e818fc952ed9a774c528f2901e2d47d10df728c2b3107cac0cc46cc646f761860a57f4ea04167bf41e8c0cb359364638e25fbdd7b52ccb67218e57c4f5bef3e5c3caeffc57431c11c1ea37b643a47e2dfafbea4a0be163f4433cbc14fd20155962da7cbaebddba522a17d63deae102d4e5a87529a1374f5d8f52d65dba3a00adac57c5ba6bdb8380f61d066159e98d0af1ecab49445958595d3443daf1626d06703e9a732e1273504008217c84706a8173ce39e75c6b1d079a163c1c61b25e6bece958c0632dc289525484127415092cd0294e29b9e7a085e29118fc4163075d6cb4d6dc83aefd4d51609632924c9481772d0a71235363d911b1cc4e88e5a865b0d52aac99010d049c02609d2f7060f1ef5c1201714b6c3fd75e6bb587abb18e91381102eb9e73351b191d4497822524f539e7f51430799a97534053c0ec695ead80d9a6793105cc37c17721aaf8f616feb5808881f511a20ab95b36b291bdae7e2c1b2f218c2c47219a757f56f443c40cd0217eb391bddc42af1f4fd462e42096dd0989f049f2c128a52ac0993733d38810430d7308834b8c202821c66b4e5284a33d463f3c164c56644556448386bd56db571b10cde8ab08c1e2d3169f648d0b907ef3ebb931dd55510222e6c6aa15956322a22357a5176314e188f1acbd17df73f041e86aabf8edc0491a6498d88163cc4be0194f4481cbb4a425592e2e2e2e2e518b3c6307e792830514e02c1440550244320e601d8f68238ccc29a10149b2b5d69a73ceb9186bb09c15b5a8041529962089b1d5a03d25e27b7788221cb426821bb4268376c4452d72149b23293d2865da9df41e7cad4a0d3e2b5cd4e20c1c01cbc4295ac21c40448d9c444b7090819641057b3d18e8285932b1600417c425b6c95801fbb53717dbd9bdcff75a9c1828628ed68ef72267a45f9c2c251089d5feae38fd4eef26603b5d5204a2f671c03a1781debb49f6398e40afbde65c14cd78dc5e4b40d7c4f678506bf155217a1e03143dccc973ceb9f7defb419cac080dcde21623c6dc2cf7ea6b38a0f33050ab2f83354566973108a1b5385944cccccccccc7890e0f1c4c96a48580b9418d681d80072e0e242448c920f11c89d88f60480023e58a03d7a1e78526566dd8f1d8f5957df0e5af341b35105b6b750981d33f33b636667799ce4dce3d91dc6d69a73cdb93a45e139e72c140f335603e6ca0e858af62063118db539b4ee3eeb7e9d9deebafa81ba3b8b7ea077f7b814300be1836d7359577b33dea98ba319eff462d18cf7e96ad18cf779cd909e7d8fd08a4ac4e7286b4798569bac16f9c5c134095a10db6a129d45167603f030d1723483fdd8217df206a010338b2cecf51124886db5f9e80e300b3f5d126d210389d704d359b49e81294370d2c87b41e35cc3223a995273d34544cbe8e96424c2b9cc1031333313b5d84065f0487fd139e7a28f69c2f8a0041f84f039e8dc7bf0819a0a11bfc7de73ef39e7dc7b41f48e44f4e4518b4288a1c28d6009518b4ed8c9d030cd144c632f3fe1278da397b48cbe15fb891516bf9748fdba9774ec27fc84260a43a0601a27d39e88628ef7de638d3596238710ba0a34716aadb5e65a634a641a4707a1a271c8b7da51d404c16abfd14e5690c611754b413a066918a45f102aecf54401815680ac6ca665f43b341eb6e4c11a86c50990c41adb18c83923cc442db6ec789722075927617b6f2e2e916b305689b5260f0482226a3ae0c20fda4ccd4c9118507145cd0eae705295c089931a29ea30859a99d783f75af09084379d210b3c348989375a12555102f71b2d79a2553193823640c85c3841c5d482058b5f0fde6bc143118a48244e886d9f2d5fb05c3424d7d50008b6bd21897e706ff5057142a488c25003dbd60beb6a9301c1e0362038210c053388c0099155cc808ae0f1c4c95201bfd0603f18a88509cd4387289d5cc704876405ee078e0930458aa845878495c004254487443a614d7e90c76a8ffaa0228f019aeaac2e56cb681cc496d1f7c10a331e26034b031d3b5e8f018a92b910c46883385971c8021866e2d422470b197864bcc0e33c71b26682709fbb16a199b1c2098d1022324d9cd0a0c91395203c79e2e4891530e184c6bdf79e73cef1600731718a9624e7449180799385040d0d0d0d0d0d8d47071e4f9cac181978fb2aeb81ec1b807d2ef6cd4f368c104155f55a567deec9f31911d1a2a89d2e1911c8ddc5c5c56586046c3b4b191598354633dc658b40ee8cee884abc47cfd9b0ad3a214a72ea786f51878c8c8c8c0c1106b0f2c41b7c3000dbdee0fe18d3b8d870ce31b35aa00c60f67069624e27608f40ce08fbeee07548194986b585e2796788929c53036cbcb7d8002516102c2b6ad14667891598d8704143d25c40d2608c6d4d0adb185c00c38144cbe8b739510dcc3c8184069a26fe205074d24e8878c184c80ad790401144d0b91358ce3dc61d6058b0509a732e3ae3c8591774ce39f7698f87350612ab991b6b33683d5807273861f483048ae2bdf7de3bbf7a9901cd4a67548868a51ab51d84c12546175c844d02b6b046d10c06b2230b7800eb08609d0ceb2eeb58acdb582759f7e81c454cb8c1caab7a2355af35d5fb592f48aa5c5a51711ce36b6ef1396602654f053172f4ee6f1cd5dd5d6ce4381263f35151ed39f79c7ccdbdd6de7339206b46885e8baaf0c14a447487fc016c23806d326cb3ae0887f51c511525c8d1388a8094f52e2d2b5525a219462c7e11510423072318b5584545022788a10adb188863267e7488ae870706f292aea701683d08a173efc1e7891b4e27077578f8cec5b93657d42cb82a0f8e96bd894c7407a326dd21f95a7994d2d94879dd8e8111734151c958644b0ff4d4cb6c13b1ec2eea65d235738fb177f916c262ec7d67576b26bb08d5bfd329aade2662dfe9a9aed49d2a55a95fcf9b6aaa298ab1686dea87ea68f9bc45108cba948cb1fbe28ffaca75d9aebca23ce41925290e8aca8bea82922ea8a43ec9bbf71076aa45bd9e4f6da95d05a3d702ae06c843ca83bff277b1cbeb9de59aeeb9aac8ae5c73855546f3d8a91eeb2c18290b56ab87507f944d4d2216b188518797d34459a72cfabbf710482b104f5877824f5277511451f542a6b587309a1ed244742c80811cac3dc4b5b0470e50ba27d56794c3724a6cb4ee3392262a9e20b14e1ce39896e1b8f6a66594b01b74474fba832b07e9955f50ca3bbf3926bb36ee458b96535f79ca3b9f134a2965c83a63ccaad750055d9277d5f50d6bbd7d5da7c47277bfebaf3c0fbff03cd4aed5adf72f3bb704e2839d15f63e66ff619bf9ba8e0af6bedf29b1ef308c6aaaa9a62eeb9d2edbb56b67551867690df559c594a42425dfae9d9467d38bdfd8e2d76a79bb247d5dc9f573fd5df670182e3e2c208f4a0e94cfd9f506c1de43b0cbf35d15fcd267d8576461df27bfd9c0770df52d76287f3d96fe5a969ec6380ff57a7878adefa1d97b9094f29093bc0e66b20f5df400e351c7a83c54566b9d4faebe38c875f112d5c54cf42f0761edaae0c1bef9bbfa7cbdff9aaea3d93c0db271320cf4aea365b8c3a837bea837baa8d76a51aff5a9d7d352af87a5de7bea05add40b52a929f5ba5894daa9370787fa85158799998a97e7df8ae392dc984e136bd813cbdee76f75f64b9d85a64b5518672996524aea5615c6b1ac2e09d3e0bc8ae7544172b8801ccbb40c77b7a93787cb3d1e190e52e51f3ca3b15505e209ab72d31fe5513dc495aace3249f8a592a7aa4be2f1384663df6ff4782296a917d6f71b9d8c4be294709025820471499826059463103863e79c57a9cef53e4a85909627ca43bee87086dda03b5ecfe9f29cabffaea9ad252d1dc207a52b44230e45bd4bd2a3389d771905a55ec6d78533f69d992bbdef4dff6a4fef90a77708afb0773a0c0bf17fd877dd0ea2add4fdaedbec740a422bec9d7a88cb38d00afc427dba30ac5e3863a71fbef31b5ec9463f74ded13b4f2b67289daa1f944fef20f86f08fe3b547248057e7987efbd0bc32e9cb1280ffa5743efd42b7a5deef7e93d410a560ae1557a4c6f7aef69a23b660cf2502ebe828681dc81b01e4f0f528107bcfc74b10af5952b052a89a460dddb9cab1548c1ba5b9beb235d3eb2d49a6e31ad216a057e69e9b7473473dfa51a8a87a7987a441f00cf57abb171589fae68d58ff4778a97acc03af877ea02e209ab478ff7f996becf899d8f100af64a967a75c5680645a53c27f61d5a017efa3c5402adc02f919d7f74c78433bc8481dca58baf6020078405adc0349eab211663b1142ab4d0c4de4649ac58b20528ac8b8d9268e10dd60a255600364a92852c2c61c24e963d7ec98c35808d922c2962b9065694840b4fecb4fc1a1b1fe7d1e6739a54561eebe5cb282a84b49136798ecce79a89eee04677b03a67bc66acd4d975ad78192fd959c64b761dcd42d67fd818d11839e54c87a09809bfc8f38c9d21a8daa997591a63656b7d32475943f4d6e36fbcae652304e2e30764f13a3a5ef82b14ff83bd4d529e31768ab1b01746363ac465361e0552879fbfd6a5ac976b3e5d56669d397df224a57cbc2ed33a751e60f1e9e345b97eacc3cbcf19443c0f11cf6724ec863c3bd3f00b9f558a6fcae12fd758f9f9aa86241f5e467653aa4c49a9174652ca233ec4aafc14235f4eba63a22eb6e81519e81d08eb4ce3328d65879447fc3cbcf8ec8247b9a677aeea7da9bc5d2b918d180903c16f38d7477e3eb29bdf0dd3c92666c22f90cf750694747819921e2f27cb4b9cab510fd89ce24bdad48f3c7c3c3c37cbbf30cd52879f4ea7af5857b9a296615d96c2c23fca831fa2e81d1d62b2ccf1f4d3190933e197c84e538d9d57935763a007841519888398365666c234e0b318070b5e20c2dc6198658c7d4188ad61a3245eb88251ec8f2df5e059126ddf7b14f528ea51d4a3a8771dfdfa4d14f5f7fabda99a445ba61e3da2a87b810a5e8082a29cbbd4297a77569d7aa1572f4fefbdce9bb1dec889b15ecf931eab5355be7371aea837977545edec542f102ba58832512cc2e00a273600364a72451512638c85ee7bff477b9fb3b5d93ebb26d1f6b27d0fe8c3db2ce5580fb9f4e9d5752d0bc4c78f6a7ec0f267adaea3abeb3614d5a72b241f59be6edbea110da22dfd9cafaa334b9faa4f7c3b06f64a8761b326d176feb0a1e9b2ba0ec6a7bfd619c659c6ccf5b2595d3a3fe58a9adfe17a615ccb65984d856176ca5fabc2305bd5cb76faa41586d9a946e9ecf2ea214c43aab05e3bfd68402c0669d0052696d0d859b5db45ec65e78b0b351664a3245c90b15e58c216c04649ba30632f576627b6911fb1bb0bc4b28ee650123eac7b649b06d1b69d93681bdd76b9c2b0db4576c027e9828c05808d9274a1889d707a74073c53081f1b07e710d63b7d3ec21aa15c51cbe80a9f72592d0352a730ac3a0ae7da5c51c3bbaa5ed684a23562a0a9c238db32ca3ff7f8a63c2e9090ac17c65d1867790696546198edc75f18c69ad821fc026b88dfb4b587300d56511c908abd19cc7e631b44368231b0eef409ebba58466b6085da590f611ad0620c043b56c723b22dc916ec9083ddb85694640b6fb00c440f611aee4c6f0bb111331a068a8468b6d51ed26d09f313fdc38fec87016cb932cb96d92a9ac18f685427c0d10f5534839d1b30a3e8067b6b1d31f3985184a3d9b9c628623f185bc039e75c51cbe044eb9babc1f4734d34c144134d48134c23c20deb54a199a970d940c66a73c4534cd6cd7dd1477346c618838957a8eaeed88f2a2ca2f014fcc23e53ba5a3947a6c24ece3c63b127b31a8a7d5d0b888ff92657d1714a81048693a9e02968c5efc34358d536dfb37e544e75f7a5988c5dcf1f3ca5b3739e62a5b27e68f67ccf7a57289ee231405d790a96c2ce3e9d5047f7f488536fdc30d74d259deb75b19b6a0ace61d964e9d9abb3384f63db3c4a164f71a9eab7aab7457af76af214b4f2144c039ea78090a9788cf3142e288c7205e69eb18d768c6d312e9c4e8baa6059f404cb1060d90db0f9b551a3067479afc150caa75cf3efeaa87180207bcd0141103390e70f442174e101bd42d27fd89772c6284b0aca1994ae32044a5579cdb2d40bc3208535442ffdb1c309c447e4f29a07f6f67c8c397269287a52c63aa686f4f97a3b66bec2fc4aef0c65ce39278317cbc6460f906a8d77c1fa59797f5613e5a917c6abf7bd472efcf2deeb183bd9f36a5e8996ca52a5fa16582516764ba244d460a7d827f6ce52ab9ef15c352e2518c87de5f2c141a227359846bb5cec3a5ae5daa45cf3289775eaba9ee97a44dc68f52f8c0e6773221a87129c0bc3c3cc752aca6166e6aac735d954e3b6475f8f6bf29c73ce4e8f8bd66b83996b300dce698fcbc657f5dab09cfa9194681ca096e1eef15816fc6d76f6b82cfded71591b767e7345d10cbe754df4a18a1ed43858ba688d8e51c2c713079f0ab790e2454d6cb3113da224632eee4d16d9a393f36d6098bb944e69bd36acfb14e22b3de03197766db0f76a8dc66e3c56a377493d81f8f8a144bc4b8c64e6159afec38af1ef452efcf23e3b67717eb26af04b3c7b9c21ac7a999dcea997d969c376e6a7f926f63759fd4c7797efbdf323171623e7eed7869597e8245fe32d9c0ac32ce7ccbd8738ec4974876c12afab5d4058ec91f27897eedc3797bc75d1ebe8e71eac9a75520d7ea13ef1d2232b04f5592f5baa7ee2dde56bf0cbbba371aa312f2f5fe3d11dd2c6d55eadc1349cc5550ba0fcccd8f889b111cab4d4dc162c20c3969a8f914f0cbb015b42d982c86bf3ee969afea7484794559a621f23fcd212e512e51363b9b96b889eba6c081ffcf0c0de27ffc3729b5a6a3e453e50bc9ee0fdc47c8c4cea13d39fde156efa97829d37ec162c241fcaebaad4e6fa51f97bb7d47c8a40c6eeca27c6363bd51cb95225734fd367e66384690461207795cb2de198e07f8cf0a78885920fa7a3c8ce759be55c2d350c848446e3ad78493f461e37a3c252a7933cfc44272a79921f2390b560c148b0d705b1eecc2d61dd3f46f885f560544cecb6606127d8835161e59f7bd582857dff18f91869a9f918f9c438e7dcc70894e970070e4d896dad888d6942a4642e4877b7a4583721cd895684dd68d9074dea2c299d0d7d3373cb3722dca0b0f40a55510bc65a50d6a2e1ab7e41abbf80ad08d70b53310dcb4a4ad5b2fb75834236ec6e42e81b117ee9d3160309bb39c12f14762b629f7c475e763a524a2969b3aca45495d58f8b3f2460fc9eeb2a1c76834853dae4298a56a7e491681c2eecf388e1f85cf51546bd91c190dd957e72692a2b8c1755e5517bba3981848b0b03f0ca004d73a2a9bede5bcc7fae7baa0971a9375a967aa3653d7701b546439b13b4be8a369aaa8628a5cd09ead238ea5dede1f7f5d7c3c3af15e337da1e2a0b798c1a1d0f35ea5a9b13147c9fa890a6776f4e342720753dd7a24d4873a2154102033434cd891817ac051b8aa44845580d8c1d7971a839e78c87612169d239e37cc52225558f1b5663e36118a5a7f5d2a7fc5a4f992a4cb39b1ae26b511425bdbae635d1b326bc2279585a2ed5cbb35eaea810d24a7c8af2982496580dbb31cf45e80ee99a3ea72451674da4cbde505da18d842249f3d559137e915e312cec9d144a7589fa64ae6aeca45252a6f54985d8ccfad93c9e9224e93ccf9accaaa23ea5549f52aecb143f4abf2a4fa12a104f58d255a930cdcec753164ae52b179532290fe9a1592f4b496289eea045208407c262e726763e521ed23faf78948b9e5d2cefabc55d9eeb6829c6f9aa8ad48cf15ce3355d91e57856067ee13866ddb93ef353f54bddfae55b35242f352bcff91582533ff3f1d6b9ea60ac0cfc223d56a77e1989b52a4cb3cd568fa76f61b11eefb9365fb9a296b1a9d7aa30ed32121b1f2bea9095413ac5caf058cd753508a5cacac034628516e390614696fcf4c852fadb445c57b31bc2d9ddf3dd703633cf331a38afa327bb425414fbba78bfad0e36af83f58ca726a362bfce966e46cdd99f6f76eb8bd1ccb38673b2955fea10c676b01d6c07e74a85bf14fde42946082133c74a3d54ed212e2aecfaa1fe0eb9e164ac5dc0f99eb0ff0ea78b0a279c74ced99452d6d4b58006cc49a7b62c2b247d9e5facf33e3a0f4f299c91ce0963fdccbff345e32f6bf2484108e13c4529a5d3945264e19532c856d245e2511e459fd2d5f9e41697979f7a9923257df5c66e48965da49273ca8bca3a01f151f1ab2ab4f90f2b234b4a5e395bd35975b6be4999ea6576f3141d4cf2a594b2569bca85ac6f2eab8a31c64292624caae4552e4d9736af2aab629537555555959caecb5c532e37b587c8ebaed4cda557524a21d374792e55a7743a555d7a7501f184a4aea7ae30c618af54f57260d21d94928b371610963cbd245de5a29e7271de57cbdbd5e2ee62f9bb3ed7d192b2f40ecaf5994e1f59abf3dbb16a684aee5caf74a99a6a685ebe9a2a799e28d5d47955f99ab73af5335d3a5fd6a553d6376f7155ff5cd55b2e96cb6a195595ced948567557558aa2dee80eaa089d6294356e58470c92bb0adbb889d816598c999395a294c7caa93776434656329a28922425c94592a46b439224e9d22459ac5103657a43608e39e69863ef46c816a5344246584429e37b9452d24829e5e3a3ac714af4559846af8881a6178f380265a20c9ba00d196390b1eeee8e24c6de20846f6287bf304ca2d6a4935167b4a2d75425595126e886eed7dd9c3e84902d07368cad01f1c1e1bc8570ba5d21f78853216cf0ad1ba7dd71381c8e2772cee9ce3912a6a034aab2e00a54b1604a05a94aa17438d651ae8d55517492f50291ea8d96a14c1c26a1204618637c6c8af151b37d1147f1374651616077cb7052e6a5202d83fd469577bdd3217b4ca9ec28f546957aad4ebd9e4dbdafea05512fd84aa742a2bba6d41b3d7133b1dea8c6b25fef3c8a70d4a73c8a70f0f09547118e18677914e1e8e19f47110e1fee221ec67db8e27bb8e2635cf13c5cf58abfae5f512423d60bf30ea3bea837878bdaa25e974f6da917c4523df57ea55e8ff5a454947aad4ebdd15ab59b4ace4e09dfeb90744ea69de3917884695eb05983c4c2bf17fbb5185b6a3e453e3132c658b52716be25562663e1a38ac16bf6d48245f73f463e463e463e46a08b436b365e6bed2eedbd67a36dbcc7f95a8d1a356a3807b9c641c82074b0a6b9a69aa873ae8d35bde71ebb4a919d99301366c24c1a48c5dc179c834c888390098602081d6442a46610fe4e8ff0b15e79ea10d6479b77ab9a32e663779417a6b166674db026d8c4dc15efc5dbafc5185b742f3a2231c6afa8a49cbea74b0d6e22199b7aa34abd91f3cd19eb3c05e5624d389b7a3d96b146d5eea986261bd243e073ada10a9c7bccb1293e235e7beebdf7de83147e9ea2ea6d96d2f775a7d3daaf4eb3de2649523ae288238e30f25eecc7a618e3598ad8a23bb78d4f768c31461bebbdf4d2e3a71c9d4f47b9222663aad7c546ebd41431d0a6de66519d2b6237a27401f184456b9342adfef69055fa75eff860eb8ac240d1df124b52e292180593a9624c84a2c812c684302682b40caeec07815c5c72e4f0782c0be6c52394d678c46234261e8951b01b54d2b6dec2b4bb296b1aa5b02c8576288d31900754875e078b473a3485aac094abc4282cebee9af2dbcdbabbbbbb43d453defcd8e963a7518a2bd4945d312642c12ff432f280693cc25c6f8cc2bec8cdb25936cb66d92c9b65b3ec4bea5962cd70584a29a5e486b45da21cb6536a3c02f3505a183b638f31ec863c7d8482b118058b515879cb4a39ad217a9822adcda30807dbe4b82ea07b66fae742bea9694ccc8b5ae95db4a8d7834437bdfcd49ba3a55e17967a419eda2bacc2302fa5725c128f5c2cc3407c948bab60250cc4f1088b50586afdbd777a9e73dd48e646326cc518067a5505a3ac1e9ffe553cc29c12b6c432eaecd989524ca19495524a73d007708d4798467579dd0a32245a867b11c698c891c3c50504fa3d1ecb8a479c7332efb9189d8c7d47221ee1178e4772e47071a1a77f31261e8951c8542123138fc87c38461384a04016d2d9ccee0e41a9bbcfde94e095fee4d96bf5aaca576ffa957de71f83d26cd6086e08eb11121ad1f00824d88d86f09246445858e90a4d1165cc081436d123268b5a2e16a55e94374bf945b9ca2fbb4aa7d4e917456270ea43a9eb67fafb84d0889e94f2409950aecb965360ad2a7d955a53268a94e88e29e488e96a91c5bede39d7bc7551a7f0f11fcfcb976f9a13c6c647f0cb46fae64a952f3de7773ae74eb01ec134369fe2e608fae92d16756b3a825ff8882368a27684c5e18d0ea28b189f44ab17307e59cdebd97356553567c593635535218d481562893c9e599db14c1791e52e28ae582a6abe94ce863acbace69cf0734e22158b87157c55bdea55afa2aa0abeea55afaaae381fcba43e2c87afaea3fa9c31565f5971115d54cc45355f5c305c4c7488f957bdd752190b753580811e9cf0629f17bce7a2efebc5db0503bef7de93a25455b09a73ceeaf1f38754352b58d58f7ce3f0789c885405e3c515b58caafaab5ef5aae6043c7d13d29c58407ccd8988c6c358c83013672e19632dc6df64b3c2f08b05c3b1f10b85e1f7dafb4c6bad0da0c5b08f5fac5f1866e617398dc57879498a133ff6c82cbef7a299c779ed3133c7c72fcccc2f3ee608c3f1bdf7c7349c551d914d2c245276cbee0e12293b8f36acbb19494bfa1fb623aa9ba1a44ebb512836b9a9d3b784407c48c948a494524a5933c9269d5f4ac1ce34498aa56859fbba2b95aa40c9d85de97424934c386726d34a85819225335161248c29253bb2e786b95e9846498a99c05841499d35f9a6a9c99452844c508a40841911d8646516c1348dd2295dbdd96dcee6d6bb32d652042b82dd88b8096cd691e77346203eba089a6627b1a34f3753f8a1223c7fdef1c39eaeb7c7046f3777777777c366c61e73c21a6545b01b3435947113462183104247298410a6e3c57ef8fc42dbe2f7d9fe752f609c453ffc7d8e7eb8de6f66d217d74f0c96f75004c3b7b430c5efe12ced03eca91bfad0431144580cfa5afede79b8a6d78bf3ebdafc97751897ca5f5cd55d5c296f71a1fc73755aae59044b8dd6adf04ae495c85698b018eb9b7e7b4c374e3544993200b09515865c8178c2524941e177f89ccdc52c9ac1afae16cde07a43d141ee3145c84c8a98a626933101c015c570957958b02231192604461999a0d62636697a7b6317b936e90ec784546f73d7b52c101f3fac7426d80d14486fb51d0c0b51ff61a58823494ca4559335c12fed4c49d2e4489724d5b7f62bb124b51aaa4e5dfa6dce4517037be3d955ce31f1c988c45649d2dd5b8b6fedad35d738b1b50bc39254a5ebc2348a09860237e734adcc532b2cb9af34c9b556ad4d5da1ae7daa9703ac09aa822a9ef7c5f294cb3ae7da5c474b5307853baf21793b4df04b735dc9cfcff93a793e6a1c9244614d7438674d702acbc5b9e70aa7cca8f4ac59e88290211a010000000023160000300c0c854363c140523619a80f14001479a0505e549909c42849619842c618630c000020002202323335090218511a9a6190c0d005f976d64fa643f46448c78dc09721cb735bd15d70ba493802e9209f08266185c54fc783ad271caf1decc996d98606681472b73f4268293f5c25f0c944c8676bea75f29e6cc752db63cfad94a423e4b91180c354eb085efe322e0b165b5e55c42782529ad2b9c68146e711d4c046862517bf8f5967c6cf0a2b4c14bc33439079781fc143ab9d730c35bb555b82cd01befa111e7badede713724706f7cc468d2fd548179b3530c2b40ea815ca7b0b40427de0393feab8d5acb434b6062414b58e19fd1ba789f6e8066808649167af774ec710405407790db4fa615ef49a0219e89b9d95be4bf337af03210b1d4f4e65ff57fe748dc27948fc9a715b9860016739570f69f51d270e7c4b68c36ce3fbcfd7598f2a94e2d7c49c91a80ade82cfa5ea3d3ae72b45559dda173fbe9f46c9277bda2cf2ea3d1483118edf35f8ca9fea998f4ef6027e1aa2b01c9f9e31001a0221c99cf683ca8ae5fb7b16208253ae6785be94e092ac7e042e6ad55a0518a06e5b18fc755ccddf058ba393d128418a2ba55019d722e495a09cab94b94982a82334334592d906c0a6889e3d3fd41e79c3acb8594bc4e72ae212277ab28092f18804f8182a1314e70a437a1baa502820b0a4ba53c0a598f3073e6791cd9bdc983d78ec74a18c7bee5ee00ae01bb313ad51524e588e70fbe0c376d95f3dbeeefd979b33a711ac212c8a48793161a85f1667abb2f929594aa01a103260b361bbbcb0ff30e21bf35c018fff11bcda673c26518d2757403a04643c8d94ea83a11f7db1799ec1a2a3c4296c5f908fa83f695eb09083425d5f1c9f2cb92cf394220b914542420a27243d9687ed96a7d8cb131e8f67af26663b05eb890e4c71a2b36ac868bc7a74a9f214e018114455c042d14fe640cd1a48c43382f6d22a47815d83b54718122183ba2f3d11a423811c3abcaef442655117e748cd8f62d3a814dd103bacdf8e7c18f51976ba1fff99c07495a4c7a35fa2e7cc6772b110b7b82d7da964c219d68fa7d0280a72b5f9892602a6f19d1ae35cbc199ec79bc384ba9a1ae5ae48960367b84ddc9ee3fff7d1396d950f89c2855d1220b942f500ad83fdba281e64e2d2410a0f0f93b416a1710b94ac52be64c360f99a050ef1baf31840222853330d88a3ccd7fbc0728bc072375a0061398daf2dbc1704119530cee8eba4340649363ab660ecf279bc9230421f681cd0be7305789de474d40e9ec7585659b51aef947f57b3112297affaf94fd09b426da3827970d55c1e1bae7d32092ad9bd27d9aa7ee154ee4ad2375cf1f9fab378ecf686762b3a6039727a70dd00e1d630e55842b4633d9d3649fba21dfbe2b373786e35e747fe8c2bbb031581adc6a9a5c32dfde58cae84d218b2e5d3d5cc0043c97cf594935af2342f10df3a13f3bb9aef44e4c1373571b82c7ef92d4d9cd9d166793943430f009e918cf9a1e4e99a39f34b714418cb8810b8a26b268728a9622560a13bc4cc3221f4ca875cfbd10f25766cafdcbeb212b883d3433e12ccdab6852756964844caa229af9eb8b5b1d9e2a8001321142a91780372ae3d5802dae14b7573237715190ce3c4be26ec9d1ca25477dee384451d6ec00b56735105690f15f5c014e6378bc5fbcd349e374f403610b95e6689e574e590198ac6060502493421c78655759b9988a92b92ed3364d6db84212b28398ef817615f4d50c4945d3544ca25bdc80c305bde1f0d48451548a56d0a623a8b451e3aaecae5054d7b8c9842b0faee6f094d72d7cb5962f057ea42a451e7c14cf354333ba09262c03b638bcfe6b5b57745d6573e7b3b5315f6923849b4c390778bca71a57ac5a2de07f6866fc80fcee4f77eb8645871ede33087fd635b7eddeba982bcf1cb8f92178ffa894eee88623116cc967661d116a4100b2ebb01c59a21f50f5ed6891636af5fcc228047c01f77e9ac941cbfe8d744dcc74f41cd711440b58f0f97f55ccadee1d87d8472bb7259665873c053421b7203695f469ba9781104de570348bbabddf78667a862afd612731080bccea59807174f940b6d53b55ffdf640603821db1f18e967ab6a1682786201ac3b718513f50aab6bfb75b61d00004fd6c400a5578718e4d954cdb19e173ddb92928fa42c5afba2a1067d382825d0e825683bf4b1405c4ab51071497720f809f9aa2c569fafd61812a57111cf58e4a46e532c7d283be72018c3fbeab9be2f756fb8a138b58152b2403706d16cc99e52ebb2f114b28aabb7602f93dea23a1fc4334b61469cdcd6e8954e309a8fabf4bb3e95cc22439f592af2402f4a5f377666d1b35a6af9785257fc9e6308b6f97b9cd8652cc73d867fc99323ce6c597e7b6bd1178c879c44a5afa1d01fce4eb28ad03c172c0f5b6d309b23fc939bd3e5f628156a1dde8d2ca71e190d26ceef34bbeaae48cc3297cf0636f37839cf3d7b929b5423287c35f9d15e1d22531f154a28b8d4aa12be688e5127b0782cf9774603edb4af575b102a65da07cc26eac3d27cffd4bdb176ca79fc84fc1fc0d4381e1084445e52a4d9a7140dcac7b9a94c6b4db10255ba1226f01cc9a7a7ea15b8674d841e3b4ba242049212635284550356a40cc11302e669709d7a0417ef0e2c499ae4af6b1cbfbbd445b0f8c91668e02ff0f1f89cc0b031321f146ee6f74648b05607802fb83ee10b40c1f2ed997559503821567c7a8e267bba0242e15684281c3d0a37c081fe03c7a99a856de4310d2c62fefdda7c32110ccb30436beabf36f0a0e905115c66da477e3306d94af57a76166c470702958507dbfa971697572c72a3d3dada52c69b1b052a28b1d820a9c0cb9c1eee836d935a672a09cf5b7da367b6a708c5d0c8a38527b573c37940dc6cd05db9548c0b986c5898129e39a64b3e137a66a2b8b0c987145691c4c0e1c0161d3c7cbe290fd1531794fd3fea1c5b8d59db6ae9b4459f4af1ba97cd9c3dbe90d1201b3c0b17a0a778681e208769f3c383a729e280da5ea983e5436d23fba8b54e24bff617dfb93069e8f365a2756e445612a592b3045f6b6e816fc781449a5401440c7ca4ab2d29949952caf684b4c70721de7bd940d68697a79b1da5d7cc2ce8c5fc889ecda4663e17f3d4b62cd73fe39cb14c497a15e6eda303346a18d23f71a46278b843a8b66f842f4b9509c0e311f12553b8400ff26c234a97caacdd2d7781adb7045d98e9bc3616f1cf4545da9ffb8590c2ac9a892004aae73e7906a2fec470be6258c0b8998e37adaeeb4f993902d06f0621f09dcaecd0c4c8a18e4c9a2c701b27426cb779ccaee851547c74bcbf0941c2c0e9b7802771f26905c4073a13857e745e515565958a552ba6f223e062c4d7c21a05abe3394b08cf95e386c535ce86f37de079ee98132976bcddb50364b48618c20c3309f25570372e8f6c57e188af7640ff760c4c614d208ca7506cfcd38290eb9e630da5d5845b2ce471b57be424e42c36e733c56fedb6a2ab4e946bcc1e7dd0e334694f1ce693f8ba353e74bee3396e64ac2cf0f614483c7c5c76b9483e618c0b8a0d6dd8beb55d6e46e68c755ec0a944c8f7d91b4a311c8e0d6a29ec86a5017b887631a9d47bb04c9a3a41fba032782401575355429464affa480c17ca678d596d5666c4f3de1570acbcb7e0e0faa29b4e28ac616c8c564ac0df5e9dd098ae9ad42610980479d6bd82cc81c643020faddddece8a2886893d79997e23f6eac82f6ed8f33b91e5ba6d521ee276eb395da9371b0fe44857ba887103b22dd5a77cc904c2a94b5e0c0b9b7e17ab6a75cb15ae963aa2364d3d158c21f401b3ec4dd30a9dfe80d896590e13462bbee9c8ed947ca215482613129ae3c1749b0858bee3093c81d2172e4b1c2b01e9097a9b51024393a0676e30eed2b0670b735666ae656dfacbfc8b314dd9cf49c232c9b2b69515877ab4a6bf0338143b450d42eea0c3f334d99d72b926517fe45d3b0a9783b6b5187bbe7ef6c08c22cb906ec86acdb69205ff6a61788c0a7bc8cbbdd5f962ff32fa8b2d5dfff85449d4a88c7ddbc901b611127d13092aa0e6e9324bdb5673219883d69d866ec8c3a6f03453559f5e255cfc173a83dfc9296e3c33aa3243592d1ea4940e54237aa30bbc849aacb07d3c09cbc32b84aa8b4155ff4ab5aa96ea2e28a8564c50a2fe842d68306cfd7dfe1b1c64989807ae60377d6301574ab10211e85c8a2854002f27fba9103efe646db73cc8f86ffc6e2b607368c09c0acb2d64e102c0b5b6c3035665447962a4b8503ffa304ac10907e80521604da9611cea38d5b8a779ee0f3a44f42b81ef0fba45fc0d0b012480e95a7d00886dd291d401a80ae7f35b94896d02c7eb9e3d2239fa60a3e1845a518e022a495c0f1b81959b7a10c6360ca47dda742c1931c11dfe1e5d34588b1578a583db506cfdcb4c507a8af40f7ad1259a16a9ce145af9700d536c7cb99ef94507c3010180be540f6ec562b61cb16453fd6a4c6c610e7de3668e448f3839439f48bb565075c428943313de3a08b04797ac6882ceb3b61f72b7882c1f7416a7cd4baa29cfeac2d0382b2cb47c878acb2a374f3e578e7ec67ca828e436d2936a9cb4fdabae07c042c40813bc4ce99d06d3fe496c7f60a24b5281e0c196188a9bfc228e7682661a9239ec5cfccf6366c94c92f994598f49ba9b99ba46da2b8b95f5a1019a385c98e7a89d4957e56ec1e7b6945acab25a33972872409c816dbd7ff1b0764b0ef8f926c07bc03fab1c1756d36e466bba5229c9753b6e90fd8e546895b43dc942200c662788e168114aef7ba8ee9a48426bb82e874c0f862a3496e4040d8079ae7c25e4d24188a921e2d4b447071d8c4a3fd5ace6cde1885b61cc9290d0ab31ab33cb570e858a0e456b8760540692ebd09087af9618e4dbe06c1219418f40dc7727ec602fbae61eca793a119178a8e657ac73b7a4054559683abaf51c2370a3882435557ac54ea5016bf5081b509f9e8d4acd97f08a0cde7d988cfcc13ec4719984a79adbf1ab2c99902439abf5ac601ab85a6506961c2bff0109321da6bb550152614036403f36b4b201ef3a89ccf7e74fb9c8bdb85dc69c718ffd3819f595f47fb8e52a026643be284bec9f7b094f5500bcb44554235ea8a8660f189200bd26aa8dec22f54c140f185daa8bd4fcb746a75485be4538c789a42235472dcb44f27f90a38803b75ea6d2e823c3e1fc6ac12e502c12490d8a3e81178baca1af6a074618f211f9f666e7d3547e4a1f4ef28592f1a3e0438fc8010c0094dc262707702bd32b0850a09ede8c62fb12f3ef3f54a63bdd3ac71032907d8f0bfbac57a671b0ffc1449b28f79adfa2a4ca14f2831c84cb9c431d9e435872b87971300bdbcf3a766225ffc9281e937f236e3740c39ee985a933c572cf9a9db538c0ba187c34cf74b8ee40ad2252cf34f1e0d354254e286606885105d6d06f77ba52a446c5f6cff014cf14b18ab7e1cb2017d52023e87b011149674c51e7802ff2c353d57481ea848d249ee4783bf0bca1dc87442851697a23430e2d31f6c7f60f2dc3f184df8a9e05fedd344a48574cc16630632ec644831e09c03f76a3d2896004877080244dcd3905cf00aede1110f5817bb2879e660b990b4181c561afeb4cc873164300c89c8874967c947b6d4fa3d6c2d13b193704bc0deb52551d0b82f36049419fa2da62aa63cf6fe23fb00fc8324fd83e350aa867110cb6548455fba19a5353a0c7000b0234dd36c1a8682735b33600329e62e121fd8251a139a7ddc2f0a1ab017f5fb57de9155b76cbee405c96b8303672b8e52aeee5590fe6b2aca66b595ff829e7e909cdd19df4b70d47dedfca51519379a317fb5c13c69ee6b3198536d5c1d2b53f50224d38c9c50efef5d9c8c0e85d09e2507caecbd5865fc7bac70d2611a4355586213079cfe38dbcdfe59898db25f5154a4bd5fd42ff2bdaa896c794928e09501636638aadeb46ac7ceae64668e54aa5dc20aa68202e30520a5c58d382ff82aa4b1160370416537c483ae8a30a3c56d03fc34396d25dee22f1c5443515eeaa15f6a55089239d9d68402a0b264852d1525479484a2a2acca4310a83c622f037122b4dc52c10dcc14d5231cdec4905e394c0bee429340f045271938063703c41f70f9333bc920aed919fbfc521283f307f447ba38a6dc5ba32fc29216c48907cfe8fde0ef38b3b99221b2165c0e9b75a204b5d1d52de90db7cfab3ba2deffd10cc35de271aba1fed4b0a153f99bcf132654d5823153c27eb21abe7f52e2f316c4709891bf948a3c5cd29498a4f1d54e458eda18c1e0dc86163c8147628f154b50ed145f4499934d5bac1510f3f09810b8c42f7f433b7a4d453a7988167f554e8180ccaeb94545fa6b4611673d1669e0d7389bfb55436150c3b31d9fa1175aa757038dbf71c100c7ac97239a7fe36ac45e28b23646b16502c15864b56f54f3c8d784a7725058f6795944df2e9d37cb61627aefbe02d81fdd0302a52dc2563595bde74cc123d27483dbdf39920ebd5f6d7c3e7a766e315314071ea9e0d2103882e666feac3a080ba04c603c61d41b0607f539c9042363745bdfbb7b73d894b746a7310ab5446e51a6e4f29e391957f2dcfdea91d83e194fdbbe01293143f04e2a37d98db9adad7a18bb635b9e9897e091075f5740c39a33f74e38ec7f604e4449785a2532754c6419f4cbade9ecbdb29dd514417da6d75aacc8d6df0c9397505bda70f50035a8d9299e9d759efc1c89990b5ae230a7e29aa37111dd39394022fc55e22e4837c953c569902f8861650ae988d4d453ca4088ec35216f72694f2a85706d81e52be692876acdea7ff72966abeb7dcd6a803862cbd3845da2c2957403c1fc6b37ef828619c754ecf14a55477dd534aca89d4940bfca9895abb8870a18a085c34c240226c4891ffc068d6f5f84985a6a87e4c54986952ae5c18b411ada49542285b411c0780e4110b1871262cfe0324647ca51dc52c1c52c7b863aa72df21fab9f42a3089dfa5b0a4a79d35ca689ff93c03607d36226124882a8fd099f691a991fedf4c4dc3c759b7468669f84df734eb1b0384bdb71d485cb0d8928f8e3b96f55c6aca6755e6fd9dd4583f9aee55b8af8c05c6bc5e52686417383fc6cfe1144b08a9dc0a89ac0f9fd9f3e3684200e5328507314df32622568d94abfc3cebde601df82fc1771f802af3a496c9f2a5b7510df4eaf8b41ccb3f7eda2d0871e4f8c80d4dc137f7fc682e7197de0bb77f96a4ff29090bcd2b278b28f4c44a8dbc6adcfe466528a392f3ae6c07e1b51d1f3df6ed10bdb02e29c545def5577ccb221e89610a29d5575e41e53465f1e527b9377a2aeeef4c31a534b31490d347af3ddaf4230599b461d47c7b82959f6a8a6768fb2a76e2ccd75a3ecb4f38d8bfabb4736ffa52824f8bde209abf35a984555982b5ce7ebcc19bc7e34c04388b905a39becd499dc738aff4522b7e075e0e6d531aea9756b4c6d6f2b3d58f332686cdda9da3eea72e1615f35c6757bb7f034146ccdcae644a0937c64ae6bed9eff678cc9de948dfe75b26771cadd9410775ae0168ac7b603c4f5e12c55708e5cb6ceb4e563f1505ca8851007e16332c49a8570715943b4305e7b5b5a895f3983d1de1eaceefdab7facd635544bdac55131f1a62949ece54d59c8b6c4f6d945d80bd3cd9bf9c29c167abbe84754a65030f8b3c02115a70b70ee2c3ae2763c19751eb2b544ec7aa8263e56932c6dd5c502e815c173f26662c5af4a24b36dd04c9b8965dc0581909851e8d3fa0db16f6fc654bc49386565ee7a343af62fbc823b8c73f0ce838fb204928d2267dbe56dc83244385649cc26ffaa84c4d87f19933dfcc23f47f43fdaa7e38d307219c0d59b8daf7c3d79770584a4eb522c483cfd1e11c52e6b5e78dd6fcc3f3af630774083a91cf91ecd3731d696b57042342d759a6890fb95bf91c1c4c6fd7cf770e3a3e60c7596be0fb83199e469ae3f08802c3aa45c360f4bd4cf1ce5cdb28a0161d85b6162f73f669e67db9216f28b112cb2ad2f53584b5a2e0407db92abe8669b736724571a02f3f64e51ed5ba08ec041cf84bb4843cb1e368dfb729ac6fe8275e9b3a304da1444e26845bfa84411584ce2c97ba7328f32da048d451baec0f6066cd022176312751caee95044625c871524027e57c12c226818ad632560f727e93b4119e1c20210f6ac4a7202f477e6f41873e868409f0a70733ac35d92db66226663fb142972d522222b18e21375add85fa044d3f065eb900fa2f86003a8b70a23a2b8f0ebacbc88493351e3a0b755d706982fe98c0fc5b48766f283d44d62990eea8d0528e3d4311e63a2443c6858c079582accdb071269553a8842ef831085fbf3cf5d640e58f4129c335b36ac650e9ae944bf85021af5159d1c921ff184fd7d46547bf66a268e569454f00ce63c6848338d541554e09bf4d068a0f820f09eed024f81533466297a4560b850528b9f59b4ce9e269332011e2567937a500d7246525539819d0177fc1529620549c2f81e0befe095463dc16119be0095f7847f4ab19d199542538e062851054d956e4c938b65f4875cda6fea1bdaa26291912b561aa3f4cdaf21b1693c3bc574c36d3c394c131ce28d75034f69d4d533e5c9d0b2f171bbe94a4857f181f244c2393d8b093a8b4bedfb1f8543e38b370b63f245c354fa55849cc07a83eb406daa00c5b287adeac9feb24f509df5054bb0dec52032ed198a7dfbabe99b3d1dd10c4154aa18a5f89842297162d0b6204bc6ac6312e4083ad65e91d0aa121c64ecc2a84d04e834f7c2a94dd9cf196c9b869bb637bfce0df787f1bf63582002e3be917fc1ba13f4be59d3c0416ce22a553a44b5c89059c2ec272b35245b163278a48dc1fd8d4ac82b1668a449a493a70e85c05041c559295bb3700f4c7a193f4440848a8961c59a924d6d95d3b5825d3b91f98d48d36d712d698543d910008808a4880e5b6ae91622e2b81402759bf4ce28e13ddcdd255b408a9d04c5ec434dba54820d278c21d603d60f7d1f1e252d23346da826dff78ddc528ae093aa8c06b3f741814b1af9cee7ab8d542c4cc5c93cc1902cfe47d3212bfb61ebea639ae5b94496826753c7c63d3feef80bafc1ca606281efaff42f2f9ce2eabff74aba76aa5c82e6e47bf44fce96c564ec2e5b65babd17181aa0421507e01f5828f31e63874c275c5f99ad1dd284c9cff9af27f28289d056e18b7c06f3f5ea6645ebcc0d717d511ddcd23fa842b009082e6a8ee33419e6894717b2ac3e4a5c9b683d603bb02c51fc4029bbff7f37fa3056731466633ffcc5274518f51fda98e0ef72995b1dde6000054e144cdde2a85d4b456bf29e4a25f4e0257e2b084c262cbc45932bf7bd348c98c41fecf05b6bfdda7d8cb66067004a07486c46293a9ffe4d4a0cc4c7e3a7ee164f6892216567f7b10ae89387c8f9f70714394e796d9df7386c6d36cbb4ea7e2cb0cf447f03ad607bab5cb4445e7257f18b3a90c628333abf48dc789960d49f42461765102d9bcf1b90878b60c1bea8a0dd9cee97ebd39d5f53daf3929eb93c90697bdd038f6c2213b09c80f3fe24a911788868301312b928d5324409e8ddce1188893140f9b999ae83a1e78d903976796ff9a43056da72e4824c7bb256ab8e442ad341a89344731e3d6ddd386d55c62462fb439dd78fa27d50f4a25c9ba22fb69114c2dbbd0b24ef5d9108809d2794040a50654ca48123043d3c207dcaa991365ae1f176b3ff8faecd6f8c66be3227f23c7795c5b2faba518b1c915c9b950d7a678f15559c071f09936be71da62c4199677622b45cad87ca2df5a90e2eb4aa7748a15067432ea56182ca5152d6c6c4732c244d1724fdc33610f7e96161e059399a88732dc3f6766a7c3ee4e54abde105d0ce8c489ea31cefcd0e8494321098496a5a6abac5d743b57748fc71d393bc5db063ac79e9b63c5cae3e7059a25ebe487451a463b45c2859686a9857fdc189e224d32460f359e726fd4f178badc45030737632e359a630a61125b4d78b2ee671c78c2c0980e46499b7d6fdd1df2aa8c975f02c91eaf61d582921e441594fcf1a4c4b26f4876a10517202b332d7afcc1305d39af1af50a134e48a8ec05c80a89a19c5c2280c4c6595c088bec0f6b6d8a2b7773ffff5fa140fb12e9b6ba8c2ba3580528d86da0643d43082a58a379cfcae660ad4f485448290d6b2b8437bc51f824fc24ca064ad78db503d467faaf32ea35662f4aec10a0296bc344c9d59236e2e9330e9ee1c0b9d74709cedd0cbf5a743fd1c766fc9acb19cbec868f72aae868752e4b6c1eb0d8fc874b6fffe0e0426ad3c8858ce845395360ea98b4d0b0367afa289d1f55068037520015c59d90eb4763f766eb21fea8f61ffdbd8c31c69ef023c8ed11c33a715682f2edc551645d4ff44299e44cc2c0d90683c945affb330ef0f0e3996f847fe8b76814f41994b010fd028d1bae8175865e595fc9ae5f2654604e8dec12fa0345a566136c1566b331d942ad8ee005efd59317f3429ab5401d7267a042a82cdf6f47b72db8d2e21e0f9a094ab5a187f688771a6193208c0f254996466277669ee917713af2bc17b88475b73c16c5ab12009c2dd45f459436c3d3c924f63d607ec13310c0d02bf5a740ad2107f3c051585ffe231c4c628d79778137a7d43b98e863d9a39583521924f337b1fdad5d15246cfd1f39129070eb5c4a8e8f4be2e133d9d39dce2d898ee05c8a90c0e0cd6829c592dd3c06639e37813f05807bc82e984a8885706e9b2709af0b3512a031bcf1c360c2875f01be69465ad58e1b542aaae848dbf4c115ae910f805405ad90471ba1b1f0d7f51980af7d1a2333ba0b531226a2e746ab1789c7894f7246fcff9bdd10e0e9cc18cf600810cb91e90f7749a8c806d378f619f6419b5e656a51449821262ab75c7118d8a9e819ea9a78e17dd0e8c8a3e4c321da000448155b2637a04d36848af447508404b44af95069c586081d19ee10edd31e0ee4c4e37108e0b75ef34a503061d95f68f569d06d61596c0af833bd130f9c1b9c9640226e17a8c5966645b694b14ba0415c275448bcfd782ea5b6655ce2402564c6a760226e73e358a5d708c5a209dfa13015662890d3f8d4d0e238c395c97881ab813973f711883fa5ac33b81f968c855e90ba56dbb24655f86f0d6ca644d39e58f1897f7b0a7c529dccc056ec3f7a0e34a9d4b329eed791de6772506b77aeb8f86b16a15d6b60512bb285cf9c2d458e407b7251498b2ab89bc2125002c4a293ce810e6553ac697aae362a25a468d18d43338b63f070b174612c7a59c8876aa9f5f70a4cbb1235abdb33591a120aa31559fe83bdb9cebb2106a135c4d097aa4e356ea82d8ed56977c3c770b7388dd192d3f34fdcda673e710affb86309e29f1e47ced76c0dff9cef1d7af47ed07d6d25e81da59d64fc746e40a3930ed5486af262590e895a353f0c667be24d7b6c58832c7cde9aaf2fac2c90cf4b52841dc240873cd523dff8fa7c627c24bbdcaa8440c3235ccf52acca8966e383e2e12e372f740abc53dddd473fe4962e3169517090ca64fc65723f267cee197cfea497793990bf3d6dcf62a778b3e3b40164a7de8c8e8dabae04e2ea55c36f9e5d77da708d0e69ee7c4c64efd47c1a170e341a574d39211d9bd21188dae24b7d2524aac6df7932a0852766e187ca4c0401281316acedb230c87393b1d62d151783f0107af211f1713aeb145f7243b92d55849ea6a0c2d43c4d6b33ab68a8078a38c3d713b949116fe536c89a384095a5c717ed065265b1854aa17f8fa1b49db1e94f3c65b99be4329df60f783e5c9677bd64a2e1c2ef5600900b2b7faa02fac8cb3ee509c56c8f1d2d1d0ca6f6141781690ec1dcc63cf4a8de6655091d142a9b71aeb18426048535f68a1dfc1b4aadcfb19b5a069fabdded364f387eabad2eff0490e582c0e786496fbdd3ae9820eea2f799b05071d9f8b9dfd817d86e905bd6ca9187e081618c07dabe3122f73bdeebad1983c78aee5010bf4dd2214ea86c59e592874bac96c73a1ad3f61b2ff61be0df5b08c3021a1d46e729106cb6f3be8dac5a828a9c9bd20c597dbd6a5e376de33fa8c6aaff8250a297d91f9355519acdb024f0c06130449c8f3de38aaa0e235995968c282c588dce337c064e1cd0bd10747fb28270d2f736c899393962882e2f0e4709a9cca2d007039537f19c3c7518e6f65f798055821269d8fcb385b93f406dcd91a539c05e43514efb80d3bbbb4e3bb23370ea0ddb746c616f209b4f64e5d13dfa1d519806418bb13d39ade152900d0f9e724cac8253797dbb56655a69ce167239904fde385dcf12b9ddc20da969aef627a6299175a29223de4f8f63ab94eb209c3b1a87d0650a87a838c849a40ce71c904577a5ed97535cce8670cc28149656e7fe0d7ada0ae70d2994685d739747c9ae252eca9ca3747e6623317514f0c766176b15142d32689e18534719ea1550ac0315e9d12db3e2f2e1107224b86b83a5c1c66b9fbcb112ea7e21dbee403a421b0ff5020e25989dff4f89036d85568691ce16ccf7d81fea35e62419929427e01e61704dc2567198151aaceba97ffe523d5953322a281c16c422a6a8ae4aa113b19e0640919a4e5c8f840d750be11abcc73b75cde857e9d7b6429f49f06b11ec94152648ed7cba66dc91326bff046b3f717ac2cb3236d293b21d91e95537f3324f6c22c7c41fe19ae0b90c97aee4a224101a3b8fa85b5c4a2f4f857227fcd59484629625d3246bdbaa1724f6844c9d5f8b61d44a7cf7e9b826931938242b5c42669315512c3252459ba0d6331488fa9debe44c413fe6dc339db773e43002dc066c0281d321e16321fc903955b6857c8b2880deb7b008c8825905a28422f8c8a6f1dc8e848351a2dbf53c38e8fdee63f40ef1d6ffcc2c2956c56624c5e681f955fbc7f95b25da9b3e9e87517c274b88114f96a5f43661f598d62c732e8a8a8515912e45b9e672268ce4c84668ba6fea7a2c91a1639bc6a8dc32fa09daabde84671b2e62cd995022e4c9360194fc027f539b1f4f43133d90d95b343937bca095d0a1d8425c73f187575892bfbdaff52f4818ba6c55c875a758fa987fb2e0e2fce594e4311a02334f6ee3f132dff4d4878a8fcf3a153c71736db6e471a2d7b3eb8a8da0c26495ec92c12e3b031a7ff899d67cddd01856d4d294b0831a2155d4f894086b2c2452ce0172b56272b2be74ae8768448c36b75bea90f76388bc88bd8c7b49c889eba3b3647f53f8a7cdb285ae23a7c62c9b521b0a993a23aac58dd512dc8763805ae49af4b788a62ed96fdb7bc3245ef94f05b66afc5220d5007325f26f31bcd954b9d5727fc4b31d0326af32575e904d715843a550c8928af9b5d3fab8167191150abbc1b9946d46e149f76d5ce5504671601012769f851dd2cd0595d2a420bd3561a3234205bbbb29486f6330de5e1a3db3adfdc4e468d3da807e37de912cb4f22f02eb66fed67e4ab38a14318273539c4e2d0aa6915cdd6e0f4e3b04c760b817bd398ca66bb910f2624ad244fe0bf10dd368708f9f4e4ee4a08fcae279c93ba944b4910002ca472c2c13dda77ed6dbe3583c348f4dc192f919e7ff864e3087b0ac1bae6fe603247f1944153bccfb1fe052250017566a732bd5213531182f94b855e5cfd229480de1ee7373ac14fa6869589e604fd66b0895549fdc508a20c5906b188f6661605f205503e2fea483838b28844f778b226ab931f78c03c4e25e41bc06ba582c535fdf01fd6ef65dfc3064281b90706652000311994fe879d8ed6987e80504f2ff3f557ad521ba37f984b7ddcbeeabbcb12bb6cd80fc4df200aac85c41af952e5690af10b55f64befb343e9509e64410e5a6295d23c4cd4472a407381d1e96bbb9cee5d2cdf391003ab1c3ab7f959b2e13041dab2a1c846d7ebe405fafad0394bc459410379ee2076625bcb68b7c4a32facee6ebb5919820b41365944c6eea9be55c71db9ed74fe988141cfedb96095e7e94943e232d72c76f835cd0ad21a03862f9f8a5d5b9d467f5bcd93d39ebc3528a6272aee74d247acbedc52ed72aff1d4ef7ae4042a7753673d5d609f75c24cbf20e6b2a0a4edad9fa7658cc428705066b02c19a119dfce4e226595df7c546edac7161956110d515e157a556bb4d704709be5d0f20ab00409d57f2497fd6e85b5e12f90e0e287b54d78a5ce68af2ab4bcf23bfa1226856bc66755a38f1ef8bbf9e5c39afa9b26535de6ab412d6a4d88f7586931715d7201e8599afe49203d1aa9904926f1ddf068493b00748db58f19f5aa462b3f0da6534bfc06410e2bc45c9d5fcc2ddc018f1b08290ddc035eefc429f8517a8c2985fc2aa32e49d4bbad6b0d9addbd8aafb1241a6200ef21819896d7f3cb99cb247008ff37db1e353cca148f44cd524f700a3cff3be3820345631c6197808522a91455cc0297d092292fc7d510d16d10f9022ade1d77f29f6941a1e0e49275121212da94731cbfaa6ca657c53cb355ae3440cce71d7cade0e1e8e8e06313fe8afc567660ddc19a94b605bc969d2c1204222cceeb333a7b51eb32d49c05a501a81e7ec5ff684ad5fc6deed8c9ac5e0e5d42890653313eae6a16a6fcf635c318194e7cbdcd00fc657cd938f960735feb27994e7adc419103536d39f53734cc0d4b36c075712cd6e8dc52a52c3c66a1e10807da89e343865c115f313347b6497d17fcba2970b292e6375ee7951ea4a073aaf4fd76a7d1911e6b9cc2f09dbb49950229daa30e082c71e31d152fe953ecf03902f502f7fdec6e4e53f3e212ee31a5e2f5678541eefa7087b22086eb11fad9d805f178b2b98f828ca3856741c03289a01212ba0c741df7c8efa9d57bee12a738eff85f148bbebf47acc32a1f8e7dc9e841b4690b213c438374e76047776b1e03c977a711e98ce737f1913757bc3280798bc4d9f9fe7fc2357f3e44d5822fdac3069d04462f7d0b9aed0a19890e6653e44a4f2b8f999d36ed334a7c44621b04389a0fd82df9b51f140c3fb058f8cce355da744a38c4c04226eb02cb228d41e22f403afec12e958596134c35f231aded03b847a30fba96b310d59dc1adceab44256c8852c5a5533d3b9aa18b774443a9345df18352accdd27808fbcfb1ad1fd8c790a17c9bc32e9b59a59ce541916ceb0973e928da2526524bd7d027a8d1ad4cc643664f27927886a99f62126589219d88227b3573eaad358cc1ab1a622aaa528889b7eac81c1cce785a687a7fbecf163c23103ae76489fb4d75b25c9779b6d2e335243b102b6477494e95bcd87d460bb4db967a66b1697e15b379a694a1c1ae28f88af645a3bb53298ee3d39ebf303cd1a769e1088a33871a6d457e0e55c1b327844ac292240d5e4523db147775c665fb1ccaae3e42caceb9db3394740249787efa7ea80e08a47e9aacaf3e1a663f9f6313a8f398a9cb0d198f37c53b90a13d8dafeb0ccd6c414f4c0c6de4c90f2d1a3bcd9ea45a056d268f1807d97a8ec5313269c03284cda28475838e1cac2e44c0744ee46b7f6ce8b4649f53a27d9c32671393a4d695e438608622b3fecea6e31c22d578e4739e564f2755e8a988ad37412a9897cf14fc00c70b960847b4df075706b82f4f8d01f0ea8969a1948cfd8afd3b74318206de42ca1b228642558fbec668d22b68861dc48938efc39a954741feb783fefb48e0e2d14a66fbb2e6d9253179235da1c17b30f7c09bc6d8a4367c84b7d2c15e2daa9bd18151edd9db4b0fcdbb168cd9b1d7a7625bb20cc550bf2dd65b6800670705846d2f470d1b528371ca8a253d7486538277035b7b1668b9e93244e42316e1e4a35c0ed1c6e918a4c4d9236c95e5c647e46b9db47de5f6775d08c79b5f509e093fad57208ab71a18f5176ebf1d06aedd7acc0b746920adc04c9aaf7e8399e03ebe018c65a2a3ce6815986fc764169139e1944ea727bd000be3b5409ef9155aa6ca95878b4a505013192326367a81560d253f1b1847e5d96ff24eb5690ed9459d23b54e9a0f71e454f270b3a3fc7f82b8a4d1632260b85e2dc388d094606a80864df2dc5e331c0161f7c2a2da08765118c8a94562d6b3e519182cfaa5d04277185794059c3efe6eded4f03995c62b416832dbd3a547fd5eca31aa07e7b2e61630bcbd727393efa90d1bab6cbbbdc475fadfe9a44e7d7425ac1bf5893e781b2966b91fa6b5fda224cdc2020eac23455c354613dea54ea9317d7d129fbf3c9ea28cc93a01fdccd500e0363c3d7be7e1de7188e5ce1fe947e369ae05c9af08dce9e897c38412b306db97f9e9a4d06eddaa0eab77d743fed64f7ae8512489f3886d5470ce8ebd12577b1cb08be33740e599f765d3ab0a0dfa2f05a3f7ca69db9f5af3fc6aa288591d5554d5243b377c2277283d349820eb2bea7a5635e03b2ab86a1f0eb7eadc23b0276369eb092409eb9f63609e66992fc462d2e8d2e4e5e969260e672b70d10dcc83e864f666e6b7932ad3b1856b1f71f475a16b5cede7a24740d1fff06552bdc6518a6b44f1c9a0fea4865913250041e0a598b2ef80f39477fc27ec7494305ce0d0ee8cfcbd86b76ddee0cb76fb6cd40b3204e0fa7ae8222aa102448ce00153da7b2a60566dfb1ea930b661e89c0b0ba22de33e7ff30312960ede84fb1157afd55c87a43026b126f73f94ce991678c2f5c2d0e54e810c01ca41c2a72991003fe76b909a7bb85914d83ed7e07ca1f27bc9b5bf38570e02224fdb93f1efb1c11dda1195e0a18badffd7a40abf83ecd573067e4caa492c5afd0d932d1790d91cc70aa52b221726433c386ab67affb2bce09082e825643c1f9e904228318c1d9330bff6420b86630ed85d695758f9c5d4f1c08be8ee362fcd263e80341e67eb297c1496e34a0f4c2106adf0dcdacbd409032dedc0bbdec19fcc86f9f9b04270a280253a288be38382803ca21bcccc6b99bd0577045e2d4939ba9c9ab7c4f2b9c37d1195a2c82224e13f23f8e020951c80d5a751964b12ee4d66d0017b4700176f03f5e31f3857064f4ac51877354efd462d0eb0350615f9d326337a4f0a00f993e0392426a23f92f466d4f07b30531bfe883d5cc8f91fbc16a74427a22270b24ff8830698a02f22c6a2fc825ed720869bec328599f33f93eeee70c00be57e605d6eff003a31e0d6135b58d61c40534c4587e3b9165262e9fb706e196683b2c3cd1f00e53ce7f880eaa8255798e3ba719ca490bf124a009bf3134aedf6c383cc0cda3edc50eba91d649c603b729a9398fcb12fae2f9c938f9961714dd9943df520caaaf8c28b922075467dcdce22804fd587c1197232299b56be175ad9931297e8007a0c458aff5a7ceaa310b0f87ffa12e487985951c4870504464b3c4c1c2c4027de126d7e48d6d3720d46adc03b4aa40e7f8c6a0930b8b0855e70cd96ea56c115290f68bcd62d86f639aed98f0316426d47aee53710a050aa5ed04d2de5e52c7842013d321282e15cf421d4897bccc64283f7d008bf1a8e6365b039ccf301950d812b618eccf145649a68968e842005b5497efb504a969ebfcc428e6a534bc4aea38d9dc0e0917398384b55f31ec255f8b1a720f8728136d20a213c1bac934fd2c7e1f55456005ca370066aaa62aecde72fa843810f64b475b3d8d4340d7d00cec1cb211c53a82e5194ffe7c9884d09e79bcaf2406e821443d24eb3ed2c4994537e5c0ebf00fdd1dd582d00b1d6089995ddfcfc39bed692b21421a2d4398d6fede843baf9541f0e3e9a0cda0f7af98efd4c85b17b72ab56b5700b3694798c2317c30f38bcb63d52b8d9b41a4108290e52580524a242dd6a9588294ca0f02e1e952b3f3b6da8a136182ea294780a52c288ca74da9c7ea6b6bc19906b0efa74ce8be12d1b45dfec5900e4da2f07392ec26177c22ce4a14f17bb66757dc2130b052c03e9c86e442cb1fd8100fcafb1b09c177cae896b5981a552186c508345200cecb0b4a763a1eccfb6b47aaf3663cbff1fbdf7f396f2e9e962789ed2a516701b516c6c782b97ab42611b035dfd56fa664a5c654739e80351714e766296c51ebbb7ac4a3b449c6f51a5c0a559de16f16885ee81bde4f26f43b89841b2b72ae3b30ecc028395c7f3a9d893303ef854a4782241a55b8d16bce5d85cddd002a0485c85eaacb9c728100d001e30f7fac23757420ccac4e4969650ec32780f9bdbf5be43dec11399cbec60895889b2dd68df548dbdc30fa36f14a2d9c04ea1a3680235a3ed1cf0e9437acf941530b59d5e8483b0192876d598cec48e197e86048f23a3be2a36c08ce90aa30d7abeafb9347a49ee26261372457f4ebb999851a00e2e9ee833fdf97b0b52759a8f7b904c5f0f67ac54a85534f03741c8bceb272c941d39af1d95dab0406a406b771f0346fa7ab9dcc4b99262dea5a9981b669915aa140393da78c4b6cc20ca6f7e8f0b1acb55c3a8b3f814ee7853321a2fc2e112d2b30a878e16d741eda66c7344339ff9e04c6e5c023a0a1350f4a538fc27b3fe2308d72dacf59cdeeadb7fab63d38c12fdd11c6e8f0743759d5cc1452ca3f87f69bcf057f10a3cbdc5cdbf924446bdbd4cb7cbf548e4f52ba40bbb515333d74b8dd649a80209d4f618c03eb615101a5e48be1b40941859646dbc984b720026fa6e5b94303a0052f9c25c9c97ae9fae7f1f631b14710a73013bb73541675921b2875b002e5d498d08163e82a8978f6421f2193042179059a6f8cf9f3dc0a6c94ae674950b75fd733b8de98defb32dd307f9dd595bbe53f347c3df9ee350eb49f5676d1ee28fa17bcd73a543729331d6b9b2ca1128a324d2b257b33a0c44d183e00bd4df37883658395c1907a5a80542fdad5ea9f93bd1dc00ad0f38415054a18ee88a98f2b5256103d8af4c899cbc115289fe9bb4f05868896de610ad166828714ed12f0edce8ae84bb71b32df732b2917137936e6eb5c7b40ed0bbdb68400a4193bb5e0741661b429e63a228366070787fbd0c33cdac548a9c335e31c47cadc5a83c867d25ace75ffce4975ff9fa324bd9c7908405a0067eacd11a4e5acb9ecca70fbb544a24a9f368075e984737f6bb896c1c8969751815b254e23897536a8af2f890e156e914ea713a0b42b0f6ca40b82f2dc83461242700a44f6aac6a8701aa1ec783325d728cc062ab5f9d9e2394adae03759cfb6df5e01fdf32ad9ba3c1ba29694d6b1d8cc5f715922a0f4c5eb9b003f40b419293450b7e92eb064f51ee529f88f0ef22166d8afc76c62285d316979048cbdf68a881e8e57e87c7832ea0b0004ff8f1e1f9a568facc64af15ec08084a425695936d98b6edc8fd7f4c99cce997bc46ca5f59aa1f4a1162fee93838010bdd0bfdcc6ab2e25708cea2f0bc2e6d051f12063cd59474ace729c649112c8e626828185e2d8ae43b824935bc04d74f6f629b25ec667392bec135199e21a2183160ccef3d5545ca90fcc417442f8861d73e5cd2ec51ea8bd42b4addf8db68ea433385ee9f7a8255d2436f38501c30b838e42baa5c4bd892ead63ea69f453e17f1da5e3fdb1b4bc9779558773f6e9cc94caa8acc9ebef189227d48df91b2db96ef07b4070ebdfe76bdde7cbfbd8a2ae2808654c0c2f2c160ba6974f0693f6e7e4daf17cfabd8f2640740a4ca760064f28906b67074e7b07bfec361e3af49bb53ed9d15f40f27704bc5fc3805351e848522ec2fa942507ff92261f751318dc481c86b3db2b562b036ac8030990a9ebab2c7990a36ce435afc5d2c3b40506acac62647726d5293a07dbf4eb1d44dfdc6c8286cd333427806095398c1687d416eccfa2c7f9b04c33ff738205e55dd2aa5363e357075851bc158cda6f1cf2ccccea458e021b70c2ae5c2e0a04815e2130f32fb99e05b666e7ab53d2e6dfaaf36c3771ef4cacf3a135347f99fdfdbd555ab509e8f1b53c6cc24e19f00fdbdd8fcf8bdf537b3a940972a00db31ededad5f8082462ebeb02089c79e5b8dfdaa1b50c3f673fbb44ec12033357e6643fb24506402d29005057f3747fd64dee16c9c8dde565a5ccd310ad9a7efadbf86a8e4accd2139d94af6edb03c1081ee43d47a12ca3d3681e3b447c0ad3391ae947232e8c03ba2e4673c5a4b775adf247f03dbd7471d9041ef25dba3fb5987a29aa1dc75af71f4240a4590c69047d9fcbe7652754b92807f2f9f11dd6920170294d5d972aa31fa57659c621e4d1cde53bd8843e1b8d7b2217807c2eadcad9c504cf785247ede4df6720c487d6cb05599499fd154de7da7ef7cea4a956004f021d22723fa638cca959ca8b21ae02912982c8e8563112c8ab0ce25dccb95b4273568389373be0362ae1e00fd307dc3badfde659af377c5a70ae1f4837798ab369aad198af7a1e6a2312e8328ee21e61b8e2c2ecdfc47839fd91e6b71c9a9dd53de3e3d622a9748fc06cfc26ff671600ebbc79e81ffdb244a2e139d8dc26cbb1d59ca0bfcdb73c48717bb43386c3462dadce036646a870bd95a7e3a2759e6e2dbd0ddfa592f01d1fd5284495f3d4bb1c7c646e6ee590a22c5ad62212e9cba0311fd1fb150d4b13ed272fbd6e21e33165604c5a35c781609342fd2f336941e121dde1c0b925e3934de9d1601b8c23a2c728c557c47171e682f9794aa5d399d38ab5ad73b6ce8b5513658ff126040aa68ae8a37e2740a08fbedffc262378b63d246ef5d904c6d6c784c556cb80f6982001550fc7001cfb2d8991b49003ad37384bde7ba1aa1c281fdc5ab99b9c3a7f9649c3354df226f3e65f6c0c8fa167378b45489865fd703f8768ceee20930f98c4fe5a04c0de50c7fa5492d5545e913a5128c35ddaf037406f7888da3c41a4e2790f6704f3d6fb2392365e5936f98294e134fd434074d925c7a39837df65804c11ba437aeade4c9af1c3a24bc1e59f393d50e5f8481da17c38b5c033f63ac2128640323a3b68c49b1ed2b25a14cbf786e85317d4d7368693ce11361e0b69a150d500d125398b7a623c88fa946422cf092c887c9be2a65b398dd1b400672439d600e9b56d10e32073270257b8f63da75e34d9122902819a3d58bba886529acc8825b166158043b69be595baf2afa33adb4c555e5b06a544a9ba8e06e57d5283fb9ad84534374907cbaa8bfba8daa34f1046a7708cbeb120a132dd12a0670e915fcd4f7e8c71573b27f1d0bd8e4b164ceaeb5c0b1654e909d584e30f6112e8b391f710a0e9fc0da4231096d633338f2885312915db0a3bc47898e950431e921b4d248738dbca4291a3c0225155d84c45103d2c45a1435afae134808799c73354eca043524c77120898b73ec8cd9384f2ea61835c716e63e6d7d885062671fa4d28cd405105797a28c2706c09510122ccc149a6fdcf54aa54de92e509c834fd01a7f82f96eb251f3d3b30d6f6c337f7aef2b012471a0a1d38aee51fd9a96ce8bdf389053d1b8d1e929fd9529983c2d7ac86cbef6d2a832eaeb12a0541bb4c12a547657030b51f0ce4b56da06ebf0fe08d96d27fefe85a4a432d242d71c6779ed54fd3cf31047de2c66088820bd66549c634c7236f908f245dc42a066e360cff7b29af45eab3a947093c839c7ca3b64656beb10f879283de0924e826ded008a914e9422a087ef6216a22313d31c7d2d9f0e48d02e64127adafa843f01c07259541d31b755399eacff38912cf71de7c1e9582f0ca8d9cab14ff09b68fe00c970077dbcc318c87ebb2b1563607d19568eb7e2018cdb233f49c776d3da04d92324811818c933444a8195dfeadd75ac2c2026b9cb561527006cc959f8ac83b114fd52db2b8d34400b4b10bb67b7c13fde387aee6e2f90f0ccca20d9504535b0213daa49b4e11403b168c087ec4597ba8a491183b883f153a4d6de9714cdcb85e8c1dcc13c98362ec8d0549ca2efb4c94224163ce0405195db450c5ee088ca08ddde616fc9c0f63ad7742bc7afe9158be135e043b0217199ed72c913cb823884af44de3208377a8713ba1d9f6f44e93d30930d4c84eb4b45405693268cfd35539a3d541a7ac0adf72037c1a8b450e6bcd1ee330f082c8f9770e392ead87d31e493c53c6e4a1bd51a40e7b0b67ed7b045ba63eb2123c976d9c9386a8ef4872d8c84dec18abab58ca5c565d8ffd3f05f5a1efdc6d5c3491b1e72df4d4eca0482f42c331923371f95d7952e34ec13b99b0aef2340f6e0068e56362700a55469bf293678f16d39dda65c2ba8ab1becbeeb362a5fd222d5aa227f964901d17ac68683d295dc86ab2d0298d71529e6b241916d880567491d82467a7e5e9c0b2856b2b3a4468ddb9bff3f2bb69c614cc6cf3936f9c332c63b63222a70cc90c2babb45d4ace8c661fe1d4e6e4bf6d68d45998ef42cd0abeb4bcc02e8e86319008c7df10df8447a319467c6023e17ecedaff420523089b7d8d1553ba2731cc3a51a2391482f4bc3f85873279fe215c58ead04fbc9c35aa44810c9ef7ee246f70c68d4147a171be602a7365f3920215a3a09048c7fb8d5ee98ac635ddc3bc7847ea776df0353dc50d87fc6912b671ca5aae28a58bd719baf636bbe046f2f188387605556aaeae323ce17f300e56682e1941f3e305d7fb4aa670ef7c33d08cadb5c93d1164801f09d468e44ea6eb41883374c7d18bc6854ab9aee8b9df4836c6c42adb7587b0303e72587691eb9ef0f1a52c002845291070a21cbbdcfa1aeb32376c740efca2614ac9ce8c6220551a66b93932f0f50fa420320846338f479575244a0b07cd1e4ecdc3c0a379aa2db5741a9fb97edc6495e9f2fafa492c94d7af00188c8a09015d8912226b9517870892eb7d29c2495724b28991192b8d507222ada5547dbf42527fd5ae7428311f8124b66b04cfc5bae06707b48a560a9ccb7ea257a2d967d791f35f1a4a2057a35084e5eeb47ea4b77542884fd9e1661da11df80e1fac2aa9c833b1f280add502c2413bdf0289c4dd4fe7784286467aa49e8346f98b4bbff63b5793422eb538cf915dc40e04825c773fff66f296d6a31106076099a414f20e7afd81b14ba6eaf20cc6e4ad4dfbff048cffc219200da9873fa24830934ba8bbfbf83b7186fb13808d800089262457055c6985c7ba9fbde55fd3884453995fe0b2e6b82d9bd60a79d0cd64edebdcdbc6fd929921643cee2664e292cae1211124bc4a84a5e0f64a310f26566a2f52043225bd982562d3911fdda5d6d611032667ba02c5634d206a775a255a53a430a67b792ebf45d26703221275f9123af20abd4fc336996ed3480faf880245f8af185da71550249388d25567ca26bcd50137db2d4b30af51a06dd5c660d4e9fb6d9b492825b1460ddef4e8cf9bc017bb697c8cca2a2460ced55192a78e4bc1dc5da88633ba7f27d6d7b05e4f4aca0880ab27c19d6aee5870eaa5199d31254207892f1e7539b2c519f29503f50c4ece48a2b3a52852686dba76d4f7f1f02a3eeaffae62252aa584284efd5852698f195d5716fbcd20b19584ddfbdf6b61493602c36fa9a87c4ba388b692dea00a06279e01c5865d5075e0cbceffdccd0b1d62fc9c5602b32fec1205c27761c89453ad36321413d523c1ed9fd4425b5103e9c99613148b24643b33ca61cc830c454b874e8905c39c0b46edfbe47c62dd53452f36f0f565a8b66ddb5415d0ea06b37f8483c3a0ffcc1a70966a15f3c34bd5ddaf57242ec70b2c768987449c991f063f1292a16043f63e3dbcc4aa01e4bf4b857f9160243327e10ffc44e10e33ed3123a8cc1c334f409c8acbcda8490d83711619164a4d7219aad006aad41351642c325b0e52d5ef9bf9d202b1e4565ac33cf8a1bb351d7c486af8894b2c849f713d4581db3fd5c1186ffdbfc4532e168ae9cd4854fb53803a278e2efae9e2a4e5dbcafc8b73bb52e515bbf0aef4ae7de8365543137ed9cd508722f8834e59cd8ab5acf40dc7a83fad6b115997bfbbd152c64a7601db022eb3ccf179e7c88ae8033ce53ea12856ce255b871a836c73cd7d288e5d5c39108081aebb0092639c8557ae36845d53c2e96cc792b4c0106b94b9f8f8cbd915eb6fb3dbf82228f4a69d0b0880a5df4248077f0b425afe2de40ee8e997306e0a7041d659ad3b814b2fc3635230c93e221215cd711791e9241b5b544ed9fdd9f9f0fa28b61d84829662c310c1256c150ed652166416f12354652128bafbc8d8ff0c64d5d84154ce31f8d11c5ae5ae921ad6e57441a2e44b595c8d4162a6ffd515e2a7961258537a1be938287e5e6a1169d8e042b8ac02921953d1bc4c7368aef1293699295fddbcfb6771b568e574074ccdf5c6096e758d98e4eee175e1e15dd9135e5452e62e648090fdd498cdf342525719b07ee8d6dc6888cdd7c5053c05c79e9d40456b0bd1b7e9d45d8263d2e73cb11c79356522adfb62ce1d3d10aedcdf36cb17316bcf6ee29d4209b7a24ebb534b775edfc4585d37150cf03606b4211334e74413d01028ac5a214d5aa10b5a0ed7f5baa6bc270402848f930d10d004449f0242fae9734054ca14c22d40d57ed7e92a126050bac5f6bbc4a6d776e662af1e8856ce2760ae9e359da6534fd5132dd45d16c133a746d7569269db3162d37511e889d1497f1af7fca4218ebd173f1aea4ba3b7342ae3c95774c8154c03222250c5838c7651c18e27eb4520bad88139bc4051b0056f388ee66d5c206ffb53f86851eeae417754ce9b57b3cc74c18076632b1985b1b11368e0549dfb221a4ebd131d60bc82245cbcb75731b1c1592a46bce7f328d4de71abed21bd9115c11d633e3080296ad1c5a67308b173d89f9505511202eaa8a2147b742cadf1982824f98823800004aa36b6988b4628c667390f07b8fae18608d8c7dbda44b6969bf0a9aee90e809f1dd4c784ac16d5fd29ddb675bd850a82b6ae96933faaa3a8803bdac984bba1c1d140501757b8c12606b809b0ad45e0bfb6838954486a29e553b816a2c6a9136b7a7578dda8b6172961d348791eac5f8f376c63c155cb13e309f35cf281431507239f30d3cde665938ac48f5a1b4e18a35c88874a823a13c61d1c44024a4b60c04c3ff408d67a602f08df38412d7df634334c3fb42104be47e75a1bb941400c72bc2d8ac728c583c4915235a6d9fc9c574d91ac22585b942cf69bd83fee6c5476bac187b94fdf3fad472f23066356190c7b2e68143c6dcd2132c0851d9752efab0828b9081c8e2e173adf66ee96445b068a30e211e9cd01f104471b6a1751125ac4178cb614487d7a43604e2cd5ceb29fc824cec5251f568de8d17302cabc5cf47a5d0d0cab6bacdcf9d14887a9c9f922c3de357373e83c2178fe976a1a365b594c20ab1ab18f5f0c13b07d2c8be69945291f9220bef3754b55d340649959c3d911d4ef49f5c6f2f85a406aebe6565886c0b6b25e51b4745638553dc00d56b37803ee4113da61857ebd1ad1fc012f3f9fb0e1c676c49f7096dfabb8b1f53d03eae90a0592d881c8d3f8f058661fbb80d10d8669e9a10b30e86c9ae9949bb6aaad71e1fec235b810fe469b65a024e0d6b0b1ac84d11301d3026973e1c7bd173a9cbe7a73d8d669434df02d97894415b4302a323bbe7367d4825c1af1028487004de45b5b75ec77af3f5cfd5fb702a547d53814fabb8e57039c807f2d484bd2022edcb85e374d9eef2736f97e0343960b9f7da0a8de9f6db65d646f2143ec71f042905c702591899c8023c0543dc74164732c549ebab0d25b8da99d26a7bbebe146f2b7ec58df5ab0b4230b5383e4c412d802f37b0fd221dcd491ab8e9ff4a5a153be8c7b3d871c9585b6bb44ab2c3768d207b8886f36636afac441ea46a85715cb573f874e5d4fb47a90ec551323ae07b5265c9748d4e4e95f62bdfe34939d71f8d7597cca5752c7ebbca0ca85e5ff8caf0957db188795e56acb23b566c8fe8aad0bc60250cff5d675b1adb4d6b44332755d010a0bb21594b2fc51d497bd33e4539f859b8b60d1782e457b41270b31e78ce6f13e67e559a3952c93566a90493aacec5b12487c7586cdd0d159ee0ea3776ad50fa5f8cd27e59808872c5161b60487b32cf8bd251c0a0364db211b8ca76b8d8558e102eaaacb8a98d6bb4885f34636ef29ea2416920d969699a02aaed2699e3c3465f18ac2cc151d0ecf405189b6d781e87451bb76aff4102a9332ec022314968b0163e2b08a39a967743dd34579de202cc8b4ddeb442a73afa3935a2d20984c8077f3184f27768cd8cf6da2d67ce1ba91b10a6f14c4acfd8a0183e1ab06175bba9dc70a5d5b4942e6b4510f5107a4d7414e1a4a3b4214c2ba888615b30616d0310c10762b08690d588f3ad0ae92d9ba3a67464a6d8711c4698118514e9f41bb01b4cf94d430d3ff66e6956745e40aca11b4fdfb5474bb4ad2b087549b0ae54ae7f426b5a331f18ef00af89dcd6f5b0cc952c0c8d4b3afb60e2422a1593769220eb36549cec7e43367b51d3f7b36f8af1143253dee3695c69a52402df8bfa2e7f062a3c3871c15ae34edc92ca6cd4996e0a93533730232a953cbbf76a49a111af463425b87d9a057c89042d2a12e796e861bce2a3a64d44f8051484b17a1f84773b72124e368b3442f4bf3f83a5d5bc02ed574e3701a2673cb77d0d96c3de9b6c0106c5e26d7bfaa87c3761f59d7f318ab69110fc933b6104fa2cf127b22f0455622b30462a1a4d6137c347efde6e2a90f94481c275d23544745a75dd46ea84ac8a1460f055ab6dae395379ceb97791cdd09057ed676a07e11bb43f14748669c9a9e9df10b299a68c11286c552f9a9e230a19b5a82b4bf577e6df054f42ad9b52e34e64961efc94491e823bc35ab7c5011a3daa8daa9105554d11b396cffabdb0a64fb6c512481c51a03112dc5c262bb64dfdb9fab188ccfffebf7632f07dec99a15e69a679bc34f8b0ad4b43e46007854c9841df5c3777416583f002fd2138aede64484195195f2d87565ce933483df3ad94f5bfa8033da4f3041a591a09cd91bca84623f38a95b47e3d469bfd98ec70bd72169e65c9621c8db39db3e0c80af6a1de7b45c4c7e5f9501873f831998e2c89264b379ba9e1ae045a6282909d2757e5b75c7f087740db7188dce1ed8f6035372ff8067300692a3febcf001b24be9cf09ca4e70b3df0890deed4ee3ee34e9aa495d7f17812d5d12850764a2df6421f9ce741e968c909b417e05f074b07c16ff86a1a8e7993fecbeba9acf5b506e08089a14fa81144d0c8707a97fa310eeef266d112818820c011b9ea5367fb81bfe4acc5f028e211005895e44773399e0318116a66c2bfba9cdc341ac1b44cba5a44c315bf78b34bec292004e375bccbafa1b4d7d80ef78a3f0041070a6a2c5d7d3f9c3240ca3cd22d6a0f6216309f9a5e580d7333f83f3f3a37c825d6fb977b369e712c3e5a0e3986a92cf0f4f0aba7ce9043f641b042c828446c213e7574b618e3a24c0ad73cc751017264c036c1f2de71e8405bfe50283e9821476457584ef78028106f6cc953598f87090f19411f1bda68f373e373878f4edd96b6987101cc815fdfac6c1a5efce6c398fd853fb25d8ca1f8ac20367ab0c77b2452be15621ffe4ecf74e7953f4fc54ff2e6ef2b866a6d1fecfaf2ed69b6811addb8d5dfda298d64dd005da3bbab197951903c8b5500edea2110aa29b2bc5723f9259a9a98a6ba90f469769e4b8318bf50fa22a59ee107c0052115042cd68761336a96ae7202c046f99cb00f0c4ed8eb686a3a3672bc8deedae60d17462b69a4df2a14be64bc5824c2eaba082eff20eaacb818d826189a5f34b306be4cdb6fa6bd5866b846d6fa326a095e2d9b046f139168a5dab6ee017b8da051f8cc6883f79a1a1472eac7d778f8defaf5f53ca29b17275d7a45b7161f58a3542c96b75707333bac8f50699cc390f56d50dfa9d257e44037d3af148606ee20918860d485eb4220d7d331e235080a646e502f1115c99157c47cdd12ebf1403af57c3c27d4f29d2aac533f291cd1b9738de47005b132fbc343c053d1697ff5b225a4cfed01167e863ca834b1ddc9c8a168b089083edcf66c3ee3545fe0ed23f09f035fc8ac6240ac8eaa3c0465259f8ee8dbcadacfecd009af24f60234492615940e5ff5b2cdb576dc34f5c939e76e373977145bccc809a157eb7ff4f5a9cba62499111b8a759a91b86990a480476f6984ee95db5b0d429c1714f5d9111d1dc8bb54524e3c4f8e60be623065867b9b2d929504b91f8dbc889a887dd3d2bf3789ba524612f7ccbb33036cd5e01defd0a802d82d8348319db2292979ae30043f5e8463303a7566f425b120b160a78fe5e77c19aeeebaf2ad1bf1a7e19a9be460fbeaa2f6525a85e3f75e30eaf62c4dea73e96f268e9770c64db7fd17208c9d83e870f6285969a47e14fc5b53a30570793bb964cf10f3d3275a1206018f266e48e6567ec8d2862e538af0d7587b20c78075d78a17027fb6c12d3b4578ebc63f2bce684c5d88d024d6b4bf44841f4cf41fe0d90638139c3a8c61ffc9bd31cb891a37462381692ad665c012d93b733d6ca3544aa2cfd17d6f74a3679f5fb598732904f7657c313ace9f23dba5cfc0c06112b6b1c9d720c81403fccbb16902e8952c3fda93230428cb8cd4b5a60def33d02c34fa1f01420b58a12a58ed0f2c9f32fd719eaee7df5b395182c558c5dac152a9ed0d0554f19d88b2dbb5e2eea8d9e8af2d221305f105442e1ee4b34152d2345734ee8e700fb30f3cdbab2ada6400f907b428a09b7b86418d2d3cb31171fb395f5b848130cca798e8c46acab4848595ddbff2a0c54667be6c49cd8634b7881034d26e3e7995575033f6785dfb44c9f4e9c2898939800b716001a964aa956560a955148e4173def113bb25c04e4009c1f07b49c9b434b10a7b242c6a52245cc2033226bd911da2ae440236ddeed77cb188657e8cb464f66b5fe76eafe37ae894da4498f034d6dbd749056453a450faaccb80064704d7b1c389320a5ba584a6f24ab3e86716969dfd6707b67b6eabfe2a2ca77616e11e2fe05e35ef925c71f3d349d5dcd7aeee5cac0f1d45b77f72a4246c32884f6432d010d9b3d52333629ff49bc8e55f96a631e10e84815ea31a77b0442c5dcdd4ca47844099631735e757f5fb4991e680239217d732886357bc63d0480816d26989d6eb264c3d016c0714abf5160517448795fd56c1a4789f5e699360abe27d37174882faab4a62cce4fca2872d7fdbbcd7a7a29bf4c9ed5532f024bf1c0636e37517b715bc631f784d283c650c778801ba8b9d34a1b3ed89aed517a56b45166926e1412ea2b38d7861465f28a6e4fc32c402069dfc750c30de29b392c2fdf043e649c2b428bc162537d58aec9a4c0f3921890c01edeacf4f1e65b9f54d148bafc7cdd8338042daed3acd387701a9c824fb04a6ac587e30f846f0de1ba1c59aa2233acc7164536ee79913c2925af85b3a730d407214d81581545aba1025f73418b6492a5c2aea0c07755695e776efe1f46f6c6d0dcdbd0e4fc6cecade3395917b5b280551e39e62f6a8058f39aca927e347d7f9af7dd344d0f77e01118e43583dda1efc749c405ac0b4e4016df13f62883f8387962fd720f3afad76e6d43593d2c2bb1f547d2c98d4eba9e76933c9b90de774c5508de9389940a5dcb79a1b3890b39214087ee77ca3a9af2762c2f1de440ae057b4c036f967e6ea562c8cb9294f8dc9c8b1fa549c8fcca5714d2f46cbce23d012a235597d1055befb6528d8d096369611c11c39a16e698ad5c81b0264698bd838ddd299402370c9954b90a2c15c9cb4076a9a1715bbb9078199b9d2272398c8090cbcd9c6f0d574185670ed99402bcba31574b646bdb495c60a071f3497e5e7c98c013a6e371c5697663852c5caad40638679cb24dcd54e923169b5cb4e2b13b66b72b2baf0991b0fda97bacbce3010ca68e27b169933d46f8d9e10201d4b500c93e946c5671efe9699b2af929f85acde488f1e49dc575f4487d45cc2581c1b4a683b8f9d3a544eaefb73318175db0828ae8bdbcfc78fb8defa48533ecab681ad8a768769f43045ff83b942be006d8bbe95199d1d1b9d7ee14e2623a1e50b60960e94712c164e0a9bc85a3af430633a6722819720913ba6627f5a3fa3dbcea2f2bc0e7ffc9ac44561cf5a24acd7673295ee542ecd9f4c7b9fe5c65ae0d6bb5a8dff9f85d73c197597d7a80c94606c2af76ac991ae9d7c7ed363b80569d378d30b082ba881f18ac081a13743a02283b86eea640e3a03a14bc066dfccbf681d1f3b9cbeb16556c6717a08f892fbf1034db622ae1908cf4dec8574f88135fd9db6c971a6da8d256dacea7b0b6bb4568dbad839ac20ef3f7c463ed786eb54efcbde2fabaf8ca33b1594e474efaf0ffc55d3a79132430aa0edfdf8115a321389ee95a042a1d7c6ae9fe1cb36dd6e8a91ee243c0eedb3d03ea9af87164d77ecd450ef15a92478f76dae2bcb63f98848cd6c2c396df273b0c4431c3fc2d18cd3ce1a420d7417ea3ec13a7a017b87b89c8d310cde0682146271e55b402d7a31832d0cc22fb0f4c9fb0ddd7875734a40769d7ac128f1524021249040f890e35b11e71c0701f88cd818717482c1f4817f32169723376b17977f3be58188121939150421e06ec9a7062e0866be5a5d43e1e2c29bcf585941b5c729ab935a11f4d15e645aee9e13857e2241c9f11c067e7cf7cd2703a9de6ca884d3993bd4886249fcf94a1b03abc9a0113053bcc50e91d290dbf67b9462299f190bdf1c6ccf17b4ca0f7e9afbba143ac3e18ef44d5f1df68d9e2828c73b45554b837ff563364f8ac072e603a19f261fc8e6c08e40800d0a01b6ffa947673f7cf0936cb48692f429c9a241d322bcf94a1cd58af54d607a18e9a3547ac0d451d09d1415bdd5e92d63765a0196e7f2beec9883e9e2603cb83edad73a43cc283742e66bc0798d47c04fe9412d25c2a8c5b9b26f19e08a76bd3edf1264966b74dad7010818eec13919406c76d4ec09a625f516c8882cc81b63128b97e772e343d0b247a041aac8bb85c40981935076dfd727ab99e48c6251f1b4d46f92208e168c94019ca28ab84102988d4f1434ab3151c313221bb1c21055492e60a5adb3b0f28a3c7a7c580551202bfb2596bacb8c4302895d58ec5b6df5a6b2db4b4b449681329539201080b070c460b3b4332a53aa71fa9ce09b01554277b17bedb40d10b3f413c5a18b0d3ff953375c22376fa7b6b3e818fafcd27f061b852fee931f817fc07c1ef7fe14a993ab9705ddc13f8a4ef4e4f6fbdb4a7a7157faa2b40ac63c5d3ef5e81755c57a53a4464b3bb290ea57f5dd7a5514a5da8a30bd115e0498612715d1487e6501c4a04a5171e6b28114d290e2582ead02794886e8ae3c27571e54c6d2e1e5c71f2a9e1ab51356d16d6c8c015a7beae5e51776cdd476a310cff512896be764c97de210d613984556c67eecc9db94343c6c5f7ceacd55a14ea3fdbc92e709da91a0af0b0ea50227c5838cb0fb6896118864d6c661ff7181eadf7acef5efe1d6f77c7ef251e559ef5610d7b96eca6f5de8f19f6e6ac5847f7dff7d7de611d9695618d6157be2c1f64d0c4e6e7fd8d292f0cbb1ec3acebba2886cd39b19f13bbe89cd8959db735f7ddebbddbbf75f6d773b7ffcaee85bf8ff1c6baf72ef7dfedbeebcdee86fa598c639746cd2a9e7876dd45c9366cc5f46df494a66283dab0714bef7957e6cd5eec8e256a5da156e69057b181d5a652b7ef473f4a4dfbd2c546587bebc312a8621e337ff4c33a1c67de67f52fdc536a747457dc53b6ae72f537ac560c6b91b75ab2be6b84442ae5faa24b7aec7a8f893ec6ad8e87d1977e76343c5c3dacb57eccdc2ece5eecb7abfd8671dec57e87d1974497b46db77e7718feae91ad6a2f3b1cb418dfb63b96f2f625ef560fb7275dce535b090892ef33f02292ec651744e7fadf3522fa7a6948ef72a816ff4284ada7fa454d78ac2394c8dcf12199523c733aeefbb1b19b39a7d7ea87614f573cf6a251f4980b17c0cfbe4596b578d3bb30652edef42e9832d367efc2f42d4c0f5e29f1c8c362b162c56ba7d38a9187459fe613d691e193d38e4e21a6d3094f21a29a0ceba0d434854c0cebee98fe9ae434c162b09c2639394dda66c57727d3f652575c99473f56fb232a679fb31b4fcdcf7e7bc94ea6ab2fd3a97ef631b33e8eff5e4ed17bf62b6ee752f638441885da5e5e64ec1f857aad6f66add67adf643ffecbb5c1c35aabb528d4ff587372727272784e6ea282dd6a5141af4c2b3ed419bb9087d485b01609919ea5cb9e85e5b33f5d29531966b9a58bb1a7da578a756c9695ab0e91773a508dd35ea46118765117a25cddeacb4c4dcba5702a2e850be9b8144ec5a570211d97c2a578992e3d666afee4f05837d18642d9d93a33355ffbcd4a989e376caf89aeefbc6f51adaf75376c5fbfc773dfbd9cefbdd4be6217fe34ed658f2bdd44e56da250d662376c8f7dcdb2ac62ee5651045cc8a5b03e1af23ccff35efa10446f481f6ee0f06e78f2060eef7a466e5eb4bf5d377beecadc5d23f6ab65850ecd2a2ed4d9078cc343cf0bbaa1735bdc6f2f5f1b69ae78945fadcfae8547955f0debb0f07f864755d3bf71a36be0b08eecbbefaeb126bbd132e88d96512ba67d8cdf50ffbadccc62a611fbd873b773955cbd01bbd757eeaf3c25674ba81b9d77377472d6156a650e79952c947153f1f0fbbef0d857f6d848fee57d7dd215d5bfaa763faf71d0813dcd1bd6918d54870de3b126c31d03accb92a816b496422076a04a7904a2d434c69be79b0118dd7a4af3f494a692d35368f3f494a692d3539a27c6e987d96bf87a22d8f9b57e53e929419f7f425b73d26933a0d6afd8e94f21b5562153a7a351311ad8d4916f55aae3abfad49a42ae2be8aa780ad97eeb526075606fe5f9500cc92bb27402858d95395f552c6dfdca91ae14b59b65d53b1cbaeaa9faa28bf254fdeadb6bfad12dfd774f2fba2ca1e9256bcfd2239f64edab76577ce9827fbaa867b92c368bd36e7d7b57fce882ff5dd48b2e8b97dd0d1de9b608b25881aaae5def966ef594f62c17e529ed4da7bf217b6d7a46481fe3dd9feef72c5754b2e122e9495756d58c171b3cb4fe9eea0d5f42eabd5e76d785bb1ace3b12588ee3aa58cad1e76edcb01ce70367378eb3df5b6edb3c0f8f32e847d593464f227d292ce1917b121e559d8747f8c68d1b374a7d3931e79ca3e95d231642a0cea8b3a08e86fd65fdf439fa917b165cf55854e15a7bb008b008b008b008ac033fe79c9d3549575743a3759eb5df755e37124d37953ecebee6262ff9e724ecb23e3ae2bafecfd37e0a9942a69029040a77f78d5e94d2efb8cbeaeee6baf720dcfbd5a1711ec771bf65ed35f7319e8ddb97f230cfb6d92f7b1fc287f0217c88ce3121e69cb3b330cb12592f2a6157e98e36d7d0884a2251e9636649fbeeead84a2391e84ba5d2775a271a75255357d2b0cb7ace492311374da5e79c34d25e84fd65fdec91e8f338131e4b4ef2918bdcfae71dae1ee2f1a516a9456a11d993d180ce39a78e117bfa3f2cccdab72cce7aced6d235b3d7ec1d6daea1e12cc7d98f99561b5d1d9bed38eead1dd91f69cd8d18b03da7711f3747ff7dd8393c02c182e68b9ba4d1f6a3c8729df6f3b7db4a5a8696553c5a43dcdd45de595554431324e2beec45df8bb8d12644bdf43ce846ba3c926c9d64947d4fe9293d450beeeed4fb5a43b34995ecf9542dea9a2dede826eaeebd6e6969c9b62f20b2743a5522a79aa4d4273cd6e4d3772552aa479cea915ae4542a9dbe964aa78f99a7d3c9542afde9747a5b427d8c9b4e2816564ffe2e0b75faef2b5d174b372a145d6fa14e2ca6121e512429c2a3cae2fa1fae456a915aa416a945648f06e46b68268e3575587e9c3933c7d6d0605644b2a4b756644da21f4bdfd8ea478d488fc9a6d853162daba3cbf4d991c8623f854c2153c814328598ba1ed1416d857695166aa19e52ba4adfe8fad2e84bdef7fd4812623995462716db493c534fe9293da5a7f4949163506c0d4d27e926562b71fab197f492565243233b09a993643f7e23d18f358faeff4c3fda90bf1f8df0a8cadfd34f74c2168ba9446a25ada495b4128b39c1e27edb30ac86067b12e9411dec4947e8f891b12691bedbc2ea63d645d2eaf55b66758f996a6848df833aa48f99248cf4a6abc3235912097b13e94d98e963dc923ec6dffe58fa0f7b169975bd65fafefb302db3584c2512b6bdf51ed6711b1eb5ac5e1858c485c1225a86e53d9811be1a9a91f4a14a5fa3d175f9f0492aa3b63fcaa0a01b3726e94777b435349ff4e1935548a31169f4a4cbf33e19f4a3ea59de449ff42c7f7ad4951e9ef0f83d8b156193e595da7e1ebe71a3655c376edc3035a633bfaeebba2feb3a55d7d05de38c5c7f9cd1d2d232baefa6fdbeafb3578727fa3e6bbbafe4fdf58944789c913beaf42361d18f44dfb778b7a565742d2d2d35a2be80e08d4674348978a311f5e69091a88e467f8d3e668eee38bfaba31bd9d1e81bfd777df61b95ec8f246a62f97e8b3ab1f4554b789440cd48c2de1432854c2153c814426b448e3d21496e1064e9e4083b793ee82f33f6f27fdbfabaaeef3dc847ffea18b3b764f67df4c2fea2d8cb6e01d66b347363cdf59767ad7d0f627d888e4e64edf5def7ded5d67e8c8bfabbcec3238f697fe4314522ec51cfc3230fdb9146dad3efae0fc1591db6ace111977c889651f2b02d0ef3a159ed24590d4dd649ba0986619da4f6926adf62ef89de72189e5d873117618b8d80e05a4989c3b2506f3c48adf5c683d4ac560f526badb53e8f4ef4e366472edf5fa96bbb5ee451cb4d1fc287a0f4473b3fabf3b3ffec2b910c9359764939e59435c926e56759dd21528f90f231ec7fac47268661daff7569ffc25fd9cf6ceb798c914c231bca0e8fa2d247328d6c97b18c300c63c1be34c25e6431d1db7f6c546241b168f1efc207e01f00ff31fcbfb8ff30dc7f7cffef9532f5787cc105ec028f2f2d308847150bbc028f210a9ff0f82cd8844ba41126b29fd7593db9c4bde01d15dad50eeababb83bab6b275dd5f5750d7752dd4759d8575d68fee7d57b78ab579bdcd26a7dd4e522fdc534a5ce7d80fcd542a952aa333cbb22c0b3858cf9096613dd9bf621850fdb8772a0e0c2f4eb906e58c2728fb63dd0da69cf14061fbc78c87c542616330511e09e342cbbc39b169032f3295410816acd7882ae5133718419676d63a5a1845b0a3f49199991788fdceb27c22073ac8b3b12c9990024fbbbbbf9043d40877e13c2561789022100c60c0ce94fccb27d3dfa89458b0ee65f9ddede0e2cf14456dced103a0668a7e8c8f94602f1c5fd197b1315da06065244c67fa3bf0d02e15e8147d4d6b17d9a9713492725c71292063f490315a78489fa22e9f09834dbed8e4e4662a0456ce54aa7a20b0de3e01ecadeb670264aeabbaee2eb060bdb1023cf48721841dbb0132e59f841b26648f828e0d19c3815c0fd8bec16de3a10c55b48d6be1099b7c214a2412684b69f0811de5131759c35a14eac3f089dcc1c3b1eef8aaee9e3936144437d5344cf343d46cc878488390751e3051c335666a3e0d50b0955a52d8e48be5726fd657d7a9fc6abd4e978e45549fcbfdd8f3204414e9e25cee16509ff3d043fad708fb32459f4a2a25fd279428226754f6d8d05eb210f12004151eca5438d2e45a31ca432ac4ccc29271881f2764200a233af0849a22aeaca0063727200213461045d684ec5cf61953c39dc80f56e0408a2a8d7a77ccdd9faba18938d95470a54e9bccdd515f03298664428022fb4bff4a85d64025022a3b70420a2e20048abff4af338630b142124d90b284921a1c0635647fe95ffd5153babe63ee4db23bf516c47858c31f0797010544488282215670425480952024410a251cc10344447f1925bb37398194ec2cd9a992ecee58f5c73d3109a8a1005f8d9ffdbd053a88a20877275480f2294b1d4471816cb3d4411425c8232a8f28ccaf2768b063258a0e3690852a60c0bf5a2218c10a38508acc400949a612ae60831a08e1491349f84bff4a831386f4c002527652d033033984234ea640450533c0c204a87cc008422cb0842d7cc0ab0c3204aa00240a124c5901139888e3fb57d761842296a0b3030b746003a27b538941cd06a01841859f2638018324a2a4c1146ca258810a186840c8cde6990725650648b84205144b041125144f34d0840c8e38e1048b2532909a029020d1af9438b0b24448f40b2a11e709a2b0c00e15a0b0a181018a2b5441fcb17ac1169e80018af8e3540471628b4a01c5055c20fe08a30871c245040543b002c6cd7b3911a209544420fa955718810ac4ad727ee90a6a20ce4b7319e181186441fc31a3080115a274028c765e1936441c11ddfa40901516883f4225a0608214e7a54909c9a006e28fbe4142e49a9872a5e3e615c0d0077c3c6ede141443e011fd4a71fbb8797b054010018fe8170148889be5e685e161018e28094d8e0c897e5542e2369a4264904304f1c796030b20f183f4e35132c0c447f40b0314712b71f3d2502be0407102f14748832b3e2a2131032e4e4c9d003dda4116763084e8575a4104e2c6c2cd3b8b48c1c647f42b738044dc6ac52eebc4a29fb0840d8444bf310c117f7853276c72ba4c67a20851e088349a124cb0117fc020710429349814f147c905e2c4d209c0440c7e8e88dbe4e6955150208423ca1e08d98290d81dd8800a7a44bfaa24e27659179dded2bab27e230cc1e446f4db6203e20fef6ec17c7007d461210416d1236588af4620ac972d7377ad41c743ea3f68645a838e653d66fdc4b2655c4f6f0d39997e0d381e52ab06225a06c513d760ed4adcabc8bf550cd690b93e0e32575c93b15993698dd50d85943f2dfcc5ccc9c971e99edb327f0e8fa81e2dfba14a8c50023c351f0815e59f207b7272727272729e60fd25add712361cd429ae47ea114a2f6a51eb713ca93ed6932718fd51fa5c14ff703f5f2e1516d6cf365aeb86476b51ff148f2fb5482592e97707cd26b44d2d528b34c1fa4b5abb460982a1b261fdac56948b9d296feb9aa1eac6cccfead090452714a4e3608e83391edb7fab8e471e37e14ccda7d7093e84132c3a31b77cb0c917dbf4562de92599f519a697124a954cd50c4fcd2e0ad64b4a5a4914acbfa4d5e7084116b7753675a60e67c96d7bcba94c211e3485c8fc70db8da1af5df9a4ca145225c852b9bc333cc466507a518b5a957acbf0b7ee85c75665da564bcba0f8059ea516dbd2d232030ad65fd2aa6ac2265f58d943e8f2cbddb25eb3f07861cde31ee3217dfada55cd147dbf33d509d94a694fe90174b73be6986342567ae8d86551cb2d1a6cd9330c078eacde50cdf0c2b8dd14e18d296415cb7b7cd5dec302773c6c4b761e5f8c12b35808616bc7c3f916913c2340b3a3b20b4d065e048be801f44f1a2cc1225a46c7cc20e68f7c8d351613ac7fae168f5503ae6435aa83ceb0205895ca47e5a3f259a2ca2a5f6136c424a086d74afe45b8ea42a9031f6a2951e2097bfdf8e112db3233367ce868d74a7ac9a892990152924476ad6402c1f99086826dd32c0d7034fb010eac8eac25c37eb084d591b5645ccfe832dca2699a1318d5341c50ebc5894dd396d834aab5ccd85a549ad6d22233261b17bad86a61497bac4dc7ea21d85106e1080ab29058659afdaddb66566659aaefce7851f98a7e2fb2c7ca4c2dcb07f6fa51f58284c5f1430e2076f8eafbf93c7af8ead3722ccdca81e3872adaf74d2196e5759a14b28e5a3f4d3467fdd880fb8a6dda73cd5dae6f781e0f3caf096a492a3ca89ed7d9c056cffb1b2da3caa01b5502498fc3be8e16beb1550cd30c0aaa0fbba9d3edd8de2a6725c55640b11da06c0a6cafb4c7368b6edbfb6a7c41cdd62c0fc22ccbba964359995f5436f9a2c5f859725bbd84e0a435ec1242125647c5324fbb2e0f7bec6a1fe2eaacce92f472725d9e733db156bdb2aec392a857d6753e44cbc81ce7ca2e09c587a89ddf7417d6b096e1b14aa086fe6771ae99603e0eecc2f0ac340732639a85e1da978b6283b02b737703aba3be1544c557425da587acf8ea8a76ad979d86555c8bccdeeace8eedf2e8b183470f1f8ae58062583d02f3699b1ebeba81ed7eebb120becab69cad166919593d82655807e5d9403a482dd232dadaea0e8bb6d97afa499eeda3d10bfbb699b55a8b42fd872136315c8bb40cb7e17436f962c482f27cef6922bfc5a655ae32d119664b44b0a30b4d17ebc84ccdafd5855c8889d5a1bd9547eb48b68ef80a3bc2571b8fafba24beca96584af8aabb975db6b110d2305804f61f07f230c87f1cc8575c90a4161332530b2402c5857e3c88896d21afe2436ec5af3815d3062c02dcf1d5681dc9425ec5ad8045b010722117da7eb42cb0081655b0a0ed023cf966e984084182f0c3c9efe5b790878d1b53acbbc6927a93deb2df26e75de3da01c1d68a9a5da7c4e7ed5f84beea7e3e0cd58c173cd6642fbbad352bebc770ccb430774b1785f2954b6a754da865f5773db0d7771e650fca57d9cfef94b0edab7e4b7bcafdc4161e6b6ac4cc4f80af3acfee5e761aa60cb07210b38a2ab2b55d3953978f3cdcc29b6b50f8beeffb3ceffbbeeff36c70e3924118a5524a2a3fcb42f308d14ed242ae536bf59aa7795aa856a1eb9a3f956821da533e4f443b1cbaf7be5e0d97aee9b6e8966226aa74555923bde88ede74495fbaa316ebad73d6176b45d5ef9b1f33bf7f11c26821212121ceb72b6c488c6dd341b0bee91c5f555c7fd69f3a351948a5ddc7784e4e4ece2867341a8d724c2552d7c77a241a8d46a3910b0b0bc631c2230a8ff631131eeb09b360d2736fafcc9e9a3f33edb71719c3e17bd1dbdb5966da276d1a07d5f145bebe6dae9fd7f59788fbcbbee87e72acf34318d755cdf0b07aaadf92fcebc12567b49c41a545d532e352b5cca0542a66c9255a66b478dfcfaf7e9deb36392f7bed3fcdfb6e46cb6731e0b1a2509f09c59fcc1ed38fb3a74da7d9235d33610f7e8e35ec82c964d23493f62e5c543699344d33cd2cfad14da22ac2a6d39baa757afad764729a4c66cf6492d16ed2ef8ec9ec99432b98cc254acc254c7a86e612263d7389127309939e212673099315b76d662a14ab45fdcd0b8eadfb444197e984639b530ce7cdcdcdcd8aef9b1558ce94ec39e79cb387490f931e263d4c7a98b0b8a9083d2d3d2d3d2d3d2d5f774fcbf7bdecfafb66f7d6f774b2470ec1783fce68b12ea6b25a627c65759ff52d96d5f359aa9618abe5fb64c682e8dcdd50bfdfaa1f6645a13e138a3fe92c5538c6bef573fee83fb1aeff75af8d33f2e8fd7cfadbb8fdfcefcec896c558ab5887c48f692ddf626d2db3add73c778743f6d877f7fa0d933130e9ee8d3faeb7707dec6a35ab32464f4b4f4b4f4b4f4b4f8bd71c934dbea8d611f4c824e2012577b1039f3c493776b48e583abeca466b489ed6916c84843922613697ef5fe4fa998647ef31000162c4905f842a1765cfb27b77b99bfdd6d55fbb41746e1c0402be5f76de2d964401fb8ae17ab5a05dbc53f3356d34addb32c63cc2c36935b68ec85085d57c5eb039143b86399430ed2243a7fc3dcc3ecafe52862919c369f5d0c7b087073d02999a2f1b0579764aa6e68beacfd946f2943012e8dc3e2f110f1788e2a1cc3300b1f3df4553d84bc757a3fcb1217f6c4898cef31b206b36ca9f2c444b97b640a7e64f1407f2942d24cf1f4579ce4085bd76b2d0351460c3431f5764e92da5bb548bea3cd33fc8c0e69801886d39e424102dc18ed582e2ab118674e9b2e64afdc543577938ef106bf10c1bb07cc0e63c942f654abe548dd666d9c494dc58aaa44f0c28bd3488b5e88b0aca08d0dc4432c53c684dae992d059f2ce3a5fccd5fa66b50dd1f34ec80093ea20c969d2122322e126f9f7f613e3a432c5f62611d430a6c120be365474386971d8d193ec6fd67dbdee774ff20be2aaad842a6ef39f44f1e7f1cc90fd0617d8c18bf5977ec9fbcc3579e9b65080a421bed82e82a4477d5cd9490b344c421c64f6cad5faf925d5ac92ea9001f48f60e72cac95e7222eedfa49f6428d9a3646fa01f8bcb5ecadea24545c38faa2ce3c7972948dcbd5a1758ef96992e319e9a4f5f0057a6c21b800b801bc36d71150003bed7c6f5c1c3f92f5c1c2e5a5c203c9c0fde1d978787f3575cd46d9bdb40e69b6ee37838bf349f347f747b8887f345b7ed6d227d44f374925ee2a1121ece6ed24f1acafc96fb9e9a4fc355796abe4ac60d9e613cbd303ec6c5e00c303038c3d73cc30c327c15a897e5134a64215b3a1e0ef18ad8cfa3f338cf74a93cb9fa95b23efcfe1f7c15806f007c7f0f7197017cc7f0fd7dc4572fbebf8ff0150cdff8fb3b89afeefff7b712be7ae1fbbbc7572e7c7f37f1958befef27be6af1fd0dc557e0378befef28be5af1fdfd03e4abd3f7b37c9bbe4b557c459a2ede148ef0b1b1b1e9018ed8d26708231ab011fbddc657a3ef7720be127ddbeff720befadefb7ecff155f7fdaee32beefb7d88eff88a88af8e60dff2fd3da60b0ddf740a121bb15fc6cffe2dbc3207e0caacba526cb9529471a548c395620c57e617576618aeccf8ca7cafcc7f657ee1caecc295b9c595199479c595192573eacaece27a1e75b69e4f57e64ce64d66128be7ee76f6aea492bf7b6500dc9a07900a2f0e0ffb03707ff0b01f00b707703b88a7fa63b89dd330dc1ee261ef7848c4c3231e1ee161bf0bd7c56d711fbcad048bdb3d2b50b7a178d87fbaede3613fcbed1f0f8148b7a9886e57b96de5bb7d850ab77120d76f3c0ce2389e735de7e698a97e1a6e8f99ea575d1957ce94cff8e0e1e7b6c9b4b6080a9de04093dc6ec35c523b1e279e04218faf052b798491dbf3f8e2e2287b7c89af787c259de80094dcef497c4591c836c823975b763878762ca3832538c9dd7f7926124bb2636f04fb5d4d59f2c00643d9414a4d41367ed8e1ab99fb697e7263385354218f12c80ed9d8d8d88848a49327c0208f52688aa06e275480ba7198d963dc47007ea39006b87971da70a312e78fa46bb40e307fecb29430467cd370f072105d45b7838bfe21a59a91fad7cd716f2e900cbc8813cb99baa962c5363a1e6e762ce94129f52cc3b586d56c142c0f5f8d75071d424d17f0022f0cee30a7bbbf8fece74b118cc015011ad6cb540cc68e9e4c1f83e121787d0f715ef0c2323b664aac57150e553b5da6c5a18ef16cf2c5fc0b9c18dc617bec7bd0fec23eaed71ec33e90cc5cafbd0f5162d87505a143e77e1ea458bf7db6772753bf6b7b2703645e5fb10bcec73efb1eaeafd847fdeb33ecc34726c51f3ca4f643395398a85d2966578af54a11bb52bcea4cd11c188787ee34c9265f8cd60673174a7ff0f07a7ab759757048982312e6657ef3f4917cb90d7d8f881dfde9fd471974c200f7352206467fc220865958300d120c9b316e61a2e539a6cb88fb1196339563a6ae211c1e11eb0389f53e46cfbd0fd19fbe7f87d1733f33c220f62c169e1161700796a70f627886058f7e3e3853e7c95b81ada70b625895305d034b1ebd2c5fb68baa53971c9d5e8a1b9ee19e8645f452cc6e6d4ebb9eb38b65d9d10065462ff30ccbc7b8ecb6a7a1cffd866746cf8269e68fb2263a81f57388dc052b9691e22d81b521e3ef2baca3b139d71d76ad067277e00e9e37d33d58473fc3fd08d320a94f635930cdf7a3af094287cef5799022cb63d735903b19968f718d05ab1a28c33d0f52e4b00f24f57dd0e7be8711f6315ff4313efa19fa230c6a3f7a29cecc3ffde87b38fd08fb4032337a96f741fad3f7c0f2a637611fa36779296257d340de46178c40103a74c69e07299a3e0234b497313d28437a900729921eec21861d183cb111473ffacc949d9e05c4bef452245d10c3e00ea4377d0fa32f611fa51fbd09fb403253fad1fb303de9a5c8722a99462491e54ad174a558ba52245d298ebee299f9a2c72e9667886e8ea12b36f992a2e84a11c72d817dc12a0faf97a109db3faab89fa1cf61b0be1467e683d74bf17f0afbaaeb477bd52b03a13fdfda6409c30faee67211148b93af03cc972d3c757de807f0bffe5152891eb293710ccad46d7be9bf43c2f4d63aa3ed7690a28de2e6fa1ddf1209f392afefb143390eab66eaaa3153d7cffb326566ea7aede2b015b352d8510ea956d75fbfe37a967c3da5225fd7f5270963fdf52c12c6e2581ad8aeef6bbc9fe1de7beb3d4c83c4c233dd7f9886a6e6c3ff1dd305b4de7b295edf63ba80160677e0fefb1ebaf7b00fefbbffb00f2433de7718a41d95a2d8f4e3ae4b5ea8be2c3cdacbea9fe13e7b17b4dec7f60e36de613ef733f3b9b7de07120bcfcce7de07128a67367f1fdc4bbe5e3cbc2d7a29b0d64bc6c144f0f2ed74e1bcef0beee0ef3d48f18cbf076e7f41fafd18a811ed7717a4ef8f811a91a32ffa1a8ac11db8ef7e86fbeee977980609c533f62d06351a7f8efb1aee7e1e55a036dfc67401350ceee03df73d7cdf611fd807920dcff47fdffbf0f730a8bd14bda7dae7f9a87ca80f7765d39001e2df7f9d6028d377a18414e97727836150c67a7026861d18e8a00af13282bd8dc28ed2e79257b0df6c1436c7749199fea723615e727d4a5133458dd4975d0f2e566c672a9c29fad7b4aeb5556ccff8aa9f850764e7fb3734aba0bdf4dfbe877e0dfbe07c2099f121516f41f9dbd788f3734c1750627087c63448249ee9df300df7bd3d4dbf6390be14fd6bc46a5d39533f857d999adf63e1277420852c31289f4767d0fa99edfdafef0ccaf78184be0fffed7d20b9f08cf6fd3e365062d0c23bf86f3fe3bf61395314cff46bef43c3aae99dc08eaa7c0175eebc49f963b6422553fd624b17eba53866594ad94fe5ca9bcecebcf1478743eb90653a813cbfbb1bb69c43a6fd968d8cd14b4c9c9f4112c6f4ed99b29430fefd321286f4fdbd236146dfdf431246f4fdde2361ecb7258990e75f45f27caca990e7d7f95908f27c8dc680744b3fbaa4df4477f49bbda2dfbe6b7f33ddef37cb6fe94dd7b32eac66dac6d1375def3bcbebc7da8208de058b789705152ae7dd15da8fdec4bba810701ce9c4fd38a7789725773fd21898be66d3972ee9cac818fda3db3b433d1347c6e8f7ee0c92313a05b9a3909d89dc20c89d84dc6ff5531e19c326cbc146ad0bab59a53cd685556ce2045dd885ed0c79cfc4a1d665518b0ed1b913e4eeeed306b57b8cd7ae46368b042b5fbe7c8b04dbffc97eea02202020202020202020202020202020202020202020202020202020202020202020202020d9b9096c97a620458a142952a4489122458a142952a4489122458a142952a4489122458a142952a4489122458a1429f3e5a42620ed935a1756336de33aefb3a211a9646239a156b0005bb0b04105d6b209dab1a13c208b15a8138bbfc9850b2fb498383b964f108ba9441a895e78d07b76268ec87ede4ef6effeb2689c6ba8e3b66b28fb6b17af08d345ce94f5ae694ae625030d64a881ed97b9c60557a41072078388fdc633544e63e500be645087cedc77e6b00d2f1acef00ea8c88efb8adb503184ed91c7e5d7fb3fbda78c5de9031f6c21ffc8964d026816834c3fc6fba78fd498a918f1a7e8b1ee0e1e3d96b0a33ff1950e194f9efe3070ff3c7123309ec2781eee02e3e7ef8011c4396ea09e1d2a8e1c39c27363c387237a8efcdc4c97069a1d8dfef170feff98a8e8f11f1985f5271246cbf34538120626cfdfdcdd9f4c17c94490fb0059c982509e3754e4e94fdc7dc8af4c9bf625798ebdc457208e1f3c9c9fc40df2c84d7f32fd499edd8f83e7ae3f47b20bb97f648cf9344401846828e5e2678be4edc0eab8de3ee9fb4716f5c8197e72abd55a8a75481e5c7475c8b7b445a24fc7f5f2492fbb1d7858593ee94d4174d621df4adb9d65c626d2531a161c7dcd234a2f38925752d3ddbab4034b3dfb11d3bc973fb3dcb897ef12a6c31bbda3abf28025fd68f34b94af748c5efe88f4d6f7148f9fa9bce3936468fdd8224b961572655fa2e4cf2c3b1c4acf72e79faebfbdd3deeb49960c2d1e579c6e6529bd09df30b308a3640c3a7a7a47ffddd1972e900cbca865f5bd47128108f0b0b97b1ea88c3d8f9ab9df40f9328bfebae0f5f6651e5d507ecdf2b7efa505ca97a2ebded060109de94dc2a23cb4fec35606296cbf279fbbdbd5e467320626ff73cd09a5f4433f00b52aa5f4ca324a29cd9e524a2f3a31aa6958e52f32f4b1ab09aa1d43b6d2299b7c31ce9e4cb7967dd33a1749ff901d0f298deb1b8804d488f97e91139b638787de12f685bc7d75f9191ce109228e8001a12988f4af1b433f1be2ab1d2434f3b3b77eda4c970e4f9b99cd9b4c318d7f867d68a6e8d35857beafd0aff54a9527339563a6e8a3504256a8626fe2a10ce8cf00c43ea594d26fd13b819d5f2b751f297ad737f522a1e13efe33531e94e97b4acc2e46c6a0bf45f11ff7e9711f4c8a413ca4ef3f9029fa45089390e98faa4c9d0914c3ee236350995f0adb387de3219dc10576f650d7acd093fbca7e4fa85105c84d43ca45145676f35b60e5469fd20f67c428a09bc827d287fafc727fbfed2ff59c737e12667e4ff931ee220956ce107f8f953ffed743832c8f2f5901646a3e0c27b6a36881ed0db4f04e8c026cf0c0024b60c003219cc8a3f43932b139277595afc600e4f9930742ec6424f264d21e0009e33f3d0c62fb5d24c1f6dbe0b4c705b66d8879f1b2e31719e389f56f984ecdff014a3a219b7881a10a3d0c33251bf71587d3d3df5a5c9a7e8207b2f023b6a06927468af488342ebec5c31882cda145ae5f93fd89af5840f1d5e6e3517ce57ddf60a0e549b09287f5dd66ba740c7ab020d87b8e0ef6bee344b0f723d2c914a864ec9dc712b1b7b2eae3abb1a9c83fd8631886bd6827ec2874092a55ac60df54f80aac9c686747b423dac998a8d65a5ddc1f9d03851243a28b073fc65d5c242c3e5b9655bffbeddbb33a1adb6f1bb771d5fbeeca78a8fdf43c0dbccde2f6f0105b81693c8cc28e6e03c3434cc2dcd827120626d3d084752036bed21e7bbff11516622f5cc7874898eb31ebb36b5ded7198be8e40c82018beda30fdf9d8e8417858192ca12ef8bdcc1e98c3bbe982a5ef5cc26e3303893b2264d1d6e2ca1e4ca1c81531f455fd16d785114b1c11351adbb7b8f2670849f08861a783f5d2c33bf6c87566b03ecdf5b70b56991dc88fdb60492cd91ed4a1fe90ebcb2cbb0c886718f6d708eb37d86d3cc4665881adffc25715b78e8718d7a26f660aeb1bae7e17d5c243ec5f0bf64794dbc814f61d1e2b9661cc895cf168b1972f30ac43d4637291132cb2d024e0f999560c2db0a3fc59400c16b08d258f89c3c3f6c186874046301ed2ef03e44fd6217fe2f1080d3d7674409e78c69c2e158acc4c4905f8b5feba406c735e540e6188523134e7bc68f3d4f05563394a28756234a49449b0eb58b5714f601df712896730c28e337860c4c0c4dae87e95af5ae47e18be8a0107b63fb4622577c700f9d2075bc261c3eee0a28dce393c943f40e4cf0bf9d345e000a20710292891bbdba9c83d65949806512d6c681b3c3edf930d85f298d88b3e786135a60b0c1f191f72f0f0957462e5883ce7bcaaf8c42c8a9a6095996b31bf624ae9e34033bd8195d93b1c3a77d34031b1fef3caa00e7d7dbfcc9bb7377d3a453c586095a513290ce58bfebd4658195c638615d89287610d999a5feb689f50dc38d5071cb0e34b0d5f8dff07c8de3f2601be1a7958d9c8cd8bd9f7a7fc1bbfd0c0cadcff82ad97f9325fa64bebaca4cc961329bc4c218baec619fe335ef8cb4bf616beeabf80b0c917a34832b141962fb66035507ea65d0cd488db775fe3fdccf6decbf7b8ef304de634da6f18f41a914e51fb4c5a2bdc6f76c8c32b26b0f47d7c244c14dbdf3fd385fbcebe5f6a28eea266ea09ed81cd5eb4071d1be146d4142f5eb9ede6b8413eb20765b4d7308d8f1f9890b8fd14b57f861b4b1f1312a5b8611b4c48d430d8436c9b99fa296de139b37c22892764d93edd3353bd64a6c6f6ef287dd341faa77d3c1c3b1bc9be77322c67cace9d8ef10b64c7bdbd7da64b17d163636323c490afacdcdf5400e55e0224b75bc97dc56dfc26f7d32997f86aec21b9bfc1c6e91c0fbbedd074699f2a87f088b243b925ce3c00017a114e754b820d94995f23d2972fda861258d05f8af441ff1641194ab19ca916e7fc162796339ca99e4fff0556fe18c6cc97ee219ff66e1c1c6c600e123472f3e2f7463efc83fe8848fc6b72635087fed958e69a9a0ce670e5f932eb98d87b99bbcf56dea4b74bea8137d03c7f5e0cc8fc04132a88498013567e026ecd66588105b551f6d892edf944124de4896ae16163f8afc73dbbc7734a45fdecbdb33c22673a58cfd55ab96d7beeb31b5e18b57e9914dcdd9fc6ca0b10e953af7cd98baf460925fbfbf70df94a6583027c05da92953edddd313421613cfbcb4c171a39842124b040fcc1f9c00234b0315d684025258c047bcfa17bfbdfcdbe554efa445f3886303cf46f68a6fc459684a78dc2ca48982ffbcfc07c3ff3d9c032df500ed94f3087ecb1cfb20be630aba8a28a2a72cb2aaac8fd19023298c3f7d97f5f93bf21111eadc52a1919c345de73ff711e6e5fa50f8fce1a7751b745103ba2328caeb2ab99f655d3c01cea675f3fab18fc1743d34546a6fc6bf56f287b29cb277a88c8ed3823efa870a568595735535ee3ee2018cafe32a0b0926b0edfe0d9b3aaf04c2b1ce12f478e7b397694fe6971f4ac6e1c1fe5508ecee9e12b50e210c97ec47bdd737e1ead8f145152cc2ac679a32c9f48220a396268c28ed647c2d0f4111088600a3a22cd8fd44f91274496ff3143084f7a209edebf974c179a17569001f107f80491e684817002f8b3e01d4e00ffbe522b104094462418997c32c2242cad94f6b18e86e51961516fbf71dce8b98e86a879248c97fd3bc97745c2c0d4bb7de8d6a7093b2d040513ca3ea70df2d5d838d6c757d2895093ec6fa3f8db1f5f492755a092fd2d90bfa5e22b3a6974cfce8aac68869eafa361593707edb9ff3a06789f434e91f560561dccf00d9e33cf2e9530d44b9470172073a84af6ef26403a9f286c203bcd2e9d340189ecdf3fd209157eb27f0b4d9716fdb36af5f0d528adf0f01558391a5fd124b2ff35a262cd635918c481660b75c119d4b33cea597e87af7678e8288be5add15bf6ad4ff6383c5415b1997f86737848bb1cead7b7be266fd6f7bd6581396c39585fdfc2a07d1e56b65f936bf2f6351967a6fcdd5422d18e861ddd1e1efa8b2ecd0dee36090b6c2fc1cd235b60312853235a1b4a60591e946161017b68f1f42d9ede7b811d1be7bd4694338523ad8569b4006260af8f993113756b44eecafcf58d405f1e9dbddf2a87ba35a2ec7a20c450bebe0112e6075798880213511cc93b7c25819022cb778f8da05e8aa7efde3b1a1dea9e6e8d99f267b9fe53f4bc86350e5f71efff83afbcf7cfc1fdc675d6cbaef3bef33c3087eeadefdec2e0f51d066d641fbee66b847deb335d9aa75acce3939d94e51338f0406e3c5a26aac093c7e6c994b34301a996a8f4cc968541eb14a21901000000003315000038140c078482d17840921435f914800e88aa486a4c96c70325c8410a2983080106184280080014ccd0264101466764bb46cd93d687284a2ef37e74a1bc1a8186a50e8474f974d1092432de9a4f38ea8fc8b22972cd1f109d04601e2b4f4543c2aed26856696e9228eecbf618d0a8caede336ca6bdb2a8a5c4ddd449163593a110e2125f8e778973242add9ea6e207ba386da2bf8dbef8b0784bfec462df371ef1a9f3d85a555a91b9b938aae01c06cbf104aafad4065785fe17e5ae3c08ddde4d43a88b83bac528bcfc67787865186d3bc69e7976439881245cbde72115edb32422b359c06d8beefa6338ee61b17d89b83bc9e20d3dc4cf7a2e1c6183c023a16238eefb858ef1d2c22191664d5c4810cfcca8dc99d932e0280d7a883dae6e817fdf7b09fa6b5a4937988ecc2946c4da956a2a19cad076dd8a0e0233d7068d770eb55353ceb6cd518b10879c09b0fd3376c21a6430db62b4d6ab47340ea47e12a6787554189f7241080a4bd8961e6833d427742a33e23d38b9a76783a8ef34cfde2aa902da4d517e131b9f790580d294ebcf75173ca27c305f0883814d1af6ea0370668f108d62f8017be91f1818ddff5c62557147299fbe60b3c5b4bc9dfdf1862c1d920c812350383c202991b05cc2baf119a9da86cab7ee0e1d2c785e85c7232f66b97880752d9a728aa106ae3549bc791b6e54d0d708e6b5167e8d6e28b6057a377f32a9cb545ab91c8ec704a953118d70404506d172d088c325e5b4eacd090cf988e6fe1c91ad2b0e8c6289a1dc9b84a2b5bcee2b4fb6e92f205fcfddc5bb697c8e6ea490fdcb69f929e76d37965b17d41e3568c9fdd1823831a30c0d1b559dee25b5a33b898f20c7ce724ae4c9e20b8aa2ff93044b2e03898a7dfdff9dc30e943542b1636daa68f04e3476e4bc690d7375f756293eb364ff1a1fb783d89ccd5672e188ecec787ea7fe859896e76cb226e79296e1b6a4590b255b663c5fa17c047ad14279dacd52c9589649003fa0e89257a3c39b0d4a01435149f26d2469ae0a56398205a314011247b05c5d1be76ae42bc582e5ba6cc20e5655edc9030e98347bcbfe08ecab323aa19214475c6431855ca887dc8f0e3fb0670b51077770981044cc9ab67bfb205ff5964c9ce43427c9f6498ad9aaa1401a3251b2519202daa6bacd3b05e6ec21f2a5e575c5babedf2138ba6e03e518c5266bc52818d0f55d9324017ebc1f63e7f74a9223a55304d369546c527cc662310a136cc746b539c44cec78425e8c2cff9fcb8a66a01957636bf60f02853af911435d18823bd3edccb108b8f9c905bef76592b75b10b59f753e7dbf1fee26565d1ce9491a537fb3032d1d24e11ee30a512422e605e268dab88d3c891d192d0d99a29cc0e9d41577e330af7a79cf242d78e081ceb395f2027c02c41b7cdb07f18a1228c196074bc84bf856e928bc0130af2ab345d7f7dfa2836c92a070868cd4d836068e84cab7a6a3784555a7234051c6fe9f7320de149381df0f328557fbe2f075846b5c15dd76e3c1072dfda4675c11e1917b605b25fddda2b04a9457385e6d610574b15044b65888466e5a508e53c4ecf1a5622366cdb91a86a4655d25435624ad5ae8f31fd0cf23d306e78f47e3bd708a8b8899a4bcadb2ce41321101c0c3b4fca486d77327cbba0a913ac893f72b06fc2b86ed3c9c6bbe14b9ea4f92d61a69c782c8797da56fdffb9fa01deb513bbc5023b2016463f0d3f43d93c63af601bb7c93ca6dfa059bc7e5a92ad0d2e56105f8c13f18233afe3f1cfe74b1489fb21c10e9f00ba8a89b07625dfc292eae5a704c4948a315456f9c8145e933692d1624e458f6880d60f18762ac0a127aa9e812d9d4b7c4551c19185e451b9b9712254d3313afb21cfbe5662cd908fdaf9fab6f8ad4bf73a867c57d934ac955f22b1888c325f956c7dc9053431f6e56f2e93f294fa5c28c13b9101c74a47533c47660e2876c8c8e88fee0541482f93646ff2a5227ed53d554a1d2ae117f3481cb343a98683c86ba650c06cb926c55633c2fd8d7ebf38428084e4824b6cd5add16ea73dd35db66524a5c7f0876cd895ae999dd1f04e977b7e745b3abba3f142210df8e7f3b370041e2f074b99ddc870ac24e3e7538c9b1fce2e1f34974d14c190635842cc4ba966355f0178626adf6de43601c7b517e69f983aded515786edaaabd7b65fb38597ce569807b2ca8c3bfe2a3dc4d11dc746758441744d548937d0a22c4cd175efd23ead706d3d4d7a06709be658602d305a0a02e5e454d661aa30162edad7ad23075c4f3ef0e0e5f530eb68ba3ad705bcf925cd8668a1d7deefdf8615579c1f09e6af8bdebadd3ad7d5363f2456ffecd0053aa3237e814b704729edb63c49cced932ab07dd53996a0e0bf6bc44ea089593291b95c924c3dfe2172812ff096c61d971cc2f2a747cea1a318830170703de5442494edd1d87bbd3db809840442fd8c695d12eb008144ac71c840ca6090775a400a498b90e4a6343236c5b79397102293f2325b747a2aac7c1e823d994a81742c2e94128039d816880a344d0e09de4765e2ad430ff0cc2f7414ef688c0a86fc466e4622b0365d00251d666e221601ca19319b065d2c4dfe9c8c360986d956f18c0e7fcbac576db690a45730934cb961635053450578b84cc4b09e0dd669b7234ec5da1bc3db6fbf68231502d5cc2cc6d8fa34f67cb1d6e04f9b0a4458a21fd9c328f8d7c39bc4f2dde2ec10c8f57d253aa746a0de1be137981a181d18066f78ef3a882061067d8cc9968d746cf9f5c85e3a0a66972890f1f4de01cc40c3693dfbd2b583eb5f44458707a02818a100a4addc7a4ae10eada19f5203f891421bc70e746950b572ba1c8fd70ff21d2de941b96c792ea40b884a24359ee3d6bd3a85020a3fd44cb21f66d790499e9d32e6323410ddcfc9898b55ab0655e06e3042981ddab814ce3741b2cfae20f6c8d4f53d0dd8ef8d3bef73d8ad0c91c20ce75c9a429a286b04901d48fe77629311032aef3b5216f60275773ed0a76dfeb2ccca3a58c4faa2463d1518f9d444477504d6b5c93af832fa9532ec6060c7b5747b315331bfe6adb2e54ed0706c9911515937b524df66d01f6bd92d412fd6ff3b888c21efd3ad196acc3732a21b1dc24aef702460b9cd25f1d450e8a5d256b9fcee90d84d07f9b222f10f9bc32430144f0f97d826a5ada873cefa8a67b20b31b4236b915c17cf41336e4ecbcd6c8b94f70598e3076f7d7d30410b7def047e332bec210c32561ecc2d17fca6d0c09e02813379823f7eed085669154a5ee3dc7c4490a2570c5ee3304f1fa30e1146177797ff86ef605dd0366181911c09010e38ccc49a9e98a20936900cdc4045d241833581b7201acd6975a4c6565e14d5646cb037cf8e2934fb987d255b17a286f42f78ac7399d15b25ab85519feea823ffe98d36b43ee7c0550fd0db9fbb1cfd09849d349489bcb11acfe89c3880f5a25b7ca681fba6e1003286591b2fa2be9290df0d2989b5a730d85f44cbc3d1afdd5fd40bf4695d6a06fdca727026932986bbb6c19bfb6e97e8ff86eee1434cf4bd4bf711bc1ce532bd5c00c16bad40ea19d000d73524411f2d8e98a0a626ccdba7caa4973e3ce1e4998abe5a5fbe4cd650f13be17bae456c5f395dd28e82656a130b71cf5572e18685201958de21fabd3072f01dcd9c261cc774c09dcc2697e8c1a4dcb9fe46d6ce1585e726043c35d5de701dea48fbf2832ab6314656b16f3f2c4476eea5e606612c271f80fcb1b124b38e8a608a295b96e0f695a39152c98a0826d1b78779f5abb5bd41662a15dbd08b64ab55bdb9966a6db18b607b69d37b7e73951b22ad299986e2749b43ffc8d1ed7954147f7da1adf4af50f533e5fa9721ad92bb3329a7d5e519d7dc1e65db43cb95e80db3feeada3093bec6debfa88c50dffdd48ca8513fc97bd79391107698c2647837dfd8d0f78f19df4fed5f744bfc7aba6a1b31e19ee5b87ad33e70b9f1b1cc09a0e6e06d4815b6550f8d8577b5efa282ce12d7c5aebd7c468ea723bda1036eac8cb71e62284a3aaad93d45d8ca0313ed512bc734d264391047b6f2372eabc397f575594e4ff32efae17984af237eacdf1ea542f96d752ca2d696b34c82ff24b16c855243e7a0c707e4bec4f699b029f52e6433a4fa83d36f5ade7f323d24fa7d65792316f981f7141180f21d99888d15a016b3c56005c07e8a934b2117a22852fab15a30f9a89a4680b768b93d3c446c742ee477b9f11ff09f0b7c94874e3d7efacfd2c8d8fbdecc3413813a3ae1283548d31e88961aa819ef76f37bc08a82f19491288bf8af4dda12fd3720bcc1a46e92a36efa4e28c0dfc29ac56d0f2290b2bf0af1d80a2e6414df6e6cee8ca5572b18739e6764c869f4beabcd4169d6e5fdda8eca109472928959c133dac274924e5444f21f6f211a5fabae93851ebba1015b737e8d412a8aad23a6ea7a1c662cee6ed665e5722f715192bd1b64aa48a8e55911a52950c16e9619f694fab9a0460bdaf607b1c8f2971fbfec7aea97c1a778845c0e1d42b85a876955044a12834b830bfa806648a9ddcf152b9f871c662aba87f786a41eeb35db92ff6c480e904c536a6719f9d8af510f35dff6d690b5cca05edd30bd46fa775818f7e591065605f8343aade11b37845e81d974357ce3655b5e7d1bc99b3029603de393bb08c419a8ef508520166ef87e3961e385be6a0580d61def567aebc3b6c2e16a4278f5b2732e6d9e13ce4e3926046ca98cbf318d08b8d60ca09e17c0449a236b3774bd75d35c4b64ea7d39dd58da8898d51e61e3fbc55d2eaf1e4cc326f0ceffb603147fcfcf343a5fc92baad91bf5166625907af66012e394e8a4b44e5dcbee8b4ece1b1b5b97dab914fce2800345f0d28669651b34b4e7a4222b76e12a5401a407370459831799abbb0d0137ea975f2d32684ccb098cc113df655c2b2246a4e505a0abe8b92f0fcfbc77b55514323478497ae5fabf1ecc1b558efb28ed39056e10c1cc10dcd861792405c4523ec17f5de3951c09c8fe532bc9521ff179ea81ff0db94281188a3f355f4399a78a5beda7933253a580f735e5f756bd28e8a8b2bc79a0a8ad5d13b78943473d5813332a7914038f15edd1c156133e0c50d632cd57274c00dbfec804587f2f942ec69608840aee96582e1bd38eb14fec7a17cdd23201b177c11b2e05ebcaf51b1e553e6319b3602a4e1fa2a6fbf88ae6ba7ba0f696f1f9c843afa8042eff8ee41ae8e7a210d615c8de1146a1b0feab759ee1ff70f3738cca4ed69f86a4f1b9b1c1cae99f2c1f2d6ef4f0ee79be36fd6fa582af6ec6d98c68b6eafcfb0c5d87b8f600ed4d2dbd7f9835387f1f374361212616e0b18b5d2c8c5a5765095d65e7b3820e803bfbda9cb18923fa569ab127f921f74366b18dc4a486fdcde6e997d70e92b7143c8ca52bf4264d5d7582cf76f3981d2d9cb2b30800786235e68f15812c8a04b5c5e88950362160b613036a4fb1f9d559374ee113c9a405a3bb3fb862f4610cc1657d7603f7a626a777b0d3e083de29311ec164eb114bce1609d0298f66cef86127622fa095a2f3edefb2a6de4ae63ada8642cd1ff1c0428f53120af06c4078858bcbb257f78b006f117de364f3d9ecf591ee37bcbcc8e76471a683957e335e32f73c23fc4d7c9dc03c56450e987abc24447273e088aa7827ab02fab551987109045f16257796c01f0ec2ed087c911718bf17b1ec6c9f35b7b1ef68bb77835e5629fa580183c4c3cdbc4ca5875b50bc34664d97550ca5dfe8a61ed1993f54d2a801e8e1bfce78b34907c8cfbd00389999909584a701dd3e35012537a3eff6cb30e323a338159fa2501d0ba4ba7efafb937f50e7245f7235c99501b3d3320863b0e439df79826822c2168e21c84600950462f70f3e8ac25d8f10f2d1cf669529164dd5977dd65291fbbf3913271d485f529c8dc762babf33a476930f0c8e99634f5b6952b9ba74b1c284b6b27d720336e303dcbc94ae65e6b5700b63539b4b67ff74ac4853836ec5ab59c6ce0db0f2cc8d997600b6b7ce9705f00f3e39d95e449612391071fa0180e7fe082c66bde61c8531a7484a25b90c129fefc9bce817d7afaa6c3623877d78798aff8f718670057b5ba0af8e0829e803bd2a763d71260c3f626d0aed0045027e9e74a23d2adf8614865fe3a163b42274ce48d14361df75167db0d25a9946eef40521760a5ca468f26eb20d2cd132b4ab90328f29e6ca8d03d92aea5ace32329daf7bfba0a8e0f1afa61cfa389b47b279c117c86e256356d3d7781ea3fa504973a0630e9cbf76466934477b69e9ebb475e97dda90a8ef5c104f517b5720d10ce459e760026a4c54fd0529b84840c6baad742e51d3b2f50922595b0ab8fe7ace2798a878a8b03708bc18cf0f8e915793c6d0534f572a87b691d037db79aebb634da695166c4c612654dd7c7c2eb563d459700ba542e688387ef0941e1c18085347d0cabcf44856bf8338207f26441176da54363f163bf2c8865a8f2be95cee5132ba1762bd1715df06959014b72124ffcbfba8093302411795b0c19ece0118835908d934188baf9ece3d8f95d17c09d6cdf98b9e060b570282c8713bf22061491d2060a7599ac7948321f22be1a8bd04694d2becb590536f59ab52ed08b05842754ac3ae5991f60141997a2ab0674343e6860a3ca6dff401e5a4a705665004353f5e9e26ce9117458f6716a4196f2e0c09e64ab3bca824423c3fa6641d60ddd65abcf0678d66ca2eb4625336860cb0dd7dc1b3adcdf79e51018f20b2da0f9c8819f492441633646903a04b9a1dbc07e4591912ebe0aeeaddceb580ac78e95cf1d480edc85b3498f7a362e1e29057f7833703fefdd27af6c340e7c357f3a3010abc06652b15fc7a6ea70e12b2afc3a8af9327d863c363156c8dc7f0c90f419c0157d3057b7a14e874e0f4d1a1cc1a0ae639e43182d613ee64695ed6e2558990f579ad4af02b2145ead04595c8b453b9f25aaa314081cec5ff5dbf0dd1b5a232aceacef17374bd874bf3a275590bca4d5abfd22d89327af0ee16c5ea5a5c1aca7ba420328ec9d02a1096168367386c537f695ebf0917740672763a30c1ffe8f6d888e64bf2b6e4236a196c69d6eaef712e14c753d59ee214e9d7a575c9fecb4f7bc551900110c9e9d305241bf16592e0a0cf12a08b73e7311f72430b931cc0648674d4bc3fe714ca7ebbad81a30e53dcce271cec4a05da78666f271baeb7fbaf1449e8e334f12bc55a7040c573538b6cffbbf206e48425141bff8c05538c4e6bc6fb9c42d9189d530fd0ed612123a86738fe2a19c9c38daf00dd2298c164da64728b9924f9ae175c1ea2a507742b1995f8f8c9c743db20f3fc14a70216220442058f7e9acebdb845536f9ef0ac350b13b397b212461366c89f248b9a52ed105cc9c842b51d11d11fb9d92484fac27e026388e3bbf60d8bfc0c8c774b999813d760a652fbb294341820669a1e5cd16966bd47e290297279c57b5432d1637eb4df7dc6bd85c345800673562a6547c00985274d0e35a58cf5714bac07d3c45d7889dc814e0e4e2309c1a5c896f8b94a73c279dd17eabeb92ccae1517b0e4e6a4519242f06772ced47b6f77e49387a75588bb9084757a21f0c60aab872135903987e48cced77cbd5ae9128ff7a24fa55b7b70cf12186c0e5981b25350fd15f55982c79a4c32906e955a11bb19697080618d1cd7d73407b3738bfca5a88ac84fa28adf2ba635e63d81a5c3df46d6347362f603feaa6889e63330a2800fa12d9fde98377a3dde65d311c5a9e0c771a3b010d475871eff91155fe279f18b7cd0efd78e13efbe8abc79bed67a515ea194d799afb68ae425f57944f30c27833ce3d33c03bbfcc9036022e333ee4e88e208c993615fd5d51d5af5c9826be914debb340466cb63fa07b2abde5425e18708f5b9233f1da16b16d439c44c7128c26d38385bd9aa9d3e7da0a17a3d6f1c2d55024a11fa7e7a602717a06f6a334d4dc50d065aae319ebc50d6eb3ced57aafb59d69456ae6aa085436fe72acc1345e04c35b10911c2ea4fd8da7421709278d59e731958b1db003a08744ab8ce3cbddad3213793d095f09cc4ce2175520b422e3fa7c6094ac816ca540d3f2987ab03021bf7bd02595631245208310348ed2287c47479057d4c2812ca385c62450f21860e9b82842408e7c7e259cb6d9e2a3354312aff42852794f8f16011aca4e823c731ea18a28557e10928622eada728a042e70cd994d4288ff67645f297693152a4c4c57c47ad37b74a2e9c9333ec840d44d1cae978f817d04ee3c481efdc61335fde2b2f4ec1ecb21ffc68e50809c37820407268ae5c2562e5eeb0e12f7d51c29463f8778077863a412026c9b7c2c3c74d70444a2c8c14958295ab18db94e5e1517e40fbb39c29b96c204e1d1cf140fe4fd46144ba279150d54a7a4cb3f8a8e91301f367123faf58f0ef9b5a4feedf30c59187fc021dc60001a015695e0374491f2ed2fa76db7a80956a820a522260eda8d6ea889de5bab74fd56f55a6a17b4ce6aa4bc4867f7090741207d217347570cbd6c98e38ffd0d5f2ce5adc7ab403e7bf60312502a3d29c079fd0b9928ac4032c76785bf85b0293823edb200728940218d11fe9811b10176a6cde956525b9dd188304d2dba36a98a2d4d3e66efc561da5efd3ae8f81cceb9be4f60205ce0c6cad2eff745f732a16015aed1b41415d61edd6a176aab91efaea39a0c116b4c1cb4bf3754ebf3d37e32fe7db2ebc6d012487ce619a388d3bf184278ec31f0d9e16d2e7d850b56e6b9d9e52beaa64fb1ca6a0ae2d5e24e98973eae48b7b4c3c0ad97ed19e7f5ba971651c9edfee51604d77eb313a54d975faa7c519ec1835a28b50bb489f5896f53f3cc667ee456b7f8672b373016caf0575058b9205d368334578ed2b737fd29a118affbc89bc43211a1222ec44465704ff1ed1e9833f2c8ebfe2fb1bd0e40c6f620f77283d330c69fc6f77a2a56343090c25aa6a213852049042adcfac8221d98597cadc495f025a9328c453f53cd007d70265964cdea924f31357e9c48875584c659e01df606d6b2e9ea9be0cbea7a7935aaa08ce0bcb70892c81f6698ac61e2c932fd2b4a4909b9f5f480d66a998cac658589b53d9deae72d9cd80955a38a62f95ee6737973e59a88a49551809df7f96b2581b2061991629f4cfc9ae3fbafa11dac1a9eddda390c419ee7ca6a4db2048fc268a456ac6c1d952d697b048abd8c202ddb3c40216a29388bab851699615982964504917daa1cd586187aca3850faf9109a56ba42da499ab5c1274a62aad6145de2a9d2197a9a1bdb0dc6b555c32a6726e7123e43b345b974d18a161f503d4eb9145d0b01662f1490efd8ca9623519253b51be3168edbd085ee780c3da964719d8903ccb7f9a94d17b4242b5df9026b6aebf338b8122f7d61a3a060856f48ea2a9500e1a05c8a831013d20e3b488cc1debd7976c1802fc4f49edcadaedf3e66d71388a453a990bb5f87553d3fe113f4953ea3f09f10e8a46fbdfc58fd35446b72b44d04fd014788d18dd1ce05bd99c1423bafb56617f77074a28e93587e0aca63180e96426a74b054ae2e1fda44ba37b43718b39ae01f1fb3f25bd077f48d4b6321f602128e1dabe03c1a7fb107e9b8dc43558834974bb14856c7bc3f128630404a7d486ae010ba14edbe6143d6a0c8eb5fcd14bd8ba1b01e45ced6f4609636f2602561f77556dffd6956b0e3b3443618ad4bb311f7992f84fdacbe17b623be32fcf9195284741fb985e6e807173ca97db9ce54ee3b21880988830f2a1d9a385653f00dd51c21ce2fecb1c4ec79ac77e14591643edf49a83d20141a405633a3f480930b9105acee064cbb9dbf087699dc38cf6a366e5aa32edb0c794ca2ed9fbbdc82acc672a0f006c4c0f4f9dfb4aed66d7fead2fc1240712510cc441032172d1a90a42f1e8bb6e3b9ae41165128c07473fc4b34094a42dc549233320c9986ea8bef5e13dc98209bcd504502e47a0b1ecf4d710666fbedfb1ca1940a33c500682fe5598958c2f7ba9e2b67a2898a3ff902c995fe1a47e304800f50719ba5b4876421e6d4740f094e7fa19c4c7ef6456f51bfdbcc770521588edcf6378887e36897f5a92088495b6e2ecb77f878c9efb9383fa738b47fb2945031917576192276d9423b553523a238e413e025f6090bd6988d48787acf1c39680c4026a3207015295f9f025a8042c585eb9edb66786edd15d2e8f12d985bfdd6f2b395b619c6a0bb2806016cec909bd6543c58ea830ce057ebd1ed0a5233d7cd6713cc5b5d1a833dad7b97a395e3a93f812cacb28a57544c3d2ef9df0576d32624457aa70e4ffb951f6b3c9aa5ccb00f9f227c2b5467751d625cc189c49a92aabd31c5cfae567ee3ade5358de40a05e4783865b6d53652beb1f045196b2d63d771a9a2777a039fcc86ef54eb9e1367aa32fbc1f87897aeffee71a941b8e2359d52b2aa5ab39fd370be8f771f6ffe65d40a83e74385db1dafacd6671dfbdd9fe8a30fb02a1f995768f9b02ccccce00dae7c868d381888d5adc7ce7e1cab4ecf0497d73d77f024a3d46a40e66d28b7e3e2daa1cf5ec4ae66e3ee57c197c0b58ea40daa1364666b58c86005ed432f4b697b8cc906662217e274290b57bb66d8131e256e259781a25ae3194ca9655148f24e693531851b323c64af209a0fdb14e5315e5249a5684a913acb44b5d428bf5f4ee61dcb1b2a363bff284fc2d4591d97ddd68d5c48cdb4d5eec61f1515fda6b4023767cb724ac7986e19269b91e6580593db51f30f422d6925548ed0c1f5f9944e031ad63e132e0a7b733952e110e2dd2ae6672971e3520d9bb3bdacb74001fb44f2bb8be75bf2db80045df1e0300ef03c4930bccc66f00de73bb09d4663342eaeb9aefeaa2dd4f5ba1e2d0f64b58bccac8343bcb7ed36009a3ebc972cc390d8a63a141b41d0bd750dec51c64771274f965a1728fea1987c83c8535071132ddff52f0c68c41d9b623397e3b1349818809cff0513a3bcbf57e25979b85ff6e1ec62396de4a0114006b301c33be69d8cb91485a17a514911285fb527860df0b95d3c5c9d60615f131466cf30a00789a09c19b74de3c675294680afb18b543c3d1429dabd7324646c8bc4bc3cd29b6ee8090704a8cdc5a1d6da36605b3fb8143caf554747ea4c9d0bcdab91f9707048f795c700bc152731e1cbe91a9b2677839b089c23a1294ed761358616e3fb8be88fd8d50d0d7e05ae3c732e8c3a57e92a0337717292acb758127409e322998b59b61e07204e9191308d20147895a13f66a2bd0805a586d65e25bdd6a9478aab15712aa8f4ec0978fa52e038aed1d88ddde4bed8b53e2a619817f5230cc9cfaff7c0e9a6b92d903c028de80ec29529f88ec6bbf41944572d302bb0c5ab759c1bf70e16920f227552bbe041f975b6f3f70718be77744b2517f5c48f66b3bf439709396aba5c926c6b814457574aa69e6ba3d213ab3c5f3f26f300a33dac395de19dc3a503e7e13dfff66b99f8f392f2108578f066a724826872ab1016ae8c4dfdd6f90637770bad62ad5f2c813e526aed48f3934b92dcabbe929eefb2a64d9c5577dfcfbfebf596e2949abe6c0d89818af23e65dd8691818090545df910b351065708c2b0abdcd10c662f10b3e13da435fdd35e87accbfffcb678e1a2bde7b4cc569a67158280706d17e12d73c6c9c1e6ea085a3d5b883b759d52c9583c4a992634e9e2c4a1cbe1fa69bb1bff9c853bab0df4d00712aa10c3201d12788568e5d79d807bdd6f2238593b85a7bba88079682372a5045ea5771d4a7af0c6b8871511f02864c9788f925e4fae4a008c610ace3199d2b3a87df1930e2f584fc36771e3291783e63b00ae1706f8f5b02941a66c851c3ad627c4a7ff093b99b963732d003c10b90f61d616212cbf76d307d4b7680edb5770f46ef40cc4efc045759d3404158f1d3b8865b646950916d3cf30e583eb30c0bec8cbc85a6cf5b7ad068cccaee6883cf6b50d4ff6296ea1891f00603e8f5d5ee7509dff530dca53e1ba8f84a37c9cd980fbf899f7f887a37f53d496d40447a472f1f3b3ac29ec7c03c72ea068116a3e5cc12f3233f316eab3bd745d0853ca57d5572fe4369706f0917f476ab161c9bfbd0066927a2ff3833aca1a912185c7edc9856203db0c46e8d5db4290097e858f862bd6168e9e6befc3ce809b10002f053296a9932228719da0fdb7ae6bccdc47c7e1f4899b9358da9316c51b0eea76199ac73a3cc9fc28a35c9b277eb973e87c40226f4928ea52f15a8e708e567a492ab56acfcdb211e2f2894b10766a08e965b15cb51fc81cff37097f5b64e1edd463714cba6ba3fc461e4aa0f019ecdfe0d47888003f26afa671ad8f35e32213bb003b497a98d7ed64fdd1d88507ab2a006c99bac0833c3bdcfd74934bef86f45e8372c99c987eec995f25bcb5cb276326962672e5f2da63128aff497685e8224e8d6fe9bcc9a810377ead40314ee5461bc55fd7160c34904debd186e9da87fd36a7e0db55fa43d9a4309e685f89555bdb8ec25b64a8e23308e127c46dfd27c10b44e07cf27b1fddd97e83d8ab336620413fa77dcd35b066cc4df4e75520ce26ac1dfbe3ef90240b8b783b91477d82f9f6145d1252695260414460883c58f56612d8512b5e980994824f5981b34d3cc10a17fdb0b3d20987cb27f8f6790ff6ad6bec3579bab83877c6de83416b22972e7f0ef7c0fa4df9c36d28ccce516b30d347f59f30c733f15de89ae895064232324bfce797fb80ae84ca20888081312d7bd4d3ed8b2bd35bb5f6c19689b3c0033f5e48ec19b3d91de93bc1dbd9a15feb112ca7fc45b1b1916bdeb521eeed810d81d85d77a196df14bf42b034abe2b251a0efdb6a0a8c08d0a4d36b7f3f22b305c069400af9fbe8ec1989a721c9c4976b522efa6f4364b84e22a2c160f21ff0c2375ba276673adde031e083802b2b0947319023c6f0b629aff4f4a853fa30a1191a30f4cd0d1d958673c0f26b0d03ba2d37b2f232059b4b7e40892a3156463a52b494bd3a14c518b1b549de9af4a61085e54d483ba733d05dbd1191808ef6028fa48e570dbe52fa2d1b0736817be2b980a70b8735f37378b37fdc633a2333e0842c4867f92689847a2e31822d171e4c848a52439b66a55f8f11679f25f7fec595d11816effb64c3bfc25b5362039902a4518967dd140afc013a4e8f59d83aa0eeec8664fc92cb34c5a19012c6edabcaa83550fe2465826d7506a32c8b0065cd458b4aa43841d8630be8035ec5ec6863a32bbca24f46f8ef454f62c3af0e64a99a4321978dfb104d817c89dd394c9637ca6f2a906d4a4c74d99bc5cebf7d11193f42165f2fd6e260339e21518293d14ad4f813eac780065305ac2d08eb60dfa2e6eada4dae64e3ca41f6967b05a0a20496f0276ed4b55aec9739005021fe6936f13df8a6ab3f6358b352cb7864a3f4045c425e368786ce37aef3944bd4d84bcbb833af4a0072da8423d743d78061db4421d7ad083fe035fa10e2de8410f3a86f80f15f44105dd6ccf1bd4b8461b3d6df84683be4d8c94ec4f1ad04c296e2fbbc43d3776957902d1350d015e1a0279f7831ea8a0147a68833af47bf0071db4421d5ad083fe075ea11f2ae8830aba0cf10e25e8410fba6ccf37d6688d1a3ddbf04604fd4d14294512f53c141dfe1314ed9fb924e37672111d15a2578ce39583e9191759ff5c1b6af374500d18781eaa028c9e0eaa01038f437524683f73908700dd898a8e135af1b51f65349e7aa03cf3a82633a8853ab406ea38c224ec9cdfabd2a3952ca4749420da3feafeca7bad38416bb1eb72bb718d8f869c357ab4485e00b49687e81f2d77eed161b94199c9a89729a816f460a187ed9f5deee11b62d6523d9ada286bb28d9f92f33f57d09044a3b6f663e8fef07d0c2759434912aa06f38c68a11fdd9fa1d6fffb4a70d986e90c2ae78b620a94220ecae6ab4ceea7a23aaa010ed8a551b04df8b1e914a9331804cb210c2989add54838ecbf735d7ac39bcebd5ee7e28fb48476394734ad1b36b43c3ff1b0915a02cfb2ff16c0cef27a39b4b00695f683e0256f3d8e2b493771fe9bd6df97ca59c1957481a324d072d8dbd61c6e1f4e4248bd67811fbafc3ad98d6394044eec0ca1e8c3a93f30a1ab25227bace7b7e48cdf8e077e4ba9c2593fe3f544873654064b803b0f79a8d97a038334e714508ec99f760f43dff0d36a531ae5a1982c3bdab360c4713df5ef08b36a258e9ec51da1c0a57fec5109f00257700d4a30df0e19afe570a5a0dd41b1cede76b5c07515bd7888aa06181e41bb101bb7df2b5c8f976eac260183f8a1a1e35d70bafd3c2932d8fc524db2ac502407cdf1511dce2672df32ec0594ecbeb97eda70cd55235e5268a487a85e30a563ccb1c18ccdae759ea41410776d1c4e4f21f5e2363e4da2cbf6ceb4ae8f5d4c3439fe8f8a3f2125fafbadb261b85b2cdc192e1b18a21b0fb6de5872cb3d2efe3399df7d1f62a40abba159b9fafdbcc64e359f72f9da67084c1c42b53b43c51fa063d72a97499d3f9c1e0272e0471de2be375dc8c0d91c1013e99b9e05ca5d28f24d25107426b904cfa86343b46003c5281948ec4f26340a431cb44c65bcb6d532ed45870d29e728a06eb62a08327c914b332cd42e534650512969f4e59002b46bd4644149cacafc3d2ae2c10e0e6db7af6a52d754fb772fc01dd4d99d747f1308c2ab917328ae1fee5332a381ba73fdcd5be3e8490d497136f326f415c8b6bf27d8c62f7fd9711011fdc18c57152b8022be869c1a3d3b245a46c340db7bef7d756fd136e5245443f9d79e8025626920591aa6619de30f02271a2218908345864bb64a15b9935e2f423c3c7976920a8530a4c1a97c6c0359f2f19766cecea9db5cb4520aeff9a853184ee4a158a62b99ec12e3244d30160779662c2a2862666868c362b472996115b281e07d8603f390b78619b80d044d1a693aad5ceadb903f6e8c078ffdc473b4474a06a09b41f8f552c194f7f5cb802f06971eddc3520abe9d2f75e3988e3d03a6afcdfcfceea18c51664b37661603d1f615b2ecdafba0f987246158b694b024ff54a8258ce2136499606cbc06dc478fdf8bf6d1096c0aa56e3fe5b906d19a6335c769e9a047d968788e1973bb1185db4d235d581527918eab13ec3bdd530ca43ce6d7434daf9b36d34ef7f6397ae4c39374d63248e64f8b963037ec7f6d341361ab46bc861ac08dad45bc2cc6c38241573a47f745e039947153746f40fae46c0cb7fc2a83464548cf0675d899d7d284d296830046d1e2fa765d45e7409ec3a6ebcf471152198df6a7ddd7015be6e8aae27f0f532b3975cf27d44a8bff68ff710331ed480675d0abd1868dbfa3d3cb7294e63ddbb9f547dcf45f4ecb5ac608a542ab721acc6d87944421da0d57fcfab45293d23a0f63904a79e976602b5f00119204daf2286ff9cba161c6b12beb8bc0b8d18839b909eddb9cd1d29280f270e8cb21b1cbd04e061b573a432c1f89260aa0b1817fbb82e67c7eee8d2834dfaecf150297bef25c7ca3382028b2bf05367755e2882068d5cc98e9ce92be2cef2ac7f0cc5b7ae8cc3b1d8b74fb81a33e0aa01909525975ea76119f1f02e8b1b2b1515de81188cc6f175cf26d62a34afda8b5616f20df52ca1bf6730b6c91e7477b0f377cab4ddf40e20579ad37ebb024a0af17878c89d9f483dd3002977f45f2c4bb2dccc382c9641791e826c5d6b0ebcb5aa33aaa4437bd7fd7b329c9f3a42c5b97b7c1850d5196d289a096a4324862a05fec814324daa89453b984ae5adac3cbf432b0b812a5669fc48580be63edbcea83160b8058545efc959156f463da638daefb653d1a47a2216b4d326cac2f38de4c345ea76346f41c02662787f8713190f27694b66e00493c07a3ce508f8ca1283807c334f31b22bdbf3977097a30be947c98367270f19016881555b780d02fd6abb2e779e8c8bfdf06efc700bffdb0b9daea44319e5e6cb2ab1c882382033fe654bb90b3c5d38f739f4417e2942a6a2759e104de472b3dd9bd1ff0476d6dd2f0299eff6fd96702df7768d1702fbf254791be5d082d2b14d1c5901f927a6cbc3eb07efb68a82de1de7e09807cad3ee39fe9a89f36ccea290ab67dd1c568c35e2ed8a019de8723b8abac12a918781334eba5abe05536e4dfc1f9176b93d109a941c24c1fc6681482b1f7286e7258cfd139c9764e779f9cdfdaeb3daa45364bb4f7a4b6a90f5ee950b31141e01a47f9e0f8ed82144bbdd6de8edb83b41b2b2342baff7cf452c988d607c449a3d7d8ea3c7470d1a743f7f3617c3dfecf36dc82065652811e6b670de006c6a3d901fd73f00069509e4f468335faca9c98193f7108fb979c8dce97541400e8e723e4c4c34330ec6cc9f3f6dde371336eb598292c0deccf8331e25581d5b553e8c08116feba82a7a89206af918f624645da3a9bd07d122bb1f15f6f0a7e3a5e0488d45fee67eb6fa3c96a88a83a6d7e9f200f7b7c1d83a7f86bc126497598d076eddcded51a5b29cecff4571d24f99fb5515e14c68c78e18e14b00e28a4f1c903e1e19e89e454b19337e1dfdc1fa3b150fb240d4634437a7fa4cbe9ec87b60f3d258014ba4182b2a8f1dca351a5d0661fcb9fa31b208bc060816e4cf4f18d7854ad0ad4cddcb5bf404d2e36b1cd50ec3fd48b8f35fa29d6d7b34bd27f8d076195ca069505d16b7eada2cc36d25ed4f33ece9fa2e4f482ce2631e55d85495cb8744c41632efd9463a687f942138dd577683165e2a0c51dbfa3008951ecb127bdb138aa31cb17d7ed816ba0b8afe6e391b29355e5efd632c9ca4ad760b0b3181f3ec95d4dca46a00aac6c44fdfea341cbd120de2c96652310511a82601f771761489092e248511b33295a5beb41e8ee68a7cbf4a7a9d7fb5635a334e716ea1eb128720c4f512dfc7e4e3eac6202bcc675791b9387b229e36fd96ead5ae9d408f9b85e3e1e619265e8221b2f9952a51310994c92ce278057696dc36071e064856f62d2b15b381e97d26215293f0979ccbf4d55cd262d4fae12e5a32ff98be96b9261e66c9dd8e78f1b6eb1ddb2c32edf6c224e2c2c77f50f135cca7f7c750374d187151fce02abbac8544c467b3b4114bf7dd2934dbce70081263005161fe8f53a28db9d8e6e14eda7e5b41e76f984ad38d2803becf56e7451218a9ff5074566b31faabe2893f4b2b2e299ffd2d617b9c1a0efffaef828840e8728b52f0ab4fd33f4aee92d4e0a5ee426a836c8759fe123c918a5eff3ae217b60ec162cfd2ffe55af2d4614c7248a3f4e7e83519a9ba66b910d08ecf9082e0a4f7ddc30db133339887f2044d648d58e99ae53c36fa4ddb36203636f574162a2f78616edc10cf7bb32d4d3d71a8a9dacac4d01b278afa8ead2df387b6b5936d85781dbd73f9f32197c351ae7b6ec61c35aa53392de31c42c155b0e139184a99c42564c00b796c9dd70ae8eb79e376d08e5f67739e6adf3d5c0af3e0fb777d6c9a1b337096ad0b52190897f1ee10be252120edf1d821bcb13282d46473b81f9ec509be82ff243987fd17c93d038b5a17608fcd875eda8fb0fd471896b918fb1a6b8beeaade32d6dfc1cc5e08f95453746e05dc93238b51e73a785d0393ff2e8c78925016db2425424d8c1122755464b90baf976ab6459e0022747d5d134b29915a485786c9d5b929d61ab0cf283027c042f0057d8b75c97c81607e1d24e5212ecc451e62bbf556a2b3a540842a4b87b8011d5d57a7b2e97c8e0680200588bbd8faaf348d0e33dc71698ac463b7f0150c2048b3d28d8f5825fca182989336b78d0c9d89569d307e0a1fe080d0c4e65318563acf5991c665927f9662b75f4df453d8248da84c79f1dc3784862638cafb14dd282750ae23089974d30534f1a8677274648f37346e1d0c27687da331dcdb703f8ceb9c96687fb1b7a4003e54093f5281e560e26c43a6de9b2a62b89ae0a6b5266e04b187e57ada100515822c6729075d3010a9b52052835b964b0ae44c9d21d6c64abe51a52041c8d4487686a4303b317ecf7adb22543c3a3623912ec21455632701009c0fe618c19a917d37d197f31fb93f227aaa2f3e4aee978ba645e297c30b77a0c00c6f4735d2937c83caebc0df23f98251cb120b07d6544d2b477fe061d54dbc5e70bc0746ed900f383e1d5403c84bd712e1bed50d8a7b88f553d2843121598dcbf105f217e23925a6fd62a9f7e195303754812383294834efef7b7b76b8e7e0eb33d8041d73da6672dc163c420a15a11404020dfe0088075dfe3b838dab84d45c414c441bc7ee092d2c37dd265aaf4750512e3150fefa5e8ca4cbcc76f620ae462a199000aabcdf2c53956c34444ab9accb167d3b47e78173a2be9c15cf247c47b3fe843e176ca73be165166d192ffbdb9229ca43dbcb38b82ca987cbc255f746a517c165aa1199e996118a11ef059247000170cdd3d21d79a075b0dcead8f6b95559765ad05eeaef7d92bcb21bfd5a92e02f1ea3b1409728528e325cc9b7e11d2c00983b41a248af4f621c6f8cb866d7c5c68fdff9dca497be26f9d43a0187cf1962d3b7535b0201ac36a5450b6c4444c884db645066320a8712407660e0169df622056fc242b99816b66214214014fcb38535d76269c2e13d9a71d922ca2ecacf7ab1df6c08db5135f3cd5547b4235d43c92c3ac93b4296e9d22589d54006b416095d6f81273e2bb81a7b760b7bacb2111384ab5ad3eba044a87e1e53f6d4623e926f3f12de2702d113677f49fa9434f00c87017844a99758bcde74de899f25209499da903318f0d060a8a040a1f871b142d6a3de6a0d25f225e9cbc2c9ab9226af32ad4761fca23c76bb5304ffb740b21a1e4e5174eb3080f21a598909e4bf25a8cde03865e1afd258151cb61496e91d5ec4818e1107775cf804868c10c6d2a0f264d0636cc49b007c2dcad491caf4e268fabc2df0a87527cd412157e904a3f168887aba8a31cdfa0d40c8056a1cc5a5e8440891e12a7876c42bb6d89d2d62f43f6992dda3789f217f6c012b5ee95932a88d9610f195f5eb594443868cc696a00a768ee801f10ac419e203015600a5d9f9475097724649e2e3904e845a04708f31cb06a8c00d92625966c8f87282b4af788537312f20a13ba4d5c7294c23742bf87c9acce78f17e18f259a1b07779249f8f7c9b5080199771078a9f7c6656ce1d146234a5658c30d5e140e22f40adaf7f4590a20443b6dfdf516d9570df0ae39c903f6883a0b65bdc07c4102ea90fe218d98981861b0b1eaf9c2ef35b2693b0020b130ca9de08ab2498571010e93d992856fde107689aca698cbe3cbd616a7e5194aa73aa055d58e2a4e3b3cdb63341b567818b08cf4886cafdd0f5f8c8f68059ec3d32b7cb03c96b8b87c362af3cda0ba785701eec71ce8fe0752e33eaeb778f49e27e74febf2ef62cb18edd5a0e6c7cdd9ed15868906b4a026450c4c443327c6380fc7add56c083701ca80ed5214a1104a85903cd77c5f2967d89936d93b420de513297504410258629130d05387d7235aee7a38f9fe92a7fa656f2f4c5eb1fd3e9e599b84eff03e55a2f0026f02d64b72769d116912002768b79f87e78c9676730a5fd93426de7357ba8089d50c9741b2a59fb31f2ba8ad35fcfb920e0623c434ccc17212a65978c1ff6afd41f164e8891dda39f09aa03102c66f86bfbbc1cd6ce1fdd6acf20216ff459c04443ead3ecd31070f83c9b9f8294d62d10d5d340a0537c7367b03d0c53ccee9f4e38bace629354abd6b04e45208cd252f72d5cdcd8b0d97894ec3cf80dca7f0c1302b3b8463d4d79813f36cd5e5f2c1f9209b74b309b2a8bf326c76c33223cb98eb2319d6f309142f9ce757fc332ef8d0c616a2dba00839aa32ffa8192f4039335765d3f8a7cf7bf3f2d79265237060ae7ccc4a4fc13f7eb6558101a35985557cbacd2071a987c42ff286accc24c8ce39513da111361fb9c0e02a59ca73b2c489e62ede6a02ab14cb705099d133ee5b1c21827517adcb3a76724c238d66a9588f9c4e4956c517b194075411c76e5d396b1595a137b04695022303a213d5240d2ed8fc80e9d8306bea3f521344be5b71229d794349f0c7711cf8d5e0a53c3e88bfe15f30b71c8ab7d6bebba05a51dae9780ad7fb018b26aeb58939dd08e692d6bc2c818c2949c729f913803dee9697fa897dc71ce008f768efb87b1d98cde60fb03a75845d0d5dc614eb427f26c11b91558694d7c7199608e27dc2c824f3c9428f11e4d02172c22a82de07ef6925e09076a338111e195a6b40d5180db9ca760ef99f62da2c8eb8fdbc1987ff914bf4540dc66a70cb3d3c23b8696a8b0f7c44e19484c2c13e8bbbd8c88c5919404b5626ab288ec84d74c8e5d7f5377dba80a5eafe078d620097243f740f38a4df43a0e0d9ed3106acd4cb3c737af9775ac9daa50ae75b0e20814573e85926b9e250da7259e7aa10cb4430e62d14f442a057ca53c92d4f3011368ea5df078aa834bc414138b044c1acdd37445361b392e633f04ee69663b1bf1c935a6f0b2b8f8c4cb3f3b4e9e9fa802a9c72c2ebae54b60b8591cbf2072161e5a935fe44177e8c1bedb69c12de7ab258830d84e712988bb5f091b53ffa04eb32171d84e289bd007d197a089c5603c936311224d7c98ac21cacc57fc6638b319130cf9d2329f9917a360a46b872a7211ecc4d3cac77d95311ef3a653c8fbdf8ef187878c93684640e285aefabcf74cd61ed9893ec50215d8373fc7f311c3231fe2d78f4e11155e3382035205c1a50d5010d1881d38fd872f2c74cb30459c783fb439e3e56b99e3547ec60286829e4d7e8d5f86f8124d9182975aaa9bdacfb0a691ead298ac71b7958856386d080885aab164726643be69a759f8d496d60d4bfe9c0d40f5975066c9e3b682f241d717e48ad1379b0887f25de68ff310cc6f9ebe7badd92c3d5c6e4e49833be88186f5be8f214e410d661f66107b29f1dfea1d0e2d1a05c9465f1db5ebc996de9bb391558e165b3ab78c1a4008c5c63dee7bda2ef7c1ad3d4f39edcfe016b66a935c57f91aa05ab9920086ebab1c8e4548780dcef78ef797acab33d1603751394117e86fd8a2cdd369d193dea88152680cdef42fb5a2483714e4a112f47a1b8c4cab9e7c08c870527f0d402c7241d2c0d3ed9602350834f1e151d16d402b863e8bc60643e6aae001727610c22c1a6aee0110851ff4cc9875939c01a27be9d6dd95610c29607ce901918b52863c48bbc54cb74bd05da661babab4000fd0dce768ea7c062eb20624206508960620c1b3ecb035e87669a2a8b15cf06ece5d49bf88197ffecc1dadb129c823aca5d3aa92ee2d3857c5ad80ac568e38e0528d0ad361bea100b7d30113e115254b6d34ec1d74f09aba6146f7aeb7ae5cad210604e4eef493af4ca5bc1dd8cd422ecc9436212a61d19a687f912b6a700e2d78fbc0d58b30b78b5e21fb6a7382bf5165089f8dec33354e36db56c9c629439ff95c6db8e8e0fc48832ee6986fdf18305636202bbe4e0b645174020a72699895a15797b2c9b04f68198b0ec67755ce077107ccfa8537d1e132d9e863ab71fd75e7a7a38ed0db49f0284ba0548d535359d8976d166e55420f45c1e4ada586f4120dc1bf19c0aeeee526f4207e9137ffcdcd7763ccf5859da30150da2616f2c524c5b8b5d4b41d6857a504a5ee1b8a695cf302ccfd3ae8ebc0d2388546f1b404c5098f4b5c05383ecd5560d7bc7d428f4da2e8c1ef0882f8c6dc38d43da0fa5c78420fa55616a9ff9934e0f1a84a4a9689224363e1613a7f73acfea53c41cd025c537b50ef77a29f11f63d25c48c91c6ef1ecee571acef1de45e05e9991cbd5ebdc52d639b617c4640a990ebff0d4af225c902c690ac015bc0296800daa25323d2e5f851ba9f8500b7e82d5a195cac6f11ec746e38a04934bd745c76232e71abf37d04f77dc52164702e029fcf07b00c0823d156ed9284af6d9f00475af39901a14fbb823e5b407fa5c5df8fccda18dcce74f8f9e38ed31d9128f765aee0a0359b54cfbfb8e7684c47049b099369aec9b978bee0086a60f1d2a55a7a4a8b44c44c8b431387579b16692e925417a5aeb91d3d364c36caba1a40acd300a88afd4114da38044b9aa75a7e1b5505c2ea7d23ebdcbbbb6c42d25b9d582619637ddb4c4aba0c365dd62b7e5939a1278f9e350d8a2b4409e0a7fd506600e0e53f76bc7dabb9b416cd57b3290afa9cdde37baf4c5699847105085a17de9035216a6d0f5b4db7f9dc9785ad137379390cac6f508b885425b5297523d56bb78e8a79c1a2b7952dc56fc12ff019b42b88140e33c95cce44a1a9da13b8cb51e0a69e8a266502b35331f27a062281ba7c4a618386e14cdc91e3047885bb070463eb1b46e24a6705ce5d45f4a3dbfa2f013a7efafdd7eb1d948c6cbcdf8fe4fe368377e1a14fc35e586387824533ea453435febc5fcfdc4f6a21864e28e674a5f128f809d95efc4176c730105e04cdddb49da1844cbbad31d0a3183fc8ce79c0c8d036efda089411a5a5602076f5ec8018d9b2764e4df4c4bd04bba52adc743827eb40f1f7a840d447a1bff8a4c615b881a88c93b2f97ec6d79d446212dfea468b0b577c645135d9103660723bafc7001b7ab7977d3340adb4a638ab2731452205471f81b57812fed1ec4dd9f7d84af7a2a8073bc28176470e28a3e43dcae49dd758b7805848d618d01fd509ea28332f0d4a37d8bc5c18f5ed801248e994ea9d2950cdba75960a267f6229a41ca0d614fd881faa80b1348b58b465d3d15810b970682c43fbc37f4561c11cf5e8f761b66b463d23823be6daccada57cf62696ea2e2be6f20250c51fb075cea142150256e8c433144a2f72cd8ac9e4c628bffa7c91824260d12fbc91da1d138d961d729af31973e37297ea147803674c0eb90e87ecd231a3d31003004bffaea8a4ea88de418aadab1168c42b0f25b9357fe320a30736e138593fe629bc29ddeb985ff93a124b5fe7bb7e0fecc7afeb278aa685f12682c901267650790c88cc0ef6c677f278cf2c8881c2e4a93394ce38ffce146afa9d8e7f944476a9328a0b8bd780823080d4a421804dc06c19804c808c4b393388b0ca2fce96f9e9fc8206577ae6cd82e5ad64e0d195371d351617416a2aad6e4a49d3c2cb21d5d01718e3bb25072e485dab0cc20bc7aa554f3a30d1556bb5a05ebdf168ac1f705a605c9513a85a7dae028ee4900ac235c746af527222aaee381a90f024bd5a0d6d3e06a257ad6db6827432ba74c0b5cca1a66119e365befad94a6df23aaff5695ad54a53ef4bac55227f2f9a4a4bed9350da751e39895540e7ed16aca2bd452ae4b920948f36786f62f5f89529c1aa2b56e40b12af1971c3162f667380ff5f36591a13c08403d18bb56393c8d97e910ebf82110bd6b59fcae92c2a9256ed8769808f75cf792a75dc1f8b425dd950266ba06a9aeeda8f589edd84f88a2cd6a01c197b62ba5f9c6075093f2e175a51edf56dc3bc96ec23e501bb03a9f0db7d842a75b2a1a607ebd7cc9328ac1e1e1b71c735733388b12b27d277401689c4d641adbf1787428e60158b5ab71698e3cb386a61edf25d6c60af2fec3acaf004b06d2a00565943aa9fe256bb2047406760ab14632aace205c212c2292172f32b76bfd481be1c6cae84187f8b62d576a871fdab0859941b70d07cea4f9ec0331f4240ad91d7f6979c395b387ce8ebd948ca2ccd876d57a12d1976a68a8274749a9d0d6e8c44a0466b51f2c9dc8720fef7ca2dc9a3740ad013ad0fb1fb6bfad7b8caa0c973ebab88683436a70fad7357c9c7405e4532d3ba6805329f529f4cad5ea7c34cd4167168002121ea8afdebd7344817cd66106cc896ffc50de4d7ca125cff8c79adfd51660b14e996902587b31bd9beb90d898498ad7c7bcaa3eeb2d78240c1629d964f8ac2a8376e763964f39ee0baa4af460f52abc57854479329f65696663a49c25f63d49f4928258d042981e262a4f3a586d0e46bc899ca37d771732de2597f8e27b68af492ae5ed284d04acabf572732d08efaae154c03fbfa097a3e076ed865ec7021225968430e626464af86905680f9cd8de335ad24a66d10089c969213e0eccd56c64e3d620f7628fa6e3b066b6f7fc6550c3d25c038059f208a5bd5814699c09a6c3ace24035016d1e427b3fb5b0d09244ea30c4779a948c4ea47c1d988b66ae21f37ed6f37905706d871ee5ef46c14ae6774e15c6fd198bc4a1929866bbc15276a987fe4169cace3406d609be3655acd13ffe95bf256f7ee6b4516e9eb9ea914e7143941e9ef569f704441e4830a3e4154fcdba4c2c10e15a78028d310909f456a6e6492f91f2fd28549115c06843771a7dc9aaa4f1e416536f6e50c084fcdb51bf73eeda6f5107c8fcba3eac0c7416333ef04bc4966541a8c5cad61469e3a38e5938d15bce683b2ed594689b14c2d3e4d3249d79b6f7f6fc41628404b5918491e29ffab657d1ff80100b14997a56f1f24d3842e2c3c2c06e54700c86679682000f2c0ba15ac79be3d645084caae7408953e297793187989bcee6afa764daca3872e820e10bc78751addf376a54853d55236068ba77a4fcb6926dad08645ed3dd6413af1c2c96f4eb1ad5a7176733301bfebb1369be249c02721bd9247d0b2b1105fb1f9e4b966ef34a016a57a179dcc9c74b6ac32163fbd9bac0ea09f4ee03e711efdeb53232076b3496fbc400db90cf26a04c29017fd5c854dea7872a9ce3047722535c7d652892e375e512e25821988fa45222a5f140943d1c3216a44f6fcb9c445d29ec263b7ff37c44b3454756188cc1335e92c82c63835b837d4d6244c22408c30da5f2858af9886c20817daa100f15cbaa98370a1880acc29d9a57b9a1841eb97c0a5473ea9d31dd8dfa2a8d163749fa226db2085d7bd0ee35e366e01254724d51077225c642b48ede1f839b89919c3653da4b2711ba633a407815a451c2ddad8249f41a78755635403a3af4c48237a730f79ed007084f875a16b36e480c22d7594ad94b110c860ed236114915f0a71f5ab52eec78f53886d6954964229aeb93db8bbdb8d77cd6872e7d21890183a48db4b8313d25e1458e354ba8469cf2579357b5e6ed0a82eb0921bcc8425747b3fd89090eee22023b20086ede1ad0e07e665c1645593ff285b3eb70659db448d793fd56cd52cc8a19c90862d94d7b7c21432d74674c5a7c356c4d54b03e2e211be07a26de4cf0773c052d3b02f97a6fb6da4e002b6091204b8636afd7be726ff342c1a4c126ae6be54904e4332f7a3e34a80dfbebf6665701cab558f93067b1dd653a7a11f2935ca6eaca8e4ac0990c98a60c2c8270cde35cf54797a9983f94f830964d0addadda386be03577d9948bd6d95a7d63a0d16c161aee70b74fc0dd6b21ae7d6578b300b6ce7a97f6c17068db0dda88eb92dea01d5bd8ad7314d774f561ac9abc628d40d31b70fcc38c4da756217389035527fafa3e99600ee7c99481adaab28f1e2987815d08646315851625707f9250d8145435031a486694c85abb009cf863cff97e881c7f628b02f051e49b4ea89e5280c2fd87304515e5495e89633590318043664bd412babdb4ec5486eff84ae3971115f20f2b8de6763a85c873ddf3d38c405467722c341fa3a9fa9edd8d06304ce0ea245f318bfd2d4215f3ce18e350ce28cc3db7b70921c4e33ec12a311cae3f8c8baf360edb9d47242b688b66ec667ebba6a750e495ef04e677f5d8c5bc55acbf1ec47f48e0e9dbbf9eb35ff8e4e6397e19a2a1dc57a68c24fdc6a4a40fec5195ecd431f6a31591e82cb8b268b4234798e055b8361639eef1cc766415d6486f5a9213dd42d68092eebeaced0bc0b82154ce78cbf7626b3027c9bb233473e8769ce269e697b7ce85de93434ab0e00309dd835409554b8a2a5a8145b74e0513b01f7d19ec7573ba0fea14858b84387258ca72d4819bc9b57f8302aa7ac1712b9d0cb7918f3c0ecd4dd752e7dffaa20a990f00807a32e3a3a1c09cb5bd17101f753b0026657b9f05ec879c519b766aecdda8bde285770f5d285f4e8ad82cb932361fbcd3937eb862038796e1c4aa9d243070caacd110beb759a83bc6b7b8b0f639713c2132daf18471638a662f94a3e93aac0a4a71ba9c744d750d7be4eb663650c56e80a1a6080271cae81e46927af419e340a088c2820503592397302e80dd61c1fce888c886880c6d28bdadadfe86d228946dd78338d66f48f3f3b9f7fc991b6ac0089d89b30f5ad9517ece26a4f3d8e8385879d41211bd62394035dcb7336bb96ada44bca76176c52b485a17399a1a69dae17366158c5b81d46cc6deac01437b7497b8b2b18a057ea67743e53e2a4fd55974660507ca6f0a1905ad011bf715d0b1e3561b0a7eca41e5710814732f71b48e18c400d21fa93b0ff69963158068619b2edd3a4f67637b885d9d140249441659f0c308a7f150a6720a0f3abc85f6f62751d87603a3e13d5708689ad584fb080299da7da6cd1177eb024d15b92bf2a80851d6fa6faf334c298dee84e927fbb816f33b5ec2cb93753f793a4ac63cd2a4e58d5c276960add7e3a59ec85911c2757f40e642904a192e2ba9fca8581c4daa2e2df8ef5bcc307438fd6484a3c0823f6630c9ab0f609a36f3de8c13908d00695f113c12d9612fd8edd4c26ded72511d60d9958a19b863461264afcab594a54b24eb6de59ae64ad5ebcfc6e0d5531174beabfa292f98d001b4aefe7664c9e03f9f0ab270d888436558592d1d73cda4ea4d47e4cf485619d377bd458f464f405a8e416287534c868b046f64ba831e5d92eba6502a194145ddaa2d051ef3538c9243a05d585a187033c9d94f3fa2d2da1fdb67e99b2cf56e425ebec831dcd49abf7036258c88fda1ebbd432580771e69fe64470c2f0864776128a1e63c9be1ac2490fb2e37b3919284a2fce388c0d6a9b884c7338d036d08fdf8c7cd44689c38a67e664d2631dec3496e792137edd76b8038d173d5b2e91c9faae2719197d60d4f5bafec375fa7fb969a2ebb4e3165313c2cd3f40c1cddecabf44f0178244baa2657c3942fac38a0fa90eb35fbaad755c91e21765b3d02729b8ab4b58f619220b7466311b69602508ea6aa53a2e3f4ae5dcc7a76ccccbac514af40c3d8952665907e61b51c0a9c6acbf76d2b37e7c7c05c4bce2b70f460b317cffbfbe15e3328dc53013a3fe2707fe39636cf9f75daaf0a987cccc0d247c8ee1e870081a6deafb2d2bffb8f2480845672e05dc923d2c780232d8cdd6e2a95c0450a7286c73247a0cfb7fe4c2dee3da32b940f63c99a371f51337a216ce63e0a6a7dfc7f37a15ac608146749e3999640aab0e81e150fabccd14b26a1266cbeea0b7c01bd0e706b6981bc32ca6ae54023c158c5fa51b115a95958d9d643d88b0388f39af1df55e2dad0edaed1b33db24e60364650594b3f3abb249308ab3a6414b25f336d012ed8fe15af8819adc5063b3eac79e63f7aa508b53837fd2664837a4d31e3b746ad9c86e6fbeda1fa3a82ce0e453b91cec06f8eadacabeb9f1e7fffc68911881dbbf7e2996720f6d17eb8437a7e8201a64ffc9f2b150ba310aede19e206a3e4d958bb3d6c09fdfbbd3abab21262d761a6c95d5086f2f8d8c4d51135d28d96df6573ce887f171ffabf4a72b9eadef3ff15af839b60d51d067ba76464816edcbecacf2f136c9d1b3136574756071771355c530ad139d3857830c131329efb151513d8433c32f9ae3698e65d5d897532fa9ab25297169dd54fbcc2534cda7ccdd135433216ce1453607b361fa26aa21b489a0349feaeabef31e08d38afb4a52850a413d5bf0cd3c2ff1399cec28c537fb565bd6b812f35545039b66070cd7e28f36fa7d5a8439bfb403210258de6c8b07045c1b66b95ed7f503a598191108d9dcdba3089bf6b54fc3396a603c2a8494809da46d558cada91876f846c9e61c7df2288acdc6a4d25279ca84a4b3f7f9f8d867942d87fd8f10815114c12c2382389ed507cd87edf04cb9a0faae56e57b42d6d27f55fc1d271bc3357296d900e5a600949f348abd7bed28b886b933a637d5841aa9d8e7c8508432c8c80ee739c14538c011a487b4935c863c89a18b431b4fa2bfd727a6e8d4307e50d888f3b6d5e6d5920431f215e4279bd123210a2c8a445c1f0912428c18a2dd4430ca78413fa425d34e2ec26d353f8e526edb692e8730f380eb1ce74c2c0f3a429228e7ebcbf48df355efcd37e9458cc1657bdd30735db19044676b7f30fea6158fa11c68945275c2b964592668655f6bf0992e25c7ac55d83c1aff6dccc07ff78ee1fdb8dd6b02f318cad96eb2a0dd9a77f5c08bf24be06ed05b57c51f96855ed8f9a1b32937a0dd23fa9cd23f6e0035398414bef5c0c4282ddbd5fcb7aec0d956f2c4205de5afd9e8c1efbae50c72d542a6ed79c493604eeaef667c301d2e76ad514a65684a4d99c43c9c0711d95744a8f5d11a0f11f4cd675551cdca55fbb4a9b68a904c62bb5c66729390306a3243089a097f8ebfd29f2b7c6dcdff3252a5f540c4faa0fba7bccc56121b502506eb3d621224249dbc2642a88bf836c715bf9f601413c95f2e30cbc18415049f7848fde1ca557719f46cc596495f91f71a4483c76c470729ede72f524f70fdc4a7828feb9a572c77d9e02bebf1ddeab16a183c74faf3688734ff05cb6d3753028de2878c728fca642d84e1dd04192a570d6df6c5ae0718cf77ad82f0d071f49eb4fe7206909e5320d8ca0b6c0ec83bd0d473bc5cb555a3f6200db54a5cc280202a5972552e255678b31d3eeb9e13895b06726c10f36b217677015bd2b05333c5f2dbfd5a60677329ea92ae7aeaae2ae307cee3b377247c6722b1dd692b12dcf32dea678ed9cd14a03e90890cbd255db5900f023cccb23096852f97fcac8a089438cfd14bddc95f965e30d5e84da47ee77d8266d633d72e76e21a5a5592a767daf321b720f7e49b26b3205a958ee49900a1ef148cda890c8730353db45d75ba03f647ae183fe1d13934354bb28175c440a247ba6f9c35e526f3b6995b8164db3351da63bcee9c02c08e22066f4af43b62fe6533b400c96c4a3b62dfe901fca624f65479be2be809289c4624a6eabe524c0c820bf9711012fb2f99afe1bda30f7a888758484c750369ddf24754095101091f221d24f0e6429bf7d2332fa3f2fc992b6b901617b1927304a15871e84856122af7f52f4c3e1bdb1541a72351569719511753bd10d9a2942d071833fbee5f50d926752dec7a2dc424ac6fc402460d0df10283bc057bb7faf85713ef3deb45cc2ad31f4e8b333e0aa02ec1cff6d2baf2f1212d41c29f3c05d79d0159005f29913b5d4c89508088e20239a8e9b5413b7f5ba86af98507235c409086dcaa5bc247c9ca201f62d5df640d6641caa4fab06f11fb9b652105209fed575cf6451f16ad4911c582ff390609137af9ee74e87b056ba173c9103ba8700201ce7d993a2249d08df4b3007819144334e52efa398c5b20ec2ae599a1d024f81c429d6b4859c87d82ead095f193aea7eedf476993e1c1638465c9ef97212f2dda4dadb56c95058ea466670c174a69a1d6113d202fff8d31cc3b0226e081c8b8c1653a9dc96d15394bb9b727ddf0f530144c63e94f16e9bfcd82135244ba8836fa4d46426f1ee6a09852bd9013d969d9ab5d802c523e46b46a5198739ecccbb921be9962c0503970ac939d7bd0edef5f9088e2a835d4a6da5a090058a8db3d161fae3590ee57d6b566a349e5013a6b90733e15ba69adabe1336777ca2b3bb3ba321f09dcb5b83bdc60086e40419a6849b500d129e32d5a655ca195893244ccd664a32bb2e97734bc3846f1f8ca82b4c38cf29e37964a827d5c09774a726f5c49d1ab0e6e332e24b1ab593aae331eecb27e70e2fddfbf9451a59332597705e399cb0985aea0906759d93bce6c7c1080ebe11a708311a68661d05dc049145e4238650bd7a380ff02576dbb96b80b06f95cb905a15f1bee624ac1a96fffe8786af33d1613746d2dd366e36ddbaadf184ce75a24e8188b712a33da9635b98bd8dd46ff2fd7a358975372fb32b50768588481cd85202fdb4ddb76de8871e75eb21fa5cdb615e3300c6068226f8e921a276ccfcd3a63ed69cc0fdc1cc87571e1b8cd88b258b1cae322ca92e4b2c73208ab0b23b9b5b6d7c4480d873746daa462190e997e987ed3192d04d644bc376f483597cf5d6d4d547f2418d8546de3c752ce0357008e46f85df7ff16e16d31f25e159b9e29a35e3915cbfeb0132dd5232e129d2e9a5da1f8719575d07af584eb2eaa872618d4759d6694f291f5c5ac1c10d3b7d57389020b921879f7648bdcd424da99a7e8fc15b8f15bf462484cb846325dcf8686eef4ea13e2e6c2be02770ddc016e338254b510602232b0580e966d819e30c3ce2f2df09858713c0b9e16cb0c95e27c2fa21d0bf5b5e3fce0c4156d36f55d0bce5532dbdea37a4013b4d95938a79bb69fed82c7d8d9f17fd76725744779bb5484d8cea9e9e2761a0f57a5cb1c78079311d6f8bb1abdc54bacbffc4eb8471b96d0b8a6e042d0815dff1cf77cdae33ceb8f10512f70c51390a1e04f1362f6d9bea9705972d1a4f414273b2bc20d912f5aa28a1d7139a8acb859c997f6f70009b6e131bcdd5b54feb3ff5bd9026b9928eaab567063dcdb2b4ca603c091e37a59ba83a3ed758d56a08eab023a583118800e03cd579016423847079d6618d82dcb27f40544140ad77d185828b2c93cfdd5d3a10edba6325f07458e1b40ce1aa2fbb5d1655f916f3961be6b4035ae066bdeff8e85e41c30726c39e6d20e3988aa629913eaf62f68e940a89b2a22cc050175ecd4c71e2030d43fcfb4833f28eac6c9d92ccbcbaf4a04b485b1d293899b9c217ef3fc5a847d49fb877c50faaf378aca8fbe692606ea56db9d53eb2f679600d78e9be10663d80da06622a71269bc1cb525407c178f9c5d75b561c87f6d09734576a21b9772ef6ebc1cb5cd60c7648bf1b5d7b1c6faadb508b1eec8c9efdac68c0ada8f044f3135531cd94a6b480c765e324adefacb991ec818a2514457f4a9efbd7f1a48ad0d6bfc05174cdb25d0a4112750fc3fe469207e81f455e0b06d40c38f63982b8301fd85727a6254a02a49e6ef1538326b9921b59f5d4970e0817c857e2509cac3b5044b8a5ca209463461b1a48e6ecb2d159125a9be0739f52d0ac73d33db97174d6b49b12cac644b320b8004a97d0c286e49275b6e58d1f1c05bd22908f932874e66b0b4db79d2cde84987ba08d73307cc737cb8e94930ece33d10db3c0da72739f53e73d793ac29f6242bed49a6bd42b906c8a0a824d13f2468b1ff1240d35f26ef35e421538fc3947707ff65340989a9f2f0fe61740db8f24cba855982930613730edeb2833c6840f8f479fee185121959413f2722fa77808fdd08380bfd4a3bde3f7e90fda45f27a05ebb0d6c01aa67f6f62b397ff97241f4227da7eb9648e3a037e71d822002578523f1192e788225c804c4b8b340859e44fcfee741909fa89c0cce922615a202498743f7c3ea7360104b42875b10220f661c95258aa361e5061c795341c750a3abcc43dccd099a4f8e14279cc8432e04242265ca587fc10f3c9843d10e72608f34d2cd89f2194f3014ec48b4e3907160a73488bc05681f65311885a9dfff77d18c85ff70b9e9ea6ff8bf1ac9a61cf40186f0fe3b7924187669cb146698572b159afe453e63923f682bc5f94fee3f662d028f25ecde62c9fe4bb3d59cfeb99577fb84dfa641bfa5f619624a8da03929bda4670889e7337bc6806cf0182be1d6c3f0d9ae7c5b102842106d79e1a2a2c00dcf628b66d96f11607b19d5da1f6b95fb972983c45022612e0232d108d6697ee0f17f169ec7c17f07e5d1521f4413f967b42b96fe8ca83a45a94b54c8ccfdab77fec0825f348ccf579377c7d50352b5fb052be38ec8328178bf903b272080e4e00ac55349902443fb0c9e38c7be6378a034af6b22a23cabb4370cb20887f675c21dea3c123fdbb4d141426b5b7cb566b8e6b8bdeb9320a62a2e03dc1874db8388d71bdc85277e9dd220f20ac067d6afe137fd8effc7a31bf2ad3d5ad5c2d2b74df84ebfd9585c1fea13e4857671ca1466d0db62220aed73fe1857daa29980ec522b7fa860ae8c61fde742fa66e989adecd89f7a7e819180c55b260089cbac9eb072605ecb77e556e0c850c88b78c21f4284d0cd47d2a774d863888efe19fe1575d3cfbd6774fbf735b96d2d57654af2022925226e81f78fd2a13eca5efb673c5ab658455c6bed3f6d11796263ca19da1b6d01c57f6cb03f6af99b9be83fd0cfd5f3f347204dbbee04580f1d776421e8d04b8705138c6152101a9156de3631f3e05fd4d3e262f5d460b387a5a9e31a8d3ed9f1b8b4fd805a9efe6413a56664c9d3ac82d94bd3e2b996d3e3ce0173f112d22c7b38753155551773c5546030572f6f6cb6026bf0e662338289ddd6bc50e5b43a98e3999fcba522d6eb09b97f9d12ce40242b5d068fcefa792d8a83c2505c081aeaf122390c0306d1d640e28b53a98c88fbe577df43bb66fc6a7fd1ae3ff61c7a6cedfa808e69b5dc37608afec43102788be13289ff6bc35b745e8b06a6b99aeeb9bc6f35365fea6ed4e2a6aace7e6696a96b0d040d3acfd5be7525fd625e80f344db3957cd5c849e7ed770057de4df5b4ff36761ff78c0f7c0da5d774f6a8447058f8e093a2d198aabfd63ba10cc4476076f96723fb3e202d452dc3efd015d702010d21402c54970b5d55a2058b97af2d655bc57867bf8b9431b98652fbb67aeb639a35c133b2e118bb813ef2a24c1a3d90ddba16dd2f08a4fb519cd91d3013b53e8aabdc2ace5e900da2b604d50986de56e88c64eb6824ecd14cb3662b1193f27ef93860790151565e5425bda90089402d6aaac70692966aae80f77e71ba22395c70ce2ab5783eb87ec5b320834d57c71adaa2079176ade8bc27567e6447c3ba558d72b14f806dfc88981aac1c81b41aad9eba71c1e27106038fe4e13041e1133f82586cfe589af2358ad13421008af3e6f856e84d84d6d912059ae3c3c707114b1262ccc9d7afe6b3e088bca4d65647f5d566e62f0a7a08c38a357c2fe4eecd4822226f8daf157e97c9c223dde3e7850b37bf25497791213986669226df6ddb599bba9381645f8cc49ba2f8599de79e112b709829355e680572a7f4ae4e580eacecdc4a1b5eda6523247fb764a65eed1d2c976bdf79ad63953ef5c4cfc8960c18b74fd485f6a166a4d58362feaeabf753e83d33e4d9374cfac54967a15f3a98dacd2481c747500d6c6cb7b9b9a1090589a10aca54bf6376455d3c15cb933c28b0f12f78ee4814620689f80e078f369e444a9a662bc18d41069de2a1687caf133860a47aec10585af4179e7229287d044d4219236e4c2089a2a483f13022bc3c7230c700526f97859dcd60df1c786a8708a18686df824abcef17a827de670a459d4a964a9a5cdf3b09cad0b9072aa42af77fc7685e03edb9e89ff33bbf06d94b0c2336822a38bd910998844102c11cae683f832b48f0cfcd30f55e07095f140251904eb7ca0fc18d0e60771c1ef94f375003109f373a2eee6da84a736e7e01f38bd26d2a3a18c6a355dc2a8b2ec556643753587bf6345ab1c4d0f222161f3b5bc4fe890bf69ffb52ae17a92620ba9ce9e427b6f139717da5f7f1e4b28b114d9c197b6368fc11485d57efddc76a364b54106dd388f6b40d62c5cee289355a1e4d7c4d5427cbfd4ae8fa8ee06c357db5916cab962a3600dd77789c2839358154acb20d219d6dfca3d1428116044cdc29a8d570192472e948db87fe424da1e0631dda758b3339732fdfb335fcb0c613f3c436726ccf99bce9d2bc8bc6f9987411beebe4cc58d29c37ed2e5b18f638d9666fe5a63ff2c6556e11bbffcb322ee4f2152d24eef8f97a3cbf3824011d6f6f70bac718f9bff6e1bf16ae0d4fbf555517dec383beda7f8718b22867a17390e8ea02d8f9e56411d615557c33d1a52b8a4f14c933eb025112608803270921e56bdf5d5f15591113814daf10d65f9e61e739d338009042b6ebd517ce7a0529ed5260deb8db39618d796776eb186e703ac98c1d02258f985c107b1469b53b5b7931b70c361a3783ad5e9aca8f2a050be6c4d12196d7ea94c42038173ef4ad3ca61992f72830aaf18a1e1566910d3224a37340dda944331cab6fd0d529d184d66ebae41ffd8e8adf9cacbde1cdf4252a49e9ba3fed54ea70ec6214de06ef6c29ae51a6272f3057c78889a05c15631c6f547dedeb75785cd97aa011a385f3214177170ff57428702219d399223bb616ae86f21e196b8ce5aef0a153ec06c554eb82e9fac7e14ed5882bcca36c6fa315c63a40eafb44d8ed214a9e98706ba72650f24df8cc5f664cf0ef70c2b657d91fd46357e3c0f501aeba3f9bf18c016ef60b46c6d7e2ebfb13cdacc2db3d730dbc50eea2cd0ceb0a9daf8862f36d764293da5704057dc888bb9ce102a7ba85e7a827ad762f6a627c8153595e2c1472d46936454d87d4d33cd15f37e4268fc855a940da8dea9e2e060546b5cae25646de0952aea67479da85f77aba1c06b1d5aa79846d4dce3a80b9de95c170e309a7f69040bcf8a2590e383610acbd132459779862d0873a9087a327cd847daa60f27c82ed3b03a3c225760badfa630dcf4ece43cb5242ec3aabb8c9ff7a5bf2fe359bdb58b5317272f6c6121a52e4bb7f90b7c00e270a2de9c8c4338833bd58eb62b5a6e8c724385a18cfcd1dbc28a4f86cdba18798fd708f36b79a9e3766b35b030fcde4b84fa0f0b83e4d2a28460289fa2115c2547db3652ae0dfde90822d202112c6c00218959916e60e5bec90508aef11fb8edbf6712ca1f56996bb9ef533b1341ccf399d2e8ed669a10703d1082a9cfd22311a2080754cd4fee44fdf5bb86dba37a3980ce5b0ab75db2876f5eb060cb6d262d33998190d7dd494d38d5457299606d65231bec064c9303cad752925b30903a4e072dba2dd1c8143fdfb2cda47885c2ef475ff23e0bf105bc262687d568365ec12fe42f59be751dc2524fcd0feee3fb73cb5d9f85013bf37c03c5093883cb17afc39ac5ffd9078f81e5ccba0909697befbde5de32a52465e9081e09e4083f374dd3b45a674f05f00af329fdaeb79f41381f761326b86d13e468ab7ebdf55d4aab86b36852911754c2ce241c5dd8241a285d993483305dae4c9a81923b8ba4f00ef73f5d0522328c9c507cd309e9eae7cf04d39da12909cb3f4a32291004283015183497ec702507980b5b9826b02a2ce56826195161b159d3a87f822b165b40a6d3cbaf63358fd6f3a3794ebfa4b258d61a2de12f01d90b12605d0f57d03e133b7ffa2a1ab682a03ef543ecab4224aab79f52bd7d24a947d1501a615dcabad9775ead055bfef6250c05b63c6c05f11ef543beb72112fbdfa3c2ef91a0de7b09939f01b6f7d06a9a36414d02ac9b85a30ad708ab881672cdaaa136eb6fde09fcd1aefe5a348d8aa651510f0bcdc362dd6e5e120196ece1d3886524753847063baeeeca2e6dacf2420ca43347ffea6f14efb6d50a74b58d13a76a037d5a9bd7bb6a92cd639d755dfbd5ea554f64158a777b554844b68b0bc7bf5b38025ded53a16cd72b49d1cb4dec44b4c0a89fc5fa9c9e122a17960fad7a554a2935d943ca9b672db50f2ac9ed88d9cf85a99405078480a53ea881880273a10613b0545825fb9175030756f52b209eaea941d97c10ea6bc2564d02fbae55315338d6f0146ea1d64b35dfcdac55df7e12980a543dea85a81ef5b5864256ab0f42bdea93c0aab366bf26142df812278d47bd0d59ed12516195ca02a7a05e5e21a830f5346fdfe6ab08a979d4a3506f5f08eaad10d4db84413e614d68847a9b7ad40f493d8ae6edd364a0bc13041d34f2ba5df73456ec582fea0b8b492c369779cbacde876e8fbee4f644bd2ad63ca89063ed1a6a9e55c8432625aceaed07d97ccdab542ad5ab4217544f2344b27a1a6fc320fba8b75c5814c842bbfa576252547aa85dad85b17bc4a22aaca2030a9b7ad6cff8519261cd08e792763d4182c4260caa2264c6dba71122b1d686311bba80645a61fd8c70092b64220640ff8c22206684765a79827a541854659c827ad4a3421790cca59ff1369c38b8d8f94433c22afc354a40d484d3c7934906bc352fbf06d89a3056c5f4554cffe3fd8e98fd46d69513d6d5ef67a394fe09f2d24f721d1cbfc8e5a7a08f1e4e9de432a8813e6d0279cc171f58811c213bf2518fe925ee215015530db1e8812ee4bdd4ae7e15d864dad59f1a733d5857af8a0b3df662f4d0518771feedfd47f7b19b09fcdb6ffe2a819d5f6e370f8f611a7ac8e1c8646e8bcde3432cee25298ef54a197228e7c63bab2ee3314f7fc13da6bfc9f0e0919373e58d77c7bf632f792d1406982630094494d31d9fc6ed68f3e0f418de11c363bc6303efc82d2ec0725b15f31daae8a52d636470c72e33ba900ff9122762d51855ac5f25c43b6e823959fb4c68302ccecf00b28abbf109dacbb06580faf44fa817d8be821b1f85e19d2decef32b0bfacd002dfca2b84145c817f05ede5a5e0c89f85d93bbf668124976ba83d83a31bc0339e32f4b01498e649856ea57ba8bff04e26c5adc0bc1598776cb097a44e7b112c36ab84586cd5902ac6620e2155ec76ea53616b40bafa8358eaa19928fdf490d4691c67a6a45a0c8b8d02d95ab93da697f8073bf2d19201f83d4c52c4f597973f20fc1e3216167ba8879aa7977ac97ba98f545d928f6fc850c30a9a79777777777777e6b4bb9b524ae937edeefa2d5aeb8469da4f9816da76bdf6b57bc0577777d3eea6ddddfd51a712a79b7412a7061576be9c430dc69650e19dc9d30a75167867944997df08bbbbff903dfcd971b02d20d9ae24302993b46ff94f58386159f6139685b65d9fbdd6f3e2312a34cf1c922efe5af947f3d4da1ecea14c876e8afca82d1694cf969f82dfaef90ece2ad3def9414e44fcfcf7fab0123843eacc9752aec04a983be79c72ced93c23e7666661d557c833640ff964280aca2c5db9a58cd2d1955bcad8703532b75f7e95a2c7b0a19bfa2c937a277e76abbab038a6d899d43281af943d2890499d7e3006cb4a9cc30895f2e1a9f3ad639601393664c729d469b3c6b9e8aa542a950f53c0833367cc5caa74c72456420948a5cbe10a357f7af99950c35fe99c737a8e143bca2d63207165a625960322ea19a572af1881996078a725bd0825a860b97d74a7d74985775a7665b98d7952b96206c94c120c94dc4e4ec0ca2d6348b972cb0dbeb0e0ca2d65c8a0eca7bacdabf909d6bc4af53a606bfe8e4f02d301b6e6e77c125847c46233941617c1620bd1f139ef60101d9ff394b118f1152fc357988a9520ec388784a8dcbef96e7dd7f8b6c90183aa702844e7778441afd7f9a0105ec77735c016108fdd1a1d74f20352e33ff8aecbf11d38af8d0f0ed816fa8e1648726fe0781c8ff3e24bde713d082bd0cf9e82dccf1aef6688aebfcbcc10521965ee38633058bafd930c21ef997bfeec4b40f6b4b5519fdee2c2d696130e19211421f4f7c071fb9b2f808d0c01f3da781ff6707e071cd0f5cfbe03cc674aa9b7b6cfc2b1d5a24f64c7e73c91115e84ec391c5bdb8ecff9213bc29c70c808210b975f8490859bbdbc4097dfc7edffc7bc369e0b7d44b1344c808df770051bcf852bb8de8dbc2e0d8dbcae8d50b288e367381a795dd7df3c08e0e857fcfe0c5003882b74167184efc17b38e2849245f19d45f100376e7cf737c0d185db31380f30ba3816b9b49befcf37c21149e67520770798ef210d470fbe85aef1a3b3c839c21cefc1f3cd91231ce7edc2b1f300e4e7ee3d78feb07bfafd707742f8a62d76448db9fd2d03f8cf1084cfc216901a3fbfc6cf70e42ece239d917273ae443253e6ae80f31f7cc71f10eed6f80fde8725ce7ff001d839c835fe03a432c6dc0f1e07688a36decb91f38de386cbbb3173841b0e5728de0847d68b0cc24f7034f2ba1ffc3f7503d4f80ffe8370c47977902711227c7340117e0738c24fb0bf56909c17e187e4bc08e1901d3f4228db41be205ff9b58288f0393f44841084cf0941f82120fc8e100420385fe37d181c6768e47571c20ffee67dbab317bcf90747a07bf3f4fbf120fb7e3a78dd0bcc5b0388bf706b8453e9069c4993cbfcc2624f2a34425638c390110b6719950bec38a9cc89e3073bcea157d83f572f5734341c59a16c97874343d5b25834cd49cd49493f1cfae800254c67fcbbea57552b37d5281bce32edeabf39b2232719a95f4df2cee953e89b734e21b8b093b9b0122781c0e62cd9f9322895dcfe2bf86a57bbdcbe9a271c7b5e2cba0a9542995e5287fff56229f15f8d5e055a26ccebe3b7824c584fbb50b76ba794d24cf32618b6c0b5dbbc0956c06f0bf4765de7d1ebd7e3eb7dde044d9e111c6f9efa9eacb516e5a1be96b429af6542df2975bae9fd1870e6c92190bf3a14dbd5a9522815b7a95455cb5454e59dcacc4c77f7e9ee2ea59452b2bc7bce39a594337420b168a62389adf783f7b028df260acb1f143bdf260a3baf4d1456def95d5397d29daeba339596ea764f800c57b0a1d4a8cdba7394521a9ebcdbf3e4475dfe013a93f77dde35cdce9db3a1b439aaa6a43655a3bbbbd378f293b2060f763e6804e747be0d254ae3bd0d2577772977e48feeee3fbb199ebbbb1cdddd5daa9eb0518583a37825d778a2f3b1a97ba06471669a6f3c659b562cca2ff3c56d81afb32897ae77d8d37db92df0adb582b0712074dcddb4cc9b9ff77d3ff21d1c3fcfc1913a3866d73d29fd64bdc92995277967e5752c2f051c9a2b47b0a3d9cdda636a04e7f677acefa7bfbb47fff636a2e1519b7ac383d16d81af8d2ff2b9868d694c72d9132346a3bfcea3d120eb7a6057e4bf53dd9c661ad7993ccb49392ff73ecc6dbf6df57db8f6a66559c66559d69e83f3527713c83070c2eca94d1dc8b009f33ee93dbbaebb8b8da3e9eebaf6e2a95a5edc393f599b49d1838e707fd7759fc0bddbbb3ba9bb938ebaaebb8bee39fb04ddb26777775d7be9eebaf6e275475ee7e566872959b6cdf529454aa5531af2043ac8badfa9f3be6e54fefb344f8a6f7f403a8c173bbc302f95b3a5b78976f34b80e4e27a61f71b37a5e84f33907dc771a1dcbe1fbef36af4d2acbb8633495b9061dd099cb01438a5cb1f05faa3267033d4cdbe73d6a1defd810ceba6f78113660299bbf45312b86da7e4364998e4bad56c1c0db752a148d7792acf93b2478fd4ed3f7284c5569706a71429f701a1b7bffb50a69327650f7be53bebca23ed02412952101c708437b6371b410880b7ed49c94ad9e3f3ee9462545d0a44a4ecc1090162110a3b693c297b6cb54c37c393b28726cf5c3e22332079bee77016b58b77e68f3386cb2f8b5a6368d05b650f0accdbffa34314a48eaa4b9227aff3ce94227d39bb6b75cfeb75e3f195cdf3fd3785d52e1b5da6e915db865073125dfe113c7244a5c57e536c74b11d7852f6b069d160d9988c3aa67185e6831454b42f0de6035b16123c309b608d593bbacccc9799f9c60bdb572229e1c46519312f71997164f0917559092c1d5cb9e505646ebd12490924a8bc7ff559c44a120677cef98f93f3621e368ac5623bc0e6f7e470279114e89ccfc21577be146368eea0bd9c544660651651b73997a2dc39c5cc32770a752f9928cabd2343b993af60995f036ce43adf4826c932312b57e6985974e733953bbfeffb8cbecfc7f77d25c872bff7ef6b0cf7bbf2c4fdbeff2b55dcef4526f7fb571253dcef7b72b89f09bedc4f8926f77beffbf9fe4bd7751d0962b723c197db8d20cbed9efb7ebaf7d8b6badbcddddeb70d092a7743c28bbb8db9dbd7ef67fbd6adaf7d3f551341d1d53efb7eb49b9b397d69834bdfbf1f9a5dcfe2440ef0fab82d8f067047c965c71de5973e6a125a92314ea19d3b4e1b9ee809e5361129b8dd5fc7b85d0412b78bb0c1ed17ab94e0f6bfaa6871fb7b7c62b8fd3f8cc072fb818c18e3f613010111b74100c6ed67e1c810312b600c89e02285e005b7918e30e2f673d197eb4af79ba718b06c7da2ebd5b2a676e5338f6c30464398e4082860fe72196988125c26e286cb2f3fb0c5e517e1fb61560d1ec042cc1435a8220218bae0418c90098c30223a02c62ca408fb139793b8fc253033f38eef877dbca18205a63bcaa30e585181076af0c00e1e90c19428a840a18203a40f5871fd5fdf8f2b91852684550f295fa4f870f9757c3fcc8ae910e2072f427c71fd75ac4e19637c70fd73be1faf3a7a88122547d5e1c34d1023a85166b8fe38ac545222c1087e90d20412103b3884a0870e5441c31208607e7485737d3fee2284c05cf4e57210335c7e59b481cb2f7e3ffc310042053baeff8defc7ab95609094a86c7c3f6d4978e2f2572080e0800a2e3f08566a89423577703c00775c0d800341fcb0c5e5ff8045e444943ac3efa727bf3cc1e507bf1fae642041e172fdbdfe40c3f57fab63c4fc2760aefb5728315c7f0fbe1fb757eeb8f2e104599e2cb9fe1d7c3fee04c7871aae7f0d110a0a78ee782380d1c791e422bf3821e33a0f517828430402221b5cff574f0f22b8fe3e3f806ebe1fd7f164cc696243074d86b8feac7702c3f5179d1471fd5bdf8fbf7492b8d1a188ebee3a94b9feac1d94aebfcdf7e3af449214600cd1a0c5031dd0220a143cb1c20a182c60d2b5784d193b61f3c7d50d931aece440c4e567e9f0c2e5a791450b4ef660cdd5cd8c25645c7e16132bb8f8612d45354b7af8e10ebc602bb1584c871af79beb38d771ee98739dc7751f2f47c94586f94292a1e38e53689c36cc1d86b25c7ff7af1a00e2fa5b96064670fd3f86eb2f9ee07a0d33b8fe3d1b90e2fafbd830e5faffb80186eb0f44e4862cd7bf880fd79194d4e0fab3706409120e5ecc25abefc7894868020429d9433579482e434a68c872f953ac0e5e304318a8efc75960cc70e5bafd7e9cd5c494c105a7efc7e519289e7c7fc7558fcbfc1649861b2effc752228c947704c5e5ef9ae8c209bd70f937678289adb2daa41892b8fc9a0e0b78dc276ef51864b8fe19cbfb47f30ca1440a3eb1796cdb50b2a3f5c13b634f0f8fc3a6cb1c775c857199915e40bafc16061f2ebfb3a02083a6959062415c7eaed3d62e5140b9fe25f08ee9faff10e2465877b9236fdfb87c668ccbd3e74a4ba749a55e1522099120517d8aa268683e152241927ad54bd8fc7e5af487a45ef543562d1a06517dea87a8c2d4109af0434b432c8b1035c1748b489dfe1c494ed89e2d567e045428c2a2fc4903a43ad245ba53a954f86a57d38040768ced5f1af3f25fb4ac1c6258f9fdf3053248466430992d2fb8c2db92c5109213423bc8ec7994b5d62c913128ca10737bfa0cd704451939e8a1b9a466f45b223571e6d2dc3601a5f44fe04bfb0332c2e5f17bc81ea7cf9e650ffb59f62e7ba0defb917eafddec339405f964fabc0e943d585287fe58df5f05d61468427d8d82b366405ed61b43a5408e567e67b9b048507648f6e8715958923d2a922a4250ff3d12fbde8fd628887def8758d61054d8d3ae7e95fd940dabf073924d50d8153ecb0292e7dbc5924533d955f5deb466c69c41c392ffdfe363998d7c686a56aa148ac6e4237b48ca3a37e8a4949de4b6c249333040cc3c58eb69177777e59fd41f03544aa72f0f7dd832386f7367833a35d93567edee927e0d1e9c7653a636aaa093f6d8a8424a71c3a2856ecf2538d26efa9995524a5aa93b0f072f15e55833c7fe91bebb3b0547a6e018d2e6dadd7fccdcddbda98d2f35936d7778dbddfbc86855ab5acda877a95a46dd8956b59a51ef52b58cba9339994061fa7eea9b4e9956bf6a1975275acfd6967e82611d7179de194aa9e3aeb513ad6a35a3dea56a197527d433ad52cfba38a59e39a91a75275ad56a972e5573a255ad66d4bb542da3eee407e776aa711cd76d454444d5f3beaa64650ec5666c93728e9963a41792877be6c2698506973d0dd8a0232c265993c974ca64b76d9bd2e9fba97ffa4ea03deaf4e64efda5c9036636d8baf366b352ceadb52857b2a2c252112b6dbf1ffa564b35100fae3eeee492c38a959c974b9230b9cc10587b2b49403f68a6c445e939cd4a120b5d1a8e938ca4542aa5e29ee6f95e1a3dd8f3527d3ffeaaef04bebdf22a77ea8e7ff72fa95df956f24ca5764912a695190227bdd839c9b0c85fc1f9058b2c06bb7892305f2043e067a1cbaf4d32bc903afc745a3181de0ee718a9c35fa3899ddfaddc7d49651a5f9ceb408f5dfe2c1e40d775610b28ebdc97644bddfb30e7daf7f80065148ce77723b6eab1ab9fc503e0be37e9dacb7e159ad6dadddd739bb32d775dd823823e20485f3063937d49ad561a59a2269adc79a79726d5cb52a714823a05136e2a2571bb77de9160b678f1a24ad7e2e507119cc7794700977ec5e2044188701d0c0a3e903ea46082cb0e5cbeb8fd6296dbffeac2451432b86cbbb9e5c01ae97ce1125effda82105cbffe5afd401443d7fdb31a050a263aa068e2bad529ea582c1623824deecb9933b4cb2738f9d5f03ba54c2426162d5fb21c5d71fd7b7c7e3cd1c5f52327d75f05168aae1f55b9be8588eb4f6471fd092daeff242ada924405ca7589847483eb48494e5c7f5f028cb559b4e470f979069fb571f9e5175e0d3c42333c2cfba187d5973f250917a877fe055877be277970d8e5edf2f7704af65dabc09439b6b4245beaee1ea08ccae045a19048f8b96f900b91f4532295d36255897b1fce946259c6695cdb7a21543f7ba1edb5e74020229a935162a662143173ff3c00db75f63770fb8e3d065bfc9b3ff743fab7900b915411b27d3f12eefdc5281386397fbe207bd0dfde04470c51430e377b397db899d8aeec297843ea64bf655bd8023a795e0d2c7628e3c21650c771df620e6c71d80ac271db7b5bb83d12d9262e2cf7db7ff4bb49279ba6989ebf2113660a8392c0503fbd5ab4bd0f7733164bb2b548cc4ca6b0670381daa5820f917665cf812cb42bfb0f3c755b5816ca5eb4e166bc85ad20dbfbb7ea77ddf777614b7b5316b66a28647bff2df47efb21dd9b4224dc77bf71614bfb8f7bd30fd9fe0b917cbfbd29445245c8f7db233179d96bd99bb2f7b64cc26033e6d3c3222d6ae6b89881f59f53548dba70a5d1735cd7be827fd6ce711ce75f5fca706c8176fe59f69d7716a47b9f962dfaf5d2e6160de5ada0b4ef58486bfddd699ce5dfa1502105fb6660cb04d467cf2dfbfd345f03b682f4d37ccb8643fa695a43bee6190552609e51c0ea6784b25d353493257564eaa53da1b2a22ef31fbd28b6459fafbcf597740f4a58c7203b6cbbeef5b910097ffd8dbf3e927ead6a1ab76ddacf2f08c3b4df381f967569c992f802e2ba06c9d8512e1589802fcd0f4848687bed85b8afdf01759f8112463950857695019f5856689760fd3503e3651115b4fa30eee64f07aa7f648b2d2df976b1dae5ffea1f600f10cbc6c08e722902459662931d07ed3baf830d58be41b2ef1f42bf3258dba5699aa64932b34ac78024307f322e51f630ddf92632b2474fdd6103107a4edcf9d60576e37e7e4fff7822cdd3fd64895d583497c2881a8f593a89413a2d49296552f3582b75e6fb708e242b5b40dcb7866c6f93e38495608bdd62f34831645e3e7e0839c93077ced92c4f49bc337a272ebce35bee7c66e6ef7db8c57675f6f4e50724545f134a12f397df0224ccdf874f5c64d3e912e6609298d8ae79523a25b188238b953f9e926ef3264627715a40f4bb36083eb19379bed0491cfe1fdccb17c2bdfc7e19065569b971616b4b02ab1c3333739725c0dc0e8d96b88c76c7eaa36acfb8328f259848c1cdc0d8d695484c60f9818928da0b2cea4a242698183121745950c61dd384abb67a7603643a8ccdb4d0c26e57645ea6a85d6c2645455a620925d4e707332192626d84e062603f275a1138743dd87a25d21234d025ac7625d212b1323e25fc4041496933aab6b28c5e5ac6a9eaaa7ab655edaa7a2c82b10116189b33592c99418017a8d03841cd1117963db304139a1c2ce560cc0c7ba6ca92d50c546ace48d180ca4c12cd192729180eaeacce281942c55466ca38b1305c4999d9a2c909658512d3186b464b0e9f9593990ff8e01140a88cc90c0f39743080f9aa990dd8c0c5883c33376c630c7533a83158e1b458a2955161656cac29986449558b127a26a695c0063f53940dd1b031c0d0fafae1866a1966664c6d32345f3d4c0019886add5ecc5bca18baccfcbf85b512208658bbe4ad72a2f83d49d3b88c7abf5e3c7a7cd02b91b01455237106a7da017db92c76f5aeb8d9a609fbdad7d108ceed095f3c546053543427d6e6ca2d2e50d229d9eeca2d2e88216b815591d9c2b0fe8536c6725a6844d82c4c56c69a4e5045606992a858ecaa035c0aba201aa20b1a6a18f61b838362bf187431581a30f48a651955315655656bc29a8018c36e4e382a2c65c2010d6444b65eb9858b17b2261645a69ab1d9955bc4c0e08eb54eb1dc955bc42cd5c0bad1095888da256fb68138ecf22a8bfd4a2425a2a8f588eeeeb6ddf3c4d2344a29a56cb1db3f1c7777af9b764f2fdc66adac4de332f76e94524ae9757777378bed99f8d4deddedee3edddd7ab359af7df61e7606fa777b4b546b06ddb4777a384114ea4eee93bb89d24cdc50345ce5c54e9a699ecc64cdc2b187ba56bd4df670dc44b9ee8e005cf9a0e479fdcbe6bada799ad376dade97d1d7c96fbce912063b9f693b6db72846491edb2efe2ab2ad5fc354d2354a32659af9c77e0fbb93d47982f2b365263529dd59d75d3eab524a69d5a4952ef9eebe4329a5549b9488c9ed34d3eac675de673a59544ae5ad56df0f952fe5cbb72bad48045430c2420b4782666cf592e665cdcb192f5b2f7fca1a2f3b78e9c1cb7f09be94345efebce27af9d3887770bcfc79c43b395ee6bcfcc98577745eea7819c2cb1b2f5f2fff070a40bcc37a2982f022bcfcf12f8f117600f0025f8ae2df006fbe480820eb26023ac0154b051dd01ac9013d167280b5051ce20df1884bbc21de00e1e7db001d049c507e007a2cb24d589fe021451b9b1fe04b8a3c5008c19c1710088a394276409674d93c00409188fd7025451b1b15aed3f020b452b431d201e8b15003ac346c5ab8b17949c3e6480b9452b4a1e1d786463806b154df4f871d68612320453ae652a21ab0484a0c141a300529d2477d407c09242245fa368c141ee00fe9a23f02a804c4c1501101ec912efa3b40295da60fc81515c8e3fb80d89e97c703051498d3bd802c287239426ee36c221113f8db07de48917eedd76e22d081ab8ca5c2eda72b231be879d7f65ab8f548364360540d3a89c352ae2c9a4bccb55acb62fd8be2f8eab9de4fa32ea9fb71163517a954ac95715eb9754ce5984b67e92c9d594a98db3f4d2f640a4724647ce138c540b9ed85e39412660ab940861403451e5d8a85a670fba74869775814e55457ab9bc93c5ebb34a09b855c476bed6ac655b0ebe96171fadce64f12b2f0d27f51b067084b7f7c9dc0a3e7fb09a79c5e2a40c24c216b489f39033b852cf0a062bff7fef4f6ab0841bde94d6150955610d39f5e88897e902914627a1b0699425468fad1c224ecf4bd698857fbcc99ebd33c1e8eacad9f33bd7da1d3a366e5efa77e57ebbc403ac08186a3eb1f7680030d5aae7fd76559969d42efebf749603e5d5f1e9804f681a6ff5e88e9bfe7fe3bbd1706a1b8201bca369daa17b6b820d9402d2e6c05f9de7b21df7b4155b85088f7a630c8fba0fadf2781f9b4b3c830fe1e58069b5f029ce34e4bd5dceb806e7d0e1cedf47e03dfc8eb6a5e28790c694fdf5f5cf6465e7433fab81f7b7e645da0cbfdfceafdf438fa9502413ebc69f75ec10fb82eccf00bdb67ce7018cea11adef963367ff407dc2d09163193df7f76ccb3636fa670b3a0065be05bc1cc636099e538dbcf378233bdbbd514ee96e4ca9dbf65147097610a09b295862d054858125812d88d2eac2082491885d1506cd774ef691e6a3467232d95b9537e716766c5873bcaa322a416b460e82e8d6928ba73c6b0a378272cd64f3a493f4884620323180d5bf3fb0b1332b02009c60e3a2c81b9e03581d1974137586034acc22fdf853907f064cb174b482859db65c9498d2155710377c5aeae445a82618c2cc86459ace94aa42cb488624f572265510516b6bb12298b249f127ea0a0a4c5ea062759c690f9410b983143445accb0c50a25455330d942e5e868a904373c61f4aa82081b8eae54f164c9134b55dca0e4a80c156670d052860a316a4032a202063520c5a858aa618b11156086908aa8501aca52440513391c11bd78f4f8e820879a99d1a2868e072d62340596b3c10602ab819115613f2d341258d4149b17cb21716424518fac76845683942b2dd041062d9081e660cb5219472c85a165494c16463e25fc40414c9628ba6e73ffc9ddcdccccccddddccccccccedee1a8b99997a6566e6aedcddcccccc939999697898dcbeb1d3ac669ca639ed6ed6d3eefecc471aedc8bad18d73ae6bcb7a1f16bde33ceea6ded43dee9bddd49bfac799a4b78f121813d771261fa93367f040439d27cd28cf4ccb786a4126cc65d89342960199338745f97ebb93d3c780d39f6e659f4623f2a8c5435247febc347726b1d095610557f6c4d39a4c3ca589d2300803300f2bd2c924650d1e3e666f25a5ec971d2661bbbba39452ca9ae3b4f28c56932ea5a4610e09ec7c6943897677f728c3f4f0d497527677b79653b38d76dba842c9f6b7c44e1b4a9ec7392598ddf2546b18840198890658a4bf117974250db3eed6b8865b53ca227712dd5833bb698fe1a555865addb8ce0b47161198dbe194ec7d9866ba3f75cfc111bcfe5dd6e32948db5d7bedeedf3481a77ea734a7736ae38beda72c164fdf8f6ceb757f2c4a9d18ecfc946ab5a2a9a95247fec93426b92d212798f6dc1de79da28541188065a16da2890f4d7c68d24427d624a9939a2479497a2f491f48aab09a2727e79d6e725a1d31b96b9c8baedf2ea3f1eab6a2dbb671aaac79523079d35df95bf3f0c15772329d1eb249a43da99d8722f2bcef277bef4b8177bc04e6a95cbe68efe4f28f245cf93ed827009284b9438fa615d1b69048ce998cf98f34cf94b2c32461f62043e047a24c114fa40eff0ef563818c85c921f30c6c0be591db4280d4dba6e631c1240a2cf26fdf0f1639c97e2f51144b60d1c78355def11a588782c9e736c661f19b8783c9ef541bacc81281b1343a506cfff7d3451d4d11d15f71124d22a953c349f3d4c04e262975a66a0b5b9d65afb8e2a900071f617c10238c0c4c58dca0ca42878f938c3cb8a38745d1fd2a1662ac7aeee8ddae638115b723c38621428c7b575b5ded8aab7d15e36a2be8a282272c2f8474082306cbac14571c9960053e58005c11039d8115568c613b1f5eb437189af209199c7851831b50312207499a1c49a1c2490e464aacc0d899c59c74d9893397e5182358cd233a4b7418e3e8beb9fdde5fc1e070fb2d0b4c1229c072fb8558bd508074190535b8fcac67518b67c5133056d0e028e775c7d5172192be78516d66830ae5ca268223b62f4370526c26a56b42c5136d888a26433728a142063a86ddc8e898d8cc063dd88c8c0ed9076c1d534760b5166c536ccacb46c3139c98253224cb5d893485084c4004f7812984a85fa68092651bf5669f127ea030e38adfc27bf584a1641bd37161432db2c2a10007ed4abba4141b285a42820702087165ca0d0490429443ac091874086228064da2944162220b25415c79f1e8f131e38a4f755175426c9183a22d68c085b1f6ca2d5b6c41a5b0a72bb76cf1a504d6bb72cb1649516c3182ed882da66c506ccd955bb660a23db1ab2bb7685146ed99e2c9e519573c15d32511094955d7ad54cc9c4231db6e53777f5ec731f3c662e6aa3187dd3fda25954277cf989929337b873deececccccccc5c2b8bc5ccccccbc52a56870e0a09bdcab76aaa2592ad3509aadb47d361a9bb4d17026a73e4a5782e1baaff33ceaed7ddd67e2a8b7e9b49d6cb5280d95ca7e7c8f51843be2b89ccd951ff20e2c76569b5251d5caa9f78aa669a4924cea09a1bca8344c19ca8a54324422000000001316002020100e8844429128c9635dcdde1400116c94386c56301b4ab328495114838c31c60002002106100380310c1551078a10948e0f99444829cd742afad15fe80b2aa10f01ce4454299dbbdbe806469d6f0b0a81752d89c8dfde2dec4c564189e3c72a048dc0a5a89e4982b0608677d9a18178cd136965fafd769a82efbc0f6077e7a5d1420b656b596d5c84a7e490da23569e0a44e87ef47bce6fe1ebe3e8f44399a4cc9c165ef184acafeeeb1593af250d6a9191f580f4b2fd4ff72d8777b091e0cd1bc4f8656884512c3e2e587419b1e6fc2ed81b2a4feec1d83b490f7aa19bacd9d92c871b7727f53c1e9da3a300f7247574b4c5e21ee2bc6c4d13dd64bd914dac7b890e8c1e990a06b72ee42809780b820296f81c4d41b24a1767b58512c11fb1414322829a3c7caecd1ba07fda2acf6ad964c081ee7449b1f6797cdf9dc62adc73c3a17648ce2d47f238c28964ca0c0dca484999a911bab8135ed93de83d640edd51ec21f2fd81eab0116d5e7394500323daa4fabfefd11bf521a50c87ea3ef28343c12e58e026e7b1c9b5d314203aeb30ab47fd238c5f9efdd73e124f2db56a6bc11a96aa755b2a47245daa9828a19f59d3d6b1a18aa9dbb56608fdce5d4fdaea8eb71b0085f43c5f6931473f8d4b16498a43158be508cbb38161cbe7ad58f0f2403f9dd32c100e9e554d4f55da2ae052785e1b940d95f4b8a8db75e7c3721ad39fbffc6a986c07ac8790f726e817535221e7a19c6722b047fc91ea7328b11e32b936234e0f728e4be1634edc4aff75bb93df6ca4801a7e59db88624ff0053460e7ac53eeb7a239e04946d92f17f02787fee04d596ec642bff49193d8b3ecca8e2b586d3f61fef712db3cd5bc6fbc521f7c9d15843fe5a585faee97ac9e5c02d6a55317e2954706e1c7b5b6413de499cc8ca665786e5e48212f315fc824e5e0bd1ca9e7f1cc6caf84473873c7610b4b8d9cec45198ed011e05f5a13392ef3615b699de33ba7dffdbf8e236705b67022ad77be12ac27c608d21e80d09e41bba957d4bb39965038c202495a7124d42ce8bac451a74258a0327b13c9462470bd0bf75f7863260f396350a03d3e800993cc33f8952803df9660d87aabce274a6ac3034da1e05ddd366ab0fdb7111aee013df75ca43777f764678653ea342934f979339615d7bb5b3c4946627aaffbb5e64ea75abbf6f47460474d52fbe3f45af3cda78f4d9e8be85e3a0b299057c6334bd3d83b9cf1b4e09cedaf92feb60db795292cebe293850ad2e3a39328ca1ce1105905c6ddbd7815b3e27a08404befa98f95175499fbdefcaff7a70b26dce835fe55d6bb2352b3f55ff77e2d609462708b56451953afad8e60cbe205368acce28ad13153f2a6a05fff21b969433cfcc3e6202f4625ccdf9b57f275bf38d1ca425eabfb92ce228a87e709197d259d73fe80c4c0f7ca78c486e50c14f9fc1bd8a1ae2e6afbfd8009f2f6e16611f5d8a1998d4de4c7b9933d780575a64e36b51c712896e3da5793038cb96a82c43fef70a1e6d60363d282881bc157f789fbe76903b987dec8773dfcf2f7dfae12f0b6998f1688e20d786f34540d203c9e5e707d05a1f6bd5c40943970e6b10c75ac0476ed23a219a2dbcfa876f1411e505f706571a83751cd5bf2f9d9de4534fdda40cd30533aab1466034073fabe645c296d07c28bffcb10fff1acac391ec0f01e92ebd2f4e350f0d3ff88e504186ae00e19d66a0ae70772cb05cd543e01813a48262a2c10e8d577e718934e25c520b99237c2569d38d626e75e183e57bf0b0e102ae25b8430b6ba0ea7a43fbae827c37257fb5199644b3dcce83b4bd8102ea3b51282ff23152fdd53606a19d1e946ecafca4f608d0fda44d09828b9914badf764ba6786056201c52f2f2ca30317dd0262e09c646d934120e9418b51d07fc0182bb0949c55f40f45b46e2cfe0e5ab7fa355335ad340291d8dd5e35ea4324e421639e1ccc8d808a1c7fe78a77ed954e09b00df0d544bd6fad9171f08b2690ccf482e667e043ea87e97605b41d4246ae987960881bbc9ec38d4ba23d91241b0e1f24c2250fbca0096db6f5455b9161e0e9182dfc9609fb22f10758ea832761054d3174481087e94308d93397798a870c4cbbce58af2d75329398ae2e5968d4c46c1e9288800846ace2f1db199857803730a92b07b607996c4f7300e518b5ea70c3e4f9584af549ba431050fdf1365510814695d2e011748d28e8d785c4393b5c1424568c8200e474202963f395fb2c97d0b425079ad8ea5260e8ff515a468e1630242dd272fdc8f33ea0db2e2ece0632c063e1d16d46b86028d95f0895573483a81a5dd245294049d61d160952e7f120cbdea7d2ef32023b47a15b5297d5ed22eab258379e23748720ab1f4925d7ba7f3bba4b0ba8a535bcbf7b4e45701656491edf92af0df23216bb7b11ba27ca792d7467d8a48545b997677c017076a899a72fe32846a4c57fe463bc34da69423c8734bc9709d21cd6752d61306185ba24ad625a64f91edeae2605b4d31ffdab7dfbb7578c0d2028ee8f4ac3acf7e69d2e4427b612287bda1d25724b5c7d7b6f31573d17500ec3cbc89b3ca0732752bb1b50c96386a1c1b5c92a72e90a802733d19cb700b0ce9c55157adb29d0614eebfd9d100eb048a506553a05823a24c996d5e26f920431f49f4ecc4623f933d673d63b06ca7fd7f2f40bde05e0a13d13261fa0a5cef00b30281f37c6ffde2b7423b71f8e0a35fa6b7d191f7da2a1eb10b7d5949b6d8cd575e08890759cd7d3fd921ae5ee618373078f521e13ef9b3a4e18a4ebd04d0baf3bd25463227969476fcd3b1f569ebb9d6ef28b67721406eea3b9ead0083f7413ce3aac2abb5e1c4307ac7037aeddb1169c90f9406dc79acb17e9ad26da99f7009ec8bf0e39bb0ccf36d9ce7c0e0126d2037a7301d0d01fac6db10a3ab5e41bd89b4c282a199bc69dbb8c777707c85d7c152a68358ea103c83ce639189c10f63f103431fe3a1c9a68fe3b189c78f63b349c10ee3f109818f73e1c9a68fb1d4ccdf7f575384558b2e7cb72f2f57536e996b7dcd0f8701cc753290bf3c568e1d7d55a1505093f96423fbb2adbf7b784ab8227b1fbd5bb43794e894065bf48cf5568ad7e6d68ef7891e370412bb652deee5ab5b8fe082c3b8a5ca11576ddcce4a76cdca75896702ac5399a28ff760fa3bad7d4ef82bf40b943e042885d20d4dbd19e1d759c9c4ea42ba059756b9e2b23889e822b1d28d957d294fd5737ee6a93c149d90465de92c951ae8b214d12b8718b4caaf886b5aec2cf468f93becda1c32bbd10f25df36f2f96eaf68fd95c8185060df0061979d95be170f71e68ae5bc50b036d1455087ec2817c1d8a856e788ce06ce07d034ed2343185c7074265aac0b48212dbfa067b71f3892ce6c21230b734786a64dac93f4e6cf382078dc5efce7ca59eb12346b502b0b5b20334991b6f7a4def7ec1ec4e29a027e50dda8a99c70217d16d6442f1d7486fa003e9c48331a962c76bb8f50f5210a5907ecbfe72d6e8d9a0e1a80f0e30ea3590a23f8197197a3a60142cb88e3cec3c4bb60966f4e7ca5ef75d8f820e7c9b663cc3f35780e790ce50af06a16d210b2beded0c4a042b226488cc1410268ea804d0196282e3464beda208a42d3036630b5f960a952989c360ee8b76cb82b48af1507822873f50738e28ec301e6cca3f0b43606ff7b621ba4debef83158354b77bd767c99848cf079f835f9faa12409f56c0e7f8c1d29feb0de0cfaeb90a8c6b42814fa21b1536833d2e3f1484d4af80af703c09922e427dcf10c6472ef74e7aef7c17a349539b91bf86163fc5104a6f684d5038ff880a6ac3dacd398a8080dbc4d3191a31e5df57252bd4c69581a11e6a72dde3fd9557995be88f9c996801d6dd2a6d068eeb23757c46cf91f42dc62203bf8bd782a30bdad5e7f93a50b7d7b8b7df66887dcd02f81e8f3debffba76ab67f5e78f181bdf24e7c41df662a48c839e7be7c348754806ba4db59e0b122be1a8a5f74d0e4263c1f765d6af84f96d0df4002ba43a84210b973c612c2846460702f895d091b314e35de0240ebec12ca2ab2a8d212112c755e48ab1812af50ff9c9ca6649d229b30cf68249b694bea19483d048b82bb7ac310206c826aaeb09fac194801690b33a10bac8e56c298aa9a36c67f4bc022c2caac4e88f818ac663585bbe46dbd120b7c01f57241bd946aaa53298600fba73264c3682ebab9985fcfb566d3a6bdb260e230ccf7f656b770bc07cfb7f742abf8a86cd768b6c95f4618474f923524038fc7d6890b2f43dfba0a656cdcbfca0f9f05e5d711d8158423f118084e4a56ff47c19f10438e2972aa2b70dd479f336b33d6c8525da9ff283a8481f40020116647d1908bb4d067a0c5f404f9034e73c4dcc54bbaaba4020b4c147752ba45b4bcf206dabb5fa450aa0efd30fc359c0e1640d8de18d22b5e1d2c9d147b09a212e21ba40b5055a495725619b77bce0e6b434ea9c6406c19eb868c1cec9ca318ebd5167bdc174d7c304751a40dac30bd960890e88022b021d9d2b06c92b1005adf00f6b3b2f226e8478afc23780dc58e754c62b5c613ff6311f30cda76a7a90dece5b0ee25e5195b6fed37e3154fbe48efc228dd23a0003ceb542f6f904c782b0a0bc0882138733207af1da8313ba6ea84c95ddb555afd55b05fd5f9aa3cd50df4eff586f8b3bff3acad164c119280bcd5545aa43c4cf7ed2b3e586f14a6647c07d4357a5b3c278ef53782359e3864ec7a344b022930a6c9ed9b64e11ab33d53e02b18af8cd5c4740a27c52e0cd5bdd0eaa28e8f1bf1fc251afaa289f5ec9755b8469201ec9be6104e656f15910e241501e26fc3b2256ba046bc758b518111f0430bd785054104cdc042ade4d4be2e9ae5548846f2f8108075c720cf655d2bb9ac39122f6fb154295ccd71c134d2c400cda5880b1001bfbe3462ab79a45b915f41559e06454926d86379e00da4e58b66e322a69a000c5cf21bd8bbe5578d916e97dfb95576100bf05fa4cdb842326e84ef6d06c56918973e8e677ce56f642406350db6d8ec23170004aad47c9b851af59b13d6d814f0685a957404f210e052cd0d47d1df90a8806bc7a513de0cd773244b767e0887022ed970250dd39dd9dc999db24f790c356771f693a25d0dfac859ed5f3f3760bf3b6d8fad470fa00589b3df48dd151596c33dd85d69c8e97327805612885234da228cd261fc5b1c24597c23db23bc22c70932b52290da20240777d99db7a6cee49791c8434e0e8001d6b30afa191a889982e7a4822ae33ecabbbb7200625cbb95076cd8334bf68417a06a22fb4a58d89da8a7d5c3315ba1e522ff3da3282bb9e3759e8c8ed3191574950d2bf07db12d270783671ed7456bc0f1c06ff6fafb612e191140d7082a8f9089762f682bf450844522f86bad2fdd51b0c17a8a4211554a5e43ac5b3132678ea11c146cf367265e8beb3e2d083a3b1a48b4e04189839ce5b64f1bd9c88ee443a8b3589731396595095f2c452e997462d0b9a466d37c691ad10d76a670108b7d1c07327bef5c622823bbc1d1b73c1ba1bad6b572ec17c855344d22ad3a85a460e22b2b6deb21575f78104cca8803e56c902e5ebdd468ac78d98bc9a9ce81afec0fdd29cea0602ba929b51a71ab0eea0c64b581598a79869b71fe68ec52d755648abb41150429555e1d629a721956b92dc039babe5adbf4a017790187c33866c23993697206a0fa379dc74aec75527c064df90a1a47538edb7b7b30cd71a0f4d56a70031c3c4b18960c437caf37bc215eb4e29d50cc25f94cea819ece3029455e976b025e3a2a232bc0b1992cfa55da0c199bc0158244812f0a056ece5c68897e9d3f8c4ba9bb189d8b75253c391ad743394bd7b72cfbb192a7425e55084e8f1548b423763790320b2d5d97c9e6c49fb9ad6cc08838218e92f212a3551a6c6f82bce6e06c85c9f67419bceb4c9fb0a7d45c9a844d214dd0ced6aa46d79e666ec3e59fa9e101a76b130e6b7601a9012ff328569b4eb507257778afb8be71e047fe84e5b7b30f8d0ed339136721559e3d39e9fc3eea13b5d3885b1b32fdac5c34a4ef82e85dd781567ebe1d4881c42f0bdba0f689edae266a27ed4502ab45052d66228e949a88dd9a7be4f1a8fd37e214069fc3ee9cdcdec3270b09950b83b6322ca902fee9026adbbb438b06231b18706f15fdf381d62fa99adb7d343fc5d05d1e54e8f72dce4dd69dac34bbbba08357973cf8f7174f6ae115cc0f19aa71980f3f37f7a853710b734a604a5b95c46b5b566e23715e8cee4fa2a79aa885fe37cc49e10be1377b11ff14b262caa3f0cd4a00158e8f8dcc4075aa938b504adec8b1edd40c83dd235b3e25dbec0719b1e43de99cde45070f25df227b884c9556516229879b3186716825774f9aba286e512d85c9d71f436fa34c5613c1e234af4dd8981d2946fadb9691ac8d0f7230f84053f6f5c01ab428e53b0c4609ea5cae1f4db9d7f7bf8f2084de31cf0cfcb816c0c88c2a4a4dd7dfee110c6f0f2e9878ede6a72c026f59ea33ab3e097eebede272d12b7e0cdd0ee6e0e406ff75322a66ac028846b0442f4839ba0da68e8dc52d2057d38f254f5d6ff607645db5a2cdd8e65cb886c406ceb5b1b9074d08ab9516d8b355f69ba03b56d2b7e2516df626c6b9cf29dc5cdf800d728434ddb0a160898367e69ac004c9cfa3bb0e80b4e3226d149a94485c7e024217c29c7f1fd66342055388959721286adf5a5eabaf8a9a10d2dc938e9f6d929d54acd491d9b4b7f44a2fba04593ea07bc4dd073177601dac8da4b3a123a3f099c2ab150f8984c7fd3e14def293ec9f745079900cf201943515248612fad0f4e5d17e0c554ba23630ae261220eba6999fe8fdda4e1bfbfcceb86bfa4f700328a009ba51a0156663865627ca887490839fe833c0ecc2b6b2443100cd17efb7ffbefe6ef6e4a0db8af96a3e1988abff5fde69febbfe9a5e7f0194e2631ec8fbbcca5cac85b89ca974c0400c549f8649ce4ee1e18bf41421227f93058aa140ddcefe69d1aa58125877762a0ffbe3df8b10d63906d57312c9bc5049954007e056256769e8cd1df27a50ce44669d007a0fb3adb9ec7d24aace0ae73cd09af13076f8eb10206e79b4d5e8adc01d02019152151a8e775871992b5937175a6b3597a9e9ec38d8aa943f36fdc16149489bcfa8fc1695ad19b7430a0d91b36d0640f0081026f3cfeccd7c7be2858391c1b1aecccff80aedf080aa891c55dae8c409a37dc6ee84031d8b7b83e5eab37fa91b090566cdcf64dc9a637a99404ff2fddd260ad45c3ce1abb654dd872220f83aa2e0d9d5ae796d96ccba53c0dd237860dea9b001864a0944928260b2868703ecd7c3a19fe31bdaf32b2f979b4610a27c220b071c2b1a4a294b3315b851834e1b026e33a49d08bc06fd3a40175135687b08ff5315d7aa573283147f5d306b5c602a81db46fe4b13a8cdb1c8038b740b5554b0c6900bba9e0b73c0e794372e2399e244f7a939685310294f657a2e0bfdec032c13256ec147d644bc1d6d54da178955a5fd13eb3a1db179882765a5ccaa2bed860cc48e69c58e430fb1c38f7f1a56124be60f403c26d64d7b6c60ddf76b65cdf2c58021c1a9727f0243eeb2a5b3788c9bb4c1929214a6bc7055d087577602aa8d4ce05ddc78a0a64cfb372516a1f73dbefaa0889387b02320149729ee3936e13de4e5c54c76d3c571f61a402085537774213450796e4f5335dead38038cfe4227b2ba14b674444077a4027cc7b397d684c0843dff20c96aa268ba34a30749c8ea0c6326cdab3ef5f4ff5a2ef5be4124467ed7fe27dc9d6813ea0637f1f2ab81558554b70aa0fc974a7a60d7656e673894b551bf6964f1ff14beeb87f6a631af9cc84b90c59be1030b4d0fd7a859056ca2bfd818a24b773ed728a36245e997abd42dc0067440680b38e7d88376fbec5b389803f0e85f8ffadc7d19e51604ccac90a3046f4fb36e97ca61a27071d3c2a11591f1a1d20c7ae4f766f8b4f09827adfafdaee869291ddf769db1cc67e518c0f72fab3f0c6822d4436720a10cddb93299fe7948e905216aa08925f31f882ab759c3a9f84b64f07e5fd721d139f86bdf442e02f504e9bc5e2fec1a2aeae14931f1bcf5ccc86db4aff9057c7ebc990310fbcb45b51a94fbc3a6451471f405c214f1316b03d4ee372115704e473ac3a7b74b95e909388ccc2e0938bd32dd1be506e1c9e9fae391755a1632dd8d6ec31827ed10a8379b1257b4600d2d28602bfab3a66d0220ddbd60ff953f1d562641ae5146110b8d8722e442967513bca4ef8f7217910cbc333408f8769a8b79caa87111fd62ce34d2cec9842f4ca6a1eb41c80347344237d555aca73d6775d3dd7fb1b508c404d528f8e335ea6675580c4062451a6435eaab6ab66829e5e9882f76d2e503d02c0745a6dca87bfe203bf291b2efb93ba5eaca7054b56e2196ed91b5985e6b4a19a26d3393338e13915ee6b3b5b2df21d58291fa504aa1554b370dec6d9d2d2de931539852890f4764bc3264569afa9d8676a9c94d7b370e537a3e699807868c50f52c87245e5e4621125714989de6d97f702b342bfbb0c9eb2559d45f5fff04470a81780bd93cb6e5b609c1de50cbd04c3b51eadf8094d357b8b3ee16d4cbe53e19eb6b354a3df8395f251246023627a0e28f36467ec4b3d28cca2b90a1ba064d29c25b32d39edc28cdc7093831ad1654c8e55a1bee6b3725b07f4ae1dd74d484d4311d3f048dc6caa36df9c10a3c6344c9bac7f0e761b2fce90e18a2c04543810fc964936cb96384201dd82688e137a519df9fdaaa413cda4af51ec3f0c182df3881f424e20b2f6906f2e17e549290d464841e0097244e9ec3518b61504f96516c006b31ba3a79ee10aed9a4c18a940863ca3edc3843f778855077daa7dfab9b8d33b81eec41857265f996c07b43b5fc8357e660c55a04083a7aab9f94b98c674918a8ad4b41592f51ccbf0740add052e8ea66ed2b426c230b16c0365c8010bb1ade97edeb6bdcbfb6a58232d69865ee021db1d51804849606fbc58309e7c5aa6d04e19f3cb50085e92f954000623a5227a84bc2d9631fb2c44eefcdc4ea189b92b75350b3544f3c65be691a0738443b81ed17fe40af5ef69609731a4f3f3ed2627e9c10a4eb908b31973dcd5fc01615d37d7a9f610939c32b02ae044e9dc53404db23cbd13371fca616ef9d9f49bb3027cf4427626ad6ca6de586b69902361fc62a2c54727031e5be76b82d9ae86f905c7498a7b8eadd9ad30fbc2413c4c10cc62f79e967d2d246ca9e8cb6b1e1d9c596594e169abe884d1139d5f833c291e23252a804e59268cda3aa4dd998d1e57f1e031080d2473cc8c2cf50ccc917e574396c7f402849043d0dc1a9d4c3ca4d3209d1f33e2254408164c91f189516b71be5edc3cc64d39e39d35c5d989e9c17d8af7c7f9b406a9446cf4c349294e251a4ce55b166b283fa8784a91109dd24ad88beb40ff21312c653d8e2b114ca2d3f58e7b1e056c7fed90f64b5c35d5b935bbf37b4e9dfcc5f00c316631b36d93262a2342783007ebe6063e7d4e0c4c59782b5c1457266d04c35bf695ea675b32431e01343267a4d28002cc82755b9a19b2b0cd7461843c23e968ca0d70b6f18b35e217f1366e7e9991dcf03603f4c87f4199943f3711f5edf3e8e6850bad2825d6c9cd6e84c24432a08dfc0109bfa62c062b1c983c036d60bfe548c79df0227c982c158ced7562532dca672c859c417f2769543bdbac8fb06e8f891217d14424e24d4660c044e932a0268ed8f01e357038445af89e0c073cd48861f756ace4983653a5f48b1a2074572d298ed6e86f2b04a3181c9bf856c5c94fba9fce17cf1050b6b14577f75b400973622a150208a602c0254f052a5ee036ae0d0a07717450beab0f45c3d9715f6f4879beda465ddfdee5866f92f43ef51ad4638e1758dfe22149f99ab8ec3f9924ed4fa75f325d0b49925e2706b32ae224c908a1a55092e2a1b80e6c98529821272597624fa093492b469e4c8cc68e256731a38d269d12e929e423b8329a5279155716563b20eaae460af04ca89da0ffd2a40a8d3ee1952615287f838b5a26df996cb28da38c36ff104e06940b5b9b3811cb7a9f7b5362a7fce6a0f4a1326059778b24759de1c4c09de8751114caa174a7e5cb80297cbcd70985fec6c0a427a13b1953e49e482eea00d91c5e88a3a4649d56a5c8a83ba36fdec8b24d5cd07f5dba71a3f361169c76d16812fdbdc8ca66590da513115699671830f3ddc5618ea6eb7dc14d45e6a69ad24ddddc4dc9c43b5b1d8cecbd33088cb97df27863eeb3b484831c731099a3cd659e0a32586374704144bb84bee6e3643f2e5863dc69da54668b616698e3b11e181d2d4e702d91123bc5ba5aa98bf79f360a8ea95cc70d216719a37cd35741da68320ad40e03a5aa8d61647d4589062666c683d27d62988c6f77049f4e05d1a89b5356da22846b9be0042452052d25b301e48faee46794576faed8acba8a95c11b4873a451d4adba7526e8cdd5a4a5609deaacf83c6f379d53eaaeb8145f203458ff50a4404692ca85cb85eac49b028fa83a568014d15905fc1980f014f9e242d98449974fcf8e02b8572df55903af94fe9c0def31e1924b858ebb49292ced2a2c73f576c8e9a0f1481a3eaab4185e0251dd2254879a30a52bb373dc743ad0852ae93e573c3a264c4f794f073dadb13ed9d31175040e10bfd26997ddeaaf4411647bb49d2527050ddea00a4c1d4244fe36274e1972e289f10ba7c4aed8d7534d30cc2fce7c3532224894d4e3be91add9b89c5fa1b546bd41e066370fede5bf3737172f1e57ed059eea51d2d14d133637e3e9331510c8676d7ae66609c34121c8084ce820ca462032ce8680979bab5c35263c5ed1d9ee59039dd08d7b3c92f3341ac23006399f277ac65947abe6911b0009034742e2246613254cd14d1459f31f57ae80183c963e6ec2e6f522687f28146a0048fe383b52bdc40ff73011c7c8b6e3fc79b30b27a13396681d02bb813568f4362e26c3fe3ab5ae47c0a5f49d404be790f254bc67530ac2b01095f2d100f80ccf86b4b0739131e3c98a1d8c505272469ddd5abf0b85673bb6723dd255b4119e1f74dc5a18eb07cba9205ccee00a2c03d9845fbc081175166f140de594686cad2ab3755d386073f23ab6240db12801c0b22524eec7ba3a53780cdec306a775964377de465b025bc2a696a7ece334ca51d580aee78af9126a2424319330e4a7001e7b738d901725fd05852eb968e2dd34419cb2c762b02849f2a300791eac804544ae2776216ec1ca9466542147f2ce44bc210f0a937e6291968c0dc932b7f141113ae48b5b69c57fdb42ade8e47d8daa10943d21199ed7b272c9ed247a9234000e2a168047c2140b91c6ac6fa0bd7a5ec42b91481e0817e4f54c9a438c4f52a93a34b5491472acbe1ee056b91b940ad2ecbe7707aae3d33c31ebd749507132e47b0d19600b4407365be9a501fbb40989b3d1487407e92c5fd651cbcc8505277afba17d0911c3ad30e10037bbd1630761763245f55ea9f941f638f58be807bcbe075c2cbac2a56023a2beb680ef03306076e66b63539015a687df70b66d4325aa8a3accf944b39cf4508a61b14c715e4c915d4c34296742548449d87c039640ab5e7a6f2faedfe87bb5aa56b6da15f1df02eb76217ef27e88607aacaf5e52bf4b344ca15ff17d5f87d44117afbecf4510eee9938efd5246792ebb9c9d905aeef03006882342b3253b0665b47848b406d68e81be36dc7e84029e78402544a90424e6bc72c24f0f38d52f5f0a8a9762764e58e3fde0801bc5ded1c915b421c6798fd74fd07a83d6340b58fe1f6c82675890cf5fe30971ef98c070b7abfc7e9acef646d26c798b38cd222064a3725b134466f68f033a992640a7de9a4065d83aaf09b1f7b3a15381ebc010bf284919e08ea7c5a4106860815d87c793bbe0f341f8f03f8147f472bd3b60873209d810b7cf3ed816bc4c02d72881a7aede12a39b4b188a94bb3305a1d574ad693bb8d75be0c99cc10bd21d8b0724b6e49135a7c001bffa6eb60827ee885e99c496dcebed00f5e2b73d2ba8c6b643138d4cdf64531d6fba1fa18b58cdc4f3c99b5a461ae3e5aad88799b80a79747650043ceafdde16cfeec7c4797cf7bdd01126bec8915babddad27c2cda7687e1876e3269acd73090848aade257587574ed8e3e922cf598e7dbf84986032fe17759e4b698258636a0f6ce1333b7eb23e6851d88e9dce44347501bd4ce955dc1b7aa62242506eb6e39527f94b808beecab96fe8dc871730b0e029e24518d65b30deef313dfb4e727589aa207eaf2fea1407bcd223d7a5b4c65d2fdfd6c2757574b75985a05feaa9b2e1a678dbc07c535d98c538f71ccfa45b9f3f5b9281f8969d5b0b5c98d997875cddb321d7356bc38cdc39c6cb1d5067c3ade992c3ad362c510ddf62bb148e5bf36c8106141625fa2cfd7a58d46a9d710190f0da3531bbce6224f0ae81048afc660703d00db4d20eda79946014f7ad5d606d146b41b24dba8b82b5e6238158419f5a086249d1c0a54f41b070e4f6fd3e6f6e893c8521beaa350607eab0caabfdf63c0ae9833336a08d273f443e0c98435a88ff50eab51f89352165ef1ba5fd82e2bc31b3e1bc0075036ebbeb6816e9ae7783013b069a1efde5b72315239bc150ef22032db8c976f3fd4724efb88b7dafb2849f334e27fc3d606d96e76c9b507ccce63a0b0206a681b29ad484466433fe29bb066080cc146e4533528ec0ddcfb47121f22f4531b0abd437cc32642ab47c89fcfe4d5a5de5ef1899326f0fa88c550537f68285adcebf8494144153be88eed54b1adbc77bbf7fb5b8d23d5187cf2c8fc541ee3a8b9af539908396b013ba10565077679f1e290ede354005e7bbb53ef7ea581c1dd21ef2d02196af907069f66e9971e1c0b1a3abff73510bd516d4221fc48fdc795ac99f36aa60aa7a162d296c8597035ee52ed4c8d62ffffba89996855fdf5b7bac6957d7d4bd63e5054f1ab7050b22c1dde53e6454d92c5bf12af95dbb1e622598d345e98c5154a682d9470b4022d89f0c32b57ae16f24828f6eb02cfb8be0f24bd6780a6eca0ee3972c053a3e58de4895796a9d6e49db7b502b52bca8a3470b83d6ae33604742f3e5514852359a183a96a360d6c5a3765a0c03636cbdec769ed81728c5c4011f036fa55e3bb24d254112abb3d19cb0cd155e791983496a0980af5b30bd0e6ccf5ffc79eb8441a35c3c0598101c3e06f3bfa84ba408e31f3d8dc07c35dab31ea34b0070c1a68e8a4305c3dc111cc55f88b78d61c4b6b670fe40b69cdb5fce0b6c897b6c5cbcc3aeca41b0e9ce7080df0c5b7aa5fb8d705f558adf339eff21cdd067e90a7680420ca236535e89a2f086e5d383b6a124625f4c1312de1d0dbdb439519c1c7e406e0737bf492f2346f83a3fc0426d38cab7a8b19b78a7d21ff11867fb5bd62e50bc25df87dcc89552c14a296ca70f67e43581a85f799fcc209196c20590372f57f1389a7068c498ec74610780147278aadaabf3ced9f6bb918f0297983a17dfa1b9926db7e2e632c2535ffd3a9bc53e6ac2a0720d38e8e5246f4fc5d38daeb0a6c5a7dbd196915468791fcd0edbe6caa21f416415587f8766cab28a37d7ccc0e12f22547bc3d11853f28ae65b9c34a85044282ee3c86f8b6fa3ae74eca4c93e35d30839e9e31243ef1ecb1275ced33726d470e98c944045f33d35a372adc60d90f73253e48a9da5b0383058081cd5d3da01ff6627563e8faf92b40d8a16ee0cabd182a093203db9d74695925b7beb8f1735a79a4ec48734f6de27a057672287f8805965aea9d210e25bd1875218cef97ac1aa4fde28b6daa3e81fda4e4b8abc0c05605e23359b6ac768dce9850e53d3e03e1d8a6da4fb75dfb049aace427a33000d96516d94fcb1de021d18d6bc5ad2abf88edb7cdbb674ebf0b168e2dae314a60cb7f5cd24767057386ede3cf2338b15fa2041188f1cbecd2c2d87491918a2774b852b95f924669bef604793e036825ef36f025d06a269c038cf6b412a6e18ee395dd07e5bb549ed753de5817c5e0861d77811cf536328378c2a1ea986b9a4d0b7ac4837f67faaab4547a56a61eeb8a06d69db6e37dab9d2720fb37488b5e3873f46ae2a947b007a55b3bae5f4418d173f7134d7ebb77b9f219d5551739fdefd5354df8dd28a682e6dde5a0da4e21f76ea3125859c469da9c4c047b7d196df5685594d414ef1475b867c34f4edc495ace52a5774770d85da7c6bfa33a4750f232fd9e1a8ed880a48ec32c8adda2179835acc093f57fa2035d1f3e8b0742578d5bc39e8e9daf96fff8480835f94cb8e614a7e68b49cce628e0bc66a5be6fa92bf4ef1dbeae19e7091eb107491c9c0181d9cdf8389032e09b7424264b2f963c52d819d09d37b0c60da58fa3c85497707cd4d5daae8b1b9aceccd79081b5ceca401e61eea2d4da9a1dbc94478aee8d8eafaca5008c59d06ff20bab33a15ad8faac1950bb909d31d626007ff5ab59867a457960001cc5cb94ac40b9c338629c6d3530dfdef8a6aa44a6a1f70d5b398d000c4f4f8412b3ee536319d8d9bd82e16ada13e13d80ec5487e6388fc7105607f22f3eb654520dcb5d5200882138dc170cd0de1aaa4883f82bf230adb66f1409f8119b4fae128901ea315a788d0ab9ea876a6c98d230572903b1fba7be16bd5f12ce50cc0e26566885b5a745fedee0c4cda638ac20432a346ef76e410dc2794ba328f0f862e45c2f61e7cd215d0f5c15f1f1649746a64f770993bfbc50515a1ad063d2a142d83f08b5a1864c3308d21c17c121f98508705537ceef84460425c3a2b13a2304dda5518b959ebeaed924c3d9abe9cd8a7d52020f9bccbbd4f51576e2aff2637e94e50e256fb1a1bf2098b9023fbed6b35f624a3acfbb2b55436bc5da6cd3e7c4826c8e26d142a45dc59f19435c212d5d2cb139a96b55327e00995b55068b8ff0610e05bc907cbd354495254eef76db000758d059887ecf5ad854c389a915a295d7473843fcc73676c612f25f65b5f355339532375e2798ac41069dc847785f5041c71ebd2ee80ddc8d0d926959e1b8db9a0a45a7ad76a6bcf28c33c208b7cb4db20802f374894cfd8f217a62a44574e8bb45bf01f137fba5a7564b2363406ec88ae24191ca81df5b7798af14d50bc216a28902f98d37895026758db8a9e748cc99a154a1b980cb912fb45f3bd506cc0919be9c0aa72acf872b910eba82b457443d4d925abd1fcbed8a651123e0fc6a292e385e01bd93145cf2dc15eb2c5733072a3793b9daf99bc5b8bd91a29abdce2e87e3aaeedf18c760221b631746b1746a7be507376ff262e77b673b2f9932fa14d39deda0a112d8cc4f560d41b50024b0f778cfd234cc78110ee03506efb146698ba56881c20574cd05c2deca1f46b9415860115e012209badf183de2833f7b06a528366e0886d8a310876c56cfbcc53d088ec53cf24e89b5ecb7de3923c055fd3897189bfab354d8e16da4d0013288a6ef577f5d03f57f28d9eb0d969f722dc2ddc719569e9b1a61056629eb57163f2600c38b44ab1f5d89a6bdc4b895cae33cddedf1a1ff6d8bd44a6ec9e49b0fd9cf77c09ba509af6b69cfa955978aa91efeffc95e61cba3b1f36ca9edde872f85b22da1c1267a7183cb873ced78f1dccacab5ec6b087fa37c59138825364dc1edd804fc143ff4ffeef8f334c5839c73fff9a08f5f287fe5e02934a43f30ad99e593e4887781754894a757753378845221950702cbacf010f66fb291c1e7d39a9d1e3e9f6c976c4e3dcc473358f2f070ab9e48eb4eed98f70adf2820db9e456c3ca91ad9875f38c59cb9a1ef365a53ed02c35cd64f8da071e5214a193473ad578368710e1456fd3a4d7f82825672ca2d1d5e83779c4140d8c79e86767776de34d93b551f0932cb515fa8c399e522366e6426934c935a9613f6c99a1662cd5efb0c2174b433115258a1e387fdcdd9e60aa87d375b3346f1ec3c12b597efbe0e04b08975c45e06bd47a290c43dd789d9c40a6542d9e8fece63ad2c0fc9b4973e4c69acd2f1028cd9cf660bf44ed54e67d6fdead6b5390f47104e2d2f6b563ff2055722507574c70f34b1c8a460b1e9d116d2d7b300abb163ff8a2231327c8558affbcfa78a913c3cba6a1ba05dec251543ac86521d346d64b97da7cee1227239255eb83763ecdbad52dcdbda2f60f55fdb8573023765a22817b55a145a8a0aa9a1e5c17fd7dff6a5c961b70b3b97320ff363340d59cb317364da09d009c6f5ae74fb50cf787642d9cfd6b2fe08b09b776c73e184d976edcf00a400a0a3aa118db39010ceb9caf636977212ccb9f520a334c509248e9e5cb055ee08cbc6dd985ec949edfdd72892856921d77a288bce75b3a60daba062177794525ae315b193804c41e9f4880816caae4c07eca2d7cf552df4a906b18cd63243b2cd3a62c71540fecf229c285ddaa8074ba11e667241d4ddc3e6e21e93e148ac46a9cba06601a15c0d41a5ccc70bc0c64d3b4257285b6b29fe479bb7fe85a6a7473d08a7d1db8ffc22cdf58daf242d499677e2038d35d94432c5b7284c4acd0f140d972df1c0ea4ecbf1f27b1bb45520704749c9fb09e76d29d44dcc8bd3a2ef14e19ab46c634c764f7754fecc8d1b11e5e4a0629c715d2ab748f8c078056222736918e25809b2a1e573d0dd4069ec6b1c5195404283e42e3444bfded6a890e40ae55f8095bb6d43a24bdf41bebbb9bdac494f2f796ae17471d9904a6b63d522d6784ffe0711fc4a78e6a8620582879c20194d940bdd0b9e0ed33e5ca7a26d7df0425af50ded27409634be43ab80dcb70b392130423474841473de2286b05fbaaecf008dd8f1671f79b75a1a79067617aecae28b0dceb52a513fa21e0225405c660e91ac37c94f1da8b68b682bd76c603b0d99228796d66dd859e490ddafce681bce62a68c6ec7e8873a7e0f4c0ea28fd399122d17294b9bf39dcb9a9d39b2788f9f3d968b735d350848ca0ca7a528f2179874e09ebd4dc0d6933c78ab5dc79ff89739fc0c6c08854dc0db4b99b6be2d286b123d34555cf8bf5a96e3a46963fbd43f92440bb10e7e95aa64b89535a97f38d734210f88353026f8684b3ac2b57838a6bcd09a0198d24bb267f90a89c236d469d1587894a19bde81b87c13a9328f99f57c8933129e26139202aae7961a47ee80e585e44693f532bc9335362801e1015d698d1baed9f28e707ea8c452135ef7f286b59af3343439323ec5bfc1bfd4554549107b7c995a89eac42e318dae81c31946a866d1f0998e19c39394ce84efd0841f86770db4f08530414bc5753a95acb2004623064088ea106df117fbe3f6600635647662b49a7203d71a4fa45103fe3a8a5e21a0653dd09d1c924dd61fdf0421ee2ac6b7114f186a472d59414eb6eae29ed986baabf692a2b9ddf547c0b31b929563d8ede8485c187d8a879a48e8ea9768ef36cc554f174046de215e12b4e3e41b9ee0654e4129749b1d2e5c8d08b9d7b11499d873d813479727acf863fc7d7cf2ccec54a705fc507942d1a851c202fe4d86f1f2939ba70032a6359bd7ae37f2957df4ec8a5d889d2655df1d60cf17a756a5dc28c515cd7d5c0c44e2279b0b0134f9c6cc61d7ba13db98b8c096b9ab6f1ba0111f5f1d2cd35d0a28fcadcaa0a74c28c67521b90f355dd8bb05258876245a9ab24b7595885bcbdabbb60c862a9241ea2c1adf403ba59da6922ec77e133707ca749ecaaf6ff9a48b00b2dd8e6bd3f0094841d07fa7186b6b2dcefea73ca0a18c0a781370978e8d2d8664659a11cdd2cbc7507bd78a14d92694831eb0c62683e75981d34f73ef6c7ec43f226c346c2e9adc81f81246ca24fa91a046df40a0f25c1fa6020d542a7a8b250299d9d8c261d37bafcc214772c4bd55780cdda0f6ab453e3d43a2d98d1653d4b22d8922be02b5b980a271efb4e4c566c3089a04113c4f63a8cdc1327f7ed891c8ded9bc96d9f6d46db5767a8fcee972827ec1ab44305610d155bf6a7f1dc14c86c05dc776f62f1415638cf3392b54df32fb2ec922a646e4845d9259d526ab03d24b13d50853ddebc6c552c74d96a3ceeedf96b2852ee960d3cb52fc6e0aec9cbacb475075885098dbff45c25c1c86aa44dd1be2e9095528230f9e5c9ca1805e6d9260ec9579f1e4ebccb386b2b55fac6cabc78612f580f27245cab793c1952b77f22d2d06a511712ff2e3d6fb98d9752cea444c0f30b16f60e12eb2aad98441471ffa8a6aaeeed36736e334d2e20b292198bc3f89ea9f4e57c92f2915d28ed6b9658789cd53af1af7b90b429ea89d39655a306231afa13c4c4d0c0f479e746623513905c2315b3b38e0ec47c02156d77070f985219b7f99974673fde193d95c9bd9df3784b1d3e59423654968bfe175cbe5051b2aacb2ffdfd9d4aab133479376aa3170460743620b4e4a465b789d8225af452bb7a7a700954cb4b07c37a8125b0c342fc16faaa51bd0f2be941fd1a52637973f6c985d6f2ca044b570e8a48b83ec74e1eed33ad5779862b0fdca4fddd9cf9e7aadb8a4b83a87f2bf80f17e9de8270aebd09c14b2c35bd5549fa6341ee28f8988cb7457562b3aabc269d2654f112f0e3be84b28686116b34b0122f34e9103fcb5afec3b23cdbbb3984b4498911b0d16d896d72cefea232974208b008293341dd55cf24e0d5e1bee1de8e02a32a8645712149351d3209113fa8ee10c23fe50397835e08bbb1350446d82e12451700a26f1440c42ae91937c3b40b9de510015f9faa4912fd1a0778cf214198d3c24b3053645dc104192d3341c98085094bf2b81d20a7b94e7291f4768785723fb890ccd254d281d2d6fa47a6e39e555f08be0e19a404ed49c8953ccb1798ac125312af23760115fea118a77844a0884e0a83769054d248df1b24fe0ec5c5a1fba2cec68e3817d8cda44b04be83472e90e3844daaea9d2b5e2851f6f12cca67ab24070fd964003175a57ff80ea3e7183cef50d0ba338f206437ac828bccce32e26b1873e21fbcc93cc14ea7a1f32f8d74df66e415387ac58c0ce1b02ef389bbf242978e6ebb5e62362e980934fd9825eca7462232365bf292562e62a6ede277dfe5c0c6a911bc4074190aeac40b3122dd2770dd7a0fee30f5ddc8146431b54b24e770f003db4c1e9f5fe5b821d132902f09151d715f710e4fe8026cdfbdffbf3cfa0b31a3f6ea94a6dc9b6c2317e32278a3908ed7b5978c42d1f3606b9cba01b3eb8c99261fdc4aefbbcf380d082feb3411e942870a1316225b3faf3e52bbabc18047ecd4aeda6cf4a6ed684c44c6f58826d46512d89a6559cfc512314ab6a4f99a3335ae0cd103d566773e8d1a466aa363879e276967332e4138a5d8d9643486726fb2a90454794fc76b27ebf3d9e6b33aaef8a90db9af3cf059784e5e821a5604a669ac7756113efaa2f8759109b265277fc56aee2fe4f8e37fa3f6ab6ffbdd426970afe075adea516a288de9f0b954b0f61ed1263231525cb8c51ad492d6e2daa261b83bb1ecdba97996eec55f8a223f16fdce025f660261b300c54c95025e5762e9b7fefa04227fbeb20543b0e873b933d6a41eaa8a2c90086885866671105cb6a270c24ce2c294bf0870e0ad9f90d42b154039512809d1bc7c369a84df8c63d42798fd6218db5a5795ef79392419a209e9791269b1211f9e36b51a0ee7267dbe95d09b3d12b069abb71ff66cc6076cd4ec0fdd512309ab24e78ae50bc7c36583f89ac67990396056d351b11f3f288c81843308d2217e99c7468df3204e6ac7bfc51cbf5edf28d3815b82d7eaa7c7531a35a76865b63568da58571df210f392c7aad8ce073242c210dc61b19c892d1ca039755607526dd4bd217692119722507cd4d1cc06c9dc6c42e0daf3ceb2c1533f9ae15668273b19dfdad8d8ff9c7cc3d10558de76dbc3202ba216f53ced4e4ce77cb68012dd3dd3ce5d6d7f23e1514e141c1cfed18c9942fe80b5c3f89685b88e413e0550e6ee82d9720766dd8dcefb24ca34d836d0bbd83312059ade8de1b2dad440f4d92fa3348da2830eed3de7a0881ede975b3779eadde393e99b9df869eb7b50722db24032e7e5590c026fc67822d8807ecaad2d0c3e9d93c385adf938c7e4c226a40704f07b9f7270eb7aa856e20dde85b659a0de9392e4b0c10d3f05d0ccb81b6c4f0b5508b140a3511bbec32ff77397e560ad841c4b637e7c3e511e2fe0383fc81bc7c420bf8858ec016c15466a3eae32c56d17ff4a11f4be71e721e14523ec70f9ca173c4e15522ae0c6414885365d15c89cbd5396eaa6dc98b54323f5b164c58f2502604430cd51ec4aedea99bc5bd690bcea12c907c027e92838b35d2c158e9f6616751a164642d3098e2ee0e9f18131305351d75b748eafcee645cd16542c09115dec3f7fb34cf9aa95209a387f262257242a0e31ed46f322ba2814687eff9c2a0f5f5d239bbbdf32b5622636a723f01b434aea6ce1d6818634a68c8de5b415001014ae00a55766b8c84c832b6862319c1dacd160c8e41a8f7434a2db5617492e00552eb2bdb07c607fd82c3e05bf22d888a7358184fe26f4292e74938b24928c7e23d16b5dc99fdea5f01c32adf01ee78c077a70f3c1f8717143760367781037c8a8a8248c825434997af03a81291eb37778c93e32b57616d27d9421a1142b6aa60fd6bd15aed2bad3ded4ed5bbdf5aba25d09d5f93bb255a5e5a3423ba76f059c83f75dca12e3e534c182ec2d75cf5974423397a7d937b5ad0ef4f3c5a17a641f2a762a87fa384e70864e1e6cdc571bb038ad62ac31c1720f32766e25367a1aa64d9c080752e4e41936541d09e83dd9df6d3a860607f7d2294d4654a0250731d228ae7df6d84e93a987a40a4357cc351a65430c9478725c019217f53039489d8c1793312a6681486684975f8e717637e9a566c5cfcc6b787cfae0e5c7d10466589bb74d744ac11c19e9f6d0ea423ed68be3c68ea6c825428c9311bac9fe721a2af4224a7a5b12fcbf02d1fb8cf306b20927a576b49e522b675e5232090422d77cc93cbcc3b97f2a86976436ba85c80f2257f50ea8a3f1a6d4dfb8b46423925a36d493f676655192c20237fa686a82a1cadf2f7ed6177a8637c6055f6e5a26e7bd643593295a491b48e49fabce69ef46ed6b4d6ddad64028ab874fc0bf3bd4b4d54a3552d4e1699e03f45c51a5a1cffeb3f273970e34b6ba5d90d7632491fd7ff86ff11b6c04855f8301cc4b0d532c7e1df4ff06d2a3f564dad47e0b54411953e87e1dd1f08cfffa4a9b5dde7eab0cbcd31522650909a6d415d675adbcc0eb2253fb182ca261177220c34c02552cdc025d4884f1aba848ab03f1a9d994c1b1d0c64aef6ff6616e6398700c557b191772a736a45f1251913ab3ce5608035fb0473694e477193553d8e801e854084a4c6a2342ba882a4d0166096e92d3869b8588132d3b73e4749f5954044cfa188c3d3a7537403e597d8d5a8a4c9b1e36b2953641ab6205b206c8b3150da0045f2f1bb8b030ecd510248df0583922625c891ede367646583288ee0d202ceb35091ef31f8d8fa779c17eac0fc68f3f47402c212cac9cff64d241c9724f5704f28c44fb632cf23a446f7a93110645402f79a3d808000679f4b605b0b4ba518dc73234b0fdc7149b80dea91aa7a0fcfe9edc8c749a4c7a68dfdd6f884f2a327a2d8ca24b16613303ccc8e81fc4b6ed0f31cf92b252c8ff5de749d9ce66941a30487d1995b2ac044935e8df915cbff38995f4dfb45b015ed8decd9e854bdd76d54de12f21c1f95e5795c2b6cb69f0da4d32badd5ad4769305d86ec57ac97a6af585dc2f7bf569b39b78e7accd7657c020d83ecdcd91ea0a379493733eb4f635285e4b36694fe3c6bf589b5db4604f0b6bf41211ca49385929d8ed6edb864f1f69269f6422906ed9c1af51d791ae5a5b2bb8ec5b1775074a24d6948f4b9eaa9efe4fe33e2e513dae4e7d6c8b516a5382a27f72167568e4b54485398b331e2b011916ab56e2399376e92022e58927c9466705703cfe6679f567ff02da3a6219f393c7bc065b2d33f90b71318717ccec1aef7ae0d81c7f42604ccd3be9248a2d7f63d611c69cc37363bb79f65ddb60ed5b0ad824595b04957b97a9deefc7d5c9e06a91a2e4b7d7406054118f481b9ce83da1642a42c1a67d97799681ad30c700be84ae3f0bd7aeebc0072e7d918a7b969eee0ee18100bb16b8d628f460a92692b2c784a9315fbc685719476c43e4fa3556f8db74f866a92169101263d516a107cdfa3ea9194d0261d4c9b711765aeab849d2d00766db8b3eea23f737fa8b17c57ba10768d78ac8866c61369fe980fd3f5520b218975cfc4c967b11c2630d876b473b7a38d4aa75b633b592832d5accad046954c877dedb9ba51e561e41b3e46a75018e3184fd514de7a65549c2888831ac0c59e05262fada64185a7d154de3043354c034a3a35c534a9398bcec1d132d569191c6591de21bc43433e4331215439ba95e242433646a8d37c906d0eff35d43aea7462c8f1df622f69b57e0e6a7aab4d87e587825881618dc083c97c76e32f8231cc8e49c138c5fd31973de56067fb6402c5a7491a66fdff03ce02d4c00994a60e364faebd00a96ddf085b9228c38ee07d0fee8661ffa3bb4c00d75580bdbb4e7eea8786573291f3f616aadca3127792244e0f7422b77eb6d072877d4934eefd2eecc4948c814072d2ea05ddd2ef8d859fa04e4317bf1e23850d6999cc9cc77db7a6287f71c60258884620fb8f64e03d007068418566a453405161d372d81f405b9bc58af62793dceb08e02c8f4b34c8634e19db493cb89b6a4db239032cf517d1e9f83815691d70f778b370bd0260f37cfccf6d72fafa6f3239873e63ef9abb8648eb6199bc8fbe59f15fe214a6224b8627993ff8712e8fd21b2b5b2875e1fccd46daf33961a4458cc22a7a6662473c24258193189771d70916553ea343049eab617729bd569d525188b2e593d16a7426b7f97cc34eaeec2a486aa939b4f0b076f67a618e54ef7372603e8f32d5a7520951769b39147445391776f232253b0cec67b248139eb57c1b21902e0e57c2a97143ed8525854d02ddfb505cef905cd2eb3278b56d2d494df489127cbbb560e5415c5d3fd65213cdd99420eec0635a8ac568cf43cfaf8e7a7595fba1a768f1fa7c9d9ad9760c540cfe4048b6d09a745e346b73f997d2e051d92d950a0b7891cfd3545ca3159d7ea11be4df3988461f7f433d16631a4804a8a111eea96a5b2a64219d01bf239040ed4f0074d33bd4d7be7654caee31944d8ba93e9b88a85abf703589f6bcc8eaf4374f4a889e3c3e080f2e5383ac85a084c184fa2294368a0394a4699a3b5e5567c353ffd921a23370c97d8c2b0d3f26e54d6cf2c28b8527987731494061a4d600a714159e7010af3d88035bcf6898f8a9bcc1a0a20d20e29860c7fabe97a4837b59981610ef4001acd6fb30fa3d4550d590989a85efa05f9466b4b50aaab68227d1586420e1a2c1e03e4c90a2f97a25cea4dbaa5aa19cb34ab2fb1c305ae67521bda4fe7dbc07ac30a7e521bced1d0a0aa19bab03f0ac85a4c3a5fc230ae9bac2f5cb0cb50e8ab4f09da3203e5cb25db72945c241bdb843879019cbd402b0d7b376cfdb62633311df70fb676a3dc4db153ec5a0f8b2553cfae9758ea5865f91c0440f42c105f12b8966a993a89bf1904f7f862b3890b14d5c33b78d8805f20fb0216ebfafb301065d79cf7208ec1d0dccbce2df9470d7f889647aa36bb6340db4536e9f7f231a6cbaee1e35bad223dea274525e81fc799a1baf477250406d51651b7e4e738b74e7e71b5716a20a7fbab9f7272fc510eb140d8dab48ce9c38144536c66228231e885d19809b40937bcdc73f5b8ec02fcfbe55a48ee8843a64f18d41f77031189fb92f390156df1f77364a0d31e80d3196c7e8b059d95dc2b20f245892ae8bb5534286cec741f2227b9739846e122429096b8f2b8eeac4693d50d1f4f5ab2e50442d1ddd4d85d58b053ecc6708f7ea0877a346eb28b13c9b856fb50eb1871b793c0d0e937ccb496dccf3e2157a6a7bf092ed8160179e4d562ad20ff595728d400d088c14d3d67c256d6791d0eee16a88b5a53309eec8393f443d735bc5b5417b0482319a1ed1b45f7648473b150aced4a83e51ec6094fcbb8a800ec5789051418cf731243d8f4388f2a7205ed86008e257fd93fc6132fcc3c8b2e75b8a4d9fea74b19b05148ad7b3b44d6dffb5d34ed9bf62ad77db67063b5e066ba3f43e36d38b35c36d0503ec16a53840a5b4c92f9faafb7a36969a75146b0e72109db0ac39bc6d43eacfdcc603c28c16bd3a26b31d237e31a0088a439b7ba45aa1a3698753d10f0899b065f7dadbe9b663baf7ae1d410f3571f0084030ece21dbe951dd9ece2ef88254a431359cb8c46ed977bdeb6beede03e2c6bf998e1bce35fa77ac05caf784887deb518719c982447e7be3067334c449580d128d5239693ef7f0a499bbe194582168ca950b77e4d2cdcd2e88baaf1993a190443a5d2822f7f6927b0e85e03c755531ef881217d09ce575a1dcd6ffc18b67eee13b891b0738eadfb5404a1808f5d253a663f705e811e1cb6ac85bb3568128d86bddb21a857efe57b3485ac3ad37bca29a055605c862b81cdecd08dd3c7f689744c1ff26974d3602c714bdb2a02f2cbc141c511da248101031c8f44eea64e987164ebfddb31043a4eb8cdd8400ee478cf9d2f2ed80ffa9ab48bc5ed52fbcb0967fcdd1fb0db8c2ade05f65b2f72122852cfa07683b581dc715221ffeda77ba86c59b045b3f2f74010d065cefb149abc65bbf8420035892b6f451e3a3dd93a195913251d04d7cbc82080b80094d5c9a4c9234875c306b4f470c46776c1c094a2991af1b3f13ea09fb2f5d81b51be372240953e0c956e48eee7390aa4ef10c2c2dfdf946d0a7a98c6191009df2c1f024d0636caded4e0b72a6669194695759849afe9db4fe609106fe0b61ab39929f052af5ba8667939c33e53c58fcaef16ee4e520cb116ca711db6b76c753d302b62c282e73eb1d73f1260070f5d38e660698d70638eddbb09641b5a719035a69de266e3c79b73914ed06219a87053b185e61f4f4d2e393def0081331a9f9ecd07b3c360b58d7eb65fc52c3a0d7a67665db20c10ba283cf9782fb3498a0f05619f654c2a32fe81a94b538c5cb64aa5dc3111f6bd2fe776bd0b51df859c9b99e004eb4bbf6997fa525fe662579136df8ed437b8f38ab908242c7322df280be7997cd6b2d42af382ba241d21df5c4a7fdea4a49cf8f43a53746cfc0d0883c79f4cbd418813b9793cf07eac2058caf13c6ae002b286d3ea11e1c787b36a2f851fa751cbdeab6792331d73f1952ab3057f90f9a53ac072375100eb1d678ef8a590357d05e31a69dcb053b195923537ed5c29315558e423e42e93635682a4800d03619debe7d14f98719d02bbeab9c36abc08868f8a7304ceead0a8ad309505c00a522fafa54481d63a6e21b5633a76bbcb7e90c0a77d8e371f78aededc7e5ecd3751b2cc35d7321a848e998564db4c3e088bf53545c65c00247c16975c7dfee483b18a08214a7b7e718c643d0c7a544b4a9a4574246cdc690cf18e38252f002dc40cae4df8d143e846889f4d4436aa9734ebfe0f289ac9c3c2f2366ceb8a5e4fd0349acce7cc8495093d26158c1446518630a3817520cf9b967f581809b16471907fa0879532eb7483280a901564f1c300d79bcb7695c7cad0922593269016021b4787b5fe4ffd591ad025101ea3f1ed44c5168464ee48836a3f68cfb0e79c9ed8aa36748a82aba4c59c558b1889562bd2c710cb4adb284e274212076b27459b14a85c8c58266ad5fb104d5447364e9d1a982afa925dec463268261450e036e185526270f0ac11a9f903d8c0133e94f107cd29d9f426aa13ccde7e3f6321587227b9fc0868b245369c781068281e849aca88134602be08ea4fe1ce27f43f398570994ac88c067cf2dec4744aacd17097e909d54d570737d838308941ebb891f28159cbd4c0c82dfd4e1d07e672658c5e851c3c3afb6ad2079b81629fb8cec94385742b6316c2cd72cec9b2f27c067d63a1ad994b116cddf74e33036bf7da44ae3a68a4a0e508447955ef06de3bfb8c12376f35db2290a638422358a78eb796bc072708bbd54bcdf96b27492f1989720201c2f651421f1013e5b8096a498047762db89380c6e753bc7b5c002e957d245103f8617283340d3c881cc4a074a082517e73f45882c7b89a1f61b1f5f8f85af90b13050afedf89297831e4afc3216fcd6ca61c5d2cf7867d186e2291acf4de9cb788767d4d7ae3d62106b747175322cd6e48a5972427a58fa7e7fb8e9c37e268dcb4f2d50a6e94595154a14a4ecff3b65bec137f663b9329ae24b3c9aa6b3b288fe974bda7ceef38b0d228862ec59981c3c2bfdac0fd62ecf43937038d4b4aba51247068fa5dc8f41e80e799d06a3e33bcc11d111e6d329ed7e1c42804534d309f97408aeb0b1c49b41b518b4eb4f8043a02c79e44b6bae287693e982150a214003591d62dd6df5fc00182c0f73adc88c23b2de3bb1b855e349db1736aa1b5618c988bc940f14f96244d463af73fda80fa108d0e4e104524bf6d2f24364ba431666a4d712b63cce4d0e2a40e939dfa3968d5f3b08400bdbe627a3e374a92e6e0bf5af5c03e3d5797f3b62803a34ec8bcd8749862f6e62be2589ca43424f40c0b7b4c4f466f796768fd7bb0d094c1877f2e8efabc84cb45db7b710d8f400e3840d70147ee5e96896245c80e407c39b2e38bdce29ead73e6280e3d14566f4caef6ce25f0490f9303410937b94d6fd74337d4dff898d6eb2c17aff24c32519733e20a5afa1559064a530b498b843634414d256b51d8f56a99fbd9ea442454daf20be8fe7f78c230974011e0527528cd3a8b32c0b2d389d604c28be9b5e884c69a6e9aa121c7def48e9c388f6b905ccd7de84ea543f41f1b69d856593c7f534bf1a806bcd0ee2d276171c04c3838af43f4c45dbaeebeb0bc48df8c88ea407f7a427949bcba1460cf33d0f6f143ee0454dd95207913d83eee76a086fd5d3df345e8865a55e4e2aebe6e6fc5af04ce150b1cc3b0758d9e46814f11f7a001d930f792c20d6aa8a32902bbd5844658da2f39984f1759ed6c7943f90075aa4fb0fd4cd6f12edaf44030ef2f933a15fb89d12c782ec9f64a88851d0b27910e12d46069fac2693e088ef4e175fd32a6341dec3d9480fb0d559e52b58d0fd6f6b612f80f3f6bcd8f55fd11d02273e06827a3e4c06baf314bb18864c387ab42c403228d3c323483326144ebb5546d59a15d64a6c406e99bee6c7da6117d2f72df00e2741c04b0a43f26fcf7a788856f34a38bacd9bc1ee4ae080aa4e920110da9c6ff0b3a754e8eba07924eab280d2bc02bad23318c83264ad061543e81d03c0a667afcb2d420b39a6184e0bfecd0b8e092b6ad23f2e201aba1d9853a8e4d40c8fe8f9b9d48befe2636bad21c3c20c11f2db695aad06bec4f7cbd5be26eb5a95c728d21b0bac218c40136556dc392af6e60dc6bbbc689ff94aee350134d03ad3e161be99cdc466ded12c08223fbd236ca5210cf8e22cb4aaf9943dcb60a3f57b39923bec1d15b8608d8559ad65f81a0d7a49b5f6401aeaad8685f805595e1806f0bd9216aa3330d1ea7c0c5869fc3643271039f9cee5744e2a085b92df2656fc51e91f2a763bf2d335e860289f879852d2b801a01f572d38bea8eac6d8d9c89d39129cf627119527557f49305ea3830d64325c36e12332b9ac08c1f8dd1809d0b2628e211f1f34c24a676cc3e423244f8dadb212c02d30dc2e73397c651347ba0b993fbddb871526f9e031da6a2e72106a0608f10473b6929144a83ecc4dc219986598d8d1bc880994eefb8e68b1edbbc147cff50227b73d984710f6c8adfff16052113c4ef6d23820c9c4fd1b08d06d15bb5e0f37264de68c80cbf3dd89aafae57799361bfa830bf437048a8f7fb45a30d815271d7ee7a45f5a478caa3b769a5db755f94f13d918d9f5cdee5d442354dfb6a7f6ff9f833ffcfdbff3599b02787c280440f128ce52fd5ba999180c2ad90131175d72689e2ca2be21d0b7d5be5d6209914608217b6fb977ad0b520bee0a78040679c107638733eed178bfc6cd14a33e3b1fe6edbbf34103a41dce00cf02c60e51a71da2c02c244bbcf2c3cab515cd5ef44d7435efa29166ef5db4a25d9ca6d97b232d53918a06aabcaaa8884ec12cd25e2f7a48a485eef558940fd8bb05816c1344f998b79fb71b90ed99b73dfbddbc2b9acfb26f286026925f70e9a39b81c0a3166c6a09c354ea58746c59b065c1a294c75e7d58143bb4262bb207ad358940d247371dbcb15526907b7f74af93bc7347f13cef1998b77b9b7745df62c783ec78f03c50747b479fd65e667ab7b1bd993b26ba771bc74f09dbf9981c18e4056f60f6beccb458bb98e9f6f7c416ed049bd5a1086c6e56af96344c6cc243a6274e0d59b0264c6c1d232d73b3586da4717e3a07a8758262fa26080868dafccc9a5610eb4776fbf48d4fdbb0baa6a795f3a303b4233f593b3a466e58467a6e78a48d4e500e10cecf8d8f4d6e566e16c690d08cd0f9cc286270c4073e34c081028b0c1990200738603981851ffc200a168ca298620903f022053b602c410a2e48c07282203088f18530e8200a5140418ba2496a490c1645866957a5339351582b0cc10a3b50816475770d8a02e7cf0b7684e3155638410eac70044b6b1610412c4008118e577411d4a25e140995c06e610a5d58e19986e3155d4401e7971a18d4200a4a70b71630c0a26a8102032a44358c1083459161da55e9e49121400f06488266a405c4c462f852bdfa3bebce341bd88ae3155d64f16920ab0b2c5299076816c2ae4a594004b10021ba0b1fe0fce19a0328c4985e304d2ca610410d80bea0054f1758b0021d1c49228c9b2337302041080646424a08e178451738f88991ce24ece870ce177a3a315ae2b82c0837bfd880f064f082638c5c08be2db4186bd6355a3426e6e5250cffefeb1d7a583e3c5115df3551159f65af117b583e3273364e879d14158bf1a2d735bf5cca4e33f0f4ba61ca892c9bf3650b8d67461eda6adaa22ddae2993059abd5d362b5aed684c932fb87216dd116ce84c96a6a726a747670ffaa993058ab75d9b4ae9bd665a43561301e9e1f1ea07ee59930180e4e0f0ece84c1aed6b76375b09a93fd58a0ef0aca5a592b6b65ad2ccb329ce3e064389147037398693cb49aac26abc96a5aad568b8787870727b3381d2b563361b41aac06abc16ab41aad46abd16ab41aada65751e3f17cb063be6434eb46603f6996659719a533dbe1e9a93835bb8c89797909c3ef9065df97655996cdcca7f503d4945299655946474984b490a531143d8a8ab021cd1375a20eb4541cf17e030b2f440516da25483d2fc8fbbc37b0f038288ab0c554d658b84f43dc6d2974aeebe6e4e6398ee338d9cd5819eddcb890d6a5c266d2ad6ed22b4fa705b3642fb9edd361374b0acb653a5d6b986055603ad81418126ca7438c074bd2610fa604637588618de5e8000a4c04c519cbc9c172705f63f56c31656f4b72d2eebef2b5e56cb25df3e32cfdbc341ac0b68b460317d6625f74e688b783bbac58b6c1785ae8f12fdd23273bae3bd771de46e311d14537a51d61b90e3ba485407a81a956f55b602fb0648f883e45bfd1936a5518765efa00b274c83536852da6b20808898db98160b266d2a457f512fc7007559fa9ea571f1a96f85426b5d561571f2558f90eead57c2f2182e2dc4199ce8eea3361424b5ad567d26af2e304e8c9436384215688d561dfc38195e774268c88dbc1cd855813469465d67edf1f862f2f5974833bc4c27dee66c27440409c11201ca01ca009d3b158412cae86c5d9b0264ca7a3e3a3d3d2d19930ddcd54f5b31d9e1edce758dbcd84e1b81faec5f97c391607e7cd082b13b130114bc412ddcc9898979730fcbf2f8b6e44749e5220202020168bc5d2d1d1d1e96eba9beea6bbc1fd21ce01cdefe3808eab08c83ec124458784bd4e2f5538bc816d60ecd2124baace39a97763e5bbd460920e12593876286764d329b30e2f5995a001851a042d1b5995efe2a9c293061a00ed59e489943e3ba6d10c9c32f3ca4126931d58f9234c291c81f06460e5299d194062ded3e92737587f811362d015c1c2045814c162c698c9af3cc17221ee5afccb0e8ee3b46da39178e366a557866911e8a61c2b8d84ae5c42cb81e5b21b3d4b48231eb025d9538dc89b2d58969b8f93558b493353dfe3ea8e6626fb6be963f9d65d8945b7c670bb6601ac5d5ed48134ba6c9bf670db429a065e7ab3d99d6c30b6382f5a6bac97b44a0905235e09ac8c316659966559966595eb32e69c73a6269def10c4ae2a6f08a3cb8cc19fc082e8092fa09cd882f6440de909139c1a085b2ce1c2085d388207070b430461a8c20a181c41054fc480f444153409321c78820c8690042e244187081240f891c107b2600227b678420bef892d4448286d618302911d64e1440b142811069b1314410bac248e2843075d24f901fa585ee8428c2b64210a3308810ebea8e9809223c22003082870c2e64ee4e0bee2084d4c011b421264702426d81713e7051fce0e48da0e46385ec1c58e86238252e774bf800aa3304213052f608273c113d210b617844114bb60c2929a31961cd1f345fcc217a8700310e0400ca02cbc408b5292177cc044b5888922d33829444ea2f68398182a4a4740a941131ed066f4b800085f9842167aac2032832ad840490f7a10460d6e78b486f36444b32802d74413d9771c26d0a004f8a8108424216041ab0c1e0514e1044d6a82f063b3842662903561839092264ec0c96eac0525c07d8e84e3155c60e1154126663c502cb12581e205251a2c0945e1a4834c05c72bbae8c011a2f6839818222920c2132536458270051222d012b670e4270a4048e2880b96182571010c6a5023acca48c20c98c08229e458e1c38e912435c042055bf0000b5113be22b4600b5a0b825868a079385ed1e40976322704a49396d42706e66318569a188661d8b10de3b01f260642434ed88e9c62c71969e442df36d141d1153fce6659267a3c62731e29a1905e9562387afc3204e8e9f11fcb23277aca032010640239d86b4b41b0c74da034b22321a4911dc570641f47d6f352a20894d9820077435dc112a0876e061382e5b2d32540abea086ce90616599661599665590f9d8f53191dfb955a73a263fcc0e0b26e2cd258639c36731ac1f11447eb9f06eaa05993c99898979730fcbfcf5a6c076a43690fcba785e5e8ecf05cdd4c635de50fa531a358c52e0c03bb060251159b06142c10ddddfd45ecce00be24290535f6c4b26b5ef3026d8753ebacb1ee9e57adb4e71259af62f7638992963e68bcada47b3a9c734eda2c11e08b07f4999c73621798392c3beb26aa0c54e1c6ae6a23ae3e035313a61da6af1146bb9447c5e822a93c06e64feb1ef0000542c02a9cc29a4e51658cf790b039c33493b2524a834c91e433d24d329973ce39237d965936e5af0ccfe59153cbe608e67a66c134ee88305fce01d3a7a2966197d22458a6675f5a682ac15a5f679db5e79cd4524aa9e4f024829b7ab1cd6b5e5536146aacb17a29b097974caa8c466059af959992524a9b06947e578c1d1ec340db210d494d66f232763392528c088a2b48e714d78eb8c2d705e6ebbaaefb7518ff0169ef466073769d070e5f59965d57100e7fd7955d1a88f2713d0bc2e19a51f044f016349858f9f8fee930e63e9009c420e04c0408787ece6f7db386fb1de670087737c1b14f2ba6fd9bfbb94edc59a63a8c1aceaeef1aceae8ae9ad14b3988633ec5eb4629a584637336995b45fafebbafa327d492c33e9bc9e2b9765199df3d7cd1d05ee67ddcc3c0cb29c18e0c6bae6e99e66d52e426593a0298bf8b47e805af2f4b0a4ed82e002001c3f223c8b7009d806a52d6983b3bb1bcc73ce0cbb404a678d8d498d04496c34de50639c51a38de80280d0b30e3812216681e31270dc02c7cf99045f555479bafd071b80e7ec64f7e3b5f3f128291561a08c2ef594f6051279aeae486c9189cf920e594a7a92f05441c5890a2bbf834487ca981c2870983042e7121dc66f5bec26bd349060e5a9108a670f374814e950937382d6fba62aca1a238ac02e0cbc2ebd402b64024120f08021a6100b984174186fe262b646b3d9dd9d4d3a35307f174e8ece4ead5ad7b40d8ebfe26b1ba1b1e79c738259d3a4a669daa9a6b57e8082a6c6d3c3f2e9ef03bb1b476a9aacc1f1f75e9ab570fc4f3237023431bad81fb1398f011c190018624dd58dd8bb3c6ec867aae823401362459790121518ea89d828bcf77a7b5578519409a650c0b1bb115ed40d903e015327e04d763d324c23cba03e387635bcb40938765675fbc7bbaa4b84772113cf00f17ee3b1fbc10381d467f8c6653aacb737f310310d86551f32b10acc15a4c170f81be0908943b09d7498fad67136bceb668800c0856478c7575f5d1296dd0f948fd0611e3acc63bec98e8798ef808233f5ee8d1d6e967887e370730c02c62154a416e9904da8a6431c2ed39b6481cda11e27bda20ff5c41b62ce739e3355f47fec6274c141b2260c8fd3bb3c4e1802bce571e6380106c003149d763fbad7ee0798cfae470ec7e15b1c2273fc7a55f7ee0d9006c3378e6fbc3418f6c25037a3ba016689bb1e3a9c4696c183005ec39b6fb8ccdce14601dc3c04ec9f0e53d7e1d260d88219e61e4883e1fa1c628e03d84c3a4cdd23824d3d877230fd0d371b816df876f3f6f0366e96d8c60370733ff101e631a9cf8e0718303464e29afaea963000ee8e7b84e8421fca22ce6003f8a9c0d60072335f0b6c967886c70e6978ce360f8954c2e6c864f3381a6f503d84044c9f3b1c433e98621155f4b97a5bd81ceaa13e9149ec50f51baf9706d5cda5f06689c36f2fd7fec615e2c5ce8440bc976efdcbb5d93be9374021c28e07115681a19ee8426fefcb6b68c17244f8b0db4960fc8dcbf4d6f9d88edd63623b7a217ad53e1da664b7281399e1a27a342622a424bad0d368a006cff01994d8d46df4a06c2966aae8a947a9bdcb73f8400a3c4375fa0b49afc21fda8375802e60ce66bc05cc56063007384375bff0b284c186dfd12b1ba70f538fc1917aea16cc5fea1e98fabc71251e7dcb31e0cd2ff7e6f0970859e3661a37779219375b969b230feae6d85ab959d6a8dc2c71be9b254fcacdb275bab94d2a4098966e9e00d64837e620fd243ee9d5751ac4631bd5d0820de14cb1778abbab20d852bdead97904122a300011ec8141ec2551f5118758a80a461c52d221fda5c21641e00210a6cd049e3a1dd2504f87f452847a423da9774861280f9e78db1de60306663d51459f65a11e5ac16c433d2b3502e804e86c3195893cfbaa6d1dd6dd963a9acd796d9bfc9c735e122588db83018018dd0584ae100f80c0bca612f292b39b48b84b80db83012e104174d8548273878253a743198ebc45b7d7eb9697243c55ec20d149c253c5ce44024e9d8d76f737fb450476931cf783b76d9352ca21f0bcbac76e9e7bbd44f0bc422aee38ee66dfaee64447666a9776a8043711b48f63fa4f753f87965ecd3975a6aa3fa7ced48913bc46d2b3628ba99c0284e54f97e9eff528a1995047ba2d91acb5329d897a8b7134baa854839edc969834f1ec9cde679f46565687b2fa70613356af8ca4ccb84aceb0caca6bc8c2e6caaa711a19a9d5abae49afec8f13a05eddcbd72741bdda5e44df64e755d6b42140d6c46709a9f563ba99930ce849104b7a60c6eaa9846459e2c3a4c35693ec2763f520c36a69a9a7d7b8f9346cb0fc8c9b3f969b332758febab90575730b5eb94450ac72f3c60496ff4e5f89498bb524746ddc7bc82d0ce9c3a742fb89c096be1fa54f13ca870904fb0429a6271d05354f51f311934229e5930ee5b4893652dcbe36e94e24a6cdbc0181bdcc84993651253fb2de08c72c9294813b07192bf3c998b43a6cf2e364dbe9db4bc0607f7a4599b0a43aa94cb295b3a7cd54c9db4c988c5565a6854f077083ac9cb1b0fc290f9902a44203acd4216d9a1e3b1e38ecdc56fa388b61114b1a0de05229e2524d8757119425d8f8ee229919e91513bdaabfbc2ca7575892cacac1098bbdbb77efb846eb9b3953759de56349efcac2137b28bf5e32729de4c47a67d2ab2c6462945b5b915850a7c30b090a5877588ed81c84c3a573e7aec4a28c9660afeb7afb7478fdc6c0fe7ad5c9aa8e5775aa0ebe3c9c5e79bf5ea1e895fdf59a6302c33a21aef29079bd6e116fa0c17006e621f37af5893764200d8643e0925e5d95d5e13577264c6545d5f51d7c6961871d76d8e13b649939f3aa210b2bb178c55859132606bb8957bce215afc8c232def8d8b06a7a5a39d815af5f31c6eb25a0d17683e54844422171b72592c974996e1a894d328dc51863bc1c8dc473939ce763433f37ef9f76d22ba0eca6574b6446321e2c5f9974d5a948ea0ee912a557a6cbd79eaaa4b2ea92ead3abeeb936c1f2c7b2a399b9de43622cc699f84d765c8624cbc9a0c8a6c874b29dac8a8c274bd2614f873253d22a79b904736f2991da6a7ab3e950665564507498d3e1141dea20c9763aec0cc70a3bc1306738585e86233673db8d56b3c52da3742e51d24d29a594625d54d993d65ecd896599d64a58180bd67ddfa569217995acada16ee648ddba4749b3ea63ee9f7b4ae7f6a45a91e43fdfb192d6d9928a7492a8c29e70bc428c26e01c794236c82e2e963085cf6699b5359e7081052c99cd380b464eaba2ce0c183b34be275cdca0c250240c48ccb04f94a860050c3e2c4f7860029520d493263e3178569e20718294201d95309ce09cc2e0f9c248c20a4c4140296104a124c6290c1c908074630a03c7042863d894c2284112232052f602061949d8cc669cad99a2470d1214fb92797102ef25e665474c194ccc9401455b309e50021d2b96d80143073740603c6102303a8033e3859e2fb6b0c40c188c7cd104234f6e5430d3859b2fa86062860b3b5f48713343c6cd172b4862260c3f5f78e0043d36c002a2c213335f68015511c54c1835402a7862e6898f8e2fae8a4d23d785553afb65474c0e3a70b4c24908a2c08556d7d362a00077bfbff0c205672e39cd851bdccdd38225ce26108ef12d2b940f357b7dc4281fe8b1d3c730aee25951157db296fd89aa88817802e8f86ac1f406a977023fd644046b73a5b0b789aaf92cbbc06c373a42409122178dab0c3c820a628581475041c85fd7ad210b365b3c6d70ee1afbd5643986cd8401e2099da88a3b31b70d8f91277aa22a62201d54cf060c6cb6980a3ec0d900962fc51b68c0f23528b1f96535e30d8de5770449dcff2abebbbef40ff13419d081bdb40de617ccfac12a769d4d6577d3a96937bac4635a379dddf39a42944d7bf5bf5771d22aab3652c1573ebaf4ffffb4e514fd95059a13f6c2f10a2013b4803a70edc05a1cafd8421846c8b62b50a1c48c173757c831c115545082192bfc5ce1034af878c1052578bce0e2a60b2f94a860860b1f2f729082991f235e1869c14c17412f3b6272681c1e2b4605c216b8c03973c1d18a2bfc64ac2624cd2c7e02d4b516427072c9ab9b99320b210880b6168ce0d60217b8ff6de1481696e0be0e234e664086d5f1440c58a8020e2721c0f4d336810527303da5385811348a269c391e2c8ce00a59e02260afb7bb496096989481c05d9659fb7df9392482d35d0188b4e781281fde4fe7c103e989e06dce8e07efa5cbce87377a8740e04d869a1e47db06e6eef129f794c308b6444da37975b7be7473e8909ef49d6e9df7d82370045a30db2f7f1db78121f08b1d0f419aa5d49714763c1e469fcfec6337e3658947398be1d9a69ebf1b22119883bcdcb8366eeac670c19b87c09e2813c1a3d0bb4ce720b0779939ba127b1b58badbe8cecf1c327a28573b1f8d475ba6726de5333ee32c47d5b0df6eef7d13894a17bd4bf9057b236fe48dbc91e779df4657f4d23d7d93a713e863f4ef2390e5327dbab28788b9933e8ab847d75e9eeee85a992ea5fccb5ce6b0fd4ea5d14db7a543fb94fb5454894e25d1472d1d8a2e33edb5ef6e2ebd5f80db5fa62de89dfedebba3796b4f830c9b68c5155a58eec0d2873b7ae9662070e9b5fbc1fb28cbacfdbe7c5cb2cf212e956427026924a600101a892de8c39ef48845df9a1b5dd1b76b2de9ddcd9c6644b77703334a04168008b68f18881ce40557a006b660ca3bd3513e3b1fa6a35c76a79ca58cbed153463fdd340233105874eeda92112cca43fb2f4c99f6a7d0821908bc957ed95f5d0f12ffdbcda35ff0c76f41203f0a0884c6ed4b37c84ba492a844427d9fc874292c9d02a62d7cbacaaf9bce72db860a2b31e5a191e870d2b43c64e9d564a14975586f2c4290125c6f7d49c483f4be2cf7d1653e76a48b6ece300924827ec5d43728138a8585c5f4aa72539b2e8a544dd474691392746822a2d67a520581d06798f4a62450d6d38c53e9d4046622d81401fa4d745a6b251981ebe91e99f1add4348ed028b1743867e4bbb0d4d37f473de5f943f5f77a514deb5751278252fa150a02f99ee195eb3b6ac807ae804326be4014d8fce127b89bd26ff13b81cdb3064f1b8260b30d4c8ffa7514e9116721159b6eff953e4b4f297da5f4195f0a2caa07c5df7d6800e70ce00f8cd105854ddf48d76636dcc09248263023813e443705893ff19b3535a7cfcf22bd221df5c19876e0958f25a58f859e812d9df4ef32c1f9baa39949790f893f94caca7b488cba4cb70df77d9f299f97467a75fabcc49139281f289036dd74599e0a5b4e7707aa91b81fb07d03b64d0e19d8124802730b102ca9f076f7a5c31c42b36dbe960ed80bacf4fbe8f7e195b6f1b38465003973045b4d60730cb673d2d6c2662e268b3de3b444708c0c0c2637a5a0020b98f9c9811364d7ae85b2a99ac084c91ed240d4f753c17e888ead982e88e66104111ee1c523a7123506d798a9aa8ff4461471123281d3097c406631f5130c84de747a4fa79b4e7fbaf4d7a5f4b18b725641228117ebd775786173ec993ba73b7984e8b02e2008206a0f24148974fa05d4abc656dc5c3e4ceaaf26d7cf845179fdf5a4fe0abac6e855bce20b49703d56d32b89ebb122f5980de9745dd7751e1a5f32321d56167c95388c0273b1a6aafe0aab4c8735c7e42083728760cd672430dbd33d1f3b87b8a6aa9ec014d2af3b733aacdfe52750afaee797acded3a6e870a7661605cce14bfd4622819a4e87f52750cbe9b05e0625b41c5c7f2db97c2ed6119b2f16f72b9f7e7d3bcd9553de7e5df77433e9282512e9a35fa7d3e92730cbccd1a531029f4ec717cdc4a7232bdf36120a3c82022f9fa95ab9576baa6a04682e9fe8722de9b05eac0eebe9a5938ef2eb843222fd7451a352e927d209a57447449c4ea76f271008e919de4ea4a38c3e64e2119849200d864fdfc021139f4e0003f4eaf4fa1e80e855e9f541f40a65f47a217ab5bd76df2877baa66f9be4aeae479fc0dc4f4ca7dd95812930fd9683e94750607a141c4c5f6202d39f326024034b607ad2bdc1b4ebd1f802e315bacafd6a0eae4fe96e8eadd88408ea4d2020a49f6ee8a71bbae89a28681fb3ba4e8fdd7592ef4bbe49570213478c6dd7b65ddbe995406461205bb6f18a2f28c1dd49f4f202f390791a0c979ef2d8fdf0813d74583f64e212573abdb3fbd19df4ede226bddb5b96b039c4f5a257efdce8a6d3af6b3abda7974a27ddeba64b8361d36937733281595e6696480f8d4e2f3a290f99985ef4d1a5c13005b37d0fbde22cbd5dc4d84337bb6a965d2c5caf8a02b2f963e955c459dbc1f555e35931b2f5e0b07c4c79486cd7cea9391326620147a75755f42a2ee955bcc20b504cdaea02193837125cc4c371b283733bc1b995e0c96a9f6ee1f94aa3cd44a25792c312ec9c19b2b0b1c31d1df6ed1838a7733a9c6d63a7b5b15c186c7ccee80d09b698ca590b4e61165cea1eb19f09d3813d46abfa1c07b495b0a0104b0d6e1bdc6007c5cc88043ba8c33e473b88be87945792a01e9c6f4b1f4b87158a9a5371329caba9cfff1b7c051b3b94427af6181dd44f72d4d8f929053ccf52a9162c200a86af2429189830670d5087f3c93b6c2909a1b725db21865d1ff64cc5059b1b68d228e0f98944bc41e29965df57636c4a81260d1cb5587204a6375e6b8ba92c9373c2cca067803d3e0ac15c4604d3ce87794c3e60889c1dd12e4487127b83a80b3c127a4d69d74e55fd3d818de9b0d6cba0034b8f8110e85036ce18c0580f0c63af65e007597b81324461f34bbf3ea62a0824f2006d368241faa1c41e4002e72c9ce245c8c47285525a4121934ef92113cb970d6c3195576a30fd579e602b89447b72342c8574905c97e7813dea3d09b0602015943ba004c1607b8e60e11cca31d2abac02847182a88c3d459898c248cf116360161c7b8e68610fb470ecf1000bdb80638f0798c0a1291aa6c80c3c1d39146f59d6cd7014f41e3e76332a1c5c3dafd6476c6ba80a5f809e74483d3013c92cb85a0bc6baf180f2d1611ebb202c8f19de436298cb34e5a155d01d3a05d56175489768ad0e29939edb9292241dd26b55744871a8d78687c3a5911a8f8dabed8494784ad8102bd4a3eda838c12d2a4e30d580a66a49c867c214e9008f1f711e33f04edfe5f4ca86d37753f46ac7e93b9d5ee170da0280875abd92e1f4fbaca43d51d5f9b0f17a95a05e5510e5838e7a1da0901fad0274753eaee778ed6672809946eaf8f5aba391ad9a9a1aac03bcbccb52031bb1918e5faff70ef31caad1e1e5d0715139aeeb3a74783a88b8aeeb362e1b33d47b3a3e64621d609ee136c02113cf001ee1716d27cbacfdbe873b98da67ec06d37b44b05cd8eea657322cd12b1c8cf4ea62a2c351b9a1f4975743d5aba004ea90ca1f9b1b5e431656000f05f09ce15000cf16870278fe70f8d82a55ab540ff5cc9898979730fcbf6fb6e8f0fce1940ecf16a77478ceb00e4fd1f01b376878b6f8060dcf1fbef17abfcf5a19198cb7e3efb3f6e5e51e13209ad3218b4ed1ab9f9eeaf44ae5f41449af767a95e3f4b48a5e7da7a73cbd429dd24839bdf469399de194e5f4d249af5c4e2fe9e5935ee9385d393d8f2bc3c5e1963abc6ec3fd3abcbe6d5c8e6fdd0cea5b4733f3bd87c4392ed31bcb655ac76337b3a2a3e5d4725b6a9961866e6686cbb48d6ac37badb536be5ee765e39e776db2830163871798596e37e9b03e763d76f8f57a95dbad0eeb73dcfee9b0febbeda4c37ad46da00eeb0cb79475589fd272b90e6b3dcb75b92c1dd6c7e8b8a90eeb576ed83336c0dc4f700547a7bf2e0e56f7e4fea1e1ea70f3ec993f985e0037539b1e1600dcbc1569c12f376f36981edfbce5607a999bb71e4c7fe3e6ed07d3a76ee66c329783e9c39bb91e4c1f804bc48eab5dc3814252141d2455f46a87d0719c5ef2c89e2d0761c1f6389e4ba9c6f6a1cd99570a5b308ed4a5913804865417c7d5803aa413c061b69e05bd0960204228cea457d0bb2f2f540c208c711d62a2c3909111ce1407a1837eba6d0f9407e0a91b80dfb8116f371dd2ba4494692d480b32e2bdbed4ab1a3ec3ab91a9a2f51a50d680307da20575484f030d7fa90f5f5460eb4b88060d254858a19c5e6515273abdca2a41a11c95315482a650828356378fcc6d11ca71808d57744107d7c0f18a2edce087efe9c00f9601c72c923082b738848d5774a166db86c0048e57044181e90ed692504fafe2155d6882e9434a7a2531e591434b30e5b8193a1e6e0891d803730570bc1e87639c753fd40be02a4f7a2580d3ab00a93809d9846c629e7570790640cbb34b8e671b3a9e67c8f06caa11a6deb0c32b986d98b0b588cd0d377698fa0e17eb7ec05cf521f0f163c01c83ef02e617fc163087f839c07c7c1d60fef065a0b8eba1c3f1b76de364c783cc431e6edcbedef0deb54fdd4c71eaaa9b25560d91e9f0d26038cc5962ef3233a5ba0d979938dc900a4788890ee975088f7fc3fba6753d645eb10d6f37b932de3dfa1ab2b0a967c94a9da7e7f4d8a7a79e82939293927aa867c2c44455ea34a61e434c1d7c9ca9df54ea32a43e23751d37dff7a5fe3d7595d48f0a90caeb4d7d25f59ce195d45774be1c9b4a1d85e3f9c32c389e2d66c1f19c6196c77896876a7ae59d3eb48a9e0d1f3b1b8a98d80103d77fb6feab146ff5660ff3c032af219889e0f09ef76aaf3a9829b6b373046274f1c06cafba71698cc0de65dae2f0d24cec1de1f12da6d2660313994c4741b18172329d4c26d34d39ca1d813652c098ba9187ccc43a03cc380bd6f5d0279d7ed3387b4fc7ba03483ce3decda89fc01c9cb028b07b8340669c050412834a4681415af00c9004e6202d3886c78e01acf1fa06f3fd6b7cfbf61aa86fa81a2c47adb01c5583650585a24183c6b74b03d51d8542a1cea1380e6052f7d0bdaeeb48dd26b9d9f5a05d105374922a2a2995d148741a753328301781519799a84b53840f0c03e98e65df6487d28181c90766222d3908cc1262d4fba530856a168cfa52be920aeaad02a6dc54baa89414149851cef2d25325d1572e33576e3ccbbd8e7245ffee904a3b1fdd49df48b26340ea36bed9b86cccb8f72d555554522aa3914a0b26ddfb8c9b8934b68db78dc38248dd46dbe0b0f72d753f55b2fbf1a5ac3ce5a49b2797225da6595858584e04a350df572ecb45bdb4725552bea2024e25e40c29ff6eee164e79ca09a41d8e4a37c760cf070d04d25d661118a4057760e8d1620d6400cb205af010791b1c83623fe23c42d78b9099d9a5d7ae872e6d005c8f19988ba8745e2d99606becb6d96fde5db9bddd754fc9b8528bba7b9ef7bee5be72f38813711d67bb7b1e4af40ecca81fa373dddb07d73de222708fb8eee6ae039b0381a85c040249792764aa74ddb66dfdee5bb76dddb675dbb6795b77db45e9baaeeb8e6dddb6d91aab8542a15028140a85ba51a2f7752f141a755dd6dd9ce16ed475592664666bf1e48860532f3067d9f523d79bd04a45a2c3cb06773f32305f00085fc7ae0ab4ea4dbba0de9081423afd94556e7a49b47251ca7c1629379f45caaddc823948bde12ee23e02ed45a3afdcbc8d54462a236ee5de396efb681b157101a06da4f29591ca4720109577209094df20564504a63cfe2ba59c48a652c95a12e9a193481c47e2442828280f5d144bc6766ddb36cde3bc1c9cb0ddbd9b83d41b118db2fb516f303712e56a83bb7ba011596fbc9c0b00d59b7ac32d81de2c84c54d03f3755dd7754ddb408baf2b0aa95546489d528c61b37fd7b42ee52ae748de479b774d17914eb760a6391eb2824d28f9582412894cdeed2f33bd5c7a7cca51bceb3d7607f0461799aeee07d16d96590ba2502aae400d5cba45010b400497c03c04b68f78083cba57f2523eba7974d328e51e0824e5282010d23d21157bb715a780229023759b0ac769dab72ddb344df3469a48f469e0f75dbb9f1cc34a7b29a5fc107854038b6ad0a03163060b0b0ab5b2a2a2f27d2929a793c9542a91482828a391b59e2712751dc76d5b28a469598661d7552ba573769f9e920266195dac28ba4429bb0210f92bdec0ec43b4b010fa49138fa457a6121b5104cef142fa9212095fb0a150e99be9dbf70ff5949f54bec2dd3bf7d137ee923eba568574dbdd721cbde828a291e824d4c5715784e22e0247a7a41b81b95fdd0fa35b548772d1233622a33ad0078ac80823b03d7799c98950248bba0804827a070251b927a4310a8c1d7e1fa93c7ee5a4f299524e2793e9db4d9b356ddbe81eb78dee99b68cdbb611b759afb481a5d2b75b02b3c49be56e377b6dbbec66eca6795fb05dc8bbbce78542a15048147ae8dc48488b4e22bd7b776a45606e2c7a5604663908ce23b6cafba843b9646012091c224537e2504824a25e26a21d769769eef2a1687186dd5c8411387e52215d13f1c26e0ce52270c51a9c00ce7e15813330d72af10f1eb25f3fea2f4ac19ecd822dc8e6ecccad67233d94b2f2d34ddf5546f7b6d145b9bd5c773fbc8f28606fceb0dd4497fbe6237628baa3d17d742250f4f802acbcbb4c6f2ba36f20f5bc7f28f73ebab9083cfad5fd60ff6dbbdc37793d108890892920b1e8deb90b44c8c42290c6478feedbb98b1ebb1fdd36ba59b4ad1c05e47eac7c0381acbc03817cf72eba42e60a68bfc7ab98bc2fa5f47a0fcc279389e34aa51277ef9b57d2bc90570a7123ef9c4722bd921ebaa17ba79e97853ebb192f943d14643910c876eddd69e763e336ee02d936efe62c178151e75037b6aa3b77f3f551ecdcdd0faef326127117e5dbec7c8cbaf3e1719cb49d8fd0bbf5c0acc3eef21ba8598cddcc1581630d96691aac8c32ca08c242faeb2e8c4dd368671d98a57631cdfe10026bcf3afaefd3b04d7469ff10222504cef141520ff5ccc21323a739eddab99e6d72a10e8572ef28ef6f28f7f496259bcd52ca47a78f7e753fbca3fc30757783a813e8c30492da3ee56694a37c275d1cca7799b6defbf49485c0f657f7437f64519e8f2d0a8832dd0333ea07e928de47604699401fa41116028f6e517ebdd6ae0789bf7bf7bb05817c2781404ab7416ef6c02029fc81a5c7a33a5be256ba8ee338ce7a96b39e4ae8aa7862d84b6ced66af97c228f76e16027b23b06feaeed1a84d2c2c2696d2bd9bce628af7eef5d2cd4152d8be3bc9da4b7b0dccdcadbd9eec7ed8be281fddd9f9e8a380b1436b3b14bdc1548729ad67a6a4fc5469af045bec8de523628bbdd5d8626f372cc182261e53f954c05d022470730cf07064956009892915763ececf8328fa8a354cc138bb035b4ce5520dee77a4af998d8d9dde1cf50d9883a4c2b6f1802dd236a9173c44939e37a41e5b0705e7d6e91bc84eddb641c459a2c336d2e1e49955cc1d1d47a233854d919a31829e502374097a230f45877d90e248ca449316139f25f3b14340e4e9c00ead9a1a40da9aaafebc39fe103182a56ab272880b7533df552e2955ae7bef45cda8918244678a28db06f186d4fbad136f101dc15e6f726320abc8f04c323d2cd82983dc4035beb099b278f03525cfcc94a74fa15fa04c539f18ae182e902ee9b06300290be7b813bcd3f4c5696bc2cc29faa2926219314de30b9c49a24bb390508265c0f1084440c245bc6103f1060a48524edfa4953414ad67d28bfed0160c6c151389ad9b9936b3484d8fd141734e39e56396faec89e11dc34d31bc14c3514eab00dfafc10436d3560ba8d6b024a64d7e9cf4ea49d018bda2e0eca14d6828c1d21f90b63aac21092b3fc1c933773aaca2c39ed771354c5be8676c5ca6657879195d5c543870e4c09103878b4a9583ba7c86db387dcb9d4a5ea8c8b38787a9a4c327a7404059d22634d44987f4e79257e60cd7da84b6723c9c3d53c9646d2a49030d2f34bcbcfcfa0cf4c2412f0a87a43e98366116e9904e2c4462da8a2efde622baf4af0ba4970829e5710099cf300e97cb3b7f4d9006c32ec7010e99d8059c361df675dc0beba8a1d3719976f9a43402f3d771dcf8bcb37304e2751cd70d298f27963aee911abeb95c361cb101a43f53d5b8864b81a6aa2340437fa20b6d82437e3ec7556f79a62dd595e3f2a2ae392f7348d5ef9cf3870902c9f10c8732803e326c23c75517cc39401a0cdb78080e99d806d863a0c0023d91df1276be67f6f40a451f9bd09f5ea128485b11ff4839031bc3c1e7f9c3e2805853d57d290bf73d26f66a1c366ebc87c438be852a99ae94d52b1cefd325bdbaf13ef5e9958d778ef7fb49af540fdff8ba725cfaa3ba34bc14c7a54f2e0dba748c147851a9a9a4c39e2970f67498430636061004730bc67e6ffda54da8934b81e8930efb332e65b9748c5b576eb5a9371df6bf5b97e8b08613db38b74e0a485bd7963a9c3d26b004664b0251c0106d499f0e1be35a85bd31ec4604de74dd934b38774f7ec1b9812a6d112183bcac66afae8b5eb4ce473a1f6b7a55a469abc39e3d1386b6a2aa9f65b307f704b3a5ad52cd4baf763622b08d086cb381c7e6effbbeaf3f6e53d283babc99cf957bed66b26ba6e6acf6be341a305d1a895150b650c759e9a4d5e1920ea74f0d26b0f9c3614ccd0e39067e94411d4e15252795cb744aca6d66f6433dcb6347b382571e314551d447228902a56da8e4ab576b93982a5524020000004315002028140e874362b170340ff45cf60e14000e829e466e4e188ae324c76118669031c61802080000406040866ab801c0f5ca7f2e122ca5ad7fdfd32c7c813cd155c205f4177424226a9f2df5c4c303deaea5b21d67f4ab0614f86ac59d4b8f602307e455c59e16fc7a9f7a3a1e3ec1f19ce62dfbd434c900a800e21db66ba1c1869a2e655fc0001a0b4cff8a32c1ea02e562db2baa4d10fc5818e04f007fe75b62250b23a5757a733a119ca405c28b5ee7cb4b4539b771cb2f478343c55bda17ba29e320e8dacbfb1604d05b94cbb2b3237ab26cbed908b2d33922f3a74413144705750ef692a5536b06dc80a3f27159753bbd41751979ccadf7250fe12191914fde4b5195037248124afde92e654392d41f97e577c3f826646e24d216cad09b16175d9d61fe6d970574623fe28a06cac79db2c249696ad12e65d2c083e569fc16a38eb2004f7781bfdfa44236310678f400614a0b9c5e28ab5f0ed976f94edef951a222e07aa13999c1695fd191796204e6d7cddc057e71adf07caab029f10d59ee8f6715f4a67bb811af7d17cdef6cd6a12d3293ae43a3f1ff33962f4f6bbb6a7275bfcbf0349e3d42061a985f34b9264b90e96907ec20513091061618c89b334d2e829669278fb2175657ddaf8f9418201421104fefe25b55b1ea083fa899a7203528a2396c02e53851d8cad390375bda1b190c312a305e2e0d4c209531d6c3e0ba9c5def659ae755561c277a22a6ce711f369bbd50c03d677f5e4a681764146ed6e885ed922fe86512165b3766b548f1d65db01441ecae1d00094ef2702df2c11da873d8d45f45ef5d3d6ab6cb6997e71a1e57e367231cae28424f1dc02e28f29b9a4f46266657021c3fd64da34a98e2998e88974ccde34e5b83e62b4ffb2e3a79691769ab604c0cdb68526b4893adfb82e4eefbadac55c6569ffc5abdbbba5db475183abcdd685f3dfd4ee03706eacb52c170a943e3c1753373d620f7b28ec5707581edeb2e878205d6254e108d4dee2d3540b94bb73bb38a2bc5c6f7b5798447b20006647a7382b61006d0a59983ea17d8e2fe01e76f7be761945b8ea02871f8887467f179e27e18fac718d4bee627c4a2f2548e920c8421d63276ba4e0056175033daffb5d0df65ac3fd75e1797b79b1b643d6e20787a231ed99579e37dad4ef19ff157f5f1ac44918cb2666f0be911adbaeac7fb2ae82eda0e2e68bc133c19901a37f73851edf419f044f81af353f0cab54d4296c6d9f4a042c020103278c7cfd6d2b223aa4742339c2342f2f95f6bffe1cd91d52fd66e4371c897c520940f8c9bd37b9010c48a001d9f1045c0228c990143029dc05902a2532bd59241c28c598d3346c07085a6cc6471f0ecca01ee20d0407a395867c024731a969ca9c5e1c8c9e6d599912c942c09398f967881648a0fc70d91ac0b78a115f569b8ebcad3e021e336ddc7ca639b07403a07a0f4ba4e8d67e32d5ad818d543f878498b403d0d642ae3d8d30c7e04f54a7051418226aebc5ace063a52efae3e90f49e5fe6728c3368c6cf930046618e923a8b6e6b11f1367563e6a764f3bb748b7acf1b1620c229f442a01a65942eb783cde74a85c868980df634d087a2006aa3e7f31962f8d8f6d5aeec2a4184ea89f16327251042f80b63f7dbc690cff61c0bcfe528ab94a51d39420b3ce531a07e1034858e8126bc2563aa76f42b9a7577c26b454efcac195ce260d2013fd089ba349a83d64bcd2abaf398de7c57e5929ecdc9b868a66062e365e8183744de2394dbb9f4174f350f041535fb4b391386d5f382082257694a6025d01fd897a677c25ddbc0d0d2064e59ed8188a71ec34d32c68eb8a58c2c5b4fc5c17df13087382d846d2672c11dfbb1102e267313f2784b94ae00ccb14a859768fb3918e6f02bb775b1bdab47936d7aef604e2d001fcf4ca0b752bd98584374464ab6d74e221cd74e30930dcf9834d9426de174e88161be3b6c9cda57b077aa71a494aa7189986b44d35efb3f5a1e26b2ef1ba3a77db58f196b96ffc5caaaf6c62eb90638c446c898e48c9a15b74f70486035c1b4129407062092ce0f8328251280f38e801d0f5258fc7f87b366679db9a548d8db35a3b727756fceab3f2a46c2db78e4639f95a4487037be87905a48fb20ec8f6417c13de47720df8b603f92fd487720df07712fa2fdc8ec23b9877817c41d917646b213e91ef27b10ee45b61bc96ea4fb90ef81bc13d16e04f6113c61d1059dc20510945adf9d477ab8460a561824ce9e00bd6c24e217ec6a1ad130e0e7f585945bd061e099bb4c3b10037b05fbd39412ea8f1830afefa993891fc783a99c18c0e4e4eeae8bf8bb782cfc6a0436251934efa093d671157740625cca49fa165f126acc3d76300260f1a6037b87ecd0b4775d3f6e0d51ec6966f6aa9b9c91e2f9bb3d51712f6cf4189e8ad53631294985cfe0f0fb86278f3ad97bb75f15ca0843da4200d78b028cf35e7c020a834b8c1148b03c32824ac6769019989200506d307b1ecba1589b56caa3c1fe31831a31a2ccd5d19ecb0037f086b12185f6ca1d4dc46ce1ffcba7188634b36113bc3824a5c6444c7fd5b84230ff2e756a89389ec3d5e5360919528970f7f99433d2a6ad5c965061f4e08e27e2532ba25ec0b8d11f80f743f87a5a42e38d14aab48990980f0225ea9a256c1247ca192af38ccb201838546c096a9ca5c64b4530283fb35659782dfe05f9b8c513540479943c63689dbab4e8dbecf7b99eb74586d7ab79052b95d6f13a34259b110170714505e049beb37934a8d9a30af31c3166818c58a766a8555dbb384f8303b999f4fada60ffdb7e3ebf6bf862a2804cd070b15e64cef282b912020f5bb9fc8711ec627600012ee8006c34b04b0c96d730f0a2d4092d1aff07153004f9f8fbfe6e5fcabedf3c75117838ef51d0bdc70726760306b45c543e5ba909f04608915af24e16ad04a96d32b8894becb28ae4d93c3c36d22b470352a6587aee717409d6b7ad81a9a8f165541c043cc5f9bd0a7d7edc8aa6171964de998189253fed1cbcf358dada9dc77287a3d911f32d9b212657898df775c310882984cda136c391cd8865aeb59a9e0aaeab512811caf5699a7b4464ed569258d40131aa5f27a1dc29a7036848e27806b25e144b5b32acfe3a37e45e7a408e6d6ab9524610d226573543798b8aa0178913a054f1e00247f1d612b062f53c95ea9ff2dd09e44c6f700d75f3795f339f778a30e4028c34d36b852d991bde826c58de5c1e06955082841eaf02f74b58618da7e555ab6f67339681a5066c7b6db22917ffd934aa1d98c368eb8d9229ac52b85771314dccc04cbb4c8f1362336ae7e85eb1b09ceb656cc6acef46c02150ce25f7ac1c6096969168633f1a7865f7d46ca4d71e1752c75604878b82722b309dcf88f1ae59ef68c4cb4ee5ac47609ff34ccb3aef19bb28da30e38bb73d7f94b90ff3fc5d278d806ec8a2e8e947d9726a667ba52e611dd957aef47eb606d643f612778057c7ab5f82b29199ae0add0f301d32244c63128bdf39db7572aaf47cfa5ec1b963c028abd9a0f4d6282cc176cc21bf5adc243de7234ae2c27cc26add9e41b8e4872b6d2b80547bfea4af3bed414acf3bb079092d1dcb3c9cc540eb59d1ce649b3a2b0b8f0f0b76d65826ddbbc78e8ad88036b72910da362b1fa10b4588bcb0c01009270f8ae89c7f8789cebcc9a6d70d3dd90dc8fa5c416afcd469346f38e7f22f9e88bf92dac787b74347b6d16bfa1f4decca869f94cdcb1ee8646e414ec1768eb25ac69881e564b7c35dd8048cc711ecfa887d432a0c561f0bec9acd93aa2d32d48f45a05bb44b08c34507a7469ecd93d5dc1100c27dda389e768d4535ed904ec6349ad669478cddbcb3629bfe2f55735e7c8e7755de67c56aeb74ac76aa38b0971f6d903b76870c29d1aeb0ae4176979c5ccb1b1543bac86e5508f91df47c3ed8d8481d6ed473b32f0db2fed71cdfe2995c534925191676e2c9bd7ca242efd44bc75dbb557f09e69140d7eed60e7573d95de11131367c6a998ff163b2633eb4c2a47f12bf9b830a2833ea15f89a6296335b0a491afe9a508a45e9b12668ef69771ed24ed2e2d54f97ae473a213fc7ccec257bfb690c4c996c0d1f1040ed42bf323e0380666bb9e3fc27705fcddd313f6f87f344e30f5a2a4580e8552ecbb8a0d99c6e384f2e52977ddd1d34d27446906631d6967f85195a9635a54ddbd4e17514b5a77cdad350579eb44a14a72c11239b76beb06478728b627de0be93a35f5e5c99bfdee672dafcce3732a13e83eea043a779d2ae47a08dd269f01092df749ea8eecfa0dd64929c0ec7987a17b21f8d8015de90f6b40f82f43a05f8f752a36387cf92216070721494ee4894151aae2ed009a420793b88a25fc712e13cbbc9e1a7b26e87c09a31d7a5670bbda4b66def5fbc4075feace7c0968837d0ceaf37a522e9ee5b7c52008a1d49722b54d06faad06d630985f20f713816fee03f98662d3c10473419cc94ade3df299757448cc1d59a623bb08436edffe53cfab331d5c366efbcd081bcb05e0ea3d38c06917f497ab26e6a78b422a49afe68f947188b6404b3929223102cc976618a6a299925194155af0f5d19b9b066e3ebaa3d55b9e48cb85c38210f56c5c363f3a4a47b98bdb4203c3e9c30bd79c4cf8048ff67ee2eca53142c5f391e4c8244af47eb1984c856b9c58be34ba2229a8461a469f377d0a44dcd6dbc56afa6a98989ee66a34040dd73bc857871ec82f34f57266c3a23524b7781fe9f245afe4ddcba4ecd5dd9d4fb7aee84e08f12035868d6af743267f2a5f948599dd0e52c604a53cbc59d109789fcc369f35c8b22b53b3beab3a9c31bbbee082183434120f9d8ad44b1e440ba5597a5a8e73400e6e0e238ffe7bb1407aa08cfa4d8492ab4d76ba91c8967b6f73abb91b3fc7dcc0ef354eda792e5893ded667f8b6411ba8ef968757ba215ff01aa2a1e78e7b123a9753b631ed1fc135425ee4ffffc4992a17385f2023b167e8146910c8b6c7ffdc46e99e99316691bc40e041627f87e05a491c1b629a273bad5fe75a4c7a91415735a3035ab2c316eae2e2f03fe4c496936ed25d3aa188511b9e23a41c8c1ac81a3dc8c001e6aae57cbfcb36375f152e5df74e933f31a8ff86194e8d0649e78acc210c5962c6fa3c379f717ec4550901763a19322e6dbc6d58d8b37d8b7cf7a5d13f7fe16672041e8afaa72f376e9ccdce277f11551b9dfaabfb1b8381f36768e6eb2eb7c20dac143edbee44869c7488f1daab0fea9839a5ee5c265190a9c46f24139f7c246864633cafefc963d98873df41326febdc1037756ad83c5c56f57f494d0990c4db2ec535d401dc78106c468ad4232377138296359b7d5490b7a79049c0468acec984aa6c3d440422cc32e79a8068c631cb462d57901c6495e8e5923790541afc225b1774ec230b5dc533ae7667a9fd5eb02916f0ec978af4f9e861c01b4a8e2a147ceeb04f01ff638f9adcd8db789911afa08e0045081e9e15be708f90548c4a992d8ada3489db3c72ba51435ee2059faaa17f56e360451d499a0bd8ea448e90827b097813cd25f511f78936307cd46e85d44dbacb531e9302e6e12eb7b39428c394435501a37821e506a3e6ec3254a2414c8634a6a2df646238df0bd1ef4b2d2fbdc0e0c1dbb99a0294c2648971db68bbff1d0c63a7a3c2a13421cb1a910fd94cac37a0de4c1751678343f0368c026308c70fc953001ce1e39fcc95ddc34b2dba12d41713ace144289d3c73d821b86670766b93d71346ccfa49f1b35b9bb5a11adadac7413a693b69814c38c12b0948ade791056fabe7e3ab92e68ff4762bdffee4def4bde5ca3c7362b5958c18809eac2d90330ac27e02b5d19b62f2e551cae8d1fa06848d22dcead61773ed3b1eaac22c1baad088938dc12f83bb5390f2a88eddcecb63369e71f86a2a76846ab0ee328a6301db96d2bd716070c20fff56ded9f33911fd66c62ab07dbcd9a0654e6152fe621d97069dd05220320488871cff804ba8fc967f3f9d6608f4ffffdc17a7832b7563618206e11391972afadfad35b7d078461ddd454acd3e9f0b1e2b24b4ab53d98894fdb0911619140f5dc5d7f6a2b68b2d03a6e19dbf843e7d1eccacece6273008c3b00a32a3ef4308a1019a3965e6495ffa5622105e27ce519b8bb8c1d8ae244b5de23dd614ab00972e97416124342e8953ca447d0056844f87b36718265c93ecf85382cd835a67a5c876b2a1435b243e02bbe00e56c03cf065df8b7c08cdd518383125da3c1f78a978c55530e03636c6db4cf79cc067d8f5b21727afc2c14049fbedfbe4242ef64e282495377b874201f057ab0f46c96077c13e0c3b0e9b28943d8daa7fa37bb8fdae924edc5d3b30e12ba6ee970ad417a3a42280095fc865f4ae1f320f39e2050205b2a2c3e03fc50992557ebac488ef62912fe0925e2c86c6a6c3be7c189d2965d4d214069714942560e0df376f2b13b843f4a2fc61ca60802b0fe2cd2044a7ed05672d693a7141c1b38e74f5f33be0fc817760023ce2d0bc0dfff4fe8b729cf8688f2804a6c35e2aa89191b6e01151f031141f8e2364ef515b06d5699ad93ba5f288907c10b33fee0594b1e4d4684692d1b267260eeddd2e3dec7270540a3c459f2179368d2966d8a7426bea6bf5110d97b688ad4034ce99c982bd48eec33ddced5a8a1a3d14ba0316e272d60ef324f5c180aab0aef40c0ece295d6eed4e5f7db0843faaba6eabdbe0e2a5335374cc6391faf86ff86ba52194d3d63021f44fa88283492216b54ca8a6741d2cf24e17e1988b3220d13a2364af08d329b79071e50c178255e1b3241d8427956842e098ae47155a44765438ce653d35c3bb5dfa4978245554c2ebba913d6342038807757cceabf437970662bfd8a440ff7c52e4f4dc795014d30ff8e808a6f2bdbe6846b3b8ed6fcadeb8dc3cdf17092866de1a7686bc254a8f20b0f2bea877382dbeffb3ad895cdc3876bd85839f2dc3a4d629d8c6cce0fa3b153417167a9a1061272d6d3dd9e41be90bf05f9602ee89ac1f5c9d9021ce990431e38d0961673d9afa45dbcd2e189026ed3a82494e76ad6e2c6de1a6624b07bfb20138a4e5501e72ef8c501f819709d193250edd13b8bc2b0277b04c037e8d9bfefe8f24e549f6d194131d8931decb1123d9df2885b768fe041148b3ab640da86d855784c091b97eb09b098c36e08481f10b131ffb877bbd9d311dd3324352b47b24142e7d89863e5f2af87ee24e9f0fed019cb295ebed8c5f6abe437c675b22261a7b661131e1ed51d9b46f80ce6cfb42263bff4c3359c56842bc4b6d1806ccf744c0df6e2c56e93642f76841e4d473f8be23381a60a0942077d8b8d69723ce2307c54d170a7f853a60b9ff49d48c52491083cf65c5a8acd3820281bdda73ab895381bb347b0299eab7936b4217e272f059c0b6e67ee0e1d537ebe5057436a40298599f8f1ebd4113b9a44532c3d9c6de6a4bacdeb67cf0ddc825299f5da0ec73e560b401a8e6cc68aa85bfa067ea5978884495f72af03fe5c2d11347361e0bfb67ff3ca455f0de8fee99fa8ec664363b7f09ec17c237e5dcaa736a6fadfee8a5f18bb95cb00e5bfb6849fddbc324427bd5826c34c7aeef3ce6f00789ca123f87904abdbd456ef7e3731e1df7a59eb43be5af621ec25ae21a98414149e7cb2377e3d345965d59ebe9c34f80caa5d0aa8c64c274b51954ae11b3424623cc7e9e280493866bf5cf2aa6680f77b0e474b82b0e862062098335f0fe9dba13a938e909536c0e27c3d2d82cf7b560d6ea51e84fccc2b105906170a1799280ca198d146c480a5f2925c14943217846a520026128037920004b87154e2c9a9360188c1da478c4f68c7e9400a3b7f5892110b80800a22eba8cf5cc99b13f9516a5613004a9d00e07e02a0c869fc022431a995479676cc2e4bba01953e3a704c48b9f23cf92115a1c4239c920e451478de01719373bc30f5f196ca0007daeed3abb989274e16af293c6e5853cc753d44e3d61a001f8962e931a2b5d7c524ca743c5a38a8de622c73205babd838320205363d5f2b374cbd7a9a55899f45d52ff2264f385b45af2d8edbfef79e78b1b4c94aaa5126298118c600093af69c5b7eaff678ce1b8a7bc94a0c7be2073246e5693bfe9c404891114f6eda4ca8216c291a8c150b7de2e212beb9923c3962cf2c27d9513aeb7065934a88e45a4beb94baac1da449eabd11c6a13229c1a9f52f7b077e4a88fd627e0d9301fffdb087afc9346a19d5bc2419f0fc33fefeaf0ef072906c714d18bcbc81eef184227a8be9858b2f81d1f4f27dadf2f722017d08c0154f577312f129600eb9383027962d3e991088b996f92884e6fd2ffa9c058192ef244e7c7da34f42eb23cc769a87ae9e4e6275e5bdc4b259fef3d6c456e79b0faa26a54e4e8dca1c5e794932bf61aa408b1e08e81ed77310eb9a1f5144a4d62a588ce35506d034ea591b99b651cfa59ad34b52950c8f81bbd02e8c34258787f2d19662e2744d1cc38f50c4aca72deeb75f4dce28c2d94aac551a1333e637ac1773cb02cad20ba2202e5c1610874bc0850f5d79e0544c00440be5786b8473ebfa88ffbfb9a8ff4cbdef76989f509069131725649582e31bda0970cf962f4c956cf42b6c8ffbb2b4831e1040a3555ce15dc7cb648dc9d67c63085b50c3f59e9f978b5be0caaab0dd9663d10d5e157aa76a64ef2a2f6a3c7b5f0dccfa260fd9325bd10644c46e2bcc1c401b2cd3f7597ea0ca22f3d7e097de9fa282912e45891e57e946fe53176dbb0a9841eb5805a9a7c018970997bbdd93312b5314a32b1e7a4d459196ca2a98b3ccd88768e6ca92ea000b8c68d2b84761aaa57c0dbf24beed3a5451622849486520487438caa2db9c1cbf8a93487a7926ff9dc6899b993c935392716e6859ae41e98bf82703fde80fb14c9c8c2ddcbc637b88a19dce185b4bf09e3fa0a01139dcc4a88a0b2f9144d245627445a99492317bf05390e3a7cbf69663dec151b224a44fd5d9395ed114b9ef0697d07a31e17c1cd3777f49b5102bc1b2c5a8b7b57174c51dfc7749a4c2ab945e424bd257f5e094920cf8a72ee86497678db2c3bca32b23e1ab46e19848bff8455ff422cbceb03b7ebc8844d816415dd6655adc71aaefa1c2dd3b0ecb9f411e33936cced3c3f3a7fad0df6fa2f1340f882f029d668231a47154fcf5bc70b31385170c46a7e51720fff3909fb25a754a24e59d10e91804d33070b1daa33bdff39516ea6470acc07ceb7f9ea543b4fd33cd6652eb9ad67349a6e826d0c022de12122b926a3a64b61866b21bd2a04187b3a4a990b3bf9e624005ccb9d1872f614d608b8f0608782ff3bbeb82f1c1be5e28d432a5f38a437edeaf00e5eede4a6a967c22e2e6055d28ce8ac364b45000fe8e34a691777346b51d2b9e42b14c4be9e993a9e414b6681c28291d8be17ab110adf73c94310b67d2672ac02a252ed7540efaa470ec3935da539aabf2d8ada35083aa4932fa1a09174ad2363c3ca405acfc0991f9eac616e3bce00a3efb080ae5be0aba6191ccd7a432730f866fa4a6835cdb4527df4d20b58f149a1c58c814b0093d06104c730ee40b5cd73e404ff1e0156e6f6d76c67bea60dd3416686de30ae5424cfccd5648fc32f567030d4678489786f29a9c3d0b893a96459eca386db3a98898662aad51b07fc215ee0a4d775aca5d0304eb54afaf35235b0d2d67619e620abfff0951337c6daaa07abae0fc6248096441a41f03499426993901592e23b77c25d9dc53d6c329dc20c9f16e5ad07998f994145f41d0581d8044040a6d8cecd85b5799e47a81329dc424633f8bb822ee7e4d8d8885ef35d924e04b8dcfe2e6248717fbf15141cae6fffaa8438cf809bf1d7c15780407ea5339ccdcaa403999ff24fdff6fb01a90f194eeb0fc579ff99315be34d22c05aa09a087ea6763faa391821861558d5066eb597f09e4aacc7e50f0c869441c70d657ff5f5c8abb64d6f64303ea03f0366136243e490dff65dba954deb4dda4f08a015e340ce19839f654d8131db635204994bf698b80f122255a9872da2bf42ffc97e5f7c73d4315c8258db1d11913230135071470abc5daf574af83108f9319abbec6e23e9571d95895e3ab9effc694ef93c735d36d2ef265dede958bf9fefa079e7022d451f3635a6b1bab3c64d11c64d13d6f5cdb963187092f1694c785638540afe51f35b35e27246bedd008f838c0013c865ec548e5bdccc3dedf1a7c8945105d727349ee01cbb5accfc3a018047823a0d316705a29e07909785932133b0cf18c55ac9077bc6b0d6938f6bbd88b0e83aba3794b88fab30f529e5c32c619e62487985a34c81a061179bfe46e79794c5bb2ad882b2582ad55ff8cf71a2e9da75263dcc9ec38c7fd2564754101836ab17af96863dbfd355b7222648e393cb4cc321b6c67ceeb601f53b3ae332bd4fa693a8655e5147e0c1bdaded47b42e02de0514231e909769811b1dcc16bf6a421a2bd4b96ca09aa69b69aec69e83505ef2b26067badef57fd0c96998a4fb8dedefedabbc5b5e6ae7ad58247c381e215a576ddbe15f57f942142093da6a45fcd4d2dbca7848d87e23514ff631f4607d1071adda19b7a078b518508e477558b1a41d8d2288257989b45bdff86f20aff9dcf60f4389ee7c50717015237bd5cfa53fb20db4c7e6dc7c15550a6bdb0f375ac5d12fa37c200a6dc5acd8308a362f8ee90d3f49b39032fa565c07866920eeb37a2e305810d4f8ecb8eb5d9f88a79e7c6bbe04eba3ed526e6fad91aad062e5f98c20eaede60b148cc4eb8319cb1d743ec98f1f142eec9d878c21436b71cad05c65a0ea8b0af47a4109af7e37846ae6cfbb8ee1854279f5de3c9a64e7982995c4b2d524cf98cd367c9feca71d7f164778f20849daa1a263c1317e2a40ab9b9f233eeb68ef7624fb275e127454b19fde6d9236842cf1248b7a7df26c21145a05e9a8554f2099510c18f028d29dc3f72d71a6f94b741085fbc2662cad3a8278c179c050d70c7a3ba8b02884e4c8c0a7cdf43be2d62df57aff75bee538a1669bc31fc8fbbdde691e973ffbe0f1c10e53ac77842bc50021678b1b5f6ad8839ef2cfecb16a475388283c30e5accd3634bf4b6be5e4dd42f46ba9b4b20372a810dd193f0e23953a4f988341b74193fd1996d20583bfdfd024f89dca7d83264518437bfc063dafd9eb73b052f9bd7d0de65b82c9eed302be5698bd4137eabe6c425d961364d8195446d09f2093139c0c73cce8bb77639142de05ca66eb8344fca84e3580c4318988312433de913e5c90866d16fade4106b294c51a83210223ad112382f0bc4b6086b94d5df8f91184a74cd374fe2ba7340d46aa2a03de55d8402ba515a8ffaf9a71e04fa27ae5b7c81eb0c9c7d57fcbc6776b599d1d5777e1623774cee2cf5e7c492653396cce178809decbc3f5e65a0ddd295d700ba2ced0e3b31dcde6e9d49b680b1e9b4dc08d6ade8e4b682437527b7323b1e41a74c761cfe735a61ffba5f0df2b96e54fffb72cb37555153eed474bc2a80b351193051206d8d7fe489978b41f26e7478c6af8b72cce64eefdbbb10b68c1c9669d4ba475d65bda332ea04ffcd3b177ad38c5f5f9d14ad920957d977323587aabdc3aaec13391113e5c9068bfda7c44c450e8bc5edf765b1dccedac352fed1eef7864036bdfea94562cc7a4b48e83350989e0b3f152f033cacf3a5c1d6809c32cc252502b71bd980eb22d9e9f0d5c473d8e9fce10548191e007d54b0b3897a8cc806f51cb59c0d753df3d5ca7def704ad1104ec317e28c55a9ad80055ddd85e59ebe483e06e46e81b3ab2ed68ca1793140e8e9124d79d312b5d890d1df777d8e6b1b91899238a36fc964e3b501ce83b92ac4074d46d957f5d03ad24efb1022815078796d1199f10d5f866431fcd5e58de04632e9223ab54b9b4ce74d7f500d3fabe1660d8abb2b15bfb2bb52df5456941b2762f00b92a9ef8b72e4f83ac78d08c23da01f0111102fa050a743305999dbc76cd0f6b6c3c23cafa735139d6010f3616907920c13961eb038eb673e9284ca4a2bdb8b321b2967caaaafe9b06a1e68a2712298f2dfad3485b62ba5ca69ca792deba5e5aafc0344885586def460d9cc37a101af17fd9a7d0f1f70564a6c367bcfbd147217bf07ff4ade2c77c86c20c38a0ac17a5316669e85821eeaf9971355ed9d587ba7744d2edc8a72f46e4db2de00f2c81570c18640fdc55ae781fc2a7cd9322a795bb0cf51a5f0a7ac4e32f8d3983bb999ba1aa2ad851bc479aafea1b1930c61aab91065400e764be10af6e1a319cd389546ebe246afc03223bbfcc801acc0d3ca77eb1bc00ed74c4fd4a26d2f318cf6c312812bea6067b03200266d9e7fce29c1eb18c5f2bc64fb88de1bdee5a80d1d9e60e34bf0631dceb2ee651c55ee76057ab84715c2e780253d92186584d5190208c8a5003e3a07d749823c1a146561d57f27a1abfe2fb856d9be4efcc8b381d71e93220da9bcfce4edd8e4cd4655528e23987aa292070f65d241d8e80515ef582278df5c9c1a8580eb16330a22fac05bef41932172eafa627d8e8274fecad84b8560bf1939c87cd0bf3fd4fab817ca4bfa6e665d2ffab22d7147d826fb4927a492659f99a34e27cd8113c043d6d7719c34031b23ca43cb7681b2a26a8495289a59dd0d3e5063aad840e696ce42cafacd2810f50127f0f6de701bf265c50ae6601e436719e692ea102824c1c08fcb32731b88abce96d91c337bc0950075c7012050edf529e66cbb0d1c3a88eaaecf1b4cdddfd8667086f60041217465959b4a4598992d270755c83064ca40032ed73b52f0661a6d6f4b24affbbc16e08166f6e86e955d0190ee74daff8239785e33daa1d32bafdeaeb039f1a64ed4aa82c9debea0118ee9045b38599f69ac185e684fa97deea143f968d83dd5fd36bd153df507cfbe3b0b58739ff8f5b89bcf381ca18cd0aa86f2818ca3643ccf06dc15d0a84ffc41844b628e661258190a350046eb3ed79d4536c091946a8d87593a41a208a4a1bc9cab35156a2e5ff745960291b831847b005450d1dfe67dea4f3e92a748946f747a2d30270a01224b6a28c42d7afa4d84421092b2e99060077313615fd99f4b50953c07d81ce36af5a91320959c48407477834739fe44ef9d46ecc0b94cca53ef7a7ef9c532b9cf3f79ebd2d2f388bd85a1dc1d18848e91fd20ae443ef546f3666d4c8f5c63d64013e738fa8f44031f83ee11201b02cd27c69431a4b237061a1f69ea454a636810d4f668101deea7ba499623ff4a6fdd820757ff625c5a228eb432f234bda5d3a069171b0cff0774418edcd5eae4771fc7fb0003fe88e239cad8d67bb6e4f4097d2348a0519bd1ca39eaf5ef10e0a6fa98034ef1b5defc8260e3b1d4286f7572ff5464a90759aff408aac47ecee8437168b62ab4d6c17ebdfb534b373196209467f237348fe4075e73c52484372a7bb16f7ac83d9c535f196c5a01c1dc0f74d564e0f28cfcc0c12a665ccd13c4f0af2e1f40ce56d4c921c87f9041a6a0ddf12486fbdeec3f21e280bab3b9f8ae1e1920e7896485194954606456767d9d008a0db0931546b4bb54b9ff4854bebc91b860111eb029e9c93cde37036d359624a07ffd08133f0d4eabf9c6ccf31d04f9e833f945e90d1d198dd94000629af42deaf0117fa9e5efc85f423b3417ed6f30a5934f6ecf6070d35738378fa9d37d69596557f50709c48ab4ef3d4a9436160935ed1aab49fe27a941df138475f647385a1e76461e2c6a3cd40cbd40d7872c0a186c6a68d53b3da6f5cb1d66537f42e3a4a8701e8b10328b5fb1ed790115268778b7d1be1bb29628f8df22215b89ffbdcb5c1da913ea32279ba172c0dad8092a2147da9ab94d8c51036c5c89cc377c77c5da8f5d0a663504ce5327aa667b4b6ede5d997665ce8f203628b88dcd7ce54a3c6b5ad2771db818feff948044bd9d4166ec446b6d3ace318c13bdb4296eb1ee78a120b56f3412237b987dd3c37b8b906079c7088f2f8421808987c8e425a0c40096f1269724c7ad911b75a2b6f21f7e8192ec76764e975b9a90798f8efb7aa24a2d2cf6e8b389161609866c159d0cbf7769ec6e95570bf493522d2146e4f21b158ba70131a00dd2b64c54ba71f1dc939f00ea1ac28bf3bcba9f0617eea732fc1d4e5d7b2e1f18735270d2730a7bbaa4679ab82afb737e02853ff3a1e07315d088b2da40fb10bffde9d175ff39e429ac33811c702f86a2b17369a0e0646e6d027ca6b10b15dd3a38a0529e17c5f7aa503d342bc39ae860963cc53381c9df1b1b5d4245c1c3b2175141259e4c26c9713745c5ddb7e0adfadc197e1560acb848d60ffd1ea693aa1719a7d53ccf31ae811592777fe48e2fa0581d2cab480cc9015d56b7dd6d7202827558c00a3e472b5f25b75f7b9f473a8b3a549a75cbecbaa6a38cc8a10dbbdb841877de78c898fcbaa3b4dbb959e947184c9d4078bada53aa6e7ad283bf584d276c3bf5866c9e16375d0965035e5deb833208f98a086e0f6e57e2ae300eefb12b1c8aba1aa62271eab3b758e1f1e0fb61f8f354da8be277493cccd0e400acc68dbe2e59f09f308bcbf42dc5d1a9f381e96fa5ae67618c2111a0141f3224b25b33d93ee7f6d03abeef9582f70c274742e8870e6b3230a754356965facebb2716f4438096246bf100246e125ea950b823286bd76a5109ad6e70fbf774e7666f2e570318b3bc3ce662baa2dff33eefa833bff4f267e334a794b0ce7e8b032d9945dca8f822105c6cffeabfe472e3a94b44f8569af925bf9ec202b043e9d0a1cae6103d4a364524bcf38d167133abfbf5205514fb79c63efa1a87f36bbf8f51f94fad2d9f53a92c578d02fc9ffbdcf628df0d0361766886b042f5d92e63dc50c697b394bc2e269499ee64e540e2cccf059a2996d8509c73b3f072429eb1292e41320422db6e06e72b780e0dd7953bf5f4bbc3e9e18ca9e17e14fae000dd3fe1cacf030c2465e8101af4418be70daf26ea224f36bdf5a5251774445f1d25a32fd29f3b8caebeda8a50a2e1fad91ba6e908b777acf45a222b27165875753447485f2636c7129ae5090ee6547fbe362ec2f044e6ff2d93e5e92669dd46ba2b3c81cab9e696f4fd4e934b75707cac5d899a69e615c6c4c3485862ab9e1288950fb172513e34a3cb9e8428b0d985ec4b58a5be6e18a6c41d660ffa4385e2a0fccf8a2752fec5addca34e0374fb951c7d2380926b48535888ad21640ac8a33ac3d972a615c80c0f98f82244baf8f93d09ae0289302d5fb0a54c1ba60838083745250bc3efb98b5e4254b0fc417892a56d6b4fb2e99a2ce03d321edd59238cd2fb806bd84f6ad32de9a69925cfa01f483d4bdeb071134c236b8cd58c2bbf3e33653ac1ac78645de9ea29d6757063b578dd65d56cc191d20a82af95465fc100600a7ed3ef02008196d04f2e73abf9f4a0f2abf83cf6b14a3ae100feb683cbbd81e4f803eb3f5e5709a22002f1322cfc786c2e97a97d1b2be82fdf584e9bb2ca4a3c4d30c6dfbf2fbdaf1a06573b44aaf5961068fd22e556bbd933818cc6f7a478da9774450858923d6393bf250f06fa3745de5a8c2700b2b522acf97b8a4af734fe903de9d4032ae25e55a4082b7801506d1b9ba4e73cbaa91ad7b862587e61bc52afbda8e4d91795094fdf1541e45522e7fd2c4d6ff5884f75fbe31c60240a7c7f1aad09bcb32790f0441d266d4c58d8506bfd82b70460d3b4280b787fc6f9d9b5c3f12abfe358aa780d53c61a458a161863a2a9368144b70ba4f638d22729e8e71033e9ef9c10a195b0a0dcb2a5167fbccc1a53806c2bcd5f9965d02db164b51a7b1364c06508ecb3f4762d53505313bef74b506ed7233f97e3ddd70710e035f32a176c99f1312fbdc92d38eb59fa0e203aae94c55ab81ad94efcae87fc658e92b8d4c8a99fc72c30e1f66c0f78be5621285d85aa3ad8d282b2082c6057b334a799c92db44214cd03074c2943c3f0d59adc462c1b35ea34ff19e9840b8fd36ea47cc21da8ce3da075c802fe9aafb1273ca3f87aeebd4d411973584e26b177ff4aab46e7302629cfc60853a98c98e7cdcbfc15e68f481b0da2a4af40ccd81ec782906c5921929d8d1e2946d3da9205bc6be13786ed729d99c21e002b44b1b766fbc11ea92e9a2970a6754d01a1e392c7e899f6aab2d87c869161f29795bd175ef40e33cc838697bf94bf38aeb7f8c479ff5fd9662602d57820801427986e85ce886cea126d039a8102f40ef692842e51ceee04ff9278d3b027791358000391ef27dc92c87c5aab98febfd52a46895ac525065471947cd80306d29a8ea9687ffdcf6ddc6747376fc04f9fdc5562af83ba28c5e37e76d316b940e7dc6f68c0b61eac852f05fbae74b3c4885fb613aa01bf17ebac5d0c3ed832d322fc9cd0643cfc1ae1fbabd73b57180804c18b1d0078ac4eb3af47b88ebb7735b480d3732c03ed25194b8b56f8d60647628a975e2ebbcbea26105ae82b9f619230b9c31574a22b197fb42900112b6763f5c7df0e3e48c13638ba6e8cc209c8431c0b18863ffb0d05020680539780cfc8583f439474cfb0358fbec74403e73a7311139a62d1932eb46c388de46e5347c9db32bdde6a612b630942695b5434847a977e6ced2adffdd63815baa94862417c50998f6f4699f069088dfa8ea9b656352860c5bbc1517e5f2f0cc0759fdd2e65150a0baca73637863884903ad646a3186f28e14603c9d995e310a903ad6df7336cbb24f80d749ce52a310a732e0167d6640a4ca8b887db74510b4ebf5c8d236453985bc2c10dc84fcd87b6179a6381e2d24ee6e5d8d4f9e26e38297572bd210c8e76d0eb898043319f138b5a23076e50ecfa3f4925bef065e14164b68938be41b1b5cc124aae2bac9f3e9b24672ec25d2e24a7a1bb8ec0ea3bd2a0aba3a8c0ae24b364630ed3996dc9283766b49ca3853d811a5a4f682c11d1b02b8c468c1f4dd0268df91d3eab6027582570072473edbf08440784cca91f9c4c2cdab0a613bd41ddbeecc9a89d695f2f72864a7bcf6de7bd4c6d703864e74f228f90fb4da1a64f99026c4319887d9d8637217442c4346c80c01180044afd149ddaa1bbf2d5e8df08c1beb65386d0f6a4edcc095813c3e9eb2e1f00a731facf779290e44422e6d914a7b9cfb25683ee4dda9667f439cb3045c6a4918917f10986dab227c88647f9a7ec43453903fcac66255f77d6dfcd9a6731278a1c0b63181ea4ab42f0407843740820c9d543738b05e716b0c1843262a8b882df7fef750c6740f05ea6eea0222cda8317af14fef6400851d33d8ddc9c65f251745493d1367c84955c365f220ffd9f6420b9aa231a83e0ccf3f8e084fc55cde59e674a90e9a27362553842574660faf88ec8fe2e14b1ee314a6c280612c63030ef2d98017aec587c0e97ff5777bf3f28c476a33078e47565461b979b6c8c41512ae105480551f6759afade88a5d0f5b40d70aac06d1cb73bb0b1c305938f17664026c1c8ef0ab5d89c4715fbed9a067511cc22bd9f06df429be98e1afb3816bdc8f7eed540ad55987933164e3ec32bc088488d1df785217d1fe9bacbc50511103a1a2b6a78539f0e93050b03e2ae965b9a4fd6293f45ec34789cf826a90576e154ce288cf53c389729f190b3e4b94809c22baffe9e1a9f9745923fb72afaaa14e9769239cba587c4547152875d6f8f60e5cc80c9ceaf6cd28357b588209be16248240b83bab2f823cf882e264063e8632ba739d889f6bdfac1825a4283b5725e8a17d44e0e91ac6035ab411e09ca48897ca70b9f803d33bf160de668dc848c92944c4de6e0d85f45d1933b2bf24e8db821d2efc2556330b9675775f64c86afc9fea81366a74eb387245d96ee6b17ed210dd4b98bd9c17261fe4c3c1ea0920828a3bd12607024543ddf36289946d88b904396f9b49800f8d3f04dc7e7aa8a47873057c3df0561121dd954345089d433130226f6d629f1d7198e81f909adb944325f415fb403ed45812bab9760ddc4c157fe507bd1fdbcafc40813b41a6ebd08b1ba8ff2db9ddfbe055148aa7b0ba67cb6b8ae7af70a3da712a545a28aec420efd19a7cd83722e25dfad82c4038c72b411d5102633290f9cb82bdcf526f20ac28815a832deaf76d029b2da982236efd3c672abcb85c234c0e1d571a1200d7048755d525c033854dd9055a03d5bb8af2a021cf3ab33428df0abb5d497515cac46e1820685a3ad1bff2109eb1e2be81b37cbd47c5d4925c7228a376ea186c2aba4451990dc53264cddd6c447d8a1306e3da3d5c12a08baf5ddfb444ab16aed55a82f76c61a7e0dae44f782d0cd5d972ee7963d31cd69e1f771761d768f4b26cea35db3da2504b10979ddea1e3160ee8b391fe7abb07b5cf2713cf762621d16f93fc82c617eb9cee23df788d1ba5d5c6002d030afe447210fbdcb404c0de3845b8b23f5a94183cfedce3b3467284df4b580c597f4838ee6450fffe804407aa7a0f066dd9fb85c39704bf24c058ec445a97a340d88c4b077b5fa9eaa3c3c297b0b5989a4842e1640282aca569c3abc77ee92af3e2ee84ff1ba59cb31fbbd7727df83786dbb9095dda16d2ff18716d65aa352d709571ce2cdec12008488ba658bce60772fd926615c91ef9b86a1e18372a544ee540e3a308a0ad00c8fa89d9b75bde5b528a3e824cce996cb8bb9945fee6008a37db25726401f75360baf10f2fcc1c6eccdd8e571202ba9049790b6d5b216e868db192c5385fd7e3faf92dbdbb90ed390d1084660d1cbb6a4c957a5507219a59a9790d8387ef07330c5a21ddf8f2824320f72c8a8ea2ffb9b5f86aa38121a57cfa7dafc0eabcb27981f31416131dae218fb70382d7c5fbf2c6631abdf11ad0cca4f6bf64269c1b172a4240de389636c4d1f47e7c34b04ac445b174a485c38d9476ea1fbcc835676198a8ee11b0438e3f7731d42e13782a02e2214d061911f48178ac53cbfec55b86c6bc78ed170a2664037b109523f25812fdb0df09bccb8ea4631a77b2fdc37817da0242804fa8725758eafff248e9139b86026e1ba6dd37e9335139bce7c9c2c7daa35f15d6bc7b7844fa84436c3d6c1cd0b6960ab2898350f74924d63bc842e040f9589251b4ea0057419198e44c5428556029294e5f2ce468dedbb0724815cd4525f4baa4b6650e9bf06f3fb6168ad1411575f1d40d0218caee8a52e11794c58f75dc7f55a72193b7981baf5eed56f3120aaecc5dbf1a0d6c408a186b61d7769c0d269d2225d6d9d18a4a0d21566a4180c66d798acaeee93e7ac937cac3cc876e7325ccdfa7119c2c8e93317734992d7f2bf70ac4d4994f3c601572e61e5c6b49fa17c0c08b646d887daf83d19b485eee50a757baa338aedb805f1c0cebbc1e87ae9c1a86cbdc4a693ce36349933923436f556ac32fc03e03c7d6c10689d3e15a7fe2c7fe82556d963e295daf2f95f1f6ab43dab1b15a945c4d01a21fea7a67f22ccd39edab73d3406c1797ac12301e86f5ff59e5871d78586532d0cb7080f7b62e56e179063cb4e08efb4c865aa897916ed91a1a955b2cd61c1eff37c1576c72d3bc643a5acd2f9068d70f285250de8ddc031404599439607d89dcdfda88ef66760620e0a68825305fc180107570927bae9beb11ba2e605f25362103b2f3016ab168c874dd0126408b3bd7eab77ee106cf5afa08a2a8fcbfaadff685996fad2637f33981eb4500697e286926d2ed06b1b4c357ea0e3afc6e9303495848696de2ef67f9d200724498b9485b4609acf2db8e042990f92d4ce13bc988123cabbbe8a07b9a6eff665107bc6c5e586865d7b501feac95f9f53273fcba6e5c4d6c3c2668f2c9da55d38b7a15106374166b5b1e009995943d4242ce618cc40bafb2486fbc812ea4300452586cb8683f7a315b1c6e20afd263c7d0489ce331a15aa0326af6793ce8a1f1c9834a0d3c0a46ea4cf6998efc5e3167b88e97588ae84aac59690556c488406aac1e1560f45f83ea7511107fa483eea01750425fa94d50a6a61dad2aa3f75fc47e14004cda15a81ba82b13da4354a1f400f94f5b890ece720c14bcfb21c8106bcc0d00f7315fbe2b6b12dc54341ac52644d11144b64e0d4163094e5e6c0ab4901688bfadf5e700faecda2eb0dfe7236ab09625ee89b53bc824b71a84a33a59547b84bd4f21cfaa6ba56236f83dc562e54b8104e6f342aa92bbf5ce28a558530c8096ba058799aff7d7d1eff4b2a291224d39f077f1ed7065c9de85b9803a6db04be0896e6848b531c9bba904dd48fedc9a3f39c638be8f9b39053b117242c737f655b522215674bc60ffc9858957e0d3ff1d8e1605ad8cea2a8399e918e68cd1050bea665b403c9b061cf4350dc34ca0c143021ce32743e0688f97fb1ee3ade0f5121e9ad289da307b68459624d60b07a1bec329a7cc1604d263c0dbee0c4c5b9532b12bc82661a3cd0cbf76306329fe9b116b2f676b767ebbdd065dfa959140d30e1cfdafd596f6c31987c2d8a46b743877f1b4039797b28fe4e247b2b5a81522f8493e52b11d6c1849f0121aa779d625be005a00c758a4d43d282b372bad97c9bd9a026a88080443a9ba1af1db80ce60fbd2fc2fb37dac3f320c26c327a55f48e363ae9a9a297ca4d4d01acbfecfcc0a17f885cfa19fb944ac32986d0128d0a4406eb16dd1396cae2690ecc41b453f87685d861f0546846621bda513299f09a6267b3e1197defcd2d708967b9a37326f4144b42b9bf6801c6efcb275ac33d452916a465d63b5a843b0e301828b6e30eaf36a90eba8851086adc0f09c90c7ff85d040590a23f997255503df4f251e667f3f05e44ae1549511fd7d032c152795f7f8aeec95f5e6b45dced4bed22f92dbaedd09ffa06aba7db67ba928ef4a607480dc872291306ee684541db1c1092660f98e5d9f6c5e25c4fe14c05c710c7a9295dfe238a4523091712528a5110e29fc1ec3bc055bf455bcd7f86b5da1fb6d5fb728334e598c74fdc89036af07141829199ecac213c0e4131939d4dd714cb8f75d64e57e9b4b2678c73c4af838f7f0cad030e86273b23ee5afed676302781e84f5ccae40ddcbc4de25443885347fa874710fe96ecac6fc07dcbb548c3b079d9744c295a16c061aace2bb194ec0ca06e5e959ce01ff1c1d52513b2bb2093be3ad999ce6722957a9fa626f91d5b92d3f24315b115645790a58adf2a18a0188678506b1669419f28f64653844e22fcaa30c63da0b915ba982a4d413acea68bdb9b0a63343a7aecd33ebc3b1598f0916ff9da4767a0dea127971b2afae3231b1cca16512b145db4dfa8338909397fbb7119d70794a9ffd6190dee32fa2b4299fd2c3baf054d21ebfbec24e4417f5e6dfc596d406d28dce86420736032c677d2ce7e0c3302423b9b7fa14f17d90297eb4f1ea7bd1ae7c87369b441e83436a797411a8abe51953d599007c5febfbece57f5c865ddf9a551f8e7284f46421b56d3d0d206154da37d168ec4f0545d274de364f1b1e83a385c28e9710fb3221f33d80417f06528d318ac3474a750740c69696d6a8416e37deb2d42b7d8702ce2c41c1f8aa2bb281ab5f87e62cb77da5ee095a195bbe01b555566803b75c494cb0ab31964dfe934ed4085b308d0db9bd01f2ad81acd26e54c160ee9a45655cbb54af0ff2d9fd62266d4249d6611393f3a44e7926b1128192b945e4c9433da235dd50889c6443abd00d669ed55d21df7b8ef1dc308c73590a5af58ed3383d06daa7aaa74225eede32a6c8b55c6e124411077772bfc28b98235b0e170367641ab6e3d1058d69c29844260ca055ae183789709af52ce04a6b52ec81822a3aea2ac8a1d79afbfe1525eb03330f06ce20dff34194bbea70a0add65ef9f7e03dd40dd78fe1cb1de96578787126a29744edb496cc1bb6847f9de5bdc26cb63a9497610ca290da80d1394a70ada2d79ad0f4e405d0050b7f35f2564f1276d5eee94776ff908786d86d058e334b56018a742cb2e1694b9ac032b4448d27b8bb5becc05f6dd2208dc1ebd6dd13f55fb93fe761b31be5c8a1cd7939bb01931dbd36d65ebc851f58d077187aaf7909b07c556dc5e293db7fd6e32bcc4c73239a80517b878cbe9e78ae28a2e7a2bede1159f54893a5f437df560706549aae3697d6dd2b32724573f638dd9594146c422d71d12c80795d30a06d9a4711342bcd62359c94e6fd6e850430d889aa78b84d11f1e00441f286570688f1aad6eba33a6884a3fd15e8d2caf944a5ca8e36c4fa2511cab2f6c01fd867b94f776dc5c8a739ff1263f7991c8ba12ae7003fc20d3338472afe3537ac061965fc7cc19ff5b0bff4b6b138ec62676dc5fc1d9c27202a48addd2fde03f481628ce7d870648c716a821fbb0591fa930186e0caf56e98733190a12022462ffe84468134c6e5220c61b257e7faf78bb90f0a502908ee1595b6021961b2801576676d1215ba3e8cba39913ee531849fde9f7ab4db3883fa8aa5a4a34e863c717e8b7850c4f72025f6d7c8de826f5f0116ee1a89349002e2c3fdd3aa3dd8472415fecfb8999a75135a5a3cbd6973eab6e4559e8c00c09620284c26c765927da24a201089895c0d2b12c6d3396f2db2e4e756403c08855716296411c265c2fc6c65bb3799803c6c1849f0dc6d4e6d07a75ff3c3268c1c4994755919cbf30c14c597998c71abbf84ba1cf59ada58bffb55d22faacff7fdf9753dd3d8d9278ddaef803d5cbdae4e7a58380a3d8831c697a879de9e165a8a365854ad4861f9d75d516aeb865678db45e24045493c756d57254aef1d8f12048f123c6fe9ae0ba7ffe8e2fedd8d11dd738cd5da24d0340db7f84636d82637723cfb80770d840489e397e45d532ae9c7c1a852529bbdacc6d58f645f7a5655cbff5695eefb4829768ae53c1572163d2b9631e33f672785162193b6771ee46e2616380d690c1a59918176c9be9083e1c507aa163cb2ef2cba004d5cf18089ec9e5d449d2c0925b27ac542f9e5c54f1d09274370146ee9d9f5a7c59239246df7c03ad3ef1f866d051dacc5af20b512ac5f2d1ea310b0af8dcad988a16264c598a4bad474b1a0601300bc708ee9cdbda3cfa3d810dec63bda76d3aa8edddc50ef989e9b5c1eab58a69bf8fa897e19e71344e212701b9f996cf85534fc63a19e5fadaecc853ed19380e4f2f73024f73ba6aedf41bfca9aa96b71c2d413107addd7db19483a8f0d761fb3bcf9c21800c4e709009d84791787ae865ed045e414a4cf3d0a49b1b05bff2e60d552457d7c6959990e8bb9b6480193a05d9708119f80a588881b7d95669f49d1139cb33fa54bfc03c46b7f8c137dfab0447b286c751c69a8a0eddba11f8fdde77517a02a53f67c5b6f9d9d91381646a224b94636afc61fbbfaa579f172b7175e504e144356240ac1cc2dbd31993b92dc396def6adf726795e299bed822de95729672cb1849f56244bb84cfbb11dc394f030859c47d2e74c45e9abdd760f85cccb418a139a6452ff2f462ecd3a38756208d053afe6192e356a4be55df756a838293561fa27e4f44c07ddca8621395840f6583d3765ea755b434d40900df1b9f84a64f42f5bf4941ca013a9be6b994be32f989cad62266dd28efb8465709480829e455054f906779095751d1733354df7e1ac4640ec1324f3f69ece62da99bbd0f471d87167e43c832850cab7e54b182ef02663e55a3d24d2491fbfac944a01ea13bf0d7be025618d4102810dc95e7f0e2c112f58fd554f4aef40120facb8d821489bc951bf408e52868e8907137bae067ac81ddad7341c9e27d55a7691026bd4b80082422a42c15c48023b53c42df4b09d081ebdf02d0ccc663c74e8b565429f8d66b70387dad93145292c04e5628eb42271c377ebe9e87f03b9dcea458776e63f468b4ea491ff568f4c2e708c270f03079ad1d4487f2edfb406110222213f213a4bf815dde300f2fe32f504aae6c6b9b92695200cb68ed91664c36d07e12a16662a21213d0ac4ff3119471399719a2f48a278210737a0bf6154360c94de10d25b06d5486e27c732265a86a1f7a96e7201bd7b7faf9428b528a25042d8d090e1021a4c98874b0ab1f0df8a545264dd53616becdebb9ef5e9eedc8bb6de8720e388cac26f7e4cb09f0e5ef74e5bb00bd7fda283a3bd489c5729458086fe952c05065cc53778d3ebc96f25bda4acbd8e3398ff6ca919f8a91ff185d0e4368f7c57a8ee6267387f1eff887488bca8755a5261955325d2bf1c64b9dd8e272ccb2d1c9a23931c3baaacd4f14f530d8beba24ae2e5e47f645049c703bc2e4f735dae349c62fa526b1dbcf4fa7a646c770085527698d0a747cffe8dd6b2d00abcf63a69f4b4c2486cf4076a9c2e07885f0857b50f0515085af29c8035ea69063c6739dd2924b392ddb4b049e30e0a2516ee2e1a066bd5531f3e376b51531bbcc3887acefb331d3452aba6706f774ef1e486580667cddbbb98c702ae2d2c025449e66e1bc3267b0ddc8b49f9dba2384414d2a6bbcad9bbf6ad6238c5169ec6ef9a87048122d04ade13090bbc206d8d2cdb9d57d37a1a720ed0adde1a50fabc842a71e833c6edb6fa00688d9278c9297b9364ba9b6dae180e5104e0d300002345b90d5610a3701a277a30f9fb4fe76c9966ad32834fb16d2416b83efbf1b039e46cd26fe2642831869fe8188e13d4f36b69069ba2fc1bbf58c3c705f58ba60681900e7ad39d1a8a194589d4c47fa890ad39e4dfad9cfa4c97fe3f8d31131f53674a09eb8e81cee429eee002875a2ec7b0e6fcfff78df1c2b14b2e049b448574f90ec0c031a5822dd7e98f873488bfd1b155a8c1067dc27be19b0ee8d33e21fffd0d300319824d9e61ee702d847738349f980c9b51450d2d153e2116b0f9ca0e68b846e313e20cc1cf103c745ff98d3a48bb387282823c1d51ab155cdca83b022a9a90153d2424f625962893c4a1177f26bff46688aa1b7034cbe1680d6926aa126bc0d90455e82b3e388edfab5a6d74a2e0ad3edc41317fd4c3169dae32737eb3e70423180d101cd1a5fb30b4be4d12cf18a60ac82a07f1522919ad02b13d3d1673e88921851d63faf07e9ea60b4dd6b4398e47fdb2c13da24ee314e6ac9cc11c3607eb3d298f178370a3f3787e26ddd13aa01054814b66aca7a5318d3cb454685bf71bd4a19dfca6268a45a3bb8430c8ed0313a2509b26c3c67b376c76e0b540c761850206b7b2f509a4a1e00d998550f292c0a876c0c03d7b6beefe124843aadd26c9884eb6ee8e7fdefff722c7ad9982b23a86c252f1dfcfc1ac2cfaed0f846581bfaf03df0cc831da735d39514ad96a18d2699ae3c782efe484b72c5ceee2ce6d3331d095ff320a579df15390c1e6b707da8d3c3a46ac7870c48b4734ced92c7b070b911c25f3991ddebe32611b8545ec4b06128e6d067dad56c4a57826e2c2c9e0020c1965372efcf1a30e0b53c263288afc9b49470276ef6dd516cd5d790324a2e890a372736da2e94c8c5d58e4e5fdf56a6c76306cfa239fad43910e75811d9892900eeb8520d2c4b7d7013a2c3c3a249aa04d84eed6c2f6c6e4d7367dd060427d7970323bbabac88c846d9674006fd959cabf90b3ca974f4950e8052766240490304db471993a496f50865c1ae15eeb4a5bb1e8334650f6c70eaf391f85d56645710a7ea478035d809c9f190f386c4cc58a07d857deb704c5fd82208550179c3f63a99a879cf9ef3d7c3d564d7a1a548ff11ef1cec8c0b627744ba837b4e367e0dea567c83f87da8bb74219fb8feffcd8d35a1d0d781008af5163d768c82a5afb484f34fcac31571331f30b82dab193dc71560dfe2e35af54d99ddb078b4f15b9a2356a27da6fea4457694d183a1b4eff3eeed375e6235de683f37fda8cb3002d3bdb310ac4640790f08e2f4bb9677520d44a53cf8e2ce903c384d0d6a3bb435d026304b5b1898cfe612138364ebae973d32037f1832388e785798aac5bbfea5c6d2465ef73400a3e39dbc57230e0e029dca06e466018644c74cee198d63189763f6a024ba3031ef08ac2926274d6bb986077d44b1ed1c98f91a76b19792e2501b4aa6cf6d65b392d1f43cd4fc3647acd7381259688b0c8d7f433f038e6a54a1770ca15c6a633060f65eda07482ec1e6a16aa5fe362d7fc27bd25480397cd43280c5bb6a2467c58e83ea7e2683f03424b44f003dfdd08752ea9f57abf7e4ad693490e0fedbb01411d5d2e884f29bfc5fdd872291412180e09817cda3fe7986d6801defa176b871c6e62f5c5f23f34e09b9b2cd787c98099d46a3282769ad44cf2ae81587bd565dbb57e97f6745595de76bf4e6cd58bc01202e595f6e1bd73be494ace8c49d7faca99ece5126932ec5d52cec87a014551843abd9325d1e92363d27f44460a53647107288f7e7103b7cc297c2058402c87405c340557a65c5e3fb7b37d3070162e4e76518d83c7d67068c79a9ae8a2759b6e14ecda5af980bb1a6fa1b488f17593b70b6338ade329f95ec7cea1ceeee07ac833021a60a4d934d463db4e12a9e486d9c936f0f1f54179f9ba56c6d5689829d99cddb77df2ca2857cc304d2d0b6cb94c565973aeac0b468a4806fb71e89665edbd1e0e47466c4c78b7aef002de4c13c5e42fa5121c09313a2cb3e25498e3a8a7a9f6f85443aadd0c5db94b07c7c7b70e4aa2fe87304acdd636e52be44df0c27d346acc7bc54f531efbb97bd46bff22f33b1363c2c0d2dd05096fa08d83380299ff648ed7a2c43b5323240fa22ee12fd5eee41620ed8e80c9fb9c982f566f1e8ca9dec53a144d5b006bdfefe891afc52ccb51b92b4259c7aeffb2bb060dea31257ff2ded01396a1ee19cbf97dbfcb722cc567cafaf0cde34db1b50015a0ebcfd13f298e88bfb2daa10235aa9d31bdbc42b5a61737137348ecd6d6ebdf43135ecef16d9169bb7b916f0f57842c3981c0d31b7dd41d3921bf2f023b937397019cee808f77c1d8e83d97233a9adcfadf045353d352d92ea645b4723ef058f8983f228083d89d8ccfba79540bef3a714b62a9091d964e3a2eeccd3f5f7b96e7994cb8076b4a896c6fa2d0234cd2ecae4f9726bc5b1e3effb7c2f7dde6cd5fb2b41293e5235c20258a28e279568ca6b475939b9c76b4cd119f9c8bb4febf8be1ea9775ae1b59d3aaae69d7ada4a5bf7d24011850d8ebacf68fbc22fca58f4c2bb8f45d0196cee6a07da2953a544e21cb85ec88a6588fa107d5e70d7c73ac2df3f7caae8158d961d4be16eb847b121ad34a0f73e253b828d1cbe17580da765fb74294092e6ae6f610e57d5bbd5907a50196c66eb61ffcd1800f832a0fd35f1a11cb07b465c8acf4f1d7e35d12cd528b1ee77ad274873fe1e45fd259043b805b20fee025a30058899dda75382a4fc077c9f4056884378ba26a477c28a676550237128296d3d5b7cf1cc4a41b9e863bdb8598b4ce5b1807b34f05c478f5978c68fcd8c66c7e69508e7c6ed5ba41548bf65405e08bf154d28981fd0f8060a8f80ceed2b5b56859c2abcbec437b337189a87730882540a921ae6527e1bbe7d6d7e9b1da252951e248049cf41725a3c7af8e41c09c4c4a26d70f40272f665743fd56a4ed3ab2db507f785c441b38ec1db7d14f6664a715cfdb070bec4cd273a100a19bd71c04775291b0cb3d989e1b07a7f1f064e57769f4c1875d5f867b75928dbe425ef641cc5099246958ff155b9489e16e92cbf3bb2090309546fdaa3e8a6b599261235f04e0c712041ad01c0f9bbffa8854b5b86ae1d3b6610cec81c5cb904bf89eb1713c7ed1e2992da31cf32438ecf424625cd9d40945f26e832e58abd8d8e41e8c0b2392ee1d9302de22cd36bbf79a9c9cdac250d8e59b3d8da62088679b646168c7eb2d9a77300765ee173a89279d6719b2f90c605dc6f5d8c8749de043e5102a74120d9d9f87ce19a253c8e19004d7e319447019f096c2c6708a530eac7b7f3c0291567331af67df9f70b33845fdf09e17d09a73ddeed4317b6bae0b596b2c7a5bc852b966c1815971065053d0088b23eca25e95e2d92c28b4d284733f20222bbe8154a4ce288abad2d0dc151cbc53f75fe41342131afb8f34552c6849672232fa5c8b824d40f0a1a21c78b807f594802805dbe34dc40d2dc1f6363569eb4bbb3c7ce1be08100716571614567d8208a5fb2b718b2309e348aac9ff0158657398f2dad56e88ee00c28f339232f73df08365e00e8041fde1d1af8b397f3b51f03a1bc3a6178c7d090225c197ca961f32c4379309e6cba63259ea29523ee5192284d43b45d9d4dd29782f491f1b2ccf53a328661dfd9288f54e5acbd1b61b920abd7f8519a3f6d54273f158019500dba50b8e345857a22620f13b16b4c9e4a7d23544bf25ef4f6512a93ea9706294d1e87586a771774212c347bbc9a0f5c8278c7e29eb489b2db5f9d13b967c52c0ef36e1c8c364b7a85ba2bacbec593e79b8f4662e2929fdd8a6aa94c467c35f482e21bca9449c6682acb77f0d8a1a484a6b984b9c89d7853b36c2395698f831b30ca0b83569266c0e8fca8752c701cfe7eb10ee6c076ad5d82fcaabc7cf0a377b4c4df4681a9906cecb848f13bf7f94ca67b514655a1a0758e90cf254da72117960fc268e5a541069f5233a7da299acefa2b1702855b499d15a47315e6115d3060e4929ff4aa8e8de7df4e8965a84d5dc3ff5917b9a766a882961defc383e16aa092e1e16566ca2a2189e3ec04ee85c2a373905561d6a887e2aa1f077b116bb4d0ebac643f361accbcabc299a75deff2fba837cfbbad323edcacaea48f6aa84d58583be8a0794229ca0ac1c412662a04fb8bb7ed9813241cc9efb366386c337d068a8b8922cf50211f2e03c5e20e6a8b809858c6edd048b5e8591a7344d9490171d668f0cf6cc9517e2248296ee393348fb88ab8e44d6f872dcc7c7396365acf7fe3cf995d8d340441391e37242f06d92bae11f7bfa352d55202813ec399f5261e65bfa4b65b9669858ec8d4986c59f276540b615ba2a19b92c240b3ed212a7da962da85d6c3455509e08bb8b71d0af42a65b9959b90c1e4bf90368aa0fd97e995e329fc4a860ade464248fa7b61e64e59643ae59a8b7f0199961c82b51d890834084b2ae9608da45824076c8a678de19af6c42602fbbd98ff4905f17f62a38e2e3946cd589077739968c92b504b3561b2fdd98c414c13caf65fcc660ec83423e06079054214b6ad181407d669d4317feb703fa7b6e8bcff29c8d4e80ab5d61d8fbc878c650460788215ac86524e5182755c110c5fbd4af89aec013f2fcb86012571a9206a2cc067ed51a1b711ff1cf34b195ea85e045ee557e92c9802ef264c48376db9bb020b68730bf8911ab54b5884e1e413d9fcb3ab5167853eb92626ea0215888ed878e4662bec0d6e7119bbe3702b15d6a94295c731135d4b86a7a3edc04797484210aeefc85b3f8b4ad4dffbf1a087d760372e75afee45a870f9f33d6fc352a14b48be5970540eee5d9b0bcda085435607a470ed5b52c6f86fd7a8cc2596191644cd2b0e32e042969edf901bdadc68f540cf4700b7534e7344d66b25f922db8ee6c07f3f76bbab3fec710106ecc750969c4c03ffc47afa56f82692d7cfa15cbd98d27fb19a77564d897ba42538f6218b2c49426fbc95704940a0a0bd81d010266feda2d34704e2bf226038544804a6ff6139a4ea76c85c75f44cde949599ae924547ee31869ab0d99e162f6f4f4b6b17851268e2644cc330dbfec988a8ccee1352c95154ca852329e5a8eac03b3b943817d6231419fe40a91a5f3e8515466aae56903f440a9d4cb3c1b64c6f41ba026011eaaa267586e1812fdc18152e3a867502aae77a6246793676bff5ab4a0a688e5a651c7d758dbd88f071c488c2856e8918751c4169741fa21c5692f14ccc5706c931c2601fce671cfb899b2ce82d410fecd97394524fb9fc3fa1d7a7b3192bb297c242108294ed544786dc8aa80c193a47fa1b80cb46292ccecd05c0e0f67c22d62c5b5c24af3569a6acb01e39bb89f52c0fc0d95cbb9557dc2793fd5ae2e57b35f6d5060fac69f3ab340493e9f09082651d6d3c3c9556f87c2a1770b301ecba08a3456828aa1900af812c85c5fbf1a530b9df0a02dcbcf652a38ea57137ba052ec8a641e1044064e9b85c6cc798940abfa7f5449af5f009b96a9445a1895f552ca3cb94a54c14f9166ef8702f912fbe7cdb9aacea30a0c14db8a73fe5aca73d9d6cc4d1400b251c66bd1dd8a072097eae583387e1c63b1dff922cbf09c143e29647c86f51a705f9281832dc92f79f6b4590472e4dea193f6a0ae72e87ffaf3f1a28d5afc441cf5366642c85ce2a643d34b43c6f1391f950577c4548aa1f5d08c3391938de844601cd418cc90d6c7e98a9ad4744579776a540ee80096b8deaad5dd0c2b538dc443f4571ca23a6617553344f907472d83d401ee8398bf5e8b7811789d85d585b2a44835e02f2fca1d39265831f65af37068ca67deba448ce78fc03e64271422e25507fa8d280bb27040307d1703bfd91bd51bfbbffe7ece18b35d5eb68f62e9d799703e225a428370487478ee56f1e4b3feac41f6c067e9065b20ec572d490ee58b596e3c1cd23fb03802497bb9a8dd5984f377c2d5dc5bef7f537ce4f06f176933e760b4100f0550f00fe1bf73f1d03a0bb45f6df71327d60c3714daada11a861002ea4f8095bf39a00165369bfe79f22e7b50ba52194be158348ae7551475af0e2a85961250d65a68ce78d1070ec48f4b526306cd193b71e587e66ac17f1c9bc4bf5e6eb0184486193751817c6dfb131e32b992c99a5c35dbe9939a3346521c42d8ffc2f3792935c738cb1a2ca9b3d8c5df1196914c890dbdaf3c0f0464c53e7daba20cd36af94df9ff7dec457618bcf3a14b80ff95a609098d6717e115d4117e5f36f3df2a1dad58311e4b2aea2eaca251241fb01fcc43e2d0a6c1cca5ae7025e2a06935aa9141a290684086caa9d8e1ecadedcb78616f4a1463cb99433de91b3c6eafbea3e44b340b60e8d6de0af7238beb6a2184d90a33c980ff09a868bb14dcb1fe745ee7c077227883bf1df5d426ab086047fa689a0e06b46c4e0bde395c223b9565024da79176c31bc51b72cca9e9db49b0ca4743326f87990437ab3202a997a106a73c02d58249b7534c75a5a95e4b436b480a04e0c3b37af097d3d7beb02c31a74b45f381815e27b616902695a12acaadc6264fb5530299f3272bbd39ee0b3309f5de4bcd506f07c6760a6f084c3eb3045406d925ba5baadaa1b3436c2789594eab38388a82aaa374252500ee00d5d0094277f6cfd6d4b47da876f392b2d2e8fd48e285a85163ea15fb3d300d1a85ca8d13a22a35f88b41533174eb6b46c79259a65bf5ea91f87285b48fe5b3bd1ee1f7bbb977a8ee38a6a7d120799a08b5debd31ecc8dd9d870ebc4a0d8046293986a4fb168fc5d9e2094da6610032cf06ff9124ab21534c73d2da7cabeb785e1a056ddf282bd8d1e1a24e4098bd6f068da1a48419ca2a29378c9e6dd3752657fe120f0d7cc1eebbea8037c8560f3f7f05c78162b178afeac8a457c79662f56712994f7736488295d8d6aa04dd2b6484418a2b21d0985178254050698d8e447f3f28ee01d81e84480f87ae7f05763f4690ccfcdaefff156d6396e1fd9e124af9c6531cc0049c8ca7344aef8b59678db01310ca1e557da614fa0f18de42ca9802b6894b3a2c481cb71d315dacc474f102b1aff72d8b6d5b562e049eaa38667044e60b59c44132674e5ecda8c93c4e0ab5a0ec98c5f00f01bbf89a4eb27a07f0c4f7707abc115bc54a6c5d31c4d1641d7b91f25f121d5785e17c981154dd91eec55b8cc345f0e02545c49a8f53684021c0e7156a0d5649fe515a331677213943f7c9300205fd633b76ea942956898b49f91b73f1d4c5b61dc68bdc709a634ab3ff051d3511d535a2d1bda6c195b9c948826597ed196bfc89574404225b5596709ef05b44c43a27d870a75776d0efe27bd4ebac5d25f1ae85bce947fee41fe4337fd03983fe05aa0dc16e9bfcb998502ef7f50f37605f575569a18b04f7d4f139a7e51e904a0defc3680376e50df5622bde1f502be042edde97bded22d97ff4199d58634aa651938e189f72208d889f97ae8982a1503ec871936c81f89265ce31ba8ac32d14264a593863162dcea41a91966c438f4f175b337668a07c1d8a761e54efb58d499f68f63428f80b45ed128796271dd7bf24c3c607ea7edc2bcc73d0b49f0d8e262f00f5df12d7c2301dc8db4c972c1d1a5f6aa9f30af0285d5ab3d254f0d42ae5a9f9da2d967bf46e4b20a89ee98ca70689ca3ce5bddc0eb0b66c8dd465166dbc9477fdc09ff01a88810ee94514853b24b8deb3552e8708e1161ca77df1f81161c357eb91ed422fe63af988701159245d8c32498eb608ad692315f4ed03fa49d7a65920161e35633d413fa8453dd6a1d7f588bf21086c2ae5eab775f5f61e5b398a84c51eeb67e9f9e2ac5bd91be6a580090001816010286632f558404b3d993c70a1cf7498b76c1c52adc3fe6fa81b3521a1a5a54d429b4829a50ce609460a8c0aa6cbdc88e9c337f27dcbfc74112aca2230142482760c336d8f11c9c898443132a6d21613532a954a254dd38e650d5fbbbb09bf64d2a3b5bbc75c264b3913a3476be3934a9a74986c77377a27c6cc300638dcd5b54cd374b4ed6ed9d2d3a5b3afdf5027a438780226e45e7a2773d347fa27432232bae8def781a20ffc964711380231f8619d0f04313ea50775744420470a37c88d3412199d30dc5cb8653a9998b0d475611886210c0cccb30c839f0875b6371a7d6118ee0ffcbece0b75c2ad240b1ddad825a55ebed0426bb65f9a5ecba3cbcc2c1b759da4dab32fe8c9f2b2332ddb8258d475da6483f7ee42bc777a6783e0910d5ea39b288f76f635023dcdeb3ad135930ddb4517b25db4b3af0ce671ee231bd3fd6904cc17745cdfb26b99c6aa65e9d0e5007642cb321aa3dda6d2b156caf4612e65ad6e251bb687c7a132c754ee2192d8e1393d0e91c4e6c252095fdc90a9cd084744f04b9a88e874fb41024cc3d8baf4f0dbbbae2bc1c0c068da7798dc85971c908bbb81c6472f65fa8a1b42b56b2b65ed156780b9691ce75124d2210d1a1f692433b84c2fd23a348c4d63d33328a559761c2a2333ba687491cc48241269178944a25fd175025f37d9b0c3d38d865a9839987f1a044f22d130a88de8cf929e3c7ad245f7323d789c0ae6ed9f7598300c436e72446ac83dac303030a5124ce9fb604030775e498f3adba6dc431c9a841e6d6e9ff71d0a82da6403e9e085900eea9d3d1a1dd9a3c378301a01f385efa33cead81f3e69ebf26593b6e402094400e596d1c149ba46d2261b4ea2796cb2e9479994c7235b748d6ea31c7e67871a01f305f060f72f636db1ecedda86488286b195cc16a84909edfe561bebfe806f3dfda053faa1444f20028c61592683b7ee74c3a5cd719bce1181dcf72e8fe027fa4cdff6c3f6303efd7ef861d3cf74bc95f677fa6924a652699b4a22f86153510bdf657094d329954a9bfb38ae44459a18ca5dd16eb5198134b486fb7d0f5ad3fdde7fdb876cec625c2afda248b3b75f4d4b9c2cbb9619f97e1d06a604f327e1f552f624d472c7675f170dd9971eb14b7b2fcf3deedc1e54a4e26665b88461320e3454bca7d9b66b1b78d29f7c0fc1932eeb09bb91ef6178d28d940e136a927e52ba87b136d24737125e44bafb66fa49688de2be7a1cb2ad83facbd7b9a1f9e63a42c321c0db6692b98c8c16b86b5e0ecf65fabb855474ea0999636cf01cc7711c168114d3d050916a586b2334f45f4fde719e63944a18d713c55a3fa1a167604fe47ddc908d8f31c69886666321df699039c6f67410738c219b9a72c07b370901bf2db9eb3fa1f1199f1c688406e8e539c6c81be9f1c878647f1e8dcf00ff848696f524d2e3904d3f430fd9df17924831f446e6a60519195896994cd6f42c9b6a08eccd90b7f05b6df4ab8cd2c516f44823c32413532afda24843a3b3ac3a3794c3210867e34f68fcc62767ca61c66ddc088ddfc8356a68fd27cffadf9941e346a6711b79863723db388d7ce33ad7f8733ecde3cd38840a996370363ee34f6e9c868dcfb8911ba7f15fdf0800eec2b5068096f5f4d1bbe0c3a69c369972d0af71237fbe7e0dfde4cfbac8a636f28d2ceb89d323109e0d3454ecde5deee419aff127349e67bcc68dcc780d2debc9088d67fd7aea9e5fe3466edc46ae217443631b7a88e4a8369972a8717d23f97f0dadb5acdd9f647d7d534fdd77360ea59165ed3ea3bb7733e42628db31d1182ab4ba6557ad74937dd9ca11b9ba09a54660026b9acc683709639c791947046ff7cab20c671eeef4055a1d86614f46067b32187bdec8c3dfb187ef61cc84d77151042e5b72014697d2965c808183ad6599c9945dd665655c10cd035fdd665c4ec5c7638c31c618fb52d1d3df1262adb51ed997f85a6b3d224e113fb07132f8df77b750fceec5b854fabfeffb3ef0c3f89ed7799ef789dfbbe3efc8ee3e1ed9187f5804c51247f270d76ddbf62c6f5dd7755df7017ccf75a6aeeb3a93288aa2281e11693080591610bbfa65f120ebe966da075a4407b80e7c97b74d6fb73a501b3169197d0d831803b1f1863fd365bc6f7a347dda886963b2bd4db3fbfb066a24a524767b5cb76d1bde36bc6d1dc0db86819039f85d26771b0f32d9848dc8dca4653d6d9b8c163923f0ad36400061ed1438702f8661adcbdcb792c9e277dda6c1cda4e16fe30ec4ee6e71386cf73eed186b3a0704e2c35c122b533ab61b5b3b2ac184a4d1280cc330dc44222c8b3870efbdf7de7bc17b2fc69c05626827a99b15b01b71d4c56e06b2e40c1d5222cb382d461381ffbe6b79043feea28ffb34d13739037e9ce671ff3412eea28dcbb22c874a801789f437f369afdbfee54ece8c56ce8c9bc42193ad0b767d5656fdc52a0d744c985c97062e151bd4a31cd57ad8d7b561b34b7a6d7a2c651aa33dd8a86263a3b50ac740e999e822ee32e1bf87611e9d668f1bdd0bc187dec3531c668c690f5e88f1781bded8c3fe30e68e3d1b1b46536ee344a5986d2b954a25eff34a9fe7799ee7791ec640f8eff33ccff3e84d9e67f24ce0f5e9d1c6a6b4fb6863dbb0e125716ff579511fd5a5ae80a8e8f4728c449675dfde75deb61dc6bbc511d9de753aa7bba6bd63ed32591bbb6bddf6aef3b86fda76efd39af7eed33619ed69dcd66d9be76dd7b66df38eb77bdbb66ddbb661243c6fbb2949bd760ba2d16c6cecdac6ddae3bd2594e8f776f37f38e8847449a2f34b8e787761be9322f99b42f87a7998bb95b383a179ebb4544944771d350e77ce7be8c3fcae3f7910e7ea4f008f77ddfa74d22f08848e780dcbf234736f761528849c71a09e9a0461273ac236e7c4edca44ddc31a5980da6548281818181e9baee59ee7af0c5300cc3300cc38edc985f52292485208c1e2ff791e8d33a2286899778893aa2143a22fad0dc7bb3ecdefb99dddf7b2feeeb575ea7a1f9a1c146c83c233d8b19dd7498edd3ba92b45bf84e098d2d7a87c1e37b3dcfa35aa47f3081df1d9f7a0ff308e2d1457884f1a9a8c8f63a4f9b40fc0e8f458a80a37f79c417e9d13d8d647411cdc65a87668ff406538a219960602825919e9d4449daf5de913cdcc9c85099675946eb346c04be9cd76158d79dd212290465bc440a41ad61f488495aa43f3d8abb769791653d75dc69deeedd3ac6369af12ba679a41dd53a343445686852d80976629920a19fa2493fe71fb0b3e9b516f3f196b46f4dd3eca6c95ccb5da795c68fe2d6b40ac3306cfc2e6d96ddf3bc0acbb0ec38cbf2bd97391d5be632b7da2fed22ed21882f6b8c2e6991268d30ec15c783e932aec9a0329ee5d124d217f676ea66ca320cc30b913bfcce16e52b8f3eeceb3883e043d133f0f20ee69d7d61efbecb9cb64636f62c8fdbc6f4b8370e07fa7918ba29a151e0a74ae5665ca3714d5fb7f0fcdb7dee5c16e14c22ddbb566dd806514c4c4c4c0ce5c1a3721bd9dc63f46864c75cb381b98abb0efbb0bd219344e96bdc8dcba26bdae47262ce99ce1df370e3363eeab857541289b4c9a48ddcb88de3dbe8be4c3920df47380135d0d33c0efd2a8d73651376b9efff04198465cba693e2d860049bfede9636c022c6a632689b02059e800008a89a7bcc006501296150407661451528a89bcdd3082f88802557c1842f94506d364f1e31788ab0369b6b9690822e50dab5d95c638526a680d2ee66734d952c154069d8128640851e649bcd72c8053a7882b6d97c2f565cc102db6673938791c5044ca08888210b282c01655f739339c5145044842240592da98f116f9ba5129ca8a20baa66c9832ba0b6d89265d321f06c4a25ee6440228b0b50358759a0aa13a52d8f51f256d6487bedad4db49a85c0626c192f7bc45d94d45db5ec510665d9f33855db1c0496290a68b1ed96290a5cb1876000cb2db7e0f2c53c028f785735cf2d56a30c128748b145bbba8eeab86757353245819f5dbd065a43c517a0c66dd32368338abdb7aee350bbeca6b592527b59e520a6a59976e3b4acabc12ebdac2154a422fda1a3c70d4e0d54bcc1083d55cf0a3c96ea272dd11a5a2d1e4dbedad0dc20659845842165aa083164c04c206dd436957a9ed219e489aad261adb87333c5564b6e54ac97d993425a5b53baac10768f96d6a1d99516e26e1d2ab425152b0e344945ca733fca302e4b1e085a3356977388d68caf97f3a38e22bf818a219f5078a121868f618f8f251f1f651ce03c3edac8e13b3e8a928ad8c71ea48f37301f7fbcf05166a1f928b5c0f0517e4144722922bb841fe51729c64f1fe712cff17142f9ccc7d9840de7f1714271c3777c9c3fff3ece2a177d9c56708c33cb9638a48e8ff38b9ea3849cc738b96c2943be031ffc38c5d8f2f487d2004437b1a81ab413fa437dc813e0f298c7e57f001a2abec88ecbfb40c447bc9462c34b97325284bca429944b192e6f67b8fcfd71011c8786017c945ae07c94a9fd5162e1a9b1f9389ddc7c9c3d0190ddb98f538bede34c6d8965cbf3c84bae1e79475e72d164312fb972e499975c38f2922b061c7200801e331c5cd0230c0e3b78c880030d0e3b76f0d0e30c38c4e043071e3f80bea147925e72b303d9d023a6830f01fcd0e3d481c7817a647a24dd870e07f2711f7ac42eea90f1c881870ccff4928be9313b4c0ed80c7a24c5a0471fe791430c07e221831e6f1c268703657ab4712c07ec4019498f317c8603f9d0238fcb40f31d7ac91577f8e8e1e3403d00f01d2ee0007320928f0ba0c77ffc859c22ba861e2b9abfb083063de2c81169f4a89fe32fe454071aedd0e300725e80c1003b4e44671a0e743d5e03881b678701f413274034341c06031c0886c3a0c77bd100e10543a8975c1a0e74f558e92577007a0c0f835eb2bda04718be432fd95e38d08ed3a0c7fc8bc381ee2b1cee81aa173e8003c1a0c71da741eb71141e28871ec51c071261a081e14034a11e73d438508ee7d0a398333a5008c337cd71ae7f0272836e418f227baad1238e4f2093c6ad5e8245cf01c41ea885931e6b2e0239100e3d9e66f2926b4b2980781bb4c9e640317abcf492bba5146026007ac471a3c75900f140396c5e8003cd14e03bd0cd3573a3975c9b03dd9acfe8251bd0498f3317f592ed7420d1468f57ce4d07cab90e646bf478bacd8166f428bee63134f4d8825e726f0e74717c663ec7cc8172dce85144e340a28bf4f8890ef45d8f330fc081a61e73fce62d9ce621baa25e0338e3542fd93a3dd21a70a0f428e3e06b0df54028ee386aa03af2920bc781e685681cc40a32e33882e808320f8443e6414ac741f4137c20eb7ad43ef5926b4b0162e925578f1548e94095d3e30644f538e3532fd9e881a68c1e4b7a09de32072abda4c70a443f710254bfe9919e3bd00c3dce772fe9380ebde49a81d24bae8c035ded33f4920d48871eb7e3d04b361d07c271197a04f512bc671c083ca847ac97e02da506fd043c10be13238e02d2f4a8e3da81363de2f87619c7a91b67003408e0c70c3204e0c6a6c647d6f11e19c763c8f43cf23c0c59c769328ebf90e977e4f999ac63892d9f23e338659ac49617f39407409e7117b28cdfc832b7914baf91675c6719cf59e6cfa5d3c833b4a4620b598696543465192d1f934b50b6041f8254b69c92ed2e5b4860316484cde5ca4411a926ec2d5f35e8f9810ab6962d2f8ae8228c9d6559c3af20b780bcca526ad04d26aa86db2c25886e425135bc66294074938aaa413b91d407d523fdd9f204d0461c25a98fa9474ac59653531e22be1d14ad11042a9e165b8e5476f50ac59eafaacad249a6452fabba7de58854af96cdb3aa722e89544d244752d13ed3cbaa93cc4d77ac59895091a074d235399fc032c5c3656f2f85a169f657c681f4d2ad4c64e6eb356bc755600c3bae02db6ba7bf9eb7fc6553cef5f94b2399bfbf4eba12ba91c41cbbe6494e765b77b9a796a5f7ce93f734c96d44e47c9fdb7779db5d12b1bb6b79641204c976b93fdc6473dd0376f69c720b8374f72e3712d1e51eb9a9cd3c6aa3768f8252ce8cda25adf9f4a809c1846727a19be384d0adc9e420e60376f6a7b9e3c3607953ce77ed9f46d2a4c9f72e574bbb4e8f399de85f1e81d89ce838d413bdd3e3e4d9a24eb3da96b77ae9363791eb5b0586a1aeaed51d6ebabae44221db2792502b995bbb964df8a26b0fb3095f7b28448eced93eaf7ddce1d99a5642b7a673ae93ad6924f25cccc33c79f6e4d95c26bdf418fdee93b3617be994cb21bd44e4faa769dc4bf95e4b42b96ccad94efa76529614cf127bfebaa65ddbe4888cf6d4482e69370776bf32a7376f9bd7b58343af65efbafc523c4ef67cb79da4c7b949154744eb3429cb7d8d3b9ac68efdca92c87d77ede6792c4bdd9dc354e0793d9bdabf0f09f7ebdaf55d5ece4f8f54cbd77569da3f269e5632bf2c3797c78f7373a6ebe035d3452f9df3dde3ae819ef72e5f077377ec7dd7b2e9d3393037e17f076fc23ae73be85dbe74cfd41d1ffc954de14b99c4715a26c190465a1e3b9d43baa91bbb73978739be289bb88bde5d03f376980c9e9447a3c3e4eda41d29c40c750e7813774ee77c97f7c0cc71bf32be285fcff9cec9716e5dde2e391b60d8f349e6beae659dba2fad84ee790d4f81e7a5855110c4c543a22529685a45245b4de5a47a1352d16b0c2a7b7e57757a735e39671e4810fa7b9c7a8d7667572d2906c2f4f29e15b03da5af6e55746e8d3e678708ada817647ede7acd959573ea2b223c30266c16b4ecf9ead24e3b85989bd67aeb49b86d559984561a892967beaa74109756a2807167cfef6c4b3fa07a926a57fa01d5957cbbd20f984fc2ed4964de6aaa95cc3de9127e31d5d9d7bd18df707b76b17be453b81430dcf6d245dde85ea6dd078674f49d7ae14905d83e3a0e0d71e8611def340c290468e051676330dc4661a8916c1f69245db8f169b8bd4ed4712211c7711c2745f8ef1b799e17def08ee1a6f4babbfb18ee500759965997138c9f2e88bb95c8d8dff6751e77cfa3df2904687005d8d99be6ba1f19992ce3b8cb5d18ba8161024debb6980ffcba8bbeeedbb8afdb38dafdd348ba8bb8ce04941ae172e1c225cbaabb55acc9be19c603a7aff3905dd3b29e66a68b5011bb972e7269950205c7850b972cdb2e4edd72976d9b28dbb60c7260967526f03cb470192650cb8037d282960116a1a255848addad631887451de779187b5070e1c2850b172e20088220f84e4606ecc0c9030f9725bae67ddeab2222530e0116ef0a822b578866b805a532aa28b1e9317da98a0f5a8005087d1646f04ce182225c9003a19d9ed40a94b052821308696182951f68600b9eb0800640e80c10522ce0b1c73358b962a39452ea71406a7843ce90851634acf082ca07a8f8a0091f2a62aca0052ba882152fd8f6dd13ac20c1b6f61c07c45e6bc508aa426f6fc45a6bedc5af5620b1eb350e48c5d6082c2e50ca5460c5a6c730ada162d8e0a2342c68a0010df6f8635b394a2c5530018760db97ec6f826d2fa20009db9e268a6d7f334509db1e0705dba652302404832434ab0a2db3877a61e58a663920f5d2500595296c8a6f0c0161f6482d415f6417688b1b51b4eb1a155f6875abd95a29b56907d96408497da02847640749cd961179ec3ac8635ad6931eeb9554b77225da0802fe9e7fbedb06562ab0ebe50ed2b04b1b9f1c0ff79894179ea7919776ea110b0d31418b2c951a227fa85dea90d41099aa94ea64b2f4129769449c7a9abfd9969882ca96a92d535278d9527cb1a513b64c9d800953ee944159b6f4a19136dbe5af05257daa4d917a9a17aa157341ea662267e6bbdcfa20675e0421cdd6abd268aacd02aab0e776b91fe40c06ba74e1385b2b103a549cd80f3e77c3e00446b877dcf679cce5207f307c7ef0e932bbcc295c13b50156cbd6118093a02d65bbe476b05a50db0edb10dc37add52c002741db395cdab4bc388bf5a4d92a545eabd9b3cfef68134a9b8c64d7aee926560b0eb5d588f64c3731499128ad845da25e696eea8952bb65f2d8303c28d48792708077a5d7a61c2a4a7bb7e750b5a13ef2343f87e65077ee4ce86bdd2ca5c1b4831ec2847da29a4c14be77890ada62d37a6ac2c3240a3c87e66718537eb15e8a528a40117b9e1eb1e7ad127b9efa4cca31913318a016e3fb2a6318add829c54eb16f0cd393e76e2bdf9d652a2fa0c265526dbc4f265791523d99729828eddd37ea537db9526d995dea69f654b9a2aa6659966559b5560fb5cae950519a264d81855c1856ab4eb8edbcb909156765f20226571cf145078b62e2c417265fbe58f9c197100b4249e0d9d20a5b0a7579b283f501cab44376ec981e427b86c22e519333925dd34d4c52242ad392d341a26e3d4dab052551a68badb45ec47aba953437f5347f3068acca5689af60ab81ef96cc540acd947724a458553d54ac5ecd2b2584c4fca287d64c2fa458bd9a7a6aa182b4011617a0f458ca206dba7f9f5b6c60cf9e3c7deaa96eab279417a1e7c6000a58a8580951918a51e091fad01abb81274e8ad8d5e912520649835d9da4045c8f3f873e7feaa9bab8add777f9f5641dcb6e55d32a426fd8d953eb883bbbe56c88c172042b76f62354aceed6e6cfcf4fb591a8db55b9c105bee1013c4a214aefada7eaf4876ab49f0e4e9ccc7be78f3c5540e68e2b7092bb4df33b7ba6b4e9badcf313557d66a9466c5959aded8a3bf3562d6659b962f6549b79459eaae7c0c78b5d5544d8d57da0cc282939531d0333556750954d535460d9f2ca96292a2ab02507a448a79b4c940f374080c7999a58a6d0f7487dbadf6aa7d6e51b58e0cab45dd2ad3a955834d9058f4c4d3134a7a4a6f8b2f9a49ce8c0a49452aa43775311ef9e6e3251264cc57aaabe83c2415ff8506d3acd63b5a04c3b74f7eee9214c4789f554bdd326ee12d55da26ee50a4d3e1834160649ccd4901bb68c936ba062e5536d664a9eaa5713d3239e152d526da84f3d55afacb5160b43f6f566ea43c5ea57a64bd0ea266b7ea6bacc30aacbaa9a59765579d955555993ce1e5a53a57e96d8954cc2ae3e93c8b130f0c4b6348522c309a69fd5a760f4860ab4fa49a3501a14a5dac84cf9c162c527077ba45470291328618fb48a09b44851a19166d9f523b573ce392d078250f2e265eb895e622cb6a25ad8283445b1e460dbef8002b6af7c68cd482b28d546f254552e2ed5b9e5f6b40a0daaf63425246598a928b4eca02cdef692ea1317d81e8756f6d65aeb96da9ba4c0348aad5eaf57b6d6caca7c35eb7c9d75d659679d75d659679df5168bc90478be9ab3ce3aebacb3ce3aebacb3fe9ab3ce3aebdc8440e94f5cd028517ca82841b95b863f4880ab57fd830498f2d4caca2887367db5252868be6a828ab1a716a1ca67a62a9fca27a8fedc380993a87ce612160bad3101a61f6d141d93465a2aa8cd264ff45dba6cd942471ba5dedc84e168a3d8d8a38d6279aacdecd2656888f6c85b965a49b897431beff156d4d5a42970bd16c44a710405b2b0334b290aa1e10dac10bad1022c3af00545f31c7ae2e3044a4041d16c8a02752a44e019811628223c2d76a359c606503537994d0c31310414119814d546b30c420f503537a915684207544011314a01ea5a3a9490440a45c41dc2b5d12c81900554cd4de8145350d00545445804d4959755d96bed0f72669e0b1864d10545f38f24a076261194522542bc517156405a21ce02e35f71f67c230dbed7c3b82b95b85f8f347b14051ee797fa2ff532054514bb82bbeea02aa502553fb5c8a02e73280b4c0f4488209264d97550b13e882473bc1ec4b5b59f8a9992ba35fd5a8370a954c719347e72330a98e6b002631f67dde49cc1f2583cf2f2d4123d0f2a602db858106061440f76fdec526bc7b3e74c5131dfab671018f83be85e1bac1c4bf7f4d4fa2b2b21970d775756ff2067e86994cd094dfaec7929af6451654f9de49ffcd1634445014d7da50c4234798365f6b43eb7fcf86df9571b4fd7d0692cdb92521c65168b89714249c1900b3616dbcac1b6b80945ce58542e1646f54bc67e36515dc774fdf5faebd7b3bcaf5b435fa0c0234f72cbb0a1d02367e41ebf9fd0459ee4c6b42ccf26608033141bbe915ccff46c828ad68c426bae5b986db2b1213646c4c62e774c8f577659bfd6b1d3c0007397d93e50d1ca3d589f4d584b3431430e1250c817e4ce41220979ba321b875e5946935c96651bb07def8375fdc8957da0a2751a2af0d50315ad2c0b41b391e8641bd30dc8f6fdbd7acc7bac8e549b89b2eec35d82943228c19b9e5ede7241496a83456d05a6a9124cb176fd0da6dbb6dc0f2630762924458c2d854e30836d3921d84df6938b3db5d856abb699b70cf06cf91be01c4fe09166571a9a4d93019e1e3739a2e0b164bd3e4666567d3fe2d841cc8e67cb6a53aaa79ae18d692f576e233472a6deca30c899fa2af3903331c8174639835d67c032c072cb54133efb888ea103f8dbd62eae0e36b5f2079ba2e489ca3d5239eeec3b862684fcbdb431d264ba6f4e72f7942fcccb5bcb1edb16a556756f61d7fac4e16d887266c6e04bd733877878783480ead9538ff24bf7118bc071fb4efa5802411d1b041a5de6e3cd06411004c14b2118f072ce901dbcb665519662ea22c574195ff6bc8c6934b4a744855cf6bca8cb9edfbc685bf694f385ed5866e5cae66abd2c252505e6a52ceb6994a923b4ec7952ae0010f313226589c25aec792f8545723a7544d03ea2ca9ed778f67ce664cf6350f6fc6d62cf5f51f6bcf5b3e76dcf9ea90bf8ecd9f55c3b236a7dd1e49c61ce908212c64e3237044a3b49695bcf616a73b372cd1465e55ba9edec514264555f5155ab4c45e8775044a0344a5196be79a2345babad9da5af9c9928ab692582521ac59c17b0c24f151411b2081cd84114d4774aa7e7015a437a9ad72687432dc06577afae5d3d1ad9575bbce13cead8f4029fbbb3b0dba81bd3dc2b4b478749bbdc580df464d26eb796577087e0649f5b4d9102f6d8f4376c80471954f31a865ce2b7d4e9b1e9ab4ff71c05ea92d341a29c64c766b67559d6539528c9012952c2415bd620e2dba9a8b784266d8c98cfaed656d5cd0d438a683d5c9ac4a1a148d68a614ee6b6244d0f6badf54ae620a6767d8161d65655d67aa85893b0f6f6f8c88bd4e6bb04b3eca9555b50b5858a35e3f1040f0fcc9ffb9c536e2f54841285dafc509b4fcae0d30029b4915ca79fb7ae9980ad064821213b537655c9797deaebd29796eb8b06d06c24f6d52dbd655996752599bb01724b8f4db3c79d28bb01349b6a24f3486c906b9c1ac8bce6edd563f5c57339a15202185e3069104da1321f5e2cf414ea9b85de940704fc65de54058fb787c7123d780478bc7cacdf1f2a4201c3c0023c26b1fb3251c03fd74fdd92af2f54ac5ff6909aba7cae2f3050f1a93ebd5fa77abc5fecfb73a998e2051eefcf2e45c1b6bbd78377849bbaf355eebcab8b8e8d3df53504061e6fb6023c5e5a3696af2d25c0539b66769b0415ede57369d9f5f76ab9a57da5523762a5a2f404b63ede54690498c706f065e574023cded4beb474d1aecce92b888afb62d15e7d0badd1b858b982f45505062baaecfa4bf79d72a9a06215ba3fde0f700b5370123a34fbeaa9f4c543c51a64ee9b92a7fa54a9d2b78a2ca62bf078f16834448142059439a134416b2c17945e3e97cfcf12502e1f4f09d81e94610bfdc01713a5533e90d2e3504ae935e50351e81592c0aaaa2ad355c910c54b25ba526d46d5e6fba9aaaa32555736423a78ed5ef7d2004cb11e08325d7add1e5a73f55011caeda1353873ceebd2261becbe2ec4eeab497892bed9c8e89f6e22fa486312e0d18aa09876f80e1ed44384ffb4f5418d37a46c7d28a5d70c42b303424a582047adf49a426bc6faa50a187b68bc56e6d4287764b403495b1f6d79eaa97e942d947ac2a161be5a44f75e3cbbfe2405b6507c9eda33554f75fed42aa6f9b9a7e6634a077cae181288c7051e672a456ba490b5a5da885e6f0d551b89b2b4585dac2fbb529e2df76853f6a79eea45d94ea9a77a30db28a727f06853a97b31d6925559767b042d91258badb26b7db040a936403ed5e6fed45305858af543542e1f28d712b4c63ee1de7ba1d01a918787a788211e1e54bdfda13534888706f1f0ec2ccb6e0c4b2c71b7ec9a55168afbf3d1da02658ac9f2d9b5fede2de371efbd433ff766b9d7cb1dba5fb02dab7e68cd686da182d6d8a1aaaa2a8b038ca5c0b0178b15a2624de5236c4ad3a6928c940dd242f4d14ce1808f97cb47288a969f6a33aab751aa8d4fb5099fbab2c7fbc5976ad3e4d34dbe13815d0182115a5040d745afa16e02ea26e0c38fb4984f53e071a63250f5a953528b6d5333be90d2daaaaaaaaab2f60815ab0f582a9a1ed65af94a9626141a4198eef1619ea8c95db7a914adb9ae8b86613202da14f5510f7e07e5f9e0d1a6be6c32f25d74916e22faf71d944d8972930d0a201bf00045c46f30861628497d8c94cb09aad081104041e154304bd437848a15949cd545ea966a6353b56ea95ca88d44d5ea25dfc0565a0861cf1b2ac0e3c592ba42370bad1969123b55ef531f657e4951d17a9ee2a66eeaa66e6aa6687a703f98c09f5ee6480ad6526dec1579aacfc1f562572d9608bb5e4bb591a88bab4dc9999ab2360b1b5436555536556d7258a12f688db4616cc0caaea31563d7cd6ed935b5abb5959d5f684dbd37b553b4661689426b70e697700ab17bce54b529cd21f506f3e9680f5d68d2670b61e9142ad22954884ea936378268152de81525a8159aa226da45a3f6a7dad0b4000449b000892b590ca1e8b58ad91f1d846e9ba2353fd5c6852d768a159b85cba68fb2e947fbc5a6d514252cb0474b653bf186b070608f251f2f7bb458361547fbb32976a78d426bc6da6543416bac13e69cb376a936f45e8c4ba55f14bbe8405135554ff4180c2cf738a14c11481b8b0239a1541b2bc5b452cc9a2aa64d76fad1b260d35b608f1cb7c7096553a127fa9badd0295e1578ac5d36bd17ad1ec3b00b911bfb0e933d2b2cff60025ff1a9b235ba5db5feca3b7be624755bf555b5549498a5b56e57a8c2f6ec02df6bcb7481ad2dd305aeb64c17d86e992e70dd532894e902d33d3580e7ed1e3fcc851db890030c040c84aa7241484a8f09d6da49abaabaf6558ed5da55cdd56eb757da6b5b36d7add129691d87d02e64995688eba54dbae16a2babe6d8f53576fdac2a7de5cc744107dbdacaca63dd36c7b679acb16d3dddf512bb975571544c114bd286b392f2f0509e4979ee0ea4483f6e3593092705887aa277a1063c3876d8f5cf9464d5e70eac4f9e2a5a4329d5b5529975d6aa95bd9775a5ba52b7bd525da1db5ea9aeecea4ad572f228a980aca95ae70a9562654960d7cfaba9b5d65a9753cee85d358695a60d4ab3d6a9ad754d0d843ae1bd2c5bdd541bec3c343c725a40da501e146c3aa56c8ad5e0b26c55653ea7501e5a6b152a7da43c41b43d854a4410ba32e5a2a324d45a6b96556de3ba8edbb4cc8bcad67b59d5e5be5b747e487511eae1480d3835f5e3267553a5ecaeb4e472ecae2ef08eb098cfca999a89f5150797b3a6684e39060b7542ec5e569565b984b1dccbaa2c2762db4eec5e56e50556eb7647db85d4e852181e9fd168544776146ef1f45c8af982ed489bed9b9e4ecc0f6860d38fd3029b5e2cce29f807787e34dab2e66eb2e67a359233d4db7de51e8e24c087baaf7cc3909411ca1511ba99ee2bffb8e94163abeeea20e6187b017286fe071d0566a2e4eefa09c89aaa93509102b1c5d22969d6557a6e9133740b38faeaadeab367fa60787fdf00339132486dbb092fa647bc7d31f974237fb12d6317bab83159d4985cd3e3cde6bdb854e92d5300b0c7b9654ab58900a594522636a5f741b6ab66f2033c69c704d33a3bda2e6c81474ce40cfdc224a324272ee4a0d65a2bb6d55a6badb5d65a25a6f4f201cd9cb30bebf5f89862eb6a59a6498c450dcb19fa9eecbab29ea80b58f0bcacae8dcacb395f5fcdcbe46e69b3ad69b609706bb3d26d6653ce68a5d6d9764ea523bd4eb8251577c4705b8d56db52aa838a53dbba534d8bc4c74a2ba516b52c8bd62b8fd6a9fd45afeba2746b368f56b5276bc4e4e5680a3c4f4f3b8fa22d3349a7c545d3484078524a01d083e7ad911478debe3a0ebda4945655eb2b6df5b8e3c4a4955ad6754111033279021bb02b95a76c574ab2aaaa9f5665ad652b6b6d554929a5652b6b596e0712b0fd3c0ecda6d0269dd5d67da9cdb5c12e5fa27bea0fdc57033009e473c0ce539eeeaeae25bb1edb555ed36e550504152b8b43e794524a39a7ac5765a5cdbd00b080e5640b617755f58e2e3d96da597db41e582a5842063e4d780015832d4ea0a0828252547881829241179b2157b65c576655b6d2f4b8f94153575c10d4850e30b865ea8a943b0696b165ea0a121812b068cb54eacb90d4502a0ad196292728b0ed96a9d413f7da3bb74822705a66cf083e2d39e852a925b83b841a1f96c7ea141728c04014bbed2adc950c71db8a0628d8150da2b0ab2da8ec6a8b293441dc3184b2b7ce6007bb6ac1c40ca0ec5ab25a5073079bd797a089ed15a74d6dfb792f74e7172ff60614b0d8e8f1430659b6bdb54123d836e805581881c50eb278228b256cfb163820360650f064c8407f65008218e060d39b3011412842ca115e88604415720859460004822e8ef0831fd8266cb1014dca4cecc6608b4daf68c2a68fe180501cb4c52d8d326cd4587181952c5c91c5b6562ab0ed613820569c3d9409185020a394524aba5568e3be8067dbe3173cd9f6a517f860db1f06402e38c1b61f714002a3b3a8744cb7a4514e3245230000000000a315002030140c888462b14816e789a4cb0314800e819848764a188a93240862140421648c32881842089019919119022700b1e93befdce7735ac0c7858f9980a7ec852f010b693b71b19c7c8eb5bcdff64b59fc5a65d9850c0fac9c1dbcd142f73eac89db6747b11f920f66f35b0f22820bb40569b86f23a108f1a3b539885a9d90692c3448e70effbfced2695bf80127bd9c2a2cf50df5428977703634668d2635c33cec33a3a394b6cabdf30b8d4234614d1652e297550e85763a52d2726cb929b9b4531db8c729c67c52cd819c6377df6502140463e15a44974d289ee51d1aae6e79b6479baa79d5afcec7e6ebefe7dbb5fa144cb520d2360e2328fdd40fecf112baf7804ba25fca5e65f611ed3fbbf12745c129074a6b4b536d02e5b6e914be41f9f23656455d39c5830d7df1c550b29c6546b32128f255b1f9ca10bb4a7a9ad94f804b3df4428f06ec246bc57af48aed4e7fa3ff74647ab9188d589ddb52c600c715ec7aeb8677dfa8bd181a30ebab7895f4605ce87378a10659446aa0252bb5c6ae008e8b5fd4b1a53a8e28085dde3027da3ae70f76e1004bd40e66c1f9202f7d6a3e6882b79b87cec0325d2d032e36e587d3e953dea1ab54aaf7e9b92aa3d8d9546c949f1a8e427c3d2b0d5c6664ef578880bdab1386613d350202f07065d6f3824cb0b2d2f62d4c3d93838beba01efbfd8b8767f1f63c6f547c5833a04717e4bb5467ea05842d4d4657fa03164c223517e06858cad5da97bf7787ec8a26a8dfe401af9ed5ba28ae517f759c9313b09b7d22b844e4d2ee521c543cfb8c4188eb1289dba9458a63b3f2329f73266545cb6015bf34d7e95f0a4d900e2d4959c22312c1dfd89349fd3c52662d123ea4ec064cb40f129398bf207c252106ac9cfef2ce200dc92655d57da4be2a943c16159eaa803e322188c60a4bf4a4b4617249e22cfaba51f3a243e5996a3e568e77edf41c2111d0f965a1510052b569f2181804b2b9a12871f40aeacfcc0f0bc3be5b4cee1673c7081dd08f791f7f83a290948b27fe63593c716938ab3b972f7ee3b1f562a3d741e50387cfa4ed57f4fd71f3ef8f4266caddaec3e75f56d346dc61a7377bc0ed6cb550e3fcf77e3c319144b165c114d424e5ffa8ac153e4b98da865b45c4dd58f418a27408423108285f2708b1bb4cf9be5a47bec9ccaab25ba8e0f6f16b55099e6d04ec7bce249038606e514f50213abe16c5407625cf72713fb09812773df9aa98cb8d9f84603f734a877ac2b4ce4048ebd27f767fbb8f5ea6a0074c9dc9c65a89cb276b678cae6e1450c789312330dd94c9ddec4fc90f09ca0400d056f7c20f73573500e730f2b215d1e823361095c337a77a60476a310ff0cd2d10fce12d7f48b3e3ed614649bca0f45da765730958969227eb6663449e889b8f385a3ce2104205a8e038df43f9fb4ab8fbf32552e1f3f4881e23f28665e8208a03354f33571d2ec679cad4baa7f40e42dc59fb8c3bc1202043eee9441d303ef75148921776b90a52dab6d0084cc14875062968af24bc7e9c3c7bb3dce6ec327a7a33a81e85b0f3b7f53f8bef7df42bbd04556293f66ee71e30d1c29b1ee5ede96c765e51695531959e034a431b3b7686c9235330232d450f94b24d3789f3965626af1a14a2134a43087d1f4037181515a6ca40e71a5b87a7329c6fe7afec3b9d5eedd10455de12201c54fd2c8f3b3cc9f7edba38076748f2113938d31020d39d90636def74fc650f9e7c509b21710cd25978e7eae09a87967856cd06ba744080dc68ef37dd274b76a17ec216f8da35f1658c1c238ee0afcb06cca337b18f1e3a16a701b6194fc21cac87c72501b7682acb9c1e464b39369ff050e31df60ccee2b9746149dd7c75825fc97c8d1194bff2b69113e57b59d85cfe5500ef398622416f82421f70283098fd0af3d4d7efc032be96dd41d1135f6e88769284e8e5ca1135a03ab74f649286e564c7cfdf0ec3038c391ebb001234647d4a6ded3b3552b11933bee18ac695568d5c0007deaf31e8f221e2f54082b0f1195453b808515ae8065b705c5b91693a7c0b4b3cc94e381a3381ac88ad2aab0f87124a70de576d1addc97e607d24ab3337fc606a0d57de90fb4ec71d4250fb733bf1cd37e3dd041b55adbc59bc939956e6fe03dfc60c4afb4a27b215aacaf6b0c590c69520dc0614125c8cfa3a4d93836eab6d096727c3e01228fe82da65213c8182b78340b4bd88d3614e00b19a3a3d85e21da9a6774fafe308fe9a958a896b9535b2a308fde57b641b2968593c3894b20c4a4444a88253f4aae32f600d4f0e1387666e1056f9ee136d67496a2b609ac79a53c15c3aa4849d8d4746247090240c0b9b90534d819eef4dd1ef071ec2c1d533b52fb9f0db9df80d1f66e6b199125f9b7ac54152b8a7a4a75ce72bc45c91e1af1ac4ac6d52717895846636b6f2e96c3c47914a840d78af2fb0d4feb2f0f9354a72ccaca58da32400a0f34ee8714543a1351524337f6008834f8cf6cc5ba586f9245e4ddf3a505f2bf86d82683325d52ab09ab7fd878ecea98582c9caa5075d582488bb492e8cea5c1ea00d463e18c738aff79a1029f1e77e4b54962b10febe5fba360c16f83afde3c488977d9ff316bd389b199ab5574a8deefb192cbdd4ba80fc08aa30ec856bdb055d4e8f772d24a9bd2ba577128d5024d8a053a642a33f86b124355396e0bf9ded09ae1ab39b0f198fde0a87442af46f0c8045d2ca4cb2b23b033dc468ff5a7597170c48aa9e867bba8edf99995c3848a6ebec8d1c5afe9a3fb55dca4dec49becfbf531ed4cdce5646ffa04c45b434721d1c85eaad273effba7c9e98abb7aa613fc723904f5adb1a0fe51fbb508e13de8338d499bf56a244276b157dc9e20562621245b81b01089cc757bb934f1d0c94aa60148950c3b3db035d3c656ad0d2a5ae2e63b83fe421eb0fe5c39ed70ef34a2c688cf202befbd13353eca9aacb96f1fe1197f94ad16b8734c3a1a09e44a37164df4b1d4112b38728b71c041ef46afe63bfd297b8fe8d120770fa24bb0e2ca90538aefb6b8b744407f959b06cccf98946d04f4b78153a4eadbd7d41081287d9f5d5f6ff8cca14d2feb19f3c5558409a974654f9b195e2d24287ef3118947d3138edd55cc84caec0e15cc9937a49aa385b4b46568cc918f73cca55f1f71e651d370fe1d4e7360bbd9e85b6f8109a38ce18b36c3a6843d92c3f8835549ee61f081ee2e087a1fb568586c5d0773473e074b3d93d2a45bcf6f8116a4017240617ae4c4f3872a56b1ed41d85a3f80d68161b36500c6e5541965e15d3b0d13e44a347c5d6baeb282baf74a5ad144140b393b4209cbdd157c2a9ac30d83af581e842a54a06113cc689fa5a5d5e3d2161c4a055dbd12b37af967055df4d46025b455ea97988ebe524f6a18aa86b8dd6612aeb45fd2c190eb2eced57710c0ba22191de54d9f13127d46566678b60ee7d05f01df2e544e720a51cc0d312c545d8cd09355894feac135a307e16cd9cda754370f702405772eb22644a088461a7ceb0c6fc51597c52e476c8595223fa2cdc4407354aa599f2243fa4da42b506f74e94b401459b74dae8b72979f8a502a12d40b010ba85574ae57afa47b091ce0ad73ca14b854ba0cc087520d34aece2980494ee8e89b2dbc6c4c2361922c44cf244595b6bd0a2004dcac7245390fa470cfe6f825c646622bd66c68f984c1ebb18465471d3de939123109361a19518464f56149868f311f60cf51034130b0653ec15896200f403d929b764211f798b7ae48f2824ca0439ed01c472bff8e00ae0d71280327a8cc20045093d750802aa69f851ee194fe80ddfda6e99a13d13ab7fd3a4e5fb654d1981c49d9281789b4fe4f9c38b8b0db712d1ad191e682bb7e59ac6e304fb34e51bef5273dc8c37cb9209a960396f1f39cd0807f877fd7dbae5c738ad07adcda930eca9df58ef0b654045b08572a9901537e0001a5512280c195900a8f24aba845bba481ab1a71c59b9b7dc86348eb845b306a83fc7d114138dc0bfe3e9f9098cfa6e304fc663a88e8db8646f43ec1a15e38df68282fa4748b5d0bbac71a1bd7766365fded16fa576fd8d1d9c6c950849eeeb64a771010143c9a9b1ce8ae65041198ea6dbecb9ae37bfe380cfee1611c6fb0d38eb44b756809a3bd083a3506da2e449c5e99fff5b872e04fbba22ea20972d73d086f981e23023952405d8f224d5f19dba5ae13955f336286714790c007c8189c29f7496ccd49f0d16cb372c277dc4c7f948173555c89ba000f94d79d7191c1117dce9ebc5085e7ed8d61eea3beea46e81d10bbce7294c8254b8dfa905536ae3e2e33032cbba79a2cdb3fedcd2cd7d48b8cef5e6eb7bfdf81a0ab014e587b832520aa31f5502fd2008b323a0e89a132903323e9f054df7d833f8cc0e1b645af2025048325087a8762aa86603e68fec1027ba8457a07803c3968a7548c107082aeaa3c1c9eab255e404a54bf12423b4e8a38c5502111292bd7f53b2883448cfe8ac80cff9a9fbdda93d60c0877703e9905e7706fff5a353b24f745c243d1a517d6aed78c3197f758aac094a1db3cf63332d9cb477829e7b5f9cf28f9335f02326f212c645a7ab2e84f22c21c566afda5d63bc9d9940a12bb76b72f1bff0a83fdcf102c3d474e7afd79aa6b8ed7d99c26d16c8090a00e541488ca97c166bd31e3c5611447510e5754cfb70548cf0f85e302717e0092d789592b231d4a3a3158fd54100f55a46903dbf198bc204c4649ea195a42c29795f1e9224f5d01828b2e3404b7e2f0738a0e8a51048956aee5206d530c37c143f781ded15ab1c47fd57aa9a5e3e82025e46a889ae7629c217ada4838219d1fcd0999cbf2027253e97d3c0d1214842b32dafb4bc6d85a49f081ce698268036d546f752d6e7ea2fa10523d61429f03f4e22b9444fe465e6a3846d15f796728feafbc4a35dbecb07289077f5db9d57124b9d7145f606c833a55c8504b7b7a3bbf83a8bc21b6067573c1c874f53db1e2bf82689b23e8b2e6cdcecda6b7fdb5676af5a23065c987d0cda95d75ca56b54e15bed17fac93f2884fda25f3a3cea5df5ef1990174ade03f9d0e706ebc89e689eeb008edb9225177014b511635c4f494962afd6ddab2a8220f790154eb4b7cf9ec0e2985db334b543873a7c8789902dc258b23a4df0b8f275c2b8cce9e6157a59d42f14ef2a22dda1b5ea5c367d7799739e0a251f09aa983309dffab04e52a905ebaebd8a5647013957be1d0baa091d08a627632b54c053125267fba92b60cfd4543036767252f895a63707aea83e948b2528cdb83951734a45e5a8c84112461b35a2699c36f2b5d2455fb466e22d7f3a6a1ee4f8a60c96870b6376c461471cfc408e373ca8bf2d9ccf29fec13c17ce099792be28dc0400f6d973c031387ce1bcc6077e3ae0614ba09cc521c1c9a4c2cf028abb99cde300af93cfbb491d08c723ba28c713a132863d3b9b80da929c3756b3ea16d4c63b5adb9a924a7bea649f3cc812306a626c53d74583e048486a89887a19f8f7257d6b914b7bf23497310126621ab2d09ce43cd856838324c8487e758d4b0b670ea7f59afba5b9fde4a5352290b765b89171caac959f307676e6abfb052266614c4c1fbe24100cb4dbff2d1e5c9d4aa7824a8ce0fbda740e1de3981cf8a4dd7c56beacfe97459a730ca62639e2804370088cd04f10c71d383bef060ac56f5667b8253667dcdcb8ec81d2324742fa36264d55726a4124107bcc82146b0a547cf14a21ede0c0f51917658a50a6d4c4dd1119bc1c66519c288ee9359f3de69a0af283abc32340e70cc04d0ccf07fdb257389cb028f9609c9e601d80007f74e5c652ca60da29a4f8ec5a10e82c518a1372fa77994625f8490b650f14993724432231650f5ee52168e065784382843d2cf01d140a6488ef02ab8411f5154c8493da7d0072e0a63ea001040fc841487c700410a2831cac5efac1d51c42f4e1c04df5e2a0f9869654cf13061a579e32004c780c570bbc1b2a996b255a88151d4454f882ac721834ca734c0f12a49bdf2cc715c8a5832ae09ec305ac64ac963d36b4ab6787de1b8a27586a6e313ad84e8ccb8488f3227263cdbeddbe75cc4d229943b5112dc420a2ddcf18e7fdbfda15198567447ef8bbe53a16b3c5ab35a204753e83cb4e0ffe9819a6c9ac9599f35938c2cff76033d8ec230d39042992418327fca6f3dd383ebf0a1b0b399a1c3b4ffa80ea47e93dfd1535fb619c1d7d5f1d034c89f8a96ebd00a73d4bd0e1442d51907af368631a12c627e61b0b186c3f6ef38f8af1e22b96039eb983970c8c30e60f2424210672194ede810c7246fb7d84ef2152e06e1cd1dd1f15246110fabb1bcc3dbe26cd37e7b96efee321d2e14162bf574a4f51f8d389235c27ee7de7390e061ab4b8b580e2afe09cad1809ebc13f22428e7835e670f246eb429f448f053516e0a7c384754ed011f6ccbbe582d7093db88bd89309d98802c4d70fd6c9010e13bd6a8473007f2289d68d816eb8033c1124280903c8462b23c042c5f53d8525b049d89ec205f5d109593b950504dea5ef57314f519097a4f902336bf82431d358f1de5428bac44e9285d4032c2799c97332ba5c0039846466e4e6511dd6ea3ef768bcd3a5103f072e9ba2c974e72ada1a94b13a14e8fe76115ff822a7cac026a184bdb7700027802f099f79e0a879ef49c1f6fd8aaf767bb153c786df33196cf73eb62c2c8ac5eee13f98cf9cfb3c82a2ad28bbca754232204d10a185f5fbd8c0bc75f42ccf48ac69381a5014473a0b74b9fabf2e9f770461defb2c2392f50d89ec3db1665a0336d6fe2a27c8101c58604a61c3b758c00b6d26c992ad299928afc74b5476ed3edfc374d8d2a42a87e9ee14975494df27ff6f0ce853dcc7408b820986f63e0dd431332994c9c446a7afe563c104b142bf778dee89de7cd68dbc514b6ecee274570dfed845203474bede63c7ede08904b9ae37ad655eddf092d4075cd47172ddf654bc6f5dab0545ac07c28e7ddbef50c19f9f7aa2d0b4ad11b6ce75fe59c17867c35312aa1d1bc34ffd52ea4542ad61ec014732de7fa3ffca212dabd14312004f6c899d114aec3eedff640cddb934813597e71ffcbaa3505e3ad2dcb6de37a05e77421d06dcadfae5cd63c8e0974ff23a31acbe4fd25755c83470c8290d3dd0648962d8f47bcd28e6e16cf442f7cfd793b3366dadc93f1fb53378261a5d1bb4902caec9c5dd391904cd57b4030d1c53600d288a22b8461d4448c09395fd3294e1c470ace2a2581e8bb307d8cb9432a601e1db6e51256c75db8938e5e8eaff2f6a33d0240d150dc40541973fee91f8fe5cca444cf05e8f6173bea857c814e0d87306a943981db0ac77640cf2cb49f414e47c04787784fb2902d587fc415a88844ffab87e6d1875d6ae6a0c2cc0abd5af09f67a03d35cc444c59d10fd2e0061d1a8491035dc1c060f2f003f944958660c02fa3b4be3646be4894228cfe88a7811373a6b344ab8e98532ef8e66cd201c11de1b2b49b138fa4a48e12cdc01f3a1beaad1c408f2372a60670166298e1ee5a9029bf1a832cb8fb5344099b5246142bf2997c9e3ab5d024c549a29d8b8c3fe34ed31f098e5a6c3caceebe564d6ad6b9ced3a5b86381dabc06ae6a8086cbe389e43d2746cea956ebe374bf1e1087e2151137be3b6b42c1312e5addfc2563d33d3ec7335ce7c02133c299d7ba03aa7433b061e9c612a3170a5fcbd07cf75839352fbdceb77dce4d04f2faac3c4b58638d24f97ce8bee207dd2db5fabe81b54bf2ff8c0cf96ea867607e0515c193d4372374ea595dca723bd2bacc7ac642d54dd046dbd60cb44c54089a4fb9300b80f9f93ede815922f3dd3f21852db89ff4647c93e4ef8da44e122d346580e4788ac9c9bdd92c31639d7cc7e790b6886f81cdc1f898200bcdf2938f8831ef6bb3505bbba1f682afd60dd078c841ff9c3cb96d16d7d32e74611fcd35a75ba27e36d0f8f31fd7981882820129c7c540709be084406cc81a2aa279458521e68e409b520eeda833c236d4000ef5b32f5042805385b99dc1694cd973d0d40b461e6fe36db81e59c99b92e1303ee303faff15794803b0bafc0f5afa5ad89d6a01aa337f57b14450fa643ae51805e6fef452387a6dc8421d16be51a5c1e4cf3d60062ff60ed4f957f6253725d49bc019d5854fbab2e9ae9f400c5fe26e25e32725dc7dd70820477c3e0cf717cc466ea739e1cf642c2820de11ec469b182a6c118507efaf8dc8c928eec02f7d2141bb2639d2f40881f559e8dacf2f0f44b44b13839de83e59c40436b9969dfa29810091a3c74671ef76a59d12063b6ff14c6904c44e37cc2f5d3a5ca5124ac60a4cdf6f6791363d709ae05ab60bcb006deef336d47714912edf0ac49d8676ae750e46f1764a2aaec77263143d798f635be1d2dc1595cedbf2a3f08f1aa8571d34cfbe92a7284f8eeb76fc1aeb71f5ccd703d223de5da71b11ac0e5f57950580a122fd2fef8445805a49d4027ef790216a972220b6abc7af8ea8bc72248570e83033ce082a680c4906f01ca205c3f4071a117b0d5e84806c81e4f644aebfdd765b70d37ab4c768a78e1029f63780cbe47571d8dfa2d2562872c2162887c4202b3437594843473a76712493de5712349d28d8a3dda8befb00a22a8f0a1508bd80c0ee298b31575b10cdd19bbca815796b7820320ec578d1ddeed24f3d5443110fe1520a06e614e52faa645d2069a6970e65a38e68dacdaa85e1a3e52bfd4736ec085bae2007996e4195f430a6b827c2e6116ef2af7e9d4565da8ab407558bdc2b7524a5b95c5526fcd38c72850a117e80f1c47b5be8cba9aa46a3e19d07d4a8ab196fe1f917ee798fcb70c65247bf9eeac6070e9208c536463102ae64ec8a4adf9f7f63fa2ba0317091e86264cfed88f74a54216a4458d7e08edc1b65f5caccfe78bc23b51d42436daaf7cbe87e798a6bacbdceec827069cc7e15a509d530b2dfcb10667d11b255aa1122166985d179d60a02c43d615072e52590a8c4d60f080c91159d1c854a02709e36a499199b46f086ae194a3c62e516636ba5ab293a0b3342bd0d03fe4c5183fc5af52d94d6962d8a1ea307a5451d45971520dc01d13355281c42a0bba012f984a1616ee98a232022fb0bce98269d1dcf720061ac9005bc6ecd611b05e395c4d0c7a330a2eb9e3420a20c8de31bf0ad9b31652391a686e70b07f457856a1e416d82e9233aa7be8e31481ef07fec9ea219d367b7d222534eab995c450b49249eefa2ea39e8b2b5e5c6b124659cf1012774756bc7b2cd1b3e2272ba451b9adc2a31116e149b8000d2ebf1eaaab756f76256da48196d09c3796c01374db6e69ea8fb007da9f1255e2b1cb55a6a95e057e770ed5faa6408bc7ab45dde79cdab98f6b83a80a11cc7a92ec100f9b0a7ba0756a9eefcd1d9c9b079591a4e29447e943ef719274816ebec26ad05da374115a01792ca79f524273acde09e5c89e01443352f43a59e18300ba81a8311a465d99125fa99101a1d0c532e25f11cccf8a93151c1048b073a21868a53c25f74ba1d58fe9a324e5e415ea65b076398080be06d4ada2c873b5a92dbd33c0fff3ae0556a962e3ce5458152a3abb107c93352a0ccce9bd4038fa50096ebacc903af7136949814a1de449256cc9acea86ae5005fe93acc2a5d18022fcee71f4be00216f79477590451dfb0a224998825dc6294eb066f54e1272bbdcc358597a084fbb8facaf9f28e85ce09afcf624fbc154d6f9d81e61200c266b351e64048d17b3a57b966506abad6ae5b7c26c7699681332a798e68d390bb7b243346ba1422de20491e16950c3b5ea66f632df32c5dce272b28bab9802c4c94ec85a9640a62e0bf7b34165d725c5e7747950e22449aee0b716614046f633aeff930dbb1454d6a584547e5c7dab821e4d5233022ecdb8702d87fe810a68fb0b96a96e8610a737c725e0766b7182ea961e9457ed8c1a61a589039afa37ce4ac539beb34286f85271eb3f6501c0a7e2749f7cf1b6d27292d0b48280f5604edc4cd7ddd5669ab31ca2e1e4650353046491369545f4b5de64164120369db736ea0dd79616682572a2fcb4b3c74660c5888322a1578a777ad838b1c1fbaa4ae20201a0529e88370e5c6bf97d1a117426e7d383fa48024a720c3040563b0516d772942b6e32ded0fe3d6c107a6e929ff377e665c5413c8f004a27999a7fa50fe8342ab300f0f8838efe441b67e4b96ef0fdbc1fd9b4caed2ca6c930ca796460421d0f1321b8482fec8b60a27cd1549fdf0063f887da879da28416d5963ae92485ff25015d2c752fb9005b47a25daae8069a2837da92cd7578598dd5d491778ef0b6d2d269f082bf28252333022190f01cc482b8a2b8102f15268f109057377fbbb8c57257eb841da8ac5e24856da0c5acea340e517e4aca636e32b6b0daa5021f4a665e3f7b7c78cb78709a09271222f0a1f78ca32c7d48c89844ac6e842fee80baf1b1c341c0c45d00c6989ca5023508b7fb402c996bc36ff7d4981ffb335b79342b17ecb990df542f56f67ee6b8f0901317d9108c84cbb53451b29b2b33120a546f2a17ff5a12068e8fe21e9c1028c0a6b35c29317560b04ff97b3e4973d9540923dc41cbe89f81ef77e7ec73d83c0d87818bd2cd30617223e70f62b313b2323174532a4cd2ae2426d480cde46a89230b7e7121302d19082151ff07c64ac622c0a17a0c2a84128050d220776263d7a097c051a7f9780fa6cf3d2e4ae8427f0c92ca483974150df73b2d1af7620e2dd809340da2d221b18fe3b95cfff54dcc911e2e8b31e1ff5ffd5df8f5e771b5da12e1ccf8f466b7184f4f4b3ceeca4c07b4a644bb442de1089395097b5195affd74bf26e66470c74cf418144186fdf7c5a8c5683889f264a018e58c94941138f00dbc0d783011fc65d3e14ead1e6adf5338971167bf316d849773891fe4f7b76baa9212f44cdf3d4adeb31cd021460aa47b6391c232aec6467d03a1881a07226311d21f38a4a5fa98ba32f397c20e721f460721565864b0285d5979f860e7913a9eb3f8ee4757c6cd67af552a4f1540d9e382a0426b9dfffecb9ed4696ea8a30735775b0cfa2c34c94527dd7069e8a31c1dfc96b325b879b6908191740cea711376edd552ad4ca91cb857700def9e7997122180cd1b5bb1dc6be990182bfb9ae22a7a1ff595826059510ba3b01103faaa5c868ab5eef41deac81b9c6072fa6e8f5d1d8bb5a0e666b07960330594a7a50552dc35abf4b8f4ccef841c48721281098df1b9403266b77dafdab679b32fce61b7777149655592edaf34351fb43d8cf6e9d06faf4ccb745a48a982b9ea08c4af3a9fab2e0730331664a8caa170e53a47371b200048ee3db360cda551744ab7d3b89716534c9e6245a6e39ac6d392a99a370f0b874e46a928c1539e2bbf38ce2a44b27632413336f098f57a694526a304083efcbee8e4afd9d2e4af5737ebf368fa8f18029286e81a94407a3492825ca3ec0b6bfdd5b5ff03dd02b1a680ec269e29e35ceea4ac018bf26def385e2376447eeff477ee9021f48db8315892545a4d203ad6086551eeaaf0e01c2a8fb5cfb9e53259bb13250c5bc0f62c0cce58e37307ad581abeadc0a31dd70c106f0e58c2bd53d3cd29ab7e308c5886bc1a4e5a10afeec2de0204aa7dab9fa960e09b9da507436fff121de78622d267b43874be7b8541f79066e1ebd6cde6c223617d7fc03398b891cf80f46f700902ff0f6400b96fe2dd0cceaaed6bf2c95f3bb66010352b3d3e3c6b99fc97631aae9f11d671b2fed069e1a55f5c58117ab926238bccdc54d6cfe2597301c428ca67c4d07ffde35923ffb44a36c8d607a3cb2db3bf582a9b7dc8fd0bd899a6768b28ad801d3fac38d928e7fc604595a9c89afd43652d81b7a8ee23368a9d88dbb375db83f73bd675a220f96c64a980120aacbd23c81e78402c950b3cd5f379b38c5bd9aaf9e1fd43b4fd63788f438605b7af472774fe9d7f349bf9d7be6d363b718f8628f3aa2c78b6ef25b5536e0993243de5f0ceb62dc1ee60c257e3c40cff3a33005a51dc16c79213242248ce8c7e3565838e38f1183fe8ba47fbb8c61f1486ed6678d74f1a7846d2fa6308d8371fb209622e3a291af983f24b2b183e199872fb863e0c0e2686d4566d0620888a5c194f32b59d59b2b0f0ec795020d7ae4e4400f399e8a49f81959681ba44d99cadb6cb6087c1f6f2680ba5a5bd29e8aa867ee73017996dcc6a93b2c4b2a7e10b468232a20d79ef6728d3c76a0850f799f6baba86b2651e6d75e8febdad71f46f9bf6638fd7d9638617aeeb92dc7866bbb587636f8626f198d5d60c0fa1f88abb0e5ac186cd4c51354c980f1e8ac2c90730d30e585a4252d46f87da5be7bc74501f821144de6700c43e52201027993620f9b04f82bdec153ac1dd4ce126d2cf083415af33403025f6ec391a48c96c2e9251246622c88c80ddda6230ffdd4198d130b8fe4568858824a174571262880e6ce1ff2270bf82f443b1950b7f75d73bde42c10e2dd29889b5e2359250640be1285a041ded2f5ea092850c5988caf4d03bf6be85a7818831df5f18b88f5d088db3cc6d8f8ca48d36de28b960f64261d5e9d7e931f657ef88f29d3285ad63dc789a9dd3a387abc8a0045a38c1aede2f94c1b20c270892d33554ea4cf71ab8ed30096583c9985957042c75161b58f158daaa0b3e135d2f0f3e41c335246418508562509ac6f75ed30e9ccfccfcaa541d6a73308442ec4aac45ae38a89538a81f405be040e5218c683c2f2c72583cebabbc675a0fc37cfd921b5d885361e5f4d29c6b791b234e4007f367e4791d4518bd10e4dce1d2ec8589c78d2319a2c84f3a325ee95a18fbd3ccaf71652e83d2133f940da21addef78c1d6919b0d932c7eae20908fc89262bd48df34e685b3ce73bd71c146af6dd416dfabed0caa170a9ea6c6ce49d0846136f64dc4e5d8f71b4e4f6c42a0c2c75a8c586dd8eec1770189b8d16c1f4abd3c30218ffd66c317f4838ebd1d9112aa367722ba69f79ca1f9b644f1ea5e62984fd44ba8beaa84039f8996bfceb84f21aa8f7585209163002822005131e59c9e3b9e3779c8e2a842a294b20a74330b222ef27e853c1f5982f9ba9c97f653833e55371725875699f882b3fa233d062aa0a100907e1f8890e635e626fc384e63dfb2fdb477fad8dd7fc85fa5078723e899e51944ae0a37533c86e8712877f4185e675428b3d926d5afc78638c9224e0e7efea31fc58353a780d48ee0925f73c6b8e0b46e3d7295dcd4a90d81f480cd922ebc2aaa551ae9367504200dbcf540cea9e603464dad240eda57c823c519b9c04aea8a0ecc62699316ac0ebefe60a6615d9688c34b89e12bd073299030dc37bf99829623a90570f4744adeaf026e523f4b448b85b11f37f185c5aaecb643a5156990f90640249423a1e6818b173bcace20a4713c2da217f3ead1e1fbc834d929bd814b5c6031216d97235372e332c4204f4ff855743880c0f195247692daced14b4ecf2d08fb0d399e74843518e24d1daebd8e89c8d20234f3eb1c74bdf94dafd3d1452072425310ba7c705b6cccfb5643eeb816a401f4da310a1e5d3f95abe3280384fc6ec431a4b5087bb2d3275c9ae770ff83a489675ec672495399ea2899772bba29b48d7e3d5e59989087bbd7a4625d6079e36b5e237bc037b81cf64cd00d44dd07cd8b3103f160dd75ac3ce6a08dc8f9104851d3beee2f02fb012dac64ceab245ed88828b532ee558d2a40074b235534af4b01142a884f8bf376320ad21f31b8b4071e26dc5d9f278d612e3c2d74197be443c1191acaebe6a94dc5a0302c4d001fbe079c548337ca3cf85596f43d5543ab3332324e23aa9a1ac8afb5203d37ef1461a4f3e72df909d073cc8da23df3233fd8decf9867079838b53febf683f7935bddc75b90728361fce4e598348f53e073eb0f60df712637008a104ec368695236e9b0a60c5fd3f877381b8337df30ac046c81de265a04456e1f531376245959c74c8903c64dffb25debb407a5d11438c1042ccd0280c80140acbebb22398f5837962e0c52913ea14b2bc20f7f72c6b03ae82fe3e7e1b21310c0902e7eb6aa50478c99264c9144f8c1e62cadba04fb244f44e6014434aa8ca7a525fc9505d0680451a33b7e0cb556481b3f62f74ec06228dbc48b51381affa25b45582d284c0abf5a5795b9e35e701b5ae622c9daa3263751f29623178048f601f4312d399a9d2391100ad40e4a223c23cd8c48f7965950a8c07eab7534f394ee1131f7720f368c42ed9490a1b75fe22742039d7212fafa1a1f9470f92b0d58d1eeca07a8a3889ac798aa02564f901d6ec48b44cd85a241b9c6bf740261bd8e863fe9bb6d65a0dff1eb678f1ea75620942b3981071348c6347b5568765b410d591dd91f66c0b4fe99140f8134ad9c12e4200bf761b408a7edd5ea3e9647f163aa1e0d441709df5cc80c711244464a094c36da9613a59f011171ff7ca45106dbb73a1f5969aea4045e31b3b117874e28b480c9504bba622fc627fa3ee33438b029527636cd0d585f038533893421457110a32754054f2323ad548bbf092a7b5041771d83b11d765822cb0351aed0e4a171d00b5db14449c89b35596b7806038aa6db001e7910516bd3a0f1468de3c60e56bba6026a25de32fbbc4516da67eaa23fbbe4eddb9f6d94eb9fedc5ed9e2a58a7abbb752055129214bc34d842b725b31a10ff80253df240944dc2fe4a733e727991c589a2ef76c23f22dc9f072ea27b8d6ff4966a08345100b8967ca331a5e963ba194399226b548aecc9a471b8a9cd80069b2e1affb1df323db692953ee1b46822f2c152f359085916783800aa85cc7d09767055eb97106870f50c480c8b9816c5568da5bba37d1d3d6378c944262209c35ff965142b6a9bfae7ef22f680b02b94012528112ab2dbe44126cabf80d8098b111ee38f61d83eee1776524b11483a3a904a87daff01e4f74beb073ec5b9d9838dddf1cce8c23fb634300846fa678af7fa467ce11fd69d3d2d312ace3becbdeeed1a60bb3b25b20273e35bd0471720c36747ea96d18e0769de2b190cde1cf9afa49fb09323ea079ab8422ccdd5f48f510fc1553ec97ac42270afc9f94608e517907ff80910e981b2d5a546364b55bb653246e4caf220984bb9e871aac4485bc6896ff08ad76e6a319665882a8f5886f38d529bc42e67af430f039857fc6c146e66b336e31455d33a0742da43732d82689da4f1b7d66fee033b5966d389b2c1e30877fbc0b3d1c62343cfeede4bf31366ec09e39d484742cd8b0c34e64473384a129cadf9e24148514249333b445c080e1972308571250cb4bebe5a8dadabcd2c038de7d61feda0980e7a5b2d66683324a6d1f93a458c2322a0c2518adfa94e1769b2927abc7b2ba9307891aa8e5257b941d6942765403ca8f101212d0b650db3624a4c285ab4f0c81508143cda1ab87f37240204948425811513d707742781dfd07f8c83f272e3b3141055cff5b0bc2b9af419ee15a4d1c3aa506458aa3eb6d6cc355e33b1d93d34a0f72e81575268ef911dc4bd2be2c8298844d25f1ad7b357782d5429a42f2fa44cca4cd7f4f119a50dcfe361e006276f551cff6a2b10293242011cff32e92e9c344533c2994208f4c869549c96d8ca321cc25efdf00f39ed53eb8612c9768fb6b2f19baa148a5b3d0de40847b742ebf9971266dc64d1cf68fb4eb88a082f7998a48c32baf62a22ab2bdf89a185f5a57660e4c44d7906f75ccc8d21806fd271c8a787ef836ff3c47db033d30fcf46cb97ccd7a53b14e7774c13019d73aba6c2dae52d205f55ad19701112356d1971fb51ffd5da4ab7a53e0db279be7d8548a418b4fde69db21c4c8720a4c4405dc5427eae072110c2e4fe061c5c238ad7ed508006e75f3984b16b03d73c7826aa63d23db5df6635aa556d11217c83bdb22fddcc56f4239a9b77d8f62f51638e05ff0fc6be6e75d28a570aecdde77fd44ca22d22315af2df8281fa533e9fb2a142fa9c5cfc8389a772287af8462368904046ed1e2d0b0dea346a7ffd6bc6f56d09ca5f5b35bb8d7c48ecfe8164dc8b4683a30741ca57bc16586e810033d849a51cf6827396c5190b101351326d6e1a8ba546f17a9cd86c823224e56157fdcc075202c90b6d26e62be12b7318ba828052abf770c5355bbe542783cc39a45039c82179eecf5b0e5373415e9f5f6802c6968d632c2827af3caa110e8981bf8841ff2404ee601bcbfb1319596cd3cb28ce668b7e0be5c1d6225110377604f9efce338bd41398fd0d2e04997e2282dd3778122586b3ceac13ab58bd80ecbc9c6d52d0752233830664018f6220afb2b9a48ccffbaa783e41903d991f1619f43fec4a0f08df0ebd503aee696e60e075c0076e219b6f1f2c299931ec7f41803205bacd81ab6a395e3890ce5abc6feac6e7f2eeb4f2bb55de3478f970e902591b9f87a9d9511ec594ca3959131c1d45ffaa07c8cebc71903d5910c6008267f5bba491e18c9dcdcdd3c13923f7769494d445889cc7b0d6a4c48ff7606e7411bf618444c2f82ffc1ceff38b4d6543615787b0c8e53c6a57a6599ae1dd57aadaca5290e4893d5b87bb7614788497b09887c35e4b14a6ec84099d96b6f5e5793f3380dfe7bdba579b297d5c45e5eb5dc5e2712ec28bcad65c1fa941236ece4babbccd706e7765ef1622f8b5dfb938d9646ae3d949a09f46794634fac2d7d2b0c725801228241db2ef8f73e278af27706cad70640a3ad3d43defb9b0f189a323aa3de5a3b51cd4e63995c9a0cefe8216d6e81bc27f5f96dad6b63d0e25501527eab3c4614e6aee3619cf23c77ec62ffe749f36fe3d7dfa17f5d99c941c521f311f89e8e320aa04cd8d1cd0d76308a5d9a536bceef8343f34645abde4aa7097a4256dcfb0d45b1891f25f35fe592d8b6403926ca5fc72ca4da0d37df004260dc2b2c67aae102cbf61f1cb79d4b507c45f0303f5f84cbb449d1272a36ac36fa48d2526a6201df6be8f736ffdc1aa2a8992a1e5b1508cc337550508db4dc9c06d120731fcaed45d44df3d3c230e06a396d1ab492b3ff3ed012e74ab2df4f71199657b998628a484a2fefbabfd31ad4b7f440a258dbc232dea76568233d63fba01ffd7d130efe6a1b3232aa99b6ed27307eb438525faa8cb84c54644dcff6767e0d0f66e65d9b6a579a905e761e682e9510257b9c265670e54b9805ba3e60dd1453a977c83ef926db342f2b5ecc7de4fd399b8d92065991959b0c0d4a18d6405e180003d38a34595f75ebf18ffcd8c58b87b295797aa96462a14c0187ba326f6c96eee8b8688b54aeebe940622d639c127bc41b8cd70ac9e38da232840f34132d9794604ad852688c2036507260262a56646748226b2737eed5b1c17e7d7fc984ea019a0d889fdd0e84f9e384f233aa342632738724c88e0d7b214b43b1e43be38270b3ae19264d8c2dae4c796ae10ec1a71198afb6b2975fd4d1e4bd42a86c486353ece288bb252451ff4f455162c97f8be79c055116fdd816a65acb922f1a03f1507715d4488768fb2da9c580c10e34bb1fa77291d143433575f3487689c5f3c79bcf4601b2aa84397736341c2617a1cae9df3b8e6fa6f1427bbc7e5ad1e184e02a55fdf14239c77c1287bb331307facd5abccb2c0436654985e8cf98d6083de7643f617ad093241480b6595214766bc04a90aba3902b223477f738c7c3627a6ffcf71621635722cbd8bfc1c89ec45bfc8f66a71d8e031f24b2e8c948e0ad780e040290e99e70aab08dc3fd88745c7510fab53f80678db0889b2dcb4b3604b8b59e8251b328ee077017c1adfd610e27b96ef34deb20a5ed65752ad013986fcd0ce2287312b2003be2a014efbdfb637a85603d2dca46d2cf480e0370e5c8f805c6de6592e2e8cfbf986360e93235632dc1d03e8633c87ec1edb1e06249ad98cc016a7be5080cec72ff002ee0b9ef1981cc9c81d5e414761b218567df65ebe6374dff8c441d142ce4da60db2fda48e4178a3e64e808d194bebb30d16bb75600298e5640f062bd8508ed75eb0bf4601d0d99e08592bd0fe36c1e39f1114e5be04725d0dc9b3052aea8fb144863512b608295dc55a9e9e986bb1606c398c6b8ab129c6383e19d3659cc2848ffba90ea540882badb9641a42ae607f20fa81fe50d928f303854f4e5908b666f9d94579000a6e94d5d199ad28825f4760ecd44c5125ade787454b1bf900ee5403a5e70429a4dfdc4832d63b1058f4793a6fd908b275989806d6b3ecb7370600623ac94019dbea72e493fab941a84a354a75c985aa3fd65f7335e04c6b34d9968e5a2828328c30718705da3a671e89e27afc8a5dd6107c3c1c44e041bf8e223a1391431bbb4354cd3a4029b4362a7c9f6798dc8285ade3480875e6f9eea557bf4be954deebca3b5d81b8f4a25a2bd838c61a6c63ce6cd4b8ad204779e268a065eb6dc25d1075f8752301d3c194d9162d8d90c9e7c483efd974e6283250ce97c02ce22a959d8b092175f81a66cc591a4a2a112c8cd533185f4d54a4e2d0ff12d823906155f832a0cc89b2dce65af25530f6496c5a8bba36c0f69a323179a46dd6c1a5cf73414f1acfae0951512e5bed02148257a18f30e188ad45b68b3cc6115bc26b6326b18126a2e5b113b0514aaaf071b682a94af1fc63cf7605fc9993264a6099adb79e88470444ab2a659d0b635013a0e577326d7e55336cece5d8380437071a36a7bdd33c7469888cd3eee5d308084aee362f5d4f9f7f7571d06c8478d9a2297dd5391f04a969abd778187acbe466daba1a7d96614008420c67794ed6502a3a4aa016032dcc99e2270e0957e90d61f7f3d916e6a441bfe6120f405dfe859f0c0de66dac3a72b71487a482040f8552052a0e44403594b8be1b7460d25cba4727fa8055fc58f179c1193a1130c8a5df010ca201a80f756aefc1b46e6260ec64b178aa39f859408455e18796ba7ef187285df86959813c72c6a71cdbc4e64d7b2ae7b371daf156d9a36c4d26710f9ae0b3b1015c0c8bc870c3b800d9c01f204dcd5389256bb46ae71693a3ea53a91515bc5438a9602d0256170b95f102e9aac8b7f3f442457ada4938c50e7a9a88539ddd12d651a440b4839584d480bd63b7316e68e08f159fd7c38da6ac63b4f2e75ffbed674c3c105d8c770f503964ebc7881b478079a55e2027f41bab89923307a8c12cdd065f9027a952243ca66f1418922e214fc42b496e77d041d84e9696769aee8a6c445913f0a7bdc1146f13b566533ea6bc1894a8b3a78cf35042413b82447b263fe58005dc7cae6b8508276135c8baa7017ed24c3e4762f6cd5fd8f4d303d2d58a5f911b3dd63729dc757dea36d7c2454ee0ff8581aaefc8e39129ca79fdef00a9ac1a731a82dd3e09ee983b7bbfe6353c2951b1c84d546e91d6540eeb818824aa20a4e241969a1a0347e3d917fa1eec699080ad0782ea47acb3a6c23b7a932d086675795a0b78f77c82d72f5487f1669918f254ec49b98128c31b05fc1b974e6bae762298983dfef7ad1ee719ae301749b9bb1903bd1c23ce6ddd077a1728c15028c36bcd2e07ac39159f0053af811eeb81aa41ab89838e59f71bc14c099f60fc4e8823d1c13240816377a0ee988db1ed23c400e6b264ba4d57f3d090d2f6c27a25e261049633ace8a82d0bb53a3c00080547eb29746647e68f6fb6a9aa6d556bc6e6b34610204ca0bbd9d1f29a43f6c089a1a5c595361831c35bd2949d54c1ab1b9ee3f2833519244c0489bae24dbb293be62422d2bc6b4e62eed5c8f93b73397a49e631edbc525aad80f62cb9df656ead23394b3307909ccf71786595207f02405b740f9b55484a5f0ca522aa492c4c2b63909943347ff01c61786361388ee00932e30f3b461d915dceefc01db671e22665bbf423e4d7435b7fe17b2bbe59b05fbe7507bdf4457bfe6ac66d42f5485531b0b88a66d790f80454d1649bab70722ec0b1c6b520bef1ff757e52656f6620c01798335f4210981352a1073ad189035565937a2f3c169f26f00bf694d0ca1c93ecbd771b4714e4640f5f20353ee54dc4096526f057f6de1a1186afdbb85fc55837a8fb3cba6370d1a4d78dafc128c0b2600d3b831cc2fa6ab557ce903c8f22fca76ea26cddc850e05c5c7c3954a0cd0ce0c9c92c277b3c7ec0b4e6411c5e0e14e5588bc75360a9c10cb2a7a29937fddee89f086ed003c5b98c48f9e7b71dbe4f9ffeb8a1f05e7a14b1faf6f36897865ec81d6ae2f9f23cc0bd7be72d0a39e3acc1164028856df7540f9ad90d0df8a90e8ae40f715cc38886239ef994488633423e1a806be7e524cc5670872b5f1a51f9e8a35f71f00f967cf6b2404d01d28414b321418282754330988413cc352f4b7f746351137b88be237d6b69f2c12bd53fa794bbcccfd92b2817207fd300614e95e28c5dd71c8dbf98877abe5d202551a6fc4552a6f797361dadc46bac5f9fe4d7f883167f1e10e5f8852fe05eeddc2e864ce3adf2d434eddcf0b0248d1c205c4e0456573830f12b8b8fa764e88748a0a6481001517ab54c7c6306bbbb0e2e100f924abf219a85ceecffb00c441187935cffbec7ab6a1324f72d206578c691b43b60a552db408a4d8059cc48e81c591a438be7d1c1077d27e356b5a4ede95cf9200a8f56860cb279230c6aaa738992e4dc7f464057e62251ce1a6b09e6db8d8a77646e8b044aff828a765b7f7aba8d33ca61b6c4964901a98b179ede97524b9b2356db59dec6e32a5bdc7fd0d48631150c38699a75190515eb0b68434159d50552c2b8240e6b1b40e1f5e4eb74a279f8035f2ec2ad6417fe2973f1bf7675baee96e652c026e8ecf0fc6e533ac90446461343488e6e733a25786fa60efbef330103b6e5446011ea94134c4fc30b93594c37526df30923e68f071db6b85545b3120669dea1f0eee1f8ae8b54b1a526630b4ff962426628a2b76332ce46c715b4d7dd0a58a482012bff978791849d0a8ebd187ee648e6a72538d658db25c3c20b124f852126844070c38798416971ac3c82324881683dd00614fb268b8d6de1e68d8e7c36ac974ba9391c59c7ed87296b5737aabaaae1faa4aa462f9553b511280e1ef277228cf702831e87f83bfaafba647dedb9b8e9f986f6da25942b108fa82c3b72e0ac09c88c7a838ea4e927a37c5f54c2cc89a6a80c30c1e2abd06b2d87691926415975786d25b1466478d97773b4e9a057a529bb7b756eb9c05e7572cca1b18b5655a2dc55ebf840991a3c1a7cb109e03d084bf3bcd4806fc5e2249ace3d87dfb89b9dcc8f8486a1998ec6852a6ba9c0adf2dc707f0fb7922fd31beb57669e49ccb2600d6193d5883e18ee91681901cfa5329bae859a89f8a5cef03ad434c2cff2dd17afd07dea9751290cdda97301d9e08fa5bec4105b8747b97fe87792958117cf849901578441d3a6f2d02d007983a2855b20cf2c5425a5c79f146474b287c044928f02f97b3d715534dfdf04cf4c861542141ab75f006db962f717f8ec97552c7a99260214356458f74b00a5153b3b261f94e02feaeaa160ade1919dac03e000da5dbcd8bf7232beac63ff651f30da2be8cdfa8c1f2cba58c50ffec48f671f5e486811e4ce9c2e5b1c9a7ef47d20e4a9371e2e8a6d39f4171bdecb58f67fd3acbbfed7188ee1900321bde9661a149d7e5c9d0bdee79150c7e05ff405223469de1911585a7fac2f4a7a48d30fe7fd72febfee60177763b62062ae2a71c30941f82866d66a13240bb34055984fe8ea323f66ffeadc2cb38a980834647eb3575efb531820650f85ff6651dcd5970ddcac1c034ee44661e19263b3173a0e396558abfdc7a3e00db359c4b546f60e5cb0599c66b317f5611721ee163b250f45236339d72c38fc72cb5472ba970c972af30deccf020167ba311721355be605a8e3b05eb4ef72bf9a058fcddfa8563a8ec40fc948562470bc4abc5ea61b7506441b9d435a2c3bc188976f9ceae19078611ce1708ee8596138bc65d25d167127a304f834a172e757b256e76e583bc663f24efaebbe83ce63ff273138950d4aa09adc6ee74b782a92ac64e58097a72fa78b72278d95698967a959ffc13be92b4cc603950cdf5ff43d373d4af9ef7ff8d6c61735bdab3ba9dbdf0a5662426571fb5a7295d4f5c4b63b5dc31e767092b05fe2fc8decf3d1348aa623b11ece9536e86a952e9f3e6609b49f9a40073e22595de5d8369a63c5ded29044f703b2bf7fd1a4e90d0ee59f4941827d89a38ebeab8ca4e1a05a1099818d6fb8fbc2a108909563d11145708eef584f14b2802a92bddc213f590cdcaa3170545d461fbd4073a3de186e1cc33686f9b36c36471b3a1655301b9210fd78920fe303d96c37304711404bf2aa3d9371ff7a3fe880d80416842e66f8411d2d9a6a511ab66d08435489ac87232ffcdd3408cf16bafc8308ec34442eda12c53e681174883cb0259cc98e8abdc02f44eebf220027c98542dacaa867267d518e1ac5a851eb89822df7fc7cce8e2d5ccb11c71ae12939eda1dd3f9f95aa42667751d1b88d2ceb9b3f8d6213fddfe52317c8b4818f66789dea06d69eb76c65ccc0af5e2ca040cd054b39e352264ee8f271e04bb7b6baa8618cb003e163f86d04b6a28768180b75dea0dc12c662de833b30b5f206bd9ab932322bb5f788c9d2a8137ff1779530ff06edbb200a4b05504b51da1ddea099e98aa2658bee0fe8b075fb98bec18dc35d08eea7760784906a469e274989cea2b477404da46d2f16adb563bd5749c127cbe2a1f6cade697f439600b1115ccf825775121c7de1595f618b13ef61dbaaed08c8a7c1225423730ff64b1a8e10ee01f39ff2e18cd5a653efbf112840663eba7fa523108d8846080eb0e6cb0b89077916419910b3e06413b999350b15588a460a0f5f8d95d94578013cd98b35e31f509058d31d2bc55775df4518a98345d59cd4c2bdb46f59b35d9d7ea4c34d9876b1e78345c883e235d6ac39f7d89c99a47ec09a22c979ff4e7b34196677633bd489e6da4b4174b205562b75a467faed264cb023f8747e3669d5df308d620c6b00a98c813ee0578a63c3b47adc87a119576857acce77b0d3771ed63531573564e240d0d578e4b430a6a8612d05747d532ff4abe2e69c9304fc8e30137b16da4d6873fac10157584f6c91707832fd433036afd5ffe34e6beea8fae4dcfa2c372c37ceaf9c66505ce4050039dd1d32beb71df01a37761497d7a58f30884e4cea24e0e528245225e7b36dfe938603a89bceea80d4e26cebaba9e5f170b4a0c7b278b8b4d5dc22026c7b0293245a07229166c5249cecaf4df379e056c0845a90a3a9d3d29a4bae835b760323307bced0ea3a67181846806545a0988f255d9664c18cbd573d0d2200ef4acb352db665829176746a06012a528e41ace6f2fea02070e3b01a5e4b31587b5c70c190ef5fd8d58da6c7ad95fd9dbf4b18ff59a44db63ec458396522afb15fd5d362404072291575a6b8bb86ec6b3a723a95f848d05e95c0adc77510712e550783cc32195787b0edfa5fb04eaeebe838845debf1e1015826beb05388c99bea4d78c46f0add1a297a4b660bd07d221401986345d2b209d01a5aee0184327045c1f8460a5d1c1107003087e551c30c594783175b4733f4e74e6451177b3be047a9228366783b04299ec007fc40e5a4b3219d61f9ec06edac692f70ecb4235f313565aacb72b6bcde4869c9f7a9e29a2695ae85704f333590c5eb93e276020c6f518f9b7857d9181d4487cac1f42c2c4b0ea78c2aa27200d90cf1c76383e11c28dc637bb4088e4412413eb5d89af75f994eedf27b8c80bead0ec3d73ad0d6ad769174596cfce2eaac2fbbf111b8a30d4bf45b393e0ed942d81cf21aa88c3c924b03a115a9dae3dfccdec07fdd05f6de5d24c029e06b256ab1a15192bb7681b0a0d25a1ecedd95c87ccb5feb58f9a400edf05ac7fc1e6911d41f1d57c3f91604a809fca04542527db0a805d08a64cc4bc439824494df694e214e3f6081b4a1d20acaa7adfdeb163f106e5871a844303c6e54778ddcf202d019410b013d1369f211e8174b20e17d5c5849dcfc2a372123e2bd1d83bf628ddf5dde622149991785d031599027ff885b4f0878f600e1e072c7d5e0801d1c949a144f6c04fb23afdf6542618203dc2cb8a412bb3d231fcdd74ff31b8eaacc7603c640c361690e659c69ebe7618bf3104c7eaf2b4c79f38932721db2446ce9214a986ee8e28912f3c2989ad72db6cdf4145121a34e6da2a8aa4e7d31e427883f6391c623593d14edb968d48dd0a0367cd44d66f674caceea3106d3dcb4da63c4770b2201672d9370abcefc85f4ce98fc0ebacffabd30ed67d30fd2b219ceb389ca73ef10bdcbce2cc2a6c09bab486c1e2d1094dc88584bbf3ee655c8ade975a91b97457d9e33eb14c66533a9e2401a00a9d30218434fbbf1abbbd3028d127b0d1038e91e2cb4b985b94a7d0289c9911f3a1e3491db68f37796d60985ea390f3deabc4617f616b70029ef269949f725571b794fb5147a29b4649a8101aca74da9da279e5757b16c4dcf9c7308e05f8d3a798e72b08f94039b0bd803678a68cdaa4842f976e457d5d7f669c2d189e51d7804ad2162c908dc50add289b254924aa562dabaf5c725ed5d9eba736b3a7937d1ac2ec63580156bb17af81b18da30d97d960b141322e47799a767383fc0b23823a9b263187c1fb2ca9cdf4bceff64bf527261e37d60d94e0299e4604bb035a409099dead983d800305dc232b04284efef5f12e4b8625785e23d6304ab6c3d343813dc574b72c01010223e723fe7579501dbebd32324ceee7b451e98304fd46850e13685710046323be119fef7b03821af87fb39a423fb57dfbbd0d2097aa9a9af29b3c21714c8623ea0432352f883180d4b6e893818fc3f4ebcd3dceacde0a39c38eaca919d5aec1aa872cfd6fc0ef5d5c2b9cf84d69359a3918ba38ca914b9bb8076ec2959485c8efad0010e5e4a5a050e32b067aed4d592b051e55c43bbb198b17f476c61d41d8bd032244a457db651f731a1abf3ecaa19df554e2f4a744c835c3c29fc5ce93d20ea3e6e1ffd65c293a307f22159ed9333320884371d0001d90490c99dd625cfe500fb65d5aed53cd63d3f20110b7518362110e1138e2d8492abc9db033823b3db4ce142629838824733ee53f5d0214599facc8c738dab83784197a95ccd40e117c8f8a7118de1d95809113e3fb0c65eb606bec5c6f0f2e6c0355f47c86cf3965dd60e2d5acd1287cfc648b0ba879aaffa2718fc113f7ac4c734a97ab4c66c79af0fcf83f7433e2a263ba802b88daf0c863980ca3f57fe31e61d792c4d857fee4515c74ab21df4f7b0fd06482efafcaeca7d1c8c1a016f8d88d119e1c36ee003271b0da304b0382170e05fa7e2194e73ebd484f1afad100a75435bb50055f32c85e41c39911516d55aaf7018462f75b05e9aeb89427c968ae2ec0621a7ba83fa7ebe63d5edcf1d30437d0583bc730a571ac8e61841cfab5c3d86d566213195fafe288b3af51005b592888ee0ffa0a4c600c4fe446298548b4c1e2d837c5cacc1cd537f348ebd972a0909f4d3e771c5e4c86cbd65d1fcdfc9a17fed57beb38c531967942b79d4fa7d90705408b51422dc07507fde1cc529ebadb97544b86151eb1c6d428758974f06b069c0c6bfe674941a888d7b9100a6bb06a5064fe41b690fd97931d874797b4957eb683cb713a3f9691e679a17a617c8921abba63f151bd00d4ac90696865d048aa010020b2e0fdc77b74357aa81b6d040628374c1ccea44df11194a86e2ec50761762cd6bef8815158899a19fcc2ca53ce043e5b5f58d0a94863b9fc768e1ca2c1b62ccc9251fb4d321678839296d947bdaa482c18ebcaab293d7011d62b3611bfdfc27b699ca0ea8865e117a383bf9d7ef53dda861e75221ffa7ac41391cf9c027e1b6a07a527606fcda2b534fc17fef3bfcda25d8ac5c330601b1d9383e66e10b9f73ec0b70e4f939e2c2b2cc926bcf24896ed827f635721eea82aa7e4d9f8d649b1fe3bc5002ee235c3e7e609bccbcf3347298041b28d0340def87ebfac1251b476c9cd22696ffce80910d546c6fa6f73aee1e6411e4625400b89042d4dace2f18de7434839dde79fcbc38c778a4f3c1e100683b95613b73b4372b6962492f3d16a62ce0046b5816864401894903708275177024e24d18b80670af900227e47a6ac4600da54bb5ce180ea10549b06106118513b185d7c7e5cf8913a421460c570597e5f6c67e4a28f4642040c1d3099dc48d1837ca9f5ed0dbbf60c438d8c8d79b3aa5df6f717646379cf7a8ec0d944bab3a8b5673704ac741a788f4e35a895f3988d009f7a5897bd171b13a25678cf7d235f48967a9379b3214c7373c57a2951ade1639940fbe385ee5641f7b549c4b697878a67d045e12190effed225d3978f73083c93f7e17c87d8323cf4a1fb44cb8ee0d70c10483bb832f4f7bc7643ce373a869ece25dbf8f8d013f4120dd6f7afbd96a809940a02db4b63110c0ae2ca67bd470c33a83b86f13f5d9f6fa1e722b6a9233b934ec8211f8275c88be67afd2b59413b3b00b0af525ae77fe7af1dce9d5241fddec343f78e3c356b210b23f748d5828fae2256f8e9b21a335c0cc8d58ee9bcff0e947cdf9e411dd4dab9a34e13c2cb4bed1fb66d908a22abb990019e2173eea563c50abea0e436487fce137b711ab1fa44d00f57d2ec0fb27c6a29b78c50e775bbe8a2453bb897fe2daec2666102826cf9bad2be062270d8fa642e6f3eef4785dbb2076840f5c9e69d3a12b45a606a93691c3ce3a9509489d238d1f8c04d8e2af97b06c02bc4b780a2c9a35329bc45ec6d05274fd729111ecbf561b21769b6ede33a534c0de0948c00d33ff42a32d5529c817a71a84ba61d117597ef42c962c3b939e457727aaf7aeaf6899f7207831d5a0f7a41f96d44dcd34811bad040b4147b1099bec7fed9b3a18d9bd8801b59243136b81bd68dc31f534f44fe06f7b51b960f9f352cadcb4101bd4855b984f0886022fdc3b0b4f04a1974fb9c568fd3e8e7d90d3945bb12c1ec39501bf8e8fe203bbe8544031428fc416cd390ba2d33c25dde0716c0fd859c4203a53bba999da60e76dc1c0fe6209f28451322c7aa7bff167be868e0f582160e8267ba0b0bf2748d0adf2927b7f8e599bd66750089286d7d45ee1bb94c74e7c2a1eb33e4b49d82fee4cc9c48861db09f180f15a91bfb5b9bbf5a0f2e76b6e69865debf72afbda0119f9731b8256a5ccac66943ff4f6527b117ec9c98c721cbb93e0cba5a4909816f17fa1e4c6257f1fdd9f877a1b96649631107fb47405be1d51e814833b092fc76fc744f96fc81132d1815a7fa367c7490588c7bcd56a0c00b5d38ed994df109fa0282878bc244c07938aff822b93407133a3a0c46a02cb30c81398d11847a260963d85d58f36b13da9d5540457e0b2f22ccfb9cebc91edf97b06ad5262c2295888fd3f54d2f08458274095e25dbde888660b6cc1f5143085ae8c21c9a50319a4318c50933904ba5a0d817d2213b84383367d5ee01f33ab926b85c851178647a10cf9950b4a5e142cd5c1148dacd5d17e511e9d02b7e8c23f1e46bc480acbf276ed952ce7da774e008e2f77727e900f3964eea34abea8c2de9279cacf7c0b4c783f3ffec900fec8e013b8252b7f5bdae59bd1b7db006470f3a40275d431ca29bb39aa2f8c8de39666f916d068c80840dffaf81614d6386188f54c6142c52fe4af5e95c684278543f41740242332a482598f0957bcfa2dc1a07e1016e77ec0aa75dd1563c5554563500e3501ac5a28084342c2d0fa2063bdd7c0adffd4fb8078a70b092d8a7a6962cc2453176a17bac5296f1d764275c49be8f53fc52ac308f5494615c407ca317073534d4ad8559e7b1f14bcc1a8b59291ee886d01eb2143351e4ea76d39a78794a5da0cc6ff91476ce7b19e69f0af2b4fb980c0995fad24d476adae40493ad68381aeb66fa5d24e9d36c0ddba15eb27b73db328ad474a59f615d6be1285d71ce93c8eaf34b0c72276ac3732877eac80b5e16e0225ffabc5e42a4485c18bc10c233d24f84ae8bf31d42c33dc63e8d2b1882711af64492335adc7cc60d0944b72f03ac58ec960c35d8929fff13ee14d06763383d160b8ad18878e8b18da98654b546aacdbb7c60700fc92ce4dd32ba93262026468e2200b3613696b4f22afe282d90d9321374024e8262f6b543d2e512621f34a5c6d3cb28be23f60c4d28711bc12196e1854a84c1ff8ab16038f2ba05c9491676050336492cdea0e8225749e64404249e7c14be3e01a7240810d11dcc5337136b41fad0de1b90db92fa68e18d26c90db0d7932db44e49325c17f68204a9e7f2ae53fff31034284b5ab804b4e0bf3e11745da9954a7518603468dc34066200ded8048acae195818f56336239b232b5a8f5eb401b17e004489824ad81fca0c2d4778c711c05e0564869a5b4d75b33cfcd28c5a3bb85fe5b6d07d98558c4f36621cc1bb576c6481cc73e5b6dcd988ae06b9a22d371996da2fe2c305bea95982304bc5058208b9818de2518bed0cd41a4a22644068ffc8f66079287d1fa5c31ece2ee4cc41dcdd88343adc958738a196937388174d81289487f30b70d837eaa92dbc600bef3946531e92475947f64db586dc5a1fa62f0ec0315e20b13d67cac39eb5801fc2f37ac08700e91c1c31b30902cf2f2be41528873db322b5b83a4905f21c6f4a37e4ae1371c576571383e63179755c052afec5bdef64c87c9b1bfb2bc561bac93a9a4ea8aa86b123be1992f7fce6f953cbbfe8246d5a7a8b19fc3c1177f071a719fb546821ae3bf241d71dacabe6f444b5f7881fbb46d609dd2768cfa69f817f9ec750b819cdacc4f37787f4b0e6f7de671b1ffff1fbf942015a7223d7e9295ea01bb60de6b45dc3bf8c53ee1c2db30d6ce2fff9729de2b356e3a30ab2082121878c82803b0a7cc4f2cffb2fd380e39a84404cd543870af4e4afbc1cefba834d23e18fc79adbe6fbbb4696d83f3f05d714ecccd38cbc8452f9410ac6dfb6e916b8e1b0b60dbef7408e522724a231af251c0894106859d6acb7ad32c350f123f870d7d888319d6b48466b1cfa25d26602f10ba6d2975c8ae02599d3698e51e5a30049ee16a784a3ebb48b02678fdf7d201824dd5a4ca7b2fee7aa6c2874d0d27ade3e3749fc94c511319a95bce8ada2d98d08c1384ee0dba5672a2630d8dfc5ec774243436a415bd2a3fa4f1e5c0d78c6886ef4a6c4ce5a75fecfe87dd2a0b43609cf05667bd1f97e811562d6619c5f20183698e1d2633326b0e12c766463c8c58926d85aa7de649a9c080e092b7313d8946d85e6588505a6abaa39ff443e47438bf2b79ade8077fa0da4c72a03b9ca31d1ac0466c6883dbb5870fb11c1598b20f4c84a2c605ec6d214281756858d18beb86c22c6c041dbca5f4dd96a801734effb389da387ab0245eb5e991f7a8e9dcf292b89a77e9e0d3cc6c7502e594d746c0786f803d22ac529aa0d9f822892d27452247f7b93b021811db34e578e69f8c9887ba62d45d450df93cefcf1fba5d7d013d70e7f694ac47aad1293bf55664a064ba78bdfc1c8a3285d8c816022c0f11db33021465241a9fb7ed46dcc57beff82bed924739832245c62e8ce1435982317808c0c9e2118d73366fa01559b20806bed5a843268f72ad4cccbc9e224d1267358388b1de7c34412c86bb183e9a0af30665df3cb81d3847c7888e7a8871555fc817315510369582420643fe7263e3f0a3344e96a8fa6cb8044772e87c4027c2181e06f0a6500e70b4eb431f91a39a6563b02f6cb1feffe5d434c99a6fea1dbbfbec194e1933f9aa4bac648720afb061211428bfcbccd4b1a4de7e1acd03e1bddb8a23834b4f25a821859be4534508c88873e3b5df2012fd15b98e10023842791573e360ea3717c626eb58f7b503171d1560474dfaaf64fa8503d3b41b9ad6b11237ea36e81329f2f36d717a6c5fb3e94917cc6510b6bd2587f153f796c6e68cec27404794316cd2400db36231bb7151d55136653d4d130664ca495aa25277653d18dd0de94e59e387abb9ea864499d33f312d2257aec96fc0ad7f7a5400537bcc36f9fb2398b14aae52dbeef9322c3e577264607817ce1da5339cd862d9109409bd3ab4b7079234644c060c6560c6da9b22fb53ce330512568527579b3042c74eb726756594dc91b46cb7de1ddc520128e66bbfce6a155539bfcc1a64485ab06706348b52963cce047a83a072b9278f10d1c0104ea14f79d5920da554d0739bce3333337440f35e531849d712302340117173d6e413e8ee3e8956344653f9920159ced9aeb0148583f00da018a8adcf2c1014771999729ec8623e5dfb255cb5e3e6db25c6c1228a4b5bdf7de524a29659232b609df09b4093d72c83b07bded03f97ff1845a6d1994ef7bb9e2a58c4eeebd979bdd68fb15508aa8f7c0afebba4775dfafa03ed7b5b3f7de6bf15fb7a005668d1328fd00a314a2b5863518f58592b2eeae20de32052938fd09a87d0aa81fdfaba343d219bd4e7702e6b8ae7b4ca0d5396e9b7a95c282da4ea5134ec5843267ed705771ed7057b183280ea5629993db30c678e2896b2afbe4b68a718f540e6d543aa53f4d90a6001bcc0ca702a6fe04aeb80af5d3b3393d45a9fc277d85faef59409cefb757813845f2e3a0bee5074de75651c1ff03f52a8fc39bd3af843fbe3fa19efb1b5418de7c386f4e05f4fe04766f1a3d0aa85d9b827252c375d2ecc4652a99429b5228c3954aa6d49b7064d639ffe4882593e94da6ffc1f2a5b0f43962fef955e9673acf667546475f4ab570a7a095ef54c639234202e847e8c77586663fb31158a4fe15fab925d58fb2a8f4dcec546091d2b7944ca56f31994a2a9b1c3a666bf2305d5226cbf6c7da1f2023b22532a19f9892a0990d9ac994c866b43579663c7a3679f0cd215bf3073f52367f7e342dacc14fe3a9faaa6f791630553ff52cafbd66e3315ae86686016f116dfab3ce3dfb837a956f01714acfbd0ac4e1bef42c20f738269c2237dc971ea77bd3573095c3f4ddef283df733468b4ab2a010059ce2c97453c0ed57c0136c4ad9741d972204048bc9826643443f43b39fd989eb04c60703f339cc0763f91c7796f0c7ca4ccdeba0a4b08c6116762b2c2653a5709cb0ac9436930aaae707364e19103c3bbeea8c743118ac33d2b17cca8f32e8034929aa67f992ea378ee35ec5954e6f52d5990dc817dae2c00c6606b3c31e9904a574ba06f29851c3f48f46c2dd5dc37211cc877cb9b686198c9cc94f9f0030399c3b3b398735f6693c7f86f1186dc457b435ded81516daa8eaf7a7d75179d3732ad0e559c0964f8129bf02967e07efd2df0994837b97bfe1eeff4879ee6f78b37d4bf8a3f41bf72ce0f65c05e59ea2296553b22850ff07924a29d5573aa458c1148a6884270683cdaea758a16ab3eb5cdcc54575626149ad702a28dd6742a1508f7279965f71790e64e93a96efdea563f915708a8e53e426f5a8c751fdca7b204eea5134deb9587b59be73d1ec6b61cdfdd0c6c585e54790b3698f1ca6f0ef48f995dfc102a6ecb37c8ee802a66cf8d63ef72d9f23729ad5b4fc113d71042685769d5ab6f565983395a37b97bfe9de25fc51247f4bf84315a6eca7fc0af72ce18f5498c2618e945ff9940d6f527e2575537ad4971ef5dc8f1e057aff81fa554e53a4a0dc26f194735d2ba14b2922cac96fdf8df4d3095362fae992f9f4b87aa468fa51ce4a8ff2270e2cfd06a27c8ec8bd8e1c91e3bec4a1fca95442316ddcdcb8e91acd572a07f7dbdf6cdb8fc21f27bf6dff2365fac669ed72b9be194e97ee714d772f55b7e7e6ddc175c3e9922fd365fffe0d8bb8e12dee29e7b3f58fee29bddc37d44bd5d0867b1d52e47e878bc72567f0a64f8ac91999939e949a6d4ca18ecee8bb22a60d7f715ffa1bee4b29dcdbf0667b94f0c789f69af423efbb227c45b9ce1b9174e7f2e971f55c271d51b5898292e252a77075fb5a4f5feb49ad2ab55467ad951249c1144d6f6b7dee04ec7e03b912caa77c0ffc2412e95148298f02a77802a2fc06a6bcf7c02fc55a6ba6294a67adb5d65a6bad74d65a6badf5fb6a8ffb2398f5bdd64fa995877ca9d3b3fe2e450ccaed8152fc407902a5697a36199cbb447a1338450cce6de9055336282829cf4daf04a6d85a6badb5d65a6bd539d7bd196cafa33d102da2502ba4af8e5a462913894545d334d5a6d2364db5a9b4edf42dd3d39123aa5e478ea80a7fe488aa27fd8d05b09001ed20aac21f16c04206e412472d2c9f7ae9a5340db5c27195e3344eabb5d6ca6ddc73da08b5b26ddbf69b16d2785d7996d7417d8ad36460b495f6daa7696d0373a773c6816efc38c81c66e7b62ddcd19235178802898664b19530c57d0b2a4ce568f9954f71e18e9670e5558ffad40ed5a35e857a1aba8138484e0274e340f716e2b0002d7416f0e453a0fe1530e55120caab9474505e9348a3ffc4142845150fe5e4f529d421fdc83422e9139494d20e4f45c9d93c45094a63323034ef2edb99cdd60394525a85f650e606d0a61a0998914f79ca3d4ff5dc7b214e911bd57361aae2b878e6404df58ffea1adb92359f4b3a63b2c32db26a5faa79c8a09e53ba508e92934775a28c7cdae458aeee9e84096e7c0d4cf14ac7cf729403df70f4e919b5e0e29ea7caff252e4e6cc0766666b449143323befe89f6c830c02646bbe40d3f628b3b393bfe6af61cd7d1ab73d5238f5f655a00ba8b5d0a7ff5ec7f42a3f7d9e1424676436cd3b72266fdaf283a6fa675324e48cf6f4b51064eb03595062535964440b6d902fbe47399483e555cf2365e3e202b6a84022f47cb976f28fd365c351af867bc9f23aa4c812e214c18fb3f25d2ac4413d97cab1f2dddfd4cf43014f34123d3e3f40b0986cee68a09f9d1f994a0e761417fd85963ad024a03d7e1029c863f2c77c4542f285963fb7cb8ecb0e76d971d9d9d3e5886c7b6a06baef7c19a4399264376ea0493d18bc20a844874a5812440a725250386a5290cb8f7d42a63a40b488f240b2d8c31c432ce2aff38211511e8816bb979b7692b64c2699bf0611a09efedc19a218a82188884de641593473b373d3a3bcaaeb506cba0ee5bb3775e18f1c11e555e0143de5cfbd87a91c2a2aa7e7421c963fddb0fce97152d34b69cf23f52acf83253b38b56f3ba7720e6bb8c1c7d4a13ea050ece043738d1961704080ca987f5ffee4cb5725b59fca2815902ff42b688305268b7e27a701c6d11ee53cc028a7b071c84306d5c7ff38acb9f8f108e6b69fcaa18dc984d243871475561ef5292dcc917a95df910a557e074b78caa91caa4ffd8dea53e18f22daff60795578a3fa96f047ea55a1a4ac5c7de52c18cc7b05d48f02499f026efffd09f4de04768f0272fa47af437aef2dc87d498a28508a1f28c5295a50ee94ed4fb41465006ba02cfa9d2c0279c8c0f8ca94839d44034eca18356cd31e3d72d0db3f07d9953ad992a12d1a47983db4f5bdf6a7a7de93266ce4d3e3abd9d364d3b7e97ef6802adffda9880e29eaa4fcc97fa014635c28da320a5bc6be10c24e790d3cf90f9ca20a28450f2481349425b3bd0ef9a3c8cdc96f9ff20571a3711b1dd39f5e7a299b94d721c59450d2935053d609fc1c3a6e30e02cfa1c0d2734cb12dada10697f0fa5f46e689ca3e18496beb2817cb9c1ac51844f22ce1aed1ace1ef9423f06245afaca71b8dfe3be7d1a4ce8fab504b9047a1b91f2dbc9bf5e4c59d24a514089a66c524e9e7a291cda6cbfe304d43aa4a8a3a3f336291365c64a3a3aa3ef5ec77bee39ad859e40b347ce0cc9199914193699c2f9f241593b1ad4427a9cf4abcda31e2dd135ac1b0df59efe28b36f2465b5fca0f1ce4f1abdf7dd731f2e97b8a557e9e6a8bbd399e4fb72961fb8e5bb7f5fce4e29adeeeeeeeeaa21a49452924c4a241ee2a48c39b3a64f5cae775b03b5b4d67aadad54bec8d98b3b17e81ee44767644c0ce60fdb698843c670c0ac563432ee2e04df0f35f7dc35c40178e2ee003c912fbea3e972b9e48cdc3397d37dda1d298a3f6d6863ec4add08df53777bca647bce30bcf5396bfae83d9e84fbe6ef403c6c1ecbc2b5dd611c0bd876ceab17dc612e972b88e822e8d9de64be26103e87f8106df72eecd844e24a669090ed4e83cde2adecacf958aca00363bb11866c610925409cc0828f384a2700418c2e1021c80b3f4944395dab9810465880831514ed20322164051178828a7c208e1348023e5378c28e0f7c7082083e8916b00420f05c81052f82f083e8527081053128ea096276856ddb64eced65cfde7edb5e4be189bdfdc7b3b7ff2908eded37af665bd9806177af79359db31481351cec86afe6b6adb6d8423067c998b3e496ad8260663243ce925b88c859728f3236ebc1d65e7becd568ad9c05104062feebd5648d0514d8b56f85010b216aac8c7198949db71c760515326cfa33aba4a0267199d7c35129e39133326c9ab39cb19b3e6b6b529e48941cc17b2fbe175f29b3b99744d4843c6576bd4688a0041d2e84c098428e114590c113848a74823c21162961c9685e81c4a6bf9291f04d945de915378802149bfea7a74e8c09a6a9d284a24dffa4e3892ba0d8c1074ff0200a1e3e54c081155238c1051e44e7c2126c8022674cd3094b70b0e997b2a6bfa294de504a7d079bbe0ca594524a698a5743eba378357586922910209d0a6f8257818520226c7f1db464fb137ea0b0c3f6879131281861fbd358b1b3fd715891c511d9366374ad02b6e993667041064963017b9461bb1362b0dafed90947d8fe1f153c6cffa76208dbabd8c1656678a1a48a1bdb677ca1e4082cdbbf4b62885b6b13c0d02b29cb2fe3312e0529aaf8c2c3415bdff7ed29abe8b57ef66aeadcc1a6f43115b126e86c5fa248cb9880c4a65f7386fc20041766510ce102081d4174a1029d2540611603d1298e2fb69faea03f18993d614c80c10e377d3afd1b80c363eacba11ecc014c2144b30ef4143b98792e6ab5b5d65aedcf5a6bb53464dc6ed70a5e1ce8b637c4815a9bb3753c055aa70cb43d91beaaff4d6aad7532a10724e108b36b1d6ff8f6dc1687694389c39c16d75a6fc5f8a98871a5a0ddd1459ccb4073bee59472ca9f36b42ddf9ee8e80189afe4963ffffef56aae07819c2df3bc3f9fa31ef52c9ed3ba17a66ea8989f8a39fca18398ed890e9d20be92bbe4315fd853beccb7a0dd79bb846cc8963159903d723c7b3e8d2d6349665ccf9ed927d7ede5cbbafd3f199a652ce5203d934fa3932d0fb2912d0ba344b2cf0ca7cf8faf263dd1d1431833ffd0300615e8510363ecfa63f689c0efb0ab0e8b103a653f7747d01f22d9c7085ac6d75230a57d106de523246bfe0f721134137bbe077990077950f671ad37d9ec41cf16e4317223f298bae76f61788c8c4951b4e7cb711bda53c61e37d956b427e7dab31347eeb527f509f2b30304044c486c081911414346af6248c72e8199ecf9d3886d849c2132a711194a64d8e3f41162329b6c618f338c3d9becd175f6f77d2b8d482bca3eb23d9f89c760224c8489301126c2449828f34c9fe9337da68f8f5d4206874cccfb4efa6abc3ffb0259988fd5f118fb9af6655f2f9bf5675ff6a70a39e32f85b611291bb96fdc258e421e4468cab281b2a4d08ed17761caa67bef4761ca897c353f47f4a0fd23c31edaca3f9435df674ffd659f0ff21eda92a2cf0f506ccfec4359f3c1c83eee44c8194ab5948f1f423be36beb1072267f081ce61ea6a64bc72544ce6860086e90427b2372b9f616a6e62b8814da199442fb05c40e103b4b146ddfe119e2417a8ac83e16967d2c6c3a0d753bd713002470944a3a539eb1ad31239b72630e625ddba78cb13f5fda4de3ab496bf0180b1ea1fdb5165a86ed9a6e40b65692e55426f9b90318db7516b657610131c8d64b967c9964bb5cc276036cb741674fd890c374798c5d3261517841ceba9e9e1544c1648f53c7561984012fb66b41af562bf9a39ef1f018f935726bfb02b6fffd13394383dc3d4ee4cbfcf9f406ffc811e74dc6f139e2f41d2d5fe627d11994a91bed734edde4c738cc81d23087d79ceadb8be348d2e98b06a9d6c757d212394942e467cbd7485ecd11ed2149d774d23d6f7a769472c0ddfebe3d1c29b07fbc1a24b6dc60db7f050bbdfdf84a8e1b10d7755ded3aeaddece46934e6a41ca072b23d1c3bb0e7d3f88a060d794bf9e248642ec3d6de90912f32cf9cb3b423396b482c6560cecff61c2470d061e20052ecd1e0cf91bc9aec495f691bbe9bad1bdd369f9b548d4613ec198e62f245be2645ce5a4b4d59f275f460c4575224f182caa9aba44900c29e3032ea85adb3deb0e70fe91b4a7bde50da59d04b44c136e06d750bd2c4a0025db3beb536d1be85ffb44593e9a76c198b62073bf4811e651430d8f41b20b78ce1a067d3eced5fce131d3d0c994f5b34305ac31a546a5d6aaddfab7e07ea55429c9647bd0a857a9cff2f4cbd14f17c14f8d55abfd65b6b5551f98f964a2da80a7efde9daa9b5ea5a6bad456e1d89ad36e58f7a297e60cafffbabaa6febdf5aabcb7fbfc3e53fd5e3fcbbfc0ed5a3429c96573d0575941e54790f2cfdf46a46af320a7fe488a507c129d2946bd48f7ec7f75e88d3f2df8f5afe7b9c7f947d1e2e8f7a1eaaff5450b5525a6badb5d65a2badb5d64a714ab3f569adb5d2cff47358831f4ce547bdcbb780297b431b95979bc629d82365c31ca877f91d2e8ffa1daafffec1540e6f50ef127eaffa163075f3bdea3f8a2fbeb6d65a6badb5faa85596fd6409f3fb3c65653b954e5466909df97a2d99bd2eea378ee3384c009a02700aa85eeb0c7b8aea74d7ccc78fa21a680bc70c47ecc2e0ea03cf0ab8f982c1eb851a41cefe686bbe5e2890fb4fce8c367db92315ae84a9fb2b2fc51d92b270eaaefc0eee57429c2237df6f8fb3637bd4a3429c2b451aa7715bedce0f102cf69ab3949ceba4d8cca55b7a205afcf7e1f2d2a5f2aadfd1f22e218ecbb7bcaaa5e571c2570953538a5b0b98294bd3968f700bb10cfa0f7f94d93276aa20f82e2d1559e483b600e0a57ee55f3cd307e8870f5f15f9bd362d9ff21298f216d00765e1548e962ffd8e962f85384570c26ff91daa5709715c5ef51c373b00a47284aff23b5cbef43523f0df03c19fe1ab3c0f972f3d00c0294a2f75ff51ab95006c1a6e8a6b51ad3e5c4510299a3b73488fcf848181c1dfb72ff8f58226902faf1278822f9a3cf828c2618da76e68f361ea8261eabecb971e270c53f7ff5bc007431c973095e3bfe55337bcf930753fa5a97ccbbbbcea53372eaf7a973075c3dba326bf8dcba7b430b543e53fc429f22abfa3f4ffaf1a41ceae2c8f7a9dd47f8fabaf5a5e85f229f0e44d291ecaebd73979d268e4fdc956506e53277a23923e4149f901f2f1e5688e52d4a37eda5f6ed7c196311a20b1e71ef1cb673064bb3f7e01b1fd7110c7af30f6d8cd399f86b9e7a7fffbf15462a0a578958cf9458030f47895dca2eddfd244cf1f3150d0f6e77628cb1f465740b425c520590cc35e94e5318ca12790af469b861828069afbaec60d34f5f15507ea1631625789c7b0ec198e8cd039b9c6107aa43f9327bf64ece992029d72007efa384cbdaf64e0898130106de51706c240db9d98c1b6e1a899d0c22c08a43e33965f5dd094556397fe28d9637559253e63f4976421cde46b62c3c82fd7f69f47642bfb20b1679e5c43881ee509660f3e509053347f982b1a3933579bc278504dcb396f396fdab6e5bc79997b2a72d957f9955f2a3f5a8ee62c51e0601cd018b6c8123591a34d2d116d4912c9313065986cd26e09a2dd66018ceb721894a0e9cf97c7d0d7ac16e44c09b4259a366658022f64eb7bdd1eac17b6dfe02d3bab806cc948296c7f1ef246f7fe769601c9f22ee45eb3ad858c02baa7e10c2513dbc40b3d778ffaa22d5b4459fe6f89424bc41109a2b91fcec71ed1d257daf7c9dccbc35926d511cdb93c46c763b6f727a22deffd72210e33744fc5ee390e3fe7eea225a22d8ec81259a2971cb9d768da23f7e2421ce618291bef73441dc4951b37d05687a8035de47c4aeb75648417deefec8e058267080e3ab8f60db3afa625da0eca6d8938d8e6a331fcb57dc290482959a0af4d42bed89e3d79a4ac2d2cd07a3b0d21f4386113467518ee315938ec9b4cb60fd99061d690c2d09cc9144d50093d6313a6841e659091198be1087a94b14007240f2b64cff7bf80d4808cb1efb6883d7f9457d87e2d9671e7b66debb6addb9ed26ddbbca7a217fed041949435376bc4c27c351f839647beccbfa01de2ab1e5f25215f668cb2a65542d6981f646563cc76584705e740db278f2679bebf266740f9e2efbfcd56f899076d650ff26818ed2c5ffc5bbed013639ce5cc8886d19ee1ef407f40b6a41824b378c1155cb4a4174318c2822fb2a0841688c4f99d2763eccf7932bd19487b7a33b8dd377ce51e04f9e20f0a691a195f790c35d03694a161ca49e99c944e7aed90201e9e85382963dac9512929f5a474160f44291ada6cff4d6cfa367ee32bd7401f9488070c4de81166cf70d4ec903df1bdf8badfebdecd37b43b3cbe9a22702abb8e9390b3654a793aadd669b597fabc2670b47b82e0e630f589ab7fcea6937e9de52eb67b7eae48e81ace394b336b74e21d5c6dcc34acb4d9b1ad175b6cafb5d65e190190e539736d67ed5bebb386b5d65a6badb5d64ae9d65a6badb52f7d65adb556087afe57a4e7d357c9c05a6badbe8269ca501ab5d64aa9bbbb530ae32e43bec877ea3be78d6bddb5d6fa75594a29a59492548fe8f9f45333687bca1777afbe916c70ab6671d62cbe95894c05ab69160751af6683e83a4ff33c6f942fce9a0d025f7cb3662fce9a0dc256cdc6b41a55ab18638cb10d42be0ef4521494147a7110f7534a5e59f027e5aada505e1c84bd75b3b732b1514ac3295fb4d7a86bfbda1a84942c39e0aa755aedc5596a5e4d7eed729bc3d47891366e660d9fb9ff5519b44f4863991b1919a964fbe75b3f1972f861aeeb3a4ff33c6f94f368e4d5d41fe14d43c6d4d764e82880eeb70ee4365b6572984924afe63e495fbb7ad296ff656f86968ec81a1587d67ab3f669e3ca1ad656972bebfb56eea4932914971c7fb94eb9ba7fedcf19eac6f7afb53597bc1afb25d39cd15ec2e48a8c8d6fd6f00f80127a3ea791e0db39d4a75dece94940db359cf22567cfaf6d59830c6d79c0595e0159c3bfc9963317f878086192292336167491843de61eba288250173f4c7491031774c1d3c5cebd9aadd48b609b177ec05020d2887eb84f906521a127ec0859e103146242b21fa0d023147b554124047b59c12354041504c1484adc2010d1c4107c00848821421001848684881f362410e1c24886d0c21186a0429e81d6b68c0d1105ed086db78c0d1164032aa690f3f785d5636aa50df055cedf175297564a974cd0efcb19acb5ba0df9a3e740fbf69f207071d690ff5fa77c91eed65a1bd65aa753aa1a42cf7749c3484a2761319d565ba9bd9836c063ec9592b5e583531e99423e61cbdfefe197b5294e1bf3670d9f36acd033674d535fdb648dd2734f5bdb6b6cff4903739ad1b6b7529f764433e50ce3d943594da4fce48c6f3c7bf063cc7d7266b4f18fb4d0a41fe12931fe11387f280b3f09bfef1128c51ed006da43fc143f0c5ce81166c77a34f8d67c4e9f73dad03c1af0ab8ca0ef1ebf1b424e58a0c7d933aa6cfc786efcb3081df82f206de60464ccf6f8292063b8c71eee6cf7c999b9f1733054cb5de7759dd755eade8d9e8aa3f0870ee2e83b3c7b3c067760063590827627abc819faf8a50c1c8260c2b06b57bcce75f54332d050f88e158050a0f09d2b00d9ae20856dce5eb0e714a262cf3dfa102d614073487a00e0c2677b9ec74514b68785207cf7b97bceabe9b4e4328764731c13226c8e0b1f3677854d4f11bbc24e7e5c6f58e1898dffd62882125063db212aaa80832a7861c888d59c41912834ec08a55bb460d32da4a0c2135f85224fbc3a2cb4c5829eaf4b312ad460bbffcc2f4cf04e0b2053685185498b2672663efd12107dbb05d9b232488cbd85cea630f942df06d19665c2cab6d8d41ed9d406b9687b288b8e76dd82a696675ba24dbf6ea165ed428f96c866415a220bc6a677874daf0fa69d22707e32dfc6aea00e1e98c82349e0d9f26bd51246c6dc18fc474896c421f403c99236aa8d4de3155f30755fee6aff56fb16c6da2a6545382983932167e8cb9751005bfea35027da0ca9e597a13282e6eca496c7b8da737b5b05b0e773396b6d6386ac311f6f1bcaa013d49ebbe00dab7db7707cd9f5d63d3f77606a86a00d60e042c27ac071d2868d9f8ef7e5bd97864a4ceb534a6db5f6daf77d9fa360ad21e8f60dc71cb60d6fe8f6dc9cd76e941adb7bbb3cdadc5170bc95664ddbd257141ce58ff45de61f7cf3b54fc35ba55b198e36ac28e1ab912f69add47a0be34e4a4925b7034a299058b5f369b5b60289715ec438a21890189018e83bd3ec230389612038d8be2123f3b4d3b6ca00e32b7f986a6f119ac66a65af6542cbf8bfb8b27c38d3929e95d33a19434393b386737dbf5e20518e88900dac101302c266416f5bc6845690c5183fc88ca0495bc6b220e2aad07acb5816b32c8230deaead94a601382050fa228b1fd9edc1a7750622881591ccf01429704115a300ba322dc44036b34e9881679d3b9d048924492431a2bf2c3bc210538a22a420a26332222ec8b21d198fb3e41eb3cec2a7f445f705198d923dad9689a04fb68c09d1e24a01054c85eeb68c0991220ba1b92d63429200d32a5bc68410d9a384dd233a6f191352c41ef396448fb68c09112227d177cb98909dd21716e8e753f0737094479a98b97ff50982a004741b6182fadc96de04ef96decd0cdf1e7ffb3ba5d45271da39bd4e84a0ef73de49195a9e3b246750b6ff652267e8fb9b7efc2f17f26e61fb0d6317c997098664f9fb6b87f9851eef50133dcea09da0ebb8d6fab566f97287eed069e71aa10b337e66f84839fe4aa8292a3ce9f0f482998ea40a483669cfe7eca9d24b5f940b710d6dc895c02972267056a10b5604899309168488899c8b410517ed4ce054c2164d008927d0a14842e42c756ba7acd6ea919d41d8e20b44e209b42e1842d45a6819a79e138cb64c31ca7a4d1b73fb9f829c766e38fe787afdec0bd2b2eda6536cfbfc3a448f58e5837cf107c7d0299f4279b94fded4c48cc1e126d8b4d13d044c4e6c294362fb978e9036e692592252fa29f9c8993cafe001c9b5fd4732dac253f41f11d156e97df4f408440173378a9d5ea3980e47b1d3e9fd4750c8d629c43e94e5ef6902c856e9fd614631da2a85a62c4896bf45c0f670cc76143381b1dd74321199c21b64d19e8f7d3c73dc0340104cfc38e580fbf669b86f431f80f60db268e3709c5f82b9ede790f60571a0638cb1bbd00423eda99520607262fb9b9a982bff207b2c2151fa291129f92c99364a251ecc253e7b24d5aa5732caf2d12868fbeb70b1148e62a7516c8e64b3f4b3542a85a797a989a9c844743211956e89e7749af183e2a61f70b7d1156d75a1cbe639afbdd32567dcdd082e062be871ba968cfec3397b0ce6603735e2f522174e216739bd94524c2995d44a8c25c6aa2ee81cbc1a1fbef229a482140f7a9c2e57c1f6af31e30d32fc5d057246faa0ad295be5b09a487c253487e6cc5763ce13e3c933c4e51abd600c599a25a7d5deac6d1ba7b5d6baeb4e929c24399d462492d627282929a592c9743aa95c151515aba2728292b279d5badc75a85c773286a6a19c25596f97e29546273f9d462592499f7c1ffd3eff4c1fea745251f93e146a6525956a695151f93e146a652595626151a1b840bbb8fcffb7c2524299564e2996930a4be988140b0bcb8a2ad5c2e2f22d1d8baa737917176f06fa5ecd7b351e565f81326233e88c19337cc68c39230c012043c68c190108800004b05ab15830c010760000402763c69c2143860c6f06ba3329d7cc902f3460701804b062c110038d9701ac565f3a6286ac140b8ba56a61b1582e2b2c168ac56255ea1386d10c141c4a6d8df4ac31da483a3d6d74b386bfed3adb754ac0d9b64b6cd09e33b44e98d3f78910b445c2ed8faf7cdab047c81afe9607ddbdd7fac81731f468617bb43e3688b266942586b461dfdf8e21673a3b4459d3860dad13640d30648c9d42aefcddca8abad05661ad4cbef89ba6d0e3edb132d9ce7f85b0fd47026c1adbafcfed61e95e763fa66e4f079620effbdcec346db9c7dc17fdebc87b1ad7dec2e8f62a981ef5eeb93d3dea8fdebb1321e819da227c75ef0874f1f6e8db737bacd6dd8854bdd088d40d15f5535187d7f20ce929828afaa7f351179a74f7151a56e8e9d1909dd0ef56b876d6b9aaf15de528a5b55a2954613b11c9ce62181aed0c02ef0dc92cb63321ff289bb09db44719b3827a35f869ad565aa723aabdbfcc97554ee851c66812b0188e0acead85d6b19cb5febeffd54afa4c9f9cb5febfef2b1fda7271f3597df76738fefe9498fa74b432c63ea535d0d6f4e1344a22f21af2c5321cff7b4c1f9f3b7d2ea59752958f1e57abe7a69c958eee113fd8fed99ffa631ff9e2ffaac13d86032fc2d8343058d6b44c29f6f1919176b83fd7a7c94ad5053de58bffa8adb53130d1a3157ad19685c5b67f157a31ec901da2adfbba2f3b6487ae1dda7e84883b6dadb3d65aeb7d2aded5fdc14dc486866c68a26d18723dafd0748f7ae60328b335a2b45ca1ed1e75cb15daf7a85baed0738fbae50a7df7a83dcffbc0d090a6c286a1d8880a5a8a190698077a94b10f00a1b56c397ac3197a80f015cc0689a07fefd0268e6c4abd18b0d038e4cc071c205be3dc21d685edae85294647e871e503c46ab5e2baaedb9e8adbb60dd930e28293d265a0c73cdaa325b46fe9e55a71adf8de6a6b55811448454d78482be86aadc5b8e6f70a6818f018f93c483d72a6b5fd6ba02d191919f288218996330c90b1b1001928a64b9f7484ffa3f4a31fa5b5d6dc93840b09e7da8a64646464680b86981eedcc579a909cd9420b29862da2ee2e2343c346b43561329bcd68cbc26033d86c666116369bcd5c9a132929b5d65a6badf5556ba5aa257aacafd9d65ae8fa923377fb571f6a1094fb33dc10cb975a5f5bd0566c7f0985ed53c80e9d08d3a69133f7fd6d3ca6c763e8f64712f07a51fb51ca1b2f185123a2041bc1bd06beb2a8fd06ea009111b57f65911bb2a5b8559eea0a69517d515ab4fd9d525a5faf949f0d082793737e152ee8fae367e9517a29c5b022b4fcb4f8905e4d9cf4ca1c09e322122ea22d920f92e5ff029710920d482ff9e2610f1a7352cea7d7c8f61bdbfe14467a4d1ba3ed4f0ae231323943dab194e443a3057a24bd48af70d43a7c799b9b1e09e62bdf314978099d710c43f428613953da8203bded3133d95e222a0d9976ee2bc76f7be5c60df415da238b9c655c44598e5d7b2415e55a6f80033ddddb5149a3306ea049ae5111e9b5fd61b0821e15ed69ffefc518678c339e734e0fbff46c34d28bf46af9d147acccc6b44c83e48b16d21cd20fa29452db8d78f0a2adfc5e05d992a2644d4aef1c624bf9324e212ec3f6247c85648f94c9f6a74342dac22c10bda1754aa995b914283b28afedcf35795b6df8b48679e85f60adf52167e2313f726601dbabfdd18b647c4167a16b385f322b43cec31ee7101b1fa22c7f1a2f3d830fb90ff910ca8e0dc29454aa70b59b437c95556648d3c4d08fc6b7e10611b802bcf7e781811ac09ff3e7cfe71952840f11fb4359f3f10e3839d242e3cf2f836710070d207a9441068fd17a5a7badbdd6da2a23638970d72c4acd30daf4a5b74c5ffa31eb2c5fdc1466afdb9cc6b94ce90c66c45bbed0a31a4568ee4bbfc45ba526dc9842dab8e1757206096fd19478308f20f2337d82d01de4d479bdd3e97295c01a6633ee5146dcf49149967fd6e1283482914dc339e2384e739ce6ae0ec771a5a762c903ad901df29565e2ac69a5206bcc9f9fc59e3ffa06da997ca1c1c01299cc85e22321589805fa9fa6247a4e3a27f5e6d3199731861effdfc2681338528c6b72225b2c2d6746db577be2bf23223923a7d8beba02ffb8d272c66b758942a7ec514740faaa879c75b8f654d4c21f3a881a4f5dad48442a3f2a3eabd58a46ce38921ce87116a047d36ff942632c601e33e2d70e104e22e72cc606c21863fc4232aa4184a63f33b6696bf2bc785e2ffce25129b94194e59fb3fef00dca413ce62567e8f6abe4249333328aed9f81fc738615e558916c3b0e6938aef6dc415f25bef2f77098caa17ff437fa478f7f14fe2882c31bd27be10f9427fd8f93d79f23e6d7b495b29f62df4b097f70f851c013b0c60c3469148e9fa62c8a8b80811ab09383f0d06cd9ca3ec0605d87f1cc3c3a5ccc3b94e54908a550a814ed17453d0c15918c000000017315002020100c074442c1705050532dcc0314800d6e8c487854409687a324476214a59031c6204208310046446668481b00c44d6a21faa695bdd88540057e08bf563a00b69fe8a20c14bdbddc9ceeb3589dd79dfafba5c41e973c51df2dc4d53fc224df1bf07d7926923e54285d6c0547c6dbfd9a4542903c06f5f05d5047e13115a92a6c8455210014e30e80a09afbf7782daf200069ee9cec4fcb5d0181476a8e3ebf461da85e2033609708a2002c1b829bed5a5ba9c9d423f05891d6aa3c98c6f5a7e0eb2d9013c42ac890c5c10845cfc763ad9e817a5a446996faeb74ea1a18ed05072f92d369a43ef9dec73a3c06140b81a766b3758ea96722ecad727cea15fcb3a5c1b5ec7d88dc1f3dd10b4fc2da917cea29438527ebdaf9e451335fb5d5d80c3d79709459a4504c5eb8b03d27db6f3d40224122f435a248477324ef8f6b78da38f24a805529a87b5288ebd4bbef21c319b85349bf2602149bf0e3ae9d604341daf6e7f595c0ba2fe7763a6f4868109c4e1dc0d9de0b4eb814a73ebf89744117778e04d69bfd4d2d43819649c9aa9a3ecc9af748688642f6af1f5ed98d494210fefcf4ec07401c964d8c3970c830ff68af33625089a6d96825f084a32e0c0e0d41a4a3ae4c00b045b6bbdaf8f623f62d2c3c1a588545778d44b8058130064bdb28ec1e005220a2909b247ae8f0f838a6938e9178ff39925c75d231a78c2d4f65a7930619b24e007e5e629ab1e081fef1710ee230d9e7e0d3a171ae5a0b1f169785661454d536076dea39344e25ba51dace31c85116751b4a661d0e530743054858080825b9980494704eb9524ea7006c3ce1fc33741793202bb912b1055a6308ca5c0d67c0f942bd320b29f6b9b92bdbc2cbfc9d7d6219094e8e3ea5fc05aedf9eccc55808c35431710f1a93662803741e63a3ef343160a478dfc8f5a2c0af735868d4027b2cf1386dc56b890dade39c703dddd947d599262afe5e690cf82cf062e6a6ab9315c373011ca5d674194764a38e5759a7e1c7102471b02400440396c2a744fe608cf0a247766392b5a65a42326b6a7083d038e755b98433bd2bb7bf861dcbb0ea3afa0eb0e59f0824b2addb0b69b0c2dcb817478358d5817bd4bdb8483a40bf81233dcce288baaf4d15cd22959daec350055a47d6ecd5b8ef00ce2ddfac779e52af08a2d92e38c3793e7a9536068e956eccbc458e15a78719bb61d7f46215d508ea9e68953b46a8f158c21e660535ce0521151a74ab37f484184f29ca52c649aa3ee963bbebd14dc50b77a4c53a616dd029565090292d7afa6966cd41527ec8d8d3ddf37c7a7b777a83234095da3f2527f5b2258051c8af149a20fa69ef461ece0290440e6f761d517c0dad75e7af894483ba9df88e79b3d02e6e64930a3f3cdcd2a43a60fd4310bd786e08440c33cc732a880c5279f2a3d871b5e95007d4654b9c8ee43ecbe5327417bd727b168aa245e726761cac32a54ac13b17a126c8025edc7cd12a16d7e42851fc88633355052b64c44ee2a679aeffa9fef71d003217d74e29e556b1e848a12fd19dbce972158bb4a940f7cc7761a3bf8462736e66d0c83b55c1e890531c490a199c88837908b5a4f3e8cdd5da35e79b4b8aab57e40bba326dd606b5f36c2019a2e94315917b3fed8c577ac756ca1524460b73cf35e4da328b9edfdda202ab865f7e2f34f23d0845023df374a176fdc70c2b78415f80e4645861bc246764c627620a62608e11fbf281bcf6613dfe8a37c177a8c2ef0fae3549e74df93c19123e400905045a42bf484f7307407d98fee984dc3a27018d9456a0bf007ae765a705722ca879097784c655fea33418d6bb832380f217e0a773190ca56f7175d266f21baf965549d72a74cdb839c567293d7c6f816e3c8debf8d131c16f73478a898649be81f2647fde29bcce20eff1c7c4cadd59bc8bafcfc735397ceef392e389a4e415a0ef01d8974caeb6c9d192c4df38da6dfa344ff139b94766bed4a0e7cf31e729ebab41f43c427e2c551d2fc9d8bea8bb732a554d4d8ab89212316604f9245c7b63417383f51507c064160ce9e2eda7c6902f49bac72472f1c050820c5f1ed0b72961d05d6d6a4332c4cd194addd3777d437ec549dcddac1a8056264e595165a0d4e406a5c5773540e1d1cdb73bb66e98f8de843d51bf19a47c29fcdd650deaa2040d6190edb7f407746c3ead87a0bcaf3a49bd912ef72d332b87b190c9ee681cd24ce4e31da8428e790970c96430a682408f5716addea498045335b7ac26f7bea71f1c74297e007aafa4c8567012bcfdc99d430bc6ebfebfb11993facdc71757345296ced0f844f07d482f81a70c5e99386554ff4db606e39435fa25de2fae3370303e3848d73173da2b129119ae8e2ddd580911051a515409d1360057253e102569bd74c0652293e4127438a57ab9aa45c4fc83833ad5895926495bb92feae35bcd325600a9ca3a4cdf9f263f4e59cafe1a7c1db0f19526c48c4edbfb3e308d3f8557c1456c51aa1b892bd7a124f82548b0ceac39575eacb2fbb1a36579f524e6c8518c8e0b8ab79536e955d9bfcd401cf72968668bb6f793b0c09d062f8aebee44a7f85959ecb4caa78153898cea4ef7f9d6b22e567f49f2986892549322e108233c09c50fa881eee00a415a2cb6e5216f3e514cce8e9d1aea9c9b9d46bd1070ddb2507b6bed66dd67a5871a89afea3846a6ba13cee60f71a3e224b4ee480adcc456a4602d65632be926b8d9348100b7a1cd980116bbfd63878e52d0aa0428fbd38c5e6665e2a8678e11092c05c519f32765f5873cab7c9fcbd6637f64407b2d8675e8b9e8bb66ae2fb1eacc95bbe44da28a5f9d42b398a6624693a7a8bcf361901a66480379493b80da7d510d05950a0c6a3ce3bbe309eacccb77016480e9a16169e0fbd48194931e0c0f51a9d16531983e1e1e94c04dc813e2a80bd991b981117197f80b51c60b4e0910f16fe4bd563796408fd030b1f428f3effd26f44861bdcad33d2be9c8c8592c1a351500f018f46cd58a49292957714ccacc7a9f0bb951cb960ff95c1712da13a54ca7c438c05f62add5cfba78190b5b923a5ff645cad5826165b9ef1151e1187a2c2be1832a99955fcc4fcef179adbd729c288fdba40035d08e53644e017b3badb4691591b22b79ce87c9bfa609eade0c68cfd7ed7cc8a16ff48ea0a694d38a963e604a1f9df54f9ac4710573bc4131a56c72cd0a3e0057deb03731e6968478fd76bbeaf9c0b177d2901a45406e651c4251c4a964d3bf6e4506db3aeb0c581b103209c079bee08b352e800c247701db0708714b13e4d7269a67c94ba82001e3aa2ab3c39f529a69276d6d0c37edaf8841487246a23f875e4e74123d804fb6a37a9804a626abe693168b6bf6c247f0ad1ea614754695fb6ef1de240db16b61da29d5db4e82c76e6f5f88f07aa1d2d6bd4c0f1d2df31696f5b8be35526c58608c442c6b08cf12fcfdfc304a8fb665ac049b07da4ea8e3b231dfb6c0be719acf0539bfd3032f5b45d866a8f978fa356262aa9efa10517b3ad26f1e86d4287fbd14193038a2330f141326d412315520aa9f3bc229f088eb990c22d09d6762c56fd13ee8e033e4e1db7c3b3845ab7c64456dbe04bad27a520da5400124ae04fb99009edf79fe8f236c4f8f64ffa0c67c3fc562276c5e24d4fc8cebc5e4b11292ab8facb50dafc0f9a3dfdde6447c14b8775b1f63ed46836f769a172ef6b6eee066d328f68ffa78d802662c4870928e1d87643c721d29a4fcc9d27e76ea5bf930482c09d577b8caa485b83252f7e22efea150af8a1986849b6f406d2611e092e11663a03bf1502772457b39607865d3c8414b3614e82d4a03184d83051a4db4f6f0b977c5e7343ba79c08da83a86c259b549e2205a67c059dca4d738bc82766ab9c8d04a659c8b2fed25333ee0e3d61d2382379df7536c2e72ee9a79803f86dc559469259cb8833790efae2515ba3cae401f2da91e4e9911ef51929dc80b15d4e3c703b3e9ffb0b50934404bdb31fad37f87f1d0bb2dc7f7946c214b0c499c3fc4773a1f9174a5632e5fc4734ce83a809735f044732e22bfca99123fcc2a8dfbcfd6d6f5f32103ce930a50c100de58e937d217503e81f6b5972702d53861d1ec1416f9fd83abd11a228e461025615e1da622eb2c198065b6ce5688f28c48acc25b65d1999fda983a860b308c00cc42893fa8d3ae9adbbd132d5efbe74c52ea6caedf45a061422900cca04fca24919368469c537839008ba95375f3e2de2cb4617cb6728f9611cd6e13a65dcc4484972ba07642b271dfb047f296c983cccb22a3006a23c0f130461e3974071c60ddbbb75a8db078e10f282b406fd5a629a1fb423a5eb80b65a513ac6cbb60ba59dde161c3e12acf455955a29638ea7435806bf9dcdcb9073014c5ce425065882796d8fea7058cc70b1afd029cec0def041935d6eefa60df08897a16b297f18fc7324894f923b93fafe5a7019aed62d483823311230ecda0aef5ab46a2139fc138449644e788dfc0253b7d1ff313f2df92dc4b82ff4c08ff36d47379fd86044ddc05a82a0e6f11566bed764ac356252d15a5aff943e52fec0b8a98891f2b81a18195d109bd3664196e740497a0a508d9d9c59955eeb879bee712a4954d25c00bd04f98a25cfe8a0aee8bb4e1e849fa84d8d0361d644679c73945258f96cff91e4c44dca82deb1bf45a1d7eae7ca05b7ec1322263d36478a6b411d795fe0bafcd52b4fccdd137cd5809c71514d2bfea641244ab539f9773883a1cb10505bcf4371fb0089fc81f909f8f98f16007ccb17d419d4c26cbb44854b80932d0bdf1fecc25e5460906fe0372f8e2b66ab5e98d55b07ae183ec2d803425b7d8c62f11fd04e586937b1628ad25713d9b6b0cfee4f7eef155a48f7fde6ba8b906a4ef5e53c1c6a5aeb385700bc45a536fc5f8ae5d5eed6bd653e81f56161adffe442d779fc4b16d039d2880a01693afdcd161e6f06f7b2ce9f3e070b1a0bfd0a28f9e56d01a2f309811968c08dd19e609f9c139e10a306b677e85a55f952cb9bdf5031d12f64682887a83ac67585168c41960e506311e214868e7d3e2f198f7740e026a50a55cfb71b54e2904002684c2afeece5ff79f0b03a6fcc759773af082f33252dc7363aaf54bfd34d5a34c911e41c1c8f594f02fbee561f96f67aa23562fb8d1c99890712aa1a033c2b187c51f9342126b75ba0765793a0f07944f031240bfeef0e1e209f46ffbd9d70f70c33bcd70c2d106d57c0f4d2c097b460287bc37e4d27424052d477c4ff93bd06de3c9c36fe75aec3a88441c9f75741de6fc88a6af0a47a7f17a50521924ad9d2a93be853330a55770e53526b0432269607c1fad82af1d2c8468a7a3f231cf745129ccb269611296261b1f123a15296445733c3ca43a20601aa17a42a7fe4ec329e8dcdbdfbc03bb95ae092dd3493e651bd505f56721e90bfdbb96c9b14ebb248283dfd2a14e3b1db8596696134867e4661ac920c608e6ee6c0b8216c322bf00a1097e0a4eed035199804ec130c262e0d3d8853f5e851663856b9f9062eabcfb4f1db55af481a58dee90630aade4cf836e9e4d6a2b4f1b36de494e04688aab4ce079cdbcbe315c74546ce0163dcfe94cef1a655e86f0bcb6ab7c99bd412f42a60ba2975b5faa1094cbcea2badfd0978fcdc61b38e8439ed7a32f4f8e47d554231a2cd3fdea54d0a6cf1f2c1b00a0c03a53aa7117b6626f115def912eefd7ebe8fc91a0936e6f930c460aa403744f3ee6a1796ffc72484518da7943663853f43616721a22b77113a48f3862cd692bdb214ea5e9eb3eb49f99008f59db3ea705dadcc1c1f9113f1878fd9f46f6bd01cebd23b83972ffa43bdb285fa5ee75315d401f6eca1343d023f0fc888d745fc8258be1e7cf7bf053694ba7b6d5e23b5d182ea920c813a9d0a05c2407e545cde1014ac14509c88717af79f6b6ce3275b3a644b5031d721a2a6562f067bf11deaaf35c90330187ed48dc2d8de80833e1638ec706307d9975a9348e857247c1f8151eb36f1f8d65dc46d381619e80f3ff6ad253badccbb0bd335a60a499580b23d3634c1478a21015801cf1f0423a44523da2111ca6ce25d94bc08c1f3a8a829fb5212d54ad9412fac7083a9fe86049fd794bbf2a7ec57f968807a2188d9cdd3b23a003909dceed0c69dc741a8dccbfc246d9378593c82f7afe610a7a87218f5892db1d3ca1f3b459156731c3ea7cac2cf7158cffe378e3b47d1c595bffab89a2730df357049d290a714bd1cbf9c830735152c521c6fdee2ccfa5e80e896c81e235426e41e9ae527113f549e508d32b8efda4dd00b326e278c428ad0d9f2375d3d7700b3334ddd046ea196e6e881267cce702d2a94eb6a7f915328bce2adc81a2fa9085a3e98f06b09df7ae6f8d7495f4854d983740c6168f88978323aef124b4b91383ce7351037a3361b5f5438bd59e13022f3229a76a193f78efb3fe73e63895116df44153802fe186a261f05322e4ad3e9c741addd8f1973cc2304cb147229b41e25a39c438c790230280ce4351fdddde13415368681911afc3323bd75487b47f8b0e576237f5e3f42629d5c896663d402a5ccba8bc848f886b8b6eab58528992aa50ba8dc198c2ac502fcb4cd79590f931932e5dcd3be810ea01057d2212d6b77f2337790837827a450e3737e12c26783e87707414598acfd4a45b02e424c81f8c282082a7536976574664ebca556a1dff0bcc4226624a225fdbe018f49aec36265dd933bcea917f785d38176671ae844fa218a4d12edc158bf0a558c7e11002cbf19814c82786c2dde069ed52649adba15c2efa32d84a69ebb51f672d15c0fe2cb78f90c5e2efe7cf8f3472fbf629def3cda2f81d4fe1ce4c813f67818c028c2d7708d3bced0b04f311bb8ecf419d1b1cb8a611e4af172428358c22e79190c0b7db305c594cb94d8e2b5d731a6a42dfbddc764275641bb91a8cf5719987a0d0aa1ad86868a96b92c2f231bf1c17f2a379664fa43f6218e7ca4096ba74559fecc0f0ab721b728455ec2bc976e751a527f091004f9528769d449248e6e310504917d1e1c991685a4abc0cffc9f91aa53ef5e64f435cebe1194a730f5a0792012fece49225c2c897da9824e18f526a0d34e53c402714e49808bb0ab0febe0d4d665f44527a84f7d5c0c5972b488102a02080a7ed4735cc50d8edd1156320ba2163b8841df0ba79c33c0ad0aae5a3f0921fd136544eda24823e2f6d4f0edc0013f65c6e93234cc6408ddb91942e0cf332cb79bb3a024f1591a302865b82de7d96c070ab1189c5876138991b2595c706217b3ef495c7d5625b4dc88813d5d6d9b97dcdc4d61567299fb0bf5f5acefb8d4c095e5134368b7b32e7d966144d0a8e9ef133bae11f50c3f59fa936a90e4aa788b6944f74f9527f673c08815c586d7eb08424ea3a95ec1e4ab5cc1caf12c54df2856565420568009d3e36b2ea3d38374b6f22cc2fa859a20f1b08aaaf729008412b195d558f08fa6b3ac5e92f115fdac746e7365d08b3da9f9e6abce1f02b5fa10fe70a8243b33cd6653d96586d430e7a171ce1c8a2e6e080ffc1c09c4e4baf5405889ca78e125364ca968154f29228bd162b2ad2b701cd22ca987d362ee142900ff6c06cc53077f1a20ad4b7471cabf37a4fb9e8fbb726fc91a37c2cd063d7213f812d12b817d6055504f5c230127862c5951e91cb303192501c33fc973dc056dbee1581e107c8cee477cae73baf6b3a5ead10b7a6056b81e34580593c8fa6aca611f685942c433781e837210caed7a39eaf58c7984488ae146b163ab45c93531bb3bab3528aad3522b7d909b381c22c2dbd98a0f0e329791b38f0c532dd837829e88b232e825b7778e83702b4a3317f850568ac19ff2ac6e18e644e4b904836675a3054dfcc27f2ad56904832eccedc2288de8af10d8d111d6ff401b99016a34bd2b7c498c45e3777e0c1372c13772921134784899288a52d38b5a14dd89bffc346c5636bc21da37797e63a701cd5858439c4b6f2eba1722ac8becdc609da866494b5003a12527994ccd30526373eed42908dca2f27091ce50d71e57b15da1ce7f7c52784d292487ecc452d04d50ebf071c6f27cf458fb4f00888371be3e09d07361725d9a345ed02c5e62031dd0695b08e11e442882218a83e1e5c09ab13e6fd7750f312264a2c001ccf9f40991bb4c27399a182e0601fe15b6f39f01e8b050661703336bb9199e2288b0551f95009764d3f5481a634cf69200a0a0abf80699b567b98181b1af93927ce9de7729f5c9cc02ca60bec3cfef563985b7b150e07d611a20af24459b00acad5a7f8fecd0da01a0083c9eea06d2322d0fe350238856d1e711bf517f98c90f6f561faea8f155bc7881c7b9aab6ba96e2bac8157ac35135c634cb2ad4b7a4049c90e796a65f15dc2091a46d2d1f404e8a622d6fb92542ca48abc670c840a0584d2aa1ff0e7151f002539755c2c42c531b09b2eac82d1604764c682b5bfa7184a2b02ddec954580c8ff326264bf53cb7293187dabdc545fc4f0683500988d825a212b4a202d8435c2974fcaa47b28d2c4208a5e094e18722e961647d1725dd25b91cb83ea2fe823a2bc042e2b345d9b171e24f6a08cc5bac2674c04a54284c37063a782db543fbae3d8025400672cbd352f75b8df4e38b3ad38b2a7a24196e1699dcf896fd8519daf5abeffd2657808e34f577149891d3008ea8986abbaa6803b04efba7c391912cafd65b3366603c5e1308164784c0f2adc5898eb88cb1c90b04a07d755362101a90724082912212f645514ae574938bbdcc896d78fe829c8293d14fac4d3bca7632b626375842b431b14d7009f176ed4c0ddd305b0d62d6607cf39562db10ea3d4536cc276eb6dd18fb3eb0024a1bc36f619a84b3b18c26d0a0d8ca310196ab2d7369b297923ecad96e65cbb4cfce2d904386343138e959f95e634e8c566ed8d6d9d747bdfc707a2e009d3bb8df0a83e332ae1819fd8db20d9b41ef0ce00c0c4dd201e7d7a553d1ee73fae2841aaa59dc96d8a89772c06459415f4292efc7075fda0b2fff28803d43f40610997412ea2b1171b436cc9abea33c903a57ffc052074064ea6a74aca5399f64a88eb31144be2089ef1a294e978d4986e874929cda0f8006697acc83034e19cb7136d8432a34f19ab64534d3990f183f764d6f9c0aca3f121cde876a6b196e4584f143e7cacd14fddadbd173125a6f39013ad9daa5dbcb205a10371738e4a29099efb30fb514bf39ad3f89eb6d580929419e5f194c9c6839db30da9f1fb5b249b807b75bb5acaf03660cd71e1916158452dad6a0754ed57cd326b061f16179fb5076574ade8b3b470f752e3f06618170b363f3e5a13cf74378a70779a83b066a0f16c59a2e29fc218b88133ec69c2d949c5fc6ee1c5fbc4d6d29fbe8caf755f0a77f3e1e78e1be4990ec0efa3bc7dc71517b37021fa6ac86809dd1ba05e79fcdd1bccb1bd965c7d08a1be948b94e17f305db20bf2fbfe7101592a9652fd928f9a01e0d8c7c32befc2323757d1fa42ee320c1183880461561c55096f69e90b7c03439db621d8aef530193ea7e756c80feceaa7c1ba989097f021ed1e72a062e981f2d4c19e376b0bf9c5bed5b3c7a0be6f4ecb18390f9db0cf02cd1471e1c32d37e56d4554356d6400f33df18e5891f7f743977de3299f8c58473f822df026648146270ab7bd92fe5023e0851b5a32c12f7b68ea76a7876d68dac8ff33239c21b38ab4f1621b2f51ec19c9f38385617655a4ea9bf2bb1f1bb5b2c821f2a5e946715c0752faea09bda0b77c38d040bb16b0586a6851eefac5c5518cb9d2688d21a343cd0f5e557ba5b3ad8d27e68eef7b31d9c75647c53619391a93e2c595b9651d9bd2e5ed4c09afcffdf1086aca4c63c73142ab08c921d650379e479338d93632dba6d9d464a103a20ef8d023e26196ff0644b02b0dd3ea03aa505f87af1a0accf33a9b0cfd4db4814000ac38c971122a016ef5666b373ee75919d48fe5dc2415ea42fceab2b695f1651da0847b40baa0037c4cf715c336123022402ea28db064b0d6e165182de343035df7c844f62ca3a64fe9e5181160937329b0a3bfefc58511ecf70541f2d78053d13c77c8f9b06a9d1ce9dda69204414bf42a504e2d343028a14f3b03f7148c076109b55f78f0b2b811fbf13b8bca02388822b0c2303a73d1434eb8f26905e8da38f0a5922fde395f1506563b2c2d02e4fb3bbad76113a46bdd0d164dbc06a096b6c035026db4702327ba47de9104d6c18706216e6ce898abf75f42c32bddbd12271f091f17c377793cfa89a9056cf61374233e72913a67c2ac4e8e373e01c299ca450f8b4eebc871eb6962428e58280d7339348d4c9e1f6fd09b6cb6a0217f7bb3274a20bb855cc4cd874de91541b72d8828acb6460b9fd6c0c0c975756e88d47ae1bf3d82df99989c011c2a432a2d7cec01f9e248e620f98d2b28b895914d4f23de5da09a035e26209811677e1081f43865085a1e14e429569d83409745085925bee0808c032dc79da7a5b0d95560eae8745d1e9dd0fae732fdb1132cd004af2968154ec7841ce98b5be88cfbd0e3cd700ceb40795b9d0c19baf77cd7a331c9326ed77ada491aa57e8a63069c039603b7c0498aaa2b38e3758fdf6247e551e744903c97d095d4fa3d9545d467326861b63fb0a0729dca9fd6f88fc35f617919657cc12125920812a8a23707a8716613e60fdf59c46768e99afa9a6da58067f8469a3f8a1a6dfcaee2b14d0916bc219712903c75f4c6b965ba519d7168886582ccbf58835f75b1455f301aadcceff582e77ce8a2b82e90b38e4eab4e3d21691c5e032c59b3af0401627f5788b50e654959548109d48643de4f514b7c1e93ab44d1746fa4b5afb3e9c2ee41636f894aca81c94991b6f27445b41643ee6bb4ab9825f76783f21d45aa7314922126967f12ce2c9a829024b3a2c91aa3372e4fe0d8738cdc441ea77c1425fb0af658c0b8648388df481922fbd18df8308f0f2d89d2c1150e012926da783e5f37256e9090da64b71e909b395859f706d6b4a23ea97e28e3a8fb4d847823412c734391a1aaa217b3148226798ef1708f6ec9ca5f96431798f5db1c38cc0be4fe8add17f231fb37ca188bb62627285c8871bf199121a0374a6bbea912b0c3525a38ae72d1452e3bb3fd45efc13442cf220e43406f6e984a97636f567960137d288c1ee56476579842d6df4d00a02360a874bac5501cbb69d1e31cbc8d518c35c0eff8de2005d26afe64a81860d0812795a02a77504c04a2acbb34b65bc913746c8c75806bfc7339c893a3a1a5363bfa567e1ef621469ec044c2bcfd0137e49660c663263d2862cdc6f281dc3419d06c905c5b52dc130d6dcbc95f57029e5266f6dbcdf30db08fca995c504d4853ae43987d68571971841fe389c1fec94906420708d84449fb045f9a8e3d5a58fbf242395b2a319b2c928bacd990780a66f91060ada6e678fad2099dd65cb0a4e11f3bad420ee753ca0de6fc7556ec6acba30d40cc2ffa7c23d0b41d401fdde0515b8a1d1ae01d9bcc3544ae32785800df5f706bccb63a9040640d19660a70e4a3f27f41eebc727fddf1c2fcd5a3b5b957932c7f12f2d635d52b2f5d3f464067072edf6506807d580e42ebe23c276d00fd99147037282a5b4a064e1fa225b790cf5dd5e651a5b9f1a1ca66ebebff8f502da4f4883da1d6b004edfb0d04fc700a16678dec53b0751025280b77264de60f8404a4003c5a6c46abd5e7fdc992ec70014596769bbcc3f0e2017151d169951d506691472e9a00617940a9bfffd255a06f36401b54477cce40429d0cd75b0b2ea9429b4415e6aa6d89ef56626af902da3e9ebbbc9963d1f348543907df82ac307a698aeedab746cc292216a5741df8e283dade90b443a4371978105cbdf9d2292f6ad695083f9de6472bca4b07c300359579bc3adeb80370db3ba63060665258036aeab1996c2f9d1d43a56fd35bed1b97cb26cca48f150c69c9f26109de8654eeb84d7e91dfd58f983fa13a998135e150b19847b35545171a7f68db1351597868ecf4025a7a0aa5280b907e3cf07f07d01bc48123877e50c0fc4cfe847dce0735f0182e60ada9be06f46e9c6add7328734a5c51258914f2960a3c06a211815fed62e757389e76090cabc41fd17fd11709b05a9cc82ed53191bf21e428e02eb97b42ce2f1eee17e34ccc19a3d0175744ea41f6246b6d53bdec4aba52c8776c787b19a97e2304e8d939829c4ccb2b86fa8c9b30b9ca4517ddcfacfa11422adc975657764d1eae9f67c848b312a7da86242583fd1441fc8a48e7a95495a72e3de8f60b2c0108c1cfb40c6636328d21fa372ccdb53c730b93da1c6c56ea0fa586c77c07a5af50d03e192b6c9eb7b56dfad42e66065642a76e56eddfc2b4beecf964a1fc20897bd7d2815b7af682fcad08e5eaad68267d84b2b6efd9cc87c095a54220cb1acee42a920360a7a913ac5a59e8871699ee61cb1d1c815f1f312ac9840ffba2c3756c2b06150e54421c008ca5445fff8378495160644d82c85e00b704bde8f0b6aa11cfbc0ded259f2289684cb8a930818b2bc37ab0878f0574188c6526577161412705b6621dca599bebdf40cad6e3bc4956f3cde1f935ee5acdb5f80ff78666032e5846046200e7b66848617b9fe94c9c3bb7cb99b13d9df3a6dd33a1fc3f18b060f3964e4f64dab5e5b979810d851b15eb448e46c5b6088360316d3415bdc9d9a80687c8c53e0864c5e44c725d1162c52e2187cd0554d3b820b918c3642a548ccd22f1460f55afe791b1c4b2bd0615e56ed7d1eed834a36e1de8dadbd63e7d62110fd4f15d8f454ebc31b2bc1703e3f90bfda3af7f93f93ed71e9906a386838493669fa19271f665ea89883dc96835b9d4af59e67db7631c41b5ab55f55accedad0c97e1be92f2b3119e469d039dc98aa2b077ac1c3b910868c2448d48928b66e3a73078d9bf7cd407c4203627ac599c294eb2cdcdba6f29faa11e4406dde5932e69e323ba1fec3667fca7601336c41669be42ef1d04b32073c17ce4e379feb635d5e416a4f0f01cc934dc26f199506bdf5507d5f919eb6e6c9f1c4f679c9aeae7aff8c44862bdf9eab73637a54d8b474aa3db84692d29b3c596e73746e19752d53f4f90cfbc1458b5edbf0f1f398c22016692bf1263ea9f79f0e15ce7734d03468559ba798c391822a0cb0a77d09f440fa5056a7d0508fa170f4015afe32226cee9105c68e0f925bd27a444069118ce947b5a07aeb577f7ce3f0193fdb4a4390b9fdd098f285406018d9e011e60e065e460a37ed460e408ae8573847d8dce9e97d11c0a9375d1482cc1529fabb003bceb063697c07256c9432df4f638644e3136e80abbfdf42d8c6c96ed33f640a79438c18f17454f3f51fe908830287e9b90dec8137ed25d0b7ec098d4f6b33229455707a30a1191401ceed7d44edf7264f820b7c91e67adf6478c1b5ddba1cd27d88c17de1fd67ddf3ad086e60392927f6b9499413a59a6a4a95d0071e0beb6294fe7e7f7b3faf797e5961e2adc6aac24fa42855cdb4fb6cb6383469a1d9b5b0fb95fe1caf09dd6a3dbdede4c0143337bf5ec2c60ad8958dcf82544eeb5932ec238a01604047dbe649021e6dc7b34ced91e04300299a6ada995ec654cb3a933549eafd0f09cbf28f40db7118928c03e806845f32dcffcfd094032d44cd4e6b810dac905258594399c115d10ba401e8c179366b35e7db316f6625fbe7faec0fb15e7c653291e7c1a0afdb2fd62e6f1b70a35cece9307ab268cf00f46c473ea1cc94fb95f771a3fa75cf03ce2d56a90e1298feaea25bd7f41509887ebb449e6def95327d6db66beb3b74bc3e8606dfefcf6dd34f09dff7d8f3e72e52ee791bdf5e7cdff7cd804d5a70bd5f8b04f048067a9f05ac5688afb47f8890a3a16e3d79dffea05e6b0bb0c0cff1ae1fbffbb9906b839f77c1372848809d0d60ff0eb109cb04031b867ed81344399d72d071f47a585ce6752cf52400403af8713d2e8461029da043abf0779490eb545595c11008d25505e6a22140b31a3628deabd8c78f39fd0297152aa7e0a1609e28ba20f659c73b71e99d15a4a503be3f4e97e7e1681483861d811ce29158d67665299a2544e8b9e96191789afde0e38f6431c7c3f46d0487366cd24a7843c7f2a0a090412e4abe391e3b36a4770b66568a12624f0565adf24f085f26fb9f994822878a388c2cc5490f9d52aaaefd675bf314ff93b7e51fea85e2cdaccf0c531029d036722adb03d798aaf737615b75e1a9be9ca2c6327ffa403ff2992420d979ba79306a91a923dfd52a8c145da12c35204104c6e556451146fb93cd32ee9482b57b8d08b08dda237dfc064052a1844faf375890b60c09cfbb2e508c479c5c5cbede9519aa21156b167301d6836df56c4f8806ee80289b3daf6d8acf7d200bdde239a58b8cf256e9149783b7b8612db6b8b39d32234c2fd7d1fa84418627b6ae4cec8cfa70e183afb55b0f2be06543e3b7b1c5a41b0a560c11980e3ddb7acb7299e164c0b72b6f74a43ecdf7696c1bf816e6c1e1f545c4a1b11c6aa67ec6a0557fafd0e43ee150bffcab0aeb2df17e380735c25c344bff74c8806eb556c75282da7fae0c30b62babddcc51684352b1136ec8ef5ecd69e21260d159186b83da81dccccf42d96bf0f1a42dfe48c6632319449217a832fec973b4b368c42f5e4b6a7bc703203b0372df104f6fba38769ac0d736535f89765affbd3c5a3e6a5eec30f99bd89dbf10a305985e58f59725c00b88f8af108548fe7411eb58339fa2365ffaef703b5f47e8bd2c4b336c4c0601b8e790d4218b1079dcace49a395efd4c557704176a3f86b2cb8ff4029787a8f61c641d35b9d9e42073f3a24362969458f481f69f9fa22b9c884017850d6d49a5cc5cd817df18a2ca7aaf38e7e793901c9e265c4b5813fdfff973ecd3049b89c37535ad1848e74a2368934e7206b778c5688acfb73c35a9f3942044b4e3211eb2bcf2b376b719f69de60ca7868b478b7c56d3daaaa1b24294db5917be0413f6ef07609e2127d780cc095b90bb34bdc7eef6009405d41889f179454554836455a112b0e739fd660c79a9751feb57479f8323405485e6bc8ba34ad147d26cc44baa501af848ccba3ad6dc56ee2ab02aaa93df6a1588e61db6d5c2b628835deba255c1a9842af465f0863f7469cb3138caad750918a4ce96d5b68a9659540dcfc573e02500e8382bd444d09a292eb4754d8debc7912c348b66d652a268b313842e7b1049ea658143f003f08d4ae5ed0335c1afa1a13fae8f583914fcaebb2b97a431022967720c2e740bf003194ada123638c80883f4d7f4394d07e3367ad1b8add6b115351cdb44639c706dfa54d097c96e6200bde14cba3c15ae5c8207b65cf28d096c379f841762275808a8f5c2d42ac6e12e13dce197811d5dc208e34a6fc42cb80ed6f818e315a3caff03eff94dba9cc7b5721d968452df743355790ea95df3c4749c071ec3f1dd39cb0c72e7c29f2e9b7f7714fd605a024c57363796c83f36cd40bf392b4e64b4a084e6023a9b62de160fe9e21a779167762d6d4acd84e095684974a8e23eee655604bd1b8e36b73a304ec36feca210f233710c84e7950c0c97924b6623391e4825a7c786c0d0000fbece2f11e3ad05378b551e172b9771899096a8686fe0e28a423c3870612fd4feecb5e35e1e84faa9d6765c78a219c4ce3264dfb1c486856e627c544957e3a7b76adb8a2650e70ab10e631e102258a92d5b3b0149c3b34d0353b99df2b783f156cc9bfe62b5026c28255ca3a2e4504ea0d5afcbb62d6e6846247b51c61343a9996386df28a149867a2f67078c9c12312485f71e8f73d33ad81128193b41bb7568c045c713d2da3264ba43a436a29e27f359df1baa4cb327b3cdec952ebd97a3448ff482e63c738e9488551336e70300f7b4af198cfb78a20e03a8cff7ca79d0b6bb0f942edd76a63d33ccd9b0c9c99669c76e837073bc34289a45fd2da77d35fcf642630d61e51d4eb7d996f15aa95809108ce22c2da5e2733e45cfb48e1a6f340d6cbcacafcece001c29dad36f546e6deb99994870ba4c33331262a6aff1e53cbf6af263a6ea363edddf140cacdc0a4fb48ed16a8c0a189e51576e9dbf7c1ba39f9c0c2f95f5074ac27f3527439de162dfb7cc476cd78cd1fcca2a3fb86c047c4c1760e927a36a36964f7c495244b175f24c687589438b456a221e1a44d17b82691b640c4897010e8ad17af9499533a4b5027f0d4493a849d78a2c2a23a6498b6e32070313a74128dd7866080d42181edcfdfb2357a508c430e0ff4e8406c0b40db15cb1e9163e02a01597a1385dc157de44a2d0bea3e87e1248233b10320c5c9e50985bc95a9064a171fa526beb84700bf636586028de38bfdc6e7253e216250d12a3f29dc4b1ae9961bb5224597a5d83660ec997fdff5e696f8c954e0c55c430339d092ebd59b00a73eab89813ad12dba834d526069644a4fa9d1dc61bd160a9d23d884b37e702eda2ba5c916ce614d6a3dc5b88fb08cb6cb9dc4979e62e571ab84361376290d8a29cc41c558b294a152344948579e7b71685e35cb72f8d0797329414061fffc04c1f00b0d0d469a593da077107ff175b477ca5fa164d74b935f72aab2082616a1353a961055c7a68acfe3b117fd5c97dd397a1cef31b7c3a293a29939b0ed74eecefa16c59664f2c6b1ca14687161a1ac6b53fd020bad86016c499f391dfc40ffc4475d63be7013f196509ba3b8757f9fd844a3eba245e8de51c77a4b3c04ce4d241d771661b9155fb3882ab135901a712909b22161358c532ed14eef9e411907cced8e099f44e333d053d72323aecec0db39822b1e173ae9f940932dc2131a4092db728d6e1b8cb3b3a25aa3a8299e0e06a6a5d4716277ccf58df23d98d85e9a1baaf4d20a45355a9bfd7d8408127b75130fb096bd8ffe19d58a6a8cb83e5cd411ebec32dbdcd990c6ec53e8c3fbe10e41ce1a6671ec23a1fed705506a33c7f10ee40a43868ae1d20c0f2dc09de2371dc6368afeb05fa2b894e4dfc23b38bffbc7aefb3a34e9d99ff39f7612dd93e80b4da01c8f2e3cd5cb52018ee3b0621f3c319ec37738f4890a95e20fc755e4dd50e8beb60d2f9f86f034d9f5982c4a01587aad68cfaab1128581e2a761ad422ca082540fc27681bd7292ab01cee7da1e8f7053c9fcf039595f4258513522d7642593d90a38ed8bcc7464f0d4a7e16f01322e881c6590d5ad8b76fdda82e64ec283770f0707a75032d7a14c74dacb0dabbdde355c8213fbdce4007966277ec7bbf38c431219c1dcfffc92f09cdd486c0d8125ae4842f77a972287f3bbe4585819f097f8bc92700fc64c23ca615bcffce620ced129c223eb4510d5e43cf5d8f3d09fe968da43403b319b883c2ec8fe71810e47b4122a35353cad42c3c107f972491806c50dc3b405b949622af078dc7e598891764e07f6631e020577c41375c5c23fd01eb67ae7f83487692d0e31a9d411714ef99b839fe078f33e8c5659434c7a1f8d8b59132d63ec93d8a935edac8fc9088f957fdd901ca5ac30e1fc46484563c12f98ad6ea85ba2ce9e242ef4fdebe535e698f9fc3309f23701edb7e2df8868a324484dd9efeb42a27a118c41f79a745884199ff432b0f62f0b4d0eb1920066d663ca6e238c100e6953f3857b90a55acd02b0956de3162e649b240d01bee2280464cf8b7c5dcf4e356f7320e8786628cd73d863a23162dab36131c2c8c6419883d1f04a1a445d3026a183762423a6057459484168c113bbd27bb92814e050ffc55f2fbac00916da6474c647d8d075a02a679eb5a99c3d9e1b4b493bb363fae6183d016107565d6e7135e191b582894ef2f70e19df444d6bc4343c389da27ac72c80ec66f8cef0931b5c81e7119b03fa6ec692d126fc24c97a6ca97e0b95dabd42d41cc3922bc3dd7437fd55a2d6501034a65181319b78af61192c1611704ec1018915a23027bc018bf4b20bbd4c8f445c40aadd926fb5e85f46beb003bd51e9649623b3d54776ff5215a2ae974b66e6f1ab2af3068480bc075d6d0683742e1cc3aa0f5c4df5dd0adc9be78232f25bf5d56574145adb0d942e1c6ae52776f270797c33f65dbb5b7044e1b86585e5361991fbb27a409c5502be941f2d1306de3ea69cead92d6c026fc6cf9c9b194098db4a273c6e4f8973a7065e137e38244ea348da3f67195eb86b570541add84510259dd8fccb4635ff5b450ee64739bbcd057cb1a23c3619086477c38d5ab178c20004acd416a7d93b0f449619a96a3896e79f586716c37221c5012826dc6ce821a26aa096b45bc95aa5ad17942304ed323cef6ea71d254e9bbb378966eef23e1f9403ac99b835fea3e15b23be21c8c19b5cafc0a557db9b2c1efa9974120f34a995e7d0d62e41122b68521868d912dc8186849ae6a0a8173bf716f6fea4e22b567a501328442e078fcc64e99d21d56a6133898e9dc1e28534318c8046b7c6147f31aee2d4da7d45607a705240d4674052e54a4e0c610f2786ab86070605c7004ce4374a57904e3d31c115c165820947eeaacfc735b6dc4040e1a6e6de66311091683ab09078b50a96b0c290f1214cac1ff6d3aff0a4db233032e759b7857b7d99b04298291ee0499b47a4463740ee5767e7090935830d3b9702f1b710090bc0b6b7b017838c74a6aa2582c8aeae6808cbaf041c4e613592f938f1d34df5e212f1031171f1f6793993da248deac0f6f7b7841d01c44d9e2dfab611f78248af6e2872967772b56c7a7cdf1b247f26c9dc998e8d40bfce8f6aace2d45c14ebd8a0ecc887cb433764bea80c73722f45ad3089d688884e6a0f990e2d12149b79bf5c25c2483155a166d7becd884c39b0d3d7ba1dc40305e50d45e913a00153992e5d2c727c6ca95afa884178f732485694582ae3842c253784c102cdadf0d3cd258d80aa4d6bd653be10fac7223df09ed0282d440ff808f9fa4c32464bb610fe887a8d1e4fe662e3a277e1e61a0ad3417b5ac6f4e8d9333152801a06b46d0391ae072baefd8a0ed33f4e5ee4a8ca41426a61ebfaf26072d08c2c60dd8fe83a4725e996519014b8266ee1059383876c4a7ffd3468f509f3e82b1672cb392617f0be3fcd0b158fd443d9e3322b4737c8e48811b6fc37bce299b2154c0f0f0258efa89fbe79b1cbc0465bd5cd4d20baaa07307cae3234d281ac9b09d8c105a8465963861818d280b6a9d1e502e31eca8ae30c427627eb99bf7bde688dadb5e284552c6c96241406161b406022956887b4f6015a60333716fcb4a77d1685c7d32c08cb9b221f5a147a462d096eeaaddbbd08a2f083c357a112d93886e81b38966e769216200ae07add5661edc9ad29e709e1d6fbdd08f5b5d68d2f6e64a5a6f59121b5237c63284792114eeee781356f6d04736be565a8534bc5942dcc8d6a8515883944a950fb18953c74ee4dd0f31cfcf16845ab49ffa715d6960601779c689d2ee24f80060b8b4301eeb766fdba0d5ca22ca6afc811ce2f70fa6e0b337008ad13a1400f47d4aa1698bc0de4a99580dae2098441ac60082940c33a205ec94b6b80390162618aff5b7d553a7ec60b9437c092ba57852a18e45defd962f016726b1226ebca09a3c622f368707eac820438a73981a745f2049ce4c332edce2a44860235016477893def48defc56fa6f245417cc55b168b41d6d1eba62f9a79e889de4a9420c1aa8bbfb628c238bd3749bf26fa52348d70d7daa9f56a9a1bf21af9da5625693ae1e4554e8d72314de0c381b742d750ed03411d81382ea0bb02c073e1b0a4c130838b30e5b3d58efd12e318bccb8df8237c6401f3073b0967c790e9982bfea422966b03e09fe9fb22ec238e947fa8c2c4c5e065e51bf09107f9eaf53034faccae4681df94c5ff00249f40b63ee18fe1fd1d1420d82a2943853a2a6f79df284b49f1381ec534248885ce8b15f8e5e30393aba82f584d9f9250ec36a28b1792fe276c0d0ae483d7dbbcb99e01185d48963c02081a59547caa3c6cdb5d4f40e56288ca46435ece23f37ab9b46193c8d2db37b0276ddc68a0c9b8d2d4d7912f2453c7de775322a4f6a50388c3c650749a4c775b489612d00677261afad697dd1a809ec6f58df1610f1e654d90c99480896a014b720e1b9454da8a5ebf0ccb3c699902aef67094c3f598516cb4a6749969bc857ee6b2890a1a98faafcaa3d6fa5ce3b36fc3450f8b4c6dfe05e0857c34ed043fac807b42cd86ca2622fa44b665245da40350040ce721db6c9832de2d3767a290571a2b5d9138853d1d75056755cf8b35c33e4b91b9f19009d8715e78a183906141c07ea26f9e3aaa0153dbfa5a394d693cf5ccbef4761c6ee12b1c06352fdabc4253c34a2d5ecb2cb9c2182567945f791114af992e4f88ef4f3def31b4736b42e423dc9f99126cb391a00c9a033df3847f87f5d36680afe00aa7dc8ee9bad28987b02b07e89186346b9077b70c3d43d30a0382dd3e13e0df963a75b5dd291175b01dd25f374f5b51c83a071649d2b97485a81aa4bfea678801f2ea5afbd5a551b4f0f6a2e96f826581c85f3e9f418aa2670717b15617247caca81bf4f218488873d62d8188a5791b2485a2dad26902ebebd46e8d76ddb46f40ab5dbb39ba0b42ed116866f9729360a847730e8de31056ff3efaad458619088648dc2d23007b0bf80ec00495f214f1dd6291e1f00124b40ac71f8a42b6a4087ad9b734e0dd53202454b3fc242049e9ec17e162b7290e9cd668d6a0df6799600a15fb0da6367400bf2ddc9b7854246b4bbb11d85fdcfff118bf8021fdb090ad73c3bf4b17e5d3404e209ef4c8de68b22d3eab71ed59826e17ed9c6e080d4ffe9af05ed814ead42055e2835b11b9d2604fd9b5e22d9e9776595e58c2bc8929061c93ac89f25198503822438ba64e1bd676f5412d7e9042d152aa91ba1b16cd26232090234cdfc87f75903af8fe5785297048a0afe1d176c84f8d5a9fafe9f219c5446ceedea90411bf7c67b90508bf0ecc63b635e3ac8bce80463a30aaa9055bcc49149b59be574c385214be44a133924c6467a7b50011270af5e59a68548408e830bb22522c1ffc244e90a9942ea1132baf1dc2f81d69723d7bdcb0ae030d45a1ffae2e49b44523ed1366bc1adf2bfe8c1681e4177f990a4dcb6c1216e420dc6ae98b65f9cd9251f665658e38d732d0ddc6d66e4f79e5c8b0cfe6177805b9893f7d3956c6f736f24bcce66cdb1093bdb81bd059dd5a619a07dd0b1a6f0ee2c4d000b7610991887dc563f1a0c3e6a48936c461db5764c1fe15b5760459ff4bb97b40ec14a12c7f73a51a5643ead55ea80ed594bb420a98c2b3469c8b3b18e6f0e502bd30c819c5e9abfde7856bc549019022b008cee08e8fbbc30b56a08a6379a9c057a3fa39472b5ce793e28eaf0545d0184c0486ea2b9ff7cfb08e54ef7cb35a0dc24165579f8daf71058d867623b6e301e7cfae7792db952029e67749a4e57c570adf7993ef0430b92afa9f607fbedbe491d21378578d3a82c14a5aebc883bbdac0872395234a0c40d0b3017790adfca886180e24b3d8eeef64da18cc75ed4bff81193a51688e1db0040238141eb5425aa3a77e9b26a9b984dd7b4f59ca701843264a01fbd08a7197797c15572418574d7d956d6f27f0f5d4a55bcd8391088fbd888b5423b4cba81515684d00ec98e041f68028df9d8b5e24560f720211dba38c70624808ba8b4155d0d07836962ccb410ac5c36664f542a6409bd0220f681e72aba68fb4228a3ae8656c9b8276dc86040e00b3201d96b89741a6c424e18f919f408a66dc0230cbfcabbbb6da59c7fdb95cfad999413174e112e98d432a7fe8355df0e62c1be6f81c48e49b751c80a820245155073e540905c2eec03b887e8a1462cc33f5e242120ddd1368ef8d2640cfa186f3f4e8deaadac608c274a586088bc2931f681ada8b94772e08e00971858e72d86feb1218c6bb2c72979d0eefb13625b6922cb7dc3f35f227f361ea281fea09cb9a7fdfe160092858058c93defa94c95d8ce79c76a2c2286bdb7a56707c582ce40fb274e4485bc84a8088c091f0143f542e1c900f21edca4977e2bd5b4878d47ccee9cd5533427fd454d60a16877dc962f6281894455db796b2d89a8e9d0dd01021805ce05a16abd27a9ece9f7aa69d69980a8cbc1f95d628b36beb2d6cce5c6dc9cd320dd4e3ae5062c43b0e680e9b748e0067f4b2776173e829ef2e25f76a447e7c4dbd40e78f9b24d4f6d73d2e12cdb966cf94f42be2f15d9fdb23ae8324aa618891d26f0cb84545e7bb7209696f4d6d85a9d5d07b4b75d79b32d9e46f62cc711966ca935207ca1c4d17141faf3791811c2d1e6976656b94ec57e243693f7518cb94da552fd56436562a59457fad35c630541720482728e6bc804723b1fa2fe1222589ea16d3b459694010177fb58c89877f5308b5302f92218d3a1e6d3f1cbb91d8e74cc53360ad6320d2079ad499ee358da566e03c229ed95b8fd03b4ebe45d7938fe91d57da522c991668c6d9573a251524ae163f0eb7efba06ce39f17ea0747e39d164c1ea422a2c299ed145ec5bc3b4d3373df4059315ae9252348285eefaa0e9256f31d0fd2ccba7c5593604f6a1e54a1dbaa427d5b2888254c78de53205b305facf8134c9129dd8b731c7ceb1799d417c7ac2e54c77b2e557e50a1a5fa9ca53bc70c5cf915c9fb232ba6de51f6242ea9163687358dc9450dd1d232b121f4456d09d0044dc830a6d06592ad9985195f02fa6a3b627322647610732f51bade881f9e7bf08ffe7365384df76d7af0db836873d0bf1722e96ff958a5d0672b77991fac685092f33402424d253efc0432bb24db7f2905defeb7f50535d163a5167e2c44bdec69d89f0759d69410b4b4d34ddff78b2fd578fec2ebffbffdd2574737b17ba8a28517f700742a6bc7f29a98b436d315479111edad1ce27a8a6f3f7ab7f4191386af2abd1f0fb9b1a3b174e07657512782875d66f2e74f9702f615123dc2a2ab240ae824f73b1776d0bfa81e7761252a8309f303e8ddf70b3cb0fbf92b9a5998ae1877d4ccf8cf2323fc894479efe4cdcb57706ea57d8529143758685ea05e4f3ee80d81ac60f716f4f05039591aa3d5534cbc9b596095d2500f146586edf4dd8c46325e3ce9c6379caf15780359264e44ff1892a6cd94d1431fc38f3ac5d4d8d2892b8e34affa182620494e39d324ebccf04ca94977c8d1989570c58a1e90d16f287bb0755da980413f328a60092265ce8f703357862813355efae8225311e1e597321f9cb4c05aee6d33c2c1cbba70c1680459910b7f7a26a319da2b1270d87ac1b81061d50ac6ae45b8209b015372946af64e1c35afee469c523d261679e06d15a1b19541a69b9b11b848abac044a8ea3439e939370c525a2b425df1a80ce7e6cb6ea0bf3ee41b97225bea891f220ac4860b96da108a4649bae339b66b064b3cbf0292ee18ed2dde95c12889f2d8625bd6ec45966bd64e20bc5159634ec936d3cc1278841c22cde3c12c81411236e4a0478a61407ec4ca128410b0a4fa46ab90d7222e9c5ae991b625405fc6326e5b6d6bd8118bbe9c203eaa046c33c61220c2da434202f723b5d03422165b08533319b21727f60e80fe8aca322d38280477371e968bcea88983cbb38848968c2fd81a44774043bd852c84b34db90908975e0882a5c2521094e9179aa6e266fca01b7c90a99bc358dcf443744a6d5c54557a8b12545d70e485336cfd885251b5ada773bc3d0abc98397a25c72feb27f5c3b4eafaca7c10862b9c32085685003c6b5486e4cf95df7aa86d5f1343c2c1d4d54dd6b3ebb4e6a444804119278eb1520d093ae5c5515134b5df36ec392ded59db0c0d44547f748278d9160d521f9e3f0896426b1c7efb2920a0a60e23dcd83e84fb6e9efcb18450fd6f1eb4d63943a5e280a6aea954d1fc28fa4357b1ee8b18116867aa7347bbe0036fcd3f20ab78785fbe8052742253f4a7aa73ef1c10af1f6a1ba64fb612f068b244e1ce1bbc12cf0d868a10493aad47c20d3982eaa3c682d1031f29c2cfe2b4675e6efceab113c9fbfa016730585406dce641570a1ee511d04941fc98c833ca303d5eb93ed2b4c0b445125b459638cbb9fa2cf38273e3e24329ceb0767cc133ff22504890e00204bc8ff489096b4e783702f161a30595669b436b660f2c049f28b662189cfc57253f703e06d3901f7b3a4225a221cfca65ef09acc67744b0914025110d6b8a4644cf7a91c1e375927678be3b349df58c5bf8587062849cae471f0dfc5d247d7d58239ee2d17a3967321eaedc0e6d928733384c10f4e2b573d2443a0c2e24ac23f5de96908691efd77a92397fa0e4aca95f96e9f87d408b87c2ceb4262a281b9a430cd06c309c2ba5feb9b2151594498b0de5b28d8b091a58b0336b107c63e7cee058ecddedbde3a6a0bf99751004ef4364428a1f895b97b8fb40a47d23b3f8da6eb7f04093a0067756ae3c74056fc2714e6d2d0413c72dece251a64bf4b3ef103b67bc09c4ea564260f683f468954e41cbf95531cc4e46e5193c0818b821af77eca5b0a9b7c7c1d25b41a07fb8ee76811e3dd80212cebd8ab0a0059e31502108da5f55e2ed049cdc49d74b0dc1219fa85a269a9671750833441b35201203a06f2829e4771dc279b6859947e1298059188ef4057b061f6e2f7cc8fff29812f0f5ec49833286ddc44a9d9c48e86c1c53a0c3538db8d4c16689071d41aaebf2bfd23fb905c61cbbdba25d8377cdb58308d67ec48082be9ca30d47895f20bfb415891b52be294351199a365716323d5ca95000873f2b36fce18dc120d840799d1f4ea71ae20e35841a6d4923ffa305a14f1cacb4889036b7e706478334629cdf0d4eb31fbbf42521c822b9c85fc5201d5196bf8d9c5b06893c948f0f2a38479baf71fd41b928d6a3231928e89d448e5411b1a371b4cc872a90eb8074934253e7247843ad3681d0e91b8dc8d3ea8169c0b25b9575e5aceaf6f80f0a067f3b573aab9d9b696d5bfcdbb2013ec084b9a1c16b98224b5b887be9dd4525c802458a377810ff213df2116f84a51745b97061b8ba741262c45766645f453ae2ea62c323ced9704c65d14a6668468ddd2123737fede108000414cb193442d4285aad5366a46f5735cf14630b25a0d85699747c94f1f5bd8cde5512d6ec410bff5c49c40a8ff541d146d420742ebde8c2368f51b864b40791d3698014431aca6f8eefa59f2b869354ade572bfa3290ec6d2f6624fd27e89be1e57292f647de17f6c636e25bc38bbde23fb4eb183985be1102358fdd5a7303c4f7182b8a60c8883290af8273ef2c84c18339dafb2e3b455e422d70bf824b11f3538a4e929e85e347dd98aaf1741cc98d3a7493cdc8a05666085732c8a58ac84864606d92257ac962a384becc55fdb98792d2c6788b37d99c9abe574806089301f5a25fda8e60471afe61b50be757f532f858c53822da6b14f9ebd5640273bb3b0a541213c16c6c525f0c1cbd8c994fc14e5af2785b2831016f960c89f2f535bad650a5aaa0df7cc5b35380ac07242b003feb85a0b149eb7e1cc616071fde0e948259edc77c26e0afb30e129a52280a4260c3df5d806a03a28686d2ff843044cbd14003d512e53277f75ef29de7569548b37f425143f75d74546aac90080548f101fd7e5416d0a787d0c04dc441f0184485e48a65075f5071b74eb5fb9b0400991c0dd7d7c12f7a305ae54af83550919881211413303e3a84036e2cbaa7c979ed7c5116dc4897c9a090f2cab16afd11cd47ebda21e0f1cac3e7f50ccf5020eef302c96fb7ea4d42e0676838b03bb2bb87090e08393eeaf089dd952237cddabb898fdf2546c3fb5172244c55605ce92615905ceb7bc0c9c4468e6500bdbbf0366d581507096be15e7b72c5ef6b5fcd78b8f7f59fcf9ae7809f2c96e55e2ed4a5b2bd5869c19cabe2d2dad942621dd56707501739471fe86271c62e428ca79e0c98c8563c83e580f5b157d30a1571eeda7cadba089c80bfcb95ce2856d4813f848baec1941dd20290fbc8803936c290aaa2f56438462cff30d0d917dfa25e8a73c1d685f857ed3240b4aa29a975a55c4238b86ce0460c87f98cc88028c024c4626fb01c507f4440603d2e1b8385ad312c7b8fda3b2977e4d79e60fe8158104853737603f5400b8bb0e64fde59bf9a858a01328203f7971645f40358ddcc0152ee1ccd8fb2a7ddb8be5eb59c143dac089522e2a93974c9f0c69a35a1052b943a93cc0d336c2e2a1e86724f91835039c57696f9b4b58f3c88383cad8e9caf349bcd548a2cc574f3b48c787a0bea22547d9ecf5b8f83ce25ffaca94e57877dad729e01b6ded97d635a421f001c7ca7f0f72eb4bcb2b30f778c2bdd9b13203d4943909b0c18c6f0abcc6a1cd986e766d9ea4c8e57c3c7acdec90494ab79e662fa1ac15a73419ac57b3ae48daf8a04649f315db3b200f535d009ff1ad709e2932bcdf04ab925fbb514917e7d93c4d7fde22c62280ce0f21e10d9136087ea49c31877e169eb43c9eba8ce9a5176d2d528eb726fda602c4c30e07b0bb3e54e00f2f7e00fe7eea43042627b85c5a352d520acf3c320fef29159f7facdca47ea75bc82c1263fcde08553e3aeaa00aeb98fe4e81dedf80600ef0a23ef3eda924828f19c4c0c5877d58b4320b541a0b32c5b7cecc6138160c705b061e8d6af8f481aeac518eafc00091900310405f8b8a18fb46034c784b0ccf71dfe9292153336958556890f287d59cc22cacd71073147776815f8de615ea4b07126a47f94ba0399f7900fbc799ec7e709c5f355034861cb29dd29cfd36a6fa03039acb064e23c8445c64eb8070fcb0c5631658b685ded44605e80fadc594a4eadc15b198479733af5b9ff3b896f7fe4a731d9a090630df8f6940889e29f3534680d0ad9c101b90b2ecb6a7038c84c8ed8e26035f82c61aefa51d6b407229ef3b017dd1a72031cb176554f5100cd89e6cb69dec68fae5d651cea4de44ba2c3df673c22a6a4baa3861cbc9e2acee22c31f789a4a1c2492e5f3af498714016f9e6a946060aa02762619725cffeadd1f84cf0ea52be70c09315782df9d30065744cac6294d4e18c5cc7cdb09cac949d4637dba8f51aa90bba9a8a12c7f64a6b4f44a82d0ed60a2446135ba44030b7397e061d8588b6d45cce1be33730e3aa87918b55171c2609c22372868a2c05e460143bc00e45d58233de5aabd554a300577e7aff90b94b919c07fc91a2d937e7ffc539e168926a2fead1c693e34f6cc18d1d4df693f3e2eb2af7362b5c4f2da61c8a4238cd14e9be09da8b6c9b5a726e687017f3c96584abb79dd97fb1e7d3fcd1c32fe6418e4f211ec432608d2e38b3b8ec3f192ad02ec99995f81afc8c5f818730fb2e4c783b9109649de3e9f79bed41bec50895d4e56e1e2fbe717555b668a827c8637113c353bfe1c62ef791904f78dc710be83fd068774c4d5d5bf617c861d2a8759ca443f09820351eb7304598d1321ab3f18327cba7de5d9519dae4ce814a23d91d5b5a856ae70614ecc8d2fd73de127976be8f92be8fdf45acf1719402f5c4eb7811094ae196a5d786de09f00b23c6a72b5dd6c4027b866b246893bb208f6cc26d7be1928c36a199a4cfd3b157ddef32b4ad5bc2f9e26f44ae43f73edb79f556706e51016645b68eab7c800972e3394ce7377db9633258b82fdf336c8bd3a88d22044d8ad623e2ca6891e1a156fe8dfbaebe7158690f7a046411e8cda03cef95c4fed5e08ab5c2b74d9e4161343a8a2d8ebc26f184b70e5b68d532fbdef8cb83cbfd1f1e5d5cbace98c801323e4cd40e7e63c3de1d600ff02a1bc50cb9560e6d79669f1a8a58f6dd61498681ffed2f9bd9d87573a8d3397dc68df5296973674f5715cf7657e0c9bf5fe9b3e9843406d2d01d5d45afb7a9b2e779c862ae929444b4d35331089b608c17d3acf02b3bcecd81e1a3acc43b3f75b27115bbb2b1f4c6ee84c23e72f05870d7bb74bbfa53cf338c2699292bb33d574e3225489852e235489c52ed1d99ebbf8fb0b59c7645629e74f7a942b19b6ecf40ea20b2bd3303fe48a78ace9683a68d54d4807f6c59a2ae64b11a18ce6d7e9d54b5b01044fd2e32bdfd7e292d75ed8c3e70b97927d03ceb0aafe531f2c2b35655be2508ea60976fe9f137cf4592d3faae62f9a7c94257b7a3e786fb8b5704ca96ea34205f664db4cdab859f14647ce14219422a26ed3a287879234492b275fe629b72c895e38b081cad431a06105226b06e36b17e42d485baed431d2412c3616114c0e7d2a71515f6fb0f49b44ed89358557fd16f974cff249510476744bac49014b579eb57451a8aa181b7c25d597612629be1320879756139ef98ecc17ef896060a46f7ce19d322bcfceb78de3666615ed7c9d123c6ed47f188b4402c256f7c311a40417bf665bfc5fe82df2070678b2ac008c970dd2b112c10413d3a67456c76c24d6e18c5c390a53fea5872f137deb12c2eb303f93f0c3fe3de46c4228aa119ec9b82e498c5b2d6f30c3112dab301e2b8157c4f84712406f5eb5d14624ed006f3a9e940899930b7de24a0e9e419b7dadcd79fa677d3f64a0feb7e058521fe36d86164551307c045162727a5f6923df40246e70437a611aea7db6ad67024e3bea4583febb2dd0aac181ce845169144bbc0a775f72530fe5f34db86908acdd3fbd3b297c2fd79df7694e81164c432e3a8e953a80a423814aaf8925d25b6e106c21762c500afadadcf654d157c9c76c229859b6155e7e5892f16e51ee093b6f447515bc62d7f5bdfeb594113905d2fea6583ac361dd8528141e4d00f6dfa85ca9d35feac4baeabbae6b06a677e83f8f631b7426556f386ebd18328b6c3c14b1f903912cd41c16a966cfb30793ddb509e1c989156247814ed0d30095010e36129be243059cb2a7d82a0d2236f05a7fbd70ce15398e1b06a716cb31f1835480ed463fb1e422ba05329c73d7f01e532438776ee4af2b8396b214735a20bd380ade09c3febb515cfbe9565749e00ab66651edaeaa1ef3439ec7768289d0410c587a482b513fb073c60de1fc4a3716951a3d62f14f7b6506eb82d0d9d4e2ab9abfaa90091b77e03a3183d5cae89062ba57dd2d162bbf67908d267718240b87951d582a269e991b595ede9acd9e58b7bcfd2c5c36fb1b51eb1e5bd4824bac297bd794d23ba81bd9ab070c38554963e4aa185c80c762763d340c674be8999421d731a6eeb69d8b9e64eddd6abc1d2856e5f7f4946f9b70df49c1ec5add59ee0c9f115d9061b83a1117975e071f5f3f1e5a37be34ea6eedc434ee6e4572feb6cb2db4cda0fd45e355c81755383aa0c257403f53c1508c1938949989a6605e6293f840049f5c8f2106c57238801117960cf12af04e4c42ee7093b7a538d3d15705748f03ee7aef82f6165fdf414a2d9885c785e3736898165e150cc1ab60fdcec56a19667be2da60cb86a53b1561a5ef3087e6235524ee3863d0a252cf39c1ab1d1cd7d2a352d1bcd723c7211205dcedf228bd65e4c4bcb4537bc8d43827ba96eefeb0d273bd208f10d7883927c283b554a53770702e776f85ad812aadb0d6d40758e02a456cc4bb7fec9f640a39c8360117d6754a3333e01aea28cb8c135d85848310cb523e0c185354f974cc11cee73e614462267f92a33101cee19f5b558152c0a63d2735a7c024485a7af7ab556a34e3043736b45509a662d5a02e8ff9912b20826d299205e41db0541d3c74d1541f8464093bce9b0e7d44840724d44878b1841795835b6c50a865468d622db3140cd392be96656a887676854e94538f9695db79498fc36f9df4fc15a9333277dfee43e84a7e690b3b90639d6dc282464f9d1896a49819b5d30527d075489674dc7e1f64a7145caa6222a45d37eddaf94a7a4c3cee28d85f674e189468b2ab88a8ce33c96c46c9c7c14a562836260bbb8cb1ce8c8f931eea4c408a4add3a6b244c81be0f920d07edb53fd32feca32efbd55fab0d8e69f41b8204d0d09090746d126ab6e3ccc159ff0ac101d9eec3da912f893a89a71a2cf194da4851466fff016c956a72a9609c4d7bd0eb67078c0910d5913fe27001b315abe160d2942fda4cebbbf94929b8b7b033f71f7abdc9286013ae1b9f66a226d48b35c13b6550af609708285fbb45768b8c4dba2528e0e735133b502f59486980182750887229e935bbb49c58422512cc397efb59a747bc3288fe40d4b9436d8735fb3d72eb19af81b1dd908b132eb2ea0329a97b0294ca4a5e361342d6a45b44d41c7ee4d2e3f08bf477eac87a8173de91a4acc17693cc61b94ac5d5c0c1ce1395e4af8ea4677d4ef8b6228a9712c8e4d241c1cd21cfa3c77ad4b3ff4611b06633897d701c6d4010e7a2a3b7cb2ce45256f23ae21c53916c866aa3ebd49a563e684c65640a5abf3ef2e540c46032e2098cd8050dcaaf08a38846df8404ea617ada62b85f5c3bc46a30cf0f9c4aeb680399a9d71f3d764ede53a4565d4cf2ede1a96e4badc4dc71437a5114b272ac73ee17c90e3b8bf6a6b6d407d05dea355ac6db51483b1b8eaeaa84adf2bc0e77a49e2ef462248a04cd0f72e605ee2b54a21ebd8ca0fc5567f241db30def821fd8831f789fa636685fed87a9fa00833e8e60aa29281473348401edb61e92a11fabb25c7310f94a1f519e73cad636b7911324592db4b2967538595f6468943ae2d941278e8f91f00d705258b7d0ff7ef6fcea3860cd032fc842771d653a6e5f8e8150f8644ab36227fe27c3728868acd5f38f7ae2ed3239143313ad338c623402b5d7a9414a5bc9dc4742b0657af50107aa451b3eae9e194628448ced0a0c8d470950f4e1b4bcf73d3422ef90b313596405efda8bba54e43969877387f74f994345746199e4894594a3161e9095ff192c3769a4176cb880b89b677315691223f369171527e7bab444d39ef5b5d164648ccbaa2007cabdb991d98b7c93b350b0fdda6b31c211dfa0533300b80a32fd43e2d8c9b1af0d73d3fa516ab8bdd32ba4dc1edff8a6fc4bdaa9536302a53c3ffe18cf5a2ed0e029e0ed7e8de59899eb6c9b748e27dbbf3d455f59784d9892493b89b3f0aac5ca75f193eac6c2e2f8b3cfb29324b48abade8b3c8efd255aa344b6d2063c69ca29917829d7182ac061bd888c002ef7fe9e0ba9e99ca29584c1c874eb72480f2e33c8b12a12cd2c2c2dc07cd95e2a1289633a5a5262c87a783c4d984b6d2058e87a8355a9ae8ccfc47675466b41d75d037680413650633a1690a57c54c96169788b19a09b18805b2e1085dd74622ad4f7ea8ce38a50ac554bc89a229c2b23b609a53b9f692c33ed5837b6711deb3e89ba8464e1126d7fc1188b0dc9b197ddaa6e946db9a8fdccf4d9ba0343b93e5bf6f14a31783bc543c0efbe4200f4f50c0ba16542ae51c445222891dfe946a172c451af241829748b0fe3c5f9bd7514c45679188ed51b29564b66a5b1abbd657423e4cac52ed9854b896cbb4cbde1848951599bb1cc353f557c5bf0cf79cf54884c77d32165d4000766f5386891cd35135b6950ff0b9632e91152effed03d89a2750f76f04b750dd914a605a7fbcaf5699c8ee21c2abadbe9512b130857ff1918c0331642979bafc87cb6445c49ce509d9e58867f84466bf7337db673cd270807c916e798ad021d7e95352303b842c62dfdbab6f7177724b9ca3e1caee058457de9f25025bc959f52f2b63d9322467b8b623836c8c73cdf7d8c43d8ee8f371bd5539ea74e950e2c860a9c7e184604a8092c0274de42842d63317039d1db06ce082c216a7e0d0f8010e95e49871d052017568a6873137d127968cb13a640417b88baa0d8396d70f91b1687db88870cb451ec26b0475e7cbb25bf27b7e0a39d85669929c71e7511112beda1836eaccb91206cdc79a3a28d73cd251e593d50a3a8304a4e42805c458034a2a726f582018daa8036ecf0bd9fb8cf980f861287d841c329a31e87ede6dc58969a5aec522fecd75babc72382b3f473c084e7dc53cc67d1302721debdbaf0d4879d158f7202632d6e9c07bc9bcd19803df24d9cdddb69452ee94a40cd806de06e806a220f0b471d10aa60cf42d035d71c20827535822537fd66fdad06f09fcdef216ca5b1890257f41e68166d179a059946ee34a3ad5286f6ddb067a378140206f79ab25f66900ac5e5e774f57bc9aa6793c8c80c57962a28205e4de80d0be883c8bc54e41a04e1c0841910f48192a466e599a4f434cb880dc379c0f6aaaa2c230c438c421c63dc09d83683ca860310c5b46a43426d229b95fa4f40ab5923b040e8a4052a1c2298b4162a7ec379054a7ece0b74418ca4207c33ca5655ef4865a699939ef8d28f0ac3e8661aa7601b3f0caab780e97030788a4b2d62aabb5d5da9f58969abadba7b34e0a16e9b00761d561feb8a7d20b3e2c59da501404a5142103f2470eb2a4e5fe9048cbd09b0fe130771472e060ce3f8dab9eda01d1de3f2f27c9f6945d73af965e0963040aa37ca48314f5df8b51a8dc52b28329c822a590e1ca3a7859a47c1cfcc90cae38a389b5e0e989fffc5e3c2b2ff57fc895e659ab1029331f3598442232611356c39c1346a44a315313e59a76ef06a4a81fa7c815b0286731130e33415c954ef7ecdf7bafbbbbca66a6aa90d2cbfd6200b2fce40fcff421270d02c6b8c110a624fe032d4cdb1b21cb07801c754cf2b7ef008d8003cc600009d32f7a31325c1123628a71bb7b0dc65a50d3fc82d552f99c737e9c7beee722c50ac7c4b9d69982314f4a281527ae64aaa984a0847ab117132768132b4ae96465faaecdedc34e338bd8c206c7745d449fc612acfd8c8f2e12bf77a683919689e1880c545cc9f4736819d17ffa1ceb7bd70fc90b7898998749674e2047ef22fa21103142644a9a271049873bc8a034134987f479bc004f9777a70b2015689cb33d4ea4b30b840516f1b59dee39ebb07bce663d671c07d2b146c5643603a92c11f45da81891b0accd28505a45662c5f6354c9f427cde2a5b403b26db2d49ad601e1ec7334473a7bfe7e21b8df71d01270f8ef11fd3b5adebef3cf8884653104dedfa72fce34e001428c789e761098a0e8816fdfbff3337e65de3e9945fb1dd8437bb8ab03a4ad0e485d39c0218f25b0f637ca90dd0df7e7b78162df2802936d265fff39b73d470ff0acb57e4f5f06418874d17c1d3334909ae0f0ada051772ac4de44e1020172b8a9392b4f87994fc09e6779bea4ad0e29abc3a9b96beeabcc8dd77e0c5b60913bf9531977f29174e74ece9daa286f282b4f169416a7aa4a5c2d1d2de37f63b2bbe7fd48ed5e0d009f8772382174ef58a3ca62d66ab572c256d80a5b3e0ac3960c674b96ba4cff244ba5dc3fa3c8a450c93dbb22f77b46c041e4c3e04dc1a184e999c5d0498793a56292cbc0dedd305f0621b07f367267b944cb0f6c5c2d170e65d901b95db8b6f3db5760abc00cb9a81bc330cc47b325450dbb19c36c15b3d5289fadd992308dade0d86c49172cf7cfd45a25cc6ccd16e8e40131d2b44b29ed6ad03cb9678a866d061e5fb0eed6354d13028ba5d4aea61cd9b760a7c44e39a809eca184699114f51f9167e8542a4bef344a29a5945acd5329cb2ae28b916105d8ffff71f0897d603994d21c3ec0fe1b69cbfd347c4e2a80d2a194daf4af46fefadbfb276a354c506ad9be589034939232246dbcc813cc516550962e22cdafca94615aab3bf5ce27d649d1f7fa800ea7006e5c3412f27e012ce1b363ecd6dab746425903390d4435aa7d4d49312e9a3f83a623cbee65fa0766d9bd68a0900d942ed305df45f3cb14088dd3b29cee3e79b5562a733a94cd49517d8275acc350cecc47f657563aec3e79150a76ac614da2fef569c7195ac883a8a009a88009a14c92a506220172d429587223032aed0229f95464c719580c85344ae9e9d438dc195f60fc7abdbccabfbafbe52f4b5e1836cb5829c82f244ec912037ce4fd8c07f7e2ec22f77d6f09eef1048bf235513efaf0c8920b1ed0013acc1fddf75340da307f74200e119032da4b09c381541043555e21b70c430036d882af571465e4db5a886571be88c0f665693a0e22b0f5ec0064b8bb0a78ffa9c0e7416fce4a6d5e2f8cd379e2f399dd01a9d50b2f264bf226c7d0cd007fe8ebf31802f74b0f855c37a882165266b18e739a442aab63ad691955cbd496e1bebf2a6999cee77d54d61f3b55e9d0d5a1a6695acbc635e555e5a6432674181353064ecec499b2d05c328e38c4c09dc590124c433e12037b16434a70cd6268dc3659dabe1f007234a54c5728bbbc0c42c1e2fceea7f5af93a108fcb2fd0f79eb0105bc81d315c3328fae2a5d7062ca0b26030ad72ec8b805f6e1c97c1f3cdfbd0fde7fbeb3e7bd1fc1211ef8019f80458923b2028b73a4428526e4fe59d332aa2d44a9b1421324a0c8028ea97f7e319fefdb1df1d1079c352deaf798e038c1994d5cc93e6ba60adc1105961d526ef3e05082e7eceefc1c885c67cf9e9d6ddbb86de3b66ddbc61a1593d51ce738713afd49824fc7366e18587cedff031a48b58005c785e3c2c2f572699acbe57269d8f3c4621e4fbbba4fb7fab85c2e57f7c1ae8f0736c1dd58a362b2fa70375d7fa648d9b2524a8b80b5278580d03067484a60926b9a46b234a03854e69ac9b933774e1c64dc7bef0b3cbec00d6899dacdb7a22971a2d11885f90c56b5cf4696dd0d0d44a66fada53846e0edf33a4e55cb3411fb5b05ea872eba3fbdbff7493ef26e4c58c1f7dccb5d29a9d7c4f35ac65ee0397ab85b81fa9def803e74be1ef11135dd9f2bfaf73f2d5992b07c1fc9c5f73efd420973bf7e979a3ca110f83ebdafbdbff8f9fefd23b2c4c9eba2d771c110e014163747863e54e40b7c9fd36e4c8ca7c3b3bbf95df7f27c2f43bcf7bc07a4f1bc07ce1f4c9f1b4c33048e421651cce6d8322f38b8833b60d80c28a440993c9f8683274c3baec0abd56a357d7832df034e5407d2fc60f2803e5880e98b7305e47e36b7e6bddce0d9dfb36ba02be01f4c3f98c4f9ca343b4ded62375aaef77ba9200f1198ae0f8203f7179c29294129b95aebf50ec8f77203fdfb97fe0fa094220a709859eb6ad06ef03ce3fe6daf7d9d8d4e5687bdc99247c23c91a34e8afa63c8e2bde2ed4025ec3802737f3a9deea975d000cf1b1e42c0a2ccd2a9d745f46e9bc7ba66402a98a36d74b7fbf75e3074918e7fe17be50a5e3547e92edda711b2c8f35e207246b2a096042bb0e80843310011e279817570517f9652ce48a232b0180ac5d03a423f23f71f4096e6bda110d590688f84ce9270c5142492a6a938276013f613e6a37fd8c3fe4619f86a9e1b6560cfe2df7b9b4987edb9461f5d537f33e925a4cc344286fd7253d548984ea76e76d292c5bf510606c00e26abe72bcf2a138a16258b9e39573e9ae0c4b105fe1f9ce409bed0cf482ca8811e302681cf77ff525ff07b58254ba5dc2407812ff54f8dbadd4792c105b847132c4e18ecf630028b24188f2a5824b906abb109eb904404467292add5d65a6bed6030ae3f4ea47c79796a7ed3630aa63fc117a97d569f958fee67353fab7b35ed5a6b6f624e40a1503299cc7dce59a9e802f7fc285876f8dbb5f65a6bc79a7f89040c2e185adc9883471f61c741067e01071998722ae74659e2723f570380982cc92aeee8cfb9a8cc4ad83575efd59c5bc28ddc78069ee08d27e01baefacf77f0e57a5efefe36db5edbcb47dc78b9717b71636552532eeafba5723f0c0e6eaffb22633b62db8ed8562d236edbb6a936269b6a6be5de8e90252042b88d0913785b6d2a287853e57eaf6054594a96e8ac44c8d1765fac4b8cb82fd623726f2f26553aec6fd2f9fb6df751d7d4e19c6c2f6ebcdcb871ab7b735fdca88154d621c5a1f4bbd6da57ff0883ebf3046b3535adeff672db48a6ad73b4ca45fd2d4b4ad02c5f49e0204bd9fd61c5a0e5049a7999eba654025ac4de47099012be7c4c905473c8b0278ba4069d64090bfc72c3045fecff0fae96d17e8a9d20988fba413010ac41b0ee6edd74ab5bad9b966d9b3703b7057b1c028281602de3a0906eb55a2da70d085cb4600aa624750c25a4c09179e75ace08d814489892482b987004234c1e0d3f6416732c00754d9d0250a1a90369e810373025816109260f3c4023a05fbc91e57394d24ea7e322196017c9970daf9617dc719136a48cc501c8fd55d620fecddc714d993e6c9038b70a372f774dab8f830afc4deedbbf2ec39ee0dcdc37d056173181fb78e8e1e6e91f0f5eeee1d65aad6d071bd0e10cc8e30330803740d634eddf1ee1c60dcff372a687f25128e4853cbb43901ff2f63892c0a190a704357fa862f0523ec2dfa8989cdcef0143fe9853a60f2c1e1c8f6c8a270ccd5e214795e5a2c6f111b6b2dc968bdc568bdcf6656f8890fd9d2c6967b8665172571c91ac37166591f8a417d8a22c4a96e8f75b21e4c8e5454b44b64bde43428e5cc0daf279a0288b1e0a04d6295af75eef24304ddd73d58323894abdfa7392f32ba5945ebdcecff4106a02bdcc4d403fd3fe71b9882cbae47c2e382e585c6453e60f17305cc2904293bdbccf37f36ebc97979230fd95e523ef0a8f0829ead782c5054b3685749d1165c604ce1248e4f696dc74a06795d894457916b5052c7a1e2ab787f25037585c7b70a8d0126b81b5bce52d6f79cbefc5f87fc65b3e6a534c4c1886422ebdd3e974b3721d4f27cb1f25f806f408f451e4fe2a2a17853478d98ca624320b12ae1003534b37c19464da985a5e2479cb6d5aa26051c2544c8a68f968a6a9c5b1749802491a2097afe102fae0f2344059b71a2098b8cac70e3dcfcdd92d1779be69e3a38f5ee6db70958f5ee60b2fd8007d007d8d7f01e4f2794f7f8d8fc6f75598f5cc473e4a517ba08873c83373afd10196d9e541efdd9ae96ef9c85b2eeabf2d6fb9cb37e32de21c458f5959f66f7c924791a27e97d2f249d3ec2ce8b22cb49396d1ccc8fd5d44cbd0f9a34f63d7e4f9de01a1739b74823e4d2df30c61ad57244c955dc127db6a1928f6d532623d4d81d2320358417fbd224bf3bd903fec16d287cc4717b4add000b2585d9d5b65ad095a2b12a61fa404d32c12a6255558e8208b249a5441a6aa4c98f505d2e64499484110b20a646d819499a716892e59ac279f9425611a4a4b96e796f25c36523650322bb332992c870f30e83f39b260d897e5f001dee4277f94e0662f95a0f376d6f99395c912abf3b21e517065c9caf2817b0f585bb95db3582c0e68651dcaec8bffe7713c1fd087ce77ef75beebde078e6a9d07b4b2e9a0c5d261cb8404c17dc7ce6c96ce67652eea57872d05feecf7de64d7ba209e680558a4b38e45595467d2af5ad1eccbcaacccbeeccbcaeccbcab258199d592c6d65b68abdb12f2ba3381d6e93d2d9e974acccca6ca4ea0fb75b72a660066b752fc6a150ff3b1192bbb59f49422c2047930b12c957b955f89226eadacf44715246c1f3a3609f9a67e33c05042125777ed2b004d32ca5741185fca2bd1784e66e2ae9b0bb59c4ec342b4f28a801284121f1af07f048cd7d51e27c3e9f77d367ac51a15098d5b5c708572be7fa8b975201d8cc0e88a6edc8e2da132a4db3d5d62cb048dbc4a4439f242a450a3573a494dcfc9a78feb68c19da735f398e93538e40b0611e3adf03279b40bcd705962599a71cf154cd9eeffe83f0842a6c9044155490610ac2f35d8d1846e2a2938b46465ad40fd68802ee96b13f67e5a107cc699ac6cd776dbecf9b65870109d3bf7d19903efaefa70109d346be23e0233a74b8a306580c591094a1d066adf58c35321d521ed8fcc2c0e2cf39a7bbc7a8c86b6f9e37d74e0f06efdfe7310416b58e36a7a6cda975c02a48b218c129726508cc860e3b943107d0118662f060efc206274b2a3631141528c6dc03ac652415284e262a4fbc322747802515285659527101962c4e30b2a412e5ca111cfc39039f21ab9455fe4cd7d0e1045992f38776c22a94923ca76b73ce39a97dca1db1385a0c2c061613d3b90eda176bc7704d2c2d330b62b65a0975d900210fa10a9b31cbc090c5308b130623e5092577dbd0538331a1ff308c8989994e260c6706935d106965c254f8336cc2260c0786f3fa224f50c447244cff0c2a4c25ca153072ff9c7eafdfeb5d8d0a06a39102f7649a69334506285387c70becb5d7e6a0f3d1cc2b3cf84265eaf0d80119d726041f0b1663c8fd349de76cbeb25a2b37623941d9a17f87ce7fea82db43ee7ccb47e3f22def9fcbd734c8b9c131c9a004163fadfb1f1b599a21df2f4015fc345ae6c3caf7432f869c40c9f763f3b132ff63e5d3fab83abcbfe30b2c7e58f9fe074acb58f00587f9f73fac96b17395841731538f2958fc58c9f7c5edeffdb47c843b11873c1f2b2d6325ce37dfa7e1c1eefd78cbedbe56beeff9c4f9f63b9f11cf0b0eb97367993fb14ed322b8a752a9d44ce5d8215b5fb7358bef21ddd40d854231969b2db0020a382611e7309e6012433348c5621c77e7dc5e24e54ee6348fcc72c4880eb34dd204ea0245e2a7090365c1dd4120910106b85f861496e1094cbf471898bec300cfbfa04802cf1a28dedfc1e6acfdfb0097c0f3066e2fdb77401eb4970d34d2617b423132cc794ff7769867e4500cf0fd9b8bb4cc2cc2037234692045fd3a74dcb851a34637db4f1df2080226222475475df7c916d19013cca426943014d4d121b5af75375cf005d3f86f09ec9ed4378be8027f4ea5b69bf28e5a4badedc09a54ca6b249142c95ad6b29c7bc3f086375658d3646128c7e82c4d54b2ce3a7dce39a7bb7ba2d80002961dbadf98f252985f44a39ca669367860a0c8f6b0ab69b7d3d93e6ae3d889ab358e231ef188471f613ce2711c65a9ab51f9688b89aaa624359b896635cb5aab75357819636f168e2c362b8f2df3d24629ead6c67e5950c4230efe33d5e1fca904f56921122a1b64c9fe0d576091c5cb8a3714ebe4358eab6eb1c6daac19d63a8e2eee0aef3e464c29b5d62bb5efee374a4ecc4cdb74a8697d330ebd2706045e0c4abfb296853126596a59ea2ac8d11cbb26b95b368198a9266311173519b10ee4d032f55229c2026a026bae06030bb97fdb42ee770722f75f998469d9189ba377f7d61e1664afd7ebbeeeebbe7c74efebbe64a9e6d27ded7616ef84210622cc579e04b8027b40c0409a6c7776f3abf88e2c60f1abdcbcbed93d37d3dc378df71214e7d80169ee7b689e0cb9cf8134dcdfcebfd4f7fcfd97219ebfef012fcd7d0f7ca9e090ee3b3e3ca9efc3fdcefbd3ee4502f73b3fe4821355c1211c384f2f0e0a31f96bc28c8037b0c7d74bc21461335db3f5a222617a52c1056c3a41092f09d39fc3ffffbdaf576d0f0b37afb03ff47062be4714b8badcc949192973ffbe74773a9d9fdbedbc87d334ae394de33ca04dfdd42bdcbc3c9f4ed33a4dcbf9d4936786650c2d60f9784020b0584791c65c55555746c87a842c8d158565fee8403a465d2265281670ea1850dc64b7764a957b6f28bfe7b340ba2edadef36d1c27615cb898b3a5bb5b1baac105ee1c2e60018981224464c9e6cc201320a51419ea9e73d6a826eb8acfa74a8e9c9a26352d14037d4d8b6aadfbed30141243e67581adf5a0c02fa1cc71628b2aa6c005186401c7d41eb00711b0286faa844288ecc8026f2f860fd86180d08794a1aea9695a8873031aa3301e60e0f9378874cdd4d4dc3629dbc10416a51644d21113d0b0c4565befb66d5bbbbb6bfab052985978282fa7bbd33e9e4eb5540abb448eaa8cfb1e65a98544c7f31f0dbf25c22eb12a0c56d965a23b83525a2dbd9d2773dd93f6c7650a06819f05dd0e08c83dbc0ca1a6ee656ec2fdccde1744102c7893f72c8831750f7a5ba96abe3c2224025272867eedf346afe5226900d1a3419633889e0d72bfc7e52d619d31e3400fe59d2e66b4d24a2466c3c6bd37e7ded147f7de7be7cf3bde71ac94def185982c5d23a4bc4ae43b84139984b1600c912d16eccb451d6b96f6059ef78eb234f312399a41e2e62ec144ebda68ef1aa5f48ea30d1767869f5e965c4a5196b2bbc3755c4a29a594528274a454b31d6a9f7e3b24d961e6ed1e91b37b7fa6ddddb99f718d036fe815d3df5872d7e93059c188f8e90303d578efd5e1c610300f2ab028655794578cc8d22b071a44ca54d7126cbdeffefe3ebbb76ddb6c362bb5ce395bd3c21b29ea2863fc5e8c43a1ff30f45cd7755d9717c56c16bb321cde9ff373cd54d58bb3ad5057a194d629f5d5eab0ab4d6eafded016cc959bdebc7c64552eea3aa5ded059bdb135d689b5ab0e9bc25630180ce6b2570957cca462c8b0a91825098825092bdd1e5960fa443050ebdf3a89146182e98b1256ab65825d479e79d674785975d5e1dbafce808495931ee930d93a565587b49f888fe8bd188742d5094e689ebeaba010222e3a610b56565d3dc1fe625d7d41448afac590a13852d29c0ebb7abe713a9c75485fa43f4d1d50ba88aba00a3ba775b7d65b6bad9d2a2b22619a888f3ab665ee7f9145519e12468b20e2a2a6589014a7e5a55bc8fdd424bb5a6b056b544848d1fc284c2c916775816490e326c70b3b815978b59233dda3068bdbb8a9b6d147d5d4ff2dd1a7d5c94f787572fcd19e85c2a12d88938ff01252d4cf042a8a94950537d476d2401a2f7c93471d66604c0377032147b36bb490fbbde567dab3cb47fdc27bafc30c1c53e35ff809a5452dce295556f38727f7632738706409b37ca48307863a507c0b8a2198024c9fc3c1046f7d3aadfa94056f2bbcf21135f56cfae89fb2dbfa4c57ee17fe806208f6b1dc2f7cb7c667b1b4a83fe7da2c388890922f22f7d730b9c9b22b9f8d49182b16666f687cbd3a754d8b4e3e6a21a4d827500c654a9f7e4dfff3325ef948487f8408916f9a881eb793d602f60937aaa505a449626a6901f10ad760151ef10a8f37a8c0225ee155eed52ac70d6e17273829659d970fe8b0a5f63620f1d66a60e7f3728f2598fbcda7160a99e91e3bc0d2451774197640117f9e06bff71f90469a40ff79ae83bf970dfdafedf5554cd1224f500baa2cfedd3a1cd7e974544cfea5a7b72f306cce29a66bb6723ead8fa6693978c0a7108e9ae3744945ab63681d13b5c385c5d9d2642c8b21eeb51e7a44da801c695f8414f39107a4a847a0ac426e0d74504716650c0b0d1bcdf5a8c99aab160ca1a9e59032348607c7d9b86a5438d65121679248a49983079872d2b525cccfc7118e50b56ddb444fe882b497b9fbb2ab61e6fb127ca9f7e9cfccd91aeca5b756ed45d24c87f44592f350824552056bb059e3b419d2e7961af8354cdc54a1e1d202c21f0f898f68802ef7b660dc3351ce6084c0af43bd9d2791484d38a114d404a6ede93a0fc7719c13d60c49df78bae3440af7de23482477f72a046725066bd9409163cac88d0d3d7448ae4f5cd8c33f8b4fcfa2468d7b319628890a2b6ace9c7b31fea73315070cb06751bab48a8a8909c3af2d436025d9082e10c10c134d12508c1d986423802689dc626585e949e793844e98b9c0f4e4fe4b2cb8f05f51346e64494a41c445dd8282b97c4b915c95d454457538eb5f9a27433cef695c9ee6c910d07b208df7a0a7f19726bfdbcb0e0828ba7c342d204dcbbbd0b8fc4b4704148b48609aa48b4cd245be4392dcd95a66ee74c00fc944790d125932428ebce54af8eb895b0145742c664eb374d8f78914f537e1ca50e42956e44ea2a2b0404998eb44c260c11a584f331e34b5e6abaa8a9af933bd0ad6110ad8c1ded18519d570669e74430a166b45d5a82aaaa26ab03c0d72b1582c96dbc962dd1d536071b2b656e7bb3e127247d19943984fcc22e4fe6ddb1e7f7e83d2a18fb268d9678be5e06459111b66dddd59ace6dae3c4ebdedb3dbb59c51461cc50590c6b77ad6d9ab6f5bd634d1886d11b2a140a5509c95987302b4c68491fd956cbc63ad4b421600b8a01166d8bce3a9f82a894eeb50545c968060000800083140000200c0a8683e1906048301e47f7061480096a7e46785a389707644194e5380a628c31461a020800801802a6466c8840001ad35242247515dd25aea9bd1a815eb13b684f591a12e5e2936f07005b91e1280395374a407da2a5fa2210d60d5434e3000446e8254883c0e8082f937664ab41307f8e43c53b3df9214aed61572b1ce2ad97a1cc323d1aa8c59eeff5747a3451153be82b1c293b3ebd73aa827cc48be50b89aabc9622163eee20ef807562c16c2a6b314a8d6a60791b1cb3d50c5595fd6248ee8f2f4c5e7c4b6228d43f319abeed966c94ddf12a233bcfa2a6700f5a1246bce30668549ba375d34189d49b3f5623f8448a707c222d683e61e4096b3b9a3e81cdfecfec11b16b0a315b34081a101288b026c199e6756e1658c5c6585db0aa20ca9d206e649b236e3867254e42966fb596c4572163a29603a08a05622c1a8164bf70c57e235f4988c2c5ef111a1ba5ca98f2fb8dae5c2e2c21a904cd86b58d80d468474dd21d0a97dc76e5ed7ab4f29c8a51e17124bc73ed4189df74bc81424c1321c1f65c2e7dc5dd8610ffab3780f4c95e8602c2f9b550b0cea4380b464ce46cea4746dbab8c8a32c7121946c0512c6f945668868d821e52c31efd58e2b80e46eea42ead5a2a6fd3b02f505bc2e9c793b166242b2c2c2e5f3e8c46b642e630e67b7116ec0953b2577cf6080e775ebedb294a2e77a36220fb4c5af98c39c9b80435034a053300aa68666986d2f655117f68e687e033db859379ca671893624670f2d762e9ae0fd4c2f1dfd186fe3d35519fff39fe9bb4563e1cb4fad2d400d550c487eb1cd85a1f2d9d10f503a1a82bf522d75aceb7d711fd2cf3cca0527dee80786ca9ed53d1a0cef6faa349616d70a28525f2b8ec8bd0626316e61f358935b0e7ba97be1833d150a38d050f13fc02b189a98d7d995942aa17eb56b7ef4ce2f80b3c45455998a70b38a1d5ddc1186a73104db8f226875f21b415e98ee9097225b982cdd68e3586e00fee1b0ad841c54f92c9ee9ce8ace47de7d72c2784dceaf1c4d7c58d114319c7e6ceef8342546d0b4a291368f8c9a23258079f081bbc9b023e2891deab175090f42be2f395a13c7523581df68b39ed85855944c6f99c3602e0a83a59e9737b5455154280c1d7c9bbeb0eb9af43da1dee264bfff8e5749c6ae7d60e9fc6921a8dac6d892e3eb026998dab0511ac24bb1dfe4aebec3f1c68867366fe6cf3077758b7b933f57318f22a1a06d621eebcb29bf1a5b44d04f6a629177780b0b54dd21d95fe77dc91dbf37c8d7bed54d0a9ae744d930fd4a1acd2f370026b2bfbd28596dae134a79d8913896baa4bedb089ce1bae748c638aeeb49322bd1bf1b273adf9110235da41b4a47808cc2608dc583528901d7065d4eaca3d90cceb38d21d93ba6f486a6d020db715c1dd91abb4aad177271d976a75d24b2f0892bc943b46285f893fe5f07e6e41a017ef0b39b7543f17babb1f6567d95a93a5b4905b3c5f667376dc5880e2f2b34ea7a59f683f6021d88fe8ebe319828f28b89d74e3623d51e3d702636ef4df3e75eac947a6f796fcb29c16a111c9404a7f2954b9ba689c2247bd99208978cdbe6a7badbdcdf8d31912522e3dccf570ebcbb51ba0c2dd951a71a9d3cef7a34a664be2252f2e12f1f931798f96bbb90f4c6eb4e4c779e88f9c914a19a9e00d5da8aadf2ca002b29f80e4508163a704b12042f4149f0a34cc85691cf5b9fb16cd377472118fed2c882b486a29309d3bd6d51d468d8f5247624536875856f0f09aef960224e1e8ed563fad2a8b925f6e81a77767016f8a8e626fc30ad4de082f33b7e30d041bf9d83c0eec99436f1cefbc4b2a75f222172853d70de7611aa236e2af1d9c43dce85e7ab6481b7ac00a1cc1ce2522143bbe8db98909817722b5e381a4765353a229156077f6a738f398be0095b551b1fba45e3e80d4814f34e13fee56435bce74a1ab63e7d7f1d00621708d81b94890d20ef8ed27c1f899e31a0404828ef6887d8e5b605d8db427d65ade2f9ae584151ef682c401e708816962161a8470f1dbadc2085e92b591fcca6c66e4fb5cb4db43aaec92e9a3196d464d5e93c81834447948a26534fd87cfcef9d527cfa0c22f3f2ae7d1f4ef22e028ab4c4e7f7dc11bd83f50413b39b344e2f945b6f61c819bc5a983ba97b9e8c678d22ffadaad715ee6a160a9b3f8cee850103694aff8eda216e8ed416ca4b602589029255f97d7214d323a943681463e563d075fb0ea4816b696f10c66753c2abbe1266646e74943699faddcfe58501e7cae44cbeaae05853b2bc484ad84e28b471f261d6ca41a090c415fad0920b123ca408b6b0befb34f64d0fb121b77b25ee94f1f61282b2d2dc7ab4e73fac76a0291bcbf1bb212004d431014b13f26c6cdbbf91ab8528838dad23e9235dcdd369ab5c3bfd9c493747dd7eafe0a2e8ea05bee2679a502f96feee3b2930d56690b77f4ad965913ec1fc193163cc1ce896ba0c792ef35dc4307c4227d0a681bd7d8c03fb1317e128c645720b720187401873c6ca93782c65691b5143d90b0c0a22e788cd2a890026e9567ba97ee10a58e8f4be51f3f9f2f82383d2e87c7c331e719bb2d4cd201adb4538ff2719d0ebe9215e01a232c2108044fe00681f0289a15365b39cac829cb297e0037cc15406ab2863c7371e73fd7d20459379fe60d64bd92f3f5260cc6c0b690aa08f46ba1885084a0688832b09265489ccd9d457f98dea5931e462ea40698808c432a3c9d2863f0a09bbda496da4403326e91e5725ca2eb66d1b4e9b8a2cc250ef85c397335d127a85ac5da441cff651fa4ad5981b833c242c783a180512b063cdccf8d2314431606b7144e21f8e4730ed8ed1bb883b6382df6ef74dc7f06f27f08bcb1db10b369561bc884ea1894d4469054720f6c4a2a185444820873cf73a11bde7a776e6d0217920c057ee2bd4b3958991fcb2f50f400b3387e1f84c55198a8e87a4f460d539f28d260d943ddd5ae07a9eca4bf8eefa5145a8c0e3a78336a688f492e996ab8a56283122b68c858cbc5400f7301f785bee22d0dc53fb134ec25cba8187c5730da9a378549c328d5774995bcc165f9c04304afa308ed2e8901740314631ac3b13cac3f85ec79d267cc9442d775cc0d52bb97199192d4497b4b3cdebb927db7bd410d1cee745d3a7cdbd022b887d12b4faaf0690b9cad772a1871d83f2d0396564a5b380f86919887dbe5190baebdc0333f355bf7f494aa9fa10e4cdcd4cfbd2f6c973d61b5b854c0e700fa147846c517c56a37bbc6e4eda39b526d14fe64494ad792e95b6875718ee0d92cc816a5094d8434a58397ed4cbb5862a1574e06ad975f12db225beb7b58fa7d2f4bbbec8207996d74fb13fb2fa291cde27d131af34ad5506dc2ed56d9edca3514da72170971b34f7fae2fc02493e25672539c3e4d25208a7a57a0afa5e299c440ddd3898a787c922ab0fe5ec5ead20e97d02da5aea9c348148e98ab9ea6fc1e318051ec5818857129e3fe52b346fa3ee6346b45775082b7352135fb2892c7cb1731089d0387b19dd4691331333f2dbbe935642d9b53db333d8c5f8640c04d1ddadc5ad4b92b568ce5db9633a3387bfe14b3181576c57c98c0d68f2b45261b7b614748d092430890e1a509dc61f40686b5689eea15fd9e5d704d0607781105a440aa4561986745d9f8d392e6a4ef31e44ffd2ffe6c907e4d3774079029d31eadc2fcf4a64d65a917945e792d5640b4fbbb97bea9db8786ab457e5adb3a1723767df504cc413641f444001f718f6fff11e9f0ad28b1e8fc2db0dc53b6f9c7646ff3e24cf51ea2ec7896ea8fd8b633062068b8e72950eff65fa1a3518b43dba683174ee80ee8869195af357003ec3a23dda5407b5321814c049f600b73eed059fa8ab028b95f03e71581974b8f1f0e8f0ef83bb60cf33a695036740901601792ee57190abd932d05d7243250cac7fe450d03a1739a8c21689851202f1994b8bdf73e2e76cb09106c431f3aa0afafe1fa83691190dd18a7cc9d7cc3822f9cb434c7699c6aad130f78e5ad6c76e657396794a2da5151d74e12e1ee8f1a74f25e60298a9126456ac2e553db5fba0aef2755814cfa94e1f6c0ba8c3c77f4a3a95509e6e794dc8f7ee6fd78abdd2b045bc0a26ef6560410c63bed05a43d9858d79dedb47f9288cdc04843476102c82c6604147dde05de7c8b8c9f45731112eed495ccdb31db83bbb968ac61900946c6f154ae3163575a29f82e8b94566656ea014d72876c34c5da7a23015a85df05178a947b448ea59edae8c111922d1a220e9878b086de5419810cc52ad341d8e781f9bf849f72b1ca734177852e232e35e6f2c5881f2d84954676b4682445a15395a3d0f915d29803fde0c1d7955add5333aa09d3cccbbaf9f21c32135389ea4acd483bc7e7d5bb61e3d9b7ba8308615fcb5fefbab56cde38a817b9d9329b3aade619998470a15bbc4a88b71b2e1613a1df3c5ee0be45428a5034673a2cc740c237a1dcfdd07b56e03e6ff3aca19a4c665afbbc644185201f77e61226d193e394429897df1c1ce11932aa23cbd6a8c4d6200479465c5183d84f412db145aacc1996e3e8555ee3a302d26cbd2947807b14051e8925393c4a1d29a30c89f246cff02da9493f7a06fd998dd5c34e543a7d804eaa99f7bf3a25c664ec01615463d18705aaffd203035520caca3049c05fd2eb7aa33b488c94651523f1046324a8616124a14f1ff259ea200e42b422c5871a8d0e01eb8316c2671f9244285b30d02f3c242fc0188de2470a76eea3414303093f3ff1d1309a7ef508fc32207c17eb5654658fcb667e6aeb34b52b1a696ae500dd6e1b19d50229555f1546dc4ebda087dda36b0e53ab2ac61ef38ffa244f39a78ff6f933f7783184b1ce1269309531b4546f69b514a026377b1ff3c0d4c50b0d53c672045dc67900ad99322939796e6e226182663889720d49553ba44fc1665596e006d8348adc96371c2ec5d60a1ede52d6a8b3b3146e72d06af5ed31ee591e071b3fcd1be3f990c012ace2b3ef3cc694c19e25f7886311999bee4712a57d042d8f5c410bfa2767c5cee7058c5d742349a03ccdc4550f87b33007fbee823637b1c6cc47ce13e62da9ae463388ee6e62e4209f5a9f07de7af81c2a48f72cf418f397c14f0467bf0e47d8d54f364e47450827a8d83ec05e5c80df651c44a8800dd4a66bf0820753eaad2ef8b5d5667dac02a4a9101503541db6e89afd8c4a53626c39cbef710ff57df37040e18008bbd2d8163eb2bc2096308f0ebd3d2b8c59e7473ded2159e1ff7946211001b236dfb3330db0ab56e8ae5a20d9c2fe69f97fc8b6f3a7eeb19d74f987f86ce6beb81a7e8f78beba3028ee1b9784d949544c64ad4c88c687edeb4118a37c277084986ecd1f7006d2544eca2e301a11121208481165b039077c1a2115249bef9c99a790a42bbfde4d649b5d4ec77a690b00cd0737c26436a3d40e93361d7b34683833424c2b386ec486adb99c30c76a5fde823791a3832cce0bb883373343730694f11f98068dd35ec68afc1f8041637ca965ba98512402bee0f049689063c12110632a47ec1ae294430fd497f31017c15df28fc0cde13f192708d57aa2944786ee7b2d30ef3c3a06615903de899e8b9b6de8ea9cc6392f078eb071c02faba22b04b97df8f40216f808d9d6d3a0c90e9a793545df12e77493ac2fda696f315c5fa26d723a4a8bdac2718ce973647e19127642f2dea87b84642ce065c4bfaecf886c29cedbdf2974f7a4f2ac33a407ca21160af3f111c0d1b7e23d9cd2ab5ed8b288663b84de659137e4e6f3c74ab2af4320d25fd3de3a8c6777bdcb29dc4761dd6f7d8b54c83023111cc0e143b68c01abb4fd221d1c0ec2187a29593ccbc99dea46c7b3c84baa814e49e7a2e6a1214ee5624b52143cc0eecb2d676385fceab7946a52a91701afce00ddca67e2a651c26ef9b222c0dbd7a959b97a0da44765c68b2c32a91825c4ac130ae684167e418f6558556140f50a3e7f876b99e4928981b297fa7b140d9355c4cbe4078884e16df95c9cceedc1d67669da8d873cfed61fba9194e4e59e0d0f2ac17f117f70b16be7d294b743f17301230545af7f886f700fc58fefba5e769897897bf141e2266a418ae5fcafef04b5cbe128c563848113a67ae190e094ff2d7bf4adf58bd83bc0315af29bc4e42b6789e9f447e3b090c3b617191410feeac5258fe55e4cfba3db1f027527f5b0a0f545a238578df60b7d7160c7719415d53502822917951c3bc6e309c69be1a067b5b87e200fdfb161193f736826957c480b14205bb019e304d1c08e621a20d77a0133e010e5c1280d5f178217e4a0c4ba11120a80dd081f53099b32d8f8d186d7d20383aaf732bdb8e245012357c07efbba849ad02210debee21bd2995a90b87e120abede046b0f16dfcf5eee4cb9422c64551558089c34c6455fd927435e3b7046a1ec2fe75d161cbc9bd683f49d5a40bacb94c2f40e02c559930a66f84593184ede64c997d63f45c3aa7c917b8d30c76d02a03d27fc67e7891c593b018f54f68a51b1df174d5a966acb929b35a7d4770f1effd3fc36ff55fa2dde207600a7eca42c08c6d78decbf02e713c79df46baba7dcb673136dba46f2871d3f1bc76fff4faab721a390a93dee33583eceae2809b71c97b1f7b417a97b34e0cc89e53f77df8a8d355d63712d3ddbc2b5a48afee9b5a399a1b1a42f7f54042726d9b4c4389e101396c96267fcb253829c42b49a0f0e29df189ec643912a9edf47999177c71547c199a3a063ade3de8264e07b40beee1eacc23187588c4181112c176693e6a5dba1baafd1ece46af8a055cc4d315de8c64262ca93f8ea0bf2e3cfeace9545810328f729de075297880ba8426ffc2f62c3aaa59362fd1aa8c1b75e52a7232ac2c8736a8f301dcb5b9297ad4e62f96ff97a93e419fc0039a4b0e50407bc022a5e076ae8f56c7249b6aaa017ea2e883218faa9720f46b559c29b4566a570bc6d96ebd9d858b7b297a623f331dadaf75e2246d4955d3483105f7f569f2a3fcac29b149994d12df555b986051ea205dfc3b3df8a34f874f0b54b3b7a7304a39d479441705146215fec87802da013d594c1ad9d87ec7fa2326154261f62ba632ad0c84804a0f6dfcdae9a153e155f15933ae606a171b85c4aec5b4abdb19ccbdfc54cb14943be06c5dcde8542266b71b3c2f0d889671dc32a4c3bd9046eb370fb0eae014e9e227fba17c1fb8ec0ba0b0f114cb43c67751efce48d11e73fd1d202089de111638ceb719a48a78105cdd70d7f17a17b76eab72e1a1adcd71458dde8a3df1b0dfc96649647feb8e63f48a2839a51bed4547e4a9f95a826664e522b2018c59f07c4d45a2a8321fbba03b7fb514f4ea4c6c93bb21df88b60ebd75258b94c93b01749e9afd4340482fe2e1a6f04c817feb935aa96911225799e903f768884baf8b9fc1ef96015be73f9a8df535d5774eeb438301abd695b6f048a1b5ca2023886de887e4c97480e272859f0b9b38f0c8a7a0e3495aeb31b1d44e1e099b2532c3ceba74984e18b6e92bcf8d5159eb16ea7d85cea366a522818a077cb9f718228e5b7307069c85554b545ec4d59aeb587390ab86d8e1488532806b07f7cdef024f1e5fd28eac181cfb8a2dd250eb67127a762e112d7ff9cf3c769bcedfb5221d1cd63403b39568cefee9180a9021f0f8bf8606e8a1604e13a49608d635463ea0bcc3ba3fdfe880a5c7defcea98d852176cc3b3373e715ce30aa0ce0a0987df9dbddf022381bf9e7cfbaa159aaba58b07c7a34752eafe5e549a351850b0664801a0fc32d6647b38a0b49f88f80a402f2910baf0df0ccdfd8876b697ec5e9d54630bf04b8638c95339590eeeb01fd4d7de6c13a3fcb0aa2d5f81bba4a561cf997f144a1213870798cce37cca85a6721d84190d9f2610801536b2ed213f7b72c23cc05c62f3ced50149aceeb5a21b5b36703354a42ff4a157ce2006e7bfb9e50e40658c97ab0adbc4304e444117bf15fe3a2ca2a78de18d915dc87cdc3f474f07dc2dfdbdb7da584c32ce01460a1773e3744918e2308b8753b31e4edb1b136a4fd0966b7c842e9641d6b3afef2c182061be14279e196845c715029dc21252a181a5c1883252023e447c88fe1ad94b18b31ef2ccb07010178b61b7611e69250d0614880cff227710d150757c4837ee649e18dbd3843a923a2df34b0dbf82559acabf4590a04bf6812af248e5689e612e11a88fe5c24d3ce4a1754ec1f61674ef6a98468694347c9df6069fd2ee2eddeb2913980c4c62c2f1b97342603c3183b1364cb7dd756eb2ef8a464481a9da05d2b206c9eed196036fc478b58fc035999259c92965ccc26ca694d194661cd0234a2c4db85da661751618a7415c0fe64f14559713cb84853de1db24398ba8caeab81958c2658d1ba78ac23cfcbec96b2c0a24230236760d3da3926a900461a8a1a62d5b1341b08eacf71ab1d08dbfe50143bcfdb069d5c75bf495ff6f98f63c4a84844d7a65409efe07cc9c3f2c67c232556e7005143e5353b53d7a26abdefb0d325621a1dd0c587323349bd57fb1e082340a788073a3bb67c2d0763b50080887e786624022eb8b3c8be4495d20595378c971c079d704b28121332784f6766ea7bcd3f23f3e5286aab3ee94174131287962195cf5bd2138a567d9d47ce4c95168488ac9382cad4a25d1716a0056d43acc83d7b7dba4c5d42487f168a9c34d866209871cbfc3f5af3df77ba506e6dd582e21e867f74a26a31a263a1a126bd161d81570895ae3e48e7a6b210811331aca6b3b1f675681305f656aca37bd6af4dc32d51c2a158cd595d1e0a9dc771a50cc39db78c836ab5e6841ff4200bf5b061219ef4ffdf6d31f9a5bc1159d4407a9f607b31cb1f06f1cac9f9c5056b5055add2fd5999820819365b0b6481c2d944ba9bdc2eb1ddb6fcb2902e87fb5b2c848c3ae2714f1d77348001f5e6e0ebfc18dfc0413e68103275b2b1dd301f900788534b00f5b301906eb38981b338fcb368f1d04b7ba73f56a1c006591080ed1f87b7c0317c1cc6132452ffb1a933c740b0544df8bf45a0deda8b1656f8493970c416c2e50fb7130591168c2fe9ee176df6490555421497d7d1c944bf5e079fe890a89615f2b574b9263d2b8a59974612c5076bb9ae5fa953ad5909c0a73f708332671d94906c5181f04921dff2452f47a12602d5d3a25018771f4621b37ba35bc9e6aa93561f53ea001d670863b4a7556f6fce9834a6063e1e0bcb022904e8e2249c360d911f8e19fd7c7773cf0c70c3848b27c2933b75895c41db11a4ed509b70d90669416c05d1facb869b7406a11239b7cb78f1f6321b70a026748d0b6bf0a17f956afb50f20fd52628242cd4cf4910df09516801e232d35e5a09d60c9c84e96b52167753f6d001b06a6a91cab7437448d854a2bc488b48c1b510ed721e42af74594d81e06ce5f831a8fe17b6fae02a6a3a25b45bb78d042c3c4a72c7b56be30852490ee91d9d72fb509f4770b25fbcecba1eebba786c6cc3edf65289a3a7d521a80707c00f2252f3cb20d570184d163ae7be0f517e90cd2787186b4645eed11c721c4badc09a1f7992ecca001feda1d21f221c296cfd21d244b07db898f67f6396a27c9156d45bc221e26c3a45a1ee78e9db8e0c194343001f898ec3e39453a67fee72804bf9d853939c46092af30107ab074f1d3c0145fc4a67ced4314185a0e28a165c5d226b01baa30aeb2d839e7354f15024b9da181c1d7f7610a0840b99a5e1302ee4ff16dfd53a81185a9d7a508ff0bd3e2071b5dd28ce329d06e4b90d483ec0cb0c9d6dca1a95615a46eab3059ba8653d2accbc04170a2de77b35e7217ad9eedfa1d2dd3f5e37c06a95ed33c80f5d0b155c9d2a4e34e01f94346e37c7b0d06bceeb34fd501be60430a9f2548832740715f2f25ffb2a7387476dc51894fb89b1d9b19d0020c853af062c5d5ec0f08a6394c5fa1652bf45e452602570b90b411741a59041bcc8d120fc965b7ea663f636c06c0a4c6a2b99208db60f3cc22f3906e24d172507f823311675b0dbe39fce4d234de175d7b2734d4723d287673f1f36ba732e7508eedceed03ef889ea5f2d1f84e6e842c825682a987a6b4df7486e7d6e7fa1583bedd291eee7276789af29cc3ed61005c040c72c0285e8fcfc34813658b07a6084612e15ce429ab6851285284fcf101599573a2cf33c939599da526772ca7f1ba167f88b868eccbc15e65eb5cca9e18b855521bb0228156651247eee9b28b2b03c0641d137bfbd33585152680ba7a8a414562a0401704e8594f0306020e9f0685e3d7529901241ec5c0ab85978c7a83ef088ffdf341bca436910f1a0fce055b7cde39b8f6c2ca2091055707f606505fe0536bf79a0c628090a78533febacdaab21760297e567c1faf220000e10e2e99f30079c864dddc11aa7df2258ede8a7c4a6787e79799436f77fbdcfd69629294d574f3cff9034fa9edf3bda38615f570a5840f3598732c584d88e2bb2a465a412803edc11d29cea511fb217f0fb154a8e08dd6996a0c083dd0442550348b869206809fe5df92508a7474851ca81a92a46d559d040dd8680c008ac08aaf8dec735110b05264928c52c24fbfc91b2c665316f7e55fd0bc55053aee5dceda0f0e2b120aa0c8058e3ce02454d917063de20573cf9ba48884cd02e6f1794fd090eeaafec974c7a15e1fe9f412b78333acff701f8ec7c277cd8e244b6d4f100750f53608517fc92174e1a2f25e3a3b46c94643d90e8a687ac919a4fd293dfbcd558452fe720c82856627d187f87a2c5dedf56cc1510cdda7939060fe2c66155b63957fb510aa4f681b626c392441d5d4a1b482fcf4021c7dc68d800c4e1c24e9ad1b3b4de3d11390b54d2d5a187b233d9969ef323b3712e48387890033ace1acd43d72ece6212bc3fcad79a5f76d771b218124a65e863a238b385b3f4b5f925dadfc1b9c1867a31f623eb73c282b38c599af4fc9fb2d06cf4be8a27101b62cb24a46fdf6d7b9828890eda25228c1e6b5e01427655176c03e4bea1605bd05c351d79f270a50b794c6779ac7968f4a253656d08ac8d21d5ca401b336ddc6c5fbbcf1456d279ba069a2775293832cc455018a380f9057c12a93514d533fd23061067feb47d571b6eef982a20723c4fd626337cf4ced5fcbc620725085aa8965fb81bfe7a0589ccf93e31233bf39afa83f099fb4c1e79219d3219e2c696b5df3530924dae7f3068fc2a6b539b449ecfceae04c03d014eca253180e2f7f91dfe6f2c8144427955944d9c3fe94828917372d00dedfbf6173298e29632f2c3d6c6faff40cc81bb1f50c069fc77c91cb585cf59885719c290bf7cb2b75be049eb3efd396a95059ca5686eecbaa0064a7165f3c9f45401d32def76106f86085980fe11572d8dccd7473ba49f034347e6ab34d22f02ba4014382c54a145477b9cc1a9ea54d30a004289ad6665bc7e391659fcdf297b167718cc3a5af31928b0bfef88128362cf28edbb13a67913b5029b82ad349eeaefb176301e765bbd46475231c8b921a1aaa072068396da180b8caabfa9f947d6350fb8d3488c99f61030b8a0881d96fde491bf09a0c9737e7a31b2e20625da2166ff045a61b42cb39687fd2877d316b505df7f0807f11dc8118aacb56d6a1af6c90f44228c19c5e761d527aefad365ce8d50d8fa13c9f40457e6718086d3fa4cae121ceb4ac270214463558bcefbc7808d71056309be84e2659cede327d07aa7b59cfac95c438a801f0c921093011a0b4175812bc8d4d5874c8d3e5296de8f9c4deb4c79665d3ab1c952443af6b451950afa9293ed22b89edff93884bc938e72574f66337624b8c27cb46fc00c4f84202b526135c15169c4962dccddb6bbda55bb0b18a079e0c4bb381682c42ba27ab6f11cd999b62b5060db8b3354e5cf84521f2af8c05614fcc0cf91515e91537e587ebef3bb3a0c976b3436ed385a4026de29a16593744503b0a30fbb5add02d851594e6b3e5fc914983eca6a572f51c025361d3e3c20c4ffa26355af4326be333ffbdb0a5322af292887b90ed060e8b052ee70b60f6d826b4c75c89a94a3093fa46f91637dfa81fd7e07822c77f7e88c6885463bd01528a420857e0071e89b2ec1003e21fa931c9ee3f80367faef174c9d9887e1062c5ddd5c6497e2686b258480dbf1f4deb1acdcc02487a340843889111f82e1fa5a58b3ee47aa202f3a614c0771e88e5b503e6b40b913b6d3174b47932b737b349303ce07b62e7b3577386c99c4d2c4076edbe4c459728bd9fe57c21c6eff2aa4e3f76a0ebebe434e89a9e79ed98a6de80236e8134243f1b6e828b0d7a910c20fd50be70b98bffd94278c59fc6d3c5f40b61f2eb7e41c64bb03bd87f520633204d60346338cb11566b98431898ee08155d205ca1550f140e07492ccc8e6813ed10de83730d6891f2374e48227cae408b9db53c4aafed1fd77a54cef20c2777ad39c6c30e4cedafc49088a4a43ef267f8f30afaaae01386c4b7d754f0ad31dd909d34c3da32ce6c6bdfc2522bd72d43cc7f8606c29dbc161d0d0aa025be078585826009b284ff089c73533d9d9f5bc953664a5fcf9568aac7c3e54aa94addbe1e54ead5b6925956be0a77795afe6a7cda311c80569afe424c24b86f456cd29cdb08347551beacec138f824976537908197a959234cfbc09ce1841258d8324fa48c416f26fba42653e2cebf0f6e854721dcdca8b482a18542eb1fca0170cab1257f982702f79cf8ad849238baf659eedc36bb753560a07d11dd5609f0bf98706b7f0e3b13bdb63f0c59406e6dca73ab201a3c7c799790bac98f3dcef77bd53bebb0f2e715cef82988a2834ca1f75b87a10a902cb89d42a6b255943ab542b5c7b37dbb5b2a8795dd0ed662eed0fe0d2b5c09748ff378a9b7a95d5ec538778831ac416fca3c42641e381cc21a6056acd516c86afcbd332b7cdb0d7d22a4cb73ffc2a86df00c38c3be0c641f66f490e93cedc5a3f648e59fec32cfe2abee6cf12de5f9da13912667dd9e323d1c32f1c935d6f856444551fc621acc75eb70ede3bb38ef740e6f228fbdc01c7147966cc379ec436f59f38734a6bc38d316d0cc232aba8be940ebd0af2062ad5f13365ecf2d9ace2c485d9d550085603ee7a802fcb4227aef875b6931a78616210ed38b1ac60387bf7a62a793656302fe86012703e3b0104e91028dc443d144a8cfa4b3ea55bda0a102ac10dbb51395d5748a0c768280684763d0455fc3a8ad81ab3821aaadd4b0b51e75696b0185a7990d780b0a3952429040442e76bf74b583d733a0462b6e2f2302e9cc0f7f782291136147c5de04ae63d346c5d47c900bb97c4e7326d019ad298eff44d7f4d351e875c33889e4885cafaced34ff562787c3004a79a568825ece55113c8d2e742716ea2406167e0e1690a480dc16830a0bc80335b5a1d28cea029a96b253da941787987895a41d88edbaf4e71bf53b52492a52c9df1482b7715b793d5b54ee9752010f4abd71722aa57cbc793113b5e4b1ea4492e47336a18501385c386d70b2e46b425e7b71870f6f4435dca86ecc81e7283faf857b5fadee2a512717fc031d803f65b6dd7a6d9924fe6e3afde8957b156b6e712ebdfb1f9e505a0deffb832394f9580994142fea3e5716a1afb387dcbc802cb9028a2a5063c148374538082c6c92859e15b6ed846cb4dc8206835b0ed5b1c39fa91c2b8814128868452f20e17b4ad8635f796fe1d56efb27c223617838529ac4b3b153998c40b1a083b440dee87812e76eecaa031f40840a33bec2110413be7620882b16607c64cae0d78b8d10f32a18e62750b744152a5ebc768b0f83a2ac85af02e07456240f836a086b9e341f4b3346164f01f1be4858fb37d1463ee1063e9b02768570f0dca05696f839384f4fcb053300822af0795a71dc0912605b00824183b3be9d9e709e53851d8fcbcbbe541cad3d2f915a0fc62a185af17ae84cf9a80e3f36a6cea459cd45264232372bab7e03e5069d024b353a03b3897b483696a4f9ee52336632bd9cc3aa36ade094ba51767aeeab6ec70d5221f82d1a44d453d147d219e30a018a78cb6d569f6b6499b21401385711736adcfb01c6870587b2beae740f0e5f84dd1b986ab6543b073f5b8c338ec3f86a42f5e2ac17fe4c8ea6d1f6efce635dd24ab6e6778b00c08c21b2d6b792a9fabd979448fc8845a97e1cbcaeec40ed5e381aa5cb0706b4df8d1b930b6865e6160361378737cf94122d34212716211228832972a1372e88ad007bcb78f68cb14fc0eae8b3e8315fc32191037e43a45ea3d861f6d930e2ce2e22c6c4547081db0d86885beeed3d2dfca16af4f0efc75818a673af204bc024607c6f701ea2ac5c8b372a3da66c9153925914dfef8b3574f67bc250ab1d0a378d77ff5d36ee2248ac73c8f8260fd0c860ca48301300866ee73211bc65b97bd9e1252090cb6d82c74a318c7ada7d20993a151a0668f5ad3aad626c6db88c0b89a3355e0cf48dacd17402ce55d5e8e5c7e968b0464366e239a8413d33c632279b75df5b1e67e5460f2d313fec646fdb9f70edc056e7739e081fc30efcee0bf15e7e9731db9d6a01e1061e4c7b523eb2a7f3b2ccf662e83b837c45a4119c78feeaa47f4990def4cf5e329f60615be6df4fb4513b234174b0909688d3803003b5ccb7dc6448ce601631e0d01e171eed832f76b61e53826d61f6b4f62b940b8835aa423f3a077b5bee6a20a809291859d5880bc2b80c16917793720eb694d6696e713d5cc1212ed547ca8f361cb08bed9689533f2ec3c8896b4f354e94fb8220e9e837abbe7ca68b8835793b4c069704b222f95f6563fa9e6cce67b79f8c340bc3f7f008a1d359073c2b4123dc4819522b34d6935d1e1cf0959fd2f3799dd899b7a32eae6667fb3a4ce58538c1ad9b2356db6b9f0c862effa84772a9071055984b865c34e1ca7e83f92c0c0740dae0ac5ca47b1aeefb40e0f0abde6011a61739c71bac32f80c62feffdca9c9445ac0d770a7391ce1650562113dcaf71b2a6a232dc0e6f79be84c34ca2b7ffff7f2f9fc86dc51e60aa15a399a21a726db5189d7264cce2ace2839a9330368f4bd82ff22028fa66b4ca286db01f5c6aa9dac79c7ccbb329a4da304e244161bd3b3325c5be82fc41ccbe042c351cd03bcdc8a0a10e1143fa8cc038dc61975266480403ec905b6c0075518585d71e7aa4bf1df2c02d5a10b5dc2211c1ab10119ba1e7f61f0f0535d9ea7130cd2abf40504078d9a3825a42daca66853b08807fa4e41118195d4d7221c5e221618fd392301ee403a6cad55f9201b49c1a3bb2df64314986e0051ed50109af4f4f3e8b5624f0f0d672d0e8ab320cba18588e75286b7762e779c460c69f880ceb395de5d721a6bff4eb42a8eebc7616baa751164b1a54ccca8604cd0294cf1035250f96f44533e6393cc039afb57c2042515dbb85fe655feb0b3fce2b61b755e9e36d5deff76b93d04567f5e6b422887a09bbeaa72fe9ab96002bc7f6ebd00d552028ea772a3b720f6b1e5363d4d56a314cc29c2eca0ea7069367a5c02d15d0b4d46758c3c0b06cf9c297dbb69dbea6cc2e6c0a92af6ff96fbb64de32a0ee67b54dcf464b1bd56ef00f71d384d38c9d329fe128c9d64262eb73170725ca0effa96418e9ba4d157c7b1400212a415b5394a3e2efee419103f5d86bedf4cfb9f578a6ba712a16022a8c0bfd24ec15b9f77230f707a8f0f0c91f14fb7fc0b57dfad59970984de7a7ca629825a1c84981ef3b9d0d66496fff4e83d18772ededabaeb347802fc745ffc2c43ec1945f5d6b756c26db2c7ea1665560a588029581c094ed2daffdee302b2a01d6b255c3c2673d7fd54ac6dbad93263791cc4ddba43b485b358178877ba805f2b6025006b3539498825a34c57312b9861e573a7ce89ca073fd19e8f09f1a2e6ed6f27d5d86cd92cc7b253cebe2932960e8caaa686ce9cc42740257a247852b62f98075d10a08a4a4b58e47888d9690c043de3f6bde383ab07f7bd11006d3286a36c226acd11e1b1906c5f83efd4de1a28823e2b743eb8ab684d6f00449bfc0832efd217c9130fe8429b7a7f44818c43c050e948e575103d1b9f06026c6f0e2df9a8756606490856c8bde69cf726b7370a3378563175ac84a8c382f859f51ce670e3e1b759bc24795e49261e16212b869d733d98285f5bce2bfb89fe2c3a9e0269cb2b67da9d384b68a03628dd7fb27681fc51895d1799919a5cf8b05a6ec53a0bb510df5244ee8851bb6c57be96a600e9c03f5932dd9545ceae12746f2c2be5e70fe99a6537707e12643e889d0309e5a1fa019a79234c23f0d8158e30ca241b86bc37e074554ae880a328ffa8ac9772cd93ea2056effa72fcb8e6f803e858ac394cc1ac57f800169ae9a7d8ebd80f5a904049ec5bfe531fbfe3f90280f603838b05daec2eaae6af01873a4f7bb89a15a5f99e2f1c3e4a9bd826dc24bfd64aa511a95e230d8d543b7da799de659c4a06ac616461664e4e85af6144a9fdfdf822779030de49ed4a7e464916386827e73283ad77fe8d148a47b9dd8f24978c2d05bb7d560319d8b6e137273842500035e18e58f45500efa1f3a7abe8ad29180e08ea76369d53b3e10128f363146c18891fbec5c1ab30fd3d6a29145446c913c9891dbf8f7f0e635761eb9d7471a89c4e6c484ffe6e2764601c24bd9c15f73d70afa20c70cf28a8ecab03c4f052318176eba996180126770d0152485278a1def8a9ad62c7e4f5fcab62269359fc99c0622bf3161ed794efc92e1cf4022a7ea311f3aeff9b675507139e94c1e35d44f4e3da7754f8c4c4fb7a4d3ac3a875e47ea8d21557a7165c637f2b319b33751e97e16a70add02a300ee345a0b5ec4640d17e9a3c2489e599338170e746a3805053082e81d4398501ce5423b10b6ff885126feadbe44d81aafea4447a5fa774a202c150da3586d2bc10399aa1941ab1f17e8e33296433a1fc1b002eb98e659e2971dfd5ff4edbf9d9e879118a960e9d68aaa6ed65a0220f9d53bc855dc50d1bbef9daa4d1bbb09e81b15c5cedb6749fb396db6d5529f935f883c67fa0f4a1e0dca1dd21689ef8649c7d34bfba48816c719b00ce34788aec6583cca60d6f6ee7d562a38f773f5062f89985ba0b92279b248b1d36a94466d37f1b3d77e466e8bab9c0b62a84819ecfa5529c0f4c5dd3823cbfce02651990ec43b930c779d7b4c36e6786429f8c372533d12e5605ba077c95a47c0d56905344a8162899de18f30196434be8b1068f5f90afffff1d4b4eb31333aff4474b586b80c802acd15a43fbe0f9cac95568eac44dba55279aaee1c5a3a483b58f8dcd9372e3bb7915ae75bfbf92acf7f8aa92baff97e74795148d99dcbfa8e180b8aa2919694ec63e39c3b07ff98a45c5ce696a387a8b4e2284172f3f0a96a5ddb1572bf1406248716df27edc4068f3e6b468f7c7f11c2b63a693a7ed6f28436975a07b485634042f8db50c3d0a0f46a3f719ad7462260c9bf42ff182c38bb06962c4cf7cfe9f697919238d9977d8e01549865627e9ba600c3aff16161390de872e94d02d5ad5e92ad76be30ee9029d7ff177bedf855c959f7b3f51dbc568173b93e461fbb0cefe409c6a9a1a545262c462abc8add129cb92152b7d434064506438d42beb790b7bddd829db28d385853abcce1dde8eb3cb2279fdc910f019b65117735a878e8bd412ddeaa82cf9d42dec20242dc3cbaa64e6e812c6278d540f2b9d16b3b81e7f0277e3cc7a0cf95931821089518f56f4723e8ae8d29eb79855e0eeb484522f41e23efaab13cbe09621011062a7c7d5154b5ff03131a8c91621f478d3265a9082e0d07014267a0f02d9f9fc80555a1abb6752c0ec96865a40e05c0b489ef07697ac0dd9604c05c30e151b05d12bd2a0c1e1ac36aced0b286da1bcf4fbf5e5abc867619ba5c2d7a4293a529670802dff444f6822d6ff3de81dc576530a69354ef58510813e308ee02604ca470c228282ff2b2554af1b5da533c642f2ef76403488089c539602b07726bd45a6166b2a8500c0fd74ee26c1083723eb8bf4df4d5ab483e8f3435e75721b163c8146faf88afad07f2b348e334898fdea807a0919c1a4bd21d8583aa7e48be0e0c5523e931eb8c1d3e5842714c963181fa5658a2de73d7f0710240d031e07975ae4ea1165193cbaffb6210144fde14488f32c7e559412e2969e99651e29c7bbfcf262fc3997c4f479081c3730a0d135401e78c222b3f8bee160a0a0d0a011c2f0164b224ba43ab1908462745d39edfac97d2ec4036f6c0a0d2a8e952019f9d0ac7e9c9be695b2ea2df6bb7b36419afb1de8e5cceb2c98dbe27b85915b2cc5b40ec3d03c181832467a103cf32ad5a4a1db4ef0eaa584153fc276a6a992d1765e011aea880f700fc3948f10a20f320181cb6c103d79c34e93e65fa4920bc9be7032f99344b13a02aa8c1976377ee1b847bcf3a9524e137697dc78793b0aeed6410087b1f24d5e10572ccff7aedd0adb60e9b042baaab1ef8657865962f28958691a8ff422b6ba9a03791e1db10e4cda3d17eec4d62b56e02f56e1411a4614860c9c937e8d5555ac10698408041be2803a8592a7d38c56a1f7643f34e75d899d2a0a9817ccd81dd813a77e31b58e5755fc4332a201b0aa5ff2ef9289476018c331f165f2d4c0a9347e238048bc1e9ad37f21fb42c3eb351f3ab6d8392750b5237c7c0fbe218671d045acc6f23ab4a35e25f0f8bf8da5d0bd22855513a155ac29a8a0302d22e35ae2d64918ed878862c294109d1abf2638e255a1ed3b3deb10464a4eaedad250d3d130a9adde6f83bda0dc2a23b2a9c007ab7aa03f75983c7f6eb9c4d6ecc4162ebd058d442452ad8bc49016991ad4338056623a7ee5198d0e54bc5adc04557eaf5d5c730e162e37722fd385a7f4793bf159600ccdff9a29837b0356c5a542ca5560e37eb6fb4ece57d1b64729b3dc95088ee3068315bde7eb4724c7bca0c0f11c5bb74870ae635185045141728bf708a0b75ed7d33dfd46c1893fd68b613891f687388bdd544516c91f7c1a445664687b6bb3c8a44bccc7f8c33a1b87e4a26299bf3dd17bb5377d8ab27fad394b7d46c5e50050ab25d363a08ac0225bfb017c45cb1a0011c6bd55e43f7ae25dc9b6864cb9514e15d274ee5b592cfa0f890c772a3702ae09221513423cdcfdf1b9de8d1a44d3e87c8440674f8a61b41a6b308e89211a3424c406fa557c2a494874032c17cd88e4db74f6e28cecd722e498446474bbad9d27b7f54776e3761ab10dbc327bde78366baa0d1db5d39e872190f627d65ffb632dc9fad0e50adb99ac7f9998da0aecb59a7b046aff7a38bdd72fbb4bc7bced8666d4e86d4b6b8dbc40c0a8b2cce98b97a5ae9f41f4b3b6c3308674f890ff0ba8a7c99619b1af214ecb373bab204f551807b9c3c5fc3a528a6e3a77add5e5b3bea0611bab37f96a778bc5b24e848a6f367db1ffeb7fdcc36ea23ae000f86928788cccf82706c6dd920b129182562c8dbd46313d255c266bb537af4b1b768e0662cb93f483516a8429843767f73748873bbb86bc144ad30a81edb91eeb9b86beacfa1008cc25c0e1b13b0464164c2ea368561489c2421e51a80feb2506ef2f36fc390bd034c06d57c167ff421dc18d338de898ede2a7ea87590f755ffc5d93665f69d4579152f0c23f82539aec82501bed1e49871daf8f11d99eb22b73497f2633b78d3155e5bc151330520f15bdcea1e7f0944e77cf4281ac8d110cca29273b3dd0b436194e179eac5c60016008ffde897f1f27d91f08187ea6259ec160f0865d306b3e4b0617a35f4f5c787ecf3b9f50d47b2898d270579c99174442800630839503b87cc487ad5368d0642a1242eaedeea504bda4a45b35208174d3185f8d8dae1c2ebce4f8135c73fb37123a30bf9aaecca1b7e86747c1739b7d5ba28b37bb1907f7eb803b24e43fae983647be677ce18cbd5b693a4cd85217695f47f0fa70d0c27dcff03e4d681a250825c71aab1d88ee7e9b1205488d563406bd7c0c172397135cb5627176c0a26f78d091da779f90c88e782845b6526615ad3fbec982e5f18baa2d835a48984c22e3af8730afec8f461f57217c9e3518a21e038508f068e48b4cb7a5df5568fff052e4770e139e9eb60a19b62f5009e1f0c18a54f3b2fe3aaa274e767b0cbaee6e9800767d82de563d1a135649bd0a1fcbdc5ac89a4f72f44951a9bedca38ada187118b31957188948b32d8e0237d8a1a4a656bdb7fcebfb927d75b7bd68dd2bf371e4fa3147a381f2854138e8e4867080b542fb3d3dace18efb929a32c1d0bff1d5269363ba695a8345062bad65114359e45fc49ce5fa67fa2dc4903af573e076d8046dbf004704203cfc434ec99e434203daab8a49af1ce43f19adec01425c741913f5aeba5cc7d369a27b168cbecc329b38dc48b2de5bf8f6140fc1582efd0e19b0f3538dfad580156d458c175f31201380c55288b301dc313023baa585f8ca149e9537fd5b599ea9985807d291802f4eb48f6df92142cb8ed81df9849465fc65ea30a6b3d7593a537320a4152425ae80bafae36811bd793df55ced6ad58a8c43440058920fbd9bfc7297872637a0bf5de31a213d91cc68e41eecc5ffcb95d3a89012546c8f01880d4906d56310ad2b4720980735c2f1bc85d320cf0939177cb60d539f23517669c378a6280cf5dd9c25e983736d0fdc9482f68b9eb72e9c4cba3f5aa36000c7436a2a04bfe882c4a4c836c0223c384fe678c429875022cc05756b9de9e882ed255006ef1d4d24012bc716951fdafa3147cd31d9e9ca72949420e675da20a7da2ae0108e8ef21229b0371a1a4cfb2c4965f0ef574382eeb0c40536696a960a1588daa65daa9c034ad8eed7e1ebb37dec045c744c70549cbf95cb722968f9d164afc140573840f02435b35ed82e62d45ee7e9fec567ad7ad368f3d204ca1d60d8121622b8a35bc7fb5f619a0adda306b5d91e47a91be2957b194ed9fc99c23e3812d30ba99995f53d2044670fcfdd2cc31e614cee1e6ecb10ca59fd7f30489d37a5da80b42b39a4ee2dde91f428091d660d0bd7cf01a0dddb2ddaebb9bca842659c706bd3c9c9b012dc36e270e9f6eedb38402b9149ea129619c8e23343a0f28c814d880013d5396d87a242beacac0d1b6efde9973f431ccf52cd0b2ed3ad6eaceb2146bfcea1e2e601bb3e1aa29cac84660325193df0b0f27861d9d5f545fa899239d0b0f757297adee7b9d8f4e8d98377746481006421ccbbde87b46dd049024107ad613774097c9f6643e90c69b3fb942d24f214ed258a2a1702fda37cb9418b49918b58d80a9cdd18615625d1b5156bc4210da53e0aa511ea9130a0f4b881061c12ce61eb17b38361f82ee1641c58bf3d59b2710fddffc21026611b32528b196c686e4f6db72ef4f80e4306b4c7758246e878fa8aff39bf7f61013a680690e85e997f4eaee12240f48826b39e431933342b900a74d46390ffadc4782718d2ce519b20c817cd56c450e2391bdd2dc02ce972da75d67f79b0d7a318f8479c7175386f041ad5d724ff641fc7867f20bd2be993905074861fd3a98b4b7c2ad4b648cd9eba8aa4d3e853b6830ff5cf8cbd593905771e35adb63f5ab46816f633afdb0ad99e7913b4af4eee974e140c8e819de74ed7752687876680a37455e36ef74065328741a27383c82192cb36a0b657fc01a0bf6104bd737020ac8662edb42b6dc223faa50bfa5a2108f86b063e331ed91cb05ded6ea3805a945e59cdd103749dbe1a161ee0a55168cb631340722957d5b8bf30165a51fb5346ed3770efe354b73a61ef25b4fb7b93dae2c8dfb4b5cd34250f733a746e6bc5b6a70ca04097fa39d5fa02a37a6d6cf5345228ce5aa1b9fe794db1c93837df81b0700e8c235a9820bb1e6c870409cf54e4168ed70faf7f5c113374cffaccc1d645bb2db84726298942439d271fb6febae20db1d2d1828e038a5137b61463ed64468ab433c4cda10d544ed9c399b7c37aac2adad3c07d9004cf986a3842b7d430d3d2f4e3fb3d25b5212a946c96eeaa35780376bd3cf6c589eaf2d59fb65cbfd32f17a9652ca42162e337448ee51b5d6ca7b1929b4fb8df40835bdc5c9c1ab5a0be2b2e5f64a6154cc9d762c49140be2269d544c41427c252b9edf5f716f7dfeb9b484fb1ecd518d0223f0022745269cda60900e4beaed49990dd0e9ce195fa973891e221a0f52c27fa9c91a47766934bc68b8b2a10120c71650bb64d8c00bdc78fed143ccad3ad9457779fc5e102d3548fea9ceb990f520c45398ec3ee5ccd6193719b31a7e163cf5460d37c1826b042b48c80dafb80996bbf44ffeb21e23710a2daeb631cdfcd6a026d8b66bc8358b855c16b02daae2d8dac14ad448dc277a3ae25b5625785b5e6b23f10466f18a35e9bd610b76b1a0bc3db4d3f21d7d2bc18233cbf8a1158a68edeb9f764a85b736c45b491272a20b8353398a2299356f9b656b2cf0832c9f52a22e4f5938fea061e4122d07616031cf1708390685660fba08e718cfa7d53aa13a939108b320b83bea111df0a1b91d8f2682ad8c74bd464438cf781f89a0b9d677811d2edf9664039e3de59b7143a05e250485b6e27314bdeccb0b05f42b4ff87c6c6c5101cadf43c8c6e09d8dd8255e31c9173646a66684da1cc9b0a000400c0da6f6281b9886f9eb4a10cd4aedfece252aafe4e609d5eb16bd8caa102f46378a1655236658e9a20e8e11af8e3549d16ba9f06ac841752cc9524cf822ec316957c670e2afb7e37a23ed2a1baa7372780282be06c5d6aa3e101e46329bdbbe648df822f8564998173e0cd5e02bb8624a4ec340e539e052694928e84473bfa3d336a1f3fd1cfc21b38eecf7574c4f043e0d1f14ba5a6605e3f65d0fb84814d7f249fbf91ec0abbe643b96abb307df4b56774ab8d846fb2e31aa50be1e8d916bc099fa289bbb0d9132df9ffc1da2a98b1e61a2ad2d4fd458f6342661fad75901be21b073c48500a99f6a25662c267e4cf8916bcfd03622be6602a82f5043d8a7c857fe67a28c0d1884d65354307df2907b064c5073c377bb808cc4c3e2e2e615c2c18ec5ec330069c58adb2d56f0704dbbfd2c8ee30aa1f0c61db69589f7f1e3929baf5baea3d775f600ae84e2e07c70dfab87bb20f4bca9364e6bdd3ea3d363a8c15582207c8591c2c9424f1fa07c910030e5b4bf826b1d4027a4156b0245e413376c1c5083cb05384ccfe7d91cca8414fa651cded3aa4bc0dab07e7a6ffa944e1a0b25840679e4f6f85857b9cb1c9844427113d62b7a8a59c9f2cd8601612d6f11eb24af306749ad5394428930044c64e4e817eb7dd48d218532365e707e70af84f99681c00ddc043adea8c0d90193e0d0c921ec5608515e0eaa8d7426fcb53332c4401bfa6ba17d0a47eee3b8f0db9b7630786ac90a444d3b71fa6dbf451888d5503d7571cd1f0b937383b80128d724850b60ee46af4002f72aeddace5850859b20a79394ccb388ef06cbd7746c6edaccd5215743979b5888f2ff97cca11ad7048db5d949e826d8a02728e3c51ef6837c491cb0c8dc6d43006e0d1a6a5c38bceb7a69d60cb741d73f55d5b2ddd5339983575f51092b0d59653111ad48a603b885f6f2c0735ec2a4664bf4786c55617659d8a78059ce600f3d7e3d36e7791e667910ccdee62992fa8ab2d497aa259ab3bc9745da61266c7e82f1d9b24ff0cd172d5b811422eab668f23871f24073ac9a5e73802c39d293b13557c341066a0338d8ce4ccd57c4979b9a39cd12c6e57a2b1c551f30233eb407e8df9255c7d612854a8076d334d84434e2bf255902094999f64539ab8ad0a32eb35172d92c708a8f90b12d61b3a0aab9faaa267d09d9e2e15ed253060d7631050f3e1932ed83fc2b3c0c436ab7e3f6ea6984159d3d4f2017d6163e82a2108eae8870cbf208bb710737bab0097c4c817a33749d87abd758fa2a175ac724d816d68f5df2dd8e8187044e93ae16f36f1a5502aae9450263e01c648ce26b9840184dcaa569107abb4a665d50ffa3cea042ab365134750c04d42a0657f0f9c7e8ab8bb32bd21b6049f849e54f1e0145d02e999c893db3e5572f8acb46daef587422b87763bee2a5b25131b106fc68fb313b76107da86b0d767b9303d293c6de682afc7c3abc2d8838d33ca9254763dc7ead576134c194455db5f3295b716f580b7ff22e2185b24d3f7779c537f996f24b0011db8d8aedf334f19b25280e9fa71197288764777b98c613ed1add4423da43f344f3aa52e71a1545751677186ce3d0434c66d7deea5d668fc34053139f2e6f89a13eaad9c6b3fd0cda650cabea25f20d5a0f26ea6905ae30fd65f1e4a69755a500cca2d80f324cd441011e5a5351d82e057dcf4095dd21c6eb4c279950c6391b35f08fcbdc17ec4554a741460cf3ff932c443b09fbb270fe90c8e558c7ee72ac6fdd06fcea8495fddf78af9a3398618cea73fb9d2a0e4900e9d23d30ae3bb409949cefb25ccddc8416e29e597ed90fba85b45e1ed17d00fb01e188b543b071a08b1eaf232aef8f4f635e21e8a22921773256270bcf8de2d37df4e364ddf09349caeb7b69a41d02485478f45abe8952e463db17dd20721564e6b117bf0a5ba8f91787db1d4bbd499c7a987e243933488ea8116dd57162336511f5b56864fc1a6f82c705147533de16fabed8d8814eea4343b57225c51ce39934e260496428b09e60b0d6f7cf5516650178cfad05b24e811df095ca664711a57044acc38cdac2cd6cc26118c26006cd12e3a4eaf934c2677b18c9f94e72df34faf4990f4ce5c265cee6ed2b5e8056dcbdbd35016fc1484388ee95267d762430f762ce5c82f9ef9e09856f03c8f72a4138fd4616bbffe6ea733536882171ef7f85806c219e35aa14a40b7707c8fa2488b16470a4a07ae99d2b4a3d199e9c8673993e03553dac294759c6b8d6f42dc51e387450ef7ea9c83e0e46a9a000410dfd9e7464fb6236edf1d48c7997d16beb1bc3585aeb59a275b6e5ce51e1e974ffb4bbe241ffbceaf66e18763941c673cc1f42c41557d1ed2232b900af3175dccfbed3675fc51a0459d7703f64a6be74b3c56d092125fc2facf47992ea89fa0976aaf8ee359af3a6ea2b08403aed869b19bd7a053b2180b5ee0a9e8d0940a5601d453e7636a97a6e920d95b8996b69573a583ebe42110a8e0892871313d841faf6ccfc6bf2814c571fc8a57983870699d5b4124e759bec98ea775ae78e2ee856819c6f8b225648886c84903fd1875d8568579548cd064554041bb8345b02b90bab6357cefac92dc1cb9a2bd7a4ccc3e7cb062080247463cbd1a10d8e218cebcea6251fd4760805cbcf87d1aeb507b2d7e8174a55e07dc8fd669406935ba1443a4b55594363e9edad32a5102a5bf7d4b845d42b871d512f1fe051da009447488b31a06438c64538ba1c3aaccf843fd8d3b7921f23736a2a3285d4606da884c9413720fff7e8770eb2bde0e4d8d44095fa003a42242061ff897f0893692b51a26127945429b6f4bbb5688b82218ac48768055fb6059224baf7764fd4ab42926bd00e10fa1a9ae07e30533e0c106ef1cea046bb430c9910f0659ecc65379757bbf6d5fddd40d6bdc3965c450958d33fea3771712aaf9c8b81f8698e349d32b022116b8db661b151c4aa4641f5927cfae5b985d4c34c5b9345534eeeaccac8533edd82ebfb1c7923141507f8333ab8f69221bc0037899ecfe53419c5403f5b323ed9d6d83608b9f8f4ff45bd49133547509bade3a0e7816a32f95d0f243726fc8ad66f7295bad638355a28f64451281e8fe71d7165c5621685fc60998509bca9e53bbd6ea062facb9576374c9ab246b10dc599fc5836190236d649e7aecc23887d450c64fe23deb2181ca88fc7e08ff5b3f2f100d517c801c32b44382d393c03895a4001e9d44e72a1f089656a8f345619d74acf6805843c34222a215060fa12b8ac609493724ead35b01068d3e33d0acb8c69e2d956845960bc1480177d72300d4ea44130ee064594d6f4a9da8eee9cfbc9d73e724c60bba726b76612b80c579918437b56821ad8389d90e5136e4af71d7c413ceb15d8eebb768632a4e1a62e016a205c391aa2250df0c0ae2db96b223839f62c020d99b5f6fbf452f096b11e7dd3a1cb50c8e4b9521a1fb6224350a755ef71e8f1e625affbb52d86091d5af9a09432547b1090e8012d6f258ee222fb60a625c57b7853a4a5427e00fc3fb545e2a5d8ea8e77b171cdd83b0e9ebe1baf89bb06169dee8f683b6e49e3dfaaa3f34188617d987b39bfe57d826a2d06e31c9560811eb03a5fed353fb94198d2680221bf91ffbb9d659ba8fe57d65d37a0ab1face49eaddc8a605ba649d3d0fa784f3953c44f0cdd88d588caee355f29d3ca63d0532ca85d21229d22c3951c72835dac61c752a4bf9738b4de9b965d8a72f964dbd9af8b3ae15e702a7011e98f29c1ef2e30cc294f1866583265d6055e177ffbda00c05106d3c65862a0b8d5a06d242c9c9131df17301ef8a0c5ec52a6cb2c02aa34d530d86cca2c8191932e15093b0df9574ce59cdc63f8d02aa2630f17092cf16d7b675e52c23dc6efe873ea083bf84ac59b58fa0773b1a4dee684928d1309a510f9140975c6045f5b5ddcfc0d1de96d9e9fc391cecba9ebb55467a2128fe390475cb5f0abadf4660404f5d0a2252d7d82499511b3291e7a7836f6411dc894aa98d5836af994bd734cbfc7492e24b02f98ad29177347a3bc8ba7e9e37bc7f974af514193df45b0a8ff2e71c62a039b8798885efd2e3cbd5b065b3bb6465783c849e05ab8377f902a78c52f2fc855171462c4146b0bfe09d4e46f816511e0160f3883ff371c65ffc9648933774919a74beb7b16c107a3b44d24dc6206b16c539a37c269ae95f3c8726aa19d899e40eb6f6c180252786f8f2311cac8efb275405b3de4094d1e6dcaa4a649f08e0bbbe59ef0f6a15096284ba7d3d1b318dd0fd7674c09838ac68e230d0c47c7509a869148612a79f40063631b250a5130a19be762559cdeafd94a9f40a2484793347b6721f240f9db1e4c3a6c0da408f06f67d1e5bf301ac91d6aa16471c4967c86c0b44594a1bd52788a09197e6ebf729fcd37668cdfe60550c371cb59f0da53911cb05ae18cf6385a17e58c78e1bf3f6376072fb7f4ebe61bc65f798e61c40b6de5297fad0a5c3c84524021ce14030340308c1c049c8c39d125ae16ddaa55947370d7e9913c262664fe39d1fd99b2a37066128100c529dcfb7e1edaaad4b09f1b18c2448425209e596b25f72cf3db230ce9a77071c469ab476aa2af6b097ee00d6a2d7809e62376a7e5e229cbb286144595fcf832f6ca92cb2e00b45a00a6bffdf799f2cc65e3ab93472c63817bf9a0368fc2b0d42ba2e0e007f19ab0da2cd083eadc62e51b915699e4deba81c2e89fb52c94ec40ee50adeec7cd000b761cc935b2996b280e0c7a444b2128fa4cf868289263fcb8adb26daea5867c9b93ebfc8194fe2a59afcd06e69ae7c93e29231efd39f7a62b820e6eb8583aff3c7981b39e8fafcc0e74710860f2d28d47dc1327e81a2a71f939edd809a7e7f61e16a420a9c7f5602771d45af3027011f6a0e36501fbe9f5800c78539879e73930dcf391bb81c993f6f5ea31733fbc7a3f2fb8ffeedca7ddf3608fe117dc5037999154482c0e0857ff84e2ba86f89c4f2900e0a7dcadae595c5652a292cf85d4839eb720d65fd7f3433f9c6ccf5f08da8a380d40fb143234cb4ae8df9a47b9481ceb1422d62ac518f34385a2ba6ce9bc7e90cf082b13df6ce73d56833f20fe0a49ceed8b237b71b307861da1b39f8221f46dcc041146477c9dec57609da7592cbb9a8ef3405a35d5cff42eea30bb16bc0d28d79dbbd2f622e49eb54dc53bdb8e6f0777daf41f9b67bd7d7ce45794f98fe31c76983561594a58b5e3cc9681f523d3e4dcaf256eb89da8f27a425af420f3361a5a12cff422374385069e2f1ea3d61145c3446aa6203c248d1b975753ce8c94a950567de9389724730c3ddcb28dde2264afa166c8d05ba2f5414eb57e241045835b8ef1043c2582d6aef970d99037250c858aeb3df2a1cbb2b3293ebd970147e9cba6c10dfe6d6680a03285a35ad0ec2ae6c9e2d2a22293b821c5ae6780c898c9bf3e21b6d263f03b2044ad1411baed524ae539c2ffa46e179816baa912a4e2180398c1752002afe923341e2e5ed807db5f6279ccb7a15fae30441e670bd3f5e6977c2f63204881468fed91ecce2218ba08dac89e2205de38b5e76c4c502f8154e52c30966712a644ebe8a7db81f2aef9de84290576ad18042f48e728b13b3b71060813435746c16446cbd904f9347426902485fc21e93a1e1cb9dd79047ace9dd7904faf1fa1722da16b3c6305c0d6cf14ae7e2d36e102c6d86529fed6307e304b8136e3e926dfe7aba148882c2d3b93681b6f143b8eec6b9512ea674d6f30ac1bd3853ea1459a337fe7571bf1ee51b04427f12480b22b0af86a5151f1cc1695a9fe03362f0d8372770082b38380dd68afc0b8322ac4d3d00028c3303da0106695e4050b2710e2543b2d0bda5696e1c7b7fcdefde39187aafb4acc8dc3877039e51a3f78574bfd23ce76ac561da0e7804d88349ffe781da1b361fd0798146d8ede60a48702be40634e381333c776de2cb72173181f6d24d44844829a59452ca6e0677066006b29c735655b29220185725f6ae6f7d20d5f79a31f5459825500d73dfcdcd40271508a40282ef6fca54fad912b743a457ceca075a8154948708280fd04d0d27201008e402a9fe3bd51d45be14e591bffed7c30bcc96a6a81393cd7ad9ebbfb86ce9e5d5ebbfac6c89db2467f597964bec05654ba09385a932797cd4c5cacbc9a59c32fbb9aaa77a75090304ebf5c31317ad703b24a77e7f888bacd7f7ecd451ed1804a9402217f011478902a5d79781523110aa898a5ff835e212cae45e5326664b9dfe19059df64fdbb5909b3dc16d69c6fe82405c28eab6aeab236e06524d983a8254fbdbdcacd79711305c7d04911c1066c90bb997b51c47721274e25e2fee15f238d5519fbb808fb844d912c755d935740ed5ddc0a1b8d9898fb804a9b899aa571be21909a402a9dec532444b0bc678a792b6b4372637b984e34eb2cc2a7e71fabbcf25a080626b4a526bdf0b3e6292dc9b2469f40b43828f9824c91658be626f1c3be0e363d89783ebb88dd3388dd3b88edb42249da6e2ba11b47c3ee0355beebbbd3b0eb76c690b5b16635675824c825f5c2f1573ee6cce298f8aeaf6a58f3ce75c472c68ac15e86b346370e361acb50962ac62a870894b5ce272c75acd47245c9248a3d1c779a937c7bf09041cac9440b411e222b30265038a0fa212ee858c68708506a2128d734e5d29ebc125cb0b9f7089cb19f0e7f3362cff096d3e1f7a1bfea0e7b6cec3f9e68b3d1eb779b88ef37061088401e7304b96243fd0f2e1081c2564980a694bdb8709535f496b333942895ee21b1ce2992c17c125c7a536759851b4d6eaf1e012972b1c586d4fede7d6e6dc94eeff1b3ece98e92b9553dff45e4aefa564ec85d86ab55aad56ab952d9148a3d1f7516e4610ee8a445a913967fa03856191e88aae44347b73b129745647f5456535650a30636a49863e316340799848d01b4c56f838632f0c11f76b5fb35f0b6d94d8b711d1d79edab086b311d1df4f439a6e883853abe65a65ad77cdb59381172994fe705cc11f50f342a9031ef4bd3f9df79348a46aadd5f9b19db0fc655b6b298e2ef8fd4a6dced4d2640decfd7abd5eafd7ebf57abd4044706a711f473813631a3af0dbc7518912a930259b0a337960200333a6fe88a3477e98edfdfe12ba46a9a8a67baefbadc119b8972d6dfd7abdeaeb6eee4d908a1c17da681e9052035108be222ab13f0409f733d513ce5898eac3c2d0fcf082bbb48ebdeaa846a93022f8585ff555a3c02cbd4c38fe994a030a1feb4bc7ea8ee9c4ab895e2fe56143c38c41f1b1beeacb86d56bc09c7257f75e9cd76ba7b4fab1e223f3c1d138c2ab0ffee2af39f241f3e37cadf0494d99033c41453f827bd89005fb34e10c7d80393ea87df2824e4f9d5b00a6e1421f2b3e435088ede3351a519bb3cdd9c767b6dd5481693db22e7dcae0881abadd5b6bad1a8d70928eeb4018e7ce93c331c6dce6f6deba4efaafad200b92247768687ae094356330c61e4a5a1811cd1091dc5e449f8a229aed450e1039eea9c8fdb430a33d4ed96761663e1389a22892891f5800861826200b8346d3eebd2b6d07e317c0d7a13c4c003de0f7eb9390cc5882cfc4ac1353ecb71104af3fb73e5f4facfa9c75d799f5a5f4aae6f3f022fb4e95de9cf357a38a9cb3567d7ed87baa3ed50e89341afdbf2ab403bf3376ab5eb5555b657380140c72441b2100e0a289c8bd901282b881d87d0eed2ff143a70b9183083e6ed52cbf8e050fa2a4860bc2bdd702f7de911fc8cd7d90cf7b3e88f7dcdf9b03ef442d7c3edccf4f588e38b403a7e1b899c420a46f17b621b6368649e79c938e8fb3dd7beba76f29a5337bc6219b669252aaf5cc1e3bee9a59ddd547dbfad013f71e17dae01f482145104ea2e7eb166b8a1a913263eabea9230f7c2a7caf5475b4a7d8854ae80f4eab2c20d8629b8ed57666cedb96701113a63a7945d9ad1963855340c8a9d3cc654aafc8bd159f8561a3dfe6ac2286d9d23fec31ec31ecff7feb3c0cebb81089b7a96ebaff2dc655c139a5744785984ae5517d6253060177d2cc92e7ad09ddbe66799026fefc09b33477e0a7aa9f25fe36d62f48c3e98615befd38cb0f4855fa555bef9efbd951d516965aa5ca39e319da77c0e78b6a9ef280441158ac4ea2e7f3221b25359ff7bcc8859f914310465627d113da28195da081c44ad4800188b84421d60698e87909b474249e30c8ff27e416c6da0013f97f7ee425e021c9c2d437001197189266a60cb517637cb36ac25d3a96bb16abba7592a4df54b7d74ebb029d163cefacd67a98b882f16b49ced7d6244c19fd14a56b933a7abdb2a516cb32895df8256bbd5e2f9c33c618df9a730c2a2f6e9361c6542e9461b665a855065b5a408de2c6111ca7b417ca607338ed146ae4a5fa66216de26aa55a796bbdb5d65ad75d77ccc7ded6dabd6bb438c7c48f3fd2930f2070eaa9306526a594ea6d6f2aaa430454c70d183a5b8c1298533a10fc3100995380604b9330a153ccdab61f6b689b8744fb0d446d517b90887b41708a2022b8a5b403bde7b6d99c278c5b0f7a7d1b48e29c258c1b17bdfe96c544a1be9ddb4eafa5adb45b17dc89032b01a0d082e438706b6d2e0bc381a22edc5a22aa81222fdc5ca1887e17c67add64221ab650c5edb77083859bcef5826f30d4146e7fdcb6e02387faa8d0af00a500e854d4e98778e0a7cf324b1bccc24c1ef9a91752a8175326ccec2674aa03ff5661eab326877a129c2287b2a50db6c150a80accc001a063047bfd0d56b120c006cba193c10b6c118d4602ea02bbdf7003a9c8e16bb1f520d142d587e2507cd5e5e05331bef77a3e39bf60eba78fefe5b6eef5add74e3d776c1f0bb761cff3eef5ba26ae27b1ff4dc59a4c9b56ca7dcd87e3be0b6d8278de7b2e14599b204a8274cffde7f343c4ad2f95711864af1828e0e394793e08f79e17d9af11d9b085eeb977a10b5df0845e68c218df2b2b81d4110c5998baa7e1be0bb911bead77d5b6d6b66ddb9a705728a551f6de39e79c338d1cb8ae828ff4f4b53e87168ff3c294b154d340b1eff4027c7532bedaea93b5d66a71a7a8a6fb2122b72dccd54104af4f02d7755fc555529a730e830593226301ec46d1efacac14a7ee18294ec7357814a05726a51d6863057ca4373836072b4c4b041f29496feae8e6e488828f14a7dfa73722fb99843abad7c78cb97fefbdd746109cbeeed32853a6847edf842897041a6c69f4d7da6df58d2f46f7f7e6d7de4b737cdcbf7f9fbe66cca52cb28e48e8f7060fa860c1408683042540c90226720cb09fe92743087d83073eea0efaba31a397c2ee8773074e420ab413d3b134240517fdf8edb720a7dfd76a7dad4fbffd3e272b950d20b8fd69ad9d71c46a872a7c00a230d594994974eb5514acc409e2fde78328c11fa47bcfdbe7333e9bdd3e7370b052ea130a0e4c3a85d9129fcdba83cf668cfd1856f0d793cf711c473291485be74de3a00d3dff9a10e72c0f7a9b5028e27e8aa1bb59401eda7cc661efa93f7e8d1c9efb8c5105af3894d474ef11dd50061a2c8cb50f835deb791a85474575280cc78a5350ca734586e5d70e577338ee399c76bcf79e55262e351c052e43b09cea99cc24669138164bd56e73328bc4e1e494c942cc981ccc524e4261ea17915580c923f8ec5807c34ef8007f0c736196b5b85547ad2f6f3dc05e37472d696fea810e3d1085e82f6a40976841e1de7b6fad57036554983a02b1cc98fa9513e13cf0e813c6acbceed414c698086a1ac14793b534654a51157cdff77da9944ee2743aed4f1f778e274ea5df45f8874b607c02284971680d138c180e7dccd4d1bd57ebd3495b792eaff57ddfcf19709ab37d195470910274b7af754f06159ceb758eba0db7d60df8f8b5fa6bca1c993b30933aaaaa16cc9b8e5d0025e37064cadc1f751118d730472d20d2e9d714745a030eba087c9a31144371010afa688fe0605533e6ca27b3e2e3d6bad2efd6eaf5b7d694b13fa3e7f0b2ec69a4245ce1e3f7792eed82af06f78123307b0d1d4eb8168a36ac8b58f8c03afd0facd3701b475df6bad8d345b7ae8ab7ed0bd80eed426ead76813e6ce7f9f9ddcfaef3849c63249eafc13f3d8bc4f31d88daa2e7b90f38bfd0000f34a6830d5aa287ab5cd0a0a436283103d5dd49cd6086bb0f38bd88e2042b93290db874f701a910ad28b0ed44075e30d3a2a48a406d43c8410717d77dc07985092350a207bc8185c875575c29affb8073c6450a60a2c7e3f13a0ff7d097a9c19397e801c314885c8e1b6ee4bd1f268f11f570c8eaad7e1b3d2fedb225ef31a69e0d3d2e8f931953733cd2c3f1569487f78307c40d9dbeb54bbb2c8c28ff74b5a89e98258d3daf551f712cd672534bd948c552fae87931e9a30ccfcbc70a13a6fe579aae510b55ecc219ed02a2ebba2ed4ae281ed8ab8e3c76ceedd1ae7b3d074cb1cb3a679d73ce9d7669570c180fc1e7b33fb3ced84f67ce0238317d4c4ff887c3cf5aab62b23f860e38beb02672be59c5b40c40a05a6b256de9bf7e7d52866631636a896a419fe69c6d8d25dfc929836753664e51492a9bf1b1929ddc17a6020da0a24f461dd5ef614330d4a9ac92a48cca2a496595ac64256bceac24a5426754564701d65eead97d83a3f0973d5f5e70f8aca34de9d3a7af71dcd6b90796158b6ac6c5bd30f3c36ecfd92eb403e77e84b83eced8de5bd3ca59d7a68b6f9b89c4144290816823643231022044ef85dc88411044cf9756cad03d6d5e96b46575e86fda80fcdb7319a4303b85cfbeb7cf332d689197f77451dba6b79f9e8805fddaaba0c3b96d4336303fa5af3afa3cf00a8008e7c2914661a54c992a6629fb50d256495b256d95b6cc3761f091aa349a1932b7bb991f5a1f676c857bb2a5115b4e98aad9b2a5952505a7082805828e609660eed09b0ee1a95e9832b44f716eadd150964d5c4f6c694b96169c92531dce39ced1d081ef3e723d434be51181c9326562d08163be370d1d68e8c0372aa6f774065f1759d49beaa332a935a7e26c22b54835d2eb7b2b989327f1ddb0c1cb5301481dc150479cd5993138b5548d5498fa948a09539fcc2724120c0c08529d2903d5d4fbe00609f848592c160d287ca43aaf2994c7b6b3811a04a263507ca43a3a9c3369e5af2bd43ea90eed676ad65ae390391f1cd458d5b1b5d65a6bada9bd39ffcfb7a66aaaa66a6a87786833a18ca0074c442123184b0b5149f743c491d42be73f441c4d394ac0c79a0a8136a1e7a0cd94228c50a8c47e55d9127f96285004210491e790711bd293f59ef42aae3e5f55585d479faf2aa74e6ece7b1b56cdf57d1aea889e8af03bafe837a4a78fb6c34d43063b954a8113c63ef5a0c24ff83386a2beb146a7e15853d06b7e1ae8e9a9de9e8233e0ded137d53e4e578f27d4ce3be7fde9fa5e7998ab8e6b0af42c1f24f4fc83809ee53d58f00f7d1096077d76817f887fe86bf8879e86354dfa7ca29f094b83f389ccc8cb3e0559f69da2920b569c4ad610b881b473e0eca02dac2b9d7a6935625535a5537f58ab632fc638e6a9220c2135a79dd3ce49a54fe1235e6dbcc2ab5ef16a8557788557339ce89415169973cef9055b6b53a7e584594b985c4722599bf357b7e6b6ef746275554b62f30e67d2feab51bc8edbb4adbd309b4c1a879f0dc707a9b8412e583dc0441b1d0af13821ea1f226aa0688ab8c3198797f02b56af070d0d251965aa28d4bf504c7b5f93e6f5b8de02865c269cce60828f269329e3bac576acad3fbf8bfbf8d876734331029d2c441b210058ed207a2f0454821d44cf77e1c877387e4d6c2b74b2ae6b5b3a325414ea7b60a9433bf071eef40c7e07615e24db1a71cf711fa75fcb5e1f5f8b03f000b7adbac3654b54f43c977f8331d8cfdff7952d62a1fbfb2a747bfff6776f200c7534b230da7be00f2b534608b384ab9830f595282182883e4e9d26b5491fa70e9d3137756457d614d668efd14c0ba3e9b75e03acab8e2ab86d0b34c2ff878e932bdd8660a0fa685b2693c9e4dd848e4c0ff071c248dfbdf72b89d27ba986d1e82252f66ccbf491944e65c1474dce46cccab33ccbb34c2fa537eb7c7b36bbc117d46e2e2938d064491229c4ad69daa6ddd5f984329f48218599029878dc5801dfb183f2e09c6b245c52dce21f71cc85877ff9b8af3977a8ad1409bfa139656ace99fe83a6cc7dfada2c69ead1680f7b3434fb3d2d678bf1cac2cc186a32c5f4113060d6f26b7b6fadb5d65a6b7dafa6cda9699aa6cd39a7c6699aa669dad4eed5eefd32de9acea96d5b0762eddebdfa40d149c9138a0ef8f88da64f6532c5c0d8300a8542a150282479a6da3e62b23ef5ee9d76842738c5240aaf6450c137eb6570cba93075cba9a33a02149cfec6aaa3ba91755491887ae023466daaba63dc90742375c70824b33a12d48bf98bd403a0521b926905bf5f67f4cbd2e115a3306a736d14804094524a29dd296d89441a8dfebf8f732b2566b2a52a8af33561a21a4dfb21e20645357b2aa144dc3f44b44ae4d460266e702aa1449c9e02be2ca78cee32bda652b494524751d04c198ddab29e520380f191a6521c2d3fc0e97b5f6ef937d0041db8f7dc03f9781d8d40be0ea33a22de4719bd858ba8078a2847bd9acfd30ff8d9e8001fbfad7b403d75130df5783caa755a1f81366ce0e308878e9771aeb44cc2479aead4f5991e2e4827a2ef7df75bf7221ad67861b7bd880be9f75896525a2a331911593d951e2ba73aa2e5cd0ddfedcf54da6ae2a2f58da852e5accbd0799eb7736d49e2f5a4dc4fa3078cb1d6a30ee0fbf89a4c26d38f30beba81a0bb7de21887183172ce39e76abb194670dcc79d73ce4264d2434e1921b4a03c5a6636063427a125fce980dbe005c5560137a2d79f548644af9f434573cb963289b5880118529cc411d70f3ee04e94767397dd4275581ecce00b51884eb212390e4ca1a2509fc318a7d042791460ea78f116138c8fdf8fd91636b841bfe2fbbe6fd50446b38d58ad563ba64a4ddb13b5d0fdf65ccd6fa2a5e9f3f9cc08028fd147d3ecb60d1e5abc1efcebfeb371031f81e467c1841bdebf21901880cc29dd8612985372d4d148073e8e7ad8a7e5bd1914d99002b4937a0933a63e88846aa55aa956ab1e291ca9f666a5ca38965c9555668903252dcb159d5514a6c07eb0a7bea2426f56aad5a5a114e6793c1e4d53b9404570e0e29273ce39e79dbd39ffbeffd188442a6524d94826fb3813569cab22cbdbb811477a6201a9482b91f1aaee15e2a6e0b6e8ed55cbdc2e70a0a5fb030a53b106447083d0c3cd55a6ae0195478af2783c5a6b16da7584808fb9a47bd753ce34c098c9bace279bc17ada01cfa1033e525708b4b15c20b1da4214e2f12207715614eecfb0011f7349631b8d693436230a3e665b6e6e3f5ad21021127a22f3676a8d0d803456662b75473de9952db5c470719675d99086a5e7083ede9927c6690f85a16f09452db87cc8e543a29a976ff9976f79172b7cac293baba32efc1f2286c09ad0b73cfd969677096d5ebee56d46f8d00f11638022fedf0f1163fc1091b3a5cb49f42cef828c770983b8bc8c67098328a97179191f4484175d548d16586a84415e7ec6d3088328a979f9191f648467f9297e9e7b0147a397613ae1875c82b4c386d8a2571bfd644b592766616a9ec94e80c2c95cea932d89e07933befe65d9128bc7237a192c3fe367ea74f92b03b42f22136ee0dd734446006b70808bf02e8f5fb3aa0dac54e7d7af427efd43ba05c76bd32968480785b607aa439bf242d7ee4d776b583e860821cbdbb026c67fa18d4b18e367ec071c6f8a2c1f504731baf04709280e8eaf4f7587d6b3eb1d3bbc536e4c7b291c69a28b197367b9d46182f2caea880817e55cce1810055598dd0e6193acb2e8d56e3163ea97f7e472975cf2922ebf448c0f06970595e624788ee9f0909a32fbeb0e1e66892534c3a1b9cca52de198e95311add23875c77cdd18b9339d6387e863e7b17c58a28f3ae5034e1ff58d5e69525b5aceea8e6bc49d79d65a5285aa91b47c08446d31f42c20111b4c62e8515b6cd1457afd1630971c65d128d625b386c09dcd6c29e7f2ce72f9f22e3a1c3f5441404b2fa10efd3800969a720997c4084fd05249c01206a08f77160af500fa7867b9b43037470b7ea9eb22d1c474253177e41d98061405035dad3acff3426fc55059baac3c4378c5d144399371b4a3f6298c863534fb4926f0201da9a424ea0e67a09d737befd5b3fd99292cc14aa176601c0d2b78d65a3ff812025ea3cf9795221d2311810827cd7882a3501fc5b8d3c734b4526251e8c06c0f1c38e0143565a810f48659a2499c18a1021e3c42f005d4918f3aaa2f93c96430c86437639c71ce18670f6fa94e89280ab02d3ae7fa9cb6b93a4ff1ed2c48de4be3d9fd4cedc2146cb5b6a73063927dc718e3cd0724128944229148a424f8ac53e324520e311daf23cd182f2485241269ca54da2273ac9d110426ad3aaa648eeaa68e484ef8485d1e2566d73670e0f5a9124c4c990b7cdd3e055dfaf45600751a56581d21e9de76617dd18e34656cf727e88a4375d4af391586491db570288f2a441d62c6d413f44a8a8cf091bac64a7698caf5e41585e45caeaab2252a4e58102cbd93f29cdcbbf46d915075cb3969b5d59c0b2ebc85a9d4e572912eeaaa29cd84ba8ae458223e5eaf17a65a53ad55372e578d81849698f8020bbe350e4ddb5abbdbb66d4d3e170782e0235ed5c7387593b5da71efbd65a50d0e22b3c8478d984c37abbd81d02ccdd22c9a44b362668c661d8102cdd2ac24569aa5599aa55930e041b37696f04b6bb57b6b11c03ad758c2bb1a4b38ef359670dad558c2731f778d25fc6509c71ffa53d80801dfa68cbee8135694bac3be58698ba43019e84c4663df94699e0ae38f90c3091fa70c6603dcbe6c7b3d361b3b70edf5d0c1049f3115701c34e0b38e56d0defeac1e0bf6453100d99e7b110bb36f5cb86de116b2a0fdf6d55b41b3b08573be5e5626b3d6daec7d36c04dee53d2cee6c084af9852abd46fa76e2ab5d6aa75db6fdc26a2e962b5e38ca862b12d04ce77e6d43026a7cc2747123e5292921b11542d32a3a4ce988335f57dc4392a9a199bf1234952461dd930ca4749ec71dbc66ddcb6711b6cabda14d68a998cbf6cadba3739c70002d75b75b3c2c9ae2aa8adb1033ee99cd43ae134ac473e9f8fa562084d4891045d04718a531c6bf479ed7da2db3d4d26fa32eaa8fe0f12a6a0388ee0e3f7c9c8de0c273cefc0648a59d9379c70fcf7b3d6379df3a864ceb6f5b474664600002000a3140000200c088583c180503c289aaf733e14800b687240805c3a9687439124c9a1140531c810480c008000000c31ca501195019cabc1bb09c79cd789056f9203ad59a3ac8b70c46a30a447ce99d9dbb71d269c6835b89406e65005a0623fc0c2e1e4f4f60c5e14afe651c890900f851013c17077cea3f18700407172c28c512623ec379e550b45757435117cd6f87f85e95ea391047972fa52af434cbdfa663984ea82ac01292e8f8a3147c4cacd2187b539fe2e828c9b0ac697fa952d8153d626909f3c41b424084349813d64a6c13a1ee05cf719e5c0e2418c35c79a4855cf61d76b598191e68c2629e743a4b471a478670d44a3316d382e526ed1df7b1deedaf1520a04b98491c7e09cc33b6de7ae11f8a6e7ff12da86300cd53cdef308413483735b133227f3d478c7df22b1dc0aa6401221f35f5a3c5d3239e0e5f8e402a04c5c2e8acde18357858a737d576b314cf4dba599e86406da5119d61d4b42df78d6e00bfe0d246202e4a93e2f1db2a41a77691ed3605b64f3bad2ae7c405c141c5d2738e3efcc7d873a525daf90152be2205251af73d8d09ad8705d2d921ca8937290ab24716fe036e13c8db3114172adeef976bd0305f873a24eb526a3cc80459900f78abe8d480bbecd1628fc1f02134ebf1172155671d87d032fb6015a4d845cb160f59d995f8f1a33044f9e12a50e000012283bbcbd146d9f7862a0e1137c48a692a9ac3d445ccd45be773b49f766c70ea4f1c0f888d195c443094c2defb387c5487d1c670a64152935c9e75c03d7d11829416e675b13469631cd6feb19cc30096ef52d961940dffc39a1119ca53d9a48e5ab6b52dc6427830999d4aa43404e3585dd88f30b7dfc58248b31050a307893c322de1162e629b04963d6379a1d5cd90ff0c721e869a0b2f271628d8de514960783e68583308a858aeb718e767cd5c142a65be21687818e1f2e848895f870e4869cda7c209861b0361533c4003630a080942d7b6bc60f4a22780971d00c2e117e1400d15d82aa446136a1182a44a1b7ec8930e2807c8ff2d07ba864e553f945c32cd40e87a9260f32b0e3ce4c6b390534d0688669f9ea734bb6d813a04a6dbdfdad2cacdfcfaf01986585c01dc0c5a50c801cc221cb19023c003a8a04e6d1f12cf3655b6330dced1a83eacea00351da705d7f616c441e8554c1056b84ad16dede116cc87d3d20c3a83a869ea705f9471886f1d1fcbf407786ddc50d2f2d47c24c079b21d76c4b54cdbeeeb537bb0684d90736c5f8ce26b10c292b1e6c9f87f7e4844ff7094beeb675f35f75bb87f3ab92aa0e515e19531769b74152e811ef527d29f0411ddda10d427d5f15a16539569674f22312dedb42d5db87ea950144163f9e39a743cb3854fb4402901cc0ead83a42d01e52af228a2e4a8af08c11dd84f1b4fe08ade3052427a15c85cdad7430b6a6a98aef8faf594b76b2b5791eb2d0a1f5316e4b380b552f5d1b3e27e75726774f076052d7a280cba39d06652b43876674d3e9419036741b4eeafd6803108cf0a102951617dcaad6ba6642e75809eb03f9b5b112c93447f5e4d7ebdf2c137b9470978c1f3bb3eca32c4f645634d4381d5fc26f7539cbe60dcbbd4ba85056929b5c57b29ae8854010de77062cf61d984124a77e10bbc3b93f8364fee6e949c22740457d116d5bd9067568b328265c81b6ef01f3b613abd597ede790cdaac896e979d8872da0e662230cb415b917c2b5d64af5e1bc7b1ea450b8f726e2d24fdfbf0f9f5081c013ea43ba569c8da274d33d07461811bd0a0c3271bdb2c61743a765c97e9e2d76815973463683fa8bf7fc29e895ffaba13d7367a67a9977451fae6dc9974b4216a8cbce8c1adb2c248049f7471b9e9691053586aeb3f08babbb96b25a5ccead731c70245104b21aab62942ab445b9ba8d6b5ab050f33bcee9d9189c3ba7cdacb93e89f101713ddb1ac8a319d9954e245b946079fa6471c141d57cd2e3bdbb409b4fe2819ed3dddfc45308480a5733ee128eca0729262cab89bfb540d8e3df0338cecb9a049512d96fbcff258e2c40faa400337da9d95d12959f250df27d019113f3d232e41496372aa008b60385fce178c9d0d3f159a20c5dfaf21b09cd01002def8dd0c3d63d14e7191bd5a219223a0dfe299b2c0d442c4718718d27f18a1fbe8ff346809737d923669f081ad513fbf5e732ed6a9078a57c52921c9d501c8168e00d80ece63f4a428a27b0dc18a18f2ef14d84e6aa754c6b36db5c66680a3318190ea6550fed154f89b0855f246a41ca749aa85cca838fa81d8c051d7c847b2f0fac118a787969c8da08197ca13f60c416db386faa5a40919d0c5f9f5d4ca24d0464452c9a2ef2c6a604da7e6e57e09839831ae3287730cc4355c19b6dc449a26c873d83fa446defcc9c844919adab189598fe376bc49b31175c8a06d5000663c5f9bf903febbdfd56bda4054b388713c5bf2b7127a3c4ed9711c9182e892108857be8a2f0c68daba38976b807828240213fa197b783b366540df1dcff02129ec995eca16e85175144dd18c787c75577222793f0793de92a861d2203158a33bda1352df299533f8b7d6beeb7f1db1c789557c1e28008bad5f12a6a504dda7b63d58b5810bcb75c2546f2de9f370b055f3def3594b5d548a42fa13a9af06253255707001f1b556cf3fc69871d1edeeec342f5b85edd627268a8a8f0a6ac4afbfc1bb18751ec015432adf733df7f8506416191f5fc435f92c30a3e053062bf12f840353e767dfd925aeee1a8fd68223adba0286015d3f190d5965145bd6e746ba2c6b5a6f34648bf1d9f9dc3f63b63074c2ffbfc6e5554b566d247a4b01a3b279fed4ac00e3bfa7706ab4b2804b3581c5217e4e008939c943f9feff68faf1fae33ee5eb49b6598efde63f3dd12baac697115d3269ff6f926cc3cc8c993a9278e42c700a57866272f19a9478d016479af3cb8bd38523e93cea4a64ef0746330267b8e505103925cd0bbf7e8e0a5c5ecd8906061d4edf29932bb71cc38cb82eada8cdb6daca01b10f39e5e3a6fe52b59ceee150e78c6c75880e2b70713ce1b3bc58a2cfb26a7b1c2f34612c35abc87435a6e749bde532ace4f3b11d3f5bf0509aa12aa6e362f9faa49a9e7354e5cbcc3a804dd7487f66369b03526e20da141c9e1dbc11cbe0baa74d924464fc3c55a17dfd44e535695db25f0dbd6091c0a718211b11cdcebf6c8d68d989c834d36707a5188f636cc29b86cce7d55cb2fff1e7c6535dca80fbe1e4a2096c7d1f4925a2281a16eb26c033ea0ecb44d1c472765ef051f1062fc38092f031fe869d01b1e29b610f8a0d188a43b70901e6b40b59b9f67da257efb08457b619e9aeea84200c8d05b534c5b1e91b766f662163130f30ad13c4e2f15b60381338b25fed84f362cc7373e73f4e33d2062da0e14bc43bb48ebdb36bbe1808a53df952b513c41a891ada49faf3b5d6138d3ed3ebd00117e994e732e036a4540120acaf4ed1d81d3e67ed24aa7f7f167ae812354b995de540c5a901632a3b00c268d664b0684be3760c460928f96e1b063920362b4bdf6d71d250f7a1719a9c2988a66949e42a1a59c0ab988fb0d94297435990696f1b4ff0b6be0a079f42531c1dd099c5ed5109a9f9c5b6b5ba86b5c8f94a9d49c38d980735724714055a6a3b188828a8575406c17d51336393425d00926743e36523f7a05c384b406d8a950048aa5a7a121b5c0db35b484d47bbd21603ed392245f45c667fe3a1f464daeae03906547442a78043a8be15c55c681201c58aa7de99fcdb416aa2acdc40beed01f06bdb47b89fe1b23cc0369e4d1f81b66cbfb3b997fda77dda3737dc4ca90116dc4f575bd7725608a1e0b53dadd815b19db8e0ea7370b5ee583245496fd366bd6f30f25799fb8e187c53e3326ca45e2c5025679f4cedd1ec83f29712a320cb0d4b0a0e4adc281b4e7d13d5ed6bff39554656c829d22ede5f4ed4648276409cf49ef2b344a8c41616c379dce419f920522131e55acd0df1f674f00d64ae82410312648406d44666288a0208fd89bac499835416a791ea1d0dbd8f9d56dfafba09503e84143d677173ebea61eb01a974dacbee61d782c9a0b32ee93c036490b45968e7db4eef66acadcbbe452cee90bbe58d5263a046fa6a88a5f0180abcbc7498b14bcd50e22574489fc373aedd7a4d2e5c6f4d0abcbae25589a22f62115dfc51fc1fec654a281ff043f0d09b5d3c238eefa959edaecb168a0a24f257ea0da85f1cd2245ef3e27c670d075fc5138815c0ce0746ddc22c27fc149e204df29494df0c03551eab765cd65afb7a063e52eb83888814fa05f9a560d34af290dc72bb688835f0363b702c7d6924753315cdfca3c8605d00d6dba944fb32e146fa8c7d82fcb81a8614cc4bf108a56a7d0d76c8a5a8f5d7bdb4ee7a9382f1f8c836d2ba8864a43e31d565f119db7a8904963ea6847b5ca62d93791bda15946b0c011bf5eb704803c656d6f4648e1689e191783f246be8e88919759b4b6cce95b0c592ea6c3fe23920309287057635dff34e13f2d354f25119908aab2a29734c0334d724643efc2183b772101112b04e00607018a768fad5e361d68be1ad551280005beb36d6768be410b5f76da03bd55c317e60397819cbb4c03b8fa9cded6cd45f8ada7792695aea7f8ffc0a0436c3e8bee8460472a60cd379dfc34fbd96499246e54b22910d1fae19a7e3a6f6d41cc277d7b0a7e6ecfb78efb1d117095700341353b8f3c7c0d88b942cbb2d4d38dcf630d896e40691c7f4069c04df83f9c2d3f7588a085720e552f20b066530b57afcca8fb50074a488a9490f25af3446af06c665067ff4a0c16f2f0976f527a3ab7b058407ee53c0d7f9ee392400973f295f230677d0f15e32e1256542e21308a78f832d171eaa57a0b9e8a12c857f1b16980ab0f9baddd33679b7a27ac2b349c70ea6bcb9c5a2ca8db597c3c997ccb9ac532e49ca5583880a32f7b21d6a1c712ef78d9d42a0ea73d863e21ac4b2b16c830cef97d6b3477439ede5616638f37ec89752235421c9cb3b7abdecd8400ae33578d46996f8f8e003c306d4ac60fd399d11a2cd2093dc9d9485d64f710139f3846b5d6821159126cfd896b35f853eaadbc8151cce6ca78fc47c96c9a117824766cf56d5bee6e48d1a30aa26451150dfa03ad1130c3fe50d545892cc3628258b3d7c0e51852bf3c82eb0e005e61c823b93f01271993395e3f3a247e262e4b2a3973d16d1dc7f1deab17cfd70513c9e38156653d26835b61d0c8d11b03912de92fad584ea8c3322624a5c203a682b6c9da1c6e2ba095e1cd974c9df1d29eede112891f12221a8f3b413cec060404e8a0c8d444679f4b0110435b42133e42103235965b59e97dd1d3c051dfacc0eb5a9198f23d36bc2c3c5fbe9f0536d538e7ebda66b784a16b3a99a016a4e286a3441b6227e61ebe31c3f2e5243f22b121f4b061c5c486550b10f6cbba637aed3167dc4f3f97330690b7bdedebb4204e168c9631683f17ba6d30e74a01918a8052eeb3584dd5b488d45a424729a7850765f012a49c2d265d9110c0fb95da5f81e74c3242e32d021e401dfbd243c32f1398ef0954d417833bdb68ce33a6a9c006aab4039bcede821eb7649b0abac969dd07f5816e13ce86e55d5cc79ee147b0e00a58516b31855f93650fbf679d3943e27bc386e7c42d59fc3026bf919e7362be2bfe7124eda77d178603d56508c0ebe6b31201368a0ce29e71c5cf2dffc322267896c2631f2c826d586482185484b6d170088a07d7f8c0e150467ed35d5afc97dd8a2818d75f56b0a29c2c040299c1e22101f46ceca62b140e86932a791a9b09c09b85a94f0ce1e6ec4208483b3b8ae70ec6f91c482742a6800184e7624af489219558bb9233440dd35f06fb7c92b47d5895df75d47ef7df5c55f4894f62ad123bd6eb467c76a9bcdf9218942c49f5fedf127cd327ff92fe24d99889b2661ef1a9c2b7d34314c5d9d1fb47264a479fb7ba638a13007d284627d8ed5537a54ff3696aef45a01f81605202144af65f545229aa6acad51027077ee923ce68b1d10ab3c9842a51c050f4f7d6eeb27ce0ecf5c3da9604ea28721af69ec6ca705152b068e952ae6c082f9c2cad2ce5f06b60aa5ab807c343c55e2e1b0e7a62ca60b004fdadb28693e8a65711e9f9188fcde1bc51f28414113f1a206cc0151fd74fdf4824105ce48905204c54c5b9642ba3169c02c84c6ec3986f0a9dc6561d36b0b638e21412814c2627a2a68b2a550c28da1018f3844c0fbe0be0c0e2b0e3d6515b1fa447d4b9e23402dd9900047cc45f569df9614cf1ad5f583f4b15bc9036c531988039b9e52c87d35130a7a79313315dcab3400f6b67e7d2b64e12fdb19281fe763af3e7fe25a552837c30d4ae9bf6f008ad3b2bfab26285d22c666f090b1c4512ef9946db317080242b6a32dbd9c5a7586c1690a175f31bc048e2a785fd61ee3e7aa14f674bdb26b3f583115b46f103aec26d7e308929ad963f3f3676f7a29d99a202ff1b0f0302dadb400eb2bda468e5f153634003e27e04f7f75bd627b44c637558d6d94370f59c670f1b068afa4b76ba28755214d4e74f39e1c39616d4ccf0e792bc00542b5c7bdfc60c605b68f56f9d17ec37811acb953994eb4fd597aa100cb57d7d81884a2e800d9696d302400c0b02e5663bcab806257e873e47477ef5c750c787eeaced4e6fc5897389d0e3d85eefd33403e05a05cd0f1ac75ff98e5bf6ae1bc87c524256d8b95ae430ab90433a7c301a14381d3bf8b0c62ccfe1b7af6b8466d9ae4ea74bdab52d9399c74ced51a17fc72f9760dde54f954761af6ed818eabf025b08d2e632fbe5b6e8e51c03a1012e76434015969a3aab33d7e5514a4a40748965ee78dad9ba168f8fb8442e14968deffb345a4d1c20d523615d2c20d5b9580c3c6b340369fd7c6e46d7bf8edb11fc5a50056018f50539f44a4a9152e78859d45c5516905607bbe8a80f857d8794ca0deceaf6ce1d7ec4072fc3d2093375d2fbfda23a915dc81f51fa93b4dd6bf7a055cd4cf593b4c8370fd5979a3585e9e1cb18d2ce4acc7ea1bbea4cff87399e84f3c44c49a7646f102723663ec9f94cb1c13e240e20b83dcd22d0da7b2f7822da2396adadb180ec4351916f57f905e6f83d49a044a4ce3d1511c8248ab141db53f00f0be0284d84034ab1cdc38a0603e35735becd2f59566f62be5bd5a318899fa38e93022e78e15a030eab8b42bab46c245a883977004cfc55f81431d514248aba5ad10d4d86a1cc2422ec9a64e59976a341d1556145781f68bf8916a0abb7db1269751911e0748a9215ee37af5b9530588a6b53534f3604cbb2d97f250b25821de35fbd118e7d49198d2536dd292d7e4e58b032e3b332bb7524720e668e222df87c49c69da891ddbeba746daf55850b2cefdf9f790a03e1014caa6190c6cf33873bb50f251f31b4960e9ca449b85339130e540a029d58c173b52af15d9f39d92b0b47cb85f3d707cb7bc030ac1ad4375fe7226701e3a99079acc0c3d66adc4aaa2b5e46d5bfcc6cd0321c8e435a7ac2000f1514a657414ff50a07db0a299d8b33a9ed8df27df341c8bff26f163134f874d579f63f053c92c12d3db2ef8ee728004e504cca5bc7c9909fe4376f6a5750ca57291039026e527b365748ed5968f707c1a9565effe0e0d5641cbb50eb0c6c808f5f56d2488b5e9f107a9edfa088092ddd445ba7816d8453392842c893cf9e459f45f22fe17c92130f30fa5f0f28deb44c01896f623e800f4c339a2424caa6af7f03644db8053ee4e056d7a78819a93bbd808a2e602e8584ab363a5c31813706079cd128bae2da7c0841b0048f56142348df9068c41f458d6bd30e4a81eaf1e3669b888dca48442c9998db5f7a1a8a18492ca21b330fc8cf2ebcd40b272c596f62f8dcc3f667e4a954b3f803f931bbea96f3deb015db8b44c2ba3fc5aec780903fb245a4e53b0f6d5f10f6ce11f87ba852f17e24ac8dd94c949010dd83481d4d825ad3ca81c7800fd898a198749221fa1d92a692bbc88f57df2c685dc3941da53cb836e3925f9b1331863f1c31e88f4f6022c92c4df7080a85a01eccdc42b7260b42b86a474ac57aa01df20e4172fa66aa8f00c2cc5d81dded9b5a6100d94db19866ea16d94e846d5081d2e7085374c6808609f83900398738ca8b5cfdc8be7f85640c8caa9479f5eb420920095c3e456c573612d30c7982c285aaea99efcc92dff9a02a55e5de286aae3bb10458af58ac07faaea8571ca3228a48c43e1ed435708931d690185d39306492cf5a92f831024d8b98b95ed6778ad87d1a339d342e4dbf2b453fb68f394f612d365714459996faa1c8501b434bb4c05eba7f219ce3ee5476eca2fafd1f125b0133800d306fa0a5b321685d90aeb65eea0d43e6b578ea6cb6b089856cf9a40e0c140e934c7c16a17a72442a7ade5a26bf24eb575fe7f0b494f13343204dc3231e2636f3f32cf3f3ec016c5e8e67d0370cc90a508c1a12b04b84ef29df7341f2789915f80b14f482070ef32d186e79176690c55d22ebd6b1f38d618018039f0143904d00e58b6194914addaa591834585fad4f415b57c2522c906165ae4d130af07148123d1a2a66cf992de6a8139965f74338cc0717c68a6f95c7d64a39de1bb3ba6fa4459b55de5e681da223ec9bfa001e731c239680e72aaec60f59b23ea2de9a62008748bd691ef71f6b8b0f7dba190d7e4a0754a2db24cb5c44aa899c306bc7cf84abc06d9c8e3a27d636362e0f765077b87d43adc7d8c8f0cd867b6ee33146922f84db8ed187a858bcc7b8d33b87db2a8d7a5917ced41d7a1cdf45523b768b70ad2d65a3d4026ce00d8d0425ab3c45b5e520f20745b8919ae11613b43ed26b42c1d913c26db05291608f8720478414852b0bdbff9519b930d45c8ffeb0fb2aebb7b63ef5ad105618c28b81646bf9f79582a2e90a63142f3bdc90a1d1c4b50424a51d99881aad394a21e7512bb3fdcbcdbd68bc8b3220145e0dd5e6295dbe0c732b91a5280c025c07083eb3da768636f141404b6f7cf5425318c87fbac182809845931949b7bee05425fdd7af4fb99d27ed2b43b1dc4eb8122c19f76a828f1985cb9bd1f0cb025f9030065ac799d062293e8164ec4e621afa53129a0d58369a45a05c1e15a07d8f9cb334d700afbd242a622f903049d410a71a4d09161bdc7b9f778d466668bcdbee39e76263a9f1281023d7530ae726b0fc6b60db524459a62f7577599000bd7a19eee8ffa3516281f0e6ecae2f78475621c31593a3987641bb908ce29279ba63a0bbf48c37abaab2992cf9e75faf6e1d31b1b6a2145efadbe5b2afeddbd0b642136261724a66ec0737fb30002df8d62196344ac1bc47aa191e8f67be6c3aac322abced6c04b40b20a7e664f2eca39a312f40c8a98f57bb989b4addd4cc4d4f9668964e73d3bd3f64544f31a9a2414b03bb73d3027745a3c1aacc2eee0196982ffe91384f12cd3d20934311741a3bd8cbcd3236ee22866f4d1a0feba788410be4a604daa932be5e4de1db09907fb00ba658fd62c6543864477b19109f34b3636d337bcf866de0f558a4645b40e39e03ca0e546466821de711b848b05ef4188fa7a1718937ff8f7e1c66b2baebd59fed23f8f2a8f4ac91d8dd4ffe2472c8eef9cbbadad6239ba3a90f41c9947410d88ccc02ddfd78dba3e2ffd2c4d3261bcc40f219526b94abc75a7d03f03974f03a296b25abf56d7df5583afa4c375b7a7bc817c7e736f997a7d54c7283456291b6dd84ae1dcd129a34a5fab2962aab008ce02dd3441381f59dce84abd357b99b7ac81d5cfb1d7ac640d87ec553cc2f70562868c8c0ea68ab8ecfc6e839e8d5f27c6a4dc869ce08e500d2189e5ec11ab94f34a658449ee7aac3c518e246058235e31ed404aafbf2ec388b0c9692a155f7371f4e9e1f04b105c17a53980110de11f520b840a0ac8e1bb7abca6a09ab71483c00df58943dd8a8d19388aa07af10a89ac8b4194c62b8685174a6e75c7aa1015658437faf040530a7b01a372f84131250ec5d8cc025ebd341d1bb99fbe012e4a112646e5c2c9914093cc0e26aa3c4b834060146bae96887052d1e346fd2b582ad578f326f8fc0a46d5f12c964f3ad11b8229fea1dc50e6c27dd54c8fff4c71827b119c481e92c0ff4010dbeda115695dc12b0ba8f3ac4387e3bf93717b738761ba407f13f2f6faa8b9fed956f575051850935a2b43569ddd2ce56c89cf6d5e6f73b1019202415c87274a887b3f72c8bc0fba3364d5f2517627bc9d1bbbd8b5513033d331ef62510678137d1741ae742ae0ecb0f4d3f9a32fbc553c88bb24c06a94b1d65c1819177f36da497235c3519f78548c8017650c53bbb8c1cb69cd553ada0b130c065e0d4289fd8cb4bcf155a95ef04debbfa54f5b9ecd657722d821274ae3a9abf45854a5a67315eb37429e1463ec5a983bb690c0666a57c61bc3053001ceb48643f758c8272e7b647d7377b9a76881f07b47047a2bafce09f25865a4a953aa797d4eca2d3a485819759c59866c39a3fddbc60e45b936f7562fee6266852b8446e407b6fc13e4fc60bd94fad290bacab790884ffbae472c8443b08aff302d19ef11be196ed740e2bd9a4fcf2cbf9c0191464c2671b2b7cf943de2d07d6c2b2d1aef897e6e4d6ee1dfeef5a0397b7ec779bbf021ca32abc3bef9f09e14212b18abfa32282b167e47d9d0f9b34393d698fc3379435a0ccdd04ea3bc483074fbe754a16e1eb051992efc744ead7c51600cee60c85e3739d995bb5aab4f38b68052ed7de91ca2d8821451df98097330e6a357aaff8dd640646f08de61cb2b0d7eab089b2cb035b91ec7fdc2012b27958d1f281d3e4ede26cef5b03942937792a5f671778673f9c582c7dc6697554e203f181d0aa22896e488b5595623784a65755f13d05571fef35db71f4100b4bc95fd15a30e8a8f82d343d197a02738e0a6ba36d2c5437a112c3f21aadad6811d08641fe6d2609051290fabc58472bbca253ae651a4ccfed673308a8d5343798941e07d8b4985dbbd484fa47cb72ca4d7f938faa12b0a5b025eeccf27632fea2a2864a9c58969069a31247a23a6e7b64d10b3a75dd798e75eb4b2c597117d04b54a9be554614a662a2adea9d988bcd770a684fb8ac9072caa94e99c7e779fb26108bb36bb46c18833e075ff760c80d87e5bffe3fb302164f2cbfca2be87d9a90eec4acaa4441fb36a4819fdd0933ebfc06be6c3e95341b9af549f4ecc2d5e186bd9abeec36fc3ebc3bd49b189da0ba6f3d725cc57f559a4f78ae629abe4099d87195e502247df521f079cfd69305106092f45a4ee8e205257f5b58a3cc8d76c9a6e43a7a510a0b007c857652a2bd545064d41b9857e5e7d59920da89c03e6c8e53c90d23a02ee29a4d84e20f03ea94c275ad16c4bad85fd02e8cfd2bf3aeac466ea80a18975463a79b728ebc87ba0b4690cefb5acc8c5c58f0bd044f7f35eae1503662fe24e0c5644484604e893fc87f0ea2a046a5ded233698a6f5cbb5433558355a4cb4c0599b4461f7a8223d886eee66d65c8fc2be5aeea14c6153d921084f5d4d0b5cc93797266451f19545f0448b4d062d81fba286b1daef345dd079b5833506166c86edcc21804192555947322f1b436b6fce06d7e1036ee3fa72f1318f2636428b4516e3b274e7dbba6eb0c279113f86caca6568b45b71a16ef97ac789edbc7822646b6264b21a37a067608e7f1073af9303dd4a23080c90dd8b70d785618ed5a9dac5504ce23e900f355a6e08a00ef1a1d3df5dbc91e6f9fb8c7ef847cb41bccca50eabf973f69180c636f1a9408ab12baba7c8116d6632314fe33e59e36c5338b7f7633ce8971530c6f7d68a82d925c24c5cf8222a163d70842f1399ef431041fd9ebc8df7328a17574eaab139f3f9856422c8c7403bc736d8ea5c5b6b4ee12905bd15664a99e2d925fa1bf009d4fcfa3f20b1517ee1eaf429fd4c2f100995f37cc324acc89d71756a802a023a06592c98dafef2def1801033f24aeaa78353abe4ec30da0c368791e80359088c0e0e60e126f01513d4666c8fe4b5d17aa3eeeb5d857b7507cf24e16badc92a64d789fa26ca70b51a3408912ba687d396525f78e38b159de81df7b11d9de73698ea95db309355c26a779a29be4c8711cc78344741fb23b4cdd1917911c043560493a59326652106f401166ebdb9c39d7e384887b8bd76d0c3938f082f98e3450d04a4b6197ab351f3bca83f49545962d9215cfcdb2d390875f7253f5ede667fe10f8ae85f30fa185220e05c9d807496c4b1da39197268b537a3a4ab43a8503fd28c04e185587fd9548c98e5018e1aa589ed9e1399a9e0798304edde338318b299f18389ede6ad25952de4d6f404ede41df1d597b8b9ee947c558ed698bbeb424bb76ae715f4959e09d33acb11e9014380f8859b894b682299df6d9f2877cf93518dc7921ea150d2788ad26f640cb46aee51a911b6246905aa3a81dcd23ec01be54a0a036bd019118a24f76b6ce63f5c5c2104ee00cd40ea76855a7e980ba3007f78049e3a458d07b737691b9988ac6403fd2adca49a1a1c8457d14285f011cc6bf3e957aa77faa1c8e6826f9246805238b78d8f732a822c0a746190de1cc83beff9e34f01b20d8c840d944914709189981d07a9ff41d4b66d3f15754b3b7fc6cf3869f513bec81d1b67b254548bb0b2d3e4112544500c251828c6799da2c340771e02576af8b35c12daf72a828d4a94fd8823997453457efe048295bd616239eb285c258917e3d068f3a2a2755c621f7087f25b37954f075bd04df240e07c827569bea50debbc0b80279178d68de753668de547d20e950fb0e5f191e0728e7d748f4e9aadfc4ca32b1d873f98073c858d20492986e6bf83f9c8300f3868c4befd01e9efb7becfdfa09d7d3f768f83095d5d0386173f8e5b6868899d49b9f15668a3607c5464962a10fdedb6672e6af9573afd079fce05745a0302b3ea076356f84aa51314eb051bd8b780d0f895fad54183fd6e5e824e241848c5bc73e325212e8d8e80274919935d8bd97ff11089489f35bb20340083bab3e461c184f7c9ebe88dc92674240422ea85ece51c0030dbf78af41320a7a50f2cfc6c327caf68f75995eacf7a495be225fb7dd6acc6a3275d5ad385247703df595c1cd015e311fc1a9ebef6fb211a55ece646fc5fa8448d1ad7aaaadddfad2ce37bd13c6357c47dfc7a5c3357f74921ecb671ed5af3d6a86efe10f3ae44f07509c41a67c85d0a750941fd0abe1e7de49f4c42ae21e625f980290823f3a8912a3c4b1176a79ee2cdc41316908da32871cb3450667a8fcd99b2e7855d3bb7d1c9645dc68421760f71e9f74997c52530ca7ae3d5187b673b0ab725447837acd0a3195b51de626a27296b606ae8cafcfe0a57ab8a75d8fa96d4f2bf8fba074971e63d96dd359da2ed439dedf960ac02d1ee2a4a5088a73fb502d3617556a1a7ad11a85131480f4ca76cd3ea480225d1ef97625e370ae4df9d00956ea4bf1d5b32cb37a241d53949e22cfd9d1981e5799204f9c104614b561c9faa24cee688365b60b662df7821acc80e4824067f34129560c690e85e4b51a0ef2c4b30bcc8f949ee326ae84c38a2fc13184840317a8a5bd144db2d701b4c85dcd01e4b010b0e0e707bce76b2fbaaad1df162e870ee0bf5bd8ae55d316c996246aa8888462f1d335639210622e00ee163b2f85230409517006f17c71d577a91ade85f3e999ba48783a3fd329bd31d8f79cd572eab63f717ca97ae0d140228a3e732301d44e0f39f20b90cec76c378785d7682a1646f33959306d05e5ef42200d94750dd1d41e80ef1569c95352dd00a12b919bbafd43333d9a9f296a384f43675ad617eaeccdda12c3027e52138402a27dad9e6cf6e277d30de4723e951275f5219d2fde3ad67ff33fb5c0bae49a15c1e04599afa4b819c5d715731e7a2c7bc6f60e3d800f19dcf2e0b428350a0f6126dcbd874b328e58974489f22b8db688c32a334ba785841fbb01ca762120b8b03bc8418c7ed2a1d433a920a2a98b68fd991d72f01b6a4d7b4b2fa234ce798cdc1a1784db392529a01726d37e5c844337571ec09557d704a0aa3bda02a76bec69491056f0b915ace57d9d8959523b9606c3f1e0f3ed7c16e3cfe92e29c450dc528c41cc76fd6264c1743e825a2309c7e2616e8b8cc218cbeef538f7f774afcab01d61a61807a34cf600698737cb85299a8bb59230b221fd45dc3be6058d81252aac3b12a7905aa70ea439e84779cc8b2413746b2718aa4b0a65051bade844bb70b1d041eee6bd46ed7ccc4c528a808444a11884ae6242748585ad5c94a37fb640670cbf6a1419cbf2740f46cd6094cfe8bc3e47a1d86be1def0b70287796f494d6775be2a768711d31f60d75f6d9a5a060d2671c3c1d7bd31e486c3e25a2f12e254a01aa1f9a186379bb95db562f27d5a78e01b0ac8cfb137d8d559733c93276cafb93bd18a44670bf4026bdbdcc29c3951b2b4cea3b7202fd974214b6baa8a47b50fb2b8a1044e8b64fdb72e4a7d287eed020a503f424b5072d709bd8900bb14c5df53e5fff2f09fb6d191465a0f0159e8cf6c2de04a7bb4f91e22f39dfe78569160da1d08a8ee0a91e5a9bac312729e14e6abd410f9161f513020ff45b8062974000d86d5ebe49d9caa04902ef8059f6b7ae509ccd0cd14727a266f52a6b4dc207f40b25d06b561c4e6cddfdd9803ef170ab62685617ef968d4261eb95c760547d4dd08ac88a63d189c3306334ba9a0e052becb1d17c4f86a69035ee67ed8e788caa0696effeed7423ac3f11f51cf28ca4c3afd36ef84bced048df7452e96dc952d25655fbc4ba895d4531434647ab108f94e59d5a242cb81cd96ef84279803a431c10241897e70231a219b8a6cd4731bf72d50523e94d0a92403bba3d7e1917739b01d05aff550b6b089b8b849955c93cceb29b31f2983351f84653fe1b84d795732a08dc8f882250643379785b3c54f732452bd356cfabdc51d7de6f71b9b2ab3bc9e6846413cc48e347bc573025e8814638fad7ba6c76e9d7feb325b4f6adb47d84f3dedc539bfda7e96e822a1ebcac3294a5f29992949ea7f80e389dde233ee6eddb8e0f800594ede7f156ee3ef855bb27b5fd4fd9af05cb24b06e0f8d4cf468c33fa8bc64d46a829dcb195dac426ef3c76f41b4ded3203726587acd0e57e9f54fd2ac383cad20aa20ac3f39cbd21429f7adcc613031e7c843ef68e38f312f3c119919a53f298ce0774c7a8fb29f58a4f0139f310b2fe3c1db53560953a8c49ded0a702eae16eec3ad8806a440fa1a80a5e8a633c144e8c9c3367687f3a19c8088cff8b8bf64c60f41cc47810f1b3c800230219d3eff359b1af5cd67511d1da08949e9a8cd29c3776c9631e417b7e88ca0c01af10bed1e617b274416291d5d2f4fc24d8d0a177c988c5890adb1122b73301475001a74312a30d5e0ccf88da90d4b69f8be88728d0023adeca9065960946b2fe65ec6d911cac16c14434b47c63896d95b0fc78790688c6ff258bfc27786fac0d8b6ba2086bb674fe833ba196e74cac25060bfd8db4c4104ef2193de2a2248ab07f91bf69315c660bfed13e182d113b2a80fc5e487639ee5a19be9036d30b467b43ddeb388852f45893c768788a31f923bce036a7eda08293e054a14b8680575f181712a36123dff54c604c9c5a0ad7e4407358f7678f2d8fbfba0710c0ea45f83f69004caf3d386c28c2a0e39bc05452041f5ef4d698a5ab076ca8121bed01b943c7af1c844e8ed2448d5ed96f650dfdb1c70b1eb38527f0c41ac3e20caea0b97073a03d5b8e28537618d2bc69145c7a941a2b9f787222744f856439c3750f168f77790401dfb3701c7558da523af1bdaa13289075016be3bd8c12e1c3eca5068a3ca6feb7007a0060f8b83b750df32ac6891b05ab89163ea4dd8b0a3c4d5974fe791dbf6a4495808ce28c322ad0e9afdc4d44813c6ad48f18b50cc36363086aad6110d203581520b08bca7435b6e454c5db160760e260640f371af78acbf2ba3a95be60025a92f94dca9b86881b2452ae3777191c33b9c489905d029eb5e613fcdcc71fe1e651c45b5cb83cfb69f767a3f7b629646ebfde5dd46915f303b284dd70503a69bbb00b2eab9ffaa719b1ee30db2bedcc884e775c4b90e8c58f7ef8e3c0b492665d6bd191a95d54c7878e92de721e82bec3de5903d513ad51bea54e6457afad97c2ca829c281c97d37fe60739401b432cd97d285a0245c245c4743ca17b676575d955d61dd729ee3401c512bc4b686de02cd55facb38abcb4f317fe50dfb0705da71755cbdc3ba7c989dee24e1e44a9406322acc5aa97564e5652335f08270c17f68caaf01c0324ac892d224e3cdfba8301e49017e38249bb26cfcf5428b579d33653ab50a44cc5537f9495ca99dda75ac8ca5974dab538e92247b64e2d192957c211fda88bd871b95964b9d282d7d7727fd785bf5cdac6c4473732f3510fc33ac516615c6e1b0f328386f714aee5e5e539e4bd5df05a775260152ef6c595708f2442c6b72c9c6f1647bc60e51b906c17fb8849fb29bbf7878a2aa00a0d23256f03e532933a5e8e8304694f8ff4405b286694f3f835debe5d2fe3b2819d0a52fa924ce3f369181793aca51d15cc2d932c2c2adeb4c416dfb3089b8d244ab9740d4a8d2a5c5bc50a4bf71c1e14e120c5b30ad5d0fb341181b52953b67d9fc50ad7b2f1f199510d88e8a7517a41b6080b360840131d6bc9fffd4739090507cd4edead665ff275eb8ad11f2278c4dcfe4ef1fbe491074b146b681533717458a108058c15dbdcd413684c52bbb3138c7caad85d928965162f428eb59537d9954ecebe1e24611628305af907eba2a29f895138f64253c550aa2fcf41b88dbf556e0a54595f425feb597f31cb870ca46aa4c0b82d7c9cf4d33948b1b292875734e5469f4d4bb4a7d1744010e438ed57f5abc250711b945cc850bb591b63e1a8f1598ab832ca63fcf00acffa3020fc43ab785137feff22d98f31c0aaee495fa28de5d4876ef4d98970fb1870cba132b81753b74054bdb08c9fb85325efd7ff751d61d9b0e2536f01701e1322a4aa9e01c00821517e3e3ad0262c2d90f6bcddd7b9c23110ff93f5fed2ce345faf9b093c36b1e7419c9e241f4a6dd53066df76923326ca5f2a963cb91d885aa8030da7bc8497bfc1c2a0728608417aaceaf8410b5916aede8f6e16179af4729bf2c6a747d1f54ce04d3fb7f6a538acddd73478501a4b371c81b6d1a5f55f6dc477ca9dab56eee308ba9712d74839395761563fea2aeff298f1b34a57a1b0d32e065d7eca75631587a805b0df275b8b263e39a63c5f9a24cac358f813a81ba077b763beb4c577bb137c54b52c5042e26152427dd934389ba92657db6fff2fdf86533ccbc56a0d2ac712b034acf5b62b17043a787fbfe79fa5eadee7c5d23980411914326335aa615b84dbd41442093e104367305ce358d1801f9b8bc72e4eedfbf4693079ce6d99e52004cf00d25e79006a5bb61f0b0a2e0fbf038a134c4c26fe655dd4991da345c6a17f7532305665c11bd685716fa1f2640d607d801a258e7f59d13457617f80fa3e7f44b230b9491295786dc29dee4c4db00606f5585f2b960887408acdff2cb691a34878f4426144629518cc179ea35173405161f9bd556904870d6ca4a1e2a6450f654304b1f0f3239c52379b14af3c91743e0f3d0583513b9175a7d90545115a6f377a3b149fb7d31f4f8f380ee048a4148ad64981cb7e28dffe7cd5ad37e1f3ad69ccc27ef16baf1b5be48a39ad4892b7ae4747d63309bdc0937b591f0b1c95860f8b6e693afc4655bc57966e11888e5f6b3415b8571bdd0fff799ca1aecab9382abee907847a4d2f23951e8add10e5a25f526b959832520d66158cd41cf3dbb1fd8de2108c1a7a6e8b759236b9647beb240e39a803f267cd92ba0487e11ee9b5e94daa6002ce3ecccb8be6e3ecec6b1f96213d4b4e2e849add7fe0337e846ad8e2ce3515039dfe56a4abe6e45b1cda8c49d2f3fde0d1b22e80f934c5d3184baaf040760bb539320cf697b2b875a1e22cec4f14c3b4b367fb7cbe160d0f829dbd898eef4bc825f38c06c347411d03354aefe7d8b22e8c87eb0e5181542d04db09f7db538030839481a26ca10866654fa04a09706e580a24678132cba2172739fa8d4d2b089324b99ac282f786fa660aaa1346fe0972ebd510de75854ff6c446e6c42ba56d4fe3e059cbb0e33dc34a44c11b9d582b9fa7ebed792c035e5f68f88e9fe7af6db4db332555abaafe4453cd568d648f7dba508af82ae8b26c92552f80a07b0be8905a8a400d989e9861a0afab3932ead7997c5aa8e351adca49fb28f14d6f97b55e0bbe943716913dc250342c65f78818934ebf8b54cd60a7f499b2039f90a2b65060e2f1962636d86bca2bc63d8bc2218da40073e3db9e629ab6dd6cde2b93e27c2812a2a91e3c21c34d39987cc28fcc3b614612dbaa962a58664c3fbd156e44b5c8285f736c508e1b3e551e9827afa0d90d1a9b6a396336894be25a17d8df907809c662c75f23db7179b91e930d4f2830bb030842c9074d88bf8e1a5c724f2f732a187c151935040c852e1136958b52277766c20f61d3dd11734a936b0d56c445f315f8b764e2c1d4f9eedfa4005033ada7c7f84d1e7f22d66cb20f66bec89ddde30e34aa0048092e893fe072768b6aec9c3290e9af31e2a9890d4db6f5a680f8ffa35eb1b95058caefbefc3064399daedb6b391a858eeaca10a74f491817fe0a45489a9d96616bd1841eeae2b76020a3f120dec08e7db4a39127f314778804606d6890313f341d1a8c19323b1b40e32cd3d14a22ca229ca1004081737a5e08fa5fd2a3c5142e77dce13399e796b6836998e4ad6af82a86f2405e3c8b81afff9970b6638026f74af89799fcadf06175e398c57d91d6365464cdaaf9ecde8fa3ce4f2feaab3f2b31b1df1860c5a560f21d4df8ddf46d42ba573ce50542ad11eccdb5c280e888777f00e81c9a91f75ccc1fa75aee7badf8d29be00d36b467815222914a4e0d9924c34da880001184fa2b2fde4cc638ea62e81ad96de11942c9ca02adaf35be6aebdd16d8ab386d13a8e7b5cac25abe9407f451f9a0aca8c7c45b7dba74a6bb49dbe831d7c0174599c621c7aa15c68d4aca456baf33df589fd407cc8fca1c655a089dcd5ec0e94b6b3f1942ae2491b68272262eb02bdb6af120e0b1545284e06975fe49dc1c986490bc052e3043cb6dfdfd1daa5bdb1c6e375073e107838aa8b53c79ca75125c3b94ca35de68fb9e075c3243885d708a156fd96f434f952618aad78cbc7f8333f8737b51686987204cb03c1bc7cda3494669f3e50c8a210251d71dd7f8cc4c32b45b8a327173615e6575b13ad4db2e42e6ff42d46e0dff550eadaf9a86a02244e64b47a7471e5d3e672dba24662bdf5c56cd9b7bb0ed8bd04bd80be7c5878e2f48a35641c35658a5205f9a53f543b9748fcdb55d313a2429e6c29bbee2c942ea144985f60b595688a164dd80ffbb46e42928c10b9b42ee27bccc863a9428fd5a554594e69df39a9b18a1dcf8338afef91a1b10eeb3229bb0c6efce1787c76f712891fb2dc05619828b0705bcd8eb2ee2a60ad91bb980da500e4185dc7d241a6750856dc0be4cabf360a7edaa2add54b45b9c538273ba6a72aea7ea2283a968c20b8e0846260c8fb09ed81e76b494264b4f79a40aa1b6adf4f5aebfb5d4ceefa42c82cf7708f53c0a82442c2d1c739de6d258a2aab6b72fb21d5b3399c782b4432b5843c29df2162bd5855461eb679def39718a575cf8da672405216dcf9372d6b0cbf2d879951ac8206d20c7aa60f2e04b093b706ce346ce1ccafa3c2cb8ba01d7c04978bd955589ea0697d9f9c1864ab15eea0f5aea3ca59f1979568e01021fc5b06fc1bcfe260b7ebba5a343cef7976422d00b2b6d658f133fb687fef38e4e477f76dc2f850f921ef443f1a1b2598e3f7741deead531fb9618a45d59018c76a1a0d5d81275543b0b3d2f7e72761246104312be4f1176b4c173c064bac8afb9d2e97d1e72dcad36b61bedc9e356d890a23c5207216632b9c99860eb817e8e5a15b446e8c5ff62549b6126460086590f2ecf826e9de37f8c08d8e2d7a45ccd24f26956af44d3c7cb7f4b196b84aed952b905b25145dd0a65587056b1691e9065dc4cc70609db79f917e3573db2b0e203a0862acb69a6a4f429d2856a3b00f4ebe624d1378f8f031b5138a9fdc4993a273e4c3f0c68fcb52dc90d4869469ec9a028c7e007f146842155608497994d9eb2362813add94ec625015490539c259275a4389d71483ee688160682f14616ce17e51ad67cdfcda8dc2d09a551ff5a2eb8b0b2764689c9c817b0019209ab8b7c074f1f9de15da1b52d3ae441492e763a2eefa6e40da5f54bbe76843c20ed692cf6fcb6832e52547067d187409fbc058e540503b139f8c1ba1f0fbc8905d6ccbc0bfe08b5d71137211755f4b0868c8cd9e96ec777cd5555c5a994b89a4a92d5eb66e4053cd4c34a7b6ecb1f54daeb780f68ce0623e6381352837ef340c6c90204b77ab5ea3403ff6fa4c72eefb8359aa115010f4faefd6fc8207cb459f02d48cf21ead338d8d0e253597abc2650650b633b14d2895fc46ab4461919a4eee67b48bcae074ea10b3ff4eb8748473e5927df6700bdfdedd417df0cfb71aa5ecdc3825060fab3a2f940ed1918bcab7189849080870a33aa010d9d5d88b64700da39c61756abf43f440aee45e1b12d883336a59048c55d102a9d4897ff974f2d5c41ef3f7aaa24fffd872564c96d1e39ec279fa183c1c1fe6a4c29821b2c4debdf01b20c137f152f96c57012101ec5d6ca4980b59e626ff23b703e3e61291dae24befaccd92ba78725c4b6bb959fbaadffb51af5267e47748f502f9addf2896a752a56fa026d6041ebf8ee04c665be1269ad9085dfaa4f3c0a6573a20234f3024ff07e216cef358d86a4e7281863f0f7205e6c50a3efac602bca0ded81b7fdf2ec5f83c8b08236760ee993a29d61d0025bcd0b13f551e853ab651f6039b83e3b5873111f7fc58d773b46952ba011bc0ea08de2a76b8df8afeb7925371f32ad08b28bfd635c84034cb120e2339034c36278d4256c8b9a770be440919af0bbd3fb976a37d66474b75fb7826ff34d88030311aa88ed27bc996aa3d9fb4877f8884468cf58f0765a4f69ccf148ed6d0f0c6749a77c2814773d8460d48122c922a5815453a371d51b13aabab13c10326b8f00d0200aa70ab92f6e9992d6dfa80287fb07989b3550446caf5af40dfa2012c9bf3e6021811aea1dd308049da641472d750b17a0574039b9974cb5712b442530d0614339f22bca784c99bdcb81c822d71a86fc2729a50923a385459c58b8248238969c399ad595eabfe0a9d81919729493f453b57bfee056813cd6f472283a37fb3ea332129170ff86634d9d6d1283bf49ef410664d5b74ee3f90515b053ee095670be9a7977533d921a49635284414c8f54f813acd9f787eb888fc67bef318979ecb0da6173aae06c89663b87d7e1ee0e5658db21a73428b34867b6c32e99f1c8073679dcabd4f0b01fb26a15eba572a3e0cb1bd9f052fb0925822c47ee1f142b33669bbf71946165df504c0023cab0cba3b0179c216f10a32495fb6d47ed2515caf779ee5f368fca1766648f21439ae37e1897beb862fe5d7b396921ea7006d995cca3b3f4e32b3f9e72063afb74ceaf09c10d431a1710b8a457c9c4672a1deac86076dee177d6dfefbc50de6a39cbe63c01bdd4ad160e596c443a046d85875d20889cefbbf22e93693f77c1939af4c3145ad6413f759dbd0e12851d3c243be8cd06fdc531a178f5e7c49f81216a72cb8141457c02438f05cab66e9aaf602039c5d35d598214be544ed1a6b0f9e4409717a018ca89a0db262cca67b7edeb78fe3f61fa8ccd1e4fcbe8b06f60cbf6d24825802f5578299b1c59b7f85c6fc74b7b3285705aca33540d31be0b49a6be336d9a0bea357498afe630d9eed768524507ae8ef8e7f13a8c4e76e9f0322f58bd5bec62e42228166396ef2abb718bcf14ab510451c38dce7010694b6600c01ff3b8297c62c943fe599936dbf8b3dad21b38f5d23d5c32deefeaa4beeabdd96c25d3a0975782b10842708abc704a2e70cbdeabed664f60272e622e750411e405f2e9d9d536374111d6365e42e8c6e14e06260b9658dbfc4aa13f90a8e01d1a2491a2963fc9a57e1adf9baeadc9a7ada8fc87ef8486d6433c51d2dc756d8be1e81c7768d80504cdaa705f523d6b5b57e83a003c5f7ca27fa980d75c566e66286e1c875226556544a7de44e75a4604fe55662c6b52deedccfb95ad6d0393cf047b1b22055e32a817712b2d64176348b55af0ebc6cb57ec003a93822c35b935d8b26d6f9739559ac1c4e8828999fb65c328b8827e50b667ed1d91695ecbcb189d99ab750d597f4b3d130fd9b6a5aa31c1cbf0fd3d139de71b35a660671375f605878a9e1fcb1f67a792a56c5b3a107ce145edd0806d770ccdb60dea7a108c3c95b66d655d0e1dd8efd58d940cb1096bd627b94455cd0b45a4643026a392f0ed9dcf65b853ce11673ebc36ee3357940735c90f239711e6a008d26f5c511e1491afa68df6186ce53045c3a5d0c19287f14822461b897bda7175c72ac639cb7407afd76c9cb80e8c70ee960cca5117d152721495191e466076068bf2479be07c3bf464a3bd3bdf849807c13c5209e7d0aa600374810ea5bc5988d8377abdf72eb2748165aebbede94b49ecd0c1950ded6a6459d19968db5e21571a355935e864233456a785c6b7827f066cc2b87519efa4bc3bcc12f2e9ed4e51fbfb60d1f6b78f8761e0b23f0e2448c370043299f6ea840b2fd5793777a7193947b2d16ab19be4d168daf98227b67ea4a31e9059fe1ca70eb0480e23f9f01dc468522d0ef37109e73f0ae4ba2e2ac747af6cd5c07d76e3c7f3cb8e0b5eb688964ec66d661bff4ab3e90a98a458e6998fc171cf87a6bd0a1172ca0a6b0ae8d77ba9327d7a57021c5cf8c5d4b55d362f6f8d59804cdd88be79525eb9e0318e3e6e4880471025d71d706f2f9c42ee9fa6321479ca5f7fa5db945949c44425a10b6d1d7d095f04d1baa00bcc0573ff1125e625e04d654126561ce5711f70bd48a68b0631a875e201835294a4500a3de0ee79579849e9b2b0b079e631aab380b31b23a3063ebae07a6d4751d7817c972e85337c410df313417df67d95de425b9bd9c702e03a8325682726d1e3006975f5ec46e8d2ae2d1a2c0f973bde4e42974d9249d283d538c9cb0ecceb911177ae3ee92fadb0451754e6fde6f47c0a84e0f3bd0906a4021777b8ea40d38034a754399752790ca0d61d2dc4a1ca967db990c1083df1f230f7c70121b1c3cb826ab5cc728aff81a56a027aa7b6a8c2fbf9aa9629a44a295a3ddd208de0a14e7661de8ad3589e0ced207c04877e9fbe92f8b3a6b7a1422c68e7538fca57ba7d35144d97225ce0d7cd1a0be055e002c7a5e99cf796e468b16de8cd84e36967142071615e8d4f792b39f9bea0c88990235d177322f7661597512b86949a1eb940c3fc0003646546cde88185c9035cbd328c8d3e2a90d18f9f15a9fe1381788592d631cc8a2cbfb0ad26f41b988e0f8a3b88bc9cbd1179d0781eb46e57ad4b1301efe66d3c797ea0eee2ecab5b5728e1081aa3fc06db8e2fe0f22ff24bcd0cbbba872c38f445d8910b634d4856a6ed95f9e36442706fb07e137ada1ac11528ca0d7244cba017e88f82e51a22f86a702a2802ecf5143bd9ff2a2ffc66ed80bfbef47b532ce7592c169ea0d49e55fafd6bd7a53fa2e25dfb0481f38d5014d035cfc0da872707ef3cf1bf991c9f2e8be4851d769d0ff7118c146e2847a508d09ed9fa41ef73c4adb0b6dc44237d7aad5b6e2a8a2aa7e8accdb6e448044dd0b06baea1eab5a78c03bcca522f24ae0f1c4ad2203ce8fb475bfe40bf6cb4415f92b6b6a21b4a62fafdad28618757747950e12c42c76017010c74e5dca3c21dde1a8694942e60ff85a259dcca7fb7ce2cd4540f5537b3002b9ec21952247c804984ea99a00ddf544b835e5f039997e7bff9795b5f9a4aa437321c6a4aefa0b9d061a0274955ba19221dde23c3387304d82dbd407df41d13fcc8353fb410fa156b2e58c3b259b151460a3e24f4a52fcb566c4a3c678704b05d2e2f1b57d05a327b1990ef00f2de65c59ae8ea5ebc1ae5df6e2a3a4d6ea8b90a31e439952cdd0d2f7ad1ed5d292ec56016af588e2426b3109876ef6e4de4b6ade01652856591107df824a5b68828bf39e2ef9ad544910b1ddcc8f33e502a991eb988e4517f21774b7816a763beb52f344be13f0dfe042cf148ead3683e96c476850f6cd4c5fc896a6f17d313e427167038949c968b279141cbb738d4bfce09e506a0a34423dd172bd649fc8552cc8281c915de1152ebd6695f2349384fa6ac94467c8deb96ed96bc3454c1c2871dc236728e90811f5d74b1f552c516c6dcd0e143b486cb6910360ecf99b391c66c62379929c215c4e34818e74a26764526ae3123505ffc86b4aba945dacde021cb41499c9e8a944af71a432f0eaa7086942e3e20486ee940575840ede582e8adaf6d8a26be5a152327922a95476b15ee95d3117721b684dfddabfb8d48e4fd259020e1156737d279bebe303ea0b120c7b15e91deae47c8a433a55e8975368dbe4eca06e4412de107c8ae91ceabf5158262c864b301b5b7ad3a4c7e8d38ad088e64db8c0ef4ee3c43547f3aae4bdd6cc68a43881033dc70208cf41e3c07f514e0d3613620a5b63450d868b92e896bea811d52f5401950fefe6f5a059c1a64e047cc2cf00939684e71de72db555b1944d4118cef35e8e308e945cd3306a63f6f240aaedfab1e45e2ee220ad7aab1ad6b337638d9f7105a6e89ce1e69e43c28b4842747df4c68c644ac42a05e6a0d2935a0ed65141f48a193497714ca7656b4a1df89b0a0a2ba4a27bc22e7e1842640c9b32e00b5c2cbf7f1afd4340e613ba4ac59548319c8a1bfba0beb546d9097d93b885434d8dc492c1d6ac0e6d7be8edfc2e4dc576628bd74db10f35056d5ee4ef62c1d7d9793d1e4bce966fb6fbf4d501ede69281fd0e892388b1fcefb935875e815c0830e1614f7888f95cc3abe3e8fd563720b69953a9e32ee113efd72bfa61155bee210cd4dddecb998eb2687a86c15ec47b6fda154ea88c7e2d5340c9776af147595f77d94a20fed7c9c0101d434c2b9a178bb7f1b2858d874823a15ff3809e32c3a52ec7944fd6a2e276286f4a1bf29e172dbea12c84e82193b264072dba696804dadada59d1e4986b22f05c95bd88110990dc6ec5ea09b1c7cd5db0bdc725869a4efa42d020553683a2bbc415c57669057fd391c74b9f0a92513c01bd4b40ddab8b9564139bb348db3afa59adc89f90c35a960706bfa0b75b407363993de2df042545c42221c2f0683178416ad4f86ed22316cb2c00b835468c0e36329770839ba100bf05f323d631cabbcfb65250e6af067f538960e9f114b0f5b5db41adc1c4ee7a665699f6d7aab5f207a0f840160ad4713dbfc90bada129a8d31985ebba6d6d222d946f34a6de02a8f1a4032106bf1e06142d458efbcb52842b6ad622e230ad1799763e2b9bb2586f00244e8dbb0cc17201430955b482f3f47489917f2389e711d8459befc52bdaf5db4e74014e60a3d89906dfa30e8c153d4ffb145c5f7d4e3c60603839a08e3d303355f0e2f24b032f41ca99c3debafe805271808bdd512a078e4060d3f681641ef04a61bbe92d723ee098292d9be479ade0957a10430087d056276826ba2eaaff6e7695488cbabd07d1108159d05a531523144139c71ba159ab7b0965e2e80efdd83dc6e6a6700ea83526c8e64986baa44f6d16b056e598d0351fd53e584e9a47553f5eb0857612b4c043eaa35774cae5740eedaf338ee688fd0717610b7ed8757c3c351dea861e313c400ba5a589a4378f58b25f01b34b1f140d86a03d1fb2f501ed6d9ab4eead03aba71fcb1f5d0f913bba776edf8e29511a5f1285227786802de4005b29aed83d671f5d786f3690906f03efd283b6544830c703b0fa79427289f8d46a117c14a0885c02cbf5442637d09ccdab447ad07107a0b00b11a1be30f7ba15a43b9d6f5db88611dd71de6f79cf95dd17c13e36ca0e790cebdcaf5b44bf5369a2b04e63cad4d2c5526027aa8c24ecf8629ec616bcd56befde8b31095de91a05b7798f8c2651690697c23e2c9b3733f06d702d5505ddfb1af5f859a208c22e926e6b30ba69dc4dd9831fabdfca1ff37e1ab6ccee6c06ac1f7c1f463c0d22fff9c86ee9a4030210e825c4b829a1bfcc60e8fb43b58ec10fd9158d7546c5e62b19dfc798d2cc54f089cb94f6db80d1ac360a53b41046b0c93cc635068db6fc1b7236e952fd638df64d008c9f7745afb2ee7634e4d614e4d2f494c89726a410a0793fb42fbe3e4b5b694d5720a271859753300aebc17488875ac11e18301777e758b89915043dde24ce2e5682f68731dbdb49db0b90fb49a5972fd75c726a23c8932a47da0f518faa88327e8cd9f602c4967ff4e24a4b3826b82702113d730048c112eb87e4e69bf04402eba68d5d67929aba2ea9788246883ad32df2015b7d351a9ed6be3007ab2fc7e89f58a9088ded987191c6f0de2e81537afe1fc9f415e08d1dfdf065a6083bf44906922e8daf360ed8ea72edcbf55d4e66fcbd9e69774d600946ae7717f8a8a1e22317ea5ef04ce094050a188318056045ca1d655c27a9a782e094f317fc655edf87a6e8ac0261ad194d7a56573b5b4a4ffc513df64ac6243e2ddbe699fd5568d87d6761919f66f02f1f809942e706aa6d27e1d83f791e2ab4401979d6810bcbfd297f635d042375ff1c4fc0cc39bfbce12ca8c5599c3710e9803ca1d0731a4b41c31e3d150323ba023872a2e13d9e0efc7a3cce501291686de39f138cf7be2ed71790d6b2a7db9b0603069f9efed5d815241b2c065b94ea720083424593b3bae9d06fb5b91e9adff23b59700be4cdbffdc2ce6b76455e892943fa7f69a3f0d9069c84c66e6a4a21aa04e7941a754cf6339fffbe4f2d4626d7e09e05c4046f32ff05ec8d963cbe2efde1a0bb740650b3b6d4362533dd22c92d5a7c1eac1127f2805ee9d574bd277e022e1a6708ac64a67cb028ac1d0e2f45bb2d18793e77612eeb07c1f07cf50fc66735ccfc1f31b6e5fc3bfcdd437e416fea917b2990b6edfb5e291b38d14bb58060a7dc4ab3088bd48b688f548e4e049b41f2be10f7fc40449689c5592b1c38cb33ed0f01b60b66a94af276010c48c5634201fe3d5f44f02871de745a07baa320031f869fc7c97cbc62399d446d537094e198efb05e2724281d4229df5d595e1b03f80fb13c478ca3ef4d6175286f3be3d59d17dd370c49d9ab87fc68a0cf503ead086935b20503ae21c0a33bb97958e0ff2a4b27582ae57fcac616b7a60469b78dff062ada3db28aab6a8dae204222cb12015a000044b81004aabdc959bb2d99ce70ae7cbd287f4756335ae8bbd7c5f7e6d408df675e57bb97665f7962949192c096e09be085f6454aa4442b164940c52789151a8b23e41ad0000f53852a80f9e8aa80fb08f8f4f9e419549ba3c632a53a64c9e9929ab2c45da4c9236e3206b2cc7cc939f7a102506493d989ac1f1549cc171fac142443ebd6ae6f4aad3a9ac516826c90aa53ccd9cc8a7e2899c8952a443c6a752250e9989529443c66e738ab4194556a01f4360fca89f79f02406997970269542d5ae904136bd4a846c7a95380455bbe28b6c2a31cd28b22ef1c084512815152d8cc8a557b572e955e21015152da8e492cd33a4cd27928536fd3b207f0c814ba0490c821fc4255c9aa919424c12592c952a7148cd106290c862129a4d486e882551fc241dbe4a1c6293058c12e4b03cd2a6db8c499b4da49136fd6d90a218a4f460292c85187c5508be0a9c00cde2ce0a0c415392ce2a5055c46691143f0c1f0c49a4528ea21ca4e4ef55a4ef55df5702a122f9c3e6237de253f113756841658b7cbf12c998efabc4213ab4a0a245be3687a4cd20d9fa41bae153f18603e8214b18d9bb259254f606d0431630b2e7953c68fe72d478d7f34022954a1c82803265cad84c226dfec8b14d7f1af2c710d8fe77edb524aa05152d8cc8ddabc2dc6941450b2ab94b8560f725e95c42f5f1f1f121d293bb328967ee55e2105aa64c993299bba4cd9507f964006ce011c0715647a0f53acd59c12c520729840aee4af0defbfe031f0c3f145f2c7dc9f426fcf8f4a7b396a84795503ff5a9f24c7dfd9e8cfa9e3cf33df87bb2e97b72e97bb2f83d39fc9e0c7e4f267dcff764ef7bf2775c5229f73fe1e4364d64490cc126d983fcbd27ba2362d56f7ef35717a3ac7e77bfd5b253e176a3e1bcaee3dee36ac29aae86f50e63b158b1988a0642b784689a78f005ae5ffdab14325e5c506532994c269389a132158a1c2972c449534a458edcdcc9fcd56a99e62d82824709620b336027859dd488964255bc30d4bda56b6deb4eb5769d27334eb4d3967659276c0a4eb4931934a77eb74c147f5561a7d357d8a9d64ee2e944f357cb6427da8976a29db6b495969d68a75a9b2528b00727b21e59598bdf61b3ab09bf4e7360949639abc35a79fe196398b2bdfb07047766fef43ba8175f25561a9ae7317dcdcf98489e2a3ba2f83ca63ffda57925a7524915252a2562a924f5a8a7f95a9a30f3a747616687e6c5e7517d0d0aa8174b9ed4d3a8fc3c924fee918c33640d4fb2fb20c8e84ddbdaa88ffa46ba8fb394e81a085abe28f795dcdff509bcb2c9b4d9d5566bb3fefcfcfcfc7441dd600fd863193988720ca9a6a884544194d5d7fb4a3f252ffdaa519ad52520934fbb56dc0523260aeacf926de6cf1297b344e4a4d5c42cfd90f1122dab8228abdfaa825441d50798fb555070d85442fe32bd0ccb737c55d0ab825cec6eaaa0eea60a520585a251ed218a316735aaabb92833c52191c814696117a2d947863432dcd266adcda39bbfba925305f90bab825447dd195eba20dec45b77530575b7ee28954aa54a5590aa890a48f5a30a52fddc58013e5541aaa0dcaa2055500ea2992ed93003da4c2693c964b256cb3431a6d5ece188872a2786d4ba8b6458aae1d7528b0bc5b75f1d67226c8e81bbbb049f55169379f5d2ae15cdb15f87a5cc1bc16e0a4e2b0026ebc9d126bb8ef7f54abd4407153fbde4087b2f26eb51155365f446899bcb82b4f4955b0859f0d9b17685df32d27f5d0d4551dce896f662c2a55a4ba552ada552496f4a9c10e93bc2ca904c8612e30b5c7393d09b0e50567f5d8206c705f11582f857279f032a608157dcd3f70374dcab04fa74f65c2984ded0e0804f7af39b0a1c12e3388ee3381b67e3074f70f5d1514173684e052201e6a139de01235b4d006670dc78c3f6c5ec596b3da802753319102d163b629665c6bd10e3a1b503f5d1e2688e2de15322d76f551f3caab77e88d026bd397de43e798419a441a842d185ccccc1d4c867bdd523ce4601bab7bb76adb58ad0ad560d9f75564ba84978c9b6d6c546da366d4fe6c89e8c2d0966f287eefeb67d25d7d90d15e0b3ce663353173114c3dfc161f862c9139ec2c7f8bba413fe2e297cb1f426d39742532914c5c0a24e2896a1f7ddef923c04ad05ad0581c219c4605c8467a7b7d6e258acd2a016b50bb9eb19b96b98d10b5ab96811ffac4a9cf504f50a9e5981f1ec887e1d59cd9c158c95fa04969a654b77a9a4596c964f259ee1af3cab90a9ec2c9058964660e971a177c309ec660ed2237c39722d4f7724a6f590d4236aacca84c02a1c6993ce14e00021432803a8bb3bea1d86ba9d1acbc2d0f8a88e4a267b54f357a9b447b5aed6ce1ed19c52ae5d1da8f8fd9e8ce6749f43fa7ecf0634c7a85df50911a31199c90da88745f594a0af5b03d08561cc2806fea2cab8b827c057a8572406ccab64fab3f36206a63fbb306a34e772a13939f09ed01c2b04a55f1eebc6d0973deab8a8a3958e32ea806ba0d683e17e81c5a836c8fdf6c85f15e8e8681c6bf698bfaa2c16eb237f551aedc86947652c08e4af7b812ed005fa482499bf4c992933651ecdd5be3da2d41d0798e3ba3fed51d791351fa94caa8c44aaa417f3a307253c194d0649da714d3c668f4adc4fd78eb81cd431943a0cd46ba8e5e99db55d67f1117f79cc63376e74ad878086866ab29aece8e8c81e5531a167037ad32f9253f09b4c5f32fdcf85e1d7c1bb81afc0889108fc24766b18ba300c8d19ca5a484f466f3c2c2acb5382b2fac518bfc8ed71512b1aafe0131c75603a23172a3da8f3a0720512e8fd065098a95da47710247d2417037ad33d682a35ec9220ed6aa92d4dc165a97b13e9b0eb2fae0bcaaa6fc64846185098fee2525059fee27ea0acfa5b8c5738c70226c62ab94ac9f56b351a9f37c1ccda1a34bcef0e70ffbf6a6bb5ffb4d9bd248ee370a0a0356bbf8b73e27c97f460188258daaca140fa815e771b7a9ea5d6526bfdab8305e8af3f12c791ace538ceafd7713623a4d875f9c537dc51da0dc58bb517d35910ee9de4826d693e8786cb3ce6b7dbed76bbddb2dc6eb7dbadde6e5f687a9df68008d7dc61b94fd4eeb6440041b044f31dcab5964a2408964a6009044b206845131aa6ba0f964aa552a9e4485219fcfbb795c127816f6b8900826089e4400bf974aac105f6c7a0bb1884045cc224ce0f20428814d9998091365168d3853e68041aca270eade278c1dfa612486a271dd42eef1f556f94d59f2acf8b2a716e38b3276e57caa0e5b3de54333333332ad53b4cc50d6153490c8f905969f309222cb79bcb505d438a98f66eeaa3973855748ef36c1d17db2e0f7fff0c7317be78ff4924cddf7be73ef3978579ef3412a9ef733da4de3f9249df91e798eb02baffbad346eede59f54f645b6957f7deb7f79e0522f5dcfe11dc10a2c0c11039b8f0420d5a10848b0d9a98d5b47831668c1fd21839fc0f37c612a029d35998322b5bc16bcbfea12fcdf1ca025c6b12d5396ef6841da10eb141a88cc1e4761a9c77475c0428a6a37d373790a921288cad0a0e14b0e9f002181e8480ca8091c10466041fc8c00315361f6663b6b8d560a6050b846e18411a6088c014fde062f85246f7654c080605a118060f5f6c75810f9c227c491826a0210756b49800003784e912c41819a858e20b111e951b8e89031142c404bb7858388ee3b896b3a8b5d6ba7b128ef31a61e0fad75ef29d45df23a95b6b6d795a2644448810f1ae73794f7fa75d1f480a2f0ea59c0e1021edfa4468d9161501a7cd9619387ccae29e4452ca3acdcc3de58ae06c7f1c899c3e45d2a2e6f998f6ffdd39bee842c755ebb5062048698ea5f45e7b693efdb992d66cbbdaea2b6802e47cb439d9da2497c1ca95baa4f4c63a977b6cad4adc2f407057c6f89d41c108680a70708cba285090c617194a548cbc3cf922831518b0dce04f680813c40f656420324157031b6e094e1156bc8a47abc029228a2f3b7c1dfb4a557c28d1fdc10a14a441060e88e04107d839669c2b26e0220a2f8ab818324107c50e0e069c22c6fad58ae314d1312e0a31aa78465c0fa735f67f1137d3591820ae0aecfbdb3249674a9b3a75eaee3bdc881021d22e2241ec1321d2aefaf48bf40bf4befb1e87ea0011428282b9df3285442233d0ac364203ec5f3f7be945e3c5788aa9338e18bf91b76da77c3e5830b097e92c8c0ee338030d9d83898d304b98e460528e69e4ae3efda976d91c4cec770c97510a239fb6a802d21c16d31b0fdba45d378ed45a6e013709c7d9f6527d683ad4ab91829ba3cbfab7bd681581693ec7eb759c1d6d3e73e4c6a158c2c827a54699de6e57728391fb7f2644eed799e59eddb4e4fedb3ee35733d3d9ad873c93e9ec26c3c885add5b9222e32575ab2946da53acdd91950968f048662199ae6ff385631de0d3f929172045b2d92697eff771c89c0def48acf1442301d33809d2d9c1218a3e64a2f4bb792d18e11e05f552b67a42183d52572704557f1440c9f2523237f1521cbc0253063705519a98cfc555219a98c4a462a236d1e71561ad88bf8ab64e4acfe92110a25a336bb488a283949e70ee09c04e7faef053e62c428f7ef8801d72f024385fd54a94fc9b820c5110cb016198023d792d61ef64b3810a586ba4942281bcdd1919b83e2a43ee7a45df6392123703eb9a01a943b2888c88bc8b0d56280bbffe7869e1ba239ca3cf7231444e977b64e4e8846fadcdd3defa315e9ac80d44a0eb0c4964c21e34662037c42b8c13e18fe02054d2c985a8594e20e4fcd108cf45f493180e96c0c992250c688c9fd44fa8bb1f3aa69050b6433cf1342cac10dbe4f4c0748606b726210cfa779b3741c59612472b5f3f15429594c1982f17ca5d742280290bc4102180f49469b00fe9f27eba00a969d5c6d363b41c8093acef2824faee6d19c5b8537cb523b9fa614b87abf8237cb3bb257eab4494ef9de268165edf2f181f57bb1761dd107f879d8577a593ab20b2c44a7cd1d3b64f168de8c12e91011dd98c2753ea1f00a15e0f36b6c80ed90ebe3936b75f788aa16d40c6a0624f379adb5d6e20097f9bc3da2a0401439431ab12d00bfa5b431de52a3b529fe5969268cf1e313c6278c319ec133a66e899197d213f14d2273e8844d367ad36f13e4af5369ba265b68830b5e8dd0652f4f4ef24c3e4db6b6d904511780e045ee07c146733ac0b125f7e3b8623374c388e60c7540441295371c44386638b2b46b8524378bdf8f83d62e0f0796324cbe92cf0eaee4be41039b13e47e9b1ee8eb944365f5fb20c4690812904076c2c1460cf069b2e50e7aa0ae9493ee2088e6809fe2819afd67075072eac96933a339dfdb08a239a4b70922d190fbad8ce670dfd9da55f2622492537e2eec248a24a2d203c0097cfa876ff2de392fb9e712a81752c8903d2f91908886502fa488217b7f4f5db8ad76d1c96ca716602f2d68b2996ce1835e78226db3daf348445dd013900f36b1769d27209b281f42e9039c826c844e40e129e5a45da69f3679a02e530dd4ec6f130ea927a69418f904d443f6def463aa810bfef269b281a477a3c884838d1e6c41f4a68c4d904d50f79537da7f859afb46fe4a2bf39c6b42a2e1e45ec025370cb50c0c979c8fb3b82649e415ea0b32bde14a2bbb31c3a74d50b509ca6d1364136412957a060d1410ea87d29617198ff8e8236da48d3c03c0a14b1a309e1606908213c0c26f811a91710556a58ea3d38cc058239a6365f5e7c7e8c7e8c7c8e8279c895fe2380e3c724da8b0f02f797325e2bc2781e0832f921d9619c27df72470df77a4e748523794c50afaea6c308a19c58c624631a3119ad09b36726b6d1806b9911ba180442c543e47b55aade6af71ac8db5b156ab8d5f3e47319f23b5d15c973673705cb8dae85dd09bfe2edcd6aed3bbc8fdeec56d160d3f7277f72e6e38d29cd2d94337bad4bad4aa8f9450abfbf1ef460d9f5cad5d14e48cba25adf287b3d58e70cd6778e083593d647f8aecc0c168338ef466269ff6a7b333d017c7a5f6c3d56a6d04bde9aa09f40592280c72d32e7ebc546f123e8904492118ae06724041f84fabb632017cd29f0096a4f2841f0373b55a773def7a9ee77924aec6d5543ea81c665dd7654121f6240af4c61f4441003ad4cabd83a9b51a75ee2507a08ca159bbba775b9bb9b3d22e8e2bbbe43e42d63dd12eeab536bbfd766b9343a1fa681f2a5554714b8051d04991fb4724eec5789c9dcae0b38b5d2221bfed781eefb776519b6bfc18029f7e4bc27d4bbb66ef59da455a55afb9cdc1b48b8e1d676d32b5628a1264ae93b5d91d5145f779b626532b562094391edf3a7ec79f2e63fde94440a3100eba9efa0f1ef51f3c8e273f657a54e967c43f858fc13791bef4bd783f7c90f45f3dca3783aaaf06c7d5d431f4e0863d1a914ceeb71dc7d5ca55ebd584a732d8967e6443abcdcd4dc9d302cc6f9ded7b60a00e9245ea2857f56f5825eb75fc0eeb757c7d1d3afea6e4d151763256d90363911446c52045ba580d14d8b9c028cc69331d248505c0087cfa2d6685dfa81f75e69f75f6c19f9586e3cf5a236badb73663fe627dfddad5d8af6ff2b0f9faa35d35beafabaf4fa4daf80a7ebdf1f533700449bb3af8fa2a2461a15d1e7c7d9ed29276fd4f937699be964e309476e5108a02802366acb40b84a1ca72b33c3bd907258e922ccf6e660442ea713cf9208d18847c904c91a90f4c3248112cd267547bf8fb93d020c1307e63302adbb2ff05999080b4b83fd5070907da83069a43d281def83b500866e0f303cafe9fcd5ff7623c8ef5b3657ffffea26691bfd057ed4259b6eaa36af9964187415ddcd360f4d2b67c62027fc7d1ea96366b8d6c9828f4c9a08d46fffa27ce9e422d5338cca920f645223dd96b7daf61bb2c13600860e07efb379ee0ae7f8307dc7fd625670f19c1da28ebb44eb773a9b7131fb4272670a5d19c2dedbab524a29452fa558b4802f7ab213605abd34db3421ee4418f717243a94ec8d20d6a1a51f5d1596a8f7eefa1d4ae4b534ca692fb69217f71b28f09651c24d4259ff688dc312b94a5fab0425822f2d959727f075870fdd30ac1a848a447241b4645126ce6002dd37164d8e60c0d905aa7b43bd5ddddab12b8dc4f57c85d6d0d50792613d129703ecaeaa753dc7b517ea2207dd92fdff5272a5b9cff1c6c2aa5ee8d1e70bdfd4345ddfab7db82f1f90c072468822447c66d26c089ed6b8980f383c8095883f20297c61333a06030d3d91330a0134f649083275b5c2a3097e9ec8996d9adeb3ece7aeb001142a42fa6c974268418d9661180673dfd3fb0de367380c0e7e546a8b4ab535baae514fb0eb3e5aa04faf56b7976a6a5b582ed0a3623a9b4ec3c6081c5ed2e024b3de0fab67a7d166191d11b6b33ed8a28a5f62bf704005ab470eed5ba5b263817707db75e2d13b87ebbdb2ab34c709472d6bbd28e0a4873544b3baff3bc2c5d9656b5defdbaee8ad9c72531c42a81c1aebb62067249743decb78762d75d3113bb9691b806cab7be675abe19f44226b0ff0dafbfb8ae23cd27715ade8923ecc8f67e24cec60886b4fab0365bad091c8c2b8dc882385006438721246147aea511247010afb4ec5e33a560747d19a917a82faed471d53fa918210cd587d7fded2b010d94d9988dfddb180d4dc9534e212383b5e04c24d1c40ed9988dd99825b23299ec88d43d087a1e27725fbff63e7ceb854a6a3ccf6a8766fcd5fb9b346f435f76867bc32a92e09567a5c97878a8a08981d578507634aea8d880a621573b347fe36f943c379ee606e906b9eae046b922916abe060744a7078740d96763fe02819ce57f2f908d81402010080402d918492c039fa0ec03037f436f65a9f79a57a964fefa88401928eb14ea23fa883ea2f323ca5e43da7c8a44aa212d2c45aa211d4622f5cf083b32a9f4686a901118620b169847d23c7392c56c50f6b719a77ce418924868480a1b493a92ab223523d923596160a57987d1943c2dc068ded2d4d0d08cefb0b1864626a37d3da856c588848484848484849c95e5b7c0f6753c7c9d6efbe1cf586997f7357fefc5781cb9b26c599e994f796984fef053686f40c3505fc3a3aa51d5d4d46a7e7c95ea6d54634d1916a437b4b6dbd27d4f484848484848280c49081fcf000bd11c6ca44a91ab9d544a8552a9bea6f4da0a7cd5d73c8a5ced8c8ffa1155aec0af01518f5209c94c0fc6dab542929b4fef0f0af90bf57d27527c14e8e303920dfab8d392d35209f44191347f024ba0859d4014e930106cb0e344d5e333a4499d600f2f4c752792da2a154aa5fa19d4cc0c6a464888c8d4a30d409ae3ac21642db516f471965b1f7f35cc6dbee66b4a9e9ab729794a40348102d682cfd0c40eb02af67b60270894fd5b2d1baf5ee2dee75e8cc7f11ff4b1b6497fb00b4db44cfa12e883f10cb0cd8ce6d015647fd087e69cb2631ca32c7ffc949e9ed2d338fe679a3b35abaff91e980db9dab1f9f1c792677c9bef81812bd26ba4dbc01aaec8d58e8d5fbd8dd26b2bef576fe34772b573e3c7bf51bacd59fe63b9f2de46697d9ce56f7f9ce55e6942c3c61fcb55e947a02dc32fe88381dad52b24b9197c7fd0c75fe3c3b8237ff9bd7eba2aa7fea33deafbcd552a8c6bbc69242d0c243d70b3473acc23c5b7b1fea965ffd13f376c910335ab7e0bdcafe31eb9814acb670bb29c02e94bdfe4596919fcb305592eedc8de9f3fb20d49612a92e6147982b9a2c8156c3ec37c82a41bb142ad61425269d9be484e193f24572081da3ce8e18f7f630cf6421b92c2ba1aab05956c411bb2611fe981249eef129f6cd3a10d69611f796bde6135254f0bb09ad7691bd261d4f3c6afac212dec2b6bc8865d9b77984dc9d3026c2c1d06faf8b4cbbb8650aa69a600ab124b28b1020b408ae9749a799f29ff95f4180116bfe52cf1c517d2ae8b31922319fc9344a6d0fdf7dd831d0982a4f2d371f169eec4b2a1b4496ad3fb9f80bf4b25fdf8bd545245094d0090c0dffbe77f82f73bd8e4eafbfa77fcfbbfef92a7cad77e3b772f4ddd5393e969cad5f718f7b7dae9a7214ddf247e2751ddafe4bb08a505d17a9d56bfbf922e8da8406d5e5267894fbf076d78abc77c4bf61c8c57eb25751ef323b8aeeb3ab11cf2955d596489e971f820899fc24cfea63fa11f974af0f79bca7e2534ef3f6bd3fb12d9596e7dd4ad3ad39f80fa4795279894e037950fab1d0db9eabaaedc493daae4c19f7a1e1a0aabdc9b3e02f653afd34e2a5bfe4a954adc9fa65c75dffd7845b3dac16f22fd31d96f225124751efc4a6a5e49aaac3ecef21efff834e5a73e88b1ac403e4f6a4a5c7aaab29554d9c16f7a254a705989fcac4241d0781ecae4910da54def4d640f39cbfbee2b895ae1e3e3e3e38215cade5332d9b39d6148640330f98aa1e53387e7c14eeb93bdafa4eef4287d24e463e5070ad02c68c8a3b46b556d6d7a69311ed7a46fa72fa9219fde8486be656f867c3a94ec793ea32cefef387a5dd73d0936773df3973784df7bd0c611de770d7cefdbd65eda4456186d17e83d8849b08a45681eace22a02a6c7a8efca1dd3e392a7c24ca8c7a4e96fcef2bc46dab2e73367792f420c9b1e3fcdab1e857a9adf413d8df75d598d9ce53daaec1f67799f2a4f9f19b907f3fc4dbfe36f2a573bfdb85c75a6dfc16f323d2e77508f5165eb6272f53dea7b602672f5e1df313dfeef71c953e52b77f0a3bac7cf63fa1ed8e9f37e158aef64da75f6ed23536d86df6a8bf7dea55d367f2d11b3c81e18effde662bcf723ebe3af0af33e14bfa6a2862cd9fbfebeefbb25f82692c270bbc22c4efb9ed4d33de94cd21d79f6e42e05f069eec852fc8e3c710b99f4a7a5a4f20403fe320095288208220ca3255e78132b248081133508511b0373772e87a226d9dddddd2d17b4052f7801d5229f3c8470011745432841440d447051148509292d2b95473e534232e4c6a248888b104604e951871660ba30a9f2023266e86162cb1442d8ae3831e30b8703172cc27a2a402d081c647f3c060144f6372bc5e92472d384c8a6dcdddd3469609a436df5bf188819003194fdaf18c4c7336ae035c18296f2030fb9ff1679b9c5a00c229c4842043698f1c30db2386a414c09583fe5807e48422ccdb10e258bec5060f0e48cbf6d858ccd8230729f727777e3581c3a13f2c4bf1ad1200cf269c3071e6e7cc0e2430bcc34405312b4562055680d2474b8d806294420b30108292c30b2a1490e7ee39adca0870e3285906d62d3a1d682cc6cb8c9143d0461c10f6d0c192d1840a63332b60851062dfc604cdf10c6bd95c9ec894bafbd5cf4e0e1a3499108c0b861071bb4742bdb1c6a7db3f3148a52da6754dae2a83b7e1d8b4d2233652f11111125f230345de0fa1d2e5328ea56c5cad47ab5d6ed69adb596e338ae6ba71cd7d1b28201a8a26556f7724c65fb1cb6d65a6b2dad443905fab4e46814998a2f689142924a2149dd1bc36c069862fb463ab184ff2e1718604ab10ad6da54b648b2fd94739dbd626de765c98bf3834c5f455f98fb4e94e202506aa3cfa22f1d1d7a9305c65dc782402a7b1e47a7d0a109a02ff0c1b2c6681528a8319a8344ee0bd4578d552af55583685de20aa554508a05ad415f707daf134b20b3579a43a23a35e6e30b7075afe4b06842c3462e5437b27d09948073f735c6597f557618a5020b2eae7c912d103a4d710548fab5288676c9c05ea6453454c9e78d626f160e8d99775b4f00d98b6f88c70475ad2b6be26486c89c170b01011943930108080819a3188e8280a001a425065768c1ddaceb82c34c67529eb84e48598226a50a0899ceaa88a20cef76ebeed6dddd6d8e3581663d380277efd9adab70a44da33a037de17cf988bfc6ebfed4b648c25dd98ee4ec77b633d2007dddf7770fa3017ae38fe3af5b9e95e5fe9d9f71d2298ebc15d8fa9f3b96f8b9d75a6b74a4ab4246968a5044c394dc37e4fe2b3ec164a657c218e5d3e68a83e3c457a10e055db2bff5287586235ad96da9faa9ecb48bdc41f62219d0c8fe4394fde78cbfd7fde949b3d0d10a2c5cb8ec2f64a75f16e6eeee14763305bd360c67b98e8507c5841d0b98e3bae7bed29705288b7bcec671dc8337bcdd57accffd68937b8efb191a3ee951500f412e080a1a476ed5559104ef57ddd72972c5923b285d15e2e8d107e8eb7bee59a039fddd9f98ba90b96ff203f4867b21fefa4a10d4fa42e6decbae3ca90b58a037dc631560afbcd4e4b8f7efba7b31eeba7751acf7d61fefe5388eab32db601324213029d3a2186af0518167322d8aa10bd704fe322d8a210b8f09c69916c5208517e3e3323ed4e02101060931488cf7e92df342bef753edeabfff34a7cbb73c91e430f1fdf386b7c44a7869160573c5348b2a41a659b4ff96039012048911039024645c00015962a6650619ad8a188054b1b5d220aae13a012283d22c9acf8b4938688621c668513184171b99ce8628734d400aa165b676b0ccec62031ce65f4910b2b5254f08605e3617d75adbb296479b66ff0f7a43bfd5f686b0025c9fdaca711ced4afbdcbd18734ebf922704303105b5dd729d77ef77edad1f09ec606ddafbdd7beff540230e46dff416ce8f4b5f46c42070f570dc70bb7bafcdc6dd7bef6d97ff2dbbd288b3b0e0fa46dab446aa8edb8cd86cb60bb30dd2607477e79c72eeeeee9d53af2b4b5aea68e0bc7b45606dc7536d57bb1304d9be735de7e58fa16fe97bcec201045293337120bb474dee1bec40f6daedf2a80976c0a9c93df53ed0aec46b575b826c8bb8186c8bf80b5bdb4118b86953dad4bd833070cd20c725b9997bfb780630fb289868b8e52cfbb50ceb2df2f543f8824d37d3519bab13c0d26cf9ab05abd682ab2129ac86dc5c6ee064218b257cf99629ac86a450ff2b7fdc52a74dfb344f6087ded80749234d00fb1c04e88dfd07d01eb6489bf6bb750481fd17e05f4b1c93e9af222d8ba44d6b3a32dd7634814fd32d5bda7577dd5c37d7d692213866b4668c7e6dd22fb359d5745285bca7c1cdf1a2349c175c1f1c5dd235218a209ff5a64a192fcc606082c30860fd1a6b781e9541be25c89ec7c48aecc5d0c4a341039fe6add86180cf9b6b98bb54ee9e86c9dddbae088659ee9640c9dd783367b770418ea36c8b5cb822dba217a4644b026bda8e656fe85e9a189f308420308f221f191a8d22236badad3dcad4b20f2bf869819414d8400614d8d9cad6bee9af1a60c698228b1dd5600798add91762ad0dd95e914512d986d95a6b6d8943f8824fd3acb332520690bb2f5e01115ed555a594e2115fcae351224584507a34c3639b674fbe658f25d423b5a8e7512f883c126d89803394fb7f504ae90a63dc5406b625b53f0a163f21d6893496e4137cdff77161aa4dea79a510b2452271c2558d26e19b4aef11f9783e8431f089851469f37b30c1dedf9ff1f8b0d0a6589e3d99fe19e610482934e1b459fab075a44d138bd1482344ec3ed448d620213327fca017e630fca73ea82bfc4e0c120ae9193c73c2b585858a4144a8a909e1cbac45e2b4a9fa7e16bcc334249076d17cea5134aa31639a2aab1314256a53062c1c75b3b21b427afaab9d1a5fc5fb1adf035b91ab22366f53f25498cdf7c0c4b72159a83eceea2791f5a736a941154a9b9dc5b23a216926913be02225f511b832a444355d4304d21c5d582bede23336d18c4c1730d4df86cfd0e892bdbb9bbae877a6648a94c1e85d6494bb3cb1181f1e44b89f0714f8c42bd84c7d6aed6e5e3d842ff8c446c823a82ff8cdcaa35d94479b3928ae7f6fa53b6dd623a591366bef68029f61bdf90bb8a06cbf921df7fddd9fcd9529f45bec858e777b18527b91b451ee9e025a8a23c3a976d970ac9d6ad76d93fe6943897bb971bcb7b4e5890400b4f1b3a8adeca5bbfb58dfebfe035ed779b7abf92d0c30674b7707000dbb3b67b91c9e839adfbdb3ebbcf2b4d97bb7ded18ec4d65a29ee7d106bddfdcbdc7f524a3ec4b0c12406940f8730a21438a4e1c3859f2c409c22ae8f3c3b830638d3d9195cf297e9ec0c1a1018f61391dab2964c604a733fa263a5bd1ff9ab6dceaa7f2faea4579abfbc095c7d7033f7f1d77da782deb8fb64e7aaa821fb73b3eae3fed41e1c1534e7d2406f1a8a7c92b82a3e9bcd5fdf171aa435a874edb645350bd5d0000000000003150020200c0c07042291502c1e69a2327e14800d7288487862369508a324c7611c858c2186204200010022023443b4158000ff69ec42ea38e690d2e044c09771405c4011f467ed583ea67afc5fa7aa6a316d5e9a1dd56cd1aaf1b3b609c825222205545447574be311a73f31bf4e05ee1657d85b386e41d3b00a23636a44e6fa2fa039e24c2673125ed7ad7d328de929c17bf295c09db757a2c79890e41428a6cd0e52ad43fa216b9a7394e7fbc2141f24640485ae806dcfb7fce7dcbe09a6e9aa59dbae52cc931de88dccb269f13d01ef387ca403d31fb643977960438bb517b61feb53340b00f295eb3270fa18d33f8f11c64bc4116767d750087301e98db1ac6d4633382414a2e84a7ee348e089908e6df2383bcbb9c33a6bc4070fefaf2948a7a1672139446e54003ddc2a5340b367ea09c2438a2ca20864c9209b7dbc8bb85e27cfa99e25c8d0abc6fab5b55a0743941122444c6a1bdf349a0e938a5765af780914ce2c5db8025232b71ffd1dd0ac775632fade2dd55129549b129d026ab5c6041005acfd090d752c24c4d56da5cadc13810436fd834c8ab93b6f2e8fb14283b98b729023410deeb901c023b03e3cf9a4d846dbf9c55a4af984d842893a492bada78daa4c294c9b67788d3f9dce807d24c5c6fedcdc8bd1e21e39ee404dff10742c2ff1d630ed625d27da535565cc0001a4b0245f44677d574163e562e150e7be59943cb302e07fa2a4efc54b8db53cf6986a850df30e37335b3b657c2835b3967f2060ce1e25106aa521541cc3814b188050b986806363df1fc5ea20c51005a52a31596b730f98c0cc1e4aed5bf2e5b19bdd87016826f32e56186320193535609acce401d97f64ad000b3d25ddb2c82d22d70d43be22e183e2069e2011ffb7b220b94ecffddffd19bfa5f8a595cf2b128dffd313b9ff8f9fda799f172012ce14c7ba6d8a33a9a53dc88c8cd69631ebe23c0e289667bb6070e32307e2a9f6165a6751101d7de9676ad68bfcc572445e5cab4bb37dadd63dec892e3f114406ca6b2a9f4b423fbdd351a0ce42edbfbc3ce3a9adf66800270fed0445f8babe092448b4f7a46b00ceffed2de727ddaf9732bed5c63783366e6a6a5494c8519ffffdc87f4a8449193576bafc52a71d86d5abe30bf100c92117248556d63145b8d5606f17164d1b51f00073c414f4ea151d206cf3deb5fc57af2febb8d4a6caf2a2d224b3413b3bdcb27fc7eb62c8eb14fb547925a9a305b0a70ca1a4c004949a5fb2b93e9114b0f5fe9230420d0da71822cddb48a10c7bd5490fdcf66197f1e71a92d95ca267b8d7cf209351a1bb251b13ef1772192e602e8859f2d594776d2ada51aa784aa86454f6d688c2cdf80858cb1429d03f947dee07d4b5f59c59fe29e56f1467dbee3ab96c25e23ced021b0de1fda24ee8ef1b2de94bfc0fbbd6461903d36538236cdc14000c2f26a98ba5c5af2859717a020ef114d0d276f682053e452d11e68f8890db8ee607b28e8f94c1acab0f75f60373db21c1f36e191403025709c3106d4895a84cad8104af3a155f9d706d422c4ae91ff3fe2c37826878154d8b4fd5d9302f2668b5567bfac5ca3d5c88e0e4109622df3e4d3c9a0a527e995df45fe1725ce2776c77061b08ed11865d1c0680ba9fe36aabbed77db764b8e5fa8d7315e309d8fb99ad48a646cf68f7822087d8bb2919f1f2c707c983fd950a3db7575083fe0485b6ecd21dd4187a2ae394495c4119eb16264c4d86c1b4dfecbfe986b90b895666ff65538547438c6717f49f2a4c0a4c2ac2dec675edd4e592905a79177534d32d35b72dd221944152a7f80558b11c81ea1cdac0a7ae513d3f74d684a1ce39dd8cb698f31e100944dd5064a6eba3a0073bef4c5bd733b535d0728b0767516119182573500615c1a1edb611f9fe0b9f77b7d1b058cd86065adc7d904e2306cd7f29e69298d9c17fb0919cd3ddee4c10d8cc452f35a3c2fdcc93b02806f1fb0e5702b1448d5357b7f18d661be55ec4d9e098d10f10c5abfa02558e33f1dbdd0b8b4243bb285b1b8cd0da321b830056c96d86acda626f4b1b5e6cf417d834ddf84eeb07a7ce8f3bc7d4ca8a521174b7f469853886bc0269ad1e9e6b7a9205501e2a970299570d37c8c19f382dd533e0893315a9bc122b577af75c500518a95cc0e10611ee09ba2ee657e62b91fbcc5bdffea348643f56e2e00585416c3fc14b24e2ec4056e16d594b64fd36477a739570b9af84188cdad176cf5954d99df8ce22655517811f19870af839cac8680086e78e14b42b4d3c0d1347882a8f1fd3cb1dda5638a0c6b7c10a2b7b1db9af30954bb1e703ae0393c866819f6ed5d1f073013e24cd6ef68cea42235bba7cb4d2869d143495deeffda556f56e58a2d8a9f96d377ea575e90d9e582b3ac035e900d63c0e6c5aa538923641f330e476e26eda339b25b7861d3fe9e15d5d550cadc8625c7d60f60fdad6f962a5a1bb139777fe9e17ad9f64a11d9a1295f10f96474363a6b417633594346085b1e56fc4e8c50f84af55cd9b7d78d5848381f8c1861d31c22558d34434c666a505bdf6eba7ba1daaa781b138de498846def6954ed57575da3594d2131bff6ff25407d2f2c75d02467646ba67d0f622bf9d8c13ede1d387aadcc225b8200a7c8b80c77ae784a030721c232a56cab4f3796dfb5e7be40b344cfcf77ff735a493bf9610a4f02b2e72b882a3bccf3cb8fd1deea961fa2783ad4c4033647447136359ab8506b76c31b86b41de7def0ca5bc15a40750a646af86bf82425c51b8de8614bec8d28f4bee9a9b9ed306449808080a3d22209054ab0123a4a344a9da581045c4c84b6130f87d8dba953dc3c7ba09697fb57d1ee37d9072b317be1ef93e7c085363c9f90dad90eed6ad46a7177a90d98d7b83ff02cb90ca00120bb51add79068df553e1f0315a4562ea346ca6b5532f14363d973e0a67819cd0076c825c6b38766a22f300f1245bb937c8fcc3debf446a8e02483b65238f46b081db06d6840dd2e282a1c16d64b83f9840e76a46889c3611b1c02c8548da19626004028ac71bcb6e43e12fc7ef9906eccd893db8e1b8b9d12fc436ecfc510ae210197c999aa0af378fa1108e19c00d6c8fe75110266df619eb5644ac6526a1b82a65d3348108814c2d6c1392779910bd893d9ec69e4d5a5a2ecb782f03f5ce61e26c3304577712087c04c55dc96274f559ae44225a8c29b883cba51ad89d772f1b4112d3cbe9e105b631091bc348b8e8ebb73af926d0ec9594742ddca5ff880c99a233363787fc47edc6a2166c8b2e42cd8794937587b244835ce74f1e0a0be443a993ef5e141162bc940a9df9f26e0d464f06bf7dac2ed6e0dc05867808851a76ef34156e6698b57f7b2fadfc530e3656edbeea5dcb23a6508b22b2c1f2b080462266d97d34b8db4c4888b4685f53349a61ef52a6532dcdaeff5a11fc9f944dd0c9cf6a7d32765268f5db28ec8260c50c83e22aa99a166c1c3a1b7bc328aa743292514b6e59764ad34059ce1ede5e48b96f7c4d5d1923508adf26b0cc644a8f65be79b19fe066eb3c885f0c096aa701045f0ebd61df89f6821f2fb702843a050ca340270559fd68f36eb43fc44baa710e50418138a54d425668d920bccfe21e39536b3714a91c4ef305c4ee4c7926549bd1f428fd0a81617a86b732108b5734f9cc28fa7c9e2032ef9df117440d0974f851d041e6e9a22a16488abbf539f35bbcd8dbfbcfb20da08a1929938aaf7621addbb4a96ea0c538db69f87d0ccf4e12cf82f70666bb0566ed5c07726881ad405526622300131f35844e3e0d71cac580fac08779f7918cbdd6da2a1bca94c9220850b664e0e5f4bb48a124c073e2e91e00a6a3f8e100713950068741aa19651729943cf6adc62880303175a34a913738902f9557370695395294b2b90f628ecfc0002015a58caacf15b9b2ce6f50ede942a31e851d134026e5a883c4aff869d348520345a8904a5b22aea98153bba8a0a2f2c964f38c534d784d17620467fde8e362913104424eb3cc5bc7db85639470812af75edf2201f6290370860a2a80699606147c3baa4842a21e39f9417bc4445836037bffc586f5153f252e677a57843a2004effff05083ee0dfb49550d225d8f029899408ae646760386a603ca19cbbc99872337d001b9c58f4f5708badd91531e90c84506eccf1ee110b8b4642e91d1e9707cc8793c6e310195c02905350827527a785f36bc06c55a9f3e8f6334302b5275aad8825f4499ae0537ab0a8934eea96d4cf8fdd7ea79d0fb4186dbb55d1ef97d9272a346a747b94f8edcacedf3e866a25659b48b9716403b65c2b93659bff9d83677dd02d0ac0615ad994d37b0f42dc752c7b0e20be92e6db1e047f9e10f56537421c10b1e3e98b809b47e440656fc24d18aa6a40d17738521c87fb02a960c6bc0acf591797177d5104e84efb772b8cc5cda0f356ef36d4a02fbe9ebbba7239fbb0916a2f9a783c672f4aacd1fa0058b55d470d5e040d48487f4ec1a156ded5005aaab19b052bd9a46c89a8ddfce283c35ac420339e55befa94eaba9676f1d897f590f0e5fbb67e1cdb602845576591caed6a0147a0aee9c77c199414e73e12b79abd43d568aefbd604d163285a1b41988ba5dc7d36e1e2346c053498df515bc4e425a3a0ffb776c42ca917f7565c44ba1aed8440eeae84bab8a68285144f809572bf58aac2484c141c5484221b32581dad414dac0a9d371f6cb4dc61df8a0400497c1f35e48ad725b8c69a9859834e7866140b93d9c84cdf5c4aca2a2d2d831919947f3ec53dca6380da4857e290eb8b6dcd1c53fdba060995507fd92aaa8a8452a1effcdfc31e0e62ca562de7036882c8c24af3692360a0dee869be8a2f8389cda3db718491b8bc31e94a25f56db738cd0be367dde84a0c6c54fb8e6fb2f9ed81f270855d468660fa97a2990d780f568a3acb3fb1b91338e6db515e082892414c818e9a089cd5efb84c94b837ea78174d23fe59a1b749182a2f4ff2753db2a1a56bb25815b3534918ffb9a0c272db77f7db8e94bca4f4105f55952257daa90414d3fc7547cc35aef2fc9e0f42215e539049627f1a32cb3aa073ccc8638c47617c76123b5d18aabf010bc03081bf546d83b429fe0c9f2abf09e6725d90c02d0706c7842e74900b100bc6b09b7944f64e7160aa01ddbf2b505853c292f7d3ca5a739a6582a68faa69e04726cca9a4a46bf4dccc04036b9415177aa10cb67df8a08da8e083a933bfafeb240bccf61083b0da8c640f78be3dd44beb15d0538d2be6377f633fcf94d255c512324b4cae838c11a033b707fd200ce0e6c8eeef0bcdf115bac30ff4eb8e0b3fa17742eb7ac9f655bef69bb0eb446e5447a522ec4cbd818e2dfefc1e46208e4e9dc41cc0acea27f0a9fe474cd6d86cff5b788b9b77cc58e9c8797567354ddcdbbb3a521d09f82df8c00912ef5209c0cea89a6624dd408aa8bb6b3325c53d4dc61d09d295273ada84382544c4ba26ff95059de70a57083b775b32c7e276b29678b892965c980922b35dcc4551c424e6ccc62e0ff8f4564b86d2600062236125e4dc307db8e846ccccde4a9e01dc8e37385c98004b8807def412949f46cad51b981550234b122b248a144f1a4c541314adcfddd66bdbcd8c6e4855785b7881ea56152c9e235b575e98445a95140780bda19d718b8af9eba8747963520bf645f616033d639ccc851c25360214181670e9779a08c1b98bb7755f855cba63a837aa71714752f57ea6167a02e3e058ce3ef01346ecc331f8b89d8180e14c3e00814198f16ae547e80b18e91cbe33e3aefd929522a32084de036359c22bfd14a05078e353d3dce53eae69dd5ee5e67c12b6d910b6be651ee39680b5bb1705b9ab061e46adf20e7189484804a3fe56021f5edb856e07b7d87233d8d68fbc8123c55072caeca12e92b31b1361381048275c5c425eeda0817271e01fba5a2e4b2756c34b148f211b3040dc73dff14b45c4818315edd23dc4251dba8da7e3ce05a99216f0682675182f808a1b0c244ca01b2c1185189868c2ad22d6d1eae74212bbbd01d95362c5a52b7bb65bd981e553f640eaf54ad114d35be7803bf0c42b7492f3f751356f668a23b2d48bd88edf76273aff7aa0c8490097f3d3be4be9a4dc574c06e3b79d251db544211931aba328910e1328c1a836b357c55407e836543f324d7d9fea249da4b699a48c488a48c2bc5f2e141224b9e56eee64e49a43d1f4e54492c5f02be85ac00a988a23db4a3da7bbace5ac72961ccef75a235be42f62227097663c8b8f72b9eb987801db80ba6be4131429d79fcc2046510e818ed7baa8e8b8df28ee687e5aa258d6ae79f8f1fd2836ebaf26b340a62649b7eaf30ab49166825650402026631916d042cdcf2f39233fb4e66626fc20209d55db13661127eaf4edb9ec7419721db35d764bf02cc86621627de70da998f91ac05f6935ba49e9442858102470c866e62988c1a95e0db30ef687e1faf559a80a5d8303e08c622c4f339638901c102ab5b5ae3b0471c905e4c9665ee9d3de3cfff7a3333e77aa52d7cc91b62270eae2fba513235f74a13a7ce642abab46166713cb84dd6e1bc31a0220766cb542fb795f8596c6d4fad77d0c0213a3ad40bb5a3855dfee4dc27670c6c87346380678905e8314dba51f512887221973f9f50cd08e9f3b5617926fb4dab023c50d669c4ccd94ad5a409a2fa269e9f5cac00b498c5f1eb038d16a447bb547007388f1361d9d6aaf0800d9ef7c09e3758127fd4f0580f40ea6afb532fdd11c6e4fd689985c41b33950d291f8c0c7095d88ce2f6d296309b15608670dd5b950e40331f92775123506da2ffebfab2f5dec45fc6da9cfb87ab3cb02587dd1accf8a95db6683750457e6fa82a0cfe6de59e0aa8f3ef231ab1c1952158d1738e81d6ea96ca04a3c52522b50201de1f1628d7ad79ebf0b316d6b6d0ec7f3a69356ffd03775654069c14b6388a16f10b6a293b95563f871b87424be1bfb88ea564af503762aaf3511fd22ab78f4dc2f56db9aaa646f497b81fc111740c5d3c1c1963a06c48a21fb995df6372b1eff394655f96ac89a58c067f7d93b9c4413ce698fa0ef0d7b240f5c19e925e874c9b88d428f2240291fb088822c3fc479fffaab5732e880905e1d92e509d642f28d370fd34b9b1a9552c8aeb2d2b41363056c0a8bf298502e381960a53a2e99f71b12fb49b5361e9da7c633e6315daa984cab75bdf00e24c32a1fcfa7cb5fa0d4c0ec611bc537e25cb3135f43031e74c35a2909168e09ab88d5453273a5f9f920ae8ce20b38d5c72c19dec16e6733d4077ab4bf52805f3a71aaa69d1141a02eccae1e0241f3c39a93ffac3aa9d44f2a858147c6a478842b13a9ae0f581f3b9678361013449ffb5660ebb10489d8a4ec22516c1972e7497ee300d3716d1d7bb6f6a0425ee4d69c7df94a8de004bdb5cc7b2cd09684ebcb9a7b90b052cd09c24a264b9783821bf91b68490f9dcea914790e8246959e3aec5bc63ee80c09a70bb89c875a8e5d5bcecfb47605bff94af76a33b9cc33d90fa53f9ecd8a0f617263e93597861ce61710dcc1538284a79e2e65705f6872023f4cbf3c605bba166ca28cd4578d20d080c733dc0425e2243052b505eed8c1f084e3b8563e293cfcf30c4e59474290ae3895039a68641968cd346683360c1c3ba646af62eacd5f186174811e547f153845997bb980542bf000b2defad9c2fc56077cf19742deff1128cb95c41f38e091b038087b1ff9583e14f19b7d8a079f7c784a03f592bc56a69c65a06da2df5fcefd540a04d7302c5787bfab7c35401a5d7f2cee1d0a7566ada64372994f2b56ccef4c828a7487c970bf4319d4fa243f0d535ec06359f2a3ec1e07bcc4f04915d4296bf0d34cb663ff16e76ef4148be3be5ebdec95d90e28728b325e937b53f569a09ebeb66be79b48360da7bc72755dae75613d8f550b8a18fcb08bc8d25537482d35cbfacc13a104db5c181229dced1b8ee0d7a2a3fe789484a3b89aca7fe828ac87edce007d466d17ad8b14fa33ee7808a9d15a8fe0dccf75b9fed46e120d3be129d19c073c75f3c259de4002e93b22374663b103052aca21178b8097dfad11015dc1e59e2322e449facf09cd98c6b6663bbe59fbf686f03c90ec88a97945de579a7bd6c2e70a747d1e1b5b307c8bbbc6fe6b093c3d5d4dccda8dedf4ba2eed64f0ba702083957f2c7105719d41d2e96bca2a60e11485441ae72847dccf6de4f3a4acb766c50dd0b61dfc943d5c46730d8f17500451d5649ee33d8245e7552e44793c94d95e6c8e27248c78fb21cc49a9bf589b1adadbac1839077b466756d6eced7805818b8af23890f96719efc7a3d0016720c79ece8a2db3310cbf0945c2ca37aab613a48ffd68c4a894af14c112272f8f13ced2969a68bd5e4fca2d3419a123aa511c384adf1a574f4bab147937500e8f8d48fd27dc7ae850677bb649b0d1abb961b1a45261cdc883b6408ed5b3cca2440733beda0ca7f20f622e8d8fcf4522592e2c705c9d2de47e5cfcacfaed53c1c44fea6bc2f5f0686cbc2eaccef864ef663e35e56225342c854979ba2f86e5e3148a8ce26dfb4636ddd4a4d68a21a01cc47795a72ae45e3b8a6274e6e1932066105bab4f57ae19f2d2ac33c03b024e833666b4a4be24318443863c5183597946d2ac119cc819fa8c457e9c187396785d7f30e49077d50493cd94aaa66d06e80896a680dfcb9fdc190731bcda6ea354ed012fe1780947ceb223de3dbfc684652b2a92605d3a08a6e5e4a52c584f87f64c5733900111389844bb39fb94a81b7c276a7e36f48d6d1d10d45360f313f8f6a622f4bf905876effadeb985297700ca452a791a84087c9d1d6418feb20c93e4b4d35d1facf9efe8a5aea8f1f28435d51e6fc57bdf86e8012b994574ad9af5a8a1da2f1482df6843e2373c9a9379d360730ea31073e405d445cd48ac3f2d17fe4767ab9f940a00a4262ac0b8be536fa54cdea0940dea45e1cf00c0920813382d3d152b2cb3ec9a786eebf891a054b970b5cec86eb216b6e8d68bb0b1a047c8028ea34a40eb77221e057008bd6b26c832e69d3b3e6994ccdf8a1e045c46d58df461518a4de30931d30dd359b5b4043090d9293b611df01e587c1199f3c75f889743f359932152eec416b54fd29af905a08cfd1b80c8e2b4194b9baa435859a9ec167be3bc7c277a78ccc1599f6de7bbe23cd4513aeff5628fb2fb7a053103d9cb8b1836c3a46f578ebddca2509f5ac1a0d0f55f96d364fcaf18964d08f65546f47d93993cf7cae52ec54aa9b0e31e7ee14c1bd3a4af72889753f6cbbe7c2b2570fd09603e440a378ad13582bcad526f6b684a18104570674a3f043553cd7d38602d0d39f5dc59685761bc5ae8d146549276947677b5a3322e1af9ce4e923d8d72c3672685a69a6ed218c713898860290ffb19ba1a6fe04829c64976b1a27148f2473b6152f232683b6c5fae593a9cc091344e05d2dc701601d9e943db93e1118f7dd0cbb5ce31e56e545b58687b0c0b4467f33b85031b86d52250d8018160e10f778350d0cd39e379597fdddbcef7efad49a0a524e8c3248c70b6a8a97e32bc6724f6906c0479fb26abd8d947afc379ca412d4d2f89ec1bc2082a4f0b628137b10143d0a7200bdd58d6259d9412243efef0b5cfe6daf26515f6985c0499db9d5a8d10e8bec2ed6d331f4694a77d39aa51797d84363bbd7967c25b415202e209338ef122354fbceaa3af9039339db194f8502c0729b4dddc4aea9764658b0b3d60cf97e5fb2544ad507fb93f217a5ef4de34e2abf5340c29e4050e0912e57d3401e65b714adc347df949aa9e5db130484d89e569ea644d1387743dec88d72dcf200cd8e089379e9b841d15ee0d9fc0ff208d4b39894a7f144fb2f99c31039a6fc52233cbd7f00bbc8424c97fa4a3ed2bc864e566860bc58d4fa62a7277c539f733d59736e223a9cfa1d29b0c868abc9a647efb473504ee9510936e6446f9311f5c609cfae7bad89480524534bb8e8ba169fddd769fb2132fdbee1332f283938f5fce6f12df8d1367d8601f5ab93713b2dcd77afd5e8d67033d1c3d4af07525c7f894c21abc1ec9f7663c4c290a2b1f38fdff21013f19bda29f07197f2462869f0718c197694e434f938f6aac53baada38bf404b013e1d31ea8449748e923a0558ee9a8c39c67557f4228b876488340f88752f39ac0cb8395b296b1e35c62375f69126be03fb011413e90403deafd71adc691c17402573a2009377f594a6ab976c65f7f3a6d45c53b68603dacf539bccc433c6e6511e5a78823d718466034125ebd1894b8c29f94886c38c930f81588cc9e39c31058088611baa736625407a4ada6e0bef66221b3ddfd429f135000a2f5287970d7da86a7c5eb91f5a8a38bcf20a460f98645985cd85832342f7551ce6487a9b80b558a489f08874b608f95a9c26afbbf8228b45417f7ae962c6234fe9f290a473d58c67cccd1fc23a617a842aa853a1be670d29f4707fb55a9514276f073587e0a880ee6296a53137aeb157a03ba2c6954809a9c5c2a9a4a34f2899131f53190cc951da588db1e117f5156369feb543363e1fcb3dbf2d53f00a6f726489243d878436c575b150051b4c60c9eebde8b4384c4fa92bcb858b6206a862a28e725523984cb424cb450f46eaeee2c4b27205b67f0c060d4d37ef56d5dd7f639a43b5b21649bee95ecc3235403665ae3ff1a3a25bd002eddac98b0b17eb9e0799c227c5632043ecce47b84b4dfa9713f894643f59fb2301ed5a39ad5ead16ee72e8dc70973dc0e6f40c90ece6573de920d7ad36e6420662b017519104d6055708bb5bf2bf301531a14021b690e328e9c03dd754d4e24b6745cb5584ac769ccd35c40b312a3767c03d0fbbca7ffd7bbd72672dd49c71913f63379067dfb90e0f8763c39ddefb83ab2cf63a578ab88e4bfe51f588b7428f4b44101ea183749de8151d5bf45041a44b953f78a4843c51c9ba6546d1a55856b91fdab53f74b19289e14f66280b514c42251120f21892b51a0c873cea82bb00de9dcbf14891a3a13a0f796c44ca133fee5a162c411629d5274f07c9220b79d0d725fe9dedce15913ab243a98b2eade234121833e798d1fad2ecefab5c96fa82de940a8a609c1cfad6d47a5829145cfbd403a76bd5caa1034e0d3f9ef118abdf6d4668bf52a8f665d0ad98a840348377bfb1ad305d906a63df6f8c840f43ee9970f0a254f433d2c860b7995bc2427fe34c649916ed580f2ccc2f64b4ed0a2930ef5288a6552937c0c781dafa4b95f96779dedb904940cdc94309fb08149cd46b5c64c9e80877cb068972ce84600b6294afa88c2b71d045e8a96d9636354b200c7e3b972c69219679346f97e4fab8269aa3de27d319a6f60fb367e64101d21ecfaaf398707efde4e1232d937fd0641f2607bf9f67d9c387c1629eedfbb9363566be39955a2b84f8b3acc2da600c30d06cab5150df0a19e127ba351dde879a8d7d4b0a71aff695d206ad92130fe9fcc0e93e326e52b96e0990e49de25a135d449c81e240712a443af544edc43583147d20774cc784be2859868022ffdae3e4dee15f4f9a2985b292a6f2a4394fb6e151ba995dcd2365f12b2342b4ba09675bc4dbe6baf7b27a22095ad20924fd6d479b26d7579865ac8ab5b6256e4b8bda8f15bf361ced4064035a96915a1f10ff653a7d2545ef36a10a8dedcb6351f2d32c28897bc04fab6a990f31e0436be04b917d949695a322a33671adb3113ee0872fa15cf9584a6293f622ed413c71652738e5a8af0d49747600c81ad61f4ea93c88c704d1269609e5b4d2f61b8d938513e74bb8df4c3e9a3ee3b7e7008054fb374b08542d8ee194a3174b23c4ec4d28d68a77da7621bafaec875b4ab52716d3d885d8f1a3a5aab6e00728aa23a046cc6d22e8015f85c1f7f0bb490cc214c170800d45b0748c62347691b7b3c56c1dae377ff6931668f3a432c62b43db2234556c721a658b41049abcb3b50f324f766b1905f8ea5e1c90c945ca71514ef3caa7f4929e4ba5d93ed9dcf0f29b3d2a9f5354fa953b4eacc05940353bc88a837b06a9fb5c055848ec86f1d4a5992bf93564e85ec568c8d06d9db3670709a5bace3bf3972a5c026e265e559a8b79858b26c3fb5ab85ff73d87bad6915e12471cd65e9ccfd311f7f731decd5a80732cd48fbd358f5ebceb79f042978ea54c94ab755fa94c89ef902974adb95155b11718527cf82d301fc7a8e267bbfe21504385ab1f5d452d39454d7e75761a17898c67020cc0fc46343d9c36daaae61b110aa081450150b407a66fda274c5c14ae0baa2ebb10e959d97ea2424bc4a49dba5f0385f65c34bc0b81d77dcbf877c0b585867d1758f674ce4ec6608c28ba904e9c2f717aedef3849115d9c3ae206760ca5315af688fffc6c6ab112131c6acf04a6a383bc3d9bc17dee50a6c781167e07393424e832b40203c54950cac608eed24f365e10855e36084f62e6bdbca032b6be67e00a017296eb360ea363eedcc6cd4e27986c29836e719c31bbb43dd91890e5f796a599bab6cd4633952168e7ab1d682e36f50256696e5c83817b76ddab433ab1aa597fe7a7f06180d3cdcea85e76b303b179b7b5f03fe5df611438096d2025ecc324b8cdd824166bcfabdab685b837aa3f01c4eb4a39ca87ab43f4fced39e658b9b9f453bc7fd4aa2f0d0f9b6fce634cb82592da2311ef11d54bcd44e563cb3a836e53e941f977d9ec9c655cfbeb637651671bb99914196e11502ac6d3f5defe914d522fae4fbbf9468ba2e99e1219d632c2ee4db8bf20ec4fae2b07a4a214214a174894ea24c6c5c8f80675367770e6d1b16437328b5b5b030674403ec3d0bedb02886e7ce084732cf34f14be91c7ea6d329cf7e4b02efb3ead68aaffda4659444581a00e7be1dd4aa5dd98e78e0e1b4bdc680049e90d48e7cfe66bd03db09f097d724de936364086614d77ae580a5c86725bdeef4ee0b0639d1056ad7a01e0a1198868edbf61b55483aa7dda2b2f77ef4f2ec43590db0f09f63631e0eee509cb8176516f90819b276a44dd54c3bb28f1871d85c2a2709379d4a8748fba4e0ecdf0d3f91f607ad166221420e25cbc8023bcf6c2bcfb54fc40859c5315205a0bd3ba15bb30d8dfcc8c03828296f5521ec55978ce17a3b4db8fe94d808c34a743205c70356d35b391c23b008e037826b569bdff08bb5f4dbc32ec4eaafb59c9237b3fb5fe67ed30882f6980fe158566d665dc4e33e06933757301b5566d9ae0dd025981a283191fed6a2ff0157f8b44d2f6f4af4a1b268ad388ee327bd7270b60a3e73cb54a2bc4d652f271c2f8d8facc3aee4096f0662ca01346fd14d9ef137220690501763ee5fd40fda7254f1cce0ff7297329c5115b46fc68e434fdfbf0d8d4a250000698f85b9cd9485ab9506767448a2d9252dab27a6bde51d986141eb2400610295124e5ca59559757e908e711f14ec5ab806198123944b8445b30e7150b7b0085d6ab6eb88e6888165db7c54b57cfd75e42a26b99387ce61da530303e7b1678b422692c656dc3f5e2f0858ccf7aa981f9c08442556a97939a1fafd6684be578c86bb1da014e377b80e873c4d6439cb7d5cf5be0d84cd46b976ffb21631ab9c73a44c89bb9499d9d1b3465e5129a8e3ed680bfc33e0ac6ce348fea495277e425271f9b92221e875e219b7ec246015de64c04a65150e1ef01df49512dc70c4326a0a43c468b2d397ddcc29440752f5f9f8949db513bdbbc5a11cfa36af383876ef3a16ea16412fa14d0265c33738b3b30540c203667e6818893ef373b058cd8a5aeccf5b48f5cd6b581da9e32228fe6083913e90f39a3fd2a8b9030d75d0ea1121b5f332cb21c196b759a13fbfb83bf95d406e89b7a4050eda8a6200edc365ffb84d423e416b4541517a144074b9391c068ac8acdb41a7a0840e6e967858010985d5991ee89c29a8912b2ad5e3427fcfe08e27cee41fe52d88f625f178ae84b91fa3c875436527e007b6634fd50603992b37a0a53b58dbbc2c17457c38f30c642046804e8a20d013845944fd4e6d2d14efd0f844bc83fbfc4fea2de3ebdaebd719e3870908a1e4dc11f41d37337c4d936b73582f5ac8e620bc4012801a34884cc8980e264201339c3466c6d769d90f1abdc38298e810ead5269411a42467a15cee81ff90858f638c6a6c681fe95a0dbd000a5de2508c322fb9a7aaebf5a6826d031c67f6944bd2382acd17aaa7b72cb18a1d2eaccd88e79609298895c4b91ac1522fe8e7f0cc86e4619c9efc0e046dd758f0a82a4acc3ae11fdb8a70b24347bc0268b556281476c84575d8f141678f4b4df2318d0acc0a53f8f98ad60527bdeecd097ce8df8677e61c584414e287d925804130b0d5a81b285d1421eb4784bc00257634d6db545e72f12d78c8d01544a5c399b003b2c0dc7037247a53d03f7fd6587d650233b6e74df9d1be68fce431659d914711e419e82b1fed9c86fd3973878d54ed5312dd4405c385efad0146585aa89bfff611f597580383af4f521a9e268fa99a49cdaa18985fbdfd2e38eaa812f8f45828d340094e518cc210d44a7b5b5904286c5ad9a5087db41b84cec37936040f35ba893e9183043fc284cc3a6bdb26f5629c887cad708c994b5c13affa02451d75c9b5c21beeab3b058b257651c05d9716face1283320712fb055c6f8f4dd64fc560e9c5259d82210f904e3324f9fb44f6a5238cccc9d08e01a0fd88bdb498e0933fb02e47ec119017901b9d91b9fd097637ff3a4f1ca2c02d36accd72534b32308f4009039b79ff592629347ca4188179b148ec704bc4ac140ad5170c108547ff861bc0a0640990c91620440832b81ca189648ae8880db02c43caf0c1fde9fee80c5c002a8d2a6d54f646ff63278caea3a66a35358009b3bf8e905a9630c661d6570c47806c4bc347178e8b2d000da8cd372f0dfbf25898e7e8d2bd033a407592779649707f82d61cd269c5b42107e30c58982603b10e3464b3e23087031408119693fbce9118eaa0657609718a8cf8a052203f59ea3c3c10c8a0c5ac87faac6bab9bd8d52ec0d36ce6a2a0c85185343e8220e3cf166ca89e2be79d967b46deb21bee8bf21e4c31f662ee480767d0687d267cb7d99d246438641218028ea9a010d312712aecf571603a231c53a71082d5abfc3e10c56cc175fed776cce8dfdef4d3bf0d9d59c48039e4fe7dcdf78a1bbc3dcc5e789c4f4902196323437084d93c4970fc598040ba251a447216ed3e81fac1cbcd9ee0efa147f762bb6f436af8335bae1267bb12aa1d20c2e84ea701f9b671851b98d6b55012b8361719c3f1c32c42e0a5ef486baf50d4ff788256009768b4f70a5cc18a5162568c575ced919ce71285ff99b3102c38855063c4c1dafc70be8888c2952a5e658aebb2608c7c232da4e876fb07f3a1d467687457a89ad845a54c5165f2ca2b12c27ff47280e4edc4c4843df368249840e4145ae6ea88467dd0dbd909b3c0293397138865376bebec4b48a0471a1cfb18e1310195c4d659f8f249c05063fbb08108e4ea157bffd7251763cf3fd597ee19b28a00ae8a7626a673a8d83b519366f05d32d1afa0de0b5c222cb5633c35943219aa55ec21593f29548cd4c41cabdf33fe42b6f758a22c43f7364bc1d01a531d91aafa65ed26021d47ceb47ab4fc5f32aef5aee00b9d12522af3696042d9692cbceb5c7fbb623fc075abf4132185534b482ac5d2020741f86b3ac3b1bbaaaceb887a0a67e06d65d6517afa3ac9c4fb9a0c81e01624b5d7cd559474d41e137fd66c28c9feb893c59297421723052e1c9b74c220a5ba95fb4a2f493851caf35e057cfc3bf5e71e7548f84cc143caa52c1e99596baabd0ff518d2c9f3778373761b8c07e0da23b48418795dbf5bab05c40599dad48e663cff009a3e5e259e17bbad6bc05b94311893f794b9acc1e89dc99638479db97a3afe3c108de8ad75018062bd58fa432a8e4be998256e8406097962a49d977cd03760fe57e34cf7aa0ea4da8a54f5f87205f6bdf9cce259f305544c15b5ec6dbca079e7d32c3458e275c62030959680c26524548801fee18cca43090dfb212cc08c95752807b37874134ad8a6cf17ba865f5d7cc25ef3308c2b6410eb76c3d54cdfc2090218742aba2ba19347b340cfa6b114efda5aa5801ba8e69ee074ee93a1cb3fa79a3640d81091814fa8611a523b7a054ca68ca39acb28732ec20d3095d7ae22e14202661bc969cd86cacdf550481b07103c6e7461840fa11a9dc2c6ddc06c3d0c4930cba4f24b0494a6f5bd9e47abe09e24acce59c23d717d19aa51517bc40619433bee82e8d362ea50b4289067a3bab37f272e1fbbdc7c062a46c11b26b0257b14d9801ed560413d38683cfb0bbf3a7813e6b1ed8dd7796db16ec77eb457f8324a41cace7f84a5f00e07612990dfe698c809cee2bdccc685e3182937ac020ce8230897459da0520dd2e167a0fd31de55f3f69f95ad22d5691f211ccd061bae4370d51845591d4357482cef2d30f1872996beb80c984f48b8b61872828827255efe0762d9da931d700ceee38cc090144ff4b93fbe42e8542ef28ea9ccd7ecfa28f5656223dd843c8d5fb7c5fdff386e81bff51822b812bd1a5ac2e3d5b07b7e676bea6bbdd705967773862b71a7b5e1704d2b4d1ee967d6c07f5b69501409400016f98909666bcac8df7d5d9d199c651d2411a681f3d94d2ad94f316d5c1c00bcecf3a4bac3d938d15e7d33d3536cafef595e1b2868e14fd4372f41752551b7a24b319a912f41b693ae692fdfc98ea5d12ef3d679bdde5f6fd9e846c720014e9d5d3285f11f440eee6a418f123f4e269c945fa3eca6d8ea1105fd2747d8c0d01f34f74d06f9bae7f3bd0eebe3746d928faa70865e0c68b23ae830b4838280a3940c20bbf0efb1391a4ba2cc53426d04a0f3502349a2e1fcc899d2cbc0ba707375449f4e824c2cb1954d843e1bd1969ba23e410777d2775a3a9d8ac951632ed6f1b531a56a0510fb9e243ffbc3d2f625880e8d51c84eef167c054feb2a31253b00473ec3d1afb32c3cbdd8d8e69267c84c6643040413e35ecfe9eaa97f0c1297f5ce91592aeb242f78e93717bcc0c0ce83f3bf4df822a79b69976b8c7f65728d8a41b51a2acd79b02508185f577842c42d24aafb994cd1ece8bd0130bd6cbe03d55b4ada3b89ebcae9ca4012e705a0466d1f392b87b9b9f51aa502c7ec411a6cba71d5b0df24438117cb6c0dc22a2e28670787a0d099e6a3b5917edc2f34227482693791e22f549f7128ed22e10285f1be46703e92877abd0c846abe95617b0165340321c046307592f6fa9907a9ac280dfd05dc232f6dd0e59ffebd7d22f1b959e0652116644cb11ceb258e0e962a2cbd16f551a9926adae5fea650176126292c8c3e1a28b3c032d2d629f84f0e9cc9b7174216dbd3dd6525fe510fcee8b3c12dc463d716db9572285f6b5d0244bc1c08aad5a18167c881068dfadd495f3bdb04d58d6084df2bcf7409eff573adf4bf07bd74182e2d36b4cad69a4f769a5a9da231ac4778a7c6b1b0bc401d34ff165b641e07ab33f3b9f54e27061dbd9101ccba8df5870360863430553c4fba7e897460958c6ec936de50c5b5faad1520a02c7cb48b32ac16e06edb0fb584611985db2f820b039e5167706198ae835192a8d7104a81f6ce9b504b7b8d907ad33029bb5f144614aa98db14b73b7dda41ffc82650ae797962ee8b7d460ba3194aa76c2192be8297314f713b72277c1d8bdb1fda159f409bdab8ad59212415c39bd9fbc0fcff9079fb357dbb03cc97b97498daf45b7176a8da5365f2dee14a749dc1647fc818f9a7022e257610ca17e02c477977b85e41f53ad1fc10fb6a9e9bdf4d302254aa2831d9b47481be54cd83340365b795ce482de59fe818fa2606c4edf8a0aa0b0886a284f615f341b7b4bba4d55936beccccad9b7c6941686f6c5e7662aa8e9c75b436ef9ce3d4d10cf96af03290015583f7bd67c36ff5c4bd92d38dfc9ca2fc79b1b5c75660841f562032b14f6a0263467118f5a03406d674ee4181b67e560835fb43ee8845f34a0852bc32fb1a38d19ad1db71bf6024e35d32a714b59f00bfc731d6f7b06204d8ae0f226986d4f57f3b773cf4c4591ecb97beb09a0349a509f53ee2945108401b5048d310ae64c903627cc18822ee414f7dd7f166110b5b39e0a2fbc89b1728e26593db47231f8a79bbc95eb3c59f6e60c8b2093d14925a38612d7dc3851070525c315a89bf84b347781ba154cc2d522420c9d5727498df0fcf81bbfaa3ed38f254e45ed3aca631b0e88acaf2b287c56db43fdb0f51e926204caa772c9983f770dd620f6415aaa37b3d1ce5d1d313115bc875c5edecd63391b9ac98ade7ae16479e7ae117a387897411be5a119efc50a19f0d94d50bb09e29d3d0ac7433cfbb7c060a92f440f777203586a2162c0f70eb3a59634173dc1d81a9c102f4b1beda21e543977df7384cd4296d6f47e419f2615712f34e9fbeb943f61171401368c71b7293afd5aa80523e8a387652086e3f1b5cc4c02fa08e67ed8701423ebc4dbd370cd1a4bcfbcdd56b98c63bca39e1525039c318f79a4844d73edb1f75f5193690f26a9836a9446a9074652f56043d93ad6b58eb3e30488eb645c68e145059f5e506e4ba91652c8efe310beaddf905def263aebaff73cace39058c5801bad598b58478ecfabd8884d8128115ca2d3408787cf4f450596029940e4b380f6f926e10ad61045fbaf648c4e62a1165653c50e28a2dfd62cfe37f6226cdc088140eec5a1006b31e29e10be9d5093b116fa92e6ef0b16b49a7e2e6b98632a16126e7adcbdf9ac92023b6e226cea45a5e30a3f5dcc92072fd43a1c63976632c321e710dbbcc4a05cef15e40f34e353d7f21ac9ecddd65b0c32da25dfb83c5a573c157e7788a065bf5df82949319b2ba7f07beb5f801c74c8ca0f5aaf7a58dbda5b09b4e24ec2bab8b5ab2acb3256e055f5e688e07e3c926bb0fabe586c9de51a64e5ea1cbd046bedf95e331a8c81a6a937732c6d370642c00e409db0b6b4f490e9538b86b544d545c163489ce527b3e46cd5d3e9d97f922f59846a7b347a4d9ec2f84989cbb48e574d17bb6a6d3f6a5aa6ff715c1ba770e45e86ed38f8db7248e39334c08ef04db67edae9106a38a08287296842141b786a6d45a9afeaf54d46e5bc072af7c22857976675abe292041e54463c038b0d688dc0d6942cb3120db6f0c43eb47847231a6a38c96e07710475341b24a66a3283797c7a572d56b05174e23ee19ead53d68ead2357cd4604e27cf9a56d917a6e881ec7555b533bd3c16cb761c2e3f13c13235609149f6cc23543dbb8dd297ecce481f5e47afd23d2e469c82b57f5f47be913c2c75b487831243c1df6652e062bf5dd1383ac4906cf9a5c8e20d229b9da750a10c87972fa0e2e58cbbdfa4af1fa075b80e9b73581b446dd71d16c6813343e6b8c1af79012b755334083d7a3710c682ec4503f346da158d301cee757d96aa6251c0435a97defef7cf39028390314fc0a3867375853f57cca7d5d105332911d28d0e835b34d167362c8c61e8cec6adda3eee89570670259cf7cfcc3668590c4cf1b2d9efd3b643e97e00aa0ed24303d0624e43b189e88802f1e25fc74cdf327e7101ea365cca17c8f2eb63475bada05686e0728f2905ebad04da11d04ca0ea3ab9e09846b8e5d764a73bf0c950aced89b3a4b75f7170582d6ea4ca8dfe1e3f81d19536fe0a0dff2927558572e61478c40b018b5d2b4732eb99ad484a530ab92ca0bca03dd2abae1c36c8a65023e64a0e0cb1897d19513b09e2ae95872cc8c864550c848c3dab5df8686c0e7026be4b481571f402d569bdc4cbba21208a0d8897552f9e67e0062964560e5f58c71244e75dad07dd14d2db7cc1837317af745908a1e22a551c0b3e07150a491f1ce157dcc205c24d8b1ec88cf1596ec233c8089324e5798d8230019e85fecd9653bbe4832dfcc5b475e0a1d319b23416901ec77c519b9d47cb30efc75800604814e778843c75ec8ca2a87e5c27f57c3499cbbe5c69723ba5938b0a7c099e5a0b419a4d9fdd82f3c060eb30e153ccd945003c77679345d718ed30b6bb90a9a1786090948047fe5a80e5a186a24328c4b034cc8d31c60483a16daeb3ad0dc7f5f651be9c41543e4de9c5dff28fa01714156101fb5a830e41e676e15c5222d90f41c34c3528ce9b04d22250e8ca3d028d4c2a5a2e6c442ef9dcb68a0a214a3d815036d56c8425d7d0bca6f9fa2c4861ebcbbe672ab4d6e0f9f9579adfbe4040b5337728050caf810c9a0d5c7ee7de56471af3a8f465bb2c5985fff6e9750b393c4153fba1768776b04ebc5ea356645723798ade5428d483ac6125e3abf0b13a58337379f6fa4b08287e4539b5ecaef12900294fce193c02d0471ed247c4abf390987fd1aaf27c273880d8de43e90fc8a85606e84b5e72f84205d546f1aae6d372f494d9940d8cf23fbf06e5f4941b0c4470d62bfd448d918530e53aae7b390a9a920fb894b0317fa74c83ed6307f682e52673875b1840c0982318cbd1da2135008593aca61ceb068cac339eb54225299e05a48487bf32be7d051483b82a4c3ef2e419ec123a92906c878eaecb73712ba45a85c4904478171ef790f3de2412a39df6797b1e51ad4865acc8530613bc654f361d24c20e5d1a262778c66b965a40eb60747c2bbea246a220accd8f88404d7474a5695d25313c92c5a1ca0b01d92e49a4086221383a53ef2a0436bf338ac959fd3dde95f3f503eda305d86452945596c256e09306c33133baad4efa9cf23e9e59ec2512c2a11c594fc54260a313cd2d51a5329baea2dbea5626371ad475009469ab64b6965566a603da696e259a033b858f93ee34fc8edb416da1d1b83d996b29db623c43fb3c1c50aa50adab1ded8cb0ccdfe44cc12006604da8328bac2c5761a75f6c8f6c20321110fd5c11d16eabbf1d9f6b64ab9281889f8647ba70a76e8ee49ef56c048645f3c403c9c7b08201996efc4f8ac9527f99f359bbf48765e0befa668b8a101a149f8a1df0d5e9a2215226c8cca44c6ce4f4acdd27aa545f1a0a5804bacc483faca833c5f94c9e4edf4dda44410d88e3b5dbd54906cd104422aa9be870a02613e09b97a052cbb3e2f8496982adccdd7c349eba366fb0d7202f5ae1346e5681860fabdc5b5acf5513a4d35b22c7e1ee217f0900b56093b1a93288ab083067f9553bf2abd0e06653546dfddb6297fbaef1ae81769bd485d3b17fe0348a4afa5f4efbb32ae031cc0fbc38fc52dab288b604e08a7254df2e9650b95c9e76a32eade377d254eb034f1ce6be147d4fe07807dbe42fe8dcf2c4a8df1b665ede89f88f1158d2ff5a0cf69f11f8c0f1ef4ab4eff30b39fc064dfaafab8d54f065dcd561dd6dc0d48950c171b52c318c422854c43327058bac23369a6f382bdb1fda2509f34812cf32b9eaa7b60a7db50341edc699f67bdb226f5504ea4951dba4a23f128a7b642c901b56cb61e067f529458f33c9bbaf692358087243f98e9ec37e4281f651ca5d5188eecf877bb99e4a30413cfb149a5a9bbe92380ffe1036346a5ec22b7401c7e11cdc8d06500588aa06fe423428449d6021032b969a640f236b20768ce5c36a8e5a99dc7ae121fb702112f93054269786be7a24cc3a4c83b1fad40119313e3569c1e128ffc5a6b9dccbf8a818849d2caa8ebea233175f5b22ddebe0d09226454c1cc15e153716ffee221016c2b94ddce91e24502e47f48c0b00da8f8258641283dd742e06b79e27e4d19c4b0ca2850ab6088e1531d7b9bff086c7baf0a120462a794ed88f280694d6644d74524b841059ce667922672602aef63c41e735c7ec0b4030a0160089ccee93cd59d8a8a6c505fded193b9971e0836318da6e4e99da1ee3d56689601d4ac10c32470e803105cd5b0ab150537d16c3adabc4f0641b70b9e3451f02a3584b2304f6ea4d4659bd100f8b26e17606530516d576aeba9a8e0a2a24d6f8a4cdf80e4fb2df58a688b8934a6a25f01363d4f35ba4e758f36a9a81d33aaca48207eea106668dfd960fb8023685795a37c2d42005800a4eda599db79737f0a4ecdb8da8150a7c74e83fda25c1a56bad4aee515900b8fc1a058bf60faa38460148d1c46ae6f513b56933820c1381b0cf1f4a632315aa5eff8786b34a9f6eb237ad162e76379f1a9476c925edbf0c7e264c1ab5909c8d2e8f9c7222f3263bd2af19e244dfa80f7bfba275e8977dc782af638a7047195189e6d335498d28d7ceaed84924b40a1787954ec90afa97819355ccdcbd01363a716a0a3e547a760da63f1e446a6f09993311188a29024f5e740941a6c5175dddc6422f13c3901d60a3d250b16461925e822be80e93a765bb711d33c774fdf1367cb3af6cc1a2d32d3212910c634aa8d640213e0b64114fd8c56d07f97985834e3312fe50d6b134348c8124fcdc712ae8c5694a58d3fc542e43d2cd2ba7da3f8ef19c59b5e7cae2ab274f178a861c2a68117fbde1ca71b3e28301e54995a7761b935b3d3afd56eb35e5902bea62e68bba11accc13e43b3b25eda5d700650648326618c4faa089334d7f9002a873cff85114c6c3b9a9950b1ccf49daa5b9617c177545c18e2c8b8941952c566611d1b02b4c54805393c1e10c6b10104b62a4255433dfab8f06ba5ae0a6515baa2cac466743026178a2a8ccb3cc8208ec9a896eff4d2aa1560d9203a9cbc82a6bd60322ddfb72699f5b0263519945f8ac8e36ae4b3f5dfc81697c8a0bece7ba975012e188daa371312af32e6b3f700d44ad5436abfa601463b548c764c876a1c9887e920e1a89bede3026e8b2d9f002dae5f54db419c083e7aa5b3efe5a80562fca0e27fd0e15a9139f986ab2e9b61ed36e82a6e791ed3ef440b64d71273ec7acf2dcf1bd6d6e3570a1a27e49b5520033536b0e723546eb503ef2f1c682834f5af9150c121f5db72a1321990b9426695f93bacae993b0713c2717e17860c7515085cbafba1d6ccf9b3e1aa6de8518a1f94e637727dd48b6e17f409a543d29dbfeb74c161cd5d26138ffb71cc163ff59da3bd6eaa80ca062d7a95428fb3cbd1c3425824ae4de219738f48613835018bd5d24f9fe41db9a40535c819b0870bc63bf0fe7f80d96f8527192e59e3e42389f03e97db639458ee882382361a414e1267e3889ba99126ef49aed496a3a3ce60a64aa10a60c179c9f7e4a3f121105a12b4ef2123d9fb77c758da1018da9ffa06b37f54394020f4234945cad3beb3a664c0f3c966385e8b7614a65a760d065e93cec692a81e262c8d23f8e544541ede09ad438d5211d396b116d876cc4ac2ce9029a516441744fdf7dcdedb6dc52fedf6520a2661b4a8662b4ce6ab4056e578445fa713ad0db80e66f222584a02d27e0389a3211034b4b52ae0b4d2f91a9dcd7b5817b45d99e2fe3807ee3119aae896dd02c9e4489d81957fcab3f6e2d02ed903102cf64e3645541c90eaa871bb3abbb2068769aa95c7f95cccfa1905094940ead729c9bf9582a20330030d9029cf0bf523cd71daa2050f616cab4d590ecc48f10b745cc0322dacaa6970bea78306a7a12aa1ba7647a661ead8a30dc2bf5182b3336858738934497a78083541dafc67d1cee72ca24eddec4888aeab7cd7231d6f73de9b993cf9757d15496dcc156f78c6fd21903071712de61f63a5ec981e2c1951711222eb7f8bf2ad080794eb311b96f1d3e98c1335c80ca176d2941fb93c18a829ff0678c339d571af874b33f03520c534fffd46a94fbb5bddb12654f9b64c7621eab3224d39986a42d5b33da1d05491c6126a510303243b78a237952ed8cb45943069d26afcd032be856ab46f320294e45a7a2cc5ef9cc0f0b245e54c862311b65175ef96f151a39f8570b792ba13e92c941a7ef2d7d8f4d07d6265be0dccdb3bee7c245b9d962793b23999f6056fbb985a72a99ceee78ca2d6488b5eb7ca061261e814ca253c10690a6bf3f8f5ef34548ee38de748f8fda9e124bf2ce760e24c6a5d2bbf411a1bda3a67c5b45b573741cfe6b417b72fdc55ea2795dac4403fd6bc1408cabf0df9d4083125330c0916fdaf95d5d5bed9370f13dc9a9073f9aa9716aceeb40a5ae64c7db032b4cc92438bf911d5bcb81e97c03a2a16829802de9975cfcf3255a8ab138a0fa513f6bfbb263fcf32a29b111b179e0d3776d04331aaf925608cde44bee2b41880d544fe1c84d769e1e94427f298b50d52516e549ebab5ccbe2aff6097ea2e18681f625f57364bae5446289952dc964e76d173987a83b8846d4f718cea386215b615144cea451d03ada622bdcf5d70cef89db4020044dd6ede6363731557b3bd3ae4b329e545545a9adedc34dda42c38973f4b9b9e3bcf3125589345e469b97cb981144a6c2abf0306917d6a537e22df410de49e6837f996f1cbb122f172114b39ead3779bb1e2d2ae97ae806f5392e01872e5829602038ef53e27ba1e38a097e148871a78568f6d3bc813e4bb32fa7f1dc5d1f53de0d94d3c66c290c314449fb9e185aee324dcf8031d9470798c4bf7b1fe1f8ff785adeb3644cdd0ff5a67445c481b2f31e17609f696d6a2cdd64c0df182792817a2a42d5cb080a28452419b4084a3496c79b7540dc208c082c50bac70c7bd38ebf4a2aca2341e682f17fe3f65b3ef12f7fc23195a8cfa546fee77b7c634c1cc5ae525980950a39d564959e79874a5bc5d675459fe2de8cb92506605726cb49eaf809dd149a6da46160dfedfab83f328a6ce878ebaab980c4f7a69c6563045b61c8ad4d6c001e10c1945e912cf26861708b51d902d7026e0f543317a5ff9def006b272a32820ce0ba4849d280a21f76ff67103a02a45aab4fb82909c0789d459e41ea4245163ab5d9646c1c033c29a3442d85aa5cb6e7f4baaec8a0b09eba7e2686e535e060ce76336e43ccfc38e8e572b4ab4106c14eeae7d089d4691e5c76ffc3b0d406a6fb175c0d12c5ef9ff4ae677bcffc6fe1d3114a9ad523760db203158d5d0f96d94478c6282117035f3307a75e680b434478631d5a16c7ffa94d7d4e691b3d536c51d114413d691c506eb24f5adecf79d31e85451115f598c3eca8e4982a2a4cb99381499a4575872eb8f7a3955ffa0bca07e69849fe78f1bc4703997cc77b1fb185fc55b3f34490bf0e7bd8946861d6525cb3e60ee285f6c31c8b901d78f9af3adf256396234ec3fa0ca9b0a61d2fdcc90da7de72fd18ec7897557cbe97b4b4e8584b9bf81f3ed12958ce26aacca62121a4f4bd3512d52cb3bd6ea0fe44a23802af18c4ae87f69277d7cf5cc94a8b3b7bfb979f501d72d8913caea7787b9975b227f1c7cc98f71377020b2cf3b78fb21c5d9962aed360f040da1cb5781cfa8af6e44597cb0b1e8eac429808def6113829a823d7cacba16d1f5985ffc03b7b490e7e8c69a30b9d0ea0045f1160713f38a28c6a8b926378c17ed654c7539f488d1cfdaf9ffe9ef6ba4b5721a7ed5cd888271c28e03f3235e67deca9023f6e5b7ecaab8d29dcefab20e637bc21f304411b769950ff4a7f5c4c0f060f3f1c08e8183a5d5c9729949509f503d73a18ba012194da4799ea3a0aa88026ece0334215a26792da859de2ff695206daa449317810828fb9a6253dbda08d9f5791b1f1474239fac0387f7cdbe85e28c95b8fe4655f4e35d1960f09f8536549855d10f33a7c79b4e3ee7372073393cf5cee4d1148a7ecbe448538fb494586ba5c7f94fc23903d8b5b2aa60dcac5647f4669be5252bb33115b9fac5377fdeac8ddc9c298b38cfa0b55f5f6a3cdd5d606446bde4272e5e5bf184e851eb9b52346ef678f8d761597245615a96f5fc7478f82e96a144e0ebf1c2ac10e2e6994f07b14c259a234b634555a8bd514de26db8c8e14a35865a89c830518e3cf76700f9752037758402bba5a83552fe368fef0afcb148c45ac4beabb60c40d50e6730daabb6e8702c27c8c0be7124e325174086ae73fc16b20d38dee419c6dcf5395c771733bee79bef093748a2613998ffbf05162ba739f4dc76149ee9c959d839214d48dffe5d76627c982d42c87caf0aac2305f36278f6f0e11614585446b5ecef24c300bf0dfce4ca244e3875b9b0bbd6a8f9338da6d644951fa9639a1145201e78ef7c47ef342ad49962e3c0b04a1ad408b26109f6465bd54556a23b60a340d66ecb04aa517fb2045a3a4bae231bbb9033eab9421548fb98663c39eb776128c441a33995d815d886342bbf2cb96db5f86f5bbd9bdf7591f7664bb884ed46da350aa5a62b40bc607f156f27fdc2af15ffd33b296f9308e708a69e381ee7aca5ec823886762f2838218205e3e3d405c60ebe8a200aae9c3a596698be213827a5136996b2147a4d2ec2578267cda20527f384b6e3982a09854a361e4dc206cd57ea97e07384954476b2f427e03fab78a9cfd3f720d27c9c9f80c8d6ab6a6c9d362a1b3a264bbcfd5d3bd0ce94ab5c4335c50317d0e5050b743bf3c5e005b9443bce0c7f11640e6824f355a6b2b1333401d73875e077432d5a188474222d5a27e98aa1089a407fe753f53fb9a11c2fb5bd68e910d8a1d0eb95ee20566241055dbeb0c1664bbd688d19a96d2f55a458f1a2556f919842b423e65e00386c203315e7a557b8ad979c55d60ec3f15ab41a775bb420451670145cb40eac69f4dedf84e3f416bc689ddc7b53ecea7b58fef6f1fe61d9f87bbe1e8809baaa823bb528c379a8a31cdb664cdfc19029125440d568cd736ccc0ce650e1f9c1290b7d4a8187d0d8206fb19348ad70763cb75aec03c8dcd0c74e33f6ef817b20f667356d0145898607983070c84182bb3f90aff033c18ff1b509f88da496dfffa06bb9999d3c00a2aad25b6ea8ec9d89b08151bd725065a99ab4647d14e16ca19a3d4d61cbd476ab895d485bd01025046a3cca72861d39f3db1bf26c4b691425b07dc0f48403cdaf39dd906421859ee03da27da2978ceb1251fbbb9698ff158d4920cc38bd553d8be8ea058681da60a14690ab5f7490df1c579e07c9e9b025ed9e57e20fce7d1bcea97e30fd9ad8d349f7bf918f3060110cff2aa8421637f8f898f35b9246bdbe2e5845635d669fdd142ec9ad1b78e2b432c07b6e99c510ffdf004f71c66750dc1949fa99a2f6ce0cfae3b61b7b95ea1ced46a92c9b4f226759f46a2c4c5a9ea96f4051e077fc422ef18fb45a115117588a15390376f6307e8799aa152c23a02f08b76363a804fdc7a5da83ca0692be3d1993e5039e33c7901551d112df5afea1cf748bbbae9069bf79ef5c21b0d0e186442cf76aebb52a59d5cfa3d677a1416b0026cd8095063425b156ec4d564bda151aca9626b393db11570b3a4dd9966d7189f0c767b09895e6a33ce49340c4ed8a43f2d077495360adad8b735908f463e0b3c8c82376411bf53f63f31ccd52be2c070d6b0ede24c11bb3456fe6a00b25385a5763ae21ecacd306b285229b1aa324b45279208d6c32b9c5216e842af3de3b75338f141162678e9ea4ecfc876b675080b37a3b094a2f39520a3406c558ecfcd59e996af0b35253cc6370e6589ecd4771278f236cde9c662271cb28c2a10e38c1560ee73cdc11f5afd0d9b85289b0420755746afb1c7e422a2dc1186a63e91b034c5f1886c1f88d18cf7cc389f709fa8d4c2b7c02711c63ae9391a52112baa21d653cc7406b65e7132009479ff1f20c0394733ad5eb33be3e5fa7817f60e68d1c129779842233e8cca7621a5419859b96a544010944984feb8382bcce3caeec60b3df6be811d328bcfe1fe816abff3075f05697611f655394dcfdc6bc58dfe724e9cec805e2dfe513be5ba11663a4427b523d80c1efcae28ae60748576a622c252eef19219a647b91d3855c05a60a1dcc9909c40ef2418178e10b2a3d5ecf98e4478eb6215db237e79f1c8808ce9a38d53cdc0321bae5d089521432306363556e274156da805114c16aac1eebc0509d5773384f804848c38099e32ca9d50ff528b49a21442e1b7c8f5badeb9d75b1dc8c12180c5452ce740d717423babd7f45680bf4fe0f7819f06280f7e74cd3deb0a2f3b33ba9d09001ab93b1866042a2fdc938c9e9508369f8a4113454807250a9e4401030b1122b4c6bc2ae6cae48c5e806c965c251cc13755c13a0546a76767580055432e6823f2178c64b3c01408d4f2ada312344f3913e87d95f37c376dc324de56122774297161c2da2ebee42bbfceba8c92aa1637bfa4e9b0edc1809b0eae9aa37c9376ed9754337001df7d0b27858f21782b9dc81846972665f44f7bb0c26262cb8772e50bc9bc193eec40ab788d4258ee3fb0491b074cb52ea5f89e9a3730a8ff5ba7f064f6337f3cf0103c54d1ab7cb6a6e8c3dba046354225ac63cd2a26d681a7c8c06ddbdc5c5aa8be2eb440cddb940644ad8eac219ce40f40ce6731984044c87c75454d478a518753b4a9a72514903c02b1bc6ed2eea6f9e40a003ca54730ea2ea9c9750bdc72d11894ef20698054539ca2400f9d67d7cb9648a1cf3c7a09ae8cb65089b6973a0f90de3300ee9ad2bbe74569c2b826bab3c664b6b5e698c1c50e768740a95c107bdcd528ea28c91856ff297695dd8f77299021adb8a269791a83777a699d2c2e5183100a6b2eb0fd5e4325a44650faab201aea4d68dbe834443f481bf37a27d97c5d0e2c609794558255f488ce8d973f5a0ea91c3b311cfc1c4baa902c30017b377ff6d325d66cd6252c0236925377f7ac5c10b97c49b76e0927863cfaa58ccec3661c28c9a96a5b5c09b402d4245fb8c873a82311983812af0f07c80a01953570fe8db2fd57ac086500aa2b7f13a8a21d7dc3ea72814471c1472743e61e7d7c7d9418e67301baf221af265051caea32db56eb8abd1bb66c68c3e087e037d3cec1d07b09d9fee66fa8c443c731adf86963048abd2d8f920ca17ac3802f4c2ad0507f0b00fa298cf7262ce4b68c9efa5562888a86c4b72079d7adbd82ad942f8278ce8079999772b12b79820c02dc6a665025d223a05e689c9fb287e5be78ec6c22847da2cc3af1274d9c07cfc2d3ca52c960a0af635bfe738db05989a2eaa13e508fc7e317f086bbb82e5a621b701d113ab26f1f1860e24c1d778ed32284b0391ff2afd9f36aeaa8eceade8b20aa58f1eb8aa4c8bc4d45c2bb576b209f420b16d54affe788f675281366cfb04ae1bd936cffcf2c5545cc77a481fa44a385610fa7ee931c1c9a2e53326ab68ae935ebc43c61de0babdbc1c211a1da1d3f608b9841adf41426e5c129b67f7a007ebcb9f86bf95f70712037c11fe99d2cacbd2a719b6dd096c9a14716118b78b013e37d0620f7c2f8695b7ed0c60ab33ccf4ca011831c32749ad5921361c34479d925e454c91d08e9494d0fa4d100d58efaddf3674f7a81bf74081eeda5d4bc3dc9742d7453e77729acc2b3a5f5b12670b54acd7cd78bf1023d8ebf7251404874a465eb8b0c600b174865052ceb6e715473e36c13c85c29678de0681d596085835403dff2fbc5a2b215f4e105ab289fbb5fa794bb1bed93718b01a746a668809e7577d596d5c5b2e887308c83bd60db01cb9679f8d3abea9ff04e4c15b19469c7f7bb38a48ee8c612ab7daf82b892d33438ba3fa9c41ea876563343b7da15e342987e344add2d07a20125d0c54cae96179262036c37762b4c22f7a48544c7020323c85950a9210a3f9d586031ae0375f39aafec6ef13d44c3ea67b1a42751f8a631359b64215544eddf722d34f43e81844921a59b924069f39b5b3826e97bc1aad33142ef63b4306b2f7b150306b16f103c55bce35aab662c1c18b6f66f344cead86644706deed609acd6f6c700a0099e646b73f4436df108ffa004dfb0cdd8a7431e385d4d01b71a4c5f8deaacaab11ae13f3fb1aed5d89cd47b12ad9cf2cfb6589ce13b73d90e449c4e9b5c1ed757244557ee4e752e9cf9b2b172093358259c38052246825a8a45ac076aa516f59c3fa7a6ba59f01d734b2a27c03edc3717068471994f1ba41cdc3f29761dbe4bdcbf6f16445d91dc7e06e2a1a40457b6cd38a6f366c95c2568f06bd56b1f0bc96f63c5672b97bd1bc9483b30ff2adb2c9e28d8ad258ce55743526cd9148abceacc863eac4bf5fa7754d084570f47c8e7c05c667b83afb0d3f11a577daf1bfd1da2aa1a080b71718f3e89f6a03128bffe84315b3ced16b63c597c70cb2fb1b978bfce5d58ee351100018f68d0d445aca040ec85c10daa4e5aac5ca8cc8028047f5b3339a78f9ff51eb6e61348216b334fa526f25c392c6a6dc566c73342a0187d69d4b17108b85537980aa9c85610875bc2767d6241a183b1ce3e0835c737fab001f18658b4649061f1aac7ebb2e6ee24124e5642a94430f1b30cc1afe3acbe949a93b0e5cf28c8123bf8bd5d839c0829d756079680464c00d3685627f30e7bc114017e06027b10b4900873690c2b5d315ac55307bd7a043d3feda9a358e7c925f9b424b4e65f310dcdfd27c5b71ef3c8558a2ce5e2f9365ceb8a1578d5018e83843494a0a2e7386e1f273a630caba8f319b9be9c8a99258d5ea87bc7e16dbdaf505526138bbdfd4534ecebef9a76782bebbacff88107060560fabff97c77b797c941880764393c29684259bd0b604a15a02801cfbece9378404ece1c4347d63447853bc62b30c364167c1876ddc7f5f9d067ca7930aa13bbe9d2bcf99646e46838e28e5a980cf19a41dfe6a4d51d369b335062a8e82fe0856b931c167d5ef876c3ee321c0fcd07c72e361aa67cbb25bac9318d491eabee4fd0590c6593a6892708bc6e4fc1314a4202820bc381f1802529f70df65805dd23a0ea8115986429127e94c02a367fbecb631d3191392e5177492a020c6eed33419dca7253cb789612e9564c42d6fded62021b9f0625e5240443118779c0be7438645633164a4c2b3467aa9402e5c8aa1317c83068b45134765255d8504b2c7c9e7940c2e9747d0d89ed835ee857bc9a6ab9a10788cc13a22625e94fe6778f9163da8ff85f5bb5462ac96854d57fd5d3847e8f197d2df15e9efe24ecfe11584d4d44c5d8a3b778dcbf425768fd1cb386a769fe88e2a63cc4ba5e7b003fd4a8a769f817dc8d3947a79654ea06578f4ebaa86b552e9783d99937b0b7a5dc5cd80c69d2e3941348736d562cdeb4a30403447dc01059f1a2e7b7c039c06944dfb36f5270ba73e93a550961e8df08572c4bd336f4b0007261273a384c98b3093f09eebd285b0520d0849e23c1896f4c5f2d5b2ceb7447eac36eecad28328d3e8014886954f9e50a60a95df72e29c490296829f6794b9d95949711a08f9395b275025e2bb3d603e9143644e61bf0a2911a930f29e15c9d7be9c071580a9575c4ebeaf9a2ed89f1a4dfd5cf0db56a57d92dfe735f164b08738223acd1f1d465aa46bb64cc3afcf74531d8552ddd15fd0a1286c06aa0026b8500c1dd6701b7090983a3cea995b4fc74489c7b46ec645c483d3658bca7d9b9cd4f2e1791777ef84f8999cf28269b5e940645529b0bb0897b89eb8735c5eca33e4480623e44896f56d6c219656cba0905e2efe8658b4a015e586f361f29b87b4a738b63340dfeb44d67e0015919b4a7c4fce9590cfaa50497eb18716ea31c329d558a37d61d0a32045c0214349d8701b3f6cf4ba639be60e6a85bbda4f5b65dbd8a010fe8ad7ac029a4db5f0413e3139e252f1524090d1325c187a205ccaa42ffea6585c7e0e594985f4652d4569242addd42830ff288c5fa750d48ec981bed3b08a691c4fb517bee4985b8de12638ed7df237b327ad9d497dd11759eb4b2546bcf11810c9a8b4c8b674694b5a69760227d03c727e2fa95bedf7873d9a88772b76974981e647709afec10cef7252bf543feb8d339b3d6aa9c76be997a3e438ed23534e9160441a064cad0df3b8d0d24939f5a864f3bb20f902c41d40f0b3d8d6803b3afd15fa1d3cbc0ea707c33096d208e0723b195637d6fc6364996d85b4c6eb7e702e9df7c7bcaf1250e060fd4d6802a0cedd077f58452530a4abab5264f4b580281fd1246ecd7117ae052495b1931dd700219b901e84db6f6088e542caa18f72d37901fefc79689b2807b401201af26c8313c317cc9e5d23dfe7c4b3843be76c312d2bb93ac17296b967bf319fe0d547a2b83af666b42a3e0d6244936596003c047c1455243cb61a7d172b955a41028b8ecd2deeb7b32870f091c90105d79960923cc0e6c5e9e858351e7cca7ad8a1200038f0c967be4fd4c067ddd0c69cbea00bdb01d25d308154c31a2f3945cbd1035176a72d93bb531baa20133e396df6cbf088c04dd9e07dfa8804ccd235d47cdda2dae4e2f5d974a3fd4f5c5e45bc983d9b10c9d99b8dd17e743dbd481403846d023abda15f5a404a69351d003f8272edab34503972a60a616d76ad5e233dbbc40715295556ebf686b941d6c1fd61466051148d974f7840cb3e02c53b50e97a4ff363d4a53077fa707ea968f90461df3e97fa18651645ecde6d6defbda54c52069205a005d6053154840ba434826ff34f94c8d3d764bfe4335da6b0f4859b6c2d0cd30bb4e99c02b77f08393a3ff9accb899c822fba8dffddf427a6a11cda77f80cff6d92139d2439ec964832fd4b92d8efc88187e559d889ac680e7c86436c39cff516af7845d4798e33878df173c83ab285d21aa9d96ee57993556b5231157e930a106ec4dc6a53f9cb47c94fb15f07b85f81173a02dea4ebfc48e839f4f7ffbf45859d510f57fac2505b84df7ca71a69cbb46801b62623e1d6caf7a65b2b530f565a75cf39124e6f930c5b7218675bd807d701a831f620058a13433ed3a2d5a18dafd346a5f49fc04929bab26e565796bd8f3b0035f67b319a02559d46dc74ef9a62288b1d801a6ffbf745fc77e30fd111c25d84df6e1445383db13dd8e9df5996cb9b2c194eca803df25fd195c283215c9798787eeced93fa2dd6e2c7c41781c6c4094712457fb1569ee89dc3a40b57f36044fb9f2871bb411c2927de1de69641e9f0c731ddeb6b345159897290c1c8513cd1cb630726572badf8e297b60df574ef1a84e84aeb5caa713e13c957679902e60ec167e2d36ce8bc81f8392572fe9297109f84bdc49f893eb3e9c2c009596b7cf45af4fa51141f952a21be288aa3489221ee683fdf67e22ff9288a3f8a4f0113edafdbe8fb248e2f6251fc514c41d0bad18170a2782f056b963985b25086933c86ad002ae0b61bd19ce480accf8cc222fa5a13455503ca69518839843703934a640bcc5947084d512dd627508e517878c2bdf73ed0694a7e490a84c8a3afae46b6e4bd17c7a4f4fd8cb3b539678b2db6388b18638c7328ea10873e628c49ac628cb13531c67875a4383cd2b7e42eee10fbc6e8ab0edbaf718b1bbbdb0fafd8c24bfebde35f58698aa2288aa228c6d9e18d10d2100d48ed2cfce00031dd210436bea98ba228a2f73caf949e19c270b617e71c9e4038dcf80c01279dc136e1065ea2c9c2759c61fb8e8e347e7e9c66f043dbdf062a29d168b399c5d8ea25233bcb6f9391f9c40edfceb2f5608736994c1473cea2b596dcff82c1de6efb3074c88f48d0bc0fcad20c61f9038b41799a5afc601cca69780261a098697e6031f00d4bd9e09c73ccfcc062505e5d8c74247b1e008fa25b0f73ce9e439c91b299b168862e5e10fc339add5dbc6593eb388f9e43511465f6b31d493293f8f57218ec9626f976c425e390e48e365e11566e9504d2418209e58f77066fc0d4f8cc166abcd43c955c6ee4ef099643888f91cdee9563060e318d8dbc75dd6062f3748343030d8f466ac9c034259a054a697cf8c8debecc586f576430adf1dd9ac86042f304a359a09441083819a6a27404dbf2ac846c95a4ddb18241faa873c332538525ac5295647ca18bb6e55545953b3f559a685b5e0f18625b9e151c5fafc4eeee6163111b47608fb089ad3d4fd0f789029ba6d19ce6b4ad60883b5aa53191610598609f4b1cc447bb96cff05fae223de4cb3e990c3bd01ee127497c7a90729e264e788042021f8cd9b73ce8409f51c0448be2bdf802e56059a7b446aadeedec38dcf35ba375b788f172760f8bc2508eed290a77c4094ee39a843c2b385bbd50b720395de8b7c991548d0befbdd70313cdc7dde6239bef7a9fee3a82cfee0839ebd9aa71fb3af97eef8a8ff25f47354ee7709b54492d028d56354ee31c49bd6b902e9d7324d5e6bf4f299a5a3cdd75e6eeeeee79f597de9d7ffe922fcb2f233fe3d18579ae84b6ca81c99aed46dbbdc98bed2f6bc2c2f68fe064f237c324078793c981669692dd4c0970c9952749251b6608c1c9e4e1dd43d6b002d41a3098608cee4a922472367ea29309bfbbbbfb1615b6ebedeeee9ee164f23c81c54ac243c2b5f10f75757023a5ad8ab020032d476a1cd1b2a918dbffa7d26cff199229db9fa6b4848167e7e2d67585515a23e7e07e4504cff6cf9e0bb33de701a9284568ec5e91ad1d4f3d2369b6bfd0c9e466a280824010f9b2f1eb9309cbaaca7011d2a66a4812224fdb3f16bb950cde7e5e703cd97989e2e30507ee691ce113f3c22ecc13db385e6939bfc871f305888543c455b9a8dae1831c75f8175453c38e6ecc3edbd39c60092448c140645c1821406b982e5d4c847c41ae8c686c8ef0c850e73fa99d150b9e6f8cddac5e90a9fa33c4ca05aeeb77fe742c6c3d6c38ba05f379b067b5c2d7eb62a3c7cbea0a92b2550baf576466fcaec0f8aec4b059f7dd70efbd5f001e6cf6558d783cb68832f62837032f4a6b14667ca3d0d8324604963c60b240c196ab066f46be2fee48ada8655404965a19ee96e4f8d44a310b1733346ae5c8c40b9f5a499a71643ca9d92d5954606a6193919a5a98eacc46679885dddfb9d1f1a2965123353577af533a06b6c9eebaac6d6a2a622cdc89d4afa642003dc0bca8e5c76893f5d554582eb59c4ee5bb4bfc4308554dc5cc049d8ea69b829dae9a8a198e5707c53d3d6e74dc6a4d269c1a5c3515b8aa76ff92963cb3e505aa1a464b2f3547ef56e14ed77d85e52093893ea4f588c37bc72c8e1f3e467398ef95d27b53de30b41c6432d187b41ecdbcad4d82fdab6ee4476e36a1d68eb023ec88fc229a4332c9c88f4e266c6d6833766bed0bdbdb3d6d0394315445b1ad7e6b5d2ba3f86e7b5e3218638c02e312f885f10bbffe7c200b74a2260cffebf57a2d71809342c0e6638c4dfc7a8c456c6ccbf2bebc2ccbdfc0ee322d61a8fa1bf6248aaab07fa1e28f4e9b445d6b8fe2120e330ebbdc762eb5119d73892ca6aa053b7f92ea40517c8dc68e7e9eb464efbe8d22e4bd9493803eff9073f024d21eddcfda02a50cb423bd2a62677bc5170e0d607798aae64892e779fe06769f290782ec3344d517d11355c387954edb2cc7878dff4255f7edd1f4990d730ac21d73646b2d699568d5eeee2f1580038c4fa6579af7936418865f5e993dba3f7e0639f406f9d10c7ee4dff8bca718aac1779f06b0afd7eb64826518f9426ffb332e6169110776c37e03bb61efb45fe8455514fbeafb7a1f455475ad9dafe9b38b9f94f6add1ef4e712b3b2e974cd537786eb4bd0a140d93be8defcdf2d9fd25a7c2494092c7f3f9b27e5b4d6f90938ce5339cb37c86b3cf8ea0ba6702f2cea903b78a575c0b5312878ff04fab1edcd891ba489f15eba5f5520036b405515aa3250e50e024f3b1b55663251aae2467304dc34a8e8a90376e21a2f709ca6718e38b23772d440afac48e037c847928fc08bf4972b024897da28b6d4a123348401991a4d632d9ff6c66adfd3f51f8cc43a4a09f445bec7638c541c2ec17a8efdb8c4568c11f861de0cf8fd322ecb4fd64baa1187e51986a30eefbf7efb6e02ad186b8d3687857da2f2d6a81bbadf97eb4a6e0a6d5bcb7bd4a349fe57dfffa28ef0beddbf6a86cf9ea4b616d513b089fa71b756f17676f968d315a78beb323700e1fd91bb480155c18d27887ad256bd5d9c598e4599fc5abdbd809e6e3a0a0192de84b5b5a339f1a04a5eaefa0c7f0504f6b538aa03e43437f8131df5176412e7f8702dab647c5665fc78db19c73ce262d168b415d6006a1954f1757d0674c772be7abcbe5ec6b4cbb66bb8ca1c927fa9cf3cbccb76ebe7533278bbd058ee9fda537cb66157d86542855b5ec8b5208487243aa14f41adeee215495a1f80245201291df0c7a7b76f0eb6a81eeb6a786f402774092c45d386623455717e6b044ab178871b9e548d6c476a74b39030f3aedc1895667b25ff2526ddaa6cd419f3fc5f5fddfcb548a1798b384b25294a208345abd595bbd58dbddff062fd66de233718a0dcabfac953fef9cdeac2c5ad0e7183ad35023aca07fd92c2c0f4460c92e96eccc291ef6af1f316048519cc873d3b95224732ef644a94a664887d25495edd8634873507a814279c88d021e6f4204330d18ec96a08d7c5696d9080201b8d0f981be8c4089fecb551424f4425f14f4426951d0e71d94de1c6c8b4a46e656ce3608bd4021f406af0f07a5463ed3c0770876446ea36ff002b7b0dff3b423507e0dc6ad1c4c2fd0681b85af51f536d9fe01b510e9dd619889d983489b2e20c2d5559ba5970a1f95e975275df4acdffd91e35b2e9ff9d5f2ddb30177f64bf865e2e843a44db64a4ded28bd3b7c04e26769d3f55571215803915e2a2d470a53cfddfb6f4958a4fcf78a20d04b7577f8c8b99c8fe7ec1afdaabeb7e83451b4ab7d787b9a20c01daa5fcd8387f7bf541f3ea01e509907b4113a4369525254095d5241df473ba025644424404fa028c4e8acacfbf31f9f8d530e68111a020afa6e08809696a1f7e9daf091ff871bf79601bdb8304036b47a7f9e66fb772db90450fc754ffb0fa118d0144bcb9c82fc65f4a06041b9b2da73b3562b94d51edbb5e8be1beac99154bf637b31ba1cc9b7b6d11195b6e1c98496c11f6c68fbb135da62c1a4f467204e32ff94c08d2e128bc4748e0c0b951093ed691b9d437294a53b2ef6eeacdb90dbd71fdd1945b73d9946df69f159fe3952bef2d97d114db49a7d57192bbb5f89f8a1d53c4526cb37ffbccb3c28ed5a7c76dffffed99ee6cc6687935cdd659ef3b4e80ca4e08856f3943cc5918a6816d0d2055832bcbc9d5335dc39e3edf955e7ddfd4eb4ea360cdbf6a06e3b7ffebd9e71ffdcd6f766454f935bcddbfadce4e1e9bcadcf8d9dec3395965c1c510e4af8bde1a49cc61edd8743bab0efe70fdc7092ad91fafe2880ca38139081e1483671f7287a4605dcdae59dfe230a827ffed2f198c70df08fa9ea8f81bbc70f476066e3b31bda0cc3ddb35f1c3b3b8a84535b3aea54fb1231d57bcd7b2a20d7cc34dffbe98f67332ffff24fd47578bd7d1d845e120dd1342d2859bbe470dca123c7312453d28e184754d5fb83f0bef03bd54a12cda9ea3b7cb1c804f9452648f2853ad596f02bbf48a2b6166e704f99c597cc6c7498929bc4e9fdd38afd0ec1755d6368c837b6ff05bb755da320584d1fdbdf0253b7ae2b0c9b93ed3f00dccbcaf617c04b47f2b67f0082ebbabaa00a7ddb9ff65bd795c6ee2566fb5740aeebbaf2e8117d20f863b1fd47fcd6753d2178dad8fe227cebbae288e5b63f05bb755d6940652bdb3f046e5dd71936fc65fb1fd9d675bd812bb5b6ff6cd4852fd8d9fe2082ebba463939596cff0fbf755d73f8cc1bdbdf836f5dd7a8df9964fb1b89bb755d4df02cdb7f0251b7aeebcdd7730fd6f64f45dcbaae26b80cbd676bfba321aedcd367fb3f8ea15fccb6fd3be85e44b6bf04bb755d83ec205061fb47f03bcf6c7f0e19471424f904b77f11fe69e0f367fb43807debba42ad619f19db7f03de6978d2b1fd65389bd4f6d7a0e1361261c7895bb67f86e0baae3622ddcb6afb0ffdd675b571a18c67b63f06dfbaaeb6ddab4f70fb0bdd34f8f4bafd836810fdc8dbf6d7d7b7aeab0ea01091ed1fb3ad57f7e407ccf63f67d8463f68b6bf695bd7b5060e989f39dbbf5c897c907efe6c7f58705dd719e38cedff32410ab663fb93795dd7550713a1a9ed3fd2e0915db6bf3843836f1cb3fd431bd1efc566fbe7185b996bfb631a1aba82e4953f7fb6bfdb64eb6bc6f6bfeeb24d9b627a92a961bbb8f2d8b98495d54589628be2e50e1f24bcfbf1673585708e73f1a40cbae0d95e4436dcd619a0383c2edcebd563a1ccd51c2e1d49e27e5a3c80706758705185c13a6362bb2d315cbb17de8dab1a2abdaa0972f5882a08d6e9f29be3e23722e88b0304f2c9b1113cc5a048c52546a587ab4f0436db5410db94173c50a76f3582643532068f0d8b2b9d0ec4e830c1832bb9e08c7421b9fe7eb9df6f0c1e2727d04ed4d5c10a5e9de0333be87e30b6a8f0fc62ba2b2b9d1e3cc192c44ec4f5d25c61b158cf10178ab901e9c46491a1857c3a38a7edaa05aebc527441382c4e1f1b16ecfc6243c12fc0386be6e4d1bd6c9775851e9f15bab410c3adc083b142558b1d04b1a0af0d96569edfa90117b40ae3e3a2cb132475941d5fa420f94285f5254a903c5de66e0c2e471e3d6b68ead86099f344be569e8f383f563db65128d8e3d1d13245cf6dc410cc412c41204f70e268abf3428feee5bed176c685d7ef0c103d50827666bcfc5838b27bc17eab1c3de7afcd961e9f0e5a833728df0d14f4fcb20eceed891738595ee0e0f400853ae0d617567e557e02b21ccc8b9f912a9d602d4e519a50d9f510d3e5061c0a20a162430ad58a3441462c615080b97291c38b983a5ca4baf22c6047c20a5caed8c951c9912cf08ad71c0f2e1158af023b65ca64d932c50b551ba9b185fd43c7d3947032921c4c485eed8fce9f13e0dca25a50a148e9c38b885e9a381141218c6f2a09162a5052211f7c8bc06f05307fb666bc8002e31af3811f7dc0bc0066cb8aab22641c8c070645835483ef6405a9f4e8e1b952c2ad058cce0c0c3e42a06d7b7ba0acca34f9486ed4c282d46b489fdc1b2e920b1df10d0ba90e537aa854056bf0dee499a560664a1f1f58807ce131b4040415a9292c2b27b4d8d1e7015645aa604921cad7a64899524b1136e1141cc1b6555051b6b96d151499a8110fd612c105172a177ab489b3239f308f9205f7b16427868d0f1b2c0f007325125c059d234707e5094c982c52b00f641e3e2c3070e2953df8e5b92fe49edd6d4bce61b5cacca811d58b73cb2235069fb1f1bafcb8d2064d1f3ab07ca3c808057fc9894eae0bd80a99d4b805639158baa010626141875892656cdb1e9e2b3c74c41eac8def1963785529230709d1a78e9d29467038b9e5461e1653bec953454432d8c9ab8a4c6a94825788fdc8f3a6ca9230695ae4c22f17461da0902d52eefc294346ea87332932eec0e4b48c21d18ecedbf6ac80f418c5307b60c58ac79d40ce0b161c2540bad418c096be4985528c9c94c8c1f3c54b8cad1645388891658c1321515990cc2031d2bbcb881280282fe0ac7af4acd8725242c5ca4c941c983025d89d25fd657e0294adda9d06aa29283c3551be4ca9a94a349c84819b1c55baa2e61c6951f327b73dbdc605177841c2c3042c624c207306098b0c78ce97ba2c53ea8f4c48923d1024e1e9a9abf38896a3728b921840a6ae0aa8489eed9ffd0b98218c6643292b757eceb28d10940d4570a45d68feb89119d905e96cc49074652891608921010384e91801124192ac096c45478c6c302283c80906194646f46c0812c7c415c0c1a205334b9e80607441b6e8a8b637492243562a292aa53c9016096334554603121c19f016244788b64c0585b016293de74b36864c1962db2a1f4b76d0b6553e7c604027a4ca00853d2e5401a9b3b5a20697609a24ab9b35566bfc497f194eb2e6b620b1c6fdc936af3b2a7475e123248b19193b7c590e94a75e0b0fbc30c5cd6b4f09c465e785e094d612274e270cb1b1a70e579e3b4fb89861b63fa14366a84e8d3ab8d812a01d093a72741d124cf79c85ce10d30996f935521aadd51e0ddbf6f6e8d8af6d7b7b9468184d88fc54e1e974bce989f9f59122c60b90296b6cd8352cda904893e3277e409bdb56ddec6c55764687db56dde66cd5fa5e6434b96dd5ad8d7bd0c373c64ab06dd5adcb2eb7adba4d91fdeae01e58a70e126ed26471b375c9175cf022a4deb6f7429a3d6edb7bc10c0d8b4326585034b6588152e6e92a5c72813f575a5c5b4c52a053d300151a5175b0c4c8d3c462d991c2102a7fb6fc9c99d1686b42254e40a87a5aaea480230c919ad51ac265851b50c008c920059b9733b916e60041009d1e2538b953029029293d51ca0aa20e4d4c0c4cca1051ca1151ca92520a95224a563c12565f643d2eba5db46dcf6a6a8bdbf6ac888829877adabe1d2fc0f892e06200581028615fc9da1724d61ebbdaf5034461ad394a6b52733977a4046b8e5a2d68baf4c801c4c3c29fac5a199a18bd2fde20c9d54ad1c468d21230bc5a399a186dba59b0fc3152535176b12fa0386278b89aa31ca2d454f8bd554afba8081ab7edbfb6ed7189da15d0b6c7a5c5deb6b7058f0c3db46d6f4b9acd80d2faabb4462a6d83083b621ff519a1b4462ac66d1046e9bf041c209079207a0f69918921b3451c5e6de83dbc87b4c9c3046887088a3668780c6991090cffe13fa44d191ec33bd5ec976288e2bff835c02ff42ff4ee3234ef99ff85da1df3e90bc447472e84867fcfd797e3c994ff9ef788d62febfe3ca7f31906391abfaf5a3e33cb9c69da3d41b3cc1dd1f5d9d1c42f1f0794651a84a11c4975fce4487e579fff9c8d07bdcbf9e015b7c0b68c2f2f8ae5f1c1dafe8ee54819cabdf7965cced495d3dbe5bf2c7c1f861675007b0c7ba77d659a0098c343dde733f7278ff2a80a14e577da3955efc51803e59c56d081bb2f900353fa41a41758d400103ffb59dae4540391de5feda278976e3ace918a3ad03a2dea403bedfc4e4e3b6887fb938310941675901d87af5bbc73d087f7f0eaa5327db6e36315b0d0aa3f81787fdf89cb73805290282053ce7b09fbd3532e776f2e0bc46c06e2ef6922c4cfd2a68c82949651a894edf546b175686c00004000131600002810080884429120092345d27307140009599840745a30164804712486510c04311c840000c22008024000220e31a318d50ed7e74b2d240f98433a9bae8e5b869ce533a1cb90629b003021a9620d97d049c5f27ec0a26f469174ad554442bd56dc7fe55ea1bddde60a581dcbdec3d7503759d108bee1e274c9be15f71f235d4614ab132a9c5bc6be099c5bcbc0559185be9f8078ff524537e67d56630c77a95f6afab4a22880a996dded1620ad3fdf301d5a14cc044306ca4ed531c4c3d283629d2450139172be36139cb8ea06c56c32d133bafaafeaf524d9329f017a7428ac5f4584b61b6d98aaf71e56fa8c2872120f358c0cdfb5e9fc55f7152265b025d9f59fb872f767a6cb9ca2fdff49d6bb9ab10052f4085d716eb48f0710a45ca15c4dbecefca9e858a1c8d36476e2c6254174e2280a5ac58f5ea382e4c943ed0aa83f3bedba0e508a3ee927a3a02702546053bf97296b5c6783520c1161123fb6a3a6159c9a4403ab1664f5f64539e845be9604dfc42b7f2087827a0c1d7428d826a55ed131b6a237e61591fd8cd0a3a9c8999cb241cde80a58846cf0a1d7906e6245233835a2e992ad00368c68595f665d66454ec82f8293b12f4e04e7c157f52bdc61c148a59a7f226b0e5cc1877ea382fa3d44e01789e4d2283e063e4adb1daccbd2ec126c3c5cae2b0e258d7638f98aa3392be35813f34b15efcdb6ec95c6eeab2555e688eaffd71b702228f6c04f78cb604022da6ef2601c1dba299889acc6ffabc5ed6e3e9d8301809bbe0945d9260aee9227cbe8ed126baeb84771ba1e793b7f4f55519977341d9a14d1ae50427448ba308b56dcf9cc7433a2689b50cd4e19ea45cc4e570e94dc32b99b0f80e9e6b18945b24bb99149751534bf0b1238be72c549b77c83232ca7407b1d81b41a44218a941c6cfdb623c2f62e75cd28a8dc26ba023e2fa1eae835d54d4ed1ad36393c02f5cd5cedbb82c92b37891555ddc395e61d455599978e9ee51444adbae4e403c559b1c507423ca9e82da348d4146c7d1c31e256c15046b070a56e0fa858b5f606e71c2021cedc1f3b5d06146b27a81940431d251940cd01a6e09ecc3a805fcca530e9ec9d090c273282b180c2225c1191618ed2ba1cef22660453bd4e4e8932664235872bc9317b2e6490207d06141821aa7c67867a59b0a7c7afea8d821f78c8324c5a2f7f655886abae281881b7eaddae2e01939422bfe9e92c51c42495d5fdc4f66fd3fddcebeaed14b8afa2fcd804ba902b1a054d20dc1f26facc2992bb0a266e6cb133bcd28b892dc623e06a5f7a9978b8f317e04fc7bf28c78e7c9e01bd8929e68dadc2805caafe65fd0c743245d1b924ed0a60c17332ebcbaecb9822fa154a702fab17e28a46806595727fab8ce96554b897d32481f4c3c8ae78f4a3b29ef9f1ee12d6795df8d3b86cbe22e8948b5263e529d8b2dc48315bc189ec69b23883e2c190d7dfff63221d56cd34456ed90caf9de818e260da0b40275deaf0b8e4b254f188f03fa3353dabb28f5352c2f3d98e218d0a9d1f641360b0fd5e392af677609b00bcf78018fad3af858b068cc9a215e43263e0b55520b736ba6f1f42cb62f99296d26dc271c5a855bcec010bf33cfa8bfece32345a6777966d02fd1df6f948253829f3f15f8ce0b2578449db122da9b118454332d9f47c978412651121944debddf272979752cb05eafcba66be6316fbeacda4a6c9c1ee81bcb5c85e7cef37fe4efafa10aaa432ac544e8a78ed25ebc46fc155157b3e8c6bf6ef2d8d498c09334fc0568fbd379a14b72daae7a3e27f298dc243e4bce9a3700fa323a698571c935a9f3d8a4027422abb2f13ccb42d49b0de1c0be9178b267afde156aa3d455d1da018c3226da687649b1179b6bd5ee33ebb9422efaa9877cd7a98f5d4a5adf613122ea397b66199c32e4be593722022da1dea26e511d5a15dbf9be7cedce665a78ac0cd85dfee54d171c4ccb43dd4131a0444a063759c9c347056e97782c82fa5900c256161728376b8faa25e9f10ffd8530ad29ed383159fd4c4b5a7a35811e468d7252d6598e1086b1d62da46914e7a4f292fabe2b068b42871482c9b00d73db9756e4d628fa2e9f562adb87297c6871a87a3820464a9456341c5717a925348bfdc9b90991a0489f2d705afaf1887b9df1d7031225cba5e9b441a2be0a370b805e4487630c721b03aa9073fcf0f71817e7f3ff74404881e08eb06d761f94d73fba73c122ddf1aedffee5cbd50d81678aee7e164d7ac2dbcd843b8a80d8726ed3139e36e7e6350f5e025d9c94f0b3a8320ee8d9f271bda8e6bf08c8770b31c5248169529f6ba804e7a05ea911c5d45a6bca6eeb3dfadfd56e36491dd8c0ffd8a13b008a1c31ce0376d066dee3ae166637fbc2f19af7eb85413c72d924dde4a4871d3312683a2f91172091df9bb4919f996bbe05852e7703ccda08e4b644355192a0c81125f8499527aa1cd081ee29d4a1a90641b5b2630fe6d068af09024f0ecb910674eabf8a4961d4db21424fc55c95c93ec1da34a8c7179b7d134a0c7b2c73cafe4122d861cd2738cadc9a2e2050013b8d92041b6eeffe6c7590f681bde85cabb229167a46c24e8d03f7465538cd473e1d442fc656e54373cc793b9a1049ae73be630a03ce2f3000487bf0e54eaec3aa8a29f9a7fc01fe6f0b320306fdc85e3b2dd65341b2978a07a1c86c9ce7a9cb60459b734ac82bb250644f6249eb57150a77b63d3feb93a9a7e48560fe7420f4e0bb8e40935ad9abdb18d67602794ac8d132b9170d215631ab47a4299ab6e661e23ff0c2f92bb46639e36773c5c4dd4dcf16401ac2a30bd9fdd6c27d082cdd525c5a0a6b9e95716f8468867524c0e88e08ee9bd1d499f7c5915df0b3fe01ed28b67543e0729b50022277644739909a270b74783fd49bfc79acfc4558dafaf461e3d14ad7d3b404432f27bd3716c2eef6e1abd3568195ac573d402888fd4d1b1e7ee4d6e181cebffe7041cbf01b2fae29480798b3b80239294087d0d0ce046cabdde7bc9a17a197f4b975db2b49333e6866993dfdbaec826394669d824be03758235cad558bb623609c6ce9b564546fb11bd763f36efb2433fe85b3cf48247ef5e225a9d46eab213239fd409e41e999bc41287e10715364b066798249840afc49e4668656bacb0ef9ce6a8a8f9d1c1b42fb163db8da573aadf24b15ca8bdd8866f213c5b278a03e8043bae436d4661d8abff4a8abdb98036790be0d57d819b2968507f90faa5635c991331cad7f0b9ee6bac2ae29bb307a0a9037fe1fe3fe4fdfec0cb9251007df6ab14a05f4ac767d605c404b2b82812878d57debea002ab49e5c541a1b79f1a644481aab6300035a83ac5d72bffe2b7beffc6fe883645224b27dac1a9adbc663b01d99225a49253ae7a7fc5c420e6d2be2e8ad5d764476ece5624d89b6bb29f77679150c1c20530fffae3e4ad7fbbd0c354b692d0c35959f9b93433086699debf3e84d5967f81c57897d6c05be7e3171df02b3ac54f37eb7ac593e16b1e3a4502421d278ee242dc2665f2f3a796f16e416287f4ce2380abc7720fa3b460fa1a8ed91cc0735ea80ae095ab05b2b6047e657e3209521b505aa6a388208730a2ca140a251896b5b86a55799e5c875e62de81d677ff459f82b58328140dc19e2c0d65eef53d2b8bb86fe8025301811f1fdb2c86b660a4db4486802263c9ab974e57adc92964eb54bce039efb2c2fb5f4ee1714b5301d6cd6080532328ee499b08c1f4af902238b64be1b37d4a9aebfa18fd143429fd0818a06e2a85df841c1042756a2ed9684daec8a0b1d83892c069a7dbc659e7f271135ee73ffa1ae289107764a20538c60febedb3c33b1b34589dd95bf273d92ab99e584cd3aa124df80c3a90489b3ee6e3a8f51e83c19cc88ae3d6ed2e366f488461ef6e2e8b4d2af02c0fd24af17191f732bc141558c1b0692b926c1298dca271d1601a83e5628a36c59fe4f7f4ed26647b7f7171550465a4269fb0e739d26e3cd0c18d8a5adb3a31ccc7913a9d3525409f9c842a569570d7f9b49ddb958cbdcfb6ef50b45199b6eb33df7d5bfc8f64e0e0e1dabfc809423e94a54f7e2185c8c999d401183f2e6984f236cfc25214ddc7ff2ca690ce6d46b11e84a6e30948f5cc7f20cd6275ba4ea6487fb803a4e227461c784fbaf92a146748653af06eadc67a4131d0c67a137394d55c2e3cb3e6cb4c95093da6bc2d83f85cacb2d1d86b9b17c46896819aa8cae0237b21ad1223be80f6528cd6c83ec80b325667934b35bec094bd92d4a33397c693602091d03cee8e8e357ec2d67f3e949509f4501c7ce1815e60a5127556e9f06500b53c8dfaf13892e7856248ccbd0f891e066cd41448d7792d2e3da3ff7644876f4fc85ee4a642868c425a3c7622ff4b7eefcecc0a3c2028a88ee6ba7e0cf3fd0852de44e82a52846998446e2d67e4038371f6627e3982434730293a85322d1b5f9f16511658da0ce6f6a806979a274d0e6032ce0ae63ad2da943c0d466650a6c8fab5a134180ff77e9daa552ec3d599119797b19936844bef032edf871ce45111dd145116931cd7b09bdc2e5a5b4eb54dddcf9937b0eeb8b8cc411980c316624282807e3bc09990687570320a38c6e793bef633fa8c2c2de63120fd079405af234341e1bea0940e1ed2d31e8eb57a35b1828f2b9792d9d51a1d9394917fb3eccec4e3ecec2ef4c56ca7793804f6080f612eebe2ee39370aea60e9c1b80dcd61684e8600a8ce1d1ab819468558fdd9198aeb1a26b000f9a290baa29c894e43f17713146278b5e6e597f63d4f06a2f54732bdf4bc67b854633fc0a48310036b1ea709fa6f9f04099220f6825fc1f69581ab3bb1513137fb7903b60e4b37bc859fd6e36b42c63b1db93caa796716f33a209a96e65b38f69a3bc300aa87952e8a1fd6499c24dde75ba565d53f1c60be1edb5b9ffea45d2e0619aa1c47436ab9b9022543fd0ac93108d2897da0d34094c71b53b038409855bf36393001e29e0d7534177c729e74620f22c686ddc394ab45fa51c31cce2172b10d07a9e45ea28f284dac38e809f0ffead1ffda2a748485d38c9229a636cbedfa0fbfef08d3924ee8580969b12d994e322403e9c813e6f4586d67e4a3a5e578d76aa451086182299e1a29f0d8f422ebff9cf4b2dd62107fc3ed0a9b0b5768901d92aae91eb03ff53089c29684391751bdf68fc4058ae2ce110a8963769e795ceaff82ec9ca6eac5eed0f0861c9380a0f1f474f05ed500a25c23aaad2baa93e87a297fd2c5a1d30ad01b810539c67fe800a2e85f614f21ff76034e6655eb23be4249fc277a510afbf8781e984e22f5986035e690e6744529c8f6e0bd825713ac660c09451e2c1e294289aaaf2d1c7d355f2d06f52fb2bb74842b82e4ac8458f24c256d7ce4650e233632e06af4f5024333969ae3a49e8cffab1e8f42b9a1d8de784b538044df1d90dbdc5709bf37a2c2843d5b99bf81994bad0f85dbff61b55fe5ef3a466a36d1c8a3ad8ea36eb897efb0b8aff9e63417593c598af1adff2fd3bdc6c3708335a1c0fe6bdfb53c76209d9ee94c7c838e4099af7fdbf89b29cf8cdd4c23a5154f28dfe18c26977f7306ee8acb9db3fac924f11f69fb7035d605c0534e97365733207382e493414b8b59e241bd860841fe3e4329351d3fd44dd4b0698463418464911a83cd6aa298abbdd00860456443cc892d0d30952f90b605bfa607c4932e8885832be2402e84c00d484d922615dd6da84e4cf6337dff208e9f7b1930c417b1c6dde4bd2b213f3bf2252f1b468f415c37c599cec961232584b1126b446d5881bffbacb3bda4f244f73bd51f6d5759251262363952275a124cdd92210b74f072f8b08006622098582cf653f3717fdd18a9c1f0528cd4b76c1d4a0e211882f9082983bfc8b6662b67cb17924886c9d6b84f18f59cf03c23f8787b8fa61a8c4c9e946f9a3a8388677dd6a4b2c8ab3aed1ee18228f239994e90d37a3a8e26f1005757babc26798924848be3c25aebd503f4d2198e74d282ab06620cdb234977852de0c4dcaa071879b1832e5155493a3dcb7e8108c7fd1fabc173e4c3b6dc360b8c1bf0cef1d3600ee279e73d009dfa1211e1382866053c5e3ee643f1ec4b8a66dd797ca82859cd0e21ca1012b6e006597c5d9edaf377f9330dde3e8e5b7f46d7d9fe1ee23d440a5ebe408211f8d50d21723b1f3d11253ef99cc558760cb026820b30400f896d0c11a77f9f1eb4151208063a0f4171211b2e5cb14469f3b19dbf778b13203b3c441b743faa5aa69ab729dfe636ee4759081534a17cad1cb75b89b1fc8e7e45ec0560cceaa4384a7c9c289b7e81e07cd2d949862d9c46aac447d9030de21c10f4be854aa090dd29eba0c48f8aa8a14af04de0e095f405d339e7fb5d76a5f9188e6e55527c00b94f20c32240288878468a5cb31c8dc7be384cd40b5c321a09986d60c540f64e2789eb378bcf200d86544ac2702f10c028174dbd19ee8599b8e27b90d651e2d4a2417390851d1ff7b886b3bdc737c62a382774bb792ee7636650fd93e1b21cafd3a79628a9c4ac6702f6c4a8029049e704ca19d84bf506abfe0b21f50bd6fb478421b1ecde21f062c70a37a2c3f297f6f65c64435cc041e26360d95a7cb285a0b21537dfefb334c4502c7ed3210c590a4bcdd7104e0569d56b14aba1ef57f644361067365839869cb0c72756b89d6f962ce7d40e530c3fbebc126f48aceba1b21b0ee716fc347e1732ac134f874f085a174eb7d7d8c0663385dd1d3468c0850ffedc7eb11cf6a1056210a6dddefb3430a221e31c1c067e1857036b86759321c32b1f872ec65fd848e506a1876ce1dce3404b42af626c0acbccc6a65ba8b636daf822f88662f7674e43f4c29a42c54ea4c36549e106808606547f2d75d570d7bec0a2d570d73ac062d55039b71deca03de86f868173eda0419b3f8a06a5bb511cb103853d7ade62da5d1d3d882dd9033038d26ae4a84aa132ed072f997c404a2bf7aaa116c220c334df5f6639864b0943a3b2056486592cb22ce787341824404eb29753222b146577a01c345765d21efc3cc706b730f3bbf14f1ac83e60b1e47af75391030d6ca7e60c71239aa76670a345699defc2887d8c81ed60bea6d04ba92251d61a89c5e7a599d9ea64ea71affbc089c694f1b40ae11609de81aa1b32ebb7206cffd23b88de016660e3d06e8a211eedd36586d1320b76b3d1653619bab202f0d537141ba810eaac028971a48ee7d883149b8036866c5e0675c908ff7455468f7cdfb46cab82696232701e0d3f870bd5c4475bdf2815d943666f7bc433924f1adca0faff60577eed0267d8c76a9c498630c28e19590f40d5aeaf5592f6fa49a3fd83528f0079f6442655afe6e8eeb6c7f25e824bf5b78d8b4e62b3e2ff6122ce5831d42451f940ff0f03a15663b427ed322400fe39b90204b5a68018c9e4488e3d74ae93829601a891e7dd75ef3ebd1c97a17aab034954cbfd0ac017f564348364d0c34a69e6c8a66dc80c2ba0365c08baff90fc334ce69f736a9b9cc5d417f2213cb50b5c1582233daa072c7bdb7a947e08923b4f4d62b81f0b1127838e1649f83069e1c8bd78524623b3fd91b7eaed9d4fbcea22cffa78c40cc20b18055174aa6595eed61912ed9f33201cad52ea43d9c6d9d92cfd3f90210009ce1762b99c18224afec8012d91e63c8699230b7daa1bafc117c136cf6ac9f0b1fda5b0b44dc6da3a3f64c61daa3bb79735b4a72c847b1943f831406a77306ac23e99eddbcf38f8ea540cf547c086df4f1e6ec7bbdf0e903a81f7cb452d79c756fd20003ff13cc822ad7c1cf281821f5cfbab4b9cf5639440844c39570c0cf61281415aec1d092014591164f6e849c1de05f8c9f3980c74115635700b0e2f26d31f6372ef2dfae039b215f6186cf0fef8d677bf7e8a64ee718cd69df36f640678b78ff567ae2b9f7f1f5639ff03268094c99ec7643133cce771875a6b4022e6e8d63a7f843d8a0e64a67554cf1130d9c8dafed5cf129994567d5983478e9ef8ee779e483672071eb507636636ea2c317eb50780d379540f16398c356254abf5c8860fd2f3b7855c72b684a5aedf5c417fa3ab66f821afda56e4133e5b8df9c1e266d1f19f9cb630d5818b5c694d943034b6ad2fd278e8bfb844b37483e4e41c21defcf60cc8787b343a811f0ebc79b83f8f7def41a96cbfd2b992c8b1861e444c1a405d4aa3706851fc68f4d288596e75fbbd2b07b530d3513d1317b16dfd6c871f52fede032f1480f63c4d5803a42038acc482ba822c604fa3b837cc938f28c0f760d397f0f5322a0004546c2308d09bd27cb07f05fd1843320cdfee822a1be0ea0a12cc0bc76360ebaff92027f06372b5da09a967b80eac2da55e7c43d2a47f9417e0add5fd4651eb48ea9de85f9f595c494ee4cb3f7b4479b4afa5cbd2f08e4cc46112b9e5c1865c2260f21c3a12c1de4ae21c03726e44bfbd483431698d010cda5463a3f0ec1e7af14629a4cfd5670436a8cf75931fbc38b53cdf1b2a9f241f8c0e0fe1ffd2cdd57b71239b45bbf1a519b253c5d58184ed9654c496c40cb6fcf90c7e626d40393b7eaccef77a65a0f2db2e3d192e626fe4fc9772090f8d39cbb8ed41b2ba9249765bdd04d259d60ebab1887e7ca45827a04f34b8965d249c142b2a38889cecf2bb31ec14ff19524ec2782fa050f85ef59beb499837e3c79a53648a663394069c8364b87dab4e755f0b6ee981da91ec1b10f42ded265ad5cd9a1246462a04890a1e213752ec0ad122c29ded61cbbd9797da69651cea9a3f9ce1d2662d31f88c16f7116e81b3df9bd6d73802a2a89ac7036c89d66e9905e8e270585772741698abc592967bf8deff9073774c6a0969e5e5c46a0906df3823e6a8caf643ffa5d1a6bd4062310ca4d55c85914f014f81e9334aaea0b0546158de22d7ccc12a8ca3893910ab30ace5999323d84ca15fe75195d223be901890fc1d8ae69fbaa2c80c1c40e034eafb815b51bf076bc0174cde9e3bdb71fe796b57be1adcb0fc21423cccf09a4223071d73b110990bc78eac132ec6a3050af7ad2ac09499f9b7555461d66bb2c882d879ae98188a5c717018c2f80cf8a011c30ee2d2c563fc1622899a89928bc377fca40e12970f408ec77eb76a86e45f2e329ad9410a915e4ec2054c8fa3d15daf6330d5f319bba6e3be6356ed8ca5aa0a8e8ce3d909e83e1befb826cba82fb06609eb4ca0b95277cc864abe15f5bc4a87217797002e7883ff280c945e17aa9bc7cc3b4fba9cd10186ebdc7c2e5f95cf9da15e26b30348be9a099b91c7f44b498117bef803f51ea01164b233758c0624c6c4ed913b9bfa362f6d2f828bbb950cbc7002168b21af8f4432d681fbf4367bbf982a99459c3e56b45f0dced78ccb2e5bc385060ac8dc28b0ee2f83a73d830184256af963d4a63f79fadc0ea45c02f5deb60f2cf3feb0f0b0d10f832ec6bdf29bcb8b26eeb7e2695793a172d21e3cf8fd1a35ecdff78516a5ed0d24fa4e5792c15df7758495310d132c25d95c0e0b005a97280b6d51013ea004469ddefdc80f55a41fe05d0217ea1404b8a8b206cb1efb049430a6cba0445a246bb857219bb56058146a7ad4e67141b9f861126a6363bdbcbca08e2c024490aa2966daf00208d50faaf07e5888f3bdcabe7cdb1bcf38bd172ba0abb76dcd3acf6301f22e1de960667ec082001a3522b5e187a8eaffb0569a3d0a57b4bbb45358a1f2dbc560ae0d1ee11ca3429d97a0db71be29c079126d1bc6fc259a3c7b183b1adba9bce5b498810f449baefc2a1dd828428af0747e44849b51dec214e95e702fcad4e347bed2f66cf05a66d0432fd74e478bdfe8071f635b3cce5ed3e9610eab301de821ae8227142bb5a00917e80494cb0c07e79829cc372c12afb5de71bcc30219d1fc0e7cf37158df2b413c830ef03d663cf26ec86184d89224d73ccc8259adaa4b7e8d7786fb6f4f5ea02b8071157bffedb16a20c9dfa6582486ed1ecd15909470b7343d655359b8734f114f74d7b3d12b2e4214d8b8f606a84dced369f96cd44988f375b6f88f77d9284a3a37a12fce92bf75416597f5a5e4f97d1d408cea3e7608261bcf06b88d4ae200d65a7f089cd2b98f16f7b3929bcbe0202592629970e51bc9c025431732ab9f83e1689e2134854fe5e394f4016a442696e2f588dc790680f23418f162fd38b118675beb5f833ac822ff4cbe65497e4afa9313ff3c0c4a82847d4e2a9e11096b2389f583a2e24a3ff3eaf294ebfc2ef0c344e3404c60c813ae6ba0d8f6d34948f0a016523dc66f933541a43429c42eaf2564a6f2953f085bcec8334114ae15a3cce7ce3f13d8e69fe43722758023a853c817b147ef60a670d7e3ab88217de7ba61ec8d0221d97e4e19382676b8ddc8a280c95e4ced38e08a05caf048c0524dbac39c86ad7ee3673afd57b15a1e4358f2d03913093878ab2d5b227115899cc2d5d77f4bb6625e5219c4a314c49a7a5d5ee557cb87ca84137412068e8d40cef97e7a004640adb58e5d50a609020163e43499a225bfbff6dda7a5dac7bd6ba6495afa0a588e23056127dbd3695b6ae608972b8c996a7eac641c331eaaefe8bb75d741d0913b87a89b074e3c0ed333dc97fa1b43eb56238e7dbf6e838bd645b51365c2520417636670204861e2bc4740a5ca9d86e9e33911dffc5607ea806a08cbb80c58f6fdec0bff48066adcd9ff0d50294b9241e877df5fa11110d0d7b2ef3df32faff17c080097959e7be401ac7a52929ce260b26c5d900463594200c2329a640da9c86f703fbc3d21797878a8c1b38c0ab4c1cec38633ddc01eed92972d904397afca582a0f6a37f80b2420c3eba91fedea1b4a320c6fe28e144049ef62d5cbbb36a624c5e1cb999fb184277fe2992de5ccc3687e1414aa98eaf49eefa15b3590efbe68da3bd0a16e1e8b3427cf5469c553e80148d02358788979508a08a327f89f5ca0dd84708f5426bcfb5b6f5f6c770356ed745242010f1ec11b2b114e86e8953db7b737b68ee54376c31c510866d83ef62af1a21e76c2cc301e01fc16741dcea9ad5bbb589e1073d1c7f2a53c2f1344f84a9babfce840bdd752f08f60421d558a947c88b3616e5bdd16178e7e376f2a3b034ffda56e7df8061aff107bf90d9773dc2d36c79a641e58cba4a027e892eab5b9c106262b9fe47ee1f651953ad5ffccdb395a89df92fca9aa719e3481f4c3c2ae683843a831330f182fde56a60a111e5b355e0285dd6505ec85db7f77189e098507572fbdd98d8b94b927767c7ba886cdadb63bb7bf4602d4d05f8122a8b116f605d2acbf8f62ceac374db5b59e3c12aa8a3ce6837a7aa871950ce4a7fa48d41a2550061a552f7b1d4558e24456dcc5c784c29af1875b98d45ba81a0613ae3e7aacb541f9d482e29b58507e5adb013ff9c26e8188803f88c5c63d719e4459cb1f449a08d3dc8304b9d33f0ec62a898cda29d301c54aced91839cbd238b36ab99055a86f22ffc766e69ca601939a8e019b7a42f7b2237aa4f90b09b61cdb31c938183af0a1f50521246da779640975584bcc3f2ee3009a920e08315e1f6222314dd42160a3011d40e02aff95e6b7e62e7706b89932ef9a0d2888adb612ea6ff343edf2acac3d9fc0147bf42722bb26eb753f0bc39f7d123052731b52f3fa1fc27f7faf317b581a2c97693a850033dc5c08b084897bbc4d5a09e62af2518a7ce8f978203516812940e0cccb886d9462cf8af132706224636f9bc4bd683cf70c10bf0fb2a58ceba04c178a6853ed6246ba47de0298616346f0d9dc3fdc9fb1eaf5f2881e55940d0d0acc3cd657da01cae79377c87a692011ee365243c40d6eb93af6ac3b7dd4743b0208cde29f5c22368e5f03a8b2f3524b1c597aca583d430edd81d9c60d99344a5f3e9ca2aa2133d63d65da562a155fccb7126106aa06c625d016327bf3111d3a76daae2fcd4e9d22e67429e44afbb9bf1dc537848e79dfcee41f6a339468b31bba049c4c2168d60ff25f4676f4b885b006275d3e22ac8e88639a13590b8c7c4271448a35e06f3bd9a342d9957ae85f3b5120f59ee03b0bc18d69182ac3b0a8097cc3f333816a6f2544a2f842c2c77b4f442615e1e901977f989581998dab39c42239a223e72665e3df3701b83c7daa2282faa6c3623777d075d69805f00819a542940304c8634c45ae1d41e925d105db5376d86110111e6b0af1c2816204c00a8e644b1935cbc4f4dc866b0007e03193e588ec5d2befa63564369b36b92a65a15a60fb03ef5b0dfef4081a4fc2398d206957e698a64a4d86b2ec18da7e6d9b86e214278a85636605348eb16022b2acc3536b49af63dd91c0b7d708ab886cb81ea76f9371bb178d7074704835be5c87feda7d90421b81abcdbbeae0903b832ee056207cea68c808d5a4e457386b8ae90d2e8a6f935bdeee875cd25ebd36154298e66c07ab7fdc46f91fc153f787db75fd0387ece79b534ccc18345eada8aa4db87ba80b355dac32bd90c0dd00aa7732fab03392af8ac8187e050da43baa6095fa013aa4fa6649bc6e7b9efa0ed4136bfbd8a6de97e0c3adf5045b15dd401c796e339a4ed406131b5d5055ec832cb28355e34528387d6336cfe0e9c25072a4146698d7cef9d2fad445f6b0da06bfa045bae870da69ac17b3462727e047ffb428e2b0b4b234ed2d89962ed1032abc4e5309960112366cfffa6cee9461fb5c99361677b886b6ab0a17622cda853a4bffb441211d02b78cfc01b428566d4325e32467978a1006d76179dbdc115295f12b78f6a7d774c9f167ac956487c333537246008374056ac80d5f4fc93cf6d57a2b3b786cd6744c6a7a20d5b1c6604ff667d74b1c75b308af25d69f576c6c91ff0fad881b7437502f1b7df9a12ce529a7ccadba9cbf0ada8de5c501d961c90e4e505d6189725bbafe8425e45bd102a1921b5dd990129c994edda09c73b632cccf6bf3f7b5f4e7632acc615fc943670bcc1bea2bf8c4928518a89864127ddb10458f76d5e64a8ad45923b6c478ff7d83bd59fec00c0493e5e868bbb112fce8832071efa4e446b3f9283ddaf15e65292348f664dc123c965336e02b54dd8a9413a6d21830db502dcdd35021e0d63986fb6cb551b50a9cd7545f29310cac705e546e3537c2f1bec306256a15f683211a0e1c4be52611dcf98955e9e83a1d0418b30b4d678bdbf74520d96cb430e6dcfabcbcd97ce7edfe591b6c176f90d0a642f3f285f983778cbc3a1786242d339414d553da4a62e7e8e403d99d76152c97d4f536a882c237f1eaa474d9b7c236250436bdb191a5d5fb9108b4d208da05fc91f455fb91d49abbc595419ea41e943ab20127d2eb164d810577d825af6b180e7a71b59121aa8ad90575c77048505fb8e9f29266f96863b0d868d666c7cf51110415e45410f894a103bfb6d158c2a02e3afc6d8ffb73723f51eff0d6cda5edc6b7cc1aa5ac40ac99631e732052f44cd0db45cbe41089a00248a69f87441cc9cc0f83877a5ed2f17b80bdda935bccad3b898c2d5f4a11102ec69d19d6693f4c36bca031f93468d4444caae08b21ef26aefa7e197cae4cace00c8ceb5dcbfc374451a661d0de39c18b4f35511c570b6cdcf306345d87a1974137430bb74589ae9cc781a81b5939a73dfb29adc427454b08cea15a2f85b4c493b800acc80a18427de4de42932fef99334e367bb58f3545c7b392cdf4ffe0c342742e68d9ca8dba81955c01fd92b5ca21c0aa4e1bf311791f61bea7ebac2c03642ab48689e9d19218fe779280b7102d41e7f1e287b6cfb8faf88e8e15dbe7d8a4c26ca42e4e59d5130dd512a90e8dbc72a909a8edfe54cae073a12029ffa3e1377ba59cac67a30071b51e9cf1e92948ec8c2a66e69e9c0676ca14240e8be7c577357d135f50d851cd7d0f5c9b7416a9813cba66dd03ca250d97a2288f6516f8068e519f1095aeaa59c5f2aa26041ba21458fd9dadfaa11003575418e09728c585d5eea7061ec8b8bd5be9482ed7ba37f3c5047bd8f15efe32b01664e404d27ab7741861e8b23a5ae48530369a91a8b79bb42c390218dd34d9d7cc43f267fad1f714f8e385f0f042a1c87930d00b803eec341b09cbcf0ff58343f3cc02df7300709b96050621dbc422d5b72511f3517f1518e51f530f5c55ec6a057fcac224bd5a5e88f99c40fe9b0c45e88497402fa173454d878b377421b9bc3ea23aad74c7c07d80dedff8d45b80e151f6b4f4e261af367696c34d2e613c76e9287361a54ed541bec37b457c09e0475e6feaf9fbd3e21101c833bd6bf7a90747db099cb9d12302afca3c7ffe76b90502cc2751b5a3e7c819a91c26e5cbc4812cdde45345fd8c633417a25cea1700a619ca452f2ffa0f047e106a2c9239a3088ada15e220e9bdf2f03e4fa40f3d516abadcc6a67f5e75ee85ffa332c3d55290de64f77ef3a7f4862278be0d0efde7b640ae96bd1a9e1a0d52693bf450f75465a1ab249c53cc6800bce6b01875c285357b67f36dd457c3cc99d797bd1a17126105da419c63d89d52d9a436ba0a70acf068eaf7bc56eef84b57f877963bb19db88ac3a33e097160fae1b59e532d40a555f928ccd7b349c9e1ea7316dcf52d9751c5f6b916d8f6ebef106f7e19ce5798aab13574fa17e23dfdbeb732fe47ebe672c65dd01acbf15fec8b36887242ae2f041a99ead05795b1a34c8a37718473e1352a152052ecb70be1ceade2b24189f69f7c595ac06b445e275ed35d346d89eb0ab120efee9689253c9ed6395c801b391d357441978d21494fc2d7c88efa50fb3ef18a34c77fb142e8e9b7ab2351a2032299cf1bf339fe070625bf3b0a5145b78b40915a4d565d4f198ead9f911e6024fa17290d19ca0d37ccebf363588874d03f962090e5687d111a7d989cfb994d0cd867c2d32d31284cf06383d3d3c45d38f0da5972d0a8564d753350123a571931b3403d40ade54dc39800e9cd868384b5f6c22c9eb4a95ab227c0854b8f5a57a212190c8fa6e48e8ed070c83999ec2574c7b50bb7c80b3a3ae750f5671213354706953b0b36abeb96b60320181b3384e252dbf296b912f3c93b4265d07561497153b67101105cbb1719c9ea1d0981f663e7882b9aa9e5699b274a321ee7d786897c5853528fa6702a2386a36f88fde0174819142ed60bf85df3ef8f04831fe9a8ec88c3512dd765c889541dee62829e99055db3ddb966b69c8cd4dd80e794b0d7a63feecfeebb0bef3c7c1dd47fdb5edd9897fdb8d6c30f242722e1be9f2637b99101589eb5fa86434825888eb277d3b8881ca4dfc710f06b465b443cb1d1c21b15ba2bdd8c46ad9afedc06f837cb07413ca99a05a3ec3849d5a47ea8bd8f0119ef252364ac50f326df040b31570d004be1b70650aaab981244487b44fdfb2c99d638e5ba750a8bfd35d62aca728f59717188e45ab8a7b6da8a5981e573bc10487836b20bdf32ea565ddaea0f4c0d40db941ce97174b9b8f52b46491f45613d4c9f90697465443b29b2843153c241cb6a0d302b84cbda7e02728bfb09641edb71e1627c2cfffa2dbf08e3369a9758acd4f3ab7f5eb0aa37f74d00aa5b2dd27d8338b9a7764cf789dc35ff941197c8cbb13f7d19fd6785ba639c6cc00ee58dbb138b28aac859c79aaf288d7e586c911d802745101550064d29f0352fd6a434f28ae7f5826d3a6057dfef131042292904f41bfbbe43adb59697907b70f7a924b39b92405fc2590d50df217c85cb76df8077b66bc470ef948d5a0d6d9f8aa209e5b1dc3ebe179ecd282294d3f95edb69faafdeac682caade12e546f9c7fd112f0721060c03f07a4334c2226b54846fd71ed42174f168d34fea114c4934d1cf2ab244434e1c72c6c8494b3956b1161c30cf5d3ddf97dc51748c7fc8d73a7bd3377c6f025cf6d27a64bdb23a40f103cf841dfe57204d495eebcc573e006b2dcc546603b0f93d4b48f74182b91cf859d72cdfbd369ca95d40c48d8aa1bbf122a37924261ba14a01b9887ce9dbedbd77191ff381546776d5a63e69243cd74c93a00178ab22e40f2fcc8fe6595d2e034d82b2b72a063f904cd2de1434e41a8720350646df47553520cd64fa49718e6a75e34ce696d2d825473bbbf6a4ca1af38f42c1a17689a5a5687da69e8f34a2ff59a9e7f02c1a6ac2dd44cda08cca362f9d99350e4a0d1521f2be154fbde064cd10d5c074199953c3615fd59e009654704b9987bf4f77785c345f97ccf8ba8a85d751520b1b1f6f3dbe1e8dd25a303602060ef8e93833538d6676329dafdb77a2ff2ae8907be05896cc7cc3b6b4315f7eb5f01537920f817621a56e6f2e160e87100d5a19f798f419a7a21215e811c52d7dc1c70448288e77a941cba19528ab324040b903c135596fb66cfe23f67282dfeef970941838d57ecf241b08ed239e5bea715d2ddbba4c1318471ecd80d8f298f8ad9c01095b736ccf63c736db62cd03d0f3a4228cace74a579e0bac42b3874d33b9b7d7f629527ccf35366c86337eed9261b1ebeb71bcd2609b6ca7dfc8fa289a50beacb8378d059de2e8d5d83dd5fa58600a015fd3a368e373c83f0157f9e5dc15a7367295a1f54960a15aff1c6dbe6f33b82a374c365f66dc5e80a1be42eeb0fe3609bc3e5a435d3f1db9373364581cf79ea3cb75a237551de8f9140617458ddd4ce629aec49fa2fccc1c5fbef0da1d21c1c7529838738ed3df0ac9e5fa1473e6d8b57064c5cf2eb46e4e9f797b87d26113b2eeab2a10f12e3e09ad9c65ab19a6359ed0f9d461ef03c05e92a643eeeec1a765d5ea492a1af780b46f58a72a1673ae25393695962f95b77b8b0356fc911c3a5017e89f6d0f48e565c5e4927bcc395c5ca7920667390362bd0ef9951bdc92bc174c2e06dfdd57630dec7c4e71424df0104845e554144a1b6f94c8d8ed5b0b7c2a0f7710c277829b218bcea729ba916366d7549236dcb354a2f4d142708d6b8d56a9900718eead5d8f2e415b9b0b867181b23871ff3998e4875fed9b9c1b8cb26be4b390da72b67cc1ba6c1a827f6a41339e2ebb9a2ef98258979d4e050c2de2a5b0bb1acda1a833ec50dfd847a392cd5600b1f966105c26a186e62ac01fe232bdb5b8a6b151310b4f4adc6d5976b77111f6201e51e625ce9001fe4a24dfd22ac97be93734a131b7d8c401c3ef7a616b68bed3b65f6ee887a54e71273e1306a224a19d487be910cc44f8eda12d897e76ee168ae72f205b0df20c91d8a19b85bc246ff7e7499b3bc7219165a3e02d0f5baaa118d8d779b50f726f7e7000a4ec58e4f676c2aef4280791678595269e5844428f5e204e952ad00f45c6fec6ee7d7a0fe3fe5505b70a33b6a68cfebf1e003485d16c5e9f5461b3a3c1ab924e48823ea317ca8e1f7c4fcef3e52e132be355ffee330a358900c97812e699bfbc1e1d489f4010ac39a0c9f41b84e0f95159809cf790f436534d38d809d37046a9e3332360149395da11c67fd4334353189888891926d9b0da98e4d715018bd023d416661c5c24ede02dab4098d4e7c01124e9e0b1088559187d2e159599abb4b53dcceded091c55ec0a3c68cccb46326b7a529f6f9f3e230a51595c71c19681a78ad230a87247826c33fe1b4b51042c039d048508583634e98a1281cf5e6646abee92947d1df51d47b011345a7b599ad6a377c25299f8146b674610d10a5b40e61330560e345d9e6b7092e4cbb6344c84b5d718f86ef939f68f282c6425c01118c54e78feb734001e847a2d5c18e58868d32009d09fb93bb9d2585b6022da0dee4194a6bced0bc74295b9415214b0ea9a6b42389cc5f35f687834bd772e7cd809063f64f5be16b487ff7d6cfb8a0614250d7dc9c64c1fbb23923a5d882af013024a580bfcfb2f307ea3aa3dc763ea5bc1e86382dd6ef2393f6347fd3500f458130bf1c627ec875ea1ba1cf3a065bd2b778c3b1e5968087dd021b56d6842ed3743325a662f620b69ef35e3ba4d62cbea685078e8998298e82a878865ecd472b1171d0eac192a83c579edd7df7781f6a9150f3be060ae5ddc78ce47a8f4e1f925eba57103701320491f429d43ffff50fde0d701ea73d302835fb73e103a95e3a0f005bfe4c95d9299f42dc1ee47943d4160ec924842e49316e43888dba506661c27a23b7d532bf34ef00f49fb18042fece45f0b84bcd0d48116627f3bb10d08d6833a8f01b2bcc3803a388a3b3037cdf9d585e1da581518bbabae5cce6319ff38263f736424bd2f31226ed2236b28b477ebdd434c92ad79de6c16abe9fab0d296baf358f8b6f3e5afd2e2ad1e8dcf600ba6588746331369f6693f68c9d6eda034f2f5bd54e340f25a367a565db349d57a549cebac48d2bde268520448fa19774d3378cbc82ba8206ebfc34837c7c234ef5176995ddbece9b7c533aab3da80d63585323ef0bf8701bcc25a4e7a3816d0d03f4f85840a27686fac92a2384e048f169eb8aa9453c9c91ca32740eacb7be2430d4f62190381f01d337a22be2f6e89592a20746fe68ffc80c083837ad82ea331cac5a234753883b1d1841b5b0aa4239f223ff7f9d2f3d4d1a9cfd6fe0da627b4fd42d32589f93933c9ffb809e152f2f5c46ab68dce011b81cfe6f48c3d13d973163ceabe2aa7e784a2a113dd53ef94fb177eca41f49cf0a64bb9da8b10f6c2f0ad757d535518e043127c558932774a3e94dceedc490de5ae64c3265d26b9a764870a89d558436d0578b546ee399b00c9ad4704613cef102b6ea2261a598790756b0a222c6a509c02145d2c9cc98d9bfb7727f7afa822a9b0103db4f333bf53429644da627de08e687f7a6fd7c497bc3f9c7e3fcf75a1e3b23839467f9ed63344948263460cd4bc61810938dc34423ffa0bc4ecf2876015d51dc9cc667b0df3bad497cf82a5d4738cfc90322581154bdde09b44e636d1c6c78b359f3338f7cb5d2edbd32b95d8f26bedb899d20be6bcdf4836bea19a305ef174e77cdb69cb3a447fe6bc5a21784b2e4127401283e871387d0dc4a5fe457937b662b512314898d785e6698313eea588d9c10fc66b36bec5ac4481bd340216aca5859585cfd09127ca8fbe82356ef09510dec4887699c587633bc1620c4a3d1fda69fc65db7286dc8ae492d017e31f6111f62bdec6745ee6ffadabdcd531fd0f4c60dfac0761e3afd40819a11404f0afe6ce7e9ec2e68c7528e8402d914b0dee8eba0729cc25a8a8ed9606970ccd0ec4831fb5a6a00434d2c00d79d8fe343e415cf87290b8c2259efb9a313356375dd1a0cae09c3d47ce0eeef683ee5c0fbef746f3c95ab241ed3fb21b7eb22edc295876ad7608cfe045a39ae2abd72e22577b5f26a23aecfa138be4ac1136f557215cd8d588e5e72cd26f7b7fe3225c832cb79d543055abe410fca33807b4b3030a9f1a885b308e424e073e567aed2248d05d56237a8d08903b1823e00d2581f168f4017791a7d59e3cf01ecd05986bbc643580468efc10a0a30e83989ae8790c34c12bbf061578de17a4bbd7b4511eb93a7e814fb424d484c8bde5de52ca24532108500880083a38d0bd93fbd4972f5518958ed4fa14fb25238c936fed0d27d73f7ef7c5fc9252caedbb872ce58734f7d34da5c545a53e859358304a2bc46230159e62aa6c2abfe1e4468fb22f2e092979debd1bde6484128d74b847e44fadf7ca9410c7aef9147729dc487163f7d4709bce69d78d3ff63ba7fbf026f76d7d503fe4b2cdfdd30950e4c1500fc60f3a0c147778c5b847f7801d0c85d33deaa37ec41d8ec2b54727278ebd022d0698291094748ffd8a3c987dd457f430fb403fe20747e20e7fdc75966cb91408b6934ebbaeebae9b9dca0235d34fd23dfeb5492c2212c61832c5491c8c4eba8a78c3c98d798b3164776185ec39348f4b19b2bf63a0239882ac7b6ea2b8f6a353ec774a488c65691f89e469343e72ca2cb3d8d3c6181bc8142dce50b97d4a4f1940832c719cfd70a9bf94b9cf94529cc7c1c4f8b2a8c8c176d5146d48846938c912589c49914712875116694b55774facc2864c906c1f8293abe990dd20dd63d2a7828b003c5d3237f7aaa87bf8783715cd2425fd1824288a86632c89834142780a00179f82bbe120c923bf242ed0ab95e2af7ab03d01a48680d2aa3bfab70b01b3bfdb006ed1d224f79626d2640d726f49224c7eca9f7b8b9659b612a5bd0f1dee4b2b5134eabb42f0dfde7ffbfaf37b43d12fe6989a4fb7ed2745406707e1eb54083cd9ff73d107f37c0dbb2816028230d8ded9a205494b946c236ad33eeee3f7dd78b9fdaef820b8e283797b2d622160debebea5dff69bf6d1a5fdf6d4a53d9867eec7e1fc5c202089c56229e49b272efdfeb0ba42f04cdf021208b5a738ac5f71091a76694f7fc32e0d0b01337d30530c3ad85776b1736aefa04ba9e1de72e64bdee99ef6bc5ab1c3d03e71ca2007fbfd29585f3fa77b9ebf3b8d120448d0a34e084e864056b9103481182b314e969b52d020db2904ea2ceeafa59e05392d9151b9994c50447d8112507777bfc0f7a69452768e2f130a3b1b63031b9b642f452cfe8352ca12a9f8cfed8f56805a098a51ee8ee506ff8b3161727794491fd5941662b91fc9452188fb20c1c2d20b3858335a5e682f1cb01282262ea5944b34f990b012e7873b0bfe82329ce90566dc9d4ee93e521891fd5b289752ca0ef294a28769b8867b28b829f982b552caf872cbda74ff3e706f8cb8f1dda59c92ca8c7ee1cc7236e79c73ce39e7b49e573f534a298d4579d2a4dc4fe7944f9f52cfc08c22e5f93745dcf8d30845cafd71ce396717c3acdc36e7e49834cf1cd3ac584ef9d346d6e6d4a636351c0ed87e90996a13c758a454c45423f78211e5baafd1d0b7b28617e74b26d373f7b5eed2a54170b869cc3d744168b67e36b2a669da951e8a6215af92aa14b95442b12689b498166be23fb6892d0a53b4a4bd46b929d669ec41bf935a892b9da58e14a8256e6042ccafd70080b46fe7adfc62eebe40c1acdb3d7807cad47dd164f64893c91f7ba4c98e8e8e8e8e5654303551b926c433b24ef6f00ed463cfa99278464d8af3f8009cb8a13da2e23f968a3d428db147ad2c31ca412d57daa3eef13f3aea1e9d2f1287c3fc4e6a60e407790ed97e53b0524a29a594dddd2de5f4da3c758b0db687554a29e9e790e2c6eeeea6b81f8339a7ca861be9519e734e106ccca6dc9c10546a9cb5cfc9b79de53a1b9dd8d88c71c63aa7ad486ab4d65a28248e55cbb6e3bc561b39c662b19846439745db3a14eabbed5116d55914d79f6b91ec6a28702d5073f50ca05028d4131b8e5a46d976ea9fc43568ce311d750fd954e9152aba24c9e33e5dc7a541ff2e49fe74b3cec9412eedd365d1a0bf276dd2ca14102122ce001a910af10c587d162a8cebca38b94f87268bf6e9ca882d348f93dec0bf43e33e31e66019ed135568b0e36207617c1269f0c03f16bdada19d5827d9df2d0ed9df35230b45fed822798be44fc3668db98f8d3938dda733179df44f0bfdf353bc4d5351fc69b9e6f072e3bfaed8c854c6dec66c2c081aa18dc5f00ac9c6dcc662bbcac66cccc66e8c2381edcfc9cd14850c3772337d79f22f39be955f8a9832ac72337d999231c8cdf4a568d29b9b698626d7c8cd340ba379b9996659663c6c4e747233cd62c80f46f61144ad50ec9075723341d184ab7141be11e68b32dc66f2d225a7723379c19269e466f2a2438e1f93170fa05cb9999e4093e3178b2e8ddc4c4fa020c729b3b77b58c084ed8c33d0e410498e2fdbf2d40ec6fec1a4fe50f7f5fb2b4e52a531f749ea3371c1f64ed8fd5c90aeabcf6125dc57eeabc5dd374cdb628c542976ec962f785c3c2e1e178f8bc7058790bd5f5b213ab9fde54a979cfbcb95a5dc5fae2465cffde50a11b9cbfde58a0f393eaa1760e5f74ed8c96e7eb8ddcd45cf9e33ced83975f3c39d3ff1043200262ed8dd23a1740f9bb9f841ec1e37d99f1a758f76027950c91efac8ce546318a3b7c480e505d44a321f99fb84338afbd024b2978042915f27d3b4d85696de5f8184b8f2dd486b3e4d01a159f2ec2672a6f3fd152900f20efe7278e5cc32e7d7ba6dbdd536d2ca8d42d5cfa98c90d756924baf18431db95bfba2561a98b62d284fed5faf577cc1f64e18631a7daf4cff08491ebfb7fdf260715b68f67abd5e454250ab91dccab3465cdbfb7985b8d3482bd39e4d6ff3b943c5d541774e6e5293af1cb3ebdbbb77fd3afbcc55a2720c75e4d8b4ca769c2a48e67a3e7864d7b1d33c8ebd9d1c7adc87ad3c67ff6cbf933bdccd61afd8375cc37d76b2cf3bb8d34ed3670a64833a74b8efe898e18231ca95dff21abee33c6e75af39bcd3676df92d9f726e613d46ef183be764f5fe393f774da3dbac92f32eceeeb8b6aa99aa3980dd53e7ecffba5d2e5a15697ae8a89820c061441966c600f38297192ad10823b06180c8968711b6175c210133319429c11815a830c410d3c8227dad514f3a758c53e761e02bbbf7f65effbceebbfc7f7fa53075273776e7e1e04e8e31de98c325b91d0b6bbb7d7aba4bb0672fa8c1411b355c3aa358dbee137239de441e5f7670ce39512d259538937a761cad46895aca19669832be9c728b2fe39c6106319a9db3c1f9ad4d8d6edb91d47711ff597d7719f7c1d16fd07e770f0d762c4f7ff0a36a7367f5dde6b1b6b35db5b6b3f52307fe0085748fffdca65677c6545c7768d85240b4df5206e8eebec15ae7bf6eada9ef07ea5a8ba4ea565b13c1c121e7f10fa177f88fc92e2448e51ae5ad9d1c24489c9d5b236a3f8d61c54886cd08fd458e5f638c4b35f29cb347991164597ffcc6270982486b5b197148c4c60beefcabd113688ed808e88ec32a6eb7e39203182a4e61c820c64691134838c91205164b5409252faa382b065ba0608b24bc5a95c400c5191e5062054ce860797861cb152284b0228bdbf74809893cc7dcf0f3162ef864ffae148bcedd7e3cbee87283e6712d05e484ede531b51203f05754a1e91e404dd23eeaf5f28f413c9cc7dff10b8bebf3ebd3ef0414aea51cd7494e4a89c19deef1d73e00f40ee701f4fad54c13c1b797fd43f9839abd146f5070ffb9b72688e0e07c950eb773fded6790ee996fc38c5b234f073b83196e5833e8a07f5060fcf91af48ef6f108824d7d760f9bfe41f58e5eb50f7d9d1963d4689b71698e292042441d6e79532ea12a73ef4ce9348dd591c50d513a9adcf0beb461c69531041bd9714561596d5e6ece5b6ef4e40b63764a29ddde45377cc290f73997629702703cce0ff95e072bd1f9ef71b0922a433ad853928393d486e1541ceffbedb7bff2e7bfb3f90d874640eb9f43f19791d17f2e211c44f2788f5ddb7bdf30ecdab0ab013a9ff34370dec34aaae060d73624e7693c0dac440757e9b04b48e71252f3f46b9e7e0e762900e7bd776d7808ce7bae213a9ff33a3898c03e4c83c6fd242ed4bbecbb6860d7ea5ddbd3b878083f8ec78193b850f884a1ff1b4116bb1480e35d3f04c7bbb0922a43aeff5ec90d9c0448f2c87fdc34e4fbffc74a5c98c887b16b854f18723d7ef9183c8d1f82c1d3a0819380436cbceb5d58090d4c021358d84bf84320d7378c46d7f4dfb01b1f82dfb0c7555c42e86fbfe1126a9e7ee7b0cb6416fe6efc7f351ec787c17f9f8d8f299710ce0fd9799d0d0b794f640757a19ff33a007826301c1c9c9d07004e82f33bb84af73a5f922a433a8f833f1caf040723f95ee777de070e3b5807bf2b8c45381e7f03be77619710c61f61ff1f61bff34c60dee7dab04bc8f35cbf839378efc2556ae8e7a29ff325a93294f31ef6de0606afc4c3118a8dcf79d7fbc02107fbb8e1de781a8fc1dbc0e06f7c036c3c0dec12ba71e323ac468d8f3911a6b37d110bfd625212a58e2900e61252bf4abd7c7f825aadeebdf7de55e8e5d56ab55acd94664b1e0ececc4efcde4dbd7f2954eaed27e5af56dc0a07ee6cbedfbebec5e0c6ef34fd8a579202602ea17b0b3209997cadcfb5baf96e1ee7876e7070922a2b3cd45abdf70d6b7d12d70abb1490f3383f44e73d8c83697c0e1358953f396fdf7d566f7fc77d5457fe786f697cce1371e188e63b75c290eb69e024b1cc021a163def23ccfb86d1f830a2a181abb884a04a583d0ae7c35886fe7c07fbbb38dd7b6804447d2eefec4d1c949acbe457e952ca8da374d39e52eda946a30d33eecce14c85a0fd86ab839a4fec4e354c58ae83b4bd95288fdb5b9adb8619d73555e572f36cbf7deea06ddb5e25e692b94482ba47e7ed5745db07913ffed569dba47c0fda2a0eea9eede6ed3f21c9b3bdfc88b4fce787f36cbfbdf2066a1f4735cd4e6d7635e6fa7282b97efd5e46b7fe9612e2ca2fdc0e6e5feb6b0be2e0f65b06340811d19f2ba7ed8b4b7eea55bffa5c0a48bdea5d12bb24eaed6321d5db6f980f22b2c8f7dd709790ab1fb2bffaee57ab4f927afb4c607665edab7e88bd778595dcb7b8e50943aabf38494b1eee1be612b2ef5a40afde3524c2561f612bdc30d5875785abb884d47630fcce0db358d24d87831694238034345115e02419292971d0c1d6010737543850cad2847444054a08b2f468a0430002f01b2d621c70d081009a30003eec2e59caa62ca594f2c9f5619ba1f161a3d1f9b0d364f0618c791f46229e8f4db27c19a1d87c18a364c97a29ffc36805f5614cb21f462cddc72e597e7dfd8e0f2ff801f8d0cb353cf8f03bf810e4f1e12b73f01bbcc4a191d894a59472a50c721effb8c1eb43edf8c0af1580cffb6a7c227c38bea18fc8f75f91efc647428defc8870292245f8c795f248a4546506214998352e291ca4ad217b138a8f4c52c0efa77d13e0fbe771e7f1edfcb79fc3bf8da7938f8da794220da237b5e003a7ab04bc7d7ac4387069f0d544e3985830ff29b30321995c926079f81c753e43e32070070e0ef31c8b9612366711fd7471a1f3f7689b30826da382696895fb4cc4434ee93c67da813ad3ebe3771a39adf3e3e09f2c7838f8f44fe74f03e3ce2db0cbe21222338181f0cc0179f832f36719ef839a044914939a28294f3452b495894b22cc52e71d614c338e814c794f9a2f5c5279b4935d5eab26a3cf848903cf13bf890489ef83e5f4b1e1e31d6d9e76b98075fc3787c0debe06b588eafb30dcf385fcc3731dbf855755fc74cbf1e93e7a765f9d5ccc1d7302b3b924989eeee425ba69449e1ba4cd6aacdb09db3158123ee238974601a6305d3982653ba1265b2817f5978943b927e6defbe5e418288c8294292c7232c07971b3526d1231aaf7be69c73ca22e9ede81eff1d1146e34b1e6fcb8e86edd8d13dfa153d2a51bd6bba5a6e263142283189f961678529022766871eae38838b3b9cd8b803052e68453b343aa552d08f2022b818195260c60606ab7be6ac45dc2b17653dd59e77e57a57aee78397a4e3bd2410f4d1835d80c354df6e69f864f93187feb93d049165bc92e5531d1db8f1b58f1f38ac99d5b2c1a19759ac8f29202c292e731fd607b1bc224feec37a7924070907e906a985648354837491a454bd4c01a961fdfd6ddbb6d0336bdb3ec8afcdfd5c6373258bc5fa22ac977f84c57acf2907e33cdd3cb1bef5c47a9b27d6d73cb1b0eaef53cd62a6b70a16ddf05bd7f379f9739dc75fbe6b888be33a67e6d7d47cb7be2deb6b7d4a6b5d92595f5bb45573536badb5d61b14abcecea8473deb67b579940d6e7dfdc23f8202922433d71a246d4c4092595f83dc842db35ed69aef54ad6155160bc59a125bf22121118355fa141b9139647d0598d44f000b537c1df49a9b9b9b9b5a93ead7bb699b36578ffaeabc2c6a436b28adb53e576d6a58b5dae0e0d4e0fe61b1587f63f3310542fd16ced7af6ddedab46c5a15e76f5a3838363895561a83162d20a20a2e6a1856ac68a2c51058cc9081a9eac449a56a77d3b2a961d1ba62a1501595690d65d5505cc2eaedcf1408abb741ab5a6b7d9ceea66553539f55f1eae9f6aa2f82b15f6864a35de538ae260dc9ba7d5e8d470de1a5309f8594e5f7e7b9d54e79dbb62379db5a6f6f53f7f820872e254ba94aba31cfb735d8e6b72ffc2328204932eb56f375b6f94c40926fcdf783bcc6842ddf9f9f6b88f75374feb3db7ddfeefbbd1f5be2bdf7d6fb6c4c0d793856659b3fb11199ef08f76bd9d6d79243ce23bff509391825c871158fe2a01bb991ac3572b8210a34fb7050f2e895eaedb77d9cf9701ff9ab2ab7e7e1c341f9af26777b201f46f2a75e961bc93133300eca8d08b4e27a918cd5bc7c1fe33e377ff3f2adedd4d6dbb77ee270fb9ab7f920c9fa6ea44d8dcd76f32d9b9bb73735377896dab6165c07258da51bba9153711f494612155378f0c18525c4c0361558b9a2090d3790e00b2e60a90df571168dea0dbd97af6c34371c1ae9d94c01b9f3adb5d6dac9da5898023dcb1397a0faee670a04d577dfa9ad673f5c48deb4b0b4c13ddb9e85c397eae74cfbd417ba94308201e58f1096281efe1361f2cbb892ca7dc28ca51cba51962f3484f3dbe6d5f8b672fd430f29378e2593898de328711bc852450e58be94c9e20b9315c0c052855316573851a14b1a6e051c2b30d1650c8e0924a66c3f1c3f71349978820a8e9701c443e58e5039ec31ee454ccdcd444696dc31b1a0082bc83892e286306e2a3713193284c04c1a6e298c29cc381d516fca8b2e62e88890a1bc30c113ce8a91f5e2896ae5a9f3422986cd082a4658e16e112f684328552f46408790499eea4514198a58f2a289111168bc883529e2a88b26f105f4e20144c44cf274eda2298a114e669a5e3c807c7c0b4a55a2626e2b37139318459069ba282ab4242eea892992c8615d820908ce072699970e38c1445481dacc10994b14b6b5a6eeee7ea5c45eeef92ddde9a4de6d37957bd7011b5d6a4026a5da46615b95dac3bcaece711daa6b77d776b35bdd54fd46d8d0dd638cee2ee79c94d2f8797b7b03bd248fbbcb962db7f879dea2478f9eafe4e997ae9131e79c336eae7577cf996396438a1c33a7af38e7cc21c59c735e22daa7cb9f94d2eea6ddada1b6ca7576ebee4aa5942d4b29a572dacad52dc82c492997a4944b332c492997a4944b50ccb024a55c220305d78292c6551466ea4835424299ba45a088536fa9a68e0e09cdec741f118238c83d2abf6a6424958b4f3aae52e122941f3515e43ebef3aa952c3b1428dff5a6d43aab731bf0e6bd95c5fa59a75c19f5835145184a78666a9e80f07218a930f1813886284d8e4bb8512c16e3c06c053d38187f32b38a32e601d9244b598e2f8f2415568c4c666439dac8a61c5f3ac931f28b1ce553a3f1d1c40bce787186480c0ba207883e8082a62d4e1cb10516c6a45806a80320404a42aa41082b786608c2093324b862690c2cf4236f92465942914b72966d6cbe77c83636367fc77022db7c4d0a888d1763b15cf3ac14909ac94222b3fea680b0769c608918ecde5fa580dc5b23af5610435ebd2a056455555f3b9502a2ba29314690538f4a0149a13ea258513851b9dc7dec9f1e366c39528ac13a96971cd6c89c96cc717fbb64eec9062615b0f0379690e5ba854145de5e4b01d91a8a186259a3df60789129ad1b510c0c199a6c13afd38c31fefcf833fe8d7902d1f24c89c024a4399e51ebec6003428cb1458c1061a43982e6072bba48628b0e4f2d3cb1840bab1e1cee84c54c26fb4f5a99ac004412134f889278c2836bb1610c1345b327623e9822683aa3868cfb4513def3c41753f2cca2847d7971a656e9265ae7faf46f51f768a64c5f470db752ede9d3d701c3ad5f44d2f7ba875144924f299aa34c29a5342ab956df59f5a8a8d43df4555adc8b591f956ecb41bae3044bf8534ffe44a5e6a14fb19745895cb1bcd1e46e4ddcaf133d23c61cae0e2c1715a3c7182b875df563ae381645295d52d618638c31c618638c2fabc718a3bb7b8d317efd2e9aebe27e622dd238a3b7525432010739dcf0d5c4158afffd4528b148f2107d6d1b22b88c3ee84713077d621cfdbf21eee730ca5c69c3b2279018935b49a9956690fca9d1b9b7bc900595cb7451f48f1e65deeed35b8e54c8ce23fb77d1dcb0d656c6c29ee0b1dcdfbd6502ab3fc4d5fa1b4e22bf26a9cf71cf64eb9eebafb3679e2b377c6525dccbeffe1544fe44d8b7f6f55ded1aa2b2c3aec643dad7af0db312f5aa40f2677bf94338ee25275f09ea6129cfc1eee5f792a77b30ee17913fafe6e99e85c37a7158ad4c75d2d58f42ccaed40f6dcfbdea63ae9fab5f491594922a2a3c34bfbe92edb9979fabb12b8587b8dfb0abff66180a0fd59faf646257f74092a7fb86d55761b92efbdb37cc65b71fc2fd565fc97cee875425f26bf8ca5d874b88b1285a145d68a91cb8aadc4c5d247581d44551b76961668609c549d3220c1459801a9ca81652b8e04ef3554b30437c01bd7800d950648391f3740eebd5e2850240310aa18bd88b07900f67e2a2c9ce300bd222b589220aceccbd2141b744133f98e076b9999a90c24213b210b898e1e4665a0a83898b224a2995ef78767b9d53a33495dbb420242f1272fe56efbe07d6d96d924124eb8bb09aef6b9ef939738304648d4a8baa936ada5bb7399a877e4b00f4fa1c60a3328baa391a602bed1e4a27b5aab717d5748976a133ad8cf685ffe47cbf664643133f7041f750fdcdb7d6a18694fbb532dac736e8bf6a9be4f44ddeec2ee57e2dc9bfabd793b54674d32099c9fdf40bffe9b2c8dd75a163ca50a7ebb69f82f11fab2479505fcc5649fe5029ce43c5a6a88c0985a3ed54b8bbc766d4c7e9203d92b2a7d668018d81159bf311b1f0309ccfc9399fd61ea0beb340ee3edab712d3ee417dc35019c8ddc7c7f9627b807a5487fadca8aefbee49fe58db3dd9eec976360c681efbadef8a6cdf1a59236be4df646e885330f121d7e7d13db661ed41b6426abe9de6b1cffa2c9585ddac9be5b622e4fa91ca507fb16c85c3abc261cd3b2380b6fb9ed926e1be59f1dc706f50821bdf1d49fe502aced3257e4073e81d5996b0286511745db25399171995514a3d4f3bd36183ab8a1eac78200726ba50c14b0725b6b0e20b134d4e8841868ad1c5479f98620917829891c8e9d38c1245e0061bbe20a2881f7430ba00194178e940161e7c80f274457d22738376712fae0a80903331926ac4d8e2cafeb404a7a4ddc04969c92cc450a18a01c3942a2c5144457b222245b988e1843221c613b901ae8a90c6071c227712e270682a48b3430e7b960408aa0d977b52af6892ed935b7333a521f252c60baac752948bd62ae4b0d144a208a5c39814635344c34404b22c8ad0c2820e52b840258b165c999d49f20116c6a3ec1129c63096894f536c7203618ee02226538a4e61c49cc8e1cb89c3610b039aa082055ca6884208a3d88216379841c511175b8ce8448046bbe169082964451c2105091e6ea002083090b8dc40061874054c4c2891a632010227de27d0c20c5416296437452ac40d7ba9676514f909ca78a10c18b27f7542e56672419a23a4dc9f54c3ef3238a44fe96b956a5a8d54a47c52a3c42671de9e4040794e1c6a9a9cb9b539254827add5f3a4e3ea4cb425d1390ed8963f6ee54914295424981ae68ef1be783361a7e1b85706aa1ba594524aa9369f0a0a0985c325b32560ac46a7c66974528dce8f60d688e449378dce89238c09b7c45db3217647799227aa67404d5e91084cf366bc2fee983060bc25a50a74a3ece608f4f42a139572777c5a6214a944a42533af23952560b2b41b10d0eb0582ff4a4d2c0e9798e9be20de9575974cad282929292d255122597e8c4e9da39cde5b52c5df99b88652af7a550abb866c15ee6de8e5d85cc07aa31ae540872be35eaac45cff20f2a7b3400ad3a5883288d83206163f486e00c30da35134721fe772ecde360ad40146a389644346b4752077266229b5c08b15309900b999d074c9f1a312535c9a92cc557deaa510910afbf7c3052228fb1d914136118486462812012982d00649378c46d4e80995f056aff588ed8b455f247230d614cb42fd94a3947224a913397eb4d23d3a17b9cbef8e1f8d96bc5801a68b113258c39c5458d8de09a92ccb9f645c32d7a9cc03ed080d0e39ac76039a984b7333a1b1c14b0d6dea992ec2c4ce1ce14298d9193145561c9d9922862bd09c61ba22e90c132c5c114b01b5846c89871cb612154b34dcb0d402134eb8208514b895b56f7bdd318c7e828eee1248d720a3774b29bd728063c519664a29a594b24894944ac9c21299195d4a94e7fe58ddea9f6d7b11119fda7a21020fcc004408b040220cc194278638aaa1052c3868e1090ace00a20b3136d0c4951d9ce4a0458b0b460073bf7ea596ecb315b2ff0f77f7e8c50ed31916bc3a59378acb534a2aa594b27bff20a746504e700d532387d52add3fbcc9347e3735a4e41e3561f4b340cd73e2896bf7c40ec3343051768bc4289efdfb696b27575208fceaa8886c41966264c9c50cb7be9350c441a92273519ffa224e4e4072ffbc0cea1ef34749e986933ba34ba99a62df53431c66bffba28c84ee2932ca1388fd64d982170bb4b8c88f2041db0fd68783fddb536ddb288e76a3db06e460fbd02007a5b669da576d52ba6d35d28ab5df34cd37ac69af69400ef68fbf7657feb5a6d1ed67d74d73dc92a797b85717ec266595a0a50d6a5aa5786a409b5993f1b92fc2ec8733c8f43940c00366ec1eca692bcdbb1b3448db0321597e7c7dcd43bf9ffbe8dc2001593a963f12164b68250dc9c91567de8e7b8ddf0912f4038acbe5663a7304d3b5b999ce0031353a7d263444648433b29ccacd74c603397c398160039f1c63c78e03c85187ecfe1112dc473efd58eff5bc078db8fc99648f0f829e279fc62ca38c3246ea30b90009a3f8e55f12b73aa84194bb9a7de9ee6e29a594ddaedc34bc9c8c93db06f5614dea43964dcdb33e4cdd0f55ab0f5759f5e1b5c18f627d1fee1effd587a37b00d03dfea82f47f7711fcf9741f7f86f9f06ddd33d9f00768040fee517d59d496c290a12d460c54bec03b01838808505506c61461064d823a6f8c18a253198a88075961aaa90a14b129414b4a0d16b227b162f6160c0a1a18f3c6171762be4e92c60ca527eac5cce64ffe95f4c0da5a1e8779cc532566f7e90e49195a41817749f9b6f3b0f2b20febd83b443237e293febf81ded63fc904796467a96a3747f726760bc6ddbb66d6bd9bbdd223a3f85060d1dbc44e775deeae844c0f39aeebd37f7400ad344cb182b8cd902968220ac08430b2e538821034bdd269f7b737efb7a732a12368e83c59db50d8bb5dddf6cbe5320449b8bab8335373aadd68daaf5418e48f79b75713eac99157144aadf5db36d3f5340b66865db3614620602d43dfeaf577deb6fbea686a5aab997c562b1582c16ebb654ad0ff2db7ab96d97f5f170d0b7564b67de0cdddc74531011743e148e605142b2622509294b061da94c10a411869e3820dcb6dd3c4b4a330e8ec0aab9deb5b94897f543ac6f049601888c10ab9e0d520d928c49a227332c2947eed322ca79c9fac2cfac9a5b736b588ff31787ac6f7d4c81c0fa9b9c677d9de70deb3b75c3ca799c9b9c9c560e1212eb5a61255dec481e4342b282d405098bfff418425c21c3095478228a3130af4286226008428b23601e46caf271be865583657d13a200a874ad3765b174886a060000001315002020100c07040261402c188d144afc14800d759c3c745e341709a320c6619441c6204308008010200044666868c6012a9973402ef8003624399e6e793a3a96eb8f018f6db63e43ba85ad79abb41aee0d27a280265c31b8695aa0ff4ef4572ec0b07f6c2698a16d812663327f6ff805202b0425804d189912f08b2759cc9c17b19b1ff19c96e413b94d8961bddadf550c0bc50099d4120859454964c3296f470f43733b372f69a11d1b4729f3189c925ba87a88e50e0793d9afa07a5943c89622b309ed2f6fcaa26bd8bbb5972b9661e49f07b6a1143422c1a65ab6dbf5c3800b3636512e67bbfa6f3775ad8f313765e442abbdb61837f024f27759c4af6ce318e63be0ee7342e2420fa06649e332246ec4ad961bdb953353d2c067341d7ba9972af0bae62c0b5a3a7b0588c42c0c8acfd2a3249c3a1dfbe09b40ea6703bc75c8b6fe0182a32fc62c7bffbcc721e43f2a00d985ae804befafacd6d3e0ecc33cae3999f0d36cd757636cb43ada3d392bf1dac50f4a61999802e13a78e08b858911719c809edfcc4b12eddc08c3252e9f24c707397c2f048861ca6a13e5e498658d5bf2172482c45c308da16b103dcaaa4631ed95a2c5eb3cb68bdeb4b7abf7e0b1c8c0ae95d216560afd9926dbeab2eabcee22ad27faf54e25d692cc6bfb252df44ba171d5abb9207b01269ab72a045d26339a8275a8722a7ef346fcc72d408341c0d60864acf886007ec0472add5c98f0df8737328cb6ea42051867d69651339b6c3a54cd02402a6ce31af55c108cc339bc2c9ffe7d1740749467d4912839a8ac3b3089828a9b8e627fc91538e92c8ede801cb8f472c75a7f93f7d3a88160c31f7e015c567b44615e37b29b01a966aa4363d7abd8e4bb52f46c0b9975070f98e75d80f67542e59723d5db3083748ae01b4974d2d9dd36204dae6bb861b6562a3c4d72f90ae2d20be459fe81e605c01f10a5c5f2f63e2a2fd0189a5ac59e54e3c87965e609a8d25693523a8274e6c749c02513de88ace66d6db6712ae4dc8ceaaa5d6e4022dd0f19bb005616db2f235f378f5c564e7b5eed114025f501b9a8edb37a6fd67b9dd539652a68ff8f775dffe9db4d4f3e3e90abe247ca56128b02424333105d797a9625c1312ae943d1563326a566b6a9809d6435258115ed7afd7e0560e178266c94edcb9eb250e8c580bff8fb133e2573e0b41452896aa016d67cdb989908578f18415f14eca787ae2e19070db89a415cbc87b16c98f48aad38cd743890889f8f8f819bf4a05fbaf850c9cdf736602a312e72bffc935c7e339e6b01beabe13d08b85f5cf0a45bfa1f27ed5110e4c4a6ea608e8fbe44f647a88b1efafc5f7f34c879ea8804a0feecbf05578c612ea7ae612ebfb97f21586b482d304a2045abf65d6260b03cd0e6abe810107232db811b1b9dbf218d57be48724af21746074881365efee65d972ad6e0fd1e11e21fb2151b3e5d8de87da899b2962a3021fd52e10d52b11c0aafba7d299c867262da47132b07ef611c7bdd056492e3b68c9c71181a215496fbaa38520a7aa80ca244084d490c26f4f20fcbed0348c6b474d7d88f511b2de24c28e3294223802342ecafff7673957a60f2dd552054fa80097cbb3c9b137411d6cb71d4d46a1b0111edbaab9760c1b5ab3704ee6995109878dd5abf188a0e04d977cc3c120466ac1347d4a9a11c685e584c9f3a5c17b493d3967415869d6f79d02267075194dc9b5cc582a4823bd06128f1d451032859bd5a9119e063082b09c7b2c4d8f82840e6a34b0c08de7446efbba9e4e3b504dd072aa4195120aa5f03854ad68530dc03492aef0293344b016b4c3cc4403cc1cfb034e2b87382d4beaa9c0fac21e9f151ff036573a7d93d050293277436e795a925cacb76a90998cb852451f40e9397904620ff43c5032db1b5cccb86e9ac09342df68397631368b9aa09e07bb464fb9cc4ecaaa4077018d35591b6142061232d21a899aaaacc915c2244538152a0078cf539d5f345c6962aac5205066d900b81403b113dffbc08860f529841ddd779fde756002cac5853c22799c66f6a221efc61bb7351f4a2939320a8932c1de87b24f470681231613bc656526685ffe9c065be26db5193181deeb3944d77321d5efe17a5a3a6cb902eb79c044fcba0255e1de14bb3004e440975902353d66ee96923390785e75b05c80d4d7960dbc96012aa3005f048b0431d8b856610b9e044c089a485345a66372a4391e050aa5cb12eb8631618cdcd66a1c69d0d4a9ba1b1ed47868a102e81ba6790056ad8edb9aab5d4629de44f4e60b3d94d203577982dc18fa311d9c914d6b6fd5ae69e7d1e14ab7ef4d1e4dd9eb4f5b67a4c5c61771d77002f32e3ac450da2cd6f6eb428bbf84b668d99bdcce4183843b8e611bae67c15ffc32ab25016a03eadcbf4385b1ad071a55f17678528ca64aa9a2aa4422d9be672e7e5b0151b648dfa74a0f83f07fb69fe63d31c8e77d3f8736735858949f3fd34ce36817b476ccc7cf57456ec8735975a78413d489414a6464ddaffb2dbbb0c1133621de936fad22637c42e1f64e381a2e9c1c8443c29f1c2b213b95a722b72b38cf46c087d59701fdad23c3e6b2087c625f62cffe62f3f7354a50d347d919cf506c5329e2e19559840baacb654d8fa831765dae33879819f6cb4aaa8df5742e3c6925034d2fdb5047282a9676accde57146fe4d0c4ca6e780129e05577638ff32934a35237b2f75e1081c1d6e10af63ae31fb3d63841b7c632002337e282bf9d73e62aca7d253692447eca13b8a0c0c634475ce6fa0be150fe5e414113bb6fd9d930f99241db724dae9380bc14535af67b250a003058c507b9ae6548691e98d79cb86a3014e1ad9069b335739458511e6337a7e671c514754ef5ece8bbc22d2b82047aa1578ec08657a0ad1ecfd64870e2cb77d09deaaa45e729a91497b9b71f41c834315c9e88acd6123f3447331825c2c3929d0d497caa74f72605be6d68f933ac6037e520591bc945cd1733bc23cb229be0ab997156c32c4d165b1b72513207d9bb1969050d5050291b52ee83a54bacb32595746dec0c389ba14f32ff2531f8a93bb892a1e9f9837c689b753040212420d1bd379969a0d9a2b2d0efc84d1ae80d9648d88b726014ebff35eb8cf6c4636ac13f39cb1dc0c5619fb3441da032a00d969939005d00f0fa0fca779999f4c32ea5a612dcc40586b0ffd383e7a685becad59198ab60f6817e0c9fb5f7d08265cd2071bac7bba70ec3cf13c1b0c47e7a72514f017154835824aaaec0c21ba19ca1f215f4083624835af7ea0e1266bbadfbd807d9a307f1d288a3566c3370db0144e2aaefec090c81ebbe0ee973f29134db58f18846e5b8da919ea629e9fb1ad8a417cec460c28321bbee00b08120a8f4b67de7f5ee4f0b482e06ed45727a3342330351f9fd58758d2a47ff8f323f2f1e68c1a218768e109d15dc9ac354735a4cb73b205453c097059d945c00742ad1e4fa556614bb852a486c5919b404137302033af8a593bace23aecb8d71531583cd8b06aefa0270b441d32506de30b587bf0ce1ba315bed903941fe0b13fa36d7a24d07022f902e3122eb25f2d82a667989d495133bc546997b983c27bc2ae51334b1eeb53e86b3ff974ff2c7c1cde502066a1acf39792084e3eb0fd73a9b6b8e17a3b0833331fb5a17255cd435a1dde6abcb8a40207c2e72134b27b38c660a58d565573a4fc46d30defd3cb3d5a6262d0311f672c266403487f867d116db863ed72c24ec2308d19e5c02abd7468a599611c240c4a68ca5e5baedf2da3e4c047ffe323afcf472519a886cf453f1ef83e873c89ba3dbb1547b98e43fbc3a33d6bcfa811c06f22c29d75020bdaa53f05d9ec2baaae97795cfdda6d9f88b6a9da0d6cff2e360251cd943a60309c18ab57e0a34c71e705005621f69c91169df5fe4ab79f3644fff85720e9f086c9df9b06490fd50bedc5ef8834c69dbd087b1c26d831fce4ac28bcd463e57035a8ac0dca0c8a6c558f940d1384982f51aaf206a2358c1e1c6bab3620b0ae5b8310f118fd58d60b83561be7d858fd784e7b070b4106e543a7885d75da4871466f84bdfcdeaace0c939fc2ee45a8a903bc3b04892293b61fba6f3ad2960b16c8e819c5aab957903046cf335da09d5c998e79b4a9967fe0e00940452f587fd127041afa38eb92e86cecc1127e1bd9d81c8075a5c1edc349b7d1e7d0d0abefc6876ec93902ee822cae30e85998404d1d4e1c53d5f47f7ea08055be279d1e2d02275597b97a96cf8440d243ae8fd6028533b18ec70b9be2d5cd631e266d0824982b900b26e2a62ed8f8583033dd1ad2b35fe86730fd33c1c05acc3299d401b13c01be7ef042608ddca4fdd8828777488af673e21262cdbb12a7d2a0d14de108ca1fa738919bbec42622cb7033e73cb95bfbaf5dec2abd35088761675f04b7844d50aad7339bb1dd8de126b3123ab7365dc4467d80563a1c3092452091da5ee55a45338d5e095198b01b8b7ace6f9857fe9f3d2a437d680497b15e2c31af087f061b4a5d08846c452ed6f5cefb1d31ecb9f3e74b81f6a701c37e1245074ec6108009bdab63417ad1e857d979a6bd164b52d9942d16b104eb6d34566380bc34245b661742f22a07a09de6373b2a19988b1e870f57f37e15750c0bc34ec14114782236e4c5eeb4fac0f4a0553af72e00a839bd14e2d0b7f294071ef5f493261014484791571a443ce14a815e91f006e0cacee1b6e1968b03510479baf120b73c5a75312023d672628af14cb09bcf1bc70d04ea09e3b7ab22482c7f479915c434d616898ca04e62fdefa3051bee426155d4626ae680aed24c401f0930c88028075239aa2e9b058b9955a2ed6f8cfcb0dbeaeeb01ffb164db3dc4532887e6a74d2984535718594f305c916c65d9acc33b95953d1ded52c4fc485b96711e575559ef43d124de4b03b7ce9ffb637ebb5fbcfbeee715a2f14e8e887728ec4db95225b0d29dc59881eccb78b8eb82861114eedd478d8d9d5f2a989420aa48ea2ca46f73b6476928fdcec2a63c350dfd3e31750754f0ddaae5b164b1ff29b5e1d15f09cd58197959724d85c176967d98fa8a14ba37de052f7f095b8342c7eef18cc85bd5c42a6258f226811ce6177b5a7d6705a8f2fe18088e441f4cae4f810b8960d1abd0dacc9e36d75e2e2c3c26564f79137f38911cd388c9e4010e5064c683fa374bbc79d2b24b213155a32b33ba047fb4f395d89c5d79073db28cb9b5a424c15552facc98d493cc070093a3993e784db5633e19354deeac3ed5f68e3eca23caa221915cddceb0880e12f4a08521e95422e9f3e2fd760e4868618bedfcd94e6853c595ed0d8875299282a7427c714f1c6668654b16548380fa6aa7c52335dd7cf3b9ab58d70afddf1ad0f48ea8c801bfe268e6b2c4131704b90543f283adb59134f40ee3e07d87929045473422b51389b8c63a81e2a074d967ce4315b35bd8c495c85180837e9c6ad0148cc51c95683b1f44af1912998dfb4f7fde5c7e2cda9c86e2462bc029933404ca83fb885be5e3b1c37ed46197d945120835b2e78b6ac3256e4a43fd67d901c3e6173e1f142479c0cca74ace2abdff4ca791b96e73c14fd25c63b3bcad7672b43405fc308d1e94caacd3712d9272015c478f5fa576043131ee9a6f9c5b0a65e7c8e1cf625ee32da2ab623a5d49591900958e952762beab54dd0c19464b48b4a90581c8a158c7dd65460389fac268a47617ee6a1f974daab7d73ff51d5aee8ac8767206923bed934f410724d643dc80e3635cf7aaa3832c4be66b9f3c5a5d77411d0b98466e2dd71ec099552a0e7ddb85dfbd99e40273e272fac63d793803439d0284067cecfaa324c991a45063a1c96521abced68934ac360155a7b8740848a6ec2b7158d3d7fc031e133d226c38844dfff42f615718ddf329d38e51b23659ec5a97d19177cbcafd1a681a96633064aa5c350a581c41ecbf55317e4c825552c6142157b2e2c2912569cf5735975d656b4c149ab39d1e580e2b8a3eb478d46fc6be527084726fba2c5edf2575b57ad00aba7eeacde5fda77a81184e907c6796755b6c9243efe90cf9e5db71c7505d97aec829840867d6625db1b314c260e7a19da807c81efc640c3b417512935c47a962915aebfa31342331b064eb706c5d58c3a1a1a98e2bdaea456d19c869e013fc68a209572bac42465c138b327a94cd221baa886a0455d90df121875ddb444b4caffc5e651bca6be2f983d7beda53fc46d719bf4883393b73751150174782e9d4cbaf00eacfe61052e5b38c7426ca4c5c513b59e5e2a6d0e66d1e9bebef42df92696b3ef8fc79e8771987a2c1d496708b3c5bdd01bd83d9886f274e10e8434d0ee796868d676d5cdea715c64594043fcd4b50a49a1c8c3e860bcb887d325857200b53ffc2d5a80bbe9205a6b83890e62a0ac540e4a5a8b35f7c74b8cdbaec851407861d3711cad4427f5328ac356aa5f8b806ffad440b92df5e3c505985c256dc2034039bc840cba83b78f5076afc7478593195a471920c0d238e6d5c3d3412ba1846e7cea1b0eb3506ceba468944ca866966550691e2fb4869bda3d7df7ea4546a6a0f028da13ebddd1615392c685d21088d6a752dab31f2b99e63d8123dfa01bd57978246d229a971f703289543bd4551a8cc326a6fd9d46f409641e76e658c1b063aeb0522038d9a3fb64ce89cc9cef1dfc3a81fd8b04e200ebf4924dc0357a6fa6cf66ff0d1860a7bd7987c1edc775d8aba9c9af02830a7a03f3908d7faa85c4eca3ec434f4dc661b02f04941b1133885aea2d70828fc64e7069a96cc4ba5d85ade11aa5aab94044171c9ad06904cc5f0a5ca1fb7347164d6e93cda91c0bfd0216b5627bc4a6854ce402476e59d25a64062e17f296dc7bf6833a0572d2c10b77adaf54d467f56c943f9f3b8b7b59d5aa6f4aecaffd1d005e2401b66d34fa6127b5d99dd9510cb08fdb9287db0cdfd460736f884276030a20028961168319cd2073bf89216409981ec38f205050b0e9d03414bb801e5d9b927f95d8f9628b7696410a731742d49f65b762e650b103fb279e298631e80b2dce1d6ce1240915104e6932f9ea5f3224ae503807984b8e87ae05ef90062227a83a687b69b14bacc9a9445d7744c2c41b803e0b9d259f78eba1017b217bdf422810b949a0b977988893445d6039a5b3d7a2f38cf5fbdc792f10db545356d54c84a6d4db816a2c8fee631e1769745e385202c25230285227ed69dcdedf0ad8e12a59880cf933d80c0c5f710bf8297424fe582198b946145dcabc81daab943de811103e168309cd1d1dd459e910b74d1530623f5e5fb441e34ea21ac519b5c97353f93ebe6ce685983bc7a0bc345b5d02e7d84ec72e82d883e1f75086928f8b54a521b502288fd7e8ddb3fc4969a5c6a8f300524a52d34973ac06668e08f7ad1c4f1d196f63d3a24e4b83b1cd8c4d01783fe7b3022b43c9a68a5e4c850868511437e2823c7f78642a991b70b8abd97d709547a63efef8d153538c4dc24d0318c9dde9f332d42698df8540bfbd12e151b2f4424df74723dd62ce2e04590e72842d264517a03645efae523114f294e05b81a50fac76ba093e8e8b961db7bec03ded2937d3a4747ee36e4bb8e50efc6b4d7794c33503a969e05eb0845aa17f541f747cf3a9887fc5cb43f38213ba85bfbd2b189bc45736de0ec9fef66fc3b0bd8b21da02f919807c223c8955ea80e90796d2515020789661cc3f760e46da50b014fb6ef1532939c85d1de75e722587ffebb6d869ce57b52dffd16ce338677179f41ec80053744dcc91872bf39481b0d7b7ad9d9f61c61ac645423a51b9106ec2b48a7edf1cda8c5b81df8d4e5ff16914a3f8c45f2b0bab9960469a8b3bb5e0f566adf7e6c14c629d03c12540abdee7a9a2d1fe4dae95af84e34ae56ed57d7e08dc1cc1713e677a5b5ff38d6d3c9e49908768b85169ed72e9911447bfd7691e3fac129337c067dced96aba03660dba16a35caaee87958d41599052d6031520746bbb7022491465037282ac51d361ddeed55f6450e49af19e557bfaaecede3ded1505a68564e365c5279ee705eac930a6ceb275d9bb99f416b052bc809733913b6ba6e750cbbd4d71715f7e910d78e2ac7a3d0bfe78d0b7e184a0ec3a9dd43adc77fb6546cc6a4f7bc958c298add5de1c374253023ec5387cacc60a2ab2316d0e12e305d1f68710662d59ca03ec82a5df08308b1e73f49795b60ea433da425749218a55ad8a5e8836000dfb533e5e4bdad5cc86d5f01687fcc656a8ade3cd2e92e2f3112877716479a2d8bde22e5e2dd9676ddd8039f850958072147a3787272ca405d052bf7b8943fded7f6b2309dcc36f0e2494184384e49103e536c8e76c9b96c7cedf6f81d08eb589f6a71d2ca14823f9bb51044aebe507019932037cde204f63df5c50229b0dcef72b36e3f54d279e0c5044b7b830ba275d246fb788f51e321ac2f6910f7f9c2486482b2ee1d009ade9b78b7ef7057d991b7baca47c423d6c0bca70ddc8a26cd18e25d961c6def51a073d11c060c0989321136bffe9ae1b5b1bebf09b9c771d1f6145f872d088287cf47ee78b77c86b59a69ca1984dd7ccc7df855a1fff33d4660525419929d3a59fef52bfc9c173f574e07219afd4603cbc29d7958658dbb4d282823b2aa76e960053da1a8eb2d678c3883e8b60ec18ef7c51b9f630c6b8d3795a98b0d623a1d0acaa4803b3d80cd2c586741c6dfb035b10381aec17bb79597d5fa3895d542c2e5a47099a944e5535d8305a317e8fceb0b8b32df8326d2d9495c365ae480e54388ff5bd5af52a6531b8b52d71062f081afafcf3b2c7d5e40bd497d4a4f05634df232beba30616e8deb843054f88676afb7c62b71e8c27b7c71ef649bb34eaa3cb5a21ffa96811146f25e1ea5b0a3107457ba883aaf6eea07e65dd09bd8cb81d5fb2c743dc01c066c6af22921dcddce93bd4e51045c382e961044b2efbaaf6b4680e3efd758d41740c874520a998199ba0744cfcdda2651eb8315f672ce092437bc2767e2f1596ffb12c9a4788865f14c6290ea068db9195da8ebc8b16ab3ad4dcbc0d9a38b31b1fa268b1cd622302c9ef35ac62e703197efee49f4836ce12664e80bea28517a654d2310c4aed59a44a3fb13989cb834448fcaf6400f04dc367455b76b82e7d1734896e57ff5668e2afb0affdd633443457c24f171fe1b37d9768c52bda8e17919f25180206b159f5bfedd0f7b026bdd15e86a880d3328d3fe0b53c29ee1aee38bf2f4292a180267cef8fb26ffebe2b378423d216e659af003c150d2646f352f3bfa40880aa4f912d4d7774349d4b34a1c4f6b9ff4879c2b77ffe8ea814b045d71ad78392bb22921dec14a20a2445e2db0097e0c31284ca8ad9a4a53296ba0a175c96f86118f6ea2b75efcb1021324422990d6f60d13324be97c5226ba61ff839c2a14f1180107d54afdc0534394c79f9298c012e140840dccf87d5a09b9c58fcab8eebb1c8812338333878c3cbe4cb3c7fe324d67309c8fde32c6d4dec33e1a1a7e90da24e131bf1383d05a5ac2d4c5cf8551a039e487180efbfe55cc2439f703863da81f5f6d172b4631dc4c568ae1f4d542a2f6cf5cfd305764d64d03918c488e31c3c4499d695be73541369138d5a7f8b1740a47a8a38b9f7bc3d43e01013db043524223b0deb75174d92d41e506944e0b4cd5d079383d9542c0cdf865fec0b37efa75bb30acf8186316e4beeef78adada2dc5c984f226f21f3efb7a5e4fecbde44be6793ffb9ffd85d6fef142cf4ddef4d1229ae4b22107ddbe52167bb06b1cff4076e3fb8b34180c74fda4f08f428c430a57c8522d3eb99e2ef8d20f1e30d05bc23cee31645e5c12a38ad5fa65f80dd2420003b68d97195cdb8761678716499213ddc73cdecf66e7ff48cf492c4f6c622a4ce16c31e2cef827acf8342b0732cecf55855fccb448661984e82f2a46ef5b8f0c3a9ece98ddfe87f32f788651c20ba3c7ebbdaa5d0d3af278ff9b6fda789e0f5bce721abcfa04a9c98c20ec30d4d1f690d4dfda99724ea3ee2a5d17e1a757b02fbc4e597fa509ef6dede3bfe6120a72b608f91d37a40b46733605d907e16fc2b8b918012c5a98cd68cab8fb25121f016caaae69544dfcbc0aecf175d9b6e5dc85d9302d5d67e4e513608c3606c0abf481daea76a80156060f84354d56da00b1a0430199f25b9bbb1c8090aaf00e5ba0441503c0a772b735cf4d83b5b06c7df38dc3b835b85b8f44fc2e386191bfe9cd71e52790af90c50048b9dba9ce9986a1de110a6540d8215abc0c1c3b9e152d43b8b6ae6216ef66090da7d21fecee386ff728bec2828cb26ad6cac053403f53a218fa3c057c5162416458484062f27ab1814d753d377c3ab39018957fc5768c6cb160145186f696dc1d94eb5637be75d860820ac6da40d2b3073ffb800489bf4dd009f13e04e47b2f9bb618e6ea5b351efc4cc3ea0dc58624a4444c5caa5d33f79cb4c88a83a0836a8e8a17bef1698af49f39b88f324ecc8405160df729738964c708f055a8342cd7bab8365e281db18f9668c16c10f9d0c5e8eba22bddc537246a9384d297753aa60edb58488240497faa23295957cbd210212f710ef159ec819c1394c0b325fcebca13b01252bb52c803db7d670426c2197c5498ec377ccd732c95b6363788b25ac93ec7a3e47d09ac893f95cec1e5d949dd57190680f52b0f5eb0c2fb678e5cc848fdbd2e87187d81aa90d74394ebae76f24a9fe446d437f96ba6cba187a6ce3f3f0e28849ac872ba34832b8038d341d7a573e4989075f73d04171ea7e8add0fed1cc1644594b2d83c188d8e448d8eb4954a834b75cb6005fa4773c4a8d9b700702deaae3175296462b5cc0f58ede96cd670c687930c2bc43d56ba5df0c359f576e03fb84a78a489f0894afe62397f39dfd995825ccd0688055ca14bbe817409dabb83aff1ffb63925332e4847f248e2a67851c565fdbe6aad82fa3421bb6b92386a8cb018a06fd1043542d50105376e715f32fb2196c221180366ca1073e8313cacf243b46ed8e5e74527a1e50f332463ba1d82dc67c223a684e1033b218d790082dfd97e24252b8b106dcc3cfdb3bbdf3271e50eaf7f2bc5bd3bd40831607f729eafd37cace9e70deeebc2e4d812f42403f3084ad874619de09c814fffaff6e5047d2c15432252b8acdfc6d1c5236839c864d0643230d3085d23821d069096ba22ca82ee5dac05bb7065b2049a0f8f05075669f3d50877b0450f56506836874e9f7703ba889a1071706307288ad923f2c7130b0c57b53270447ef98517d8062fac89f2629651b21ebbb4f087f04c76e8aa59cb1610e94984e96b2766af1b4b4eee94239ada163dbcd146b550cc57907900967150b86da9ea8b7d04808a49e70a788c3ab94c5c60ad8883ac2e5607d40f28a4470da07b63951440b0625ee3a9ce156001855670bcbc5caccdbc70dc53df1ac10c629de708a61705b0505a41381a80dac458ac6166ab35fec612ca4ed5a90c024058fe0f9b76f9849ff1b6a6d1de21dde03900f6a196d9771b9ffe11a1f49370576d60863ab97b1bdd8e3cc9771fd0f550726ddfc5704df19d503b616710b72e2c8b8be68f5302e563a506b6543c1b27043be44f196557feb6be5e40553052399b45ff17b54d5bf80c30e4b5378af700538300a4f471f8a1ff1a61a4e3341fc848bb4f7e35ff835a30643ec10e8a10f9608563a07f054a4c7d0a0b00bf69e18d6f8bf55619449747fe71934ee834f33cf86467ba6ec8f1fa114325f358077185809e959d13334981cf61e64fa70225ebe6f8fc0c6e4b9530be2ac388abccda910db5fcef959399f17b4d14dc6f98fa36567b9024be4f5c002c7784102d1abd50d43e38a6f415497a4cefc63502ecbc2158c11298b39b1caf7caa98cbc100ac691a44810289da75e65a477879dbb4e3cb7f172ddbe808cb5aea8df91d7deb8b68f6adf345808a2ee6f5c62f8a043344ced800de4d4c9dbfd70f303fa181494c356a1b60a8665abee4ec6696fd31c3ff41fe76f0fa30c028cb0d10d5ebbcbbfdbf9ca67b8347e6a050dcf1790f65a5ce05f060fc7ece38adcbd1ebe05bd8cf91875ae49b1cfe20ff809afbf1b5b8321effa1c20dbbabba1a5b7b7b262215da735c733a801f9720d3c79405c584049ace2dd77d4d8939228c1e5fe54b42cc4bb6a428f29100077b3168be083fbe31de23548152920b738a5de776d40d00eaf63fd8bfb8694bf6a3c9ba226deeeef88c9ea590bf8e31398903378d03012091cc3546932475dfc871371e08008924047afc3d4666421f1f9d3df4752d7dee90f7dec604c82686fafa8b532df9175f1ee96c95362121eb99691bb804ef498311ec70e7ab7de2a6b62139412ef8877cb110e6f1b1212e4f382f8ab7c896a9c38b51e5370d9bcd9e57f2a7367cc3d40012827cc237cdf62402060489d39ce7cd210c8d76b7f5b4b077bace44c332b481ffa35ec6675f98961fb82abfc34fedf614ec35f202cc635e30e54181a6bf1cb40924f6cd042e038accfb738867b365fc3498af489a85be7e452a678c18b54e92b9c17c83af72fd87b5c2835dccef3769d84c4b40cd2f62584fce49bb60de389e823f6174eba65fdf1579e2d9b81aee9606d5d65e2e16e4397448a2f4315534a1d51fc3ad003841b5525c6e92bf541152949ac41a2e532f170f5f9e1baa361eefe93c129a55106c504c40e184c38336c8c3851add3c316bdd1ba52c4ddcb8e35de75bb05bf796c54d4acb5400974f28d4da425f4d8cc70462ee8b5d1d81f8c362442fcc53cfda82c205a8321f339578694e2c4621217c6bf44639fe4cc5942862becff9449b630e92e7f223b52111bbc2d04a3e53e11a04c8ddef947d3c80d5c09b00be685bec0629f14969bf588e4648e4ccf3e483e110f5ed7d32cf494656b9de2af6a9d3ff4d494b2acbe17a536ba2e2872e089dc50c29e44e5e63130ef92007a3a20a0299e286b712b893e2302079b8311861bd41e41661020ea3f0180c3d971d79be98cb33d2f39de89fb7fdb277d0820c94178232bb57caebbe828653166e920c9689a14ab519f81344a4730182992e128778d15a86edd4d4bf506a7a911057c366839eddede9f02fb6a84a9f16aecb7ccb632b6a5b3eb95e389f2ea05a7b64f022bc5eb81e740566c583f01649b58508378a1185869a6f3aa1fc5ba7c7ec3d0edb6c9e65e03eddc3b89ae29e32e02f773f9c2c044d859c30559ff78670dc180ab3da10d8404f9295087c08ffb506b5646b50292e508f03cc9df06a31d8593eb283879d9307306c4be0ba216b0f56b686374aa8ee534fd693fb147a0d41adce51240f7322341ce019e4f2ed791aa7779fbed640f8d01da7b59f36364e5980d41eb8333e76dc6c0f81281554bc6d388562da116524ad5c6d9d6dd8e48b9845472da76ad5ba799716086fa054d5a3883c91a1bfc2cf8c88cd4d1de121cd625bc83dce1439e512339b33bc9c06464e37fb705c268796538a5e2e4ca0cce95ef8c32cbd647b58b9f7c5c85c2283d1e8962d21e9db37a92d9c3a8503f91c89f2d183d8c085af3926863b46d6608a8e1ca181a3c60c42ef5eb726a6ef89e4e3b5c8b57c6d3237753e9f794f16c2e0234a943be85c3a57509ac83202ea4d21ac82d2f4c95a4fc83f86564809d4dbdc45471dc199c7e5bfe286830c966cb7a700c5e08bfaf4fe9ad391b08633e8e1082eda31c89f54d09b3c207c2445eb12699ce97f58c65a6d9e8ecdbbfccdfd3758992eb51514f575e39043d652d61eeca8080e762b13290d42fa285339b9212715ebdd2ced70e0801ea0433aee66cbde2f405b1f0ddb7148118f84be453b165b7446029a1364796c7b868389afa7a6f1efa6c42a878d6bbe39559c73ef0508ff27662d3f42a5afd05a0f09303d206808a404b71a18767452f0265cf6501e27d467cb3736651d9a9c76d4f65ea62503c55b8c501528500ce145389de09865ec5c0e437cb164339ec31e5e89c275076c4f483a254275c15568784ab981ef066fa9225832c760119a62239f709c74d349456abb0f869b9814ca3b13f332654c5be8d5918497efebfef656e1401969d8705a5e382f86e0921190ff4d6fba4e84fa81c0b7ec570602f0635237012bd901c4de7b0de4655a2c58929fecd17c284d89700ad43685264d5107f36dc96d7cf1596321018325a1d6d79f6de0baaee48a0c1bb5462d4e2499834ca5984400f2399c7e999ab792276298a46391dbb26063ef069c2da021f024bdcf12051e1c6bfd02104293da79f2b212c6e0759ec8df330bd7ce08245ce3bb7e557e3a6526c894c994d9da903ece76e433685bcf89758f35af860f14e0b4592185b73e98026240677c49d7767924fd745fd7d1cfa416eda5b9b81a309ada71df18da18023fa676fc36fcd96d4838e61039e9d62faa85028b207c781872705c73e505cdf3494f9f2cecf7898d809683c3ded66b8ef8987ad533829a66105ab49603505f144a6a05e168049fd2fba2baa93c672c69cfda4ef3d84c9309b78630cb71cc2bce636a34f012844336eb2e96759fe1f60d81d57c035c09bab77d8c86835efeb2ac3379d3e5a4c65f22bae4549dfe4b05e9268788ebeda9a6536d4f9d8d29c88d64c874534125780ee12f29b891bf39e62cb3cccfcb901f465726c11c02d9cb2ddb285efd3ecf1e84eae0cc4461e542ec297b14f1bae4c8582bf1bc6fe78c4f47ce36b6515507372bb5ac91a558d140cc42f94fb0da52a72780df9ed7b3a2d40017ab62498a3618478a2454d5639cbd0b3dc7ac490c70df4e1bc3085c901c56a0b31f59d7c738e9a084f52663e8fa0ea35ea114fb7cff55ef7bb7e490f9a58d84212a605f46d54b06752d3323e3647b2b6c6582f4ffb187f8c84c8552ad295de7c938dd3b333d3a359f3acfd901c8bd64a745722c2b2c4f4345c7188fc7ef79df7a635cf09bd5d7f5fc9f176f17b054ec4b3bf88d05b86a4443b4bb0a3f2f331002f7b02dc031b84df8b24a29114801d32fde5a3d38d54a0f03bcfbf5085c59796f355b66ebc1ee2ccd142f08c6752cdcaddc80171bb14d32b41f4ef05a9c2a35d26942c431626bf596e011642d7d2d6debfc654da62fbed2db53f8ed3f130d08b694406e69811c529aa143de40c2ec0ac702a386107904acb7bb2342815f62404f93a82a343b40a64923d4d5048a4b623c421de2fee0070df46b117663bf0f343b826ab2bd9b676e3ab5538b02dbf67cc080b257b0ff490b6a85015d8b79fc8cb6870edef3d76fb8b8161b31f5451c6581f290b2b4e992f740ff3495eccb222032195ec8a4d7c60c747c5a302638494774d15222c93eea0089d470c81f1ad0a6e300a18870c817d211bd1a444511d23e97d7d4f4413e4836d73d72bf1c802a7f4ddb42d540e6d134a6bff6110f67cb80bb13b6793e1a4f1a864a1157ac7d73c0f437b5292220c55368ac5cddcd781fc307b0078e5c8efa4cdea8a71c22f08aae5264ebd76354805bb1f273f3e2d8e57dd0084606ff0ba168a24c8d84afd0d138c2a66266258199aabc03b07d010c48007567493e29c0f2c042f63329ccb197b690dec1c6361ecc2779b0b96e166ac1dadbccbe51ea4aad298df093aaea3df2ef84756368bd179873db908fbc56e4efff1ab47564e0ca6b5b2d91542f97547f57e2e3c169232f091926bdcedacc011ac3a941479bb73289e40749c5eb17e8098df2c73e4bfd8074166eead3dc7ec011aebf2845224b7232d534681f20c2411a32c36d722edc463a6385791d880d056d176ad470338270b7e9235d7414d22e9d36062403a467e08c0274f44bcfc120820f7b48ddcd44e1f27dc29bd9300f48c3c40d0c5481520bd52b7ad4d848736111f8f7b97fde6bc03df283606deae1bc9d39de4c5402c7ef939c3abc52538c7ed32a686c156117a27512335f9252641a1c9b33932f71ce6cf40c0f5e66709eb332109e318585408fce1bd66560e2e6b11aa4699969c0dabefe1d1749a1e47917ab06595c7cf1e0922962a8fc92ba30661e7845c172d1b3d5c37d58115909dc2172ca04ab9c7ee56159f7c6bd100b0b1f17836dc572942e58d759fd4a82cbc056c3e2fef1b6a8d97bd957a868c36f5faec7d2568550540b5c7a0b5933fe270e40039744f62d835406ca8cd8256b31922e48748011b36e280332706e3be3e78d195d74a346f2ed127e1e3e59662d4bd0e8574917ce846d51cb1d22765553327b52362bd75e46a2329b40e779f973dc43e5e73e717101cfe1d16136fa2a84ab145509060ff54d0f6834e209048c54493381dbd4575f33ab2a8925bda59d953ca3ba6115f8f9c90de1c12fc58f702a4b88bcd936980a8bc9a003ea2cddc9f25bd1ac1f7ebdc71b9752f996d5f2989fcfc5b13523419447d1ca0412f80246df048cf112dd5b56dbff13efae8e62209e8fe2934cdb93d3457cf395fc56380ff0dfc99241cd917db6de2b9d63289679912d330185582e1203b31c1c73d8e5eed909c207d0a74c914805fab0d2d41ac39fd00b6f2323ab026322cfa8441956d9644723a7425f00864a3062ea74aa6e39e48240b046a7a38c8eb546188b00ff8a1e32ac154f07185aed167c6054d0a4553eac5febc33aae5a3890dc64d4efbcec31ec68e8bace0401cf5f3d58fd0ce244ba99991cc999d5652390c1034c41cd02bb3ecc631fd8aa7f5923deaf884a8e695982963d58636b2dc198032e937fc99bf53da8f103b9e8df0c46d2f3d7a2e6362fdbed64a2f3a83b5a9612de91f41b658d6d8b7d3ccd23dd098cb3a4c8d84bc4e03a5461e9d79633fc5b2d3548f3be8d5d7ca04cfc5e386e6c11dbd067292f23b4210647104a866fa53ef328f9efb1f8ea302c75130019595b9879f6cb51c34095ada5328b8183d41c8bad20cbabf107f3f6e1783a8269f519606c695d2b46dbf2fcf3227ce13a09b7dd97d281ec831e33e631660c1550ef62caa8f9eec64a758d311c942746df061520a3cd395d6b2b83c32252013e6314a5600b8a3f7642c4d54767630ae69d4db61b90beec2505d8a64fd821930facdbf16fa877bc73ffa38ad284db075647d8fcb88182fecd32df66febdabe28116f43e72464d3ec5e1247d80ac601fa4f9dd47d8df4aa86894af8a3ed18884200b14db22bce8e1da00718c75f1dd23fa730701e285bcda46a972960600a68ed16621d5016703f32a71f65939ae1b08aa5f527d4397a8db7e97e91c6b7a250e8016ef45a08e3eda048480bac1933be1f85ddb7566d9e0cae478ed5d07f1da20ffda65f8f4198ebf4ee39662b150bc03fdd0817411762e802faf8f46e2c8995e142acf93abd2ca067e0d7b4d41bf65c2c1b99a2df4e420ecef4983e021e2e304aa4fca0b4bd04ccee587ecf1a1a2278ccfaee6f6f0e6a418a64905d4927506df3c5719d6d1f498a612a70cf89bc73d19fddbf072b65a69ce78c6ead7a93997436e7768dc204948b3469840bc20e24e72d08e647e1ab9af92522a6e417e15f16ee2a5e9138a7a5ae2064b0b64329cda446414d2d731363b0e840a1df0a39553d19df8e0358b7530851add4c447bf01026b9c603973e8d1e0eae594a69cb090b3146e0ad436b104d55aae3ba9a2dfb389f2d2349e640d296effbc6199100fdee2fd2405ae0f78f28aacf772570de600f7e4d473a604f24dd4e4cab5bf7b54b76904c8bde70130a578b479801fab7d80fdf14d6e24e99cf07fd7da4a23ba869f6d80d3c14cac92c2b602c753da87abe9d4bf3f121161fdeaa87b6cdc747e6c826861c14076a5fd159dfffb5b36e45d9c11dcc39a27a24317d0b64e9c342b956a2cb5753cc3d18d9cecefd8d19b5a73c96c3c37656dcf5c85cad59bb3076226fe1f01c6d45e205d4c415a637f94f22f3aaadf4eccbc14427ade84da446781b66fc8b4c48755cd0e565b502f2e6233daf541580fe46d8135ed540e3dbc4f26d9effb4e03e4dfc3d08abc1de42c1cafb0c68880b94b51614426a04131d671300170fa04e905b60befbd66dfce0a8611b697f665b80ac204a20c29c01d6cfacd3f11ac73c7104eddc2a03d2ab0d5959b7b54d91999b01f1f0187dd56901d95b65b1090050e32d00a328dd889f50d8afda0ad2ea05f952e73a3b14ede232ff35a1c7fe9c1ec57d6135ae9888b713428452fb44a32ce931b95268388a753654860d54e75fb3158d6499a0175da09be6e549018ff92019c7c4d5a7bfa30271148c0544a218f396f27b4fb652b92b4eeac07cdce1ee43d771f1accae37ccecb4ce094e7ae1b8ddc146f88f7ef06f6607638705c1fbd9877e48ec04eb1615dcc0f54e7c2b201daf9fe1d69c79d004698a2526d03e0cff03a01de8f7f4573b428735a4ab9f43e97b6c222beadad9ab56fb1b03766fe6a5e0872f223c4cbbdc9978e4d5dcfd3b82c508104fccccf9b137053c7c424524da279e80a460c0d3d262da458d2bbd443cdaff8d9b43d15f157de6c212200427e09daf0da00fa6b84d05babb9c5b361c894321f25aa5ff9bb6c7001849be6857460f36bd05ff1a543255585ed69d41287dd90d0cc72f0eacd702d2a1f239f09e184135ccb2fc1c1e53acff2b5150e441abca48f8f9c8fce2ecfe9933ca7a2436228a25dd85ac6c4492fa81b52c9328a76cffae907234639b948e812a0e6199cd83559ecbc5420e73ee5f72cbde6fd2a016a6c78266b2be62063d21a13be99d8fad7cdf501a0d2a752a8e6532a99d807ccc1ce3209a964d3fa1a5c556d7aaba806e4269b50e1e5af97a0d46d9934e83e64a59958136d9dc7ef84cc8dad8a21a8fb178b18b4dc786d540c27bde468ad646790658b922b08854ea2c0b793c180a2e4212af68b44e0fba1bf3de6ce06f1b8a30f2d75f2e8ae124bee9f6c984a61cfe176a3b419adf89d39e338831faef5bf31e14e89041295a5a61b4ac98880ab0dd21ae0da42ccedb891fbdce9f1beea2d1c7c5d68e43f03a581276155f298eba893c6e076882aa597b8acb8a02c555c76c9b3befda966620d1a2a99cc7caaf0b62b4a9a77cddebc17f70e1732ab947b7478548f12cb94bbf7e0dfa761e6c0a010f1bf092eb08ee9dbbd12adf7318ef5f3c37822152f7083bcd3bc5ade28d45e32245fe395886544bee46e57f380d1630766aca58c737484d5b25750ef77cb4e574a5726a97d9af14853aaaac596de58a52964f4c9bf0d084979b3f36430b560148d2458a3e8f74e80a307e02b704e32fe1d3dbba71528218033744f0f48b92fcbdf19a05bd112c0d3a25f576b91031859191f261710a859debb5d916ba70e2936815b57425b8f3135cacadb7a145044751f535a3609a6e12c44b292416a2a392d6759889982ca1624ee7c699e24cb37b6d0efb3428fbeac018b218db6fcea0b201b5c197077c3c655c8a540331c5640a7fc4bbb97524edb23dc504640b61f36bd1ce51b912991c2fb93593921e106c4a96bc30becf2298b2eef1f119b17043c3184810aec263fea7de7fb340f1b02fb22772a8a7844a60e287ad837f1a6c6be658a1ef2908f0ff1dbcba018a2474aeb40dab9b89faf2ae3be474f38f43774f5ffd05660f9817a9a257b1d606e7f28dff979f49aa65d4ebf15aaa9f67d2e3824c61f8bd8a5551cb130b2327a4af0a7c971971ff08cfb81846eac3dd6c52f7340a8e49faaf4acf9d59551827bce014ce3ff8540883d29e5c564eddd363b95989c9852df111470e90ebd24a20a643758253a89f180f2f1774ffe5bc7add46c4070f4912db64a3f3da2e14858dc8fafdc9486d67bd72adf31533108acbe3d3d94af29fa9ef288b1598541d415e2baf87bb60d0fba0fe29e2bd94547402f1a84835fe73e2f4445ccbcbb5fa79ffc0c26369c422ea70ba3a72eed23ea116dc24927c5aa25200ff03e6502c0e9564d309924ce31ca8d13ce61330e3bd2344767becc18d182d06453e9b389e8ab9675eb5323ea531d11649517e38b35b7a08de9f09915fb3e729aaef4768ab93384f07c9987822c75af1170e2ebf362d9d6b48b8a763b9725f70979c08c119459efd8f49133330fd5997480730e25f9e3bc63d60159c09b84d6af45c6ee880717c5e3e337b2e054d33fc99d3f4dcf99f0ebd8e9a8fb2f1d8467cee5af5aa21dc42ccc662baa65979df8dc421a6ccf22dde2710e8c9954e27ac5809704f974c19e750ff5b9e998346da8f9483bd2cf52892c6fcd5cc9438171e89121185cfc2bc82165fd4334e5aec0bce590d2660e697b4a3106ab351ca4521aa31cd9119b132cedb7513fe7345f58a96a8c5a021f17b35116a0cfeff9470fa97bed9484f57b9cd91b0055899e24e5ece9201d071424693d567dce4e737433be979ed74f89646444c0a22325519d960fcac6c295e76306cfce8ace62b489de22a5dfb7d860c5a6dd8e5fdb203f69133463e507af339d72e392834ae897662c9977d1a24d4071a2354dfdb5cf321311d0e090bf5411e36876c39cb1db43d20f37c8843c14d8b84112f211710f552480d00de17fba214a4c1be27b3684ce88e2ad23f10d74a43f1fefb239243704f42437e8f30b4a4a896e9871dda007154a4811b1e5b41fb3c38225010738379b86e2eef09c9739046dbea40b4cd2ed0cf4d678923bc64b0bf9f818bde626622a7802de9da6e5263c00f5aca4e327bb9c518985abf75cdc66906db003f8560747dbf6600d37915f420fd1779fcd2014e929b98996ef7a420cc58f8661c540e697aeac5f3535116d29a6266edd969af0689848d58d76f0449bf05c05077a1d72a00e9f03478786ae1c732fd2098dd780027adef62b4e9ba00afda42e117df7d2d0048939034589902d6e074d7f4f9dd326daa95c44aee4fe8132580350e15ab628334ea2537c8bcc36dfb9f82d92fadd19fc003c8373a119da84f7b140b45c095dd44e42bb4e7f00ba6122e22f723ac76c4495d949806f26ba30cba9d2813abebd14168c1dc61b1fb46b8fe7cdbfa75e7c0a59b56e142b5e45ba54c2551f3665e2f85a53103bc4f49efc7f5a2d2b819458df1adee453b8efe747ba4c60b60f0d9ca827a19d5b6cc9c633549ba3f1a71c5e63c15444ab87542a23f74ecf69c7e9c04329c583c4da11ec4f7e7292b94f90a51bd9fa8bc9cc0f03b8cda126b6fd5bffb1d4721d6951efc85af4d140dd2c13a26891d8ec024bccab8e3d32da6b428926c9f0509d2f75fd21fc77ef481722647dad24ba85c043f22bd9a304c4992955c9f683d2527ddae3d1f341492c98fdc83442e1999e9f4f4d93472899a6eb9f67382a116ef3d9e9a6b744852f9aa85c339307943ec78fc4fd33aa6d84aca6999cd272fab382298156172151a7cf905f1d89351ae4efbe3f9ccfdaa6bbfa94857a07f04f1180eb7e468136daf2834628819312d59356b1bfd437ed989c6e4a4bd0073280e357ca3ea80834255dcd811f21cfccb594458caf0084232848719030d80c011b8818f980d42c387665a23cdf0f50ea2b985f578462088c3136c954be243e1632b80e4c7e705d797a9304c50f127b731c1dad22b8b9e222385a712924c933ffa9a11403d00ecc99a01850f70f6feba747f39a113a6bf29d43b1624921170bb2b4cb501243139d57a67afa35a4154864db2778b8aa2cc1360075689339648e4c3f4f546adeae5129d413b02ec32eb849a3b38bee894a6922f8f32534fe26fe22a1ad22dcd562d0586b4174aff8262fb0d77cf2f601664f3ac5f4f10e5f07cac64e4170743e18c97be025650c1b20a35fc188ca98cd69e0e8ac5bbb47cc0c5069326686d4ce2f4de07ee38ff9a34b046f4e5fef42269a6baab657d0c03367509304dccf6c992accbb916a3710559a8ac4e3b25e4eaa5888116a654fe7e4a547593658536a1e153e6546cc431e690f73338a972d114845bf7ac264465976d37a0f08e78e388ac4d2b97448fb63eb7872d975876e613bc74bec42c055143dcb6480accf982650c5e729073034418ee91aaa1a7f68741bc68777d718708bf0489362733f4da8b8d6893f3cf7a949f37b419621fe13587c74ebd9b9ca3c5dc3a8186658ddc2a0a2d2bf442aaa0e108bea52a3921ebdd80244eba3cab89ef5c70b55aa158b271a4b5322e8af3c25ee3113ccaa0c62d381289a5a656fddf2abb6463162e2ce21952dd9d88ff327f8439bebbef16de26567efef12c0351b126590b7d2038440c9cfb7a9a9a0671cdace3597a8ceccb0ec70a7521d04d02e6204ab5525f56a59aaddf603157bda1661b0d40751c800c9568c81992310e00c465151889b4e80008c14255dd6ecc4927858444e73dc4aa7773c8e9808f5109f92dcd95fa7a10af18e2239fe81ba3fc4365d9be2d647d55053494d9b12491c4a24481b7dac617c4ad2e762798429133bf66ce1b460a6111bb447221ceb7ca7e6cf9123919a6b1e426672e65a07bc26488fd55497701c4c4effe41bf67927ae8c882aa51eab0cf5ef5b8d59949c149110ddb5cccfbe0cb27ffa09f6e1f95a39868c0a65516ca16a1d0229c9487216fb7548c0043e4936f4fb7f4692295c9e5a16ceba9dc092a6aa2b1abbc0c0a10cfacf0f19f494cfc721e35e2270205ad65f806387a5569d42b23424e2283a67c85d7ec08fb3d1a49d4bc5dc0e5839d6216d50554c7d44b3da5122787a033253b32b1c829e56d245646fc1631dbeffbe99a26d83e15cf9570f4f3a1f25ec8ecde29921bf254af06792a7238cd18e076f2bb26a750e7e725dd6fb161e3d88e5462e69fd6453a22ebb020dbaabe5401ae087cac66ca529ed03446dcb0be2a9e1520106920900a515642efd4db643b7f8a445ed0643d0b8fb1f86a42de7ba47207b11a87e56e86ea6e5ccb42749c38559120265532bd80d17f9b2207b1c13c9ed2dda1fdad5d28f6fe738c48b3ce407ee53a0ae3dc3c73d6f58520254975c4381b600016b44f727e07bab87ed93d0ebd312e650a590c01de22ed38cdb4e5c46bf471153fd6ea6452869251ae7c2049c5674c7f57d1a46f6cca4944c7a62d8488d5d1809a91ed4639e755c4d68879ac36fef29862c1cfbbfc370177ce3c49518ad23413d5992ba907d8e62b089c959cd79ff48371142f117f091d41ab4596686d05914c4f556885de716e3f240834e0003f0847af41be9cfe568df455d04c775cf3a13e39848915e515b8d81348b6ff2b6ea3262d3c7b3873f167cde0665ed6cd5b7a0b6ab2fbe048004b387ca5d8b1b74644a40d0c73705127dc4d846d5ad813c71e55bba9ed0f144c501f2b6fd307102e84d212a1068fc1e36e3574fc2174f4119c6368fa7d9e79589a35da1360b49876ecef094bf49a4e5152830c9e55fc1d614b9f9491ad2b52d56d2560d965904b03276af9547bf3097fcbb99f0018248a814ae7864dbb2b3fd715fe06477e49130165e8277493b7257d92bc3560b3ff2b0b8b4b08bbca3968c51f6ac464bc63f70f82cc57d96413583b749d361a87e0d57dde09ad7990324866c64fc614c08b6a47695576a996b37e493673994f8bd5b395557b5cf379149b0cc905f0a423259c4d9baa9c75cbf6be1565f2006c63dc72892b865b4a52a0c39330ec202723698357cbd5d09c8d9e429df63b5e7cd4012dd43923858c71856529a8b9d203f56b6faf7992e569bcf22a5eca3f874ada4860ca7596919ec32ef76c2b1a1e08c66941844f29478fde5c6d60ea702e83bd1f8db54b40bc4521cbf573d917596ee8533384a189f7cc75fd6393f6a1755d2bdeeda7dfc155543d3a2e49901d3a7e4564c4b83466b71b1b6742b0cd29d2be69277996564014780a96a1aeaf8e566d8500c8ce893497aa379f16904525a74916b1c7c88a9f56cc57fbb17726822b0c6af902313fc9e149f9bfcf2598ebe1816e230d74704c15d3a71c3bec10b183aa2a874452f770ad5069f8df22067245c9c3e11ef900603124234bd1b4fba3a34b01edd691c2d39f4e3dff13f25690134e3f1ac1a131672185f918981da4ac25fa180a1516626a7788ff9161e68a719f00a2bc49528e956c8b296a2fe3271b20d4bfa7f6ad852f4c0bebdcea87d486735b476739ab5317719575633b46913081dc6007b7e02c8faaf9f73bd8c002d5a1db1a44623485a7dc2b3fe600b050b0dc4d002a57cb2763ec8d3d63342d9763eb863f3590d8fc0aef9069f833ea0958b29fe1b69cfe0fc45e2c8ecb34d51b2b1c5e3175790e8918e4a41979c2803bac587ff513c902a9772717238a4dfc0c3f99d9fbe23f7ec1968722933882787bcf352316f8e20c28dff2c22c38be9d95ed4f2661ff84539df351fe3129020f634c7e85403c613ea7c48f9df0e416679c478930656ae330ebf1297e443ed33de93a51c640e6999e4171bae597d44141496a235a2d0299a6782c7e1e4466a9803db320e89219c37f9196e41b81d778542f596fce605eaaece8a7ea3781be64e6b9282af6ae688e514bf3b68c914581c8dd114374d8060ad313552a039ca493867c7404c78e08b79fe4a2350e076edfb0c95cf0e531ae4fb7d35d3d627e9d789a9a97c49a62963dca03c5324454633564ff651e4c1d12d97594ab3e04fc79361161e3cdc4866ed9392c5a4b06b166b233bfa98f2405252d9c8e0b6998201b9333ec832b6e64e041ba146a4121395b4aab2778e965f01f6480e30e4be370c85dce2951d22afd1f8d69ca3fda1dfae26b833b5fef488c096766de23685c81b4efbe29c68e5b74c1619617b9dd485eca7633d49435a1c6af1de6f39de7b404d3307e0636f6f222e52ef98641f74e8589f72f6abaaa3cd50a7893ce0736fc8648f669b8ea692f0fdff2b7e0674c9cf009c56ba68ca34db85c1ef4a8bec49ce23d97398f71c4bcac23b309146fb02c60f9fe7c47c92ae533bf63aed317c46b56a4c1d4dca53d30c89a1c4155a11b6a25beeb9699cea90cfd5b8101a347c070089ee208b0096125757c19ebb9f9081c08f80664bb878a8a8715e62c1e4b06fac48be327f202a412a318b5abbc82755c0ad3757cc1a5accb7e6f8285fa8388891e13e9e382fc21e9356898ea19c57527b68bed66b24047135d0c4265bf01c899867b3cf33ec603b254ee8826830c1ba24fdc4dc214256feac5e15f8ef17149728d756eccf67989de43087e80d537caa99aedc2cfe7b0b5cce309bc2f769b46870de19bc4f2001a92da4fbdf31ee6b1812d435f854564422f6f972c260104c0f63366b654cf46a2c756236ec0d03966fba1af4896a0c1cd6fea753a1fa8a38c9acb07375281d8b64c7fbec0858db3fa79a43ea4e9345143df9b8c7e1c771ff01a7203de9f50a363d992cea950472444efe94c538bc0bcd9ed847f260f8404c51551d42a84d59905f2092eea93951a99bafba989bfc5c2ba2531448c063dd236913f8b7527e19a247a6628fcc3580ad87da2e4fe1b03e214d699aad02451650c46be6bce3c23e3197c2758a00b6085e1c6c546fbeb8e703068bb63efdec9473ecd644dd44ad4c6587d06d871867719887b7e172648b23e5b4ac40d6811869b964e76d5ac959027550f18943d5e6dbbfa52b9fcaeab49cc348c634c1d43533b26130bce84c36ac788e547ef8852c17e7e9b2b3c09a0fbf629ac7c8ff3071b65d54f515dd85edc9bf6e387dc4627829f8938037403eedef619f1cd0185f081d8dab065227ba1823d3eb3a1fe115704be610c9692ebb0c5ebb51b3d147f9ea65bb151fbd0ca7d252e4668bd1ae6be59b470f98ba916d3f1212576ab60563c67b21d9f13997430364825181cb1fca2600184a21fa0425572b0f1615b4102ed2c6fa387a1bc97ec40317d4f1ec9f1fac1a408face3aff2a0cd60f2c48fbf4b71ddb1e2d294a770e28268feb18822b5152386062f450b10d556c18cfe859cac572ede82629710a20815e3800e30fe29b1a04ace1d9471f8df994b400fe97f86e033b76683d920b4ebaf5ddb4e21a03a02a5d06742c31c97b2d2541b889384368ca5826b450d26abb983495acad2fe07ab9bb1d813071801ae0007bbd3397ab560ea7904e049464292a24abdae552fa3c68c882e4e4a0366b7cda73cc2922798834e1683c0e6d9074deae807044f31eb2be018d65624bac4836f4b9e0ad4d0e823526c5845d73218c83829aca70c383fc2349e92b697d41b250084d712c88f598b2adce4a784407a0f9d16ab8affdf71d886b1f1286ac0eb46bdd2b3de52c788973f26717dd8d6dc1d403b501b58606e9b628b96382e47d92e6033ed199c92bb9b9e0443fe0b18d2490fcfcdf93f3de15b24a73dfd1152e79d19272220a4581c35770aec84394db06bf0fd3a91e6bfbd79850c2618840aac0a374c01a788c8e407323635404def5d02751fac01807af36aeeeaa3e181eb4023d01a5c2213b6aedc414374aa295e57f6903d3c4f11269f93650e8b756785c85aa23491a0a10e33a76d32875a6fc7f7e0d1e891b5ba32d4002443abac6471cf0c212f8e9742b6096227ce9d5d22da97c0bdd1e88da09d14c8ebaee574a41649882b72ebbca693b465f45dcd7c52620f1d1508cdc24873cbe0c2c9e200d224089e828eb65cc14aa27a3f21d15c6124ca28cc6e5222a58b987f0d9ba4a3bc2e3c710717d1e9caa49469b4900944ec43c8879a73143dc812fd6ffd247b6f27fb1e0b3626d6ef6365540c081c3d0f133bda9f04254b6d8f3a02fe2282675416c37d0bb923b6edc842694d35711e4c41032981c44381f51f216048466e1d08ca30d35533b061b109f88945001ff468f499fb5b77f261960a688d97c8a0caf054b0af3ce90dfb477c06ba96ba901223db0fe8001ef316134fb21499e6db92e45863d0f3f4fd64ee4c966c2058ce531fd4228c3242766574cbd78130d8dd66a010ef7bfca02c3b5ca3296f2883e30b833e71515be97e82c74021e3a78bd7ed330f80726a284fd737fbc0161ca11b82aeb8027a0b016bad637eed8164a5155578978140554d4ccc650d6c632522b6258683b304a607c13b4bfc8094dc2c12f84a9418ba48ca37016c7eb17da6ba88bf69fd892bab99c223810954970de12261f616f1cd085598e5d9a65ea0dfb2da3064fd13585c233288bacdeb23f507645860360700a4b1d86a12089006fc7a51817f260cd1e4f6a502c3f0692e1941ed8cfb4004f879dd2ed54d2c68ff706da4fc91b6c6f3a906b657f55639902cf1027eeeebf046e2a735978a235084382a1482544b184c3b216f3aa326ea82f94f5a0373c07ee3933b122f735abb5a5d6103f91f95e5ce4ae43e5e1a316dd1fe6a9f6b3305b52a081abb97a37566de8856c9f1828bd7460e4e609f5051d221abc33a320332d75ee821d0b4b2899314aab4e8dbb8c6d3b6d439d0e47ee92423b9f72011f065c026bf47a90ffd9368182ae1f778bfa3ee26975c4f457256f19f4bc69b3b68f6d12d268ed9e6f12f94762d5e0668117851b922fc55ee8641ccec424fe360d59fb84ff1e191e2c2575d1045ac24641a5e5bd6746b5829c814a3c36d6bd33bab42b894a3e7690943368154da716d372c46afe72affd3edae35eb6595545a444cf309b383806900a49236011410c14ae259f2ce7f3a89b97c4f629c83236b3d6ecdd7bd7d70089580209949d24f313dc91978b438d8a89d1370b711d9270d331fa3f34d8e50f1d8d99bc6c429b2b48ae5f688be0e61345b643259cc413cca12e74771c6efb1bc8858efd46e1d560942691e47d1d5334882a3311da409d666db4c422c3582c131b17d2e0f853cf33e516a3c14bd6f2d14ddb52fdbea60c12db23cd021f741bdcc6f4d2a7886eddc0d1a1a6d6b4500f5a78ac256a32b689844c39eea588dba1bdb81bbcf3eb5f8008e0880c103b0f24526bb59e4117bdf22271e511684075656ebad45bd4208eb16c6c9e0e2031286b91086d5c257bf1fd2e81341637d02552b2353fdb7ccd61af16948ba32b1489fed94557bea9bc0031329d844f1ee5b337f80c1da5357df1ad13b496e73cda09fe3a4cfb90afa39de2aaa7dcee5831242f5895400ce39a4efa6395bb9d1f1f582f216833caa426f0bdb8c145eab46b78097a9fd7acc7ec004066307be7ca31ccb0eccc4b1dfdb5c71bf7ddf103e58035f9962dffac9fcc4a53869acd44814e7bb7006f123b810be32492a884f70620f3da0f360c98a078736e3db32eca37994b3edf8b594ce546c3228c52d7de85a9f2ef4a595b896bd8a687bda944f1a4b93f469e305046059d99454d3e8bc9ad51c01c85a71c34c82835e87fa3db3e8a4897ecab39a0d4c84f618ba0aca5b8894073a30cdcf49bc6e427233ac324b5bac4758addce6a08540a6413c6ad9b3668839122407a75b8f12715b07303ab22833bea1abb10dee94682c2173c5cfaf41129ea2008d9977f7868470e0e54c94368b19c5caa08b26c55f6952dc264172ae3e07a294a620021bf44e7f51cb6667b130f53a0d1b877c3946bd6a3d6d6b2789937973364536491275dc530573d6af0606088b1e998a20cd595a9b4c558b2ab1d82ec94f32ab0667070ae803f128899c6cb835584dcef17bd65414a5a7fd1c83bb0abfbf3ca0894571ec8a806d5a612a14b1503576e362a70ae02400c7ebdc3ca900530622bf4242dcbeee49eec01d6c72c1df9076b84e9c8b67e5f8465ad3792b0be4d025e6f8314054595b4201f9b59c01bc0b6972821fda612133f2571547c6da56a2c854406e0bef9c7418be83eb7bc697ab56600c63adb1f27618056876b4da9a950693c76a0cd6b131a361f138bd35bbde6d3826b9a43d8760ec2add22cc7666d20cfbccf43e857291be0a4345fce193a63fd0b8e9c7cd12e323a6adea734e21d310f08618286d30d6925322dba370f0e3706544973a310ced7076d60fdb8d4d1106b53c32568ba0bd55759ec86d369860ca67aa54a86bb7fb3a399c3cbdbd6bb14f5e728ec5ae4a9e29f88b672c181d0e499eb4f806686dbca10b0814ef8f72a25dd1114868e4385b6a8e3e50f3a307650181d355c090839a7cffafbf899b7c28e3f7e777263db68633f620029016cf863dfa7fe87c00f6b04ec4057517324f5e1604fd4ad8c927311c64529459c72692cae0f3ff1144fe8ea5cdcce0157a1a89f53c064b42708ff8753b04f511a15f9fb50b5adf339b51eb1215b4ab23ba8985e75e20218646809522c4fa5c88b9927d8fd8caa94a1c7f7d249068008688ea874583094f495270b5b18aeda2c662c56d9fe1afc612f6f39a44f04574a3073c28f5807bedad0ff73aed6c281aa1ac4e9566bc4d91d85a5e4fb0dff3506689d140197624544af9a840125df3f2306b5e7f5677dd02a200547f9be70833c186f1310cad2480acb21ab7104b5682bbf521abe7da4543294cf50070927370ebb63a2f94a9cc12b0c6b24ded69cbb5b6e75bf517119f879868e801068ebf7beb21db0f59e84219aa7fc68eca6f55f63bec86251ada339f74071bd9f65d6839057bb506e691b05a3d5efac7a2919ec3b8a404d800688eba66de6865a3aab61d4d702f5ea11405206e549d9fe574b102d5fea4a0acfd926966d7fac903869f34c6b641aa2a36c35c7beb91d1103bac45574f424b33c63a5ef0f4817887fca0b010d145508fbde5f6d4221a3a7ac76d494c09b06a8b0f516fdbb219dc3ba1d0c7722232cabd0747922b2b288055f5b8b3806331b0415579122a53792ac827f8f4308969e950c902faa4d689e4e7c48f9b908f84f247fd272e034200d3f4fd65af374cc98fd7b4fad4332036767a501eae3e322a05f967e18f75ac81e4409278e0685a67e03fe29b9681de0d32291459f7ac4184c30509875c58817ee6328d26f776e0cf69543be5c69a3e0e279a5ba2cca7e19bcb2055cf15d823c54ac976554f73ebb321fdf6bae8663ea934fc477c92c0506eda12fd22aefe6a0c6aeec8a8c4c0f8fe966f28e5448d941aa7caf2c50a3e5a2cac91d48e4c73199e5194c909ac6b835ebf50fecbbe1eb58432b870d85d0c55478e5eccd66f66736385140f80527213a0a31775b0c76b20581ef92c9174ab328525f7ac8457c8fe0c4f6c152cce82b0258707c656c401db8f4305dd47964f4df762996bd3c8ff16a954e336c2be388e44dd9b51ec3f362e3a304f08625341ee2da051e748da8a616182bc35076164826c9dca4e522e45724d2c031f4f724b33e0d5988559f7f54cad5184edcbb73a99497b532172104638886452cfad9f0dfc3d794c87a066baf3c7723a9f32eb3c06290fa76ab41a1afce34247e2845bb1fc332b65ac800308034bc44bb62e43769bfbcaba2cffe473266f8cbfb7b1eef1d56eb83d7321467394deec257c752e08ca7e14656caa0613b0154bc966184f51a4aca7c19f247c5e5afa1b159481d553b58f62f511e4532dd72b8d7eec5120313d432cc174b3e255ed159095adc0a82acfbf74047e5df5756c941fbfe84d276fb402abeb65398025fd98416d73d5f4040ce0ba9ed87eef0dac29616ee81ada76a55e1558bbca71b9da101536b5c20a56bd465145506ac0dc8eab330a1ab09175a557835ee94d02040303ea08c66a59304ada4a07ca94563ba85f41b4d278c99dc0f1d9ac5767b6ed689d69f5af0b387a812ae2dd18684005c6748bfc1880eb014401812000e24c29a6b439d2dabb08523cfdde2d3889fbd08110479a89652d219b10b9a59429251930067106e906734e2927571fc6e3e8d6d7a8e4fad6174eceb9cfe5f90d725f977af2eb6bb6810f79a70593ca7c61c486f53a6b807bcea317fe8d4e698dd297a051be1a74999cf4c339279d4fa953a79f7d71d639ea74e9e71ea07352ca5646a5e4e8d00ed672df1cc77134d2196f73b6a6a8945c12a5d4b68db67fc7794feeeb567deeab747eaf06e3acaf0de873cf7da1d0a59ffc7a4424fe68e6faa0dd1ff4fa171b74ba2e18bab864634ff5e9caef0511dcb1bb4ff7f9385a29f6c4e432f674bdaf44a41a43babb3bd26ee4b89d1833d483e5176c2c7f3cf2a63edda37bbf74269dff94d66bfdb3fbe527bb186d92d660774f76f7492b95eeadca7dd2fdf3ae67a8c04c7df1d2650b162b531a948212a504eac80f79bda9871521041078ecd0d141831a3428fd820689a00c5919b262d9b362bcdd79c3bf99694c225de45b1b2c345762a8a6a494524a29a594524a294379a5f49f1ce52847ed0f48932447df3fca4f4180d81f2434f51021041078ec685076a7b331725e07baf7f46e7ba5fc29b33fd1c70fee6610ef8d530bbf5c4ecad596ab7bc17c7e2c502c4868c5d01051d117c3e882b6d1e76acbf5f179801082083dda06f4f19bda16fb1f6d135af1f183b46de8e3f353db883e3e0f699bec238b8f2e3ebef8f8303efe47efe3b354db661f9fa78058b674f1f245828f323e3e53b58d468b9f41abf14934bc8fe08c97e1157d081278b22211903c21598f23cf0a3545e0bd66907069f5f5a3e6c91940c0191f65cc90417b7e235a8c2f7e455f0d238b6051d12d1261e609c97a789e2d9a7dd1ac6806a36856347b51342b9ab9289a15cd5aac508285d714c12c2899d743c88e12224f84a09b540713a0b9353c0b626d7e9207e6cefff1962238df07b681bd165c2025682017ba7e6e01b558c49aec67997ce940573ea05d561001eed28fb2ca9f6dc05d7fae84b8e7d28f2392bcfd3fecd4ee345b56496a5303e401800928b0a164abe1d19e06c2357afe24251b0536003041b30c22933a26a5abeff55bb556ffd6ac25f09d5fe5fcc2a3cbf5ab2ad890dfb9e9e8ce11fcf9a8f561d3d19def5cc4baf5bba35929d6a55f9dacdcfa0e38baf41ba1d5fa70c7a57f745b4ad66bdc44ecacf56b55fa351d4d49d90405590b0404148bf9f8c82f080ffd40e7734a8eb6f4d8c3de61dfb57cdc7aa1530edbddb2a0c90fe701f93c07f4f90f4cc307ebfa3c0eb7301b83c9a72fb9fedadddcd7da957bfe9ee68465a1b6855688363ff96d935ffc69aaa68b34fa7a3aebecbce38664f15fe199b2f0147b2ff93f2bd8c824f43f1fd62321fe0843807525f5edc762b1eefe0c621842f5dab3a0099017f411c6412d2fecdbb5b2419f9fd8a0cfe368210c5efff3f1e3f0f7f164450d361dddee73c0d1757d23cce77eb27f6d7552fdf64a20c09e3d7aeed10d7778097cfb73c0d1e56f848a41fd92923c60f9e7d3da16d26c341ddddae0837dd436fac9a49715d1a46d2e858e56ce6b4ab572dc50d5026b8414dab8f106e84110e32635d8822dcdfb4144d2c134fa250fafc5cf8a6a50decac90f7ee01bfc8569801078b5fe0d648a6888886463361164305de32f7c83a718ce19d6224444ea0ff987db1f6fe8b1fc1dff0d3d16838814ce0f798a2f87b1214f319c5801d30f89601ac4cb405c090755c734777e48e411201ecd776f01f168f270992c623d2dd171cf588341c0ce1e3e7808cb8c350983c0f58fa09c9dcca2d3d17766667667eea77b910a96a347082baad8f8b1bbdb6f04db63b3f491dcee7102d1c58f3420310f908e317afeb53774c5c60f1baa6df1a31fcc3c60a6ee3f687d330f98a9c10e8815af6df1225e836ab02914bad199ead7525ee3b73184cde2d82454954441b5947fe467fe15556c7fd874428fba9c85c782196ccc6a97aa4374312a712ff35a9d958bb5725eebe9dd1fe5299dc6e792c870a683823bef4c478d90efbcbab01ab703c0fccd6f7e373dd7ed6247761f7aa537d341bfc6e5cb5ec8f3761ce78d9738ee0b2284897eb14e37a5b33f7bfca4586bad1f950e846b5859fe38e79c13cdbca22222c587b183e50fa9971b7fda6970c6396beb43fa533acdba91f29cb37e94ce47298d0dcef9352acdb7d16bb54e4ae9332d72a97429669d62289d540dc67751c6f20d4af1308d39db3199dcbf2042bc8d52e076392957bb208f32d519e4714c5dcbd54d97ab6bd5ee255b2d57e55e30af1dd6e7fb94404b2c22925154aad512b9128e9f5cac2072609a5b49926e46d9b3dd65db9805793b92b9fd49f1935c8982ac0b7480d0af48c54296f3d82aa6b8a41bbe8c5ce0aab9fe15ca2e3939779494eac288054649d0181aedfad1751b4237b420061114aebfacccf5ff6845248aeb5645c4442b2334ac00e74513474ec6558873dd7d8517ae3fcbac8dd93044132c35486498e34dce4c5dcdb0850a23c430b9cbdcd55cafba2eafbbbb0fb5111a9281242b159854cb19a97298b861cd13366160d842811eb89871220a3b58a8a250a11189648c3c81228825392c01b5a409244a4045d14413719454714aae6c58744abf40830ec0163756ede9b2a7861b2638214e7f3107fdb0cfa01ff64e37e4d860ebd5bd3ca7db7173aa271be4d8e01e1d2c206181273c54b920c5898897354b70d0b2660930696612467420061d862c11e58a0c0a187385062c70947499ba891045ca9233718218a24224b304c914726c28e365081825503e4860eda172e326e3c62a3d7bf46475004e126cc87cc1f3821411091782d0f3860916ab21261a4e72fb7f072e6ea2c6cc81c2654c9cc6d281cd963554f2485de1c01909c0d1b38207a67093813a39a48042981330d0c3130f767298624d1a20a29a70e3e508be9244892b55ec61c2c40c0d189e9871c24b9d1cd4e88083935372b516800a2368f0418c932b380065090155878815ec541d995795a353ca9c6cc0c1863d5e907ca0ea095368799669a1061922375ce9d2e58601a3eb8367e6d0c5a5cfd3e6c67632d7bf285610a59452c6b6648e3073fb9dca500d43553ce098a2d79e4c800e2865465df9cd5044c765e5860c74fd9bf93b5df719752b8862e50720cbcaa917d7bf16554402e2733397aa0f35b09a3c5bb9f0961545d87e968a32d3452e7f7b5fc0f2739e0b443b5fc407bee13c924dafebf444487861e687fc3afdbbf76ebf0c03367c294cfdeeeceedde979f723127f122ad8fe10ec7efbc3b46b5d0393997f0c8d61eeeeee39274d6e99547a4ddf75230ce637c2e40c61fbfdfee80be78bedf7f1c3a474ce3929e539bb7e8d4aadafd3c53d694be7a5a6633a29f9081ff2c0bc6db3ad63becfa51fab69777f2170e64faf2beac0535cbe5d99bfda56be35b6df5d7eff7494cb649243a72998faa53785f5281c4654935017596388ed9f534e496f13edd6065f4b5e1cd1aae14cbe776310379c71f4f9b66e389bcf97e8deb82dcfc9e5afd10397e9128fe641ca6849afe70f01cd77ef67ea20a24138b6dfea8e95fbe343e22fb333f7d5dbcfec1c3b4f8d22ac8d51ba0c14ac946ddbfd41afb4a00a8d2759ad2f18121bd63be7ec1fb257e85ccc59331116d69fb2d60ade56abf55e63be754e4a69e7deb1ecba97dd179b8dbbbb2c224977ebeeee37acaf6be7d706ed0d9deeab41779fb35629b95d7a741ff938babedc0b629801da69d7bf26f0d545f9cd5b91cc68c19ddc9740d62143d112454cd81891fa89a4b4838844e97394520e4783944e999c9fad310c950f6e63ed67e9609d4d1fdf0fc96a6477db8854bf93927b2993d51a265139679d2d59e78bfba8bf9c3a1aac9c94f5d65b0290fb6ab0e5bdd7eaed39651c83950789c80673fa10ba3fe695f5948884252333b3bcaf677e82abbbcff75783b4db05cacc9619f64d6eca555aeb944524fe99848529e5942848191b8eed0f6b977f080eb7fbe01bce7c269faf578b481af862fb59ba0fd7fd31ed9bc9fcccb345062ce52a37e9945f8e22393ca77713d681d39df90db9cb52c8ddf283c4c1877a68d1849535c89f909cd7c7ebcaaf09b418b49d974f60be1dbf243fbf6063fb65ec6f06923fef87c5f6f30c03bff2671ba47019851be3f4a5b747448a4f0401f1a32fa51ca594a3b6894bb1fd73fa74293bf2972ff9fd47dfa6d7651bb876b7773bbf7f330f9a897eec84cbb78d981f02777757db1d043fc728fbe5927e6d0447b918634cba3ffad2f05397afd7ca752d6504c1a4a4a5258e23c0d4e3f088632a5c7af9492b9353b6eae75d2725add231101293612dd8b0caac943f64105d47fb29ed29e5b4c558677e1c1af3021b9cf3b32f1ad86028e7d7f472d7d2c5251ba5b87ced94dfd57facc4ffd658ffa4db515e8b8c274ad13b586696ccfcf99857367777b770c2caea3daffc7cc82bdfe946588e1f7edbb76459202bcb79cee7c4f6cfef6adb22fb38b12c9d5bb2d71cfe91df935f41143b65d490172c2c30a92347e6a884d4608888362f6317ab757f19665c1f86b3d56a81d7e57245be94528ee3a4ac5e8bafd7cf1d718ae935e59d2925c7399d2f67b73ed3b95596b130cfa9a8a76348f45aad46a62c6c5f03afd5ff205976f4ff7c902cafaf0fdbf1f3b02f08e8b5da5f90d71744e6b5fa3e5f0ddd8b2c045fe1d2addfacf5f568b03e095eabb5ba97da6228eaaad54b83554635589fbc56ffe5d59fe1829ded787dffeba9da36fb20320d6128afd59fcd74c0fe83c804fb1200fb2ab08fa5bc56bfbe8be11b7cebcba8b679f1291b566c64926a528873c51499988b192d2ad8b1f2f4c41499e695d7aa7ba150d589396b121137380e3f437684e25499c2c56eb46ab2a652999161aa4009c5095343ab1b4be50e1a8b6dd98d564d84b841375a35d152c6460795166bb495b88ff12348bfe3105cada8e30d5602624d82cec4954ee2f43e88e0017e92b87299a2953c028709624d7eab822bad1057fe70fd19887e3522929cc05a2be74f777709e3e0e74e1a6bf45ddea493ced70738904f3d6205554a6e8aa5ba22365ee160274b75ad1b358a4e569414bdd1aa890d564e2ab4f9a1092758c26c00050c6e77a65c5551530394397594669cee464d1365d5440a77a35593175a4a645f545b707201393a4c3dedf0860c07dad0f1a2840a940b13865b0c20da54015506cd1ea80a9464d141cb9e2e4f545cbe4c384fae5c619eac71791e283ac5a6e54ceb2c98c4cd75a35513224160e12a9dd27b8aeb5a375a45e9a9024616ebfaf83a76f000e127ca5fda5cdf6c03d7cf777d4e57d6d74bb69eafcb13b2b67274ba38e897eff2fa4acf0619ecbd31f6ff26c978f5e362ce4c17ef4f6c70466ff4dac4407efe31a0eba253dbdd3ddf5dcaee6ee6cf76d3f9d99fe9b97b83eeb1bbbbbbbbbb6bb77bffecc05436c74de90c26fdcb38a54fe9dc735e392ec92ec95cde7bf6abf7df73fc956b45ffffffd6ec97194ae7337dd9b77db9bb33cb33b65f1ecaf739677b0f1d63a41c7333466f15ca505151515151f9f7cb6436262cc982255905936de3aa1e9630e181a362c544cb103676a3159318506042019716262d5059a2a73bc1fadc68b524abce195cad22a0e8095735a9f610c58505a90bf664254972d3f3428ea7292b244ebc90e30428174c0fcf28678c70c560fdc6aa33542e246c7763d5191f6a37569d512393b748c410af3297a9122853dc3016e667314c217395b42974a70577ce2548eeacc011535684923dd7bde63075a513c7f40699e51a93ba7c4218218c507367ea46c4e98518a42c0165a4033edc6192f34d193bdc101a0acbe1fc2ae286421440c28412d99697150c5dac28f074e54b580e69afd2c8ee6e67336868570ee04af916cacb952f3372a3d50b6eaea4e2caa9223e324692343726a57475eb774ff3d6a7cda1d1699bb4d3b6f959ae448b402d1d55c086f1d6f5c7162d4eac5518592c77238c2c56c2c862dd95ac78ad7eeceb932d121a417d32aff1ad62bd56ffc8880d7a8add62b7d88d888b0d95c4dcfa61a4cd695b5512d3b69fafaf64c595948ad450c98a95d62b1571a5d8d78ff1e5b6caac52915bc1d852922bd925ac51115a7d0058891544246e7d1a1d1a1e5712fa0a6514652475eb7f68f474eb1fe160632ff4a12d039fdb7db45b44aaefc3840dfa4cc8f2f326047dec577c26ac78a1e70ffad8ef08fa66afd847a69f6fc78a6ff6fa40a624afd517fa66dd9700ee639f095976c49ebe0941cf7d02e80bbdd06742ece947261c1d811e6bbb293db5adbf566b43dbedd68f7938bc563f21661e701ffb1ddcc7bee83be8fb0d8a8d3ddd786337afd5d853f78291c5521859ecbc31ca86b19b7d877dd04cb49b074194b51fd26efe2d6fe61f6d4e44aa2f83023f1fd26edf1076bef51c20848096ebdba0e5df0ce8e3f5f9101aac1fdd813c1d3ede8e2bd8ab73b568731aacb706ebd36eae5606fe331e0dd68f1784d8cd9568b758abef43bb85d5765f28737db1dbad456eeb0b2ded76691461fb95ae8072e87884a68f9f0384ae8f9992394c5df738c63d08299a1b6aea05668a0e4151d0b8a2bc199216f8acf88091c102302d45375a1df1001457a0b043375a1d9123bb82d29a49b47005c78932354819c207248cec8025cf1c36420c61c17043411b304d58add04399233c3552b2a0dcba0c21654305826cb0d262b609c09a2a7c70a3e776054f950bfccc80a7fad390162ca431020d0b56724ec09345050b49707083849b27920049214d36b41ca0a0323587035d88683263860631575d6480a24a13af2a7758cc3511b899c2cb9e2c501cf1668c153932e46101c64a9d203730d80b4c152288980a288e6891adb8d3f26a5f5647667041565b5f16ca93d72aa7c7c26eb43a52811b264971c4c8912328dc3089ce602b155b5ab33a53f38eccea8905244cb0f6b4c0a4c81d234da6e8206952848d0b4bbcb48c8c0b51535154515636ab73e3b658b51005a5c1ba6eb46aa10e77c6aeb8d1aa0534b33a31c618a574eff923449fed5ead5799bb7062f9a5f46777311d8e399b3efd6aa562659c93f22fe1086cf936870edb612c12bcd62ec6a7f80b7be9b2054b18d1c436f116e7443b312b4a11f1c43cfcc443b8081fe9d006ed7a91bfac92d18771aaf6fe85313c9995c1c69035e824780824fc0012c49dac80c063878e0e34b8e0e270fae2e445881d2159333e142285903c4e4f4e439c8a381d71825af1a19392a10f9da294647ce804c569ca75f09f59c8ed7a4f11024588d475a3af3d7fa1902b9085dc84cc111275fdeb226c83cfb34d9c75637c322a5955a0223bbbbb7bdfee7d84e5f8beeb22b33b4fc9ffbc12f84ae955011f47c300c2c6efaa3c51e5613ccdb69e4b48a6623a6debdb56a6ac6a18327443ce0a394f3fb177fe3ed7997d8b77691bb76d263dd87598cfbf880e80a3815e7aaecbecc55e7aadcbb4678ff6d2ab97d973f1d2e32eb32763f6845e7af3327b967f5eca59118cb7f816f62d5bf83bc9c199cfc3ae0fd1bbf7ba43ef5ee79eeb461807eeb5ae74f17e80d9cbde3d7a859c039e7a7aba3f0fe3a2c7d1ef4181ade4d242a69a9a63a724689bcff7fb94b6c99ec5f7fb111ff2424cdb6048d136d717fdec5b7c1b3d8df7be90afbcf72fb6986e346d23fafebebfdbc478ce4e56dbb05c49c6f7f754db84bebfc1b46dc5f7d08f559a2181babfbfb4cdc52d826fda1772d411d58749525c8c9ae7d19815b9bad4175e6c908a85ccc7a373fd259851b1a190dbf53e8c5448de9117810781e7c28b79b141a0195eec9afd191292e17d5e6c90c88b0d829e7fa110a8eb7da1fc26cebaeecfc273299fe2e3b915cfb1349db6d3592d4591d778665ee769e1f953e7f99097e745fc48830ee5b5ee4e6a342da66b4dd560bc9eea2feda5bb0061e9295d93f21a8ad74aba06c5623cbeea270f4d1e29de8e6ccee536d48bf7456472e1f52df2f8ce3cbe2d3cbe2cbcbe32af2fd18a182f50649ae145a6be308fefcb8b736ee7d1ebf2e66d79d58b1d70b2c4d3e5bc4806ea1a799f7441b78c0cfad2cfbb417e558c3ec272187d4c15d6cad42fe32cf6a9988aa9fc2a462361d9cb5ebd9d7c51d960ec2ad7cd71e498f90ab7cb595fc4b1fc5d5fceb56ab7a6ab7bc17c7e2c10500c284868c510918c458b59918b1730def3fabbef15fbfb62d08c64cc006b1044f08a5e38efd12b7a9d04485c0c3618003d81d790499306f78ab018257077772477773f6a45e082a09bf13282d17cbe1fcf3ed0a413468c4ef717412e848a56cc865810c964442c865aac98091505b988bd80f11ecc7bc162a8dfab85958d97e3ebeb62b468d5889341674c50d61c828e808f5eeeee1e913eef7f90908a7842e5dd4260ce8e741401b743c041647fdc0e4612ec1166ba9bbb23337fb4189ff7305eb8e020b228926067b746126c0b1632a2a11542413120fbe37355a673b52a47a7f4ee6fe796cf42cf8ccbc636a0ab6d9315880c97de4db0178e76a70ee92802086e4d823e468cd165498bf1790fe3850b59646757da162c6444432b84826240f6c787c808a2ced5ba95a3f34aef29e50f9204471140500367c830a2c54042fa90bc4782f1c245d1ac050b1912d1d00aa1a0189045424272b52878210d5851b921499822766e4f70f43cc1c1e202e70b97068e0cf40638465c4bdedc89f2e68d9c3742b470b0b41babde44717d7973048c957163951b265a49dcfcc03d61bd1babdcc430ddd8193756b5b963449b3434ab0d0f68da486d6963c455874d16f7c5823756b1a16a99619365036ca0e8149645075a606c0b37ae276c511015c99a2c6fd6249961acd08d556aaaf8809a263a3716e9c62a353e6cb9a1caa0a609173bbbb10a4b8f182bbbb10a8b0931d6c58d555855f78695e586550b561445c206dd5885a5428b083bf4840a69e0d02f16e8c6aa3464ba232c8b1babd2eca0c416dd5895a64947c4c2b8b12a092a26b8b12a8e98ea03dba5fa04ab4380386108879765a41bbeb0a6e8995283b5d6c907275e80210a17272a1011a9eedc70268a17a69ea881c93f3acff95285bbbbf44ea25f4d0018b77b862cb76948e176d390e4360d19980189d113475652da4cf08274973c018e26bd7b06a6a65adecf7f5f2225c97763d51154a4c8bbd481cbdc57cc9d0be08c8dfbe3514c44736bb8f3119ee20485249c60399173fdff8905ae3ff8248aeb9f048588ebbf8463c9f5d780caf5d7b1c3f5e71102d6f5ef118313d79f042ed71f8812d79f9f8a4461024a061ea25eb8fe2c255587270db10bb0bc30d1e6c8153b57325870c2849b254eccd061f229678a8c4fac32e6e838c51e21ba2461a108180d3085f6c69b0e4dacd1f2440b95104c530921bc00c56bad9c2ed2569cf9a099da4bf57478cdbf7e90d9df9a7590597f330fe6d7df313fc87bcd3f881393135374f9014524973151ea1ff0df3c4c65aaaed42f0babfd75de80fe83c804f4e101fa2a40dfcc9ab75bbf35f078b413d3eb3bf6c29e0a9c32a814eeb724ad84684c101008200073150020180c0a0604029148301e07ab2a1f14800d637c42766234134b23418ea3208882188661180631c418628c210c292891556adb5debc62be24c8b22c941c640f71d4f5ff11289222290843657cbdbb4db4273aa100b5eedf0b70ba4f582f4990b1ccf90b1360a48ac37cd72a036030d738a0530abcad1a5be8e8a8dba8797d3ed12a17062ffd99496f3981cde2a8f782107a7e52217d76fe16432743eaf44ae77749a1bf135225b6d8e9c7defad6aff08ae3a52df0d9f7a806c93f062014a369c7d16d00d1f9ac195f2cba09c0fab9abac3459b635cae705443937e446a5fb862d8343da7cf2f1dd1444a580599fff029a29f69178066f2379a038933ad67bd4868e3d5af00f8dc7942104d5c219a6187688af9cdb49f36330bd5cc854c689a9bae5202c22834bf2c9e29f3d799d213f327a732973238d37fda664a77355351c832cd6f3333c5bac30e51d26536f3bc7cc37e7b45c11d4fa7f5dbfccbe4956b0a3015fab738ec8be84e9353f01a226e858f490e12ef57e6a3d94c381805b6a3f97b6b1aab52e7f36ebbcd9947749516157222684bab84a151364d587d8d98de0ad21a7166f29bbbbb8ac45a79c8d1a4e45eb3c6e9c034627d74c0c64d3c571693e9ceba98c6da01fbd4f2ddf0ab02bd71c856c3641760eea08702bb3508a0da6c6faa3a2cb005cb5988b86aeacd7b8da7989a99af484cb17ec96c6114b10641ccf1e9982776e6e0aa7a478a5efedd35833c48201565fa80fac66635595b8de80596fd0de48a536e27dec880ada6fdfce344df6e682055ee9b467e820eb038c99194b19eee6dac131d39ae5dd1c25e984ab03563c3e5541321905c28853392d9639de21f6ec9e7c3214a925543c1b8d10acd93c43ddeb71a511ece8cd8cb2244f44867a1acc52c0c26229b4204e4ec097b425cad3795262199b5ef2ccccff89ad3c44614dd0809fdfb80a53a4ee1a823f29e0d552a232795e0cd05f1806370a6bb8a41a40cdac02c15895d1c560d12474f35bc66cfc4a10119995517ce103e47826c7f0828006d8f728b2b7eb9a99026e24a909c0b9d5b6e6e3c46d3edb388583aca4a2080164f9faadd5ed4222b4c5509f6ddb75101a6cf33b88b441cc6b03e378935503db6a50f92bfbc6865d09f0bbd4d8a69733a088e0bad8cb47005a00c095410e799a5eaceb97c71075bb5f64f5ed0571652c55a84fe0470f808b3651845b7cdb61d133c606450d37101548e6b05cf353754715c12a6d193358d7a29e0122f339a55b3a4829288b041b2cbad5684f103ad1429290c136d824897d9f859ae3e29c489475e93231c2acb508bb877ce67e2cc433045432311f0e5ed45d2420924fd41862d2c49da2635555aad4130af413d5ad17c3b54ced0703f1a9a93887dc9fc20f117254c670898ee38f6d7421e4f7df026b686fa41417d5729925e7a23ab1f6d8ca2a72cfab97d3ab4832e6f23173b9843f86dd2bcd41c7cbfb1e53c4e76698cc51a858577092aa9783fe140fdc45385dbc30c3348bd5d9eb99d2ac9d0f65c3a5ee1ed309b41658ef1306f084bd253ee35110adb764bcba5ed919f3fb4a3ab467995849f2950b9e1768281455c37a32b2b621085cd6e207be0bd40ed00153616b2a84831610aada568e7986dd632591c7651d063743e66bfd66d7be8be392ccdfaa7847aa486b00fc92060b6fd0b224418f44dc8cca9f78a707e7cba29c9db5038777674f8ac339acd1cd8dbd054966de7f1acd01f684314a16a23001412e2247eab7ee19f27817fc9b628ebfb54a4c951f4e13ecf995c74b2af2f7031fa5d053f4ffee3f514f5731fee30a915e126bf58c5da76292fc3d149502225a03e0f4d4a00f8809362e073a30ff844eb324e4c526eb06304a1324a4f677a02c7a4c573c1033b7fc536aa3eebc5cb440cc9e498c99ffd3a9894985a0d65006e2cc8c9464107b8ab3a30315a23ce44ff0519bf08d77a0ccb87dfbf41e8947f738104c4161404fd1205a37f6a8dd1055a994c72f75ab21024f40e4c69b4ecb7bdd7a2626f9649ac3f0716600ef870774883cd1decb81e5fd3a6b5d798686fbaf9b34a46b065c1f50cc12fb0521e802f05789c2356b688d97e4e4d4a39c64d800fac5acea72acf441e287a64b64ec7ad4955940c797bb50d8a5a3d097cea6bd8c9dd0933c4ef4132cdeae6748f65725a84a22b37e1c9bb770129e926c8b9d2c5ae9ce409dd7bbb7d094eb5beaa995e64f0282fd5c551598efa7be3adea2891185ba1a06cf96ba635d5ca1b2c5d2dafe01d3d1f69687de9e5bc8af8ca0a3e8b6ce1f314c2d8e2969c34afb6132733bc179d748f817686b1b782b5cd122bf9eecf810f3a1966dfa81c266a01cfaf250b1155b336cd12fc1c2e54d004347d912a25027d23d97cae3cd1aae8d463ffa58e997c18d31193858407266e849bbd07f2daca711a05b551fab0798fbd1a08c7cf5d28451128d196445a01bd58c4cab18efa11ddc8fb7205641b3b50e47cc1494330d4be17134e5ac181291ad7202d8e73fd392bbe34a3726a3f8423f928e7550bce91b52fa0c589a1607ccf9562cb3928eda83c5cddc09024288ad38d319dde1736b9f78c0f50129c0c3c26ffa4da0de5bc1e1b599484ba378c633b4874572ec5d69077aace6bbf3651c20a28e847cae7c94987f11db164f983ce86d3140c0de027b547fe6615c41ea0cb8d289df731a2977253aec672acc38e6e6545591bd7b11cc3d17af89bb220c6eb8a7943181fc53fc48c638cf1939d7027e3593999f3496aefe0e94709642cb5c95b2643bd37d6b91d64642b0fea6adc8e75a8c8a5dc54bba11cd663238b2bbf1fb22a670e371827c52e53a7ffdba92c4445b3f570b64aced6929d45ac6e6a0e599aee13a3d1ae5e04c235364e0c9af822db2935e6708f08d4d080d5d8602240b24cbafca46254e9525d0e2360fa8ddda071318ad685b6852a8aef5470199cee0cddeec59e32cc5730ecde88bc713040b6348d18a5026d4872c753eb2d7aed6f8081944dab5782042c01eab807e2963d0282cd7fa49277b4640c25bb3bddfab9cf4e5dceb5b5907942d365606e7e6225f2c57ae023e5f556fc14161f4467c902930dd2443749836a260dfacdc2f1e68440b1905b3df3d3092d57a2ab0efd4123074a1b91f044f43cdf61d484fc14d3c6b7504442441309114520c43491122823d27216ee7eebc93e99a227e41499509364424fc82495935d74546e9dd566cbe74e0f8b8b1fcffcf889b46be343fc86c911350a72fc1c907a72403ba564c172f46dd3890e81b0db4f10d5039f950f48cc1c361cb33bbfef6f8b2f596516f0489695696334b967c2949127007aa4d48aa237904d458f3342663f310475a33fad51c7281b0e4609cedfa02dfcaaf60d0c0c7255cc81d991672ba352dc624d5b4b623fc18926a4cf3731a6dc5c50252d693eb68f17f4699dbb08fccf3ba1a2fe7a99bb1ae221decc37e45c6a7248597e8e0ae443816b2cbae2c468d84a245deef4b2a4b4f1bb1376c01e0d048216493f6a5ec169e945b4b3db581d5f31febf4b1eccd70cf4f3a076feef09446426d07c7ec47b716c95e294f2fede3fbd33a29e02e9a01ab41663b549b12929a23353c66a5cd3b18d48c15384e6946b695b7aba5ca519e3803335d67fac67f06e38643dc00fe48a111e719955c77a1c23f77361412cab58622d3f3170f6d774437b8c80851141266dfb6756f8ae338ba7e76679cf37d844cfaf7e6299ee0c85fc1fa7130214441f8f900f84c37353afea3eb10cc60984d355a42ce1a4d4f849d200ac4053584d56366360ffb537cc66ed18376aac082d0bbc8eb9b4321e1a51270eb0a3b1230f32fdaa8f93777ae74332294d3d00fa3f3264b498ae53160ee822075457f02d1c21ff8919e82b058cf290cad19ec248e5e1e64e29e56dcd25d773cdfd6f68fc6972585a5f34c194478dc1a6660860279ca207e59950c7685e0b16836fc5895f9c7265e5b53a869aa102798aeedfaaaf1c5601d1f4749b047a46ede23f20803c6b2cb7a8d26ca74de60c616b733e341c579772c3ba9317a8b7bb806f3f2a242873a24f355dbb10fca2f2436f205b06df865aa0837f7fbe8c86038e1273ab14de9778a1649e8411e558dbd60bac50a6f744ad8c3937b1627a3cba9a3c34d546058bb743f1fab4dd90169a4d527d860c1e9f240e8322055ad8627a16506d541ce33081f0e4aeca87592aedf46f717a5f6a914ed1212672a56501a98080ed19077fdc96335c3f197860045a7ec429b1fe34e8ca3794ba2cd322c827f8fe83551213a2c346bd81cd53e58c21d5a5f1507df49a9235064144476a6ca92919c832f5eb70549485271c64962166359117eb4f71db54acde7a07cd9adf612e0e4643829dd7bb267ed5d8992c50a77e03012a4b8aeaea6b948eeba400134089f93f97836ea5242e97e89356c303c15995416913db2e7ee07138b6172d9de4565ba656c926bbfa89998364be49fefbc44f127a507dbbb99b08feef92cc9d952704678975e020cc70294cf747deec21436629532c7ff21891f12b9ec90525fcb448a4724a2045d965219101701c472421ea4ff8cd222923de06229ff9fc9abd8df232fe9a031c64da654268d6a8d463f1cf51d761249d100926d8b2d2ad390cb68874b9fcfbc35fea689d180268082184b51be58441cb297b54f3ab83135a3864604c4785f959263ab9e7ee584ae8356aa351564fb2289b904caa2a54e81bd51af6c6afcaa69f34838effc6686d61acf8ea304b483814e30a76b3ffc05d7f4f7b94e3b718c00b175d7098d91540c65fa56b45160d9bc95df16acae02476c65983d2d477c48f503c803f5ccc9f0d7d573867ff45bd6a38c93a4b8da4ee03897f750c3fbe7d6cdec6f0f6c90eae915fb21b85dfadd1d0e74fc2ff09034b6fd2e39b91928ec51407cd1bff318a86988d01caca55d7c2a3b07c837f934ec22fdb1e7da5fe435a654956d928a47089bc59f610b5d254fcd645689c11e9b5f62c7e6a48b8d4447ec9b2ce016c2eeba572fb770e9f904330fd2e2f0211fb826ecc4a4be3493f4cc6740e653a2753fdb3370d63b1eaea8e81d6217799ac4e2362674a7c2cb4534eeec01af6f955ebf736acdd7b92395a7bd475137490fd21d110350e7858afab4de5b0bcc3684e09e7b6c1571890f842020955b3307086b0c82a55af8dd4a168a6e8655c70ab89898d0b9c04dbf7b4839f5070f6104fb9bfeeee2ea86fc1d22164b9b8c18bc2bb04dab64628e2d96fd7de26dde08aaddf80ce61213256275e3549a046f31062fb42a6149d09bddf77a7ccaecd89b84c21d55c32990a421d58fb8d53ac2432220af11543afac65e970a6bb8116288fe262ea514165366c73d72d6b44934e903133a20b5044052a2392d7d32c597aae5061a8bd3553ef38aef39107e104ed8bc23e1a2964c5ae0a78b92f04d4762714355a393535dc24be13e313dcf4fa2cdd85c2cae754b55a62b76b089bbb80c21e6988b627690db76cd6d2911d118701e9ec9121c2e46b32e84328d6e496a02793a0986f5469a584d954af851765924c66ac4bb6009b46239aeb415cbdec0ec0e991b085d0a31804a48403d09592e50f6160e494c37ade417da4aaf9102fa75371ed6f050beac56ac466d7c92454ff415f4e75885511f7c450d85ffa1f8183d8f1502cceb6d3e8087ea75566e79382a07e6f60d0f38b8cf03bf164a00cf8a842398fabb183588ec42299d10f4d4c2014f7959157643708cb6e0ac95f91314b9d97290a3e132bae06a434177996080a02be18e0ee9cb176ba317452463edaa40642c534d312ae77b7810aacfe427364fc7148d2085f5bbbda20bd56de65efb60d8219ac24298df7bcc8703a66dd7c54f40efa425b93d07df9b68e2979ba908a9676517f690b802ff2586d33d1b2d9b149a284953da8ca3f486375abe99ffaaa85998efa3603b2d7d325a5f5328536626d09051b2ee1e0100b213bbf20a6ac7638d3f8c597cf8e3eaebc7d650b540e8d2a9ccbcdbe03dced458294ef35a84982ae15cd9b5b83ce80ece0afe0d5aec3b9b7dbe9ad271a820fbafac43405a8d755e3573b9492042d35a247525d80fea5c54618293789f110dee15faee79834191584df5695e27a2548bc44ce998e214496296ca0b66f203a6a1b5189f38ae9f3242157ab616376dd67b7fb510115e8669fc20049f1b09cca53056fbfb61fa8b101ace99442fc4063ed7fa0593a1902604af9192120eaa62e0e45000b257d289cb3043882a11a9b725ce7f5096be25cbd1f9e685a2634d43449fd784bd281d550e9aa0d4e8a964414c0c7508b980a45146cf016512821542d505424dc0d858997705e584277cf6095c68c2810588b11c5cfd01997cc643f16dd7559e7ac433f3afef2ce9df7f41a7f89bf2f1f26a8599d821572016b0b91443c23f970a722a5c5d2b357aa97880541aa67d2c13cf970a017adea5b80b81f4206237c1071c0da2b9080093ec458d4097c48ff2a107d9ffc3e6221dd62a793c8d30b19cb0222c195755eb6d4e0f29655cc5bda192b9af8c37d50d6c1ffca742a9958cd68aebdcf7e8d6e9075ba9815e8ce2b3e9217ff4280ede3057f8b6996ed77afb52756de080c820b68cac103febb93a01b2875bfb80c04a023d39ca930b473c7ae5a1e19a35b32204679906442c60c3ccde9fbcacbf87c96a9d0616fd11adf7f453618956b52ed3d387fc040505d6255a6c7794cf8042ed77140a2741e97202e5774a84463b69f71d45ef3d9766c719d7f1f8bec4b40174623ecea164d9cabbc6a24a7807ff37086a9640ccd590a72516fa7db04faadda72b755f26ae8d34f8b1afbccfb4f074899d86b4945b257cdd36faf11d1f0a07d348c2105274d45a907ea3334fbf827a831f0af71d51efa4aed1a0789b9eb49dc8529bf99da5c4843640f0ae3ca16e716fc567dde93b8671e4197bb1a99dd3f01629ed8da81010ec21d018a8e97699b20a249d7fce70c24875a965ef2c6453953422d74e948f0b7616e2d33ba24c8eb374bdf4c67e7f16923baa276ce19bbaa9f640bab42e1ee20fb75ce897b944800b3db14bc232f628289a97bdb2799cbb484f7496b87503e70610b56870fdf4cdd65bdbf83bb358cd5139c9f4a71b89a6e022a23a8b8c29ccfd07ac9515a22f244b11b114a5aa24915ce57904d25950dee3d0d5e9425ab9242b9a2534a02646376dd11e6635d5efa1608b00df4b2885b5bd46004797527e151c128399e93b0886f0d5a6725f1ebca0fbc6b15e5264f6b77cd9dde4157be80dabc67636c9250f091a9da67d687bb9f89d2e97a6558f6aa25f25a2452ef26fde69839853f0aa42c281cfd4b48cb962a871ca50bf307b911322097ed1c721d79af1dde4be8b90c46805c467e776c63390cad732fb78a3c054704ba71e82d3a29b66ff04d21cd09c960f29c74d5f8ad0eea129708332548b2be3f41b8e106b47085cc383068fa5002d20814d706f6880f78810e7ae4243023830249303bceb18f4cf31ac2182b45d2ec6a592a982dd32f70b8723c23953589db1b97a08d0159e96d576722c118e517830ff91bbd311e7a747e828942116abd33a6668139700a639064ff06d16d97527217fabccbf0997a205bfcb22550f02162068bf8c5d6d057f642bd83a2898d5089fe89a288495dfe8423c2dc4b449fe4931f01691f340a69e30b5ce67e3be422be959db137f6dc09140f7dd92425274f8ce02dcd57027f7f8d1c11414842dc16bb8f25db12fa57aa2e78cdb14ce3c87ec2badeb084670dfa0b76de64833892973e5949de787a74acc1fa17b75da3c5483422a1f21e455fa460b4ae18a89a16f1d428700e4b0c09076b6968eeedad5d4ba26511e029314ca8c510878f76d3dfd62003d652a128e99196534dc80f6c176d1134e1e5e5b34cdb0111823b15dfff1729659513d650f9b4b4ed9937f23b9039f98451a8a7252a360d4ac9c9a6bc0a8d1530c0ca664f51448e6ed85b274122d50fb1a05792109e226120340cfe82b05b5696d63156010134981d21115f00378522a4c14817628608d6bf6d6e993ad24fd334a589ce1b1f0f2ebeae8d5c9922813100eb2d66715899caa2e6599e4122333c5256aaa0c519e9c227bb62d915fa04873afce45b8799e7791ed93a682ef132782c9c5dbc2d4c32ec7cfc2dab044a4ca0a1bcb69238a1dee661afb64e7e5d5aa5017d6d217176f2e3f6fd0ac50d0947b2091732dc1cb9762d7ab28f189bc37ae49ad6bc778cb0a9ccc16b174d5c18eaed6e16f1e8917d38070ccfc0af711a8a55852cdbdd4a6379912ca0df795009d81decacb4d01e9358b5dd412d57c329df0bc77418f89f7b257d52ad247099c89fd09d64bd2eb76802750b1ad710059cf19dfbde54db30131543a3a25ab57062863e85b33339dfbca1d47cd6eff1e3321f945c310ed412917ff7aa72a4dfff3a831552e9a4a99c56dd0d1054ed74c214759043be8192f3b7cac0cab410017264020db2b468e08092a99fa87cb1f843b1bc5bd736a1cf0bee8e55d8f92a68cb93b947f02dc62523d63a28a116476de9c22703dac51dccfe79258dc8c983ee112af373a9b5c83c1ead6f1aa727fd0c0005fa79f606a71bc9a1bd2ba15f35a33496471dbb2b31c5f8d9edab9288a5e61aa4c94c048b1cd6b217d1e44466ba58753b1e6279cfa2006c0467229b2d8a755bd4c55603c9afa208460e0f381637dbc0dad188f36b0f4e08fa82a3ffd36dbf014cf89dfe1964319660fd96e4e277b0ae3174694ee4b983350c992eb47aee363fcf1d80797e6e6f8a025795a2228d19fd2b7b56fc3e878cd888de5f9c2a834297f0459e1545e8601ae5be4a2cd942bb97fa41d8553eaac3e21e4b5903bc162123567c38ba0405d1b5631cfbb30b9d829f923c2c4bb1681eb25a3caeca1664ede3149256007a73f14352b8d20863b25b8b45bbc9777200095a533ef2ace720922e056a6f2204bbddba45162c4f3a2fc7e54283aeb43f7781d9ea93cb6b8e27dd9ca3865428c2fff1b02950665bdb78c85b0065322cbf4c5f9ad1326c0acaf6f842e48891cb29f1c86aba54db9fc8e56cccecc819d74fbddf428d0614dd02612aacc2c631c880efcced88040f857ef515e0150da0f6d86113f4c67965477b0ef8aa3d7451a41c931cba40a737e2ef2cd82d407ced10fe82ee3c8494da0af352b9e63432195294f0240bec14b90a754c4504345ed34ed50942e6fb0d8a8b8401956a5f72910ca223384ad87ba011f485c7ca7d6d92e43f1c5eba3e196a692a3b5ca0796ae4f2f2a16dd94a5049008b75e7e22d2424d9d937de22b285dfeabd4da8f13741331e2c0b763e5926ac480888756bb3e0170e24fc3a56bd7ae933d2fddb0353897d17574c47113ccb036cb39d7f9e022aaeb383f27e2e39a346e07b246ee20c69abfcefe9c4d79e1132c7331e0a5fca2e29dacc898436588ef684e3af6259cc7082940c5f3cb999a7d19ac92b44db7f68a8ff394bc4f1d1f0f58890ce6f0c1032da8f915b570d3e61e9264ae57a4a26f517b15206940d8a8f69ce832d3c7078590de8e2bd00a0482b1fa6bf317985f4d31cd1ead4ed74c19c93db21ae36ffa6b3b44b14b02ff1da582472f5b508ca2c7c6f584e117aad2bb4ede136842a48a5e8bb7873d0b7db413ec43a9b5b5545c6e7fe987bf2c4d438d3aa02d5bb8ebad141f34e6e6f33bff7c307088c9de4ca2431d70efe3635b3f51d32018c9cb0c1b32daf8ab465a3e3a225d1acd5989836d5a8feb75c7efbc157ab44d5c38a75e1e10cf4a40b12af1a07830d4438a593aca557013c0edb07cce8978b09cadd0aaa70490d59db3475f558e7c42a2e496d6c2ad0f109fdd4d27c30dc56153965fac17414ca7d41961acc2b09dde8aca95e9b682bf87783ad36cda2353729692364a2f7db996e908a1baecbb1025c96b37182ab14d4d2f7ca61eaa39611b82fc57c60bfc55b7d97d413257a4767c77119e93c8636c578558b177cb9eb0d49bdfc7e675f4475fa593ca0f7cab334870a5b89c0ee87c088dff1b8b9e271d0d6ef5dd74af3381c8af635fc4fa550dbbebb45d9e5a7216a86f3a33652c3ae295129acfd691a3492e7df8cf3051baa1639ee8448b52d14dee56209a0d6a4be9e9d673def76702b27f06486a7c4efabdd77007d876d94f91a21a9f4893c9c835c9f22b65356191e5dd461853f52383c1608e56f490af2677a0d339f06dd88227199e80ac84fdf51e82b1aa09d483c134a3316bc7b9b4d10e64b473679a6344e41acec55a4e94e1baffea5663de9f1d0bf8031735294d6d1f72b517720da7248ad11f0d8cfc1ae4cd2043953efec2768bebc60f129c83a73c5f6af60302b97f47e413f8e9ed0eb950f087a72077cc6cf27a7d6b0682f99a9ba8f51bf68f3353e849b74f922428520770140f58d9879b0fdecc5aacc36f0a140f223807e5f323f1f91b75a913cf2c23258fca230af1bcbeface82c88fc29d3629504c5e639dbde4ac3883d9cd52a847ffdb5f59e15806825872f2a998c51367f8033af2733b6f53e022ad37f57a3781468f2dfbfa6a90480e6ef734d5741002dfef752d04f5003b0e5ea31a15ba19a358f52f715d38b2d57dd379f2bdcd68d4b31f651ed571f0cd764925982bd7417435c7aec98f6834c9d2cd486b8baebcf90ad0a6a96a253ee76eb8442cf0c4d02f834576d177f2dfa1c962fb26be29ae5e0f4878b4db490182a50d6e00aed8b2589634ff4a832040d439a0874cab47c8e078fa4781033f565c7513024c6485c98843378ff194fb1d4d07f47525887479a234241ef2975f20bd1b6007d720b3b9aa858d620a642046035800cf7461faae720e1904526e9c9e8a20bb54ed0d66a53f2859e3d2797fdc7fc2e672fb75358e54a5819b3315681d98c9c93a0de7a7821846dde0df524cd088b3714e6e5f9182573601df9ce79c2fd5cd0549df8478e4f58819636fbba03d98264f2425faeb78ec4fcee8d17d4af8ad5b08bf818d1e2818b01f911798f1a5cfe7d486c4b5cd3bd8758ef3bb46e4e30fd275ef093c289ce7d044b49bf154fe0a015d43447a75c9844777dcbc7a33233da6093ebc2ac2d06ad5573b5d904a29a1912c2b2526e5f0cb0cfd81a70d4383f63e278b0a0de78c79958f082ec58ea41a3e1782cd90683bbb960c2b067bf70e879dc760bf904188a206b1aeb1b885e4aed0aac3b8f4d51f0e3d2163bbed2fa285d546c2a2afc1ac1c7988ed81eb20c25cc6be5ac1a4f4bba10d4bbe86fbca268de52cf968dfba9b6aa5dace23ed3eed60cade533251de12fb33348e8c82b50697b4540baf6b6521d9f3c4f7e1bd68b3e9700e2be49589f597a2486800c8ba86d51fc72429f652f221fb68fbcd49975e85172b1d4558014b60fe32e32247c9f5a1da5824aa2bc7b00a54270dbff28b6925ca497e5aae4aef173d4585eeee7ba8c9204ef4394e9c3fda724eebfbff02df1bb5f090fb98246f8191659732ea9e00c103152b8ed7d568937e2e80489481e7884b6efbc085a80620b4d0e5d47a8e50730c2fd9ab6a30eba4b5fa54b9828e1c82c2d7b947b022c79f87706fea9f351af58a19ccfcb51318723cf5fa0c4a209e25e8ba81c26365dab0e5e2c31002d2566007ed18f5f43b5232f23a7cf28345843defee56509ac4348e92aee8040d9d5160bf3b5d84ce6884147cb25b86c6b3f9643cb3d986a7f6872edf912258f1f72535f90cb5e876cbfe963f095424fde4622515b3a1b4bda62d0ade043ee76a97edb44c802f284ad86b98f286010d030cdd6c2cf37024e7a1821dec037e2cf33a9b423f8ae1e73700fe9f024e267a25d468600e5159b90a08c4df9847899ba208d9347ee29f4f5869733c24acdc0da25155df253a86cd39e8781e4e914f0cebb4d71a72b768a84f23870df3595a3a24bb650d1bdf0fb2e0e502ec9b1e80645886f3e8e3d16478bca866fcf1d2ed25a472f3a3f351e211014042450adb6f70269762b3f8812c5d5bd88180cd1a7d2c0584afaa0e666ee17ba1120aa4876262b78bda2d9c7c473f1809129506f406da1b3d1fbffddb1df9353844a4f67f35be96d74899d0f130dbb74cae761f9f794efa388b31afab185d12343c5b3a8b2c298700af25aa449aae5bc0cecdd0a5b889072e81fd59bbd4de37569b43dc62573ece4d97d756fc8b155fe5b477bf6f0e8975c9682798141b68af5412cc509b73dae4ee3d07541dfb8864e5b50eac3f437505e51547a58eb0beec11029ee565cf0000a624ada5f6122d3c3347c07da9ca1e708e881aa2b1f7a9be77a45181d6d5141f03e6e780ac3ea8b0bf1fc32bc5f5d7b3be6c1a66c402bc690082168067b422bdaf9b8040ca205dd65a5a387d351aa88675a05912245cb51a0e204ab280b853bbace330d2fc967099be0fce8e15162feb3cb61057c0703244431f9e4ffbce0ab63cb4919fcf614b227f81017999cf90ee660b2b85ca6c05099c2d35ceac26a3067e0e2d7fa601c801fde6653979902a53b01f7618206f9b72d035176755d575b811ae6f461af08a2cc13bed3aa1ae280a253b707da9decbac24041c95503f3681fd1bcb8a808053a0ad483b6f9ecf50a39e59ecf6120afdee58cdb880aa3468acac968227051a8ae6a867b0a3f05b41f1f343d57d01dd00f17b973cab4104e1257b3dce857a7a61352558b1d723554904607f6f111fc84b7c1215a1d59f42c56914d3576443908d7db98f4fac25ae3c32160f4de4dcd87c17908fe1b22c692b3bab8128d4f6f32b63ff630646151f402f4f5e837a77de939bae6f55b511e1e2e919cd308eb96c0bae738ea9ff9dec5f3cf759367287ea2e03f79befe62a9c8fde9c8a8ae0c81176a35f5ff036a46beff6201deabe345d5031b162af52efc4f0ff91c309a336e0b3c302a9808233e68212f9acb140a48b2c2f73a7571788595f32a94f3fb570c6f7eddf9381647fdbb79da362c831e55dbaac3b1b1fb111847067a2686a282ac66dad1ee5159ca2697b01df76618b8f25fccf758e0e3aa03503dac3ceafaa20451942b3b81b86e72bc1092ab856628ba6aa85e8cb453329a4eea2360c4bdfcd4f9f4c72ecfaefabfe3f6b598f8694f876316fa5da704c604566f80d8f9d89997c65c4319df205a9ac5567f1f4e92a6b8c44c7d4f41c53f4bfb7214148b0a2ae449f630b9872da677880e8bbde9591f67c2b1cec404f2c4a7926e90bcad181409fd16d539da1e5fa4c2d94299f5aae18c559cc5872c557a5470d54f56f556e397a4570c9f6af2edad9563eab27cf19583b6fd1333f3e76b011514bfa87c456b52dadda28e185fe0d792a4c7ee871bafd23f9d24db3c998b27f6e10b83aa8dbb8a3bf945edfbf49f9d0f49d6f75a131f7ef891194c3abb56d9bb0c6c3d8ce72340b341a69a0f76cb111453f7b0115aece97073a785aee3f93127b4e8a404ba6c8dc4e393c72ec908556e046e2c8629a9cb3a0f95cf23abebdd1cc37043c5b873b7b7703ba22164a1641a94ce75d754f5a0f16f6191a85397244468f795674f8b152dbed2b5ebe857de571e2969d194b527f9208c545319025ae348c0096e4fa92e3679dbd2f98dc3c288c4fbbff49cc9aa5c9d5647c49b245ef3158784341c0c479425128ca359684d64d10b86c01c8cc10d1b852271f5dd190996f9d1215c437aad1f28b1b65f244b969a50b8f1e23c088d64eac2bf0b05db80e7cd2d442a560fdd1d0297a267d0e5e6bd71f4b5470f41abfc3716fbaa5a7adb410efdee85d01f3c4e673bd40b8930f0f3032cf40d32e07613e9114c669bbe5b6d726a92c9b219e4d68f65cd727ce8966f2bcb486dd0eef43e4e6ba617ddfcad1c4d759858c97005733fb9a087392ef557fbe07e6e210000402c24a3fd933f26db61d6ce54b7491c848dc0988c98839607b60326e6fc6a4ced0502224aeffe478c1f58ebd4c08b4b731c8b7eeab1011bdaf5004f893d715bfc008c9bac029eb2831f2f73a4f85cdacf32286d552331a07990444b6424819a017a9de6b50fc10841289fd935020d621781da124a45649256d48a3655e26d4af2c9192b638320e1453a8480d176902897318947483eb539d236a07e14fe3c567068c03071c0cc341ffbc718f40a760625ff5a1df628aec7f87694a0cb679e5def3e6d28869cb7e1eec9c32f60e3f3809ce02e74d3c838085b961aaceca8606ee556ea5a84e999fe29db213dbf4db4d6f91b94dfd155ea15400d7954b5ffe402bfbc997428c0f4c31231b55ff2adeab30060a99ea87bcfac4fbc9cdc3b0c96d2f0376606eb4baebde5bd35e49d64aecfd990a78646546f4e19d72a87b2c2187a4ccfd76526cd55a1a354bc2d4a3cc5ba8598078ff2e0354efbce1d2085c135df55b054f57ed067171bad0adfe166bced2de9e08b87c79e027c612063a4a781cf1cd7d7925c4fdc6f77ef71fadf110389078466e9ddeec9022044cfc84eb54647a2f0295ae3e5707136177d01a8177e6d22629cf59e23ad67155347c4ee6aecdbd8fb3dbb2e5b5e0ada986b4e4fc490263d42c43f219200c5900555c90525d7f21a401d9aff366c47fb2a55d51d3307f218506b00a3eb7db46e92396132be948498b4e09fea66fc129bd92433ee099666c04140eb3d3a40db0b9752da62f357cc12be51b93cb1bb4c093fa2337dea1f08908d8592c13459c35cee005e0115ee369505ab5cf15b5327b73a0aabe275e798fdef7f106be94e9178c317c1837470668e364f4cb1f860b88c9e6405b122b6d1363da6c2010fbf2ff4b0245729d1691e8b87e1b2a6150017b99c837fceebbd4f861faf9c537629232da5e354ec0a35cd975ee35f198d3b164c9b2de83a3d881665b90348a81bde33cdcdd26d911abde330822ac53e368a11c3773dfcb94c207b592b9f7c4e3d586b1373f62736c694d3fd2099910e3b8a940890600c1a48733dd9d4ed80cc1c1d9426e8eb91cf0cf20807cc3adc4dd8df264b544afeb1c6553858042659d405401a556b6738c34e5b79b01706d01f1be98c660370dbfeed5cd0fb5cfcd8666c74a9b60f40cbdf98d2de98b0d6de9b80966e45042b7e42a4de250ffb0d1800585a4cbbff76aec782779569977863ddc3f49e2627255ab20484f239b6df61f1db472a63bec75dd1c900c48950106c2d0bac55476e924a09125af4f6c7d90b67dbcd973c2400e0d457b337296e187d07befc3bbe9a29a1c92612a9365e3a47ad14966920615cdded8b9ad903fd74c0c763a58170ac0ce003287c70ddb6e7d28a819c29ed8d1e13ec45821a4d66e1d4fac2829bc3d7459f2979c2562736f32e17c8370554b172f44e3c42f1814d34443b47febcd8140e4f637c3c9fd504f899009732f8c60603122ae2116061ea1a55418c0414bfb4f0cd5f0207d1ba509136faec3985eb442235221984c46f97f2326a762ac78710701112555c8473d56a5992f4ccd36c5605f6f12ebcc72d9957acf14b4ce726e1c13382d5e9f44b6d49f6f43c5113697d2c2b867aee311bae67e6878fdca2c9f0da3a6af54fd81b570e2c3574ff17f3a48fae26831cff9570f00db95563ef3a9300d702dc651f94b2a5911f52335ca44d3e1ba5752865be2411c961b12791419c2709e7c1abf87f6a2bc70ec1836aebc8f8900584e8ac4746db68eafe5726a2c5775edadeb6ec3c7898866d2612720f45e03114183c253391d9781ed5b86dee41dbdadbf227229f1a5928b37ab9eacda66a8a0046a42238e158edd614ef00687b586eec44b87deecd0eb67d96bed51688668b88ad2bfe4bd7f44a939b2a004d79c1abc6c9609bcf20cbf740979d1fe179bdf0e791eb5ce40aff1f711832c9b4ebc55da4f4446d1e12d20eb1ab555952106c80714ff97973919128778c5e23452b1155ec34f76c1d23567ff5062e4f43eb9eb8f92076ca0e48d46885f82ab04cc385f3fd1e8034359a2f452117b011217bc3f5358b1d9afd60d70cc5bbd5e92d7b8282a1067e433c8d34d6a36664c9c4cfa199a5c9b07c2157323ea09e44b88b8231b9d7167dd0e9109f3b4b6e96a3070f0807c25e455e3c6fb89fad64cbf05267e2bb05fa67492a3a2bb811eeb18373bfcf663c8d26239458a0c438a4733facdf9fbb950440338797471dff353dcc6a1fbc4a01e8cf23f08e79c948f3562551f8d01e595a26c369b7d0c8837100eb0177ffe36b1c250e4934774d8d9d05d6210b0421c2df8619e7b6dd03b516aa43d0f0f2be0af3f54fc95a5792065778e5b3060b975150c4644d181d44640efa9d80cfbd106629f1b65a2322623084c60955691a2901ad531f9f3e221401569b518763841f0c2548cd2e225a5b00222da9611d8d2d88b7314a172b07a02d95ac0d8a4e14a35524a8ab79578a6f03d19c86e13cdba7be2ae2000f212dd0ef10f19898d124363fad30fccc5fedc03b16a17f8f9946b513ee30a1707e9abceca8bbcad511819829e79a30e7a30c4264d93aa0de914fdd2e5a0f337d7b44b238aae01d20cd8369774972b9f2d6c13ce266c93a9ba91f2e519c025f18bc47fde670e5a86936ad90d79a5d416568c093a8b89b9db1d8e15df185b46edac6c4430efe9ccf2a499bcd6ddac1c3b3475710a501795534aea9fbf81db8c81a6cbfb990f1d6492e9b9aa8415b47a3cb9693281a38acbbb65f0e3162f5e3a0687512d433bc4cbdb5c90068df7215c1cba215c84d01230669b85716d08e9444328175659512406b25d2084998f322e5f7ea02576ec90381fb74064c9a8a7d1286fc31376596d90fa46c4cc89dab555a69380b06f8168c46d923bf95f7d220fc093d683fa2688b151013aaf187a4eba4f3d4604b9b6febc7e593071a7924a721ad181caabc4e97429069a942e54809aa69b47e028828281b4f897b7992890e2955c2133a8cb4e4d2482c5d8cb58bdd058133924061716374713bdab3ad663ff3e0ef2628452fae5b0b426c4e807a019ad121e94a3e7b1d6b819a9a4326175bc0d35700d1b4fe3aca6ccdf2d509d5a69b08f1d5c8d40cdfbf5067b7b3d886e67b5bc9de6813b560a4a163b35af5257a5c1f9141378f4d64238adc1b3c7fe02df50aae9abc604aa561128096b011f7774bb231674662b6ccf04617027f2f6f75446e09095853f97260ce07665846200093f5cc6dea1b36bfd04525391e25a96308637ba28c8c4f29ecc44d8306a80dea2f3350ca85cd852b2d75149841b7ac491426c79d211791d86142e74e093f37958705db04fa2e1f47add0b1813805b2a215c4919eada6f2e828b3d9f03a88c3e0703a98de5f1dc69ac6094ef4af9f1ba67cda71922e8a8e583535acc3221a66cb1b418d36ad8764066af244f9a9a8b0add4c05ffeaa2cb884f241c9ffdedb278ed09c23eb93d629a16cdfdf83459480ac9203839ce9583361e028b0b40f78a7cb98cf1e8056af46fc3c68163ef8a77dda07905b298abe793100d0587ba02812db83c7019d1eb2460e4f7e532f7a260e923c8e5325046972229e3f291058ee965264e4ad2021c1b8bbf4596509f5c5b73bce23b58b5284be77b23735095031b4955c7f6720967ce885b857fbefdb1c1bca5b9088340bb663f9c4406ffbe3c0c34d0c406789d85a5e5c9bdc375fbc7c02cd1075b4a4c17b0b4ec85a3e737b2483b7e25dbfce8b15053928a14e9447fda796cd42ca4c2a1a38d5b99c3281a1900de02dc1d0b42c01b974f101d8fd7283f6e1338e4a0b04a3083c67278089528fa6bec91d2141f1ba5e000c40a9f1e97defaaa10091c0b998ba01ef8294243631d064d00e24b5fa921997414679ae1f87bfcbc6536275bf4995992fa4de542dbd459f2aa946d9f28c34ab6491de03388989caeac6ad0aa19453e72dfbd2caec5dcd90d77d19809684cba2038ae29cc236afd97596d79b13c8eec5477b71f922486c9b9911936abb9b2d6a831c4ca2eec168865fa1b37780054458d70c74a6dc008dfacbc013a677388204a7a1456c0e6d233cd6459a927def86db6ee24b1b3add78903a82a68d0695bb713c81a81faa34de2e462e23be3650076d990553b987cc7d99887a8e00a5d0db7dfeb397342dc5cbf56d105c6b84290efc6334dce00a1e5400dd236e40c9ae488d3a0865c0962e55931a54abf6759cbb436748e2b5c766137d0dac43b6e69144e236f001f47f1731e581b34ce9f849eefdfb79b0d0e9850673eb3bf4fd0eb080333d8559128798484e03b4df55d666c51da65b21161003c90a2ad52102c93b8efba14966a9a43a74f51787bd9f43bb16aa1396637584db90392a946ae42c2fe866ec5a0a918f09bd4122e36c0e3ac4d2af866ba9c022bd7b9d0292d92d459c53e9ad0b191a6cc8b0ea5d40238c0a2a6b1ff6ea067052e3011c1f3f2be098ae43d141248a209aa168b366ce5a58f41af04c86c45007ae4d0ba732c6b45ddd02d0896f276d72fb171e58393382b292af86585ab1f1155c32c32d74e7f1cfad631d8e8ec82553a5d615334ab97b64f35e2f9b5deab3b6cb1554571339adc8ad110059b43911247fc1023e6449620cff73d3a5c0c8c0bcac2616f872c54d981db99d70a25c66e0763cb9dd264d7da70897675d1b56c8948ce8ed420ef9a223371c01758d6ad2a74ce035d8a5e2bac3254973bf5ef12c5cdd5b0f30b39183eaf56b45fdea02a50ccffff585464b43083dde855473eb17bfc5380261ff4dd126d6618f132c4326a3a72353246c7ba89145bb2f2c8088031c32440df1136873eda8a5f563356573399d2a463042da4f48145e3b79c60dc8e09d1119dcc66dc6a361f602d61d61eeadc5aa3d9f4748610c5801f12c2c3924532efaa1de4f9043ccb89ef2003dddb062d14710fb89cf8f85062752b995feecb8f4fa55848d5b58bb7b96f28c0ff63927bfde78c7b6f7a19701fca479572fb3a81e63b2ced063f63ecb2dcfe013cbed45a09201d3a39dc1adb4f4597a169a2b251600a78fddf28c894b52517c09beb3a09231ce2b2b17630a829b36f5d2bda8e34f5bea21a23b4896a1a1b1235efd3be7f648a51b574b7e268d6cd3aee10d559688f6f6cb61d579597ba57f23816cf2aa52abc64c1dc425a8315e452c70438bc7a4534d98b5fa41a050231b5d87f549c543c8df28b00ff47bc3587c173044c41f5a010f3c43677919d72988f9745814ee5343177050c3f7a55f159f2000c41a7e26c9604f895fcd84643342255eee71855766c2a46317614c94c25a42dfa8051515b35a4cfd37010d5aa168ef02b5a3ac8c6cf8c4e5b5743e8bb9951243c100e74aa819c213acf9eeeebc3317408bf1cecdd5ff12af4bd2bcc51efe149fb531671f4cc3f415ca15f591554703cb5797ff0140424fc2b7b318192122966f2c606aba06f88f050c4a87af0d49e2d55e97206b89aa0dcbbd610971316b9979b35dcde14a0d73d0904eb02707f654804cf9e9d689709d40046b7795e8e90fac78c1757165749706a94c36088901173ed7f5adc8570d8edd89135f8d19229e7b281961ea61538e41fc981f3843b4f27ecb04a1fa1cb0408001c6605a5809974e913da1573900421b90505375de709d0c943a2e37cf7b7638a0b7f3d6de602e8e405bed211f9947a4dbad6d22ca5053e27a1e91931aabc8f84809a80b15408a5fe1515806fcc403334535869d97f37b9739deed4c399464dfb3151162bb1de8e15ce2098d1f348240361c031cfc46564606358eea5fcba21c5887eb22cfc422930b875f86b7433c4b125ceed79cf476d9cdbb16b2c362f595573bde2e70bc9b05ec447dc536fb1dc8e9e9d5b28122efd12c72c1bd397020f155dae9570cc92fa01d3ea0c6b9843740c4fee2ab4cafbbf18fd5df0636fac1944d48d75a03bd400841ec82b990512d1a636895b01a02665710aa16bfdb8fd4f5891c8806491894fda286d9c3c7a5d7956cb1d37761650fdb9762079a54f69d03497f5a76f4b57d374cc5b068f89f56b387880428cca3039998867342df589d50957c7bf0498a168ab06cd8d407b8fea5001fb648dc72da9c19117bbd37f54df0036e6e473ff262aac2ddc687fe309f1ae1f3d0b83314440f491f47fc40db7339db31b2b14e3509a5a00753866813118d05210dc14d7c19f65b1711621e83ab1f447525f686f37a15db77d9c2e93eb55eecb653b24edca375cdf7edbec90a67f7779d6456ccbbc0bdaa099c080fe538694a99dbd4a3ce5658d63b7e6f08c094f254c1d09586dee9f721e8c62ca6bd101c622563dcdc4775ce4e7b96b2e1a0e1b2ecc6870f030591a2a332fa34e324b5532b78ff3e3684c533bec8e22dc23015c0e7dc9eb1092f3c4da403925536acd08a8124dfc44cce70cf8517a3cadd4e43cdd5aa5237b361fe9ea9d796ac9264926f6b2d93fb41ac52582849ba009b7006e2baf8e08b55edee3178c44ab01a64c62f99ce07b237f6de75b98a5bfecd6b851449b22f2b130a8ddaec456df12f3ce21ce42770a3dd2218d81455dad7175c31529d8408e09290483800edd80ba99fd10485b232ab25b8abd3b82f56e5db5b6faa15e4d3e8fb665259d0b90b3e02eb08a566b2c541f4839957974e359239045a4922983fbbe5674e70795b5505002c55aefacc09ba5564307744ac3b4dbbd643089ebc0eee208d60a2c8eab6a98408674bd21279a622eea31a539632a4e6a204790860e2476bccce6cdf00269da13d97a5c03d5d003dce7672b287a5a190198ce3b197d40d5ac940c4d486aac9176ba8634e6658450b7b67eb43d27541cf94d8fd009c05d8be528e3dc4d20a23ae573255b196c30374ccac8ec096f7a0cc671daf11284b76afe148f0561656c7ac5fde4f699bd4d34059b064ea560f0987a1d575ea9cba7e95ead1a2ecb04adf137d81ef7b8225c1c303b53818a638606b25d5102f2c48988312361a6c97a74f466f1d22bc12b51070f5ce5a8c58f2838bcaf26ecc32527d1c3178b317605d289ef3aba08b5667112df9eb945f47041f6fa6e2d385abfcbe0a906355dcd59745416caa7e1c0625a72366fd2d52cbcc38b2146769196e401f98be439cb2fde793adbf0afcb5a7a999dbd72b3e54945e801d84b9fe73577e526f0a50557a036c4410ed84d935ed4290ffbb72cd069ee5da5347a2f4cd8e15f0dbbd81f18e9b4b937c83f9223baefd81836bfcc80cc0baea80e25d3399e9e403be01a354ae1fae41d0948c56068cf683b49bc77008f04ad56107bc6b0fcba0ab857317bc808fdfb8f53f6c05ea40c303cfdfa733f63b7cfa3688fb24c433f687017f30f147bcba766705a5d738431d50d3a16e5e6ab4e86e057648ebe4f083e5a01821874604dd452e669fdab6dfcde74338267b5a3f83fe4c33552d70f985c87d6d6e172aad01d8f61328a1456f3844b4623883fd5dfb7289173ecc3b7db2caff0dad5521092785e560080e005f6fd06e06bec103bda095508db417ac6ddb02b6d5d861a12a1129cda50feef7c62ccd2c68f817d5207daa9e1ee7ae33a0baccbe36aacd19902f454aaf3230691639e23b94aa430f047b14aa1796a1a0905d4fdc285107fef97eac5455dd700ef86a345361a30a8dd37ea8a9ff07e8371f542dc1ff613625cd1e66036f977d5dd74ba4d577de4d362d41ddae2fb611addf16557e999db2045bc99e45be1dab745796524ac9d58c0280e961014ca1b61af51ca97e7a5fa23774a4b5542e1b378be4389995e0640a5bae5e0c98bb4be0ea0421e34f486e7d335150e9c88d69fb65333b10c88d30f357cf66ec577077bed9731627df0e16e18731d70cdf28cf048a188ceac964ac21d101086ed720e6c770d73134a45bb56aa136e42d9e33a228f63837031f8b415431753c25c31353380e6212b04d285ffe72d3d9857794c8282bd90ffb448eac55be1f2934d0df015631890a8d80d6472f4e8ed78bd2fbdad09fd7c36f038be115b94298ed1128f9d8a005caf20e8dfca36ab62a4ca09ff178d3415a003cd753abf8a3f553894dae2cc4f418c520f33f4992c836170022b04fe21d12f9df02db8ab81dc1184411068dc6210d99311c1ba9fd75c9878b8cb4a653cb81f1f987806d6b57b423cbed19fa8c015e898571c5e12e78f1fb1a4b3e817f02b92240f8c4487247aacd3efb4a24de6014fa13f264bf461475ac3e47d2fdb5f9891dafd532803f350db67c395dabba2af1e8f36789b1ee1ecc315ff06c9e1b7f624b079715e96961b48d1d57f85fa9c6b17ee6b5dc5cbd245f14d72383ec7b5a03cc8a980243871599dcb8213802ef2a8d1be5a95a2d06586bedc3000eb59cc7d853d3b7d4304691903b520251b65a6101ad83ce51deec4e000c85277ffb4a5cb02de2a2179c3f0d061c24919f9e0964f946cdb7cb73281feeaf80e5617835491dccd24d1c51b40406c6e6ec14681f09b87853675d2c5aa9222da3b54d6ffac1317a84d9b8a0e89bb667ac77bb3cd1fde0e3826aff3a7599e63914d3623ecd044d87435a0a4ddf77be06a51a369bdd06766da9418060a8d44c0e5fd8e5a25ef1cbeddf19b79656e87151fd8f234af3b027c4e3145394b01c92bd0fa20cd2218ba0733a431119dd99d7bd3b70286eb6bc8735c8e1d371cae62a711f1e20e6c1501a2e25aeb2bbb258df5514e0e297ef4acffa5e1ff727d344448360c4440947b5196d9da9edb05490d848937aa98d8e37509be9b005727c29a55e3ebd992c32427da50808a3494268629c8e72097c065274ffadfd08b5f76e9123b7839b8e70b17d6f98f6e1771e112a552345147555435628fe7a16718015bc11cc7dd4ac8afe2c1d37f622d9ace927157ab781203559db4b7ce3cf89c94a9d11da74ae235592462a010459a17ec4c49f8aa84dffcd83517768849e133589f7d753a4d945124d3566321b856848bab3d566c5cc4ecc1d5728d8d8480da0510bf61a617c465d541f4624d1659ea44006e3da9c5e4c0d0abca140db44037e4df4ca0588c0712536376be23eacb6494dfa8b1e6ef1446290d964fa6464fc0c7636cf406145aefd18c9cff5e56839c88752bf34f92e8f26a78ae37d0e8e8e5e7aa3d5295a22e2d18b02e03226cb8fbc6f841f32becd80a2515e00202c5ddae57a215abdee549f269f186900c71382972a22d67d773f6b0af91b2e0ee098ce7dc4e07fe5311e60d8e57c28cdf50b79f2d51463a9548272bf8958bb03ad94820f8915eba02b5a49f731c3c328cfa3a0a29e29b1e75c9300cf11c4354a40d87572c3940c6c4fd1fedc47a1bd5850f10f0820e01a53035a12dc3c0cdb7e82edca8cf9f525fb87f4b3271a0c7d244ad2efbf375ae175a91401eb0b8f0d5e9125dd14d41fb4a99f4bfefee397c634fd2e664c92e9404be41a2d953c8c1520b651242579ce5703480d282831a64c03ac8a108e0f117761abb5957fb9f0d453d510924a2fc898acefa1065c74d62dd220acc4da693e81590b03f84f53d87483da5c95a28d335700358af3d1b4b2d2bbe670c6f36a3fdb03b530a3ab4124dc62705e5822bfbac53d0ff512623327193f1d584aff5625fc1293a27a3c2f7c9661aee55681ef62af0b8f1e115073d610d4cefddb9b412e631b12c6c51638238782a4aa6b415bf230b6fabe84472eadefa4ad3e5f5f37dfbdb5360357c3031d359a3d17a614cc292bba7339c1c2333622b42a2ac2eb0434233fa97ff58e434051c54eeb599c94c2ca933846e0a883e78f11e00aa52e8dc72b317f698c6efc8303c32a7230dcf6eda8cdf46a0bf82e7757bf0b9980d20796ea593e9252defef2f3ee8bb1196a67b87de9b04b3fc0ff114e699b78af64e644a169187694a476914b970a5be49bf01764962df8ede7ab60f5ae390140d157c9a844c13f170e841f362995cf8e35afe5595f9d890561d99266bffcd3c29e1656834b1675ad45a3703621fd24e5d4ab0c167df577ea98128d1d66b36bdb742918218fa93cb855ef7e8ef5e244e0cb9c6d8f7da37e44dcaf1d37def80fa5576eab971633782e42f364bbb9f9c0cc5f6c3710ab37763eeae98a78107a2df1505ae6f16cea294c508502304cb54dfddab2c94c22d251351f9915eee4af9e24f712fbf45010a59dc2c69154ad0fcf962f48f17a01971f81221b832d12fb61a3fd72435c3bdeac5a64694dccc7906be85058d6d9e6a0ed746aced691325c8c4bfa1b5dd4b757dc04613dd38121538ada05c4b4a064d0b06e3c67f00e14adefb556256a926e21c2f0de4b99670101ef226b25540c9d3cc41f17b8c435ff63e821c11e533a372375ec3e53f9a3898802f2ebde11449c568d16a5cadfb00951359bc711f37343374fdb6ae89abcb6f6f11a2ca1cf8dcb3f090c88b5813d63af18feddada2b27b7c9ec8fa5fa25e3488c5b6b148e39cbb576eecf4913bdc562892af487f42fe2c4df9a875b3e251007d29d8f41ee57be5117a0d3a2f1da1c1413b013cd6ea1eed81b3a960ef886b64be8f190663e77d0c32e7c6844f63a0dac750f76bde94d050b0f963940afaa915b173687035a32d3761e18acd31401ad39403ff7f20fe1f3c857f5f74b74928534ec00f70447d9f393f2811dd89e9d2d2838739146849289592f5a0259add664b0e8d23aee7c53ca8b202fcb2fe29d90da28812c44cccb73ff16af6599267079bd604a169facf3338c768508323fa68a11e6ceffdd843ec90afc6462ce8dcb86d8d18c8141a24964a4cf8b33a695d68dbfce1855de3385ff3b4c6376c58b692f65b7e038904d684bd44eba10e429f02aa24c5c50e5ed34a374dc20ba984dbc23307059a15f8da91c6d7016df9ea803527e9dc832116968e746ff5e0dad14b88c1f4748bb86213703f46da44bbd160b216550ed64527767da4e290513dd30aadacac36404de88f6313fcd228911fdddd04ace86937535708606be26ff7015b63a5ad77ddfd76b7a261ca5b353f0a19ed5b6934ff95a24dd15e51d493ff72346808c2d24eebf62449629e13182c148344482684764ed0256223ffaec2f3f79d6f0e06779f122a711bc5fc3aa59f11ac9f98d499f180b23e4ce2c076a0125f91e029d15329969e94f8fd8f7d83ca1715497a62c25cced053d07348edceb2fb5cdc21cd4e80a1c7423ba9ec08fd2f57ad39638a823c1e2145ed2ee3845f8836abb1b34f3a58ad720347382758918a7d1ef4b20aca11ab7b97b600ba853ea4e699012a78906870ad2042fe9af796aa8bf9c2776642ff1b6b2dd3d569e7f10c42ff8f0f784602ac8a00ea701016402051aa033013208e1899529d5051e9e044a4842352ca0982d21879a7685f809456a694371caa965584d0fffff6fe965246cdb26ddbb66d5bcbb6b5ffcb68f2074c015d0130019ad47a8b611e2f994a62c8c8b48d2b3bef43c1c7a7659ba66956317c50c10182040a2cd8b07023d336aeecbc0f051f9f96746b6d6eadb7de3abd53fdb27e78c90af8695b565e1c7697cc9e668f50c44fdef1fcc0ee9614d426da79dfc658a66d5c79c1e44c8769f18f73bce46331f4f08e0ce652729b9661e8e775a8065317c34cded16921e238284c38244688080162e3a0e9e3d3825fa2b1bcc440f98e86fcaab95f1d4df84e7aa2e72981984e0687d59575edbdb7d595756d5bbfd2da5e56e5d6f357d695ddfa6555efd62fab924834f61d8deffd799986811c063d7fcf751e96691bce0efaa66598d771fff9e775dca6655815b93704c5f16299b66daef3be1014c78b65dab6b9cefbc602ce545fab0fd6e7c6fb799986f988416ebc607847f1e33a0fcbb4cdc5f186a06f5a86791df785e01dc5cfeb38dfb40c7334f7ab23710a38e3f8126a97e2311aff4c285065e3baca3a2f2cd3aee582c94094c9f31f234478481365fdb22aecb69c50a0489aa8cbaaa8af9a49fa8926fa470351265489acf3cd37671d82d677f850594a1cef2445d0a46aa81b2a070a2e2b7aefbd43d0fa1120240a1c409040c102060d1c100f09d2e183891f806c26b8ac58528ace79eb9c75d679925af5c9a7322d927baaf13e7642ce6d816165a91253a63b8a15b7a4df8b09144927d7790f8a65da465e301d321d52044d74451cef44c165055ae4e375dc993f003804ad872269baa348d9ca89f19d29f9e0b25292ef54077534d5578d7d490c0df568a408aa9c9449a5b29d4c0d490cc90cc988c48624c7050c19aa861a62c186851c17306400d110b281034807100f5ea661dc874f83db4cb9ce43b14cdbca0b26673a4c8b7f9ce3251f8ba1877764309772d3320cf53a2edda00e11e9b84dcb30546b8deb6bffecff9edf7d739df76daef3becf73cf9fdddfddf7767777bd35196eadbb751759e79cb37e93c4658aeabdf77e32454d73bce9a35f59f6392b26a6b2d4349132d8ddc3fcb27eb8ceb32e2cd336124db7e5f2680fefc888e3c5256543b0c25c2c294a6e5a865d96d771f93343b07a0a1449771427ca7e5ec7919b96619765e2d2919827a00d6d0d417a24038a3d49d19ea4e87d923e3f3a8af493a5c931a8d8fb72bf2ebfdc5d8c63add5abbed3ae7b57777dddddddddab57afeeb56e77afb57a75afeeb57aadb556afee5e6bf5eaeeee5ebdd6ea9fe1eaafe1ea8fe1ea7f71f50771f5e770bd70f5b770adb56a7777ed9e5f3f8fceeeefee7b53f6b22acab1a5262972fffce8cabab0ce1e491365fdb2aa8edb2aefa1913451b6424bd24c53e0c718e32fa9498a20ca64ebcf39e7929aa408a24cf47e8cf363fcf831652faba24ad44587fd40ca236ae1e10ebefcc7e6c4f5518596c2d879ec4c24f28ef80c807de31b890902974fc00928c25ce759f822906a08d9b09519dcb1f988208ac60438c74b4a93c71365c5b0faf0e8c858cad442c18b1856d91999e1a0329c18305eb868b14204850900e908071501e283870e1c36846870305cb87cb5e1a42315440d516100c0bc88172d340e09cce525062c2f31909e034e88a09bcd66b389303232b2d984301d0c8bbd29eb7558767d9b5551f603a9c9436fe3bacabab04c0b7da2c0cf6a19765955c76d9ec8de94f53a2cbbbecdaa28fb81d42479e86d5c5759179669a14b13057e56cbb0cbaa3a6ef3a489023feb75dca665d865551f26e9836299b6915ce79d1f0597158bde7b6f110f4a9e30b2ce37df9c358010b4beb29438de498aa049faa058a66d24d779e747c165c5a2f7dedb01840813285400ad872269baa348d92a822a34f6b69e53f41f7d2d178cc9e827cd1ea68b634976643017cb7d14ac9c6db5d67a5bbded761b8810a864877c3b1082a201931c042000c010c00ce5d0681400061530bc448c5431180a46a330200c060b828140200c0a0280814000445110c5a12009f24c510db312aa6e3f8902d5808b9f95de29f4901079301cf2b1bb9057b766b866edd9dd5c2867a0f8c70074d3dadfa04cd38915d3a0ccd3a78c43d495bb3438cce59a76dbb3fac782dbe066bc46b7ab1a94c9eaf20a33d85f7b71a9d0d50d16b89601a7fc13b228a0aa012a6ef739d1a3c52ad7d6e3ca690c647f40388d86e46fdad6bb1aa09bfc1d6e67d60c7ee3ba01ad5222f6d3ac01c37f0f280c723428d7e67c186f2278de811f458f9862c9589d1a28936d9d9c0e518a7ae4cf3fb3a7b8013a5c56b7c35d72aec73ed944071691d1a98eafd99035e05ebe4119064a40d480034d8302240d8a503428fb8c6495c56c6421ea236bed28dbd700d02ebbc93e3a820d565c6419dc54fdb1e08042139d628382b9d3d6b553654b3b8c65d1ad9c6948b3c038de22d56079f8a7f29972a4458c4c0d7a3d908eb30236402126bf05f2f78b9ae1f777b4c370e6e0e628a407d1827f238957bb21479d716b50ae3962239ad628b2e6efd2888cb1f67c0d24aff9f9733edf5fbc5ece35381b2cbe7c98982320b241515ee494406df309246a711577bb67230b5759906c806e5708e282dbe134a206b22e4c345717a63b9f8abb1cff2eea607e01f057310301c32866084ae6c0b4b0d98effb48e365daf545de351ae6862130f06408790684f1ce7e8566c970927ca911f1fecb82dc36960bf0d0939db1eea29d9609860b44d8b9c8fd05170e5f0f3b1df42ecfa73a04e23bf74a50c0511af1df865afce80c53c3059a172f294ca2f249b5d55259a8ff623fb68a901d172f80f68f2bbae65ba15a024f78588ba640f681160090431386fefbe0544e52864f02e8195f9dba813fada4514cf7e092bae72acb085681ebaca543eff6461422592a9a7793982657fbf8d6df76f351e1e31b5f4a48f7c136e0961a6fc47cb956a143fb5f6d6e493fd4cdda3c2409253047b4f6f91b5b02705f745d271b13a203304386a3949d621a88a74d98f9660cba4646e753eba45645bc44676081e623c88bf9e5943964f5ac63a43a8547b861f031d181d1068130c570dc9c84b50647079c8f52864a514648002906bd8c7eab1c7403c3caecbd6b18e192d645d0447b83f0a52a04015180ac88e0c3c85a7c0e92b21724ee71a429e17601cf2aec9f6230bb6b120851728c4903dc73e1c72270d8789227215e1906d0e8d436eba6dc8149bd2416a508998d33f255c30dd77387e9b374ef4bb5f5a05ea04da6ae390601c770909d927478f5383022a58f91ab3135bb6b309b4d05b438a3e057dbb0a56365f3040c8e16ed6de2f89bdd5363b5cafcd937ab34d48e0a6bc9f11adb268b16ceb3a6ba96b3149399a442d2ff80ce760ace267057aa0119e182b5f1c24c752f79fcd08f78841d16c8282b67e38f2898eb5576ccdf6cce0cb6b8d5ec157ae8cf3c69af740ceb6fd00405eab73d2d456f08110ce2cdb5a9bb3b1f9a1ec3c45371ef646bb1a0e582d78372177a591cb62e98d6dc154df36eb27d0e6ad25fb353acc1b46f1ba592f8df68a296c5e415c496233fb6d317537f672166b9cb48472b9afbff9c06b29c77d60332a68951163483a4d4a68947eb6e518dc983823d9aa897445470a30488db6e1f9dd11159304b9a5d61cb5fdfc06eab41163e8359b6a3d0ab22aa02c4033388aa1fac94784d39ba13d9c47d3bd276af1614d091825d394ca0408bead4748886302da86185cfffc46cc0e917faf9a98d66fc9599d19b48dafaf7ba1c0e16250a626f7bf352705829637b133dca16a669d1cc8865f0408995a6f71c62cc08bbf4a998c29a0244867f41a478e8e3a20fc47b1b837a46f006ae557ddaa0c2742deab4d5e4d37203fa4c811b0b3077b9b3683f4f19403586c704ff3c1e6e682947a427fc835eea2c9e4734b7472edf8f07a85fbe3eacfae1daaf725617ac76d6d145803bdb88b004ec62874080632efad5f10fdf111a4106e9e48daa3d3d41af79fc94f18f2cb85c9c97cd32f89bcb27f06aa8ddc95bd6fd984a86e453097c94494e0f5e8733677aa0c1842900f0c91b8c794550cdb8d5cd2015a1e655f4bfb08370b61435f12671c14eea9d8ed858e19524095ac746f57755f6bddfbc7bf671fa631cb760bb245e98f01c99bf06ba34ea04b2ebd920bcd062c68b5071e46c65254711b952383bcdb399f5494c54e8b7a57078b2cec7d271d1982ef47813e1c50592f6a5d7221564cd6f5513218685d729548ab80ceef5478954dbc4ed6152c9962dae4c4826bcab16e8d93b3857f12b5b99712faf30d5003db14d1f6790e668420828edca1d73b88aef228ca02e39094c9f381c889430eb10bc2b63b42263f95c9063befe769f22e597cbb65f5dcbf5bdc8e2b591f7a49cbcda60ac8fa8b62c94abb5db288c421d39f999cea0747255d32e621fc0a4e9a9dff845f15ce1e9662324520cde48ca8e209d4b8e1a8a960345916120022c3c4885e580820f8db85a2fc26681b068a890844551a2fd189315df306ed13dd674f1e4b014f43eed9261601cb447c3276ccf924da2f19c197ab0e9c407260b448e0e85e1ab677cb8a5dadbc5a07708b3a11799b32cd6ade0606365c0edd46f2392136c3bf2c0d16b1b8fb4e74b008de2ffed53cc4c86a1c1f2f786118b73f8db7d3541503b4362509372d4e971b66318f3701ec9456f13e13eb2add627204257869268a10a4758ab97ce48cb3c5e9934d2713cced831876434178bda9d1e0adfef6addf02b5ed4fff6b9107e7433cde54b86d2285d81e84264447edf5fece9e45306f1044eb78f778289f609d5c8ebe1ff8befee402b28abe7200121f9f9b24e5faf44ae26f703887fd06a6008984a82eb943f96ef4c9a24ca54e567a91d897d0413affc7d4282238dc9c6da59d37190265e22694349a03e09b65ee8e18b760c26fd6d66ecfef747fa1f109af1437c38f9b6c993b4ffc019a718b86b8667f449070a3296e89dea56c96093726c56dfbdbe5ca75a4b1071df63c4464ff0b3704dc513478848c243e8c9b1036b9705ede3019cd563df38559f5654cc40d3e0aedd11012424dc2e48787674c7e7d8e356f0388116b4b37e572a3dcc645a07db596c8e80b0f88552a825f9c4c7188430711cae6f08b903a373c9f20a5c2091647e61290a46875bbd96227ebee79713b89c20a67dc22c6de0ed07afd20ea3e5b4baf501fcdb2db66344d42fb7db748053abfcb044de269b2095c340c347d97280f07f9b13fe192cc4789ed89115ac634893fee455752bd1e129a977ecaab475962649057910be11afb475a20de5c0382891719b2301de98ab996fc93117d460294bf48c0f8f1023cb4607624e086c0f789677173e1b3c97f467fcce2f267d613eb36062a1ec24d644cb02dd1b451acd1cfeab74bffde1054dea2d96e42856a2b8161793d098b986dc4525bf13edb85ee6143b0eab678adeec7658f96d01567dce8fea1f3f61d41a054537d8f800062c621091873054802314bb700d377fe23a81f4a546863752303a71bc162b6ea037ce0731db89716f01099d928e1f6770cb4bb0753b814463e80d5b6f2721d8102dbc9a37b72d3cf82d8216521c3f03a72db8a4100e41d2d4cffd0b854e66fd9e29f0277748488a0a660f8c3c533506d2b2f1de45de26f14e061d06b7c46967a48a5d47d6d4893affb90f3bb7d81f8c3e55f99be629eda0669feb4ddabaf1b498eb6893e6d6517c4dfc12a83561becffb57df5afb6984c69b800af36ac26f455c1255e4d9d6cc600b4190439c69a90bb4ffc3840e80be7c606ef98b858962f89120c202ec05131b385707cd8016248305c1958a2a2737535cd0d4cebeef99692c2de74f21612925df8ada72ea856056c379df33526394b069edb332b657286cbc65dfbbdd181d424d10651db20f2b2839f251a5e33ad2a3312ddcfbc8e0f21e6e6337f8ec7d6358e64586d458413800b8710d2d9d681b2ac8e4ecf27bb40dfca89a497631a645fd7f745d9eabfc9a45fdcabdb54d135a19785d99429772b19a9c5c8bfe2bb06da45ce067d39ae03bff0dc069ad67d9831e56ae86aa1e4b2efd33063681959a6735b54dbdf4b88573419abb401dbc96f514ace83ce7066b7a9a3387ca0f353fc6c6b4a73741b1c1fcd9e963ae806c8bd3f45452634f4b3a84f0eecfcd26c16bfde4850cbc8e13174bde15999fe88f71bdc3d016ad3302c55801655e722f3139c5f5f03860cee15f4aada13acd33a67c5f180a0efc470ea57c3fb835e5532ea8abf658236e8c6adf586cc498b43f3eb0b0c5cf7dfe1bfe33a068b4d885442d71c06aef5a85b5c5a5ab2a5945206c902b402b502674834fabd47a2d0d9497cdfe09c5342624acf9068442a8da0aaaaaa2524a6f40c8946a4d208aaa6699aa22321d1b99f84b4494ab6a9a33cf548a59133241a796937ed12923d1285ce911289a3bb84649bd0911269240a9d3b5fb59dcdda59dba66a4de747ee8432395153a954aa8569a0c6096572a2a6545555914c911265b249d4b4c54be57aca53572794097f1254eea4a893cf8f66e56f5b5b6b0a55557748749248a57d8644a3912874ee126997482351e8dca7ea549daa7acea8aabaf7de1b8742d56eb5daad76bbf1fe3b980a7e58ebca255b652f43cd910aa5a7699afe0ea6821f994c265b57b216476d4685c2ea9ca7bd76abd56eb5dbeda673c3e5f0d8e47674bb1e1fce3bef9c75d3b9e172786c3d36b91dddcec756abb9e9dc70393c36b91dddaec7a736d39e50b59a76c1b75bad5683a9408693c9522ac914294fa8d8b374b05ac7b40b8b2b84c72cb7949420fc8da89349f59fea1b0bed6028ae48a511f3d733246a4d5237b57fbfa537afdffa6ea1329d50a0121296159556cabae2ac190f9a8cce8e8e67d7937d7290fc93af88ddc872363e6e35369a76e69cedd011f3817d507e6e763a9589feead66fb7dbed26bb61d9ed865373eb8a533dd57d9e7b9ffb3c55144ad5f1e468359c8f9b09ea5affe327bfb6d4542a95d2d52841644cc74c6c38646a386670b434ab9a5255f584fa586ca53aa152f88bcad582a4e4047532e95465a198a8a8fa0bd37a4ff5d7eaf556dd0fc0dac2e54261a529243a3bba1f9c89b6d5ac2f3af9dbaf85f3faa24356dbb65ab7ba6dd7b5e3b66d5bad5bddb636556ed952b376366b676d9ba6743c3a2f05d3b00caee11b0a471b601680ac65aaa78fffaa9552a9542a5d0d096e88a09cb072b43968d8f55f396c3e3e3ead94942a356b67b376d6b6a9544a7bd3da7cfca8edd4e072723a58579bcdb437adcdc78f1a5c4e4e6707eb663c68b905853299b5333d9bb95697cb444742a2938432e901a6898e797c85585e735ef3bf744cc7308d46d3311d9b9d728907aadabb0a55a1298aa6b91269240a9d2b2bfba82854aa76dc8b8c1c1fa12dd6eac2f2af5ff9d7ea72a152c12fb90491a3188222acd58565052545a5a5a6694abdbb345553356df194b0ceb906ee8ec70d12db31a3c9d4722eb76c7c42e1dc8b0c96157e42ad7805dad6efae15d2a269676e3c0033d264720dd75e77a772773dd965c53fbb4595e5163014599867c4b4c92e2b6768f426cf82e2dd9debee52ee4edd2abf52994e287ed22a21d9292e14961556ba665cbec939b21d331e3499da4c4b63c33fb7d80d092ad0b616c73599e50367935939b91f3a3acc93d71deec141f04cb36aba5551fd0ae6ee6060724ebbc0e45ccee51ccb8972acb1d1e0f6eadc9dabbb3ce61912a146a4d2887762d2552a95aabc91e306be1430830603bb101196b9aa2b144fa5eebdf1c65aefbdf1c65af37fc95a6b6d2a474a67c8d4e863feb178f4987b576f16873cc620acb56d879c73ce39e79cf3cd5ece419c6fd6ea2a41e4e889ab16eb08efe90786ac11a9142292629e2111aaa5b2c212825fda5725a693e8b95856545a292cbebfc727c8cae2b142f150ae06bfd5eaedd56ae5839df501181f924de2a35957e4b5a71dd551bda72524227ce7472e3750c35b4d56225ec8b7ae5834edc2f22ef546e566e56614c32f45d9aa138a04ff0454869088e8f0c8323b5005d51404d31e9c9ef6de7bcad795aaa59e4620f3e5729162a5aaaaaa3ce7952acf7c0a2ec55ad3ded5b4f7b4a77d3da15c3eb1580a0a0f112957aa353457484a4e1e7532a558366beda9a75a99a4a8ad97b25852bfa2d24a59a9faca1feb5e726c7c9cfc68db56eb56b76ddbb6add6ad6e5b5b0b0512b4c4a48a46a4d2489aa629095a62524523526924358d94f6de7be768b519b5b5d5a8aaaaa66e5bf548486aa9cd4db372dbda52b9c5a3aa21d149dabf3727f5af412f8459c0620fe31ea027c7f07bc89e80b247d9cd11e400cc04e5356bf03f1b22b84dbb87e16b6f1741c68461f83bec36bc0fd9adbd1739049ae5dfbfbc0e0327d0630e6972b8c13904c9410707071df68586f8861f36dfb063f39f74a9575804fa94d7d6e9bd0b9ef7bdff177a3137795b87bde5eebb08f6963ce6be049a35e07618c8dad80a741bfa43f6776e899140b3f7f5fdfd3bc6b6a17fff3de5b564001913fcafbf8dfda7bc6634afff3df8fd6decbf617e71732c46c2400540d78773f109e6c5c14207bb5f7c09342b9a30c4dfafc7382accb0fbc30fc3ef4311fc8e59f17119e3b5bb092500ec305f201695808b0074efa6696213e37421b86006847f00d677abb96514df05f4a07dc1be2bf921fe519730b628767555d777691faa6e86227eec00040f3650e1c30a51d832a021c109201c7c40664c0019826c421f81fa40c4133d7648d800420f202c8074004203ba7d708142282630c25e9c144688e1fb91c2ecf321050df6e7ed9c933183060364c95e9cd60a5467c40b6f8ba0ef511899c5fd86e8d7cd9bd7ec85f90529403b1237d1c3cb0d71479039628e16860e7cb4a0c40f1b00a941091d3246f048220b118cb8953a18a183b74488715a1e5893bd38ad0c419462587515e4555fde8ccd4fde3b3ef997d47fef385e0dfe2541321cc71e8ee3a8c7518fe1f609510c760fa68ddb87e633d27a720ba6691ef60562c78fe596b183fd958345a150202e2177354d0f9ddea1697a46b7daa66b50a006c7b1ef38c5f2daa130f18f34195c1aa045a1bf4f4367a6cc06e3eee31bae29e10b1247fe517316c02e9b248000e8fe3df96b1a3f64c7dfdc349222be75f6ced6e5b64d5e376eefdbaed9b64db3db3db36b3a485e35ed67a88cddb19bbc661d327dd32c8dd33959efc8acfc3fc21d1e5c4fcd8ce66750999de6f18519b36608f7d812249e84e803397c146533d67145182bc6786756c332bb3f30311e8710c17135fe7d2fc6de55c1007460e2cfa9c96d17afb595f3828ecd3f3a62c5c17a9fe77dfc0a00a30007fbe98781cfaf0a7ecf0591c6f642441a5b7cf01bc82e2fba6c01037085d4b8710520ffcec82e1701004030f723f0a3089ea0f22c1f5496e55972d35996270882231979dde58b1979dd2ffeba3defb7b7bded79def63c10b8c12f79cc66c7f1bd171f2496e5389631e3383e3882decbc82d21bf7f068d1d228688e54fa0d9b2bfbc0e962d3c305f34ca458ed9918779cd62df79755d748709f60934fb791cfdc0dc21181404b9800d08346b8aa141501c4131bcf741703f49bef6e63a6798052cb8410ed32cd8637c322447bc31f8fbbfbf9f07de7d4720f73e0604c1d7a0cefb3fbe3b2cff3681bc7fbb09c67df05fdcbe6f89efddb87c21befe0b43c459b0b8c47fc30c6231fe6fbfc85b201fcc97c95ed63dbdde25040886666e11bbf8e493222618e28f1fb359fc3121fb75130cb17b1f9359f1c51e03f7fd217f4b9801a34814128542239833984110148542a2d09fa407821ee8795efe46a4d17df145fe7240bcaf2d7edff7f5d7f8a0171f6601fbb1e2c7619afd46bc07e9c93b967a944e7965490ec04e25a8a3e1cbfb4d1e8059f27f05d36b82f576acf924794bd0e52528f4a217118542a233f4217b9a2152448a4851c8fcd34445423848fcf285f8e4c761ad757d6176fc8f9f4e79c530f5aa7c7f717e72d88fc3ee5519fffb1274125f66c8923d66b32347c1f37bf13df21b3f6e1a45f1bfeffb185114c50fc910ecd9b501999fccfcc56563eeddf96120bb3f87c631a4f731c4f73eb39825bdbdefbed7031feb7f85e10772d387c15dc493f8c31ff8a1d61368165c60bf47621284c7f740d0f3c28d6ba8b4eab7a7920d0100026318000083300c436110888124ccd3b90714000b4d746c5c50521e8cc522712814478118c4300c043108c44008c34088c290630a526703c3054de9bab1597530f89fefd3a2ac14867a370f3e88b3ca825664022450a2fc2f279a5b6a461ca33ca9243bc088e29492a50265356ed550052e71425ac23cff828777eeef7ee8a55a4dd9cedeb5c96a26cd01d34393dc78a5b8732f7553b257713fe1884f8ec5ca862b0b71eb16acc1847c1789e696fcabeed5b5f7496c5bc9a6cdb5b4f994abe4c99930db9accab106a8fac4d7af1ffd72cf09d30f155fe2568544c68a3dd1e15935fba29edc4c26edb46c999b07d601e0560d3debc713089521f485673aa27958f1568c2420bad1e314025e93638db19992e9f00a56d1285a39c9046825c18c68a8b42a56256c93eba0a5a300595c98b4260bc0a1694edd466f67b7f43c69f89698000a93bf5eb60b3716228935401f24bb0a5b9dec89b70cce29dfa1d56dd3c13b89c77b256cda4f0055b70d84dbff1a0f78cb81d84e07e8bfe6fd19ee64d4d3a1d4e57fa5fbf9860029a01350ef5223ae5270d8ca71d3862af1f37bf61d6961f83d81d7a79371fccdd3901cf6431c5a50035007f0158130237d4c88117809b8558d4eb828f1202c64224b2971868c0ce1dbd885e9b39587b82db93e8217560603493d9cc008298805d8fc37e6e09a6001f2e0765c59eb7d82967119fc32dceec982e4e13d4418715932be67471bc6a71117871c59d320644513ddd8fa618dd18b0a09ea295b40c0808f48cb75dcb517626266a94dc0055ceb7e83716e93c85d5abc426a7c5b165d532ee76ad4c501a3cab3bbf9d2b79bbc5697d28ce770b702ceeb2e11428a3de4e25d842a57b70cfe5b1fe25b67fe99c0b6b47f75622bff92ad486aa3b7d93d0e3c83ffc321a9088a5f96fd238d22f5a38b7852a5d26826cb9d55b80f514033fceb9989afa05fea68e49a6d471e1f4162b877a73097257dd28b19675d44b72670c6ae0b540ef833151698a9512b011d69127552fd973202c8cfd20ca38879eaca4e5be22976f9f4b2e277eae6146734c8bd4b5ca167ee8940584a2855f9768fac676d1c2f5bf603bc8d62746f3589d463a57b2ad5bae880f69c3f3514e6f5a98b634c982eb5bd0fc699cbfefba4728626f8eaf169290ce75a43f1a77a916128be555223fb5ed9a2a95126dafa63112c375d8a8d24bc25bbba4e5391c59d989278be30f908651a3c1ad6359a2705ac30d6bbc4167360d331e20b185b186568c2750a5f6b823bc1818585091667294947893c42880a1485da16392cec3d40c382abe4151d4fb60fae597ba4a2d39d2b0accfed2bfe0f8938e2e928447b745f3a8c87b6abdb699d82bf14f5d9ad3377fd72f87a5ff9385e32db442a38a9941cecc4c7af02defff8a45d780cf33755e03f6c80438a7f858f35ec48beea7a775a060b51a5574e7aef4bae059549f57b4164e6b158355f855f9bf5c2c25ca19809836d2ffd7c723823333e8952b147221f872c8c5e8d9340a64bf5706fba674b33ffd51b65ab5e42d2ad596c151301621846c1c49791b3546a5c25ec149e754a490501b33299ab634cbe29cf8daa23ad9c14b4e5547f2fed8f029a8709408fe8b3e7e8e44a0d63c94e4c42342df42161a5a44cec190273c35951c2674e4a74847a0f7b73a21ebf37459ae10b54960d081d6d8d77b10743089b60bd7fb0efd6b4f04aeb6d107327922fde8f45f74462ff4e621c5ab496a8fcc970b8fc2181bdd3057d7f1476023ed503baf08fb6a85e977623fc65f9bd91036061d98dfd0a482a2da641253dd1e8f4c8116c440db7217f2536e2a912ed45710e0bf18728d4fb126306d6a0a3004ab61d1f1139c837eed0a276b74744a18fa69876a8c327fe23d13e4531f6a21cfe5478977ab13893f7b9521f484002d5dd3755b38b1f688530ab5edd4ffa2c2d11045880119b8a1c2a35877f0709a0f64e02e4861190db1b9a8eca377ac7f2112899ed8259246ad8fabc8175c789d1a6f09d0e25945485604991cd6e46c361c1bfc6464403f2deff2eca606e297d7412ca083a97b4b776eb3f8501bc952606db46f9ec29b5e91041485a77103c99d1b669ea34ac75656d22e275402da1e9d0dd7721c0f15dd235f41ef1cb2c84cd8a0deb01ca034fe99e32c6ba5a0e76d6b0587a260910d1e5118b2d39a5f78b75a3acd60b009343f2a6d6487e33717ee8bc73b9dfc38cc24a7889b815b11c1cf35f95f798945da20ba5af58d1dd49d9414e6763797cc78e36d1ade6a484521aaef9ad680d9f5f25e2e77d58464a315161ed3ad19c12bf31e31c75ad999c5004c759e182d55d145333cf264e8c5c8c24d9c2cb69d887bae45ad81e54a2e3f0ca80c99dbd1a4472652da3ddd71f58c2ca14fa4149df079f751a78cdd141bc4ecd0a6dd14615d8f8188a66d5c1f33e691dac2aae0beaf513179606d43db0377cbaac182b681fca1e344ee10a5d87665ba1b8b15161cc7ac2fe05b4c547fb69438b40efa404a9461f08a3a1c8286e29aad96ffd26e43c904aa16c036a347784a255838add233e0d9b267c31f3c0ba24db8333ca524b463f93efac48038fc3a2bc3678bc6f805a7bd042b8e0518dba7fe9e3b358532402e3cfce231c9454d834c53a8b12e28934268f8859d78d040a9c81471279819f308a65f0243a37784d4b5223f33e0ac324d44786c5a9fe55ca4e19aa3c17978c2af140d78fd13347591c3e5563a72e25b0be7a855d224744b2390ebd2a466b87e9515441e4784ec4f2de4698019e01cb580db4ed78c21ca25ac1940523d0c22ebfdf9c1088554756a0e7f3e481b4f457eb31829253afabb8402cf2ac0fb69cfc59782a61d81ac52e5deb9b83a6206ce3601dd3ac26e0447c40b80be9ee153c69372210b4c76476fe656b59caf2ccf9ec9d746eccee84e720aa5018a50e323417a8f695541b6324b64883485a00f1195b10093ae2163f024fbb1eb6c5580ec6b12be957dae11c4359aa50dc2d8ae92800a9a36a14e4d092f24e3a09401f58d1582ca1858232edf0f9df4c86e587d246669083e647765d4925598a2c23816a20223eeb5522c22143f44d9a2d3636710ede447e0809d3a8915a9a06afe1b1fea57a0dc9d3e31e23b88a489ef1db18f0de264c9d3a47c0aa28c1a57e9d0509c15e34ea84c88af4ab76a2ba6002b68aa641246327d700f9f6ef3e92604c84052767c28996df3949f81513391e0bd42960acd0831553a85d4a35a2d888a0b8e568e2fed1a418d57b25554828260927e00b6645d93ef581151d893a29543e9093428ac732ba9e4904d85eb57c77fce5cb8e787c9d00f12225639c80fe9345f9aa2c012a6c5947a025ec3835f9cbe3420447ae214c22d39a72a2a754cae7edcec0050d3f2d6d3dfcaa335f58674e15cbbaa86a31d62b01a892d80536af7386120125427c80cacdf9d107d0e41c707d9072da660f562c698b4b31cc8d0815a09177ba15d61102d8b017837604b6dacf58c7980c2ad5d696b4449056882834dc4f57d34cd131b7d35f3c1d81e3bde8210671babc1ea7027a082051eaeab51c9ceab2dd768546297dd552761f110851940c4b8bf318453423a6c76a31f2d9e901d473d1585229c5586acd7f6cfcc5153211c11916a707adcb3e0da2401962051767ce1eff374aeca03fcc2f139f9e43c5c03c8ceb4f706a39b2fc493f935b8dc35370c9c2f8840a9bd3c3203907e0e81d89c14b8b66c5a0a14556c8705d8c9f530d1a1eebe4de620b7495c6aab737f3a51393da28986b34dacf0a00df30a6c5f9ddb39d159a216f1ad0f7f3cf0a02e344a7ac49594c945a88203f49c759e827ab8ef34ebbb30577b801583366b28c9d5c61701b949ab731ea68fa488600d8c45106d8a422980e73b4103cc83be385d675628fd14a9f785dbc2641613faef44d0f6032681f0d056556eb0bc7579d03d91c267a5f8b0a2594a5ab8bb7957c5aaa43a48d9861657a3481264363bdce925b9242a02be2eff2287818ecae9c6e4249803addfd07050ad82bc50e9659108a230af8d6d7191cef575e585d8ea56873aae324dd7fcd575f20f39878a54530948c8eaf5009840f928db1111660f33ebd1bf22e74d2c758eb0a88114374e1d55cc33e4bfbfd093580e779168305852a1fd1722f482adeb07107522203a9438bfe6e44ff08851a4fc5962441e86940be76f906905434daa22f2d27ca533a7f9ed4d1380473a3c8861ad07181ecd358287213ae54135cb6b21b016f9870a92fe1d2170aeb70874b46069786cf6b8661dfc717ae9984c1258c461292ff1e8ba5da18fbcc3470802bb4ede77be371663df02cbb88fa6c83ab5727b33a8018b72717991d84c25d35a165b8f41a7c28351bdff5ad3a1a1112b76291dfc2234dbd23e5d9e72441cdb7308c50ba09cb075982ef263b46b827e87be210eec108faf120172fcf270e22afff66a9d044d40055882816296a8ef591722f2ee406d61d2032090d842333844d8cb0100967796dd75963fc03b765208ff7303f916c7dbe509a925484ec1dba4592fbefa6ca2fac50acdc0753bf77f22ef26019d06bb7ea03b9da7bb9a0f6c2022e3cec41f8ecf7bc0114011b14ca08a881f6aefca450a6b96f26f970b5cfaf03c428197c3b3cbc7674ffd4ea5b0bb11bba85db5fcb22c6fccc5ff350e658c03a84b844fec308467b96a3ecc6f300d7dce204ac327f0e094e10e272bfebd1852afa086037382016fa7af4c0bd98101943616363f359d0912844bd9335079945141624987f002b901a4c538758ce3b24aa5a95adad8863327226e36d9c93da991fa61d915775ebbe68a54dc2825e92f52d75c9d6ecb16d5909b997d0be4933cfbddb4260a5807dfbd4827f1995ba77c51f3934ba6ed000ea57d8fdde85d0c3857c51bf59d5f8432b45bbbdba8bf496a29f938c67998a256fb752647b62a7cf2a111680a8c87bad6d8414b33f7c22e989294f4f9943c3739c80768a3abec0ea9cd146ecff2026eda608b3aaeb4fd0fef73aedae8705e349041bc59f557a5ab3d62a88a32a2ae5cce84b550af0a6107b39954151644d1b772e6942fb5b78cbac5710336490da4aed00c3c5b5b141ecd394451307d7c1b050d164cd797f0d9ab05f1ef4c94643dd8c62f747c76d1d608459b40314aa423c51beacee04e24564d1a8f0576c5cf2138b8dc9210f669ec6c6880071b0fad0b159676656a257ef04e5318fa6f0648f8d6f04c0e2bc883983908d4395ac93a8c2291e2d9c496260e3659e5c0b46720def3e18cb4ca03dd36f98251b63c8b27f4349c395b6a6e36c72af85ce743e448a8b40400df5fcb86d1864cfc92de4d613180d1716407f5cf4a6c7b830643d3f0c6d5fd8d95c04958f3459c1f404e417b6c5e53b7a40c8fd0d73ab80e8af7b10c560af052f3796394010b589cfa981cfd96dc748ae018754f5957a04333ace81efa16ce8786f403fa2c0ae670a40f834cb5576ec5f261b2ca9a212d7c0e77d06d5f939111b536f1c85142894c36bb5d0c573e4a85b7b163df5a72117908c261def8bf90f5d2b62730579107e3d6437315d23e16ae3b4cdc6786b0a80c69cc02c8a3989e622622385c5ac1b1663c37522f62801b10e03f42cfd525279d1312956c75369023a9ec1df02bfb473d1b1622dec89646782d883dab127b0f088b526c8c87718d595d50ec96a77a181cf7bc6a1bc9783185c9f8eb5de6a2aadd5b2b2d64edf54abeaab35bcad564357adfc4db52a3e17be60e69a072c83a0956e39555506062b9d9509cd8101c586adc7d15c5990151ab9317777c5c2396868a0e292bf6a5ae60a74f1da73eec08b76ecc436dcb304d1ea0d594cb82c0e73152b269ac8fec1f764b2311a00e70bd2e47b62246771858c2f50df65c6895b2d0bf3b342f8d1e5c087c235d972d92432c3e30dd2689cd0f39bf1108c433aa11dc0bb87aa930c5e563feac19b7a2ca79c8617639ed31824f309529e1ca601bb5d0a6b04122612946d93b3a45a8e5c4b9c0d5e2e4161aaf252a59d62f3df186ca5c2a5c21b3b105e3316bcec0e4a1d6e92d20b47ca65a8a47d7a43c9a50aaed1cedeb797d2d95481a0c0b78f38f0a66b1c921513e0c8da001c25a0d555516b742900387420155b21aba135995ea609985e6ed774f017fae0322f03955ebf7a28bd67c7cbd3654878250775a9a640a437c22546815b8db85495cf972d9332d526c97351953581d75213fb6ccb465a7ccfde46dd939aa39814182915334495033fe45023bf991a574f061e4cca3104beb26c52fd4ab8fdbb0047b011c5ec5d828e15cea3f09c9e0c11ef549def2a9e4a2bb266b1d572249c4993ccfecbbd587c93aacb4cb21c29d1331d9480359b9857330bb83b38675258809e6afd72fb469150e2f8f8033841471f96f2b2f7be7ecd9bb9ffc41935a58a162c33093148834214b40842554e4d30e66100b44fedf1011a79caf41dfab7a71fa0da0996dacd98f39f1d68d2a02af5403556404f8e79403104244a0fea021b0de901aa59e1c4e2cdc1a9f13eba816adce431a8f0106480838048e47087e6eb5a98b65a405595a671b479c2576e40cce05645cc1e12f25c300c03a5e785cd25c3bcd0d0351c2ac32ddc6da8000db3a8e533bbed952a5e56b32f8019cce3c24b86911b64a38d32914a9391ba543e82b3b40c3c4913e8f255ea08ba246cf3c8f319134eb08fc9ea87d91ccc418fd255296d90d27c84bde9424c2b52da2f24e8327ee699765e30757c36cf5de005157af00bea3bc1de97e990ec4a636552b06e1fd96a91f94aab725dad00f6a6634997feb08b652b5f9a320f291e8deed1e5348972b698d8ec12a12235b1678b292307aaf7bcf0fea017bca03df389db32a6225d9ed0f79ac43751d2dc172d2a38c29ea1eab50be3da51cc7bce5d6a9c018468477048c859e6353752f287089f6b773a8a3764dbd788bf874869675186af27384d247f2696250affb450622cb2381259f30355ffe9b865f907c5771611737bf739ffafa2beebe8aafc7a093a1b8b69e4d6cdd5abd028922be1e4e489c3e7623eefbd98e02457936e5382a5a8429d1e99d6fe43d4e29bd045b6bda53e06c49e84f2a2d33cd791ef10c67ef68708ebfef48508770041f0af97b7213b46836d53516e78865bfc98621336e00d93a8703cc37307f164144d19508a43f2aec08416c65e6432d4169511b315ac9b366ea3ad2c58165588d2d5ec8de8c920fa31838219e14d41f14bae90362aa322a5d22468f6dc331b6431de62d9651a4ca20822f41081125eb30d84eb9a20b30db21aea674c173793128494605812d8fec519609b383d2dce9222b6337a99779d40f6eec0dfa78b21f0c69403850e44993178dd960ce1e2667941c8146466edfa9ee08d85c4523ca0ce50acc570881eaa1631ed57c3b45ac27427eef4611fe61421c6aa78bf3873027dab01e9543261a191a45f640022a24da85ddc8906807c27dab7a60ce1d030850b05413c4edd10f38de4fb4cb542b3a190315b7af0773ee13ff92a1ed317c5ed10d314fc40f509e4491ce54ecbecc9180d9251abaa05091ddb12f49721f8b11a5f617b36b4dbfafb98f8a46a4898df272ec90bb25d8d9603b6f9293ca2e0d6503b7ae0c90ec53379f489755edf0992f37188a7150888c702353f35418b4c8d9c1692665975f5155695b7db87e0a9770422dcc07ac66d0f65b59801aa43619ba5a79bcf570722a9781c83c1026a7a6edb7382e5e7c87f3dfd134429d22bb73c0b0c22083fab503d040ddef640101a85eb56db73f8ef733aee4ab1ea635193fb53603624bfd72046e0b11d88ace9952e998108fdeef61cc5760eb34cbfdaf18fa2d83ad843e4fdcec8bcdd93f75344de1a330302c325f37ceff61cb2d7c8b96ca1af357b869f5a32e3766f8f2a914f0bd1aea14dae5c885c74aa1d7543acd6e27f3abcaabfb0e6729b8d29428f313f84a27d9ce85b8f16a226a3d821a21dbea78541f7b435af3c8d460cd17681ca8f0879ebe134c203f7b62bb6404cb40ec4315f80753890b1481f9070ecc6048e1bc07ae5a085ef771e440919f1ed9147a01e0648be086e5fbd6eab643aad9228df6c6a3dee8478ed67621376809c81a6c508f432de18204ee95f34fc9959f8dc51bf1fbd8fafc84484ebf5a152b00334e49118a128f009e65ed25a677bdaa54023103f639e61c912c3da1907745f28d2c9f61b9e9d1a1036a1e5eeb3025abe97406371af6bc1c8564b4ab38b8a15577c25f1ca50303d32cd6849dfd6bf2703fa36f8543f9237dc6a0677c6d3c42148bf6e9b4fe7d3eea346725c0d253cd239f6a29f6431d7c1881e7fd279fde43506d1ccd48068060e810569016ab6d1c60dc280a3b41b222f8dcfd4a6c0200118133970e3c618d49bd6087c22785cb109962a1855a95fc87b77579be6f4686804cb4a6491879eb8008d25b8836cf23d74bf637788a559462d432121a3b03401ded62abea381bd94c780e0c79f0d8a5a7698e0284ff2b1b021a0245b56f37727991c341636bd671b95cf44c69db66b937b8602424830118285095bc79807a0ce3d5194c17c51121ee79436f90675a5da748579f25e7281374a5949a4ecd23b63e1a970f54ffd142b553c3ef969071429c38844ba0efec0d05c5a9ad445ac078007a665ec1496cc8cd9d15a0af74851d2b11e887c87906195556ff948505827d66ffd91a1d0c1bfe98b28b551523ae6d67da2595de36c0e5198add3d89246eb21964d60d03c7462239305e6facb35e078209c450755d9b7804ca746d3ce64ff1857d02a0c515ba90ca2805e09c7a414d8b12c32f0e5bcbe71bb53143be4ff1b247d0c3864ebfdf70e7105ca238a5d681065bf8fc1dd20ca2b98da7f1da1a8055797aa8d5cc184d8e94f33cc02a5e771932d4050b26e9f2ec1507ba82a1a7c6dadf6517bb4904ccf89c9b8ed4a6f4e3399cebbd0a674788d439851f6dffca5c5c56d06c536197b209dc1f91d9b9bf659449cea0a2517261a5148168ce91f27dcc1bc4f7a058bbf2b0ece9f126519c3810c0ded1601fec02cf8f4ecd08d6035af5b56b2c6839f7cf6443af27e201db829c1ab8f1bf7513da54893d065c0e98f486974145067faf465e05e3166448235027c6a4618c4d88153d339c19bebe060545a9ca6000756dfe6ecc9d68b59a3f34e2368405dcc45d4068462c272fd985d99aab20b42a81ceb3f55b55f01d54656ff9c5bd1c0e49649b1046917e342672e01cc1a2f19fe5aecab3af4fc58470f3d0665c716a08a896a7b8c2d7a4c211a8f1fb93b5e7ec80adb4d2024ca6f2b62ab7c6307ff57555978681c2298881c212536d4c770c4db51a16caaade245dfd8cc83e3e8367df17d9765d177776d9aa386c88497394aab6245ec0e792e9addfdc8bc84cc6725f66acc92f3028e94866349dd271b30b9ad0a2245e4efb2f87f3cbbad84443ac286ad4523d454b7c26419c6b6f0d9a7ff601a9f36c4e0d60aaafcbc5681e6838baf57284ce03e738ac70de6a578507da6619daa3cb9e4ae81d8d21a75eacf9a23ce7f0dd9233cf7a80feccc2596ce7a3d1296758c5f59120dc3b6b8d1c0d905ebe4ca3c69cb9a0c54016fb660218f8dbae929bb13adb94e6a3d511aa584a681cd7009bd23e427b2eed3189524a6ef8081595ee55d355d72ba17140dc56af2eaad1f7aab4234ea63947a470466808dc505909dbb0a42f41298faaf1e2ef78ec29cb1db9bc6f5f5825902acbe81302399ad088efe2f7c4433cac503120ee4d163f9367c12734d596e7a865bfd98a20906d2a34988f98831f49d52ee4f81246022155c5a80b6b2790d1c8bc7d802d406389a9d9810cdc002eee5072b109c06174894c013092b81c6586fe819e05d670da02cd933a62e035d488e34eacfdd1af0c8540f406cd1cc607c6e19a415ca000b8b0cce140071caec8b8140330ca2d1c1c0f80e1830d0039ec0229cc2fe0c9a69a94e56b705879f02bc251e160f86f904d56e2c80907c6becf3ccd8c5461633e298f8427d6778e14b6237035f6130b942669f452a39863bac7a35529224e804734071e6adb6389f378fd7acd421c9140dc8f848f0287b14f37936bc24fa350661766a406c024d023727f11214309e607ae306ab4d81010ac880e4c00c36e766dbae358117891e5334c12a2a5691793b41f396265d62454168c748c4d58432d4232a285c0dafa0996245034fa4a328f1953873085c68e0f1d1132e0909642b7063bdcaa41538ec3027585efccf85eda61200f637dac53499beb8163360aef4ad8cd33c009b2fad63b3d791d9733d0dde5adc5d8305e78be2f640dcdbc69617c9720d93820403a476049a5047b258200c5a351da6ed41f13dcd273a8d38287c409df3182f9b932859ae0aff740623d58ac17b1339f0b0f0b501810bec32af41e89965307cbe2e2a690d83b46f4a8dfe0bf4be5d075bf66a27959d8b976e64efbde5de52ca2465a50a780a5e0a634a701ac7284933a4c782f9887dd25d1396202f4001b2ebda4aa224883d4b9cb0e9c28585038b4db1bae8e9c265e5fe3892424ebb426e5e7aa4459fbf4fd9be67fe1ce5761956123efeeffb445114cf10c2d0e20fc9a66d41fc19df6c8188b4e834f2dafe340f91b436447e62e69c50f32162310384105c4de86b90b9d25a9e4bbb6e590837f126dec4dbd708a2868e02574654a7116efb1b4d191985d98ee3fedb37caf2a45bea9cb50e2995279d46b7299c91955118a3ab206b020808e8456fb4a4d679b4a406474b6a99385a52368e9694c1464bca62a325652fca464bc6f468c918d068c99889d192b158ecc5a1bcc513228ad968492ca6182d894515a3dd22d188bf6ffcec16f1f891be456ffcbc12937f2ba06002bb8248450a9fa1383124542900bea2d8f74637ab54d46574cbe60645fb2b5dd0a3fa455df573515751d7f821796a328834410291e7ddf63cc7a2ada238453b24fa34d2156d79d269e28de258ddce93ec5b75f9aa7d6a1c777fb1d6d2adbe324a46a66e60ffab1bea69532c28db3637c55aa1cd36d219adf1a4074110042dcd0bc51fc7703cf1435fe3443954c1abbb2f1ae9ac92d1cdd2dc2beb0e8d6e54daa8142d4c03f1611d34ed9c29510350fc89af81a2bc209cf8a1f751c3c7897266694efd45f64aa31bbd5eeb536ade8701450ffd893fcd5badf60e1f228d8ed0a35a1add92e8efe9a6fb34baed1a21f480b2dad52fab9a2d2a57b76c519e9bed7653b8aedbd314ee4a0994d1cd4d3f12a3a3ebcdd2cefa54c3e8e649f6882b3182b2fe46519e74ff6c7f232a94a96e6a6daeb5eaac528d6b9586deffd69c8d74f63930d219e9ac92895d35d255a0af7d9ad802fa1a2ae7d09d899d89389e4474fd4d6c9170b190519489b2d920d09d9b26be5aa0313ae2a63f96dcbe6d37baddc80ca8fcdc6a466b4ee0a08d76463afb2676bb9da5f9cf1940137d36ed8c6e16bcd1a7d1cde8e64958728019e9dc74333bddf6af61954cec4cecac899d899d919709a7a1a95531d8a006d0426e499b6201d96d27a74db1827c51b0299610ae5daf3c09167b20af7d22c3b00959e371bcd23b54c77a82f431fb1f2e6afe432411082786fe84974ee52feea720e9762daa54afd094a14af576df48057dbaae87a5dd17ffe6e742b1822e37c50ab2668b36e3ff1e6e9e58c5d7638bc60ffe49bfc0f7e1e61d7f04fa60342600cb6a6b1abfc2bcf1c77a8bc168d4fa0496c105c9722f78bb22fa222fcf7a8c31fef2a4ec01d0cea5ef42154ae8b34e59c9a62a551d227d0cbdff09d2cb2ad9bb1563b83c91e86820a82b93eda0204abb1f94c771bcb2b4fba3d6f729bd2ff422b540a018be75ba7fc1315e71baf4dc2127dcbefbdada7d31049f3ce9742aa8b32ae9b22f3622834040210dbbc39761778862055dc1a6584e579bc23e70a2a3fd4ffc59af6253fa745dfdaaf7c4df5c7ee5d583e503bda5e17792da3a75a7ae77610f440a91a7dda7e33a507710797a11670ea42d7b18154f12130524e738d763ed871d77d65b7d72338bc9c27145ecd3c36cd3f33c0f973c7ce300faf0efd7db114fd27f5f0443f2cc1fe6f7c88fa4a78fdd8382d5e6e6051a817c4702953bdcbc40a56ba23cfaac502265a21b477ef0ef8ffdd108df0b3175f32371e0ef14eb88698ce17bf8c11ede7bf8bb347ad01033b0c5a7d5461221b940bab29e47e47d3487b3d96c406a97ebeefbdee78e75da17e6b43d204af659e45ffbdada696ffb7efef0d5bd544fdd3ae996e33c49f617e7215a8281bdea559e7dd63844ecb372ed8b679f458ebb5e0f1fd586ef1e2265b416bb71dcbcef91bee5e67df15e9806b10f46436f59597530b25ec5c89a95459faef335dac377f6e9776c76ae7d2fc6186795ead595be67b49e6c0c8395ae735357f9ec18f4e8fe102980235a5be4931c2c02fe44205822fc43441140f1f651943ea812272471a4f6c3a99e7829a136f4b6f4f10326c5842d25d8345d4ad850fc0f9a07cf0a5b6a28bea9466111b04f1401159fe255943e846ca8fd98c04b6de853943e66a58fa236b51ff50a1035146595f73f5cd486caaaef63f80992d6b25b91dec573441c10e9fd951db8791d77a5831b728be3f0a8c3ae1b224f90b4b6c393c492a8c6a6006945bfeb28edfe0571198255f2bf20048d99f2aaf9c7f013405e405e80301828d1d55aa9fc3226f9edbd3e66231bf4394bf21767f6ce3e84d9159a95e5cc5e8045e7fbeed696d7912ab029608dd716d60d25c0ba210e0537a9623bdbadb52fe36e3bcbb3590d9d445a84e4479f79bb7093bef54a928063c7dd4433ec9ff5f1d7a51d779ffed44b186e962e9ae8336f5a472d54ea47a29452aa1369d1e9390cec8b4bdbea518f6fffaeb8e9736989831abe6d079e44310c34f78aa29fd14bf5dfc670d3c2b83ffb21132aec8f44afe21da601113db21a7684f6a4ef7ef79bb637ed4afe258554bc9344e528a4a2cc6e529807353f8eb13d5c24c5ac44519e28874a132079366d50035c12d1c88f5f46bef7f3ae50d3ae42fed7650f92e36752e8ea3fbabe90930913330c4cd0e62ce8f4afb1a75bf615df1a2397dcb4249aa8a55a63b869ebd2166da10daf2c6dafd67b2fbe24dd600c186eda7269c9bba6559ae066a5094ad3d2acd28a726669f6ad910cdabedbd9f55c0a479125ce089f04221a557c221a1407913f25029feea2d3a3b69395b492ab88c910dc0ce98fa406197093ceeabe329b69b7615d3dea0ac1b57e30d1298cb4226a9946d2b18f524af397ebedc0f7f40c3f87f7b0bf1f6c86dd59c42199e3fb3c7a5e2c869f88c6f612477efca218c6c25818cb0fa357bb7b393beb86c9cab369cbae6ffab1f39d3c75bd9e3b6037fdd8d31996e6f81ef6570c39a01bfcfe7e2f52d1c719a5ff2dd194e2c881dffbca11f0dfd733a3288d64978caa88688c40ffd63b9b76d17f42cab522c99e88b4c8e8c96cc53b898368067ef7f2471cd89d1472535fa044eba4254ffa4ae215305caeb0f429cd947a492b2d71d02d2b84488b2e51ec619f3709f9b1e7d51f013f0e98f8a07f1883ff790e593bc5a658374411c57efc321b919544f412c54af1a9c539931f8070a5e60c5a6cedd3955a6fc55ccc2bb0fa16c94d67e1a65326278b5c2b8aa2add59a06fa2421fc1d378495d44d12872d77dc1dfe8e13f6e1e3c80f0b4b1c4433ecefb07c5b8e487ef4696edf1ebd63082b73ae3524ad0dc5a7306bc91dbec5b2fe505be40ff383e449c2ceff915e499d051a339b21033a097f4708ba99b37b99639a4f60f5adfaa0fd5b497bdfeab09f57c1a7b00a56fb38db33c7b8eb5faf346ff9469e52fa97ca5c42aa01d687cd8aed455b7ab0a281cb095c80b02187eda6b51978999364af8cb2d9b57191c588ed3500c1aaa18d9618b6386581dafefe05469722c90030706d66a09a210f961cb0ec683861fb2fd140e6c8141be878d9b16343131724a090b982c40d2784d14388d963adb56556c10587baa84ab33d062dc36dfbcf5e0626dbdf94a16bfb23e1be6c7f0acac194293fbdf7efbdf7de5b81caf303b1ba732e79d81d7b209283d8c7801ea8bc6ec64aa2ef71ae14039bf617b11d49180c060404f432fc81be6967f2f4b1f3d60f445237635963505b8c1f232d8c04c14d0d983a207ef8621986e5e9afe3dbf9c1ef8576e66189be72460e63619044df70b1eeb7d10cc0587251c6e1c09540705ae5c069f5a90e842e164845316e9000449409faa4216416db29578d1b24dcbbef8b2b92e87336fbf0f77954ce53a5c2513d58543decb3dab0a8acf6598f18edb33e41797805112de4344f0ac10394624189942a553c46f424efeba54be8df7befbd67a5d44b806d940947cb5ade0928a000dbea98211c434f4c2822de17efd5a64fcb4a5958ebe1166905ad877788488beee761ab6125ad4254eb751731cdcca40c34559a252dcdac776133c2edf108f70529cdfb0cf6f7eea4772ffe42fb47cc9e44e451337276dfd3147ba3c027f6d0fe488fd26cac03221e2f29b483b6892de6f192405b04c74bea2d86e325655b1c631bb64598181365e325c32d028d1fb845a0d1c428340a8d43e389f192768b28c6d948a44245ec96981ed9b722f0c84a5fa820ba7e978894821428c5699200a800006a595aa074f29ef01857fc3482b6576138d1443482f67da14d4ba21942db7ba12d3a11f5241cf8712983ee5b5e9aff8f784a80d4bcb07d3d803308822ff7c0a4a5e6fd42e09604dbbfba162722b54a35d393486a7a1efefad7535cf2021b539af796f480b6c7818d4519c6b526fbc37a354224dae0ed1629a5b452bb455abd92be4b6aa3d4fbf5b18d32795fdfb757aa0564d7a93e517aa0ee3c71c5d9f57d8d2bb9cddaf0d7129c2103b17d5377a06ea047823bc15ee334ff3837aeeddf9dedfff5d1ed13db3618dab8fc74556cdb92c0521b3b9b76bd14388e325560dd6d5e09d893e278180b7901b2a9ea0383c3be332898ead92e2de1f7bcec4bbf78a5d6ab77df2d29c80b90946988e2f2d60a25524f329ac0b65f7159a9892bbdb8d63953a2b5fe157bac5689b43e912d6998268bfc6295027b91cc8b77848182f62f3259209d303628257b9094b2ba9dcb8bdfcaf84b83087c5c8e0f2bed1558662adbf9635617a7cbeab11d81a282eb72b566eb8e9327914e55b027f2b5aa7b6134bcbfe5597e63853140e88369dd011974832fa3eebb2f6d718a0ea341822dbebd7a5879fa16775eb5edefc50f46e38a3052fc91ac301a368c9b2bca0c9b89d1f8af3c497cfb1e8cc62d6d98f2e451f749e68b01b2efab8e1a963aaabdb25af4c8be782badf4e2d8bd6fd7b849827dad8e1ed178d0a7cd85a1f829c320d2a273b46dfbd1f68f21d00a65018ba7faabeaf1a4154fbd3b2a4ec4090a450d64421683f9e8b1c393720a4a7fd30fe80756a9866095ea96599e59000130b25e92ffb399a6c04ef916533c6e67ea3a17c05b9b9d02c09f3fd36fabe0cf7cea09fe9c9d3e05c60177301ae924e4e80990779666ad5216802e67a372ab686b5bf06669535609c401a03c7f5696e74cebb7e50aca336b0aca534f50da29b03cdf823b300e8c0144ef119123a0786db3d936dd0348a2cf106a43d140f12b4a702bccc959e1bd8a2dedad20a5686f06a14ff06bb7ed57da835f7d3c89a80c9d8436ab442bc3284bb31bf8f6ca102a097d82ba2ef08e2b0de0ede7a61ad2dfa71f38b5f80bbea946bb7f77946968dfc7539409b763780cbf800ca1c229925a1a6edb7731a5690de9ab40a07d8b6f5122953e5a94b412ea690da9c5d3a430f80bfe9c6d1b3a21972ccdfe0524928f2a105a3cadf451512032c6566b513e1e1d4685507ab4fffdd3fc40aea84b9fe1257388219427d50d556b2da56e5f1b8014edc58fac2f448a5ea21ef1cb4dfb2a489100a410128e3eefac92b86569f6bb76621c7127ae1175a498255eb9695f468a61c49cd845b4128f884fa2123745284bb38f9b4d6dfb5d51dbfe111946855ce156e8c44dfb2cc8d00272b7c32e4bb31f4e89b7176db3af6ddfeb76f5334d6b4724add17d82f43d44fa16227d0755bc63b091a4679e28d766b1cb5d387037d35d3fd3b86d2da0e06ddb07c1328472d39257f4835f562984dae0d7b62154084523073000f23acdab22d10c1c59478fd6b812edad8d32ddb777865dffbc3350d9bf69e4755afd8ba34775b405c027486183eb664582c908b78c705b184db403ac57abb52fc3df3660c9d2ea2f59ece1ef0a6d980c9711caf8b6c33c98031ce62f5ebff7de5b698e394c067ec7e57651b641a547f5eb074e4386644ba395a447f5497a94c10d46eb95de0b93619e409b82301967d3fe6032b49635e0dbf71da06928ca3400ef8ba3d31ccb3019a518d21ababdd8fb7218c32fc32b896684e5f9816d7713ae60995dae6155a11c00811b04f2c5ded75babe7c5f02b3aec8a47e85be434fb44f4a84fbd85ec958881ccec58ed274c871ed19f0d1166d3ea4ef18836c6ae4f8f9cb43fae7eeff6ebee0540a79d4bd456a9a4e07bf9f37befbdf75eb02c49f8fcde7befbdd75a6badb5f6964328a59d3db2a5d52134d456a9088ada901fd65aeb79de1359aa793fc407fe99a5d5214d35af1ce2bd2def7b49adf8e2c5e98316805e7036ed937e1896945e50db219188c91f7437b5c490355c6cfc54d57cd81ff2e328073a56bee4d192b2abdd77f727b254f3f24793949b2025b8d2020c40d2d49c9c9c6e4b35ff9b59f377bacd6afeb75cf3777222926b42645f36dbac26e4eb63b3d5ee3b11316b42ac1f5bed3e91a5da2d87d8b22a2c89c49286b9c30f4bb3d4fe23fb0806e3cb87524a29a54540859b6a157164532daf3e9b3e6c532d2f22bcb876fdd1adb5d4ab7d1bc36dad41acb42534ad481ac058b35b1367b7866bcbabba5b7b2fb6f762ec795fbe395baff962cffbbe9c416ffc7206c13014c73b8ed6eb0886a1288e232c766331eb358654c57184c16231d918a342b5e9cba6367dadb36cfa403813d78409ebd5047d3d5f7afa7ce97127b77985b90a937515668d2ea7a4425525d54985aa4a2a95fae45cb68b72e9f10a6169d30dc3055275b7f65eec5dcfb35ebdead6de8bb1f7ddef62cffbbe9cc1f086a1f51a7e1904c3501447d885c1ac5758288e230c168bc9f4d5da7ad5b0984ca635109089a01b1464bd06990812121a1a3a7102c5ecce66d6eb0ca892413768aca490908ca1b192276032ead6282e0a14d62b8a1c239a01d6a11c239a91777d0fec164e436aa88bb448f40abc9040f0248ad525cebeef62df9ddbfa457776ff7689bae5b9e35e4c8dc2e8d3ace5f541c42fe2ba45b1d64a3defabfe32ee3b254f1f9be6a730dab429b9c3772e31a82dbeafa4a5b53cafdb292d2e5de2a65a5ce2ecba3465eeeca604b07257536e5076bdb80988f4bf36d5b241cfae4934d5b2816b532d1be06c2ae36e4a8f683982488bce0fb7ed8b32d26b32b2d6282c8fb99b66e17e79d2e9b94d52e9f37e6ddb8de1298cc359b6bda21d16009ba6fbbc5f39cfd9fce13ffd0be6c14a5a9e6699b3d6b3d9f9fb34372c7c180c0683c160397bbfae2d4f7dbfbe0f8a488b2e4022460bfad42ca6e8136534b6b2ef565f4b315a58b2d6ada5960ab96b0c9258a044639c38bba2cfa5bde466f5c7b818f68215f4a9ffab9027d17d93bcae5802df823837b31c3d39316e2f7db72ed18d7116e370cefbb2a23d623dc952ea2f5e6a0bcb53e72bdba37d850afa9cbd5ba73a24f6497718972098adcd76860dd5b6a5587313911685f9a3fdca736e8112fddd57814109fafb73c5f67267532c1ce2b8d8140b87a99dad12b54b396b3d9bfd67f0bfc72fe37b7cfad86ec3a7300f4b0c6a8bfcf65e37ef8a7c811e7d5ed1432acf1c4b2fe88ddf929e277d35c7923ffe73e9235db8e9f9eb86c8b32b1afc2a86b58421453bd49775284bf3c741ddb6dbba4c79d26795c4f7bfb70b659564d7769fb6dfa8ede7cd62b5fddd8a76d91db837cbf6bfa675d1818c7c4ab31f234b297d622f1a16e90318a929cdde4a31fe70b78dae7f7e19caa1b29797c2964e0956468383909d15285373e8c0d86cc94152848619be04555ef5aa9c3b18b4a035d9c1892e2e4c2d34b3ee62e33b07c9f220c7e6a3c70e4b4ba3fdef96b6ee5fa6bf403ae1c7fca24fd35c3259f8e0244b0f5b3217721827e482b64369be445bb0f81ae522d3f63f2dd86706d37563b0f2d4db0626ca936a54571caf3b7ab6d32e30fbac5d76a8924991ea1174a9f2d97e855c9d6e64bb05db5bd83e857c6adeb346d1a6ff9b963a7cd4dab44bdf3b8cc1591217240edd427261adb545d6d6c75fb53fb0928dcda7998f3e9f7c610c1caf888b30f6d66a2d78d25aeb5c5582010bda5f5c90868ea614ceadf65941df84d9fe77fcc0ebe5fa5aa8d6ea3d486623de0740a729ad3beeb6f885d0d94d25fa2ef1e6a9de8b228854a96dce9b6a16363a3d7c501ed66cff3bce468db454e4a69b5bdb1e36369a85105dff498de854953f0fc6170f511ee7de3f5d777a56ad1ea36e9e393c0e09a8ecfad6beec89f6b727fdea416fbed6e36c5cae98812a2db1f025a1e7419fb4eb460ebb6497966e5d0283655befcbbfb6efb2dccf5a21379dbe16a2945e2f7fe18fc2499f59b6a52935f11ef36a375edb5f68859e55a0439abb84e4a6cbf67701a35e77473241cf70126d5668d91ccd01a5f91507f5919066e55507ba067a7583a8b1a3409b1bad11c296ae608c3ee9a534fbe39697698bb6578641d9646dff3b5ed15ff89f78a3fd2bb8d2bbbcf4a896958ce854f5bd38d36c8e6c7fa1151b8fb6c7b6de44a57dacd9956adb9741b101d06916db9f45add6e6b054bb82304ef21a27db7f14728b6badf8bf9a55eca02b00a3cf8ca4450d0bef3dd2ecd244f6e9c6e50f607af8dc1113489a2b67e1a6b3702faad58e9a526a7568000546edf4a9cd20faf4703a0fe7e13c9cefd9fee74cdcb9b8b5c5aeeda2d7f653fcda0e4279d2e9e140a8ed44a751b2fd85560ca9c95f94c9fe1eaa64a32ccd6dcea6b0fd6d91ed57aeb339db95b34af9f47e37d3690f97dbeee1b68da2548d7672d36f6e7aeedaeec16f0f84c289ba2d7d7a51509ec7ea457954c6112b6f737b51d6da6dff5188e692f4be32b43bbd0bada89cbd2da2684a692735b350184f3aadee9d8aead6f6fbb552c047dfc75f591bcbb06b58cc28ccdc591d2d29352ba5d152689f3e76dd72bf4e625c9938091d6efb17b1f02a7b896a29e53dade1c7a4b62d5cd0e7e76ccbb7494427fc356aca5fe0fc85ff055afacad154fab6cf1a35353585a60f9567899232e2ac11d1a9ea3e2d0241851b5d75bbd217fe41757489d3185cd1e76cf601d5e124d054f1029cfe00e7013d92419f338ac6031a1cb8a900a7b9180ad0425b2aa079aaba4fe46bf96951addff77ddf57dff34a9a49e8e12fdcb4699b2d223a11f99af7df7ff90b9bbff0a7608d3eb500fc68abf274ed5fa716f23ed6a906dfa2477e6595bc77ec5757b73c5da7a3e5e9bb9d7ff997f64a8c0bdac25bd8ab887fa65edbff12f91afefbfec25ff8c358d0beeddbed49569871aad5d62124f499bbf6399bbd1042db2f212b6b5b5bbdf90b7f1744f0f0a2ebfaa0cf6a73779bd74a29a5b4565ad625846c5d4e47b65722319ab4d5a6ab6d684a9fd5ebcc550f95586bb448007df459fbecfae4496c2f83ab1f459f799f7aff589fee3006b7e97bf5282c2c3d585854b2fb2caac770f385bf2984beda5c5e4ea3713c4947fdb32908e4002154620c2bd6d19d7812d5127264d3ed0020519e44b582786dea00a79d27d14d8398df73999fee6badb5d6deb47d1a6475b456b4d88a32196592c96231ca148bc1609409061b47ca348ef4c87b91323189621852a6300441ca0482f4c863caf9fb28d3f7791e65f23c8c2913c6f4c8fb7be991f79632c1debe53a6d85b6bdf52264b8f484b8f9c1e59af94a98664a547941e79efb00dea9fd88de55c9ef73d80237cfc3842f0fe99c15ceab89f1fccf673f8e183a11d2d7e99589eb8b40f92b0c1177dccd75efca078411104022a6979dad023294c830b66d16e40470fe4d701dad89f36db5207f8a707f4197cefb3b5405ea923564a1501fa213f8634d5f4032dd580fe0750a9b5d63fcb1fc34d26babe7ea7a69b0d080808085b0161279bad06f44c6c35a00c66ca0f959ad6fa892cd57439a408ca1bad5bd59114d4d4aabc12072ce8c80f62b65ad0218830b54ac5e98c9394ac3e40e86a2b785173c20f5c782852ab1ffe08b3b00d4412878319ccefe519f9cc3bae573fd7a7b53a8c01d4969ee7bdf54a221adedbf7caafccf16dafe46137bed6bacc510c118b7048790fc3118bfdbdde057ab18e4123f859f77d1f56864761f9812fa3f4e8962778e6181f249b701b0cc7d781c392478a1dde1979ebc0ef011ce07b8f03fc3be27104ff47b0d4119af8fa3888f4bca75bdb36a54740e5e995f7c73bbe26cf26dc98c7dcb4f1ab80e182f67e3cbd1f5f1c7f6cf0fa70a27f72909347093e4bf8f953137a21b576fb6a439a6a4225b5b4aba39e32e81ebf31c334c0777c7ac90df08b2f8a0f7b0f34edfbe007be8ef0cf1ebbe49162cbfebce02d7584420f0a85ff3df8f7de2b242ba56873f49983ea760ce4806e4a599ce2c3fe6cc26dd04471d8279a9177f839becdc3ee26184e74f8f5cf3ec117450fbe3f7ffeecd9df3b6c06f85f7986e599a584de6152b7af09953fa8ae564594f7ddb93236ed647b0e4bc9761fe1dbdf8cd8fecaeffec723c7b73f18959849d8b9c471ffd381ffecb1bd92470a100441102c75782a5214d13aeace650794c5994b1d3cec961241fd0ff0e79d3fef5a0a69b2e5a29e6e4e4180d86a94d2ceafd4e19552f5716971102957adce0a45ac6a5fbac65cd57cd0218ecc70abfd18626393b83272abfda855045189dd978dd2227f9aad12d196e9e2c2d8f75ea4a5cfa336d49a2bd5853100197dea22572afacfb98a0c636c1f5becd75a6bdf3aaed6af93e8f571c5f8def1fb30c6f8defa38ae2daf275dede685c9b818635c31feeefd3e6cf50ca68187312dba9e9b364ef211698d92df4af13c5b9ea258bfa803f5f1fbffceb03f2bd818c5c6b27dd2a45806306a0beff17f54696673cebfbd8731963172b65433987d65ced2e2b5556c9aa585cd3ef1e7937ae59c3dcf933cef49b04a263e3f8c9ac1126de1bdb7b43d18db032a67b099acf44698379621b8e93d2e6f9090bf88f67049ad9873ce38b29b8eb1873d7f1cd8f33cafe2ecde67f7444f2cb59bdee71894c96e8a1d48ced92a91404484ae4f7ba3bd8ff1de93e049e07ba107e6fc951ee8311cd415d4ae1f5e4deddf418f31ae5f2953f899c647821d7ead3cf2d661fdd876fe5ada07c91d55d49e7406bd3f0e7af7a0770f821e87c7e8e3c3837940eea0ffc0e6ac35ae603b4d0a7a8ffd19a3d45a5c9d5ce126fe72468ff0b760a3bff17778d2073d424099bec7430ffba0c743250d730ffd50c9c2cdfb428f85c820597d1340babecc2d1079ceb6ec357956b0656507ea8ecd368691592cabd59ee4b5e2a8d7dfb197da4d7ce68df1cfeea5b6521bab552351e9f0cf3cc6f04a860e8236e7ec353e7013bf887403c5ef650d37b1073757ea31179dac15b463d621dbeeb05dbfd0db190429386207028275a447f5696ff4ac66503d7f8fbf86279d77f3a8d4bd129738aa0de8ced5ed7ebe97ccd56c6391b10f43a434e95efbd6ffca00b7ef4029a598564a29a546889466e05e6b0bbfd7dddddd7d8e789d1ed1f25e7ae46177f7aaaf303302bfe7b987e9a547b4faf05ababe7d7777a7348d48692ae6e89cf3a8a7c051051cad628e3e73385301478fa30a379afe08dbc0827bb58609a9d8d27af62ae06831cb8a64e695b1626b2020139452ea79d4a31e3d4d8a834c0401e9a0a0a0a0a01431fafe358787dbd60412b11e11eb0c584850c5f5815c988b814a8e1d20d0a40a1e9a665565d94db20dda54eb01645cc6cf2b4f1fdbfb3b8efbfbbef3fef7b9b6ef746910195ded57e0d673d738d37d661ab27db3fe5cec9368c67dfc18e9c4f6ef5dc221f821081fe8bb1ff898e82b3f084b0f2cdfd2ec506aadb5d4d24befcc5a6badd6e9159e64690e7397604a28350dce5eeb88d8febd94eef09a44f530ce997edf77bf4b1d630f7b9ef51ec334f0ae77b505e7cfc33b7cbbf1c7f0db87318d4fdf2f192b69f600ffbd185f8c6d4d3ac23f92951ee11749bff4083f487a1bbb946bf15f6db37defc31f6c862daf676148d1f7bd92be78f1bdb71cef119556a51fbaaa3efdfadfdb8a4bea41c518cfa8e508cbf85b6037a78a8ac0dc5b34c2528e251b4658aaf6491e78e3b03fba993dc9ef83611cf48047ddb5fc4a1e787b258efbb82ca911b1967934dd39c2dc463aa3bdf7a72384b98d4b1cb71c77368166e5acf56cf63fa30aa8549c6aebb790b696be510ced17da184794c9c77126ce66e6399be1f48863aeba250d2c0176fda45ddf1bcb1301bb3ea66376fdf0e8881ed5a8319ac6b19432f9aed56b8afec619ce7339c1ae46bb8e96029e54df26eed179d1f684e4e96287afc55a6bad59ba6e51145decb13997a7d633af3cdf34cb1369c9d26ed0a33d9805d96cc592ae2a90bee8baab577ab5296c8373369b8d4ee7521236375a9ec8cce9baf2860f102f8d0744ea4489e109932668700a1e08b244955315952f249e161c2553b2a27cc5a0848da6275c514bf441b3441165745bf6381db9e108ae4fd58da91b77cb900d4890c059d961b3c4438382094c4cf82a4111556cc084147186cb1d1c0b5dce20004814377a9cb890a5444b04ae254aaac8c025858c15335c5b4a30258c540f706e4481c189902f4bc80044d6047d94c4a962f594a5c5860b3c4dbc9c315244d6ae0c0f3246f6408d6972831811c6682561029544975d1c2f13a7c9132229d451c187126ecc000398342a7cf1eac1082c165de2ec00449e1dbca246d84325ca1e3e759ee4d9814b0a3e683d11e20a1c11727c210933b582116d7cf0aee024e9f34687216ba69c70032b77cb010b0523e49071c14f9624a07499418a08b12a2a505852e6ece9618cd11b2770a2d8a0d15382084e271bf1c3551f3332fc39418c102549b6ac94d17d65a0013c4e6faaa0f0406113066b882f6286f05206852186a8d3470aca11728c8069c282e785305a7d9ef6f490fbb243e4cd0e5fd674795f540862491f34527e9410b9f126cbcd095f72e0fcb9e9f0250fd51f1d96bce9b2e606510c2854b59003922266f07220d052c70bc80b5d43d019c109c9172d45dcb0c515040c373a31bc41028e9d1c3810b505d742102b46ac11a1cb098d10373d7039c20bd533e5c60b1254bab4ecec20a60b9e2d23b6ece0e15001334254e173c32e8b9c2a51585e90520218ba94d0e50f1421654cf012f364ca0dea67c7c3942c5d92c0e3e486bdc3116eda74519287ca86cba006cfee8b9d2525d87936fcd0e4aa4892322db480e4c6053b3545bc41c2e40b09973b60b29adc4a504217121b502234b1d1946407ab2ba9ab23528a58992dacc992c3126682dcf13978e44479b9c1891156b64c115265080e2b30f1937503881b1cac3036c03922464bd82608175ae8a2a6cc141b097061cb1139ae2542b05003794547eb872d50a68c10a187953f75aaa6b850889245889a394be8d49142831036f62881c706222c7c716282474313273a3369b6f8c0a97203cb9c125ab8124545c3110fcb1129455030a14a9a9dd48d1108218286ac2f3524c9b994262466bc58e0e36449d61c1b61961f2580d0e3278d91193060458bc89e365660a6444883a58b9ba923de9cd006b71444949d1f3b76704dc00ce1821e343cec50e48a0c43cce047862837396c70b871439939428849828c17295e0ce1540c526ffa08c1474b0a6ca0ca9480c6852d395439e5dcb84085490a67be6e6c202565a4c9982a4e463c2a0f7819f146cd183048ae8880d19cb0478c9ca72b344fee54153650c5cb1015b47265b44210e50299345cf8c040e40a0d49a488c0f2c2458d9597620407264a4831a9539facdce1e3b4030d3c7c19e24310281eb8c0cce0c53e8d5bbe865cc12192850d0d3044e9c3431ba81deac0001565092959659ca8497263823a3ed04152a4842272569ab22c6122e44894962f4f6c386027678f911f946cad99ea2145ca9623391031048808396278ca0151420b982552b48e0c3924b68ae8e08216154e8b8c1715d450f179618225e8d8c963240529146c046581f3a50d152b564554311264899e228a68012286a62150c8584569b3644f0f1e952f16a418d12609115bde0440cb142264f862e58725bc29499400f142c24a171b66a80ce12a82872062d05d2314cf1337666c00028395126e5420cc1162bcb0389da99292fb92f3414b0c941239ef43a48f121f6e5a40b4c0270a015288a3e5e6eae94e1d1b50d2440159a1862248d04405c9b1e112c542104fe6dc30cfe4a278c86201c90b1e1473ce9594921bbcd68c1101851b286e80f205852a3925599e0b4d39e860b36d61d9b1334401a44851192142a58b9f9ac29e2240c87953c50d57960d10ea4c4509d245880d7c9e88208d4e8f17a7257ffa8890270533564cae5290ba726201266cdeb411828812c408e087af3d3258993343550b5240bcc001d2268a0e58e8d51e27384b6e678ef08105334870f8631b82851e76371ed0650e1239405902c39e264260a452c839c1210635224c5581a20414a7218c580285a3ebcf9cad2b41d6dc5e5862c8161fbecc294187156a12344f526fa68cd0298990c1891049f070e181c99f9b1a3657308cd929a92ac2c709ae0a1f1f9618652139828f0b4ae6fc60c3c80b393471e34394355b4aa88e883f2b68e113e44917dd25797183831c3a5a5f639274708301891256a204313253e26ac81e169e54d1a9a0a30e9a266beed8e6d8e9006a4f1519323cd4a14ae104dc8e889a2a66ac68b0d1028b86155428733353e689027ae69cc94a7226cd9908b0394188177448a1cd170a1848c1814d90175ae092478415f854e132a30392ac2cde094d44984c59a2464e122a4c81a1a9881b2d39cc10853361887523849a2f2b4fa25e60f2a5469fdeb8381340acd0c64a1d343e7c21a193f373858b4bd7d5121baec3c0882e5a4720a13544093417602265668c1518de105900159e5d0978a688d1f283053453ba1eb8004122a6032c44edd19db0020b54bc232144e979c29a41a7e7c93342819b204cb09c9123074b7d5a3f57375a52777e40d3854a18a7b2819f32d8f569ae3f1be399b05f106208354ab8e401539fe60a0061a7ab873a3bc0f095ad08e29c7d9afb03bb64956ecd2b92222a869c0f79be708152a33ed450e5073450a818e1a5567f56eb53769b03a9b95cce79e95c98ece564fb8f42f9e65d2e7bd5ad9c57cee6b63fdd9bf8d52ea2fab976dd2893e5c0fad035d54eb77d64fd4c54f183f03dfefa187fc63e3e6d696e4b0cd5e47bafc4f8894b9fd6eab62d7d6bd565ad6c973c5b178cb556947e0543cb7b3bad952dadd595419ff8b66f47a23c26482ef2142959ed563a67a1388841849eedaf80ac6aa3aa764cf481f70ea0b508782fe5950f0207ee5d3b341a869b01c8d227cdc550c0120c1b75e37c11d1e5be963eddebcc71b6769ec341632f5cc47dbc6569eee55eb466715c24deb9d980eb91112f4d8d46e145e35d762fdc85b78870c2534255b7866be6d1c4b366fbb37041de4042e79c5f0be9fc9db893469fd52be7bcee1a7dd6ae3bdffb9b7af044d50ad360c5e7f55e9bfeac68b60297c564a1ef746d7fa115970592e9a696d225a90652a3d0696ea7d56491ab726677a8b6ff8aa2a7c04d0562f499895caba79bbb56378ca7d30088ece5bcabdb3e3deaf428ab1dd5028fbe9ece4ea1b89db952e4cb0f76c2646d0d11c7eb833521dca0a3b519af3ca375f46cff3b2ae933ba1e51c789d61042df1f8098d1470ce11262bf8b992e32a3a2a83895b7f54ff479af6e97ed7f7a5917e74fb8edf74e3dedf35edd2b4ba399b9a3b775cb5d4eaa14c6e4ff30e5cb84599e0981dbfe2b8aaaf983e8828e7d385a68531d8cc8b3cfd9ce39095f2178eda8c1658ba1800e3e284b60c3528ca5209cb63f0c1aa6fabd9605d29889a6e8cb6597e9e8ea67adb5d4d68c9762f0a02f65fa144024459f481bc9050f4ec7c9671003e2779096d8e81890ed8fc485ab0344164d0f16104e9c4aae560f7b377b37536bed753f52a19e94680c90e8ece7872c56a8da8b8288becdc9a2faebdbb91a735b5c61b2bcc22c59b78cd8beb1833e1daa2ae5709a43dd3087d027ddf911a75d3587a365e9eb44ee16157f98bd78d4f729bee4cc9ca3cfd9cc2901d0e873e619d9e18b9712a5b42267e12ef00ba253a612a8b4ed94453d4c2a45910000800010005314000020100a878442c158301e104390f90114800c81904878561a89c324c69118c5943106104000000000068866a07100c0293ed899b5fa46d87b8be6087853ce6a1f438fc03712828be9653b91dd2df5507a819561d2a7b5c9fe79f09d55c2cc6199e6ab98401ba5ebb91b10689dfc7270701ced8452f556c5a98fa2cfbaea1ede5b1c2ce7c1336044916e47a798fa65b2296f08f496eda95803ee0c7f926fc5b017c3933a6946616042644f60c1d08db8faf29912bfe2cec4677299470af4a8887247b3d13b29cea80f13b0f7de16e4c64699a48d5fa2b76e3e886c2a20194e78d0c33b8e7c9ef561bdcf4bb2b7c482819059f2cc507d12d51a22263c0815792920761d0e36c90c306170ce6430a3a5a34bd1e88e1fd61dae52edd8d5c0552b50abd6f55aa1bd5c83031a9d15bcdae09a4901caea5482977b39692ad5dd4cc41a282f80922c5e8074587ae25483e8b20b1f89ea6ed9c1d0598134b7bfbe4c821296be75a063cee7d2d4fae83a3bfeb619c09a96d5154aab50e281d25a73e5ba5f60182fac47419c8f1238b412c43d9842b8eb91e780b1bc3b7523f2a9b5e2159cc3397a2c1972cebee567e8ad70a6688228dcd48e65d3430944ac733b68831008aac203710d0b11a26de4c8a5242049403e080029d7db09517ade40c8570d35739e9728afa891cf0e2fbb09e4c81aa1d49c6afdd91678be009cff51cbbac391279a2ccf3b70b3a5bc541e8b0e8f041d9199310cdbcec88936c7647a1675bebcd75a5cc378b03049543a3acac87c4b7759d78a4562c5dab86a04fdb5002935726cefcddfd8fe2cd979b797e80f97c1ed6bf9a7b49d3943e97cfe14d3a4e3d3c3f4ae5f3053ce11262ad6662f0cc4def792faa4f2496b2fab289d7d5342c1c3775439d049b847b3ddd66deba3e551a400b9acedf9a4b1872a80dbf8f16a9b1e6b1e33dcdbe1ae46712428337801a6fdb7ad2423663ffcea4fd71f9c5c4e1a668b73060c33b76e90620be048d285490e69b02583c6bcb52e355a5b868b122504e1e1e448a819b729c215220481e7a39e58cce30ee476bce450855e93fbb838755bed47ed982dd1df0b8dd40e6367fad067297e45fc51941564d862cbbd1e53086e397284a5f277599d9ecb098dec668b8662de6337c957377611c01d480f877dd7a17cf460773aac5db006c2251353e843d7a0a5defc08ca014ec139b73e01f41449d072ace8c505fd918f22761cd9b2f2b825a82603472e1eed9bf4739e1f5d122d303e471d1a5e73bef5b8ee72a15edbf3fbefc8fabb257e2c22e0b041c651d46240617190005c1ec685abad281986dfed7f18adbc9b6de153055d34095ebd17fb81a372ec34c5c5e0de0f9415c8c1d5997315e8f328e144c5ce29e85be535cc61446ae308ce942de1837c1a8b764e2f948d7f9b15ccd2f521b999154e498d166c86251b9b7f5861bb5eea0f1ab28b00dff4a8ec18cbfe8fc5b7b3488b8f4e3f79a91b0bb144691f34805d9aa0caf3b7f3748541f433fcf64f1a3194b5fe93ff16080ad44d65d708c1662ca27a02e9dd3062e3692710fc912f89c60747550521dfd1f2358c5790e39bc15c5fe37bb29e5bbc92371b8fa121f790f928f71fe6069c1e71b8ff4999423935abe9571a9f3592cba2d2bd587fe5129311fcd16ae4aed361be5e708e81312011410cbf4c5c35b87a81ce37eae262cf39a23edb1ee5e34371d26b2d05fe46a56a4dee1cc2309e7134920809b8349944c74bbc80c77f62ab7b5d0471f4317fa0b6899f4b8e304e0786526e7d497b7890519efe597b0e485040ec58b4be76eb8729f721b1cc3a74fca2e6704b7669aa2bd69d8a916f7d2cf0f169361923c50c356fd7238eb63ed42a2bc1983c4bb5a30b6a4100ce5f8c1b53e807ad9298434c32078e902702b211b6ac14fb27e1aef83cdf37effda3d08153fc11b4ff2ab50ce627a83298e930a2e503bf0e91ae24a29a00ca772474dc88d0877babb3ad3dc0bb6688615c927cc8d402fbb24da0e44e9d652feed80b31fc44175054631398b87093c6dd6fc9ebeabe8c99f5fc2ac0d6e78506412c2dad1987009f9c7900eb5a05107d9123504374fbf084ec9514cdcfd2bf6d3bb88a0b7fca5e6c8129683af19d6d0c6ae5d8fa44646d03b5ee0e510ce91790386d2f3937c28febedfe4e6a280a186b291142fc921ab2cd633e42c8200cf0a8fd517fac789e733c3b11ebe9b91be3308976aa577c3c11c0b372a37c27de04a2aeeeffedb7f3f98a50bde27ae5f72189ef4422c9b68bad814705f27816f132dca9d0be24bee68da7278b8a7623e249c6a75a59e00afda335a266fcb061a5369fc1a726ae343a4d52741463126d3fe5e235e6f65a857a4684beb6c800d2cc69bed3a7aa96337d74e4d1fb7a06a1ac98d9c92eedfe1d564a159223b47c2661227c6129514d89b4a459b9fd2fb24be9cab02cd7219856c212893b24322a7b75be9f20af560e2a961b5666a8a6ff83fa01207c8b5fb6850220f868dc7f0ef7185ba946ca45617bf8149c72137499431c9dd710448d8285178ca56c9787be4cd94c950cd66800a2611ba57d74cd112160a7912b74583c60e7e44869a0eacba32b70ba8f511a6c57c15e880fc3feb328a65dd7e8d2347efa488be18edd84ede7a7f99ea923f899a052af0d1cd7748803a69f72d46ccbc1a6f80123ded0b564b4e8018b1bac10040061541083088e08e57fda6dd6d90d51190e68ae99d9da7feb17a50af13a95c85c908be0ad9c4aeb4c33a2e44ca320ca47f2e7cd2a7da78cb83eee634b111cf41e8f2c01e66ec52d6c08922aa9a739b7ee21542d0981d589fc6e63580f571950a4907c30576beff09ecd1f4a12c2b6885dda9562d64c797e4f7355e60340bb204c1ccd40b180096197afb9854dc45934f7afdd976b1026c8236cecf1887c8a00c087f5937ee0410f53817a1eeaa64781312596e3390f00842f96703564b8b714c1a7c502c606fea0100718ef6dee5e14a64dbcc2054c71f1a42124cce7d2fff40330189eb48a1515671d6fef23ab5acebbbdd969e0ae8f172df39dc11b88ea4d6e1feccc1c9d6f19f4a0ba152aa4c1db8c8733893aae2af1a45a6ec8559d1048cedf47fab28cf2ce796bbaf14d1710608a9fad7246aab5beb1847fb6123d1464e4690d043ed7004944c8e8e4a22301ac8a12824fd4a8b7185961138138a72292e1f3d41a9aa25196f4c9966d6334aaba813626ab49869fdfca98619657c53a43e515d209a08f7df49c3ea4cdedd0732103bf460be340238b4c610e2d0ea76aa8d6a1521de3a9f21c72d1594ee201cd58011cabddd2a5c7fa6f914ecc927db430e49a004315189467f82732fa1bb6b12156693cb7a92e05c3d34e0a41906d656201a8ee4bc37e4a62ee8d3fb52917ac04657472330dbde4cc0d0f016afc46e71af5b4e08964461aea26d1a9c320882c840331257f5610ce0a3c53cbec712f8138d939bbcb6c3c2a754a710dab3811492ed2ae00c50bcf683b8991acfeb483cf595a65fd430d3eab0c2da24cf91153024b5d6afe9dfc4405b536bc49ee464f5e72ee89140ff260e9f0bddeb0ef2d9175ab023a667162e86ac0545569c0190f6add9a526b8a378c3da9e409d2ac4a09965a2a2205e89cf40abb3556852bd0c2b073e73f7887f2f0773a6ef9ac5820b292ba6bb476e15ab5308e93c90cac281154cab29d3ea8650fc524d5ac0ea857c69a76edef1cf9938d1e523f0594ad8a79a37fdb482795747da6f08b35ad495792aa6453c1e191d5aaef99f45a4f17d7a8af5b6c6bac4e57a0f032d02420b940e5703fc2adda063700afeb36f5a369019508b01a85e080342e73da4369405da872d78f3d5819fc35cd87c750a0651296d3b705e6b6796d5e3e18a73272abd1f51996345bcdc0e1b5fab565c7126c6202a708b15323a7282b2a76476cc1c8148f24ba7eb4535b92a8e85a245c6ed3b0ec0de565e543a420534e664735ad9b69ad23191853ad3472525f64e90d6353f5701c1dbea705cec126d5b774a8edf557350350d931b1860069945c7dd5321115339dd3aa67a890b529023eb536d160194e0cd93e4ab095ddd53e977bc6b57e9edadb0623176a56578ccfdb2c45b9e4cc6d6a5f8781e4fa863700163577aaf287bf3aa36cf96cf1090e06754e7e8c1f183f81193252ff9371cfac1df7792d8046095691f4b45802d2a41a170f02549854b1cca9dcad41866fea480f25c3dc1d83d8487f1090cdb9fbb2fe4dc03295c4c52639fb39e07c80fdeffa4ac8bd02d362dfffc549a8bc56fce91d3f9fce66b60a882cc6948265179d5c9ba5ffab9a8691bde607d5236229cf7e64eac7df383b11423056ebce828fd3d1afd77272c3f264e39366715d71d3293b30add29cf954bec84cfc41c5b0cc2fbba74314070cc3dbeae2893a8328a94e645f90fea3c5e8970bae2f009ab85c1f9963184e735454e80460283f4b2999cee601aae8953fc5c3389286171b18787a27a35dac2fee11d0f1c06ec66ad8f9cf4cbd1a240005bc3e35d35ed4aa5dc23b44904333865bc550a01e64de01c7d95c678b9177227e2927b1a14e59de167011e68cd89017bbd2353c7f134624dc8f68c94610dcbd1869b0075155f0e115e5d653756023629474a5da783e48151ce18ce3468a9c74df0f2e75c5bd42490222ad0acc64fdba82c1d889045494045fcbcb5fd931045f59e3ca77383081556c63df68507387a79223256796b4e5463932772d9f5dba372f4dc6ca3d1b5532a799cd8d064328a471534fc9cd216e39be9920a737abad397fa4855750ac33ae7b3cb3424cc2f3824913f5b8c55d4a2845a9c31dca6dda3105e2eed63e553302e279e4f6876b4efab6bc2c2c3003e82dab162121f6cac5a1515ea7c92fed38f70759f9d41de5176605734195f7711cc73dc307b608d2375dbd594fbd190f7fe41e728e53f131b2a3b9e70c36493444b03c3df3880c0ed2c93182b7cb1cd3af0e337e18a821bfc03684735e8011994f2263ba46921c6586385a1512b30d15d3eae3e1594a463c68a82898c0989dd643fb97967dbe15058f10f741bdf258ed802c145e845c51f968bb7e67f3f615d60171972ecbce54f2350a54a3cab7db3056cc16fa34085d602ec20e677032791e01b8bfc87e4d0c31ccddd2d8485a316e10d1adfe27de7b3cb561fec6b7034fc6feae1028086b53efad1b2e0fd72c78e94645e658209b4192957f1064d4a96a5c15ed1504f4e8661fd8794dbefcd7da1189f1a5530224acb6ef322ac62b0f10bd82258fdbaba321a4e8788b92d18a1b9517fef67b36dab4cb1842eab177034944bf909cbf398a8ab54197a9690d41a092a58edc5e2008f9b185f57873d40217caf86f022238517fc370e8f531726cf77fedb8e8c56ce37d791be061bc6d70d431895687f869a8cdf5571a556ac6cf7b3f3e7a901014ae8891b352d75bf88e6f3217552d045524790458bf034b86278016bc2f9b6d214e776d9b9d054ee93bcb7c0729f0c055f4917feb3fa71ad7ba52dbccf89bb4122218b8843c1e1d2adc2ae0e14c91e2b119c93acc19c1f2758b36aab1e35a9ee584cca7468b466fc14eddae336c4387adf6d0feec1a93c7083843fe8ddbc107c177a3d8786bcf2627ef96247aad11608d2a3ebca874fbc0a4da1e6f027e227a6147594e2d5766cb6ccd344eb950edd955863364653ea8fb740c5c813b23cd043e1c1da62753a302334a58ea7342aeef36bf715d3fddab0c52be8c820a6508d4f7075f39edb987c3b3f96199ef5e909adff3f5e6a46cd6bfe94c3a28cc663d636433134f7fbe29b0948625c59abb58ec2e638f95e7efcdb4b35e73804fcdf55f256dabc5e65563ca449056830eea09c77e89b593f326d62a53a39fc64f2e3be334064036a50270ead0a328fdbcef80a9a657f7cf7ec5c040fd55762bb797539a8af7cb3c736e8909b16f583f7fb20507ce89b04a1d26b8a1b75e02e9f21173414ed90ceac077af06d547cadfa2a2ef8dd82a3366505a2e46b2a465f3dc4afbccecaaa9505e8a51080637f927c1a532810317c4b5c41cc125be50e0d7dd5dcac002b0bdd5d7abffeb8f60a7c3672863cea9374ae840a817cbbbf1cf4cd34ec879e5dc10bcf2adfafd2610bc8b5772ae8bd4292b231243f7663126f7f36a373142dd6c828ab222a220515e44df020b13dbf1946fcc54468f66e1991df09c9b26a4cd7dd3f536e7f3118400d3c68d4a9e577559936942c6f8df8d1770ccef18d3cfbfb10a8dd4e192d2778716894e7ab900da978596dc9ab8756387a280ba2496d9e0958dd49f79736949cc00de151cf5062cf0a96d37a851471e0d6b87e315921961baf0d71fb19e21f1d798acbc8cf0cb69dc68d8ead7a8ccaa4b6126a340cdb72d696ccfa76cb36d2fe90f016c30de5bec85b416be3a8c6438d3bfdc6e045024f0d1e7ce5ff2af7df634f367b0cc005220c1c7c80164f03db5ed11d956b4d03d6f57a642fec75248398995d6a6b704300a12346dfbf2b497e867480b304777da8bf908b848279fdf22df967c2e5224f0329b58c91132fa91f1875ae973906221a14221cc9fe32316620c4ef13d3ac78487296f33d47ad2a95e17360eed38b632f5c1bb5931021bedc4b9f53f7682ab690ba487f6fce72811080ca5d3fa7f96914ea14ec2638dc00cc90a7ca0bc15a95f6e8940161a9d1ed36a097cd876eb01378cf4223462cce1d37982294602996cb60c4bcdb56fa228cce7823782308e1a733d1a9b3b5db85332cd9f29c9d8cdf1de1ab8e8ba06defd1c4d3b4c34dbfce45a94e1630186e3467a2bf0eee477acd33d04b9e7b85f4560d9a2dde124475bc3da5831b81c44009cf8b266572d85d1447262b289e08b555e1a30e66e4a63bbcafa224f9ffa39d47d2eb87b38e64cc7d24019f622a46ae4dfcb5692ebf43c332cf2d13a0189bae1ac5ea0e8c51e8466d57d36448600d1212125798c7ab76cb7ee5281315109ce8ec5f781acd5f389570417467d87ab5e9d7a194e234fa69588259a07a2a57b72d1969ba3df5ab6a5cd7ba871088bbed5cf8a1b113f2f1ff0450adca4c32d49d937e43c43c219c460e4c138ac302fbb38fd15000fb257185f06c6052a1d847210978602b07dc9aaeba57e49a9cf8812bdd960693ab923d9a466a66af1a01e5730915eb2240dd46e78cee481ce7d4991e3f2e82ca47b30e76f167e6f28c2e3439f6b04c0abef516dc39aee1d156385353995b08b584fab4b09e9426127231d07c7ebab9e38244c7ff579c02ab9964a769b49417f95a9395b3326f29a3ace2dae2a7436cb68eb3c1af14a51714aba71b1cf32f8f86d83874143c29d03ee93fc06c17133f8e5c865a7384712517c0e68003b379ba349953f2b9ef38f2ff5e6f84e5b50be7867326a9bef68b504c7a18101972939b4427e6012d7a21a79e2b6f8559ee3410dba5001174ab18e05af7b992175131a92d768631dfdb477ea8abbd0854fe26e5078f5a943bee104f87f99da0a53adfb98f1cb698e0ab7fe4f1f8c129d5cd87afbabeb2fefdef7a1b1c4b28a8d81c0309aa1c5b27601912501e6f99ccf0cda59b51b325e178afc802c29c7b2a2331af7a2e66617c43e91bdd7a12b022679f966fd71cfdc6f2e0d50600affbeb9d9b57186feb1694ff16b4c8602221fbdc9472de885986074907e813060cf1a7a86646eafdc9ecfa1295f99d374689d2376f81a2389da2fc28f660a74e96830e8b85ea2b97d3d748f1e1d455cc27a683a81ef492e49fb468b5647e7ab8caaa5d884825ed8c97e018617036318ab49e7fdcb611937e1bd2bfc9167c6b250126987bec8c01eb19ed2bc9137f9bd7bfbcb78e72eb7687cab48f72df5748885124d1a231ad281be19167d1c6798849e32ff58fbd1daab050915fc2da7e80b0b74b4dd71c0ecc604fe4e092d673624649239b31d97304f29c5f1608520f09b8a27add56e1a4cdb825d053c0d85ca6b9f6f63b476af061ed22e29496bbab605486acf102522090d2b7fb7990cd2e23f40163bff5f9cb040bc779b85acfab09399fc8aaff494ae1dfa57a7356f98e7f929f17a7b0cba37c83d4f6d8c9f6cbc4a688d7fc5c98912c8ceb16d20ff0562e5fc6db66c7c4266db30c7dab25ed3c36a62427d6dc80b35e88ef2c44ef32664c5c8319432d7f90c8eaa6ed7ddb3e5a6eefeb60558bb0e2f3c23c4b2bcbb1099d12bb421d76d6d9299cd63210834632e8bebcab210b2523091b56b68e673510a86518e87555e953e273c1fba0da6d09248d61dd6ee6277cf181d2a44c82702215bc215c4b12a6e498936421d5c0a94c28fe9a43829bc2632c91571f00dd1198726c272a0b2578c2d922a1d65f3f01805c113447d81152ec3015ba9e1d0fbed6a9e0769536f81f9ff940d2a3eaf80158b23e87dba34a1c96617015bee56cdd86ffe042c3441e49740e9ff704efcd9e07ef1c882cb4f510cd20720b6da1bcea32c2bb1660e49137d62eaa1e82ed4cc68866de405c12f6326b15bf058a97176665d6904684c149e024842d08838795b1f2c2b9ed0c870d84b23daa7d107220f8b2baf98a3cf7e5a4bf05c9c375dae76cb86e689a760585ee17982f72294d45e8b910524c82b5ac1870868159e58b468576135eaef9112aaba7bdd138c4a282c24c4d6461aab9aadbe2af7be416cbb1604c3ebaebdf9e9561981a31082907be7927007e56f4ea0c1ed0b48ec2537abb90291056f2219e9d482da35527d69e4bdfebab8a695b292f0e0b74bed81764dbdaa097491d9e0a789e9b9d098b77b2ca684b095a4884d0e640bfa9b85a93262736917045753305384cbd7c2dc96ed39603f4a8019d9894856e28d46156390f3976d1f8850d4b58159be2712bf8dd77415ddd61df4ffc3d21f478e790812b02b4e7dda43c0e60e8433f5c89e6c48600f64fcde808cc17f3eb97edf1d53f633ff5e260122f7b146727ec4730459908d84a5e69144a7657055f4c09f8b3673b5422173689e6e1747f72683250c4478074a6585272e59e5f8e3d06528e4f1b742bbf8e64edb68d33964442a92f63d4adb6004a68a711f9d6a16496aa04d08c5c911285b785ee371dce0825f4152f9c6c4c515608093ff5490b5fd5b128438ae5d4d09c39e4f025ae9c69433b8cc292ef831e122e4b7d48389fee4caf5b31fff04d18241479a9aec54dfa28b3d81efb960ffa2718dbcf42ed696faa08513ac1d8261b51331a0be62109f81f4bf6ead296aafdd24bf0ee9ad7ba21f52a9b18bd5974669684ceb7a2b8f6bbf58b9c1af0062febae782284d7963f8a509a854b520b931f8505f7ccefab7c83281e84239b6d0052e78ab2a92c171e7754f9f5a4c88b69e89a24a77abe9242831d94b5fc90a49ac0d4dee2106398a6782a38734f828b32188c03db7c4ec14a65b3ad8f9eac97623a2aa8bcdcafa82edc32aca002835fa2d377185093a6976ac7026fc5ce7899358594afe1ed5cd281afa534f72c46940314632916908d12588f5fe46ad917da775e32f1c862c8ad45463600a464c257c20ffb3326665093f3add3d018210344ce57c1764dc3490ed4eac6924d6521fcfbe09abde9cebe58a3bd133c1dc1b787363f5927b39f93ad9fdebea52524c7df95ce93cec5d1cbe5df269af779b18838474efc3d7dd86f73300833232912ded525acf39839e6d15f64f06a0b2ee196fef7c3e8e56ab899944f50b40841db255b76c418f758fbb036d8ecb1faa5874f4936a3a76f21579681c29be718238934ef0a3e019814a174c42e899c7c34fae5c5b681713e8ec24313724f880c0c65fa3584668f6ce3e8480d8fa02adc449f31762cc1c43506c5cab71e5fb0280f48629d35093b480ea2961030a76163e00c264053098628be9f86ab32fcfc6d87245d1c641abb18d9a3f2c8b239caa013aa07ac244134eba0347262d307a0022bc8d6652411699c1a00690e08a7498e3eb5f77b6f52b8ed0b6649b49e71abb5dafb5c7e7dc2d403fc5cb8d7feaf5e5f2fe564f832a3e04175e41df9b9bbdca8d4696e5287e6de33b86ee92d5938c6e160eb56f684cad57a2e7860cc1d33b554cb5df92197f45ba240896de3e53362acc0bb9deb662a1cf73b8653a4d4a73b8b9823d5c6ac2acc275d6d0fc5c56228719fbf1b972f2f040fa793a78d532cc73e9889bd97014fd488a801483da7fa081a691dda23892e787cc5ea7077d933f5d120acefd10e97405c3777ab30f62f5b5aba3afd1f91444e3b0f6ee2040e5761ac2f6f8693700a16f589c75fcb02db6b787ee3a9d96cd4c2732d6987d9a3913f712dd185095f20436d49291474a22187b1669830d1c61c2c1d15f538f2fee4fa0fafde6d07740e150e795ec55819f7adacec7995742fe397e3b7f5f506059a00722c86db5a9147a3d79d6cf421802cc3f475c7cc33f977d6856b70acbcd9f6dd44dc09ccb807115f44b5386cba9fddb81b3184e644e2f98db0c7a3234f80efee3502c3427be286134f1e168ac8908e9480a98613ca6177896d5becefe406da87dd7ceee004bfdbcb3b31f22b1f08d954f517b14d40f16e847ca2404d83b58ef708514d83377414006c3b31ed2c4863540661eb61e9fbd17fd44f887d918068ef24f282e4f00860b69f27f94bc086718c74af26e29474e145bb1bfd34062edac4a6f98cb6d14809141b4caa842e55a96e3d3cf531ee382dc0fc248f92ac7add55c558cd0454358ae2b8b14c7fa288a73b604149f07da660cbfcffd374aae9887fa45eb24ffe13a8555aa427bc6c9ce24074c9ebabf640b780a4ed4a41dd524ec96d7b9ae7d594dee788744c58b9c38186a402c1edf7eb31177f46c1bc72b3314a8382172fc70f71ba9241b73203b3843e96e6d1cc56af5dd0f9d0e67ed50566b43a44d1a83452d805fba5c712d104ed10c64cdfcc0342ae9c2a68f49402aa3ef89b00b17f026fc45f784edcdc104a52e8b90943a2840eb067d96471b4d9c49da532c6171a9706a9ef2f94441b6debb794ad98d415788c093ec658c5570640324d361403103b1ee9868da36fb575ef26cba00316b058c0b806854484a2a89fc89bb3407d434001fa169b3baef861867287a44333d30008dbee85ae4283fb975e03ca4e0d0096187e68522d23041255aeae14d9bf577901d28dfc95cc78c91bf8861e2e2630d545ec598bbadc88ed5424c28a3571e5faaac383ee736ccc2cf301b115317181655804ecd730e4374797abe8dbf1fdd5aa4b9fcefb2936f86eee65d12ccb7a99facbfdb6370b9007cbd9f21be60ee367d33950719e6ca321f9682a0b934e85d0af489f0981837ca4274990bf142b1f6415e1a8c2e573c0513cdf5918ab1247e56c1325e670b85613781dc446028d0a541ffea9efad700268e88b309baea1fe60ed018288fb9a46e9740c9fc6113de585b19b575cb98f6e1f256fe18818d4b3f2e26e84dc7b5f8a8f271c54a460f4937a9fe04136a70cd2e21db5edb88ccdd7b91f88a6d213aa360490d333f79755948b6b4cbad40c19f502c2dc851157cbc33e6d8c0108a4702d60f3fcae3cf8108340dbe0770fc09f10b022ded9a0c646cea8427903ec38540fa5160ac99a4052124b0d0adc090f61e4e1a42dfd850f8914d926d3f3462e854820b2e7fdea9d30325a4dbe80578176f946880c65abe118b3447c1c9a580c8533d2af7ddb3d091c582ba86452d887c25d8cc10a6ff15ca7a9b2aee1df554ba657e81b53ccc07f404f396178eac18da74e3474f95141a1b1da5ec812f34548682b239dbe085f98b725444c65826c86bcf522301dfac9596293648a97d3f4e97321d162b14d01f97aac08859ce4d6c5cdef09fa4f35dad7a45a49e16d270e1aed18fe4711680d6ba7d1622b4d4adbc3323a68416c6ff6a000cf9d0d350378f6ab37017a0fc3139fd4709a39431348ef454fe579791161990bc55bf260866acd3e76069f6dc2f4a4dad70b1577799f294ebd12f4340012e1bdd61f46ccfab4a0006c11789747cc56ded7afce0f1f84a9c1cf0545d5cad8a5ba209749f22562c8b9f38c9f7f61c8fc2ff46c8bfd9d9ea9ea3b2dfd0a0b833f4c6396f950daf85407014c63656448089dedcf0864da99071ab681ea6ec5299b6f451b35a3356c8a0375e28bb58bd15f60f5d37568afbba048811f2ad52d2eb362386c535ca510c20a1f81373b744b29f80864be2ff16ad4205b60f0134f79343659fda65fd95a2d68560e0bd2dd4af9679eb2da8cd724cb6c456c332be37f2e8dfd0125f4ba2ca669891bca848227255df1cc2c04e6b89ad707c5e1b2ee62aef5d35e09933561d087273d8f2d68d96ee3159d3573938a38ee3ad42895b77c140e387de559aaf4181eb26c67dfa1cabaffe2a4c922d4814c0729e83ebecd7e37c3e0c32dda1d4c6d4dac510c5a3cb94a65b4d5eaf3ab48298e443e34511767783456d6bebc32c0b397b38a600b07c4a8f578d4983fd7d3533c569e2e0c85b11cc08b98eacc0a0c89af423173a5ee44407fc5bb68ef30e9084b361f6a8553e505bdd0c8cb079936b3945e48f686f2428101142be63548b9c3729543485c7a10098efbc059cdda9052609b07c513cc93ddabf8782465734685a6d319092f4fe80b107336bd3ac521cb5731b3708ced5ded4272822663e7d28a520c7a417869e3fcb9ffd9f763fae715e6118f999bc8c650d5e42f85c2b92748828481b809442f741aca1334293f29308a15cdb0a1d089c3c457677a1c15f9082519fce785898efcb14ea85b0b483c8a315404cc8631e3d5a26cc8319b7385bda59b9258abbd25bc621f66d06c357191d6afa87ae22fe2d938b5442ae72f40d4d501dc989a97eb8057be41d5b0c794aadec173078fe48461c1ed08f46796267e551484df366497316864db6405320286de1d25e678e5aca70efc198a07ec0bfa5fe8529f36a44489dbca491db919626f32e8197d03499bf41ede1571d032239e020dd15de620e36697543158863a3e5ccc57331473de64278d852dbf0bbbfe6a4e9f03ea3658d6625552edac869b80c5f47fe136969d2a99c890904b8c441fd889c6e405e44b99882d58b4675fdf1371efd3dbcb445cfb6b1b7c1519f4d462e92c1289437282c262999f22c562376310c473ac76beb94be7de467f0a088c003aacbca25e314421e50714dc8a13d5ffe55ef300252ef14de2c337cc3b19b650a4e87dbb4d2b28d5776754308aeed5a0174913b3500e98785025aa8b38860318b0f0e522f7d6efe54e33314b63db66f631eecef47d8cf9944f3a14d988793a0c764cfd3a920441e37d2523df11bd48b5ad9ca9e6a75c059875821a6586d797096aa1e8b51005236a3d8a92a6402a8cefcfa5515989b6c9aaa37c1e1457bff963407ddaa3fe0e93a466956e7aae3f4e1abc0b62560ff1fab4773388523e57d4bc54ac86bd8a6aad0c3e730b1ba140f34b1eaa1d5200b76522724b50120f30840ed346aac4147f52748f287e4f361d0a6cd651f43be418f6d09c8931fb97b4a3c268d668c13db1cd37866ce4f63026254be4c972b8d545d66e9b165979f901d9c800c995facc899b1e0a8ffa7eb119af58b0d9f0291a5dfd9797c4a0e855285e8fd1f3362d1e2a59a6b55d35007be1b9d19c585f4fbc0e3126e4ffb5faee8a955c38bb1fb1e0f5eff0f2868ad95ac40758310abe054be014e6ff95451e0b1a5282b3c244447e911e91b017b6b3e63a274d41a3797024b03aee6f6d1552626ed6178bf7539ff9ee6b6d16cca12283ff9268c93a269cfe6dfe0fe42b0f13c55b8e65004a3091c13c8a997ea47c5b28a2e591ab484770dd25dd7daf7f10dfdc5e1b94047ba097e8830aec009a467d07d45fc7e9bae25224994b502e50a2942d8ea26c2e23b3d77823b58788750eace71e8623f202c3bca507b922626767e0ed54735e13a5a9d06636bfdc544e41baea23f78a836ac38d8fc68c2e68df951a8e6b220f740c502206f15239ef07e8e2a334988148f5fca2e31bcae505d4ef968d3ff32230d9e460236c006283581a254bdab603ffeef5b604f0de8802551b857e7dd4f7cbeaf4625bf8160f8293a4afad2c7fde4b2bfdf9805e9afb7e74192c4ac9c62dbb5c41c0c42a7733b0789f1f295d5e51e4bf72e3f0a16b4b468fc5499d1405c4324d83c8767466bdc426a0bfa2c3f04d5f1a165124d957e6a4a957f3fceedd46b06d17aa2ee9dcf21c3c570da5eb06bd1dfb818a8824f547c3aa07a7370be44d960c78b027295e4faa86467474c6ad3d3da1968b3bb386c3d940c51890869f827f22bc494732a3c9ac28a0aa4b4a1059923f58d7d652ca69854465442058c8d6d313adab4f8012b5886d362f4b20af051fc4f148408168817e5fc652a59cf06e305503f69275ec4514e63b67581b62738c4e7210be9599ce10517396453ce9c9c645edc4a7b7671464f0f445db667340642ed152649035398165986b06bb0e0de92fa4980511891a88cce8ba3023206b520637c0220a28aec10603ca49f44229108cc310281f4c794d8c230f67a8a26af4a97c48eaeae2bbccd208aaad47d17ee3fc3fc6820f930b2d08b24ff8f85313261b9387febec8df40e8581bfaa1a4b37ba011a6ff5c7dad37356ba7d54e30e6a12d05c8748c30911cf181d466e68d08eb6552cdc3cbea3d41da6207111553b552836ed0895244f7a8e59873c51c94fd64ec05dbb2d832b36cea55218bbfbd6e9d6c5cb60b1bb53ee7b31da9399bb726a7a4539022aec7e6ef702161aa1a8d353272b6e5e2c53e7b5848fc10c0332e0998748b8f96de056e0a8343455ae08495445a9ea3497a6947c1c44b8b55c59f181ca32bbf5ac977a4e3f8859bba9e8ee848f98b429f1e87f9bf5d4c633d13b5d66805264983806d198bad46408499d6039e32890a03d1525dae4d2b41005a9478d652f8887c8c8876c28f5430527747c9b60e367a67ef173321035e5fb5ac0fd7f3f1fe550a12db7cc11586895dfea22addc09eac023948733a18daea1b12210260d82a5e050b8adf19e1952b035a726255660cf1c2e537f10f31947c5c3b8ca425135d8c9a7d069d5e6113b95bb0e4b8696d189725cd37ad1a7fefe0453fc961c43c4c3152c3bf121e93aaa27368af0c9e0f6626ee522fe29c9c31be7b24e055efb904c06de4d902788d22fd597ec1c6f0f799ed3d3c306dc851cf6a820eae3cf9cdaf7a340a5b829a073b9e667961917a274ccc64c29814eb2fb797a4a78cdca731968e8bb74d737b1a0ae757585113f401cf481d14327c9a47bbd009514a1f54e489fc1c06832c95274986ce4318a85727bd2d2c801cef0e3d9821d9692c9571c7c93ed8bd5b25b66f37e5676207d2ec25beddee3e00ca03186a2329b0b36a2a1822cc4aa2cbc20dd6dd02beccd88c64964d7c087b9755b8ef7b46d143401fa452b2e48c93a4b3024ba23c547f83e9760ecc9b32fc9dce84c0749aae7e311f8439899b66689adfdfe6b90916035beada0719357a783083b594ef2f106742a4c9b7066630293ef3ee429fac61fa1e56b80f5de1b8d87c608f73e39956d33746f635f0b06fae20779982c22cfbc658792e6218632a86b88d742bcdd943283db872de510b2524d41d41eddb30e8c554af26fc325fc328d7eaf3582fddfd8699afdc492d67eb5388cde028af3f11b266bc2f16b376b825dea1b12504df79f355d73ddf95b2b6faa791daeaeea72e96741d9545ad722cfc7735f3ff43bfb00981b85d95fe422314fc4ee9c0d1436c638c7092759c7414ff3f621278d761fd26900db0b0c1c81c31f825b30c05717a00e453b90f46d27ad9611b425804e35b8cc6a5aa945e523097cedde937014d0639e067ca39b49fa6db5405b0114e19b57eb41f00fa530a576a27646f14956e131930b0746d3eb30d7991e6c00d4eea35721f9d487156dd72b46ef938efcf671f23af525064d7db14f0c7b0eb55d6291c8a7af25f048b28b280ec182d3306beda17e27140f3d97990306247fd9708e2c784af4d23ab07ae50e3f6171ce89f9c112a707c18f0d0031f2bd183190f8ad15d5b8aff87397b458230f7716ba765cd59355fd48ed9a83e4223cdf5593536f36a22801e5ac66976e0bc2201b4307c283eda31de2a4e766ea41a0ec24182b65b00d85bb70fb6fde2fe18b66c0a6107c584e069a5d2299bd4762f26c69bd46eb508e7e048a314089dff082ef12c5b665c9320a4f646bea134b40bd62de82ee7b7c6cb6f0a3105f805c406dc4ee6dc1d69a574ea079d58044f7317d68eb596e791f88d21e4be647334d95f2e3f6f0782d3402f0dd28b066e35d5eb796a064eef403253534930bd081669651f336d02317fcae3b9274899d810eea0fa10827b6ee49f30b5dca556c30de0d86980d1578d1d7bdd3583d5ec69a115913f904a925598df195add396d62381fc222198d7d1b25af5fdb6ae1641285129de9549c5850083304b91d4d83ace21c07e25db7455d4e5ef650c212ce6f3e27bcbbbad0d08eae288ed29c1b176d76b340712a825f0d0bb012e1861468d4ecece9114209cdb28ac4f21ec2ef09fca3e64ea060fa3043e764611e7fdbf6f40984485ef10c2e05257e7c33f624c310bd77ba058f108878e1c7638d1e2ff1deb6ce50d5c771f3168729fa3bb2a90cc33c7a1560340cd0a5bdc69cf6723aa5726fc7727386748f94c71f21764eadce8449524ed849975c27db335c8f412f6039bd74b2d5ac33cd2b91ade5182c1e66b84cac155113ea784dc54a48d1d9c77a4d5f3eac5eccab494cd6a5986c67775764e563d8723fc1d8c6a030161b4e410827337ae47bfc448e33ffc35a8c578351bd027cbc7f172c4a91d79db4ee63335a0123fd4348140459a8df6ac1ee728aa7af9cf33b1deb9204a5726e07bc4dc6761f4a3a62b7a4403f2c918e70383a10b1fe2c6b0f95a817f5c7c6029736c3ef35ab2aaa70adbd5ffd2884e7702fc1382a4fb1bad5973b3a33db5f8a8848f8b3b8e8370e6dee0f3e36b476be9a366293bcb1f38e5752831fb5b35b0dd70c9a67a8e55c6b31bc80abba06a2b52cd27ba8841e239ab665161624b8f2ad613e6160acddcbfea09057023fc87125efede61d3f17ff55fd4f20e86b80ab0abe9549ffe8850fa97eb56066a5d0c87ce55db4e97624d04c80ef0007d7127c66a4199b0f0c9d502e2a1e02664f82fcbe5d7ed4f1b61428b2fc943bdb838d5681779ec318a41f90427ca2535534e40c913e5f88dc801777cf49d8a6cff4a7ad7d64bc0108d20949e0e8b38fa1a9e8f525f54a25e8cf7144b7fe1e9373dc7833c3fa36d75ba6bf9f98faeccb47a6f898137563b70be390084139a88647faddd3b1ae983f450f69963a09b11a9ab24ebee9ea7626fe9a1403378cbe66e8ed8fd89a8973942fa3facccf640ba707c62a74547b2fa3219d1d719c35c447735c1b17ee32af54f84ada0f43b1fc75db790bd376208167e7c6b4fae36f7d35c0e8ef1bc865feef9f1c6c5c0845ac25604523e6120c0a0a0ace96a37e16182767b2de7731398ce8b9ea3e71d0d6ef448fb76dd033d57c32438e968159f6c7a4ae1bcf391f0905618c2dc0ca616f29f27bf12ecc9b9c34db97905d2300cb1f41c797095cc04ea876213914edc1c181b495263bd79111f88a692af0be3cbbdc27d87fd13d50a8aa10096d018c730d2792bcb4950d83065d4e8ac71416e0bedca6df1619fe92fa6703b54fcea409e13190eeb8793f6b7e51d18364ee65a3f1abc2ac200988fbcac149368d9cada14021d9323b5b4146d4d2911ff541a214d3a9ec8a47f9318289e62c4f50dd03909d630a83f5c972615de01796da0c6e891748e46fb1ba7b21aaab99762131d35be9ecc6cfe4ea2567de01b5059ebef108980afcfa6b9886a9c0cd5f58c35c76aa15a84d2d1ee7e3cb89640784e221c718e7727a8ddfd7634495705eb2163483866c835f1da7dbb26be43c78dac81b522a33dae274182363beb1ddf8f34254723e38d5c2714dc03baf7dc39ea6d5e712d72b2ccd688f0c17340a2d884acd0eec85995074923a94269424c21ac960de7209ba92e66d22e7a1903906753fcc72a5651b7f305e8251ff1cc5d26cf28c7904600e19db9a0770fa1847bc8b46c284778f92876572414e3bf4b8238f26d4a3989613a37324746eaef9490ac5a79acd3b07bfe1b54e595905e8e8d6210794301fd1029c1a2117521cf24960d06004033123f8340e379f1efd1a6128ca7490718794c8b843bd0ad2493769d61eaf500b4e4595f3399f175bfcd4074370ba1b66aa7ae06a01f5a93929024e5013b13c51be99bc0dfcae6905ce5d26e4693182bb919913c708db2b50c78922b357e79d17e8f511995661d3944f860040e839d79947b01cfb02fb61685c96bfc98e1c1179155a460279963bd80797c0b3020fc2c8949218a9f84cc5b6745e177efaa3b0dd7373d81d6e86c93501a24a9381b7a7af122303a633284635f9004fb6966857d197473561541d52df0e11440b1b2c98d36fb3ea57cbb60223c5ec994e96fc1e1f62bdab25ab18506e8051494e8690cc55212b453869806eb49fdbd3c10f53676bf19789a7d16176dad5064be4998ace2bcf4086beea38e37acc4103eeb5dfdc977d93020c8635f8b2ecc2f5331e328d925b424e3aa7c421263ebda75ee65d68133c8ecad4b4ca7c8bd679404e676b43054020bbe98c897d040816d8640c235e1bd0a850615318a01ec1010f60e7a5f4916c0c68aed2eb622b1d3e80e97599e334cac4fb4c60f68fb30e7e8234e33cf9bdc3e3d8a0adef30821eacbe9b6585bb8e6da085aa2439a3ce9c23a048d9d2040bf0d56c7ac01461fd7decd5d122b9ffdc247d8c895c1dd3aee9b1d7f9dc2457688e816806a732a9a89835027fb85c2a439888d357f500fc900ae4b025636fccdb164b775ad9df4634b1d80ccc98e8467334c7b6437c8031ccc81afefb5e4c72acd4970b72a7493e65cc482fb10cb646ec33fcfbeb3c3154a4dff79b8ee65163f10a0a49cbf963389986cf2a20e9c88ac35bd1c561dc606b60941560045b9b636075622e3e62d716ad39249c46bba14553ba2cd3636668fd7ff6023dbcf92555b90c35dac7eea35b798513aab8a545cdd11211d0c963e724c9a215108504d95d74a5da1ece3201250b67c97d8451cb6c16856fe33cd7e169635dab03c8aaa4c38cd25d4a32efdd480ce27a3c23e3d301f848735f802ae1d1bcb961ba29cf318853e9bd988f85ddeadddb8404a8b4eb62c22cb0cafd38a394abef4e935098acd1f7d7ad5ab60c3ae3c334346bf4b1f42e4b2c5e6d7dab0f04640f988411f22e40815f6d9c779f0a6fee2fb20f4ddf5fd04bbfb104ca249c2c0da58f8f72aaff7c10ffcf0ec567e8a183db584c15599ee02d520b38a91faa48378f78ff94752b9da107b2036b9455416a21420ad2dc79fb86a1d8af8aa4580d05954f28782c1244fbae0eca6f51fcab4bd3a4737e00492fbc7a97548372bb4ceca2d973419dda5b19456dd2ee0e43d58e464f7cf4f07aafdc752fc63d434bb3f84d6821d73b2328c3864e9a709445698d6adb7afe4b5f9de1ebc8cbe39ae1090488ee1c1ff49de8587f495fbe8af114e8288aece73c691f730846a3beb68b8c120113e741bb09f3f01f29e9cf43b11cf43592e8d250075eb65bce3b3d8ea7b0f259deb52a352bef86a6bc2cc842ec58b5b6a24c7247d868e1de48d3270054f7b219537f901ba354f63f99d7fe0a8f0a7e004233f56369b253744db0e7f578e1469f01ffbc06789e987c20a9fd27f2d162e007d8b75debe8a462248e454f4e30d2bf01ee1d45cd02975a278d283aa64c3a22024ca63493f9925105aafcaf58a024dac84d2ddc8d03635a81f9e408ea3c44a1a07645a5f4d434e3714aec05395aec3504b8a6ba9a700ce749b11034058cf6105348605906c64c05b92d5244447616f8f92e634699954b5ff89a7f3db25f8748bfc0080581302a5bfedff3cf94bd3f8fedfa9c0693606e7b3cf054057059292fccd343c6a1e1fd3dbfd44976700249408f77486d53408a3d94400815ece9dd28da9f5761b90365a885f23425111688a34e86694c5450e85cf164f873a0cc8f0e6a477a1fd4f1c3a6c163e894aa33666aab85e4ae228b38a6bcd8d246e3b5373b21f49a0785d988e4f88f19a57b03b6ba491aaf0c2a9a82ba2dd781187ae2a5423443387c74afdf8430b993216b350f2daf9fbc02b75b0f4abc5b75f20a4e1c70b9218be10795ca591ab6c555c48e4db23fd72d042de8b8d7391a1dbd799dbffde01ee482db89f3b21104a181224a2183fe6bba824d19e5e56d71ed4146994123056522ba43fa06603053130d54c510f693dfc9df3bde8582eb624becefa9f90671d734193841195fc6763ba4531541ba670b2d7fb8b377049dd63b8a2f4da6a4df825c4ee395f567b305289e766e061e1592254f5b8e64a32e5fa74d1e587494735ea38e4b50d3ead22fb9141b6de6278e7edbd2c983d394954a15b7e7513b96ae4d8c654803c9ec509f21948a2699726366fb38ccfd5aec05c8908079800cfeddacd2f16a21d4debda295e9e7310c53e85463fa21f947612e2973de14301dda8a156611fe45a45bdea8146771dc81268104476e4e26386b02bdbcb5cbffe94a198780e342c9adec3a888de0c2d95e68864b270f60347113b45a08e5bd64869cd7fce95206b6c24d20517543805364a1b3ace9ccf0e134605b784e567320831266c2b154983954dfff7c5aed42a2da1e440619fd043ccbef5078e56e2560e0b08bbf0618f455d72a3661738f09cdba8968b7254ef9825749b54cbc6c577e951f651ea00867fd5b51f0b1b7c2c5c1298497b5cfe1bece5a25e061eafc3c21fb44ac486e51f2a07c28c86cb19310d69fb203beba7b5d67369281745a0ce63d3a1e69aa0e19aae30c3431e52753980f932585670eb196a1dd32a2ec1357cda02d15e0bc4ee9046b8ef64f8e4fa9ae933e99a504d62f87cb1f064869f8454d409908910be18c92467b0b85bc4cb88ce171b648b60e920265ea0d9503cf28a21643fe7f01b466607200c41b20b78208fd872725b2f290a4394365201ffce04ce51457d8f597fc65b32afa0f863cdcfcc44bab796a2f8a50cd99c78d0bd6e56685179aef2d08adaf9a0f14f37bc4978e5d5eae0c716429878998d1a0f4d05eb77365756362062e1c3b399e2c8f70a1fc15b7149684be39a7f91ac25e10d02cdc7d9ca62f4dfd27bd1a4a08d1c7140d14501e48bce06573186008a73549b70d6d76a4b97845c322065c4471cd397ca8599665824c1aee1fa4c6a991a0ea8bf10927e87b06c58488df63b5c908fcfb548c9fab41cbe2ca8d8dff7dd774f701e43ea235ccee5c3b46594dcbfab627c1d1a4f3794e5dc0fea3fa015e56828d4620c55eb7008e441318aaa7b08369f38a729627caa3b29e127c3fe60ff42b25a255236ada0ee793da3f85b373deed7a40849294991383a71d6ea7ad4bbc60dd4b3a2550a076b6574ed5c92463cde6603a24fa0ef801b96de591d67f17c64810bdde867d568624cc8996cfb0f789d9cfa00e36361782fb03f41f8655c52f27c250371c6296cf253fc38aa6482a5421302e1a61d33c274e75fa3465b3d2c82fc73d5e13a29d0bf41e81113307f0805a2114500cd3a1322cbabdf926ff782f3c1f3fdc8776e554a67688ea266f875ca5cd67117a6925b87a42ca268820f17b723806e39d84a7d3bee1039fc7411a4d68fa12c28504627bcbd972face4321a0d0a16a10c8f106611b0bcabc8b827f87d4cdb1c5186cdcca5eaa9e4d88992806d183c83a609ca0cb808dc97c045b9e3650eb3f97db11d765870f2f7aafd8965120be1a527c412759873cbcc18e422832dcd251df298aeb532cdd6937b9df7015f59ede79b4c6be721014bce3907cb8a213ed6c11f5a20d6d1c9c01e70c1250b637a43e316861e89e784519816bbb591409604b4f2a6c05c41b8c7d00ba9e7498aa2e81a97e1a3e61fd0e664a8a9882b1393d52f2d5cd74c6ebc536f3cc88ff6c9c26ca1cdf373b26e1ba808d55fb9032d9bcfc3265590b76450975a7545a4f6a9910880f489f19c5e22d514c6309daf4fd5bb99fc1ee435e6d4825227938d0d44c8ed84181cdcd64fc619b8078e7efa1b41f867565243e7a4df6b848c45c7463bc9005a555e36b6758b989b0de2215ddd522711feff2ecd1b9d1976b1136beff1acc972832bb32fd3a251a7c664c53bea97977c603702f52a97e76e709ef7a907cb6c3df473871c5f2198816b8c49113d8625dd2b29d2aeddd3098feae5e123b6b0427d5182061f20a419408c5a270d9c20f348fcbfe757fd7e1cd649f00b952ddb1b689b02ca0529d9201b45595bd5bc74096642b98511887dbdea458fbcb4f17a0331d05210fb0db8fda2665cf8fe9d3b025c9ef5cba92c1ee1c2f1bbf658466ff92fb94a10e573606dca60fb9a9d48e19079bc4973af61bcefad26e1f0af450b5a20f1bbef02dcc2243a384f9c2b9a0b8a16d8eee11d16a75d90b071a1ef36e87b24ce2b176f039f141fd5fc6ec3bd8c5d5fc58080b7ce5f4abeff2e64302f533589998b70318d1a1757c81a96cc4f15001a9db05c7969847173e41528652ec5bdb8aa53f846c1eb1a12620b7919f531dec9d6ade6827cb385ed50dd0f4b86b5441a835d1baed5c427991a17e4d55c74b35a8e1a33e804ef1c244f9d3cf3f7bf8800d792c7a01c53c0717ab76fac58de4d88ae027d222e6ed9896c36b3813dc52f78f011ece44f2eda347cfe021d5f81da141073e21910383f1dda86ef1f670a6d6fb9ba22ac7cc2c3c574356e28ca030e3b47771f8278cf6839420bbe1b36563313d400a68ee2b1977ad9ff6a3c462a53bc5c23372b9faa7fa51778dc557b6fd3b5f7a9f3fbefe91bdd8142edbbbda36c3904a44a71ffb9c85e06f99fd5847411e02a0875b4ca20cc73b0c402b7466e99aa05cb36f42102753802ed41fee5d20850bcbcdd2a1e38b1b179c06ff560bf6a04286c1cb1fb9e659abe27de4d7b2d77df57f6941601647e61a9cb45623dc81ae6d8acf1b32c331074acf43d4f00f8d557c32348e5af99d12aaf931411fc674dfceeb72e9ef41bfa14f0986b436a3ae3c9b7a76988f8106e19d545e1c14c9f3e210b8c2a6609f4fb1edc7dedd0884e39d6f7c695cc1a1b297c5525243515ef9827503a7a964f859561613d85d1d671598aa8ec0d0b52bc2619cba984cb29b04a6769e9384d6544f6c0e2344e9394e95640727ac12634bb397b5b0be4d7984d44adcad1930ec2376718a47f4aaa3e50c2e80a17eefe557a9a488ffbfae4a5db4c0e20b3f95744f306e27c030bf1937eeb88e31e4005100a672e98e10be4ec695b8922f6a1b9ca45fe265e7481694a0473bedec1446d227f12e45a2c1c6202113c0c2d6d020d55b0b00bfd042c30d085acf9d97a72211fa086896c4749c628658f6227e77ee2883af0d9998b7f74b8d28afb20f40ff81ec88cc0a836086301aa723fed2b6b12191e234002953e1f29077c7d5c4133a1a714408fe0b3208b9b4acb131c23e169eae43e26c4abf84b6bb5ec2697728ff7342df37d16b7db7f71254855da5cece9b7ee7e664580289d114bdf51dcb35a4f2321bd6096c4b6ead2e8489022cdebf1569caa87ccfb678f2e51e6f361896527aa72c7aad9725f0186e27bc6698de3a10c2bd2794cdd799395aeffb155e7ee1e24af8959f49f0998d19ccfa929036273a9b99567b60b74f63159a531b180818461d12d83749e4bab2bc2ccd70892885700c96561897aa157c6e3a8cb287cfe3185c8ca58c7b26b56f65fc649c46577d0ec613c1536504a2c8ee98d96ce1d14a2f74040faa88f4d927b9290ecbe5fa3865f07a516c60d1adccc83ea904f84436950a62252ffaf025eab46defeeab7e1c69dff6829226e19ba21f2c22abd6a1e4990767a3141a09c457bca2f01adbea4d369a69a90e14731a5eec4c0c8c202b115ea2d42a18284805971bcbd0d68ed64a677d1755f57219e8e05237416655304278c8bb62e355bd786185320e810eb1c9da9d77ce0e6a0c0c346201fdb0b4cec9755c30889ea586f9bd2955d12bb6947936711f0359820338e159de5a5b456c07f9760ce551cb69dee023b203360ba4ba046fe533552d751aff4262dcd52dbc1144596339b0084ac985e9ac74ee13711cd442a5288665a0336fe00779b5f672b0363625d03457639ddd1d5f99c008e97549d534a00b062c967bc903a2afdb693eac0971aa2b9d4c6b137122bc1bd204cb94f2eb8c83241cbc9b01cb2c11ad90a859a2501e7109fe3898f25e1dc8785b568aa6b52530b60fb65fa5e2bf26288bf04226407784c3e423a2829a8dd42753592092a412274e55ea3fc61aae98280711a98c5b44630f9904430cdfba850710825fe633d976c52ed68e30c4cad09ce9c6f86609dcc42a0600d1ed32e1019f4968f0c9e9037d4cb14a026c43ebdcc01418955244a3acfc884bf57f9bc9775efd042d2fb2a9f2140e04dfd6f49aaf8fe12a66617cb83b5ecd5ad43975fed3ebb98c05213e38814ae175af441348a6a5d2fa1c2d267ae585a5cbe405c1fca11ba836d2c7b859607628d4bb36bd35f9d099d42bf1d7a0576d4ce5249bb3307f6e02fb083cafc45f2948ead1f3ba62c855599e67cad77b2003952f3c4faf664230f3035ec4e17de64486ecf538f07f874bc5e4c8e6ef750c9da8825a72aad5576dd696b18ea3043bdabdf3f075165e47c74966756958002c9da691d4c8ce7a4e0031ae9409203fec682910ba309ff3454c8ee516de77c402364e825a0866d698f86f3f997d1256e6ec315282209448f03faadfa6259a5dda06e51fa5d2edb752aa5c15d279262737a855a4125752557be32ea86598f57d30227f9e03f0e088fb3be07aac2e631b6c7b0eea3102601120cafd58a4e7c6c35c955e3dc84e0dc802e0a14fc9158c2e302446251b0f565db17508935ae8c99dd6e9176f28e67fb2e70b992b6cddd6472e93a36ac61a1c8f836ae78ac52344c9a1402cfd5e75077dcafd9432c5a45706ef69dbfa6a1805c5c93dbb205f20741ed11ce9f9598eb5fdaa627c55f6a71b54ba6acd65b7efc2b195b4639e757cf718b2c56a47469dcc2c316f5efbca744f3fb6318213eeb04dec87927a4e478923c8bf8edec87ccab90b8ec0af9f4d8c9db6bd7b48f09892a4d93538b3e6fc24e69e1baa3564848536f7bfebf6a5e6f02b481c77421a39ba0df2bab9c236aaf792455d93c8da050459e5cdc826cf50429267905579a3e54da2404c1f3564f3357c6772e89c22cd3ef6eb3b58b00fef7f644102e41afabff41a4f6cec36945dab512cbb8867c1e4f8bb4f65bb91ddc04e68432dff344d15a05596271a8c8a7893db67cf62fc31f69b27bf7b5fa7ee7261f6a2fcaf8d4c254b20171244aca7129f4b1cc25586454e3dfa250ec58c5e24b0e96eb730864533884b9f22704cba2d35634e5477c28567ae4544ed797756557f6909eef10eeeffd3c2c01fd860142d20b0944565b9e5281cad5e461adad9db7569b10cbe56ffbcb39081132caba43b6202a856373e15660240aad20ae16477561cb074e2ccf2840e643c20efeb64df6a48be26d331a64aa93af117746d96a6c204a9803bb1308e49a6a71e8feead80263fb92a51796c4bf1c95db0db79c0e31d31a03ee4e3f7b7c23f7902d1a7b2c5910b0f790ae23a0b6e64544bcbd5dacc89d8def95b63437651fed0e53e34b8f724be8ec92f8873273eaaa41c15a8c7129bbf800ab16934bd164febf2274d1216e23e9ee58ff1872e72b702a0cd50ee76cc7ff583d2f762c6643cf6c4a6d1f256952c403da0f31df38dc699ff1a7a538425b6f55b1a5b565fdecad9fc7f9f0acc4ee989cfe3a03ff71e72e9850453f462aba8abf7e042139792674d8f2d8fd1c7f49dabae1e0240c3b8ec4c8cab9961b00f96f1ec0de1413db21fcebb4834d8fae40943115c03126b55cea2d4831b5055aef2461f4f1450e211c7e6578861eedcd61b7bc14002663f4ee31d00460fd25d0df1dcd1ca15e2c817b87ec610326014aff7c176b54e7f9e2796281c3b6a97bdbde420e370a89e6c67cb406d6b93fa3213d5b6a2d66847fee34f78557d255265de528bfa143a543cee7fb541121a9733d8ee455b60e8598a84524d4cebdf44528c1fa37515ff6eac32649abe3f814b350f33aab19686647545bb5bc8056e2994a5537511e64c04c506b68d53fabdc46df0cfd2ce039ca4f1b5fad658f0c831df79cdf4d62b4dbddb4ee24b716de65d881d9a71cd4b2e0c19ee5edfeb1ec85c9dafd338de32a0a9d069c36479902494fbca4ec551eb2a1b172ac3c061eda39c1d0d81956b6c5c2baeae7acc63597114fa88c2d1f71f0cf9a2d9ef8f231298854520eb69e3276045965086a78b6e2e78826b1bbded04704710bf3e812ba0a383885e2d52bd078d40b7946d06d4feee5e61074f42fe800ff6441d7455b8c5224430a3246a941b0125537c667bf952e2a7ba975036f5e37f24397255320fb5200286f5c5751393d3129d55163a721d0a2ff9c2583614f122bd79308355b2fedd7994ff376a1e35a4b6196fea86435c0e808e0878373ffa16d62f5c3304403a14ff1f5c7c953f32ab8f9360c92d7feda643309aac9a9d3a0fb3878c52de13181e5be039f243293311c2011abd18214b420df4d02d921ad153280df2e2923d1ce51895d175aeb3bea47d5f4733c73c1577fc83b8eeea9513ae1b7384537cd83dc65345799b5b0f81bef4fc8a55b5a7774d7e8201c6f9614082305fb21af58f61f303d784e76f2f985d6e145de576d3bf1366f41bc25b3c57a8fe1a9345bcbae979d8057ad0bf2344fc91df2aeebd21b9ccfb3c7ba0e54a7c24162e1667b6f16d9343a288708c14462609569902bc68a1a8114b1d423b549f2e90a191f5cfd0de749d0f4788a33201a10c8ed47d4960f09febd2e2eca5697ab4a87f156787d8147d73a43a22360b63b257aaef351a95af635fdb33a56ec1c50878174336d0e2c22d8f5989b7cc100fd23a33e65dccc79070cdf3d37a77ed028dfc55e2f2835668ea5a3fc647b4d981d887ae1d47c94ef48c7afd21eacfb403ce1270dedccb4c899052a571d97d8753e4bcc9622b191303da79c19d5cc3b40ff1189718460d9f45f31d8087c08eb7918c1ea9c1d0ae799af4c833c3dc8d8c95318d59644d63b6cc2c00729969a4b3a447cb0e67d94f2570f98df8e2f74f80ba070766b94dec5613ecde1d8a2d085119c24e4cb23be948add915613f86266710186e93c6977f35662628dc7537a327f0a780b48fc830940bef44c1fafe8988e24724880cc393128d59f8940d716390fd5e1f162db2fac22941b0b4e686e85071dc7af9b991df95a237f3bd4d7eaa0cd01f82214e92d8c60d4f6895e733f709a16e2a535498bf2ca495ddf5aabf9be8824be4c34a2a20e5e4068374c5b8ee27106758d171729ae8aecca105de4601c5a00450d9b37f0041f38c15d5de20a41f31d1843a744455c57e58b4f0da1244cea84853e2e99e89e1a3bfb6290844925c2e485dbde80f6f5566bddaeaf5d39f5c52ee19dae828e58296703981648d13659b06d359fc254ac3d8d8387f036155f3104bdbac55625f3bd84edae025f2b30979388694881c91b335f182eafd16c2f5b506ba111d36f90c918bd674e13680d957ae235d2ed5819655c2339e6c81a729515022f187841baadd1d46164e9770787bce33ac60f62cafb0a5a39760bb0ac527408fb48fb9be63bd357223afea70e6ae343f5afccd9198282e2785df59534443d7ec147fa8c375b02488fb8216d40c48000a10d018114a160820e53db3cdb2c11cc052746bae89167eb5c333ad8f53edde1d7330cd4e445c93b5ad1396c2e494666642bd0d7921f3187d96551609dcac4aa44a7d54de1b21b324e3505fa46f681b37b30de4ac066972854380ecc7dc8e4da539a0844e8d91c5a46a51fe597888c2a5a980a790bd1845fa25df22e9df003dd6eaa7fb2669ebeec0b78ac79bb92b0e31eb8b93a72267a0dc4c68d58447d89459dcee2f5c044ea15a7d91a66a4fd10b034f61992704f53a89479e8def3a7e44058e45ce5c96be1d0ee90bb2bd12b86ef8201e25b986d4264ebe463879d44268dece70b1eb08ab96fdcfb85ceeda653495c06ab1eabe220309cebd167196b8578ac95861803fc3be626b5356e54810ba0469e8616bcd6e696e806d03ef4ecb003fb567f38ad7e4cef29b22654699a6105befd79c5e9c0bb9b7b8f1e1b206a150b54b73684b5298e6da8fdde8c787d2bae4a2cf4b0dabd33f376d12a94d965674d938bc470915f2848d36eb7d4f48ff6dff225ede0d5ca970bed7a600f98d3fc71f18638f0e21f6043e4ff06c991a1c1ee08908998ec237e5c8b5edecbdeb186530ef9d0c20e89cbc0b75dcbce02f085d042b4f536b74ee6c9e55a769ff588f7f2b354df17bfaae565648243a51809cd6c141cabc5f201fa805ff28d1be413505eaef82060b026db8344713a18f3ba26fb226d76d97a09e222aff7bdeeab49e2a429272ed9816bdea1f715fe2113a089b5776e808d2eeefd3027c494e2fe4baf528e3294d750f6ef8cf121970c788e6738d6504bc377e96f7f3b654947962bd2947ff15d576a7b945a4f00c7ca277c65bbf8ecb74cca9f9e3c1e42bda94e935c36eda84f478be212a8444d47ee2c6d700267e0991e103b6735cb8d93236631977b3b77dcfc74aed31cd949f775287e7a0027cf56994662dd2674229d8a302013b500a9359b6264047e1108503298d2ce38c2c37fdd0644c00750705998d416ee389179666ddfca1048cac544fcf93d205ac48e0812855344cbbf0d375633b1885b308493de10b8b6018e0ced0c03d9f668ec7f77748619bd959cf5ad73a97e7c3e332ecd73569d8cb5d1c7955c586c4e7256edd418c9697947e3f0b6dcba23fa5fee5076271d8b73e2812bb0574ee998060a5c44e46779058208084618a8e094d077ee6fff5109fe85857c01273499a356b27653a15cc7c275da85bd62238c680a76c373b1573be54ba2d8af93583658c7219fce13967a5171748d2626de39ad0e8f38873028403a3c4798985c8d865f39a588ca070a1da26ebf6044af350203c2d87866f16defad122f99e76dcef049ea28079c5c121957985db521036c94deec026cfa8bf857f32074ef03f51bd47127504f607d09747aaca14d81ebee868ab0a658ae961d8d581157f7051f4ef321c0beb0d01ea5f940f0b3326effe9adf62ea0bb08135c0224c55ab32963203d0998f3c22e92d087c257ae303a59aab2f5f9c1317446d5b9f9a26597eb11790579ddffe2ce8d7a7f8facc1ac25195ffda0237e1e908c281ffe03452e87f91cd5b53abf052d8437a2f0e17815daf6480dfc857024ed6c392554b4358b9481486a7a1c4e4517a3a38473af8a9b3ce52ecf7b6e286931b3e00b8c352ebde538fec08e5319d0b9318cdaab837901ad46d777ad0ab926e7cbd383b03a6813c67c0fdc29cea41a7dac2b972f84a84411ac01f9abcee2a518d4c0425d93bbf6000c1849343863921e1828dc7f7ebd69922e31b972eced19926d620292d08402fc82b540c82ebaf3287978a3077b982502abd65bfa88933565f02d93fa7eaa03707d04948a692dd794f9d2c8503a1f28b113e1568572706b0ea3a2eb40697ad1a8d3fd82ffa03307a4185cdad85b4bf3a496e59ff81894613c79d171ef918e30c440513f334ced64592621994071a71c06b0672d665cba03458aed4b4156631702898c56be328177c24d25f689cc3d450f0d56ad43a31aa276e1bab529bba0738622e0c493d5259909af05d289f2053b59a3d21ae15436a4e972ce88e2cf2997f0fe1531cfb68672ca6cd2c3e5b7b2568d59326fcdf7aa7f54a76b125a02295262cf3ae153d2758b834d6b3999ed1909a684b7134971034365b2e3ab6e2b9d72061d75bcb5b1af78dc6ce30a7ef8da53c24a0d3626f90c62712b3fb44c9d19562a8fed0cd2708d68433740fb26ad2418b9a18cec35b76e459ee3fed30799121a1bbd4d4e9802e6508c6efd4ec43cf874c3757acc7859ab1f38ec79f3eeba20f738c76230ebf7812916e5edc7befdb282323c6066232c79959bc0cdd7174e0aee21b7e034e722665e05843924b856a53daf7019a1a2aafa318637d08a97f1eb26a4cc80ea1aacb29f31138e5be01ce76cb01a5460daea212dfa217c2f2730806843667629142f7f66ba626ea270ff4a5209210ca8f27736567986f4d1e82d5e8420ecfa8441f3d23ab6c3973f842093dabbb8a2c9ac0c3b52f2ef88123d6f4f587cae92c4d66526bc10e92cc7e452adb5e784b058ed1ec501a27ef60cc31fe671d3516ddef7bcd7fe476e4a7670f6004b56b2cbb21240ea4fbbc4caddf3428aadbb7b44bea7ecf733ec10ea04a099f302e91909962bbb6c13dfb3811eebaf675c8caffd7175144d68ad3465d0fabc3ddefd431e019bd333fc3732caf28cc3faae51101165d2acb12017237db95610cb06ea2d5d06219f776d19282bd8b26e31c1b942d8a322bbb59e7d42c01e15ebaa5e30e5950066fa692783ece7a5c68ab0ab31f3d024d2f1e0bfc37aa18dbaa3632da5e6314ebfac376b0e4bb5930b3dc9695a128b38af303e230cdafc7ecbedfc86d64be0426feb74e143b8de0a2e84d0bb7e4db6af63b31c6395cbc7e5273c0936e349b8e0f55465b42b93c3da41f4dd7003c2394d1008fd8f1c0d8ed8efe8165099baa46214b314ac4b9421fc517045ac4f1a057fa64f89931c38887974c80c9cc4c67548a081712bb628c130fc1a1533517b757deb5c1b6e014bdf14f52f1cdc2625c2569ce6c4b2d8d6464d87c836f28effa16a744620eba48accf06c13e8cca16560a0896293be99db391d694a45ccc61596b4a546a9b80905d9f576f904488bfb55fdcc1d798421b5588b13ca566b380bf08d69505f0d9e10873d61abe16d035ce85c16c632422e1b820e7ba4b735507238158cea84535d020806c85e3b523c7744dac9eaf818d25eaf8154df08cb9c47e5c98f65edd51cec9c1339b8224925b45a43bd14e49b2c400f00b0d855a2edbe758eaeca385ea7cc30269f49668907338056babdacca8fd6cd7d7b292d62c2a626c5cf72dd11c521fdfa06961dbffca2c460be040cf343e8a1804750c5fe884a09a86c32548e2a0473b5b66ef03e85aacd27e153e845a5554d5d00dddbeef24e1b0060069946321ccecb0f53e9fc5af69283ee4661e8034653118c321694aec67e9b083d1eaabae22c610417e8eb8a1b683cf593e20da3d47bbb18c787c0ce11b63861ee7ee7bc2621f2f48016c09f23e82dee32baf53ea2c7ac4b534a0874fb51233abb3199095e6224c9d9d17c1354c11b55486834a9db4ccc62b81dc8a2ce3a1ca7c6aa0936c0a8a52569ab3a51710d0eb5fa7b8a2a5c91b8dee255f049369e38b2689b24e015f9d5fe88a646341651de3964040f430fe4a1c684d6787cb7256521a225f10fed61680b34f668e1e01e32cb06d5c982893c74ceb7448200157bdb826d1ea4233230b9ed330d4ea8e9787d079e41394e945a29383a0e731c1f2b99cb8ac6ef24113583105e0daf0866c7322e79932803968757dcbe0498ea986ae83591e554b4e66cb7ef98256f379077df0eaed91b17b80fad47629f916fee40c769190396f93822a7c422820255eb0bb71bbfcc0a4ccb03db10e858c5486e85719a713987d35e646415248b3b246ca984b387fc6237fc6dc79d8f90356fc435bf4ba1644b4b2f5ab370c1971b496927d10b9fefd89f6858675c20b9670e918ed64a3612ee914e9a072a6b00f2be0f8b69937d80549710c72921068b8f33ce620d46bdc3edf28978fed4b4099a2d26178cb83ad4c6db955a419f610835b0388c87d9c30823d6b8dc61d0b32fc679d1aba0d9512f351e556d55c6f8185079728d5fbeea1eada78aec31873562c99ecf9354f1b072f6ea6855e91b2c501bbfaae52f2d36ce61b5c82e1ee1591ea83b497995e6b42a04f3f648a1f3ed19d1c9e51c1d63ac1b74990891c83eb3410c69a99c2c9fb136004d54c435ae879ed2f515762cc255dfe3d3a84eca9f47bd412fb13e053e3b9a1f3eae7a3ad7896565f54d1fa3e82d42fe092824668eed594a8b880094c4ffcb0553b0f865149cc9fdc8e85bf532756b76131a302986c666d0699974c7182ee7d3910533df6f73bf861c4b501317eb0a3dfbc38d51486962962d4a343b444b0b232c3c7df60e3427c5766de53f0aab2116e301ca09e7ace0236132a5332bd4ea140082ed8df515a98d14f454eb74d12826525ddacc2537f24d065261aa850fc3690f090a5fef620485d3ce5061a321d6999fd5b1330ff306cc680b816565baaf97c3e4cc0f526d1beeac7bca1c8fec2881aa5b6f95f9443411d38aa8c4ccc20b8e1cdebe9948b6b84093de0c575e66aef08ae7f9cbade94446df7420e7056d7aa74096590d305250a39d778bbc3f067034021a0927fd1d6bc793c63c75e03c34e3db359a698702505bba4ea7c61b073b0375a45c53a7a159ffc0ce859a7b8b3e4bd35caba645847495b9d6aabad1031e014b0b3932f90bf347893697687eef526a5feab7359ac53d886bc924625efeaff82dc19cebc6888f50799606328a241a952ec5dc7e7373e43004fad8a7d200a652348d9c71a820538cafb2c05c9cbcc73612946c6743f6a58ee154a3d59d63a863b4820ff12f6cb5cb26a36c5bea453272ac46ad15c83d256b5c88eb8e285c123ed2d5ef39c551b378e2ae53bea59aa51469129589067629afa8b005fa28bfc7abe831572804d158ec5094d081c37c8e3e918447986d649d3a0ed3c42ba996abd80fe3d0353dbd26f1ddc47e8a28ead2be17c3cafe04f274209aa6c4926f6c8535002c55f017c1c4d35fc1dc5431b50801e4e5a377de84829a97dd0e36fd23dbcc8f8e88de1aea9b6b2e9c319408e332922a2a0114ded2d6218e2a0390f9603d1e93a26ed98061a2c84095b381759e4a2dcba26ea05f62f12a52586610837ec29b8d3af9ce3eeebae6608fe7c7392d7d9a94126bafb3a07d1daa2250f26bff8a2ed203d9216a9c1ce1580f431644ac429c7f6d7c93664b8283c222be6fd1dc58ff9ecff431d0b3fac4a0d109856636635b19e5149474efb7f8f8d6693752c8ec11955f8ea5d45b548e33ef767ca573dce91c1082630089feb35dbc9108ebc288492fbbe4668fc31d83e63845ce7dd50724c97de13887b57c8a56b1d5621a064c7713f9374fbca9d66c97b3e81a3758a7164e6025df2a560c2e341631a0a99bb3e9d83bae2e401ba0d0537cea699629c8791ceaa532dc93c726587c4edc3db1e083b9e67716d6a5322120632952a9b4201e4fdf174f97d69acce4c553a1172b178b86d274c412035999ca6c252725ca0bd3dfbc9eae0b831de808bff70c40975b9e9c32967236f371512e4079747cc161a44a150297d8e46be23e19d8f937f6608bced0e5ebe6a8205e808a501051eb348abf6946fefb62ab64946a16f22856b1fcbe2b6231407057c485bb89f3d065084ea92a8f1cd1a690699270664bcd1622b42341875feec4ae7d9d917b8f5eaf5e12d4803eca3d1dce85e371081039021d0c3fd6fbc0102215964c52f316af1ed6fef709c6ad665dd5c906a9da19a4d3a53157885066f7dfc3e9b46137ab65244ad8d3e2a4ab17038197fe5d3db4fa3fc75422351ea9c5cac1a954708a8924a6c239bfb75f7e7d05956a7efe26643793a917cd907c6fc835e2427223f41a3011be31a22eda1c890649e6308c3016c26505eaf966ce548027d996adc5be228d66d38d64d759f49f585b36b8737581f494b35ba20fb1b6631d7900bff4777ad3f17eea805cf7c4d349647eff60487f8851aaf6fa809051339f68a01ee6fcd600e465e2ab9725eb3b9668ae2338d686c7e9e3c05c62fd183fe75c9410ec4afb7c2913adc108b75bd25008a55c83b2a66fde79ff53681be41a94854af253b906950783188012e22eb2068d7d2bd83068d5a06170bf869de97d8841ec6518890974a5c8611b0442a71494f1c3919d72e90e631664c486d1a155c6c5f50f63c313a2c26c14aed24825ec841295c912b7f2b14a77aabda00a40df57f2a120d5986056b3786c08235193b9ebbf062871796652c7284c95146726fcf5e7d04c618ca4b45732c828524aabae9432c15f12a1b4cc85c00fc17a1f03a6a78a98e87d70571e4bf328e6e20be393e8cd14ee656378a414a16c05080624868706cb61f68811b29a7d1505f15c1f745abf114037fc7b41254697f524259b2616209a1da24290b21393b2f28eb44c7517718baeb633c3c32f7055d484b36534756c3d795b18126d4d1e335b817ecc850a35cf182d349b596006f2ccaa11a4d07356f6cfffc83854d4c7106b41380aa26e86744b6425dc3ffd9f92294f5e24338046f51bfc884a237730d64f5aa6fa840524d1542540b4f929807e8591ddb3785617c38ff21abd62fac2136b3146b2bac4c81cadbf1d1f5f6f2bc4c4bfb3dbb050181bab86a14b9a0d0c10181955094370b28248f7fc75080cf1fca46c3b9144d904d0e7fbcc816aad27d37858ec77039fb0679b61ecdec13b6abb204220526a1cd3feb2071023b21afd561b0cca3f30f434b8ec4ef7fa7378324f805def5562470c86b68ff299d90ecc846698141a3a61822fa23e938623e8e786785d365109ba0da30db7c5e3aaac20816e4a543f7d116f45810dea0bda822f349a68ae4b50a41bfb0bf23dafa8e697be1c400937276ce5fe794ba27ff10d70fa62d2da03666ebf0df815d3992e1c8ae75190ee1e24e37a542ef970ce8d229d81803a985e59e234ea1404fa4a9df4d1c1f998c5d46861487a53ed7d0b978f232e3b1491d851831f719368781099b2534f2c6d02761c127ae2d71f09b625fb6a073e3d4f0ebb6694502042636f82b56b45b5eba0d74449febe80b57b70176816e9232b331cb47f783f86fad13ea9af4f7fda6f94e632d8d32ed06f85b7a55bc8f222cfc053a54f95ec500c32501553c5604702e79eea31d96ab44a72e04815dba9b8a8c2163332f73a02e11ffbcd9b9a3ec0497d905c333bd52b48dcae68e52bb2c900aa2d7dd9161fbb63f46d80d9d807abf6f7372a2e071c2712ddc20f8cb3af6cf5e6cb84b17b6e006fb4ed663d88f3050b9a1ce756e0481b3a85174b0495835da89075e912f0488dbc9dc62cef24399227549402fda27c44e1284d0f93ce3b82e60eece08caa6da0b90d2fde829a2777e6a630a20a713e4bbf4a1264967cfba90dfeb55098fae5842fda2f540754208c543f7258f7be54ff435da1bd851f8afb2e8602d176e36116488fc4607beaf3d16011c21f13d3d1bf1c37a8f5d972437791bd463b2ad71b7310ac20bf906fd3741b0d191fb4bddd82bb79f32b634028b79b7b57a6948ab2a30e0a6c7fd32db279749b605b1790a21cee93cd6589526af0705f6caeacb352d35b092695623084d48e75bda2904cb4fd037a904a7d57409a55a5034d78dc1830bae02df36e6a4b6ddc09616e769cb45a286c02a99899b46615f8eedd4c9016b03d2eb003f4bbc1a1054c78921800b44c7ae7d670ff553357112d95d0966d042a1b229290bdf7de524a29534a32b107e307ea07cfb2cee39d1b07543242c9a15b5642a7c6caf3cedbd181ce09baf5111fb18ff41176255889f6d131d29b5f8896d11c1584cdb934adc1fed1fe6e5c3ec0e51867ee76e3f2cf5cb63635def3c59e45db469ca01bf33037ca6a9d05668358473aa69d70b9e803cfbad1b833fbed857ec32e46a2bfad8c7e3b95fcd67231988bcd60769b2fffaa8d1a55ba32ffd57034aecdb348449cab1b073d77de4be44e40397e888ec16cc6cf3faa354712285fec6d4ce0691ad6acd2cad2b15ef4d9b77d1ae26f8da79a4ce3580d9ace310128de6542b607145b90d03380c5a00324e4f88001246c4ee8431609fa18a0f9cca62e1a2f107df69beba1160a7e910dc251fd3456409d0f3e641ffa9e5a8b7019d78da467c3ef8cedbb8ccc3fd3033db753d7e6dd4b5db8526facd4779995879b7661efd023ae07a7047a27cb57ef7cfeb55299a502195d6f3a49319dd81a7d4faef7e1f1e13c30b8fd2dc590354c71fd3a24ac2104270e096a48d2464e52ae27dc1120b79ba7e826dcfea9aeeb7a1b7e2fd3f5a5773ef4b710176f7a06a87cc962a0f42aa557313d0654de8575f1ce0794eaa2feeca0d86d9ed814bb95aa52d54259a02cbff29b3b724dd12345759794f257dd52f7fa94ba5d7ff29dd5b81ee569fcba495d77a436507feba0d04037e69961055af21bf3d430f992a7f1edfa12eb5abb56ae95ef91dd26b51b5561b12bf51d75fd0d9731857cfc2a59cca6ee65a35569e95accce67473d289dd1e082fd94e4df55071235fa421b76fc8439891099c27a7eb62a49644edbef8ec304844dcf95bffd757fb2e2cec2b5dde04c71e1bf261289401a4bd07fcfb7f0749e05ff7d94527e89acaa29124d2c8a4aecd5d0faebfad931956d215550eb2badb3ec43a1d068347a1bee8e1ee76275fb9be35ed8953dad38f7aa3ce015d9e602bf644fe399880a6afdd6424aa516f243fef8212b6d8d0dd4b2ef67159f8e958259cdbf1cc2abbed6e4b4d5bc1c167aecaf7a41ec3d6797c886f5a2c7b959dddecd36bea11755d75ae63837ba8d4086556fd56767b42ec4cf09f753032ff7734527b9f1b37f2a52a0f15dce9831fcd7315efbb1ff843610b3301bd55b76836f045febe5d7f8f04168317e1bb8663b23db0d8e90cbafba8d7fbfc3d69ec4f1e19d85ab6d1ef6734e4aafd6a968557d0f6a278e0fd9875c4045a5aa9a9565b1f59515aaaa29aa3efce35ac3fa3e9bf7fe9c6f3735e27a308086649a3ce985307992ed0105fc1e26760a61d243c3f1e17dc80594b5b81dda026d1e2580fcd63a188002be7ce7321828f9d1cbe7cca400d29bbc1015b442945846e2a8fed1fc1b100ab481b44e6b57eb581b6bf19ea8ad11ccc9cf61f533c4c8dfe63b08655f081db3a1b51ed09efefd37cee73efb9ed3e66ff2a38cf259be7c185acb20e63d2f590380d63d3fe73ef28b7fa93f109d9bce49e9fe61bc0f19e23a67b7f8b2fa4de9ba960eba977656ce39ca6860e7ef3233334366e68706f79c73e7cee173f0c57f2e9dbbc1ae9300aa1091f15d97c8dddff3e7cfdf797b68b3b9fdd31a3bd7eddab56be7a063e7de3976ceb1732557a2a48c445b7be7d8d1119774b77b7b7bbb63373ac3d5a4ea5c6bde7b10c628e713359610ebe29a65d399abe85d9dd235c268e6ce5ea2aea4a4bbbb9949272728288cd2dfb7492829272929292493929494114d494911a584b2949414cb0ad72572fcda55a640b7f9446b8ee709d4bd9506ee6ef7f6f64dbb63b8d8eab1c25401a2ac83cbb977238d851680be9b9082a77758a7bb7374b7b7773be79ce36ee79c73dcddcdddce39e7b8bb9bbb9d73ce717737773be79ce3eee6ee6eee76ce39c7487a58a7bb73743737777737777777777777777777777777b773ceb1e3ee6e6fdf2a7059072f5c1792eb3a0c7d248bd61c10fbc3e87b8fdf0505ea3f5d0254a0e048fe589266655d5816ca6cc4db261c4884618ab0e76fd29393939393d1a8bba973aff243a9406916b4bf4d534668c261eeb6da4badbc03a5609e8e953e515227b9fd2a52a0cd14873b4f4e506a806668c038233559382c48254ab211575656e0caf3e6158785b61e13a56ed36aa99a73715fca6a68a90954a559a5a7a3ae92ab2e4899a94d2676d045087355057375a32c2ccec2d22c3c554ed7b995172f64c2f1ee868469a5a5868554f382c280f13f9322c9085f8c18de5c85369c95151616be308ec280f1436bee3faba9955a52776fda65d13333333390cb3a4892dcfcdc6839f116ade1682ddbc9f116ad89dc9f64c870193264c86876a1e9a82860513079418271f2f504a5aa18f95aab0bab12c37492d13258063465355664b83761c078f1a41b64dc4051ddddddddef2070fb9d10b0e53a843e63c68c9e318367b85168bb000e386828d48c1939e40053d392d948b9b8e8a0c3cb8bd36460a86b06cf782a46280a95d5d0e28caca65fc582b6b0eb59e35c5a3cd529862e598d0efebabdfbbd5f2aa776e021ab0100856119da70ae0e3abc8a11f9b2c2f2f2f202c6cbcbcb9b5e5e545e5cbcbcd028e1226194f41ebfd9da162ed7974b02bbd9ddb9f7daf61597c85961e522b53f182513b0372713de13359510e7e2deba30fab2e976ae734a5cf72120ef421d111f29b99149a6d1745712d6b5a6eb9029fae4844f60c884235efebe6cb7065cd133219d6435282728282824931214941145414111a184321414141c42ce981397ff45999fd790d7bd6738e275763a97f74e6e4e0ac2f8e27cd8ce7d2f31e9022ffa0a9b1866b92babeacbf5605da18c5a34945d96e8cabebf723d5cdfaf32b31a4c947175cec5aa9739ab015f3a3ff8203bf487570b7af9f5006b8555e7a89e952fe75c2abbf1c3fbeac6efb19f79bce7cff5308f29824ad4fd73be957bbaaf545d0fe16ff2ebca75555895d53cf84aadc57e79f3fcc1d7ed8db563713dab4b2b0768ada624ac9cab68fc70a3350f62450b5a1750eb75c1fd4071b999aa63faba8751cf20fcf83e5af15fc7c468a99bff62155f86233e7c181f6607c0112d8fbe2f28089bfe3344098a266e4a34ae070b1e710b220505919b548fe7a373bc0d9480148022c95340026238031bc470063660745412123d5734b3b4a4a3f354c46c71c5d38a6c8f0d7850900f506cfc407050d0b5b9b1443cdb1bfe2034147a9128c4cc6cf9056b99862492783d3795d2518244ca588848a5baa82ea5a2d493d010528af45beac23c4d33901f8e729906d2991532e44d0ba47fb8ccdcf9f1e3c78fcb6236645b8b9292d6c2c47ddcc77ddc6762d37dda8811233ba4ca7787145af016cc82d646dfa314ccf3eac262884614844c1b69203d3333f107c88f05f2e3a595f91df39ee8db88d69acfcca4529ab601f17154bb0f76b9ff70ffe148ece371826efec3914cccabcf665841fd43224fe2e268011bc0c23a921d3a3f64fd87cb381247e23f5270a3ce2c3dcac907c15a6b5220d9f1ae0d72f28f75fc9568400486c6c51ae5885cdd45b82505f3ecd3691cf5be049db3801c90fbcb7507d7a021447319a74927654e0e20dbe3ee103e6889384d8c3f872701d4ce0509dd38a72bb67ab43f9d34abf90c2d3c96d5a3040b092522f28c816ed68ff5e37a58893c3b5842883ca9cbd6d4e35c4e6aa0db0da69e7b43cecab57e228ff563ea69e1e9ee8ee95311a6ebee8e699df744414133e0b98f7f32dbcc24c776c36c8420110ea808e59b3df6332e63a1a465219735c256c8133c3c847d86740f11f9d6b788f925ff11a16a5a1acfb0d3c524d632a5d732a2c7301e07386a4ecbb516446b6c27110ee8013da08cad035ce6089fa2b59e12d06de6468c75c3dfa2fad50147544e8be9b4c83490d25a5a525677126c492449361ef166ff5ccf1585b22c140a5923e215d98de6da5c99ff765dffbeaaa1d414e8e67282a091f98ffff88f8bacddae7fd65f30777317f3f08b2346b1841539173e76c52896a822e8c2f9a24e0c26ed18cb2a312131b3cce50f801b0001dc4b3fb34563524bea95d5c9d7b25c66baa8c7da0cc01373cc2fb79c67d9c3b81ee667ef3214a8e428ada61cc559c52346165c1f5f0e4db93f918a02dd1c360a7e3cb261a79621358affda5a5c468f37c4800c40373edff81340dc10033258e1c61af0dfbb77a3b579395b6839695acb4be2c76da054aafa99399a0f9f545d8ed06736d7db54cf422e4c59b1a56cc0543587057401952e88f1757df5a23a31cca298257a6b4e3729666dd7a4f1506537672405c39cfdf300aecfdeb10c4d96fdb8343d443823d7665699868fd5eb5f5633ab8a71725c8677723c6756be2ed3e14141f7b24146ef320f0af26164df51a51950be253f7ad29bbcf3c1838248cee13360f42696c651f05d16848f123bbaaa07055dded981bcc33bbc0383680d028582cca4606066acee16a8e1e73a24a4018bbb4d24a4618a6b44c768445f9bea6555d569659126b9d557564e8b452a83cb9d36cdb9e8b9f37e0f3791a7a282f2b5ac66e9f856958b9ebb8d3260c74089b07a2e9ca924748b3db7ad9e1ed743eaf65b3d36582efffc6d9401583777d9a6f0c86002dd588058805237f63817abe7c2df62cf0ebe5b8ab6b306d6b92f9bd7b4666aceeab1bf30be552a4b5d29cbf23f0cc3300cd3b9ec56b26c65dfbb50da0c480705feb9f2a4744ea081139eb8f0f926e59c400327d46056d7a84e7d2014c2aa29afd0d3bf68285465979ca2ca12655996615675c9c937ab1b27a1d4a2938a68886614a392524ae9b46829f4598aca129d724eabb2aa29fbc1c0a9d3dda4dd4e1de332ea5ccce8b7232c60f950bef3fb5b08703984c3e5afe2b6cf7673baf1e1cf1867f68ca344668938dd0d67c89dd646be0dfcf8ae46a3d5396d6bb92c5f51ddb2bb519a439699dcac6ff69773275d0c7ff6ce0da0855f1a6b71c17259d8776b6166f89299194266d872e5e96e10384959bdc56e4e2bab0dca151bbae7ceee71763b4149d15cfc96e21f5a2687e9b799a95417b554532a4a3da9ce5124d13381f215fd131541b21b3529c9e99cd44c0ecaf4e7facc3292d2cf97d696ac436176e3241fca421ed26e28347343ff43cb509a8ee10f857aaecb64f6e96b77fbf9a2cfa1180be8cc9536e759a7736ece8f496351c889a556e21fe88681aefca71304ca5776abc4df7aa775d805a1ef0744225b89e7a327ec2773f8fde899bd1b82d0ad777ac7d57088646ac0f5b07bbeb5dc6ddaad4534b749a9e8b3bfb2ea86e0220ca3486c71b1a769a9832fb54460d666be6735a291cb6ff42596867e9b7714fa913551fab2742293f2925d8ff3f999a42beb8e1defbd96c99eca878eef840fa56c54b74ca051fdd39ad8e6d85a6e978450ebaf9749f9f926bf9d563612ca6fd8dd1c9214fb50acf5818da2a4526b13ee8cfa12c2ce7d0fc3405262a03fa4ec6ff37b40f9be3fb5d6377c640df6ee2dd7eb0fadf5cf79c22e842bdbe9b6cc8d2268e9b1a035ee61202931d0159fe666c906d72383fdf557ea5e33f7a241e35ed64c4afb129dae514644896375e700a6259582e916c0874fa0f0ab9793875f1cbe44155ce8b9f06fdccff525aae082102eacf3f2cb4a8d80b35d705d3977ca941cd5dd01137308693be7029ff51450eb652d15c1e3881e6e3749afa024ac06c9feaaf6d4287ed1ddddbed3b5aa8dffa3d957d5bfd905c8beaaa94e8dea974dfb851b8a4829a5c45a4bc0eb819c2111654e79125297b552a21aaaf2bdb44eb2bb67ef9e61b4e44e530ed25882421cf4dc763110c94681d03fbb15717988cbd62d819af871ae0907bf105c53261e96a0d6bb9731100740241dd35803a1d66f970e0ced8d52f67bd98d2e017dae552b28a5897431f2a7cb885eca189df3c7b9ce9de2855a50203b3f7858823adda954c8ed7780cb50ba843361c1edef1f72fb2f1d77e4590a0408f59f27e6a109ca365e5c51cf0b28ff76e9d09e2a0d5356816eff0e5dca1939be03e27dfc686da0bd6d82cb9dfcaad2f0c416fd252d88dcfe95130eb92171e386811b7fc36086c36f15eb8673e36f3afccef82f4380fce8291e507e77e1cdb8ea8636f22d0efbde752e59e4dcf757fcaef1bd7e9344403b1ca62bf503ca73dff7ce7d0fdba0731fe6598d1d3c74c83b9d8b113ae4c59c0b23a01100ed86639246bceb9c8ba9dfdbf673024ccec5aee1c186b2995f669609c75736884908515090b4f8b3aa83b9a594ddb7bbfb0885a21ffe7b4dff95f837dae306603be2c109e1738c2e282828685e77f2ab6391cb0980f2f37bf7e6353feb88c5f9361e8009c77b50d0b5ac8b35fba9430605056d71e3c7c7ac0e8f7c713cc957f69dd579ed02d5e14141f07de3d1b77a1e7c2beb1bdb261237f24b845ff5b8cf4d18617cfd821e8d5d78efdd83ef1551821a8a28e1e3f37395c1bdc8f021c1a670a1210a181409824f1545b2e073832247f00152e40a4ef80c2943912740c1070945b011f85c498cb0831214c9715812ce8786591ec0a33f67c3c5eddedfcf5844416dd4d0ee732e1e057d990debf604b943fe351c07eabe1ed73997b6a61af33ae7f29ecec5cc1b70ce75bb76bd02cdf57673baefdb39e79e73ae85812ee79cdbb4fb80cb0d71b9ead773efb5753eea0b981c4826cfcfffc38d03740ccb8a49c5452905e5a4644445a10cbbde6a71d1e125b5030f0098f1ac5d6de61ae16187d48b0e2e2d3918b941460e311efe15a3c2538cfaee0da7cfe114a3facde114a3f695718a51f9ca38c5a8eeca389d6c8caf30feaf7f87f1f6fd83f12f03c200301ec60a162e4a29282724939211dd62064ac3c148158e3861a40a476410c291d1d513203f330d64c0a7222690c1caa988099a7044441e28c21578c4529c584bc7d02ffd7672f1db8aca6f2419d3978c7ef46cb7f7a68a354af42a2e445faaa28f750b9d3cd758b7bfd9f66e9651e1f25f6cc5e5b7a8b85c05e0f24f97cb32321c8a1ffef529299ff229768b4f42b1cfb9c42ff993bae1dc1393a7f1933afab8c1cb25262526551882e4e08e9edf8d3b7247ff3220aa3004c1c12d19d9dad29a4864238d67fe57b5eaa6dda4a07fc71590da9b75b4a43091c40634463f883011031695fafcacf2fc33e7e41fca4a87a1635ebce7cc8e29fdbb48f9ffefff93d6728af1f1fbc873dd3ac9090cbbe15c18cfd5543737846b92f19b0070f86d07ed3714eab73ae3371739fc366af9ad9271f98df957dea5b243f1b7d41cea8c8aaa1a3f0e955f466596a77118f5c5b5c2b2c282430424040ddc17cf59dcf816cb8bb75ebccb6a5ed89d534db5163fc6db4a8309aaf2f0996d5ca97c612ddd507dc8f80ebc0f322c14b53273cbc954377a4df3c56f98cac3b0b06ef442154c056b0d3e347dfd37d5a4fc9552532affc36ad57febedcaca43080306cbbf781876835f7a93e92f99d5bcc05e9858aa6bcdf42a4fe32bd5c56735a5bf4a2a2515176faa4ec5c55b2ede65352eec2cd57753eabbf1679c71c619bf8a55ac228c6e26be49c93b8f3ffa29452b5af1adf85744893f3762f1319e92109ae9947ed0f821cb7f42aafe2675833fd0676b24333d9b03e29c1da0ceb9dc404f7460664034d0131c9839317a44050f789a2d656b3ea5ff649e743a79ab5775e8e077ce25fe73acaa1b3b974ac7e9692d25f6f7dadd3b0cf1b93b9f19a8c10d83d0d23aaad4a138757bd3be5459d30e68ecc8cc4fd4cf053031150047600050ab6bedc81129d650c51129d69004ca176b343fdc207dc98f8b139494928b520aca09a97e6ac6fd605c884205ee07e342144b881afa607eb9a5b5744c28543d3384909f7e267a1a1fd550f65726ca441c8aff44a17f21be26f51d85d99b999b7f57a4ac1b7c401bfa730f7f01fae52019841e3ea76066628522518a090945f4186ba42afaec45d55d18c242d9bf50f62fa3e9923aaad7aa2af497342727a73b0342141414046130735a1942862c7013ef5abf6135d5abe07bd86d8e02869bf44b2b1d337ac1c2625271514a7994e7e77144c7909ebf470efb60ce742c9919cf393c3f3fd1322dcf2e53b48c0e445ae6a58a9649c9ecf0fc9c056ba16500f038682fe36f78a67199eafd0350a7a3dec30080871db078ff52dfeb50dfbbbc27eefb1caa6bd48cea1a857af3f41b5fb8bd8bfa6dd6877fd50a6dadef9eeca36cad7e51b6d6be316cad7c63d85add8d61edd71a2f7cf173c26079ae79f1d70b182f60b0fcc360f9c7f217632feabc2e63b1aeb595eaaa6bcdc5fbd2fb94f72827ef496f8bfbbea43e2a621ff77d287b8f3dade250dfdf509dcba8f19f855f55f8fc3d264a90c46d4602c463a2043fe6082746576de898d7901fe69a185102162ee33ce618c01ef7afaa87f03d0670c77aa8e332220b8540a873e19018b818f803a7f543211de39c067f70af1752ed063f5ab6aaf1fd9b83300421409e200c2108f3a90063913b3d7728dade6566bb892af655f57bb9181a4c502cd45d5fd59961ef3ec4cfbf80f0dcdd397a7c1e3dbed773af8985e64f97c97eceb9e350d5876af51caa7aac4ed19defaa9b2b2bb88118a50cc95065853ec650cce60c7d66448b4259c55a2bb5f6a7955f798c4481fc9c551155258de04558d7439aa779e43f87f285f0971f44c7bc9736e674135940f7b6cd3eeacf8c3450fe9e2b3e56ff5c0f3c1c0e890f1fff16ae84471e3c72db676baec4ceb4a673f15dca23e6a4b4a4c55f5877bcbae3bdb703e5647a346ac50dc169d1984bb252c29a8348ad81f2f337e6aa4a14a2212c14aa7e34f2a1147bce6f55f91ebf1ad111360a8d46231a9aef755e22cf6a2cfad49a80804fdf067cfa38170bd5adc70d5d91866538375479f4cd2c0ffc723d26dfaad5d3385683b2dc395dcb2bbb5997c708e35695d4b04ace895552ab60dcf97a3cc8838a6e3c7adcf7cf6e8ea91081cabf95f5733ed632d7cf79596c9f0854ce761d87c431416b664cdd8d524a697c1e3dba477ffe1e1394671c8502ca90611234870aaa4120f8a64c30ad9de0967a7465850acabf95da08bf3dbb71d70dbb3dfb954cd05277495ca0d3cd5001dddeb34d3fbf08639b80681bfef621bd8761948280542ac157afaa9678e03e7dce3953ce65fa7476af0f0ab7aa22cce60e7f1d47dcccda58c0afdb0dda678e5f41e7c1100b5dcf14e0f7ae7b43bb41861f24f4d75529a02388c8a61cd532936a69ad35eb37edf98bfc9535c2777005a355c548dd75c53533d331559532d5e81cb74a550fd35abfcbbeffa239c00fad758e6973b4d617fb703db89b894d0e01f3044240a23e1ce6feb07a31bf0bad093ecee5521be8f6eeb4b05ab09a765a8397053983fff1871f9c0b3f4d7f6b5aa0fe57a01102f1fe7a1befafc7b9b36eafc78517c4b9b0f2c02ff167ddde8d8fa6a5352d50b71914918713d04d7bf5a580be9be4e3ac60ad69adb5d657be179f9fe0d114381864b8c7dd7adcf9534a8961d8cbcb8208781f5fd669b7e72ea6e9371fbcf32902a6fcd9f3f5a07a8b67564ea01beffc38808cbc95726e1025202023467e7e7c7c36e7a5d7b43999079b70cc873fad8db4a9d783c4dd47957d26616258a9e41806198887cca082809effd3681cf54cfea3a72faa26b70c18d9ec4d0c087df621cb468ecca44c525a06641f323180fe45ab49fe287bfa42644f5f3ea53fb23de8f7c0f16188eb4fd319fd0b7db4c6c3438264ef32e7209aeda024e946fda3575c41c81eebb7167f0784105a1b7eef6c75c8536b2418798a2fedf6acd65ab33dc1748cf55bcbedffcae5ab60e50e1fef70f7afbc92b22a49c13b2af97e9316e3ef1869846bae14a1cdb305abb47a77ab8f75a3d566c221dfddaa7af995f52c18ab0ba78bdb94261cf1e7c79fefa309877c7f1d740c7d66ca7fe3522cd506ba51fad70dfefe1cce301d2347fec3352d93aa8d185a5262d62cadfc24a105235421043707293bc321af05218edc90b8f07902180bfcf21e63815ff823641a7faff4e0e38e799eeb622d54ac85d65e7c8e2f538d0ba663fa8a3e9335b54267aaa802b318e67fe2efcf31d31a9f3ae6cdebadea996f55696bd2c6bfd2ae7ca935d212ae639add79e854c2990c3469ddeb4f5daff1a0c22aacba647d58f5f362d57b23fc62d608bf568bb49325cbb7a3b23ae4ad5ec711d7b2363cbc5692a9d6f21e4dcbd17bf93c635d7c49c9cf8f7fde07ad8a5d7f71cff84d50f86e7d8680ea8df06bd9e01b77605687bcf2751c712f6bc3c39fb49bc5f3e49aa0d0bebbbd4be2b0f75a544399dda42bc2bbdcade815478f55e5885c4cce39e99cefb4eaabaa92f2b99a391e6b48449b53f4257584e5b82220389f6d563cdf65d887ca6f34f724535a311dfc7873bafcae8729ab4d65537df61cc3f379b80d0fbe44389f8bab27534328bfe3775cf9bb6b445f9bf856e439df65d9ce4d5889385d9bf7300b973bf93f1ff99b7adc7019184108d13fc4cd8bdbcfa3ff088ed9669e0f4eeffd458fc15307a0df743e37dc5aef9ce580f031f66e252002fcc26f59c72ff0bdf27b0de38800bff85b7fb12f754cc7641fb29bd71c7e55586a0835d5e88b3d5f7e5229c8e8b3d15fa32a7aacca873daa34622f4bc0bc96ffc7acc67aafefafcaf70a23f4dc1caebb820a29ee7476ec3c041ffb93d60233d328fe5849ee2faa3030ad71df1b251d50cc03f459538dbe4e545b1ac5836fcd7bbe4840e77396314ee9b4f9b460ccf5b03b8f77042baae8b9ce8a2a78aca8624ac7f021acce7d6ab43721e73ed2a42d7be65f97d56cb429ed08f9cdb46686d48f139079d0492ecc5c6bf2993dbe25bc0bff9d74656ffd1088237272724870fd9b88d2751cc83c85cb27f3e05dcf3aab817df557dddeed31dfaaaccb1a4d40f83b15704e1e8450668e3f74a6b5c6dc7baecb6ab652e9ba8dd1c61853a999c831c2c78310ca5f446bbd430b28c422f505aa95a8bbbb1513b32aa9c31dc06f19fbcb46ece5baa3efc639fe1b0bc999cc33daed53733ae0fdf6ae0146f57fe0b6095470fb213371f9e50b94b6c639110bd331e1fd5c97d56cf4b9abfc0088c70540dd879ae6e3dc19658cf48f54ae2a7155e1f896f1fbdd6887f011b4f4c84da3fcfd8770191a1fd77fdbc17f43ddad5eff52e908a56ee47cf4ac235fe07ee3152308c3755774a0e796aebba203402ef6ae88b17b7c9f0da69da8c4ce3654b9644502000004a3140020180c08864422c1703ca289aa8c7d14000f7e924a7c5a1b0ba42087514a21830c22861010010000919999a601a1d84f23123ae064ae4213926fc04df9ca1a7d842d32fedfbc34464351b9d2a4bf571c3ea4db504781b7b6d1e66b194a14dec4f50ab308a4508a51afe7c564fe2793d46f349001dfcfb7df93806185219d9e5b52f1c5d248003ff86f878d4cc315ea4b2e23e741195f96afa6a249d2d1679180a1c55ed04cc998f87f56e86a38590487854d84d08a9ecb574dd4afaf266712f2f457a6ace1f4b60496946f400bf55da77f8467a50167b56ca1939a10dbc804f1c295bc41b0f08ba725410994b77062b1e05b0494cdcc5491dc65f3c7b7c0e22e3f7133bcc59b10102c6131ef22079104eec18da499a1f9368f060aa6fb584ed6b9e60d52aaeb87f7f478e074fde22dc1b5c60488dcc73df2875be2d859c63e932d676aa0759c8d13088ae5e9c3211712ddc770b234e16d51b259c156ad00d6788fd59396be6b9717fce3eb8b287b84f205a1bfc4764342d0b6e58806a5d5f86275fcade366ead82f10c6af0c235b545427406386b515808a13e253d4d81c72570355ea8988c6236ab47e88a0895dc2250e20e8f418053610b06545c4fe1424103cb17435cf5c22642f6987334c05c815b0440dbd5cf0d091431ffa9625910707318024b4a794169d9db055f536724b591fdd8dfd36c61ee7990a505bbb8d3a06f0f3fbd1293b618442144ced6348f06e8f1dbc98ecd6d8c30a35b6e4588e8d94ddffcb0a75c62665c6f1e906e378e4192b31c64e3ac30db9a58e1477128069c6051d1defd11876c437277bc18238ba1218339b2b0e9cb05c01a4438558d9d3470e4cfaf610e8bf06c17dab914e5598da32ba95826e0dbdf591b560cae7b0ea71981cd010548b7798ea12b0bc788c11e331d6db81a4f0aff5b8c762c3c800363ddc44c294a78a9b56bca67730e3371af65584b3ecb92a766b1625004e5a6d6caa90303b8f3dd59420dedb334c4929d250d202d0e880f10796871a458bde1f967110d5e90971154b9a6c5c1d8d3dad384d54aef3c42b1bb115076f37b37ce20915c68e5dfa8f6626464aaefb524b2aeccf88b6a911850bb0fa52150560a34182be4b665f6af43038dd861b00ce1cfcb6f6c90180e35489772f0bfc7a99252075df86edc4175345bb6aa18fed3e2ede3e175dba48e476cbc49b7243a9022e06074085d6ea333502b9614a310b9589256fc7e534e580d8a5497b781354912af1d92868b2a7d04115b61867663298090d4e5c2088c0f1d01c4cc72136c5f90db8b242f62abaf5ef64e1aeabca144cb98407f031e7ebaf83e159cf7c3729fdc171ba307d583a2a3b0eeb9d04052f12b0cb63fcd77ec2fb17dbff9ef691cde2d901bc0e1fcbbfc7359a737d62be268ee2c99b5ff4b9b22c2f3b7e970f8ab0935dc0354d9b94e48885262057c41e89ffb8494804a9f2c4119273c1579587a57bc903009960b67a53587305743aee3a4898158639ab7b3918441d13669bed41171d11c25cf536a0e5744561e8aa184c2422093efd2210c28cb7e57476d485485f1b921e35b60f35f0e10cc2a4e19815683eb7292f78278c456a45039e2f30f59f0dc013ffaaade8e7abaaa432bd2ac7c162318631b6837129608c82381006a87e16fd72060f2662657250c59fc1068ea74a2b495f51dc58f2209c97ea6ec8ec6ff59c5407e771a33d7afcccbe66aa5e297a7c187ad5ffc949e1171fd3c26a6b0f31a3936b0c035d9d9c0a032647482daa4043d44d55f0529e0f62e668bf5698bcd5e241ca3d4d005e13738764d912309d69e32e1b15c0c72cf3fc8e2ce61c8a4f99f0d63eee14cfa18e99b1f085226d95392f3a53a6ae9916b168721a43575b44b48cd43547150cbe35daaf32bb9fdf66f741395faa2652054c733101b16ad718a1ce2b230117e43a022f5bda1c9e0086d5b4e34987c4c7dde42c4a4ac5738bf14879b9acadcc630132fc9b8658577eecaf804cf028589c65c21615bf951fc9d0003b5acaa4a30d4f88abcbef5513d25c03d59495d8e0ea1611c8345195c54da13c44bfffe7bc57a859632b4480b14e4edd6b9549b7e3b68476d8f26528cbf1489b6fb50e7614c2eec54b5769b8324263ccbaa5c5a63e35f305fa8f4201e7bdf381467adcd46188be6bd8b197a8b6a1c61477bf0064ca20b2eb898e44e805188dd4254958e6de652235577d510acb8f0007a5af69171ad8237d55bbe3d78af815e0aebecdd632687b65e40deeca8485d857633dde5282fae62ed3f79042871b45b3a8dd956b2d278d56b8e0eb3d5ef8b5738d7d0027773397566afa93557c8018df0a18e624b672f80131fd1ac7dc11068c57b49b181832df201816f3ef4c1a225f110b2c46d92c9e9739fff385c847ef7a54463cbdd9a46ed87765a043ce77e1fb2cfef5bf033fe5966106e756ff2e4f68fc348c05fd0caf7a2609bb9681de4c1e8b91fd578eefe77f59bc91ef8d2468412cb3b8399ec5d703dbcf674ac48d95292465ab7a99677b8afea3677581f5fc539fe80cc85e94b828c2af4d274e583955492e645c80c4dd192efd004af710d17d472028b5762eb20c94ab02458d138c0563cdb5ad561a4a154ae78ecd8cb92225d4c0d593de0ad5d7d6a45a37db003f27cc2bc788980532f58e4aa44fdcdf2b308169c9a44cccd791458f6d864855152178295f92e2b6c4bedd2e25e0336a078c84d2149e02e4905f83bcd29f68ed81a731c1d809bfee8855983f985ba5bbc995865398ae9b1b847b178b924501f0079eccbec4e0080531362c3a0f88007bc1110a7f7bdea100ad3374c2f19d0c42b1eda68c84c34ccbfc7794ddcdfd7e5480e3d585dd637e48757fa527abd269c9c27eabb2e67eec3686948731124c69899be399a8d82565a278ba1185650a97a87e277a63dd10874d6b1d8fc967e93c6b36cb7bcd280a963a63228ae5e2230b8fdc3e88ece8fe603b50edb30636331e4b3b8fa20d09d761115400189fc8703ed2c7f38d6b4a16bce9c7b5cc4c2b2f5d39c1fcb16e62ea648f31ea533580bf7be30d4fcfc271096e676e96c5dba75301c1fceab2a8f6417c1b6782f5a021f85bbf5d9d38f40f9b8f0188614af35b057efd6bf9b8cc3ee39d637a7bdba388692da33b3c4da15f36d07a593a86040dc7fe134251c54c9f1d3fe4d721c8f39663d41e8aadc20add2abd7f56fc17270a11ffff034b903aaa183e862f4e101414f8a0b8fa6e7b04c3bbeca1eb18115716c8760a0eb834ba9ae6db0747f8830867606aae5f986ab0a8c64d1cf7cedd162dc6e50d271ed3679f59b5f76dea5b7ac09c593a5b6e9d4b20db1f7ae725fc1f7c2e9cd1d2f2700e667fb951e3efd4364182eb0d697f7d662a1cbfa4516a6695b2f2afee411e9e6e4d70f5b3ab80e63c67304e20e9a2a22710a74bcc5f50c5567f61b9701ba3e84e4e2fa269d86f27774c799f969f28a835eca76169c9e22808f1fe332f7a54bc53501054b07da755a55d2c20e6e50c6cb66546bf206e29cdd7172b50d010b38c755a7c9985241163f4a04a48302ca967dfa705bbc7517aa3811ad429235996078edd7e9cae031ccdf96bbaf16931657430be37a656e41332d7e453f8e8334aa8e4998106b501d9fc6034681d4422c8f2bd1518d72cb62b2e76ec15d7d8502cab0f61592f42a5bc5941e84c11a1f9c813d080b866a1e924d5cc93f4276925b16bd8e579c41000e53267679d53afbd09122b1a3e79deb485fd4632cd2084e50bbe114bc0a45a2087656f82b25d43358688f6ad36c45d0cd14674b8b15155f42ac41c5517aa088a39cfaf8c71e29eac65bb3cd7b19770a8432e4b0bbe4025eb66d8009dda5073204d3bf18c67518810b242fc4c35d53a051ad767182a237c234c476e4015a14877058e3e64d45c228e272dbf6f7e7d984fa3e2daba683bfa802491d79daa7c26333e1284921e02c5ccc577362d46bce8e98f98ac9ffb5422eeeb14be38ef4148ad959161e863ff54a6e730fd901d3529c4af25da7725b065068b090584e22604987ff41577679d61fd463bc0bbaa9e96f986c629970a0b9f7b11aca083fb53f9251762f29804d6da2f4fb66dc814a5b46bcb5b6a785243b38db267946491014b96d23fcd76b9c628e1bbf5f49b896a5a156cffd82281719974d451a1e06e68d300c0198bec5ad8f60a303ee34324c2edd8f0be56fecd5d2b2e7fc62e1a4517b8881d3b1aa01b8da207bcf44df051d9613ca6820f353972680945cd9dfc89a016e30642d25dbcd0a160f8031f9f168a2c3b9d5192731f2657b63243b210b0c5cbf79354ebf3ca9cfccbf52425d3181d77885d6525ff93854833e495d3c8c3e2f525b8100de30dde68b32ecb51af4fc7a02c04144a7c5e6fb7e7140391e9d1c2d9cb01c3d881a4ca586c6a28f734bcbc730bf47804d721295d3d2783dba2c420272a663529324a188f5378f849caff9f3896ac5a810a5ccab951cd9073837f9e9c13ee67aaaaacb26ded3e67e5cc9c190138c97807fd16d1d397991adeed5bb9fd6eea3e96eeb6bf6585ba8696aaf793160d3b924e51c54a9d4f064862471582dcff6bb3b0400fa3004a362926ace06fba176a2e3c0b2cd5519c4ec7adcdddfbe1f8963555f8e897e11c43fd731b33a1ccf7a5b22568e810adcc82334947afa989e596b2fcd3590f63e61b7afa804fba257033851be1119262a06bc183fed6e39e30ebea7ad2e5240493c3eed4038858ee073512614341586933877502d91b147971562be582b59259d8ac2626dbbc3cc1c2170e5eafd851dd61d6cfb02f9c2d69f3c20e46f2ac7016807c742d1a0829ac88386c09b09aa61cb316e3b2a0d3368de9fbc7e729c3627ec769e3cfe020c1827e27c6337cc3f75f8ef8d44be7f341afa47d234a1fba05944660e89634de735603b625404a3331033bb6c57b4975de0ba0812a6d0812bfa69126c96288d7ef39ff8dfbf83b20c13403b8a819bc4c33681c467b115df101dc2f4c60901ccd20dd2989c7ee18dac4184080d93cf778a36d075c626919dc5aac8d57a85cdfcc402ebd648e7a964215c893fbbbc31db832fec8621f38c2c1023f16adcb92cbb2e591eeddca717863abf06f212833def8f4e7ac24252206621fd3fea32b2ce370e43f657e0e76725e9e32a23b379d32f09a966e37e4e426f3451d5af41513934bed5c884bc48d32cdd3f1e7878bea866bdc0d4e4a1f5932da1dd49246e12d435fa80b855ed3c8d2051708c9f7ab5c3bc4df2d7a0335324f98ca22e787ea4e88cda49a449cc2c0d7d01fb50485fdc3d86681f977560d515622dde6f7c376dcc11b47febfc5df1ef29cae1d8cc13528c5f085aeb020dfc85ae013156c9817e650d2a999cfa4dcc6464e55bc513efcadf01aa93e4a5a4aeea9197014c27c873a5c9861e5a15f6d6125f160a87719ac0b1b3f226a51cab66e1744806092532d747990717056999da9f2f03005ad691aaff129e6c308c60d6838fa6854383a6e2e698a0ca81dd1d87549a3396228ab30873883daa2f415ce9cf5afe6ed926044ff3a4f99d9b8cf6aa2071c30276cc59dbbc09c925f48fa1d92e3ad34badd113031685d498dacf23db23ef380ad9a15e1ea6f863310b796ccab09bd36fb322f74010b199911cf1e5364cf7ba077eb3baa33d56b1c994940261b3a1cd9a495fa38231c246e18761a590ccdcdee81a6ae21751e59494662bfee39b3d7d188a78eb3568da15dd37c9815fa57cf41e485938f7a8bbc41b73928036cff66805daa998b730da2014f332592b749e9efeda51c2f8bd1fd8f0beb910ed9e92723f04910cd69d75d119c482200f5e4ea5cae9137de023e7f658fb1134eb42ab74be8b4d35ae2c779e90327bcf5be7536582a65be5d27815d0d3e668b34b4db10d4151a57ebed9924f020eb43cedf761c9f7f6148f315f6970dbfd4f35f5c68e208d3b4572d238d04554e1118a272ccb7d19229838f1de234c0a3a82a99eb7d7053cd802bf73df2213075dd3a193289801d4ca1b57f2e593916677c878ab106f400aae134c349016b9e1e24254c9694f103a76e93561109606c0ba74092cfd5396cd136022dcc38afa11584101a907a884ff8c9beb1b2ae667cb664f3bcda6a83f365892b482901ccec7bf659b8130c153b0d1413d71a90283e31ee105a18780c3eb242e02309242283f16f3d62f23019121e9cdec8be7b3ac20a87e2f5a6498d965a45fb21837edb7bb5dd4ba4f8b3de83097e70da346745a493e64fed831a1967524046e9f2dcb319693526f3f22b58e0f23e9b4aff3dd251aff6dc726525432d2a39ada450566799c6a3209549451abf15037c881e5e551ebc3f01d168b795e73745e0db68bccadf9da57667ea6262136cf48ba81ffe59094dd443e70ba28665440948f0b0e3954ad691102c90c72095df6fc35ac1f510401d4f6e20e3f77e5c77cd2e53980d1edc25cb9e0acd69327b6974bbe2b53653078f1982b8acba6263873d092c897f4e411ef1c79a808b96e6b0872809ffff6d4ded46ef172fe5e840126520e4f5493cf1d9c70bff49313ee5adfc2581415ad3ea1bab66f988949efaa62568e2b3f0ec4074d152b32f10459b2eb3ba75190daefe5f1b1c78bb115ade0c06071e31db1b54ca43a1d17df0dc502499437a474f09f8b23e586e0865ad05c8751c7abb7466db4024972ae3037ba0e303560c05b13b270be48baab0ff79d327398e585b527c6425253090de9042295915fb16b8d29c71fd18b9e0efacb4898b34c4d413c46f81df939ec403751a4e35f7836440f902915986104b22277ade8ec4d5eecc66535d96bb7d5d616c14d94d2e8d3b6fa48370a71b85591b8ec8a980c646d0980f8a6c076ae993ef2cdcf14bda9941e5d9e9c7bbc5d15da1d806ee7e4c6173b3539b69b7e7c60eb3cd74a1ea4a95dab67e8299007aee3a2a671eb43b0fffbeeecf041b606a8814edf57453071a5bce9efe960ec13e21024f6da7e6b61489ca864d77baf04f953612ff4e2eeed55286201c5fedb2bf24a9b3d7ef9e7f7fd5156135be31f8aaa404b6427f1feef41c4c729a03155a14fda6332baf53b4c2664d85887580a1741ff9facceef74650aa3747f5f6cda97b4abc4335c9a11ff36d5f02fb7d4cf0064bc5b0b06013defab01942df33de9e37b5eb35456532e0060855bbce9a4d009200e676d568482a00ae4a8cf70fd3baa31e3fd5616c618e141d100bbb8b2d86d2e34df08ac941becae190a5a472c32a19f70f53eb92e856d3adaa55e12dc309d2a4749bfef06b758548cf9dd57b25b289ccc9e6c01c4a959ebb7ad673f64f388990b53cef297a4cb244d961a1f6ac1d6f28dc091c58bfdbf9523960d8aa3fdb109bc38c18276e36d8c10aac6d38d4c0ed2947e93d90c8f7b35070c9fcb225be59f03b0b21aa5b17ef5b8ba20e5d3a882b845c340b5c3e0f18f35bb7b05b573c2d1417067eabfcb0328854cc4f62ba7ed19e85eae9efe12f6dfebccd5a0cebe799102ca8d142381c5415d1fbb281afcc80e2dff3a3806b1d463c69e1ed4ff5c82e1df859ededfc42649e8e01cf96ea776a3c90c75ce9193a17cf53e400e1471d476756dc5a920ae4bb2944ae16aae34d0d6109ee48ffde18351ee9c0bb438637fdee7a4e4e62f4e059810d31a04596645f2c4e032d0e17fec5c083205578818dedb074114c3dfc69374a5d3281448b9870a33f23e9a78db498423438a96aecf57808b76217d3b59af21e087c7e3f86ac2b9db57e3a285ec62a63774a81a56576f6a1b5f7b2ad85faf5049411977f0e012093cafdcf881013bcb8eb53ecceeb3c05eede49a73fa3f7f7f82e254f92ca3c4187f3da0bba5680e33656d0c1982088dc937f4ba2e9564403383997796779cab2ae66b1d484b3cee61a947be4e25579ca3dd6c0857a8b07871281f120a49a9942f0e45dfd4f2299c9657d06e0d8e0e6e943d5f847468f2411d64221d529e4a5f2a4304c8644f0035146920910e291dbb085fa05f43718ade45809d9af56b2e1a850dc2801461e568c7cd821c0b19574020eebe96fb370a742800bbf364300a0e1a8036d169ce7adf00315eb9112094822b3c6023c8cd3bdb2c783194fde9776828ab227642553e9d2a3ade1593987c6e7d80ad0a2b2a89b754fe97b6e339a1ed5136c805145f25ed79c745a0713162d84ef78f28e29e5dd458992c520721cf0527fe6908cfe1d70376f1e6c41471debd0b6036b0ed89fc2003d7660d67b74ac30e6fa04950b9a76c357692a798192043e4b7d35553f5029cbf239afa8370ebd068a286e613bf46edca57af628756403de15dbee8d5d6d37372aea6b79cb3c2039e0d4f14b813a44530accaaea9dfc6ac82c3b7523c6cf2c0fd347ba97411e15dff2a5cfe33bce8654d0a3db123d89eb97edd46b882444e5671fa4ae7d4d2da27bf167b07286472d80cb63c4c659ca3e6d8772e9e165c5da83b6d324502b6b58e94de6135aa8d4702872d57fa41d2febead44963810760914d0d80138b930b088996001dff0277f4823368d37427e28a737162176e1fb24917854b76fe2033362d185452a3abfeb4cf7849a218b895e41e3e982de36e12992ca1b0e100581c25ceb3aee64c01be8fcdbc435406f082422540e1f5dd0eb0fae31ffb3b0a8911b84ddc8a68926aaed4b990e08aa9c835452961ca9cec4102ada9fb24fc2fd924f17daceeec75901ca18e7bfebf0acc7566d2629fd1a1a25aa93879c4025a47465ea8d2f0741b29243d0ff7456bc1d92a26ea9ae80675e924f71e803d8d06a6891a9c70c8c4c6f0abc1c2957e844a06fb0ca7c28366bcfbd0c1f7dae623b10940a2da82539452a51dc9c5d4e2204539dbe914b300c66757d97909fbe5c632d906df200c0a9004189f2e23e7cc1024439f777cbbbf2342690a9d0cf8bc83dae8fb1fb0dea7e14e60d233ca41616c7105fb6cb794096245b5542560e3c5f9e3995bffdeb490c1be5222360e5ac4c515c54bfd736249aee91d59af0651c04e1c81b2b72276ffe3e26047230db751e6d030205504076156dc4d16caa415f6d881cfc7e53203726e4d03e1e55998ef01e0ec2304f1196ba31365214558ce1db7f5f7f44c376ab8308fa74ee23e0d1a2f3571c773d7524b1f7d2ef01cfe2b8a45e8f2015de0675e83c6bc33ecd9c726637f2f2c05b0bb988397976da7a82a85d0ade16695d410be572e538279e9151f84250172353d2c8ad23f4a63fde5203f7a5c34395c1ea24160680c10710d26b75990656ec70a655eddd377aa667a27fd1313774a66e3bc4f0b42a688ec174b911bcbcc959a01bac57815c5c6a2bb35146f39ccfcf7541cf64bc6fdae21d80e6651666c4676a618a8f007a5981e73490760e8a488fde5a239b3c193c56edc809ce024a9955dab67a6abe2d28ef8c0f468b85bc16565ba3636b82ffc24e3cc6431ca7b4dddd82dcf70d80af4e24757d6ada7eef5321fa08160c3661a0b4a0ddc829d7c386180c134a1a7e0e3ba0df138658291b8792eaaa27b3f33556471aa34ef5baa312e05052e42b3041fda6c2ac5187905d8b8a4c99d98f61a9731cc42c765a6ffe0117505079e7020c2ca125a8c5eea328196f4adda5bbc3a685efad5a6e572303883b3c71177aa512ff1d268db295f4815b9a8ca28d09f5bfde563ccca517d117bb397b7e93d7cf517a6cae43a349917c3fe2c0b56f91d152c0bb650ef57bcd83634a5a570c737d61040e57655de7d7f7830ec032a5171d2856d044226d836ce241999b4c3912025a37aea34fd10d08bf5ee8e23cbca1d95d7f9a1cc79a2bd515210de54e01e0b9e172a22dcf146108e7c1cf9e747e1e98c8052dd0779b7145dedd59036f0f7c80994030ec2170de743826158e0bd53fce29bc0114093ff2105f394d030b44b65d804bdeb332a845b9cba8ba486702b58f1c3f086970847e038351974c194a1da84cf42a9875b2b752001849ca1cbc19d92e0247bb00f9e7f8c7d2b172c70c2cf9dd1350fec7db2c14b6ad057fab93093ddfba1af80c5661c0c5e30bbc6b30ba54d781d5b88720e46c1f068a29508d819d5f7d6c8d419d5de2b4256a99aa0f849ecd9e3263edef36bcfdfd2ba69dc5f33cef9b5728c15c3e2d68b83e9568118e90fb39b78c90d9d8a29235fe7d891af2c5f927d9f5c8ebabbce27e201e001b0624318fb38bbfca87a64512bfedd0d62b17e0fab742cad56416625220b833b9007776f773903a63e8be18c7b1ca4dd5cb30ec664e507e69ddee648c7ae9729341ad30a9d414cc480bc168ee69c3c06ca8831ad83340f966beed55f58cabb79cf26e11b1426def051ceec9e5ff4520816aee40b8a3f39f678435a37ab45db1bb60bd8e6f6cd14c5b0ed17e47d98e879175d3e99d53ab8ccfa2458dccc7833753ee5fd001f1c69145e77f55956325bad01e11abe03502cc00c0edb0effdfe6dcf8e9f9c77988ee8eb94842211ff2382cdf43f1615e7f1e932fea8498dc6f3579f69823f51da2eb320fe5698d0ba5dfb762cd45278577cc926113c404aedb660d2508d4f4cb45cf648c63d7761c7a548c1c6e09ca2a6543dadc4c0315cd5ec8af2be4385219fc8130ad9e29d85cc703624b7edcbaa5c7f8e50ddb9ea567c47167710e2ccf30f2dc0e44738ef7456b1de91bd1337dd4f3c0f47bb99a9232de7406d050055ba0bda93c6db48fa778d7ba20ca0524926fd5bac86ac07118801a15dfd2780703ca043fcbf53f475ddc10f94aa1820a0219746307e894245d3e99339dc1385378f9fdc428e8278e850f09cacd52e3624e5c1d11db5bd0ef0d97dafe851435d47a1d161a06a223f796ee5662c77e2aa3a22a873231b0963655214fbe35415b76094a516e1081961465509e50c775ad634cc747b5931eb191f52abc91a18d6d400dd4bf48280e4bbdd9021d7720f42e63128bbc181a0d6a54b39368399cc0540a8996ddd1a9a4e55f5afac2f13fb3349562c303113c61d67b05aaf30ba67874875be8e08ebecd15aeb471a332d7942abbdb1c8e791c4804cbb858b184e893a24e9bd8e1cb04f656347c1cd05c9452cbc73f29a393644263ff990d6e1d97dddab07267ad3db098dd5a37ed1fe39bc2152fa130d33206388cb5b265b1ea74d8e6f8410639efb02065a8dbc8ac58c60d0e7cdf5e15ff56b1295277fe811b30683d50f962085471a452397826e13b76d8cf60973ceb147df1a09f2099e4a429c606ca063b1fd064cb61a2378bba66c76be306f2c45ad08d1261e0b14621feb5c75102ac9a711311ea63a99502d51a66c3a293dbf6d8a149c913d8502658eedd64f34db8502496a9ffc50003543414088ee85ddd528b201d1f11f52788cb7544e3b0cb8edc83c2dfbc1f442de1ca4da036adb8d494136786eea602771b378b5ae01137fef28d04098aefccb7ee7bd12fdf96d33624ec268d5343ab90e92de29591d88ca98174fb0d04476b4eb0b4a9e65ee2372365f2ae3d4b416efad29517a78d562e142f0bc7ff6d61fe1ce9d392dc8782186a38a03632d0593782345c6e279341067640b63f01460607e6f45deedc8c96d9ca0c94ee8387d77c390e01f3e4be7aa4eaca766a2b279ee3ac62a7bb1c0ac394c122533bfdb9413aa4d595e0cfccec94884b7ee61df60e0c5376ffe45b30b73f403bc2b1ec5775fe00335f7bc877cc1bc3be8a53f9cb2e80292d945a86edf36fac00a9e7e386c58f78b642e52324ee0c88a0ccf8eec24f5928ec437dc684be5745487e3ebbd320bb23058ee499595da0513de4a1c82dffe09811d41409cfa6181b4502846f82525c767d89d40ede04aeb90fd8e5ef5e4410074062b6a9888201d5a31debb518f719e73ee6521393d00005b43f943f85c7b2d29e426c437b2e12becf8bc33ed151f17d4b842c623f833fb2bff51d874c2d4673db42f15a869cde7eb592fadc82b53d8aa683181d6396a787b17b96bd9d665e7db2b86f0541439cc0913fb196adcd063c727255b5c6c1f4be7be0fc21ceb6b63e03854890a4a12d423a31f1585087630e1bdf0a1c5b43bd073bad71352d69ae9875f90bac503078dcc1ac01506b260e21b6e689443ec6ec6b3fa8d536d36b6116731c389c8e7fad79a391c308491164512d05739ca091c413c52c92c2dde48823bce04815787be8c1bef84fa8cadb872a2da41d83192603a4d060d5bd07c5511231ad8c955c736efe4b24f9142deec74fb8dfa8624b540680cb8eabf3e0211b496bd6056940d5b9b4ae69025c5a1fb8d435bfb0c53cc98a8147b853d79640d4c7cf7bb6ebd7f2795e8f58214762ee1056f804c6e4e5ee2a0919822d8dc566698571ea6511afa1cba44a837b363017575a4e8c714a67ea481d117246ea91054c810b7a0e5c4fd006115653feb007bf3d3297c16d1e9e0313556288f03a4008781674cf45e150921e1fb06435a283b732917b984519459f64024081e11559abe3e4edb2c12ce4fc1427248f97075ae11e4c6ba9bcc87c95a2feac5c3a8efa748798317b0b0e599a312ceb732384c48490bc64a1ceda6c0e3d989b74fd0b3cfb6bbe6a75a30556a3fd4a2881809a0dbf09db880838a678d49a2498d0b1bb1a3111276222275474a5e8bae4a0f7c86c51523369cd4b236385f78f065b212847abe10e8d3df1c2b83e762f5cd0c834575313cb1a4b19444380569c8eb2077619c9ca1d5d472f139d501338f12638b12672a24dd0444de0c49ae8891bbd26e2c48e6e263a4145a7893db1892c749a9843cfc44eace8688263a204092f9ac2dc98e64aedc1ec9d0bb287463fe9f7541efec1a2f26da3e4953166a3c50e119301b046edaef3bce20d5d6130e34e9826ec33719425f9e80fc7b745f413aa03194739f022b4f9090b674e4a4ce61f400ebf5cd5d3bb7b0d978ceb316f9a56546c0e51efdfc6466403e7629d18a8e13f25a542824fdc7023d8bb17305d7dc6a65777d40c39755e828c66d022a44a80f379600a377198cd34d2f2aed2dd4cb70ab7970521beba399550970af70c782518c3a320007256268abdebcc8e93cb7f0a4a651ffd73a6bf2b1ac1898055a810a0cb20b8c4c3c4f908315d31d5583e134a8e224d2c11ed484789747e2f40c906d7d73e2b200c86b0111861d7f5d75be5e1eace18bc7a758a4da79d29764245464a08bfeb6261bc0951a389ff71abad9c4e63f7310e031d156b1f793436e545edc3fc5bca60c6726e3d6a14a8671a69c8abe6f2a1990603b7722ab3563af66ff3761654c4c5dc4dc0a9f229d9cd4c15376ee37ba2e6756996314470c0020aa466fe8fdb3a1ff24447e69e40c77ffccef3b5fcc79179f8505e7b17e30c1463579ee4a8274c103ab8c84f4e261540285abb7c9deb94b38d63767443a8d5cef34a09671c0450dbfb3f09cbc75a3fd78ecb7027f0864aaf7f12ac64c7f91144314184ec6773152fa6b3ce20436d5edb3914c78d0ec67b1e0421151ea8dd92e7eaa2ab52bff20a195c39268d6e0b09125a2c3b1fa9ff61c81b1a6651cfdb18c54fa83741dc20d873629dc4f6fd935e09851c0f7ae7125939cfbf75fbc4616e57a1d1dd2e3e9a9c9de21933246f0aaf731c0d7c18e6d4b8508aa9efa89841062079e752a9200c6b944de084d948933ee31a9a18e09664bb51c570c6f65c1e82cea3dfc4fc99b12213adbb9d21fb8637b35accbc1c0dc34204038a41828112ec3f86c075efa03d597a1858e95b730a10b3d9b501abea2009bd922835f38077f510829a2d76a2763571f44561c9fcf54fd4a43570ceb0bf9546e7d819871a9d7cf13430ea3e87a4e25c6caabd7ca2edf086b028de62772e05a0192942f33b2457c3d09511611bfa40bee02502a49d123cb353363e76c61efc939cbee8cf1ba48159431af323a14dca9f3a17d47c56c838c6ff5f84b93b0da6d947adc0b7da5330c2e0328ced3da66487f869c3c8dd483032e1f4412d237bcfd707a745e75887efa9ae98b42382f249fcc42d5c60f5b2715196b6555f6ff318cfadf9c7be1b998032d86e61b779592c52a009f7b3096d8f40e3e6f437f9509b85f722de6b2aa630a02cfb0d1c1a0f520c0e3e10d41dd6020d47f6a0b28a42dc5c3df01ebd65761a1881d2f0fbb08d63974e3d530e3e2143677caa749859a55299bd6d2cdb75f2649386eedbeaad075c55a3b50628ffad84d1bd2bd62374f12f20b28b07c8c50b8092d0810a1b07586f53c373e8b540717b19a59e4e384007a2c7e911e29fc43c00b1da7edcd739337e462ad79befccbeeecbdd8701a7cf28eb221303d02b306054fc416ead9172ace594a3db5139a2de3aa68c3170626bb393aa603b29fd64bf06c2da9a43db5362405f5cffc852eec412b6e52306e9098a67e9728e78334b733bbddbc1625c83753b94d2ae9f2fa3300783f20b81a387d2abe8eb6410c25e0d044120cbb0e198b9b5b9d8071931a07cac4029cfa37190ca3e10935f828a5686d6ff1757de7528a5e977d84d07e38db6a33d4a2bed5f787316ef18379c212fb6b50ba92d0d8ba9fc46cd50a35f9e930315da091fb4ffdae99893d5d917096bc6cafabc31485cc12ffd86b295d25d81f4a2155844866500b82f495d2dd47bed95c7c51ed6ac882c4e7d5bf0f3fca7f7513a95b639252cfd042c70f934559a6c63996096408ffbaac5c71135f1381480e8aed2b6b035d96ed8432efd5cd184333061aece1314adc2eb04638e3aa0f3005b4858e174092b1ed102f712564228b0e1d67e6f8d578203a054956e46a7606873f1265fa5216baefee955f44caa1f155e25768bb13239857dc939ad0829aa4c85a5f11a997a24c7e49b5fd0c51ae9800562a6a07e459a485a5e6ab5aef00129f181df64ad1f2587d49f9baf81851a03c87f9434ce1b2bf84aea84857d80474987af5ca70e4f32b1268b8b5867e14b06a8d5930809ab9b8fdd11cb9e8f250a6759dfdb789bae008d3d17e7b411c53574a7cd51c4681a6944c27fce79a41405c25387b8ae8840d0cf77f83424162babf08dbd662ef7b663b49288e7e35c4969643b0c09107f6c1f3393edd458736e209d222e61150ebf1056b12cc788f25444727de4f7281755746a16f5b8d9d97309187c16885216e9030743acfb180aad849387ca6668d1cae0731d36a114db0f42bde7ac06ba7983ccc984b7375eea518bae2f90a554e9830c97d688893462c59ce3d470a0258297021162986c232caf0cf8e5d635f7516609964a06394d7dfb45dd2b50b48cd29b086e7881ae792c2a5799b1ef41327ccd43fbafffcfa430b40055f4865aa90fc7c4eedae43537034c6bea405a9d24c83eba6a22b65fa435e07940faa5173cccbdf44b747811c46c2de96525f60e86026bf293666f275c98687e210432ad3a420f990f8baf283ad2f1172399870aecd00f0d39b13167a1592bc156ef857ed6f3f196d41bf08c8f58dc400274ec21cf6bac26d4a8b5270b2efbcb11099bb15eb8db54d7cd663adedcde33b29c66d3ce5fada331f6cb682f41b47382253a87aea0dbf402b301d2c941c855036dd11fc1f31bf3e91759111d98145b15e2ee545474e80dbd3962a47f2c23cb6a7d46cc13f810a0503ce3e52c288710d73a923816c525a478aa339de49949326f4dae8b6d7ff0a515a79158f4b2ebbc7b22f245d102da061cfba6e911ef6f1698ddc7bee1dd9fc384aa4aa107c109000637f26ecd00e4953294b1d0e70df2148f6761929dcbd8ad32cffb608caa7102dedb645c9a9102e8065ad59ca4e88299884119aa578e0bc413ed29b3583451a8e1a71958d871867f869c651363fa2a6c0939ef63a5eff070b239a30fe714b981433c347d547ccaac3e35f76809c6c5cb9d70349016f9730b43d50e8f8665403a7192e97996309c26d2bb706e3ab8fffa74ba6552cdd9ae50ba5f40f672991cc86c85e42058483e453a2d002cbd8a2fafc55c8413de380a37c2c31c4c99a81a608e9450f221498907d61e5ca4b2e9accd81a74cb09900fc5045413fe44913b5bbaf13a74080d7bfefa4ad9a200492b6e0b73253021253e4759e04b446f7e009ff84a86ce2831ab3a9aa5e95ac4ae6983cd6e1cdbdc1e4b1fc84b82588600030fce5e2eb72f620aeae2c33211c5f3210c39378060fdab7012ad21c38a066c20ef992b6fd426f62f09069bdc5110b9f450bfe1decd6c732d6d209e778a68c7ff91c444677090f7cb815b5756e856b91e65c3bb7452544fbe8188c38ec8584863e334adf99290975213881a620cbd1db4224b5017d08ef41a2ac279d759f4eee8c30ead128ecf619a0cc664a9ba1f902dbd5a01241994a6693cd316c25bf070eb7beb21e6a9e5ab4426065897480a0528304959266f11ee16302771446fad85f8a0ce129091e54096bf22fe536c1fb7a954d9dd33c3c5dc6c7d29a92748529a52eb1a8d41a2d508fb85faf6610b1c5ad58e0a5a5f16bb7ce263ec703385cf713f7170c94935141f7dececabd027909474348890386792a0c0c8bae3cd630aedce8038a60a54011741e9523b5b46a1e26ca9aab8a1f9e926474d1fc827b4cd3b63b24ec2d14046aff51b73f8f84c551a42693f58c9045c5673ce557ff6a279e83686dd6026b152533e594de03ca3d471da918490b63f3a78346689a4ab62198d0d37dd6512382c662c451b168bc05c446cde246595baee46173953c441255f2680ff1c7ec9014e6e5a148c1456e4f2a2d23864617491343e210f9044737612167b51c70923eaf592b957223f0594a7f315116912363dd9f4731ec83ba02316a170de86333d2801746e5034929e23c83ab70878633d768200cff94a39e2569263ae15e9d44aa237a0cceec1e3fd2d5164db4801442392d7298b03a1ffaf9c7dbe11b18afbe244c8ec490c48850dcf0d178d0037325683bb9beaa40d6a5a0d91fea23355187ff3563a3861f2b23c98f11b53c04791420959250da6a82db31c0fb4ba046f9c7bcfe2d2eb8716c6a65bdf731f5a42745d50e26d275dc41744142f44042ec0db4ce54d9c8c9c942d4e43bd0c1a0a5efd427d28c09f144ec20a80e4829b5b01116df245447e24bd06701bffdf5da60cc553846e86651f879013a94244fafcd966156f01aba33db28630f261261e80c704b1a5b549b86aac4a14944e27102494a3d81dfd6ebdc7bd465df8e59823558d28da55629321a081c0df095ad7d0a24622ad0101e037665ec5b02e4eb49855aa46b8691f9343e98a13f86642334929aa383dc4249fff7fccfa3f3f9785aea2b50926b6c2732f1e127b2a90acce3ab71988d72f0d7b6679430ab0b98c2a8be1a95133abb9531ce3f26bcb5d57a51b1a22751142bfffd1c5da3845f070d203c7f5949e5510ad82148fa9d3f2694e6b2dcd5b47340c0953833857602dc37f1a12594e181cdf665efa1451f9bcec6a2766eecf19ebbd56db992d21488f82f812e4a399661864622b944bbdeb331511c19847dd3486f0f0644cc776e0fe623e2bd547f4522c76c8b0d1df99bda2d0728d7676562986bcd2628317d609ebae444ba4bd934920ed5760272121db4590ace02e51e62d6b7beb9a5211b56905a67915a3f29b6939ee797895a0e4eb33abeb5c2add2d0a327ab2f178772854cff583d8a52d5fa47524e571ab3480b91ddc117b6cc81acf7296a5703994ebdbf7ffd1d8e227773d883df3dbb093f87c9107285a0e0e1ebc72e2e81382008473026661e2996ff221834a2220bb75a4ba9a2336ed4e9a9804c509de574053be22ced90dc1f0131501414a342620eff949c1f5690cb759aa1cc07901b8fb4b6d54470419c5b2d7857980b8216798bcbd4943a30d2157ac15f4603cc2af3891ed24cdefb96d75597bec1d1f531a56d0d81a44a430594aab61cefda852bd6747612a5b7285bff0866cc62efd1c82e6d67e2cfa5630a8bb3d2d0796ffc354a715eade37b5c6a6e9b1381f7fe490395512bcf7660b8cf37ce9aa1631e5d3db7f67da0f35717842320a06e045421de4cece0841ec316f17e627b366814b2fead0eaf0a7156d0b8e3812ece9404d5e02d182b68b9ef0149484587fab80a3bd35424769396659f7d4c81b9cb7df441781510bc0eada802ae0386341d3425e1ec90159a98269542d4231a349df263148f9c30aa0e1105265980e34f8b91fe09658477ac7ebfe8693e4e8e9b4cd6c10226b59b834d988b85820e7dea5da523c98b464fe5d00ca9e6539a9768d5f67f49aa323759d06f48332eae322f3b1003d6f27e329452a82898d95fe225441cec8514a5046827f2526bdc46b416f50a127f9eb421c34e39dd2b887a0c3ca3198ea9f3000be2ee54e87427ca386e3d48f5e681e36ecc3b22cef6982626e428930f82e6a390feabc7a951168079f67b39256bd05cbd6c22a537368721205fb90bcd4beeca12aae60574d779fc7fa74bd075c99355dbead6bba6826eaa3246f3344738435bc45921ea07d8c1cde984dbdc650aae6e7dd8f59166f0517b79b053b90ca0b44a99a4b9cfce15faa3a28247e78e79d28bdca6b9b69ef239aa0cc6fe5957bbc8ad4a3d7c9a452f4bf86ba9f8e65f44d464a18207846a1caa0b2d91b1bba8e0fc3d2c10af62b1a1d7a190499d3039b0e4d09b8851b5c022e712f65e5772b351577c14f08f9dacaa954711b216bab8f05b28220e5a6fbaefefaf7485c188d5cb14547596b82819a4abdb7f6ff49981ca4f6ae06d548f03b14ff88945611951e127fc83e5018205ea3e2c0965342cdc927f51f4fd0c785252a791f80590812c209245d989a983fcdef12f68a8a20b59b6111c4b814035d15749252e607bcf597636b8cbb5e0b35976e7ea567a6b3a4bd80d8a610e78b087064f40cd433d6f0ff4b401c15f54a8c5ba8a859dec5a8cde69e38fd168d14d36907b13f35afca4d1014524318a10bb4b74facbc35fbf0585024599bf47a2f2866740596f5cf5ad7d36ab28dc5599306f0bf2376faf2025783703594d696048775592896c8b87654cf2b17ff6e42023b53cae5b8f540eee857d7ce676b572accaa1ee41207ffd70558baba50e08ca140cc99f686475c472749218bca7df0ac7d2778a5fcf887c13f4f89c16b130e4764b21edd5b3dfbbe6769e6d0dc1dead10387b2d4b4f43c7b9546e29fc0aedcacf6ee6cd5e31a9feb2a336fc717dd02160b65a1343eb39b313ae406e7be3e152fab97a4fa2c660967940be10c2c7c48c349ba0b40f8d9fa0d426f50a03c304061a9009e547580ebe2822e000d8f9f5d7806b48eaaf410da06a40768ff0202d6b4031e1079567c14ee0e5b301b4c09b74a1dd6e588b05ca0102c9e4d6615e3983ca7d938160ac6143b944c532580785b7db12396bf22ec651fd7b30151cf6c2282de14a82d718c81a53becbefc44fa243aebcbb6e8e45e6d98cca3d9b187eeb8c57367dd9d04608e1b7b9541ce762b6c4df7429a317feeb8359aad60ac80d89e3e107b9a09d1536dadc9fb5423c3377e1ade04397aba0d8018ecd2371ae4b06b99245e040fe188a4eaf8f76e89c5b3fd44acf72aa7ab3f0160802602d93c6631b30f30cf05c84ae9a22737fcb583cc6c65af5d2f73315d70cc94a11b1cd1c7d6223589bd90fd2f6ca9cf4d3561b72e7c9bc7befa15ac7b4e10d40408a58fc4d47c9458128ae9924b031543b0306ca5b0af54b091fd0d15c410607da60d85c62ac31c6e31de3b6c95a8fa6aa4bff00e800c8689537c742a53a6ef225005eb08e5cd6e5a2b2d581641524c10b40b73929f758651a54de80db3ae756ce26dd6687c4bb6197a1ec3ff1e29c36edf7033487daf96a8fe97eb39dec1fc674f57d82d96b5d5805e854603eaff8cb94b51a9858e57533a1c36f803e9b8db733d4f76e36460e04c7fbaa786a4f1b6660472130dfd2070c3081cb27629e641165cab5b4cdb2e627ee779200123e4fc39e761d2c556be65514dd447c628ffc357152f6a2b75ce92d92f091cf005883d4b18e5664580274f77637bb78afdb484c1c2b0a365d3082a742c4dc05dc28a64c8d24c50d2e1d0fc280a025f28f2ef5ee5fc1c81fc9206ff76be1b745e495a69162695c5677a917c0c67ea56e088dca3cdf54ca05fee43b5287b9e21e421686b40d798096effc4a0862147089932bfab9438dc3236f617a6aabdc5341e6d2215a38dfaff8d5670312b249c3fe417b2d05f5431699044ff435a7a92b9a04e157da3b3fba5bc78e997edc0a5f4aadfa94fa955a0044905e1c74df96c85e2f243166da577089770b50862dc8fc24262ce9c064bb7971c94158876cafccfe54246eafb7443d2025022a690596c45b55a338d390882e4b1d41df48e829961dab7f9236496fa6b939baefdb652f63b823b07eeaff4cce445a74239fbe53645e2abbeb62ce54cf2eea174f27b914cd4830f88488a64af46879886e68528875086cea00e486cb7268928dc4a883bc6423447b8a4d442857518cd457249e203550c9e6ebd46d270b2b37a6fe27aecd34ddd4059a40e4639b7677ce5d467684b66b7088c5a19642d43a7241ea4ad35b8398cb88a9c844b1d506c307528611270805382b1f0581cd4b22d406ff65a0c0b71cab73a38ce2572a93b41cbd44db6a434998980f5016cb44be8c1659d17bdcded9ecb34b0c6cc2918115df7837d924a262d86f5507001c844b0fc9b95439e00493f8f3e4221e3f513434248f5840e278768a9df7f20af6015236ee093cdc8ca69e2c601965217b59a1caffb15abb76d1d2c2c6bf84cf5b5a9cb1831e939b609d609ea62750ad51f7e7e985a851f6fc7ed1096700ca1bbe385578513e057f87d22dd4e5f0286893553f341176d95995f11a08aff0e97d739d04e99bbee06d634360039b3546a7405dae8c9351c9dfc84a0592eca7f588a375bc9ea197602ee83e19c488453de741c16eb710476310f99169c58bd98d8c0b3ccab42571b1f065d57e34961ea06f03bea2b23298112176ee68c11e461fb9b4a9746e8c90e74d9b2623eab7832ef8c92219f77255e8635df59afbc3cdba83583d62f84c20593bb12eb1ff58e6e7d69a4ae41ae762d3de708cd418714a4949a84d33fe75ffb383d7cfe7fd5730c1fa321f53848f56858a88b69476d0eb64199428e0097148fe1d0913ae1c3e462e2c83583b618c462e7f4ae5baf797e1323aa0c86ccea5284a0efc6db277180242e54a7d1c5fab663c6b597edf1809eef906897a9679f2b73e70233690b9e5162802b90e712320df24f12a57c27f94965058dd7cb2f065bf8e18d1b69a2e67a59a4fe0cac0c8b0887d634704e220cba54ffbf18987ed384b4b290f6f8e4e26bc069bdb45a6c0abbaa934b5d9aafb34eeb63b94d084d3e679080fa80c782fb05f6c255c73130c8d8d42690c72aa91f97d22e8fe389587bf50b64bd059ebb86ee904686bd26829b2f65902ae254b9786a26f9727d8845bcd475a84db20edc9004eb3735eb0c844e4b8580bd37f0e83ea0acb33a833105e70ed72cb019f642dde84a36dc19bdc0468114a52e5749a7d6878ac80c444d949fd506c62d7634068029301ca621b15406332365b045d1b439296d522beb16faf03289aec4f47899650be2419da7820d91fd9db8075ce722f3e40d494df3828202c811ec5727a22a98b35b1e3cebe27a18b8def35c92e7ab6ce0e01922ba9ed8540fd00936b0c20afb371aeb3f676c56bf0a1145175640b61789caa5fe42fe31ff8d3cc6d5260ccd2f869cecd45827252d72a76ace3b9834f169f9607c30cbf70b0b607e7f5d2bd45ddb84e8da57f1338a2aec63691b1b537733432b3022cbfd55888551ee5531f1e3f566096c67ffd5865bf455a87b084eaa305acf291ea2bd008466aae41a6f1654c3ca64a58f6b016d27aa006543eb869985f82d652bf074dfdf2991086e7aad0f65a57f88792b58995db74f7cadd50e632b1266e97a72baa7ddab453f8599504798279025b5c5797d639049ecf5b174a526b91c28d17ff08ae4a5b426e2176027581b3098e8938d911e69f22adfd1a47bc515633232f4c5f8ea8b4c995133d500029a8bafdda62d03ff75937cf856bd60f3bcc35ceba38f34a934d41f28db30b185049a2b8754958d9b360cb8c303c3f461141cc6d27aac58b8f62a42666d071b2acce0024484f21014ebf4ed2f13ed12db5da4f11080fdb217318bd425db4b5baeff8b48a409849e0fa92364e716b706a2a5fd86fcf605602f3808e8eeaa2dd437be3631c2cbc822a4578e8664ff7d74269d14ec682c3bc31ad761aa3483b3a9f1b6b880e8f52cd3835fa6db463925442d46c347c4d94e82b9e620e4f41dfbbea8be19b2570e3a40f66966e42927544f033a51d7ea82845735d3f4b33f5c7954ce6d1272a4d0070117e164119a39feaaf6b4b0563b5101b098298139f5c6f7fd03f9547e320dbf9930d8f3bef469cdf68ff303560a3a8d7beefdbee87ff2152e62807cac116bf22a944b6e05f815c53ad9e43fe695e37a38e1cc83771e53c00b484dc668fb80390f1fa2a30030d521bd8e0850ecfbefeea3baf459bf0d2426ba2e1d1c3ded8a8815346526cb9962b646792a6a629ccf4647e52926d1241184cada5af79bea864068ae5e482719fe6452ea6361385cc926d941e547324731cf27cd605aa7e94cfe6c1a9504a6ca0e7f320bec8d39adb6dbcd294872957840d793f611170e36e095307b51396e514593fb51f54224fafb2d6e0328b271113dddbd01f6d7869edbbbcdd72185fb49d5d65247c9788ea1d474a3a58f8904ee0ab428f9fa07f9d5b9f6d5e989fa6e48b725f3ccc06694e44655b1a8903d1e31ddf25cdab6226d6ef061058180ef3dc8d38e059802170a7c85b813bd646b230e3ef46d725938c11e48d76d33813ce89460414794f7cf7eb991bed7db9decaa87ef370dc6d070fa62a5e82e061719a7d194d8139729ef1a3d661517d8b168fabf9a1d46e57bcf178f6ecf6c01837e9f0d2cf3ec4380cfd756edc480e6e16f71f790211741eae5175afc033718bc8daf01804a1c148f5f893c4f170e715e088bf4050fb91ed6157de90ba720f7b7a3da386eb388b2994117ca4d70e2a7d2154e9ea43abbc9154903d31193f843a98f7f5666df28364540061600fd184a0e5bb74f02febb225c77a9fc2deefb98b64b4fe12e37d737b9bf275ec91217a7ab26cc8210b2cb9c6012425468d286111acd726594a5634bd4d333acd1549b3f0de2bf485923c4db4376ccdda8bae535c32707885f9e0f9b6f25701cfe9e9b0b148b7e34e95a4f845cc7c9b50911db6448347c86aad61aac8d57a776a79eb2a444cd2b42b741677cb14c24cb32da218e6af3979c050ba3d34ac5a72c7e6e4d4ade17751fe089baee70670343e5a3446f5c3ca7419dc3ecc069581208c8bd42bbac6111e173364343c510f42164647b3e300a9c69727388c2adac7339d1308a66df31b233e567c4aea25c308e82fe69b145d6f8015182358fb7b0cdbcf09910ddfc42b273e649f3723a1105fb8e481c2388a400e041e83485bbefdf109c48135e3b84a31c24ebd090ba89a2790d2b9f12870dfac0f59e4e45b95a44d38b5239f8d8185955290d21dfe96d5df36db6179664f87815aac3d668005adb957e7fb66e3aba10552d106f820bd83ce34ac19b34ffda0b19bea54711c0b5f578968f512c317628a10359c3b3fda9616b5421debf951be9c9ff3e28d1a451a21aae1f7c68494df7b4f04fcac9845d6c4b957794cb9b415d076d682ae448511e24827dcd18a9c7a2f48a5494491bb684972dd5d5ec02c2eac11a85e93b9df36f9c5e6c16a66a5625bc937465c8ae93c732c0a5170802377f983c0bdf7beeba636147f1a805467c1f92d7d14eb0cfc4a2b4d2cf893ca6803a6ffbb76dabb82b3b7f646a88cc984393e560afbe6bd65f59bd25ca332268c0022428d3bdb7065c19c149c05294d2e239bd45bba1246e3aec4144d995896c74b43fd4eacec29007d5547427274ecb56b1f186cf9871c8ceac3023036d4d72842fbee243d382b40743ea2cff57832af7ee730b5f63e35cf3cf537e781366e11e0a3baacf3d8b06762b918d5cdb1a48efa5271ebbec8825a39afc7f4a034c1da2208f38fc62696599a9f7bdab06dc531182394e7051ea04d8f77b3c753e3a0fc6165ddc6be685b9264e8e02a1132ce3d976466ca6980074e8cc3c814b9cf1fac00c80e7f71abf06ea7d63dd318d28089112393dbd10a1d7ea64e40050782575fac85a7333549c43a2db9c29c71393ecd662eafa2e47f71c8d7ceb89e7c18714eb816be45935280ae301e543895e19e62fc03994647720e35fa9ecebaeece016642b72b43fbeb38f0a8b2628b71533f5dbc7c70bcb6d8a1c1d806f2dca42a85652c175ff568246fcfaf99dd04ced17ece2158094f055a773e1033a899069c8616fa72fbb8acc9214e97c0cde0b06467f693570c47f84274f0d0be92864ab5d30630be7c43987c62e1a17cbf0f6cec766c25d430e3e016f9c7ec492742c7be79a8ac99ac6eaf189e6e2f9a39b9f62984f5b0a67d104de2dadb643cf4942af37dd2e6f629a5ea09b47f02f8601db9c87b97ed9659bfafa3087f0725ca25decaa94640dbd4c5085741a74508f7f84c6d15e5845724c28541034a4c5f657be16ed87515b132ebe281d9225850e6af947e870dc5e8d4c5e567a4fc9f0d4c4a3ca6f2c96f94d88512bc1628e170df2d19a07c3e30445dc1d284e34e6b53ba5bcf38232d7210270cc8f21aed202ef5d68cfd41806ff1f9b41a131da4ca3570247ae073aef6836e47a00f7ef0c50389a9a9b7042d9397973a739db2fa5359128c7ad24eef1d3fd1fec3dbd9c34ccff287fcc5bae13142c3d0f58372a01a356611480381a11b2710075ad193d20c96edbb17041cb3c196b6efa10565a81bf64a120e3443071c6e6334ec6bc1c84ba6f5c6baa9fe9f4665aa6312d04c4aa6371a90cef87c3561383f87bf434505256ead36d6f972121d97b8c2b27b1d25e457a0bfed709b13d58123944b2db22636d6c8718d1a1bc24be3b5f2eae7797cb11cb1cf2ae591dac1f21f38c3ce0d418dafafb471bc71a15dac231fe782ebc1c09a7efb4032f87066a8810fe619d1756a8c1e97a319db1f6c83353930fcb018c70598d4848d3d427f23927395db000a7c1f3364bf29379939e261b2d414df4b060378bc4a4a34521352b6af6170dd1b2d6dec74015d8e58454ec35f8e915566ed256436fc6c7e9d90479b80498d21e8153b946da59f7bba6061bc9306206690c59ec39460645aa30964eb8aa951910b13d3d892de0063d5d6fb5ce09d9fe5c03df68937983fa79cc631441ffcfb62204c3282eaa1b034bdc56ec06352d073ef984bc2bb5d17e8cd4356a3271b637f3647e5bdcdde0a674e9d15f10c87282ae8148da6206f462a56f6ef27e6dd7051f6240f3c794f63b5408a63559e72f23a4594e917fff3280d419284002da9f9354be3f35dfb16e3b2f9afc5174e415b0ef479ee1dd264d394b88ed9f983c20e72ae94e3ac3bca7c2384e2eb503b66cb0710f58eca44d6d86c1d1505c9a4f3deb94cb1ade582f062ba79708fadef8911ccaabedb8738d51d6cc08f5aff227c58775b498f80f50dbc635e25800245b0c4ca0be47a31cd93e910595a6e5bf46222ad2aa41ff549b3c45b3d3ae9e713c68398505c331aa4ce6fda3f88be4151671b3ebd5937dcf2afa253a24e3840c65f89ab315b4ac66943ac17b86858f2501b649724afd902e68bc5f6395e6ca61d98b303f20bf61995ed61ae339eb3ad8a6dc9f8feddd10a04b7ded1306a7d4152addedf8c561be94203d1e985d908e4331eb6ce94754a25cdc3a9cd606fa82a44e38aa591e7303dbeea20560af051ae222d4318697e31697d56577a680849dcbc16d9948a85359b7c949bb9f6cd9f3045547f0b5651b9a2c79822d131bc99454058da8ed5d1d34c49a88159f273a28529ecc351ca19a82a8ffa3a023426f3b60520db70340191d4261c7af26bbbeea62c29443ac0784749a282eb776a349153c24079326d2dd3aafbeb46c21c35b39a6ae6abe6d7c029f75b4ba641634a02518433747c46a89db4abf46391481769118d9ef50e51a8602b7d17da2b2396cdd6ccd2ece4ebfbc7bd50cd20e6079b9b5749d91d25145aa7f7cf3a456785eecf608b09bf4990355115fe020cd5245934bf2dbeb90a0ff32154c9e0548a4d206097ddbb6137700c15496c23b896c6e0ecde9392e2f4d5bd10ab857a7b98fd15e17d6039c62a160691d3ceb84fdc71f88382502f025cd69dd5ee2b23676af6c86d3691f597bd40f56562502b2477c4d2e07ea332d1a23be58f543a0192f529fb8a1112efc20378023be904aea2447f2c351b14c334a2c8c5601ff392bb0fcfe220412793c3e9cd66a5f714ac32dac4f24a7edfb9100424eda96a9840959baeac8615fded3b92d66d75115b713df83847d4f3c1ec87cd400e3ec6800d62855a5c2e1e630e782ec825b8309168baeae3a6ff1c99e002414c49b2ebde44b0f3c08409636f620736586a59cce22406031f906599d83743a2ac6e16e59ea5ff69d666b93df4be8cc068b7d7456aa6d43c8723a0a6b2180035392cc9b54c3988f060ffd00c2239ee33e84f6d1eb416b14c71600432610928653db01477c04bdee575cc23296aa465ee34bf1d10a300a74b93dbdc18631161e0260746cde0c336a2be4d38426fb9b1e06ac2cb1053bb15f8f3e2b16bc16fc55de0d5afeb8d52bcfbdd96c4ca4908b4bb03054ea4cd032e56be865a07f3e9dbd5caffe44b9d05cebd354bfaa1b3c26d5e8506be10a703d733bc27e0e08f2c1dea97dfda0d52f116757ee255fb51f7dcd3b0e65cf034b809ab4b938716d4db7feba561852bd98504f64e3b4464605e8a2079052692b585db917fc89c16eedc418b5b7897c78aebd0c2b44aed9a339d77697bebae574fa1398a9b94315e844a1d2ea8dc8027a9bd5860386959bb29564472fffa9def661c190c128d08c6fe475d2f4b4eb8a8dfe0cb8146c727a186a21225069d972666363368c5efda675d780fee39dbaddc9a029b0581fd5e7623bef23b8a27a4870f8cc1836819c3091a8f4635bea9c1571bd58b2883a9014785bb24142459a6e1d5b55741d5b57e3d2f361a1ca4a91679081ef797bfe0be769bd07f887c23a42603fda01a3784676f89f31b425c9958203539ea07ffd161b71192bc2f09557ee10f2c2f722c8ba7577bf21998e91e3bd17a440805dfa0a8f2de2a16c2ad875af2953de1700ce4e16d58b0e5cf5553ed1011a6f578d9c6366d2c7805bb0d61d26ff196cf4a44e400439c21a8bf8adda4c7b3d18f6773baca23d1d97e04449f58daddbbc79b569383b4eec175fd87ad2b438ad4930f687c4394c218f92011aeb590e9c8912904b764674b75471bfcacb974672aa0ad11cd75860b8f6ed010b03f992d593a87100640a2c6b5fa172a033008e54c0a012d1b3aa0bf9c855e9134b74cc546f11de413c0cc8e6d8d9b13ece8a71acab9a11d8dbd100e01fdf2e39a7dd4048884f8921be88a92a314d8778289ce9b6c46ddc226138084f5c21a20c48ebad3c31e1379b3462d6c8230f03e9aee17029c63fea17e1e509a1c606ddb0b843b183d7e9604b796f748d0171071d616fb20badf059fb903f594fed7307778ec63a4b5c601d19b115c30252e16b1c08e3b8fa605a12f3108de9a26c85260e5b0144bef642a3431105ea5d18dd20d3a3be08b21e4bca5eeb4e2f908249e4d24e9309c220a9244da728ab081ff68e44d44863cce4226cadff159c9e54d6b338a4bd0d1831d66ec292314bb96e233d7834fa3efcf1f4cbd0c8a0a43405e9c0cae27f57f210692f0f3e87e0bb1bd3996808cc931031a5be6633b96ebb51b8102df0b2da28e1c0baa6828222f4c484c0219783f0c6922a126c5cc455321737b42b67eb5eaaa733036d31efb2d1931285bc0adafa7edd0e06052424f33052a1a812a4d5206c648b0e58fdfa6c31f9cdac4306d80bd9a7f4a9b8aa73f14850479d2c2e52c9f43840491956211a56866013c1961fa5898713ed76abc767a2715fc5ec5ba4f6a2f395afd0cf5f4b04ccc7eed332043210cf58e23eee73b981fe72b35d6f97f99e7c9001b59c28140164365d5718e685d23e83970d10741ad9d0e11e056545e896155f5c4bf7f7a7d0b68dea2bddc86afe3504f9965f816b0029806abb02070e69877b2b2cbf4353cf79a52e2f7c89af6861badb940aea8ac5f926ad8b574f84b6289cc353655b94f31970fd886ab333f7505053293f2dce8be25e86e31013bd8fca40486db42a2ea28d49a963f44faf7e3f5d042789709d00048dfb300a02bcd109d782df369e5c23def633c8f32af03d21e39dd40bfa0f8a7bec52d1ff7346f0c3f0a8ac60100e49978c362db52e2017a05feac0dcb169e1565582f106394e321effd87ad7956803b4dc3e09348b099dfa4b3e7f7ac0bc5a4650b764bcc5e9bb0cd57eaa1fa632846365d50e2bb6c7a7a4d95653b3d09549479c12ee3a75abd4bcabab74ee83b87641b747087c18d25276e08fc4deee9069d916431f39e661374e66064ee0beaafcefab35db6c38082421e3aa781f6639b6ee823e77a983006212b47f8dbfc66b8d83686a3372bb73dcc3fc1f34b66520a397ac97d5c13e0fb756b1fd8771484a62958e119a66fb471fd7dde2514353065a2826bcbf33a93193db1230cd860a1cb47f80d110c7438afe25c563865e9bfadb9f7f3d5ff2c1b128f4fe8e86056dba2302a4c7856f651a1cc79fc65f8604b69f4f12331c78f310748daa520804a711995d3faeb0606c6c1e12e3b9de424e095b18829359cc5215c57af356ffc888649926a6bb66d51c03a9c85a1883bb6a85e35338d4149476051d912309a4bb172fc06bc2e5d21e2113d7a65add1fa54e02d9a7186686ef956df917190585cdc81af11170558483c1a17c62f7995cc149e1a9abde09276119d2902fceff2ba9db11e024d3e04a306835fbcd9cdb35f40cbc79602668f1c51086bfd7f76cd3c0890a027081fc7f4f625d55abf8dd56652d628f15dbebb3c0637823117996896db7d51cdb252d547522f6d3dc9cfa2063a318593dcaacbee3a640487f2b5bd74d1cd7ea822b444f41357d997d6ea5c49a4433b4b6f5ba3e01fa4f79a94d5d5871dc922daf65003d3706b2ac2661d18058a2734029bf1db5d8384415be439f7d4f81089a36c65b2102893eeb3047aa5c4459b363a6720bbafc68204a0557c1928c67462ef5c093e32a8731bed3fa007b8f9a45608d2c01ccc383f229f49992c4121f8ac30a5816770636f3c9f31c4d882657cea21b35b749219635c9708a075cb4e42909116e1722c15dec7e83608e1437cc41928e98bc9ee8540a3f3a1e07e500ac680d38983a898ac0e86ecd109302a10d998707263252572f5ff2280be10604e6eccd363ab0d3e2b941a1d6fd0ee2c0c34cb272780308c9194d950502f6cb2aae7fe8f770f61413c20eadf86f11d22c7aa66d18d50b82810e33f050f41c1aecdf5e45d4d17f50628af36a687a21ea86fdd168089596d1f4d5ca0b3fee3117c120b231071317c32b49a0b287bc88f60607d28c8363255cef64feb1738ee7967296150d574009406f6ac79743bab4387dc3a8054bcc0635cfc30ed486282563ce68389b32ebc36940f4ee68bde3c77e1e4abc2e5b928aa0535d17a78c57483ed6d6d7a9887306074aceb0348ef8fda39b3500aa1726fd78462c7797aac8912ea14c017d68391b58f4491ca0c6a5c99d268f9ecf2960042af4a32ad76b3d372188fb57f9708744600f799efceab5cb0fd17ba93c20042489c33c8365f543789523baf1343e2c21ee870099da0701a221eb245a40f9020e4fcec5a89c1cb108a80f9a78b0d4964fd65c96bf1dbb10a92c70cf08b300df19ef969a9c74116bfb65218504d35c649daae28e3b4c1bbfda0b00202c87d789cabd9aa5493ce54a25e60e9c5443d09223a82e355f722137a84970efb6011b69b90d8cbc01c28ec42244bcf8d3d453b98ec102d82217faea1c86d32cfe72fdc5fc4c232445f443f3ba79b6dac3af8c304bab5d63de46c34c114cec0df7d77304a9aecf9637e0993448cf5efa93f6ff008304407b38498cf81cee6a5a37e061f7fc0b1a5fbc10a207aef8b98d60c757dd75e0b3b3f93f3786c2a4d6099459d096e7122d1c5da7f1875c455d54de103611c738d6c82cd572ae62d8aa673d32f017969ff401b91b00b6b9f1be25ed18a61cd00624a656096874328189ca3c62d9c5a8212032fd6898d1555a8e7c33b25acbad3e368c8cf674a25fe48b9a2b50a4d45488fb50a4bf3a76c02b94399fd043936aacef95573896d36cc8595d0a3fb8174de87a4b299014c683d20eeedf3991b6386ea15f27cead6d4453d801e8e1407cbafee0ca560303cc2fc0ef41e3a5c8cd585fb8b7b8487c3a89c476ffeff9b3f7dbd15d7990780b7d6867df9be91ac25149ebec9d911ef0a8086faabab8391705bf2953939e81a04e895d37d945721ecd29b7b11363f4ea7aac9f36ca8af2b5f1051739c35d5ccfa5efac6c615b54bbe937b53d879b4551ddaf312e40c909ac0aa9d9c968cf88f392be34cdefc320bab3afe060560d5cf3f3378171cd909bda105e52be127ecdcea5b5ae0230cbba97704467890503b703fffe3eff356456c2738aeac5b753d7e63a4e001ad9779b81c313fe234dba68f94134beccd0a9b78c8bd5600e0e7626dcf371e77c77c93a5514004bf4c08b1c762f5e5866705e18e9ce108558b84cd96e0da85f9481f0ccb279f13f8e0b02de4c600fb8f99b66892566f21c682905a42c9d130486362687a9179be05a8343c37eef84044db1107eeb5aaf62a3f2c58df1f0421b57af5426711169863ca77e05e9582fa7c202a5177c177d4f409fec316946b7ef106ca255ff3342dac740741383edb7eaf75a59b6f9318d4e22e020ad0f7f4b94161651e5d7102511412b4f647fd60c4c8e97958c55664b9df7cf86cfd59a3002a79ec9e6fa97e27f048714fdc3e658688201848b328b4ac2b10bde733b48b7f7a395259cf6aa1cfc408dad0268ca7fa0c5023443f83dcd305b50e551d6a737ae458821b53f173999b238eee54baa2cc6b9cb91f1a2c0a35ea2268870c8d62f721051cb2a837924b97a29e0ee6abcfd140ba0d95cf8f7deeb8085014234b75328763944343fe989b02405670d560846cc85fc852086df7106eb2f43f9cd279212a66fa6cc805890bc412c0e573445fd7c75034de9cae828b2e1a94682b7ae8022732bdf6f73a69366d3d007a41a0e2e60602fb4f649c1fcadf6f11a471daa1baf6799cf7fd78c5b51397d9d64bd74c904bbf47c1516c0fb3a3e05a9039aeea810da03156fcf32ecc43f572b5d9406458efae44501b64847e40a025b50dcc3314ba234d0564cab01cf30c751babaa3b438f33112f6be240ae631e231c4b5bc799ee8b09af91ae8e9b08d3b4d7f892bddc7f3ab4db10e9e963c97a18dcb9a6b18125123b48457a13b77d1e80e6f16c5f6d5e32a7c78e4b69c75926eed7ad314d5643ef7ec385d0604adeaab007c438d7dff1d0e1bd660c6debad995e6d630c0c890055cdd5c0d847fe33cecbb0dae3b14838bcf20fccfd431db33929e80fe0217ed066780dc9d2e48974c1fc0dfbd0f74a4a52346e38a3ecfc6c9113e2800bc03c310cdba61c908690a22fd0b251933e413f8e1982dd014312780f62b37859e440eff65924f0eb5e3c1db078a96f9ebf51937cd29c34621957f165f17bfb1f3e59fadeffc1af58e2187d1fb3af04d99c74a9533ad7e8df67a5b06622667cc264b547efca84e1b9b1be2c9a3a76ca6acd0e93818155c5f167e2b6dfd06afc8692897f7609002c32ed26b58f30f6b418312c07f65a82f5cbcaa9fae8583182d16b9aabd61ee326de906abdd132c270fea86349eba9375335d3238031fc4605bd53fd7df2a14b4e84e34c6e3bd56aa7c18041dcb8f712abab866cd5727b9021f88d6a7aabcaa0ca8f4c16ddeb2a9f37567fb12871ba245aa04548a3831623d01b2d3b0ce68fba97b49e7233556b1a5a18d1de85cd96fe7a2a8db6072e101be11fc7b8cac8320b77503edd987e2c8365c64526dc0c7ea3263e3acb94228341a7fa85b38df7fb500a6b5644c64ecdad3e9685b2aa399b82f9604073d8b5d000b2d3b055759ed658beb4d9b6fb0d31d83b875d091b609f21067be7a869e103ec37c460af1c352d6c80fd861aef9d83ae8506a0cf50a3bd73d8794be50808416dde07caa1ef95eaab030fc2fbf31bd5ce67f68760214919122c35f9e63d9bf107b2d427557e5d60a451e63d6ced70329a5e6e3404179c7799b7e8a0df952170bcdc45c85ac037e587e64bcca2b6546957cc63fb308dd26b81dae1d2fc72b1fd955828adc059b927b35e9da67b423f065f55b3e477f70430372189752cb28759814ce71588d397202d4e8e9b13c18ea5e5988cf36099e62ca60f3d78ddc44a0c8919931eaebd66bc616fae4f032a882319be496a7481c869b3e13bac5a63c390da373154a5d758734d88a41604d0d9f6dfb01b77649eeae55971a4a84368bf3e1ee393e4c25d44df71fbbc296320f42668326cd385d683510df477eaee9ae82ebe0f909cdcd660188ce0aa9f2c12c8138e3f0132f0bc8b4b38b02354aa48138cc1e380c49ec8ed834394d239d506a748821f36df6fbfbc312e9df25ce45c99bd02a9e358d8a306c2150cd11bb53136f24f92ce07a4694816c812c0dd09d41b3af2c226f0f129ed9646cc8f080b45a322d824a3892e9498d19049b80910ce96780fd4b068d15c08aa14aa9cfd9c117599836adf6c61fb4fcec0e6df3a912d513547941e2dd85508c21b2d250e0f922586f78649804fd84c2ebbb96d217378d751aee156132be01616341828e4389998261050fb83dc6ce5690acafd72922ead594d87001828694da02c8ce0f96c6a048197896e5bcdcbca536324a412c3ed609d46d5e60d1825d123b7bd3487a95f33e50b8592d42bf8f2c77a9896486e445c9a842ac5f708204a88e485526fac1c1552ccc96c397170fb3afb2f2546fd5d380d6fbc6f6483c92ac7014c02c5eae4aedfe71cc76bc8f93da25bcfe7c6e6f3209873bd8a008021908d2d7b58e143907164c85d89eadc80db7eb68778c32ef195ead796575976aa829ff818f3c581d1bbeca8a5c8df41a46ccbf09480bdf3cbea84e0bdfdf71e81b16072a38fb09ecaa8902937d65cda81bfdee8846e587cff9d8d35359ad3401852c105b18344b9936e0c870517fec632a03ebe28c39c7d9f36349b0ac21d9ec48f7bc8a593f86a08abf30f94a486fe54dfffafc25415233d5a23acc7b5568a3a6614d8bf3e002072c9120acb7707203aff80b6252872daaa2f828b327c81149d494c4a03fe8e6e26364c81e47fe766a654088353fa5d45bef63cb45b5d4fa487fcd9f4021fc5a35faff92254ceed26f546da1f1928548110c8185d78f4519e07506fd48c3277111e7809c50de28ba0740ac6078919fd17e8353dd2ebd55f5d1276466df0a9eed075c0ddbb2a4522975a3e095468c0aa4fa12a5f2dbeade073595a957137cb7dc1df68562aba2fbdbbc7a6909184f2772e646e36e41cc2fe2393c08d1d7b175ddf487502f127dda3306725df791ed36f30a3fcfcee4a39f7280e38c666864766be8349d65e3cec1041655987df1fd105873664621e62619c95a14454f52af04bd0c67b1ec475cebbaf748aa0df8e32ddea0af7ca42c6664861276b5248a1604fa7ea8004f75b2729ba63c8b285ec9f9b6fcb91a34b115297e9dc48e7305b010cc4e9497f8d7ae8900da6a65e963876eb25dde6c139077e6a5670819bab61e21b20af02b83c19863349c1579c7a7ea7e296904afff57b04dd6e0209c5b7cc478bece93372df1920093d107b463fd9050deb6fd426f977ad3bb05e4afedf9a4f64f0f48e98abdc84e27bb4026dea06bd4b0792147dfd25013f6f7412ad26d94f48d9be966dd6a0c6f3a7eaec751296b509f48aefbea1f6c14e8e609948f58972a7a12835eb40288047a486e1889350273ecb3c49598ff4b79707b3cda42404ef5d93ad5e16974684dadae5bcd62227162e2503a55b5cc90c8b105c18ce92698dd0118a4da3dfb456e484a8af376b91fbfe2ed49c4befbdc75d8c8412780b48f01f9d04bd18092ad81ec1f696172e70d5cf6a4e8c1f2bd0c23905d3a9248e2b98c27f71f1150242f9e5420fac2cacf627b424f47435faf4008843731446fede05af5f802f9e0b6413c2670cfe74e122cdc62211f89cdfb65473b36546ac07405aac3a2b4e0519ead5676decc2be7a773397af192e9ecc79daa8c41b9079db9bee25d35ae40f62837298bcab4ab3f59378535c01c66828a732dc27c10c7a0416a1b54d1989e006ca14135e90238823100fdf7ca3867356af0ce0e9331e2b4ccc546bfbb26797f4ba47962af288747ecb61c30ade3b19aef3c6aadf0f846fb41619f7279e15c5e2acdf953d3e789f455b3e553c2b80d48b35cbce6295e2a8b76f97f8c1254b70600c323a5ab58b65e1d526470034f58b3dde198cfe02e38e37f9e60b1499bd516af857492a6eada92062aee55fd506f4dde4c660b9ccef4571cd03432e0151abf115bf3123c8ea4e5ed53ffb1ec9696fa309d08bff2ca1423334af5ed1f76a2442cddb2b4af277a1776569ef45f020c1bdf46ffca6882b07176d2a5d2b15d1157e4383279f8372ef3da4a4bfc3127cd176a0d54149e17672789fe5153a0530ce837b642dea1b6ea49a54794c630ecc6c4395e68b2386924907ac5bc2cc3c9db16bead0e931be03d7bd610e4c0e78c250f4e82a7aa8c1a695d3a3a6cd03261342ad9d69d74f1b060590f22b9cae6dec4a4e6c5496017475039a9716895d308e3a5207a5f1ab841e416006137f03789f611899ab8804af4174e7e6bdc0ab755f6ac44f83bc747138744065ff1f94735707875005d077f4b59175a70093ba25ac848651b12b5c47716ff8023f5c04199b2c217b37917b4b29a54c0132083308ac08269c08de74c925fe0007e8fb656ffc86de3bef45b542f84a960ba8ae7313e4a686e949abbd9d874da6707e7355ab288aa2484f4128cd375d72937386cd9a1fee8a496993375d322567b0d7dd195be9ecef54eba4b3adf5ca635fd5f2f4a03af356144a14734a4646a55aad6666683a1a1a9a4b43935332a511ea55e6ba924c53006542d56986cecc9c54a8959869d0a83468501a2b1aac99191a1a1a3458ac9a1a1b9b1a35686868d060b16a6a6c6c5aad9b5651a66439c77c9338382e5775b95caeae238b688046a3a635e79dac1a9b56cb63b069b55a3735705cd4355d35705cd3e5c2c171b97c247374aa8e8e0ed5d1993ae348e6e4e8e8d8b071e3060e1caf170c16926498a3337572723ea8afa3a3c33d06005461dd841eeb83d7db30af623b1e04efeca9e4dda1a2e3db412f0ca92cc7b7b7aae432c43406b395ded9dd9018bfe257fc8a5ff12b425d67517b0cde74c9e515fad7cd976c72b06b4f6a4130c463d357ad18f40524d1182ac7915d25d118cab1db718e393c007e600784123df68fcb63ffb6d01776cf9b9e75fa962c17f01f8ebeb0dbb169746c1a1dc285cea437bc306b31b6a6a79c7a1e5b93ac723d7be7d3e428a29e7da3cecfa80354613d6e39dfe3d62308348514bcf192addfe4721ea25465d7b10f59aab2ceb12300010838d23393938f757ee806366ae377408f9dead81ebb8d9a8d1f7a1a426997d4b163e45592985cae92562b2505740ab89ec92140686a1c925461583cd2b145a66e4374c1db10d117be8124973ab95c9519f50c74ec3a53f4cce4d8758e7472594967f68c3ef621484392aa6cd2f0506695fe4ffc3c763bda7821672d1a09dc909f9ef9631fc08d13b9fc8690c03deeb9692297384b9f4346ce18d1c5b18a53f44bac423c729a4234ea1decd52929fef40ef69351efdc74c9a05d2a6d886ea8e30af52147f30755012fc0d6b31a577cd952d4305384dda95e4b1b22f1a6897c6b2b2c3aa693a32fecd857473deb98ce13fdc25eae90be5c2d79ec2ba09e59b72192c1e2b1cb1cf54cf411e5e2f8b94e8eeef0d8b1eb3cd1b16e3c05ced292da6328b078eca50dd16317c7041cf50e15c5ef86e46337e53cc65e7e468ffd1bc238677c128f401b5228dd349167ad77a6e72c81533cf6326787c79e13d433d1b1fbf065dde1b19723198f7d0ccac125ced263af0b00ea1decb35b2e57495fe3451263478d41d8c12fcc5ae40804f5ccf5b8bf243df6214755461d93270499ff91de3bd883e87890ac925d862d1e82344ec94392c821471768c9d4cbfe72f4d85b0793247416b51618d4e7e3cc39292533a082fbadf8049396beaed31a463d7ba1881e48485fd7c8de246b93501793d88e0401885fb0429539c6999c749222908b4d9838c13eca865c8a40a20d9ca368138172982fda2819d217c674d2f27e594267a1bf42b132f480c64420d1f6d629c94112f9c716b91481deba084463b489edc98dc62819a49f8a184463d8ad8b5668cc73fb038d753ea405f736483ff552dcf22291c845ccbda564d8792982c95ecf091d9e3842a625c0cfc190be3c0f9cb576ad90540026bbb1049e49bda6708d98a8dd026c50a46397458a3c0928500bd4b64ff137187a94cb2602e1a6eacc1ed5074c4bce4095f9b0326c6bd9470f1ae3b95122fbf0014295d9ca833ba02dc0d6c198867e2df53bc286c89d972ec42f760c7499ba754b5f578ad9b7bba6dd42eaad8d5fd9f3d2877b40ebc9764e080e43074f24261bf6d58e5e92ac1eb56480fdfd8d9e7f26b22502759307a1b5f6097ba391c72199c1e4f179fd2c58670826c71ec444620c5ec8932c5f3fbb8ec4e0857cc912ffa4a74a62f042a66469c159659894360a17a4a338558ef2d5d8afd498e9493c799f4e33f47a0abd86b5d2ae14e8dc93d03ebdebf144ed0aed4d5f18bcf0222d7dd9fe1bb9ac4307cf0a7abc7d7ae327a44cf32a83f9a3ffdedbc3c7932ae4d2a914f07390f423256cc2f809b0a58022b30b21dae72647617e035ad3690cd18ad018a2816ef2f94d5fb7c847e85fdf453e2e7c914feebbc807f73bdf452c4cf13c3d9b3c43b60f28e144045fc488e03deec6452c78e95cae4a913379b34a501e40ea5eef4caf5d2b256f13fb705281890e7e56da797a3891400bc403132699b1b575ac514a635db44253da5c72755a21e69c135799a579f644e2d2436d42994f3a05b68e4d01d58576dd08ad56af649116126d898c9427d922626d0aa1129a7523b43ab688d4225d8bd4d88166494b37986e04052248628906563abbda2fbc286144ab630b89e6935216da34621313b576bf3ccfb2fec3a09739042d8db540bdc3dffc51c17c2306f29f801d85fc13dfd057e7df67e70f0ce43f613a0af94dd9278f4a7f923c2f7a1a93abdb49e226b3a01ec69e908ee7bb5cc56422ade5b17905438206251a424dab0042714989b81835f98401682e97a3399acb5122ca85e6a80c749353231aebdc64327d4a97cbb34007eb29841a445f56b4f2d6dfc68a9c7beb1e98b7eedd68cbcbe583b4134f63d43b54bc7d89819e3a14b9923456c0739c596cb5a79ece04cfbb77b0d7530f366271d3ae5be56cbb77f0cf39bdf6a9da1c94a8a2a767ab98a71084f800a9304b3616609360fd9abcb49eed48ebe0bd9dc98ea5053cefef96b40cadc5268ca5058cfcf4ef739c41d03b9084b02582e7a083240926f7becf1d1cc3d1e4e0e87d267c2ff6ae081dd912e15eb203efeaa705af870513b97cbd3068b29febe49e5f999f862c1c66ec5def5e5180e749a8ab1554993ce8e4411d8327b4886ff2983c9ec84c1eb356a193c7931a758b7986f29c643e7d40fdce39e79c737618daebb66bea7625742d100282045f9d005e7d84071c7df56f27b06cf9fad52b50659556bdb33d7a74c9c2c8092192582c5fa1f8eaa710ea1963defa88b7a12b3fa37443394b72290e894355d6d4de59444d45a402a33a5285417a9bb2bdf55225c667de908ce0cb10546a81e84b95110c62be54215995d25bd5d2db6ba3b132e76e34568a43e250ced158797f524f68ec12f1b633b28135bc753abdfc92de3abe1cb0de2574c9f3af4a899b26721721c97d89bfc6ffd4728052465e92af8acfbbfc8ca05f8e7e60fef3bef366ccbdf7563b1d08bd1789bee84dba475a72e7e53d3a9a493456fd7a4e7d15d4330c9e7a37de2d370c955d2bb77b74bbb87bbb546e50eee62e98d64f20348713b96461d64ccdba80703e7cb086753c3d68a99d6dabf550d68150f1c11aeab892cbebd7281b3d75fb894ae292a8446362686c89c66c334fa80c74ca0374b58ca1b24b65555e5b292adda127f4122911d198b56fad678b45a52a6b09011d248b4c9ae7b56d55262a358c92a2d21156de924a6280bc2a5ab19262502eb3a8f434bb803c2b60eb983aec1d59e4851b60728f2c6262d548ca657e3c36ad8e257c385a6ea4a7b7008df475529352bf0f0f9e3cad3e7ca99385892f79b250f9b203a23aa5082bad6000f97c17011d7dd177115093a74133d3b3ce59ab9e794e8308f3d57b48cb571205fa17607d99815aadf628b0c4ef6f133c78c209d6bf9dea78acf631599216a83fbf45a0762c3188e97c4ac27cfb24ccb7f4656fe7f5ce5720d4be6013fb62f0e9d80774c59c5ba1efc8896f0fd2b2ef480399005a966b6c40b5e687d532b156539e7fd828993c66dece69e79c330cad652db54ae969f74ec9527a1a7a9f867495ec55500ece3b7ea00ae3a9d77a0aa29aa409f38ce95532a94aaa3014e452758f74ecda809c864e9ddc246f0dd03253ee83b44cc6a9c3dac4c19bc294d31f9f0fe8d431693a5aa2b19a1aca8c8ed5b0d09127b2e6a7a64aaa31c255594d925195d9d42a0c69feb041327950ff54388c036b6a34f6fdd4b0d0b1af03353fdf518d5195a170a8dc67f4262f7347f31f108d5ddb1743c7ae932b45cc5da5a7b99a9f2a331d5518ad32d39292f9e3f3993ca89b7e6a7ec4dab5d1186a89beae938ea1cca849793167ca55994ae8a8ca54b80a5baa32955185f9cc1f2aa41ce8655619999654489fcf53f7bace73154e25549354652269a3a46159257455b8a76da3e486b689f294d26c6a3648e60f9498c9833acaa6f636485a442a4df4b1ca8a642d8dacaf03cd12f3df0f8db1c26049b9d5a32f57b8a75e7e473fa557551a465d665cf9d030ea285c95ad826818f52250b8554db5a41293abb2d5924eaab2d58f98f9431546f35849795ac353c7b915904a8ca7dea1c43c755095a452ea99854195847b6762da54bd4aa977a88b639114682814a94a4a419e5eaa924c9867d86bed9c21ad0180d27b3e718fbff6f873d46ea6c85e77a32f1715faf2dc757305e1d025b4b3b4a3889c72194fb98c9736401ad47a86ddcbb82a73dd6efce4a6af797bc9a45c37cf5d543c1bdb7f364ffefb5c41bce7b3652ea18679fef9879b3fa807fe4bfd37e3f39f77cffcfcf7fdb842d032972bcbe7c289a2288a28d4e9f42df1d3ef5095a97055f67d443fbd447d8d7b26cef2a967ced47e66c415d6f96acc3874e1538fabbb6fa6c856354e1af835b9f7b3cd8c3b8c563b8ede03426f4890cb0fe803fa9a785b34970f4967899f60bed421fa99434699b3f4b32497f84912fd0cbb58e2a7bb703d3b952e22229b211bdc4f9fa9bde7e58cd0cf992097d0ccede7e471bd9c51f2d3bb9c41f2d33f5ccfbe9f3e53eb99eae7cccf2c7b3973e4e70e29def396edc835ccf32933a7ef78a2f10e2ade7301d953cfcc51730955d98e5c85dd68cc0688bebcd2757bcfc11db92a5b2955984763363ff4e5b987ed97363fa28aec0aeb384802e86328d03d17910b04bde3b9cce8faa131d795d9f3870b88c9c3f3d226c907de8ba44ba8773ce7e0886c03d4b3d57b6e63eb197dcf71703da379cf772455990d508581e9d817437be9d807445f5ecf7295c9d8d8def37287d27ba2973b96f017830dd075cf3f20afdad852e367b27be7fa25cb12ae832e72f19e11ee4f30619ef155528e02fe2a327e3345c605a00f923f9896ea92a983f5a64bb6a720351e7bf7f77ddf77dbdaef76b03b4d07bd3035ba7ea0300fa42e21fa72fd405f9ed22c49de7144639eefa882c6ca12aad04f303400a9dc0e231a9beef94ac99b1f12dde2030a0366f92ede73301cc15a2b10e8a1354d13597be7a767433d03ddf3ef48c75cb7efa767d33def8eb9a6f4cbf3f2fadc9fb2aa807f7a66726fa5f4defd99eebab9a650f754000a3550e13d2f3fa0f730f0f29e973640efb969c420d73b27cc95d28e5cef784ec1d92d9bfc84f9a54be83d770981a415ea5a9bef95ad41ad773ca33cbddc917bcf01a05403864fc4094fa86f1a036db574dab61eea5f37389031cf57ef3aefbebb555019e89da3967ac6e3bbce793af7d101958514d6f9aaf3f2c6e9cb3a985cf274ced383ca72f79ee7b9b2aaccbae736d7b31aeff90da231211ad3f19ef779df75622e06f0f53d718e1df2f47a001007f7d627ad2bfab23776fe2da9671ab40bb94955c68395accff9e4ad3fa1b1d2081d858c405fb352d4245bd4fb2f1d41087d619cb39539e7bdf3ce2b0a79a318445f748e2084be7004e5b27b8e23081941088d5d9f75ce52147aebed54fa4e18aad04fd96c49beeea4102b6456cb58146f199f82e4efde116f62d0db55ab4ac69dca00adb74ee9b8af5e6bf5aadf076fbae45e32e3b3a582288d9037764e47cfc5a57bc40c2c47ba3bbbe5ea25f65beb1d4a236473d43bf5472dcf18f5acbd7e365a83f850cf3cafee583a268a535acbbb927a661d67a867264f0581a611bb78a34bc4294dbe7a35198197a4825c5cecf01507cb572fc5259ca1dea9ada1a0afaea4dea93ebb65939734425fb1f7cda6a8fbb6a585be6a0bd71aba404b9e5eb6867001b6967df8a604fe087d8338fac251a5e60035427099e5b6823c78c2c6c183c18d9a1a0c3230e13e201b46884aaca49a0c34d0792063082068d02307031e1e0e7cf8e8b141d8ed2f58cf2af9eda911241a1b069008cc3d759b538f101007c358e30e63bd5e34368885263c7efb1c539d9b8563b2d0abece418e7cc62f1789088be4cc0c2a0cc0e616f5726c282415c85e15b31cb47e8e3d463c2d8e320b4b95bcf8c7ad6f9f42fa86717e767cebff6ef876fc834c5375173e1c56f120dc9128320ed23c12d234874eaf148106794cbd5982f3e4f566368ac5c996146cffa53ca444f9d46673a99304f509a8b39f481120d073530ce19c481381c88fb320b51443debc1a2810271b89ef5065b6a596b7d7db73a15c2aa305b2b586b7737699b9c41c946fe84fbd34b68d94c5fed9472a084cbf9ada6af26b1d07fb89fe4246d0ad348a5a16dd21b5f5e5f2ecb5e215ca446a918637babbda545d540bf7cc16e4ff0e1a667adb5160a6b1dec3c6b2d1e3b8c6782b8429316a9512acde1c460d8a76e9da40f0736596a20f7ed752c3ba1af9ef3443ef5b47bdb91ac3a545265c5374db5569d31300e1ebc5a3b9a2c79961dca866c496c6f78c9934e1c546aad1447509e9e438c634aee5a41d003d65a6bedbdf7de6bedbdf7deeb996468dc8460cf6a9d06f9d1ccd8d09033ad1c7bc5e8543238aa1c991c6cc38ededfa85e6dd4da75b3e70d1c7676213d05a9f1dd0cb5aa4e3dd65a5babadd65afbb25cb87c51e9c06aea860c2c85e3de7befcd616fcf256fe0f284d9538fcd21e6783991adbde00545bde0468c4b6d48edc97452d9b06c705c39372e0ccc31eaf8dc857353a36523dc099374e45654268412a132ec94f4463291ee1526264f2fbdeb5a3635a7572edf7b7ae576f08e9907f238f5541e9d47fb7543e8be5e1e0ceebd56e87aad648ec6ad9d7aacd39c7abab1765720d4c64bad198455663215d19c5e4fcc9c7aea0e0deacc4a4695c2c0b698c83d424b633775eab1e48d23f2f47c7ae550a79e2b9e7a841b84f5f40293af9f7aeee995cbd5e7fdd9e03381a86b732c1c40940d7336834c4adb31fe39e71873d2a1fb33439e3532acc001e84b1c030e3f5d2eb3944c2d641a127852a42461b29251df455286c09b94295d185290605b5ea9a043c1155be499efa21b139e086e436cb909815e6e35dc6e47700d5966052092ac42e2210a982f4ac6df4551b878914fdf45518ae85ac832df45517a288ab283b744367d1745b98910c506c4031008a0843d3070c6f9a3e1f1415fb3077d21b5a0aae136639444c686551724a9186caa2c31e418946498f89044b421857998e4800485330ef312a1cca4862427274022939f25a1932354194ac0a413e65902c687330eb30c47322485590b24a62638d008cf40f4f1e0a2173c1e1f3c3d7cd02064c2986708251dce38cc361ce6e1c1432d28dd6cb41a94d066b8152d71e187d644c98c0e30d1c2640b85f5973817012911d19ee4448092c4d3c3470745508a1883f0c8c8f9bb088a0fa61f28b620b28b0cd309b27f17dd308549868cf35d7443960f885cf35d74030e265b4e7d17ddb0c4cb0d4890641adf454fc4f81277423c410aca47223c317a0264bf8b9e2451015881f7ba2c3e095d51b0df9fd71b0e1ef2acb53604c2e021092753c45062861058e0a28915a32c80183a62643a82458f8e0432744548587c590188142c818493fb7385a61281e4d61d814407dbe1174f6a366072260ec6e4123ffdee10daa74fb235bf82752ce9cfa064ca8152a60eceda14554a60fe38839227074a799a70df7552234010d4d1a2e648419bd6ea224b8c8c83871c0407070f793a9db55ea07a04b64eb9ba3d757b7add27dd8dca538c276e7add5fd7de9f53082c1effddb0c8d3cbcff6a4c5442e6f909b9fa405aab2cf566134e8e9edc7f5df4d4b9e5e0a3f7be73aed92957c797f5ac9d3ebf78a36d4124f1d4544c3a8e1a98761a82c753bd942a226b82443271fa1314f834231a91c28de9ed63a52a2304341d79256e8a66e5546c1d02a52142945c3a4a898141d93ea2a49739d37bd9b2ef9fabd15fff07c7627a0809ff68e75af5a4bbb77aced3edb07ae370df5ce7596d1f55b13c3f87b3bbfa9dcdfeb140c9589b75aeb59f5eb3427128dc189190a73af37bd97fc6c2096309e1ec9e11f223143411d691aa2c1abf1e2adcabc2a288c3a525018213143d44724faf92ce919d51e5b2d9dd557b7151691c5059d4d5f744957e6d890ef779113277062b2f85de4040743f6be8b9c602972f20199efa2168078f0bbc8c9942e30c662804cb8edf431828719d4dcb141054ffdb4836403113ede7a78c3c7861540115c9041280a1866280289991b922f5f449005122aa03908d3bb2958f0d969a8a00207b65146152b1b0b6fa7786babe2ade71a86debae9d463593ba0cc2f431a56785bc55b1aac78eb38d360c45b23deba87775099a185b7d8fe588204a8eea9d3892fc32219806862450fcd574a7013c3edad756c3d0bf1b6090d6f7d0445317420364363d6bb8d8eb012d230c9848ba754ac02b6f7833a94c8d48dd03eaf2d4a0af181c17a049d3cf41e88803db40ef0f9c98bf440bd0825897c1e92453e906cdae71f394de043173ad8c042056a351a4f85d50ea260e07beb258f08d731305f47973c21e03ab8e430102881c684e0a38740bd22787e29d03dc203664d84268b08592980fedb8b143fdf5ea258faf2d6beddfbf61245187ffaf61205d24f9d3207e8ad9d21534f684826cd538fccca7b093063bec4375f862f9a5e0c126d1566ebe9e6289739b5b79e3da796e393f31346f4923c7a7108e8adaf7e56495236158ec66a8a0a95e55c85d9aa2cf55361d65335304b5c94b62469797bf43665cb292b9fb5c84674ec63d234947a46dd3a0b47fef42c83b79f0c5bde9634c2789bc422aab2942d65cbbdc5a9b6b4aae432654bd9682c25a3725be3a7cac8a355ea473534aa7e185542b62a53015598751bbebd75d1a60ab2a96ae2a8f251fd8caa24f4656d5fa692de7a290ea58e5248b92a4b05559875967fb9dcdb9451eead934755967a4261d66d8aca5b9fe4d1db948dbeec9016fab2738a38fab262fd94ec00877c6b4f2fe933b78abbe0e711c8e5e882b7731e5df0d6875c5621a1fa03a5175cf0d48523b6704008283c8a05f6ba6b75e6775190cfb7be8b82a4fce9bb28a8c9982a4693a667d7a7cf641aa33e2bc6f38ccf542589cedea15f6def4cefc6db4d6bc9b292735a3a59d001e9769ec55882b00c59dae1eb9e7dafbb39e43a450bb404d1eaa801141a38835ac0828596023e1a1a75a0a520520ec8f0820a2d85e9c5184b569cb2a0a5b00a2ab2c110421cd152a04534a1020da8326829e0b0c20439a4538b20c638a2d511070c1ad885769c2750d2248956c71a2da0811e46d11e9c2831a2d511e787464311194865d41e14bb9690941ba16523b4f69bcf2c6a1d954aa1c8222debaf0aeb8aa05ca6088b742334f75161afefdc9227109171d187342d9345647c942c1a2f7d5c5ad364bcc4f6fa0815d65df284214d13d2798a3442eb200aad755b44509e1d45b684acbc45e4e4aa49cb640f14a8127a95ec4d6b00ca534e44f419bf3e83a2a15c7423347a1212de749d4f2bddfce1bb69fb6e52f92ee83b3aaf108d9595a806755ead74f7debb227d569e7220b468e9cb775eb9d098ab75c1d3584b9d4623299f9e7dc641d5585b79e82d22a1af3c24ab2df4490b89642e58801e85fad667c81eaea7c6169193a7fc44d69602e6c9ad1319f4d9659f7105ac3c456e20e52b9f2137d0039194af667c032bcf64cb9b366b13a0afce67c60a5458e728c83e6b0debbcfbc8129b3a96d7cd54376bf4d5898e92711a17e2e393f295fb649f711a19199f2e4343169921e7d08aecaa1a8dd0c03cb6a6cbb8115a6acc329da77c7ace2e4316e99ac92229b26baab32e925d9bbc5ece5a474f4480ed28e01771d4e78801fc267867b4a0f61495d4330efe02a9b2cfaf0ba93293df19a51cfac93dc76e225b950441b2480ff5f3ea28b2c8083ed207c1b1d58e6ab5a3dc082d47c441d051e4abc2ae1701bdc2ee748addab9fc2b1c14904371e3d52c4517a71005b87a7867177639f4ef35052727f2bf5f35b37f4cf2f89c922a09bdc08ad9e7a84f8f87c1efa981c24817c234febfa685d92c8e726bf6e32394816f15c619e17f9c8ae4d6b1a8d2172ee9deba9deb94e61d73b1d6fd2da05ee80034fc8f8b204e50a122338fc5083210b28c014919145c997c586a239645921cb4f4775a838201e80400013c5c1880d2bc082852bbe50523b2387173a1d7288c1468cbf5f784bc0d6e9bada8cce1fa8da47add0da5fe1982bacdeebcdead183be74d0570f19b2ed415fb5e4e0abef00230301bd7a75c7d5787c700902e82badd2ca4cc79bbf71c7ace32eb4fdd9eb706825bb0c6f19e26fed4f4140b2d5972c33ce0cd9b6d294bcf257efd49092db7996ba6ba90720104087109fada022ac1ec05e77edd210952472560c201ea5d4abd75d4b737c17fd003464848123b61811c18128c210238127bcfc90822286c2004323eaf25860afbb16f65d14822d1ef55d448587dc176037a57dad1540adb5d68aaf002e14b07b760abbc1afdb8429a59452ea75b73ba42fcf4f299ddddd6dc2a1c3ef8aa2382b89423de8f5a0501e36fd244fa7a7deb3bedd330b8661c7c23ea11a25a250e0ac2d0c60f70eae75fcea4f42b5d55a6b67dbb646605d75b7b5b3d25abb6d77405d3743c2cca5d5f3e6ccb244db2bab1256f3d25aafa5b5c785dbfeb76671b794f125ab289bc2309520d72fbe2c53b818b305cd447342888cf0001fe58b67ca172a58df455384f8f0bb68ca079e0a53ed8829054686e032c6a7043f4861748445e2e5882f48ce606294041066d2d16052610a064994b044f101244661a838a304616411650c2f68e824980c2561250b11415b6a1960e440c60d3a7c41228a151c79c13b325df8e988b8558440e6048a2a2a58a2036e694c4d0a2f4da8d8e06488d5025c98239ac00186256a07188003135466b84911ea00077246b430c101a9800c9c9511f048eaa288304d7c60071c8e18eae10a31c669ba204492498830acad52b2a8e8f094ca93aff92ea2c2c28421d7efa2294ac01b32fd2e9a92e401b85947f0a58f05ec1085043804b14208b868339ef82071023184983c112204478c9c0823258856f25499d281a7464522f08012188eb8a2684a0b5ff21c1de98ebe6cdc29070e30c9c2248b920cb4d2079525619c584116221052d2a488a771ee638616fca90f2ac315344ea680d1c3952c5e4431c2c2d26d05267ebe3431c309b0e8a863ea2c2daed4a248dae213a50820a48a048985188e6081982b4030c50652e4aee8a1488a1649f3d559610514368ca0084b142f901cf03386172fece0840b2d75052b740c8e0a6f8b96202fcc0871f8258bc67751182eff7d178101c5871ac697afef4249174face0831030e8b0c109943892a28c123061c509a2781394c0c80519bae0828b5a15508ce0c41061ae9871e40a92d3a0a7de18a9ab620563b878822b020a1217a81d9164c88bed0920704705c61507c403100820c4027b0658ef16423818e1705423c372b91542fdebf56fa95359ac9b8d202a1347ae83c6fa7e750f6c15c9addaa8f5dedba542639788af2b1a9b5e6fba9bc303f946a9d66fe7cd710682dc3e495338c7ef0afd24c1708e393ca1c239ce276750727981c4708ea5756b29bd264b5533041fcce11c4d3ffbf5f6c13a0341fee055c215fa3b49930cf993ec991077b5b2abef5bc01104569a1a02d17e8166eacaaaee4dc63b7bbb45db7fb66fb7b5a6bc8c6badd536c6debdd9507d7fdad64e201056ea0da2af767b4393edae77f1bdb5d6ea16fcfe50a690f505ceb8bd140b870fbb2fbf2a1f4dbd83ad8e16b5d65abdc2aaecc3d8b3f767f6f49ac3c4daa1ce7e417f6f3f9d46e84fe4e9dd3442a0513df5952c25f03bbe98b4dadb79d8f481e10925e6948c6a354343835563d3baa981e3f291ccd1608cc0088123cfd1b1918110d1fda13d208ebe6a5818471b366e6030badfb88183c75d2e1cf7c52367bbcfe47d26ef762e1c9c174cb4f5ccb6db7c4a389701382318d580e5d8b9c911de74c917e8b8c1b1c30596c8d6337cabb2d305444bbc9cb8c13a422b54fbc9f1930471f465415cabb513ee9c7a3adf51b14fd8b5426356e8071af3c0cf047e26700b48445f9604712c80384b63bd23b4b89e01f50cbf7073c81a91039e59a814aed455410a95b21901000000c314002028100e09c5429138301e69a2d67d14800b73983c744e409787a320876114034188186388210411408c21c614d1504500c9816fe54a02a389bac8457452bc6ee419a7d1204e2e2766a9221c9314b6e8d1208020ed8c088dd4e22536ddb352d0ba562d2ee5fc6c3f4ce9889c1d9f6891f9c18c7570640548eb320182007393e344ae008dc6b8a7156ec5a248485b752d54198c1eed500f03f9e6b94f9db47417fb340d3e155a0cdf212314f2160ea848572c28374963698101009297e5a51177cf6888efcb9ded4262374bef59e2f000e8e5687932774d5a3a4bc10e2923ecb45af16bdaa405ebb41bfa2d8c56cb0f2416988171a896d3b65a99491b74a92606b8a3510b6f62654c8548ba01fd9f10928f003ae56ddb0eceb2009514a0570f3da5c856bdea54be2ca13a4e53fdc4deb39d0323a887a9675146b5ad762cdb41221b0b15be6479e88ad208f7337a18d195a76f7404964d4aa17bd8bfc6d0953bf1a5262a4f27944cb96ad3b909426a8357d2dd93f9681258361a90d296919cbca1d2c5c0e05fff755f2b338efcc8ad0404311a5456f4795f17800786219dfc5b631e2f791e8637f39cc3a7a4b6a6aa6a8e751d36624b8af6916a12a29c83804bf3ebab86f9645f9310a240fbe081e13633ab1074f4664683f266551e57385ae7369ed6431f8c5cca063ea6458943686d9a3317d7c3241bfa5c147937c44a40b70435d055078a5be91e953c9f4f8654c6d16fe5e8a41c34880f2def9f56782a0ac4a0d2bcae721afe88f039b3cf05573860221d076931b76de6775d97114af0b02db6552515e63f864fec5f72820c314584eea8c761589cb322e78b013e260cc6967803285eb985f264afd45c0b0a472a66d0e68a2a84b33323c6d3aefc1a50941764a382cf81fca60ec97489f84bc9afc3c68bc1a5fc1a2e1c7e474d3f95569a56ce7b8a2f8e3072ae869987c2e8993181ca377a7ecec84c5fdf74fd20cf13a08e74fe3cd50ce5dea0693e01b4402c0a62133e54127c8d258ceeac355f08226ec9ebd0a105e27d47c30f2d30c29c04283c41b0f907b3cf4a440b410500ad1468a19b13e2351ac76133061a7c03fb6a1eb50a913ec2c96b55edca4f84e32c79e2b784b169777f0a8f894d433384a0074f406293611c24eeb6a4abc1e703f4eea45821f99d470c89d4b1150b2aa591d2b796ecef853788c44ecca70737d42737f80881b1e4f101a929a31bdd03163ae4cea4f3c934ff0782fb58d61ee171c680a18c3c5f228bb7730b15b0554899503b8ae295f8f010532914d29f76da4cf81caeb112d7a699a6961c8cbaafa0b498d651dbe48b907f1a5446661219cd31b58b63c2c7042928a71cf7d77e7da41de7c65b220b493bf925a6489936c394c8f4143f0d860a265615f50deba550758e470bb841963cb857fe790ee863900ac21f38e6038bd0eb6adf957a29fef4991421d71ce793a68dbbc76ddd66137d9fedb6139532eae47307509a127080f33f6322e024ba1a31c0cf97c6631ad04e47bbca458cf8901faa582cad4cf0d6360dbeb581222d1815cea4830ad1fb5b33415bc1961ad9168fb0f3077fcd459317eda5aacea3a29de17e37e5149af178a2ece33d44d91ab3f5e83702fa18b491e96278d3a83558cd92cf91e64fdf9eb1ffdd5fe4d6717c66a8920aebeadd626d7c52e87b7e9f55063f1b3cb7f681b03fefb3b9b4a4f7484b6d7cd30dcf96514e981e3a15c2e88bcb86e2bc6de28fb1ae484da8806e72ee6a7e8eaeb236d02d8505bc0e0eb5f9a5e902d35a565af25686ffacbf78897acc03341348270b6e4f718570e298796680d95aaba5a8d0365bad0eb260ea41c7822e708518823643c1bb922d157c0518eb437013537f3928be5f6d11d7080ae9321fed8b3c7455b8a1147999bcbcd6f6a033294b24516b46b5b6d392c7c0dd6cb3ca304cac118b5f071ceb94aa52889f4a8efc46c008498827a9bf2208581ae3568e64ded763173b3a021b217cf0ede4c76c0d0664083f78f3f201cde1280fea2ffc2dfacd0baa19ab1eb0ab13ae6abd00741509738fcd89ab706af6569734e7a9b971f49947434cd3c5431ac463f7ead2cd2dec4e0aa58272aaa8ecad9fa6335f0d9ef4f787f058b98c795124f6849f4c1ef2383d7e7e42326845d55c1d407f19ba8e8fca3c1083645cd074561b28996790c7b327a85abd8618634c8e03fdc500a55b284ca442929e743b0d63b861da6e2682898481401360704c4b6fc8aaf71de39a148e757b166c001002150036247cd4e3598c2262603825af0272257a82348e50f860c55b7edca77e5b69f6b117fd0d6c27e1685d1cdc49adea3828408dcd88a3402ff71d7365464d718418bb22d5b0c4e3069bc4100dd3296886a16e626a276419520ca580814cbd39fabdb29d355ab366f20b03bea34d243f4655b9559627b4ecbe7951783e82e9ccfa806a5d34de3a409409b68b788b29105ba888f7c24ddfe6be0013b954a2e45dde2a12390524d88bfdff834af15259bb6a5349c2a1e36d7ca606cc58865b0e5f0aa4f72c3df01b651d0cb4c1311484d963596a7866e806a974275ba2e61d9f4a0faad179f6be897dbd62216a0edf22d51fddbeff79b8d78bb875b80720bff0182fbdb94abdf6df8430c33fe7a00b2eecd9989f522ac71ed13b966de526528467d13e98f1237e78986137cf09f30212c1f44790ece2368ccf303b3cc43a607f6338a03430461a43f2842469f28f09f26c6fdd89f89702faa5b754516ede657661529c8ff6bf928103c9faac64a938245f297264c91238a73e63da82f448a495874439de9e79c61f9486bf4f69b246ecd8b9ba63bcb3c6a4b8ea265fd718cdb398caf1c6f7e9d0da01c9b9309e11699c4998df2c0a2e7d1b4e351fc964e8247911ec713870d91ca33879bee81ce99f1d99d4ff73b8bf83c8ebf1d2bcb7dcc6be656506d51453436a5605216885fd1d96f6badc78be8302292ecb7fce9c129c19f632aa50e5d5198952fd543adba1c7098912e8c3f729872eb41b4ee0485370942db997729f0a6202cc6a170c2d7f6faa021e7cf903d1ecd493e73bc4a38b0c38638d25f97c32034414f08354991f3a73e025eaa878aeb43ac8fb1c58d91d959a7f288dc78c3f27e052a1f814d9d6e4571466beb777c2b25da3ff76add53f16b05455050eb47286314227370f6e1731b0cb95502adafa31cf6483992fab82166ecad2f7d992f3df4cb7591e073f558928eccaa401ba451d9d2448d98d43941eaffc0ffc2a2278259063587b741066fe3653b931b1108b8d826af9281e2c1f83ba46945b3439ea175fd8ab1f34ab189e13fdd08c68f0678b5e09018bc982060b540821bbc33d1b4549aedecfdb4ead6bb18e50f92882cb10cecf9067c37aa6c5f85594f29a70e68e824577a1e0c822f58ad24e70edb82b9fa4f257dd6f43752c36e8686fd4a43292c6fd30924e8c99621ac12543f1a96a95639f5da5420c9a38075b92a1bd386a0ef56a05587170c503543a2ccd0b6b36989141a35a3b63b0def12bc7de77d6bc215c9729014a13a1d781d6fe5506d5c7962e477fdbd9d945c05a20d396efbd6ffc8a9a6717a900db258f7c3819dc54e933f21106c996d3cfef258af07fccc0280ecbfd3bdcc5a7bf0da4f8a2a3319829e75ffea245525f505da8aa42116cc65c2f8fc2be84b2f7b05ce8ce8f2eaf15968edb0c1543847c22358e23df3d9ac5603df774fad84d56158b9ee55269a241e736f5cc5a4c490c54ad5cd806cc8e3b8feebd0a47e9172b2fae53ec7211ee09fde8412e4a37babc4c928e5895cb1af11cec396534eaacd215c0944b1d4d1a1a49687a0177ee4a5142f58a5ca4b409c138846951562dc13fa3d6782ef7961c053a0379e53622ad7230f2a1d0b9ea7dc8dbee48097ce9ed8ad03f8615519a0ef91f272ff1f6a5fbd3732a076a34372f5591bfb052b7703fc385db40ead4851739d556b41955123f7d5511ea6db04a51ea2e1de75fdbbb285a7f274ac264273455272fba9e2e70d7dc4e99bc9d4c3c1d8da68a505bfb19447366514a4836dca580c62c515433a6fc75116066ce526ee1167ac47a4a0e43b41da048f235d944c4bfe13f45e58d5b5e0e8701ea412b46ae382e826d960982e9bc1b98ac50d755f4359ce3c93544d18b6a48c6b55d53425c32e598ccde471b44524901c8635f54174e721be5bd58b298c114473c4f6aa7fee05524fc3b6c6c3a8988b02f15e634f3b86c3e3ac65dd1c20cf556965d5a36c3b4d1c1ce02b67fe7438c0ce256c0e450beaff653d4211aea5015dadbd8e86f33f46c60458f0dbed9c70bb02d8b799b020a769f4ccfd036cfee535368c6fd77ccd2002741044fbe876bc10c2f7cb9a86310045f5fa2ee6a91d67dae311984c8a9b21a7f655086ffc0afeeb439070ed1d2fcebb4f0ee78020196c96596f3793e0fd63f4bc91980f5293d163af79e5c08e2cb0594fcf5285930813981ed828810457bc897efc52e89190b39a9150125d5fb6c115f03a75fbb030e76f8d2b513f36514621ebf1744302fa1fd196b1b1ad12670f1b28707d5e2d70738d8c67cb9f7603125bb58c4e78c1d0af67052be3791ccddd9a7cd8822912775426b4c268868a0484eef0049a915ad446ac8e34b37f8d858fb0218efd7aebc727c1add3e919427d34afaa4bc163bcaef2f27479c33e47352c13a1f98c0b4923f5a4e7c09a893e50561bfd01079204c5d41de0580be017b893da8877c52efffbb7c6e1887e7f7341e5873049ae179737349c30143a63b9aa742b3d061d53cd6461507c785e80d14ae189a38752da53650d83c2c7c3a38d710e48f5f0c8208e120bf912b9af88df36bb21246da146a224408bd3caebc291a86e0d31e69f169259f5573e69f3c05e177c61a5fa63116485358c1eaf9f34cbcc2d413e745db718d46881d85196c4df6d7d0097451131399965d5d311eb3cf3a9963dfe4895bad52a335e546490834493524716cc2857051ffd6b30d09b78558377ff2019019d6fac8c67c328915e6699c9f0dd143acc58d763cbea170db51c3bb104a1c0264ec12f2f4bc90d7d22b9db50c958362dc5a8b4b873c9e3bb48d125b88be19d66307571c846eaf0df1851239a4f3084f66c7cd82236bfee9a1b0d2f79261d7650d534711875832727330da2f598f8f40587585551032042c3c82c27bd711df9cd153b260fedaca8d3231ee95a9f49d76d4a7a27259b55179210dd3809ddaf00aebcde6f66228ddadcd3a26337f123959fad0b4ce866bac015e61363c9780621e8524d81ecc4ebd362442cde4c0709966ca5fcdf9aa839dc673133acda5d5612462136c7ae174ab09896ec6284cb3438c092d3ea50d0e169a2a24949b819059e0d7d2a28d23a85b93cd0933eb7f92cc4fa1a37c322a1dd3fbe2a1ec2d5f2cf94a41d81f2d61099326ef9aed5d151d0495dad226c7cd546cae5d357777f5877245e3b97645877dd79f3a4d7944d3d4ff30145914c320649b98df6c10032336fb6e1f730e01aa0288ec7f5d8609d76285ab4a32c2127a456abbe4eda3f2942098cf3a814367fd23f0595acf663beb06f97607916a29ff748703fb285758f099bfcaef144ffdd8278fe137dbb0d18e095e9bd04a423583e1b3ba571919cf63d52f0047fb3d31e12812bb7a969f5c96f060270e19aeb0f8a44a21843f10c3be09722fef6b05123a286aee51d9bb4f556924b705b793d161975c69119cef9b98432f6c3447eb5f19cccf84a6d70e5667432099a462ee863c28c30c303d92e2cd67702d941ad067db167ca257b52d7800739681eeba4ed90270a82616bb5b93293e13d10f1c3942f2ec9b9e517040446e0b6d2900914575bd2429cc23261a8ef73e8795ee6f093a837fcdf9c4d7cccd2ced972600c8ec6c5fa9eb64ad0d476e5d28799e4edc1ef9c1c1b426cf4a7c0f7ddc639a9abff8dd98cc4a83d438a1c5adb15e71698bd0adac5511f17030aa524a55d7dc38e299561e2861eae95dba3760d95011c14ca1d721a5d916363e0df39abfde32e30baac8d87b6f0cde75ecda14f57610dcc742d6414eda98d926b3ae2c18b082b1dde1954958382c32464b2490386ccd9151c02e2c3c6bbef83ea4b39a6aa5e4288d6a8f9f89dacc0373bc0ce8c41aa6a57d1a10e9f230e6a161d652273fe280bd2b7634d1025867b01ad0335f83118fac7cf1eec97100db70b2a5684cac2953e5efa3eda19215c62e100020c029750bc4788b8a3be531f1388ddbb8410b077490f83fda99fe3e587b6a67caff6882a0b1ae29cecee439b2c13e57d36a3bc19e2898e10a5d08527dc0702d5972dbf51856eacca4bfe648ef8561a5f631e51e42a8db508b178667ce2d4105d88d20a27e9e3bffdad5a1da53920cdc5964336f62089aef20f0516bb5b9f11450380c781c78969df02daccc44c42366d87784e5dc3dcf42600a7c81c9cdca02cb85748473f0eb57c8d358a88f0cd949904265b0c45906c5dfa7540e2a9d2d52e4f2a19c3a38be1f2f57a7d3ede9757a76ba1d8f8eaed3bbdbedf674745c5e9da4dbe17ae67a88b770b1ccf98d45fb3651f6025c11d014ddd0e0051cacbfbcccdfaaff8cc9f47f5b9fe9a277d3adf9beb1870a132eba8cd158c92de61ba77d5d2d91fff3762e3658c9eb6a8af9d7fbb9c50a4aadfc3a0dd1a3428b6c849a39eb3b5eb8a1f257cdf831bbc0bfd7adb5f86b1c27e7c056ac896a39296c9ecf875d471778b0b09b44e6889ce43224f41bc46914001ee3ba515c3fb9d5842493eb93180c3fde8b3eb0f32b610ee2a4f96f833f9a5b1176ba3b1412c074c31569b99def6a194dee98d7d3adccac9988f1fb9ce728829829d6b19c5e792a10e69b13b3b33467ff45dfeb7c0662db9a07f9aebf8013a154370210d8bd21e909b471525f5e1ae22cfc7c24436bbc33e2d331b2ac800a6ef0694f9e542651c621f5a055541495d0da8ae04f55d2d76983b02da64210647b91585af6bbe6ae696dca8aae1bf930c9da9b679fb1c7d83f68b86d2eebc82a2e242959267ae51da4b6363a059c933c50581a9ed78beb4ea32b12e2400b3ac2f6f12673d063aa8d320f6973c12f5ce43a5ee7e4c430e017ed5e2410ab1060fe3c2eb897ec89e624de4c8a76da432aec705c7b1aa21180f4329fbbd51cd1577eff9ff2447aff6e50691f07cb7e0726934dd892e4d714db6b4ca3b615cf2ca632020a08f24274f23956aaa80d07acb7e94ee852f3190a46ba498302d8fc580db55b7bae44cbdae6cbecfed7716bafe5db4535792cb6802104503157084c463a0bc6d178a6dbb23bb7370ca424e1f214afd4211ea400574e9a7ac420cdd03d2abb92c6d4995668e5b93ae7998bb534fa1ae7221eef377493ec238e39f2589cb3b591317f6071aa8486e55072e08607536c3b506fb1a2c83aab4a91ca3d6d49725815799aa5171118415fd51f8866d202b873fd70468db388e71b9cd846442839ef168a522768590606c97ac4120ba0d435ed1ee0b87e747fdb2f91ddf23d03eabf82d2653de9c740e9a63d928e4ad3d9264daa0eb1d495e0f827e855898497ace9633a85d69079e42a44b23933b072b7f812014ca933d7d85a8d98386c43563f0c9632c590de13fd5524aa706f20d23d95ef83c7a34b13b164f59e9cdc8f20022e2078e5dc5f696c75023ebf3068168551fa94a3e28ffb1c60653d9a6839cd919ebaf8933c4c451e371c2868dba6d57c386c3299fb10a762716006a0531918cdc26bc9d4d6c26cf9b141927ebeedd5f791d89fcc24ed5a1a8bf3d74651d969c6896a00a602a33c3a3843088544857a5d179f5e359092532eb0e6c631fe3572eea0be8282f0c00d3d413b1a3b31d60bec166d293c9d0fc13c248ed7c6c56a6904b6922f16ecf48f8653a3005a168ae0937c4461761807446229e334a30e31778c7dbf7a20dd0246fbd7d1a32f0e355e9c41151f55ad8e20a49eff4215eb3584e876ed44d8d49c63b17f6aeafc5da22074c416664b7b5d83c9b10aac8301155c46742bc44c4747c952227516fb3a6b1566d399ad1894f11dea45fe14a205af81dc8ec522359ab82bbce85fbb351653d982f30fbab79151d60220e655d691dad884f2640110d08d3103bfe08ad3bce7747d275c62246b6dbb031ee8a560542cbc9c7c55ef88192f62d80bd6190ef1bcb8c4a91490f46ba1e45298e2bcb3729f05f12c65ab15e83d6cf72650b54c804bf5ecff1f43e1d293a5faa3d33bc6536f1bd5a828f0782e050b9e9774605b71ed2190fe0da6f4396b415183351d77e881049d2bc95d856200fc52faac2623913f1b32463aaa23d1493463413f121d094843e1e4bb4cc89ec6ff75ce7d7941787b4de8b5ada2efcbcb98d833474957303c09ac9e6669f4cacca400881e392cc9475a0c7a583f989c1bb6c5e17fa8403f878ecfd4ac3b876a08319a2ed56a4b5f427c102f8f4c0fc9537a637807a68e7f3b15f93287fc74ddbc67eaf7dfd39b650c4f80c1b3974fc92afa91b2ccb83725f80aa6555d9d94fd260fab237dde1bd271a2743c6b7eb4c06048dbf43e16c5441436786066e8a66e650fda9d16948742c40e965fea3746cda4f218796e4622f59b4238e21182ae1d0e2979617aacfc97e55d441b0434c237df2b37d58c8906e2537dbd7fc3e701a3bb4047ea620b2669fdeb79d40ffd39669044081bdaac9777c5cb525d7afa3d9316bef810f34bbdc84da75d5c52b4524cc6d3c784da427381aa5a965a7faabc1b979d4f682d4477ea5d4830cebf8e1bfc30eb6411fc4a7c1f81dd4f16dfb6f216ebd900c0410c95e1629bdf67be21473e452d4ed7193b71cf4c9b90e0bc4b97c1815be27ed1b8800658fc212c71aae323df3c7f3e0c294d67e0c9330a679e4f3cc87502b4176f7e294bef5560e870eea87d9d004d04fa3c286ccfa9f261cf7e88ca63f6aae0599710d05e7ac162461b05b453e02ba140bdd80762c950281ec3111edd56b5edb6ab111363675fb2df39c10449c88ee2d95883fec214ec65af90817335a2b85de55da48d696a9dab1683956c7beb440b1ef652ccb64b0fd5da737c5644c52549321825bf448a00c3814e03f04c585abb95e73a751f5f13874c948d51d51e47f6c0ed33c9cd2cc1bd6bc0adbd2e9abd7b82600c3c5aedef34d416429651e32c9eed01aba84bf9fbe168c2c32ec38c3d0bbb8eb3c00d5ecbf06f8a8b3bc92f705c7ce71ccf5c74cb967e4abdd7850ce50052a374ac984823f135be3db53364a5dc727dde92485837e2cb2c17f6bfbd98c10bcb115b52367a306f7946d63152c9d4fd886850e73c54d53246ab818e41fb9d046a2ad9e94228b8c5169add6052f32c552cd5a19b5332300afd0d26951423085f99da262b78235c4a46ae09a44a639a8ea77f2e0a41c99c88c93bc2ad16f935e0c41db9b6088833152673cacb423aa65835beb2648405c725fbcaf3e01e6cedf4a09cd541079803c6f84ddf4ed43ac1156b5a8910958c357bada287c96d7f8caae629becb80712a9d1595a775cc22951d71ebd705c64c81ac6168f0a7c9948ad4040b5eb2af1bec614e08d2da6f89ba6c9a268d2896a6075a0164253802d08abf80849bbd7a98463ccc27f61738a0a1de2b8efdccc939b65552ef343798c1496d19711d80ef5dc33485a898e854c9db82d05e2621f7332d81198c15964d31b82b4b2be7e010231308efc9606fe128c3156ac85d6cd31bf2ebb0ad71ccb27d2675eb1123aa10863d793f9fd1addbf72862ac1adf6ea4c187c4e50c66ea8a960e78130759b449baae3064c98a80b7e8d5d72520dcc6f85cb27af4108b243d21eb2ccf308d745d971615ab510e6db90b7f3e1d3c3a246da7c8534ca979582ff3c1732226d2913b2078f3d7d17a298027121583140d08c722f132451d8f8f103810dab7c4cb6b0abf534f062b24756eb5c8feb14ffde0d571c430ca6bc89d7ccb2ec9d4a035c36400448592d3a170bda0f008ee6d62b129d798964c846666444501419db18179d6f36d46f207f001f19fc6e006215e64270e0992b42cc94578cd05e70d874b36fb7f062a4476ffd15d1e4989b1d120232c2b919e1f9eb4b3e84be7393eb06f8e3b1d753f6f900f8af5218ca8437463d9c8b12fcb88abd5d6d65fd0c183591d23159bef4aa4822aa12700ffe4167142148ebcd8f7338462d8d6ea4ee19efa3232330583402b324897837baa2a1abfad2fc4dc98822b8fc7c7724715d6234a0c905881410d8e9d7d21e6b1a26c6e4e04929f4acc06e997d08749cd05be190fbe629b5b777b2c9fea051a64241242266ce83faf40a0a1ef7ec7dfc51b139529001a56d139d9f64dde6a745f0e400f304f65e4487343d9a437dd89c2ec65c03b38072d08a2e309d0567809aa85dd2ad30398b9b5518f1ec5c455484344567c808517585a8608353746c45fc448cda07e8604af121dc2bd73ce7fc660e8a8e61981af72a084ab96430c74a3c7257c6af078f8e1725ba905ed3a84f1706c56e93e683a58e0248f3935a99fc62f29649b1d2ed09bf3d6e53fd191c1a2d0849a868f39c260f2d8d45ae36b4a4a1b92096affddfccb2d077e3f27ab2b596e5ae0eab43374e4b9103d1fe14b0a125736338d80d38776682b5226ab3683d51631427a9b3bcafa703eaf9c2eda2f4ad80dcd0b43519234ebed7b08684e7c5426c658805d0577c30de9342c3fbc85f10519405dbb5c885fac3a5142f24a26ab105348b5c9650401fdaf9a97286b6209c9696558f6f2050ea08f6e17bb0dd4ee4a1f8a99b9fefd21c5175565e284979f5c4b0cecff2ae9456d962a77c0bbe6b0d2a868dc0514543214be23f3eb3f597dad0339d6daa2f256ae33962838bcc18cc2ad1aa778a4c833642f55d5eca21fcf10de53501d2382644334586de28bae1999c99a3b53299f956b0f32fb263458b1d698b64cb74401f4414f6f85cf5033e953f2e67d20c0fcbf43d73a8df351a3d17c65a7b2273e0fed4928f97b0b9b95b7fcb1dd947a3c7e099ca9ff48a58d8e665527a45d982aac9fd14074b58c75d8f54938ec11118a9cf3641af41a9027a86fc4826bcb59427a00b8caa58faba199e5fc813f7cf30d62f99493d84358db63d901c0bd8d3a53aff0bde3012d4a1f92ed116e96e22632afd90373452623102c580d280e6d2157063122fa5f6d471414e220f24ce87dcec6992c11f12d22a3f58b9aa58469d4438a56ae104872a835b4aad2e1e8f30b2d5a70abd35625ed4563724d03851de2a94461bf6d7ca2258494be090239b4c94f8f44619939e9e518da215c236c39da7e596dda52aa240f1fc7f783a02040ed56deab7d9ccf53779b2bb0dd65d06a4e9ab2c552e02d2f3da1811014d32d3936d9f6409b5a6d21c02254e762b83e9cfa9034ba31daf8e35edcd909d0cdc295cb693a783c1fc986b2a7593ce4f893c770bea4a92adf201ad764f09384206e7bbd600afbf024f64bbb8eb1543de951de764210e962570ee9e34f22cd25957c56c11f36610c9f4b464c67a6fbd93a1a6097838ba637934159d6251f26eb739d2aad1985d3e65103325d321bf82385c4b0694616304009794f07b764c6b593fbc02eb272a711ca79bbfb7be2679a12d8ff48b7d468899ee32c21c88b56850b2b2b62f4ba7426b6881c932f86fe0658c4f8ed31f342896d0663e30870f2c719221734b42aa2361ec13892b360dfb451fa02b5941ca95090e46230506333c182db8a0396e1b43684b8053ea9c429233449d086379aef2d840dbcdb65d6a3201bdef6893ce965a720746c2692aad28b3fd409c183d784747f024b2bec7c239c839c64620f836e19310b0154a0f332e5db8b0050aca494846e3dd472b5091f6eac65512b27648e3a836165c4db4de7297845b4c406181ac8543c127b5ffd69c9c8c5089bc3e6c06df0624b85c4d925f4714903dbdc811f78d7380bc1abbd61151c6b016d8652954758b3894f68751964ee9fce20c102baf08dccd0d584e66bebad4a8d452ce7f95e7987827698303192aab29e7f7f6ebaa2f51275a141d0ae3529bb048517ff64e56481fb982ac8d0f63006d9550b3d14cc9e24aafc8813b1e9e7530b838fbf1f5b6cf4faace9d08545dd92ed812890c57a6ce6001c76eb862a2be2f3d0fdb4d8ce9492d5a2204536ada10c552bce33ca9f3479248a747908d36c46466792951dd4d1d9e2d00b31be2f15e2ba2853cd634d56d9e9b34d0e46f726941b4b2fe0e2a2350bdd8d59d5569780cc776b02515253e1ed000b2919b757c6e1f326b07180895570583467f0077e52def6c844d18ed3688f3a8bee705e13e9ecc5d55796c31ef424a5b153e7fc16c4250b340aaef1d207e27b2b0c7e29a1dba9ba5ae960db93e0b7659279b93ef09549bd84a6f06481de1e5abc009659cff32a0a140cc1751713f7420126ba9cbaba84be9850372d2233a64aeb5600c35ef658b7429f9c0d817b432266836e6189987907896cc13512254e1f84e3eee281d13fbebf8437b800368355f8ee469193554a97bc15cb1d0886ebeaf574a97609ce966d79a91281d3e830a8b8e72ea30c84ad028c66935aa832e40aba3ba6afb262ab0011cf00e3d4daaa7621572049009dfdfa4d35a2cbd4a82b68db0d0291e55e70ceea87c800ddb33744d71a40297e80b12506cc43f72f6cf6cac3e36fa3af16f43ce1e54dbae371c4870028ea17c295d2d85c8bd9f78a8d7bb721b9f70392d89f64cf5353779c67fdf6a382a566c8254c31995bad2426f557c6c270f98abc786f93526a4f9aca9abf6ad6c00d8831a93451b3a64b5b321be5e88f140c3f515b6a80f15b8cb3cc1592c699a2d6ff7a6e91eed843cf7f4422c12ebaa7c0e55876b0237c9db22531159feaecc3e7f4ecf8523e568a0cc4494c33cac812a5137dc98d5e1d3f1c042e22806f4e6bfb1a2eb0f72ab8556c95049a638b152603a2dd87d62399773d756e384ea9b685bb29ce04338b5dea4d445d780dc74f85bda220ea8ad63df1f9f45eaec921811dd8447240397790fca4b4ec5979b73a76ecff485b09edbce769b280223cb1540963af4e9fa0af46c00245e15eb4642de63f602fb75e131f086bdd55d691b21a88f9d165442b9ed0bc26355c708c8d0415f6944111f491dd48f4dab2f3b3db79725123029b78f94fc1d98a44dd6513c3314eed42c855c7391b082c6af88b5d60e3a71a16ee00ed8df8201db0053294c3f5a8762220545354c7edd46bb486577b0d08047a8db15da2475941c8c2da03aa2bb83da8060b8208062528a9f823fa157e87e9c0ccd0fc7118a2be30a96150b9fe5aac3c87f170a1451677bf01a2ff86aac804d776db5ec6b8d296833ef4edbd56507fe05c97455c710266c527df93d147e0a99c3861f5692fd36ccf904786654edc5271f1e552bc9f7971495859afbfa7b67135300419f51eaa266e0e464b44036f04bb1edf07606c329f7680440491c5db000c73ba3641f3e3e52f0e593b50a7905f84f995909301b8222eebc8a8e90b2adf994e71c2b9064004e4a2af4371f2adf81a6d700a3521af7e4c7a84fac3dc96036350fd67edbaa0f4e0ad4f287ec1bd13c101c228bf0ede0cb2484f15891a635d32e8cd6194aa74bebf2243b477c930b03e133a10a73c04beca29e25860ca02071c7a0335ee43d1d56f42f10ebda2714479c7b0702de6d13bee0567090cac8a2bbd69b94ff9ef36b9bd545097f4da771902b0411dba852efb15ed8fd4ae4db14355a00ef61c3739d991091e401f8b3d54248db45c20863a60d4022aab6d3b825f61a39105a26f2f30cb11fbf42bb238e57036b544881df3dae11adfd564a256cbb8e3448ee02f7e0c462df72514df0e6324b7bb8e71e057034d295a14524c460b791ed2f9e572a34bf9cf1059d466526f9fe48cab4f8c040345d2120c9e14169884216337e577c91bcb2d885a871428368a72b034a55a9b81874457d951b588bd9b7a2d98e18af17df9dd60da01187e52e0274576ac8ed790cb7e169852cd5dd18150ea08e10a15159da31ebfbdfa39ed7dd4efcd226b6b6891763858e320f4ed6aa56b96ce6e4db87c0b74110d0739a59edb5f43a60015ba63d9b85dcdc9c227dd9e830567b80de0ef042480e9ba615a988a6ebfa05b06a63648c5a88be3bc79218fddbd0466faff8d903bdd4e083b9c6c2800b43db7f6dd26ef5d54904c20214984d2670e06a76d5c7f2f7e8ce90e6522e3f4ebd273a6c07433f9117fae0355b3c85fa5fc300cb1a7f00622c3a522f356e11db2d9b06c5b019553e51b9d5964a20128aa2a87cb0ac733cb1faeec8012983f623426b75b94e29ccde30585fe193f98436a2512bd0be3ce79f8d78d1cc06abb233e7de1ea8ae1c059d9013ddc80f9a9c01b9b7de222a1f84c901d74ef1d60901362f5c52906ea94982d8691a29efbc4b167e6dbceba5d7f399c6cb65ad675fe2396ae78b808af3d09af840d374ba2bb5733e0191365143d5b9b11e47b1f1f73e98937be641dc43d88d844fb72bfab55e26195a04c4668c1606225c166a87ff2d7e4b435cc585a13adae99fced7192339790f3107c6813b699e9c6649c7fe951e73509af3284ef21ecb835fcf318a849ebcc6be0eab179f4e324cbfe6277c6efb2d73db7f35852bb260e13cb9603bc07d8575dc067148238fa79495de698c1817fda33a993c7fcecca4a8d517ff1d12e2921418c386f5510c49f70881f43bf02b3e248eb012d1ee27f2e759f43262ac8acd19d6871264481d01fa55056a42d3e95251491a9a573b3766f7d234664c9f2173c6cbe0ac7ee8cdedba40ead1b29bde4cadd809a3a1b83207e8e7b20fe0568c834a18363cd3738ba94b48f9cb53eadc62e111eb476843ed83dbfb68e37f6227306c750031f15b6481fe0c09a17754c0bd5d9669c6c7d3729f7e68559148a88ddc5054e9afcad4565d1e02a3fb259a644c1933d8ddb2509c59c4aa2c1979fda70edcadbff79f1f666ef310c760bcaf7447bc3b13c982176c1c15552439d01f0f3688495a7b87482c4c57224a54f2d2cf55f28e682265b678057943d5d2d9f2361508079977c1d2ff34aef44a4041737dcf0c7314779ed3bc086036c3c21613f718782fbe7fc40c36b17bf93f90686dd08f930c5ae5309f24a19f1955550d48e2496db80af7f414a0f1d013d08f802c82430a6126523b2cf437238609b4762782ea1153cc37b7022680fd18f96dfc1645f8c7b1c22b8ddd769ce7b56111bda24be2902b264c9da1fbe04a30beb8db4cb65691c1fe6c514838f01fcdc3e31a0f1ffe6e1acf045b9e97363f55b8eb1906b9ce8d065443ad83eea908303ae980bc7af2157430874994cffa18f4d8e8263bf18d07326948a3cff250f37c2f6e49dee9171f2a045019438b38c2446895696ac404f34a909fdc4b3682ba32c04a7528072f896c1836320b0b1b487a7a94eda430edadad3a015d31549f7037dcf816ad42be4b2d35dc1ffbb529d9bc03f0bb8679c8630c4ed78f32097c7857d9e3cf7d03d8309a18e3d24f7ffd0fb10d4ba3a569f938723d49bbe373f25ea8ce22edbd9aec5bdc737d2af6dca96a03d048f54000ac930ff09907f70e8a80253fadb6c1098ba2c95ed479409d015e3b7fd2d0a42789f78659d8cf27c8f3f9cf1e7f223132d7c3c2437bf5cd62504fb00ca8467271667b64273ab3ad1319ea948089b7b5ead9ec11cef63e1d690a0740b16ef7302aaffc8116b106d5ee46a5e59b7acc0dd5cefeecf3fbf018cb7f19c819e98713bf400d356e92f697a404d2331d74ac20ce8583acb813da9f480ae9a83bef2d6632d24d98bfdb1907d4334640b0c019fef216b2f2cc1437d01320f38e89a44b995a50d77a0936f340cec80490392ef3a9ae353a940f0d5853b1538bc1b8a0576abc1c50d607c0aad7b22697700dd88aabfde5a1f8877cef45fa00f8ece16fa084a750f1e240ff17045ce8a87d91d50ef328c413fad3300dced91db778a0cdd8a6fdab9fcc45c19be21bd70fdb9b7c3b3290789da3fe08a6b88afac6c0d06628f0e374f71da53e74a6e6895a1d085685b5f896c3f1a75c49605b270f9d5114e399491eb09bd415280f71dfe23aa91b3c09ddf1b6f7542149625de22e68ef8c2bd0c5ea7df1348131bb9f06f39a64313be3ac6b132bcc588771b92484838a7e79c277a37f1349ed9165ccf0f4908656710df7261f932b45ae1ab033e10a0c7d0f931f57876475f2bbb06b57d9f538e57ba75831d1fa2efe45bcc84d09fb0302ea45760da2afb9869c24065f0205dfea9095e5d64658d9fd1c347ce123067ea1a444901ebf52c2f90e9218ded968884b48a423b753fadc1ef70aba937820ed2f5aac1020fef4cfbfa6fce70c7a5dc42c4e5924cbbf1f880d71440708a6e7cd8840c0d6e2ff8eaa5266ef83acac024f73e946df49a6dd289561213e77bd470e08b9e1e6477e57bf2c5a65805702889e8924c0357f25bf79b8ae310be629d4b9a81c083a3fd2740aa7a4277423f80c3733456d1133c92f2d35d11274cea5bda7fb5a95990cc45db2d83d67f1025bef4ddde8e2b0124ccb1967036ac89e9d7fc85131af2a748c4aef62b6859afe10429c3b74857f36af746476b3540748b2ff76bf9ea330e85fbbf1d606086a1bc7e188595b0e704dfcef8a2a49ce1981410dea718d06c74c214074283bcfd21c1f5c2276c552bf1d0acba2efd51103cb82ce19462d50fed6d5021bb811a3ad87dd956919552869c3e1bd55f20e814c801970b4f569ca91d41b4b23c1118c4ceb1801021b6bb7317fd4633d279a6f4dbef98c52cfb1ba259c32ceff5afa6c74b01690207550f0057e544dadff05eebdce89853e0fc01f633ca02071913741cc8623bdec59d37db0ee4fe46ba84be18d500f2cf623aecd57a4a64c2a1f943d0713832f7c307308b0c12648f15b35c5260fbc81b60b86342e377318f97b1436c344a816599e34d05f214fd9842e1a4033e46f182d42c0e68503e3cd5c2b5230046f0ce1a7d8a0f2f21609c3a5552c056420b0d809fb850d7108466b7685ef6e27a0e59ca79701c3bf0691c8565ece5e1d0718bee6a612201206c70718f65760c3130ff676200457d3ee9bbc47432c22da5a02fa24713857a63260d0a3c3a5c02de08a48f269dcc917e888698f2db1d9c3645b795199069296064e8e76122032fcad193abfb9f49f833d277746889911d15b7b6a25838dcc524b716b9bca17d79428fe4b2b40a1efbf5f9944d5fd161e2df0107bc75aa75ac2c935152b963fd2f0eb520bd0bfdc62641d066053d7dd63a7a465e92c5e7decb50c4b1dafd775497c8908e5532469c712da82f962a6a5793e473602b4950065b32564e7220e8ea8ec4d13f4e17041a787feafd2d364d27596b364e2c3926c914eabcc1315ca10e17c65231aad71201d1aa20ba2bb3476fc4b21fc5adcd566fcf7d66171627752ef3f2b5488933276a775b448faf4c6b13037c7c47030197da231177d0e785f8381f06df824a89d53a74cdd86c315f71b4b6726ba43b53840f7806d572960ed0eac17358f32daf574a838fdb77a8972206d56917226e2ce1e2d95f76783d160b0c7513e528fc00334c2483f23a070dbcb2cf47a1e2fec9542fbfd3d6f2b4701a19ae421ceb606fc77004f610105f074d2d9acea1c296a20381d626fc1e087223a0de5ecc57c56002faf3422d01b340263880e65f88526676385b3e42119da4e6c8717707ae7eb6764b05d15c429d24a07a02d8f3870b0fbce71a69488fecbdf468d95adc00436d0f9e08584aa66b2fc8a0f52343063dc57ed4f00274ecb2f1ae2bc651b3572e62330ebb1758801569c6d65b0b56107a74393a8c7f09a2e4561dc21781ea220eeca049e57c18e7bb1a803437960570605c066fb38c2b111881fb84e9865c7f8fddd54ff5c9fc72cc10737202b23f912c81e43f31526171a550d6cd1fbea3685256f92a5365fa71788e2d25e5d40f15df147b79fccf047cbeaa5ae4bb9a23f9b0ccbe2552ebd51520439f09807638fac5ba4c2ca3e2a2399b07442a21f64a9bf3387c9b7cecfd3472b302d0242e4164c6bfc68025bd0cd689fb7c0608c25c853966b8b8bd275f65037a11805e44b2c8d19e5e37fef84d6f55430cb6a63a56847019031665a98e0e95209e65a3b740e871f1f1ff83ab6aaa3d52fade934d4a8a0f348f50a90af3b6824ba8068fba4d38fe0637f69c63b1b0b5233826dadb23e419128a97900027cf044395b5ca1162da9b5b2a520188183f886aecaf70266c296283a9912776bcf3dbac2c53baa7f5f1300247d7fdebaaf78aa70aa7dddb443ae3558db1939d4431703d6279b485d718b598193cfd1e44f4e1d78eac3abd28c12f246632e7f58645fb7c81fbde98c5a65c43088a0680607e01dba485200d197b1c28b369d4b9af3948721d69cccf6cf9cdf5abf2e4374791eb4ef6352804c4b2b70c68c41d1a36fe8125675c11351995c2b39a462e0987eade52aa150653b208bbeda6c16a5d3ba87a88d45589c452598b80cd54816f3644a9afb5dd3621ea7b52b619427d8613beaaf2ed45c30965d5a70ad9b5782965550cc3de25b484058b3d0693f6e40f8dab0a7b650a59001acc03bd7d77cf0551cadcb4cd397b87656ee3812c62d8d615ba60bcf65071ec6933fab42ae012d1d9d0dcd35a65bfc04ebb3105c82ec75bbd1d58d5a3fcd1651a57702705d4b9f11dbe1d9fa50da3e5c460450a1306ba1a4e7c049687941fe9682bf5d1244df28119d02259341d82efd406d843e3b3c05039d8cc95f5ee54b43cd0200baab138b2c391695da1a27023258a089d83a9809e59cc2483d56b234bf8ec2a0af3118ccf32ed1853cc29234943fa45821e3b0269f88a8f9bba5de11e2e43af4e4aa85865bb57b7333e6562254a92b3108fa30192c78b83eb9c56f2bf8d794001a678a835d74f8f2960b79be7da4eeb162819a4773572efe2a3fc72f2a89b8aacec2f783568706ca71541294e0bb27ab18448d48fa9902757b5fc3078b65fe7d940e1392388520325baeb8c870dfcba36d3b38c4625553b859f54a4b231c55295ba603a96c1ad68805a252e3999c1e43dd5618a8719f8c1c270038d11c8834c09c8a7bfc262218125e40122caecea42f1f20d95e7218f28a7ebf2814b193903e4e5054c8758b49d0c603aa69b4b79533444901b841b4784b60b79e8a73b520aa4b91c842484f39e9558aef12888f1d52d58413b84046a86593ec73ca4ed71f887c7d4a738840d39535da02a68f6259b7fb17ef154e250505fe2f5980468482c27e6489d98cb26fa19b3763f1a69c4949ebc20e077e4b2b9f8956e1bf478f091ecaa51200c8b07e87e0e8451f7ec033960072bbc9c625db2d495334b4a2fed68e8489bffa73852887c517603cd9005f9a79236ae1622672eab6deec489ed88dd317cced4fd16778cbe0dedff2cc1bb94c6b33e7819dd20c16e0c0c4c74358877cda1906104e93164ec52ddb23b14e42a23d073d949120410badf6b9c1651254a5ae121df17af12ea1af662d91881232508b3d309c0da7e448b8e49eb815a3a98f953a3e53788c8c2b4ea4e1fadc425907f7e714f0e586f7d9c9621fd5265f29a2a74a74194ff15ca3e0ad4695a4f7816788a172f8d6487089359b89edb164059d90d6556021abea0a5aa609d0888b882562ea163ff8935110365d389146be2032c5ef07a5c3512a229c35282bed36939b13755d4a22b52518ab0687572a58a8e0a8a56dfb287b7474f63b274109c11c3988d83972aa214038693f5ca2df5daef8648ca6d6a848d6b1428b080cc81339f2a08283a718e8b7d166c860d96eda39ff78532c1fa0002038e437a3bd35e647b6cc28fe70013c7ecd617a8eefb8a359cde80634a2efa9ce391d17d14b6972a0c8783a7fcb1c5c65eaecb4ff8b959398fa7bb297518dbb61a494039e08e9276f2107c78843560ca99021723c2e882b6d8d264302dbd58ca7b8543c0b1fa49f43df35096d5cf0a95e4f256c98387508e5f6daf864e985c717e5f25aeba1d4f8e722764a8463b3c489160f0c09f27a7a3fafaa841a233db445478ee23bb5aac87cb27c7746ce9030a8a7a49ecc911434022d02082c738b1cbacb50ef5b9568c40847b50c62018ab2ea3b46bcf59945631c48069d1825e43c854cc60eee4940cfdb8a9a660e65bcb3aed65c0e67986b087c5a235933fb10eef8fd1b5de8e1dad96ce2f132827f5cefe49fcce0e79aa85526e2145c5af9297d8b9d11cf9f64f06a0eb83cb7b5ad88631c17aa00a5549325ceb970fa6d02b847414daba9686825d57a9a86d20399dc2be25fdc1addfe30b968b7c021531ddebe64e14c7acc3242f855230c8b77590eb2fdbe7c8c00be043f96f1ca608f929a2adbfd044faf3ea3bae707085694ed975fb67eacb327366f979f300de01b1ec8a894584695d997a1d076a99dcf744d3d60c0891f5ae76b23c222a044e0e6bc5f7c14c24028775e4d12472ec2825d569c9aadd44d19363e5c1dfd1f49b33be2970ef43992d223fbb141d72dd7e0840a3281d09e46ed7751a8ad417a8348a6dbb72aaefb8c11240ac2021be18e367976effd85b3abfd9240065eed22927b4890d375c83be5db2b7106a0dfcdc47b4441d958cd9f32c8e495440815dec6934f4cc84b20dbe29d8be624acfb8039edac12619fe33a25d7d9f9819d69c9244377869fea116294bf042f7d4ab41d948b5d7d040c5e5f2a4db4252126b960ac82899a3469e6543b7ac5c101835dea5d9f6d8c98312da3d018e8b1657f1f8dcce85085b1d31de92ade7bff9bb236c4c2d13328a3ccaa386aa84888dc89bf065439d348f61e21f3a151ceeb4984b933b4faa3f2dbff398634944ba702d8a751c16a9efed01150ff25b426fce10472d3ffb575adfd21e8eb3c72fc90d56fd26c2db7bc5a32501b9e235c9f7350b1ad4993d6f7ee9078747cc5499fd5a7245627f5c999ed27279fa59f1c5040c0c6c2a560d303a10f19ddc7c2a939f71646b5a15a2bdd9b232479497ff32ac4884cdc444b8150b46f802dbd50ae00479acb0998f0bb85b5c849bce75adf608bf5b8fb9487ed10923a002e83c868cd05c61a8e3b6305bba9e5518e2e65e58e0ef3c81b726586f28e4fc3a41145a2b94892125c0b26a82cca409d208497264ee1be3b5c76567d84910369879ef9c440d0b0f6ac581a341bfa5814fd229d6c4cdfae933b85b8d2b9d9b6dd92d37890c80f303073e29d2fe31681a85e30aa0193895c299f9c00e87245720c8a94cd2105c4ffd8f3ae22e49fb45fd7f5177a3ed203fca1e8c5bbc7c51ac5123a72432acfc28a30cc50fe92b6f4d28186f6e731e2e9e5f347b1d39eb00006032949d51d642c0b4bd5139a59c49c7a000b98a5f37018c5ad74fc4444592b07040390dd78c9d1894117e614850778b6a86c32d4305010e6bca6f9a31dd36af830cc258bd20cb169ee06a2a78f23e124544e8807d96f02bca1fd26e0bfb518f547e9ea5b4358ab594568b1fe7f7eaa25fc5e372793cd07b61d3858cb443f3f6f9406721610804c7428fc699ac9918d9b73e1f7e3160ea75404d5b069f4a8a3788e54264e7a497071c05c5c473b40e7925ac888e933df961b12a370cbc7606d3410d7bc5539e4e577c5bf0b878d545e82a743efdbe283e2e4d799af3e9779f2716580540551ae08222278e6f43467ecdf74ddc892d6e32efc5a6fc349cbb4282744fc724548c5c8624cbe3ffd555a4a3084fea3f72e7fb8e5942f65084e0a0aa93b1f2b2430ca1cd5d6ef1e1cf869fe0310bb6b32809f21c3f482c22909ce23e51542e755ca789bcba2c7a5a50e41c6cfe5ad42c9347cfc4ad4fe2e0c2b17629325d9e3a994096d751f9978df0bcf397630f4c57547935d88d4613a07896e9091d3582d0dc50db5166e72f111110d0c973122b827059ffd7559e4314be226a212f1dc60085ca0e010bfe75a27a2673be913be3ea78e83db81a6f338d86f57f1feb70af7e4dbeafc081590a0329d52343fadf740dfacb2648af2ff2dea08e2a44a4466dadf524b651835848ead35c65220e9eea7a09fa8ac148bade6f785bb862b7cc8b04d0a3d8605531d186889ce4dc15fd68e3dc6cd72a06402b3c663821349c3d1b3e415e326774572a27452f890a0aa4e373fbd86eab20ba87a3bf1739f693de235c2ad189d185df4f2a0c1c31f9187f9fbd224f87a69451a1ea87d31e596bf02ea4bff672a4711e41965b33745d4ae16d93346cc83831d39391f146d3e4f9c93686fa828232d0105a14ab1bcea1811309cbdaa2b9ac75a92ffab73d3ed8db91827b9d093a472b1afa6229c0fc18e154347103678ed10b786cf430d98b06e9facf8b6157c63e2327913ec4842f7e899b2d59ee75371151697fc357a74fb2249298d1fa38bbf45d2b336c4a606896e54d854c074282471c042484148386ecdb801fef9da4cdb138a00729991a6c874139383cb1113201b84b0a65d2baa6d13d5cb743f48b873f61d0d2e526b778891b92d957db4303bf49bb649d88ee1b2ccc99dbcc9fec3fa00240b12b66124d2c1ff5dab205f49cd4db3c2d471be1e02163436fea193d18a58117f7e447847e848b6ffa34b791b770094a9c1ab4178aabcc6b5b34b96d7a19b9977e44ab8648150ff818404bafaa7e85f4df903df3f050e069e9e863d49427d67291c855821d4b6d8cce8de411d4d3caf3fc51e901f706d04ab045bcb92ce20737efa6dcf16803ea77898633b5f812292208d0a16964db6fc8ac903240c0a3ded660e7e3651e2f5b33b14af9e351b8e1d2032e25cb6d7cdb41bfe1f0c6bfc31a3b14de2b3f335f789855439cff453f24934c1173d3b9f67809f4d3406ed4ce9415828eb3a7338d9193eaa87557298c688deb132e0c10abbc19f29ff9448ea8b9a9d3f1b96d1c0df50861a4259c267e1f3852a2b4f30305d52f7fe4f0f4ee9e85e2133d5a1025f16ac6937712b3c89af4ebec37b7d43105431b503ebd4b1c6929fbc060ac4aa24b98d713abdf27b2bacb518d1af966b2dbb30295aa9dd9e72055429f8c83c4434ce71bb4be62266db8625cc7e834a77ebc22155a7cd94cd464cdbfe833c3e19439cff289cef74f3c2c07025760cbe6718bab1b13fe5b301c184261ef4648bd83298a07553e58691d0527921b534f31b8313178066a252f104b3e190530c9d3c2eb599ad769d536f86370e222e7f2875986640a87ac93e96988ec23834c3578db33af3ae5002edc5ef2dae2c2cee062a4aec1c6b2e69ba68925161dd094a0432252889c8edb2178ca9b6f31112ea41c0aaa91b4a6fd20d8a72303c3bac4cb609f858b71e067f01a6d030207a892aa09860d1ad0b594131ae4489ccd1ce0837460efb9ece020af26b05f1ed772912e0086b1d2c85bcf3a7e0b928bf451519880267f0fd58c482089af741f0629612139696d36da67e3065916eee476411f132dbc5140a2b56c814618fbed8071707ebf19de39701dc09b4103bc4bf6ed966f7988bf04e08ca5f70798f1638e47d4c49c2a6031d495059455af63052da0f8fb33dc4848c5f86e973911074e9ac2ecc9acaece3819abfbe7747fe376d968a6b93b48e121c41efa232788bc5a78d1751fa600ac8fbd49caf0d11c4ecf399c335a307a05eb42ea8925b34895d95eae0942d80008af1d4c2ab280860c376ae3889bd5f06e1d1c989e8bc20369c9f005254eabe8d883b23329947475b796406a6c92e4f2a7d35e365c8fd70b0a3262bc0a17c6754fa2e36f3566cb987f411b0ef68e49510a51bb59259df69cf524ef5f815541c4aae99399b0b7f8adaece0ab8234bd5dce5dc552fec7ef850d3ba1c7607b6cf0262f1cf5b0afd3dee0304aae4f14fb16b614d5fd34b732894c5068ca22c1d63ba6d47c13b0fbf0b9aae6b690d1f6a37b753b17839af4eaedae885cfc5a8e0ca7dcf475431070c51fe1a515382fa31bf928b8d1f6e479e2c7a78c608f1c467c1fb203a14a89ec464c803d129a845371a02e5b66e47979af6f04c69f37e59638c9d8e5595c74e37eff86bc43fea19082e3649ee692e2f66e48e111b47b03d8f97aa3b1be2bef4c0abf268ae90cdd224f2202e77e14f4f74fdd8b27c2a29fa00816d7c6c94f67e6498adcd7d306dc8cd1d534cfd5c57c5203ec323dbdaa1d005eb33738c583184ebe0a5e17ff800ddec491e071c0d6995866b329d1247d4d3fca5a901ec606991949f70bb63daf0ba4e2c6fa227f4cd8d0f1c42b7cc3983327fd184c4547f995018e30e78330ff6cfcb89183cde28c07d0f58e5992ca7b1f47caf44056ab7af0055e2c33d8187be96cb36431cc7fc858efcc5ea40ec586ce420c87ed1022c1347e7d9194c985225422572e5d241c13515566269a342de394ed6cd669a6e9ab859766251194bdb60b2019f68b6c0c5124975513083c6193434382e73eabb23ed72a48e2ba77fd30f7cf6ecaf013d69f101bc1a6c05cafbbc2a1fa17d5555bd0f8b5b2f70e8320e4b66420fb9916d11f00d42f9228c38426ca24ad6685fafac8b28cda21d676053835512c32bb66acb706ce77b4be01b01c9c5e4ca284cdc69b721e1c111a76f9d2558d9b750662d0801a35d1564a31b274ae6698087313361fc08b858cb56fb413dc07567e20cdea4f6b809ab5670c0c4d8139c2f85872d009ebc38f69c564b53eea1d562bfb982986b4996593183f7022f0b5f928ce8786fdcaae49f5f593ac9d3313855f3c01c462f483d55f42d2541d17bb36ab5f8831a6d186813f003a50303e5620365ad82c2268eb3e717029f714202865d889ccb5039b3959048827c44fdbda923cfcf91124a927531572f573e57cf2bd8a87776101d92b26385a784c650590349d93c17260431fd5670e61c6fcb32d3ffa8298b6f1818cef6d6a326e009b3b612dfbe6d570407e455c6e082a1c3877683591d2df5d2381d16d23f268a64abd21191457e245d33cb0f21372dbad324ae328c85dd3a3543c880f57cc46d13baaafe9fa8038cc6cc8783c5dacb846ca1ae11c65082632aac1f7dc7e31c2f3c87b592d4d8e6ce631092ed8248758c546c2d0808a1eea6c09a1216a332d75f1185efb26d5c2613e31b06fb3a4de56871ba7cb2ae9f48439dc1b6b772b4ba3b8f7c5d21cd92942d1c8e0d07e5142880883d237b4281dfa90e41f8a50bcf7922acfd02ef059513859621e2e7f0ac2ca5da1936264340413897c8d48043e821d613d1d9ad9e61e04a2a5f710ec56ae17d4f3db17a17f026ca70ee59e6d58fbc39ff9835eaf01c56401290715263599f686c71140c8e0da536d038e047421eed75dc7c67bf7f8955be4d582d97f7d7a717939001ab097b79c39ce975675d71c47bd67a76fc4ea907f96ef6ceac33c45da5b19c53dc102cf0ae2d7e9e42cbd3c8d9d51ebbb36bc30a3d710ccaee4a7443201cd348c2c6cfd29000f2350e9da5433b6cee557466fb44f7e9a2a363bb1c5f3dc0ee5e535a01a06ea2a6c3b3d3c480a3a1c6c1a5d9c505a23f7856f26a1959b849e9be7c3fad11a30fb0c9212c3f759ddf30c954529d78d9626c195017834e2ca2573b2d0a718a644ecb00cf36f2210699aac08d112ccbf81a6ce407e33dd8a92953a06d0e08eab328fbd28b823b045b2f4bc0499b024a753573815a3b28b487b61d86fc2e3e8b23d204b75e1f3535d1900490365e13767cc43baa87b89be045f08aa382c4e89c08d3d9a67ba3c36e84dd6203c09de9d174ddfee067794bdbe0731894f554bba42353933e08cec6f74ab8972fc6ef530d59ef317172f4787abab5056b3daf23bfa4f875989a6fdf4e6196bd5fafbf1f3722695e7d8189fad26da6fd4f1c47df206944598e48c05ebbcd6ddaee098d978f78a42b70e063f235fc655e5d153c1da6c7f66df961b49ce59ad3dd2a0e0f40355298c4790947614cff8eb1c5bad64fad2b9e454b30ada5b060cb95141950a525b0faab5346173bdeafd5a3530b86756a6cab547af1daad39ee634afe7faeb6fcd7a9c42b3cd26533d615982e7510431ac4147c67641995ae639a0be2e8b8549589d03d1f6e11d0d0c0e6f01d2b2a59474d170c2ce9064f740c32e14a4f6ad463568b746469cf5d59810cd8c3d246b8742b0147def463da94272ea2be0cf489ef447a095ab91f90937b67ca9b266f68a246ac2c7dde591d6c1991416a5169318a22fe0f193f1ad27e3f7a4d478a7cdf13b3401c7371c769983d49730b3a55889f752096da8dc330ca7135f1bf76a48b91f198fb90ff686d9b18d2e76ecbaf1e46c392dcf5edcf1e07c0f84e2ad24b89a5f686736fc4d39026de90960ca30999b5576805f31694db77e7551bac5d081e93091955f9ed18fc7a8bb21ca4febd58dc9718191e219d963304a41329540779550c0601523ea6c659c744ff1fc6a3ed1588e4e7038681a4c6fa8202e2021e5e58a678c23922d1930e8a4e31cd12d963c7ee73e3118cea8bbc7594a09ba1372bc2812207d789161becb08cdc328842ba3370b636b073918d16c8251db7edab60e9ef80ebd5c511561399ca991e5af27b94be20ce33f4408e90580ef440920c53657f1e614d360e1f02ac54f59e211ed2670d88975365af607eed40e781ada3a35ebc8fbb4f2aa8969c2cdf505509c98225eb3ae4743b245399c0dadfbf4c9dc6e89e31a129be3e10f27341d7fa9ff1a6850f9db0d0dafd5f7540d1548a413abe85c07a8b992eeff3eea733f4b6ba5e21a46951fa6bceb51936a36b1e89a36d4f040b407c4d8355f9cd0379dbb58b5cb8e424d730be62051d973a4914e71a178fd9a42488507788930f3a3e74f1e43f7bbca8d3077cea81a974658baf61e532cc03bd62b7a32d415b81fe4c0c610566cb08e55cadf0cefb14a2b07b9e3e7ba9f31712e9d5e16f6a7f7c2a86a3c0962905c78fbe1ce25f873ee39eb7d87bddccb0376ac9b79362378f61d2ba0cc53f10238a659a545aea55f5912ed196d8280c268d01c673dc9a675551048a8dc25f946987fbca24b7fecefe50e065c03428768a23340c918cbb72fe2c7663c57eb106dd12c4a07d4f6d7067a9e1c16a28525e270d57d00a1d96f4513afd078824aa4a5c811eb9469d06df8c3b5b8899d4b8f27d4312338c3826af09b3eb544ba32cd40f757c951e354cddba468e11df892fd9f8848b623e158be8292f11c8c1176e12fa27ad3267db02785c205c1e021da9e3d2cc1ffd6687b289ddfa39289fc26765939aeb0680b135e858ef23e553ca30e381e55702a4223a40d17dbd6289c42d4071b3a802a4fedb1ce745698884cd62feb58c7ffd88df84d713aca2280b85dadc590043671814f405b1d684794bbbe9e16b4a4c5122aed0cafc9ef3d8b36095cafab9335f2afeb7a890bcc881f5208d1fc47027241eac377433d02db7cf4f63ebe028d12d3fc4afd065d3606b95695b132d44181f56f14a8c976a325b9918fb0cd2d582bbbd90ebbb2ea68e46f8b603766086146759a01fd1b52acf4239a6773e69e0facca6f9beddfb45366d94e7c940aae37d9faf3ce6031df64a4407b09ba0f05d31ef36d37aaee063c226d05533eeac03059c6fc86dca3e05e820d1f823af2e3f743a42e74d0242784db49b9eef105a686a45ca48ad548e032e25ba628118f68ff3ff492ff6020104a1036a93d6855b3050ba9a0e6512d7f34fbee968193b47a7de584f25272fcab5a0d6d5bd1d8db5b5bb9dbf007312adcdc55594f1f52baa57c2b0820b08e4124c3bd13b33a91ae21f0df24fc13fc3463fc8b5eabdb022f9571be94df6de52ca94640a2308440886089e2765b77be3b0a176afbabb9bbbe7243323c781649d6dfbc89b4f9fdc46e7e4365ac3dc72e0e9520564be9c12874ee736b9c949afcb20495541fafae3cc0f3def3e7232a7dbe901c28b3de8ffc123c72d4803b8b90c921c732228628a9c94db867022c20927e593227018e2288ce75dc76d40a8e76c10f7285bb74759ce5f6e6f50e353fadec7c92f44210179cfd920f05b0584facd06a1be9b6abffcb0e57d1c431991f4b9142cd7a08c7992fb3c195bca6ea52bc51b7281aa8d44feea088251f59ee6538f7a2a40aaefbeeb3ef540dda76c1015fe200bd43dca0671e77df7443cebe22742635d9c7a22dea7ec122a40aa4ffd129af79e48ea57bf7a8ea168defb1368622eee04558fdd2962e9f227e41b92c44cddd653053c88e1a1828db6d1c01cb144115960d0c10d564c2ba629aad478203921c3131d78c151c41849e0ef6febe2fe46965346203c98a2931c60aa3fa33a6eab717dae8b7e24c1e5ef3e312e3fc7f49b5f3d8175f839c75dc041c50994e8c22486c73d2edf39ec619e9f1de6d979e6797f318f2a4961d424161e564c1b95de2ba616d34c06d0a4fa5377f759bb96739c0de5e7491e3c0cbab3bbccb0778d10ca3bc6073c54168e286aab0a51c31d2e465414f183e3b8bc04965918965e1b1ca3868cf4e342577acf17f51fb7f974e92a1e5554fe2ac8d41eb63b3c902a7f65b14fbfbb33eaeb3ee99b5be94835f8467327dc4340ab2ba623c8ac989e682f3d7ae038efb8ee4b711b9d72092462b80e061495ffa71d041e0834b0a83d7687870a2a57ae3b75092d4597777880a961aa0694f7ec91d0493aa394d4ff7408a98ff39715d260076378961db5f55c74e7ee6a624321a594746e939b93eb8e93296fcceeee5488fa312827f711c1458c189d9de3267fbab36a4d92e2756d713bb5ee80d03b67aaf4cb4112ee92bfe73227edececc814705c8e6ed87a024467c31053646d08d00910f8cb4a433cb9db65a5215c602ab3d1daa8487e7777b7d7498e67d1bc61fe307b983aa4e086497a417834a3a41ac74920d7f33b9cc4cdf37f3657ba4bf7f849b9f1e93edd6f966c4856eda666e37f3abe94d67b7148832d02abe692f5e58b64d5fcc67bec86cbb29270fea725eb0b0b994bce73f3fd735ef1440a315100937a9292ee09456ebe06f090c9147a376425cd324947a830b59d245451c84a421da1689b0d5146f78955adc1c6b16a82099b6ac4da52e37ab4864da6068360d8bca20c3dba5d840a133de8dfd901c1ff224771616ef396af7a8ef3451c1b3f2938eccd52ad8955149735c4dac21a620db18c583356118b8895c41786a196fa66e9464c1f60e86338df7f53631f1ba8296ad8fc8d8c7de6b35644ac304bce73e3fb594ccef3857dacbad0a8596d9b8defc63f6425452938f666c95ffda8296ad8f026cc452d35ece68b8d0d6f98587123631d960d6d3cdaed777d2c26d692bfc234d8aca65597e883f5c5ce5811d5d8d086a86d6863235b195d56d26ac64a5a15dd6635b1f272fb3d5692f3b4be9d95c4c558b59b56cbb2925849374c378a50c51837ccbd585526cc1887440d5147b3a31e6646b3d96c368dbe19ea08858a1d3bc6168a6d1fc7389781c6a3c9aac518232ba9417f0f8a785748717564a686a8d9d19dc910b76fffefbbb9a9891fbe2e8eebb5ca84199b43fe5a1dcd9510bc3a629ff9ad2fb7b9dcee8eb8fdfcd371b37387207e8f9850b42a412277379c330e55a5c1c8527a514d88b1e70f45ebc17928fbf47fdfcdcd6c168db69ec5f828215047a82f282ea8236efca616c5b48181a2ddf893a801d18bdadfccce1165a403f374fce2afa9b9b9e10fbfcbc50d5f973f7cdde63b6794da59c4458d1ff9a6c686dd8dded3dd368a66c5e31c4fca54cadd3d544bd4f7b33d123d983fff06fb449b8475e6f760a91f6f60d81f711e0ef5f3a3933894faf991a861aa9ffef363110aec13697e7e0598c6d6596b5db55a51dac0bf0845f545a2f8243a8932e739d2d9b0c7bc81c18d13a148004f553a5d019051e5fbcfb88e76658ccf31472666b20200a3865d547400a20a7611c7d5a62e621f9a58b9568d4cfe92b28b2abf8b542fbf08e83c7d027e31cf11254023fe4acb87d64dad71c2a9554ff5758c9364d4e94305ee72ecc359018c51fdbbc6451ffe9129fa70eb4dd103f9f2630cd887b3ae05eb789f807968bc6c2957b60f57f695d5876dc495adc495527a93f3d07899f250369f9cf94b3eeb9334ac37f94bbeb45c8dadb5b5b252aaac2c12000daa7f7f18694d57f2472210fc6fb538293b8f0c8f7386702770df7593b9d6fade5f5106ad21fc8a1fad6c59550338e6a4b3ec4e5d78dc53a7016ad71fefbbdbb61934ab5a43b7774a39c97deed3e746e3f48fbbaa8fddfb501f0b9d10d71e460bb03c0d5184c39b072b49494c8c85c4424a2c66ddaceb665aaa965ab580a10186060d303d6c3d6c5b0f33fadb6f1cd356a51f7bfc155fb6941e00a755414add9097bca5f78f90da10202e37524ba53fbae6e4a056c4c80ad1c9931bb9169f5099f96025fa8043bc8931c69fd2e387d0b019373e90bb3b90aff7bb5ca1dd108c334ae58b08be88808692dd6b80db2f7e355763f15905c62f865a39afc70ee8812aad1417d0fc10bc41f497b4309f5a17916d09fdcd52e1a81a322df7e0de520710c6e470b585f3299662d410ecbe72abf3c8761e98625073c01ebe835359f50335e4a51c9852d074e5f5569c4a4c65b542255392893e6a931a725294dc375598acede9c7ca3d5f5a5b9d0af36e3605fadc141b5c48e684a6a85a6076fdbd9734cb386e0f4e97958c9cee002e2b1961b9376c6e2d410d513526a81afbc4f7483f443159d558c73f9c4c5632d641f9d8505935f691cffd385767d77fb821aab6fa72fdb72f497426d7c3590b5fc63e01de23631b352c5ccd29d3c884158d468b6d3d1c6eb8e9883a421d39cf84825ffe55f8cce2fae42272e48e2664e1ce0cd8247145bb9161f1d49a375c67fd8083cba4701631617469ae24f1a6e317959671936c96b5a2dfaa4a83fe92a6a9d2b21043d344d3b4a215c919d47045e4b3e5444473a815dd0a2e386846349858c78d9c87a60cbffcbba0d18871747dc5e4fa37d1e050c3154dd375d415d6f19fae399d674e9a8769182b9561f21c6e98721a26325b9cccd00d67971a3e65441d352c5cd1901a16a2ae606918cde23a991ba63c7efd57d8a79b35a38ca4241acdca1337e430a89a9716b47094a38aa51b3219ec5d8750d1c08a0ae583175730a5aea2151d8f7378005ccad462f4856242a28f78e937bf5593ba626aea5162e8c72749141ad6354320a0a461ac9444d18d4c46129319e91d73dcf8f1c6efb18384c50d53636ef8e373441f6e5f8afa3704c1f85c0423926c8eb631dd2dc64823b673185e6226769a52a5631ead056626d29513ac685794ae3ca111c588866482133150d49036591aa6c16d8931626e2c525969ccd1ed17410479b732573648e30e611dffa90ae25da663725c301b536b4a1a530bd3e494e444a5490d6e3c31d6c573dfd2c36908a606ccd85634631c3c51435a6b42399d798f55415097552238eabd38825fd4bb6a84ee46b94698d77fd22e1f4ddab622e7e198b66ddba06cdbb66ddb469fb6c89286881a16d23177a34f4fa0dcedfb511ff7744b7f263811b33dedd2305a5b1ad3b0eeb7a751a851c3386a53f0a71d398ff7db53a486753642f1b6975f94d1595083dbfff456c4c1520de92c16cdeef6217dbadbd3a78635190df3cd492c52b24283dbfb17d460f418db4636a628b6f3197e8a5094ac1014657128426115109c26aaabc631eb70dd37bd685ca0f4779fcf18e73c4bbc4f3d8ddd64fedab8671590f729cbb4d6e0f6de479ffc85e250a86ece80a0a13a8ed268137da235eea3ef7df329ad614dd40c7dda64b4067402041ae6bf7d11148e348c6edbcfafe5afedb79beb35d7bfb24fbc6e7b785f4d0f6a9bd5e0f6db47578cb2ede38cef36efa6b425cc46c50d535b0d883136206a378c58eea6da6e1893ee168bed5b51c3c29451c3b61edb155bd1ddb629778bc10db72a77ebd130face337ffb6d7b56c33626d9392a40424c114345e070b3492e6ede73cac9429285ee6ed235d190d12101050caa05952ee6f4ec68e1a2f51cce65252d4d6849e2685aa6b0162c1d5b38e208094b940d090b1145444ce93c7669d0dffe50632da995a4a4e393eb50a8d73526b4c07359c908a7db7d38471a9cc14542d83aa2a441ff0f68a8f18cfda2c6a7e8d4a07750821a3f8c66bca96193d672c271a6a63e2754e6a77e8523a9ef6fd7759d9279b7d088dc6c28eff628a4db7d7f6194353d313935755f5bfaf03dcf8642b4db7dd8d3366481e976dfffe3fdd1df6677aa80d0b64ae69d5b6adacad15ca9f169aad4d842d4505e97754c62fce9d10dc51365dba4d69b5dee7caeeecc990da167444aa2863db29e1f53c6d8deb7ea2784a8fad9668c14656634338a520b7b7a8c8c66b32833a3591423b061b5d503758337df6379c32337857fe6121ab4407c6e4cb7a7fcdbf723a4c12ebeb794524a2408f0cf023deef6fef5b8326e51fec7cffbed0b81ae911e17f55205c443bd8732d2e3364c0a69b0fb7ebe101af46efcc0a186dd951fcbb8250c497d4d52affa23370524d1e92a89570a0752a9dfb6944dbdfca4ecc6121a9cf684e82a20f1b7a8da6c2462525371369fabe012332c72e9ab18f037ca38c555f1bd148312889152534a29a5941d55f259e5c10c363be917fd8c4550e26cfe94a1a45f2c226a7012c56dfbdb91a86133ce8fb2228f426c8ab99c74c3e8e4cad87c21254c1a0b0ccffb240e1a54666729a3bbd330eb44291ee7782ba9221d715cadadd6a3dc3d46971f51326ea84f7d38be305e1cdbf6010dd50be3d5f139787c4d787c8f1f725f37aae0570a07783cf7f88284623c78581b72377640769d478ee7f1b99023478e2f569956878d474f1aec48e4ea52bbdf9155ead9d0482a954a4d4f01f59bc731c618a35fb761d051838da5c1a69163c61c83c43e5b1ae6763e81ffe2e003f0fd8e1cffd2e6594e1ea9119ddd904eb9ed44a3d0a7469cf5277fe978cf3f6af4d15991dbc1eb78a902a2c3292c766091846e8c3d46feea1e3c7e033d74e8e0f1aec30ee9619f1829c6c3ca223ae5b211542ee3a041f5f762ece82ee78dd67558af0651e37b1d7cfc6c74605dc852280d4627f6893e931a7c59d086ad00580e6c5877d8cf86dcdbb02feb73d8b0af8dfcc97a9b682712eb748e1d2635c744caf14da779e6ff43ffe9d4a0530a0ef674a2b3868574ca94863de5f8e934cf34ecfb1cd626e16efcffd5ff47e3a9ff549e4cfd17f6d16da90a42bf70614c165f9880cc17454851e6fe57f3f1fb3b5541a8920c5a5871fda34a04111440bf70610c99ebf6082c88ae8e8f8f7862e6c69fd6f1a170e591c482e43c3c3a6cddd68dd68d0fb9dbbaf1ad1c1b7200b0d6de7cd84739fc699ef97ca8f3c94e270fa3865d54e4fa76fddb90d3615d1fad3f85b98df3dc3838ef5f089f907ee5b03f38c250def8c29c7be32d7faaf125894e49e28c2fccb9e144f2253feaa37ebafdaa3e8a4429d4179fdc7e2e34c2351a8b71c84b1df65cf6624576fbb68c75b3185ddc0e239490976e942c64dc304e5132624a4f4f4f4f9be124246cb8618bd25efd31754454efb252162f9baca22e2b65d9d242962bd2cb5684141f90639268114cc0e05834cd312ef4182759841243110b237f315704163245fe620e849e1fde0b71d2e0b6c0b8bf614485854672388f4b13a5ed8a2645a0a0891037e49668f2c30d9a4ca97159c9033d70351a781ec74d4abbbbdd36e5660a2eb7fc07a78c1d3d32f3ff7fc3fe5f9220ce6ee7c278db3233cf1b043f43b6108494d0b0f92740603e5d4ac63c132b75e292ef2f147349eb6a40bf3f50bfdb202af2831c08f5fd285bb932ca0ac5e2cbe69967fa459fc59a4e3ebc54d039ae7fd8875efa4268d3a5ef3cfe94babf021043adfea2743af98bbad3a14bfda5b8a5327f514a29a59c8be3706442808a187172a9d3a594525aa9ac6161ce3c43dfe9727143eae4d29c86f5d36f390fe5ba3003ca09c47dbac748632839ceb9568373cecf81a5522faa82208965a05e7e42dd573dd4577323e7bf759603f2a968b906a795f6bff52d9c6f7f0e866a6b83bdd35df1bccf8165c852971f9a56f3e58704c87c8e93614d5b56ba0287cb4a3188a2140318d86e6558aeb3d4a71e506d84250ce578638517fd6563eeee66ee19bb9bebdfedb465ee39ee74b39219b63a9b6401fd409c0bc29beb966a5df4a38bbedcbe21ea90f8d325b5614d71c8f11703578b1d15d40e5644e1640512655851a5c585921539d440b3020450889698bc289a315d218210644862aa8d200422598b8b32350097953cd0c20d1909457ba1cc86c50b60a8bcb0850b24665749dfafddc9f6e8ef5177204338a791e2401d0b5ad2dd60449ba51a7fce3967ff4f6f94a31da55b4f4739e9c6c939e7e4e426a99453ba803ae6df31b7414b626dd95f2c746f61f4b0276d5648c76ca0e0b8e9c80d916888da2350d428847584b89cd2850811f2ecc39b1231723b1edc69b57429a50f492b1edbb98d76bb945c0eecee83dce84643e0524af9453a36119d98fdc6cb1b84c795f65950e33333b781fe5ce9d71be5a2d334c384a405494b181bb5ebee34d6727d29d2884e701ed47b34baeeb5b65aff2078435efa711eeb6a40c736c9453dc186890d020d7a91136850c348a33917ddaea006d58f8042ce299554315693500912631a600242c5508030f8c0f5266020a68a20984060e34888fac49404adf3a823e6764b2266e05c0e15475752115541644f22f681d230ae614713cb449a5bd867fbf8138b2a754a941b7fe2d03c7f8011dcf85306f6f1237ae082b9c474e2c649c58d9686fae24d75dd1719ecbe5523c8ebd9b003f33def3a5942bffa8e090326e0003f5eea0fd2ff50ffee94949ee10e005c086579011143b4600c2d2a98c2c9183d7071664b193a70c142f3821d4f8e58925dc020bd890b64702f382980d00e2d28638316803082e249cb8b215a70620b2dc884e18211b7c5055aca4940a7f4d6944d943a70876bec344424e607f9382889b1c289d1e1769795c414a59ea0c2488b96f829e61f37547fd9aa20dd755705e1542274acb35de70655416a10bffe1ef58e9452a654a268fc7f3a480e1e6adf29628668636c368a6aae9b43254d4183779cd21421f0008cfb108424c00c8d8b420a1b6c1b4afe8420a48496115e709c0403c6086a60cc8020015b38ed80d0f3a365040593aaac9e1d10a899178e6ec8b58cd0c163256a6cb538ee5fc74b29a58c524a295b4a29999999dda50d3b04a83e523fd454833b3b3b671ad630ca71ade7c70e08608fcf69e1842cfe72a50fb7550c4aaee9ecd7a9bed3009d7272d167cfc1a02ec5218f915da073439ceb51d0aebb4761e6ba143f5c1ea118d72da892979e649c0076e80f6e985a1262e906d504666ebf6ca11eaa209a2951650a92140d012f9298fd70e603664410eb967406fd2174778d2622144720449a4c268361082f5d77d8e3767bb9216f690ed3c4076e7f3fd744edf6d7561351dcfe0fb3c3ed07c37071fb77acdcfe1e27aab8fd42a8dcfe210d63a5279e2e2fdd2660c4b01218302e2b813173f959041a17755341e24512cb78210e4931837ecee960891a2a99b3bf78bdfe695ddcd703d74d027f0f08413c11e356630293317c638c9cebc64baf54dd7fa23a9606a9233548fd8875a89cf98bd2b0a2ca99f3748ca22e4d22efc64c38358c8c1e6a2845b565605e7067a4c01c5dd5a579eed952474894ca2025831bb2ccdc1027c6185b382740a008051a368f18699036f54b0bf6012336451f4ae2059887f5343604771efc1ad69bb7f9307e51031b1f76934bc386e1d2ef115c1adf36dc59c1796e6ca4b56cf8362cfb2b456d6a6c08d2b0a1ce657dd14cbfe8479a6d32127dc43216609fb805ebd0a7ad43a8536dd8385cfa2b1b825465c37ed26a6a43ce9bb18975b61a135a082399db50380dd2ff69b97df2721fd7a8e16293f3b49cfb4c60128661f237f9a15fce4a06b767700bba1c67bf41da6a9089181b4afad14c83d446a7cec626795df4364533cde334994c56821855825fcc04bff892f0050a26e10b0c18e41bdab8dbe6ba396aa8b12fa5b2b62a81c7396145bafc2eefe3f57e341869d498d0c29306f9368965c4a8f4cfcb5f564082eb75eacb0a60b8ac4212bfa8a08cdb359ad4300e19f5300fad9ad8e700973fcef8397e1157103589ec6088164e6d757054f9f9bac0dba341fe7a005d355420d5f30b29816f8c32a4612aeb4a7dbc291b67277c414422c6dc38336a90bffb6294297116639c31cff8c5cf1d6d5839876d0a95267260789c53c33fb7d43fe2aff933e54aa56aecfc10321f684e10ee9c4bb154ecb0d631773eab617cc59d9f33bbbb57c07952fbe3bf2bf53de5863de5aa9e0ee1e552d5e4407ecd9fa86e6e934e228a82aed5baa3dc5163eab818c6be7dfb3fb24fdb8089a523868ec08146e7430ba49610d4c09331239f029c96f3fc6c91c344c2871570ddeab29297315ec45ce1a50bd292136a8930463421e5e82266c988198ed2982cb22c53ec0bccd096a60c355cbea8a165bc26f933f2d7629dd8de2cb490ec58c663e671fa7147ca2f43b798628a2b59c088114317ba050352a065042d20b1021c6a90818aa0a30b3d28c8a2b9cb4a5c9846d07a9c249c54a1a149110f35a8c2636860058b32b21966a075b13d512d281659b8d8c0458a0f28818403c81445a1e28726c260a28c46c2044c686819275a5d74cc840b588481c34c89329c5ec8b285062292a2d8528218cc2c50b4a946a5e0707842d229bd84d6c6c5082e555a5dd18cf1a79c5a393b3f682e6ba23a2951831b824a20dd10841b332c61e6054eb8400397253ac8820b148cf1928451162cf3081b67b03411c1161f12c892e50b185441a6c6041216e400035217677ce0018b0c282c2550d12f6670a5858a214a29a59452f24b29a594b239166129a59c62c5491047390011821810bf1757b297a51aaee42f9878310a41142c00810762524a296b7c01e60832375892c238c3c5c8260b96198e3245649951d352c4cae208285653906a600db162e6170254849999617c250f2dccdc6e8e4aedd836682166d24d725b86b618491e93028f2750b9f6c419a78671cd092cd7b9f644d2f5a766e899ebbfcd244b4b44f5fdaaef8ff1696c5090d09121457e9898b86683a84869816c6abccd0bc54276fad573acbf7e9a27127f6597ac3eae6cfc252e196e328ed5fc8ebffc3f88cad350a936b6ae6c10cdd3588e85dfcfb1d54b9a27529fc6dafc929aaf4fc466498db7798e853b0f583dcdcb9acf25adcdc7fafad19811692dd98d0d8a3322da4c66e3a34dfe7a9245a2d6ece65d2f14bbf11ca3f161a4798dcdd7bccd07b90d1b1499bec6065101aaf91a3628d6fce53636282822d56a906a6a3562fd303addfe5cf355df1ffb5dd312517d7c1791ee7fdac534c5943360cc683c15a0199ffa54ea550f947a55aa67a9a761833a657b46d4b2d4ccc6bb6cc60c16130d1b36c8c6ab7e860da20234e35536c8866d272b63b22fc4188d7672dda035cf4c35d635c376aaf11cab3183c6872eabf14154805a9f1a4240ccc68d0dba7995ca06ddd8ae510bea967d21c66c58da64f361d36cac6bbe500ca95ad7b4439c08c5e81315209b57bdca065121bafe2a1a90ea6bd82027f297cd8cf5d126ff195fcdf7e30455f5a113a9ec122a40f555b325d5ba805634afb22e22aba7f9950da28274fd89d0a71ab63081099264b29823f9cb3f68a863f559984ff32bff1f3a548ed56a488e05062b5ebc8c91c996b0606529eb9a76042993327ff9bb5c43ea4ba9d699520f82918c552dac08330343a34d4452b6b22ea0d4af3ef52bebda9e63a124baeeaa776d76086df2973f7572a7ebff62d4a749ce439b6813a549d78da0e2aa3ea447d725ad3ca248d7e527679fa449544cce3696d0ec56141ee7c4bcf861bdf3bb6f0b6a750532848bf3338242e2d8c6316e58ac490c78cf492d33a06df817f5294ccb75a36ccb561e7a768bd5f2eb9cf58324aaf431dca5d30d0a2959b8f014c5165562e030ceec30e4c529872a64b458ea7898d13f48199262036d8627b62d335041bb087b42b0a6050f44435900b14319156cb48b323ff01622326a52443943c6918ecb4a65606822a3ca1435a6aba46f0e313cfeb9e29cb915aef3c7ee6ee79c27f2abd340d791e7f5561be7f6064d66905842c20994362e6761e6329dde61b707f90dfb312074e3cbf9575ef95288c62682f666af7357ba46e064b72fcb6e7c067037f67c6eef8bdf7cf948b64b73285193448b64e3b7dc955605effa7ba194510a6612a3649d792309e9c909c4e79c4aa612ef3e236d5030a7eceb72aa80c8a92a41a8bbd3ba4610baad1aa15dfefcfcb24efc27db6a4daebbbb6503e13dc3a4bbe49c1b2fab3ce7fe747422b9f873ba9c72cad864b8f66ca254124466ce83d0acae9c739b91759a3e4c72a5656732b7cab5b6eda75b33de1c101ac656e27c0ff71f3faacb193c66668e53b04e24418d2a6a7cc9decd44c4f96da73b50832d19d4f82d316a7c3335fa0e1ef5c83ad2a5949267e3a4f3746ff79eb39d9321c71725b252da2a53d929e539ffa7552508dd905ee61c9f71e3f5d8443633b38f0737ac53ea8c1b7297797a2693c96688b90ffc621f24205d610ff8928024855f7c79c6fda2c7968612ee2e5dbafb94d291f8299f3aff5f67f7e7568be3a6fcfede305da8fee1fff5778e79a494538251762af497dfc489ec6e29653fa5d2298d1c0cf1caf76f5939fe66638cf1abf2a59472d2ef183d88fc3a6ac32ad31a575a25f3a9305d7ed944953f656824b6e2cb6b2432b5149e73df6da10afe9c12b74fa5fe949ac49debfe6f6755f0245189ffb42a70977d92748f440afdf9ace3bdea1bfa5893d5d37ca4a15f381fe5de1dc6f93e91045dea1a81feca8a990b76b132e64a8944cad0c7906040a87b1b2a77b142c6e52e41205df939200fc72467a5a8de55403a2b85e6575fcb5f72a6ba0f090684ae149a577d4d68b66715cdb77d9f03fa4bceb9cdcfb5cd39a7cfeea9b771db46376e9bcfaa05743605fadc9d2320d9a60ac9763110df7fc68fc2e37cfb64abc571ef3978de0e78a5949272b5e5eeee5050882af9ae0ad2b7633f735038b282f378511687765c8e6ec31e71fbd5c7314e54b53848523d40f59e65c10ea562aa1f9231279107d07dea8bb15601c998cabed06415f3be631dfd38669907c0d9d8bd962c5a620bf19e9e9d1d10f4d675ce88bb8dc047a06c27c4fd3868e80d061ed730e6daed1bb5d24a18bc1b59ec4c39a5bb0dbbc3c87e7e7e42681e14ffa03e0a1431a226d1fa38f0b2512fccc4e4b15d4eba711dca4ba96856b566060d968d1402dcf80f0071283e6998eb1907478e671dcf37cf1c4c019f5fcf1d3cf378ee9193d4857d7408b0c37edcf1e08367017c1f833b3ee7c3f145e0da1c1d8bc33a3b704ca0c7d76270c7b30a080e0578ecc8d981c2b59565e4f5a5ea11f0e3524a02f0490677e47077c70a1cecc8d991633f3e00ecf737e68d1b371feb060a77d639e7bcb9716327013e56bf5c635af28301ec781082d4e91a1f90ee7c7ae5d2e604f54dbf7b8e49da3d11ffaefb25a877cb4ea45bd2dfd9ca44b8253e871a9ca82f003154cfba80baefefbe3f045daff92ed710d49bc03122525036cefc35e7ff883e86c09dc99cbffc35dfbf4d6e1bc5419b0fb485a8372a23d19c33752792f7a4c2e39c90ce2efde2e51ac6bafc1fdc20a5949cfc204aa08da8842df645412b15d140000000f314002028100a0744e270382c18d38555ee0114800b7aa43e7c521a8a83519002290c32c6184300210000008821646686a86aea94d47dd2fae5a8e099cf943e81ad240ecc4163d2344f0f046306fef3d1608dd823cb868a8290fc286eaa502260f09406f3ab1abd058440d9a7069da3a0584dbc7e686abea4f113a496410fddb61fa3782a58b03e2f7da43fdf3b57dca6068a9707d6837c1f6cdce8155a94643c0ca7cd03290436c7979301e5ce36afa5f52c6419e3d3c46268aa4ef76458b3543eb6b228929aee9ae0b74203bb249bbe34b6ed8f97375899121340e7ccd22bd19f7aa8cb1ebbb2601fedf8edd77862518004f0e2c7f445c610300a4d048ed39f57a688995aa95ab8fc4497bab8f8e41ef54dffb48a5a72fd443775bbf4c91df59bfa943587c4839c08f48f7888fdcd2547259ab61e647c10f07551423eccf206c8dd08ff7bd6970829baa670eb69193bb1e8034d1f5a388e5930691096880448c84a3b3e621ca4dc59d91b638a648bfee6d10e0223afabf301c81153740a65acc6008ecf8f1af1437ad66c85998448146ae69c82401467e8159ab7806c3d245643d14ace1910f55fd59e5e04aae920531b18bb1fb3ecce3476af67d89c0f8696223e544c72f6c8517caa669942e72dc46433821e6109050c00c21188f7ac128868d4237fc777dd8a1305a8ac64d8b0507a86ac03a0744e5a369445090ea0c5ebc14da40459733dec8330ddc17a534d8be74eff814c1d1caaa01ae565f4f0a7f5b1fad680edcbcff7e94d543e5d7c4a86b8ddf9868a813ff4d1722f944dfb3cf93d2369ac96936bc970121bb39f75a30e7f7f7c7496d550b10987c360ddd3561815cef0d6aa077947a0bb885d630d2e8a540c584ed79093d7a49ecf30b79cdc99a4bc09b2717e12caf9197796e6fd1bb2972724203d21a3810ad397ab9fa5a852f366ef0c751697022050a1a86af4a7c5f1769679089ee9b9e52bb4ad0814c798108af197116ccb9cc31b116b02828a49ce4a8fcd5badc5c5778b85c8f5a766d12901b7dd870fc4e5b2d5a97c943ee1f7848ea24b51d9a5cd54eb60419805162fc7efcb699708e4702ecafcdc37d801561028fb2e4d150f12f912a176edf853670a8a9d3ae46066ea493a8e97495af4680dd6cc15b0d50fe005bc691b6ce8797dbc493674b6ace87cb2609d0377656207d09e8af431b39d3f6522cfe241bc4a1494ded3a6bfcdd7f9e96fb221173b12e89d24397547b31c8a354fbf82eb657b4679ba9f5be9151928f5b9f6cc54a1d223f42c8dc968a8ece06fcd6222cf65ccaee3c50c79e427d642d4aa8b27ceac544d692020dbadcea71750ba5f2a1c56e131cf65d3483d15621346c04cdcf842526315c16c97e234a626c20ee58bae1444678d9eef05823b7ede794ff2b881c40c405e0335fb2644ea75e1e05558971d292addd997238fff2c7d93e8c3c3499ef09cbe97e81b85f199779a9ecd84ef48471019747420dfc33fba2a7a7a156eb7551f21645779d5b43b7760c2b0b0a7b69f57f478c020dd20d676fdd587acb8eb042554e75f7a2a301ed15e5037c71242f5d8a751bceabb809671905c096c01bdf4d414ddd46bce4bf7c1b31308c483b027d0bd14a1e0e7aa114ea44248564064e7c13443fe8919bd784934f2f46bb65024bd9731e390468d6c3e15c7b63212db9b77a9a682122ad297abb7f627613a0cd8952aa4edb0c3fe63e5298895502d33a1c2c9d927b66dfa0302640773d9129087938140351b01149f96346b16b8a6be26ab2d04c925512e60a14af220759505fde31cb602de28bb89113a3c305e19b2ebf9389cf678951a168072db716dc9e7e123d5d00cb96e36e92a1d5c4de61fa785dde20879eb4dec50f077edae3a549e1d18807a0ac1a918b4cf4e6fa463002f5dbee7bcd54e5361c5953c3861026d2651c8bf930619a91e75a2e27ae8be85f0309952632684ffed1b9433b3910e44b100d7539ac1c9fbe62cd0e3feef363ea94a856b31b37928de39f82aa73cae8a4e64e0c001e4ee13003bb8714e8ec63ae3ccb50ba2d1b0dbc0c9750a2a1e7d038a3c1be1ed2515ef923afd64c41e38b58491adf14bb011c2c902ce70ed4811b84fd0ccf1d4f59f910ef4dae2e905861026be460722160c069c57df130af97142738d5ac2e4eede3b27076227e075cd9c61011de89acf46bb35f175b7d0a1a1d388abf1f6e9e23d83baf8d9f93b88281213b74878651c261323e94ba04092a43cda5a69228d9ecc15245614b4a1f0bb0520b1fe291a56602e9dc105f9012ca3330607375fc4b87e389de43e82aaff2204b414781e3b18f9f37839afc6be38a9b40bdce9ddbce5c744bfa8f58e436ffc79c5d44eedfc4c4eb3e1794f43b498feef1978f05f641b3c55ef23b027708f44e16805dbe91421b678560d6af7e8105d94b473366ca88438d88308014691fcc0640eb5e2b535201b8002a874a5f35dc19fd8533449248381daaafb79768c3887277cdd5b48b80c815bd99390628a7a32e8fddd757013e20b41f90955a202ceb4377ff0a4ebad4b944ffef54bc9463981164387abec2eaecf13d2600d42a94d7ab996aae6beb320535115524f79cca6e67f15f4a31d9f58ad6b19db02bef1cef22d1dca3f8ed344eb5fcb0e5d116f5bde1efd71f2be2eb0260f2aabd3d336ff6a71f463db8674d66db9166dbed38593064516917ffa88f08aa92b13c57c7dd26326930fdce46ad88de073d16ed0c892e1ee3559c56a7ac857118fcbac0f732be80d6e83e8ae58dd9ed805b6791b5350cb16da2208e81cde836057988979013f05dfd5722ce9864255dd2a5a39dca8699cfd53c78a7f7a5845657b056aa758cba007856e4c10773fc87826b69aca46517c445e73bb29dd990ac280242552da38838564465899516142ddc2fe75ab4e1528222cdc26c89803c993ec47355ccaf549cc5e8194a1f34f47f5b5fb31fa7a1780d393e0eb60b0caed8209583a36bbd16303f00866838fa293706ce0bee804d8668a048f522190a656e875687b54846fd7a9018412dedb4263c4a744bbccc82d76fe64f0d5ddc3faf1c1fc64fd7010e0fc824afbd9f2cc12e1acd21d9a57ea6d213c4437fd1df94459192474d1c838402f7961590ea4e4522a17ddee2e32d4e57f1c3c3bf091dfd2137fcda3045d184513318242df6b86fa15fec3a7178d40affa0df67172aebe6f212745f80392dc2dd561f42463720bc41e762ad4356397fd325e28697ccde7be8c3f3b7bdba4cd1161edea1e54a007ed4803f1a529cc68c5e15bde83af5a0cb937381a80899d258d57d10b0765c51a8d2883b34bdb4b46791fe156eae50d4ec91a35eb288961a97d403174099b540631084301d985fed8272d78b1e62cb15591deafb421a04a79613754fcfc2ad891c04053222ba0a2a7b37bfe43612de9661ecc4146a6cdc8b1ffe3d5f7c74f15662a84ab199171b3394db1cbe43fe50e041576762f7374d4e7d32b517c5fdec3660956dbc02858303e46e93993ea643d640976f233ca883a28ecd693853c8399833b29beac8b0a8dbb941941e160fb965dba9abe889367a89a8db2a737fddcd4f27d7f29fb61c3ca65e2b112d9706129bb6e955cfeae1e09691585b5bb806ffc49541fe68c551c3f7075eed9d9769a1cf55ed1026e3e7366513eb4af38a52699b308063c6b12a625f39bb19fb54abfcb978a35b18341bb03de6e3e5cb2dbdca964e30def322204e93150c56d12c8589c80cce3dee1897305625f6804e1d08a09e2d59ab2870acd30aadc347b6dbd528b1a3ba5aaa7bb10cd6c9b577d8d51bade6e4d6f965b936fe2650a3e936ad46b5da377f39f1fe51e2b5cc467e2bb0b38fab15125611c100e27cb243c85cfc11186b99843fa0e348d6837360eaa1b50501f3f8986559f0b93e1fdbcb3a86fb6a5db4890a3bc012641d40ee6b5f35486583286ac5e935d009923d72fe8172d926c93588bc52c464befbb692864567b8e2f2257aa4424c438366170d8f97ad31be0eeb22f70e744b69e092bf895b1605db392cd467cbcc1726f9be57a84f41adc924a6881d678338da92c2234814799de58a6ac5dfb9d565a46f7b12d502538ef1d3f0a429214f2cb54b1afa7caa2c8fec7b528689d05a5337ca3260b4796082361f9718cf84ff08f39fc707a2ae0611b1ebbf4f95353f33c83318533178997cb13993d847e0ad03d2923b0a3c50cecd675d670f3d48524a5afa283bed121fd7e4215c224223923a57db48ca24f71331f4207301460ec8f6ded41648995c963f0777e4f3f8885a8e3c879cc2425c4f9b39608e690689c9e49b73d138fa3cc94a3f39f0f87d804b3559f54bb7538548f7793b7914bb71f1515f3aaf226ef1389abae77c51c8b5039d08034476b1d81eca3dbc4dbd428eec89526cf5c7c807618f0434b4ef33b6d61e71b5a50be58bbcd5a4290ab7482e853f71f46bb88cfa2aa8537e7ac573b1198b414f3fa5b6cc06386aaaf33f1759e441138bb751f2d449e66039fa20ee413dd88311917edd8f1881b9f81135494013fa1809626f4839ac4dd139ad1aef2be6b58c6e99dada7f28806880363f07126c69f806226fcc46e2d1e1c28afab304b238c7ae91264baabec92f1349da7628f7971de73f42403a24558744f24928a13887b434181f61132a108bae013eb94ec0293bca7e51740f3c74708d06daa8253b6de9dba1a73680a37800c1ac216ffc7a7658c4a51477940df17afdc02d44e9bdb7f0eab722c52e399955ad437a55cabcdb9c23379031ca5d7d76099c235d0f8904ba33ed833263861bd156c006614351f4b7efd23780ed91c6bfc2350d3b3ac712cb96867088dd4873ca14f94bcc258477f4bf91438e9c5dfcf50fe9d682471193fcf5375653b103864bc66a9d63d4ae32b1a9a2973e0b2821bcd90f1949e1c6c8c9aea734d5fe97e8ff3edafaf079d1308d4315e726c4f180093fb52d03c77dbaf29456e4e88efe601b03f9784dd8fdebf61fb03e2fa22843f3afbb89c534f01118286b8d0dfaf1406bfdc799a80151fce7c2f326c8b992555e0bb1e3acf73334e4f3cc979b92c3c5ba4b320ccb7830120dce811de956df279d96742781e1914ee7834a679eae77fa8760b96032907fd0df52f58aa9ca60bf21f35032c7282c84fadedc5cee3c60eb2146adf115f83fc5311360d43909ea39805c2faa1be68f7968b0149e194ff85930e61770a836686520bd74490e0a188b94801c395852a9a2059864e83b8fe7c24efaa9d89c16b01eb561cc9172347d20eebe5196ee208af783fd562801190e2088b680124e301ff0f044a847c5363957e2cc3225e90a1fe60edd9ff64411cffca52777fa241f5881d66101014d7fec3c962e032b7b51392624f8519785c2ea05259525c82867b997eb79735f7d81591b2666f81d057cee468b917ad18a6211f2f95b8a83546d4f2ff6428eb00f55988cf38d5156eb17c262f41f251cffec49497f5c0cd5e00e761d4af0b0fa210ad45019aabdddd6f7a705690ac473ee3983808c25d8a04f06d201b1727f7df89d9e19e1bf8d5793ac1f4876dddcc9d7c1f24d8d0d7f31aaad98dc375cf92ceec1b0f068d67f0f7f4bd98cd869fa1e0462bfaf63d95e87ee8d8e4c4e457e14407ff2855bcfec525a0d471fc8a1ed70a7ea08b31495dabf639ce301ce00317d4d90b28de7a11d29b26cdf344a7f168587c26645adc87d880a744db7e6a607cc1113911ed3e149364537c8207cd7730a1e16f609376d351e22527d725d5d0dd3c0996d7ad3ca6e65e2cca56aa6303d5ad6a80ba2a87c09d90f59e2230e16a6a5824f3f6f6c667728141004408c1696a6151f281cd57fe0de23d3edefb8abc0a5a3db4ef063afaafb2e8c8d79237713aad7a384779df890744ba74a31d6ee29dc16f7d1a5009eaa26ce472f1d9b61e5a28543dea3b8b6559570175cea124750b2c4db8a58810c904f5694ced386672e7fbe6b88e3bbf9119626f23a4374d855549e3e2ffab2034b7c3c7aa99ecb4a0714441d344533427ba2257a147d58f4ba52f6e18173d0eaf747975b00efeac29201dc2294b1b3a6fdd89f6e1f0a6021b2908f952dfd9f1268a404c6a3b868653e513aaa2398a0742691a6de68baafd1e4020f21da61fe1c517c5007d122af5a4caa4f080bf757a043874cad96f265a868147f09ea99aa154cefa0570aa44f58f5049d026aeeed2f1c8965d8be8546b2a60f94f0e384a7499cfb3264207a280c00b7685a73cc2fa27318217b556c873562754ee373157358f58706d2efd5b4d559eb0fd9a9e51f7cf334832c5297a2f8720f14f5c049f9d2fb839bc201678a4238e1ab89bafbf3316a12439d1a53ace70d108cfbe58aa375f75934bef183520c20ba41962647c029d84038de992a456534081aa0aff3f4b1b3aee59ae2c66c8344d35d3f0515239828b375444b9913630c87b958134bb01d9ec46691413876458daba8f2a9d16374583f4a7aa35dd175c3819d0b6ee80081244a0e1bbbe4ff59f8e044490511e6788740b34266fa644bbe13cc88a2d3ee906af4785aa408f2cac2d3a53d3a82e3d8888704187b0a02cc8e4a65be66e870c77aa1c2f3e558a417c78bbd72692d757a12a444eb4de02996813212baada11f70f23d9249893146b92b551079a529a1d6441b4f4a9da036006b9cacef9aaddfc835c4b976130c831f4d077e540b0799b56fe9784d89ecc458a3fad1070d5e14d68ba68bc2a3f806ff97ef8955d3f8e62cce36cec9bd9279755aa4fd0c8e322cb0e0d1ddb3a27180f6109ca4388ae93e8ad0f80f8ba48b5ed3e2cd4220bc15289b7d99bd709d3a56d1080ca87518001a0bb2160e90f97d528989462251fb3b1aef4cc5470258b3154256054d8265f540f20dcd7e73248eed4d7499b19357c1e1c42c86170488cdc0e3c185e0b235d489e0ade7ed1317c75f084d75a2906a77eab811851d7db4231603a0f1e5e772a03c81b3ccb8e164d63061034ef7d180b4f3f3509c61c17f54a4b264d8e57fd247922c9c36ce467d857636d31636552497eec03cdc5475ae726fa7f50de060452f78056e7143442027e7fc8d16cf90a6b07779ba69b09dd37c5378b232d64ebe5aeb3592b4a7734b1b5c8b8b96f55d1d1bb98337ed3283a45dc4c5a42607ab3597282cc6d592ed8a4910577451d5d735bf1050d050f01391c561de96f0649af623e7ad7422ec35a66d86fbff8d93100446db440511a67d2d2ac83a77625f9389619a5b5fd58972f026596f8e361f12ed6aac713ef03a25ea9cafbf884831b1bcc05ece55bd119474a447dcdf49d4439acd4de383713d19f97027b2037bc525cf57a01009a19f124737e4c40f608bf88bf05c8ae3aa16f02641e803df6f3ddf42b91327f5d1608248a71ac68a845efe44146cb8103954f56afa1233b532c91cf4fa6393080cc48a927a6991296b254f4e0c72386a6216edb70fe0d685cb2b1df0e59301231724a957e04423e902c604994c76f8ea9bf67a1b45088d08c41d2e5b061ef96a186c73b2509c139ae65ae42352b460b7682e22575d61c1abe2b47192c3922822ac61e5190137c72634f5202b0798c46e8a7e2388149896d8bd0d6e5bc92af0fd431118659e764d01f7b2d9caa56f3409163c8c638db03baaabccf916f8e64fb51ec68f3b33121e92f2eb92125ef602589906d4a6d7aa6d983842b150aa628c56ab31de0e45f07291215f529f93656d931dac0b264f4e176eba6cec7a9de7c62cdc5f607f699b08b5318ea97511e6ab08f3d186bbff7c93f49ea8702bef8d5c70bb4514700929eb0a2fd04af851ec253943a7148d70b7a95f3af845c9cb9b47f66edfe5d8c3fb11078c990e5f6da020d06e6368871b967614a65f17ffc9ecd539530be73190493f7855e1e4c5237b06ef7f864e5a11e9ec17c466365f55e2f90181b7f8f90f4fcede66d92a7777ed2881220e7b18e4f7c90c0380936e75a639e8b4148738178d2ab03c9dc45cd0a7cb0a0f00def92c0747bba81dd8eaef40f99c368aed49388e6b0de2eddb32b0d719902c2858c9a4d495799faa21cf6a98fd206826e5529dc20bf2735175ba76ca2872f3862eb4076d461fa75b35da3db82c119eed9c22225b1e708fea5015514b42fdc33394ff7323fabc11a0610669391a6e551a06cbba3b630d5009115ccf11555c34a243dca918095c31a2a1d7604a0828ac4625c401f0a9257eb1b9c182887929b55101d410e713578e5f04360bc94f2d74a9cc9b006881b8aaf27f32af9f37b6994381b8dcc65022e704ea32ddc3b5e935bb89c71759bda014c4fe18d83455ae24f2652ea4369db98fa04eeba90a977014c378743fc841388d9363e3e939adb5da8bd5acceea7dfceee511ebd99d83370f2112fa62195210fe6db117a7dc74b0251fde37d076dc9065847c14f750f17802e09e01d56ae3d0d25295526ed2fd635a57b9acf796b87c7ec381ac80382e48ecb83be2945393159410d25715c1194fd261672a472de8ec42321051dfbd0b1e6a8a351b973deef6e657f161a3d65abd4934cc712d21936e6f9ce4c15519377c1458e54cacc0e8aec57a45ead51971ddce39f4c02114d04dafcca41fe564007a94bfb50389185a44312a311d3c1597b2a86e1ffd1075e0e02350dc2cde6ebeb3a33b0b9695e8fa09681f3f6fcbd4a32adf33e066af02c9ecbbadfaf2690a4c55eb26e69632d5031feb26508bd2a8c3add6220e98c42d7d0ef65dcfe53949ad2f4df0f6d02afeda89b4609f5601091b034bbfe2c4ee8ce91ef1b1c791a1da62cdcf37ddfc59c136a052410f8a7fce1893edc13906e5552e997b8676e7ab8dc892700a524d4bebc02a567df803a4a649d425fc3d4fbcdfe078844a40799e14b003d898c3007acc12b50eaf077afe849ba4a56cd63d52e6903c0c39f253ee3bdf9be50426d86e29f7102d7d19a16ac8dab417bc38638b33665a13e9228aac333a456b04a5cfdd6cd7be5c55976b998bc5e428d545eb8ed6fb1844032673b14fc8f73cee5663c4ea1179c6d4803c71ea4536536c9f6ff6e5391022cee2a7a8a26e5f387fa3fe827d1d3746d7780983b45261e892544eca3375e74d21de1c97bde9516bc8fe469aff653ed71ececdc592a8e93d99b72489cc4c70c377d1b48ae8a17547497750a2664e8e557e18036e044640c981a5db251f08c8f5466a6bb5da0784f25a038e3bff2c709fc5e8558f5e390a0b21317762294f1be92ebadc641835121cec3270627dc093823ba4bff7093f6c80fd2d6e9158af6ae431293c7263dff462ae912eb96b1e8357946e3d61e2d9e6c1754b1a668e1bdbcb0a6543bfe0ff96a1e83b31b364b060007b5761cb94d1edbec1f640529e477564203f04829c10f10e3c011222dc36a71438567c2a80db08689c8352ad3352676438106d98799c8a731285c3cc4d93ffe963691b047aa692cad3fd3e15065f712f6527440939f42865cb71c2e23b46e7ff40b87e94c6a470326cb9723e62b78ec0d70cb67113bd2bddf80649378e005075a6ea3f95b578b08f6ae082d83672ecedd08ea848502ab31ae062e9b838ced42b3ec1e6111d964919dbe421b88586bcbe7e81885d8e9bab67d905b043f3ec6fa3fd762370a19df7a719aa72b444d31762931820a41df4b7d9f13c8ab8f30d1dd143b7737184a38f963a8b8caa2857756501a3a754944d76014e552a7e81dae2d6e0da48cbe28d8dff782bd35f7d128d2b88d412a4616273cdb487d778cc2af0c4cf1f042621a3ee96dce25a6574392b3205eedb79f3ed67c383d04d4aea079a9c1cbbd8e5133617279a909b327b84cd35785ac014c4e7ec09c3f6192387516828cc641f6a9090b9299335350241553b69e048b903af4e237c54ccccb17cb5234146462910047d48115e9d09cb480fb4088198a5b09aff4c83491fef6f4b19146590f2c2e7c46dee44ac269eda1cf67698dde7d87a240326dc173cccac1fcd14ecd1d20ec261100746e5431016fedc295b01170332f33ff75bf6b2f8bfc97339b39c6a7905de393f68aed4163927e1335ce3704639cf28162c29c03f923e3e76e8f059e2b1360e694be7c8a42178f7a9728f8ea345b1010f60d23b3805200678041660a6167aaba9980b37f811bd9e557293072d52a05eac5cddeeb33a73e556573c13d0aa1141855e3c0dcc3323c58ed3a297b5e825be0c7bd7960302313bb49a77a343b5c7a9b8ef006cf6e970c7f9e2d6f018f341df2df5f83ca7bb675e29fb5408964de566aba67884a80036f3c5849cfb66b82b3ae4cf6caba3ab80d530d4658badfc321061a550800fe46614a52b624c391466387274fdf2b93606575ec274092830a05a2c7670d4274b4a2666629a1fc7d7214dd2d4656250ce51201777f74a79571aaf0766bd98b29e1431f89429c0aaaa6194a78fd7812a4b3a4a12efc5a881d9f8284693636098cfcfee3213fec48332e03e6268c3737557a1c88ac1a921db06751b4bc13cc8d66ce16d164a4fbddf999b9676dcc6cfdabb513a5a1c91845af90436684e145f42fa66a557a01accae11b51abedb6554fe8c42601010de0aac36e1eff757fe3c982186fc6681abaf1a9e4bbe9a1a2b71bf98d6e4338a08280cd1914bfa65bb834c9c727dcd89f1d94800296766c4b22d2f9ab2a92759a4e76ab21ef895039aa29634cf70719f6db2e299684dad46b474b251773e0f2166d8902af7814582dcca9b396b6cee825e826c852c9051a2171727af956e55fad047707f262c2247967b33fe580d5b3a83fa376c56158c33a09382b7d7c5cb226b5b25a61b6c9989313094bb35956809afde13e4bc3d1cbf70eab1ed241b6199db50e3317708b912e32a6ed0c12509eb5d144f7fbb8cbdb5f74e13ebb94c49f971083cbb86c3013fd7c5e3d2cd33eb854cd1d9d5b10a7b764205f6f23b918ae24a6994efba53745b0e98bb2ed0067f260da39986b5bc2bc258a857b1c8b08e0e3c7805ab3bbad90c6e66c3ab4ae73707dbdb169434d8c977c2a7db55fabfa9b3c9f52df6a24cd907d63475bb5d5b68c1e90dee67ee22b40ef31262448cc3cd86d44f9b9107aa23de84ed8b44a641721f4c02338b557c98e382c162ff496b0da5381aedbdae30b7eed73f37f8148f6101dd0db1c2ec94b655eaf32938494b8c20795b87605b40f77771062faa07e27e1aacab378ea484c2bf7724625ae1417c6a1cd9f58059f019f544de79fa7fb34b14e56164522cbb8d6914b12c150eb3b56b2e3e878ba531bd43bcd4c712def31500cc4baaba323b42a25407b516279049c4206521d6973643aaa2bea9c1b42c26aa53d04a95ea5ddd46419da1ea9ce145800b4e34435c538b325f38e1373cf74d55f62ebcafce950db8cc77b4d7c2557e5e1ecc75c100813133dca67859c9aa3baf147dbe6e3473e02ffeaf5762f07ff009158f8ff39ed930faa48d5ef02d15f32291716ec0b7ebc55913a7648411a8cebfe32f33944306558a75284d72c5e2e91b089f6cc6f06d17c07696a3c058b666bf82cc8ad4718895021af5ad0400b7e04503f23556d6ad01768462796a743b246992bc82ee1cbaa0213610c95f1717d176547fa1e9917dce15385138f5ed50c1cd2aeac699e6503015eea3e43dd102e4ab9f825061ad8863024e81b352fcd59b2bba345fce50eda201a48936c245ec7d4b8b7e3b9508a33747146ecb780a9b777205830d48c4de859240f869e427d1613c23b5d08b7d0a5f26f61707c25f91d2537d247de848933b5fdba4a1b15561ef9fdca43aea7aa1190324c42462c4a4e40186c753db74b3e77d9a333cab29760102d9cfda420167eb8d8ee31baa23d607fb9f63cc018199a3332bedeafb5e9101ae75cc3a3c51bf53ef44ab83e050141c2e34ed72ebbf8d945aacea7e35372297b0b27a736ee2d6b7c5aff2e0f7cca34597d6ab5adf21d973bdabee624bc6d6b8c491dc1afddda9e04efa87e670dc27f946e15394100d4b3da557a0771c985e18e95d87c88bb5707e79adad539a46857e3f315850269e1c04787f2abe7fa4f2d3b6e06d3d242154181717c370c73e1c691722735d87cf39059ab33e54d601d95bcf09090fbee7b82c34dc3208a0fc90b3df0af9f83334e6802023fe47c4e102bb526ec74b5390f158e47e8ac34928998e84be853177ba4a2d981e54a6c89546fa9dc219d953ebbcf44a4f3c11278e83bf8a6a14c712a29e433de4ce0895aab8a18d3c9b269b3378379f8df6fe156cad15c92b490dd28d72623a88ce69a1a321847df4c9b41f86650a9ad241654cdf367336f198b1a13782e3add4d25ef13ae9c40c8cdd20815483367815aabfdc2953177f66ba5929c9923e95d98845736459afe9927d18fe1c09474a67e18e19c06ffdd299c44672d497855d42c649cc46f1b18bcae75116cc19be0dcb93515d7b1351a341fa862938e571eb34fe2d487a9fb38a8bd8d76095427624f9db1411e68d8044dc2b062072d44c903336fb608abe2e2f5a09a4b46f10d28815c7a85fcebde45a338f56993ee29289b2e7de1603c2877bf5c4c18fd37c64856f2a96c85053c68170f8c1dc9acfdaf89bc03c6531e5a42111a34999b2cf37ba9337596f17f0d809da36c6c4a8b76636966b19b855d5bba5d2404879a12c60b8eb79c65cdd530f29593d281288b1c5f7240f6b6635079ce662b62ce78d2379160574ea8e0a1c97bb4634bc4d0f207702777f5be6a7e0d065444e017422b08377f9a9f2cc5b1f5afc558b8cc5cf8c3b6f8b6d9fcc7babbb30f1b14072f2673d4a03334863ce61fb0415cfc0ecef85a6c4471d50946e8feacd4f7b4fc183182f9550f6c2db2b7228ee58658bb75de9ff9e8683a216639787b3d0837c6b2009e2ecd979037786b4534a13158f703df37dae8c55548813aedc793fbc6697d5650715ab995ce4072f1d232a4cb666d31936040f8c75ea43c432fd6584172ab8d18bcf65ebd544d555a2d43293b4a51490a5bd1a864dc984c352d1ed1535af31531a17b32c5150f1fef2a39140200e3accf74494762cb7554f2db117cf01b3af0b447c272718d9e250a831363e047be1b0e40093a047e19c1b4b19ff578d18bd2b7220ba80015b611f374dd878fe9e9782108f9308307b6120cdd5d32844ac9e9745335d521ab810308f3d0a724fdac104e82eee0b95a26ce14da64e105060a0eb9a2e3aaf94017e5c654783d932d67dc4920b41e046344077b60ea37822c524297fded04ed38e55477d3ce142e0e5a354f66fad9decd6b2051ae862d79671bf0c6012028cb53360b7fa9c8d0436667c077cb36ffa2113ada8657c7ada76cb93fa5a4e43c1108e622243c982ef80bb2d01c129318f639ddd95f6a172de4854bee38bb960379436d4bc2d8cd19f71d5c0afd6a2e32ebe5a4a7abf540b9d9841de064e233535314c52334d878e6b62d671cbd203e76c4de154b04f07746b9401a873434cafe8783afe036aea253e2b2566c2ba42ac4c192ec7e4c7b0ce3d42add17f6d4ec3688f5c8d4034054d4ab65bf23ee806c2fa5c3fcf3572409a54eac8d3e402c0f9c8c701257733c784142e4f0b4a8cca80a0656f813cd7bb839d6c2de483829140cb82cbd564f2e37448a00d5212a62b66b07ede928982f1c8979c8419ebafeb675e2f578289f2c6d37bf105336a66302a90f4777ecfa6b202d7b14129f7205216c7e42509eda5a87f3d4add07a259f9b35b85f88d5adb9f0d3dc8be4c586a6daf1026a327bdcea07430a495d7e743557f98fd686e47dcd6d63e32c94ca738db704f0116fdfebe4fc521ffa28589815c769766ea01a40f8c31fcba380b20a2a99b0647ec874f40fb5102225707cb44831ac97527ea29a67d76c9fe690c2b5b0d5fbb56918d8b7a271b3dceb78808906997a91f8b8744248bb743b6dcd8af150fede201cd9378b685f75679c9adc1afa96729dc80e61ce197bb3a1e172f17cf526da73c65edaef6c2f6cbc0e7914a1dd1acbf0772de8f286e0551bd23054ee1a288413042348ea378d055007d886e40798914704b29ddf5a61f29882c41436b20ce3527c1bef98c2f5296d83e8c4cd93ab2f42f10af66f27cfec2f0c11ab75146e5cc524487f2dfd0cf0ea04a9b570d34e4ade2608c142b73a1bd2e81e584003173ff0895f6aa99443e5fd1bb2570a3fb5b34162bd752dd3214263c99aeb5ad02bb94ac6cbf3f5dd1346cbc3b75af8ffd7e223ade405c0ca962b2d6d09fe7535a0b64e07b59e669143fbab9a7d01c22dbda90620ea51a346d0d83035e84ddf2ad3d3a258db952a56e59204e21005272e3d58ae9414695804a885e1c87018b72aef5cb0db4da19d1c8c8ee262879008a87b4b43080f46bbd5b554c92b6696583140ad2268812e07147630ab0003cc5badb2c4434b537c85a8473cd457b62fc47ab4a64dd1be42e81107e5af22fb02aa740542d3207ecc470091d31b143da7cabeeddd214a7bca8a0861682cd52f56f54c198c81f15f9b4dcfaadbcc115024ccd6dfe2b6b95f7982ed4cc2550337a2bef741b20ef8ab0669ae2e488b1a0fb15a184c16a182cf510f869e9c238f6e76e4224fa5cfdc32831ff698159c0afb22c761315fd8015f05b4adec2fc643df7f79e0ade06f287ab71baae5d09598294b0be9a46f8697a9aa5653922f29691388c34cc43ed044040c83dfecdadb16bb3724808858e9dd0b26543bde0249cea128ce399c9488a00419c2843e1aa028a2c6af65d8cbbc070d8a403b9292753ee71824a6d4ce485db7b2214ee2119a87985eb938987f68a53ea00be0af0cb1bd8b3e4a1616e8eae63f9d3457668fe7a9a595bff4ad2011db8df45bed866bdeb972566f0b8a8a7afc2ccdf3325645266b55117fd0f837422511a56a945b417f55c059f55a1aa28c62211721a87a40e30c7ad953e348a136685930f4c503039b6419445656c5917a96f24e71ecb80f96304ee1601627b9892ce9bd647bfe7cc1132eb7cb28b800d6fefa8e95d5062d0c45c3379025bb715a5674563e345fe71de98822e326a013d5d41050709c00c1e8cbe2386401d878dd30513e1fbb414fd27a529779331a63c0aaa4cb80ddd8584132143c081b57d670c53366aa6ef368ffbb8174372d85c661b09ed613819922d87f7758ea9ea5dc41a6fc9f94415a29a0b4da1d4cae611cc0b7b87a5e8506cf9aa533d221f08010bb9555e85ac52878879ddc1204d9fe4d40e19bc0e2d0bad67b5c20b2001bfe7173e99950ee447ac7bffb89580fba506d8863b0a25e293aa522494bb6bf81cbf419c19625a3cf3c85a3c32ae42086a10f915c01d27d19da532bdb53d52f8406fdefcee89a630fb64b2a415526401ecda590e33c4a82304cfa976958d6a2c93f26e067dbe025bffaecde441dae429a6d3e1da1a94686aa5e35c1ea060b37857e9c2a87369671f66d8d31606000571d57538da62812a3f8cfe6b2cb68369739ddce703a9540ed79bd982b9b604670ca92fafc7e0a8df5ad51ce4d38266c22b2a14fe3cc9b6f654313f6265698e350e6d6a4769e099d7b3e0e7e54d66bbe2f7907cb9e5e14ac6421e12404c1bac0a4b8712dfc9497059dd674e039a23bed1a8502665feb37270bb44a408ae87525bab4a96c9709a5efa1d97815e087d5b42ba080eac6e82b28ecbe2cfdcb361497caeba242cfab40507c46bf445c13061a16fc74753f332e216c235ea7ac4ca014ebf830d524a53f5ce0e69e18e3396f60b2742e9b83514b249c8d7e624168c70b8d9f3bce9e8a72ad032f6876461e3db05cd3b74689a418b49889acb536cb68159e1ea77f3eb334c886f27803a13d5bae3bc024e0c942dce2b5de5ab0e4e58367fd12d8f508c66805528fb44aee6e6fa16ef2a2cd291eecb8ef4f629431f5f02c64ce3ae191cb2b84e7f8098265d55d237b5bbb0aaa0794681ee5cd98e40ad7dd4eab02a51d64a55a1e5355a8a40841cf16674fdf54bf06d42e9744e5744d50842735f53883a7b4ed8b3303d16587e413ee721a3c92e46c223dff1ea64d107ca45cd574c32b773b9ca3619e4a76faf64c6f1a30bb74effff693c453df991be7c2c56975c6a4c8d5a1cad54aec24b2bc1949b3292c2d42ec738c3860854caf306b1e5dc36566836a1bef87d0e58e274e0386b008469dc5e9093ac6d5152c2af5f756e36bd990a083f395adf13737fd00b8107c6cf1ad6f06a9bbd029cdca351770b4db51d30119c56809f4cca6326587107d365e064e7331eff77d9adde1fb6a76ac3c7c68395179e47ae53b7e65f93cb7096b5ff22eb8f32a60000ce7d8f48ef81004ba97380f219c73d9ab22ba6aacfa81aae6bb0f79742d45209bd6e42971e0384471f97408eb2159dbe8c6acd695a404e64175f815fc2cc2890c878266f1e954138318bd86858552625eed8d24c4484552c97501d6ba431dad8e9124498d126fb3a81190b4d839eb82bb3761658f0a3dc00f7f0457ddc069432e8b53d9c2ee86380697c698cbb4a0c916d1812913abada106bd74090bdce99f13b7b89114fd84e0a66c8d92d55684e1b97be40ce1345363281404e921e6796b56358caddb4e0d209de24bc627f5a11e3589c75f9c2f4d06619975c8cacdf2308353959920ef056e8102a36ddbba8779e711582b80ce306e7bf233d4da16cee5fe03651d9da519c2cb47c03e9c9fb30138e7c4d123d40529f4e834995f1bde21bdb68edf99039ba8eaa52618b054d678a6a75356964d7b9f82cc56463d4b80a97868a782fb33acafbe0823ca17f5456ca3f064005ad582d655eb97515c65c19ec5276557fa191eec20ec4d838b2e2487688167f9ae6ccd08e5827e4235f500d6212caa2ff4652d1a2bd2febd63c751b2a324a5206e96b86c7a20eca9a6595fa8ff9a9a114fd6b72b2e8c2e9ec6e51c6e397d5a4e201b64393771b30210b30ffca4c73b2ead1d1b8abb6d4351838ac3409909ad2b9a78c80e821e84429fe9b46c8cdbc8674a461957960f8a48dfe484495f783834ec951abc297fe1f50c13ae5ac53719a7c20e50d0073400747ff431a945909973aa6d974306aceca894b1e61c901ed5dae1c5081b49069d4a437e4d76ed334bc3a2ad1e90919d6e5e80f57e80d5edae85ba40fb81d758d47d4e5dcb9b17c3610083cecfcaa968bcd2fb8de2d802cf7432ed7d4949b970c22fe272a044841297422a8abfd13e3741e962dd773a044a32840a86a40788c9059feea250f6292eec0ce6b8988206a87f8d35c8d41cdf81326c2ddfe91a00ac400ff74a73b9614d2cce586a8384bd65bb797c937beca9b83a4ee50f44131fbfb8d30d6aff047fc3677a86979fe136cc52e214a450468835dc4e5b04a39cff84620951cfca1787ad8b7d12eadf0808e2cf0de82344bf478bd8695b6c44f98d402f4429d510e5cc6725dd6692b87ba1885e56abbf21aaeb2d823dcae71d9448375f9f51aec05c2929a2e6681e972d21758b4dc8b194eed9f026b5f7acf678424e69a7f7231697b149d22d1f46e1516fd32d6a3fad6a5b23ff268b13812ebcd36f6b5b174fa514ef97b651a7547d0aa8dee314b9896713f9081412d139dc115c8237bec79e9b9f622b31691e50534a7b062d6cff7d824300b5b1a07b7133ca77fab5f22b9bed4fb2f22edcc6984e283bfd03fe448566158649dcaba7372902d4b53bcbcb01435b646fa1a638825edbc0f1c978900f9ddfdb66b1e840b5e6bb6b6731ec798682ec1ce6895a6244c2eaa67da5fed23bae20762d961d3a88e42683a80b0461d9fbb2ac82c8388e7690b304503110e44e60b7cea02e1430e16ec574ad4e3d3be2f3e00ec840ca1ceb9a5bc08875dc91bf9d2b75c7fde9fbf58bbf2afe949f340d85b64b69dbfee362f8a76c4e5ce8da70215f7d4ef13f12fa6bf13826e228d5484f581414804711d64542810e159961e4f8fd0972d467cb031098b5f71e7ba1cf16068db1c0ccd51aa83872a89f4f9b40f8f86ff22cc14d5fc43022cc27c4747431c400fc57fa0bcbc2587774c9bc24805a5199a7040cc3a8654ce1c78258d0067bf76ea5810a37a9295156c623a945f338ef4ebdf750f746aae4bb10e5e643c1c62960fad960a121765cc2d01512ce4e84020cd09acd47f408b6ee2397d1f8e0694423f409959577fe267633b1f096a586848fffc0ca243f14560a0891912fe037f4af1a3c4d2750575beeac819e2942870579ec1965e239204d8310a1ec27c5a3ca125b3e92710d5360d91e5ca54e88bc65423961b82b01f9d86cb5aab765f3b7d76f2811c52338bfc21156a3b3b8bdcaa067f451c235a86cf511afa1e615740e1e717e0d20f95db3fa03fa86aa68ac4236d465590c1508969b4f775308239a5cccbcf978ebd1305c5ce5f86086f90cbc730645c2d8dabb056c7af0b4b4418a22e82f9f68ef359aeec8525105b1b8e51e53c6867e2595f82bdaa88b0dc2653400b46730a66656f6127d3a99904993f4c39eea5a043c266df81d594007650d745c8d43a18d5decdb7be312432b47c72c878d5275df5cd9942802c5ca045bc061183eb18b68418ee047633fbc7313d2dd52c40ca47b959090b337270dd24bf8a41cf3b49d666d1ea45cb5ba58ad2accbe165e455b533b7cfc87675c12c7cd1abfb753aa4c5790c5e9580ad912c122de74b34705cbd8c0d075e4d382c904b8ce912ef3760be6b84d4573a726b3f1e75c543de16b2bcee524807ec53750775fb4434d719cba7f297874781ed56bb8c4d163ae60b4fa837585c33a56938cfaa3db93f8eca055de4a595e1c5a18b0682c3ac615c0097196e40fbbbd31fa09cb0d31214565e305caeb5da74c685ba8891d7b5a84e4f0fc0fe61223c829b1520492ed2db4d2fda4639e780d743076660e7382879f238b289fdc89e46fc2f88517d2823d311358513ee0d33d9b5a36719b558d17680f214563f48b66b674b5f1e64d33eefb66aa96463c5f05c57a39902433d01017993f9bac37545ebda87b82d641f4948b7b3763db0908f93627ee5598e79d4ad3c8d88742e92266e35e031f0fb6a9e3065b9a9b81b62fbdef0440b76c846d012f836bdfa1d347c7f8145872c64a8bc3ef1474d2102f2d96523241a5a2080a59dee1380fbe81e6a856de326c4dd75720a816469c28f2e168a54b86b3d0485895ea10af0506b4e24868a406d62874d059300ea69baccf056170836088d62491078f95da4dc0fc26c14e8f0b8200720ae6721d66c7b21f3f33a42753d4e26311a31496da152bfb1372b504a82c9e3352b1e4f73d863acda4c5704e542675e98c6851349bfd8dc2650869c22595563e0cac07f142d0b2eed4129ebd8b9df0e84dd6498c59f48cba170747e0900095db18373539225b1576c10fa099ec639c61545d2398ac37ad641f2b4d856b8b76492c3141fb6cb5851dabf13f90580c79af3af21da19f238c38523a9fb232e6dcb03e5978e7041528542a1e7c4008d45f69df3605e273f1a1de74e3a906e6ad9916a95e388641fbac8206d4a892acced5aa62501c604853414f809ca1ec0b2cdd251c0c042d632460f539dad1e716986562e5bbfe3b02ab38ce2cd40abd52e8f84b1a0de4dbba28dd771263358a996450ad26e5f1b2da33acda258947046c9102a4036b59161e043eaf6ec14648a109fbc82100cc184ce8727d6efc13a7a26a8451f0972a1e7fb08cf083f14247ebe7ec2cd620a55ce7e4aca5d02da8972afbdbea270032c58a85b9541ea35ecd96920b4de547c85b79954872421b50659ef4827a9b8894ac8dd647aa485f2869f9ca1d8b5ce71f4888a360ce62833533c17e5bce9b2ba65afa092484f37b17c1f9733b9b280b8c806e7befdd56f8a0fa324f2320dec8f1fd80ee70e4a98ae126eacefed4a6692f47785ab143e9c191bd964bbf95cac6b791507b5a92e9a8609e8c39c3b0a76038e1be0f3776106ad527545e2e69cca0053ea5e4383f9220d02a4d9a19deafd8196b95506324027b6bca48c07930a09115b89ea1736b814018752fc11a34e7b29ca78b86e96f42fd258f1c6309fd9baadaba9fe82c0589b3eba957f42ddf89218cbcf5f046460aa5f4ca6fd28505e066fb0bf2ddd360459455ce10c824ee2104e02670e19912b0eea9959463c04db2855c606fb3c72f7539e4437ae870e0d4b49dc81b078efe34470e7f6f5f01509980ec309ff2208638e77235635248884b6136069ecfe221df77752aa94803d24ca2ec30c12537c5134267bbedf4461053322a27df149eff71fca96fbe140460f14fa73931995d8e37bf46c64e9b6e3a4c9858e3ea145f877a9619fb4c9ba344da54489b02ae89c3bdc468d5b5ec2d1454b5d03a45ffa2fc5f5f5b5bb432d1f3d86ca137c73e964bf6bee316d3e81a939b76c4ee1bdc72593daa9a69f7dccac7a5fe4677b03a1399747b5f2ecd4b278909046107691b95040fc6aca15335a011b2743a3b74cac73acd2de163c47f30389b174eb19127d002f289b5c25043e628e5b5f503c23d89ecdbb009c8db82ef0983ce0e7cff96234bb78e2d1a9a95452dc19328ae3268e9dda6ba2a48587a8a1e397d955d94b786d100e98784e44411590389688ffb26b6c13de7a69615387b19471cc66da60dc181b88ff614a34a82f8dab34a6cf45672d5c33de3618d08b5151eaba1685f382a9f033a5374b4bebc465ab529f68ca35162df4f2249ec591d1a7f724b589f56279916b6decffb3915747ce1f0efe9e3b7c5ee2217d2230a752e25cc778ec428cd079e83ad953b2fdbfafef8952ee4b7f69d06900a3ad79b107ec3af029a491f22df8c1e80a45bf63f4d19f4690c49d2457dfad0ade56486cbb2665fd4db7534ba4c078ce841917269bc5270f17984194a81f792c0b78de9dd05797970db57fe154dce080facda9daa77d0cf3c2f3071641a1935826891d31865546ddc0c21b0dc607b1e893653e85285ecd11617c2f6a53e4b2462a2524cf761b94bb4e4982cb4576e73f306e45d23406ab855e97703032fa1fb24214eb8887e2cd601a20fcc105ad5718732a939d17456285765be587206fabdcc46cc4cc33b94d4572ad7d0fd2c49290ed87b70e1baf6f23c6fb2c82bcf45aedcbd484b378d09351719c984379379585fff5e94f6424fa9c848758fa37cf3d44a6cf03a527766a6445d5f4d23e5e6d08a8632541f19f693c8b7272a8fbd4b06965cd19dd7999b7bcdede8b31a8ba0e580f440932ce67143c01465e4cf4edfde96f519ccce0f8b0d44df5e3e6c29231712ee2e1adbf41292348a007c90b462f3e4144222f446c6e14839feed21b0c986b85989f49547151e90675dd9a50b1a9a0792e9357daba48fa819a088510a76f50c2cc04585c24ba4b8fc02a8d6960a3c7c5824e96c26369fc488645b7bf68f55360d96d75a70c314972a25ec02edf244672d150bd6683e854026fcc193723e99382788ba4936900698b9313838ee8b32eddab43061b5f34270458fdabc7bd5735199d81459cad5a6b81ff8a61c342711351e7af5e417f936bbaae0b7a0b90b4739d8351b7660f182a88703cc27cc03f70b17273a7e306b36f54bf7bf993a80459b3010bb88f43f03591671f09711216a703fa7b3dc0da47d08230024830d073f332b21a41460cacc0989c092bad4878025844ca7c98756ffd195e44f983cdae0ace1030fc641a22549754c943b434b56e298bba45bdf242aa39dd50cd62d3c182d3603a944e3753749546855d276be35821dcde468458dc7531134f6cd32758e358b40443056f72aa4b486ab40733b522f3a69887e19c41389b624572b4b54305626d461c7ad3944f60b034cea38796b837bea76a164d5b31448f986634492986a881027119704991b1fa38f541e609691c5ea4436f4caf5b2f8da5481b078b54cfbc876b3b6a4e32e6f23ea64ceaf755f616b81387a063a2302836c951de8c71915a95567fb31bcec6f56582e9100a4e1172e6da6a19dd8cdcf4129c63593f77a063c305b988da4ccbf94e6caeae0cec8dfe2215dc9da1cd539e727fc6afe973c5514acd9350b839a9dc9834a5afba5842765bc643d42c78eaa561f0cb3d0eae0ce3a19ab22f05d39bc8d28c271dadb74d4fb75ca09e37192788147dea18346e627072aa98c1ee12653ad01171970f49b0c8c4b9e830037c629df6081165e6b954949e5a345c817d1c472561f82acbbb02e598e5c171a6d064d4b7896b5ac611170a8907e5fad243172aca22a6fb2ac995396d56848daed0365c27fc0754351d0113ad046a135a590567851dc1b22997d26d8f2fd831f5d57e294e11689067a01d0b2783ba96848a14df71d5ca2e5d0e075ee8279f2ee3651c9057aa561ed2862d6fd4c0ab11f276a2d470e36d6fe4222b06c2c08d4a56a24efc253cf40d5664f9f4f752db72f30f792ae577e03d0bdd155d9926c8764d3712e22e97c1be4ea6945f84a0c59d06efc1d957c3b9bc4e7a5f35390ce65919de8795b9b8fdab1baa97715199dc017978f535d87720d1e6aa2ae50a09e6e0c9282a1fca2509d5c23d697db13b105f070add2fcc6a71b8f3702393ae57be8c0074e13610d589e7a8164af6e7eeec85e586dda784873742cac4692b34645b1b3e08131db004dd3f3330cc156ffef26322192a478cae6741d35fe108decb0c78f61dd98075cc2a63ba6e2458dd4b5250cbda703fcc76edaee4bb85709e1b5c76b97b616ddce6f629c2c4eb78ec6f2bdf62e77138280fc6df33cacbed716bcc0e31ab9ec8025bb8b188314f41dc424b8826816b71870eb1c89419547f931ab94d00636f952acfc37e4506a4da92294bf012228db848fc5a2050710c163b527769e03c5ffd3cd0c1b05883ec73b48faa4351cb7666f8d2ba4eba250b093718d100d5db694f8a318796ccc691bad06f9b1646dfac7eab742cf6451880f397310744b157a7cc87a7f70b010338e00dd621513065b1f10896945103e62e651d12c54fcf349924c92a5986180be4d9a6fdcb08e187492895c63942d25fa518424d7f8877e02126c2625463db1e5fd16bd76022ab90648e8375aed018b1dd12ac9d0a826418093250e5501dc284a2eb64fafa96000ae8b426f99f30b31e5115ab6960d401ce6ffd4fd0784a03593a5c31177a05d627ea165f018912ced5e6f487f791638b396ab5b4bb29f10479c008a6c24bb97fe0ddaa72457da42fd761482aa394c1e9c8e9c16fe4cdfd956f2989ba0c37d7865701a886619ffee989a181a1210ae57ccb12c29e3ae24c62c8103a0827852916b01db3f225c2dcf6d423115833ec8b102ac02173fb4dde82e642e502fad549f575086dc2ea5011f332bf85ed860dd5558b7974e89a7b5ee525425e4c40ce86a814368fe874a12eb5361879957150b7fb0deb67a347302bd27ce094d32a67655168b52bf94392fded104396cd015c60267df80c30c0bb5b181a157e2cf97ae4ec382d98d2155055908295e38fed7967b4a5dddc11bd0b7c02af738670d3afd011637a9e799734a367ed730ba1c8476fa0469b5f201f35188e44b0d1d1c87dfbc1b2616320eab8460f1845da9ef5ed0d25e4e7649cc65cb5f659e3a6b2f02a1cb11e63840bfb0176b323636a486564d33d3b95e14dfa5b8ea98eb23a097848195f28b05334914366b9c43b1ca3c0e31324e1d12eb659171d9a87200e225f1c57d070f0d8012372db73dce99781e32b1ea4219f7410464436934725ac2b2e2c586fd44347676129b06a91692092eff51cae383eba9c19728116c36c663023021cbeec88be4f176705570f73be9cfe485a804b319c60c3a2633227f4a10db17e1207a8346ade2c4aa9283dbcb8cdd345257c0b4b4a72344bc0e74a8bff264482856e1841459dd9d0a6136fb2d50681d29365aa3723cb86cdd6124514dd8d0866912ca251bd4eb57b7b7db6d8f864b61cff08d5aa82bc8c09a3b0b4b0ce71e3f8e220ad9b20e26be7b6e3488cec1fbf9d3dc2d3fe9a9cbbfaae65d608cdae3edeeb0c277288792388bcce210ea6bca3e4d31c2b19dd1f55b2d2526b6b15ae697768cb740d48927f580561a001f87550fb6a51a4e04dcaccd8cd69115a98ce82f5886507bdcbb5d35764a567c45caff7bc34f46530fd907484f7853be03872f55b278ed7019126ed457cfc86b8213f54c6ed6c84141cf573c73457b2ea1ccc6c19ca98a2845e4458b2532129ed68c962c94f6f555931507907e5759f3b207735b71976700c942b57a6e0eda6f66f10f8b73abcfef2cbe1a6e1cc8a6a55503761996ef39d0e962d58b4fa55352b10a60dcfdb0312fa28ae9c2b298580501c9b4787f8d1d2f37af36886b7117af4664606d582105fbadb8c5c5d500a4e822325019ed349127c17e88182444fa38018b6baa71dcbed7c76e570340b76e9d0f37fab2bce95b60606ed8a66df3701e2d7edc6c170e3e1529a4dc8290f712f71d9201f4906cf58e4f6fadd7a533c4356c8c9c4c8546da7f8b69185216a92c45cc01c3d4123c5bf626ee96b95827504e19f55a8ee327dcb1341835ce068b37ddb3fbe5524b796bbe881b3140a27e135d77bcc03c28d10c746fc7289fb9020d266afac9ae98a4e12b1d7a588220cbadc525adbeb2df625a1666ab71e05bbec3675a389e521795f3a1a32d804c1e63d0a3099d5d7a30093bde1221c349f356fa470d5811a81b117823cb17c72cc971ceb6be84626972f199d32b9aadbd9cc8f31528dc46114b451469390dc621ff978b02cbcf39ac7de0bee2d3e0cefa95080bedcd6c211810e64d395f32ec79e70724f37edd5555864b37a0016c8a51385199f8157108d3505c02efb2c452dc8cdea5e37df38eaf820022b645b403b92d66b21dd2e4aa0086f5d0f5961398ae78df05a96c7e877e0765210f0130309a54c9c3c5359a13052084d71bc39900c760775f0744034e2e91e7deaaf17e9cdce92e5dd338a270fb034273bc4903e9f6d20c44f0681ca0317b69813359786c6ae8a1bbafbd2431e266b05cffc1e210120d8d04d7cb31638861a55524047221eadebfd2333f119a64939904bdd00f484bfb8a2860e4863c8d060eb3bc82ce87340727d214be64d59e614fa34d5ec7c8667bc3cc2b1cebe07637288946406cb243a294fd6dd6155037f5e8da1e25ad7908110401ef011ae1c51098ca73887ce3cd7316ca023b06bd7cc9fd87af5e41bc390bb20cedc06eb554382487528f5c68f2d369e8553b2afbb9b9b2e284a271c7d6b3517d73f9ecaaf35bd1ae9ef486f168729551c54047124fbe08a51daace0e9161c2807a1244e41d8bc82724040d2c025ed6e69dd811db0ee6e7ad523e2c5e2cfd901a3c14ca44d3f9b1cbcf54625097f734e3213153b0b3962f788dc4491876dcc79b9810b9224058ea3d1e2ad948fdea5e0e24a9c251c0bf899c4d22269061ad4b506f60a363128c880d44da81f1df08fd2ac19a7dfd9f70230e60560f62caf7442c21bc5bbafd91cdbe95e5dd48f6f3e646ec1db82b128a36b83af958e1d3e5f91b745dcce5d48010e125c48d7820c6c5809b29c462f40949f9c59de2f67a28d48ed7bf6c0ed4d598fc286be09dc94319648c83bc5802e1c618fa0820be5cc94b78f771e01e4f88ed48f65fd7dc3cf7ee225aa6564986cbb4d901357a099101b1be5552728cfccbad4809b1c11522f442288e53ad36067ab337bfa8d08db6b018880020b87337a55c8bc19e30e32b444d22ee5718256beb143d962ca92f16a37438c64c74fc7de0ae6c0298bed8f36680f760a7b805396f71ce55b8bfc06439ed0eaf79a22b65b7d45c0f56aa87506b4a5b53d6b6352bb5c949e03ef4cdb7b1588f4606c494fd596acd373ac24095bbc99c648b7433776f2782a0a4df3e221543638112b4dc51f802a8506d0c8a3a2609e60e8ef5e508dbbf69b83e8ea1a534aea99da5d89bd065e7df0ca1163fed6a54e662b17b2de40cb85c292878e620601cc80eeae4a6202220bff842685e90708913fa8f6d364a4c1aa4fb6d8961fc444a3ed35b0d1ae54ba29e597d44130d881806d8a03eeb56de1c7eb00a5ba14a5cf1b9a9f5cfa94fb4c1016e5c084480526a726ccbd1a7f8dbe11e1a7668212cb9853cb9bcaad2d96b2ff25fcb6c3ff892032d47f8a17aa970a9f354213c1d9c5fbbe2da0cc20ec70280735fbf35fbcb935fddcbd4e5f74824e610f9e3a3741d2e7800863ac7d7971640af76eb9be9e567bbf7c1371dc513dc78afe717425c4f9a2d403b1e06bc16a7813ef74cb48432431cf40bd797c2113a42d58e1fd948358ca443a52048e124d615e207883fa0afd0854b300869479468021d03b9a29536f81360ace7848d2bca47aade0cfde053c987349cd13ce1433c749c2dfc5a474267e4e921d3132a2d6600bef8b0d45a22bb3d723132002b941c06369a743e04ac0aa5b612b31d9ac2e74abda39472bc9f046f951010c7dfe12ff77fb99a248a7e7e13b1dc18a791e2f010569293043a8b85d4c8ed38c23b9e9e0b5059a04de2a2ebe07cfd4e05e5b7e3b9a59537c714b49964621f5f71a133683538789af51cd8e1a960303f16d49cb50a96478564bae0746acb8e5e6e94f83dcde962fa9882820146f8d68642b7ccf46f9d148257137516197a04a822db6867fa55a225f5f7f932fd3e433a65650bbdaa7c4db337308880bc05ca9e5101b053dc68212cf3ae7aa64a58703a1c0f60736a2c79b86ee7a1a3779676ec83a0bff706ccce9e3103373c66f2db12923681f506cf23d8ec0fce3047cdea31e826ce21edf41a9eef8b6e26bc4cd4a7a6b07e69a2a9f413b1b308288f62a0951e5afe80efe428ef76df9664e83aadd4d1d50b0c2ee62bbad3746a0a194d5be1f830898d81401ee37c8405312a4fcb1992ff8149cb351075d69cad2f4ddd6c6dcde124123aff15a7566b650ab296052bc3fdba49355af98767a07fcf0b29c24a60c52c0e2bbb934bc46565d169d19b43934a8f19d0f3f6cebc08d5be987b9505bcc9758b1ccc441e231c000802e180c870d6ba968ffbef50538e4d3bc2f0d79d11f2051aa9268dd6e1f07c518ba52de606ae9273277c9bf0d92d4d37519b306a8e1b3b20d9e9641a01314c0026b61f1946c811464441306280114b2d8c7ccda160c3c0c25a9b9d4ed4c764a9d3cfaffbf9407ece240eb0e8ecc418c54a1317c4cf06694a7b64ebefcb140556c4376a6c302ba73c4fa977a02396b10ebe44ff411c80f558ba59fa410131c704d842e80c7bae8754002daa243c6977d668274fdaead1ebbfa86525ddb845ca90b3bfb4337f0e5792d8b0f140c7cad252030e3e4b4a25a0d9ea573e89d7e81c202c9eab9dee5594913c9ff5c2cf5e2d619657e35150c9c5ea0b0a2910bf4250f9b91767671344f8d9e2fb60b2f909d7b8789a46336f441d0e2577ab209ed3848dcdc540311becfbfbf8ca1f354c17505d5673f7183490f0b6385292acf3facd446782b3de9d452342bc8855f9e94b5e21fba4207490d0f4ebe0fa8a4fa4bc256f4feee6f13c4a9766300f5546987bac3093aaf64d0b8d649439e04f6729e82c15e43ff867fccbc62b65f6626508ffbbfe0b031c541ba2c22603a159e6012ca75a30f506a863c8a1a57ffa390e68ae1236d0039ce7c12c97865dc75592d03e6d784a042e937438a2f1c2c1376e93d1391d97a38055bb13c147cb9ab5568b91959f7be54c061f8c87e7f47f59f7317a4754786f5510488e36c6eaa3b647b3dd9ee8f5873df2803a3398657559570da6ef0f926b995ae72961b8266ad97f39b8fa45f908b86987eca02d28acadf776fad336a5b1d660323943e29af0d98f7e4ecbe6b499776a143eae671925ca11d371ff13c8bfb2e86d365c85d39d3befdb4efff76f903f591285b8896a09b3e9c9bb225091331ce5191ed519badd9ecaabedda411c48c6f0ebc2853f7b9cfa996574529dffa1a5189baa0472718d2da754405ff591db49198f5ff021649fcb782cab8ec368be19c156d77870e5628d5e94352fa6fe63124994c55e93be06919881bb036473cafe12be099fcfd84f737d1fbe69fe1ad54d2e69fad83241d6f7314dafd508cdc2acee182ff6f6fe266f59d32a884d767eef3baedd5c53c2ffd81ec2376d613202e27e475f71ff79313f4e8c3fb402ef505c191364675c1bacf2f6aadf9415fc0a23eab3088c54388e09843c4825cbda9b429795e204ccbe5954475812ad8faaecc11bf1dd2919b65fd6cd8ceb55d518ff817a57f5f63726ff4367de434c4a88eb9a033c2529caf079eb7e72f768457ad1f5ad361e5fe56f29bd883feac832afad0a6a1fc4ced01a5a8fa6f30ab772f735617d9131e13e0cc7025a4e97da15932c6d914cb89476f3847432bbbcdce330d86e4573c2468f96d4c804b11b8d0caae0271974995aa2b3b80b386aaf12e1e10acdafc1bfe145632cd34d7f6851e47743e3e2e1546d26ba14a89f3be2059867daad0682ec76369c7332a2aef204fcd776b51e4ea0ff22ec6f8f0372ac5301fe63ea107be7fce0d48bfce3466abeba2d22afa6ca09bbcaabd60b671eec6b0a7ad43b7081b0680569557e4cc6482a3ba1bcd0cc3f85199e5699d79c79546f34f6fbc0dfca596111fd5511e6a391eed12665fe48b9383493a90c22e89c7074ba92e3de935ff90edd10b41a9191b95f194e5866dd2c9f5460a1d88f81ab7163b99c3714056c8b309821fd77135df8a4557ce97fc42e044ad7ad36f57021a2fbfc17b4da59fb33f58e81e8ea88a064ce00c98c43179307d60a4fc04e8101ce115fda669e12f9ee499777033bca7f756b45f2b56b387ee4536085dc3ba6fa3383fe67a84aaef7c833d39d3788fbaf774139538d62f831a4f7e535d3ce3f08fdd3bba198a94635fc81a14c0e8cb8bbc4bc03432ea5708d659f7d18b6c39f1bab977e5c2bf7c4a07e7725ed4effedf0c29694340c053e52411e7d32541224453a3d4f6010b2409d7986925c9beaee28d373c2903039619e8e0278ca172810008c7e4171d5a41c53417a984e2f528409591db7026af62dd3c10c62a3f20afa56ff7149739f688b875b86869f9edcd731d38e026cc9aa67a953a7099e6701b675d2c6a6022db4d30d610708ae674b7044f7eed55ff9954cab2ad55cc297e6c1939744f363f729ebf4e5b63799d45eabc892baf376e32f359d31fd1f4909b4e3de8bdc9afd507480ee93495bb14656d5408102017aab8c88c34c346b390d57ace73ffc7919a6619a4a895167fe1d642d38f4229a2e33cb5315816df226d83196bdc3a98c06b114ac9894a0bb2ab571bd263d7b0915d5287eccd1f710b4392cf0f4f3c98c6ab0ee923c2a142883075e7b30165f5323f88fce3afe0a8538c56c7062fb4d035d06767fb13d6361cb33a252f34185ed2f3d4eed5aa95f7718875d027b99aba3fe6efcf28c6537472879ab89c3dd159b1d2ce7e6898338cc64155ba15594a9ab9b058059b1ce6d892f035ab168913de158386873e340a2b473dc2858e055ab229961f37d76b19509d31e0314a871b9958f7aca994353a8d70937a28d1d55e8b1ee3105e1204e11e342db3b874ad2b44875be264d0633ed15ca283206f9f38bfa0e98db59aec0d744d04a2c34c4eef7ab803c8800741be902c62e6b2e02a38d36644f712260ce2f097f6f0542282e85ea0eab1320e65f5ea3437e79f0379812f4c2d935b3ed7ab0c92b68ddcb518c71351128eacde0642f039b471c7ce68858d44f7411adaae0db0911a82b3afacad28a01565caa4753305023d7f04e8f10d038dcf571b463c2d5a07953669c2143a172c4e1f12e649f8cd29586022f789a239e61bafef015ae5931d9df14cd8a94450fcbd7beeda5b2cd26d70e6b415f09a3bb60fb421cdacccf94869884a00be10a890db10a9bf015e4addd19e34260765dc00e2c1ae76366f59ce7ed6889fbc59de93b8b7a743b1d34ba4296b97a94e275dd4ff3e6c529a1978106f489045aaa3bbe551048cb6a3a84a3f14889ab8ba2ed22a4dfacb67845d981c730dcf277c44ee8a9311762280ca5d42cab117c17af9809cc849c9897acd00d6a5a1b229a1bf8ccac9d37b2ad7081c23ade0ecbdabddbdade7bcb94920cdd0b110ca50b2e2e3d0a7141f55bba681f8f2284d0b774d16c6c643d8e2284f0293b8a1082e53bd4a3f8d4a36a8e1e9b013b1fe451210380fc8baca057430becdf0a2c8865050579fb56149a65605084040b92829afa72bb38453e987ceaa87ecb5711925a8ffd7a3b614150f0717f945a64aaeac9c910be3dab7a523dddfe959321882e9a0711a7b7ac38bdf5e2f496eb8b9035eabca58bc63d7d26f541766c2c057b19c552b0a3db2edaaddea23765ed84fd84bd53fd5be2141539e9a2cd563fca45f3aee314b9708a6e7f41878b36c33882c28a4e330007feb9e3323805795ea754149b1bfd5076c2921cf1e50aecba8e6b4e82b32f7288611a7bcccb752639e6b8e5aa0c39c6f8ca37d6d22eae07d7ff4b514aa99db02ff50798b029b6c0e296ba7141791e95d22970993253c8c8e0539838c932323217cbc934e7d3e7a6701cb57cf91f610249ec4f3dfd2cd7d8e80b18b0000b2e3b88830cd8a4230b2e708cd142c9eba76007a09fbe337126a2778f2851b934398fbc26ad6ca922168bbd71030eac8005d5b0f10227ea188ac5829c6896e42022a3e90444aa0fc5dca79e76cf7dea83b84f75ff812108865fcfb951493deae77fa1078ade6f62504a1ca974415ce73175eabb4fa5beefc4dabd88127bbcd5f4a9704fc57bee4b759ee81d51e9c24fc57b8e0a8aa2bea3ddc5f179e7714f592c741df79d38a6fefb4e7dcda19ebd399df45e7092a262108a592c74cf7d50f75cf7540cea1e250a75e2b7e731b5e77def81ec79a2508fb73ef51ef75d4ae4a818c43d4a14f244f15b0ea29efb20d473a250170ee2be1385503fffeb4ec19ec52cd210e43dea0f30612ba1ea0deb3cb10b73937627c7e7b56bce21bee9246c7adcb36ffde366bb3275ee59a4302b5e8536afc1bdd7a1a8cf0d56bd6e9663a2ba78bd80e88636247ca048c82e6a8b43892d0e2ddb9d65c46184f7831746163aba2e8c23c66c5e47e607649c3a5693eeceef3a324c1bd7510fa9888c2b6494569cd8c1d2184f4858907490c6186330ade030dab88e7a70b0e0ce32e0404add9a3b06cdc98b184b63ccc460a748bef9ac267ee7fb9d22cdfc99b749144760acbcf881cdd18c556380c22204109313ca3881115c6ce8811348f8d0c653930e9a7a5005921757cc7801c68b7bea628e1ca2bac5c08b5a07c68b29381ee0a8f283d110618451c50eb44401061c6ebc6185185fece001718f381ea0805b41b8a9c06b7e82c253c1135b1b47402730516196a9a1be7062f5393ad0a157cf9d113978a38d9d1c287b32a851b0c7a67c3daf4a379d738e1bdbe09141a181840ef009065d19153ed59d65e4e00c3378ce31ceddaebe737e12159c043d993f6bcc1ffe1e373f7bd5d3ff3db852f9366fb825d754252f316d4a4a3c30d9456c83b962a21a71cb1e01c331bfe41edcb6e1cbdec1c949b7114bafded29d56976b27d149c9492f62b6fa97f09ea84ec56d2742a3f297eee4aad6551f51a1c70dc7d5167a9fe139723fc3966f68b7396ea80e802208b66f8594c873bc1b4a9c9387e33cefb9d6755c0bc29ec81b08360fc364e1e6253e1270d8d9e8ca37bad1eec177645cbdd87f7f6c51cb1fede21ff367de6ed56ccdcde96c6de055c9503d4646a579e2eb39b16811850fbc21f1cdf9434363bba7bb7bf16db08fc18db33c5b54039556712bdeecc4c66d1bab898b69038b0d977bbf7c3f8e5266e2a3eded77b3f36513d5c5ebb5d401e105b5850b252f8ab660e3861570a8820d22a00843054a5f9ce81718d43812a855150355040f211120b419be0516629a0083871d5ae09283ccd21a51b0e04a0a8abe2d46e0e418001a3784692329054c70f15f8c41c70ae0706248065ddcc0c17481031a2e0e25666c81830a1ab85186072cc8e6e8628d33ba0481032ec6745cb4f1c304dc463d9603f6bcd8d9c9c9411149615ce48004471e2a0bef7833d579df02ea53a8f7505d9d99de87df42ea67442adfa7a8809b45fd0b30cc26284efee8f4ea994c2f409901888913da3dea41d0033beb59f17617d470dd6a06454521263a52ab34fc2e41601784fa5014f2c4d15b1ccb4a0ff51c0a35f3bdbeefc10fc597b7e87bac4af854988462972f5f4a809f98e488540ba9ef514f25d5028aca27d6d45b014a7d10aafffb096b9185fa94c8ea3e8512591dca0acc0a6cc2780ccaf2ac9b98a947ee857c51a13889fae6b888aec5b2765dd7df75ece4ed61c13d6777ee7472b23ca722cbf37c04f2f7d664ff163a086d0a2491c52df8f7b77f9fe2ec0cc7e25c7c716210088a3dde9af341db635b9367fba1439d1bf7d9717b94b76d9bc7bc11b9872474a9e578c77695df43a45d25919e232f6ee2a69d0677da757be92341c6e2e7de0a6cb32ca61fc462107d4e149a40ce56d5637d5db7fe44da3569dfbc1e125f66f2fd0b097509f2ef17ea12847a7fcffb8fbef72951a84b4a6c178550e2745ad694e889d35baccdb23691c582bff72df4a7442a292a5f87e4e4c405285228a59476dc06442995d4f7bba5f23deabdf767c067bb04a5c4ea284bc5137d3bc1d7fdcef59e4a3f8f9ffc4fdf0a6ca6a31fe44f45a12edd0bd119b1f46ef89d18a4f2578d35353348451cc771dc4f8e732389537243061cc7715f33d3719f93032c97ebbaae73428214355ce1bb28d4c7819dfdee0c531e8628d403f9ecb124c24df5dbb6ce865dc731e011402f77869428eeb058e8e7f1411dc4bf23bcd38943e36335994f9fefd3e1f5b0b7a53bec438eca79943ef9fc9ee7edd19b73e92fe144d6d35139aec9f6ac14bc18baf7ae7da23ef9c26cf93bd3912732d106a3facfbb8d7167193850ba7ccbc9e47f823f9376cd32dc0073fd5ff087c143664e92c2ec919f49e7c2d02ebfce9af4f6cc980cbeb9f32599f3c8eb0ceafbcf77e9ab6696e6cf0c73e9f6ba34e7cef7ff6f6c175f1f72549c15fc89f4c8db2ff1df4496950bd4344534454ed6d9a25f698a2ea5515aa351a854ea3df5549c3fd4a73e10f529f0fb362e352cfeed276cbec7bdf72d74bf8954b6efdeeb44168c0aea3991c5a213efb9667b446599c8b1d273bab18f746466e62d3ccf5b347c70d5a2e325427b2eed717242f116fd17bc45cb39f6f82bf5943ec728c33ea09e308a7aea33c909a3286ec5711cc7596662bae4333720dcf0cedfc2034cd812be41f573a8f9e9ad0df42147adb9f3bfee88cb46842c783279d89b3d535a5182fa68c86261fb1d1f74f33cfebbb12c27dbb30e30611bab850f429b022906bbf18ebeea5d9c9ec86241f53d9e45c51654aaefd1e36f7e7b560b37bffd8dc8a2f909bbf94d64d1d8d58d7dd56af560786718304997f6f4d8fd665fdeeabe87ed01c5af13b968c29cb0ba9fb0ee3daffb42079772620edcd7cf61fb9a1248504bd672bbff78d817bcd52539a2de7c8f6f755f1a59623a754a51b4713b23277d46e4adaef39ab7ba779ab7ba4ef59dcd77cfabefde8d9c04e1bbf7a39538614e866ebec703358b05eeeb3fd978ece0a219208a9cdcf11d9b609213d6cd1da98e879db01a30c5460c8695584c118fe12f8cc469f01233dd2ee5b47bf7d2fdd7e10e18a57449fb518fddf7b037764c75232feab11ba244f5ce4664a57ec74f58a712592991c542addbd73c15eeebb7504365ebba671a8fefd8e87625cceaec31d5893b3dd2221eb6bae52d2e2729a243f58e1e54aa5fc1df9b4d8190a4b81eae90c34fbfcc7591294b7fdbf5beeceef4b62694099989e4a16a1697fb3890861c09b3c5fd16a230733db167f2705fd346e56a5c9193394c9289b78638242ec7097139ce87cb3d7d83ab714f4cd243959c092ef74c9ce49843e23a663a9d64791f7a419e18047e280ad1884233e20848d407b9ff423bb9873203442db99a9333cfd52ef733a80eed844dff3c5c3223438f5c8fdccf3051fbd2f7a6ef396ee501cefb3cef53224a2c579ee775ef794a5b7f6c7ccc71dcb672eaeeeeeeee796dd46ac197fe12beb4b472ddbbc3bc5113218420f367fb9df9c3f530dd30c45c16a374735c297d594d7eb05882e0d24c9ea699118129e7bf79b6b9134b1763f0f7b27b16bbca620cfef4c6e0af52d9dcd81e93a757459c6a4943337ff87dc8516deef414cc4b7244cbc950277262872f206ab9fa6e32c9096b6d93d207c3e9f2a740cd4cbc06930f3e2eb55cadbe9c76b5ab1cbfdcb9e3f5294ee49f13f5d8dbb6b1faf97b64eef77e37c28d21304860d208c109ad0c1ef4808c2bca0813421264d4f8a1cc1b4d6421c5f6c50a94bfa00c3030146ff1bb605fa5fa6ae79da93333343334b5d6fa4bfa561474dec51998a86533b5ca3e7f073269d7bc51e8ad81753760e5ea7c2013279be94938a69673e98949e7e7d0941ec3ceaff333b41e861f8a52faced0cc88392058bfa4379c0fe43336c74611ba3a3a51fceacc199df75089ce5b5b3d12d4f275f9a3099f454353fbf2d19524dad3e5207866b684979bb444ec969c85696a18fe0d7f49dff05fc8f9a12e5d7eb1d41159363fafeac1e76fa6768122cbe6e9b579fe21b258cf97f5fced46bb582c714a8f311f5688f52cf03363e98a14ea67be9ad1822dfc7fbe7b34b599bc152af11d17f893ea8439d50c356cb821f82ccb4a017c7ff05d64a5c07a7f1763e09ef5f37e340cce50c94c5d81350c439aaf6114bece45979f9999a7f4c821f8844d13e94ab3359f5fd52e9648653dce6f5ad5a53b5fc8ee00c2aa470f4f42532cc7befc4c0866cb751e9663b6c60a753123d28865f550a4495ec31ad62a965e3a0afebd7bf8a175a71ea77f9fc8fda58f1a4c8f483d26f5c87fafc8dd29d74651bf999c9c325bfc1e9377b5309a4fb689c4b1a2e1d941193148b8fe5c111ceab8c1758f070544c2b8c0e920e2bad37174bd0e1faefbaa5677e7a2e9ba3f93207707ebd11c2bf0c850828e2b3f48020932ce8095f5c270822c9e00e24a0cac0003f39f9c0fb8a04355aa7e506b95f10314ccc1c51bea66118afadc377341c746868e5bf6d06e6db1dabfb371771ddfdc29671847b783fccf573df528dac47892e8bcd4cfeb6db39bfa0f678d9a527533b8a92fc894411068d07688a595bb0385f1e214ad514b170d096d0773eca771aaaa6fc97c68f387e63d4663793c8d53db40b383d4f7a7bedc89a5be6cc9544f5beca69e47a55fb6787e94522a1e1e43c1c7558973f294b4e8a6fc6e62b9d9e0b5fc80d32dbb97619bdd1d3f43253bb6fcf820249061031a3aea8e1fdfbd8bd6aed4ffb02e2dddea77d160e08921c6759b584a543d9d515573d8c46c86be1d768bf829f13f959d41f8dac83670a6ea73a0cafa75a3c77662fe1c33ead73ba020054f75c03e9c09c2e38bcc8acc402c341f5a1fffd1cd7b07cde561875cd6eff820b688ac757172bec8ece6fb554f37aaa79a1d3e688ccc8ccc8c6009224208eefe851620331842c9c9204fe4aafe6b30a6c3123335a6b089a99e7a14f2442d5b32d5930821b88c5ce112bf3bbe886cfef0f846635e107e4e1710108acc788ce64fea8b307d3c2c12dae4e90782468f1edfaf8353f4aa2714746e4afca1d5d2088d074f4a4cfd4e4c84d8687f18fd08627f20f90f25fb0308131026275d34af56204c2ea875de1b9d1e3620d872b3e1962d59697305c40155b66f9122b322587aecd4abfe13e7509d375544cbb545b2cc11b400759d412d5d344e9a020b9a8bd6ae949676ad6aed02e1038cc463b0181c06836130f80b36011fb117dc0573c15f780bd682b360232e0163c157b017b6e2fb492727990a9e82bb7014fc046f61127013bc042bc148f0115c0413c14270100c048b807de01e78070e01e7c038b00d56a880606c0955e118dfc043ac03cb9807bec23f7cff0f8f80b1f0104cc44670164e8269cc046b6127b8c6503097ef47527392a5f87e24454e72d1f723317292abf87e244748904e689a3f3dbe771e2709131535bb3334473f9b04a2e4ad2f954acddc6ff3ad799b5b37a37a46b253fe03d603cf63d80e3c8b616b780ec372e0198c95f20c86ddc0f31796866713d828cf477686672fac069ebbb01978e6c262e0f98b95e1790b1bc3b316b67ccec25ee0d9c842792e81b5c03316b602cf57580a3c7bb1303c5b6127f05c8515e1990a2b81e7223be4790a1b8167292c91e72ef685672e96e7390a0b8167286c91e727ec039e6b7684e72dd601cf4ed89e671258179eb558129e9bb00d7866c296f0bc8465c033cd1a7956c22ee039091be41909fbe4398b3df27c8455c0b311d684e7226c0bcf44d6f54c844dc0f310967c16c2063d63b1afe7202c029e47607d9e81b007789ed99f671158169e7fb0489e7db04e9eafd824cf3dd8159e79b00078dec11ae0596603f01c025b80671dac009e73b02a3c0f59a0671c6c0acf37d8fb6c8325c073ccc2de8a6df255ec009e8a65f242f68407815df22dabe4478bc2a72ccded618718d1d2631ba919a1f56884c648d603cf63d829cf62d80e3c87616b78066339f00c8695f2fc85ddc0b3092c0dcf4736cab3177686e72eac069eb9b01978fe6231f0bc8595e1590b1bc37316b67c36b217782e8185f28c85b5c0f315b602cf5e2c053e042bc2b3151686e72aec90672aec049e8b2c91e729ac049ea5b03ccf5d6c049eb9d822cf51d8179ea1b0233c3f6121f05cb33dcf5bec039e9db0243c93c03ae0598b2de1b909ebc23313d6c8f312b601cf341be45909cb80e724ec916724ec029eb358139e8fb04f9e8db0aee722ac029e892cf94c846de17908fb7a16c226e0198bf5790ec2063d8fc0fe3c036111f03cb3489e45600ff0fc834df2ec8365e1f98a05c0730fd6c9330f3600cf3bd8159e655600cf21b00678d6c1023de7600bf03c64ef330e5685e71b2cecd9069bc273cc0ee0ad58027c157bc253b14d5ec82a79105826dfb228fc68973c08d6e657f6e65356f53d6ceb0219d363036912813019a1dd7e214cd4d2452b8130dd7e2334275bdf6fa4e6e4f8fd468a8c18b5641fb045801c7d3f10a59a078f6ed70051ba1d53d9224c37b6c8181b5ba40987561661bafd2e9a931ef87e57cdc929dfef2a72b203dfef3272b286ef771d39c981ef77213929e5fb5d4a4e6ee0fb5d4b4ed2f0fd2e2627a37cbfabc9c919bedfe5e4a406bedff5e46406be9f8c398981ef27654ecaf0fde4ccc918be9f2472b2fc7e92e6e405be9fac3909e5fbc922272df0fda4919315f87ef2c8490a7c3f89e4240cdf4f2a393981ef27979c94c0f7934c4e46e0fbc926275ff87ed2c949087c3ff9e4e403beff1573d201dfff9239e9c2f7bf664e36e0fb5f444e32e0fb5f342717f0fdaf9a934fbeff55e4a402beff65e4640bdfff3a723201dfff427232e8fb5f4a4e22e0fb5f4b4e1ee0fb5f4c4eb2f0fdaf26279d7cffcbc9c915befff5e4a401bedf27e66401bedf47e6a40adfef33733285eff721729200dfef4373b2c9f7fbd49c64f2fd3e454e2ef97e1f232751f87e9f2327957cbf0f9293277cbf8f929303f87e9f252761dfefc3e4e4fd7e9f262781bedfc7c949017cbfcf939301f8fe9f989300f8fe1f999349beff67e62492efff2172f2e7fb7f684efa7cff4fcdc9d7f7ff1439497eff8f9193aeefff3972d284efff4172f2889341c421d5ebe0c1847cffcf929346beff87c9c912beffa7c94912beffc7c9c99eefff79727284ef471243227392e7fb91cc901021a1e1f4e368f19b7aaff5a9f153a954eaa78d299460f6adc0de36b940f5290f5817cd557315b98c5c472e2497926bc9c5e46a7239b99ec818292367241149236b641169441e9148a412b94432914da413f9f48abd64afd98be8457bd55e452fa3d7d10be9a5f45a7a31bd9a5e4eaf279f988fcc67e643e443f3a9f914f918f91cf920f928f92cf930f934f938f93cfdc47e643fb31fa21fda4feda7e8c7e8e7e807e967e987e9a7e9c7e9e709490c890cc90c09111295dd12e4855899070b22fe28794b057ac0e2144db138461db0384735581c240e581c252916676903168789068bd314c5e238cd60719e346059b10c58960c03963593c1b28862b02c5a6959b50b58561114cb32b280651d55c0b2902860594a3058d6d2042c8b490296d51401cb727ac1b29e206073620fb0393207d89c990b3687a8013687c6009b535b80cd297a62738c1460738e5ab0394809b0394a41366709013687e90036a789059be3e4c4e63cad60756206b03ab202589d990a56872805ab432380d5a935b13a454cac8ed112ab738482d541526275944eb03a4b03b03a4c30ab73ad0e90d51180f51100eb0300d64712eb0389f5f1637df8581f2feb83b43e5cd60792b7fa4db03e94ac8f256ff51bb13e4ab03e9cac8f276ff5f7d81f23d81f45ec0f1efb838888fdf143043b14e471a8128389f04276bc0e3db03949e0f13ed89826b44af4c134797a27e6439b2474ebf8d0e68feafb7ffa7d7850cb96cc12914d1e9e96c589591c99c599e110f5a87a6ac9809a872d7dd4c0c70c6e7f4d11170d491292253036182176fb41a84d1e1b6a9119679f0bf241ac6505d90ff2416c9020d606f9256cb0b16db533a85852aaf64b1aa75493b5486ade4a358d228460534829a4105248292436ea2c3273d245f356ff6ae5e2d2aeefc522b3db1ff425a5bbb7b3bad111788bdb85cceaacd579c4f6c43777aed3b94ddefcb7ffdc3b54f7ddc7c04bb8cce5b66ddbba7b9465f55356b3bd018e6f67d2f1c114fa9d7ba26721a4e6cccf1daa6fe66dc41ae8dd21c630f3e003f587c2cc83ffcdafc1192e017fe6a9092184f03737aceeaf6d6c942ad7e6c6e62fcb46e16bc33831e8587dfbb35ddf7f9f28fb7ec8e6678f37ffd9d839c325b3471b71f6f83d50dfcc1ebf8eb52c663fd632d90d958b84c05155fe3732a825d73e226c6e3e2fadf34364d9f7eb581e5d504b96e9bc3f5f69d204988e0917a83bc6b24382882151f108fe35407e27c8bbf8fe2c66fef0ff9c3e7ece1cee717afceac5a25a72ade634ef2b1e6f45ea43d4ef6da038c9f27205c5c909f36a932df9da176df9bdf8aa9aef5bf340c4b2af6879a9477f6b398d17cbd5ddf13f441f6259ef8ed7f1ee8e67891d0ed7566239f610cbf196af6bf31c2ab91159cce4f12b3c63598fe08dfdac6723ce99077295a5815e1e76872d4db825974cc7f5af76c6a63e0429f47ea2375ffc7ad566407a4713dfdcd928a5be811f9de1a29eb394bd3d90c3251cd74fad5c2e67b852e8a5288c7c8ff4b8a5e089447adc7adc52f0c49e1eb7ef442fc9e4d936282f0c09a26e5f4ea69ea20cd349063feb0e14f73af4c0baf7de5f070f86faf1696ad5fd4e52e0bb89aa1e2965b1871c51cb99a442bb5641a8a8e5ea5294b52674235cfa1ccfed77cb6a1168f2d0afb9fdc409bfe7b4cb27134dc137773e28eedcb7813fc2d4548ae60ee6bafb7f28cfdddddb38f5fe8c42f13649ef75f0607548f682d5d7c1830d0de9f0b0f075e829c3cbaf336d2608d3b54d57f76c2fca76cd72e19299cb62cb68505b355fc3cc25ea5362eae342ed13b58bba56aba5ca0345504b15971efd6bffd4b1263163c64f4ae38913d31112510f1628d3dd7f0e326eb8bba3dc1de55d9b3cfe9d6da32f3d1e35987ea2a9b8fe335d826ba40c6fd935b17dfc1edd7f8817b55ce5ccc21a0d112dea2472469d3fff031a42449d5fbe6650b7ef3ce7e80c2af7de972fa09793a81791e86c7e31e161177b860451e7cf60d0ed3d71986ad3f9fd0853bd3b516ddc999444d1e5db453349891897f672b7ffa8ff58a3d6b86caa1eb7ef5aed21223ed4fed2aea306d32ea6b551bb90bad6454e64564bbea81f616af7234ce57e84a93fc2548a227b87d9dabe6528b1c75bd5a8aa56602271880e6aa9badbb3e61502442d552e66f26c3fa4071c5fb12aa83d137b8817db77ac879e6b3d6e9cc5c16ddbb66ddbb66ddbb66ddbb66ddbb66ddbb66ddbb66ddb7edbb6dfb66ddb3ab1ac3fc254fe11a676932ab7f48037d371e9baa86b3d6e3fc4895aae6a77db9eceee04f2a1d160cf6f9993dc85a96759bad62e2fed9a49483cd159123edcb2b15c6f5a1231efa236ea2fd77b72874a72982a0b0706955bf6e4fcd49335792f71927375265ce4cf46fe2cfbbede7577777777975514e3e0a5afd0e9ea96b59773d9cb965db634f78a6541ed59cbdea8a577bf4c1e672b455dd50ea296de0cef0c5198cfedf45d697fa15d76f54fb5acaa206ab542cc830f6a46b09aff6638abadf9cfa3b931a3df7312d4a313af9b6ce7edba8988a9e54c427ae2531b4c7d4ffc69c2a7791a27b68787dae192a027b6e41b3eea6798824a042dedb169a8244abd21588566993265ea106ba0371463e83e752993767d28b0acb7c5eea66cd93da7badc3b993c8f9a0ac00967fd5f4c85f2428f4388a8e53c5201e884243d7aed3a436f555f164a8fde2cc220be40048d5aaaee64720a3bdca12983d4bbdbbbdddbdddd79a6d8e076ba719d87a294db50a9cfb90f7430e46ef34ab70e04393092aedcda71bb37d8dedded35d7de9b534a5dddcd6d1cfd4da4de5c37d8dd2111125f6d5758a301ef6ebecd917eb7510fe4388e7a4db6db8feac0d65bbb5073a4a16fa8b0098de711cdeacd9d494870b9a5b7e1a086772621a1840e90b8d2b55179dc9994a5074f557567529619009dc04485383c9b1ec05cd9a14693aa07122851a354e3d1430f4654339e76f0708325685020abe1a10c25665240ab3c141d11aa6144c3031610054d333bc891c49782a77007359648a92103b340a1f1f4793d3b2091c5f3aa0756a7541d4a744ac2d05031c8c22951c1ccfbe2c4a6e40ca52e499644124b3f68a2c674841233944ca08492349242c04508256818f51c7925f9614616511091455d9541d56a60022894b61ad47a6719501cf1000a29d6a8ab3bcb80620837a088795e5d75d172af783ddc74e9eab5eab942bd5ac647c8cf1a448aa8a30549462c1d01c4115bdcfe3f228edb3f6651bafd333d2c00897c5004096e7f182ae9daddb4bbbb6f70bbc7edee6eda60a8a4d97ff49f3eb8bfbb192af0e1faeababbfbe6a95089f38634c604d3f081c62d67d24c430cce2de7182c26100209219810e206b77feca1e2f6bf86e0e2f6030171fb991031c5ed7772c3ed7f424b226252d24d687c2e08a2045e0d62ccedef56757c392378a2c8edf7ea085670fb574170b9fddc7321829ca65b8820a97276881c0122073140b071fbebeac71efae2495a438d1f7a2046046acc5645725041a96241920f31f8c1e8f6f7aad65893164a28a9e00a1d341cda1060bcf18317517801ebeeee396e6b21e636eb7677b777d33874e8b9a58a480f4a23f450e6ca1457b4e8b95eede1435208b29ce0a90c30497abec79551f9fdbbfb1a8bc52e7b89f1508f6d57afd78b480b6aa9badeb4295ceceefd9d5755dd7b364a95eb7905e8ef58fcf37694d2efacea6b50475108965a8260bb362b24884ac57871cc7c7a34d0e106b7fbdbe3623af14ece0f92094335af0ec171fb5742dcfeb76226e58083db493a5cf15aaaaa241cc8dceee979164997de8f59a0c451a4415994f6524f1226415eae8b7182028e5b82344c5b5a9004451ab79c493a97f2eadbc5e00f5e05758e183f35538f4c3d0ee4fa136917cf234a93e60f93c9c3bfd3dc3dd123267931aab7da146ff678cd693d5bf851bfbd777da2dcb538adc79fec28f445fd37d5976741d99e2935a1287a509ec537d1b5f4a05028d1695ea339cdc91ea739ed3a753f0a99beb953766deaa0f4d8cc3444b59c4d53bcef97418a48c51545892a346b7beee765b23d7def7696b57df7f3a2d077fb6f9a602e142f5cc414c5094a57e030e6ce3274a8dd227726e1e0a5c9b83e3d8957e7cf51fc2393642ab868f238e5d8941e85c8514bef841e81dcf39e8e8e9ea228d99ea328e19e6605d54b8f46fca5c7a30681b8a84777263dfa33cd42b3b48b4ef931462d7bae5756cfab15e4228ec5297f71985e37c5dfb9e889d2ea605eb1571e3cec7ce1ba58722f65bbf4fbfbfa0335cd0f6ac9462b9adf3ab0fbbe147d71d58354fdb92f2b7f0cdcab762c919e5792139838097a420487ba024dc8fa68be55832b9aef075b5cd174e066691a04699e9be699e63d5442238e9d05e28998284c12991b76cf653fd83fc37db773dc7b98c20f4e1cc3ea24c318882effd2ee277a22222ea2f8da335f9270d072e9a39e2a5d7eee598bf3c72feabde9f247a150ff31ea67e8a447d4033595c1b95cd4731fae40df7b6a9bc8f64c0a2dea91b9f45893555a3b6a174aa9c1b40ba95d9ec6929876d9a4cb607a3c83b2ae54fef6d257da5576acb9b4ab94c2485f2e7fd3daa5a56bac999f377cfe2e62d4b327c9aeb8531fa1680de5a150aa1e696da3355abbdc472cd4d39465a17ede9493f3d38491e0115f06d364e5e724274ed2187489c19a8cf8f9a85d335b4210e3f68a6a3426422273d98dcb7c144583393aeaa315b758d63ea24a33637c2b232a0bf5b3ebe9e9a1a7bba7e336eadd0266fe1af4a17a3db61039aa3ffd7e838a20654ac68a51fbc9694b2ddb8d4bbfdd20a2fa0aaac79807493760390112932b294686c648920d433b35df8f076afe980b088245cc44b8a828c9432de7d3e3886957c7d42e5437b931f350388d7671ab29423ae41332a982597db9acc5a6dad8e4d8e4d45a6bc5b24433e95dfd4c8f0f2d6bf5f382f06e6f66a038396586ef2f65bbe1cf7cced358d68ee7bbe3ab65ed709b63a720d5f0fded16203fc326e1c7e04038d62efe1282a8e57caa329ae79fb1cd647b0c8d7562f90ab56bde5a451598f4c8217fe81531b1148661183e50e72051cbb9145f40e0f259ca68e2072cae5cfe0a6cdbb66ddbb6bd6a73c1c6b19a88ac14e883d103e4eeeedc3747e74f0dde9d3f35d43b7f6a586d4f275bdac4bb3578b7b78ed5e4ef168377fb995f4a94ee4eb106efb2d8af234051a41ce9d19d29333333534a5de9fa768233be64b93d5dcea4fb7f5b8bdb67e4f0d350037d29ac267fbb9fb71363106bf0ae471fc86990e27d0cfae5b8ef5e3d4601737b02f5584394cee7f6bf8ef4d8650fe76c59deb1a54b97aee03233b37f69e5fabb5883df242c926ed33792aa9883864bf9530b7edb281d0dfd33ca06acdcfe707235db87bf644669514a14be35cc28dd0541b1640ff54d5949147eba9f38bf0647d928dd75b1a4dd7397592c6bf0285d99261da36595d8f5ff2e757235f49f4be552b99fcfd1d0b11ba56bd2b1db82cf6b7288723fc270e032566ec9df94eaf05c334ff1a1ee4cddc9bd953bb9e6067cb5c9a1a12e653fbf0e3d30fadb4fd1eaf0b02ed4bb9bfde1548519023fc17066fe78574a94eefa6fc0ca9512a5bb566e99ebf9f86893133697b8e07c7367b32594edbd67de6cc95068e818cff6de770c51b8cc854243c76e2746f144ef3db1f608ae3c863979ca9aeb0f65fbdec4283c608feef57bbf7df7cdb565716de9125dc19d61d7dddd9d75255945dd995405d1e5ff38a98ad9e5073ba98a5812154f97df9b8c0325a1a8f67b2a954aa5288792958ce5963928cff352a9542a954a656957698584a25a36adcce4f127610a2f73fdddaff8cccbcc9f9902df89b27ec5673db2cb98c8b15cbfe23367227e35be19a44ca95caabbbb9bca50dcb6799ee7791e0d3b919d52507d0c99a71e6d6ab59c4f4e93098cc9bf755eadabd5e4be39d113a914aea158a2c43d9367d9cd4f59dc78ebd19632c0e09bb3a57c3376b9634c5c34477984dbc5956166513a9ddc31fdf213f192744b50698aa65baea6f872cb9dcb47a8f77ca0ee36f2160f362a7fd94660b3eae674cc639b0dfc3f1d1b788f9a1eea3dcff3746c505fc70695d3b141dd363a79fc6f72a8a53f4d11e2d87be46c910616a793c9f344634e7eef4f97da2546367f369fe2a896058d0aa227664bc88ab8ee3120aed3a4922a3ded10a500a8e79e85aa2a55c1a7ab1cba2ae793ff0ec7a6f4e83f84873a613c65f2f8f793931e9845533c515b825604d1757f771bae3b939133f918effddd0d77f22fed469fc62a09cc75386a399fae3b214df93e1626c9d30908a08f2c6ac7f8e9b3637b5eadab15b8838f86f9fdb13bedbcb13b2d6b7edf79f92604958f18c90c4e761c7be9d64cfa82491ab8c59f4aedd88183238a42849470cbe954c22d995ff768061e81b9a848522d7b9054e07690c3981aa4c173cc7db2a3b73ad6adf93ceb995e8be5f7ac0664bc210a66c8a340173269c850e9975e49eff633490a30777328dfec4fa9ae92906a5a86624c62be18116121e3a494c4a5261b1ac374f4250bd1139934947a88b8c14a495c6a544687c6301d7df12c4ef444260da5222e7da5654d63c01cddf934ce32c7d39dbf74a467f24c9e71562b6a79e4cef726ad4befe4adca9d3dd218f1cd496934cb1c4f4b697829f2995f71a309098c96a6756c0e314b465e78e624039371e77da82cf264dfbaf8667f1f3f6771e0beebe65ec80a8c7bb6a515eedbd2e72cc8a0d84d9fbdbbbbb9bb4a5bd9dac17cab1fd472e5d4ab32b5b9bf1d338b2ca79b2d895cfe1d8e6845ddb8fc1db8caf9bbd14ba9c8854aa84841e65fcd51cb9516b5a497d30041b8a1f6fb5f6a8f8cf3270aaf723e907da3cd93ab32032c783e0b7c1f3f018597c9d5803d529578f331155550b180d8821460680856547e700a2ccf4554cb4a3dcea53b65f8788aa2ca5c8223463e3ee2d5e54eca572a7f0f754ed737df4aa943b7ccc1d9409d49528cb9e52a87476065a0f4bd3dc739b73d2211a424212a90795ead93cebc9565fecc190957d4243e03bfd9711cd7bd731dfd2f4797522f9756ce7233549dc8b118b5eb4bbbfc68fec89ca4316fd1f756b298ecc67aa48d458e5aba2c76a55d8e65fe5c317f7ad61ecbf3708ebe2c3598ced2b5f6d2467dd4ded62d89e9baae9b39a533293dc407757ecf668bbee7cde813f5bbac47fa4dc91c264aa48516d12f3446c1cc688d7aa146f488225dfa9d3795b5aba44b344687280df48a2ea34bed9a495bc4b44bc8a55fba0c2887885a4e24262a38097ae2c2d387a15d32b42bf5f4679032a55d1fc33e10653b8fefe720f89b05bfb3dfcac71ef1c3a70995709c8802f733df4d4291a65f4aa750723fe3851fc79a5704727ebfe01772dc94eb1cf840ed16c8fd8bd25df013c71e69093c427ff7f37220673d2c3de72d21885abaaceb3aaed3323f0e14125925f008dd538e1ce9b1bb28ddddc49c1ebb6fec69179389d4b38ec90c0be538a21ea6e5cc6aedbb42739172de9dc8443d524ee42c62cfc231b5ec19d1a5b276cd1c8b13f5ac5db369d35937650279e7082e4e673829d576b60fc34fd9796b580bd34c5012eaf15876a471f9b9ec71a15d5c1d47ba079c79b003c399f203a09d37ec2e87e10cf8813db2fb10a2eef8f9359ffa1eaf87417feedbc640c52445d4a756eab7adef333889f3362ad1094704c1f356a2d2f72831654bbea9fadfa3c0ed7bd8efb3dc7796e53f6b2a13b564239aa41ee79d4e527a9cc285f3da63101b6a5957392bb19b850598bfd3e3f7c84a33cc16bf938b9dfd3617d3dcb2f8000c6b9973d471c42563d9714b26a271fc41fcdb47410f53e07e86208e7b4e2cc31b2e7d2b33f4c836d4c0b7859bbf11abdcfccd0360e8e87ed4f64d0100434717004347d7c52d31000c1dc1aadc885dfabbd0e71bdba529f58196428f0dcadc168ff4d853469d3f513507b061fe914d57a727c6982133630e136a4b4b4e02d8420b330be32500368c29ba5b0a1c5780eaee3ae698638e53cfa13cefe6ba9b4688fa48b3b5bde771dbc68965eded4114f72c14ea3b6a25314d66eb34eeb6b51b77dbfae96e3dc7dd3c76b747751cd775bfa46fc7897dd4637f8e15b5f4d9ddb6772ced1259dd73cf6ad2cffd6f449ea55d76360b598185dffd2ca6fe9b61932d3362952eb5a86e1f5ab9522cd0dfe296d0fbd076e15256a8942d5299a18a9472cae54aa1cbfd6cce2fcac610650af75f839cf5aef79d8dd25dafb9eeee58bba6ccc999dfbe89266cdbc424596ac7eebcdb57ebcd56f7f68fe4e4f446ba5bb70541aa5ee4753886e3ba8d7af71c79251972671945495cfb0bbceac5f11161e3066d0cf970061764cc7cb1c6510e64a4e00b0e383ac0bc804711386af9979c302297939cf08113b38614618608d304920faa1768314616242cdae8a291c070018f0d0e3592482046a53ff90a982d37f7eb53500b0e5f6809e3f6371751f06035d1e44d2fb5d4c4525251d28bf273ef5d6f35a29a678bbec71efda6da338aa09674ec51ca0c4c8b82d29ef908beb9b345fc21a6cea7f30b15f2469db3dff99b3771a7e79cf367e9cdf9f3a8afd8e87b8fea0ff50c54c20db5f4bcef9d1c7b5ecc1022dce3d84f38c2a262cf7dcd2a132021b35a528a060d96fae1122b97134b2b979362e5d239a43667f86644b047e619f1871cb19a11a833896674670bee4c5242cc5522e96e4fe48bea3d1135aac72068a58c2e90f24dcb3326ea9183a83cbb350ffeb7e36b97eadec315aa30955b7ae04eeacdcc07ea999c5f39512d11d0f61c59854ae6b3f89a3ccc53c4197ae41fe245e52d65cb9e5a69ca29b7f4a76e65f5999b997b35d3df122c9f1eb4a14525a4fa9ab712c60026c4439cf1014c88c75711e105b09ab752b3c566137f88a92ebc203e79a36e4f435b4a711bd1856ed1076abafd185399b282543388c7dbbc8d28e4bd15584b06157cfa4280a8fd655de588a0f6ff8841dd848cc880073360558c84b1c40c6035cfc30a8545c0aaf0b801ac46ece25f1fa83f17c0df9e636128ee3c28bef064a67183549841adf91d230f1e2af44879bcea9fa05036dbd3e9e27ee31eb421d8bfd9ef39cba4470ad41b0fbb8122cb28134af3334b29f0431a2c331f6ea185c1be40639f883aa8fefd43347ceaf70591053ebda0f8a447ea82acfe139447279d61b41073b71db6a68716f6e0f329fe10534767299ea4472eb925535e8adf397950cb890424be9aa82aef039073996ee1befff302a647a8e4acb486552d99a2110000100041017314002028100c888422b1502820935551f614000b8aac4c70541909a32447619842861063003000040440006666b64d948d99c2ee6b9058bfb721277fdb76a8aa23ca06bd1ca28ae4383c658aa2c382f9d5731134e16eb9b2a16be881c8851291f32ae795747ea773889f33628c4124a05ce9f913a620634d3fb9d8efa89bc55ed8a79d7d49ae9ac05373a588585057542d58fe080c59502b2263c382d3e11956190cbe7af3993f57186786a623872ee3eae928703edb0705da3821166d318771e07fd0381a4133a3cfa14a876c1c364de0bb1c6b5258a7528ff74e1eaf16443ad87d7b3e7ab0169352f892a546e4d1dba496948705811da32c83459927e600a4316836e56e858055070854a457a7e68b4898769ecdcd757421395f2ceb52d9c7ce715a68454a02987d37cee16a835666cae6c731a3bbb4fa4ac7a58f34d2e3ca650fe57d990e32602ab8b0ac0a6154f92c45749ca9df1039f3f7a6b3f68c0407a79742f4e286401ea8318aaed356bb2b8d702956c7e71c6da77a50f3a33ca9270e9e9c9ee718eca48b3cf7485cff54791fef1e0017a677d59e2324901b84a9c2dad0fa2e2c70bc0ab3eef6698d37fedfaf54493e3e10545e6008faa5c9af2bf944d9ca6471361d7b18c9b02bf39d08affe88f258f50a29903c3b2dbda4322e594493ace5780f6f8c232c3a033031a0fb32c063ac04e309e630eb6cf24c070574c78b597fca948d33a219c3c132e65a3cb190dcca8318803717f0d9b81a40f0f5ba509983bffc00a4d2e215fcc8d5345f774764866f3ce0ddd280f1e20d06cf49a59cae5923fd3c43d585711e6c07cb22a50eaa76c6683bf27e40e17fa08b06851640930f894dcd4a52d2e4aee3a491825fb0d36bb0bfc8c247687523843004f7f7eead97d41c6a2183380b62bf464a6735bb0ec460e799a5bbddfe8dc563886b1b0531abfcd01e7e946ecc5d3b34a69ed0eed4d3524733d1483cdf6a9e20ef60c0ab89e53df5b0765dc462edade1e78c66e4635bc28a3d27d5ddcddb9558e8f93fe3ccd390821fbcd4950cbc30db4b80f3a02d7b0462e6c28b2dc1e0800f13a9b5939981936872c00b8b0d23f4be4d674500038990a1e9424984a4c59b68cf6c6ed75d2b4a2e3aab610000a710b5b72140ae4b716e2c543e16bd2ebaf067c665121e5665c9791af2154e886b68b21bfb3a3096e42b75dd53b5f84c476a8836bda30364e2388181918e907073e9ee6fa70b41664030bc26e269ff303f356ae37e70b3925cf3b965fd789c2de95ac118d2b356abaa965fe3e8a2371c6d038738a7aae3c1991f668db81739de981cab52c2e16aaae7eac0d4ca056f0a1be5a8a338aed4c6b7c04752d5e9502f783e9b75d24578ece435f71bd2f862e183b633c8617b7c7826b8c4315077c3fdd652a66710192e2b6c1bc38135ff493c8040395bac1151ef0d0131c33ad09bd314cd1642b3ad8d96d74ee7baa8aa9779bdc4bf8d1f996f9b3f602158398d999d8c194d51bbee7e09cc7f86c22f52ef835f8ab6c0fdf9765e6e8162438aff9b5ddd7a9f6fdb07c3b3713c4e328cc17795b8309f52ca7da0ab9b8f9e5dc7d6af66720e10dcbf8b86983cecf215708f7962d60da6bddf98e64ed4943a08c9667fb5d2e285c7a1e05a84cd70f419fca9b635e9a5acec7892f324c9cf78dca223e8081c400b8c7a3c47f0212c644c1ef18ce9083157b0e519241997712b1dd0ce016f06942fa2ecc976c66c1b5bf3916d35051251402c204c641f629a569421ea276dd79fa51181b063c2eef8937851be4475dfcf5c711034f58fd8fc8f0cf7c7cb82e0d7079209175a9a98b975138b701a953feec8e235cac54e7958010d8a7be3af757d68533d3a6f6ac56221951bdde9cb3c54d9b98a36bd8c36ddfa5adac2996adf829ba6fa4322bd90fc764ea72a455a49c71cd53b5fa70f4855eff6d3dd22731f3037f030859030c7bd12e4199579aa23bcd3063489f83f80fc254593ac73f44c9f43e3f874d290373c4dc3bcf9d2ba47708a7974404d6efa54d97850cb7e691d27561b6e0f4539978c86df43f1f0a8f162278ce4cecaf8a28156dacaf168ea8c9bafe1a52494422491c04cacc616931f4f383d5b1b6580b4662f933d59591005e7b84e789baebd67b7740eb983f1f9fd45d0733a040d067000349d7fbaeb0df024045a3d6fcaf4a1522b292a007798f871a44d4f4807066c6939b0da54b53488af0a8230762f204306b901a63624760e587c66e18a1350a1605a0f3b4f0217faafdddc1d89c3b1c72f17e54e5084fad7c76505e79df0eec1172a44da9b059765148ec80503156fe494ce78a414ce2df401611e042a3e201688559219ad924133e827d3fffb0e91e26f8e4f4117c9dd23156501152900f73c385ba700c7ce7f1eb4d51da9ab441e22ed618ed8dc141ef757ac147fc28fa65cc67cb89d86b9ecd2c0e534ab1f4708f111e795efd0902af1b2d1668f3f02a29a5c86a491ce8000124e92f51dbe6c0f6025db21cdd7ac950cba77a85249dfe2a6c077d559aa5bb044aaab2d9c6eb733a6ea16691851e3890d2bbf9f9c0f0d710c406b88a5375822dadec50b43aedd5d70468584e651b79a3d5b0894fb1ad9f4cac050f4d7cef22935bf4611780e251565be1e2e48bc879126a6c5b25abadf2893fec42c7021d2b6d1a61f95015f987954f55251a3d2d5546c9f638d94573d6880a91e65e3e2c20f73f6094ca74cb0b423aff59481c3c9559a3e33cb9e0c1eee42591ddf9a1a7d56cf233ee7ee3923420d1f2ab64554dd26a425a32e0ef52a42caf8ad5fdc88b065cb3edd34b8ccd78789dea6d05d880720dfa9114d382f6aeb7e09ce49ff140c40708cfe66ec74addab0b6193ada306bcc170e460dd022474d9e854d9fb52ab893dea9168e94f366dd76356e8b769b4747d5dd33bb3778a9b508305f378c1e700e2170eecb04de735db76f6a5ca05663fbf206d9b3b6087492b7e16e7e0a5bc1a46b94c9e292a6509ecc140b63a710efac14844d5cc3820ba9f9eaf2996d05582b669a35a390dcd2ead4928f035cde7722cd1388aa40cc329825fdaf122883bf1ef8ea630112045fd72ac455e4a65382c2f5f5eed77b4dda3d6b8921f0315710d6f8e9e225421153dc546f650f5d690acda7f1e9aa7683625b2e9bb70875626f09a402e924fa337879c33c960660e9549e429346ea142a068ac9fc104b187fa17fffe3705a61843bee01cd7942e031198cb9cfc15170d3bcb01fd8fb5b6af68d361484679ec4c0d86661510720f539297f2de2207cc38c8605f230a5e62cded7b7d2911ca355671e4feb6412de2d62bc2536ddf0e819bd423265b13639e18d570b36b27d81257d45e807ae1f286bd4625ac5b1fd2fcc409f80461aee224cfcbdbc7a5e4a7f2b9b95832821071f86d1e1d3fa4b0431009b07ed03570cfcdc7b5caf7886174cea044771ba87304ae9ef1896becdd14229d44fa11cd7d128f18f6ea928347d9d4d358ffb0e844b090f3cf51e38e4cc2ab03bdae0fffeab3e562f394f64b1104006fcac6af72b9ef63451ee0e5b283722752d7ccdb51e9895406a07b327b264dc1af7e6cc62566b2aa7b4b3294d2bde26363f74a9e6d0bb532b7f880fde66696068ec36d7cf6c7bbf9a3d6de38faef131eebe1a8fcfc7cdf738fb343ebe1f97cfe3ecdb38f83c6ebe8fdb77e3e1fbb8f93c7e1f8d83dff5b9981b7cc6f75d1dcb8393eac7c031403063d0ce0892b13241a73ccf14d0cfd2efec9a0fc711ff7dadc077dd67e38a9fbe5ee0bbeeabf1f17d9ce6cf6b0e5c97b88fd4302e717bae011d5069757649b51935d9537251a9b3fa76aebfc524854d57336c68b86a32676545e1192b3743ea17b9157afa40641a514d5bea8852a48a72b8ff3cc32ff6abdffebaad95d004ca0f76cdc7bdc9824b9d44f93ada15798f45e9b2d48832817a34f6ff4704529d50aa92a7729cc17472a94c9eea08f0f6fc6a9738d525e23ba9687ae3f3d14c10cee7d216efd83c0f64f3fc38be113ae21307c121726a679538640f58969e238b2022b099e35dfde7520b8a2435bc12bae29375eb38d80415537f55d0978c31b5e0bb369e2899ae8c6d0d5b5ac10ada047cf93d689d7eb24759f92ff075baa469c475034dae04748f360a2b826ccbb26e23e49a7453ef155fe0bc2aab7e6c94e27d26475dc53f6d579b543ba6cc1316a714b46bb3e6e8959f381969ea0dc46fe9a53a7412cd70edf80525c512eb2449d6d22feb98b1e3a1f9ceebf6aab876019a8602617449fa4bac05a53b945f3c9f1c0b99436050825ba9fda93b196e0139b5501f674e1928ec62d1bd5bf10c19278bc0fdfeb067c3ece8ea9bbeddf172cb7ab77fe30413a5dd156eaee89672e322bd361b8cd4d97987f43744072a545d06e5b324f303a4ad6b23ad9bed323088a63caf637140d5cb094b6c35ba2753fa93c9a4c3b21ccc32b818b2c3493d80fe16e48913af070e69def1a3c54ab1a5df643f8e105a5007795d582105205625264c9aa53deb6ac46c65462b8ec2d445ac2bb880df6a9fa83cf49b677b90ccc721a0565ce08c5c698973d31abf76ad4a01d89ddf7d5137d3173bfd386744e27adf78a9e8660b68c0638f89864ea9c6538fb70d1b7b840cd991523807754146dd09101dd21fad2bfffa100d5305ae676279a36c0538849c3d81d3e467c02ea2f803052634b06bdf60c247a0fc696decfb373805095a5bb4dd8098d654ca5a7bdd2b191a5764a72d0267cb91083a960a87afb8d06f8b4b089480b21a15d4441dcdcd90f3951a7ad2c0b8b3b26d60a41270bba4164d26287438cda0ba1bd83d1deda30ee3e474c70813ef4b8944db7b53f88410674e41aec8fd7a06c3b9fb8eb4c5fe970c73ad694a837ff7173a3a8a7ecec1662e614b0653cc97efafa486f25ade2aced3c2ab1e2fbf04e69bdc2229f03af60208ad80c8a136ae5578f082beeee21cd6a0e82d7f87b790e206d94784f74a7072f421b5c43a880f0727ef13a580c04c72702f3ba26ccc1150d15b891ecc10a92c409c5453d236a7a2978e9780f894d0cedb528ed58e6f4193c1112f7d012798c205bbfbb065cde929b367324dc491009cb3b2edb9dea31f6ebd9f7099bf8fc9a780eea243943e3ed47e2562ea355801222d297a9897ea8b74913ba009052b120c09581243bceb6e15783527669cef9b308a09a3d32e2f4c944de92f01a175641d3e355ab09d76054ebbe7fd0cee79be2949c40602ccd08318bbacedb81ba6b33d65c9a22df735f2dec86c4cf96b808615288a62fc130796beb7a84e6272c3816fe7fc632d8aa29e051337332400c5cf453a206734151f83f9ff2c09c6d3b908f74205d4928a35b777b4960993f4688d2567678c6b4d5860d3cbbde6d01a8c749a2a2351fca5559cc250165cc29fcdbc65779583cb9557fe560a4e044127b5906345f34dedd865a6a89f6360f4fe364c5e2135c5e2315a374ea55863fd21a82e0a2363fd990a2f3d9aaa44ab6f325d25e96700ae41f0ffcacd382ad1c6043fa19153a286647c02d4c892fa8c5636b2acdc9f94ca7d86ff160b28b112248bc95292861679348c4392f5ba76afa2bdcb25506d705ae1eb94b6585aca22fc75488233fc06f525cf0306dd201593da93ec42d416ca7762d5a23c1a6b55f83a2a8e369124e3bf491a80ba4c2f4e09a68f6c9d691f1f6ea8a9cad3aa118dbbea5ebbdaa77d0429314c60bf3d2cc766f9b6db3ea2579c2ff5dc1d4ff96b73a6dbdaad7b9f43dd3319dad855dde51f8585822696afcdc1022b821d584aff527ded7f878e6efa5c58f08d02a811b8e4ed964263ab5a8c73cb85b4fdb006546bfd2a7bfac87c3761ad52679935fef6313f61223fccfa8d21f27aa575a6a9062f51aef575753bcca8277a920d0abd3a8cf895bcea0279e083352dea5be116dccabd29e9f9dd47dff6b43050c0858e6f198358ebfe7b6f738a9edec4edefc4636fdaa6b68d35c1dc2a06b5b2234bde35eba58186c7748df5b8d3534112dee157dc9063d0d0902317139285c9027edb4d9e45912a3dc9be6ea6843914849c49c37c85219e1a61c39de05bf8b0b530bd6fe888b45fa4bda7010eeceb8597688c22ca4f9e7b6c5c3396b83c386368a9423a14acc604dd1c425df08f63e840c2f3401cb9a0f10b4560621cc58455d85a3eb21b0a6e6054ce9e15f8847a762447465c2e8dcdd0430d0e8b291a4938bfb60090646ae71fd67c8dcffccea40f49d236331616194990d32d22a96f422922543f1f90edad5f7fabaedd5f4382ffc59061304281e0f5441462fc5ea0b75951f35ef99440cbbb09a4a00d3b9833c441a1bd9f53f8b15c3fd8bf9bac179eea1243cc5d02d97618a46739c8c14390bae5b492751605af761dc3a0968eb1d15cda83899926a09fc771fa7541712304c8c61c82b68a59758855a9ca3eeecdba167f67ba3f07bfdfdf667f5103b8d33307cf955457d34a02c3c306f872e235702ca1f04bf093134861289f28217c013a656a13f8755024f262b5b707eb24be39d870a277c71b271b9475d6c9398c74085f96ec160c173c5533cedf27465e59f9fad8a16efaf3209feb32eb822f6e3eb012813f076a1d0f59b2b6f9feb995b039c856d824f3b1e90ed5cb71143493722b02b60e69aaa8e73d618dc3f6708ce70dfa4e658be1ed8370c13743262f7abf68096e681a083eebf9430eeff5a7ec0f24fdc39866c2302350158340da4e5e16e3a65a9bbeb04cd2f77273b0caae511cfac8af52d9bd818d70e17acc82dae204b44a78a523ac5bbe34cd6675fc67e111fc23b44bcc320c19f05ecfa0c18995c42d1e895a38da644bbb7e0e4a96fde84b57f84e4637ffc006afcf55ef45dde6cdafce1af866a8bdd668b782e2704051129045c22c7019b0fa4030847dc7f56583f294e141c0c16f12d69e538e0e4660618fccef68f2729e5876e2d02790c6c0e0b801e0a181583b4c2e7736d6d74b872ad80a426bd839475b1b049cfdbfe13a8655192494f2c5bd1c025bd5da89902d49f000374cca5501982165432526ae8ce4792ae5dabf65b02ddb2d6506543b9ce2fb0c108c1008951b43c9ebde834067d093543c4aec981f3e88e53134288824786dbfcbe0444560714a4a877a74604311be8fb9afc3a2e6dbd153d3e94b774974e9d59313ce3c16d9971b6d097d3b062476f70f8b9ad1940879c97323a1933828650de83b06d75ce57fd7c5784ccc7328aee744731d7bc380dd8bd2ac20234f71c70ca2c8dccd74fa9a875e42befab1ce132dedb4386489cbec315a551ff211da9eb356be94349baa72c038371bf50ff7b264c0971e44a83ff5485c096245a8417fa5959a9b141b454a334b787d8229e6905788a37d26ac0e862f4b97b422087b6bcac65a9fa8802abde88229af2e612b04942fdaa802eebf472757ec86bc8acab76974dcc3ca1f6553d49af81367653eba28298763250ffa0b586a44387c3ec10ad48da3634b8ef29472b20a5ffeaeefd2895e41ed97cbf0704506da4c7739240f6d87512d6611779980dd07e74374b46e4993d4f33abad0bcbef36feecb804fbe20ba32c0020c2188c25d939a8ee4232bd13a3e3719b82d72a56a5bec35aebbab88676320501a399f4409ada8c8ce4ec37967c2f5bdab49b0e57b4e3a2887b74045ec73f72144a1ce3125bb570ab8cfd71a605dbf77240d08705677c4940820502751f752fa5aaf0b2241b0f0fbb0b8acae5bf4320fde3a93457fc5217aca0db90f5139e547d3d610712cbd6ce47eb207bdeba614fe8a9c1f212c8a1c2bdbd8d4b835fb12a80b41753ad724461aaabc0790896397e56ff36cc94a3e607abb695e516aae75604b34ac498774da1dbd559f9a1bd91054238e64c729c409f5fdd49c029bb9c01fb76dfc1d8b6307d2a277390e493fdd90211bc141897d534b6122a4efe3fc243361269a4090f98ba74832665832c0941560bf904e3aaac6dfd2acb6935e07cd42ac55e3e9923c30680bf42d15c2b15fb161a7a5301ec3b0bc1fa6141c392a6da260496d0e8ad8de6d5c8211c6e0bdfe6b85622e03602c26228be45bdaddd23995a4df361e8170ff33cf749d884e38866947c076ee7498a86bc4a55fad1fc339a11725788e3823c0ef524cfdf12502fa501c851ec8fd97a8e768134ee30886cec1d14aa3aff70da50edcd4b32893a994990b1d449e15b6bb8c8f9dca8657a624c30d678f946799e4bb3983200cea73dc5cf19d11a969103b0b24cae67aac398e40cca5acabed5853162726c3aa7e34986a4486df3d5a67d85fbf3849bc7750ffaab625ca22f27b73960a329534cd60dd3a0cba2620c2fa3f09967af8075ef5e4c0f257978f0a2f5963dc185a5ea91d4b31addc99baca637b41ae864edb6377295f3aa0d07b46722d38e8db3beec33507542c2ae3ccc4024626d55cded18e0a96733c903a2c084876309e3f00fc307723f4731d187c4569dfee2c5a0f0fdbb871690758443f5ebc363203f5427c45e5448f779321888ad8687a907df97082551aef75bc436d6e9bfc53293219c025f5671fd1af0455f004e68d7701ac7873de392a9c1aa8ad089533d831ad66312e1259bae1e368d3d1703c764d285b9310c40c88f1274456bf641fb3d996ad65919d77c1b90be006e6e18bee4dcb1ae2ef31c39980ec9e25c6b3bec4460be86b9bcc1bc0a476f67ead41deac318515c561c3b1b7f812fa5548a3fbbe8878625a21df4f26a759a2dbf5f2962adc7b9074c28e796fef72f5e069886d9bfdeab2da21a7e084fb043a77d526e6485c6e2f56c75d2fefbd925803b8b37dfbb08a3088800b5b245b9ecb320f775df47356c466f9ef2989c7ed03b626e3f35b1f2c01117892aced75e87e8e965527cd0a9507e33a2f388060f78fa47a929e7441b8eb1fa4fecb63bcadb881d08019ea9f69ccb5073d93976f1f2fb39c1f3e64ef5bc2e5235657f9ad6714b99ee19afd4ede4dbbae769ea84b4da014e78c677d8d6fd98d45250aad594564a6bd83173318d81a8c82374deb7b86d87e05f638d2c3b18f574f4f9093fdabe5d3042f7e439055f7441a6a8096f2ba6cd8279d8960eb7c3461f7e190a4e6adb3392c5a438f565ece17a78e71d247bf17bb5e46e64db1044b24f70d89cbb4b2a4104f1689d957b7379df4d3252a94363418712e7593a1b604ccbc1b9b4f9475a56402b92df41652c6280d3714f63fe6c84a63e13e859447cf1f7a83efc16e20438f19ae14ff580ec736aed6c9f9b784ef3d9c79e2c9ec501f91e70f87f262158f7b703594b3b1a4df0539c0bebeecd0caa13b3a1ca791eeca163a45327579c1ee534cd06869bdd10442d11c82d6c311af7968e1dbbdc2926840bad24e9362c5c74755eb74c1efaa6d84bb1a90805d0c5aa6b63c6ffbeca8e17757a075d9725e36976756a60931f852f8b2328909dd9c740a0cd3c1305a0c42627319610ac1535a4685ee0c7825e9087218dde845b10016fa5b025bbb0217a68bb5e10342bc246e988bafb872b144d962c91ced19e7672b1ec424813e8b09c85025f0ad5115519607530ed757dfc5089f33f419d8f5d63514df6cfc51335bdabb604ed1eb29ebbf5d5de54f3975984efd820b1a1b818a4e5385c7bceafc4ab0fd1ab703cbe71d85a577c7fcf711310bfe4bfa997ceb5d20080ffb3ef312d71620c4b3a274b23a22c0f105db0a32fa0070fee82826f731505d8ef7d39434130fb961d12dac19f5fd340833e6fec8963b051da5e77ca6b128e4e905443f34547d1a407bea6997e253ab33fda64a263e23b23f01e6a9904eedc0eedfcdeff73cfd8b64ec21b72f69e31c9ec6e0549cfdaa0e99b6644c51d45954a9666ffea4cd3ec67b3baffb9198c6676592691408bf311a9072ebc4b05e5ff0e3c7aae3489b036e9ab25bee8842f16273342d04a3b4858605d637de58573caf981dbf5dde16cb767018ee493a12359a367f0fa5bb15bb556621492aeb5fe1c0ccd5fe4d30ff2f9e3350f82d93d454197a6c01735bb8b0ce83a73628a521a1588bfcc3cf495ec610858ebb9cb54f9f0b6a067a079859b506da6402d30e9689346a2890fcf8913f4acee76ff7ea862950f9a031583870b435030657e2bc0ef13292ef27b86c8a98418feb1451b7ba35ac788f6d1298789b6881a5b175541d1598833dfa98b41345759993978d478e9f9c3fe39aa84e3386877f79b5006e5eb8e9a2407fc45ddddc8e261508066c4b1fdaa44820f1f9540fcc4a66c1ec328a252863b039350465684680d0055493a3fcd104e1404558dcc944003bb1130d79e1bfb0a8f65e1308339b0f539520e9a05dd86b8525c0afb586709589ae10caf6a68a73de07ad284358b2022510c1b6cddd14980d53d7eb71b4593d2d09201c92bf56e15f9bceb9cbb847891c2f4d9945a5e7483eb583b70047cea2933db3beb2365149e1fe14acb61b43f3510b14c012c2630d18823bfe9345a45290dcb901cf9c0ba2143d3beb7c929710a3a02202f304d40c26cd4bb619c519e43534f2032e6d16bd9d821c5e0a275b1c4315b93faeb80ef5bf08499fdc0dc4a41fdbe704357f2c371f7fdc05928c8de11e31c50c6af2859f488b88d5f9286839224e7e930ac439a40afb21e323df0c07a003fdfd4d74963149a19cdf92d31561d1c46482c0cbfc8588a886119c60bfb1cc94862f70166a03d3ad3288e9fd04cb1b22ecb065e6fa8c1303834272334985076e2dc1af3d1a31b25f330f3c6838a11920113f3ec20cf5af0aa63ebc63c9a6d21259d333b3a150fa0a6ee39fc5181895612388d0bfb7a01bf0e24da0b0393b08c61a13911db27c2fe4d17c78ee26f4bc007a86e94a1886edc902ee07f4cbf017e3bc5927cff4e4316673a46794e992adfe00fa1743cb90f38a409d82c7c062e25249c26c8c5ab32670c5b79e89666ccaa123346cf62f208687686566434d7779a28674039560ef5ae79b09aadc4250bcea899adc1af1846c7088a4dc94ca3a3e0490c0d8275971cb64710c72eebe266a7b779069fcd078708e6ffd1a12ce691fb981d2e75129027da921ce92ea0bbe5b146ebf1f3f11312e54c2df1de625a2b1bdddb1f0b6729956a185b3ed72287bafa9b96e6e5cd3dcb1bfebbe9a321bf8006d3a86d1daa4514756d6626afb0b3df9a5bd85225bba8b0579f53c5d73367deff12238ab4e445164e37891d0af83690c67f78d90d44ca7ce1ccde0cad0d08fcfefb7b013df089ce43c006451b955c2259ddaedf6809492b5c99cd5893e6b220428cbecd74e89b6273ee74eadf682fd546992f97f49a0f031196890b5513c72521850277e7c091d708423ed18c528b0aa1c6941d151160516e7a69fcafff5ee58059cf668749891804388114751afd95d61423f62e19045c78d6467ac036babc9aed214d9be9ed565475d0562a581db0f6d9d18cebf9cd0d845f598023280cd96a81545df7852f85c24a8354d2b90ba707e2c524030ba8d0ffdc370eece9caf793a20689a1e77adf7b81a6ca66c902a18f1e9577df1e28a588ace6ba46738ad97f83d0da1b11c190a53414dfc3403b9fd2b37c12337fc11fbd35d729a959eb65bfaf1009f3d4191eef08a65c440a1d990bc8aeacbdaac7a2b409fb572da886a22176f125a8fdf010ee59732c6f74734fa6c11563c7deb1b72aff3903c5f8db613de4705990478a5c70881c5b91e030f30abede23e70fcb0eef078ad3b8d91786a826afccc04c4056ffaa81c5bef0d165722b1e73852306681953ec568c82d395f6c56486d244cb38c758cd92a9a9125153eb8859fcf2672db1122b900cb81b13235e59e48e7f9d4c54bb648ad54256504bcb3571379b024332dcc85a9a336aea106ef67ad5e83970f0c94024d49d47256e17c59df2bba9bc9207d54999cf467fac67e8baea6855fedd933b8a45c8ce6580ead5c0d15f305c591286f4f8bb0ce6d6dac0b3d1f1042ffe2b76ef8deb491e9e975b604175a3f408025bc3c1377689fc1ebbf2f1a84547cb551b522c068f16d8f58246d15cd28bac7e7f0ab6d81f8c9ac0af2937027a3bd591a0145acca04eb799cb50c9037935a43b535f94c4568d1990d8f553bccb80c25f75a3ddd7e05dee4af0c53c412d8e4d5a6f559d2fd45264a6222fb6fa117311bcd468e3d0fe8e061b10b81301487f3ba9efe5f02125d1f06d2aa478b090752d38a29c7126388fcf82ac3d3fc2cca85014e371d7995d700ca650f5560ed7b500ef38d714691d5055dcb71665e8c9583a28d11b97c8ca4c3e88d9237cfa9e10c9b693a8f32c66d107cd4315809ab3d783c9f1b369bd2dcd10e70534f58aeb28deb85d4eb6b5f23d3a09b3e262e445235a1406df4ac09aeedade28856ea6ebfd110aebb3de325bce59b90de3517cb62a216ac1359485d9af6a09523bc4c2353a0f053f091cf75d240f3f43ab17600828e1f1234c82964168b33387d93a237cafa1d5c200fc4d3c8067df1e0f67eec208a0a7708e3edb37a48dc7b3424d084d58805659313944d920f26087eddcd95f2e93e072fbe82dcea4117d2bb6f49f0a0d8bf641113011c08f590c2c8ad079c603050f54f73d906531b2875a2164fb1df039a5400f8f5e2d9320dbc39e1e10d9386ca487a2e1f106c17112cbb2c1aceaa707e3f026c872fd84bf1c55d4a817754fb0c0ca357a2d42eb7447f8ccf783f447d8104469541b76557087e84e99dfeff4f22d279cac23139d8618422a60a1b12118b19dc6cfe65e0b47379ddde2fa88a6d0a66e2b2ec26eb26e162df66c0670073f4262b95fafe612c01fd974abdc5848722539e79dd1cd8c7e354f2bac64a4182b926efd6b094bb3bcd08612ec6d3f79429b69b65cf04aa5c53e75c086b1e56a16c104fc1d15cc0291b92a158269019e8b92ffe2ae35cc590022fd5d3107d427c2ff341d653e7371c0453faad52d2a35b88838695aac1243cf2e01daeedc3e321c850fa3ab9b5f18440fae7cbbb2c63864dd2138673c25fb6c7c3218662a16c932245104e76a589fc9024d4ce40199bf53284b5c3ce1b9a2d21f5ae1a265ba772f4e3094b200497b42a2c2709c19074741638a11580e156f2e7a12ef9e12479d6c1317bf5728589be7f7374360620d534fbb0bb34620abe60752acb6cc0a03554a5c702b1959dd2fb19194213ff80f2bb3cd89189afb8d53bc7ea4533d1558ab62d0c5ce070ab72429d19f8890ae6bcc5c58a5b6eb519aef08f107c14bfd05d2221cb1bf3b4008fe661dc95e9c5c831b6497d76860d4b67fc789da11e6e6f46f5fa593c04d445475b3e7e397c4c06150133f139a6e4d6dd95ed164bd6aec5da31ffe8756856714a3b200215bc7c21b2343dc7ba5357fdb508afca45c79e47b37f07c3ffd478ce4c73b217f8de49c67f9ce97ac97f2c86b12df00c41f258640fcea69d4135406c02c4c3de8b05e91d079c73357111c20f72b60c908b384dab724a611ae3d9935304f66c1bd00a59e83a682c741d24cbb993681c9cbd2c9e1c2e31096428befbb7a0dcbf913dddac027637ae2da81e4fd394fd6abc5ecb5dbeb832bdaff5b52dc4c0814782515c5680f60c410581cc0869b5b45b8bac4a4fdf8827143daf777d6a4ea6530c9a699bce3dcac5d24c19e405556e04100d28247a1a15640ebe0b8cc7585da89c666406a9ffbe3ed340e630eeb52980d7810758041117ae137095bd0d1906f45a00c05c2ad7b24cdc767b625349217333fd53cfef851808ed3c5b9e4187370ce8657201750634f5240421f9022531a072d819721414ab625e430ce814005dd15e31f9babbcb6a7b5302a66c06b461241d7176b89885ecb4248d65b6d981c82b16cd01c50bb4abad4907abc9333700524a9db219d0b2ac02bd86d15a592aa06bb41cc48348fd4ba8e588b64019d3db01c0d6269dbe43844a651f933d21da9980761dee901118ac23f797727f6d5dc2bee0bfa8306295c1991e97cf42266883060aee706fbbede3e75c8b8161ae6e251ce146501e8aedd7dcdcc4ab5a7bf6f9ad178ea9526c2fa3b755332155abe523fa6f445f6b79d4b74a2dd9ecb68a3ee0b1198127262bbf889a71f98e630e33f970512486f31d9f4815957c2855b6be09db6fc11cd74a320f37494c081dd601b67b4a4a2b876da0af150a3e473194f5f5ae63a0a06d41bc2b7cf3c601b83fc97d2494c8a08f7df56f0512f7f649c1a6e6773e7a49aa000ff2b8a0aa937233593bfe0054894dd34fa3000c3bf3ac97fce66054e4ab4b7cd5048fc38f9e769cf68a87e7ba1f285e7573232f765942831c34f1b84003f2943e8487b66f11d6795cbf0c6ed307233bef4708087438eb6143ae4acc5c698d2fb96dc08dda7737ae7208aa699795368a7d50eaf4b63710b5dab95719d2940c3a3e4e3b43cf1690c0946ce196907f637ad6c42804086b0b1aa946f23e79a66b434495741c26b1a1dae85020bae8b6eed9098ce31fd6be90ce5b2f3b98724c23fcb867ffec83d7bdfce2439a2cf85849f4d92330f038867d8b78bc1363e45603eb0be23afc3a97404e76d67744b89aa00a1bdb03f9dd9a7f6bc49366c1fbcb29e993f9d6db0cad1475d6d35d206f9df4b7ce71587ea996e9fbb883c0f063861dba6e7274c9dcc16d706459b180c17eb88c89208321c0e56b50885baec68cdc8304b9d847c4404cddd202b35420cfb358f211050ccf4fdb2600df0c5f2117f1c2707eef55731b1ad1421bb5cd20541b0ed16a68daa615c013e5fa7dad91060f8eb688622ccdb7906b7b11d191d4aaedab082803043d3135ca1a7a35b49498ed9d527ce1a05a75661e4c7bee9d24fab255fa71cb9fd2528084311232b61bffadd5b04f5a4c0b025b437da6ef1f7407ba3790b986d991b31f3e1a1db9959479d6a8d700cb9257e62b5b8e98dbf989219e421f9a40798ed88e67585a0127eb72280df844aa9607ff44991d3649fa731704de8dd05f6a4e060e1d321c82e20e88904b63424729a66b1a54df98c10514ef3b5036af547beab3e372268890d01555f385879bef1c58f00b5cf8f9865062cf0ae2fd5ca10df992fa4a98e704ac4e5776ed4203658d89aca2f446594b52bdbf923e88e6c9017d7e83ec7fb757c58e4fe9512b5017c075fae4a30d95ef1f336e13f1b961b9213bc92b20f04a91178db6b6a8d558e4f55b3aa7aac671e9cd46b947e4a4c63f20027e89b6a4a3e2d028c6af5ddbba823af35a180a05e291f7703734947f824730ceb53c288a540fda1c16349747e64786bec371106b2d6ccc5b0dbc8245f6e8dd4b75d42be8631ed1b75670ba532d39ff3be09e3f43e96d70c197d947e1b26a25e691e1c2b3086853c574113aacd096d66e11c6c446f9f833a66f7fc59952d5c119f4500a42d366f6527c5cbeb04fe7d4b0cc7374d10179cfd708a9176d31e1335f1e5bc8f5a2d72b3fb7173159650cb005642a5fc756d2a8e37c5937b383957fdc4efe7827157f9c1f238504e9a5c2f61d9b558840eaaaa7618798ed73be174776200f4b5210f1a48fc60b325944f2656b1d8c6f81eef4d63070a425fe6a4721f8d775674fb14d0f0a117e0a9006c2bddb25b63e44dbf9cf045b582dc5a9f67250820d2b32442c6c0c71c25f7d68ae25774aa11909f582d4e2448b5e0eedb89c1f9013f6d1a1b84123fe0378df2b0a889a1344d667faadd623ee98be2fcfc7d61987bdfcdfcc46377ca761d255bc092b892aa51252a4a1e4a0a076a7cdf19a4389c25d3b8e291fa5951bed1ca838cad64eda7044d3505c5d6be27841a3bc72fb3e340b6585734d1ca034ca552e9a734cd1283ab73ac87ecd8a048a65fb9ec243deab8d7f62c02347f82d69e1fb6adf51fc4529acdd89db35772abf20a46bb773b3f695f2574d89b5743d303e21e82ac3b0be578dc47380835b6dbf4c069dd088adc6853abfac96133462d738a1e62f268bd8afcfd4fc62c65ac1a759eeb73fc29a2c729ffd01d62c994da5a9133f16b827eed58bffa1eb0f383104e24399204c597e2d250b5395d720cefe60e70ef5bdb0e238b40084fe1293ce10d44d3673b8f8fe9f472402de0729f6c5324321484d5a98fe364d5b8b7a64f270b471545602c172d952206634c09060fe1dcf8cc80e6e70961e210598fd80bcccd0049c305dc37c30550eccd5b2193a02f5839df62400ce364bae899662fa4655deaaf1e5548da00ec7f1df68dba8430afbe1cd5b91960812d07a167560ad7ed969e2637925f21c607642866b6fe9485b4b0129b38aaa3ee2e618e8185ddfff2e0898fda04292e58cf978897c16442630ba13b168faf2c6dbaf315e410044ba0101acb7ab00de91bba4a7a6aa1076513252a2a90740144e720694252699c36befe376a23516f31ab2780469a806653fbfa831acd224c5427fc8907004ffd9525afe90649ad1a7654c6c9513cb17df93d1776f28da19a98e0016b09306c4dc0368bbd3b72153a9c4668bbf6c5f403d91d0843cbae696e130c52265875bbf5698060097a613c97440197c68ff60855ff0d0d723de086fdcbac4c673635343ef05ef28d77fdc29c0de59c1509f92edf2457b22269e3ce2bd3c584ef0da176fd006500bbbed11d7cea45d5a884072ab310af211361ad7c6756d049155aac8a54ceec573c3858d0401cf9dae33062d4891689b8dd72cdd00210468dd0f3dd1e3f7772e8032f5c7339c9926bcd577397255366391315bf087ebd47f1bc14cea91fb004572d11f7f1fc96d44ba5b1d76ad2b0ad7dd43c2d3807e1943a331d9c46db5aba8f8920c77a52a487ba15cff5b19db71a8173c0dc56e99f22224d0a57e4333a187684e61ac177ff4c9f3d3ad97eb7c20ce328835a420cf6e3f824a3b55b73066848b696c535f4be21844237d39de43c6c5dc02369506cad7da6a78e68f6c8a351115e20a2c5e26158d684c3380671d092ee7a5fc47591a59e5059f28c4d0793661f92d513b167fb88e70e3800466bfa12fe88a91ea93cc5f1fafe0680348643eaec33e25d236e92b13e157b8ad7f1c56f471cedd6dc626e46abae15207db43bde42a4807dd0899dd38ce772c4e1629538202b5f38ffe8b4e9cd8afe42898eb15aedfec9bdac65d40928cd00f7b37fc184bf5b857218807ad5434dc21b48c980490df7c056257004dc18221891b03604080f96561b2df0078e382edd7c2c8d647eb4d33e496ba6f5b8b7456c786e4ca959266b69d3eee3c6090966ee5f9150b5cf56c221705bf57f90e3482c6ccc93c21076cb123f46c7c7765285b072787b32fdaf354520e90d136a66bb41f89c60d91eb111ff9ca39e4a48bbdb6f17935c7cb506be31b5628f6a044953c4527b41f44df453d6d1a18a450d0b4321ef3d627f9c983755741fba1aacb7a7e40d308d3ab7b605d5de2d3f6ce8e66d1445e2500da549ea4743a2682a3a5fde56c1485e19c1cbcec3c7fb5d95936dc2805cb3d6c38570827b3889e7ef62e322f8a622234c2b083fa264b680f6a488a5e1e7c483db12cbb6736e65046b7c93fa94c3f2b88ee909497a51999d43e54732e7fe9359e0b41f1cf1200b9ce0e2913e9c63d6a6d78103954c23b8400310980dbf6c9272a87304799a0129a8da23622f170271bdc832f210ce4f289b905c6fa8bd26eeaa3c5e202185d78fd9da6debc5ce45bd3c7c3683b70f3682a82a909b2eb279209667cffdca4b1d4dbc41312b93031db52b9e352d9444a43205c9e1704344a031eeb4113790466d522a3d6c8283d7fc25ecb7887aed4df6c7e9c1a56225c134db2d04655195f65629a169a0d00f637ecf9d834e6f47af2d51b0fa0f46a1e2622e6f4f08a9cc47fd44dad10003d267370a64ba47cf186577b43c908aac18e3d11d2ba931b4f68aab77d8d2925640bb034a0d915acc87fec9d8d1bced73129eb6a91514a75e10334cca42b23f54e5d9a7f3118de94710caf5dd1c335226ab2b45bef6dd88b7555841bbe902f259814fb7d798c08e6e38fb14a76eb44881c9c03a1003e8f3d8f48af3620e8f0faa73885fbdf02ba76f28390869d9dca13ff9e2c9f6ff0b52b6523381a43c1129348757fedd3b197ade5910e5cc956c8acd75891fdc4b2c59deef4999cf8138974fe88a0ada849923a53fd89c114aabf50c64fc38a9d205083a0b117bf176608e59837b7acee57a9edd0c0c816119959354b26fff0adf7207c781414cd6a75b372b3141ec75c7c7b1fef0f12bac7c0a75482b66adc9af8cabc880ff3724c91f8f48e912e05bd7d1743271398005d739e3378e8c13f22e2da4715ffb1059926c7cc454623092821892be6b31a75bbd5ff5d84e353b02506440675a8eb22ffd2d2bc70f1b8ca0bb8e2623e1560365eb46d9ce19ba4076819424af6fae303e49eeb65440eb6a81cb6319626703ff119f368b703e34ea6a1a49baabdc7dccea78bb66e2df7e28c06413954f4a0d7a54fe7b8f92dcc6c963e2bdb7bcb079e6c3f4af38397320d94fbe4152ca835ea3c97bce2cc6ae494651ac1a9d6708f21a7b827770d1671f1e90cd9c128cec297f93923139f3918adaa4e84b901e7b419f8a62a47da46122996180a8ecff9524f0bb375402169ca7e56d6c37c692e55d07270a56fd8bf785489b940e0712a0d0c142dfb48e926a4b36d813e654101443ac8d895831bbca3f86732e066edce750cc0b70ff25b69b307339acd9227ef3de9185b184b25708f4653d334513f0b773677521db9845f05d76be48be4f3476f6a64c1e67f6633e47ae7d85966512fa25c43a6ea7a22b3484db6badbcba4c725804e962a2cabe8e392e4ef8b4f021d8395cd2f036e0a96721885dd7982d995666a89c411d837b35568a1c465a84d47cd8189a67dcc49c8685c8294001939160b33f021e4cc6a13d104bca760f9eafaaa4f8e5bf52fcf85a605832c0fa7d73e46bb2c659ef48762757f466216ebc2665cb8a55f27edd36a162748dc9904269564e11067f25dbb059eeb229e678d6b559aa3fdfa5517d187e32a5cae219826e3a0defb67c92f5de2ad04f5bb64c0faca1bc17dd23a1a6de8c0fb77822f1ee643adf0f5b99c7ba4c88d83af672f4700e9d4c3cfc697c9064e41f9afe8e045c189138f11a78681abb2b23b43f7d30065a13c2d8ccb02b9c60d32a6bfdc6835409a7ac2197006accc45ce8bae7b574d0fce7e6bb9c94f26fea09b4023e5cb3611607ef35d38ef1a9e161aa4848541b434d64730cd704699771b934b3062b482c1fe2ec705ef58ab8c8918469fe43752562a8ff8033a8d369eee925ca62c25428ad92ee59058c2951651ef615676a741a1059d1027001b2f928344048232c2217bead31b0fa3ee282a0bb16e94d0016c59533ccb3639156dc023cec9ff5da16081276093fb504436342b0f82e1202688f0de74f38314abd14db9b297258b55a2901e31d5ae174c9fd712f86d76482858db61ae81ea9328ab5885e793f338c8f49f0fc35d3388be548583c71c14d2f15ef781266404866bdeb082d1e534c95cbd2cbaace1152e137146d015e2169d3d372f73c657c5149fd3b445df5d9007e2bfd0b362f8823875a78ce9498d3c656710184edb6cc1ef6699951f905667ebac61f52e77c79b508237254c9de5c395ef7e0653b401dbb07720629ddefccd13034bb87772d58416d82d0fa14c3a6fab4968a077a034577d22c63169c71072c1c51eb4eb6d2d6dc1a6339ee50faa97ea7690126f1d976474008a68e3202bd20940989e2b12abcbb905e8c7d053960eb9f58e3ebb5cdfa2b1d8b9adb8c419b5c9f215f24722593c692c5934758586456283e030a1bc97829f9e20abefca06a95c8e6c00ed01c30e16599f61e344b01736d489a394a5f1894c4e5f67b679e474271c0474ad8e234e364e18ed11a4ffe855494791e4d6572e6d52a2ecf39a99642060a34caec85102a3dfba16db7a322b3f9be051e97b4c6f1022afefba7fe6eb673d480e1f7792ac5500ff16c9e0b165700773c2d785c61f392bf7efe30649d1e0f445e9f6e960c24cf2f038f99359f04f2ac9fe5cd86467a4d4d597045ff243194438fd2883a139164aca677e2204367d82dc7e780722c2a78c17b47b8d77d4076513861af0883f1a6c0921197a47602f9847db8872885d9273fd4177bf1626094053e76da531a893535a32ab99f62c556c129dbc66e0da34edb3a46c6368ef726a780538c9bd8ea555a581aa698c3ad695a30efa4d63709e27c4ce5a9ef00ec734954e21d4ba95696689de3e854c5fe509a47c2d75e8d89183a090ee62031c6b2edeb36f98cd4384c3ca1921842dc4a15b33e122be86072ef8c080153b03cb8cae51dec2db229db6b7244d3792688a78925fe8fbf78ab8db1a381e62ffc9c4ac183924e6e030e56b263da4e07c94a183070862f344ba01965cebd1ffa392a1419567625c628852241d3d013ae8638daec50f9f46d216d7381990ea04a18a25a41fa42d8ce0941155ec00e267e404baa41860c38d6ea7448a2023d11131f148b8c0b3baeb73aa58e0ac0929879064b4b05b55035830520bfffa8f9b7452507d4ce70ff77398b2205432e8f42a60f363dcc0ce85a2e2ad583ba108d1a38bd4705d189bee39c49786359a98c006753fd0a05cd9832939968990fae4fb73b2effaba867dd675e492fa5342f1cf12730cb116d50e2d166746fe68c96d42fe2d2138de69cdc5d70f3c76ebeee2c3f39f776111c1aaa8d57bc6a51fc68d24109edee97f6ae2c4b422b8b10581ab416180dafba0a62673a39e9677f322c7e933f2b5e644fb2cffe49f601ade1a4b8dcc0fb0513844e91b8eb57467211f0536737c007911e0fb6b36d1079fbdfc8ffeaff0de2c0d440dc44fa0717e284ae09daa87a879b871b52f175b1eb7827a2679eea030a7fa679662f84bbcf64ac680452f9409300efc666198b88615255a6cc4b0ac52e2a30da7250828b8d60f377c590ba6f443dec4596e877cffda0bf2adfdf14ed2e5af064d5e4f6fc6810918c536e9694490a947434c57d1aae4b4b25b5d0f0ae811fe665700ce248f6cdc0551ee59d03c07756b0956c0316ebfcf1fa2c1461515f281d47f27968763c57b521ae840cdf9e73b9ad9039273c0ac55f0244cb5c8d09de8508659ef979eca2b5b6f3bee8487f6a07dbd10e0f66c6d40df60f1069c6d0e6f4f0feffa810920debc589838f18ac87e87c25180d58212c0db16b22d6d641417abee3222d952b47d831f19623b23a5012b5502e5c8f7b4c60de4801446352043343b5a433d239ce456b8e7d6e81b939226902d726d1279bd5ef4cfef0335080dc8c83b8996eaa29392680751cdbb9dc3324296e9bd122bc88aade2c2261c272a448637aa0a59584bb0adbbe49c4f6fb1571a5e6519852ee0d35ae49f12c1bc436a42fde4b893c3676168f43f8f64057021e74b40ebee1b70e3650825f8ce97c59bdace6c0fffe80c34dc4ab59b532816292685c421a25b1ced998150da9e63c510cc9a0f44cee6af24a3df406f688c8dd816e7582e728b2e9caa3f6e0d246151ddb38f92ca0a7c349eeda9061efca96a4e0786347bcc85a0cc9dec291a0bdc0b9ea031193acf5a12a9016793ce5e28b237c325c118785b7a26eb2c0da7ed6d88e34e4bb75112407a46bcefe32ec8244f0f4a0ce3e51ee810861e94ba5e817838f8ae4e10a7cef480453c839be9648b7add61315824a64471d594ccca6a90b2baacc0c05a935ed9506c86e6f7fd5e2b9785740f41b325212e70d59b51bf44a1af78fb7be9a715a53c46c502306a0390aa18eb698fa03e1e15752c0c792c4df5b7eb8d843ac227ebda1b08ae141505be3a5c92ba9c72c96b1abeab90a4f327b7ef2065bae77e99c67a04642d50f4b8c7a9187a800585a8be22233ec86974eb1dc5396dc283e4e7b265442b5354d7b73a153471daf67cef98e6791acfb2026ea1ed9dd3509aa45b7a95d911f270d5dc047c72f6b11c857d73fd1c0334acd4f63ebec6f490740ce9a9cff76deddbf5e08029076926d0308da47ef51e981a86c8c9bbec87fa1d993efc842be6ddedfa2ef1dd12bf63be8a5368f173a6682c9cdabbc862a19c73617beb8fb52cd8b8e82c024a84313d9d02a046e88b667b5dde0d9835b94025955d4021d060c68e70ec7092d18df5925cd144e103dc3107b62b166a480025a7a085058e7da2fe49e88dd366a8cc515514c9061111093d64b7aade403f253f19e6e72d29d02b53af5bf923c1fc3e1ca12250dc3bdbf705c30e5ab726002035978b4e891db09688c962dff7da7874f8ec6c4e57477432a48c92c10eb611583a557f694ad009dc62308977f78cb1d04a236a0dd2bbd50968493bda533ce2391f1be53331060dd05060ecbfbcae31897eb49ffcad3dbf10f76df5bd9372528259ebc71bda0970e0987cf3a6b5c56bd227c121a470ea30263ebe82619dfbd4c36e4e0dd1eb2f35fb8ed27917201d34bde723550d2cfd8991d361a83179a52bd26d26891575189b28d8c642a403faefce1acc9ed0e1df259a9d84238b1de755c10fef1fa9e94673035df28b6089410d9c33f164946e8a1b6a4e32008b4b56a33e2e201234b10cd4f7df74c7181da60d256aac659175d0b03b0980ce4b0325056f6b26d6197f78a2d0e67fbf39f49f0f412f43708b548dab4f7d4bf80b6e6723f413790f0eb1aec688f4626aa9ca7852572432e34dae209601cb312b923db6532f4fa56228b1d95b2a9062597a1e06ec789cf4f66c5fbe873aab463f11664dba50568e7c56e3f87afd94f09a6632451780daf0b42ea68db3ef794577017c631c8b273b0ae8dc6a57e0da3e6ac92a40536db3b8e0d89f74f0aa92a6e982c91bcb9974f9eb4c1b75158ae8ac5b17bfc571aed361ac612755cffd9912eb3451a0246ba6b6c6dfbbb903783cda2c99366627778a77860d17979e1fa5dd1f6e033f251df15f2b2303ade8b124b679fc35cc229313c6be8dd99de025fcf0a023f5d397c22359a298b222950aae470884c04deb8f0224ac2aae08b78faaec8cfad1ec42016c9a053402af9594ccc313e744accad40f39a4dadbaee3d3db87dcc17edf79cd34506b313ae9595ec5117c75102dd40f888adc214ead654cd869466618a18e1a39dc25d45152e190ec6bba892e5ca272c009891026b3369162e6c3487c93ed20ee386656eddc09d704835ea3c6a08004aac389a59912f5b5ec04c20afeb76cc8530c18a6c19712d29c1ca377051bf917cb242b481440d7f3bccf20503c555301237180bb32357bea4d18b21bc2d941a25b1af46a4d0237361cb40cf7d99093cdacef0a152e1cd3232bcece930dc5220a6ec304040140ab6f9b3f4df1464c146aa5b24439fac1300966bf651e229a0a39d8749e1f782d4d011f927360637fd0e178e09629bdb9e2f86d9e0b9c03eebdaf4a3b97a03761767edd0df55e9403d542127b891e74cc9b4b049d2c3e813fa330f71ce1d1f5b89a24d82327329f0a4ad3a853c7aab0435658ff68cb802dd98578e17e0021828731ec97d7c200f6c965a2cca2c6d262d4581ff697addcde505f41a50298f104e5c4039119209cb0dcc8231d9c99f4093c54b60d81279b4bf55d70234efe58082d5cc5e8ca297666ecc03baea4fcc30312f93fc64ccb303f3aed6de0b81883d43d71e4ca6f8f42d667907b5e4cca36cf0b267fa04fd58f5223ca7e484ffa975808fe075a4751c3e4994866391b409977eddc558c9e894cbc82e966fd64f71ba7c02441feec9e2b942966c4a06942d5994b246f44c8f0093a1863b42b0a5f7c9a067f5f15691ed323a7da81651d04c6ab100dc330703f6762f03cb21ff44eaa20bbb376009037a66a0a34d1beca9e7325f5f4e3347928e58b66016587f3b27dd4594f9a94ce3314807c0734449999665077e4a0915dabb9186a5a5ace9f4d8ea67c8b066542230bd0f0dd6750d33302e90c9773066d6f461acd704766101e66447919ce5806d92b23d094e192c9a08564a41719ee840cc23c46f49f6338cb1864be18012a864b1283f68891f661b8c730085118d1230c2707832c82117860b83460d0e62f52f885fbf50521f9229abd705e2fc83a2f02c10b17dc05edd945cabae04153a7ace0a22cd2259673598f5c1c3e2e511b2ecbbcc519dc12e168cbd20f51bde95a0aa116544e8b20a185e7e882f673919e5cb8332e080317d1bf85b3dd822c6d11005bb81cd55ad8cee40b01a2f0856490820fe71cbd577f62a876c5e80c787e228123c1c4b2e02a6783fe83684530c5e40b06531a80d1df67f7fc29934c55a2ef0d93f149a7c3c79cf691618171ed9d838b2c8d1a6ac83100e970e26d1aa479522fce2709934857eb2279c1d365ed67db4566acf90d5734f430aedb288d6a926b1a1d756529da4ab1358cdc2cf8df9733ec919f97cdac261370a1dee097254dfaa0de7c80794467427c81c99f370f8435e9192c68a7a3a21601806e3d238cdd2efe631cfb882a37630da659f30115740c398bca95a729c1338fff825a5799167f56a2bd17dd988736262efd728ae6abac716e847bcf77cec4594f12fe9635f0db21c1bc20cb3cf567510f78139e9e09b01ba6fcb76b00f70293f9689641bae7a61efa26203719619f4e79ec5542ee1b7d929879c45ca017f5d289da8fa9bdf520c3e8efedfce9cab319a033eff34d7f4f652c1d3c963f7d7b9f5174eb41cee8efedccd3956773a033ef339bfe9eca2d1d3c9679faf63e5774eb4186d1dfdbf9d39567334067deb2724d47b337266882f621594c518e63944d44e8fe9b7b30b515fa6f767019bca40a6e23f102d44bcac67f168dff01c1d5fc094611402f9d0e341ba05ff45e5002c5764434a0ac6718e6ea73916a45c7d2cf73bdd4bb55aa4191a0a02f68b6887e8d71795a6006819040e1b38ed6cf5dec8b83856cf3ecd3ae6896629fcb18fb27c9ca6b1c8d7dd6d30e3a909df5d451a88d7c7ee8f08586f45bf9f468a910e66df5c06d2cb8a01cecba0e7216691a16c054e6a593b850942f7520b114dc945ee163619d1602053e3f3850cb6d7d71e98dfbec82e188685db6dd438126fc79d39d30920bbdfe10f1202e05b38c96455ed108cb81fd6b8dda957bfdf3a29cf5286fa40cb6aaa8ce72953e2ee0e419e2fad3d4fa17e95c9d52e1d2b9aae66f4e7702eae9ad31bb7ea5f5937d97d02745836b96e8f879754e8f47032c5e619123da3c322c99b475e6b39ef77e3c497a0f596c74f2ad551238fe785b4f632db4ebd9daeee583e8cebd20ffac8afb4690c7f6e37937253eed350b8c185b74478bf2672184674c866790e631c980704d851de7ab457093f4858573118b4754dc724c19328de522cf8724af4143c451b08fc819af97279776638eb1030da4bdfeaa4a70078416f65733299334cc9ec3e819865da9c8734b1f91dc09875180e401644d089f32aa5634e88916fc807ad880cdf164152f7581a5eae11fedd399ff7935a95e09161cb4c01357d0ca4ec47c13e9e8310848a484bbcb1d72a46d2544dbc3c739e47248c389a3b20072449f0d98431c4050958ed628e601b7aa7cdb69ab4925be1f17fb343c205cdc23bd8fde9c72d8d3acfd8474cc0aef94f7a7bd45a87631c18b932ac2444ae079b57b1757cfb1e45bf0c2e9883be1ee35b3703b65fc07eb34f66b1a48c883d282bd722ea1e7927b99c8b12a589f089d5979991fa3e3c3880c349dc5f1249ac40317832c3f17adabb505276bc43f1d441210230315add864ebe0becb685207fe9e8f219155a2a3a548831c547a948ff939eccf06601be9b054bb03f4d14e3de084f5a574dea656bd31a5b9603e1d86e748338ed598ef4ed7ec0c9cd4b2de797e25a38fa9da1bb4d1ae08e3169a2a320000a815b58ed2a1cfa4d4fe3e98dd4ef29181c3704babe38833b572585f72d492aea0cfa3fae4ba5a920f4332e7830b805ed69e13b7c015ea3a339adba44838e5dcde10d420f34d079c0dbf92edaba5697a00f3372b84455cff7d20093aaff501c551dcced18415302713451c81475af5d25de84d895a50f71ff94ab0c7f953950fc360acbeec5bba8c97b86a03d549c0b8b14d6758dbec6e2fe33a9015bb839c5f56e2cd50228463fb563c09ae8538fb0b1fc93595f0dacd36534330f29e15d336711bf9f135495201cb8b6f1d89b202c473ba43419f076569ad4b763d7e71e635be1b44498d891db3b1097c5e840e510520574fa7730259f041f746e5e224de6d9b758b2d97aec20a02b4677af5473ad2a65c99da5e47c00b8d37f14a86f49f89fa63830045022f81cbe399ccd166b4a40f20428338df5a91d00bd25f9dd9a1f8beac9591f8df9623d02395eefcea66e908d54c5c749dd1ce0f805038fb1563578cdacd4a5aabce1cfed14baa8a4ffaa8bda445e64eafb4e0ef620ebea8ab567ed3e937ea12290cea8f8e8b9aa6fcfed1e4fea7144749d851130dee51cf18e2bc6f2cd38fa5bd3de260cacabe94eab99fd566619839d2b2092df01f3e5824ba7267770d537b90c021398f011ea7b25f4dc6132fd5bff91e23600726ae41eeadfd9fae6b59959438d63cbaf2408cbcfa68a1f2e099786d3a24a0ab40a5e283d50972ba85abd84e68811d94aff7c4510cf0fba2b5fc47aea815dcc6cdca7da3cc5582c86cacb4c377f2759f6becf0ef2529265e3d6e8f08f42c120f8fb528d20b1302eae490222a0d5ef8b9077d36cc3a6d2b060fd35723fd7495fcd53d1798bc6a1dba8bf6a90de08a82ce2ed1fb7e02e7342bd0300f1383164dadb5972c1c332071e705cca87a3f469f5705561f54143386f66a2bdc57d875743d5889b814c373bd21bc1d6759aa6915adf73bebff0ea062245f10e0859f6c0972ea69a4233fa5b0b4365b32e9d76cedd379987db25b8c0bb1a369ff011dc4077dc3e03d6c108a73034fc037bc992c5f088f9e26abf43158e3ce07bd8f46bd01d183d653e337b67c157933c1c7ce3c0054652a3628407ba903fa7041f972fe39528b08b1e21e9ad828b4a9da7861ef73412ec3c0d387c191e61daf9b2d46205a7bd59806f5eb7aeeffcf1d2f54cca983129f8974db845f4493652d2604e8e2842d8916c2b91e6ea5564a0f5be0506298c8ea66d6ca82bfa64ad6da8375e87fd73bf4404121c689c3ffcf5e11fbff52a1f7a982d35805d74cab09555ef8302c7aaaa02febefcbf868e994bbc4f7ae17bb4e32df1bb88b2bc7b33aff558d54a40a8016a38a589559aed80cf858af0ea9075a7590bdfb75b7490a9ffa959360bf3465960b8f417694c2865714804eeeb66ceb3ebe34f8ff9a04e617022967995f214ad55d1204225f5da58577d565d7e5eeb7078ff4ca55549a0a59e3706835ee9c48801e7a4a375b2e58c3890904eef5ad0b5887b8a6de4df709408cb86746f7eb3d7291de6f40ec9fcb0ca1665c2caa8c3313098c2c945e228644e75a0e2531b300524c9c5f2560be700173cfe134b7437726819ae919cc4d2e34a035990ff62d3aa0280f03cb42ddb9dc1b7813a007e0ee7a31eeff79ff47dfa3d22f96fbe6db7d0d1d4f73d0ebf7691f57c673f0a1fb4695f46e236771e46c6231b574c5ac3656976713c18774abfba3dd629f4bd5fdc43572b8cdbb37cfa4b2b9f14d7959df2d38232a979a66436f449c6e9a768ee288f4f7bafef6b297765ab29746eea61b07d5f437ed9a6e92817ab59361ff5a5213edc8af6710eeb83b88a8159dc0e0558705aec434264cc925dd898ea6e20cf02259d6cdaaa7d2ab1fdf9c8931cddcc1280543eb8e6ffda31bebeef904db411356d9e34884e6cb3f1cea8ff77ddfd442af79c078030d14e4f5706a2bb6d4546fd796dc15748a91b0d282ba93a1293458d61a32f9d98a3d35e88dba72dff00e4ecb6f1dae41b9b880afb54c9ffbaba74673ba34976c9d89208c28e06b3a65cdedefeb2581d4f7119558a81442cc47bdbcaabfbfe02b14fda48a4a47c8015428ddef2d37f30a194015773e878fbbbff0efcffafacfa5a10578468dba62c7deaace027b99fa38477e4d4754870db8a8fc4c41d323e6dd253d1b42e7284bc6e781b9e23339af52dc0c9949df5f671d4daefaa3e3e1b3a1a1fb50f48de9e60c8cd3d23b34139773204155d1933eb8f2df3b197a667fb84ce515742d3990f63e37b88667135f8afde2d580fb9524d67e818aa7f3540410fc40385ec0575b8141c02ef311df8021d4ac09da51303a2c82d93964247df195704bd42fb81d72a1f7399b4d6a3c3ad4534a98507d04132d5060428a9958f0b6825885e6070250fc28e5e0a3cfe2663fd4b4f0d537150d62457f1b58f1a7dcb038fb904ab9581d8e707c6cef380bea221881a2df03cec63c3bc662facd5ca80db0cda16536744ee63cfb120f5a663152180252af4825641c1722ef98103728b6bad2e3a107ce52e9317d4f70aaac0181178de6c731f3977102f708c0ddcf5d57cdfd8b80c1077eae2b3b5ea6dc6db099db2fbfd15d3828360ef74be1a0f111928ee1acd41d05df7ca440b555d23a2051e7926c9a81298248d27b19b824844242ce1916253fce3e3cec555599b5e19a3d0ffd149f2348dab8c35e549852721c16d89af19a1a93568ce2811206db5cf8f22f950e552eb5de8b562940484e362d44f543eaee6c9dd00478952776f2fef1bd4529c66eb8ca9a5f6d878f0d0466dc71c6e6cced9d93980d82eea3d9c5016894c4e2e23d65c11b2d25d69bf8dbfc9d999c042b70512494491669e2d76245c1e5355601b8ddb4e267fabcc4394aabd69087d96d00ef5acfc10e4c48b36abb97971c67116029d25bae248c96f2b34538b4289e3f5901fcb4e2cb08cefbc6f9a9d53d284bab6d9f3bd698b9af26caf6707c054f5bbc6abe4b57e863f752716442a61d733f7b6c105b095d095178922cdb327fb8f5448b189a16518e18c6a624f434925db05fdad0ef82ba17a8664cc4b070b9af45fd2b161d6cce6c0a7206e807dda14641d374208801044c65876601022f3f159269485961cb3a0fc8850ebcd1c5a0ace7f4ddd2c6c51257f08f65ae1111989f89539bcbf45c3c21e7d5f98ac94d96101fb43b6e6d025885ce9b08d5837fbc1fbe6d6d9e14e8178031c23c0bf0dbb670a36ad93efadff7a3a0e3340dc410ad83d816c6de2da1447c41698d9cc0c2136d5db0aa9131771319fcb8f8e06c37cfdd6878905e5ad3b81344762fb828eb75ee70d2a20238fa43436092301b24886423ea034cc9330cd73318f4394d7c3de8003b018475705110066a8338c076d37033278f90ebf1826b4274a03fef5b1c330702f26899043ec987975b05ca3b344926e9938d96c194e1791ba1e426fe5530cf9c1e025cf0d31458c99576284c6ae040085934cd78aedab345e0c44560e87958d36c84c377048aeb8eb89586e0ca23d474ee6311c7268e2d832930192387907dec785a83bb9623f42f8545ffc2cade194b1ba681dae5dd98e07b821e32a7dfb894e68ac68ecfdc9c2561b1b9774a28ced37149194b0a7ec7e8b589494a55458e1a0a4328655ad11a73f41c13cd1dbfe01cd35aa673640562e5c155f8d8b837b0e44910ee6c2b6514345916b224d6616ac2c893baf14abf554c22b78e7992b4831fcbac458fd7964aca102cc40de2d108fbb1c4fec509b121a799c15cc23dec0f0e762f2cf946ead518ea25b55c711a7fe6ae7dd98d4770b1607b580fac04b77bd6e571f90c901d2bbb36f6988cc8dc94ea9a634c568c72a267499e439f118075fe8f4c66ccbc4fc48d8480009f707005236e85349da75f405ccc50c7ccb12bd6f9e96e8b1639ceed47e3c676378fab6360ce6e79a170ba2c0f0ce4fb03d17e423d7dc3857b6e4b1a8f16690891e2f5a5924ae13d0b791c4274d17dbccd3139aebbb67953b35eb17647e6f49bf35de287d66d04a40d370c31a6bb54a1362ced6026b3a47e2363c460029aa391c74e4e44e997ebf0cc384b1e8741e75c64b001720fa16e5fa712692a94837307df9f2111d8b27dbdd3c509c30f483c037a0c7cd5eeafd152f0bca8ccef6cde6071696ce6ee6c76a83ccc9269e5ee6c94bef1ae8a3dfe765ea08ba5cb9ddf50348ac88803ee9856ea83c5f7db60323acc11a4014a267f73b0a3072c2d7cdc34ef458402004cc0253b2a53bdc5655a929d931f6625368e98737fc3435b6c230ae6283a692f23183678c46be1b2531777c2613edebc720dd2563acf80f05805addbfeae117de6b98ee906e44ed731e3ef3e3bb72f84044ebfeb5411d98b5508b82065afdd896c44c71dc48489a75f999e2243ca8e26c81127394ee0bf35183d664af68710d187838d960947acac11ea4a1e77f0791dac53c4e2ff801aff0827d3b3254f9ae1c2c55d977791ccd12161be394556beb7ac7172c9641f0e7c4b168e32c337b29249d8e48991c0e2b65a8b4c382b0bca91cf0373d7532d82b9540e0b2a04d56fdda081af8c54d284c01e120287e328643eb66927ef3940c13b584c007eb6f8808132249f801493c12d634c4b624435144c2e29e0620773bb859fda98468cb5d7cc06dfc1c2a4d1a707ee020178e84ebfbbba0b3014601d15b60e5e9c4aa99a8eca9cdd7777e233ca90901bab011c92d331fc9225b14e2e23edd42a051a161cccc50c1163afd0d9a5d295ce09682689b83050a153af8e0465c664b4018b003128f25e4cccba06396645b9bb44c2780724cd217bcc25824a6abb3eab4bf7cb04a1b9273045e1cd74970567cdae59426ac2e929753ca9c267bd7ea05411f3eea960f34108f4dc24e067d012038df991e8cff107d494d6a99845267a83b3026f30a863d605e36d14066115a82fdb3fd81109f4d59b01c3bb58b9947104e0c79a158962b6a939b01beadcdfb1ae105594d44b9c8360fa69f57d1f92ffada161b59344a62655cd981ace47011a0c59833839b37153759844533e3a2512bf6432eb886d124af5d6ce729788960944cb4b12f2531cd0d2bc63f2e0b1da5da281f1fda951f9fcb35d23a53a11ca127553cc6d328157d52c065069fccf1bdd3a9d25e0c094b39753ae2b1749eccd739b03e974bacfb96802e092f1884dc2459f3278f35b199d157791f510881e2e0ebd29402cb62aa71baa1046986b65dff0a29f22484f6a2f5fbcd21232397a2cd3a747c5bab6cc00ea71d684a5212359e90e0d16e0d75169d1c21b210a0fc718f170630f5e9528edb1e48b338f1771b66e651a08e5f4572258300929b9288928d9c8baa2f701a9c3906c74250b8dc8ca4f4e391e5ddefe4edcba626a200be076b0b387a1f14d2dd6103cdfe0c1a88d226f683461e68f1946c57aaf6eb06526d3f2d790d837ca6f64272a1e46e6b36368439e367574e2047a3a5a765e9e8d9eea2644fc8029312c7ff9f86f6c6f1d2fd53cf442e0d2dbca4442392cff538eafdfe71738c89bc4dc12b7706e6aa4d1f92872277554c4b9eb7f459dc74fbaaed78fa0dc6ce3a2f1c9ec3bc4e7f12345b0cc32e29ab9f55833babe7789f1f111df6b0c8200abe1e30ca4de3d7db1ae8e8a1037d8fd626f261da9f2ce3f47e9bbc4a3b6ae3a1b3fcf4137bdbe20ac7ba835ddbf0b5f9f42fc1065c6defbeccf28acead8166c4c201ef8cca8ed08fc82cae1e205764bd638af235060523697e72b1b6948d93020fd01077e81360cc77d545484b3344d60abff7099e72688ecf644d8fa88a31f0194823e8848e72c14b7180f98a53cd7ff1570661b19f81c25e2dabc42698e7775d565a7c098c3c99d85c6722cd2bf74d0b07b2ce184a22a50fac55da482a8573bf9d49846e0e179c68e776f2aacf343f593207f3da89333f35eb13a1489783683e6b9727092c9f49bc8cc062a1123de210e7d9d6f964a713c0c0b8ee4b33b43006c397c6d80bf493c3675e62bd792717c16c98806ea7051095c406240a2b2bca49889bc61a74b852a86e62a42a3f8280d2567ff82861a47034cc909bd124320d66409ca8bad2b2a6a01605ed813f631d9542d7f49deeb0f0519a0599904ce803b6473fbc1a6ef2c707621d66d12afc58059e2f34e3534c9d66452a27d1464667a1407d2c8f0e3e88dd2179b60eafd65abbee086e6671ed5fc008009a70bb0027c88eebc1b6210e956a315d323a5bb0841aa0ac337a085a597136620304e098292c1cbc2c14f286152a988d806dff4b301e624037ea91bc4fa44e512d6f6fbab9ad5ee19cef40da12bc5a0d80cc3f0c777f40c9fbb555a69092fef46783489062fc15894b0410a285ce60178be49e6e838d7aa40abce9ae69c7cac117ad0657c8bfe562f4f159acbafb6ddd8ad7ba367ea82fd0cb13ad1124d39651e97658c0e11f01e9f87fbeb0e7f2b15b1f8944b3d81dc020eece15934b2a0da1c80c701b0cbb901d40201c41fc070abcd3d504d10aa080099021c6ef2b22e6cd641f8d6bfd0ae427355b516b4e872e2d6496abb1834927b047022b9e903a1041d5570e3c03acec8dea6d806c1a80381af836ac900c67dc106f7cf005fe7f3f65af7d4a09a1228d546d1ac92fa6820458b87731c1c067905ccdd0e44297848821c2f6162f3725a83a9ecbe7f8a3d892349bb2aac68aa42c21490e1f48bba6cd5726ac6790f1e8f2bce8ecb580d413352951fdfd8548644317a186db54e623e1fa8b0e6d4727dc7cdb8e314ecb0fb6e4729786cbef4aee853fcf1ca5e84b99be389069cfc80ef41cfc058c0ab18f96a410d1893fc86fca58938a5a649445db571e6075afbfe4892f2a6027db6c1d821c329a2344f2f2dc21924cd5bdd04e3b676b6fb7060bc262c3cdb89cd1ec3967d9c194c0f32113ef5456982b1e272c3838faa3d6eff04ab8ed8a0c4c7837dac12ce137f743dc8c7cdc9120ccb6e8e2b3ef928eb6d2b0a11d82e1755f0d2d270c38e7b7128de95ad156d4e560f8e9e73fc1c652b05b16459cefccb18e51d1fa04a57d861713298ce6f9d1f72b7fe04e23cc8cf7c1795f327474b2ee00b0a717ae03ac832081c994e228a77cd8fb235fcce599271f16009e2e51b208a5456f98ca40589a13082454e0c11ba78f76191a921435bb21db067747b7388cf4bd1667e0ec944fcecdc7576472506096f4a275e9b90c7f5e0397792083507a2e6043b29c4636cd6e71b59664eab523d615302866733849d095f0f09fb074225f53f095d68390377b2b9e024f27da2e1f933ebe2abc493ab2bfcecc037309fcff3910d980a809582cf28679269199fa5a9a719380d0eb12be0623b0395286c15a1bc5c72b22122c10f6e9545596ae8e5d2b625c0b3d5f78b2e64f797e81f2912d6afd05fe8569bf749a3863469d33e22580b0b2ab0bc5731b558e3bb8c1d2693b10b5b0424b343eb7d0deb4c720a7dfdaa610d3d4fd7a8dea5cc5f8022ca6f30e4da1c6e6e4618094b14279a6213324a3867d8b8c60349db48861bc7366682e0d152cbf1799a134fdf3a033fcf26e08150f03688dae3b32f0ed2e879673c86afa81f2943f4a901aa5936506171972f2746a2c4896045e79e68d1c4f441bf29135dc83994319f61c390d687d5bc76e808c686b416082cb900d31db1ac6174e97157c0400892141cc9564271a3a882d1f3ebbe12dbb6bbfc7dafa117ff046b42e8194d851aecf92be798924814864d10ccc3e8bad39b63d4c6874f7275be6a1458d21fe0991846833a2e82bd9c94aa585f7e69e3384d3c8421a8dad7a99c975ec44918aa93b4c1f04470d08359c2571eef7435390bc5977a4e0b43caaabe1553e2143f6e728692b8dd7e3920933fa07c66b1488fd3b9e7614ad6e7a929dd4bb091e2d3ad69f989b1465f099be0ceb003ac09cb8022ba2d04daa5b5acd56e2c31c9f816acbcf484f9badb466ca31bcae4fba8673a2179cfab68d87dc66bb8e1df6fdd33ab7837c1bb1acaff34adcb2389a96945b8aaddaabd3a9043ba74501a757efcb74b98a07ecf01718031e8bb3c572eab67257c38a8b09538fca85b888564cec98bfc4285c27ca9a134532020bdee0deb55c6ab58e34cbe9797c38d1ef8242d79330b9e1b8a6a8e4520a715ae0c763ff383156fb2a6e38307eec316c42aa43fe44627497dc5cd9c91b42b556a4d3c8bbf51b15f3ed85f322fb357e81a99d7aa6cf847955fb899e72d5c009a046eef06ff2a1a72d4cfff0019cab3ff76c45311d5a9fdea734dbe4f9cbdc47314f8e4eb45eeded2dc4a4701a13cbb9ba509328bb92b7df2dcc8dc8cd32dea0f061a81da28bd4cba0ae9070ff222deff24f584d61c854572f52d51c99950288d0d18c65e374de92385fbeb886bab36af92f0b1a1efccc3a5f15fb685ab57b18415225895780d4d788e1e02e4ad75ea494c0dc62c8ce3809bc8ae80c546dff17deb1bd28f1afc8645810963cfaf3ff974367ee2e2290d51a9c25c8c2956ff70c48b795132b91a80b85dca90bbfbb3d26b29ae8bc72ebea091b9ce7ccd0a13a2067a5cb29318c561b89c2d8f4c3b0c033f31f39d2d06235654f7c46d9dbb713c9123af36ce4106147c7933d490abe28eebdbd477c2bb21735377eca9fcd0be49d9d8f8b2f5379270e21e71e88a600f799dceaf141ae5d0ab1f4b668041a6152c51c23345dde65934b9a67340c11f79e6dd1706fd83ef906eb166cc28b1054f1e02c0a6b5f0ccb0fc533fdd121331911853cb3e085bedbdb82bdb581274cb766a14388416c8dfb699bf9226c9b3ce026f34c8b04d653f15dc0665a0325e4b039c808628d5d6d5dd2b3b77eb9a71e5e4d3445fd57feed5b684135e8d8c777374dfd2c5245fdeae0c575d903e575b9e9772ba028015d76c60c87b418b8cdd0403966167a3db28286aa2ffb77dba5af27f47d4971af0c62a6a557e9f658370e64d1661658ddd1904b379e56d88cbc4d879abb0f0479f4ceeb19c7a30692567368002cbfb46edb29253fe128191742b39d3b72c766dd10f2a3889a7ca28140c341b0d12b85301dc6cc2221aec5240e8ce9c593f055478bc5fd4e09afed9606016d8220092447668e56a88436272bba4b9e8de2c2205eecbc89a1c19260fdc67d9bfbfa1eea6e7ade90164bb7bc2a36c081509b4b608da0843f41c8a60bae84d5099c06e4ef4a3ac96e5118cb4cb489e1a0326cb9a4b18ecccceb740d0b0e6491e5ee7957c4901b559d4b09c13557eacea7bdf360e82acef55080fc65b5b6ce31236f58a77263bf7e9f5247c4fc41704a2411d5585a336f92893c316f249ca282d3c21838a28f8029303ddf4a1707825fba1449edc034b360726a9a0de5216fb3d08b6fbf768af802f2f52abbfa8c4fd3f33d2d0b884a866bcc5765e0788c9ec22f49e0635f0c672d851e48ffbbde80c108879cd2e9fddfe6ddf6ab29220a621198824ba05bac7f6bb4f8b2b3780d325ae5cdd9b56084c36ec5d936f13dc3825cfe0d08143273ac02288e7fe52809c2e02ca7af94b5a3098594d077295699f6fdf369bd2167b1095e58a68c10b5394f74fb22269b114efa7cd663bfd9dc07a16754054a5bffbe031dbe3f801749773a2e2c6ac743adf7b9503329e61d9a26ce2150e76031621d1daeeb6b79432c99452c504ba047804954f37b0ecc32b54a87dba81d6edbab3bab1fce05a817d184fb87245f5d30d3175bb6c6db43a4f37c4fa65a066ede5d06a5643d78c676cdd383fe590f51b6263871aba6e7642a1240a3551dc9c33a2e6e6d3047bce39599b734e146a57a81c34892d3591e2b5362698966db73b57450824908d18d45ebb03c5577bdbe925859fd6f63db4366629b78d526edbd60ca7b580818179818972bac4e0b498979717162f2d1f83050b162e2c605c466091c212a5328b11969f5394135291cafc9998485313688a998e2a7bfdfa879e6c70b7751c779f0956797b975334bdcb0907edb74e4824822ea7036c0b4612557d1230c1f664c323e0ef72d2b152aa77a624ed3594815053ea8e4f88708044fd6292da1156bbb7e686496a7f03a1ca80555351df6c145392bef922506db8ed911823959fdb1b7fe6acf5c114a9303e95f9f9bf989f9bf8ecc2447d01ab1cc5484dfd546639d9601a4e53ad76e001a416b48cb2b8c069593659502f709a8a9900050f5ead4c050388d6e6719aaa4fb0e407a0d6b6e2345583a0ca1100384d1500256450d48281cb543238643c00b5b22edb6ab893dc6454c99f72b270b1e132550fad6d3bc51e5a9b492893aa4864f93b06518e448d0a1744c986d6a68fd4d68eb88b43dad110bb9c6c784f659567bde210f44f1fe955ffd6dd001d1ffa6d94da434610c524f275e2105cf5eb18a1f2bf3854a3aa856a01d8b8034b2801d4ca543253b4603494b4e52e43b1d40d36372a5b9bee14d017774b39f540d04652c50a45365826826e931ab8361883ab8e71b197d84c8ca626a342dd4aaa48f4a9db33a56310475b8ac56231cd8ae988c9c75444b332934a498eb5c73580a05ffc893f0e2115684c5b82ab7e93ab5bf360da12c47124b8eae7ff25d7965c5b6a97d2ed569c8a4fb9f1157652fa463a52ade143dd6538c6877e5f915850a09f6b4b3108a9763cc2a43212cfeaf8103de1a520584be9312206a900b992d5e91a7f72ac6a2c6aaf3fa3591df632564e0a16a369ef532f2cac4d73716950ed8cfefdb5a1017dd2e4ff6351cdd3a466e8cbcffec055d374aa068deea5e6c6d3c097c24a92ba52584102435d29aeb0c42f09f06515c756486b00419fd9612f47d48b6b5b9aefa454fb83aa57871254a1402691212cf55e8530b8ea8f41587f7b0f6bc8a4bdac7a076135a01f23c1a038a1de4c65bc0b087705e17a904fcc62ffeaec7b521aa2055295bc38a724b892d1b9a1a07f4a9227a5d312cac54642f5732359370a228678a28d804e49308655edb5cc849a9082e81ad5958f2a42fd9c92be53d2d00b0554654ccb906908e2b4f4cc96216f19e2962198a2971f97a496a1961ee9dd1a5577589977e012ca46f4e35e43482f3f2f402d207879b51c79196a41c1cbcf0b514b0fc43975dcd253e57313f47349aaf25d94608b56c12e4bb245a9f44abab845afb02e49a797cfa207e268005eb972a5876b712f9f26419c5307534493b80e0abab059370a228c54982249534555c2205509d37d304a55ce585295df4fd0afdb240645aa06c434f0cbd74eb03af3e55431146be3cf2a36e219fe31df8cb9d129898daa9c3188a36531355640f9e35e2d4355fe07e58c712f66827edaeb25a9f69adaabca6f81848ab2c100e880feaf8a50c8ccce47f0db901103c68c4ccc8b948b16302f2c5c5a280beac46d262d9b323a6c86bfd3dd1101060f6ff09ec10f2455776dbcfe01af58a9fef007bc72e5f9a1ac4057ff1fb07ac73d247a355edf70d79dd0fccca5930dfe0c082184703b21f93bcd515c95ebc6d234954ac576401c971f1e0ef0d184084bede21d1c3ccdccea9bf8fda91cd455e35357ec64e2eac42ebab6960368604a7b5bfd83287555577dc5206410827ef45301e96c37cb3e1cdae3caaec9ae1d9e29a50c4250b94735acecd7f49f07690f48fb68afbf852ba87ff64258082a2091c2526b88132182052dd3f7c907124d0028341c0024faad124fe3143922fe0fdf327547c8ef67f5c76003fa4920a7caf7778da8c2ae17764b68f707c129325b3f7ceb88ece7e3b043ea2249c99d0f151014118ff6fabb1f7504f501fb7fa2d83adb36166f4df5add24ef3e7ff4b9d27a86d7dbac1bdfc3ed9d07c7be50fa76a33bd54edc7556aeabe97ea35c477f91c3bcbc90677ba316b37a59bd209c1a45eb468e1c2452af5e2454c8c8c4c8c182e5ca4522f5ec4c4c8c8ccccc0e89ab03635df3561b522800db6fea5711173b95c4468ecd8e053799f28a91f47348422d42fa7b2f3cb4daa532a64668e31461796a0def90d2b37a20a7fa6ee3f334bd741dd325cac0d7cb837daefcfbd31dddca07e9f25c533206f3ded419faa9a41a2dff6fa1cb621d98622901487f58dd7d05d3db821690f76f736b4bdbe1fa5f2224fe244eda160bd207604eb2e2fe23deed31e54c1ae624450e1c31f9e011f3a1215ba101f55a30abf83ba7ad740db6b7b41876d445c4b2aecee427e0821ec95c9016bf7f1a84f361860a800a847b05ed84eafdabdcb217eb770e5ddc2550e70b38cd29d57e59c84581e0c30ec2ccc53f002bbd02dec42082184ce42eca46a7e26438b6182b1cd7032a718d40b961475d1d262f783ac03532164f1f2c202c6a5458b0b9a6279818a39c970331b0c530c4d46f65325bbc882d3c016da057e81dbf550b05f8ef0349542e15e75018a06d0173c175af818e567a153bd8c18306664625ea45cb4a8fb1b0b6efb06e625cb5e58b47071d192a22f58625032dcf6cd69fb0606b77db36ddf98f6fd33d5ec240b34de42bfb0e2b66fbc95879a33be36feeeafa676e4e8ddddddddddddd1b9bf59cccca71c4292a63dda708a96acbd9a0a7f933b1007c260dd2645f0a9900a12887235290213d8640846400aa18c3e5f2c7777ca9dd07c9a87c279bb0f5faaeec6ccd57d94ab5f66fec684acd48db9a089ea376466f7ccda93df300c41534cc37cf9318c0397b72affebaa6451e57f00d8199f6a4fbe7c1892a012763235b0d4f97b83a5ce8ef5816d7f55bc33e4d7a96df3b718b518b56cd37e99becc48d5d378df84f23fbfffd238956d5f4e8e147593a42432ea3a0102c99109a60aa07c40892a9288708419ec122bac30831fc09c00842853082246a8984294281051c4496b8b48f0041127f041131330697db4a78b80527a58e295c48a2abc008a0f45d821a4e08a269c5812a50a53a0a18ba8fd9bf5a78892b6a892c99c4802b6d45a1d587125a9b5310d807a36c8794768ffe64898c21043b188253f10492eaab6090e0015b55cd5c5a0b54d2eaa784a1525306ab92a86e004ad2dd372647588254b2cb55cd55128e12bb494bfbb0b218c1a34c10d42f7cda4755f2a53c157651f5537e4672a183f7ba9fa0cbe77705d88712fd89c8cc055a350d2f236790537e18a2fa0b0c5400c14e4de0327c4ad5552b6942cb9bbbb635d8ff9a48387fa61a04647edda7857a1f9d5854c519a543c3b41b0d37afc9eb6c30c66a9d4476dedb443ed4cd33a6e6df8d7630e486d3799aca4bcf5fae9efe0b061bdfe7c54aefa6ff743887331081144f718638c9d674368d64c2bde3e4ab62a5fa3c3ea642c560ecf8e1e5258464f8e90927480c0deb009d683bf3ba57eaced58de31d0dab82862d1c08a6808dddd214cedc01e3388d07626d13dc61863fcae8a0e1e6a54c51a87d4a8eaea0d79e31330eb62581b8ea1366b6dba66aadf15c35a85a6396fc16619cc12ce81244c2104aff2e2391781923c3a424a8272245477e0fa7975bdb5f17ea01fc7624fa4927f008920ee8a0d0aed313ac7bd40188b11ed37d8dd65ad8effef5479c75a1b566d1fb59bbb3a717729a38c1e77d59acfe54e018c10caff16c6b323fb1bc25132773bc86e1eaad77e5e6f42280524bc7a7a7e807c7a9ac480d1af5dae223fbf5eff0f21f5878fca942b62eba4e84a3da5935245d0af915a0a744108bb2184707d10b74ae910babb7315ca68dacb4eb466dc139c90c03f669d659c7177776bbf6d4ee597b39bbb79c8d4248ee9c5d4ed34ac399b0d33afa6b38cbd59a3c91fda5e77c7f85e77773b747cafa6bb6364f728a46941c05031e7d4b8a5e5b3009229a468d6f3862a84f065bc813ce4eebe54f7453f7ecdb96e655b1a1c3f8314f9094242a2d47304885f53de7c2c2e720092e981f8680ffe8908f5e731a794cfc37dcae7211f7e0f8f73763ca4a9477b2e38a15028b5473c6ce8f13934a415a99497eaa173ae03815b9d4ed2a11e59230e4a6217fbf00f03f1cb238e6f8f6c308a31c6f8fbcb03eeecf0f08028a0df1ad507c440847e9b04a46fbe5542ed1b1f0f589ddde1d9e1d9e1e1611e6e7538a2b9a4062edd5d4a29a58470bd79811cb1bac32831e02ea3ec7690d085c4938d29a5ec1a66006e378ad786bb6b96b9944213399003f5ab6fbe1e0a027228acbaacf65880a05ffff011ae89fc67ce39736a34cef6a6df5f9611ea271ddb0c34d4e0e119746ac80650001d9e33c38dda0f71d47ee899ea6b74a8fd907aec9a96d337eb191299a669aa5dcab90bfa2659ac1c9e1d3da4183d39428a4b7df3c19e6a0576772369162c4e4fb12bf8471c51bb673083daada4bb1a2ba08d2476fda4e60af46ba556ea1bef689a4adf3492d5e9ca413f8aee31c618214b8611d01d3940f950b2da9b59426d58ee599d75779f43788cce10421c3b70252308476aba5e2fb7a03e1ff5870fce091cc42a5518b5ec8b6d07f232738c9c1520113abac71863ecf534cfabe1692f6e4b34466e862ec421f710dfb6764965c5abaeded11a68ed0f52fb997246e67477e756a6da5d35d7439b6594a652cf62a101cd529b7913b6a8031a63e788901bc6287c597577673ee5d0dc63d4ae1b4b748f10c618636c82fa7f9e338e841181b98c7075a0159f631c13cc07984b890b04adf82f8c4361455c2e2b2e215af1679886aec65fbe7197abc618ee9e14dde322d1189f6d7a48bbfa2bc0defd15e81aa3f42105a343e8eeee7daa81eb54f1f40aee0841fd4f39bcebf524066a0751babbbbf3ecb44dbbd49e400b8b1709c04480ae4d37059c4eda37eb32092a9c11d1639c713af773e3f54cef991e66a637c1d73c8781d5f0a9ddd4710ae9526a9a0d1c6419cca66719776ce8b12fdfd8ca2fe42f0429ecb829e073da7820ed448852edf85d758ed6c96e9bb5b1eadf8eca3eb68d933a6877f7138559af5facd730d6eb8f877dce694073c423481198cfd12aad15578f9c0efff378dcdd63d6edc015fcce451170050835a7470e08581df69c1a1dd7d32ce033ee0c9e953fa7fd8b3578c8a99153635f7303cdceb0eb325c888295f31f1a56454bcdf44da6ad945e2450fb9d7393698a981715c18c9414ed159647857e4ce41cdb01c440afa120202476b5f74207e8c73f3f4776f4cdba5857b0acf8e19a00eb7d8dd0ec7cd0e1d2637477f7e6660e4e814d39a74318238919b1c43f1cc4432e777838c4a494d279f4681c97df9cdf0522c544160a4f33082cce0e1db26c3d4de388fa84d41f4204b05e7c577d3766e0530edfdcd4d1d021801abf4545436b7ebdf82c2a7a522d8daf4795d283310fe204595a5ada946822cb284da5fe59e0eeeb2107bba4f207912b5776d57f8bb3537595bf721c74adb7a52268cd139cd04903324829a38ceeee1b3be749788dd58975f69c71c6eeeece5034726aacce898586dc629cf35bc6d9b1d626861beaef2a3e4a15bdbe813b4e2acaa572a82a53d4b46e21d34f55c7d32bc9bd68f76fdd107a429807ee6e8fec26538dd589b33526201c8210c29e523f162b0a0a9170f00a15333d48d1c86e01d1eb178da10650024979dda332d7c29700a9628049a5a9dc47e5e6e901d7993ea79cd27b6c6c3021e8c9cf5290be71f50859ca590fae5a80807eabe403c8cf0f9b155e299a5f1d19dbc1c3013e844024495496d8c53dac1c201aac676554ac6258826a710cb02bf8b2dbb136f06d4c403fafb2a057133bd8f35747fa2b422152a204997429e3eaec92aa2343dd07c04a334aa9ea66194d753172276919d154020eda15b5cfe6fb43ff2d4a539f74c0a8fe1bcc321eaaa68ad5a76a48d5545de3c9c6d4b4ccab1132753c55745029e79c6c323995589bb9d78bdbedbd64842c8369c29903465e36f4f4fc00f9f41c01619103fab1cb55c486d7d267e180383b9c27b548b239393c1cb05372a05488b449abc44beeee395c0471d895431020a09f9f9ea52525a52fa7763c8e36e99136678786886a7f3945aefa63a73252ddee470e3fd35e4f19bc68ac4ef7f4fc00f9f4b8bbd3581d7ff2c48913279ca83b80879e2780c551c0aee07bab23e8c72ecf355384c64b8a1b3091a2f13c560d1c3840f1604d624748523caf45129e137d80725e82adeddeddddbedee45234067077e9d28b31468f6580d5d17eff009b05811a8109753df5c43231430ceb59f6382084aa8f01aa1add630f5996d4c312b53fea90a49addafcdc70055e51cda33196075ba66567adcddb38cd2548ae5068e045d9d6e293b5f9b2cf39ac94e48eb8c504d6bf9c46374f7fae346b0419391c9c814eb9bcf74646a623232050167a4d0cf0433c14c4ca00969c666d12c32aa4a66d1944b755bb0807e936812cd24330683e81e79ba7fcf0792d5bec11f7e9c337a648f9123bf33d72ce394205ffce2a124ec3de1571113a3988cceaaf1bcede3217ec115fc16019597a8348d3935317466440000a080001316000020100884c2a190503c286a9ae81d14800f689a3e7c521ac923498e0329088220866110020821c418030c50481a34730de576912d14b9cbd9a0176b156079e2156016c8430a33d63a2712126694cca597d8a44ea56f62cc15b801b30514a5964b8ab439db0a06fa6949745a547b116f36c20da6373a07a338fcb2e94c2874e8abd9edf1a65ca74c49430eaf716bbcada5770f12b79b0382ee3a7555d3d0a10ef9b95817c19dc421fe99d2ca76dfdac0143ed856244c59f61a95422d64a1913b09c4d7d22219ed4c8f9764f94870a65f08ba9c1f420977551174538938511cf43d800bfc5f36afc05b85edd54504b8814f95f8550673b084af6a991a1cf7565c69a6beb12144a9241caa9f368d436fa783adc4e155aa55525ace3446cc2aa514276cbcf99b31fd0517561db2d5f09cd9bc893bfd19818118de24a2c3c9d69292205bcd7af35df359705869f7d4561539d9d830b3417f6c7df70063298729759f7c9056d342c7edcebe988b7d17adcd9f5fdc03a1f13a04f56c4de0ab49cc2a212b7c0dc06f05c4603e1b1530de29302778d23e93e6aae0a928b2117b670fc34c18dc1563ec6a75c8902ea54247adaadfa593397c56c0032b61e71314959d8477dfc00cd06b1c47e1449615bc9871ede547ac1967d46d951bf258da8b0d8a73d07ce1ecb63c1dd267d2154a31daec48b42f05d31d279dc8acef2d4439b3c6eee726971a74396ec355097964f1c1a7ba1d7e28ace3e4bfa323c9a7b4786df178a46d65844a0764d661b06dcf9b43d2d9c810a7245feda091cd787bb0690dbbdf717136c11da54c2f1a42bc18fc887ec251559101ab071da2ab680ff30f6488b0dbf1f52e2477f323870a45b80ebeb85426af224b6054f05ccf80ef908c28decf8ef7dd0274a64856dd05c01ed3a991c20002b1249e05c3416b90dbe281fa65b20b16d0cd8cb9333e1bd0f6a3989e6dee8db7c13775df0c7d4e29ae946b8101870824c3f02ea0485b2d9857cae7096c972a12a43297ab8a695a791aacbbccc1698e742c2905753fb83d0d699032ba90fccde94a00c95a93e6b1fb84dc4b3da6677d622f903a2885909e30a2478212f09e995b92157fe44b5dc7cf087c0ac30483a94235da60aee560488f189a37c5337580f6906325bd386ab16f1de470355541c09f90689083317c788cbeb865582cecb7c360f6f726272e9529254f4b0b967b5d324328452385fb012af65a6c15435dc2ccfa4080280d82ea9e24a101c1487ae24b393d1997eb7a17e444ed6e8356b50a8adde8fcb382e2e202348d4ed6a7ffd21ae4d45c2c842f673f4f952f71b78202b1ffb88491fbc2a7ce5f3b15184c6ad5bf50307d6fa25b97fd114b44508f01cf0af8c3018fb8316fb69f9c0bc36801ba1e38b70baab77acf0c8da85d3d7d024fab6fce7f00e10deae01ede4e0178e3326d5b818717c0ec024620b0f1b9bd48ba8ce995174766cd29bd674dda95090b805b4b352d5900bf1b37be6f01422d046ed7d381b8d5b876fc43b83519242454fd35aa20c2a6980ee67483e3c18edcaf594f3cc21b2a91a66c138f3e887356a4e0e6303830912f2a06fb0eea5e13efa610466e060d940d30a9385f00327fb2e04a38943b61635f2090795f066bc17d96f08b60d9f5de119b744cee337f5a537a94a3374899a42e7a9f6ee4c4821ab5bc8328bc371b47993112bf652e02cb8dd8d7b58b5a8824d45fa59d79862c5d861e416d9026b740aeefe6163d1da08ad6521641d8c9569c51bb0d9b538d8d24a6d74d6f4421780675ce06943ac73c086caedbb54d78d4d5ab81001666613fc48a3ecc56c9c44ec489b6290893c30ce5c3283d503c5bef6a30101341661d50a9c11a8369ce82a8693d92aa3e7a24556ce245a665b8098305f7f8ed816c607601e7c843482d7233fbcbb015984e87fa7382dd52689426fa95f6f06b33582b00e6fb2b58ad32377e8043b57e58655251d1925a266007ff8da507d30297325b66876463a3b144b5fab8b6ec7b56b56e2826faed65d1016efc67804864c4dde4213098df4585ca4156f5bcf0d828e88eede03636bf449a9f4d5ec8df2c08ba26fea6aac261864b21c3f066682d96cc64cdeeccbcbd2c0c26c41574aae8890db0db2ae20a986e72769ed7b359b91596ca3ee6ada873f44341d18a3fe50c2263bc28a579cbdb05225a2fd31e93128f10f4e5e6d100855703af73d684784c7548eae4356fec905d6987de5462989e14c391dc11b11b78dc29770a2d2d3dd62efc777e29369cb14cf1a5d9261b92021202ceb3f72da48602e0f2445ddd4e4c938ca01eeef07c32d0400caab7792aeea8991704e4be963faee2cc53e9cd22903daaead83d44c5a5ed4d914d102496f1853d260214e57baf0d532c1066b338637b48fc310caeb2799cdc92aa095028eaf4d92e780c0f5ef338e816600aa7e07d94931a6deeefdba89861967de1e75b12dcfd9ff2d7af1fe72ffedd3cd20b76d4367a5aca8a9be30ce17485f5a56641896495273c9a21a052e38cdedd25953ac9e161ca4f4e15f62113860791e84d000bdbb8e099fb6a6b2b370573ea4045bae78ec4cf7abc10e6fa39712e5bebf8689203e580808d2e853db1b52a31a5763490f4c0cab99e814952b2e2679f637e7773df84cfd3b5dbeb47cf025101586c1b327806abb554225810b71b1cd0afc0ad571906a25af5ab0b6e00c44b4b3ddf1445e8863f6e186618a073d9b1042ffbaf9cb9664fc1b62d083bba9e684299e2cfe94f70dace3bccfda10213562171914e4398ffac514b32f616d1b576cf1083314a0c5f5550e90133a220b3011c45de959a3fc966bfc1e4e1be7762eab1fb2c6b110d243d14232602865871451fadc8933508e46620393528ff6ae49c52b05db91b3ea9921a7f8e72b8a6fb2ab80e30726be52834b836a0800152092e5d661b95816c60651d0f624242ed387759cc867096cc7673cd0de2ed7bd56e54ba6ff78591de8f28a06cb54f6602d2005185f14c01b602d91bcb8a950b68f87303e8f91b55f2229421f9f67d188faa081299f0b68cca0bb9be562d448ac9778d496e221af705979362ead23d5c7ee341a24f9718fb6c69a4fadc930ed85c99a08e0ceb6e0836b5c40f7da969b0a0f418782fb5f32f776e4c28f02f1f5663284861f710d48e279c4ba739142c7e990e119ddaf22da5f6a6dd9adeb81e1c9a00ca146714d9ea46ec204bd3fa5a7fc8c0fd653d2ce3127cc7f035bdd2101afa370f53571a8ac23cdf6417faa5f011b7e84fd33aecae4c70f3435813d69a63874eb7b47eb7365ee65db7b4e5d2672616d078d4a3af037bc70ee82ad092e9dd6bfe2b7e0ce76392146d809f99ddd68cecf51f80cbf8f35d4ad27579bebe7071653a925cd2f4eebef48770a97aea1f33357711c90f39d900c176404042237b9d1c9f6f148205f40752cfdd7299d24629f33ac3eb1360b64b78e0bdb300ea93d591c57e2bc4aead45e77fdcc2ced6133607b9b7cce13346fc62780c94553efa99f58d63987b2008c8c7c41187a36b4cdd840a3a445bf37755e88b7d08f20039e8e07182e76dc037dd9bb9e95e0e4c64bba9941108cfcdc350fb22c0684f636b27802a0ad4831bee1408b6ae8cae87dc9f8eccc8476a6a8e8dfb66bfd138581aee98f1fc96a16b49e1c0986c841dcfbf14e8cc09c89eef873ee6569f348316841b000e9317cf33b8f80f9527ab26f7a0c5fb7eb3f7ae3f054faafbcf8959ae62809934808fda03d36edcac489664fe589be0163a1157cac5691323d195b1e35e1018c08c4de75e26bf1d54c62bc482890341054831011927c14194386763897ec414b805e4d7951e115b43cf581bc5d2fb32360eadadf080748866d7a249888e05ea0002945ed6f243fce26975bf16611b6774a254888afe426267818277a975bcc0dccc73b934b915fcc91685cad605c7c8b2f10a0321cc29202369a92276ca54c6583fb3c52b6bd2f9bbc60ad85b82a9709a24e181338e4d3c684ab27f884bb4c1a0384a6143aced76d7984a6f27115328e7b903a19509f3b876d26a1e97072e32b035d74b72779fcb2022f90c05c3700e1ba7cb257cf70992a02a6d1e93d4c75b3396c0f8616683d742cae9712ad05438c91b59ab6b3a2b3a6ce268ec139e01066c2ace2fc8d041309a83e7e53e17722b4c849f70246993d3743d2ca3f005593e24cbe4542a3cb46986a5220a8412d114aa34a42f7073ba0cd27916d40137e37cf68f9dd4c5d747910cfc71068ee573c4ce007c24b36a58cdd1f0422b56b34535a6aac019efa4eee2ac972da90946f505eaa98eb6ca4f16f0fe2c7b50640a9b3cdbaef60e3fefd21bfd08b0e3a7e8879263346ab633deca92da62d7b130fdb4b7b9f7db868d4bea47b589e61e0368b890b5e1225e167be3ed5ff26a11291702fb604d8050e57b59dd4e450ccd4207c51940ce9de6f54b25bd1bdaad359e42aefebef4aae9f797a90dcc5101859098a27164a622a0e98f17eb91b0f5580c5c0f44e1170d8cac7c7eddcb97bbb10f977f29d8fb888fcc99a2f5cb60e6ceafc252dc7bed8538bb890ccbf3585471daec88df0c8c38dce2439e55e552340e7ff35936a3c68183b5e4309dcc9d8364e0bc555fec90529c368c5bedf9b954c11533a34c6f4ff399e8af475624d5b1cd1f662a4be3fbd0096bbc6cd122e0d688e62b90c72955689dc2f123fb86321e7dc141fc2e28cb12c8d3f970d0494b3cf19044dc86c514403a1c51d1eb82c411db08ebd2953e26352ff56f7a014db6e835dda09e72d485d333f410436a818eaabb61fd62bc0c1fb3e9ef4c716e879c43c6c32880dabc0a12254878f3a4558e8b48739516a41879e284b9aed12695d12750f505196ac1439bbfa4124c72bbd9a540f4af61a8b52993b7fb5a4d5800a40ce9798697712aa0865f67faefc93a59c905da8c51b2af95f8c3a98639eb457729754854ab1fc50367cd1247c58284544084781aab42112a41f8302791d900f3ee27cc56e2b7127ee4e989079c0006cdbe9b6aabe3b258829d736825a183ffa6c4016273bcde64b49d6ad05f2137bb3cf71af59e1866261b27e7120ad811852e7e52fe88beb4176b4f7eb5c24d0ffa4a8c280a788f7aebcb85561e76cf89a6eb8aab200f3881be06934dd767e2bc174c45c3f3c6128c8c83c2aed00c5a18e48d39d03f9ff30cf704f4519d6a1aff40c4510d37a417ba360d10aef101335d349245f19a69a2f8259341f8036f527501033924c20fde5ffbb82d6d13315e387bc9bf80adf62a4d9e00e8919ab09ea7cb8988790db1a4f643e92ceb86997b9b4216f50f6601b07fff628e1e56c955a67fff2f41319f050e2cb72b5cf9ed97fc3a9da657db173b84fa69a3caf92a976a3cfbb594df000f7e5034a046176a52e5dde87962f25e97a0c8ca0cf395e4f352e2f1710b2e65435948fed96355c88a918aedf03efa9dcd81c1e286b2a4be4f027594d824cf860d93c1cef4069285f0fcf9dad5f2e1d1fad1f6224bd468871c8ceb0f1610ada36c395cae6fcb00693b85b3afa11863e893638fe81d5cda331014ab24590ab99fc7f1a8a7c9748ae57255725e31f834211e9fc10062950e7484d3f5a4db8c547f34ba7824f2ba60b413185c0967151713db3e3eebd59bb5c660a82cba7c0f85816130d46a2d89ab00111e407582a1e1cfa5400f860acdad44e22ac4922667175c3ea5930b861a82dddeeaf6cb05534e1d491cb9817741616af551b84df6002bc592c26e89cf5ade96ade7880bc992ded82ee393b169de773a083ee5f0f693ff08be446cd31dad158259a1313e8ad08f618585427bfcbb8fd728a9b809dce70bd006fcd1acb8fd7fa9996ff0d7f1654c2e97242d015f68dcf72fc04e373ba97f5821bad13de197531c287005150de7dba8757c04d8e5666c0419f793e331cb936cc1d7a63203b1e754131c1cb703376c3149ab198d89278f63a1011aae94ef15aaeb647e645d3354f7c1c94c35f255c270ecaee3d0dea0ab73f5527dbf4881ca7f0a1512cd9524b3479db0d44185cc76ca5683ba7c6f8f94576f18f5a22efb70142989baffa0e8a7fda62ac465d9e9f63e052723e0d3cf0af68976bb2fb3966e6de283d8dc74624a80b3a9663267fe6c25621580ff03d40684f65cc03934aa8eab4f6d854ee633f0320a0abad5f1deb278c913739e8dfa6e1a680a3c627ae9e2db12d16c29a53fef2726254d3e3cead627ca1bf9ba236a219811317f53893d85d6171e45774b5a70d4d2347b1a76c3ffe28fc8f5fadbb81edcdeded7216453246bb747657c6d6d77578deb971a51e66c80f3409ce8f93081975ec405528f13ad8d9d164de35f664822552d2bad414acc39f236dd7c5eac84e372dcdb95847e5d21cd3d309063df05da6dcd7f6debc0f8e00c0e52d69476f50a70f21dae80d55a940d58cabeef4100f898f94ec8b02ec3618e2b51f3f0810d1b437b0c9a66e1ae0dc66cfe966cd4defd568f81d82f268b905d88729847bc374d680781d7427197e86e28889d845189a6218575d8b51280f9f75fca3b3c78fd3a5a3aecf337cd958d2b10cf9936f1d14073e7d8f8397ff730e9e8537dadd0bd0022107f136e99e9de431cc7f7f52f2ce794c86ddf15944b0afba2309ba144c858a4ee1941740f93397ebcb5df676c60cdae6e0c7a98f8a40554dbe265084ea74d1a8cc5c5cf25fdefbaf66ae31cfc4b9322aeee17cbf156a19129cfa2ae6834bf4272540364b967eb51c96a1ccc8b97ddc624b2a3bb892912f98fd28657f4849df585030ceea978c0e3541d2754b9342a8cb364ed81f31cba02f39b3949ecd14b413a8782b9982b53117f3e82511bdc25803c6ef950f2d7fc8e77035877666f7e54bcb002dc9d6d4d1311712cfd45d4ce54a568a6178799c45f1d7f908c28bf65ea309adbe24179303e2625e87ac8d4b5785ac8158223e0b24d1db2e7c0a7e7acf138674842e3a4eed4d036633452453be86c307160672e87082d53ca1b03b3d0071ee14d14bb17abc42684d37c9182c1f59639e15afe0dec570878e65f75dc35d74d758c2f1f79785aed626567e0809e5cc90b00ec03116a1418b32a9ac64649e9c413fb0b20bbd7086a71939a113e9b8d7d873f06bc8bf7f606364a1a94acb7f1649c35051fe703748426ffa6130580b777cec48519215807c55d7261cfe41a73f75c7cc0b043a7a2440beba7d1697b9567c2b7852095a440e61f184985dd521db9bd0eb0ec6401b2b8f6e10eacc9fe353f0a4c6a5c5519030db8377f6e02764a45450a41992b03a25a86903469613b26f6f0609a1d7511ff3cfa482b63e2a6e972bab18af929022fe190820e2d16ae514c1e9b8877db5523fa0d525eb331290ee564085d3058b1fd4e9f5bff697218946b7d83b5e622413f05a06d7cc3d3ad5835e9c3c78659371c858c152336888f6d896134deb54e887c24b7c082c848d32dc15b2e524c8c647a12f6512dfa3bbbf0b910dbbf250068a57c231a71a2d64f628d3f7a4cb4a51eef028eaa3d914c93349b45460ba1c38ecf713d52151d73ed7d12b820d65af68cdbb683879fa853ecb8b75bc8c172e9428bd84d58917789de1bd7782ae0d312dec4fab79304b8b3239d8086e2ce7f8737ef928faae737253bd33b0cf578002741e6e35908d6e1d2129d7d9976b6e3b89c1123d641e252806be581cf8354dee3546c85d7fc002742b53984dbe0453035d38863e480a0b5960b5f3d5227ac48f616250441ba8aec32b705ceaedc21192c2d8255ac951f6bcbb8af159cb573355d95bd7077bdd85cda6700249653c470f09e73a8da210321929d22a281b991713667f7ec5331e471184b8073806e79537a3556cbae5832ca1fb5737cde3023a00ccce44131a8086c53c7e984f85c981875a16281b600e8d6152b913c574fd917682681892c6b7b5c00757cb4106451e058a6de3342428f8bee1b05646d0006771f17a5811d270ea98f402bd67cacff782243ed9c43dab80a434c113ce1351506c94e0e313aa6ec7973b4b3ae87fee1851b4b7452bc35602b59437835b3e1d136d6a40e8429b6b621c8b7707656afd13a62e0cd88ec2a22ca511e901e989995ce2aab4f38e8e5d86ae754a93d0f4f2c5a98cc58521b67e6140cde46f31d2720b1c940ef3d5648823ed1b53c080eb6e5dc63275774dde2aeb0c78b1e0dbf9a4d72c5f29ed5f77433ce68908355387c745b2829c42a4e8022fb1f232a7822dd066987e649e16e481b28a66f5939a5ad0fff2f59ca6786bb3aa15f8dcd9fb25852d73ef51973caf5311b2a489051d8af68e653939c6f2daa4a418a7197ecdcdf831d2ba4add435285a67e6db49423dba0c3dc4ccb5836f83c7d9705ec75b4f019bfb1dabe622b7a0a73242b6ff39e408bc5f946937d18760fc4a9a082184c2c5183d3f9a6e81f071a96242d6b0cad214b1aae4a3a06cc0f0cf4d287b5d50feea27153de3bd1c3b2ece08790ee74de111376d51bdf641acb0ecbc75bc735d1427d8d3be1f9350185849d781537e22673fbfdd6eece35a9a22cdb9bcc98a903d53f3abd2eab55e68ff8c8d5fbcd28f4e212582ba17547a6835734decbb1bdf54122509ee113e481e48a1ec1874257c7331559b2945db1e09c58f50d0dcaa80fb82748b79d5a18de4bb71174d3dfa1f5c18a3877f543374a95a74c56de223a795354146dd9814322b6b6b520c6e630de588fabfcb6b51a58fef58b37e5aaa486dc683cc6e7fe707b173da9b723b84bfa8683671cac0e22fa79fa076f02d0ef3757aa4820d66c4d49a0b227b585c6ef29e1e551c186294ff4a46d5e36a32081536aedae4b8177bb0806424a1795ba948d019da57ead7985825a588b171aee1231bf46612f34906dbb97f2c0636204d1b9cccda743e7837e9eef6a4ec04c4765792061fc33226ca3b9ce275add9f746e5e04a4ce8a9992760bd19516b64a9b6abf7d5838ce160e68fb3be6c84d02203e7752c41eb827a021bb3f44a64c34c6157f9086429c46f7e1a2da7e8d67ff0b1815db9b50fc0134202aba0af5bef94abfa2dacadc6adad97d9032e4567d1fdf2a6db5a96bcab6825ad03633b53a073ad332ea121268881bc162245acef4f500ca069199a61c1b235cc8c322fe1ee03726e9d8dabbe35212850014f0067356c84c54cf92b8298064a5dd034375a1bbaa4058b7f8c2da95b6b8604313e08a05cfded9b549239ca71a50b1126f3c700eb49d4884fca590519a8328e94f803cbf6cf54e4a209db8877c308eb94e2b596cd037bd0ceaa63773859658ede708eba86977d2ec706f26047a54ceb397328b31204e82029830a3edc1e8d05919d6594ad6794bc940ddcd930034b6df1ff9e8020223680c15d2e216d289961aa4ec4e7e7eb7204405ae2628d57ed8a680eaae32f199b655179d016ccd8143d7581140523e6b3a8f8948b7db2a88a31c28c859c0ca375a76b5d653e84ec9ef10be6dcfe1da4be9f26cb1690d96ea8bf60d851fd435d66ef8bb2c0a12d26d1f3527dc9b03fc8043f832ec93fee9fbb56ebe4bf9f04c6c6f49d92bba5f52bad469fed90ad05754707f292064bb1b590a05847973baa27f3189eef28ac9f24358e6db979dc1a8c2106e9c966c85a2c61d421b717244b6017a43869ecf8221d9459504db861dab023f36c97e197b1dfb2ade30656af57527907fce8c4e8e452194d1c206cc6387fc48f8b8dd6039aebe032b8786172db00e6025187f0127a7e80d3d25113a98303148ea3948a98e5d9dac38f6e04d9a2dc1e2873f6fbfc1d43a7b264d5567a0bcb76727a0012b88529ad1c9510891998255e2c25b8ceb8bff09782b873d605b3ba3af40ee9d1a7cd01b87122de29187cc3e865d3258c63ce52bcb6136e1499d8bd2bfab50202d62542a3bddff6b2746784355d592d9217013e2198523278979e4621c1a8cf4c1be27e46be2008d6d69609e21be645048abb642d9ff9ac8b031b5196e0ed61d6966443ffe6788d621c724d082b137f9403f9867bfdb792825b6f3f17b6a44ab655cd8c1c2d09af92561ee9f5788db9ae76e354444c7f1e9375d05e681708ee52b959cd624e76ff8bff431d05133738ef600d7eaaf162893f34c979480434e2eeb41506939030d9093fb6104b6f79519997f92140b600cf6537f9546da687024a0135497199207e64dc904a0489a3d8948638ddb0d8f261b2ff226f1c14b00b526ac77733076d019e718926e9169c1a80a0962af29d492493c2813d78f0c1dc16000a4117ff07c814500d604441fc13097315cf83507645a62a921efa810e9a25c0332d7a9e1365689a3aed987202a613dabd44b9d6392123bb8774f5993ddf17075c28bde4ff7760a07309d567df9b741cf1450d802e53f754445a373f014faee1589e0fe2e71c3da7d5a51c7b65f801266e446a3ee39cbc05d26cb899adde6a91376bf6223284036ca15aaa928dc110a6980558e10413d4f483eb29fd3ec58b0549ea1af52a3f127d1f0d824248b88cc80db20489494545de0ec78d2e6af7a25bd187af8c81531ea895362c3d026f02da324f2dd17fa6b788444416e06945ad926ccc1011817426eb51915119666a63f22fb8881565f0dc976df4e107ecb691308bb5318a81d9e966a17485ff12df76840e6b1121871e67915777f12162091b41a7bae51b0869812dd4227eb409a6fae3235b064956b715cae8dd45d179905c8763abf797406fd67baa03554d7b1cf1992d1bf91ea2e218ba61debe7da0bfc293c5d93202984f46990e0c6348b3b10fc72e8498df31f0ebf8704c5319503a7da75e95190632ca9bcee9c065c89743d6d4692122afce00001bdb2b9c45e0803810dbc4c824af9d24c86afea17298d6018cc54144106a152d6ed0d68823c077d77fc13afc1e540896f89480e8c0124503feb387d1aadb93fb10c1a271eada07a3ab6a9b2dd83ab6851175c08e5f1df3580de7612f17823152cfdd6d9f7b85b36a98a543d2bd2e9694dce1f5135863e208be3ea6177a8329f6274e72eefa2918b9015bf810d14e5673ad4f48d806609a0938e402afc39d6e7876127337bd955ef6ede26feed4d207e2346c0b32ebe1eb6c558f7fab062c02284de633eb3bb6790815a07a9db645ed407132ffef37b1a50c47858a893c372b8203f9d072c87e758e08f13b232ebc1fafc5eef9053a954e3c1280c071008f0425fc0100c5ad207aa6742180952ae532f16c50dc124f4a95c3ab82b84a2bde308a7b3b4c7787a2c15f4e1734006e3bbe9e9d781c4ee6e9173c80949c02e295233d85992e607384f254228487733c0080421bc050692ca084f1f85a9e42168c18f6f8e4023d041efaa7b295092199fd21c9a5c74c854502df06ff805bb5b6bdae341dc60c7da07ec26c9699d0e7d4b63b422441c7da9b5d6c29ec449cdebf4792615d687c027aee099e7bfeb917c0bdba601f1d4e6ced630103d314348868ebf90e4b046eb5163040cae23ba045a2f1119b18951b22cbc09c70b36e558bccf74f3c5f6c066aa62e78cb18ef9ff9c9629852920290ad633b3352e75656194fabfef8ea9aec608c9bc7956e305f6746b9b4eb7703fa8e54d6df80588ee425c7c1cad46f0a395b2b04101f30f97a060bfe93331bfd3dee205589179e41360dc1b3121f2453d9eaa297b9e4f081681a1f5a19f82cc357f3df81fef9e3ab138a2529c66f6e2815270964513046d4c2dea2b0e42d9b111f994425fd610741ca395019dd06f5b5b8054b7ad3de72ddc5e2dfaa4f64466d5b48270be8819f05b58e23c5d58be07fec2527d8342a2a3df91e1626eda816b0a649317698456b408b5eddc7992fe4f3a2f3f8f0aa5a37f0e316a3e5ff84a83299c2793657535c808eb405ba79d7a3a767b0300fb81210f1c9da48311b436439cc6dab7a49ffd94137e0d5c2d3f58de12ebc92663234f75694358a68c0355cbf27b75dff2b4c37732e53c0e6c22202c82b08fa20d2e8ea743d3b1dee60e61da1357113f1fa18f9ded24c56319f0037bd4c496141932af1847ad9418c00ddeaf7fb34ffe59b83b38f83130c30f9ef8a29e12fdbe5591a64dd5be0021a4b5b0eb4280ef579cf49952b3e19f73cdeab80c756adfe5c945fd759f60fdd4ea838cf7b3611bd7b79ff9a5d160b9cec387debfb87f68f36a4aa150b3c864e7b0d57dcd33488e7b2df9a42d7d46da66c4c5d6bd25f0bae62e25ba43136fc72ef7d1334841b2e958f8c0667501e61677a1ef4384aa9bc7ca21493ce9e53d161134131e8111417551a6b73cac21559401b80e82f92a746972d4d5c5437375ea6e741eb3bbdaf440695c304424c9c98634c781d03b38b0f9668fc9ea2d8b5d9852a95957b07686a1eb0a0950a2a48ed32be04786cdf4a4633cfcf0bfa3d14e4f5fd2171e60ceee7e507d8a462a540c592599fe8480329b6e35a699ca5a8101853937dd24a952701f14e2b5c3b2bc47cc26bb5092969ecf387c59d113558faa029ee22c4c11de06e0d596045f9dc84028eac861140137c3d7818f347249fdd2eb44254ceb54968f79a682ebada217da25d39f9d70448885339ec650d4056d1705dcb904f1af0f122ca3870208f324daf1cfb33c3ce5ff5ef224556f92d9ae757346505c639ef78698b5a02a327e7279025c330d43b96a5dcd94de2fb4c0fef0441e784859ddc34f57493492d85ffb9c50784a6bbdcb10934ed576cdcef794d3bc8815386fe34b65347fa45340c5c4a209aa235922191fa149d977cf51e1e67996979cde23e843095d0247ebf6e5a83bcdfa44fd1705fc376d66816111ac9591859f255dbeaed94a031ac64ba81f1f3b64c4d021f033ce3acdae77ce49d2fb04d8dc9c7f86fabe7d421024957704380b5e046d3089c16e7ebab9fb3a01ff0fb2461bee8c4cd13b354a3416fb9485a3a0fc801f7b484c6bf8b2089146073eaa7808403e078174b313a236aaa525c4479598055ab10088c044e3391c54127dccb735fd1d5389abe1379d86eb43bd9a11ac6983b99faa98def0b9d8db78939e74155cf1f16ac6bd0a4ea61b2de1a0e9ca75fad2e93ea7d15c488096d151eb64c3e8f17f28e262fc69fb757c5eef6696aebbb4bc4449d8cda19b7b81ad96738a83f9c8395f895e7c1c1f10739e350f91c84e26316517c6cdab9839676060cca43ad06c85f88b34b34cd4df4d6be06b5061bb569eab837d2e8513a7452fdd25635c3ac734664109a77f7e6466226d3b9736770768d6fe70b80c7883c9ad9c9d41945a0064ac336450dcb3bed913992dbcd492d105acfd165234eebb77dff6dfe56fb5bdddfb4f67fad40fbf918e1a4a5558126eaad24d546a89ae8a393ee7611aa12184c2cc8d6cf06edcbe5dc8969899b95960e2c749f226b43aef66fb5bfe9fa6deb6f9bdfeafe56fb37addf76fdb6f95bed6f75d9affdef3ac4e0365c78c9a1011b0fdcda64f640626cd60f03a7ee6d1695bb23884aec1ea4b1872c619c63e66428f54168e839893d861883dc5215012da67825054b3eb441bb019b2df030eed6fb2a73ea343e93b96550a22ef744f5101860396ee4abe69b552ab2d695103870431c0436c8813f8203f145ecc21a094e4e129c94e5eca7a83a1a42134c2dc4402c7457c000175a6f0921c838840bae5d03cec59cc542b734d630878d4724f48663635261d16ebd57c238b8cf4a28565d77b18de1a0c4c88f311ad8cd910cad511f8b09d82783ad66cebedad83e3c09ab0661c330882df31a99c4dcaf5603db1e9071db2100b61d0013e7e00b9cb2d69300bd31d45c41f47cbd2841f8670de3333ec2aba2c82192e000a4886722d7906c7f3bd1837326f101a38111a16a05e9c9fcecdf894de83a3ba01a0eb6ea94950e946a69350c344b02c0936d8dec7c858e10eb628571f5e3ef3e7947ff867fd5779800a1498cce95a8d75c54d3575426c4787bb52aa1b443da57292f886e49e74cdda32326aaf6aa7d8a5173ccbb8be839aa395b651c1187a8870753740348ac0ef01a2d826f74105e8628aac88eadb829afd47bacc3d1b8e23d0880019d024032e8409f185381f064b062c5ee18e81b11bc9d219f6e1f5c1c14165cfdf787498143471085a0e134f8baa4be14e895ef4952274935d7d7c35a7cfb9cd5b46ebcb3b007d1496afc722e69d07518f79f44b021d98944532dc6639c82a0594e0e927f7553376a5c5aa46fac6c06ce5c4db42d1b7376fa441a19049c6bcd3270853f2f5f759e1dafa78bb04a5019ff5a561824203f1abbd7a3e553f7346df33fba9186158cb8c720169aaa230484c71b4e83bc7f9883f629acc910f6ec58156ad8495841d3023108102ba5c85f7ab3dedc86d1753e184d30a1571e0d3e9090fc88036f9cfa001ae4256fa1c45c4d31aae3ec942d2807843e44d446de916f3c7fb08c1b25df1b539a8a3651af31d1ff2fc9ce7352f260e56e6033ec751ade8d014dff02edf9f4f3fe22d7889cd8724ed3ef3539111c4a932a706a1c54af9af0ae9e5b25d3d77f92092a8764a2bf86a4a162455da5b4ca36667df4f99f8e2e4139481511415bb1dba9036374759beb7f52752e478f83857ae99f34b86e1581457bb9481d0a11aa3a648a30bd34300eae48e09b6811731aa0bfd23700830a76eb86fb09126a9823f816655209da3a14e1b784ea7a16f011865c17e56e83d4a8bc1aea95ccec18b7d6e3ee70b2600e4f0add0b886281c6a7f0b0add3ee3147db007e70dba154c26e3b7375badae531a2e3748fef955e6bd34d35784869a468a1298ac4671dcb3bf1ac33c4c47262423c37da69d3c1df7a14f1ab5bb160d507dcada05f87cec75ae55919f8888352f69eb1e4d87c4e5a9ecc44e60e080b97c77bf88a97171e8b83c97bcbdff31fb2cc7b76a59f3c40688bce92fd2ab0bf610b1667009bf2a7f4932e3729d3685725c59fe710ae4bae0416ce57c562e04913552b1b4b4e9ba203b80c2f90111559de35a259f180de14ffdad408c4e72101322287a30f847703024e4f406041480282dfa4c61e16dc886f2a23b6afde0d35113176532dae8fdd91a494b0795e3f4804947e66a45ba1a2168040c1d946e92e3a76f4bc97f89ad0c181f9d951c1885639b22d0f602369625c9bc06c295c502f88d750fe22d15e3ce3d32a98fa6902fc651540e69bf69128f6a8a0e3946834d08eaadf4d4f6599e07843a29c2864376aaa69a5bfe309fce54dda128f02add17a0ca2656476fb052395595a1a2e8555b8bcb6eed8ef56a540210c1e57070ad3d8008e531da2e4a95221c9dfa7d9a1b3a6cb309d98e934e25f6caf79cb4b6da88c39a79fc17dac53cd94dbc447686acf001d52ca7102274365c9f80057e3d18ee92797053d2abb0a2adc9ccaf9295842125631673a1ba001db8d89311512daa1011bd4955b5407cd27043c46c6f3333a6df6c4c2e3b22cb496656198d1f9a1e7891610e2175a8909d8f73093a95b4d9acb46e73c2cc229f8d5b569a3f37f3015d2d9d99d62bc45027cf042f4297d6d3dbbbed54345f52673212f24feaf44fe0ebb1e44276199dc07c9f08e7c5db085d6a9fe1392e135ac0b16d9ed5cbf5d1bb0ae3d0856ef34b3692712bf5e8612f804d9d3d65e54e6b27c6aec766962c6a52d9096b0e8e279511aafbc647a5ad70866aeef2f035710405cdd51117a086f03ed14b92845f91b41b7f4cf7e4cf4e808804d86dd0ad4810aad07cbdfa4d6790b5b9e838762d7007612a01f183b8a8fed105eae48d10629cf072e2ce9bae5bc4178e3869d01fc6ccb8ef0600379150c46fc68201e0cd4eef1eb069f864bbc7b1dafc289ffaec5e9d1405aa48e500d2b85922246a8b5d74eb1b40a2b58bb981f5910e47d98fefb59518215ac4abc4a70a0eae9d2a72607512d4cbf2eef435dc7fd57f9072b3ff0634a73f69a342d30cde4407d0e03b6263d7fb050cdfc393c965a313eb847b3f09786377c454655d9d0233f150fa71b6ea0c397b4baec897d6dfd5092c591f2cd60c52c00ba9108a8279712a8a7eb5fec9cd299999e241abe8023422175609514a6ac749595f03fa48838ecfdcd4680dbb81f78044e9b1d69018ab88d24905d101ab0b570f6f72aec5c3fd9a225f281c44c36a9d3000048522f5cab3d48532b1fe41ebc1f24ea81a84cb11cad6cf73918a6dbcc185f2f2ff53202b89bb9847678514a24a6fd4439b0bb6d9ca9265e928705124f9b6fd4cb55c4eecb8b2a26dc82e12abfb77161ed6fb11b8f08c3260ee094a60b7afc4fe11c99eef528d6bab0fcd7ee0dc0a1caf48c3bf07a27c16bf72a4983e57732a0649caf644b9905ed48ec267c5ec93b2c7e85aaee92ff5f78fbade401b27744e9d83a6d10ad3418807c81b9b22c2ae91134328eafe0fc0cb8c2b260d83ce6ec51a5580edb8983d0060710945b988b6045176df65258831cd87a20ea510521b62547cf15251d525e38876485cb713bd437b3a61da0ede2a32aa46ebbb0570fc6f4b8abc0847cad1abb809276b8cadddb9339df24100e9fbfaa2a31664d7855b52f464fc861a97fe5b704eb340a4be06ddb3c6ffcac2bb42054b74e417c83658a5a43d12cf138ed58d8aba5e248ae85317d4d1bcc943520fd824a0f10aa157c01ec0aca9da05041b82902c1600f1ac10242b095a2ed8af0dd8594b50e39200fb150e2401d2406b02e0303d12137a8b11eb211c832b06c53871820129a50a147f74ea4c3cae9c62871bec082fd8906bbfedfd5996a4a1d36294f28d941433ff1e2d163c62e16d0cc5df34d0c358002bc9a2c0e3dd871a8b5bdc5c03045d5dcbf733fecb84a0ac1c18cbef9d787a21d7217a84c328de6bf57fe141aabfa091a6966e9b11cdc5bfa7e7d7a5d3b04edacc417716680212e69e85f94ccf4ea5f656961ae396760a9da1a1c45de742915aa05b8bb8010477435ba60093392f43d4adc635c0497c4ebde960aa47a4ca384227af57d43008d7461fb4fa163156e841661a5c71d52320d2bba3013d2b9d41d582dec70ed44626bdf845a87631e70225269947a3363c6b0a52329d808de7706942f2b348d0901250f901de4feb156ccfc87039d40c53e379daafddb206fb0f17637aa95dbd5b7e1e0794fbe997adb35450d7bef1f76a4cf0934e3610f031df15b3e6f7aac85cbb212f035b35c15643fea561c8daef4a293bc6277df95340415498b6634833617bffbf137c109bad7778030a314227efab112dd5905302893f294292a4d7e5ff0233b0e46704c02eac838a489496ce9c4bb2f11289c40016542334237764423d0d969e82cfc7a87f2e4c61ade339d3d6a0a2c0b0e9afc74a0bed3fdaf2203f395ba8d53b0f9030227dbbc00e8550ef38f6c2c3d512ba1b674a0d75c6911815af01b8227d1002d3ac32c49528596c7d2537782b87c6efb7d46aa0d3fcd24392f38f356154195c56a47331209e6f058402249b1df8e81ce734a703d99fe814e4420dd6c3854cb7dbe6a57eab169c863e9bb6dfaeff245e3b67621d700f42cfea21c1440d81bfeca1f008fa1b6bdcb65a49cf8ec8f3f97eae7c44cb4d86d16200368e5269a070048ed0fec403a215599648e5a9738fc7c6718452615ef4114345ca3e777601429f6f7157a967bf32f6c25d2286c9de2290b2f678759a0df12fcec002b0cc18e37f7078aec6420150f68f1861ed8c5983f035aab50163106726ac71ec46f1ff12859feb151cfddf9e3163c533c3d087190061bc6fe0dd49e5f59c35cf282f4b889e6d1350a1bbd0250b403e2b9b10b31ddd7e93fafc56b157b54a632550308df98f14051549aa779f64c784880d2145049a2c160ac4fc08791df6c655240ca1443df18c8ded7fdba81c34c00f7ce722ad5164dd8e3cd6cb0c2bfcc30510baa00c9b444589aadcfcfef5d00bb36fa5ccb732bf5b85f6ef3f536555b19c386e817737a580159137976783618e3ad119ef92718e6510a591674364bd7cb7109899f9bad86fd71d1804dd6aae54dc49d98dc9b62eefcbf8493fd31ae274c1ff4c08521baf19d6cb7664f4932e42ea9d698118122433b3feba0895de2d2a82c7b109f8fb3283ad680346590c2feff5e690eca4df0be81be3af3c55918cf699a6a37268e7e0858bc59683a40cccc50cfcfd0c08ede2301bc8e9634fa699678c143bc73d4a0dfec4d67f445945b45c050019562e2a366bc5de65d530e2d19dd4b1d2fb516dacab4abb305456c4c7daae29a4b3b455784be64c1fb840c24fd4aea1e1b11ba4d8531a44a8f9b334b07b68c262a95788c0fa3c04cc39d1193c9f8a484abc8c04cd6bcd9a0ef5c9ee932f1b1483769732461a5f702d725ac76464e41172e914a29e8a43eac2c3ffc98ab100c72bd74b8c1ba2f8c4c2899bf5821cd9c4d106032371024047c24040a2317a05b3054b24a0799e92cb0b8a3897b817ddd2944e71fda97e6d155eca77fc2f5426ab874ed93cebc20428697c756a1f307aff1f3e3e48c0f00c268cc0974138e5185aa16a835c060287f972b630349f5ff7f49c8de7b6fb9a54c324919c209e209f509dba54dcc920e917c38fa7a8dc0a74ffdf422d333df260b3ebcfa515d731fd5354a1de8332ff5d5c35e5c1ce340028525f90f138281e70bd56347a4abd78b614d86b08b7209d16b67f8cf88eaa537eac527d860cdc7153d466dd48151276c83511ff121bca198c31bcc3f89bd401d986f329658aed64fe503f5f25217bc19621b77d020a00eccb10bc01b98c79c09666146f006731f76310b73ead1261d0cb34589a40d765d969d061a80c4afee033e751f7066813cf031a740409e766c5a790ca8e9b13a8da87b15d592457a8c62cfb9e456258d329d0fd4f3b5f006f3118cb0f23ffbd5f94775f81cb330ce2575a80bda605e2be77accf55c11d6b4727dfb3682119675a833763727dfdb10bcd9362ddb138d11e451e1dbe50dc2b2cbf9349dc2b04e4adf6e83ed098ba0ef6d8b6fff38a1ef2478d35158e9dfe6f46daf6f23024ad436046fda695097d49955a890d4a1713ad92a49ffd1984e52677baa4e2fd016bd9b93b431618afda8d06f4edf4e13fda342dfbe0d718e5ccd18d05443a74dac2344da50a707c4f73c30ac0fe1eeea87fc18c0ac9f1f77f44f8721eec87c4e2d36490d411ed8c44f9f3ec30d5247c6278e8c3ec01d41a28ee9133ae11041f1c34fce0a759acd398e522efec65969c2710a32b3f8e893067df4f9f41342f17332c95479caf4d12918da01309758580cf3a0bcbc5c19a4cd9c9e02917d711897e133ae848ccbf021322e4366888ccfdc1f973673a6a69d2f9e72222f7785f98b03b5524e0426f5e22ff707e5d6815a36758f6e127b51d7a346481fbda34b1f5d6261e95d518735b8b0d9a54f510735fae8980ccc6a77aa9c55b141ff60809867fe41c16e50769128115d8922468c387b74c095e1b2277360d93f9739b0b30617961d4a965d1f69834364e9e64a0cd13cf3ec6eae75639e39117a57337322f5aee69d3eef10ec873ae6402d2cbbf526c1e86df994c5a94948083e262424242424c4595e3a3bbd746eea999920a08dec3be32ac104f643cd30410d71ce37c3e4a510e7b48b732a6a09e77cddd14bef192671072a48428e8fb5e65de212aa4221b061647bc52b229857c7bcde4884bae6d4b5bb02c27e2f472111cde9c541091c6aa58e5d185711c332c7885c1cb26baf531b29b08e83c362d93082b1fbc177f583959a5879a097154269d34ebd1e0fe8e1037e8437cc0d21134dd2f22cc49f1da3843c50eaa0e59de08d44b9325410d046b2807abe28d793fd665c8f72cd081177a084a28e99269cf37593f39e2cca157734e11cc8514e8712670ee6a43ee3f4797f80aa03b522e6d587605eb10834826dba9c4b9c33a9709e184ecf7ec311158e844c4fec079d8ea0be76b1d3674b7a577978c52f5179b8c42ce8b40633399cd80f45e36db1abcaacf89ccfb8a40eca056da4d73ae362940be57a19a713c97c3a0e945bdc21bd641c5a3a11ac5e289bbeaeca4369635d2f77801d916ecdfb83a435dd87e7b54d98258750ae12b058e81fca5584dab4ac52ff761e4b629be8543efa165d8b9e458fd1b1fbb1e853d411bbfc37b37cf40f0b9a4cb3695a6156ec60c0829e4160e37f95bb5892222c0a1584053d7b09586cf40f1584924a12fef625d1e474440f57968800e2ca900e436009d242084b5a585e41ae10255d091281d51e264d51c414b63e4c9a4203419a9e643c4cb20118df0f939a8a5210219c73ce597b0a1bbde79c937960c1135a1369d0e5500b49e9249b24927cb54a4569236d1ff8d6410e48c6805978a0f60b5e7a64a24a9b7c2b5fd246be7a78f54bea4c26eea2e736fa792474d4aea31e62923af3f56a7a39cd2069c35e91ecd2917ca9aaf45223a954d6cafa1f922326957627537c21613a3a3a3a7a0e0a7a513a5fb24e97336806cd201feacda452592be9fd64f8795946a6415e54968dd5f550072eba78297dbbc1228397d2b55a3b47fa10cfbe0233334711458de481eb250f74f0495c8c600ba767598b3d11841516204501c5113f5c8e8cb0424b131e88d2c23ee0849386753d64effcc759b912c51631891346dfbd6c9f5d8f8e36ff71505839da41109ebdad952f18821b610754683ed0031655827ee0c3095a43a49452042fb597524ad95226ede0045c6d4a0335b8d88e396260a39412494a49d4dd4cc826f6986563e2f3360108cb8a4dcc7ac1d7c05205f0867d9346f0e6ca224964549fd9ebaa3d3acf58b5d7c0ffb158ca2e2dc42cb9d404121f75921c382624b1b149d66a6dd3b3cfa03a46fc2dd54484d128be5443d62594b5cb50e1920fd481d0a10e0b879923e51a5cacecf172bffe17daed304ebdbb3b22c9c425991b9180e8199771497dc6619c7a289799f13a9799f13897f1fc379799f1accbcc7829979991811b8c973985f1aa530ae34da7301e3bed86f134a7dd31b75f607ce48b37c35baf86f8327ee065cce165161f6ce2f36810049657d00f4fc0c00932c1234ae795ce411cc441481189858298254d00c27ed1296a894e318904362e45a412beb03126c64cb1d98d59d846ba94fe05e0e3e59935b8583621a98986f8f14ae761b19f2c92452ebc7c77ecda31a397de9e90d8246da4b7012b8db02b8b4a80818dfe49c8037558b20052361bb1a44ebc52002e2f1d081ca55b0bb3643ff56da7a6976e4212fbc9a222593483343021fcad35e7aad5d8c253c7b0235686a742349fb57acca026a710d537ea6d3f40adcdbf2a6413c2cd49c4bac432df380f87cd7f3a6f4564c3a1c3a1f3cd6337a4cb309f98f5aab4a98e09e1ee0f508b336221dbfd8942380cc38648973a5b02ac6ff7a7737bab0dd89094a3a417944a80f4cd6d13db90f370e01c1527d68fc50c49ca3b8747d8874d199ece30bde898075fab9f55a61c94ba4ab0a32e0edd0bdd5d0de1ee8ac8e6d2b73a6473eefe6c1885ade9d920b9257a0096235619f66fed18977d0c785a318cbba11e793ac353c738af34c848039b9e616f99d8afbf2b867dd4cb30179866bea21e9d76be55af08e6dfe6d5336f05042b4294794536c73c763f36c76ee77dfd5874cee3a8718f2c9cb2307a76ceee97d523ec5f8cae459216aec7f130290ba48f9d0b9c63f7db9cbbcdacee7e36c8ce0576eaecf487035c908eb955621b7691ceb52a8db06ff57e4d6bd6353bf2d486a75e69f899409529ad4cd901ecda2d529dded50f7a574030978eb9ec56c75abc1efa86fdc0bcde0f32ab529fcd25519bbb6347666666016b4e4ae9a47462dd4d29362785526b55d59a016dc596ed0cb8a3aa204f7b8d3b688056eac4e045151f2a9bbb6364d657652c33f33da2e2c1d2bbc28582e9e0e0b072bca258fbc9c848e963630338355689c990353f24736240d42c519f186358ac21c222d710d51471ce578394440d1124923044af79110c91b439aace5e74f61aa26aad8a61340fb2d837efc60d10159ebd8648ea70354491086e2a681f10bd5034676f5e8dab59e2c11416dcb0c3185dfe8bc01863746129a564e588dcb30bb69c0367cf49930234badf6a8cb0fd66c3b3dfbcfadbc57e2381fe56337fbbb1e190bf01807fb301008b859217f360ab67cbc9746936953cbbbb79ca49e7a4146339f9c2cb30a0419689259b5282f042931284185915ef0454849085890d2a2086069e5c2085131642489a22440f42a030106441449024c612cfdef5e56192184588c101d80d5dc239e19c734e6fd8ed4566dbda031a2f330bd8ae8f79ed84c3453e104328045dc0a8a24b0fc4e892c552172b8ce8b2d405e989071e9ebef042881594bcbeb862081f8abea022b48290d117525c2bf85065cbccc2ca20e1c4600546501981b685ca6b7e91fd808a10555505931fb66d76cf49eba4f4768d64a60e21e6957358ccaa396e0d4be6ce61960cb1a83d45963de9eca658ed9a499adf3c729c93d230d4716993c2f7bc4fea7de00d1336eaf858eacc2aecfacc0879bab52dfab48f0ff5e9ae6c5f64e1f8131ee8eb6fb3a3d87a57f4510ff41b9d4d81628c4f6c9bf7ad7264fd04fc56dc673046b16d53ca8e31c6eb6ee359b38699650e29a564296bec1338b3aa07dd90639e2d3fa0879b9414edb84d7b999bb669dbb6715ad723db5eb8c65a6a4b5e2133864520d3b616d49a6990d58eaae12585acd620f0d2e3cceea4df1378197bcc29e551e782c8b227c56aa66d5c874ad18edbb4947d9935dbb2ba6d9cf6f3d230315c0aafc1b064e5601d1c66085beb7a4c67815f1545fbc754e69134d626ac3736bbc21f73625d8f49bb1ffd10a3282d2ce8d4b2cb11323d9bbe1a1d679be860c8a0d321f393c6cf9a9f6050f929839fd3ed067ebaea033fc3d8c20a400e2e62541c3f2cd9d85044e7121493482a683c6141002e1be0028497ce0e45d29312c824a59c82e5a56c3802eb830dd6d0a9b2ccea806d55ec0e507d9bc0d0cfee79abf7845531b1d03feb4ca96cb61cf2c067a19a208f0a743accc97c4eead912c2b09f3b94704ee980fddc7d6a9ae6d06934ffa6939f997ff3023f7d0691f91ce21c17e4e17cdecfc86c7ad9014b299c2e6f369943413c3b5131c9ee85d9ea1c68e8679cae9f3eecdd6cfaf9c517666b7a6d0ac0d35b996539e9d57a4f58d6751398d8e8ed4d29f0863d7534831fbe28026704767b98f4c510350876c6102a062c7dd24060b31f08c105c5c2561d604b6cada20261332878605147740626984a36f530490820d87460510f93848001ac055b86f0013bf330698b46650bd3962a3e2bb41024694b111d420a8b92eb098b141faa6061810f465848b064088b114ac240c2d2810a2c61b9c00f06100213961e80304017d7952e4a0cc085e9ca5312037ce174c549c8004faf2b3c5062003086ae5ca1c40061046d21c2308dce96383829ecf48890847ac0720f93aad0210676c6c3242aae0461611e265151057681242a64d0c5f6c3242a9c58a2a281212bc2c3242a92e8818a0c0c61e9c3242a5cbcb38587573d4cba81d21217db1777e00d0efde850caeeee962d25c7ee141e28c6c8029962d970420aa59492f2e4e68b6296b265c76d5a562565863c6d9c604e6696dcccd6a6a4aa62159352b664e68a554cca96b14614cc12325bd4641aa7c8b227c56aa66d5c874aa1521645dbad7de9e60b0c0713b3c5c868323359aa9ba93264602f0255a9381877cc87cc9ad133389fd1f5983e83a6a9c32ba8304ceaf1d9f11d75409e962ae992258554696363091d998e3bb21c35758337ecd8fde8b3c3501abb5ad1601a7147c755af82533d4bef4b0dc8962bd72abfd648f26ad4c1fec235ee801f77d887bed917abf14a0cfa5b6afe9692bfa52004fa2d7af3e7c38f2373e42b5db6648c316e2a2d35a75b623b9863d441674b8691259cb3461433071b1d87590ebbb32f521be378c95005a7dc52b0c692451161b12a6f034b8f178759d0bf0ad9a3b4819c740707078771e08d6a0a9c38293029562bf62d719019d5e6d69cccb4df3aaeeb7a64dea5b41c35b6663938145cb09302b37ad88651c0712902d870a080342fccd676718a6cf4a31fb638e5c762a96cc0d2ea77ff34867dc71d10ea60245c6936b5de24e748a9fdc6715d0fcd39474598e3332dbe40cb6a30aab1946cec126c2e94b6a405752a3bf4152e75614eb2c469ca8e059efdeb599af0e8c811504b74c5261c9d3cc717d10a9e9378ce9268633cfb17ad3c17c15e8f20127c622d86b0428a2bba90e20346ad2f36a580092496b0208a962cac16197cb7f39d6f5d8f0e05859e7bface65a4c046ef50d16df44e5dcfbb2040dfdd1afab9edb298b055685a1052f09ae60593d7bcd8e23555fcccb1ae47d6b57af5c157200c7d75daf5a8164ad0633ebb1ed8009e3a5151adfc54fac153d5690d7d2a6a62d4a52f8eb2582dab1d7eb00ab308bea1a00283efeeee76e278830bb1f87234d105932e9a7ea0e4075cf840e919e7043e70f25dc1681bdd34bea9f8f66eaf4a7cbb2a4bd2777b0edd83107c77ed6ea426a9eeeeb64958b0a83dd860cd0a739ac1ba85375186e830ee80ce8e5119664b8e348883501dc3b0886db2d65a6b7568848d58acd56b55c9ae8e79b156afd565adb55257add5656dacc6af9487af0ee114e3ebdcf2f59b3ef88ad5aed43faf1a55ac6215ab58d5eaa6611a8669b23acb0a44734dabb5d6eab556add6aa55da8459d5e90b0c3b50c92e7531abba0945367a7558536b18f3e8a50ec736d13f9f45acf65a4737b882204f0dd335cfaa67577a5b6ce69c65712ecd25a0c8046f249603e499be596fb6a697d28e82908424d32bcb9cf3c0b0d4677cfc6dd61bb0a0b88326071c275693333d84920a491be92ed590bf58442f8b5e62387f73b01f5c2ac00a08f5c9d45a247a3d61563b0a49f68b2f94f78c56fbf4569a4f5ffd98d5a7033df5563f2af57a2bea7d987ad483a40ee4828221252a9050e24116ad4eba52f44237b4d7d7ebdb9948cc92492f99d8463a0df227956cca667cf2d12c499fba417695aa289ff155035b3da5aa1d4ad35ef3609697db6b34e51bc6594fb6a6877abb858d4e7147f66d04796013d55a95ca5f62d82fbe56a8cde123c527c803b9d51e5f55b314f60df0a68168b5c3b803f3e928af7674bab5e78d2f1b5ff0a6ddebf245a7f67ac59c4bdccc41e424756ec831036bfde5834f4cbcc6d1265ec5a7af9f79abe8e48561a9ac3ebd2a9f26c713f68b4eff2475a891b7533020cf8fa1cfeeaafab05633ed46271332c04dfe9cbc11f8543dfa342734b1d335af52e7c533cd85ce3589f25aeb5dad5e8071eb4460dcc25c28adf3107355d5377f71a0efbc7a9de655df66f8cc27eab2c00ea7b7b916bff3cc33a2face51dd8d419b7703bc41eac4d70d52a7b61abe3c0b1b9fa213b34ce8c162fe456ae46d1b573deeb5cd677780e89a03fd56bb0374502cff100e9236ed246d3ac6617cc66160ec1de232b72d0e8cdbce5f88c4dc5577572f58dbf94f8c5befee1098178771a0168c951e233d09cca546d2463ae7120b8bf2ae0617296f437950acc32e01f60629515d89d58fea28af8e4239ea16d13c7a55f27aa797de3151a3eac5cf3c8ebb1e42340a06bce1a0047d76a91666c9d5bf98275ac4ac1eaf5b391e04eadfb8b48859373cdae3c9162d8237cfc3658bc7fd41d2eab99448daf08eb7bae13c6edc1a88ecf01e273200e7e13dced3737f2a8ffb0337a62cf0867d26c939e6c9f57ce3ce202d5919bf41f3ba342614d919ef71c37d3805ffaa00fcb33fe33000fea97e4604ff6cfc8c6f59200f0acebe31710e8eb36f56588700cebe31c1393a9c6f9c7d33823c2798e09faa04ffec7736fed5ef3a967ffc29877047741275b0a75c05afa7083b29112c80431e2fc0fd5139ecacfbb00ed6077c1cf701ff060a8ec35570ef86ab80c3d3e127b80a5e7c1c1e8f24471f83d49953a04dbbd2b7a770bf6a836f170063f1ed01e069e5db457014da09e04d26d8a61dc79b46cc6ad7e1cd26cc6a3fc19b2e78d37ee34166e5b8df1c9a4ed8a6e38e1904d4d133cab79b703f5512df5ec2936fb7b917f876961300dcafc65fb9e4e13e0c7978d76b78ec5ca0e1f7c28e056fe515b91eff8687c37da4f4dc6b3cf824783d40ef4977dff156ed3dbee33cdeaa6f0d29a4200b1cb47e761c09842207265a4a48e7e13c6e5df6a3197aa719e29ccfc6e8798759343c6083700e0dafe1ec2d08b1e1c11fc16bdf564e98c52be95ed7c55bc9db3da1829eb034afd5a519ea9858ea1fcd10911dcec363476400dee3b11bc2e33cee0fd38089168fc76ec88ef7dc1f288516242ed0da711f49e3c19fe101bdcafbe812366478df9432e37d9b0fbee98af1687298525294e8dba43ccd946f0e695fcc530d911deb9e763c1e6fab418bde955fafe99eba27a943334433d43dc9eea97b7a569a82e5a319faad06ad1d1707b6b6c8f124400062e8a04a6b0097b5e3c1562fd98f65b301e5b0f712c19342de1673a30b2bd3b9854e3dcf11f2c0788f8064657c4675bb99da671c421dc7c9628cd228120955573cf2a472b298ad55ca8871cd93f1fe627cfd079d8efe834622d38c6f3371e6473f2184112fe37c8d44a69771ee80f413423c7919d8c95c9c18184f27c87e3bec3640a7cf061f214374208f0ff86d03b3e2123454359e6c3b0a05f6c55fda3b3fa224d290b90ffe2cf31166b0558c4e2391e9534c1f639c71fbbabd0f0bfa7e7a72726a6a3a8248d15938f743f28af1e7e8db37a734fc7ceae8bb140df253a9bbe21ca23c1b8e78f13d0b587fcd09b584ad0e80306cbd324d6ce6f9161db5aa691984c2c55a2c3d27894c5a34fdc775152dab9811cf972333928d1e6c89e0c1966b86555684a46850ec10fa61ab80162e680737d841070bf880054858250b204981c11229868432f03245084a8d274b12892de41414833460228ba02b48d8e04a152e2830c10503611491012743b0a24ea9401631f206594bb1b2a3c9c98911cfee23831298269864c4b4ac7b36c69557d8a22861f29fea099b3d5452c2c3ab96949404f150ebd5303a9ba60542625800fbb0e599ef43251fa6f0c1091553120d22ac746700e7c0dc18bdea9bf758bd30e3314e24e5314e044a9b940720898d71194742ea7ae8c53b47f926616060601ce8a57cf1603cebb0ebfcc5dece40d4d179cafb78e93bf79128af8759bc734472d77ec6f7ab313831dfce0b46763e3aad416c38f21e142ba4059f17a6466c10ea64d5da54b794379bcccd6e668a51d93dbb677743299823a639cece11929d96b9e96c86ccde53b60d724efb566595b2bdcaee6ee64a5972d532b65de79c933a63fe4daf4de90636c9cc118b0380ac56edb4f4a802640dc0477b6d0ae4a547860ae8497b4ad9eddd824db6943c008f5505c8ba016da463372f1d02796ef6972d218437517a41a7b0f4a1920f3f64562ceaa19290185bbc50b2c549488b20b61c255d0972bac202ffd51f7030860a70a005c7c3a42b3a00450b0db10955b145a12254d87905e95480e9092c414a9b16a3e9c4c9d0a8c9f1ec29f4304c8259a0169dff60971c50f03ce5390c251da6e080d20e5b3ea094848b120f4728f100c643a51ea478f6234a150841d0e3606b8735406080463c1ee0077bbbc0de3d7e60ced769f454455640b848bc2b20d78342a17f38bff30afa79ad84d60ab9612decaca873ae79e6ade825c2b9b6225233dfaab7a29cb7a2b5d6ad4a18390fb62a116e6d31b4f046767ecea879ab786dcbb6ec9a61d56347845bf5cee875156520fc0ac5aabab0d3891290406362b1874a3910614e763e54ca01043e2bb410a4c6166d658ac145931504890105112ba8a0480c15acb0822a2d11866974b6c4c14961a7a73209c256e08a85d9a21d59981d502d53c8a08a295b5481024d08551c51e361d20db6f0c006a5dbb8966147c8b329ecac035b4f2abbab43168ecbd9950697b506610f2233334b29657310c2c99021c31d29a54ab28cde07f45b9ced129852b6477985cc0b5f25a594b7331d365ae31c02c7128410564e4a1c4b73e258a2fe350e84104e31e79c13c36200216c0821c56aa675378510f68410e2a0d2d3238450353d72f006faacd365774fefcb308a83ca477fca4fa51581848484d418682424242424a49e1d45636022216db15589a52ad6458c2c7b52ac468e424d5cae9a69f48759413168934711e93987339aa1c906a78deb05c45085013230715d8442baae87e65de7837fa21867e7599ed276c42891833c9305c5a50dc72326866294b823aa00ea60c72e0be04d8c327fde6894819e9d9d157c52aa9c6864c450a092f568a89e506557da29d66086520e4b3e7acfc7181610678c3162f9fbd3bbeb31db2a052969a01965154260ea605d628c19cc18c88cf104473dc1881ee3c677dd818d3b43d8408e21c8c0d63ac56561edea61cc1144a6af47f0c2469e9d8359fcd19b63a4b2c4c62a71a98427962212af9f6eb7b031c87dc219fcf41c1ab0edd14b98c2c6e0d35b903aec4e3fa57d0d35575863be8874ce7eddddeeb7f98996527af56e2965adcc51727767157677bbc752e9abe6556a2e359fda959aa669f7cb6e95d21b366cd99285d058c39a397661e6366acd738665ded9ed6c6634cb304867eb748b65d740d5f1f3af11de0a55cf1ee5bc12d66a2d945cd44d326fb57af1dba35fe318bfa2cedfce2becd2e0837ff4cffb2179e9f4e36781f1b62afb30afdee718a6c52cd6fba9bcbb1e31898d0132306b019cc3ddb105690399636016775f9bda9136d09bce1a43367ac39e01de40666646c24092ab13d4e1bc75fa4729d5c1fafc1c010616875910c3e0ad4185be93a980b3bd95cf6f1a9f0946b3ba69389035a13623945e557242e950dea6425ea08f1e3e3c923a357a5c923a5aacc279fc62d3471859d2bd78249b524aa7c32336a8ab089a9c8237dcc236e7c421050e296cec49b19a691bd7a152f665c274313233324450cda059d1a831820df72e09353770cca49ab5363fbbf135afd5ccd5decc576f8723733e00f36da67fbb217fc301002e8b0060a1fa36bca1002dc1a6930473c8e9642fb9ca392c00fc2671fcd6377e9b9cf46a3ef36807036c552624fc86dddfaaf75be6bf69367edbb81abf75347e43ad7e4bd1fc6667fcf6a2fa0d4684df626438b9c3917a21b4917126cafc2623e63711607e53bdfc36c3fe46b342fd16329e70c5a9e01b1c6161843d3cc2a2e8e11116af874e1f1e6141c4cb787884c50e17f244e12ca8280521c5c80b0c3924f18a5bbe1c41086110420f21840c2194114208236408238431c6086552942c28adca593162ad0a79620703d6ca2e0a3fb01f7cbae1877376526056749b8fffe1c4200e427b750a29f5b18115e442b145310b97c5a6ecd6ca654e1e85201b8026f6834d31c6196be6510be7749edd9e226c7492f18ef14f367d4b2718db32373ac5c426eee5364981114ab2f7c62b629391fd2012abfdc87e314a9417d82f1211a9c07ed1891325ec175d2e22fbc524314909ec079f9e56603f98250b0cec07999892b01fa4422505b65d4dd8afa7c705f6c3c161c27e353548d8951396faf41509ac4e6c92362e7a8bbe2fbf6e606b1c1282e5e2cb09db0ebfa53c546262e5fb5f2b20152a59c0cacb6f8e926559f6da386f052456090afa4d763e864c603f7edd786311eeaee8bc2b7a81c42af103162a59a0cb532ef3da09b350b79bf41073178a6dcac2ac8e4e4bf40d6ce61148f5ec4220fe379d731fae1ebd58fd7e34723e3dcb327eceb3cc6996c18fb7488d2e66f9a871c885ea597c41a57ed22e29b3eaeaa157515337e19cd84f388e731ffd5c11e7ac8064ce39778b54cf6e642792727b7f7018a2092e2d6bbd9f55920e783144eb47e603ea86a45c89eab556df64bb9ed49bf9f43887f194c89c7ab46321f38a705e3b17d833a7dd0faefaa6753110d9601c760978f118ffb18e849b5c5081168c731e04e2c77febfdac7240c1095c2d998bc41231a505e331de0f9745eba787d952a273241d8216cc55823d35a3d8f6ce13e2e34aa53c7ec236ed5b45d9d48d454deeac32d3b9ac8798d5ed2a8a4d63d8a6a2f60f3655263292e3b3eaf19324f825a304f66bd72b36d91cecd72ecedbc539fc84f36213b3da338fe6041d587ed2c4328aec079f6ec8814209e09317e74c67400cb20521cc6af700f4602bbf64c3dab036ac5052ed1aea1638677a7b10213b6c13bd6f77ed1e02deb46b5e6300ea68c7bc6e026fba87a42be3b2ae07b6d5ba39dc38af59562b92e7bc6e1cc7a5547fb9b915c7f14beaa4e08ac239479cc43950c9b5f431956fee3f36622934dd5c0e16826faff5aee2d726a9d34dd8a64fd881fd3836497ead4c60637b2c8a51a2d176abf7f9578ee3bcb2505da35acd1c76358b35c2b9f49004138e3608b196b29bcaae614aaa522483242bb4b0e228c90aa3d84e1bacf91ace3aeb8ca194c69692e5c0e96eb8f5b6fd36b90bc56eb0ce3aabab89d4a1a1f1d80a6f94a35d8f7ec22c4c6676cb7018d70379264da5d1b43aebac2804d998ad3d6656c98113e370f6401e76e870864a0487243809b7a570bc6dd447370bcb3940b222b6c23afd92e123380f22780d95bbf330c36d38ec68dc731e564ec3c75b4df7fcba0d6f55bdc69d041fe24e825727c186d7dc1f12dc86ff5c77076ad1f0562f787e7d35ef10cfef6a080d27c16938095ec35bcd11bcd5ace1d36bd4f09afbb39a0ed4aae13f357ec36180ad2456da607efdc6fdf9b9e1376e953618506b04121cb648f04ff5180917b6ee85d2f38064bc3d1ba8e7018d005b343ca016ece46d226661de37866029e63197adf4eb31df3c66923102bbd4472d857334df1c7b71ed63aa538f9e8c4befbb5faf741f29433d96919d18ef3372bf1dc661dc87bb73c17a9491f1188f763d625a803fdd07fce9403fbd1e22e88c8cd7992b85883a64985ec67da48cc7798c87f217efcbf1304ebd8f7b98fbe23e72939c93ab496331de6f76b710a42184137be8995bcc535e74f2988a911cbf79c6b2ebb161ae79d06b295d1fa9c0f292d4e923698361be6d5f0c400fb6bd8f1e630861748a4f478dd41e8e200b9949ead8aab2ae62390b7b499d5aad55a9fcf2eb316f6f2ff5ddf990ce43ccc2bc3decdb0afbe13c8655973a5c3b86798dbef2228d07e50ccf8352040f4a9b0fa72d508a5d07d027852e215c61ca39af845162f70709d6c22e840e2d60a3c71ca8c4a4cbb3d755a382c4c08025cc8402272520ac7c03e1a469cacab143954aeed0156c90634f996fe7b9846f9bef1c37ec7d383bd2dbebee96b023eba061b70761cb164698b2f35d7b0002ac022811d4e0828b098ce0a28b232c558722bad080164f787801096812295e30a29d236a0d6df2df0e0e5114305069001ea93295d330620993951faac8c194244045b8e055051155a014910413581227524e78e84074450822b8ec9005d2c08a2d5376e0820a97a7244c9264000706a56685168268d912235687049686d18959d1ebec9edeb3482f61a1c7a48dd26ed8ce7476ffe8bf124a0c92f8309de02203b34b2771b073841735063b8411a7173b4754a952292d11c1f650698907ba701a0f9596ec204216be62f550e987235924f350e90727d0b3c13ec042a51f96fcc7d13c54520204ae1bf0900359930f32e362997cb01bf4106b78a86287ec68059f168228b101d73c545252829f0f959424f10456181b2dec8eff7cca752c91ea9c7394c7f9a6238a85cc424929573ea4f4945389e27e14e61dca53bee958c24affe28b7a3ea60f7a2110656ffef1a6529e622e76f356d9168459ec4393870fff8b148759dc3b4236d41632ab17605cc61300e33237012f1e736160fcc55bbd20e330320eb38af117df64bc15e6320e5b31de0a8b812de3c156cc4c37b76a8771d87af1567d5f1cb6ec12e7b6aa2cb7c492369cc3785c8c175f3cd8b21cc6c52732c638774438e7bc55778f592acc6229cc627b64916c956bed927cb13a212fdef1c9141b89e2cb535e421796fa175f3d1db046761e753fa0e82f2c6e6ab2af1166c93003b398015dec078f988e78f60504692afb4884a20aa78f5f7c75cb653dbe5e2fc803a91431d21e61ebc501f23aa53846ca066b3e9ba31d1e87bef94bef06125dde6df319de07f4337c86d3958d1c1db01f0dcd108d13ce198186b3c7aec708fecda697524aafe13e2c2502e2d738ec6cb80f3bec7a90e03ebc6db15b01c0a1d4e1e1edd72bb272f87236c9e170e3e1cd168df7c5a7f12fa23c0dbfbe315753f382dc7438ec7adc9c60c3fbe2db78417630d0160f1578789448daccaf7ef6f3cfb6cac5ebdbf550bec57bb7946f193763498f192e1ff16708c19bb67e82751c14acabe0996f3351d81b9b6fb3e994a8cd28e55847e39b53613fcec52d256a8690f6e25fccd30bb38572491bf6bbfa11fd86dfb89f0e8f0ef45ff7d474c3e36f4d37ce37776bd2e16d56ec1696668886099a231a2990e786b3b398208f0acf325c85fbf967321c85fba93e93e138f784fbd5cf704ef02ff59c439839843a1d93c78e85d4a380c20a05f7f196f3788fefb80e1d3c3cf079f4782b142e941e2f80bf774c3897e94fb85feabfaee511c07bbc96bfd7e3373c9a2078c34e3304e3a987f12f05f31e01bce5cd78427debce60eaf16634cd7092364c33c4f4ddd317f3840ae29c1a6eb80df573bce709f0f7c7e7d2bc08707f56437838019c00f7a7009766e8ae84ac5888373c4e69e2d58a5058616a01b576dc8acdf174bcc7e356cc93d4a1a9d5c6dcb8e1c5d7f16ab041e5b40450073bcd109c99e9e9f1a50ba8148d36754d0b95aa1100000000f314002020100c07444271482c9cc6d93af614000d7e9e3e76589a8bb42c87511432c6186308208000020044648088883300f1233dc602bffea6afbcb3320d16aeb9037f28b514d779cd1f01c7ed209066960d9df822958ab7367c56a8210083aa9cbac2a55611cec40f04ca1acb7a4110d05ebddd8c872622f1badd872a8a5d1556a5b739f03d52c3ffc9a90ba3b6bf474dee5964a481808a40d99420fdf3842ba5146ac92c3ca1a50dd2f0522cc53c5ead06b44e2c9b53dd311ab5ddb36763dab46ede6e95d40b0ee012ee490f216a7bb33524e4f2e8ab998ec0e8d1b4166a6aa7ce67ca456a5d089655b40558c40611857d4f92519e87dc6c0268de1fc894af0dc2faa999b9baaa25922d3d2614389cb9cb861ceba8386cfac25d9e31278cb5fff9c096a056132559b0fe4d51dd891fc1209af7a43d500147c2dfe0e3e6d18093708b97b991b3f65fa3087ae85fc8d8e431aeeda06d776823eecd3de4c1c7311965a45fb925d5734de015882e85c24eec3f11d821dad253d5c47e28f27e5489c216dda7981d2b67e13b8622caaa9c0f7ea18fdd9ff53d08b38667217cd12e64777d8bd38e223957b786858b7b956a341e43d6ceb2efe9e6b2d7f441f156c4bb0dd82159115a06bf2f6e9e55825921741485b021b4d66e6bb27e71ac50de534f33cd4da0d6e2342d9eac01f79a89597d4622e8eff0b5272d3828721e1a6c2897c27521403bf53c07380a732e9d5d78963beedcca3c496263e836523fae9052fa8d4ac72fa612a2cd2743cc297ff4d7e33949c2aeeb830d58bfb1016161ae2df3932ae6e1724c970407be8b44f4cdf05c65b0eceb82d72d2236c8b54669b22a49f265912039cb61af84b1d751809f6e8f19b0938d40bf70db067bbfb8e0533456ecbd1b5909996b783ef5060eac5fe1351632003ed1d1678e89b0f69a22d802671077e25ed7edec1820f54f65f7223963c84445ae08e072d50aee9c5770ba4b7bdedc4a531349ac5cffa2017eea38aa1f0273a73dba2f7e6ab3769e1c6d236075d5e12b99a00b0fe5d215ad8aab96cb88552de91b7fe0564961c8b5c58eecc0601940a4409de6bb300a4b6b433dbcd2791942695d23c00c06dd73b49bfa99feef38d45cc4f3bfee13c7813d5f46915c16878ecbe3f6a4568b591ac4e300abf023827e327193d91e0c8b60f07d8bcfb1fdf6248eb60e2a08649ec30a82bb0de83a583231c8dfcc35700a814752f6f0b05ada14b99cc50b860cce2177d354769005415035a131a41996f25f185fb1f031b4d147ab22bbde70a1a9055611e2dd1616a2cd4a9a9f32d9237bcddfa0c0c801f5ff0a8bd9b9fcbf7df3f1db8179b24a0c56a884838d22dbb4c88400c1902ca2d5dac409eb10ba25824a4ec9fe419d71d3033a42a4239effa292301f82435e536344ea0b55d648493835b15913be42da96180a20a5a9a0ff8129329e30bdc1d55c7649c3d3e7389b951aa8113577c41877337e73f65b9aa26c9e651b40eccf46e858979d437f8829d743bb616356a2ba6ae2bdeca4ba2cd0c78f08ee71a9b0daaf5ccfac78eda7fae6272f1155c162b5fe191e76285111f1bb5fae6daf0acd5d62fef24a7f9f3d3ca525076d0e1db9c1afbc06797efb519b44d19daf34018fd59b7b2fc1c7376b4fad350d9ef4024da7ffbe56980e13cf5a90349f9517cf12386a07af780ba2454e46544f67d9bd000be464b07800f7673698acfa55a90777b25e7c7424c24a20cef768ee90031a18624143c34e326a5128b1d01bd855a410b2b20facd1b5e8c5e18abe5be0676df6749aa8a78905196a048e8533c35f7d8e2a646c32a03f9709a4c16ac1751cab3601882943a74c7dd4268001e69efe173eae6080f4baa60227bc4e7098b3d48412e535a1ae4f21b01fe01f0c2cef405a14932c57eb4c2b9be36942443b34153a043ef2ac4968523de3dd92443046a1eea4c8649598ea5668d0f0df3bbecc2ccc4baa34c905c37f785f3dfa039298b61073c16ff06e5c91eda13664a8ef8e7335d6f3801e4a0b35c8d8312f185192e821fcca1998827f3cfb1070a6233602fb7c398f3c2d1bc888f3c1c8e0e30cbd5e8e9a2d5f4df755459dc87a079706257041a4f89354652db6e4387da43c53cf95df13831c66c67f868eb42b7825179233ba957e8e544c1e172748a8e48222b969436c7a1b6124700da441831beb6baf46b7259ed996b66c39c523aab20cf1a1317b337e404ca86d49989af46632b96ffa0ce40a96ea0e5b374c5664863ce0bd08b382b0bd14156a39c6090b129471becdbd58122714ce6363ac26888f3a533013ee4060aa060de8d70a4b62488c6fce645a859358c4410fd4248366a79ff0639ae895aa9a9daa3607f1418c5a84fd6034c173026088014da939fd73718214fc9cf4cc70375dd28abe7811b8c5a2596105ab9c911c059e77235cc9089c8e9c5dd41780535571ee80727a11f26a419ad50564aac8071697e3e2d05c55822e63aef4cdf5faa2613e5cde316d32a174d040b143171e8f785143631c01365f7a66baae9e95b920cfb5d45325586c76b3e0900cd5dcbc287df4d948ad7dfc9e96ee994a1198d9ae7ac6f3425e0c90cd3228a32e1acbc3bdda82fbfe1028438b8f174bfd0614322a6f1b8cc1823719c3094993fda72ee2b17636991e1898636469e65230a770c5fe724a4acc8274847f501aab0f9bd185f705d1a961a98f2a10b8c61975c4c9ec0cf97f3daf08cfe23091d480583514046af01bfdea0494b392b950c76de5924d62c8440de7a77d2bafeaf26868883fc87c8ae3388132760370a31a7f2aea3ebfd131ca0aa017f24f606d16fb54a8d4d778963f4fac4eee846d625c5b1d6e0dee8b8391e6d478cf85c59abd20a7324a92c433097c00f713bd7205ae6ce8eb7500453ca2e199986724d00fa4e71fe6c70e54748429b0e46e3519b5481727ffbfcf7188dbafb263d2930612695f178a24515796cbf7fccd332bed37dc47af3e4f749d903bb3a216ed68d33e041f7101e92c76eea6b1fd07f162990c070c0d8a07388a664a6c472e0dfb9bdf6288b96ecb431b306ec0d90d4f9b8dd7276cb9d70098850cd41912ba2335cbf49a71bd862d08d03ea1bdf48f35b06045a1f1c3dca7cc3c5b03051b4d8ed81ddc08fce7189909bc6a3839c7a4c0a9af7542fa3eeb0073d2aa5cbb8ae203628eadd68e0a841a21f6bf4e951143cb6925f8c5437fdcc8040de74da2c743a65c6ee3354e4f7f287d22fe01d707d32c72f922c5f3410e626c80463a8df7990148e4cd7979e2f9dcbf059d8c132a7fae9e8f5513303b81f1a927727238cad09661eca44c78dbba0cd4c020a4d1e67c24d4d336e531326bd9038c6f21982b660bdf12f84362c0d9bd484cb82e12b84e47a81f4fbde472f229ed0d4e5139dce6343474a8d4e581dd1b4abdf011a029bfacc404c839119c8c1e915014b6684c8425d259b72b8a037b0abf7b7a870eb0ea893d3d4a44a86374bb9846c16e607b129312bcc0c3f0fceae3cc482779cef9ce0e5e532cc1a86f6c280cf30c6015fecf19a95d1edd83e98cef41909be0064e01d73313814d57fc7b46af8afab8c9a7728153fb839e5ed39f8b956185826b0c686d572476af426b59a6105a650e2bae421f0447b7fbca77a4e3daf77ad007e926d03f5631210c9de5e69e2a146cecfd6c3e5aabbe18f3d26070b14711ad534c9cc84ea60835e0ddef09daaa709b4ead715fe7009c025833096b970d4898a300a9ec90641612d92c8d7daa06a17d5d45772ad73551973f157460802c1fa24a29ff931469fa97ad1a628455ea4daba5098655ecefeb2eb1fd8ca018b765e17a9d7bc3111cc09da467d3cb7e6507901d94f34bbec29c5c32c35b285159ce7de2c0ef765108eb634586396930bfcba43aeb381aa8df6547737e2d1bd8a75758b95693dafc3ad5c7f64c1fe80db20e570f4c649d03fe64c850f8d162d9fe14a1c2cf4abd18976556a740b09360ab7810ceceb472f7d4cf6e2a039ec67b1958a8351353653407c1a4afc5e10771ca298fef4a48467c2af401abbc4d9bd93d7a820108376786958fccf055599925989578f5ac77ddb49f8fad4d048d9527d1e27327fcf1aadfb51c34fb450e60cbbc568cbaffae41bd8bbc48b3491004f284f8c559e9da57a1e7b92345781d59aaf8eee77aed5b69a6c0cc50a1251dda38a30ca583a3332db4cd0e0f74dac646f4692e3d32ebb1e171aede5e0f7ca3d7c2c864ac9e8c4127cdc13a10f65a52705b5ed387e05323e3877a299332777134fffc20526e0ce0ec9d37606b3a5a8e1c63788b1baf9580bc92373f53fb8f1f385ed527fa121c5fc3e039b07d1a16de4670ca57145b0475b7e55a9371cb58f8d41f2c505ce10b3bb102cf3140416cb2c6c4004d05884324567156fe2116478881bf2f97d31b583cd7d844726263b95a7877940b0ba0ae4765075cacaa1ab5218362fcf2899a2f7b2bb73760ec8a5689083c56ce82995b410437b30ea4a7800a89cda4f8aa5fc3d6f91669b5659e415e6d1191c807cb9ce4dbc76d86d52ce45834dfc2a83e089d81cf3d046814cfd915ce0dedf03d6b6acc3087d4d19dfab3ce67d5077b7a3dc0c66dd2aa127e8dfb0c77f4b54d2aa17d0c8d0cbe13960fc6087d63212a3dbe7304b534a5175c4be0a5e283ed11c4c7920b137953f38ee5e7ca3661ad8ef656dcd181eaa74abac8b942d38bbc0d332630b9f3e15f0d28b6ec35be49c373b7982edecbffb2f0a1d3b2fb0be55cb38509ebeb6d618077a2cab3fe54785f03377438d19c8a3981e03f0dc1a6f4b8e4d15dd841298bf0ecf2915960f9ef9dad41e877033e99db31be9ea956136aaa67089e45055b85a67aa1fc7f888cfc3fcbc77b3a2b85903420db46482feb9a25b41f5561003826ad9efa420a6ad7e3c44d4cf03dbc2b4a1a998e13cadae832f2777ebb522ba04e5d1917f685316b46eab6416eb4f479e629779dbc2acfe4293a79edf22d8c0999f36c9a45ded75a008db89735eb539407fcca5722158552823285a53dabbc935a2e2f08039985ae8daa2bc750d93308a5db20cf5e44ee980846e49cc9e0fe18637cbb51390c9dee3c9497b497e11f8434b3e99123650d8cb232a5db30a7c089b376048609ea00acffb2f670d99b3fa044e89787050180667a3a461165a54e969e9a87514b1cb785a87845badd942749cb06bef7886bab391f4d269882600c8fbb759b73b22f8a0f2216d00090f0affb0b1fd9eac580fcf31d650212ceef3874818cf0a0df4b52aa07a24287315553c7aa0dc35ce780593d8c420c7b241adc862799bc87945dd9464a7f596310d8d8424369309cb096a7eb884e092b39254801e7c975749a78d26cd2eb0055c262f95c4e9c2d6127af29b7339aafebc7b0c3c0ffbc5282d82538c3bba328bdbc319d0e9b4af5940a472a174a93eb69c75e3c5f7aa61aef33718f8fd780047797b5b2fa938baac04aec719188ac0b3666015cc5fd03db1723e9a26f390e2935053594c99cc6cffcc1491e697de8bebe524a9e9106640906de84813aef7acd293b03ad3a5c6bcc3575cee4b02c16dd0775fa3d25ea2afa206fd078b2251c093bd900445cde52862c7d5150c0a23a4a2b81a00d6e10edc636210b5d49ff585a045a8d8ef8be0992327a4757f74115772b1b3e5014e05566014bf5acacd6d68411a4205a6f0fc5fbeb544b8aa4bc896e2c074dcca8d0918d6b046dc2690ac09b72b823ee5f113691fc8c1d82073b1e7c5df50561c5ad9ad1cd809563ca83a6774d744ea32753ca6e68db541323c64b08dc19a289cd977fbcccba9a582dcc69b2b922bc8cd860d0740610f10207da135092eef5178f794c864fab4e0fc5669ba9bf3626646bb3638aacf0d8362494617a827b0d8da8be181d65fe5adeb439674c2b4382f22f07f7b2ed0691cdcee46444ba7fa320e77917bdce4498dcf90fee5e430dd705c99a7f68ed8af326f011756286344e0f06acf43cc867b11edf132b0fbe85278f7aedb209b2be2fb9e1870f6c6cf5b09f87e22f11801bdcd65db5705b9bc17c8a153c7f7970a45ed8545e3998f894019eded0c25416930156618f4afe820fc19a6534dac7a5d5ffb20487d5052269e351dc2c49f94da81916aab2053b33a942840cd3dfc0de97c6727207d8a1e3ac60e621b2d2478f7ec6875ea0edc1bffec59944970426ee0f07471db4289f4396332e18369ff6a4af8ff6ac8861135a1027512873a2a1e8bdc252cdaabda9adc25279dcd9097f9ff02421283d079198f3650361ab648381a7170c179b29f58a03cbfc9b0bc0cf92aeaf71a03a1cade447c972018107fc6f2f74790fd75b9d5a19953ee24e21901d16c0c38d9a62712ba2cdf34709c8cd8da319b12c270aef4eb56a6af8365678f05ed3c15d48093118e10cbf803bf01bcce98401d5139d9fa4322c19d0b48002567c104f581077c4d172cae875a4f1ad19623169e8c9544c34a29c77a28cbc745237704036eaffa06890dac4f87113cd9441cfcc22fe5ec2f283b0baf428c2d9c6c45810b81bbe4023e0056c26b63adc5696dd997515c00f43e60e9eb70fb702f9c75e28fba331fb4129ce57fc158a40c22cc49a7af063125aa26f2719b29a34d925e1897eb35020caa4371abb09063128b91a9921ffd0f8e156af03dc2aa6939c90f398fecc629d678d5c303fa265590e1c0beb7cfe60849b2b928bca08badcf15679e2c9437f968886c3e1bd88433d1c86e3948749e91cd7e399238374efd91de638e4a40a929e6a64d372890128e813e24b5f3703d7b755b8519ff7813cf3b1074ed28441aefacd7d8bc31fe677982c4457e0328c218a90e432d14eb80d3a940f4147ee7e0efe9c2a67de07f263d21ecc29697352d5bc29f9d8e4c3b79c1636e75b2a5e7fbc1e773fd1204bd1cc7e5c3da2676f41da8472c09e52b27db383cfdd4fdf14cc47521446e0cd7d4a0cf101a4e5de90a5c2842602c16030664c7aa699a1bf5fd806f7cd49b154a7d4caf111d836018e9094e9f5503b2e5e71c6dab242bb8d84b5cfa0597a9326c49c06d4a36d203e1eca9f4373c031cc3f4ed04d7443f3bfd18bd056b4aa05b88e833cf99323aaa1b116816569770ee3913ca4bd0811097a14c3698b70a5ee70c86c3d53bf1da80e1e7cf096cc369d49f66034ea5433a508c4fcd33b1e48b2b490c23f81a5f7c9aa4b6b113f0c9e221f2e0f2be2ae1c2e28a2fd383c67bf6ca44949c496cde90cdf4a44eabd150324da89696b8923a9eefa1d76958490472e4ba772233ccc4b5b89c729fa0e0e789abd948cba2ec06ff764af76c7c193881ba9a25b6e79e6b2d147a7d3cc48d6014ba6a93b3dd98844408ed68626c9eb0de83192047a860b70c62ec6654e09f387b6892ecf12587b7118af5de5aced0bb143c7a20ac3777ceb08ada9aebcb0cb8d6641d2c687c0c33ddf3e1582aa1aa8acaec8d2475b8c8f5af48edd875699370678ac8d0ffb5b70e6ddaa12590f20580c4dac684ca033764bea87e80c6c67cd1806a0426d7e83d4a23dcac361e761ebc84e427761333423d1085f3b2d501838ca9603df0c1e904c10a823532e5b7ef592ba1f3b28fa74c0c818be139386c13bd747bf4fa1d1ba573362ed94d97d5fdd064c42dc054a7c7a9dcb0614a60e69f55322bcbb8b1ba229cb85399efff7d39e8934c9c7575adbf35a15abcda6377d979a9024034c44cc488ee7248a65b32f5613e869a93321773c0c243640a40d481dfea88004761b3aec4d7dd9ed4997d98774e240a6ca32343f1dce53a1ae9044beb2594fb1696798c0e99854a4a8248b8f8983b1ea2b3ea68c5cae0ed5bbbf73f4a4371663860e6059a04b396867ac9b7179f1bfd01c8d9a0698165491ecbeed69c39625863a6132740f1b7f79827fd9628572e126acd53ad030138b37390fe75bd8b928df46751f2ee218c1438846c04d2129da973d6ffa7486121ce72244143c96544b4104f41bbae82fbebc225565dd4708316decdba70b72ee7605e6171cb9d1a0a382786f13152ee94b0f247e66446c85cdcb776a345c67d428e91815004d1e700d904a9678c07e3d4b39fe8159ff481d7866a5c2caac3c71f33e7ccb0033018e1eda10cf3453f8bf9f67c9a1320ad17359cd494520251569c68b52582f0009c698c8347f7aac746204477f43e09871fc90216d2d3ef84d4e6343c9f2281fe35bf1734e483e5f63545ff52205e9e66a6a822f6f31c0f99539e44b876970028fbe2194a0c97e0950569e8c28139dd75ca38c0334cebd55c162574d2c58a9de39eb903e7931d8f8e881ef517549b4cba7d55bc381cb9a75285d9688baf3ffd65ad5ce90be4c41604d97cc79f276aefb59c083c974f6004ad43d7979e97fc892ecd6f4755e6a28016122837616197a8930f4d7b67a6bdf11cfb9dcfedd46077fae1c5ecd5b28b6c3aa258aa8151716dc3e49eb1f2e18c197c28b38efd344643f8d57641265bef504830f098b6f0e17fa6e0650aa1dd7d1a3ef5eb96dc64431cbf05b3ba13d6817a1fcc40256222744d9ff560092dcf60f5a75771e088dbfdc305421409380e0a956e49981c67b5e6334e4f2bd2437e7da8129108228e6541701bdcaa2856a3c1677aaefa36f2b8eec2354db53f72fa457b9a9476e7f5ab5726c3fe578ac9b606ba0f5718b1cefd0b898c5b41587dfd698ed352473881b7994225be23fbbd61fa6a03a965c7fb10545b6c735c8b537454b4d1d7083399b294521b8f9acbfa22596e0c4a6177a04ff2c9693b7df3b81221dc037a1b33ba8e7e19413a476628b26d0811bb72f0ebd882e4e10de949bb63b0b49a09d1cced0ca40a1e0a2506e92f4d8231dfab966e88f169acc0470c6e3d21f04cb19d965aaf47e4890ed755a1a5bed89e29b126340ec2ed2d4cf9ca0b3669051c834eb905db64e461938282001739c5d254c62483f7d3022faeed098848e604878d72fcaff134883b222b54e57aab0a789db2ee7a7c9b6fc79321ee6e3007b225ad13b2730f385aab6fabef4eb317331ec2fd155038b0564f6e0a9676d5064bbda75990428de9af2836528bf1bea6a499c0d52346540115b49daacbe1c32a4223207dd17f4fcb8fe58f812313bef4811d45ef6085bbc76cdcbc76c4dc01e56501d40dc843b6d3f60921cca801d4aed2b247400d8c020b755b7c5f547ce26acd61c9cdc5dc6028889ba8fd6687d804e10deeee09e58ae7c579ee35db572044441ee8bb7ef83e96a8bf915ab75b4840c1d440ae11c1a7d1c46938d125d7de83a188e9bafcd58bb4f7d575659fe44009bd00a77a6e6fe0e557bbab5b35abb656592c34cc64f6941eac98eb4fcf7d7458c4345ee2bcb1fa798c96f5307cfbb21d0267170d54fe2ef357667f1fb2ad7d25d06cf29530f3065c65627c6cfa42829c8d16862a0b7486202a83c7fadefe8ff6dccc04b9c2923d53b954aa3b50780e81f01a6182b6bc245c327b468c3d71da5f4548093b57a76e83e5be03b86e1f0c383fa5bb0e97499d23fda007e5ad3929dc17118143fcf66fa247f7f10038f5d9474c9f7e9b9b33b7227fdbf7571870b1ee3381520dd7fa6a3a006c07e50bbc82331e61dc97b66e3d378db68bc5bb7c52c59af367007f95518ccaabf9a731026053d71c5f2882a46c43bd2c5f961bab8cd60651d5b0b2819e8abac72dc9a2b22af463248d613aa570f8917740c071994e6609f10148e9fe8751d00b90b4692c59be2561151e98a55d2c3c15a1f410275c58d2afcab2fdbd2f8b6b1ea6d707faffa2d6aa1f3aba6eb2423fe05283fd0c9ebb2002c46fa8371c4b3e50b3a5b620fdf08ddd9714c01aaf1ca45ccbf21fbd633215a5312ecbcbac925e739bb3a3ce54e8de02eb6dea4af85b34871ff166ad5bdef4ccc4b5b5c6b361b2e5bf7f6a80d5a827365d93e08cc826d4fff0e1b68d7b1d19a04a0338b888ad98444666e53980d417b79b80c477df94c9e3e3f91ff693f55e23ae34258aebaf81aa442a50ea3dd5c789895e98e03caa83813a35a05e97205f1f31ffef612c2b8cb55ebc3a44435ceef181aa946f2b68de245787e42255fe92c89d30c0b4af86fb0391119bd5d97a6384a27bae50dd7861f992fa59b474f15bce1b783ade9e0b38d1b09c58530b969a66ea4008f8a51ee1243c8c800fe6bd316cf7d5415c8e21c3eadc0edddeb36ef11621565cf236d75f88c49ee8052b68017bac3f3f6ad090c2012153b0e3425194ef5d02a5a49ba18d4e65a30ed8c0882724487efd35408d62c9a236d8831d741fb20b2c3c39c0fc5d6cb809ad9b6f05605cae5cebd4ac413c0dde2627750b7929efe53cafa4e500252c71cc91301f3fc8f8c5bf5c420cb5a98855845a9ff2eb937313ca06bb607520fe3a421eafe4a4a0745f423d767d8c5b52d29cd954278a804fcf01478be289d7f00593067a530a73b907ee35f913d4d441ffd4ff685f3f1a8443fad9427a940c24155966f7dc2226b7a683108f061391adbfc94f1e1c8a68dc34a43d1e4407949554171865f6fa06ea0c3ee481f9eec788e3026f2650fa956112f007a8c291e39b583c085d97a7bf5acd484b2ff202e3eec7bf1120f4b48acafa3a46d6da6d1484118ba74ef8285c1bb3fa66c7e055f7c98dfe8e83218b9aee18d866e156c8640950e6ff8a045d48189fcebb4231ad01dff0aae4bbd62a355a7cc0524fa79a7b5724956a4d687e90d5bb92f0e6be6b93e5f0fc8f63be20a189458c9cd4118dbf1f1fa08803d62924575d0a2b4b53029f729dc88dbe727c32da13fd6385aa1fd1d17a58461bb732ba1d7e4853572ba614e9f4792133f99c18f5861c9bd931794990c04ca22d634b3b5f8e26e0ab1156a34a1b91c37275e48e8c9a45c6126386aabb2190aad79acad100509dc18d46ad805160bd2920f09c44709c37eb9ad7552d2c728ad2550933ef7c37791f11c5315666b528ef8e055973b6af9065c203bed64da36892734ebe186149c2039a857653a1ebd25d473958ec2ca133825b83cb71e9fca85b4ed182d60ed2b6ab1e6855ed8832927b44e90558e24eb72f11a04f2f5f10dd5fc031474bd056dc4525fea9053cbdfc33d0cbdade1c258d7ceeb97d8b638b243f1203b85ce1ba8c3d2edcd1141c23559a024352082b325ebb0df05e5287f1713eb3e7b3bdfb6159844227625c95f07157879b6fe19f26e69a95add7700e010fb554b177295364a7d932b0415f5ed75beb09a182e8363f4c3533a227f1f5901b2dea8a167b21d9444445416626bf29bfbcafbf685f3d20c3db26a0ba5d0a066862c0ef2a4125347f585571d4d7ec043c3719d0886b88070c449dd94d7638d48358c714b72adbc200f315da539bb5a430e0f0976aba403f67f851071e4be0bc16100b61fdcdbbc2781d3000ff1cae3f9079337da7f090e4ce1e99b50870e6715e22d0aca5c9f31cbbdc5ea630237827266f0c2672ee6cca6420c691cab60052562d8137600b101e81bbc84970a86aafea2081bf394e32b42845cdcf9793d6019e1c3df39330bb3261af85278fe099a12b79997508389a788fb35dac1a40ea5484232f4a36c6e5f721d8d5e92f70dc4e8ee7bd04ec3d9404ae6a3fe2cf0238100710815e2229cb487530adb6c09e2bd627a0462bb2ea1cad244f77d1861f3f6eb6d950d62b92be4f00eccfb1ec486ba7f98c059411ec938b84294c010d694c6a0156de2350bc8608fa01a10c87232ee502de81e6140e694680a2522275802a5484f6c1c49eb56a3ac7d4d0d48c493be6698c414339a80cfbd49976079a56b7aaacc3d9ec542daf6912125a8d5b288ad10ce9e0199561b5e6f14ad83dd176a276ebe4960928300628e99813ee3577ca4d6f8d29b0fe3598d5c212f2429b2c5041e2dfea43c043517519137aa90a5b757b78d91bc0af96befa059890495686da6483c8e21c817810f2c1ad7990fac43196ca8cb49a47ea56f19e9a86a021985a1c47f4463fef055d61ca80ba586e596998724d32f932d063af1eda00e70485d941c7ea253d0cb46a2d5ba6b6203b95cea66fbbcbbd0e2f35d250b51ed15414fb8df398bd52d3109ae637e20a0de8177007fb9d0e0b40679a0ced73f2ec64ed1e74afe394a3ebc5495bf0f464acdedbb76552373e217e79eface0440e89f6ed1a05d7a67ebcde5031ec78bbefa0267e0f1369cceb1167ad39f1b7faa36f323e2913ca7e827feabfe472f4890440daf2fc9b9323ce24915bec144daabd6cefc2eb38c4d082d5b780e0d7b4b3e9ac77560b0c931e7c65fbc3569fd45bd91bf128884ce54afbe5c738b5b6c6629df48b21d19d08f9cf4cdccf12e2d90a1c775855c15add606ba24a8f229ed3b58381bdeee7ed32eb74e6f63501fd67f6f9efa055428569d9244411b86a31ded970d29317abfe811413d0e93c0d1edfc532e1dd883088e113325d90b53f20d44897105caec244fdf9fe2cf3e8ff48228af9bdcf6fe68a87f8f806d6f3470d4f4d00280b86cff01e00fc6265c9bd12b504264d14339e086045bc04991f1cb9d750442be5ce053deeaff38cafe3ba8d342ff1d73e25464c0184f1fbf895083a9686aa4a81042dc13227f83c8f91d43b1e98f914404144fa83a98d373eb9a7b9311fc9ec783f2a0de416184cf7102fc69555250b050028d3b76454ea070a92b29fb885ccac6905f3f02087e60a549af57350ca49ab80aa6267e3f72bab3cb909a1c016db09b237b832bf05842229b0ce57bb7d1db092ef7c793241c29499a78befdd7749be325e6075504f1583b061cb71d952875e9395e7dd0a64595bf64dc4aa4eb92491dcbe61b15a1d3c81e92c29c9657b421602bf3ae384574dcb53df6e0a7771332e20f93493efbc590ebc71f74bdf31bf5fef65fe6576afbc71d5d38d0406ba9e7917f07a09d8642860cbbf4a82165d5357374eddc41adb835e875e92ea86155e1994f27747ec0003271f2562cf21d82c263dae597e49557cb66922d96e84f3e95afc468268a0b3ba9b3a14e91b7b8ccea3691b2720e5dc764408c164c92da704e25108c70c35be53496a454acb06844d150b6ad7c1807fff298278c2e8c5a5cc2a3adfc1c098f96956280c0a419f4fe714b968d36868bbe83b4e087482d38c47c0adf11533fcea298e77ac06535065ab645fad8c9078a3991db3118cce6bbd62c08bf04e645cd513a2db65ddf65d11eb57a4849fe9c529ef419920308549e27d0de69c4c562c6862ac964154b316f3af0e1c27888f0736109287b4ecbe3c374610842520d3e4a260cc043d562814ae49374976087ed2daf43177ebbc0c73e0d72a8391d5b652aa9102ec046fd9c8abb2bd4bb3e31a56492d894fe1c027291b5e24d7f9c8c5d1760025331b495fa2975bbe56007b3b5de028bbf5af0af40633211080824d9582c07efd5bc173d5b6b32f73fef7477e3a2c5406a29ff9420751db9b3c0ca817db53b79b4a90a594bc74a7ab03d3e966f7e7ecd58a930af6286e3a7dd8ab113d48d3984bccef2c4bec4ef1ea30a36dd65303a0ae7070b0b15c87adb90ab0486769a7adc5baaa7afbe4bbfbbcabf0b971b12458f896831739a4d053bce11bdc4406ee8122d2181f2bdf56353c09bf20de9cf329224ca1e7dc195f2e02c954936b02df5c296672a881c7cbb7314ab699708bc803ff8dab2bd27ab4cf48d1607b4accbc3465a186d5144b4a2ea6f09aa3c8312295adc9203750d710abcf3eec3161414d116458137b4e802cf8acf48c02cc79fca8de2c347d0f4930b1a874501d213c4f6915e08858ff6f404040b1cd60bcd495b44c1a9356705f6a895b2b7f4eaf4914738630400d86e68115bd9003963d7e73bda321f5f9568f6f01c15f23e8778c3e9d7cc291d1a654efaa51c82c78050ec5af6290ab263829dcd99e5cff8920120adccfb7581e051d0a8bcdd5938ee0746a8fca6e96fcf0c024d17ce1c9b045c636ade1935da46121d082a59644114978eb8d06f6d8ea410518b3a5d0fbc8766be7cf19e45f01c783c4b178bed13dde3b16789c98c780afdb125044505d00438ab5d532b9102e5de635cdf6586d1cf16643c09b71ba388158a73ed88610a8bb8e00c123cb009ea79831e8c6c9e27ab1a970d1d9e13511b4c8472d334c0563529f63e7b047a926c63296adcf028e0cd0bb6281aa4a6f0e3ac6f518e2b0dcf9cadeca01c50a1bd0ef175a0e5b56ae71c3928498596d19d0ec62c41470ffaf03df9cc195f1aad1b27e7836ac7bf1c054a441957af04174c662cd9b26e928ba5e2910ae4a5d0e0508bbfbb161ef1069444fc2e50c2a4b81624624f293ca142ccadb70fea72c39b9840468c163537c287890154f8a018c94afc04eda4c0492d90e113241090f24515c254850e8baf40eca04822a3c42292742864dcf1e9695f007c09a1987f7e15f048b8a1e7ee35beb8211a04dbb008e41e55c60a334746029494456d0f3c288993f29f1edd93cb6f0c7ea0ee4cc2216f47cb1348c7b42db525362785d10d88b6b6335385f1341719fc95d45decbbc4a8dd1bb565ac500354040c4bf9ea8244655bb70efe4ed4e7857f81fba1e7cb3563d930353f1dadc5498cd2ede28cb1abe06decab45c252c8448f401690469fc0a2335c91a1fafef283019a0bdeb336366ef97cedd9ba65065eebcc3080a6e39158d076b4045e61088e94ed3f584b631348d09fd1bdcba3c8619784e242039603e02c9a8bf5efc70aa8fc7400b5c957e5202936f73e565f4530415f94038c2187363d7be32121f6efc08a13c61e2178b3bf30eb1d2594bb07a167ded256910a506c410559c8be1f7fbb4ab3b79c69bc8463e39ed6da280b1b5477be9afb2e9c94ac604bbdc7b2cb3116daadfb784d1a21533ba4f4623935afe8337267959379c298588ae49d1c81352f65bb0815655cb85bb28455adf81b430d6eff22c80dc17ca5ad3a6ec57e699187725498022181f2ed861a7a737010ace939176e3a8e0a1871c6b913368c565d9cc0488396b5134e0b34d88601185fbeb605131d9919326c693fdae15cd6ec16002f688a4b59bb707716aa019b3a5259b43bb01487de7f688cd715541386eac208c9b48af459bc15145a7992ae90b77f00f16c5ef85cf10093e7a8e7dfe0bee2d5185431a4124b6ce1367956db4d22ad7d6d4b25e04aa471738365c4bfaac394ef3cacaac53a8e600784831beb76f3cafbdffa466440363603556eea4384b0f03e90577342514e1517106d04ea679e0a6469a8f7ea179edee9063f5abb10a0810920908d9a1a5a143ae61834085149733f0ac5d832d2dc47f0403e494a1588e89ca96ada9faa0b1ce8ab5cb5b3a613b6ab8e29edbb57c0068954cee3a84a085413b9018b61bed51db64de0503efb5fc4559ead42b53ebd11fe33aa98583b728951e71356bb64006d5dc442fb4e740afcbaa54013c6d15b97fe2688c0b7e95d6d55ad2c5fd576d37ecb229f3f315c4287af3333760c487b07dbc3304d1081f541ee125d8ab3b5b2b0099fd0f31ab1992fd618f1a118a3ff5bee9884dd901d12647aeecaccb0b5928f72726d20c0b1428a02095ee115a98495745d53efcae364e53d4db2ceae68203a1653213b3c4272b41fe679dffc33990a738d24a4f59cca1a579f1dbf40da659e4ac165a4aa95a44223d1057510235149a290f49cf61d6f10f634ccb7368fc500e39e4a5a1cb03e5ff1c05f731f9794b98476848ce94d6dfef475e75eb66d8a9629cde3f10d681c351969c64b129d2fd7f34650176767273e984145756b08b1f5b7189cbd1843c8e2f08d91b001b28c90204ba67fac1fc3e57c8309cf86aae391d1cb4546ff20d02ca7a72917f1d859cce75fa9f3587c709927b891fcd10552aaef40875249efd1ea9b5ee107b47070ec666ff843e9e4f768f54deff0c3d2e4efe8ead106f0623ad0ba78a8137a94bffefbb6fbc8ea73491f0c93c225297fa8c0be6cee1dc84ae1b24a129b6ab1b4836ec73b46fcf453baa786c5832dda23f3c9fad2cb47fb58b4651640136caa6a5863d121fd9367fbc079a78368878b6857cc83ebabad9f74a7363fb5ab74eb8b522ece28adaf5c39493c72c63d45f18fae4d664fcbaba092e9859d9faa494398c02a2652039d070ec315d2c1e4e0304789f45256f106d9ab7aea974420b4888f12d1f80cdc5d6ad24ad2d3cd031e624f3cfb44f671c48e9ee3cb488b538fd96796f3a83b4f5036326c96d9418a5ec8c98f9667e75f738da0da99ef2cbe07809403e66101def5987dabfef43595731ad6bb83282a9d306b62b5e2864e85a32bb108d2a549469b99f6d3414d63dda0c0f46afc3c90843b8afa74cad7ccdd26d06f5532558e0865e5c5a67264600e14a7294c413a75d780aa7a51e8c8718eb62febfef8f641499fd1a5db9682a7acba304fc2c74f21a3a4daa96827bd47b20fe6c846439ab7c881784fa5c8dde746d2c73829b4268fa6e4e5a8cc4a595571336d7cc659b03f36d45202acd85199181c3eb48d8edfaca2b2cb41082ed48fca7c4eb43f6688d619f6cd680fda1c182bb5554b42783f9be21b5d1a1ad07de3c3c2d38925f4ba4556458b2e3537c7a6dd0b94b579f71b1e8503c594c81e2dde500a14c561bc6147aee087be1cfcf905292744476c35d36624477087c2c112960dd21fba7f20b9b46820c34d0c83ae208a91bc0a96ba4340d73f35ad3e488abac47ef282d1021329172e9d22c405a8b71e62858bb18ac7ce17629a8d3a83567d8b6dbd45f0cfaa0fd81cf1f6434ed60da4f0a7130b46a9bd4c99fa6859265a64c1cd968761c3a80babb97df683a86147404ef1122c15f3437f138ede5d0f602ebac991e8785acb9a279059399f6e6050a363aedde20a83a361faa5ec47706d5f4917a775f6d525ec1dee9a04951db64f2acc8623a5e4e3e15a41d85175433746a2142270783af70e423cb9132bd6449cb3e5061f0cb40c58173db1366aa9434103d8a11e5ae4769223f2be2432fa1a83d55ac8c1f21dd2538a6f47eb6219f037a3289af1dd7c874bcc78d7c2754835309d3f5acf1eeee5aa5916cb6d9db48472af070d884f5e08f76ad22e94666bba7383a7ed7b136031ab1638739a958f9f0d06ab3b6513bc8d7218e0bf8ef4cef7ed32cc6b5eb74ddf8a6c2dbc8772ad8cf1ab61bc1361d6db28364a6845550f2085150437f11f010774d5191dee371b857a955ef5c00be1772186a0b27f16383f87e1f9edc3750ceda79c9135264f7e045f4d28f7a046b272ba12b887d03b771f3709e8e1c3a63756ec4028757e2371116090bc487e490e1b031c4c374315c2fc48478780218c23df9ad7a5042af967b69f8d8f211d29bdf45259d4065a9026d21e7012601e6ad92b0fa088b0b775eb2b065588bdb4b5896c0c9aacfe62c25d2176496f6519a4f55ffad94c20c4c477dd4f6959ed11c3be23972470908be52f9c0bdef44aff436f63fe8b44d8e7cf72941e406e9317318632ba48a37f78c04cd553c96fb71bc05e95b9de4d793086a6d1899d5169a0c82b918d01e4568db7b267d750566570240b4aa0d3c86e508f5548b74d26d50c2a4fdca4d3b93240cb1ea35e13b04040234b99bbbc32c88a3421d07ddf20b914cabb8373ae7ad109872ef36cf98fdef81e9461a6238ae470ae67a7214d719b52aa346b2b9e2533c7b02071dbfa1609bd05409b21c6bebd29039fa60b1d0b0365689461dd5a44dbae2e07a8c0992381de25fa7c29130118f0cb6c2c9fdb415e76fd687d0408fcececb3efc02a15a5861a9c5fcca397b50f2dd9654d1a06b8de5ad46faff15473b7323ab0a13b5b45edd16014346d8e5343ac5de9d781797e3a0a184f1fdc4c302845922927153524c31178f8a31c4da9938f36a311a66246cdf42294cafd338019d7b27bc332ea701907bbe8b140b07809e251a85c6a10d85caedfbc509162b56a72d2cab452754f346b15d2884f28add106c955a109398c3a04e510e23c25a6c704ab1d67970737cc2162afb339013815d4933854c8d63dab24a2db281314e093ab9ef19ad3428a9ebb035471d228b2c066c08741cb14eeef5f08a3f71e3c669b2cd3b9f21c81c0243bad9a0666fd502ccc9fe15dbe0057e31ea8ed68b94b92a6bf611ed8d5bb675c9929c56d13a63628f80c0c6023473590db25d315782a8a48f65423f597a63c759b0955910cbbba2315b32c85819f781c2eb747727b7d19cebcb34295b8083039acda3d27b60d30c467b3a2986531a82b549d285adc3e4379ed54b0fa598f1d983c73cc266720916c5cc63ff3dd05357e21b424347eb5a543e209fd88e022b3f2d8703212a28e7eb374e0553f1bc6f3ac74d5a0f8b4ef5b09c64a067648e9d41c3c941d4f9984ed8678ba335ca53fe0abba70c604a11b9a9cacda1decf57c4391968f4d25f9e60a0767f9f451850b85a84b07bb3f0105413092b29e2fdfb88e67197d4396542069e5fdd436c8c5b247aeaf91553fd27c652ab62c7d0f5169e0dc716e9df6fcbe60bb9d397f45f66f999cd5acfc59133b13c9a6cb412b3cfdbc05e80fe5efcc333416f249f912c0a6cc47e1f3901dcfd12c5778448a6016f5f723ae328f09d7f05da583e747c077b36f692d32f0082f0eb6cb50535783d51e116522ce395b145d98e31e2d59335d4e01fe9406f1076c40fe948cf19ec90c7d0a1fbd73409b61a8b693c420ebe0020ebb158e3872a99249f41b194a878531f7c2fbb6d27b7fc8c5a4e94368bca0aad10aa6ae2cf7227b5bc3e21f4676878ffa43eb2fc02511345cf0e8166391384da0bc3250d74d6865650ef76c243c83a2c2ddd3353c63b42ac0e2e2b60e9e367242dc404c6ee72ec8a12a62f5fb4298444b59cbcf89c2443fabc54ae244df255407ee7d348accb76b14374a632220727368559ae095489238f1d4c43a2c4750aabea39dc0ec39f5c815b27e4536f287b36633c712d44fb84a9ffda8464493501fba9250c7bad6387f31dc208bb210f76eb6a8eb263ab934805318f92c81ec5559f0f3716086bf03f48bef6566c4d02fe08b64a2e19c2027b793f2ee46ea2c8b26fe8f5324e70c05d5534ad8bca0e16fb3398ab2e7afa36cfa74d119e037b8b2b6ea3d83ef8883f62d7166d0b9ccde282ded084fbafa1bd6fe2f016e202fe7014b0a00fc79e2cedd494161b1b390d518d8595c4fb203efcb82ae2f418b45b921143cae471dec82de5b824c6c084f1aa9a507586d7631d4554dd8d1be54435926410aee4d241f5ae3aeb632592f8b33861c218a522e973014116a920ec023f05b05064eeb84fa284625f2b117b109494cdc94cb8c4dad37ed077963accaf3b628e4f71dc29ff6fc7af2d83852f9f6325017abfbc60ce8c50c9d8b90232add95015a5e52ad087c108a344c40344e9ec3fba0f6b3d13278316d4e84118bc0f26bf6bea296daf6fe279fc373a996bbd5b2ea50e2dbe5f747dac7d1e04be22068adda31636d8d054c586b9c98432f182126a78efe5a3dac46d3702410c6be5af56f5420bf6741e816335ac8d14049affe3dc2cc901d14740faa232eaa23d9a1f5b5abfa3c27a3ad5845607dcb17dd93deac0a8a8e4e72b9050a53e24a2968061015a35e6f33dad24b0f644b9a8c9e5e549dc647700b1b13476dacb8950b97257a41ea977d06afdf74839ba1469293368dd6753ecd15cf1ef637e03890df6d81ff01ba0c2872a22e427f0bd51f76df101d0fb8a978ed3df0866d0682c5ecb00b9c6931992b7aced9e4381b3003a98b8f69a91dcdf695ad7295e37dac463c3918a35c24ba2a044288e3742250c76d2e982c366546f9aecb8755717de309456fa4f7d47ed3e1d46d1ad4bab5b3c50ac0456b971c7366b01c5d9c6a9f09679aca185deb59586a154d9bb534a0b6c721ad686f314de6ba3606fbaaf59782ee2242ec3ab73a3aea4689b1de73c4b2fe7b5be10ca1474852cd552fa0aa5c356e24e3ed86ecd4725e081ec90862fa9203f3062eb99cbdbe8830e7848e8335fe6df1038973d870cf8803f5acc77baaa0b79485ccc73fae17887e3ec4fd3303685f90c8a0cf61cdee4de9d97a0350de0b3582459ec09abd9052d9e21640299d6d008f7e6e02e90bf90cca997c26b9eaed3fad57907313a3cfb97ee6b1dab6f856616b61f327c88ab6ed5bddac0b435629449bd7e103bbbf68f7fe9ab1d1c1fdcafe06713ef5c4a0c00e27e2612efa3f419bd5b714c5d0a79471b53ea1a6582105962c1b7296820ce7821226d558ab13a7b94c9c09e2662b3d0eee975a9d380e7ccd7de33096ad9a75d09d23b89a03b8c3e3f575299c6f180e16ed89bcc62714c00d17ce08b3b0f2c2b2296d2978bddd9a61491cd128c6bc91d8585636f2af6fa284d21d1eca4f71ad20c0a35900a5d6dd557ac079727d644ac4824ca1db64247bbbc67e328a2f45c876b86765ff1a15fff4c9c10c16bc23b62b0d81cba3e3e11df5aac1717fa8ef551297d6a2488458dd911c197bda3e7bf73afb943c493059dc2870b3506e8ca4da1873309357e84510a4950e456eb3bc46bc865359b9af47d24a03375c8dc0ebd01e576c08ae1f8b9ce5c6b0c7a3b9c83492ca173b54c5e958e7b1061d4cf2dc855818ecdb515c5041bafe811de76ff8153fdeacc4bd05158e111fa2500be4f3af74381fa0e13b9783120c1c58f68522fd38cc626a187b37e30c30222444aa810cc39d6dedec7cb805c900c41bbf164f999204765c2cc623775534177bd2d65decae9f886c36fd3695dfc8cdb9f89ddc9f6974d500980f645578800dbde7e2270619268fd3a64c9c6de2925e29351f780f7d46a4c71394ca7268d3602c24a1acc664afcc8af8e78c7818896bc1a25a5f1ea29acee1a1c1d557b9ba880c3745bffe9f50bd83e4a873518ed1e5366406b7a3cce4a86f99729b36ca5419d7bc73662dae25ddee613fea62ca65cfcceaec47f919df2ac0d4100b4a958d64860d8b2f2d018d72e52691ca4c7891ae44b37fcc6f2536bf3582f8c0b4b56dad97a1026d5b4320086fcd6487cbef14ba61a9192a99a5189987b81d9997ba6e742178a438048e15b6f755bc390b1c8ff7a86ed58e813c59f9ead4887438dc5031ab68b7f16b6444ceeaad22ca5bf58aa0ee60deafd3770ef8527fece159caea8fb59a9e2c26668b40d6e6a1c390b0400693835ec85ab6624a8e54e5eecffb124d74806f48e009ef804e2cc77b3c2ab07795cab75ddc284b05566cd37bd159ca6fd24d7009a1386ee1e0e72d17a9bda593f3421a83dcd0e82c4fb758aacbfed7a09e75073142f91f00d42974f2ca9a71c8a45d73abd70ce2f5c951358b788ef95b23fda906ad106b4294df44b5083801f8e884800f904e7b28f31e788e92c8ca3267280d7d397fa0743646c4267e10066e9d907085a0469ef3036ec3e78d7dde5ab6d325f1203aed490a4c3402233176065be3b7a780e9d09c36b5d7af9d1d78cbea6396fca53f1d6e0bc2895baf2994f9d0c36eb7781e2e08bf7b866d91f0c64be1cefca89bebbbde969bee35f6d5ddadf4f0e520d280bbd87e4581435d516d6c862a61d44611d4161e884ed4461701c8adbab5cd134aad71622bdeb3dbc9ad4d92f7478440a9b0bfdd7c43ac4c0b15bca88471a488f1590edf8883b446609173fd9086dbb7104b6f1a334ea1f92df256bb41144519e8cef4352780dae1f46d74e6972cc1df09e1cc948f730a9906ae0bd206ac398d946199c391d528de553281ee34a53b05d5be8fd4fb0ee14e516d09664d47819130d7832f159d7daba3151a7d7e11a09f78d2ba46dd8c461ddc480566a0ac5403c85f5502dd5b1a9342d20ae9fd056766404145b0463fd959468f10e542315b383340b8bd65bd8096a83dbf0dc7a98cac12b35ac921b3ca197621915be8b7ff768dffeb79d0411217a81dbb7d26c055c6a7cacde22a128eb516f22826a5fe5823800dde5317d55df2842c8c03b0b5e13b3280a37bc6f24e140d16c40cc7a2b04ecfb9b253f6adf3d884aca5f02a247e26b084c9e3d457520f0158d6939aa8c305d4426bcb73d266d4b385daebb42df2d48c29016ba3fa390d1285101293a0500630118e5e0a1d04576ba9af65265d53ebb841394fb5e76f292eeca6ea9cc1566d7410ed4c40c82dbdbc4076f5f8148818f969660df7d2c2d7332abbf98d35290a054d74cf243eafc5ca519e00f82a09bc786d01b9c4882fd24ba335b847dff3ef3ad7422be7ff909215b0b420cf84a779e13107c223d36120895b35416368a1bab5d452fa35a42180d75c6a47d50ae3626109a45d8ff8e412c4c49a31669f95134ae2b47f7afd5365f76f1c0efba30bdf001872ca41bca55f8f8ffbc778afc7e080a8c13bde0d8fd64fba23c63e36d8b2585c668151d8358703081293c07605488956c02b6b43cd0851d22f0b6c50c2ac1437e121c5758ec383f522b8469faf1eb93b32c9140e49abe90f362ab35317ee571df07e95dcf7f2d53771530a4d3d88782cbf4a2829cee498ee5634b4d8d36c4eee76528c79ad99086cc8eac369b60506a1aa26f0a588f709657d4eea10d08b06213bcd55d9089876c78c2182241e819bfba1555450a86abec05f26fcfc712bba3f4669824fc82ad4a0a30ed6925e4c908b7d4d103ed2a532034d563085a3c0a37b31f78deef7629d430cd6c5d383a2e87240136e20906f7cd5baba35314156c402dad8f19cc7844e0652b05e575d7e97752a90a2ec00cbeae36139261250627a9d99a140e6149534c6ad68e7b06f70e442d9997aaadf28ccfc9e42405979e1b6801357b3d160b8088ea1bac351ea8d0e2efc17bb6406573370e0017ddb233424148f5b65e790b83abe90ef101b5d56876fe3c1a8b8decc330baaeacececd2d65758023d9958e9d966eb456d707e40382aafefe8ca71dcecf4ea2ee088f9fe606dc96399ceb8cfbd7a701d703021611371a8eda79fafa8d4419c062667ee6578b4bc98f1143f5b97e53196ef4d389a23884bce6cc331f0feb32ff9150f94adb5a3a2bd0831e811c492963cfe41de6b1f080e2235a0b87b448acc93d46f4a98620333ac6edac2906a9e6a078c6cde340e4f15127cf53497d0154f388772f2491bd0a7a0587a7ab17d48ac2c10ef1130ba2107e046e8be30c2d7df219d254b9896867d3c76774787e26572a6050d6dd8ebfe8dc4c37e5b7ce2b31f01c317e784936f7097c85863e50d0562e71d4ad9671f9510cb2dee75852961c98f2fb3d9d8561f1d85e9b7adbcde8b30c967210b66dedb69b0bcb9e15c92aba76b85b64383c64f399a2bb3a5253cf871b53ebfbbccc597aeeec0c0c1144b2054b41245141cb243ca73d029b213b15d4a569a766462310f7fd78528e79995802902ceeae968b38a5f00440864d17ba3810cf365de00674a5e620b073596038adc27eb96901cda40c7314f63fd77587fa447249b1da6347c43a4a2b1e289037565c4a6c64fc6d0996701630423e65558395f210d79582227c16ee47b0a25a4bd3a7db3a272dd8a429132cc1c5bc4eec5c2bfbf01e06b744824c01db2041652c94b6b6f57353ee4ec01cde38b8b5db90e00b54269a70efabf482b73d365466bbb911a76cbfc0f50538087249f75009e6e194d4e439029c65f80820cca65bfdb0d3c543a62fa0d044e275001a206b6077c146e7e1c0f18944cc4addb1ee1146012094b2f3900cfb7693dc13a13176694c63310d7a035fd0433e266a12fb2ab3290178652b32b3f0ee4e032eff50b08ad1d59b1330f1cb744915f92edeb6cc39c335e77a66b21ebe4531145b31b46e1361147468fc3b44193bc570af9ce4ac09e320ee92b25da1285f935327c0c68e47615a08a5ae62db99ffe590b499ea0af9710c2f67c651c4a49b4934ed8c1fb9fb3a42da34d85bac2c09dac894e50d7c2b5d2646a6a54a5dca55926e0da11b6899dde9fa2658706316ada5ce3e4b85c61359d02165c78e334429a23f2de91ce3b4626009023205ceb1d50ae13eb055a2b182fede06252e605baa17f8cc0a26ca187189c017e0577e48cf509c1cf1a3924302070811bdf674ee67305f8f248024dd61a026a14c1249d533298220b9be36900780328e756d8c68a542b1f6290b78887c6b35064de967dbc126d7b690aceff137af2c59a411ae822c4a94a1a0181b29b629da52737128651c7e8ca528c83f0a04274505337b5e28b32cddddcb1a3634f8f6774464b7305d4dda73d50a1c035c70d8ff82b408624b9e8e1352432815eb206dc35962fe946b1128fb69622aca0231ab4e801516f64825a4d1f27a3a6ffa56750f589c24ba1834a4588b47f0261489c0918e7e32d68f990fc62b9db92706e195b5c6d9e10b6d61797c66ede1cee8c938a44f018b3cd031689f15914c83063fca831086fbc414e9d07bad8e2e83e8247075c7f5df0e090c44a0f8e54f06626275382d22d91f9e9088bea8761bb3971137e3bd0e5595f0f97dc01383bda30a7174a6c6011dcc36750178da7fa78e911f9556218a653acb99c1286ab1b060baebef0a1d108e8c022ccaee5c131af6cbf7f12c53c7e4f1fb4d84dcfb2f1f0b8f3478adee60c95899b8246ff66b1d106685e1f6f06fc1ca8b22afe280004dd20ca3284f9c88bff325a6334a0f8850732953896008683b41615c3fb32857feec858c69eafed4944d458608d5e469b55d431b3d7095c50447f5ea14823b2ea66afeb828dbc6a78d2e260eb8ce652a87ec5158334f13769affc29168ae4a55426a812c4819ae0e80499d399115b5c06bac525c6525eee3770df2b59ea647d2940bd88d3b098c7f299e7ad931099c3f8d14f730d1f43bcf0fe7f9d38df46e877651d57437702046c8354b0fb7b46537c0d30f1f77b913c69b03e2aa89b54165cacd8d9e45e1ef55f656339cf0b019088fc3ba73a0c8af31db85c46d25ee1ab245623a976a1cd3ae0a9d01fab040eb5d8e5995e8aa99d1887fd47a9e88ae6ba9af7dd796144111be04650389c89006f82fce479bea73e6e6f9fba115eb1e8f402f2ac1b51cd2faa47abf0205130e228777969a4fc0f01741bddc27f728d9af3b858ed8458838f0c64ecfbc5140f248529b5a3f1c0a052f2e328c585750361da0b8134ea5607a991ec88bda9770c46f8d6ae440e5c89a88e78e05b89e1756a109cde1ac59150ae150c52b5571a8ed759f1e6387fcac6bf92563667a885ed4085d8fa43d50fd524960ec1eea49b7a1c11a0f06c5b50c360f1daee1f078a74431f64c1ff3b444be21c4aca92d88315d936f3b06dc37ca89526cde13194445717b02998ce76fd62c3478dc8b0b38208614adcfef4509a43a12e52006889aaa5ee009328f2867a9ff459a1b4408eec256757f0de1878e1f62bcf546948186c2dfabfe1e001c9253503a2f62336112d6207a0de1c578e7f53586e42fb6c85a2320bb79db51fe4fc31e2282ecf5affba4fd8b6cb48d9ef8c7f4b72c87be045c4446b4ff3e718844a1abdef9bcac8a16cfe826952fe5aa6885040d2745688417203d0c8912b9ff762e8dea1e44c1729fc9294eb29f96fa9cd677c8a35b830f6c878efd80638196e1955440b4be7bac4154ec875e7c53f4d6b8b67599cdbb95056c59e8ccafe90244552c2ff6d6e65bc54f019c30b161ded69694e7a0fa22181d57a561474ed66d664d2db219f33536928323694e0f6a61c366d301699c3f6da6fe51cf6ad47eb54b71d41fd1c0a1d3997006e6aee54a3238e5bdb71b5659c7d0ee19fa08fe6ab554b2f57211ecdc78ac62ea7312153dfecb615af96843e6d3a0aa1165c19cf81c84fb4cb9ad78ba52c40be28c714199871232b31e4df42f3b532a207e36b234a46b169ae7da855f0cf71a766214cd0b83a669b354d021b3266a40d665166733d90a4205ca8e208b410d6de31a1d1388823f40a2c177f0c854f4914e3e430e2bd1e722336186a2162e41a15ce92f4185430e8d4181bd4267588b740ee47f6bd300795e206f5ac6cf0be58bc082d54913e300d1d19aaf5d3504c9d103d8d021d15379753a40e8fbdba5fecb8ee9310d21ddc55c5037ac15b3b3d913863086944695edc5f6256f50d3acd8f0060a4cf541ad2dfed806a75c45e4a2680d23b3dc55e0f9eab9f5753ec096736122c3b291a28aedd358544e0caa0b71132de2ef1402d7c0c47c4488805f309ac4b8d83bb28282ec75b1201bf091c0af5461a5028889004d0c03fa3bc5074c73c459ba8e7c7ff13bf9d4257cba0c5898676bd86991e156298df5239983e0e11b8ab85a2f50d6b3bd71744232654380d35bbb92e5d8cc6a479656f75e008457007d64ee1ee04d297f65a4cefd2f073e0e31fe22023769947d0e4e86735eac822f5447305624f292363e015d8cc46e852fc5568055abbb785bd1a0174ffee39da21dee2499abd4ab1f2ab7174136ecf209fc4ab6d0b06fdb4c8dee428ebcb52eb8f8466a830aee80a139c540b2ed01acb6309c78209483bbeea703e65afbe2159605b81ae63e815a95e6b3ef91e9a79990687b1016e382e188164307a698ef11869bcdca6378153a65a65792979cc959873d6b3de72296f8a63bb9a7e3b5aca34e072d257f63f00e72017523198634017283379629d0a296ff8fcb964edd00f32b69bdb00c6e80e3b874d91f2702c0e40b5766aae8f08c399a00295006b0ccca82961c0a7176b19088fcefe4d232cd33f288dadd9d6608901d0c04271c48ceae3f7c1e9993a62e1f8e8b4a7bb8427bacb5ec3c1f2bd7d19b42cdaab0bd4e47fa1ff907f8319d0086449d28facc9a1026028698ebaa94aff30e95fdc3d4c45c79e712b17ab3f2e954fdb8d09d2958d84eabc470e88452c8befed1d2083adc1fb086cf568ed9ad1bcfe253143f47cc1a59128040cb9bc6882e7493e563dd51326c1a064b244e56b81cab6171c55ae1e05fcdde460acb830de6104c7c855063a9cf43ee5835ba419455a8a1ee982d1dbfa0268ad956a49a4158e08d4685032e81de8c4559961610a44cf10eed1ca7f3687662c51481a3cb3b409036d9aca56092fe92aca74f8bc55131d35967c65ebc96c7a392cb0ac23256f0ab728c8552deca3c96e083ae0397360b84e11f9c41d81eeb4e43ecf689e133f890d2181c20d599f169c2e8f2e09f3631aa2106c9669c361162c8a81510c38b2986b69e5e2e9d1704d96316dac7c28b2aafb7ee685d89e8d7e176693acb3a57593c6c36d862c2a2a30f8c8ef17d09dadd06acf70191c6501999f444ea3b80bbad10e7ef3c26646142151779e955593cb8bc645b108bd4c93ddcf1e1f5ebf1dfe4f199a0ebac7e51291a7d6717644325816c802f57726bae2e461ce56ce830c7316d957fbf553433870c0fb14430cec2424364c411fcceefeaba45fdd4cdfc8fca710137e6ae4661e3e247c0f972ff7e8fc4762fadd8184bb95b313024ebd9de63ae2b3a0e2c1dd6fcba3080de64512d664c5cfcc93fa1c120ab70455eb276915978d954243933b0810af9f37493211a2449005771aba1f0b11050fe9b2d6624a144cbcc868e59fb8938afed914fb5a28e3d85b57b9e7199d32e63a6d57808c9762e651a8672fe4788a959669c0ad40af0419ceb4290941ba027fbd2043f99be8c581d17c4f7d6f65aa89b059fcbcfb978f315ed1c4146131cffabbcae41d10506cb4f56f4d2366999d690b36891866418e13a5d7151eb7c1d7bd4413e51edcdd180886bc6939aa37bde79ac8a53479de99a762754efe6ec680f9a6c9ee91a3054661c4a727e6386ee477f99e26c160f8d1cc0ff4183db7040a187d9ed0e77f3939a92dc4c7c78c9ed1bd12d8adf8eb9cc9d567806d4cf3f51f1ca742017850bca1de7bd2ccee060860c2c770cf0c0f50122e99c698e45c04c41fa264b12dd0b22e02f25f05ee978c175414dc5422785af196f7185e67fc897a45b64c12761f16ceb6e3909807ff171b8c3d91941ba1b608bd334033f83245a3ed408ba9de6f739f669120febf9503dc0b8edc5700547e292b4c04eaaaea4059325af13b2153712c8e60ca7defbab3950035aff022b095c550cffd08c503f501557f72630036b75112cf07d40c3d819986103057281e00f756672098f5c0a804a3c891d97257dbd8398bcabf9d82bb05dab00a5cc7fbe95fd5b48d5752955935ee9c32edb2966328b0a5444f9d80b6f94892de544374b8863ceb8ef3143b17eedccccda82d531e1fc6b41aa530713b8fe5ff826ee41367b468b0a21c4009f873be25f755367c958167fdc0a4a2347150377ea3b73c69a16b24cd4c8ef6302979e55e55c3a35cc0026121d805c155a68e6aa17fe5671a0750428e416b686ee7490793fe9a1ad74d8cb613893156543f942025ce448bd8866cee44155763191c4b24a25ae9879629b32d735bfe5f7f292346cb09238e11132d4488d145903e6d021c3b226b601fd944d12310e4318f70e0ba731e7752f0bb8239881382bd074664bee02009dfa7b3c49848ce071539693f71b256b49228b912bee6d9f6264a258ad89daded00863084c30de4d393bcb49d284954434da48fe8e9c02935b391f70b424caa4d002c7defce593d5b4e5b0ea1f44579c8a95c2acdf031e43c9f657a6e9e77e6e9e4b0d9568aa8262e076acf5ccd76e0f6f33cabb792807df3800743ee545be550a16ac2345be5deb92288632506f0e9feca75d98478fa0a2073265fb0b4900290cb991947f46edc158712751effd1a48721c8573b849dc6e3bfe6d8e6979c9046c3c3689eaa81ebf101c41c36f945f8719e3b737c006232f8d8c8e52d9a8f1d8f6066d81685cff8461ca6fcf4da700af61928f3a578013a0e05e6ae112ff243bf19adc734262b9ac5493efdc400cb1aa2ba53a2ff488b618066ffcded4311b1ca111ce0d23be27ee83c79c08896d62f81e2760d0cbad8652d00b47af7fedcfa0d64f09ec3f26adaf5f9243c474ff78bf78043f3e4f200c705d61809eebcae4dfb90ce6ab5439df02b5494d6925bc083c6cff0ee154566676bcc1439b9dacf630a1b618bbfeb93126928a035d8bc483dedf91d59afa90bd49a934880e8d529caffff6930a40925a82b0e7e7a3d70ccd2757685e4cfade8ab2c48f22dae327a1eb7ed683491f8d99b60720f38980e9518f0a6df6fc2b645910f1e0ae9f0eb4261e3da68a0dc5d65e9b1a2ae8de4c15fafd9ed221866728a2ee9cc4bcd9ef8a689306aad0339004727c8c09f245208611e6138b8ffab3abe60699fc6259cf4c48f83ee2699ff2f858602a72dada4ede293a55a497eb9ec9b25c1c322b46d5dfc34aa4f0b57a861e859d031b533c2d4cd921884aba562ef3a38b10543d8c88dca1d0898975d52bd1a56577739cb7daaf41a3c0f3289e12732f1d23e029f62ed4718ced2dbc4b6b7828e818a0c6944737c094d8f900a113eb9898ecca085298128bcd8b282ba8862eba6df9ec8cab1ebfb5a2028ae056c5cc102408d5496a7bf0e80bf70f9e0040b10642f51b30a75327a4ec897e48727f96e356d62f41fa58111810286ccf4e919583f8d3b7cef621bd6ebd74cadc8b000b01bb286021164a9bb6686af684031f9468ac3f8c661397ef327ad54a5c53e775d0036ca75b50c7da2d9f30fc00597993d81552cf03b34941664f48dedf350351d78c0383e3d645073b07e07c6dfb69ce645b66c67c06fa2c94d89fdf53d10ab304074c897c92348a9ab829d0a64be5d7cb2aabbdec4e64950dbb4f3014631339eb539edba4b4aea354e2424d7458eb1a962ca9140d5c404e38ba882e90ebfb56887bbc120fdbf4fa11a0c8f59c0311cb9a6743c3bb7c634007dd85fde58a15bbf7621a25472b49ae506bcb5b13b9f2287388af4e66ea6479885c04cbd429252f37dab80ae8941961872d62bb342615be6216b35b0f8bfbe9a26374b5c6c9843a88624d8cd1072a11092cd23dbcbc4732fa6b62bc8a29c0b998547a513c39ca282a7d92881ebe572318fd36ca53393d10013f4f718bafad0811fd1d55076c1a80e8584da1d492b0ef7ac4d47111b865a2d9139e0db78352ed5c58af8cd1973c74bb8bc2b3e4cc342bbcd07329e1b15ff1e3f7a3679c4ea1b5600eb1262cdee396c1881d93ed61a13a9b5d8461fe5c6919960d486d04e68e2a2243854b58a23e051d7c97c9bd42349825c136142620a64bdacd7532b1177e936dd7ca7cd01ac9ecbed38f38a6c0099d9bf6ef9658185e363828a021c11f8ecbd035054c25105206cd3523f7e85e1ed10365a0656485a68c81fa5571ae0ebfb1d5a1a2e06079f616470f4739486a0d810ed72034f38eb28879402e66cebac618225dbf1397775f48548f2e5c6a1bd7daf5c7c38c3915b01d3f1c333b052cfbe129557dab1fc555a0796c6fd3d4505e5aa2399e2cdb96a89755ae68d26ff94f7863a225a24686f88268b5628e976e7b3e5bd6535f99ab975196dca881382cabf245a98c210291839f04efbbf9fd514c3d52333e0a20536d160916f6096cb89d8d8f88ccd9dfd469f1e9c54d5f8a26127dc9441355605050bc062036ff358795a69d963630a456ccc8154409f89f7069f54a070256a984d60370d1e655e300745edc34f26bb5201e87ec5e13eeeaddebb88d606b6a51d9033a860599085c6d0a19ff01c442ee2492646dc5b093d98919de4fe59e4dbb47bd89ed30d39268b12b39eda6b87a3580ae57aadc70c46451f816ef0f297bd374f002300e637dc95ad13c781d407070413bc73b6ad97179f6ded2a19173e21c6caa283640302036fff5090a344beed50f5195e93b64d0ecae631dddbcd2f1e322c03e074c9667d30dd8383a1daf03502ca58be80abab6ec56c64b3fa788916d7160badabd94e80e882a3078050a4d4a02c7d2a3151baed265b35a0b1e16ecd24c837510a9f50ced50cb88948e651c5940f00d5d5e53e0e5f541133ef0f672747941364838012eaf7c31d4613e552fbbe5457d01fa2e04560874b8818704d42cf9825dbd829debc776979534fb7170bd949f975d0d535731fc0008fcd10082abb93523f62eec44cdde4d99bfce445275d5c06687d4279f1b1bc2c1159f8923d11428994f53249f20606f2848c3d91a6ce9373347e8ae558c21b45f726d4993cc01690c0aa04e008dcf3ad4e2c2163389d407da0569861488ac5f27ca268f38730e27b1552c30d48e78af983853b73f231ccec9b20f15af1e3ff58d3af78680793e20447a6e45790bfcbe9cab599e4db5f9a1d142825485528641402f260983a86c3eb207ff48c025d81a419f7d3b00635d104ac709d79c75822b006742dcda914a02db077124a83709e6514b36e6f13a5f6478c4381f28a15c3454acfedb6e30932e560bae883278055d45c19bd6474088816ece1c9bd7ae305f50f0e4746be6b125dcbe177a7d5b609107fe8798daab5595d448e6066c74b168d6c0dcc39dd8cfcc860cd8cf12e52015aa327f8048a2ce50ef41c95df6c133189d01b9d7776a382eddccf5e078fe24e407149f870ca257769365519e22fefa49e8a1d32246865095428e28fd028660158dd7280ea100fd89261c4db7dcf818a812e3a24bb4f6d6c094a69a52944684a87ad91b016d9264a763ff833106abb9831e94e9eafa1b45178cc73fa4b09261c3abb417aff5e6370e4e74dd683f8790eb0fa8f787a076281b41cfd4ca8c03079a748bab1ead7ec9db5023e461e223d08d71b1a5d665269b3cb2b104a51a42e9fe88898db846ae5174e721086eebcc8c80e380910115d543535d756dfc2b8b499041984af4c446f136f20334d005b3aa896223cf04b314ed7ed0a84574b711601bc8a2f665046c744d1bedb7db59a6290293eb4b2728a81f092a3abeaa51548db3a140e0d666af93bf37a3c06937ae19e40321aa51d0937246a3b44a7c97dd916ad4982a20817b845ab4e93a0cbdaad19aba2903a6b7a10084204971fe5cad1700c5caf88e30ac9a31278392ef6834b5c82009a398b1bbb553c62024616fc62c20468988b8c1e2755a17732b16a54e2169bc1bcd820dd4dc135123e4114050c617dd416b83081a11208f7f0cc8a99deabbe7e460aa96c188976194a29b783d0dfeb47444e7d541c4ebadf9fc6d295edb274d09d9483f20b76e7cc13ca51a50a7a7720b38393165c79c1021292a360cef0a3fe3265d89b8008751452a0006758fa61ece35f8c468701b75444300bf4221780d3da787fbfb6278ad6fd09d8a3122c03d99bf5105d350c9be32fcdb693ad6ece0ee8cb43a2428777a50f7f144c11a2d9901533119ac7de81b3e77bd5974fd0e480537e35a0e22535faebaad439eb71b2b8b9d6588cb448fb7a516d37aa3bac1459429aa22e509152c8bc2328064bad70a98ece2f85c76ec5d2d409546d193805f112a6621c72a0dfc2548212378764a24edde3a1a0fe354ed7f3b6756e5579f181206cffaf61e0994885528f794543396adb125e11eb30db50de6385e1cb6000c76ed5c395bcd76eb8f6f957fd1af83879a5084e6942d55d53244945249daf37d91ffa6f798e3b6d8233360cf35e36603117f040ac66ea2f346b6c161ec07f2eaa7cab24e49aa1fe870cdff3f826da1c5dcb088eddb266afc2582538a704496b62d90bfccd0955527158134cd86d603768fa6950ff328a88850712ab8685c350d1eef9b6ad4ac2bd183d7ecbc05bb6944a46b6384430736a65b279c1519031f47adebdbf439d7d87803a2c406b2ef744272ac46d42fe444f5fd9f95f28aa359385f782450c20e955df989f2d8c0f53de3c8dc33e88ecc4befd55bd99b4f1c944be1014aaf1786a54d2d0937569bf9101af6b2fe848367073ba1441be5242533343b7adfd87538105da0e28228905f9284237de07318eba50aefc557121fc49643595045e4528833f9d5dce091cb6959718ec4c3b350aac1a272a6f5f7ea5b6db0b53ebedfc41e4dcb4d2aca841e28e4211bd617cdf74736bc3454b6b47798e80c98df1eb1aca2af5d553962bc8905cfa5c576edf9e5fa42dbd5639867b7bd08dfbadbee3c2c4826bea23920fa81d50989ce9238104eed0c048c6a095bac48387a8a88ce1235f2b74988a0781da5d8b086427be3fe0f8a826c2f3b9e3ed1c6893a3335bab5b0f2a3dfc3520b38988ce324c8c4e42600972f18d26c4a6a12f45a0518a439826e60a09114d2404722acaba86f3fc9fccde76c8eaa09ace4f50418cee21b4f8d4ace7deac9ee7a397c9336e701ea54004c18705c7ea1cca774b95be5d1acd5676207f10c8a219d98b03861e5091a83881cae00ea4037bcf1db741c764c011a2067479c8dbdefb62a38a4887a98628ba1da33f4fbad61bbf49b1c73dd66e3b78678a3f51a3431747a5e38b6db8dbeb2dfbb9f7429fa7ec2e9ca5da87c12cebe6847a37e07fd7aea404383a7177f85e4247ccae35cb4e8dbbfe7c17daf18e4c6455ddfbdf6bcbd22dc05ba0d3dc00326d0ffd72c7c3a00903a24748abd632a648a529304b3cbbd3adc34eea54cd0e81e39d863f69c6053146b7fb64256bb31b6cb11da60eda2a2206c9b1d3ee62643daa654d743d41c4445f652631b037472022aa001555f40103a520749337a2ff74c9eb17c5fd538234b5d7f94b0aeab24a8194f51eb0b914295d6a0661834b85a30fb5282dac12026a46c81ce0077c299cb62cca54decfbc115a33efa5a89c860da1f697b9e45a2f69b07e511d94df6de52a694640a2c05fe043705d3a548fdffff7006334c30816a41959672ce7108342d42087265195c8910028d09593896fbf7301668ab9d8be511b3425705bdd0ff0fed38c1554e432bb5f5411fe4ac2ef46edb966d97c1c2732fe590cc02c73949509dda133a87b33ea8ebfa9182ba1c246efca01dd07e2f8abf64fca117fa3f09a9adffa0eb6e7f4bd7b4fee81e750db530d7836055d023008604a798850058145671dc78811cf76d0e677d4f685d5c0682c1aedbefe9b8b1a7a784c28dcb4cd3a30c0664a0059b057eabecbceff597c3cf4f952a8cb2e99c65c50602dff4c018a4e3851b56d85812c314214364c780af98e224091f3220aa62053b4f86a080e8c847902a349c7904edc8fc232fcc716bf031b44344e767884d2b05432263004ba2fa61f244143ad0600620a0244549b4c072b0e1c36b494d1180978e12ae08c1a8b2654e0413dae658e52073285ac827a90cd163d32dba60e3a20b369f3bf1893d94144c1f2170a88f0e3823707033d4812efe91d8cd4322a7062f12d00caeaf881bc8a4acc7e622ab1ccdc0975e0283adf402baf88110b358055d9437f88090cca6450904119b8f0592a31268b5296c3e174f8ac0812182899e17516043309a184216e3082747b030e6c3188eb1026ba266f3c9907142e665c8b08c8c1334b8a049cce68bc931c5e898d884237f6e301e9b4f0674b1451939b28d49069b8fbf19d2ca9478d07106cf90eed26ae1ce1703a92048cce633812e4a23a288c166d3a20c6283cd37430632e0f10074513a81a246037491067144cfc79fd835bc00064734c655139b17e58f1c7864f624458711f088281d45aaf0c85ce35703e492b42cd8b428b380b6f95e74c1668a2ed8c860f3221fe192c1cb864b9ced2ec749ce85d895626bf2dc5389071df9348a96c61896c06f1cc771bed768c92b9797296220b369d154021b17ba856f1817d8808418d12bede7a05f069ae104ffdd820e9c89fd7f4e4a39aeeb3cef0a89c4f37d2058faff77e9b8ffff7ffb55d03e51a7adf36dc88205c7712dfe398e724fffe9ff3f0ccc8b1730beed93649c2c15f97eb64d9cd384ea145857785b61e6093d671782b5eba8d7cdd925145ca4401bdd1e3d4a173c396128d3952bd6e7b5b54d9f63e67c744a01dd6839497a2aed9452be9ddd3b9ffdbc446fa860074a51fa90ae5b8591b9aaac02e00baaa95333b3da629902c250f6773bdf17b303496d71da8ff6a0e30a7f7fec412df7b747bb8f2bfced41d93aa5f2d9b6387b4cfb9c5de1dd4e3af670abc2b4d44af719504a291dd2dddd34d8092484e8dacb40428e70b1b3eb17915bd5b988dc2aea593ab640fbb6649f64bfee1320a78c0a9e3dc14b25913db0fba6fd1f7972d3722329013d56f8eb8d322a4caee3c49ae4fb627620a92d3bf61819013ef698d6ed1c7bf4f011ecd46a862a4729e4e38f4116ed0b10555a3ae79c7352cbb99d28b0e52cb52fb29da25bb72d8e45ce999dc1f620cccccf2477676667d18aef5f7e3584093bf5bf82a7563faa5b27b9d862e196c6cf798ed3aed0d76d277222d8bdcdf7f031aa822c655326206f1ec9b668749be443f7b32d6fb7c5020ca480bcdd6f6cb5f0baa4b1c7db1ed472ad1fa9e93a08829641b16bd15d5c25a9a06dd502c08c61a7ea25594bf2c6aeb3f91cb8fb689fa8ee7588b7ee62c7e3e7a4942bf1e0ba0e7c0f7c91db2d898769fc7bf14b3c3caca5ce1d76fd4e9c97177f77b79f14755aeaeeef3ee79cd4dffddd7ddabed3dffddddfdd8693649feb93b21be4e1de318d8fe0d675573f29e5e6a44fbb0761f76d3761606a3834278fc9145a9be738f739702caa933b35168d45b5d5dd07ed58645d9c008ddd19449f6406c00dee2f2c615247d61c088c9d72bc8953974ff0e6b64c93631e16f76aeebd3c9977d32c50c7ab51596d04615e0da67acc7b81b5182a4c85e95477e5efa1529d368a63d4aab6738b8f20f48673d861f306e3d76d392cbcf376e2a17e15137853f4a86b9e8775388b0a0911111515a53c968a5197c7fe69cc7178ddb62c9aee777fdc9677db5f77c85fde8b039ee542f9c3e49475308bf2aa3b57558f4f39b583dc964972d679e894568137156cbba559de4dabda0a09111115155199f3c8788ede8b36a1317726cda253a80c46563d99c77628b3bbbbbfe9beed2167f7d1aab6418afcc6c8e8b656dc5a05b96c63e4e8ae15f3c3b4aadf7dd6790cc9c7a816cb4cfff4f2c80c4565f14dd7533766c41c9da2717d5c75aaede98a7555e8aa192bee819626095351564a79830e999e2a65dcce59e1c949953606078333752f505606067c1aa24a7b12e2d4a44a7b0aa2049e4a50a53d91a04acba75895f634822aed4904a453083ad39d999d9854694f40c4004f20a8123cfd50e589a74a7b3af950a53d2da93366988e440712b343893f8e9d2aedbb8b6978ce69278c7f7b825569df7e8ceb930867a594524a29a594524af99cff4ff13f34d3c0b8df75524a2b6827f818d5026b0e84756069562864895245dcbde5b6dcc7f5b1baedba5ac3b0959a45b72d8e7b8ebb9552ca59d42c0ab375cdb43c463d3e2e95d12074466f688de604398ef8e2d22067791e0f0fcc59df9656b5f5c1132476d39323bb3acdc4e7f81df154695b1e8f6409e37ad7ba2606156a5509596acbf3783c26cdf21cc7a9a276ad6bc27730a6836ffff79e6982ddddf97fa6099e2b8963674ee7e114a9c65dfa0cce69a79d76064bcfb792bb3fb295737c87e1b9cee3ba1678f2c6b9a4bc55c0eb3620b9e9799e970a9708e5c81fc3ac87fa29013b81002c7bca752c1b9a22c8d6292afe0f56dd10e42c9fbd6b0aae79186641ff836aa1366016c9457a915c540724d71592abbbd9e1b6fd5793c0ee3367713ff8067ac5ed1bdeba5a1c90fb409c458f66a547b473750dbd75ea3bfb37f0ff6056aa5b5925ec8ff4c63492bb9d08a4b3e146da4adcfca6593e731ba433c4c4d6e4e67334e55def7216bdb9aa2dbd7d4675470e2a3966cef2a6b4aaad152c41424344b6a29bd111bdbd4b86030437c9ed426ff4c63a4830128fec9cdaca715f1c750d0cea01e91a0a05a77ae6aaa6419d6a2dac6a4b12fd0ac6d196ce3ca86bfcd6140aae711b70aa9dce5c0bf7e3320703b3e810bddda61c0db7ad9778d0a14eb5a5efe36320811bc25774372ec96d5bebe880eb5f52c1fa91935a5060de4819a00ffaad6b9a5b1db8f3fd0a667db6ad6b61562a0c39173af6fd69e5fd44209d0d69ec3e48b35ce640bc87754c3bbba9e504b90e13b735f1db8beb376771edb7dbae113ad576257396273423aa157946b7adb78573f9e8d5967053925ca4253e4681dfbfb74c91fa5f3339b9ea1a0ac8a1dba3b20dcbaa564f8c07d6cd6f8170061586235fae1281194808ee4d735bcccceccccceeeeee37d89d4170ff80aa386666073244aa7b75cccc0e64081bdd8b449259af505469e7cc7c0dd5409d666a3594a9531ce8d3dddd5d426a7ff25017ddfb8620a44a16df29eb1ed2804638030f98dd458b1930964db725c3fc029c31b7e5eeee73860919cc3142f7903946864c8c3bccac35653155aabc31556a8f8b49396ef2d0f08085a55199ffe58aeeeefe2f978a033233bf8852a5fd92bb7f2770520aa23e926703ec263755eedc29ae9269dc1d8493900ffa03366aa4c2b80c54e4ca6d851c14f5c565a02244dc16cb389d5aba0c54e45b02ba4650c244052428a2e449141d44143a3050b103262c883d15b513d8fbf95cd71d5152848d072d4e847c04e004162388f8c08b49139b2943cce0460054a4c80744e4a8080dd72f03150112d6c0fbddfd03feffeeefef333566e6999a64d7e7de726f7e99596ea4a8a44658515999422a21ca52b16047a583a954eaf30098a6ed000660c36c369bcdc250cec974b28efc117674ca1d65ed8d54cae74b5a08ca3b994e3a3d8927bbe69cfe9ccf4c9db9d9dddd3d6666a64382823a45e47bff4fc16ac75c9fd3ff1f94ff11b8ffa4fa3333f37b833876fce9e49ea02f38e64eba0ce6628689c9f1b4e0ba8fc402fcc09fb0cb5f4b964f3db8944a3cd8babb3f8f0bc5b9a71eaab4b3e4ee140c71ecb068e102e60507c1c0b1e313c78ebfff0c13a71354699f99993d4646cb788c34b1e02798cbb89f9038e184b4d5f07ddc124bf763979225d317579cd759f024555af7efb6925d46858fc0ed96ed62fbdfeeccdd4fcafd7f77b7e4cc952bcc5c6b8c18210768133464769eb9c2b6fd9464e68a7c66a6cfccccedcc5c7960409917304c251e0f83c3072ea4b5414a394aa9c3ee0c1931301cd6b00eb90ce8eea285f3d8d08662eb41165bf37a0b16b4bbdc6df5b84fe79c5f8018f7c7a0cbf25a1c3e5489c3076646fd77aa06337f5f1751351e46cf80364a3c3886bb5b8bc38769a5e83e7de6ca094b9533573a1040b8718326090d8d291544dad067ca5523b4aaed8e98549154cc7577af6296e5e727fc6933d9c6483bf1a3e4c7090b2544d044254458415332e77cda046135189a92171ea42949e2e727c8121a8d46a3d13e4aed7eba2a684baca04999732e9956d09ec88fcf8f15342b6856d0989052fed4a494424a29965002c8ca4f15dacc0454a494b424a620718414991145b8f7db8086fcf780068d94cc5d756aa8bae9825dea46b34ca14cd73534fed988619dd2714fc7e3f160ffddbafd7fbaff9cf461b43b8f7e5ec9a5e4c2a2850b98173068705dd766620f755007ddb61f0d295bb6d33daefae91e6bc5b09b74ac63e3090693e6691ed48ba2d93a1faa86a753a3460d0fe6cd3c2bde0cc499e1ba69a341e3f4ab3d06e3becc8c54694571044f39f5046241d968e1c18e6eaefab97970eb1ad8672424444434c354da69d729c5a2c8663399646aa8b869231a1a9ab619a3527d000208373e90522828282605c2b43de7c1da26adb44dcee6f4695bdbdad6b6b6dd9e2db1c4c828c99a077b81d5c01a0d4d890788a553cdeceeee6050a71aac85f002bb01d63a2c9d504724a748d9b485b7eb5152bf1bd346c3859247c2ba9ecec63a7c9af5a2d3aab642424444454546602d9ce30bac27466947c6240d1802c876dac01a0dbe9b08e06a7a3307875987f4212f0e100093276fe028005c07d69cd58dd3d65ddb023ad5f601a6d24e0324d3cc1600009e72ea08d336b90eac75a5182a014e7881bdd45e749af519c1c01a0cacc1c01a0cacc1c01aecbbc914b50dac8135104bb33c1d0f76000f96c208239478ec70932361729d4f37a5b3326dd3366db6ae67c9b4b9ebb46abaef88f94820a1c483ba33333309b3663e751bfe84d3e62aa34eb5a5e23cead496120a34ee1ce7cda74a19a59d54aa86d530b5b27248b0cb51027b3a1e6cda6651b3402c60edc11a97505d03b0a15d210897e5eda8e872ed3ab903212128b676562410926258e4e835a6e923ef71993bb92d196cbdf655b689dd16e7f28e9090629d024f7ededea4ca64db75b2653299ccbddafbb0f058763bec2b2c16bb75cd4fa366793e68cc6134e6301a73188d398cc61c46630ef35c34e6c5e61135ffffff3376db7a55b89e3f5a125161222a4127b8c1e2b28ccb56dad52d25a94f3881a5892b4cd4965002c8ca4f15daac8a09a82431058923a4c88c2882089f2854a03ce9713284104d82b0d6723c50aef3487408275f7ccf839052cad907aa54931b4216a49a295563004eddd4a4a0805aed5a2b8514b5da74590370cd89536d39556518b68a01cd9e06bceb27057cbf3f1d8774a238fdf0e42cb18742a345a145a1d128f7f3f37393cd59141a117fff2834ff28341f9969b44829ff7b58a5dc062925e55ac0b839fd273d22a3c9683f3f3f61952ab39f306c420394175854283a9eec3a124fa7643428495481a23384d28732c3cfcfcf10284368341a8d46aba1c2d5099dfdb1de4afcb9e94fabd070b8215ed0bb8ca6027f7f3a87bccb683ee04b75297d24d2101acf4ad9cdb8b2febcfcb894b2803f5307194d4693d14810fb1b94523a9fd2d51d810842c0040810fcc0b383f201b504a583ea01a504c58394f2070543254121411d41e5a08ca08aa088a0705043503ba07440dd482969a81c50425038a05ea81b5036a06a40055935177b71dd07ec398b94253624258bcb2b26737989d2e6932419da3c09e19678e86e25587793401fa8522e6ad219e67147c577b79779b797b57551bb21cd1866f6721c87ad9c653d972d69e6ac1448331e2908d516498824d4352d1214b7ad0e9efd51d7d51a8636bca49b020a66a4a17fa1c695b107541554b981133749630de5bcea759c294475aae52ce5c92efa1825fa7fd05c0205f74562d186ab548a8a29932fefe602d774ca76c86e0e992391d6674b29a7bb3580745d1f9fc72d1f8d8ba2cce26adc72e8345ca552d7c71c4aaaace5f031aad5e2b6ba1e5cae23b1b82de5c9ab050fa59b6c012bddf8e78c2b5bdc94cc30adaab3de654b1942182f6ee72c1fc330b401545b3b4cb8ad832510753ab92dd59c71d286e18ccd2121aab455f6922d7cc638f6e20949caf77291a47c2f8f8145e556ff226ba894359de56ebab86c6142166cc20c2245e84e24f19074a4e42409365f9435e78bda9c0ee726883461e290830d2fa669fb721bbc3077f28587927ee02ce9a8eae4c0e60e462edb49844d98375284e671d6c41927ce8bcf8b4fd7b45ea2bc44f1483fdc261dddf6665367c266cebc91264c22d3c8dc61e24c9c17d9ffe0c2e5f67b80bc93db922eb57983e315c19e8f14a14b543c69b9d46e976e321a4939ea59b9edcdbc293ed2044f0a124cd3b6e51571fbc513990bd70de0fd1567679615539e364bec87da8897d524bde68bf4f2644ce3b2c37c59cd66b3d56c367bad56ab5468d4ac06b2e5b6cb8656c2ef1792a1dbb66bac837e93db82a1e1d86e7b4336846acbabdd2b3e726ecb1bea9a96b7c45dc20507da6d6fc8e5e50575aaa987c5ab79435e6d88a8591e91373434b4828f51adc9ac63257b266a9652eff9ee0e93929ad457ab550d278fcfd86c327ba6cf944d188eafb18ecfb2747d5e961993de1089eb2c479a719934f2c8755c9533e62a9f29eb548b73868208d7c7d94354db96ec2cd2f29aa0b6ac458142f57f2585cc2065a8d2d2dc90ac43ca4f8a7ca5942820555ad48f2a2da362a8d2a23e80f28182a14a8bba280fa05e40b9aed8c1c98a2aed962aed4907555ace418c531555da18a7a32aed494b9516e684832aede90655da935195f66483530daab4272aaab4a7db890655dad30c664e32a8d276ab535195f6344595f614832aed090655da93edf4822aedc90555da530b70ac70acb82316e080e6f044880c95e1c80f1406f52f031d5982834aba0c74c4487704871962908a8ec40083fa721928470b079413831a6064158c82e44305af783e6abd0c947384e753635c06ca01a2ab22078937430e0ddc4e05afe8a4a8df6520234631232f9012c888100da49cdaa24ac7a4bab80c64c4c99c551997818c209937a8dd6520233b501f8c78e0a6966ee025514b0198dca8140d9aaca964330300010563160000180c08064442a15818459a9a730714801061823c6a563a1d08035112032908a22088610801c6004094310621858ce606000017c8c4065e76bfb25c3669bdc369148d411174584935211f9e0b17d910d4ab6bf9d078d10a61fa1b236ad794246a688a93890b6d3c505daf422192ff410deb3c2b370667e6708975744ff4fac4985edf5ae516212844d229c5b1f264926c40a11235d8d089ca45cac51040a626d22edf056fb1e588afb7d534fdb52baa1f5c8271d8233031bb5351be1e80b11f1a1a8a2dfaccc18fe01c9b24c4d5dcf52e6f84d9bcd632a405a9e4c360b00fc9541e21f77a9930c8ccec0f28ca137b0578dd7a123a15f433c3a849e1207517e3299443ac412f0da7bfa430f6c2af6ac6d4c64174b1eb24cbe6133c42c4adf2f429fd8cac74ca9e3ed247fa1a987304f58578af811b9e92c6df755fa6a4a7b1789c40d84a9096657987b477c45fe77f8a192f602524df59098a814ee63bde996946134850821fca4ce20125e6252de2015f040f9149597bbcccdf631849fa7c71a29e1aa308c868ae77bb23f56ea854c2e2a106532fb6efab781279a2cb49658b2b3c74d2c5f0ae70127ffa1b3af5acb026993826ce6d67b125d6ebdb93a4730a486459c8839bf8b233d54ccc306ad2ca08e2e08a89fba22434649d2bf54625bcab15960d304515ca1bd2125f8a4a06922a93ae01b5be8e39a3a34dea3ec9295f99f9e08ab548afe71139a9c40df75a28f10446285c1e8540801bd02f9b27b1387d3f07a99f41e8bf7c60b6026713bd130835e29348be757457c67f0bad08d9c5e2b1f9fc96f1bae61f31847dee2e67ab44be24dd8ada343c2017e199a97a322958a430919877f7e23a375638905025d5ba82518f5abb0312ba7cef86ad91af5984a1fe2b2eb10943136956fdd8816549c5923ba0e16c25d4fbc12ac22ed5bb2ea53096ae09817414865d49a810c9d7af8411a0b944e28bcf1a17eb2fc0b7defc34237a36c328cd276c29882af902820d68a4f08da5998953d06bdb4729f8f7984c5770bd845ce173a6f1d2b9f5c4ec9d053430514e73579e6fb621ccfdeb751870104db35a24897ae90be786cf4392bb0cb758d4720f87c94543d4d7daf75b9c5c8bf0e29910dcd489b7c03587037a1aad8321fe87e00ed6e05826ef550870e33f08b8ad4340287ef59335112a52a6d61fec3c60946e6f27c4f2070b8f355b83ec802dbad37b47099a5478f38fa7a0411b83da07bbc616048c4be200649db55cc5167ff1561060ee84345abb1734760e536580e8ad3303bfc893204eb9aefaee97468f19c2d99a026a153bd4225ae6edfae28040054e0a53fb46bed9a1ddf447842d22582d981abcd7e4617c3016f55a42e405140fdfcd6cf08c38b8b70c45201d4f6e912b3d41ec25773514aed5687643697a91e09308821be997e51ce0f8cead99f8fa73876be945ae4a2fa2df5bb2872433eda6ac480f77bed2bfcfe95c2aea551075fd9909ee4eec2e727527178c2e2721423008c69c94071b5012968e8a70ae91dcc5cf808a859dc881133f66d62559891904a88b76a10067e989cd9131365e873de257a92bbf1875802670c1aba0ef30ccec53df674633b2e77e658a0cb6cf58e4b41f8031d6aa73f5b9750f18ef2870a42fc6b99e5874a2f756d72404bd9b5f9a0a08dbfe9640f0305e6a0dd52042e7e83293bdaf94387eb3dc429ee6a9685b800fa40aa0743c037fc1807a2221f093b408838c7e8474ebee063eca1393d09b44ef41338e4cd5d77eb7e3d747990ad17387e22b1b639581d7ce3f298acccddb4ed1d017c40958132f590b62fe24edea512d5c0229e0ff511d61d98973b93b5ce5de3d349e913e2c9b7991c778e02cf90dada22177600740430567132cba3acf058d1ec9ae1e891697a98a52b198cf5d9e7484f300351c11a94307affa179d4dc53aa7bacdc0635b3259516f18c8a2af6a9759a258f052f333a51b8484276d366a3a8bc6b11118cbd83c8b18c1457f1135488e9d8081dc2dc7041561351fff13f33db70f48cb06ac94ce336bc16c69f43b068b8cf2695569d3c406d38b266a12b9adeba2038b8377a9515cd5d172440f45c702f48ec7597ee053997f7ee9067c8f97c138ecc27880406e99e09d0fd13746b80b8196fe3467e4a66d2891c29b0c98bf86d4e468d00056f46e3c2aea56e5ae03fd725adf8383d97c25af85e367527cffbc43f13bbecff80c45ab06e901576e3023d15664851f91e7eab39a922e179813739681a63828172786c50a6b68d72fd2f6e893842e33c5bdd741d375c56569a964d5b2e79fe4e8b498c3c3360ee762a6d83411926514bb56a043141156ea835087260bce2fe32e6185ae7903158666ea60be19b5e467015c2df89fcaecf22d8e2c31748175a5c592d89e1467f17e7d0bc97e29445491e38c470f8b2b2a5da1098a0d86af5095c4d4842aeeddc10069dd0bd100a7303f4a753c121fe730323348eba71a36df1fca91dc2a382f18da920ab58783f19ebb94124aabb0d01c9c14666c8cc6cd64103e16a1172971f97ffc5039455d8c24d0e41e509bf210d98312b9ecaed49bcdac2c96ec7c045635ec94e48962ea77e6452d58ec94130a8b262cc561112e40840d59a7b8c217a2ae703eef5ed5b095d1d864f3e6ced840a9dc0e706a43a68219d280101a3b13cdcf513879e21759f7fd638e0a9e40ea8a0067c5fdb1bc12d5d80b0aba32f2889b46dcde876030057c2f74140c99f4f44407433b656e90a8f41ef503d618cce2e719d521ef18f19c6a630fca391ed5613e200c7eebe9308013995211900934793282447845d722ddc3d43d904be7348351ae82fa7607e6a1dbb0a8f8f8788a6065715c2073fa5b88d0a74bb64a408abd5666480c37b2d569048fc0e9d317cf901987a11a225868536414f545b25ad3a0483721a38972565ff3cb949b50a3abc0729a3e5a0f8553ac890baa5341b7abe5561c5e971c3b52e24c14824a429378963f9596e728f50edac409e4c13733776b69e454b8f6e6d63af7a54c72d177f4a5f6a658e6ed53599a3c0bb825bbd0bb334f76824c98c708205e3a27a4d16e0078605e4d84d7cca8fa387ac3ee7e70e9b372dd83f37805109d5b0e205fe8eca0dca262f27b385a55a7b56bfa2db2503128c92a5409be581e2ec2617819482ae287789acf904b45a86500456a593d160cc7cd78bfc007580f2365c511b5f9cc03cb5e4e0fd20ddb63eb4ca870dd85e36dd518d1ae04a82c6b1884e140502b9d7faaaafeeae975e7d2a5599e8404ee50394bc3353a63d54e90168f1825b0bf73024be813b8acf82ae16734b47f467996b8ccd668149fb4ef6a89d4ecda43a0b0c80dba6ae6a3a3b8a5e9a7ad7c9f16ce27d2462297b32e997a7df02e623974c49c0394785b353857d9f52d0b7dacce4938bdd9fa72675d562de15dc2849800402844b9033105b5d7156d297642554e8b62ce010c16354950fce03b9c092d8936758be08259cc66a943649e29f381627d51494dd9aa6b00e9727a6344a309b89bfd5f806daa366e6eab1dd7883105b26a09208b3f75358aba21e06b2fd11753f86cc88154c2889d090038ba7da78261924181283f5cc190041971b9de32119d9750e11a7bf861cedc77421c98d641948dadc2fee774b6f6ce040a167ca5b842927a91137ef28cb847ec8f5b2e9882ebf87e5f05e04e80b0c20ac087447c3cfe67c5da2b48fba987d29e19051ab7b6b4379bb0713a11cafb5433ebd24bcbb730ae4c2aed09caeae15206fc90853c3820825e1a2eff2de859a11aea95ecc3bbc461d3d11f375ce262e5f8407c6fe1c0985d746d5d55bc7eb7dd0f2e1702beef0da07d6165d149e30572509e6385f5c6a86b4939ba37f64c2d8e09766b0b61f77e757f600896afe4ca53016d34dc418ac46795250a0819a09200cb8bc7d56663ed2d1fac0d351ff9258d6baecee52571442d2254cadae8e9e8a94c4a431a4fbb684ed5148535299a51877d5aba8a15d296c8d63990313c65235cfe1b8340d7ca551db90a42d956e914bb767df20882c42056c69261008f2bf5e586d0c766ee81427780823ca34e2f2d06b66552512240083e2190c08d8a58fd6fda6fe0ead5141a5b6e15e99710f430960a4fb0b5c0c16f2d1458173565d50a0639f3b0098d70b95436487e0dcb9b29a8224498aa2f5b740b0d2343663cf21b8a86ac8f24668fd88f1dba73613771af2d1ae1291602bd2b084bb19035cd8e0c2c5b688635c7871ba1c3a8ee50333a1eabb5a5e1d6c570bce5b61870e1ccd705ab314cad464928cc76c11cf334f89800239b63fa1f44f72cb7968503ebf3e38b45ffb7b38868e2c2bded7fd20f4bcb401d62c73d189292767c0c93f6296caf08d166486035fea98b54af7c9229d1f03be4165c33b23e2e021be9354c9bd1a2c2d7392524d02120fa4dfea24a6e1d6a87f2ec0d3fbf26b31ee40cea15a0f1a53b986bec78c5977e1c73881b9aea24a239dc5952fd605fcb850ff7130b57b813ff98140835455ebc0a586b33470a03e6deaa98304043ac4c93a5ed55ed7efa24d6a7fb43199ef8ae2555d966a7f33e6c915b0394c07916ee042c542d712283ca4ccb6374bde0aaff924e8d26b25ddf4fa5be9affe9ad4dd31b8989e4e831986669ac2fe78aa0e0e350877f270d5b5cdaa06b20edca9a7fe838b2109e7913035969a1bf0805ca8108ac288b6025b004555f9319506858df50d99d20e68f2d5412f98e21032a97a7bde9f65998a52922e1ea29e43f0d93d0fc290b143d061eb7e91d94f6e718d84ed143ce7cf4a4aaaa6c7b0efb8465cc49acef252997d60ee71409b853c14b5599074e1dff7580b42693b55a250246dc4b655e6d298907a2dea43dbdaef96d7b5a96a0628a8270ec05f93c2b92bb078d9ae8504dfaa0b5f10ea9f80fcb1977d1edfd7aafae57f813ad0dc6c522dd91a86858fded3167fca20ce2149d71509b92f783812752d9a3f4885a00461fec228480c00eed6574e68be2ce5e78dfbefdd39be7c3017ae767623bc2812d0c31fe9d3642f87a3ce995ac42dc8e71f346480e9b07b6064ec5a496d5dc7fa5cbf610b52aea90463a3e61bce091da162c4d337c9faf9d4148ae0a3f3fee7e8c7c4c37cba0f8b167a227258c40ba18b07302505fa3234e4afc7f23c58fd0073f1ed47308ed6ef60276255541e58f04070f1b189d2cf7f1f64f1e07a0c9f9ffada3df5111e1115066fb94aca842cb6a541b9b1e8b123c9063668ec4c3698457eae1d908f7240d9ed6ae055d27ff2db88ade33a3570683ab9b43e6fa3c75389ae2b4c5e2bc2335c06059cc622ce7a25cab732c25c7d87394ce6f7b470bf8403f832ab29b8d26a5f3cac74910ba139eb85420787f9071d9c0c192634ac00bf42cfc370c46344d703a8a50ba627fac6f630bd01e0656dfe12a539d629cff1289d94676d64d205a4c23f1258c917b5fad6b82c590574202e5a34e7e7b20e9add1affcca9ac2933ae01b41583f272f1d60cc536d7fa7387e0927a01459234b132d4f57bf768b554d0c84fcea0a42de0e59a8ca60a80ca67a60aa8378aafda6baf5636d3ba0eae190d8052bdf7175e9f0860617f0d5bd19314b2d8bfff58186612fad68d877810ce3b0cb3d6821130e06bf854cfa580eece7e35fd1786fe4fb806e74247b528f60b782624cca8abd816913d9a8edec2e94f7f04e2b20ced64616ea4476898864b08bec6ca0332894aa60e82fc5ae5ca2544db1721d7800df13d158d5a36c37b9c9430b43a2715b2ba1ddfba9d5d96f1ce8f14f108dc99aa16efa70c3d3e942ca57c985a11919178d0e8b77cd546701bbfeef5fc97a0870a6c9038d3054ca03cb8c4f120258d2d23874978d4c72b23adb700cc4d83c23c4a71f30254e99fc5b6099f26b2b81f7d8e445fcdad8497be052e31febb4f619ca5bfc439c240056177478e943e178163da703052b739d3b0f462bd2731e036c254000446bb472735e70849490e49ce500a3bfa7a6f42d4b0f5d9c73e5cf2d0630afb1cbe4a16f29b9413244557d7d32681e844d6c2412c8da46892211847f3ccd8e95455d572826cbd03058db724b01bf5efbb538ca54df4d0c772a96ff60873781bab0e5497d5fc9b94a4c5b83c5af232121fa244025318d0660f044d544d6b34b62dcd8f99dd9c00e373fe7194b1b9ab630b64c4c93ba98307135070bc3dfb3855009752a890f0074301370ee28b14df94badb5356ac68081615c2bc62c82ad3cb327b372e081d9ee649e51565c3e3755e44acd6ed21a3ca262c3f6e7e7c8d89d88b7c09b060d485f0f67db551388ff0eb05e400306f1982d935731207aa69d30a3ab41603398685f6503f6703b69858a6c280ea12686a6e1e76fbe0c20b1254724b5a2273e04e2c6ff286ab5f54c91717c334cd46e70caf09f07da6730b2e9af6ced3503d791a5800d1dc5244a148d10dce761efe6a3e74356026a288b39df6dd24062623d0ec1aaba113f926cc565c676d036e64fe78170f4a7e2719cd499d0301f8570620036d2fadde038c3db288b39ba6639cb5508d99c54fb8eb07847cb288d5bf961c74db4d00dd6b2555154591f1cb833bdc5473104a062bc519d418dc993b5adea51a619482d6eb1c6d73b63fa13a5a3e8a71b4c73194812d9e8ec00ea33e439b806e85821446dec4949bc918b68a1ca18eecfc0cc23519ec40c62ae12dcbb43b7c877359d93f4c426c28fa20bdfeccc239d04e2d35eb12e1f8bd9829d6b5548b1c8cd96293e9bc7cbc021cb8c14b375c5b116c3c55d87c45209a34b28d868461d0943b75a54373d883c6883b6dc7a7a191ec7323eb2df74eb2dbe42f7cb15e681f770aa49a99779b72b735703d9a9a7a169b9f75972e4dedca7cde43a335acfb03ff4e1827a14d2b2055a5b19ca5b3ae82a7734971cc061690c2433cacbcfd399b4da88598ac8d0cb6242917d5e0a08192960ee680e758c6858f6cce1a1a49931c6c25d4c134454cf81354c11fcce791ff796b0fa894b4ed8b37af957161a87f3f033ad139f357ccecbd900b44f122d467cc9f0b023c0108957f53b020c47ec29c9a2ea820d010f3fe49b406a6a05f4b21d6fa6148d509b9c0419f31a31b745cc8f3d7e6ac2d7eb72dd2c2a7891835a153750cdca9ec9862c0a0aaabdef017d44460302c2aad21a97e02d6e7c797954163143c7af60f52ad8a4fd53e5092524fa8901403056d3014baa8d3e2ea4e5c79b21d7c6913287fe6b865f2690de1c9fbcec7b8c4abf812986ef79c2303fd2246120770098dd8f0fedea5a1af9c313749e6ea5dfdf050d314af5458f445b552c3d0082f06de2d6ff424e5062795f29dd0b022f095e74e6a3deacf743f77a2441936ecaef49d5c47b0075cff4401e4ee9a8847367d2151528dcf2824327c445dd9edd9e84f7e664aa260800ffd3f9fa014e1759d504702321c980ee5c36b3d9260e0594684f0e1fbfa04588f66d4529d1d9df170a3044d91ff5141001b67cdc6931b9de5a5a889d51e4ae094d17efbaf32f4f4910b86e0536fea8f430a75d6922d7a260134b69cc30f88b2564b99a8c532c835f6d32b2ca6ac8009161fa3623690d44e185f40a98e719191905136aad91ca296acca2ca08bf1ae414e14751f2b5861d6b2ac5eed27848f8c8e095cba2795cf67cc635e02e8c05e3a4e965c1b54e3917558a4fef5347de57888860d345fdf90e856918b3860df44fcae3fa093e7f0bee6bf1bf2ac757d6b58eefde46162b815d54b09a81a9e82e84e0507a5409434f4c2013868b2ef044c24fbc084fe197a40779deb54b3a8d536df5de6c5d93db88e68547890c3f90555987329d176a5fe0d9410c9341a5a6e0f1e7f79c7ee0fa23f6c229bb10289b3804d124328f7f75b0084b7dba2ce7668c61cb4d21e38bc69c64e0ea869749f8202db8824fd20238f6c507830335c9910d7d9a1cd65c6b92dcf717987f30b430c9b86dfd35ed56b2e92fde4b200a18e1bd4766d30a9d029af66da6f061253b0f770706299e0c5a1eb94fc87cad3d41b7d0ebefd9afc5fcf424e6a933314e044b1641e2e22e2a8902f808af2c2a87203e8d41ca218b8c81401852532817a80c4655c40c3e129e40d4e2d977dba52597f4e2b49d3a9ca7d7b163e0869fb8cd18099d55f2f73f76af04a6f529b7d6d95a1a442d52c8e7c0d650db6681433eb21c28e8afe3cc49dc7ebe8388cf21a33c89ff2f6bec265480f10e8a422bd619efac3f49ea4cf1d329526d6f177a0e1f273bfefd0540b329160567ca8c2d8c4928d3b9f0cda96ed77994834ece298e2f303280b7703cef1cfe87c639eef237c8b634ded8adebabac42a5b9a237a3b30e502c4362a1df61863a2c8eab973118a951f45b3ac880580cacb60dae4aaef66e723f85222b0446703be8a8b208832fad7c5a9a932e0b531bac0f66b97e564f24ab1e08b318267c2c739fee04938a2ef15ca6477e367aaa764df7856b6d7753648a6bc5641304596193eae07d25d9a4b1a80f8762a6bfa5a431aa835eaddeb6d48589b645a54ce92f969d85e86135a4179841127017f46f7f1d16667afabaddd7db0e79140f36e61013a31dc77e8184a114a1b171d88a1f0883458dd9ab06c28ffde4b0503bf59c321df095bdf216fe31328adabd7e958580ae129125a7162fc2991b8480a9fc9c7f10637b093bbf0800aefb597d22b94d5563bea9b04f33db8c724e6429d5824d5b437947bad43766249ba61f7e47af53cc786cd6291bf2533f0dde01cc5837d6b4c7de6277d471ded92fd9e040b9633b0090e143b767dc3376d797aaa0e656171a89f57fed2c1df667b3501b7f8e9df9e933ac837fd3aa3d9505734076ab943a45b6c4f00bcc446b01bd15f77881fee893cd442282cef605f7845989ea25b0277181f1ca8f392a0c9c229e30744ff79caf2ebebaae197a2c5f3be58741f2ac6a298c14d7c5e844d07aef46d80b792c9f3375fa60eef8f045dc5f223e1c3e406e95c48a50502f5691d8be1cece50d4c63846220a88aef413179445c3d0a2b783a985f416d40eaf744f43c4b79495fdccd59a733ae3d2a189c54070b3fd4a0bbda396c1fce5a6ede4e0eb0a94f3bbbe37330a7c1c4f79c6d769933b2f2b164fe43edb4984aa985923bd2d541f4598c29f9eb3ef670afaeced996ac0e06e26ec7fd6221f7bbb363f4bd8c4b4345857f467c3a62dda7b31f19658d5e17390027744fd032e9055309c02c30f115a71287618a383b04701d9a6451b08f4d62877e7a88c84cd22bb305288d45956f0812b113420540ce1e8082840c66f29eec32ac1ec0e3953e5b2047a5db5e0f3a270611754d3ad782ff131bcf3fd46c6428352b6abd9c35f6c1558cc0887bb4182ecc05b8ae0b344dea44a3ab641d259b759b890474809a962112cf56ee4980f3694bf47d5c3056834c40c40f896c1f687577d45a43cb565113be6c691b518d6763e806a53df22a63d194331fdd061fde41fc3f6d431170692e857aa0aa6c41e1c815b6f8b66ac642e9d576c53c1e97c856c522b7d4c7efef718be179f80853a0661e2cfdc8e72646d4c9c3c231de05c21350400fdffff0bb33e6f51e51d890f80f446bce5c2b1cb23b600f44de3b8086782cb1a2dcf19861059e846faf9fa964fdbce1130c3d4a5e4706c695e32bbc02a3bffeb569c09855b83dc77f9a4d0c0a13bc23dece30dd8dd7d09097d612d152ad735f8951b2fd0d81af878d540302237e91c1fac738e17e3f348dfaf680500c0c91bd5b3ab795d1129b9f90664651e679c5290eafbca86fcc600f94652da211cb590a07e4a05989806cb86bf25080ae10b0fbc376b6ba818d27fb1dd9cc8415948f78c98e170a166002d9bb9da663182aecd6d83fb3f78547b5fa02a68371f7068d69ce6b996d9331fc0724f579b072bff7d7f4ce43fdd4784350205f3f82a7972e4448cd2d4e01f9e02d8d36129d945c86799d1ae11b1479cb4609a6dbf97794be1c190c3d847f417684cdac040f0e785dad8dcfc61f43974797d2c65626e8c3b3e2b3cdfb189858fc9b5456793ff0befe46292be6b1419f08dfc03408efe725b78f28527aaf027051f4685b05e88209ce4615f736f31cc8aaf8de92ef2ea8b95e513cb3eb39c2bebd6ec50da6c9090d53b4657e6dd9d70d25d18dc76d029bb34a5fdcf719bb7beaaaeea55f104613cce403ec8d85601ec4fe9db8f4b6504691144819012cf64c9899025e0cd02122854e5107ba8210fa5f651e854a9e011d9437cf8011b16e6e36724513ee5246dbea0a9d11ee06ed222361378d48da3503c75d9058e165a809d4c056a65799cc52e329ce353565c4223796c578c7d124d1d95cf08c9520b3eea2864ae1387a428f556a3a5f1f452aaa124d463d55b5ad2637576c2691594860efc6f3e41154582461b5bbff1f619b13596b60ed4b7caf584639093fb3d8245e933b7e31ae73a3180b8d495fb32c0fb930b7f0e5a46525f290883112beb93cd1236d02245ade41f1a7497974536252ee2d2f32b2ec5c63507ed80c535683a8cb2d7c2af2520690f57cf895ae739d4f37602c8015ddae31c4a33b2276321ba02e5ca3d005fd73155f1c4dc242f3292f0e72f89f3809e043bb5409a76aab34823f64fc768778a4424a826d80646e0c12178e7140d2e1596021c7e116e1f0698403a711eef488daf5eb1441aee1492015d57530b7b133b6a2f5b04cc1b27a75f49e434a63414e2bd8e3158d428abca208a32877c403a4a9278baa219da406774b56689139afe6140b16596fe10ed858f356e746ccfb5704cde0d1e8e075c37ea0478008300c8fc3e3783fad334b0c5d72f1301329397bad89ca63e5c043c11491291efa49ae88f6780ffca6a250cfbf7df7c39cecb7936a16f80b00588eb0d700494f4aeb2a7c3e2c09380d3e220401076235385663c421a36a4f71261ecc89a0a049e1f8251bcaca1a6b2fbe43680de90567997e3e7f2839d38f340f17344a1234b0120fc983babc39f8a4db9f714f44864a19c8e319faaa67a3462622fb053deb44205c6708a1a5d8c4470aa1810e4245242fee29535e9360202cb46692f5033049f12243101275bd79b71158ba53f3a98678619ce286b243c348280503b0bf879dd3524973a3d94513cd2fe9a78c96878c3aeb236052b2b77f4f28247e041e786f947c692b1dfdd83a38666c2ffe201bd0df9ee16547e7c445e5081ec4cfd6185e25bfe76e268197314c95d9c3b14f4ccd01b1c853010a74bc782c461476ca80c63eae96d1e2bcce65c0866c22f54c4d1dab0f281ad780fca12370c9a5959c54a3fbf0a632250eaf75a8758b1a79a97aba3d7ddb840b75dad81475f420af28ff5e46c20aa1b3df6cb820c9a17f98f0925f850cee0a5894ff1640213ff2d217cea27c4584253393c72d7b7bd05302ddb03a382e260d8e5da8471cd6f0c694a67a36404781fc3a187def450588cd61c3db45121c18c725f2243a417504b51955cb5e3646ab2f1f9331d93d582e9b510f7a1e63d9645fb1cb620f1dd150e66f4624431ad1fc9bd40b1712dc53e63f5002f30861f24cc7d2466d550941896b0ff31487b8b878f737efc865c33b4b611c156ee0a90213090a1794717564bbed6dc2a5ec31c3dbd27bd987b7099a92e3fe0c139193e7abc6ee702ab8f8dba436395dd53aa760cff764aaae0d422c448500ef49fb162280cfed3d98b3afd91dd179f27198b01434ec817b5fa1f1002ce3502cc5a6b15e740972b73bee78534f9b18ca25dd1226c83852a4b9a6b211553a3450abde69f2c1a1a7cca3b13d6d7a65322ac3be9ec86ac408c7581634125f5418e9bf15de246f912b80c4a3c3da206f588a8a9bf1c787efdcb2973b33aceab343aa7f2608461b2a5389ffd20680e87df965799036823015fff3126fc85c08eb42823c97168cf47f702e831640ef1bbc46183b322de5d2e001615eb886379e78163296f1959b4583de94c191bc2772411677d159668e1c5fcd973b0f4338ebe1be37ebe5be1d0a3aa05bee2d3025520cf74a79e06803a6b2e70d171433eeb5f053539443fc115462101b8dc517e27eb15525af886640933b039d6bf599f69303e9d49158ed18538b1c6e099f1b81ebd24d99beef03b3e56e11a8b29afd35cbdaec0ee96e0a230094293b98dc27ba42f021b97381bf0eb38c26e5ac01100082b6cee587245085db1c3a004c0c1a6c90aaf458345970a6c786a785021dd22a890d6c649b625e125c241131623b71154f34462bfcffad508118421f43930a6d60078fe18ee6a04c905f3fe462fc8680ce74f5c414abc9d81d56801001ed1129d2c34a9c140bf1f56ac5b31491dc09d255f0f3f5ebc7bfc2747d1f16e19810c1dcb880376a91031fd5bba5521102e04665332e885f18521f426892743321cc8a88f0a8e859a937d4db30f33c0e5b93dc82c9b7d56aab0f888d6d1f525a13491ed2c4d4377d128409900a228bb2447a7fce35ee69395095cf1945382531e07c6ac0038263ffe8d9b27102cf899b69548d3161579ea7f4ef328e9eef3bd5ddc41aaf5611c6241d7a804904bc7cb85641170d375520460e40560b2913d1151d6302a146efdac21bb48a47ccca7f3852c4a1511e4ccde0772f899243f6f12486e6f38c517771f4e64bc6c4afe835e980552ab6d9a7ccf068381ff34bb11d66d802c36308f255852c6d1089708adc48cb21d1739ce9b86feb15cd2ae088e4a5e66ca8c0aaf152fa8dc5ba2be23e968e2178c41c93b229bd88c212a190167fe7d03e035a4f592615ec15ee616e7140900a3cc0260735c86cc74fb102d554e61f3bad75d3fdeb61a6aba5588ef4be975fd25ffd9ae8f6ab0828dd23c84f510977fd1d8452239a3af7a35041313c81247573059426bcfd51c3760c6775a36b35f9c2692d37c415fd6639b943a4fffa927b33bb20a72edd6b314285ded9d4ec6557a4c7e5a06978e25183b41859a779f78ed141b03521513ef6d78bbcd5ef660c635d21c40171431cbb567c87de48272f626103532cd1608a0b205d93c001f06a4f912bf95f7c453473131372c8ed31f1b84e49c41ff6ec943667a0da46b7a07401d4f87a22fa8a7adef507cbbdbc15f2092e77aca23a7617aaea51e7970beea8314a63827d1321ed895a39eaff4cb1594b759b84f4cf6eac8c1ccd01ab365848508cd2bba84f7dc4a12e0f92763e3839cb893c18c0ca69ce073f02ecab5617e2bd1a44ff58e04c0c02cf8445e85fd197084e72f26333a2ceb04ec17e5b75ff98221c1e4d68508fc28c5342b6061a1f0a33fb9ecdeaed70e183609bc945ad245a4bbd842541c5b4996b76bb71964ee8c2d2c498aaec0811581487bcc1f4ee8fcea0259081dfa7400ee41c714df622d8950101231f04a51651cdc7cd2152f63e0a6f35d67b57855f2b9c7e5f9c7a5110a1fbc0a09f20f8437aa357d802a42126b2fe6973a827b892047ebcd95dc2d5dadb4678f16059e81c59e4bda8d99c8412e5db9fda6e393e6f31e3c77ea06515cec4198cec6ffce25d1b42b11c83293523670938cb356c0c991ec8299989028bfa1726d36d7d7908ea92c92d07f8ce2c7937a5fe627b3b80d65ac7a32b9187ebcfa06baf4e66f3df097fa4210b70fc3c2d79352da279897864cf6236fb32ee5beb92bf465e010465404f4f0834f2321c7b33897dee0c04d281708046ebb6fd466ac4222951d11b4b863e20953a5d609da7a87872b61710b60ffa58ec41dfe7a6e9529468e71d434079493173c28afae6d1025216ba1ba83433d1ca3aec451b83bd2575534fdfb4ade905d9807e6427542473363d26838d09a5f94629efcdb2842e2465cf6f1c3b6f2e53ae436d911d251d6fe8d329a4ac65812d13446c87571f839b265cff92fc19dc21c50246c017228000cfb11962fc8feda94b094181a0b7296600ed222a22a3905bd7334ae2c472bafb84bc8e65e05a0ad2b8a4334fd192318ce6e375f663b8100a5ece21a39fd03e1723c856d828862b47d301d5516ac6726e6ff7956b28b36669edac153ef43897fe0878a0e8f7bde98a9036ac8f440f0e08d142154acd347b0b5cf789a4a8e9970381bd0c95b1cef1b190f07f4a0513249e29bf2f9d26bb1ecc9e9a58ff9245f3cfd97fbc7b6b9eb9316aea1a4072a5b89d5b05f8d1f1fdb130e3be036f0bc9a457653b7e21da4b3efec4f0d8320ad73c66f88299155ee2534b3e88429665154cc0827e752a2d1f49b8bb6390f7add1a36275cc22ee190e99b6b988b908156593f35dd57a9ea3d91c212bc08ac15fee19683e652218a09d459e1d92e126f4254ddaa70247837f17265e1cca2630e54cdc952eca2dc888852fe973cf6c2b84ac8dd30a4c8b71554c210290b333725900698410d57415465ba1e89b74b7fe127a3a559257b9cbf0e9e01c2a5084325427cecd7ec5048d923cb699887090679886a8f9d8d72b38492e35a1d311ca530fa93ccb4f24ae895c31dda14870769c6d4f2560397e6030928f8c76e22e3aacbab6bb20439d271b33a27b8bc3e3724229668784c593f612d8fead6e960d08eb1538b2d624d904dbcd54461d32fde0e11f8f2aa24b516b0c7d6eafc562801b33ea52fb5660d5a51430cdac723fad9579cc35c0feefdbd9159c1ec0076eb81d11c63b7649552ca5a664298de8d2505e0ecfddddad0ba7ed6f184d78ece2063d38e7e9f1cc0c6fdbe285226f6ca782da34f8270f8ad7277c7dfa13187c4e546b585d9f675f43828b6c1b6adfd31cd8b5c776567b5d03160a08211477e906ca3c682fdd629f077a920ba4748227f6362202bb6621685af65c63273de63662977f6e3889a5f08177776c19baa361b03af2ca916ac6cb900041a473c83fb4fee3e54418fafced79eca298090034892aad01090a05f20c370b15ac335a4f8a9bf15b212b9b1cf7318d89051ea2af420be1e8e092ad4c2e492c20a374fcf54e797e7ba6b4f164014769cceb58b2cc16322defbe3fc35fd1c35aad6777e81d75cb459d01e829cf48807199655fd600d8124d9c9c18183698621f80334937b8cf087cc1869d34b8b6cf1241cda4f9010a25746577561988d12d189fd4004524e2568c50e60f7c83f4a95d0532730c819d46a20893237ea936df69a51362eb0e0219be6f039149fb937b22f1122cdc137e62569fc624496b22954b764411931e2dcf04d301887080bb3dcee827ae00624c5ca4242ddd534ad45eb9da464255abfde67803e460467cdcc4d06d524af71e2b33f3768315e8498afc32063a3531305850a288605b752f3632a6294d3890bdb61921e758157ab8f05645fbffdf97ac781144b6671e7efbebf262672e3402b119df6c5c942595a3f2b7ee968c5fa3d2813aade7b89c12ca2a710da7d81894ae7a229e02a97f712ccdf7321d364808f1d70714d2620c62f5de29d53060093cd6fddc41a99206c41dbeb01be41af7cce53a931b7379307156523e887e9e6035c9c296ff331a04c1c43da8e0d670e8efa967e6bd34667405d76fd8711a4f66444f736c145fa0e68bc1889eef4e839c0687ded7964f1cf483bd1d867b4b10cfd4313d06b0c9092e230b8029121102046f3c97fb1423ba9273fa5183d88cda96a3080ed4ccc7c6811a42ab5f51961c0054793c2b1a2a8ba8c83b8d679d2881295cad00336d0995140c5160af7b1b276946bafcdb8b158cc1fa7347fad0b5866f23280b3c0acc1b595517c2e559f6442cbd113256503d871fdca6a4698d20d2bc000306ca8d9013e72ffaa8473a53003d3c6bb874e49b6e8fb4b2829e77dda4b484b8894205cdd9704611721126878fcf1c92132cfcd73a60ba2da4da5a97eadead48df9802405df48802e7fbcd1f51ba1d49a2a7cac8310b8500cd34e3c8db04178b33195640389a2309ba189cb263e21d1122439353cd5f412c52c36ab71256307f7c623fb2c40548d9e6c5811a2bf09121ff364ce9c4431488b59f7295547e18d372a026a0360f3a275484970122932c1e9c51fc1a6e4bc8a1eefb5b8cc44bbb5f76e2f5f7342edb364a62af98c022072a84de20af74e83401038cd5927856b5f20e78519563a5fffc3920ffc2e9417cf8ffd8bad17ef9fa74d7337adc7aa3ff58c878aa6993b2c7c86f1dcb55e0f7640bd384ba9b508235bb1798dadf7cc5d3065a5d49868c324984d16dc7051e66abca35ca7ed67a674fce2b93c339e753cb5de828d7aa41c20ca90a670d280eaae01118522e78fe9703a294b516ed0b0d0ce3f772b27ccfd34bfc8e77088ce69640fa77830d7617fdd668df44c55ea59bfbddc11931c22a24bfd1eba50b89e721421d0af9f5c2756147bbe1776f801725295ed814f516226412d1e047a9408ef45420935d8106624450e1184a388061c63a418800eb9f21cc97b87c68b2caab70574f762e2873809132871610dee58eb34342902e8f99fe483bff0029c187cea7262765dc69cd93047b1d8fd0565aaff880e63a0a89569054e6b31c786bd04d3c0635fa79562ac208e1004fa5fb3da5cc398fb04d61f049232861b45fbf61330d0d1dadffb73002e8ea9c907748c8838d9c4c24837f79c47cb9f83e5f89ff1f277443649c458bba527be9423c2ce8777ced5b5f38bad2ccb29a134edc379022d2e39d62e0801d65b96d8c5b93234d1a8b9304d05dbec8f9aa1d519c41bd836beee01e9b67acb3cfcead7b57398dd6041c472e8cf55fda2f0d4971081d3a710145fd7df109fe04bcecb3c80d7bfa3fb83b80bd76bcb332a4ce804000bff360ac5069399a15e1cb463db8467d1ddc1039d525a43df75c5649c18094344cb6087046a5bab4ec48a00ecdbca13ef2ce7cf31bc41b0b76f8d1c35a145445352c6a66af5ead69af0f1f81495e8b4d99f208dc03b7aa05c1631c1f85d1b3ff218e5f4d313062cdfd1623902465c48586106acb183a2d83453d09c94a2ce61ffd65287ab69d284091caa5cc1129758072eba8071e5306e932834032062d5f3e4773b7c1fe1923adaa052947301f1986d895500432f0b682f6787969f92a2932e4709af2063c07813d817dd4ae98dc7cf505f49e551aa9ccb0bcc7414e85e43e88889f3e861a204f7dd8275bebfd15f8b706b4f33c3f4745c72b2d381d8547d330cac4f052beca757f4c3f8b492d6ba1b8cffd0d8b8674a79d03f4353930c47cb9686e049a416139d0603ea7638d772caaf180d2235a0200305c727cd56e031fff193afa5fbee3d1b900da5b80ba0ff4b34ac0342f9e1ec0f12fbf9b1874679a8c6a203b174f12c0d198fd6a36cb9abb0477989df66ed319dd7f453e08b8152790d8cb39d95489b6884f7fad4cdca3e87f27c7e95ec10141d8bba1afcf48cfdf6b8953c0ca459c531a7c13cfeb327abca4d2e0581f9d7be2c73ac7a6a2503acdb4ed40ba4db59e983e55aba8b4943d16104ee98544d1f1d91babeac4b7fab69db8f5c7ffae84f97a00cb4e50d02a086d5e091b48c48ab0929f569659d8c3f7f5a7ebf8dd5511e469cb4f877b804fc7ebc504aeecfbd3efee2c8b7a7ac1c4ce8cd7ce401b19773287a649112aef25ac95c2322057d2f26e4a03991e669aeb623e6b0e0de84a48a34f25e9d781ee221a626a0683e32a948385e1c37d9d8650246e80688a3432700e959ee748147b2595d4c37067dac072790e9402eced78c6cea0462f7e9c0b372badb850b9159b24b38d99548fa76ab93ba0b6f7fef27fd789b1465501926e0d3448af91f6d43cbaa26546b51163a49d63137abb60af6f678b87b8b13c1a4c825a4474bfb5ae006ac5c334b0a2e7fa92f1c48b74a146296561ce9c7da085ed99c9ec810f0fe52ec7e10ad3738900272efa68efa3cfc65957500f0d8aaa2d01457f8b02faa1f6eac59b2341a20728b26f52dedf3aa7525131e86df5ab449390ea945eeda3367a5c6832ab05a722243c5db6eb3e006778597b72425416510b6e0cdccacc4c9c0d511ff0be6d936debb899e441e5084974fa198161cf5e1b5ad8a490a44a387e6c341472b6ce54c4e12c174f224fb6c3593b92d15351b96c8df27c68bdff4d602b70b8f2550c1df6651758f2387fbaf5564f533334ce77c1bfa594367d6538e17a228032e1b2302cae0d570876de13bce74da3c1e467b19036c0b8c4ef1d6cccef17e34c3993a656a42f854ba1acf3315d62f6dd73268cff797217e86beff6fe055998b5f00deaa9720fc98447ac5a3a0e0cc1e85b56a01b3933d1bf950e5f50d28f702a481f72a911d984b682c4b39a4967584eb8166ac82a09026a900d8f9d94543634b91b483edfbb3ab47919abb9bdf400d2f1f94807f852a8a7bf7a8139dd869b1f3d814a16d0a8db4c5bc8161c66bfd592756a7761fc06e87d1c4b36c502c9f8f6bee861fd7fcaf9af825564fa3914013654857fa2abb94b96c20aa50219b06b78964587e69ec20c310d8c8056624e860bea016fc2b214ccb400b8ef2bf262895e15fc4cee7c9f5a5c46781392bc16424aad3b7190808e0733b72234670271de1717d029e7c23ba98a0107663cbe8960ea49ac5e97b03a165cdc176ecd471249fec85ac1caf9df74750e291e70420393b2b62b76e647a5ccd51e0262ab3169165dcc2466d740f2daed7ae97b091bc4705d1a831a434a264378ecc50e5fabb7303fc52336e32b8d569c541b2578978b91374c1a40166808230d6c397a22a85db3367315b30ff5a23e749ce6142054b35c5ad59a0d0847afb6d019a9d8c6380d31f1478bb90c62ea0c62eae23c09ee30792d767a6f56d30327cac70c5bdc1be8355d229117e7218f298049917810e145e8c9c0c46ca91b6f618bdb66712824e80252f733871c6a46378d11482008aa3b3f615514cc235ebb9b6e5bb3e22a68e292b3b017298103b9011fcfbe1c2010ed591f58c440c265014fe6bc93c4c288417185b3b992fa794231b0d1cb61b702c41ff5f84c7466c0641693eb2a10639098454031ec773fa394c1950a7afb05bd4393c7d56328338e503584fe2481b96c8e39bc29ed117231573ffd914ad8fb0807fe6b00665ae2fd4b2f8e4c7e7f9ac0203f9d5114443b6acf7e82959289b7d617aa1d78a7948ef905a2fd07b7f875b87b0631eee7c78651a2210e5d00410cb5c657b6999349d26d744f00179c71cfb48408c92c6ac03b20efe0bb84813710a785a88599b1ec8e9bf967f37f172efb09ca06bace1bddf5add55f6ad2e0716b4f5da1c16da6b2dd6236d7bffdf858027629086fc9d04f13fc202e23bdb53240b97bcd36894f10dbb7192dab209865591368edf3838e3ed0d917bf2372254c371d78b069985a2cebf2c7c8f7b77521dbc502d31c3585a6db7573ea49aded431759e7c6d8addcce819bc16b60ca50050c34f19c270b1cf127367b3ea4a584ed7d8c45b65b760d26780caf36deb5ec7d90ae1924548d3f1d755d0b58128395eead58bae640a33602a8478c501dc2e552ccb51e94a4dd7e8b4f1dd990143107f3c45e017af867b9f71c91dd2704ae663bfb2729419f03e17f1122e54e08f7d94f60ebcf7376521100c5f2a9ea41a7356316b922faa150e0e3f9353c0229455a9038946633c50327c92c72893270e47ec812647fbb1491e1a6f1b9f1c5ee903a491d4baed0b1dd5b782de56ad4503a8727f78b454dd6b7c27d829ffc5454f094e17c0e39e64233ff4e2de57f4ada7442b32ab421263d9eac72a0f51b912f867e11b694fdb2b2ea1ef6cf2938132726ab718339959c22be16edad268ccc8997ef014b5aee28058921c1daf452915f5fb9846786ebd7097d32f19fa5ff77c19a296dec8c8919f2b84e951e9739ec2afd25ca7a3dd4a3b0109826f48a8a8b7ea12286253e1ba94f3cac07a26a5535208344a2692aa871a850f753e08122b11c8254f5a5b44665154645c5a0fec51519385a849eb230d7e065e01c92a8199e903b72f7840c163d31c88f9acfd2926f5f87f72f964a1e3cbf84d6e4d4d3289b0f356b793658e2c9ea3b0bc79cebcf765d38ce301980327ba5f8a1b507543c1587520446fa32860b09eee552015a4aced03f7ee98d24d8cf78ff895a355a8cbeeed01fee29cc35d2a1b24f0204d7842420266720aa3093aabc9c6d83dea93ec9137f1e2e2b4ff6c593d9acbada32f22f57f43e80a368e2cf73bf41fdad935dc133aa38134c69e796ffc7507fd23bcba21a17e2c83c8fcaf6e10c8ff3117f9e12d8176f35efb76ddfd3dda399314447e79b1b0c6a0c8b50eeaf5daaf0911f408fc8ae2ca22bb725e36bea76647bcdef646524c85b24a223dfd75e1b30ccb189554d32029cb119feb62d652375f76c60545b7258d049e435546deac526f285799e4884ebc16e9b842cd34c659723582a0950e8de7e3a4e008c2116d749af68b83a9c0f55c9a98d7f93a229aee6d03927595fd0e091355b2a1af7c9bc2d391bd256f5310b950d5a6086f45cd2391ae9c5e26957b7ecc3ea4bb64a4d109059ab2b3141a9959dbefc76880d18e78110e0936a2d2b58689de6744b970de4eef9fbe878cfa29919ff8b8a57f8265c20d0b512c32a288b51380c6e529a0c9ddb9158d49c26f6877ddedadbc2cda1ada0d099934b7925e4b4df7eeca51710ab4b17a7ef4a6e6aaffa7ad4c8f70223a978765ef28117917342d73f303954f702caf87968604010b2a20ea53a02ad4d86ac8827d663d67a610aa469b876d11705d1142d635726fd12ca91ba22b2f65ee88bc3eead9aece1e79c4cb123300fccdf5c4683ae1f5cd753fb8143151fc40f1367d156344860869a8a288decbdf7de7b4b29a54c01be06ab0609062ae54e2997744a2ae56efb8c25ed5ad3b121624972483828375b9398125419a3d168f279327042a5dcae2d640e976f216fdcdd915bd4b2ff51cbf46b9335a335d488871c6cd06f0250def7bdd329e7af5acad9f659232816a3634939eb429212c3651d7b12b3f92b568b295162d767cd688d5892d810ac5957c668349ae4f39494fa61874a392b9464f558f2185957bd53a2200a026485a09269cbd64555a30beb4b9ae787bf92fce5c2e259c183f60e16be338557b18d643c10e560c3ae9fa4da678c568bd174cc665d279e1ccfca0a6943c672216dc8588fb7a865ac0fb5cca4652ffac7fbb8f83b85d600b5a035f5c3a04b85e78429fc59f77993ac4ef8c3baaa4eb8c45df5439a75d16a4e68abe6109e132a51a33af34d0a6f2e4e493232d0cf45f318f11ce159d13c45feaa0f6a416bf0f0e03529f0e8b0836a0e4f0e6e561e23bb3e086ab173d23be10fabb33385bb9638d2a6599d9d18b84b891d28bb7edd71819be55913c404f22ba87850d875078b5ddff463dfa17dc668e1ad54eee44e49326cfeaaa68da54f228aae461921d92b4f49ac92666d3b6a99cbc3e818cdc69ae8984dc76ed6555d1e458250b3bf32568bb1205b1788b33a2a3066a563644ad22b4d5b355d5ebce81b14a4652e3fba942e74b62e1717258bb5cab77361b156ab1569c37c629ab69797163a9719f0f5b978faba68f719f50d0ada2f5a8696bdbcd8b2c8678c2663c768d51cb23a1f089db11844bbc668bbbe68169614eeb0f7383ff64e49272d50a48d52ee9454ca5d7c4b39b3c32b2b2a2a2a279b0df349354f492ce43346b3edfa315bcd394f49bbd294d49c1b6b724aba1e80964a7d55721f1742e45aea015a10ddba5b2fcf1e5ba89ab4f43799ea5b9f7a2d406bbd2289da0a4423538835dc0a37b0f6c457d302851a9e917dce38c1872152182aca9d80033e4d9086a080480c52923022851a3f76ad827ea00882a0d7596c9a998ab6ffdd825e7727dd0ca74248bbf7deeb55c9c5d8886b0405c2ad4ef5e9321522ec2144c1125c0eda819fbdb6f33c12d4c0c43edd1684ad86230dbc74ecb841fe82003b904523600b35e010a5862110d4c001a11a7c844d327905120d4834acc085165622a3927828e4d10478ca08f6e9b6246880e1abd1b0011966d8c28a2c56b14fb785413268035b0e5b8e1d361d3bf0cd66038db0e5c8b1c3a66307b8c4115b0e1b0750ab3f9247189c6006187828f082ace0410104dc802d8a2d872db4c187016f06bc021b08a5a3d93e266cb61c3a7690803be1707474747474c48409931f98fcc08489576b5bb843ad1cfc64e2c3a87522c07657ae54b2f061d45438d5759f8a00b3416e39fe49fe09fe19fe29fed9bd38d29152b2547a52d7ed254af7a8e916c1717c702ca9287e2876def7bde7b4c7da12cc4d6dd0d25aeb84db6cf55a8cf1fdbcfab0c3430b4b0831840a470491c08214178678008a253a28c18dc2d6e3c920c2ed20899c1622387283911c30f18128462240e1e88885871996b833182145eb8917300060ba9c40427a1d44d156530b8a4c1f9743320982b9b1636ca2d59ec076de87546f37e61315896e2948d535c5d2327e3d08a97ac82e54564ed45e1c63db120bf9cb3f37415f56acfab8eb3ad1dafb27feae8379f33ced77317fef16f578cb212098bb7eb6ac5766c432adb14529b6d6ddddad75b76e63c46839e13507860af00ba77a4821c9b4d2982ed7581343c6cccceb05a5196d6a60f6451eba193f9a4292a90763c5194b410290a3334367868c18391a632c56434687b1b5d65a8cadc5168b3546ec6edd7e309682086074db76182a68d1a068678707f3f44c00a77ac03d3d328a544beb8877b4a6987eadb5d65a6badb5aa8af1b5d65a6bedf781608a29ac25836a77c67c15be560583550b05d529415365339b5298d9ea986636a530cd19330b73fc8ebe3b83f3a6699afeaa262ae719538a79dd34cd2e08ad0d79cc7a4c6a1ebb5e111df66b7d075b0dcdf61fa9caeac02c2c8a4c69b52fb7225b1172cdc578a6a6769dade962ac544b5438301accf5d59c1a7c034b4a898b7ff0fc7daf5205c1350103961414dc799e0ab5ae096e226b416931d15ac25edc79b49250c9eb5425217fd592504908862ff7e5721488182e73e85e233e6e434b4091393a3a3a3ac2339c6f3e9a21b947f728e7fc04a51477b72bf1077b24e80c7fd51933404029b5d70e913932e7312773ac4d92390f4839927254441145a8a41c91e076b317fb6015ce0787335283548c689153360af27d1e160a874839326272ab0de1213c84878c82d068349ad1162296859828045b3298e5868e8e8e8e8e8e8e8af822bec75ff53f803b7c6f4c86bc211c08e23ce64f6e56ca910aacbd9dbfa8942312802329869fe70dd199bfeaac88b108318c92e99f013cd017f7b77d9b94525a29a595e2c0c9910f44d888820062ab95521c88107aa1efeeee9edaee64491387d97810edbfd4f2f3f97a68751a12b65a1a1d66acfdcfe5031af24981cdc33ef862fd3e120420198300961aa86eefa98ebbbb243657396142c5c66d2c746bce22ac34f5cc10d96ea06edbdbe16ce640263d56daf5511f6c8609b3d6856cbf8ab0b2ed77268e5bffc325c0ea98a52a49bee2c73e4df0c80db513c16eb1c5165bd87a2d0902dd55d3ce7636308e2744f4e209215c6be381bfa8add5c65ff4c55bdab84937eee877bead8640dd98e213e87e0961d712effd0561dc61dce1bfd83fec73a5c8160771977d1b700edb621eec90bbe87f5fceaaee52ecbdf5f1302d08b13e16c234ab036e0639dde6d9fef5ef9766a823541df7a90f42d1712c7c101285cc06206e90f3b16f774fcdfef571589d17b0d3d9baaceba1f86ce983be09772b63dea45558a71616138ba18c5a113243f001b0fdf3eafd5f780d100aada9244c89c562b158a8db8d7563b14a130a8b45f3187d5e99c98886543f56d002d4edc6badd6ea5a865a549abb4b09c58321f2cbd2a1f9459bd46adac6aac8f11b5f6a161bcf816285a95937793a4c3c285f1a265fa9852df582d2c206a45b42a274f8785abc342bec99c5a6466468caec8d104d1a4e0e2429522697edc0cdd5a2c466679c5e88a1c4d0a34412e462e8c54462923d2e86544f3e366e866689f5a5037f1a4a24d1f53b6d46aa79695cc8d095c0d4345445efeac71f9d37c55d6b3174ac25b8b85895b5ec1d53044a4e805e782738153e180e4c7cd767d99174a5e28d9f54f2da81b289e54b4e963ca965a0d865ce922f8432d7b51e54f4443643aec008ad664b28e7c2c244646ac161622d910d4ca0e3a80a235a99c5847be23fbd4726a11b54ce6432d6b3da8652ceda3488bf8f657322e542952c88516b7164b5e71a14a912a999aed89bfeabbd082d688adc06b622d70a1c546ddc432e64d5ae5d47243bab5b0422d937951cb5aa05eb56e4619d5925961b995316fd22aac162323b185e5c4021fb5926f0fc3caa85f3d0f4441be7683e2afd80bbca67e1330d82bff2178d23298558afcf00642a1354a5368cde9a1ecfa2b91d5c29242ad90a035a908edf3a3c5944ca13562442c3995a6e4dbed6f59b3368c367d0c08f32b160b66a563ca91257624cc08f34af3564d168c91a5dd0726d432d68bac150c2bd43298076160605837160c0c69c384d204eec692e106a509dc6d25c38df50259acb19ab7db0dcaed06e5966f2614d3cdebb08a4b4580153242b27fbd94de40146584b8aa095deb1d6996110223071839c020d2a22d191999566be6611031cd9d2442e46e14770a156ede5c35ab4e0cadeaac7458e407f3fe7888e7641d1f2f780eca1fdbe035ee4320df80654458fc14424f2479d04dc2756e0feeaa7fdedaf6bf495c07cfacab3e1e02c9f6bf3e784ee955de4fef3e8a88afc2fb14097d14195f85f771f1fee08b4e69ad36642ed8b4e12fd5b1984f3e99cbaf681e232aa698f2c42c071b82a8369015543a1730ac232e7d312b7bd4b298c79ae7e62f9e293c483c381e28d5ac4d6a349bcc87cbabf0f9c030b1ebf3b8c06b6a8cea5f05988f8b8761a2248911397fd5770153f37c5c6828c9a78e905d693ad311da558baca2f20fa37dc0c8bc0a309ff2f58d105a439fde10dd8c37453734b8c1dde46ea8b0d944bd9b24a47d9afb8cd164748c08f7a07ea9634bdca6bed6b1241e805a3571d65561ca18cd6d681871ba117273c30dd17823e4a6e8860637b81b2a6e72f6a6e8a6e8f779537453e4dd14dd9ba29ba46c5d2a4c6d918acae955f422f29abda47821bd925e59b4b0a44031a4097a117915bd662f295e48af2c5e492daf19cb6b967acdc0d74c7ccdc2d78c26485c41a146fbe2056d6565e56dafc4df740c5a4813e91bdca4affab3a6e54ff3555917f92bf1b6bfe918b490be4113a9fed6f23796bfa5fef6b715fea68b50a914ec4638a258b44bc4a2b184582fb084764dbd5cd0b45de822f8452d638dda840b94b7e93f96101611eb86f09454bac25da59c65155516911af355d7b4b18e54d6ac9a44b066bb7e8c565342336209a1357892b06e40c222aa393c3e0cb1eb8742760dca9d924a57b088b08ac653923d2591a7a47c4a3a259d9286f05712af5152cd188d8611f97409126209b904a5522ca40def4d281921f9ded21eb5ec5fd432fda196691f29785b6cb1854f111380f21edf7e4a28e5426a28d50277d1a7295b0a978ae2267dca425314a4220d690a69535aead22de564c8678c463d1790ec9450cde1f1a1a4798290fcc58342aa0549299bd5d9992215654a0a5773769e98d5ec3335942a4f739f297028c81090d4504e21edfa5fb3ae61cb14cb0741f63fdfdf490278d92a5f42284d1b4e3e7ced3d42f4a774fcde35f8a23ec3107f085ef0cedcf2f7336ace57eaeef1d9638324e8794928c594522156d81866456e9fb06b2b16c2e442fe7d9ed0e3f3bed33c6ad78120f895e5596dbd9756773020023527a53b1212b0809a133e502a45420252e58e6cc2dd67ada55237bacffa84fc9236bd8b4eda608940eae5bbeebb477df7be51e5897a95f76aaa543395bfc4415641955ecd54798e5be50cb757f374d29468483d7dd5c4f1297b42e5d353166ace596b28d4021c4001fa34a8e6e44de9d31f54289f50b59a43cfea116dfaf549cd816d8a42a1503b584a902a47e84ad9ea29fd55e9f67fe5f429eca2547a9732012e34095a48559edf4a797e79a3ca14062a59acc82a4f42cda17fa252507f4abd982a5f44287dea6f943ef53d76a7a2cfbc551ea54fba519fd25ecd0ee53df64a4965406b4e47b603f6e9a4c1cf3acc207c8f2dddf713e8e52b7790a091d8e12efa377ccb587f7e2beea59698b8ffe7bc7c9f7fde7a27dee489244931b000d7caa37bef45b13e0f20bbbbfffdd99e3ae384f506d0fdd7bf4fdd6c55b362dc9dd1a75888b4415324bf098909893b088a3f6a0edd670958687f47366bdfda897f6c2f891434d9e6f6248228c1066dfea21f165972001e655ffc347210b4bdafa40d4adaa0919487fc45df7bfb9dd0fd57da1bac5df3570958c86a19f82526b22e98289ccdac0e26fabeed74b6692dcf8c894cb40f06b81f4008f59d00f5fd63f890fd3d06103182c8feeee58b6aa5735095a7a46dabc8dd1bbef57bc330b4ff85f6ba75fbf7be8ed879f5de1b3efefeea30bc37bce1f789e54f75511d23dc9e7bc30afac084859a2933eeeeb2d2f7d452e9f4c75b9e1410b125bf3ba1c726bfbbe508bbffe5e0f11282ffbee557cd3229d3af3e432c4f9848c72328b5c1ba92ac209217f257fce2d70a82fd1bdeaae6ffa0d429a54efdd63e1002e287f533f95573fcac45519ff2bb2efd29eb5bcdb1ccdf634ba8f1c3d38761b8f2a757d1e7dd2a2a2adaf4272dea5bcdf0b32e8d9f75f8a692fef4688665a971f937fdf0f780a298886882c1fe77034316c5b0bcfea2efa28d0efebc4f1f87cd16f9d62efcfb11c08625ca86864c3f7cefeff6deea17ef7d7fab3be3abafa6ab54fa7e63ce05c9d5a438eee458a26aaddac8ee5ddf5b8123dbaf6bf2c3998795fbaae6d0a7ff81967cd8ee3e2c75e1e35dbae4fdeecbd3ff2c01b6c9c79824316e971eeb1307b64db05d2acf1c1b973cfc79dc27ff84ed8efcd3cbdbfdfd51ebc8314235a9c6a1ebfcef1d99d0ce0443fe3ed767a641f961341b6e7b6e7b8ff5f403221082b74f0b6c7c428ffd40179624e3b73cec5ffbf575ec0a9d11d10404df5b5617ede6e14f9f3e9015b176d79d53edbd7fdfdfb86fa9f7d8bb074b5847abc6c14aa44db57d41b4995ce83adc75dee1af6f3bd7d8f3f7eef7b0f6929a964f34e87ea0e4076abd74972ecea826fd1630e083884d9fa506f9846d6ac2855593ea1722c83760c2020a9b3eca636ec4a66f4ac9272c17a9bf29e6e1b7275b7ffbde43a6db79b8f6baf2467daf3cfd5afcaeff2b61d6757ebeaf856920c34af78a9342a4ef2dea4edd9d3a0c6fbff75f42144db45ad01492365e2891fd45d32c3cb29dd2d938de71b4751c4767299d3d36fd991bdff6dac49ed556a95b8c3fb841f78cce236fd0fdd1effb1c979cd6786279967069add47330f4ba10dfd08661a5a1b34aa704368c2db36b798eb069f9b9c0a4c30b59b6b0d615f9d62fefdd41b665f98237dd3d768f5d03c73366f9847dad3957a4f5039c19e707bb7402c40a24102b92192801dbfe6f75baf7209a6cff5426adb687d9f7097d36e8505985589c107217fd8f529adbd4a935627b82641b12626492c1bd5e777789e20e83e97425b5dd1fb627399cd00b3426d4bd627777775b8776c52c4bf23b922cb69341ee14b6833c03c7073d3f23e4d0517b6ce80cdf9fe35ad0aaffd5347f466dc15c2892ebeff78af7adbabad581c196d8b02b45c16d7dfcd67eadd65efd807bcd9248b64952b0ed13b6daea0405571c19220765adb546830a1b4175a9413ebff53fe4903425065adda4cf82c5ce39f6cb971c24b80408897bfa0f850bcd5b238bed5f082656102df166013a63673575d7146f4dbf9de92e59ddb968ea2f5a0370fe56cd8c56bb6b487575a58b2876023cdbe07718d38c58cbca076fc9b2dac5c6f7b3ae981818d7906a5610c4ae221791cd4c859ceec1ce068f38a3d52b1bbf781999bf3fdee7c5cf8f0b6efe08559a229aa29f21ebaa43e20b8db30407091facf7a1c2e753c4041380b2cb03a9f67d59bd0aa6093f4356e767487521e1b1d3d7c739c2632a4e3cb6e231d4d7c731c263a9af8f5384c7589878acc563aaaf8fb3c4632ebe3ece91c740223c869578ccdeaf8f2384c75c622fabaf5400276a9f38b4983f59368eadeec47c7df16748cdd9c1ed73075769add56b57ea7ea55d44da65832b04da75836b887689c0858376c9fc555fa55d45ae1c5c23d02e222e1d5c4554b48b04ae1dfc553f06b54f1711cb76b1749117da2573d70eeeaadfd29e8f9337baddb988acce0e92abc8d677ede0333f66847e82acceccd00cd14c908c241955c8a8c96822c326e3898cdb8f0b333e7e846ace0c0a34455647061419538c76952165d7771191a58cdc1299c60d87864bedd6853d4023891d5ccda9bf836477a4ec5c713a7790b096b5feb6ca9f20eba2a9d118d1e0cc708c90ac0e4d11ce6b1c221c213843da839c075554d383240fb4c8020707c707ce0b99051b548b6c6636336b6354cd6a63a364574c82a0da218d2838b41d8e5f1fa709ce101ec36127f11a3f43280eedc747d581f9fa3f4130dae648b5f19536b3961538b49af37d7d1c25383558924d91c7c8af0fd3a2eae0f8b099d114d9cc688a6c66344536339a229b194d910d4d569121d4107bff9145a39021414030c4fbc0d4164b1c1a52e4d366f6e19021d40d7ea73d30a44444bb3e481feb4f0ffd04d11aee352706b2e9535712643568f5b7adf67617a325536a7c5b586ad84a4d29d48acaa9b42ab194cc5eaa029a181f3646413bd0fb28052fbd94d27b29ed3a5adabf17bcf77be9f9c1b8553d140c5001374005fc23c280ade3fe6a841caa5a75c6f1bbf5f558e220d7f38ed5aca5cb088d835aec4fb07dfc5dd781401ffc1bf7c112fc1e1bd4677dfc62edf179230e7a1d97b2f0c372842719071294d64c6bd64c5bab79556cba4df67adf83fffda7dfa4a19ea1b5d6daffacadd6ba635391fa1ef8511918987192e9fb5f0bf2a8dd574500ffb416c86e0fe3ec75228b4f7baa48ea1e3edf88811e3eba878f9337e8069f0263f9f2816e5f3ed743f1795db54044eab466ca8a52fa9363a43d47b83badfaa6f40bf507ea513b81c172865d00b65da4f688ce5d6c0d5517e2e8ca9e9ff03faff32ef4bc1e15adb1a22abba235563fd5aca58dffa335f64713b1c55f19963f2f3d2f74dd124f02c14fefcd2e2f469007e0ffe202b9e7fb520a32dd1a03f93d4908360de1f49191a54f111e2594e04964400741fb960db0506cf002bd5f09fadff0ef0dc3f0e6eb2f5a9e40d6a25efc2c794384effd6ff87fa5dd62795230fc4f87e0f74190fc8f1de3a8e64f8f36d2a38252690dc2874dabb882e8adeef3fbdfa7747fd0f35373c2cfa1c3526a677c945ad4a6efe995c7e214a21d81eebe2f2188392abac4412e89f737e9d52c5d512cb1c8f5c727c9f2a47b14e9586291e98fff5e73c6f14fef7b2c4fbac9c75fe9abace8fb8d237db2145fe55fb03d8ddaa2e8a40dd3d3cfa69c5f14ed98f5e9809def03e8a66f0261d4be3d0d80136c27b3f818e8ee8efc91d440779f2a7ff5e93bcd23bf4a3efdfd938a4a59cadaf73de91239eab3c71e45919a4a3a6bd335e91efb62f229f9257d3a60833feaf045907e106a8fd99d76274ac4b0f10c24ec97d65a7badf802ecbdb72a8e1f2cf2e934fa4eb3ee53be14a0fa807f521d0fea9e1cda477ef7aba28e3b12bda54a92857230afa480f75ff97d0f963d7c72ad2ffa77b873d86301fbaaca7aa5dae90c17d15a2d35479841b6f4ed57935293522f65f796d4863c46d951ec8bb50ca839753b212201e846673ad8e7b84faf8d42417eecd37143b97dfa94ea97097d6a5a076ca04bdef0289b46d9b4cc3a8ad8d23fab83e3cb385e901f47add62a9214b6ad600656d6bc8944d5fd96ee25acf6fd19b2ebacea99f70973ec30ed7be85e9a13fb8a44dd13bf1577b04d33d0a56e56d3bf9a4e9a2088a985fcbb5695fb0b20f2e934557ebf7f029d4036e3e771bfd3f75dc7f821d38f8124d3f70d64c910aef711d8f529016c99e9c656f3b8efdf0d4055aa6c566520df5ba2be27ab7a6ed868e34f287cfb609c1da884edd7353965340300000073150000181008068442916830cef254543e14000b7588506452389646235990e4300aa220438c21c410428021861084a8886a000a94ec377a98db164184fd2ca107bc803092e20d8afb601d4a1831d5f538326ac5ff87e9b58b9af2dd0282cab05aba9dc72a5ba24d06ec72cdf5820c1ece49e3510a2a430d3dd286cfb5a2c8a5a73ecaa7958dc1e3b8a5a71915079d91f2435a0ccacb949d9cacd2e9b82a295e49c69c5dbffee974187aa3e20db41a2667a323a01c281e98f5b054c2e4bbb818f797a5e01e05b1d8d437c6f1c5671114119245d029372eb8035cecac51a41986fc22a2f3c6b27fb1c71c8b930eefcdcb45c45f1c3eb1cd9680a56a998938e5d9542aa73c6dbe10dbb27c4f0afad2e77d2634aa408238d5a751e9acd25ffa07b29ab4c0aa8bc2a14fe11cc52bd4a901f6fe5ee1e4c6cab29142478e4c83de2889de935dd6d3c7135d0e45f06567e33fad05c5e792bdebf0ca19cd6205182c417986a3286ed6b8af8d40cce5dae75615f9932c10c1701868de00b21fb7aba3f4e45c36830741d1502a2b97be6f36457cf96fbea3407cf354d7d96574a9a0679700a230d53799049f9d6f70a9bc2a457d49edb60905bd38892ee88a2afc3fa0dd39cb576033cf47f2d9ea70ca4e9e4f6ab2e1f15b5101b53d91ba3dd9251cb4eed1098d9d445e55efe08af264369cd9935af54e647035f32b549177afaf3961fc934b2ac0b77596b5de70c56db73650915937f012c7bebb11390f21099fa53e745b03b49c9b2ee91394573a0379c4e0c2d3a5c52f81e3160c66d70e0dadcca2151dae51da25aaa0154b38b80134bd06ee8b834cdfea52567f65b2f235ed5c15bd91b32313c1a05d51ccd18818bc9c41119e7c18f82764aaac8c145fb0f508d48a6293aa7a3557eb9113ba7f27ea2ad017b074c4deda824ee165a8f00e3c24eb160a7c7b74ce2dc4e6455fbce00125151ac35064262a36bd5bd93661b2a2d35cd717c8439f22efb953ff6b75bfaf5da1d51e1eeef6bf81809061ab369982fdf98a97d0254c8c0501aa0aba290884aca49528a684f14b17f77f2c25455a6b2dd4ff681e08d13837a0bfed743c370b9243276164ca137d171dc5102d22b6a93f1627214993c4393ef079164ccbf58a640771c3be274c908cdd266a1909acce27e091700171e53ccb985ecef4187997c290c7f5ba1a51846d5d0100c0a63804695c51dcbece06e5a0814e17005737a06d4275055a0b088d482a6cc637dc6c58fda193845657584da07478d52bb3ec623431ac18d487633ae6a611e90be9d107bab8dc363d618df2994c7408f7e1d9c1121e51f15aebf3166f2088530d85c550ae2d5c85cd834c0ae6c5b711c4e4e22d74e7dcbf48d4eb3443eaa1e12d2cb920fc4ec22941579f082be1f4af184dd556dfc423830fcda70dcd5ea8dbfebd505254a5d914b007eecb4051f747613171626f3a8ada7d0e201032726dae64694a57177b757f512407b021fb8d0946747bda9b08566cfb569307279fe2236d0c4d3a61397aaf1cf1267c7836f3f3cbf60c78d08ce7a454952125f63f9f15cbd0fd27aa4a58d2256ffddb05aa6d4feb506a20ffe9f846b1d7900c85a306a8751ed40966b9924fb6a04665e35d5329667ab5c7c32d1511303b4381e60104abf920ea7bfc972f70be16297e32cab58367ff8e2a955aef1bf5cef353e72606fb210ad4d723d8c406edb95b3d1ef87af4b2936a84323c2e63f77a0543371f4649541dad05d1636a5139c4420f871d3d36654bd87c6e1722aaedb69ac192eec761f75fce573e8a22cd01852580c92719f0f215f477523deb7f5c8213ac41b8cf55c1709055d3b6a6fb8c1232fd0d45ccbcb1f36843c091229233fced0c9cd6de12200ce41448001f803c41e73099f72d50b250d6631a6c97f61e049233b27c8c5522f169c5a8218b8c48c1b9a9841b02325f2b6cd1d80fefd6f668fa9fbdf587414e75771387e0645a57efccbc64667e22d272776a44e89141cc1a6a878b45ae74023703afc1396018330b77a05261c26d3baa84342859c142c242f52f53d6944581dd2d9ee9de82412ab4690fe61bae6003c5302c4e0b401b3302bccbd65843a087748cd707c8f9219be551dee5623d4b00cc7a978d59cd4136135404f39a35cb8c53dafc827df415ea6fb5d3ac3d1f7d03bc5862c5075e05967557c6522ea35797e964d41cc7515a45f83ae3773c83aa1a3988c7dc10d6c60119b68096ea7a42072731eba73814b238b7decf8d7f9ad8e506d0b25f553c4819ea108a6ae57972d417025e79aa5ebd547b29553b22e090c17e1cf66e48dc6faf3f0a24c37a54482cd3f331fd1be850abd32bfb9a764407fcd144e9731cab47495eddd91301bf3af0242e857beb8d2e35c09af5333386cd813e98b84fee3d9c0beeceb7f341971ba41986075a159ef0d3d7e162fb6358642deeabb3212e2ed6ca903da27f273afee07721e7313a441e0502d5303e268bed0e0d8931c17992e6423f597a1e661ab8f71ceb6c8d0fc51feb20d885192c409bd7b0c756e11ac3eaf82d8d8017cec21b52e35b6496687547e777e300cb0c4389cb6c24325e0920aae4002687f1015e24ff25476f3c4727608c24e0b88a2e7b4a70df1ffcc66c840d4d6aefae3103a928e60c6260a08a29cbc136680f61e69eb48b83c30a0284c87748fc9d97ea4db5c6c78e91182d66baedf978f5cc08af5ebe6c5d9650cdbd21fc4f508169ba65229cd999fd52251b126bddbf416620a8cc3bb631ce880ab3c2f4164e95e1cb6e00a35e0a815a81d1fef6a587b403e41347e56907495c59df1c043717fc6fa8e24cb4913088d20ec5b6ed28de2acc95ac65d8ef8cebcc2800e890a1f186eec7196ea04f478b6317a27e38d214619afaa8b9d54b5a253af62230e27636edccea7422290a37548eae1feae60e2036cce62311c29c24a84c4b6d99053a4d7c903afa9b2e2760050c6b905b2c36a46e9e026fe372341b7602a82314f6e8cc28a41bcd4ff9c09520760ea94e638060c31d7a25072348a232de7e6c63d126c0b353b7830364a57a0d90569a7045058ff046dbabc1b9293103017a369a44aa8529642049cded9d46a00e50fffa08fd4d533b736704c012f69ad6bfef1817726f6b21fa6bb6ba619d9c08105c57b13bfe1a513c883e108a1106ba73cea5a1892b80d07ac4659f994154a88b8ef01028f01e05306170996bd3e52eb1ca3447693c5584e89f20b36453d11526f89aa707d5da65621ae36a28da0dbaab04085af70023fe769760d661f5003c074470f7c69508f56f9af92cf751b4fdf128b76ad7f71fce169e67d9fcaffdba3ddaf880e64aeaf24a111c0c87e8aaaedd51d7b27b4502e33b4afeccc7e6496ea5952adb80a5ae5a178f1b6cdabbe93f32d15ff978134f7196301d401463d6616630a8bb4d18c3bb66671081176a38925051c4f5f5c075da68b1eb4e7046f51f3a14eed8257714e0a8c4de9544cf8942a40ced808d08233001a8751b248186abf30a55185559522a403eaaca26c68ce53c06862867cd590f94799a019e6dacfdad319574cda18e52d4d3b3834a1fe6cfb9282d3805582b466e8c05c20c97c9645dd8e45d78fd1e005803205688c51b9f145aec3372e66fa53de2688b0e9ca1d4ecb03c1aae679ea07b640e21d57546c23b5ab8bfde38e4b3775ea9308150a9cba3e2ef9479758ece2aa9b834462bed857f96e4f60b367c6d8cafdbebc0b33f48780e9aeee929d1d44dc86316e5a5ce2f22f5fb161c6863dca2d3610007d0d80b02fa1e5a012fb7d7bc07a6ccd81f155b72945a77883f4cf52bdb4f0c5cf82e0c65494e2ae5ece4d809319b8406a549b0a91a54e6a950097405a1115e4d68e7cf3f879425f04f47b3d466d752710c0f4d68c80286d7a8a46f62a0cf16acb1e9e6c6e1199663806d3cd903d8fc728fd106cc027b992b68a9c3592cc19f0ffa2e0d4f75c3a78292a183dd3bd51236d8a1f6e25302a10ca30e368e19cafd0d677c1c8f682faaf933d17ed823680aac9ee01270887d10b7b79a818e986bb2bb7dd10a0ac86494c941dcd05dbb28181f6d09d90fd655ec2d2f81139ba5b80af877fd2e0be8e6ed62a09c5e08d7bca5a5338fe727841ef32732cccfa7e7eee31c8b6027f4c7fe5bfd0e6631504ef0e117d147528c31cbb4325d81c10285ec0380162346ca6984301c326820228f80442414342dda2f32d482500273401c9afb3095f172f834123880c1444a7248539b132307008e353b33a80f74d118406dd2078b593b6f744361f0799cc566adba3b70b7bb389d59b84294bd3bc17de327a076087b3c2d89b0de0eb2313d326fe86d14f5bb2f582e1c8563ab3f64b6ec8ffaca352c82d5c3eaa398c0652b09a5fdd92e90dbcf2fc79173b56e0814e89e965c466544eb36af0b1e4bc01a213a042d563b2b55540ad7c6928146575ce1b817ea151c8cfb7ce0ccbcc52b344ec2b4df43122a1a806d77fe86ad165b403c9eb3ce7f3dd123a37b1a7b120944afb9e66f1e573c72413117e52aea858a1f13cf10ad9ff85689fdf2f2e1af939d99f71ed8e46e264228ebcc61c1043c9189f8fd583534bcee9bc003443bcd054aaa22db0c8c840b3a50109a49d1c2f79f2f5be1e4d0aaccb1d3284bdd41cc54ae9e4adf876e35a19547695952be2199e7dd8104eb9549c355e164d1af5c67b250f67c8d8fe8d9aaa0674eca7b4d7d573c6280e5218c01bef7700abc165d96d7f6ff8e0611d6cdc76c222ff855019a05f7bfe475334db83d6d9ad56f085fe80cd75407b096560684ac5e19b9fae89cfb548132001d521fdefe2be2e2ff0a5f4ebc7b5e49115ce805eb67004b121a5bdab8b70e45c475d3ee60bf1e33b01f031b76f8a89c6aff35c2b35a89190a171783ab7137d90ede2c07b10905dc317d07b1118834aa4b40f3f576a00da5e3dc3ad647400a27c0e3e95f960908740f246808e716885d6edc4928d575005e00b42380e663d3d3823cb7af743decb57c63a0b88cbb4c4a5462bd5f1b4cc0915111ab7ef0ba70a703a184f31808acd80e7c3fc10cc1a540001caa38d4272a977f3eac5487ea1d4e093fedf7dd82ad7b4de6879dcf6524c5362ca3756196b83ed8e3a431aecc77fdc25a64847f75785b8fc85e3317d554785719d5c877dde3616b15b93b2702b74192d7278cb7929851abe3168b73f31fb31e4275db54438f531acf45a0dab100a79eb4fe11050e8519a128d91c9c30873cc91d9ee81b21e4756363eec3b7e10b2feecc4c285f64061984e35e5e06be415d3428e3576b6db261737720a2c6d78dbb94778153640c7a21eef50bb2ae67ba1bfb1d07660fd597cae1288098134e1568ba611acf2755a964b3cb117155b491764c9e2c62d1138e4ffe820753e69a4f9cb05ff920e46bf185e16e8ba220a37b8124da3669b1a386a0619c07e3f3a03f84a568d1373b2f63be859c964bccb9aa17541611c5dfefce4eb5d33bdc0281ded3caa065c1a2e83323a3c4c7887b07a8e6f3564399b4a8e5f6e4a554b029a166a7b8c88e987ebb704b7f3f4522c92af1860285fe84179096b732efa713068bf4aaf9fd9fd16b9f79dd253ca3c4ad9372ea87b92fcc8985086be8a94efc9ca87ce2535e72a133d7c5c94cfa9930073dd90d76879f94918145fb3a680b0d434491c857e19698fa0dbc7f3b2486b0168255a68553326751032b12742c8ed6d9311c54dd3fea4683cb2d6548a77d323f51bfa212f271eec42992174335c1a3764e572c25be136d5c97d528b23fb868df00f7b0e7a1359a066a1a569b8625bd42ce7c49093ab119f142a984d07d0acb5c34784c4e82b8bb0f360057cefcb93812895a3ff61f8746f89e576c354d547563cd976fd102cb02b617a6f103aa597a9568221802c1d5de32f7eaa212a7987e5d98e8369fc0b94382901cabe7bda11c1e0f3a26786f010f2bb9a19c8e6d16ec5adcf7283114324251b6fa2b23e7ba5c3a7c8078c2d27c0ed2f69e76a4a65d32c19811912b6bc52b5971dfad11bea9b0d582a28e2839105c4455bb5e18227a17c150151a877c02cac9544df7f4af592d951e1562603e5ba8f33ffe9a06307914158ddf0adb1e8424b5863163b30bf95e94545f3e429256342f086be13bcac0694e3c58a287a01eb6afd0d56fb01c06443afa1f54ae70b1bb102aa2ce18043a0ef3af5c3b7b2e64a9f6921195cc1d41b31281f5c022fc97cc53a963024963394bd10b5ce19a9f30ed9de99e7fecbda8065d103190d3c3e2f669f56742cd1f4094832aeb76bae55964249bbd14bc96458a36eb9df492e1f82ad495317bfbed7fcbfbc3ac742873fc4d58ce28bc39e6cf8e6ff036b6c0119e44a303bf37b311fa97026e90e7bc676c9c31a579801e116388ff6fc581c7b673a460041e5f67192a8dfb59593e3c7a1e946003f87834a4a424d53ac31487f664a6e23ba313006f6e02b8b85c4e71e85ef5b1c3cb10888223b2a2daa841f1f207aa8be749517211b237daed9daf58c6b556f7730bbc7b41b30617875f91de932dc80374e576836a2790131db99033370f29948ae16730a90a2ecf02d40980be967de3b6a855cea56e09d7d09f8c948ce3677e1f28a9ed399f54174e360e15ff451a580fe1c928057d60bb00f6dbdc4f40b194c0299c83af540dfc96666179065ab7a950061b423b570a53462e1b1b34f722ecb0913d0e3538a8b390b144eb0375ce75ae1c6c8edd09d6393b79737035ddb732b0f4152fc0687c70b621c77077ab1754573cb00d5c50ca529063242e97c70ecba8752092dea05999ce42793ece5c1d09ca62acac7e712c515b11b008246aa9647fac6a1e4cd14a57905e334f8e6b33c0bc7d19db4e630b8f82082b60941f2003f8cd99a7ecceff90e967e4a1c6b331acb38f79b1656c2df205cb62f76a78cd987b510f5070a4b51e048cd4375b4048929fd25fb9175b96855058c415cad425e0e8a15baf94d141f848689139700137a0edb6d4f9511f5b6f79bba8f7cf5b0c19f6419562bb4d95824e4f43953b17109077377d0bbfcfbb70ab88579693c5079b50fa8c336b84a11121bab47ff03d15221efc6091ddb4768ddc40f3f589a82619dd18ffe889800f0d9e2ba446761473cc5ac5d467eb40847ca4a507cf6956f85a72c39723d47c2735d97e58e41fc02336bf2d0518910916a2606dbddb7eaead09a3d60b0d98046e3953a3c88c66bc032015514c734f0580d2491b3d7005c274340b6b56ea38ad1770d062ca8871c13318c84ccfc58c3f06e6cf918681f90d5c009fe82565fd1381aeff8c720111d748e4182a7eddda1909439b59f3e43a1345413f9a6ec1dcceb41a818e5ca247cd5b6e8705b2cd0bd7a7c555968ce144b7c2ae647b6f34e8ec64fc886e850ed2b84507510d85c18691f74c0f4adbddf0c802b750c087e447d587eb512af4ff50191d96dc466ff4cf92ad3cbbb29b958d835b12fbbf21903e6e7f345b7d83bb8f98b426d27d6d1565845eeedde10f67a911943124c0ff6a7a7da47b52028c00cdf3ba7f0063b30ee682f73208cc2e0f53689fbf6672300ff83b7182a6300095bfeeaf33ce6d9146180da48190d7c30674c107c69bf0a2afc170ed44247470285c30836502ae924e8d1aa19d19c78f2e634a0fc3664ddd3439f29d7fce49178a1768613370425d023c2bf6b2ce36167c86f989b6cdb51c4f7836e719f5b911905a67b7e7f3abb8af55378d05ab7e839455a33266bd5b99ec9c2a8d755b53259584aabc400879ab10f19d95cc93d823133e729ff8c9defc1b12609277457654d7f40f60ff87bbeaf651265a9dc02f05e460cbfc73d5a80486d54664106dd4e97e29dcf46bd29ad47fe9b65ebe74e5d0a4f79079295563e154f266ba86ca38aee6b94d9a25493cf7568344668259f5a9b816987114dad41107a24935458043a405ac0a7789760b21aaaa3b27c62c9d4ee72dc67e8fd4bc0d43da362f5387fda26a996ef9993573ca61b3c0d09b46b06f3a7656d3e5181d376956463885a039b67e41b6cbcf7e2ae0e0cf7a55cc224a04b8b04e9964fcfdfbf06828ee47f92b8a42f8375aec202423a5f2c4fe85344f144a5274e8d64b8359c878a82eb11e77936990cb158fb0731626cbdaa97b18cb15b6b1940a9dccd7e044c26773716c40a9585415e39d6a87f7afd78947faf36983a5e20dae98769172ad1d0c35e1529db503ebdaeb264e60370a8318999f6561a067a2bc9495f7914a6e015d350be4d40d1d4f328029574bd2d8f22d3eb00235fb7ba91f12472323ddc80d386511660f509bfcac2bbd7d16e5a42b5c671ddeeff40b24ce97285b02a63057dc5e635b6924ef009753a728a9a5e8a6accd9aa6be00ae8e236d94dc9505c2ea5aa9cb70c2249f42d9323b032db001193f6c849a3811778d1a44fd2af62cc9335c267f26f9c5f747d5473c6f568fd8323f16af7b0a00cf327df20c255de8927d09322a696300b24101abaadab873f6704f8185ea79ea60673ea540655b0732001b6c14201f4ee46a8eec62996d064326e81cd08b5d105a3ff7fac1962520b96d95ccf0ed00350f79bb2d5c7b301a4601b8be3156fe66574f96f64043b0ebbb550fa41c092fd2cd99be3aa808f9dc94261421a91904c0990801d83cc2f4d1e413d67a654cc32a18411d2e505abcba267c78f2da5b720315ed2582c0af33472e4cd4b1af5b1c5d2b9425f6588cb36d12081ec1b30d502dd1f74642eafeb5c61dbb13fd0f99fd7cb0a5eaf4636e8b6822df31c2d0fab0823e09e7e068961eb65b5efec8422a03a89ad8903876ae290074f4d6e647c35ae866744073e985df6379b188408f596efcb734af6d090f8e521c4680eb418f1ab9278158a179c41e1f5e079322eee61241eff277a499da34161424e088f018599d26e0cb8f15a99c20aa6d91b5a8ab133d609ddf8bf6978d9b669f69b65bc8c71e24b93dfee4698536d007fd6ff4305d55c8e9749794c005c2255b554f5fd50b443014586eab7a364d38c5bc7d58e949409b6a9a06d71b0845ef35772fc34ed5f4a825b132d5bfb2566675bc23080d0bc1edcb7f71fb80f3cc88fa048f2062f1d6f2c91a233f9bc7b7b3643595c555bb4685f9ebef289e4ed5be3e4a0ea2df843a8fd1a4d804c2fd7e54857bb10323954483ef05e37fd7df8fe6a0db48e5ec89066da212d41f082b7f22ee98f40caec97ca9b900ac210108f8654de1e03473b1ceb88ba394ca5771fd166b5c5874326a90ae9bbc286f535fc9a9144ebcd7e86e18a10bb3276182e0514c25247e62969a760782c18b519cfe179da7c9c1407e12c803b9ae2f8f8a7341d45431d438bcba416b500af57c52a4024db43e264f901cc58971c1ba64a504f5a59168507520d5c5956840b141b65b02c3d4caf957622abdaaa5010679a23365138d8e068b20feb4025597cd42e48ea653eb2d42bff43a13957cea87e672f31a6b960d4cd12f9bb8aaa229582322ffe794a52f204a342b6d4717ef1f6b6ec80eeb2968a9be008be681fccb3b6d3464b873a20be208c937c9f3aa2f20a6b53689f1cc79855bb20cd0c66b1599f396d3e8680fdbc829de18b1778e3ab96f300a5133b49ab75b17db682bc2c204b07d8baa99b2256281c36f8a512ca134b16cfce89b863fa4b0a446f45848083dc7f2d866b283f468083d90495032e9f9b8991f61d651af8cbf141219cfcc666cc77abc88fd9a359cb169fc8cca507bcafc398c1b0c2eacebb42a6cd623e4397b39b73883871eaa5130550073ec3305f3a1a57a3013990e9cd786e1b3b92609fe893264cd877f000e2f10452dbb80696874e06f2b2098b880497421ae1881f4df72f3ab459cffd935b898c9ced35dde2357031510b7044f4c810ad0257ed97b13f9f276786f2a7a1508f4d9c5949e53ba3fc5e91f05ee43ea12d2a6a5da90582623f8c4f945222eb0514be85266771c794d1601795b1ef0ee94304432eb181e8159a93062cdde594658ab96cde40fd7f2e5387cbbe398e28f5ef2c92a1a03f168ed37074cecb3e01ca5d3d279137bd77849c70913b8c821c29616a154ee8b412033ba2c8fd601678291be8e0f1e800dadb78d97e8caf19a1bff07bf0d18c0bfd65471b816e5fb720403c1d6832c4e671b5550ad4875c5f92a5c900039b9964cb21c45bf1dd2d23942d6d8979a596fb9d1f083b8527c4f91c1ae100b971698c26a39f684374f92b0361e56aa9ef255591739b2e95c8e9721e43e42c42e171766c6809ffed8378494037d2a3c8d5d26d427b6d88198e3f1c77afed139d46ec31be10c537af69b4ea6005f008f605ebd50b750ed78618072ea6427cf9850705d8e15220573a6da15cc662537472ef78f15cf1cca0a6226299dfc1e3a9c6087d1f40c15d28dafca318ba3ce7c90f09a7ea62dd4b932784255e477553e2b11d1e7101a8526696cc7b68a341e0e3b6cc51e4c71c8c3e0f8860141df00217b784da5848185103e58bb1436f54236477f52e23dd8d218fd50884a51e2849e4d2b373fab497f8f1104cc79337e9839ef7f1be87712c41baacdac501c7f04e5ed3dee9a9811d6947bc6b48b8cd01419118eff1e3c080e1e776eb9af92648e59711e52da58248725328b18752a12d6f24b67c96a958c904396eb6c130a086c15d038796b7c0cfb00ca4ad8aa54857f8c70aaa41903bfe5cd2bf4d5ddd4dd308d5b860f51277fa6db2e80341d80e1596d5d7707b2dfbe7eb86559073f1bc04b547034f1bb424d5eed660a55b39171533c8eb855dbb2d9e1c4953c10bcd7935f0cb7dcc91afcba2ed9f2d7b8c40254c5da56d255ba812372305c5695a2f89b1069f22b8c07c301117c88376b99d9d9d88bc25b303cfd2de1b33620558eadafbbde0ce60adf8e1d9ac40ddf423631cb59b27ff8e2a5d399239278a96b80405ad3c693a81d5a62e855991b79f593e21f5eef32ad90b3884ea7eb3d985b629b4b1e02caf17cb9bdfc144710f33a9fab8b9243079263725624d1f95a22aa2e34804589f40889f32ab038e2b8d0a878029e29b767fc34726da2b04e40f869b49591a82656c021968d222c45d3972ab0fc0f471a9483cbed38ef4f382880d817aba8ad801530457c15dbecb0f599d21939faadba36a26f6e2e986280bf1e6833ee9869ae3cf2e5b9d2c3f6441dca014d86ab154a13e1293a4498b84e307ce4cdf124918d6b9b5ecd2fe84200872f74f5546e74afb9532381f82fd04b9fbab513e1e04c3030ed7363b88ff9b3b30036c107db1e297db2e8cb723cca2fc8656a35751a6db3128bd3ca7ea862f3d01e05f66fc79c7312c159974d695b5c12e26f10986b47c89f37929e7a945508b71b4d765d8667c02b0cab3fc8ba6d2869983dec07ee7fc49c343f36b3d8105f8283ae3fb980d317fa7dba838acfa37f5d7b3e7c78efe359faec2a2de3f78a403d96e0d8a725419ca020a10d955a18f585af487ad99dba191114fde62919b90da5ba7d5cd8ab1612b05b1ad78e365c1a4d71d2d7a5ba9cd9951f0f4a774a5400951d485d36577cac0a92e4f40ce0203afb80d45888ad2f2e9f08e526eba9303fd407bc393ea9f3d362ee935a588c61daab27a0ac4f81100e68663c849e0f89e85039def13970094d8f9828acfa45492d50a62f3397db0d06e4834df916d6463efa911faf87aa58ae8dbf7a108e57cb470238b870f109a43202a21f085e12fb3961b7ed7b857da9f481eb140a1109cfad61edaacc9779fc3df9a70e87e67834a1e8d6544d8466b463aea4ad680b3b0942c22dfa02f487544076908bde082711b005132d5eac7d5a2d07a16515dc9057cfd98b02e4fa071b8c9f7c3b789ccaa96f0307c4eb727caa7a88e5f38a58e0949cc9894076b63a4df18515dc2b06f4c789d0c8592ef1163d1b6cc5f95e0be0c0f5673aeea38c6fdb0010b77863d48b466700e25975960f6838c1717d6f03b309ac80e29d6819f45e2486cd709193f04e1ad1283d39e9371ebdac5c72dcf54778d48865a099781eb9c043763ce5f58f02eed11f42151083e8baeca35b3d08b5c02973e368bbaedac239b61d63432babfedd4259c2ad3154b499076739e006f54d41a4fb82b3f02afe9610e567912c6d3f18008bcd19bc02690074c3c9cc1d73b107d7a40abfcace018ab8e1914dcd076823f712a345f870546bb624ba71629cd2fc908c2ad109c1c43125507efd732bffd97bc7e2b782722769d682123342061795f0f11f4cf13d18272fa45db93009369889ee210ff2c091724d2389ab3aa1bce74c22b50996997d20446d922d497c2fe38bac679ce1644111114c127aab1a3a3593b15a16aff36e9f12de425a800442e5c7c220f3099f3e0609bc3a5363114bea908dfbefdb2789e71641f7299e32153371631aff063a7a3081ae44de06131218286929e7e11c95e7ec8ce86b1c4361e044e07b517e6d224c85f2c68dbbbab0bcd230bd5038842ec31ad0e28c36f6e1c802e013b98ccd471af9eb14912eddc99839f814b4c9e58d59545c20c4f36232fac07b5c0db3b8393aa28da48c581197a94d7e22cb1827e2d33368257da6d9da04ceeb699a8b0a4a050dc2b0d4d619defb9f472c273889c2f44873e5aba68f372365883deb7641dd576807ca6778eed070dff6e1dc16b915f6715f931282e8aa6b1105432f5a9c1a03b3e05133b41c5e067733947b699257b4f97d59bca95fc113409763bb5eb2f6f70d94827cd9e0fc71dde2ed4a270d998c944390536dc943da8920df314681845a4fa8f1d1e300f0166fe8bff529f61dc57e241c74ff17dcf19864d5e99238f4db39307240090e4552aaa8573096ea7eeb275c0e878cf5914b1886ecd5a2d2b53cf674d46376c12427db66d5e540f350e94df5080737d2c52140bd2930b1e9edbb46f88113c133503da547110dedc47e019f792e37d7e67cfc0e142dc4a84fd8dde008fc365367ab23a60181c17f32ebb0fca60c70870d1a6fc5450b5c9bdac2c355bc31c147bb3c8e16896e1d10e38f1157df3f2ba01fd26d9aa590a3077ca3fc1dd330189a1830105293466c9184f2b03f5f2af9084fa54c9cc19649021099e4b5381b36a026ac49e5ae3eb891432c355c6afaed37d326f21209ed0d23b537d11971103ddf60ce8084e594ef54e88c7709929aaba0baf47e058dddd99a384a5b257d4548dea40e4911c4d2dc6cd48bb91762dd92a35d390a8ac698924f0a5cf0357175ee2fd0e19175393bce3581a4ea88ace681eba6d821d89270a827e9dee8f40cb4f4e8bddf82fc50e18ffac78d28177213b282074c3d88390b58f07c96ecee28e259a3a6cab4100a1e01168f062b39cb4851fb441237ae47a99cac6dc220094b7fa7ee246ac285f838ad409fcad21cb1a6989f8f83529e4f9cf3de7a46543284c0b19c91d83509635126057c8bbe45d6225e6e3c85b03b7c55dc0798c37d61576d30a849ce2883b36ca650d40860433575e71e5fc0ada8a96d319ca493ce52d0a40f8bc22c924997781f65ed0624bfa4526f99874bb53a9bd4b33d99312a94d577e807dfb712930fdd244147817c4fdd8c0e97789a8c605148c44502d77b6eaba9b7715455da111d04656ed058e6dfb6f41ad6f8b439a11b249bf667743b64a2addd233dceebcc7b479d9d2cbc31095ece4996acd20005bffe921d4b6cf2bce3df4bfef40dfa715cdb94c8768c41289d55996e3006267800453fddd62437957f6871c172190d665bf6839e61a1cd433e031afaa8267541bae1dc0bea1c919ac346919d21f02268355334b00541592444932551606f06426ab51a8de684c37d86cb66f82ac78eada9fe0b5d38d36d29956a723c5f2aeab2e74c24134742cf32e10e217a35eb25dfe8e5f831c678b806a025a02d61a789160a0e90eb7ae4185cb81268a00a39e99f73b5806c0ba71a41ca1984de7a47ba22dbc090eb03141c8d6dc439799f13ea685145cc04b48886b3178a49576897e83b4f6546f31bb42bfd88ea49a5419e091b1b3d68b53feefc5eebb277a102f61fce2596de4295136b457e3638dcadde4472e255451f288874a43b532138759e3c0213358f0030e96de06b0993592b9f857a20ad0c2e36e61b2e2641e6e9f790a0700f8c481206e5ffaf08a04380422a695346ce87f5bd5e3959e4c59256b471c89aee1b13228c8bbb60383c5259816edadbbad3a74e261934b7cc8c553dfd2450a86e41bcb98265d8bd8c7d17f8243fe97a6839ad53b0b0e148077940b8110a252867ddae5acb9d706ceba685f4f89ae650810ac69e232bc4dbd5c4cbf4d5c239b8085c22a5161f0ca2d50f280b45424d0c95320232c4968e0e61d4749fbe10574edd820f573e52762c717b29167906ee74e38e75a4731a2a3b573d3b0f49a0803445e83e18dc7f024135e738d04f639b63d5f6f76423e3a52e7faedc2583af751b96a19d9686adbec4929f35d3b06df83627f0dfa59e7fa9059a249c269cddc88089dc23f49281b9982819aa931540f1c872a2177f470eeaaa9e3b6cb583d03fd38ad8f981508f5bef3373440e37fad407e5c35bfae55f4e0fdfd3be488c1d6bb8eb091f17f26b81d6071b7c73ffdf3e84f4f42984d8a3b541b298163768223d5fbc6637f964f1608926c2536164084f404745ba0763cc94f70b3adf88fccfaf91387f83f97d78bf6f70015dec83da8049eb25a512105e2ff245159d8755d9f1b03ba1bb6299cb3c711e93c46ab3fdacdb78edc65ef4cfa18dd380ea3253ab7cc0481ac80859fb0ed05dd2c9e0962c0de70ca5c8738c37321d044907962b222d520776db5d93fc1eedeefca3c32db6833ded4fce0cf1d641f1edeb46dd95b2a2572df077ff0574691cc7bcee098eeef583cd151698221caaf7b10f56fbc1e2ea7d163471242efe253154f0105683526703ac0a49b206bf57833dc22ab45428bb455fb2a7f916f5c8c87a4a242eb4dde3c870178b0ef9f0b4a9dc56baefe159d7273783007c83399779c5d54a162244aeacb3945406c7c2621247969b501b65082460d00acde7755bc1af4ff466649e675c3d04621cc3977feddb125752370d24341357bf2a1a029d6c66294ae8dd3dfc00adc52478f46506234d03bfbfd8b04d99c664d80956cd2e2819305a9d77111c5addccd8926c0e1f42b7699458a153c5c240505511d917249c8883d896ade446c84023c1ee026725a6fe5cbd262a361be7a962e24204418b15c4fb2972f402694df1dc2b743ac94260664f6480b4d20f017d2e5ef6d58057eefbc51abf818071a922b11f9aa10210c505e323f42ac486d2451effda11b2220165a77e92aec734e21f0ead41fda44d8e213ed10f28d21dc078fbca40fdbc95bbc2983af95542f63ca4fd5240c166fb79a709694e5a585d48efe129956973adbf2f7c79814f365119973cfdadf952a2d4ec5c436dac56fdb0460a20521f220def94752d3229fdce4cbfa9f39e66fa9827102dfa6145e412d6ee6f25db229157f7d01cebc86651c7c54ae26ac92893664ecc3beb1ef9f936ffa5f659475b5f2e70fe66a9bcc968b025f2e9a0919f5ec215c5862224c89a80f59c55ad7a82872602dab3c5c7994829e414d74c544948a245b3557eba52bd74fe6f41f6707053e2bc2f79702efa9cd3ade7a7f71549f6de5ea08bb6afcf940cd538cd70809a0806c2f380047f94081adbd6d263df7a3c5571dceabf1029f66fc60845ab1a01bb0949d8c93e281f8649db25c6b9bf88aa9d783b5aacc46c9349f8c78b8c2c8b1269a2f8b06e6abf7ce49b7b1aa56fa069c59f5b43412a0aae13a26b6f69d0c5d63ba6e4042950964a85055ac7b60359587fe9c4f3b1929437bab9066f55d7597145afdca2f987c75286122aa650e8d05566494c1a2beade28177d6a2871cf0eee2c746aa9e774c298a5eb08ad6eae3d5566e07c1e98f8c9d1acace6764261d0cdb950a28958a73d72e4264766d9f3bbcb6608ed97684e79a982d36bf2d1e8bf0b7fa659423f698d93e05f180c2607449c0e344fb047d4387aeec58d965ee86c3178f25855d21be557a4f489ece4c8510816638ee1081c007079bc70b2c4b39273f54ea4272df003e4bb18dd4d135e0600e823296faa3647a9c133f01c245d37cf21887ca3f2062bb15370562ca597a725d9c70757b62f024a31fbd63d01ef85220ce9aa129e8e689b14159a5f65a1a822b0621bb545c398c2ab4d549535eb539d78613edf94a73b723695c8f53534d5137a55b606ea1aef64d5f73535912397e0f815a776acf6e58a3bd72725c064983b3aba18efdb131584623489d80afde0ba4d3d9869727702fd623e4e175052a972796a7cd6fd76223dd97c68249392f1d47c3570b9e1004222dd0dac69bd5b086cb83c2f0280f14e65afcb21d97e088c17738360c69484cc7c9f4d4670d365862cc4a34c1323eb0f7fbc34b4ff21ae8a6fbab55789561c63dd58993f62f6f869b3a098dc7f86ee56253e5e808c87d22e0de9785eff4cae4c6230a87f51305773aef1bdcc795798a0e13b59022ac2bfd0d57c06e791dc9d3d21614834bac04c329860ebd70ed13cc5a38a8d4c5b8ddb73d93e172dceebbca9dbc46c69cef58039f8dca9d3886d498e6b3c0580193cd55591a519ccc3e04ccf8199615dc66669a4195297dd316e2cd90e732014b7b77ffe3b35f570d5a4cf4307516cb99aaf4db081c04c4915a7a6b07090538fc47d048023c6a2ac5a9ba4140b7c1a622fb68ab41a0ce7c0be4105d0a9668cf9b7a76bc15ba92167f82004d02bab453b0c3f80b1436052107b521134748f70310a9afdd5cea95c10ab8ac5083d2f8501f3197cd261272905979b74fe927ea78ab11b938450f3038a446b231b5c1f43e92a247e0f3ba76e4241ed982d850ff4746afb0ba271691fc6c7d8630ced105b5d0347e35a8b4c4ae4db8a63cffce4059a2fad7464f803875118f4e9e163538c3b7c3a502df9ec0121207abdbb87afe7caaac53d6c209a7e7dcc2be9dd6e1651d8aa6e82af27684cf496a48c043a0f8e2506cba568922493dfa434559e54240ff776b09d19b8598e69d8a0315d080bd2a19b2bda21afa83ead68d1594561544945868ae97078bd8c1e885d29724e1f7c020c73030d8da0fcb18d7a8f30d4cb4c5e3526ad62de88a75a010502b2d90d040eb7d1959186c55d3acdc95998d0b9887f493f9534c31571acbbba7bc4048790b3e4010d8ac51f5d9339729d49897a376e167cdc116fe3f206131e8eb30e97d5df87f8d1cd560a477c653d068c1f9416ab61abb971a1865af4ec5b09218841caf5625c88879322f7af100ba6b8247919b2d88fe800f1ff37846b24c6190003f2112acdbbd1178c3d193e6f7558a128ab73620f4336b0c80b430a2b68d582ad1a8880a3b8197441501c612eb08ca05103ad39f1a97895aab068485e9e36343cdeafc18441907f5297c347f1f8de6094cb60767ef469e57098f89408038d12e4ce9ec5ef992234021260177ecb2e534758865a0e4d9fad31a43e6a0690e4623c33653b7beb402806862c509acdd65b1fca143f28afae5acab4750fe76e59f064b87b6409b06241788229b823825bd033bed6c53f6b1d1e1b9b29eba30837771ba05ad52ba026fdb30cc674b33ce6af96d894dcc7d5809a0a36d02ab6303f01a340632fd516b806546f1028ddd6966ac3b76b6543c89a74e6438bffa52871c7a9a2d7f7fbab7f156396ced9ea7086ed3fa96ad683970d6fc3faa9ff8530d5f9ea7387b1cf8dd2cceca0acac0c7621f2e01491861605ef5e85e4ac8689e8f73d9083d3a620410579650ef317232320375e5b7ce6031274bc09427b8beb17b1901254d340baf0f8324eda1b36047a5a91e6fe923357044638c47c0d87959c9f4a22d11d1b1ad95b9fea7e65a6f6bd46da69d29b2c231418764520c64f4a34b32eb9bdf3b4c2097c21245c5b1b2200bd43bc53551be40bc64f774c486c9859768792947b865088c90afe182c7cd360854108339cc05f44db32a59eeaa49a971fe2994600991f418970f63de3e84723007200ee893ff2f00547bf22f8f263ff1c7a227d688b7e9e30b77d5928b1e9200bb1f1f8910dc89972097cec87f7d525d18ed31ccc70a768a4440f1deaea7fb1a13b25f1bf6dbee89fa93fbe0e20dc604d4726c19ab94a131783963b530feddce355f81d72535bbb841510357d6e9918510d565af3779c6c53ef8c91f53fb9dc6d0005e3e84168ce8ccd9957022d5ad9b781ca654c360fd160499113aa46eb8073621765ed841d1132810ef4f9b6f8b174aed7e3c94fafb05a724cad8d2449f214a248ecaee69394d9b29f27408db284c5cd88c50bca6678c5dae7e8c5d92be2b0832e713414ba9403f54184523ca6b602791c129dfdd092774251f2141b0dc8dfb9b4cce65c69017c0ff419fdde97f6a981f5c00f4416565bb28cf8aead4b3a1b1d43aecb94e35a6b75e94f98b59589fea14b5fd2d1d9eb72f36a2dc85a85718760e48d199251f456068fd984ecf3d533bf6bbf0f1e64d2a5d6a39be3d41155f673f03a170b59265ffd2fcc5159a8e5252dd3617665ac9c1f2b58341ac65a066a0d1b796a8d59102c53dd45b11c0e80e7d7471e3a4b51c9c2e3210e1212ded8a0a125f438c600c5a031052218bc6b17d83cd7562fed537725d58e69400eb413a7154bc22028c7a6218f01a5d98a0680787d1ec1f2f48e96d311a52c497eda3652fac13a93d9df4bb26bfc2ddfc02751e9ec418a30e32219768414af2420543bc99602df574b4eb8977e7354408e8cbf4b8345c8d8d32869aeefbb57a47bca929f9ae6310aa2d4843ad83e67c802656af922dc7bd546fdf4cd632edac8c298e4424aa938a4d374b1f80e4c9a41aab2539694335ab41032d650cdb1571be7939571763c4338a8af20b9411bf70b17abd7beaca3041ec84f284dba32d2315e76d61a5222d303cd1fec0b686d960d5d2a7562b4e6a00c45bffe4aee6c0f8d8fcd4032502a0f6125df3444d1253bdf3c3ae1669050b43cb7a7e7e9ef74cac5d5bab311d77a0a3c7a42404fe0b43b32fe5dc59146ae565414b3a92ce41bcd8645896c41cb67fc0db55b647029f3f78a52d1de312112325cf6d40062bc7b287e6b85e377a9153ad72328a84cab86dff10875b80e7964952cfd8e0ce9a493626a969a2fb7d06cbe165db2011c2de2b050e5a974253baec2d567c138dfe8af01c22d2a2c6d811bb8ba219ee985e37b74a6c20073497974747ec59c36700f0d4ad77026d283106de1d021ca879160e66ebb211e5ff088c7edfdbedb93e0d4ffe9f1b94f196227fae8e80ab5aa51da44f8c11e9e9dce45721f8d116ab4647ce13da1c55ff43b13be34dc78f818660f1bc73574026520d865794e81ae0ac5de9009d4ee09a897bec3fb55270fbdbde52f5796f05e84ddaa0fdabdf3ffd720d1c7409c3a6b41fba240cadd070aaa057f3210f2b5e627cd14ace510cfddee9fd6b97dbc6dad6d9270c9d6b259350023495a5b4b877f04b69e36d9f7fc5fc535fb7ba078fd032627447045afea3056097391f60739106e9d37b98d4fa326264f78fe1e3a57eebda44cbd9b6c7644986e1b00fce1e771d2c47e3de63d21e7df36521756e1c234063ef8b03cf78575a103befe90f5e4783d56206be9271b527b865b0470c0bf54d8d5430035ff605401d8ba6fc1ba925fa4f2d88b4f0fb2dfeeeac085436d58bc4699d95bcadbd02792134640b95fc9cf779d27f141557f9b3873a5ea5511a9803ebe2a678f05dcb9ea2ca3fe622f2850422f78785c7164d5cb6cd67fa9f94237bf7e533b409412287723b0a93580d1abbc52976648b360c99d5a522c7768818c9655674a8bc957588ca11b538d991fd158b4e653713f1691d862cb91ff803047e7a43d659adaa7eb7b663331257d65247ae2ccf292492ad2da0c6dba5b20e15e08d83cd3a7d1d1a4666ba2dbb51cc56e88c6a882322916e3c46017237256a0459da06cf082bf6f45e57fe68536a5e7fec558285e4a0ba9327d551deac6b06bfbd3dcfa75cfe26cbba403c243989fe7ba5d1f237bb7644767e5d3df8ec9722e93a6c7be47d80cd88f4100ad8eb9d721e5c7b64a598c84a540a60d6c2b3b3c8eff53135a57784627259cede46aa3a4b07502e95e4ee9a76a2e0f7f6676981ce91560b8c4b64e47104a7c96d781b5cb319b33cc4fb6087122cd08382a08093619728073654edc19fb4cccf7655e9989504abc77fcbac9095af27a17fb0ed563e78e7ce81c1e7f4d4e5eb8fccba72f1bca241706d5173e2b9db9faf92a43bba9309ef0c9ea0475bebc04952b52c47f770b24914f55c0bf9f0216cef75566e50a65e7223228b1c413b9af22fa2fd7a09ef755ecb158c1f0c7af225945e9cc07fc2a76ea55a04a821e10b702d41971c7ba6ec4f954f45873a0c8585568c229ac200790302ea21208246d07e94cd32ad45ab3ff597b7b7df7ef9ec85a480e9fae196b6bcd531e793d4ee7e8813c627855e75d67bed75a651d819b219b6add6271b43176935d2a047c8abe4765cf891944bdf0fc91a00d26da3fb10f67de6a37f8bcc3374f7e47ae4eec2684b8ad55833bc8f0dee9a131259c4a5b276cd10b9893119492a047ba3c5ed3ace569c37734e341eb82b1349d9510096d5c07b735bd9ec54ab4df63c726030e29d479df0e1e2da1b26665065ddc782ad053157937f4ad0774bdddcf035a505fe9c62e64f32e38aa1d47587b89b89b362d754b67f6d3844a607f94aba8c75189f661b05422c40f0c9f843ce2f86327573f279f7720815be8a2d2eff4e7d14481f206c25dbc8fda1309f30bfc13a8db84910c2fe6a7ca22af0f009964624fc337c8a091eab88132f4b3321ea273411f239004912bfff746d2ec2b956489c843466dee9224eaf1929899e2da0ab937c608dcc07eabfae6fb85ec913c34ffdfae2876edc7db46ca6d74cbbe36d087db90fec8e31a7441f7370165e550ece46d65ef203d0ec4b341d71fdc5ae940cbbe11aae62f90697ec72795218ab0b8ad4af9c8c3ae3d8b4088ecd9442b136850f46c3de7d74e36ff4f5b6a10c2e619d89a5e8a4a0f77d699ae5e2815428c2f6f563425b60248085af28c4faf51ef8ae456c5292b50a0f87b54b80b9e304aaebf6697be2b66f58a9a768f8ddda3d17f521110da5c28e5241ac651352184faf6de8e93521062bc31d6ba7f56070f8b1f9b70ebac82312cf15c48072ad08a7d9887d3a810c78c86dd63b1f551e1776af65de0bcc4bdb031bc8f6e668839c3c955d830c56f8877a4f068d1367d27cf54c6f17bb927176d0d9a21be63db5da68d8721e0a104fb6b3d3ce73ca4d80224fb4b6d0b2728736f985b234e70d4480ab8ecd9ed2d994ef2e9da60aa30d25cab1af88ee8a467c966a71e8d87b81ae29ffa3ce5739358dfb7c2e60cb6fa97d9e0e4a7bead943b2b5458797c557e593e133b0c06b32fe713846527b81e1b5d9541eb0aeb0c69bd1057b56db1deb5931747b79da001f6b11983a6773660c43bb001e89f16b588ae6ce2a2e04729da87bd7747a0aa8bbe8f3f28f658b8845fc09c6bbd6c845c08af35d0515d66f07aca39aaab8d6ba88a2d92e484a2c4ebfa01437ad5315ea50cbd7be3770ecf4afa8134d6decddff2660e7413d24b09f40fd0c001a01bc00df0ee7d3fd04c44972744d66bc309553e2bc9618efbb51925d89f8be04ff0d8424c3bd51395ee24306a87e903233412f11beb78c60755862be26a3660e44125a6cefaeb4735f2ab30980bbb0767574f178a0b31efc783631ca8a4164052204b0a74178ce11a50912e581638eb18c8c0c15095c2915302bc0cbc9671c0aeedc728bd01648cee0f03a1e3d0b3fd21de2ece83616d3d86f92bb971f79a490c9a12dbc003c1e02b52185257062d8bf7550913f86cd3cfb592ee282c2ed71f141494c73b4fb49c3b0b63d18ff46a0636225481398b872d6c8c250e90913c91226344b94e11379e3530370616b54e1b8aa502f0a12fba7533c9e7fa854a63830e840b43241030559f412fdd2f9afd309aec859aa845f3640c0b810a38fca92b852a4682f6a4b07f0fbfcaa52e2e1e3dc66f81acd406d59e9c45fe2e961ede3ba82035fa439ebae810e57ec23533862cdae1cd03a8f3f106bd4ffcb24e1ce1d69ab1a68ef177f50bc59ff62f9b1d26b940030c9dbb1483e8056abe89640621f55cad3591e0190a8eac0080e5f1518e1a18f60c9b2504658ddc9e5ecf5dc6c6d6340c828326e16984103f6a00450b7ed289b58bf4c6b240aee2b8d887db4f415bd298efd19102062bc6c807e0f74b211f1910ab795e0602195f4d462162dc90297e07fc3b39f2c506a9639f083746820d143e6ba0cc7a5cfd9604dde35e7b4d48cf751066663f96d2533769510fb7de444b42ed1d4eca9317c2312682498f76a0c7b4ad8833ef8785ce249352a2d9b4ee585566c902ace00975219f332e671b4c205c2f5b47a4fff707612e1834e068f010d4f102692b815d7f64464c62de47385f7be8a7b6dbb1156449381b4728e8e8d7bd49061aab1402ea1b0418721968e62f314e66f2df2481bf7ea042d765df79f80e3fb264dfbc401407199c1d203c08e5fa7c5cd06bb76232eb3ca6db357850739fd82cc53806848021a4bc70be04083969502f2fe636b28a79e37de672b64020fdc28e0043547c4bc33de3dc019aaeafbec08da0d8196c6d83385493d6b0b3ecdfc2eb11b829923e75e8ab06c207d5b71e960e9f9917adbc1ae265eba1e535051117aa439c41952068244bef40f129030501c132c0452dbca3dd9093a7effa9891fb3a6775f5cc1f2fff03c7f9cd4473bf69937b7023f80efc9daca5b822b208cb0be24d026d9b51dc283e5fbf12ecfa6e25305e7b2a2b4710f968c38359540d2e3b8881da805d5eeff5d631e16e06f0b7aae652aaa975de9e391e66ee28c459e61ae428dced98c42d4470780b1850cfa1eda72740613474f7f6c8dbbb39d9e1a89c2fc0d242dd01eb961d227795bd36628a005e183884322da459cd7e228910dbd0e6ff565be0f6da2a51d457d69be1b33930cc7bc3b90e82eba909ca6d2eec31afa9a41a57fd84bed391be814a22c7928955f9995640e2658f5de554ae26d87dc43f7b3e8379cd674313c61d9c00b259b6a2a3a1161c26b895086f9470374620bc2ed13ccb083e0203226497f8f82b48ad69e83e730b315d6355a05e7e3fde5833c994a0dbd1002f1f9f20dd6bbd3e53e1bc052ab027d0c0aea7b96d0b61e72a46f091139a429daa81e88377de936ce7d9680047d9552c6711a3896218ae1f45c00e8a3113debe203f19bdef0bfedc77eb3de9cd73ebd02efd7631bbde675d5abc779a55160bb1d6bc71bd0607226f3f55bb98928ca8e3c0d02f6f32fdb6c67512a925365813c280fadd0af7671fb476aea4a7d00b51bdf6be20ddce124f25f0c907322ba1fe5a3efe6df310a334f2b83575315452f0c28aae9b4a4fdb78086536f8ea489250bd0e97ac45243d9d3eb34b3986455b4a681ef9c267e20976981c5a7e9696ea0e771df16feeb3c37335fc6be3938e34100c1f5a7969fbda85dc79ae381819bd238fe3f0ad10e95abf1ca9a2fdb5021c5773a857587171fb5d06c74db6883c6c4abdcddbcc0df12b667ee127fbc94de140546299a262154f688fdd217e91ebad781dea3858967091cfb45052fc96e79b9ecfb4907596a513ac32f3b5bbaddb650f70600e0f1dc9abfcf446d503d71662a5ef90bb9ca02ad82b1ec1074cfa05d6fc99be12b5490b56a66a63f8e1f82c17801990657f96b96293bd767d8297edb5717078619fc9345c717333c70ea9d72bf080455f013a1f41bb27eea2f64254e44debbbcdd2a6249487952c1fba805c37f23bbcd8c77cd01fc96ec8ed8e7c875e7f8b96426dadb38ebb6fd7aebe57fdee1cc2d5735e60afc6e44f64c7396fe5b5a8ea97a4088b62174e2dd6eb3b8c0ce46d8444d198a9a1b7ed3679b1ac0716be6452f1cfb9b798c66ec0f60704ee5de0f4021372e3fc19e215e38da5583bf077c1e14d99e41163fd582513ee41fa682665638df1b2e7fa89db9eed057253fd797ae3f88ab26ff7a61717dfd4de4dedc2226407df3333570bd1d1b02cc8f4d7a24c35f357d935cae15ca6adc39cfd4af70fa00dbae18aa2c8994629626c4591309a5ae462f286f2455c78f5bcb4d1e0c9e80f3ce6242386bd4d6fff922166341d51b1332a657af519fedb8413c362c5ffd7abddfdb97c35f78fa58627c86ee9402fb9cc704fae816f70b243fa33d5c4f52a7059fc6c3ed73708493536a9b604e5dfb86c1421bd233984486aa347561130894ee73e4f94e5b4afd8577cd0d80a9d40c99f615d969b3d394ceb10cce29610e3dfa7d7a5a9dcbb4b64ba27443e840b015506ddc36428b674490a971a14707263ab8675e1dd19ff3d3ed15e889ed4612f36895a0ab049d7ca934b6f242acd20b03f9234f26a430e7772cbf560cf7db14de9d7037c38334d084e794983cd0cf3c743cb7f75cb103939b2a3fa255843e6be1ed13069c7255d14c481f78971416c2d48a437fa84ce0fac949339bb1aee4398021f6046d929e4dab95fa6418117f56e53afb07b92b8698dae995ee1607ea802702fe1070a826883e1bb9070567e1d06deb4529f2cd81cd35e2e52cc2d298eb9821b22465211ccc1dbd3b69ec89b08023387f8d75962b11148234791f01199d943d86c25a5d86cec8eca2fa93a0130a831f473fab960600ce58cf95c1fcc5a5d9429a8c24ef988a96858dfca9b548b1057147a4cfcefcb79e1923ee423ff37169d0a13c7cadf30c980fc12256ec759beee4b4a986b9c27b72a44a8ea867512212734da3d1c8963582fa2dd3a7dc6b59115fd18e035b149c04a54db03daaff68e5a20ccc29a0e75fbf31e1222d880cd51dc9fa684dc10d4a1ede1375973c25dd702748e775300b6da6604fbc4868ae1a7661ddf0238f0dbe4e3af96af43c7a4e085eb78e70aff1fa551d86b4e0c0ceefa65db7b77db724b29939432d408bc08cb08322c1165043332515d11db7dabb952c5098733b4a4ec40ad9d168e6a84eb7d6d46d8720e0a74adb5d65a6badb5d65a6badb5d65a6ba5456acc504da922320bc644d3244af38e2a7a3a19213342d6615809a4a4aed5314353d377efe18f9cb3e8eea71395a5ee73ce9f7f481da9cc48fcd538bdd136a1b428932a40c5585f5dad7758ab633d0d23409562ac7fd2153e8d89a4111a13bfd30ebb1f8e3f26835f14296e209f055ff4fda2bba7db7b2abb7f83bc91167523bd9f7198404f272ab32d8eae57acc761f77f8c7e30cf28a72c654ca0518ff510b9898a6c971923d12118f708dd51dd2fa432127dade89ebe34b1e1b834e51e6c379b6da8032009b0cd76f9baabd966b00788aac2351d68f02ba40e70059596613606c90527295a649b518f4f10075ff3b4204349df2afc4293a95de66dd3ac3d9d9a8021d3644b1158ec5b8d3d9d908e7ef67dad6cbdc3d75eebeeb57aadd7663ac519a8e7cdd0ebbadbe19cafe7d9d5cafbecfc3cb076b8c666d69d9eaee79c9ead5e105f3927adb5babbd53d2f87cdb7512cf55aa5b85dd0ea96e639e7a43196e3a657b4936776295f7b7eed6e16eede842f09f085c2dd9bdcbd095f12e09b67ee7630746d8f3bbdaeeb7c07be1ce8963dd7de2f4ff75c9996cdd9466b371282870d6ebac494a29b2959dcd0946ed874690bbb4411b923e2cbae5db60ffa35577fc4a75fcdb03c4f6a9bcaa1008923a618c3c51a21623ca099aaa20433e84046acac4a15aa466dcac2d92c22ac6c16139bc57a5d44d166bd18fe60b5c40fc31f623884173b7c30fc11662c4e4344995c667bf55ef86365c9eda9f1328d2399ed7e4e6982975ca14286268b619b288408226b2cfe794c10306cd7ee026e5ba34dc4a220954613e504181e10501460d7bf75669f58f2596badb5567300c40c9507cdeb98d991f318db5a98534d4b4f135f7e307ffa13dac130ee96ea275a7b3cd080634944e52731dc9895a92ef79c41b2596750df6eb80b247e45d31d53af98592f47340a4bd416edb483963163b054d8dc65d60a9082d4752b7cadf7f4f80471e0f4434e4c8ad2e09e4e348c609799890460ac214194027e98aa5937216287d1f27d140323bd85a69fe6cb5bc1dd755dd500b83169c21d4b8cb7bbc5e18ff91f06edd881762cbdedb58e2f2eb457ad0768577197efb51d78ab5cf8dbfdfdf2c501e7e0e04d1e987d8b6d0687f0dca6eeb762d002d12a5a8524bffd4965b46ac6726ea05579f274dfbd7b204fbf9ecb59a8520f69441f92087f48b2690efd493b4a2b67d5a6b2dd6de93a9d9ddd69d95df7b95b72b2bb2532bb6392b23b26355d0f10558ae1bfe10fec43927d65b6460f5218069a92125cd6463c529c2693c994dc701c4f1c6cc7b279ec726ee1816afb5bff0ce5caf6d72d2862b6ff2b316dff5714d9f6ef89f2b4fd8372d8fe43eed40311dbfd2794951d401ab3b63af17084d4ae8fb56729d35d9d9b8f2ab395cd5403132cd9f5eb0da7262e20a1008b2066f0c0243d393303539918dcbd1b020b1277f70f4c8daa3e5284916b820a3282202256eaed56342d0dd18509a06c42c47437254b92ed3cb4984faaec1aea505f57870717f7feff4efdc1d47364917f0407ca99dd1f62420ab4a875b4ef94eab6d1beb37ddfcb5dd074d281ccbecf41fd9928d8f771dcffbcebbaae52327f23d49fb208fd6a1802bef7872af879b9ca6c77f4deb00cda41f7ef972f16241b5fa35d4ea84d13c2a98f596bf51db2a62e94aa766bda25dd12e29c7290da2575cac1b64bead4ccad9bfe077553fafbbb209ee1365380cd9fa96952fd0102d69132a148f595545f7e5f58e826cff13bbe7ce9b87df93b5e07991d0749de20a991d31945f22792e566fba7e0404431a2587d3afa76cf41a26fd4877f0afeeeeeeeeeeeee1e000a34298cf5394e6b3cb6e8262009a8e5ec8273b3d17abaa5fee496ab076dbffecfc0b979fd2e1c4f6f3c7d6aab40441ce64f6fb4e9a3142aa4748a4ea1365a64a99fd025a01a24254b2dd5a27a333d39246d7258de39de67dc6432c7d8dd27e23f83b4714d06edae67772f7ae79f77bf225d238d95d4b62f937d9f26d12774c971dcbaecfbfe408e827aee97af5dd25b49a3a85a525a8cb7ee1d67ecc648ab1c76492a429dd5a839603eeb23d38ffbf492509bc688a80a5e89322583a5d645d3ff28add531b602bbb54af7def007eb3f8c71d7513d79329829a6947a5ef8035c853f30d62d100443d0022974799536fd501445960e7f68cdd262a86d6cb4d65ae36b43a4fb0b47babf6fa4fbd323dd9f08b2c2133e2b516b7691f9748b6108ad1bde54a72a207fbe238d9f66bee6fb92f953ab666a64f32b55057259911b55a087aa62c01ff1e7d72947dad9debbf0b11c3f5fa702dd9bc3ea0dfcdf0776e007ae40d64877063dd63831fe8169e4d0fde110ad8f2d03c8dc00d713bb55f8e55cebe38c2f4a91cf9a8a7cb66c0faf3a3162c829d8bb4b517cd8f433c963810ecb8685c3860e6dc74c87b66386937bd4bc118a057f47283a51bbecd1a3c74e8f1eb61eb5273958c0638987d2998b65b5295454817ac4889192a2a232c34389c6eec89eaa1b331ab22c9bcd764983064823fc817f65b78e1aad63dc51a24d9e4a951b5739f80c1c7b4ce911e5e1db0131f1b9f9dca42a95cfcde7e645bb84f9dcfc6897b08e049ab172f66a56ee6b843fc0aff15fce495074fc50c5b5a85c41928fe10da85df2806ac2f150e251b3b56cb5251f259f221f239fa3fa9a55d9d5878a0f1330ec01d5c3e63d6a3d6e3d9a7a6ce9d1e5ebf26541f6ada44212247d04c7efc61da4c953ff8f8ca2a4a6a8eaab7e8eb1dc49dad5899922352d9ad2d294d59c3d3efbf8252199a952b323db296272d4a4e4b0fa3a6ab62a58be0dbac81554304ecfebec48710549bae280e9187790680e9b4d9e6a54248312132535555f3b46a38fe5007796cc0ca8ccc068b027b0a51cdd2a83dc0e2d0333301a8c06a3c168305a267d642b1e4b1548c7cd3c38ad5fe56b016841f8e3beeb09eda3dd3fee20ed30d9994d5199a9aaaf0cd4ec1cf96ca7e806a3390ca604abc1a6c0aa806406b90dbac8f598528174d41f9cd3e57cf47dc9df31fadc1c563f87cf962ebb861eecd899f469c2429717e7435e9cd3bf4dd9f6c5793ed67d472801760a55408ebf43470e1cae1b365a357268e0dcccb0d12c3104bf95973b7cadd728727b7ad0e95450c512041590a38b65087e870e2b964674e4c0e1ba71c5f208164b153af1ebb228c69e25d012687df7c76056ded3f748234c74f51ee9ca46bc278ab9f2834f147357fe5e48f87de2836f248c85368b21c53910359a64d9a2463de3f43905c4ff81384962f2d2a439e7caeba0befcad514e944c265b610a6d3baeca766a44697489d6a88dde2854fd292796ed1437d4410ed79514171ce9fbf8cbdc813ba577ce69a9b5f30677a388da4ec34eaadd65547c53c7e581b881ecd7d6f182ae3b7cef4700ffa3ab11c86b53ef57ae0578ffbd10efbfaf47560f7e381e61aaa490fae047ba2a1924ac1688c3ec83631087d9ffc6b1064d95c857b6b909dbbfa4105ba780a062a9082590f82217ab4fc3ba1a33ad95d6b74d34176402241499dad6d26a2d68ade4696b1d1a9b47f88638908b3ea52bf0bf37e2c5bc5f3d510cf446d0751cc51bb4f7aba02904810d265004a617db6ae1c41ca3c40893c7be4f7dadbc9e111ca8551b62022dda627b7c7a7c6867a36d6b23436d2887d99b93da36876d7f6565d7ccadba6a565553a8be45bab76f26c554b32d6e25c627dbd668db10042b584921e2830f9246c0173154fd1163c18b6f858ab2f6ef0d577f2e547d49317f2e15f365df92d6896dff62908a1c94bd25c85463b7fab49245eac67a539c4d2d48eb78b32906691d5db8cb601dc14d3db08e333675ddfb38bbfbef03ebb8da1404e904bf708ae2353379ecdf30e68efd3a869bded156724e1e7b73e0cff059ef00f141f208f8e2b3c8234c42c01749d711f143d25567ece21c8ef6e67298a4e078c551bff66b0a5d2f268f7dfbb00974bfa049b6c52c6cfbe506778c6dbfecb16d4ea7be6ce80261d74a7e7dd99bbbb7fecd39d08d5b651f273d99d9163fd996c9b648988695b6fd5be9973adbdad7f9689a8b6fea945f2df47627fed45b1cb191c3ee06b39d6dec0b06c0c99c1477b80bc0135d62d96aee8a547f6ad250fd1267cf79bf04418d43492c1b81beefb86804c912e3ec12cbb0ec8218f47d2cc3e37c3a41d5fe30d8dda9f1528d37773f1c6fd50d1f6274896566be5c01b1efaf6a53a8fe5dddc7325c547fbc3faa3f4653087f17e7301a16f368dfa82fc92ebf59f9218553fcf085881f862f92656689cf228962949cba54e2d3cf13cc159b4695b476a3b6da145aa5fee4a7bf81d10631501ff407dd60e6818e7da7ea4feeaad917cbee54bd58cc9f5b664e7c1f0c184bdb3d3ef996993f73de169d2ffab703e9a89dec2f8374c4316a617f1e58b5bf1548c71b32fbfb403cbaf0cf271154d9f3490465361d5d983cc1cb906d7f0df6cffec02aa6dce809a49caa38da943cc1c8e640ce2e224a0166d99f06e9386388fdd9807874753f9f90e4b0bba7a3ab7b9c9dff9b01d271d5647713678a62fd70e3713e2151b2bb114af839c4469804495c545f57d4414f272ffe063568a88a491aa73585f00a93e7fe7d1b1308b34061f7af0d1bbb922596c186c230596225fbb6f6954d9efb6292d6f575c570c4b8c3ff652ccb58e64038b011134cab3f77dfc74b514cd9b7c453f6c5b27d31d2beb8aa5de227fbde2f716d5f6cdbf773876df5e7de6b05dc495c3cd20775fda97f1fa7fef87fb59b22eebcd7b2a27052704e507451eaeab5930bd47623b63b41419b4fdf01f52979847ea55f8fd4ff48d7cf1838664d8203b93c7f220ee4f24807801f7ebffa7045babc23ab074997179b636b7ced3fa7be7135f6883968ba6b57b392afd26a67684bfbeeee42e66da87ab6d2faf3ebdf5a69add59b3c146356f96dff6f86770b01a1eddbd083d7be7f6bfbc35e2f9d188b2e10f0c65f3726cb07ec4b7e9b061d463a01b65620dbda3df4b858f55ae55a16a8ac4e167ac82b3d81bbb5f9e9de9b1d46438b33dc597c5d475ea2ab42adae83e7eceeee4a78de3649116b9ca4d9220c1458ca0091f40210b32e4db1b2675b7b655b25b675a2b22d8f2d676653aa88920554cc3a31c132c66808a332c088596badadff5daf82249c0755238907358574f8b02decba7d0fd5228cf674d28245efe9a4e5c976da82dbd3694b6db7f674da826471c531d24cc9154849d702f4b35e887e16a9492336e47ca298fd4250b4218f301d211d607364066943466da24d6f689d2c2794991d8ad0ad59b3664df7de5876d9c748bf6b8dbea4ff161c1e628fbbe8ca4063e5aa458d57b594d12255df9d7a40d76cfa816f5d5f3860c8aff91e04089dcdd6f619459dbebbcc917c53a7874cfbcf1b63e81e138276aeaf7f1ddd33a5cb1935c40224d41f202370d0cd903eae63fc5d62e8ad63336d485b5f4d3b7b00becd7fa3cdb772ced7c0f95abf35d61873461ae3579174ad38630dab26cbd7fec2fa0efb6cc6cf8e45aecddb904f95282de44197bf71393b91a86d5b55dbd6a91b9c204d501f34469cf1666cda43480832c22740a702d178ff9d0a94f337dde78caff11d8643de90de6daaf56948da3cd1b61fb2f40fd53a126d5be46e16799ba01a84b6bec2909cdf371db4ff91b304371d729c5d7e39b1e8ba6a9ac9601081981898e492c8b7261ef20064482267450b0eb92f625dd7755ded3adc7d0d24ba6cb5c0a89034550605597820438d952c57ac22e0a4c995284aacc031117377f79e3274f9da3db854a22a5364c43039b303d20b9d65da5dd7755dd775b5ebae773edd7d8b290eb2761d7eb7dfe1aec3ddd8ca49a34b3def9206a460c9cc87334d922c9144134dd068001425502dec00831360bcdc20061326b8b202cd072498a0d59851454a1326baa8a108db1134b6d8a205aa32686a10a2ca9a2b49c0fc1005134f43100105092f4c7261a48ca6e88e5822089d19a868410baa24537039e2dfeb1527ed911df9aa313c63fe2d28364a5a9862885b9634606243bad97546ec4e092bbbfb0eea8fb83b1dba94a144aa488c24625dd775dd50d791b6c3b8eb7037963387871290c3852e7502a6d0cd422482335c64f9a1880526b6a0724341ce0c2ba2aed40003134a2871040736cc9ca850aa628b1d6e0d892438e84aed0733b42fb8f8709bb62a22083370932101e505882ec478323a798823a2b036700a96ec4065ea40ddee1a4c109fbdb703d588c5f8fead459470dfeeb9cbebf686f56b73dd1d768140b3d74b62aa41922eeb2e81fedc942cefbd25dcefb0bbe32f0163f283b92f69cb29e46848d03ae8fe4e66df28d029a400ba665b12a34037c598fa98f69ddec903d6a7fbf6f0b42482916d3f8770e9e75977a5f4f1ee403812c2fda7a5a21a7e40b4edc6395440477d85af8296ce0d2b1dee74f0d8417dd113e096844d2801a9c0f0311dad9e24f14ee0e4857c8224b3eecc0c984ac98d3ab25d8e7c08488b8911d4d6e32abb4b12ebbaaeeb3a2ad4759d98daeeac0e6ec1e26bbdeaec00f10df674a2c20b313d6c1b2adf7420cf6221450b1e4a9053051022c84256772802e389db6cba22e90b1c104f525aa05292c9625f680a8a25d1a67f69ac92ae42ad2ee549d39f3fe80fc779b552f47cdf96fa5069f8f2a2e9d310b2ed800edcaeba3e4ba902b16a2c9b055074a943564d0c3d59b45db26a33ccce5125d3f35935cbaad59fe9b44e179d64d558b54d9f65db4375a8eac0e1ecfbdb79eb0112df1fc814c2ef2f8ee1088ee3ebe43067507fe4f4e9c4ee8a588d16ac7ec276f7808c499dc9d3756fdf4a607fabd54d60dfb75d8749eb7374d23e511c0a76cea74395aee03d3ed5d65adf9fda6abdc77c6ddbe3b55a716d0e74bb3565edaff7c08a817d611800baa755cfdfdc403ba5ff690d3ed081563f7318fddc7d2b31b401bff12ed1a1077877e49de58f06a883630728c33175d8a864b7e580e095797b829b46e801de99cc636b0af1e0d9d919e4b8403653dad456d361c1c4edf80a3cf7d7e140079dbf46f8a3cb38bccf39c7b176203d661a5ec31db415805726f4fb085de61c16e0b8a0a56fd8684101400639b51d1a351e1e336c4a51966abfa32cd96a4b516cb525a570cc2b0d6c7a740f166d41c1c1b169611c1d00512b21394972d5b4e724498996e4448976932ee97d02082f6dc945f2beac3433e996205911ff50657267ee03662170003f409ead3f368342f93fd077c21f9d0674f25070f431effdb29557b7ee2f304297fed8bbef3bee59933d376f0e6e10e08bac88a9fbef439ff3de2e16f1bfd0af1f8ef6bbabe4b029b77db180e3955da32374796d3e433c85e7892eef942bdbd9dd7895c20f5edb0260e3f1ca6e5185d53ba5c39684ed02540380b6025d99d17641d11f061a5c60814e053c7876320000ec85414fae3e513e5a1b62d5af33beeaaf13d7ae4e7d4e12423f8bd1b5d65a83e8d10ffd1ca46ff476f354b7a67d165966912cf5b5d4d2d64863e0d0fcf93386501a0dea79cd2fa98caa35df8656396c929546b1eaf745cba9cb6c97383e2d1cfa4f57a8550e8ce5eaf6c404af26502a0fe81d3a72e070ddb0d1aa914303e766868d668921f8adbcdce16bbdd20ee8b985698a134db198ee71f64f58cf0b88aadcd48c429a19c9a0704db7fbe09e385dd38daae044b552db37f7fb13551ad349c3c5a4511fe540396bed9476a37d5425298902ddd4b17893dfeacb1f00686e733a6e0b0fe273cee9412a509edf33e44034d67d140c3f7c4a29a55aa4264ca8570f142d8a24931d3a6999b24510443102343ee785d4f896485252088dcff91cd208ced398b81d86afa54b484508c96cc3ba7996288affc1dce213ed702c7f0fb9194bba6f5e1cc31bd6dfb0dec6d6179ee2876339a13870123e1d4b22a5d18409f50db937769fc732c7fc75fd197b5ef375dca6662a3d497499b7ceeb494ad4ae0f5a27bec67a5230f3f444b5e7d393988ddbf3e9e9b6e7e33d9f9ea8ecd59e4f4f5236bd8013154ca891deb2e78bd9932c525f333c3dd9b0e9d313934d9fa400ae8c2a3635787be2ca90614f5c194b7bfe991dee8923036ad3999e4f4f454fb8aa3d9f7053b8a83d9f70381c13db66cf27dc944dc959814fdcf3098ad9a64f50c876999fb88cb1e9e76ecf272e60088511f3e5c916dffca933058dfe0728e8fadf1370aa36390e4dd8305032e090840de3c427c4c54b843ce09b8488d4615b0e530be3831786a6c3ccc2187d60aa3278c314217dd61478828c030c98bba713982ef435182c606cfbeb412bdd40830d18a41b5e98916fcce0786568cca042e3080c0b3644a9015503abd136564b6e581715451647921638a0a8a0a26c5038bb25a98a4d3fb4926da84287beb2c3f6504a50b45b1214921e2d944e7a81cc5046339d2f55d9822f53f9824fcc05a0e705b462c61318809e17fae013e017237217da17fa61cc7cb9a17594b3a7d317a3eca5eaa3a299060088f13d9d9c98b1509f01d8f41981f774f23265c340ff4997f45e8e567b3a7991e5a6944ed0d3690aa829703bc3a0c3291e395168407ba6b86dea9afa2e28c1534dc9812a90c4a504392b676460c47adc92a86021440f2e10119b3f7fb6ebe7392f9893d1a97ffd0711ffa360e8e0fb832e8cbd4e264fece92485b6a188645028d2f4dc753bcc488e248c502c8e9850c5c0ff6cf81503347a3a8cce1ce672f1dd4921e2b3482354242b4d365dc441eb0fff48f8abaf4242177609117ff54734e9c2a490f059226984a974808e2bb4180b0428bac554985c6631f13530a53614913c32e459641087d50f7f7299c5582f3e8b2489388c831a9c4e39acfe8f8a830a2f2f3123dfaf1e1c8da84097ce8c0087d84732595045ab4097c88cd1456c85a5deeaab3e8fa52d65bde57033fcc85ae342973557cd9415875d99fc6bcd816acec95ab5d59c124a0e840349ab2c9e314a2b0e69ce81c010fc5644681cc936fdd86a9cb14f93d165cdd9d8a69001f6f7f5ddc87fe540e0bb7e22d60b119ff59e470a61bd268dac8c804434259757bf5689afdf01acb761bd66912ecf9bb14b6df4e6b699dd43d285bd858f746192e22814e9f2d5ea3fd2e5ffad1e7c7005feeab7d0bf6bcd4d587def6235f5555763ad7258ad329256d557c57964abe2aa1a5b737ee44533669928d7d781fe47ebb6407d5112e8a465760b0ca93f3e4b220b90505ff6abb8bbd27a5b91512498c0529a4204a0f446161d9ee8fcd2a7bee807d517adf93f3b290a364759fb8d41f5e528d059c5211dcc280b90507fc217ff3559126ded7dce5a97ad9dc9d2fbf06dc677d88af543ae47f1bd1a869ef8ab2c8a9f37387e506c742a107d1b7288052a8c3e8e3752a13f4acb7060085d74f97a01993cf58980a0657e710bba4146e8241fbbee45b76c2e9723921b920b02a3cb9c1c7c94233f220e34348488030de5a0724153e832ef1ca61ad01faa7826aaf96664a1607c4af5a7c4008329e46f2b92a4292d967479a79ebceeebde5eafd72b686a031f578bd77d1de9f24ec9a6ee575b9df9a64e79b5cdcdaef3ce235d06fd941cec6a6974061243af219de78d133117ea5249dddc8c0b11382e45c8268f12a5a5a827b54a8911d3a5cb162cf466866af3c587f6123d5dcf0dbac44d402a7dfa5886c568cbee82b4c5d06c0a1f48b344db777cadb7aaccb022ea93a23ea6a690bd5483f29620850fa4c991d091f04497b8694e357546e41adcebba1170130426154fec3a71403a2036e812378145a0d114b25356a64453aa95442e31df1a5d521995c9681aed5fce1c119a52ae92a1cb193524bb56a3cb890b626dc85c9bcd661bd2b9e5822eb14d6963255cc3369bcd26457fb8fa63df66b3d966d46673208a4467363ab3d19a8dce56d065b6edfaf9498eaac105e9390cff2a17aafa9d7a24daa373ce40e4db7e1245ab54d52c96c974b6e490cd181aa9fe787df7926e0fc1078a216bd970e99ca7f45f9ad22e3fa9a6a0a6666566572a8be29b3a9ff893259247c4078f7c9a3cc262fdea8fd8acc66f7451f185b05e7cfaa2f820e9a246c067912eca7a21dfb39e86a411d6afde88cd7f1fd2983c19045fe713183063e26bd28891a9dd0893109b120aeb4919eb59a40a47865ebf0df859d701e4b2c7fdc19128f636a3f87a643d1d43f04dff03472a3332c461fe209982c3fc5160c08c9dc080190ba9ccc6e6cb99b3cf7a5d69a125673424da4c7c7064fd0c45f0fea3a34776809e50e90d0523e28b24ad39cc193063455464b186fceb8b218dcd90923826b476d7b9ecd39fe1255d960c811c9289ba9ab1d0ea17ecbc4e7f22a8f3baf9726786cd973e3b68f2b85b9b71ce57ad20784854436d0530686882690a2b62b3c2565fc7902c6233d25d8d6cfd3e9a00ee1950707e060ea95361f66d46ba6ff843874834786d9eaff06758041cad0d53d8aba72f8e73bec2f710244b237b455a9c51677cfd11dadaefc126b096fcfbb7de647177af2248fd9941863a00f23d41bbce39a188100197bc47522615568188e4ea6cb73411affed449ebd576a1d3e20e8258bfeed7cbd8ee57aa20d9eeeeeeeefe938b2b479ca9626326045d1ef21d7dc61e7f4a963ab90a1918321912e854201bdbb1024a6a8c2deee92445d5eae17377afaf5c5f157477b7d6adb5d6ea3ac5c5f75a6bedc5d6e2fb81711fd4ee6efdb670c02779befce7ef40ed10babe5b4a9f4ed14e7f70f79d22747dfad9babbaad1e4a14f378ded4db568d327da55b4d0163050068dad0a63c989354be4aeb460656e7172f2c416c51563aa545d3442a460090f3b0cd103166b88b00208a918a280f1421755f58c0e2bb22bc46ce982c68814be60a1a20a2b5fe0e0c4991c8603c0c82181a1891460314410275344a191aaa20cda19d1cc0c25413ce103172839dc5af89246891564bc08d3c5c148a20c346b72a86176c44252103944d1e4650b2aac2f66134740a1e2a68512499a2080cc1819b850b1c36c8be7050296a449e26987269a8c70218c29906842022f929af872442e48d96104512b8431430c2ba489020832a238220a49d8c5ce0f49b620394ac26136c9c882ca0f567e18c3c90e980b2750a08397309c38a1b261833267ca9c4982448d0c9a6e8b28a6386121e98b2a3150d0b0b4c5d4122d0731b2548154385dba60418b318a6861d45052021bb4d0a2872d569c01d2000c2e3488a9e149154f5e664fa71c90d0b214050f5c9634a0854793e18a292da4712244acfc20a2206e4cc4049193c50015a3dfd3b4f39e216d42f39a5fb24c2d16483345ca48ca940f68ba2cc25853860b293e3c71a4040353524f60400208a8a82450f46736c04d0a2427a81c92a4c059985ec89a907841c612150ce4f9f3025d0aba28a5618a818c2a2fa22863d39f51a4e182062758c8c10b08a634e942b5a4ca122fb2f8a03f734d22c8816cccc73743c9099d41ab2d1bae9c6db8e8f27e47f5a7c421f3ff6a1d0576c613f7c688297c63b31d98b3d63d2f0702e2b0fa2ffffb0e93a2aa3f75aafe7856e3cd2832f3ab5cfdb1d75b3d3db6007a70d487933da8002ad0d7181dcbff1b29babcb8d514adb0f2267d6249b42fd237cba9c2c1e5f7f05b4c5ed9142a217cba57e0686b9367f5e10bd5b05a09d9a0c1ff849274f89e087ede20f857368570f6eaafd114aa7bf5dedbda14cad92b121c73f687696df2dccfe183f6cbc27df07960c1c622640fbcc7ae10f2e3cf227424c629536942306983dc99c3ac06b48aaf56b2bcb76bbbdd17826d0ecb0ebbd9138426525bb67daf3f63f48402ec39792c5955a095ca8278ab2e77d923bb37cab11599b11d4b9b7d838c82629e0553c8df8d33e67527a4b02d0d45e8f60658738e2774db9225b8eef07fa0a35dc657f4e05a387448a0a71316b75db6b0a8ed32b770bc8e2b48feb9855459ec5b79abb1c885a0587ea31cfb3e72f579f4880860cf308499823d492fff073c8f9cfb32cd5b82add665490f6297340aaa3dfeb27fc73d8d5ab1fbdfddd348c7ba3d1d8f463976dfef57bff2d347ad94feb843c9ef84056d97190b249ca7414fa731b8ed344636a669572ba0767d9c6a43215516f3429c3bf7b7f545f30f790adb625c4291ba2dd901dff36ff60c43c0604f12ca07ac4c4665b258fea11ae69bf3c75aafbb7e39e79c28d05da47e39e958a4ceb796bed349913cf57867635d7e1f33595d0bf03eff085eeeec58d4bd2eca3f1d8667ec678fffd2862080ee7af7f8ffabadb5deb0fbc953ffa7d074e19b3a4cf78e1364eafe8e28806065b2f9ba21b81d7847148450992cf6fdfdef1be98479207831f01b29e86d8c6deee85a40f8e08ff023cce7c086128af8f67e4e6da21851acfef78d451f3816813f1db6e280a64f9855bb886ffc3336678f8e5a0f88c071c6cad6aed88e370c41003bd739a787a2477e34638cfdab1963ff72be5b90bee9404cf63d26fcf6827077154227ec5e9b3dff137091d7037f1d3b4ae4952a9436841b3ae7ac57a41db59d659a239de19b3a4cfe391e99e8fb88c23bad36682b8462928e60c47442d02ea1c8268ae1ff4ea0b408bf0b4c2704ed22dea3be0b4d1f63772cedb65fc3106e6ea8005fb366bb02f2f5e9b5567bc5a2caa8244ef555310915b28100000000c314003020100c07c542b148240d24395b3e14000c76924676569f4ac44992e328ca18630c228000420c00426066686856010ab84147f5bf29e40739a288bf58f6f3e206c2ec85a9cdc49152f2c85623a5307f5d698740a5a34f7238bae1fd53d60c1e3814eb6c756c84e35ee683700bcec65c7c19b5c071b2b9634d4a3643e8bbcb19375c399aa46f71aaae7f9d973a9ef3b3e2ec0a706201bdee2ccf801127628a477555f3a9b99ddce46a179a67f424207abd4555e34ee4d3f6ad50db97dec9e8245f25a595d11dc3de5e06b24141e451815eb28c7ad279bc8cd8dccbc6e160cd8a33758ebe6a2f7ac06f6027935ea6c1c669463ab32caa7269762cdfa34138ca8ecbc9ee36e9e6141c0f430508ba157e6437c3eafe00e095e714c5b35c54ffa9588ac0473efd332c7b36270d76f1bfdac5ffbab13dcea52054f1e40cf317d04584d6883be108f2136433c6437e8c274a75f47fbf21072912fee6668cd24318171fbb6db89725cd2153e85e2837851bc54cfbef9a6f3c9e257b2887dbb6914ae020e2245398be0b8bcbdf6732317b7a2f89ef92b5e7c53244adafe37b477735d1ee8893dcf681e2bb252a2e0878177ee41bb7ec9c742065cf6b593831bdda386f178bd9cbc280e7c3f3dd98ff70de591ec6e040481365db0645efdc741f43a4c957169ede04f1d15048d6e4674ef4d340a4127a98068492e842fa436a63a205af0ca745bb9845b6af47d613c9561ee8b3e8e1893e1b3d60f696e0a0b1f1c09ff343b4895e55c606766d70591160a4b705e224a71284c63d92053edbef334d605985affc50092cfe68a7a0cec3bdbb494a6d94f614aae4a70ea0341c25633f1bac6f0db80fe135154a97da1801c220334b8b267554bb433281b2d3e96541ad5f47dcf291b7fc7a11dfa95b3e4d2d8f909992f46f413b65c05cb69aa5479c7210ad709473aa061f248243f61d2a41a4ccd2801cae1efde9181b679d8ca011f9e78f4e826bb07f5be094574b1dd50d6a9dcea3080182c4d87143e476e7ded81e3d91498152692a5e37d445ac93b647414a6486c472daf23cef58c7926c5a99f9f7a192436aa93eba1024e45d13f518e89e98c2e95c2b65efd0436f471a8505b9c32bdd318ca218f360ba8bf25c313469493d1a543b2450f31013f08eb1d61329a4cfd39e24c15e3fbafefb08692a4e6aafbf37ad42b77a30ca561bc55eede9e183dceb4346bcff97f3d50614d46bbb9e367a61963582c210ee327ac78ddded6ad9ab03f53f3c07dbad9f4078057eb7d4ad705c5025b427fd8a3aadf58cb90874f97befbfb66bd40c38a58c6499187c589e1605fd0f0a51b4f3f45c5167107b6ecf5d5168c4b42051e3f4bc2ebbebd3c364341c14bd14ae277123fbb7b125fce0124c1cf1f589cbd5f939935363051526d4bd7d99fbe007eb32a81d7f11027a3fd8f1446ee0043eabb9cd393762daadad132ba383c87afd70bb83bd84102b5c48ad5e5a742253b4a6dd237d9afb19366a855f9cd1de74f0a341140b377ee616a0f78dc3fbf9dfb6d526ccfe5538955262fa214efe1e140dc10cd490ebb554341d6fbd62097b373a56dd5e9d66ec760070d875955df97f17c88a263c6a809f431a9120d96845b419db162b7e97fddd9c116419a8172159922709d5e88ba8b0a9f25652a7e79452154744d783a01ef777bcc562f7225400ee7e6224a316e20b2ca729fe4b9b3322e5460e5269f130df9d5ec5807006cfe0efc0feeeee4f65a387ce9681ce82d6a074339cc0946890407e3f60ebbaaafb87c07f98e3b9d382ae4f51729e67f0c0e1b90c13692aa6bbab37f73bbdcac63b5b31e03eba4705a1ce5a01ee1d442b7f0010159c092a0b5b4b22ff6a47dc5517d26e2986a8e9ae8196c5a0bc172050ecaa2e9b3023b78d4c45658c4ad404f2343b9b9d81646e3ee4693613ebb7e9586bc9db123ffad0b73a7a3f0039c6279428a0472499d8a54539c244b9c9aac7f7aa5a70e5d7e6a06ce931c7936ab115fe88b25e23edbc190bc0d3c8b32938980d4b181cc08c2b4de62cdfb4aad1dd3faaf7c70374da807e0ef4de05e16a88916403a93318bb783440a8dc3de5f4145ac52050efb4a5e2c72c35e91e22abb4effcfe5c3f469d2d7d56e5e806f330d075b22e817ac60d620aa9792a6e3debae4c496d0c6e4ce3d22d5c3bf4ea087fc4846484fec7a23d49e6d03258595200d46eb3269e8ea149f6c5d336a0897d72fe62dfc27678d80fc174a06823979cc857522214020c9abccadbd7274a9fd850bc8a52589ef3ffa7f486f2b7ccc8cb93314f912107dd31a4d56810c9bc7a59ec3d1c80c1c799bc2fe865e3db2bf55fe155f1a9edc352563438cfdede8dbcc2161dd255199b44b9032971e15065f21f6685faacbf89b4470a7a6ff47505bb2ba56ddea3d3ad758dd52d4c7c7ad25a44ba37bea2df63408be28710012d5f6d4b0f1bc067f2c481d133f41c6da768d0b84eadf7bfc4129ff022b2b54af3f4f1dfa1f248e2023153aaf8964942ba5ba253357d7b8e353a5d7d6809f4d4f0cb9b96455e18b591027b7ddd50bc4f502357a7a6239786749045755d1ce1e09b33299a2bee3a3e4cb723caa325888a69519e8ffc04f55d9054f3d0acec8dd3a2e62e4112666367a98dcd94159eae1ddd9712e04dbe465a0bb164a187f5388d81e7acc38ca38832a35ca572dfbd80746aa310b3d4d4fc607dea1f0443c166d540466599237ff0e67e4d06b3a28a69f747974bdcda227674f01d78c3ca9e2bcc5255842cbdfba62a0e5c8df4d3a7a78d4a76a0766ff777a879e3b6e16d3b9e3a316fe0d424b138b9ea46d2aef073c10bc1848be3426dfacabb2bfec533155c3fb31f146b099436631aa2811a2e9b86048cfb7b82a654db1c8db3d913cda8cc2ec62c7cf7c49d0742fb9b27667a03c3d79dccf976d0d5d3b83f7f4ee809d989b21ae4b6973ed3cbc23e19ec730146ed2ec3a7af39cb1567a04ea05adc8261724876dd9be7d9bd000e9f43def0d98f6916acc1f65ca95b21852529da9464f8317aee9ffcafd0d35c23516c91040aafb51eaf0f7c25340c393fd29c5b9cd9673a699775908d9a351a71d9d30e217fc667b0664703f2cf13238d0a0cd3f6f8d362f819d0db14e7c64a1a8f1dad0e09167931eea9fea7eb4fccfc6c43dd3525e88d7d4c9a2249bb6887dc313c4ac40a9bdd45077d95855802653c86d5717dbd9c3fc67a543ca216d62d6b6f2cf6990811ce15c892ec15bf35561ae33d9510ae5bb2d87b5e09848b4299e0b70835a6c636dbc6d626a798524d4adb0db0c8d444ff0cb1ad08071fe63aaf4c74709cb1fd3e79145e7eab8dfefc02298feda7b31b2a39bfc09ba767e55b2461f58578d7245bc375f3d9c7bd9fa2add836177590f4d41fd8befebf4935aebb4386d2668707328b609fd42f55d2d0d9ee71625f59704bdcd167f63f498894989d19b12cb14fa7f1163ea405d3c14770c0e474badf272e345485511b5f9e947b03a145878c861e39255fdd44c37664b03eb46b81a7cfecf205247580ba49115001e7529ab324b3e127ee402283d3834abf37d87c5758a77f4ef71c0113e41d622fcbf292e9be95b08a8f0c03e70e97e6e39dc9e9f012e7c99f1f47d2862df2ff614913e81c1bc4b6651920e5f88b0f967bad06f0fc1974b0c4f81a4b8ea913aac8836adc3b55bc425d50be0b328701ce594f590af249faeb7459d23e501beaa570fe1d97472df5fa778ae9d5e3fea9843fe76bc40e4761229a05a2eb0bc8e6e722e75476bb98a1bdb56661ce53d1366722abb79db14f4184ad1d34f81e51583bf6e44685ff46436b913193e420628343d2d9ca8404fb734d4eb6bf7f08d296d5e89c0a3d253b6f699f655a54088318340f846442f71e1471ea839ad44ed24787010631e465c027f6d27f4399e4b45bf1f1e0936809befcfcd193952612be140ae9dcce9d473d7d43503467dfcc7332ae81003967404b394f252696d963ad9d7762d7ad9d35efd6a21cdf7a4a6139ec7b833ff80409beeef104125b93dccbf4d9142f2f6f7f1b91d89b3e363abc8c7e767b13d10fdbb8f3db89cb2e9243377f42f463e5b66211fd44cbed4e843e6ee29ea459143bb9bf09d8e78d3ba6c845b9197873e5900a1a50212446ba412b08d72676ec02fa33ad1503f5ac7f7079984574545a6e836e2ddcbe8a6e94bb41b71677978a620f0fb91d74bb941bbe76797572f327e01f36f86995dfc959227591b457f80d9198e5c31a8ae847edb97d0d4c94925b9dfd7ef8165bcd38a2ad9ed70cc982686453155f414c7d41bc63d267d8df46dde75378e35ba58a89ce5f91288ee7b6351a339aafe333d1bb4e782bfec51bce886e580d67b937ba2eb0923edb42baf2f1f22eefd5e4ed331384db5c81e75e350cd14e834e1a852490c1d534b20e13a255399dab9b242809266abeefe08ff6ebef58f904b6fa7f2a1498cf703cad64e71ea855511460bf0061d9b29c430b35130edc60e509453ba81eee4c8874aa2db52c3e04127caa743fbac4ab0d536566dc3bdc499a6aed71cf6451122a912f857ba46dd49e17bb6f65fced1dab1c4db24db8874eb10251a1b706aba2a3dab77b13218c04475b09e9d123bfd45d1a2a32529fa1c5cdcf5caf3a4fb6feaa682d6bf84ed07f98a40408d95e7689008afe284449a89424c1d7de156fba4c3da2c4bc867392a1ea63067e66fefff57c5d81f88911f0d410775be2f0c6ac873fd06de47bb16c4a1367fbe9ebe986de20857f793478599c50244fe1574a5729d6a90c03d39b8abf6c6b0c39b5b16783f92c130dc8cc0e727cfec07d63c6b0793d9b6b2ccfc53600a3985e6e969270475fb80124b638df5c5795fd28bfc07c30fd4f2107ad3712d81e40c725b775170b73346db09001470d3d34b858cca2109084cc712d2000717e4d8b7cd1d997b8e4007ebf10d2f7886c2ff3abe2fe6eb8c94aab49b440fba83e1dc9825f309a6acfc3b408c8ecd80724182a1d4fd12533fe572c2cb5f029b9f2cef0c68a4b2ab01debba674b604dcbda2c0611bc22d6844cf77d7f32dcb0d9d5b358849879cafa2e2dd12fa3981e88644a45af65ce6a32724b0930c915732d8433c132abe7aa72d2b778f819b3ed5e1227240158dd120dc06f83afd5e6c77028890068da2ad5e30e8a810a054b247d761ff7a988d3a94b94e215c8866e477804f0464464741601c44e22281d1b730cd60d8881d925634481176b8da1779e7a8706443314b3679484045c1ee96d2eed477494bc0712bb7c6ab98849824b579d6ab2d75b9fbf9c0143641da1106352454ac5ccbdfd82b97953c1d79485203ef846923b9252817d3372ebd98802c9604374aa50a378d33116375af05aef69a4e365727a7477a3f04d7e4fa082ccfe540c209426a0c0a1793cda4e52467cf86fa838f9c11afa7806e2fbc01836dac9af11920c2fa855b2cfca53fad2994f596c79edbbded7319cf10224d4f55518a13ea1f6800817dbf0ac6f341b2ce4b7f8e178c0041801a14e33d342e233296302415ba722d110416aff8b0200f4c95a199e8e920bfe253205008f25c1d3a760b03216250e3bc8b0c5f22200fad89084b4c0a35da28eddaf9d938d60e6bf2a1efe52a2eddcf621c2eccd9d984a725b17656cef4252c8b4fb50505a4bac3afafb4c2e389e082b0e0704989f318859377d0ae7fa8ac62fd3e89c1cdbc628a2386db7a28a308108d0a92cbce365d7341172d330f3795ccd8d0b65cc6d36a4595cf4d69061ba0c7d7a8ff3a7103d175dec4b59eec4a0e8c78cbb76cc9ae9047439e048735c3b263b8b4f483947d94acb53f99dc1346352691b1cf1ed5116427851690fbe0b35378f55f2d025e0f6bbecc83e65c86547beccd1be6b7066b0e65423789f2eb7004708474f0c22bf5fe13a268e94a139183db4abaca2e5ba0db54ace155491fd458c278c3d6a2a684182a0372529d246b655cc74a675d3e1db9aa74e34fa46ef3c6756f8e9f74fa6c626dc133546b7d002b9015286e2d8972f92dbeb7b9a575f5c65203f1456cf28685f7d719bbff2388000ff4b05778d847de5a6c28bdd94c560918e86fb14ce1085f3c9e131c498d38da06b6167bd1dd2b15a9057541012475a5d5f22f46acf05e9f310c50d11b799736f658f78cf3f5cf3db6c090a8a898e5148a9d4f82f7fbb00f3f45b445f5a4ad00f138e6e67edcd9be5c04156c405db19dadb0b0ea3dea86cced164a2008d0a33c3708010931183c41e855804bfaf0d4a4e85b0ad9add58888b90c62cb6f8ccd61a71e1998b3c25b9326cfa80628f20e87cdce008a92593d60f30abcfbefad76598a792aeb1f3ade22dec589b6e893817a8e1ae02a25a355698bf893724faabb9e6d4b28ab13588c64c433426d0179631c5e45da18829535e8dfe1183e2b4ac44eb47cc91a7dfb92d47bf61012ca9d8b93c056b72a9b7bc56022d768c0859ac88265fd594eee8a82219643e4ca8433cf7a68e0c292286a6d5ded8048ceebe28b0d317dbffe2bb665242eb0f1a69655b54dff0567df225dba1c9053cf8769c39bc426173e20db3813a1bb2f5a427dc37dc00d4804f0b7a0b8f061cd517ce07ffe3003cc4976d1c7eb2e280c1372ebf7ee79fcb990f44776f3e5e37e642a1c92940b4f61d3667fdcc09f0aa13379165a5baaa867db58b25556cf922ed838fc0dd202e6b000ff916a4d48ff5c23207d38ba262cab4cff6baae29128990706480aceed12c95b10024977f31121db56535db6ce6f34dd78eea24e2c03ae90dc1625cb2082eb6b01312d2fad88a8eb3d935963899ff7149b9fddbc067ab507be4cf772b8b04677937469485662c1d0abcc8a983d55c8fbc420d388706dfd8921aa232b0b8feef723af07218e0b124c235ba4bd826e6c8bbf4fcea21097e11874b99d55b2d3b5fabf11dbaf7e18e94c38301937ef67fbb6dbf105885894cdb0e07adb7e9e85e1a459950e063e906b086f3554836f3fd4ef81f0acc02caed1ef99f268cf50e3b9210a4ec8ee358f363e09f8322f9984a551ee1b9afd5ce1b07156f1009f0d549d7c7d351a38d3673b64ccceaf983016f1d018fc33c1a462df98303fba51f68e05c2245d13815418f29ecdfc00fb74343aa57882ac872681c45e74bf2c070e43a14571beaa82510242e520a8903ab0406f85ca521b3c85d4a27e561ef440ef098957c866391e0c53af7dfd45ac26828e9c2a34ede99290e0075ea5fd1229456fac5e21edba2b16b98c84642892ee92d77ba49fdd2ed82d2ded75d0febeb144dcab70069cbc0b7451353992d42d38d99db4b250750149a492534d16cfe49fea1af79a1b02d25da4da09a103815b07a997ef7b271bcefb39c11291f41ee595eb3e93f173d2e9de4e675f040dcac73472cc0b65e121592b9ffdfe2c3a4b77675564cb48e10a365495d0a94796cc717e0946ba761308e10c3f6f11cafb396752c66d2a575c651449c2050244a34241fffc5b2dd9c71ac163e86b1816ec537e90e0be7e09411e78792c69c6fffd35abaf0d7aa2f9dfd4500718de5081a8bcc368717081660140f58577dc1d077701abe99be1338e564ff47c05f249b85d92de58cef003a16eeeaae4ebddf736e8f70d5f600fcc99bb21401961c0e56f9b772412585df53cc026729fe20f5b18b0c223ceaa97a1b5d2508a9ce5631ea384a7e7e85148ba5e470174526aaaf671ca9aee9def91ade0f5c8e7195067e7594b7d12e955d1c930d3c23f633568ac979e297800e8f9e384e056285b74504ebbb52fc6b49d65ab2104c2bc2ec73f8e1906b571ceba643159072fd19abfa5b65c5dcc3bda60913b1fdc3605a9398f8ffac5f9aa246474ec00ffca32002b167d4c75c148c95e457580fffa48cfa400de4be945ffb31340ce134f1ddb9ad4d6becf315077ebb7997dd2d8d27798f3b7213a0c1f155cbc34d64c37f29889870275b039bfe62f1d2dc0f66b510c10116f4af8c880273bdd3c66bd255fec249904bbeafa21426a22d0fc6df7d37f9d9862247749d5fd32e863b5994fccc86ae84ffc56de75b986e600074a5e0c617fa16bf2bfee30b6e0f6f9984dd04ea88a2a5d9fbfbb81bccae66cc15e3d5f603721a0a054801711031d0c59c881069497aa15fb765c07bb60f0f3f3e76240ea8ad7c04465d9a21972da52895e3ba4d2eae4835f55bbe6d725c8b29a5eef86e92932ba94cd5e5db46b925c80384f3890f9f1219e0110843329911a803a5fac562588d5f121a3df8efbb2630e881510ceb5781ef1fe55f43b34360c49e444b944917869b97260ae2494aa2b48275d4aedc3aa4924cf6d994baa5f0f22005d71038a83eddab4c1cda3985aca60302135ac0f259c3a18226ed3ff2edf579b75507f129a63a487033d292c8ef206670373cfb591a8aee2b251b0124425c3884a16559af16137115be15c054a078c1acf95121f41fc7ff031ce70ff8147b1d4d2e2806294711a6b7935d67b949224242e13d07952105b7c3fd145a816248a4900235649dab0a1700c00a97725523b35fe89ef07aaf3adf93adfa339770a2001039db61c6ba8f64b0c2520fd9fa8452d8d4395147c759574b7f99a8a81b628efe4e05b3f005f712357556cd95e00e0c0d5cd87023ff4c28fc3ae8eac6922e3a69d804c1abc4dc94925a8eff5776c1ada2f1120edd3f0e4f36ebb6bd1c8b32a6ad571511ee26ed94130903bac9d45669981fce989acf9f913fea418005510c8c85ac7f0dcb8181fb478548f52761500626ebadc67ece56c204b038f8474c7b1cb3995d7307bdf448e2076ba37600cc0335e1eae02cf7609bb040503524ee1e13bbda4d417aa356997ff29a315b0bf8a454fc4c68f5abcbb51c03b291f43593843b200aba8f689ffbb84bc574b4a54faf27b85b554724a4a31104a7e00840e8b84dd6b384d497b3c5bba0246e2a9d55326cb6411f4365d762f8004f299e5d93bc8dd4815121cc633b96db5e0d5b01629772dec5116b6b979dc8ea23583d0def9776f801371b5b5167b3d668632c8a2970db180b19295cd933c2333be39375b74f0c0e44fd3c7b12c4c25dcc62dc2cc44e805854733155360fdf484329256be245e64a99efb32f4f9b1b534e588117851d27ebb41fdf77c5b9d5817dd979fec7cb5012000a8069f21b8d590195f079a93dd77db5474a45e675df493028ea0fc1e47b4a3b406e38a93e9b2d4c7b371bad4046ab04a22184d4f8ad7750c536b824ae4c84b0de1185c63f737a39b84aa5dd51215d2c4e669b7a1689b7b63604a98909f5676b86c2f2802d786a887858776d18408f00795578ac7fc42c3343b206146cbfe5997f150a676e8ca84c0cad2ba2686c30079fe10609e0d80c58890fe1e1562a6974e4efcf0f586f807b99b06a44c1b4568ff78bd15c84c4eacb42ca3cd03f0163c86c135537a4fbe61445c457953ca531e736985d0a3729ce60125502887c70a74392b54a90e37b65a0f046546ca2d4752c7361e2cef83329de4abc3b30cb9394e04d0c1036dc974555d7825ef57a57720903c39452a4ecd3dcdbf130b8082dbf66759cca5fb77865927c0ba8e8a245b177240c8dde4dd0526192c25210fe16adcd4053f49edc4dabf2f4c06358c4a9d50d7549b12334b9fcf0c74a6411db55cd87876f4427bbf16f0511931182e5c62828be30e6dba566fb1018e4e6416f291dca89953fb54d9d14071c375a060fb7daf14142a4c7cb54d03ec23a48d8087b9c887ffdb80e922318b23b2bbee5b058c51d0dc990b7b321d1f87afb3d55a9af2acf44aae48b00a2d5fe4db2efb71aee7236959bd96f95d0fb353651fd045af3e9a724805123728d80d11a9cc992676a7ba871b8a134dbd838ee349c3436cd4531a933ed1b4e71a234c68089a8b7dbdc3751bc7f09e6fb4c594c80fa4d7ecf7ef0bc380df826fd7854506194a13f8e21c863b1609874dd8973bd2a78252c67c0eecc3b4b333fbc2215dc3db45e8c4b8c15a640cd9a5d441ad0d240d7e6e688777d957b5e1ae57bbe07369adfc8cd411d63a104af8a654d2258ec70bb8f4f7c38e43546eb936a9096810f87146de51c456ad6c022ba7ac89cc68fcd1d836f91a658c74321ba7c13598e3480602f8ee7625b6adeefbd5d78ca58e5cd1dc8a18174d334e5220dcf165d5c14a057f022eef752ca51197f6bc3a2c9a37794b989a25e33f95f8275c9c04b4d9610a4abf664878cd45044d51d882fc60efa3e280eee026e6b286b2ed534cbcc2c6c1856ab964a2825b6c655ddabb8686ae01ba9acbb14929499058cbe915c669653f54564a527e9107a2f722144277c53749033352016f58ee298f27de274ede7a92f2a146ac9148ac52e28a6a997900a18fa9e10a67093edbcea758e02642504a60b47da7e3e43f5feca433c964d1b367f43efdc69ea37dfb2c4aaca42c86050167f0eab5c84cf6a86d2f058827d187dccbb069b7e5ff24e1b8299e3cde69325623915a679a1024e33b4e021d18f452a0af7bac907d67b84ca9df0100ba692a122aa1783e721d984d0272e1971c460430b71873dede9b0002bd27e89fd24c613aa5fe8954b36b1f5fa8dde50c0c25aa6ad4f657ea44ee0c4525cf862e3ea30c06e14a09b77ba492531c548dd75dbaaad5d1fa1597ce4607ad0e24f6756c5bf0eac45b92a2c66df536f67a6c3cb29b3b40fb008aa509caffbcf6cd98d9db79bab94aebd1433ad982cd2e55384b4c6a23f9815a46b185af4067c2254c16cf556c68eb5f89f7f75b44e71f3da138fa316f70bed44f797ad887e5128851d8384e16c63bcd1297f9aa1d2b621977639d2eb1f7685273bbd288ecc409512020df625f393a1cd0442a807441c4f098173c6bba7d4c335fb915689ff9a601be3a73c32da664b42fbcba72e6fa36d926e38e984be6c4d43b0f12409db9ab7bebcaa073fa3dfea946b0bfbf4394a2e600369c62762fa74039fa0aea21ec9efff04ecae9b710a24c3104e2d9d79398b6f12cdb34b01c27d4bef0d2ab0731fbc9219ad23e8e34c267d0163402f997e9aed14a973286d9470db7c9ff2d7f9a014e552504cf45e00f34d4d1695ea85223e509df8c51bbc8b6c30626bfd1db20ad1fa967f9f127e702456d321008acf5b0373cbf1f00fdc25a8ecda23c7db8d14ab90d02fdbde092e88fe746a7f03efcf9deb2dd48ba13521a19017e0dd9272669f2c90bf090f3cb7426a6b78e4e8401af2e2cdb843dfcfdd77aa07c0718da89da5ed092a65907a8be91ef814f35ff94e2ec064c1c8c20bdcf0bc2b44145ee07b0b720b15f04ad42a42f07ecb79980b8e0c181235416e07b53db12f973ef81e118c27c618b647aefb2ee881b0817cedc8ea06b75a71d1b23b5606ddb5527cce3f4cc46d86fc2ed8525db0b54341a1c229c1b2f90a41306453672e9299d8008632b69b90613e22e8cc5a50d0ac2e878d84a29523055422d67cf1e6b09f53a397bc107f8f84b5476ccf4b01dfa0fd54bb58531b9ae74d70abadf1c27427d64ea87bb388e13d30bef302f49c3ce82000b1b6fa469af5025c5cb5c252c294230d8d45f301ad6e1c8537d52f8ab0556119333badbc5d7a05af6cc17ac18eec3a294e393a572cb1f4c2a55e0687f3c26c0d0c10a91a6c69110bfba6e5056cd87c6f4e8f63b66878abc293fdfe0ac2505eb0e152b4c1aa5cfa26780a4903e258ca0b8249937e60eb994f3e9412c717d080832df6faa13ef0142221aac58228e1f923d6cb70a102b346d6cec3f1110fe04d8976f4ba5e61174b5c9d42645fb26ab793f965c02e8b6920344dee42b7a0fb6cc14557301c9bfd3231453b8685b89650b1d6acbe14c680b6215b2a73e342103969d842d86d9c5efca69f61bfe786ea412369ad815dd258771aec920675d1d8ae34ae3b0d764d63dd6868771ad74d23bba5a16e34d8258d75c1743792f92d0d0d7e6c3309a2be926ecc8cb671cbb30eeafa82d1c194bba754e166ca79df45d46e2f04b78040c2ba0a2f87b89704f416e22e1dec9d0167261598842695fdd149a50700a5f211343ddcf94ab3b8e0ba1c3357083dbb3b2709fb9ac426e8b3733a1274ab98fed17d289af84b228dd0cd26f10b6bd3315740c772790bfccdde1aeb6d707ada299c06d5d7f3fa934e52a92b85973a8e4c945ea5e2ce3288604b9b36c8e00548d381cb0ffffbddf160ae3da3a2b78c4ca23e1a652c06d6cddf08f61e58108a43e4c0d2444985910428c4b9e20e70dc68023f2437f9fbc89dec4d0125c6742d1b132bfbfef09de8a6d16b942151e57a6a426764ace7efc97d7ab81ac8757d9981ba9b5d1d4470fdc98e0ec4869e4baca222173d588ee058356f4f541851d67b7e783e88468167cb81be0ba1a33161314e7ea4a2c38e9f6acff78646ccb8fa62d3716410689e726aae7e16be7889d38a843b3c3f0ea016bc2e0a493136734fbfb55a7ecb3e88c7543279938301440aaeca0b23c7ea9b39adec84431e4e114011c333aabd459e60e3f632dd874bd50c8321af274235aaa473fc7c47d08738074f1f58285309a092ef264af732fe2631fd227603a998e877480426b98cc1ef233fd7eabad2065f70683d954250715d735651878f6b4e6cc2111003d4914d357d35919b0716970f879b56d2f4d456b550cc193ccca4adc17e027bf98adf491e96f1fd238d1d27ac08246511eb2bef83921b5186ba140178d254e3f0f936709b140bec607939ff0df9e9c65faa0e42e01da8b9c9c1f7b2e4f062e322868b2396bf808eebd890d2d1dc557c2d1d1d9501b9e516d735b9f0a5cbff7dc9629c8a856a5037fca6def9d0c1ea9ec80b062e2dbb50b5de8e779ae74830b984f55ad1a1cd2a6e79e3c56986abaf9fa225cad405561b671aab8de651fbe29c3e305204b2d7a092cb2c884f69672bf005ee5de745ad43f5717387d6f103ea8eaedd34fbe1908ecb22e971ef20cda87fd0a3a944dc7ef0af84414b5fc67a7de711911da53c30f07461e63f61ca7097268e71e610d1b5c3c2408b7012378a9433414fbc318c6f7ff6d8d52154243535c1e175869ca12d031a3e39322b92400757a730fd0a73b8deb82791fc52a5375fdafaee29ec7ef78c2d2996b43b453d45fbc1ced874dd5db4c724ba3b91d5bdee140a4cfdf93b8d70834b645a4564e79d06e2d729f3a4ba422f096dd798228643e38a466ed21ce1ff41723408e4f747c724647d2205096b7c9d632366eaa0ea506eee1be45f642af3c35e8dada01892efb26d7e7722f87e641f71f892fac0e52e73ac200eb9a13c2cd491ea324de50da514a8d9b98d56b3478909ff9eb04bebd38807a9fd92e3b8bd2a718d70b29bc8bdeb6c505e69a1c2773d1948fc2a0f05c77bfce4a428cab734d32b329d7162a01a9b7ff39508af4906fb0d571f8f1ae7bd4ae3b2cccd2af33f02278892c3b68199607a611434ed4934a278678a16f5964b8f11f787dfb60097c33795200e9875e90c452c898c7d688782686563d346c858148155822fe04d628e3521e737015e387d375ddf3dc558b39e16a0a2662ee1546c72c2379a349fac7c4940c21e7322639351807af57be27bee1ca7ef11c28274d20a816a604c01f236eccecf3729d115145628cf33224cf56e88d0183a735afacafd6fea0d64e417c2b207d4323969aaf266371181ffe1ae2eed5a918c29bdcdd4e6ca720816db489d5db7d83bdc54df03b33b4138be201c3ed63f2130cc362cf3d8abc3b83aa9881d9ce036ddf22bacf2af62f65ca8d2aad8c11683ed0649765f2917cc27aad703d6499bd744744a2a5f7bb1eb1d992610ed550f4a55dbd95a987423939752525c94225e516d6c9854a79026d355f9d9cb4c9440e578fe350774d78c6a5ea696be1ca9e37ae1aa0c3dbc9372d1234881130650132a8baabd4e3efa31d24a50e1c25e83f1d495b32a4bffb3e21a85053c2569e15c136ba72025a9040d9d61cbb784179b409e1ae251fa1849764d14971c0b56562d554cab3dd3189ebc9613efa990fa76c84c05f79a772a36dd21ab217905adcb913c920bab6d94fd62d6c3fadc1003b786ecd2e393ef0d482fc072ee8f97ce3bb2c7b3e5c2586edde2ce0197ffc0b0193093bbb593420991c6ed6432b552e9ab83585924667a128032b7641cf2c7e0028054abd8c6c5a6ea918cc1dfb2c703660405ad8b5fec13778ea61a264fec90022a53194d642c37c97f800ff9dd46e79a23d446d31e69b8691c51b4872236599c15243db4a777875502584261b3425cc88611c7a99c6a03f29b6f6ab0088f881f5b740925ae075dba1b78fb06ab9c79f57d8cd104bf12c51f68e13190eb6ab0ee2253045bd38a4b55e541213afbfca7162e8a4ff03fdd2ac8793809508d4d8ed5f441ccc9107d37e6097b36ed946b9bf225fb947fe9ff9ad9b9d993b3716937dcc03764c2191dece267cbeef66708f348aeccfe4f59a0ded882653e78752532de22ed966f9e022de03cf4a1dcb345ce2cc063ef97aed9b8504f3714d5c42797bcfd6023d2729bb8d53dabb629ac4d7d83f9b45b4c47fb1256b82378965dd3509b62a9597244320fed618336889c2ecd06529f4860c2108102768d5c508e229cb0884731ccfa72bc6e4424ad82af9975e48ceac86c06eaa47417956ade4a52da3de6eeed31c6d440661bcf6761bcd21db6e602b77917c3c775471c49e2a0dfdedea2ef8a4673011dd748ad9241eec300b87c64702f72e142b4b6ea3a6843e19ea39ce3cb0cd4a0c99cce961429ba3f9f634e1184d9ee24d5b23b78d3212755d90a68ecfaa41163b14e7a2a4f925d2e4296513e3929017297352996336c0909052e053b84b5abbad38c9eaaa42619b2486b7df73c7222d34cb4246cb59fdc012577120ba28aabb291c5a06b68a1065648a2977cf990efdb5b3cd952cf40783894ab4ed90314c554e4bc84eae9662b3a8a5609f67af8ea21af02d5499909158420a097e73650892d158a9189556d24ac4e55b57630ac6e2009f6ce105c9edb9d35e7e6a409fd5ee1315c16ea5b7fe224786b87e8929857588ea433159c40b989b640d98efbd87b8d8a5c0d6a8d04d38d8c34f93d1acf7e8d1458b25b1bd47b4af604cb2759630e60425104eb389314137d09c26358a53844a26a4e11ac452cec08a3bf4f510a4718b61a35ee572785291bd165ece53d5d2141ecae3562e55ca954834268df9df45dab338753a19cfe5a8b41e3dbab92c642b285f435057ec644975384f883d4e79d224192fc24f2945172f1c4394b1c85c3425f83a56539327442dfef819724c1738c873dc818dd208c4d59418731e3103876e101a82371887a42fcc9ac421bbf344d482f35b074698e4fa6893c8080b8d12788acea47574ad6f824b15f02700c42870cdff4f1056c4a5b1fab6c2fcda632f6981ee9a01b84bb3ec738776a190631618c2f05a312fe399aa9bf2ed1cc1c4ada2d4ab3f001ea8d0fe78bceaf8c08a7b226cb3e1319b3766dd606b2f9921eed163ec8bf1d05aef8435279ff34227cd66b2ba27e9bec7b1441800874709f22f36a1657dc719692c3c83b754461c05bc25c9a056505dbc12fc72a42b48579410be09add0a6acd669f24ff682744c5b1cebc41a4572536146d2fa4b7e3bca24aee987c79506c86e7ef72b05ef78b0abfd4c0dd905526f89ba0b5811d8a710c0a70e79871ac1210ac2cafdeed01a3f1427e5048c686463c741c9c84fc19f1e852fa2a593eea6c9f03306dee60662f8074cdaa087f8710dbba37df033de915a81e310c27722cfdb884e530ac30b73e03b8216481883fffcb9dffad59e8fcfd309b6bda7088038ebdaac3fd358a97e364a4421f9271aa19ece877ef4a1e538b1ffb075118231610b9bceae81570583fad155062c8a5ba7b969b270ee256840fd9f89b85a0c455f6b8e55c72c666b5b79b131d737d900114412aebc8215cdafbdd48838b15434b2fce64550519670a1fd81416d1aa514e143f96d92e71423cae69973a9699497c67c37e6ec823ac2c1e00fa7ca54a3c71638b1537b678b162c6165b5cacf1e28b1733b67871628d175f5c9c71c58a1333a67831583c6d40095f54bac6b87ff68a6f577fd9ad9740864c6f7c74e8ca720dd12420e593724d4ea21815053a89bacbe6b7c24022570d3f9991f8d2153621f2f6ef83e48c0f6c721585ac2922c438a1895aefe35c630cab1633b9d02e8fb5c4ea6d489276919579a6c8301d855e549e16f5264e2df2c2b098a530605df86ccdcc7483ff0d12a0a0eef0738d5f7881b3826c92a3c353b1f54156a4c3ca61dd0690d929d11ce9d6ea0fcf960108596dcb292081c612318d4e40be30d2a92f53d02774e4c8be60c5318fb5a7ba25469c06df33a91fd2a9cfdb29394df8c32a7e1ba0806daea094d592f43a3023e6d563b52a8e5b8070315e7eb421547599154c10d3ea2a28a2f9855699dcf5641a298c5e50021b2b22f223b914ec1e46347e8268c7475f677296d16b5a8ec7e6e13116b9a056afe145201416d95a4181b47162021db688150edae880d5d19da310e383a857f37a4c3b232c9455d26535e00b454411ff2f7f42a4354d8f60adfb651d05a08b1a0f01aa96489f0483ed7672a640a02d085705731bd6c80144311577a282bd09c38f4f21090102ed6ce1f7f1332e91c5e37dcdfa7d386d693e5a3f7d92e7f9017cf9a3e75101acce9f4b61b9237e09b5547d2bfcfa39b42e40b3569fe7491c7d2cb961b100a24abdcb71bebfd45d26c85f1eca6c802d7b9fa9305d64f817ed3841a958c18e7f48fa20a448e4170a8ef278f85d2277f4100ea61c03d4bb87bbd67b62c02b2492d1ec67f121f7f033ab0de4826cb23c03bb0c45ce8fdba3176619171d680e92d1308abf3d0ba3cba11ee0573c268867f5625505d441f7df12029612d6e2e157c9f4185ce96abdfc4cf5498261d5e291d1893b4a5572532846277ef47bb19baf5e10992d3752e918c5d507b59a5df39680936478c30041610ef6bdf109b78bbbcedf2afa6e3b7432741ec8108a64ab0146dc148f3df36bda5549bb209fa74d1217321f46dcd474afe36057c0366d1c0338b09dec0a848a1ad2015a256a7582a483b69b6ed0191beec2d84da74d67e8b066da44ac005b1f91505b0c6c1a68581a6d720f833b8e335f800d4d7a9056a69a908a582cbd84b6f42b8ca7615deb5cb19700ee9d3add5e21e10bcbf664e43579afc0d5e9670863e38dd1ebcc3468f85e00f985783055c6b9af5464a1a3ea823410b17512ba24ab120aecbfeea4c6fdc397db16e8cc52c86248223fb70bdcf27815f3770a5459d397d477b057d2c02ff12a2ab763083bbc0a59be40a993757885d03eeb699e105393576e29e284613f5a83d33a1b1213a3b8f1a51e5a0805dad38c9bb1dfda00e0092b78b7486df01aa76b4091337c436f70001787c8d323a166e0e32537b0643335634b56ef47182bfc2afd146cc13960140d5601cde17a76c41988c612186be6e414f40a7af450aa1580703f54d6815d0eca1431b7a83ff507bcb36881594e2759fd3d029a463a20da9507b6322a7f51f3b76c8c1af1950f8c51a62b9827d063e340d3f1ba3f3dba70501d8918a527babeeb269bfc8723ea19958c2f0c95bec967ebc5d96625a869e2a81232b1cd60545421e4a08abafeb8baefde3cd1f7366654843c6b4e955186253a5441f8a67cc0c9cca51397c7a8b11f28f41f86c021a3b08d73c99e3507deec2bc1a311351885eb9b0cca8ec3399755d4910057c7fc572c25536cd9f7da2e25c5320b52e449936e653d43837b27b8dee49528328b46fdd8dcadae99d2896c3e4d79ca4b55d4f964a9309290c4c14a213e01eca3d0d762338fbf9b4e3dc7d91cb97fbb409c9e6ba2c87f4b12657ab0a26e6ba4d860c614073b30ef361b90f7e77215e5eb872a405b216e2fad261b1fda2fba432953a3506a664c31cb27da63f4c4121d28c1783976e8fe1127cddf908ea293e594698065b627597610962438f78286c246002c4fd2ed2329f0c7a86d83c0a1e89cedb3b4570dce2a1ddf489b7b3de761497a0baae725e400b18e82f35778782374566c4a92da3d8e7a68bf6413862247866e67c16a21cef152a23901a0b853d3805fa2c45d352547d12e68fe74581836513fdc7db4b5e059ed08b9086bd44c9f29eae8ba0ba7e043a268b6bf88a7891b989ab1299af266a462396a26d7646f43f1c14fccfa543a61a5a1c6a08e38c66656eb788ac9f072d478faae983709cb976b096e043c171fef32d1415c54f863756ed5d6d9f1afd19bce06c4e9c134cd1b21e1fe34fcfbd33588eb02365cbf2b9be2e780e064aebf9e4b3b74931b7d4fa40393c801c0ae05e81ae2ba12c686f86ffb3de3f95b56610fbe9d80ab8be6a6ba8ec47122794ae5746cc26cbf069739f195fb67995cc77326fc339075b1e83860b3a1c14b04a3c6dc30fd4f1ccadcb0e12986f4bce714c1dcefdb481a4714cd0271638b052d44e933808388876b5ed559f38563b28db46167796b048714313ecf247b70a45b1811bf4716a55a4a01f395eeb9be660bd7a0e049675b1830e8f8fa10cacd25160304230808241d5cfc2705a57ee949c3c4a69a10b7d1ca033a58b39e3a380d3a293774d27f8efee653d19205df26d2ef5a4e621e0bcb8a6c4c61a4cd1248d876901ef996b8232fbac948ff4548149ede3ae8a063cb009290f904c60bc91fab4cfc3f0f5161ba179d84f97269ca13611bf6f0fec64d1f520f658d4dc7aa093ac2d19de24431095255d8e379d4df005685531e2bf9447183194770f26b0777bfb221e0c5abf64e4975ad90fa7f7f1d781db906dad5962a565771d96f19d0b3ff92c37561ad83d5b6d6fe343c3696abae364d4d2bd3c7ac32df1a62f6940c9b8c34a5087855f823019c7a2013aa2fa4c717ea4b79a015f6e616fce196c21ba80c4f7863435b45311afdaf04985345dbe2f807a4e93a1ad701b98d2945f3cb7086ce81a70331a10342435306a3604d402ad8e6df83373ec0b96249c3f297ca42b739ceee736e3167d7cb33fd8863d3156c514dae171c2373641535735cd79a8abfa5571d42c8bc0bc3b0d761aa54fb73bc0b1278ce8a27a74735cc3df1e380cf22ba602cef672d2745b6eb48437a2541cd67ed5ac14b577d6ce81c1e0c0b49fe393a8c4d084de540902104defb529196097d0efef626b60d195c3cabb591ebecea6bef04169697d967794084300cd063b2c445c89110fb981bca8b76d89c552fbac292c4f42b7a04034a3ed98004bb9a63fbc8456b5a6010757ddbcdf4e1efb21cabbfc908dbfdb8f1b33a6a05a2fdbfee5a3231c4f157cde55e0b162549e983cdca5a11d7f3bd71000174fb84afecc6f65337f620022a2b6798e3a89a4f13d5ed205d11634b7a183a1cde8786431c8f9cee0c2db58dbf7e161d5a826b45dd803163bca6f40de11097860d87c45ccc5111f30a71565058b998a82dd2ae9e51ddeacea81a422be5fa73e93001246fe815f12f5a0417b7ce82465442b3b957def2c8ebbbe1db567556c04bb4acc616706694309216babffd87504ee9bcf79330c29d0b7f9b87b7cb2d83ee6c3d6c7dd5a7262b654f618ccfc31007fc2271f4c0126a8d4e13b9a365947ded5425e9ea7ca3da9164eef8a18af4980004bd9052df3f69717a70f7543171cba232bfc648db6cd43762b40f419d33fb6c64ddeaff619fc65f38e0a065bfde363a7c5d0c7782ed77e2075a6ef7200d8f51989bda2d03a67036ab06b4adfcb07ef38a5672bb59ae607d181acc24cb16f1c8d7bd62c5f5c978a98b9d7f768a9cb2b326dab66b6993b8045ed7dea7c9a1fc0fab73593330ccd277394ecc9a2956f3d5d71c42bec07808d98a5c7045721fc3b7424cf43c22f2ef1859786b327c05d6500b8459cef6ecab228c23916c7a9a3b0f5ed1aa96e86a52bd9d7c608a763a9ae3db0947efb7df65201c1ce4ab71a06bf6545f11dce02d55a68c7abc6f23ba90ff59e32de7ec9df45deaa032062909eca0a7b9d0c6cc482ff4648bb5779446cc9af0eec998b831cecbd6406b17f90ffb899eaf311ba17d6170892419327384a9c2898788614ef74ba33f2b70618bc172037ec68a535df4a2640b49bc9b20dbcf6b712df8105556b44b5026b6015e218c7bf04bb1cd6c48d8ee7227696312118a98189dbbbe23686b08c4b9973e1beb11e98f9ca49ea41becad662c46a3f98c37a828c902393b4e6d159e2e002376febfda8866433a097f1eebcbe7704bcecb475615fb74064b63f1086e5adcb04f7f67c0e0d42061b73021097670057878166b1caf06b0407ffea9ce9122a0963bfeee95f04c7b88c615a620305da3d546bb5741768f5c7a06bccfb730bc4270973293af9f35116e1b8e0b2e60449d7c20f6923c9611e1605b2c0845944f427e1d2a79b88943d739b1ef3e622fa05ee189d05301fb080b6e8bc8a942bbc35a6fd93819aa62d4c9da5c186085c928588ae35e68151813cdff9f15357b43151619c41b1a8dc0b53eb2dc09776e2f0e5416310624307bf43a29b00cb758ddcfce337359f37faacf02c3d80c5c46c6b805180ecbc3a266ce39acfbdeca437efa01625f6e092aa0ee93c07f0cf984dc3cfa0fd89e7b0eb0a551e803233aa96fc21660a6082b312a950d263fb53d618a7d2e32734a5c75e2196056ee10a5c0ed126decc61810981e1f0d7f39894723cd41218ca78c51be3226d10f243e88dfa8e73b2622797f4c72c77c3a5dddf24488eb62e49e096362ec4ba1d7321dd6fe40cd5ea75293bffdd0ef8c97054e0ca0e6b96767d4ad94a402d402f557a52b13527d930af807149dc495649bd6a989eadf14f386e1c5c2ae29bc60b185618d9177f1b86175f53dd8dfc29527fc7323e9729c120aa45fefaa09e1047aaa7538f7848af113d12b255931f12d56cb1d416f49706bd7ef8ea466a7c3a1b7f0efd6c23866f783c5a71f5342662429d994e86096289c12dabaa1d5a5c9f3a4955e8cb3b2a53c3fb1db8f167ca933d4b08699c254f3f8d0bfd1a835beb5548e3257a3bd8a38ffe90ed41f0a4936bdaa02ec7c476835f3203c193b08559ab6bb63df410cb2750670cc910b0b789af7f31c7ac1c95e0735e3a8ae6db68923e1ba6ae558393fae03668add06f0bda30b5f41d0548760391681cb0c5e3455e03320d73e8470f3fd5d81bb6cf68144ff6cd6f623d23c7dc43dc77b7415538ed6a103f748ad6f2e7745158f7240040a9c7726219a10d227c3029e7f1f85330370812663a0f7bebf17d0fb0862f6a83c4a518015e4eab418b9830420db56a34ec4f4b5a3a67c1277aac42d87a2094eb4461518f9044e074039cae4213a4b9b1e58511f5a72a45b4d3091ef41371f992304ac3535275e3dc7cf11d076daef7cfe4001a884ee2253092c7ce2785ef01a0a498ae256b6f6d2c2052f5ff16b23346281b3954346b5b541973b47809aaf97ec32ef2b3b03645c58305750e8838305e5c4c550bf41c93cba14f52bd0816f5728b63becd50f6618eb97c455e8052ea8e712cb80e1b1148db18b944918c32a813c0196b84d2ff747da0dc1fc07ca67e65114a962c05c35d30eb41f70b392ff814025c2f15b5d609ded73b718afea36f20836367e21a6784bb39fe6535d7f8a4618a349a11076e83ccf0ccdbf81332ec518668ba82c7fee0509f3da07ba6d8fdd6286749703b60f440c340b70f4842c88df337db566f394d80efa10900210a4623e0d03e8f386461fec2cbae5ccbfe67874f53340f8e484922d5b40704912355d2b48f2976d027fd471ea05180da5b8bd3f037838bd42bc2bfee61b8443d0101b004e5bbf935e486ee35172681c47363ae0297553c2f30922baa105c08102eb0152c62ea556ce82b827745d1f4cb7f28132bd0776bf48157b2d7b5789bdafe45859dda175033f85f7cc437a52be675930060b9649ac8cb2cf8dc677b8ccc9461ee0ace6fa8a37761ab851621d790b7d2ffb1ad55d1b9bb9d25000174248eae4b47cb3cf7bc3342f705153ef9c03baf41a4ed48670a43dc43255252645c0afb6da5024d324de75e8407ba6cb38139d3131d884b6ba29888d975bdb6251d9a352599799c83eb9bded27d61a74b6b0468c314b270e3186feec7224fcde8c502d778cce602372f4cd5f72e862616568be9d8b93f26475743af5524f4d612715741111835d0e841fefe5beeb316e22081a05e5f9509fb79575d92d5421f03d186b6488c4fa61e713d66f0d097d7f5b90f835a3d40827319619ad6803b326b641b183c6b08034787451dc221003774a2a5aa1cc039ef8386bc0168c228940df3e2527247db022ec8d09f35542abb26230e5af439e054d33311364c235cb0e9f92a4efa0d28dd93f36b021bd27cbeb38ef69df8d4221ab333535c42180abdc7e9d6c7da4991f8bb1bdf642c75dcc37783d7773f3eccd7565948daa7aa501c74115a63b63375c00bce93948549004eb8353e18518b5d50bf6b2a5bc9b03f0781ad1064510e8bdb1f1cd6f31f9720185167d9c42323d17fef5cd90e91d513460553204255f33a03b4ac04869a2d7ac54899a17b59b6dab912951153425dfd178fb80377159dc8f427904646e249625ab2599ee5ef7039db1c427f065947b2c4f843e5f1707c1d5666aaf9faa5e0c1a7be67ed392258e770fb70da221f3c95cf318b7cbea886d40b070ddc60cec1128d174fc911bff2ad086c067b96559ba39b09958399f4051d7a36129588a40b290346690afe9f9b2a7ae1fc5452067cc6504f1375119f84f55f70f08a1653abbdb163446281f476dc65ed1135277e57fedafb23e62d5b791eee76120cdde7b3f07da1e5e2194b4bea18b0c77c74825614d3b07826af2f9735c1693898331a88598b864c931b4e129f8be88c81ac505fc5c17b6a67c584dd67af761567187cba9846665d0956a12fbabad0671fb81db896b3bcc003228892ed7380e330130d1e291858e3ac0f1452244eb7c19b48629b3fa78e63551bbf23f511dafd4f8d1b7919a643f43d1bd12604fa0047d7385d3f277f9d57a80ac2c252774b479b25b57f3fbeea5b08ff181fbbcfab20267729b60e991004096f2985c938dd2350a9710941b395ac359547902270aae9812acfc34bfbc50b63d8aa9c310a9fe285d14f2bfd16a7246d5e462aa82f85c8753d178668b0745bb74a3d5cc36708d01d14b2e5e307daa67b24d57b3716276475dbd56c9db5558f5b5a53048a8d7016b5f138df35a93482563d2a66cb475710420d4c87d9891967886e257b3e33cd83bb75b338241b4852c858051c166301e5a279dc9b99c874baf59cecdbab8ec9661c72205a05b72d9837e5e13a995cf0505472f3928f9803335cafadba31ed4adf6f454f08dba5e8c0abb5b90fb0fc5d76d14fea831fc7c15e3a680bf2eb8e26a8c7179f9cd5d80f7309dff634409cfb76460e465fd1583b901b447ede8892a341a65c38e8549957f282041697971f459cd87d4a3434b7f45ce40a31c36a462d3e809f1514d09ad0efa0c3dce01748936ef2404119a9b73a62a9c03f12245307e6bd55287ca8faa7a1e86b6078342334925f21edfcec35da94ac4ac1eee8b15a922ae04eae5b0dcc4661acdae211b9d1500ab17d191da1aca8225d580b5bf82d5c150ba5dbcd5999e2e3814232e195de9b4994e2d6fb2fe3f6b43b29d7956d2119573b0cfa34a1ed8133a57459422e3c4246c5dc60144cb293d4da98dc824a2e4cb1bf4ddee5679c99fd5cdc4b9503e0275963e13440be59303d4f4bdffe607d07d5f6c52aff76e4f1a5a8e9b42bba97835b4955f0468918674b04ba95591d98b420294f11d6236aa4648a4ca46245c9762b111f9c566d364818bce9ef120ab45d4ac598ead45986c4424e8247a28aad29e9da3c27ecca70bb37c166480435bd2028c6c5cd797888a6b8393689a296da0866b1024f792b6c875948687aaa40309a89b5f903cc2d2d63a4a1d3991c28e5f2d7f446dcb2e679691207299efc15ee87572a10ddfb335e6da67dd400b9b9b6256971209905189e6ab36884ae30d1949f5ce03c81a7d54d3e7d1f0079ab57d8158137b33d5342987d98dea08b4c127dd952ff40956d168a346685049f961ab6635c1627f386c36bde4c4064bd00acf7ffbaf413678faf70e08cc54103dfc6a6548bef5ccafa60c5f365503ce0e70bc581b414fb0c501880914d21e20d48c9f3e2799c3abd16b6b5a9401baa07715534955f87cfb1bb627a795b610d804019dba52416fe408ae2b44166595af440a700b5f43f086f34e6e6fce4afe82e0eb3126aba3aa32cb8bf9628828a5addc522562474375e72d4d6c790aa739e3a38aacda7a7b2c440109413084bbfae1f2f7c5bfd408d53b8b9bf755bda213cab3b9f3415f1f894b30b3dcc7a6046e7675f5b3a28310bb74eea35ed67c83b97a47d8ac920a2c782771984297ca9234b6f2bce007c35d6d6627baa2bfb3e5487a77f84528ec9d50c2e7b7a152569fc033cd9558d6bb026a08096ade932c627d33374690180e24095b4c8d0e7bbc4831cc4ce63583c7911b7e9679c2b91a3d8c064ea461f2735d1f15d99cba5576fcc87c32ac093a0422b14f808cab14f32fbbcad8826e391ea1e808e88866441cace1a483a270c74fae90904ba7fc11b9be8d405af0ea73f7184e6528196dacc5ee25e518e734c4f5cd3f9dbbad1546928bdead044612bc0d32068b7f301f9227a1ae0d35cf0b61377d1ac1b57798eccb17b6cee58f14890b28c58399f3e67f4229c90ab951fc9506b8899fcd6e95a49abe20fdd6999f26d3d026f92eeeeb27c6d83a8cc329714c8adedd8f8be95b323818af50dc2166cb0e7a295543b0c2499701b31dbdb57331cdba7276422b4c1e2608016d8442d3a370f4fa22f9e62ef35dcbeb27053f284ef57872f6d4b6213324f0cf654fe68dc88f97ce9161d51b28c6cf16662a0358a38541a985a8cc34ef20cfc706ff106a7a7211ea3f76f634c1886bd18320b8ef62307add33a82e79812d3ade33ba34dadd96cbc9be9cee55d4264fdafc7129598367ee9213f9c2ad63da7554e1ca7785b2f1ad0bac235c78f70d790b38c8f61a35a02e9c6e11daa8188e37be39d6b40560e24a8825dd7655b15d88ef41d79e30ff0e7a32041325f6b46f3dd4398b229c71619f8b50ea0a27cde209418d26b83a907589ebf708a84ec41cc30b124973dea5a37f2909d9d5bf2e496908abae571ce359fa4b437c86aeee02c08b246065a7760dff3c1cfa817c31c59f620cd32a746ee952b25b15e1200fe329b3bae1c686ac7429f0d48b0598b9d16f9760224fea9753703af5d12476fdd999d6918c2d77b2238827d6f518fadab2e6f7b3c98960ac5f2609cc8afddae54e3ac61833215132758ce405bbc0a70eeeb4314c5f37ae2e700ba73c19f170ee0524928db512abf67111c1890a6c2fe4c9a4b7f3eaf0f664382dc193dde435fbd0ca84cb1ac323ec2ac3f2996055a918d83f173cb9f27ec041173cf9cdbbb1e4742585fb45c982f3d71eedd28905336bb531b9a7279d52c413ed64ed02d9866a145e96c6e079e8784224639be5b264167f8de8104fba23c06ebd3246d0d787c87b5aa5bf1ebabe96868d3de3cd8b537c2af1c7fa889419a6c2695b909e04ce98b392aac68fdf84a4379f327da6aafbb8d3c5036506da0b7d30e8b5d151e223d0c13f2ca85f769f8c68f2c8b1a899fee278fb6d5c457a86357f3501c4469c0529931c5276d7f5f19d7ee25c5bf8f037a68bee0f3854fe83a5fb9aeaa96736f99b8bdfd7624b68ad9a8c7566321256631aa6e65a364c747d95f320c434d3f25ec2a8512dd1d04969ecee0de828e6cd640d7cf7e03ae114006ef0b50bcad3b878364e32a5b6ba0718a7e931e780c30ed043fda17f5f94d2752e7592ab4f855aae610111b735f6c724d24d3feabda48b575769dc18e22ba5d353165b8ed11b0823707f948cf601b6bae78f602e83ff6544dad28e6df16201a94fb608651f749882b14583c1289e71de9fc3a44a80f9c4afc50296fc1c1f6b24e1bfc4dc029589f742496ee228af185892891944eaf254a4c59aad4400541a1a1fd6f4f9afbdee8115e5d52007baba076e98b8cf4ecf6a6fb65311cac83939213f9c21cca0a7e156262e94b20544122ef7a958bc74cea9babafd90044db0f5d27acaefbc6d5b79691d4f9e2780825d3c7257fd1d848998b181e0cb17e4a3b18941c1eaf5b0e4d3fd8d2355f110d2fd96b1cf729b773378538e0a7d9f06f06ec5159bc73e9c5918ee88603cfc92a9da8e3c590507e71c265490d57c7e288c24e1be863b37d4c610b6a3f8009ddd810342ab732cdb7a6c6fefa1ee81a894d18f0a7a82daa61aa1f6094281551ede8e0dda645d886a8fb143ca2f88982efe046c1c9e0485717ccb3742b42709699bcc901389c43c287a22a6e0975ba5c417ea9a74ce4b827e05d0ccfe7e1cbc57d2b3f08feab6316383e79b359f46044a8971a434b8f1d4f2236d0f47960caa0b104502219ccb59742abbfd9f2ebfe70a15835ca071fe9d2fd1043f7d76b85cf11e72059e2d75f829cbfd20b0bf613f64c6bcf3eed0ac7f6b3a893ef2bb23fa7942bee9987124a8f8574fcc067d3bfe6264ddc47b73a2118575045a6d9b1d4ea6da1653b1b6d7318a941dd6fa4122949195437693d9082d22ea87e2b2f3b442ea40afede338f5d1b28f70c546367b0157433dc98812ace281107dd4152ffef22c5622b700049e48e453ab447670a7baf217f3b9483cca50605954fa48050feafae6c1796b54ee60e9ba8cbe326bc68981787c77ff7635dddb1aa0bb67b9ccc4c2ba0b1ed395fa2232e43a7e693794c321668085a794e762aba4afcd18f308adac9b057f2540acf40c648a8a4dab45b052725ea7a09fda677ae0ed3af346b9a93e69c81cfd28c00e584a55a37f812a9bdd854f3c0ab7781c931d232eb1c2b851a9babc4c74d240042138a776b05464252150e11bceaed4fbb0bc686e82a5d109d56c5805c49b5bbbb270f49440e654893116741a280feb56f114870080829707a10cfc1dcad865925e73908b3a83b720b39ecbcb52673ff4c34e45a8ec2068288951999c8cf3a48ba53476d6930e486c3d8de941788fd23034e4a0bedfbd7da502283fcbf91f6c4518b28ae2e6073c055aa25ebcf9d08fdbe30abefa1251f712f829905e3ed3b0c81cb78015003706355c889d75216dbb505d00c7c40367609d9b85f372a91cb1d65020c4d9c82d783a255c7d547b208084e2663199ba9f0e579dc841b20bb3cd92b2244614959c39d61b20e7f1ccd6e0a43fb25e22c650bde901ff21651bbc795030ad25548d1373e85d05fe4300b64b229d3273f60d90212bfef5178a98be82dbe7e561544febd003b29ed679fe3e421f9d90615194c1658c7c0969697951fdddb41050b1411b1c77ac5c7e8f25d68a92a514d0078b9014d2c800089e31f838b0333d8d6c46a7f94046096c0679d07fc242902f03edcb7624bac8eae969c6fb4708639672494a4f67365de1c6c40d00d56cbf2209e8e0eeac77fefc73a0e37a0e6ae344611fc25fdec90e778f48a20eda50a35e48256ad1595f6949dd1c7496b3a0ac517533cbcc9ad42e700cd815ac405215e82ef098b6b7ac9915377f5b94c7d23b1e451ee06a79384849596576bf183d8c09d4cbd2283ef3cb8777e5d772a6f9395db3037a67e52b35f693718d1c5e505c890260b051d63d84edbfebd560686c9921676b36cfc55c20ca35ae0eb8e11a177a0e634ef32e2253746a782015aea5a8ccba41199772830c160708a419067633b9d30bba933807eef33e30f406973113ed4cacecd1750b6190fff58b38daf22ab06ddb1f3bbd8fba2db0d4a25f969ffdac06ae3e086e8a80fa35dad9042023586c1c830ff7ca299eba01fc93f5f4956a2ba882fec6353a113299bd84c5916bd095493e584f6b180f81a63d5876f89b3d9d9413ad61fb50df11fe2fe24fa7b188e98d8e509daa844a3609ff1e16d1e76f8ea46dea77d83a8da4b8b8e5399bbd0774f4bca985dff8d098140cb8b72cd249c61fb29c4b710d05129665e4e016830ea1de913b46dd8bb95c2db5395125455efb85e17855aef5bbc6c1cfa31145a932d00721f9c33879bd15064f78a5ddb242432cf0ff0b5a0a989e336c7312d04829aecdf36169e89fa4d025cf08c63cc8e750977b2539f110887e395d631633e2fb4715e36587a0bde726c64c72fe0ea988ad9a0a08923e5a3bca925d466191d367fe7899cedfc3a647421b4a7cc2b72fd744dd78f3b9a791c8bd5c27b7a02058f9ec91e89999a5a8d1e86368baf6f8240822a4c7f7ed5be7d9504cde1c840612a0c1bf4c33c4141494b4928af983da6d36dc8475965827140d9c872c0dd1ba16a62b1c2d3a94fcc24c179cfebce3cf108355d1c09eacfa2355a51afaa8d92470707def06fe80f01109bc037aebb9f45f3e7ab738a1d7f23410175ef227bf8d835ca8e6f4842e231342a0fba57dcf6f54a308668480600cb9f1e063ddaf1e9a0189bb35373d5aca6402456f1b94300f976596f8ae37500bbb1cffb0d4052c066d148af94875720d8451a6273c99cce596b50a220bf8b3916e8921c8d1759f3d6058b2c0753a546bf566b1900fe7779f68f20d913127b24e9ca2f59cdbf57d71096918550496405f32896858561098065e98602d37ce9c580a14d4ef95db564ffbf615dadc30844a84c9d4f42b98b3a7ad2efa3afdc5297c3ad22bc8f344207df2d7a89d3c93a1ff3094e8cc9bed49727f6f07254371deed2d7d6e3244973bb33ee7252df97afd4984092602f83a4d470a9ca4e290ecdf57e5a3ef3fe27bd0a0892a56e271836e4605d812c28eec041fbb5f83ede7791b449d9550a3cb3b8907be5179631f0485ab0266991b348e48a077d630982254415027cb09e942586ebc9eba1beda2371f85b98f50ee28853a4c105e98e92c3abe90a7b015e85af54f4e49b30ba8eaa281184c3bbd466fa096526a0e4d680f3f71df0e5a29f544c8551b134233d564e9234484833c53796ffaf81807906377ac31a8cae12d313e0012b25c8ecc1605bdd5c305320ee64b4a22afa64b9d0964f3b6550e3c6f26375a1c6a2981876b588f3e9b6f026f2ddbde7648e686af1f01179a46109bf2fad16a3b69044923b49addf9816164347449f27671dadecee680886ed7b623ae0c5549a95d2a00a58f9f09585166515c8658d34c9e25b92d4ec959cb3d1fd0a68fc7f50d22b826bcb55721acc6b226fa226a2cf5644d379840ac7ef90c0c3924a333b181d7381ef3519d9551c82a810f952acc5032555022d70d64a9c4c0694cb7876d0ee1278e207b34bcc18b91a48ccdbb1ce24049c0bcfc2af17d00b461053ba5407210c6838ea5e113fe544553627c1b6aed512217192088b9d86b02bdb00af465afed0069340212c933d3f677e1806a6a78755c80570cd60ff3838f1770f18d84d0b5375135cffbf4143e9404c682756475f4bd0cbc129c2b45912fcc6c3cf22dc92b94f280497a847c523676ddf6dda7fbb9bb0535f4c9b366e467761219536fb2cb310048e2f4721ff8bd3fd12f5e0120b1f25abee2c318aa903fb36217240a84638511112de160703851000aeb5b29dcc1e649eaa42744e71855919a0d360700d2506326531d6a964bc97d5969a7261068e194a8d366885ae64440d9eaa830600e423700673c4f1957b111e315eaf2a5f12da874d994307c3ecc4b7e08d2704f3bbbeaef9968fc25c3fed325a878581b01dc9a1118c62744b5e61c2a0a52030b714367ff9474a603febf52e6094fc29c257d10c565550c22d14b7081e21ddc2d2ef1ebc600cf751dc19af67ac86070d80528538e27807ea8aed04aec8353d8fa1c9de9eca1cd48d8ab4234945255c6683bc8960e6fe199056b294ff2fbd7ebaa33b325e8d5b05740517f42277fbc55434f670d34b0ab576faab32981398dca24b8ecc7c8e31908cb2e6406e446bac7c63539a0ee3086f882cd3acc128eb08ef34dcec5f90e6d8aed52e793bb0dc1bedeea7521dd3a481db3f9d550cf392655b297bdb44659cac040fc12be2cc69c16f875cd26e197f00354864965cfd829846cdf0af58d78aaa2e0cb66c48d6c3e636bbe6df292e62dba9e21b8925b64bdfea254afcc63a1a0c7a93f46574e37b6db4fc5636014c0aca8ab0fb041e0ae27f6e0e3e67127ad7e42c68afd4dec935482cd1d97d8d40c8673b8472be98b7e72fe174462c6cdfc0d4b0cd41c756d73ffbc936325f2315f349924a356c62869763cc94b67a257596f051a5df24db7add8c0bdfd6083f5911599d325bae0a297d59f6023186a921cacd9e20634ea31809b7c30c61d9b1eb914ff3d94345513660a5c4078fe5c289082f573ee39473713183e1fe88e1f1cdef6dc1efd122c5f9fe8352b570212c0bd7609c437430feb2713dc329548c361ecd13b7ce1f2bf3aed689b69a5e7ad2922336ca2de918e3905856354e94b78ffc29ac4bfabd074c5c5329c68ccd0e9a4db86f8acefa15c5fde2e46b1dcdae93d5977061fdeaded28e9bbcca92e23ffa3332913d0d99ab648d9cfdcd6eec610e181abc18895c3ced82d564ca7be8ef9b45bbd2909307aa262c0391a0c21cd28c8bae16eddc5b712e1195805c495af0309841c8bd835180a7f822d2b423fa2be7ccb0c1bae1cf4dae1ed2eb6b174dd5d67c0339c70b69503e0c7e4158b682f5e6c5ef0fe625d8ab983cfad431602e3eb2321fc47583712b61c221eb30340f58337d2f8b6e38d8490b4c7290a2dde38ce898d8193294722a343f9e43ae6cc7374e5c10f3f223e6f4e4686a7a99aebc56ca4206a441fe2815325888896b2cbcc8c3a55801c22d3d393fd620eb972d8ae15b76d81e6cf645b61929ca4ff2d73d421a83eeefe012d01425bf66e8e6b94721083d084c1eca9f5604b98df779c072ae795a22672c96f00fbe1e3def533bb65170aeaa8f9e1b3a6428794d3a900d1eb91a0e24b5803d981f728ef343c5dfba59fdc7c1bc31ee8241b91d2179f7c005c9b85023f6b481729fbc74c85b85b6a18660c8564857bb494d24714b23a4d2ee0851f50d2c70f0ee222d96fa4f5619bdd08f5245855fe18c1e5706a3e17f9c0d6ca362b44551106fac2af47343e4f01fa7103e263faa84e81a8215667caec395b8e5dac707ab3fb53aa88ee5b45a984a324865112b208d34df25610a994f0f1bbe12344b0cbf41515d848cf750454e34c8c7b13478cfc42c9e309720bbcec80312a29844e4191b48137aed2f395b6a52ef594eb8a683541f59ed5998b845baec1f24e47b0ce16680b641553eb148c77516e894c41e219be26d9cb2926d18c5ba737fc81a1a0087d61115216090d889f9f19f0d85098793e4edfad9fb0b720c3f3acaf17b87bb90ebfaaf3bc72cafd3d5c0ae7e0dd462dc39f88f2f4953cbc9aff8611ad936f4682f1938e2a6ffe8ddf5646979030f9c9cbcb0baca3480b3df9c42bb0063bd8773ea7855ec6e0ce6dcfe0f07b6e6322e4273032a4115773e14a17cbd2a2446311769b12b9885fba251d79a555f089d337035442de8716221f6399799e39cad3638559a7b0d75af7e64090b1c1a76921a3eee7666a3fb2e8a3a21ffba77db29b5b8141927d68fdc9464b2cd384e2657135a44c65603830a5618d9eec19dd3e47d0eac61e378eb475cbda24cc27d23362cf1acf0e12a807564b15a75e710b6cfc010a33753f60508eb26d0e6b351e9ec86702a736ff899e10b52c90f0c8fa099e3260389ed0d209a4e3798141b94b86a44be276a80de12082fc173cfc5a00d0bb85b7d1fca72cb028bb135caaeeaf30eeaaffcd96d9c4d40002f46627f1bb6bb6b79432492903e603dc03c103d6bede30c899192819167538165d3c638e69256c1e1c9b8deb59e16ed9e6e9689dd14cee70acc3446378c3ae8d5213a5a4182d17d3748b055a3870a175360cd8f87d6d8f16c2f73b56bb5e74822565155f1ecdb3d9b8b67e7a298ed13d810123fe9c67dc8f6692d096decb8247550613dad6a1a5e642c602c45a6b9f5a6badb5d65a6b2b0cdf3d320a002f41887e3bd653adb2e3575f63ec5d9252b275bb604b7486e5a592918b058c8872a6e26b8ff7de910c0c2ee09d8e306032458beb5e2653cc3d05674a1253a2702864a0ffff96ac96c579a70c654d1dc348de1792ea27070b2aa2d678f17e3c80413be49ca9c8a499128944fa170ed4dac472dea6c8832b423aeb11e88ecd2237c457fc36680104a42443a3163fc4a450c9d9a2a2c0fed7cfa75aa37ed6c003a17b3e85f9148ab8bcae10f19d62e546603f3dde4a4ca9c4f1a03b6e9552addbc2567cd01db74c7de35d1247b2343d261e42f70d3ee8058b7168bbbc18690c632108733e2ab81826269fb21763b7c6f2e95f3e3ad8229e3b7358973b028332903920722cebca54f9944ff96473e52ec7906748e5533e1dd13d668cc1728ea19167a07b8c3e5d5b95ad72276c39699f138861b59e973d3105ef616674f66e704f74e8411b6089e1057580d278fc79812586f94396ad0b9483a5d845627b73e566614c3b6f5da86434c6599e287caa74e7799e3a74e8c0202074a7670f81db1d836198057d00e3900e971732c0309644777a76e7cdabcc86b302440811202a8744891a8290729e6942690674a7a3492507026709a1cc0d0e4b0811204244c699171068935028c4449b5a775c9d5c789c900afa8105ba63f38465c2f14d1363139b246c62a020ba6313336fd6999233c69d0cd905bae7ce64f5dc61149098ac13a782501da3a4121c0f93f7352aa0d6c021864b9b8259bb14ccceec521d0aff2283eeb903adc9cb8a5c3843c2edbe516bfceeb0ea5f2a127bd3755dd7755dd7755d07ea9e3b24d6f443f8909c3241de73a7b2a69e895d8d0db72f18709f771ed809cf461740b49c6baab6505fa8271d3ae88c262a14a1c5e13ccff3739e2123f0448622ca64193a838b5266241606dfd897f33c2d8b87e0fd11823844e1f3029535f56bb3412c14af912ccd560e97824b06248356c3bae1a020bd0e0804ad9649e6c6e72c09dd738ee7ad367a922a72759e55a5e3f383ee993c5be48a8524c94c922449dec86499c93c927142f74c8667eee8494f7a5a11f29e4b6bea1ac85510254be176e3110e4b3a74187b44300bba672f0bada963d98d35f5bd312b5aaa345b673ee514aa1c42661b8b613ce89e3d56288ebcee5e22792d79ddff51a27bf6b6e889a5d93a31c6e14d200a22e30d7ce31303ddb3277a58db32c7c4d71e56cabf7feddb6d2f232c0dba5fdaa839b126d29aba3d45a1820294c6ef0bb4a78711314a84ffad279df1fb026b8d3baa31a022fcfe2b46f0373f25d0fd02b9d6b2a6dfbffb05f21f5d2a28bcee2a5657785678ddfdfaf07672c199a0e65c9a31c0084d483bef50773a9a25038cb0f38e42773a921023521c6e656e8021aa79c642880a5cad562b8c3f1c4782f056784567489183affd0cc91ee35889d95be5d5157a5f92247194709024c955a13b2549906d6a8dcfab1b330ba034eecec02cccc46ccc486ef1571cb5c6570ae59385ee9414f3ea570f43fff3eaf32aaff2cae6921b428736268ea5f005198db163841964e199b0824b1213b24d33d184153213b291915aa372faa24ec7d66e8116ded978e31777db18fb6ebb7dba0a8326b05fc12ae44cf094c25532f702ecea01c34036375023a020419b08419718a14976d092a851f07a650a2da0a8539ca82950c2513ef8169d99083c21cac8f4106a276bea5a8bdbad9ddceeedd43ab7d3967a186db38c97876ba186641c11194ae36a1f24afa1f806fab694b9819d929d929d92295e3bbd21499254752c3a48c9a80c520973b640d5b4901411bbdcb928cb3297b92c73994b100c24496aee862d308e5be99e4b1b991b64ebec38b2ac5560d80707ecc491e312a15056604a15250e1c2023bae7923cb7b0a60db6ee2d0298a8e13ef04869413174b5c3b865058358a89d3575edabd1424dac5f05b54f03b5b0d610374de4116157087244e00f8b822488874f0d1e583fac65856ba27b6ed55853a7a70e6bfafda981e7b3c2524cd350c6a160d482b4360e04505c7c44a0413470dc129f8f2afc7fd007a7d5d2b292d23db77616f388a3f9a034eee5000b00b45a2d9c5b5f255b0f53c1af55bfd6985b9f148472300e5b4a8cc04a05eb87eb3745f7dcd27c58abd558cdc66a438ad08a701d686387c75b1a35e4504f5b438266ddd6733fdc1b31319f2962ba1a7d5718e3d26980116440da787740777c92a059378f37f8c432e058bae373db642b6bea24e8500cbe422d4ee1c1934e29a5f4ba59c6137cd319ffff9852fadfc27fd7dbc269a682534a29f5800a5d37bd17a33b385625f3408a6affe26caffd2d4f29859175346d497457194e2a6eb957df7b6534b9ffffdff25f6dc79bf2fb5bc6debde39a41ebe28b45199928e1bdf7de7bf1a62449f85756733c4c3692a961299324ac35cbaa1332363c9e8bf386d1d242c72cd3b28baf6c09bef6e38bca50b1330a6557f4fc13702349784732b556259bf9f7627c45715dd7755dd7b58917cb8d8b6b5f8ff385fddf60ff5f820edd9efa1e4f8631c6348ded8ad52c0b3d4ce77e47d3f0de30a6176358cdb2e839cf3e5f37b6d27b5972ddfe5f64e92c51b5979a4fc307d2f07d20087e56efbdd90c1de9c8b54063f33b1bdbbf714e09d8fbfe25dfdf33b5461e71f7ff4159e8bbf3c62a6c3343c919bd6a4274c209100c6700c119401004c1b045d74083ca9bf2abf178aa029ef1cea3170ca0417934288fd66bab60ad89f23ca2417934a89535f57ab2bf69502b9ed1a03e4ba2fcff6950452c89721ad4d568509ff52c8ce634a8219c06b5e276a341ad284783a2410df9110dea5ab12ebe30c6b8096df1755d178631be17637c31be70cdf5e27bb1063defc361e5e1b05a799ef75589b200ca6f159cff6fc0f3e06f2d8f8cd2ed7757c1f2abd17ab295d2968bdfd2a7d5565a29a574db8da37674354e0204c3acba37df9c55b546fefd1708ff4dedff2542f7acfa70eb3b6e9918988119187a4aa0526113a3d86c991734e6acfa8c7437d5dd1afbf4cd1fc803fabbd9ace126078920715b6daa4d051ab5284030ec3eb0fb3e10044392c425909104328e2449e232f3b2efedf7f7ef5f2cbb248d85344807ddb199d5bccdeade22fc8ab06ab4fbed6f6adf665ee6b5b0b935218e220c61288a221eff3442d36f9da7c64e8d5d394f9bf3b439cff33cf369c912294e97dcd4dcad395d7283e255582e1e095dc5c66a39df1de2f10112fa8e76d796147a41b7843476b1694d3c3a4e99b43ccd29939607f8a96e0eb8b7e5d2c75aac386552a5080f71ca240b1af0ec2bc6a35e9ccd2452b8203e4cdc2a3e33a04c500bd4b4b9cc2b44a03b36b3212c5ee236b4332fe312665eb14329f3d13d8cb5093f3c78564574c722076583af317e42f7fdfbf7efdfbfb98897608e06ba63514a694dbf3170453cc4bed4fd188f76ac600256fd8ba755e452696c338e75ac631d47521db92b18a67528b43789f45d89999a64634a1286fd0fdd43dc86b82b544e8664cec9694db4f4ae9336ada99332155c478ce58ceb18448726dcaa6a976bd7d201dd313e7638ded80ad7a9888d8d5249605dd07de3e414ceea4f210e26decf123678ef7ded546aa7b6b7bfdca5766a7b39f52f9c14d7a531ac05dd774ead52a99410389f844731af4bb56bb0a14b5d290de8be5337ac9ee170dbb3108b8f89d684634d79e358ebc46216efbb0831ec60cb8112a2285e376e90c4a7ff2283182926959cf1f5b820e695d7e28288e01df4f5926911dda9585ed70dba845226ba53b1947293008c5d28e1a8c040ef182596624d3d84520c52081bdba17ff97d6591f658fd507d9ac49af01879b70bbc407bb21ef830f6024f7a7581f6f401ad914af0ba99284d603e69f1ae9ddc08af5b0824b869fa50cdba85ee9524496b3b1b839dc19eec091403ddab782a2f7bbac40e7240a9a2bc222f3486d9a03b164d8009d1f9b4c0f38992817e68a0203650c702bac1c587069a1b0213b9213e1f0e5c221f3ff01e83c44b94ee6d3fa059c8c11c0dca8725518e457b3bbc8a70d7022262838f83cf1400808e843816b87c82e800e4c30b24608c01e0420180bc012cd95c12a29bfc320281079f2362808410600a199c0f1fc440a2f2f26952004e091072cea01e301c829673fe1899f180138060d8fac0d6f78120185e01c130a4431ca8038cd21ef8b3a6de12daa11d0a59619aad20a519a42c4dd3bc4292e547921f499224598ae258238a35a2288ae2686e66cda6ccefbf31a5920674bf52243ae3f7957a01e17261874258e87ea5b6d29a3a9649de4b29cdc260fb4bd8663337f3eaaed4d662595913db2fb4ab6d16bab1ec13366deff8bd8d4e60d976b4c36e9611cfaeb6b5118c18518988ee3038de18e7bcb17b6d695770317651addf7d5ddabeec66c38355962d01bab7ba7bd0bd69598707bf2a5c9e8dec0aaa089e1eeaee887aa01babfbd26cb53cc254741ce3f7c3f2c62e90ed38a23bdd82ffa64cb4f85e72c8603ceab475ed7b3dc639be7ed674f78f5aa3dac0fc12fdfed2c3b02f8fd9c8f130bf53d0b1ff72278a9c1c044e9954a172817a801c34cbe79da56cb7afa68dae25613ae38a5448e1d49d863294c609d694eddf38ac49443f8ef7d572b0ec4cba441fb040dbedc5b6e5781850eb743a6540859335551f5a9cb4a665845239e534e19d9e3941f05e5103f88de50a51263929fe1b863581c07f9ff0b55efb8a5e5ca319548fef817177b4c3d355b099086f36b2eb4504b604503d740f17a315487e6d1e3c8b2e2d8b36962d6379f07bf936b23faa089ead897af5b8a788c733a296d4c1b68cc576dd2ec6356bba59a3d5cb4129a594562f877df94e4b4a3fcd726796512a60506bbf5e8c73be2e0c6bd2e9641e0fce326ddb2aaeb5561616120bfab78baf21ad31c6dce70513fa471d2301816aad2050cb66a3830f444d9ba0402ec20bda135ad27397908b8b0b0038d8c0c5a505e4e2e2f271e1b48b8b4ba73ac0c36fe7f15944e258d42bdd1ae0e1d707fce606e33cb2264e8362d9ca628522ce632c5a12e534a8d19228b734281cecc6c2d03064b1404ba234a8d09228ff9c3ca267b4425be1113da247f4889e511447194f4451c6135114457104c170efbd474074df1b0441d206497b8747642f7f40e4555e652f7bf923c9d28691b4611c49922caf8060f803047f80200882e69123430c41529156385ffc9b546be4df7f7ff702680c43a23b89ffde2a15a9442a91481d2c8c885248010a119253dd11fa889ccaa99cca9d5903254f9e80201816f181457c1f0882a1e77de0ca03572bcff3be2b2459b24692358e244996579070e20434cd560ca61983699aa6d922c9f20692bc81244992069514a8644d9b2b1d640320800000b3160000180c08078562912c8d23b1c7f814000e4f6a3c5e5240368ec762e1502847511444311883000c02010c0200a48c430e297c004a88ce44bf8ab106874144fd3b54967914ba45556ca8e1d83862b39986bda97098b486de66dba4e9c0c434be265ae3d784687c5c5cd3b789687c5c98a6af09d1b04fd101e6e646a7e3e1cd9f2477ff83c62855cd91d70bca9e1a8fcedfb5986e0854be060d0b384c48f788f82344737ed2f90ecd9c5b2516d7399658832748a89e458873e34762e2604cea91ab4b409b815f2384c4a29da67b7e59167bf8df016e60f38625a434b83cdfbc33014d5f13adf175219a3e26aef1ed229a3e26dcf8bab8e96322353e2e40d3c7c48d8f9ffa0b2bfa68d2b9b551ca0145475b350c958a37cae6b746cdf269de9cb0f135319a1f276e7c98b8f9718234be26a479becd25819152ac1c46306d764d22320d8072d7c78525ef5b8391550db325ec05ad7a5194c302565488db5692fc5628691846025520d0cceb9e829325ad24052e0c7e92b8fa7e20584b0d6b5f93d0adb1250d4d8e0501444ad4a10009ab8446c7ed807918cb9a39518b66fe8bd3803d2120c2b86a8344575a1c0c46e0917f2127576dfa202fd3aa12796c03a0329a7fe36082cfdf48e939385dab2761358ca1de56f6f47b9878a9d409e29861e94727ba63b26f2d7b9e74a9d009833163e9452fbb3e76806af4fbf1a7bf961ee35d6051290304f68fe86f21b85dda231074375729024369ef2bb00bd0184ce1797242fc6833cccf8ed1f0a732da80ccfa7b36a7c4a2de56830f180a3063a8975ae379ea0126ed20965db86b319637f2222df1d827fd500ea18b0accb6a7533402f6ab00c30f4e12387ecdc0af83422d12fa88fde6c518d49455b375d3a9520fbf33f2586cab77c76671f7e4c2b4dd33d53e60b0e7027007f5d2f62645d888ba89f88300f08e464781329d13c2430150bcd5130ff94f7fd86c0af989ea01239b577847e6f276ded9132e79cd1ad9d341ea3bb4b23d260332ade21a31be1901bf5c00823c9488cfd9b3e4d37b30b2ada007a772b5a1be91b995724bc6882011238848fed057a5576fc9a3bcefaf5e39d1e8598c86e8492a79cef7ae5163a571a18e953d370589e9ca098c2ddfdaf92556b611df1e6b40bcea95073f04072347059f3632c33160d6261f2cc192a152aac15697c366db5d88e123ffe06ff5ae17d33acd65becbd357e72b5cd8db582e06693a1f504cd22aac9ba52d272fad68fdd4c00988e0cfbf163f24c7e5d1672d39d1c4155b8b40548dca1951716fd64dea7a7ebedd33ea6d104b214ced1ac4f76d7bd583607ad25584241ec9758a36aa18d26cad19c1af63bdd1a2f4260159dc0cdc67d2ed49002b1f3e32c9b4436e42962bf7c8c58428dc5ec0865181d76ccf165dc030bd5a3402c68bbc27146367435415a1ec211b1c4f4fc26db54706c34782ca2816fd8314e2433d9057063292b3079d1f05cd5b9a845cedae96441fe0f17b900aa770ee7ed5100cd8727a3e1a413d13c03b9cd0ad0da0b040257796240422fd270a3bf2fd4ac4d11ceb50cb1a84905edd1128799c89263016f4f762943c69e4a63f558a01038c8c4bcde3ec777bfdb27e1afdc4bbf89c65e563fc0eba1c9e55318e2b0b100ffa4fc9c09cf96485bdef7da31113e520156ba49951bc8e6908a67717c43293c61f5a8d3ee8a390c0e9ce3f8a93877c7b6727102d38f7281c7e18ce28607d849413e753bbf35b2cdfeef8ec8c09f5c3513cbb91bd1b294a8316cae7ec7b708099b0dd2420642e28adef32f9890bee5b0cd6e3bc6da52f88924a15b7c456f979676687463da9b28cc6e3c6aef0982d7b1bc34596860813afeb6d87a56cd0668ae0e1ea9410431995cb02b6b2e3c6219c4d4bc25aaaf52dae73ba62108d9b241159f62f10120b46352003e0e79bd68345b2b875b9b258c459908c5ff2995dd27b6cf46f1be6739741e2a5bb621694a910f89cd2ea5dc1b4737f364fce3eb8469aa413c15f1cce289d5720f1c9b5d9ba25607e39e9245bc3168d6ba2b5f3ef0fbe01f4ceb1d111df4083c4c9e632bb0cabdd3998ba6020149ee8e232578bbce050bded2e493249879d2fe484c464fd89c9014cd84958d15d589fb727f9ec85f34ec85f32977b967ab7b0305984252cc22f2966d7454f94478b90985c9348325bfea736a5fff7b38057ea033d5568fe05f698f2c2a4a467d45095564d44dd4a975d2a892f9544c627ee7f3b7c56ba4ca2d7cf4511f3db8d99c6b0cbc953d45082852c087440e9d65a88deb6d75053fd5f01457e779be118c495de20ebecd6d7c5bd16f473a7871184271772baf86c0ae6c79343c10d60208a681881967a163d99e1d34627240ff87278e06b198bbe0413593bc734e5de72c1b3bc1a672f350b5764ed8db3fac4c60eb5e49f6b8a651b263cf9deb7626ef8ad042d7de0cb46f06daa82e9d45cc8c44ed5bead4de0b94572b5bef2b084f7756eddda2aac61484968d63093051edc8cd811d05cf8d0e864b20cef93dbe5e0c2f85990f33abace889a3cb652b57b33d1d749738f3ca1721b34384d9d219c2fb0f02070ac6d0ac6911d45b6a300531bcdecd88a3bf244008d002a0a0ae88fd6bd3e25e3312fede1dc0d0be4d5d0800a0a286a919ae7460468f0521a133c8a26883f14093180fe96e3c2b7f56541b3e2f878902b29c20a5c91c31a58d4559fc45d9f5df4006a85cf4911e44bfaca1d9c9fb76bcea957ec7215672acd333d140fbd9ca44b2f25e7e7047a1a1c58b9a5991a0e75c72ba6c9323dea27fb00e0e883e94fdc78581a501fa4e80801cdc70cf3d3d05271140c92d5c7003b79c292cc850f3d2a10f212dcebc458cf5692ae2671c3816d6780fadd16dd25994c883ecf469a08bfee1d3ee56aadc5d4ef46585304b0166d686cf1a4faddca71c2a801d98c469ec72aa67ab77bc7e5dc55c23215257d59097d7630c6ea76cb247fe3ee838d75b692747fe36182bfaf41e93b7576ab5e92d5b1fd51b793d33af11d843ec720fe39bbdd5cfb6b5513e2a3403135a2f4006b27d252c18d638ed5a240783c9954dd4c14863dbb62e9f9d40a21a5329ed1434d055f59a35397fa3b016d3a87107f3aa74243175e005787c97c3524f4687dfa2ba6669217c6cfd78a263f6776ee8f672c9e006ce73512fe6ef6c4ddc51cb443b99e5602df19a31a31b560f55ef05a5229468c7bf30b1957ee8035c0643f289a993ecea334038a65bf575a95b54b11ce7a2ed6d685cf43c215f2d2dc5b7f83af112ecaab05abf7c3b7c5976ac42aec3c6f21a1f71b0326f87a0dcacf81dbad9e63951d29badf1830a1cf6b507e0eb95da817c08eed8dbca594d67f4c88f0ef372abdce4e97ea0b4c3cb607a5b468b7cd22a518c11c775e6f93d17cf19c842ec720f639baddeab3d2b6b1272543ebc53909393e43c4bc6bbb25349278597935275494790568735c9f6c89bd6256335d39f74398c8230563633f01e73f0e4cf0f71a949e03a75bbdc0386b921a5973d760fb81f0d15f041d51a0c403dc867c5ad63460c2827d4258fccd8852ebfca977c54eab7b04f29df2d7691db4a21e8861832b37ed7c63a7edd81163b25cd86156b8333096820624fac63ffc22f04a1ae36dc09ec9297509e6d2b85ae0a54c2cc461f897cb70330c8ddc0b198ad32af8623653af437216d5cdd778c8ef8083b3e47ba885bead9ff472a51b37a8e92e069fc07406b032ce4e34ded27d61f16221462d30179d71fe30bfccc58c674e915a4b0206906d2f2d030444a54b6404c86b7c8f5e4e7dd35626451a2eabf783c7924aed2449f70326a13bc63b085c8791d87372bbebe4ccd73558bf27edf98bab60d77e6561f6d041ebf5fce3323da30a1ec6b9351369b3d97addabfaa9d61c022d4b1be454ac5f2908e58b3b8617b4b0a85a511ce51a8853182339a2e2e748cf14e18c44b2d8781998e4559fbf0b257d2588d6783b99ac8b925434840d86181123fc3bfc40db3a88b84089e4e20c5768e2c9b738cb20fa2157dfa3ebda769ac1c8185984b51927ff847b28bc13f0686f720168cfb32658f999f4c153c38f889411b164c8fc9a50f0adbdea7e56b5258a613d490d5dcdc00ceb89dc44df08def28c9d912a0fb621ccfba0d259c26c7c2f65cc5ad48e38cf2cd3d5a603286563646279da1bbe176559f123531954468b307f3a3458b08c1c3c5a1a21a246fa150c2ffef54dcfb8a724e68c62d791f8c980202b65d270137ef1ca7057800639e5ffb46c839f7cf44973a10418b98d1b0acaf9d3e77b08695ab728b5e18612ba9ddfac1ca0df5ac6095170e85afec27e291348487b9459d334d20ca9a343f785494e0550db26d8d6aea19732c552f9af6b609c21c85dc8b5c86f164012cd20371a49208797f1c5f55e6c1c032a01f0b65ea587848bf726e192dc507b9acb6eb15c7f3506435dd583336c8e573b6681d7df651f07fed217c1a535ea61aaee713d3a50cf53d06f1c2b98af21d22d867162016b70cbe4184ebbef10d29a9c9b79861f77cd92618be4126a94ce858e16dd8c8dbe534dfd689eb763653ef68178c5e903632645f020a0cdf10815381f8b530396d2aa222010be03ee5b6efc158d7d0d24b5aabc81218883ac387a01bad765a9340cd375c58b4d0730565d3fc0da67497e9140c47f9062c0f995aa50f7819f57efbd5705d4e429beb1a1c643fbe61e92de965eadc35a7f86e50a1bb4832f843572e2248e148093ccabe59a0c94861541138640b9165b660503d34868b7eeab712925328572b5bb0a56159c2405ca6d7259821f281fb6ed761f7d34dae4b150575dcad84172555f44a003c2c91b58f3c89e80f4eaedf34d14e3f59c2e7b937f31f91117268c46c7146623afa289111965aa0ffb6e104b56b061720ec54acb572e3f49ff078df9243cad95119d5e2d9fd25efcc600e4122f288bc541ab5ee7cf83cd70f092654d4273f63d6f65cf679cb50737dac314acfc4563b2ab5c2b7c3a084702d72b4672ec4cb93616c934a9962f06127cf64d30ea4e672b5c92810de1070edb3dfa994d2a4489f654f2ba1ed32e83de39fa723e7cb8ec48bfd3ef3190bd4c260e9d09e151b1a72e87e47bc3aeab4ef15ba1ecafd29b65526dd3f626eb0d27ca8684e59e422bcaa492d17cc70611fc7ea3d2cfc9edaae359cb8e5451be400c82a5b451fd6910ddb1dbf92b175c64cdb124aa1f41ebdcdb6ff0e10ad78adeb30c0f6defe027b5f97c604e88c752eda0c7066d3f06f1941174e27ab4c193200fe2bfab7040338bb6450400f6508327f5bab860ff9c22ef3b47007811dc4b68f1ab7f7d59bcd8a70a4266134ca067ead3ee23327969251cdbb6e38cf20ad55b71c723a3e42a3c8210edc1514387611cdefd913d0b4553727974ec518e1e01918638312d560b5277c9c961a9667723be82129bc510db2d07024b4c8d96843c679de274bdecae69c031af019f2c005689eff5ec7497bc362f4fc52b31049e494733334ccc993e87550513fcbe06e5cfd1e956b78d85ad01f0d028a3ac828470033afed879e90aa9373c7c14d68194287d4c6c0d6d5bf7b0316bbf454e8d2c3f2e2a3a08bc1e83f87374bad50d2bb58d249fff6f6f7cabd5b38d68e1f10f590a85a64b8de79d67757fe567174d83731708e3134bcd5c6f0fc86e49bf8e484d5af1f5bf177029b1925de93b7bcc575057193617060d36a2f2dfa058b89fdcf3b33357e1ca6c903e88ae4753465578070c4810694dc9597459fddf835e3217dc2232d8724e41aab88a636a8c870c5fe5d1735d2603aafdce79b5a3ca250a27be1242fc57c4aff54233f5d42f754416a644ce5547829cce17fdd939f63f0a4c866c0f0719cfedbcf2439a37f1d41453cb33869a787538994703ddd3574d18842b74c05a9b3621ad75e4fa238493d6b8b4063a684a1f9c077f021d4d9fc4b42cc142376dfc31fa9ecbf37f31b6777a7bf212e0c8cd7a3b87e089ae11b3a603f257115dac82d69c5e7d34f76b0f09c98d58aa6981e3800b38a0041bfb8e60386e6086af95af6df609b517d7d6c21c9a796cd5ac7686e208b761997559f81a19be9961420a9a138af35b2df77c12266327274597db3c6e5dc6ca1d6367e78d91650d8d821dec9f889b390ce478ba3eb74bb5fe7d0c5c1efe6020accaf9f1f2eacbfc6be46965f6937c8a333ec5e6948183d41280b20a3fc3b86bb5921ef4a62efdd8e31f1f8cde9fbb2c0a85a45ea29692784a93351af5c9b1dd0e71c68f5c63fbee0458361348a6597df6c93fae015ace9f2064de32075bc1255ed5033418e838bc1962bd4a76d1d5bcb7eadc8225b20d4d3eec1343f345f74828f85cd04d886ed6bde249bb5e9a2406877c22fc34afa12a262e70447e3296ab0368a8194f6175af82b6241f1b6a4face92e70483d29e53928ff137ef5c0f5a17a9d6eb76860ac50730a8490f36073ef03a874101884878094711120d0a4108c1853b24f0e7ea6b4cb09b8a2cf91123caa6f998d29b79fe69a2903a5b3488d35613eb7a007abe1b0f92e45224ea33b8f9d75ae4d3426ee1007385eb8f01174445f204a8f18d5aa7abd86d84d417463b50d8cd070f2f7fe82021a4023fbb982b4cea10e30e547410cceaea76285023fd2956640d3c516ba31baf4900a1a1e2b716d590b2156172a6c824305c41c8fd0e43a2e2ec480c32b3715f8d45489e6279409451020a1f16d7b01ac2918921c22ea2f10d24542842818275b264ee98671cc39922b827c5df3a12c581f7cecd4c670834fe87c86b84640222f9a6376d707463dbf9d3cd3dcee394d70b3d11765450b8d134c394b81c02e84277812ca00aaa083b36ae08e0f8048ff7310f08030b43f2124f807ed69115620419f70420eb79f336c812052113c8d31cd0e88197abb051133d09bee55fc88ab83448833453b2b40a07c6a17c58a20218830a4e34ca1b6f51297c1af21e006ebcb5406ee16e8d51beaaca2631e82a3d006cf389f01ec2bd8d318d5f1587f7dea087b78acb399f783842c24b37a0e2eb7c759d1926ddeea887d944ad845de0d570355761c2c459bc41a1ea6b672f6d6845c6411c53b48b8737d6dbda1b4a245caf51fceb75ea78a640f53eff387c59eea987392d90c4848f7557f69c77cf0c57042f51b52869404fa97a5aea6f95c7e3bb5aef88a58c4cfddc35c337fba00982765c38bd404cd2d1efb3a998642155963389f944c50235af0f30ca5cd5239423fe1b6c6e5eac300545557118dcab4217178cc1528f47600a041c3c7473d9c66c50f51fb233ab498dd3ea12afd754d38415553cc6b85627588fdf59cd0f6fdc832040f4482d96d690bf469623ae9c92db552105ccaf03d1005d9417757f74928a98230bd24c631d1af294b1fd49a973ca3cd5de3be16961b00e04cd31e03802fb8aea0ffb431ce42a99d1e92975b3ec68fd0d86f41336044b67305d76b020bc2bd73b079c34b98822ac3f0fa210e851ddd59e1f22be65442d29d0df67c2644760ac4b14f12bab386eb69a4747cdbd8002c01a0f41f8f442c2c6ab0ed77fedb812539d4bf8f1e5c49bf1eb18c7d01661089e7be9cd37b74f5df80cc10e2888b69f011c7fefc02d748d18846bb5c3328d26905cecf3b1ecf54fa49e5539c094ae8ae715a941d348f73ec5f3103b8abcf2e0f702567b00a379617d431ab514d956791d6147404dd173f786fa4ef045a3a559d66c0696af0a5a8e99a58f4308cc0253109d01afaefbfdc0cc3db5c9d3544bb814c413ea5e13427c8482c4fc6ecc537d347bd785dbd11a61bf8ed82988a664a03f9beda875eef7f745c5331b2929a0b9717474db91cb5c41f796c27ac32304e1bd1e2eb9835cf77547ca09133a43013b2a72844ba23cddb209e41db0e2b81e16eb2205f0b6f7e634dccf10e237dfef1e978a41b824368ef6991c2df2d43d49274a9877f7a1cb771cec48660e77a05cb79aed1a19fd27c61605342c176cf5b5f25db3e4d6d2b882dbcea6c5718be2b33ff8722716f8a14c983e16a16470bee6317eb6f7f820b01caa1362f2b7cd40535ba0640577eae736655e0ce83e2145ba8d811c100e22037bec6c4244f727f929a8db005048871192e994c9ae7c0fe7630b9bff92f5615546eac2bae681073218b2b4a12ccd013c680fb18b2acf207192d321a36b3ec12c4b27cf6d1ec1a0ee124a48bffdebf4d2a07b6476b1bdf35c42f75a65a65e1bc1e2c99261ea30374aebec58e29d07d640414eb542ba8759e9234b97f15ebb0677e0645093dcc0e6b7d037d9b7f6f5141cb14e363bb856c5cda8e0cb423f7d8d24a71fe463ae7b3c982ad489fa244d31cb1cb5f4d32eed7d090649465b9c1a468112c074aaa25a351ec2fe287704189598e25f7c423ed85c145fc8c1a70881e156a0deb5a5089f552caec664fab3550bd325770b22ca7e82dd0fefe298bc2c54f7752504030a8b12dca03df603e886de3e0bc4176471e4d182278e35c87ad32724bdc890671613deadea39272ab6d01202eca6aecd8838cc0a520372acbe0b2ccd951d927121033441979aaa241decb0f3d2ed07bacf946a537d672bc2c298acb073409c23a0eea0bfa7407179f28ac2bbb2fb861e6ffe3640b7e45c63ad3456263076f9961c296d0335be6950ece3a4853f62c0601ae0c3d387ef1113a34889ca39d6a1c519547c74bf289c40737dfd151d52663183312fa06233e7ffb8fb1444056486490b840f3831781c1644297526267f4c15400fa351336aa1506755f347e210e6128b3f8817c20bcda94851dc88aee800a833d6c8f461668c7830ce655746a5c35270c9801cc0a68e36f1c044ac279f1f9a36e32d7ef0d5d09a6e49f07f5873d75f9bcd3d4586a2be24d8dd176b48706b14ab0658d60636487551d8e8a8007a7a63cdd7be7018a056ab8994a006043acca1ff194171aaaccbfdfe491e8d0d84a3ef09b09aaa0caae9585dfaca7f03f1654e6b63674de76f90df1bcf910b53f94690d034392e27b0e322669003638ca80e3e19646afcb3085cac86e12fa3ed57d8509f6217cff30445c23999f48008084c215bb23ee98b1980e71d5c9287c63a1b757c25bbdf8d77fb9dd434e11fe9472216dc6c45bbd901833c3d27e904a14fe708c3bbd0db6091e8851b94f7b760e93e6b1f6b708440ed085506c97c3a4f055436d80d6db754b982631f6271143163092bb6914a977827ca6399a27e905951c68212ab060181b70e5d6135859eaf4f586b18fe80eccf3bdbadbe066d6775a31e243bbd8dd2ac4feaee3a1d7ff05fa89f18c49144c98e5f313e40f605d47d0d54d4c56ff460ba4be182d8d3e3654a2da5d3cd1f23666414a739ad789d9af06a00d6dbc2700d3f6a7537c94e4958de23566d0b197e25316d16632040116419cb2b430930b587e015016f2f5ad50b050b571ca3b801087c81a40c3121a3155afaeee94ba726fea395c4ff3bb34c2090deedc54f80a6bb80dbb1d78c1a8a206b0222b5cb93a83f18ecca18b36fe4eb2496a4373697959d1d1f0f348b4ac34ae026216afdc3c6824f8e88a6a28341ec059229601b48ff9e2e0727d886be2b90498b9d15e269b5def42654e1a66b60d5bd194ceb847ebd0921d23a28a7423c0410fff25e3c201a10f1e2f279a439f4bc7fcd8c02f280cf4b5e5134a1463f2cd62e67ed89c4ce4fc89a5cb7a0020d04fe5c4f13704d16ecbe51bebed16a2b637ca3bc74c1c2d553e7ef65164ed9d3a64c680f202e95c276888352b52779b2f4ab8ca06268a0010851480d8a42851db70f5ca3908d4a6ff4c2bf26fda0c67adec67bdc25c62d1bdcd396164ef8005ac9262214d867c36d6ccabbeeea078331f3015379bf57a5c70e6301ad33e98cbd120227a8522b9441522729addffd274aea4b7419c6581881a03f81ced22dc130dcb311203fd02bd84a0616b8913819d400a705f7e4317a12d69e99b8c27d5e3085ecb1f200a02b02872c6ea382c06c1148d3178bb31b614f08c37e5e864d1c9396b51702c7dbbdb800656d674c18945c4462d184eb3150a7d6942f970a103e2b61c3125773cef6287a2e8a52bba444db3bcc4b80c2a69b732ce44c4ee41761ea98e022433051bd551b4df76c538e553961e7838f321bf75121caf49f2bc0704512c54191a40a4d9c07e17c42f8444e573ed6f068d55e03aae5e080415c58263fb9a632e4c909fb443ee14cb0a542df7402349d12684f4ef8a56fc75e2289439e30e9a4760fbad73a6ef72606642d079ec2bf46a5e675eb5e5b6d024cd02120b16622d08accff5189aa2553c59c7947e82549f3f5dfeec1ef6120bbcaefebe7ee586415a7077f667ee20e7075a7d2a8942464cb3c6a4fb215948959666c363998e1dcb685c81fa0c22b3574f0552114c46f4e9ec8787a1f387e5094a06d61d99891c4775bc647cfb1fd2704d995d408a3f786d82c40beb72b97503d4b42193fbd0b2768bf352758bf51a421cb248cd14eb61a00e2b3a34edec661c8fe9143b97986406a77a1e60ce40c00dbb6c89a9c961c810467d88f7164e055e9ea14103ec4241f4a55761bfbad12e2761706ddaefad0e57ea8e73098ff1ef739e36fcc44ab705f8bea06f8a62a4269c05490808d08d4a8aeb02d46dd2ecb49ca979a93823e105cabf85ba85a82d71a46904149241efccaa3450121c67ee930c2b64a41006e2c49406ffddd5c2682e6d772bd572f97bc7885ad9295c21898047ce3b76b54b6fe4754190b6bb97c85f50e54153c4a6787ee743b12ce116580a5aeea936c43e1a0c989086b250768d691204d12680bee5e39f69fef0fcbce3f703a48ebf349786c9b0f8c1bef5bafdf7b320c16d8453b39db4ed7295ce0144fda07b486567023896ab63c8fabf3cef2203cc99412cc133034fe8ee55d36228ca28ef4846036ba01961886f75ba767f66033eec5279ac47656ebb84ab0c218b77b031b13c841b61c0f954ca864d91fc4c7b8848048300c93208a44a594a4c95eea9392d0401e745b7cb1a90171bc1b5decfb450d90b1942ead35ef8fba2e02a8c26c9f796a2699b51711151490b0468b3c63ba4bc913566fdafebe46da53cb0f7042bd24eeffd0cb4d22a89efe50f8890933e6f90c1747bc932189a00d6a33af76d862d9bd5e2ad769c0a6c10189cdc13eca89bc68d93dc541958c8b165f60c9bd6093d3fb8794dce11eb3041ba7b683ee8394c1701af600cdf0a4964bae4a1c32489c1641744b1820de30d7d088d058fe519b2a77fc99453b8b6132926804fe3e19f29a50a11291f8686753c08a11d1f4bb91950bf395a5271ede02d9bdc1f563f96e998553ec3a23d414e8e82eae50ee7a352cd8042eb4b559233bc08e6e65baee2d032acb9da4578b0b791dd7481edbce7b39a3d8de8ea072ec23e88101cfa4eb8283a97bb1cfa9503b72426866c6517edb05632734c665289433d72b560bfa135afc58325df1f71f1495896c86c7e8c88b46cec05d70816b24af82998802a4147e231461498f0cf57127a0efad5ce8f1d035da0f52e131441730a087288ca37745b4a23d0eef4ebae3427ab37200549f0f31dcc59c63a642797773b7c9d60342be2d4e191e0ffd584496ca663aae987bc7f604a122a9052c863a9e4e90e47eb94e8e04e56f3a2e48825b68a2932df60af71e726904bafa86de233b305390ac82edd9ea496a446692df532400118e988065f2d9c64a82200470522ed6e011a629f4894d5866ce4e01634d2b0031cc019c06c66358afad872757fc3511554ba060f5aa838ce8a634b81fc3536e019bcd51d261d667dc3a49093929b41cad2435c504dfb0483925548353ec2c8bdee43ba1c7640641e6741ca4c440b239e2b0b085452a6733a7990a466f09f0f8564ad46490bf315b17d59ab640d56414a6bc233cfe7bb62e3382c6466b536ce974af2dd46e51a0e22181720a9dff29b93a8358c744fd1a9feeaa804141878e1080c3ac23e753df53f14b6d0002cba9cb28bda760625c7ffe0a8bc98aa180dbd602cc584720c60985b5a970dec5372a5e03cf4784c9958e8ffca05c11ea9bd7362bfe1c87914c6b175e2a13ea6f59aa87070e46b03c24af8d480040897b1db6bf56fec692457b634499147c075a189ab3517a01b2aead07fe7cc96d8170cbb1ed6e8546d61ed8330333355b124e5db9d2d886e3ff315bbf228f2eacdf69609037ce5659e7ce581d2212a21b4f7214a6821cac30a9bd17a6e053b6e0607bb362796bde218616d70e55e6d8a2613c466ae0b9837acec080fa67b0bb36ea527971ec22cb23c2e3d95582293641fee0ed586688e9169e2030c865b96ee4ed4c459cea47298892cf53ac4612b8273291c8491507870cce0aa157da3bbc823d4dcff13e8103ac182c291b3fecf50c9820620e1c2815de8a39f645c4fa8b3cf1e5ec519656d3c544d4456bc9501ca6e104b4fdcfee22b5f75573b65b07ce23446258593b78859594c5594edc894594a087db85b8e8181a17956186756639c34544658459aff021579139ca4ff6ff6a566f1197b6ccd7b7e19e384d7319d6b57dec41b1ff3c3e34eb3c2f37edd498c557cc9db73e0c01fd0b8a673c5a90aaf9818ef5fd4cf15f7f9d2799dfc1496ff4933300b27eeb5debadff8839d77eeb513181285c8631c9c956d2149fe023a6031efe5f4494b9c1ef4da31f02d91fa84f215ecaaca015211b936c3194081447fcdfa7a8ac13a4b5dacdac0517b67032d480fd4030fab18f28900635b62474ca6f89ef2e327b889b5ce124b73d39ca4e4f91eeea26f583ef86b201c18cfb669d44c92b07687e77c76cede7ab083f7abdaada4366152a840c9ff9178517f29373cd64c936495095146438172ec201bdf48256676907666b11876924feeaaa91144cb20c4f8ef0ceb8c31b6803c41f5a3cb1705c8b157f99a1b44c0c4d3bcd848975cea1adcbb69d780cd23f82ab6256a2401b6a3382767f06acf8a1753061450dffaeee5d0284056cca2f047d247ef9374f6871c3c3bca9d415b06ee21bfb72882a9262434c4cc79fde3ead131f4440b40bed948f4df194d25933f780878a4bc9aaa5e2128ea4baef5c56db30d55367dece5d42e2d4c912fe7de0dac04bf5c1f00c563ae78387645b082211e793d43659737c876dc2a8eee8f21a295fd8ca0c5a20aae5dccf6bd234a6c1c0cebe23790b9d86fa69978debef3fcdc2f66b4f32ef0c7be1795ade3b669b0e561a1fd1faf884344db4b1eda33b16d2ca64208c5e40dda41967c7d50f669b0de6c1ffe4419c6f22753dd0e9ef7c8bf3c974e390d0751061fefae6c484214bfac0c9e8ba56123c0ed88770773a63ab6600870481562203f8ba3dbb8d20e088467c8b44174f3f37ee2484f31f5e874953f6347e9f548736ee676b747dd0cf30c4a330045d7f374d401eb8f99e16319466b324e9723486d5267aeb16c87de794c42a9fa67380de4d0cba9b00c8442380c8d818c1830224bc599bf6aaf4653a18a53bb03a6cfba35a1a90491a24d11ea40079b737dd234a04b036e5b6db92c59be1b4cfb18674d2d6b2b13d2df90bdefaf268ce2836ca45ed2bf6ae8536603a235d8f051457a1c40cd007cd8af38d5ee3a2b59789ffe683e43ffe9b832ba3196cc8118afddd4df2ee7d4b630e8aad5f438d84df63d6808602d3401d8620420513502aacca0b8c5dd6ef05449ed07f6ceaec6019243fc39eaee4cfaef559b88d79ecaad43994ea87baeac110733ce4447a96e7ec76d99c12c26595247ce0ee24422ab9ec1e8a61174d73604b34aecd7fffcae01747141a1a56a142e8a9e13ac241e6209828b0837430c06ee1c9304a2fc78bf8336efb59c8c39b0c1571f4a477972d37de16fd67afa22b716d22874d5b0b3c9f18ec0af850a553d991810246f8fa2d52c6903967b250ab4398a42d228799cc9ee3a20a32843e8ef1218b38698f1695231b9b24b19ddfd737ad65dab8cbf4da3987b2351b6a5965447f0d6682fab31d0076d6936d3d14d5ea456d8f08c3e84aceb0b03379e7a9f8227e6fc40988154f9ef88e5aa6a2271b7403e56486979642ba46c99f6b2db91a52b0b36651e4a973de02c312a249a6f52fdabbf2e549ab8512a7d02800332752d9c53732e24703287ac5256ff3035d2d261cbcfb725b1a77184657b62f21e44b40f6ba49f194fc29d457ec5ab0833ed07ceb0879eaa2d937b869688370197a9fea25300b3bb25e1af9f86edf558f6af3310eba8d861cb17918825bec6de01dc1bca1989846f9de6b905f38cd6b8e64dcc9a684363448b407b9a0d0eb7d0bcc252382a74636f3648486f577a975470837a9c06d54ffbb4e7e2052f8a1ce913b713b144cf135362c6706a010d1de31ac985638408e9a92dedcccb76ded5a0cc8a9415a0da5f3bfc30474ee3ed15e1e0b599f2a4cf62a8f306125413d449035d2eb485c2415305c60cb15db190ef2b57dab4835a43f268b06741c49cf43e20d0a92002d0cd40ea813c350ed5544f7775678d6ced8890dc4ec0eed2de4644eaf05dc62bf0e129a501957b4e14ee082a87ec4c7811aa6fe3b632dbcecd5f6debcad79670871da3c6d7158aa5cfa285d790087b77484d130b9ce3374539a10240c22bcff429e4adfb7168118c6fb62ac93a57238d8a733c1e4bce36663c38c53606ca2eb6ba847a6714c3f65200fa7730670821225b5235b7bf4c7c7342ba90aaa50fcda5fec2f99f0d06cbb6de39b291f9e15a3ffd58a3e3c3a597fc88486056cc476f175509f8ca7ae99d45a2664b4296e07070e9ebc954c58cb89a278b416be305a540ca04cc04a2b88604a3404730596bc628e9fa6282d71efc9ffadb2a9e6a0ebc82af23d2206c58bd391a2593630708d51904a389a802fd0e54b60cdf50f782d0c0209b9c3559ef16af2f522907273828320b4a1c165e6f15042a6138eb2a6b14a63380fa98e016f786081cab365039538bde27dc2637f69ad127388212ae55e51fcd9e6c02af89f09f256a17a1824634f02080dc2635ad8642182530fd1aff09467c07b03aaf5d1c846651e7de75061de69b145755db254a9beb16f0571ae2ae4992905222f5a3f2cdcf8a6de20b769b226361062609188f53ffdbc0fe9fbb9e19f42d67252ae2dec9f92bfb3fa07125bdba0a8d41bf3d0399b398f24b3f65a9f6dd1c8aeec2d5d44cdf23889d8cd1665a011ad725b118b508e610b0fd0f6ffd2fcfbca9f374c7c0642d3d74307f1b7244c88ee376bbcd86ffbd0f1f74d81e06c0595b22f4029d3a3e98a9b6044c25ef3dce2754f5f14e5b4fac5d64954e1d186a49268db54d6515ce9504239db087c4fcb7636c3f33c03173e4b4cc5fe82acf30a94cb68595605a465c392b50a62f647d7bbac077629f507d8ce7f6338cbf457651ea9a770f9ad4915c1e03e60b61a0e11cb704d6a61600c4f99cbbd1ba40be51662bfeae86f10db47d7bbf265b71552643e0c933afa7a52820f3fc56c0b1b4e04a1ecf1c00f13eb2f0e207c68c0c09845b9bb425ce8bc7a455f6fed2860e73ccc140a16cd9350de518d77a318b3f69790aabb7640bc23639813c3969b771361f72d5acf9fc9a36d6b0d4261fb86e7687325c1ebf5f62ea435be3f115a83cb2cbb5a49686c6017347c6b8d95293cfa2f65c630e5242338825a91ac057acad5471b7963ad5ea0a947973e10abd1889d78b0f21d0e225454b377ac8015792c47f6d77d64817cec6477647de2e8ce858a9eaac3199159141011b0e7c6bb99e2440f2937c489b38a1e223e06d707254ae226ed3dfcbb7f2bf95bae34a42d40a3a150b3b128529b4917d3d9f1723e94e0c693c9a137b6ec64d1f543ab230251ec6bb3c682e664d9379625d87de56051a3145514a2bc1a8e8c8ae61f8a317074c7d0a4a9428ad0b80d8878bb4ca4796fc1c603dfc5b1e930e31e015de5b3e50a695188e88085542a5c86364f10ac644502592a48ff11a59a495e19609c74b254c80fbc0cfb42fea5137d81630c9ae6239b156d838c6ed10bc7e8af750c9ef2074cbdf3d1b71323779db7cebc56cf7b81d165f9765710c7d290cec5e5068f572b23e8473e6752effade88d2ba4de2086b74e2af9352eaabc91fbf924bca6d06c19d9573fe4e79acb142fad39040de0d7cc7c62a3ae8e95094285b764b6aa09edc3b29065dffb9d9a3078d4fa05864a4701513f5a11301c6c7071e5638b06d05143539aed4cecb3d0ceda6df04c2437db1051190c315b22c7e2c19a709789bc448ed81481ff203d5648074a1681e083fd5a459ca6a8d16631acc86ef23593a400ecdc0fcd58881495dc842fff452c076db1b2b1728e5487a61c7b2321403f4383f5966a411184b7a874824adbd8e8142ac3f9c011f2c9113621d81f4ae209473ffe519d1c209a8b5f980d5a5e36d0477e42940f64056b971341f0992983149707d5b27af62410892059adacd5e16cd0443f58339387d1325aa9d1982d400dc00490e677db498b250107e0fed1e2840ec1f3655105ca01acd5255dc9cbc9ce988e00f5856e1a0d7abb66aa7cfd8843a222c6973065f9e2657ee762759ebacd5e442f05257c7ad97f52cc0b1b720d84b4d0a3e12ceb0bc53df8dc321d4b987fe45b3813584231546a692d35c65e461f12e59d22031825f9a73afcd728f4c27a7328fb454e82d79cf773fc0943d41ebf12ac91d85aa213f65b15049f37d8fe2d79cac40e0530ef87a5fe168b360c8030dc5ecad2685f42ae6a14743bb6a45fffdf1905ccf31021665d36b4d27373d0ef556676fca5b55fb61876868e59b198e99c8c34ca726799891fcf364fa4720a14a57297a15a1d9bd9330e091aaced2dc86380242aa3335e2412575e7fd558cdb92421d0d6af4652a9cc3d813bcfa881ee62806e16a3535e31344d3126034b54693a80c00f62017272f1756e199afc9e47251c8113ac1babe4eabde0a297d4bddfdf180daecdc0894a870bdce2c13f622c191fdfd07281642eef6b6f129eb709faaabab7eba17d9b8ecab5001691a7172308c0e71b3dc946e3e07c92255e4c2cdc620f4b746ce360371ba209f6c691077a3e92ce1ac4ee8131ba8fc8c8992647beab6b5dcb09b3bcd52c76994ff2177da16b66681641adf0a698121e53829258299414aadce767b62d05e731661e8fc5c125807b9b1dc3ffb100d030a1128e78ba347ace2820b7adb1deece982d53257e00bc8522d5bd221941b2808b8c7f4376d0ad11cd03388068407030a0fea685c30903a4e07aa31e9ae52fccad045332e99a4cc8de263f87da403fe1803e3897fec1d88fa587b5eb289ddd13a66b131ed0530300cc380bc8620c7916c774690f808f0746a8316b6c1244bf7429dd4e1a309416defb626a59432a524036e067a06600634c88bc2acc19317c5764a8a94142914d87c0a0594e8c6cf64ff700ab26b189b103f7e2f0173bceb2a9658e9410e13587f962e78135f761f24fa39590fe6a9f8d54a52d73476e3075bd8fecca8bd28a5bb7cfa405c76d1a8bd78647360632b4254d58c602a7e8dd18812318c104a29a58450c6d8f9094416fe8e2f2ceca0083a090bff535dfe0e858485cf3d25833fc2188b8257a5b2760c0b632283353327b0f03311b05898d397e9f377440d9975087d12438d06ca00500b9617fdfab0855240697ee961eb48773f73327887626175fb57b7ff3b2283ec502cb4ec28d05ab0bc6ef7ea3a07b50401dd19562805681828550ea580b911c99e76a82194f47476444aa59f1d6ac89c5ad73f9e6281fd4ef73d75f2d48f613fe8447564cb1054ebbace3406c426748139dcf51578d332de61b9ec910b668813213d823763c0547fe5e1e2b692dbcfa66b7760bf18a331c7a1419e6a1a1414330085c51c878853e801e6c800e2b41430f5ea202e95542a124808210414ea7e34f6c1fd1ae8a3b3734061fd3f1a14c1d80f16452f9b066c246a2fd65ef308c27253acbd50a8033eb79f3be6a9f6eed740b15a690c28d6314f7db15fed890115c5b6b05c7dea930ca2604bcfa552778c31c6d87da4f1c2ce8effafe0756f23478197eb2260b15f1bc19c460dc95e1ba27df6d9ebb4645ea715841a92fd96bd4e4ba7c52fc335100beca7ba3341d6c6e6a08425ac0851eca7ba03d8096af9fd7e5c7ed8cae2973815e0fd01849517d5517cd1e276517b03d809baeda5891a4c908e19c58c54465607f61da7c88d19abfb76a9f43dc3cac00f236ce949df5d2a75240ededcc8e82a56afa0bf48d1e7f257ad5a1289d25a6bed4a690ded31bbca7895c143c618444cff422a9650b9700b42bb3260f78b3c6508412e62a2dc2ff27cf18a81f28a501a07b698b85fe4b99f47d7dde955bc42e5f2472711cae5f7235609ac9123f6ba0cb68026f09b11e5bacc80026754200599b32fa5b4371578fb0184257dad9b0adec7a4cf2209c29bfa24d6086ced68f775d7d09e7f6f2af477c72e57afdc9231c2189bbd1dc352fa2e984fb90874d195a1390cf4c85c278237fc239c61f9fdc771b40f8add7ed94f6a206f695d0379aaeba9769f0315e9a2cf381f47da1353743f78c47359134374f99170e42932525f027c499d1103e8b8241748ddd7ad73fb935d912eba116a375600a6f8955c661cf8c9e5af8e03996b882f126eb09f0e8f4d7bf0cdb030fa646d83325813e17743d890fbf8a563c87e9a12fb591af8d03b147cbe901b01bcee820cd67c0dbbfc157ed695532005804bd283680c268ec41851a217940ea281f9c82502111635c57e7c04a4bb677777b7cb7c4f2eba5f929edb5c74bb9361be092670d1e5d2cfd151ec0e0067c27bd72e97085ff321fc07c1dce6fe8361a0d18ed7f1ab1ca8ff78e736cf8dffd8c9e93f7ed9f88fa1d4f88f7b40f88fa3cc7c2ca5398b89b7dcbea2d44cd41f8cf1ccee547777fbf84fd5e33f56fc52a5f9a8bd76116159ccb304f230faf3f81338159772ff11388ea63d77777777777777777777777777777777f71e1cecd46680beb3ab257c97f026705f112ebadea16e1e5eff123ad4cdd77bf37cd4ae1b1beec5902079c42b8211b66aa9676f8495085ff32174cf5f64865efdf31fe9d58ee7afa1573a9e1f49af723cd33c3feff40af5389e9f9df4eac6f3094aaf6cd400e17986a5306c87246e70b5d883e7e727ecf373965ec93c9bb6c07aa5fd2a2b912a007e2580f7f1fc407abc07a007075b3e38d812818317de8e8397dbc1c1ab83833707d77d491cccee071cbc331cbc2070f0d6b81bc7d70400aede1597e2ec89a3e184b4c7bfe286748a5f048e01355c089c033a2e06aec8733b7470357048d8b5c3dde0d809c72f8ea130081c47f169ef0806e22c42bc856318c757708cbd30110b807b4ff1fbe0549ee20f00d783839ed258b79bc77168fa1585f9a8a9f44f03b5b7cbe8480c1f31d721238cb8fc1cc67fd1b579781ca7d6e6699e587d5c2e97129acbefa3e8327d35616bc4650727602e6218710dfe11bd1b7642734e74f887949edf9ff9618704890e64c8b209760169aff46f12c2f2a3005354b07458b11f8b056456cba25dc7624d21202492bd02f8618701f80c9f31c05fea5024d8fa86092132190a81a95430150ce6442c4644042c46040c168bc58866cff4f161bee66bf6cc9ee94382588c04b1582c16232a8a3f1c1dfd7074747474e4841342423020828480080a12121282d1c8c21e64d147380d2bb18ae499a71b1d9185bcb4c7441c8b5dfe6c0719acf91a08e6c048aa0d43f358819ef759e589c26ab97ca2e2fe7085fc0383e3308fa798878747c7fd2011acc2057893c30aeb8d05ccf1a72ebfc9e0150c7dc6e5da8571f8c753fc5fbc68302ef30f7c860c1fbe0b30f48aa580f9791ec7e92e9ce2fff2f2e23283d1478c040f3716f6840b5d1a97a0782e95de028cc383533e4930e5a5f85872727a70dc8d1bb38b5d2d793958ff0a7370a4627c203de3ece84f44487b106601c681bc00ff0ac09cfafe4288c01cfa3a7a4e3dd81c6cb80e71701d76711d6e61a4be9442aab8fc5dbe7841afb7839552ce0018b9bbfb8cd0af0c2929ba1e638c100a711462aee53f1e975f72ace521165aae138137aec4921e5271f9610e2bdc9df4a598821bbf95c1ed0032c40ec528da0de98f620652ee11bf2c7425c742377a6e3a23eb8fb7c714bb1561bfd33de9d0713a7556ca4a9991d8f5181bd7304f716371998ccb5d8825066f82b01fbf7e18fa53e995771a076b0e2d2a3f00922abc710a13c269a114cce9bf2de4b57af7412d2bc01b1e2978e35f04c2bc63310d6b210fd88fc57091a7382fa2439c82905318bf1c47b3027320dc54f02c29b81fa96156ac0b7910094aacf69f074df9fc6c14c60e1456eaf882f6dbebdce66ad848903be297d4d12136611a7d3a3f973e10af2c4fad006f1e007398993f1d5e701897e378109ce237e2f27fe0e54bf45c061ae232ec1c0878c36cc445edf1736f69af612dd41e0bc1b296d992f90f29e9b9255c38e4e2223e81f1697461dfe1e80406cb2fb75f5a8138de2381608e9fa8b05a7aa2e02f6e7ff7491e48ba39acb09fe4e1a3eee3239b22acf652bea41230a7077eb204e3c42b724a913422881e3d7272b0608142425cb4026ffadbc60656ebbac753ddc7471f1f31fdf8a8a7b41498c3b77f0acc911fc59525ea9135e2587fc00a2bb18039ec400ee49e05c4e198a7bac01c3278256d60af9fbf00c3d600c65a0c28c6fd244f7c6d6113c6fa7ff1d5536e7f2b71fbddcaed871dc5ed97026ffa59c7e9f5f21ec7e1d3c95a20efb9fdfe5eab00eae2405dc447314648828b0b510eb86cb1437784602284103a10ccf1dbef2a74ec301ce84b9017420e06cc5d70db085f89451fb5113f0c1a92cc2104c9978c22a5c015b85e924acbe83dbdfadac8e705a5e32b1ee1ee6e0473fc7ae740bd82432e286ef3f09c58fede88e8b4ac10e8edfea987ffc12022ce0981c13ea24aa8d2730b25c4f4a817608b5bda772a4fc5a0d3d2def4a6105876d5105f3c35521eedb3f8f254bb1598ead771bfa8e3be5e2f2a4e5a6e33904701c446311bf76b1bf7e3587c398eecc2a9fe2faf973c0a81fc7120c791120798ea8f010101ddbee109ec2416eee33d3d502416fd9c141b7bda7b491ef85f7cddfe1d57348d1b5cd7da23e753596b8139fc47b55adb2ae0f682f94b972aa2f40d7c62ab8053fd55b8badcee2f5f17f940c5e5aeb570522c0f30ecc7e3760e2b2cb30ffbf81cb90073e0490b84285c3efa4eb8fc2a98139f2f1fd56a2d842f70b5cb49f7f4115e7ca8dc6ea227eea76d3f63aab85fbf88c2dcafa3dc9612217339620c13375a611fe77161adfd2978038d4ab287d807d224d293866c5f8a2a8d93ad1257a96537a158f0db7d44ee89eb56737c4b08b2b0055bf2493f4b2f896410cc31823935ee7c1cfea6879b02a0972212d2679a6d6fd69f25ceb600e6d43103db60eea44d29938c4a1065c22dccf3296fe9d57cc19d3f2b732fec78d11a87f4f3331247d3a9796a6fce2a6cc72984eac17e304848af3e29f4f3e7afd0027d219803ef9c3fbf005b9011ac98324c189803e76b5b6c6772eb1a7ad3021b0b3301f1d2799a949efae773d78ecea799d2285381d7b4f6cde0b0fd32acc7838aed875cce287a6666afa78cbf7a9573c9b22a299d916671c628e3fb09c2e95d9452ca8e177a476eca3d92795e2d65f7757b0d10a77e4bf91e83a7e0e954ebec38f392cdfa31384ee9e1d7005ddc035780156663b012b154a78737b8fd5eaf50844d28027af2bd153cf740165c8416cf4aa0277f85a7cfa48ceb31c91807404f16a1af64ccfb34d50e0678239f4a22ae0b81299922f2b90e04a6220cb260815c7f8f05cbb5be1149074434ba740f0117642041c4151be0608a211d4a80840f539668e2ca0caaa1633411a3c89c46e02c2480b8bb3bbdbe0212410500e2579e20b5149a25463a4389db0f8408049a9238a34b075280d819438861e7855ccee8c94070060e672c69d2a73fd10829c3fd8510810d113261ee66e4e0fac7f61a2691bad7b0ccd082644691193033b204f634a32568d68053f82afdaf54fa4fcbfe33691e6c9b698b5cb7ba99eab699344dd3364dd3b62ccb322dcb32ad542ac5772f6532524ab517b00f150b0a696992fd49fb19afda93a72568cea04e2aa564a65272e44a2b2d554a4b31c618238d4292085653ad3d9dbebfda138d4a08468411d21fa91a4766aeb4c4b596b23967adb4c639e79ca54a6b9c71964ab546a694d219e9cfca5752e1e3b24edacf7834aa1a968db5efa982b4501840229b156c8fc572d6c7fa1a161572fdb827ed673c9a1ab6898c63594639e57c2999657d5959da6a4f42efa9583746596bf745494b924a4a4b52b694f2e57c39492492c32be47a92f17f304bb5f6747aeb59b68c633dc535fa67ae7136b93effe418a1b7cbb78e53abb5a7d33f847d96c5fa71e7d7973ee41448b5966aac92ca5afa5a6b8d55525a4ba54aead81921fd917ad908e9e3fb76806ccc98fb2171b96eec48921b7aac513ed78a253305213dc618a3bf2e8c4117c64ec6a8e349bafb8bacf6eac6c9460d9cf9528230f3810734ac8c69d3b212a9d229a33733fb66448c2e79da83efda0b3208536828256cd90d3b85be31c61863945d8c313a0d2e846c027c18142f8a7dcf657f04924f1c07b8a23ced79691cfaea18d5c1c9a5403f62a484e1437b82a27822e57e5bcff6d28874d8a05c9e5e6d4f209018293d9d29e807fa721c0d4ca7fac3f484715bcced6de7f6e6a4f4d2884a2fee2452fe6b0a65b55738a84ced158eeb36668d9b51cd39102ee5244cc5b8b150effc8c568da439e7c1a571b34cd33493464d9a73dbcd6434e7b49bdd8c86f681463fd0663410341bf16627ed8646730385c3e45d8437f167e731c8384915d401a08d3f12af8dd7b99f07df1d8a851a335fe375aaa058d8baa97d243d8c98617e2c7d2cbdec20e7daf14b7ebe5819861258549902045a6046ad1d5c735af5588aa5d873ebdc82c8cecea0a6ec1d463114699c9dba448ccb7fa406c7d9f16068a704979f77802e0186988471997ba6e4ff1d2f85ec7cb7a3b3698f3d1c6c4b6e6326a8cd22d42bbac5b4712c1fedb5200448018076bc4e4bfeeff821ff3b3a2455fc91ecf8efea1024ff9c0d1b9f75bb7a2381fdba45840347108e201c413fa7d37f95bb8ba20f9c0211d785f0df09078eef381ccf71389eb405e9dbae5ee968278d53f3dc7f15a7fb1b5fc375085cbb8c3a857a4671fe05e9502bcc8efb66b8d252c961e087c607e2cf3d3fea4bff5c733a85606d8eed9f6397a7681e88dba0e1501c0ece48bcc17d0de5f29fb8af8fe88e7d523b6016c3cf001b10b6d03fdd6769842cc3186a941e840e45fa7a49cf5fa4571f3c1f997766fb0f3ad45744753db8f669742899af57c6dde572b97c58ccfd184ac3a12c98b032a61f4a50362d83818b0eb76380c1012af8e1b20424d2d13946907da5edb79fe995f6f0d2876dea96981e894ecbf459c79f5a4703e9bfccf4f5a3c9f44c745aa68e89fd2feb6820fd9ce17249c8bc95e970306ddbb66ddbb66d2693c96432994c9fc4b46ddbb66ddb165f6e2693c9643299b66ddba22cf50c8369734b96d435467267dabb7183e5ff54dccdb407add7633f55dd82b094359769664894d247f9cff727912825a9be8646a3fca8f8fef1274f29e59491d9c6534db1fc38d89af698344353733bf3925966394b2f29a594524a49b5d494524a29a5a49e73ce39e7ece94d29a594525a996c07b091524aa594df84d592cf0489ff69cef94d58add92561a2d3921d13f9b49b734ec99259f24b4e026352cc60720598169c51a585a40abfe524b54b5eb2f82eb98f24a409b7b2cf90dcef48bc3294b447a2d3d260a9a3a1fe079f027e93b080f6f48174b7044992312ded99e8b4b48ec9f659d7d1505ffeb433dc9984f61b97845d413e2f9e1d1b94b496c0312d9e1b2dadc341cbb22ccbb22ccb344dd3344dfb26ac96f649b42ecbb2ec4f3ed84cd3344dd3b42ccbb27e773ffd1c22838ec3443b74016a411e8268c187354e3ec81ae3a203242e3850633d508932a6ab104363215183e285434b74200905cd1d9c8b1ca21439987121260b87a12539dcef54e3fa85434b9a482d58043f4ef8c31a8e45cf8889c2f44e969793db43368471bf9aebc1fdba5b5f477ff5ea83625c52f8c7092de3f6f395d7c7475032ee57d3b026dd28c4f8b9fdbc83a45728db5edb184cf5438e712c167322129470cc06c6798195f01610e704268239fe1ec7bc9c9c1e1c77e386ec5ce854ccb156f3c09c293007d60a3dd50b42b9c58b08deb48a042596babffc386f1cc21f32c8cb35a716404829a5ec5841a01c796aaa24cfd095f26724e501c853f0caaf4f7aaa34aa69c1cbd48cfd832b709cc032bf9d61752a1f3b08c32506366a293589a2d6c04628e60eb692601e218229b65ec8254c12f7abaf30428009f3c3fdaae34404bc8a623cf1b8904b982c5e512e0c56a3b5b6c6292a6d02053243af0c5c7e66e6e18a8b02a545314a1e90d861c8f295226c50a4412976a872dd8bebdf168c134250a10110508061d4aa528b1a6b904f9dc2ca46796460270514c0b41b573088abc0891841bab27ccda0b21400c09eb838b1c5317e9a0e5e6eb71325ae8d3a57a8b0811533e892832e6010e30d30308a220c1035c8402b4ae1a65295c05ef20596a55cbe3ca403161cb76f2d4d11344f4f038124620004151bbc5060850b3620c490155fb8b0f8a2e5b3055a75d12eb6a059ba28a2932705d4bb708887089e1faac820cc8931c648ca4a5b0cd0a8d63a54bd162650bd5a6b1de386a8031dae3fc31630b37eb450bfafb859ea16d8021d10509200ae3c808cc9470b1b37a3790d03ae97b422d79f3d19914458edca4303be0cc1e08a2cb400c10c7490b8c2c91721c8a18b218eb832b334d1458a8e914ef4b049b14419590ad985433c4e4a57c84a659c31ce0fc8297aa031c6219e1b6e8c3fd3ab223593499c205c38740318376c518266661abc2f6c752a39ef0b5b3bcf53fc3870a79d40b9dc512ef343619f1dd80d9e78395173f56373e517c048caa0af66677b3539ba9faac909eef7e34a39e1195742085f8578e146e3051ba8b407650d2b563eac91cec318310a1fc154dc5dc89b5d06590d86357c2c3f842fc09657fa3a9c849b6340742af56049170e35698289a5170e3511418cda85434d3a703f15515402dea0ca17452f1db89268c2004ab09ca0035b7cc8125445b3e20135c3889985045224ab9a1471fb6313236e7f6d92814be3c2212662a4bcadedf5c7244add5744bbf32b259de4ac4f9a098825f95fed24f4fc6b4fd919217995df53caaf11def805ae7c08bfe8041b989da5d43498c327d81057809d73101bf0a6ff0425f6f36edb606863099f52c6f625648ef4016fa6ab1c764ab6775143d5b6b2bb6b47d9d1cc5865fd4f4a39254b035afdfaf43ff8f0366569c07a51ca0f04cda6a90e64083dc4602c3b1f484b2965f7b953a72592fc3ec6e891c8959f04932edfb6ccec92898c5af4c844ab9fcee5cb1f716845d2d56cd466da8b524a496ad91af58ff25457b53dabc5b6b56a362341afcebab5a01324b260247645bc2ce6ac7476d9e4aa26e7d3f93e5f06ef2cf5195bf071630ede530f58d91dedaae4b4aebf229e663d87ac5a2d4e49e5894e2b63ec8a68d79f708eaba0c11bf827ec58af32de2235d75f90d5ee29bbfbaf75b6cfaf7677ad1ee3fcfc639c9dbbb78ced710c464edfbb4f4a2244728518bd7d68f76ef70ac0ae87e0823f4de650b1833fb714d434c898dd653c85615965e3b998ac8bb0b13ed378c10630dccc094938c7b73dd35e4b97fc69f9bee57286b08c829175fe0884c3ee88bcf2ad3f8d14d29eed15853bdcbfbff0a344c922aa0bdb8b31b248dd9c13beec424acf53313aa4420521346251f2f9721748732ed860ce39679c73ce7903c990a103b0b045682ef3176f119a8b033a6577445e8eed822cbabb17eb2ee4ee63084991b9bbbbbbbbbbb7cbdd05df239412860f9897179e8ef43359760f0dc3478c1417ec28fc4fce272ad89a38b4026ed1c2059714f8bb43f992ab79e803762a3873a3e4663a0561f70fe1373441c9f50373a2cb792e2c037aae04aef80842082184902b4f7551585502bd7e08a1bb8cb2f8713e579afe7e14d42a141bbf0aff4b72658cf0398c16a5fc60b9cf0c901f34fe81d31434b0ef2ede0d5436d41ec2878dca9dd8d4784735118c5d0242c8f2a1b2f16a9ee63463356f08cbef3e48950fa15ac40fb63eaa0fa54cdba8c94429d5d204918dea673c1a558d2744f48477d27ec6a379980f93966a966959a645aeb50a1951cab4cd2443a5ad965a6aa9b532323232323232d46432994c26d3b66ddbb66d54d3342d324552c5fa0113e24264634fa77fef6b5844148a59cab4cdc432325646c646ae3255c65619196b32994c3226934946c66ddb64a4940ac9b0d5004b55c3b2511915c91dd2ef34b1a5df69f2ad253e664cab4af64d54ad2a3446d6b8568d526d524a6b8d7552aa6559ac91d2f91e638d7466b1465aa2344e4a4b94c64967294e4ae79c73d239e7a4744e4ad2015653ad3d9dfe44a38241a1a9d69e66c4e0f73c958d161a065673bd93f6331e8d559d5e457590f6e4094d23231fa77fcf5379364274074436aa1ad67b2c22258268aa0d9ccba8640dd934357568460000080043150000200c0c074402a140249205d2aefb14000f758e44725e3c9586a21c866110c518638c21c010600031c01043886ac60601222888c38903ee1cfbf2aec6c22181a7c6b8895c8ec5a2bd5218a73d02b5d7039c78ed5ea5dbccd46d8c12730d1ef01dde522cb6cfb7b4d3c7668e474735d1a1245940384448f97410f9f74ec2efdeb8d9dbb88a6ef659c8aff1862c2c945fb98b9a479d7ff19d1b87f29ad7eedb88405bf59d4a0ff4e8a5c6fd9757e6983e648509f1154020f3e0a311c24dd7e899c8013830e0b34e80039a2f3b78d0635726c2183abbe21288a1e540d7f0afc8569ca6a32a48a772cd9151a1e53106b90ba989ee9ca7939958b467ea7f45ee3f78ad0511a23e424edf0e29182a70d0ae20fe306112e344286cf322b2780d0270db4857871b0f348b26cd2eb41b93488c70d6e180150ad7d5d72697516691286d83d6103135e36453cf3ac68c329aac23e90c0788ccb21ed02c8be6502b23a17f4888c6645c9b30f80c104ac4b4844de31845182e5bddbd6c891237bcccc372b137b52da161dc3559cb2092f43a4e2f0345821b0598701d81597046a8ada3ef622141dd47a875c267e5368e68350ce999ba48e16181ebd3edf72052fe0a92cac67d48ae62440e45a9ccf110bcd00a3433a8a291aaf4f9564fd437e4576dc058e3fa07ce2099b861e21cc2f09593a09a2ef15ee3cbd48d060c1c448214b11dff54ddf64d4b18e6e77aeb66b28b3625619b2bb5a002500ec795ec0c77ed19bbdfa212acbdc273315ba2b6db2e727d93d6fb5bcba081e0b72a3b8061320a526a0959d90fa461c24e0cc840233ee6a3657afb1c8b38bfed19656401ac7fbe0d27230a35a6db100f7b3153769928bc5f6dfaa304bfdb8dc4691fa82d6ec127e33650dbf245d7ab38fe9d16b024613c02b5790ff9b6ffebd234e550e18031d8793741c8102259b5606f07f817f19ebd9409ed971f0b75435b3c3d9f3dc29e0c214be44d87fb8d3819e326a765085805e2c6295ff5bc1811128e025f079345f5110d2d30d399e3222680dc31d7d428a04a324b5f6b835b6a69f9a41fa67309ac0de9474ad1b2a92facb8ca9e6cd8cb0766bf5dc91386e260b3692cf9e2d6e80d652ad4024f95965315cbe760bf2f043c30b4d8001fd19a2008815c051c3a345f62a390fce77e165bb13d00465487ae955aa427afcf87b543776ea0a52e88c5913a6090d41dcd785c2ba9abf599cd7896da001de1ec23caf9239414492c0e3e1decd80191a2e22ef3d6bb51a641a3346849a243ac79c0b1cc72ef4092e86a0e28d77ea33563e2d7a392daa3d4e14ea11e8534c8fb3ccc25ba12ae95da887c300ca0e0076d471bd78660c0f8604aef3e7cedcd735f3b285e912363714e2b4f643b215d09086e0d66f8497bb8b5b93e3a4c406a0c4cc7ba301db53bc6106686309dba555895e623d5fb68ed9f3797829061b63ac46940d31dc4e8f46d484601724b39099a1e5cdd447a7373bb27a8a6033f84f58600c3472a768683b73a09490aa14fd9e0cef50eb57f85b372adae93abab6166bf6e58f4f1b388f81d93acfd3e8cf51711b4ef32052812c9ec8774762e2d2fc107cf4ef22e9468d7123b74f27e18928512a9987dc07d4b3b0e7d98a50d73a54c8284ea5a7b775433495ca451d66a23d75a44b0a27694311cfdc869ad4f529c1f8979031797164e4924007dc3ad024a14e831c3375801ad6628cc94c54024a27a3f64510110ac4b5bbac474cf3c8962e58ec262572fe923c52206834c5c7424d1dcbfb18657bd076d8c252dbdf255f89f6ce6e48858c85c902adeeb5dd74c7d9f93f5d2671c1242aff45dae54ef3057a3de009256ff044aa52de747013f5b83863091c9033838c7428ab1f8d63733d85df56072dd769615972ca604820f0128ff30597857673e6011102b3fab6d7936f6b5d8a54d119611e98c1320ea8a46c47d641a1348957d2462e8708181df58078e8a71d623ee5ed25a7c0868f81ff042c8e4bd93d164d3ff881bec1cc08b43e695c3e548b5eadf34443cf8618a1374740e6251a9a92c3ab58740e3aa035382f3a5ac97280d0e0a23a813a59d1b1933d0f3cd36589404ae2993bb2cbbde7d1f85ae453d8e427dfcd5939f079a12a6e48f32b57b5d87865a53a9b22b483822d99ab1112c8a614af630f0b47a8f0a7d27fe4840e91517bbf50b806212665ae73d871319b4148549c551d652c45261cb9559bb91e864fa6f68e91fdc13f2a6762a640de58a2a259d49954ef2284754aff6e07aaabd1282d764a9e4971124e202389531b1a9e336b731b840e0cc60394d5dd412e5a553a67e51ebd96266b428c2432a640a2ce91456203c3648bb97f862080eff3ae409e0f187801175bdc8773b21344175a68e18cb4bac38ffe8b5584b661e7c8c3da5a39c6d2159fdd18bf7e2d42c64a6e0cf1d669ba088e12c05bea4ca6bd9a63a66c4ae08b1ea3f1ea53e9973eef0673733514863f755e5b29b97579d5d0ef6f331515a813e8ab64d0f6533c83aecd58e5c24727ad923a690e0777e5220f13f19fdb3b7499a5f3b49d0d9928d232c18172aa7695736a0a1b347a7c9063aeed18bc176c454eecc22c237b91a10d147e6def467475a5a338b1c3c515033ec355de605e6edc9063b65fc2b2dfa8383c9b482095fb7eca4af9d1c8be43ee3b1182526bd1f6e3573bff996bb7eb1fc1850cd0b9294f1a439ab4f132da6917c5cd20cffeea489c1e33bf84d6f7bb2fb979ff90152d1d5444797d3048825cba5c723ec0e6ad12038fff499da757a6786a8ee34ff454e4806b87cec47862f6b2c924c731160f3829324d59d1400a54f3d1e6b0a05900840480fbbec28c13135b054d95bf0c261bac8b7589c4b54ea0a39630950455035641bd3b521601ab23de41c7eb78fc0d808a9a47f788d90b280822291c1c2712408e09e02166086050691486b04f0811a20881d397e64729098342d9306aa000b15f6cdf34cf02225a1a10194886836e060beccb8273648ee30011cda6a89b04fcd4b11e97d25beeecebe62540d3b581895a5c30929189608c9b262bf53712821cc60f622f9d388cdd06d8556ad88ecadbeab51b404e4198ede650bdf93b5f28c7d5315fa158dc432561296fd811eac3726f4aff8ab2ad548bbfe73563cec60996aed43aa0890fe0a671383f1b20d96930e841f10514c229d8831e6930f664b56aab3af9159d0bdeaf4efefd3f639291010a7bad8c59a208cd2686336b28faaa1ccc870af6b40741ae2723b8a0a719e146964e725808f4849f71a690032c1bc17db55d804714538a52bbf2fde3f98bb9c42c34a872ba253a77b5c666d0ba12ed54b33154efbca5755ccf0acf74568576d103c437740ad60f3132a12a2d927004dd8314342ca4d79263dda5c5db416fce27f63a28db1e9fb3f6c80184d1f0a8c32acdb2937c3c286b5e096ed0ffbc0d39aa984839f4749be3fafc10e3f64ba01c046a4943711d4b18c2aecc72384435b98a9145d45fc34bbeeb059d095cc5eb9cb2d40f4212775d1aa3b802249f88609bf0cec4e4ad5dec16385bc0316fa734ddf49d5e25cd259046bc44b6fb58f97e0cf478f3afeaff58a8886beedf96300bdb78b6cf30f42b176dbcd8ea12c13c1c2dacdb96a9f728b46a78d0286edc274ba2f46200e7c917922d5cd8214b96e03c4e0035c5e009504fb96442ade137389330f703120684be7181bd9580be44c35aa2100489e85c41460307943a83f577c433748a30d103c514b07e1a53fb4dbeec0fee3988022938ba075d97a4630ba30b7b7a09160dd365cf615734fa8f188ace8876a2e4a6407eba12b46f3ef7a028a6c65950832e83b88836cfbd416f27f525f65149abee0c1449ea516ebd24ede1d18550b14078e67e2dd3e4a14d41d35b7d7e795cf77879fb65d0cee896dd00eef27b6db3d313a8f247b5576db3d26850b00bca4c3f6e290dd6eea31af169a689c71d97e7afc113b682e901768540c2bd6640509d105726636e732cce19da63bb8100077426a303330526b1199a34a006ee0fc163595e72a7866fca5ae4e9b182e48e6795a9c291c278ca526f8782f65122c74d675b0826c0a84b4c89714bed3e99800ee90de515b1b06fbd07ddcbaf80883cf26914a89dbe2dbba15ea928b6c136b8c91a75e6adad3d533528b14051176ef9d7fd10af0bcfb0c14e6aaa975138e05c8e6390309ebb101a314db74cc76445842e280acceb964b336a71ebd80ce03d9940391f66bb6a37a2328cf116e909f52b8013b5d0c9200b523de46b5cf64e66d1437cbd8dcaf5c23296318f6870b09d05e730c7b6eabb1a692c5741d456510d695c4c42fcbb7d26315ac7610b0aa21e002f002a9007e9379759e919ef47a80dc27b6bfd3bdf30f1a50f5a128e696675da034460302bf281dc2fbb488fdc6da482dfa02941ac6535561200bff540167488035a5f5d4eeebe7a5ffdda12803e709e68bab95109f8d96a237533844eb84e34974c127e1c387bddaae4177370646f29d0a25de696a8c94d7b5892fd118b34b411c57da3137db07e4136a0120159917968ed7e113115e35eb47dd2ff90a977bff5299f72354245ce5c1084a75479ce9a2b23ef8ebc283e004ce39fdf50bc284f95e60a6f23a2679d278cfcb0c7fbc006a7d7bbcea5ebf245df9b3d7cf34562d9ab7b24ca1a5606c0fcab03d3180c46016a5d1015ea1be0573d26d4cc2fe7e9e8504042d26f55d48dc463db4d186f8e8e7323d26a439a5ddae62a6a9da381af0a7c8f3061a35d53ee285d0821c4e7eee9eb81cd225412f9a202a284ef834d00bf168bb6bffbda5ef57204b64b8ee07fca4cd8c39f2958371f454c46485e945d9f4169d2b1d8e71a12e959b87d51d1c8d1c6c21a9ad41d9f91c580a9b999a1569dcd271feb2f306623d3fe42a0dc28d0e5012d73e3b1cdc93154a18f18fdf6735d0a6337fec2ec3ea40284d77ec40e64fc29e04c2b3ef7a7ad6656e90ddcc97329ba64a328e191247faa7c121522e9bb08d850c869d51a299f465b002ff42cc1580db3a7fe094e55afe8a8e2a9a1b29cde5a4b24ce914f807e6a2390f5d3c204a4d02f0282d4d282df4dc41f5efc4c6421432fd2a342ae11c433ccf772e5c8af91f0786a8ab3c93466818ed614f241616730a9a1ea58c1db353a80b7ec0f0d1c4042a43b302a882f50bc5b70249a946fdeca14cb38d6951a9f12e31801e99e2d3cfc8606474f625fdd756814a23c9ff78b474095fa1595e3a8e636683f447b1f17ebdff08602d1c465c0fb2a2beffd77de144ad4e21feb131a880dd523add2d7ded90b6340606f564bd9ec25031e6796e17f895ee2bd2fab52a3bd1accfa898a8bbe3d56188138c7cfe45750c1e6614d936bcbd89f8988e695c0c0e55a690a83569f591dacf81fa636286be2ca54b4adf10a0dad4d8e3e243b2d1d8c603fab87acb859091cab49a8248e1fdbaac0f8ac50f52c5d706f41459a1c9444528270125121d02310060cfe13c701eb44d307bc7d0bfcab99cbff24a22f17dcd10ec3e9b4731d37e36bbff900c50e06090ea05bcc3f3a0c092319dd5c3fc9b4310ca6298ad1ede20833d6391dcf29346167d4e9e7c7ab731a68a1934b2429f3a8f1db29a030c7fcf570c9042851b57f287d9e1db51cc0b54cd84534b60955066ea3c7ea616a6aa706af533fca053124dd356fb77ead4685302b36d787adc33ba62bd31ef2eb5a218be167223e3e7a3fa8b0b70fb3aac5276b833d7544c33e9d59c778962d46e83cca61773de4545b38df994bed7358c2ef866141dce97224c84a31863c07ad63307197c000cb6d82619dc31345ed4b376af5762f1817b8bb524927848d0d93252449c6a889416baa7f659dafcb162543e656b555f48b5454f30558206543aa1c9c55fbaa0f9d90d6c5dab10e9470570e356cd2e3f9ef4818b99bfe71cc9137dc5cf43a997d9081d3c8d38b6ecf4b6a5a48d10e8403654c33b67d0ee1686133b511f395212dbb873249459d73c67a646c3b7444a77134ab34111b7028717949a49a9750f24c686591ee87f7774ef0471ec43ba662d2d31fdd2a4ab154c625f43541ebc282606bd9dc2afe51f61573441bd49ddd9641da30bf40f38014f671874de837c45d62ecc39bcab05874ade4a176d16fb5ea196030d9653ccf121af3a5fe55aa5db8fb4bab6602b51c9cd8081071a78403c9c603d8eb3b95ddb603adc6e6cea20104d1d9e0b7f2d985bb25f6d4765893a8d7e45b4f6d24e8413413b9c8dbec2bce8364d6a646d56824062db0a7febf8266a7a3d84b0b147454fb6ba43a549059e0a63268012db06a126df51b28ac07b63848f3b80498b22aec2ea874cb36a63a6e1df3ed3b6650dbf6ef8589e456b9541fec6b9899c31622970302f25457159d170df57fdc0424322d3a4a2068bc246bd6957be05a96cd3943cdbb64dc165b413445630826edadc583b62690c040969e882dee792f8653b11afa0cd989aa70979b5b049be7eb3c5b53cba23bb5de4605ad4e16bc0934c66ba9025dcf310d02bd6f2a5ceee40badc2afcdef04c71700463a3b4447eed09005d3ad27ba1a70f9fb8f734a3f794ef1e826dc96185d2913f244847172b5c6928df9132c64f7bbb8fe42f021c48b04af9605a9f3eef4a210a5ce52583be62a58d4fab9f934de0144614445fb48901e6358da5257a937adac42e541ab7cb41c198606380767f10dc08fc4768f6a1b81163f1a83baafff661def6d5e85ab48d13d9d629b9781d297f69824067bf09f46bc5d542deebc89433147531eefd0d9e6eb3ca376b136f9df9dd732d98078a0fff7ac4e48e1e49bd9c2b649bd545dbbf72d03f95b33d7bf3c3d36ca1fa826e116adcb45e81ee9624513e88946853239b9c0fbd52bafbd3de130e1ac10ff527e501580cb1492c89fd660bf0d33cc9d295158fea75790dd3f89d849a402a7d238c018ac1064a7c901d4e50613f5dd1da15753d28f8147edb13bc1457c50ee296a063c064ca5541107e22b61f04b25dc418192a3e0467c9c61be9abdcb9b9ffd502f22e7bdb79fa947830ddb21d194e643737e9bb5f4226a3ac855ca17bf802912573ba51c6e2a63de74bc924965dc0b5a37bf6093f35ad94bb4e947bcfcc22424526608b047e7f112bc66b0fe64a6f6df6fe1a4f7fe0c3be1fca4de0d16665891652a40b6b92d16b5f0e88511d4b4c9cc898c45ad7e842d9dd21495fb931ff084069c05e046d91dbd6f9f59d558ca3ad9979a25b574b40d6296adcea94652d36a09b440b7f6c93ce3282baad3af3c4ce9dd03484070b4f13c46d1d56163e559a5b46417c21d6def9ba17c5cb36ac5f8855e0d8d6c3510b94865831564eb8814ba1ec46f7e3b02676dae4fd913d2c5ee10e17a1ea1f75cdacbcd7f08543e8733a077e20805127f6e266b3eaaa1ddb4d14054f4beae5445062fe69e1b260c0eb43b42b821d247d406835a5488d14a4d60659ee00dd0ba468322a13d664262792162bc5a169658a50896e1b86ea804d6daf54a7d2a14a51e7b308f4efd74bd5914891b446e3944230a821dfe55cc307366f8780c49d8e12a12633baa561a8101b10728ae10dac4d17f586a67be9b984854d83a5866aa6b8ab95b5bf9f35db8a183b1a7be53f10d0bdd9de1cbaa55c89733db6fa5aa5b007e50b1ba6812e457be23c5ead7f51cbfaf702f20bbcf6b9701740c764c5e7b9a9feb5143e2b4683fe6137243d33c2bec8a078a53949d1aac97447b5119806b40bbb37eb16ad943ef230a3022c6469501efad94264b6efdddfd1e07a6913f403479b2ceed91fae61e55fcf46e018f248af36de4cf268997b1dc61bf0815d04cd06dd6e7afe42b69843f4db546f7f021faca60461755b7acf0510a1cd920f634d10e4f763abf5ecb8fd1d41945079b0e865806e1ab0ab18b66af39499e3243b844e31e912aadb4a8a589c2d5cee76812553bd5e96392c7422db72f96092063ece5b00563fa43ac3c3a18f35a95b5dd507a35cac9d670a6947fa84c37481d301729bc74a58a97d7b208b09dabf279606c270c1a70090b195eb0692c08a7f5d53c4a2a369be7914751eeed04cab897ed9755d0547e1765d95184ac5297438820f4ce92a4719797e058de1be0b4443255796e389fe0150154920a3e3707954689343fa032072def4f36b8946b06ad1db10910fb125c192307f0d97db7de4ac5a6cf181ca5b960ec0d3553dc731273f9d5634adbe043eea986485906a196f1a35c0e2b45e209fe817d3217408e9fbd15085811f5ec2191c134b99aadaaf7a6fff388d891f12b5050b943afa2ba1616ec81c24f6610df855cb7aef574eb0276c9848ed44788e7d5ea2ee81dcf170ea64b2b79ef6ab8918a7de6ce00ddd2262ae3b4a91038dae677570f1b077029967512b656202f7c45701ec34f5c56086d9bc289a0f66375317561a4607606e2402fed36a6095747a8d2c67ad19f2d7665db90a15bcf9b4bf239691abd254665ac539f7333ce552c767001537816be7095d1b9fa5d673c1f38981f39fcb8af9b4506b9a0406bc093560fcb0f237782fc316880e8771c43d3de71fbf7490149b59ba7057480f4f88c4d6c1e33e2d060aedf9b6a766e4e452051b0bbdb55b49dee94e3149fa65599e0967f4ba4ec021e8ff2d545715d414d45297f0fdbc155054d76a968bdcc3633c9eaecc00d4fbd41f70ce7ae1bc5bea4c29a3206c07875bf26079e3bb8585da2f57698ad7a568757d6120f656be6adfbe3df54d88fa118483e308058fb8966f1c2931f6c65da2925075b8921806920d984e123618c12f0e1d6a58d3c3ffd30de863eff8cebe1880efc26c90887c14e307b602beb5fdb15db5cdf2bd823536533b488270953c0bb4aeae543a41f1a72388934485ec0ed8c9227f05160ad1509f1cee4b6000110b5b2153b08378cf2386d05c78e499a46e6e210933b340c2c50139c25b0acbd6a21d4a8a0bb308282f0747664c7e61fe49e21e8f5527bc804e1c4304f9b1c3d4a278834b88e0ffc3476d4add4f968ca1dddbc99ad90acbeadc38c90f21d94aa276a7058136b0c544a2196f7ac201141ff6250b15665d677d0891aeedbc0b0b95c1a95aefcc2bbfe70b776f5851f08eccc155b9766e2f5b55c5240e733f5fafc2346757055a589523b0084e0da0ef31a8bb0b26854dd5140c48e405954f4861a9d03eb69a81206c509e9aabb9efab418535a54dfa497c640b4ddce5e60184af7f8c7cc517c71bbf4585157faf81336aaee6bacd927e6d9566749ab95555e566150b8604ff54a4fe855062a06c5ac1e66d764db4578330ad3220e1961896adcb97232dd5902f8a49f55b07131884981f19a0b60964cf58cf9700bb962590c6d28632b0b6ec1e94a9eef7918663948d360c8f6b3fdb4265db8741b62c43fa3a6d965d9e191a543f399f2e2131a55ab5241089d9d9d08f391641db21ae2510cdd51308b3e9328362e988e442c9dda6c9b5c727ceb15b5e089617d5e607f11f5df56d82d53733472c1903b309451d56bdd8c878d1ae2035dc4503a5e505e594094cc2a8441fa7a0e6d247ec1974bb027d6000f8214c5c735df400f8695930a014e34364aa15a644f26822fc49f7284ab991f8f6c10fad2f03edf32f34f44f1a80aec3431834f97de1664f7002dcfe2a6ba8f340402977970a5c95ff6247c8536aea08604fc44e4083ca02a37a93caa12092c0f58120a681e5a110d381c581129581e540131781f550129340fa90c0c4e406913bf318e97b02458a7ca1469c3ffd73cfb4f8da78f34a36a1ba2f42e485588794906354081b1c445883db2b516bc47de25f9e31dd991d2bc33ba96cfd170bfc577fa71b942ef713ef33835b7efe28284e783e11e0c7032a794db322cc1fd54cf247ca3facd8f5fa491f3558bf83e8a80472968ed0559e073874b0d767990cc3dba1818d445fdf77e90c3f2fc02448f818dd7c6c854262640ec4189007ac9be21baf0e561fed65e031350e8ae739d0dc741e5630efaa199df9c77c4dd7c5c2a2500bcb995f90aa71d68f9a470eeee04caf49d009bb512dc9b178219b72b5ab44ef5af8df73a52dcfd2ad0d92fef3a11d7054aaeccd5d739f682a045aa284abe391bf715ce7f374d47241b243a4ed80fb7940bb22a1c9b6302cc599464aba0c52af09c7fb5b46ee43f3b52e730b16848082c1133b5cd85bdcb8812623fdd76ecc716c429cf4d71b0b9b468b59921a5a8050bf985163a4fa5ca8c64372912df4aac627fb43b6350703682d661d887acd98f9f90c06bf775ef3d4eed2030fb0f075d3a77b41560f14c86c829c9d39541c79299de3b6d304c8ce62f68dd0b3362bad5bbafcd60dfd5a75df177ea0dcf3f05c170712e5925db701e0b799a6e7edcf97e089f45e2ff30823c7b01fd6a5253d18ea02b0fec91a8e99d6d2d9ca8c003e9356da2672f629209655a189e7d66f83969b85cece700cd94cda337f56045beab29fcd35a7316cabf4c59339eb6543dbfb2d8c990103e1a4d4ac66e8dc7df3224425da0d1d61c2a143580e1db324264271b8615ff1729f1e9b72bea3f4b30c8c6e1dd482e2fbbe1a54cf3fbbd39ae64d821ba35c083445685b8adfdbbc20a16de3b58299bef521932ea988b02da1cc4ed60f789eac7a0576ee500129ffaf88d09de5a64b7f39721948f0a4e0f5323b653962a700180da0f61a410acc833000c901d627af760282000292fdcfca87c362ef907e3f46f1ee4c9423c3ffafad77eeb4ca2313d9c6b6be44c83beac19ae82e6c9a42f03b5f0ec80b21f9081c48ecc1cd87120301b0a442f2227f40fffafaf75b8afc94e020a4ffd66dd95eb635bb3528964176cecc0dee300262ae3df7ac164355bbdf12b6e49bb8cd83b85f2ac5925a71cb8015bbb2eba39d6feb4ab3efdea4f079d23f3fe6b7813d18a0232a04af436b3053004308c43135ae521494cab61f6071552e9767b93490ec84a854ae36ece74ef6d00e17400fa2be229a971c12d75725b20f4e74c179e263f9cca8fe19280e2ba096ec71c4aa812a11a8febbe1bbc4239dad578f1800d2c041b58277b95944912b347cf40724503d1fb4952c132528892283786aae865be1c4e0ddab26230711b7fa90eb42a0c1b26b9629b93c856e1cbfea9f8f2cd3ee23a8fdad53a6d8d3689668d8ef5375434531eeb244186fc26c1eb00bf9427ea3e200b08bffa1a34095069946be50226e6e3940e368746d49fc93263fff91fd9ae32f00068215f6237f7b5aace2c03a1bf58e012e1146dba93dcec64595d7a15ce281609de11f34f4e51e00d9d016ce7b2a417c6754ba3188e07b51af5fe38b6d460afdc3975c897494073a00f2e6ad6c02f8b507bc5ef3f2d3e8e89cb2fbceb350eb3a7f9b4369323a1ce41c124fa9c070023dad662e54afdbbde2aeb8e66ac79aea9e4efb5e5b076dec7aaaa4be064330453fc285e24d39dfc48d1edd4d301e32c8a316187d762a1b60f2cc7285ed35907d35c6579c744f0e4e9149706d45e13c96746c404372cb6e2edbad39f144496ff5818da6ae6c8d2b09b8b49f1291eff72cd7c84d0a38073dd3b905e1f4df1952750234488a02c28ccb487236312fbff8132761e565b393bbd2d5fd8bb6c3f2de960a5b9930f97141981cfb80411fad3434244a82ee731038a2174b124f9f971adb82838dba949c913deaf854d7afdee138572a448b2546bb7f3ef81ae017111dc63d025b9a7bbdf2c0010bcf7c0f4faa98dc7ec3669aef60b03e53a28de2534587e36e3c432b8e2c7a1cc92cf014a1af794d25b998500a16ec283188a3f2f21ee74e3b7b02627abcee1686afb3953b4689c804e322984c15a14ca09915066db4f4a5d926144505846b3de06fa144dcda2607847ccf34f91ca472a9440dfca9d304bfc32137e0dea16d820593a8d414fafa696a32949517915a046f65b295b7b1bd90458e5fea0781d02cbbc83af7bcf5d73230ba44215156a751d665f66a060e80ea6b8bcc74d0aeff7b40147d7c58f9dff33da88778011609e9dff30635e1beb0b0e960aa82d6c3c3add728eff69d134911133bc8e8f074f3616edf2c257d4374f48d4fdba845afe4ef74f028b4447e2b85719f95a4c2bc7b8945f36a98642c62e1a746ecbb60c67749262f537a76898288883d770f8961eb48b061870e60d1db396ec86f7d055d72be492260d541074eb27e842c87e339eb84ec5ae715266845fd1967242ff04122b8b31bc12f3b4bb9c8158c63e1fb677a7326646a396b7b3f0225c810c7386ee902a52f9ad6b2b664636eb63a4bd29a189480b0626cb0d0c8165d78002c2c0a889a11f8b762f8c3660180b0c71a623053405ecc6c47f9c158b054e0d454e44e6c71a3616f19be785970a5c078d196103140170d22dcdb7cae7e9ff081c3aeedcf9540d31c8cf21002048ec64beb8ff86457bbe3227c980a587bb36ddc7bce824238e2268c4d2755d24cf64f77640ae7fe99cb1a412cef54f5e56f00177ac97d0fc57760c00a045ba7bf06e975117f436ce1e455d021ff88898700a6af71e48670f5c70140df7a4bc1a3423c810137d4807305ea49be8956b4adb20d49ec6d86edfb908477c1743ab1d23b51d19efb7fd141b9b588cfcd643a7e1042633f1783dc306b48c1e61179087f479930313e92e8fbcaf2d827ec5d2277afe8ec6b10aa32aac318d2949f95807b36b2fdd5fc9b502076874dfe6db4e3a28b098e64b92351617296ad36c4b3a0f250e13a5c2afdcd1b6d1da631dbc95800c990b39de62dc497e3163ebc57ce06f4c031991d65d03b5fc709666b7e17f1c0b6ad2c9cc0ec61119510d3f6d4a85ff0a5cafafca108fa99794b49188e5b4a69cfd8ce3ad80bdcabbaeffc51a42f28373da41d5cd9327bd84558cc0b51fb8e23ee3218c82e52dac80e83f182b09c95ef0bf0a97b62144899b19a13a5b82799f96480588790c80ca39948529f9d8f3cb602983dec327ed7d2f4d9de24354cb8830b34a1900c8fdd4c829723b0035ab4d94289f81050cb16689305a4d97354f9ecaf0a0e276271e121b8fa43950187a05a7a45ae4b4b8f9f42aad8776304b20a11e2f13584f56df7e33b943596f5f7932d3f660df60ebe4f8e67f1b1f7d63ce4311e0079baf5c0b45ef265bd33ad0107e344f1010e5014bba7d8cb2c46cd484ccab3f45d2d1e57de91c36b25f39cebc7fdc82d9f640e9089d7cc03bba642f9fa635e01fd046d6907fe80bd92f1bfcaacd1082be325c8b9236cd9ac2d2ff9d6cc44fe2a599850f5ed9d67803eb072e6c73b74835080ee8bd982950ff74beec8abab7264271f329c4a31992839b946264e0b459d71d0740cbc87aafc4b05e78816494aeb98eef8e73e38731a8253ffd1cecef700e53f601625821fc56cbb8005c1b9b7b1cf0005e853f256c83231baaf8a74167af5c2a05fe1ee00b6215ff04a65f16990806a60a300e839c50914bbbc62f2d91d0abb6434b911ad10fa6f55f0064b4fbff5f3deba4049252bc11bacd4789259ee31d793037941562851560588713dc932d1fa4ed78e5edd8e16eb45d5f7fb7e9d6282beec6fa7d4ef9a04f86182a39f4f5fd51f2156523b2c8e089d0611a8166d3df646c850b4dc311f41d1dcb9ee1bf18430b152df2a5c4bb7aea1be94120857c1a9e2bdcfad584cb3937c110eb856497103e5ab038944200c30b6891ecc684658e15b2dd4e449e0cfb2b26c513c1610e8bded7e31abd0fec194f5eddc0e06fcdaccb31ccced08577e25d26797b65711a589fdbd37f9b1f5caef71122a65c07bd78f0805c0615d14ca10a285be1f0ff4ed10b49e532763753afb709092218cd0df0a289e72df82ce77ad771097422cb89fa0c0bbb6c098546884850169313fa741c8cb1207b313ccb65a6540c5bfc9afd3c113ede53fdc4977cf920f1813d030e39ea523727bb1610cb46e056d4ed359feb8fe99a441a55b8a91255e943981f433a059af8ff105cdac143beddd60ca60619b1c553d3eb4ffc63e06e783e69fdaff2abb47b805207a8cba1193986b42679274917b7f49b26f3119807771adafd64946a4dca45744ef1a0d682260103d57ecc59a306f266ae4360a235225cd42bf393cc1b0a63702dde2c6abedd5e505291728648242a614222b6c9da941b906cce99a2291491f052aeffb50ac5912a20e2656349f2a4822d7437390552110219d7b58209167ae1d6803e9996e8a82cf4b238ff80d000d81966892854ee0ac62e07df3b89f6e3e29f8ee919f4651210de8c65012dbf31621ea49767ee4a541456e91f930449aa77625cd8b696dc3d3ea923875f51eb6312f75dd99ba58ce42242cd3d0e2133044f00522acc920e96a660079a51363e6bbbfe559b11df2c2aa97d5d44102162f802d30fcb6330e8e56fabddc616fc63fadc3bf05110997a0a62e54936a217bc9891ca800047ef49e830021608ece819cd1154f9ea37d63041dc83de2f53214291eb9c459a5777e2467f46f1a221732d1275a1330f4cd38d6b258af4c55c9400b47b9fe3de1b466c19b6618f8f50e82177c847748dc600317d20b4d51abbdf2065be0e4f1f45330161256ee4a3a739da560ab95878ff75e3288f320b32bd8cd26035aaf826a1f93b5a2688b4f39556a29e06422642a88148ad3beff85434aa4c615b056cded2e92bac84e95419238692ffacd94e5c30d64df0d712251c2833ebcc06a4c406d2ad51dc30ae984a05c0a9db0a58408c799b61cacb0c4daffc8fb5cfdf95cc3a2a599e866ac370c34333da97d0f2415817818834659cc78a8c39398554679556b7014067e4b57edf0bdf8c81a94a5c2867e7fb058cbed460ef3d2fb868a4c1a8387fff81e7474d5ce86539b908b4c07e0ecda41a0fe6e59572253cb961539d6ce0bd81fac9d46a93c80aeb7edb30678783d4985bca4caa055f5dbf9a4fbe611391247f14a2285659e22cffd367c0a93cccb00d404c21cd28baa4ca96912ada7cdf5083a3db2ee3395e8a49945248ba13827bfb23beb64f1d3821ba4e3d7ebbce2c74ddd8fe513fbb48efdaa871b21e6b96d947eda6260e5409b4f324277da6a54b626e316d3caa0ccfad271503a6eb8512f712c3ea0e943abbac30c46b6ab1ae588c715ecea5805ee03167693fde5acc0ef22321627d282cd1ceb57790c68fccb57d0a8dbea006f2ba472a0ab5d9ebe3eff21195d6ab7444e623c6a96cd9da5db976db569b21e7516edb2a5d2a0ad54e8755ba105ab75b492acf7680f69211c4c3fdc2b5ab691b77c08fb867996f3f29db23c21474788f20d33f40a35d0fcc693b955a2aabeccf0853f63c680864faa5d513c3e17c3e7a9d2ca9068c11590af3694d2c2afa2a1b2bd8da9e7258ef787bba084eee4f2b1e506356a6cf0776a11519c1a9fbd214d981dff8bfa3951bb9d63f14b972992c4a4c9baa33f43b2a3092cdc35cb65dfd697b5f605f1958c1fa001204bd41216ea28b72f8589d54ce6154e70a6481b0a93076aae29741b0b7d8396a3d82a4451ef34e2f35f49ad9caf5f546d2cf9cc5a8d0af5594ba8dd405edef4456abb7f534367153e8827a4094bd5530043bd5eccae51be53565f9d0d3ab19afa6dc46e32179fb5b89c1b7bb7c0b9abf559dc16468cf4cd066c69e72190d6570b368cc65d515f79a7d26af4af3c736de24344efc0ed650d0b32287af3a65a1b456525802c1cf9dbf27f7202c4fe03848d087a2f15e176fda6c02c2d4b1bde2c4ecd9829f31364db839e812ee35581fab446ee07883916806994045eda24771c5ebfa43568512fcef0e39b3cd57d535b0b161181702b1703a14ccdcd36d1caa5ebcb6f15f05a74c694ee58788a2ea2c2aafebe6b1e5e64cb8e5587493b27eae3c645ef5a220f837e5fdd19698a596f4f22eaecb9b44eab2993ff5417742df522907c6a29d5e7dcc58930760ba6620a0f2b10bbaf8cb882757d5f39e4b6d4208997ddcf9f2dd0fafb02ed325579f025d662d62d5582639edd45777c0c5b2e5633a899740b50e56296972f6653e20d7365c89490c6be223691de575cdd506cc8973500fa67a89a43b91760370583a9eae5c560ddac8122bf4214bd6ca2d33525aee4dae8a27f5ae5624d30979611e80732b8c46245a8cad8427c1b365952de9324074901f27c597e2c2406042b317c1a1bc26007116402710572e103321888dd2a2a664479a8168690f50cf8494aa23a7fcac39b4ec4affb48f0cd3103a7e3d2f995b75e5a3a11b240e466eeb90b8ba8a800de2a279d0d59b8785cbf5639e7bc300fb8ac37bb7632472e3d457eb1d135840fae6a60800fbcf67c393578f6a8b10b3c4af2a959ebb449eaccb5aeb5370da777293c19f3fedf9c4cc5570e29e7048d49b01e862dffae96c9d994ced52bb5381581dbe3e7f3ac35435e1b2c49a8cae17975dc69969d601765d0dc0823af0d51b5db0acea54866a4392dbfdfbf80f7628e8659a4a63f6f5c47a23b8f276cf17f5c4e9b81626aaf37e306aca94de7abc4e8a3da85848e5dbfb6194367048642aeb43baa2836ed947d205a091117b81f3e476398deab16833deb4b6f3df84417fd3119a08dcb88470b0ddc8286f7ce17f5b0051fe2fb306e315e48c5af6f74474fa68e2e7668a79a9578ec4c67a611c8615488370b3d23c2702458dd4ff005a65b4fc37c4277c95ec0c878305cf9b2c4b0dd13cd493f3aeaffb70aba44e6054047f15165fd67176fc14409f4fae8b8ec3e4dd1ff224e9e1821b463a50c519e3c07588c224fbf705eabd63ca509a1c80b7144579a2fce4117bb7f95b444bb667ca5c593e7081e3c437045644de8ab6cb3144df8cf3f005d082786e5773712b8b15f8f8eaeb060033474c0a585cee921481d21ec63cd047bf9cc05714d54eb4f73c2726a7157b385f95122f1ebdbde3d668acfd8b5762d4e1afa738a85e61e4eeff9cccb44b7d0b2f09c033c5bb0ffabf4a0e806c830aa0bd8be17b9cc053dd86ca7975842e985f3b6c41282bcbc84c38ee6102882c0752980f16b93a5cde54822a8bdb1beb10a96beef437542918a0e9088662eebae50e4845882ce19e4e00cb89c5a8861eb7a957ed45a0b140565ab91cdf04f453459f75bb7fdd71b26374f2252e34f5dcb501002a7da1376afc1ec8c838a4b741fc212bb4085f4037050c8d0402ddd7b8c46cac2e56f53414a9bf5a59232793bcee8107c462c6ded846e3eaabddc1adce65959852c559e3d21c4419712ba55a02c369caafc53168b3cd0b331cdf3652b14304e14607b5ec4c3f9bbf7f98732a47509fd4dbd1d67df4f3fbdc4ece0206f0234e31eefaf4dc8e60ad398d0c1c8468562469775341dc4038e5dd895eb2cc8e2a0d6837234ae498207306e07d2e135a627c16622116ce2986654fc9a52ff05de427eb63a9c8d1f2b271102d028f552eb2374f9f1aecb6c86615f493c986dbead489f6056c48539a13c2b142465387f78b3aaa26891948f22001a831fe15b2833ae7283faac1393d417235ff2e95e862dc8d84207fb3e8a7945275ec5849f10c3fea139dd1690e1bb5cabf133f5166be34536c7d64937334f29980aaea7d007c3db95ac3ab41da854a276f63d6eea50d7872c99c5e43ab659764f45692e7624a704dc4a6d8b086eb9490cc5d45d90bc73f22e9b2116d9b1066cf2b9f7ec0da7b49a10865bf4130e88afa0ef2a2055c41301350ff6a7490c6a868d8840b38a62f5a062ca6b0491c35e4799c4e39822adcdb07678b1c34e4d8a941e1d3d59a270644e461a5b53dc9dcc1870b57b30ed92b74428b6bb1425f2be37e45835adc507cc13d5e1ab1006a282b9d5220d22b2d5481aa7a65cf30a69b924004782aea5ef4c535ff5e2a938b0d7e6ae605e887e64a3c5b1f45660c0bc7123a4dc61cb349f1403d935e2f988ecfb55b4914aa6b72415a1a0bd2bfbf8c70943209ac741b0160e47f2ba90219363cbe597b5dc8646b54edd8175ed3972c454205827f7bed59e9bc30c2dddbb5f317222764658baf92845afc94f37035be396f666ae296a258f52c373f19272a4a5153341078c27deb402a4aee08075e350914c9224c0fa083d1167267a6731d7ef14bd9a3df0c6e87fdc89218cbe74aa1fd370787ddfb9cece07107b87ee4eae49ffca5919535c5571b9e973f48b70a915e395cbdcf7392a173e2474ea28a33e5b97d16946c972a939e8aaea6e96761170fb19b3d0de877db194fc4354200b1d92eae5758e29b78d89f9e5e7a7c9d8afe54007345a1bd24af4496765e0d0b37d91a2888b702363d161099b32d9e7068aa8c749ff603b05e91ad3237440ce46b3243034a9cb7b3f77e9438495757ca3647710bdd36bfcad11473f3e7f58be0719b1b9053f7582954d9a8a4f8611b19e92feaccb702a53598b8f31bb2cf7963a1cc4df8375f5b80e8cdd7afa8d44ed27fd61438b2516dc48eb9c65635f5246f59e88b1569caee67cee362ba39273276d85da021e8a0dd99fbb03eabe4865f13cfd880a79d5dacf0d21cbe0d0ada22fb9bc4518139cc6520ad2f2491232e1a37db80b1f10ffc7b22d7b0dd4ec8909ff47ad884ee9d0fbb45021b3612b85473032cadad230b0284ed19d3db0be753fdd71b56011c87eff547d63244d7cc36231f4e48c3b76dbec9e092ede4f5817175b1d76f259f70947daf66a77ddf444c3ccc8152d2c295b098809ceff6b700d8cd85e0c139bbf68f02163642ddb08ff4c2a57bab819fd15792562767d66350584c0ab47c53004f54f91e3cb0e7b40936c2fbb211f729aebf9caeb04ab37aaf0e6fbf019514877e94261b929c341345669587fac30bb4255aad9dfe0f01773545a15392c536c5370d08ff729e6d3693b028ac0e343dfdb95c61099e0db90e3eac07e089ebbb795ddb3768797ddf768020c74fdf524effcd13ddcb53cd3d4f04701a35fa40f92975a4604147504af4232760b34298881e7958f09dad8bf13911fb77a541d325e006e67b261c96f3a47996388b9705e5eafcbb3ce34745863d49d0cb2c061ba9bd0b0403fef3c5317ec6750df25757bd1c3c763c0630303af4b98d80e6ca92c841737478ad832b050279b9c3fe977e2717c2b9803efa862f8604cfc3f48cc76f5e4303577ef04b25ec041285300baa7829ea3fb4c9c0a627cad08d2585b82ebc982cb0dccac25554c40f87a964f4fcf4bd465156ddcb51fc6a0b8b00050fd85bd4ed2b58870172f034a2a26905a8e0d88c30cde653a992768de414c05e1fbe232689717d888c8b7b4d04a7a63864a934fdf0ecfd606c2d2d50ae67d7be8ad484c810523c810db76db506fb27b71a16e44746ff775d87aeef926d38fa37e00a428ec81078bb83804c4f0678048eae5224b55e0068fb3ef85772b3d7aad0fb73fd69c685f8904fa2fee016e5e7c87c1b6d4bef89308532d18999415064565e9e8fc2d8be2af5a029e62526520192b036577fabc18f07ce82e6d29bb7c802dba5d2d9f4d32cc6f3566135aea079d24072c42fecbe2eb4eeb4ea4a5001670a628147f6f872195c55237fb679ce76edd2797de5dd0bda5942a7829209ce2f9c6de69bb5144bb93349de5ab2cdcb8592a2d5463f059d01f00278169ca7d48698cedb91b250796b87f5a5e652bbf1d896b710de9b50a6066c28ec0800f1d63d83d11e5f036c702e78220263bb800229061e76eb253a4946162a27860aacffa6bf92792be532f6a9d68822c4e038465a5a1e8d9a858e6db88d40cdbedfbdaed40e877f74674dfaf6c89a7afd474a8a606a91fd39277bd8c6ef583baf041dd5f1aa8c97c25ce339190c41915a009c9a16ba783d62f971737e48ef7d6b111c82bb92fbc00581a31141ddced818202fd12e3a930516545f4aa2abf753dca314b1d02527daf0d1acf568ed3f1248dda1b5a8c62fb24e79e8b82c8fb24c6b4890982ed3af8589495867f2bf1a706a1f13c8552b1a750b83929c36af67f84f0d1c0affd7c0e595968d6df8d2320922bda8c1a9857543df386d6606b044915c2cd9fbdd17a57819c87da9c9ce278602be7afa0d56ad32456d6d6c2263d621c9c139ea8dd606bb7a5a3168b09a8e97d54af5a10d31b4835c95fb0b020987c0dfda7d2a6512c757f8ac8a0d5e43021fa6182534b2ae14e4f5209bea2a11ddbcdab04ffd1be5956980e7e4a560545684790df4e1f9074de605a23f7667d6fbf1d50bc5adb0877a4e7b9c0d0029af5dde03a28ae0c82f6fa8a9385e9ae3827d67c099ca3746f7411b03411caf222fb4b803fd25d3c87db39865309dd35bdebbc00a1f05fd71a5d18d142e738c0c5578743c0c32d02d6bcc1a7c754f602964e45bf4a59848173e4b947d8a59042744ad12d777c2b5cd6a0ad5eedb65da09042ce16b458075b6193c8fe365a3f5c4af76a58fca075b7fcb30d87c90f185e4d20f96579631fb1b2d38ba634f7cacdf3b3eaf67f701aa47b3582cb2f80c1ce7e00179113db311efecc575c8c12378bc13776d0f736512c39aa9783d373b3de83144372f79a482b1f04e1e63d67e0f38d3faff7e0ba047b498b8683a8dda91ac450bdf2fd5d5a0fe374f6e90ebd02ecae1743135d0ba353ba6f2488fdec95f7cc8c37e9643acc1dae07b4b17db027ad725dc9edb1615df4f563a8e5db6aae5e0ece61913d3685ea1684c8ce971598f185408aa13f9d1dfe3be931dc79be17127d40867268ad607aed970b4bbfa39371dd034293528e6593b7e8872e21d43cee3f19d13d1bd8b38046f19e1ed9e6fe261e60af251321d2d98e2a268509ecfeac835dab8ca83c5d989a68a4f1117f25298dbae649a18f368fb70d5258c38059429180320e369b6cec9941c2ce9ff40b9a28946ab8dbd4fc1805681afd157947451a9a8937fddbac8653be707db4bf19fa8c144c9a15138f9bcf6f1fc8ca66fd09a74c8bb513a40316bb072f148963701ab169d6c9957ec85692c4aea1000dd31e70133540c6f1efd082b6ea251e48c3d2399c9261b10e262f348d6564e755c0aeaa53e9074ac2ffa13bac0649028b03f3f39a8625a343dc4040f1959cb9016eb6d33bc40b7727cbf8694ce0f7adf170e6ef5967c9ce41ec75479ba187931d3831800310a3022d64bb7584e57b7b117830fe6ca03610aa5a98fadc59cf700433b8c3887ac4c6274f52cdda6da1382897cd6351c0b8d8a260f25ed5fb1bff3e75cb42c4485c2f5e379b8da6d2d6e834e4e9c10dfca06983dfddbfbfcc8ecd477951579815cdca9b03d1b148c2bdea816ca405862fc76d9cf1b47e3f54f7f12ed6623633148ad33b238d65fd5d1ffe48b519d2de0ad16f18feff58ef3644c78c9f025472fec6fb578447769187e22520f1fed809b1b54697982ad3d91773c85d7e95992b64d5acbe27ba12c234c162ea391804c6ffe14c2de510fae65bc0128eb0b690f240af786ca2726b8628a7c4a3cc18504bcf95a0b61a5df8b4dd52465309366e9b7ff8a54c5a7870e522eb9ea3a98db69563222068def994e9d0161178003f718c022b94532e86dda6a2189d798554d35ca1fb8cb591c56829e6a181f22806471b74152e30c70ee9eb9f64a4d6f6b2aac3fd25412d2927c0e05a10d65ad917d7e621cd99bae3a75b9716b92e17c446963dfc10e433a2cda6b727b64acac2663137b00d59d8a86526120117bd7de91231e53d9dab956367dce1d890a69f3a58f133a8161e2cc761c7e49cd3b0ce6f70ad33346529102be4c5a75b0f53dbe66ae287508c1ff5fd3bb8348fa6b2cd93ec013b36452138d466467b6212345b3aefe3dd634e3dcf8b88cbdc2d88cb58c3a9937bf985f32290496915d5547e510e65b5a37e3d9f7f15ea602dfa3889544b8bf376ae61c2f07053484eed422cd3ae884e5ffc47e905eb78b997b2ab955ea33fa93ce0afb5373bc821ce19e25ea99ff1daab0e11df3f477c37f252d22d9c5815c402943be387000e4c409b5427c8789131c87cc0ec902f415726618f781c4b238ccff26feeb40c38b8cac2e253cd83596b5e22ad63a05e861ff7580dea74849926eef5747ee1da8ad41e709380069f53d3100381bfc213343e43db760167e44989f468771a44a08e3aa3e8ecf2f033d4b043e3a536babd86d5980a4f70de6ff13fee1d5c41db21fc053f3d76a42bc429111fdb82d7bc43c7c75a70af9a44f4be62849898936a37618a441da7803ddc4338544f4d56117a60a3905d909c45cb7246373e4e0a11dd3a65c867701a0203e919af9664a9e749ad70f57cca2419ea4a807a3e33083836cc935d7f288b09a53ed9705429589d1dfb9fc80fdcf0a5619d7bdf961703d8cec7ec0533cc2cf22c3a30386b9e322ce2ba7a1a8bd5f1f49dab4c86cd44433ffcc26b0d00ce7f46f5d1e5e4260d6e06c3438d7153b8876e102ddfd2aae99b8eb67813b0df27271489e2ad4addb0a9cfbca5ffd572204ab3baa20c1747e042c53d03a383c070ba958f1e4fd2cdcec75341710efc41dbc3ffa14caac836b03fb04c66d606afa64279cea5d583cf22921e51f8356d11dfd27668fc6673beaa1cb24b73ea0dc27de3c1112deb5f9489c98207674cb0cd88b47d99ae28d28d15ebd6da43dbf84ce1ca1145dfca82b1f347174c345a310573f075820cd80a8a4a0eb4e7fbacabd12a16dcdfad4e2cfce6a4338159bd24eef96a0bf31cb2d7eaf5ba63c063ef1793839569d522c6049cfb756bc6cdf82778f84748b46aeb5f5174b8459d01ff091d4592d2579bb3d52eb3aa236419bddc1ad19916b96ae415ed48e0631b885128d73ad7e2dc0fba369373da84525af6c0a324cee285452a6f77b77e8aa777466c485aaad60e675d81768f5bcca93bd53f9da789248b9dc1a091440c06654cc3b6e9363da6130d10c4bd18f2b540bb962dc39610344535bd6427a5303118029a096577fa60ec57f26b395247f0bbadcb1f07453cf4f13e2280547e9cfd3bb9908d5991f87222ea42dd822da4b95e26f5b84821309460a6662f82851167fb3d920ee01d546d83cf3b7491091fb18cb948fea8a279c6c6ba55c107bdd41c69483d466a7e0d72d4ea88095d6e2ccf46a18f73a160d7b88ca4446afd5e88aec5b7edc5400ead898d1c024d4525ddc13324cc4ad40024f42d832fa377e4a58c0db256b5591c43bc625cc8485a5f77fe862a091c790408941f60fd7509c705bb289042fc8380d8145eb6a185e33f74509142e5dd6f01db4163dbef823dcb2b6e080a51a0dc36538ff17877ad2bbb77bf1f81c303e97c15a014c9da576eb918ac09dae3cc34725e881e0f14c95d0a4c610ad5ba03e59da3eee07fe6f1039a81de879c979454acb1e427cad1a012497b9562167c76986c8c84b14089aa66f192613d2a3ade0596c52230034236fa054fe7c2704dc45b5cf041c2d1359124f8b2c1617b46a526f37b6148c4e4b102f0dd25525b6324032e963b3a73d00be07b1ff8250c21fbf25a8efaaa161399d437b27f2ce12c67988f42d51e9486637d5a2d7a1aa714fcea1cfb32c210e83c3a9a9235d95264a58a64be9219777905b199dff4864a5d2b48392384eace41b29230d99bc571b3b62c29af02d1c16679e364f0c8d21e62e53a554f4188824578f87c20c92a63e9c6a77199fcc3b2a6dffc1a17c5653827c7e86be99eb96cbf32cc7a89b49efe29e26b58b53e0c12cff6220ece447cbaac920eefe93b3204f519ac636664084605f6a6cb1c3a0ea1bf3b8dc78b6a02ce4bfe7e0ca95f96a104d199304f66a8299ab24b905bc4d580a256ef191eba25ec5ccc4bcc9279712dbbb3f76d2178c9d231d069136ea641296afd069ecee03683221bdd85bbf3199794fb5f6be54cb9834d40e58c4355a936e08c87295e8db09b413d6944f1724ffc2183116c06ecc6c2a10da996247d9a78cc8266320e1fe4d8e13774615be2a3e6993cd44d9a0e99236d4bc2918f53509f88ec550ecd78a534c97aa069d3fad9e37986f4451f697e0bb0a8dc00c05387311cc6221adcb698b8ad1285a96f7e46e7377ee1e3f4d43fd0664eb77925f2d12b10ff42748ac53bda7da26d56d52d800ed4d4f449644da917d6a7b5ea87d9b033682c040f930773718570a98d4fe6c1693c31ca6cc58d2176913525a96bfcc0ba8be2393f1ddf22367723eb39b6f5bb2df9bd41170cff99c493138ce9a6d8f982c559e6a47f7de8eeb3d0f9655616c35c3d5371962a090df57cd0fa4aa761d6903cb91419c4f42512d670213dab563c451fe32835741f8ac5f71a0624ac62748d5ed41bb548e77a18f0710d695bc47450a1b874c46679bd075dbe5c57b13f30ebe2d0a68a3576b6e51c1a3926eb6057704af20ac0a6a1be33baa6806756e6ff88b853c58f405c404f0bf36bb05ad9a2847f29b97dd3267a80e9ae813aec42c9ac1fff6d468470295b506ba5cc5ae7bd70a52b73104bd782e14a430e15480e3220cc496305cef79c980ecb25cd2a27e4b24088ac63dc0f5eea02c7abdafff3cca10204f209b6577c2b7f643a3e90be5c891a37f116285d5728002ea8029689d87318be5b68402ec80845b5eef691379b6a9b24a10c6c978967e054adb6f4b265fa93f3e9b95f4399f83f4fe5954cfc460d0f63fdb35969b9599dbb2becec7448710682a7fd7f1688fde05057f9f474edd1e6a45aec16ed1943d3b45a2ec03504af1cf12ec4264400198ae7a256d3dac098d5b44cd38f0add65cac3336fac4d1b9e381badecc19dec652f177fa300d4e3fe1454528f1d78330d4d5f5503e80b0776063e1f50729461b83e63904620824f7bd6b5fb88bcc91a1d2fcdc3366852c864665897faf86aaa2fc31a99ecf7b7345d33f3891f560e19ef426dff389d1f97772ab409809c1c83a8c909ccb4d1cf546e70447a01a4ee37fa6189b94989164472462bf5c7c8885c52dd4384e5028d9a82cc901c89aa770095e15b4ec3527c533911d4fb145134bd962ea0318afbb5b026cf0f8739b1427691da997acc8fc15c834bd27a9ecf65b1b68b502ac1c2231f17b015790225936d90814f32a6dd7688876e992ebf656274752faf44832fcb5dc1cf4c05b3f41440f7acb68305063b32edb28c736726045cbb6325bd2e9c25076b1765a9f49c8912a75ca97f7d8285ef2c6df4d0542044968ac4c2da0d9552192af91d83b127e8060a6c987493b1f4680fe9341c4037b6b32ea33b636ecd8dd3503f071dfb516ed2055b5e592955c0a4841bb647dc61c1676be08c8f75900dbe1b53c993f3063b9d7919f21a56e7d2b977b0384e99b6cd946e03c2f08d5632b74dc6ae62566e2673b4bca0245d51f5e601682896ca954c834239e54443cae9971c493a94c4196d2346ee3a0bd040f668e5e49e943e924854c7b9d1dbd2208ca252badc4c394c84c276b28c3970cd99ddc9f0084502b15e1bbaff56707659c10db613f0391b65e33ba13c26c85ae3ae8f03e11b8185f126ae053e723671c5ee4ee8aa0f90a1cae00f01fd15839b6f95ce2e5cf9b627fe42041fbb976c7f04ab5f82e4eb0c378f559c5d57ff4e80e206b503fd88e04ac22824c686ec0dba2e933b191fa14020de6b43f7df2a8e2e2b7183b2d5b2b1fd6f668aed87695869471b57fa8334569ac38d15f6b8b92bc94a265460dbb573f415e4ed032af3ce965a20181ea5033d9acde470a13059648294f547a6e8ae580f6d8cd2cb48845e92b3385094645a8948ccb06fe0d102a9acb732d90397473a1930848510a016c9a10d324fdff46c658d5c140c3a8823961049c8de7b6f29a5943225198c0921090109398eee676844e5287fb088e786979be40f3e069a64f99f975b42dc5f90b867738c26e08006dd35a5efcc175c2e43232a3ef9b3ad0cb118c20e41364600d26c88b9fd3785036e0b1d496cb9011015a024888087ecdf120192cdcd52128951823bda1f7ea96fe6bba18347f6a2ec53b6647fd510d9ffa111126040a310c820fbdb2411348567b20028c7d782b2bd4289a81631370ec6bd8885c9f1498d1ecc1b5e5cf85144815b9072e14b16d09d712fda50c1c540930c9f0bd2d18c35313beec5ef4ecb86dc8bdd123fd94facc986202b7ef69363673b5298bab812673e992a891412f79b637a72fc6cc75d33ee15616222869423769423260624aa2184dbff65431f06e6b16cc8e62b7d3425528ad7681fb78f3fb94c2ff3cbdd7c8a4bf127cee3acf85bd762382bbed6f5f01b2d5ed362a2f09a0e93c56bfa8bb36ada8bb3aa784d73f1a258838314c3a5189761bcc6f4f1e517afb91f7ff29c3ebe048a35a88f3f7ddc35c56b643ea63ebe1c8a35323ebe0c8a35333efe277d34e953147f4637c486c88a9f8a2fd3f516671175385d0f4556ec5a8ab3e29bba9ee2acf8a5aeab382b3ed7f515ff0ed62f572a927b114cfee618950ed7c6145745e57eac9963222bbe9d63628e19dc99a111152436a0ad89f58d8a0d221b88384eacb9f488fbc1239c58f3f4c66957465819e1faf76feeb27805656b520c93c04c57b5ca3db7780342a55a41a90a324283e2064c88f112822d5510010210c42001842e437c49e28819f48483810a2a86a04188a1392acd913f9bcf6b1dd1041921c4e0a8aa7e2608323008725299608fe8a28702210a45d92106587811e28a992300b18322f430040852d0022e062ad80ef8db2e43a323a4c8598646476451691e5bca2863f4e812045a92a4947206910a7f5785a143d8337c9ca6551df67cc88517797eca06105cffdee9b62de892b0ddfa3560f86b58355e35c5abfeece16be21c4d47c3abc638db6b0f5f4d362deb1ad369f25acd5aed63af43356fe8d176aa4adde31747b9be5663c86754ab4701e6a80f13005fa8df823b60ae5f1a0377402295177707508b0140e8825c1fc26e46d54213d7561eeeaabd4a00fdf939f4275ec99cf92bb97d0ef7db4a3e075f8e734c2bf91cce7dd3c357939706bb5664d5377536f5b7fadd1157e216a8a83f74b11a4377cbb03322bdd31ec3ab20d9633f43f618869de35bd259c39ffc1b3a63a69c754922d69932ec9a49a403d00e8fed9a4aa403d24e969d272ffbb76b4c443b20ed70d991f2b2af6a57f3ec0065fb332d03a6d132f8d7af7087fc5aeb9b8ea8d0e894d27697a14f8f98a3605903c8f03b58f33fe3bfe441fb68eeee54cf5cb3e6ee32b9bbfb4bd261e4ef9497c87e4967e09463db9dbf556757458f51da1c713ca9683e991d1b0d15cd386584de320c9741be54a188a932028451060863945ef731aa50c4fc2fc618e34c01843046995467d22a65a553c21db336cc41730812b3a451f6c3ee49e5a4b7093a618e1cc4f309598a2811ed51ce496985453ac85e531b0673543b6924a40f5b06fb10e6982f3dc7873433fa9c9f69dd32ccc722d113a932b435443a07dc616b0da14b89b40c18cce125fb57eec754818898e36b1adca22ac6f7a21767384137aa3d518360c4511423ac28aa1fb928795168d053654c142b7ec8aa146d518682c0a81c6951847aec0882b2284a00518192b0285084a023b0519c00319500a344d2852246082022283e0842044750b47802e403258b1e2a3d50acf0814ad0b49fd20124d2b4b82730b25ced0b0f2ed5010f182e581260b6f48029b2110212be89975f441732b48c8c50c109cca645fe5234c8df4c1140c89326cff9f3439e3f5ff2d32844d90631c6bf5be4f8aa229a2022042f776411128eae0e7a4b49d1c116430c653722224a56b940026721ca163990b202c7a2411aad0613f7f6091e37189fbe72568d715e37ded2deee886b4311ebff41a4031019e25e6c98d449163e843ea49cee6a896589002855401c307f160150a4802c8965eb47d020cdf7af17dca0cb5fcafb448334df492857ae0613b70613b766c8c4c532acc1c4b53598b826ee29e763f32029b70bdc016f90ebfb4fad379ed0bc1b36aa5ccffe867b9f75369edcd975762120abd660e2cad460e2cea8c1c43da1061357cb7006ec6fb8c7cde05c11b7a5b8eb739e9e5cbf725fdf9fb8abf4f59da7cb8ebbb4d5fcd33779ad26fef92814ea7564fdd216d44b4897be7c9311b5bf7edfafdf49b1267eadef4240e91a872c1fb8c3f43b76c000430b2d609c420a1f2a6779fe97e5cf7d7ec46cc231b70fc4511fc8bdfaa8ce7d22ab7e2928d7dfbafad77f72fdcf725bfb11f3094a5cec391f91551f5371bf1e62ed70b5779fa8d5774e48f3b8571ffbc6f04a95e119f7eaab9ec3381a7ac7bdfaaba771af7e2de1cf72f8b31bfeae863f55e68361ac7fbf06249155ff947d915873fafacee5a0fe621d2cd8ebc847610ce7dc3f619df81717892cfbf56ffc9095ccac6466ac7329cdfd88d962b7f56fbcdb72ebdb5abf0530d76bfc8a8d9c84b81eb0f6686c3bac125239a78c31c6585dca6e6cad4a25a58430bb3e6859967387c54ef0e3d3e0f6cbf8b4d66ae5bf94766298ccb2a8699b675c3b845e4b5e196794f1ffb3ef3fcb4ada13dad70ebd87ccab200d719452cee979dac83499e24cbbebb256b7eebe23209105bdc7d75ff78dcf3dff7e3a5f03744e8a69a463430d808cbd256f689de9373f6a73f6f0fa59c62aad5362d99cda5c21db00c0ec708e5df7c11f31c35f05f10c71bf20432a72e715b8d81eb22b8dcdb5d8142d2d84508b0bc6282595534a08b718218c31c6f835e0a6c211b60610422db048859fdb1f1bc20dd6e0a87adf8d96ad58490c972293d49152c7c405915d141515cda028c6a2188b6691945372994151174545453328e284f01d13964548e85ad44a08514a4e43c9501d1cc6344f89eb9d9d7ed23dddf3b37156dae74a0705c9a4e61224476c9031a3a3a431620874399eb0f500926fe0566e880c3901aafac6b76c8888303fead237aef2c1ddb83bc3a9542d2b8fc16d0737ddb15a7a826b6aa2b5e56a55a8954b43e0734d191a4109c2055078786209da977bcad0488820685f5c9ba191103ca852ae96a191103890428823218a84000a632f512ba2705313db1f5200c48c218e543f280145c6077a4ef8018a10299f31337ee0e189cc932019b675041f94bd76bb4324a55a2dfb05caa965d3d26113658bb360a651b8380b6699eb830d82b84f76503e5cf1c444c4d0c987277c4a3bd707267ee0a004997ca0f2648302a6e4c310406849dc1844643f106d627ec08010d27a0002101688a3ac871a48a93e45986dc9a0c7de4b840f6581102d1b9b0f10d12582b0f70ad185f610e5a765632325888e3962ce19534a8ae7040271c8b78dd93a63c428a5ffd1f8f2e50bb49ed24a1b23ad31c6183b463b2d9c73ce15a4b8fd3cbdcd1a4d5ad1a88cb26a34c82cb14c398b56b111c620cbef39e77c207007f6934529a52ad036ee69b80ececfba15a0275bc8f05703b6b142960ea00fa05b6818f6daa02945cca41ac4f323871044ad8031440403088c20bf56b8903284232b4551c0e86245e827a98b16410063899a0cb100c38a1783c411e120bb05ea2027b2fbf021b44739a90eb8c3b940b805422d1066456eb5d28b2cefb20cc9f5a2b5f74ee8cd23d09b17898d1bf4a4c541fe50f1cae2558eb59f7536b2e47f164b7cadf10c0d2fdf91a63f3343e9fc1c3be331ccb733331ad6d6fa4724b0acdb3c069c4c9f7b72bfcdb2b2b7c26cd9b225ed8eb4727cac5ffd722e6eee5a05e95ee560186565af762bd8c8b6d65ab3ac7a0c14431f510e4183345f3ff62fd9f50bf5db6b7000b76ed106b59d5e436ae9389d4ea8d7704e9d357c81566e6c04f5a687dc0fd49b5e43c5c6a8d4cb4ee6b51beda7e7fddf6badf636eeb53e7067e0816f4a3f45c3b0875c8e0c5ee5c88fac89539fc23a2955644d14842a20292cdadb129058b3392b6eaf75b6bbfbf15375953cb59f280db59d50a7d30bd55ddacaa7bf9887bb4e7f429d7e8542694c489a737e0f41232b405328cf28f29c4579a2b4930dee9aaa233309cce974fa19643ec9ae7f3c86f93819f5d9f79f7e7e675bd73feecdc8f93875571fd51d69cd1f77ad82b4767672f632bb6a27671c0a7f4d32eabbfb5adc93fbf5cf76faf9da8995bd53b7c28d9f3a1b79eb5276e644a383f1f0012c2e7831e93c4005062ff9cef938c5a0e1cfa23aec1bbe28f7a35ea095336ca4fea9bfa27e43fa3ca3741a558031c66842c6be7bfb1b4761f802adfce1e40d1bd11ef5e164143ed2caf6d47d2d6bef55a9fef479f934df0484eb8ffa29f37de8a6875e7217f6cdf94061adfeed3e9bb73795ba4f95b7e7363c5f3bd2ca98fdd47bb126856d64c9e0cb5ae2b62ad6c497ef4d4a2e830570879225496af6ef0c1d7f3a8a800172c45df6e3db40c409a4ec39be72e03cdc2575bcdb4e89ec3c5f7674351fbef0e47e57466bef6555b91d45d0c4509ec9d0a889295933c1ef32703f9ba5c7c0115be218e7c3243537fe66f7dcced0a8892fb91fde15dccf1a35d1f9ae84402313e2254d78c90e8d9ad8e25646256849aa96a436f1244ae0422326a6dcc61205962bd93f2f89524a2e48bf941c0dfdd363b7ac75ee4773eed1bc85f661e9748aa7533cbde9b1d39b3ecbbe3386598b751f663130404d8231d976966cadb5dd25dbf692ad7d196be4cb47b7f6dbe9b1eea4c2432e890f1affa3f3cacb529e96fa1e776118fbecbd87e37cf84e7b0942d294c680ac07b286e1a0f15a76e365bc4c966553fb58f815344dab618090b28d5dc55d3a3a5b1eaafd82680452a6645b6d0a5d671d5d4f71cf6671af0a18482ec57fbc8a07f9152fd9be0b65b1ef43b10662f6c875af05e56216abdcb35feeb764e699b75f07cdbc5dbd7d1a2a7c36ff5fabfbcfc3ffbd8ae6bf3b24b2eca3f033dc0174fccc4f71d78c0b2d3ce492f8a0f13fb69faf09e0b5efeebb21e6d6f76f39feca55b224e6171e86d75ebe2000fcc120ff05254b6236b2fdfc2435b7f097036f2e6025416cc63e88cdf26547e3bb7bf72c06683c86695ce860c6817d707fe3bfc4b54eb2e5c9dc6b4fe3b3c734ec6f3cea531f00ac3be16f74aaf71df7a1a56e74331eeb240eb2ef685d67e771572a1580163ae7f11df72cf63caf45d14343eed97cc56671cf3e8438dcb3d0767dc53d0b71d8875c907bf6b14e3ef62cbcf7abff3ac86b165e76ab962c484faef0903b00868db0f036afc0c2416ca6c142e661cfc32ce02435d3f815fec64fd8afda8bbb3edfc1ba947b5850ac815e08d96fa12cf63b8a18dece6cbfb7d855b6d0880444d9facb7e4bccbeb52bbc7de7715767fbfec45d76876cbfb91966dedcb3bf02be21661a4362cd7516f636f06769f07701803f15f6187f8f7d873feff1d7c2be06ee92edd3e854e8ac7bd8cf749b7bd84bcec7ead4a5d0c11c43173b25d23e0af655dd0af52bec67bccd33fe84197815c466ee5742a411d4db1c1ff532f00af5728bbcfad13985bf19604e5233f637c48ce12f3eeaa5972cb9c8327885c2496ae65e76c9528b1c391f9874af84a17bf071dc355fa5ba1746fbac2a37fef733c4bf21660ecb94bbb0b7afda1e72da2ff11c64fb811320c8d8bb7342b61f386144c6320c3b0e6fc1031aa499f10fb353b79a39328fc23aa997f9d9e5c83f611d192f3f85a4dec1d19386afcc69184426cd7e48ac815f7c8ee0e02e996915a14ce996e98a529f4c1fcb66cbe6a70f99d239e774cda7df0388a6699fe12ceb9bd8dc8fd2cfc8d5105f06ce300cc364f02ae7f4a8476d1c0dda6718723f4aa94ec69f3a999fd1a59eb3363ac67d66448528dbc7b82f616f039f0c4b18c39ae37ec44da63b7daa936132994cda09cb07b5641cf7280d2fd23dd363bf3d8ebbba4fd2a03d864ddc8f12e42aae21be8c97d1a564b8b71d8d7b942b59eb91a3a1542a955ac3b2191d7c9d34f9a2ef99328ecb389389e3b8bf711af7b6bb44fe4d6d290ee2efc896b16fec4b9f659ebbd4256192b3cff2ed9274cebe39cef4d5d441d9a15e86e3380e857ad489e338bce21ee6205d26d3a15e76a72f52c46bfd70b3ff601722ee515ac30cf9278f81be44e1558e8ccc118ecc30769a1c0da60deb8a10e98630718d5460fe673871118fcee7de54eab8d738ae542a954a1808d7ddb847bf64fa2ceb4a2f653af83275df129fd1e5202387d4c7d7b8ce732f637fea749abc4e9f65f82bbdc984bf259eb12f7de50e90612b3dff423df796a3817bd4e9b3bf8959f619b672fa538785e3b0e71efd1b2f7543dc853d7d22eeca20577ac871251db27d5fe242dc664ab85f2bd3d7e12e687fa3dab66134eed12c3bf87a5a837c190fb99cd4c75f31e1ba98fcd75df5293744fe09af7264a05ec60cbcca49a5bec9abc38265d90fd192873c0d2f5eb63da7fdf6da10770d71d72a486b997eaa63825dc1050f5d5e5834ec6272f6a86e95831ae231d0477d9397c9877ef6a76e95a32333c45d329dce56050b1636783179a331b4bca0c7f0f9979c7d34325d972009431cf1f3ba89a80ebeec6bbda12cb6a70602c0914a755f9b72ce988424202123255e903fc8c5084a04adf20793a01833ca88002a479005bb5824c882190154c04016cc9f0a08c41104b2fcb5c8fe01eecd57e169ccd73480c45d5cd350fa7eba0407b8831352fabe617bed6fa20add4c6785e6571d740f854e8954752774df36a3fb545946a7a4a6ba259d65700ff7e6e34cd4295e7c136b68f0941d949f557dd6da4c916a380b4910ca34fa8624d6c878babdf630662fa36b185fa6fba1b6270a2d999ee409f5a697df48b4568c6489d65dbdf8477ffd1a1b09bd91455fe5c58791691232fd8e90beb5f766cd4dddfd5396244d6e51d2a639b25b6aa628d2cf6056bffe9c3750f79eee9ff00d9d51f8ebafd8c895528699b3fa29c6d3431df8bb53507868481b82435483b17d7c6ca0f1084d5e25e9dc7f83ccf5939872c55fc43dfa1c0df52fbea173e3259d2b9e807bd4e7a90dee51bac3fdbc53d751d07f95eac621f7e8b36c70efd79f2fbf46e2c9949e30ad987e876931ee925fc140775d2c1b4955e5fa944ce97f3ab01f7f92297d0d066db78b3ab45a21c783e77e12c90931f2d7434344994a16640a8d9c1043db6eb165a6f629fdd83526d2534687b4eb37851cc77d6322eed1b75b3d951e1a9d004cfe7a88529844e9d752327d8a24b2a8d528353d4d29696a37aaa98a609d84d48538a71103edfb0c33ec81c01d9eb53fa27d1058a37a085559785a644dd31e5a4d4cd6c4c8da8dc3ee4ed025c330191a0985c95a732d3f995b561d33b64f38edcb6c31d4ea296524d4257f3659fbc9c35d9af640b44d4b6933db75427b07e29ef6d0ddb601dc45b17c20eeb256d31ed268d848efd02aa8c45ed37c6bee00b4bf1e23db3132f69506fab633653a83294b9cc494fbfb89e81fe1bc2a77ffe813cb8738ba376be48698ad68807e0a5946865c4eefecc864c8e540a2172a47911d43c7d03358d033fd5dc447605176fc9d85f360815888c98655843d652bffc62376413ee51bf70821e72fbbe8317601022ab4392bfea41de3d3b88b00f323ac3523eac26e2da5ec606b5a51c16aafb47fe37425a446f66f6cc461fe1caf827cb6ffd9e2cfa6e5366fffb34f71abeb74f8db3762b10d6eddb8d1d261e32e8aa34dcbbd9863a6d6d2da7257679aca6ee15108608cdbb641f11ae33bf6a19d619c1525ec31714c4fd7afee6d46305f8f99ac7e9b1b8be12e982b52140262857b2040b8879048bb34352dd5a7cab06aa705c4c311d05191de891049a5ba77bedb80deb40f5979be3320f7bbc43410c79cef4031d2e8fd8e437ff0e5b50e4877e3c4fdecd66ab9c38d072dc397ec9d95c7d0595f367094a3d0845107c2d82ee83901195df1e16c0f279f287c8c96c8020805464b68e17c087ee7fea80a93446db55f6bad56aeab60e5ce19e28c0edc6ffa14f5c7eaeeee5ea103cd1fb8a33f6260c2cc2e5e0471c4b873f4c2bc82f542c742a13ba1809d9e382b4e1fbf02b2628f7b518e7197755177d5d9e32e2ef24886915fa4971cffcee0eec82eaf550d580e2bec79705f1ec51a2f82acf8d6caa31ca3b8227b8c562e37a304b7c88b44e0400ee4400ee44091d5e39e946c2726cd1b71d8714a29a510d2a949f1e9ee0ea7ff207d716f060fb7815a06a4f8c56ba214b82552e91aa741864a01b700831f459f0894fdc85df18abbe01781f214f7da7b9c75c583dc2743ffc910c877b4745296dc499b11341892b8f061f576f88682608be0c22c8cf093b1976f273d8a44d1bdfc45a28f18aeff2bb83ca8dcf692edd78e2ff36ca4c8f2ef8b046323493c5f6b307047e7249d9421c4f1b517d9bfbfd080bd440203774021d84bac93dd0d9d6d131acb0517d3200d0ab96fff4c865b9453fefcae9b7b040002b3c4aa9edbcfffaecbd9e5208b2574c9420962d89eec592c8127fbe7402fac8c436b8bebd342c01d504a4ff3e4ce6f64fac9f9324ffc31691e1c6bef55a9e2518e221b500519197e4b070e28030ecce1352dcc6ef83b6293210ce242a8f1f8c0fdba07764fb79af807969d81c0dc2477cf344013bce27c405f490c5b94f2c854c76c8f13ceef9e070f17be4b4fb6842e6969152443fc31c91d810bb340c24ede91611647d072a3ff5b792b888548f79c0794ebabfe6ed5ef65fa72d558889729f6b2ec96482532fb432b3df695edd063bcb2c737a21fb98c2df75bd5c7425ebed779acfe8d0b53a6e5989ec33a58b4d7e1de84350de3f4906c9f9df6b1567bf950c31f14a33d9452d3b477cda45deda4697fba54669c2538e8b84b7bf913f09afbf273bce654837af9a8cec29b5873f1859035a591ec29d59e7ead75dbb69f01e60dc70f49fefca97dec6fbc6b92b32e07a18c59fa3751526cc5f4d7a3941213615ea3180915e5ec3f834947287ca70fcbfd0d6b6c220bfbd6deb577ef6e758b7bfa5decf4d9d8c01d9eb127e22e98b1b7c15df1b11f00f658c4b088610f21866112cbba1bee6198863df7b0fecfc6266296c3d8853172337cb7f6dd5996411a6c06416b0f5ccfd0c804423410ba4378adad74ca083dec21570386e11cb0dfb0edbd6fc8d5e0afad8132ee6bc0b0ed31bc8a58c4197284fdf65f13190159fd22282ac10972ffd078e2fe4fac59c5fef69bc8eaff82a87f2a6e2a1dfffcf060bfd13441dbba9563ddcadd71cef626ac63faed7532cd94659dbfb4de4cee3960c9293df6397038fbecb72e8752f62b8973dc0a1c380982091f42e0e5b5cad91efb0daf245692035f483c25246561841d2821042a5ed863f0cb8bc33a364456ff865959c3a3177c61ffc1312f0d2aa05fd8ab5a155930671d7cf1d02f2c38d84324ebd7055aa7c5fd92183e6374d611f7bb2af8407878f817962873c45f13dcc3e14f77c37e221b433708a1ec502b753aed440ba03cf162d256600045d0cbf45ca7d3420f2f2633827899deca9ddcfceb836b8aff9e0fcdfe3c4ea882fdf62b9bb7b791a82747557c75f7d67518f7fcb1ae93bc22adfda60530976268d3473a79899b70cfbfee8d9b32dc3e3eeda3fdca7ee78fa9eb9ecdc411734ae21b3992ca115f2095bbb111fc580fa40cbd7c6cc45c21cdb5a239a7c322222f33c9c8043a9890be706254822f2a4c87d562363a2c80799efdaf2a15fc6e26c1f5fee23a1c7fde8d268246416332342a410f2bff53060271f4ecb93d3f7a8c31c618638c31c224249d43c8852d3647ee8adf5bdc253ffeca0497477b2af6636388b4b8d7337aaeefecb40c91488bd72c71567f7fdd81ae81a159fd598642a59002c62db4d082a16df2d7caadced15fefb40f34c18d9dd778ce6ad9d01cf980522d56fbb3e994bfc291a4b26b0d2d2831e39e50af79d997d0dc1fa57bb7fb54e242bc5a59711d7ff7c6d075c105175c70c105175c70c105177680e1445df0770e9732c7af128725eee938ab65480273f83f710c7c46622dfc205e85c23d21811880403a8aed1db2c32564d6e2ff167a6e8c3516b352eb3a638e12533b1ddb4208450c71b30c8d8880b052887a8876b8900116dda738caeef0ba47055164418b80298a301e3343a329ac5822295811a63062882b2343a32978b41e5c99a1d1143b0890628c4c86462c6041964510437a509112114abba3bbeb71971389114adaf285a8884b17243061c6788f509628babbbbdb470b8d488c50d2962f44455cba2081093366c85d1fed11ca12c50cc2c1832875c3de99f75a3a6c6eb048a465121111f970219fe6c675bb59a47eb8c3610371b9021494a587888ab674c9b09ff669293da57df2431c0dd4551aa8813a49cb110e0e8e9d3407e7286748ce5115347087dbf4b474f0f81bd5ae84941e664c6a1c9ef45e9c61a27b1fc36ed70348dff8945c23c16b99a60db9a9192bffef8d1eefe9b0b90162009c213745e3debdf7d27834ff566871e7f3a428149fc42a7127fec4a078250e6598189e94e34edc893c7127eec49db8138f2c1531c6687160641d41204c8916dce1407e6e7a18c0dd55feeeb522cb06e2c8c139c201c2a0f0b137445ad64282834d4f4b070f57fdbdb10698c00d909c21456c38820407bbf570cf6d0f203d886e7cb02737ee82f006ead868a04da9debbd1b29130051a8dbbdc2249699f23cd53c4061cfa49ffb8be0ec2c921028b6e580b9172ea86bd33efb574d8dc1499409122dbddac15da022471302dc3340dbbe961007777c7699e1cf7e051ce909c239c2584e00e1a70024d2eeefaa60fa669f38a960904873acf707dd225c308411c7002e58d06da94eabd1b2d1b2c5691ee4d202069254caaa23526678f7d5c69af69453a7064d30308ce10225a86794fd36a0cc3b0f8d0dd55f68d609ffd87fd96e154cb5bd84fc05d9147ce0e924d0f2038438814b1018b61628c313a67a3b5b2e9702fdbc7f72d4a1d31dae888b86575d0822cd97efd5a315b31ac3a123e60305b81b4bad65a57cd43892ce923864cc00624eeea19d0a80557b27fefb8ab27d674a5328c534a69e62d9aa76fa4befdaf06a91a942705e85005e2e88757dc83996a3f678b6a3cfc4bc3586a7d5b63adf8dd53c11db0d62139ee398e7b9ec53d98290be298c91d51d09286d84dd84563e4ce1536709891b8f127eef82b21463e23af9278c6563146bb8cf1657c8ae194585ed15c9a561a9a4a051df26136d1038d134c821ee20d90a229d9dddddd83706b86464543e40f12dd54372a92344e246664c515333234b2624ac632342a7292a12062915ae207405488c00318d0a03502275fc4a841115584c183e843f68759a693317ac42842d2109e24c105da261f30c2d110493c71842614e1070df80289158401c1159f2f70c08424ae502103268c008a11ed9202072de8c207598ca9220a0a7e2840051228b8628c183b2f8063f020063180220b9e1d2bb0caead67da60663c638e119421364a0c3eb536d2c38028c116334c18a15bcfce1154fb2d3ecb688eceeb6d229a3ca480aa1a61fe04288cc03114a0c51832e8e0045092329aee4cfd0688b30b600c2cce265ff6c89c82e032a54d005142f08038957932b4de820cc0e55bcc862042f7f95cd90f35627194521d4d8cae6e0dcf01a1e47ea11263b10429e0e1b286090fd6f80b86b4676a328bc64ff21b1c65ffe5662aa9b6a657f2cf7c9887cec3f29318823fbaa59f93008863df7dcd2ee2f4ba043b0e2043d2f880427c62892e145182e5ef199c8d0c2ca0e2f39f3c58b492a88978ec458fa23c6e207d060acd1915266b0a5e8a5c304ce000b1308bde4eb3061e10736f879c5d761a24aeac9e2259f8956448517af5883e8a5c344c6102f89b1f83391217a458ca51f3e136f1cad87fa4ea494928993262fa5940f696aadf5850f6281236badb5d65a6bad9562085fa8554a29a594924a29a59452d25a6badb5d6596badb5d62a6badb5d65a9f498db5d65a6bad9276d7651761acd188d0fa5d7e779d020a3e5cf8f761730a80afe9a73fe1a4f00ea9d769f24abd46b91f497a8c4c3f498f41b95f957eb57d7c137ef756252cc4cba52f61faf439bcda80b847538d934aa5b013993f6518a69d95fb3217f7907a274c9c34f9d3e97452cd4f412c4ea9542a954aa552a9542a8545e22db93f8555545cff88757a38e1e58449ea743a9d4ea7d349063be1c015521401050fbe4042e825f3a877c2c44906c0b8e04a184854418223bc4ecf24859ddc542a954aa552cf83cd2b859d9cdefd653a94ffa9eb2ef92d8106f10d31001a8c3552b6ffd0a4bbfaa5bb7c157110ffc68066c497c4ec7815a41ddf10b311f84dba5b3768703febd2bcc94e8edf648abc9aafe426c7863856130b218091f8107690c6d3c8fe340a204bd95fc92d65ff528dfc35c93ebb1e237bf731d121fb4e6ef8f1261a81ab88851020fb2b814419e2551002647f028c91bda575b2a23fa9bb326471b9fdf63f1bb31a35b2c5496a64fb5a7673924eca36492365db3274cbe03a681f4767694ad3060fd0619fc90ce3381aa6ed0a90212764fee7798602648b93142076e6519630e0f9069a6d8542b4e88c9427cd774c685e4ba2e9b0686fd25e6a1accfd7133bd508ecc0226cb2019341fc9fc25538c3c352459f6524af944ca1a658f7c9204d658697aad93575c0ac9229b4dd806d7b9b837df8f7e86c01db0a6214bfb8941314e3c1a1277997efe12994f827f3e127f0b937075c813ffd73de429a73665fec64d5f391f49847cd6381fd8772731fca3bf6edc7d9d3513a6714f7b2d6e5bfb164b10e2d0beb56e0c9225eecd67e1e0664ffff3a33886d330b4a7eddb61c7923d5df778f294f12183c74431dcf533fde8684e3f32e1d27750a94d12ab818452ce47f75a9b249605c9a1a8ba32c8069954585cecfb769bbe6dee9737ce838a69622f391fdde3b40cd9cf5700dc217ffe02a0abd2fc67b38c9b65a82a64f5cbf8da4588d5c8fd364ec8fd349de7cf98fcb4cf4c32d502c00600ba935967247b259db16f5bdb643299f00da67f23a64ffd8d678fe127dde3554e903d3d793e003a27726fbe8dceb5386bbe56ed140ce8e7274806b90b7f0dcdcf9744b2481eb92b8bd422b7cc28f2c46da70c823bae4821d3df20737f12536e3cf332dff886cea64f05cd9ff13aee92cd83240988bb4cf8cbdef4f37b689811e81ebec243871b6be2188ca5509e4191359f05c55dbd0a4fe3e3fbcbee71978fbb68fcfcfed1992d25979ee787e979e870b111d32fe92cf346e4949f5813c7641b6c99e72f19c3c3bd99e1ceb3b8379fa6f3a1c89aaafffca8793a8ea13f6b8691b837fbff53f8d523598283bbfee7eb409b51b8283c8428749dbc3291cc2415f7580605a2c0a8142d3765412b15a2111100000002e314002020100a0744229148341ee89132fb14000b839840725a9bcac32447511c841031c81040082186100344466a884800031aacf0d5d739f9fcbd14924a56f631046ea8a5e3fa9c22763b5c90a02edd4e786d3efdf95fc828c0af6a32ff02223cbe7ebd216eb8f23083ad3cb6bc4956b1326309f510fc9b5adc2e40e6426f7185fa9c1c7679add2fda25affb855f283e1ba02d0d4f95b44a06ce4188c6887b1c37956bdab508d5bcf75b7d152370839da51e3ac95db48566dbc3918d735032b92053175b47f52004659d8c23c2df1859f3dd15876c9a87a51789d866c0c60068a208aa4815054f182afd58b35de20399d5f9443b5a152b00f896f46e73833169b6e12c1ac48fc84b79a16a485c9d2a6155a1d120baf45ac96087f2b33735f178dc59ad86df98fb871c537a2ba6e36e33b6c7224a7b416a2a01b1125f00e8909a3849c9865c10c5941454f05c640a52680ad7f39af52191e940fb38b8d812bf0088579360082b07cdeec3377aac05808fc6e4c39f55d4bcf9343497ae636043d4490a4b32309098296ba4a748cb6d72e3c450976fda83e1cec50377735856ab64a0dc6a7be1ef3e5cc2062961ff6f0b06bbcfa32bc45c0281de0066b29ca1d7a17be7a178b1602a77db4a48bb75ad79aa495c8f0beab2d381d9293c889512da56f85d2c205731a0d68937f9384f2e0feceef5261d379096603375f9f4b515b84e0ed82e84bd9421c441bc5e1441cfc5c33141f958b714e1631b14199c6387bd96bd006800fcaf2f3e184f00e3dec38b9d9c2552f7f740b75093690bff5bdae5a2818789f5c80425c58b6e5034bf08306671df7c1f8c7581ee90696ffbb6655308f619a1e679299fc33afea08628d4e82052e256662829ed6febf2b6f6c52f4b8526d14d88cadcca8b62cb977ca75a478e0158f294769262995f6fee3179da1009b34eb51df62468efc9713da65bee239fd12cb105e1cfd4a7dbb8d98177dad4378be147b04f42c6f7434831e573c33afe331f7ff7a3056fc98467e184ebc254166925bf175c9a8b55b72b82e2d4ffd07695f9786cdb0b77de2a61c3434770b7ee1f1455688ce3c784b12355b04191d5de47fa13e0c00c2c4733040f1a6ee8b1e96bebba3bcc1bc48bbbf26cca946e9744e0575e0c50ffac3e049d4928cb7a37aa018b16e1d8f67698101694a85dd91b816466c658af64ff8dab9325fa12fb510c8c25655376eb968f3e9b31f961954e80b04121ea6873f914925bc1b33c243664e50184611f90e3dc217615f07dde084b1c04ed72ba845efeb631e3a34588e1eca217f18bcb2b43aa654ef6e8387debfed9006096e3d7976c3b1c00c419c2706c19c37e4958254c6686005e2dc9d0e1629839f8e863f876e09be2c38712740c32638b6a669e83d1f0457aa00d535bb754bee89dadd07a782c7199b528060bce485fb66fde52b4044913dc85473eda78814f7f19db6fe204043734d7969cec61220df17fba9c3994e968031443f478018c7a9f630e05a47f47ad10aec5ba278eb45c1df56c48461556fcadc9f0e80ae19d0b7cbfbfd286e6266af80a6718b68dfc83ad78c3254a74bc26cd7f8ec900e06514fd7a4c4b1d3ab17e3e356c8b44b3d8783ad27d4dbd518136794354faf79e006a66301e192d2a09279300ad3fcb540b15b345562a55bd1a0c5eb62f4864eca05799df1e5cbde52416c40a0156cff90be3ebaf4d3279e4a6f033aad4bd583316e27ab4686d336f2a58822e600d53817e61d2fb8aed9c11576f5b79c88bd71fddc688da7862cbf6886d6c7db8ffb2bb48c8da6e0d8005ba0430a6b21853a9b0bd9fd41137ae6bef2d93297b8a309e573c4733d2d467bd1a0cf04199fb855c60628a90c1e0e0aaa8cce001abeea86a2797055772bc8c597e6a9df4e125aad253e07ac8f814795de6772674ccf1b3d234ba9f1865fec358cc0a5b362d47652ee674ed5a01193425618d348479231a20b69a212f3731e7ada34595ad4e2f61414bf34d3ef23cc7d27f64f017d312c73532418ee7fdca39d6e3bec73337d127c760f141755e2a93d8b9d6393e9b066b53d8d77e6cb483a1cb72e7934dfc3144954140e9a31a1c8cadc40af4508dab3888da66ffbb6ab3781a9880618600bd0c727cf0c95ec5af34e8e2b6ba0a4878589738176cb33caefcc29a0a59e7354023584a594311b30e8d41f42f6a6a7c30d3c400f3226107fcdcb53603e97c538017518e54805fcedcf8fa051a189929c6631c79049f25824c7b0a2fa1ed6d61ccdf8b81539ce48f21e6138eabbb4172dabab51f6df013c5a168db0687f0fca33918463966871469727ae837286dcfcc87c04c67225d6959601b9e3bf01bcb53b71f0aa9f90fd24423ddd123c11c9be557ac4a90b7f1de2486441184b1de9857e04cc7db562f1cf53792402026c9b1986d15bda1a217b5a31bb92889517abd2c4fccd0fade9bf7b8dc0b813f94750fb25cf0c1d9a83067a68fdfc53cfd8f3d8bb8269647adfa822bc1ff1232e8c5efd4572f16b53466d7a0a09aed125f085b18ac29e463da9f3df77f807dd6c5fb207b6a549244576b2a2b209e6c717f6f4c345fac3c7fc82383ec826d73835275b403a21e28edc93ede92afe5e8f202b16539075c9c420806a3aeeac7250174cae26aa05cab640b24b6db10ef7287fed50d2478095929697eba1a9a116109d4bec9cd0c9d4c2db3c38f17c13033564d11e13111862eff1d035268d582de491f68625f8a17c760a3e96340d25442b3c182d7367f335c1c162ba67b550c2b45e7f3e14f2c8b5cbeb50a1d3f11923afe0c0fac7b596c39a52f64671eaa53ad17aa3addf58805f4a91c2227adc0b23375c117d7c340141a468ee049200326d2fadc8bf0cfc873b748a29d9d23763c5bab22aca3d53245f45fd350087d63cef5efe8512e7152ffc5c6771b7092e9a165b4ce47270e69ed4fa5426b6a2d16d4e029eb338667dbac52c344295f66f955c2051698234f3302e5d1545d515254b2b9529402876a6c09afd703089acb3d4bcb091d9ae3d8231826fb277b88d9a78b1667e3257e17691e0ca67e4b71a29c813f750479b083f7730eb54908b19b156e69c01444864105e186458363edf187a6caeea4d10c456fe3c6318869b47381681df190fba287aa0110c997a49908c71610a011120563e2e6ff8c508a8ea37d181adca052ba1a93f497453555cf4eec6563035963429d1658b99c888188ac9ec1e81381f2b085f52e419c0ea617003234e9f06abaaf1d39dbd57031f227692e093031ec5d1889a5f5b38c4f1f51ac1f366288b2e5cbcbf2ab42737909e4872838af1d490dbd5aacfdfae6ee012dceea0910cb2203a3d7fcb4f5f645e85c83627fba56c270a335b34974c08f660e55cdc4db07b57a23a2d63c17f79c0c262b79cc3a14d26411cb775a2d54187de7a048f94cfa30644f7ed829b29c66f8cc4201edc50d82445bb9a918a00b09f0b5168e500a9042e4d8ae62d1bd34cfb6e2c5a1910f615032406e5b8ad1747260dcca0ce436b185be4041e280d4f6d1200a4d06c526b54b3aadb42862850704b5a87552d913e9ad7a2fb209d02d52828f0eb0bc036f338c706a1caaec10fba37c6f9699fdcee47163331b39d586cfdcdbf2fca20ad74ec4d86b28df7e5d17cf9084f6abc15de52c831a10238250b74c0d4f583549af93d1df88f92265247c1e5c2a40cf5a4aa49b359af7fc453044a2afb2b8786d11bb937572c6fe46fc1afc4790f68595b76ae9eb1a71eecc60ec0a834114895191a9e8ef9cc24dc714210e2490a58c157872c8c308b6a5715c8ed8820bbff8d6350176dcb04d3f1247442a0fd41620487cbf2a9fb3033dc0e14a4215c6f4516ed118c4a65f1ab06ef9a7e6148031a41c5c26a490213bebbcd43555249d7b6d76e0f2798d67c3e455f801d961c196f0a958aaefcea6db962151cb2b96733d4265b67ed1e74385838ddb069da6813cef186ebb449fd04fd71851d114c19ba2253ad9a612003a65d772e9fbe9f23d176bfda3c370e21c77d9960b8c6e413451525b0ba9e4a2465023624ca95ca7165c1ac7a8ed0cb2b79da620ce60c91b961fbf1024d0eb2d6b3ffc96bc3d8edcaf1ae1a5a5954d07c5d02d5cff74673df6fc21c5e0ad2e52c66e3c8f7d81eeaab95ce560e40be196bedb3fca33761f8fcbc851b00bbb15c6db8febb128b5a42936198801aa8faa0e9e866754e5b88afe5ff443ab0be2bf376e405b112b3d941ab6d3e7603101623c04f9f5c6f9dccf1e399c3891008a0106f2a0ffc97ae71414a072aa96c26fda4043b86ba6b38798d5516114cfcd168fb414483795ba2896c823ef89fc78b429cdf79144af284939079352b2e2863f4d820af778358d710dc9ddca2c3520c546cf42aef31d4a0eb0818865860476fd1341b0ecbcf4235d256bfb2292b0617256eb5de696b54a18226b4996237c2d57a938374a209c9b191ccca099de7438052cebce821c131385460ba27421c6d9605bae20a45e00cba2776c674cf6b76b1cfafd7191cf9bb07bd7b29783cf38d72433810b47b27cda0bd54e3f11117bd8718a1e0f3ee0130818ee4d78fc4a0339f676ab8c3be0af5e83fbe8b28660ae5f9cee000db6e070d32b285bfcf7b402ebe5f38dd08147d2b3ebe837e26c1d3edbea5320a5e3a51d083d70ea314b50ad9a82041f35684053b8feba20cfa335bfcd98b3283be7adb64025da9cbc160cbef202778f3c3bb79212ecd847deaf8bcf1f8899236a082e3ddd7b82779de5a94da0df12dc0e7bc1f307bb281460af8b21bae04c8627893aefba522af6790b3feb50b4d4f155ff30bcbecbeb2fcff2abf698cb09b22f19d918b058dfdaab8a823cc7fe6936fe2d4a04c6039b99add6c4d94fd6a246af4df30038e1da00aa081783446bcfef69be72a2020f55ca6837b442ae75ebf3a59b1bbdae9711166dba81ef6e45b7b48a094e56bfcbad80e84a16397051f29f21ef1591253ffdb1eba1ad17557f414fc98357c256e6175d8ea568c8c763e9ea7700aec9e5a718ddff4228b8091b9ce6791d6a2af0c1fc18fd7f82b43062d9327073a9a81a0c5d27d7a76a206de6f7530cc6e6ecf022ba405b73f40a4e145003cd9e4ed32563b13790cd28d4381b4acc82b3e90b32d5d3ee05a6112b7ce6e5e4c727bb22aaba41b0c72e7616109c20f6d2dd04833faa83d14b5af71c7a7ff435ffa9f7ad8cf85297f193be949cf589e4f5dc0e6a6f36418854a9ea5fc0a41310ec36e5083e1de5e18ecb8b10aae6e3243b0a5441d1e5391645d217a4c15306e4ae5496ac090a9b30293a013041ea49f099c430fcee57812f80508c9bd47f6f46c01e5042f7b9c7b4c7d1639871340831b429be30cf7fce2614f7bbabb731925f81688ad1264971f79a316381e4688747252a75620eb68663a20386d8ab601388048c2825d9c1fabcbccea6307ce2b19b2dde034362f20f9f7bb8055cd62f4023836e9367d2572787b8fc44437b3e1986b48b06f4287324a7bf4313843abbb060d96c3b121ea0855b4572466876f64a5797b4d3f3cf31b42c2bc03b938b4ed35b59bd5a8a23b7612094e4f1d666441d8d11f46a9c8d303d92d551a04e79efbfee7a58baa53b00586b79375f7f09bbdd4c5bb14e899ace2e3d902b30cca123e1290624463595234cf3c362c5841ac741989361cb693a2b6c3d898934cd36706e9d3ccd9b3ce73404984b4a831bee0a5f095e4e56c0224b5d2c3c98b5a5acb12bb2cbacbc11c4a0241c7dddba53a09e732c1758ce2a35dea4134b1856696f3aaa52e7acbd7cb404a2382c31f82fb2d19b8e5945b781228902672aaa5129228cc6d3a445232860fd80ffcfdf895db1c0946ca8e89c2501016793735638790c13517ec9be4aad436447298056c4e1642cba91c1e2fdea13e87835527c1aeb614ede34aa4fb2e8c6ead4fef91f947d9e5393ab6c1eca8914c12308c486a8be203d088954872811373b9cd8472fbc2c3cd27e234746218db7983f91c1232a01182eca3bd9fbd0b10f0494fa677cc0a4c1948dc59683c6c87cbd5fa3b3249d444af3d7c0584896e90a848cad628e2ddf5361b133c7a3eba1e1eaa1104987fb2c84bef1201c9dbe349d9c583f217ceae136c62fe8da72bea1fd96e5281a4ef97fc58f8ef99258c2c0dd5421872aadf7da92e344e441b31b9dc38e626558540cf770377c0dae6b8d1ce47b0c93e2c66e2c42cabaff80c9fe19f123912edb17c6a5f865988689dff9d02b7611d2f53523a8eb9a64c5d38e5f3c2578951f1113b989de2853a945ed6cdb188fd9fa58104785d80ec81703bc491aeefd4da159ced79110ebeae729b93cb7f8b804c01fe58062fd9eda9918901aff4e2cd0707a810dfa07efc45475647be267e633cbb8642463e55689ce3c7c897da07dcc0f4a178afd129c4587d57a734551138d37f2d7a407591e1319961dc06c8ce9dd673a101df790600d254b23c4b81361ce00be42793cddbee0aa38185d63bee874ec16731294dac338e07969ff053a6260212ee3a565ba1727ba6f388323d0205dc297da33671a831728a1e1c419256952812b81345c603a5f179145749a86bdfd138aaa99132697f7bab48b4b19b1d003622712866f81cec4c71fd3772e6c0eab033b1e3af6b8c09812167a1e5f51044eefe6e27350c63408baf2a9c86aaa6a4d61f0128c6030140a63dc3e889de7e430319c352eb7452b3212d9239753bc9589211d461418b61881fd70283d9cf6ff62f327aa11488ddd20ce18210fdc7beee8e7e8ff65149f7a327a084dfccc49f682d57d2bebf3a0211ee402a1528300596c62d40b6552f430cce454c3d90b3c8608718ea7fd63200db7192797c3a5183ce4fb163b012e1950e89057457ae2aad81e786a6f32d1a6697bd6f4d9755b7997e3e45b86491e6fdce60a5ccb7d1e1cdc7d52b6b21f0421ce0021b7a545fcac833e4b217796a26370559e7f11bb70467b84c8b624da78db51e2565817d214f6e009d47f30c31e8bf72a623f2fe755935f9cba7620da556e96de9fbb9278906a8154a692af9534b3a499fc8a2a9429ab531acd546bca2294f0c47c3f1c4c61c9a500b130bc642874c429e9ab14f9bbc286034300407d00f0388315bb905a73988a2155d253382c7e779f0b540954a1f1626cf286e45dde60147de499d00a41042eb20f583e4cbbe1bb05c07eefc685575692e781ec204115a2da2268bc1bd7934280815090c0a6ef0db73a44bb238b8fe9b0b3260de0c1afbb671d8e7cacd6a8cdbc0940f5a30fc71c0a9cd837473e8e1c54ba040eb8eb863aee3d591101dda76987b6533e95e00e27655986e082b6773ae25c8581d60dd1e3042f6242adcc453433ef5d930600164764a41eec607706fff292f69a09270fbf57fd7c07a313e9619ecdc0bb21e95496cd275be2e8a84876575222db98e628a1ae0c5ec8056ab2a7c6476bfa6b1f99fb9486a8780efb262c1851f30eb23e8272ea47ca0d4681038cc651304582075a225b3913462a04632bc51f6b03a03f034d1a5413693f878344549006977d39d381f325b4e04afc3d8dab0e509aa75bfafb91d79b5d1481b222e285dd00fc0da438b987916c53ab693ef0796656a14c117d231f2b2ac32b3577906c7a2abca466dd08f2b195268f5b0a583c0378a99530573761f14de85b282748c8fb29283ab8bdf082ef83231f73978e3c5dff144726689f26ec171e0df3b28b84da7d5effb2f635839122a706e36ee1b30d8aba8e8212b1e9adb689d3f41ef1be947d78b0fbfce6fa3dde122e5a0a5eef00ea1dc591848f0655623d67cd5e5e99aaa03253fcf4f3c74de621cc2f849f7fe5da5d7aeb5dcc1fcc931bec0ff9006e91ff8eaa134905e2504f66ee9f97ce84b9c6b1376e29ffedf626949c9bf79401a38fb68abb370fb23958a313813131101745ca4bdf344ab7df7a638bc41423d5d7b86dcd8ea71b7b1ba1a9834ff91f2648c8e94f73edb866edd46bc4c7ab80c7ad95a1fc222f8ed6a199412a5959fe6de7968d2221e2b2a496f2ed01169153467f48edfca0a04fde9c12e792cdda0a8538e8178168f505bbd4c6c7fd93651901a6facf610ea956dcb6e373d099c9064cc89027f62a40e15e150c013357d224f240fc717f19491b641f56a1cc34d77d4343692b50d6c609aac031be8d9e6395b9b9f0457f7ad2d61d61c0b896f03f667dbd2f4b98c59baf03272171a8f4346e1bed193873b2a1d5a5272680cfa66857f2a934a607a2ee4c3a0dc790a4b5d7e73b01430d62bc75a6fc0e1c0c1ff09efa48d3529b4b089072875e88ee1d8cdeea96d7ad99a4d0d4b36e74be7fae3ee493b3a1097400b36679332ca1bd8742c3700acc945cb0962de4fae334feff7858702e1bbac7ba608396dc946ee61333a8deba1693cdd4a270201e0036c2d45da7269ea4216847bebedd9f60fdb2592160e6ec5f24961783596e0beb22f7010df381e34b03d5dfc39900d23073a2b509a7f99e492bf2c783e52204c9ca557fb8cc0e98f4a9c385f294629654e4569ece12189a678083a5dd3d24b3c5c3bdeff2ffa55ced1ed25cd954dae11bc37a01fa251641031c9b5b1bb21241979aef87bbfac239003f390d9997c14d8ba470911a1d99f06cfb60bdb632c729f3d79a839c84113017d197ad69154ac2184c2f93612c698f3564e031db719a6e5fea7c4ab4d238dab7235515a550a3b048dc3f996bce6e78f59277ded9a6ef0af715db0d5bccccbf67250b1975b4ab861a2d3bbe85aff87d135bc46f6d03ae7e4b313bd7ccfcabfb8ad1ceaa1a1c1be062e16c5b9293e2322b812cfc8e261f2eab294015254b384be12ef05e6545902cd7243e8a20b6325afe2cf1d578e71d62a9c691d3f62f655c5ad09dacd944c135f3cd27eccacaa9247db3d78835d0635b495a1e8359bfc5427e73222ea465c6d223f88bdedfcf2ebe2637af9898e9a1056251c65110e41a8ab8a6a818b4bffcd34abc655352e9331aa60e243b04ea0255a19db044d0e3ec74871bfbfef6afe40748428d7f94898b788f6ec82d9743820f86d38a38d084ef201e46c74e849811c876de555613075a51185914c4337b02ce81deabf44093a3790af912807057d377d6500f437868aa55d9130da23b8bab0e8624bc800b8eefae41d8f32821e07d0930367a3a70d218dcce55210282da01029e3ec15bf24c67cc6dc938de9fea6a21fd1c8cf47b916453b8bfaf0784f0348c4f2643fd6fdd586a4329354949e4516369d0c035629f302d987fc0365edb40bd64ac41d5d438a09ecf01f7497924edd12671e4c5b7077e40b97f89ab2275136645cab0a03b53e94328dca30d09e9a6753cf3d6bc39a3419894144a095a75620f8b53f8c80206ea6f09a999240c17dcb401e3fefbb76c73b6050810c87aa94d0f90fe5797e6dee5ba0904d659021532ddf5a3eb54f612e329c8becc62086bc8b350e87b075dc0a12bffbd1116cb30dc2f780d13a5f3a3a41444f9c46654e2790ae9126453858b602984a007e7efb30ab10c714a80a31c29b309cb018211294b69e0c7a16ead8c1b4e56612693a6cd7b6be98ae41dd409eb45e813f5f3d1440aaf1d80635ade2b0fa5026fda5f43947cd707526cf9f9efb08049936a610085d4e39b210b80e65cadd83a4a4cd6f0496fda19fc28dacb6abe3f3262204b338d32e27a51c42d9836e126c8c03e747881db53d351941cffc4df27e9c39cb67f56ebe91884100114b64e171ec2425de48cb30233e74d7564384921a7d64018ef7336810d44bedd7e159b49f4e568bd5f70d66fe4a3a951fa471a30f2cd3aecf715e6d228c729f2c3a0335bd3d68770a52b5ae954723e64e9deaadfdb0ed527afaba516894967a21e7c0f23ec095a215e4704057d383e897aac69210f8b586bb8a9431efc7773eeb8091431b12270629b5779722334d75f95a22fbe9f958b1c1b530aaaf491604d89ca00bebc722bd1733edf3712f51ba01b97197a2b48e8c62d3b6895852ed5e6edd1d0ed9d9a88995446cc06f0de9de03bcd5df3406a45807e2065605c3cf22a14b1457845ccb055de269a61852c07bc8bb267846a78cde558b5191992e0f0f6b9a471a26ff6e73108a174d3c3c5e020f001e888109b8cc2db315f4462ce388c85efb8cfbc6954c2c0b8f8f48628d77a2284615c263db3cb3bb656fe01171406c8246012193ca8b32082a6aaef0aec87adaa1d2f43bdf3ea43a4c24d5258fea705224702567756ddfe2b9afdd4f13362a3741fbe0a83d0a86586eea76fe9cdefbba0373c3e360affc2be04b72c004aab2ef075ad0875d2b5283292c5495880c1bb13b13611a66ad2b02deef77d5c8007620069249902b2814edab4c130a53105b295bf79b6e23a41c5ac617e90456dc69190ac113c67962e89b518a97c5b05bcc5eefc6130cfe65af303aaf30f74c74b327a270418cc699b3a3bcba68fa9fb7604f6f80e1c435dfa1527df580359039422d2bd8c3e613d7042cd4478601159977e8d0e943d563129a9fb5c86614d2a72cbe8c72aa3bba5ea5798ebb8dddc2e368b5a062e810dd571529f6fd6331aaecf6f23b8fb6e03e4b8d0ee99383e41a249801530d4c28efc5a35ed8e7d0292d467441706cef7c7a365554d5180e44016245155ef7226891c67375a32fc97c3d27df14d7e38e8aaaac7aacdcefdf434c9e01987b99f352dd8d44749b01ec4777f9e1f7f2d0b6326dbd73493a0e81941401ab423b71affee63d933f8d9e55295dfd526eb463821586ce5a0f55a47951644812fb5c7f25c201030d546aa4501b2ef632aca3902dc782d1838d6e19f1229c47dbedfdba512e34233d8642da4b3892e193d6056e03c8e19c395dd37a6c1d924d7bc69f088de661e1aeec25ea705344b89d5afc7c3f8650d8c2d28db43ced6c92fc83c07128096cf986a5768687ada8c76ead378564bd5387ed3dc2ccbb0f9d15373600968e892b903320da3a2a2b5139ed35a788edccdce0e6f33e2e77de6c921f4645a29cf60566050d6a775bfdf4f5e47dc785f1cac5e72158fe1c0c499d6a1a97834ddddb7fdb822487fd2dab252dd138d8b0994812d9886727de3d4b32c197304e597b7a243decc5ac759b9752afb42c9d7efeec5c25eff2a034636be4aafae896babb4fead4da5226ca40a29ae0d84beafcfbb336108a82f95b9aca1ff1efba00a17c52b361f09922ecc388c222aedcd41d03584845f7a014b394068646ed0690f17dce2cb4afed57527b6ba066a99760dc8ddad8da73c3e422be3560f297dc58c01bd217ae101795a53bbee5f29cb532bf1670eb87f02bf2aff8422c6869ebc6d845167814018c704387340cc97803570d03b5c7558b4c300c4163995bded53ce33afca44dcae6acd4dff1900e7d03cfb65a7c5b39cdd086adf3a8ec996ac376b399f78fc6c435b1754ffac16d4bc15da3ad57a4c12cf95eca996bfc6ce045a9083edf7b86cdbe040380e2b2ea548fa1703babf3ffa55ecdb3e778b55fbd70b763fe6c6ea310e9b4e806d43874efc20c11da9bd1fa01fdccf5980d051321f2ce1ee3b0df5f2a2ec27cc70958cd1625b70b694ac4f1d5a37b67053e0f30974eee66174028ebf43cb1045bbedb486f64d264dd1ebfc950c31e47c55ddfb3d44c87f34c2b669a99643f169fbf65ca079d55c8faae32e37e75dcc8e1b0c517a9765a45574f5acb854bb0e15cd845f606d580a275a7d5966410590100abe4bf974b1348c47a8a1b90842a2728a546da8e23d4637f75d08fa76c83fa59b6820baaf8bb00eb5d7451160fcee6b76721cd9f518c0f6370c7125358a9d8490fb453733ec26225dc5f0a389314150a5f536ae150557cd1a072a2857c80d9d79629a66d70f8c858a24924da042bfba3f6af8835eecb9f0d36f6e84e1a6d02cb0b34a4d8c4da29a0f2ba00e07d589f82f505e1506252b968dc279edcadc51387c93082674dffc2824d6402cfec21579c0d2e83adb1cdf61ef5b1c133772fdc9735b2c2b6609d4ec1037b393c073b26b741cde7c7f622c33ffe43c99d2df69c397f39592b7edefdb762c916778276a5aca98a9fdbcae94d9c11ef9c8b7ae0dc6644e589104328e2c4c96b65f85a6d5ce758dc0c7097a35ac842e81ab9be07f1eabe1f81348165ce861a92dbaf9fae248c8a62212f7f57e3a5bf54e3e7c1cc3c99317092b7e0f190710dcd2c580686f250ad61659eda436ad016254bca2ec15910691777470acb49ef75e46e0255a171af45b97c16b3aea6c8149dcdd04c31ed46118da98e6a38798f72393420231e084e4c924e25494fbacf9d1a327d526d53775334f9e5c17a035e84f3e38cd48557e700808018cdffea5ed4b515335813ccc73937da6daf888d1cb3b73c7d137bebae064e3cbe4d0c7fbf7d4e7f933bbe2e99c64b39f3bf3cfbae4ef24c76fed2bb02e60c270102a883e20ceaa54496b0941452aa283457e96b5458f117966759a206cba605bd90648f3e2420d86ec29a7201e081c0146931c03c310a3b8b84d6321b0b839d958f6c1c8051db7aa144133040a7c9782b146bfedd0bd01f31376f4c1a0474016f2151925cf38a89ad2478c6200ea9526e9f4ed26d1b5a7bf2a242a08b240ce91b8197cda2ee3c0a0ae23a2176ff0800877ff70384c5cf8822f8959736d40f6ce323ae3419b911aae896c15b143437eb2cdb4c1c1d4148c836634e7012b986675b080dd80618cdf61cf88eaa353854ba36d0379f906dcd298aac9f8f9ce1587c624499d72b5e7fcb996624e4dc548869d055a4f56546042cec04299e8d4298d909d7df438e3235d16ccb6150a3771cdce36b03ceadff59d8f80c708426102d0ca23cae81090429605513c446d4e623b522d8afe788f613cfab61c21743b9d02560697803ea1437a585ef22c580f047ce195d1fd543765bae341b72468b0a6adcd95e0e048a553bbd6c6b7380a5f6cf0297ca6bef1c0f12bd5413c5327aef9481e530feedcc1f946517a315ed17456fa2dd39a6b37a0053c88b621865afb41d47452d8fa0425c6092c08a83ace0a48d4947f628b961b8740fd9ebd31799ca40d2396ca0f86ba8e1a06190fb9e8469aa8f2e2b69282299c6480ba124df9d8652af17625ac1dfb7e544e79fdefc57eb0edb7d84a5d73ce0d0053c19e79c6adbe900d744d118a2c11f7bd419fb828b16810a8f6d8e1dca65a155c2b434f5e939cb7587503b562b8404eb695fe2a1e233770677933a400c6ef6586c60997e545b058d6028a06a3e17eba648b10a40ff55809ef3f938819156bf7d4bcfec0b27f45c437fa23b563b5b9a2cc011c653abe2017414deaeed6ac8ed03488e25543a93a7c7e7ffbd75169f7e73929ce58e8bc648c7792375144290478e9b0d0965bb8df146fcd20d807ab06a9239c992a4d5600af24490b1617a01b8b030008f460189013d35070d952e20efeaae58de3a6f4c7f9e45042714457400e600454f76b4b9106cdbbd2c1aeeb73e758e8faccf2f99383eef006341672e8d2ee46a93183f6c15ce494821b127bc89063292b0dc32b3c78f3379067cfd2a4dfd64e728f96b244c1576f4168aecdc7201c1cdfc2c363d7961df64bc9a1279b2de49dbc3602730e3e5ab3c9c171af92bbdd44af50cb817376ac7a8a8ab659b589ff4be915e35dc24193fcb7691a1adcd4f4225273819364590f660ab5f954bd80eaa1d9f61c007fe0d111078b00c47c68b41b0b50a5fabce08a6bb7e57d626fdd0c278220ca0810134ceb03ad0181eb6290e0732e396e0f1d67446cff7d49fef72c43b057fc3137cc8986b05f9ac1f3bb961a97504791be5f27eb6438a0a5474e5da4ef960b42606cf56d21f8fd5eded28c8411b5ecbbd4c3800132d86fa5add89267f851baff65dc29424e687ae736c9856b7f8b78d4770bc8816e042d33385ea2d0d516b75d1d93f4224f43233204995088f436c5b1a371a5b4f09a42111c850df2c2131f504537af3212e81beb49ef438a5fd77096d1c21250b64380bbe5e26234d609fe7041f160aafebc8ecd38d2996fa2730a07bf1139c70d39f1505dd0a9174274c425a62f654e9b82ad202050a91f49aeaab65ab9538c37409c7d3e8a0daf44a65be862d58e3d59bc1ac380a10db12a7a82ff469544457c92ab69007329b06f196ca68021f721617cde69e47c48c0a55d851a5d02e9bad0c10c47a3ef6fdf34ea3eb32a686138294597656f5ab029e4c3a04c9ce0fdbaa7bd97b265346cc6bb7b1bcf5b96e4f50eba191be03120770e04a7ca00c647ae64941791185f34cae3e502dada49fb52b9e68f08dec4166375c0c0abe3c5096590e38ebd1910c003e7201311303478521e5e37d473266e7514b1ccaa068719edfcc75d32c22f8256b8fa68c54c705c2a93909eead5e999dbc116613149ee5f9a00833448a3e1371a44fe853f85c559c6f58579c1f14d35e1d249bbd64bc6075bef6445b242b955be94e476d26ce77eeefca37a243a3f9ef0808e009da7c46f57303eea010ca4700e3c89c63d57ae8647e0103a8d9298a2b07710c53736b07454ffec31be17fe99926693f30712541f7a4233032cd2799befa2ab15d15f3af0d17a13e0150f3222fe4b55d7e507a3a28fe7519d8fe6e39bc9dc3c70e6d13100a431767982918e0bff0021de3a58b33056c1bedb280b093169ffaa030cee03fe152fef2ddfec857e297195de120afc73a8f3d13f04749655e4c2ed9df1b57c2e32c1cc553ae40629f1bb3688d4de1b01005632b24cb1335d8453d25110aa7d2c87559db5d6aa2db8256fc1928c0f7dff7670e685101999481a53215a443381741556c70e99b78be9e704c85d0df119c9dd413b88537bf06dff8ea7abbbee5d6a9d5fa77a336ec00023dbd2721b3e46702c8c0d69a6b77904d3e25bc1de923ce62b1320f3a0d470d8db97e2054fdf675d8e4e6e2be2a22cd494f6f3672ab0e31e302909fdae2a6246894585abb25d12e61949007e6c0a4ebb62d86c1c2cd7411f8f42aa90269c0ec60de50c6bfcb623863950418651126908ead51393df4593720507e2c044b7ddfab982a8f94cefa985cbbfb6d1020d35fa831bfc1d02ab942b37e7695969a28bc5e8ad2caae4b3f3d190e28330dc26fca6836dd25b227094c7be77964976c9a727ff595c73f9aa6eaa4942f904d4ad2bf27204bd384d22bd1b2d943e57996f3ebd242e968429f6f82d0d8dbfc92c0a9b1b7c077a0ec16c5892979f8319262658a2f2d41ac2f953bc64cf1a33142da1b8a3967a0ada0eeb5d3054e4267c6f6ad6a445304b6711d38516122bb36763db3d066b8d5ea68b46fb0800d9293b2ca51b58e9682cb656a8f951e3858d046967d68f40f5620d6e893104761431dbaf71ab09176657386144634d8fe1704074397b1e330cec3c66bb88f9acf61420834e78380366fe185d470eebae6a17b5c70c81b6a9800a7637f2b3180bab1382bcc8347ffd998272910af2b2c0da1de320914e49c93885f3cbdf5d5ad125983541225498812b1829ac7362325ac35e3f5a9b78f9c1b8e5f1f615cde33a61433eaeb65d09b49a86f1d8c78ceb7477a60a4eb0e76517020f938806990576440af4a574fbfad52dd826034c7a1d28b800ca9552fdb39185299df1e5bca918a82b55d094581ae6c605b6c3d244c385e89eaa6d7ff87d62ca3b8e36de8b10727fd231a678f8caa682ed383a04c6aac7f957022110b4459366580f206e420e93373e8605b6a04e37d790743e7243325985979b43a9c95e032935038615325b434736bfba38601872f7ee91466403788354b9c1001df73dbc8911fa5f49c6d4dd428e962b0204fa0c4f8a0799a72a61f64fdbdfd2099e4a99b648cc8bf9e9901ba216f1639e79d79abf5123a31aaf3e7384199a037eb3485312d3e6f9e00e151c6cbef41088dea41124c389f26ae1a646a2aa5a58fdd91343205b3994d0e4c354485a4ab1698a15778fe7decb78e53c5734123579fa4840f800894182572d2a7baa28677a65cda6ae8bfe0fb28e32e95edf536161d1a2296b49445b908d0511a1328a1b100a7d945e829a5a9d7b6322ebb4dc07bb4605c4e3ca84901dd4803ba5881e9dedb018ba2504123f41d54bb77264baea473f6470ad1096561eef4e02723fbc321ed43e5f46f3c68cbf90b90ef4c7e28314411e53bda5fc2485da9ca4be4bb094815f7081f091572edb35ad32a935ab23630d643afd3bf671d942eb1cc280307bd9025a069879d657ac161a409d243b6d3c2de5c1bbad6b72561d8f0d9ad0400c2027106a429828738abf543d39028e9fb16aede11f3048811e79d08b71f295f1a2c16b6e4306326fcdfb09f0837cba0083be8b4c93198178eff15fda11bf59a7b2939de1ae3942d20488f156fbbf193d85c7e9e0158d410e4baf6f11d340c5d77f4b27412aef2274a3de9ff08934c5c732ab2b7031592b2e667d19c5a812e54e250a4f7327d7098f697985cd05ebafccec3f995f26fa385c7136a86b22194169543bc3be1fe1394a8f897c95daf8a434032841d4c86277cc5e919b88bfb00c9756dcd1a0424185cc3dad6098ab84b1d05d435a441fe70d41782a56f2bd5b67682838843e1c11ac0cc397cc8baefeeeab692d9cfa2329a132ad730c107f8336e4991400069f793662e65de67cdacad5445f299faf6d11bc903276dfb982ad3167a3405eb92b622b6ee0d2f93d6a8af57487cc0a114401a4346828adaa1d8531a462a9e84a143a3d871768f60905b0d8d08877e3082f63a595b1bda5e11daacaffb7f4498eb07b00cf5b6c64a17e8da6d4d70745bdd81d9e16016afd33f9a7d78e1b6a60cca6d9dcbde9881795b3797e426013e872bf5f0d2db6587879102884a76f2e76d66e1b5ddd426a3b47607a84aa2a51568bab4fb141c02525ee5e1dcdc0c423fbb1743c80a1bb9eb873c1c6c8103666f394bd88962e487bfcd4f45afd09d5f90fe6f60071bbd02e16d85456ee0489d9565b84138add7aa51a4437ede145aeb8f26792126b036630a1687cde9b492ac5800dc0b4c60cbe79467a7d6d67e63741a630bd274df396e915356e32943e38dc9e7d4a1d3ea540a4db76e04d263798c42afa070dc437cc4649321e894d2fde5dae700b1d0b2ac0135cd314826892f4ac68842e048e7cf2a2d79069587c17671b416d953ec0773724b0ec11a8ce7b42c7e420df9a000f85407133aab987cba19a98dd92ed393112267801c8d58501ae9d5f0d81b4a0a5d5427081dead6f5b00b77b17ddb8dd623d7407b88d30b875283c298b03e9ef610ce309cac70204b8346fba11cf84b67941d03889a3ce0c9b3d49521a71a036389ceac62521cb0d607ebd4d4681523eb12988d960cfe95f469c4eb89ebe704164f7a7c8f250749c1a02e95e2a37220988b4df8028d2d24f08a827a7254b5845afb955bce17f8030cd17ba503cb4d5b52918fad9594f85f3608e0c65974e715702f5eae4ca0cfbf8efe58a31c9eebcf3361a12fbea7d0aabc307c93899a7b24a8ff4f3e58956e7b170396405938b7311b478b74edf74bd2ea21cc6a9b3dc0a750afdb73e14cab110920a0f69e2959f8ce7373c27edb63379703f06c5bf1449363f58b1e2b32726606c249d3bf19e60d669e738e0c448049777ef836d3c557d6dd0e51f3fe6fdbe3e8a60206c0e5d1b5bbe33a057745421600036bf11f9d5f6f53f63f1f01eb20d792eba3944123b3f8bf5e60339c8ea39211b35932629072d98e4a12942af1d3465d281db3a05eb1d26732b88b1bb0dca412c4cbe87d53efb724081791f2e9fa155c875446c57cec345aaf021b3a017afe3761434a5116a272e388edfc7f35cfc8282d4d1e93588207ab1510507f869474908fe9bae67b105ddb1acd3168672ac71ccfa9a5b4856294e0fce56781760c60134f0f9cc7788da28957106af42fa0c387e95983896814590036c0948b7fd5c69a6ed21456a348dfa97b4e96526dea1722861377789ec25cfb1c68e693c7a24bd8ddcac9e19d13a07dedbe77f54bb0ad7cb2a70646c1afbe1690810b6c147c50e6ede54a3f8625dafbdd5483827a2183bf2a655d9e76fec0dae49bfc8406dce6117804f8985dcfa7bc518e127c28d4b1636593f71969ab8dc7909d7ae9d152ff7b7077039730353728e6bd617a7f0ff2caf53821a144a83b13b89ff418bf0967609c144af819c30244079a7255543e7c8ace0dd06435c93e6ab55810dd63e0e57fe36bd79a7aba9d829001dba926b17379090dcaa80fc9162ccc188ff50d101cdeb6e6e5e639f0dfd6e33c45a22b4a50e7275988a553d730bf4c652c7dd4ab0ecf80072505c3dbd231471d5d6debe8d798ff6d3418b61810249d07f91c54e7131ea2d23a2f1499852c1ee02e9f49c67cb61edadf5bc8d8da036403401a9b6bdeb6e0733702bd000e7192662e59161c4bca2938d67f5d772b2d95e0c3114987f22773fa606c092c11a9c958158b2f43fff52f531f0f0fcdf25539eee75d1d78b56af6b4bc2f471c2379eb3f83daa4c88544f8cc5ce82e057c8e75f6d1615c39844901aa6112a8e2e1d67d24128a17feedd69a48080245e2d19a02b0a597828ac5e0041d108e450bd38efd781a6f46521a3ce51ef2668ab6403ff65e0f81db220ae282799105750930468d57daa10240f397a474480e89742ff9b8754a460e344d513a071942468aa951520db133fdc95f5cdcfe5fa7435689a864770c9428076a57b7aec5b01963ef583559503dc677c4195575ff6d6f0f5e9511698a9aba00d49c08069762859d5602611ff82dd2b8f8ff92373809ffc36049d7776e439ac1d5e03b3c8e424aa3012a257da6c4c8831f2038280e58431cc386e77c4a06f108b9915a7a0948f51a1c1fa7bb90b7b6de945241282abba364bd27a8717101b9724e81d4c3d4eeac948542b1099a624ca15569e4e304d959ccb4a310741539fd4dce51bfa6ddb9fc497446132d4f60c4d9bc1c92c65818180818d74e2959ae5c823e6c225e63f9fb428eadd71f83543981cf85e9bd599676409ac370b7396ac3c1ce6601ede26bca5b5104a431600c8816cde9fbf43e2266458ebe9d1b9d061fb6d0a06209acea77beaa533e7c4f5b07455b5f6775f5ec9476ed292e576dd84651a9aea61bdf6dff3a66bd68b674746fc20417a789c7b50e4d3da1f53c5e4eeb31e3b09e02882ece16947a2fc661b39affefdc3592528179093e10a9eedc5a086e42e4afa883736edd0326dae183d5658afa216d7fa06e9a88535edda315df216aade1ba283f891c1177c1a8231f25ae0fff6cfb58d3e126379f8cfd06305894698bf53a6e44fe7732fe9199ba8d5525a6d327ad8db33fa2e8e476b7ed7d1068436c443b0ce4e7033de9c6781f14a6c594ec6b85699978cbbaa991a3a9e8515b41d7abf1d3f5d462147aec9a3c7df8d0301c6cdfba2161a24d2516c74a1fc465f383f01c4868c626a11c15c81727fe86dc23535a0e661d05f4c9dc52c6b2387a0b82790b84a56932902fef4a03b61867456bf8a138265808df82660a387e2ed34f5e161e1ec8b408ff150737e400f94e6fdde14e53871b79c91491f71877710ca804047ef6243a47504cd02607c8aa944f43710a318a5f80b5c7a33ff62ecae4fd7562aaa38cf7df872857df97ec79f5c392a61097d5da097d677f5628662b9800769dccc5d0caa2511995317b5c95b41574e86b97af9c0bfe6710152b135281729bd5225d90e65d512dc111163e7d24401f8b3f64fc66236fe7f45efcfc55ed2eeb49d1e1c801f08901f378bd69f8be916fab7a00504261aeac3ce61a247ae868bec530dda8bb0ea3b8f0a8f44ed0bd8b81b1053a2faa3bd4796cd605ad06c3e594346a78a1a6f79683a5b26413c2bc7472e9769644959adf0736affa08c4bdd9c7fa3fa72dc64eff888e6fd905c458f325e3261d3422032caa06ef85e450fe355dc4c027897ea4ce9714aa2e40b40f6244f992db51545921e757d3268ac770c395eab29141d3c6a58730e8bd428e4a11a22eb45f5284d7c49700a8092a0b6ca6fd765c8eb60394ed0f444cef0c2d031179376b998bdfe39c5224f59ba4fc7de184f953e5440fe57f70cb5fb5446a4bc83465eceb1e2bea923ebb08e9becdd08c369872f7b490dfcba695581811f91fd4b5d50683df5e4efbc2a7b6a329b7485c12496f154fe962ff541f153ffb369ea4c2f9a819b3a9612009e500d57c366d01ef21b00cf1256416bf0aa64df84a8f8d30bcd6cf3de7ec06c40df56a93e9bcb0a9a0d746735f8ab3d07dddcdb36b8d492fc3da0a6160b9ef4bfb8cd046b8c5cc2983347d861ccca2ed6c7b44cd3bc1c15ada01b773d4c06c86cd770dfbbcfa7d884e87aa8b3a00b04ce2c91a4e61a41d2055bfd16345ba3d56b457eafa1955d76c6e0624bbaa2dc4cb88db06d6162e24aaafaba73045ab3e93f529e6610ee4163a2ccc72b105fab6addcfe687c6a501a92cbb00bfb239dcf0cba81ca82b66419ce0816bc92e5085b6c373d8455a888c9066e9cb5e84295df3bd9540c583da1dc138aeef6003b22ca32fea90308dd6fe762ab2c4d3ccef85884d699cb24943fa1f04490478e95de1236cc9b024ce1785a4590932b57bc40d04df12c0369326e29b41053b4b30dd4b7716e5b7c91178752451e224d6c856ed206a345f29ec439be3541e0c773babdbb85bebe3683cf923ea474914c0c22b949001146a09c2bf77f0d8fcef1c8a1c74bd5d589b6689e8aaabe505ef3dd1e7c233fa3146fb5d8b5e4fc5ec37eaf44ee9893207dd389054535529e15459921a0894e40358800089c5600643022c28eb971778c30eb032feaab460a3f2cf19ad2f04b2754fcf12d1af70d04244efb0d50aa1fac02f85ea5c51c2d553dd4f12d254addcf9745bd26230bf0fc4924ce91bd8b482b54f1885b5adf0594e7eae90bfd75b18f6bb0b107122950169c8bc716f5abdd4f3b3ec1a95ea0feea82bd2415d7f30bfc7ebf70c542bfe83250086133d754264cae015d641968e27fd40a83921bbf107181c106892962296bf84c6d53b7bf3d2dbc0ab928185e054971f1eb25b0d68de02c0da5e928e00d43390ad11cf775a20ca66202631962f650f7c5d402fff520be952d3630cd16305095e007571057cdf93754e91abdd15f2cb8d73648d214b23a4ce57adbcf8b7590678daf8a9a98ddba91e8e4664f7a4f27beb3e43cd3584c522756100a94c5596903f287991b8d41c012638e216229f9f9e9188a0846b0563f5c34a0c47a2d86ee7e9afff33af7da4879abe57ba2c5a8a046883d58b1c06c004b6860ae1a40c302f740d11e9fac72d59fc5f665cb335826eb93b3f259d99c9afb406afd7fe37b377a8ca4a3a72404465d28b066624cabec6b4f472f98e43d96682704bb96a9307401ff1b41dfbb393c0a05a9956a40d7ce12758a2024b99a474ea603daf3f5cb52d3bd9c328d126735f696c0e76b5a7bf060918e53f247ebb456bb8b1909a0cf6a2841f457114abdbfc2e22bbacc7cd9b025e6765519f59efca39af7e80f539274c8c0d598a8f24fd7a4addd3861cfbc568cbfa0de87fba0e95be132e79f446a1c385a76248cf66c816b37588bf188fa6a43e92ee6a222b8af297da087342e1fa717c2b62162df5621779ae4fcd076da873d90ddf42c6101c695c788cfc579672e537d06058457aa63a1aa19521bb81024fe6861394e665b2e7a33ec0b6f384ce0b9bcdd794edbd7b05284f2324c7a2123df064dd0a84b5c59c22446329f66878d7e165168ab73ec271c651e9b43292e8858874eb2b5765c02a9b34408897827aa1912a695b6bc7fe635b95dbd4d73c87a6f4a90eab915101cabf5bd1e56c8639a346030703316f5db63f39a8a64b9fc490620f7000073469f68f7b5121e1a65af4f612cdca6b22c1febfd4a1a39ac4560b1181799bb2e22b2e57731bdbb4f6def27e7a6110c673150e8f906e724d8ee4aef2e7618350ef308ae5812e388e4ac852d33144bef5072b1aad47f5435ddcd132fd0da41a3c758a16dbb7c2df5a4155d0a191596d98144d36e7a0a537e07f16b92ee6b28d81b6ab3f3867a448f03edd91bd0918147605c190b8f2c99fb97687d6b550e086aeb17a040ab9f36055557bf32b59f7f6a70454fdf437ad49d164c7aa4cfe6aa89049f4110619458b390fad1cf9a9dfb0e2636e8ed61d25188379986183894544cc9595b4a761fca035b95853da9f1930b3da110d75bec2b616729200502cb56e3be43f3feffdb0c86c5c7e3f011efb009779a932fa6dde2c2fbe453441aa2c43edb050a147b8594494620c4ff0097350863b096a3b6a647b646bd0253e8f36fd13d1adf7f1476857e90812268c518c4c0b4660b592bd158971edcd5a9ca8273ccc68791b2c5e50059a1c359376e0d98e69be74d9cd0c0f93a27392ce7dff2b78d2222c846c4340e1edf389b5872794963c07bc06425b907617d177621ae185ca551474a92754dc3129ab8b5f7c24782b6477cbbc2be80655ed0a1a175c2a9e93dfa732f5a4b5662a508ec6db6edc1214b15c0208bfda5519d40e44672b5109b2711884a1f7a1ef8fe05aa7df62baedb92973a601b610ef5c3cb842d1b67d7f0ae347f109250f350698e31295a4f35eaed8a5378d5b8e86f7c7332c43a255daabf05eac0dea6afa76257061744e6c07f7701c90e48c0dfe40585d475a3ff074fc4781c90aada519757a13e16b2d22a94e1b8f92cf30c98b1578ee82e1ff299f4a8bb11543a985044ad95510bceada89198663c5edb18e2ea0af58638fbbb71900325d70dccb084fc37325b6a3234a57c401feb107d55cc3a0b4c97f1c2fab8e277a34d07599d733038403fdd1cb05bacbf7ebbd8a88bb1c8d7b895d242354af496e3b81b3e0cf1a1d65b9a5bc5a4e78b77601f19d7cab8bd5af065c582c247d77376bc6f0ec791e6eff165fce852413c5d649e4c002ff5479a2271eb09dfbf8f731485af3961ebf6c68e52d61f9ac2d8669e8fc4c4ef025427f8d4ba920c1cdae0da4b73ac03c0db74a383bc20466793278184f08f81551800dd256c9e473742495fa4e08a2d23599b60f6892378d4fda902c07d5e386faf2335742218acf8b52f527924710b0837586f3a09cbd8b8f6c1e27bcc87e6a9f2bce042f2c84ba1ac2dcb2191b6985f0217e446d38abb91117cdb6a75db583ab74ed3df8b676fd9f5a909301ae981c815d0573b6f45282713d5fa2a49e4570ba6ab1d603af091f1ab79d852e94478b708f4847193250e0b3b3c9be3a97bc8f542ad69d5202fe74adb7d08f1227875e5415826df331d3b8cb53d8128935cbdf08708b553f98e9c9c42aba2415408882a2ed0664695fbf6380d87ad60bb39a5528b9ad535fddfc62f5cd6bd9928101e5a547c6f7def1417b81cfa81f266db7f23760e7d72beae533b01ce04f330e59985c5c0d154aee9d6aa4fb7f7d42c72aa9bb5a2bc86af9731cc640d40d75414fbe8cf62b11d2c67581eaef72a96ddf3b4a1108d626265bcf9ade1201c21d6c08e6b0ca846c72a3939db751aef892d5cf856b02286ec36a6f07fb523d3cf719f685c996ce3fd6dfa375b0fb8275a9b3830d7f344b724ea3838dbffa325b8f3550e0e573466fdbd59bdb943bafe92bb49f532132d142a10fe087f400d049cd6f1ec68612a9bc6a92741e52a376265cd62c1f5d8959337cc2805e49fbc2e6e42156533291632a8cee44a64db9d103277c6b0a5ab2c8993e326d694793e52eedb9f27905db60de128a4182cb48305eaab2c35506963cbc95cb990915235c78b02b322411b00bb8b70d7cf666b374c4578bccf2b5ab7f7f713a4da8d7298c18862b0ee9cda16705d11febeb972a87b526c5d5c43c37e8d09855c76760b0d3db2ecf9593bae8d22a90d04c11e872fe31173f536481cebe34395d8b898ae2de9ab094b713a04ee2d5292d475c67b4374c9a669fa524feb8a7c60b1329c846fa993668cb2684b4a80fc1094cba507b157c7dd7b024d62fe77a1b83c14ac1d67a7d4b794e352f271b5b05c6a223830211d7b6f86acaa8967d69d515f0791050c0d77c6df1d414fea1a2e35b8c1ac39967151cf426bf367592d39d5c2590c0bc68c8b15839471ebd0658c187c671a4c97d8953c42d738d5477df101a1eba6cffac020b05fe807fa1ab7976c778739176a5585978dd6704432cce835fcba104e3f25558e62d03562c20951742df3977c129bce8e47d3f76ec5f3b3f0d6337d978b9d1ad7cd10dd1de92f6335585f2455000c2a19653154e7303f874712109b35b581c5f9314643e1bbb22058faf42924852cb0490dc08cf95f0e8e5114b45032e1c3d0c63959b4203e8a4044009021a725b034a7168c43addeea5159b34397e68d7970187c63b630ea6c5a1ea374ea8332874308f6f771eb998cf1063d32b16c9092af6732f277d1bef3f66a7a77ec1fab91fca506dff29d222868ae361f43e3a60a9169cf82235034e61261bc961959592f5c426e7ca4401e8532a4e6b89afb47451b5a20e34cedaaa4808b526c10bcaf5a229a55b0817fa790af3215a7023609e105649f71d94785880fae7c76042a42ac99a5ce3db8a433a1de5f702bd5367118b436ea048d4e9ce0338d07d0bd039c8044b69a4c7d2a74ed4f0144484f4065f47c50b284ec2cdd41072962b0013d7b5435a31b87a4d2acb150a3e613a3aa147dbfebe279066d74f639af7a21a48c509cf6a638d138d5dc86b081744b02b085cc70687cb05a20f6c09e6bb2bc023243d77002c2c38a445dbb9f30d262edb70544bcbfbc8a8abd6860806d5f4f527d74661e0c13a26ad0ad959d4947b4ccd17d6b19e0654f087e0aa4b51912cea40481439d7e638fd29a671505341770741c575e5ea495a8d73f9a31566c8c17952c1ae789830a602a0a0a72e6343f5fea6778379ef5c97a3fbb7819078228f3e5f8931851cff050a899ba3d0a86a25d3b875f23d5f023bdc5668b5be3bdd416e022244af975154dcd957e1acb119a24698905e23c426b936239b63c6e8896b82dc247b3ceeaf2a423a9eb043178b923a0dbe033e2d5a823047f1fbd01e2fbad3aa9e76f84ab6ce0156336f179412b8153acc0e0450099c3ade4801bc9030bd972c68c3e94d0332a4281336a292425b9213b0581db7a8a3863214bbc0408e62c1ca997509888a425c5a249ed06b8f86de6ea1ed1e7149b4000533ca8f3622fabb6560ae85a44ce33bb74cadcfed829bca604f97e3c9f152bf09f1607ee00e3cc8f08ba5f2be10dd362be2495cf9c57ad4ad0cbb04bd29b33d48b89498cafc345050ebbbdf0d363f97f2dd6b51e9f1b0fa550d7bfb65bed016f07e69652c95ab47811165d7d8ec6fe713d2b9fc87f02bc8c8c00b89065031fc7ffc0c724041fd1d03e0970813e8d5ca695dba0be80bd742cbdd017c6e023a1885b0a644acd8473be917744078c84211d01f266192c7a6472baefc13f7282669f59ffcf13b94cbc0b2e9b239ee237e1cc82456daa16722de219f12d874767ffe4bb2cd790bf6234526a0fc183544a979ff8178a1f57ffed956d875aa1614179756817285be69274ded3db2135b0004f04141e4a3180ae2001e1af88d36c3a818298ddc6003e17b537365cf238504829465cd4fef6d64cb6f7256fe1c109a725debe5091a63b917b1db2c0e202a42a020bcb01d2d534088faf9d538e84b8ee264b7642785befa736d7783a8d82658f09bfc4eccdb4c70cefcf15e9be2f65a2795f2d1ac8406e44cd846c9885a4d294386255debd915fa18fc81c043997333b196fec91640826af2bd1f9f200df4bbb4d65765464885b4c0b81c51ba45d51c073ef65b062dbc05240ee9d22d574543a7fd37ab349bce9b15ee63aa0f37b31c00d3e6db0b04ad8701bd4a4bd790871319367a08d98541fc4ef8b38a803ae8c7d048ee061cad9c7a513e55eea5547d57268c3edcb912b637904f1a87df6de1df5beff5e64d7807b1d15b804a0136545b092f0d5b3adf53ae6f5bed9890e21a5d384d34f6c3016f4cd9e389a31b03a65bbc1e0a4b60ee4c9a0a8f29baeca79df10017b65cb9483153ebbaafe8c38ec540f54cefa4111482ab0d6e6185e647ec0e2678ed243c1ad927fdc172cafe41b087a8f6b10074e2149cf6ee8f3fca4f9932d8a6f0309e58b83d9537501fc76e43333143ab290ec6466bfe674d627e5495851d7a5969cd0c06c230afd160d691e929f14c76ccb3109b68ddc212d8e6f91919be4c56994133c49bf1dab66be816a5e0e1be92b23b31d2b6d85199e95292af83b2e46987e27d12503e9aab9d0dd0f2508733bbdecb76c1a582a3fcadaefcc7e9da6a07c0c8fb090473af0f564fe8384360d0f399d7cca2044db2614b0cb67e736dd7b20a18ba8bdaef1bfb1a49887cc82e0bb3049fef78a4c0ed31b78a23b286024636ef17c0f9bc45b1d74009980b01db65cb1f32ef0d0005a32470cb8047c9c5d31f0ea41c92b795202877594e0447ea0abbfe7f56579cbdb0b54fdf313f4bc3fd294b512d4fccff33968216d47e6ef3f1fb004bdcf109dc455eb6c5869cb8713f70082db7ea1df5e282e91a8643f0d12eabe63e02d31afa911f77af62e19e9d4846aa67b029a4fbb5b7e234ec6d0093f27a0eced70d88b6033b243a4e082843dd471a640e091064a459ec83f26ceb2453c83fb80791ef715560f0e6042fdb7dadd9a4c9eb75653fdda951240c412938ed14314a749fb377fce22ad9ddb7152d5d970b76109e7e98de96190d019ea9bdc89c1865cf4e600d37049b5a14e23fd2c15ce4f105ba86c21c2e14a0633475081266e1c78149c3968c4a1aec7b91913b42fdb7f246198b76c1ad964d7646f9cfc6027f0904895329f8865219960ae8868054bb2773e5eaba205b813afc152f2f689ddf3385f7180821c6b41431c248f0b86b53934cb6d4d2a8742ff909561e20270146c75749cdee5797da0ae59d069a388cc6dd4eaa5523914066134d01fc2196bf1440ff0340f7a38427070b9dc326efd5ad9a00e60ce93651275f5a45c7af3fbbe45bbf65320a02b9a449160451d618d8acc4e21513db31494c771f6d1931fdb58cc53a618a14e181531fabdd4fc3880d29875b240135e4034f67610223c1e611ab5f30bb30beace537e79fadc5b82ad569807283cbf3a8cca8fd6488c9ed52ac162d36757908364a9df7b6228dbd948c5e3599410aed018119282c61af6626ad2558f2322f006943fe923817add1b42dc62be8f3fe9593c889d54952392968be441b2b088c352c3db624ee308de425a12fa85ca6e8df6fb763063c588487a056c41d9ea86a756dd8c05e0c7ecff202c3ba04751a126cbaa1d2bfddba369f47c1373566823696b85bf4aae56559a4d2c30bc01301a027791144fd7940f9a193690a2ede09be857b21ea51ccf81ef593d0fe8d6221396fc052b6372ce73d6d9093ee9440c39e1907aae8e9878763b19cf6e6b007493a27e0ef976c7b4e34da5ac7b6630189b5663f2c38922bd171af152782c5eda6fb52a946bfdc92d0334de7eb2cad55de0269c2ee1720e3c88086944923a984d5583f432b36ead5b30aae581e0fef623f6069e5ff5aab906a26c32079c2d1fd7e1b840dc7479864c6a8a74496ee531f9987a08966c598fef37615ea4871f38ddc1f70312573180d01204ea54c40d00641e7065bdcc1eff97289d1ab609fcad7df273109073a2b5b596832c51a897e5fcae95661668af77243beaebb53c7fb5a2f902d5fb4ed9c6ac46f3b223dd83ea747c062becaf6ae04fb0eb3cc05c71281e017fc82cc90372cd46e8892a4d33194ef39265fa343a141b1373f17f24fbc4411a64007d1cf4e8c39bdc5b7f97e8634e275f1f7c8a57c0f5beb2eae2f3f34fd6fbb16d59947f5c21b85646f7682eb8eeaaf4f0eed2fdac8bec4a852487fb72a9ec0f49e5851ab771faa445f798830e073f75dfc6a6397667b86489e5cc3cf523cfea07894f84271458b86a9a5f8f7a8c2b5ed58f05824e1012d2909fb7dd98904414e1ec86144886415fd19bd77c2c443d1704730ea4eeca354028ef207f4420e30bdc50e79cf743dda8e0ad13a71ab4635075d319d53ddc04f7041d878aa71d60498c38d1c9194a9e63b88280346e525ca9e2e32d7c3bb93d67eb3b86f98ef210308e73f3ce6fc1cce5db96184cc4353a4cb69f51455e889744d50370ef238fa918043ee369fac8a5ff72491804f702179d25b4d11b63a5a40a63e685adb823f7a6ea827664c828c18393fb8c8efaf7ef4b6343450b1c52d1527caea6b7687019ba9f004f7e59380dc2ee94f228ff3298650b4661cfc8568b6dbfc4beb498d3ee56937f659fe04d1f8feadeda501b39c8b6ddf2516882db2379a1767d4d54ac4e6c5ca20643f13ea58227ede28fa8753452fea33dad5f482649b7637278030983fae6428e463753222796fefa88f00508430d00e788ee010e2d4a8d54c5412ffe08164eb1e3047c3d7ef0422f88ce878265c8afb812506c25c2eabfe09b9bffba90a073b1b52f877a22107896f316608034de08ab0f3157a601bbe0621dbbe8dccb139887af73f25fc8df0aaa1d3a20efb04f165cb02dcea9175c435c80ebc8e01699be33893a9b9a3212337b8293410f5e4c2baa7c573c6c9d1bb2d6c45e3278071a510c86a9d07cca10ff971e20ed73ce710ee3e8165ef5030d444efe0484c533273d5d10d7a0b143c516b28b165d3bf174e28e202d13d876edba8c09e2d7fcc0ad406919b9e60c22ba2c3dddc5374dffd1368323d50491457a114e87d449ec6b171ca9f875da8993ed8cb93c881983f20465cf141ac23471d04828d3d24c38e27a0746b3e55911f557c4a87dc8f86c5eaab57d5140ec9b7f3d6c438658b9f275e217a79f0e9cba9633dc4bbd7116eef70fca65f7a8a65632ba560e86a2570f85858d3a5e12ac698670a8a056757a20b25120d86225216928b1548148c587970a0688a1cc0e2cd565744b82d72e150aff899e0b30a1c412c69704018da03821d3e9f3a4c82e34cdf55ad87b4d225b8807e950c1f0235df33daec773ae4566cf1a0ba0d53993c8b5f21d4511f5409b50d80931e589e474dd8801e3336cde54c1d7787223b9a7fd0dade6d90fb8adc659bb2cf241c1296168712ab2ba13201fb6422f0b28a43dd40be377b5114dfcf78d68289316eeef425edb2c5428e795664431958c74da7715038650c64efb5021f629c8e3091e6c6ece832b26aea96b04d8e78b9ed3e88d6fc1d27fbf12789985af71ee202434d57405acbab65d6b6e9aeb9d6af69784662888908263ea1fbf1400aeaeaa3d2cb5eecdaec275fd18441711fee04d29abbe68fd0e9e7b12711521c620fb8f242e2da633235f8538cacb16abbab5a9bd521128025e0ae995404bfda91e6fa58d15beabf09471abb64c92357ac6744e9ccbb79b95db5a5b5444892dec56ade38f32de626ccdd840206410beeb8d24d95d63bdbc1ffadfda1d32df2cd84d94e76b45f4e1a86c4b133c4f7fdfa8a97c192c616feb0fcc32d1b0ca8f8213f0a96e60e0293361045b4ef84b9a251497cf7c7a0337d07916b417218509a97bf8acbb865f24a5731606df32f4c349ece4a7981efc45f2d1d0ddb3536a8450678e31af0dbb03a4b656714f21554668fcef1a6e4ba086da2b9b0a9b7ff59d31872807ba86f538582458cd2b249760814c3b7ecafe9fc53f321faf1b78884f0845486fa09d3d33e9cf9e7dd1010256be375bc542479a360322e44a6270f893445271eeba74e382591479a1f51e17e4656cf45fb6af29c5dadc20c95baea75ff9e36e5c832ad3b6724fb5ed250181b8379365706f2a162fb10fc081e7483ffa372d2d6a790db074cfa156899491a8a2a7cd97b01f8029b1676e8841837b249bbd416cee26956f01bed5210d2057dd9ec955e82500f16298523ea5f6efbb8ee678882b661e6f7c21a307b9520b54a7fc960062c93e5724d4481330e32bc5587f048d0a62b7392fc975dc3923af8741ff3a1a1ded2b97c05fef7a98151ff0c2a4cb8a36fb971a398ce04a5d06645e2a4a640283b3459f526f49fe862899c4686e151d6d85e0c24d4c4fd868cf7683033dd01140d858089b4f843317c276fff5b7a720eeae37443a60e994de1cd27a01df90a159408df370b1dff74a5225d7c2c9426d7c37162021b95ea2a3a02e5de239f60dee077746d1bda200a4f9a1f91bfae52768060b666851080eba66ef1700949aebf1a0f5f9588f289f914b4a5a98c8f19e2aa867d52183f04a09d62e55211f4e503395f656797b643b8accee5b5af33aa10e747f3fa7ac50700ced32b9c8e21d89a8fbb0dfe8cf841d9e93d91fba7be2dce745b59fc8dcd96af8c139c75a03e5f76b5dc07980a7a4237512dfb7def9387a6d26a9b81ccbcb30adc4ee91bf88ad95f9594c3135a66340ffa72addc4d8e6553f507bc0e0526df36eedaf952940d7ca86f4246dd10cbefc97d9226a2746a068ebf41ed7dcfe7f189c58ccbdc5d4ecf57e84733c772609a049127653a05b0e5e98e573153267a572b518ab8590eefb448934c0cc0a016e014013bb9a42130c3e0cb93c62c1483740489361db1bcaff7fc342521b28eeac229a0bba86197f6a901093572e2cb7443fe12d693483215cef596ed530f17a7802caa62c8ed6c88f571889c9d30a2ef19c40b0bf5985b1a8b67cc2ec997467d99aad17a396f7caa5a5800d73e1cbefcf3ad44d1cec2a1b19a5bec21df4507541fd5b9ed86e328a67a560db1b43a9ef78e3b269b4c6e23f1ade4777d0e45e0191121e8811a35afa3becabc27358dedd197c82a4d0077986d18b1d5c1d96e8314a88471c3211a26902ee86e52cd7f7ab92cc448c3d303061b6d6bac45892e459aebe2e7635c8494eaa66f355610ac82f428a5108158fcd741643126696e7acbcb537cd9de236d603276a2c1622119cf89c2af9c5a16f04711f68ca57ac07246ae80dac85a2ba50cdc5fe0ab25d90c4a0cff7234edc5a9f030d2cca9ec263cf04658b6cba79755a645b9705af0c3ad3aeda675ea5a6b81d2db36730f826f07912959f784acbae186e011c21279b4d97d8a726f1026a7fb62a72035f0c8e7f705533e679cb516abb31f4ea5b3a59835188f565c2dba4ccaccfa4ea117c3501d7e5d1430c3454bb9648ed3a2f0f66e369c1fa3e82208d7c56c34946b6503b6b471bd3e3706a30c6d0f097788beb5ec769b179fc9ff799bf06b2b350cad5806152f874a5a9804dd124fe0c5d586c53ce58b41f8b73e07dffbd7ab7b1a6b4e1fab5179c8bd13e5fcb7b066050d0f2fd25e35bfc6a73dad66f393aee650d242d084a284b7715c83c7b527ea137b7a2a23f538816dd473008c6747a148b713c3e6d26de3c1297331f3dce3744b7c66426169383125f22a4dd27e625862fa297f40299082a3862d0c1a4f9670921d0676dc2512c14a6f14568aed5c586fc28f6365fe5dabaacc4bc70a935568c6e094e9d2e277735f9c5b801f4a4250c172bb16b5a624df8c826ff0e559bac3962d1384d825109d25d5dc2deea44381a402e713479fef46c7446365ede51e6dc3a960c5028386b0b72141595f56aae1f5ad65c41ed61e7a244a55e9af5bb96dc2c35d04d07505f9e0f2af69a75b8dbcb9aefa5820ad4b513e4009578786b1a567e82229c114fe8e7a35164561c621315dec9aaa4fa052169aea2f6b8737b54548bdc7e1342132bbab7bb6a1bf56a25dfef109a5a742f77d1328ab596ed57a134b522f6b873ed5153ad72fb27046af605bad002ac977b30e6f629087f83f2357478707f73e81f41901f485e85feb7ee374df61904f206cd57689e08c10a06fe9e12cd613ca2b41fc8d56cda4b27b294e81de1012420024a7a394b5f509419271d93e39343ee3952de4e72c088d36b79272185b51e23c43502cce1281a21e1b04710ac8d00e914c75c8120d23539c01608031182014ce8ef037d1df16c7ea66f033a845ffc3fcbd9b8977eeabef5c04317adad6d239becbda5dc017c0475048c043e3d5d0ff1c0e3a2caa7a0dd9bc538f66a6ce06b7a3c13f16a4ef589baed76e9b3f2d0ae4a85b98c3ae32ef5e5b602e02b75b2946a116b537d97ebb8546a1116be42b577398ebd8bead602c9e1ae232c3f525a41c657b88ecba6faf63aae9dbb58b0a9b6a919b8dbe370b72ee7de168785db5bebc39e0515155b8485cb90711d970ae6aae3c05cf5be6ac665581f323ee33e5487b98ecb06e03a2e9797dbe3bcdcbe6f01f000581ff600b80f97bf5cc7c5718fe1be73170b67a9ec84152a0fc197f81900a830db4b5da9f372958578f600f3344f8c67a9efaed4c93f2b6cb7ee405b5866611946df3a208dea321ebf03d2d8cb50b9dccaa8a9f9c397781d97aaa6a68c78957d50f5e7b22a8b0347c17564d25a9ab7f5adb84b7d715beb9fc9749a77fec5505b5f5f8c1715860a35baa81c832ff19ba8f29221ae829dd0b0e6e2536aff5053357e548bbc784bddb9cbc55115480e77b9b00feedcf5c2b201dac88d8f403c2e3ece7baaaf54b7fb5ca8cd356dfbbc98f81da86659168608ed46e9b468161668d103142b4e4067dddd1d219b84501ab72d52160df43093457022082736d0323637ddbfa9397d9ce660c7186bcecd93c59c9e8934d248238d393738b2bec981dd7d8393d3af95e4d11c8cb1edb1a3b9a80395ddf4cc1b6ac0d08d8c5219956930b879f5d62d1289b61999349184219af0811336e8ee6e668e0c993972e4d867abd9ea318182c38db0490b24303ed0deb66d8b318a628ca2d16824aaef36ec36db9a968342fb514411450d2a5310c1e20828989939c618f9bd5a36319bd60b76cbe6c5e25e362b1b2b284fc82868fce6ee777777373f61e309a8c5be9a1319b8d112a104d8ed5ecc888cb3588e9ed15143acbbb9359b4528535471bb179b2be019345ecc7f71bde1db680eb2ede263bd69aedf373dd3afb7be79d908e2d70dbf7a8667b815ed8a0b7adde0f09999b907eeded880b063f15fef059e0914236e0c1a42d4a00c4d4bb65ef3f134c4dbbccedc7ff50c6f87902143b8d557cb6625448c1b5f22d8b279c5695997b196103a215c08ff007ee1710b7d781b10b636e8841322a89069424c9a50c244892976104510b1fa002604d400bd7a4fa6fffaefc6de4eaa1d8b0e02379e636a68d18ad7023c0fd4ed8e86950b0f573c0e5ed4dc907611d0aaacdd0e8a0309e18c8767a84108a1256993e3571c1932b3954f76031f993811828a21128804a62601be8fa3f639a3fc8c9a167780382011833c425c40d10198020d137473ce77abdb34ccc339e5b55595791f00c7e5af5a83125aee3dd06eb5623de92738bc5aad50f731494287d56a9684637d321cd609f48df686f91b5ae8d48b692db63caee58cb1e5c5b416512fa6357909731989d4b10794dfdccc0c7fc0fd5e0a2cee8befde1ef7295a7e35f1a6fb5264ed94db87d13ebed3edf80aafc67109a48e4b2b97d4f2d64b92b0593e798a1deb5c528c514ac9a8e65e44426373ef3581a48210aa0082beef51143f184008e106482a6e7908212cc128a36469a6516acfd22dde80be73bc017d31420ba120b5d4485a0986187768739b736e22d13677d844737b13d6108d78057104e1c604c6070e7ff196bf384b3dd236250393d9f6b6a98df41c96b1ace34a0582ba8bab5420a9b35c850a44e52b2521a88a7aaa1e119da5e670970a5fa939dc95ba4addb94b859d0e02544450ccf4922c76811c49790e77a93cdab33c9e1edf417a66c5234df266b8a707d2b0cf505579d743807e7c7c6255f8f0b8f8771c25855909b46bd9657196c1262c200feda6d45eb1f2532db262539c528bb85cc552577e43f515fbe3c80f18575920474ebfc172d555f6c7ca59fe5c326c8a77ee72b129b6a9195457f90dd5555cfea3c555bfe1f2a3e52e7f29b688cbebca9fcbdac3f88dfa15fb63e5f530ec8f23382bafff01e3f6cf15a3a6fa2bfcb9fecbf88d185fc1fe68798ccbb03f8ee0b43cc67fb4f8ff5caaaaa2face5d2e7fef202cb5613586dd5ee7555597da3c3ef4fc00d9b7a2be4bebbc293196b60d7432591e62994708d2c090419a19a469795ca91406aac55bded1bb5253fd158c9a6a7b038eca57b815ebe32a2c953f57cbbb958a3db2fdb95af48ff07b401a95168f67d8dd4e6a116a0e4a90e6a92b2ad416d22ff12f6af7b0d4075395c88d4fa1fadc781728dbb0050c71e36392375bea73b9a8cfc5529f6bc525aaefb6d86c03bd5a32159d94664103d253c1d0e3c5c4dee1e2931b6747db3cf4c25ecde9f6bbe6b9f1cd13a483700fa4319dc4a5e6696acea973a2d771994ca6d3e97dd09b4aa58aa2a777ba69339dce97aee31acdd271e8bc0f0e87bef492f541fb3aaeeee613c70882763c84fba6678c60c55c007af9a92d77f4f778c51d5df46878f4d733f3a36faf8686fe6b89fe36196511a43171ddf4f68a9ac2ad4ccff41bd4f4d37f9436d34ff68de60f6952239b9a81fef41bf4a7d3bc71fa9162299b4a6dbbedcec83086c5219066a3287a1477ae5bc51840a3db75de68aa01a1290190df0baf8c788955a0961ffea8d2d070341f0389877647a36fa28faae80d83c8be6c8f2aef2bfe26be473c8d31c6d8b01713bfbd213d2d7e48529387b147507372c9d476faa6b3cce074538f17234faa54d0ae615bc380749057cf7412d0b9a26fa38fce3c50528a42fd23397ab7baa377ac2ef57835a72b8168cb506988a48b488fa14f12d94efb0458e76e17d5ed5aabb98ebb72de1d2f464a48b3b9e45f3b5ecdbcf29b9472c555bc18f9d34db2135dbb8fe6e63bed26cb3ccdf1101622ba4683f6926521cc564a962c79547948659ee63412e9424dfe7622cb30db0dab3d9a933cbd83ec1dae94ef1df885be7c0f5488d4ae699afc2635c93cdd73b240ca53314b260aed568dba5c73244be10bfce9a91ba5937da49b4ebac95a54e905d48a073adf5195d39ddddd7fc12fd899aef1b885f7d137dba83bb905a690c664e1514e50cd6e2f04f4bdef53c1ad6515a4a7a2c9a1a3b978687134571f8bbc783c2f79e1628bef9efea1675256b41ee311f598c2e3df9b3180900a5d809678928bfa5ca8fa5c2c6300518d044baf5773baf1367ac60734755d6e0f630c9cd081109aa00312865cf1303fb4e358cfd047eb6223ac2c184823016a2e7eda6e7116679901ed3806833477c53c9e8362e991e571e5f10dc49be12133186319909dbb629ec35d5c0c393732081b36cdb9c191e1dce4dce0e4bcded00e1e3d7cc058ac85030fa4a722b95001dabac1116d5e38336d657aa571336a7aa9647ae94941f9241aafa6fb0a8007daad6e94797ccfa09047130c7f3191656a02edbe83478fbf1ad336699d2618e845a2ee157f26d6b92b2cec00b730dff3a3dae1b8f32d486b8a95692ece54bf5b694f33699606bc4702353dced86d676d2bd956732f12c9da3417e7bbee28a3ec8e3d8a31b6460cf9157b7cb59261d18891638c71c793f1c4a52745d886627743f8c316fa18813e902184273537ecd59ca2298653af56308250d1ed1a7600193a5078d22c35ecd574c74d0505fae0cb0d103ade21c59ef9fc00cda8853bf025a2209049443adc81a70eee90b652c3204d3f512a71945310e8832fd0be5114c80e6cc8b6513abfd9596fe03b2a954c3442407d200dfd369f681a6a1b08be44fba2b827db4ab8315a6804088c20b4658d1d11dcd9e29cf3c194128c24506ef873e8d34035b40b2df479319148734168f7c0dc80c69be2e1ce8537f1a870e139be187852a90423088d979f6653dabb9aad119b5019615040fb51b68207d20b1f1f1f0839087d7cb81713fff27c5ecde94410608becd3a91f91c8e2904836258af7417ac9a64456c7157f29a8663988633036a0af39d21950b22406ecb06fdec9714771289934a2499415311a414141edd33dfd43ff20a7d641f315f46a4edd03e3a3bcb677dd53ba6946ba192d694e760f7c912fd5f6a9f29507d9300e0aea9eeee99977032892b8d2a767e20fcd499808dad456f2e9d96ad0d3ef1424fd18597a29e8b4bd036b0ec60634be6b580fd08bfc0d1c4fddf6f562e4678b15c45a11db8ce0840849c4600750805df99652f619887f18c90f4766feecce5848d69c3c4c11949f6019cb30bf7d8396a3f00ca6067493d4875e4ad2696a3ea774d1734c1fa520a9a620d79493ce6cba019272d25b4d7f43749a523ad91f249b9a760668714436554ae18c4ca72050f82277e08be427cdc96ebba4284232c93f2f3ba01dcf64fcb3e40931b8320acba03c9b0e20837a21ba1508296750cac7d8fdb8d3ae22f7d557c0463a909e2a6a419663453417cff5e045446df662e2ec2f269ee2551308ec761308ec6a8c3a456dd7e2f6de6c868a36beaef206be70d68857b37f31f131d2866932906729e5679685cef25c0f68c74297675086b83cfa768c9760217ab9ad0d1c85d88b91871184b65e8c3cc74697afc614c3e9b66521215052c7423575e3ad841a342183b9463675e3e3084ee9a3a7703eb23e8e744576d8353a0c253dae91fdf1120c253df2344a50b2872ff2c19791e52124d7a3bd816ff76255de678a816d6aab11efb4adbeb509d52c0b0605435a05b60d082169a209264e8000b6e120670c4cc304546ea2f868d3c98b442279d1697845511445d1166394716ed3c6b25aaf18638cf13146196514da64898e4855e38f469af6ae941bcbda691f8d46da471f7d1b89e8888ea83c9f24aa2fed2dc99bcd6bb3ace6e4a59452e6a0f2524a25985c4d762f269d3074e35988e63c1192c97ae5f3a3fee9999ef7a6b9a8d2b200d7acefb2b48c5c1c3f6300d1ed764fe8b6a8297e8ba7f0969a9aa1c553788aed8d164f2175a3254e84544c6880074f7e0842d334a83961016b094b1c217f70a0c3114d0845a1890a9a24217382c414b2084a5060fecc9f2431ee63f26489100e4964387012646588206442c8a85c8e528bc1603024ae272329bdff61a7a2e776df81d00e4108f590a40510f32789123260c2c4921844a552fdcd5cd5c4081fd309501c400209231c7181d6e6fba5e138846d5d40bbedb6621d9359e0f6d08d1a40c2481048f03c264f7230cd8e78e288274990c1c80165e205ab950cfe40891ac4981022c42a88257850c42c89c8872492b8c12f2c2183264d700282274a86624d782067aad5b66ddbe5b66ddb36259c724a4d4a09653225138928495c60fe285102190cb61da129a89831610326c09a8ce089105b0f4b14210651c205b21e7e264e9424b1446c453c7f83c160b098eb3dd6d7adfe34e63f2642513490262660c18418640920926cf0bdc984582c23f02c42164b888650cb064208211218605101bb1d4b090dcc9230917d40fef0d08c09e77cc79ae74f39e7d662d160c1b318da55e458dd8392034ab39830018b8ad8ed5843311e0d6a50831242f8048824b21f55cf44c9a518d9543d93a25d80b46d52a55fe4dfca092a8fe3cd1483ca8db119ad0d3e2084f1c41393491cbcd54af5e2bdf0df2673b9512c5cf96e008d72e1bd2043c511617b1c7739e8502c6889ace3717bbb36f840d19c783e8365a35ad188052d91bda89d60e399401841abf56ccba66948df268d7e912c0ad08e5f4905c428215c49183b2bb759575d8fb992e9d67e88908c4012638da0ecb17246739ba816592107b4e35ee41605480911340e24b9f23048d3cc18d0abe99ee11905c9cc88d00f57ca88402143ac23282142e340ccc4d39c7c14234241b1a1a16e75632b9918a4310931110932fd2033191142321b224a6cc8c4d3ad6e6c25c362b56ce4e478453cd98312e54501233723b651c18384f141f6df525e762026913ec0c09570a785a494524a29a594b203579a3860e2a9252027f80ce11808a6a6c94b29a594524a29676976022adf8d7856bc186671b983c0ed4780327dc1c93cf1334414a5d88788e27633aebc1c1342e87634b8654849e1993c909b08ee9b25c92f5e0d0c534e08e59c734e082543295b4ac92d802a08655acdb58d666d5efcf87ddbde7befd5b289c1d64bc208212be2e8991c3a6a8010c2586b067b43c16ed8ddb07340028629010220840d2184a9fe68f4eda9b63736bbc3c4da4da9194cdf9ed2ec0dd3b7d40dd245dab33e4c36a57da469da7d94ba9cdb0f561c9aed76dcfe83a4543fb5dd52370c06bf6d70d61af3eebc18789e1c48b3cd0b7f187b41505a22b23722f2060784c7c96900a35433150ad26c2e544000385018a55f94575b2e7ce0bdf75a372aaf06aa1c0974bb7c353407dfcb2636b2cf42660819f21f4386d0a6f58a36af1d72d378c7460b056325f9bc66f8ea1450160d665142b777181238e051951ed0a62a92f94514440e8014b45f1f4c0958042ff6f9ef32421bef7ddaf7de7befbdc74f0a12a908e93fa0fd68d38d8343478e19db1c3a74e098e9f87f1d3872cc72e0d08123878e9c570b088f8c6726640811de61d8ecc50c078ca783c10e6970ccfed967b3fecc00d70b50954ceb6513db80468497d2b4f73aedeff1ddc0f7ee05bd436ba3b97ecc0c6fbadbdebcdeeba6b7375f369e665bab7eaf1b9c0df59a851345c7d60d1b769010d253a55e8d0d2aa517035f71a028982213e033ecf22bbd219c679bb637350747162d4e4e9429a8b44d983439e910cd000000410093150000200c0a858202a160341c877b5e7b1480117a96426248944ac3a12447631c454280006200000000000080cc4c89885d01a288a83f0c36aabca9d738a6452a7926df2a073442e3c1abacb4c80569a3ec7aa5ab3fd71ea553cb7b6740039901d696ebaf867c2a6ebc79970fecfd5f444ffa7892f4871a23af129176600ecc977ebd212fe76478472333cd0e57d0610af97f55b3a8d3c2dc3772939170f3afdca116ae2c152d09f347dea7e53c444d5a29352f496a02e55fbe0be2bc59d6195e523b653b685b9ccc5caa24930d37bfac2323d7208cfd3cd904dcc919d0bb4d706ed50a980840117ea2af79e3f7a8331f1b41a3ecb468cc8a59c63dc01fd79db778474c1599abf624323c0128e02ddf936ee829efe6a623130461006df38d8ec19d961337fb1289cc3ed06e4fe2709610c56819c225f1c43c6c674016c72c92d55537a762d4f6af3b5316fce7d0389d0599d542927bcf64cd70e73fa7ead95f969e47ac9ece46c428f49e0e6d40781ef72761c7a3d0c7b22b62834793440d56b44abca6e91f18f98713c5f01f45202f85b43da167e2925b1e7d00bfb79fb73e62058eb715a96bbfeac77b7b6247c720a9f8e105776fc95c1f2034d240aa999bd3fd10d30347c0b9beb4f593af0b2000abe9e104b833f1af3257c22607776427a3fa7d86035909ffa40c9174aa80753c08f086821e6c337be3ec1c9087bfd36c74f71b640aec3d43d3b1dedeb8c7cb2f384693acbb57f82dbdf971b509edeb09497b70495a616e54068e6e757d887b6c88d3e69f3422bef93fcc4d3bba8ef3b7d00404386e8f4944e84ca406601c577c158e04f7f01057793a0af76cd4ec0c1c9ea09f58f173dd17adb91c1d5cd08598e58449572caa8094fc268d253885cb7fbb591ae192f0c4675dda433baffae171bad5818b3e382c8ed72c6d67bd0ef527a28587a692780fb73f859e463918ee255a1fe43c761cc5035e0e666198e4df531a8f4dd0643f21da2d3ea675695e5736c68214153d0316db1b9f7f63697182d03e9259e9c45ddd29510bef44be984aecf4cce5b776b34c33f1b14f39b417ee269adcaa1aff59daf8bec4fb6e54aaf59f4da8508beed5ce226fb04fca930439cc5c2a66ee4ec019f75246816dca6e966b4c997ffc26005d196d36651b10dd42acc3c09f90b72086bb3a1d59dee36f43a5a9abbbc2ba2ef95b861f41ad37dbf15af4dda792a4a6ebf5890ca16e19814bfe6c82da11a8bcfc1b22fb93dc88f8e54ae2ecde1796cc860854efff70b666285c5b0c1f95538bf48e1a7165eb64d3dcc7de19e16bb6c1ad0b7fa03adc6117d31e3f63d1e342cbc55def9e895e97f48d7aa565b8d650939e634675a0df12c53555fc8d9344813925c524d59ae2542c136b6ba8cab54da337afebffcaa3acd08793888ea9fb6a0757020dc62c20353b92b85da758c3058a96ac863f02945025791f776f36ea31e73be1dad041491b7d103e5832664512b0941b1b79dcc1b35a1d7a69b44187445a3a525c1b47d4fb6c9355b83be861345549e51f69987adc887a868a317e13e96f1884a937b4fb1713dd5c1d874c33d6a33c63791b58e761a823d1db4cc56476f13218022d182579e7dc0b2c2a75a91817c5254a82f575c74f863178af04e040de2b8c0fce7a2d0280354dc39455b05941ae9228bb60e3db1c7383bbd19cefb7d962d8b74c9d3457e9a11864b4c893638cd63259bc7d18714d895ec7edee3f873955597e498cd179fbfd844b0c7fefa044a1b71d39b23e4e4c3d820b34203c0a22fa065c0d759409f3ebc78e93bb5c1e56d62dcab6746ca5d4c43bec341ae9b1fe6e08015775e963f20cd867e2058e3a2570faee3ac5a29a3bf6abcfd7cfde3e0f83fb74d23f4119fd7785709f3a3a03acfeb539651f52ebc7a791d5b85c4b2543444db1e0412a8ae772ba0b2383ea5bacce377b9f607c45ef68533d138ea4c7977354f44edf83fe4885a2bf7e0a0a0d928f9c0f2216a65f72d307b9c519876985c71c3e930fda2d35e99644f68e1171c56a12a3da5e72287227c516b5300c457209516addda4e1df7951cc0b0da2a4099b610084b913398e32be2e613329a4e05423b0eeba8e6e72cdef37319e7642c19fa5fc8f6d923db89a7c7ce9077ce07ac9f482380c0de32f72df4ca64c0a877143e76d44cd4259bd9f866e1e1459e69c0c81b992a8e9ca6871f45b6e269526dcea8f309d94ae3d13be1e5c9ffa5ac0936fd126ffddf0a76e5ab62b8371e49e245f08af874113714c966520e7cad3a9b97339a58cbab47c080ca59a8c69945100bb28a2c4053ce1d22899ee2b4f0a806125bfe2419afa41b8176596efa489a0103ab0a167c85860ae4d15b4c7607042c38141fdbcacdea6cd05a96194372d28ac1f251d5a7213c39929ea6d62f3c968f23a281601d89d12e456461eeb707f14a5afa51bef6bf2dbc15d3046f7e2ddf83c8f1a16ae443cadc6a797dbff72c870fb0a90b9e621da4235e6703e91c1d70e67598d3cf2e738e758497468079dd3189ee4aeb845db4e3d9604de3fd6ea503e8c9be96c88029d61135596015e0b9732f4029401364caa7c4661babce2ee88a31178470249a35d9ea06ff4b5aa481f44042f9e7f081290b88a0aa8a8ccc9e9aec39a8f508e461a4ef49d77bc38a6e044e26530e32843578c6d7a0e19307dfc81e521d10617df72e9e186cb79459d587170520c522568407f88343650afaada0e39cfeaf68928b91fea9d5038581c61641f5729d458361c0f54ea408f6db20e1477509a23922d63dd222226a8bbe9aacd278bfa5cc1c8d32e0c455751f5adcadb4be20ccc48072d54a6b63cd7935ffb258e847ddf502c840256272abcfe49929a562c4c39829aa8fdc90df163ce7bb2f4c49fc1114cf6a37d42c6925f0a8d6d7aee78ba9af9b05eec95621682e88fb4327bd40f1a9d7ca69ad8afa6b3b03d00d63f957f2412e2e39090473de701fcc6158edc683172a2bd7f10d9e81159d62b3550f6accc32e1f586a17ca8a87d6b75f8fd8b7ae23d5e35dddabf99802eed5dac876c388beb2ca8f0daa8d81aa192b7215ee59b5b2af5a68a8aad054f19ee5dac515f1e54e0504847725b70853ed2b3ff908b90748b91b5321e0ed4df97b26e62c7c9504590aa71c7301ffbaa1e32cf9363a4edf1e7ea0e8fc2131dd579c21237b4b69119459b7474c3af1863ed7937e3966fa986fabe19b5aeb7bbd87148763de70f9d64f6811d3e8e0ce0e05c5e62af198b889864c76972403f2e77d698cbfbdb0d35c1e4ebb1ccbf3c6f5c20c5eb1767daa1d7c081ec10d102661e4676fb8e378c05709c6158da63889c77b1e47af445655307f6fef165007cf388616d7816d59947c5c3fd8ad888c91e7f72e3dccafd06a1d5f3e6bccd98893142191b7ab3644756b9c2378a853e5a47736c8a21ec5e0e201af14290623f1a1ecd4f3e7302a3541b8fc896b0ebe713d04d03a85152d824f2a479d96fce279b7a386fd2d1ce1896e116240e3f1663602d1cfb0a0ade69a593998c8274c4ed4b3c4af5783b1d2da9fa958a5a0c8ccbb924e83dc861396027e4cc3bc6f741c0839e153203e9a11593357e0655d962a123d3693129127445099e0bdb2663073336708f9e57bf527d79659938f212184b6987819c3ddcb3d00be3e4845a2512e55088e10945ca03fcafc607d8742d0d893ff32a10ec9efbc9e0cb5915d7a50a6ed08fbf32625c800ff87bf92d385e0a9617eb0a0cde429c49fcd2e3b02358bdf74d711d8b9215bf4fc3a82e99329e6b085ca47633b52ee086447f480af4b370592fe27308f453fba42a569f3899805166ba898d3892938ffdccb2a5dcf38ab80d6a1b00d7849a671042729812f6380403f7626a2e24a09ee2800d09c3e56603ebb0fcd2cf129f0355e1043b209a652df88865a5e1e46e2f8611cdd60694cf6714009f758291f33bb5b32a3116fcde2fae46a7767b6f0d9200b2e8567d2f8fc57ed0dff36194fdbae1744dd8d7f2e5e2a81950fd99546109caec420e4c49d2f79f7f5ada965ed3b1843d5b5086150855a0a2b26931d21a66cd3845f90ccee0391a41e507ac44065b2eaeb495c9dde79c3ab55b575f174d370a1f005c1b9ba13022427d21add438d15f0d3309d8e5fa32b22dc1f57df860602fd25d5390dda830b09e6620f8081081e5a93aa229d080642a36e663e96971570c0498c88a7a07cd070ce43baaab48cb65d6f625b883ec2df39abf828c8c947c32b7274c6cef04e53b2419bea843f56d04167f68c9284cf308855d7953f87fd3aaa8ef2f2e46427333e070515101eb0ac5c71c2a8d242adddfe96de255a9e7de2b0f533bec8e641c530e502414c02e52202add7fb04db8446f743d3a1daafa9d8e30768a300cb1962577d912720050e08dd3489ff0cbc3e415d741b188d0dfb6febad095c46821e4dec2d05653f85fc9193e26b9dff1e4f17f90ce1a1bc98739bbb847dad131ee7e0a2b8410d31b5236dd49768eb1a434b3f1680afa4c1546c2e6a0a807a322b2cb39a0a7a118810cd493f03aa24cc372d4c58178d8efdcec3d8a177ea33eeb5b2be109fb796a3cf310239d32830661212a8a271b6163ee6007a594c23a288a383e3bd376e6cdf1b17a591473d083d32d1680b4a349a2acf7425e59d6636bb31316896314a92b96d76bb0efb6126a02939d4bf45d789c83f75aaad519ede398355a2ae7d138d2a900dbf93612c550688a1ad02b0d065bffa65f8c0d582eeda80f42b9dd7036d159b7ce47bbfa23854019bf34d7f1ce7251b3512b0d79f4093ecc41b58e4270757e4b3b86ee164fe593bb9dd80da9900e9dc855899c046e3de1b6915be5850bd35f26ea7d0a83e90d71227faf3bc50e2570f5d96c9fa432e41e52bd95323c5d91d2d5067e885210be6c85bd8ba0084b1fb5e550a72805661ebc3b4c691f652c25cf55c62049708f892aa539565026285e108e37142a8b6beb53a199f1b8b89e7a66c5214c7e8faa5ce12d514d0d0684c7def4d79e42b4a6d45024f0170099427d2847268e602ddc7385d270c81faca903bb497d8eae101947d60dfd7970b62f3b2012bce1321de810fdb3fe92dff4e4ee29883e8fd6f193b4d6296f6cded598b92457ea94f32a7ef1cd92dc1f18900e8b3e33f68a7b23a1e31080c70760716ac97a2eb6464236b5e283dd9354fb9b7a6f715176f2e4636548f38d1c76d1057b81006251a932bc9fb5a39f01ccf8e233903bfd38b14f9e6faf61c144bd3becf7c9fa6d68d0f43e6f4546bbe9021a46f1d9775f9a66187d37b9fc2e98c9cbee187db2d41341fd11f9275dc037790090f4c643d99ea8dbabc0c92dbaf97667b5e16f8eaa81539b2ff43095644baa520637f51114f9ab42fc7c7a36e9cdcdcf6aff7e8d7cde54eb53cdc7f8aa830e62200c9eaca301a8b44699c228ad114592333458092460c13086568b7ecd2bd016882e9383c2af0280e3e1f12dbce2ad70e835b2bbe2bea830487ef430c977ca078e3bc52646706489d775b02bd4b5994c8d1edce4091e39cc4116bd5a57787cf6cc03d5a736ebe634bf3663d948fbad13a2d540d3bc245295b2b848066239df94c7b4caa63076bf8ed621c5c548826d81d9f6c3732a00c2287749d00bf5a6a5c7c60a676eda8efb3a009b8a12645721c71555ef00786276bc0cfda14cc8742d262e8a2d538f6bdf1aa0e1179dc2ff2855357205fd4815193ee1bac98ffaaec181726d5c09881fbca2fc918ac995936c4aca0a7b8a1b6e34b7ab3780265faaad2df88ecc47d17a6f228e2ff3dd4648306f949b5a6840a131f111bf2f02c5cf6ee7375e9b341ba50909914948b996ec39d99114e34eb51ef476e6c7814c30932e175c2042c10285f824ccedcd3899b604d67f1cc7a142ddef082b2677e63355af19c139abb85dc68b5c12bbc7e327064442d2806aeac32cb137fcf5f0d6d301c56bd3a82f95c1893ecd3c1339c2378b8e3bac03a88f463a147bde21524ea3bf111d82df5f815f349682c51040d46c483783a83d29420a84ead44b05ee4a166cfba36b12704b78a79dd7e8d4c00c830c86061d74e1987415e2eb24e3da66d44bcd7a9abbb923d87181ef732b82004f6397d9ac1ba6a06d9350348d11b032aecc7d39b47fe499506ba37061a2eda9a8089597783024c6a90737d16835ac73e262902695f0fb09ba13d4bfe3bf489ca492f603ff32cffe4c71c4b71d60105f78ba23ba299c36e4d52df8269a548c1eca94bf54386c6b7b2337df45d7f4109ee80302119237053653485021675d2d483f130d4655d10c249bf271cfa2bdb0f971038bec95d9c201235ba44377082e5862090e329d3e27eaf585916b4be8fac23c6ff63c21224ada8cdfdd22f8c05cb983ef1e234565c2a4eb7da5a029f32cc82cc704ae987c3d86132a8ce98463bea3810e03c709705189be36ca038de66adad24aefedf964cd7544cf3ab346f9bd881de68d507fcdefd270788cce2bc1349f6389d66e9cd70524db14fb86324b3de40162f795d3da35936e844ea670950ec1cfa1b58dc8e9fa935742d8e0c27fc92aceb5fdfe6831037f09ac367a6511a4b5455014ac3acc960e33f67b7f669bf168aa0d98e01e75e0e9a174d4b41a41d952f7390f9ab93c1d2c115c08f4f439ca3e30ec167abeaec18551b97539332535a9aeda5710ec8dc42bbf4a73f8cb12a90814b122d39f0497b106eb802e5c23aaf179cc53de2d6de682f7250286d41126ec7c098cfedc7e227ebf822ee061f22fac44f19c9107db0e90bea52ee62e66d3a9e681bf20cca2747e95f5f80262c10a9a367685d3a0cd42ae3ea267314a5ee276e74a87f14fc5eec8b03347a073ffc4c9b4db49e4a74392893fc3cb46028e263fd817860e035a33f30d0d9a6d771285c5346f38601f457a756e25682dee0b45971cf0274dde01a43b634807e1e84cb5c6a06f7aefaa2955f5071fb1d045ef1a2576353e8df561f55bf22e344125c0afefc6592d03caf626955551f598250ede74ae0ca8d9f4113c3f1c9486bba8f58c1449d9d1075626cc9afb4e637b6bc1f6402aaf1f322a6b88ce08eb033691e7e0ec5b7e0708d88e8a67b27210bfd48b7c1222340cbfdb639f362deca0c4f41811324f3f482119016bfaf454b1b57208ad81686dd136dd69b5bb85c583176290ecde3b0cd09674bfcc21498bb22c179693b8907e9527c85c79c604419b34ff52ccca51ef8e5145d4a6bcbeaf83e4e227d9ed23e00f07d870e0ac740ad3c40cc35474fb5a1663af1689fc45b2ec22dab8211ff7ce66b28466c0a6fb2c6a3a7850d60f5015cfeae7518484438b313457d6741606e37f7cd4f2ff91e909f847a768ae18e68ca513cdb2dc664ee892df0b30c13b13d8ab4c5a1bfbdcf62ea43b2101ba1c8d0241d44b1156f438979ec4f509e6bb943e96b178e684bb61c12da4e7a43a0b39113ee7c4e34cdfdae766a2433f932c978d2c35d47c6208701f00037d80e017b57b6e33a98e866480bf531fc92dd82f914920af0dd96c2c233c502fb6981ee27d07431cf106325de81f48a925c4c7d39cf95f50bc74d770db35866c7b79a943266b4a6cdd345527e8270b648be17de6e60641a635661811aa641cc21900fd2cb5c04b693c51df3b9b2be758a6eb0bd2a07d5df8efce70959653a604cb2f9d6d0e467a73e7341aa20633685c202e841f6bb3f7bb7f1b9326c62fecdfd7745dd955721ba2fb48c13e85e6cb7d46d09ed9f7c278d7163f381d41477c4576cfd86a117610384e9cac79b1e6b0aea972c549ebc612642002016c700b1f610b8c9ced1d89f34820dda58a3852572caa2907dc96c90af7e353db508754c1db1725481a29a1e496b4bfef3b22b23cc108717c07cceb2c21ba0a41cc0ab1586b89789676d49cabe2b7100a3d738dce6e40cc31c2a9665f17e69676f4f82f6f65778111132521a9209e68b5310ef0ea05bf98379469d81705bf327456b504f54247f6991e8a384ac11066b61f62d4ae77ce6a2b310101a71349fb8e5ab442f04e4bb632fd39fa0684ebf61a475229d5c5080711bd91687440474108be39ce9a78ec50945dcc883d67e523e12f06bb44edc222f9790906e91a9db0d929ad40d101688a497973b45c98c8f5b2cb18b6cac6c06768d147dd9241ac46a5fdb759dbe134a0ab06eedd0f62ec093b0b8ee21f72f9291065f7a9104e008294c98b97d655d0550dab347041da13ea97890f3db9458e5647925cf488f0832daa5bddffb75c35771f174131df5528388e488f87206dd9309e0980627582e947abed8dd22093cda2d01a3e8d4c41dbd271097cecc79692f7886ab53511a85066d07378f0e97e0c011012fcf5614ba9c4f12f1c8d4f39594ecab59d5d9f5aa87062ac24444deed4000b0fd0188b9a93dedb5ed6d0ce9d74ebdde13af8140836092a08e3aa34cb69a46e8078c6b850650627611044747da20f0a8055438c7307d19114ddeaf1e2af29e28120f66cd50cc7f6899e23bb11311915d4210cd03d5f14a2a6cf5bbb3798cd9fba4a5d6d9208fd0767e255c5e1daf7df71f85cc8af04e15e2ef694c1c3c387ce5084f98ced71a769699de2534844606c1c7025c8dc1b762f0b72bff25f13089f1b611c0290e39e503cc906801bf981bb06970902145e745ac6f6e5290db1f3bb7d5fac6a84b02f593086dceba5bcaead6da902c030bdc9255079f3406e53cf6c2c7ae183dc28978d7ee75af71fbdc2b3c8a7fa3daafca02492a5507948c80faa15659e5882bad2bb2113352afbea574d520e5495733a40fea05b70791a26a39fcc6fe380775f2029411209a06d8539528edb024d8686755e0deb02973f700986e625cff752ae3df0b4704273b062ce21a609c857cabf4360b0921d921b964dc1b89465b652d8d3118d4e632476931f096db46627aa6fe54047168357630c19f1ef186a4f347999c607cdb35091d884440998fad1bc63e8c1ee0f402d981fb0a03167ffd7037c501d5caea1f8cbf0a79eb3eb1c75156a5da3694443760f6e06efced69ae90382578e6da6019af3534e680ef284d00626b0a956e72087b4f721bbe95aa3ba5889a3d42da6b9e4f27b50c43c873cecab6b82f96dde4672b3c33c2bfa7344879eb537463042371b1ffd972cf67e0fffadaf9ac3c7eea212f69aa98e335e21e7f0ebe056c1d257e29d6a392c51720cb32e29a50f4df392e3d809f4bfb86da09bad738884b73958782cba3b58b0e6f7a3f5be1cd2e74592b80bd635b8b19ffca331c60911f37e990fc271f47859583b8c7fa70b900cfa0a5823c24be84603935a6e034b249aae66d0de690756656cfa870807e90dcf4d899bc9f2d8cafe2ea0ba943639a21c87fa30bff5d7d34392588b0ccfb1977763d0c8181ba18b9132912371d39c3b3a4446b158ca8e7b6696981c09140c76846f7afecdd404402fea9d9b91a73c99d2d974f7af5fccf0bc7464fc938e758fa7f2dbc54813dfff6fc3a8ea2942be6fb2c16c39336363b6473f762657ae1ef495d0cfa16fda3b09ce8443dbfe114a7c65513d6105a2558b31772f21e3ac129f7fee831a7ff93731459b27a5108e08c5f9e9aeefc9e7ce17c88118c09a47edc4f54e459b7fb5585d36ff484e3b6c7ab53e626b87bd9d5114a140c08d3f09d32d5c490de8152f5c5f86b3f8c5601712df41ce232163940bb610795f17a87c72151eb08f5c07b9a71a620a046768b79b7db5e73bfcd7c47a1e01f1b326d8cebba7e94b814cf37ccf454809a768485e0e3b333d0da6e03fe1bcb59fb5fd7d106267d55426f86fe542fdd4112bd79237c0eb7f7b3623533c30b5d062dc60840d6f193e2f46489fc45f231238785417b1721cd0abcf9a1cafd1d7013ad5a0362e40eb0671d01aaa1e8cb53a6f538ab89731ffcf97d03883ceed9fca16edfe2ae2d256430ced7c9fa730c967620b2c59c3ebd0475e69a2c48d471bc7e1ac7b5c8350493017d8a30dd6283c7c499f371ab8dfce55c7afb49be1979cf1b8efd52ce231888c8c5df3cc3e9faf8b897ca2f6ce53b05f6f61423ffad826fced124a340fc83912fa06d263469455fcee4fb06482df194743655b2fe43f937b0801f71e5ec6d8f86ff3c05cd2ba97a2bb7cee3b77575cda2eeb1fe9e1eba644dc308682a984dc72f95adf5e01b93abdc4e8839dcb8516624a9cba5b6d1080f04cd31d94ca9633d999b25ef85f1bba66436de41a45f59ffaed7d966a9d3b8ddc0a9026e6005efce7ed0533960abfba1f7654ace2dbfb1d23ec3271447d76c01d9867e11092b718775fd581629c97009b8a50799753cbf5c6606f9fe9de1fb43d33980ebf517a5a754cc39ccbccbd45c3d9ebb3bd38713fe9530fb8cf9891cd18ffdf565469b81ae9924bd02883c318b11070a96a0abb351483674e619ebf1a82cdff6f2b3795cd0a0de80e19cefafd7d7a2b7740c5ed2a3cc1c9f058db1c5e9889fb84cc40cdfbd8afb1f1518a9507c185cd2a2955c80641f1f8d815ebf382c5377e2b38111804ace428093c3a9cf32282f570b7916f9fd1c56c260e67dabfcbfe39d3c1b4d83ae4ca770d949303e2d22dab76fb0d723dcc4bf633b5d2fbedd3aa58e3b7e15da1bc3109a2df29d3b26a0a04ba16c96eaf2e5b7b7ee382c444b0f75b6eb8a3b963d06986d99f98a012f2f0cf78921ad61418b245af64b401ae26e2df4d868c9a7fb987578b8b355fe21d24bd21bd95e157615f294c99ea5a401e02979d3f604f0c9068aea33c89e86f8cd3736812d9fbe8a8ddd609199239999fc58aac2cc0012cc1692e4e6b4bb1f9926901284a381bc2e247d74670d76b9b410a61240e72008acbfdc7463a677e33c2704d1425092cc0a379f647a93cad8ee7e101b9a639f26b4967a04b352715e37abde3141afa21cfd6051301d86be5bebe22c6c1ca5662249735b4b801d9bc65856cc3ebb777ea716fc7c9a7b1a780dbcc751805e3cb638784558ac3c4655313bad71e8ca472d2c61d003f7f113e666f69c06300bcf78f544353d2c13e528b44e4649ab152643a185c8252096f92933e0d45a4eedf9f2b6345c12c1e2c525bbfacd85c63c1301e645a541d7a91c12662a287def63ad345e9c2ff378af8d164eec09fc8ca32349a5551f553111314f1932a547b5ac889ae3a671f72a3d0580c0f18c4562abb5d4ee2b90e0d2155d3b03399b453f71de33075f4c523d4aa907dea43204c573cc16186304d7c86c627830424647468c188b437f0086910f734baadf6ff3335ed89f941630d789c07bcc3e360e1222a27018368e8f96048d5f2299239e97977d7a3fc0932644849829fa63425ca6ab0d3f62ffc483f91737dfd358e98116f480d2bc7866a3903472e7d2fb50d490c51106a04a3ec262d7e3a708b184c95300fba72549ac56d222911d8b8e254b82dd6754e1e98f35abfd3e207c5783d19fb46109832e7d558a1b3330298eefb548716805fd478c68e865d259aeba546bc9a01397ae444b745cd6033e2214cbb6e4c802abf0957862bd0240cb94d0a6e4bebeb1b2d56908513887095e74df8ba30209fa88333a3984d00c0080be8e55e945bca45b822d30a0c4e130646ed0535ee4ea4abbfe4156f89394932b8e0cf12180b8dae500878178c0d5574d7f775e5b9b0f2ef86ad0b3e1b0721bba3dc9cf645cd67874f28bb13db883795988ccacec4409241770c4ed6e3d80d8c777aca29afb046bb7a2d3f13ea1c6ccc6fd7c09f9f7d24c36e4e1825ae102ad1742bd27983ada2c913022690bfbe510c2370fd1febe8726ecdd30fc69abaff5c627456d62e434e4afb4413c4bd1f27974db5bca2ab0039eeccc210bc1b4298947713dbbb3259f300b183a4c3cb62ff47a721669f0a27d0e69d387b084713fe80d629b5683a2390e470c27c748c7a31d068393e3eb1bf3ff1bbb71b23ae7c3137ab9e02ff77bf9fc5b5046911ea98efb7198dc349fa3db3280e715ba5b43f36f1f3f44f2902a13fe3a9a77783813020174674f741a6ba2cd4141f35d754228922dafcf4b7d76a10b54048e3f307305a696ab5e2184e1b530c18740aa6907abd55cd8cf11cca66894a15178c0fad8ccf61807896f5e90cc7b05cd0d063fa4f3aac6f14c1399a325fe988cfc59f28c223a8d9b5264b0a557cfeb685530a5338b1ff62d9fbfabda97c7818bf5dc8bef1d27053435bb291ea7e5ed049f15d30eb408afab35735fcc7e93926190c77712aef9c4b194374c58dbfc630afaba0d88d858239e2d92e4873159cfa4f636bfca74199fb6ca761c3f66993f24e78664cc78ca71dab5c5fd27c951cd1f9e39ae5c83d6e3f1994ac4109ee9eaf546e7c03b4d64e96b8c20febd5f916dedfc06ffa656a733588d0b5e5f6ffa2bafc569285445220fdfde37295eac81ed0aa55d3ca3929766056005b24de6544a198df5896d15a9a3eefaf52b27dd05b581993fbb11b2404fe1f8335f3f0234414e113e6ce61f474db179775040bda69bace1db587b9745d2a54677a6d5ca63d0ef9a1fcc82924761e5b98b342bc609ee3b236f5df4b074a986642ae54676f775f4f8e642265d5682519ea0628cb9b5cf640a98ff2405d05d48d090b1415e1cfc2e97326b9f8260244dbf1ca6be8b29bc1711cbe516cda7500cccf34bebdce1c1d6d7b912aa7197658af6cb2881fbec1677b49d236b7c495b5b009cb327684d9aab13e5e217830661c1a63a3f2b43f005d00af8f918d2ad5638048f9389982c892b047241ceb4565ec75bf91f5bfc7d2ca74637cb0bbc135eaa994891eb6097370550bc250b7e31cc7c4fcb4aa82bda256e98297c8b76a4a205c09b74cec6ec48be9804851d2c94a9f01ed984a3a47862b4df1870212e1b35059bce22d5583a604ff398914875256a4b688ba42e1737f6c8a966454c3281d82be3bbb9e7696d90269d3eb176e7099fc48f29c26cfd7eb8db1eebef8ac25e1aa341a83fd740a42f794ce6a22bb68c47b77c11bc4d6deffbd47eca7397f5cce79c1f7c2f81bb53a6598a62ce4f39370f3e2b92816eb86483460ca65dc7f8209ddf86905eb876dc613750413aca38d97443d74940f6226aae366e935d9180fea521423c0afc32d66715cd5a06bb708f70d1d85bf791a96d8ef56a588c1a3d9efa7a8f898a407158795f062a4be71ee2265aaaa041aaadc56ac71737c1a8adf38e7b25bca09575694249394da1836e45bd0bac64b8141c175de9b525b1922bcdd1ac747b6b0a8766274049565ad201d1a9be07111e41688cf73c1584f74ee621d6f9b548c4aab76727af241031b5a49674320fa2b9c0e629d82bb7d71f7bfe68c54b3e1feb61f9b89965e49a070a108244580ea13207450080a7c71e85605e11ee4521cdbd80b73550f2aa06422fe84d58aa687b5cfae8b8fdfca9237e0a69219ba8a18d5c129e3a5b8caa64e949947dff40c4657d64f4107a3312c5352bdc204c301fa442347e059f39d8da31d8eef3c42856f3183a4d999283e408c422db9c912677e68763b91ad4ca0543f732cd79642a4b5a487a0c173ff7835aad2c92d6bfeee6f0da6ee46cd537bd7174c4339716f301110a4c999334a56e489df8e2ff914112a56a1e60b69184d0b4f9b76403aa71ff7f778ab7ae53e9d09f2ecb431675df372ca5d9ae58ce8901ebf4bb74daa81b2772802c8bb40aa8a6725048dd6029e706018d36fa7832bb1bb83fb9c128f802c1625f23a555fbe9813bfcaf841edc92ff318998fec2f10b5843412e6074dd499bda6cc396cb1ee180493e10cdf67c205908d4b17795140ca3b2b908bae1fe8357ab0fa27187338e3d482a1a62c1c7c7a242a077270d17cec50807f7b5bb2be80a82a521881e3652006671a37a6b596bf718e2f9a634857536d92a218d2e31eeb96b9a33ba4a2011567f66536d610f37c44ab12ab8cae0cc30d11bf6ace12ba207f1c8554a767d7a470df195de2ad3636bba2adbb635fa8c7c58ccaaf78ab4fd17301da87affcffe80d0acc687534b2dec9f892db370a5a3b2673c5909d69a1c88ff6c12bf1a2dd1ec5d3d6bc7071271e3a89130a0b19e17e3aacc499c32d504abfea0eb00c9566d9a2217a0bc854fbe03399de87d01779969fd0ff4793657cc2f239076c8c87783d0c797387dded6d728ffb4930a6a0281c55833dfef3a37411aee80468e7869fc06852e3ebf978b6d933d7a0f33306e2b37ab7190de6074ee88eb85bd0226560beaf96399e040440de8d1bf5667df01e5b52037524d340a10a489b3d879b5924e80650f9637d31062ebf1d2d282581295f64a23115ded90cabdcb8d16488ec7cdb8bf8923701565cad18da95c6478180788543244c440c2b89a484c6e90278de75953ee494fb5f4eedeb5304ec86aea1aeb746aa57e979a968c00326209283f23c385d5b6d545867486e7020a653f553383371525afa195ae43ffa795dbaeefa98956f0be8e20a7d33dadd5f407dd70f1cdd5485ee6d2f5b49479b2a757462a6f41285213f41f74b4a597413ea84eab86d7652b2177b3515cdbbc4083ba7c4fd3c94fb5a5014116263b592dca3ca7f3272099f416858cef73c9a756c047a98e79ed1d76f98f6e60131b027685def3be6262f33a25556097fd4eb6f17246722b3fc8c169b09ae8b783fbf6327caa73191268d04e8d383e17427d5f04f68e5119136729e1aac2902c788a10d2f6de3e4f95b6f0aea5aaa5041856aeec53256613fb9adbedfc1a1b0236bb66974e5155d7c1046be4c3e7d8c6268e186291b15e3038fd6da0989f8f78d47efbcc9d387669b98c3c77c111b03c8105544314c08fa7acf9c3cfa1ecf57f5314ef39c379a122b0cd220a0894a347f32418d2d22ae093f8c1be03286002045a5e41e51d2d92cc21c0bc199c277f618151b9da0b6e818c2ba28248cf313cbb988fb2c59a53c7ca2646873561b8d4d876f5108f0aa9e9eb48df288b3470189d246986572be4ff4c1ce00f35885d39765ae6ea7d3e60fcf7a1c3879064f6ea7bca5478711624886c10e47d3948b466401b730015e13a27e2e1ce73bf110987d61112543034cd9d8ece31f796574971824d642e80e95f47dd7f832269229be42a8b9a349e1d280507372f4f426427306bb600af20815d383ae094118efd52b112ec471423a8afc84d843d7ac391312c445ea423f6cf5692b051c7996f3f5f501bae14dd1b6e5909493c73f068664ab298e0126e501091d437b22b3d8f31360fed5b3741d11f988f8191270e229ed5a89b45b63e167129f5933dfc5578f782ee27b0e37239f9881e052a9e21c6bd90ffd99e2100c3912903ec6053a7255f9df28270fed81934a349d1c7b6ab512ee3eb58f89aa4b34e487b97a1f6770ac2772dcdabc7828009f434b2a4aecac21305a832cb471b81fd87c8f019740dfaf37061ef9001ecafcaa6abf0001612b77fff5d54bda079d71164e05f11a40a97ad971d708ef64bbfeaea5023e046c282bf9ad5538c6cc91d12061a93d590ba6aba6c828dded09b3933a21f89d26f8046fb82ae37d3ace04ece50c34b2073bbe9500fd9996d9cff26083efbf4e0a54bb3f893b20ddea7b47268b62b054c7c6fb36866744030d0228fe3bf767836f8d7c391de5108807ac16218e3170086c671eb150963d5d3cebddba41f9c36b436ae6b620f228e16c6160c10266250f29153ecd4a10f14740857062a261f525b9273180f80d431ac2672f8a72ddd401f1c92516afd4f923bf8553230959d16412578b040a5cd52cfb187ec097230dd8c6bd162f3fc97a611d4c6779f0d5ba63d6ccdfc2b4d863a11b56811d2acf888e9a26983958b5c671c345a813e6a0699797dc0d1426d962c302b9b2662d4d18e7ad434a82180d6581cd30291209f29bd97b8e18c7792fb150233c1a385ef1bca14949923fd1d4a410bf7be851b33199e337403e0cd7dc43fa6c5fc9940049844c1b27e39a9e74a1f2f9b5ab8f1f357666fd197fd3cb087c55767e732e2a3faa4eca135856670ce7d2a0b6330c7e5cdbd0a69d82454f530529aae8d26eef322f7a0498c1bb96562b3732577f82c2164f07bba6c7d368d28626ba53e0edc5e991748b1efb99fc6057a861c8359519a12ab9ba0f85eac437d95ee4a83e7da8b4f5960db0e634d380bc7baf4cb6608c240e262450e40042b427a9944d049f2707ae392811cc00bac1e76a96071a9f6a681da60c941a63055c210002e9d3b998513d8daa3e0fa95550164135c7a8ea8145790cd0026b8d6affbb03766bf4e061998932e3ab632044976d1862329c6365eac33fb9dc8cbf9b471366a76436b1d4fad514b2b5f35e4092eaffc825354a90765c9f5ed6380f9627052c48cdb54e76e5190c17e6ea7dcbbb79aaa496d51f8f479bcfec9dc5a5d89b2098ee2e995004151aa45ced007ff5854ed73f5ad46543111c7c1a2c051e722df30aab27107a4100040431c2d68cd9afe60d86780663f219bd54e3084e39a9608289a05b9152b58faa4213323c334ae5772d777d0a90f627e42aa377af4a066284ccbcd70d82a5a89e940b044405f3de207bd2db056d68df3df841e98812b864f3e7c443317b3b4dddc9d7260c018f37e5890aae32e780227e95af55e3610ef37d53863da4e348d811a9108063b54ecd6988026223bb9e772aa53224e5c8046297a52c0d83ca3a02906360561c82573f579c015e433058d1be3cfe272ab3bc4edee09eb6e7ae42c9b9c9b979384bd5cabd95f6a814820e3924ab51a146a202fb50430cfdf354ad2859e34154ea8792771da62cc8413c33893ca5e0f3dfabaa900c59ce84ae148a4aca18206d33c316b48120936dc84e7826fbd54059d75e7775452628c1fafe2bc022fafb31e2294938e7ad77411667c29d5137a15b5ea6ae158977560414ddb096880973ad39996b65207c3ca589953b76f5b2303de1231bd4e67c51d7369f7c9a362aeb232167950308a6f2b6e16e2383b0b57d48281b787e6c3b10068b9a08b01900773ef9b9a42de2987081a28a45102b2a794cb24296a7ad87c24e9d22762b63b4349b3470f3fd78eb85434eb0366a6781230b76935fa5b7140e5e97e49935e5f12fda2a442193eb5979623abc3a29bd41a29ea81a16ba0fd7f5d7e944bde5766df5e28ee49a1e160101a7a8a44fbf3f86b3a52626cca8af53254f746471e4ec88ead99ac3e95bd52a38f8909c251d86baebb35bc355cefb2e1ce646dda81a0eef7350063a2ae95f523b09ae4d63eaebd37b61364b24e0e537a00cbcd78392c30ac34ea98e62cf2bcc9199e548a10085fa1a52f3a077f263ab50e462288b629b1df00212cd3518c263c57f42e836498e5f5f762c547915b8932d9c13e89e20a06b71de73b7242b828dd6022b26b4a4167808289b3922bfb5cdf735e62a35f13976102af65d8e5bcccfa451c43581785aa5b1296415112868ba078c5d440691b480853dce5b78de947c56ffb67071f4cc9c498f9151624d58b1837735502ca267530c2bcf46e69ed4468598387a8cd3b1702135d10e1a66de9bb024c7b1c573acdacf33c84c1032fcdcdeaa8caa5f7a620f079cac02b6d88aa9e30cfa9ed23bede05065f08035853cb5df485614c1850a7524026b37b8803b5e6b14240bb75604c06785db135ebe7c1eef5041d3d0cb86e5ad2425a9fb25ea2dda1b450830a1df9a064651c7d44be3929f72fcf241256192090a5e7ba88964ef0c85757f1e873ff810e46546ad962d85292d283e8e4236ce982c547fdbcbf6c04ffa65042e51914c595f3edb19d31e4be5c980cffc61828eb9773a73d7f0363cd822c3197a0fb989e057c0d04eaa1ce8359301856a503398aa0449502d81d8c11bb8749ba20ffa05aec8342ecb5596bba7afd477bb3294410d81fc6a7ba8e6b7d06340cd1078568a048ceb12ec5e0428560216c6c185b8d823ce8f2d03bde2e3f2164932da59432a594020a08ff07ec0775eb9fcb9d6b8627494507510fb1201dca116a39828d25818bdc93274ffa35110f51d97edd361879cc4f964cd71debc64faacf5dc9a579b237278ca6baafbfff908f5197ba8184c33a4da45bc469fc67917b42cfc36ca029d2579fad4d19e15b7611eebf8f3487d6b6f73a2f03d25abf7f14486bfd39b4d64466f0e8e4e0bb638952fb47ea622f9f246525a9135f2fd10e26a5d77c55ea9c1b3d43674fa6a38fb2c183b9bfa15c30319df82c4ff66686ea4f97cca8b337a5df2f6230b1aca5ec54df573ba8d8968aeabfb1907696542a5929bdff909d22bca605941e83a5f8820c663f77c5d6542a911eeb52cc0f66bf9f25fcd661e9217cd29b1e50a245b06ca7b592ac18895e1487d55aa43070b6a6c51526ff24b16c42909361be7254c6d11197d136ccccd97e511d6c1f1fcd676f4e3629eef7a1ebe577566a9ff639623ef2e123f619729f1a3b8d4dd77346aa6bda21bd7fdaa735afd183b9adc10abb664ae6a38fd27c181302a74cd79fb337a7952461396d43a43bf081adf1154fd330922e7212433e9623e377164448d3f863a730b097d8cbc7017b893d0ef207f6248cce187f9a1a2085b9ed955ae405119281b59961357fc74fbe08c758ce103f9baecfa1527a7f66027b7f0682bdfae9dd07a82be614320ac982f91bc3003e8eb6f16bd5c2c7fc956dce0dbbe2253e433e43ec63e4e563de08ccb7f03e2d3ccc1b89f99737d2c2c33cff8f978ff91f30dfc2af29c5f486978f791c5e3e86c7c90fa781f91668c4d079d1ed48952d2eeff29807208ad9d8fc2bd3817f3ec6d8bb66d6c2c3f497e92f975fd345533e58fe7a1e2c7fb95cd7e5d24237863393cff259326ada9d19c4c868b535fe9ccdb031f86f8d3f4cf692a98c988f6a9bea83669344e02e8585380a7314f8ccc39d7ba854a6b56d7f70829eeab8289b81bf5ca157c4af62cdbd7e42b99a293102e67cf4be5d5321c1dc7a682b159c7e59d4a69b91dafb45c5b8f4fa086b1f9fc1c2d4c1fa0876fba8c030d9c04a5af3ffd19ae70cb9bbbb7ffb0405755050f577312bf5511ff55f6937edd8a3eabb3009ac8f3aca3d45dc47faa0a590620aa1edddeddeeddeeeedeeeeeeee9717b0144951c3e8860e1c160b3243862c66e9c0713a709a9d9748070dbbbbcbdcccdc3c05b69201ae17b6404004545a9bc1e1bf41a89282e13bc80c1932dccd54385ae367150e966b766666fe21046c679c736fc8d6b8eee74710fe5ba5622ab63ccb4f6ac4c98f9667792353b5370ba17f4bc63ed990bd39ed28712ec9a9cae47a7a96f7ef66edc0b5f4acbd31a1a42963652757a24110b03b1443756b85569d7bce39a0f7c4730d5fee2abaf79e8c5062ae989bac42364a75ffe0ebc70fa60ad9284f4587a7c421be8a3a3da21c5505d49dd2832ceab6443a6d438477d8c0d6f86aa769fc688718911fdf08e9af3792ba417e7c1ce447cae30407d25fb1a330020b7a388d3747a9f037211b45c329c164ca243ecb5743503c848d27ae230a9c9919250525e59314e153b967561804ac3f13351f75e539af02fe3a4737f88f9620a493965a933af53dfc182c228cf051215a752d8550f5bfc158cc07341fc8579302659acef214f2fd1906ecf5c6686fd60745e0629357d08099a8fecb1cc5bbeb4460576cc412510632e2c4c8cbcf67eac298469cfc98fff2465adee58dcc7f79f93f5e7e4a7a83cbb73c0e2eb485cec7e185f6e0796338b922494fab85a2b8054eb4e869c177026c0e6ec1c6e02ff905d57f2b40cb6fd345feccde945efe4be69209d1aa84f0e147151493ab8eadec1f802826bb127c20e6bf4e9207f6f2d9e40363791fa697cfc3f492ce6c0dcb1f49f55849750c319f856e42b47aa21b3f07f888c36798056d6b7a87f4fb457f8f984cca40d259be72adede1ab6d99182833623eaaaac1046d0a99daf40526596064e62a0d2aa6d3665c1deae79e21ef676f96cae99b93acdce58782698d73b6a69f851a7122df88c9488b164d54d21f2d74b64ed9b6e8145332b36a3ccd8c253b994a376c2b6ada4b291f89b93c66de2469ce45e2217fa51056dd1e75ad6dc6b3b92a8beaee36b9b2d63e29fe0664f6b42866fc477578bfafc3fb99d61af01e62efab1cf972984c47517388e588d4a4294ed5350c2598dd42a5dc1fa98ebe98aed7f2a7985f5fa17eb64069645c44ed7fa11b0751fb5db26dad85a2b2759a4937ee791563130b6a6a285446c4743a6b4c41a39d097c60ae5c29e28f05808cc957b0c7d99bd2fbd75d3d94385be37fca8098d608a343ea12adaaef16aaea6b85869a42ee83b56a6f56a4efeeee26637ad5e9df58285f6d8434088b8562c9752cf83bf6d29450323333ec2befa8350ffc545494ce843ca31afd31256db3614992bca3b629e35d11f28c4c37c016a9c55ed46dcaadb9b2eeda4db59837bcd7c2b09eb6619af2115fc833aafcd93b729ad75a938f4851cfa792b2d7928f623ed009c63a8c5c861a0032e6fb55fdaeb6f5bcd85df5783204f9a29291af520f4221c862f2376a7fd44f60ccd29bbec998ef2b03edcdf5fe6cc4ae7a784b0db235ee92720f5f61c068bda8be44d5b3114c47716cd860c621e8de8b8e424919639cb2b58d30ce0c66d9e8c174cf5f627202e25ee48f35c6da1bf9fe08d81505ae174e30b9625e62edcda9facf30e61601b255ac734f12d26fec231fc5a252b5268153cbbf6fa13c4ede894e7aa4f568e901719a9da7b992f9de81f86a9d5e9491d41ef982165347d21c1b399891fa6a3e03b5cf8c253b65920269bd252049c1137a5a913ecae4f4285f0129d250fe32244c47a76cadc619b38704461554aa1b90b688412d34818b219c73cea954aab8854a85c3624928657cf1c507df7b44443a4960b19c900ccbd288706820dadd6536c29d93ae72ef82d16439672f95e874293d7b215d948a7ff220184dc53fe5a46e383df6a948713899be64c61ad5eb01f277f02aa90650750b5285a04c99bf5051ce5d088a88e9a8d65898999971ba856a1ba73ac8bfde8504a9f29763203d4e0b4155ffa983a986eb5d4a130f29976390976aae4975041b434c219213ac64812040dcc62a42a15828162bcba1357e1d140ad53f54301d9d366ee03e1c44751563596ea11cd492b11323981b07d9ecb4b470cbb7d06da72bd3213bdd6b8649b584f9fee76cad7fdb1932c4848382ba494d6a09f302f3450e04e7e01886c9765f481e84c9e5fb87ecf42a6645e305e6afa791f5c8709c068636ddf620568796373de625976c9f4da7c7d8fd796c757aa472b63d4f6da9fb26969f476a4b6604a8b20301d35ab3561809a66e7bc4411021e2b6a67f09f3514a847fc78c21d486122d4d12c2766663a1ed8edf6aa761f9f6f9818f93b0509d08577354d3eaf53abe9aa827aa477a5a3abeda5691516ff790504d50bedad6eb384dff125d194b08f6c38183ef1dd6a427f562cfc31fa3d7468a72cf677627b1bbbbbbbbbbbb3d6eccf0e01eedc636e39cd98cd6f68f38fb107677bf9d98c25cf6b1b252fad1fd3ef2a426042ba59178b60f998061bb37f039ef5de726cbeeb6e6da19c130d13d93d9503255d21b37981beafddfbdeabfd3b9087d6cea88ea802a1381a93baf3a3d526d48e16a20af778fd1dddd2f974c60d8ba27dbf3d1665a5b199665795dd9d7dd39e79c4c6bfb6ee22153b98c1b4d4c860fca84315b468cc950bc603d2a0e0034b3586203fcf8beebe07b6ff7ad0a07eb5d319841d960c1dcaf802be2dfdd5d56edef0a678bcc98fb4c38a1a1306028418d29766912747b1641e510d4fda2a67c740db235fc4663b85684b9bbbbbbbbecc218bc3b8223b7ceed0b15f3d1540d5eddd6c00a1c3038aa73efce9d83cfb97577eeee7c092f5c3167eafeeeeeeeee5ad12a151898134f9a245104904f104838491133841c01a9f263b7b51552e198d15032a5246ce4c8ccbbccccfb7177e3f2261104b31793a6f2d3f062a21a6ea99782345b0382c96114d1d7fef5f02390df8b3e99cde43f947fdbccda2b775f8430a8335456ec460feca3a23c231b3ff81035b250c5a868071e472a13f83fde7b349078bb4c83c9ac41c6dc18949c1b633239428d283030bc5a260316735733ad7e9fd9b7bb13a7dd938dd0df935ebedcd5f592a2beb55d99182c3618267892079d8ca898c940d4a3645a6b94cc37db58626e73c1da6f0d7f0e6606b09d119a3586989bb36b002bd37f9f77777737e6c85474852d614c238b29e9be8d26e64ec1ae049b3ae75ea63577a33a4d43b50d7c674305b206ced14081f3540efc19eaab29567d33541b3008032b552272c0b60db084b571830ffc33f38b008a5b06c0ae50316b03f36ce66f8d8d1dccfdfe554548513a013863c6f8bd42b4ea358498db4ff69d7735124c7e9c5e77ba19a9bb355fd41a56cc652f98983375f79979eef2645517c1c1e782708155594e3304168bc562b9271cb19ce52c67398b15646b5230fd5907334ec78ecbccd281c3d281a33d8b85a3727de3068bc562b1de17af57a4528521511a9aa6dfd5f9fc6f4429a57c7ef0e13cd65834f46000cbdd5d4a09afb07be618638c91d9d9d9dd9d3d875e5e5e66762f689a0d820f2f851338b3fb83fc9c1f3ff8de735591bb226362f23b1c2c952ac618a373cece9dbb3bab543f3f103dd18325ecdadb60010f8fe3330e1ab83d76ec38711a87861e34f4f06e219cee6eefa3103ce71b3a222bc6e8ce721d38cdc45b91c2fdf7dddddd9dc3810d5230e3b226e64ce5dfb76166e699224851c619ad83f7de3f32bb3f7ece8f1f7cefb9164bd870c2f91d92d29412c89425294b539626f7b4d6ecd345482965510b7991c3542a2993fff9732ec618a373cece9dbb3b17a10a025b609bb5a5ec6e4f1020bc05b6dc9ec9cd4aa8a6737f9b13c0766673e9a9fe4646975193066279f727b08a51d1d64040ef75b02fa5e0294bc554c461be3ccb1b7179d9bac785a6e26fcbe5e7ebbcd054a44c60583ebe7c781975516b31bba1f4a787190ea46f895d05265b79ca8c38f9c1f2a596cc080b4d3d9a82f44789a620069f09b38d8a6a5431fbb72e223d5b995917b9d1915191509191509151dbf4bf4f693784847cd5455ed442b0a881dc7bb8f3139732a4c4e8031587a552b9604762633d0c5517aacb4f561cc434fedb7caad812db412c57f6068784627950dd39d73f145171eda7ca195727188612cc9e39b40dc38defa61d444c20e45176ca142ce4040712ba42dd588a5051dd984a75262ad24112cf3133b3a41b2a5a601231c590156419d369ce3937e426d11095ee86ce3987d58d9fc020c55ca7c1a188d3b89f5be3de2cf22a40963ee0cb7f116397a6dea33574edca6a9b652c4a299d9da1bb3b1dadb9bbc8d281c31a8b45a483088706e7eedcdd3944624807eca07622a89fb44d50db38012184bd6457bdc405e90e9c851e39bec2520cdf6746caaeacc6871e14e4e3e31314743deda08ba670789acae1b9aeeba24648543ef6a4dfe40b4854731a9722a4494a846baf941e4e0a2b5ec17ddbc4f59730e67bc77f23c70d6c863165d89bedaaaabdb9b67d792089b0fbc5ee187b5a7e1cff9df7373807cdc6e0bf37b42c93c17cce060d58865c1798b39473a250ff9aca65f5d7cff5632c1811d1d35239d18a0f3bc180f439482e9aeaa7a92ebdcb8a1ada2efcd1ae52bdcd20eaa2ea4157687ed0417dc58b9c46fef095ee69c2072aaeb4a268fdf4505369f9d99bb5a2faf5397b03ab2451fe691b4b4cf85b934a7cc557dbda4a0a8f6e17b852df63dbcdcddccdcd1de4b40d71521fd556735dd757a91c6eed4be652c55065e2f2ef4acf85201f24e167e2617a5734a58a264d000034858a1e18a65401f4de7bd1023c271ffe222f959f9130fb44f8de7b8fc7d71d8a54d343530304504d10bb68ced670c6a4e5b3114c1365e242937cab85e6d0345f2f20ade5a0d31a7f15a2eafecab22bfbbabbc952e9ddb4a3e4a4bce8eae547caaf0299bee01d7852103e77777777770772ce392e02cc9441cdfc8dfa70d4c772833e02b6336d33518fa46e3306d0c1641f7f6229ec586a9aeeafd2ddcdbd0cdbb9eeee06c2465bd50e3cb56de0e6b66bf6af816b3fcb000421a7a2b5cb2d8719b7b87d05337bd352a2507b93d9101fd0b54b6d23b1b8651ce1334f6477db07b64739ba18e376c4851e0c58266907f90a0e0ac5baf67168e8d136f16a930d2cd55dd27dd395964cf7aefdb97fdefeef3987cf753be79c8350dcb9b6d94ac4c580852bf9df9b5ec95f275422bc65750d8084b9c9394f3ea819950e190d074b288a94284b1e4591ff9052873380c91b2200050ed868623707ccc519dd503a0835a6e886ddeddabb9b9f737ee420e71e81ad5c1dccfd1e5c303733ff00fb674ac1d4360a73793695cd602e45cd1e9512b065ba357ac0337b6086ec1431627acc8893d21735c129e2a6efbd9144ff45ad9689a6724a18f6bbbbbbbbbb53840748a9a8f452ce8942fd6b9aeacfe88946a809337b3543cb67a8fdd3363aa4e43bd7a1c6bd694ac3d6786bdc825ded581a5f4d2a5a6831a9484002a49c1385d2321bcc142ce17fef9c93f2fdcb48efb1953bf0b0ed38d263cfb483f4188914638c54077e57657691b2f79bc1c7f882ef247cf735c26c6b37167fc2ec6edc1d1ec01f290a664e8e57103afd50f6f9207c867e7eb4d61e84b38b17e5fc98a9259389e6b4f62468c8a727c8e7ba7c2e9fcba727c61e98181a34b2dd980ce63a3d4eefb4cde9fb8bf0b4cdcb632b1a2d7cc7bcfc16321ad93b4d0c098624747a1696fd93634c5d7e7b976ce33fb51ca99b1901da7975a25a3b9d284c6bdf5ae9bff4a52795de6344dc4cdd76e84d5ffde802356572e4d02506dcefe796242d3d2d488ab605c9839047916a36f1d2ffc0be2465b7f4d4fe969efe16242d49da06be942d3d06a90448947f28acaaade94cc98cb48615737ffb2a5b7c9e13ccedbf776da3398ce65ad3948e21264ce55f38e7d6f8bf164c3411be443c43ea4e0b10a67c285fc8734c66fc48ddcae882291f5ebb10eefa83bed0a13f775f2a3eeedede03471392743a8d7b3f09e67e5ceadf9a3637544569d01f0b6cc843b93c29e662661eea45ba6a8c0b4998f01fe971dae5a22e990e566bd257aee574c70eb35e18867563cc7c750da7d29f1ecbb65931161af35be8e66acb63da0dff03700eae979309a407035c5c32977fc9b623f58564c391daeff2301ff3476aef7485a107e0185c1ec75f321ced4271bc2563f999b1d0781c67a1f13e4cfe96f4548a3035e2ecf45eabf58074ca27b8ee7969cc08fea25dc741fcc43966e71cd31622f2a1d6daa9f89013b5cd90536108bdc9d6bc16daa690a3358cb298bed91621c176a694f34327fef5fd38be3272fad2ebec75f2ee3d3a55995bb775a2a91cd3a77e947e1f85914818866154879d57e5f3624f7a99318d30870c27b61685aa71064b11a92115dcc5a97d49c2e4fba7f8698a9f7449ff6dbe36c3a4092a219e5f1f1f93725f663aac73bb0fdfbc01161dee8e936e378392c61691f62a423a553eccc7e33ded57c2743ec6dcf7206cdf5df32338ba4e6b4ee38ab9f10f13d24312d57e878445e8e460346da060364e4be8957fdbf197b407035a731a70bc853fc559b4cdc65dddc911101207c482eacf49405152fd541d0948aa738444d205d51f4666989fb9f1cfcfb51e95fca07e22659f244fcc248c04c9a9080950eacb96a83aa5a1357f940f13d37cc53fbb722dfef92a13d55a0f17190bf969d0dc542a370931a9c8b034fe08e0c1ba9f60aaea0c94ae72e932ba3b2f0e964ae538bc8c1d77767700d49dc245142a3b0f05014a1d128294b6f2f8c77c349523e5a77078920e01223fbe931ff05fea86f778247cc17c34d5294771349d9c211f035b5fbd250941551dfa5110921a535dc12cd8b7bca9647a6c4d3c8e54cee05fdc3f49d44bcfd9cb64b6c95aa2d7fbe88a7de4276539b51f23bdd3940fec99547a57fa57fa96528976b605a95b7c21a80abf25733f3323291fcfa4779974ba09b9bee55f361f66a4c7b2eb796861e69fd747966cc697d929934e13699b6a70efbcab5408a9b461abd48e4f3004ba85bd5b96eae1809099c975d11b5738ac21fb41fad2f5580fa42f416682615405bbfb516c6304f372530ec0c3abfb3e0094616f52efbd6ecd39008b8757477b6c0d6f590aa6d3d954e2606e0f0cdb1fd294fb232d28910c711ae71ea7f1c7d1646e8bf42ca7f17f1e273c4e7e5c0f9fc7c98ff7a4f7280fca699c47befc6dbd16a43c4e7ec097ff5e9394e76485104ece58e2889e9e16fc6d459a72746331ad51c6e46e0f02c68e999999999919720b7a7208b2234454798b2aaf95caccaff7bdf736e72b323233730fd89483a2084a28395128997f191d8c0465653acda11e3513843d5282064b9061b16ef72dbb65d8c64e61ccede12bed0a821df5d050d47f294acad6b410e61ced7675a30a07932b84912ea57c1efef282cc84f4d35724fafc358098fb2a8f82edbbe3b1153e4b15162396222196293485a6d014e22457eae2ec8de3a8dd4b847aa43291fd17b337379b8de3342df4c0f0a79343518dbff19d6947dc1ee62ef3ee83fc961f3ff8de0ba50248b91608b2e9a813c70cd68f1ac04c01d1b0ae1fc2e722906320e74c2c32d03090bc7a7ad68aad0fe440b257b294529e4abb372fcb2dc880c8a9ae01ea5266e75c77fb200261a84c89a47ae7d5dedc77fbf3c1ef32b012d979b533de79dd5447f52ba0d6b9f7778bc3ddb7702c958e1ecd7265a830f963bce15e724f4008213c8560655adbe7c79c0b8d8b947f5669aaf6aabb6275d26db1e41c8490e53087c5923c9976b8f76c83cee483e574d5699ba0d40ea32461a5d3c9b403b2904824928358bc349d4b5ef2a25b91fa7e1d0ff6283663fa27b19c5a3009dd2b99aee843c2e4625fb1c74c19d77855796158c9c425d2258342c909a10b742f5e246c003e30e460f25b4dbe7c86bc9a24c90f540825ecf196402b9c7b2e2ece6bc0112abdb8a909e8ed304a520933954ea575af84e3d5bd9cc3b2dd8b2e4f29ba479af9bf7c965eebc139dcb42a1c2c1d3834a8349c07f2f5511209bba40cca997c74752ca51a49a6fb969294e11cfe5be59358b21e3803f8c1b9e8a2bc1c8ccf7970261f0d5f1532ed80afa36d204eec815382596aad75b40df429f54909946a8ea032f714254c53a870e229506a8e1a1f9a764469f34c3ba07beebd7c3fb510438b25a81f2c6656b75275a1bac96c16759bf9badd80a2fa4f7f141645a8fecf82ea53b210e30a30aabb6ad5ad6945573e9ac215772e8705500841142e4cb0648cd686aa0e8812643185085664418812fc8080074660c2c41196b472488162a88c2952008194164a2221836b8da40580b46685b9693df4153aa804a8ec57acff4e916284cadfcf5d6052be77eeaf1677a499a180556c4d36643a6c0c1bc29d57bbfb5980edcc4643a8ca777fbf5b72bffd33ed60d92bb5486bf2b70a2faa70418b8787090252105860a95fec4aa70a1b9fb063541ec41934142822cc2dacc09ccb27bef2971f9bf80ac6a12a65eca2d628995b51db1c61736c95d18b2a5b8821b590d1c8de31e95ef86172d7df1bd38d5ebd2e9a463e2a4d237ff7e601616be46f03c8f1b6d818ae526f3475635095d9aea21130026d8dfc93189306529e67a50623f8e96945cacf3f5800f5b4b67f9b25ccb4e3f4588d24a6ba3dc9b4835b3159ea079c818816a4297f1aff829c46c638bda169d0174379d60a44082d69f1f060f2c109091cb49c5c7fa485954a0a50c28b29b47878c07c683999cf037422a5e5e49a8188d686aa12894cd2362f4b23df09bf4528aafcb844951f6750e5c72a339af148318a8c54ba00c2bafcf68c504fbf3d30aa945f83ca7328efc15ce9943994d6e43f20134c98dffc89bbd04d524a77e4a45c1e90d3c8081463243f12b5cdcbcb8f54daa6e5e5472376f586e4d51f9de86846af743c76d11d4495524995124995b18c8e56aa8c55249418256651e5639ebd275bf3a0581af9f249f1a2ca5ff92ef4866e41e9a4f0867eaaacf2df10bb62bd9f19b096a8d2a59cc2989ec46b1081253b7e74130ef0235095f94a2ffc30b11a49e616811e50facd7dbb7c948f23db81877c1f25ba438d0f33e6e51d898947cb7b4f8691aa0b794bf692c9270ee5bdc7572dbdc77bbcc77b5a8acc22268b454e23ff94c52eb2d8527c15819c46be9473a250ff9a1681e47f13a60fb526bf85ba94d66ab8606e6fc8573ab3ba64449cfc223abe72294e235f9e4ad95697521a72a208d49a7c97225fca3987acd047d49afc127d43ad61ee09ccb4a314a97362bee761a32e96d9a82c5f45a0a5912fff052be61bc2a2ca7f54dac6f4f25f179ca35f9ede943d2aadc9d31b3a55137d435b231fa76b92cccda554293f0249a02adfa54897f280ad52af67d38e8beee092ea4043282302c6ec1c7c8733ddc377cfd5bdf0c3ac41d2f8a4c7a0c9015c750c31e1c5d926771e468b60a7376e30d939e7a02f71cf45298304103f3550c2064710e2052df8e2ca1146e4600a1547b410c32545ee1cc698052b3c49c2103968c20c2758a10415380081122730a182bb422663c04408254e784117538042869210a060c915a04c3134858914362049f1440112062c24a41799a22c5118b51f070a4525222881edae1eb7cafddddd0bc005fea94eb235fb5c63aa9576360ec5746109937f06bbfdbaa39b6d33759ff323e8ce618c477e888084268e008612869c58820c31a650c1159c9c6186142980520c71723d745c2cb870428c02cad5e46aa21af20114e9440b21be0cb65eab8579c945e7dac78c2d2cc6d36e8d6b316fc183254894a081cf1320545284d822046264e10390348208084f28c20984b872020885951e643144122b90c0e804a8d5018bd52476f166ae68c111a0f0842ac838430a2b6070c1842d4ed053e404162c4c0924c50f6f098e85c417ce42820ee1b19088b34a54a2bada3eec151f3180a001135378e2071f8e30e2c910097ab0d282d61457c4e841144dccbc808584640013b56b37ea7de0c39204ea0599438663d0817f7bd99334e523bec3e91d380b3b70162a4e3baf2fd47e1b5b801dc06a312c0df7afa80b2e00f730bea3a9afd03d184ef5b7a66d9ef3bf59c9d713dd3fbdea265c4607e037364326f55b2b7161bf8fd89b97774f5a606f48bf1f4408cb6fe9779f93d89bf9bb2ebfcf437b03f38bfa05c0af007cf5c2ef7317bdea245ca585dfd8ca169ba38f88f98d8150f75b06bbe22327fdc4935ef1d090d03e3bd91c6cc58a12759f83e815070571115c82cdc159700cfb437ac53e572eb03938098ea13f0925d47d06f46ac8f6a0eed7cdc14a3601d4fd006c0e21dd849bb80c00dda40c7581c90b4cb24f61311f74325ea613a984b1b4b8ccff35ed0000cc4b130f580180ea247d440b34682789a17d04cc0d3366b034501cbda090e0d2326425ca9095899582b208ca82a583b24ec2278912dd1a4a12a42887b092a3235672755027d15a3bd1423847cf6063e89774eb28b53fd2ada1d4fe1a6c4d3b7ac38cb9ca28634df8ac9b384dc7df2ae1e3f4be7792a5f24fa6291fb3c29f15d217b24ea29b8460320c0c3e981b4c1d9269171af0cf0c899393e94def5eb53707a832c850d7b4e38218c9e537adbe977f2c34751da0ca5063762d1575e73dd735d9006ba665a8348e9734b9748846000000b3140000180c08060322a160301c10a55df70114800c7d9642825e984ac42889819852c810430c1100000000001161da0437a6b0e522f92cd1dea1f89e37971ad5d5ae6a19f08d1fda4017a2b26520cb6aa0ed8c4096de7a7c85e6fcf3fc69c0e1280c41dbb03ce1dbf8164a0ada0d539c14afea76ae4c05ebbee972f67c993ea3ac948e8202c3f4fc2926d0e056b3a5dd8c5f4e19e78cf55573264b50c74c72e178684dff59667d6b287d758ab6c6b84147fcacf6a41592972c166e59afc5377e3e1147ab9e622219a8118325cee7107ba4ef3e8ee2dcfd4d4b0956c934a8b32cee0b8ea6e1470a4a8a4867d0e040498af32353c25cc695a03fd8bb5d9833210360401d1bda1f68a8f2abade700d26ed461111c2a3fcec7172ed24bda9be33a2b4f4bcd1c37859ac64a7e32d4193173ed1221198a1642a0e84990695df40bbb8528b01e40299b5a7a282d3079a3899448abd99005d84a349db69a06748defc6d69d613ab6c191cce9872ea292a7b994c13aec11c00b1d459a6ccb7e5fd0393c8a3b1ddc41bc3108046a34cee57d58e4a49eb76173a8aa42c064dbabe18cfd566842b1d2afc61e2c4d6bb250050ac8c0d185b0e1c87070280136c1ee2ccc5def23e24ced8f71b9ab83afea5634cf6b76c1fce88e58213a065985221ec66ff4fac3ec96a850b5bebf57c567d1941a4434848bef5d4b0091f9327a3bd742eaeb26e487b5bb09cdf252ac5ed35395170539f9ce0f4a5654b95b264c943fc941fe1f74b9894ead8263769b0317eb466029b8d220459e3839c28ea990c7d3f4370633dfd331bb285d06acbe1b15ce55f4922409f3fe1375b456242cc52aa2a67666a6b94d178881c0a8f1a265362f63d748a7939809de85ab9590cfc0bb9c954f78449a4485e9e5667e89a4a5669a973568b732ebee259e57f34baf616c957623a29b7dedaab895ff888f41375c9701b6887c28e9c80d2d7c1e680818e368cba5915faf72dad86865638e9a3ca6584615786e18f927e06d17924563d4471c6fd5fe829081fdf011d33bd55be5d69084183c481668173b227b7b5bced22a42aa97d7ebc3836381e206d5d0bdbc87120913324513483a85696d75365fcebf717f041ee7efa6ce4a602a10889e5502fd53c0ea0cc95f32c5d09eacd083db3def055333d5ad4f65a023b582a704cba1d96a4e80575765b5f33b07a9f2c37af8a1efcdcec3f3488194ab170633e432a600cd5d64d6a6a684cc5b9e468cd019dfe805dac20167afd0b31005f190ebaab8ac58da12bea89604fb44d5f8bc5bd9e938cb9a72fb4807b061b9d3e11c7d0d0720801ce5f38a0919aad0d418aed7a138b95906c8a70f31d5f2856f88961f0683cfc036d9af8905ceb8b28a0bf9823f518eaed2e527bdfdc401664eab89ac9868579fc69079984a802c196546a4c34e57e35371e39712f5ce9afa8383764e0bffa4b8b47f0043368ac780e1e5b94ae037453de232812902c616971fdb0a8d9c00414c4c9498b542cee512ef9618fda4aba7d9e685f6ba3e3bc2d4c6c89e7558bf29351644542f5573e53044604c50e1274cabdc5db0a2e0c5b9d297b631cde910a1c73838bdb93fa2567455b40de3cc09e8ceaa256d8deecf131d1b10a290bf4f60ae71d69686d720e20738298acf90e446044250b39da5af7d6c7adbfc574f8fdb71ccb2d08c7c8f178028c78b5dbb1f705ec4371e03535c2c5635533d33bacc1fdf70c460d1b64f46dc11dd812c67c6cb1fcdec2dcbdf97dc69a7c77d8a1335967d90cbea9e2d24e6126e9fcb2ac13a09c385cafaa9347048b3757403c71ad60b3ad0be104cf7b4011a79ad4e18a9fa2b9252446416de918d40d8838f375fcccca3d40c1a59033d030fff5a34bfe9ea5ab8a6a52c80d94333837551bb82b90f9f8a520b1ee8584205f216a27e4be7c432bbf922239a4ee63d363e48db00ba1ae842936c500d13e6091caae4a831574e97721285bc7053534c9462fc9fcc681ad695ea818883c0be88cd9164d77e7aec733c320f2f150b743f75e1d81735d02e086fe3e45cf99ed5d601375bddb55c1517d2f3adf779c06b34f4366ab022f945844b6c48e75c948755d8aa5161b63f8e6421067e633986f30d3ba20fd1b1f7c1eab219259830668996ba3f60738827bdf99925ec8e381f92765bc5029d60197c94f2ef0be469ee53d1adee894e96f03abd70751ff87b5f08da0a80c57627d1ac10e2fef7f0e3614771621d55688ee881ba39fc359bc7a8f3db25e264e8db84c65a35b5741c928a4cba3eabe4fc0027d44b26d811b0fd584a10ba43ff18e8fd26ac3df562de1c86b466d161d8bf206331bb325f02d6724a18ed9bc4943e0183fae027f6ebb1f3f735a1c7e51417615c05b9f121a6dd55f02069da2a0464491ff376ebc91c726b58e255b9cff9767b1821355883fc6007e79767eefc56f29f1a0548e87462190757dd8d13cb861a3bf7a9b1254810d7e72d73e98e5fded4b29cb34c8cee367e791c9b84e6d5289724532e1cd63eb1302fbd00816a9f3b9e22af4cd0b92a340911a13e5edeb820f62d3568a09b8f6dc972c8742859c879ae757b7e9e49ecbd1bd87adeb42042fa91e0b55317d40d030f4521d95b76b06e3957c9e68083e75c45911f79f312a80840a48371f1e518494b6cc00f9b2265bbe9f6d71ae25e3a161bdab4bc9c7119c4f407562e13915eb4cd6d97cc97447aa3de3c0b6db5a2705e3842fcca8885363b86d9dadff2f08d262111baa1c4f7cf5fee4654001ace2aced542a9f48f1e00558138da355864e9a45a48cf147db037a77ff6069fc1f1011c1a191ff7f239732bd9eecb9c2ebb5a6a621e21c6b7e799a3de30499f63385682116298a99822f1e05b626e6ff5a465fdc8a35796d657e82513404e1efebf246ccdc228798811dfa1c5e1a2e5003e9aec41d9cf159be304a3dc48de91ca874f4cc8f7398f643b14cfcfffb2567b1a38cb9bccf422f4a11dd75a26f2ce4d3b27bec7c807cf4e2a32b3f5a5d9038d2c1a174d9d98054577bee976f00519eaf6fd4b5561c69f6860bb98052cd1c20fd0287ad0c0497810541dc22f7d76854ef36bd718397ecbe8c0187852b0e193a0d69d58ae2bdabf31486d6e95c8066f538a6b60e6e663ea7bd8f4fd7e740846137c2bdde6ba8e6993482ea4fb4dd898159619d684dd5df2a0069e6c6faa28270a8118a9027212e0f214b874c110fbf94d2c1d6cd8a03501a97e14e07b6ea6834b899bebfd6c0a3eb22f14f8c033d9b7fbbc4c7a4a494da664232d583fbfdf8349425fb3d2ae473f6c7e475f7b282a0c6eb74c8a76aa0009eeaa7485ef6448a892655084d9fb6785c79a71f9382bfd123e92ddc0fd88bd0225f0dbb6145c1c18f2b8805d05b1aee7c1c431e3c1230e96c11c545866c61d1a64c25f4a2f38d5004ee03250c9e9ad20c5d29116644dab3e0efee04961fea8a04f25aa9a0872d825d20aafa1f95b9ce8625b97d906ff39ff458297e20462a7e6f213d4bca78e01f980d552ee0b8ce95ada802d7552a233c3449f9165641387f1e2a52631a4e934d9c612d0bfd2dad6fab2d35502af48da2b51a4e8b3f1e25f14d72b96d842b90bf48845ff47151d2496f02889f89c96f0b220afb300f8d68111a1d5bb689e07d067d22b647e7a9e4c2d0d2c1b8b278faeef76a7e86368d5d1f8874b043815ad0b381934cc4387f2cf8766484e2312248706a90fbf4ddf681b9ae17da265c56a0db447013a7f3d47c0f958f9a302fc61f7ae351b84c9a4311dbce5c4b3956170e62e0bf86cb54216bfd71e845f353d28038429f97febafc4d49b4950472601993580b20afc5efc308cd518a7682e9a69c4f4b0c926bab50d4dcd03ea03c3cbd514dea36ab9595a472bd3175c736621a9fc8deee642f5a5c4e65d2af890383d823d498f26e37d8a88eef40aface055d49b044a1595ec14893624282556cfaab802dc134d0cae99dba1d3309594d33c8999095c5a9bd3619512d1ae85d673e80e2582cc95c8c46d3040959fe7c1f4d2e2992493677caf04c2c2fc05db515c9dcf02ea0e1c8608615b72f412202b3b84191d3abd6afcad98ec896c54b4b2133d9fecc235abd75b8db7de64ca129e0d23b2a578cec8b3d51b84b81d59f3c90a8e83b57f9d9880d0cad8ffc56686fab428f0b53ddb41215c17312954aaa9e4ed2204fa5e1c0ca6197a71f861456eda9958ca223266ef1cd45b794048e1d70e20c8ff6283e8e64027818f4e2394abe32e0c492f0b650d014935d7ada36abd6b794e22b6b6ed7b4bdc0b45a852a252e88a896da978f976258e73e1710957c9a67ce9a8dbeff41f187845e86f2b88b9144eff427aa44d8c1f95e8f910ce78104552dd1c295fe7a47a0014435b7613b5cfa8377b7731544dd137aa4ca6ad1054fb5c029c8fe260469b5630975d49d754b57ef06690728922f96ea53232346ae27c181186c632961d412ad5d28e404292573e8696a49e7c9d31e1d4de43a6f464213fa844b8937b2849d5cc86fb0efa101709e4ef94d502fb8050016de7b6525090b2aeb0a50279cd6934310ce4b8420fab73ddbf06c4e28ee6ac38cdcbe580c6b8302f3ee70a70853c0699d5d2c2b294c30f6aa6b2e69f37c6254458f7fe42420c9040ef993ec7e408502444865f21355a0401b2b88d8314e1bc11a6c65bba14124abb8ada805f9b84f1f271db02cbe351c292d52ce12656d0def703c6eed2af423803616acce8821637ba2bed4db1bfb48a64a4ada9b23d3780cbb9c46550c3f3f661bdb0a8410d3dec0ce54d5275f50e0784051acffb72536568ea374cd9c9324a5f9e81ba8fc15357bb4c94057ea709b3df870ddcc7a6fa9d4a68000238dbd23ff4d051123b67590c4e2fc0b5c5e1642c17052aa558bb17adbd32ddd30053ef4c3f09fa4b278a491299d7afca7a6260f60d7589df7ecdfb060f1e80e5a20eb5ffec13750963380f02c530893fed0116b10327e0309ef6483b764e184b70c4a0035e01f95b0c5e634816925441d19b0a58041d7b220ea2241015a5f088f00eb8770f41937629b3f21198e18724df0696d4351765cb121623e33d5c0693abcdf0d97db1da4b4043b2f987022f4447374a97c14cfbdd72ea40fe0addf7f262d71ecf0f5d94981f11e3930d99635f62007beb11741c4b1001f90f87d43c38353e8438f382201779327c24199711ff8e8933f11d5186340fe87fe66c48853075bdefde6d5bda5ba2485c5ec687e7908f973eee0ca78f5eca8236cc7a7f21576a50aedf7b811008a0d5abfadb6a1cd7e86f2a9fa23493edf886afb2862c0ee51814d0f820ac9903ee7b622766e8f9c358b445f7994830668006e9619a4c4a23ddd47e8f4df0aa5deffd990bbeaf34c24b897fc3c3cc4ff70803ff4cb55b810983ea99c205ea9e128182ae65cd3231a8a3efffce7f7d8a72cd934a90f7e7c6c0eb7c229657c3f44579ad0f77e96ae5c869ba29402c891dfd42e2b3f4b10febd750c690fe2f0ed26fece5e7b7c2cde893ceb77b1d267560eb57b5b391b7ee684d1ebffa0cf2483f469fd3f0f9c524c99430d660c21d35d5313636d32581f998fffe21815a7fd1a3fa087bacebbeabde37997a913bd0cd6bfe3159e42c6c9e85443dd68635559c296b53a48f9bf1ea8550779f48891a27594c42bbc99b8fe6ee57c177fe42e7fe56032c4ce73907b4e5fa5cb2eee0dffcd4074c19aae70d0ed6d33b0c299fcf0eb217858e200a33d313625a32df5713591f0a443fc05472008acf36e5ab71ae7e7bc8d57b89e6698a26f775cba95603716b8a35d9384c2073fc7a12b6e9bca91cec855d39a3b914599396a95c1499058fcb7e48f2ab54bbfca0d6936b0422cfd6f2efe788d332091729ff42269729cc190303b89134fe5868ad77d8ed34ba9fb7f51dfe22678beac53b8bc8c64222943305ea2b173764d6eb4dbfc50c22ee72f2c7fac9bd0639f93e5f357a2a22228a8d1158558b109c9127b565211112808aaf084d2a1ac147967821a691eb23e1662e47b6807b04d28f55dfef06dab40975bd671155295217eb554dcfa3db8c860e55854e8936e4f474c457ad17834bbd5d0a01c4098f2964124baa8105dc53f11adebcc69bfe98488aa9cf1d82f186b6d89d468ad922860725f27d83a9a4b7319336c510d518f54d7e385411dfc886bf6a2bb8c1a97acf43b1913d38f2124537b6c15d5c0a6eec27f06f28cf5a3541ce201c01698dbb7eb7d77789f939a41e470a23fbcfb2640785cc334a12255aca1ea88d20bfc319cf293f12067792a1271385d5ef0cd4786ff98faaa86d9029a48f154032bfb8e06992bc93f5a6358ece5c98deb80931b0a686b36312d4808cfba99c3f4b408eecf19170a908eabc62178cfb14cac67141e9ce32f0fdee7ec0950425f1f4070b0e5667fe6dc9a292dadf196dfc42c4ae5e8f04482e1752d01e6e6cc67cecce3775b97d9d9ed749f593c8b207cb60cecf3e3c787c59a41d98037647461aae97e653bc1434089094772c7cbf7bd626e94c446a234932766f620ffeb25b96fdbb2a1048785517106e8d76a3f328a756b7c134165a40603feb6cdbddbb798e70654e7e1a4ce87c3efab2524fb9ce265bc8dcdc32ad0c0836cf0974a015027254af520dc48f9d61f2f011e1ec523689ab9a1124cc76a0e8059ac5aafcf2a49a33b28335778f8a6f29fdc81d68b3e14ab97e26ce1f0e28b80f45a99970cc615243d9e6caa6e3eb9857a37d1f7a4c89061b1db4b29150ce61c290b5606fec0a5a1e249589dd65982069a861f6c39346187f8a0bb1a7aeb31d5b766c2aeb88f6104c8b9ce72eb8701585b7bb736402f925b404a8ef7cbc7ebf2cc2250bf08e3a0168b9abe070bec1579d7ada40e033d43077e3ad636d1f1d511d9935e0c2c5c916ed9456b5aba20d2c9e06713a2b2a18a6a066fc88e1fa0cac0ecece833f9d94a489c9e88bc781cd949c36c9956f64df1c9becf7642e3a8f0ea9df5c28236a318590a243c21290636195df81eac5957e911b1a2a56a5adcfd09e03b037429df89e6e3c2f3a7596c98e992fd583b1f6a5730e1442499bd1a0148c8d6708ec1502714633da40ea5dfda27083099c63a9ee95269672607cb63db9ba78e9a1d203b7a36a70d3fd6a6b220a11559687a22dfe7a03901ba69a05f9730b59229a2f6ec9f1ae82b6a72367505e4121a3c34793b3c174a3020be757a979386516b1cc14b411e7738c2fc8b8588e597b13c76fe64ad61efb052d096a2f23a4e1c32fabd8bb6ca479248ce243846106f544f121c6455496e96f4e5b80cb120c471b9b9c5ad14eaf0703f3afe0bc6d138ff7b5162201ffe63634e0c80fea68312e4780d99cbc49651f59f3fa1e6a7e36cec658d83ae0be9a481785746be9c259037e87d1e6bc2e68ea42d2e1df34f17670764f6f3fb584112114985abe277b58f3292c13ba94bd380d2d47d0d75749d42c1b520bbfb12faa21a465fcd1e66af1fc8414212ac21f9e2c789944b973ec5f49bbde62284074222d28bc180219db376c7926fa5f2ec0bf422eb7f5e6ab13f34853790fce584a578fb2be09f5ae194c406049b9f9b99742d9e59052316e38d8c309847b42d029566238d36c3de4fe7a8b3dc99d8a4ba633dad850b07219dc37dc18d529a7daef5b611042224fdacba3a0af8d3a5d6dacf36c3563db07b8e98dd0850621d6501da885b7d8cf5f99fd783976d320d79c28f263626a701301e7f14a40f4c5d8115c9ced7b8612816733bb6472182386365e122d1b8b892072b549901649ad8028eff9a74e3d74ca0a269dec98edc55fa2c59d8bc48bc2b641ddaa6b002de2fd3730f47cbd7b237abc6e6f462c1866e100dd20c797cc1e57521286ddb3afe87cf8ce3ec36e3fede6235cf45c4eb821fd7dd1146d6d8daef728df8e4b242e400e852b7fd6e5e2845df51ba4a460d7e1c2726634ebbe97bad0d103b24e397027a00d319ece199b8a85098d60a654ae268aade236ea2d12f5f2cd28804cb86f4fef09b4ae868ad2e0f3678fab4830190ed0903fd833f01db83fb12aeedc11e02ed1470d5cfc4b70924f3ef1e3b334f50eeda4815690e84336782572e302242c89a50d2189f0c897d5fa28fb74a228ae30b813d1286d50f9e061be052bc2326192bc4a1436a4883d02718e1e25efe8a80c6cc775fcecd1f62b9410b4cff5dd13ace15a37eb10cd2b22779f34d3560b7c30b1d155dc135e3b6697c6aa698b4d0212916f9c46fc4917ae01246b3809eb2e501ab30d29384820a15c4a0c506a1a72bb4e24ce53259a672916caf7b40bfa0c4839223c27f46787760f0e4582f66aba9406501e04f15dad249001f890b47c6d69a11088fcc25081532269fe1bc5ebfcaeed1abae16e410eb7b9edea4b908b9328ff7f34bc8a979873718f6e70eb40f57df555081708a63ca89e73df2295ad03599d88b53bc2c8e9e19e8a5d44263ba48c045c8f376d59228e0cf549f6779613ccd03599b5704ebdd678f436707f250965af1571553224aaf80c0d112451713a9fa2f2838f5a433fe79b81f3060c980f2850e5cab8ade9514b49363221639a420d0e2acd4f1db509220a394f0e6239601ea5bd9350fa834bbd9ba1bebe2b11c52843a61186841d3d22b5e091bea95d987ccc4058d369968cfe462eace3ac6955911f0a11976250e9fdbc3e6faa6af57f3ffd368144ef358f73848fd6f20efb4917d28f8bb551e7e61c20814c9a41245f523f36cf4a34f2f515f1b30a2b531b99bc4378836c33e45346e2525b027c56f5362251a3faf55ccab9244164716d4ccc8b4716e59fa5f9788230dc8da00fdb6c236449f83e51cd13218ea7c27effe38cc67793b9acbc4638ae4628544b9de8ebf291198933bcd4037398c507adcd6612de6d8dc2a8cce52205202fda76f21851767b2427126df9726ebd0434b9438602f1a3ade89914aebe119485b48a80471237b09a1962c0b213c3c0321350bde3420649403906511c24bca715ba30c85f02c030621e0232ae620408e7366622ed961327acf24784f5152af3426b39b5e4f19d35c086200e2ccf07e6802672cd14dd747662b8f6f50b0ff3021b1649af962dd5cb4d33c3c2600068ddd0a9b905f8b04683440fddded5345cecaf6ed3798f95a1a46dc318e3ab5711595c7fd74254073fe4a6b12e9dd07e9b7d283af5ac4d2144be16ae5183f50507b37c59da04720131f2ff5122af2232426b7c30defa2d65510fa8f47a6d5f14dddad6ebb1a3d88caaaff9d9e20cef776449e883187acb3d79ecdd38ae93ef8abf257bae15eb97ab3f8712427ae1ab0dd95d7eb579156f8ce01b1d3eef83ba0ca91aa4b01fc0e8045c8d2e9eeb5eb70f3f91c2890ccc64a7bba8b8919940499d2e3db1b62059a1c1dc081f2e5b3d240e805d6bd83818fd812299577370c43341e9cd49f711f1761aa50d9159c5d10102954afb820ad3977597c206c5ce15093744c2beb582cb7a3c1b41954a705e762790c78e60f7fbc6af2b18e93f7dc37ee36388627ac04120cef317ad0b1a8052f30a9cc9c827caaeff8892f15c97830bf8acf09d26a3536f795b1cc2e9882048b0f822d5fd141fb9ce9ba1c3dc12a37412a231dc0d43b9c6c4f2f461d5da5046527c7cc73138376e9b20cb006218912e6acb3e2b7ca22ac4ce4083bf5ad022085446696fee410c4bae905694dd8aca8b1441c5f3e1123e7c16d51ade484ecc50cfbdeff24f50e3f5a8d6368ca4cd30f8bc16f59a879206f3d1f06a83964e0e1762632001e3c7b47fca105ae41479405c2d8af40a4cb4c91af709f04ac9b303dc31c3867705edad89b30c7c11d4a43d762fdb94176241a9f0ed57231f3d0efa16c2487574ca9d130287eb67e6d3e6f8565bdb0c0d44df43e1c0bb518a8ef9341a5fafba1a41779bac1cd0654ff1be3277c3aa228af50b4711c44080ecda033f23a857bd0707bf4d87a860c8916ac866a15dc3f97f8eb0c66c002ed056f06cb9cb84e1fe8d917598b4800ac033a5533e4230c5d854be1f7156c06623c6068ca30c16064b259c1bbf6f1bedc291d7b35ff83936c9103375c736215c23b06019653198b8578b6075f99945dbe8c9f5ba7e7d9c3ea1fcd2e47847fe3baa53fe300e7487ce7f23d4c3f589a2e8cc36ac6dcb10a90595cde30efaa117bdf8b5442525b9e5b7407dfc7aec4cd2c6093423c79ebeb6eb9b9d1044d149d3951387c9894c998620fcf868fc3441c1ebb224e6acbbd1ce82010a3212e5335a2da0fb85b4c6beea4210e81f2762bb5485df0d08588cb556a0ea3a7c3a9d211eb63e8c6a4ca8d364c557c791581c3edc60593926a09d56cf73c1ae1fee92a2d252d2316ee06cb3a5e4161ef295dab91512ff1c48d2d161a83827ecdc4ddf6960137f8c6f5bbbb1a6f41ce82b8f94716ee03267f14034ecf1d316f4a7bb1461e6eaacff2111cbf10059fd748821cdbbceac659a73c6c0876e008b0a001836fd860c4cc5fe9ef7e7c614fede49f6b1985d70bdf98bd104d99a51cf3cf01374ee48cb80a11eeeb698110b5c2a0a0c87a4b73388e7a556eed13648e98bcd23072bb27dd7694b3344577f07ee9290b2e4ec62d1322ca4cf0091ee2167c10fd2c0bde344fe91206793e4180467b1b86e0d32a5805bc254a6df8a1cc3b7b0af76951650627b24af71cb0df512a47b87b7a960da0d0195b61fcf10cb462754b98f93d0c1368c89d4b9aae382a5e3a110ebb0b133c1ca95e0b9b72a9414a5ff93d0e3d45d75c49eda0403eb2582e47191cf83d73d79a037d1f16612454214e1c67202c3ebe92a9b046261523bf5380cf18b279731e7510d0e215f8c459ecb224ba3575e0dbbe4f3214e34af0216a453daac63d100a9c4a0fac5987ce78c6788de51a7170cc7b4b915688fa88c2c4a88fbe041b832315a63ff1ba0a4c7f1c0eabd2f6c003390f4e3ce76f9f2de1137f801efb6f43f3a3e67cd4337b30e5be8f6085aaeda67c098081f3866ae9448238ffb79deb79e10ddc99bb591cad9552461010fa4f9e5b0ae60cb50d78d26191da6b31ae98f4a2051714a194735a74a53125c6b408c2a8cc0a5e52e51b0fc4e9108636c213fa7af17135011750a318eba568c834df544016a8f77dd5e4907a78a4430236a55c9009667b8935a0326287dab23ce65cca5185bbbe5a6d93622c41452546336e4a4712a3fd0866d0eafaad3f728b3a05dfcf6633cae62b494cf9c3daddb4fedb5a009c98ea6cf979129f5e2d9063cae6af300f0a8443fd25b414e4f5404a9a019d636f365866a0bd716794c933cf7d7293eb5b09694d7245e23ee1d314223d86abab9a2cb294310eb41137c836f60228e5d24930827106c16f82fdf1c69716e4ba0b3d692de91ed517ca5b28a6c74b74a8e0c823de0db44010e62eaed6b0fd756bedac58cdc0cce2b20fa05b2c519db6867c4574a42a41a8a9d903b3534eb62301f258c22d7128a5319d5c73cfc0b420834ea219bec8f1a6a68a0ec93a63a8e21c16c766037c208948beb268c83b9133b9af9c432c755cac7845ca47ba5425d583ed7d8ca9bffe6e04febcc5b374f02533ea6bb2d15ecf4da2f10d8c01ad4a88a7bad6daecd5a66ba4e0f13c38c61afaf3100a48af17026be56922f5362e717a893816a6d6cbd504c7fbd2c068b5a3aa5d2f2bb2bc1d1840b0d81a420399ddec97170378d18b60a0323bc60579e881932580639ce3bfb6e4cb8631716fe41803326b0e65e235cbcd513dddca8182a9046a8b5e74fef09875750eaf38bf991cb3800f3e3e611e5a3933155514d2b41ab50138ec0be376befe13a5669026edbeb216e189db794969b92e0af37e125eb51319332ab9cee6029465395ef5c2a26fb912d8f0ae4ac9b31cb265de939449ef54e4c565fbf3d7ed769f80174394688fe6a06f3c977ac5e3bdba9f222c0e67116b2b59156217901a27643d93ab3aaab02e42d1a6de7148585fc464028d58f726b21344d196aba5f18ecc1731e99f4a470494d99ecfc4566fe9df8e2f6b7d1ae10a254db2f259c27ac973b29dd51a917faeb0656d90913b0fe5d7a3c5b3002c39d0937c1f0168415f24bcd9c361ceed1785400598519bb249886f80d0c4025a8fa5800ee55cbff79c9df684c5ba46c0faae04896a8a4297dc71b2e30fe8fdc89a5a744e1caac32b915630a11f5fa857823b7f9592b2ad01a3fa8afa79c6bbd12786cad632a206797fdef9865c1d934f8fb3087099f8e9d78748654747cfdab18195056f8dd02fce06b6958d8a1c6914699797638e0dbc1bdd8371f04a55a99187ec54bc016424df0a91f4bf3b448939a5f06ca8931974d904de36be11e24b374e5b4951c311d87cfda86a52a9e1e77b3b574d27217194f9e14a0ae3c8c6cd09e56b049e6fe6400dee422af6d65d8fd055dc1237d0cc3997b0395a90b8af31a8bd48bab28f787835d64c0dd099cd9bea5d0fe1b9e4c021aa6a2cea4c1f7517781fed540809d3a468211c30aa12dd495308fc9044979c087669b4c537bf4300b970469481cf33b8322cce8280b1b621d354cdd4184d2320bb8f1f9a47d6ac7d05300ca9c7d39645018f9406afad6d370c70b5acc726b51152d2b1578ebac3028892c8347ea8a5c3d2072373b2b21167051867491ff86ff48de7a2d7ea7303d66224a497c8efde42a55242f285342e11a3b10fd9c51790c392ee5ae2ee38592564fb86f9c0e10e13b368cecdf5cb27abdba24d1c41d071c256900d7a2a7e14f35b985c385b387485c2a0ede9171436a3c6f1095b27412b9428a394372c2fcdb1672c61ad70ab11e62c8b736f3a30587e1914a6a6eaea740c45aed230b428d1d23dfd853e1a290f540988cdbc6f455b66444a28914c747d9a963041487c0187c1c1b9e54afef856430cfcc6cd09ec0296c1fd63883690a43d2c6c634d9623fa482336c86e767fc563a56e1a08348a4d4433141a744fff8b5dfb2a222e1cbead10374aa6b5c09c621c95d3d60cfc466ddb326fbefe5bd447b98cc95c15ba0f1b7f2b8f01bd45968112d9b806165adbdd9296215d6898240e71db522c05a8e45a749ad2fe33d0579363bee81cde83638e7d8393860cda0ac915e25da03fcf51280bfe12f38785e4a8f266f35fd387498185f8aac2e762f30a23f4c46904f89b38a84c2f865c4365bc6392e349514d3696c6445d300a363741df73c8d6bdb85c01da7d4aa3cd87e9c128c1da963f644bd041fa69caacb0128a4dc3f11d074a19661c104ad66614d4d9b909fe65964d14aa3a819d83b1d830266ef6d38f72ec17b48730c500ff8156baa89d3d1d9c1c2242a430dc7afb802b53c86707fa0349c76925851e9e5f0ee94a1a90d0533dd8d8b6194baa4c045e8b0b18081a2ab3974a1aaf6ed4aa60759d7d0eb1c0728abbed2ef0c1d02a49017a1079250bb69486b416e786544d1e47990bcf71af5bdf3c1e8174c6fdb813b63b285403a641aae0b07d8da190b8c9ee397cee5fd007614851d3d2b7ae9c85b459c6113ee2debc0ef7a2817210587af26f1dd61b6eef953247830c76ba0462068a9b1a61cf141b77c7bf6f759b92f2455a653eb70a327e4d53dfd5ebe63ec0e03346e42ce882a0b6095ffcb58e9d2554478265534ad461e37dfa77a819d10e96fd82a2d6e06cfce7ec9e2742f790def169297d2b802149e75a08ea9d1651882ff55bb00a4386be7784d89aeb2fe36ae12995b13939998cb8b2e74a69ee433b450c914eecb5139afcf1a4480e6105cd21973baf81d28e75a42ebf464ace214a7949fd893b526d681c2a8d6c22c2c5b34068fbd2a1a7d228c719db052de518405b313c78dbbe1614e3d7ac24939d24ce4094a7fe3a4cbad2e19fc701d7c63289a2598a934def10ffafd247eb039aa7c4658b8bdd6478527316149b5da8b2af41a5492923a5dbe1748fbd69a7a9101f06ee62c081c3aff8eb2ad87dd919853b939e5a4b58c8d4a08c8ea6caf9aff75d4f2827c88b14c3c7c56575770d8ed2660f7c62813454828b96878b43c46a5b2a27bad018abebe9fa7c77fb7893e4c9c71aa1d95a7f5ba9b9c14a5dcb785a18a41f6e801fdd2425aba8099091892af4b5beb7dff39d8ab85d89db87871e09836f78d02679bb8af70333d3230c09881777f4be66b633a55137b4d1a1cff05ed846871e0e1a27781a5eaf01d22e841e881539ef3aba434efef091d3ffb4d499ef07f57c3b6436566e27bd52df34c1c90caa1586010b939051c6a2c26bd462050f4b1f45606085082fff7bbf1480b19911af71801eafd49919b38119a581c5672e3da361e11330c23be2b506bdef6bbf265391501cd63044a3c2992ada7001d4a4efaf80f5d9df65d02b874f3f622cd888700dbdafe214fd414ece95304e58bda70d860ddef26d5fc02b1e3b1ad26538940a65a09e1e5e306904106035053d83d92981e7c10436d066d12814a324734993797932dbec9348d8a3c1d47efd08deef0f2feea8c46b5a603ae84b91c7811ebadca3703c55d973a91e81d7cb3f212d1424e0b471880a4403bb018c4a5bc3d26a4646b91948e32b0d0c176572a9dda8f2b46b4fe61aba58545bd8c85ae4c5279bd4578db77a21ae77bdcf845be816f8be65ec5534376941421b4ff45311cac7a0417fa5247086a4e334d4d5bf2ac4f9effaba24918e4e44492d77676ec21c9785e5f860cf0b2f276e767120032badedfae1284b857fabf681f4ffbb3622bcd66667bf8f71c4ea7794bbe4bdf4e6489d9066ce2a79b9268aea46e80c496cef2938e6290c4cc1b1b893e1383e01dd5b351868d9e6f8257e8903b0f4592aade8b13fe23d842ed52c3c557f1ca1bbb9c4675dd81a8925fa0dbcb10e1a823e6ad4bfbafe7b59d6886f7e44bf15a9b30ed5370fe6c2ac6cce310f07e759140d79e28dd9a1fc73030509abf274e5eda474b5f8392e9e82bc36e251913e0f5c486f6a92fcc03668e09455d78a8149d12b9b5354862a43a3de804562f953c38bca13780dc49be93c70e4c09c22ae1f9cb83afd88eb34b43a9de4d4c7998d878b8313f5433090f13539927ab982370b5e6bad30aa1f99037d650555d401a6e869da500b5acc5a3d41203ab974d94ec06c129875c2407490cba3e8c6e45654ed2f2c4bdb55a2f6059d20501c16d9751573293bd2dc067a97435feab151880643c3c588b781ed58a63666be562c1a9551dc09243db5f419222d17c086f02e1e49c79b10446080a5282b1be99a5fff411c59657d923c778add45cca198301647fdc85bfe483233b8944489ea6d238c3506309c57372c22c1f7513338238b70e138455a109c412ce9b68a85b7663b9b2681e10875717d2d24aaf2deffb7cbf04b2b629aaae7354925c595e627ecf06ff880679c4a55103f549f80102fb7df80a6fe5b964f54f9a9ef2a46a35126014edc53a21e0de85c492dac630628c8298cd5d848e369f1db4b1bf4a684ffa6dfd77ae4e97ed96a8542aa9c3e467886fa81d13be30674e51a1b3ef90c822daa1382e0b8dc3f78a7ced51320683b4dd41afe50cd611d870574ad7206b05fb7885f5e53b58737e50d33142f6cc42481e0e8a663b2e5623ab926f0ffdeb6d26f7a6cb32d53cd41780d7bfb42cc5b2e737121fde26048984b03bd1e7cc2c1c980dbc9254358bfdadddad3cf9ea908fb4e8dbe610228ef7945c0823834bb33046fe11ecbf96f0890e72ba9337b2183c32abc4f6d8fd37c4455a6fd53a926ef3b5de169b52e8054a09825eb00db573d28cf5153405886ec37588fd815492de1a119f49de8c9c8e1fa92647af5085b26e033a555c76ddd2fca82da19e2097c6202c1fa03d0bae54498809f8e34239aeccc544fc58d662c34d09770a6b13421555a711b7c09255c60f02483e150c5c32405c3af12773816800d04f17c0d61611f29da5d2a06b6c2060aa8332994c399c3907a57b7632a42fb7babfec50b3fa6f958de6a53842799e1412a52f7d2368fb2e13cc335aeef8c25906dce6bf50cbf967035906623eb24cbc913731d2a1c6bf17242a1960a8f982bb47a4b07924eba5eae212ee8311ac144d5f37c9fca0a485565e18ba1b088a10bfe691021fe624d2888992c0a1bd3faf8a4f3ec85a9a06a2ca4282881acf4d3f96c2e77538f4db8a9b61ab9d1b8001b917f540dba8b2f1d51e0f8614c7785698e8d3484004ebfbdc763921b720780124e876fba631a35ddbd2e9e8d980e24addb94374f5fa5252b018ebb6787840ae6f1a2ff6d4ea118ed902924acd82251087f5a52ce9e63954b0f7963e99f169c95a82d4901644f025fc1425673c02f648caa7de8942641ea80b92a2d45d88b0c7f2ce993f037fa58921caa5d052517f120994dee841d8e90f01a4276eaa613d98a64a68128719715e05e5546bc60c047913186f9ae15a4fe0040fa6943d015495ec08b17b2eb20c18ce3b279d06a0976f14ee2ff91f1bb36447c54553c384e5d0c82b36cb4d44fd00a1f6d19a7d852638a5a919562bd74634ed8de4d1a054835b363ad503a08f5ca1c8e660f7882edee207feb0021ba045f8f1ef542a7ff3cf744c5770ecd16544be029191376bdc2c44b5303a6acbe6c16d57c867532b4d669a9eda34085b73f6afe660502926d784997651184f153eab5cd8047b6f8b9171db0342bda4e2d7bc96bb440b5e66acf246241872a5b058a52ee5676c9c8a88fe0b201baa609e2729baf49602dfc5f69f389d6802bae66688660056944e4b3571167455490a94e6be19afa3310c3ff0f7b06145b951c5904c6f66bf491d13a6c73ec680039fb847c2ec5542b80fa4b20b49b104a0738585dc1e82d6ab3c538c192caea5f294694708a52e7a64cbdbd05631b9ccb8c916f46b725d864d1c942bc638d775e1eb5eb1603dbc85b7cb069153c4fce39115bd7041d1d45eeecc7e5df631b1e01f0b0d67b3140c09f9da91c320d13ba946ddbe1d46e13238dc47d7513a38f0350021c95dade483e69a8b950e1701c7c665af92b36fbbaad8b1cd8114880443b03a69666da42361425d951a1e604cab4c488949a8dc4162b390c3da39418b19fd839d6620047d22582462e0f67d8c53a241155828f2828248eb2b73fb8d6a329f361bef0714ae685d5d7cbd67ae4d08c1e0115828f24aef2c745252c4eb2b76b7243235ad98c15fca4c98465122d91b02980c25240f52c464cda14416978ae90a00fa8e15c55ec18e7779df81a14565ab81ec712beb1e0516461c4cfe13f57c8bd2f552ea3753f6af4294b9d8f98b236151f3a9ced565c95b12af16cb0d61142c774a441793d3d44448537653d444372b9aa01429a33169ca4bad9f0db99c3a80a856d7c08d8065e9a42554943ecc9061c1dc636657abb2dc009b0038a4070774ca45f2cbddcd1ea6b8b156fbf1171784cf6fd46fd4f934929cfacb90f1a7a0403ac011ee78e88383b4f92c561500cad97baf59bb32735c218ef2baa09295c87cf9c002825b8e95ef60799a6a947b045d32410fb75138c70e7558513d9a7b94ac13f0aa63b4fbfa05484fbe7102dddaa4bd72416cc69641217b413b46c6597d3eb72e2401ffe80f98c562d7da751fd9ab84b8b0ca6c3c53ee09ad1cf0b5a734c14a2056c901206e97376331214bbe5bdf91e5955e7974963379482a83b6b4c63c02586775c06384be876980a8233db75b3a146c8fb97f8ee1c3b657f0769f8aedd0d1e28029562fc4f1b20770c4fd028c4bfd132715a2aa8d68006b135ad7cafba801a53800718f4e7804462b125d80930f141159512f276622cf55fd592c06551c4e85a31d51b059fc0879730a70bbcf362d430f3fc20dde6be140a2c711a75b2602dbef84d25260489db5b3e6002f34743f4367f6541ed994009d660be00238ba4a22076ba994c7c1806eb383fea291bd491f31e19422998b3d4276d302801a023a203c8ce91920161bf6b0d4930b1d408075cc0750564b22a7dc1d5f9860ad12a398ae43df821e01116a7d92a421da008473b23305e1819bd03654e61041f37086018896ca59f9edeb4330ec16c95bc72cb3eecd1ccfdb6dd7e1f43d0741aaf264210dc98ea80da625ba62dba112766d5188b8949ee2890588c83c5e3e36c594491a9826e5ae7d3a350230a45a0dcca52a415e905608d03d78e5f38e06e4d7027687b921b730ad3909295a764897ad2c884f1b4a61b931ed03806388a11e2637734a3d409c8c273047af48049ab39120d4f4b943be1c342032f47df8fdce1a00fe223189958e9aaa3e406c91279bd9f727beb4ba64d757c1038f1fde43cac27174fa0ef8ba0c1351c3eda8a870ef291b6da7e6918a37f9172855640953295f6a5e1c1200a4ddfded5f06e333bc02e94f2df9016084275549429da16f08bf686b632f800073441dba5b25218a95a64044457b5669af684f7c61c5e9ad1918f2ebb758f677e95f5274faa4eb4a5589205df935ad4eb30bca5353448f46522bb4cd6b73b7c1922e986a397e281c7fcbf23ed7566c13eefc0e293b741cb724fc50afd7ca092541d29602c51e289de3611f0001413300592b845147ce0c064032a19c8a4d2a6c9930454f01f3d40cd97a4c5f03657f70f42d60223aca318881a1e396ddc79eb36a89937dc111688a6cfc83d9d9f4ab0c244b35787593bbfaf4efa1169f5a0f268744618cd054afe27b02e337a7e91fc0eb0c44d0954ea5962d2128234e2e5c705ad25bb665a8f5efd734d2742e9495dc7efc3779b899226d7099a73fb1f62af4d4316ffd697dc6b32d973686825ac7d7b9187c6352253581f3891d57bde4b4354a64f71838c7390f5acb7a911c7db23988c7f09fd4d87496e15ee74e69cb46d808b417abeeec7f75ca1c2323e73c361c082a55d38d35cf8dde8e0707b0a02c07122c19e4434f190eaaae180825d027680f1eaec4fa891582fc9f68519ef7c6e7b50acbb077f456a00a1b92603712abcf6590cf7a5ec80cfc15e172f2ba4452e13b2c3b61eb3405dafa64d71a467cbcc814b78af114024d96557ea8373f077e3e04509fa69473f086ee89d1720353fa441478a6ebacc21c86d4c11db6ea914bd235377e96caae9733cc43445a3a9eadff5f57e748f531142fc649bfeb5df867884e47be2e34af9aed43df99b00812fbae3ef04d83788720bbd7fc6f80d4ce57dfc97273c30ea4011ff600a1faa203292bcbc7f59365a8a95cce5e9f42ea41933a1ca72d8db8960f204173f51982a85bb10061b4304497b56c84c548de60688ebd651d8625860c5077cf26cf2c24ecda4e97875cec8cea592ec24076cd56d76faf382c827b6c687b7873939fbdcc036cb3f97341314740c27dd272a8a43ca6cf52abddc423749a3b10385423c7acdee2afd7a4f1a21dfa591239929a3e0a8c7d45678d40a167064946913579884b2e62f42f2fcff68fffd2cf05fcac7c41cbe85a0178c1ae667035ed4f095d14f9411230329b487b5b349c367d4cdb30f38a67277c778d4d67f42b8a4ec9b34435e86a313df3f5f30d0273bd8e4aafc5943b17010f363879ee3c94d3fc39f72c27ff53580de411c5b686a16aaaf0d3eacf61552a5380c3d2e97c1de9c0edc0fd02ff6dc2e212ba5c20cf78a4a001a39c589f1e25bc0bb506e999989b6e19c44b16f98d86179da0b9d9f91f5e36f589c8e272618b20ce4361178f5cbe15b14a8a9e8cf260194701a2658016b96160ce9858aa1313d0b1425611a94d2089a55611b4b576033ce44fa6c8767fced849076fa1d7adc48b4fc062b99d3900ed9510521abf3e9f53cbd43059249446c3c2d589130b9ebe79c423d688b94f91b59cc8c1c4faadb1a5cbbb77fbf8fac209bcdb850fee7faf44df5dd197af44a8cae568749e749b3fc32312d9ddff3f01635423f677b8ca291ee28bd4a8741249fbb9d30c5709b17297c4ae18efc0fad0f00db08392100cce618f47c2356166ba18149ad989c7d043189c18f553a89ebe312f0211f2685408fcf36cb08b03d4943328cffd7aa3aa5054240089ac038e304f4ea99388f5074472e99582611866834a951ec5c8dd683f5f0424532f0bbec7690de72f28d9b9888626ed1eb038ac79e4bf7e1b976c6b28d1934ec0f2dbda7616c0c0f12086fcc5619ed9ab59b241474a0244ea76ecd83c0cba45cba45693e6c418ba3878bafec30d0c07b00bd0db7207a12c80623d08839f60f4a390e020a93c1d9b43c3e493bb0a76142cad280ad64ac0dfc1b169878fb7a221862728e897b8bcf5327d77f70006270acba3cd14674541fcd1bb64d655ac373c4af7ae7a324b53e1fe100c51d82986e954f26959687c9d2e67f2295f788673419be50b4fda3748fbfea585dfc2643c74833a5e441847e9ed36a3e79c20fd2bf6f8e38017c503ee7407c079fed559c7c4a940af76e8f8c087cd8f8d97ce2d0fb3ff8f9be6261c3f2f86359a3626d84dcadb16a05b55f1a892285611aa3e91082898f75d873cf16831914bf35a92fd1685cd0acde5de7f1f289cc13e3d346ad212b9343060719932b8ece56014855bd20e32533299ac63ff253d4e74626b1457f2a5990236544c41f370d055a30906ab6c74cf09da6762d96057c600d199e5d9f8c37b5db67c12c3775b1688c6e48d170c4254a0b013e0ab6d8a86fe23282eac0cd1e43859763f83f045e2e8f0ff51c39dcc4ecac6f945f8afbbefc06a43158999f4935466c8ed89c2587a0157e2d26c4473ede6292322e6e11810d44cad0fb63234c6424086739ebcdaac4ceec56b4a25408a15b132b27cb03666960c0877470a136d0d0540354debadaba2156f8ce8ab2711230d85b20bc133374c361be8c6b1092805c7c19dd2089410e7e86727bad81b97bba4fb6da6439b287ade143be60c0bc1d92205afa6d3e7b7a34f87d742eb182f60b9db5ee283eb31afb1b8354dd723f5b9a7f5c2242e8c705d5b32b696e5f2812b5f9509474f48ebe5bd95a76bf4538b4351e736428e9025d0101ddf28d57496ea12e4cf1d603643a6ae3d11048acd2f56f52464bf1fb49a313396fde52fdb8abea8510663a4a2c7a1e72a3298235f41e23ccb66bfaf925f979080c73320bccfb8bfb5435b647b2cbe7fb61facb9cae926a48cc9de11cfe4fed76cbb1bd3632f4893fa480158b556facb408f77b6893188de464046ac00c9566d8ae958a6b8fa0c1b3a66453e13854c85321f389040cd367035a48855aea86695cbca1fc67ee9dab8c80c359472546d884f0a6b8a9309ce13bdb59e639d4e8efb78d3bd9cc27cf746d6eda11aa9f2e0b68782e0faa27dd31db38eb49c238de771b457c38892ed42fc6c1b4d163619f60e671ce65f7cc323b3072f8d68db1a9e5ba61e42a3133c8e41aaf4d8d714e2d74b1dc8f901bf367d4b3b74a9f0042bcd42658c3a596e8a900f61ee10294a625ca1728a94273ac3faf8f261bcf65d3ef7dadded34b246624b82a4579d41fcd6f898388de0e51ee075143e2eb00519811718306cff5d57565c78909c58819360fa8b4611ea61c1171e1558206c1e4e77731a143cf0bc1302c9d1f2beadb1e2b66ea2a45e812a8aef13c9ed5a55a24521249786ef0ee1e074c91dc037a25fec35d6c92451e5aaebb2fc3341062899666ca31968e7c6c9094d72ba9829e0cabbab17324ee416cd852c5405909abfec57375f8c36c5eff2d511ee222a7b4438ed249f348a68b5560339d1ebd4eed9088010b9120b2e9bf8ff2534d166daac503e95828e45c1d5a7c57026ddd122693d749d7224a9adbc0eda0c321574a5c20b17ef5bad6a7c292314b4f413323bcfcd15d4c3f014989bad19d368020dd9b02eb83f5975c68a17612d9f9af8fcc07d6ac1b555e32ab1bd450b02fddfde09c94d26f6de82030cbf2c2c0b5825dca086b48daf0f234e5c4a465fdb071b99808127426142cc1c11a1b5a565945a389855d07e98b1e553acbd8d1c29b346835c440731024d4c6c64990ab4402814beb87d59e75102086217088f1d23cde8d549cb480998436acc40968255722f2c5dc535be8d113ae621ff1bb1a8b13576d09314845ec528d98f0557c5f814898d6f2ecb238b3009f7181ed9cae1d5e15178ab2c78f04c17b88a9ff7ef794558c63370ca7865b91a93b8a60ab259cf2792211ba4f6acce88e73dbc820eed992da8d365d004f35f2e8660701821be38c107c5493b16fca105a15ac217959b39b83793578046e30ee6514d0971ee35d832fc38e96aebef7e1967f9b3553df71e230dbe259160f51cdc9a0c55c60f63b4ca39391d6fa9901b535d20837c6de112023b8c7121b5635c8d8b5ec556292bc7a2b85c8e69a1192bc4c3f705862b416530b8149c63ffed98fc8dff876fa21526450901bafe1b588f2e80d5022a7b99b31b4b0fead3fa32a70b601cb2eaf3b205a9fcc48cf6adcb370a20f88cc016741338aaa98e9d001142ac0ee31f568b8f9268699f64313b22cb4f7c7794f9f55595d863399710c8f68400dc4c4f4d18ae0505ae9524608e1893370e4eb2a5c74cff7729faf308c1e06d1180de3d48b982a38d43b8bfdc17ecd4c7349a329b7e64e7b29853f48551ebbe43c869274804bb2c6529d6966f106a2e1606a5c303eee0a47bfa3aaaccdc1cbd0f3af68b14b19f4189946ded51cc35f191a546d82cd09fd1b7236d8598088a5d663efc226166e76688fe2e60a1de7c108f07332c1ef84ea3e0406c2f3ff8399c9dc6ed681856a48c15459a4732e8221011e5fbdc608ce420fb3c4ea8f87779c2e8dbe4bfb31f72f6e1ec75aa410746e01c1065c13b6545c540bd87cc3527f1726ae10ccab059ee9829c7bb90da6ec3d6b2ca8a2a52915d2af6c932f5243d93d6867740b289e480641120d7a0df971017d5a6e74695c6e2dc515c70d1e0db18d4bbe1958e5b627a6592f5f88bdd124f35628b3825d26ad30c058746748d870a6a9442fdfb7b29520a2626bf89a4257f83df77b9a5dac980ff0b81f450a3340aa7f484a87a949e5ee6c14321e0f1f533bfd759e4ed3f7962a653a811439460ba243e353caa77262979d0a3019e105ec7ed053112351917246045521c8e408bb766310240afe616cc6769c9b7180ee194b0f8cd5046a6895faded2c84187f8fcbefa9e53d88594bef08173593a8b24d62715f54621b56e9c5de54c4a87ca48cda10c13154a9682d40702c104f55890ab034d14ffbdd6017ddc4c2bea3d4a03803930cc1c157e9a959b3dd9898c77efb09f4f20661013ef1b1c7f4a033a004ea2043078e0218cd9e60623f7584a8302eb546653a3ae78e1bf6c8917878d66ce75033caf18bf0891d5f4fecc1a69d6e55fe1641132989dc91e6c095ce93d9a527f34cccab22b82716bebc09740e51ed84ccaef1c122e9f970eae1a94f769f46b342befa5e7424307605205919ea90e1f7a0dbf3a4d28e65f1d3ca04c957129c64e3b6420463c8d4dc6800c830d3bcb963ed535a30610c7a71f7c51687c0f092576598d8931004b44f01063aa77c0c1f33f75ebb6307ea59b1727877e8c104ea33a29cf164b4b5a0205d56907bf6db7f5ee45fcdd79d2f15eeceee2db3e458841ab122a049578e6c31c69b35a350db543d39d75af890427e30914f3d5c540da34dfb6393218fd76203f2c614491764932ec90a18c138b2670258320479bb0d1cd606e345532564ae953ecef89e7796706ba1a4549be570cce8f6c281a0805e570c74df88cc77146790cc9f709767b52329c7dfc27ddc31bf52f1524c3dd8db6f99dc02f08e6300403c7ae1d2246ed46d35f4e60bbe8887531772f4e4c3f953add4f1a6c0d8a3295a300912a36b00ad048981b0f4b6e2248d445d5e2fdffc0006f490f078eff3103d1b22dae8fd4d787369404c812bdc1ae8bb4f12159d87825cf56dbd22b5848559e1412804c2c1f84d5eec48d57cddf3ea3daae01538810f86995be2b22cfa180274e97d3910d05845c8ed00b2e2646d24538c94d6b57ac1142927f25ee54ddd823d2bbf2a0c1e35b4b485c85fe4bf0e6ab2438084cbe38cf3e5892ab8f4b42e0d83ca9996de012fc136086710949bd892e3ff20f4b2fec76c1b26fdbf3e8529ff53fa6f584133fe492df2a685058b2f12302d6690cbe3c23857c4e407d85e47f9e66c2ac231be138298b39710847e9ca338f5c57ced675f4d7a0891842bbb8c2a7b3d534b01093ab88562d684a6242417f3b17db7b0d9dfbc3559a514aaddf78455d741900249d7738a7b12a5395f3055e01c0cf7c1f9218747092f0ff753b03cad2f6a2358a7dde355948485d20f011f93ca34154a93a6e2f1e79a7a4f976d1ad1b84318f49ff4b4ee383342456ff302cb26e58e70a14acd3913f30b6d3124903565e9577133140f09893e952374c3ad13c5b49e15ea1edd8a58ce7fa4ba4d0acb9a5d2f5784bd1bcafddb4a311ffd6cc322ea93eb86f7e19c4432bea86161598280cda6c8e61965b5d53b7789525142a447570aa874a20ac0a04b67f9c222cde5418716484871559d00b0bc1296d25159f20cd1216fe0558c8a5cbc2ca91944431c4fc11e364479fb1480d6a3c4d5d5338832355283efd365433ebef58a3414931815219ffbb4107c8817b8c553648a31facb61863c3233df7d8b83546d6cdfcbc167b30114ba4436ec645606a0266c556225f2d07dccbf2398045a6bf1c45f79410ad0cb4ce7c5841962aa00bb797c60acca554687b80799153bfdb51f781f0df387fc0bc7cdb31e507d40aea310ffc08de8673cf0c0664b2d20c8dc1a1e715d0ff4f052d0d7e0be4a3aa2218f982bb1bfd4510a74a4f95dd744230d2ca617382a0a24627099f39c08d30f68c5d8309c8ba2804ff2240ad35eab9316b104953ef3963ac8c7bc9988cabd4e4b21040a181f1506706f26b9ccaaa4d41e63461849c494283d1e3396ade895aef2abba39dd3f154376fa613064361c94dc0435ad0b374395db17635bd4af95c110189f4425ec67658d59ed9fc4362cf8000f8759679689d6093514a606a812ab55a67300153ba6d37ec51c282072f1fc07c88398878c8ab3ee1e1653ef34893df1a419291362714e09951e83dd9e989f321e002e0efe044d587a665dd031e9cfe219a4efc051df94c1acb29022708c6504d89395e8cb5e14e40166e5a8e09298bee70664605e34fbee761b78e68bd939e2338955fa92085fd53de16cc22b3d8a1be709b38775108b183aa4963b0f0888600e1575f0575c42a835eed62227ce8d6db6a5f876f5a8d7c4c5ff96529a3ecd0c666613c61bdb0b6e230a716c712fc48038d99af22e3f31c110af2a84345058715d92222a5a5feae614196cc0d106de9e5c3902b3e6df150681022d8a6e827bc0cf76138376f79d358fc78a25563163239b24524aad1e595e3466534caedb154a7c8595f650eb4f355ec95d541e7383a68da882265497711c078226d8fec9a30fdd921946b8d2c60927ebf208fc63902f0ca85e72f8415ffbbaa96d4e6fb56988114a42b5a03173c963f8e34f4574830172efc258315e7d7ba92287e32d79250466471434aa322018a31e4c4f157159a34cba1e8d2ad19e82bc3b011161d95a8959da3daa9f46f2efae1129da985560644c77b5c04de98a730cef611b66ea4f8ba222722a00191b0790368a942cf73a21d4cf26f837451c013734555a84b72deaae38744a2b22405026a2d0b677aeacfef2e407a1ea07282a6f6c3e4ebe6abaf342eba52a442e342d38ecbf405cca44ce7cedd0f3af307749cb7e95dbff4c9261457e0d9c686c5f46f5fe8fe384b2d8c17a09991892b86b7494cdadcb72e78afe44e1b862d0bb8dcaa4534eab540da915518566da86e0caec121d056a0f1db1bf3acaddc9041aa768446f97043d01598d26df356c10063e30a9bf6a8a21589408ddef932809bc2cf8e8cf03db5e1c8118223bf02ac0125e0204f4f5a7cb185c8eb8f39637652265ed8be8c4007f78503f5e8ead8b9e9e0e7db02c35ca378086ee076af0492c708db609924a80e59580000a368cf888cdd38d895c0106de2c24daea3f5229936c404d3e30726f18b1caf69836146b1106b6fe428700aff6a4a06276098aeeff7e5416e8fc62b621769b47682fd37d352e72008ad95d13d6826e135d468cef1deb67fc6277909e2da0ba8f0a509a01f8857596facb6c1984ce38abc812e43c710d6d187594cf677ce40368af523822f2742c61c18c62d4819727aca2f5f1295ee4de7052fe7458db5e7a5994c9a41cf3578bd65dd63d4a280495d8221acb89e3ae0a8b315d90360631b3a759007186ea47ab328e592a70e50908553b343543de48d8ba881e0c1c7a681129a51772e6a8ed995a9bf7d60936b3fadfc8872b23dcbca4b57ad260aad8e5563a222e89b22463238f82f65ff317d420b362184b01cb5eef28a6e675145929b819c046bc7172a1a2658270774d7e8d06aa1a2b189f8a0683f9e4ca99a41ad94237b9bc7850ab29d5d64d89c9085ccd889294ec3b1d451b505a21b556ed946e4929d39cdbbe895ea2bd8dd38aae85b3c3fef9cea2ad2a2a8b729547168127c2b3b42a0c895044271607d110f4fa4e7ff52b79b206db45289e2bd21cb9204faedaa0e207175d165cf4a2441011a081180b78d1f2decc997e70144a602eff2c1bd0b6ad0135a30d55ada2b08e286800ac096c9d9838083fa2b41c0361a4ac0e069a9e46e4594a4bfae27acf7291afb32e40089fea1eadd748f817b40ad6dda229c3ec78d0696f780fda7dfb81ad7c9b1ce4683660a7db797eea7a00a1874aeef1a47c4e3f6bb74814aeb95c144815fb1edb767c5d484e4b50f3af23715868c2cb3bed0317cc27ca7143c3065e428d06933b4409fe8394f7344314f5c566aa8b55dc6823a4812d03bca708537b8bc9392ee0861cacfb8585fed01a595f619c70c080381c30034f327f75141c597ad7bd2410e2b760fa582ae820b1336ceebaf7958a57151718d57922d5df4b9264db174aaba4af2d6716449e83023e08730a66bb2e60faa7bd3c185b0ac66edd19494ae508ce3add8a944431bee1d6804f12e431b27f1725b45498fe7d834a5b47ce295e3053a1e798385799b6646ad7be246c433024b13722b7b0ffe2d1819ac408734d8e4bc780f6b0931298693363c99e68cfdad196cb56e21c4d90e0207f19701b24422d9a35742086c71d83f76c55ac016d14983a0d66c0f38b55f7e0eb3146b36c0e244396dae4bbc426b42e4052dd625d10691c1df3d645a01347330cea9da0ae47cd3d2ec79b6ef016ac1250665c0bc024f6270015a16ddb317b0ce4efabdac72332fa20c5ee1cbdb234834ff63e7f291cd75b0047b0b3d21849f1508e823e1cc36a5a771beff6f41a048affa0b1292b13308c98686b105f33ef4467a547e6b40c5e91f1e19650e9c4095373b6075118e5187494ad8cb0aa8b652578618a2cd15172314183d39c7ea3693accf65d60cd485750bbe2390b2a41bd7935f219781bb1ae312e332dc5a9551770ef3da9cc18fea40262e75c615c81478091d3d230fa78c60878c65edf35be60e32097724629e75b63fcc586a9a31c3e1d7ae733e6af452c668d1984a647add56ce19f8ceafea522f38d182dadd41c2418a82198dd36bb39c955e1df1edd34c128e6dd64482d42fedc86f092677c9a496268f6bf083f2606d04f95fabc2a9fadd5f8d1373fb75f0b5c853f23187254439c1af7f65826853a1f708a2cde091595545b5c0ecd29366ccaf67122c706ed6815d6f7204b3499c5a7fae7f12a208d46ccffeed6b839ada70682f419b7041890326122772018325dfe81ad88327eef05415d8d9aee5c79d6f072341335f192407e8aa28b2f07f7df247a6ea55578e682059b21dfc10ff9a32a656666da68660841d078563b0991af95a1ac43315d7058e306a2a30b5b453d13aeb96501356cef3b6961daf6480ccda6086abc98fa214efb568a6fa9908d7d100cd8549552194665d19688794a020069e9d1a1af2773dc8b616d7f6dcb23d3e9e16398e629d8e44408efed9ae18b72806458a61a4ca1a79b517cc676353d67faaa99f8e13a2697ea8bc4873f555eff101f48292b15611207b55ed6cf9882001fb8f45b0fc4da901e9a50241f860ca87047f8c41296b7a6ab7be206841c60a8a8d704985ec23be7bb812c33d65a894f650252498aa6b349d1d6fefeab661631ca5ff6819a32e50ab4ff81e08c63ff59876096c40423fe676dd7ea018c42658f055b0e7e131ee4a99aa05d02737505e9ac5583c7be063693744cb41bcb903ed4c9a5202a9761481b0101d0d5731e2c4131a6686105241057b44d8207ba1617c1ed41fa1ec5b4c357e9d7aa6767e0300b63466277fce2aa299aab550b32cb3892056717c000b3397eef1b2f4d7a655a7dfa1267a34b4f5c67386ddd613872c4632119aa4b0e0bfe4a949b58ce38d7b7d5f8f9574ab07175da1df8287b72286178dae578145304c210167bcbd64aafa6d9d4f01d6580feaa77dd66721d408bed1f770b04b560614ead1ec5accec125c78e1dbc1cc264e6bbc4f2b2cd05d9ab92ae8df35b53f565018f05bff7cd8bfd44e3e564b37f5dbe4b9d880ff2a2af8fdc8e2ab9e31fdd24a7b91672fd251a7d615340114dbcd5d213462147d425ba1d45bed0baa531570fd63ccb1526a84dd93ef37b28a76bdc0a55a1b40837337708dd7aa67101b38009623685a2ea30ebe65638415024537b8f6411354cb774a6ddc152d4f9bf08760772d6f82436594ffde49ddd020b381d441deaae7b340512f62cc14f17273e78cd756cc6deec2a956bfd10685d2bcb7b867e6684018a2abf82841a1eb052fcc4572df46dd474b5af72020ec6ed003a251f42eea7ed09cbda5f6e03de3847d108630fbfcd523dbe254cf60024c20bdd621f9ef752309c0c2937bd8471fbeb31cc128fdefc9a5e123158e2932dde031a7d8b3269836ea02d4f09d0cabbc752af5260ca8317d453d8c9bb3789db69a34e1f070ac4263ee9a53553c44696bd91fb595296197c2c80e8f63c1ad24b34374adccae4f79bee962e46099b14606d7ea98db23fc0f6d19b0ecd6d0a622936cf9ebbdc434b2f66ace6c8737a1af15a10ddd9dbca46904bac021a6106706cd0416e3f1203c1fa40e3195fa4da198c345f23d56d031807defb50ecc96b255cd25c0a8ff1086211eb33f1cf90c2c3ba6bfbd90e855c10d0242ecfd509cb49f971bcb8a00c28d2c7bd1f988e2ce9ebb74b4b355360b5008131a6cbbe12ff019ee30b4d5a5ee0427041e596555ea7704b86199819a627414ef0507f92454424853f5afab87042d735ac15c276feb9d38514e3d736128004ada955ca067a2eced1aa8b990e952f01ee88f03305f0826cbd1cfc40cc8d6d25dcb2bf4f980fd2a05b7132c7e46c9209911d8fa4a183e32c4e944a7146a29b7cc8241d4a8c13f326451210bb28bdb83304ada288ef0db846365e3dc2bf1739c4e993234fe6b21eab5290f0da895fa7350b1d327bbb67be456c025afefb3dffac3d135ffab55feab09b46710c5c9348468cd3b93224815de79cfff281ef062f045540bb2a3c381525da0fdf48303318357ff16cb8106945027421f90f293d4066a05f9ba1c9625f1a928c052dceea3a440f4299fe26018a1d8143e35da868e572b1000548bb72c2b148a5e60c9a34724041350e9be2c146bfa15eb0508e9c6b3e940c7a858333eaaf4ad0088d1fb148abe36055f0fd89a2b2005f938a3d2b70d775a35057db6462bf74d491e46bf1de7ce33a9790572af0f148caeeb841c48678a1590d36fe0ea40d129c6003e5f345e2cfd0fbb927b54ebe4c0fa70b846c760ac90faf87f0c3f2620c9484863595e3e4c434c54fa49ea6f0fabb62995223943b9f66acffc092e430c07be273f10503024c6299c409a4511cc07861441938a69e02f11dcd08aca566e9e351ad2d1e0f4694b63a8b8dfd0006762ce141853900ddb1aee2975f2d400074fedb4625f023dd756442ac088a1d2895e004d12082a6dc6789690435887ebceb74da86b198cf0a6f019b7389cca9616cb8883662e4564561384f362c1f3792835c3c38b3aa35a9f7ab5eed510e2f06e561d3b937dcea4b5a85c2b0373289d742676aa32a421301a1c80643e68865c02c2bb0013b6b19d914c1a17a2c91a1a916ffdf7ece1096531e7fc83ed4bf20e34b109b3458239b173063edcc7d61119208093f5ed8125d1bb8642a12f0ba1914b783a8b25012d434171b03eacd1c527421b01d9599438654961d119d211873c93293f04683e53224198a045cf287203b4eb18de4690ff8faef85d22ea54b49553749182023e4f3f7d30490a0ab19f1b003233996d243d5808a4672c3de8d3d5f35c877635ada3d23f5c2d4428ede9c9b8111f2366d4608c125e4baa7958bec4de8d7cf206a4f27651b23eecf9b9e62d8b3624cd74a2246c9527f12da85fadb2b08cf44aa78e15ba2524563258bfede329d3eb26dbc8564e9625b99306e3203eb583ef53792a45db09d6bdff660c2beb03338d7118aa063c03fa046d99fdb686ab3b21f01a2dfee3aab8245a3f9cb9336466ff176ed2b60f26d4b8ec6ea8285a0665be0f20a4db33305edb9fc22d6a78b56b0151deb719e42524dd819f7b332a74382ad63bc6cab69d260125cd9b8a426383768ecd88d180fb9210a921e17dfc93908e0db90d395fd04d870ed932a297c3e3b7a4188bc43e0419558e41f85797fbda6bb77e39b45097fd0fc16968ef8ae522e1a7264dac444a2bd0f4d4ec22db106d828344d37d1565a1fad795a36087267b390d3b7753465666e7eb91ec7afaf048682e17fd89d25c712d518f8d43e84cef34cf632629fa2cef7bf9a43c8fcce4bb631607b67215ed2f59c6e9ab305dd8cf58a980bc23d4b8a0022f1025a086cb8d9222332139f24b40a79a0df278d70e38720a1c5fd8c0e2fe204b6ba7b9c88c34b4d163763b439ed7a404ca1d09565e3fbde52010e8852d11f0eb7d47812d8c9f80c884aa240103eea78213a849edb1a4bed4d3194b929e9ea7011c4791776d7bad1b4a16375e1f4360e0cd5243d60d6a0d2a7c5abb38aaea0a4919d18135733a3ceea1dba37349d09d706f548929d34012f322d56fdf078d4029769dd71448c1dc43564051dfb94f52a843247bd320bded956caf554dfd85fdc991989d12a53bc1eb81468da0e5a07e089b8b09c8cf212415ec292898f7275acc2ccbb219047178557048d890ba85362df2aeee83e74de3b9b2f54ae8bef732365743fd4f5e150e5729446501d5c84538dac530d60c34fbf36b03f8465a2bfc1609c251465fead4ae71a0628c4bf401805efca8c32262c9b0c851b3a0d39bd197610857403b4bd7b6af10e43d586716e70487cabddee304ea3e06ec5f15dc544ce978d55202c563aff6027ad16ac1660856dea9a91b079e18b3c1def01556243b89f38e9aa61e67d39375463e6d23858e7c31e73ef2678272c6d8d029d4522fd1197916058cd41e73668236b3e0abe2300f19d2cc7489056b57c45894e6aa2432be00690100eeb24b9f047db98191e67138f83b635f8bedc2c5b2794c571cc65d6c4d20c46064dfd29595804aa7bb2041469aacc34baa4b1e240b203123d11b41d4fdcf726fff5e88f807b67e88939f11104cd507bb3dbd0e335ea1fb6c206173afc214c03c88f5db525295f8558742501ea252ff895fc5d12db02809d0322f47a868fdedb39449537bdcd6089a835bf48e384c388564c7b325e6b0c20329b3d361340e18aa12c56bbeadd3c5f1c243c9cb3df5778a22a6c9ab55189860a535c085790c6ce5a9c9a7af05b5f802bd04e71c016250c3c350c3fd0078fe3157c03495cbbc65cfdc62b6bac8b35deb2f0cad67d2a4d604a4d55b67e2f0dedfd7fb30980ae7b185067d1fd04ca80ad38fe066745e09151f97a31b418d1c377c4682e6e4926b4902d9c74c0d4d4c98a3f47a89ef86c89f8cac2e259e79431333023568220ad3645cbf8b470a6af254a00125669d66e718811c7ac785e1d8ad8a9928fa43bcd4719095ef7cc26c860d88f0b034793e8d776b775c930f1c84a4f279cc1d7263c0c94ec4c909098c546e131df07e36870dfbe73dfe5b3518a57568c0a2991cd56cc742dd213ade0bf4caf2b12419cf71abb861bb5c4a9fa915b0cc0e7a25cb340396bb4d2cd60d1dc1f3d54ee46cdd13cccc18a03db72c33311ca03cf9769169bfe27537355fc8db6c379be26d1522d439f796669996262a508bf601be8e20e7a74f129a603f5545189b0164e4563f5bcf97831f93122db697506dba799107d69b21719a2a3460110c468fce7930839294b3d7268fe63de89128243e35faa6e78c73d4c17f0a29c1c137f2f39cd5eeb0cb76498532d2787f746112d55f7019bd06c66602b18403534b32bab2a7600881d25026e1cf711eeda544c78f962e39cc3e86c1366fc6c2ce5d887105e1c92eca6d5ecc42296dc97c332fb0ec7145463a2183dd8654e875ca4ffbca284e0953c0870e9d3072c3e7a897403e8792646be44f1534aa77ade41eb96e9d5d8dac97628255b869335223dc46ae507021a141ac1e323fda5234f3a9a9313b501fda6e607990846aea34e69e5202481b88420833aeb35fd58f3f43bfc9564190d59c05389d90e4530960b6c83ec0ba54df1cc62b784c6424e946672e3c12d7f5dc6673ebcbc90da85d8d74c9076e4dcf0fd7e1c5906b15405c799c4e00702a6541ada2414ce1dfca6ac0a682c7209744ad60744d5d3270fabe412051310a9ff89f9a133b004d9d116404a195b2d06cc541a23a4bfbd8aa93e2c593cc28c66d959d4b94380bd09899f944d16ece81ef5a708dcd290e6c4db7148141e507684aabf4f12f792dd639d1571c1f4eab50b6b277a2892779df1a9e30fbedbce0bdfd2f13694d0751a452d8146d43fa6be177ecb7ea7f0efb338b8789fde96bf050983ecce49976e42264b3710336ff85833549c253fa58e1e82110dad4664b9ce5f2fe0fbcba28fe7b6128757d298154c81174d19b29a2c1edc4468e5e25b56f8a6340ec41840e2bc2491387cfb18d889beadb9c40cd0c3a0e8f29e580e7e7086b57052fe639519053f2017c5c3ff4c51677d9ed8f209a639511b11dc7ba4ce75ccabb0f0a33e30371947704418898d88469bb1d462a898466513a41592b84d66244ca425162bf475dc06fe5a64de6074674bd62256b82709aea1080b82f2b85901d1762c9d2eb0fdbbecbe43a6048643b1f0ed65dc511e33d2b7d67562bf32dd7c991530a44b8a03f85993ebd4ac1a32c98e64fe30784dcf078332df842cb558bd677619250dd76efcc012ed493ac303056e655d027aa40f00718ea0183e64c1001493518f31cce6a7c76b90113ca62f5187197219fa0748ebd125644410666ce70d0ae0221af3db1110d217e3a9bec92a998bb511641d4a3299bdacdc9751184a7f67ff014739171ecd315f0db80100d92ab08b6224e0efd08d2b508e385621b859f0ee0cbf44ae2630dbbecd260829b8165ada8a120d0b5a7503cd26d29e3930e00cf2264a1f24bb7038535c001abee20c87b2b49a5b201eb8a2a5a6f297161b8555de6516297b4c3d66da473f544662289cf1551152268f912c1c9c5c2ee419e15f83eac8e526cdf3f3b8cf12b0a2d1a99d1091e33ee5b7928bdcb35d7db1c4a3714c222202eec32494a2151b96ebad066a0e18bd1137bcfb157d5a42b108ec3bd88cbe0bac4772a4163bc633fa35146ea996d2a107ca3c56febb4d1fc8b326b7ce081716cb0125fad15b5eddd8ee09bc17bc5b1e8d4acbab5501984ccd6c2e29f5ffce5e15c5b5f927728ff9927a04dd6d38f1382bf2f4a2dd9093389b5fbae5501cd12bb4a8d2caf18a625a19ab872091052651eec5fdcf2c1ef675cdd29ecbcefc4232e1dbc77719d826c391d2e4e238bcc2d15d6fd8fde830ade9c82ecfc242042c3948d844f467cc25f26b35ef27bf098c716514fd2e9f9a3ce46743065a11ae3c66fab00d4b452a8850f204f8d9f654eca932822a66b35a23d676a70d9b78685f56d11f6ae62911c217a1b39bb03835d030c2dc675cebb43b9d82f7c8542102ea05e9935acfa19065ea00f2a35a3096f0771c647a20cb14b92d7475bcd670cb4fa5f7cfddfedb25c9d4ad2537376cca37cc6506d2aa28b15c8b79a06e6bf6c6021c0f2793749618184c68b2abc63f467518a956e5116ea452873373dc2c53141bbd4c044e2b0403584b2a7aa2330401262ef25c20637dc9ba32d2c66b840d392a8a55b7c34719bb2a52d13ebf8ffb9362253734e148250b518865aa76f5526c2f635f52c5df8f922140cec21bc75ec9a1a638b10ea109a98319d388472cdea01e9e09a0ef30a7681ff9e76174d5eee00947a034c859eacaf2611ca57f7d1715ef02a5d79f8546b8895e3e2537446ed832ac999ac240f2d7b002c4d91741d0b72d8628eec47c8dc8116a22d76b0a9aa9fa9e61a0a4d850d7921885dabe0e0d71a84cfa9b8030e280a404fa3ad84cc1e045ee1b558b27f6ebff87025885b44703b77e740f568f4934ef884ce59c3ef3801715b1ee243b3a30f800951dd1b30582c91cf22ee59d7f849575f3f8128f49980fe5c6ca03f177cbd0faf2d1e6172cf93504321b93b7f5c50aa3c157bd8119d1b64fa6a25115e4dc9400e38346b218aaf7df05be2898b5d1b01c42487a1c0a84020d14f5dd71df006ba046b2a07f2515f0286bdba40ca6563751e4d32b458c6ba3af6320014a01376a1cd078a224ca8f8e6a51fc256379a2ae89a4d902a169076f5b728ee11d3ff3eac96e606737e003af8376d3a1348384c24591f456859ad235f869e285b032edcac0a93036ce8b0e17f23863591d52767b59d31a91daa205d605922147fddbf01ae711609aa1058369914ee66efbb8867a23500c36713bdaf0ae8482a5c2c779f75406b98f6d257cb93796df3b17576dcbe8c48111730c00f75529a22a2c4427f39c478f501a52b1a8e0c7cb664dfd080202d3e86172a178f351b92612c9b1dade46eb16555a807bec8e07466d004c254b6044dfd4aeb888cc00242e068af9dbae20dc6ea015cb3031a0c4faa5420ca703a1d0f066d54822641171946b47507ad029e8549a1779794812c50852ca99acb720ead9779568bf57d1969db560102c1ba6c6778afbb9377a3a6b94796bfdbd16f534c23af7d662ca631369bec2da59432d10b950a260a67e268f579abd13667238f94324a82ded4ecc081c6250b180554a07d9912c7ce9a160de07213c3c40c15356dc8e4c061d482511bcbe5a36d84a96266d1239ca1bf336f80dc5961b492864593734c1824670e23725ec8b933e60b961d179035287e5c619b93858c8e0be3436d8d991b993232753d277b2e1f4489d462c7eef48d0f81cc193a4ba69cd181c366dc29264c0ba02653f4c46d41e943e74cd52fd9884031e5a8e34e8d3a6d3a0c983c20c8f384edcf9d307aaeec0de646482d851d2963415274b903060c99ded740a608731664859b1c3960d28476b977e74967858d3f7ce00411e285035ef0b429a2a3870a2970a51130b32b695174d47003223423248b8fb0e3169af30b98261bb820b3e7c899b3326f6c987480094294f315a73e72e8a009a991c46b878189a156a00fdd16252fb0e6dc947149f1e2c5103a491a6f7780fa9f1542d8e8ec1892e64a9913230f2f5668b0b945d2e0de8c20e264c699990933616b88c4f479d325c5598d17d98b172408a0fd109312034e720616377e946cb5f08af1d6a30b1c16f4ce0c2371a80439b224cc4f804f1c254fae80fdb972751cb824683ffa68c12386c4051ca413a61ae017da952326b214d98c7181ebe12b6185860f2b57c6885129b16091e265a2cfdb9c3aa71b1c0a23117169d0bcd85263cccec50257050f5814b02957ce2d5f9003d00a019136b917466a941f941d19a10f9614639c531bbfb829594471c2a58a9f2e2562ac8cd7b831be53250f1f0f215c68c489ed68936cfb42a65742851cb12a78ea548ce0f38dd94fe5d5d8110f0d167d6c40394fb62f6b74c00811c10b6c479b3c3605cd12442b1b8373e44e193579ad0950928a392776a8a0e2048d39e7c879f3171e4f3152746dd941064b912cade54b0b366408b2b68ad869c36546af38c00834bac6ca68e99344ed8b8920ab3178c6e008b91167c71d93b6ea9dca73fe482983c1a298e6069767dec010c9216913a6088e224729695cd8d1c60f3f615b84acb870da98c83509b22699cc02828d588f1368289aecd1f101b7b6ba275933fef031731343058d2a7dc878dd13cb1b96a122712edad2bcf0c0b5c84031690b82b6bedb6dec1b89c58f65aab7254651bb3c965d514edcb053745b63002d6865c0a29c719171654b99982e30b51e492278bc2c515387434a1d3c7e8e6f47be889b58113131b5262bce9c801b4a6a44c92ac2f0d2870b08f0a0f1f2c787193569e69508c01102074e599b0c3c416251cce4bc65ed5961a508122216173b3a4c10f9020357e54d849e05548ce122244e93b433baf266b1371526501a13695b4e64d1a205803a798e7ac04cf8c8a272d3fc89c3626dcf0d185f8e5c294e92106961e7c8b14c9a973b441f5eecf831c2973e2c44c045bcd009456d736f0ddcc94a63e30c189b277beb7dc48b170ec2dc58e375e5448b1545f6856bd3426b09111866c6e4285e8c4745ce529881e51102a3d7a2ef5e1ac111a7656e04639f2c53bc8cf9ba077ae6a4e1a14336f10196b66affddc965ae1730a0173ae4f068b105ec461c1b7148f14b0996231e3374a4906950d303ce8f1b376436a68c5cce8e56a2dcf98ae225c70e8325696d578824cdc2f6ce6135d6b8a801e3ed09dd69f4c2c5c34093b4197bb0b8e499c2be365964689d9961a37342f1b26217813d7accbc49c216e48d9a9e7befedf3c571114f649da9ed506bab01b7697831718659c2b676878e4e97277b977befbd77f9e7ce4f505ecc520706ac5029feb0012589579e33016b46306df6801dcf7a6418730c630676747b73f7f4482142972e5374903d71cb20059b1e4474d0b0c18664136b74e9a1c6426b499732275dea5089bdbd986326e4459cd007073245d4e2d0a859b1e54473737eb071078e971b347386e023565b8ada582e1cc35cc4c9012519e79e7539f34a82e78b2e0cd2471d76efbd371b11a58b4c15a4e8e27173b163abc7091b74c6ce265dc2ca0b770647943a4edc8cd129cbb20cc012a310375d61c60c29cbb32ccb3213e965a9d4cbf2875aaac40f3334803cd13337025b96393f9af7a7bebcfb7dee76bbfd278a1d368b74c132a7b059c46c4a571694ae1f778371618394abdc989b526ceb3aa326888c4f1d8d21658aa4d5ad38999c5951c442c48893166390a83f3af54ee9342ba420eb9898d97364ec9ac105f9a48800c6e46c4e51ac82595a762dcce5b23b95bb1f39f3b8652746069f3051b4ba80bd403291f77091325486658db9a121c7c9123ff74f133b695486d040c1b664b780a3e38b9626264608a2828b8e2224cba58f16b03d47b8214a6a98178d961c687ce4b161460a05f2ef8d02197929b871222ceecc9326713a49df7bcf98d68f3b7de8c8b68890b637ed67e7cee1eb564742df7befbdcf32c80cda05019d69bad37def9a382e54d83921054ddc59e6363774f3f4908b92f6c28e9c1686aff483aa9b90b0ce683a373140267611a5ce45dc1958925387b96d6991824d0f9935b43626ecde7bef175e0bf93fb379dfa9b2cc453bb272dd824ce1f28a1a1c2cf6d829cad8a3857708dc6ca46249312d59929405413285b5fca53127038f092878e430b91acbadabb420cc1e2763fcc88d90dc4776e8f4093715bdfdc3a85dee3628cec28870a933f346242285c79126469a90c9d248f6f088347c8c790286438617d60f4b3ae493623a239d6ed959388f4026286a9b498c3ff88cfd481e79501dd9f2762ec1e146e52d86153d7419cb85b32b4cd8c0655959711ad96265c84452c56d091b154392e585a3da72c6bbf28489645a477a883973c3069b4b452644c40d11b464c57901466b579022bd7d17cff24949bae744991d1e67926367111f40c4194aced4d48001e5cb87dabd59b6e828d58c372501e6c69b23689a80993112e5cf1e2349196ee67211225b5ca40a10b31397e624cdcf0a06c4291a91a0583b636288a2f84f6954238eb9c1114607c647580eb23a387ccca1393202d7102d1e56cc7abccdc833262cc91f227dd0ce8ca17811823bb645ebd440999832675b38dedab07befbd4b354c3cee958e356b51e478701161939d42904e69c0c0a814b1ce98f8f6ffe0d236bde5e724518bcc092f3073538c3cd15c580b4ec5723aa0681de19c357992e59e23ec36408b8122c81c96156a2bd2364dadb2d672ba081ad69c28c8b83a3b6667102c421dd84326075918dc93b3320b76801d371d76a2bc5133970139383dc25c8c5d99bb9a4e73693bbb000e3745e4b4c4b0e0215366ca8e2f3ad09cd4b166c6e263c3d69c386246c588442c89d96f9bac217bee88e9c2a449bedb579a9d655eb898e167ed4d7206db3e890121a370274c8d0a3811d6c8951b6f8d45b854b472c0a913e38b6c4d3693410b911d31a47889f145ccd053ef1bc91a9b9fddfee1bdb7d5f0748d5359e3281feffd1fe4aed78cfc0072c8a3e48a63de01a4d05a8fd070bab161c3cd860d1b366c805df916678cec184b9d468f3f6365a9a4c7fa99ee14d0e31f5618c09d0a7afc06f870a7861e7f0738c58fcbee944f7d2c410ad3619ce452e52cbce24ae136dc16a3e3b66ca3e3c739301eebf8710c2ca3e30701630c60391d3f081c47009ca53f610a1d7f04adf049375d2a03e00bf9712b3c4fe059fca47bef05629577a759ee7a18985d824a97b3da5cccc51659c51b79458c361b6dea1aaead2e32b5948bc7f356d78a21aeadae15614834a8343f8c7803746ee5ae6c004c9557986b9bc37ace397afe166a450b37d2bc557493e6e2250be6d4caf91f040484fbeecbfde679feed101474aebb5ceabd77690671207e0acdcfa529ccbd2c4d0984ca72af42daaccc1288079b98a016597a7b26613b0b4292a2fdaeb19189d9bd196474faf4995ba627a6ae012a0f8db8e87919f20183e706278405860cf42dd9c362e245d0162ede9d16405ce0d038679b59909ae2ae0b101719a697aff3e97c32a37cd2f004a5c1cdeb7c1a0bc13ed393977669339f9e4e1cfa49c31394863732dd74cfb52b2c627029ee81b1e5e886cbcb11016c624f501aaa80a83e50a443fdae31496231a13bc244ce2df5f5bbc644ed4912a9dfb533227df7bbf664cc0c8aea5b966559966559965a6bad4bd3346f5c59963bb3cadc69d06f9625d4debebd77ce39e74bb7f7a6c0bd77e79c31c6186badf7d69af79b7326d1b38989d430ce7a97e6ee040a2a3a4f11412854dd75809455950ac5d4b3b9a61e863afec212b1334d2ba3b1fc0a2710cfa5f10bc559efd2347b1df46e87b3ee14bec2aa9cb14dfd27750057ca4a3765a9c7e606144093e21f966fa785797116daad774e2f61742de25e2457ce725fafef6fabfdc8225aae177d0b52ac7747bba2ddce34cda223bd43f18e9718689ed9db3d8f97fba8c8687fe760a7da342a3ab2d23b1e90fc2790e2b3f9d992630ae426f345e4a199969e8fdf3c32459cbc2dff3cfaf63cdb2bb7418e3a57f369833c347fc745700a5c115a0ab3bd0244a0972fe2cddfc0347b1d76df1b80067968f20f7928228b02394ae8cd1f91a37a6fe2ac1cb545dc26f3cf27a37535875ad548afedd1df237e1ebd79b49e79e85bdbb34d37277acd831e7be875e03d51fbe5974fc48305487f7ffa7b0ff1f634779c0bb90fe5cf94875a63dcf19fe7699a3b4799fbaec1fd668a532bbb9cb3fabb4ca1df3539586ad4639533fb01da99e58ea0dfb5386569ea24e8772d4e988eb2598b03e642bf6b7280aca5f103d7cf8e0e01f50ca86d47a3199958c65c1a04b583fd214bab6a475899355cb0e8b4b0e6aaa54197247133749461c2c696ab08dd94db2bd7adf2f9a7b7433fbdbdc63ebdbd707c7a7b917bfaa9a79f79fa9994d1d6454d859f2d42583576f6e04003e54e991d368ec71cdb9020476aa8b17b4d3b4353a48bc88f22db903842deaa3ce1aa1b637f9c8833a3216646094be64647eb840d316dac71cb8cec8a9d2bc6196c8b8f279e3b64fa2063f0513bf182cd70b2d0f14873737285cdaf069173d6c6a3881e36b775c123c348450b071356277fc8c952f7c2ab8ccd64726c99c0026ba302069b1f042d9501186f66e27e20c183c62e8df183c41ad2c54c8b251e7182a40b868bae1f746c7e6cd452c41827d818a9f1c4c79f38160ee3a0ca7d7a9e52e3ca5892af2343cab0398e0089a1e518448f1036bf3aa726cb4d73e1f08b9e91a848be7861e7eb0deb013e7892e4786b01a7caed57871a9564d5910c2ef334bf56e4e4cc344f73bc820c56dbe6699e55687199b199ff1b5bc11536e68ea779b682034671c3165692cd5c9886c574d8e6dad8cc2f7bef60992184cd3ca9067bc7d85121c6663e418dbdca689c0ca1c39640e38c6087d59ff9d50435b684111cabd3aef9ee079f2872e78f2316326ce64f652c3ac4cb3c821cace657984c0710176c896c228d4904aec5912df5d80982c5a25b67dcbb4547422dd164f1e30e199bf9a532842d91b1c6f1263208e27ffd75bd0ae2ff553f91551202dfb7aa6ff47ba3a527b2fc89ec8427527822dbf444768227b2169ec852f0ba09bfef282928e18fd62088a3477aa4f50ae98f9ec8fa9ec8fe13d9f5892cd31359099ec80e9fc83a3d91ad709f02aea2a5162af027ac7402270a7ad2263e8021ff609652e01a48c0452449db0bb7816ec2cfc43b5092b697aee39fc0415839c64292b637898b98ab2c5de2d88be3af2529061f69bb93acefdbb363313c9687f8f1ff12591a36ee648ecaf9f7f7cd07abf765d736c3f210631cdc747988df68393da7e97cbff4207cbfb45e0dd17fe5f3fdd22fad57dbb7f9875faf30eb7b34efa469eea4699ae6d09039640e9926119199979e0f7d7e3ef43ff44b3b99a3ccbf9b4f96e2bf2ea1ffe8afbcc4e27c27cd2f2df5424b42e65791697eafd72bcbb2dcc9bd4b336807ed24163235ddf9a995f6f1cb9aed96ebf885b807bbb73b596e9d3ce572ed36eb1acee9449ac972d479a7e3cf5eb94c6bac732ef79a98316a4bd228717cd44df893386ed34df87f3ad2161f3b9c6ec21fe458ce061d468a90b698ae2775137e249eb14ea43f9e8b3c1f8949db5ce457be4f9e3e3e04a8fc5dc97bbc1eaf27ecb9f5f57cf24a0e047dd0ef64e905c4e5e6b6658e8e4b31336abd2dc73ad665cfa8e47de666ce652fe79c332f5f674d02f7cc270ff16bdc9325d697d0b73b598e7909097d29b6935a2a48aec4caca52591ac9c64ec75f6ee5282e2d95d533b6e9ea3847978e79c75f86e5a8bbc626ade32fc9b41466f1a75c0159707978fb105780891c5f516d3eed749cb970f378f944b99906b49ac7d534e621fea09fb4d5721aa97532479d751dbfe673a7f0d56ff4b9cd72ce3d332db593a7695626cd76d244f63ba18490589499c4b0b080885acdd5734e0e3b5ec09d2a1f6badf1961ca4b1e0a6fc6e58617afe333d6b3a1a418ff90c311e62ac3263e164f9b9e7afa0a0c76e584a01384c983367dab4e92dc6ca41fdec05ad1e74dfd2f1972511ef51203d1e84e6f3355616cb5ff9aba7ea267cd105dc29ddcb070eb728a96a9a96c9b5bd6ebdfc04dc29dea3497d9e69aa5555a99bdf2a25bf8256ad93ab462681bed548bce54e057dfe5b7e98f34cdaa6977f953a50f93901772a27e05a28d72009dc5e379e6caf5b6f73d283be60c26cac15787766c0c1eaab5b45091d0fb6440f481a7be60cfd39fc798bc396286ba861776930b2fc614ba4706ed8dd7a73865643c7e74a64776b30c4ee817e770643049dbb075a4f7ee60ca5ee7530bf670022de6569b90af310e70caddaf1a99baea6c65401c29628ffb0bb27b24972f97a02e95d6382d6f39f6b725e3dffc6ff548e41a76e578530619a4bd52ba1af3046164489c261cb35dd73e9de3b831c1038b6e4281c36d7484bda407ad7ca94e1bbf7de5cbbbc2557bf79f8e7cdf2efbe3783fd1c5cbdde37f7bdf8eefe815331e36b060e9ab7b5383c6cb840c98154e3b243043823e81329670c172d7884e0a862864c1f0178c9a166842772c8eaf2ee496673cec6a04c414752471c1850cac4dd3863aabc9569c32a42e3b805c96fce9dda3de8ae19a3640a6f2c6d0e907302458b24264e1c39e18840d416a1087133262dc61a0619507ff9b4654c35a68650d4ce4624b3214c8e679aaca1311903e39c5263e349b20bce5816d4538521139edcb38ed2564113156cb0f0e031f146974d88469c6409d3446c8b5b59e6dbcb55b877ce755af253066ba8d84972fd2172c2016de0640109a3960279cf376ec6b0b8e04b8a1a2d2f3fd07091f1c6c78dd915214bb67e70f2d39e3849fe207bc0e072b689bbd3419c570b293bdc1457d061b3913557f443b7a28caf5926ce8ad19a33d300a14646640b8e2a648a9c6cca6ad40d897b92a7c59d176ae27a1805a9a9990186e58c8a2363f69c7471284e0a18e1e81882440b1523194bee800d4711ca0b2349b2d856bde79a0b27a64ebae409968c316bd6c4e49c0570c3479f3c5fd6583039d588315374c9c0d8d1444ff2861f1854415af9bc38d2b2d4f96f8931d6eaeaf9f19a98b05e6abcfbbb23767d579dcfdf712b6d06fd59a2df0fe71a2440d0df0ffa7bb61b74902f2fafed799e98b723d047879ec785fef2201e2440f977e814babf6f1b02eea6f91ceccf7f3ff316e3ef5dfcbc6cf2f66c392040fe5288f3dee427ee5da0dea9796b3b62bd1d3640c4bdec75305ff732c8ff3b03fc39efdf25361128efdea069be367bef1d021b3077e2decc42f086c6038a4cee7cd13366079c338db9437b6de02c8b4a914b45961e1762e061d13564ae2c8e2e0303830f275e4efcc0c1448e91aa16509e88d17186850d093e3bbe72b0a013c735278112b03845a40439d307ec66e1e28285160d28715960d46921829799923068da9248a0cb8b97a21a8ca48c6b278d17133ce2b00901da991f4884eab6c088b94991278d59124a8c1a2d62c4f93acd9849f831cd96334b7888d1413136f70486989b3353736a6cd5a1d193e3c7290742903f6c8688cdc1e86196350982c70a181230278c1f8e5c5d5b6f5ea868d360b299cc838aecfcd3a3850d185702999f1ac4a8fdaed1b56143f1850d7ade7bff9eb83437188a629cdefb4355dd99fccfcffa8d7b4acef929e3ac772f4d9db1794b21541337ce5450f4485f7df96f6df7b7f9efee9bb76bdf8feef2dae2fc0745936aa4493552fc17e39c73ce39e3ab33d3b5703fcfb9cfbd33cb19fbdc99e58c1933d4d0dd0e33dda99dde993e265d018ae9dc0953dfd4042b13cedad4773864ba533bfd56e0faee67c7f72b64a9920c0b0b4b08cb86024b0f8845cf7fa63df5092980ba69b74b5cd777aeeef239f61667e1adae1c5de3b0318dd1a07a8bd3d470178deb2af416f3d17fdbbcd575eeca39c2aa7a9bc7caba46cb6d56cb5dd64075fd675a87a3eb57ebe074fd4fa5eb1f9a79b253a7ebd770c7ca47d73f800f78e074fd1a8848aae8fa3708d3f5770042320d569e24c53c7db8ae787dd175fd588c4ccf1db33d598c388e6d7cd8e0e444e8fa315d9f6416961fb262b1ebb53f6a5e2274cd86b547cc0417323318471c97ed441db89e8d141ffb8d92460c031551c9806e6693dc789b03c506971d36adcbc3e5065a98b6387fd89cb3be9f8156f4dc26a5e79c73ce64d2f63bc6bf3fe32a12baaed3a3eb3ac5ae95e8d26702d273cf9f5ae91819e64b73e19caa689a26d5383ddea9ab86bf74938b34ffeb4f8002b01408ba49ff19263da3350d0f70d75bbbe9d73a2369740f30feeab797b75c0b1a2731320f9de87c955e74d2fbf80d80914f5079981fc38c9487e5eea48f8bf92cbb740f76f7601793ead216cb0551a4ed5708eec75b7988fb5e719123d11a17711159c2b8dbdc1be313e889d22122554dd7a155e81cf6d2270f70d720e4a146d28196b3b98ef11b8cd44d5617d381a54db7497f05e74ec2937e17d3f8a89bf4abc6d48cec3cd3f47fa89f7ae9234b8d57de8c38e6a852dfb8ae776b595ae5a83bbc163406a183a35a8eda5f96aff2d2b22ccdbf24708fba1ed20ffab5d61d4c80276d791d1f3b38f5b16b5e8dbb6f137edee9130ebf86b49cd70442a373834e570a330429afdf353ac5b6353a594c5a5b679c55348f9ce956c524a30694d7aec25ad05062850ec99823ad3e4cda74a4a1c205472a240854e472565e2f9d47e606a62ae7d499533727cd1c376c042db55ead74d37ec28ff1df0781ffe207817fb75eddf557fc5d3ffe10f9affefc72345001a0f746e57b31407d8fead33ccfdd6edbe003b1be351c7b6bc8346b48b354438e6a55abfd55fb6f8eda7d69304dd3c406c84d7b00bcf6e9dea79d9fd6611e9a18c3be32ebde7bcfbdf7de3adf7befd4bd3a8bd56c7a9eaff29295004b664bd62c852e5c0bf92ff4fc17eed47dc24d500f784cad69fc4dc167793536f5be21d2cfbd10413ad979edf943736d2b9c6bcbd47bbdb64261cfc2b60a5d2ba0427f7b2434c83f54db3430b974537ebae0d07aa5e156ab8ce25e08dee35e88fb81f31ee50d3d8fc896436bee81187a74bd427f48d3b51aae67a1f5695575931832c9e3c1f28bc78320ae8e3d3fdf46dd9477105016eb2d3e6aa98da5dbd4f4d517ebf9d8731b9c1c9d46ea646b7eed5af3abc45f24f09f20014efce74aec569907d1c9affb9575f2de0aa6719785ea785866bf3fec85487b214edd94f5b3a56c53b67a9000e567623fef4df6525760d2da87e65716f0b479b1254e25493858cdafb29c1563bab0257c756c4e01176764330fb2692c34a8d0b1994341c926e6b6b0d8cc97b458d4e469ce6b50f921c7669e44854577c6770724d412fb52db962c586ce64a48d812196336f432b519b0baf9e88d0063ac817231b68cb8ca8db5993147b5651b900a53cc444bd15b336d69c97cb3880f9a75162a4ae6e152d652b12f652d6d29f1e94ac93c3497b03a061b396bcd95ba72ce5c5869ab6ba7628ed2af1fbf52310f4da7ae1ca595b2bab9a58485f1ef2f3a1ee5a323df13d2c9ec282f1d8b8e405a278e5a0aaf46c53c343ff73ae8d288ab9bdf413fba7910c43e810f5caf526196347b4832124b3a159d8ad7428b04d7cd477d41dfea21779f53514b51f0e5c4e594c349cca9accbcc09cda9e8f4e534e644d6cdde3ef5d6a9e864ece6fb764b6d6d51122e47b56a72492d4799c86e02652db54b71dd6c95b0ba07c1106a084a66bac97cf52f5bf26008094a46dd64be84bf2c8564badfa9e8c4d5cd8fe04ada3a15f79745272e2db557b26ebe9258371fa5c292b64e45acfe01ee4b6d71d82a757573e9782d98af04256d8dc4baf94a5e4ac7e007d7ab720d86088600fce05f16a8d476b5d76088fdc217ae2194bf896c08e0aa145c95ccf6b197281cefabefa28890e54a8424064100812bd113d9cd8bb8749359f2a262d198d64562abafa8acc80c2d0f8382f467ee2b22f3f122315e3456446686a24345c9a1a2e4d05137999f665e84a493a323426aa92088b2884e13217593f944d6f43d2f3a6aa28c75c6380b91c0186858671445725a2af8e617d16929e19b5f84cc51bf37bfe898a37cbd9ed7ca276d97c8ba79f419c5b84c0e7312bb5a7375ed5e07a7adb234cdddee3c8180dcca3a5c300b2243511eafc7eb39e570fa72f2ba1684b6847a1d9cb89cba2e845d10bb5fd782c9bb90a3c385afa11e06bb5ff0ba16cc47531e057329d1a73d0f1374a7af099013d41111f53a38e5c843f381655227af3c349dbe6e5151af831357516fb743ba90861af190f805b40b461f0f895f30a65d40cb43f3f7c3bf0b667968fa7c47473f9ed3561e9affeb7570e2ca43938290531044f0cbe01359210f82100a9fc8eef56a3f707ddd0404aeab9fb4752a1a61191575d387a2a46e325f294dda4239717127af8c71be4442ed073abe2c945c8e22f61fdfbd905f3608259787e62f7969295368c96bc9ab9b8f7ff8f7c34e6d6234bef0cf87a1927c7214d00928392d05758492833a421df3d07c1f1f760a6ad2b6c82dcbacb750c76e3e945c8e6aa1926639aa35c5928c39cad85ba72254f24ee16ebecfe89d8a770ae3be7b33084a6ff1d1c353c74b6641c6aed7fce6efb8f6f1615f42cb51476b3b822c47e5377fa96cc9a835913ef2bdd1588e6a9d8e8e24e0cae2ca91a32e1b8de2578ee2cd1033223bf269a7628e6a97968e392ae821a9a3c56bc134df692b470199e0ca51bc2eaf1c0594c3c97ca7b01c55c2d150e5012ee21e6c22a762373fe51eec212e0425d7cdef151dbbf93cde12d175f351de16158bbcba6955e455968bd2ee54b1484c4b9dacf944745aeab25f68455c456470bd35c580d69628d9d1230fab9bbd554f5ee5232dc57a5b9434c58a8c398ae8a8a52edb0627a76291a9c56eaa5c5e4466dd244aebe603ef51ac9bbf5bf7e315f8796d4f20bfb70c92c0bd94bb16cc28a064978e497fcc97f0ea5bb54bc76e7ed956c269a9a16e328b92bba2a496928065be11d696919751d8576b34d6cd6c74eb2d0f869aa2241b0cb3de1ae500f6d6e8cb48cc88ac9bbfc3d91423cb51ad06b31c65aec1ea2dcffcdb9a68ddd490dfcce64be0aa9901ab284bf1404f34680522240110909053141305c674f72657c9557a6929a13fbffc2ac3c4721450b11762ffd0df5e88f285b28604a1df2bbdf2f07c949739f2f07ca1f3d10ce75be534697bb625573fff3ccbf2f0fc3020642a1c9e0f7556f55317e9adaf9f6796b3b0133d4f7c9665255a4f5fc3f3fc2ba5bf8cba09bfaa7ac0bdc24b61b03ed00b39d0ab684392f5f5af0a3915c6be3e5ffa25a6677aa19010be225a60019a2db0c0020bae8842a6b7c04978c0bdc25bc0f49be90affa2bf5fd533fdf374bfafbe8af43e777a95f7283cee59087af87dd34bf0b79f39ca47f5556f95518c2f78e24f4dad20aafe82f56ac357fd1587a7aae2c1a9b7facb52f1e0d405177c88aab75a43d8f0557fc186affa10389455fcea26a695c703f282bef5cc431ffa2daffb7e6fbe054ea24385b760f520f5c247794bd4f903794bd497bee42470172e2d39dd2bfc35f7f89f40bcc55df897af370f2908ffdf2a93c05dc3da5678a99780e32ee4b7a3403c2025b4547da2aa3160c050c1d37058c15be50c19a0fef63a0060b783fa75e5f178bcffdbebb03e9a7b2470e79dbf55be5f01cf90e195d0d2e097bdfbeacdf0197c1b783c20d08752bd552676e0dfdf4ffdbd55be44f43304833fdfbde80a846a0d0a9feaabfeabef37716f9ac4654113d76f16346869bf59d08cf5aea19e87f5d1ff7174ae4bb1ae98d6d7bf2bb2fa654b61ec25ef0a854261a99126cf443970aadfc0ab5e8affbe02c79d73dcb5f1f1ebaf57d5346dcf60f0834ff51c5e03aa95c36b50b5de0e3af0373c7a7b4f5d7dde87cb81af7220efc25f4ec16ba43069eb5e06eb077fbffeef71312821ffe35e06ebdf35488009fef7b7a3affa567cef45efefff35e7b773e044f6c76fdfc089ec04bc25f6f5c3847ac03528fcdd0fd16030f8c160505541e8c1f6ecbe7f20e7cf7fbfbf3dce7fbfdd3bf3d0f748370f7d9d03dfa36b1b5c3fc89df7be15c88635285c0bb0fbe157ad59432a787aaa356b081400d62001763ffcdd0f1f25e2754de997ad88d5716f5d31f23916ae48dbec85e90ab0fba88f5a39587ff7b7e36001861cac3ffc0bf50ff5b88216e82b78fce8cacb476f0fb8b6571dc8e3ed55e73d9a3d90c07f56fe5355f4d50ffad46f89fa5551f5a2ebe9417dfe17f842de3f9003fd8fdf3efc9593d07f386faf3ad40b797bd52b7814f3d6e1f09f7f90fbeeefe39efa2786bf193ec3f378c7f02a27ea19be25ea1832fc9901c30361f8dbf39061c5f000d869390cbc02aeebb84e6a3e4ed2361f858f12f19ea7aaea9a8faafa3ce003d77677de2ba1a52d0f484c7b1d783cf5d5351f851d80e472d45d79441cf845bcdd7259c3c1c16900455454c4814fa491d4208a7e9bf6b0d2ffb7e7caf3f1d7e1fe1ebd1aa98fda48246d35b2ab5fc6f34c4a8ae07104aff2b0ee9d027e7bbb745555abbafa50578ac3abaf26fd069e94f4543ce9813c495555fdd5795c23f310bfae7b5287e9e7a46e62353247a13ff4f8359f8d7597962614274cf87ba570f15120f468f38638f08538f087f8edb8a851f47dbc2576df8fb7bbff90823f8e7e10453512090909e95121bf3ffd05fcdf07794becc147354f187c1e6f55551edf00eeb7a7f4c46e955515aaff1e05e2b8e35ef0510c81aefe13bbca5b1e011e575f0217fe08de852b067c2143ffbd95fe71f483dcb7eeb93cc45b833b857f6dcf756dd3aef4f7f6fe3e5f5bb52b7d4ea647463c0f83823e0dfaa3a0a637dfe8adf44e7996902f9c07b8b71ae9c14e6a892e50c04754e8f9d1a1a5bf40b1be3b2e2e495b5ccc49b9befed5fcaf96e2dd7be5b0962b8db73cf65bb6f55bc251556de070c1b7c36f9f7ae7f75af1a0bf80073d870d559ceafc3a7f88f5b7ca39a993582d4731017d0702aab798a3a4745203a4b51dfed6f6d107aeadaaae17aee3388cf116db8a64aff014d85814bb04af6e20fe13b89e62bd0eeaca2b7b1db49c6b01137b7ad256cbe9f81fff9ecb51490f7cfc5a0edb0a3afc1a99a32edb0ab98e5fd7f1c1e0fe0ff73a28f1b7caeadaeeaefeef712f83dc1f49ed3081733dd71fe955a5d5c35dd5ff21712df741ee13564de73441d30f87aababbcfe12ffbbb6b3001545ff521363c8735040ebfe1abd6108680e0f01b3e84aaa7facb4af09a4ed351d0729a4ecbe9394d7746f013d4af7aaa0f51b54a1082c3ba61fd0fbdfdd0473cf508fef2dbeb10c17ae6e1840914dec2dfde01287c85b7ca2acf148643eef4162a3439fded7598806735de14c14f58dbdd2754e8dd3ccc4a8f7e95ba061340f5550f82eaabd6ab212a1508aaaffaaaf52a53ad445655d51f6f71ff21fd552faf5fa5375fa9a5f0b77700f525c81a8957347775bd7938e1253c7f2b3d810f9f02cfc53cc42f41047cd8c4335a36cb43cce29b39b8afbbaaaa2a07f7cd8c6668c6b6446f6b538f6d47b536956f0077f5b3d1f8fb6c9687c64733f20de8aeae2470ceca6d6d79f8ed07f9d822bdbdcdc7ac639b59360a85a46df6f2ca81c3941e2b8965b2ac1c9524b2787d0a7f35ff082620fd93a67afc439a1001855582758d606dd33e61e52b6f55d776f8f454bcfd20f709effb24de127bd2a33dded9c3e05ff87071dfaa5d029cd2df15c3e5a1d2a3bad701f3f9d09132568efaad2deebfc71bbe3d39fcd55254df0ebbfaafa5aa5efd0b386c507faff4e88f67ac3c4c7aa5bfdf5be52a2adee1c76f47e2239ebafa57e933ab84415eb15c904eda623a8ccc51b81df1d4919e0ee9f1a3b727e17faf72a4b5add0d5fff15603880ef7fccbcbaebefabfbfbc7de217f7d72abffd4ae0ed0f09ddf198f884c7bda447276015c85bdc25fc8f23f11677a447558ec1edeaa39a378123fded21e07675053e4f551f83dbd515b8b6f77ddff3705fe9257060f9d5819ca8c43f30fb84f5fc812ff83e89f330cfe713ea2f15e9db54c2e5ad6b7ba27f35d7c6de4b58dbf3445adb14f7fed5f5ebefdaa6bfb555d5f314aeadda85c2ef0d9f84df6a10f2e03fd7bd0ec05f327aa517f296d8859f8484f4390ab8e254c20f871a793568e4da7e6076e0071f05f2e76a8d14f85659237f8fd3ce3b3befa7d1df4b585b95f7561a890b5fe549ffe3ed91d2aaa4c46f4fe2edf7a3a0fac0e0a3416090dfbf3de0bdc0f503b3ab57e51cc0fdae238cdee883dde8b7b6c4fe7b95b7afaaaafa565a45faa3bf48effb21adedee482fe155de626357b154954ece781ed336f5db0bf7ed0f9fd6f64357bfd50004aafce891f8ed123889ab6ef4aacfe8ad3212bffdc749e86e74e4fba02c0008fefcf9f3a78f78ea467fe661fa5639c36929de6d4a1fa75fb4b667fa446b9ba66b3ba2421f7af385de4a6ba10cd7f1f7f86b64c76a204654b87dcb6d3a8ce147da9e7923a7328681ccf94e95a7861e4fe8c9f410b7690f77aa803b4cdf46e871f636ede761d96e44bac630d5f795f284a8efbe020c7d236097db0a32003af925ea5b03445d6fbddb3d2e1fab1d65ba4dbbbfbf81149fe5fd1de2f4369978b7db958fcb15c8b9f68abc92b7b799777050b694d72f9b165795f4ec974dab68d4c28af352be2ecfdd79ee765fe9ee972d0baeadec972d4b0cca3542498ffa5d4bd3a5b767993454c4a465bf6b698c19647d99e6a7019e4ea8044d35463d0a2ac6d5080000003315003028100c078462c1582c8b5245567b14800c6f9640765230940763518ec338868118c61843803106006208414c19a3ea00b67659f1135a3f45bb41bad2b8d5fd8c33c9e01ab613befabc027eb857c0fd863488540de45ddcc94f31f93877c89690f638aafc6c196c195a4206df681d70c0a426f1c7241584c5a05183412c5310dfa43881add307db713a9aadbd5f26cf4e542033e0a9ff544c9bd38f1a1672baaf5a3dce3a4a02da4ef56b91cc436ab2ecc7d4fc662a072da512d204dcee46fdc5231826fcc658d7c89af47291441e64accf7c43f0194dab7eb313f98add55c9a8207f981c62c7a038a903ff5b05b89118c34825ae39a2b2e25fa6c31040eb5f512ce2b6e5721f78f58bb2b5d4550c26cb0867223613183034ae30d42f334f97c503d136a4424216bd7eae6d61f6923a2fb9306c421a4032ba9e7866111c092c50e169ea7bedeac223ab29f2c9e2aefd727e33e90087582e562ab5a3bf608b16b790c8110fdf647aba0a5d5f35c378b8a28c95303319e58d694067ef71536302ab034a4201f87d3896a64f149439505d5090a699c690dfe405d618ae1decc70308024909451370165c2122b9c3b018020e3a66d0050b665a2090845c1469046e17c3abe465d1684ab5d43a82095a584e7072eb1fc6b38091416a28c51a40c7085f20a2197c9fc48cfcb2854ef6c2a3d05edc9c29c22b5ce89d3ceded19536a5f2d4b84c6eede442b840d10da9c4bcbb1c5da6bcf6dfb8f80d5e95c63c8a375cde32e435fdb4e3d1899245ce7541f849c9adc2b99900e6eb8a228953151ea111cc12dfe6381b83e48b167a56762c87265cdc8265764edbd0703b40c27e430822f74d5745f7afd6d8f55e6b3c88cf628d037b81788247f60ef718d20be4be67dcd86154a55e8882fff19efcffac494a9144b792ae5abc4b2ecdf4e12fb9b5c3d34df5033463330f446cd0600b8583224dc91c2b1a88863b4d487ba9f028d39fe8cb7741d64edc907186410e101ca3b39ce6dd81a87874de7674fdc073c357c9b969834ce60243e110c99a9d6f23088729bbed4505aa0570cedd7dff9ef563a305b90b8b399d2018e10c05719ffb34c3e1ea3c10afb94f27b821550b3d6f5031cdf3860720684bb95457b6fcc365ce1e0dbead491994d2eb9f9b165388e2f56310380411ca4d341f42d2aef50419a89c12a5cbf09d64224da6f99df015f5e1a6e746c420095fdf74500bbcaa3e1a26f1e40b2d355ddb7d52f9031fff0a12585477b4661db903bd8b2f5cab3438afe9e578cdf63c4d1a406e75d25fccc976257df13ba7b306111ad5232b5fb431fd75224a3353f6307b30ae5868f7c4f3de595f4e7d9b706c960990813a1d7b34a65825519db587be4152e10810d04c7d12b29451cda25f6285c5577c1c0dc2a58fdc508c844ec3022b4ecd930267243f5c97e4d33dbec7327e936f06d7c38e630d21892742dfc34f720950be9b2f2f6093ba4a2e812d99a4af9ed450c2e2937c57844f3777fc29a57646122627d20dc4b7086cb77e0a1bd7fb155ded046e3d9027a14453e1fc2d79d570e5e27271259d84080cc319faa59dd6b75018aab0529f4d36d839b1ca1ddce4d440de9c38ee5c5f504201c04714b12423b3837df9b29ac4cf9e9b00578c7c6528898c13dc37d2f7542323577c88935044433a6e496cd461668941eaed91ce39242cb239ec18b1989f30c8e1aa6e5a2f5b467cca2adfe638bebd351fb63c565505e0e6b0eca2b6fecd0154e7d4701daf70866a3f410dcbe90bca91c07090e1d271222a89da4a0ae6e844975b3ca45b22505f06c44f4161fa63f178df13901c85ff2809c46884952c4fe7517c0c2cf46a202f18523294f2520512d73b8e471540c55d1b780300f898ae8c2a872fda11f42875b3d80be5193808815bf3428c8a47cd1a969b7085dbf4adf6508e930a69c17af7e1b2cf0128565f8c0b8b3e3e0168947efe84ad3462d891e62651174d862dfeddc08f94abf00f64c39c2843525636739ca7e44c61a2c5ccdbe7f051399742946c0e02f37ef18e9edd70097add5244f469275534a56d69d791737038e044f56f4885de4f1d7153a68c07d2faf0aa1e8c6f2c1343e3f7c58243c3698ceea74a04e7b969850ca0c4e7fe2e0581894b69ed3662831996f9b16e81fa66c256355e52015d063115c235877346fe298d6c620cdb0c8b73827d065ce22dca0d463db6df06d11ae64894d01946a9fbc85e9d9b43439ad9a28f833c7beadedd5be39dbdc0c1e7a4be73ca01965da20d5bb5b81f243f32d0b3b0d580b4c2a5c26fb825bf33db860612442a07d4cbe967415c000951b3ba8dac5113a15b7a8c07fec3ffc5a475964d01ac28c6fd77e3cc79a394f0759803cb4627dd6112a5bcd01d90f6b0c3fd036a497cf1b1770001b6beb4b14a4b55160374880e720b4cfec776a74d0560b1b9fff537012486881875590d1a828913488281b485bf7c9c8cc20159d2a479e392e596f7556af0f4ee7a756dbde2a26317e4e52271a42f7ad732d7e962b86e6d9dcfd9121ec1d3a214644f586c681a6622bd79f920a9a40ce26a1dd807cd749d02209a4b1ec8ac932415f2e3fba3546594f33a75347e64545774ae309c6a1fc514c34b8be3b7823b026564547f8378fa7363d40b47e1cc2a8e4120027d66cfef17d83e3082f3188b4351d082402537e7b360e707bc32e7cfa3c20afa3221f0f820a4b47eb383174f22586e33956aad1ecbc26b0ac37ee74f01e2cc7ba173d130762e4ce99594b1eb07aae29cb989ad103c9649f32a6af7237e79dae587553878b5a244ce64594f308c7cfa14d26268caeef72f2ceaf757674695a8f04c6e8b2d096e08d4ef278b3068bf6b4dd57cf516842fc98170cafce1accd7c40e510716cbcdd7857e50f16fa4fcf4196ec26be5272468da00a4d50744fe9b5c33e62c27cb7525cb93b287c297e852f12eee50bd81ca12119c255be343f9b229d9e1301f85e1995c03ad781952a5da9186c809ef1c905a3fba2eae54d084807374fcb1ee0ffc7cf1bacda35320d7905c77b3498153acf6544f7e12e77e9b31cfb5dbd5db7ac6c7de2867b5002cee598080c979c0b184c2570f231731a2e994cfe5ef06f99c2943fa1d7965223c268f7173f6ca531131ef2423cc1734075d143b337b45f3e69738a386def3d58b073e6cc62f3bd64697511b8814c8a118e840ac980aad1780a439c94d176a88c9d7d68a88ef240b77eeb655c54d381c36a5eaf17c63d741e79d95e31f655d012df80f543f66cf4ff0b2b6be7244284281f0345046ee784da26f8d9d065ae6a93413ae34099df820aa3a2c8ee42208872cc90bf450ac596b2d3752579c0176a5a2c23374303035939335ded550afeb2531a11233cabb85b9dc501afbdcd4101fa553c279c13f1c2b3fcdc452868d418a332badc9a6a5d6f3d4ab7e44af544059df93d2b011fbcd28477b448d1dce163094e05d7390f8ca7a8a3ddb333ad6e156ba7b0d716732178933fd507835f0b1e0189e503fc1b25a78262f574b91c084c4bd82183b5ed102efd19c0f6ef6ae8a97085931236693838acf320c4e59cb77cc0092d5a55db516f2e86df06234015c4f9a356d1d159048fe27c1f304055e5e9dd102ea4d52eb88957cff1aa907c04cabf2f90e0752deb28c228b42b35c2b7bf4e208a11fd89f5691b4ddc84f9c41cde09cf3ddb0be830e382389ee70e5ee54062da1bdff664b42edb1349e671c1f1b38a8410129245bb3f205339551006acd5d88ce5b27e715702b4a480c6780aeda3c981b2078d67b84a09df88c8c328105c332298192d18a86418769bbde714538eab4c4d3fb13079515ffe3e57239e2e99f529d54cd40da6f495d8ad9c50ebcbe3a6f0e7dd1ae2797513a5ead0e8aad8d2d6960b02f06e38557a184daa6ed0c3f773cdeafba390de0f88a885d7a74ad762624b687709fa35703d7f1aa92990d9e8602f5afac01936eaa5b92e2cc07bbf8e188e7a5287582605bb6410e648722a49b32e6449bdecca57e85581305706e8c95f2462d16a2989ca7f1524de513fdb281fa6db9edb85d8ae1a4d2358eeb72df4887f80aa09633dfa60038970479bf7e3da6ba4db54764d17333d5098a22e5cbd026e31449ae87774ce85beb1300a0eb3f39ad1b618df33d0101e4907796d6924ddb98c99a567651e5cda11911ac30033f729b1da413d4b5b29aeaf309ea3301915d248f0322bab1109c624edc666ab45ebe77c6a7daecb4ac19158997614d32815c4824e224b61ab0c86e233507ae1531016c0dc32bac084768d3f780e0e5a49366cecd2016645cf72b3582e1151159b1f18ca96974f086724586bc6f619e57fda3e7d2ae8459e2308968ab3f8bdd353b9da7a3ee029e684f7684796bdd5f06acacc5223f9bc6bd169f912664ca661438c7c92cbe4d33ac438c623816a241a74244db1e8e6455e591cafb8c1606ace5def66ae4813e81d589c975b4f82feaaac4409a9a585d36299290f360f8088b7daaaf313e10a4122d65579bf97ec4619a2d47c4bb34b864d5bddd722c0e3b3717d857a47e7c8f7d251e0182c98edbe0d70ddbb3b58c44475d37ca30c046b7974b347980e5b516d545b241c84e9ec16480db1ac84dad7cbee454be9d7309b90dbb582f5048eda534047c8b6f6a23e4f11d5503ae8a9c90958b4007d39003eedad5017a2e934ef45f4494b43c3017ed765c9e282b082d7dd98f6d8f4924cd09e07e3e3af93990f96a3858442d3f69b336be43f8b534b52518a37ae69cf800f76991f52385a9bfea33d61744fca0d84487c800ca4bd0fa276dbd6023eab148da1107950b03cfb01833a4778fffb7d0d04a12dba0143d554c4274ba1df85873a1d9fa92c6a5309875bd7b0ca5e6824e1046034d3e3143b5b99b5ba8b6e34db689eb6d39c4fc52eb4705531e75e0278e3c57c55c47e5c66b604b6da7a5ad28d1caf5a0cbea16d8b0e98bd8ab87c1ae3ad0018008a3aeeacbef46405ef3d1c623c07567b746cf49a95cd7ff516e2d56d6c7b889b052a1ff8548491f18e543880f75cff4c147fdf7857c01cc12cc48c25181d713e5ba44de7e4eb3cead7c0acd39d642c99ffa0e07e345819ff5925484fcc662ae48ad2593cb02307cbb03b877d35c6fa35a3bb2131ffe011a35ae814bf3b6343453f30df928840ac1f069e16793151f20b01dad35f2579a7d37634b2212d8cf2705db83d74c1bfa8ace2ed6a50f808014a2a3b4afbde58e285970bc8a5f39da408ee532603df14acf8db568ebec843f52465ccdf37a7710ba55e39e7f21da3b7eb8cc53e3ae289704a51852d7d11e66ebdff4f366843772ccc2a4ea00021313d3291a14f5f93fffcdf6fe71d51a9e2a70f51581f2006a3bc6c46938b7148278efe557980d04e68d88eb6254288fc0f389a8e0f4b96eff3d2ec54a78fb5c1f54cc1e9b81b2a21a3b361e993f789c7b4ec3f058f876cf7ff84a2e634c4ad28a62e84d429a153d658c2c8da25fdf935a41d8da4e43fdf7c686f42663706ea7e765595b345ea788d4a0d33506ade385ce7c6a88ed51072b81c9d0a7cc6e81c51869038fdd109392a37e206b84137d747a5529da5ae76950e866a47db6793307febf010784cc75d34a68480b17aec0dc0f82b96ac01bf0a317a2e09cc69c287e22cc00bf705f9b015b4630eaab9db69d166c1a077e2cb30ca5a4c31aabb614cf26b3225d07d0303aaae80b4a2a23ba7ddc31a7e1048456f2a6ad503f3a4207c584bb13b64dd355ed8ab4a18d874de53166729e76cb502e1b504fd5834192f4e804b97543b822c24c0206842b95c7402c20011e4b83892b726fddd33db9882f1342fc6ef32b5a464ff1ff40d712e791c3155874f68894772a35a2c9e76766dd7c08f68a7527d2a32a8e2582066cdd0180066d5a246bd9f596910798ae77b5c1f1667689b31805dc3fb9507ad33939ad29544d1c83345e3e2ff87fd34086f3edc344f3e271c36108b364e1a9e3a6c720aca625ee3e43b7f6480180e4b1e42572342ad0425c232f4d81cce00d3e4a47833d72a2879f1d4e4b8e5d309b32589946c39e7c08faa1e7d93ec8715724b75dd28eea4b927e826e4ffe6d44711cfc6986e42802719b125a4c63bd3b9b4fcf855b0b01c05704d3207ae5d296954dcfcbfaed449fda7f7082cf1c138968ebd7c515716f4eb2731f3b9193276dbbf2411fe7d8263676f10c9bb507c0f3184ba761f37071adc5bc0f5505ad2bd31db72a3ba5bd58be055f6511e01b9db3d6f80ed32ace09ef825fc3740cd9119d8e5458b9732afa6646e48c4ec003c779d4b7724ce4bbb1867519578b569d6c55d8f13a8e90844b9a167aaf6a3e4474f82c6dd74d4265ad1084caea0e81b282f468eb44320b0ccf7ba810ab665222b1f590546181a6f2d3ae83bc5f8090fc5bd094057d39687cc646e0532637c9bfce6cf1fe1452c574257696c9b74ec7d97d719b179c10338be4da3d85a92c55c1724a8b3ef2b05dc5df459ab5c88c035ea193b69eb949760937c3db8a46e18e8180301649f2cbadda64012c402248f50e1aeccb0c382d3a7f832c654eb6c5451d9e42d47a60365bc3d323d4f0fce7530de9d3d2981d537772e7c81fa988d2a3874e04f71bc4dc97b3087fc7c2950df300b8159a4251598966df15de001f160314164e0ac4a43743181390885b768b905e6d63ad1e14b98bd9694169c2bfcd8b22cdea3f87f0174011c016f6a868881364542a020646305b0db0db027d0cc5ab6aae5d07b2ea0cf9dc121647d9caae74f58215997795a6494c1660e4d60ab570578ed90d325d40831c6fa002ac15167a15276073d0f70c297cb67e101ac0d77da2c3efc56448e2dec945b95d16476f4fd12ed42774050aed173275fd9e0ca1b661f3bfb7eaba382c54f8fe4a7de40b8947b6efc6f7bb775d5e3330b5d1224109d265d55d156b0a114a0dc3fdf0389699f2c6bc6e060f2e8b5d4ce6a222ae5dda224454d08af899d1d2d403b5ce4423ec4a3ec2086276ff70ee9215da4f4ef518d7cda2e40d38b5ff97f690da862953a7e4c49b5a02b4c374c3bb5e0150fdc7c705fab8236118981bb2e0d719a86b16b66dcbe012d87055627631bba118edb2a06faaa7a28229c2411fa9d57541aa2d785695b00d65ed2f7c68aa03999f3acf977e6d36f57ac2fd85ad184d420653f0d7adf3f0abd24a17041bc68c4eb38b14a1757d4f781721f84b4166773d320a1e6c773dd20b52d1a122fc41f94a707f78f5547bd83fe61715c91a809783b59a1ffc3c41533ce01bca8153a040c6e4cd046dfd163c68ec0ff4f7ba048e4449d9e66eaca8598172ddff946564daee7103275a37cda11c0339f3aaaab9f65e9c55098a6e052c033b320a3930435c92321791f352837f4955189e65e9c4b0de4efa13fa12e2da20be72fe7585fcb4d6c0205c53475435b68d20c4045e88391b89a8f1862ba35a80f56c146fa6dd3a475ffdbb1b5b29d4d7466966084439c5c76d6e2ecc0778a76c7f38a4aee1bb0aa5e93d0bc06423c17694358a4c1ef2888386c87d4130388a8177c82fadfdee2452719c30ddacaccfcd69fd5b4644215adc3e9e136a07174153a89f99bad29bf1d9da113f03ff51e3eee53c2d647b62ef42e2d7441d33b21e5ea03854ba10cb7e7abd23b816e86756f0a5b2344820cef6afb44f0e4b25f01a5bf555e1a81c8cd52c8910c458cfa8ed1f5f885e59fa18f5af768320f14138acebf4e86188bb69a82397f5557cbbef32b31c8d10e925c018343fde051a5a4570a36d00ad7726f9d6fc782eab613af88fb71138043d4e4764cbb4f52af29f701b01c6fc67ed41dcd82e5d89f28805f0a0f4e932aab74d5d837dd4b31c6d7e19a5e5dcfc85e2b0c4c3256b47527e7d3a9729d80172e4389771739a01abc90e02efccabbd8cf1bed38c9d7db0b01212086e65ff2cdfaccaed2abd3333eaf84ea89d9f500d04304263690b8e43185596a3ed21e7288b4115092987346fc83d91825d0d119ae3a28d0af4ed22a3941903998355ae2e21ea41aee1d7104f5992e800d2b16351261fe7e81d3ec923b15b397a399306427a8e1d5b930e7cce108ba66a9c4840c863d30e265b25353118df0a6f12b79cc720e8987568b776f30c08727b79f110d5e796fa3360335f1bc60af09b8c3fa107fa636cf43690a11e05a4ddac6d725a0f7112394eed3bad53e0c6228afea810dbab25dc517d1dcb5b03c1cea2da329a6b60a72d78dfa82cab03837ef1cc759ed2cf037e2166c16a7af083932b63abe5413cf19459ce7afb9f9101d2921d0400639953dee1ef7ff880d7012803c798cdc1faa57f20be8aaa87b21fc801f2663fdb913df31c697a953d9942c2311b7d9428ee72e1f2a669093021e5c944c8530cef16f0df94711a012e6d878e3715851547af58ad2b5d18f4470b065794431e5b073de3b8ccd547983b8cd4b020c4ce58d93f12e022e93108d199cf0da6d9909cae355d7496f9745a1b8a010c20e572be790bd42242e10242dfdc064f42c8d9b6a85a24b5aed801d8e9d0b6de0a15536fd13fcd505ae093ac951cd35b8871d9d7ef024f291497ab13c8737d5a701a8753ecd36ea44db0e2e8c18fb6002c10469493ff2f2fd60353d2fc38214c745a7bb0fb5150e79909409c6161d77b071e4e5c4d1058e356de6eaccc7a91b9322b845b8f2201541b83798552d978c5901f5f6d0c59aa96519f6fd6147d4dc5df644bd9822c6ade50f51477476f31479aef5a91cf2bd36102916038f98a50ade1061ef980ba5b874c8a290630f0dc188e1d7a53f8b29e6a91673f7bfc07fd66e68f7b788adba51bb0fe5f2e94efce43008723313a80d6d32ac52327695bad2f0809487e0d6dbbcdf9dbf9e495e256bba4ea2ae3190028b5dd613ccd4caaccef6839b232ea92cd1da50931a9014786f2387101831a0ab81c697762dbd822678a222bcd2721bf2b875d619bcd396bfc8dc6650eb10c9f69ac701273e7f2a5d1f32297729d2d9c0f3be1893e448767faa8ce187c9e2be90aaf0f736f00bc42c206aac7f5528adddad0c40a2733e60e4adb03a62ca7c6d3304f085291a5b47dd469d7cd753f60e24815d71450340d0b73f93bc10c0073a5fc18107123847d6d69cccf3dccbed62db1d6c5c5a1a345333dd2e804d3db817d5eb10348af657de738fac7764b96c9397b4d7aac37fdf3c905f9c026b3aa5970c9d0424882781cf271b9b6acd0d65019a6a4182b16289c0a33fc64060715866003ab1f34cc16f3d8b92789046dc29ed208ebd0a58adc4869d340ac5c4013c3291154ba7a90d5783e3c1ec56bc787d4298dc1267fe9ac70a66815081205fa4fabfc8526f5b8373fc380c1e02aa6031828c92796c28eb60068b2809403af78af24dc5c903e67db74a3a22c2a1a5a8946dd6141f1babcaf2df6743e8c2ef79c471de8a29bde2a78df7fd4e05e7b3d5f8648d0ad31f2004c0e27f96cce651f57ec9c85853483b45477581c627cd4c1c5851ae13a5b3050cee3e9d263452db69c5c643017f67bb0184f9fd141cd856f5d281f7834374fbbed77f2363c4d2690d923502b7b2ca21cb3297437576652c0e109f55c402cb31f50a34a0b38aff0b336acf2c8547d2bb944f1871056f985711eedd8589657de578362feda46432335d0b66e442b1f54fa715d20e7cf6406bfdbe09d6106c0257868168fb30e930576506223768661a7de2135c4fdd6aeaf58e70449dde3a3a88cba420a636d1d615e47f5cb070d09d0a84aa2e08cff65ee05ccace999bceb9090ff7c9772f9c6f6e1340b05258b6dda87eb761f9fa92b153c44828ace90cfe8aad527cafccec344af98d2cd616c9cddcac13ae2c5e7cb709b447beed54482c6fc1c5c375e6f6c2a32ed32c5c7a541f48baec4f547069b66a9040d8759ebe4f84e89ed3432c8f6938b30dea144168c46e2a87363870d90a176663f92726c9b2e4ec69d490cbfa7706f8b4c4feff5baf1b8630d71a46ed5f1392deda8aa15277344889de2877b0b316d05f5d7ffd933a1daba3a08ca7db00e0e2245eba4465a5ff650b19daeac5d8d0199c70941d7e93fd8401ac41aed42b972047dada2bc6126d18fc4aa6e6f58b766b087289f0e3d951d784c376a7b89c2d1b8b094d5a431e04874dda4514b61f403201551ac40c6f020338ae473350347874582801af1eb0b036cc4939dbf90e87521111ebfbbdf08e7de989ef347adc7e578b1e992b8062f942c36cfec741c6ff6a33c6571752cc4b3999838947ee7422f0421089e2b91e94c532f3140e2d9489e909e0d39622d59344c8f95705646a9169ec3c88c48f982a40053423e7e96b640783505f7e7d50d8e9ab8af2a4d0582271f7d4493c245e6ce7063cf99cb2982ec0e4bba711dba495db731692b490d2b406401d09b000bf0d80c3cd8e4c223f52ddee6a1c9b82424b33955212b9b73ec216e8a58776e22da0cabb24acdda98315e2a2da88f7314f151b8e4f47912daabd5a6a002db294b9e2095aad3bec0e3d61c274b2da2b8ddd8edc8d82849d8b4bb39918af8a392b9d9e808b69bd0a419c7d9e323a5cf10de66447deddc22a10b67f827f8402ac9e1566ea3636f946de1f0f36a5c675de5725a4fe116cc04860fa1b8e8280e7add130a58152722f5e1fdb36127479d7a393622de81cbde593f3b0ef9b44275588ed96ebbb7737909a3f8199806bc10fe15f172ceeebb9720476ef38037941744d408ae76b0afc9b256293a58ab132ffe5d8f737a601b18f6001a676f446a15365c623187efc1a4fd46705fb5e47d8a30c34d4c23f4f2f98adf208ce6d1d52030099d890a4ec7f2f8e46923add566e574b94a4e532dcc202c4f07bf45bb2cd3904740ab1fb504465c05ea64b8974c87a3346ca138900d7c4e940fa719f1f2ba13ea5b4128f33e68bc2c507763e6f4aab29c062ec8db1c8b2b1b18fb04c591955a1ac8f3a829ce33d4e2bf66b71b4a3a787b89413acc1aefe240847f92d69f1b694f0d950b4a5aa887eb863048032683d65566b6f7cb4aa54c8e0d436ba1332ed8105d0bd5232e42c52f9d56743aba41ff8266c0be8d39295bcb563a5eabc27343b511b288f056165fdc56335797198e61f0217e1365453afd971c3e8f4ce0c656557c64d840c8ef3cb2fec4cecf8c968d254131919f56ec1111489af8b4df6fe4b1452c908b0a38d98ddb85d590d60ef1a232f7ed30c001e3240eea61a45bf4a808d9677dae29d7274c3d8e5e4effe962ba69ad07c7833cd6cb319bb2ac60b0ffe94caef6c4f67ee6b244866a9c0cc44634ff2b1db1dc13e299e200f04128e5b6eca20b12ac4a10819f800f25c16978169f62d69ad2fd20476f68a85db0893116082931048ea1edcc124667ec058feb9ec5e0768a745ec94d873239a33905e4cb936ed040d8ddf695702236f1353d41493498cc34a3b9c077e160740d4898c0b72410779d9ebfa931a2eebf4c7ed2c3ed121c04becd70f60aa2d89808de44658add1ea2cd71285b003937a045b68461fca2c9ffa7e34fe6b4fd1b8e094551463e9c9b6927c6aa26119f65fc70d8a774aa54f25d34cb338e8f145745fdb260d7ecc6a787f0e5f0347c2f389bf464b2c62633ec5c297bb21116b2bb62632380c1b9636e70e2c830d4702e7f6b8a1be3acf4eb37d2453df0533ad083838a2f489c8f8a8b77072ec34ab20c37b23a3730675fd10f672b1ec5a8f7913692ae92153e296e8e5335e2aaf4f928ff72b0c869be5b7b49e15cba0208894b3bf5a5ed815b6ccd05418b113a5ee2767d34f435c508aa56108e73a4cd8e1c017e11b70abddeea8167fa1ec628ea45c0ce586a6d3bffc01c5f137abad42e48203caefd91be2fa423a7d3958a2f0b6da2124a50e316959fe28e2c8a67b4dbabf2992a1336d38558e13942818e793a67b6caa8cdf8e50e31837280382eec9cb97eabcdf294c3bd1b44d72e87f564fd27c36037feed8cd86407b4b9b9cb6795ecb00f9241049f953d0c6dd51336ae8290abeec4fd643438df8096dc96c1022eb0172f06ac2aeb146e336e0276e9698bfa5e5f3c24e27c0e0c942e693421e3662ec73311bed66773a97b5ba73e2fec4ac63c7f311c5be35ea392889d5cb9329970cffd63dd45b715f04994057d33864a3663b7ac44124db8a807c95202866dcc310c4bf01c78c38a23db945cafe3de182c5a52cfa9949b92c096510d3a349a9e91d58eef7fd0fce5a3f9eab628b9fac1e4e2f1caa75148d0dbd81af1bb2cfb36aa90d7e210b6fd5ebc48e9b3cdd6fcb8b43eac3f426c2b431da18e820fc2f9cc4aa156125945bb6da94cdbb907a57ff0aa05f4a4d39c2825c2b662690f3e6970c20da477d6e126831cea533396e1a994d40634ea78acd7f41c6bd25ae59ceba5131bf28d5f12df564cfae3844f800aa7698342bcef57a7970cfcc66593fca42ad3461e506fc6ed1b347623fc02e86f42c071a9adb5daa6138f50ecd9b8bf36f2a9cc000fc07a278f5c041bb7a9d564003479d85eca42a4670e6f661316f1d1c737e88f6ac1cb27ae8ad61ef14aa0e2e4ee81dd8a0e713d61801bbe42595dfc24b6d4463e9e120353ebe10ee000f96cf472574578f5cce16db6849cbed900dadd4d28d6f8a72d87016e6ffe5da40c21527cc3142c4f2027928c4c6f6ee586812cb6fae88374c8a194a923f286a098fb9e1e2c988be0a40ea0bbf96477f64c33409a55552788b97869500e4ca356773ed743ef243aac0a6745bbae2a5d4381da15cb025c52b9e80c197f29de0942dc40f1b367f0aa82568973a636baa24bd71897687fa5107ff5711f53e3c93f5e2df8726aa4004b417621d21fe7443f8ed40f335f125599a86b1c34064d8b38643819a0f54496ac2b5a2ec2f866b17a5cf38c2b5619dc42b77b4851da535ad971794709874dd24d3bc7aca5966645c6396fabcbcadc84f90978c5aafd966af79c0615373c580bee80795a045f3a2f538b619f66e7118c1cc23716ec9f0b70566065edfdce0944fb47bf508fc43d9c829923fdbc8e7e5eee8b5db670eda48e83fc9657409e806f09d5ea26e6e80a1397c599bcedd92fb3d8fdd7602e851bec09cee61b1206629d9239ead70ea24f4d6e97977188f0b320d2b30ebf47a2516fbb16a5765d6dc5d96661211717b5994b27e353b8abe90fdedf764697d5747052316a42f6992af9b220ddbe9896c9044dd8441b7902e47b4f557abc48d59fdca59fbf1a266f638e0855263a1a1f7acccc173a01b9efa239819027f550ca1ec22b2d3bc7ac772fca89a05262e964e16d08cbde6ebe9a00e201414d24d874435f95d6fd7cf84e1965c9f4c4d2a3aca0ed8550e8527ca69932133a25ffc7e794a0625e534292c2b8a932f44f117a252a0a998acb16b02878ade41157638e88c4eccc74bb6793dbe2614271ad6ab852d6dd8fc3559a5f7ef59967e41d7bdaa4a87f3f3a7dc0c369b464edfef7eb04ad55a4396d2c4a49a638b0a7c612c7df8afa913467340887d6dcd39cc8617cec2d80cffec71ca549efe105a6b65ed66b5bde53b26b60e28d5190c383a9d0eb0ac944d6a28d86b7f5f911d150f4937bcd216ad63cc3f0e18dbb3652f7f4dafbc7b51c5fd981bcbbb7e966226133350acf6063c867b1ca996e95a348a86e361cea49740b2340fa253a0312cc67011125c1e40574b6eae657869aa93217c320840a37b30981a3282b1706df90fd6cef2da4395bba987585ae1e904a3310a2acd910624ce8e9b65750368779ec7ce29dd853bcd376c0347360aaa1b3d840e140014bbe4c5c91aa2c95d4b5cb8274402b7867880bd3ae2ef6052ee3f610395c479ed8d4bef4020b5447d2db908b6b7c9b8e3071ebcc946818186dd5425c33fcb1e37ffb1cd008db91bd5b9094a61727e00a79325cb4010713dc2e26eb7e7d23d59a64c9864a2c6aa767af1c1dd518abcbb937e34a3ee043e6243812208793d23dfc0b68fc6e955448b01695ba7b620a801697eb69b291257cc1dcbea6571362e508fa51e0ce6df0f69b55fbf162de098fffcca85e8933be85cea3dafbd66d989178600fece72fdc3468999fad43fa9f472bbfad25b370fff05194243cc926c2845a09ee24c9666c6cf03786748d0c1d3728e6307eb9399d3006f7c728ac5bcde0e02ff6a96010cac1d3f6a6f4dbfed005d97cc963cf6139b1f42c74e2d68fda1e40dcb604ef6d2651ce22ad06e72976219ba94a6f895de1b9916b75431dd5e7330e69568b3b48d46d4966b75f5d1a769c0ffeda6c01968654eb0e8ebeea379b086b5ee3fcfefce9705a0e1c040cfbbd477a10efee9f393ef02c7fde14b4d0697587cefb35d783773874751b1ffab59211f3ac46d18586318b12608f4abf3eabe50d527b4b44f038c5f81a3521b081a3333a524c78660b3b933d0c8c6affa450f213101a4297dc6ce82533c8576c7935810d7523a625e5555750bc49e73012b2a462a407ac31a286170aad500808257137ba95e928cc6ed8b17086960489065ce9b3d6deff4c7411516ceb7fdd8a52c61bfe876356a137ea5b0475b9292f82cf958d7ea4dec8cca0e31d3780d814a4d1b9afd30ea9aa0702bd18f2db8839d2c3d560cec63ee0d3e1c6c62ff44aeb6a6b32ca23f3dfb3164711ae1308a7afd3c8700860ea888a122365d3eaf14aa098db7203ecfdfdb6b52891c1131f6ba341e6da6c3c1fbf812181ec0a5da512c294e7fd1c2ce3ea6e1c7d1c17630773f23980f3fb856f7dc7b5d1caf0a67439bb8517420c47752a9f05f70459743031eea7616c8f172a3d3fa854af78504bcc5c0d930895c6fcf5408462d05fd518bd0b70ca1049492d43be221dfe7883e5be4965f77aa885c1b08fb5c25a02a122877f2d9b73828152aa73c90ca4f4e22f3d1f33bce0f9919b0925bf9460312250aa595de858ef034f0bb1d2662c7775338c0d88c5d0c4689b3374643cd00f1ff1bfcf5dca0242d492ee99cefc7acb21825b41754dd006de0b0eb5db5d2cd3889455c2209ce955d453d0a1871f7721dde5f12f7ed3e2dfe22f3760de3cf2f06f1e6a6bda0d2321d4d9d441bc335a721ebaeb167b4d7f70b3821b9825d0797e1851fc3d43176c980176be909b123b6b1eebcbe9aaba00fab04aa4d02b4783ce2a1e702328fcf7a720897bb582e5b2f378efcc567c3c5005938c45510dc586e82a32d328ca6d96f8ff1bc5718b8b352633a442e8d31250704457e7022d6eb40e855d9f39686414c806491a38c2b87d21ae42ce6dc0da17f26b0ac7fa9314ba796197ad2b9879b9595e61dae6775f5443aa3097568a6a2088b0e0dd4a31b631f2a9e5a0feefa4f9b52f883014d9d863b3c627950dc78744a1c00f9f615fcab68035d37baea167505f98d42af5d08f8b7961f17c6a0f2335bcf6058a0ecc8da98141b58698355854e03bceb9edf1fd1bb96d00b584d60731e09908777c2b7d0b1ba9301cbd9282313480e059722464f42283881473fd916c993b0546a1592fee2d73edd2f09c374b1e0e3a6ed212a9c3cf5f8473031080b61ab42aec3ead87b07e218df5667b64261fad172af53d0d0cd8f9cb55a65e0dab82c4f0f85f4a29cdf84c5c2ee88ce44b8795bb001c7b7b5927009f198abe57cef643420b711f308a216f2ffaf36308d82a10c072ca1fbd799943048c3fce63c340703924d7bdeddcc7294f9efa9443086ea4585063165cebcc40487c21bd0b4c8b632ca2426cb3723148b7c4fc9fd7341e78eea5318ce9ba5e37102359a80afbf515f177452ae28da8b67169ef4abf393618037e2f022075724c7a7a989922f523f30020d215b2b188d6a790841044e814205b7548e199606537565683be5942f693970319b8d83304f7e279027f4c462429375203518f5f7c118a320b01c2cd621e7824258720a1559c685ee43667484bf94fd67bb1c07f321894f996d8d27fcd0d440d29366a34ba5d9ebfcb4aeb89d942161a57fe9432745c05e4d85e5d02bd22e1d6be361a7b5b8f23f22e1e07042398cf1e81b2f4d06624e65c9f247d989c4df74f5ed077337589d42795fbe59910ca24f0c42bfab0301222794f7b2e8d6540ff47b88489d007966e9010cf2a32ada8ab221e45b7752e2799061371bece8bb253da2e5c2984faa2501a146215766ee27cb3a38843e9f0a31f03eeb900aa55c21ae4a536379b9fee0cdab6fe834c010a38acc3c7effc7b72758639436fa8d33fdec4501e87ba7f0358003113042dd0bffd1b46a03f858349158913954b93f729e2b5305570471ccb2e24aff82c8bea6dc12f6fdd070751595843481845a26dc0fc4672321e58b75db1d21837ccfd8f07650538c5963821d07125626ad0dd4d66a98aba259731f63e9f44b018297f6ee9e4e9448f84d436aed7ad9ed2587869d707c12929cb6b3ff5ccce4945c5fc8db8d41570b6475b3089ba2396f2024b8457655a78a5ec74b80032ac1090a6141b75ddb0d072bd68a7c93195fd161d47bd4b2f901c3fba5a7ebba352ee9e459dce552575ed250e3ec430344cf676396c4625c4513a5df1c0fb9d272223e294ba2a8c5de22bb7cf0955b97872d7bab31bf700090062498b090083d75df8db9f41a11da308a4b04fbac3b3c1309b6df883bdc2bc3ad13867056c51331e666fab129f9407d775025b58f072d7682091cc30355858c3afc7d3ee7a1c3b029b6350550843c174e9afc994574f71bd8e7fb05d07380e7011d8ccc474c3546b22708f7925c5714e46a72cf10db463da51908eb89efcd694c01a2f3f1e10f493e99e469d98ecf2f804b70b164dd50e9d07b8d716da3bdb631a7bd15a1d73187853384dff3d4c8a54de14081b999fc8f250f4d674a8999a6d58340b427d7e02cc540e8baf6166fee897eb19ae06234d804c0ac392836fa79f0d7286b927875a1f4f9a7bbbf17211252ad0ec85afa2a94aac38f67f29d55c70acf684d6b211b4ca8d101c15c022e7c183f1aa4e8cc5bcae3006d6c348f605dcc7efc5fe576dd3cdbf3b7f1c4f63b0ae22c8a7c88348273c9172f918dd49295113b3647a728c4915de1f5273967e4ba6693c65dc0fcdbed6dcffc3818e801d7088225ec4e347feaebc04d1ae33abef50c5489214bd14a2e355c47053141012bc0ef0256b00bcb1fd0a49721e3bc9f9098696094a7d2c43fe9a7f8a641edf296627a20706c0a5f74c040fd8b1059226c9f3125c5ea1cd9ea953fd48f3ecd2f4ef1b820a3bc1558963458ff6f885f7d98d1f6c450aa8232ac78a818a73d24cffd8b01822310f94bd070ab00fbb1a4f252a41b9e61254645c4bb35d4b467201d33423304dd0bc04af0d962920e93c82e7d84e6d24ba0fdb9d4d561e5a36674e5cc66958a1a438c01b1291a1edf561fe85615b919200cbc39959ac8b937f8798a19225fafbda4ea20cc8dbeac897fbe6b061a3629289b03622cf05a37fa85fa6a02843773586f94b75316da99bb6db10aa2ee03287f999fbbb50f4047144b2f9b5615fed2d165155bcf15376d753fef35b8eadea303c44b663f5e537d5d2a901d4f0834d97533deea56c289e6276fc7e5bd4431f6f6e8bc3eac34430b284fc14ff69a0ed097ae08af24c33e7d9a943b55ad6d68008c0b1cbe4235ecbf2a94050bbb7d4e6dc239d26582a1eb58e8c38000c8072d8bb13db9d730b06726add42e8cf94a241897d3beae8c3afba0c3465c1d4f061ef05dda706740ef22fd0db5e1cf9d14fc56bbf6b2065c708049abd88e6c3bbe9e47a41a527a8b87755ca21c3fb03b59396c77da85dbe9bdd876bdb181af2545c4fd1a4925e6927a9d13500e20aa99b0a8ac8ed0ecf2b43ca08626e052ca0d18d131dcf076c0a8f5464daa62f37a68f713b4ed9fdcb81268182098404cf71ff4d405148fda95c59a4c16189da52c1179db7a226fb61738a4395ef57f0744313f01a710a9ef01c14087f220c26056445d53d5d1e687eae2cde57a84c61e9fb3eb7c648c3fd52780c7087e5bf65a81475a797dc1fd88b7f4e527f01d6987d86013a9d4e93e3000224bb924ae2891e1011d27a99516741ed123bf685a881b991e9f7226c7c12285bc8c61db86f7601452265b54ee68893dd04802c4d86b4550895e260cd202cb422c83a360601479c329dadd74554fa632439c441fc874dcec59eb56c0aa008d906725126a930558e7a5ab9c6671b5e5bf37336bbabd5087515ad970e9e5d86c40931d219fb478e91f9b43eb3a322030bce84e608bf6ff9e2d68da4ce00f10310dd8828559e751c2d0f96e4c9a5758eeae60e968c68f64244612eaf5eddd970553c3712db89f5935465814e9f974e5e64f73c7a13c96acc90e35e5a0308858f7701163a52efc41cb7af9613c6eaf0df8ecf950e3ace48af4273eb8dbb63544675c578ea24e7390bb490ffff0d3ef4928cc74c121d54e592cad248b20e9ae2f88eeb6eb85bae19b95026c6495fc11a90cf3dbd8efdf9d9f0a370d0486d71a7db383cfdb924d0f256537360bba346ba3cdd736b519a11e3fd93125bf098ed44918560058e8bd54753a863d8b200ed7356bd24fc60bb89fbdc0d5f10d0b5a860fd1f0890a4edd65c65590830e2de4ec130a38cbcd4d2df316549b7eb4917935c0e78893a32497663a70ad0a1b7ef23b90cd87210c63d633d148a28df54b72899b7b174fd940b9e54fc8d3d406257d4581d8d7ffcd3af448b532c5204896dbedd8d24b1fd09a4ab3e89dbabfe79c3743c84a102283ab523441f44d49908a255b1582cad7b644b5b456b6dd828794b12a6efaa7604b138783f8491c4e53d2dc91443f1bd70755e296afab4aa84fbe3562276f9f5e93d2660a1065a96ee55c15b12b765046d5f0145e7007ea0c2aefd1339e83f6566af611629335cd4be69a71f20023a73fe871a50606c8ab98876b6b5b5c005761e99a98e2a7a6e11882c95e5c210bdc4618e546e5291021694270c50f171fd8540af41cb0d02d94667adaa02dc84b812560e014d4d870f0b425d63f54f42d23d5900379401ddc307d925e29cdb6cf6a097b0497f224587acde3a898dce8696ddb85827cd17040014ceeadf6cc9b66cf35c53b6d236835c63ede93f2ce496b56f9ae1b9d9af0f666a69e903e7ea4716f463e154b22bf9e933e1d3f603ea49213724925560993431173970c6c9b2417cace14f38e083e42ea59594b9f7088b23cd5fd3cf0548740ea007672307e5170384f50fa034bb577ef518914db8d70377081965513d2a87c999c0c3616ec5bd6538a572fe0d7a6fe944fceddc8bca9a7ae3e325373176fb1d048992ad6fa29f2114351131b3ff5f7868377cc53bef41c6de8ff173c54bc5ef1391a0a319a056629ed4011658813f399cd7ec64a838e8d7bc05d7ce18b1c68132ba432778691ef43ab0474f42548a5c7c631bfeccd6e9d3dc40940b02c7b58f7d3ef310c3ce1ed74824747d01bda61bb7f9b91644da9761ee9706982faf4092f99550d43ef378a5a667411d3546c4ef4af2c6df1b3b67f48c6cc8f86b5df394b1bf922825ce8137b5874a3e5ff3aa69db4a2761271a97d6743b0ba9f9989483a138fc06e60903fbefd205f20c0d2ba8ab18cd707d8f545053eda7582edd37afe84625491c75de97242ac87bd7e54b63530c494b6c235fdacf319d0f9c16d7c2e5047989be5aa85549ee24e02ced025bcce5c5067443b924a9af69477ad77ac52590347dd1d41dc578fe6acde89c944d2e9e9c66749d9ce85580969a4616f370a9cbeaa5cfe95bdb7502f5d2b475c5ba80d2a2b4fe5c411ea607246954b6735aab1c29eb6ea9f5341534c0e96d332eeee522d251eb4d4b969681756b67b8bc000fd20ba6a6ca6efd992db8fe4a5df853abd27eced2be471a6f56252e8b1f3c5b10275e85ed56f3b420b2e9b800508a490104baf42c8cfc008a79b7ec2529a377027602815ec57737ad7c01ca99b6625eb8a049ba93c82ecb575299a469fb03b8254e861d0db02eaf64872fd0254c323744e59332cce6a402f0e40aa1494ff699b293081b1aaf0ecbd39f3baa982729494bbc3a4516b38bb50ad92f41add9f5844eab4ab49c88ac27d13baba2c3086674d485294de3936ac39c9e72cde129830e9fff0ff3e4108a3a874a0983fa1ae9a56551d189d8945e11a073a0a6e92329f6af61459408ba224af8c2cb49d102fdf366c99659e5288deaa97eaa8307cfb9ea3deb1f31e8b2b1bcefc925339eb8fc48b7338457e236e3eb4914167065a47153bc64369ae10661dfe1272ae9afa411ea1b7de787a370929829c9bf7ed7348e5c31ef19a1f82c750364c91e41fda0318377814320a0fc5274695bec98b6c318846c2f6091218886fc5559222046848749bb4f63348d87d0e28d6e205505b67837eed442f564d690899c5cccabd71180cee6026e804c717894e0978861b54a692b2c7dfed574c25561051f0880b91c2c5ce44a7e10704191f1d793e4e5b121b95aaf7b6d88fca61170460d1cf9ac106410c78da688bd9fdfb11d3b7543d91dc640b0254da0f84920e0610060f6f2c900b9ff56966bac9d5ebc7e295306151d3a4928858b5f423f9b888a98001721de556c59f924bdccd8429d8ed95693d64eab5bc61d71a43f9098ab6d3ad0967f4eb1d507d85b70b699dac44d4f69ebb3cafec6da74a80233a74057a56d26b496aea60901eec40c5c6d5038d2abf622bd428104d816c166b54702127b002c13d7f180bee4a7b8412ff36ad3c9fac87612e2e1b95457e09b9557ce8b1474ee36980e282b2698e29ee2df0966c575076869e98fe08ffc5503533aa50e0bd52c3c81f460fbb327d899e228462cb3142d29f68e70d92ec5c43114b863749a1e87f36944a5144e23f589bd046631f4c1b1e3de3d4d5028776d76a685f2d83e95918faa4b04a75638937b91b7fed3ff3e865971724815dff1318c6f63c532e040e995068f77c7f1262f4503dad6e1808a1abee2074a5b57206f10891c02b6e8ee4c4fa9f6cd58e92a769a4ddafae17f69007d2e4a3e872ba54405ed75e213e821162fcbd38c6e23c4ff350ca23e9c90610f4a75e2d7d8d5d42fa191f4b2571186fb594fd5329e918bbb1a682a766dd79bd54b7228e320c7354f6abb0259836449aea68335992a821d3c0a647e8aa38c85ed983e1a2bc703fc3bec4ad84d0db4b4e68d099aa953513f969c3111e027b149df938518d998eb262be9fd15edc227f001678173081cdcacc9e82503e5700636b33e04a287c3abe20ebd07eb7d68f15dccccac2456df7393860aae8d097f61a788229ddb60b3791b8dff0b5c251be621e95b84ac455338326500153b7d1505704994371ca5955b0641844f6cafdcc4aec5f6b8d27067db24dd2924f112fc111c0aac0b16492b2c959f985d8846f4d13c8d8e51984ae4fbee65dfa1d7a4cd28b366d258a2d6f51c1b36a4b7e7e543d56c5b534e7e68d6248d5086761b533d6409b8f906c78dd6001cee515720559e6ec5bcdadc55eb99b5497b5dfb929f7e5aabf49d152943ace17c12c569a53f43c29cd5f57facdf4ca6f177a4128df236aaa825e0b4a0665a8b78f832e9669c6c5369906eb6d3819eb5e8232a1759ae60ca101bed6e05adebbbbe0c18f5b4c59d98b7a194a4be018f8e05f60854e4e3e9161bc06e06266874176891f1a3f41de21d2b0626495a7c3c16899062a367002629cbf8e408d25c76f7274badfd088d3d96c6f05a683d172c3919017137de46b65d1ec95904052716dedfccd32d1a4c50db6f52a0cf42dc31680105e948eb7997379cfb6e14b2a3ea0d853e823f839b8903625432cd7acfa06430c175c2e6636e631aef4c260f883fb0244a31c2418ce21905702d2baa354568e957d34ccc802d8c042517487055af30f04cd01f5d2cc653f7a732eb34dbb3f2bce2eb64ee9526b77e0db4980fe23e407a8a51ce36a7e791f6bbf55bf331abda96697a450666d0a372bad1718d202363039b2e0b699668293e5140ca81e81938c218d640b8f420863dee6a1991902b4873fa90f2b969e4188dfdbba61bf722387cb99833916c662ff13481e51f5599cafd31b369712dc8e109e7b244649b4c3f5036451a030dec16fd9a4dbb9cd51893141c6b06429ac375b382ab4d0b5394a05e730a90c031c2d4cafd17f43abbbf86947da3029a0d8e3ea3327026b205562c5511761389d33d539bd8117bc7909e7041dd6522fafd09c01ae53e0dc53c7ec9abf2398d9091fdc49a52ec12f2e56350dbff40a97445d08dfe7bbc01fbed24e10335bc61234ef0f10a1873eb2cf22673e67f351014f48183a0470e7de27252fc4613e80466ad1ea1ddd8b41dea52d582e75d88c29ac1f753acf2be29cdee452b15c2da709e5c0adcf1770210a2dbeb0be7fa4c01754ec84fb61de21bd34567b3c68388678ea553b5a23a99bb4b49399f87fab4733a057102572878821cbecaf5a2192d05a1a7bb0ad0716a85e41199332458a3eba82ab5ba94a22672253ece07232994ad1fd0689d37c7bbcaa2b32353b52141db412a1ace8887e0b1b9d931f1807284130a2d8264c9fc2a94c47ccae0e205762a92fc0ef4abed72f4be4696b0fc46375a0a51f6cbac15771e6b13fac02cd8c3facea81e303f5a0b4359414c1360e2e1cea8874b84b8d32f40181a1896544241b681f42e1a4b37e03f367dac85a6b6e9d2af383cd3789bd221f808d85cac9ee9f22f16b7b64dd4f685c300ccd306ed09b8f23a93a6699ed8a88019bb6aa313dd7d9bfa7a49c75c1935d123494071f6ba68f67104d9479be9f241096e5cb4495a9e9172a90bc120d04b21af022f8c8fcb0860ca647875e09c2ebe5c1b69970172870991f93b5874abdff06ca5128fa93911f2d943feec0483ec021e0dd988c7c5a971ddead8225ae938bb9ebc4ac18b43a5342b5e39a223b30df162dd066525831da8125003458c81660166b5c54858620a7e27585594c48edd7e8206f125ffac308f5e02f31e3bdd7380e119f3d2f81fadf21d946d40a377e9629eb9f1bd7227004788e3d3124a07e1ce43832eef9cb8fe113d01545402dec0317603e45966d9d68585280a4bcf93c0239c65bff168812d227377ed85a0ea5a6af6afb4e84c30f59012d213b63d3b2e0c74556f2e5f03bdf6c66aa3302f47898245f92dadd5a9e1c84a768ca02ebdbe83bf6ee7d6399fbe6bf9f753347f9abab077c0ac7cd9a0aa0ab1ece316bed289259c500d3e0ce58a1043334457aa58008c1305272e2f8c185bc75077f5209e13c841a7c3bfb5be90af1053cf382b7167894979150932df731c07619207c066fb8336285c6302f2e9184968767d4d4164276fd274cb4ce28ca268521357796cf5b2fd7a8d6055da38db9c7774baff9091989a28141a3d5063b65421fb307eaa9a1496683a14841f9af46a22dfeeebd4a0485407f1ae1b643debf66c28dcd9491357a95ab46749880107b4ec779c16799ecd127c78dd9a39edceea8a5a31de25bd277bb8f51d3394b603b26329fbd897fe5cd6c48ef8c7ce4a172b8c099607766820bfecd64a5cc3f4d36a9173ec2ee5d6f57ba9e2103f0e581cd62995834589d5ac5345486bc9c902167e1f4d66d236f37474013da25d09b8d1b95303979c58d81dfc2d02c5e6ae31cfbb41b96ec28faa70d508b400468679b932799141ade97351a5dfc0fd25a9d97fd262eb0d02f9ac0075f22bce782d10f4164077c6d1b1fb8a947d6d30766ede165be5ba0b308a10f4b5e362d609f4aab4c2969e5b942310b4a33ac8938ab02592dfe858661f1c19509df4f06e47b21d29b84300c16b72d3bd1d00bb3d38dd37985b559bccebaef28b29a15da12e9adc3b2d9353f7cd0c6f65956e98ab6f615ab238f01a51a1904861e6f5b60a14deec07fef3d104909c185a1468c498475eef0f1bb02ac6ec5b75ddb4decc88698b4d11dbccc1e367a21cc53b5b683cd48796b3080a1e6deca281ff68956c819469f0ad0dcbb779ded3b7d18c8618044d8071137cbe862be7b36ca972a542c05a2a30d83f113eef050a056fd078f8599626a321d4421d85c79f5c16774c429a3026213058ba2b45188a6611e3e08073697146bf1aa8123c6ac65b3d38081f90f10abc76e8a7f4e9abd9a814e2eb2998f03153673680af8d49f943137a9ea61f16619e16e22d63743b0be7d1ca4889dcf949861bebc02652d00497113cc07c48ee209e437077bb0a8e2c8ebe536b9578843b4fae1f16dddc9513a5d4294cba8b9819a2056cf6b31d50c0cced818ab2812159f37017d8d55937eb605fd8d134ecf20aa4dd1f547125fa406e11a86bc14d089592afbe5f8048464b19d087734ae2c4c88ee494fd56847b537169c2b5fbdc8816eb0ab5f8705ccc5db323d71d1414470a0261650c3306cdf8084d9d5157595b56c07773c732fe7b1a3229b9665d13b3a8f53367d75be912224744d14a8ebbcab006a81466bd85bd0dbff24c35055077e50e621d70cf90b28b9cebd400cef29a1b536ef9361638face3fd742a490bb45adbbad4a6bc005fab7844e6e0eea8a3e0916210105d3d36a66efe518572cc18ad154e0822bee6a2efeaca85922eb0d05bf56c70cb70e08b06b23a0dac0bfa28cd428cc8ada00e26c7682f5a26db409232433adc4e29f5330688682de3b2609e5d03f09caa749170a6581e020772a7950004a8c77a1ff69d42109bf0511922f6693927a65a0012a1687d8459eb68b341282360da20fa795b4c461d367a0c0bd1bb71dd46e94607f6fe55b496ece0ea7be44a529217aa47a09200eaea0e5a8d89064b75d6434640cafaadff0e9e92fc8d2f1e2861636815a59f028dc2725523a4851863e4fb1cdcfb628bd16b16bf2664bc32c4b2e681f26595c204d57d06ea15a89b1cc1d817f568550247b27a3cad850a038f808d8d88a05fcbde64e04d3adbd7763692850247210452c30d3e6674c4c7a7d4b5410121d3f3c845cc6758f9bc2b2e8c519a5efc79850ed0ed736b1d5f66d1fe5722e4d90697e0e67610b86a6ce0b6e163d800fdcb085c122fb197c70fddc7a9ca4cc0bdc9f73142966e473ef48245330df44c39634ddc0784dc4ea1b03c7076091cc8d35d3c5c0582361081dc21a7e95628ef8afb0372a061fb776f2e85e85205c517bbecdc2d353378b8964203537e5190c3c47180be2987ba262eb3d59446761171f69df24ec1e3c6f4f122470bd88b2b682a7b9eb14e37356f268457c68ac5c3c951a3ecf90495327b6137f283a1a831fd3abaf3656ec42afbc2330eb07a74b326cf68403a4fabb21040680fa63c45a208a98ed53a5211b4d0ed88c28fdd38f5758e53ea118cca426462aa6178389d18bed9ff13a13f6827b45df8a246e2120f7abb59ba1476c25860295ee7f12dec1a850cc0d3067354ef7ecbd7bd43a359b0226d0dba72c3fb9452483186012d45264775d7d46e66600e1856ae6028a035e1a4fe0b256e4a88f457dd8399e50c7a398954729d38d17e06d87cd6493e240f4dd1d745c4a06dbafc4e191338ebc9ce880dfa91c9b72f772a2752cd0002aa7068b26db449669ec8c9025201a19cb0922e1d5443bd4953c074836f3a4234ec45b3e676a13972bfaa742ae482c39d67c072e7b6e84d8156309433b7e527db34c4fa2271e2665aeba266301885055bf3c10ea0fceaecbaa858903b716914ba59d83dd3026263c79dcf13ee4dc4f883c0c6a02a12f392cf5267ea86beec99c899042702ca4d4386893b14c40d2482ccc0925d174b1e1fc7990786b0200fbcc501260e648194c3b3ffb87ee8c69b00c95245c5f4c35dca94ff468582691b40725c1fd898074ce4a4201296bc2b39d3f58889db25be33df67ebd3ab895d2797c97c4558c41749a507797c41e57a155fc1749e46c8266b9ecce9e6312ec47db26e8d248116cab45212a651f5d64534de8229e723c72b89da429036050e9e6e17f1b6763c09202408687dc2a47cba95994997541079fe8b0a2dc915072e64601a6ede530bf93f09b1f73dfc0b44fb5c0108a50f27aed46d36faf2911b6ee3bb6ccffb6dd44e887e2625e602a4f2cfde0904b77ae7933e4e68ca6a86850b0dacaebd9f1e2f4d54b506ad926abf4340a4d7ff808df6fd9b40121ba78e0ba200b286903a929d81471e31381e07dff25e31aa3107763c0b8a26d87cc6bad38fc01af16472e8a532f7906460d8f2d3230667cc76c6d80fd6e37b79709c3ad31aa0b79a6f9bdda008670e1bc651441766a23c8a05e1b02b1897d7b8a68bc6580d136365a85b7ffdccfb35b00b8a9179775c52fb8b7b0d46a9d983aa5fac07cf89756ccb1f078539f54a967166f14f7781f70fe209fe69d0c61d9c66c67e3f558daa0ced6de20f87e38784d287ab7e2f1f939e25de792548fc13cb88c51b77c423cd81b8498f7aa976f4270101c363ea590db1faa9280e41b146a60eb40b6913983a565cfe4b4bf6d4b9c7f3aee0db224d000de2bffba87087d432db11f71211f3e5df9da93d3e2a12d5c633ba97e5361a897c5ab4cb3c26905cefa4c09b31e2cdabef94d6eb7640b9acfe9306565cfe46c2e545104ef6c7e8045e7c1357c21325ec0d1da3451f2bd9d4e41eaedcbe1955b7c41367ee87a134388577dbce66b7fe91c4136375f6bb31e87a5ad77682207b15efb721f3638f8924600124f05288c9b3a21f78032152f6a6b48b395c0b3556e23ffdbe70333bd9d301c843b1d0a44df02d23bd7b03da298f3d107b09921f0e07f3b92425330bf69faafe3422dcc43afb1a12b2e090aeb13e4f5dd90c63a7668eba74ea5792f8831757c00998b5194148ca6a62c8e45b543c13e6d2b44c9f7d0f98248fdc82961026d9603fc25679e30154987ba6d50fedd5188045d9cc0d610343ea7931b347f765a12b05fb9934045033f1807749105d8db240872f4db5e2c06ebad2ffbcc2e26126ec42252d8fc129484a16f97a431553642834509733af9aad4b54586c898e4cd91ed9cf0673cc398950efe78623e0c20bccac83f71eeef0f8a763da94b08acd4f7a6502e643f40c777902ed33cc8a3f6b919af4aba0ef2b68fe5ee70f15ab743d67023e5ca13d659bd0f17a7358db4e5ae80455d5c017f6ed3f3971876bd9be56bf2a85c15926ce1e145fa11114756cf2ae51bf1f2e63444d6b204cbb8b03b89e393b88f5f958ba8af4b586cbc4c9be238e6aad69c4193742d6ce9291ce9ad0e261015b2a88c1c4e59304e75735aadbb48612f64ca373ca8411b10e37ddfa5c23fc5238e1c3b19970a2b5fa265cda612002c7c945ac466648062a0c1bf772d2becdf2259ed5a2f1de5bc4ae33eae24aff48e155e96c5ab4b113d825138cb70606501beffa4a15e5d74073a2db77bca2efed6e8a068be79d29e9353463c15c8559bbb0a8b2351d3c3b81c6a1908ecfae7173ebc18113f979168f7e9fb1550e56177949d618c58d3f126d68018a7c4c36c165afa010458e1a19148fcd4fcb87e2da44704fa4f3bab5c30145a4d07998ce5c354b49dcbe3d29a5a269d22d7d66deb35b42eb7a77eb363b0228c7b210452e64f9cfec0873e047127731cf34677bd0e9c838baa691761bd61abde0f109832dfaae5f27c34d6a06051486b7b77db726f29539232540ace0a630a2b5b63f498b596bb775badf09f6084db46f34663fa1385d4714c7b9036f469764c874e38e2faf78ff42729a963edd33f2d6b2022229a51ed0869ca6690d0d04c1ec520011b666cfacc9f9c1c1c3b7ae41871479be9487f327d7b57ef30398b89384476e8bb91dca1ef3387d11d218a349b03429e320803a40ec5530769d3df30397ea9ec35b20d153c16934191d98ee5f028663ce2548cc35d0efbf0ea520fdf0ecfa8e0e2d8f0cc3a12abe4f602244cee5cb185344278e4ce21211a38dc117834fc941c0c7c6bef5dad5c7e39db1652c0e619b82f9220f10c934bbf77ea7b2514ddd982f725fb43bc2ffd90ee2dcb47e9bd2fbd873bfb1d2e6169b175d7c491b46e2af3b6f7e6cb7f61de9878ca80489dc6330869b33d87236fb07870df7d67cff2e9f752c41d25510fefa7bc418197443f65c79d34776ddbbfe0b012163fd33d59bb6ddb865be81d0fcf99216e7dcae11390a87182dbd34ac3a68ff7dbbc62edbda00eee3bdaf6d3675ec9db0361c9db759fb217a7cfddb66ddbe44e28c40d62c211576cb105b087f7f73a6ccaa46b7b6b370e6fef9542ebae59caf2715670fb913622b44b49ccb6e6ba7d2802b891404a92225f0c7cb626410c5b802007d91757146104992c70b0c2050cbce80112b4a0527ce0a2a1b03d77e87aee6005122c5cb22c42f2446ec9b208899455a783f77ccedab2e240df52aed65ab17feeee95d659c35f407fe28f72fb277569730d5bfe5a6c23fcbd696d2bcf64cfbf2e94c91efdba9095bdfa75614cf6b6af0b61648ffbba70953dfb75214c5665aff475e14bf6bcaf0b532ed903bf2e6cc99ee9ebc29bbdd3d785a7ecddaf0b4dd96bf9ba10cc9ecbd7855ff6505f177ad94b7d2f5f1776d9537d5d68b307f3752197bdd5d7855bf6607c5d58b317e3b1be2ef4ecc97c5dd8d99bf9ba7066af35d3a2a99fca14b3363c830ed40a34df37d4f9787e94d24a316d91d2ed6b9dd551405531b8fef2638070fd37775fb5986a517edd2826929b099d9712d132ab2f85f36869aee1fdec479d486e1aa3b925c5a548485b9fe2e64ee0e2f6cfaffbfb32e8df9765bf6aeaa57c55ff99ecca385a08fad57bfee8fe94d66dabdb4b1cdd656fca292735d52a324b9e3dfba86b77d3aedd9614b79fc6a06df7a3905c393cde39aa90e7afb2ecb467c938fa42a96d72ceef580d6340923124a42c3d9182dada90690cabd5bdde1fa4c683d85793722621b9d73ae79c73942185c32bbd92c74f4c32652df64b09aefc71be7455e92fadb532a6a4c689156d146fd09e34d440739318ebc7dca93f772af6f976ea5f77c967f9cfcc3a65c72391dcc402155b77fdecc2f3bafb4a29e7fc666936c54879ba1b7b373fb8fd5248daf4cd143753dcf8a0c6dff88000518a6c000829638599fd63fe857e18ef591c13f332312ff3ac897fc4bc0ceb078c673d8c67d51a0d5cfb758993055c5974a48b3c73c8b2c8c816790723a8ec6084fb2678f148245f16c8026740ec83a6f53438c884b530ab9bc1ac6e06b3ba21f2a8339964fc8c909a6f59158408bf84ba81394aef2940e61242d60cc3d6d3fc8f99c77808fe1971c8bb207730164264a78559d347f8ad9fdffa9fc1425aff2f64e6c3dac5e3cca6973b3558bacb11d07d13166b3ecffc1f319ee669b010229ed7df04758078a4197c8f559a0959a52f95b08fd6d36021257ceb85c8f89927b22341560be18f7f56a9f5343f64063f919d1f345ff3357848eb6930ab8469f041f3180bc97157adbf43eee0e81270e963e027f3e58e0c5cf212eed1e27f2f77c050e6d61de28e32e97b1b4010cb16c1fb63e65b3f837fb486d0601cee32e116963b263cca1a11108fa5ff7e89f92505b4585b40560bfe320fc45f06b380f4b3f0cc0cf84258a56fbddc99c1acf9342f7740ec03ffcccf6021ac1266b5107eeb7fccfcff90d6fff80f3fc443667e0763d6c44f83870c011fe3fb3f688680d703c3074d263c7636fdcbe33044a1b08f184f0386a56781d8470c1fe16356e94788f1833f4f6f7a80ea1486d8745281e12964b15ac04ff33ff0fff889ba1e1e3ba33ec5327d8ca7f91bb258ab373dcccf67b1540ffecb97fe3e0e592b13fe1103d36016f83160304b855b88f134cf02f18f18341f3e7ed60bfe113efe103f0ebf61cba31ee0f2a59619646e7109679879e251ce9699670c2dca84a17d56685f82134be0c9bdff99f048249b7e965e3af8f369c0a720eed1a2e9f4a5f0fb1b8e1eaea11be439bd770a4b35f8ec7ece84ac39e79cb384470ce4d2cf70b4add0f43398059a300b047f060b7902621f334f8385e07017f8332f04dc99e1875f903b5e49e2202d5656963bca208db2fd69ebc784720746287770f8341149b52a09504e94a25028144ad51406068f44f244499a7d1caee2662ae5a1be460317f5f463b4b8281898944af5425e1ee5d4b75e857dd0d0a8706a4e0a5a87b57ebef45a1fce2009f2a872c495b58ffa71458353293c06c93327d31818f518e3b80bf5385a4a7fad295377869a28262da7934ca70cc6a3ecafc2710a8d32c89a0e59a80c65593465c9941b321330c7f631ef12c6bc3743160a8f4482568fe3309a8781791c0e83799a10e743e92e18cf92f9182f775a3f7e9e333298d5c23ffe1fad8f8187d07ceb311ef2c407cdb77e48f82f669c8c7188c35da96f8538ee4a3d4d88e32e98ff3035e66418d54f14ea67d8a3451814cce368160c663d0e6785f655e178736a944839f5a9d4cf9048f65621057950dec340a94279bfe55b212bf5e394ad302b8573d830c135fdcdf956bfe6d351ce685a3f811cf64f514f5533e8f412b42da6b0a79e26f5ad30f51fa61e26a44067d54b1c0de6001fe65121ccabc2514856a5469a51ef2002b815b62da2ba57955cde419eaac2a3ac65555086f954ea2dea671516ea5b307a14099fe65928cc6ae1bff53efe5b2166a14eff78855b58080d66a1708f22533683dc45ffa5bb508fc2234e9e6f23e8c678fc25bc90273e5a1fbe90273efe5b2fe4890f19ff4f83853cf141f32560212f7c88853cf1113e0d161243885b8f85c818a7ec4749f4a33c7ab94383553f4aa316c67197eae5cee37797ea670c8c8910c932d5a345d5c3843248a33c55ff1272d816e97025cb221d92e47116e950840785472119158e34a77e94443f7172eb5b44763e9c3b611886447668c2e9a3821097e65bdfa3080d6e61e9ae897178f7a8d093b925bce1388dc85428d3378560387adf79b8c3d257a83fbfce8914d32b1c3cefdedca3b294dc512209e997046ae8570d1b6ab458e5e4da478ddfdebd46769ceceefd9bb51656e4c936f390ca53915b67873d64a8912d7ee1e78eb216a4014d80eeebc7506590b5fc5776655c28b270b8638e01fa35d6d079cb51a1fe0eef041f5c58f7f2fbbaad84679176d5f7701a69f1c75db5fe093db8e3ca48bbead7b7b57e2de18beb0fc41179a33ffdc075e17166d77b9e9c19f47a4a2adb57c115c0d583df87f3311f53f3aaef8b898989514da479e4a556dff77d48dff77d156cc5e08ed3c7915a31b8d3c767b5f23e26f4bec529b36a71e2f083432c8b38002165f1c5a7e5180e70c007e49a08e535d30bf8f2792f251105f167163f0cc598989897a04a15d3a06d31d5443a623e7ccff33c55ea1be4f126e8799ee5c01c312f23a59c3eaa4d05e68879eebfd0c62402f2787dcee3e85438fe2ae78e01a34ce206d9ff2493a0616ef209a1ec93ce49f3c9d4a6eec658b264cf4103a2f68706945b3e4f56b11657e6ba7932262efd96a134cbb46ba6009298a66902bb3fc21205a99bf334815c9137a6dcfe0ca4e6b01e2cedf2286a8deba53241d91fe469a9954b41765d3e85216e4dad86d62e9f2e26ae9c123392251517c8324f4e094fdcfe31c7014b5a74160b4c80b2bfb300d4afce0ec423894717fe2c1461c1c79f851f169224657f1664fd7ac9fe2c2ce9975ca209a0eccf42109d0e009205f56b94542c7100130738e957a5c17480cc014bfa35ca28b35933a586e825558bd5f470c1cfb34cc48514fd2f0fa4f766b8e5140adb58f51cf15043aba119716b68996be1ea73554ab9a3d820fb4b589ec98c8484f51c4db9c1e18eb2762f0f2e782089220e4ea908f5f028a5f03122c5cf298914b2ec522cc9ee0501794c3c275230c91e508b3e7b36f6642d7aebe0f2fc19569f1fe9ea39029a228dd41075ed40eef7a01ea017d7fb51c2d0d97043f6dd90b5d8dfcfc0e50f869f161d06232d7ac3e0d3a27758661898f40b06188ab488420e77f46cc234ccaf148e528a22520a9f7c6f142320b57ef595232c4090b2004902d2050cb1262f2f7393d4fbc350a45f271f23fdfa812149bf4e5887cc321896c000d42f8a9ba0de1f0626fd6235f698b4e8ef2d9161e97679b270886b0987fa157343091c140d85593f548f7ad48b91c3583e500ff3303f5243509f7ab9837a223b13f5e3057bd89bb96ba65a5a5c6a475e2416f3a91dcd192486574d96efa1bef95e92c3503f7ff2fc8ce449e96724499ecdbc17eccd584979fe0b1e3da21ea429927af41cb98b8a965778d4ae9576485ea50da4d6af514e410272c5290fa47eb950c48a447da9971790e7ce15c873bf6e3568144b6963fa5a8396fd4f9b09f720b5e87fc31e2c3d4732556e6d56579f97cffa0bcc475f2607777b14a53f6eb1148ad60d66f5c1f8649eb8b53f266dfabd188be226b0a8926513588c009065135898e40aa3fbf44d373ae7349dde9b734e9134ca29bac8b216cbde7354a3f983d10303e4e9c1d2a22a8b59fe0d2a7794531c4d8114c3f241478e99b419abd00c93f5c97e8962167375c105d44b77398f0a4a74d4dfe836b76ddba48c69ac404ee9a03a6c8bb3e22b23333333e5fc36c9d6d773d2404515945cfa598a8e26a8a70e43e1991918ab150c8c419edbf198617e912930837ff1c5045550724bdf7d3fadbfe1e89e29983ccab0ca52b630cf40992f6cf11496c2164c7642ee150f2467c5e0cef729dd4d8d61345f4fd9e2fcafb586d8e22f648c2fcfbe12660f2a0cf54d07ee28a3a80589c9578d1352bc42be6a683d480e4b7dcd277bedc70999f74b4ab1f15891e47ef73c3459134721cb1b1e6b50a62df3627cdf12a933a54dbf8cafeb41cb15758b3c2514257c35337ec60c9087a3a20940ac485d2d326a1545117a8ebea3206e4d30c1041a0da001eaa03988b4f1afd18184bd601ea93b458d153c90909830f3645b5099695bb9d22fd30c8b294a1747c4b2632058808cf288224090801c01a901b9d2a2df28baa3acd520201a353e2a6f72b8433e947dac31eb7ec199a851518c5a33b83580b23fea533f7a403580bc469037ae01d42f54ceb31b4b5c290025ee588334936d91b2bf8d0dc85353e5e6e78e9e2c4b295f70cf91bbfc53d6de97973c8a20612fb82775a77c911d53c101a78606f2d45469d17b8e78b823cca706f381197199bbfcadd0f564d953c84013b99fd25278d47faaa7201965bfa2240348ad3c710364d2c6e702f5cb26fb7b4c1a16858a939c42f14072180a6729edf22949f966071e729661aa1fe51447b518c220ee6ad4a7de5937b8a9b067863da8b027c95ddeb8e7a8c59824d4c61a5af6a7dfa30cab5cbfc54c946729195cf125bcfda8efaf31b23981bb39926752274524753aabf209df09379fa4b4be8ae88e328a5acf11ad1d865927889ea31ea406c8a48e8a0749ea9cde3f4b99efff49293da8c116d92591114e8b27dce196eb46c3f66e3e0fe793fdb238287c37462e0f520c0a28803c5c0c00be09ea287de3f186121701decf921494d05c73ba9936d37b9e9ddeb314222afdaa6fd4affbfed94abf2ace44a7305369f1e22ce54433ad457f5398c1301bb528df5e8765234f85999689dc95672dee70bbef7b52007370991691c759b3ff8534ccecf9c8508570ba96fd3b907e0d5914e708a99cde079a4e7d5b9cbaa052f54505b38211c3929969d17cb87138868c126aec0cd1654247a386cd093738b23fca2c7b9e39ecc64f26aa926b194b92298ea264c92ea350c95ee48125799451ae64cfa38c72943d0a52f62849d97fabb4e7a8074bbf3a23d9a910ba3d9bccc0933262720a4a563545bf16536072ed8bfb9c927165defbc57ce306d7f3c95dc3cc9f0c63fb93a7b724cfc769247f2edb7ec9642985a4ce5057933aaa2cc75496b04fba52f4351b4b1d2f668d625315122a0de1ae26bb3d549a499d23a9a3a24627244fca18712bcba71f874bb2cd7f3e30fb0896aaa90651f2785a22cba61a647f1ac224491b2799069a4f4bb27f0d51442dfaeb7871fb4714914cf674bab8238a28053405799c31a2427926266d5c4776fbc719235af69f319aa9611fa9a3ca8e22ca3e93718d084fca10401277ac31d616d77facb1ecf6c33a644e7daeef620d1c0eeb902a649fd87fbb31e5caec9fcafeb6fef4073c19e4ca221faae4fe79c5bb0fa83fe748411e200f0be4ea74fa03e6f70af3c869fbdbaf2c3dcb593bede4388ee36aa972dcdb0770b766eebd7636734ff303b8fad4e2b9235760adc0e24163b15c3f572c2d53457fe92e6677aeaefc65fcdf57b5d64a25a5a1adb91f4767dfc29adfbd56fa8dc5f356fddabc66979f2292532228f241ca7dc0f68d2f8ffe5a9423cd75f2e061813aa9142b1ea9ac0fa0fe54bceab552f1675684840ba0a21e5650a9fb6084bbcc30a11ed02c151f5891c74fe80737e411c707b5eead521f1421512437a5947a08ae406319c89ec70b64fa8ea5e4415fe207f8016456520b191919191999ee362fb4d26567dbfad372d972145cc1e6effc56aefd6aa052a4d6062a843a0a5c6635e5a4ee33db03125638a14e4800b6176029cba21e4a800324900051274aa438913b370a50361063c1076a55be903d48410f412f18a20a124c8e6e52a7031250e050ad7454b8954e07d5ca8deebdc84b6c9765510f3e5809000b964082021b3401e58824274042104514a5204b111fa0229841877082225105169523f26e309d204977829f1b3924b02e23afecc5e1460f3aa4b8c8540b8f0b4fca18eb4fdede731fcfc1083746f3367b623a9b37db6f8de911d2667bfad3bf3dfda12fa03f5b6a436d2e5b0ba6474f65ba901bb99043e1422ee4426ffaef4b75868871956707354dea70bf6ddf4dc817bd428adb6f2d98ceee8ff6e2b14607a54e78b4a6edbae015eeb04f8ece1ca647d266fb138ea0b3a4a48eb54fbf3c233f9da45f326f20bf8200ee2dcdad1cdcd2fb95120fee2dae34b8a033d68f212ed2a826755ac22137b43cea85a030eb87cb10d4bbbcdc11d2f2a8166cddf564db36af49d7f676dbb66ddbb66ddbb62d07c78e1e2f04c931e26e6f57bfbd88336fa442223bf488ce286da3b35c7fbc3eed2047765dd7755de7799e47c548894b92f592581981bbc23bc27647918a2cab7e9c7efbfdd504a62e281355fc7c5ed8eff7215312da3dcff33ccfc3f032e141eea7f68b1bb9dffe9c9ee8adbcf74ad86209833bb3ccb308d9620e8f385b75ec92fbaa80f04e40e276de4fead5efceafe10c18f8199c043946dc91ce2811a551235aa3475ef39a1f399227d118f5f19807491d7ffa1ef312c817ad98fe04b320df6a131226e9aad6996b8d2261a174f9e7b4b86e5081dc455f46a61b664956fde7febd0872589df96ae2f1d6990cc5dbac45040742daf8534a931c460329c6c4654eb2bb7b0dca5edb8170992ff1228f9fd75aab0321759aa707f51a6bd1a1dc20d2c6dfae9a7bb73fb664b73fbe64b73fc264f720ba854dbab75c57abd459a5b5e844b31a8259aa461bfc29ed78589ef04c5a4873c395eeeaa7f14c1a0d072eab76f7f347177a2f926c70d8a4c9499b575adcf0685d68d2f0acd9e043429336fbab4c239a4c9ab8895d49a27731f79855a6118dc60bee7c1c706f59f6c52d64594c838ffafe34b82077de5ddcd3c0fd0c2ec89ded1d0b11b2c2c99cd7973b746723b25343223b3638acf5c3fd8c19e124cd4912ee04b42749702f99e4712ee1384e28735fb21cedc992ccbd02fad5f190b91d3267adb539fd92b413042173af42bf4ac8dcd7d0067771f3c75d2eee71340088ee2893f2fc06c00dae0d3e4930fafedc0ec7f5f72842df7fceea90d759e4ec9928ee688566a4b8a31ddb869d63851c6685ae5006e26ad9ab9594508ed49943b3ec442b5af6e7ace82f0009eb2da4cbbf3d86a404956b983ff37cda595a74f74ea888992866a4b8fe6fe53656c19332c6d36d4741dad41f698b08b794475aeadc5f763b1c26258e0d5352fd9c9f8e6db4583b7feffda459d2d5f4edfffb0e3bf6bec34f29d8a3c8e7dd704bb8c3fd230e8eb4a94fc381add6df30abfbd2734f6bad5f6badd5ce9a0c3b1a164fca18b75aadda98475276ff1060fbb19303f0f99ded4750051f9c9d986dcb63c764370522ae0e36d926db803627dbd026c568a3b2c936a1cd886db6116db49a0e8cac18e9a0419e1e74c906b4c9a05cff7193e56e1bb96f3fa5430ea3814467548cfa35fba8a9155aa347743652bfc68ef55163e917854177a48fdcdd6352e7a957c326dc6fa18fddd9de86453890b3b3bd8fdde1a8e4915239ca43211da244e1151a826bbbeea933611eb661a3f438e8564a582cddc5613a94c73edab0f4fef1843cf6111d72571120dcf6c11d6b910611b7e66df192021177b491b7f7ba7923c41db758cf6dbb34aed22e157733da68f346957ebdc8b6df921c46dfdebb7a2e96b7bf3f7f7aefc3dff3def1f5f13d8885f87ff86e3469d31ac20d3723afd68e3723776db4ba516e11e1cef7c2edbb9574df277813c41d3b48878c3c3770592bb06c8b5fb6f3bd886d31876db4d5b644121fc8253cded047d8402d6e9badb1bc7d953ca67ad01a87d4996f646bf7688594379a94b7ae92695de4edb3846d4d48d7f6566eb58d266db6bf51d222c255b5887063f4f097e00c43f24824b37270555adc7e7e91c30ddccd68a3b5b83d8d19dcde5ebe20d1a0a54528cf9fe1c19db972678d8a3bf68fd4a9797e27b94652c787c877d77c2f74e7da364e4e0987466b5aa5d1ba76a9f41f1ef2c4c7101924865aad7f1cc6f2c9f2ee7d78dfbd7f87853cf1ee4b9ef74476bec7e27effd8e0ae1933f1e0f2c420cbef3e4bffb84be6ae190a71a7cf71fed46eff8c0f6effcc0fae909090909cf3a74520617267fe48e9f24bf174f796596b51b608d976a93253e58eb37b5a7279fadf65bacda7d2c336fc5aa48f82cf1de52c16933aa5223e4b648a7a0aba7debb0475d19f777f2307d7d22d9dddae738e724912cef7b38f6957cdf86a304f2bd61f7a7b0f4a650b6e88d53966ab1f350f0b952babb944f5d22492ceff49d558bc56219483281a6932428990e511a3485aa4b1bfa2595d0810a8541a6524a49658884a481e46e5586ab16e96f61096ea56f4212aefc0bd425e179275ca12101e0792928b9325a4c81c995d27573e4e6c8cd919b2337476668d97f66abd5a75dfedeeeeef333447fa4fed23b16b81c491b370d19310d350c92b4f1d590c320ad8850442b9a4c92d451998666689e8527658c357e327d6fce39533018a92c0303d7d28ca7e79c73fa0ac68b0a66868fc36060d4cc5df7aeb0f49a83b499d567decc97336833aab869c834d42f234cb3af32493368fd72f9f933aacc90396c45e4337c6618e957e9e7cf983f23899c8d38e26986cf29cb90c9583273980c1c64f060650091276a264303529caf0a637c21c5f92f610c24f8cc1b3192e64d0e318e90e7cf4f85318e626069713e2a8c8114c6c8d2e21c710c13612a440ec3abd1fe154d785ce18c2fe218cefc52888b601fecb9b7f29741c7461cfbe4898bb438dd318eb598d4458bdd333199a416a74c529ef3659264ba98f36b5015aa43ee4f6952677b23d9dd578fa363c2eb2e7f18a19c3f968ce4f9311d0bf2c4395a7973b982a6c03494296ad62efaf4561f50c74cde46972b321d51b34cb91f61b60883a40d5d11c924b5485fc78b5b6b84a40d7d9d2eae4cd27c5a23547f9c816399fe0c1fa993caf467fcd018923aaa3048ea704f659232a54233b986e3aac64faa5b66605ba4c2795e66b6fdeaf1bb593ecc8f2bd8eac7ebf22345a55ee6b015ee2077f9e3eb47481befd9bcf1afb578a5c5ee80b27fcb77401d932ee8258dd640af3995d12514a899f48bce7270c4a7b2539685bda4456f1ca4cbdf9b87ec0e446b408a5f48d1df259c4890a27fcfe68d99346f8e903a476809e7d1c4226ba21d2cb4e8f7c3ee787c91c335fab5d8ad0fcc9ed3536e222a2dfad39a2806923b36918c8888ca3aa154773a7894fa69e6f57bb4c58903ea28e5d651cad505dfe6f47ef76f2127877add2a4779c61c50472953504729ebe0b8d56a03754c0b76bf479b524ae994d6d4a08efa5d71632b6d4e39668f221bd8c0d4114a9bf9a1b4b19d8ece412da863b664d9813a2807eab8b7051d5c09742197401d3353efc4337679fed8d1f7befebeeffba6b4260aeab0b82467a99dd68db32553fd0d57d60aa57102d931913abb291e7d8f86373edcf932266d64cf9063263b6e9c8388cf15a8a0efb4ab894e3f71208f69036f0d92bb7ded544fa7c779f673b7a72f4ec0703c6119aa50be7f4f9745b76af2fcbbf9b932546ecd28773cd6a0596794823ca50f12eb49ea419a1cc853fa7b3f0525dde0373dd1d34c0ae2d3afed67eec1d22fd993a5a78b7ec92045fa35710fd266da7a927aba08126bd1bf7fef6f2843157a567fa52d8622709c37a7f75ef705f1f1ac37bda9006e00e2d102b40c56a1b0fbae95524a29cd46609e1db9a5ed65a84235b41aa3f0da59baf100ebc70babffe577502921ac1fa857bd0a0f61356eb27ad4ab1ef5722795e7a70a334cb80af3ac03f0bd57c1ef842b20988346e6817480598bbe84947cc29591726d92ac15668cc563c672e3185af49fb9732a0c12c56d6bef5dbd28daafbf07c11de595a4ec2d1ced4c6d92408e3a00fe3048d95f1545920bbd03a4e62e7fd592eba51e853311f803f5f4ca4bbf9272ad274bc382201539aa463211d842dd79c12d0ddcbafd3c0dee8b50f6643d4750b24bc952da4563c604977aaf72a3427bed4c2eb1683ec16d7a93a4070b0fa4da9e109eec7493e47a42b0908407120f242a496a161e493cba88b16084455948b2840a132a41549c5011a20225fbd3aac3c5279b4e271e591af340e2e19ede54e3045843bb325c667582b65afd83d763623a6d8f235223d463b264a314476f3287a1308c2cfb732d15467643895bbf960021a9d3ef9f80a12d1395debb17e499c9f2bd1494dcd34bd0f4a93007adfb20e0bbd71ae72092dd939702935646210477945194649e2f0ede118ead76a80e4079228f72e65181b2c4132851a6dc529645505c60e55ea1a11c402d66560ba22b544407849024c444072e868482c8610b9f2d7eaed091235d1633af8824f06091804a4564f1c37161d415d183239b10862c8e7dc248c5c9c1b19163e42e69718aa8c10fb5d77e778b2177495bc40b8c607154440a7cb0002a020809164445f8704408b1e6b8d256a9e3e0d8c85161c61dc982491659f0e015c9220359c46ec062081cc0620b19606145c7040b28bcc0a2099c2c99d02207b4227b5770451114225c66965c9ff60b054b7df0a428fb0a82a0e2f6f522ccacddc244bbbb9bae54b044767b83b692c7546e192129723fed4ec192dc29487a1b2c454247c048c136c51b9d813cff7dfaf49942a6a2bbbcfb4192a11d4a7d468362eb46d0483c1a13d098e0963a2582fb49970609ee482912d856a9ff0863c3d55a8ab1cdb141022eb8adc47a9184a04b33458de2ae6cd0c57d5141698b9b020157c5f5b22c42810f1e1614e0b07d71c123949070bf2cba27b7a3a21be27656381b5c5bc5aa608922ee9665d1131b7826b85c96454f664f86b6adabd45bce701860070b56ecb684bd56b4b7f4413ce1438b4a104d10444766a6d45a41c84007992664334134f98105c5904c10497c888942c652420410c0a8421403f258253b50b2a2920443090d400073839f9592263255133518253f40bcdca0a6baa249ca09da4b076e976591ac96479c291e70594228d5020fb4d080504420b9472e40ec70324095580b0ff6bbbbbba1f07197b5321f1cc02866272e3cf04d1132e15820ac30e2e1e4e0d8c8c98191831688288e949e307aa2f601c184914e07419ea5c562b10d5819646bfbadb56f6d78ed8ff6b3f81611b54bd2acd1adb54b161dbde884338014409d10483603d0902c8e05e2c80e152707c7468e911323289cc5c9a284da6bbfab84358012f6b77be5c70d4044542d0e0e7a704236ebc1c8e807284672f0433bc4b191a342d73835218e88c8a3b54637264b268e74b046e06eb8a620944e705da028f9705335d8a0b897059d066e15f238c0e488eb65c984154a2ced7e593261c511ab81db65c98415459a30514517435c54964c5471c50c7e50e2a20a1c507155593251851145b85b964c54d1028e04d70439dc52964c5401b4a1e0d22c99a862899d794593251357dc608952ab9135591bf7d9affb6628a548221b3900d903bf19cac81e4864ce39c5f34ceefddb56375ca7fbb7c232fbaebc4bb673574da19a423585947de2dc7b73afeeabb7978aeeeefe77e53873dadb2b7777c7a3bfd8d3dddda59527d3cc0e663bad9b69e32cc8c28e10dcf99b3d759f77258fd6dd2dfee072a5d2aa7a5fd7ed7097a4d113f7a33c422785bc6307c5e3e7e8bcc307f7e2add26eabb424679b1cefb092522b613b24ad524b4da7d3d6e4cef770c7775b2815716e4ecbc9c52dceec7339a1daae5e94d451224e2e853b2e4dbd48f93b5aa43bfaefc9b4432696bd66d9ec0a3f7bf59bdba55c01a44d5873099995637af69ba14c6afc6860e598998eac16e68ec86a61eee0e82a0d36d750f3953f7f622b3d726aa4ec8cd900ce6e771b2e7a77535a719204dc25dff4cd90b5c2fc949ddf0c6df6ae6cd972ce79e7cc3dace7f2bd6497d06617ea02b224ee51b1cc3ee46c87621794b747450dd5f30ad66e63d912b8d076c7ea21524ae9a525ef132a80b411c2d24628d7d0f9fb64bf6452239316bfe290e51ac416e58f5b3876d9c3b104d67a2f7d9956aad35a4d3d726aa46c920bca5f56234fbda8589036f26d4c2a4a1bf9326ba5fd9a5422f56baa66aabaed6aaa783ebdfd47eaeeeed4eb2866a9fa46560f9b5b684d95d1ce55bb3491a917fdd1dde9479d526c5194baf8b7c2d24229a594522aa594525eea5e4f9b9b2848f3c30f3f34e09b18892c697ca0f1008d07683c70e7734f93e4ceb74f93c413e58c7e291929e5cb9f927ae9a39452ea811fa594522a3ff497e001bc866a29e5b85126d91a34afdbd738b16d55523979f56be9a4d49b6609a5d4be648d1332a688565ab797af5f5d75aedb5ce6c4558a95ea0045e9d672c39e70dbe6c453dad4a695d62d884ab71f4c99f6b0d1dac3466b0fb5a6c0156af64a371e74d8a80e558723b43140f35e105e82eea48955b5d1fac3b6fd50e9f6c3121baddb0fdb0f95feb004adb46e956e3fd43aa5582f909d565ab7252add7ed8b696aefa2ea14bae3f2190fd279dd2a66e7ee9122e271badb46e9ced4ab6049a6ecb0b4cca49bb9a06042e94c75cc17069a15e89ab265030be29612e2f5b5ab24bd8127e908ff9649e52c75ffa64b15832a7ebf232c7256c097be72ab9f3c7297ba1fd924ee74cab01fdf23f62a5234dc8f2b18475cc7672052387728a9422cbff41965f0009eba08eb9c7fa551d84b19191d3ec906ad17caff35519f938707678173660e22046ee0c65e0700c1b968090169be6e7259c3ebe83c23386e486bd3323d092e63d2a5ede4b70a7c49d65312145aa0257a0d9a3a101794c4fd3c5b03628c0fb7cbcd0c2289dc8f27b489d0e46bbc9f26de48d49933af6af8c3c85a89c4ea79309acf295b0aaab9c11cde8c50a51e1846aaa8751931d1ec6200ff7b8cae02460c3aa906964f92e79630ad5c0594da32af3a67fe47207b564a1611dd44156a851956e4655aae47e979630a7098e0c1932b6547b597e276f4ca3d9afee67373ba87f5a4ab094d29a1a90877ecd0c9dede57f527458cbe33cc74da379d3ff20dd3a66748de8ec02e6a8d9710779e0b66c79f9de0de54e8b4bd812813cef0de74ec5d973d1895b6e58744d50a5502e2f34539b1084dab41249c68a9ef090e7a8429e2f2860ce62b19891f976d6272a4db5916bad555af1b94145b9feaa044c72fd174b8044ae8f638225b97e4ebf649109b6c8f57128916b2d3ac116b916394122d75aca336c3245f66f6bab0ca8bdab3b6f8e104e2e68128294c5e20919227e0023411099fe8a045a64faa8878194d274a136882822b7c542842cd3a77f2d92124c7c9260c244a67fd2e21bc11399ee20d3215490e99bee16320699529b452a258222dc11e0c04357f28b243e80f2c654144041c8fd5704508090e4fed2ca065fbc7426d0426045082c110a4cdc0938b8020440f0f41232a0596a755aa2280201073ee024f7d3dba334eaeedfe1a3bbbb291414534a7fb491c54cdf5e1764faab9f4c7b4025d3a2252ac8b4e80346321582874c738e108277670471945be58427658c2eb56cfd732921119dcda27428b06e2e02e9b23e8b99373a037ee4b07eb77fa9f099d491525c2cfd403c7a2ddb9fd1c1e5fe6604b7be149793b42cf38cd11d7d56f32b3387bdbc45d11c26771c0b90bd77da0d3b90a97667963bf66f86b815bbacc597d089bc95e43e9336f65b46b848b28811f741eac8fe49010be4ab7b4bdf7ee3a07330a3982eeb17f7b6b990cd83099b3227ecaf74700d20210721db97b30a284f64fb2d0309b3c15d2a98376692d948a412358062955c1158fb0dd268e2cef71a4440fd1270b8f6ad5d4206347fd4ffe867f5403dcb05b98362fdf812808a208aedbcd8d4e3dba2b58f7279d6c53f52a977c12cd68f9747fd0b66b5a030ebe2e82b8496506cd1fe4b88e32efba9507cd3566f88a345fba87087bbecbb84d667d265df84478badb53f651b946d9bb2ed4bdb531beadb9f49ec4b0903acd6f3389354e9b99b64f882c33a236a5fba0d2795b3dda5566a141153468bf476776ff9137de9371fb8fe5ffaeee97b5d284b383eb384c91d2a373c5e49bf93aff9953e8ebbe873a1745778e5ae6e08ee10def4b95286b27c23b2446589c70b64296d743c29634cb588703fd3b488702bccd6a7c02ad3ea4cea98f2cbc7ed3bad138955e58ed75aed97700bb9cb5f08f75d0f65afb84a69d13da607a804ad9556454c199a1100000000b314002030140e08c582d16030cb1349f13d14000c7da6487a561a8bd3244751983286184200210010000020325043b4018c0f58006069b7f5681341a15507ed5c4750d5fdc46fda86218da9d6d378c9a6ccd1530461e85b913471aa077bb1becb7a0f02d3a4a2425c0dec7311fde01ab3cc8756bf877d3f069020048d8fd86e581e47d6927c29ce8a491d400fe3e21d540213116c00b940e9628904b4256b74159b79d59a5c1445d044110bb4dc02d8af8801285f6162cf65c8d71e09dabc420c44389a4aaf313815ac8789d626128ef3126112c07892d0e13ed17123260508ddac8ff740c99918b0017a590ede49683688405c23942d06bd0006a8002a2c30f01515093fd6815bd97c0435ff4dc6c46dfcce71c529a12b5d4bc9e84280066ef719a34e097404bcaa8a94408b3586bb5953634f137de1494f7bd93af997655f34e3ee69c0e36dd9333a75e990e841ab09b1f109bbc42d040f4603ae998616d10977f8a2e38d6502b6143f842c50a5563515ee9a4f6933dd70c550927864719fc0010a4d519e556f691c250b4cabbefb31108fc54d0d43e6b17804e54a54cf81b361dc79a2cc8e0bc302e568e68aeeb49ee9803e72df69d48c93f96959f6ecf9656cba64a3542f4776398a61a5c615095620a5bfccf21dd3649b1a12d9c07f6506852a5e46781d0235b13b84be4e9437ab7f98e948944da2401824a263b7236022c274a35e6111517f100e3a2f72ff07882e87b02abd73483a30cb2528e62e1247ba340d822993a422457cabd863958bc1e91246ed9283c69fd75add5c0a5502052aadb6cacf286ea0b8a221473fdc6e5fef1903811091dd1810764e857adfd177c6a1aa9cb62de1d67306b544978816f98bb33616487c22b662cb0111b348aa686ec50fbb500b68436a90bcd04080ae3b1807211720ffa7a061575eb7bb70b0527eb96766d75ea102287ba8518e3eb3242f5176b84e55db20a58aeed861405ba9af5d2148144cef8a9bf1b32739192a05c002b0485527072fd4e7293eeadc26ca903b51d4c9e7f1496f5ae6457551ea945cfa58c848175818bace80c8dae4ddee487418d3e7111345587603b824354cf71652e3c513f6046770fe3776c7ad1a59f6f001ae2c76a3d4d7c3f9a0c0486de681500921c0e09ce456102ac2c3f9b080926a217808373e87fb762f60225b61bca67056e3558c7ecae79cc64ac13ca1cb103b3cde58e3d8184ec8927528491027f336e6a6f75bd3f2d64a0cb80ac0a54a18892b0a6a778903500681ec58c5002d5f00f6155140cb1088bd451c50191562771903a44c71a4908c9d82b08aafb450ffdac089189ba81cf9d624cca60b0f5f6b0abb6985c3cfdacadd641cf8ac5f583747ee455102161d0bc6697903b2574b33b322034a2234b3a200a2fcce46f69b4e54b3e51ae745b3a902fadaede5f7de08f804e7101b0a2b4bf503770fdf30b46b8b27df2f02cd4614509905087bf6e893569348de8ab3c8974be506f9c0f274904cd8e2c9771079067b2b1cbcac219a36af0882a9af72579a0b9b38a3ec0f4e078c94bdb9bda14498e473ae1d67b0a7bc8f4b5fe28b4b9b4e69c3bd346f3ec0dd3371191773c5c43504ef71363a6c56ae7bdffa2414ce6bc44884a209f848f395b3ddebe91068624cbb190276aac08d7884e2e74ae2388bc9c68135365ee680d4ddfcfff6be749004353717814a23f9e0d5ce0b80250e28e42e16db6b641ec5d18b0e62bf0f37d4da6e00d2d1586e8a51900cea04468e53e277edfe311ca240d8de062bcd89c04cf6c55a3672554fef75b7c1fc008eb8f6a358e354e1e829430967c22f4dbe058353c1884353ce24a15b4efa531385700f821b0cf091e653150a94a353fca16fdec6a9af31288dc84374d278397de82174410cf612a3e750b96f6f649836274c474e5a333108dd0d75b773746ddd002f067903e84a206fba65f9d8fef5858f3c714b3b5ceddbc9c445194d359cef9c859d1fda047da2371afa89bbbb653f6aff9a17296e01f45d960dd73fef30136a13ee49ef4310c0bbd93f934d5d7385d82ac03bfdfb3ffc888b2ac8270bb0bcab89502f47a145c7a914a2b1f92643ed8d7edb032bdaa997168128ab232a30ca182c5ba370110e9c14bf857bfaf7b4a895526f82e9567a9320a9b60b739635ca24a64540c02839b6f50b85254d4bfc7d8ed2d2afcbe991f527cd8d7d79fc42525bf60f2921bda49d3faa175a7853d748db82af76c9451ba5fecb20a7f952e8df1c7794bc6cace4d36e6df326579e228e5d702abd32ec93f5c7527fe21193d8aa25282c215fa54773bedd48f201904800efe9f951b263a25767671cca6c746762c6b3dfa3bf34a67e9a0d786fbf8fce28083f3783be7c2e1bf01ebd39ba410832dddcc47bd2d03ae467a92ab1f59dbd0faa2ad71ec27f76e70afc0936ed2dd389db80e06efd80a73f7383069e234eca4bce08ffde8ad254fd09855d36f8048aef1f57e3119d70d472aa6f96be7e286cc5dcb60911d6c2598a0ae3289eb77e32eefa9f8fae899251669be66a6601932cdacaf9702902706303a7468b8864624d63a4ac4d6e046b0041e08a5c8380a3faed02926ccccc9c0851dc7cdbc491635681c3f9776b7cd10f701a0c98f63e2b9797a9ccb80f7b7eacb8152ad2d77554afed3005034be47c35a7947c6c94cdc72dd0eb7824b9b7a4103756816bf1cbf33a90180e615f4b000b18368eb1bd323a1f0ea16cb88fb17577d4ffeda2701211c97b81c15ffe0503434c7b9c4ed60d66d518351a06e3da22ee37c1cc219dd67706fd29a5ad127454a883c77d36c75f44eed50c20cae63db1376603b9a416b54d18545a9f8e8627f7de53a61cf89642873c2069793cb93f44d0169ce530b1b722f87f28d8354b1b510bb35fa8ab0de074cfffa8e7e5e30afdb125f22a685ec36acee7bdc1718f49bb96efa2c856627d6819d754fd10acc0e0e86ceefe6251056dc271b5de4f49deba376e228c8c69456fc1bb28668e691a51f985e54b94d6281af5c80e17adb30632ddf035a4ba6db02900152b33713cd5874cc5c920c8ae734fbfbeb2ba7ec290b894d3999e1b3447250822f81dbc0a1ff8e471591f234a3b80e7e2725233077aef9a5129ace43ca62fd2a364ecea94640ea5c0bf84bb851fdbd032b53b3d343206ab100288c031ebf937a57d37855d0ea6953416573f84182e45c851ad0c3d71449cd14d72fa988f17738d2d828ae9a4ed973cd9c9635066818b213938407d56fedfb61ed023f0f22e69eaaf09b62f7e0b677cbe54d8d5693538c59daab93dcd705617e8319ad18a13b98f90f64e9042634a632bc2a86e1176dc5d0d9a43d9f371fe3b5efce1ab0374e4cdffabce56949952acceae19e2d863e2263ce19ddab93f04147256bfeec1e87d4374aa8f83a2ca74d6c9832252532a681c07f9cdf736a35fa225163a6d8fd1849fbe4afd156fd9988dde35c829c90ff9128b0fe4c593d059254e940705e53728995478b17d95c85c70647bee82c71b6612d40a6bdd9b52615d91e1be2978c21a126e293f710cbec5bcda0a248d66e2117fcf421b9109097f78ad7eaf44b3a81edb228a321cc72ac1597fc32976940fc19aab9920384f8db32280f3b0f2a27a62176658c74027f090bc922cf3d9b39c0aa31b3a3d8050043297ea0168dd95d46edb4cd815f3999b7e12bb4849b654b9df8da4bb7ad5bd03bd765fc167c425cff115169dced3700158c5dc5da7e120eb55ae9b1beb93adfdb908c98b133d581cf8037cfc913445fd7144fc2ebdd7cb0037c7e9b356854f6577aa352fda1960986218a7a746aa042cc7ca261cd9897f361cb047c331b0e213e78ddc55a2099ee48fedab931d8c789714c38877505499645f696e9132db7327822e1f763ab1bc51f3cb6076ad0c410d4d6b450e403133ee2a6df338ded6edd6d332aeaa02cd9df02e1f637eb67517d5bbd6026ce85affeb0f8dd8a39eb353a45af6551eef5d9b9117e0be6f840c7b840ff9bab7e72cf3d2956aa26c853cd8854dbf11c0d7643e95b118077ccff4700c4dde15cbbc40ef266e021f288295107af41e03d2df6a555017ceb1dcaca93de1eb93da7eb336450aa8d14c19bd3d0b1ca3b7cc51292ec58ebb0ab0969e763188b2d50cfa31199303549d45b1162c6abe58186db8778b7279b02031bb6d1c6785f1e61285d8b754f4db709204b6bf6e88e84ad15e13147ac707149d197010901882689ab4c11fa3f065e25ec8c3eb00b08656a98b49112570c8c5843cfccc63d0f7b61979dcdc8f1be2c14fe71bfa8e577b0154f87920cc7251d0d53f62834bfaf9e7ee3491e90e145a950ae4d63c1401916098f0eb8fc3c4e92f69fda6e630041c06bacf495596df6ce03c7e7c36cd18c7fe69f4c6882382638b6a705286ddfab1bb74f961d131896e0229a65bf41204733792a67e24a912cb1719b1e58c8d5185214b4da6644b4f31cf7e2606feb667c66bbdd518b48175d3d2c3d1aef8229bd91d8a0f00f17b08d712a6a2c5f996d6862310cc612444523fdd623311f07970284888d9a61cc697b87d72d8ca66c3162d5d023ba160252fbb571a108248dfa647d26f6c86fdcac1524e009539b6143c40f138aba2492a1f338790d869773ab175429ec243b8c28e4d1a71a103f9721ef0891737407cce1de33e62890793f8cf66bdfccddf132791bca21a1745a4caf4f30b67441fa8cd16c78e6e6c7ca8f088f5a4b73d8a39ac6164a9542b16142059a394ef8338915465a8bc19ee720a9f2fd0768939b076d073a161b7cf50679b4a3990c3e393a7d1f7c60d714f354e4fdf0eecb2964018d0eb490af9d28b65ae558e2895262168175cebc5116b7b3157f3399229dd239dfa15f78182f17e5e7b65e4d218e9bcdcc1f6e949229603a397010c8dbcde9835e62c90063d041491243d168e04e0636003fbca694f1ed7a6b0ba23410f604fb68194d54331570f0280a5205e472c96e86b81fadb030098c815d49512a952631eeb0eadb378b5f3aab21ce16bc62ffb05dafedddce6aa5aa003bb824a927427d7bdf9a119a73bd57a6551c721f3b6420d0ab8925e744909c5d204f3ed258e208be43c96675d0196cc9d326c33a2412866ba9b003edbf9625b11c0241503eee7180a076223ca36358dd184df8f8c93e52bbb55518b7fb02f95a96556588a89e02ee1469d54f40fb694e324b7f405f945eeb2143e3c040b4b1acb4119179ac415ce33993d9f9e5bda0408f7afd44d63abe145da0124172e792e2ab89fc614f69fe698546bea13b4634e9b02c28f3e1b40aee9614483794d55aaffe76ab9f9a131767c20ee4bfed08f54d742ffcf5e0fcf33ba51496ff992e4acd0400ab83ae5ada101b1cf75fe54c3c83fa7a0002602a2fa53401159f34b2aca8d74453bf6054350216402924a2c187bea80e5860e5bc5da1127a7190f78cbf2ad6a083e8e903a873fbb5a85bad2d2d09398a40b34a929a95643d69c01904dfad1daf45b05711fd6a321a92edd8ef0cb1d391ec155ef363ae7ae929dae22682bb9b8885c8dbc3a550176753add7af7817860534f50824b35a6b7bae74cdf3a7a0bddc2e21722c709fb1d860595c7ec874103fb6975632d6b92451c52359fc14e2cf5008cfba4de4b9a81b9762564c896f71380ec7f328b00b133af8b694b1158025e12cac7866086eb3ea78cc21dc2bddbc11f84e76c029768feb27947664d0b0e8f6e717449e5b4b9b0ca11590e30d2923cc9a3e6dce7d5bd5f5fa9ab4d7ef8cab576685df8be9912be5b7048026b1fa132125197e988ba60dfb26a5efc4741ef4c84121fac8184dd335c3e72af182118d915f2e583ec4181c8e79ce70635f6cbdc9c150331041564f4bd2152d8fb1bf52fb06a5b0109dae8bdc28b49656aab8ffac714503e4563a25d72f153958a969361362f56d8c0b20ecfd88f825e093132d6019b851c23ec0087bd31fac7d58311ba041be71550c76488b67991c0f7d2cd02920a1a2ea43b25a9a7c33b2a67984480088bbbfb661a1a22be40ea8278bac04ad70c3ce6777e840eff83dbbcb9bd4268892bb4f403fb6f43283e19190ff911eb31086d388d6b9d5f7a0e36e906e891f9eb7c46b9d19a26d8d8b04541cc0adc0f85714432b64118c36074f51429f7709c25973f65f7b6dde65abe33d331b2dbfab471132c07280c6b395803afefe95b79c8acb2069295219bd16056a978a1b4056aa6ecfebee43fb99a8724daca8a34730e51b3ae40acc05d13d62b3e564f31779cd8114ff67ef880f90265a4037196cb4ea458c3c4dedaac4505bbc20007fa2c0d58526390032f21a8ef647ab2cee8e053cf1ed4a08ea313c93804c415799e8777e874deddb8feadd14fe8e2642ca0a558bb81b70dc9c53355381459d046e16886079671dc06b22113ed92329103308401e60415c0463b13e09479aa947de329c7a0482c26147b4b44c7b1fd535308269a505706e5e7c34001ba2ec7cc5a76012021868e53cfc53555fc54ae6bd12e3ccada661531fce74e22d6730f72960dfe6a2549c9b99852a3a3e0bc12055a7986016591bded7153c43df16fb48fb74162be2f43a052514e74e88a4ca788bd501d35f7075f3ad8742d7495db69404cb7ae45b75485b4e6f2a6223ef270ff703d2267929835b388ffb07a628e1fdcad5dc3bf536cbbd21407e4bf38c467f730609c29a2325b6bfedc715b6e479224870e3e0cc9f7a6667217b0ca3b350eb49f3ec7c2e0442f9f4b90248b1a2e99638e4f3d964456b8cc2439793d94740111c96dda5eefaed101b7f6a2b1a6b214915da55e5d66e2622545f5832740fa70621704e0ee9c3c570683d02666c2ab2f7f720582a509c0e47755033f2195506a240101c1a0b6e4de9ade24b80e46bb2bb4f15630595c22d73c89905cbc6c26bc3246550112fb95877492627b330be1517b8e9d50e6bbe92968b5811f3268f65f513108382550978b448cf603554b0877c0d44f93469ef043e84c422c1228043ec1cb1a8584e395f438c522576c8898e15c08f139c5e0a294a888b84e7ce3ac5999869f650637b1472b90461ad7a974b9d6edae1ab4b91c9a65e6278ad397fb3e39743cc4777d5531bd9355505cec77121028f9a5cf9359e550d6ae7ae608f0548bc2d2b1868e16c55299d440cef6dde2374bbf0ba46e7d04ee29becf7b723090bbd29d50c85bb8c7652a4af0525ee750bcf5803bd65f393e75d4b47d80e3d3e6f2346f4ab4a517504e7db3a5db3f513bfdbd1871852667d075e49228b374023d4b4f13c0164eb8053dcb180aefa42b6c727a9c0367b4afe049a1b3062ae984ae226734e88b301bb6213ea7b0587094bf835be56f14d5be81e7491edc12b8c72ac99319ff151dca3c321c4b41de748e244dc7dacf35450d0c1b41116c6466ad44a85680592bd9ee5a4f654f6e4c445a400844b8c2803a7f7c609a7d8ae9dbd2a3db50a71b647eb35992443315f2951b1885bae769ed2819e660aa22218f16b5cc89b62e629d6d9d7fb2afd68d1068e8ecfa7c8388b1903e2a50c5207e8d3dbcb0f9bd073f189ea888fb2b8de2a41460e5c2338220700e45a4dfbb602723673c0133aeb65cc8c48d07d84a8a1f2bf21396a146c4c8c0a3063cd24d8ec12363d0202f1e4b0f0da3f69c2a1d46ed8e035752e87559986e00f63c377e15ef24d2df6920f96238df4363f6ae6b86bdccaecae783791f787d9e08d36dd3dd182fcc8e1641779f2b6e4ad7fe89b60c01afb24ce95a9470111b87d5e8ee18c106b2024bc489bbb028645c6fb23665d044b092610bfcfbb354dc08c09100fa238ad3d9640facea5e51fcedb5ffb0f0f1ff882ebbd9c8c117de1a68a96c663e1ed5a18db5d152b2eddc70a8e1eb1669cbadf436250b364e0736db8fe9d1df80a2c7bc04322c6da978dd4d7ae55daf49e38dedf3f842936121fa32f8eec3b30a998da3ee3973db00aa607ea669504218e19b94f012ea7b690cd87398204bb93b42d3e7b0d6261ba9b0630ba920fdebf71d6f5636ccd397c614836c7c66a894a872dbf22002cc99bf184a5d0add5beced8ac15eab7676916acd84f597f3941c7dc0b89ec2bece60d9de91c5c279f015673df0be264ca6a4f775ddf3e5c65fa5e232dd74edd791ad7b4ae531d9f3986f4942bd5c5724994c7cca2e583b89598f4e947144fc7fcce9447ab29abd2d8ded946238dfa1a4bf336201d0f3df3464086364b4fa0686e3585a10881f55fcb84b5840cba413b16c006c69b1fa44403c1d6854ebbc0570b81a0b424504229c5073c6e6df81b5aad49815d4417ee91994784e3a78b044f97cccc0d8aad2d265a63161abaac2092861fc0d366fabff3d9337d3b589ae3c6f36471d6736127a61acc4d40268bf8bcbe150ccbcb6c55d433ff4a29c562a635675f353dec999dcada8acfc9f0fb4de2070e8bf28aba3bbf8ecec04864fe487fe7c65f820f595bd9e27bc3a4407eb45fd04fe6e521447dbfc29babf084575005c753bda17af366f3619fd975bd0b4cb478aed973c0ac7f55fbd39b9fa870d4924a0943fb97aeb41b0bfdf7399c9fbbaaf1a011c0f90b8efca97f01230e7da5c8076b7f561c7f0eefa3b1fb96da2786be56a028cfa9ab8398ff1f40d2e947cc32402a5f479e775351ef0b450e6d48321e61945893ce090c60807586c9eed9d824289f2843fc97255cbba04e4e6eaac52eb26efa432c45ed96218b83a1e04fde382beee80862482b2a633fe50a0aec9733c0dc0fdf038a743f1a1531ed13c080fe49738d169ab8d4c484e8e68c53854e8976358eefdd8dcc1d9c270d24a9203a003958b55bd474734c8eabcc553c78331160501539f4915c4e75d80bd45a2fd4911b3041b1182bb86a42d8507055773a7d7f87a9b3e48038fb875c7b5cfdc76120c9ce522ec2abec27630b7cfd2f55ffd0eb57270e3933ce958566edb1d35ae41708a16c1420b30451e44373a1af7c1dad9004545f474781dbefc6d214a72fe058d80588b6b97ac7c2165f31802a0a98fcd6328592b728551b080414cead34325b68fe7e0205f2a11a404121c3f6b76b988d83b49fd0b1b3658ed5e4f68699d8764cd43ec2184ff61a7aa770b165bb38ac439f01cd58716415e4e74a7a3bc983b71b493ee2229c6eb8f99897881eef693b7333647b4ab918a42660e5c67eb622b81e332275896039a7cd8c0b6a4cb6dc7f26c1239d9e8f2f0ed3425acddca7d812bfb11504c34e92a3c3d9b5662048a348721b023a71f3341db92b7982a8fca00ff96bce32f282693524c7292898a4a0e3384aee1396512eede26784cd3b6fc241d55033cc5829e0b6422c06db4b3c92ccbe706a074443a587c9daf6ad06e5fa9c8bb6ef8f8e59d3a5e2c9e3f6ecaaddf09f284d5a21ba2cb7bad612b7c3681cc9249fbe086c8c5c3aa3db7691043e2f5a2ca0be2520f09dcd941f82bda99fbc6bc4dec8185da93c4d2989af2ffcf60122269e59ec05ddb2ad4b3b7e69ebe4513fb3961ed199861ee3372ee17972fa257b4267b68bf27aa90d5727799c81d16c94c45ce6f72bb62db9e3433788921a49dff5095f7b4486847987a6ae67dab03bc356f230aa0d39dcf3a51433a701a324ed7a72c9cdf39c8f6bb54cbb2d82a33379bc0546d12b65d8a917eaf674d4d96f4934d69a96e77c59a7d8aa0f18d43a3975318e79174f57d2cc7fecc51de5a182852f09d46087c279875bf2c60da33f43e3ce6a47f0b68be8f38071711f9445cd37af5092dea466191f0e83e43e66905b7f0a04930e02cbe26a8ab04ab388050933275c1c53c4d1e12d0c52b842e9c4baea7e4fb7f718da01217136c9784f0695980537820d5b29c07f207173c8f3a17230a3b21708a4e08f166eef94b2770f01e686abc8a2662065869a0fb7bc077ff52be60aa38cb78380040d4e25ec7261316564c8a30f85076c50ff8630bdb9e07b9df694a268ce1cbb6d5d4ff423ba3ca57179f002716a7a3ba3b4d0f9afa3259ab40958118c99db4b87bc99145bd56594be54d7a6e2b14a831f26377e125614f0724ee42284dbca4ba891b3c680333323a311d0e7210714820321839e58a90daf00ad60937d8325741c44eb96827f3adc5ddcb806976aee1919946909f3ec005aa86d59b133918b6261eb1a4efa8fd03ce1283b61967eda2bea5be072e8a137a472b54e9f68f8881b1f57fde67488a6a45aad44e375fb9a90b5dc58a6ca02e7b3768b0b9ad819411152b6de189451e76528676fd2b152b70bce756b8270d313011159fd12f907bdef1cef2212c3a114c3421f659c2b0e27b8b1dc1306508cf6d4d5bd43ff74f8b6a2cba95d0ad1f3650ac059538f4d078c7a7776ada0f75347354660831c600fdd89d0261784754b7dc472af8fb1280227247b0c58f030f5c452cebab26f0b31dc7a09f3326538a645a22f466644643f08c1a6c6d9439e2bf0e496480270707fd9817548e7f15625ffe2ffd4370488ad6665d1cd3b55f0ea08175608f2a4c3118ec1cdb7980e4fc85315d49b783d25437f911df8b948724054d377a0a549d68bb6a3d28a42cc3b30bb1ad2c77294e020272275107c197b5e3fce910283afa3097de480b8450d744b24206882c7ed3b774d9063c174becb286f7a9cb567ebc236161efd8985235d34ae25949c88b7a6540eff1acc3061b6426793c2d2d9fe42a0d2116257039e325462e5a12508bd7ecdefc0ff6e32a450ea45adf96347dd610609acc9d09f61a4ac21db027ddb48ecc44ba4b4b306e6e03a4074682352ffe93d12735aadc3b014b7ab7a345cc529061c5d326a97f55318631202b064821e20faca88467b1a0b9b54bc1fb435b6d2d31b3ab54dd4cf7854948434fbeea2374bdcd37d8552e61f3ff8888b7c53996eb5e84513a8cabd9b34024edfc79c8f99e52a402a1d8912de38318b9ad1eb1552c8c95ba9689064ec1c714a1953d954ab0f18c31b18d416ac616b8682b5e0c98cf14ba64b297d087adf74236ff29bef87ce0b1d0432a3c81c4e685e2df7e4c46639954723abb3fb488c2aac78c581fbe48f2c32ebd6783e72fac1470bf0bc3cce41bb0b133925ca5175ea9baf8d6b64ca1e419838d475a246b4d0acc07c1fc51326a206e26090ea51b8a04b31f18809b2b46888d5a6b3b6066d32ad837b88f248df179a6c3808a230cf28822a911c11b6d2ddc9134ddd551ee08fb3a43181cc1470dd5582c7070e52bd8cd8425fe7480fc901ba76ef6730448fe0cd824ca0a74efad0f8d4420c9101289cdb48a246ee88f9d9df14a3e030a4330463bca90f1b6336f17135dd50cfeb6e9cd65a4dd608b6de7d7859abff6c5c63487fd3151744acf50ab1b72eba2ac65f22872548476c3b6c128269824c6032162d0ae46eabf087ba5290b383a7bb72037b54d347130634aa625dd6648870cc0585a25dd8a0167e89234c95923220c5e9411135e24c2e39a9991eb6e0165d914290af9210781f8bc133320c4d9abe26fa491f9243beb5b04b29b3f81ac1a7142a982628c8b570a1858a9f80978c3a52946c37b4d9be800d7fcd185e3ce59dafa5ff027b3d9f6428123f390b8ec77f9b1f0bae1c0419b1a8f0c032f250624dbba61408db092381630e4a043b4a47aed704fce3a59c74c1a33822a3c890a41b8a6c2cdf6a9663c545a2473344d90f5025af71b5cd801cd9726276a3e5da7909ae77695f8d18412180a40c98b0e3098766b7a582a577494c33d3734e156acccd9f06950755f06468b36136b1e13925f1d074b545149aac9b25ef125d2f70cf47f81e733c4fdcde218d08054aeecb264dde3f1657be2d6bab3ceb3376cfc9b98269dd3e01404bc1e907011f8890990f8eb5ca1386b79097aec48fe370525d2c6aa6b4bf3beea90ff2cdc54f10cdd566c082e93a2c7c19cc5534a4fdcde47382f6255c84ecb138a3234083a5d7830c8cf5c54248e3fc729fc3e84f0f3244df494e2f40adea8e2da5cebe670ec98561a07c93175a4fe924d360f4edd5b711582ca447403db33b7f089c9e7e177c47680e262a6de1f8aa26c804d3821ff44110878894173dbde7517056cf58711547b19cbffad612d85eab1c5e0a98b68189b6f1f8704a1c76cb0220a7bfba17120b98f517108381b40aa592ecd436d5233b653c8a03de51a00f7cb164dab42009a3c4ac35030376d4bb35027be95637f9f66b135f49029695966c6c3243fbefb819fb4d5ac8903e76c26ce19e89525774790615216f33f38fb56cc6b81f1c8f882c8332b48996d78d02ea5d4d5c4a3487ea7e711845a50aef0c86c410d932b985fde669f918bdccca572aaf6bfbcfadd6d29814e071a450eff99684d2bd3a6d4d756a94792c3bf4f3b4f41c5caf4f50aa151f26bf344cb14ba69b29ded698f9f4410dacc6ac7e25775d835c0b0d2e07c7528ce199bf224af630407c76857288ecaf714cac37197aea74e9a52d891c489d148cc39d0750b020af9b515f291dede25d356870b3484c7e5b2076a25614949784cb64f27f0766280ad76bce4da0816225642125859eaad811e563009a50e009276900b689dd450fdd5fa9171a080e2864894ead60ba9be13f4586182bc29485cc23fd13dcf0bd8f4e5d5541b6b479c1ef4c34cf32ae6f2cb10e97bd7d1b1154fe2827cc95540356fe7c57e1d88e4f632ba49ce4aa5bc29276f6eb638c0c04d07cf113717b1445dc8917f7471f1b0e4e41a7c97e26a3e2784a2ded6bd9bc705510afbdfc36cc60e74f8b3ea5271b4fdf34c9dfd6c62130feebec238a8a3b43c858a87353d2d1d9e58d271db0666f492530a72afbf64c82046182e39c7e8f3a2954227a1f5398ef79d46e23e721c6c1d85b73e72cbdd5386b37b1c0be0e71b942d91701c8b1bc2bcf2bc24b17ebd8eb883fea163e5d4c8baa4a45ebf3cf1b767b17816ef4b11e147b42173d9bf96a28ca9026d48f756df1f1b3296cc4291fd4fbc9738fa47214dc1a1fc2d887401f0031fc700491196c03f3242c21e108dabef433c2840113fda35a25ab347790345ddc996f481278c1ce700c7c28551e6bbba415cdcc23411a93a46e7c02f7ebe5eca29d623529b0cc0196a769f4f4c91299815dc47a6f13b62122cc9c45893a1e8f664f7af0291b5446ce2c72c92bf097272eba39ea976f06bc7ac1a2e9d927bd898c2208264f2aae4b458b98e547e86d6e45d7420716c87db722685d6c9e974cab0b38f983dcbd4765652d57ac85f51335c6469c284fc48322d793052be8fe580d093a07352a164128f291be0e677ef212cd3f847cedf2834f619665fed38d3098d5d522c88691cce5a495742db41378b5b229a0d79eb8fee76488cee2d47bb0ffb9c672c5b18dd9394c7b6a40bb82eec61cbc0b01fdb4a21c99ff8b1a8d278e05b6ffccd2d49cb31092c88daf85e7877701b27668211a72e1f0c2218e366bf76fb77ce2205c6ad410707dab2edc604d76cf7cf988c37ad2e268dff4ca0af24ef3ff934db86932d7b81de1402803cac05a19427d3fbad7309bb195deceb36f3852f5578f06901434773e3710b26cf10e3554dc2d1fed28d5b35da988171364c6b9ae03ff3346342b58daaa02fca85075233d1ece0a33832585343421029a7dafa7cd09914116852d6bc3b3a3b6a7258445859e0b3955ec5c245309ebd0a5a05e7fc56383132e3cec162c4331e411b81df0d4c616f94e90c8cd946c8c40edf1ab67f8b4095911407c5973e16254dc24d3f80e774570ed30f9266c2494f1c37ff0c0bd05c05e0929412c3e063060b08c719b3c78a0a8a87b4a4a33edc023753a091d286b8651fdc0d9f65de7f00c37b92e1f18a3d55e0a63a624d859d0a9298956f3dca8104d789cdbd0c67fce256b4193795c848c552b5228aa61ca44ead4afccd2005252ae28d2da8981618b48a495cdc4e57f1d8d822e97e2cf7333bf673bbc697b2bf7996dde830aac5300f343dde4bc2634ae12aa1285cdd5ca5cbc7adcb3a6e3a950476eae0acd053ed405b5b19aee99810d55e769e0e538185d4bf10582bab7b6715ed32cb4a3985bb4e21c0e1b15e3ffe57cfd4785d3eada310061efc06fc0b212ce26ef931bb81eccf08b3d2e92aee9ecf8d174ed15c3dc7fbcd11609f0ca8d0a0a82c301f612fb22f5894ac20688a4ed1cc00bd3e93319d3bbe4b4dd0f018533a1dba06c1306d4e16d463d7a0757cd1bff2614641f1ece28a0ce2ec9b8f3f88cb5feba607e519dcdfc84e0fe38ecd9d585c7c19f2bf3b1de79fc4363102884f6169994eca8d671eb8359e0a206449f0c21467287d2b6855f466d96a25991f095008f99ecf3b79fbf682cd360677e76bfb6a193088eac40b55ec7ed10d418bcdf74eb41e15198f0bc4a6adaad0ccf06ad9bcb5c8e4625daf3d2e5f5dcf51c020da324cb0c6c9fc13be0d14844f38da99408660875118a996cc2e14de330c41bf5e9cc7310f9e13e5d0d40690e79edf7e4b0ba223619bfcd7beeb505255ba33a6fef3c80098d82c109f2aaf97f5c55d1a4378e6453311c0918114829d545d464be3b419ee3611462e6997793102337784663cfe948740cf4aad28c2b408a8956ae64a1e992450ed931c6e7963ef32d22ea906d326e70c07912f617b454f66944538a3e251817278c44961910430109a0dac2ebc1a806e151d3d157016aa490bdc76cd5bf383fe74fcefd15941bb0d30b29c5a715a338a230dcc4714ceb8973399e871eaeb69b05e97a2f95e64b9a313b65b3873793130bc58548e80ca8e31300afdbfce4483fddd6e45e4c6c670ba11981fd9a2215ae01436fbecd4b6367e4da26a820c33006171ee4d86600eca1516ee3e14ee9b5e6f15a802aaedcd7ae6523dedaf6224e6234d9095e3ea914dd93910e672994de12d279149ca83ffb67df67502ac723d9544d68e72d50f69bf7911b4d5633738e2f697f980f02472ac32a37814910c628cbb294ffbe1d64fdd7da7ace79f69753c8709934aa2809cf0f2d20442ff0a3f3e2483f47f4d65ec5d054bd03dfa2e8b40c8b867f645e6df586344f5ddeea81d287ee54ee7d8f6ce51a315598ba53c7cd667594faea585c548bd8e2e7bb009577ee5ae81dd03d03eacba373b9c1cd529100760f601db3d70c16e64f3e5e6e928f839e487b3089723fea3e65881e312346b120259c47394b179f74449d53239c33ecd454518bbaac4b0495640584d77545c5f478c3609db8837340248b6cd95aa238e1e27399f56c0ce0755793aaf019d943c876413233d017858e544bfbaa9e913f8bb2232d1c8fbc01903c282aacedc4ea787d82ab016266a11409432351a1d3820166325e2085fba8f5e06eef8125590648ad138fd06b0fa0df58a2a636ee62071a39d4591c452cf5483c423649a4ca80ccafb3998409da56efb9f9e6c89774f4d41e742f4344729f304ad4a3ee9cf11dc655b543d56715628a37bdebe325b6d857521a913701c1b00a56fde2d0c477eb280d3bcf7b940e718eebacf32de8b637b5f97d9320d47186d9cf49ce91c574442ba86d273d07ee60b4a2d8b682d351f721269565392035b878bc91f4eb058dfb577ed1c09986d5fbd136f255b74e7f5b4bd78ae475b6a735a4a75fa7ab654393156562630f9f5df05ced26ee208f5f02a2b3e31bbee73c99a1a93f1fe93047a8974e08453736873c5c61ba879334a2de32f7a1cbbee14f9826e4920bb797ac7d67962df72938cb25960e232f3293d96c14fd0e123d158da6bceac37d104697f41932f81396226f191f919f6f6997d7fd73f60ad5ae60498cc6d48e840046de04fe5173885c1e1132b5b40145a1aa523ae1431768315c4e754b5146537b1f031957a0ab409293118d4fdd424ee3107b6897fbcda0ea1554059834848cef503ea23df8fd422ab062f10f14b4d004c6843bdfc98dc0bbfb92398ace29a3101cc1deac54770ba89a95ce32f1abf973950c4d3b6dbafe699cc9b008218517f8980bf482fc19b7199089ed89678969a9f532e50ab3460cd7ff8c945b8f960bac6098ca3b4e44e0c7d94b3571c869189522806f430e0c31bc558e6eb0bf1924ac6e4be75b8dead6849fa7d87377cfda02686f930f67cb400a2d92a19fc3d1d74a7987d79afec004dce023256601dcf389a31639a727cbeb43d47f2471f40c415d27af27077ec47cf6f0097133eb8db9ab2895ea51bc3d5292fb66b828eba38968262a18acdba2ded3f0a29a38daa603f4ae4158f19c5854a69c030e0f8d4f4313f81498dfa30e545d815ddb7f5b50af96e339c8ce0425da997a8cd6b7e5bb5caa3df8947c582f2c3d2b753f037bd48784a5465057b1e3bfcac3b3f2e264e3cada2f82f9b31c5020482e4bdf5f96ea23cc3012b15297bb37fce57db873e540d172b6d2427e24f30dbcbba8dffa6bd500bb5e8f681fff226e9ad43eb9612fb6b71ddb2abca31286d9aacda5f4f337f57c9704566da969b9ab1d4308788b1065528e6926465b364a69476dd861caf517080317b61010f4d07d96e748c1d17bb174ef4f660725743e8f913a64ab1921ba980d5f65e630ee985a6c71aae344b12bf8498d93131df11cbc0d0f4fb3adf9841d92a1df52b67c9b27349f3fab3ddae85988507781543bb653c99506090585d647a1cd9374050e1262e9536cdc8247b79551e21a30bad46af83904fa11b3db065abecaaeb45064a586e576bd000f0a3bd8095d92676634a7dc3790bc8d57160a96ebf64831795e12c7655c62edffa4506e4c121e5e7787bf4460f7e7e3d56173f699ede9886265cafa7afb3c41b6a2b78ed1bef983780aee87e6b95295eab58c9cb113aa86a507a234faba7405397971cd912964539cfac31c19519de2f3e704c3ee652c24f51f1e1a9c6146c2b115cefac5a8156ac20c34380562b84369a34990e5ebcdc2394d82dbdd139bf4cb3146fac34faf0ce2befa7b6a50417af8763e0eb6b223154acb23c02a018d7182a5b2448f062c2114fe9b69311f57aa78b2485fd8f8067bb3a4d5de4254a3d2145c77b5b0d67dc58d22d6d7560c6c44120f14b355a951805b22927f20c3ef69b7e9660f4de9bba747e3a79eb3839e2c0252cda83edeac07d99bfb2b587ecb27ca663378736aace4afbc90edde5f90c0a29b530ecb3a353cdba472b2c42d5412f90edf7fbe31edc0d45dfb41e91a563ee7ef60284d8159386d7014c9239c6bddc7daea2c8290a16f809880780348e9bf495ce1fabd1e505762984029a4cc1a567905ecaaac00e1a1fe15cf19c82ad1cf43ef58114150b3e6dde4b2ca8f341cc968ff1b0ae998d03451ba5a2d7f480563c18edd134458488e4ac888b82d784e18de8a8729d2574492d887404ebcfbc7274935092687771ac279e15db64ea09e8bf4bbf3106ea2117b9549f2753b885b42a061cf3aed4b030ae5091dbc99ddb4a4019cedb6cf875ce4ba72fd45742c5aab41270be858eb6864fd2c1b452f6e31c654607b428d0e43d4087839735649d82d2b428eb93471965acddd1d403aa631dfcfb90895d7d6943f393b0282e5a41246d011a4f1b938a1a12fa945d88493d0a3fd4ef7cbbd63a9ed05e54889d056df592b9d8fec2f73bac5f96a26f1bf3a28413260244dd7832d04c94d6b54266edf21c8961102965e31c19a09cd236d7f023d8a6da2612687ce4135613c3611d60612289ddd4a9361676781201a9dcf86173f5ca0f37a081b6ff292269b319359fc02aa4b2b9dd276ac4a32f95a254d226cdadbbf1ef7750f49803f186946108c90215b431131bb29c34d2abdd5bd06bf12d97152a295d00dbcfcd07d0f881958b15787200701574605850ffd505b6d5b09b1e68fcb8d25c3eb1b14431546b58190079dc0f41002cdfc75cf0f3f9ab30535515efc93bf47b20a50cf7fabb19b3031e7b377fbc15b056ba293b302a427a5620ed91f971dcfe1b537549131103813c4f8d83a45cd504e8d27538bc29d938ff9712f7cf38a5431e4a2cbbf1bd3427b686355ddb5bbd2044857632fcf50ff2d4b4649ab0f1037cd01b396beb786fb7af8ed3e9ed458eb96f5a4257d842a6ea54d7156e77c9f418e1e4fd9f43d48d2d70fe288a0e010f4d8bca9615302fac56c4926085ea5a460105b5b4bcefcbda9787f8127022d053c240ac657d03c424dde90c1fec2e7fbaf682f7f21597ba18357363fe3b25e9a460321980a6c980bb7670c332e2bbc49366251ff64bfbf15c80c220a1a1d9e239092ead4067eaba84497c4fe1eb7c20d66e803a271afd25afdb86bcfe3bfd5dee7f0cb7133816c5ed19aa6398472f496d450996021a6bfd814f0c4933a9dc30f3c835360557f4f815ed2f7ed03354918d6a89d44b3bdf958870dfa94ca920e2d4b547d52460a8583392961b3579b04f72a5da13d6b7a9605b78d7e53cf1830e21dcf9883eb4a41f7a09ee0120c9bb8bd43e2d0d6e0be2d567fcb35c484f2ff0c360d1baba6d2d28e664145f7a308ba9e516ef54dc76d47296745968f48fc1d7ac932da43058b1aca518092412ab84892648db03b0d1f1d36de362cffafbdebffa79056b6466ac00c1e0e0dbe3cde4a6515f39c969792142204d0a703af2b05442e07b88966ba023abfdc2fd0d64ba7ea943dcf37f8471b9ab0fed0816efbd2f77b321e4e4f4ea43193ef9d7264880869bef1786f58f52d17d80e3737ef1bda9a19f9c0e204589a7efb796ee0d0b8e6b0d1cf6dcbffaac4fe49c8f80337e82236760e580d0aa88c577fa589e50d521135edfdcf60627b372c4b573a5075aaf8ddf5c1bc82d5c4a31321be90a07a3b0a55eba71a77cdfdb5fa80e52544172138bf2ee1e5a2e7e79552780eb965f683347558d8882aca3ae15cb255c04495787cef7c23f0a8f7b43c1ba1d8ede6ba5df21d2efb3cf42772c7222b0a74522521d2eba805e6aaf5ac6bed2972cb7dadbe8dd05a57664d58866f2ca513d5ca5a328874cb5636ddd7980b5f21e3ea7fe395d1a3a1cba00802dee74ef70709c6deb2073d76cf76f3200837947831a644396c2234f46869586699c17c87a98a45d62e9a59bda417b82e67764e34af509cb8a9cd221acb8777a3dc13098c564ef33a3026711e819fb4b3493a0a134ad615513da2e966463b1df4e2bbe6a1cd3955b32be88a58347d87689609a6aad00d6e4368bb7f59fd4c610ca8047e41fb686b9810ad5e4efd0a24b48f63a0089d7b3389cdf0f3b9b2c3041d8704ca46fab2edee6fde20263d668683d0927bd1205626c27ae43c55626206d2d44277a7d55f5b48ab5c4271ae9479dd8e9ca5fdb2d215f66253ba8d9582bded8c4c6dbf222c9ec1a7ecf50472c12e89c22d8ac23ecad805f552178997fcfd671630cb2034a903b4e972a777255dbb6a9101912596180e1aab64dc07809f9952af5062986212dced7877364dad1cfb29a67f94756cfb2ac898cd072c67771311a974304b8d8cad5765d50d74d3090b005bd16c4a0028832b8885cec1c28f2eddc946eb7b69e4027bfbe0b821081ae325bb571bb083488f6016250de3be2904a9e8cb0a606c27ffa366ad93df3c329bb60fb95ed0162bdbc3368aa469e058600318727900b0121bb9d3d5a8ccf6838f0d102bff16b4cd0c1fb49423b13732e9db6b51e3c42eb39b4eeb19ec35765646f8acd252d703202c08bc02e3590fae9af79fbc029375a8ddb73e262794e6ec197ab0ccf24281f687f170133d68799472def59751d958b2661daeaf4003cd485062ba9646aad2bbe4b58fd294526f4be95fe8466dc6b8f0af9d6e88834fb7842093bdebe9c4cf47f01096132602ebeb82b49d2259f10c42b2fae62f1b5e96aa6b56fae5b2e8e5c91cc2c6c304240e1f4337091a4522018347555713148bc17194f7824e597984279af901eea8bd0154e20f0058f5f112049d29ff8daa305ae92b0298e6cbab6120dc0bff790d30f197cb383356dc3d02c38873a809d17bcac46b5acd5dde402e6a0889cf3ff78030f0711c1fbd78d0576a01ec1d3bcdca6611eac3031542b7eb5ff6829fca85e4325ff9aad19270fc1f9582fc0bbb713f7bc6b3bb6ce7394158f550a245680b37330d6be4766bc1632d0f272ceaea227b021108085acee18eb49a911ff5261acd4814255e5e688d7e51e470996eaa85f146c60d2ab4d0abb9ecfb58e79e8bcf1d9c9b3e05c10b93b632e9c6b53740b0426c3a44de6002060b54de65d86940294c33b96910dba089fadac1b55002d7fc980907246f76353ee2e74e3f69dea6756addda0a807495c57d46da15bce2d23cb82c02dfd24fab0dcc59ac8769b7edc1d3a9a6ef2e8b007631e1853523061626e0daa78cecf0438988fc35ab06e1ec0ee97ea2fad185dabd6302ae0795a862fcd44f01380fe18964cb6093faf16745267db806ffe234ed82edf4094ad551eeda10c8bf1bdee80076223f4175428b9a4250546b2c2591679bcc25ecb2504539c9811b33ccd0cb0140ec9c3c7fa72060304b0e7d606fa49be9bcc39021167452e3f22cb5c2d0f368d4bea976083400812e4fc0e3a2277a27167a2ea885edd107a5c2a50f1852542d68183d91aa23291421f5a5620399df757b8cd4c0af98a7b459b9d9d593f884d9fc0cb55179ba9282992cac43e6e3821fa4a82d718518a94979ec5a627db6a6870da25da330901c1b88af7578879ea57426e71091b9614b55ce2c8df5ce126de5503ff7ec64c76bf2828a8c340a6c465daa863c719a0f6df289b7a807d0c767c99b84f85818c5913ee23f13da00834f8958b904e77254dd45936529f8890681813c8b0252e2392750acd07aabec90205eb6a46b0aa83c90023083066271c2c512e8fe04a8941002a8a6c2c0c05fd2c35d20650308d2f4e3ab3e8a3162cf4e810ea77aa2c256e075c1e65f0ad37e7c8445428104ba1fc0dd6fcef5c240a3ef2b1795bb70d9a407baa8539767fcbb95253c0ad6e95a30d73ccd752ace0413dcf5e25ffe6789c8f0d8037315f1f8aff25299ded5b4804d097d21378ac88543fa20e6f209cab9db2d3b2eb46163d65c4a366b81fc58b24b40eefc59825a351ea546e2b11aa3af35698ea05cc1134cdadd118db7de148ef88d21d87a659efcf2c8231af51f04463ed34595895420d034bcae25deeddce40ea7b2ec478c35b8dcedd5c2ad99857506a3a19437c84f6a1c4cd604e99c83de14bbaa31f56f4b9cc5b7b2a712520aff06d72388ae38a57ae0cccf6644604b0fc476afc30f159fca169580af7a1bc702288b23693588fd7a04c676bbc14e9a082d941d9edefc81940ce28c9c4f24389c7a348bb9d5a2ecb5c838d2492dc19c87d11928b9261ed35009611b3258c8ddcd1cbeaa4c52e41f3543e5a3758c91de8ecb3598d2f0fe5a9357d6e0a89ae0fd7699cc42d274fca3051154ae516f845c58b130543e883a1e79d11a2b24a228c2e461ce4a7a59c8f0e14e9b33ffec6b787793f3b58552a5cdc6e3f73e43734df340fa94e5fb244d109767bead51887e3531380f464f24a134b8e9c8e9959a4acbd1ede384c3ac773190759b4b689c23967b4aec329ae498af8f1a1dfafac8b1e9c8ce84d02e163025a6f42cd152a5eea37e56814c7536175448072f36508dccf4bcafb84e7ad91e4156d36b92972efb6dfe65ae3a8c8241b425734e21b987130c4b130f01e0763de38f5aa4ab465b002f4f1eb3445397df7e7eba40f5633c0ffab75e56c40e4501037d066260e62b880789cb52aaaa029556790e16a89c1b37eaa70e02de77fd7079cb03fb9477dc1a1623785895777b93966037208c39d8c20808f042dc8de218e2d0655a64fba71b44082ed7d5822152d459ce148eac8522dbdce1938da9381c17ada130edd7ef4bee10584c89f1aec3df9e373aa4b81c44736f6132a995b2e8ec1d4f9846bf2cda4c2ac4726774ba50ee4f546ad152d97f104ebbe439f5519649b609b2769576715c0f93436aee6b5a4dea6a1861073ef5eb1715788749ae8a6102e5c97c97373ecf76b94138accbfe3c2f4f8077ccb3ad6c528ab7a2816b7a6bf86e0e934061b8fb2ec73e10f15bcd62c05159aaca17e097c05d3e29cc3a35bbe30b10daeac28ab9df28a39d464f07d9beb7550597a251042bbe8d082cc711231cc20107a731b57dc321c412dedbe9069e79536eb5bc031b0e28dc78facd97fa8174b31510ce47484d2353afa24e230abccb0f7e4b36d55fc316e452c71a45276e861002900340caadb69519c83280de88034853bd8bbb893d1766520dc605bbe020ab1199deba51ec997d8fce5e7052be09b5459c04bf884db2d6f029b1cfd479d36146753bf9d4ba681b957509a9f062ccf47c63e56f3214f360e6b3ca16e141ece512deb80500582787b3d221aa53df50fddf359858b65a834f7e6d4af650b1fa1c89e247ad867bb9b07d1044d09c1a092389f1de579b42090439e0b1cab51b4dc1d8fdc5bf89ba396fdfb93c8812b9a29cfb5e4ebf2c397a3e317c2fa01c6c552924f09103c834eb19d1e5256c9c3fabc61f094065622793498a04428a2e69982e8a8cd791e7770e2a4b23b698001f862377869bc1c42f4b01478d1c15e7991d295e2d0b30b6ef8bc405aa29b7ac4818e0eebf8597aa060d7a42200c732712c75f880000c512ad138ea9a8f72e20d0ca2e75b79a1ac5d9a53ac292fa970dba48521f3f9637915f8c880a099938f86b193b84e86a9bd5ce177c8092d62e3165fcd4bc52900517c007d352f98d1b71249c69621cf86dd765b2998f98fe67e16c08e5581a8207b314cb563d7f60a62d7dc70e7adea17691f54790cdfa8066444444578e2a98ca4616538a7be67c9008e640ce4aa18b9fda9512b7bebb96c69102320dd0a464a32dfa4524e4dc968edcd78a1ca1678bac09b5c7385c6553f7e310a3def7e921945a56049b40e35e2555570b1992d4ac5d1e85593b2b50dc66bb2e7ce360d825518e557e84a13d13162206a87c75f4fafeb1151369c58f4c306f61f5470d3991aa2361d8c0358735d0a49030d465c5ccf8d978edec6bb198d286b8bbb384ecf8477b78eae9544ed71499e3813c67daee0ede79b10db8bd06c1f2bda7e423f3b8b335f5885dff27a777a89827e85bc1098ce6b1bb9c3ee35e31dc328f68a9dc9501098b355b2a274105391f41b5e97e6f6e92790a384b17964cddccb5e5f907a97787d62d55c09e7bf8c37f1904a1160b653c8dcaa539930aed8e2ee20d1971bfb3d359cc40a4a332df16dc09963d6611e2e9c03e307e74c725ceb272a222825de6d0777c0266844f13b0652c736b5e404143cdea75c047ba2fdfd5cb7d3804b3f16e4717aee5e17a20d5c224ba38d9e0975857f3eb5702df56933ccf63062bc335a72cd3e1e821c0d0c319bcb154272af4188cfefd761e949f5ce4c9f71b5da2570f2694a132cab7d439306db0d2c1d983e9257329be9d91a5c2d048d6044fb2a4621e37e7ffbbe37e63122a6e90151981b4a2aca6f82d7cf1d208a7b64b5f8a2870954664df34d36052890f50dd6d62e66dc242314d2ff94a395f32063b58a673d34187f7dfa47422bf263168cacf89eb860fbec232ab48c40168c0e6a0f8791ba029e32e32d31b90bb9f49d84a4fa55fe64984d1b7049e19dedb7b6bc6b93644f7aebf404b13463f9949a6b7603fa61c154c421e1015e3c1e13f0bc2c9e53d4147a7c3eaaca6884cd7efb08c43146958b4f12a029d71a82c9a5c119ae9dd2dd3294b69a16152bb65f5a21df3b1f7f52e8ede11fa242e44bd68ec17c7b0c625cd3b271180364c54c298798a48975f06c35ae708113e1dfbf225b4579e9a62f376dc218c034bea55332c9c2107527e7c86dbe235d57ad5ea28041c69d0c611c728efe1305b563165e78420fabc56ed96c22f51762149518a696642c83235d4ecb009ae37d8cc9321fa7f0bd4c9c860de6817e869822f5e7aadbce64d4117a99160d7ced1a98275d5512f6d49dccde0d806c91a651966beb9ed02401533a9f0a55578a1895a212e7ca7f16c582a8ba3a64f13b5f756b04f9e0388ab16b0a636192a50e132163fbd332ac0c8a57082d0c7e359295cdb0235f2b341db19843c3045603d4ccda05ad847fe3a7f3e4cbada8c33fac08ec6eacbebc731a42d7cbeadcce026818ae7851892d63c64ca69d2082618d17ae42bea52b7117c1e810f0f0f277eeb7153812bceaa605570485d282b82afecf80be7f7ce23b11fc82e62b591e7949c485470f767544c55bd5ad4de8792115037a05f3498afe6fa10f7b11229bdb12fcbaca9b1f07a16c474ef13c883e843f7a0b011c526d00f589ae2ec87bc323767663276df2b7a1ed0791e7cef33a9c2e45275244d708cbc8541d2eac4d518296d1a58ea94ffd8a72a2102039e2ce59d28b94eed21ba5fb40f27ed8d1db3e2fdcc24e271938f46dd52b20c7ae6663d629e6101121ff177c5b8eb1c5a5d4dd39426333a74f162adfffb2af524811b73a05b1547e3514dff15148e5059eef75aaa18e0218f00bc6d2a5a910e5106a05cf6466ee6499b318134edc4b9e10ce677b13bb4ab8114c9bc8b72984e94984d4432a9bea8532a657685371341bf4e43095916db038031c0aa723650baa8816e6db9f5fcc8971b3030a05bad9b52acb139513c9bdca0df230f81364f9baf91f4ef599bc3763461d2d9a39aa60b893c4b69081e0044a8b3bec73d7ae594bf078f35b6db775196a37b3aa63504caac07a63d7fa8db2873c541f273854493a17b374602c4109d097cae77d3680002bd158eb365a51c6674e8bb54a6f1d93d0409facb494bf8c3f60f55fd779563d0103c1143048c619236f96b7bffad1f9a1942b4264c09c05f584417fcda8f035c50a7438fe0ca786dd649bc34003a0bba2bd788735590a272108b070a105b41f0411955952299d1065d3d836bb8f91811a39255f0e6e86da0f7694d72b78a9ee138afc9aef1c0a4f469af6283bd4c0f44d0d280fcae81dec26af7e23797295850cd437384541781b79e25792d2635cbd37622328e7cf3b19aeff8f730deab92ef3dd88359e1c7a4831ec147e9884a715aaa892a2f6aec359af7213bfbc8d3ba628d3b6c5536f1aab28b61cf7ca39e02e947ddd59b638432e72d3b5598d01ed815c3c78886a39bdf2e98b397764612dda1c7bd00f88887a6747c48ba0a9f40e91b2d8d2c5fe2c0df0d62013d06dcbec20b7b4da36c26695a96eced3daf276baf48e0959afb650ec2768271fe25770134089b0276ef42ca1427339d20cb3c1755195232f5bcf816137b6d41ef702b0224a4af76383a99e8e6641463f2e50ec5cfd3b1dc416be5038751d564b83c7ea0dec74fa290fa67310f32f641a995781a36a844f244ec2861d00af69b657fabf1517894866ca76460bd8c997c7eaf80a77491d37faa944e963c1c6aad4114dc624ef90a28f3e7298a82f1e1a11efd01ef4650c82f8e03335bbaefe3af99c1d561e345e2beb10d5bd5d807937caeb12e4e898ff64f6ccdd0a74be8a71e4309e823d7a3430fd1d65e0c97ca7d2fd6f34efb3a7877c9a3db947d6970dfff83d34b7a6e8bf97914514908f359a37e0cabd1811749455ada7023c8585d41c89391896255b064a1d806f261988f730ba42c0420e54aebce711f97c5179b7b08071da6e5653467cf6e53982f6b79a30b1546182182f950a72ab17222d31cf52006996f1f8b305db07ad31cf3970c16e22f3499adf6d37c969e8460b13974d0356c5ebdf0edd7b6289f8fd9049579de0386d69deb79b32d862594b7b77bbca21856aa427c9eba060ad414c80ed0b906262ace17144cf817a4444af4fc924af7a9df51ed925c21df86a4c4de168c048c1bd154a22c4c52c22c8a5616e9718c61cdc8d5df28b7778ec6101c18166cda46072b834c594cf231d93a4314ace5abb7fb2079f7a8a7e8e98262e9f7c4969aae7dbbfa6bcef28e916a77f86ee8cfb099f366bfb9625de77eedf68790d7b054eb7452b7582b4abd7369e1958981af589789bf7780b82c921e30a70d0f1c053f5962510e28b658d43d3a9e8a197d73b50b0188cc3170c2007f40404d168ba71c818831c4876862160d6c6caadf2511cebbc22c53ec98f58ee1e2fcb16b4b6541b3b9cd788e27862e038ca14fcb75c2e58423eb3390b6e225138177f63b20df5393a4117fe416184b574610a1ce780d4840ae57431475de325ef94d774081cef7dae04ca4aa0cbea79b1ed14db4ec52189c129c573473cc85c4fa45f800761517bc43630d6edd2f17e74866f1d21bf3c44ac734d5e367491be23c7a31247e88241cc29a0880d5f58cffb8692ed9f2c8ef768db35b9d148c4b0c784e380715a0243e873da7cc74ac325b873606a8eb82938a0347cf95e94e6e1c3ccb0d5f9d86216ddd7f050898de600ca358c690e5db0d7a0e1ae9ab5d4c69a342bb003b548ab63dd9bcd53210a35092c42462f9698376432d23955548bc5700535f5c788d02d8383551afcf32dbcd9d12cffc0e64331801913b01923ff5d2b2612d6bccbf419a23c2004463185ff3185c8cba703c73b29853c0a9b608108b1a71d3986da223d8d7ac13c3f4ebb85e064ba9974d7508569cca22828dc1a0e4c05998c3cb3cff24ba6f3d0e27d70406fade30180e16011d3f4e9d207dd5034919e564bdfefc3e83182637646f2de6a572070e8a051d413c72e0a1b72efb68a03df9a6a015f1d51553e4230c29146ea883859a8e76270b52b2d043b43cabf7930f9a6263b4619190caec406b0a981236d1b24dcc1df61e7b3fb24797c8c2bbc0c58a5ca0006c8134239b3cb780d0ae073eadc2d9e71db85843b3bd1735800f9fdd3bce5fe26a4c64ef0c575532fa41bafdf93ec78c01971faa00d1c12e030dee75b7de47770a02a14e57525fb1a41a76ad90b9662154ca4fdb121ddb8782f5b1b24a6026475217827fca025b1d51431c841dee534c211c8a6900925a8cefc170f5af5cf15d4b51678f6574c10ad3833ae39c2eb54908c4fa6a8805d2a70376a0cd1a6ec6b5a48252ec7b624d3b2ac51876608b80f016b0860533c12040bde77948e8e5c37db7fc34a927e03f3115ee585d47049a4074ef324a56ccd38d3f0eff4b59faca213e27a71c5336ac4b953ae4222db3218a4ca726380e8833cc8b7d95acdf00b84627350e413b9ca13219753a914344bdbbb653080bac60e53aa6f22859bfb20dfdd8b1d29a141697fc13c0a44b7e196c679272908c19edce8fce4941761d78d05dda4ef064470ee275aafab92355a42692fd307a2a2ed01390657adf00690c9afad6330029f70667f650f8cad8a36540142a00e1f776b96a38f3419f0e49fe387db91fd03ef77c5bb27c2dff1e12412e9a20f458de5dc68ca553e2ab9fc951c353a846d6391e46c8edd3a1b92729f335de032818e9d62f142c09339982a36b39561d944608a319add897e68889b72914cc165b18cb9fdf9e741aec27cee4d118875225133d2c3e76cfe603670fa4b14dcf41d4cb0b14874e4e64590e39c50c29172c87f0b91869c3c4b2d7c04b214c940598a1b6fca73754de31a6ca0611eeb97b75a7600b6a3cf58a39d94d8efc38c897eba9cc25e54c5f8c7d6c9b5bbe2d672885849d851b706dd690bd5c36791a04f4c551753e1b786273ba4ecf3830e435fc6bdc3adbabba77d1e415a3b9bd13d5fd3b110ef0cf567e35665cea1313752a276f40dfc307dc1c73c0631405540a5a1a66cc540f82edad7cea37869896bfae0c879d4a1e2dab26f6cae8e133878c23ae397c2827ac617ace9795746029e7cb25086aee560eb60a049e954bb8d34890deffc0686534c31d32c48a97d98df53886f7d9a75a2f05cb5f002c48c5f7231d6fb1b8a08a3f7ceba2dfbb83819967547eb2f4ae4f215994e99a70fadc66d6d60cd8d9f4e74d47b9fcc39105d8908791e5ed01e5f401e5665619b07c0e7f7ed733bdffcda82882d25d50c904c1a5af78c8de0834ce128a4bf2656c00b07205146d8b03ca27ce4bec4408679b9c1b67c5ecb8f221b91c12bb39f975e6a78e0405339146cbe424ef87380286a5e057efbca8553d1f156418542308943af506b01bc7309e654964304f864b60519504de4f96807e552466b6b29f79a2df5010c9e84612c46f08fea4a865053a17ab94d6cf15b24db344e41a4d29c0a3d235edbaba926894aaa8e66ccfa5626a644afd986864a0b9fde1492fa26ef8e128a814f28237a2562ab72c97203500dbbf59d04276723a15780708c88a697b28131a9556acf0727dca42f5c23cb8208b335041149e21cd0f72454ceecced393267bd73f33b36b721ce5c21ce186bd8b5cecf4845474a1c50ee9cf2be2e79729783fd322749989f25810d4db614e47352848c13efdbb6a4196018ced538718856219f5f2c94122780f8bdf7055824565c5ffa58869b927f3bb8c92c48fdf3d4c11d5b78a283764760aa9b4980f7900bebb90ceeb82c41ecabf4e9ed80840892b94a72b45a42edc9afb405800a1a22e63cc910227f3564e9924e0af19bc3aff0e6621b5665a0a45d3e8d4eacb60cab062ba378628147c6c727addb04c1b555ce7df1112c012a58f783ebd2d5df5ef29a80f86d06b518776f6b30837c43d3791de6ffc7457ea72467b25f41d6bfa9553a298c90e5c98858d692b01d2501836ff90fe18de9a249015e01db8a3889fb0084977364e58fa48b7c957cdf411eadb7e970616cfc8889f8d8cc3eba55c77fe3082343b4efa43bee7f89b47f1c9f974641ca57e33e2b1f3ee27af17efa583102963df4db9ed213e20afeffd47837a86651cc28c2743f7628000eab626de463a2af9536eac3fadf84ad14094661a3e6989a89a6cc91a0e6df272a59fdd4939b9565dddac7e4daa4d625d4fcd3386729680f8489730af36faaff03eb48444cfb5b184eed58c804b8a3d475382431b07ca1578b5a1d612edaadbde3f9c457d897415a31313a3cff89f1dcbe94986eb492047d9c395bc690bef00b9908e5f41ca5eb11fbc6b4395b22242150ec14e5c51b59df1c6977755b0f4a024328c30f8c52a8e8b38dc73568c99003f034a6dbbc995e704df83da1027c93a1f7ae3e4eabf3081d5e01c4b78a52615f4f2ce49cf18561dcc19f93018eea9bab97c278d79b9f35478ed53e7088d167251a635baf16aaf89889b8937dc3136f57912cd9a90c4ca9b22e8d64858f74412b5f516116aa8350b0775220943e899c84034d4ae8588dc0d8413d141df6dbfaa447ce384f2a74eb274f6639c73ca81813e6e7602c92f60fd9e89c45aa7c29ff3b25d31b3aa9de664abc2329dc85382499c60598b10630105c5779b34428ef7381f26a589f510adf684d31156bf58e111099bc66672feccf962fee7419ee2595dd9097db08580b9b66984040578855e8561f1214828d2fe184827cc3cce54d459ed38cbfb162def06cc602c002708283808898f513faf5e02499a73189fc49bb5b5b61eddba0ace5b117cd5b9e085d0210408b41d5343306cc72f92211c945c9b7582b77397c213001ad4cbba7e28184220e886e913d1e112750e2515a27f20896249d8e1c97f94d324395fb111a15481e533e5062e661616c3b9dbfacd16f95a91958aabb4029340f571b3d484139835f41861758f001254e14c90c99ea261395b69281a1b40b342384f900509e3034a840623904f74b83a44709308a19d10ecfd627960043200970e4d7d67ac98c5a16540e7fc1dc8149defab2a456c31bc124028eefe68548f6304a20e0b8eab247abbe4805b3279b2647c03830ea7daab8a627dd05ab8baa386f9e5df4452e11a221e10d97a04a307137f8b00e53c0716370b5fb854fdf95f72c8f6e0031a3027bf92e2554ba06c4a8a2410c734459ac3da3fcb76aae7b16c9889652f30241ba8e7b610b0fa6ac9874cdb9de21aac07d9d4e935e3ce87b4f42f527ef6952177d874fd0e7f123636d7ad23f9cf913c8e3a86b29261c4fd78250d3adc1be518c4988d1f45bd1be89e25ae3274e6f63ec91a8a658dd8ccaa3fe96de449cd1aad11ce9fa4a5041d0bde9c851a6a4459f8cc22e53ed6716bd4642b98ebfe532c70efe42a048ef4316ed0bb4032bb6fdebdcdc0998717894f47131fa007f0d6b50fe33009318fedef22a3759e8cfc2790927f2a1b53f7615593174b600646f6895a2c1fae5d0c36f8015f63c3f132317267940855fe8da43a67288ae1765208e41a7e17c917b64d6c9edc905589f6c98c9a09d07ef42cf305d9ab1f54aa91c60b20f0b785dd1d020f737f47d18c1483f82a542088841e71fbfbe528112a535bea0c213341b79e644dc70876a644cf81993fd6557bcd8044c716e0a8e90e56010ee315ff8ed471d17c36a24034c94a3e479fd17853c4f5f56f1293c5f384cc8a0e703a1ffdbd62fe01e99f7e2f6f5c1ab41792f384ee06d2a9052bd5296175a9ffee40e4c2e5f04c4c88de4128ba5afcfcbd635d001bdc5407747907e3deb94513770b5555c0a57b05c95a597ceac5aa7fc758ca2d30cbd1f3f3f5cad764b40c531acf1dd6e456081aaf899cb5aab9f5a9ab85692bca71d970ff83a3019d1f5bf1099fa3d1e55ef9011fb75b274ab532626aceca6bffb54bd36fac5efb52a1608cb6ebfca2414b0bfcdace371c865dd69397521c62e946cf477178c0a0a0570f767ac78254bb906d5060fd6d0c5efa6aeb8824d2bc67fb2815faba4b6c9ced052b7da7d58ec19e5506c8e3196b73bef62d51e05cfdec8ab6a144e410680d6214f6d657589d389b6e74daaa04a87ea8bada76a05771eaf99be2cceace522d0d636f07f9a54025776258bc0453798d83401a0bf33835cd0543011339384ef8db65260c5d4a7ed7db4026735bb91b14223c092997c05b4f9eedbee6568ae453327d01358b253b0b4c3f5a1d794a0b2c12ec3bfa919a4b42f053d801fc80ba3a27d6a7d78fee703a25a335f69c045ddbcca2a264d98ed34f48513fb209ace249a7f2a034b232689734d5b879a6d0e005c9b01be6deeb628f627f8dfb00d6d1cf017aa676d371f0edef4f360c6083b1e33061b6ee8b0b843758f4c15ad1599fc879184101748392d9e79cd0d6818740082474a379764849941b15b2b2f582ab4fbde12802a6cf021f5cfdae058ae93db89978d8849efb7f39a91841b4a2b4626b662dcd8d08774cfbabf7c87b113f39e4abb010ddd943ca835b9bcadf09048d15599c3d3434cdcd4e3ce1b5c241ff1d24e5f87f5891f5081e94da9f72941fe47129a3d11576a2bdfc0a5431b2d11b9f131c30536325dc6fd1985d364ae88b212d5a18234879bd1fea0c8649e0a617bcec08c047d64d1e99a8b38824678d4fb92e75cca479594f201f93594aef5032c2d09907c9aee2ab1fd00a7334afbd6064e02d49cfde1c0795210f7bd8157e3a29bd67c3394e5a26c42a5da1b6c9688284f0f0c186a760566f06df4736935eef0aeaa78e992746367dbf1b1cf14c21b65aadd7ea47840cb09e92ee0b231eb7a9eff018fb8e530a1c44148de3fb5f2a24e154484257729586caa34dad7d093e2cc4017e4f96e18b63b007db2449a736c00cd22118fda189cf1b7d83e945a0288a2913724f4417add4012770549b00f84055bca0bcf2fa9f44f7aff1a65b62d86cce137847466246e0d38c9d35ed0f73684871ebf9899721a2ccbe337e3c3e95acd37b9a58008ef2da0871634c394ad3c3183e8d5ed00f4628f4f968804ffaac6119701d0b256f741e25934738dc058e96a487ee2963ca61408fc9afd40a2fa58586e1cc69df0c653da9189a574bc67fce46da4439e9acb1396b2f1a4eb841a86f23cd74c529b05339d2eec8811e4b8934f72971a93a79ff0036241c2f3c74fce874dfa9131c049a508fb0683f46cfce9893f92193aba9a7410d592a1beaf41277a75cb54e028e1a8a4b1d73c76e1104ac53a2bed09587916d9cfdd0e8df78cadb5ab48391d472eeae48179f3511a692719f41b1c91bcb6e68b60bc04546b409df5f1c974da0dbf2d86fdf01e46a1d1d85d2bb1f7b89abf05d5a371ad9ca82b84152c4e0f50a6ba854a06a4648c699038b1548d4b708ed2a143329004a00546005e6a37fa9dfd3738ddf2408c3d131857174d219ebd1c9d1112e48d15466d9739162ccaacb4a4acf057b1ed1a785552eef19df539124f694c61442ea7620dcb9dea3398cef1fabfa404f61624b4d77519c7efa21ec9c0bc3f4265a967fd4eb9d6d86aebbd058ce2cad4b957d2d011d0b1bd3ca6559bda5037923e9aac99f5816c0f012e4d2398aa01a8d7904e91745d455b3d747365ddcc54bfad2720f9dff443ef5665f38303f1169defabab2c3813e63a9622621994e47782f1c7d732a4ed3f7a54ce38ee0aa8a1ba4d2a3e292e8bcea86f76ab824e427a77bf01579ef68476a1168f1e6fa6ab2677a500dc160124f591458b981d87f013686a7cfcbd21d21d6f2ca39b4044bf85529c98b82db541dee3ea91dadd14ed0a6b0d81143f8013746044d18da4495ddc16ea07df8e823742d675835dfc8146d9d265974b7ea92bbf330269731b81307c5b89c3897ae5da5c93f14e7e5a77ee1aeae17c23232d41df7c497fa9f0ce1aa53495a43fda0cd57fb53731dad3fe2a06ffe7006a337636aa98595eaebba26fc38538e451fa6d0f19a7d1681acf80e31fa5e8b763274e254a814ffe1530c06392ffb111d2dba6e84907a35fd6bf4d63b3b917eb4fef98d2b5d6edb91bcbc29ae45d91cb2e5c0b6e6aa6b5edd52baaac7f80eab8fc31bc43ff3d8d88bfa2ee57b4d65c3809f4e6c076bae8db66393fb674d56a5e066cb6a4d2cc16d1246ce24309530b2128e302c7cd33ece3f1186c19c8d5b4024cf7aef2aef1a1b7ddaf4ce2be3c3e7a46addeacd90f8476d18087d25b8fb2a59d0588eb64b8381e648da570abd835f39dabfac3ec5ca173b5589012ba00a55a5e6e7de0d54a368ddb067cec16e773105d2dd95ceefcc4881311008d6ecf342d07105a2fd31a4f6ff5c81107cb90a73f6a16e8056543abae33842a45f449f8adaa2c7ad0c351f7f4fca170312256857f9631b6f83794be8f76b0f307040852505f80d8ffe854376b1f7a3ddff0a741ed7503bfcd36baf69b8c958f425526632f1c2ae0a76b7aedb64a65a55e97d6e827db105b612eee91667b48b831fc596d0aef2e3305c8210f2b346db964752549239c3020685f96518b91f041e68f90b0459dd40190c009773e7e438b2cb6dd0a34aaae0db2e597efa8bb8845ae2374ea161b821193dbb377f17c36fa49c98f98d5f131fb2ddec88b1f3427f951268e226c5cf3c8dc5dbba08ea4cb3b13d23f81d8c3dda40c061e00c4bd31e16c374562682aab6caa650443c83eddb3a95f1e5e46f069b6c8c4ca558f33965101d9413f41aa522d2da1c4217e39184b0ee2d38ea78136a5323865902d3b3aeb0d9c81bd69aaa94ab6c8bd058c39463906a9bfd4fb5d2d7da95bb83b8305c595f063635fe2c72d7d1fae7a27bda68006845069e03186dc534a000ab9bd3249e8f3b51fd78124cabf0b45a674358397e1bc067f5495d499708e87b856ee32a0bfef95290176de9beac28888568fa4351719e8a46c6e6b793bbe6ea373531373b4393f302cd684575e9187e80766576e9e69d4de7bdb41fe602f8851102227a5700406f59b261a39f305a63d2e8f563235a1636987a6b730dc2ee8677c9b1730b2d4081e996024edabc83028ccd9c2e136a3235ae7c186c2ae3da3e23eaa2cf053ad54fcc524f1105209f261a3a2f1220e56d231c067631ac73cf59203d8899a99ce677c669bbcf37284e12e104f5cb70a30ecb5401de3f0332a83c90365cfff3b68ff835aae2e63362fe2c381946bf5f3a39350030b91528b70a41c1210d1a7614857cf5c201fc79a0afc8956c717c908c4d0d1fb628a2c45868a788a389affdf2705ca103b31a6b929665596feaf21f013d2d1585bdc8b2e6b290a51f8c3154d5f7f8adc1392a810b25f910ec7dda37831932c72dd3a85f001e33ac3de1e300c92661bb394c5c22a7e29890a6c4bcf732cc7de0a1d94e1cd611d282d809fa23f9b2c327fec4094c2f13ef7ef8e1bb3d500069b50371e1025eeeea5cfe9f3d625e58260f0ee0cc559b4ad615fb6f468ba4feea539f889bff602b04d004ec5c045a868bb154205e153707b9a9a976b26dc0de0f505bf22f677e12bf66ba393accda75396376cc077b27b6b5f374d6cf1ba6022c5e44eb83206cbadc8708a371ec267369392cd277b9017f8d419ef6dfd66c77f7cade52a62465270b5a0b820af38505a7575a2c961383c57672088611268c161484849bf9b2f2a1f79a5e6938389e04c70627f41e7a87c184d178783c0639f48e64be98807aa5b5662c9f71d2aa176798309a12256990cd171526bdb2b319cfac67f6036b9508c584d16aaaa0335f5cbc7a6563b19b184ea8c587be7b30616c50d00f72e8db355f4a1fb238388d04a76b424e8709637978b278325f483ebdb2ad96ccb68042295e98305689922a72e8696cbea07ce8e9925ed5d98ceacc98cc787228646ba8cb1272e8a992f932fad0d356af6a8cba5e39147e100d72e8a90c264c0d1ad2ab8a337bf5040749e661430ebd07264ce5a1a10fd2aafaa107325f3c59e813fa1ebdaaa1d73161aa12ea627feacc66a197d12b9ff16855f7a1d093adfabef29043a15828147a70f41c63c2d49a50e86bab268c075117fba10ffd0b104728270300f6f331300cb6c15af04fb6df3b88f0d6da94805b0bdc5aa1adb529c9f655c6d0cfb69ad00c9c8133fb220b082316148a8562602c28db77b1f29d341c1e50c309e168383cd97e0b93f7426b694a40ad056aad90d6d29464fb25954e9c6935a119389b6935d93ec905d72216148a8562602c28db4f295db7383c6e71423838f651485b8a6d2909b16d29c9f64728da5667b66636b335d97e38b2618dd5a01a8bd5580dcaf6456d086b2e379c8a537978445eadb8a441a3c9969252c4162b0969d676f659adc121ae35d9fb4220b0bf26ad3dc57c75654114c67322c6b28d05e59317d4a4fd2bf395377394130ae35d315dec5b99289365eb8639c37392ed7f1ed09c61dfe58ab0fef7b93e9798e3abf0cbc9b6334eabca30675bd22acbc3db3fb56a7b6bbbd166c7f11d0af3b9a88b7deb0139ca7e18e264dff180bcd55ac203479abfd1e736496f7eae154fc9dae7caf63f3088cfad7d9f00f294620eb3fa13a4b8560484fd34db0d35d2e81490fd7bc3d0064d582ec1c3dfbf5fc3eb9afaec6cc89f1b298f7d19403c8ce28f2d6493f63f960764bd7a40d9fa7f3bb883f4c09bd91365dad2d2e4c4319bce4a7bee20794292bba162e18d1feaa75ae57df7f5ef57f2d62f69e46a23d7f7ba7182f69fd46a8be5b86f7036c971a191d9a449a3b3a5deccb40a49d37890215eb946924bafc9de36ae6a535fed836b6fed7bf7de7befb655ee5ecff33ccfebf628adb7c3d5d5a4cfb8ca9ee1c64ed22e9f71244dd2e06e353900997fcf349256d1b48ad69badc93f11badb391d0c429041106e62704a021639f49a66610db2e91406f0d3730d9ed7d224fd80379a2b8f36d681cab3c9f99ed7894b32cf509d334224842d74e2168d76c85f860e540d997414c9b4a953118625d9ffc35c69109fbd5ecd2220f4a7f93b089476bb3f09bc39d2f95eb77bad96be678acb2293bafb12fe844e9e52c8b3c913acecb95011d29f266fa6f89910f6c7b2e323aa8b17a84f6e4c7da8cfc6528237bf092ea01a714a67baf7ee7d7bef4948df7ff3cd37df7cdbb8fb694f3713f8fede9bc0deb86dbbdb568ad947b276f6b927656cbe7d0585f0efdebbf7ce1defc0640feb36665ab61f2c6e9e84b3c9da39ee0d43519be068da504168df450e614966cd147afaf74d21bc83fcde7bd257f75eac914db637b7514b935c49923252f3e5134281f27b5ff620443716ae4c65fae97fe3cc9308cd1f9661f2be7f9a3cfa14cf1e63bf8d9970b280861257004971852c4f29ae88e5f95c9e525cc1244f29ae58924b724a714512a4b8e225d2d041b7d48aad103815d736fb9a28924da664589cdab00c5246ca29ca6ee4b885f07bf8dfbbed44f1846c495243417fab4ce28885db9b56f10d5aebe7ddf0958adff01505c5f7953851fe58c4c92de6aff46bed6c7dd0e2795f775f9e25a9d6af51dfcc5aa62c6008bdef2a188487a11d0cc28aac08ef6fdfdff72c5708b5bfe00e1fd615ee20a249fa751d6cccacc0639c30e9d81c832bf8c1097096248141cc14b8277936614213b97e3dca09e3d1046726dba74c5ae5d9c67c5d874d3b6aee3e889abbf97232cd3a49f3a5c5cfb760105f76172c84b3491a4dd64fb5e44abf9248cc171ac58f60aea81528cabea561985191edd442b6b039c3be0c1484dae338027e37d155366bc396f48e4eb64f9df46a5218908d2c49778dd8476850b665d8b126eb5b1c582b2c43d82a878736b2a5e123a36cc9560937497865afbf3a5fc23ca963249ab4df92cb39ab1167a1290cbd930fdd91d1a0564d2bb84007e749b65f0b996de8a94a7a4371ecd32596e2e4f0559146d93f729184d606891b25b26d91edb398212ce96b4f61968479ca51284c087f1da1ef4a9acb1fdcfb7b3fbc0f62e6f0bd0986df8d6179c308cafb3844cbdf7be38fd17f193e0a9e4258b2c8228bfca37bef7dfc11e2215af65ee47963c97df7c37bee272884877f74f84737ceeccdafc9a64e32fd8b04ae766774066fb6949b2bb76fda7bedd55a0b0ac1c13d1034db6f9ffe6995f7f35bd62a7a39b1ec9df14ef283f59732bed35cf58da3c63ac9cffbf92191bba70f7e1fee3a5ceb13cbc261eb13cb6ab27bd8824ddea9b399907e596fbabba508ba7dd4ea70200802153b5e8001164153f0c1c523061eec24c17505114037746e831d843a36484871c27603288298cc1c79a20a52004dc1862564564441064b204181820a278857d802c0832e28e141122cacc023680b6128c318aa8081cd0e783a9d1d58d1a22ae10227408315343f8082149630b284119830062098810b3d4b9002138ef040095e8409c8010b3fb059011390e4800a2870420b8c20861c48a1c4153355070859705e038e2e21093de5d964092c31247b42817c2e908c94afb839377ec8c1e3365102154ac8610203bd57188c20872ec8400b41541421073a504204275e00434cff9c2237143f557034d74b020e6a1294c8fd77873c9b2881437e916713253d1b8dd72f8488ffe4c9730a09401ee2ef1f84900ade6cd9b6de36179d39c39f858910b481030adad1cb46cc17dac2c05c51921c47159511c7610ab3df12c2fe98f94224cc96c2d8d5f7fe0a982fdabb7723c76b4e0ee78d33c6085f51ead32dff3967987a7446788c4c9d3eed183b12b93175ccde7b8c878b9820a6c3178b27f9207c4fc4711de5bec3dd734dc106cc986dbcedd6bf6e646122f43c8f1872f3fdd93d872dcd114342cfa5e44c3dfc8dc49820c6f33a76cc1d89dcbcd9ead6431bd6622c5ec2e4c363ea7b4cc5454c10e3783a6a3341b73bf1daf3812424697f6f188a622aa56197c182b024dd3c7be420a4bfd12d541af141440f915267e2cd9612c595b9f766afea7b8d26b994a3b8e75e636122dc7a686dc6597e6404e32e8b7b5292d03af7ce7dcfbd2369154dabee73ef35adea9e7be73eb46d8ff2a16ddb6e4884a3b80f8d282311dc880b39118e652e89fa299f843fe9a967bf0b6e279828eee7869d356770a14f22e5eb27414af9fa3e52be62d316c23e48effd2d9ea33a99c3454a587414e78413df97b013dd9722dd6992fbefb7d1e6067750264d7e9bcca35f098a21f8b48faf9c3551dcdfeb93396d9c63bde3ddb6df6e77051084108956d9e7befb2fcf14af3fd2e82e47719f32be32e7377306f7dde86567f90a0947717f6f188ae23f49bee60cee3d7b479ae47ca649ee3becac39cbdc3b2b7328ae0f0d5ab33031b91e264afb1a597b1a5bb8f7bfdfee5faef3ee36a6c4c9e1d49ca1556cba8f4d172fd19fef7f59bbdadfe85b23b5041112cd6b4f5aa7bbadd552ed0db47675bfb5da161db4b3ebac3d2b13d79dce5a37f7a9b9db396b7577f7e9eedbc537aab5d6e25abfd6eaeef334ebd3ead6dddd45315a6bb6da4b36c04a95bbac3dcbee32b7552df738bbbb695c68061b19eaf5bccd66eb8544d556ebb55a6b3532588d0c3d4cb2fa90eb8eec63fdcf7ad6dace5a8d0c5623039d24d75181b657ab6ddc56bd7a7dfb3ed08a3ecfb5480d3f1087f6a3ef46df14c5e54da568d4005355fbf9696110cf7d04e2d050b6af1e869a63d14fe56a35a11273456f7c7c598190ab133509437c59978c71982b1aebf1653d41ae2da83210e2cbdadaa698ab66f1f8d2bf909d0cae061d5f7ad08a11e6aa5f39be7426647fc2a3c0f1a5effcaa777ef8d26b905d090742fed29b5039c35cf5ecc6977d45ee38f8090ef0a5cf9ca0982b77d9f8b2b1907b8afe8201beec9fd2b7c36ab4119a093e7cd939221de6ca815a05b91b065d831ebeec24a3554d7d49c3e0f2253d03bd22cf204dca43b140a190f1257d42eea74988f125bda142e0e14bda03f24b8a03306ca12a987480f1e57c43eef7408b7286e1054bbf0eeefb3e406e1f72cfc8dd2ab93bc6f5e18006dc0c71d343c65f081ae3b163012c1dac1c4100f1c2f1fa4101313b3bf786a278809ed980797119c0756f288a3ec0681480003d3850ca6500ad19ad7bc3501459c83014c51855c68277c0657861e0f2b2e0f2bec0a616382e70c922a2e0524c0989b4196d8625971d8ee7f2a2e0e17837deabc36111434dc365b5c9e34a47d315a17b75aeae35b25ed6b1a063cd8046eff9b1f3cad8d953c901436c078673e25a4bb87971ae959ad3d85965ecec9580b81870331c6b06245e98197c623b2acda47369ecec8dae2b0a3837af1769766f7069eecc65958e64da793476f6c01d36c87c623ee1ab0a39383723ba241c3b831b6be3c146d3ca34860590cc079c419976b6374d603938dc971d4ec7842eb68414ae285add13d95dde10f69732e8673b76aeb8dacc15d5400630d05f5d29231a7f7f65cd158d5de0cb3a63812f2b4d05fabf6914d13bf4cc55b328f0a5ff4ce04b7722815ef9ae4144c3c099ab7e45e04bcf81c0970e7b409fbe6df86896eff79ab9ea1d077ce9491af0a5db0cd12adf377af40ba0b9ea99cc973d63c097ce12a2c5ef1f78b489c95cb96bc797cdb3802fbb474797be73e4f8b2aba0335f5abce6ca61417cd937407cd938389af4cde38776f1fd7d64ae1c48015f3692982fbb26f7e8bbc78d46a9ad047c496508f892021da0c36f1f367ac95cd51c982fa9cecb979489011afc2682ba788d2fe912e64be8fb696baeaa6cf52575a9bea42f1ffa7b1a5dc490b9b2348ef2efe1cbf984000548f57b60c21821fafe20ade2be1fc87ce95cbe9cb2017c397d66cc9595f1a58e09b301eae28ffa72ea04e04b1b02903157d6c779b4ea7e7f8ef9e27d3fc9436e1ebe7c00f45b0eb4cc178d4e1820d4c5bfb7ef17411c7de32bcfa5019c017a83811485a14d1891f20be0f2ba0570057029fad3a030f455048dec1d0d055813604900d7a030d486881a999345e00581d703b00d0a435d3e6cecf88acb71c0cece10b81469921eb8ec9ef98abb32b8bc0cc042e059f6ff81c2d01675f1e7a193fd02ed702dc0a5c33f0785a1353970d9f9c282c0e5050286c39f0785a1343fe0b2afcb51fe0ac0310e94fd7b50188ae4062e3b6f334725a08580d601b00f0a4367a88bbf8d9ae3ab6de7087591f96a7b154161288bbaf8c3e4e41820a7062eef0a975785cbd0072ca3819d65048529a2c51c456190a02efe05a021004d0f38e5824b312cc31958062edbfaf84abbe1008519425dfcb5192014268800b04f00ac0f0a972289cbe601972200700c8ccbf63c97f5f15c2e97f569621cc7711cc71e4da00c1ec796c7df827149f388c771a4791cc7f7b73ee3388ee397560ca618df12a305979549a6afd70effffff3f8ee38fe3bf0065c6ff1d7efc1dc6ffffffdf61a4f9ffffffdfd4f263cb88cbfada61ec8c3b1a9b8ea6a3e9686c60acacacacacacacfcffffafa88032bfb232fefff82b2bbfb2b2b29257565656565656564ce3fff8b8ac47642e994ce662399d4ea7d3e9b4b2b2f22b2b27119459399dfe57fe574ea73f9d4e279691e6d3e9743a9d4e27d3ffcaafe0d27d58c6ce30b89c245c0e97c3e52479a1a2a2a2a2a2a2723a9dfe74527101ca9c545456fef42b271595575151517931d2aca2a2a2a2a2a2a2625af9d3ca0997be846bb5b816d7e25a2d93288aa2288a2a2a2aafa222b600655444f1f42a7f52c125cd221645d134d22c8aa2288aa2683abdca490597decab4f38b0b5473812ed005aa69512a954aa552491445b1540265c45249e5c557114ba52f954aa552a9542a954a2593ca8b2a222e3b28c36860301a172412894422914aa5d2974a241228532291c42fbd58c22412c9c548338944229148249249fc9258c265efb8183bb7b82e24d7755dd7850465341a8d46a31189447a12699402ca9046a3d293be441a8d7e341a8d50469a47a3d168341a8d4ca5279548b8ec266633b3d96c26250cc3300cc3d168340a5140995118927ef4a41ce2300c439ac3300cc3300c4da41f9146b8ec9994b133cace919d9d9d100882200882611886e04f991004471ffe28c4200882a19166100441100441d3e8c351884bfa935fbebdb6d7f6a22cd1f77ddff77d20083e087e2128037e5ff8e087f8fb3ed148f3f77ddff77d9f297c300471e7d0d8d9db584536d6c6da584f3a8ee3388ee3beeffbefe344a0ccc771e07f0f7eb8a41cc7711cc7711cc799c0ffc00f9734490c89582c36f3eebdf7decb71dc73dc0d8132dcbddf73ffdd7b69bef7de7bef357dcf7d5ceec6ce9e7633e4e6e62648abb5d65aebbdf7561094b9b55e5cd25a6badb5d65aab89fbcb61203acff8aac3f12014c6738961a8cd6477f566adb5d6da5aabfd40996aedfdfad7da0ec73a8e35d58a81e89c9a333a9b3e9c5387f3793ed852351ac673f56ade565ddadd63a0b9bf41991fdd3e9d13b2bf4b50d8dfe1b87c273b6cf341765a1396643e7d2219bab27b2e4759bbdd1a618e08eb0e270653da4c1d66266092f43d97af1430513b4e64a7749cd9daa809cb8af36180d22468b881822b87b9dfbf26ff5329519c3d76440df366cb9761adde52d0c9f4e2eb36086910f57e74cbb487bad4a72e3da109889be76f99e2fba3312967319659b487c28cd3a57eadb4e7668bdf0528f4a7ac7bdb8ae45fcd2769b793fd2abab0b6a652ddeeb3b5c19b2de5b793697bb5da76b9cefbc090a8e6e49abd114a0aa9d4c285a8f2c2745a81c1d2ffd91bbfeaad7940b87b30d4aaf0e77fdf7b2bd4b798e4d9e271c77194f59df99ee3f050982f47c653bd70fc5a4f66417386fd6ef480e68c8ff586e9f2e57c34587c391b6c83b50a7cfb1b935e0520c6961d67835117fb381b4c347eadafc69b79414f7a8321c9f68fb8ac90edbb541196d703e256e4dbf7c80ff5a1401da8ecfd48dabe4e1c49e1e73af568ce007138675c21bbb2ebe402b5aabf1a21c9e5abb006d1197cd4f8d57c344d7e2ea0fe5c2d916887178900208af1220f0683c1442d2ff26432117e91f77abd5e229617793a3aa2f145deec991991e85fe4d9d88860bca893c9643291e945de11d1ca8b3a180c06139d5ed4fdfc885ebca87bbd5e2f918b17753a3a22951775332291a89b11892fea6c6c442d5ec4c9643299a8f4a2ee884824e260301107137130d1f722eee74794f222eef57abd44282fe274a88bd511d11771332291889b116d2f127136a20b83c1603fa2fb23f2177d90568d5ef440e64bf87abd442f47591dd1d51189ee8ce867cf885e46afee0c8f56712ffa1cf3a5bec846f43291e8bb6b23fadbab4de628fba2afad9a30f70875b12f123d0ac421da61eb005063885a6032d80e30982cdb277188c57be9782f16efe5bd74b27d1e46f0bd19cfc69b61f166bc19cf26db07008ccf24f38ec84c32997724db8fb1e29d603f30130cf693edb7bce85c742f9deee5a27b75dd4b27dbdf418513bb99ce46ec66ba6ec626dbc72d6e89937547443299ccfe48da72b9e17030ee470c31ec27dbff140d857b713a1ff77a712f4e27db67a16e082d37c3d988dc0c3723e26c3616b733e786c37e603087897e608422112e69644be3be74eeebbeeecbaf0eb752676ceecc7667ee8c5f9b6c3f0c9d4e9bec1ed9649bac6eb27bc4d45b678d7b4b8624ea138091fed4cfab4daf3618ac099892185fd62539f435f4558909b3fdb47c597990435f93cc971d3ef495d5ab6dab335ba509e1384c984d899239cce6cbd8d32b6d36fb99399905c55af5534c98ad66abe9024fe2f8250913bf6cd8884b327ff8bd939020e26ba0ccb7e37bffdebf951596b1777862304677d9348a6ea0cefea0dc3f9fe4fe236816ebe8dfcacda711877f8fcd647c31364f93dbab6c2f8edd33b64f93dbb718fba73436696c274d36509341e1d8a3b3661c89d3788db79ac4db7fa3bf1a46e9914622805ac1904b9a6b8769adb7de1009e1f6b4bb76d326ea2763bb2d9da1a169b91ad60d9b2ff65547da441413860a61ba5c61bed0ed2975010a4b1a4dfabd1e6d02c72f55f27298b8535d8242fa12c29c3142de2813f2f6d67e2e3ada6694541087a98238aa146cb60dc461ba17c471b18cc664935b53da04bda146982fdd6fef8d3d9aa44fc1c6531b891de4f6b6bdc7090992ffe22973dfeeb8b85a87d1a446af42476d7fb76dabd1e48d7fe9260c58ed84995de8bd10e779de8f34df50a8fbeb99aee3b0566deee4dbbc276fce93376792b7f716f92f8a61b8fdf4421863fccdbceec31da8a3c3443cf0a3d6c6beb4258ddaac92b64b341e9d0e972d9649de6aab3c2235732f449439efd65b6fa5613dcff37c3e16de1a4e73fb0c31fa0c7d863e439f8186f53e5026e479a20fbdc8f33c513b216b1cc976b77bc330fcbe90e3e805653c0edcbabfd1e1bd6178b5effd561bd6e84f400db4e00eefde7beffd3b6bbd9e4884e228a00e54ae364dd6d1b9ae7bad1f7cff06bfbbaeebe7fcef2deff7fdfeea3d0882cf7d1329d4e400e4d9e40959a6c9de4c0f5f1d43af8df5bde98dda7b4e914fe90541efdadede4ed3437bf2f6e25cd19e89dab8efeebf136666cf4750a6dd9d47939c880b7d73df1806a8238489d02cc2a5e8c1f75f0165fc394cc4071f401da86c6d9adcdec58ab0973499d3e446bfbb57ab45c7d6c19cb17d8f8d83e9b2bd1ddba677405db6e7c65662ce4852abd72ca00e8a7ba7eb6aadee5e6badeeddd8759dbbbb7b07c343a3fd6e89869322756cb0c26e0383b8b8ec1ec40ebe13a9d95f88c89b4d595fbfe7f33156afbac7dc2ab99b861e9469dce07fdd9a13b6c79942ce15603b34a6699aa6699aa6699aa66942a8e630c7cda4ecbe776ec87f510cc3d68db7d7301097225cd27e6ffb42a37d8f35e953be1b8550229748e8c3994099ee3bd62aaec7e705b8a3fb7eff31fa21ddba61280a814f1a7d0e73c6f629a3c761ba6c8f328ec67bc3feae031be6e2fbf66e756bce70cf7eb557dd72d4f6aeef8593b79c144c16b50ef40a0a345f3a200a4481b6efaef3ee09940171c544babfa00eefbb1fb7c9ed271884877f7c0dabb56dba3a6f283e592baceed4582d004d92b7ef9aa4c96d4e5c009f791c5c0efea4b2e8585b354975adea9146d5542479bbd3ddfd3f779abcfdf635dcb3fffd663869f8bbdfef534019bfeefd7dcfdd03effb97da3bf885a00e0d13a1d9c3d7876fcbdc38b34b16e1f6de6a95e3112873bf5b3beec5d93c6f746143389b33360a33f356b7b79bb7fab6dcfd0443debe9491a7861323cf39e7dbb9d270266afbf99a13e6ca67d53586af42dcc215a640a7531feb30639388f9f22a2aa3d1fd39a389d4dc2f4494fbbb9fa18bef8c34b3d5ea4a35d95ad6b49c25383a3fa99ebc7d4932d9bed6da73bb36add5feb5b5b60d56d8df93bb2febec6d6cbe68797bdbd3abd91aab554fc420eb246f77fb596a47f2866d2cac11b524799b4c36ad8912fc8eeb405cf6eff075a3e64493693f4dfa349933676ccf8dda139a14a88b4e93dbdb518335b9390662d2a8edb5d96585331bcdd6d278f2f6230844673acce6cb96b7b7af56f56f5f9fcc17cfe2157da5e1543a61ea8cba6cff7df7446af65e88287b366cfc2c53d94693f4fe04ad2bb623c2eea77afb5b815ac495b054a5c8db9760be6fe7aa4a3165b4eafbaff3450365381a7aee4378668e070dfd1d2bcffc20d149f893b7b2f6e4edeb6cc6fd27ea16a883c344680e61f05f73c6f6e0589b68727b0dc757f5c651330a5385305db6df60a2b80d61ced8beecedc787db05e600d2dddddddddd16c4d163b764bc6f4c84e60e7c2fc688a3ff8e1a8eb624c751dbbf2886f45df3c9db77eb037558ba83b664ced8be8e1a4e1d42ed9f7a103fba07bf5d497a6cb592541b577d912d7f1249612a07b603802f060844e31f20ee9d26b76f264d6edf35ec8e65cd6dbaffe123aa3f61b283ccf72f6ef2eeb4ca674dfa7749e149fced7de6ab54a3fa6be4ce0961e2ce6feff9f079e36873370aa1f9de1b86a258fea6e1e4dce192dc9eaba08e8bb7fb35dfcd35040cfefd069edadd3da157aba7b5cd5cf9c865167a57bb87ce58deaa150890ef29687bbe941d865c3f040ae1ce715846936d49df9dab8e4d54fdd93eb117367c40bfec98ab5fdef41fcf11eb1096f547ff109ab95ae336ad2a6b4eb6f548ab7ed0caaa3315c97c01bf7e85c17c097d0d85fe1b4b51083b2804fd92be03813ae873df3de3460ff25612a0961cc2d25bf357e1d7f7e6e8e1e83a8dea9873eddfb3bca8425bdc77a66010be44f8fda4555fab6c886353a443f86308cdd57faa0d148465a511b310ce2650c8c93fdfabaccf912741f5bdedeb0175a0b21f69b21e51a94e932dfed364f59c39a3aa9c202c2b2b0fa1ad5cdf93b4aaba5a65335f80305fbeafdff7762c41fce14a9347dc579a26eb8f401df4c7ea0287b0741acfa93447d45c768cacaf32519faf2dff6995ac913051f59d70a790eb5f21d7df424fcc8f7cd9313168f6cfd7ae56d9d0c97dcd1cad25c96b2a858d5487e6f48dd76751a9356bb5e7c907894efa27d799db6041e83aad2ab5afef4fcc17eeab7f0b11650b0a418d08a71441b3dcef8ea7c9bfac3d9adc6bc1bad2596d6bcea8475ad561194dd2faf78a55ebaf9ae790a42683341936598fa8f966b166caa2210ad1ef983e0f1efdc3a4c3dfbeffcc3c3016a186cba9d3fdd4f5f5d7882d97846b93bd0224b42fa2fd6bdfe2854808a715eb287cfadcff0fe35cf57094f63203f490b512953558902176ac130351520be6f81bdefd0d0f32a487d5acb68db57e87bbd6266bed6a576badb5667bb711a9c9ee67932778723977441fdf8db57b4debbacf1ac7dd9f2087494d6a7fa39bd41e01617d8a63c341b44b83960a0631f3f65fe9e5592910f40335f20ffa8e4bdab8cc91fbe958d6d0c2fb76a2e8773f27cacf398a31e78abe88461ee7d53ebfd1dea38ca3b10c4563682c79c81d3e828238c49fc32291a222b427982f47da6a3d96a9ac1181d3c387f526776fb5dbbd37ade2d1a4df1b86a22dc91293b034714fbf4d1c994bcacad1f2ad182b9996c0b9a22c47d5fbcd17203532fd704cc52024894d5a3b522573345d0c44a5375489833c8ce4bf6337daf041c8bd89728d77e01c4dda6f795b5ed27f0f5fb5c0a57b49f8a331bb6b93da1cfd3d9ff9665a471f0a8843d3344dd3b4da54738d7ecd137fb5f5ebe3d8b0687f82731bf5cf26394ebec74edfdafd4e73423d5262abb5d65a6b6badd65a6badb5d5dab7d6566b2d17426bdf5a6bad2543cf10c1caf58bf091e6cfede3cc74cc6992c393eb57b2be8cda5e97294aa62f32e9a8fa9492755423d799e33245587fbe8c56d1da63beccd9d4ab8f61273b2853eb04a235defc58d91fff38feffafacfce9f42a2a2f8a5f2a3d89f4a3d187e183e07fdf73dcdffbb5beb54f5bdc492acaa1c167e7c3c9a84baf3c1727a3301d0d75f117c530a4e1649e13deab9b818b3a673783ec2e5a6952ae8e86c2cc8e866eb9f4ea098aec5d8ea6f2f6daf2ce2830c96587d3aad273792e1b6f12059decdf2d89293b1dcf15ac6f23b3c93295aa5183c2a1cb306fdce4ba67dded04c8e3e604716ccfed98cf4d6c7f6c41f87e6fe87d93d01d34a4668bafc5d569a2a091b7fa7d5f9e322d5b3295914a8de048fa6aa641c31ad19ac2c12bc9bcd1ae0597e3b8fdfc0f90f9c77cfad6bf4d508dd8a659d8dee724732a7f0d5326ed5bbc9118d268d252de07e9535efb94946f818bb8f8942fd2c21b8d26edc5371283329a346c1a02e54bef03e54baf7d09177142c33e462fe2222e7ef4455a3cca1b89d9b0f82a5f8aef2b17afbdca288ea5713a0a74149054ce71a3156e3fdc6817a3496b319a347c848f16efa2f42e709122d3df484c10ff19238af8635cbc7f0b6ceae1e24d22dc8019e3024f47d198166f82008d69f134a6054e39caefcdd6bfb417c77def6a57dbec6b18486a4789892998c82494981badba392c5e22c4a9ce08d817053e270a0a61798f387104cd42bc0eac6ce7f788e778f1c602c24d3bc2ec3f962660e52137fbcfb1aca511d9ebe658d9b7d0ca04c8b389143fb90a4f76b201f2acc2139feccd1a61e86986b5aab17fd95fb9ed3e103473b6f31e089a5f36a73d2336807be7cef8eac662a9588d982bb6f9f8eadedc9bcde7de6c3ef766f3b93775c7573716faa41ce57f71c29c14ecde3014c57f924ca52850a571b1025d9f85ac99eca22c741f7a7333bb01f2771a5fd10beb9d0b5472a0f40dd4aaee9f2749b26b343c4fc865f7640f595ab0412e5bc66393cb9e39cb0a4972e93e93bdd4a13134cefc35292a117e393a4dfeb48fbb90ee6932140a8d424261e9e9d83c63c7402a1ac3b1bcb9848fa8791b85a1d1247ad297de0b471310348726380a47d308572a72f542f68484638de5098eb50b3a445f7ad2687aaf4752a7d0bf39e56f4e5b9df903e54bd18e10ff187df8255c7e2f7a2f34c110e9897826e1d2fb144cc4b387d23ff2680c127ad38ef047e87510a3534c72639bb0481ae55f7393d8d0490f5fd5da44a3fc6baaa66c8ae7f6fcec28b94b8074b27f45e24e7ac757cea451fe366292b0a61e119f8441373cb727fbeffc64ffe6e9f1e91f77248d6a9dd7129792266cc424618d1f119fdcb80e15420bb339bd44586e3e3e2954e4f1a601c2ba22bd51f8379a74f1222e5359bc69f128a75f791fa75f59f913ca89e54fe510944789d5bea95ef53cee2b77d32a25bd0a592c16abd2d880c2509f13a5f47f3c8d736a200eda4af91b4d815a559f06f5ea49774db7beefbe1fe9cc0f944f79af9553fec5d8208e17efd1d27ba5d20731730997febe911c24a37c97c6927eca7bfdf5687a12ca98c44da6436c36e16a03ea92f237fcc54895349992829738ad8cd351a113065340157c03821fc4574638aab6f8f2e2f296c42b523c5d1c47efe26fb411be225be0f266118cbfd125cd28df98e5c7510a2e6b4679d2f758d21c56a6a91a3367c2e6ce8ccd80643edd7d7a1c9bb099c3f223ee11641ce744fd384ba552a94b7f7d75fa122e6fe47e4c29e94946f1c9a36fd1a3c8b810cf28584802b2c8228bd188321afb2788d296892998f0e9e1a8faa71ab912b14c4cc1041872e31fa20fdfa3dfcde1580eb14bc038fdca09cf1e34e626ccdf58fe7844ad47caae41cd42521beb6d14fddb52c54699418bc9ab5fccb3c91550902a1faca1598af3bb07a2c35b7981a4de6bbf02dde8904c91c8b448a63f51525e03974694e452b7f7a0271aa90d7df59dde895dbe3787a5983b3084a92b280c8012a11129b851f00def1e08f7e1b06d8f8fe57d3bcef9621a62f4a19f40f8a29f74340a471f7a15842ffabed13444ca871e02a517bde7df379a4c43a47ce87d945ef4331bc90efe0704cd20ca87de478b17a17ce855d0e2456f249b8640f99487000a36818f62fa20d0029b409487c0e85170124ef840f9f09348f9d14320fc16df022781f2e1cf9812367dd834c4e849ef63f4a40ffb08513efc145cc4091f298ff2459c289740f906cc98244c8059288f824d9044f8a49fedc3f6298ff2fd36789082a7a35070cc084f2fdf519e67047dedbb2c53357239a466eecbd48f244368f6bf3fb4b7bf8d94654499fadaae817ea17b665a4042ee1e2b769cb615eeeeee54eb21b9bbbb3b6d2bb0bbbb3bed9ed475d1dddde9bbd3ee717777a7ed85ea4ebb2998e0426e1f2bdcdd9dbeb715d7dddddd69f7b8bb7b5be1ee4edfdd69fd42dbd7ba6a7508adeeeeeeb4ab204577dac4dddd9d768fbbbb3bed1ea7ee9436a5eeeeeeb4fbebb883f6fb17a80ff5c9f4bd40772a1c68e005ba6369aa608623997e4fcb9cbcc008b29e2ea7cbd182df741194d020d3efb1319ad1f9810d2aae6b37d4b52304eda6a792fc89b0e41018c1824cc91c98c87a80e0a659078c18b040075321c3850f828a20a376cc93a209ad19abf10405329f10f94401055e8859210b42ac47c63959e208b29eeb3db58ab714a8fa40062da040b21b1ba440d6736a896206400072828592e0b401d6739d0a20345262591803101a54ecf80a90e060a7876a3a42168bd585ed6e5400f9a660628a217c5588019882092e885aa851b1f395010939983bf68642e18928d89b1e20a40a933228216ba0d84441831a40521548eaea784b8525d1af5de866751562ab86d49953ab983a22164c410c53a78754001c303103898a214ebd8a0e6a9f2656d0413d48b058ac13e4eaa914844f6a202dd9df3beb38e15cf193e9d711488b6907c54368f692664a05a5dd943e118f8a26a5ee7fc4d7aa966e80375b4aeaca1ad56834a9857386f63593af91c20dcc19da1b5187f0b9a734fe3f7a827460c214415de6cb7ded4331bcf145a4c44eb1226b37b45f394ef3384ebbf6692eafeb8afa5edfdd2ff76e6f9aa41d6b92a272e8cb318f42a3b7363abb5d3845ed5b294c8418723fa7b770cb70df88c249a36e4411d4e4f479ab4e75cd19acb0ac403fb81f427d1a7c5a7acb9f5c55fdf169552773325fa61ae68be6bde6e192d61d0e1462763ba00efffa1cf71e37d658e5f1993f69d48e1c5cfe2bb0baaa4da3bcb5d51d9e56555cb9f9b23dfdda83ee595e5471aee277f07d49abba1c10b7bcf5a3ce9aa4414dba7021f49fb9ac409952a0994d775daeb324534fd224d569f2884a6d9aa45e759aa4d53567d01fdb0fa1331f8e558f5415cc97aef372e29266a02669e867aea57f05d2e1cf0535497fc3d5058bb024ddd4eaaa40ad32b9b7825ae5ae990eacba7cd56e9828fa3d879b027f81e834c894be2769b94ea6ee2d57e24d509f9f0fc4e17573fa7d439f1b298cead06da42d201691b6209c656af2af268e7bcedf959369385f66bef7de7b695cbf5faf11739b2eba8cdfebdd741fcb8985cf2c326541a65404134531c9ba6d6a8398327deedd4b9a7d4ee77e7beeb79f4dded8e67393db30299c33e66fa055261d37db07b265229e4b9a6d114670806691dbbec7c9a0b3a733da6a929a3abc83ccdd77982669f204f38542d1ac6ff4d1e49c307d435de86b4f5b3af3a5fb7bc390f416a5d45bd4fbef8649fd108744e670777fa3c13105e0173112037e1d4b23144688e9c23d6dc2c3c84d2e81cc9dfc8388e7254800feccde03e4c60d83a38f650958d9ff8673e3f613ecbf63f919ec862293ac4f2b44012bc2ba91af5bbe70a7f57eafc7b2fbe65aa7f55ea07cc23aa9cbfd8a29ab7af77661586b2d31094beded6fb824bddaa6d5e2796395f8f7febd57eff4f3fdbae95fbcca8ba7ec4f9231fa50f421f0cb09c3dc7b676303bdbabddae84637fad3f454e5e9935cb4f8d2d36f2165a45a350a5ff4a1a77fa355e0d3ff21078feed12afbf47d10d12bfc1fd540194ac2f89587b1c2a3c92356de5f7d2f4b1d6168a3f5c6fbe0e87d68045f341ac3474179d298f2a591f42dc6d2bb185746212660e57e1f85f4ebde7063f917a3e955c6172f8e2a7f1a69c6e3112760fc0a3e06ff0b944f489f36d1ade25ea797f45572fa9206fd97f40d7983396afb166101a87ca8144c180b8be029a21900000441006315000030101007442291682c0e34518e0f14000d829a4e6e629d099428c6614619621032600000000000008090c4910040d5325db31821256c9bc0c212f6d734bc1426cb686ec3c398e0e67b070b87956890058686b9cbac8a33c2d6d703116d41e57f5f5da201f25eec1276888067266476edb21f5a870ccb6e3168c79b3a361317ed071453a31151c6b4eebc6bb8fa7f8148edaf6c9a76ed8f01c691845986c3653d21f95c780bee5b2c39f2f8fb58505e59b1f9e2e560e8ad23f1d17c17888b8375e193ebdcf7de3607fac9d47cb573344cb6c039840b4f93fbf71ae3dede87af40f410b732444f0fccc183014c8bc8cf15da442753082e7a0837d5a3b19311e13c019bbaccc5a823d27e5a154ff7b3065b05cabba6190135c7b1c6f5c1fd200a347528092dce211ac5a932db5fdbec3694b7c9745230e7239ebffded8d6bf7d24fda0808b6db6855a117c44aefa98da10f7327b87f622090298656079f0b777edf9a274b883ea8821a65344eb06ce5f1870f627756855686d3adbc6a5ecb6ece22580765597cd6d4a18b1a2c4a111785f766635124bd735b2936428eddbade1056da6e6cb4d7943d63f4cac94b5850ae36921174f27df2edf574d47af5936ab074ab689de91f640ef991edffd35975e298a9adfa103a2bcea98f48c136888a681db396115db70097832f106b4bf706f5fc3c85829950e20f107ec0a2e50536d1c34ace53895b46ee9d30013d8a33df4a784d5614f5353ef4de7e503c44bd9bf726553b332ba8b3223080fd9bda9ac5eb9d038f39a9cd3cf3a1811b9b10f67607f012c43eb1edc6c055515fb56ebf26086aaee62d0bd90f3530583a458b233798c276ad65f3e53cfd741e1579ad82ecaba11b5d9a7abe71ecfb95f45bc782451808015e458089b952bf6a07ccbd2c7b6abe8e7b33fa57287a730fa50d0f58549668c1782a35ae53ba8f2407db6372f41e771a9c46cfcfc1d4c8a77403b1718d35ada1c058918a335501f13ea03cf121e9762577e8a6bf9c8546a26b3bf765288f6c26f9cbde9a07e149c4c494aabf52f29007500c70fe72b4922a9e55edb853bd5cd73b4da6b3100f719810356f1cd7f0f43782b5317db005cb6f0bdf7d907b35f6fa4ddc2ca79596b180513a691595bae44f3c2099cec9bc05d83904506d526fcf5dcbb3ae1e8c21db09e16515df2808589eb6dadd282a0c76863956ac81cff89c078693be9e3cfab53425548339ade7c8e7d6df95a385e1059d690c62fa1d5ff54ac5d41de00feec181818bd49fc626929240c42bc685d835fc5846a03283302fda2cb9828bc16c51c436dc76e82e2d32ce7873bcfceadd34a476d58772e45315c428704131802f7988a7ba07ca6e4aacfd9e6f80c3528a0c619d9cd2ac15b840813960bc17c7a103f6af642542283c793cf340bc32dd37f402c6950e9bc468f2b9b818defb58c5cdc04ab4b58e455218ea9f82e1b2601029bc08c1d1b45ac07fb75c00f69fc3c4550d49140560651be187de9d97aa778414d8ee3ce1edf0462a95872ecd910a60834815ae4f742f89fd5669803343e33a918098ce086047c1e0d83ee201365c589fe8fa8c0716733afb32ae4baedde2736e635c205ba96a4dd4486e99b2050b8513b49c2415f70fc44fd209b94a94d4608ede00f2eafe88864d6cc37ee22e7343772d828762b979a40e12f79b7406a077a14cc11421d52f2c0130a1e9d88219d9e066455eae88dcb4d3c4e196e7781b39ae6ee1ad145b38ea828836bde6226a13c275169c5942ddbd4ff765d156743a36ed6b45f6ff287eae9f59fb29bd482d9631785ff49cd8629d23fb4f5f0f69a7225047ade4a5dc3a85dd91eb125ca581f87ec02e82729dee7d6c8f79c37cd8fde2300a29cc204a59f5e916d0354f9cd1c8cd133cb2ff3ba76c748b34afb8a0a3333810425f1c6df7f5779298d3d1ff7891563e4f2cf6a43574ac68fe454a36bd5603494422f7868c98e17b99e3f438bc45489258e5f65726f637cb5581cca644bc4508e324de0cf19140a431c209a2056e90e9f750c3b15682e54ac83c308e45922b6759746f094801da41c0fd136ee239b824c50caa248fe0e1828766014bdc084c1475090feeab881d7ba30232cf8ff8a9453c8b3304a3781e7194f424b3e0f5466965a1ed2b674cabc5a03843f8dd081a96b3c3183202802b01ed1de0fc48a1b061b81b6c132c2521a265608e2ede19b73cc2ca5dc2f61e37602d695ff844a0e229ba86b447397e883b2f1997b7464705227b0f2cda5ff957d965c68a5df69b65679aabb18db9ff9c89b4cc1a986336503aeedb41da4965377e1116ada8a4d0c3e7d6fbe9c0f507d7da80a8594efa5b67aa20d5454884c1b0a841ec71ccb5fc8d333c164438ffbef2a4326122e899405c20411c1658b1dfc0e69a31901067aca816fab1bdfadd4b4b68cd5bfb4d2c0e6eb52bd1a23c1da656270671a6488eecb095820ef19243d460355034cb1e2dae27ab875c71b6220817f092da4e6600da93bce3b14cf421ac0c6f1e51f7b500b52c51c14e1e3402d7bad5f918750928da3e4b965770d55f3729a55334772c299ceaa3d3c123482b921ee7d9b300d1dd418c98a7e9b88cad8fe73de51b6238edd9f2b29d9361e41fbf21187b7422174f8320536d66b4fd368f33617f2ad79b105283fc8b4f500f2cfe5a3b2cfd94e101d05df25829cd7379935cbb3b1ac55f0567500008f03e8cc792f955eaa709086fdc8e6ec0bf1ed43a49c07e617393d0dd00f5808ccf05ceb1cee0feb493b9bb79b0bad123f486fbd5645ea9b78e2dd8e462cafb56a09501e58e2edf67461da01cd37fa868918d5215c35d24f82a6b92abc289f740b99f4661ccb6ea1b2450fe23c6f25567b91d25c1030064605e398d54281a6c9591b51a47ed3c6901d8e3d82c7e13b4bfa9249ca39a7d764fe16b5a848404abc99422fa93f6807a86400afebf2f28a4baf49ab0b87da1429794e64c2867d81f51e5f51e07ec1fc4421161cfa71041dfa00a7e27e99144493dd9f474afd15844c362cdf5ff5e30f43665db438f1132c507311dd378c816c47138e482cd01182a8daa74c16ed2179b35239033b66cb6749fbcb719ba175f0ebfe52f1849754590d4ac034d119760625a806598a3e5dce4f42938e87c3775320c37802f8f3612ba708a92db8243fd8c1406b84ce92e7399a433d47af99f3e103b35e083ef35519e40a4268853a5838572a6506588dd0f90b17ef319c52eb7ec70087dcb8a1177166a1a4631518bb1d9539fe8e7c2f678efe1867a9d048ab2ba2f4c9554b6a0d835a3dd1c7cfb794148ae56da02e9b6af33e798d0fea86eb625782845e01ff665bb99c30d7c9d6a0b54939a1cbb5fbdb39126d6c3350f930026a08327342f7162081de721dc2211c380f77c11f5f50ef2861d812dd7e0f4905cde6bb4efc0fda77894cf06d2a7ecfa032ca419f24744b0bb336805d909a5169287868522670ce83b63a675c73893f18e8e496aa5fd1b7c62ccf7332849ca0d4f044cff75f1e6e12905c6a1f209c6ab2f994bd991a66b04e9f2eca83d27f8110d96c5a840d385baddbfb08b440f4bb059fc7d1a273c0844c1117cc57d494cb3716f63f9d8f5cc0ccc62c6e84c370b39e820d669292e8b7bfd306f42ca362ae7381b8b356635f48e66abe676a51b6bb467ce26fc6957074d66ed1d7d0f14e26ede2b28dc7ec05569ba6fb4bdcf1d79d3337c7d4798c8996a97496ee05122e5ccf2afca062bcf40b7a381eef7ea4842a79a5fd96a274f1c595e86eec6711e033e73556118334f96ec0cb7e54fcce5262f03dbebaac9a590cfd65ec23cce649cb9461a2394ac84af57b9b6a709f67074e86bf8e727e4fd45105684297ebc525c2dae7605b286f6cd7e3f5cfd6193d5a73929b1d7e029755175e885fc9e78113907de191ab74c68b176bb4c1f3e340ed71ea7933592f76d7863946669fa4b70872062a76fe44444de7fd9038a15ff90fa07853ac009bd1716574a48782c03ee6665867cf9c99b1b3f845ba5d6984eace854b9f04caf3308b52122d543402efecd3f8d78e26ccb70a8120ce9e5c6523925e168597c077dcae38976aa0e4dd3e0620a8b67154690e4f85a57d978540466211343cb8654b5d4d7029be8e85713bccbba4c5a7f240cbeffaedba2a4647dc526bf00371a246c6df273a65433c098accfdd5ee145e97a93bd3a3fc27347e0825efd5e41ad6924ebe2db3dd15688528d198a336313067f6c300f6550624fa74cd421780d2084322c436886a54fb2a423cd16472e46f3479370825624d0f84251874eeb454594cb9eb98f463ee97292a5828bd918d66c6b52fd4b3d7a545248c2070fe13aa10ac8c057fc6c1698ab5dbea554a75730b18dac1ca6e1155d76e3cedf5b9548eebee830d23abd7dba32d9c59091e06bf59e553fae8ec0abd415fc0a22a6b8b4c1f25d954b2278f4b61bc9fb2d803a84eb822a920159575162b849a6d02a8acdc4aef12bb0b64764db0a7ae5056e8d01c34a2d4e5661d31aca0d390483f51687e56fd137078ba2d4c43d7f957aff8497cc311dc4e642fcb5a8e7ee406c7355c6f3f26aa9fa5d6d5f0a8c2532f8be6a80dcf8e35c470c5d7b64ed9cbdbc86c58e1e5e8cc6b35f223dd5c45b8e2e5b2c81a499bf31d4caef52048032187f3af3f2280ff050927a27f854855b438c25ae510a7d03b630fd265470116b015f80ae31a62bfa4d1bb600d5a72b3831e49b32dee6c537793c871777850cc5be9a60cd3b85b6c8ad2c8a8f9c48755442a89c44dd83d162144b7685dc8515939df7511ea62d87495a3ac9f400932b060c2aa524f6c84a3099d70b39308ccb49e7b9e42cb64e1a2e40ab64528d4db5ea046bfeb80669e2d332fddff4e9c1f5afdd593e94003da45761bd8a8a42e8e5be590002e65b3a89e5df9b7320bdbe03738920970ad8e4853202ea2ea27a22765f425486e544a605ddb9431adbe0644c11e1991e525e419ef096d24691db52ce7acf405e83c490dc3c64da2a76bb6f6e2d59a0b30ee17a054c04815e328d4de67a5af8c292c17a71c39e6912b90bae8395ceb1a97456f494959863d94e109297d1f1ee3497b9a599d0937df98659a0a78a2c960137f5c4eeb769e26a17a31437241c51da19bdb8f235f314299136b664ba416896dea1a913f33374fb4de61f181056ea3862b35c3142b9641afb3d75c17919fde4e66ae9441a6cc94bea55dc9bf60a7e917f7b252a2d3195d8757926be2b4c6c715c9d6080552f763812537e53914ccbf252ef65c1cebfafdc6b7ab1a6f0eb66ed05fba4992c8c7b039891984acb628eeca65c9a9856a67740d22466a92f50795ade3d6ac462e7ea066bffb2c4e279dccf7d8ba017a523f7e618dcea3a4f5f4a0d56588d8036910067213dbe194ae45d51d2d4082606ad182455e8fb0bbd892044ad9aa0c0507a193676d9182c01b42592d7d8a6a337c1a4c45863f585a69c16a2cfd0bfc9b1441916cba920f811e477cb5c2bedfced0834b9658b0d4ccee33acdf6ab0392c28395df20f711f7f3343725d6f16005fc3ff0e4b6e948f69974db0136339f575d649405d583a0e31e4789e9d13b814eefe837af6943ff1f5d2f9d1aa398455b2d28ce6e3501786fac5fcdf47e387ac62514df53b7f7d5b0ad853491b7eb287cac1d8aac80046df432af71988eee24ca0cbd70db8e7e64a765211551b29adfa7c845a752078768344ed777a430f5d51df11038e3f3a77d6b9b8f283e11b3f4761126a5b1b230bcb912d35b234426651f98735cbbd856f481e91ad6642ddd75a13dc0838c2f8e95ca114793d50f31ae3900be64ecea067ec88afc82f06a7589e5d2b7e99757e740705d06731f35cb86d1930a3b8ad689174e91233a64ed9371dbd814aa33f1d3ecd1224aeacf438b8d63ba795139ac1ca005063f919913c448922689437803963c78c8e02f4cca0ab9d3c28348af455bd5ef453c140699b5d1c59aa32efa6d283d10831cdcc54ce222674511610c5fbea724bb1d7cf8cf36120feae9c46fb42a4e0a7f84013ad3a676802a0120603f74b7e18c6e17c18da068054c8131a8c55b78cc169c591a5744b261b04c0a37168e91bad05003a5dec9a230dd8c3f036c5c5e91bf76e396ecfc2742a9371b159d947b7cf185cd6464d9dbb7dcc3d159ca4ae89e32d07eb4653a3f3f809fe1869f5712b52808510cd062fc52a75ba908cbbbb273c4fba4454c8947de657777ddb08d0bed4702eaf64940984ba63c4610e0684fe213e7008dc9a0d122fc70975fc4d18e12b4c8d567b235176169ed5423affce25912a8f654d72f7d6a11e8ca5c4ab30abf614088e021b964f30dacab97e9dac0f740bd10476166d509d4b273189c20d5f0011213f2ee8055350a7a0bdd73718449729afe1aabaa35edf4f948a215a7b7df743d1c71dbd34af7432e9d1179a22fe33a93032f0f673e6fbebace5d3262e335748e0905568c19b8bbaab62f20d61288780995278cf08920abba3e0b8f704f57e24908d86c7a1f05aa21f4a9acaa85f4d9454ac5d3ef58d80007a1291ae1e2b5c95712edab46cfcd682c0618fd900a264d90bf4006640800fef7f693e0e21655e96a235a0464957e1f2158029e3f242332f205c437ba002ecb9233b611689d4b1572728bc9b2a54a7ae524021b964ed9054bc0676c47b260abecbd1a495cfcee554bc034b13eef69576be2d98ac01f5467e02fa4d45293d0f14a09f84add47740630a6b05e8184c3e90ffad07cdc7af357ffabbe5441c03a8e8258613fec18a85810d0408fcc905e01343e87ff0cc282c67c857135f72179280bac2f1a634bc420e0436af101641dd7e4d4dce63a06cd4e717c19faebf72110300c763e7d9c5ecdbceffb84059de8b84925adb57cb937488817a19a7504d3bb82804d4e08640a1e5162b01d8a7da90c4d1dd18c6de83167d15bacfdf6da17f8568afd3b94105966b5d36b8263ea673640dc9e67d261546a087d446ce3fa019b8bdaca8bbfda71f27f5c8d6725d929594ee29baf8942f137ba517d416474b352ff76ddd7e7957a03a428642df331142b33accf3a4619c66089c806d848ad1389459b58fed954232cbabda45221f906f8105e4cf420e11de26fcee9c597615b3fecf3c641a1a48e97c95312387f8b4e0dd0156a51b3443e72755a1297257c7721d5a96927b297e11c96a5309eeaf273440dcc8b4b969cf56be7d6914181b107bdaa10f81b6317a79064c7555544c5044696751342d08c1b6424d210516041466dd6e3af47e4173be60b17e85c27e31da9f7328016f7c63e25c0735d0b08cc872926ade70ff02b5092709a3d08d5286d45dfabb0951902a20e400103edc1c18f51045f5a3e370583bcb120bc2ac27b99ea0f923ad39bfb78d6d2dce3f3c50c21cd1d8c053a137e870ef1ae142f9f68bd567b9eb0c162e1e00c50518351a3629005159ad466738955e2339a528c676b0b71b93f6c7ab40410e7e0c7b4442c507e7c7e9a1e3517ea3aade02dfb0ed943a8e5227e4f9ce252fb373c0f9e80f986112aa9c008a09079e1a45e506ad953a2069392543437e12352b51af941bb6daf5b26e10c4c50a9beab62b0bc5dc0ade6b944f7af61b73f4fa76b4308d1bb6e8699d20d510295f1d06d23af4113d588f62207d7bd150a754edcfbe4c0e28c540e59084e2daef7c307b01dc9549272df3b4605e183b2cb4f54331162156eaeb5ac2a2960a535454d153fa49af94194c921f140732282c0cfcfbb038b85096a19763a3f52b606ffc44bcc04f0e1084a627f4013283802f9875896c33400e81fa9950d001914e959e0f1307a216e33144894c014ee640e995ddaeeb195cb83cd3864be569ef3cede0869b06b00a7ee26ab36e90c708ba48f9ece423f9a66163f8216da57faab78fe65c23f5bcd851f1865438598ef927160009ed0558e054d30c8b185b3c8ac273a01b9a64ffe853e5531ed299fa0905788db763fe2c8ed9868d78623afd1b6600ee5d544d2be4aeb99b07f906bada903568bb214b3385f26387fd953c4e227faee6aa35fa4e8a4b610c8a2ec53fb368b9e4918db8892bb2f6e3a4a7fb06a4291cd58a26fb6d91128ce2fb8390aade555c83bb2c29a03d041e33aa65e291567fb2717275ca8213f0f7c56e2087e24ac6740069bb2e02f37882648ebc0833a6948156bb511776c67c02b5621b1df7de7c7ed966e7ade592c2b1c3616718c406357fe4a91d714712ab460f537b722f334af49524712f2d78c11dd7ffbb1cba75c0ad0e3935ea9bf42364c4118075b0268faaf5b61254514c0a6e693e89934c892b82be6b4ce3ae771a802d688fc16b1429155df7f95a33550c3a8cedfd3e6be56112b5087b66a7465982aac6c53078b3decad970633f7cfe5355ad78453f3b791d88d5116ba0b5ca7480eec68aba7642eb3466772adf514607bba38ea4fdaa36b107982602e476d769aef3757d85a455ae88ce12f105e70394dcbae6d8c6b6f79116f1433dc1fc0a37c9ed1ae62d1903ef6fabdd69c10ee354970f35ce3e9acdc2bd389d73256ffd773c55845ed82d9570da64aea83a53217bbfeb5b43458d0826e26cde0797986214c0139dd076be78377c81b7266f398b455f7560ce29fb6aca3bcb801e86ced0c24ebe47ecf41f91b404f37364064c112975f5e33ae505bec1bb2be6421a7ae2cfbd3ad5f4d28b89a7f925a8646f8edf56a0182a38f16394a4920bf426031ce30f5d7e3aeef3a13e2c411ae7cf089d36c53ed7a57cacea805d1941ca8961c0b3965bba6dbd3e71bdc1f7f91e651a9f0c8acb5f66fb8106b80daf43dc10230449e9b56eb7d4a00b838d5edf151b396ce4fdb8f9b4c3f728f379a05ea623e9877119f29c91fd13722086b1db7c7e9d63a6ca800e0590854e51b7d2319fc2695f5232d65a0200091b47a811255001c2dda1917c8a73f0f7a29772f74963b90e39a8e60b8d4018a79604c37f54ce2162b6553b2dbdc35898f288c22c25fa1730748cd9fd731d1672a683e2e816675df9dc1041c4234bc42d9fc0445f38ed6c0a8757b6bf64b32008f8c045b071d564c85fd3c8415a61348f9750fba14b829d5177e7c0e29cdfa6bd5d589fc1d14eaa526d095e12500ee30313541bab14d8ad2a1f24149eb7537883b9c37c521aaa86bae83f8e192436224b9026a0e2f6a89aa4640818766cbf8c5cb717f1ec97b056da6aa016df844a4e26be9ab62ec7607fd73c5ec994c3e1e61a40d0055924043612a950009a37febe918336e3879e90b59d703263d1eff31cb41be528afd1b523f520c49081d1fc796977714a10cdf317ff6c36a2930566b5d0ae7de20cf638d96070622e302553b05a617ef704a5444b763984f552fca11441d6a3c6bc0a39588577a6aa4fc8029a773576ff27ee990594ccd2bdd6f9d31a81f3a8e0366ac01d111f68a50313b9c9cb85193d2f95212d1481f8e41e3acc25883b7f1705c70336ab64d0631fbb85485040c200cfc8c410128c743c198a375e950768215fb3c6e99145a7027329241a10f02f72514bf4942ffb6353356c08abcbb7e156b10940e85d6265c1dd214897c06682be46647639e1861026c9acad9b63b5035d840b1023cb934e1a7377431b86959b8087ab57b08e676f8bd095e8baea2dbd0a7b520dab63db279043da3b8d5c184ef0635f554eded86dbb494f98c4f7b5b915b124e26df2d0c64dedc5456d4d35c4012cc887a0a8ecb84a8cb591d09c6407a9e90aae76db6d05850c4a7505bac74ad53a830aca5ba1f2c32d41cc5ddaae041bee068c565d766aaab05a8f6a2981381e3005d8e790e47e43baa07c7b720c8b8aae25be25a6838bf58540914d9424e49525a5ae4c198e3b149cdf4862c88c210b774f37466d63dcefdb841010c71e8823428e86015d6d346b1455fc50c51df200932283e609616dcd93d615704697b04fab3408f8360c2efcc9e0dfeeb04c2e543d40a341029c0f3e8218736bc0aa079a578e2f409990cb459824b2da708a312bedafcae64d5e202b4b2fb4f0a00b326e6326651e19207dc530e1e2d09be55e463f013ea18509ae2c014121e68d4cb194d00f86668df8ceb068f93b15acf7dddc30ce95701949508ee8d0e55c2fb49fcd1475ffe074b3cf5abdfa5b7aee7ad381d42ed45d632d98ac3ffad491285e9ae2608ecf46cf5fcd0443938ffc1a5a1c4d49f83ac95bd138ad5cdb4eaea7037345557ae1c0d255528059c10a8fa067d1049b287fcce22ebd7015f7f445ba974091fdd1da9e6f691668970467f444187e710cccc5f77f224094b48dac848b49f65506a079e98da82580606d366ce3555a5e6b90293b675271914854e4dacfb2ea2de58fea5730e216ed500f18c17f3e642f2df8e88c8ea1aad576d081c58b866beb7c7a5872f635a4ce156558a98eb8512c75ebd3612b8e377fc9dafba22c6e5c2a88035fad10eb60e8872a283c1f80c200126b01f995f4618b56b924c9139e01c6a7753c37bec63b948615444429980e505c422b4f658104e03a683eb80055898805007d79a608f7b2c15935d19b008d663289d46038b541e0396297df638afd580528dbf85e3dfda15f10c70705fb0b3f2694184109e2d5d25c9c767e247c22e5d2513a45ec02cdd21b2ebca18209aa648cdbd02b20a113f5a295f772eb30a1902245fff79142166352231994521496fd8ab1ec6a8c00421c3223290a0c562b5549a04b18e0040e472de7ecfb792ac3a1d813e9db44d39fccf4ec464425c056c99fe0dfe9d625ec81e3291039cf5323fb11b155825c6fdf561f28ebde728012fbb01ca44e6dcc81b38d66bb4342aa543ca8356eccb2b40d8461d04a600e27be1530575704a8b4e0c02635c96d13c51b10026212690d1814aa065a883d7e534265bc27ffeac1658c2634ab5f4a854ce36247158dcb8438ef84bcc70a262c77f0a3d854b1085181e098d693ee07c2802ea2f10ecdbed6ec4204a071b12c3fb10cd62d28537b5349654b04a2de67cd446527eef8456881c6f02d69f8ea3f0b180ef91e07fe1d304fc6f7e91eac1ae76e92311abe834311e596fbd08f830185aa2ba001e03431a95680531e67e880bd4d3af5144df9ded5f7a4732d23b0d24480138c47ec913d0b21bc35fda48ae107f0b1e21fb1bf02c0c788840dc64cbb2ba8850324c954bb59c2520ad25d74047d5f45772c16efec36a569c489bb058c0ac54089822b8e653eb0bedee244a5d4333d97b0f401b23d51ac03f950cdc0255994c2c6728b6402c0f03944859c5d364714333d4fb406e93dce3dee7b40feadcc10636f2add1a64c5df50c56b1d3446957d60cb2de27d9e1b8c9f921fe1f4a44402dadf969e6f2d03e434725424a10d596f2f0ab21d589d624e64be67ad6213e08aa9f23b4970920c70358ce31f3367f92a0f0dbac4534615308fb338cc977e8428d0ff7164a4b05298d6710edb4a97c4eba56d031fcdc6a0b2e91e82ede9de3ca048182795501610cf32e973ab524781a15531b04abc0a01c099a8f258bac6035857e4b384d9fdc899f6e2addb483b3fa7960d39a41ba7f0a0a809cacfcb6e88f42351cef124187bd9a279ce6633d1f33c492e5790357bdca2f4ad624aea9661add86fbb037437e9dc61bc76190c6df23f4a6e834d254824dff961eaf962085219eb5babcbeb77522a55a9af84a5f8d7ceaa05ea58b3f9f59bed095b67de356d6cb6d1fea54daf6d98109514688ba6780de41d7ed6fd04880d3d04f357e5a8d28450975c8f987d86dcbcee8c8077323ef2519d63a421461b3f6d75f5175d3438314e35951e3f6e9f1d8053ca9faf458df846480a761e2fb93bc1fe86fd1635e09954e3721e913ae1886d8d94f97f46508de682acf28e6d864040a2d6311de087c9511bdb4e3706a3eec9a909b6432495593da19019721fd98a22a2f725391e9749ca491d1b64ee46bd4dee46bdd775d602d95d490de2a809c9bce27f1f3feb754bcce8546fd08f78027e646557ef01c41ea1dee1af1392c1a0361e716357ce0cb7b696be6dd79173b60ab124f1e61386630bcd30ec2553552689dfeb12ba9d411867f5c7c4c6a445183c3f6526604ac56afb061a881b14b4a7b7dd952a1c905f175410c149bc0ab9671117a4c237b2a344ec77905823138778bdfa25eafc097e7ea618f0b6d3cd2629a020a0de4b59a604802ea744c07bfaaf1288f083b50debd4f62d66092cf88baf8677c0ada54e81c6de19dd578f0de37dfc8dfa7d1f3c851f978b5f4b42bd8c990619fbeba4e6f3498ac946b1732c72255946000dce8742730b3728837066602a7242cfab7dfd11472f369b3df46dd3d13ad19987615102180a822887f97e32912f299e9c11bbc8791fb8c4b6acacb073a2b159826589bd3dc5e8cf0eb53d844ba78130a5ece095b1f0fd94c3654dd501dbb6941280a010d776320913aa789e89db66d721ad3416239faefc11e872360c3bad5d16c3d9491fe7924dadb6a1c6f44e66f4f836ba76f897debbfd48381eb20502eb19e48fad6abacdd95747a513e8fd3cd6274c2f20cc05d2594d0396397c8c16fbae7a7123e4be67ed6aa24abeba1e1e43edafd0753f0080a4a11c469bf712f575faaddc07929d04c399f38528be6a3f4306df394fce2b6531b7f8f1c0359f7b968884fabd24d4dac5b9ee48edf24d07e4a1e921797c31952bed34065810512b3b9485ad3955af15f1e67f595d0a08525003cbf5fdf7e5d5c527137a39d92d8db140800b93aa1b20f07b4c5aa3d3df61890b1cb7e6dec166b0df6bdb0a63d5f6682a5390bc9c5af895e869b493f865eaa18e829058feacb97ac05781e439af54c41ba506c4433d6341fb24754f1a224762578c027d4997e7240b08081a5be4107e0e7592cd0500d636f6255a7b40fcc88981091a8520203443f32f46826b29e11e3246c7a82205c62235af7867b91605ed7865b2aa16d62bf38cb05a689e39d01129cb3fb92f23fcdff7283b68d80581c7b3142d0c1d56b2b29ad5093d00a5cf746e016a5be797dbfd8a01527c82f7906287fec8d91f578146063c94eb637ead774f2c8e79e024eddc5f7a5ae8c80739ac7390dd98bbcc7936290087b71a1385d13cadd2ee622993e9776b8db6e5521a7ab892b632e141359cd868b1071db241fc2dcd49259e0ef27e481bf9be00bebfde8c97353077bfa69d12e3e435cd143194adb8e1896b7edd69a68ccfba43f1e38d96b406efe85606549dbb5cb694146e9f52f1bca0e3ca3fe19d751f4baaa08292c0c76c0a17b21e6fdd04a0db12d5ae5a75478775ee4aac8cf72ed9539700d50ee1986eae2409cd7c3da12cfbf57920934b752542d8ce6f5831d9d1707d12a2d427192ace7ce0b37b2462c69b9d5633d42e3c2d54ae7b5da689b14f8e84d01b5d588b370f8a4e04f115ee51efaa69227549777ce54ed075bc3d51f139182b469764b9185f5c8883e11dda65964d01e54d8631bb3d4944abb4b16b212ba2f6455e500495dc5113d28148b46be3f5e2833992fc0bb416e441e9d28607b72d89d5a526ad2f91521384106bb1e43ff3a4a71935c139d46e94e71d7ee572c3a0508a7aeadd323d876ccd9384c1e8e102d7ca6d97da5e8e57c509094a52b3c234839047cc76c06b20861e4aefe4450a5d87311583b76bf849634c651c0b158c3cee05f6c641aaea5410d924f4bee0e3d0aff83b2e55420e2abb5ce26460f0cb261fa0530320c9cf7004ca212f4ee04486a74e493ad33a7d8cf1dff278a82c243da38a123241865fab718f4d5cdf43ec07762481d6da09c0f0c6c69464849bc2c826f190cdae0a177e80fc764312aaed274e636c1b23b67227fc6e9536a31a0f634fe196fff6029ef89dd4694886bd0965b6878b37910aedb185792ec5ce28468e95807d11c0c39adb98f87297403cf8664db0cbd55e3e00690b5a444603bd01b55a04f2149556b481f58d116f068e50da138c18f8006373b965eba8260583c22f2baa953eb86bcfc7b2d6119d91a9e0d86b94795f01d17b8c419fa50708601c0ce651cc75e1d5ea9c6340d2395f643baea0ec81f173fccebcf57c187a14ffe8774de590962334b3a9f149e320a886843c650e4ef7ca0bfcf9aa1f9acdc989acd73bbab1fe0607953b42605d9dd3b1a4ca79d10cfcda726600f7531db4442c34d2968d7003d6d98f4327deb0e4f9acd448bd83e97c8038ba7d81aad7ec13756fab171f83778ad3a38965a87c12d80d53f36f7c5e6441e52da15b79a9d397d8eb1a8a95c0565b25bdc6aa6526ca2a168bfcd34432dd20091ea9839e1419b11a1b5245e85d08af241c7e1f6d8226d79470570fc436f7d116e3b5882f7263e83d12d7bb69faef5bbd68319368bce8357302a8630a803d1fe89c4013c5125e15155f7373aefd3a788e87e1cadbaf034d7e187afa8decd62635d00928bc783c6076b309871c0bcc28896b42af533d8993034f30383abe7b8d673b2a81a02a4422975662cbcd26e7aa06a495a43ad254582bd802401259a95bc24d7684f1df7de8ffa7cb443e04e1f720d12cf384597fd2ac759376d78a2ac3bc7554de70a1ce349e620bee7a240488a720ca2719d0cd52db4888fbb38d0997e60bf11fbbcbd6976a6d796bd63b38ecfb868f3f6feeb437b7bdd8b71c9d1031a1929680ee299bccabcadc4a55a883490df389a8a0d6d6762649bcab0ba7d2d049d821dae6331a3b28d5187c5afed7c21ce99d5b01f4a2153dfaeb68823f0c147c7efb7e9dc4caa1726b5e5dfe4cacb3f9f567e64a2684f2cd2a309cfa346d96cf2d0fa0a12321217ef181313e23a6b4637980c3c56c96c865da1af3d148789e18906f30a6fd233702d4381c8fbdc312cb1b411b2d5b7f71891a943608620090a22833f232f9f5deda8710cbdf2efeaada4d113060b2a18ad26c0e7ad42ef2de048c739c5580069bd35dbc8c7234d48a4b7b66852ef3bfe9a938ea4431626219ac89f5ee0093786c957e4eed0c8599e482f297abe329156d2482fd54eeba85b7b32ec1d616ad236511056ade5079bd9edaa3585a737882ce4d839370209a01e682aacce33fc8130bb3d384c496b5342b06b86ccc4d0ce3a9d4ed13be31d1ca88b9e05e8db6e04068cbcf4328f59ed1e181865e1199d1c749ad144ef8f62135fdd994202e7dd434c464d0d3169d4ffb8a3b58d2850a79042144f39b9bf8bd8f3c3202dc43d8fd0cb9b6a1c0352bab00eb8bbf4247f63e79a382812a60276a8ec378bfd0feda9b0aa55142cfaed07cfcec1841eda73c058039c879848eb5fbeb953314e320bd1efb4e5db79833826cfc37be4942af1ba9066083838fd6403035acabb308b075bf43acd12eb0b8968d15516450e3cef4e4a276ceced81e2fff0187052431d3accfe062ec45e4676a935d7bb16b2343e92223490a68e208ac04f292e413860dbed642f4f595f93275c7199066689f37cbdea570150b6f93a44c981d2d92b918592cdb762a1bbc51f039a21bd527bb8d3dcf3d2d4637d484eeea26e491f254ce82b82f429694fdee245306df5f3399bbc2992c9c0254fd87fb754e4848590476dc70cedb32dae66fff3dd20ca57048070c8dbc14a22360bc5442d3e14cf430adaabdf0aedf75fb50ec2f02db5bb2f9d4ef3188412f4ee97150d44cc37c18f0bd5f57ee8a376cb8e768612d829a03c473dad6a9651cae9fb4bea2c4b2baf377d88d2b1496c24c25227b48ae983d3d39f6614f6e5f165445f9c892b8f602307a4044a61fac9d144c736c0ffab5a40be92ab4832efad4713b9fef024ff174e23e6cf886638652e4c09ee1d099a39f16b50af6cc8aa80c56edeb675d50563016b5d5a6c3f0d790acb48a839958216fb980c4048f4b96648f370f3ccc4bb2237d9f602c80beee95908b0715db92ad2b85c1989704bd4b41bcfe6bbb208990c73fc039c74092c3197f1434e83a92f54af67a23cb3f4d82b9aed6b33cc92f9a3a7054d42068026cfd790e3f7a0b924de1de639daa7284c6731f51e048ff65655d37532647617159a31d2939052f11d04c8ae6a5b968e655fce5178801cffe9b26ca5dc63264c3ed5cb6dd39a12ac0d88163f662f4b145c879bb90f07f787f3777ad03c37731948bcfa5bc3778884d417ba7b8b57b90940defc0b0d76d6a775807d7a3eab14c53dced5a35e0b0ec19076cf4c1a7fbe6738dc905498a54a57c9fca57ce3bea6a709d81225b2e052e9a962ee6f18ad96de70231f6bd6f0f804d9ca5b9dc7323bfcfb5752769362db2ed9747ec823a329c08baa2d3536a996b2384986ef9da0a1690bd8ca782c8a59aaa48e3b3c02985b50b780cf6208484cea56e3f29a7152427159c802046ab15ad675ae6e2b44bb9d20f5eef1013e3355363dd3a1cfa9284dd2d5990b8806c32fafe2ae2dda9c93ea8f9e85a80900d2a1e916f2ccf053f62a197a7752f4fc067b2c556c8596874147d40f3333fcbc6332c11e0c06d8eb069c2114104243be40643b934ae34aa7b1c30deeb718ae21bf254e9d2cd2c2f8bab79a5cbb0c0454de09ea03029e6b369b27290d5212301db28179f08b73a6ad5c7b3cc8494671f2bd02c2a666cf9b32ec34429c9a378d960e9188bcff999c1070c9ef8332c64e2d17f4b9b0c09dde168c4c1cfd1f73bc6e6b16c74a1a9e0ee340e2ebc2adc551e7e914c2f33c816d2100aa17cf46647f688feedb53ef5043cc1c6f8f481083d404099908e763a33205a358fa7f30bf8b105ffbf6ff249bcf1325a6fcc9846ce0e92eccddefbfc2f0db402d3db28daa4117b09cc220b429bc993ad5ace8a90b5835d9f1863785379844299165934e08486d29b78f56c3d30e0605f26bcb12a071b03df86891cee2025a09a66248d9ff2bc9e8ca8e0c20259fff63fe4aea4e2b164a696b1f1573e692d499346986e94329cffa8ed0c8d05a5f57e1de2f4e6a30c9262a4ac52fd8b97c8e9df6d3d0dc96d4418cf53a0114987409a870399e968081151510d6c4142abfbaacd1a3281d377109d3be2ec848afd7324cd0c139f6da990be2d9cd424e9ff976968b30b21eb67238aa552becb1bfe239a7b6f9a3756f3f6ce12b9f8849945488bad577bea9caa83ab531729c7d72477d799bf2b70ab7945fd75a5358c18a2a6bb80d94e38a77005e581704133f621e424fb18b9ac042042acb8da9f31d9e088088601208b715328fba07ac7241db8c2293c3a1779b3fcd5017e4a61ba374e5d72887e2a16c0f809ea013688e02a7e17af8d1cec34550f74b931d9242c5c6b68b595f1ce457abb13f66f9e2f3909b21cb230b6acd344812b3574afb5f92fa264ad5edafe37c8663f0cb6cc2e8acf4f3bc27297f14b71dc03531a35975f4e15c84c12ae9fa894c5141e97825145b2efb5fa4103c463d65034737dba107fb124bc0401ec658c762f968e6acf88a1cc2026be847cb6df4a33044758712ab71d91b87f7dc955985616e57bac91bbbf309cbd5549b429f448a6dc87dde1968c261f40e210634c134f578f344b43c3524eb9001104c2cbd8a668986ef6b3ac98334a85b13ea13135cddd01ed144811ef4516912e1e9028a8dd8843f84842be9220180cb0429b03a421aeb6228da9dc9d8d0b35d8cfd46fde9f0b1f2903684e01eddecad2843cedc2c91dafc0a69e9f573e288771407d28bf04b063ef31082fc38da84bb17c3bc6dce9400a9828fdfd937d31a4c02f612f1887463c0ff51fc53ac4bc4f75f946829bc865bf24173bc21565442fc521e22cf20904e1ea0e6423d031b049348adf609cdd761da2039a12290dfaa47d45fe2c763c96c80ddea415dea1666ef64ac2e2e8c95ddaa22fea770d36efe727cad17e61d921c960977c14cdf19262c6862dfcf09a49a766c7511d49131fae1e064fa81cd0ab2e25e3a3eaa46b260d4cb8e46ad71161879491da146a542e9b52fdfb1252c87242918e90a3671882a8fd42e6d70dfb293fd490cb8845f2821a791c438b83054f5c94dba76d46b61f65b3afa6aa5698ed4b45ff5fc10d69ab5feeab16f3e857c390cfb4351f401ac4ae4fa06a73ab3575db4a877f5cbe6c17d6990bc2569c2337665397edf2bb34e16894cf233384efb7f599220d5fe247712d013abdebb79a63baee42aa6d8eb8161b0cfb8dbade108c29dca5ff1decd7b12eb0452b6d638c59f2b10dccc95c81da4ef61fe89417a259e13e4327da78d7a255befcca91e135f5d8e3b529165cecb4635763a0c77d7a5fc7242f05d7a4f18337f756e40d1f5c725a15bd1e85f2a8e80d55403cea1d121eb41a9805fba441e789a55d26fa5989f6e29c87db7f84f88144cb014c0a7d10979c685f5d31c25ab2c45ff74a343aebd857d42aa40a8a5803c8d9bc81e1789dfc73376a6dead9dfc5c0a46e18ba1ff649a75ceb50b3ee7cd5134a2ad9f79a65c786df9e7181b52361ff3077eba7fb68b8514fa9aa98fe59924e2d0a7b3e78356915e0f5a790eff0a5acf60acb42975caafe24e28f99d0e0a967b37c493165af1305e09b3c4888fc4025f8ed10e69efbc8ebac6c21713927377ca2a4a1d1d698e4c1d64a421a8799c736209a1d1dd46bcd8a994e02781df00941b7392d91168266d1e073e430881f24e74b3142e3ad56cab59f5e4d359193f79b09b23d370214d559edcee9a00440c5d5ef18c7148f10cd0a845b864a9bad4308eda6640f99061ce856ba9c6fe55906f0ad5dc8789337c531c7b2f2d2e9349f2453df7392d98f06b2072145568fafb9e8ebc1f19ffe69ac653857370036ac7fb11f373263b64957c8e9e8552ca9d966455990d75cef59ed60e33a3b3ff55ba2546a73b8916a614f9e531f8695239bc5534fb1b5247de79a8579795f1ece42fb826abf7ec54ddc81bf7ec2c2a7c8ccacef723e3df3c7aeba1b016eb6cb6c87353adfb8a2afc8e8acf9035ceec162a1e6b76dc2c224cab1b293476e45cda02e8f1f2d35f1f6fb752ab06f1e34d786a536c2906711fcfd29de7f1449ef05c96d2a73d8d2dbbdd2deee5d0ccee2e7b2f2fd1ab95834b98669eaf039145a0d6174fe85a5c245694e9b4877b904656c6aafb8b0bca9e8bd43962dabc885680e7dfda6eef6b8cc25e2cdb17d060838645303e057dc573f15a41eefa9d0539c2ae27686c22bb986c42800fe617313f678be82981e8e0a11294503ceffe5db8dee5c17624241601ea9700c5858287ded5be24f05ae5412ce027ab24e22b5e888543849f34e42a09cce0746160159186ba5da51afdd706e625766834a628c2d2addccce983076f3f64b17fb3467f0eef18a1d58cf29e792016f71e383fcb2df61936ece69a6afcb7b3d8ecc84bfd214d79000a9725fce0ba5c6679caa3d021d7ffb50d80847dc31daf91341e1878b78caa56e207f4928413c481f38db8a1f44beda91fa632d3e7ae62fc2b36e878c5cb618b0d14af23055dba6d0a60fa40b6b1aed7bdfa6fe16d36c856b900c4350ba4c94b94a764c92b894a7df093242dd54faf731f7667c5bdda4be4005a34aa4b62cc443599d5d014e3c6fd9111a96c621acfc8ad6e308ea766d11f1773039b1dc46e981bc790bb9bb9952eebfac58a5448b6788208a86db7d3106ab2efa24735fc5cf84b6c13d31b4687dbe4da89efe6632fea2e1a341bfce6deab7f1725115f82013ae2753770fd26a8c9768b95abb889f1b2600650e12634da4d524edc699e21c39690b61452eac0bdd8508bc08c171611354ac65d17ec2fc5b6e494c7c94034e0815c4e8141ad9a61c38b06ce54d3f02d3126450d22fd5e332b1777bc276f8dda7999f6658f04f98f9939fbf343732644317fcd990842372e04d952d50d9f7cd278034f336be9398fe6f522df18e3a1a14c9414dafb01ec47c4575bfbe5deba37492c58df0dc815d88aad37353a9ee0d083e9097947d5b5cb7f2301b2674a728e1e5f10a5694ad6fac04e07fecc38e9d4a49e80df558c2ac46e91a92b8170474a2e672bb38978f72328b1c8534b552ec70a698b7744cdcab546e3c7a22dfd44f704e3512801ac4aa6e8ea2a69e53d8ce7a5e7b0cc984cbbd72d45328317e086ea09f8318a73036f58439e0ae00d930d4a04296cfe93966240e2c071b6d6e59483ed1d3429275023d5c44ed411f37a187cbefdc3c796c1f00e93d11b49fef424a89c188d057c0da2225c22c1e37fb5f41412f95b86289d4df54f28f06c1092126236821dd2817584345309a90b663832621bcd10ca1d958c266b11b12c167c041ff00efdc7280b24b809618cdc2c85fa25e3d70453d2e8703a0156cfc9fcc6d16a42b0958367c902c9d2fa3574b02b1db7bc62fac81b0d4bae744105aa6a6d651e1b91e07fdc158c3cdb94bc770187d9e5c00f9afb16246d97c02d0b15c065492557794cb53fde80ce93f3019869bab06e9eb7a48f652a90527426b71c96089bb1da2b313a308dd07615a6d285a7365b8031155b3a47aee47d417fa26676d3a8c6131f5db3ff72319af179d9dcfea3dd0be35c552dccb35e3eba6785d357f7f063a4f084ffa62ef7f093805ab2974bf74723d4df3b7c570af3e59dda1ba2bdec118398682ce292c251636dc3cd0187dfe671bbad8bfc4dd7bbbdf4f1eb5bea951306296efc03e74b673905a200462f6a555874f720136a3b15bea913ed439b80cc3fcfec2c64a8f432943f395a17e1b52b49ff1573052f12b8eeba42d7a8efc08940cf46929110123caacea6731149ef05d5a1b88e7a67bef0839b8fd260c284292fd6c197639c8befa6741d5e99bd50efcca53e32527d191f8c9e21a1291c5d3c244c60dad9f064b64175214374ca6baee9dc92967bfbfb87d89fd4b7930ed3063ed31ff74b1fc4cb05a82b382aa7ce2464aa6ee0a1a1023986ec4f8ee24d963b9cf0f830296d1dd34c33123c123b81dcdc88f077406203f09101d5a88e2e38134c708d2c7032dd41bb2c2b38e5ab28745d49967bfffd4f5c4faa2b91096b073eea77f7a30fe4d545c4299daa53e5a4302b67e0b071809d86f04f46e135207a4f49657effc6436547165b0e3827b0fb817df29572b1787d446bc5d4e8840fcc943430d40d4d65c01f3acbaacdf13a517a2f49e5bfffce4f1d4f16dd1b0ece06858170139fea8ffba60feaf502c4941cb55325328a919c628d748ddc0437afaf27811dac5d15a970f76bc00f8574e9cb147ce4d0a61fc36e9074a45f831f0e0769aaef48be184f4269578cbe384244e4f556e3644ebaa6ce5435c0dd72e1c39c7ac5ab3d17d132df78fb65c913bdd563e2bac3f7f7ebbee18b7475917865466d2a92f41fcd10306a50b0ef90f989286c15e4ee0b49b9efbef7b7ebc865a5824102c9cfc18986e022c4465f1fb958cabeaa86431b5f673009a8e732d6b45393be692063d8d2d7bc3ff3f25755e345cd020bc4574faec0f2a22bc3d1cbe6e7e02682f185d19f35dc9aa85e5882f1992622857d7f2a96998416528793756ec9584c3b88ee38cf40dfc9eb2bf79c48ca78efcd236547a8b045189faff8ca6586e9de3461dbfebd0ffb0857c1a61e69bb3002a60932c84559dc60191a06bb8882e8ea1f0cd84ee06b44f538c8ca7bf3bd4f189de8b43c862b1a740ac222ea817fb33fef1b3e28560b125372d44e9548cd545cc4636320d0bc287f4e496e7d93afc8d3c0b272f18dac8cb7de784468a476038b63301f29fe1c406c402c72b034d4d10be4040f9c914544a6bbbbf1b4ff299d636466ea1cbda8c84a0919234aacc194a9c6d79c4065bc2199507c1a6d4d09c29aff0f121d0689004a0d75e845314b1028b682111637c1cf378b42e2452ad15aa2c04f4d6727add9fd18f043214d9a925e1490acca2fcbb04a9af82c69869704ea715ef48b222fb90f33d334e97da9e5202f14da85215d723c6dffba94bca07ee543456a982ce644a15bb8b8d1e649da899b627ef08561467b5f06aaa1a8d37473d1f369e299d5d378dc480f28e53b6c3b40d9d0befb6d19153c0e3801944421609177ad99cea7c2f88e9a4ec546f9f8ab8a73a85bb178a3aa8af6ce3b90665e78d1651c66c56a16c5e79438c1d5f4c0d03393bffd607266af2bb696d78701d6888b584e390789e1a1ff1edd6d6267ad85747b1302471ce97627b5d4eb49fd7cbc49830179192fdeffc394265516e536a7c9cc20dde2ce4586ca0858bad118b19f5c24dd400341b231cc2b6906630cc2c38a18a0c1d03a4339440c01d5c0a11bd6f10d8139a320071e96e3e344ebe82cd9d1af3d95d5dddc951b7d7515bff66d5a0838600d1d725f3d81ce1f4c2c272e6f7c4846703e53dcd26d9f982a4aa15443176b1c3bdb3a9769b7dbe3905cb28da1316b4c124908ee2892d99b5ee69fdbd43ca2784ac0e32dfb1e2fb720fc9518952a5c3e8242bd5ce4805e1b594c1782ccda1a4db3f42a308fba4a0d33aa9a0a17659d840266d388331880f12a0edbe3559267a5f3e78453a35df8a10986ddfafc9b56847ebc6b47b91e1d8f9c81eab80ac698c9bc6dd8fea13a9e0c5a36d68e13daeae3fd4b60b48a655dee21fd3485a0c0a122cc328dcbf2e5d636ed7a4383260b2f79f10fc6da42c56b30b870b9e0f16b8db8fb3424a7ba9cd8f252316418b45ea1ebeaa32af6604a511cbb803be9149eee1f72e88e082aa312d7d2ec4b06d0d2375113244aac2a6b24e11a3622740d1926a842e6aaaf995a5c721c0779f8f86625ca8f42ecbe7faf610af5984bbd564432f007b1cb2081884a38d6fd724c8a803db26aa84db94aff22bb41b2cc83bf5d2de5756926bbc94c425db0deaa7b276dd2bfffb693d07d1d9c651317914cb293b0c27d6d4a4c0a9e8723b92d49a8a1a469c14719c4b2d7551e524c2b886dd86591b6b91c43a6dc1e923aabd02c341094a54079a33549ac449a7aabd3278286bbed4621e11b8ff797cc283e6daad8b517ea272571ea72b8a03d71957689036748cff24e64d8626f1e3e5451233cc413c1125392b4e62825d4b559287d69c77bd610b7eed1d6b3497f88f745e25d73f3376af7ec36327b262fca0a603b5afc07f7207df6e515e34d52440af5f0d00ff961ef8de191a16e27dc91e99214e6641771470442aa41b9c65c46ed66cc1aca6099043e0626245587ad411ace2420c7c787ce46ad3acd8653f964b9b8b16dea4738daae6d30330a514bd8180dc0081f461fcd4e59461c8bef180c2823691c7a0d40a301e8360a8d86a1d90874da400d4275165fa3550b5428ad11e834064d03a1db08f41b424336f287ce86d54850c2d7d2634b04ba5f24867a908e3998d52b08bb78e5c383dfd3e474a93673a951843b739e446119090189769b16a92543511b2766a137fff72bfd028e36c05022b3b6900c3d96f29d2b16f432e1a814a439b8af2f7a9aea3b6191fd8185ce32052eb038c346b2c00e6400d2725a4463608d7365ce6c90b7ff4de888d39aa119a2956536d2704a0e6e452413a75a744c8004dc9e7810a833f1db9807b737210445d71d87d14339c692a45bb40f02a502b3fef7dd0c38fcdcc528eb6a3ea311b66549246674fa95b1e0e1d0ed8328731be6ea8f6cd65cc2e5a9cae1db65aada2956a32e35e62200c33f8312d34f8e36d4102265b2d28c091fd371e0a09a28df4701c486bd949f721e71ddd49269ee98b999448dc9f91f6154d69fb69ad728358e861c4f84f7f54299366dd246b3be16318e514bd53ec47405f7f9ec47a7ae99fcec37f80b8a036d61949cefb997b89e953dd3bd1ef7e15916bba8a8e306aa94ea84c301d0e7dc90db4ca4b7d6d5e5aab3fd91ea1a5c54b1c6478701453f41137b60ef09a5f814824cec297881c8d792c5ae076deb3cdf51fc91a6e945144669b83c317171b6d13cf74eb4a868a587725472910bd5b8dc07b2699f623a52fd68313ff3a1addd91d47e7d03230e07bdb5ef0650801093f15f79f17f54eb5788c9afb094fcaf9cfc9f5a99f55f7cfb8f93f1bf9bf4ef7118fa2f2ee14ffeb8ffebacfb6a53d64ee1bf4892d2d29eb61fecd9efdc5dfb2fb5fcbba085ff2f22f967d3fbf746f72f5d98fe8bff3c5c6a1c84fbdf7f056dffac9ebf4ee83f89b3c4ffcacbff0bc7c8ffe2127f9e9e7f6bf4ffc280c9ffe28bff332b461ee5b70477f67e06d532c62afdff950fff351e2bff8b0bfc3ba9fea135ff2f03642b4726867769ceffb555ff637801028f2149fe8b94ffc94b77ff756cffb319ff8f927e1d3873ffcb96988bf6e4bb2e751daa96055ff437e2485172b570b8390667923c11a470f0a43138b3aa0cb6780ced84fecba669a7d5b5abba67adfecb6bc201cf35807584d9733efd695f38db7f69efea23a5ffabf143a7a20041786f138cff2a77bf0d1338e13f34ffffe612795e15d532ba3179ff45cea1da83f6538ffd656e2fdc070fbd1f3efcd7447a345a11bc7ec1c18de8886360026c16b9e8ddac8d636a8b5ac2f5198eb64102a9f73fd1d612830d738afebcb5b8b139a1b2b5763fc4850a6d3ef297f39727a25003fe10021c2640ea88fc6f8454cabb38c6a1336542f2479ce890e054982b518ae8fb0f26ad64ba94bf1bc7b9062d889e8c48fdc1d6cb4cd1ace5189aeb1f8f611548d6dd315f07b3adacce0cede3cbc7f56f51686169c8c8345ced23933772bbabc6aa8722e82567ab8e075c0cb230c1676fdbc3241a7077392b756727a04d5164f7f622a00bc5a5fbbfa3b190c2a66bab8e011a2ec6c024023cf9b2d186d8efc9b4f561b66a40b9443b3137637962959a904244a7d2da1c3e38df8d071e6f4252e7276e8ad7d38d37998461cf494fb3ecbd9d13d5d2dbd8486b6f095d430760fb6937c7e5608abcc1b3f94fdbd93f83671bf8b14c5e88d6171fa6e2693013dbe64e3ace79a7db541f8222b1c770112adfbc0669355d5f685b42415352abbacfab5cf97454d7a2b7148a981b3e866385087b15751448a5bcc2cfb2429068627825a83d62954aae6c3bd53d8ce6033baff2d9283f01ca1f45f47cf2a7edeaea2632e3178ff67fe3f8a3bdb15a77fcf745d503e50d9d0e3f89aa3089086324fad7f15173b342b6e315488d4751896202bd57f41b6980a37b808d275d3de5486217b5831f1c63c14af840c41784b5112a45ca3f7d20305154541030aa6f618f23ce28fa168185762f2e41c4df0f14523351aac2ef3ebb3de6038f0077ea60b897c420ec1f98417aac5a55b48431a3ea078d82b1109d616637e5cfc522d477bb794a95f1082f958a60c48c4175f2a95adb4c215ac1fa1981a858f1cfc3d2c8b8666da2e3b6dd5671e662ec03c7418bc6c4212722c9d1a72b7638007ce5983ce5677055f051b6a5c1735c3117377886d5ce2ad20ef98da1bba3634d638278961ec2cc45cd8a1cccb0c0ddc3fc3a32c40d9a4f676a28690412df34af2465e3468e873d0229b7773c4e7040f80dd05bdb0b0e53ce94221ed226089df6b87db5fc2170d4d822375affed37a6436d9d8a6b9046d85670f148579040b58ed67d7e5ea39b3061031298237e28a041b36abaad5e241619e82ef8a74081f6aba88b2c4460289b0abd75a09bb6d2187ef81c04b5adcd9d1b91f7917422ff18835e1e363f338fdb16146644a138c386f0aece3b082241220a35e07f0b0668ddd689c7879943a4b6d5db8598ba312a5e30d257129a22f902ad5991ebe95563be466326157a91c2d53253f3fc1976431f88a06cf8715a528d2e027d3627e576d79ed97a3f1903dd69c60efa7c528453d9518d120df88cf306fe415b5dd5c05d204378a61a9a7729042826693c5c4021002968bdd3d3e0a890cc0982486064444bf305e77770da3f3f91c10e55d958769916bea0be5b78184601f530ff2e70f022100394ba7d11c9dee6066274fb98be4f896170aeda2befd84d60ffe9399cd264d217328c574a3561396c9b04dcc2ee2586a1382828b8524548f2dea58201733217695aba9d6c64fbf0a46796172a5406659c7d91a9229d963d6240a81e4b195cd45f09d5366af3eb4f402e67edeb5fc3a6881336ee9d2a6e2a5664526a5ac804bb662c3ae41fba8369ff5918a71ec2909ada78438fca6ef91b65fc5751da6ff449142e8e6bd3101fe6585ccbb93bac737532c1569c435a675396a4f264bc3c5bf186ebc6d511e47684455550ab8f344b19a2b016181cadd35f84d7507bd0e395d158681207ecc9f03529a1ba66d94405fef13966af3583167326dc8dbfa7de8c7dc6d1840a4a900a35691cf83cc5c9dbeb01331e5393f0cd37cf0553a7c75f81505024a1f466e038fb73006e792ef439a5e35c9d43556362b44ce3035bf9e942cb8fdc9818556bb4bf6410ceb9e91e1a2b1a28d815408c45d7d8b389a96d1cd2ff3a519725a267775f2946656c684c4ab24da62064a273f561d4654e54c4c4303bb9aea87aea3e2d7953cdc719fedde514d0e3635feef7a37151ef404831055139e995d84bde32e18dd1bb4ec69a800153aad0d25ee44273a9eecc28e015b2ae539c14076522f8145f14e21a2df408d8c417bae7bf5d94ee51e2ebe10421d8351ffcb0b35694ab2b5f564bbabfa7df47ef63aa100eb72b81e6704e2090328e5547e94079dacf38a65887350944d56661ba1282a916a6225d1d555fcac2713597121dc2e8451c97c23aa49934125608267bb78fd339bc6b436e259c23d7753f511cc4d1805360bbe12bdada2b08cafb878025cc5c72365b15673ad326a0305e675557523d09812af4b54b352dc39cff278762cc33c2c200309cf3f73421274100259a1c6fbfca5707bf27ac4f1acdad89e7780c1be40703bd80224afba6c03a57fd2ad61d6a1fec9ccbfc57622fe10f189831c94c8bdcacd62b27cab7b3925ef5738a85b6b7e340b367cf9c62132b0989837b13aee8d8fa0f548eb3adc519921eca814e1bbca41952b5bde79c7b518db9c4fde2a69b64b92fe45185f34620eef22885b4a143fee4ece91da5cac444bd517d5833ba1115283b3680267ddbd659e89e02817bd5750e28cea29a4a65f32c66b01b9ac46054b3ed41c9dbd007b149269d58be88581349485832bb2b0b111ee302d110d3b1fd528070f52d822a76abf10375e19f1f2e1f59d2ff2f31c850bafa32f27242d70bea093ab7745110f397b754e267c7d2fe5f7288c5f517d46316b759d11cd902394faac175da31651ec85f96e7799134fc81c3142cdc0214e51b4a47529cccd2d4e2203da294f8d6bfca8ea497a25aa4e027f4335597109406304c2480e43a609f00ad8ec681ed3d736028402db8123b30cd79376cb79506b1852059380d48db2decc6086bb4d6345cc8d10bee2d78af20bd05f512482f41dd4b211b2407d46a7305d5094ea2bbe921e2454c0f385f2726f9e31334ac2a9a09b285bda8e4a77fd1b642417baef274b342a7686fa42718967ae3731d9d52b44b769e700c23ad9797590d43174a83bba25a29a56373ac3cc6e017f975b7897e17868b70ab8778171446bf2ad0c7502c3358f9bb3612b9074e0524f4b4a81d241415b69f7c417a9cba34f01c4896a65e2538cb4916ffcc63a9a4ab9f180efd662571999cdfba1e2fbb3a784424cf7511f9b61607bc274a88d7b02158f7d1bf058d18f251eba03fb2c7cc1934dbc61a0cdf5cb2236dbeb4f3a88c285e1d937e3e10f086db02b7e4fec9a1cea1d15df3845efb80ff64080632e31a29a27bc8d78370d82327f58b8aa04a8a9355a5c73e5544845b45e98a0bae910bc1fd25403b7418ebb0e2510e5318f7e3a8e72515f6838e93a468d3866c512c347fd765ed519a3ef123249540202096706d9225f61d43e164757d4de18ba39209bf47b1127302b72234f226a6cfab4e6d06a3ff3e2d9d4e17cc15508a836094ca90ffa3582cd2257d0358041408a1f0aeae7f520064449aea8e4e1c235ad430f98eaaea53089d878ee9b844452b7faa6d169856e911bb87028a21426a4ac7f4bf37f40d5dc62c287b0b091b77077762af0ac3810f11d9a5b290e8163ac824afef3c6ce5b13e5bd35620c28cb0ada8e9fb8d01f8e397e9a510ba53c3767c0b9bd3fd61840947d11565befebe8ee8846dfb44c5d6178ccbae4f5d2063e81958dcd42f0dfa88c985bcece7ffd9ae1b99a6fb5395a7227ed323e7af75de773c0a76848aba7523657b84d605055c43d2a8c3bcfde7d7efe8618c00e51544aa2f023f8ca90544637d2d880a699340116210f4a89b168ea387eb6405b9def464e215230c927a108b0f63ee6cf872c609b2ffa6a4230fb468fc2494817afcf27d44ebe84c4aaffa63dcba2024b86c7ef5f1435330a01a0eaf7b0c4af2f08d0068d8a157dc868dc3b1558712d16fd27d547216cb21be1a95c638252de0194b08abc1cec9e30e958489e4543d0489e599358749d936b5cd9421d5b2c54ffa7203f7fb168265be6cfe73ff03221994b9683cb4ab2615463933266ac9af614e9c320c9b464b2e7e5ecd114014c655c455dbf28f9722988d5aa12cdf2f62262667129dac08696a9f06f12d622e0f173fd2454d4ff384df033b2db8afa1b6b039bf1ce91aa835866e259a22f51546c9feba8f72d489c112e84d85f37609dccd187c279c76bcff5ec25bfb2e1b59677702503c76262c127a2d6d9699cf8c02e294ee0286556e77b42a9eef585368bf7432fabb7205b5b2bcee6ddc9adea628d3fa21ba1a3dd3b4d3223b9ff39f30cb5288c80d540fa5e110fccf08aea1041f6531e5e13a816a26c9a1bf2ba18a233fdf4a4571742d6c226fcf36a34b33da7ffa44fd4323436f65c8bcab8aa4d5e690a369b46ac791dcf1ed0b67aea91ac7666f07e164dc812a17f043894f0d45f0d9897180a53bd57772e1f3a3f9b834a60dded1051a29595e3a6b9ceb2c77dfd2c86e816ba2b4e88fa1c90a597297aec79df4e8d1fb8fe93d41b40945b0e37b33618a0714889525789298bee8b3705a67e3b065a7af8abe61c273d98bfb51f19dea9284056c1c9c534263826f7478b1461d50f13d57077d9cc4c361097cbe10e649e319a25b18d7bcde92e4290a483d074b6d985f106c2f953b1ff7d3be445587850a64ce898cebef46fe70d5e78fc96db29545ca02d93c2378446ed31811a0c29a05f8ba908f81a957427f4f2ebb7348fe155155d2e1985be0144a7c8830cc0101218079184ea7bd2489a8d687c05b45952a711c81b624f500d4a697088484e40ad28ee783b3b9b21230807c99a20ff4b8f89d8220bb25428d81d89410d4096332f072555675d9aec3ef6afc119cfc41aa312bd19c827ed44a4d26721155b8d1d97ea5eb087a2138c5201152f54ef099e4f1f562c10059c5e895e084c42941764bd58243cf708f296422687fa1eee479e02943cb7b5ab4e9e2ec47371e95da452f0244341988a3d8ffcd364d6dba8cf139818e658cad0d69e7a67326f89f197ba6801705b26e3230c3ab7f9f59bba1ac7bd56e8e6ee47ae5e48292e06d0e8a17261687a08ea99c5def24e0fe19edf7494ff01125d41b7c95df2e8305d217137845d71f3508b1ef55ef5131140cfa0a12bb9d27b1a18581fc6823b33d5d811023bd34176f6882ba28a090b1e9d52d680a35d188742ff61f5617e83eed574518a7410607dd0c35676e1f777dce5fb85c9056f5345e2718cec63fee79b1dad5a213eba8be1e2812bc74ec3ad008192587f66d636a9be1a2a7657f6eabded6fd62d7587929253c9c40b718d9f6210395b35d4aadaee2161e60a52fa9a43632e5dcd8dbbd2027532419d397145e5126ccb07f79488495b7d863338760a723fd2511ec96e803be24b74334b60ceebfbe8a7880c41602e2a2d09bc87120210a5677140f240cfa6ba085c8f55cd51cda1caf79d560c4071585107caae29939bf165e1e6caa480dba8a0bdcd84501ec9102de7f4707b78a0a04a2040ad89b6ef0433706d85408e440297b2dc33c1b463489757dc84440e92e6fd71e4e3eeff92eb0363b038a57b58cf7bfd6fb80cdd5fee1ab128ff5815295ec632b20aa849ca859123f294a604da45825f7d35e8d458768e02e07ced61cdaa14f8923c43f4b203d3b53d31f3c41c20a7954630122b0f1b7db020f7d69c32b541925d90a986b2db539ead6f48eb1ab76143a23efd1ca5e202c106a67eef7cdeb374de4ab7514e3fcbf80bed755eed0ed470404140d2bf4ef22a7a8d796ad73f90f85f8669001e473aa51a6e2fc2b9b83c9efcaeb6e80402377b2f3f0341da3836c6b81643e60634f9839c90471ee4770b839a3a97906b1098e07c466547febac1227750a0e6108042702baa2efd35a6f45a3b8d5f31f37b206be43da1bfb58f68cb78ef148a2abd7a94d0fb784cccc30e4320fafd68af20259e89ac5d63121a09586aeca020563afa6920fe980afe81dbe7cdce64efd5a26da613783d21c64de3a5c5a85c33c320b4b371996e90f2167edcbbf91aafbae8123c3c206899210e7f9895ff0f01212274fd3ffeb88547609391646685352fb9938aa31073da2ab9e8179e9f9015d30004078ead143d5acf680238ef1aff4aada5576464d0a2a6103d5f0cefadfc5737832561c1273c25c37335915a3229a7eb22a706d2ab96016a4b00c387de2bab98f2647016e27e9851e6ecaa5d7668e69c01f701b4124e301faab7300906a7bc8ab41cd35f65ebb2af014d99ee9577657e5deae4d241b56c224beca5304e45cfd49f7cda075b4969d59bfabfb74728bc1b66d686512acec72f6df102bde91c43e823f6917928dfe51591d54fad949ad74b517c957d51b950b8a8c2d81d666381501ed04034ca54b27f5aed46207c4a37bf33abce4a6ef4be59583ea5fde507b3122e00a548541b59c06195abbe13313d42ab8534c8abd54edaae2a22bdf105fc6c011a9541e3bf070d0c434a7795c7ddf5cd4a59ac2836cdc022c9ae38ff4137ede955aaa6fcf0de1540a111365a945062e02782abd83522aa397fab8e13f37bb7e40bd02fda7d8efa8e0a918c0bdd00db1dc2a2a670f194d59118aac0f0d389cfc56384767d843344d51e07c098eaed011578a5ad3d8d3e3f63d729c0fb3334a805e924c51406f46c3db17c20f97ee1f5c7c950c3b9da87677c83213889c4dd4223f3ea8e55626d06093824116d93a77f06995bc05c031c0e861708d43c381339c4a4292e12201c75e8f07c30a8e714cef8aa4f3afb14968157ff6d58ca8a6da5afe694f927885018b28c458cb01464cfc3388f665be63562e775cc7180a5125f16db9f110dd19fd1bfa213e333d12c091dd70b541b330907b72b4d4470d36b7de9b4c2f3cd48a34cf51249515635d539530e94758827bd069c2a017444b8d05063e9ff107577e7656f82e2065a3dcfe3340c1b612f239d2a39550849e90ef8f9fe6431331d65929fb1a7c88b4ed660f92ca00d309035fcad9167f895a9bfec940453dc43cc02f7fa0ea05beba7a2aef6fcebb9e3aa1f682202a10e5f4c7f7ae485040b69c7481e06a378cc34b70a031520ef6ae4043a70b1a78b11b03a99e1566c87c170e9dac2c6ba4e116c3bb2f5593fad87f5097a0365a53b20aa650da7c222a5379280e740faa6630e17d9c534d10a7a136f6ba2a674ac43ef11bf14e0f31e94b65600d6649371107e969d7ae9e3bd8c4d36fb49a1b0fc480fc0a1ef5a8115e1512aead377ff7214a0e39f324c613d05784881186ce1f2c18b95ba01cd847133595fd9230187ae79a163e722d31fe1ea51bee6929078b36582ba94e26b2e81dacf5d7f81274c62f6c47aa2194588cfa632255a7e19af219fb43bdd64661f57698d451967c12fb474e47b03f1254507bc8955a57ae18e32b1021c8ed824edf047ae5c9dc70d6e2db92240221f82069857b93d053f7620e3897441797a78e5e0713ad791e6ccdb468d50b01c3ca8625089a650bccd85c961687011822b22886fe02d6a8002e43b618daa4fd81692acb5027c673f637d2c6fab279864c823b4669e99a2e9239cf52c2e8de61214cf9cad6eddd65458a0a367c00af2abea716e82e34081dfbcf4b84aaa9804d2b5fbf42cca2e7268bc4f50ee9d2c8077c1bc84d966fe726075d70aa74c1fca613b5f04bfc5ed0fe0907febafd244542e12090e981f5beb3fb7f6e20e08a62a96c12d69c7c409e50ed8292c69d7959ae5094c3a79ea6a50a296ac3927585ee3a002b60bce09296acfd563c9d231193090e070adb6af62fca4de46a2bc5d37f7c93680fc4ec184a3593ebcc616a5afe1a4a81f643d77742ca44b44ad3433ec2c7dd82c014c19ba193c5415286ede77cb557d873bd765b71f6f06eb9e5a6d71714c137ed1c995065236a508ca25b12f99c894fa63462ff4cd9c31b5459a5de069fe9e64866296336b9446db6912aa23b4cc3957de74aa6139956d3dbc0fbfc4fc4e2581d3af5f653bd6222ec3095abf3ba38e9cc83a638b1148b20bd2d140cc729fa7aa544c478cdfb49c97c978ce845b64b6b88fa13f3d6a261a88cd10034a197c735b6d2a658181a391b8b804aec2d9e938552e70fe0ca28a583cc35776d99e07e8b221d9e85cd85fa5b996be241771e4d2cc66e7ce0efb3b8b89c462e65ca376c169b466a23f18503c6b7f55c550745b693da3d11767f67f984c93d5b58d90d87960485cf7e32d9e90697873b7cbbd0369cbcb40d515aa95a7ccd61575947c27599f1863649215be2641f30f367dda0ff14caaeff7b45033ab2d92f1b9be5f62325d5479b7c2313b38c67ca9c6af2c03b91fad138077bf7e0fe7d052311d6a37586b4f830d01d7648e20a6ec20abdbb59a66f4efec40ef047b23bd4e5be9d42b959eb7e4c7307f8a504298a4726953a49e1a3c82b1ea02a0ed407ae63d9583d0c625fe5ded12d11e623bb102fb5d0d62e2d4241a2ce30b44d4a74c155f040437796446318e4eb359fd2eb959b64559a947ae35accda2f3515e9885d83150404b146f51952ad644099592daf847e8a4aae2af8e4cb5b13b33b1817ec8a9ede5870f18f0584f23a6036c456a3cdf41622b56e6131c37db8552421167d1c49bf6b1484e08e54cdaa62dd960f1cbe84fdd2049afbbbcebf4d3f2070bf610eaeeac96f82798979aa8b85d5bc80e63282020299462ebd3da6091f08931876902c5749197e509157da47950130b28bf4228e1f4950f8c09b6befcee281b87bdf0a2f2c513eac8d39a681b81357125208fa10c04c8c90165f1fc657aa0c9245dad2032f1cd528a810137d9e9e8be90438bf86dea29482d6ad9f30af2ee122a33cd017f9e80ca918c03caf202f567569bc66a5d90461a0e8ceb13a8f0a6775d9e97115ba2b80104ca74dbfa06122c08606efa8ad56bf86b59d944f1401f8f2dc5cb89dfa3fcf628f464377bc3ab0d60f7e579f3ab6c30f14ecf7042f9802e62246be8a3bf83dfc9d635081408c8455b668cc03f8e83ac4746faff3aff9bf1ab59fbf2694c8475db4e75a983d0afb4b5dd255417858186d1d1033c06bc41fad1188920109cae256212a693368c038e52a7b881473719ddc030dac6f8f891a2d00f1440da4b84512ca0c28706197c11a3e065490376826c0a2a66d19f33a06a5928dbcda9f4d74c488a6f44daa43f536cc65a11f049b8c4292f2b1091ff12b84312037fb2987959ca47f9a5444bbb1fca29ebf3813e7004af2d59dd01f0c45bc8027c3da320c402943465acdda630936df4e62ab018030832d00f3b6f7df8ec0a249ac4b272e4a005560028d2e245c7f5c60957ffb88b5c5b78250e0e0f48a2051b8d106e7ed7534e72f91d9b7ee880a2f008acbdaad82a11770956ea8a6f7ae85148c8a77466ea0e19b1f7bd011e451133334cd9a24d42cad6468acccbbd4baa1dd7c51ce8d6ee9b4eaa438e4e1fbd084c304c55ee3478f579cf5d9148c06871b9c6acbb60f76e54ceff11e07f93233e6926093c322ddf88046a3f5a6526ede3a70401fc66d3e4ecff1c09a2a904dd70f345990584dbc6d6958c2bb7a06321e63879c4312e9fd41c903e7e6d885d5c686ef25f970762542b745972fbe09e10cf612a9e6b56d171557381d2725f800c4fe76f5560f9ff9a8bd3af3d934e65da33d2f294df80fc71f9c8bd7d537b2363ff73236e279788c872af1ee8ce2d2819573720b995ca3873e1f8249b22e88fa179a1561aefa9057f693a4fb4f22353778f5387dfcd9d5321ff2a58344dd06abec0c25ebcbe23083c75de0338554c756db432f7fedadfc7d133b96388169e23a7d1d47d7cd7b49bbc13d2b3f65fa6ac2368fb95cdc2394f934dc10708b8e3435e5438f0d618f882ee9c2aa8ffc7ebd1ce7472c93ccc007b955f0e3c0a8837021c66ac97091bb1062f8ccc574b6b78d9a939e8e8c3bc6b2288c98e131863dbff724bbca94d46378324165d87eb5d3a0862d37d5c4b35dc32c7750f922a503df8010e08d53d186d5da7ee6092b0373a06d95b2d31c297b037d0a3999ab3ac8e5d2e6181bb09e446c8abd219f7bda45f140ebe4d69706d275dc7cf83ac042b35f9218b21ea5d9557b2ae8b4b88de69b03924452fd6008cc74036a818e805c30d61da7036e2b2a8e388b3729257a04d5568413120d836f7fe6e6122a48445a24a49d2751048aaafd841265d853e57c3d7a6538c3795a10e2e521f2821550590557405ea2758c95ffb517eaa48efec57f696defb626a59452269902af072508c2073b76ecc861661089535ae50a35bd424e0e13a794524b2337abf4975eecfc69942e193fbe949d247bec72a4fbf4f86e939b33012c8346684f0f570f263d7a7a7ca087ab874b688248e86c325db387e9337dc03825d76a679445a3238892084f9df464adb7d64b2bf596c998a3567faac54d1a80013187779ed13b1afcf35aeb37e7317ecf2836a5bf6fb5ebbd0cd0b3d0184720a1fedd6def2579f66507ee506ba58ff4d94e70bddb6fb507ef97bcf8f4da7bbdab79162b5d5436c13f70a29d9e76fd767baa3df5404ae94669f4ae7f718aed52778944fbadd731c77dda4559b69d27a5d3dafab69b5d90cef3a9243995525f765546dda9532adb3f69b3ad7549a694d6ae3ea5524af94e65ad2f65935aa98c5426c589094e626cffeee4c7ae35dfe8cb26fef511bb24cf7eb943ccd12e6572879823beb70726914dba1c79c4e6ce9d9c54c88410839021342e933b3071c7416684a669cdc13429adb576cbf12dd6812c493891040f7890af0726c9f7a5732fd84cfa982547e638a9039700b9be496b800845ccd1c9b71dcc3f1aa18839e8d74f12b3f8473d66d1e4463bffc855ef88cd4e3fce1d52ac3eb13b83e28280e383465059ceccce334bc62f0c3e5705065fda6002617b463b3f850406bffcdda8b27aadbdf8e184ca17a6b779d373a04dfbcecd3f5531bb140f3889bc117224753880632b897f36588063f8e42d79ed2b39ebece9243442e5e3bd8081c1df9c0158c4c4bc8c8c8c0b172e5cfc4e8681992e60525d8b984f753b19b7887916319f2365bae91fcca35ec838150a8ac5e9d7efc60199912981e6d2bb3be7a4b4567b372bbdbde74f6e6de31a735776b777d4677a634eca52f8846cefbc6b550e70f4403ac53b1407a45fa65f86058bc8a25128ef58c4af29e55053459c56867ea0f0b46458a804f934d9328b5989f2d3c39345165271e273b4a5e686a68536891fdbbb312b517e664f165948453a39da7225068be24cbcc7288b50189d7039ba5243058eded750811bc86c1c5facbbf11078ca29a734d5c4dad22d3511a1d56f9a2e667fada60a5c6bad35cf5a35ede705533d3df002b94e981a2a708cd7b11cc28c3d3a8c0726c93ab9be0bf2e6d2c41c2f9ee4b4adc334d14701a610b824632f028dc3887ff2bfd293b8e979fe18e0f9ed369a57ea2810c16b84460503cef671b65e10ea79aeea039aba12e89bcd8baeed9aee12f2f45aaebc1b3a3791670f60e8d57cf92ec81b09f46afebc21cf77429e17c613302ac7da38e6771ac0f8aa10624aa3ec90d01c7fe84e412635893e6cb83d348e0da9cc43e38ca0a32bfa28fdfcb843e3683f83348ee64d20eda3e4c5ce517fb290a791c689795edbb7bf6abd5bbfd2ce73d3cceb9589a6e1f86207387ae094b9e6e8ddc6b1a395c19a79aa96ce7ae7f6cafd1685ba77bb3f3333ddafb515d8b7d7624b9726b048eebf292b741ce1f81bd7820a598b59729f380e88fbebb0026baa2a387a272ec84c6efff0cb09e6babf50b38cdb8b26b04c6eff3e2d0626e605c79cae8d898989a9d48529fe8c8ca8d925d19fbf7dccf3e60976a46dc328edb9f91af7820e186a481c904a7a4ddb6a1773c7bc6dcec15093e7bff88182982be95ffc408125cdb75907583be6b8b3bdeb4d6fcb52fb5e2caf5f7f7184630f6884264740deb878fa35c8246ef3d2e2e947fa2dba1fb8cb41c1c890c5c37c4c4c4cea77728b0efcdce27107d290f1a33a161d184932df1c867916dd8e8c276d1073c03caa03bd28c37c8e8ce9a67fd86bffb0e7a26b16fe93093f877ffbf69be92b0ce4c5bb3732f6eaa933755c07a6b2a6f1c0ddb67928a7af8931eed74edbb6699af63bd93bf0411ac0984daf75dc37b7932577fa1cb9798db1941f3d0a1c49928b20f968f2c023366b9e8af49e8af4f1643df04fa50c6a0fc45f3b82c43f66fcb23b3dd6809c4c5c90ed8fd86cbaa523d60699e5fd2336df0d48e9a1e0fb24396f0d7d41cc03b1ac426e1d84c0276bcd0531bd7fed4c7f3bdf4aa4fcf2a08bc62f1d07e4e5b5582a953e48e7d2efe4dbd50ea421d79fb2beec7672f529620efc39f2a59bfe693d4fdc774a06eeaf7f9b0d476ce3b826ef88cda5a7a00d32973c30e6bb1d895d3af707922297e3d70ebcf314670b342779d107fd6e5eb98a36efdfbc9dedd577e5cda9578d23feaa6d647f31462ffaf0cf6d3c4ff0cb327a2d43fde843f5c283d4eb98a3630efbd68b39e8fb178bd4808066db50a899997f1a1a2a47f9660ffc6c63c64f422277066bc01b2f3fd3320625f37d945f3c8bd7e2869fe3384e2b956660c4e88f0183e370b76c926f60bccf7c2906251323060c6f7bad3b163f13bf4906597c8b162d542a954af53bb95fbce86791ea77f1a273998b0e09cd294fee1073b0f81cd9a2ebfc6e13f32ef311bc37dbcb74b7677ff6b31e3893edc378207ef1f0a9036fc440541743bdf07bc4df8b712ae536502474c6dde904668ccc44a9b971e3fb6a6aa847287eecf8f1a37ac0ce0d35437323c71d3f426fa116f21474687ab0e647761b2a926a77a87b0e3768beefc68dea110a29a79c31bfc332c53cca24a3837a9922a637bd4906f92761fe499774b5a40c8b169145d7bd92e9686ccbc7a3782516b98dc9c358bce25f51c4d2954a1ca7c9d3e9f4413a9fbcd39b4c27ee05c604f39223711779fcabd9c1e3478ea1f430cb9732d6e24ba89794c4c2a31e8f1a49438ed46a6a626c4b9635f827e57b1f5fba94ee21f692143c2e4efdb763874d38c230fe1c897175694da37591e5f3629c4a3dd7040cf610adf6efb776a5e6edb0def43b2cd2f55407d0def443b437793a524aafe395bc21da9bdee4e968de0e8bb4752d3decabf81bea5e52adb5deca19a0ef95ae4caf7b40f43c4b03a29d825bfe898a41c50dd5c5a126c460ac980e45042bc7743adb1058318f92f9984e67039415f34b66102cd4cb743a1294302fbf93f1efe4d3ef64d3ef64ee77f2b643fa9d7c7f27dbdfc9f57732fd9d3c7f272fc13e20c142fd64027717d56dce427c98970e77584aa41b99f8d04e7ad7a78c4c8d297ce043357065a7edf402138392993232d2a38c0c95b5a059a896ec9fa2462e5ed0996aaa54d2a38acaaa4f6d529d549feaaa50eaabbaea5015aa56ea500deb951aab613daa5b2a977a546796c7b6eaccfe5828368afdb12f3bc5c2eccb16d92b168b2db2319bc5cafc731b83b1b99c34bebca16d48fdc564ab71aef84d0acb67712dbe257aaf5158100d8768ac0816140ecd8e5ad575a73895c96454ae10b692bae258b83c3d9ca293561b8661185e97cbe57291a88ccaa84c86b6719cc9743ae197f9f2223dbea0326dd11eeaf2a12ffa738bb02c65f4b3efa8862e0a73b95c2e5750384463b468e34ca7300cc310bb5c2e97eb616250281919162c5aa4662a253da662666c16c98c6647afd7ebf57ad559485b61188621eda12eea435ff42706f57abd5e2f19166118d6b0865dcac58b172ad5cc0c8c1833460ce931064c9e3f1316f4cda1d9d16cbd5eafd7eb5567335667b35b64343b72f1e2f57abd5eaa3aabb33aab330f460c1932febbce4b61a69082f498c24beb68f64c1f1b7bcdd7f7fda75218cf9f099b41339c433164bc5eafd7abf35248818666c60c1a35668d1ad2638d2d2c6a49594b1ad9d8ecfbfe53298c3da77ade755b9e8d5d5ba98d4d7f1a9adb73792e93db735bb7c975dd5396aedb92a18b933159d42d797361d76bddd66d65ff1917e6a69c236fa44baefcafcb4543baa4d4b8249374350e7f18d2255dd2e56a9cbe5b04a3a0028f3b5ad380b2255d470a70942d1e8df417acc92d8bae70e6afd8a4d55e7bad2b86337f4d5a6db5d515c319add41dac015b36e9a4d135dfdddd678d16e0f8eeee5e53a305eeee8ed3d7895643081cfbfb6b0881e3f7c7d86005b2c7e6abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb1b0808080808080808080808080808080808080808a81b08080808a81b080808a81b0808a81b0808681a4143e50675220ab42827ad765a2b3d5a49abbda44922498fa4bad54b2a69dbdc36e9712b6da58d339df0c4587ac426fc0213839a2894f4880a8784ac0c855762e1ec680b97a319e5a1ad594c4b868749f667d1d3a249f64fb95c4c172ea44717ada02954826042214c1ac92c528b349232b945cea4cce5d3c4898f0bca6b8642feb99c4372ce7925fbd319abb356e9b1ce5007140cce998c0946a9542a915af9e53f0ef3a05918866118c26030180cd68ab55aad56cb8b5ce6463ef3230b83c1603058abd56ab55a3164bcbcbcbccc40cdee91b7bcc7150ec58a6461188661e872b95c2e9794c1fc0583c16030ff719807797865188661e872b95c2e180c0683c1de633aa0e01931611c8ab158248b46611886a1cbe572b95c523693c96447def21e77b98f75b95c2e974bcaa44cca3ad50c0c183162c890f1ddec3ae9b183715d1ffc4afd3c2c7ff11acd8ec2300cc3d015ba5c2e972b0ec56291cc280cc3300c5d2e97cb25a74b868cef3acf4b21059a1973c60ce971c60b0d4773369b61747ddf7ff489aff813613128fc19a6e0a540433363060d1a35bef97dd2e3876b2e0f1ca686e6ecfbfe53a9d935c2b187be5e7366677346e76cce999c331a9a2dd257ec68704162ec6afcd4d8624781f97141e216bb15ccc6b461437ab4714daa1748397e94a75876faaa91ee5d446337f531a7313ac3949bab1145a3c179cc6d646aeb014af0a16a41e61d8da37b60ad221428734a2822c0f35f5082c8f2391f0c7e710681217cb032c5103e589182653d9510fb3bac18ca8f3df2668725df7649b464f93a6e83c3f89237cd92f1eb11c4a04c0971e0447e0d79204f221c08c91752d278e5233dc91207b90ba28888bc49d27d5424a3f7611d2fec38f69b9b61b2ac872e9031c39e7b86af8c198eb967589a726b521660464dd268e1183778c9a494f23f1aae2dca311ac98894ba21fef9023a1ce0a741663d6a4411d125bf3999b8db95339c514160f7686e1d1c81c4911766964bf2f4542dd42c5f7aee9eb8dee5451891a5076252111aed91ee5e8f0ff460d2a307d638317af400692de58e0cce9933a79c72ca504a49a994524aa9e55ca11dcd6a52980ed124a8100d6912356ed334a44374688bbc194412ffebacffef36ee411934e2412fb4641089ab5e2a12a87c5e18a948d02f8c542fd58b1423d5590691481bb34b582b76c82e811bc7ed908dd9d84bbb118a288bb0e936ed020de6c3870f1f3e7cf838d19ec6a93e7c48192bcfbd3be69d3b56a8e9157ac7e5766ea44ed01afc3cfa31beb5525a79a5955e670f3107fd29e76c927dbaa8947252f78eba28952ea564f5d722687d53d2b6e7dce7bc5e2913c9bd50a97b4fe79cf5b5faded5779f3ee78cfe5d8d10054b962c59484e72bf101ef266b2bafffafb8d006eb0820914284c00718065e3891ee8d0822b74d8d2040bfc620b68f02a6242103f5889a2ad74808916132b41a072f403fd8112563c1982478a12b0c0043989285c25b062022a5010c49322f4f840020e04c10a0978809f900f3e8e48c112a01ce123840e44705283032cb04203a10c8040e43345c7119c2c9101275e270865144e98810c7c3074031a4811d42be594d5da2357f810851c6c1142122fd8f1e13284132f2c4988c209a411dcd40b92288a519260424b12b194d08e7fe7bc59228ddd9d78d2e833d4082ac767424ea63f677f911a6ab2f48cd4ac90bb037574c7296b9612531632d82f9b7aa0e7f9b3cada42ecaf903d6b75eb4eca287b641eb2b3d958c8b303e54f9f43e07bafa7b38465bdb9a56d269594c6396fae94524aec84daf5fddb994bdc5d035af7cba65fefa473ce26b4f6fee836fba337493c8106e309f885eae409ee584904be9fb4f2a260f0c793474d07c2277e83eb81bbc30ef6a6a06031e064891d58b00408a68022959ba84a145598689aed088c55e84069877fb186087c63e7c859ea8acc2fe215914fff37afc87d6d76f26bd7c160bf345193e45d9a29bdee46879acb2ab4a6895afca36f4bb86fdfccb7d696ba684489b8d13831eb481962fa8d7bfcf23af85baeaca763fa93d7de8c7f18c3bc7c25a69f0f83779f3c25f8e5c3fc09e6f4e2a9ece96778f9d3e99570ff72fa194e9b9017afe65bae72e40fe1098008e1c19e8ea927b24c3f430696983c2535fcc9a341ae4e2d3bb55a3dfb017b2afb4ab8c79ee95bce60fad39f4c26d39bbc254ae2ebf4d83b799fb3101fbfe9c1e8327911265794fe8f1fe6cbe7c161bee971908fe79b7ec87c9337443ef654766b16d7a9ac2784b334e22ece70c702ec3e2eff287d1588c0f4a3ccf454c690eb36dbf993be88d5ba5247ba32f85b2fbeb4a0499f762da594b2a5941bc6dbdde89540c4e036f2d5382d90deb5d760e03e6eb708f751dee8481982875a1683df4456dfc428932b8781e9fcd5f90bc9dac723f99d5e7e1b89473e78fe9678e49f3b4c17a65218c4de7c79b9eb425d914905762b7ea549108ff97785f0e961de99bc1c16e7cc6772e53379237be4cabfa76726a5d05048c541f9922ff92361728aecb9f247be64cfcb474a28fe79284f1ecceb9c1ec3783a30ffe2a9eecbbfe48f7f530811b93a75a77ff919601e7b4af0c3fc8ba744ca10fc30af0463fcd85b12f3f85f4e9e8e942127ec29a979f99387598f846943081cffc5f31e67c171cc9f1ee6c1cfa9f9c2a0984eca7dad3352f3fe4916ccf4be1a2570fc96fe9237fde33c28eeddfa38f1d68c473390c0adc609d2b9ea4002831e128129058274762d8dc31f06d2d7f7d7ac944a0fce5ccaf15267ea8a90bebeb66d9d0b5181a3151948de9598514638201110c2307f7ace033d742c514635fb0a39c944bafceb99cd2cc7d90e6b9ab5cfbde6e9481902f3a7c73ffbe6f42f0ff3d65aadf370080aa65fed16b916863819b88f5e49db36c9c9509f1691ddf61389e7cb79409c8080f9ad030283b2c78d3c8b96c669bfc19e7cc178add64bde38c6d77f8a8e23b007c15e2fb7013dcca10fc99b66b5a29013ec431efae72a74006bb247ba667ed4755b8751a9196d8b1c0cd75309f150aedc7650ac0d28987a0de34aa404e9ec8f831229d4038180f91962126050a505932baf41aefc5b4b605e493c7dccbf3cd8b398172f86300ce34999de7dfc606c99007b118c2e2c5732a3582c929ccbd8800cca4f8e580a1c8b704fe3e0e4fab52b88a7942f49cc2ec262907fa61a601999f4a5219ad0410f4de0605405ab7ea94b2257f5e7cfa03dc9f366282991dfdc019ac5739ff4395e2a59efca15a94bc955353d81a3e7de2757f5733c660798be7ffd30575b6d558107833c72027a557f08611172ad4bb0d6aaeac721b7b9e2362d8b5a222cd76a25d75aeb51ae6f6757c9c14aae1fa7542251a8d301c7a118fa57ebdbe81262d99d428b41a3b902d3afafd54e355f9b3a52a637e4bee6e9707f3d25a4afaf73df7a4a94949efe0e4b6b4e7ab6e33c25dc5b255286706f5f89e9ef9b9e6093a78aaffd7dce531d408bde10edef6fdbdb597adb913c062993fe7d92a792de10fa5735a4da2984e75a1792654d0f1981e36ad5dffffe1f6b3ea123d0eafcfa028d9c01689619dce1a4e77987c6b883ac663035ebb5f7dad21030cd4d54e5cabd81a80a0f3c26640891051055c18126233751959fbce526aae2443699d0541d3dcf317b6e1aad71447f8263ee6f9cce436453b81083902129274541326b89305fd6dc8d01336adef52918bd79b3f540cff64b9a07c6af3f3fc62e5dba5cd142bc5e115b372945867f65510ca12e0809721b1bb8ec018329fba939b59fee46bedcbd111eb97e24fd9cb18fc710377fdb1cfc52c9052d027992ae68ee051e197421cf23d1ba67e4c3800f56a67822cf9f008f3c6541d327df998cc802687040cdec01e36094c3ff1341fae44b939a61023b8bc6297d300730f87df76e180a063f17f29f8e92b20929a59452ca4749773f7591f42dce95f458a703cf6a5f8146b2ffb4a42bae67c3ccd5562f94402a1c6457c221ec681c199f4e15f0e89e5703f843df41b8f51c020637d29764c906ffade70a3254010671e9b1db809f7be08c9df651924aefb1449a2d1a65972e5dba746e61beb45b8dd432730091053481c1ce42f3dd70c0dc4e5d30984a19ddbbe10c603095ba17a73cba47f72863f021ea6e4f6024d22d03a28fce310281efdb4f813fb592067ad61e9c597bb0861cbf3e4d12c6f995005dba70c9f723b893afccd7b38166e9d9e0397a45e64b3a8920422905d2d1769d4d9b521ab3382d81133f720a802212c4cc0f3598a69637d7d4d590c12996751d7fdb866b951cc77d107faeb4936dd759eb90cc5caa371ae59b23678d644c6b1a1c59d76d2896dd2757eecf83db82c12e1a722106213a84c02f8fff7e091bede04a6ea2d8952c80dc443111e4779bfbee5ad4e284e1fee9835c920ec933e74528620eed495ae9dbbf17dc5d2fca025e8302bfe191227f03afcafd7388ec76e4db351110a2644ab2d666d28d1a1d47c20aa468b1b6a7592253850a6b7b29ef4fcfeef3fe27c57e8c510ead204b4f0838870777f743dbc0fc712481c83374c03fdc467a35784e60b0674ff3dd78b066478e3f83077c7f860f26bdf69a56e22293c484a49aa84b987d08690599d40591a49923b429b9898a82b2d7e036e02711b26566d2931bc902b7c8334307ac45ee769274affceba9b010795343cb591527f9c6597c218de3a4289a04d1c8b7eb50ca4fe6eecb4e4a17720cd9da97b10552645ba5c81b192e211121fe996018ec590dd1756a822b7b4260b026dbcd9f48e3a85aa839fb2f8086c621bdbf034e3eeedfed1b9fed9e60d9adea28c5956bd0b9c255c3338b9a74ac7b4b1f4d193f556ac6bf1d35312563c7544fe39fff69769ac91b21a7d969963df6354e6317e9045ad3802e62b97fc60db08d5f7dff943c5c5128323a92531a81b1887c54d4c2c76d543db5a800742e2f6fe6fb4166be3a9880417bd4e336f7ef6de236d7e3e2369de577eb48026602660323968ddf6195522d57f8a94baefa3bda3add6bc4bd290ec5999dead882c1f8207d714f5f764a8e0fb6b0475df0f4acccb345fef5abd004df076d91db5c4c7b729b3a0a4c190566b412875252a2abe29892ae22eae35fbf00a6e850c38a28be99f3dd3d78ff412c2385ef96b62800fe82280a4c9cdaa222b751b910837577f74c3f8867da47b8210332d64c0758abdf61697e3d00ade61294bb284aee6ff0f2e4fef6eb2437bdb0dc6f6d40cf92fb5b25c43fd2938eddebee1e8b689c98fb6b38011391ab7e5309b0ca3fe777580a20c00fe08708e07304f0ee0d21c00fe007e0e910e077582629f0003ee7c17864d46f8f1a47e67e1661e3b412391ec957fec97daf0722a9f9badfeb974449d716dd6b8b6c51eee9236f5adc8b712af5d5b4f0401edde24ae368d5101b3a4b5c871e7c802565c6df781bbfc35a75aa21abc7f1383c1d157ef53b2c1d55e098fb2f4ea95ce078fa00f8d4e7f8167f53f3fdb7fffec81b1ddf7f61778a5f2a6e83fafe1bca9b007cff1d729b98efbf56fc66c7f7df2b6e03f3fdb748deb0f0fd5776b3f88dcdf75f2d77266f6ebeff1e5d2e7ec3e3fb493ca41e79d3e3fb492eb7e1be9fd4c46f70be9fe484f492373ebe9ff4f3e3fb4953dc86f434be1a2d687c1f8d1761cc4114b6d8f8d5a0d1c2a7bf85131a3468d048e233ba194fe36978e00c4ff502fd193fc303532d7e27b3f89d2cf33b19f53b39e677328ced231a0fbc3705cff3624e6709d0d9017402e8e2d17b2096e175c3f0403ce381299507fe0b0ffcf27d171e5893531d9d427ffceb6fd1d1b0a356fceb97e9685147b3f8d71fd3d1997ffd301de5d2d59eae36a92ffffa4d5d8dd2d5a02a5463158b7ffd3fba7ac557fd3eba3a2457fd385da5e2abfe1e5d85c9553f8fae42f155ff4d577de4aadfa6ab4c7cd5cf42575b72d5bfa3a35b7cd51f808e1ac955ff0a1dc5e2ab7e1d1d8dc9557f4d47857cd59fa3a300e868145ff5e3e8e84baefab5962ff455f646711bd07da83d923739662d9e2760c9fd97894bdef09c6250e8f1719be90407af0bc56d9ae80942b9fffeb88dccfd1766493486316cf1b8937e7f3914b7995472bfff7814b7a1ad163ef7b6f069e1939b524a41fa5a75cdda3ad086b95feb401bcbfdde81f146a7c3e28a076247ac25a8276c61d978153a9d6d88a5b301ca9262c393a2f26feb13c354146c8f2c177b64a37bc52254b1273251dd2e91be3fbedce667d5352b4ee982883ded2e72eb000743e4d8b247968b7ffd9d12f8ed51affafbce4e651d20f1cad103717fd3b457c4456ce50078a2af26f481508713d85f662d4af1fa41148cc2de37b0e20430d6d669472c4d8713980b422395b2d0b5cca8bb8c35b80d187992f038925944ee82b894c6182391221e313291277438a14308b87206a89c0cb1870c2e2942b62fc411c8103ffaccae715d33818420c8585ba7f28165bb22f16dfd9137ed040c46c5897cf0cace034b76eb9155b59ee5dc203d01db4a0afcbbd710113255a56682483da9fe2080074b4de368da6bded3744f7a7ee28feca13f3fd933b900c738c33bd0ee6e7953ba2175d7803d727fe7b953449e1f8dc8f7ce0b3620cfa775d29ac43610a49f77567a64092a4b5a29e560b0b96ebef2bf4cc0b32ee1a8d680061e9082082025a620814b091958028f14a02a551c310512a80e3c14dc97dc444448b04dd0486303c02ecbfffb5d9edf65faf17311fad33f235d9e125391918a483c0891482f57c2023d2ba832031f0f18c1072a5917261419010b028a9f120f2f80219d40ca9c87bf32d845e057b342152596102208212e432cb08724a0041c8640e289236cf00316d8312c3e88a0c8a2e52622da41136e8e0b0570d2c56108d212851610b119e400068f112478f2042980e8010f1f28f1e0834d7095c849ec80871e7c9a40a5080b5112587c78b281101461072738403485e827f53359f016d31146b861cbc0e6030811501384e8e18708433420063ff881080dcc6240c50e3fb0423b088154021e2bb8311039c93172132d71c5125b5247885b94316b73c6196b673d03c4e9dffc5a63a44392873aa40123a225b2e41cb98974309435ba4db7e93a80fbf2697dea9c0cd43b9224470f881e18acebd1a76f9f7b81c210a5b7614f029703062f9d53ce19141483291d8318144427925971b8b62361b701413a27fd9e1ef6cf41235bb6e0259148d6de4b64461a3178b9c611b3378e8d82358346369b83c682062c68d0dded050147f92f1cff3a8d0c3405e5e3d8f582807bce5a2914f259bc20e0862bfe75eb8861ff6e97eed1a8ba5adc90d4ac12725f47a674cea9b5a424d2c592075af7c04eba6f57f2b66077d2d39949248d448aa59fa52ee62091669c33a04ca8948df635350991a201000000200073150000201008860383a15028498359731f14800b7e9c3e6a5218ca234996a3280c8320849431c618600c1802403332432600417652408e9e5a57a18edca51e9bd4aa002a841284718d62085db891d1b4932b0d65d852b70e39fc1e61821426a5d4e52f18ecf670760c2f5e32e1e0b36f5e401530c04a3591cc82adceefa52a458e031759c681ac48b32b858f4658be4e9c56b72cee175f0fb20b4cdd458e9511461953c26b107826ee598afffdb091c1396aee88da6761bafb00c920394ebe589855e803b79a6e0389958154367bad5c7d37e3b8d2d66277d5a1f6558e764e501f2f4e8f33b7315c6e17a714e4d94054683ea6e085b8c12cfec5035e662615759c38cc6267958419faa4835fd68f9f3e8f7410bad72c8e70dfe2e6d6a3e1cf87ab83b93df800ed87bda88893430f7b7325d95f3dba511e3138aa9f03426ae700681db01bd89f6ce279f3e704ade989daf5edc51e67f931340a1ac14b3c5a745431ed30839f56c2b4a7e8c5299ec4e4663188a381f5ad03991ab6f018368cc8cf903bcf3282273ca77b9ac62d9f28cb2a5ddba7f4c08365ba97a530d7d40d6dd87cec500234777c129b326fe595c712376b1b7243aae828aac8a78a066bd261575e2b354fb083acd8949008c0106732e6315eaade8c94e1122f2c2a212d73637e5b9e4d30ee730e604b2eaea7d887903743001b5348b1a80de5a58f4332306402277ff62f0ad25a498e7b011acd2510298392a4faf167e1fb5b972eaa42bc289e07c180aeedd2784ad945c9722384d604a5f8a9a22f3533d83066f28e00af8bacc466bd3fe17eec70709f5b51e334ff947634049d1d8dec56c23f78e9d2786f175dba0a4275200e7c4c8a3bb9a9318de6493b24bddb12c386f41e97a7bce667244bc3d8dfe53a54bd4c909c6a56d8b598bc17ec63591ec9940fada5538d5f44cb83fa332338b4f63995b1cea5c0a5e52f0bccfc99e14064dc8e7918e48967353bfa1458361d401006dfa9b029a12b5ea0b616d6102c975d9187a5fcde717ea7ec96f0a815a8a7a7a6359fa7a6ed71be7470037979876a76929365c1fd618352c22a7a8f1a9dd92f2215a701f2a64991db8fa261e106ddfb8773c6610468c4755db60ccbd065268e325e1560dece671846a4a3138ec4f6f28ff3b04abfef0e438714e38a27157cb7f7e4f13edb9cf3ba768f6042072bb7a23e9c1e116be3df40f258da34c0d1f0228e637a5e728f32442150b7a9ed67b6533ecc2375bbe864da7fd27f725d47ad527710c097a6a4147ba3f92dbf2c7782d9a3de53827c9ff43b50018c056db56aec94abd8a9eb558d1af09f4fb2faccb6d2b40466154d4d1871c3e5c18d9e076a988a86a89a2602738a9072c71a3a6c05c5ad2d8f43131c2c207b8eef5f170cdfdeca27052e6342afe0738d0e858ef55590f53afa3dd8f969e005ef6e3f270d00d0e4d2a282b7664cbb7c5e57c2da651a46f822a4839636f1d381b5f970827f2564eb59cabd129042c56f4971e0dc6f64232e4b4b67f17429af83eaf36174e551d0f203471695e799f7bd420001681733d2762d9c1026c1b61a8ee5a785c05835f33b844594dee556a1822587672255607fb4c319921d3d934f144206b2d029212a4cc4fb5fc4d1c506b428c06dd4413e880255d523302ef379a156aed529fc270aa02b895192ad35980a1526485344956224f92a584b5a444ff08007b1e2ff16a7f667108cb19be2ad0f655f4185062176388604b3df9270cbccf7e75a03823654cc0b21d54b30370d11d448f6733eee6324df21f60db8b135022556beca9d0b1c685570f98bb7b5021f44de2229a1597831819249e398589b7452534d47c9696cce23b958fd3eae888810d007305ff2f2800662c0c0158a6e5ba634bbaf81a35c8c0c0c61b3e4f97e601d0dda4069f1f45a2690e29288dba3b4ba3b632dca5bb9178c390c71f8db63c846dc6b8c6b61d7c755c5d5db6120cbd19a48ff7ffab909671a941fc1c38c460395c5b0effb1b74e4e3f8d989491126ba40ab6c8c210ee723b1599fa280622248999e46cb9b43171238649648cff91fa6b6f348ac4571a8ad94f7d944975686759ae1a783435f88183c621d0d1b7d68001a470551f1b4f09fdca6f16fbafa9a02c9e28015c16b00b39212d1e917659034db367b7add3eca9489603b84837a0275a4ab5b54610b5d8e87017ee608ad68c43c09aeacbfc51943a36ce928ab1962a1ed5f2e1162624f478d1663c70d7fc405520b47057b38e47ebd5d77b9a5d39707c03a8c941f75781419b0db62d4bbbd0c37e9cfa7dfaa9d9d347ee19c39f93fc052fada4ef816a48c70141b26edd559f4e81abbba5193cca7c5bce510a9f7ba3f331954c11b58f7e10aa0ec8be79f7fe0f4acad2b7a493047bdcac0f4db7f8bca1b24c40638978b114a5fa0273c364d17d068700641ee598a2bd7a9859efb48082a712d195ae3b1d0e87b0a9b969d870ff7e2f71d8f652b74d8cddfa818bc207970227ab04ff3e00dc753bd6849e6b64bc4b4f2802903e9ac8b7a613a2f0c8a22e026cb31ec631c0ae91a99697dfae59d35be2e3f24a93760a214d261f049b3cb923436cce4094743b660990672a00002f56f1246a1b3139c817373cc50224477ff33f38bf7d56dbffad9bbac8961afc955e1ffacd59bdb85059002b908345277ed93aa150fe0867220e3c5aa5fe6f23d999ad3ed3082ffa2c89acbc0120a91d56160da4147eef7b32779773fe44323d0e0cb9318e0211d6cb5888b5c22e1a6772879b9d6beaab12179c3e11e3b380671d094424587ffa44abb5639b1d3f35cbb09692bea10de82257a622c5af8b4584865df06135600cec10980ce131ba739519ee954400a080d3f75511a4064874db82a8d1ff049f8c1243779a81121333a38e1fd508d3d84818f718d9d7145ea6c82961302360957417bdeb316d5f8a4df78fa613d9ad4fc610fc69a9543f83cb8f33c4343259b7697630d647702696e0361bb4463ce09c993a43a6a3d6586e91bf1b6f2f811d1d00aa021014a59f2a604e98ac2c9520bdcda668ea071c0185b772ef742a0d12108d5d31f5db050f499dd1691c964f8b4f0fdfd87d630ff20dd2d79381994bc554e5a0a6675c28aa3029a82026c90dc36e2e6afa9cff17157c4abd223c32d0fa851e00b3810fd41086f996f70f4210f3e866537cf5740ea5d25d1c5e046005d2ab70a59a164e51cf8734d69225017ae31dec7e22e7f89c73d4142ada1592aa9fc0af9084c278e455add419347114e9091e0cc0e78272748f0768b32314823508c5f96fa6d9ecf91eeee7f0a26fe7fa70a63d36c0e17b211c0fac8e7d99d008a11986fe8a14e71579b320c0cb69a9c18e0ce21b84b05e6602eb14947be3b8fb72dc6cb1c118c2747c9f0e1c51d74849421efa8f7847960db87ac3785627c42318dcf801052f6530e1d9f400b6d7edf0cf3ab4a79e34a88eeffb47bfcdfbfed288f33bee34e10e2ef5f3c7a1b30e13348c45a03bb57cb870746623679be7a5da388e2794798c070657c237e99c9f62baa112ad10f94452f7647efa29b2af9751319ead32d3547e547701944ea6e501972e582e028bce328cb95d44f5da06bcb03f6b01b9db305d28c8005640a44f0814ae412568facbf0f760159a8c0ddcc216b61ae80943108f214f8450ad619395229aced19e408869395626c65742846e4e01a12f1caf615903c2d5f43e447942291ece59eadd5266953ead1c56e2178c84458d33e1ec21256f6efb2b401bc34621377978287cb68adc49db328baca2b8816e3acf4151fec28862392511b3890d5924fb8ccfb80e0ffff162acc55cad68c292a3d870a8c6bdcd527e2925fec414764e50a360563df8b0e66a12110aa221602ad88158301751d2c27e7ac06b6160550040d89890108d2746bc2041ffb69e5a9e1576433a9582a44687c99d0aa6d239bc4a269f84284242435fa50ffa8470e56ac9e073470e36a1192b65c1455936cc800da6a6353461ce610a6fee36ee21a15cd65f7cb9e28b273e9a88b1e4fa16dd2b5f352744e111d00e9d73333daff45d4ec58509ab44b73fc10963dd2edf6bda237be6b41b580822d404bd04d8d82287957dc7732ac3483b9fd5ed914ff84bb1b8fd004e10095df4472dbba1ae82d6518e64e5f829a9561baebf3f20dbfb1fabc85bbcf9ad7102fe78ef6fdd6f4e1256293cbbaf77438cd1c95f34e24a9a1b5216d3b693ce83a832f056bb717c1f616f041f15721dda784d0126bacfd38b72d0a0b2285540355d5d289d97fbee0ae7fe87cf73f3fe19dffd774b206402244359847309ad893dcadc137557c157032abf2ffbd2d49ba447d7ed9d1c95921b355ddc0ef29f60269c3cf4f61cc7a42857dff44720df6630e65e965e848e8c05069d92a16e0af00efeab49a3c80c5a595980a0ec9a1cb671ffcea44fcf1cf5c155b5c3c0145c4e7b732f3b3558e05f73237061cc6fa9d9e4a11fdb9b2945e2cb254b0628b22f63d82fe098958ca8cd0e71ad6d205bfe5b48229e00b2610208f2b5064bbaee5b05dfc7f5d9788499f851fe2cf06bf539afdda5253fb956f20e7cccf752566812f368f93d38ea9ebfdcf51c1421b6ac1b3655d6ffbc0c4bfe2988d626a284eac4e54648c07ef266ed3847b4b2ad6d08c402857e52b3e73de5b60460eb95a1f18ea0aacee1d0a80ad4812c996c2a344502c3006bd7063a78a25a5b2ffa24105ceb5edc7896d0cdb3eec2c07f37b873ff1b8bc6e3cefdeb2fdf81bceed01d3bcf3cb1cd47f880a1b785060c0199fa2b92229e412c334dc875617408566cc16e3fe4fd55064d2e48d3277df0d1b93042bf344146cdfe4c87bb8ec1c8a1c347f49a804bd94b741a1b033066e439580523cf6959b88719086911546ba828ef3fe0404486fe4a5bfbb0c7e7c1893b3e3c965ad9adbb44d3d4807f6b95ae12014ce075b80521c69a01959804b47ebe70ced2f03560aed83a964ace2c7110a2a05eabd3396bff6e633636dba6de21c4c594f1c7fc0c2ca8fd2fa35dceb129f28a09cf1efdea1f8842c316a771db24c83cc97231f56482a8993ea0f8c78f168eccf2d7ec403a83b5192f95aeb93ce58096fad8478d2b551f989ca791ec7bb4dfc0b8575afd6543e6df2be80f8e5cf58c305ede52fded057223a441ae7b43e57d9db7231de7b199f562429b13bfc6cb5b9641f54d97e388d4ee6eccaa2cebced341b5492d4a5bb6998d73193e3a5c43779514f5387ec6855abb08d4d284bf37beaa7ef958f391021f8d9d0feae0ec28e6c4023d6536c4a0722fd9e1565b917bf753a428aa7ccff1d7bf18e475c17bdc5f3178872a1d01306b8c9ec7cd9e817d66e6e00fbdffbc830d8e3fb68e164638a0ec23543ce9907d42f3721f49b1f43c907388340e2ad9973a10532104fc2ecb43416ed217081e6b03e3c1fac61219e60e1594175f5221ea948db66af4100b380fccb285dba2937e7a3025a54f5b93ab3435c7385205a28ba42c430b42ed1a9c9cbc73f6d705863c414af195e90b02f7fc0a2bb865006b14a9418171c6ecaac746afe14f12a6f488eb69cc809faa3ca2cbee776e86a14b58dda1d98da73365508d3c6f94692a75e120a8b4307cb9f814bd49bdb085a1c558c2fbaa7759fddff0eb5051a70ad4e69d36abc8d804390fbdc62f92c2d4d038e3f01ba7444fad387a48def6821d6d3198caa20ee46e0a293deb85b052b4a7d369bb86f48f3ca6578050f5d1d4cc142fcbad40a11a3b28b77903ea792870e83495c7211c3d971d2a78061f21944039dd517954edb4ec30a28798c1a7d33268c2d0c678083b7e97a2ef4d7f96ad01603e878a0fe333e312eaaa28899a35667844caa0fb0e163549996c7bfc5645ed7da1edbdf2636264968e2aa6cbb097159fd75d2f80213793f2933efa008859ca07c2b8d6d167991042ecde6c16e701763f5a6f7e5ab089f2a821d621685057dd6851832cf0d97452f362b409dfe6abed123d766bffa70f4eee4aff7ad203082fa2855d90244378c7af25988aa70fa6f64a91d2d7e634aaa98720c7633201a23877bf39360a1c6233b4082ea5e8a481d6375f4b6b29a4b43684b6702dcd9e7070be0e75cf1ac0c520250d84875564121064103f0502a5e2cf4da077a1bc3fc94adf14ba8f7e4fd4caac1e9a3d4e14b42a33a98e8434337470d6d2f532482ee890dfc6fc93e8b52d27a0f600399988530f2802a66bc7b5fee6532e650b319fec4893abcc0faec5f808f694d338a2303c51cb0fa1a227405d2c4a86c81c7e53d5af93fa28c9d276179155697ca65c95422ff9667dd12a1989bfc88bb20beee03826333aee03c8854f4b46376e4c85d62b13867df088d0168cf949251bca4ddc38bffb1683b3231b7b7d00a3a71818d0ce900c9c125765e3c0ed4eb6a03b15f7d6dd28c5a6313b8c4556f62046d285c77ec1ce2c98e258172ed7f3fa45b20b3e2cbf3336cce48bfcc78122a4840630dcbd335d19ee4b9e7b5c1e8012d067190b2b719c3b690abf7b65d8411a710af49eb593c6050ef2ed397ef675c9fa294aca748ff0706862b6c1eb0ac452f60ea00eb8b5a68e7aed6e44188b232f20f14686bdba80e55b6c0689ac953400225665484d9cd87a2ebf9004926f55568a8bbededa8f2d6b7845b61196a90ef23a97bc5c80b2de4ebc179a64c7655ee3ab677aa0017286de4175b71fb1009993f58f684fcbd81b9a475fb7b7bf71d39c134ab817c9f04cc1f6d2809ad02822dfac941bed6e6df42b9fbc0c0ae5dff0b2daa86e5e6431f786b8931dad4e2c6f361766a81421d575916bb5103137afa08846175bf23ea87d2f622691e57357af0b351019dde272f0a0b3044e161f7a31d4a83491f74ddcc86493bee377ebc4380ace1a3576fb680671bd2e9c2317132a4eb0de610a01fcecff12c280a47370c351dd02cab5bbc2ff6e17b9eed5f9fe616e54bdeb177c24acc080c66140b25460a9874b3c6b38cf619358e1a3fa4f1190296d12363f09080cc38cb0dfe7b74c5b0df52336ea2b617838b6d2e02d2ad39e5547d8cb099a965117ca80824bdcbcdb3b1f9ccae390d137b871bd0426da833a139ae4a082536b7a08e2497374f3e20d0a51fcb6a1c2cbb81cfda3b903d3175293751e4b10dea549175dc146ddb30042758416c531e0cf73cfbb23eb402cccf691bea3b87a81ad990a63c1fb0e3e6862cf28411c63162aeed81d7948fa622120a34a00edcfef49178752b729a13c429af3c0bb267eaa8a0768f32adac8f24d6bb9f1282da266736409e6023176ba8bf208268fe56af81dbb2f21939f1b72d34dcf5a02ce13b6261eba66b63e8843f1d33820064a4d9393d1de4c876a7f4184b3b3204d49922b2de90149c0a860f6cb53aeaa0e0d289d84aaf30e5a8806f8acac3965e2a901229f51ed145565b0924d50163f8c8be041c6bec508c644a38c85c4a612ac016caa23bb128b11f14439f9e2cc5039f6734355459b451e71859b8242c719c45aeef229a95f91d5ce631fe2f912661f7417228140c20c2417bc37b1dc7bafe633a17b2438364c85b08f8f7502e58b06689106fea5da1571665f7b7140551030f65c9f594f42468b5e12cc38274304bdf67215c79a7d1a74b82eabc39c82765ad928a40b1946b01d55fa09a662f7a86ee857ddedb4d8a5d9ceb97366c1cd6c8a7f933e7e3b6951dbb40079457a259fade86729f2c79494dc423ddb4097cc0ad088fa3809217c2cb5f65234ed95854ae1bed397c2e1c2a13a4f47c6887f2848d8b2e4ff9b5ebc5c32a37960e3cbe38e555032584b10e2aeb53759cb5ff8fbc6befc7e281c2d8dbeb33f54fa4437956e689f4f2270c2cd0c07a175c6dbc03e532df39fab4a4a0be1dbe5e39f033e832f0b1397391419d0d9dd537d5634a6b5762263f27b355d30e87c706aafbe4485a188339d7cdd8c0071fb5dcd4e3a18a14b88dc6a3902d28af5fc8132f97dea8b888d64a2aa2b470c7b1fb8530d434edf58c5efbd8f2ae88b7e955638d599674ef29e1e04c1eb54ad482ca57d4c4547b96ff778c78ad2854a2c30f86f3dfea158ab6e87b95ebb90b7d081ddb53aa4c7140906eba4c0324374505d22dd852d04c0a61308a50a0f3b51ebdf03d67569ab199aeb328169769b2bcda2aebdf028ef42c7a3168c5597f75db7e9ee6b1f857104fc8a473e4b62ee43b70b948a0d58cbbef236a30ddeedad6a270a13a6edb5c2d80c95d91d371fd4c2409ddb7d046f9d5e0dedea3e9e2a518092ebfe3077007d8baa5f1e23574f3a0d95b3e84bad7be02ca1135a6b7d4badc45c068a9356b76a2be43edb8b4fc36346584dd2c87a8727303263dae75ddc980ca4e81f86e6c6f193061dd506f4ae41354b6c01141e2aa3a2590fdc5e87178b401f04a8625f2d53c3f5f8c7fa14932a4cc2a2bfad70b08f61e907f2ad8e12b57dcb0c7e37ccbcf832192ba82f9014e23c013cb4f57f590c5a6f73746c9bcd8142acb66a9f26f630be9550856bb5bd420b8a0dbdbf5198680b51021dd578057fd70a1161c702952d2732122d64f625e80114b071c2690431dcd09f0e1768c0b5ec123a0ede1aeda5ebb7c3d2f59251afa0940f6d0549e5d994379db58710af7c9d7bf69ca908429cf9255c25595d818b482ea28e89407398c541ad652b67bad433b7c7d9ce4826ea1e895789b785cc469158cbf608952e1953ea387df27e1bf1760107d3e547b72b2e6f3e9eb1db4888fde82f48f53eedf45752038948a6f11c7057bc27ee12358aaac7c0b3f9a43a10000a5a671d4698c82f16d619c3ca6e53ae102c25ddcea6086f87a00abd5b950547b68b6c808b426094c9e1a413741aa6bb187b103ed9c6d09b6d68c82aa2af63ac5c81c8e928356017b7ee1a6bbb788e09a8e2ee3f85b9270f4552fd07b78f2fc784b17345846934a9c469e3231ff89ecedd24f5e7dc04d0432dad2c9f816610db840aff8970e9b5b9eec701cfed59ef22c0be37cc4bcdae5760be3ed211ce0bee1843a713684fe2cc91a4421922b15ea88c7c9402f222dc03289869bdd88e19d948b13c8269713a17100047939e6ec4124749e1bee471eb7775bce0d57944cabc3b0cdaf5fe8b88172e6051813acb9a537b651bf0a3c1cb1105629ba99be314d1ff1f9c1eedcba6ff974a1c031095ac12bd9b85611a494eb357f123c64a237b902baa3fcec855072b6e8d5c20e4718a869ca188ea257d476412d00a246625168d559c68d4caf1d91103f8f3ab8a1c0c449f6a1c781986510d29d2f987fe0bf41a8c9f9f8b9d76af59047dfbad734471382d783b6cc43ff777d5165f824042eb47f86207827c74adcf6b02b832140535d778f030cfaf3a8439abbd54ab5ef34fbb675ee751cbcdd78f0cabcee7f608be0ea96af9f66de81fa46f654028a103b317e90f52174e4d0350daf2cc84be1c2e3e63c0caf96adafc05982c872e5aea860d715a6460c915140f82dc50f6f7a7dfdf34c28e48c0311bc4ca2505f3270d8e8f18655bb5665af7e9327cce5e07bfa6962fbd3e770c2d6973e8ba3959441f61614eaab45b57fa8ef10d5d72d8adc7b11a08199091556252dc4b682e3d487279613e2930cfa34c017327409c9ca1dcc17d667a8718901faa04cf48c04eff2c218b82f975e1f19f5f96a24a3b7147107a1e70e5c0383d550793936abfeaceac4eb1c6f4c8b88caad3c748068d424b39b48b6ff065a21d92ea9972846f17fa003d4ab57bcf99f962e181f88a9e007ad599906b1df13ca4ed2cf07b6ec88dcc8dcb2968b90848aea471a30f21d46745852c7545a14c33f8c4f7b277c3d0a0b41438fba80e863f4f2ed9a46528c7b2b342b6f0bafefb4dec72851e80c182caa1892d81121d8d30bcef2defca0ee2515c428280c796fb417d7b5163672e4ef734de35fbb6a6a92a27b1dde54ac691c5f9a3fbbd67a0abb74067fd3d48ade85f2dddc142d74faa40aa82524358b3d1730fb048a35b894aa07de948bb55ef0a3d01f1b5331c71a0493e4a689fed2ed775701f6cfb459bcc6974f6211edd5375147e37e36305b34498c30b28d099a91ff27582b90531a552c20d05cec952c9860f1d7f76810d4f09953a74615939919eef38b1ad8a395acd1c3a598ca07cfed4b3c4b7410f1a08b9be11be02d7a4a1bcbe8128b06374249162c5d1edcce16b984ca6b485b95ed76038057d7cb8c9d5656931d22f7978a65a141a7e22093dc78855cdddf6f09c796d71391c6250298e15519a7d1e7c8ff5e9e0abbd9e466642112ae17577df71561a1fb415e5850c13d027ce74e0a2ee1fbe5a1a8543c251ed56d1d11fb240630447a31003f60ffd62ba44fe67d074eab3bb01d9509231d83091a71909e7dd337e569b45b7f26b7224caa9382847f44deebd31b6860462ef59a8326d3e44ef973277d818f39592ed50fea00ee47eb90b5ea23a894e55cea8809e04c688b58b4355b7da7745f4ed6fd7a9001fa474c62bcba000da1f662c9a26ae86ea14a216eac16e28ddba90843e43e2e2f0bebdd19bb2461d7982c726c53b87c13223cc42d23a3f14d9e7d7c94d50a8d4b84d6dfb30139ef8ece0c8b3581dae3c612da6f1e94bc6f1745f8477caec8954ad9a81f29d16e7b9d36b1f28e42721f9d04e3375ac7ad490af27d02a59605896c433ef560c80fb0cb780e6ce7c99a19c7c979eb0b9ed052283c946e03799a7328e444433a6919225adf938ce9f4644b21f9ea94583efa0dc4f06723145f9665b9255e0f64d39f226f8c3b5132f58c286acdfd4062f7c2a9ac09a8d420a4f475e989d5a44b3f486c1d5cb978c33ad48fb1f58d6eea85a219748920c971c4e458ebc4c981c59cdb57812aa3ea5042926a1b956d905d3e654ca8d283a1de2266b70847bd551a4d6a4c3c732de7a7cf8bd53f315db87c54ff5eaed500fd82e21807cbdef89580c5c5a8b2c40e08d5f5f3d24f4a2bfcc8fdb19b5d3c195d715b92819242f525f89d0683d359fec4be40a08fcb26b7f919ed7c0cda24f6a2d978dd282bc054dba9e2399d109c024d8caee457a08b6a4f870fe842f8a433a9cce30bf5440b6232c4b4d7781b1f431a797612c58a106bc706ae46fe777424eb0c6d8c5867c61fbf2673c2831ba4e7e139ffffe12d8295e7ff717acde83395ca901feefc7f63cc26b0058df29d0d9ed7c05004436a86866d66a921043284317aa40eac444200b25cdea026ba07c647cef7f39d90c862ebf7d6d38a6b0e32fbb5097c699321ea5d2e878885cac71edcb876afa4ae3826ec053f38ead826ca75e46236742bdbed488a361cb4ea87465d4523f552ebe86e62ad4d877e21e8d33b7ba9680c7ecc981d9696af9e2b94c6de2d7df3a3190b64540666b0a2ef7a2137a5cc52ab9b2a560e1a34b66247a2f9ce4f232d948fca030ac36d7ed63180b09dbbef36d522219543fb4fb4ce23980edd810a4d5863009635c56618a3a14dd2dfb66c31a904dd9eaabab33e1d40ec225d0b574794d2d81d4517999eb94924910886ca8dd67000cb01c0d0acf0dc0651cda2c67f2ab3831b55dfaec26b53e16985d41d82b43b2d82c0e7999c441d9f59a677536fc9fc7dafbb228a48b768458facc335cb4c305e4586a6e50da71097ae7d6e8182a5ed6926749c4c0483863d132b27347c325a66943008247370dc228f304b5a3f0161b61e5d8d1955f8440902c4a414b5c75a477bc82e201c2d72e7b20be4dfe8f516e055b3965e8cec9adec1981917af33a0b66c6936c0916093ecfcb2cd3917c3baae3081724e25bf83767fc04e476ec32ae02df04603238fd014b64caaba44af5025ebe05ea2500d8065b50e243355d04724d399b4c140b700dea7c0df965c1aaccbd0bef2da4da47ab47350916b36419eec611ba1a4c74afc1b71b10b5e46de7f0f392a87d984f4b78d4d4a076ddb910fd2657cac043e2767e3d7af4b7350691eb61567ac4829747428c07839e56cadd9a173e6a515935ef44f79043384d6aafcd66e15443bb2c5623ee4504f120602735c33ee9fc34a30ff9430240781952a01124ef1a8f614fbd5ad62d614a07a3647bf40c521217c9dcc9e5d0a6efe0e0eb28005043bfd8201fdf50384d3204953c842bf0041f1fe422d4b81fa4317d2fbd24b2f0bdfd09951ef2f1cd8a49f878078b565e468e665ff8128f12fe489348046187f213dbbab3a826d8f0b695d05316afbf99ee32fdc358dabca0d5610373bd21349ce087b237e2f5f179cc108abcbd7410aad54479a69bc67386e7d943c534885421559b405dc4312595180f99169ca83e99f820b1668afd2424eef628da83ec361b47684ba600163be100ce9f11e4f8e17728fe70c38e37cd37deba2520772065575183116e23972bd99fe66afde1b3f370180721a2733d04f7108e967a0d68b15b51748e384068baca0f3c2ec38e54e3a686b0dac46e73070636a2946cec1e4021a0ece6831db88ae8a3f277a734c8ac4b1d120c029527ea4381065bb04067f8502aba6050de23278024e89ccb5a785233556af211d6152d117056b5256a8cbf99ba8b9a0360f35bbbad36936ec41a0149e25cf1e7e766bda6813d47ded9f36e5e1bcc64f9527c46a6811c32e73496ba74d734e13ba3651a65a12119fb669385ebc9db549b65bc0cd7f29cc617b49ecff94e2522a169e27e45b8f16e29770aa04ef805f39b0319b388d8fb5ee7098483041f8e21eb1d15a708d031a8c8a448a859f9b61303574a786aa4fca4b48be9596494f7e96928f2918b7da891a08210c2527885cd564bd2ef709d8b498aa7280c7afbaaa5b8fd6e31e3d812c043ae24674d2a85a54843b7e0fc7b5efdc7c472910c0e65e7a376f526c3779cd42a80545610cfbe0fb782900c57fdc007e7ea2dfd527d317e4d84fe38d9db59d5ce745e5e64b6a4ab1a8f2644f7232df46b8011510e24f1111db6e9ebc0a20d9d951b3aa53c969880d1ee5225f0ac8ae4085f75e0cb741e3af93619f3eeb4b50eb1bbde20e7c4b6178fe8b3e965dcf4662d62a1ec40f2ad8ba9fd88ecfdb5c332459da95f6eb990b543aef74b93870bad6fb80963f7817dde0b023157195c59a2f2ff7a0b73340fdca4113d1524998f17c82a8dea8f0ee556b5843611b02079c1b78f9230e2cdc48f152271c01e32286d3e7cac435948c05f18eb75e3d69c15dd093a6d1cacca2ab386bf6f8bdf77e1445f157709a337198b378a76e93d003d69405de3e0701998a35413477208559d72ffabbec879f4d570a580d40e9e93f923c22ce3538d0696407e8d30a3b897198059e4b349b80ef4270e35a9595441406c14f32c9fec1350352afdb0a66522398053d97a4d83fc1115c7bdcbd2304324f6e4eee2aabc04b84b53f71d98c573bf5a3f4042a8e600d7c679af1034892ca0df56cfd5f42f6b5f0b0c85ec0de33e25e32b0ffc2af3706963d1ee65f465002049aab6bb937e1b162c3e8e588057dfffa6f03ca9107130b2f096afd4bbefe386cf6bc98775910a0b69ad062f8160aec10bc1ba00acdb0f7938358cbc8aadd504d5f8750cf4baa8686fd3718b67fb7728cbea0e8638afb3bd67e48da91f627ebcfa491257e73350af7f949f81230cdba8d064dfaf9c6cc8d22f2d94b3ac5b2f122ba50d8e743e11e33e4eac7193c1a5de78d4d3aba13f7add0ab3a2ee84edffa88c4faaf266b12429f623ff81f49bb12df59e9410a08c37cfdc76b0042d1eb5463780dde3554f1e9ac0f70f3a15043d31198c3e860f99f8c662189f7881239528ca592c70c63485db3650be900175bf01e69b611fc519267be933c79046059226d28849046f071092150c05866fbbd48873fc2798864e2d7c6dec69d59227aa51fb91d30970d1fbf4ba4eeafbc52bea7f9b40424371fd4fed9f92fbd5b66cd92e52f397b7e16b70417e78b60ed9b08ff1b1cd9a95082d71746fb97f832dcb003af3c5162c3f1cb3869c1c5bcfb6d671a3c1944047a5135c402136812f26d4d6adcbec84a2378999dc3140fa1393a8d9a53d2e1abb15acbab4f55516c877ed571c55acd8fc1e973e88b4fe9febe76f47c6d8d8f0f68f7d75f20787b767bcdd63e90983d0c6c1810ec79a03598a1014d371ddd6093d155766a96690d1fae88c3d89f28b535bce5ac2cb3f4b2f7d979a0486d379dff476df75a89b691f74372548a1bc24cbbb66b00971b5b87f52324ddff9a29111e65f563a5558581334f7e252791d4cd7a99b96971241060c15f7f83e2ad19ecfdd9deb1cfc49cdddc79846139f65b8ae880fb20aa25592d79d99298b050aed95491b93f68e708f80931b69835e17dac3f8ddfa70a31e76b8e3814b409940ac47bb306f6b677553eb717f8bb9cbcc3a69c87f05a3b0bee070a97bbe00b8a1ec84860cdf9fa936a3dbfffe05a9820f354bed4958c75971b4a1d06f61cdb5c4c32da096eae0e73bc65bf88de8dd0241c0a05f42e678686e6639da3b249659e2ba548a49259127c534cea98c1abc9775f2a8afa9f32ffd771af90f0a9caa8860cfc677c784d1701f6c777201b2170f5f48235c254e227c52dde5eda28664676df324192bb5cba23b3dc30b6f5a84b52a9ccb1bce4802a984a171b3a33ee1766cb7bcea519a6d35033b804ad8056001aa4aa3f24cf1bad4ddc586ce118d7d1f3542bc1300e9537a4a6da8951ea14156f5ffe28b7a5d75fa680d74c905ef1cbff966c2916cb5eba2c3f46659b33251618a7884316bde3e194d1210dbcd993ea330afcf8cc9a6bdf5b8b3c837648d78f2a48e61080181696db2d3f0396c5196f5b951f62c65b8a8b645dab511bc2a8540978950e8d2070a5b3f7a24221f5ee7530ecb4e7ce492da4c60c09dca38b166421e567783f2dc02e26f9755865684065813564150ae41c6462d41e0ca65d10c6682d16eb89501b1882840a0fea27408b06db04547a419a0143983612c6a586dfc6111a42dcef1dd22cf364f98c2308b2455fd962c7e13227b8c231fa51b007f0c63c9edb571ff4ef5009ee05dc014fd68bc10e1598eddaac8f03681cfd649b8b91d2637d3c83aeb341472088256b60546e1816b585dd46d41a238b6d47698b18d406ff77a4a46ae9e1a5e622d511e208f66e1de77b1c4f3716df1e6f9428df798b75d22d7f0ee7d6df8d54bbb3757bf17a61d9fe1f34b4943e7e31a7fcb816975f015cc1d0a8976bb8debd57cd43388682faa6229d414f82d7e1e9470f37b9528bd596ac1b51f5f61756ad42a2f7fc416eb4f1757b926e19ceb3dd188040cdb2db7b109ddd20038ff35a58904147b7a0f12412db11f801716113aac8ac6bc78e0b31ab436227e4f6d6401da8c7da3d3d6a619df2c5c19f7f21bae3693cc7ffb7ce048ddec75f5256349a5132e618e29f076be92aec1522a135e430eb29eec26da64f30bfa5ae01327df0006740ac7ba62c59e113b084be0e34b9873f93b72aadc3bb24066a22e5d4d9b84232b5be09af7cdb852ae9cc7280d526627b4713f5b8f0a3e2f10be02e659b50b49f58580ef0139185ef173bb550e2d516bb8fa65773949867f5d3b6dd28c2a623d687da37e1cd2ca57e8ea149531d04822697b2d391b303185237a353cfb88b2789732306cd741d8e608c64c554ea9cf047a601923dbfd643a388e5ca8412aac314673e45d9a013c65aa5c96ea5d18e7e9427b99d063b7a556a2b251b276f8e060bfd566a955a0d167aad142fb51aade856a9a5d434dad18d525ba969c4a35ba5b652b3d14637945aa576a3856e294d00bdaae967b4a2e8ab6845e92b6845e83dfdbe53a9a89bd5aa68b7f5aa28375a735f956e055d846e1d5d84ee0f7d947ae7fd754951b7d595a2ee9415a334ef3d596e6b2b45dcd32b56e9c67a56d145e9753ea6e1f43b8bde41719f9c923f77b7caf2a028e606d203e52e461b30a7bdf260702e3c3a03cf1b5807751767d5fdc1423ee918fd72ab34a6245ad5af2c49523a5c15a34005682f98d760124c38860682506f6bfc74022adffde499d732729a8290f0555f88f85f323fd3e5dd5b8a6207b259cedd997abf961dd51512fe17ebce7b0ec1b5df65404eee2ecb55342bf1f6286905c74ffd21e56badfc1c17b8be09edaeb03427736472ef265d05b303ee1da702e9abbbd14eec7907b0ad3b8e7910edaae9c4f59c384e2b270470ca48789ddecf244bd9b96431858c34af2321a2d895dbf8ba637d2c4d624742b7b9aeff39378124f63fc0db4fbccc6041b8afab53d631087be594c5bd9a6dd28c30fd4bfca12a4f61894e5b04ec7c3ac8481c567390f9000573cd0437f1e175d9063fcc55620bffd27a522b96c98719e1ab1d3419cb6df8316fa31923b70b37a23c0a9ed3784a233950893ae6861cfb35d777fdeafb3c7b89a99a470da656020a002b8a0d57616f17b384558e0bba7b1d2d5608e0232e75df7af0da030c1e09aa075685edc60074de273658982967cce5131b829e427a72c543053c8abab656b0d857ea58ad5f7959f7eeed6ef0e716ef5b8e7785b5e5975b2ecb27ac4f93ed5df2bc4338ef644648d753be4d7cad2c63986218cbb3b24da5983ce1764d4a558105da2e545ef180f4d5b139d3a574aab0bee71f107e21309b5ed95e9bc30a22f3a1bf3e7fc4ab84063ee3968c31df8c3be10ef5e332f796f0a968bee484f0a368b6377546d6a75bf57e7037fb4b6ee27ea911ef108c08b124584838f3f8ba1ab8ba9896e99fd1d0e51b9d9dee1a4b4b2fb99c974f2eaa4bec1e9108c0ba9cf6f1a6c9c26e40310ce33a1981e031fefe40b901f8f7e3c4b53739ccb9aba5554dbc9f68a24114e28af98ab1a4558f6bd3545431ef5caee8f7df57575053e87246a8d04145b1d29d57f256940f9b3153cc43188eb5b7bbc09b5ba46f39437e30a2267db5c269717c928b992a5c546c4ea861d060a541cf3aff57ddd6bedcb72fab6ae208c11c64c169e902fe6c2ae190e6b427f2d8eb40036438b7ffa2b28ac6066a64f1e0872a12ffd4a1c7a5c43659859d7d33eb86d4188906ccdc2cfba3e700bd392bcc818a7ae9223ccec5bec551d7b35e9e9776b8b5aff1c681351a1310c1ac6d71b87ee47f5905fab7fba7f3b38984e1abb2ef32faf0a058086ce8973fdd190ce149124034bdf99c2afa2db61815126790322cf2fc3dd6df89f71cce6fdfeec957cd7af55fef163061916b2d192199ee2bcacd0ec950120db1d580fcb56835ab2fd303d27e52f4bba5dc1e53ae5e3389f23297a735ee7e6bd07dd3d8e511e65418ab871d95fda8e578d8c855e33a497ead05cde2a7d7d9608c22065960f352aa5fa33fb29d099022163216f26079593501b76e198ebcfa4d6f834f0c47ef599f9fa8248bb59e15b25e4762a4e0ba3262e1a55a8fd9a39caf0a19490f5e0635508a4d597217e263e38811f4fcbb5f027b5954240a3c4e6696d209ddff3c6be25a3229e44da0b6a30844138edbaa4456a1cf17844e4bcf7094c7f7069cce177a77f0d0d1be36021de0fcb71429b6421ce8ae356fcd2d135301f008210c1ff02aa5886ae1ec6ca2a98b298a90ba30f93e3d2694755888601f9f8c4673a67dda32a34e0431708ecc36137ecd576ba30012e4da5d95aa2561b124ee86bfb8d81f843792b1d841f902c5a858a9e5b24fc50d23c9e49961f21a5997c1bb07f5b0c20d4bd4bf102a1b0cbb146cc3d350430629f020f10f73584aeffc93822f248784abfd13ff7472e49de8a24f8a8ca30593529121dd7ed35a9c6588b3544b70bdaaf1fa04df8b638aecf39dabe21daf76ade96fcbf9dff6ac4982d6ee790cb94b6ceae5c78849e6a34adfb0fc008c77384c9aeebb9a6e269a275ac7464ebeb5cd242ba4cd9608ecc3785d5c431fa29e999e89c550b76839ae54e2940f2815b9853760da071ad82db071a3e006b6b9abde04e107c7229a42872082e5d4f0d96cd1e26f031b46d14d30974599afe2f7e3d0f224b02ecaf1e60a9159a04ec6557bebd8523990674e59895f367d4582b852d353bd3c8919b62443b9acedd308fc89a2a934c33219c02a1a998a0d46306d5357836b1ab020e2ad89c0d23120c913cc44133ba3f186fce4ec36e6296a1bba68e72735e6d5dab9b1121454cd9c5b7b55e9d28d424188633d6db025a5a19053ace4a7b1f3ef1fc1177909d5eb57e3e2f13e11f575a57dcc90b22b73453ccb0284360899863a374c04debd9ed09116d2ed458d74b5d070a810b6befeb3238c8a90d67850afcb30d41309c1454956bd0c29be4b92436899da192d4e38e72446a0f4280dcaa543e7ec70548ba8c684734613bba300a80b2b86dab4718132ecada7e95ef30b2711a4651111b2a2b402f79d115052cda7415898545100c8f0a319738277d6ba09ddfdb61e173c7da0cb2ba95db0603175e542afe458206d469cdf2c52c6d4a54fa1a8e792cad402714b511bbfdcefc7c2c95620b4550c20797ad109eb34dd343d90a65b7469c0633d5ffa5c8396c0a429d8888a00abbe4d9fed17e27263434d318dc263dc4c0a81b22360efe2c1d60f0bfb4c16c9bcb8c1851dda2a7671a3844c8421b62edc9c3501c21ccfeca4c152797d2a229a0be699679e7535ac7361cc2a4d81d746a9b2748c6673939d347890f330e02cefcac1e6d2b8dab5392897743078a0454b9a2b2ba069468c25ba9097a40cbc20e40f1d8184671a15ad4cc8320610c830efe4c3dc4e8742d3591887d278f90d9432044e5b2d81bf4a487ca4919cac3087c19ddc9293982ef62c0502a3fb5149dac781b8dd09d5f8f092b24d21ba101aac5c7a2c59da119c15351c820069ef1d1d98e8f0a5dad2871652a06dea496aef95691ec2c306adbba00f72d913453a3beada27e5934b14d0e59ba6f6b532e5dcf70fb9c833b88c54cc788b14c563ba3f6ef6ac78ad1cc7990a5a44acee76c0f729c387d7ed79a26b949d8f4cbdb5f2aafe39ec2cbfff1de747447b38abf04dcb6a926d7be6d73dd6f26972608595dc23146e8d42eab5248341216ecb37c828f13d30edf8832d328f951709d362d0a3e152e6ade20788e0817e574b7b5726391fc3192704c4ca28878686b90fc227572078f88d534c32f177ed3a1679b7bae9aa9417173efc5c7168404c94003d112bdcc535efc2dee2cc639b59d299e2ac65e8e564ae43b5bc5b2c678f3cfcf19e1d5c6526ef631871c280988ce790689cfb48f8e41658f94b13dd204481c7d4dfb5eb18bc22075a788d41515c0e472ece71909eeb08b7a38e8c1b99683e0f4f9c10142ba00c6d1a7a1f848f2b10de780a0f26feae5d876c531fa234ed83042489e5889974cf893f1543eec737b4974a428835eb71c2f88101560d1683488c8877cba7af7d123eb986a0d0db1c1680e638acfb805e40a81686ccb6302a3110829085a40ce2a11d1f3e5849994c88c528c63f26e1fee6e32faf2941cdcb4fd002bf8da92057efe0bc17aed3550bb6ea734a77478c842fccb94dfc5e52afe530ff9b2326daff2207bfc27cd8eddaaf1d983a68d1b09fb132ab4e6c7e2324d807124c8aa5fbd2f54c3476fda77f05c5c13ac7ca14b24e2f594d094bfc36b6b10c49bbb1d3febb9bb8d3b6c59bfd7821b79cb5250b72e9f74592d70f000d056c796c43b0a900ba125042ef6ebcdcb7a56d073936100fa820d16cf885d9cc1e9f21decf769effa482510680fd2b2605040ec989a05b4e695225a4ba9d3f582d7891dfc0e01ed81f4e3b9a45376ff737711f7bd90dcb3e8fa4ac55bb53e191338e668f506b9eaa1aa2bb9607f10705220b2680c083fd7eb9a29f42e87bf75a1b4d6714e971560da93ddca1da6b69e7cb364c31482679ec697593cad270d29eba0c9d54575b72373c97cca4b13c646ff33e16f9fd54673505a4d0acc5ef433d1fc25ba406fe35b7c3236a7ab7ee49935c347b3226d7ca84894c2fdae58def3b3693cd4c407ac5744682aff96e90f2564739d5d8409f2db4875f5498a2063a77ce04535d089315465c3ba39d6d6b29a32b37b8000b6dc9a50713775072268c7dedbedf88db0f9a959c302ecc56d9ee781979bbe540c4b9ad237ac13e425c1b383ed7de5733453458440ca8d6152f854efe2ed7c60e1002f8a02c6a06ee0017fc944b05a2249e6b44bfd933c9ef3988d9e2edfdfd2d3baa95f2b0ac0a03c15deb392e97a3b55e49260a79904a0ec0f5edadbd5af3d339538132735da11d99de40d27f7ac5e9dce0710aec50094efa3d7938a421ffaa1435e23880bbdead983f08b99e3c783b2c7f38954b593966db5fd5201f2c14d258044c70f82f0a46ef21ad045bcf8283eca554103a92691debd8cd8ed3d4b7b11fbbe0e0a5258e9948c976fa46056451b22b990db4152eded2a198a9020912a3fcc252a156052e9a1b4ce09225d8b0e43641257fdf68b0b67c1fe2ba0b29f01c19843bf70c524c94343fda5295db317522a309ac24c6815208c8098fcd58e2af90b5a06480a7604215c0cd0095a8b298cd4bcabc90ec948cecaf4f61f65ef0d6eec444af0888d3509662735bd515f9b248b949894daf6c4cab9bc81b130bccf3fdb16508bc09eaf9984b9fe830e11e48aa47aef5a2a2769e805f5e1e5ec1f2aeab5efd79a208ca2969f1bb9460e5579b0c3ffe9197243fe2acd38e664e0861ccb59f8e09e330104e2ca4dd7b88a356ce0d14c1ef39f0a9c390b2850cc74f306c327cd2be80d1c7b158bc18fc3d830669f096b54101ba9f8c11c7f12041306f5e15863476626091c8d52c26ecac6c2ffb9b296f814fec4cc9cff6014bbc6601871e432371e5d4b8e4c074c81ada445694e76949c4592ad5d10c4bfc78c67e8c365254a7f93c170b027221f00bce8e2d2f05c476800ae99a9082052933608c501ae946eb084fb023a4001af736bfd9253838df9b708e6f5711fcd84da2702bd15e4e2945e18d4c45d192a1c3acbb5f8f1c61e20e5ae173419696d04bd68c43acf7224a79137f0d3e4a736edec8738b384af38be5a4d258575ccb3f4f8129c876a30177359a60d13911442b6fe2afe137aa8744791b33b8dd66853e28b3cd76e5301991843110a90f82b7e054e803770f24ed75cc18ad240f1dda3bcb1df0909c13a2a3a178807c295324436d499bb7cea689d16804c2a546576ba2892270e571a5c01fe5ce42c7fd0518b32e0e5f2d2af71b0d221c4a46d5ce799391c5806b5076d44de48fd01d061078347fa4b518e5c24e3fa4e6d35d0b110f99a9f362b5368c00bda9dea5bd160fec1c6850fd14deae68d6ede7f3a3570de7e1f7040b28cc8f510c7d351aac70fa247eab4693aa0480c8d01e0e901db89532cc9bb7dab6224c23e7ab8378277bb30a04d883e667b9977248be95eefd5c3aab21d39f188518932b1d69d59f495f64017bf064231731893b3dd17596d78010b10bba3d3720dbb2b4e63ab03d32eb4fc7d3ff83e1eaab27f50de0edfea0c68532ecbab30cc70d42e88789d3f6fac4c1955333f4c619957ca2bf24bb89a408703042ef5f5820a5f970c99ccd4650a71c0e01384ed87cf791a6d7b01b7516b6c653cb3e93d6df4b2010d701ab6e7ba519442cb9f95c14fd0038c01a2c8f5a6eba63cc3962608a22a3193245e3b44c8cfce0eb74ef934f362ed382f4176894ad05397689e55d99b1a550f09f2879b6f779ffadb2273b260d22231e763995d3c3b47055fe8b9c447f8426337a8e2b09fee9a31bb09a7fd2c08343b0e6cc158e73f3f50af10e09b2cc0dbe43c09ce7cb0f6f266503a9146f8768457654ca5136d7a407977b52cb3b03c54b6c49753585455577040c3f01c47049f1b92be6858971bac97aa5179b2cf84f7219df76b819a782d321fbdc52cd2057a37ef1db3f596af4583c164d60de4381c2c9ee5f659210187ca1b9a04f116d0fbb87e884cb8ec1eb191c699970ebdc2e8016feeb51bdc3f4ca8b0199700feaccedad5cab19d657b02e1734372e3352c8b17e55770f590136d113be1426186d3b22537bdfc8b98271ba428ac49f4cf5bfc7e99c007e7aaf7bbefe7944b84f30df23835b2a6e901510143c970d68193bcfa2ce7ea9602f01ec846e80c8d93871db47d0a220e1761e001bd794c6a0e62bf9be0901b498cfc6782daae8fcc7910810d6951ff83aa219defd00f8779ae3040f7629e6be4b03710c7bae9a591dc3034298019fd105929f0dc81413d9dc05e85cc2633683d5dc95fc32593717ea4b328dce2e5f9beeaaa2e494fd1106b2f6bdbac7fc64bead3c6d1d98fc2ebdde9c8854a607b776010d42ba0fabf95e4dd8219aaba04bd85dba43001b0d50f761280788d17e9bcca6a02d7544e82a1000cc195ceb136e8f7a4229db2c1e311c616d08590890de056293f9118d21b505c87a41d5496756dad1acdf532893edfa3f9b5f2b0aeae408fff75159f0ec1c82d037e2fd4c853884316b992c127b0d091b82ed41834c5c4d49dc3ae80aaebdb7578b2e590e247f0964f86a4439667a353e04644e9988dda060d8836af62f3a44046830766002ef6bba03270b1181fb9eb6e234710592b67009ed62e89c9059369e69705df44cd5534179b9cd0faa71bb386c035c7982ccb9e10b8bb556faf93d0f1e06ae61247e7f07b2d785a86dcc80ce29582f3c385aa8034851c213bf9bc44305e8c2ce9d0426c0f52d47f898668646b514ab2e2241c1abd261b5f13baf80b1e12ad1db3ac609c9caa553f018f1c82aca475f1f16d73445b4ffc6e0af03ddbbd178f21b2ea40e8e004e68284e2e6bfdf40e06d67b2914ba1b37d7b590a626927e2284417b888da9411983677c8b9a3cdc905c1b0f3487b99b6efdf77200b432c4608c9a60e95fb78291aaeab4a716d78e4a90908b9af2bb5d41c91b1c8504dbfb375f602e0c7e6245dd736daa3842ad3728e903c9ff1639ecae40d84da513b59d4245105ce3f733ca2ecd0c2a5f5c399bfb40f26f34a5b0b0c0fc0c093fd450f1e3653cf6715ea8bbe574b90e589a4af9179555d90d84cfaa6c248e33b3861d9b0a845827b397aceaac4df3025020e3828abfc25392b1098b14a20d64996b7a540ae7140673a68a729aff5c71c43171ae7a044e987044b0e7612fec022a7365fad1d29089925a959ba125572e1aa947323cafd7e833a1240fb8c60c54bbee6cbabbf473679f808c83e5553660f47250f6b2c1d1ce08a21f350eff6a1fcde5b2f01b7b2617c1f02d9b880d795b81974970432feab7d93d76361d7d0629ed8c54868937cddccbe22850e893e16f4c141598eb6b3df9551745f932daebeafe446431c9c9b78f4934e3ff3106935bab1015176dec37e90ac3a9090e545a2c0e3eb17fbb623cdaa3128c6ca5c44c667ac244253b84cc94608b574847cc1c50b30a577d9acca6b5206965ee8d98975638255583331a1df0a69457806ac5e0c0444292309a29f7cc8598ac2a179a2cab74ce337572cec9f2dd8168794da8c1e413c58186504c28e4457d4221d47ae2f733eb66443d0f3d36a1ead85acea7582a623a8b694ebfdd8ea301bd5e218c83f7af6fccf70a93b9fd889e29a0dedf31a252af4136ea4b37daf433412f49066ac9acea577d76cec9d1f29ad450d1c09973a12efa1a9a951ae7e6cce2425d0f9f3c3101bcbe6896d7a829c81ef60dbd60fea0591ede6e2294de91b93d84d6f402995e416057b53ffddefdfad4510247a03f21c926d5560b68ed9ad467f38a93088a6b1f5da6432fa0f72c648a6a20981bfd15af212a147595d7e8d29780f6d0bf024166fa99f4c623dfa0c3db91250e9075c973d8cd3e324a8a3a68ef41981fa8ccf9ee84d02eea008c875cc9a54a8f64131f540b6b72ac2933b24ce2520bd37550f12d856023b4986fb2c8805e48727f6c2c50df9b4ebc415c97fc44aab90d2f27e2620c5005bad74a66c87cbbdf7e17a21b803adc688d05f25dd4c26832d100b630a8e3e7fd02742fc1c5448532deea520435112acafca9dc09908cb8d6e8601406902ed6714f227effea5408f1782744bc52213777e662c85cd023d21e50e4c4a00701b40877da0bad4087cd10c52681cbeb1753e7c101f07f5b2a214c693b9ff2a3dbcfd851db058a0437f05beae019f92d75f08dfc3635780c7e9f127c06bf4f0d3e43bfa7089e31fd0f0d11246d4a740b274c696f5ba905bd1acec8acffb452a4f9d5559b056b123a71160c24f3153101fe56a2c00d86999f07ce270a532e36ec57fac13096605f9ba6483d98267e4b17dc47003e233fa70dce6e57985e4b70cc253f69418488afec5f72150123b460699119e0580e8bba7af006da0855efe7eadd469015b8abc574c66a57ebd47054e920b19ba2f65fe917e4c04d4f82aa24987883437271272978b1210ad7c65cc6953d789201e3cacdfa759cd2546bb9115338fab8e3da5b008c9c5e182f753e1c119cc93286a6dc4879701acef12c0749ba33a8504181044339437279419559ac172089b1202b0b9a72b3255a3996ca5e294b3c4ed4809ebbd8b09934a4fd2bcd358378cd7bb62ba3653b70108bc256b9d77594c966ebe21aa06845d858dc500f78cd9e866f4decd8bdd2e971cc54109f68b37c050c28cbb42ea724b62ed0667715f4ee218b256ea18c4986c2fd41d36df3cf5834ae99602efa38c7ffbf7ea1319cc10535d8a23f6060bd671534b8cced698394164c6e8368a830e909f333d6c34c3855b19868db2d6f02602748867c8b908389e97b073fcb06570592bda3366e54d0009f7d9ae4a43387b880d8c90ebfb18c04ccf3e48f994674527c123fe5e6b71ec913a05f13691045c2c8f1e1a232e93bd890192216d8a7556a4629f1fa7740c957cb5032ad3d0cba3a6547d001e1011ce5059729dcf9566d2f69686f75601428ac9d2bdc090f4f454dd6424df78ce70bbf096f9d09d1e4c15a252ce778355e84cf79a4f38c807eb1feb735f410474d247af54fdbd11f3c4fd10b5e96c642c4deff93ec3a5c697cec747fe9e9325f196b8ee1c44c45890d36d024a54e7d7ec02ec49f1ae197b0c184243aa0f86c294d713198fea818dec4137cc230acb0834eecfbd557c9d01fb07f3707b1ad5b39a4f8e0ae01f872c5b6f53eecc4d058d4e2e39a5f460bfd38b3b6d0c60baad8ff8bc69e683ce2f6af3a2e4a376ee34713484f5f5aae445be9ebe88b8086fb9b7cdf56bf9ea0dac87d77c12a5d869296f125a44c880f84b1be8a09b037cb87b9397a310a31ad137d0501c18a60c094f6592f00783d3066e5c8fc8239cf0906bdd5bbae1a67fcb643c148033f5c50941acbff1955b89fa905d99f139a16de1da54b3cf4b1b7e3fcfa6135b8c6aa2c6fa123a5ff40c954057c6a81e39f834b7bf5d56bcb6fc23ff835f95c82ae9ec8859b4da1f0287939543618f5a78e7f9fc4cf044b1dbfb74bc67843006e3e0235662e2fb72d673187c1c61778fb56cffe7cf266825b6e5ad8e7fe87aba4594dce01123bcb66c6e8ca912fee0cc1d31702785323cc933919d1b7f7ef8b3da7d66add592e63e88b72b92a9177bd07c062337207e94924ebb8395df808cfb851092e96b80388a425742022f72ea09cc7de632dabcdfa8383340677a695adab58573568f6ae2a0e03a74390e8f9b992540566c46da30dad9d82c2f8839af8ec2eb0bedc2357b3720fbeed398abbadbf4d7d8787c4cae231fa0d8571fe8319942fa095aa4c23b1418bf05ca3396e70414572ef9ebae5c15feadad4e714e6d92a3096bad7888ae0e6f8c5bcdb4641579f5933f4d64329ae4d9f5582f0720657a2ad3a73f187f312cc4e70cd0eccdc18b3df4e7b067c0baf35260155f87f382eeb828725b2b69ed2968154ddeb3d23e2d3fba160f0756907a06919dd2b15dcc419a0c50dbefca6a4cb95adf26bd171e2035f05b5bcc7813d8623b63153b925ac8271fb748df44479adb98a765949f09c69001e0e0db7cea22419ee87058d34f8be4eea7270ae64d8adf13813123b077df887fbe521ac862800df1c7770f39aa9aa4c22450e7d5c9547517cbe79ddb3151e729b097bcbdb4bdbe2a9dbd8ec32f70100508d84036437501c586401463bf4c9d9b05effaab06e841dff3e4d5f116341dffb97a039bd5045048a7592875857eb901bc5209390be4d8cdab7e8d8496589fd3340f65aab528df322c722474120e0bc91bbc29c3738bf43aa8cdf8d9aa9b97357edd70c20606de3ad4657ae2ec85890c724fea20cf29171e4264adb4bad353d2d98967dbff66b2e1abc408467a945d6ebb009945e39f043a54f044205c9aa114c76ea1dea5d20e60fc638fa35df17a0e70bd37cbfb7834dab6f32ab14ff5c9e44c9b89a5c9309c21b9872e75cbf8664c2c310eea14ae1677dc549505a40185f599ef0fcc5ad7d219c45f6bdef9664086bd07931e6e751890e640f1718c42980744fad5d49ccf9dc0f3aca92ce0b3c336e64015071cb6267de3093f920d4c51a605feeb9bf6a31aa4ca475c8ed26452ac3e74e14496853b4e0f820f2572b355d23543dd0229286789c27348b3f35a92c664a963958481c49c0098bffcddfc09dbd1fef99274c895db2bfedcf61efcd4a849028a2ea1654d730344a1250e70462c9b78e9c6bcca7fa85af0dcb42ebe224a520d824f4c1a6ee271215102d9de754046faddddf65442c6b3c7107b7fc25b6de21c74119fb5bde8e721e218a786204f4a1c89ed7e2f88fa178b793834b641fc707288647c8dc891b85ba831600a1e7c84eb35281d99434abec69fd2b311b06af6458969cc002a3ff3d3a109d904395cfbc5053a37df5a9b280623d44fdf07d448e127f53fee46ecd0fff21d7b92a35120ce1ace0877826105bf893d4a4b913f5dd92a40c84af0654e2e85617c99cd39b13184f4a78926e6025333a1d61ac6fa8857f167fad90d527131c4f2da4be8c697bd9b6cda8d6b8201f1216a0058937426645b83f1462cdcd5e8ab71f6dabdb92cf2dbe5fd9dcaa456751506180db1ccc9c568011ce0b8e1373df908e161734e3b7da10c5a007a3fec510bfec0a380675b44855bb17e4654ae594934077eb0b8ed3469e39e75ef11e79cec6a6e6481324f4a7d9c27fab24c41adaeb0628da42c44bd97d0463f329bd6a53fc8e2067267aeddd6ad9e2acb3a1552c635cad2cc3bc4bd02bf2e1f42b64902592a0ebf4cbe0133ec2da8b178a9296c8879fb04e6604ccf26371ff05999b178fe8d31e5741b3a8b55186e78c099191428c21fbcfeedb85a6198be6fc830fad987a60f47f43313eb72a49aa5f51233cd49e6ab7a8700698cd48d4c13687918d11bf59ac95e3aae679a3043d2ca8d99b4222bbea6ba416b0c492ea4366a2a228f385615c06ec739619bb035ed3225b894813b0812ef202b716ee052e06514237769e61789d95a26b1b0e58970952b1b24e1f3209acf8cde8cc917f650367b4a7503376281e51f4a1a3f7a87249354a630671a230c13cbe9d57cbc632e3b722371e61862b403c9b1048637bf9aefdbf8c6529db7102cac362832b652baae02324d2b9d0401d750df8527429be5e89f5208055410c316ccab8c700ae4a06754d5fbed5b6e9b6b4c8245fb59019c550ea648319c9bd47272b7b03e01472a018384251e1cdb58f040d9c5241f28149b70c2b07ed48049ae55131ff1e306881c068a2c198906c82839d8d4d303f215d0f501de5093d7a04f495ca82d54b05141bece06d016a1a2b239565f36ac266df1461559b2d3c34c68629f62c60f481f9f325a2a6203f881143813d34e3acb5a3e9fbbdd8a4738aef0fce663db40a218522b298dfbaa8a1d102cb6cc12b64f77acfb196e38c485d627093dc889ca124033e24d1a33eec2bdb634e60b5e0395f75d8aab193b4d290769a48d94e740ab82c94adcf8604a40805bbdc52f8fbc2a49e65a789c82ebbf55ce5c68296a653cfed5be44c5016e52a20e324013153cdbe009772c9ba351b34db65c9a99edcad14eb443fa1910c4a2d802b08552741711b8dccc9324448b9fd2de9244a9a59ea7594ab516a97fa7a67480a6f52c662e3205adc9cae4d12c9eebd296224ca5d91a07aeb651192f5d794b88a45bc8bde218d94ba92748e2549e2f846fbc31c582b7bca270629a3c2e958ef9bacc5ef34ec1813689b16e59c45464b5353a6683b44597b1a8845869a04a42c37e3ae964845b0c06637067a697f4fad40ae6a4f1398030a8d048f1ac82c71fdfd08d38f4f7fa891f64396ef8e261bf51e4ee4456020ec94c15256bbf3d706ee02f0a01d5c1ef296b865fa9dda39eebed2e0d394fcd9c3458280c6e730d843c49d0fd65bdd0dfdba480afa99fd3e06e29903649b9c1a2e2413d2f781550659cd74e3713ff92037f26ed499b1c2513777b002341906c7d88859a40b739ac1de102ea56a0f17029ebdfd645ff609b272413d8ba369bb97d5765d61c4111476b4171ca8c3675907df9e4148fffe574c1b34582f138418035a2ee2745a300cda4a07cbc0ff1d299d60cdda49244798f1b69358a11b08a96cd17027c854a084fc4a6f62cd0f787207e03e73fd68570cd3f14b01e1f8b917ff2d0478bea9081e76d32bb9928bb82d052184eef8fdc9de9b6cb9a594324919060724070707b928f42f440a3398f5a4cf83b4277f1e8cf120e8629607b18828f220569790071d162281ffb917227d0e839579580b2f4f79049fdf983004992c22752d1e0f71c2e37bdd0d12992ef9ead4765effc3a94bf92de82a280889153f541882640443d6b400e5ca51e5e1bb0b99ef13dfdddd34420a9b05786bdd7479eb4688b70e8648d663a4a1a0cf4f0dc650105158042183104a8428bf3d886b856fff6e745aac81f103140f3fdcd982b245070834df413447ceac302fa8b0d65a22cff6a0068431f44d748027a755950f4768956153e5db6d586cb47cfbadcd913642f800435f893082304458202342396403238820536641c162e44836c515ae8410cbf86024009dacbbbbb91011ebeeee4a67bc2501102470e1ad09d2f440c3f3f0edf6c5112275d27dd6647d63f540e507962f22fc50c4d797198448a1c508293144409921cd51fbf4e9f4dddd7dc3f6c882488ae21a313c48560b87c301f902e6d2afb57f1e0601be3df300e49b071ebe9b072476e0e17dea483df5cf12cd7eebd9fbbdeca32e29c75039f2018200b69c1cc51c84900e9a231ea7fe412df2c16288231f2060dc51cc419071c4335ef99cfa17a35d099d07fedb389224eb0fdcb7b7fba0543fff731d3546ef7f6970142b2b69da1a2158c1ac3144299834da7bbc5d606443558bc025ab6d07e42d4713cd441f0950f1e787688d0a2605d46b1075cfd00648f3ffdba4f1f3d42d68a229c68e0c538c1d19dea816f951a560caa7b30cc1eb2985aa514ffddaee7a0bbc2aef5e5d6b68833e8cb6d94420c41c1dd0f1818f26ea320fd5ad7e60d6e800df59e79fa0a27c7cc0a30333064dea0e680d1d933ac96892a77ef3808dfb75a456660cea624ecc89b9167362ee69cbe841940a7bc51dea2a5efce98e46aa6dfd513346cd5136622ec5cb1aa83d83a28fecc76bb687f141332bc9b7ff7483edd33f5d6b183df435eea016b990229a49232c7d775b3b2b6ef5f1e999f58ddb7cb346c29e9e7647d3a75823771eed12bda3cdfd48bf72164599ccdd667baa407666b1542d6a81a9ac9aa86ca23540a09ee6a8ada7d80cce7a5a3b4735118995a4a89a8884390c97ade4a8cce5a954dbe814a62ac526ea4a568fc5623c3cde3c6ed44d33c063a526c25252392a477577dba71ad544569a88c769057be9eb8dfaa916d1ab326789b2aaea7595eb255aa39d704dfbc9e22a10ad61976e57a7a7d76da661a9760af6b8e39258eaa170b5c84655206aa5d013668c965192e0f52496c25cbac8e6b450c730cc1ad6696ad2a06aa2a7ec978693c291c246a7a7220c76cd7491575620ea596bb4b6b8babcae1cefeb29f59ba348fb949f6819aa6df8a902516cc57a3836f58e86a9c63b622b166797688d5c2d1247fb54819c688d3ae2244a41d2d3259ee7f9ee91cc71bdbb6b77e81d861f9e9a3144a78e93f0532d12472ed80aadd123866152409dba9619833a8981d4118f6d44eb524d9404535a6aa21da0f3c8384777f0109fc7634e5341d6d8080d139914500f693887976838096ec24e6da358c993c04a4f1d86ab45580a86c3230cd723296229d8134fcb8af830beded531c61763d701c2ad158ed8639eb44e4b2908b43bc9a4a1e2e7c5b7eb5a6ba551d7e7743b5629a94aeb6dafac5a556f371159d75cd5724d13cda6b5da52759d9eac66de5a4a956bd5a294525aa56ad107746ac6b02ec308b1675413512f7a7555965924a5a232dc88d455fc1d653386553181ac5bb147b262d5b1674dcb59a7f32d094d6f49daf5166c4b2dbed58ab33c1f4c80b573cddbaf0f6a11a59ad3da5a6bad36dbaa451b176ee1a0ca53085219ccb4a995dc97ec6705593533cb2056be67ed15fc9c344c8099aaa9aaa2fec455cee9c662a5719a5cb3a02115823c5a5655a05912e5ecdd50f1fde1aa7aecf993b340be9e6a393dd9565ee50837d029fa88e396887b2b0315888aa1aa9a3472066a117daa4034b745bd39b942067447192793b513eeeb40196dc48e610251e7b1a1e2f3d854330675a31e7d10c976ea2d644eb271ad346974d58c41b9868660c0a865ae9001dd116c6caa0a445dc60f2218321d9869b47ce2e1a93d0d08814c5556eee98f5b620e974b8813d75769fd7ec7efa0ef854ba9e4e28a7a5cce399793463b75aac32ca2546ac23ca54a54429e7a98234f9d3ed5a2cfe9533bc9f36da681a86ad137760d5db8ad5e2386a78d483615552da23aa8a1544bc5f7484b3662fe590a59f399fae73384803df14d558b606316656e6bdcf8834836ee0b9dfa592691794b36ae71b354b2f2d49b4b13f553a7b86eab174444a4491d531898d4f59356e26d98c1f48fce19a6ce097e2a607af6aa94a9aff95906517a1a6e307d7a8fb9bb3d7b306350cfb3dc54b588ae40e6e92c715c32a5d56b8a6b2272cebc4693284d05cf1e4c1a3dce6c60db8ce1156822183428b6da4d152b22ceb2d3254fd225eff98c3a3d1dc1c6b9a2a70121fc3822c56faab6518aab454dd554383ad6a67aeaf474449750345c3e5dd7598c33c6b9c3d76275187b8e3fcf2f2dd7a2cf2fcd83ffbc03ff8da4e7197bd8f3e87b9e7b38478964bedeb977ded98862de7906459f986787c1603c3c3c7ea369248df4f73e30f468f3431a8ffbe058992805d93f1ad95bb0dae4652bc54ef08a78bd873ecff31bd4bdd17a5dee46a1a1a18e83bf9184f164e7414d542790656a618cfd463b1e3b1a693bbfdd0428059956289ff5599b3ef1f54c6b50bf794a0cb23d103fba727d56c75883ce617ea373d868495afef19607fd3c624a41a5d7d6d9b89fb5ef7cc2f82ea869165a833e1691cc6fc920d1f6d90b82a0df6807fdc7631a69c1ef601df8de48b3500aee5faab74fc38eea6bd6773b6b40c9891d8fa407df6e542dcdd22e32be64cc913147069c1332152850a4482193a950b162c56c26a34e8b162952c8642a54ac58319bfdfcb070e1c25db6e2675e4a014dc55c8162f6d334b70dc597a28bce8e9122f83c0b33b09f678c9f1bf427d480be5dc182d622bcf1034e9a8bf046ffbc2dc09fd0860b9f36e642f47111daa86fdb86e421122d44ba127bac2f5ebce8172fe88b7144aad55e0460084900e18d0eb2d9808006308049fef83c634c1f4100d4e88b596324086f6bb510e9bb2d56bf560e1d6760c4ce2f5e843760b88c3a31e468aad9d3ccc9ac6905d7ccc9ece9de4923f5b49f36a459fadcf7ade06aa2f977f6d4368b69f8d164ae8a10c9a62157179b869cbfaac175d06f5c0747d07f7cf61cf6d17e7ccf9c500ab2f58e8647db3717058e48dd8249e33651a6301fb5c45976daee6e447fb2b5b4b4b46a0633beb29f26eaadb6792d6a2e2f4f42f4d6f26c7ddad651dd488ad78ea4185471d7ea8a0f3c26f175348faea8f97c642f389df27d7312b5db39aa19d588d46db7c5b7bbbbf1ad4e6dad55566b9d330022cc490130634ccfdd3fb3986fd63e5a411f3a2f9edd7b69a55d5bc759ad467d9b4e6b63f5daf7f24d74f77aedcc34d3222fcb68d1e7d3468b4037aa401fcd4834aa40a207804983faacce49c3ce6e23f7ec559e51a781fd3a1ad149031b19e10e4ff8a8ad183ba573c6c0180498368e12abedc027315d1e27d01dc05fa1bf0b2801ae182700a31c2891bd2be606404c3846895fdd95af0d0fcdf9de3aadb578bce3bc47767647d53a9287248832d995d5a29087274693b14148eb0155d028f0d5e7ed49ed91950147ac3ea62022d52f9bb174559d3b08a6839d2767d51c3a47f8408788cf747c28d2761a682635d07c1b45961a680a21f6fcc4a293c3bd23c67e62d1a9a243e5195d8041021a8b4e0e9bc1a1889697214f5345702978ed90bba2c3043784111b4b4f694aa0fa92247765890d25a528466c10c161a921a1898d2155433cb121442aab7462a304ad0de828617d55cd1388267e6289d1e1c9fc02969831794964f1134b0c0b188b38fb892506c96725f2fcc41293f44535470e8c9f58614830c72b97475cc7d93f1e3ad5449d53fd9cde753d775a3d0df285cd534aa7a2ac48f1f0c03c77eedc918a727a828a59d0a3643505ca294793d0a630c7ad04941826da4473494a4be09089ac1cda2c3d4dfac00ec57d411fe4f092038391628a1c16e4e4f0608bcbcb615341268817b83c7040d69a5cfba12ac10f6b1c8041d9f1b8185830adf04f4d0c13d4d0dffee61cb2019c59e1cc2da8668361b1cf8c26648280f1b476bdab160177eedcf1b13807786685332bdc8fe28b6f4ec08fbf238f3a3b6bbf693f3aea33c2376b3588b479ae931e893231e726a2b44a29a594524a672c889383eb5f06c12e022d9822d2afafea5757659995a5a55565b81171188a759bc52ce69c6f36671773eebc3ef7130e87633a9a8eb7ba28a88128eeca2975575dd56fade9ac7c7b0725a7ebdbcb8ecbb777546cbaa92672d1357549dfdee1c84075913710ed6aa596f54a09574565bfacd795ba5197eb6ae127dc84b38e48cce5dbf114b6535add252d33366ad6ad4a85b5c85c75c156df2d70144e22f5dd7ebf9ae8e77a7dfb5d33b1e6a4f0dd2ba82e549bef9be4dbaf5213c92eae8beb082a299cb46bca264271d56ea5e07cdb269bb3f3b5e5bb76355109af59dfd54ae99bac53432ca9b5df6af876d28259fe560766f826a79ca822bee79df7bc9d92813949cdd02c2cdf5b49bdd43938409a8a4b775b7579e5f3649b69af96d3ed93ac4a2f7c3f5997eaac9a57f30b3749ca45f6d37777fbac4ddfeede224472ebc25984482eeccc340b87fb16fe1322b5b0220b332c707816487879162c9028f32c8e38e259f82c4462e19ed4fff88a10e9c70ee0674750fdcc558448b3152e0b9156a8b8f32a3c4588a4e226f1752493398a104956fb14377c0a3f1122a5f8ca148153853b4281c27d422414e2f827e434fd093711229df0f13c8b42241fd184115ede84f784482672091743a412b6d64541413d697ab07a7a5e7c4f8f8b4584f03d2e2b22eb7bdc8da0f23d3ed77c8ff384483d4344118329513c238a0710c5a1177d2a79b182174517e1e4f0a2cb4e78318e9d17dde615c38b1e5482a5173d16228937f1793c0c9178ac8d1131c3c71c0c916201a153da8e9897701e1a69c279fc133dbb0e0ffc78d1e79c347a88ef39f5ea4da239dfa87ab4ec301a0973f0619ed72367f77acc32f0a7383ccf79e8e8de67ec91df1b2d68db90d1056dcb3af2c8233b1d41ec94c7c9a01d3ceac7fcc33011d36622f6bc2c3cea831ea3e188b9e8e3d867a8009f1187e719f699f0461d1d48c3811d741b6ee0efe344ce578ffa9c317c9cc72c037f98cf878d382c685bf5fcf9cb307f133be68c41471ef9b38efa264c38ecd6361d17cc18d5c8440f1ddd57306354d7719b31866030cf43278366d8619e09186d6682c232cccbc069308ff90c15001b7164cf1f236fcc2fd133f6c831d1fdc5b147ed5133c84f9d8746693bb07f238ffa7787e73aa89c08dda3c9fc044dc98f4690790a2a2948ea9f83b058fddc9fe97b2349a98fcf309a8e9a4176ea39a45191b993adbf954dec7cf5a126a216ecd04145c98f94fcc8738fca092a285c46b31955d0a3e9f0c08fa782c24fd04640e1279c869fac6df5e7a3050dddba1ecfb37f1e6de6c5f01ed5cf10e6d166302d1ecd9bf2b2fc0ca91b75e73b72ce9e471cd8f3df19752fcbcf6ce4f760786f8af6a8241e7574b3b7638ffa748610b13da87a89169fd0127dd569a80841c2979a375344e61c39539472f08a3215441234ddc25587e98a84480d304980d85e413624c704576a30019c1d56a081cd521821a40411a10b92322abc176eb82424510394262648e29405c995365a7408a3c31926745cc85c51826891320526cc2cc2083744ca2d59547040f266e6b5606f188b45b116cddc754c90f8aef349cbd8ad753b55e78b0d288cc9a1ab841f3354719284a393041ba8a3b269c8779e54dd61e6a87dd70979891d15bb2ba54d0d56253cd1ba537524d6a207dca0640b570397d299a36cc97c97e32614479c6f71e4ac9a17c8423b7c9b89e77834c2e002eba39d47be5607bd560fb2631dbbce25c9ec08652e84c7f571df1963a44e09375a623ce0c081db93b7bf3e8bd82922c48899cec372c71cb7d76264e9817e9646aa7cfe591a39a1fc668c113d21166e0dde2ee8a27c349d832e8994dff3b35c5a23fbb208098f1dc4eed86d411ded07dfd147212c5994fd2c89104144abaa6f9873ab8e48cef2eb5707698d165d106d3e6eb76c453edd01dd7a4bfb992d76511055130b619ec05046ce51f59f269212c9af851541d3d7fd5489d4ed639f61033ad0b69fafb36d20ad41bfaaf966ad6dfee336918d48fbc88e648ee6fa3aca5c10e79332b10219f54f0ddd43be598baa5f9f209bbee315ead341a0944677d55d753974a5d75f39f75eddaa6bc3bd82e2eed862cf4f392aa790a1f2534e2147e5282ac5c5d5468bd20a942ac855a05441915a414e4b08ca5a6badb5d6363535d55c6dd26aaee6ea207aab8368aee6aa545555555db854aa2eb5aaea5e4ac7faf4244485ea537daaa195eead9deb5c17b9b79794ba48e73ad7820c11ee37a77f73cc9da5a2ca3235b350613335723596d4c8d55852a3a926d444946571d26650d2a5a253744e2f23a32a9bdbb24df7da243667973c4d7a3d986be604a8072318c277e8d62a343444c3acf282c14ab8b59fb793d97962e29773f6d0bf9c4bd0643edb66e43d6e5461220f8d1caa0a8d4226111cc976cc0346f37ae8efd08d33b7de86214f8e812e446be42b4429b830999362f7e08d1c9a4143f7cead871d11bd7148c80a75a390100adfac2d71d94203f5413f6d3823e7cf9879ff698399acff3a7036118e91d845bf9de70d5a3b923c6ce865c7a106b0b7236d13deb0fef967bbcaaef7d0660532aa31ea61ee2229d7e7ea337b3bd5ca397f341c22b5504e848d5cdf47494b8a19dfaebfcf23ede89451dfeb51dff410883282882b3e1027992b499ecc95a44f00063e6deb29238838de983f9dfa6c3a11a9d7376bd57f1cd9fa659c7327f3bf30826eb9c393fe8c016e471f57b0c3461fd6dbf1e800eadee8a33af50ae49b35f24ae192620ec48f62e3950fd754892e359117133fa7ef734e1db46957fd3c74fa81340ba6889f8763677367eda7836ef039cc3fd8e7f341bf2112f881df375a3a52adb64db25a7596671e9a95aa964bdbaa7f14b4483c32a6945a1df471d88d96aa6dd5bb9e8ea4b5b2b25556aa02592e966a0791a45a5c526012eadfd7cb3363f43c422479baaed3c0fae737ac7f947a97ddab3f7e34aa1d6d875a7fe38eefb32e68918f243847245db80b5b7ea947319fad559b3a91e6315a484724bb37ba00836eab32dd59d61556e09114c1d563da8aae155c33275632c64db5a26bf684674fd746c13e180c36929e5f918a488a1c7cf6b39f1139d4a117f3783ccf796261ad2192f7d9d0adb5a10dddba98dffa17d26e3b48233fbf9de7d6fa3c56264c715edf27d02b087a6c2461220c2207356752bc437fbffccd180db434d0ba966dc23becd7ba28764771e826c2f81ba3d5300cc31f0f822208bad725a6b81b2638b3078ea4f8dda8e2279d1e3c29936d552615dcbb8e93582d19e38c4712e78931c6184b055d96ab2ca5c555a099b15c5d6ca526d12fa0a192430984c0512335074c1839658088214dd3085263605e993159c418638c31c6f331c618bb80ab4033638cb1956c7d8a6deed4174ebc34fb9d2125de2ba781260730d869204feaccdfbff7de8bedbd3e6150fa7befbd335a2881da160ee3768107bdb5a0f1b50e5a4a29b5d6eba351a893cf067ad6d01c98d1e48792346ca67409a3c58ae9071d7e4cc9a1882c31805193e54e95333ad05862822a2fe454804a530587c7b85400149c3425308571526786139e9f65952e5865edc9dae7a8fdc5b45a0c8ca874a540c7da2a5bde5a6bdd5a5badb5555e786bdd67c613db54ecbc8b9f65952455828ce0fa2c03d8539ebf23697d96c14cf3414f623cc349c4d8eddf71d610c9f2a0df5daabdd65e5ba7841dcfeb045a71b5d7da6badb5d65a3b9271300a493e003fcb146e48c10a05203aac0c6547cacd2670b8c589c0d5161276f84213250a064d26a8d13ad3c52486890b53d58b1c6e71728ec141336f15130a20d34773321154411307c893375d7006b093c4cc102d38227c3952027be408131e0e44863092a5240d982d2dca3421c20419b0e8d839ea8e647d77848d48c6037f96506d32545843f016275719610055862a89b3e9b0077f3647ead3a16c58aa7995505cbeeb6a5e36d37e96504fa094b29d3d69125a1c54dac1bcae9c856210edcf126a04ef4ef6b219d6e16bc994279c00ff2c4ff852e1a35144ea3d5e7b4eafd46b90a61178223357506a816f36d1bcf7de3bbbaffbbaaffbe677bf1147bbf56ac3fad4f63a7bb976edcf5a58adddb45a1f9d670ffcf8aaa3fe1d715487517c04881268786e71728b9fe5094c667293179fda84c544beb6368b9fe59423a6fc9026e6840213ad1eea0451e1cc950b60c6883083d451d704654c3e8331ae615c4e31f218638c31c6425ba68430831132883e3ed4a08317295e9e9c55425562accae66b6b4b997adbcf72ca95294f4f0645c1526dc55de76fe660b132048822ae54c10202a4cd10261411e7868cafad52b04891fa9642a58ba78e007e9652708fc99840734384899718de9410028d324c99aa375f5868ea94b0e3cd8132bbaeabd382d2094fe67c29296dad09e149112a4854c170c4d4c533ebdce2e4173fcba7328f7f964f644cc839f7add5d66aadcd6d445861d42c11dbac619521db6aa565d769a35eeb5427525b2304e7fa8553b335384f5c66882092414143375875af858c10b3cf0f41cfa0d37003d0b397fd0369a1675a06a0872389a3739883383a076938a87ff373e76ed438aa7bb9a38f4dd07ab234e1eb7faedf70031c5566c3eb1fce007b3792382ec6816938b05f9f21aed5418a8da8d5e4585be3c02dc7ad080edc6a8ffb38aa8360e739bbe75f9e25103b9fdf7ef3cfdc833e1d6d8ffb78c461fd8e43bc2a245544683549a208a7339e181c0b66d2dc995a1204093250e3045f4808020e141166b8ea2ae17051422748112460a0081d303ee4aeb0a074316900852e2430e9503546870be4664ca162650810282e27a047e808f9c1871d5048b345e668fac480cdd4af5fea382e38d2a6948a24504a13040c93285da264518a0235bd37b71b93120f139398953a021532e9a163b255a2b130190166a2c6d2a46b6b4741929de69bdbed4b9690490a22932232392b961061c39d38260071b3a509072170544dce68a9a14d93252e884bbc1020cc12269e25527a6c08a26acc92281898bc1113c70816921e9aa03113a5e44d4c091d15605a00d36469088e0cedd2039210b4a8b06507255b605602b0bac5c14aacc49434f9ae5302f55dfeee0b1c99122026aa6e71f2f7b38ca26462879b179ab35259426f725e3a610b105e6fde6c89e10813c25439428622565c5e0d5e95074f727237b450cac91ded70f244a72cc2c40914906fb7659420df9ea1d849a36525e6276709068a9c92830ed83c19a45579986f6eb7ae282357554ab0852987b0045348d0d08406ac21921c8125795283865b9c24251c6901bcc5393243ecc898b062b9c5c9267e96507290a334fb594279e184ef6a5e2306425f44f0670985c993321a449e9f2514a59741c165153f4b27216857ad6615a4e6450309352febd4021317b4ab565b2148cdcb3a355921d4ebaac96aef49925ae65d87976a5e5d76d029a9e6653d143fcb2770644872d7be1dee3aecc64b52171c72261852e6044d475278b3031036776ef80e490b5e979b11beb6f613366acaaeebbacee797ef9060692b69aac070f07e964fac722e6690f9fc2c9f484d71070a9ad99be611e8eb8b49649dc5db136fc3b77e6791e77962983752ea7402d119fda6b507e8eb96189678790bf441288cd9debeb22591cc426c7a86900bfef50ee664d7751decde194268776735f2feedbc1bede30bbecd3f2e0fee62a5dedde149e66e847919c4ddd449d9f58f0cc1db4c2b52bdf7e924bad3c6aadb78ef12f169c938a06557eef26824c445ec7e964e5a4fce52a88b130f4fca6cc941072efe2c9dc63c19a455d958a9e9dfb76f2edf42f4c07407cd1c252c6c8ea69692254360f84188d59da3765950772ff94aa39e0090d5643f7e2449ee49e84dd775b4d63d0a0d81812dc5cff249094eec38e59c4f1932c392395496b8b152df3edbf38f2915baea248979418d972d4f86226c90d0300488244c477309961ea43081612a923b121a22480a53998c57f7b694284c7dfd4aebd3eca497b3e78ed6a3eee0615d47f75dd7e3019c57a8048ed5553909111909000090006315000018100a89042391389406a2b0b90714800a749a426a4c30130743418ec32888612008a218038c310620640c320a19950d02043759ce9c6b0904bcf5f909cbd65c7481c2654205b7cc431d905cf7a0b1ac251e5f4c3ba8e83c6eb8c8e30831950f372c0ac03bfc9392f890f6a39d1546cb6ea70a26f746c1ce99a1a830b658290af32dc76053f5b5e173fbb0109395ca4b160026d2de9ea58d9b32e9d65c28f7f0cc2f6d20ac224b8642085c140908a60f39b8b0e97b61af82ed0f8696c6d98210e2e9d4fa865c9a159d58e6415c969cae8fb5ac8a0e7a52e1bcdc290180471e28472e33c3f82f04e57ba58a0d3ec5018801479ab7a847562863c2c2c3b188025231826125a9516128ed36181611843238f8b3b59a80d5aacffde539b05d2104127ff964a8be111385fcfe4e34065683b6f51cbd7f4f1b48100aa4e581a80021185654809e170918192093965276ac45f0dc93004792bf39d8fbfbf506d47712608edbe95243aeb20ff80cd57e49b929a848ac62d28272e50ae7b0ad1d3b39b1bd8b7cc7cc48b4a7d6f7fd3a05e453c235b4c341bf4cab861dd157bb66538d99d642305b00b899d6b39c6955c7ae76933b92b418b6be169322c74484cef2d4a3311c38d2f77ecc75d2b47e578f171a11598b5700a47d8f867b9801d0c6d5c0b54c4c89d41de34ccdd3fd25f75d09a6f1dfa95d7c4f24f7ef5c7bbcb036e29e2683b478d9ce96fe2457c7a189f55723afe846e473607a4d6ea524999fb75d75c89d4aa02e22c8328bfd7923f99bef705981fcc22d2b42725a1cae42c25cad0b83ef047666a8fa7b0bab3eeb178f246b2d684db38355e6f6726eb691628308c0a72a08e83d1c56555f78792ffff171952e7e85180ead0af2c022a80b079e3851646f2ca51fde564d26db8599be577df87cbda5bccda0a6855b6cd0c540161e1d3ecc00cd7d7cc855c4dee61e3f04ce30b9737b702d7523aad30c700d65776288e4e4eb6b6c172ce43ae534952cd9a63232ad2b65cb260c2b5fdb7ca9a5bfd7f97dfb7138ca17b6a44c6cfa6553d7cfd78ee5f38c756f1b1af0a356423615a197961c425f647afcb00649d493a87a4cc8bf683df756bc5e59dd153801af5bd9f102f1578b5cd38919f45e3bdf723132962a3f544824f1df6c68a2ae620cb821e96e004025e5484f072d52ee597f59a7f06259b30baac796fd7841d5727c4e420af9b1c2adc6d9a6497e770d762496fe6dedcf58029ee0810fdebedb47a03fcb648245cee0b863d2ea8d664be90dd624069cc701cbc883e13f728b454031085629874adb5765ca39e8b2473eccdb76fdf7fe2c1b7c9ef090dcc8714e6910b339679873198313f6692e470a2b6591d4173c1813465969d40f32a2f6303ba7a0d470f4199021103bbca1db19e9554aa71335ebe8d8f7e2c08576e9e7da245271a62efe396a6f843a642e74e8699634f72a1ff2ee5d882a6524e7554ab3755d2411add001489d7625fa78d15fd22bbf94b1e7855b80387eb2f82c529f7b43dbdc7b31c7ef8569b492bb33880135eba6df0713d60a796a0088bcdb45c38a82efe85471abe4f283f0217be852cf32ad5f62003ee16677d549602a0c294791dbd76cd6082c17241d22ed8b064521165a80e3648024a46f4dc7a4ac27889b26b3d6e50684677bb3b747d8619ce40041f0b90403998066ed893052251fdd28b8e151acd7ba16eed5b970512a363fc4ca293068cde17df822a8b024699c14364a84da38c07dd1d32efd77214c231ac22c6956d589fefa88c49304fb5b69623ba22afd4c4cab51e8c14ba39b7ba87e43941bbd445a717670ecb96ca1b27e480571cd3288abc113716a167e168a3ba28e1f86bbf1862dd873b7aab4ea423ca4697edc1dc1dfecb79b263498edbeaa0b5eee480f8cbe6bbd0649a84de084c00c47f6683306c773aa85473e80a964024c30a04c800081e83190ff402552ae8b363bd364077c1da3221b0ca23d2569ef963d3db4a380bb249640e0fce3c776f40701581db2ae8a9d8a03940b1dc43bcec7e8cbbe50a82d05ba20f09259262436c8308fbe5db0ae5cb44b94756be3d2a4a2dfd3b106e5edfc57de022b0e29c0f643588941bbafa793ade209611e5974df089fd4e8d5c165dee0d1d01038088c6e84d6f172e4886cdc605e549f0d9fb40feae386dbc7d3ad9e696663e50b5803cfdf0ff5f4d41658bed053865ba31627fd22ad11371cc44bcc8d115d1e55d79245ff584c9ffaa98a48c2a8451d198b26cdaf60cf72461dead2f2e9f9965d06bc0228f69b82763ca3b594de80204456de8d671aa9c5fc7e581f940a7fa9d03fbd30d0bc38272ff15f0d280798973429149358fc8ec78acd126a744055c34eda8da0a5940a4e70bac84e1adbff3b8a76bc2ca4a3c432b30e29a87939cace2689006dcaf9c366dacfd1fc465e55e7a5d83a8de753caeb01c198c0e9d4aabcb1aa5b4156dca9153f6275fe8410a328b98ab1dac2672a09e0f9e416a88523955f78b31862bd06aa81f641e919a5e522bc11d42af53baeba4d8a2edd90c48fcb4e2cf74e8ce4674178b89e3880bbd87012d7daa33eb5d4cef5ec396a410baaf811b1bbacebaea9053680d9c3e111ec6981a26d0f87694b23971f49212afe0859753765f69723ff60c00f4aafb4f8379d9a882f2530abf7707b09b828411c02a194bc3894cc6a14d1bf6ab3e9ded9438b58b0e703906e141e11fb98b8016aacfe0406789bf060c72b5125310c11d18b9a9b83cd8c81f4634d7e621e5609a80f3bb2e00a35bd223b04f4165fc590682ececdd57e9e5063ed4bd958fab95e9c846fe63f11a5d27290c17c4730d6736dad0a6a7dc4a1a8ca1e60f8e94467bdbce4ce9970423c1300be3d8b27a069e8b521087e3ad1c78bc25d728bb71a82949e6182e540f75025c4c46d366d9272b89c3fe06d922c484f1ec195ace85b874f30c447935b891d07bea6aee4955887df38edd77be8c4d80e44094a16de801d3177583a4d52ac29de965dadfbb35512f9b956d93938203ddc200b6a14066d4a6b07cfad3e0c7d9ed5d8a14d08f849998720c6549b027e46100549707f7bebdcddeb86f37172a7bccd9cf626f760889ed0077d0513b49fc0b21eb5ab28c6c58cfee6ce78cb638a584a2734201cdb4061dc06cd3e82c3f624e58ed53c089267441558a3e387b2f528dbaf66cd263a9a12938859034fd29066072372e49f80fc3b21e6af4ea5e063cec0658a866dcb047d9d05f615d6c10a0a8f437807b74ecd70842aabe06051960f91cdf2fdc86824cb10318af1ca034015f00a20feea6c74470c41830d4993eaa0e5cf95779cc1e1ca1a1da5664b5f62c479580ea432b468a8ba4d6f133ced7bb3f116712144335f60d35dc6a0901d04b35ff34824d34c21ca8db918ce57cd403b540edb5ebf2f24c9f40e4c5fd4785318577d418b6b7067d322f381aa54d749e01a2298e53d079f0a38499e9816a3f09d1a1a27d273fabee72c621b87e907c8d09312ebc86b7ef74df1db48ea535d032c02182b8836b187d8996fe82573c6b778036e137ce82330363110726452dff445148173f181f0387c4e8d7b39fbf5746c3ee45de773d2ceac3133776f6fcf26b0faa0430f0ce7b59d83a3fe18a4a682e4e37ae7e11891428f8c5033646c78c1a027da5b6ae9110ba2a44fade25660675add24bdcb0fa8e6652d2edd22fe5dfd9d8270ca877fe9088a5e0b46e020c3ebe01c7db0b920d0a68144f342745d36b5cfdf25d7bde689cc055e99020c22419a5431a467624beec4a6176cbbcd36083137dbbd2fb7a400c38d983262eb330d75ce34e8b3efead9f52f5ac324d138a61432b5e4163ba1704f4e487242f72354a4c78183cc463f8378a2b9dac09bb7f3393f933ed97158921be9fd59918e1f31f1acd582463e9095e0d39dbb265e81cf77e65f480af3f58bd0202f020998c52326aa2f11282a86527287582bd5bb443e4474491dd2d1232a11db9392447213d2295c201b458b739719b01f303f42b6bc968b49dd96f988418d403e497c40c5485eda287887eebfeee89881cfe44168556e76f0481fec4cb59afda220bae47ea7a7e0f1ab0bbb687a1de5f3006cf279478d19e64a8a7543a9df9ae08ee21b956e85fa203b657728802d862283e24b1d7e42f408ce47f5e832283c026dc826506352d231e357184fc7e2218ed53616481fa5d2d7017e6801c406bc26c2b025c70b2c2a6455dbc94fd693831fb99c10c5e489cd15b18cfdba45cb98bbbe38403a00569db12ff8cd65dd771c63b6775b2ac4204e8ea49ef6b1391dd7c5373299cec29c1c7e8151ff8c83871db75c865d2fe0b356afe6f218b9b0041e43f3bb0fe2118dd607a4012aaec9e357ec0bf33f00e3ca001e8ef1ffcad037e3c0cc11d7cc9d37555afe582efa51033f0ec06e0f3e9d878e34ded4a69b44d50bb4a9a2ee771cb97ea0204f9e1a72da7fd0cd6d6868cca6960353066fec53caa32e0d40af76dd5f649f623db8cea0079f34d5ec8e90b6b926d962eb91ae3befb680c6e4bba3cb416b0208c84eee5ff062e64bd3f16ada1c480c56eeb7161e4c11ff156f568e6c4876af6bc94c05e5f6589ef421b64bc2e9a0f1e0db4692a6bf1b86d1f4397df5a66dadda272babe77725deb8238701453114fd4b8da57ab027e1ccfd8f6b225f109aa90863ddbb599ac22b9105ef735369afea56ca108b7f3abc9b0772e621458a18c1f8fe7e236e29483a46888f6d0c5ef64c95fcef2247746332d862e37737004998ca914436ca3c3f06e33a1c45a8bb2e76603b38ef66a66bda3c46d530ba37c07b214ab5af90172484f4bb99f7a4ceea2243e91df91b40108cfc3a8ebcf7efd277f6dcb2773dd3c340587ce0a62137d2b079663c1129d25bb117ee701f7aa20a03c817305a9e657b5fd4a2fab7843e4f8080ffdad3dea21bd9b614075b021ecd7515c31a3f07ba4a18ec455bb9854e99c5dae071ef3bd24b7e133db7cf07ba5379d23d1436b53193974e34233dd1c60954a9660fd1eab2896bd283d20c1949b394d16daa1927008f54e7528a1e309883e0094a7b3356da35b9029faf00322c05917d3925a4ef31e8ea408fb71f558e05a6f7eb10238415f23eec31f3b159afe8bba9597026f395e9fa8532b9121df7c5d2692a319f9b21d387e22be86bcf4026eb94481e8107c56fcc050fe1c84d2c201ca6194b1dd20d60b5ed784f8f73f2f6459c35c6d82bdb8db87670aef751fce78737ceec7b5704c9a40ea544bb5ec0dbdc12593efbb3165ff129d02970855ca9377eae0592e54728b2d84292a5e6248b98e0af93a1824ab871f6b3229b4340174f7169a061b1c3f0d09426c8883d8895b1ad2917ae417748b0441cbeae3c90904d44fcdd10833633c063dd451f88e64bdc240c621b2eae22219e5381be9d26124945641c1238dcb7fca1ceb87c4e37992c3623e08f2b4c248dd33f606f0b4618331308021540ad4b8b46eb46c359b4465959f254adbeb9f72eb1f85986ad26ea75aed544fb6fafadc28e22d6e694c5d59e9cc80d74687f56ab259c7e557b5588d3cb46ca973525b794b8fd9f75550ff59a84c60915d5bc5e163832b447308a88a69a32e818dd292b8eef84d7c00f6ed2312a9240f9826dc379f157fa078a115ab2b53968559e9edd9fcdc7d44261b6035c741f908d0fb25098f8416138b15125be48156a04c095d04505740308f2110731c1fcb71e03b7ddd5ed58c676e710fd7ae82eac64b4021db6e72003bbb34e897133de8083e38db27aab76fbce78f56a855964ec8d839bd3b2f8011795d1339f79e65da31dbf3e26cb20902567610b56538b53c356bcd708a50ee32ade65cde08e436a5117cc3d119d2c8fe2b4b5b81a2b607764d34932ce5aa79e8372467bec1fb9d9541d384c1d46dedb6a00a8297b6473265b88e2046118064f440ce72d7abd33ec2a166c5671993207f812ba45af56226b26a0dae37d26567b5a9de2a149e9c1280323a9bd80ad23d73a863321134e1738249e335048b61ec33343ef95cd0589330a7452830f95d316c7367969392b84851cc622ee227d3c339348c5e315f3c60c8613d3a77207d67e6208bed3a3df2a2202e005489a455f12a5d61d25ec1267905da54193f4cf69c3910c9fdb439a768057d94b627071d38e20f089923c792e14f577e3f4f8315dd8949c1eed18e8e7437ffd34004e143c602927c7114d75c7f3fd8f3bc7a39a433eded13b051bc8eb2e2943684889b12da0d2bea00110588366733e3ff573c107e7aa5f00a96d6a222bee9648199cac2a83433500bfe899e056d5232ad3b37010908ba0af66a4b2a475a6ed198d481c1e446426b7def172888a8a43cb1a6283a199595677f97d4b0846a01550f788769e0f8c62d1b2d4bd6b8156c4cc5eb39c6f7927f84da062c536bac1c9cffdf712a8b1e65cbffac220353f8c062bed3bd6739b2a3088d1d08cf698543d6ff2daacd60e6cf53b75ef045a619f9fec2f32649faafc026b958f40087579cc6d20891cb4a663266cebfeac1f2816d6bc4a06eb8e8d28a870c9a88489ddefc255331dd6e989c556dce807345f1a872fced4b8006e2ea8f4b9257bc15b7fb2c5cdc03a82ffee35c01564ae8997a3dc27d691fb53d08f34d0fc6723d7313659f5a6d7f51cb9c6eb4a5a52ac6697bc8cdf0b7ae306bbfcef08f4d901b295dddfa9364802e3ae3a5ac146d8e043b911e03d58eb5afd161ecbbdbacfa34e0fa275af0fa7ae12619149292c2581bad58e751d8ab692e33d17e6715efca88ef939934bb806b1d48ab9c33236bfa7774d81fbe0952be568158b6f9652016cfbecd5c15405503c766dae1ab543e67e5dbf225fdfaee03876266b44d7ab89cec90f7353ded571ac76fc77a1384fa49a8300982ec5cb790deafe23c7e17bc9c13d48a933359ffe2901bd6ef28285bec2232a0d675247192667e5476abbfd13dcd0e2409cbee6c15480ce901734ac1ee2d3968d8c8cf5d334ac6f2c4d70aed8fc36a811ce7861668e4eb9fcd2be75f6b18a26de2faed46b6f5d4461c5f91b551fe253c9e5d1edb435460ed9b08610ed326fe56647776aa1c676ea9606e5faf1825e7999cc2b16fed4edd8c5800aef329c46ed5770dabd9f9b31ba24645ca1e476edede9ca034fabf7e5c3065572030c9ada125a868bfc4331cebdef0e502f06eea56e7aabe3496fbbe2afaab1dda3c5bdbd06d4f6a62e9c4a10913eb45d1da0b9e9b8e10b92405b826869ebfaf109700d6f28a07ab9f0a0e37dd806d80b26cf0923c0f5d282941212a1eff85e2e6b60285d4791188f2f1a2c4dce6a346b7879404ae8b3b9c2f31a4f3291ec09cf1b492171b795bf4687682f5625dce53dd3a4f5c3612f0ad6aa359832ae726a55552aedfdd951d52fa603403bf3cb24c37c3af7e3893e5d82c5114a54e826c96d17a1b5362e33e1c23b7900747141d3520b428538a2dd97f6480021576642e9b731a2240b0ddbe4fdd6a352fa77c80c605e750aacfc4436617a6ff3988e91b7fc87d21354de7bac0be01707451dc9233042a7e81d19b478d7e5666bdbc92967152fc30d1c74d374ed630328c0d1dbb91c23b4fe6dc3a5e496d0f5d8547c0ba07960aea2ffce7801c3ec0a811d61fa1d4697f5f0e3c79912dea37ef5bf6c26fb24d14fa8cd1d515acf8e8577c61db31df700beea112be36f2b61ada437f50949f59a1028744022a0b9a1a292181a279f62a7c481605f9cdb027860587b6388ede2d8bae854a6833832f808351e02adf5e5c7be9fa765582e535082c55d72c44ec7b2dceebaebd34a9337a5320802f9f1280e65f0d2e28c6563c99960d7400b822b2851986003443f133ccb89006767c3ffbe00a556e403afef2bdb0bc28fde91fc163123961c0aa217671089a904505cb0751a9a794719c18d101cc1ecc3ef792a37e99697b60ac816ed3ca622f9b558d4306a1511887c5c0118f751ace5fbef539f01413aadfb440d14758692ad1eda75f757fa58fc5d39097525f0eb19d2565e649423b5ded0798fd27139748c072629790968b478470667fe24b8d47444228fac13e50d54c51bda49c0dc396133acc7781425200abaf3fb61caf44bfa5894ea06d3409363c2743980d87bbe73f8e9ec6a2c73de23569274f1e367231aff91092e402968152d35ba1ba714e7a2c12408ddeeceec8d2910087450d425ea14b091c35ed245ede166af81e2b6c7c74b804109c6e564c1ab6a0f0230d142717e661cfb83226d604d79cbebad25d3695f3fa84c711bad70d69ac3df4fe7d7abff24299cb934fc5eacb2e079adf667175f524990eb50378126e4c3b3a7601b75307f632c2c7fe26cb72b42881b6f4951bddf7c82c976543a3ed70c4c9326dcf58779789c1f310ffaf06afacce9f492b7555d6885a697f3d374327018bb9065c1a9b16280adf3593a82750e5f415f9f3d61004780a96a5f28b55789d50b90449d73ad559fa0fd1d86ba80910abb774a794487061585df91e0adf3f370e8b092886aa7d88ef7b76e5ebf73913ae7291642d3a165816590aff3aac19f9b3078bf7f43ae7c25d5bcba98f0da998ac357c0c495edde25c7b2487d3842734e016ce90026cfb90d6c77ada2e51c2c8142ea1234589c054b387003e0d046565f2ac427c1aa75fc291012205d2487835c598df6eb3cb4c406852cc393c47f38d95662cea562fb45f957c382860e184fe7199e9cbec48b5e91b618efad74fe92df0c319d9efe03a9e97ba20989e4ea537511503072e6db1e8b7cbafc28f7272004295799347472fed0ea7647d3904bd2fa943248934a4d5520389a10b0e1eca0eb691f333815642c8e00f55fd4113adebe1ca12ac478ae23a511b3f5cd456bdd7c462994eecbbfbf33a8c0488d162b3f59d56a3b97c52a506eceee6688890702d421258875871f04d1c820a1c6753008fbea4d421a0dfa9ddff8d2363afe163ec536c4bef9b2ecd45cff2250c0036bb1eab847190fe09d0c332fad03bc62236b7b2c84257f544c37f532cd7b9cd6f1b5c4abd7c6fce6262099041bafb0664671a2837c9a918bfad7f14a2f5237d2e7d696a9356ef9674072a50931c1202628f8302560c3d141e7e93e6e708ab10f3fa33874481b8843b4f0c615fcfa4b738cbd51b75a55bc4949a2b3a147f6709399328e51a867d21daf9163c58fe480267b97c81e1f4b064d4256eb2870cb6f5366bf6d2a5ae864c681a9d812ac03fa943bd04945c0e88aec9b1ff4cf425e5c17365db048841026fa17e18addf22a099debdd5bd463172cd9bd3b8f672b25ab7d05aa30eae86322827f2b8b27d55bf6eaca9be58e12f9fd0ab05d45f6fc47fd5922933a3f16b25b8a05e0f0a7644821ac25c5ff8bed461c2420f4130ae85837eeb5d37d068f01f7be4c0f2baa0d5834b4314be260be0dadd8640198c9a6d1da3d1f7723a2756ff28eada35488c2879e2b9b9a60249c07f6260ac40d38fc93b257610b3aa598bff44b4a3e0a93cb6d17af8b4e2b6e7c6a1e3682b525e1e37a191af3fb7ebe5d7915c64d83b4638e00f47c25604194905e4b5fcd79f3d7c5ca01566ce1bb15ea1773b0abf4d236cfcc63fd6d3feca55e21e872e262af6d4e5276b4ea41359c54ed52f6f107b59c60359da60ba1a479afb66cd67231d8271b60b0af9a749d6ced0e896b28f08f856098e1fc8a7bb6983604bd246bfed0d6938ab65af790790c1e508b1269e4da2f9490c9356ba2e9fbfff3b4e7435e04daef74585104aaba42c36af765589db165bec2a9e61c236733bd83ded33e66702ac843b50134f97037d8a6a064a37ddd263667e94d8dcc52bbf003392d82aa26df142caa9eaf129addb45bc1392b3179982a850d0a9da1327800c9b4d285e5bec0fda36ea7c147914fc05ca1cd8e1a592e7bfe56cd74a3c286dc83be3f442831172833cde089bc164cd08e8f2228c55fbc1aaf6eca3f29f28b1f1290f4948bfe7d236979e223e36fdcb2cd4eb7508a77ddcba333d29ffcd352c1753174be53dc4f6cc2ee5b806ca9a4d9f3ab3a6c050450f99b322edcdadfcf7be1a7ef72d3e3de8ebcb15f6491b803a8945aae411cd0282f67244b4408bfd95d0d6101faa78c985f924a819e4a1eb064503aa1e3297af2e8dd69bed43e2ab149ffc94db89bf4b46e4a8ad26984c8b2293d811f62c25a7aea93726bb9de4b231034255f4b8de6b021551c164448c9a7a71506983e8cc5b88b5b1341009b103f600aa30c5ab9038189957733ff6c29bc0a743802721d4c4920334dd1f9ac8169f6fc73d806a67ef13782d307e5d5a0e06142ef5274e881a95926dfd50453bcf909a6b2ee80c28ab2571f21d249a87fb6f19b9c57f444c50aae9a47741af88d9125943c38df904e43d73622131ca7a75841c261a40274ca871a2af05ca30a722042dcaad5f2d2943c0cb74f312b96ff01df629240b4279f653957b9c5ae611537ba34c1a9f343b3e8cd1f6b4637b79579b88940bb75c56573c813673f61251abc3c1d66671255d085a7688fac38e7f0b97284fc9d23c2a357b7da65acacb252bc2ee94edb3f2826ce574b7ff85541b216d855f98596449e2256820cb250bf6b35c91914a1d6d816e0fe0ed1ea6436a8ad66169ce9687f79028d0a8118846085c6ffb5bd120d60cd5aaa13c010d099590651e59f3b11e77bfbaac4b842c7f20755c72d958c63ac9aea73f6c9ddd19cc9d0fc2fe0238b157cf707620277c0e3150f348b8ec5b86378268d39f25044619d4f032935640b82bfa431e30ca2d12767a144862818a92c1382234bb4528dffbdf9861a643e5a4ce9405d00376a699ab2a74df7bae6c6f44c64b6387da659d4f041028e1d7923cb786f94a8c603a2342c948154a38da56bed04fc0834f4fd7a2d869d0034ad5bb646e6f4141b8928c3561199f8f430949e86154997fb68b965276e5604e23a4560432dc340ba7d3057425d10d7364039bf65ad4a3a3c1871701592d627ea4182891f681f709db36dd07398d3a5419990a8dc2e2f3d02c6fdaf31a79e0939f76ba614e4470095ff0b93375a5e2f1108157de56d995f1a0a2ea346e5492b6350f644d087cd906dcf93675d287e1737269f84212fb51f67238774cb3f188508a26d9550f53fdd8a84c6bc91c53fda2d5179b71dc17f20ce4501929edca6082dc7487d850945ece3eb33902212741910ddd4efca96d943a931658e59b1273f10ce92d4442a0e64c54e841007dcf4fca029505a3b7ca51fc425e16fbd5d509d07d69850360f56070e717b3c0197ab4fc27c202c009650e6757bcab32c1a0d5ffcac162b05377a2a04594512ae8552ab1c9e59cae30787b22443b8f6c07e8497430b8bccaee901f0be41a0366da8646f4ecdb2536e393bd60507613bb4d4cb4c2b9454f64c61ac98139d42eb5d637281ad3448b8d210f4b6524d1b9533300f5f8e2161ffa2355c0d41853839ee3f13cd6c091278240f19ebea40f4ff59cf0af444a40ae7922ad7271becddfb8590455d6ecb8b13623b7d22954421b6a96f4784fe5a943174f1ef7b6a5db0669cd2ff45b68c6553e8403d53455f4e9468c1c645c1ada9ffd25de6f8785e0004826d4da8728c9987538964e4992ac3d7df50f095f0635a50b5089a778a356efddd8c1644e91582a259b109cf46ecb4f5ac189ad052edf57d0dab23558b8fe879381cee77ac7b1d57e0c23cd540cadd89c461e61aff870762c3e4de608cbe342fad0556174096b0ca30d48e2f095695b7cc95ccf386a469fe88f6774607e4c53e03131ba8f771d86015d1b9733f21e459d89569b1328605b725fc28a979bc72c7100ab81690f7cfc54fe039a195c66bf11ce736f061e313e718c1721f2d2c604ef55e6c25858d5ab9b67d1f71432f61d0f1d902a52ee7b1c07e46e07a500191aeaaa430de1ab3608a0c91561106aaad7d5df597a063d430dc9f9581a0020990d55fb35ac222ae6d0c84b3e826e110d6e8e0b5ea675d487a9f547f12d1022a5c31c19481944f1e81509be6bcd29d05677c04354c5fdf9056799e89948d8d52e030660eaf0cac281647d599e91ae04d2db15d98d71fdc437b0f650eed3eeec764a1992abad409fbb55949b39b1bfe458304deaf7154b0f13603993d9f4abac4e925fdde6d07e3f98082284582fb9931a1a5b55f36ce92d2a562ae1cb4ee65ce45dc68268479752b02045f2ddc4b380c6a149414f807d6dfb13e41f78ccebbdbbb9554bcd64be663193e630f4232605c230975e7d947731ae4b389b61fcd25ad1042f804aa63994b31c1cf25fb3224c1fabf4297d9ae4b9f5e6418b9d55255646bec6ce11ab5a50b31ce7b418086df1268e481b953fb4bea455202ce2574c991977f42d9aa3564c339308cadfa532886216d385ee017c3795445f10151f1addb4df42b0f3f36076f6164963aea5bafc18304064683346201bc1a6bead9297059915b39b2b85d4cfdb15927409bdf8e023c762526b46e2ba440085a700a90eada594095b7e521af9e7508fab63ed98f6335e4c887feb188bc7a7388a62acf1afa1114aba1d9d69e561872395ced1484fb67cdaf1c1c9bd673304d7fa8373f7412a536d17ae588a937a5efe4e05336c5da92163cae9e7b60528198490363428169b7201a28a5d37c10e66e3580feb5a612fa15396436c164e15dd3c304cadc6e4f11a5eac2ab419bb1ff088d176e74b274088faecab1bcdd24e5c7735863624d711c501013b0cdc2e306bbb529ea0e1ecf95baf320d4c9a5312f0d0cdbdb99a5235e6f9f8399b55e196fe5405d6e63f37cd1ae20dae6f0de8f62200f731f86c990221e27dd0db5c79a863946d765a96293046a83e0118f3c46e0722f15b8575be0a101cb431930657437942ebce52e2be21c664013da5d49a5e0bac222f10c72ae6fa78cd413e3707266ed7aa205f916c77d0b52b5782a4664b5918916be5baad76d6e8f4bdd9e0fa5c5ec0f9a79589b6a881550ce237525f51edfbdae6b6a249362f1a696fc18e0ab9ac8ff0a02dbcf755dfcf8488b4b70d4bcaecbe63ec226027982c23878d0735af1000ed9d8441d408e90b111a39c28b92f4875dfc3811806713d835ba18b14ba8bd567f646fab48f9b756a2eb92f9a1ff315f35bd765d902d2ac07507bdd848ce9b15a31f147511f4e666e68d4ee633219fe602611f2d7f310f2b8664ca622fd61c1a87db9aaddbd8f8a68e55e2dbb110e25d8ec192b594334c87d12ed3eb17df55b0332c2c438b67d440512ef90c0b47ed8c06143a0579f8c503f248629982890ff826b7ce9d3bdee5a1f1c5dcb7a7803bba87d09f275501717086a133d913b7ff948936a2016b6d04c6f16e460dbd6965e509f519a91bf46cbda32b82657acf5a529479a846bcdadfb00562e806daa1d24c0ab99269f2548769c6ea8809debe3366771af87b392d7cb7a6025202da8713c03ff3a6973b43419918fb2c717c91125d0c66d66a5bdd8e030dc46017567490f6bad46ff5a6743bb2ac638a3323e696baba58ee14c9476d4728002f215ee8ed2da6aaed2fe787efde22c49cf60754cefd111b6cc68f884e516b1dfd8343d31f93501c28d4fab9094f0d8a2f3d0178161801891eeb57bb4a44db051fb4cc16021d100928d0c85d2713be6a2be0fd1458d6b25fe72a30ddac7782d87abdeae4e2b33868c026b669a55af0fb8c9a34a97b278954f44167fe14ab33f6d9d7d50b60fbe0ade21ea1978e8421160bdf898f08d4fdec2289b05ac7d1cd31f7ba9a2b283bacb1f54566d97fb018b1707a480f19cc1a0c916ef8a94752ea460261877a3035da3d894c7665d2dbb7311e925ae8cd5bbed198b81c020b13ad0191a3411e0bc10342035a30ea172e78f16955579206e4e4b0189e9903bdadcbff1309059b35b6e6785aad8b1f957d6a6225d58a31ed8bdfd2716a7e9702cfec1acd91f0a594c88d7e9eec057a4c94c8469d1bbd0b8f9f435f00aa0259fe1076719d638bf9301e4d7c9b494915c10a08d1ae5b9773585f6e8426668d6ac09ee935ceb4eb9b1df29e893295f755b45c84480e38c87f6acc8b593657ec3e0f51081bb8537cedf4e16bfce18c7bfd7ae089e3c764584993b9900be61684d22959975fd7003f1161c5a3cde139771239cda9ef83419501d5065146b460259c758b29a2cf27181de23ad2903d0bde14ecafd99a4b03379756a496be0523ad417780309a5349de66d55ad23bd9d2e0fe766be8be27424a97823398bcefdaa1d09ed3008364a8a5fd5544f9698f848a3084f4f4590d00e8360a35cf1d362e56aeaa2d71696fc47c7208e7ed476a11ed0cfb5ae20b7836275845fd00c3fe30a66e6c79992542d1c44643516b3160acefe12aaeb10d214fe730de30dff46aaf1959d6f6fe48dcd3a0be50dfd0ee209dacb1f8515fb79bd38f2a6fe8aadb4a658c94b99ae904f882bedf035b30cf8e2b664465644383f99ba25ed957c7ab3a0386f4563ded78189ebd3d1a371de50df988b13e17db1c2b93c9fa0f50d637f4ed50b9af5fad54186115cddeeaad9c4c23d1153f4ddc910aba8dcdc63500f8a30b0819d7827d48a00388362661f131de545ace8f11c5a04af2942ab7866ce216b0954a1233470709c0e05e37568a10266a644fd3161de09451d831c3e7468b05c78a6551ad3cbf056b25c266d8c4c2e5a06379cfb1cfc2ed3ada60dc17e24f94b3b517a7b3474602c6d93dca86aeafcbdc5dccef235a5b3cf095d44fb3818becc68764c0e79baaed7032f8c86479413da0ccf32a1869d47c94f267decad843de4a2bc1cf17e1e51016c93cac69997e14a26cda8deab7d852b9f3ca4f7199a2411871b6335d697e3e89261360061a7d9ab7b6fe8fd395819432ae2e4c2d577c3c0b8b97326aac0568d1503aeb395a60c7979b0e3888ad01c554bb66e505b5fc563d6377fa9700ce2a39bdef9d7b09fe506da41e170fbbcc8cea4601f3ebd177ffbde73c10ebba1423a91877743ac7ec059b009b2e9f6415dd4d44ba6bc543732fbb378f311bd1b3027e34be323e0c601e31d0907bd9a12b11c5171a11af7852a4f94ac3fd2f3255308128abcdf611f5c3644b1b7281e9b41caa654865410fa376ac3beebfd7ce61de80d56a81da98d8610c53de5cebfb610d7d547b84c9ec37eba1ec413a506a5506d8e4dd35bd5abc03d4c9fceb1e94652a0f810744aae0a29f9cf831b8ebdc59ae8160485fe1778498522edd6d9a18ea54f2630bd076e885b69407527f3f10f0b494b29d25dd7e930329ae2834520f338dfaa47d3f2001887dd3d12a3acb633e2d7558d103bb4370839af49ddda6c12cd977c6aa2e2355b8b1fdf0c124ffba103415549662ac24b32a083d452b762d4ae2416c439eb92a787f7b7521046916077c5933f90ed1c0d33bf98cec56801442fcdbe65b55d2eb2310bcc59aa71721795302ef011a8a7520932566bba572175030b5bc716b370d9a198a8399880c59fcb6b55aef4d773524f36a28d7f11dd3862abf058f245d3b508452712f7d72f1cf2ca5f6c29c386995305bebc8782079fc709f1061e4b4fee4c4a9f713fcddb9db71716dc431db63b76096f354a0d56803802f8ff29905a58110297e167cd88dd8f4b0409487f9bc26510fc48829817e8e1c4890e4186a2bda35664c88e7ba12f3ce0b171b5083484c19c3ab530fa184e17dc802120950310c6bcdef24928d138069ab608a640222d7c8526011a781a1a4e718d831ff269647a1e904766dd98498b3f9d469a984ed9e725a2b92d41e2db1429b3b845d2bbc8a37a8d2032952a1f2cc4067581af6d2bcdc44f905732ccbd264dc11732a402d29d187f494a4dec60929e38dcd84f7faf8d3b64055094987def5a5fc230477eb1ad0572cc0f718985ddc8490b1e3f1bd1538f1f72a003308ac8c1df58d2a67fafc31dcd522d490f4bda9484683e4564c0e626730938427fc25461a285cd530b7f27be6baa08f223f3a5f99e1d7ec8cb8cd56e40b843b209f9e241ff1628a2f908ac3e45e41fa289c3f464c0d5f93075b0feda419ea4d36f5a59353c7a453e554aa811464ddc4b2712b06250a29506d39abb84227ce4b921655297bcffb62841d55876785527d2301bbd63883a9a501e68a2f8a601e42a8d9983d1beb00857c3b5bebe187042efab6d91b5ddb670382fcf469793759edcb40e85f6f56866815aa0d0fcba11fc55f0e363665ff546b3cf6708821c1590048dc6bd8c38089a047567079ef15e4ae1ed89450df0ddd0e6f199caf295f0306cdc2444497b2ce3c8149c39bd2c0593b492928fa2919136400e51cb8c8daac6105b0460e9c49a02b7ea3f539cca2a98ba3f0d482dc2c552ead599cf22e176cd1ce2afadcce43bc7ed4d39b9dfd257798b560a834e6bf41dd061b1319bc33e92d15398584b0615bf59c4361c1be29f892aa2413bef4145c9a62a4603ed33d06de83568bdbd4e60e15286227f1a3df7830e9b57aa0449b2d365e90a3ce8e34bd137bc0fe3385e285a144b8c83ccb312d48dcd074e2941eaea5b6ef5479f448dbb4e6f12a6cb207c8aeef1368028e6ab837ae18af4a1c71539320350ee388f1782d3c6b4beeb9e7910b56b65414ed9a8af1560387fbf494330fa6600bcaa93e2fa8800dc8030da21527a9d3ce85d67d789df4085431881d4e4bda613c7d954c4df91f3053eb4186f4a1bf7c66252a6dddfa8c34639f1a742cdea0c05ecea5d0e598c16dca108c98cade11a1be792578bec2308fea40fbbc01888c81b4110299ca7c00fb050924c2fad926eda6eda4070e1201843675ef7c279cb5b4023996fec61c0909a0f50492dc924bf0e517075337cdf4c39c719276a72776f4fd0a1b3f14a15e3d8d97be1e4d1f246f54ca4634f25220d8f9d4c2f3124a3ed55510444dbad33f32f6a6d79b5bb20e12d44ea1ca03e7c97ea510c67641ba0d0648d3efac8da609e514efcc1a89fead14f21d74bbf47b313e812799eaae41b6d37a7af18c4a99d7ce7db9893234b488e84fefb966fbbf14bdc1a4a2ec58bc5b464f716e2dd7be2b47e247b3b1c7d7295a6efc6adbd2cf87487947e8e7beb9b6dae1e1c989c850df38439fdfb19aa3c736b7c65e6772b3241b524240074ee488568485677bdbf73351e77e221e44dc57bfe265775d85bce223f6457c31c004810d1b2de45c6e24b526a3494942c0585f4b284c43db5f3bb6351297f7ed30d2948fa9798285385074a43d07b5cb32f0dace61a0208abeea856522744069899100eeb5d9be56bdff6f59030f09a8f92ae52917c5903abfd2b6d26f7c58725d0da5f69f3be3e59e067d4b3e37d2f89d6474d810ff32d1c0e7107aafd5502ce9787580d41166b9d9149ea736dd167b32d03872c81d67e95c4f3e521be86e0137f605a2d81f78998037ffd2a61e7e3a386cf25f0737dc67a211f96aea0d6438f6402cc831550958b902bd91ea7e731d71dd04fb83a120314fc0c49a0d590bfe0f45da54bc458cb940e9653d21520ff85688878c2fdab712f3fbb6fa483640d94f9c72c3991412788d0f6bfd3402d7237c2cf7d4643f1b2ed8e0c3a9a182a4a9b6a2c78e8fd5cbd1b8f401dbecbaf5872da8794e5408ec709c4c253412bc639d699b091fbb432e8041b37b1d06d11c57e4ab1ee9c780ae3ecb9449968b339fa08125e81b4f52149881db64a406010d8d29287c08f06f29e091c093d7c274822610e11a9e5b1613c0e674d6fc09074e5c9d2d0c80f1bd883cce105d8342a855eecb9d71717cd0e05e5e222b3f82c129096305de0608e46cbc6d67748cbd0cf4654fc817860700e18cb5269b1fe6559a5e6322b232585a88b222f5d61ada73e1cb3429840ff7499f615df7e95da382e1e0e4ec554df4284042b79407f480911b18b6084afcc3c8740909b73a12ecca6fe242e27a2497010c485a64f35aaf7874e26ea032da937add48655b46fae39392223f63c868377711c4ed4dcddf98cd9fb593cb9bccc72973067859a240d33a7e025ba400349038ab936066b1c58f256747a98fa42b5a2972f0ef65663055f25d48789514d0ec6cb2d1847189e836adeb2490a2fb3a3dc19ab6760095f5d425ac34a567dfaeff340123828a0152c143d7a05974478a51d8ffbbdf8d3958a6ef28370ad6bc7f3a04809a78443e9261cdb620d378c248efd98c8a8da98d8d047180679773f786a072a9813308d8b00413a56b7052578389c25c0d4a362ad4034bda4ca423f770116a230a14cd47215ec66ac383098f9e13f4d848399db9c84258533a8b7ab326cd0a41a0ead1404ddc8d7f9964d5695ce5e99f907f0ce2aa28e717f5158d0047f3b86ebcdd02ebbe5879dd8cd27e60691ad8302e913ce7cce2af28dd464cef730947a6833235981e9aa12caec70303c4e52f8c027e934fb92a8a3a55fa0488979ed9947eefb6c39ddf681d64fcc333de4fb6d247bd0c3f9fc6a9c6a4e20d988b417aa4a61cdbd62f79358fb8adfc5633f70cc5d0b05cdb756a2ca866d185d22518579501555a0e47d58660c412d98d249d46e7d270ec7ffa230e93485f88f92c189afd1a8c331a9b1ed08d30de8d7ada17c1742b9db6b488221110f9941367eb8f47105301edf43d830bf1ce932ac4a06c58b8d305850ed48f2419c74f47ba98bb2ce1ec66d5220b8273d4ff2d15dddf3fc36b809e017092b3dbf1700d95d7bb29580272bce9a1642049bc3043db088e7994a90ee6c1064562a2e957349182a96fa0006841063abfccdcaf7ac48955a31828204a193c768bc20884dbdb8334528d8dc3f5fa45206eda2250c5b446600c152c033fab6a617e387c87846ae6e39f91047c9150c86058453a4417f0e6d67aa5442f48d90c93166e94ca0cec8b324fe441c4f7410d8a8dc2848b8c63d75e97ac258a0aefa8a70468f34ae2925e0b8c30575e7ecc0c78707016d712d665fd0bc63ced1b1a7c2a8f97516dea822fb76dc448a5edf2b55ea92f5f3041706f70771a9190c69f2f66c306c1b019bb0d4fd4a78e6a9d73657bb113fc633e28fd77fea7c24c388d046efcc242f98a9a21de0dbaa88d868e2d18ce114c53ba073358495701125780f8b58d312692e601a1d97ffd6c9b9fe4d4bc19fb8b60604054538c3e6adc2d64cce23a5ab10d82f2d594d3ab0e09841b0b112efb19c2a6e3914876a7df40cb65c6e0846d2869ce542e1f25f9d06ffd882efa13e5f482d640c43c5a41e2a12945b3dcd1bac9cf64193d48aec2b63808bdafadcf67c077a9fa4bb543c4b425dc892ed699d73d067b1698b377018e293dde6b0cde9c7057a1ffb0bf4462d42f8ad9f8947739c6fdea9cc79961e1ad08047ae77cb484b07af5207ee121999236d151568cf7212d99876c313072529f7a479e4d73df7a4691d6421b09844dd1a9bf38bcb69ec2b5f8da3fadb44e7d9149de830a5056ae5f2dc1f4b719cb7b9d55fdd3043fdc61722bb8fc790a8527ba7270fc62b61888d215f186b4358a9fe0e34ce7b1608c371adde4412745000c38c844b02514a6bdeecde9c742c356f5e02c5184285f701ad782bd10586b66a07c01341b1b9186e03d5a9b0e4dc32aaea0577412e0e14846bea82a75d5a90cb4efbeb9e7d7a1e55939461df5d983e4e74a02f95b837e395053c2b08b488b82c28abbddf8cc9e98f9aebd4a70416b2734ae739a177315b1073cb46bce298c4fa8e6a82bc7d63a950a7c20074e886b24560eaffbc837d609a43155856200240e213e0c6578fb415ea778228be065bd72eca2582b174e73eb90560a62f6a2f2f38d201b3bba728a171bff676d10480f3a9f31e6dea54353ea41bb24d90e96e929e65aa93dba7e649a2141d9fcfeff3f31be30154f0271ae6b49fd5abdd97199d9d92c0994516412f15a0f6cebbf5e4783e7d739d6c2d279d83d3ae04b9752abd68eb2c6c4e0bba037be2571c57e1e01906fc13619448a0cd3577f7ce3d2a05f7530152553f9ba363e4f2c617168723738ed1e144c09736857e0ecefb1032e17981d30b81f53f3c23e16f98a39eed1f8a62ec943ade2654b91397281dae75f00079b572b29d9cd676b8358c380b384ea2422271cc2936c4eed234594eb43201bb5621938b7dc591ce2b20235f1e8543c1490ace10e414ab60157c6432d88d90be951da002e02a91dd0fe4d064255a8abd2addf55a4f71b641e3120fc4f7a831fc9b0c8a27dcd9fdd12a05c5728cd381ccddebef0296b1cf37fa83ce51af2990f20bb284845141114b7bbaac2fe8e2ea4149d49e071f4da8788ac8ccefb49f260487c81155b45799f3dd00726f74281e95969bb44f6d099fabb875e1a3e92a296efa093f2d44326464ba4652add2662727e0988afd50836e592837f57bd88f2530a20bbc29fc3d08f6c561775498a603e7ba562a06b2e7c7f257d6b21a34eec1df01d465641ce9257145833a419abdbe6b0daac71ba91b40f7f9060e06614819b1d02d3f6f2ff5c02bd0542256ca93a604142a590e812c8919278139692d638323185eafed048c51eb5e1f605e6355d281b45e9cee158081425b81389234dd5889e70a34af4b389d90019fd33ac58c1e1343934302c2ac779223c4a69eb133695f236aa8521097c46d8b43d1412b422a08498606f2bbc6ea4540d841ecba008b7b1aa5e85257d526c12a852883d2bae2d433eb97d116269cfeca700c621ca944953029f55c43547882c2bfed8750478ca257022a9f1e1315ced868237d10901a42c1dcf32b4033e58577e93f3cb2ce51d0e3274669c44f3b8c62a7cfaa00e7acf044573521b2bfdd680deacee54cca27657c5322c717180c4cf19d8e20be524918cb5149a69d6dc37c5a4d6a0039214dca5bddbded62b3e63aaa4bde6fd41626c2566fe11fe633a5694012d6b353f175c9eb19ca1ad25d02aeb9586dae999dd0dedbe4623904f94f5a4c0741e192bc4c294bb651ee3d7310d99323537924296ea8e18f8d9616b94e009a07e6e4ebe59281ed31f6f08164b9ab9ddcb9570e3423d81e3a6e4faea3520d3f461cf4767890701b72ef60b237dbe061ccce5b35555088fbcf534febf62b357809990d5db3250a471962287b122ed40c6a0d9e71ea82c98a91cd7bf0d3c4d118a8250c4d1c5987c4581a6febe334fb895be2703491befa598047a64ed0aa95d201327f8e124399f5ce00ba7739a7b90d7d9aff7c58e5036032060c970a700d851dc23706dc530f2c140dd8bbb56072a4453aed64ba043db8ac739cb987e064535c761801d30d58c77810def7bcedd4904a2252c94ec37a020f5ffe87aaf872d8f6bd0e2470af0b4594823e6a7643e291024c3978b8ad40f8963670091493a660937294efa581ca8c8c5684339a09357a69f9bc0baa4649c974234d77222c8e3b76fc2ab08b6b5c4267ab6697d120ff8a635830324149bf55fc705fc09f8e4905e1c5071af1f6a56478bf4f15001e39a1b9c128ac8f38719750e0ef800b2d8dcdcb391ea9973a0f2be11408a1e2c63b84d178b23e249289cdabc22171cf505f9d130401a12d1f87977027da0ab7316ded4b0512fae9d927e9621c5c5b61c9928a42286506869b360665fdb5d8efc1c1974d861e59600e45cadff72ccdc3a97e2ffcb918ac0f3a7d0fc0a822959b047d253e044b464ebb6ca1d0812466a784111608ab4d6ed7b6b2f62a5a948d276318a8e71323f18bf4b20481ac87081105e5b4c7ec85cb0740fbec8161feea796c045c2df71f8744501588fbd535195b5745ae74ca43058c35db926bf634f37a51a655db4b7bbe9de709eaf5b9c800e6c2a5292eec9d91562718905d7021b8fee40c2c7261cf3ab0032f811c6473d603ac2b46e26c19ee9e6a2947f674d9e409e5fe482fbf9e06a8b2cfea35fa3ea11a6ca73a1b63ec8cfafc0f27f1171dcb0df4f8b2aab849e3ac57f08cfb1b25a4ae2a9e822bf6742771c2878c8ff70abde039a7c47d69c49b2ea781efbc70eea9d7bf8eb4fd5addf64e901f3d0d43bdee6fd5182214109961f297f4e7300cd0cf52b92174227b917d23a7138cb595254849a700fab5d105b7659f40cd262441f98ea0f6dd8fd78b53f32ae6fbf04f988a568190f22597a6ffabf185e125b0a319e249a5e5c683a34acb214e1751c57af9692a1c2aa6f16227ef263ab41c9fcdb461e7ec25402bdb81d462b1ca3d4f8e2071a66a481908da9df287bb73d55e6734504a6cdd67cd22b96a4a13088a7af58abdfd4c900d1f12e11519a5a2f8b7b36e46a0c5fd34d954fa7ac0d1328d6a3bca429da0c86cfe7e1b808d3c08bdf50e964cb14bad649e8834916d583e4ede40d1203d6b8bede74e934ac8c3fa8ca1d44573e2efb031a0698bedea92f3ded65c7e5917985540e95e503e27b2b4f508f4668ea2b8e2ebb411c8845e9d34598495854f992753cde7636ea726d4c86630eb55aeeb64b834ce1bf6649f56b593bdf92337ca9c33d51533e333e18046a5e6d8935d3740d5040a17536d5c4d6c906d66fe98ccd872edb95cc836c1b79288d51ccaac765be4f6459537485f7c3862f6c40bb9aeeee91724e23357bcbbd4faba9402f4ab4b4643172c8c3c1aa6190757e8078d3235168eaf6be22f5d0c56381909b1f5b52b1c77f52423d32742dc1ee0221c1941b4840f91224bdd5a309454c274783d3887f86f6b551bb1d118742d8f015e9cc604d5499e04dd1117123e2bcdc17f7c13c493355c517a5237f7c2f7c094008da4b01c2722594451d901bfa24a3245a6a6ca254257be50dc176493dd90ca686fec55b599a4f8cdadd0411bb23628d0fabb30ccb766eb78020b42bfd53044551b9c6869654dc48ac4e8009bd931b697888fc1cd93750f63dec02f454f84d1158a958433de339a90d23d5b84f3fd845c2671d3015fc910800aae14fb8ee77ff854fd9d7b612a194ec1f837eb3e88dc524c20a483cebf9d5bce81cde1c7157f9dfc429a32c63a61ad94851a28cceebb0be32062fe9f340c9636d54f328de21bbf354ce014b9f6019ae16e361c2b36bfc2008d8e21da688bf12c56d4b8a7b0cd6b3250c35a53c8b96d05093ddf9df547466cb4a1ff6fc383f4fcc5fa081af5a79fd68749c2d56ab3900ab53c7386867815ed5ce1dc3a0555730efc0110910a21ab2ce7f5d0c5213244f0a7a2d09335e842b2650f23108d1d582e004aeec5f3fdcfe5816693de0b43746e0338215599c82c510a97d7b6d4801b76d55f7dba28f936297a3a8679707ac0c2b66cfe1cd0b3df50e4f8c6398097b78833f061557849ae3b6a723c4088eb57eee80069782d66cc158fd9b87a7328b8762adaf633aaf73f53328e6d6ce5451c37a7e4f67a215f60a6d41e973e895de8afbe1f86212dc104cebf1150912cbc05cb65b2e89e407bdd4596932f04d724bf2f326b00ba31b01cfcdb6d2ec2f060a30125dd250c7114641235ce85344d37441f421106ce88b4c1e181f2c8c9193ee968b369c40ea369baf0b48541c3852992327879cf6414b9ae9865d1ccecffb7cbacc360f693d2ce8e0827619889f73f6dc2ab629cf98d5224ad5e1f11f4cc10874a6b85c1586308a4fef486ca092c569027bc4693d76c616655f6e69c85892633df24ceb124dce334a2701859bf771091b7a9c60af8c4bf3060e120b7824e8791a3ab75063b360d307976eab29a22b027f905b2fce02069070de1ca8acb816f352c62e7ff2068e57a4106a6a5f416e6fcb6d63a8e78e0d89790f30879fc96a0b711e98b4c24210174522a076f6f4d34c0f5e87569ec9823da547063ef0bfc023690ef2de0359c5c10f72f68944baf21614c8244b6d327adc2c5dde567094a0e864d7e7f16367fa6d4450e080de2fe724010097ae5b91bba4f03b17b059d8f0b1cb8c08a36b00c11a2607c67af2c8b623c44b0738c98cfb1f49a41293c968b79a88ad3f6979adb7faeb584cbdd64ce0e2a86299c37995fd1004a477e22e112fca54a2497f5f8b53ab671a312cd250de6a9b7390463b2fc740bcc326ac29b837c8623a70a29e340dccc0a39c1c2c25af5d25d3d0537ddb4212fb55dac0c14ab0404260d60ca53e7db7bb4761ecf898078d86df602d6c816b8c8a930f0baba9b3220ad5ce418569518f45e9bae8e94c0deae6c9bdd31219649e25accc3b91ffee7c455f88af4ba88066539f968702906f74e670ef1273b74770cb47af75af202c0b1859541585036493bdd79db7ad1d0416481604b7814b3198cee24f900bb59c1e48645f117d2f2248971821950a0c75ff38cee086621c31c2d499d571ab2e947031d82e2564fac92dec4462d3dbd303aa03ae2ff1bdd91798f5d48cf68620d3c6ce7412d54a928a7daac937d70ad43063c78dd9d9f5ef1a9e60312b5f561481b021102ef371d4832082792fbc6afc37de3c954881672ff39c578d63c86cd3a4e5a841b003e65a9416f723fa8a499e56ce44df44095bd0aa738ee99675c56b98770430d16a30e9bc5f80a7581014a43f9371418d78a8f5a4c994f4ecef1a3ac7b6e7109b57eff9938895f9b203aeba58f9a4c0612c349510dd91f1854d4d8205f7c60864207ba4f9dc082f626fd18187a0935f1bcc422ddbb05ab2fa2aca7cf3645a91861010925209e6330258b33a054e3cd591871c413111dcfdee71d43faffa1e6b33b5e90de2e1e3f5d4c20b175739eea7787c667ed2800bdc8bb4633fcc4aad77b4cf031c1f2b9b790da2d2791816b2781be77ee73e2119044914e6fa934b3e9b635b5f80f28eef14f138763c76c6f7c013b7593cfa967d5ea5f1811b6c9fbadfcb5a654ec8996e0ed9a470354e2341a134a61854010f9e30412e59b5a2339e154c7f4935141a705faa58ce7a9be08633df21754b00cb7e297b919f6aa4fa704b050278c457440b187a14ce7ef5fdc83fdf0e97de1838871c18580dc0b5747214b354878a23b9729416404798453fa721817e19bf20689020a44e139cad0947866847a6369bea7b9aa5c54ddf10e668d311ab4ca94a0de82a6a6209e18c8a2e010f09be64f9276740d66e45916219e3cf5df6bcbb0e73d75aef789478cbe93cd0337656258bf3e3ec34138bce746840f77db75aa5a86701dda9c6f98b0fdee31044522a26172cb42e5f685f759f60ab90810b82c9ea7716f7ed3d8078cbf2f5878db9e16a5cd69ac240ebc99b17dc37b7b1e3bf25065fb8d735d3f4c665283189fb0a7bd373da0f1c9d70e444cf311c2ae5e032c6d63e9266710e33ad7d1724bf7fbd7df4950a0196d9b6558a1bd24aa28a4dcc41b4049ed4bb0259bd4444372d26163be1fc56f029ddd24ced93a441404fa523fa9592052ba92160366452bf55cb0e97813116ee22bc6c94bffca56f16e5559efa5cfabf4b3efa637db33f8ba01079c049b59dc1cccd1018818e49a4e6dd915850f970da4c33e81b4a15b2df6fe64fbdb6eb2112292882412d9dd3b670ae809490af897e8713b8da7daf36c8479d4475bfc6c6824b9e96d364b6f6cec8fa8e538f9c4cb1177d9e24711b2ce84ec3599bbcc379f79759a8cbab18a6ca5525765d6d6c5548c5d0a8c38c2977d747bdfe2b6594ab9544ab3b667c78f60c411ec33ac7f48c1487447ef199c37194e1eac3f248aca4698107fe4e9eeb52be276d45f77ee1c77da01e12896a5a48a0759c4ec6ff8bac11395ddb3e12b4b1afb064e36e8f24492cd6decb346d9f4892d1b68c3d7134eb6135f9cb8b25f4e98d9777ba74f4ebbaab2fb8cee3bb5b038971514f3678cd709d976e47e313831ecf489eb806097fb2a67c7b2fc0d4b27e7068ecb2ec8e6e91b8336a63f11eef5eebdf7685bddfb39e3bd79ef8ffac8dc47de371cefdb731c47e7a04f38f42782d30dfdb5b0c8d1dfb9e8684cdf680cc3f4f661ff8a44ecea230f495e782bf7617a4a25579cf14bda7bd234f6278f248fe665d858fe26d1dc5ea4f1979a99fb8b459fdc933e8db9ffb86799dedec3937152da2ef273b303b61afb7cf68fd34e2d2c7656b30c63f912b0b303ecec5fcf4f369fb11b14364dc7cc6bfde55c3e33623b944dbe8ddf0b3b1488e6bba279ec62e208d8a38edf76546702c6ba97f527c2750e8d43dfd0d1f1725e67fedb3486bdeb4c983fbafa8b5c57c4ed1967fc6603bb0df69ac389c2de615a47db28ac1c7372a4f203635352311b3b273471325ee5ec3739751bd926d7e4295d9e125445a0b9a67aec4cc00f9a2a115a97da0b82d8b2b67387fb67dba8bf9eadd2471a1d1347c062d498f6fbf8abdd93d9a3fee2d63e2b5b7463285cd53d6df547b74ab3b663cfa6882042abf5af56184fd9b5de63457eb6f7afc8cfb6d9872453b933c1fb91d5cfba226e7b8f53aed8b5c65af557e467dfa3b4f5f40783d2beef3e268e009f368d547e603be5ee4cd33151044cd71bf15464077ca48840546c65832b58b4506a832d5e36a5d4670a9b7dc1b264d30d5f58b234c92beeccf1e1d8572ce6248fc9552136bd22aee0c29dcfe26fb5213c3dcd93ea8db6270cd3aeaaddde95dde8be62a737c2c7be356def747cdab48bdabbe0e4c96ed49dbed66f3752bdfe56b1f9bda6a3938bc9a8e6d8b186b50bb3da9569976b3ba5bf37ca4edf4549bdbba7e3cbb5845d751b1dab68573d8d76a9b4cbd3aeeed57dbbd52e4c9e69647f9f695776ef291da368173d4abbbc8da9d3435c4c46d6b569abf13432afe392a66393a7a626ab1ea72af831ca939d56af9c328d5f98b670884a95529496062569ed93956d49a7c95397e0482153e6b96ba61b27d350c250528e67f20cce53ce99e4eb3061691d6b73305e59b90b1cdd5c07647b2aa5e50fc9cef947f34f3ee12e246988434caaabaecc3552bf6084e33a371ac0710e757e63001a87eb5aec6abadb78771b2ca2ee35ef5ef32fae56f9a3a9afb7389989ea178c7070985e3062dd429d84a35d3867e9e86af3d19112d658438dcd22b2f9fdbe918b7008dee423f1dec6ef6de82331758445745ff3fb1a1dc3dc47341a69eeedaded39bd5cd06244bb988c70ae733879a68e76c5a5c9630500ffa0d3ce3ff814807f71291e27eb3c66239ceb68d78ff39cec521acab9ec5829e81ce72ae8e8b310a3b0f4e150cebcd0c4c949b1ca0f1e9a62d3e49142beba95b6d4b263e1c7d170f2a8f4a73404bba2baa3feba6f3a5e484eee29948e61eeafb58f3211b6b90b200720c79d1c0130ffac91ec4f7e4751234da4f9b4271c7af2443eb13e1fcfcc1e399f974b4c668f1b9f389fef201cba91bb915d37be246bcfc9ae9c2fc9ff75b24be74bf271e064263897fa9b5bea642638ff8dcc04e73890e696cfc94c703413d5474ab052c7806daa8fb2c3262baccf39ad1cd150c290ce6f1ceaed39c7718d898e4ecaf1df18300e34bdf6927c9d7f48d34ac42b2c4f76d3ab298d3d2fafc82cfbb34712ebf0c6710e7b363c843ad739eb1fbea17b2e3479e66f5ce75f0f0f38394f9221e738f452ce718ef31b1ac3974eee52804339dd378f94b0b3e74c43094339a85e92e3377e37fd82dc71498ee7fcb3975696e4388e469a3bea18b09de91f726810e0b83cd49fc51f8eac63c0f6a7b46b8e9e37b40c337bd8c9ca70f254a27aaa8f7e609dfe36edd805f9010470f2c81ffd00829cd7d8a4731d5db35cda9766d8b459190470f244100cc9d17669e7681c9b36ec800cc1c9387a3579e269964b1ba56443e2f0e0c243f8dd451bbea0d9e3f242b3c787e44f7000f431f7c7452c53e2d676b025eca20df8eb69e2cb96efc15265cbffc811e02893502eb62a9c86c4d7acb4561a033c5fb489268268c2c9fe7a74e043056b1bbe9ab081be86acc044174c7871824b0d5b986842079f2498486209134664b4d229993001134b30c4daa52030c316b2d5aa47c0998a022c51b0ecfa0bc5880029f0079b5cc059411fd06aab5d85e66b6a8a80720840037fb00908242279481e95053060b2b4eb19007dc0d7ae2b2e76b562d72876fd8d14c334843be69fb01b4ac0f1d662bc5ab564c5b4769bf363070cc3ec4ffbfd5704864121d3df1e959eec2230cc8eda6e1a763f89e50c8b9bd48e28c58d6134c058c54261d579129a0d342b888082224206decc420413229c6c4a978288b035f0411da2467a1d2db02752508b704277aaf090c3dca9520315d82077aad4008711ec54a194d660864de94e15aa9d765785b54267f52a42e8b47067605a6c6070972b32d8362aa84154512285812b55007184173be0620713381304133960228b921eaac4c0561142aba20a94ad4a0eda18585fb9e17a012b034ea8a2c4a31408dc18d888297402a57576f1c0d894ae4ee9c459363da53488884ae910486c4a8768da94061161972063892eda933842dd3e5d28b0b3e333034a777c8cc8b20db0e16b0927fba268963f78d7ae179ad216d563fa8b5b22c92d3fa52d239729289f2370dc1185b8e313c95525b4eced4a58d905d8f09584182131ee69f3bb62fde636728eb8a3ce3df5cb659aa7328e476db151c7d992c495bd85952e7b764434c7ddf1b1ae08758e7b2a7ff4de551aca16772fe59d267faac33780758ce3b277d83d206ed6c7ddd33fa460eea9430eeb50a039ea5cfe5c9b3bd6a1903a667547e98f55a4ba873ad61fabd3442a7c4f43d982dbb5f139d531efb53b216ed651f9439d46ff9082511ae9f49e3e62bdd34738475d48aa3292dca8e3fc711a496e564a3f677642e251971d118ea6b2b5d2af47e9ef86ca960d8c02d6f7b043c1c6267f32ec8b4f947542bed4512e6c6ec60e85cf467f49fbfe6679f1539ad35ffd47650b85aad19fd2bebae6f553764472d7fce61afdc57d31d6dff30f291869e26b192902c14874df7b9f23304b48dc18a5bb47cd228a477ddbdc9748b2756cf852c2cbbe9243e523ae23da3686dcb78bb3d743fcf60ba3140c5f4950b994f33e1894b6779a1f21c94df30f49a29ea21d90237263bb5347e50fc9d6392a759d0c254f774f958fd0d0e818e2c617929edcf8b1131289f037fd71c75eec8a20d65f4465d553797644a8abf4678f83c8ed1d13a13495adee42f2887bbc9e78dbfcd90f896b437a24438a443638b2ebc167082d8286d8893e49f80031848f148c377c59e1617fd6c7072b4da658492203cc9df901892f4150e10303acdaf085041256304c48563aa58f95132cb604d8f0754419bb6ef83a22ccfede83217c1082089f247c5e7044184778e16345067144174778c9b26c5a894d3a9a75cfb2dac8e8ea14f0e9599956019fb254407d1ef5790b5f5d9c366469df5459deb29653c0561ba19ed22ed45dd9e331861b8544b77cd355da646a87ed99b5b388c8ce8ed92d83b295692212881a585ebee7320ae3eea87b94574473d53dee6a221aadd2a977345e4ea5bc73f744b677cc5a8c8f53879bc8c7a2d1442a0d652b4564639497baa9a352fa88751a7d84a3f2581cc62814eadc2f87cf79a8e373a8638f439de3388ee37e6a4061fc8b51a81ba9dfe0501c8ae3baa3bc5c94c22bd9eac1919d152a7ce06226cbb2df8fc8ae199cb1e39ee51a372b05efdd59f074a75920b2eb390de76a489195dc0117263f4a5e672c9729dbfe7279f2daa2691deade2f2ad3dccbdc95d7152a2f28535c99c2088ee6dcb1ae081fc552a13c8f46b3543a9c87facd5feaf00de8aeba90441d760f88287c8fc8461deb50f0ce1da6fee18dd22c152b751658d7390b387e83a5d2ac944e81759d1bb15437c2a18d6cee37b4918d0f3791cd1df5a58ea1bae3fce1d3e81f5230d6dd51faa8bb2a958bac36ea5cfeb02eb2da9da7bf222b8ed334cdfbf5340d750f6b9aa7691a7714d6bc739ea6e51a0d3dcdf3bc6f9aa7fd28413d6ed4397d746fb9cbe50b172bfbe8dea2eeadd743bc7de1b0ad97bfd526b2b9d3a868f48759787b1ee779455638c71037eaa8c75bfddda3b21759600185ba779d7ce3ac8ce35cfe5646ace3d0421395e5e6b244b152b8719d1bddd070eae8ee462c7d395d64b5afb687f80b225264b56358494f8b299abca6b061db0d5f5388006ff89282cc042e94372e31e5b7fff8c0efbceddaefb474f468a9aa69536a52d69e546edd8bca19b6bbba718e70c7dc9ea37540badfaedbb6d32d27dddaf45059ee2ed38c43e5e8c572282f53d9c2027f32abe4258fd67197b272d73295dc29a7e70f29da6f9472b3a754db186737d8dbe196ad17787bdcae0e15b89e62cbc10fef6dabdfb60ec8c64d1226094c3e2449c0563a9247bdc738560af3a8ab20efcda3b412794f2b6d7bede658656f14bbd0cc2cdd24fd72e18efcbfabbf9d7d8fdda3f9b7e2b4cf0eb0f6968e9e1feeaad707491edbab2ac5d1642f73dae6ef7ede723a7a528af1259bdd61be10c20e42a5265bd31e08dadf09bbd347dc8fb220967e9cfe8236f7eccbc08e447634826447d74ff679c2f79b86f01a841aea8fe3f0d6d91f52dd5387a45d401c08c105c01e3d43a09c3e5df0079b668692e7dbd9518a57145b6cd8491f2b4ea8913e64e06ec397145fa470dadfa5944fe8cc36953c62165b7bb65a33fa8870473ca45ad435c36c96ef6dfe8aac36fddd74576d6e2a49b09287cf13fee09ce77216b7cf15f883673224ae1823f7511886481123485c71e92b12b4b3d74fcc6e1d102c6a31bb5624087a4d6c0ca2d8b21f8faeec7996904965cf4701656797b7f9966d5e938fb2d75c95bf2c88d24edd9a61f4526e764084a476e1859cd024ba37375f6516857bf5d801615de7c66fc7d1bcdd38ec80dcc834e87c491cba192b7ff77abfbfab4c7f93e96fec724e8fbad39cdf6ce334e37bad2b9aa7b75d515644732db372be3adc38fa53da38a71adcd115cd7ff7343bd5ac1c1d4469a7ce12b23acd57a7b1ef72cdb5acfacddb7172761d9ab7d4bdfaf36ef3a1be5d69dbe8cf4e1e1a1894f67655feb663f5a97c84d2757ebb9025d7b8b7b3dcedced923619b7b81ebee397b35843aec8581dadfac7541b2cfdface5799a370eeea8d7f251f6a9a96cc9d7d3cfc39d7a23b7268e561eb7594c4905e61120f3d8110b6c43aafe62cc5f6c22672bf1b0e331e8058ddbfa04618b962419ba132005f2d5c313552a5b42137645557f2e561078fa2378aa8fb8f6b785a4ec8e2049328308963684ad1d3f8da041b246721dd48ec48ee362dceeddecdfd936efd97624ea7851478fdd51fbf0007ff069af668f303e42c0f0d662bc5afdad1696f6516f7bb3dbb75f9f27fcc529565056f2c4d5d55bb6d73412ddd8b38c490a63cbad8179a25327b717dc0885290a81511bc0f138e0186fc0d1a70418beb658796da9b285871dcfc933d9d2c296a5fdad342c74f0b477f69c3c6496da870ca6b16aeba305fe562b9d4f2a49d0b4dad94a27bb90cc32ec93ad745cc8322089c411e2ce6e44f2883b3b12922c2e51b9f00318be745065c3570eae6c046cf8cac10836aea134531f329862d1fa6c813fbceb577021fa80e586af1c30914f9e7cc4c0579e9ec68c799aa187bb72ab95db58cd863a1be3bed6c6303ac687cbcfcfd6341d539bb82d1d3966736adb7728d5eccc324c764815367d87521a67a492d208ab27246b0a2e9438d802c5192d62f64541c943fed0272a06d231f4893e4d2ea8f4e9a2cee9d34545a25aac5634537bf953bdd29152876cc9960db363d6034bccc8873b20f01489e2cf66914aa15c150f03b3e2122b26912d192346aba83d70ad5947b624ecaac0c25ec3ea87342fdc34eb4f8698b3f81dd9337f716f1927a5b55ab4519a89d5e70bfe7aa8de628cf160e021df4dd8a98ff712b46bf4f9d2b3c2a2bdab95a6bfbfd5d25f4f0ff65827555a01ee90ff59c23a3e5f62f5c1e92f4c00ae59562b77bd4dcb3e6b0704f58bc2284c2ba6b57a1d77374dbe46292f51713e719ce39c9e7e71dbbb715d7743a18f223b37f987141c7ff39d5d23ce611771223d464f753ddc517f936bb046e5ef1b754353b3e9716ef3d5a9fe50e71e73d60159fdae705638d4014a1b4723cd7d73db65b85737366c32ac895d10d4bd8e76403c8f5aaf3bd67595ee9b21ddb10b82bdfe2bb2136147239553ae22b6e5e86ef77231bef3b0c71c638c18e6b43bef7e76dfed990776f651466de630ad06a6a75d9c47d03a049abd46214955cb198282beb036c829ba00c397962de62be6450f99f3f6d7eea00c20823e3ce823ee2d1b3b4b483c5623f3871d6159c8ea5cd95aa85cda01f1e2cdb4ea98d601f1bee56f66348770c75693bd7fd9bdd4b78c9fe579d869c7f9f3be9d267fdeeb5540bc228dcbf2b59cd4367645d83ffb69b337848638b4e51bb91aedde85644d26f228f6f91dfb6f3ef5ae0b92bddaae68162915d95feff7c2283b1332fbed9dfdacd15ea35942ae77e7356d6a150d71689ee636179a4232eb8ab07f93fec004c203d8dc8cd29fd2468a5b7b7d2a1f798f1be7a3ee9a4db693d2d7ae08d3813ee2ccf61cf41161207261c7a8b11c678dcdadfe28dd73c38e082fc99d75416096a5a5fcc211f8b4b4b49154fb7e2271fbdec8ce7ea4842de10eed48d8de5ed88e8415b9b0f3911c474ad811eed00ebb0628ed4c43a8a31ea9ba138436843a3efbfa4bc3c52e88bdfdbca6f387833be86f07e18ecfdbb2254354a2915d167a7b9a53bf1c77f3ed9bfe90a88e9d09f71bb560c4305c0724da5f0defefb5da3bb5dfec66bf517c19b685d6467ba1696dbc08461c617bec8e5f844fa33fb9bb0b499b6d74fc76ed3f1badddf451777c1b23de365372519bc5db2f9ad95ff62d1fd9cbb023a539bb47ef89d9ba9acc7bf6fb8ffb76fdc5303b3bfed66924b93b8d243f2ed2536b6df7a85901d109fcc5a6262fa08f786b27c6371bfb77b323122d76bef015bbfebbd91f3c5302d4513fb305a08e0a9d56f01235303f4758f9159808c1f8b0060f2598810c7ec0021614c1c5c91548fcc08b2e9aecec8b0b384d8c199a80d8624509bca051c30fd4d882ca0e8c78a2cc17253bfbb26403e30339802ec8444106142808c21939f4408c332a50e3883174c0e2e60b0ea60d255b5c21054c13a62a2c40a60b33388c79a2c2e4c9268c277e86505a81134d40b0a18c13229a28cde01406184ed228a3039430a0c01a183f557e88d8d99901a53b456c4198008c2084b0860e3a685f888082167029c3ca184560a1811d2184102248881dba43a57ee1e454c6174f3f4c9913154e5ba215779e8b2f18576ee6eef74a3aad8d3c3d31acde84a961c520dc1996e98fea3fa2238d7544f1f5db96e31a1bfb16e7943048b6640f367f61fee88630d3c7fa8a75ddbd87a751739ce71d7e72f947ca3d8ffbe1017f3db0076c4291802281c9873009f81063d41adeb9cf1c77e745259cc61a4f1e78a9490dcb853b5766dfaed18c7dcb4653d346f499057a4cbbe21065a580691538dab152c01e6f84e97a267108abf59c4eb2a48421ec4ce250fdbd8cb04aea0d993cf637bb3079ace5b158cfe4b1937ed24b3c79ec65b48fda7e6a973dfd6093b4ffc1031e9a111f0ecd7f3d127b3d7c4a32bf5d88bacc2e2623ee5e69e47d6a57bc77eedd7ff020a3c693273bfda6e73f2c6f6ec3e637b7b9cce88de2297dbca68d562b3d44bb988c6c3c6a57cfe4c96ee337da46761b996ddebbcc6917938bfb764fbb6293c99345cd6997912bb5ebea26f251dec564142f5d4c46dca376b93079b273ef8e7b52874334d0490587620687b60c8750d969b24abbe2d04de2be1de72426234ec78dfb0f1e30f67a75ac3279b21f2dc03ac9c58425d54338d46538c4393971aab22f94507a3fb0866087001cc2ae421caa43536640c0df2d43d7c6a01356316e66fb592ecc6c389160977669dfb46b7be1bb623fa2e0aa8fc0212881be7f48f6cc47368de62311d3476636b3fd91eaa614ab139bc78eb2ecf4b3c66ec2212d26b970436a84cc026faf71d1850b1f367c71e1647ff6c545926d670f97bd8497fa08dece1e59b742122881967cc84e1e7aa882b6934776459bc6471fd4306da7a653c3b8c96903d4a7b463ac97f76a5d8dc13b94add915d54b7d245fa33e92bf7a45b917906c0cd8f16d57245f9f7545a8630ca5574af2488e7de43dc7f60ef78e6c6d9a5623b34dc69387ca861bee2ee2e35fd439f9786b70d024be459db3d101499d090e53a86ce181bd6fd57d28fbd8c9df6823a5f93daac67b69912dfa186514fcc5299ba6452bd14a53bc92e553ca74fc60f30fe9b52bd22ef5a7fde2fba8575d11eabb1a06a55d138fffdac2cc86af2dbebcb6d8b2b5f0a2c5d38ef7f2a87bdf7545f8567ff2f89c0e79140c4adbb5b15e15d5441f88e26bf4470345b6e8553946e9017f9149f4b2297d8f117cc8e6f276dfd35fec5ed555511d82260f3d928f932dea923c92401f30763f30c02ce013260f152234737e60803ff8a2b0e92d481e14678026c960e337b739bdd14b363493bc8dcd6dfc36329440401f92c697f4eaa37b18528f9ad32179a474769ae252f03b2dd42de63829f1b58ee81e3f5e14c517cf1e4356903c28925c6148137c2f8f332a23c97d513ca4fc0105a38ec2871d0a4b944692fae85eae648b9efb8d50248f289247fd21459e939ce4a4e00fbe86481ef4b0eb80c827b2883ceae618621179799c85cc22a8b38ec47d1f519ea73770bbfc030ae6501d10d955aefe8082f5a649cd3e6eab8f2aec50a897c71d10a92d24924f3a50e68fe4e1c6fed12419ecb76f7ac95ed349a004fa3ef9f909b7c6c41212f7b3fc1d21c93db12c8315b284542985c0e8f1a164d8a547bba27aecae4f1e7e4aae6d7f330ed77341ea512c21f4dee9bdc36df391ccdc6b3ef20eb7d0f43e24c9414942aaa2f4a7c4e443291252da052550bd2b7519a004c28712c87b95f7a83c74b1f68ae8b10dd2dd6aee35a32ef391978fb86bef324b083d777a0ecad6b4b6d6cf935505978b1beb340d013854f32c2321493e4a8ba9744da5e48d66499b24978d6692af391cf22ea526539aea577553dfdcd90552ebb3ac6219966159ed82a872964dcfc3ef3a554a95b7e30c4be54f69a7bcfcb9b6f79accc4d2f40b46355f6996a6fd46b3344da4baf6a49adbe8241bb7f9cd935c3634938a49bbf7da15a9687e6972dcaa0ce3539a46438355a97c258af3b08cc3b22cc3320cabaf4a29a93d016567368b5bfe81e6f772b3c33eb93197cb4857947d461ed885a691adebb4631c0ae5e5adc36e6932930fd11ce7cfb531ca238146bb9852773175a7b9762da5fa55e5b85358d5a57e5339ee0e759597daeebdbc9d66630d953fd746927b56bbd56b9a24d2bea5b459dc5bfe010e5dd899a02969bf5d5176ecd7eb3af97b2f5dfbb347923bfb94f6b7891d02d1b485188c1bd35f3c969b1979ecb5c5951d5f7f51174a1e94d61c7f2326257dac4a3bca599d5c282f844e4932cc63b335c33684e9a549a130da86e8675eda8628cdb15baa3a49060a05d44ba92fba88811a499696e6125e5e66b2d0b204e4a8083cf6cf2edaf07d853f1d5b5a1d23dbc6b407e07944a26dcfc3ec816dcf1884c5d251914983bc98a1517b8082c1b4b4a186934a16658ed0440e17cc19b24822f3a205405ecc641165671bbeb2584194f8ccc667750b1ceae99978f9b2af98b2e5575744d9f23a3b5b12c1635dd1a6230c2854dc046b871ad611d5798ba726a590a37a63575435d570c7981f14fce4f07382a01f124829b3f8214116990e3b3b7745921d5e42f04705599609714493306ef0e2822784c852bc10c2194d8af86228f3c289173bcbb29f12d82b3b67c3d70ebcece025e3d08d39c9c20e0242526618b37dec6088001cb287001c4ab2dd2aa9a18421fbed32c3a1ed4a9422ec22a034a45d48c6cd9ac7eeadd1f6bb7d6616e2904d127f5943e2210087e255981c9311f7ecf1469976d11087b2739a491cca22a4927af542f2e69e1c93f0d00bc99f2943f6f435cb7d638efbd609c021ed37564c6693c2683d25f1f23627d92bb1ba86128692b22bc9740d250cc9cb21b2895a895e24e9e2043f4e76764c500269450d4c76baa861c38f09b49f145831841551b42ccb320d66d0f2b8d2c8c6f06a6778dacf22514bb7f6f816910f0fd9f6d0624a56b6bdf183af0db56c7b2e1f99db03ab6df547647317925aa691e8966bfc2cc9b22ae3a7720a6314ea34b7874a43385f9da5b4b367f6579593289311bdcd93f06db4abe6aa5566455456011f7515e8575a27ad926a4e8fca49aba352a039be658adaa8e654db9c4473acb5635902b19367fbd492a4b44b69c8c5645519df6623d5b176290da9aa547166cba7308f3a0bab63cc6281e6f84635da6b346d4473ac5d718826764392a4aefab32c1b91ffe2ce5298c76761656d97a62d9f75796d016cf8eac264c70e082b05d4f18d50c72e9aa33436c2a7da5573acede4b1d9b767f2591e62e3701bdddce6ab0cf38f16dc1bd1e31bcda3fe93047f3f41bb26a96ef3544e5a3df56bb56f1e53f7544e4add86ccecb7da597c9637a619a96e430394c86599d345e4cd696a6e3493bc0d9d9454739adbe8a4d455359a6569342b53920a4159c418638c598c31c61863ccf4c4e2568a6131d68a61316211ab955ec6901d5eeaa884c5e9e5c29d1d49335aeb9c73ce39b38c6a669c70643279b6cb1371411ff45ece1bd1e6d4b2b8946924d84537a02fb0d19c3a8679dd017fb0099f7500fc8baf0f75fdf91588cc1ef99ff0853383809c7e481e3d33c76d7c5e5e813e521fc0a7003e03f09dec72fe6b7db0494e9146ecf97f41fb93518a0465d981c8c03164f34063e0bb923c6e3e7f6fe4d2b6973fa4e0082406fee20b1392587e8102d9ea8dfeac46ca76d475b3915b3579856c04896be94995e8c4dd55cf3c61f24c9e7800e4c824e76865f2c43f3e47c691e1bc91e1e4d1c92c9cecc50be7541346e7cc9ed80d5c7250c68e2f1a31acd61831cc09d7af9ef3b9820b48d0c7f6f921d8e53c91f9132c76a02ff0d7d3f31384946d31712923c12ed94a02773c912d33f14c1ab215737264b2ca677684af189665524a2925a63fa49ac636235b11491a510c50185846f9c24a36125503eb823e3017dc6126b6207bb42079e2aba5e1663348c805e8e31ede62873dadc9935d803be269160aba91ec617482ec718254aa325419c36841b66234027db8e08ef89eb3feb57870b485a0d9e3468ecee1ef0d1c5a76e46e7f2f7694dd3b96bf1332eda50ea5ea96e650f2b0719b9baf50c791a1e459e90c25cf0d8d5ea9f4a7b3ed53fadbd91cddabcfd31ca7c3ca391927cf1e4060e0afc76616462866474d245372e79d827af610d9a25e2884104208213c9d9773880b77bef88261b05a2b952abb2a4dd91586b115868161c20081c1da83c8add530518b1208120322035fb9b4698467ceec6f05f405cbc7ec36bf40b7ac083c83248b9413ac6177cc70dbd963839227864c72b1deef76398ee3907ab6952dbbb7fbead9c35bb94cca6f405e60d435d9e2ce5d1e95b9fcd9a346f270af5a6b179abf79cb5f8da663f6229522681fd14349bf1e0d95e9bc0ed983e618d61d431d8ba1ee23949d3d54c76832943cf7febab0b5f8691ad5a219a52f5bdabd2eaff28e953cda53f9e64fc7d6ec61b769da5e6862b9eaa951728631c0ce0e03e8280036ba566a02600350fd51f97a2821a4af32b376b5e2c1f22c4cdbd5048282abb69763dc961e40adb5d6facb161016acf39d56c5e41440cf0d37004109e839408b8762814d59248c52a8d2aeb168ee588fb34e48102519845e5ea2203f8f75422ab0e967fe3451ae972790829a347efeaba7b205299124a2d087d28c5207a57d2b57b1675548083a22ba8fb0df8cab99882e2d499a752870510479da0171c17257e8c35e7635c77d35aec620b785d4cb88b0cf7f714ea69d0fef8ae18eea826cd5b7205b404de00f7ad97585165cc880cc2fc4f81967a400a84b3fe8b2e10b0d34829078e215602a5b700aac7f9897536bfcd9f84486f3ad1ed99ad7215bf34055e0afd5d2d1f313f4185cb803b140b8639e205bf343646bde01b2350fd4057f50cb090e1862b4420e27326e90b871e0799b1b380953d558b65612a8a60658dedaa0862038d9f170070853367c9d99b27f367cfda0ccd63a5848c21d58c265c17c7356731e7e163fc19d9df45808fdac9562194196fdf5ec2da0961624161bbc6cf99fcdc9fe388b691dc9037718503fa9e4114f5f310502c7cb1da79c582764bebe3a65a1342801df0136dc7085633548e9672744a909788492399032dbf1b41322a1943a8201a7e4f1c59c190f4405feec96ab0887e431563b201895672eceea26a24c803b4bb1ea515b55b359f5acaa5f88f6da0686f0b10c6d83e1956274c0adc13728a574c56d202cf85bad74bed3daf1f1324639697a96dc203b1766154ec2449f844962d8b31ae07912dc1486343748dc18c30ce575181e6297c390de0d27619224c8f788526b38c6045c8b21bd7007b3b28561d88198c09fb51caef92a6e7a49e5cc703d3d16a55462398b0513c1851d10a8235b404db8b6e29697a752ff80d188e98a857083c44d5377e22024d9f0050433db001bbe809025d66395ab814052f06777bdcc2fc48dddcac61e336c5a926563fa878cc60c5f40b0b26127332d7112a6f9ec71bfa08f488fbdeeaa8f9ec68dd8bb11e2244c5102c9276182f1300152b25aaf84258f4c488c59f64e48083a229a554a543fbf68821216650f17c22c05011a7c883f10b3e3068a828178c0dff756c38e3a6e88315f01781e1eb993250f5f3ff8b2a16cc5166e06ee85f2c62f79cd9ca41cec4ca072ca5af53c1681a8987352298605524a29e5bc625aa8c10dde16e0ec14cfbb59f85da9d0ac5886552139aa8ea16e3ae7950b630ff318961b9a24ee214f65ab13328f55298fa8c638b850beced852e646208230e2c79a6008f11607108c114c910228410091c60c361a9a88e1258b27747046131a009100880452ced9544512507cb1c60d94e4009d84c8c20564845072260b1a4f303476e0e40b4870d15082860dd68c1143b8679801ca81564a2b174d3421e50614bc5eb082231278c922075d74310111676cb1e9194e0158a3045ea6988122849911ecf81b9dc057992b1bdedbf055260d1d73c0f055468c6ac357192f3bdec289833ce38a192d765f548414835a78c803e530eb9c1506610c210a1aa0714610a6984f2d788205116768c082c3d0d4d4d8734ea012c421ec2f684b26a0d0018a2c6cc0c10d86ca74d1d228638504c478e203174454f18329e8502cb3250b33c8284961811638a8b2449632d47041143b20b103304b38f1414b26843245604d6894794199271bd235d688f409374d5ae604fbeb2181106c9a6468a5b492e141a605218d322348e3876b0619648650cd98c10281cc188c8c19ed4ca5539a6186156640914412643e2e3a20e344162ac400338134a4e8818a22aa7841165efc408b12a5090d3330101bc3a10732579c6146141ecc2053e5a906642ab064054ed830e6890e6c70801252760863c3191a0c41660aab99015a32c3dbf065060accc02196e06600cd0044c3ce0e900828dd39cd992fc40d7dd00d218f17e446ca9047d594523bf79e7149562075d2ec81261e544b9f9cf86087d57e526263d84f98a7294f3ecc566bd7d34927a5b5169133ce6c770ab8e8e2cb181a6465b6b03e18c1be29e3033d410a70700310383011030e810a199cc0075de85004122f509931868c30c694d1e48b0f4498e0e9098d14f0a004a5043d40220a134e3730c11814992dc21873650c97313ad0420b2d88c8c458a15263dff0a08721166841c10d4968610196059401e50b1354a9a12989981eb0f624851562ba886245971296f081921aa450a1c4175cd4f8020c0a66f0c3097c20c649a7f9400a2bc43021c68ab4c2f6200b192f10a0b102272faec8e18a2c3d4003c7982692681201152f3af01004296c0fb4e84197d71417108295304778d1a5890765643248908145cc93234ea001a05bad073bee000a0f2d30838b993286729c44c96203334488a93214bf8a5129c6f84414514411f4050825c8304293810b11fc6083982f960801bde8b203130b72204616598061020393c5061d03e6080b86ca06a6874bc610645801c30232c8786283aa584bc60c592031060f5a30440e5cf01a83899d21e81845e4a035e95cc089918159b28169b28d41c30c4e8820892596941053c419595cd1c41332b8b0f2a5cbfde2c500b4301b182ddc172b5f9c08aa628f68d2c3184db6329cae60f94435acd259b38516a721f18584cdaccd7e94c0dc862f317e9610c306fb83af9f24c45882be86ac204611664419e5ec01f1a41c11232f44db44853c1d0c7b46d8a2b5567d29077f2795717a9f127dd2c4700156c68ab1c40a78041866be58c34a501007d0a8c2cc1445486922822651aeec50a50628510051a5ab01a7f160f52cc3a6ec2c0c2a5804550923092a8c1c6c7eaa683f47801103660b347cc4687fcc006cb823ee8cd08a22c87f19ee903d3adabf7710987b08262184624329e113d9a251a204a12804e415db22c0b4fbc3f312c9e491974df10670c7d402b6e465cc22e39538426c8a22c84b2fb6ac62886d03b843fe8b4cec11d4c0f1557ff148fc086ae020f501a240a814adb4c54d4b32e6d00c0001003314002028140a888422b1502c1c12865ded148009a1ae4266469507b31c874114830800c6184300010400024006888c580184030b8a11ee2968b940770392ae982df38a65c01af9dcbed90e116e2947167cbbff800c1621919eb31bfd26ac969e587c6c52e55b9b561170a7608b0c9f7fbbd188bc154cf992be1ab71074820ffe6694d43548f28e701dc1fc2221b790d6ed5ca39e5e5d6f315c738f9063194029d00ea9ad2e477160c049f029a127dbe8d17606dd40b052548847c14e2bab6e9ce23e9aa6b71ff45edd42388ee72c44c06a4c794a187e009e56719b253e94f64c1e34ddfd78d18e52768c547cc02058e96cbde0305b4e93d08ea1497af560109d4b74833692f903680f302cd7653f29fb6fdc01116c25ad0d1bee49e65d8fa147e899d1c5b3e8759bcdf4536553bbdad201a7b26d1c827fd9145bb5554bbc1d42a2518971f515bc077b8406d0a63a66a1b5aaf4363727b687b0c89b573a718381bd2a0c50a34ac36507727ac7cf54b670bf1dba282fcc702871e846eff600628fa8059dec2412cd4ef147e961ee53bcf144b5b27bc2c757dfa8eb7969e45e0a5a11f851fe3c1ee64cd23b4110e511660d661df61daef6e5825c968b373fa2d092c8687033818b8a2f92390e7aba30c927c55bad23d5abda633e573a684ce9c2e585edf4314e0e34f9616ec76102f2f4c400c705cdc53e61b496275633c350de0f30f31379ca6b9a10cd47a4b7aa7783c41a103ebf116ec7eb07c6fe73b734a8933a71a77d0467d3aa46fa900b3373f3e945862de0e9bc1c4322de237843e76e031b8e53583def47dc166af611c518bc089c721eaa874e8a910dbe3293f390d2dc0eb0c360e1fde1116f95b2d59d358f8e99b7ea7d137acd11630dbe4d44d39a140c97a128cdce99a3af2764ad0b780c5ce4c6beca9dba81251bfb0edd3e8abf288bbe0a795d87b39be773d558cd3475f69412886caaff2cbf7b086f8941d96176706e7aefe74a241ca2ac6dbae623ee528661ad5f8c43e61db4994cf7e08ff6e8051b2ee2f9b5c04cac0289e28ca5ec18362d05aea9cd3cbb8f2c9e1926ca6bf80eb21513216fc90ea4c6cd21178c2adb747ce8ba17f53cb64603d6a84e8dde1e385a36b2aa4bd6f6c8c8c84ade3b4e5c4e3ba13a348ebab430ad565adb61bc6c8e6f54562c2d0c9ef59c4a557eb2f044ac0771f83ba26eb8bb4cb6bd88e1f40a89ae435baafc75237f1e1b4128cf88f6222c7e471def96d7a3d7229b7e004193bd13143fb071e8d369b492741d1d45825795913039948f15ec1446c30c61b3a3d49e7e90e74f5a91304213e7a80de3e544b544aa8146356ebdfa59a6a9ee4fdc1d7ce28f174f0ea0bb42a5a87c178ebcda1048a45eec64ed02df809ff532ea65a878d2e70d75d33be7b802a7189f7c3b0ea02b65d7cb8375b2853146dd5a9878afb93f3ff3a85b047320244a16b138f79819c356098718aa71de02fea86731d99e52c1d17a15c49aaf8cf320c6d59be77c41cd682cead514cc0bfc12304d386ddf1e3397032b0e11727faf331a69b93d03a60bcf09a2bba7945c3391e9be07da9d3c423ee6d88b6f8e856e8d356b15bee320d8e940a18391f82925c0280dfe0fe44ce8099de4c62e855dd6847242370b4f533ab982ecc871f103d95a298f9d7139ddd1f26d607e8501c29baa0033ce62e30d13ac39cf8d6ffbf3a48aefab54d63127d1e5ebb0a5c8845b390430f78506b707d8025f916fa7a244b12e0989c3cb73bdfded0708443420723eee4475c082766ea487acc89bb089af58c9c743bd4f39d1d5f1071dbd3a70cb311ba6763ee45f0bfbd84607cdfae4b6dba655374a08a5fa44fc4085bc5e5b74fff40ac6864e29c218cc0f298278f306bfeec07f835e3b87e62291e8b535fc94b0d37dbd48e7eb1aac045e4f8c1eb86b0779f7829457f328ca1b5becd778c0bcc11a398834e61c47750e91d782b7d8635dde86b30df75e0bbd691c0bc19de32ea511d993ab3e27e4dc6ad18dfa227f1024562dc060fa834d8f622b67367d080d8fed2eac4814c22328da7377616dfbc936b7ec11a0c2258f3bf0a50d02af55799be906736f86e17c0c20c296aaa1a3e783191c93e22fdae58074046d65d1916d24a18587a8d8c2465038470db0ba7a074023f73749f12807833958232d3d663e697353f87677c09789c92b6b9108b847e5fdfe9e52ecba59e177cb8ca9725e067fe127be7a3929898c66ed139bedc44c67a16f0421ace5eb3fc0ec547ef1e326ccad2737225d905797bd81993982e85654b839ef330ebc8b6dca9b9fd505857b8840a5a66422858fc67c9b2cfba35ed68923e15076eccc347196921e5388342c50a01b52259bbb5987d927916cf18464a320c639a7face711016160d8652d5ad2a6518fcd8a0263680c63f09da26605c75de811c97a64cc46fb93061cfde419a5e31143d28f66b1e1ebca380c8209706e30a6805d9914a4f4efb22f1936b4201c9160cdd45d5dee30dd0adcce3c9a24a4aef1db00ddc2388427e7a2290fec4206dc7086d88615523169a53647a9714630163c3d6b3ed63a8d5bc8128ba3588b5559978f982bc1969298b72cc8a804b12720253bcde9d1def5f360eff95bb08b7102fda401707dde9b1df38ff9ff8db3e53aca767e658084c0c3e10316cc99d89a6a45332b1c4110e001e6839905fbe98d4895c034fcdefed0fb054f1483d933cb7e6fc0bc65ea3734d40054fc87afbd9201a4545e5839c84e62e7394a11fccc681062779b99d3fffb0d3d281c75f824b1aac002c7b4dee3cdb1ee9f3b2d30b7bc1b55d4339340815185ca8e6934c812e827acac5fee8aaa4f7d926c9e01311584d941101ef3387fa2e21f469eb462823d211fae463c118eb4dbcf15dca843a3d1155576d030c138a9391eda410da681f3a006a681d8cbb9dacc15259b0e07db48969cff9178c420d8cc747029f1396850bbbc7e5303e77108f6bcc0badcac0bc786a21771327cfd89a7d4b61fb021bb309ec3e84c348b2c90fb3950104123cf89abe001ec5e5fd8661a8b986d329d039cb9af93fa7dd1e193c31ddb53a5df9a16b7e4ba8e56c7cd91c974670cdc48ec0f8461014d11910b864eef43ec091404201c5227c0183f04ff59b43e86b23846840490a7a2f00fcc661b170944a1b247a228e3770e220249487007cfa9de4f841e302e343dd1016d9783cb4d01a2bd3c126f6cbed5fb8a4499e25286d0b9d66fefd6c2cfd224a0b815a1634682824f55beddc7bff24dd8a3066661b74c278225516d91a3af88cc88d4c5abc0df71cdb368ee62b886598b6f9699eeab3627081f57432dc55a6c344c68a2207624b5042647c97e9493acf6f16ab35b81bfd4201a0bf47ed666b371432d0f4e25f5a400afac97c2aebd3f1a810e365e6853164c1fcf7d10c77190bab441af549d37d5dd92ef9dac688822c4fd35815240580afd55d70588a57b911a72458b30d2634b397076fdbc85c36ecd7e0a228c6d23cf8662816eddca1f3a069e44c23a4ba871e8c800006b49d593f320c14e768c65e65bf0d88ce434ad017ea297bd2d32d13649ad9e510eb81a4d2cd1ca4bdbd4c6be72d7f230bb346a15e0620060b42f9c8633a23ad8a3c0d959f8a8aea9ca0c6cd9a61b6850e270e7cb50dd38b9c5c0d2d9232fefe9612b1a1f3f0e5fc01d63ebc372d80e52e888be164c512430566f7e3d92e62dc378e30f713691b4c2b879299695e76d3b829c592225a7b8f4cdd9cf1fff26fea0e38da1728c54eb9d79e8c652ad810c927bb64ddb759f29f9ab5fc2be7b69d50b8d0c006846bc9a4e861331a8cc944ab4aaa3434a90fa354921d6b1b89953ee5b4e1e9f48ca1cfada374f222e95ffe0299725fe20447ffc4c83d6e81e36fe75b9a48640eb42460f4321eec38fdf139e39825fd9d45c914dec32ad46e7c830de96b5198f531ce02b59bcd8c62450d9894e80b194d86aaef7b2b590475c444fc8878403e8a2814dc7b2cc9003e2a9f0a1c7afeae6684a9d334700bc0f54c0c11dd54ba0129ece5107a2ebb9d74bec8daaa6ce39eca3f23a73e55a8d3e2658718400132e7205223a9cc0949dcb2cef5ad3dd0491a52c386f8a52430eebe38cf05522a68ee64ae2f48d73a1ca94dd116ee37b027a6821fb9b8b52c8642145a411da04cf0ca92b00e92986bf784333dc1a6c44bace7da04476bf87cb4b4f7e5fee9ec9d1d890b927200e6c354e26ddcbf6332e8be4e55b46c7a006d3bc4ac417986c08f5b683378be203fa11174c0317d512acdf69f21e60dc9b84f1b13269982f8a8ab791ea139e0863c1ba3df9e244cfb7f9a77252240b7b67a635f465023a979d0fdb48e06538900c1c369a2edf1a1fb1805cebbcf7e40ce349a97f08feb352d74da6d2598cd52bb62b17165fd9faa520228aa7542feaf43ee96fda4061aa53d1a5052a9117ccba8b934fc57e4a95dc72a3df0047ddb27ea6f014fc4ad3fd35b8df696658872a2c94b9dd9f9123bd51767053388796d46b6cc2dc01c7f22b2e39865f8139ea9801625d6af8146543cac25f6912fa09fc43d716bf2a0da800e7e52a1287331a2a7f768831e217f617f9322a6d4dead7e303e4c4ac10c1bfea117028501897e1348df84123a28e4b5b8b9f1a942a89a24121d131ab11ab8671fc0afd9018f2b5b3d82c6120bbbe0d28daa1f54c744310fb0dc86cca45b38a6c0fd596788f6ca02aa0dfc65fb5ec49a455dfe81bc84ba122abdb26e0709d1f36500a9bab4a604fb5f1aeafaade5a68089b463d217405dc0b4852f17e72255bbca4e08bea2b2491c3ef4809d22c687a15790e1cbb00b7a0388cc2ed28679b2dd18878fc8fa1d478c0fe83193e6f0f7897a21d6332ce954437c0ac1f4d72e574c952af63d763e82b6e47e4db1714ecf72759d4aa778073aded9c7399a8c334036f7cd5e3e359270fd7e3364294c9770cbf1307434d285fa11835b83ff738d6f3c0be1b21442ef2bf555ae6d99f0bcb78601b2c3faff51ad0de1f656efd0ac42bc8cacc278b8ccc5b2110ab7afa32afae6c54f3a03e857a3011caeee18cf867bda6516fde0ee6d14137f26f8126f4aafc9d9aede2c4f471e11bd6ae48d2a3e12fd53837c5f0f72565163494587e116ca66c0939e8fd8b79769802e541f616cec6d958eb1b245f86fb85dcda23c663b222bdf5c81509292e5521c5ee6cb965517e6c9a07fda0b2768c84db19c2f540982be12cef661772804bb38863beeb2d1b51235e694d782975cf3008690dbe803d5234fde5975b2a2e689fdfaef1f61eadb1c4e6c16f511a9c5a4ad192366647e60c5f008069e7623001abde309642034370b33899986656b1d48e78c81e6eab3d6f95a524aa7d930c982f06436096286077688224c4cc27eb88bd953e9a72a9e9d9bf0d9655f0113cb2c6cde1e14867e1b6a4d8b88fdc9199759d7ca62bb85aa5468f6bbf83bc58aeeddaa90463787a37ff547fd43700021c822905acfc1e226dc542a60188da032ac02c7835c8cf18ebc8e791ac64d22d50e72c2353f54da7e4c4e6c59b7e91628963564a8ab8d89514c6b6437b97dececa815e38e626f8816d1e7abf5113421aca9aabb853509f49b7b81f0ec7b3b2dcd9c09af284b28a0e07a4afd8c38dd9d604f94f8e50ce06bb51e74dfb421c5eae43350874ae8a0f28de2e905d9231bb0477358b3e4de89b2d918ec623ce71979cb1301a74e0eb067801648e8b3f8d04be990187b29c38ee0c68379d828321d39dd5df856fa16ecd5fbf48f021ef6fa81de461cf443b143fb5db0b81281ba70965025a62f7b6135c908b3d29f207edf2736415b1c0f9791d17591825283a78caf262c2cfef1699e30ba4c04d005c4e0a83389c73033f0488d5263881b90d39218d64dd138af3e1396060956fb5f34a4e832fd2923bac124e27d3893f98f9071d912feb3194c8794f0986d5e475268ce15753654d7a5c42e8f3d7a4e0a398736944ef5819fc9fd126aa7af23c566e2cd8dd287a6cf4681614e7c00cb3a45fe807a37048ad83f42b50c50a47dc8db9ba25038ab56e66afb9c66bf5eb12fa616bb27b3e016e8a6a60eaeca15c1feadcab4a38f83a283ab5831e5c2844bebfd6bc15fea7b10bdad924a36cd7130532305f6e9f68b24d096c3a4f4eaac87f4674ad3028eb3143f3ac25f01c03b0a9cb0a81915ec84eb2664dfd0670a7db7055ed1d799b4609ec2d05147116ed5cb53780e34b791c06ef3736ce2d3d35be2effc33c14cc43dcfd731ad2979a2bbd3b6a4b42f6cc9e0794d5bfbd350ec7a65f3d4afe1750a901db56170fbbd9c89cc73fefa0cb6d88606b5859bfcee19d695c5d45a91117371359bc579b6bb2f0b51dfd3253ba79ed99c4885faa36a213f3fd2b7a00ee5dfebd7b225e3c6e584bc9b9cb421454084d54b0908dc8148aad8b121fcace4af0a129742c6cfc40a8be1fc523cc777515c5fc54cbefb7a90ff9081d63af5bf44bd344b431bc48a760bb242fe4b1345ee90c5303d5453d2c7bb12448fa003240bbdb8f1dd23acafc052d6f2c8a28f8dd5ce7b41a02f58e82bb912d6dffa8eaf917b2b24cdb3eab91678b0c44dfbd00453ebfc322ee3995bec5a7df83f532e90bff7a122a2525edf8f649949f8ac29a62724c615c7b918912a5a70d3683936ce96ec11474a207f54234cdfe43fa77cfeebb1666efb40ba55a18815a284c1c9d80c643c0ef51685ef3a97705e6b50e9df679d91a7f359cb56577402eafc5fb566ed393e4031db8f5dade5fab563c8404ae577f778a10106ac636d241a38615c1c93a0c9141fdd615f820c5455d256b8426b874c21e4633e1968d5c9737e82f3744c758c69267b93c2052b7e237b09664493aa78690334065d7732421c9811c44c27acf50a00087b9f803351961d6072ea0507f2745d4a88ed20ed405cc7c465abec0fd42d440a6a94eb90d698b78b6807b80046564d5bd8a38e420f71434a076a3a10fec61d973b62255cdf1485a421e795a8fb7cb8d11fa2096d61e58603c791ae24f6f63533f4dd26c410ab7d43abdcd85a883d434b5a1cbc2d0b869ccb661d833448c00a695d5ca96e63f5b1f75cd7ed4c0f77c03f632137179b63a2c858ae07089eaca1c4321cf81a30238e07ca0652a97a9de39608c6259c26df1a0210db572ef1df0506f8ff76e0a0077f86cf0b43d2861e9e2405024fd03484d0448747e9dae5a9fd8f5de2d2f5e39046b17789e65326bf0917d41f90867009898f1f72dfd8c8c6eac58cd4ddb3de8972b9040cb4f888025e13ed5c7374bbb3fd85049621304c783822b676a0cd0ff007f28446bc53a550ba3008496c345df6d78b0fd8ce89c4d1ba02b0ce41cca410d1203b0ccf5cd34d74ec61007b0f556834a2fd4c7fe436dc98c5aaa1db758bc4d15d772da40d6fd043badef544a83463271a44110484d275c8aab553528e16125f106351ad2e6fe74c50fc591ff5132291e62a058c0a45e3e219e8edc4124a6e65c7c9d5a9c6056e3f78ebbefc2dad8027fec51de0e5d8d4577bf5c27d84c18b211870c0f2f193083d272f82ce47da66fe35f7ea7378eef3c39bbc0d4e05eec9a4da4b0c26b686e5af375114c04f5b579e952b237854c81ccc6ea8fb976082ba6d122334473a995b8569725f48a8c68d2c9113a7f0a4c248639f9cf7b884e0ef61a0d0e1f59552766c67ce034209ce0da17500aaff1e320ddb55c680d1bca118c16cd18af20bd17225a393dcfaa41bbfe4095a5daf4057ef32075c5982e4e8a7073931cdc8ca58cf2cba70822ed2ddd69b9b65a2ca70baa4da579802620fcd28104e246b4c6cd526453d25af386ce19e931d44e5140921fe4989c85b92ea8b20e344a41b2573c56fc6dcd4e66f49b2edefcf39a5579fa1861f129df4b0b07c833a922fc86675b46dd549cf5f1e790bf0ef0dcdb37d773ab4914651029acfc6c045b962cf3815acebc5802765ebdd7110f36f645cc0e5868ee16c2a3734f6fdef511d34da9a187483db05880f41608c8ee58247dd89c7e38a5a9463c4b798b182148b524b69ddc1631fcadf7935082f0a3da49f589a2b3f62e5dee3a508e744122f3c3c863785adfbaa50f3c448827f2c93afe028b43d48a93d0a5b3bf83de34f0041a5a16efc89e4aae8e6a1b5c6d09ad8232d4faf475c2a02b1219e917eb1028f589f7f9c881c48b6d79bb8d9c14af6dacecfb04a4467b9c710fe5dd795e9dd8416b29211def557e3b71bf1de9d090d4c307ec8c509970359cd77cd7c546a6842fa4bc1272da3ecefaa86136eeecdaa030ac6f2537d0b4171b14e2335382321c90482cf072c1d641710e5f3390d7841bf066877a8ff7e1c894d2bba8e6bfe087801680cc76655601f870883e951fa1e088577c79e3df593869a645fc968330f599842228323ef9e6f6790856354967441631583141461834305d2dfad0131c1a32e5c2dd9b22bd8d961ebc3838bfe43826172d2fea6f94db69f090cfe5c46add8da162b029ac98628f2d6f69a93921e8c0506d7166949c8e501ba2e7b4606035c13c6df3e322b96406917f98960c921ffb6f2a1b47e17d99846ac7fe07d3a78a293a51861cdf210e70894b0a5d511d703f97d88d350bbece678e68ac0c19fb1e1b351f89561d198808ba13ef4aedd8d37355b706dc279482b753a4067fc000a7da177a74120141d9f4320bc8636837314186f8368ace17bb4064cef76144e2709718d29dac578ede55bbe11871ab15cc1f2581713afbd7c3a13b07647aef77d5d84744dd20fcfa3ff0df8eab2fc9b74b5854ac201ebda5e5268bd4963d4d2e56f59ed499b18e6bba0fc25be342afb8a9471802d0fe86c984352adf7b9e0f933aed1b558e186b2f58dc4e778e62a2408ffed59d9d9a2a5ec5a88644ef4e2adb842409c58538d4c8bc90d64e0406322fb9cf73875e00f7daf6f8d586669d272b3899eb8b43b7eaf08ddb0d8ad49e24d3a4963849bcc0bee897b5655c93068b803adb7232a6cd43e8c64d0b2aa9bf507a410b6f730079f87e936d4b338ff890f86f310db718c5aa35f2102abe258d187fcd08f63fab1e4dc3fe9d448e50d99b325e863727fe5d8dcc3dac5f34c744bbca4726dc1fa0339622d93d3f72026ab52e9493c8d652243a4c0572e5594d43633a5e62ff2dfeb51db5c6670593dcfd59862e399e88913111590391803b294d3efa55051109fdb7dffa5f1a4761910abd0a6459e07f088b2b298d7261f6c03bb8d3176a163201de35589adcfbd2c5a76c1ac27439a376ea0cec82b4f03f9b23137211f0257b82d8dc91840097aaa7bb03b5ef20415abfa35f8288abb80bffc8f50bef5c343f9657ffa5133dcc61b0f10d79aff59222a95fb31ae507050f125ba1f3b04b9b92c9feda1a70c0923a8e1829b5faaccb4efb4f70a3f05b18b63276ad04dea5f56a300de1a7a8b241ac352deb3581d460d5a2a0f63d287de6a9d7e595183d447181540a978084e3e179b3d34f65cc898ed8a5bafa08a0e903f0d4339f019825f50d6db591bdcf2626196a9d6db4139b66ca93197ecef5f13a018d5da421cf99106362984bed59e40f61f9f8b6dd7a9afb4279d21d86244026620646833433f1b9da21044519f15c93143a77e0209868bbe4cefe294398e03b73a4063597e7aae0a424f4e45eba165909284fe1527d208af3a285d23aedbb6bae6a565fbf5454b1e0dd77427e7c4b2d766873661726c8dc83f2c7da6eb941a04818e0d841691d28c517ba3f6083dec8610b7460ea7bee7c3c77c9eaa19ee25015decc06ff1d8cbf725e6369246d09c75d842b6d25e4e90291d2dcfdcd52be1b3ea7f217733cd45e81aed25dd32daf057bae6092936071fa8eef4daaf199c023438b59a313f694b5150f0629b0bc344dd71c9ca558974bb74345f88734b7a7308b0c3d1d46a4861754a82bef77c0a7c6b04ca9e213618708b1a5e3d28963b32372d0e94cdfdf20b1d706f1d6fc277039a2ef5fcf91fc9ff6439bc599e6339bfde5c48f8da216c8599c3ccdae216d06462083fee1f13c5b4f77d84e2a0fb2a55cd2f705e27bce1a6a5bd97d82d78af51b616af341838cb36012dcfdd89db0dbaa6e45683fb44d60d6e17c546fedbf57d878976c07de238ca1503b34899befb3286feda9a585dbda9150690b826b2b2299b90f48bbcdd01f2df94f2dcb54397c08556af216785770137ad409c485253fb8e1b582b33d36be967bd2e2e45e7f6e663656466d1def01905650972cf6793f8511836036c90f72bfa314fbefef7c47d56248f318a0565fd13330867dbe5563e416ae1db8189db8c872d4bed6ea4c2879e5eb67be73bc5e431aa587b7ef90075e5ecbfdc96e58e35ec4fd8108521e0865c724a0115b927bcdc869caeddbfa399ae9f96390ae63b73ad1a4c1aabeb3e16e4920ed8919acb1eadc79f20579c03cfcd62b3f84d1094d389ac2e660b172fdae8fcd9f412591dc313dd750bf586cdf2566bbb8220218134f4e488df2e94bf51270b2fa860c09f1a6c7edcdb7872d4441d3b79801cc9a139602fb24e8f491a16407152216594990bf9bbc83211c84aa5f5052407bf62ae16410a64e21b36dbe13205df83ad758dfcddc70b65a8d35fd384d3ee899409350c9dab46af1c8fc3bf7fcdec1e5d903fc60122d2027793553b5bdd7b7e4d3c227f3ad0ada9a5c74a882a45d5acab07dfbb433c752d7d357e4549f392fd8958bbb208fca220d1ec9265ede4bd1535285cc820b765667ac19763c1e8671d4a6a50fea840abb910d27856d94e0d3f7a84fcdb7b276300ab2f08be473108125bac98a8e35b4bf542b1c4bf7c713269d1f9d16164563b7b7b62b2466fd26240301f5d09ec6418ed1170ba0607a68544dd61e64115c0a67ff12fbfbd1d375e745b1961c9c07e1a58b05493ce038feec81c6524a61b0db613491cef26fb0d7d926268d7c7760ff84b41fb1cef1f4242f833ca3f6d45306f2380b67b3a8f824e9464470d542c0fdc0a0928262268a779c027979d0678fc884069847bafddd7bdbf8f534a2f132c79fd9a737af15cb35c001947b3d19569c54873f20613201c3ffc5427d7aa870a7d8a78f106d20e771c7615a1b8f38e34b86f642a770193e1564641281c428c066a7910de2dfb22820be9974adb4ac435771f80f15ff982d334776a16bbd9f6ccb1e2809a0d20e66509925e7810d92365945d987666952492f4c390ce0701168743193ded5c1e87148965fa1101e0888b90549b34d3c45c59a9d23e2384634c0375698f3648e48c4b3641a3e57a77a234f9fe555a0a227b3e094c7aa7b7075227faa1d1034a20408ae7fed648a45e1bb05c3729e98b97f286506f0973af41665b42caf690180cad8f1ebfa0421bba971cf5cb3b6493305174d47022b0df2b31cbc767d8e128f81241413d7ea9714a6bf7b3065237e2aa199fa0548741e3fd2a3a93a283497e0a6507d071ab5d29348a03847b273c5a45612ec20998bca7bd97eb1bfdbdcbd16950bb56720bb41b2ff9d8534582e056c938af0b8fcc148270894a2eac1cde5caa8f9c6eabe4c6c105212a2886543c777f38a84e499a198157113b73a0946c394fd84e3d214fc5a271ca344c91a78856afed88325563cab0b4b6a5d86f75c4ef6da011ec160e817c67c7a1fdef016bd82fc1b7eed78109c0280ec5845a7a8f52d39ef3186b90d70be1ca06ed06182e8fffbe8371fae19067d91f0a70a2127b2e4eaa55a473b8de2060679018828db38aeebf987395eab10f398504734ad86c9fe1989c14b7a130461bd3747524ee2cf5dfaacc3db5650035f8cbf3655b123d8eb6906a478d925897d55b5c56af64d6e910e0039c551b4eacc1c385ef0f55987a80aaa4423bb797f82cbfcb62723dc4f9757544a370c3c012b4a707e9c4f66de422864f5c49e53035556371f5b6df54b3d5971eb68502144cedc80a2c007075297ff24898594e4739f1ba5421b5a0e17d69161a5d2919c53e84fdd08cc9a1684a04f9daf481467186cd0d2c0582004e458a11fa8c5503e97ee9cd0670fcecbf7e38e66cc4538a4c48a7f9c7a5afb1a6f62d300b6c11ada78cf51569678a60c815bd55c95f78a1e9c095795a2cb67ae7d02ff75bfde5156c22a3f616b52cf142d313137d3d59974146642db0efe24d8a815269814668ac8245e4d0ca75214065d51da03703a3f94239a9b859c0031a22439310648ba3666eb77e83d6dc29a64ace22dbd27e4543f084e474f80cd1e2e64406743babd08ab88d51f0949dd326ab8d15c20d1c353244457cbda80a85f2336eab181ca33fd4bd3bb2cbc632e44adf19cf4e441fa3731198ba212a98ba014ac36c70596656a0e493b0ccc5ab91748c03b4ebfcb147c3529cf3a8474d9e990ccdbec7bbdfbd563d523c172eb81936840b28717d5e13ba25e3037d2c94a734e1ec34d5d96a9abcd49e1180d10418dd7b14e8634a38fb87ef98cff579a0cef21ccc1ea47afa401e42003a0203190b18c72450d829319920302609784e97968b2cdfa84c816199f06544e95b9897689965c36351270f3bf56e01b9134ba945311cc3bc2f60dad02ff86f1a40cf2c15b79416b36582a1cd0bdf31559649c0b221a5634f30cfa64eefa49e1172d885a2d4d1c7f2e092ccb17f2ab8fe1e9cbdfea4c77c3571b191f50cd2da43db9fe9c3bba583a3e5720dad1ffca478881b8b758cb554de1bc94bd0c6c2e39521a6f8588ba453b67ff2e5d607842139a76e195b33196fe2d68b23dfed52fb04ddf12da5d3ab55598524a1caa36c11e513458b72969cce3d75be1ef2a935ada9788918c425ae63b90d259dcd4c8f828bacebac9f6676954f0c0b9a2c5926ac857511127988acae14b3f7d563bdb3b3d8f273aad0cc372b01c6c1c9780d0db1c98fcbaa117473b623d4e5123a9c38a57a69451bad0d81ac8a66692fb885f860d8e4b76df7afb1b168a62bec4d4b1655dadd00ae16a5b497df0b80b6e7a1661891f8d5d07649015f40b5e6a3da8b86fdcbc7a0f5b2b8d6e786c7ca7f65c30ae75bc0fe24dcf4f74421a9c764ecdd89729acb62ddac4f7bb07ae5452790f1ed2bab926967ef8cc764ebf903fd2319ba2aed545adc4728b8f0a7d44a727c91668bb84ae649fcfef8d0a00746e68120f69079866be9b343bc27975dc5c08fe7e94bd77385abbb57e611586e3771e556b8147c104bb42fc8ed25da1b66bdcb63859c3433f5f13f163e5ad0682289914550d03a0bf0ee3c48b10d3d3621ae2531f03f89b25f539b890a609fba3167dd071013da943b61ac4091fef198dd3f6807239a85f6bb40e5845f33474a2fd2b939cf511aff9b1499eda1bf58897dde428a47d29ce648cc121a2c75000d59782f6bcd53bd30d49096d3e158691f06ba1cae4bd4c5e402f7a36336949ff8845a3a9035d2a8c9287ef7eb8b5f4a925045de0fed6b4926347a6c9fb2cb6e41e13bdaa46a9399b7f45c931cc1cf7b13839cd75e64c7a8cfa9a73bf3432e1a8a999b88e9c0165034c2ef34f64a223f618db00e02d829f12b0463759294a230da4e874d81c2b13107ba43326412565a0fae074f120deea0a97f51cc3284f0d0f302432c050a5014014d65b65d8981fb1d31f6e1bdf0e0b4f13d1cd0a21cd6387ace1ccfe0909ca49040d10d07c6d17f25ef75120072c15dd7648cf24a20c4e8362e2f6f50110de213c6d77ebaecbcf482870937ebe88a0bc49ee8349052650929cabd73f645d7f027cd67fc6837489f83e65cd732aedd7eb0167683d64b0cf11974b0e042ed67962bde41e3c9e33cdfd6c12204d854695785a176057d788234ad8f7f50f893ef9969e0a9b311e0445235148b5fa5d79126e50d7090071a41386890981f9d3301458dc8a9a87cf723a82824458e8dae4ab5e8bf590050024d4862e377da56c3f23721e8ab74c952d125b72b36533a2ab29bd3bdb6402e68abf719d80980c561b938546c1be55530a74234c7bd8dcebcc781d781f5e91e96f80062190c14575a8d006a9ca2c41968b0e996fea83ee0abf2c20b99e350299f87232caa9a41ed06864fcf3fc186af50913ea0702ec9d0f1a45f4b6635a6d2c46ac2d259d88c7ffc9e0d2905e86c279cb0ee7e409747602cdcad00b2f12660cacb919ee4d6e34b808a746a3fe4aa63dfe529d5bc4e21c8c5b464b331112241b74a79af82ae531925330e6de36254da380943dcd83a9285c14b13b9494c98fb5c914845a195ab4ad8b57088c23356d36b36046afe0ee21402f96387dbfea2907ada2939f6d360a0539aeb1e4d7b315eb22c99c19bc59758cc0bcd89f4fccdefaab882aaed802c336c0fcb9a6fc29a047a6bd3f098ed0180f335a33902f9628b7aadac11500000042be841a7b09681e08912fc7741e07458e98e2c6a74719247f3978e48f278a92c1b860cee85f0c5e1697a1235168d8bca225009e86409e75630e0d8d0b7a6cca656f8183b6c8f608b9965ac55a75ab04231d42d9f91da342566a633b346256cb53c7da49c7ab39e4d79e1c573003172f2c36600c70db9b47b6c8fbf7084746a7157bc2341e595fbde178d88694d058f76742823a024e3cabcc0b86035794ff291044780129c9ccb8a09e3496c988c540e118e9748cdefb311cac071e0b1155bb4b5d37126cf9ad1bd3c410a1939ae3b40ee47f718e918b8d65b205d3162255b923f35ecb906f0cd4efd127ca1075648e4d4ecb669e96ef870f63c26252fdd688e790971e8d1dd28387098b7e3df5707f7ee7a92e893f341f826f44a594f28cb71ad99c8a94ba95c1e3f21348901a5a8a5c4323de4b2c278d8d206d06562022eac5921c630a4105ebf061bb1bc8f4c4ca14be67c05bf089f4898c06b23a3b74f17742d64d756cade818c152eb6fe8ace8e3a446097beb51354cfb30cc49a6eb3e070271a70ed4b1ff2218e1017e97a07bd510cdcd3571256b1d4438b6c72512f9ebc34c8f4b73fb5be7dfa6569a355dab7485a1a472f8ee627b6df735dbf63be0d1bc001300e18ef2e3f0b79a945ae91b539f7536f8f3e130180315949cdde9bc8bad1c558e9e5ab698e2e80c79ec6887cbb550c6d2362172387e0dbb5aaaa94e54fe572155259046ee6d0d00e9d9e37d963b03f946ba2112d20222e25a5915b8658c2ca3dadc2ab80bbe37249be45ff7d84abba74289c00d8654d0a2a783650fd1db0e42460b8af613572d1144660bed6b1a8f683962030104809fca6b4b3bfd127ed6b902b961a46d981a7d3805111728180aab7b5dc3f863dfbbead53a84cb57a91b6eadb4e0d3f3041fb0d502d20085aa84a12c98afb51c3885d68bd0f8bb2cb3e681754b7a0692ae29a3f1a42fa5afbdcb9d65778b8bbdc3ec3697c04ed963db8b7b506ef4681ba9f1778483e346d400e43d815901a5fad8df28f600f8359e753ae5211e7c5608a80bff8bc88127a8d9445a5bb7f551cba02be0cf6b6dc152cd2baf138a3de46034036678f341c86c975bc7c31f620740f65830ce4f872e15b5e359dd80d5f021a26335e93eb2b6e9b138ee8bf5aa1f211b65e8ac80cf71b525762e136f239d2f0f356b9617fd3923e56a1e347d733d390ca44fc030af62ed8cb36a2e9c7b05f69ff7d0a69f6110190a8ceda3a0c4d143188d03d6eb4e083bc56bdf4f1fe56ed53660cae1805de188da75a9fc2be14e0236665ef3bde08e714581019f3bebfc4cd70612c625068a53a6bb38b2eec05f58a80b8a12b1a2ba94ccf6d00ddb07ec539e860750471dcceac67370697fc3b88ae1e90110e0296e1e27be597176f6d325cf2cbfd575ddfa5b4d1c31087cdbf4eb46c6f8e1c6cd666fdcf0ad19565585a307afa39a1b45c956238e4e15090a86bf6d02bad8d9ba3861641ab6462d1c2f0bb429c0227cb2fe3122c8ca25dc3aaf426e9700883d29ac74a92e472058a9b35ed1bb8bbefdefc0ce4bbf9d5ec81897e338866a71242b7895391c10983e2e82fcab90d5b90346010157d56ef8349173ee31a202ecf00649f010a33748da9f7b9764e53d4b182aea4a6a26d919c02a45bf360200e7f45493f45d374ff2bdbf0eebfe88ad74187159df6c17dc9d079e27e3d7c95bdb677b365a2c93a607ce64b04e757f3d452c6146cb544bb26d1a0c94c238628de8e325c8fe1cafae2cb4d666e0bc758a50f4d15c3eeacc5f183fb8c7474f2253e0933cd97ac5fa110b774d296fc03dc45b5b3d769dc94eab1279971d0db99b1bb58245c378e52cfbcfc15fc02b643f81388422c478da0463092f2ae429c2475dc76ee515669c28a9693c9a6b20e19a0baa1d77d1195fd63119a6c8113fa9367fab9457130f535832a65288f0257b4304e181ab5f9241a3b46b747bef26248eae3f4cae633df56e4de574dd0000de3014fcffd331d670436e31a56c057b638871aea913dbb7a5e51fe056bc33afaa81733edb6053d842eeb7c23a46504fba6d6de4cd76c02dd8f117c9803acdbabb5d8f0b37db12c5392414b0d29ea6a6eabb258dbc501d4fda3653e379a9a04fd835c0d019db02a792be1f9b0177807e0f2ee4caddc89f54cd6740f9c1507996167cb081aa3c94b482c90f36871372ac04560722019a0b5bf68ec7f46385b96d90f9932dbfbd023c26136573cf465f32dffee5b8e896409a07c7ea8889f514b906218c5f931b4900e1f82a5828d66747dd23ae77314a3bcf9366c13c945c0925143ea0621d3f559e4fa1f6ea84787d0c2d904b829bdbbdd61a22cd03756712d66b71f9e1cbb449c35de07da41c6a36d4238ce00048e85a3d2ebabd4d282606a1a039d6c0f2556336247c5002d98db040f2b558fbcd0138b1cf0937228e42df18603aa1fafc35039b4cb1e203bf542abc63e6b83a8f16f84e718b81915e42558c64dcc8db3399972db241c55a8c49926bdd3ad5c35b0b72562802eff62dc30cc6a993a5247a6df41baf86d3134f612d833810fe23ae6d4a7e89ced9c2c94d6c6e674823a2f3c09c9c0dcc5d03765a4151d1bcaaa117d5f5390181b4b6b475e571c95384d8828160d17d8d40f14d45ad2bafcd8849a242698eb32001657198676359c8679a3f48e9dee47735a2b5f58e1d82c07115a3ed6def5b6b5473df42ca3253269c0f70a84f0e3e8398c17445ab368f76951016b44a7bf7d9cfc39d2e83166b83a602907214da32bb2dcfcc62d302b3a0fd06b4b89658ab70d08df9e6bd9fcbc6cfd25bca186bb97716def62dfaaaf02a6737e27f8647ccf78c5843494428c6b21a73708e41e6fc5ad35871330294630fe81b7fda703bf24581f0428e4aa6ea0d124bed48d102dcde0df8d6b3c5bab1dffe0370d53da9aa25c1cb5a161276d4b9c939a1669b0d0bb31ce3470a17fee2b0da0f01a7f72b83414d579ad7dd4db80fe5bd07fd46bf5ad405cbdf6649ba14ed0075695da6b3b52255e5ca4159d2ab9b91d0b4057e530d8a58105778c57c887846e749ecb7688e261bbebe1e62c890879e5bdc00eb344a0196c72c0c341396252069a7c9a625ff99c29ea8a9027e7a9767e9a4fc9c06db743c3e7651ea069c82faf611a0003183268cfb319d2d3c57fef90fdad2cc2e6f3b06a9a3fc8525d4497afc49d104d7e79e3dafb2d77e1fb4dfa5808fdd336a36ef597e09a57a5fd96d4d9fd93489796f602d492eed95553fe5e13b45ce1acd4608eea5a979715273921c066455e301cdc79f8b3ef28ff9632c60fafb6567b5dc2e2a68c6bc7748d791b46347bcad1ba62b69e2d8e8800b6fed7b68033a40a66e0c6254d94e9e870d6975d20ab756f80f1834ef6cb14223d930358cb427f2b88361189e8bec09a1f34088f8ed031e40c0bc2bced026bed894f2497c59eddeb1e176d06cf8d3e75c3a4d37d0c9696a3f9c51bf83039d9798c81b52e6685d160ad317914a7b02ad45f6ba38b22fce013f823d67608eb96d4547af7a7f50c68494776556433386b9f3b1c977459d94b61f949411c4036bab0e0fd183432c1257da0a2edcae135b737fa175f063db0e5229f384e16758ba497608e150c4800482e27c7bbb2b656f3e2c6d593e0f9f6c634cf182b54e17746b449795545d10ae957557bb8b4c208aabd82a4aa9ea9581c2e9cd6703c05e84b7a3565524f4bef3ead3042508b2e90e20024a2599921fc185cd5e6c19ca0ae09e5177e35f072fdba4669099f5c20df3478861275e6313fb8e7d47cdf8d724dd9404026b2581ed44aef671a582c1792b9094b3320e3eca91e9f1096527e0809bfe3fcc810feda5de3ab3c3239728a3a0bf0c67d07c690f9cd4d2935129dc9690836dc5d5faa8e4f4e8d0eb3956a9bcf40b44a5d6b4313a73027e7f791595b48551c712253e713a8ef0c4ec56b887c53b951254e0d0b6ed85a3cf24d5b960937fad1b01dd583f4c0fc465e6242135599fe96131c9fe94bc7cff1d6a6583797c00c85d150b59183813af6499394b6df7816311c9e0b6858381e4d92c9cc43955271d1f108ab89809b61d2c9b86fb7407c69d5d09f9e0e2ee3419918ed196e9b1cf88e8f7ee66dcd27438f9b6cb1fa579918bba8d4eb961ba193eb87ea7b6a0c496994a2b85574e622278dd3bebd5c2ebdbd23d403f1a46c64c2226bd3fab38821f94f88aae56f90903f7ea9397c3c7bfe9f84b58ffd4e04aca3fab654ea57242a369e6416cd473a0a3569eb889b65c5547cb7416590f2cece1254e815bc1eed2142d638162de6368956264e8790dc44ca5012fd5178cb088a91a7767b61d73f14c4389d9e320322edddb297ee4e5370979a0daa136a1266a1a669c36e18328e680529843ea7c460ca6d748276cf29d7d9f3fbfeccc0dd0f4b89ee4bc410ee954638a55b2e85350041be4e2d4cf17930214eb179250483efd0cca98ade02e89fc7c9a2fbad9b0f50f591e09b763b88a65e21fd35a97b149ad75fc16da7d52cb806ce380897fe62fbe58076d3048bb663fc357b9e0bd74f31db5bb7af22272b0d7fbebca85969e56dc50bb5b269f72eb9ecff601a940ab92c465922dd4f2fca77ba55243879e1b9c78c47fe38c17fe4e03551ad118d4441d50c198517090c628d4ce14c0a44369413612c1300a9c37d068b11003c000f96fb33fb7366aa72b2bf5e91c50c3db626f1152b7225a3f9b4c7970ab63d96b41819f22458d144d4a3f1f33264e8303b5851b3402b5da9f548576f82c309c49d15ed502a0510b4619ed2e1502b08d05382a36ea99c64b325ac8ac96f0f27f186e0ae4e3bccf5f54a22b660c4e9490edae06241bc1daeddaf78353eba71261901c366eb6cecacd428df76c90c2a352d40c3583c1aa60c1465f0d87903bec12b75e76e92e157285cda428b1dc5e7c0734a6bfb2d060f4dbb371f5a7e35367c143c29a2354c144fb387be3a6897b8370a9eca1c1fae0325b1963191fbd4c8827cdf41da124913a3ddf0c9db20819be2f0932159b2f8fbbef875a3c722d1d22cd4b67fbabea0e2d56901c4cb710ecf8f044226b52a25a8eb6524d0f084856af29abdf94c2406c9ee08302ce28c7b631fe8ceb850904234f2b3869567cb699d63e2b8183756047828041ada118a4c5ed7516e55e63b8a4354228068d503b482ceb082f4268705a65c121a38abf3be68ab82ade2b85083908c4aa82e7cc0cc290b611d030607f0bb1309c0212a17e4026e8bcdc73f88a21dbc1ddadfce266c36d30dd38df2b6386db38d4c627b27ffa0179e43350d4a22624e15e10fdac3ef758f173572bfaafc44046f72d63a762e9236cd37c7bdfe1a058c0c89bf2d9f0a255ed1ad5af76aa1171c38295358f77c98912ee66c668f98dc64e6405ab0f6bc5bd1187b9f252e6a287a91c95a7cdb288338a5505a624024ca90512cbda6c6f94a208cbee06ca89e4a608f56d6fff704aa46985bf6b928591fc500df6f2346a40c70d8bf4b8b6c0e98d8b18b0407d8cca6971f661d4c842828f7e3d7ee215cdf89f61f7e8312c14d44b5b9ed3e0d15bffe40892830ca508005fec27cc5944555805d23b6bf5b23c563b78ca00b3abb8292d1c205db5324a6fc89206450c4aee4738e422fa14abc3ef19110e563c7d7482c4bf645ef3e4d0fac247ef6480b3ad0f5323195e4b412ca169d9d28e5838754812ae5ebd9bd1a680be32eb71343abb681042f1cfa9bcb8fa7b5fae63aa360c95ac54908b159e6dac6007f810c09b8cd560babad3bbc63dca7b3a35c2bfb4c5513d28ad34072dc7e3a794a6f03de212e12070fa0e04b217237f3caba77e21986bc7cdc7dc459cbd979d2b41a2eecd515360f79a238598ab3da495d80f64a4d1949e95e38340a86afc28eeefdffe685930aa5bbabf0d68c7abb0151580c873b2a0d7adcfb0e8a9f1455740e4de61c4ae3b6a3bd4d620a7331ddf6ed6d5a027b32afcd59fcf3fbda82ddeacacb5f5a9b505f2f38822982a6bb5299d030bbb8d916b7529b18ebe79aa5415451e285c6d6439dc0650b9d76339adcad3401f1a34bf498c38c0658b88ce61851f288b58b61cb9fd48b85277348064bc0818c416612b91749ce3e534a98f55341dfc6f6d8473196bb2499dc89ae2c98c104881995de83b2a207c9a7e9c1e4ee4c7f66995fa7143a83b4fe24ea2700312c2c6cacbfe77c3155c9ec122387436eb337edbf471eedd40788804a08ea04b21626138f89d4a0a0ba167703c9dfd0be6e7731f54c7b2ee303241f84f9c36b11a898322827b84f1d88a2f76c003600db30defddc9dc33e27b7fcdbe235789335b7e2f1396273657827028e9fd762a9f6c790744e42ef085eb35a19ccc58b6374046e08a5679aa0abe5c5df3b2f59501ed59f97c73b8cd9e73db6d729950114000217f592b68f4877fdd3b23c2b07a15754f9a3c2b2f13905d74bcbc4b04f60303a0a272cc565fb4d0fb9df143928276c688c099c745eb4bb8090484cd07cc13129c2fa3e0bc1d2084b938df09886d6f39eead6ee080fd06f7eb31985cd9bf7856d8640689da3355d1779d308a839662516f312592205ed247ed71c4ecbb0801ca8db6abe31a801cf4f339690df6d965a6f79e5645f047650047c60d1793e82795f4531ef23088626c01b2bb4a05bc79295c0a840a6d8423a9b9d14484f1ba5fe74fbccb25f17589dba51326c539f81b494aa37a5bce14f6621f5de4dd490f57e7d45437177d095fce151fb6af39636aa979dbefb870f088ccf543ae38343f70cadd7bcbae32e746cbc98ac9c64b42025859d1647b23194a695453c1ff8c2008edf85b02212c405cc60bc97f194203fb3aa6c4d76c6e02fb1d2f3c792cc3bad01c772a2ea16d263d65bff6d4ea30d872e250c7f45c39420e13c4ebaf54785ab1b66ddd032aacc11f7696536228a59cba24beaea32d0b3a0ff5d42b0321cb3d613dc8892c4f41359ac52f6edbc7006afc0ed3f9cf10ae0bfe389310b3f995953f440a2bb43972db1155931a083482d8f0c85d68ebd6c2cc832d100971dad3526b8eeb0fd3d6c2961b7968ee4c6dd22b2f0f7e097be18fb5d2e035a740a47501261ba1cc2e2b500d25175e1d166da09e5914878b003f4339acb8c1063a31f2f80812dc416066cbf0b3e20f9307116e1f0985ced773533aca5d3a812bdf265019c62c182310885c925a039f77cad41d1d390f9be2fa9b2c69db406a3e256380705be3019615e5af3f1e738b1554ee0349599313b58a8acd2051c96a4a94114052c41ea2f4ef8ff78645619ba6eabf826a5950ecc7f4b3cf866a2f07e315400d37b4faa378d28533d491b8d111f6cf3c7ee52e7672d5886e912db401837d3bad46b48864592ecad788fbdb191d248f0aa13e813eb11e88b86a29d2567ea107c64073c608b1e19926bdf1a937ab5f41e356556df1e6b6a92807d69e4c7bdfccbb4ed7f1adc39049d5eaa1169490c7bd0af960117abb430a2a289fd0ac52620447403b6a70fadb87dcc95ff8913aa58e59ecccfad187f01554bc6faee89d4d8e0ddaa2726dd932028c09c849522860e815492392834483ef5588111eead79066ba101cca8edd4f991f65f19e04fb04738005b75e8df44f04c0c8e88381afb2b61ee5c0b3643dea8d4ca43d300e55a70c46f4cdfc8165c2a76c3bcbb7728e26cadd169fcd3094e3e84d7c7d43325e7ed20c6579a334b26763588407265629fc99f24b9d936a0622cc5eee39f660aba19b720c634704d847465c8436cc1b455b27111899cf0fac8a69ef76d7f1eb64b32221ed875877ece36cc2f89b2f66f4b43fb20900e2c50efe9057daec87c7c123338618e343e7f37aa615aef7e65121e4046c30050e6284f781a3317cb053d89cab1cde7468eda6b8fc94657af7c62d3bcf8f48054d5aa2b7a5b934a208332939b457b4a956896a3c1cd666d75e0f71a16430b777f4b7f22cd024723177cbea4cdb0a5b1da2b649dba5e6dfff83ef4f3abb22d6b3bc6cbd4155956b727232a81ca9ee0a55fc89f1955ddb6b1260e935a12a3508a2b20e9f658105b9281d393b3f80e2e3f36fb42f4e154071a3601d2376c92d18b50c8b5a2d12ec6109a5877d127e168ad34fe045b29a310f116b229187116d23fa0d8fa1d2c3bcf2e4ab648794eb5eb650ea59f2cd6cefd9070e97f029530430ccf16da45fddbd4a84c778e6e226b4e2b1c6e45fef16d3d0f87bec99a02f23b0b6169bfe4b3be8439f698e8bc6895706d123dd9e298d1025c46244d260c9f4e393ba94cd28e9bd4c5878da1e519f83816679d97ffc74cb18ce61404c75b56955bd265e83c8c1350ec0245f3843ccf11b71e9c38008a6dcc78d728363648597e86705b25c5ca06801779bd8cb821a6365ef593aa442e214ed37e043b7e803abfb4ca309cc865dc42c1962e8742646104288613e01a2c707418400fb7b404bf2e0d37f0c6661961b25a648c46783a31607709974a94235e7587a61b66ae4ac846475a53ec946fc486243235e0eb24c511c4584b22abc26c43d2eaf433e21f48ec6c8793f060666a4ed1751deea314aa7c7c4ed8b9755491ca1c37fb11eba554fe08c058505d2ec8b53210e1ea744814441a85e4d5e9c0e8ba99b350bea28c47c1bc7d41045ae4ab2adf56efc8e9295a1e9fb8866f1ea599d2a9290ae28f3034d684ec22e24533c45458c216db28282e06abde31351ec9afc6aa452e601b884eddaabc50e4a9a9426e423ba074829a9a0d28e8964ff2359acfe46508e99c3b4c3de4f81d5ed16ee89b1b5d8b0144fa83d4c3e8692a058d3ab639d2ab2497b19c1aa2c11c9759adaf61b0c52ef8bab47388302f7f6c678477d23d872029cbb7f470460dfbe5e9d0677dc5c3da359596285cec6ce0109d6b35a05a702084eca8bec734597f5a1be295efbceeca630b6af3a2d4d790a83683d58c1d4f128c3bfe0fe8d6f6005283dead907225bb0dba88bc9ff124f9c00fb2eae10d10414e6ff29e66a8da221790b8b4d21312549f10f6f46c8289b4628aad84e568fad21e0a7950a9e1ec75f1bf502680da1553f80189fc0d56ac7ddea82ae50a13517ec3b75467f15e702b890855e5fa55fbb9873c713594a206d5a2260fca74add26729fe12480b4eacc31c288f3ac9aca1c4ac4becc603dd5068756aa964ab81a0ba0d2f4c5e0149e0f4182d3c79fb2082431f6010bb5acda8b41998fc8e019dcad50aba1a9166a1b5d206e77ab49362eb673c6d00d27f9c65cf9eb5e1263d50d7f1382023a5b09726c6b8c983cab88cefa4490b82e809e87d32f12ece162e5f944f1b64b02f75a5d05843b251241fea6618e5f42262107d9ea54456e33086b4cc5a7269f44b27e4b809b67c105ca0e13ac7af73138f5c42998c4efa19befcca6b6bc64f684cf43cded400ad2fdd4ceb064e19e8863526e586e2da9270aaf340768c21e2a7ae0294aed4a352cac9429294b3dbf2535a95d801528845df116f8d835a4222635ebf88372bea507e0cc02a2d3a16867b64c1a4306e87bc0ab4d33e3cf4dd83adcd2a15764ecee1221c3a0cb4663a09a90ed53e2044fb3c3111d2c767e014edca50488115269de0ddaba2c8e5c041dc5b45a8a33eebc40db75a0f4609db6df2fe445d9c0598a926125fe9908e421f4b24abf6d1f089e61556bb572c082e588680961934baeaa4c97c4e83b5c8a0daa5fc520364e7dcb3083675330bd38d507da74000df6876b8fcfe4ae815b9906c79e6ee7aefe84976da9582277ef53a241f155d8eaae5e95b1d1c5a363a95f28e81ee27d7b656ee077fbe8d8c0b7a2f0b25604e7161431e0a625d054dbafe59d3fef6fc8c347d1d946f959b70186a2c80b6534306fcca4b70fd08d18d3e397a3e78a91f3334e65d33bcd88fd75e7b804ea1d241a8bc39bd28a8eeb96cef105b23a10f4fd670fdc2a2ea8496366a2af5471f85a29fa909b3c208756472955556fd404c9bff37cd656b705615d1aab6bcc0333190879186f8eed19be5b12e2527a763c0b3bca7f3211afa4add20d660d67dab8b6a69bdc377d90de4b6f7209a92673f52462c9267514206955bd1f0f8ebfec83f0b9cc41b9fe9cda81cf0b1652fa3c2aa145171d7de367971a794a7100e388f9944c662e54584380fffc243a787a84e85d155f7086b0f0c317db07d21681a82e25f400d1f44c99aca07c9eb19ca7d4ea7dd61cf3ac526e2d399483f7d3461335df1fc2a22e94dde6f9d8024afd0957dde955999df58cbeb4ba2da26eadb7c19ea464b6f2bc3f9d849fcfb250e42d2756c260276a8dd3402fa555351bb85d09e852d00804cd1860f3b3bca96769fe9cd527a9c505b768370b66427d31250919c1388b8220d6ed94885267dd42e8cde809da3e0bbd01caa17adb95213c62e34df07cb100056d54eff8fab232c25fa8e3bde04782795df7edc585eef396db37d1f3baf8a7fb0f3e651660a90765641ab1f1362465725b1aaabe6e643f9ab48c0ecbb05e91002e65ae2e33cc9ea9655a3180407c733842c9326de9da968f5948ef345c36a04c4c68d3da0aad83c8189507508656954414223c35d541fd0179dc66a7b6d200153de9d184ba31b72afe07f40bc0ed0ed01e44f15323a47c724a8cb36ec3817d208002845887126c761fb1f2dc22ded8c61d37ca2cf501cf6074f4b196b1dfc28b081ddd588ea2f2479b9593acb390a77785f39eb238bb0c70b8c7d8a14f095f5ec21574457d40e860c07f925f1a0293cc101d8fac9a58ded7c10b1fe517aa4cd17f9b960bf698015e35974429aacde3ad9dfeb0c4825a029c866a37bffeb9284b4475bc47c77bc99b8832d57defac3ffd1c4a18ab8b5a98d9bd3ba30725a1d9f23da6228ac82f067a1ab761a48caefc5b0e04a7f230a1fa58e1bd1a239387284d6981df8b8f9756d04515ee0a35c3e959c037d548047eda7278bef0b98ca1fd7cd5f861a9467a06d5b83b0b4f99a785d9ccde960b850dbfcba75d2de4cb5955d542ad25e3dd032068423f61ff086408e0faee155ca00a38e276d31f4d402a0cebe98f2a10d3d95c92c4f255b7f4f8aa060c7953c626cf12c26c60b363d2555e4f0d3c9b4d376c1a3f35ced71680bb720b96d52b4c7b531d11ee2b3d50ff0b31ba0478ec30de017e9e4bde5571d36131f0be7efc4826e6008b2d5a19ebf9c30b1fd59545d1c97dcb757e71c512c8a05ef1e32714306ab4302979daedc16be72ff5f93209195e95a634c42c57cb1377018aa020b41f9e70ab940041877891c916a95a359176ef705a6a29892665a1a80c4c8a874db6f8eb3854c9a37472e01c18df34148a1409815ae0a7488835024b08a0f4d00f8c2803bd0b9d100129ef68538a2d98700de603d1be11ea0a6aa0abd2de7f8253be6e8ec0ccd97b81f779dbf6a0126b24b044c88e6c964c45da8384e9752d738beb870a2e7902c85011286ab7d222eea73e505a387f0f788b27a1311026d4e064b3040880b5dd9d17d4d75085ba5268f7d0a0820215caabcbae91c280197598286eac2ad7549344621d638a27f640627dc408f4fdd7bed7be9fd7172fbdcc8b35fd17329b509bfa1456c10b40890787207e3c11c61da304f76ef51e5d4c40f68a8a8c2eb01932003778a0b63b05f5430bcbb4a141a922253b04176bb0e1c01f03934a913ebc1063eda07eae6dab94a0650beacab2e27f7610cdd4216deea56adce8104aa12c9f0670d5f3eaddac38f2226b8d8f8b698bb8f5b6c1947ec885794ff30abb65c5fd4fb34727ad2a5961a1dc15e4c67a0346ca1c15fa07522b852b7298c59ab67a3a01afb3e81524552e1d563c8847b5d6057fe8e8e5f0ca98bd8807cf9b38721606975bb7cdfeb2ac608572d53fba95de6bfacbbd0728fb9d0770f9e099d25d835691e37ea4d465f96d8ef61362c4ddb58213faa2afa42e85a2ce856fc16a644b436eb59b8eb87ea26a6926208c70ddd94b27e86615256a63bbd1aa5162634bbb2dd8152ed453a24716c36fd4fb669644e154dfb0d49643ee962884ba5fc388b0e21159f4da242e36ac98897653941a782ee565ea7953ac237df2064004d178850aced5cf8b5c304aa9deff9b6d176211fdf98b4152997d6480e027ba8d3c58f710b68eef923960f704dc95dd5e5c3746f1f42cd6cf56414b801500e145abb30d875c102c6e3558fb7cf0eeb88dab4c7ebb76287d9e4497fa6a3feed72fbc751bd1fde326524f9c229bf6aefe869c7af43c74ec1d7c7c3927dda100fd8c408f1227037c0d268ff31c2384731afa71068caa39163e62c915a5514b7bca19ba132b34b78cf4f8ce4d798c5720c593c83c84788f56181cc5fb28a7f2c7be0eed65b0090f0cbb00ba7f0219dbddc4a2ca0cefbb554bf5dff23623bd87420df4cd8cc3c62965b35186de4afd0318ab851c94c6428831d7f32e910f793c199faea8afe4c5b9f719a76c0a04858007436c7a01ac436e0b2a93d2249f00ba2b5ab4403fd59fb6a0b4f612c108e28f0425a822d100592364a03be18ca37460c5cfc20cbb4a11d477c344264bc1671bd39b2373b35421335c2a78a26915a67fe71dfac52d6c3fd500aee219bd3dcfdc5685580490d5520ce00308c472a2a2cb473297210a1d01a26c86b80ec072a8b802791f855ec22cb67362a9bfc049130767dc7404d1ec4f19c6875799db87e395f82aa6c50a304447dffe52e357c419238e43154675b5022f30df355238a6b02c04707d226cd999f1ed37b419813b396d20ae120e6cca58724b5b6080aec5d162a1efd275dba2ec495c998ef65e7a470517711fcbc5cd0036c434906b67ecb7920bfc0f8a49f4794032694454fe46abe1a649602aa00085ccabe860c62edd83822a0b808dd66fda0194c0afd642a6d531f5b5ca15a72a0c46b75696d43d035b23ca016f6f8fbb3f4b8c3d8ec3a793580afd748caeed32071a0d32e7090d6bad68b4c2ac7c5507572ab2d72e10ae34a4a74b766927016b9fa45a24f9f5182cf65f5c5cc2d3937810e83405056195817cf3fb7a8efa7231e9d4a821b35443baae10f2307201dcf36081c1f92ed7656051d55153574514b401b2088e635b5b8b724c58cf27d1a90dbbf83bd0445f3675d89de1f92a51b144ce2962496b3c9d24a7b0f0678aa8699c2140ab75730dfe74f0a2180119438777271dbf97e25950905c09767cc6f0465236ff2ba22294043ed0acb970679dec3eca94d8d01071b2bdc460e2c8020146cbcb55faffaff2e51d0d291ff99716239e4d70c0ab273e53d88a3ecc3a076d438f799e2fd0117f4086e63e251c54096591a1903a9d2713ec8f34d652eaf086e06cff07986bd87adecba1b32e4981c7eed9076da42fb0a7bfa73b5e4cc65c63aef02c567d8251f1bad6614a069258907d8c9470240d0ca7811cb270411fe99760a5fde9b128347a6deb0e6a241f8aaa90bd45df19da7158ee2d25cb2f5016a62df338af0e981b85c0eef71a85d6b73d951965544d082619579eafa963fd4cef3e67ab02cc57ab9e5204494975166859c77efd058d825f18f5133cb5f0c1700fe388680f36b51201c4bae4896d6c8ee237f2eec6e43d08d8967337971a551d8dfa2e373794ed42676069eead2bbf03adb81381e8af6b36a619f2e21bfeca9693051e231c335e120733f9836fe8cdec42eadad24754022e04e87840e9a651a89ffc8575a5911823eb3a78d50229e3eaff7b7d45f4f525739a5d5fa1d088fc027404e606d069c6a88e18aff3cf859e02aa8c02624dc5fb96d560824034c652f30fdd11f2a6aff1999fe46fd0b03480e25e7213bd0e01b66d947d79f8c4fd1e38cd41bb013d2e2111e31e28c3beceb2037268b1ed681957b3dce75807f2e9524470f72ec4ca98a3905f2af272e0b07843bd650bf06f11599261f1ec619b858246302cc4aaad718fa9a6e97f7f2885e48dc251a1b0518bef347edf079a9a7984ee7fbf4331c0ebb1da80942e7ae2833bc790b52dda7927fd05d5e213d80c60eabc6bf65a0192c2a566009ce332034bd212b1ed378c1fc3f2cd32c3c841d7a38fdcf3464030775ec6ab9260fbd8b6ae609cd828a140e0b98a1b2f248f6ae6b6722dbe891b2655b2ca68b80d4140c7fcd0e910d213a2556c1da51c4a7ac3b0641048b51006c2385d78ea44ac815ce069c730be2053a272f5f6360fca1274e0da8a8939dd6824faea95ab4c9f60742097ee32968148cf2899e7a681ec7c30b200e701ad3d054343483e0e65700eaa7a91fe44d06d2d955d48564d78893d2d9d28aa3d3d0d0d7ed2c5454be9537050931a14036962892762a838d4ec5dd7da5dd41590fe84b9bf60f7e2421d1bbaa5e3b48e1f290ffff46f1850af51bad93e7e65b3e0b8485b7cb0292f1f99c9bd20e82ee8bd54a80d2ba2f3e88c398d53141a55c6ba028525f99355560a970b0cf0815734699c1d48ed9c3b361062e3ed4d424f6802d7c7ef8629f2612563bec54213bbb8296808c133855ac7816e0e42b05df6cffcf3b4f4fa7430b875340d60d51c9ed33adaa097abd744028a331e861b17c1a134b7ec3beeadea4344e517184b8ca72788da2f9ea5c52f9c9cd038cdee507753f13c7416e4b84318588e481c634f212dc27654d6d4a3b7df22e5c7bb5683ecb812abd7056c8f57e0e3d59dad44909d54ddbae456c11bb1ec78678f576472f761ede6b512ed53d4c29bab88e145499184159180bd3f015374ec24ec8903ed8e9c96fe398542e256e9668481790c4fd58004ad539a52a7aba2e962661409bd4a809db7757e2fe9154148c71af5cfa8a5b5a6087d63d2d7ffb308a07d73374cab1d799c0ccc403d6566b62c64b1825af2d661e90c2d75ee1ffea5084eb954d7ce3bf20eb9503d59afcf779f957ad2245832185846225857f7b75789cca8ba0034abf8a8af3b8c45070698c8373ab9063243137c3295353a07b1f7e6d08ebe34ab0600035a28cf2529433ff06d8acbda4d0ad7d33c9e463383ff357f09d39ddefd23ec6190955777012029e466c03db2736a697e44cd9de1c46df1cfc3303254e1a34b64d3c76ff6d80009c771b80e519c339ecd5c5520b36816e80130b4cd23ecfb18b0c15366f9e40e5aae4e3ea9effbbeaf33f3dc0d16f594f6f126d37de6e95a33404e74ab8f1807c2e2860ff36f19e47965a21f22cf79b6bd3a0544077d7f892773b92a29dc686a3ca5acaa4ebbf78e780ea1fa464fcc7a28e0bb9777b72ea95de11fa5ab736e45410c2adea685573abf0e2c3af3bcb65df0038e55c61ba6590bf707a5298c8cc9ef2a139b437c2344870d8f079260058c2b103d47d408a50683632d3e568bcb907278990cb21097596ad011324c06d5396492d1af0459409f2558f44bf060c1e1d455cc03a78c24b3bfe13667e75ad07822bb6daf1e427eeecb80a0c87310a1a053e62d091f31714dbc5f727212d1544fe46227c0764281321cb5ab3a2e76c157a8403bdff841e3fce55df2a0be63ae59a8d957421f650180d8d58031c5d131517e7743472a3b0c7713dbdc4035d330d4a11d1cc9401da6e93d3e57ec93f542d720aaf09cd90666191ad874d9ac381cebaff0b0c16fe50d3595e74d36c010f2b2928c51e3889c6e3e860c8fc9ef447bae031a83f422213dfbd859dd5b091b5f4bda85eed0bf677cea477a258f382a83a99ddbdddb08f700dd2962e35ec993a6c70eb5acb703c718460c09eaef7a16fb412ad8ae6a11fc8c04ed51443e8275bfe9f0b06bb009ad12250427543b988bbe5d215b03bea09e19d7b548c5c6709bf3764a14bd183168e208a1886a1a77f194ecec95072cf8b131368fc29e92d14b13468c332abf4a9e38be43e65728ee5e956f7b180230c2ba3b8370d3e07f0bd5507bec2cc111c92a2391068a5efebe162c049e9880cb761f50ec32c3c6907b4a494fc5dc64ed9fe43490b410d9ad7f31ffae2b2093889ecdb46b9a347de34d5331b2823081146e2f8d0db2cead6aec667032272cd4338afc00e4f390570db8b8cdbf7fc6baffe39b0d7ab390363b5a119fc9d844942be14da6ad85328a04d917845974cf83b55d0d0a39408149dcad7b3023bf4d5d72725da35a5614c7a9de131ad769e21bbc6b97806a47090273d33aaf7d2630d493d1d44af5409940d88b5d2820eb1f39d81f885f2b1cc936f6d03027f3028ca00de6839e0650566e24a7517faa048019b6c315404b616d86117179871c4f596ba02561dce55882bfc4e44a99517fd02910d7b445e257aa2c19c1c8ff37a6b51caad7aecb09fa83f7e06c7fb7d474aeb4acd2932f0c77b71e90270738f6d5322b7e3209b4291ae9114fd94076613b403f17166eb644fe3c5601aedd27b492ec57c023fd9d530a373cd8ee979ce4011a8756c2a08507758adf0162022de26116e3c01213ab203a50f6f788cfe6a7620c5be6ad45d9d5ac066c8193458e2bb34a123ac0fde420082f084dce791f23ee131ff1f19836ffb6d9969d11c302c0b51a5774472a2576469eb4008ed5480228c81f3e010b5fb00dd266c627e52bd40642693488c8cfc32a6cd2930f13f1959abe20cabbc0f06fa52f2697c164b32c0ffb6ffc38618917f28458b1b9f4e06c9af6f4365f4c19ea2671c18e607cba041cca86e69e46e5d232364d41112d9d89b3808776504eb42acf7026e36e015ca933cf472ae2a42e7fc7c5b82ab494f6a62b8548ec177a5b4338ebe4857f6ce8e52b755feb60a5b289a70fd5f63bd020add4d1aba33a56a65b7358425c3a14398e9c7d0c386eb6dbfd975060a3e8fc801137f37927cde1bb60ba5d51796184b3cc4ade3384e45ec42a089ee92a5a87570efbb455880932f98d6241f719005e8bdcd7592e27e959928228b28270dd3aaf2f5cf88c5d09631ffbd7c68573a809a26ecb6dea9cd1bfe18820d96fe34df0e2832eacbb800318ec1f17b484f3e5d1596083a6c0f0516f10301bda34747c5f4e5f102fcc50f004640ed4b5868b65d3d5074d75d47116303ae074d1ff6713f677ea4fdfb57b1df2524edefc97c3aff2dfab9925674e03c60d0d1b16f59d569536a7167b7b7ae6f82bee430c7355f07c9bbfa70344853e0c75162f75c3b24d84e55dcc78eb2f0b3baeb6a02b7ba715509680901c105b72957ec17be5e60926f5770cb0268114ee4d67d4a41a248b22c2e84962f4644e96c837176b8afacce9d40211356dd9f7e0a82831c229ca665ad4c37ff636ecf18c011d20acaf8458a9a958cc25919c8b4a9b2137c2e3032ee30408cda09a4b13892af8eba5698ffecba6365eb6de9d8379823cdfaecb54c1670427b98e3773216c1dc11dbe04faa7e1c71a153ee6f72930caabe3e43bd398b7ac3052ada62345854caa30f27ff31d49ff5770d8567071922f812731a8512a696a1b40a3039188cdc88ac00d3a99b47bdc6104882456ae061b508ea4a62519aad5aaa51b653743a6294ade4fec38f43874d6bc1c75db6046308ac20ec1f721430b509fba26b1ab49957c76b990ae8baf12eed5e3bd7e448c2cb74ed7bbbe9337b971e74309863711ff257b6a3346b48f6bbea9cb86adc80895ed34e4f8f0ef621dde0d01c2cfc009ac3ac2d525010b53a0441001058c98599a8925ba159813995851515a345a608480300000060996666b68438153db32cb422b2a80100b4a8016823c84d967b1cd020cd1dff3d30559b3121f28f19235c37cb5a29654a01c702ae02cc025438c440b625b3d4fa2bf814ffe238a6a1fab007c3108c761a690e0eda69ac9976477b1bb23f70a86b8f723c0bb85f433157a4cc8e154a0783ec850c989190a029ab119b6f31a0621f504350f36e2c623b6175d90bd44d457d8a5ffdb8d89adbdabd3a7b00baeea83b4c4fb2b3a72fec06ea2c2cb46663c09c4ccae60a4875705bd32615d29012a1d4943c257363fb94c5b033a86758ba5004354f332349a0ee393c4ac976b181345849acb0cef076b0da33a9946d6a845632c21445d5eddacab6a03e1172b6b12b7b83daae46afb6b041386a63dd53741432b29e958cee4667e56d713de50bac73299ef5a8b96c23bb1b675550f7360eea3bfba3e6d971eab841419dc6ec90556a3a3ad7266a881dac5a7b0dc76e8f6c2e66629ba8793a5c877234ced59140575b6af3bc0eeafe9274f1c5c25661732e07a0be6d10358febcd5e675d2ab3ef1126555fe95e6af6da04751d64cf35b643c5d8559d6daae7212d593dede1462d43cbe6306c335bb9bdfa10b5883ae49daa61779c27fbf59aaab3a3ec0b6a621d663b4bec355b8bc103359f5182a9ca16a026ea54fe0443cd2a2667772db90239951fa768cf08897279bba8e23a49ce548250549d46813acda6da06d4c13acc1e515bf51638eec5cf3a558fcd638cd9c53aa42ff98baed5a0ee2daa3601f50a14b6af96a096f3c4e4e013360f0b82cae574ba0dd77e2351d3b07f3998f58cd4886867ca784ea0444f3b30b9b53b8466055500742cec397b867d072ca0be45aaa6b2ec7e4601a7aaa53a0d98bb79e87808d45836efb27b0ed460f20efd04a1a172bd38ec3e7e05f7debb147655bc1910b00787af782472e0a90041e47af14e6e030ff9219623722291e31d7147f6373ec7de75fd23b1c876678d3b9aead08fa63a1841b0236a01daa0fcec4c52643b9167b7ab66d23d23e98a95a875c1926a5dac1fc74610b5b86bc50ab5b1dcf375749f752e5d1a39a802244dee2e7579b68c20dcdb1947cbf4aad27abb7a9baa7f699a5b20cd7541febae39366685640ec549c612ac8bb6e8ab7f96d3b47b55e5e1e484bc5756651f5214d5f487337c82fed98cc90ade8a438cd5290535da63796ed1ca2f5785e2db468e575a4eac79ac890e62af117e451107f3b509a99aac5bb41fd0d4a09c81d4ac8ac53c327dd7cc9f61f7976fe3919fbc78fec8fffe0f903f68061f8e4ebc3c5f883ff0f36122d84fc15cad06988bdc87901501ea891072ff24f967f57679bcfce4d8b9d247182a26ba885b6e7e9ece7713f04bd7c9fdf50a88f30e6e8e0e808c1d11182a323445c3c12ffcb01770e8e78088b803fc7ebe18e9e081f7fe15e4f1ec62fb0078b10018e833d6051e8130a3742d0208608177fef0751fefc36a9e31fbdd879704304e1db391c7b808d84dc481bc5c35f7fe1e1effde8ef558f471c43fce3ef97808b2f7c9b88c5fc3c464032f9fac712330d93ae99ce24eb1f4bd410a5fe019fdf26402638ff588c97c2fee3f1efedc1b188235cecf0db7b271ebb872cf4742a011e99fc72506417a7ef8942d27b269fb193ee093bb94f67d68945794a6d0c018d4628e3d3b9e41c3a879a42273358453c726a0bb126f6b054145f53c9d9e349896730e291539b49e64bf7145302373ebf973f580f241e3ebf9d50ddb9f4063fbf9d434e1e27cbed4cf6e08267be6657132bdf4daa500908e2f3bbc9136cb2dc4d9358d84c0e3fbf99746762df033c03637ddeccfaf904e0f39b99f5a35f465c16c8eb7e998672bb4e742c5d574694585c1e15ef8a86f15cc4afa70b6f762f59d03137b2fec1cfef65d4f7f0f9bd444162f8e59b597f7e33adbf17f9024c219ecf6f26cb3ffe98cfcfefa5dd3f0e97735ff8f9bde4ae80bd9f74f1fb165320de48965fe2463e7f87b107adff49d83f8f6f284bf21ed9ca8a3fbf47ae1e27c4740c9d6234d227716ca4519c5c25636455d434b16c7488f4ee60ca9e907db2ece1818f71421a5d398102d6841358e9137b0205e932db838ae6318351ee0a309a7dfebea231a25529be688a945ed4681947839470b487246a53129549028b9fdf3d753d6751c0f780201f1637f84f04fe3f38890f4ee267340243188dc5df4384888b7047c7eb7baf788461f87d455a8528177dc5d8e3059f889708530979cca563f9efed43b5a1e3d7d0f1df5edca1771ad878568515f87c02863de0789b55c1051ee5415605165c80a118ffae41c7e7378edb873fbf71d6feb1e37b1a65fff8210256b3e5749d77a0e633260fc36845bab5f14e2df310ce5305074997d4cd476df3cdd9360c8eeb09cb3345f998a6196d4a2f7fbc12c7375fb037d0b9eb463927d905bd45d13c8ad88a2e1959fe9e9ada20dd2465909cce8b180f658302675392c5eb899bd3b833576bc7e0b97d9e756d450e0aaf3234c7f1506768a4ca3c55c3a4aa09f1d43922b5998dcc937c6d69cdb595dad38b143eaac8e74467b91a2b0bdda471ce6e3423c81a56b679c9ccd7c9f0382ee6eb95b6eacf54881dbdf8cc3c37739b8b979a31a14966925a5ddfe66642432d3bc378313b59d023527ea89e579040ea806672b060ba644e62c890c8dcc9c0f9a6edec6286170c9f861da39a974e564a53a1ad1d3f276317932214b34491172537a7a4cd2d63655e1edbc2ae8a6652bdcf521651568f0fa3295981c234e73c1891393affb33637cb6811307fb235cfb8d680f22e9866db683692a6d8d0b4dcbd3c8f5e901ea6ce23db66a2b3192accb3e0f2715877d448d30c339d517e5c708a5e7cd605ea6bb828672522d06e7e2202df3cd6d65b696717af59aae595ae5e5b9d819ae62024a3202fb423360382b7e2a52dce9316e44cd2c57bf333b64dda59c42b46cb3bafc92a485ed3bc86343f833cd20e77662e5af14b16a7476341ce3eddf9ea6d674b27b5beeae5536831afb34d754593ef419ab9825876ae66e6b215cfb6e2045b41aae87aadb7592a3ed857c39694541acf8a6b51875dc781d961353e3fb7f82c967bc48ede0b4a9c303a64cf8ec95559a54577f3b491c87ef049efce9714aff9a62a3ea7a5b44a899ac509c342b745c9fa2a6c0a530cb65969f07029e1e484de58a852b8e7c916cc6a859424847304807bdc977f672e98744b6d5c64564eaea5c9a8e53991c9493240b0c1d35b0eaebd30174802773b7772337263765dca709542aa6371c078a6ef409484b547646872480620015b6a55f1a6bea6701b6aef51de34992673816849213d984b76774d4a86e545c590eee01930370d9e967cf99e367fc12d0c26155c1d2ccad7dd06d36b9c8ab713269c0fe423b22f1f718168dc1705167321745865d4189e32c74e56afb692941c347a4773bf33aad88434b8ec9a6b2323695ac9745bd59127221653a5180d9899e8f1f26df5606c6cb4f49f90b7918fcc7dbd2223a2da2678409d5491c918171992ab2ccbcc29f5e6c459f9dd463370b08cfe2aa27e013ebf8bf08ae88e6fef3f7804875fd883c3233ab2c4715862062dfa8d21832099545dcb96c7ceca421b32c6c396693a4134aa5a1a70ef8d8986368854bc203201002055a36c47868ab6cc415b2e5dc5a1a889109dc4442b5a22e4706ea8050117832a8a64a6945655b5a66585915d73922127f4415ce451c07b086b83839f100a211fb17b28e916a2c231b7fa645f318e637a2b8e83337690a288e17a7391c352750b495fa0595953352d4ebaf0e7b7104fa7af6e2094fb8766c687360f5741ae61508cb662926f202a6d0554f43f7c7e03e170abe82cffbfd7bf2f09c51488c7df4ff21f7ffd6d41c8ffb117611a8b087bfcde8ff8b3fd19e47f03001b1f3ef5dfe0db10d1ff909be8c52e02fe1b37f83e374143cffe1b86bf17dfa2076e82861ef267e8e06f9450ecbdd8a742fef2179a06421231018ab870d05011250d3d6145617972a1255834b7a00c1a9af522001afa237e7efb24b1c0aad46e299d534ad94a80540f469086cd335dffc8b1018a05a894895d76992998045014b319000003201c48721c86514814d10314800432ba4c5c543c44948c201286826150180c04040261000000008401804010100e85c2b1b990ee03c2817c31ce6825660ec688091fc0e3c9e6a86584e2f0e01ad0c31738fad419e1278f954b2c88c61cad542eb686b24b815a55b11098461082ce2040104b916820eddcee1f734c5f6e04acb792c1a3fd619f8cfbb7d28774032a4d3141d251c101aac70fc61e81e7df15668412021c0d2788fbe877f439a9dfe3948a160670d234c37154393c879eb5cc757183ebbb2c30db4c2d9bedd09fe4909d8a34b8df2ba821ebadf95348ddb7d954bc2861b1b5ba1a3b1cc40c6abc3357b4055a1e4316932a1671e382300fe71826960b42c08386d2892058490a7b7a2788394de48789dd22d9c995a6ef58c8e8690cb193c6dda3c88a4a1f005335cd6150941298f3e4e64a20c08eb447eb658ec1fbb98b0da8ca7fab496b25a9c633cfc61dd5f12b4ea9d70ff8920935f41272fc02404f44367e59d5cdc97af750ccab3fcfb6d63593fd9b56190c0630c0270920d5b3cd4df4b2fec4e68daaeb6b41a69b1fbdc066c19de53e3217938c61a09caa825e3d255289927872ae985806647853d596210eaf6a8d646986fbcc7dacc171318b925a2d6458b9ceed3cf26b37da35b00ceb597d8e9dbd6c6b386ad360f94248acaa8c1b7a69f8866c0b84aeb71fd9bd065b9a56c81a6be902417a2886fef4e16e7d0333fca6d3e47c7c35154a18d391c319d24cbf5ca96a3ce3d5d5d2eff8826d23e737afea3714696e5eeb1e0d65163fc9950a5318b7d00de11b50fb717d0f6b2c95ec5167e10b5afc245b782d2da696ae6cf746dd82211a5f403fbe068ae30d7a785d4a6debf4e77ae57667841a510775c41399629279c05cb05a0bd1dc3354ff1635342a028a7de030173387103b7f9ff416880d47f0de9bb08ed2412d301979143ce1cf2f3db44761e036b8f7bc18ee1e0598e3e32477803e700111e2a3f84325d86309d64de9565737035f8b7b67491136b9bc51c4ee3da86f445c947a46d094a19821e15b2a921137ed3df4add0a6c4292d1d817a10d131d0926e0788fa4fafd199d6a5621d26388bea719bf6f55d3ec943e740632abf7a24edeffc69306e866c8fee66f2c436535d1c145a8e5b05f52d2b260beb9e8f3139b2bfb8783eadeef9a5e48e4c9effc3a1c6204e329f8c3a3e67d1f8981e4b9140197e4a372be819ace7f4932d6cd81674d19ecbf3755e0124dc968ab3bb30d616e933b33c87942a3a725e5edf481475b7fd069a479bc1e3dfb583317f0dd3ffa73d96bea4d6155f7eebff2bb9fadbcb1fc0e7afa9e5f140286c41159a700b4fb948f011d6b0dcf00b6b5f3daa8424f85b3326c84ee8e61053ee95e0fa680deb3e24c1114f66977440d490a17118a11896ad0b5445b7bb1efb99047fa688f107efe469124cd8a58a14d96458a460c222d2eab5432bb1bc2c2bcc4a6c055322c997eb0aecf0f53189484c1289fef8b43904ae2cb5704737fff84955626c4615c4799ccc05fff761414b24abb442fe13eb1f047350e9744e41439b587db6323f57105053e92f5f3cce973950418c4b00e33ae7177e8144d143367a322a06dd395540a31a7f944279bb44e0eb4741df2ae36d93584e954090e8ec4b16e07cce434473cc5476c9fd2a9bfcd5566b46a6e2413e12a9f0b4cd2e1aa61a2ac19b8d6381f2811f998b0663f633b66f5ac883d784aba823587536769f7fbbb141d03871ddd7ca37e99760ed245be2cff85a5b602c4acf1504d17ada740da15107d4a5369ea15692aedf396704acb3148991d76c45629d9ed989f336efbd03ed361280249545f336433583f43552ff3b38f4e2a6743f05dc68e682531a13ad86985741b7e632edc489fa82bc0dbeef4e10cf5c98313c9266ac71c2127420d8911234421eb4b880502a6338fefad8df202e47e8b4b0258ecdb0975a1cf9c9b065b31384012bc7d75f7fa349408b28591b20b8e3c5cd0add60382a12aef7b5fcf90e1d6612eead2ba8b9271861be3e4dd16f956c036819dbcea46d462e11bad826effc220ef225a52b7cca4c2603886376b63c60406379460c11fbf49b6c56194b0407bf2d11dc65f4c8a7d60bf9f287aba75121c70832095b9eb01cb5ea9a687590185ed6b7c4d8a99656be5f7068428f92618f1488c11911489f1e976b3c96847885d082069b10231ff97d84d31c47ce85a87161bf2b12b4784ddce297ffda65f3e2b6d034488c484e9796bd201cc4da309dec1301916c6cd953f9f232f37bfc58a5b4a4ea0b6c6dec596923e820c7760f69df724c89fa09e40c7d3ed3950035d591ea8116154533ce0db7aef25317f2baa539ec377fbb7555d59bf71b569569b1b581bec7da442c5e0b4d629f9fce0478bdc40237d457c36663d9d9c3a6f60d9b80c0b7fed3a6464c03376fe36d3946e811faa1eefaea5f4e287ddca5f07b9dee2b049772e00611207630f2aceb63472289538d6bc268f54cc1d1d6a927472902f601050bc489096d13b964f224e18ec600f5412496c6344e60427ad5ab343a7a2bdc8191ea6c2adca3ed6d432b0d0d638448ee794d05cd2c9d91a2541759275a9d988268b229a3c0bc48cd4750b245b16d000c8cb9c877b73c79c91da26e7920b16b8e0dd0b43a58e1605ec4a64b28d9c410912417044bf3b6c3c90ad7f076b0acf56c313310ba08d456358110d4b7f305192e44182d93ba68e4229adddf3149f823682913830c155e08e011340f9231c02f54a5bfe2028d493c8239227521d94e28dc57345dcd096fc1fdf68b982017fa4b188c6c4e637252bb74d79280a1b97d947c06c0fea239bdbe41c85c84a612e1862747a5ece48e707c16688ffdf660c90edcd336d6b1e57636e4a14631056404da0b6904e117aa1256dbce2ea6375f244d5e77b0fb589334dc8b8356b4cfe4ec707bf36cc03e3370ddb333d14a66cac34ecd1e8e49697467077c28f60aa9022a8758428c1f4006c86e7dff622c40e3ba53e9c7c2efa8da74a2c7ced1bc6e85857107c3544ecbd4c55c9e57c3241f81236a059d7c3eef737788ab116567398af47211050b4b04e40646dbd3099824f309faff2ff095c4c4d5af00a617599cc7fc1e21fc856785dfab9162feb535e06393810c2cbf3e4faeb2db481f09bc54bf5bb392c8ba0988e4e377ca3642141ec4fed997eca94d0448c599595626abed054b9d3c5c65b6ae6ebf47ee7f7c7f1eabeb3004ddd318aef21114f46c6d02d3f98145cb42d1b78a5320285c0edf62cae572775d050ddfbfa4bbac92e1ae7fae53eb6802f813cff50c0435d0b7d25a0d9d3438574a564334589c5a523ff524a670e6aa70ea8e6aa9ed94e1f72e1977d4223b3f329526fceccd942998b575930a2ec9aea4eb5fb63984d964067cf236a458e6ea952ab547978bbc8f8012deef6640c035c8647d8c6c0062bdd840d3b99cb85267989c06da7065957a9fbd55ed8cddc88087a739c7d255add77fc023cf8faa44b9543dfd3d08bc1494d947e4e300dcd0501b3f552d85963c83879ada345c86bd7b3ef339446b9c255541014ab38d2cd0d7254a380cb2506fc31fe8d39b30b69c036debfe1a18c46b70978423bdc415536d0446679c470f40c6455eea049e3075d478c3483e71c2620f8131e2325e41fa6b2f8d44178e1702be22d9072c1b31a10b0c011dd8a56df9ce197027d705a11d4226d9c571c031fde8929b470b8090d1175337ed9d080a27db53d2a343d52dee0e50cc6fd7327245672280733938b11338bc531f02b1619a487a71a31ba0590449e6b000d8deb1749ad7246e953b978faf04ebb96582fd20c7e42734c8b2d121c4118d0aaf4d0222aa1e1a2b3f8d18d87862147f0b8332b6e034dceb66eb6817ab5ebfd5ee2335c30aadc0ca2eabf03678841d0cdea6901ca6d66ef44dfb24c82423c0cf769322c2145a554fda619ed6bc8203f90e9540897fc6905407d05f5a589a3bf0a848802b4a9cddc96ad1afc2d5f039c501b0ea64b25117db8926a03156640b1557a57daa2cdd2c26bd456b1c33b0e99319cd7aeb535a5f5ccd9a43ac6a31ea20dcc90f140ad5375fca4cc39ed0d6ef12d894140d99f6380ef01e2f237adabe544136cb244b8b2d1364f41ef61798cc3eb870b1311f1db966684f8c5315ed4e78169e6d8a28132d373f97b622a170b8a76df533eaeb5fb87730315fd008905e57e0d58b1c3e21f19967d45fd7925919688e910de589d50797a35a96773bb8f479b931d49f41b21cea9ed02508fe000c51b836676e2200bbc34d388cb43000916da90c81a429d56a0a8169272cc357b3932dd4d559b034c33dd6a7deea205ab33e3b238a16cd115e8995b7b366bd7c166c8e5089edc0acb58cecd728406778686781639c805defc796f2c12f9dd08650b0db7beea371888b973509fba2ebc93dc79f1c138d09503352c56efffca3d9a95ad4b9931963a26dd5e29f72840e3539501243fdf4cefc2823483ced29f6ffecb49a9f9cf8741bb94fde083be04beb47555112274bfda5286e68b85ad58a21cad2d853f77e455cf5de7c16b2ab0d053c9de6625629dfdcccc4b2023b47caf694d1ed9f72a98cf8276d3e0b0898f47ecfe0be02583b8e5dce3867980f7511dfb84ae2b0876b110e976e281e7e56491c78b8fde8b9f8db2a5f0c73d734d50285accc85c8995c9782e1abb59616958e56f252340ce06276b1a265baa142219fc6085ce4e7cc086d219223e079e0e252141e5eac150598cb922a82d8577d4a38c84af92f19adf1e8ccf6b24a542fdda876264fab8b55b92756dd28c91482dd6f550eeaabedb190d37a54fa20107eb737ae9421a3da2cfb092823e03a1171639a6b59368a6a6a2223d74adc88712913ad1fe81d97884ee2449f0dd88b439c33b4cf1517b8c655dead9a95bc178fdaa59c6d745a98b8231977e33bb67b63dc131ded58aa28e4f67c82f1671c638b752c6f8cab24abe77cb024404e0985ce79d10670a15954d8378b7c8ed2259a12bd95616bcb934ec89b888f2e263021917a8ade37d821888de90e28b79511e311367fcae90a0d4b6a24b3a1583205f9057dafa41450726a7ca9234ed28b126a525fc832f1bd5768c99a6691cb563e6cba23c49fb37f77b874c71fd8b9fc5c27dda1d1c9eba4afcf51e896d011ff912ad7c5bda483dfd5f9e49b0e7fa001290db205ce1bfda0e2ace96fd63e3fbf06526b40a8311400c7ce3bbc1d35bee3cf732ef583827304c6cea20e4247ed4c76bc3b6747ab68a1b7028ff4bc567d0396fcc90cf8a1cfe3abae13f49e41fbdfc099e651e8bc1d9421f488d4e68e16c101c71dc7ebe7fd7f107ddec0d179f4a819b43f4af876fb4775fd27d81c20d1262020740778395f21bd33fd8e3fca19ee0fdacf3d503b5674ec2f4b07903be3ffd999a27de0b58ed0f633cc5be850bf23c4d69910bc77b4b0c83a1b6f4d0f7d65065da37d82656d5f6fd37652bddf9937d8db7b86d70795e70b101d4e9d75a7f41d7fac33c43fe83eaf7076e474d67707089c33fb76758264e7e1fdeff27cfd860e7cc7dd415c9f0c15abd37b431262d87ac4445d76f58250a6f3ee2c3b0d1d7b87ae238ff620eddc74141d303ae2e9fc66ce7b8310f7fc2af0289ce130e8283b9ee800aacedf2f6b1dc3ad925935f20e1e949367e26d0e2fa8b382f388728e3a875e5940e5759d12491d282efb6774b49db07602e9b3df9f7ae7b77adee283f0e70a823a359d699d97ceb38eb253da4ea07d5618fc3e9dad9fac0e20e1d9fde20ebeb377b6da09043a6b1bfc09cfd15f40939f660790e0ac3dfc6e492648da327d4279921922f7b6fd41a7a7d35864b9044bc3400e190854be5a506b2721ecfc8841b0243ac2530663a2290491f6ee033a1ddfb9c7fb0c002c757cd3738081b6e13c9305bf3be7523e487a2e00adc3cb4e20fd4c0f089dbaa3a763ef00bdb46832c3434673efea07bb110424c09ef5f74827a83aff41ec784a122826272f70e641b0853b54d765c2e13987d0482c48073a72b18e7b2433883008c8daa020244fb460abfd3a7482bae73c9f41cd597b01a15c11acf05d23ae3c5d676488cc418825328c89bad0dbbe93dc73d63c384918ca0fcef90619c5b191075d90672380efe4fcf80f72cf0f7d40f2ac0804ea9e554861073ff4b3f9a09ff25c804427171ddfed5cfb699db763cdceefe5ecc407e59e1718eba875e69dcfced9597742db11bacf31fed6f12b74acdf6f4e14372e43dd88bf4de777fcfc0ae44238430c7ccfb3ba3fc89ec1f901d167bda1c7ce79d40f92cf4548d3a93b1b3a161d7a1d9176023de7cd5778e7f7757ed80759e70a6e3a3374ff473a9dd3f97d9f035fe86821b6c12addb3ae1f249f8b41d01d0ca867b83e483f3fffb9e0a40ce7e312df27009ab2245268503a8530c3eece72878d64fa19b7a78881c80221497904d28264356eeff9cc4e4c9d707684d69f1954af03087cd6168e0c9f07fa8a66e164439a3040edf7a80e25eee2baa34e37bdc2b33be20e4365d67bdf0702e18b7369a09fe01c01a5a3521d61ccb34082224591d0d9041162e0d6fcdb23fc76ce0b3fe95074ac42030a7fe1842dce0540a031feea4c75e0744e9def7400a967bd8210f25cca07149ca397974e9073c6a03ab490d8a18f190ef6bc6e4d93a59c0fdaea2f96842c47fdf14240ea3ea33258ea1a26958118d336eb56e221c903842740d2650e8abca351fd3e88daa56277e6e9fdd9656a85f4446948aa65f71546cea5f7a754004f64c45a37066b8a929d19997bd2294386507b8cb17386024358b942d0b20794e9a573200853957c575a6c3e130d3048479e2cd5db7221322643cd4d3aecece746dc2f7cac1634482c87f6b770e120f26626a9c67438039337c3a7b64e6ac1008e9dc240a20c6d237a2ec139108428f99be1ef5e1c074c6294658ab39cd788a959a3eec6b71702d8fe46c781ac364ddd6a5e092df7db83c33a966765dc6d05e53c00b3804c5f2c472c8159ae4e1ab49d2b0dc52d65c9333cb94e736913e1723c8732a45f82412dd25f882399d38471488e45d9b681cdad5811cf8402e072455659a9ffe94e92aca773531d080458e85c0739419ce1e129f8062a04611677156c3097ccb5d6912dfe2df35e6a41bdb2cbd1d182d8aa609d53a9ccd3224573b9812a8463096a41d6b2209075bd589a83ee78d4ae12ab4295fb8d36fd2379a7b68ab90c85026ad475615f40125a4d07926d422dcf43dc484799044a99eb108cb557339bedbfb77c5f1495777c9ddc827c7e57b762a0b9629d226154affb5f0b109143ed1bfbb991453a6b13166172e09f95017c18940f7b09f1f1dd2410635b6fb2f7965b4a999294017906b205f005b3c57dff4ac42ace6543487e70c48dd37fda59a64fa03ca11fdcbe1f53732e9d90fb80cfb2e5a6cbd2177b84fb49eb943c5b9f65563f2dac648d252cbfcc305bfdc2d32d95e8d5306bfa57a20764d6f4bfcc306fbc1f2f3c7de395ddaac17bc17475dfefd1305ddef77b42bc193c1778413c1e0fc87485df6f4b9781e271af05d375bfdf9361ba76bc1f9e0f2f06af9cae94a50a883d09a4578e108b4102eb499527eb05b0c61d3b7a3c09acef11830499577dff67afcbcb4fb0460a21a05bf2e9531001ce29808f42f1e04c47776fe74ef553a2b54d9bfe18d13a316dfa61446be545b438b046a27d62da40316dfa43d146316dfa51a23d9a36fd27d1e660daf483a2d5c1b4e93789f68a6891442b859d62daf463d152316d6e9d807e19714e03902a96382902c8989c57a28d62d6f4ab444bc5acb1544c1973da236beb8904b59cf8225b9bcbf0ca59d38f711896b756cec6cd53cc4d7a25379e68d3a6df250b49144fee27bd32f7bb2075bb1c39914c49148f109d9d971d3a4b997449ca1d94c91088e47e140f4a084a06828b47724c7b507ca81a230409eb6c4629a5943a80cb608dee6e2fbd74f7a6d5f05a6b58cbdd5a0d8c7344e7f98b4421d7ef7e9af322d7b1ce725ee41efffa94b9fee7d222ecf7af3e763dd3e55fab8f9527ec6a61b15cbd12e8ebff5a9c2c56d7f9b77f8f78dae018119235d38fb9912958a3e789cc19c370da4c98eeafef0ddaa8a3e8a3d8e0cb053ff73c3c1a09e0e7fe04cc7923ee46ece02bb441473a6de8376a867d9d4cc027e071c638e305bee8cfe7401b74ac1cf8fa66e6c09c98ee18313a10e7879082af2ebb47b137db3bd59f21a05bae1d4340c911e449b7640e07dfbf6c587f4e5c7fceeab59ec2473d8fd383e1a3fe84704485e0eb7573fdd95b5edd7b94524a298540aac6e6777777bf38f79e4ce7bbbb7b055f377f4747b5beaca5f3adb5177cd53bffde9773dc880325ec5e6d451c281df8f2dcef7f238d0d143e94e93f93fd4e245b2ae4bcc8f7735e643bbe788147b216b9588bf2b537d7166f5e41bdf1b5a9fc4ce0c2908226dcb7143ce18e78c45eb325a3684a98b9ff35738f377283fdf8d49f5b859797fd5f5ea65bf2045f9e978574d944284fa2263da63c899a20a9b489904ce22665a6df0496c98a6d9e443e5964fa552953a40fe7a7a788e24c1f8300867012f90c65d234897c84f224f2e9c97912f9f4e0a383099f0f916906ce5f4f509e443d434846540a37d4404bdc07223e08a93ee8f8c0033359cae2c3e9e123825a9762887b5bc81105d1101f687003951800c04654048825183081e2e3e1e4e21d5dc589206850bea0038a26464cd4a00517105144468bf97608717689129808b710dce55ae829305ee8b06006430d6234281949a2c6440983d1133a9f0e274b863c7cb4849639672205ea87104278bde252b8dcaee5f15305cc081341722c2922cb941d90d072832c98c04ece63081a440d40923c3184092c7c14e1e10644c800851652787c399e7078079c96d5d5c103804852c321c9952458c04316a01854d95102067e382ad6800c8ac00289500b2f284183081a4cf103050c33f47cb0192a4a5b7676c8420a904f8a2080b40c5142871477cb9576242b8e540413235c860072b96108cbc140831c749e8002ab02841018600287233b5c208203ec861abe2894071be76d41b10d6a98b28323db0f0e2ad3ca0b3e9e60a108901e598aa0b49881039621927414c103061304dd7c724cf9b192c41215ea992bb42d5908e19061082ba440f1e343d4630b26444c5547ff205ba285161da8e4a872031ab60022881938a1e50a2bac1b2d092242104df450c40a123510c1f2444626035a1354ccc0a78622ec65318412290a40b92c4294a80ac124c827c4954173188f18cb124c9a4009295172a4db00196650030f233dbc3034e489a1248a08a2b16024968ba076100016e8200a0d663a58986201263d9a00b282051c5070705a62b4c7951fa2c0c109901e769853b4f8d163871638b48045c90f272527c1852156627812a588942119ac006d61238276039399c9631863f18c68f9388ee3eac5583a9e2e82cb6227125a9e10d9e2881990da11b12a925002cb9392b653b10061052b907e0c69c202202670840db12850344113fafc8710f8864e922a4410d14356e589d913259ad0804410131e9ef030832b2e3044942b43362458c4b058f2821c10d1928389e6a1e7264d31a9382a12c48f155ba62c01a40543418250b223040f5180b4852b4f601886a03532eca0c20a2778a04287034531620643961e587af001009e154290013d2ee3ab5d26b787bbe42ab93cdc2477365d31b5af277567a9275599bcbd8054edabd5a7d12e731bfc061fe244bc881b711ca64d7b0e0e03d7c19170a2c7e08a2e03df61daf4a7c41e314870594e009755a2e390127d87eb3bb8cc26754dffd28e5067e70ac94d4448957db4371c1b849f0da6310c60a5e0eb4a80c532993c26e685c11ad6592b6732e11875e00841c2faf5d5ddea6647bb93bdb63ecdd52bd0e74fa290bb863325bc94c4392b7577734a4742eeeecd7324546bad61ad25294fbe9733791321e7224e1321f724ae39f471a6f46b8d118284f431f80273a64db754c849e5a472fd222a924d6547a624c618635ccb51cd69e3017d384f501ae31e76cb446977b7cbf6c78b6362ac0d438c6bb52cd6051f70efb54fe9c781ce8125cc8c82df97fd8b824007be68ee7047bb7baf8d2e05d90a8d3f0af4e7fb78697bb5f7f230fd77c209347d1cc7711c0df728dc1182843477c4cf514a2905f37d21a1ee7677f74a6badb687f6587b692c76397216155109fd6d2b53f7fbdde87df734da411bde3853f97e4e2a95cad78aadc471dc0aea8dae4d40aa6e2d7d5223b5d1fc96e2b0e9aa59fb2ea6f27ff691ac41dbabbd1ceebccf049e50a1cb0b4c4c4ab562c9cc9035ec48336da875316de80b0fa6cd0776084b09a95823a4dc4fb64810fad6ada46e298d16878a90b4b79b854d1b0ab3b7dcde8dcb41b7d4244949132632c9aab50854e02746afd769113e110a097d94743431228a1a8ddbad40e38522547050840e11235b163e3610e18328098b92167c2b648ee38a601ba6c534d70a2a24f1602b1242168bc988d56008922542372deec2f7f598516446114ca3518296104bc8e549e44344888f4f8e4c3b30e4424f10772fb6d59b46a3841e2bde86837027ec396aa22f519221a2d914578f194d84383d426e68061421396b33b00849164e0b218bab618cf10760b0a6e78ad13c897a74324d9e443d39f408b13b7352da187745bd6cd43afb065ba97b5ec517d9eb38aec39c576b8739cc5955d7ec89de10a5b74ebfe1b3ecf3fe75b5105e7f3bd6b16bdda28e95a86e373a79be6561def4b4319f3cbff64c5be70db5386cadd36271b8f82277e2e926e4324e4a5ed38f8ad5c8d3cd5a8b390b6343a7e548264f4aa79bd7348c0ce614d4b4a5a42424242312e646c2dc4c9984b9e57e981b4c128c52df58ff691d366d54d93d366da837d435ed09754ba85bde50b7ba366dfa4fb7dcfd2858df90b696fb9674523a2dd9da74d5d72afbd835d5ed1a7d3842b4e83fcb384fd06799467707beef04f4b1481d05f8fd3a1eebccc513d287c56a122fca7646a7f8686cccb7ff9afe1f8ad26e378da66ed5da737430a74e6f5a6bb7288d7dff1bf963b9779d6d6badb58db18d971549f041b6ef9dd375d20ec117aee0abbeade2b4b1e0ebd24880fbfb3cba118fd86b2ef8b2373207beea9cb8f33cefeb3acf046e9c31c36b3acf7e2cd6770277ada9ebac7defb3b556dbd58eb8035f3de7e781fd2670d4148626d004eeeffb09dc75da2058c2ccf6bd561bf6c11ccf53c1cbd5cb76f44cfeba913fd064c2604e074e0c7a273b8215d41bb5515abe0fe5600ed78f430bb9fefe9e2b61e62e04748bf7642d9a73ce39bb1e4a29a57d94fbbbbb9b1331cf91bb574ea8d66a95ec25ef910b8e9c882314e2efc00670d9f41f3ed96faf28f70b6f24bd586ed216e51ec9a25cc713d4f207ec0c7fb433e2038a5156508aba514a53312bec2c53d495d96ad451b7fafd5522eb57a28ceda9e5c64a666bc6aa4fe78d3d6267b9569791b0d61aeaa86fec91465d79127f1464bdea79c8fc6a842028d03eca84199f5953d3e06bc667b6fa532ccc97979f13ccb9f98a37af54aa5ffd09aa5ffdfdd5988218dc51e6579f02d68c0744f87dea29f8bad9ff657cd3cff4ccd05c86ccf7cf27fd5d3e25a662a9d265acbe4f3acc8cfa396f2ceaa7cb50a5626478cb0d23439f95c365b74a5e46b266da373d2394fb6b0a944cc55a994cc5f28ccf4c6dc696fb3daf4672b3ccf164abc3bc99b3696ddbf6770c28383e6250e549f4039597e96f71cc9b599fd6d92c6a1db3e50deb963f5d3a922443e231a2df525a46c7ecd3fb747c91ed0f5b5a9b8d756bded8d2da74cc1bce85d9f276aef41a7f8cc390c5f27fae63d8c6fac6e2982d177664fa8e63b668f9f647d98eb1fbdbc0d2bd7419268f2b3dae2c3dae2c3d7f972c747159fa24165268d4a8f255f15b9bcb7031ea1a7f2ad8284462257dcb51dc1d5d6cdd720f5566af494eb4e9e2de3d160363a8ef6f327a7fb09c2e12dcc9bef4492ca4d0a8f115bbd6521c078e15619d4d9707d45fc216666481c3c29359042af04313225a2c8ba0737fadec4a12b6b2d77ba2a38f61166d4ec156ea9303b94d9824f40b3838b6d09e944f703c9145c1d172b560d25d0b9e4d1b142e8ffeafbdbaadf55a6befbdf75e1192dd57dc6e34da1521e8006e621a1b6d977cb55a4ccb64302f349770da6c289c242a050bebc2c6dcbe96e535d439b046b517b3c20fdf4d17db6bed75569e79526b4f9c8bb56bfa5d65d87ebaa40af21dc3cf3aedea74d569d38139b46210e7d05c614cb56f6a9e38871d24659295058b0c6e394ca18434850eb61c0d093b4f22275038b1b2a3cb93c80916486005e89821c70d499438c243451622b454119bb2240553e97c8b12239c2cc91ee449e424c80910b2465bd637a7555ada69a3b171237fd7d513ba7a4213155d3de1a4e37c8bf44d18e4a5b4ab575b6db7d76a6d554a22eb9212aed5d6cbd9da9155286848a813c92aa5e6711cae9d672b4fdde956935548e5f9becf04f69c4c0de604d18e8c908e926ea1c965874eee7f89c190bee3e567a2a403f5e4d0ec555badf734da6d5d6ff781a89718950c8d18e3525b6d8484a49700c5088a3194e7b78c26b58c0b2cd97a47ebd87aa785dcfaa60b6a19b42c874a292595d28822e5f99446a34268940812da920d60a43089b5b423d3f2027d739fca4b610d853308846e99c790d135afe9af34994c269369b29e7a9d7d2e21ea04fad7a56841341a8d1653ee946559c2dc97d96cc96c369b59186c070c068381207a7081699bb669a3952693c96432c5a8c5c4f8dcd6a14ea07f311df60f86164473da47a3bd943ba5975f599abcd96cc96c369bcd6c0400c345984ccbb22c4bdaf77ddff75d80c42cd3b4751875024dee82b92ea405d168b48ef695e54e599665e93637729bdbdce636b711c034809a4b69341a8dd6755dd775655896256e1a079afc43711777345a108d46a3d1ca72a72ccbb22c808d4ba6b71bc618635c6badb5e28f46e36e1734f9d79d2ef6aa47a305d168341a2d86a900269c2942ced432996cacb5d65af38dde2e95795666655666c15a6f35e9abb7aede70bd71f576ebcd0026031ce0000808c1840030278404dc24e0e6c69bdecca7798e5d6bfdb3586158233126db23d2dd489a4c782463625cb8800102085d7319964a91910d29694909cc76b4351f42f2c26a300ce61a07623833273a5800948593156c2e001d013d01248513201d80860029612baf1c61a40a103f7cb25421b28203c90e33004559800c44704005902355645562e03132d402161bb86009084a04682d48f8e9b0330488098e0ed00e0e0c403a4042706af8a1fdf8fcf0f083e4c7c88f0d3f3c3f527eaaf8313a32297ee5cc1b4da9109892e55dc3311cc3b18e61201c73192095d28807499674045cca7ddad1f3e960a00face1d8c05ff5c20e56f98adf8e0fc624244f1f2cf79f76fa26d63754a7ec1b3ad66ee1578529ad111f8d0d7ffb2f77af31316d9a31dd634869e8a3306f70360c31ee582cafc13726c664b2ee6168eba3605fa08dfe9cf9feafe91c9883c1ea15f9e6bd1cf77ddcc77d5ceb82353e9c1b8424ceaacc44f88da4cf32f71c48d33d0af8bfefb08dfbbc37cd39e79c4a99a39452da42dddded962773efee5e8f32c77dadd5f6587b39ee1b71ac7c228e951338d2d8c0197c9cc191542183a7c7f934922aa0fef40eda40dda2ccfd89fbc856ba4732e745991bc9fb954c412d7fc067eedf8f9751a98b494886dda2e324bf0983fc6c4a7da3ca534995faa566ed087576582e8445647e3d5ed3f88bf209752b25de1fae0fb3a6ff8b326fae92d9ea3bebd60fd3f5e43ab940f7e736b93eb7e7faf005f48adcdf39a599a0e4fe10e35a6bed3e2cb91ff50dc9fdd493e2c96842b522db114c2693c964324fe6c93c9927f3643299a8cb819574107ea765ed8872ff89fb463ce227bb1cb95fa6c3235692318c9654468fcc7a60aa9aaaa6aaa96aaa9aaa06c3300cc3300cfb804b92fb5af991fb29875979dab824b7d65a2b375e2b370683c160b0d99dddd99ddd55cf6ac90a68d5b39aad8256b4d52a3bf1a45bb92e6c2e6c2e63babb7017eec25dd85cd872d7d13a315bcd7c06a68542acda17ad66eedf0726550a34dbd14529029090b4b072babb85b985b985792abf2881120c06b4178ee0243152865284378447c25b484b82029467f22482920494a13aa3b6f6d29b566f96ca44a02124674d041a44a021cb47deb079d9b41b95a15c800d88794133d327d2041eccc8b0fc449ee003d64a95aa2712059f8a817971b1273205a24b883a81a67b22553072277205f903c0884ff49d501a5bcfb84c65ddecaa6360d9679efe8cc074b19e3e954dd7eae9d3db74a99e7ed3a62bf5f4bd9cae7efa6ec34fbdcf04be5841852e9c28f31feb93adb28c917c45f6bfe1152e4c4fba04657f97201af0c9971fd93ff563e6f4e48b95ecaf7ab12283fa154c1256f8e427cb2eff7598e671a699e1b0a8ca32224b8cc0b4a1bf12a96cdad05789f4d6342fa7cd7cf92a7ab569e3301e6cdab866e83ee667625e441791a49388a436645a4543f118bceedad63e596dba30fe640eb03132d4b3599897e0ed9ac46da5f764d36ea6b73335a70d25674d4669a4979c3be1b669435dd0883332b26b6a9125ae44957db226a1c1f98e16e6e16061d34583b305dfd2b1cea64d43a0fee8ce3d69719c66d3c66135142c4848c6d43c58f68fa94d17f8fe1f28da1428be744fcedc6664d3c653321790909cb9a564d9ff03d9745924ac586731b099543689337f286fe696fd3b919cb121fbc7881e2ce5373e5a63df84f1b9704a63f39e7197f1cabab95de5116e08abf76cba54798e9c85e5394be55967350c834c63060dd519e58e64fa3466c00021841166908d27bc508ce4989e35173040086184dca50321d2b4da821b6e56061995dd1d28659e5074326d89a694e9879896942907c4e7dae1388ee3b898cc72d1555b6db5b533e1119b8884336323524f73cc48dec831eff2a42311410e99ba7841ba0eeb3d84bc0221d318230018404325fe18c3650060f41e1fc7e935420c98371e65b6ba040f5e8c242bbb18c9a719c99628fa12b3a6ff45af326bfabd47a86fbce651e68dd760b6fa5389377b0de68deafb7d8979c3c4bc513dcd7f18ac41c3d1d8fc357bcda917a944cf5e53899dbdd6bec49451650173268074c9f4e7440099ca7484390d40ae32fd17ee44f32a71662e8b4f33ce69937a99d4cbfcea3f0bd658a56e6a9592f98f9a4a984253680a4da16e257aad5bfd33a24be956d195f90855ef7d4c0bc98830d9e5c3f432e24b76f9005f4674e99111431acbf4512f23a2b2cb4748ce2219f1945d3ec2d4935e5b3dceab915421af5e04334b1c53313022e946a44391fb5d447266a99175068aa42d2dcddec82bab5d221f70ea3e6b40efb0c487071df6f8e60cda4d296d1a826fcec0f83b91b433941d22a3f4b169b4474e47ca1e3b64ded89fd9ea7f7ba4a7dffecc9b391f14a78fa4fdeb8d73da74f66d27dec7a2bfb53f414ba9a5d60554ca2d031568952dec816fc22057b014f5fefbba2321cd9e572937697697aeeb52a48b08b110043eb3ae2a216969a4cf704fdfa8c4fb3b54919b1c4fb26913149230355986a9e19e6ef98c96fb245bc16c163454cd3ffc170fc6f33ccff33c2421cde1f74ff0157e3d7da3c38c642bbf4c1aed329ac6cf1bb323f19efa8e4e2fb5d2580305d21c87e048b23e7ba38fd48ea49dad72f74ec3380c59acff16e934a56eec8e70aa84a4776fd3657338fb34dc937548a817ea21b5fb0c09c24994044c042e18b87270e950de2056056683157c24551c1400b2e50710cd05447240e1c1e10a154a8c96f0174e58a600fde063840f1f275b6049c2a30821555ed09f909d2237cce0882c3d3f24cc9f1dc02132638bfa03964cc6b8efd4c504c602ee57f70ad6e86e6b0397dea8e4ad9506350a9532010000a00003160000281810898442a124c8b3244fdd0714800a6e824e644e3a92c782b12c478118c3310c87100000310010438c310659552b081e3502e61e98f8688a58863c2983f088bcb7c28124f4c45ed41a8fd9dbc25478644e18d60859ac28139cb6e672293e5a7a4021f5546cb85aaeed57a3ef4fceabd58f55c4124e8fcd13b6b0ce40f77eeb5821787638f9a1d7b24df8a62b4fe5220c72a6cdf8934076fdcc656ce070103a2a659401d472f31afc94866db417d773f464d7760b882579f98473809d9a0346495f63984d1f4c83dbc171dc5f7c7eda58cd898b7f03f8e5113ddd900171bc6c2a58ff497bafc72564aa00f16e2eb881a442d49fae200a2d3c1620797e308f5f32489920a2476e05d15aa83f2817e586a1de9f153a46a5e462a04cdf74a68053b4e90bb48bbe0157bb2220c1b452d2840f86af649eebb2148e6173ca6ea0da7ffd26bf8957d1691cb88a08ca7c8e99725a75481a802b337c558044307215211b2f0be6ded7fa4c2e1e0cb8e6158169d1330845ef16b9d70557a9dbc185aa1acb85dca354d72d648b3a7510ae151b7a5fb247c66e62d513c4a3f97779c607b75da857367aa3cf573e84709955743fc77b05878e6de47190d3ed2ff204228de8ce51a75393373474fcf038de872279d4806498ff33d032c0e3e47e6ec5b2025b79209638623c9fe4cbef595a1a613eaf5fc1ea036af5e7d9962c3102ca1d1b4ecf45e75996958746d1e2611f772ba63046eff9393a19eabaaf4a265dee5a2819ad70e8ffec65d74593f3145cd41918d2529e4dbb261a157051386289a95b9202fe68cef45791dbfd78d6968005fa968e0d51bedffbc2416ff4fe739c01475d3ba359c32c065a0cb7a83356906f7d4b4817ac73bd6591a2e12f432dbd8a4362766771a83bc80e323555dd03b7b8bc20897e0acb164af3b23d4b7782b775a2bcc45723c22df40a3c64d61ee27dd24cc992325825f2f19d8927a061cb34bf44914166c9d2e52a95d45a3b333dd9608933832c3bd4406066dabb656cd1102f6d71dad651bc003669180945ff75e0bb1a65fe93426c2ad675fe3eccf93a2a32439e195d129c9e61db5ee7994709726799e05be491b1e79c0af17e3ba2bfa652938639faed79f7744bd2b8bf7f3f22ccefbf35f1719fdc49954fca9e66ea9f41c245993bb8fd7f1f6f80a0929fd76e92dc7f812619d2941ac065e847db9a329d007444a9fe0d42864ded0332c5ea6709e7582b85f97478922032219544f2b543a21af4a3566f5613ef2f7d1c28a2f5da03b0cab00248355b85688fc223b07bf5801449a19678e3e0e93e06531e37f6b64b4963f12d5a79b1a420ca8a102d4b8388e3a1c825bb43e03f97154ad4e705e29052074f5a139f677aa9f0991f8bd77e309c0d1338cabe582549a6a898d391dbf0267a083650cc40399762ef653f210c45f3cffd7be7c44656aba975e878b6b2471820bf1cf4faaceb2595d30735da39bd9d079398149eaeb9016516e4e5df5eadc73df35ab3668614e5770aa3595dec2d2b968fda6d7edb0bb7d9c160fd429d91940f80daade70045d03eaaf6e63e4671219c7ab76f86e2123433457a8fe8c41a928686cdb46b5c34bd989d18cbb7fcce83994c93009ff6381261b234093ad060816cc3f991aae0cf5796021bb4a08bdac4a14348df3cf574f5e1f637ef93586f1abe28d51d1f6ceca3a4e893fb05245767eb006c96a25cd42efe5f60037c568529d6e6881339c1f09242aa380b7463a187af986cc0e710060145c1269c0178d68a6c631dcfdd88d18760e88390b1eec3a011182d9a0d9a2c641c5bf9085373c96aafedf16a4ce31b14b1d880be7ac9c1a2007cbcf0c53cfa88cbe5121b4ec02507ec03b9c349e7491b0ffe154fea28b8d0bfd90abd04bd452498962d47016bccf66085d514e61ba596011cbd6bfa14a32dbf960a4fb5cfc25a5d18048a1a9c6296612d9483dd399d8a12d8e889d80f3918fda6a4285651cc9d44f9973ab9ebc17700db9cbeb0509f256bbae9533996681f21b17c0b53f6f3d032b4f8ec91e219d4076b00a492637e02dccfd2e6115ab8822313bbbc1ffc0f027da2aeab42b11c7a2c2ff9a1b3efa09046da4218fbc54a519f9e542e46263454a777855ea3f6e09071f27086986e3c605371d3ece83ed67072509d96ad8f39466684d4ff0cfba2c29c8ce333c749ee424a20061ca18d8a63ef6e33263344e58dbbff0ebde57831e5f346f4a73d73893dc02109dcb3a765aff460655c88694a9158233a5a65b231ce46698d5412e1d5a99f0890bd74500fbcd06d1e99b502bd6edc14717b6907ec15520c9d2daf929c80d926e45735b9e83319ddff22cc220ebf70963d32402e587ba00c83cc70c03453ee06282e26cd4b5095ec3046b08a4e96259a857d9ae90f8e074bc60bef335ab43c177a12281dfdd151016a93b1660c55cb39bad07cce8affbbf3ee151662219d03e1fd983070871668007d9daaade9263130520a601fea65b306401c02f6f1802259b168c955c842f178bbd194926a73848e10b53cc3812856ec79cdc13529926c1a104ec9984d00f2e0c6c20272c880c86e0fc7d790b6778dafcf57e82143c2f423dc48cc0fe8fd4d4e5ace262d366c4bd79ef308a11cf50afbeb50338dd0f13d33e8524e15da75c03dde7902feaf405e240dd859a9e60ade4c0951c86d39d1693203467a1a9f494a34636b091f6e23cdbd8fad841565a57f34c09302eb4b62f5a5e48ef5e298ed23982e1f023ad47517af95cd26ad19e8b66c1e792e9df53d6ea79381c58ac1e872d563a11e68cf07a538b0bb28a73251c99e0ab18840274b977eb82e935c2a97edc076ac2e60720eb06047edc0ccbcf78bb8c386761bd0e12febd57631f6b3911c2ff6ae673b6b5b5b6430bf765ab7db82755ae8bb38d72809a586acbc2019351ec6d7916d249d0d26525fa4d44e145801dc9017d4c92a2611be3e5f002e5f9ee8ccef1b2bfacd377908fb434b194214ba5e4f51bf97c9cbd4829f393011c4bc0ff36339fbe488cc9c3ab4a014b404d7da245762af4257b80b4be92e09bd066060c9a8b07eb99fd930b45d07e0d57030ca41139cce9e6a65b4b94ae135b005021a1339943ea4e18eb0a63e3517004860d92493c4207959d446959887a19f3db966fe0cc431c8602f53e3f731e91170fb8cd1f38a6c8591b4385f97d3950d0ea025ebd4d33285dedbff8bfd010daa015d241b4461ad12685c7deb3ab368b97ebdebd9ff2c1b66c4b40b21c3e90df6628fa85650a40bedcfb8959d740b618b6b12373336a879878ca3173aba58ecc9f964290b84522eb10b4a22be481d8431fc708d325004e929167059663f3972435cb947ca41d868cc1227c3cc0b4a3b6f76b8228587cd59d61a56039aad6c63c9ad6701d24905854435eda1aec0375fd734ff72a24ebd4fce3d8e6caeb4d4a388172a5cab4a0a46b23d4b9b1650f71251fb045690f2944dc9c28098a0da4631d6e465a063d866ac1e3bca334640bcfa50bc051441d2f348c22f580400a4d116a88d4acc89db1ed5c0c750aa5248ceb16ce842c99582a83fbfd12c08926357da05833740ad9dc054005d861a00ec23878f7ddd447bbd588a770e9af99dfe5ae7c24e921105abce7e3abcb9518fbd34ecee78519c35523dd1a40696fdb6dc318bb2b58578ea8cc8bd1115a88e795c0abb7f1e477e7f230fd76d786e91b57f7bcea69ddf4e4e96a2e7100a9f3472e3455fcb74604c3428754d4980193a76e0bf608345f7235371f7162b261f301375360762e6253f7dded1e4dca4d213f60f9156bc7f428c433b54b689642e016861cda44d7e2d5afea809b3bd93df268852c7607af3a6c0c41f9541a985a202e9f776736008bc7139a1979a2220ef3202b88d7402ffa2c21ed91fac7c29c30ca1ba4a01593721dec84ed10645f8e72bc77a6381364402321aba14ba6a4a3c34120d9d6f087d00b1b5b14b0bbfa9055dc3be3c1d3be88f664be17f5888189e2b6db449949e4217e74231bd936017e08a54010d6021e4f781f16345a2a4c655ec611a5e44e21cb42157cfbd9a24b846c4d9e5822ac1626ee7a3f0b436c56375d297bdd82e86b36ce822fc7843ead5c0906672cd6f1a7705cd293dd71671b1aee6d3715d968d843b3b0253c655de98b3a703f3db633cb5f8607d54dcbc6e73594285dd4c1a6600d67fb2cdd80387a48369e5c320fa2e6f5fb583bb774b93a03ba88849859397a68f3923100ac7e283793859511b6c40e5d2a3cd05bb51f0b810900e4060dbd0a030a64c2b522f4114401cccc10d6a72cf5cb57b7a3a3901c5524ab0d7eecadd4df03681694e8636c4a73476e0b7f462d9f90ae32383964c268ca375e7bf5dfd576241757aa3e3ce77fa685a77519e43b108c22e07a266fb63acbf335095514eaf292adb6de42447460946b7d1b592d0b5144cbe2be3401835cb768c002ccb791184b63234bb6435305d2ca951b34a6131a1b530309b86951099a5559b2d7a8fd02209a39fd7afb895b838a5903faa8bec3464bc2a267356e42e8cac2c214783a4b164470f5af623d9224cb7bcd165276e491396319a7745021c26c2fd987b9ca3dc53802d543b4286b89fee0552fb9c35a7a0f69eefa33065a61ecdea61631188d279a55cf33a7d90fe609b355498f681142689c9225d6bb87a8532463baf21e3d4a8b0838af62aefb0c4611a7381e25eeeabe504185e97946fa910e2308d71a812ee17957cfe916ffd127a7066851151a687402c8c8bbe3e67a2226e005accd45485a6947e590b4a6d7c7a6fb694016de4c94fb67596da94ee6d871ec415e63c962f31e2d31c485668c22e2003c04aa8b11fe27cff3864c0bf4a8d6423b690bb49762fd1a67c15c219c2ec3a9c49be3c05f97ba803e34319d817f7a827a38bbd9f56a77ecd0544d15d3e72f0179c5acc58052837726161325090eb25d43042764fbf27c07bf7c41a6444883a75bbb71a97af5dc35d4b3dbb9742416e0985be1fcb99b68ad837c2f2fdf5e020a4de476f9b52b91f474af4b1184ef31dbdf1856c887aa84ac96cb8f25f215212c0037f6eb439e72a9bfb243cc1331c1c2f0f53c78613c2d2e62908f0293113f088766fcce17cbda756325cdbb63b8742ed1737b114d3146e1f40f23ae77201fc5a7ccffe72811a8252b7c779b8c368753ab2fc2004b01521f6ff41047be2b2a8dccdeee062889b73f8c727bed6c3cacd6f271ea0973963361d116c5bca8270b8d2bf44c0b03eaea92f223088262929067f973a3365a9a712094f33ca12b7a52a9513e1009f32370adb1042410233efa5524da5f63195a2d1fd887c4cecb8ac0193b5069933f89044e288a43cc31890aa5213212e1f2ec41816c97941208cf0f78a18f64bdd1d7f543b2f093d0c198a787961c4be77bc2c0d560da218c20be8589b822712bb52314d29429b5900e8ec1409b7924750193d132ba852d138c7fbf68a9ef1eab8b554f1032a30ccedb15db82dcdd2cfa242bc3cd1ceb93c8785b8ee63c28e7281dd53bb0809a091400506adec8442bad4e8764fed922f95c085dcec005b43d631695935e5c9c55cee75eb9d1fe91b75096821d5621a0f88c5d432b310e5ae699deb41c0c71291358bbc8b3433b5f329d5a28916a80b1085497cadc46a73b924fb43a81de0bc020fb5e1a911aaa4f037b86b189bf8e08be2042dc02fd10071ebcdc3c22f089439544f8e2e93b7921969806b1c517919c2b28d40501cd664f42282da4398f220b591327f8049a5c2f7118e91d01da60fa891dc317630c7487d02c0603466a2e5bfd41d4fd7bde1c34764fde848ab0c001f00c21a083ad42b982466c2d2d04e5703c6ec1ded0468e9d367312b524f6699f6e8e69138af7500dfe5657d2518aaf2a4e25a826310416cdad76bc8dbf3ab2890e8f242cb440928aba996ecedff21f3c522ba02830aaf4fb7691109c40167f350e20c0822913aa32a2bcce10c2220d5ee1044109dd67f6fdee9f16c568f24321a4093bbdcd1b9e42b7e52d05a7021c7f12e9bdadcbfafe315802e030b5ff38da2c363e09448c37dce93fe51a11946abc4c7a18fb6785a267e5cda2c0ed83be6eabbf5cdc8ffa1ff76ec7bfcaf956a5853ec5b7bc05e4d5db4facca00e3c69628c259e6efc632da8ccd4c6aaa018af73e2e6fb80e67ef511b1691cb9f60bc9986a107dcb5d95fc897c2f98dd80129ae4d7cc3f5713f154a4548c50555497de531e456d92a32240de1c8720a6e8aba9385a69dfbae3098f44582f73a94725d28b4fd08c4c8ba84bd80900fad4283893b00608bfdb6e0af1916b6dd83a1b6a5105bc2ac9462bef77802c8d0565b0de59d95f59b61e1418f907c9aa5bc67ee5e3978c2d291b39da9712154f8470700e0758b544f735d293774daf6ae4c28a88c4fe6bd1664274e712a82be17cd92f36c27716376bd0c83f98d3731d20aac4bce0b39d839d1890557d11ff119e9b5025322f76fc1c142a75b45af25bee1c1a15291b9efb8f0e0e3fd98b197a8ee18767e5f6c2028be8eeab24dbb7dc854ee580d6fdbbd827c667bd0abcddfcb5af7cedfa4cc3dfaf94f014e6bc5ddbaddce677081349bc97d5b5442b4524bc8a33a4baf16804fa7616787761d63139193d00c1f30273ef79d182b1ab845e6b415db84aa2cb36ef8e1b561babe5f1629340947e2f081b485708189505851036f170c19ede8ce3b4f810a26a212a41f8e3ebc0cea8670e0fea8294e9b4b6caf68d0a55649496798a2dcf5a5f1d802c05413eec7c07791a22ed1e1e4ffa292ade5191e1fef608fdd06ea0a037bb75737265f7d65763abb236d94ab391a86a42d1e76bbcaab366239efb8f674440b2b482415150176ab56c1c78f91e8f38b9cf233380785d1eefcbc9d80be0aa3301edd2e3941ec4256e0287bf2586e4150d22b13d67c33d6a563c45b33c8bb7e8f255890e1e1f53be7eee4d248e8c74c8ebac7327a5ba6228d3b3e245371139a4ab285e772a3d65d6313c81ce112f3117480eb56faff35fde859c07cf485c1dda993a225e40ed269268752cc0ad820e210e05ede153ec0b39088a102ac6c211061f3511c46e517a508e86dfa79c7fa0b1dd146f03538cc5d93cb1c42291041a816a376a0867faa4026ea784bf9d1c342874d6c1cc84afd5af8b0f022930d38ad0d26f0fd0e324583c4c4d79373e4c2e5debefec099bc70427a984f858fe08119f00afe03d877ae8b3a9a09b55647003e4e3574e9c5032ad2563385197211eb15e49f2996e5b9d7b027f7b29eb18129fc89f737dce3d7fef87fa0e7f799bae7791e6ba4d290f1e0c823d66fdcb6a9922239cbcb7e2bf21aaa3d2c918f38ac848492e83e2a8a6b100d063cd69342ddee9b88971004c628ecf7d449435ac047224cf8b88d8eb1c39f147c92529ae51716b2565f1f3a80803089bd0d115230e85fe188980c0cfb890192468664b795f40a098cc3334de628a400c7a3c394da3d5be6d91b6fd0c390c5398041e3ce81a5a212d9aad90b4c1f1bbf21d068ba49876a32b0f5f0cf0466e137019304d7313d90a4a1e1447fcfb5f810f11377ef560d0e8b5979423203880578fca7580c03606b1a50ad9442e88fe6d534dec2f7e1d0c0d373996f4ed879f818d50c0536f870623359a4a918b5b58731f7d0ccb17292b8c0649f8f548ab31aabf52e41c9957f02a67e216c5ee4cee4da063fa056d353fa0e823b013acc0bf4432f0e6127e985cfbad581b4e80be9c8e1ca352b4adc61623686cddc7c8633706cbd1ce1272e3167cbf77d7e051271dbd5399e6accf2cc557494036c563b223cb751fa3da75a74be512eb76132f1952044ca699b4740e64be3072a6be324194be0800686cf23907a0e15e5da2f7c56beb49a41db80da4d268dc2764e4ec86b8b3f05d37ee42f01814e226524610cc915ec36f82402ea8334d62bbb5edfe01b8970ac741af6a16432aec1ceb3897ad3a21d93fb6784ff01207cabe726e486e29e86c48cd549349c26c86f8c363cda566c266251131409319224a5c134a139d81342b545a97e98ce350256fd4212599efedb30c8ed66dfa42cfcb0159e14bcf4c5291521f9e83165ffe2ef3cabce8be0d161343c16ba373e0d0c41b8c4add8eae825a052b73bc201ae40c3fdbbf6b36551ec4d10531ffa8d5f33b6975a79ba9825ed8ab0f338824263d82e0888b75f5117c01b40ca4c5f3811a040635e5f01a965bc6d8d93b98a547d828089eb00efe3dc1b5ce6e382e4bdd71b7c464e36e668edbe07d2cd99fc15ea3a94d6a01b4908cdfd7e710114a598ccf052d4e73863889ab55d19d659d0e6574dd5f7afa87ce4aeb6d96894f1e5643e637844fed00d7f21759bf02dced1141ff3dfbd050279c24c8156ba0042cc9b7c040324639b33f451924b90e67ec62ab3e8cb0a2ad58fa94dd31eaea3ca4d337fde809a84d91a5ae288efd29feab8be6f08dd34ff0af4e050ef65654dad99072ff07eee2ef10a8c51cf85ab8a9c727fdccae3a5815ed6f95817a118e3fcc5d26135471292559bdbe94c369eb2c8ae74d961f7044ca1f3b5e76885f82ad27039c997533480fa66feac364b26a4e06206d5820dacd83a3d56491dec32174060e14c65a825e5bb19815aff7f84c8075f83772ba0eaa064884bcaabc43f8776c0ceac65fe6d2a7097246db66c0e7859077f03ef3a6781d90489ae69b8f549301a74b46c1b9acd1fe152f5f6fc57bdc956b2fcb96507f2e8f382f40e423d4eafc081ee5a7291d8fa24de134b7a12310f043461d115f03c51f6f32623e93b7c3e64ab540021311a388819ec4118776b7352c6c19ebc64f46ddacb0145cdb2c70d682541c77166056122474a2c01a518a2178186f0d179e28a609e9584de77d11986ac94ff6730614fc9a4babc8c07a6ffcb8d5a233a085d57bfe7a0bb3388a405720ecb72522d0d184e1dab81ad49b11244163ceeee16920f05ae7c1c79a2ea827e7e6f9e40f9e51c5ca371ea7eb40e7be5d51befe797421264414f8372c10d0721e7cda223932750e7c8f6f45c87970ff9dfea057836fa746c7afe4dc2af5fc886672d92d435bf076ab9c0bd9059a6f659f2e4c5c29c75dac3702ed0fbc04f1bf10a181cbd936b95946701499f12b0601923f2f05c21cf0070a4c22c35f6ade71eba00f8a13c946a53e38ef3a09ce0271e616ee0b0857d70668a7b97a0525a096d416b70c44c97f01f553d6a08ca1a3f565209f77660c2865bb0ccc8f3ac5ae35161e084450e8635d229e5470b4cd8538bc6b59990d7618343b3ec5d12b5e8e72d66a5459f38cedbbe413f1bd3250bb48c835040d0531cc904040215a96089b9f6522692dadbe010ec3428b1d6eee43662fc7c8cc2eafb5d6bba2a89cfcc711424452eaef1899498ac6b711b097526dac0461ed5f80d061ea7b0072be99c1fe70d4323a07463738e2f2e06fb88c390a4029d754dbe58c49c625923216b17a6db6237a7ebe63cf4a4c7afa38e72406eadf7256aec8ae4d097c3c09a160ff03732ace668b412e23276e7688e805efcdd345d7042e5671874bc7bdee32af4a959281ce66a809e2ed629878f01d8584d99f996ecb8997df850975acd0fbc14ab6dc63e2b3958bd2de3e2707b5dbdcf4bd39e4feb4e62bb1e30610bf039ff38d0c722d1c7210743dde8837a5bc3cf176171fa44ac8ca9aef1c07b95703be19e7fd66fe3bcf2def6f38de52bed7699ccac0cb114de5b891bd87863da3689ea18a9348c75362726a4d382ac81c81df6df093686292fc26ebd3d3ed9e1555066831f590487b35fc4d306b0813f685bccff9a6c32f24d8698e89c5283626f4a81d3a7642e5aa7fe9df8ba0c83880f6c6266745f396c71c0b7ed2d75147752f339dd4f1461fe7a27f8e04f4863d9bd3e5959211360f3e4ccb36ecae379c12bf68b078c09739ab796cc6fb97d520da6a53b56514d939c4f5272974a3ec28116f4ae11185b1153c54053ffda291201dd6067ef5728e7f155c61ace9b23ca1326b6b3fb0d87d35609c3383260eb7266102cb0d30c83d766fdf8ecd17abd8c95f178704a44727ae99a5e2e402803c823fa0a114d2f32c3abd927cb12c13df717a93d2ce143e2d4381f6c8d67cc21c762c4e15d3f9e3a1ed57f89849ef2e6e85a7d004df5e88e2ce383b058f6f2ae9608d835b0a3ac6eeda2574f9a7f0021ce35cfff8c091229b5348ea81077df377deeedcd7f2ea2a980a15a249c67eab0033d442c58a37a471b79e150728686ea73b52f1d16595f66d5faf8f0146ddc6567c033d818a42efeebeb33461286015385af79de81d1e292dd5f40e032de0150c0f93244ab80a0f73023bfb9c4f27167abe47c96a31a731f8e4a53ace8516003f9fb7f7a93b674106df4b57e183734bf567f0848739e137519dde835858ddcfe7979e3c47dbb1851508b64ba549ae9f09105c2169405bfdb7b011cca3655c24281895e0c14cd072a304aabd2838d4cc8f6b75bf4407ae3557dde33e67d714b4988adc827c08175f9a665f0aed135b31ec340c65f75ef2b1de38ca13c586b72ca185fecb3223c0dd04690c9070e741c62068a0aaa1a91634a3c90140c23ba369544dafe6dd5e384f0af77bf0de1972f2cbba39e76e7fca62284b2aeadbc6c1a23fc43c4157677e69927f7f5e1c94c1ae9872825c1698a03a496bf5f7d7be5002e417c7cc9a58706125a956d5f7f7966392c30d943c92cc53d8444dc9f7d7705f370cfcb0fe6f6c084ec7bebf4b3e88182d902187689ed4f9fe8255b75ad41d6a84dd8642407ebad7f7f79df5e35f1bf499f11c4de58681d1a4f728ecde34d3487f665e1dcec83ffa17f0c74c0cfd23f6e21741085b6c0c428af0339fc794aa7fb6d19a6ffb2b7f46638efcce122c930dfc9924ee6cbe5e97a2855f4a64c3db51646be61a9abaa6cfb3d86d468b06b69d7baeb02c6032266e4a2c2206aa411e4d5298af650bc13497b3a521b5813d4cde61f70e15b35eee481bfa3a077021e8f0d75b6c4dbaa98ada5bf4a4c6363a9cf38029d54c2a0544d909bfbdb482fd51d5abdb6d3621d660aa19f72b150bd00383063e7fd83114f04aafd0e95a0b73689ea7718d662dc66eb76656bee957f6699ea355e213d3ae740790086a1d9e70449bad94c9fd4aeb63c4decf589e697969019c649c89c9f1af3d31c912fc734f7bf9dee9f05bfde5cebb3045918848eb2f331108444765e907265bed4bbeee363ed96568ffd879f7295e29877eff19be98bee1251cd637c3d0b3823db258c240cc33f65dd9552000577f19b24cd10d47bcb3b65aecf7851c5d0e53fa162a4d8b7b54ad7bdcbea8b1796c3a2b8b238c12663baa01e79f49e8845f2413effa29d8cbd02f38d45ec2ef562169a21c227be5ba3c407d885f25907651947970ac4dea71e2a3ea22634a28761996986397c0fc46b577ff9b30c64593e304bf4cf8dd0ad99a271dc82f57ff01ec7d8ab203164653f2536e81a1fa299340275d423a52df2ae20441aa0156009695945fe359b52756164ccc98df44867b94c3b53895c2744c9b52f2c31e4ce3e1570f991f7cc23118e7a4a12c15ca8d3a602d91f181cfd22a5cb3bc771fbcf8ba7cc430ff95fc9a63826c7a1305e158df1a8e72aa8bffd15d0ef66778109c2b6ac1800c135910b0f094838c558a734639fffc882992332f4d6c2a688e6ba388a43a42d1cfea9b0a80f83fc0d699f1bfc9cf564812f5e14b26b2537b3f5220d79890e182f9ec2d8e4d07a9f11f89e57c9262ef9a1ffe2450d72d81c724a60e067d9dca93cc5705f14f13bea3e007e22e0c9e1c1b7e9e68803acde305998d676d490fe960bf59c418399007879e9f8c20e7cc5405d16cd9fe5bf291b069be5d06ccad2ce623800281b8804758a0646d6d46897774b6068b6169594de85ce5053b86dd130b1d606b48d5c4bda9f5334a1c7a4985e2dbc844839309bea74c049d65e2e898097b9bcb1bf874ad8af8910901788a68dba1fd831a360a7a1ce2c6dc48f826a9dc7659de242512cc19804549f8e47f715c13b6f608171113496f1e513f90040b10514d59c3c34e982ce8377eba7c9ba944bc0ed14a1e503be2175824a7224989700490e1fe763ce1a183e0cc28c88ce45a4493b49a2e11995766defb8cb73dbf939ed668411b5078b717cb488f3d140d19cf0f69410eb4fcd7738894ad63c56262209e3446ca5338fbebca375b2a3f7cdb609b327ea93288312fe2d62479c25e934b66fd1d35b462d1e7dac1788c5dec96030bad13a6522ae86ad4b7c3c903a8b867bb8f8a6c34dc0feba9413f31c6554a507d94d8d5f157f0845847cf2b51ab332da3b2057718d9984424a3e374491ab14b3cd21e1913aae28b2be53f83695c9c6c5522b1e42becef728eee1fee31fdef22bfc8daefc6c7a935d1801acc1d0cc54e66086446bb1178806e7cf9bcb1bf66266c4310380f016a3fa94d37ee38c9146ea2452dae99a9f85bcc4d71f762862d0e48285d84baadcdc58aa4bf7190406cd1a4106a3cb093f58d47a11528cf0aa0590da1feb5637c54f407d8a977a2bd8f7b498d813b5f4dbaf1fd158d306be4ce8294467a283cc4041bf55f5a8a159d5ded6c1cfa9ae518be83dbf873ef4bd58d17e01b8d7f007a467ffefc37c3ce6a0124f5f909b23495313541132b7bbb1d06b20c0cda56acb1fe1bb8954da5d02fc77177ca31340536676ffcd22b577b2d3fb92c06c3caa1529198638b2a4541fac6b1759a05488207ca617782d9d7dc57f986ce290497533db1cf2584e78157f9fb6cebda12ebeb92d928ee6770a9e6244ba0708059a41bace83666f7c63ea90f7006e63e38f66f8846d710c5f99faafdb3bde142784b5c152f077938587bc32ef849d97f4b35d6157719bb5769c73be09163fb3ec5a83b9c4422c88cd8f26122d32659b51c818dd714ae4e7ce881ab52fc67de101fc678464dc4a73cd06db2af85788752861983bb134d0235dc1cb88c0b9174d9a1f8d2c13fd28dc069ade5233c1b5ccef1a17a525375d9347bff1c9e5d8f43b4f4ed7d3da6ea2fd06ec8c6f086418ec7e0091a4a704771130e569fcc5d6e521677c7211a8f6042b54538c177e8897120ce29c5424c371aa269e36c8463df31aa980c1798ec09bac1b48ddc4837b0742363cf33fa884333e625502c713bd751794691409f6ad880c0210ecc570212edcca2db1ef7f2ae00328bf198e783439ccfa4d8f737d65d614a1227da0218ce07692b6613f2963e4f508dea5909195aca8b6bf1440cbfda7bb48fc4ef7c2308988da2ef31a4ef9418dff3c1ace94fe5021182950b247d3e1776eaba3cb86f3de97fedc8d1c32db0d39aaf7707a62c2f9d6ee7920586988682200438b0c902f51b2cbba8d55b90c7ca05405458d9d7f57cc340a89ea3e3f0e99d423bf6e1b9ad5b5e6b574c82c30ff95080132446477052e7e011aead81f393682a7b22dac234294ce484e24ad203e0617f03af7682b075d3d9d320bd399d2ef86f5944d6f5fd909c68e05e99b34d6adc1a8af65a429e61e9f44e2d1049690a2134be5fcc79370b62efeb19867c55e92ef7bde37f5abac87d5f16c6697589a74eded8010ccd55bffa2109727cb561b408b1ed5f4ef11cab817b57dd3cfc1221eae71c00888e03e0209547548263069849dece4fc5de39268174f71d280cb899667f4644fc6eaaed86935ffcfee2660b08f7a05187dd596a8348f9c15003298783c950191e5eb872e9e57a8c47c3050fd07c8b32499dc241764ba1ac17079f419031b9f1a56ec285456b4138a810541e471c532cc600ca31bc6eb7cfafc52f3f4231ab87e8f067dc71f0e876a1514832820c30409bdb8537a17fc0703eed63fd7302ac8bb7e8188ed8046b41819884e3760a97c9a0ccfac50fb3a67b70ecc9ce79ba7a50ad100e6d59d33fb68fdbb381d22f7e7eb83988daea692cbd510e4a7a2de17b5957cb3e20c78ba797d7fbf3136a7912f77d76425fa3d69b8b67048ed3821cb8ea92d195a4154ab9f03cee48bc9cf817076c745115e0cf257610586fb9e7eb43a0cd65a108c3851504bab21fed3565d3486f91e9c46d5780aac4e2c9aa298a59413060b0fb32105629ca32329a44d521e7473377272f8daa2be3917a2dab3a622624ae5f7d99388b603d32b68e21bbef985f70e28f0fad7ab3136b8090bb77442aba9dba62804a2d39cc85bf01121c9233faeea984e0139583d42aedee69428755a9e3096455c171ab3281d4c98055355c22705636ac4d690996b1d577fc308757414d32ab5d67e27bb6402d9297d4339b653d206b8c9d1baed4798549a7448e9ed21e1cd05c4ea485963ad7a54ef0200bf8801b732ff552ecb70b17cda0976fb3dcee42cef965696d289c9027aab62421e5688de0e6167348625a16aad29dd09318f0df52da6eb7769caa76d35fb52b274ed3f81724e0ea3c17634c869e36eb58696165cf851d67693640e3f0625b63259a631fb3b9f80a04aa0aabae12f995792437b99ba7901fadf9fe4d9f0c6417ffe65ed25af91f770f7c18c4d2e2dc940e66f40538aad8313126bffd06244ac07bf360ce5ae60c9b6b147b93195115f0af689581d2ebbf110a0517f6a4df10620dd3169dc5fcee797371419a2565f02fdea037bd0390848e6f17a01730f9bc6d373c58349ebf2590ed0c2d87c2b25859ccdeb8266606b5f17b4fb83747f716f242c6f8c07b1fe472a74bdac516806ac4dc097f7a8346937b2dd104c4b74ed962a9adf7e01cda4978c2af433e69e37dbef5c8a6034fcd3553453401b0bbdf33cc75eb6abca36ba534b3b826af0eaf3b58dc41a1102befbbe3c9852d8339b9363851155cd0bab8280e4fdccc2ff2d058fb9fa271a041dbdf79f7501b965f90391ba6380718dfa5b51637d2b4f101fd2a0601c7e83d0adc98a139a1d5ee9744454c36ca3bc06e422b1cc22ecfdaa137dc51ae7b09a6339ce7acac52b57ccf7c67c2a2e3998b9f5d04194e412475d7bd400585fdb08baec85623dd7b71c3c305d375f22221b29f3ac24fc1c93a972eb299f734230ce8390af762f3c15356df1ca9803cdc9d1d13b415a8e4affcf3925c02a65783ffaa6e811a32e60eb62165ac7245f565d53b039d7302a0597b8778431b263a6b18fd633e8797ec54a47d9df56b6fc40b7816f5332e42fef811368c0459704db0450f7ca3ffdc55e5d80338cf1fd3303beed470d2ba5a2046a688115d91e1ca103c694016880546c477be01c67d23a1b279252a98a7959b74dd1a1c948c770412ac48fa8d8f1d92f3415b190121ee20b7940191feb711e61257bbcd2f11a84f8836707f90a04ee447186f52f670fe8c3512f3f6beeabdc9661bcde4cedd9b86374732d1f8276c702e28a56dfd95218218679947d8b54baca6d549fa93596abf08d73dc7d5028e560045ecd25dd0745c7466e015ffe08bdfd13f84abaa938eeb3b0bcb6a2338e485e4bced911c38c2f7352db289bdab1ae2a9a986f29788518d50aeb233f5f15c357499b264e66fd84c0df65e641d078942f92c265ccfb7eb2cbd6cb9370494f1c44c9c3d96aa4a54e5aad72fa7a7f6070ca9d0947658f1e467de66296750535a19201aae112197b318e8e57cdf03cb657677c4ce871b9f8b4e2e223bb50954a999f66618f71fea25174d9d7cd6e47803f127829771800a94dc1b47f93b92f26ed74226da9654d2e5ea9264f0474d537eae778a8107c3bd580a3280f9005ada51181a055545e7011431957ed7c514a265cd103e2effe3ecd0d930920b55c3b2d32f223f6467d4dec47494c29c500a6743afacef7dc23d93c6ccc4cd5867d12119a157e032535d02ffde24936adba64af2709710d81a7f4768059db1a3af21f8bcde0905ba17a90dd4c3c965f3b113d379bd3c8a32efeca074012aa90c1b66c9bdd95788abfc83b1818370569e4a7622de395add87d09b01b863df011daed74695d66706c72ff8b02ac607de56f3c005fe3b0bbf6a6938deb7210c496cad68209e9306cc48af64de7eaed44a3c8e3254846addf001bc918348a51fca426ea3d20da72c64dabd62f63f0cde8a0c26d3f5eb54042d593b7c0758f9e6c401925b3fcf367f1b93ef1cd95b5c202b4d91fc6e83965286ef6b85a6262643a031c361412ed2159881c8366a5fccbeb6037f7d82adb8a35534c82570905a40bcddb787bf64c998a8a313ea47941d10045722f28808c593255dd39279605727a00773f4a6bbd1f21bd3a83b0d3f461416c842b24bfc8c2ae206a83777280153913373d1b063b6c26964e8559ec9a19957ac35562bf9e31b84d03f37267aafea80cb7a234c2173606818c6662a14c50478066836df275f97c0b922c2a2256b2d5e0d226149c536ea00e79adff708e7938ebcf447ab3a783413e9538f534560b817706de2529d730f2c9e20a5e124fc31f3aff0a99d061ecd480b196916fb9556b504295e5aa7ac0b1a65ead5f0acc284107350fa47b29189fadb46aedcdaa254fa223fb58a06988387efb783c3d49bbc1e13bf898b63d1d83060a480ffde6b314e236495061228172543388364847af127e3cc2951b6a4ede1b29d55209a76f5e845ceaacfc94c2da4a3e6f06f65f1c7087b05412eabcd53b9924a148f1fe206646a4df44de3b8218a31a44c78e89fc0472720085e4d79df044da364fa2bc5d8f1cab38ed2e2c466d1623dfa0c071bb65b59fc8d0859a2c1700227b34def10f04a9e05e92047065b416f272d8f71292ad9bb4e6fe59b7b8f2e1419541d8b80d90f82b5aec0e44568d3bdb077178049e0da79f3a50b242aa52f92bf876a339a234753075dcef88d35a2a5d0c1c72e9dd7c4c0b885cc4726ff53c27f39ac164cfb2398b4f42cde4ba1069d7753a7a9e16aa6f43e7e8fcbc9c39ce94a9f20b20a0f9772f4a07b01b41d669341cf838f27c2012a45c5e3cd08bdc1a473cb2f485afc4b94dd3652834160e28dda50fd2bdae481fc92dede88363d52fd4306dadff99a5f76732aa0ebab8e88fac89acd94b366a334188a093a34f045be831e511a42f3733bb10b7cefb79bd3c14da0f65902326e6ea77669a2a1c89a959767fec3370953a0149840fefab36c52ff457a925cb29dbb42335c99b083f7f2509245d95b5017111533d5f43dd8e7e7328bc3b52490eeffddda87241355c4696235c2db09cc72efb2b394455b75875f1a94dda246a800da6f84716508e3f9d2f6c5baa9bafd7995ddb85e0b14fa4dad06fd2642d425dd101bd74241db113efec586978764f022389e8934a699207a43a96357cc43af63b7f4c966c90b6ac3f59ecd5a8e47f2db758f1563768b4e200f6ddbc896e735e7fce17079b39cc7dbee73e6ac75cc547798bad63974f905d336e7fdf434bcd76dd4f8ae8f297b4257097c197eff10f051b9b70a3bef23ae822be9f8fb702eb56b1c6089b3ba33eb443920bfa7efa5443c572cc7bb5ff6dcceee64b92c656ea68583d130ea19d098645f72ad84e331699c493a5da10e41b05d404f8edd2ec06ffd367bb665812f081891594cf591bdec166ccfab2e99632ac67a4adc63e4587bc22377c99bb5cd3e462307f7c867dbf76f800cc24d64e5f6508fc4bda598e94fbe854adeb21603d79afa80cf60a666409209aca231b43eb85d27f9b1f37cb020ea4432dd8461c41428774fbd45bca075cb357ef61e8e940c869e3daa278d1f521ae8e7300cd43756871cd990a9808862d763e1710c7c710575ecfaac888081899557d937c34b642183102647b6591aad3d6e589349c9913d2e904458258d8e9e42ae808c6ee0b552393f06495cd44047bce30ff510613f367b24e3296eaa9e7dd2f96eb720bf611981e4c6dfd21246339f800a08e23c4214cffe8b050862ffbeac03a4124d89ab933475bb33a3d5602f21f735491093f0fca214e398d1b216fcd58bb46060f37f3530ceaf846f840603765f451a8598594264191e68de3e2e26edcaeb217f683a91d05eb76ca8eead8c9679ad29b2562478901fa94d2923c0419b10846ef60c7b27eccdd3289f403c80dbfbd214077f21747f0877d2da931bf43200be39e977ab51c5c6a17d938155c79d04121548f96b1b78f564fce82ef17957866d2191bdf7e9f53ab60fe9309842ee58280229ec875422f055f78459d9ae70322c2785f901ab154d759634985256dde8696ee5d87204fddba16297173ca09bc4da18b6f106fee8e58e53a57cad23187de465d780f467dcdef8ce10c6fd98471712920919687445b09803f93ce4bc73a1f1a9d376520222587c435e18736b096fe519f40b544df44960963b96ab48541ac0045373dbdff7cf1c294462b5326b12dde2d2306c448f150f485c3dce4bc766e9da2043e73fcf8d2c27e0b18defd81d31c38e2105af100b101379613c51b49f3d318849e96a42dbf5b2c21c1d25ad9e212055148df3b51f05412ddf0d5e666efa0e478b8d06ba10bc80fdc4532297bd29dc5e38b754c2aa118c7a1fabb60544b087cd02587862eb1ff2c03384f478d82f89b276fa4f47c02400e6e31877fa27d7d7f52fc0933f3033fa5928fb06294e1df961a3cc332de3c24cb8f23611b565106808054344333fece06fc4085373e3abf85108d83aecd78985bb91d8774f61d43ca17a2f7e38769c5e008c102b5a5879d27050894d3315aab128315e3652b51b3c9304d258a42d7bd5dca76323f6a3d6044a4389e786064f03c38558d352c8d5ee1013f7642288d1fb152ab9274183b5d2126ff6cac7f30b199ed274d6c70c6b222606aff24feb647dbd0bb578f5fa5ad6433ec9dc86038b21712f0e4bf19af28ff1c6eeff3da2681d20357ed5468f6afa6d7e5526ca3172c9072ed177172992ea760f01161fad206473a2ab071981341f10bb91e5f84adb5767e2b984662e05b2284b7486922f49b1f20d97749775f12ba7127001cf0ca8af147d986fa5db0798a9dde355198c7b7e7360967e29e5f7a2962fad52631ce4fd2906ae1714bfedc0be07371ff4dcd9e1a5b7e627076885dd075d4fad077d08978514e39ede18fed677db5d416579f73f9f483777fb17791fe4ded4485101d39809cfd31c37ae8a29ec1491f4c47f73b29256e3e9504a9d4bf8aef37dbeb0d00cef6d62213b4b370a3b5a0436e2bc91dc85f948f6a3cd67bc02757e3981c7d2294c20b3b8c785a3b93cbe7b145317efac114c1068f09b27c547e6f04f2321f3eb4665279afcae6789c957b3f3182ad6c186d9e993c4d2e3a63724778192905e4ff6613d2b57bebfd33ca1a4fce03e723063258c60d051aed599d3326667965cc62f66f5579aafe64cd257ecba5119ea6806136fb6612f649b2f5c705908e0a44d1ff55df651ddfd0ca23290be6f04820f7df006b542bafde29db376622120c9885e16875143adb344ef6a9e06f4985c74df4bce5ed9d4ebcc82bdcdbd2a301df2dc0dff01c14f4649d5ff939212f5037e5c08018a430d02818f31974be9e5f8c887cc177a51fe69bb78e73e1a9ff4de9cc704ca4f9aa5d4e4caaa3e0e82d8d2ea91119e60b00fe2eeecbeaf9abe9b6f174491cf4cdd1b62c97cbb7fce4dd8cae668d6270e8fc9a2ac86b57f10904d966d9b1cdcfc7ae28c22ee35f463df412151044b6396427126b134f1187667e9c9b03308bd32cc88335566df43eed5bac514a4e3c175782a4bac2ee77ed8b729fc69204bb114a58f39787d862dd76f72b5f4580b5ead94836befb504d45c8bdef127baf7837d0215710f6384b86949716cc4864ada8b4f0bfb8b09d26bd7da9e3af15bbe066d9ed9cd6570b61eb08fdc4472b9f83796471138279e944fc70d0153bd0e6ecca1335c67f5380e35d4980bfdcfe41f9f58b7dccff5cb7948b20efdf5ea04fbe18219e81eaabb9fc63734bba2fa56ac00570f4e990abdd696ae2e3227b0fb3ee4e7e0a11744f9437adf603af968ec036f597ba185e9a08d3fd206ea229e564d07500a95e7381cc961315ae34657dc833fa80c08afcde7e114b0cc7274e4e78cafe5cd9a05761b9e7275892f06bde73d56db59719b6f10238e625368825137b3290e9b6f902327402bb19b913a1be57f56b86df7140aa81605246638828c32a41574b973824789eed926afa25c2dc9917426e2d6cb520fd107ea1078f54ae9213d5cfadcd3932597db9c08beaf3e889d4fa61cc1bdf303a7734c144e6334bde936e7c5e869d87c14b57e1e6af74cf5d6ea389b73c7ccba49e32b9b1e0998644047b6497bd4647b7abd1a2b7620656c39daf6ca45ac25857b215f341b57d4cae357ec80630262ac783dab7e6342f4d15a58ece676e5a30604904a6aa06f03e46857d3f631137a2503c459032a7e8e805c30d659491bd6476d36a53e30432a746064503d35ec74a6bf46fbacf987d35da8718069a337ee22846add30225dcf271b3faecdeca1ccdce77ded1b5a40c301542c60f29e511665f5ffd09b78154d6c5d476b9b88904d24b2bbbb7b076d08fc077b0744d0268e34c1441349ae0ba0407975c87b481994dad04967a7c188f1dcbe1a7a7d01d8b86fd5394010b780c295de837eec71eb174c1dd339ee635a87006064d9cce8563fd33a04d0a97dd1b144cdd8407bff76b8f2930bb6d797bdf2af029d9ebeb2c0c361890e23d18d2ac73875accc9da923adc4c933554e5a4ea0b49c14110d4929a79c52d26a2fa6184f19b1b417631263599659d6f446b76dcab845a949bd719aec3627f0b996ec3ee94476252216cac2326564913f728824f22387c8221248fa2051a98244c54ad2110b491216122743427115796290b88a3c7148f4892a098b2a3c8a52ce49698d724e4a6bb5b45a7b2fc6d8c5189665396b59d634adb78dd35adcb4c8c51dbb2f850e234b0b6d699932b6b0b4b8b8985278e95a527059e14b0127caee45e3c40e436160a68c30261c65e43269852d5c4574a00c04e1faa1b35c4180b8880001072a1c21021f29e222e1460b38e8d11606d862954ec9bad142eb88b440ec0fb69ed8396c23ec2a5b0845767087ae561116b4866c1dba5a3cd14a4e8264a2c83d120211d7a14b08435408424208eaf1b52a842227176c053a3ec10cf6aa7f314960420b26b2c8a115830584000475b1c0c2114626951b00d549e5063f64031801c2144392a0f8210a252daef8a1c8094058810e4f381285e71563dd688109284c181d651823803e6bc81a78c77ebedd0d1fd0d1d1d1c1613f532865942fdb7c1c77cb1909882af49842876fd3a7c699e953e7d0e4471a2396a8191dd2e7409f2b1011041f0a044105270061e458441012466ad00155bed162c7d7820004218d1b27187184099c24c5d7a213253de20b141184c44dd2f3b06dff70108a9840d2a30d1bf08bd1341a6d48ff686878fa57d33fcc4491fe21a03771f384d68d09af94b2284af9cf842e1fcbe8d0e5a4e524a875440c6e90c10ff90433b8f9912ac2e5848912176c27495c4e7a10a79db556d5a641132070682284da264049f98bdd8d111bde18b1e14beea3ff9c734a89d17972615aa043f92486da9a73a658b084871896a880dc69812b76b6051396903a81d14b0951144a845aa0c4c80a94106955990e5d4b585da87f2b50a49ba31d1f721f10c28fca8ff65297b44be9d221a733524a29d7115de24947ec127eb1df7b71374286ecf596a7cc1dc4a1fd781c2cc804444a33168ccc596bd6add065b2cf293becac4eeb59b7a3c950bf07eef773ec768c582376fe0d69847ebedd08708f8ffd08623af61726eab8d1120cb4c336eb208edcd5c84f0fb19e3b8cfbec225627d735d329f1b511db62bf9d76194b4a29a553ea1418e1441599bce612492c4c50263ba85b153633c2d59e60ac0996b132db9728a22d118476e9d0b5840e5b4b87ae265a34c162377995e2671625432d1a0d5ce26713131d5eb62b305a16315915325887aea1d7cc4b87aea1d3d00d34d7d0102e86820ced7453872e259200237e7e97124f946862ead0d56407319a145123d3a14b891f32627afc0c00dda16b091401582225000090511383770fe3858bd2b6d9ee0ef9e6c8773d7690fed1601528d9e9f179e4d8b33a27d6b394524668b34169d3a4079998988fa17917c4f4a044500b9478010f4cae9c78f28f069ce0832d74c0e1093f30f141832194f0003d690152528cd2ca499da8780800132a7a000093570e326eb44053446c960e5d4c98b8c164073dc458a20a6e0414744f78be0910184bb05ee8e0878b223d344b049182d3123a0499d1a207192c7862627ebe7a606eb400594d5aab9798a72c1c3141a27f9045031e17263fb430d161c572a5a79405cfae0205dc0bc8d64488bec10ab4a12154908782ec9025018b4287273b3401b28315b89a14c1e352e2870f58f840a1836b8914d512a00ed3a1cb890f2e265acc40c2c89b33a8084537434cb91982851124a9d209d0a12b49928abb2883706743883d1fced0eaf6ad087e6a50bc42c4dd0831842575ecb30b08472e200c61f9ace5e55f64def42e315ade3afdb9e3e26b40e0e9dac358d15c4950498227899d3e9f6adcb67dde3eefd29679bd65fe86d476d6affdb6bdd50ec8cf9d4aaff1ef8413af70fc3b95b88e78a56ffecdd0eadc7f33b4baf6b0cfd0da5f750bb1cbbcd67dda6b6e4388ad711e3588fee63932af790e4c4993f9cc611e7e8c8b06f3d2f2f535fe995c5cb296cf5ab2962cdb72966d2d59966d39d35832cec2f259c792715cc671f5b9c71997e1cf6e84c030579223ae242a0cc3302c3ee64aa2a8635ae9b5dfb4dfbeb4fdfc1b73c3302c6a1caddb3fb5df3af47f3528736cf7db7d35e89ba155837cc0444d4a86359f8b559771d21a67b597e298ee436a2fc6329a6553c6acda18238c3a94d68bb12cd39ca78cd9befcdc97168ccec5b2ac693d65d42c8d63d26e8c31c2086f8cd8caa7cbcf418674f99a8f26d2e56f3f1ce5b82923b7d238a65e5943499c0cb14c504c2d168e49dfcf52332599aa98ac9892a209e97bd9d13121c51f202245807e8e04fd44ec5f885ea0bc14bd10bdb4e88bd1cb8bf297968e6a8747a51364451feaf9394a3927a59896695bc31a06a34d18058a0e7fbe620c78e8f0e72a32e1071d623289123ac4b387203afcf813450cf0c63e84a71fcc2c61660819283238c4e000868abf93d24d6b0f678d19f9e9075dbe9d73ce2ca1cbaf599637ad65999b19a2cbc7b04d6b589681d2e5532e8343ecf35e2d6777c6e0a0cb97d65a6b2d0c15b1babc6082648bc562b158acd56ab55aadba7c9797cbcbe5e5f27279b9bc768985a5a5c5057f7631bdd0979729e30ba6b1b4d2b424c192050b91d2104a3f60942ebfe62c7f78e8f2698629a574b624c19245976f5988c8d2104a3f764bfe000509b1867e582c168bd5daaddddaadddda2de8a2419349832f104683d6853661ecdd06ee884d8a2d88561263d0e5d34c6b996e1bbafc89d1989867714774f912e70cf3c93729baac5acee616442bd12ba424a9a35afd98904c482624139209c984d4e5eb955ee9955ee9955e6933790979880c4adb5f9e739f7b4ec3a0c9fbfaa5c6526e58fb80f1d5f7a5d6589debaea9e3aa24e9bf6f7517f74f98c7dca754190ff61535ce8bcef990f160ed9758f297e2a67feb89de7c9ebf1e74c6061019cfc19e0b8ada01a5d7fc8b18c7f9d0ed971d717f5ffb1955577d31a86b0fd3bd741a73380ab73955c7bfdd544faa27a54af5d8d48a439236f6b38eab226decc721a57a5c7eb6843902abd3cf424628f24aea2b74e87a0d75230c29020f455debf5e37b432e2988f40474e88a824a8f0249b7e9d01545901e85939ebbe6f974dcf3a679abacc61863dc3e7a59e360f5ad10cf27d3392acc8fbd8bfc70d6a8413230a6969226adb5f97bc89cf835f4bab50bb3636bed6b12f39cba350c19fe5c3f7ecd40b00601ab0f524a5c1f6a8d3ba07ead41967f3bf22fa6d6a0ca3fda7dbbfba0a186a87d26e8f535ee11e939fa6be8b5fb668fdd85c63d1c1f736f087eabb9e039f8350c2fdeca5a5f68fc9e4f6ff9af02c1af4060fdaa82372fbe72aaf1ebff78d817b4e5271811672f2ee6f7e9691ce0427c6f2551f2ed7b41a257df72d96bb55f0ff9793e1acfb1af3f6b18b42867f6c7bcd0bc4b7e99eb671aff22a661d06a7d9afaa7fabb3e577394d91bea60741b898d5df3d7af9fbbf837e60bd85d74dad374a76e771df456d94b867f3886c3f06fbf7013ff625c780bff60b0e46a79d4c8527aa9716ccf5eb3c69ed92bab2a5149e2c7726ee9bfd243fd422cf113fefab1af660d1b8e7fd8c62666af3acd2afb557ffdecb7aeaa348ef6399a7f4f350c5ad7de66d6a840809408c207ca03ff78548d7f21f0d1ed676fe509891ef47cfa16da48b650a7967b42a20ad54413659c8821b6e494d55a6bb4b3d82d6badb5d65a6ba9ecac0a13884e20a484edc3cfa662b79e40d2c95fec32ab53ce70c19675524a3569eb97c07ea9535aa9853df69710c0e876a6db986e615e14d0338665a85e6567eab45216728fb647dae3ec02e8794a1967b6c5e71d6a1d19c59a1c40c7b20340c71de3189d77d8a4e73ca78c31c60873b6cd4fa25fad23eb184b8b558ae11653ac38d19a82c594d71429535c53964ce1c194235fccce96b2c594266011a7bce41429738a6bca121e4c39d2c3942114f3c829278898942d7adcc15e6ba5d820059814a014e0225b8a0d3f2c147edc68c1da2a39c4bcb5d65a6badb5d65a6badb5d65a18ec0fb27ad8529c4899424a51ff56d002762b4416668dece1c4d8eba8753bf97f601c3b46e6c5af7dee220eacc35d8434eecf4e421af763d7afc4a18d00cfaed471f71d5441beed62c000c01972c6a7429770865cc0bfa50f2bee28a411f3ad5dc470601c1747c65aee2c8e8a23675aee288e9cb5dc4d1c59bb5ab64117dced9eb186753771e44cd39dc491738432d38d6e2e7246d453424d37dd6538b4ac35bd652eef08e5a61bfdace76ecb2e77db516913b9ec622c1dfb504410122c3d8825237207a00e5d4ef8f4b9828e75c0b3c70955b781d2daa16b8a1521b2b77ae2f544eb0916920e5d4f14792208f984cf7c224887ae2776fad77558b445519522a322a2a221a1688b80260c341f6e0df2e1a21f5ad14e872e27aa3841c58915a61071820804f14aa730c85e8f0da400f56ce892e223650729394c293650281055b144585ca223ec4054d4a18bc849efd045d40322a11e77874440fda344437a7c8ae12b93c81e4f8c73ce39618c4872b0ba9456747a7d796447561e8cf1c517637c31c6f8628cf1c517637cf195b4da4bedc518c6b28cb59ad5ace94cab9aae9a56bb2feed4fadbce0625aa6afdbdb55abf246db5d5566c6b8dadb6625bbf7eec2149109144271f6040972f19305b883c35861b318834f2e15304a9f8f8f97cacba8c52ce49698d724e4a6bb5b45a7b2fc6d8c5189665396b59d634adb78dc3d7765f0d4696e334bb6da9a459167c6bf7ad504d26adbebc681506e38e65855ebfc5a8d77739c2dd97028e49c3dd67a3d77fa901a9cb7bbf1a5ebdd620d4e57f71a8174048d4894205baa2587111f1c42fc268071f7420c40db6d89982a7095454d1c288ec83285644b98215a54914564d9c3a58e707082b66800d38a000c8106e5022ca0b7c40c41278d0041e9ac880aa2ec6517ea23c20c39ac96f5cb0bfdaea998e8672525a390c69d0a755870d0efd12b4810f75b8481bf8dc739be7da411a50c7b083030e55eb889006cd58b33a077dfc19c3b29cb5ec6a08b03067d08799c6c93af7396b5143808bd17404740efaf9a7e6b8fddc2e614803624803af90354ed6f7674d8b1a027b6b1d013c67c0fd79d3a6ce41f77e4de370bf39ae23c3b40e9ae19bd96c2b3d0b879006fd12ff44d03787dce3ce6dfc66c8ce897f636a8975f8598775b8bb954fdeea30868f52cc82305d4480d2a16b08500ad0a16b083f7dcb107bbed98d0ffb5ed38f96d9d0e7df8e6b411ad5868aabe55c7d7e66bac2bf6a4397913e0cf2f482845d6a1da6ceb5208dc965fba745316cfff4f9f8f6cffee9851cfc9d5ce8d8e905fcd8633ce7f2aac34f2ef4fbb0736a428a22df0cd9f4e1674e86fa33ea9b1f76fd793364cb9b211a07d2188b80f1c205cd69462606e6c5e4628b5a584a9b12e136ade50cc348aead14ca191c89b28aa2ead04584a44e042510c14802743f7639020a0fa01c8192040a0cfa075b46a008a902ca0a0acf4e112b7c9e2ca17f31503c8142c81329373c69e249107080b2b3458458dacc19f91412b11f35354f7cd06f0d1146f4e019e4709f08a1b23544dcfb8405fdd610f1a4873ec10108035a98e2898e951ddba1eb8912190a127ed4103185eade7b59b062d70e5d4dbc9eb8a1892c6810b11f35354d0cd1efac21a28916f45b43040afaad21a2899d9a2c2c2c92857bcd229fd32f75a954fadc95a494527a3bd8f8f5a63fbe765d01c5750590969cab0a2b3d7b4d73dcf6bafb78549ffe692fe54bc941c9bfa8bbfd53fbc84fff7da97548d9a1a783bd6ddfb7eed39c47f5f139f2f961820b2088573aa7235ef94df10860f40a04475ef83be09cf1b4de5a55381107b640a59014924252480a492129e4803be79c73524a29a5b5d65aadb5f6de8bb190f484e4e4736a1d35481f5566377837f08e701e0e788c31c60883a9cf979452ca3be79cd3524a69ad15beb5d3c38187831d1fba203975c1f2aa43e7eb70d1290daaf13a21bf84120565d63ab23c3fd22d2bc66901762d7badbbfa0481d26fbfa3c4339e3df7f96ef66fc8fa9aaeaa9e7947ec8c7fd863b9cb78545e5590c6dcaa4f9f40fafc1aa88f4cce23f85049b1a73cb5c258d7434581523ca99e8c950d654173c67c9b25e9f36f26d42b500d80523d35c85a545a1bf22a48a2229594c3ebf9489b4b65a434d2ceca2ed6ac93557dfe0d9977faf48cb8c81a34fc781c9e907880f8f337af39acad4676a515e755918ae4f3d52155356b6c3106630d138939c87621627fb5b55bb3460d0a6a05b5825a42ec1cfc15071d91284c08092bc9109652fd645d2502f44344a2322018d04a84d65410186cfbb1fe007942ec186fc5329aa57a52ab1651500b4a51aa274ba9b254cfeb0ee3987f511593eaa94819d2fc1a2451541ee931f21839a443c01ef38d1ed0fe2ad27c8c9190bc20760ef635d716942289ca2f89aaa878c43f1ff7a1ced15bbd403bc66fcc9a44da0cd521899290566f085a87f4f85e0cb6fd2189faa217c48e56240ad3b13b12a59228ec82d6bfd83f4f485401e33ea068cdaf491549a2a00b8aa13ebf5691a858adf4f9517b42a20a913e0cb5d748ebccb7ed2a1322e288816282d83e60ab3367d8c7da638e7d604f88e71329f6843c52b7415091a8b7bf8f24ea771589c23cbe240a49a29224eab791f5841475fb5e14fbab42dd3ed44e2c7ce33c1d95deeacc1a3968ceb06ff18ed9ffc1b016a8db123ff90461d86ffec1e0f8178305a9884c479086fd132bc3e8f927ff60e4cbbf0d4fac6e4f47ddbec7846dffdbafdc7da62abafdecdbaf6e4f3e746b751e69cb61ce39affd7b398ec316637cb77b31c6b82785b19df7de7931c6f8ce0923a8c7fb75ef48948e44ddcd235138b5e292244ab55712f59c9578314ed2e37b50ecaf6e333238e96c1d7e25f4982d6bc6076a1d2f3afe1b328a126458d97f79c8a43367c4dff9bf1919b800411af1a4d3e37b59ecf81f97d4677e4c2a17199856323fe8f1084650cec10c62ce7a7fce39a727c49362c71823fd0ac3bdf70af17ca8ce71abcd6123bd9e8f44dd6bb12724466fe509c1d99027c5ae9e8f27a4bead1912ae42deabb57ea8b5fe942ad2dfb66df22f760dc3be34d6578f31474a95e2b13687a53ac78c114a944ea9523c30b592289bbb4ea960e784e60cac6dff5519748cffd5f1674f889d63bf76fc485440e9596a58a270dc3112851f738c33d49ed1b6ff65413a5e50fc1c13db652a9874fcd3da68ff45871a47bf7dc19bfbf8b7ce06101b52d1e76336cb3428a8e3c7d5676a1dfa617416bc8141599dee3469833956c79fbb6f77fa838e1f0bea98db10624f1a78b7f4aded5e9ad498e839e7dcaab49b94deca0b223d2259e334ed3729e5a66d766aa9bd0ef28478423c215628a7861eebad75abbf5d7c2d967da66d9bb67d8a273524276b5af65a7b9d452ee7d7369d7d53975e6f9afe52b7b38f87a6cd2d6bafb596c98c43aca310f3ef5ade3779896cba6ddb56e9bdb75efcdbf57c3c1f4fc86fb3446910ba7da9cbe12ee577fbd2fdd24629c7fda5a5cbb7ba9f7f21f0f1d5cdb7a7ef09e13a4f485461f38478423c215cbc3924e902e8d045854fa742d5230f1dbaa6a8421f3fcc258ee3b89c2f7b1b63bdf86ffd1eb25b9c7fc686101956f5df90a99e3bf773a512572addcfd9389612e7b8cdfdbe250e82d94b5f0d3d27c2b03df73764e97bc81eb9df746f0e4469bf4b4b867df6b95ae25f087c7c56a873bfe3873bcd5f7feb387c21f7ccbf0ce32e7ff3759136d156ae71f26631f5fc9be2b9fadeabf5d5fade8b69fdf752ad756a75b5d6586774465fec3ea6f9966efebb71ad69f9de8cf7a01d4bf5acee15a3a339edf79079ce298cba013a744d1134e77c29679f1304b34bea83861abcd594f369ec608c543e1d42239de2c728c90610db669923f917b39c61d745ab41968a154ead28c613538c53ab2cb5c218e3c71ece1a1bce19cfd26955cfcf7dbab46d97ed6319c7523da99e544faa67b5497b83144552d4583bbf23ea07e8d06544a4c7fe45fe490dd7f915de2e0704344cedc2ecb546f8d1de437ed1a74fa3203d001dbaa4a0d2f3d5ec85f7670dea19ffc9713e1f3918ffe29cf527cf8937f7cabff8747289456ac59662a5562e3fdd7ed6b487f9978ffcabfcf22f6a8d936ffc942ad5935a659de346fdf95bf45720125562c915487d71dce55243ba9ced6be811b77cc638a54af1702d2e8fff86bcd99bde857fb26f6fe2a955bff4bb37c6c8f19cecb78fdcbc57dfc7fa3e4e0de99fc6b793997e0e3ff7a534e65e63fea5565dbfccb0cca494327e3166596ab15b97ed3ee65fcc9ee327d3eb977ff9e7c2fd944aa2e4e34ff144ef3ee6dcfd2fb54aadb6c6099ee7799e943e7e8e9092f0935a61b183842c1280042324245804394589692c7d4c63a9b57cc634b1bf4a1445038c86e66580b499fb28e986b499bb481aedcb6d48f9f28cb0bfad7348ae499b1a9b6813491494f6b5a9b4919456a1d401f73ff9564e18ee7f37543e5dfe0b1afb7213cd18dd87bf1de33d91d248a264d1ab52a948336af8c58baf3ac70b1a1a1a1a3b338331a639c28c6950e3e4af12e5cfb448538d728e35319ecedf3af9b5755e7c628c18cff9d77c0da7a1e6797e55226a7afdeced7b7951f5d9f233432f3e2f435e7e5e88bca8f44fad6241a2287f4ae98d41344f3f22a1d4f492a88f0593914451131589ea7e726f52cdd726da451245f3f3f76b1bf9bc788ce7bf23c673fe316a3ec6c7e034c4f81aaa6352411a73fff7e243d3eda2dbedd736923652ebe6ada617bc913fdf74346bc4807918f3dfec2f0fa729e65f384df7f9e8349faff63438c6f842ca1793a6b341637427f9fc637c4d778200ff187f927c07ff18a71d35326864d474313ade51ce42cc5e9046c63b4ce7d845d2663ea6379111fbab4432ff6da22e331367f6cc9d99a1f94d3423fff0befc8bc12f5ee47061ed7d1a1811c68bbf2f9e76df07fa0b9677d1953ed339581e3f4df7d9747ceabeeaa392e9b4eeab4060baaffe00f9ea8fcb8bcf8b4f89e823ea26a33ee76754d3b1678c6213a39bbd17d680a71f18925f69e5a9bd27f6a7cd54a059a30a5596c4da738f83feed4d6044be09b4e7feeadffe6acffd0eed39be43ff46a3ce8131fe9ac9a00f744af10402c08afea7499a81bf9ff367195f731a3a0d9d86628d8cc75e5a128629697b69c5aefb1dff9d8cffaff99f41daa40663c6d37ffff2d9ba1876647ccd67af08f62df01fe32dd03d7f1318d951f3fc4d20839fe6c7f8ff186f821a7eb21c0231feff34f98e187fdaf1dd738e7d963651e7a82aef883da5dc7c74d96941df07baf637a696e1fdec973f99923a6df957b9fc89e854747a9d8c4c49a6a7a6a40c6c007b3c6bfc6398c4b089611f8f44242955aa07937124511f7cc9a02251988c2a12f5e229cccb88f97f693f31a5272256970fbbffdfd1fdff4bce77f0efbee33474cfb90f1c72c2fcf7d292b1823468cc7f27a27f491bfa5af7467ff454a48d8c2319482efe9b7d4686e667302c4fed4537adb516d37803d206c32437b54c44f389cdf2a616bc914fdf44346b744f399a871065878036f45d4c3bf917a3ea3a3c67e47f3b04a4f6273fddefa2fb66a7e15f0592757b68f799eeab4064baaffec474dffdeb33759f0c2a9dbe4bc7d27ddac763973a1a3a12489b287a50893c3c28f6bf1ea9d391a8f99e131bce19704812edcf02c98003fbfc4b658d7ff89f56a3fb6fc760fb5da7c919df4139237e545d0b3467d0977bc80259200b64812cd08daaa8028a3c2b890a626db4402fba8c1511f667813e18e3c4feeffedb43ff82baeb641ccd19f41fa953192b226c208992424312851fb3456c903d629158964d2251925369036570c0fc0fe32e5e14f55f328ee08d859ae61ec21a2722195c98ff7940dad0bf5f54eda14eff44249f9e88f4890846978f9d88ba05eaf4935145a71f2d9771e40d617f99c56ae59744e124434e321489ca44b948a224ef9aa5d603d286bed11195af92f456246af20d481bfa300332c4fe451db74bfe2f4883267dffeaf4ad9e4f02f954d248e9661fc64837fbf2350f5401c08a46026005af3e6d9f339f4d67ea587868b76046f45ba9ea1c2c9f69b7a3dea512f62c33e68cca98332aabce51d238db36bdcbef307117bea38543ad0304f1ca5755de115bce90d4e3b3f8e891e5659775df077ac5bed471ffd5a01cb8d3dd877bb5c9199531773680c8a88c5193f26b3da26b90b489ef19b1e3dbc71fffdefb3680a899d7cf38e595470dc262b769f6da524b82174512326b6bedb0b7134ec8eba775e841b17794add9e8943e02ae4b0c4d8d4d0a54839408cf5e3ffbcb5efdbfeca392cf0df90c91a89a89a8a691aac6ced9df788f481492d8ef5d65afcc283ba21205fb4c056fe257a222239decf3ea31fb1df9334e8391cb3f1cf937676781e864aa9f4ee45389a44d91b47949af6867f233a49e2575a9718ed85f0cea58557df4c8a3aa7a9d1ff70fbe21c31a38e4b560010fecd8400362c040063c29fbf24ff3a6ecf8106768536c39b798129bfe9450f607873c28fbfb39776c40a226a70d8841a22aec94d22e056ae177786535423ee1c89ff433fd537c1f1df21048aec305d7e1422ee15eafba0409c92e4142ba4b962cc14b2eb6042fc996689c483f6b2963d4c253e229f194784a3c25d8122e335ed1fe32211924f41c6bd6a8aa3963fe6ae5e3f353815c7c84b823eec8c5873bc25eaa8984820c6b3e2ea8cfcf9e13bbbe9dc1f66595582b0322fa01fa01ca806806d4e7474eabe48294f8a0073de8410e0f092504f1606b6d7fd6b8bcbd1682b83d24b6c6fdd634fd59dbb4bd7d49d33e8d7b486c1c76eeb52d731e9cc673f467bdf7f678e021e121e121315fa236032a41ae30a2f66bfdfcd107eb629fc17f31ff6638eaf7af8f1541cba7fec81c582c168bc562b1582c168bc562b1582c168bc562b1582c168bc562b1582c162bc9dbc1b6e228bbc2a767af5da1b20209cb6753ccc3e8e73a99d73a195f5b51a4eb7f19e2b282a788ab0a22322ff9c743bec5895734eee5732f5fdb2fd37d1b17f3325cccdf90bafbb8df5c9379fd1c274fdb6bc9bfd3f6cd70d4e57f331c75fdb0cf70d4bf2de665b80d2176cc6f9e13f3323ce7e5350fd97d5c0c87d2c6f41a7f79f8302dfac5c4f2f535ff5c5a5aa40ca105a8c4edb556b9848a46000010006316000028140c888342b120c9d23cadba0314800e7a884e5e4a998a24c22046611405710c62c6180200218410119a199a150016746f29383d0d840dc709ec8cf6838b134d1662ae6aebdac3757f84124e5012adbefda5b5c71de54d05c286ab9b3ecfb47f2327e615f4b7d6dc88bf4d14a6afbcf4e5af7fb417f7665a5fe48f5a062b9e70983c97fed46c03ddd643afbd4047f261326e27ecde9414704ac0d2283dcb3b98616210d049210816bea8a0a1882156a616c4b7f18cba3e07fbf48a50062aeba67dbedeed8493ae7b00a2ea99e4a39430300d02116bb548e5f2f0ff7610117965a0b09048557824061c4367148e4c481a18158ebdbda96bbe9cddc0fad2db5518a617674b122d490195f8765d2c227938a6f93a090cf5d220110d8a50d8c9492b3d2e0732f7665f6749e320168770424e02df44fd78f7e6bf6e64d97e2ad8cefc94ef6f79a5bf58961dcb8b5fa33efc2e7da567bdae2b756f158725c963d737c71dbf14aca4d8156e7aa2ba17fe86b48dd4cf9086b32a7edffea193a8b38b2f95a063568b29cad0b0e4ba770c1f13a2a8527e488870b7b1f1ffe46c0879ed63a7e0b110826cc8cd794daf946ddc097a15f0a6c2b0e0503c6d4429d07d84f9cb85f8f5470f83eb019a824d3ccb0758ecd01f6fccf2f077ddab530c3022563f46787999e8ff633a1b1327debe9fdad829d0a2faab44fc1c6c4ab3cac76c1aef87973a452b43812fd9d1712f7c1a983510e740f76e26f5fe90dc425ea7cf30e6eaef343327a2322db876fb62b1e4f3809f0666406981e73f27b374ef8b902a6e105efb7d8c869a8f3454a1647c64724a66f9606559e793819d87ef044cd152a4814dec59c955068c7d729aef69c87e562092e757c3cb0e28680ee3a16a90cd9b7b246c01b316e91d9a3df33d3fd248ff54808398b0ff496967f5bc6e853d12c0aa6e1681c5f38b2dd90798eda3637925d441b822d86280c186379ef000830570b9a10053a0d82d91f83b05a093df6409d501de73fee9cfcf6292d0a6a85c6f2f6f7f6c20f0fd2c7e09f436fd0a32fab4a167e32108428061bf1d7e0f30521820605a75fff368a5f8be7f94dde7bf90298969b9d7ab504048ad1a617a814fe3a1e4e24d1970a1bd9363f2e0d4a6b7db2b55e2b3c0d773bb1180809303791de6dfc0e4712f81c0278e140be549303d336a1f842cafbc1b087c4506bd0217987314f0a3fef6047de30a5348c188cb4957dd57059d34179510f5adbf74a1e26c121025f251872e8256d3dee55f187fbe247ea03eced85e72f379ede6c655353d18cc5975319ea151d34ffd24ee1483299fb71444a652a83a778099ebab75ee4d3e2061d40c99aa8228846ebc215f2174e1a7ea319e614f8dba0117f0b0d4ba559d590da289310774ff8198b561c4571c59edbe16ff5cf2ea0f5a0280b362242c9a6f93710677affc80a587970cfe175e50f6d335d158534858600a2286a29e39530b8416be068029be67f53d69ed025b440865c11085050beec8cea6c05137622435c361b482ae4d672d7d5945addc570683b0e40395ea592b28aad340b842e2b1b9f93068fd02ebcddb89e24bedb69e2372142b10c3296c918771d9d075bf5c37ea8cf0b97aceeb6fd3c97733ce8773c3c932239135099563803d683b855aa67e5e1d58184fca3544226bd5e3e9e8830dd24f4c155a8db17e30deca4cc48dd6afa301c7d95e6cab039346aa44ff06d560525bed1bd4c75c158ce9a65cee7c98220c11971ae640471531d610ed4fdcf8e1c2d8e704d449931ead47118893c3f4016264d8a134806f3010c29a3316f4c5c8ace1c06f79eb219163f9c68a477fb1acace17d170768ec8056cfd71a551791b2e5705d62fdb226de8127662e3ed264466b587846c24b2a7116f58bf6e0db4e1c99321f1958980e6d81bade5450b942c4ac969590f926bf847774771d313914a308005eab2cd6aab57dacd5f5fc0ead8a5b7a78036a0fdbeadc8acf5a884771052f19c27796dfe4c4a95b04220b03bd88d7be24a0b27711c05bbcc836ae40011392dc2e22ab0a89fbbec0d936429ecedcfcead7ca18202f3bf4c920b62d44e387bb6be47de0dd71e2eefc84124413710309570143efc45cedce0117372179a2a80f64e2d57face0223f4666a1ddaa857dc2bbfe5ffe9f59732a92bc9c7c22a04ea233c8d11f2ddef343e9f6538f70311e48ff3d1d1a81f8540e5dd4694a5cbf13dc841fb3c86342b49c2c0b0515f6b0ca6488a2d3cd8b6a23fa1e82349c0bfc137d435b57f05d2c539bfc6b27f08703ef0ea147a35c13bf4c3a7fa7ec901a667755c273c94445652b6cce154df5020ec86b2556189d42bc4df0f5f03333a3d3e2dcf2a17fabc5aee8104ba83fbcd5cc2ee539e6120cec9b36eccf876e0aa967c24880f8cd5f151ce5538effc77d6d48c2c4923fb1805603c8eeb0288081885b67b89e8b5fbf4217ab1afd4ddf1baefdd036f6c1e195d9fdab1262d34c8b255ea0bd8641a2bb5a62f631ff7aafcdfa36821cdba46f0769c7978348994f884fa4f667179568557871518c1f03f83c036fcfc3118d572c2e0f25f8c09ee212bd9dc5eb96b37ef1bcf5ba122bbf7656a7708131afa8d82ba5a6c766f3cea2070a36eb498215551be26d8f2cf851b1aebdfba68c6ca7c4fae74a83059cee8fc3d1c939f7e3a27d8732d2823a8a41eb8484142936e7c4295238706d9c32ffe589453b40abe4113e408237d41740a2ae223a8af0c526770381940fc45cc879181f6d545de69e87e0658bcff7b41d32d19a81473beeb959f80a5ddb120777e8753b4bc7b42fca70813f52cd3c01e5da42a19eab6dcc5b8dcae70b37848b804a5a5442da01a38101885cd8d00c3c78d36d2cf53c5d81b45f809a1f89ae0f2e72c3a0838ec8c0056dad64797b876244f6d3d9ebd9296d713ec88a17fe86b26dccb145ba693af40ea1951107901ce8cf93d65479ff394f8fa740cec2fadbb8eef0316b4218d0d7a8df02199834a11441e213d9df48b39654cdee648f815701b66877f99b7590ec7e73b766932078292d4ef9a7ba5e0db1bb8dcf088e48ca33680d4d5beac44062ccc316703691015f00915678911d056faa79a5b178c494d43a58e6b926ba2db91940f04a999b4b162dbf8988df8e077ee10678f6cc3bfeafe28c00f6b1d5742d997e0695f70d2f0968f72ebedf55ed870c95ba78bad2aecdec7110be19ec12e0c916bf4564540abf7848b9367a7245b67f38ca5f7f15e6aa980f11cb7256e44a08832cf488d17c9a7765f1926744c8924b8e0cd239d1cc860dd166a6db4332c2efc46f0da7d7cd89062a122235f82f4346cf55f9b138a3c2b4e9fcea88077bfb1b08f93ee1d93676af5a59f7b7b32cd9e8a94b9e01969e50494dbf33a8cfe238395ee058f9efeb02ae94524e6479022294fefed7a8f9c58f10b582eb8d57280112c30b0d6620ef761c0e4d86a4ddaf45770b0b660ff5535fa75d29ddad0d08c8a511d0d70626217072c4900fbe0191a1fcfd0d82f288cbffc656ee76f1dc67d60143acac0929229449b00b8f1478acff452d1051597a57a306a790c0c5d9405d880940da9c7594276c55df5a7aec41fe5f1f8bc9f5df679d93a8d8ad4189418a65bbbc632fd630ef78ac2aa91ae8d4b061351b94f3b1fef4f31e5052b9f2e48b7c64032d7b008670d064073f1509a2c7204a658084364ffca156da6580762318384307be631d2f8f1d28d26d37d44a1e8ab5cef2a8eb8507bc6e6080074ad4be7ecdd960614e03eb8f1781abd5d859454be80236cbe3aca9aa3c3e654e56c841f24aa756a1f0e40ef5293920cc896b2e6b96f7ce652f2bc85a6f88b3122dab401456586557aa865504975a42f13ae8ddb0ec542b4234aabdeaf8068e079e5ca6102ad401434113a9b835078490b466c4e71546814bf8dc2f1aa44c3260f9278f063e542083b7ef790ee48184e0e26977074ab612b4aef0c209fdad25a4fd14f8e0959a97953b90701d99214726c947d2a8c5ed4c1841cd99c49b82df9f586787a40157709a83db960a871ad5f04304650b3fba464e1d2dd31bcae22a3a6c58caf20c44eb8f772f8aff0b05d62e01d3d3159eff36710fecb601110fb761d5207854a3b82f70d3deee36a7b68fc43ef2f7c16656a2a95ea2265005a94c1554eab1362196743455ff3ee472faeee4afb63ab62fadeebac6b9077a9f218aa228e0be8e28edfaae5fe13a7a16cf0fae1641c45da46e33d62537b9be7dc6f8241d57f2489d38617e22c6c0aff4237956865d8c7ed1952ff8ea3cc8e3ae44b007cba3c9bf9d209b83e4e15c801d251cbac5c57bcd6b4e0f7118a21a56771264921b3826c820d17ee9abd924e7cac946515e690953e0853856d2660f52025ecd66d85c5f89e7308d37f71a97e9a6ae47cc98f922cf340576edafc4a889176df848dcdd247568ab9c84babebf072f218bf3edafdeaf8111ac3db6aa62e9ffa18109ed15052aa54dab132a1dafabbb9542b219cb40a043854953603d3de10f8e0a4ac977009936ccec845e87d586590c79702c387aa2470da9b359e9193997ce8f166c4a9d403830853b85b4ef643ae7db2ac0235f962b3583cac655662c196622b3c8e9f24932a5b36155dc4709f8779c399594d5c22ed6e3b5e43b09d6b590e666a7866e2b9bd7f1b646125c07daa5d011a7074fa5eb18979be52876be147c248ec3ae45cffd5cefb2119cf2d9b29c7e850afd7273faee26f49211afa0e87189c31df7ebcf11f92af03b5eb2044d728e084f2cad67159f067ad5d34e3108b13008a2f0c23e03e79dc37aed53eb30181435c31f6e27f7a530608ecc0eee2a0be3cd01fe2cf6df5a64a038f85a9bdf8912706ea56cdeea893fc40e4b4ded585c3aa3e5a665d9147362f23ea2848117105a485fe83c27474d3b25121bc8df972e74bb3d0d58184946e62f2c0322ae155dbd9f43e7a12e96e7790cc4ad1e2fe6db5d2c9791cdc458190579325a7224fded9e77bb099b17b7fd908563270ade1c180c4672bf94af64731434498390386d50ddf3f31a7ecf4d8fe8e34b73abbc178b07d9b5370383420e690b7a4b897269e7d6183d1180c7b65d8516edce37d2bf2b30b7036f1d111deb26daae7a805632821038e794dd4b22a81fbc84e3788f9722eccb2e81ef6847db888e1125002970572b1ad015ed08ccea71d72a141f39c41ae2d7d9341a83710d4ad3fdb4c2259c3ffee26a6c815d8dc86737d00f81c392dcb3ca2a85f5608bd5e22799e5beb40c5a8a2e140cd6f50fc8f0c73af029527a64b07b4f4cf0046f50c2331f73162ba1b592f4e3aa2cb87e62eacd8506468de3900ccccbad44eb0f009594cc43e3177d8234fa5d756167c548ef7885b38f1c1c93c3cbc6457548f7b485ab55dadd36467d3fd106d49cc335322b2ace62d7d7442ebe8a639442aa5eed34b82f5bd6ac0a85bdd0b95daf4affca92d65346962b5facfb452ea0fcfc6c7e42ecfb19e7c8b8f0a8948a264514951901e0836ac28ce1719e238e45110ac7d5c05bf6ca6d8025c31a12935efc5d1983b893c94c616615443d8ad994bbbe7db4b103c74195ae20a9f55dd62cfe1a3d9baa3a42b29f5b8acad78d217927eeff1ec31d13e8c5bfbe22df6f93fe57bb7da7b6bc4d86eb46f5982b6f251595b9133533189bbdd6dbb0c79bbfe6c144285895ee87ccdd911424c8a4d6239b51946f3addc948af972993f27d22e9fd2457c18b8cdc60b4e02dba79c7376ad74e9d4f2181a84ff0f0524b14c8d9a558c005614cba3cae1c407d90d213a8814c064e5baa8a32e6568ccb353dd57d89fbdb881038ffb24846ffea6d2b65eff1a3ad42c17d1829b14ed48cc50b966a14074e9afdbc20f21f88d957bb7909343c3077e0c4adad665a1714d0d62b4450dfad113c9b3e7b19c8fcfebb3ccea3190cb80875199a7f3bb9d50910b6ce202c316a96101258c1dd4bcafb75663ec5964eb8547e9169ba93e970b58d0ad3d07468c5afe9961717339f4b4bcc7d3d6c969340ec9a4ef3924511c9519d1542562f364b67f5ca19e39cc1995f57c2ba6e665dd37965e32dfbe08d4bb0e93210a77f65a9952781d54772764b72ad8c5290c5ed2fa19325429c8e2d4a7462cb2172ebff1fc0ee74a1a14a67bbaf9c229a9c5cc2f6343ad2e21419374eae015f0a4cbdf563a56f24308a96fbc1b75ab1f8ef7418d7d49d1a9129652cf6749679fce9d8bec3a04ee3189c451aed54db8c16a418d9de22474d9059febd075b45677f3f9558ba2c6285b8fb6087ec5a947903fc08a26d92c3e34f82eb49c74aeeb1cd79afd81ea5f58943a1c7e52edaf600918038b20dc6d6ff2cb85ba8b46b165c1366e06aa1c2be3990b5a86267068c6666c0d34ae5182deaec9892ab1d4530d02c16fcd4e3cf502b4910481aafdec353fe95e0906d83276d1c7267e6ee224d0b70beddca1f20d158b1215a42b6c1494fd5bccb05b69dbabf10b678dcf9b81a68746f42b6c7bf0350a96d1460a1b6a8963a957ddf6e0b0aaf2ef6202669a57aa6cd0342aa77f54c63c1ee8522da1d002fbe4c178e3dd32a66d917a2578a122ccf34631236b5b274c8f0b300a3b1569daf66b91982ae65743a8558e98a6182835c2aac3c7376c3a35ce9e662a3ae634048bb0285e8ffa7a811b8816d1053a868d644d80d8fac2b341daa34298e7ec31af6870b962737c52034f0a4ea867708ff132ecac6db2cff49d400fc847d68b1ec89c6809f0c293f24a4e5a717a0905afb660b135d9ec39d7b82065c739132ed04544966e7b783b2f92add39b22854ca30a734dc9ddc25988a6e172dd11611cb1e2c567a438909dfd082a770fc4a57de0cc51c5e8bff740a59dd812ede98261ffdfc2bdac12a716d3d2375133d0835eef0792b99e09b4f887919b9ee129224bc5f2929068af88deb0dc8d05d4170fba2f11be1b76873330a668558f69bcbfe0fd61dc0af3c1ac57b92022f1d345e8717e26708c6029479b13592612cf2b893fa8f5fe1e987aae703de3fdd74a2c713e39a950a32700c1220b6e9435d99fc8150698f5930034e1b0ab9f970b71347b06219ed3f07873cbec3840cc90ffd585b1539f8f8a9b7e328b16c2cc2eea16f1169311f2cd0da8b066f591c3fae37d5c5c866694e3d41bd96cb64cf83558a33cbd0e647df6f81352d3e1d4447aa3e064cd08a4337c16a5e13d2731d403855896eddc06874044855b390193dbb3be9f2db1b4232a4a1fe3750034effe6e4f9ba33db6fb157689c581d163a0975307fbe316c557d32b7d654ec995c89ae19756b2ecdff76c8a10c4f1b6a169c054af196c377c81ac281b80d150380fcbb06e8c0e07df372d9d43c3005fdbbed2c60fb46c228cd621f092ca269324dad49093e34ab1fc0e359ed9e017e596e8b46b2ed9becb978c6a3904ac896a4635003ba24893ec6999ce8c383f04ff74d1591a2d2f700f4fe3037f0a4fee8b3c8133882bebf0acd051f73ba54a4afe9b1f947bad2f7cb530a00c98386e6c65bcb3671f7f06c10c2d3c3c67e668aee1a3f4ec0fc944116bd19af5351b5311b684354b58de49d2fcf29fbca854190d6de12a280634ec90058ccb857c45cbdbbcf164752091df17523e62132650c4454f4b83ae87d0c5e78eec96c77f739b4a7517a42777d3b7d0ec2b322b2c4e9f195ab4e839afd81d326f54f09fa0665ea4e4d7d7d361bb89a88901b1b5df8ea9c1206cf39f970c7ad22344312f0644c25625fd7f7e0b37e543667684cfbb9ab18ec542106cf8620cc9fd60e599fa13a16cfd115fa0f8dc7afae05f3d8229771717be106d9aa72fdf3139619837b29d63f65a922d13097fe4c21469a68e0c511ad7f3106c473739d800e703f422640b91e41bcb4ec225cde177eab3606f793a9610d48563392cc927441ee32228a4509538c89ed172502fb32d2674bb268dc3e6ef50d641d4d3e2307abf3cac7f659f820b21327d6e64b4cc058b276d8f60fae2e9ea47ea858b9201aa10b3399820f73b29dc330128d70b0285696ae643944dafdab372525c7b2ccc21ab719316a6ee85b461b4a9f600ed42ea38bca80f5ff9939115107f73fbc7150460ad1f9bd137de19976e73527ff1359cc42edb130afc18f2efc8319cf8d1fc2c91d7c12b58b2a1ad1218cb697c182169b75c3d807bc1b7138f42354d6ec476f7ef7ea241c5c66536d8532e01d428e1ea1b81be6e70a8829d61e73418cacca4b5d8744aaeae666fb866aeecb8c609c158bac7287b009b60b0209024567a7fd7a47d431a414ac4816a3fa2b2f114c2b5fe105eee1c54d404ab9ba502a016523df30ae708ff487307e0a1d9d849f7b0534081f0f74e58ae3df57bc3bcf5ccc22d05a6ce2571b0b93d56cd4cc5761982a55d91e7b604eb2d10735b32cd2141c462745e0504a02bbe94788d18be5cda6129906ad322e5c02a78afc4091f8d50d07c71454ed7a498dba01733a091c7c9c3fa6564af770a7ab5c425566c966db22616591a36be16b931b4fbdd2adf7326ad89450160ad2b1f7cfe43625a3e729abbd6872b97ae6b9caeba459a2cceca813abcdb4b143ea058cb1327db3cf528cb6d784d93711f7c954e6093500eb591b7336021b1a93ff39bdec478f0cf357fd8f873ec522857b170b5423f94bd4d5e3e2d6b32000794518591c4820bab0df0e19e99816cd9b391937d335a70e6fd91d411d71c18861d16e7edf883c8790666093f4bc6f0e893669c84cbbc3ff64b8852d5ceabfd7e5c382879affec9e32e4e1671ab6a4c466b462ad7832a5a9c407a5fd940eb4ba7382e689b68282b458f78f1458f9e629c99b698251067d8dfb7cbb706562241d749fde02f25259dcd5f3e60050044696af814df2cd7a07e86f886e972d02c62c200ab73b15944d7bab129584ee3b6fedb7bb3617de1edcf3ababfd3bfeb44962c97f62c0b66240e55ccfc04b16746f7f59f15e4030fd50d4063a2006e34cce18518df21c05c8d8fe9861ac70879c3e52fd81b8322de0e3079aff0740527d1530873eb1988768c4304c7d9b3e37ef054bb117a017d58d64e9c589fa64c5fa89013a106461f3ac25027e53f5e8fda123df454a53f2c56984c94d1644653055a906301627a33dd53f8ad4282dd495b48eac3020060d7a802f4948ba168bbd70de3c4a15bca102dd79e59f97f4b21e978e5e60129ec524502d1aa7f1b4ba798d1b32f443e8ee6817a65eca4040204cdc43d9de625d88c039779851cf04d480a7efacee1336abf1044584975f85af493c32d37e6fc79e563543a16382eb23a3670d804e8f861ae0892090a8a098f647d78738648f210ac9c72500c6b869d8746610dbea4f7f87f5f6efa479eb003187722c1f030a7366360b8e9856ef1183b756ee565a488abc77866e87f7a967f28e4e72b5cf5264f9584c9713fb05b23624166d9322b4234d068ba464d693941b34f3d2524afea11953cf3843f6d16a01bc0745643af3013f35e1377c0169fd3374d56ac005133008404c29423b23be5df5b8c8e8eb331e6891a298a6a5ec2cee8995325715cac3ef3a8d3a1d1d5e2a3c3fab1ef27ae298ba0ab836abac101f9dc4e5047343774f9a9cb810020dfab251c58d33847d4d6ac33d13dbd39c0a26140275c3a7a0892e3b789687f3d78c24c5b5283e01e03b87634222d2b56b61555d1916f8389935468982f86798321f62e413ac608086318e21cc555e57acaa1282a7cc03ea2ef2ba7f666bc666f5e8e7c6661a0e4c562c3abaf79eb217797535caca59984fae8adea9d6b6d908cfbbc0fa32670c06e105e3e2a84f51f896622ad9e943c79d3b4e4ede9e40a30d440afef991a143ab696d018d96090d6741f3bf991d18cf6eb188cc154e1012f901ab806e3c7bdfa2c440d57c0e7ecaf12e720ffe9bff21d32ec8c51867e03eb75329ff2baeede0bae2762fe5ef6e14a6f2e5c4a4211b85122de4c31400e29f1f60353cfa9a8271961fe87c8b49327e899b82b586a70e0dfc906d4ac9a55144ec901aa69d737634b6138fc48ebf106ac246253bab965d2193a9ae6b41cba4637bfb24a3def3bead22799eb0c892f5b942e844bd9270565ea987b53eaec3712da17d8d02b122cd018b7e2ec5bf74a5645189ef94071cb72b1de6a2d4ad1cb793f472aaba35d85810d84efd0d0a0743d56420a036ea3e5e50080b0bd90b28f0d34db804302654b1bf72d0546ad662034bd05756d4041c43da69105631aa70882ca7d735fbf841dc4134cd6034204caac578f7e454f8f391e1b86a19602b9347af8dfcffd6d520b4a7e9f686dbc774492073561759add12ca4a72ec34fa6b680923ef80b6488aa15c06fc5aedefba624f371cd356488fde14dd275a752639168609bc9c599e10968344308df29f241bba255b04ae7b599c49a1a85ac672e75e41b3b8740c7bc5d3dad53a67f7c71883ff4f6b196aaa756ec2b65892a825154d42df39a088447287d2b57b153418605f88fd12fdf6dbd953e9df8e4a7eb8b6055b839dea4c2d97a7876315842aba14d442852a1e77d05cd1422249c8c37a4e171b2f4385a1bdfd4619d79d12ce3c792fb1f6981c9061ba22b64c3d2b424a194d3cfcb49fea34849709219303ba19ef500ac059cde62b99125c4c474deff3b312170cb44d8a337d05f8fab0c580e915239c7a7a453d7f4aa264fb0ad5a5683c647d69a56ce2c44648438d2291b01befc6ad122dab84704576abeb2dd9aa672b26016b832c8dc0f08385e221bb7fd3af45aa74bb3b659d77c1733b92a839ef11260a8532d11b6a8550d462d561091a02c7cd2f3840891781bf6564f7e7e5d62c206092d4d68715c6f4f498cf84fe945cb7cbc0225656a2df9f500494f8943d867175653b254a0496e227fdd85121d036feeb3396b5802b437384d3abdf5a09bbfdd41e969e1380e30d293191e4f36a8ef56458261207655718326afa2204767ef9ba1fe84a2b3f4127ed156719e89e2430d342361c579c1ac2c017ae24355952220b6d3a7a402047a758c4b666c038cde7e38056fcf7a0014ad0f01b8b399244fabd55dad16fe2c803a98d6c1377a3a56ffd3577c876e2861df25b56e6b00f5da31d67c8d5ee7e20edee3fd526b32260d0cfe63eb70478bed74236d0c86eae7e2959d09e9f075e8c7c580f91aa81fdd7c9c0547a33da6ca26ca904356ca2698d643ab6ebbdc390bf3d4a3316cf5bf17cd9907d02fccb45e346c07ae9bf0c66d2586b18021411011e8596af42ee70997fb4efbe0b1139d713cf969b972d2e121ed17f32a174e436d1410389d76c7f8859713770d27a45dadf0f67a9cfb59a4acf800986a60d02be5f65596c5c143428bf1afce8cd163b93adb2aa3d918a57d2682636cd883127c6cc50b21f6c6531bc8e6f78d23c564d643c4201044261e922ce5db476abd3faf73357ab4ffcb7f17b4ff3c17db448779bcb17bdf462df7671e906763a5884e15e34c5d2d9c7305b02193ba91c6475e3581afd7631da05cff357c042addd71db71eb3221c5a020b086f595c2e25f4c1141058ad917000684b972d33f6ed73136b292f9ab3cf6536d84a6426959bd0dc0a01fe75c44096a845f15c5d9c3dd0e9e0b4061d4251867c1cb869c478e60cdb43efe3ef597747e9e4a7c6b03b0b3a4d2dc5a21546accfb5d4970c20711bfb09b8e36b9a4569755b4c538c024585deb2b14adbbae01b208f2f93772546069c27875fbfddc39f3bee901610358d1da045080ea7bd1f29083ebb2687c8412ff9a703eb986143bcc9c6de02644ab9a4aa257fe62e265faa6cc0218341dc5d96eaaf5a628c08dc123f0646d58386e7c2794c946c2af61e4d595fc6f8f28c0e013b39c4262ee07411f0dbfdcca7ef0d7c19ceb2346c58486d1fef7827722c014eda3e10c6429f396ca2b9740053042845ecf6f78aa62866db7d767b952360306a0230de0d903158a624e24340437c6e462145fd804bc04067b69d0d80fed5810c91ed1d09039507b7d1c418c4269ecdfa61f5fc3fe1a71514d663cc4d794e6e6c0a9bce7bc42fcabae0582337d5127e523271538dbfbb0a864b1f10efc42530b409a8b3d7268fb0d24cbdd43e079c8e019ec6419b39ce3d8b5b66047c173bcbb105a8955c5e61d5948f4900489cedda2ab5a47d254fc65c0b721f9fdf322e5afa3d6c4299e090ea15cc924ed2e20c5d6624e958d3f6f86607cfcaa59be49d7a2da68195ebe40bda5895ed9b55a797bff32e02fed511ae16c6de1a37f44d91edbef43755fcd851e6cdef68e9791d0ed4cdb9ab1193c377620e50132ddac47dcb914286c4eb7045c43c5c8e6d38009a2f6e0306619b97c37606845a09018647974a49a0c78535cc17a90d6f5270a4385aa8904a826d48a220701048b54a275c67a9de7fc6537305ac3cd3aef1d57bd60925a64b05a641de708dd51221cc590b8ee1f6eadc17e128c000f6b8c1dc65f585bab50fb96eb787b51e93deb27eee2084665042d4b95bd06b326f0492f4d8a75b506dd1fe946659b893c001c966293e1190ecb5683de40c8fa39d07ea596a6612f2fc2b90da6010227635d5bf8b55f3eeedf586fd5f854313c65a3376c31491a6289927cb74c3cf45cfb6e3667fa7628a2b312e79b9a8e4867f3b7eb1317e6e9c34ac083bd577783db5424b119cc1df58948ea4dc4d79ea68e5449ad0a6d48730a75e6d018115f9541532ba4a9f9e0823ffdcd8388e9ea2e5b1634ec3970cfe76683453f7b506a31196371e91f96f9f221ad2062740ca5f2cd59e490536b6f1811baad1d24765d41385de8102e7b52f5e8a4600d4a95698d06ce2448a14e0d771b4c55908abdca3430d645d2520c7409f7aa922a603f9dc5a684b7632ffcc39266033bba05921e9d158062cac6164015f00db3868888acaae727b51ff7a961a6d88ce0b6a2dcb9d178bf1ecf4c9903b2bdee6f944bd2c2b52c15d0c8f0dced01be228103d3ebdff011dc2ddd719aaa1b0f5395db162aaa37c8c7451d7a2b1db9231374db4d544382510b4fcf811c86d2848a2c06a219e9dc21a844c65e5b1dc8378423a531722b44db503b4269a6d4381aa311801a8ff7b707738ac07e34bb243e396bce6d6b64233cfa179648fcb55689fcf2a22096056d8481083aa748e77713e2288bed4b3f51e9709233f02be3854cae2ce206acbd67f4bd9ef708c73aca894bd756240e94340164be18bb37f909c601a92725cf2c79072d9dc57871781486b9f15fbdd82289621352857e28549778869b7ddadcfacdaf96454f72d3d87cab1cd6b1b923efa100fe7416cac92cb13cf577e7484d039ec7e5d5e2af2897815ed7fa428ca2bebde590d140d529964754fadbb392d1654d556ff172afe4491f3abc4d3c3de9b2b04ec3b51053af6b562673976b0b048844ca1def81b465df6ccccf86f6b0f862b10b187c1f38e35917bb8a9671c85f9f7f91b26ec52f46e3ef00ccdccaabbff03fa07e4bace15d6d0d8ceee0504796758c61c6dfb8a765251fa62d1d9fb23e401dc755793610693e875184386f82d1b2946eaa8eec5c8907967597bad25b2bcd461ea5775e89ea5599d86b421bb0d2f00418f0b211a0e9d93671a6fc38818099a59d37451ececc9e9145b936d197203e47c242678d663498736d1895f0857e238c9c2c40db020e9b186e53d954bac50c325bb2508f558035805c1fdc8fd69e50139cdeb0235549a5980d33226d814b24da58c4b8bb6da1ac85281a0c0eaf99ee99b85fbd5aed98e6df9822cc24fb12d699ab7e81ccb200b820573947612d0fdb21fbef4e3ba0b22ecd8b61cb190e2bd69e93a6415c20ab5526ce0b58c442c1ba5f2f6abe1736cfa274e649be78f4b4db48d258d8e188ff7f123359b89914d546e7a911dd3ce1cdbcf8490982b2acdf22b05d1243208e9e958aebbc8b1a6264440584a7900c0498aba51271495702c097ab873165babfa6347ddb2ce944402cb487ce4b981fbfeb76b354c0dc9ff6f3338deb8b1ba9e827a74cf5e0a67b7b1d15f9460d9661b7bee425fd3c216f060a5a1b01cfd9db3602b985a7819bf91e2f377aba1bc9eaed819552d91a3fce60d5aff67f11c7bb67ce60635219e8dced839918f1b5b33d540a2e422fabc28898ce387e78128302ec185c965e72c9c7de6c6927ebf52fbe847113db22b93a0b37d4c78d26091381f817929a2060e9e68cb046085af62bb8f45b05a39cc989da0d9e79b8a5559f986bb2e615d457793a5d9719fb2df9319bcb13199000bd25a8da4968944af8028039de478f28a8b7c4eba8a6f66136746eed85a2c1aa01631629a0562b31618664eb282d6ab52cec54cd5bd3100ce7b8038bf8c7ba1497bf2aaac7d98426dd85f838823b394dc94acf91a83a68e819260e990c2031f318a01de1672fe1fe421a7e32f52107c8f515031b5bddb0628810107ff991efd2325bcc0ee94dcfc2912a2c51e286ac8a4619aa0b74c5c89515dd9ba74bda78d10b41088074b24b54286e32aaaa59a0ea7ca8fd2f921431f83b08afb9c874fee134793230f8b47e23e577785089a8171be57c980bae49525a0d89c917501af40a35006a6952a12d397571aedef0acdc3c052dc108562086c9337b8f0139b707280e74cbf5f93fce1b0c5f453ac6d1d64eb4e607ff57ed83028b1b3948618b6880fdbba6f12e44894a80e20ea75c672c959625f1f578234895ed87d32815c75aca312963112fdf247e87762eb38ef7d620b73f42563969956c47c8decc4e7ec6d8ec1ab22e2be61227e7a40c2503b7048ac4aa8f527aab32280c14668eb87814f5c1e6b3e6a09f0917327606ed30bf837577c5d2202102b27e9e08ce0dfe0afe109ebb85447f9761b820c9f4387d79f8dee35c4d63b07e9d57e2ec7f169c4ef37a1d865f061d6d163ed3544e19b2d2ab5d8a9e345f39a273f02e6880ee0ff4ae2a93fbf77793423aa5407dc96211fac4360007db3c5cfd2dfd44799447719dabceaa9129fb7d496ca284c2f082aa00dd6d567cfc254b9c68a3cfd6bda96059e5f4bc4ea96ff453a1f27698a302d851cf1cb48b9c523eabd5c3482bd5c2400046cf54c1275be83111b6d4a73b18324810eeea20e2278e72af314d9f1223fabc88ecbc34dd78e87d8628d8a9af7700bbcae8565774abea996a5b2632d8dc80616fc9e79a4cd5c096658567698dcb83e1b87b80ec2a0b9e47e0805998657667234407d04bfe3b48ec1dee80e30b63546edab78a43cf65875e91cb8923cd47ae47d20799df580a10582ac1f042ac23e2ca273956153f7f1e4100f69baab4b70bfa24c76eb0a7778cf75c5e252b8ab40b543e91f51569b7e24b6dec55201b9ff2f4c92aac19e08eab3136b32e8038ea1979c3ac56dfc86086707162d587ada2f6029a4048becc2ebe0913cee99adeddb323a806dcfb0715658b57a2577d758db26767bc1166c87c7a23c487c30262a2b6c3938ce39d27fc00b840224f300081d2828d8cf6390f3284b89c6c1c4ad37921598ae40b47a51d7dc3cedb2a37f3744ae7a06bf07d8cd861343063b9ba79cbedefec5b7a5ce7aca283e1e60131d26a366c2064a9479bb8a7a7f376fd7426929bcc1c8c133b4f02d1060325324c050025ffa8cf6b9880a31dde9726f77fe8503e0606ace643f1c4a0c0065f857d483d0006405270ad2ee3a31fe0a40647b37428d905b47b99aebaa17b50657cecb63dc16a2f5bf860c5d1a9b866f0b6011e53f4263d81fa9b4a2039186d1c4e405052c97b9dd2c17f5f34112cec4a312af78844896942d2c6a67e1745068a7d4fbd1a172f668f4952a480a4b0397d61c7e26d8e0e2994caf7177e2d931f91ad0833ac6c37aa96238d4b3da6373c765af79d71ca3b1376008bcb43d9763d28936d771b5deb372655f727152393e08defb500cf80e24922a24c84959558dcc5eab90047d7358ae037632498dd604fb0254a30d3842b5798abe0fd4385af61f763d1ba82da5c94f1f80d25aeaa4425eecaa02f944ca7f65d98aed94e09370d95a46fb7b6eac3f6a2f005d3eeba3f0851d59dc0bd0c7c7e612875042df57a5c1aa19079963ca53d88493af0daf0039c41cad70c8e5c81e54069a23c369c3f854c1f7d8bc0a3b2ee78be89887edd8354323d5d315b89590b8c7f154c5d168ba1309512d8490a90c82fe5baf3008b249e9d8eaa026d66e49318c946cb1eecbb666f793f279faf26d535c49b5d8f0dd972c5852027dde6ad154292e6fe9579051da73b843b181e55da0c93151e63decd5e127a5dc101940eaaf828984e906b68faf359ff15480b5fb50c4341d5fd0691cb4f487bc740ef5bae6c31fc23b20a1d0c7e799e2202c2c552570624503c2be80c14840b43a498a95dd2e831032cfb24c4e2e52decacdca18072a58024ec55d77856cd28bf4267a0ce9a53a5e60a7fcfc08c6858f043037d0b3964e0ef0e41794bbbe4a0281bd0256704d58d6ece3146b51516d6aa51bf84a95c55d698675881988241ee1361c486c96be211a0b126553015c2d25f59aa2c9e41d4cb3652ab8d6223ffde68c539c77fa443e35cd0580938ffe9a6430f42d7ac4dbdb99de900ee1e9aacc1f1f967639c4ede0b49de2d04abbf4f06439095d5688c210e746f4e243de45e3f4fcbaa9de4c4151ef4ab7d0e6d2dc13dc4fbfe2fefb7dde0740c60391f4582379ac00bad02ee35715270e30e0b02a7b60465ee98865e44698e32f77b72583e37b1d134ca3b61cfbda09facc441f1f442fee90089ce9b032dce0f38a3b47dabf2fe6993b0c9569d0ef3d6deca94d8a8f18c3549806400461f206a0bc1e6a361e8a78eedc97fcd56cd5781f03d6c15be3e6056b2b18ce69c894e2dae990fc67269db490d2fbd25a1e25e1507854ea864d6467e378039e069df6a916ff66611b9766d9ac5c36a1368f250f684916e58637caac9d174314a902984553ec47e87e867de1130f97510aba6d2524c35b237188b7c9ab62d7400c6a88edf5a502618670d030065c778b50fae6b30a498315ff264597503df77edf919adf2e95ebcecf145cc98f7a7e4d502e7c8da3101c5482415a554c0b6597d33d1ea161871ae813645296c71fd4fbd1f4fdd575030b8109496989c242078a446da84aef0bcc0e3c2538c2ae41f74c2c3713f81e91519ee235ad219873ef13d4e48a1b94775edc7ffd63ec6186f21f823c123053002f7351de8644d3a2446e43406701c440ba1e7b85f257dfcc40778e5e64175768bffb6302a29881c4c724facc2787dcd058af29cdce695daadddd235240c573989101f1c5d74bfe1970e97fd99ed3ce4767c0d4a2e10e5021da245cac22d09d3f826620435b741a7c5d8d779b2eef10690251748122f300d519edb8cdc15727375bd8309129a764607b7f97a03cf1b93e1a2fd7fd5117dec0724b0e2f2eb88b082a48fcfa12f2e29a1040b98514a9a595405e4a849135fe93a27e0e028c4e16f18eea85db8e0337b03e6ae8ad959e0248f0fccb62380b608c75e120f00e704d0a039d282b0448cc040fe1b43216c5f47c81dfbe65234f7bb6d5bcc2c43d77a8f205076816198046c46ad8bc679e3bdb36ce2c2cdf4df4453220e2fce341f83fb533686485290324645b3fcf17962d432efa4434badfadd15dec2cdc894680dd49297832d651218cdd6874ccde6a694f062e8864620f3d9ddc2910ecd245bd5baeb2e87f5f3f61644a31066a97528d9d12a5957726f66095b3d06c322b4da4bc2a678415586ab92e369dc9a9414ae7348eb1b3d28a2af9f51956990fc8accc559697b323bd253c553e058e00114c384a7f10bc3cf934f989da232721e8f5563572eba478224b281756c8f0990a01290725e68451120905be6814102590449e0023d1103e0744483e6244cfe84a2a4a24b3143b7356a42e4a5e1210101fed069a516efa98f3734729b23404442cd9af75ec127d19a1fc70f7ea15232c3cc3dd960be4f9a223069d8f6b1d9ad99694e8fdbc5f911ca89401485d42d75cd5ff4e4d249e4e4679490a21f02bfd4b34ef3bd1dd22a84acd6249ea38dc3f438725fa4e12c7138a04f17c9028ded29f886b7a25bfe8c4ec14191fe2f2af7c00fa33e45805a304197e315e0621272afc7b0615f631fc86808bff153a8b92328ae7d7444391e7b28975ff932c03fd3f5e260aba7da520df1a8d8906c52b25bc2d1eeb9500afba35a2bb8b821abf027cdaec929753b8179c529073b1b84798bc9ca9fc8cb8040876280791f32c0e361cc6417d356de37cea00f2ea84e3cb53a5cc8fbf4641e89402bfcce892af9f780f7840bd82e71a9300385255c39e9dc50089ca21651ae0809ea195e90af20f6bf7a82a43f37716f9c9797ad48774d3cc376082f8eddc18c75e447c807dd586ac8383794cf310f85513251ce4910962aafd64704d1019876391ce2d63640010c894792260328610b1100f1066f8970a35735fdb4b38f37600e476e6e17c8ac523f205c51c01fe45d823781675ad38d55e7edc9eecd24a5b229609750ef16ae67d50e05c140a4059841c74a0d3299dc29c56d22bcb0f0d950dd619af2b6fc976af2e30cbdc102494948a494dbe01f204ea73e5fa784442e5503fd638c6625a481594ecc12a42f2112455277660f7493ab0af9a65d633624f80e2bd96c6111f021ffbcc05ed33153976ab88fd6759882816b287265559c9fc9ee0d53901786d6909ea905a13b74e5e9e433389d1cf6e37d88021bc3640a25b984f133bb624eda7c3efd7fcdbd0d8079182a84a718e1a0850778b89dced7eaff80bd73b4ec6dd545aa56d40ca3e40a0814456a0171eb01b62a5706c4010870a1986287f399a5fd96366a5fedb6a75658dc14f8e3598a5050c41fae10333d97db3d83fe11aff671b5e14dcae3fdeb0b04e05de83e754138666a698bba716ea13da3d29ada19e94de623fa15085087599a917f467fa9b36ec78062ea9584400ff2135a1333c5b181c470d40e993b46210522a035e059402f51e5c306a0690ac557c5c097574b7186d6b884de17e152b922f312e5c55c4ac76fcf0fdadb6cc9523b724fae1d791e2ab8a7498844d31010042aeb259090000f7abe69faffbef695fd85ffe57e6dfd9a81ac01e9f3e8c1f7c2a28f9d8303440328d120743285afa821649239874a1cec2f000deddc6b71becf7fde123dd36291195f373601be07ef666fe45cecdf757b0f85cc8d0df359bef42b7f0f7a1c0a9198b2fd8b3ef01f2ff5278d2c3bb0c81a1602c223ebf0c59fa979b874ef30335fe27350d05bf63f2b9a4d4bf12ea862ff3336734f97f9ba36f25e89a7767beea6113e97dd12bb753b560b3ab80820e2c6ab49162d20e5bbed72fcd1a919c2562fb8950fe871e4363f488a3e46eb7f533e71a639ade40e070d844263939e4f0848d7f804ed151c4211a4a1c44a38853ecda27707e0ac11ce8343a820cae825e30c10d72ffe88e4ea7d1a0ec3062237dfd8c4b579e298a051635814d8163bcddbbdabfd117bd999285f757257764126bbeaa52538d089b3465525d81e03889c4cb87021bed6804a7bce9ab7598c6495af89f64611fb02f59dcbbd873617a4b49f7aec17fe2a470ff552df09c658aeec5b9e23b3a60aa549a46196f02441fa705279b4bf66bb2f4d641b1924d3be627b23c748386a3d869152737ca570cf76db3f5771e503b0d406fa57f794121003ab1c36d8cc1cb621bf866e3c6aef2dcb890bb8fcde4a6f3c4da17a2e30ed48d9420bd0e622539ddda82529e1f776536f2419a764392310aaff2fcc241600ef62612537652fc69d5b0d859664488d4d6df02bf32ed49ef397b410b2c1da722520532cd1006250d57ab890db0416c57706cfd88f3254880c8bfeaa37a4192238ee25dee7734c7140b300176a0a06fbbd7b37d315f0a4373e9b495a256d742df3f560bab5926465235f183332c9ad687525216b54410a513e22c76bd1ca6c9fdd39a70126324a89ebaddbb6de31851f492125b6165085a848ed7993094cbd212e7c4a3cf7dd33a5e92fa223b1f2376360923b43954d7a3b204b14732aabff09e467f8b5b42b086216db8025a4aa8c88747e4915d79bc7f8d32bcc69fc625e54b7aca89ab9f881ee1fc542bb6463e6e669439f2c5ee761aec972f102ab0503ddfb0462baa8419052d3e467ddc6657731badb93d8888fbcfab99e6f2566c4a76a53431fd9fb5a77446f3121ebedb0e003729f5680e05a651b269326b310332c496228e27b50237a36e0376aaa0b75bed0cd0733c25cfe472c033586276a901224aeca3bc082f091d3641485e9d430cf5e81f68b18e9d3e7013387a9926a54c2b84997dfa612e591760e1e615f5e0805347da66165a47c9d987b49967ef04939c99ee9bffb20020306bad6096c9b179a8ae7cc1c69894cf4bb16a6c56ac75e71721d11e2f41510c7ac1955d7f588d8e8b013635c0606991bb2b77afbf0ce245d284ef8c526738125cbc5e3b490394d63ef73258b498a1303003511ff20d2332b31a8fbf238e0164df40507f190def9cae633246a13f6ee5790bff9894f11a71764edc77202e00d006db993fbae0948642c532acb83c43328c8f511a8a88cdb076780dc8300ea36c28228661d5e51992c53864a64694b6216bb638c1c550d8df18259262904aa35659b2a702905c6ab23ebe03315bfe04344392d07a3def91b1ab51bf090ba8eb4785ff55244340401e3574cec583227071e055a8915fb38b1ca4a7686ec850c4671460de5e01a015ddcfa8ef9e26da2953eed598480e78a3ec9efdb099e9d066e73d0c3de5632a177fc84d9a4716950202eb2d2c58c57174624e05010a80f357144a7f088d3b750699d75d4f7d1d1d49885390fa566da2e285eea4939100e77edd50fc203603246d820769c5020ea1e8ba94bcd0989f374b704f1318667ea6657754b69f21863bd4492b538c86ecc7fa343fa207ba99028f05bcdbc49d5f3c823a01480ad54383cf9a16c04d5329437494fda03302b8b4f470d021c98309d8cc1fa8d3660100304be25886c4941f6820adc00d502a7b8b3bf8bdf2f0603b380b86a50aa5d2a53d0d425dc21ad434cb55365b24cbcb33d674ac7c3a8f70baf46e17b2a52f362ee21c268f9fbc1b4902b9844dd40252f194820a2e165093ee5b0b50c5530250387140efcf6f5940298f5248c1c1813ea3e42d251936a3d392c416352ca0a09c88ba4ad9e60ab8261a0185c8e275a50d5886c714a4b9de8d97d086a2d2f00029b28aad685715113decfb5331137b6fa125b9508d20e94f102f2d0ab322ace5d388972038f152dbd78f3b08cb4e15a9881f8d946999a6fde8138b59c2afe9403f9e20992f46c7a9e97fe808871a4d4b8fb9f9e2c846cf3f31689d2d70ab898d38e40d1c90494cf0cc68d83970aab8de9a6d02176214628bf361e0cfb4abbcb5580f85a4ba99bd8c218eaa70c1957b0f61058ad88bacd0ece5c62c95244443562ab438c929f5e1cf0b243c1c102f83a477b5815113fdb98a43a509a2a8acbc9548550733ffb8c13765ded4805d7cc7a125b397133b3a423f094955352c1f56d455c6659466f7e0f8d5a0395d7c29bbccc635eb6c3060a6fb26b501dbd4171803787c3f75d94fc4d1a8b5a33378edee6a1fe6bc459cdc62fd65ad2cd04ebb90e88007549a8a13a21ff2073128463096e6e614ba452bddfa394a5110a4d109ccbe04b61914868469c769e298289291f9a8caf1c7448c04bd27da70eecc1f5c5ddbf24bb5ffa8225e02bb7f1b237a2c96ae0694ba2830ad7cd7f7c3ef96e8d0a4c05ae0276b068032d11ebc9b4004f4de911f918887da54325ed2fd9308b6033398e1a29ee7c1609cfc4f057a422b4c14cdbbaaba312c1bd382711f45b0e6d0f26b8b0e6b1bded7148cc159e9709d9199252fcfbe64d507b5ffcd6991d34ec689c16b5df9295da443c61b6a398b35c7773a98c99d2f38d7df330ff63a177caea4fe9089cf6b79c6ac3ad0cfe0fe2c07aa5d4396b774c28f540e48c128089eee982dec514938187fcce2ca699d154d037161fc73c8b0682f018183fcae071990c7b401e867b25e910e833cb2e980f6d408d787995a97b76255b3f54001598dfa244765fd0dc954dda31eab1caadffb539622b3410d0b2076e415a77a32c6a5d7f7ef8e1be3eccaf3be13eb12e87bed2f56d95f8c271635fc83711f8826f0d585dca7e4b20b9d6a7609da41d4a270a95c28afa22d342625ec5965cc28589c85502e311b1e9fcfb58a51ae898981ced82501e00fc2c64708f03f24a539c54f1fb172438cfcf17d7c1fd28a90554adfbdcb7291ae62f4bc206b393d0ede23e28842759c24ad60b638721321c83d6580d5132ae8a77e7c9bfc8f68638dfdbfeb4d45fa017cb1ec9bae341fecfc995beabafaea5a3caceb65acabf3a59c96e6592dc0662d3eb2443da658803fbd9df02d2d80eff49c5575d00154fea82962cb17c3cdcc46c5fa8fcc806d1800778b5a793f6559511afe43c411420f05ca604500de2564d268a3f8059966ad2d70051774a0f50619a8ab081c1d65b28cd6307a0944d42a403c1e1425e52e2bc528f1f944d4e8910f5d7d313d38ad29388df227c06ca9656bbfa8aceb75452f57e20f4e68310b72139c7b57d7d32b85a857e26df6103e23bc1e601b73251fc68615b183d56c7918a7b5b8d88aca19cfba5e0c78e5fd53bb5aac171e4280e94f71a6397207831ac881943c57c68f871a7e3867d37559da4190a60a14b0a37a56fd50ac555b188a6093fc330b24825e7bec9be005f1c83c3057de29b675deb8981d4cbcda4402968f5087c18db8d848d3a1a0e9739fb66d4fc2a85b435994fdd8e1a11b2477a484948f3c2a3acd98184e23c9764833173ecfae8554c9c3844dd381f6fa201aa6bf31587504188be2b4f003981df20f0c96c8c07fd2b42c2f07f9ab4707671c4d880346f5700a14594f1a91b907a8e83e4d480595ff5d9d888a4ef3abfac96335582efff6c0c4f045431ab5f9a8c73f5618be91deb75f0595fcf6613142842a7bd73370105947a413df93efb0e28a5809432acba0ed872c27d0347f44c259a80fc2aa8066cca1fad7ea58baa824af49b0cc233eaf434d25bed02445fce6df1b3a03a695f3d41c070a6e77de98f63a10f154c4b9d1062f035681b30fb0aea60ec061326c84f09af0d58da6e7e6a251a31932dd4e1c994f45211528790cc3f54911dad60407e394f4ed2c78bf2dcbee98ce505e18ab020ba32f3841ed4c2506f731bb9f5dbe033c6ad8947e741b033cd616e1c0b89a66179d5017e1085d2f8e67ea88351fc9e6809fb038449f23405cc31d8f936bce9771b12d29357038caf541b355d61912509941e3436a67cf835cb7c70e8562c96ac54f3d28ccbc55bb1d0ed5b8da6cc37b1a45aeb6efb3fabe3f066b71e3ef03909d847d8e275ea1d18d74d398bf75d7b4a0783f2b56e82cf9c97fcd26e1842b82617152b288cef51232317d23beac17345208c283831468516e1f564847f497e0034c59818545a285b8156ab4fec2c7e5558848f14175acd725e566fa8e48ba931e92a6577fcf978f8b31e1a6032af8aeee3392f4f40f0a58f6cec702cbe54dfa55b77427226eecd41afacb184c82e32f84759d02ca46063eed729d4434b89130feead8944cf699e2ae3d9cc23befe27776befafe9ec4050672b2c41464e55ae903839a9cd511651ef4dcd3a16153280071c69e0dbbb236631c48b3520f0392dc9664c3141d16f0c6a13f88ade2baf264221c4ead2e05981eb9f27c8fd813a2dd7f51dad8232204d5cd8f48aec739c9623c1e325fe6acc8b52c0aa4d7481f71a16d51c52ccab6586c5bbdae539d7942940cf11826a23040e5a1f680c4f099e7c108ed92cb454071adb31be9e092811dd1c7da14ac644d98225e4b7497f2e3f8d5bd7887fd8dc7b0e4b82547bd6384000162c8f13c0b9b4c3c8e449f3c9a81ac0bdae0511ae89f6c911196d2d22d89f3daf060759517067f495adce5c2016529c8a1c257153a11d40172ca61519e56c280db00a74271366e2daa284c4edceccdab0f382a3d22b5dd85c1d742f0d1dfbe98fb124d81a7c24055af40ef2cb9cda9b217a2a08b6584a5b2b39c2e1b76e1c6ccd6813431e44b082df25efca0399f144230570902ac9098650755c2474b8abab818eb292518fa1bfd6701f1eda42ecbb7d741f9b8ae17706389c9c8c7f252da64a7266d2013bca316398d9db6c5312337836bdb604d89f6f8ee38c7f3ffc1e29f51a1fb21ab77e6861016a1bf1c4f0b5cdf22cfcf795708b82704bac6a75887112e591c72ff537e347ff16b48043b0e38535d63d061179abf9d0f61f7329dd2f540331aefd506a7d85720250280adf085c8d6934617ad5184b5b6b3a0b59b1daf4d8413b8b6e09057e3a0e225e89a63c37b23e6024eb338cb03c3a3e00d8354baa811e3027026d04644b3f9088ac26fe9b0602a3442101b1e87efb57544093092fc3182dafa6a3f70c84ae130a2484745362dfaaa231f1f74360c69dd14dec35666442c1f1479b1ad746ea3b9fc96afc88b4729bde88a7081cbac0ef23a3c0abc18b4c2858e8803b8978543de351c05e09d407194d8879127234b08c45bc6f0f448ea0dd0d1cf84c529628f8390ef3761d133b90d1e41473f098b53c43f0ea1fb5994a8d5a1768a2d4a62fe65c22253b8ef8dd0305e2fd84c12417328390583c3a097b67213769c305f24e2fccd1fd5739005700faa3a9fa25d4c5d202fc2bb06e4183183088b14637439772d58d5e65d63602996fe40f793f545a367eef19151d2943cf66425fe1116babc7d46acc9ec958f6d0a13957ee39720eefe8ad8d916cd07b25c1d16b1ab6ca91f762eb6c5ca8d16470aa88440d5cfeb07e12f209352cff84a104fede055f6fede7d9d979188396bab259d2a5c39c19b8ad0014a2c64ec92595e9ccc0c8548793436c72d11e737093b7062aaa0733aa33955b26ee936b475582a6aa74a350a31726f0d2aee2d82bc74adf08b1d1bdd7a83e8ea5872b708010cd6e15d26cf5b20ef6f12ac43a6f48fc320ac76f419ad815667e9c364c089541a750ae617f8735e5c66ed2d97d3a0b2b461a248312cd7596afb261eef2a3f960586c988ca56df8e50686211d16e3209c8d904bdb3a202d5c9b959b7e69ef5aca5d8f66feeb792676d3f01ffad7eb91da17200cf859bb234f47468823c8b64d899e9de50dec61befd9e2668030208035dce1901fc99ea1c2d7c75405cda030200462c7b348e24e85a28a688bfb0b9c0b96dedc3518defe4e10c2ea5889bce0186a819551f872a07f6b43f2a803671a3deee1903d986d32d8640879ba21e416b8bec6162607140a04177b256312daa1600a2eb5ce93918bb9c125bf2ecb9a021031ee33c08e22d27f3635d7e002e26a70edcbc781aa940f8d97e969e258a76f882223f2c26b3fdf13b7332b5c09a459a65808914ffa73ca32414ef07ef8b7e4369be8e57ca233932e91b577737740d836fd8964d1b9e024e7c831bacdece3850309d35e9d6c2a04c06c900959c123203eebacb4f5f2fa0c6940af3ec58716fea9433ea41d81a4c569a20dfd3bf094bcd327a4ebd82b68f8cb325cb07fd432232be8f8f4ac746b80fa8038059ea6709313caf9fd21d3ee569edf07bfa3cdcbe78f5f0c8184257c2cc6dfb51b6fc6a766e612d94484292303b90233fe43bbd6e8c49261de4d45caba580997fbce9d5fdf52a78673243b835c783b0031c78e406dc7ce1d329219b27696500f2fd59611c2eb2d1ea2a7d5053605043c52eb75e7c975b218e3c734b612c4142a631fffb222ac10e70b3771cccf0e36e8fa74d853c8107bd8d1915648b2be683fcf5372d215c891a0d463acc776dc994ee1f43bea1cf760a4af23483b7c44ee9d3b0d66a3f60fe7854f43ea291c9509ad901ca029c062168cafa404c5d44146c41e18c8d584900fdf33df76228fce8ec52907f77568922fc901a9520bc653d5bd4938e5bae1345325da493283053f4fc1944dc84ab9dc9871df0441c11e94a9f2e2819ecbd840c74af1642437b17981c0a9549189d324b24c9644c758901747095e0efe05e88ed7c86601b20e3686ec320299f8ec3dea99cfe70459c785ce506b4dd8bb3b585984c0ca0df4a6f675f7a74af714a83d515780f8c04e7cd64a833446ce8b5001857cd947f020c087dcfa5acc68c0c7c1e0e013d0a448d7a76eed847dd352eb0394a2b78e69123533a8ab588077468f0fea3be9878394de5e706e7ce7daf8ac43fdf8a2b4412d71748ab8c429be670a8600839b782bba5c754dccd0944e685f4ab38e9d9426f21704018ec3ccf41485e8eb57beb334b03495a0a12f9b24e11883752a296b61f59b62365223c34704e9e90aab272f442289243c5c3796cee73a78c76a62eea043e21d66671e64d7c14ff3d7430777cd5f29c961bb83f3dba395e19d2be02f4187f8882f82c46307ceb78814432e0e8400e9579a8278083f8284fe3f6049ac013658b08324b3cc661b6d2c368600e0a3a381cc54500d419a0d1c3cfae4b845cc67e87ca36e1432d77fcdd40c16ee0912adf599e53d044a3c9c7a19046509f69d97dd2d6643e1c5a5c75070340bcc303c1e6b6c3aec3a0df89e7ca320a0ebbb623f469cb4e03320d7d08bdd1dfca1ef01fec74f71125d9cf41beea28d7963a9df6faf6637e7e12a5fb317bd79ed3d985c29380879cc8cd12e966f8b29c62e1c86dabd9d613eab886a70c16140bb7e148bd9b3882b067e66cfd8dec18a2aaa80644246b615a0ee180c0602fa8c5264b4a26aa63b068c62191c8e248044a18547b40b29707a992132da486292c95ca8c28251a507e7aee2d0b8cc0b6516861d8310c9edcf9710590810562b0833a1605baf07b767e9224b9c74b5e90ae465f0291d9f181763a7027648108ae773db085dcc9c1b40054df69f803770f958b1ea68089dada617e06c4c399f800947353c4a1e3aaf036af75f5164bc6653540046007d43b669ba00935b7574b71c789ee4b25c3f1599e3bee192f774e7bd770cb1143f76acc32e8bb10918377974429cd71eaf0cdf7c0fa3eb6f9a8ef3893f94041c74f9242ad6f4678faa0ce0e8b9cf47b80f79e0e3fea328d89880475d71e58fb51326e7a3c55c85675e2a6318d7721951416bed6ac9415f0cfc050edbc5b813571058c96a3af08b8e86152e07f5536c597e30ebbac3d22721200eddf3c5d65f51ef5de2ee7b83c42d25d916d9c5976e24ed6ec9dc5a63b3eb9a6cc8163ff11c4e4d8f482cd768c79e131c03c6b909d8ffffbb096db2770a6915a012b4134286006730044ca4bee5083870c1952fac90a0ca79435ae2c910a01a68f081af1965ecd0e1b2d162f1b00392a22d280043052e288103c589200a98410b52d085073270850476843120e0dc4ae80c8433b4881106185c5c208800f4b0640725488a8808b9d0020a276cb18120aea0400080105958015f176acc40064c724f5b8e2084202ce10185135e2de862041ff0400630808512491821f6a0430e488a88528082119c8003508660f0821474c185073a2005048e20420067686941181ee8c0161568f2f424d190978c1632c6980109b8d88006b2986289023c29f6b084871c888600f1a979c9a400052468c0029668f2640f3610090d01e2648c9102149460041bd04016584cc144124d946c20a201888f0f1e393524bc40df42c6183228010946c0c5063480c5144c2c9144019ad440545a52c38e308d22182962a3460c567882c4114a72c089a20047ec9cac70d9923ac2670455113e22b4aa00a9f8a6f824e0e97c39291c2f84b949cd90a227b8f0ade0cdb05448a5e0e10051f04e7029810412522ed0464c0d978c0a3129c0acf0f27261b556ac6fb552a9529eaf9abcc0608227960bcb05acd1e261b9a458884912a208d68aad5e5a3d608c0d0f8c5989a02e25937a815704a080a7558d8fe502dac8b0d04381a797243124685343888fc78c0a07d05bfd80e0890623425e02f8c017d0488d109e6e30840c5684f0543e2f178208f1812aa46e4c8f46a69a218ca7d5ca05a32626d8002222454488013ca5e09243cc8d981b3e089960b6f44b109e7eb60b111a132e964b4a46c5041a8184102db0c68a05cfc68e103888c24506163469453951e383510579b17e80459e87294394a08abd08bdc4b05a02cac0fa318416501019820a254e70e13491198d1040044f30a76d010290d1b1e1255921058495028f102fac1fab97568d940f222229165e8482f0f4c22292416a0dcd0c117a71198a41227fb4784201b4e17959f99420b37a811902eb418aa797d6500bb5239e542997ca5bddb07a510159c9200382395d74b486562fac146484b8e4008b5c50b8b1420c2a9c20436b8622473108f1d20a593b323b3e888c5831204b05954f8ac72506d44183b05c582fe00e5511b02788a79a49d1a84ec071698da91f4380e068bd9ce0e24388a022181ead189803ccb1a2e249861aa010d50caa165c72802bd8c849b130c453b8c34bd95237604a0500580f4d7400df2b2860056aca15544080004100e1a4996c3fd27a58b283922438201919b161c8a7672716030c2f5070045c6c31830738a84106034c851458514ee08504a4b861480d3e2c981003b312c1161ab0428a0420f00028a2340087988e1de102149084b4250d346a3b9851860744fc6242096b930179614959e2890f17175c99428acf0f1e146ec0bcb4582bcc6400034b9e4452640391d0101f1e393524bc6ac8804f2461c40048c0d283035750808a207248e28307c70df00b2b3f4822a381c785b5c2a2080d54200a04347104001cf0c4134a20299201d111e3152145842f0ad442cbf8b28038f868a0c2e2bde06bc1c702973062c0f8bef852f06df16191bae2630297bc1c9e0b2d16542bc8a4f0a1f099e0dd7895a022e17b792eb0c607a37af95c5aad8fc5527da097f2bc95bbbff0b8bb0a2e189c2f6b755f9bcd1d4fe2d1de9305772f05037adefa050c776de94b142f4fb85e9eb8d3e8eddac7e9680da5e187c668f859b9eba5e67ad9c1f5c2c3f55243a3364c6b688cd227adbe966a4bb7a54076b9e68a1b69b574ef6a4a6118f2408eab1e38eeaa2430950bee728180eb1cdefc7b577347de7a0677b9541723d76efd24a51b5faa1f93b426f6633eb176095d7038797f57aa5dad28f2beab3582561614b76ff74b6ac3f4475b6a9ab16de7ba35fddbadd9dd5b7077b9e132f367deafcb6a638d00dcee3ed3aa71f798bbeb78c1d3c18f1c2aa3399fa30c3f7ef4fcf0f183e7478f1f3c7eecfcd0f991f303e7c78f9e9e1e1f3d3c3d3d7a78f4ecf4e8f4e4f4e0f4fcf0d1e3c3870f1e1f3d7cf0f0b1e343c7478e0f1c1f3f787a787cf0f0f0f4e0e1c1b3c3a3c393c383c3f3a3474f0f1f3d787af4e8c1a3c74e0f9d1e393d707afce0d1c3c3070f1e1e3d78f0e0b1c34387470e0f1c1e3f767a767cecf0ecf4d8e1b1b3b3a3b393b383b3f343a747c7870e8f4e0f1d1e3a3b3a3a3a393a383a3f727a727ce4f0e4f4c8e191b393a39393938393f303a707c7070e0f4e0f1c1e383b383a3839383838351c271cebee33ee62d9b8ce61eebc50c6702fabddb99ab452dcb63a9cb6d702b97be8ae1503dc77cf44f5b6f433b67d8d569afa56a5cea1ce4f96f6ac09b96bb582fb5f4cf5896dd367933eee4b338747ba4f8cdb56477779dfa766cd51dd5f5ae9b5b7af51bc29f9dbccfdde5509002f362fb118101488179b1700506a43014029a5d4dd63707718dc3d87bb832fa8ae501f5516d487a662c2a52a62ab78701a8dfabcd8d068d467dbbea4f48556b371379b29ddb62f6334eaa3ab7edcb86b8e061a1a6850d9b85431ee54db7dd628d5f671dbdd61342e300759a88d0e1d74574a3ed3686f35a178f071dfe7918c731ea2c339632077ffdc052ae1ee61b873b6cf7804777081482e30e635f4e787e6c4e85f5c44a317db6d2271edee3bb82bc501d739acd972675cabee26b813b9832f30550209ee2e77b7e1ee35dcc5dd6380bb2f71d76700d79746caa98f26ef896bd486e93e31c55bdcb63435a5e187ba7b8cbbc3b8fb8bce214ed823ccb9d961cbc1c1e991536b351d1dd2478e8de706db50ffae790c77796b7bfbbc03df721dc31db58cf7f8b81d3abfc6610709eefa70ee658d8282bbbe98bbdf70d777c369c8afaf55e9bc2c3a8724ceed18bfc9e5798101773fc15d5e1477bf5fd21ffa354a9627c6695a43b58d51a727afa5df84739f45b3eab4bbebb87b3cb87b0aeef2b6bbeb1c8e77a75b7f96b589d2721e42a3b7d28b29ad2666d6acbba78fcf2e4ffd47344a7e59d6d1dda9fb5773771ceef25c3a873b6763b9bbe72bcf38e7a7b752f26f3ef7e77d3ff7a599b374db9a37bd5dbb77cd656ca3350af720e0ee2ab8cb69ee2ee32e57c2dd4d7097fb407e69ab8deadfbb1aa5364c2fb6bbd25dc6b9cfe91c7e31eebe82bb1c87bbbfdce53cdc5d874b5bfe264c77db8ed5aca3cee1f84da2aee61d63d63b465c9675c72ed75cb3a5bbab52a0bb7f2408f104e3504f4f334f91d0240d18989f03e07015e115013671e2d1225a291f3ffc10808fa668003c0ad21facf8a189130aa44a72a12aeab01f8aa0402ad80f0158d11798130a94a22eb000b4604e2890475594050bc00aa682a5a8d300acbc0bf383809647e3c40a2635cc524ec0264e4098154c6af898785e0e303f4efc28c005d21a340e042343f3d1181a8fcac8a43e994f6646884599583009ec3eba82496097a235cc3c189aefa32f30d48907f4d22446e6060772691203c40bf55c60405891f4423d0a040c958909e285a6881a80521486a689130f28458ba8010804a90c4d4a7940df07b6649ad4a02d9a263034c6833d0111801485813da59a38a14032f493d94186068800a4680dd8538a7e3724a58c5e689c78402fd485c68907e44261689a145103d00b75e201c150988f46867a343337805486ee90a231b445d3c42587208060a8478178a10102867aa91a156db9d0146105931a662bea01fd447131f12db3158c4902bb8f4a6007ba8c3eeac9ccdc60045297314ad1d4b7b200cc0f14d7476154b0541029af088c83ad264308f1d10f74f7498160cabb008c7b1e93b7c4a22d26a9990b0882a00b65b540960b9862b15c582e2d18530a04413095fac1f3a80bf5886872d34755b09da22aba822dfd9052fdd052c1364d31a954302616fd5654f5518f8689f5c30ca4dfa7ca02c6534b140646e544a9990aa4aba68fae401a2638664c2bfa0263f2c3cc857e344c70cc56b09d1af266add4cc05b604520fc6e487190bc6945a02614c7ce6d4658ad8987d1f08c018087a204c4a86c6a456ab9915a5595232ab99a9621f4f6cf6e998adb60ab6b4a22d153c6999a5e86a66453d5a0316cbe0cc2ac69a69d16f15f3e80360fc1381e7ee35dd82987d9e02541fcf962733ffe208516633ccfc0b23a031db82c6163066302996475330a918157ea268cd107d94d5527d9e8c0d41cc58d465843ecaa22a1a9721aa997d54c5a29951d15891ef0818cfe1c57c2bea4259608bc2b0965474453dd053aa948aba8a36dd8298ad666656b1996a2947ca0b18cfb1a452d1964a45795855bc453f18168da702411655b158b09916f55a30cfa32e9e475d582cea59f97854d43d30664ea15a312eac15930b25728181aa97992753244559acd58aaa562baaca020250a4282b8a31662cda022345554610c14c455725dc28a104125c2b982023e441cd58e04ca582c1c0d034b16249455f2e26992229baa236648854307045552b98d0376351976fe64213832307cecf5012ad746af2840152bc2c604e8041e1938981408c4b8b7e2dbab4a25f11ef0b2380d192216ab9be98d7a251c9144911ad60e007a63cff54353c281b4fc0781f08033f2118ff56de6aa55a5198956aa54aa5220093a23029f7d920119c5c9979959943997d54458508ab551338642605a3817119a729e2cdbc20664efdc891156c29889914ac480a4cad28cd076e30055bf22828736429889994cd8c07b30153a994cdacd542e279f4a3aa09b45c38e8a78281a9a80a86aa543f4cb8be99960a46e5f281339715cc05d6e4a932a8a2b0a5184e18511ef51c9ecdc7935ad1d58a45419921abef9b61d1158bc666332cd88a49457f06e00269cb8769f5425d56d405e6023bb2a22e2cf08b28b3144d3d897a9af94c457f80840f9e6cc9624b94d9f66629eab27261d1150b06ce409818bac199c752b9a8284b15d36aa5605232475474059bf1668ac466ab214b29baa24b3345623315934757744635a3821589b15654b5fa59c2b5a23e43f4cd56b4e9b694a21e9d69d198079b69c18ac462309b8f67459760331e0c66a5f29915f556aa9567e3376e63e6f98d67f3c5bc55050c8c8d8d162c5666206d2da5542f2e34e502cad0189a92194265a8476363d604ce58748333f005b6e4d1189aa25992f1b4cc9ac019483dea4b2d3ac3c49bbdc0664090824ddecc85b6609e0b55510f64c2e54e552dea026bc1fc26b5145b026752d4b3f9620eb3f962319e2a0c213c99398ccdc7e3335eec8b398dcdc099bb0f134fcbcc832d7d7486459d7eb019162cb55a31ad28ab45615c601e136b49073103bf9922b199473d580cb6a48231f198bc0f66332445809894d06acbc808c1f80b9d9189f12331a09782155951b7f9c2804905218b598bc280d485b6102ed80c9d49c18ac462e817fb62423331b4096c0267eef48589770406d6441d968209cdb0a8477d86052b128b11ad60365fccf38f044c290ac6c82cada8cb80344d2acfc30226cb2c45c12b369654948945895c33fd511818caa2590ac08c459754747b600ac6046382a133a75982a12e4304d214fdaacc521444e38b211860a6a22a2636667ac847d3e435792d22302ed4973c242bca4a51907ab026af95a22c181348b7375bc140150c1462e2cd9878b30fd67af1400980942505a42d345a2e1c34e6b0a519a29a99cf6c66a9235ca91485c9204d5190e6278a15055b542543b4a22c50954aa552291006f20c013d19a29a9907635ad116fd689640daa22b19a21513afe96bf2662acaa482b57200e339987860eabbe13155933703b780b1e1371eb5e13e4e3d1360fcf3a6a0220b175a606185191552c081c20926dc28818497cb460d9918981797d6173e78b2811082108420b0a86a096fe5ada847554f5230400e7e3552d4035de0a76ab15a2d560c250286bec8d0189a2413034b8281bd106911b5601e90b3605354535ea8f88dcac9142a53a6b88831f3281517171a4fd5b03e150ca2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a6cc5a4881543c164859340e04040dd7920a8a0ae652c56fbe166080b0e09bf295000a1715f80114205a54aa2f0715ae58cc0687874a05e53eacd9b78217b3852b453dcf7503d7522c16530901c71950ce4062e65f6849e30b2d65681963e6d198235ac0d062458b1737b0a82045e50296475920751fb8bc190e5c00e5c16e40bda0f1e4050d951752a4489122e57bcdbe540aa6ba81e549140da4b430036137a03ee05a3241ca0aeac992095266dfd28d0fcc3e1b52fc064a0528550fa07eb856ad8fc7fb814acb929d79206dc196cc99075b62d1f8e725e17cb16f46e89bb16892cb10e1f1c580d4c0f502ca28f1d80f62be305c2f7409e6090fd7c7e3fa623318d8922b01b32ab3179a251e51ae2955587ec5794aa8a15aa95454055b4a097d9ee7f862de2cea8a0b4a9494d7b241e38a422365e69a92aaf95c09f0121830fbe84745852720cc05254597609ecc7200a181cbb301c502974797609ecc3e28972198007502901ac47832deca6379aaa854cde70416c5e50c973783f93ed5075bc211038b2202330150e5cd54556026f0f1bcc096543c507d55be2a5f95afca5765f6d1568c14284010474ae5040635035d70a1062e0f08085c4b30535c54dc27a5025d98a9b04c8101612664f19b8f0209238a77c213170f688f06081964789ee7b947c6f77dac8f0c2d5a52a9558a0c5005822a32522b2064b83c4ae4034206abf579df9016133242eeb1580cbdc1819a10e1a99aa5184a440daa7a92aa89a1435a32371831ab415546784d0c85597d9e832995ca89dfd4a03232d465808ce1aa019ba9416da8f01385cb8556a9542a4555506cd0d88889a931631159b5545358ab198b3a711f191a43dd975c68c13c06e664a5a2aa29a997147589b9a23282456158f44586c5125ad11818136f8b0a8afbb066535c683e150d9499eb050b4b014010f0e3c9941a30186a0354d12cb9662a570c8bb65a322e160bf62309168b92f00a92aae1d1158dcc0f03cc3c1ad372c5bcd0146dfd70f20389179a98161697cb8f275fec47125b159ba5a64cf991c40f273f9258bd40cb04a4b8a4605c5c680c58837e35e84b0d1919984a86880c6d5118204f802040e6bb8163f5a272690179f2b56866e062c18040f910007e54f57d2a20568a00e339965c56106961060303fbf1c4f35841803668544f3eefe54b3921e23960804071a79e0b7ef3d1964aca15ae2517b0b8e03e58b2ac66402ce0f2684bcb18365a748a1507b896b04479c1e2bd80e1535801e3ca8b942a383ef0a2c50b16b1282a900aad664c5e288be6050d9ad56c1595c68b16201648799f0bb32f6ab69ab2840defc5c91753d9983253a9e80b9417245ea0785e4b85256fcaece5e5e5e5c5c90b124f523e64a8ca658afbbc50952a86aaa8aac9c7c3522101f442534e655e625e54f485c60566b55ad980c2c05315ae9694094cc982ca165022a8e2851530ae8881658c2c3c785a0010282b20137081f45b6d0125021811577901c68c47b18c9185071f8f0b8c081a5133abcfa3711ab0d572ea7935509acc6866fe050db0ccbc1f4e603f3c8f7e535c4bacd5c762a562626258302a2729964a05f591a10232856b69855989c57d5c9801d1024816fad18f5a492901048819505872f03445044ba56a0a90200276df8a6f1d4b5bc56af36f9bc76a6abd4f739f382cebc9e475ec1eb7777f31a5b7dad45c4d5cab364c44a9288a228dfccf4234aa2d253fbfcd56aa7765cd559ff4565c564a23896aae46b48b2df95b5b9d3f776a5d492bd65c4d31cce99aab79ebf89f856848be35cf71c43463fa9f6d343f6edba79f83e8ad4d5f7ea6ba8eb42c2bbd587cdcce58eb1fc793866d97e8c83c712642a3e9f0a5d15d997013fdad314e476d9852b2b4b8713f6e637387a34fbeae354abe0f16dbaec5599b27ce374a1fb743bd9f08b5e66c67fb070a494bf7ebfd9ab4e27ebd5f8bfb356daadaeabf7f1377b6ff1af93bb4a5fad4f7f5c523d54168c810201dcdb923e11e6bfe7d2dc522f9966a7b43bf498907fa178fa2ad89d2681bd728fd5cd5f42b8eea1f2d792db5d52f2979ebc5a6aea7d6f46b368fdbaf4f6d6b5b5f5b6f7567b3f99350fd4df5cbd7e5101ad22eede8c8111b5acd8d7d0e23511a68d44644434d6df935ad3463dbd19123e2d5e1cb246efd352ddaea9762cee5b40d8b39970b7118677a74e408b5e6ec6b1508b7ad4e14c5703bfdbe78bc9696a7ed2f121ad6dc7c6e32571cd53666e9ed5a9ba5e12d7c6aa34b5b6dfbf3a89932d6edbff4715bd791ac38d7e8d7f08d9575c4a5f9e358e9d7c85bbf5643a35d5b770dc768a5196fbaa928ee9e09d3dbb519b7c97f7deacfe73e85687831fd265b526d7f57baafc526dddd4ac30f2db5d9b89bbd5dfb354a62dcfe1ca6fa6df99992f5b7ae36e37bb3547faee66a525d296de352d398eaa64446b3db89719bfa0c4942524443dd644f266f73b553d38cb5fef12ffd5cb50de36c44c37c92946eaa2ddd3d53c5bbaca3cd786b8b2bcd138fe549e2dcdfaa3ee99766ae3a3dbd336a5a9cce7f75d886a90de36cd24ab5ddb8d44e7fc31af2c77be27b2bdd953bb27e2e2bd55517a34e7fc95c6f9fe9c5f65a31c48dd8fc5dcb7008d00ce8bc595ba5b76b77db96f5667b32f94cad59294d641a1f37ea106f4a7338dbe82ed7265a965647ebaea47edcb56f0b85e8ae34cd1a6e7c69c6d752f2c9b31c2dd5ff393cee539fe5782dbd955a73960392d09a95e667ca5827da6c38a44cba6e7a6dc58d37361ba68fdb48343f591fa7775f24b46645a264b87b263a03d5d5ac6da977cff4241e5f88de3d93780b4d4a3e1d6264168444c9dff5feaee3c5e3110d35a5f5d8f649a3957e8dfcbfeea17ebb6d596ffeedf4d53651f235369d9e7ec67beb90fcd7bbb2ac58ef9ec986f3df2742c97f6d856b4892bb933008c922e40b979029ee4e69f8a1d48776bbf6da9afb4ca35b5793fe786b1379eb383e89838cd85d9e4764b29ef367fc243f0540e288a0330440801c5c414b70767ad0d1facbddad547f2e578a1b77cd19793db83b93bb80b0b8cee1f823e409776e6e687017101477279f0905a2717e1fe8edda5d793125eb97146faab7ad516bb39d9a92bf6d16a75f5f6cea3fca8d4aaebdd98ca44442ded94ee7b736bb7111d2e746a75bdd48377bc4dd7392e024b935cd94f20c87ae3a5a9675a43357902aae204e1597fb6de997b76b359db9820471f7509f355790cfddf1257576ce1ab870771cdc5583e96159be4e576a73bb76eb6c6dd486290d776579dae89396a4faa90d53991152602bf5a558df8ab58259e919f9b9df44b9df441ab76d0e41e4ffbe44b87157201a36e0eebecf9c8730211992a49364dfb7e39de524d9f773bb6a8aafeb977ff463068f9c9b6bbbb9b9b936318b3f36b6c992d4c7bdc4b8467e0e8f321e3ce78fec67fc2419db6c8a38bf0f17df9d752daba96b1e524d2420405cefaaae9cfdc5ba2ffa3163a1dbb563c642daf6d9c8963509b65da2bac799bed544ba5dcb54b7167d82fcf081875bffed766aba71379ba36fee76a5f96bb9f3d2c76d9bc7eddc79cb15b7e953dd1721fdf0c00f9cb28e389b76fc2312e976adae9fc71792eb5f6ba492f7f3db3e37e533c87d273af1e02122dfc90a65bcc76a23b1cd6f9abf3579bfb43f668c4b5b59da5a7ea39e19f78d4ba4cfd9a43f99541309796d11f25a261f502e1fdae5c3050f95966c5c6a1bf25a261e9684fa71ba969a92e46fabb1f9e4bedff4545b5c120d372e35fd9cddb466b4363bbea96fc86b9962e4ad9426bea6bd69561ca591d732d1e8fd267ba34ffeced8fc4ce9ad545bfaf97149487c80e19bbb4df5db6c98e7ec71c6aecc7d3622bf2c6d119cae1b897cf262205d626c543b91c85c757f54626c54626c445e5cbb385ca21fab8984bb9df80ed9b8e89bacbe6f7b21b76b77386ffd42c8bf6f22f95db72e3136c51cbe395bcb20f7b29ce96a2671dbe6704f6ce67090d65f929fdf4834cdeae3f3d796178b3977bf378b34dab2761af9f8fcc8e9d14327eb1d32769c765a3a6578febdad2ee96f354794ff76ad9079332a6dcd0dd9d81ed53e87b2dedec8ae96a6b64292b605b262dd55084f0f9dff8c4b2ac2d343a7e290787ae8605dd233d512486747578f727674f5086747578f7ee8e8ea518f8eae1ef9d0d1d5231e1d5d3deaa1a3ab473c7474f5684747578f747474f5084747578f7ee4e8ea514f8eae1ef9c8d1d5239e1c5d3dea91a3ab473c7274f5682747578f747274f5282747578f7ee8ea518fae1ef9d0d5231e5d3deaa1ab473c74f56847578f7474f52847578f7074f5e82f2e12da6dbbef93443942fcc848bfd57d11ce0edc8669eebc4f6934fab8241f9f6a92b7e6dbbedf34c4dd75b80b278a87e4e74efd192787e4ebb39afb7ece67d0d6d6c86cbf165d38b1907c5b9a66a5f7bf4675c5d1fd9aeeb6cd18b7cf4a755fb4e302e110778534b82bece1ae7087bbc2586b757110f9e43d315012f9d9ea17a2c346304efaadcfbc2f0ee43df1d1673c22e5df38c911af17877d4f1c74bb38e7a0b373ba7bd2fe5baedbdd918efc7db0481989289ae269e67090fb6ebc7fcb9f1bc234d65a5956211cc8bf378b746dc5055d243716c8df5462249d333e828b92cab2069d2546223fe38d848b8c98466c04c96edbd2d6acae2f54a499c6c77d16bad86a6d73b513a9c4d8e8cb5a2d6d6d9a5d1c36c669b35e24773fe23e3ef9af3df237f7bc795d71e68ddde599dbb1db3657738605b83bf1f4e0b1a3e394433ed3888d04f96fdce4e373bb76e326db74f1f81b27f98b8b7a74724e7daba550cddb694859ce466d8ffc0be93777dbc747eb8b75fd231994dc55b3c55d353f70574d0edc5583c5dd635eb6b6a58fcfd6b614f5add644535b234ede130b6d5cf4242eba55a0cf55a44bb471517edb547f68e3a2df75b4a5790aa929dd7c7d93c3a4931a166a40a778534dfeed56dc6862fae7b5fbe2d1e64d4facc3123277c5ac701d573f26b5c56d8a1b2d4e476d6eb5b4d124f2f5494fac83ff80137bd091864e8813e6340d014272948444f3dc93e2e91c7e0de7ad73429c50e7e6da327fce06a2978e9dcea135abf8bb36d96c8aa24ec823c4b9b9e1f2f3b9ebdb284ddf536c62a2e993925fd6ea7dfa35baf599a3e4adb4acfb7ecee69bdd33b93b11f721ee8a210d213b88c18826a908072441a290221c901c894262915950d09022f456dca6f945f29e38d3198f3027c4b961aae3f84c4f2defe94988a79727f7a727ff9e3cf5e4463cf91147b8bfb88bbb3b7127c093bb3c3d09f174c493fbd31301fc690877f798fbe82e1856d0097772429c9babc3b986d31597238a529cae43eeee3974e0eee3638469c425907b59b8fbbbeb852aeebec7cf198f74e3ab29b5594afe1edf747aaa2d7d5c12054213331669e403e91cea6d73b6bc0902ba5d9b379268eacfd5bbc76ae670908fcff8241e9b74764e597e232de6379d6a8e69c4652d9775e32d3ad59c53cdbdf8bad6643a3be78f53cde56e128621717fb2e69b89c3d1d6d588ddf612f960cb7aadd068f5b5793b0dd995a639cbfdd63b5d7146f98ddc3f8791fee2a2241815dcdd88bb688cb80371f71edc45c5f0dffaaf88b34d1cdfd43bc66fa2509e003c1d2fa786a772b99086eb1ce6df56ccd5cf5bdbca276d8e24da5f96d5c8e762abf3274172f71f3d6575b5c0847b18863af69736bb7ebed18d8b68a869596b798e651d6fd792f7a49f2bfd1c7cca6ffa52acfad6bc7d70bae25af871df19e334c578e374c5519fd7f99b3e53d296b5e912e91ce274c535e5d77ff49f85466d733e3efa3e13dee7ae1be9c75bcb0ae4ee64f95687fc4d48c8bf3808911548e77c7cf4dfaad67f44eb1f71de1a1b61db25da65bc2b79eb91b2e637919435977111a977d54846be69dabcb54f4e57dd8fcee18e7047e7e606a72bee9e3e3e3b63d33cb5f8b99a6d7fab196fede3f339bbef99574061051356f068d4874677a5bfebd667ce380817e9d741a98702e9397990fd88653df758f5ae1afddb44bdaba6d6b50cc28dbb9ada0ad1ba96630e1b77b3aff30ab86668709d43b2b4274e4ea873836dd7de7c59474dfebd59ad71bb1a7511850a552c208618280ea58186eed7369b2a861862a034c828795fe523893bb80107ad08e20e0e000c721008873b380379b87b91bb5268ed8cf50e170e1e3891bbef70ff50f8747077d15d389876bdd9a6ea3d0e2d81ef7be291d220a3f74b71dbbe14c912b356d89aa434d0406b62f7cb70ccfa8be2ee3cb80b051e27f1ddf19f776d4789c71d3b23ce68c3e961e3b1edece4f0203f8787ccf951499e1e3d7a7aecd47478ec8c3f5e67ec41ee18b73ef30e1d9288826646b320fa439d489bff5e9bc3eed6231827b98336f949db84b351dd5588bbdfd8b8bed8eef1cb211a9b4521f9e4ffe8f454e7dfb8897e3ef51de25f905c03b8c86df19546a28b203b9da75220042af574e42923a3261962e083af166080182a70860e9e6a6a62c6075478389884f544004828ce6a01912074a0a9c73d01e01727ae5081b38210850800e1cc16676dd9b265cb161eb80a0147f8b8c20602f7a814d73a31857f392057d8b08bb90a01a910ecc4d0c3553b5021a40747a87b0d4b86236690b9337951021cca98817b2108e24905564d9c9542152380220d240eba7cc000e2079a9c554495274b88b0c55737c0541aaa6c7167d56f6fa1c4bf1d0c8539ace087bb11a878520aa20315e541410d30b0c5593f463046f9d980ab701005cd83aa714f4a0c880997039e3a52821274707a807f547486c034587016110790e2c9c813ce32a30706702086e61e4604d2500247037c35a3c3861a51a6b8fb0cf766cbfa3e58bd4fbcab465ccb13cd593996830ed2e0392b8a47aa5e1ecb6d78aa13bc1a5e4b07f4e12903802db0be564b05a63ccf51f842ffdcbb01acc173161095db5879ee799e4ac5e383f9dcf3bcd437e4792ceff3bcd4ca87cffb3cd677c291e7ad3c967f9e4c98fa56abd80bf5c0ef039f78a0e77d2f1e103ecfc5551ef8a5def3963ecffb5a387c339ff7adc0cfdbc1e77d9ef779deeaf36ef050f0bcd4d70a812ac5aae19de07926b4525e03bccf5b7d9ef7a544ef035f5c787c319eace5a972a468f058df07e6a45ebecfabb1c1e30100cc81114a197d0efa17010f4cc540d5e7a55c7500af069e7fee72b9bccf2bc36b7d3278dea7fabe94e7ed783bbc9617f37ddfb70af2747c1ff87938a9102685560c9e0c092a7c4e78aa2f050ff4529e7f461f7df140ffecca29cd2b40ca6942e07990117c296fe5812c4fc64b41f9be964fcaeb4979df07d22fc625e6a93c8f8503e6b880e37d2fabd6e7799ec7f23c1feffb60905a792e1f986af260dfe979a91bcf05e6f35a2cef0bf2b5f0b5f0b190f2947b36bcd5f77932a02b057e297cdfe7ad3cd0e6b9e4f060549fa7f26af898f98858302e9f576bc5b03eef06afe579a9cf03bd218f85efc7b7c207f3b13e9597f23eef83f958a09752a53ccf8797f2629e8b17e3791e10af85ef25c5f25aa0f7799e8fe7ad4ef86e78e0e7a940efc707e3a5be16bc54eafbc00ff47e7c9fa7c2f7e2b9782df0f33ccfc763e17b61a53cb0057a9ee7837a386468fda466507929cfc50371782e2e3e303cccb4e0bd007adfb7fa58efb94cc08119ba71969bbe43109e161dca70aa031459ace84033060f72a835a0000e34c0e249342f702428be78a49a023f82628b061cd160243740b1a4c5a8f20862048a167e305457c0f901058e1d3f6a8d2a7cd04026870f9a178f87069e1178685b9ee0a147f0905684166e68523e1b2c52601b8a23c30c516ccc708146635ca02890e0514a50729a6a09a7a000dc53eeee32b8832fd400702e711e2f23661df5db9e1c6bf5478f0f9e1e3c767472709618b95c68e81cd65d4951c6466a26d58127b0004fa091950cd46301410897144f2a550c2b86170801429103a21003812a560478028db89cf0b2020e013cb9e800ee906a0166af625a42ad9ed54b0a088e1795099e5a549e6e2c11c2c547aa013e8899c1936acb932a4605163cc56c58079e5c70d4f85840543b54067062024c0a4e0c0122f16483c6064deae6b5a385e3b56508d50cad1ed64fca46eaa70581a7d4919c1dab97d5049e52302b15401b989c9407c680362f42aa19583aac5458bdac96626ec4dc70c1e172024b8794118658a9909a3284aaca130c4b608e8a30b000fac4d858bd402f75930a028d6250587dac1c5833ac22950935bc154c4a05c6a452a92fc54ab5522e2f2b8029160e2c126c18bdbc582b969762813cc01da0d74a213523848b0baa2a9e6a4c4088d70a9c6905da1e79008b97a5c5690f480971db7c92ee2e91130f98a1078c4234aaae0307e8801007b4b8873b74a55ac75f4ca3519b8badad29baf608ed62a06b8fd0e8bf8eed6ab627bfc49972c0021ca085b6aaa9be5d8bdbd4fc67ba5dcb44561a2671a027db6a0671c015fec9c4de9392b7e67e136d8125d44cf7c48df4d6a02da0729fc35b244165329d1d991099cecee954739624c98b6bd7e6f4ada61673e7d5b6cfe6c53531e33d569b6cdf1ff31bfd9848c812e3f467dc16afb87f59abf96f79365d0d48717751034e1a18daaf3540b5d0e255d4c28a1653eee9a45e5cd382965f8b9e9a5fd4fdd5c2259af573162a55dca944712aa6fb7e4da547fc31632aaeb2c4795f2c19a0e2eebb6a8afb7506a0e0dae70c98ee62595adc98812039bfed4971cc40cb3de3bf160359dc47cb84010ed4fc22beb27dad598ffce724205bf3cb340e4ef588ec87e99eb8201c6ed7e274dd5a86dbe60bd9f9f824511bf3d4d78a5aa6b76cfc24b29ad8cff8494c998cdafc7c3e35369d8694f5246d93252f910e5fa015d22cae78b8ef898510d18c8bb288a22d898bb2d83dd35116397cc45a578a77ce52ad635b8a35b5f9265b7e116d012dee16a86281271742f43e600b0c795873cf18354f6a810a68a9c094b28eb756c0e9d60a186d5d05647c07f99f6de4bd3597df4c727af26271c5fdb30d8b291e2ad1b078e2c37fb661616261c4b178b9a658710f6bc86fb2e514281e6e5dcb8bb1a65893ae29495352b8220c770f6b3e77ea18de7446ca64d4e68abab5f81bdf5d45525644fe6c6d8dbc75fa5b54d6fbe55f5b5ea28cc5ff7c9a148080939502d8dd7db88b023d1e3a3d79de6c2d57b525b7d5fdcda74967564485b6aaabeeceac80f2d06657eed18a28332b9cdc37bed40a23775d29196445cc277045eb7873b7f704a0ecca7d31de3675368121bf7d699b6c367fd7b28efac99ac337a88aa830b7e3ae2ab4a03c39e7d55553cb70ba0e95650daa02c7ab68854a34920a2c960a2aee4e92958a274efb264c054e4edce32f7da6c2354516a87c9abfebedcb277165fd8cd375c8c72729e39c1fdb2ed11431774d319372855e2452a854d23c694fe2d18726058a597533293329d4435d714fdad19e4812f022572f05729704b04b023cdc3d4c92312deb38648f156f2a01971450a1eeefbf6e7f8d3ea9c3652905ee964f338733ceefc3cd75490183fbe3765f44ef9ea9766ad9ee99647f9635c9ee8be47edb27f11801288fc0935089a6f7899fc46304704ed6f6d964c15d11085296962902383c54a2e9bf555334ebe3c4fd1a025ac4fd1a02563c54a241200a77a65c739f87c8924cbcb5ed8f74aebb92350ff1f1497a1207d576f588ac86dae8ec2cd5cfd5bb6fd591444565b581bc9649276ebb941fdb2e51c6d7e644f1da1c796d9137775bccd8be0f563fd368b71ef265edc442b6c6397157d1a9e672a393e854734e3527f44df6c683e794e5ad2fd1cff849749a7e72a3121f9f9d26998f4f924896180a27f7d0e96da7a6da922506423e6edc56a79596e4c7e4a9795802c590d2121e96d090099f4b1493a7a6332866307922d5c8fb48babfb2a41f1b12f364c2d80889713a270c549675a4122ad176cf24eed751a0844a345dc528b87b8a983c7594214c9e5a8b03a0ec3c7300ce2bf9db0128689bf10bd94e5f2493c9927e3216fa19f2e384818cf25f1d92dd17f1f149723de1e44f0479e286874ab4bfdd5a9ab2fc47393f999f14b2f5df2cb94f13a7ebd0be9fab29fb193f89ce4fd61fc2b64bb4c9ab84a3a3a4b3c30012e4dbb5bb6aea7f1b4f0f9d219cae38243e3e5bffaea58f4f6e74fa5c6e549271ce3d6759d611a7eb506e54425a716b3c9244a415650b704101555c010450008f0460f19056436d48229b188d3655dc4902a96702aa48409204b8879fb37b674c6d6afea6bfb76b6bcd41b1425d509c3cd4e47d283d5e8fa0f83b6102279a9ca0e659bf86b78d4dfe5d4b8a00331000055f9af84c75d3285911d072f70364f170dfd7b3031820aca1e54625e47d24da6f1b8ed1fc3aaaff850e707400d03dcc914906f8c2003f78583f1b40c900373cd4fad426de9aee9a43132c68e2c9c323414ab2cde930a564c53561c43dacd48687b89818828b8929357f33aec5e8b6e1d7eeccc584c9840a5d2ca15b42e75a22c7132b7ebf4631bed15d59ab359ccdfb4d375ad6f3d6233424df34712677fac4f96fb7923564fd7cbb96d658a8afadb9214f9a9e50770fb7b6396d67e1b694fc8c2fc6bdee4890127a32c1297103259ee88aa32e2592dccd9a37dd3fd6d27429e1ae24a84842497932b1fb6fe4e954b5b54dda924d49d4e0ee39b8ab0059dc3ddc96e26dc3745775145f5a4b6af365ade2c6faf99e54575d01a0e8b3e2b6c515c00c0bd013ea8a43428b7bdd75e3dce71f772121c577fea66b491a0d89a14dfe3de9e3928ec8b51c9fc48db7de7c0e3a828a87e43db18d923fd2c7251de1b4bb3547314e3ac228dc6d33f7f4b34e721d11730f09a0c5afcde5af691d4904a84200a7b0e64890126ac3648dee3a7e2d4680210ff3efd2da86dc65445448fefe6c7e59a3251911e5663f7f13bed5658411f770ff8f34e34dda6a7e92112d2aeeb6b336569369ac25ad549b1597df28d4f45a5a73bb769f3863f2d4da525d752e274b2ea698a458477735655963f4eaf0e392643f4e1848262bcb1a24d33b24aa2b4dfaf9c98d4ab6cd592322f9a4cece99fb6dc57f5b6e54229bed72b5a3b5fdfddad64fca6435b19fdca8c409030da0e52ae28aab8828453895bf8b18ca8d4e38dc55442c54a2b988d092e32e22a67ccde651d74e7d4f229edc9568175b7ddfd4a7167fccd8e622622854a2e9fd5a5731bf4d249f08193c54a291f7b58f0f8d07fa8fd4a39373ee7be25ccdcf34e252a69dea116a53d3a39373521ba2a0d8cff849f2e74e7d3f67b7aca6e7a4363d67ece79618d7446d65f96dfe9389287e6d5773e4eb22a6119740bbe6273f89eaa59261b5582eee3d66eeae7abd72bcf0824b8daa874ac5549a4c37b8bb0a869c1eaf1eeefe82e1e505090c50e9188153821120a20c99e0c3dcb163811577f7187ec822cadd5bac95ca25f5793eb87b0dee6242777956db93942cf15059d620d2e224f9cbb206dd6f1af2a4c5294ddca749c3c1f57400ff8b371eef496d849e905c4f323869cbbaab8d5e7ca9ee2fb5a19fc34866cdb4382de6f0d6a76edc3b279ccd9bd535912c2d4e64dabadab0cea499cb386c13b5a8b3a8372eb5aea3489e48b79ab39f8dbe5681ead69fb3494ea4677ac891e4887c974f5d3f272539d25bdbf2b7c5e5a093380e37abdd5dbfddf7c44064697141aead91fc1b2779a6baf5c561eb2ae4ee41eeb9e290888872763327c4cce5216cabb91ae9df67cdbae66ae4fb7e6e567335caf5c8ddf5c62592f68a4b528773901be54625eeee983c917cf0c1dddbb97b4e9eaec9dd3bbdadddbdccc4dd333dec3e3e2b7fbc35e8469e368cb7defc4d98487edbc545bb3b7b7397b473c2d9c8079395a9c446494884d05d35dab2858c21844058400dce51e00494123530e38a6b810016402db1445d0a2a4d88219e11e507e082ac2f1441c58b38820720282054dc29064f88210113d0bc6c620c166c6003385e8d2882d3f9423d0707883120f042891761e0052b2880060c70210cecb0e5388115af81082f9ab861450cfec3d5a4044a7c208aef041d1da5e06ae2a14c0b44a480dabca607258638a37e0e43cd0bb430d108719a5a03683ca080390b46b8c01764c8f0e42a9c9143074570798e63c78c264550200137a103608f190c40052fc1c90b4d180942c95f479440054d249181db08017d4201352a4f35623610c3043f513c86ca929d12a0ce7882c919a1596419fc25688ca72c5570c05d7ab4387aa206503cb5863200011e54e09e584c5620a288243af8ea8a920c29b648c257de1542f40122573da5e16106368280573080021397251cdc81092526104413415239986d19c00d864a09a0290a53872b9e5231300a2c5e8882fac2908114412710e0e94382840b984c5e501f51179985224488f2d5f8e1441143977a57b4d8c009657481e349a1828816505e583c2080b082024510c3c84b92c50710d0c309eaedc460880b4ac8428b77e389026e68379e78542e4091344ef0e433c039326e0568f12a41ec185e98028a67c1c20c11c02dc41c8a13d89dc40870bec40e34a4204636e44334c14303352660c54f235d1809020446dc8a30d84d718228dec31446635491c593e3e09200db0448166e845c22c30f4c7721516025945b20e13448f1b2829a26aefba8460420f7038fe740c5544338d1e236581881011381171e8b8185a817a0ace0395e37353c79c089539b9317441089c15998d9a902082568c05580810a100709a081a300448e260ef85101372105145460070174380968384006481fa880bf58424c452441e4368c989093b4012d2ec3011f8800070e311ea3c4062c8606428739e1081ab8392306ee1204a5a01b362082b77e50020d9070e2f3d64b0c3050ea0012ceeac932f3840a20f8ea07338e3481040f5c0506095c801101ebaa9f0aebc10b443898c58c01127003000efe989201287478c05326c880109680aa9ec2f50007811c74e129572823c51737f807b503f0023dfae71446168f06a27f3d4124512027c6bd2358008806549e70af045d6c192ce1718f01b02258400440b8977f761520c270cf089473478c08eec950a505174c10732fe6c6029b0f28b89fd1020caa1f10e07e45015350118203b883e0003bb4ec92b853c08b175c81048b7b0358a416167cdc0be06ab2016cc13d005ab42cf00410ee4c5820030fa480bb4d48aa898a8c3b0f32a87d67e0c0fd68003a80a1420eee36bc80cbf18026ee400960818e133fb80301c3dc32acdc7b7860888e0d5ee08e3364bd20018ffb0c221765e423b8c7108431649822e5fe827731ba0005ee2e30118111472080fb0a35d07e7c0ce09e026d479622b0e07e82093af092c2c5fd860f4c6831b8e04ec23709d1920277571154c0c00921b8d7b882c40bacd881bb4c921a1dba30dd618a5083062b31b8bf848006fa810bb8bb54e142123350e1debae207266460e1ce3ac14d800942e0cefa968405d081fbaa88192fa70d779514991620f1b9ab6e8481050740eee093033409238a3b9842173e1ae0857bea0a99d60952b8a790d840b90114eedf10608648e2c6fdab6202251c200bf7cf26c31f39c1fdd3a1c5160280e2ee99114518c4e7ee714026809905dc3d2588503406cbddbb19fddc12e0ee015569920615778f46084af40872f7c01f2a600207dc5d071e0e11057757010f54099670f72d5a004528c9dda78040154980ee0ee5731eb8c1dd9de0e055a5e6ee3e14010d2e9cdcfd02008503b8b8fb588314272cb9bb0e31025c51c4dd8d70c45c51c2dd89fc60d78475f720518021821eb8bb8f8b89273877e75193031626ee1ec2e0032307dc5d061c383890c0dd61b0c2801f9edc9d266a69053cb87b0b4d869678dc7d66c9e5450877c711c5882049b8fb092e34616ec0dd4b98411753c4dcfdf50222b2a0c0dd5d2e2f58000edcbd062e7763e6ee31676012a4c0dd61a230d1c3e5ee2f4cd048618abbbbd45498c9e2eead9c0d027004776731f1540606dc7d7582b2c708775fad401343c8dd5540e0d0438fbb83659c4466dc1dbc3350404440c1164df8304087bba778422203b8fb570327b090e2ee9f134f4ffcc0ddbf249831dcdd7972f658b15964c9b3de9bae3557f3e29cfd5aaddd9a6f4cb60da020eeee4c487777171331a5837954451837b6fcc0dd4129514c6154c206aaf87077af06267840f2c488066ce1eede113b70a126ab7eaa70770f04a920566003183ee0dcfd1bc00b371c6003184a6002774f01a1073d5460025c24a007eefe2949810aa6e09841184bb87b6a4a0c019266aed00191bbab68c8c9a270e2b3b9c2dd3f23436a20e3081d4708c1dd53262861a50c27a06ca10277f74c090000030f5062060e77f72c40819acb6c21050aeebe52c001a23c307c8e10c4ddbf3180b0c40f693861031fee0e2e80c64a00ce044b3370f7fd77ebdf373bf48e1df875358f1c0969b45d49259af6f1b1958f44e381bec6818636e45b4aa3d5fd39fab89d7150b875ed447aba2b8ef6190759fb341c1296650d0af7695e4b3f8769ff423889f66f2bcb3a86b4b2ac41b4b7d9d01bac3933fab789788be2bf0ddbae15ef97dbe9b4e6ac28d455c45bb489babf22de228dda70599becc984b46289b1298619db3e87713a6bce7ebcb828c45b0c6924d18c76f11dab356748629871a51b9f4ca8b6e64cc86e9669373bf67d5b8e346bd65dfe263c6a4bd29d7e1b3aed9ade6622e1aeb4d930792bee5a32633c9678c41b67f335b6d55d5973789f955e1b5d446db8fae8fd9ade6c98964fe29c3ec3d7373bbbf1edafcd3567b3495a5dfb1b596f74b77f5f4b6434a3a47d223b31ccb9d196dacad7db52a0300ca98dce0c40d4266706a0d8be95bc3fea2729c5dbe66da90dd07d5c0e34245f6b1c79928f1bb56975766624a468764424cc6fcbd8f6e79f3724917fbbd5249af8f9c98ce99735ab3536e9ee6bfa4b9396189bb98c6d35baab395a96ba6aab6934adffee116ffa4c35a74b5bf793f4e65ded9df6d678c828d4bbfc27139ab12d69dfafe567aa4f7c71c68d77a7abd611d65c4d1b164591469f24ce26c54228cdedda5bdd9a56aaad0de7ce9cbd368771ba70f74c2553fe1cada415f5df33ecf177ebad7159c58cf5f84e7f312dcbfad914456d6b32c3fd3ae35d4d28899128da9acc126393d27bbbf6e6b34985921851bd735b639b0ea55b631cadd96afae5aebce4db2cb5c13651bc38d4e43795587fa6e4c64d63ad519bdfa7a92d49dfac7944dad544bdad68e6324e0cb12e6b0edf201a6afd99242bd5e5df5b71a30deb7d45263932fcf34f263457ddd561925ebbad69c7cf5accfbe6d7db86ab2886afad2e3f6e631aed7318e94dfabb9296bc75a4d5b43f7e162fb6b4d9671c4422a131ed6afb85c48c6d62480bba5d7b6f168916bb287fedaa7848afdd39d905710fb5cb5f3b1c4e3a70024198b1cd673cd24ae94ce76b3fe37157271c1d16d74d2971d24b0745a7c4dd431d4e531996d2260334d9b82b2db9d8f2b08486e49f669c5bd07036a4e56109cd76ee70aab05bb0a15c1dbe4cb89b3d6bf9cd53d34dbb38ec8bb5160de5617e3bdab2e668d54fa1d6b8480fb910dd3ab17898a1f8c599c93da90d4ed7a1d8cf9f4c5ec8f849b28bc995ad9938b94c94d86c98898bbe501223f3cac64d2614770f4d236a33b6bd4c9793d80a7e52f19273e7b6c62da7dff7c7cfe2d638a7cf7b8acf84cd28d7f47a7bdc6fcb8a489235072557864a34f1f7df6a7e3223d9164826d3670db23519ed2aee2aee2a927fcf6cca8a7ef4e7fe2867f70f5e06f110e3235a6dd3ac0469c83481274e537a1faca636363cd042f2df44c25463c2e14e5322ad68b3abf1400b773b5773571bf56b498beb25289c7554dba527e412cd7d0927c4a1da2e799285b24f3686d3e2e10bf7c4dd71381ede4b77b5a0db15cf46478e86e8adf4f6a4e486e3a1b6b6a8c76d9b140fa9cdba7ba849224b7e9587e25ebf1c9f86132ad1ee9bf83d54a291564828aef58f24ce4325dab6d79247c6a890fca6fa1aa5f8683a39f6b81e5d3530f2635a7715a26b4feed78c3cd4fdad51aff55571b5a7d2aad09ed094b8d3622e6a0995682215f1491cf2dd787f6bab7535772fb1872baf1ea2844ab41ecc1e7094b2b8bf94a428392929f912a85089b6c4892f315a42b5f000e5a112ed89f340e30167872828dfc1c90e467edfc43be0c0e23a4cd1c1e9a5431071bf7ee9e00a95684aaab82b49c0dee27e5deeed5473e5dea2adc9041aef4ecf709bb43a11b7717e1ff4e3c6cf39ac7518a7457caf0e9325c623169d6a8eac8fab4c1897e2ed5afd3e58fd198fb56a736d12ff6d22796b4e6b118bb6dc84b7689e4914c039c987a41c18a7a3d15dcde6df4669a6dd341ba636b47f1b6df66f13df26fedb44d36ed90bbd4d1472d3b95dc57d5fcb7a7c7cc8ad4553231d45b9d2121b8cd3f1b08486d9525d71afa3291e9219db6cb5261d3d31d5dc5f7c64e4ae752d6f88da9556d7bfc18a1b947878d26c48fdb8bd77d5157703ce0d2e6c6474c5bddcb8c9c8c93dd4e16b3414deae110e47228393bc78acd844a2c41d090e1297874ab4571116772f82c24d4550eea97f57f5aedeb26e6bd651466d6a904cffc6497ee3243625368ac984e88b654c233652b7aed55dbdbf71925d3da2041f71b97b686b46b46821a8b29c198152564d8de0fc766d90911e0f33d67d0e465a78cf5e45aa58f22bc5bbc8114582e8dd33d1cf61b2de8acb2238f6ef6c88720f5f365c711b9edc3d5f9bfdbb970d384ea33b4462ec94445c109961dd95d888863b920867084bb6fbf3d0d3eb9bad66ae8e43b4d7b61ee9be8846af1db22102e5eed5081127770fb52532e44ec415bede2fa12bee4e858e92d0c7ed22212a7eda849cb8bb108ebd65ac752409b53cc4b9cfbd8654d1f80e6142f6f9dc15e73e37c408e73e2792641d12fb212d0f956858a0c81702458813133685e4102ad1c87b0ac982b6ae466a365bf2b5add9ac63d0134146dc431a92b616240344c543f25a4a968fa37ab4ba0df4837ba8236ded05640372e56839d0ccd758a7a38f4b9a51a129f140a3f96f179794246d4de835abcd5c1e925f9a6726ebc9843ede543f699bc80f72c53d2ccb199dbd8240710f5f41704186dc83d01aa2dc6bb8524307dc3da477e352d76054434cd4fdada15593594942220449064566ba6c4826030d57dcab99b344e8ae9a3a3e3f2e898628428868c8cd643531912cf16713a96a721c227eee1c2223af2df213c5fde7c943255a55f2135e9b1349206284b76baf92c8030d0802800c79f944b987485a47cdd53471cdb70a859a56ddcca7caf54180bfae6f24fb0409956864aeb876b198ff76b379fbb8dcbd2cabf8238b157f40b907fd781242441f97f4e347cbc39a1825eb67dceec1e2eede0315d26ad403c5ddebe360fcd5e3430fddd5529f179bf6d61c2e8bf8cb8795abc3a40f06f8c09b9a55a7730dcdaad3f4cb7137becd967407ddb8d495478bbf266fcd3d797379ac78f8241e79a4f06822dddf27f198abc9d3727792ac3daef498d2e38959753d708e4bf17bf4bc7ae0e06146fe5bbd35272b31aefdb57889fc5d370f283c682f1e74070b6db66380d70e939d15dc43ddeb50a19383ce9743829c04e40ce5cc7078f0c27902c7c9c3cf66ee4f4d146e4babbd5dbbcbfaa7d63735345a8c925fbb79e1e0e0f01d68cc5e3bb4d831ee9809d1f030c762bb6b7e5dab3638d06a697316c96a4bd2b27d85458434f7b086d694658dd15daefb9e256e2aeb2cecf1b035bbc18087341ac59bd2688931ade6a7d19b21f25e5c74432d5e32b18d96106f7c6da0be66f3a4c886e64eadcd8f87336c99610ab5c17b776b89b1f99a8166337dcd80c3dd5f3290b62646673248e0258391bb87369a31c59b2ad17c7c683cd06b6732b4428a77cd150f31ae89e2e1aed4fa4bf27546af1aa3d0de7049751d2f119dbd6a78b8bb117fc5b2843adb1a8be2545f3127d727bd3616f39c2df3697be9d0e21e9e4c9eace34b47938e1e2f1d5f0c54c26bb10dd71ea11da1e1edd2c88b6b7809efcfc5f044bb6fc4a91ef1f1a1f1f08a01c7b7ae653e75d10b862c7bac4e0f0403153f77909696181bc1b084a9e6f2d7d4170c405e39b2fcc5b8fcdaaee66898038a53cd51ada3c43887510edd5fb1ac355cdec451f757f757a6fbab4b4c5e0c54f376fa6bf192786daec4d88441b9bf60513c54a2c14caf39f1051b7ac170b8bb4893c59d06ea4513c5dde2251ad3dd69863c54a2bd687078a8f4a258442a2275628afb69cd43259a1665245189b1517e1f9f249953cdc9763d0ada358b5fee8d336ecb6a623259d20f0ed44696f4935f74aa39f15a594d7f898fbec459cb927ef2b300e5ce42149c3b0b41dc672cb4aea52b507177aa4768fab5822edcdde8feee482b92565c2196b335ea3553e535e3805089b623c9fa1b37c95e6c3e1b511bf2f5296a23375f2a68ab823b4d218a3e639496312d0523f7508fb629bfdef8e6570aa0df5e38aebc700ca1c43f97f5dcf79bcad7b9c76dfcfbd65ccf1bddf8e2c613e9666ce67e536d71e4f8f185e3e585c2c6979a1585261ebeb61485174ec8e21eee9b5dc36dc95b5f2770e0568dde078be4e393f4b76afead9a2728799db0e332d98fce27aee16ef6af48debf55a3ad6b29a336ef834532eb0ffde8ece080f725a2363da7591ff73e58245df413a4f7b5356f7df12833fa193f8953cdbd0f56d7e0741d2a8ac98e72e715cddc293ad59c282bfa193f0929abd927126a232bfa3162e6f21091993bc56b7340331cb6ad1d0919ca2f931d0919fa01fa193f09d3586b1907c98aa8cdd08f98b14dd455c4a3ace86797f71da26bae55ef13977b376113e32cd6d75a8b2253ae3a1ccc530f8965dd17cb9ec441babf75572164fd21b23e4ef65223aba136d446d4fb9190481c94442489c6266c8aa425ebe332deb52c71503e75cdbf1baf4dc4a279e24ce4cb9a354f9c6fbb8a385d87649f71d089c58b45f3940dfd64ac716ada888f8f8fcff84ddbd6a84dcf6981867eb6191424bbf8f79eedb6fd193fc96edb1bfc5543898daef977e5ab46cb3dd4a5c5e9e8cdd6d5466fd7daa02e253592974c14f7f02523e41563860e7fc554f18bcd9386b87157f27eae396aa369483492a675b82cb18dea5dd5bd629ed036beaf1825af981a3058dcc3fab917cc130fb57dc104a93f44afbde70b4626246bfe172ca112edf532e5f55284fb93ef8345aa91c9927e6ed73ad523e4cb92509b22e2c625d2c6a596511b9288dafcc64990643f41fb7e4e964412ed4722ad115971b9aba6ac06370d91d9ea1bf9193fc993b8e867fc24d87689b6c646b86d7378b5a4b887af16cd29ee6671af56ab159a486e701105f26299c02b2eef97a2d5892f96d38bd5c372bd566290efe393a4c377558167d2358949d72d7bad68af55cbc3b23c6de4fd9beeef67aa82c2b55bc7970ae7faa51af21f6ff84b15235f20969cdddbfe1148c5c1a76a1279814174ddf8e6627d82383c24aded73b58849d7242aafd493570af74af588e42b7582874ab4ddb63299918fcfe7aa7d7de6eb1b7a7d36fef2b2501ba6943e2ec9c727e9e54df1a497f78471ba97470bf7cb6bd5ec6a2fb7425f1ee5e546ee2f8fb9d7d9cb7dcb94708b93708b120fb7d02364f1f075c599478072f790e9084f47303a020e235871cf9da4119c84f67746a0b95f6c049a3bc934b2501d6940699bc693ffc5370d2569c4c2671a6b2e42d417218afe7cc3d9a4d7d24a6db8160157041e398caf0ca7eb104e575c59d69c48045a7edddbc4bf9808389e3bff469e77085157863065084f3e04a350892692f7b47d1e028e330d01a62696cbb5acfa73368969ac7997650d92c9aedd9565dd329bd98bcdae2c6b12b509a236d40609d3587352eebc5d4bdaf149d1a9e6aecdd9f1c97d3fb7c77a5fbc36776d6edfcfe123e2e76a7e36f3d674b4bb6ead2386dbb5b94cca64493f5f9a6752109e8434928816841e5bda6c185f0c84a81cc67706842be1c54540b800258764a639a3ba529208083beef56b3bd7c7dd2f458ddbe74cd4fd4503aad6e85f7c040d21704023481dab6da62d89cbbf71375bfe20ea075642259a0d8bfbe26c13af15f769fe60caadd63e377d36f39be629de6acdc7476fa7bfa5ad9bac8fab41a236496262fe265c9698247fd7cf3e802a4b7cad0fa0f800e7a10f5ca5ddf7a4f99b30d565893310a433b2787806957cd6f289a90d9ff1343b03577406f5d7e15ba91634b47ca1e529dcf7cdc76d1d2ea9b65a9478e8f4e4252a2b69452d38ccc8e20e152ad14433a298e1142ad1cc30720fcd885d33dcbd0c28f75cc6b6fca60f65e0ca5012de722da3e5feb9f6600ad575ebdb83c777f7a0c7bd07ae5089b6f1bd270fb0f0c002f7d4d9a9b95d7bbb9607d4fdbcede02ffe1cd63b98e2e10e9e76d083ef0edc756fd381955007523ccc98eae840498d6e1d97ea80963607583cac4772f064476d70510e681ed29acf3817a3bb5b7340ab2e8b95da2e0b942c41bceaf2937786031db8cbb67e9bf11671309423e280de408bff0d40e0bafe7cce26ddc7e96433a77a24e31be0d4bc3fdf405732b0e419194f9c8c21df6d3270b87b38c695319eb8ebb2ac3b8f61e43e1ba3860daaecb6ad399b77353f531bf2673690e2eeb8c8064e5c36303d24ff856c30a45d36c0d96d3337a40659dc77b7527da406556a20c53dacc19310a21ae0c21a04a135a035700fb5ae9dfae52e1a60d9318d7623d120cab65992d2c0bc3a7c533b916810730ff3398e98062cf7daa965b7cf3232563bf5bf4d74aa39a3fb194bcc3596195c99a27f064e2ccdddb73d99cca047dcaf67e0f2da29832c1e2ad172fd72a402c526039324ab0c82883258c16ba71649b2ce9cea116cbb56a665d4462f695b696bee6536d1bc991bdb4cd65e57d6db9764f95688dad4d45d85509bbaab9058dd55c816438b7b98abe3d74831a0c488a2fb22319ecaf2472b4690fc3a204b62e070874116baab516d61b085d66104032618189d78476d76358a936630c0f1f008067eb335fa822be10ba4d48c695935368b5e5056d70b70d0abc3e4be27d63a76bc7541155aba40cadb5c5084bb93567c5246446d5c80e38256ae3a2c4d389b66bd42c5b7f9e358af3cc15de9c9d6747a71777f3bfd1597bfc6e5d88231c4ddbe27067a5b7e8d4d9c4d7157f14f52cc78d77c8efffacce16cc3bb05389c0569380b2cc0029abbe3cd82180b5a619630a6b88761863561d0ad698c86e12109c61530a884e4eb2a6e17711718344b7e1e5d60e0086b32b64d15f7356d73596a2b80e261cd0a701eee6b7354d71c5e410dde314aaac00c1544d1b8a4fbb4113284ea70f935bacf9a0a9c76353a5301ad3d496d68b4b26e9cf48596b2b44c3abae30b28f79026f4c5d3ec8b2054e7ad3fd3ddb6a43d99d8f28bd637e5ff5cbd56a0ee5b7982bb591cc5785bc1b9877fdeb7d273f3d904b2d2a269b2c443e46bb2c4b822b2c4ff19c8c72729055452e0c4c533054a5210732fab68fe33a1206ad7f1b3f9a4a851602554a2a1208a5d9f1445928869c44648ab75d6b75adafeb3ed043c38019418bd27ddb62f1f9764e909701e2a2de16109bdb313e09879818517d7d2fc391a44c3bf98b4619a76aa476854575c92cb0b1c5e7526c8620229b4ea6639d87689744c80638256a844d325b82296608a6ffd4d2520c2bd29bf49deae2d01908f4fd28f1306aa65594712946515a790c049937d52d495e64e82202448c171dbeac83fb148da6a3a3de9f46425712edbc4f7c1ea2aa6bbae42436ddad16edd4506ba20bbc0f1f099eaded9ecca5addb88856dbf44a4b6c785842bb68f908b0d4cfef83d523785213a323a0b98737fab9ea18818c8b280fc937c9f2c463cd7f675c40dd6b69cd8f8b28174e98b8182282dc496a4bc98bc7d73719dbfd9ad62c821188c0741a8de276c63a4ad315278220ee8e13c10d4de25c08ca0801145af3db7cb66fda643c0b01ce3dd4f67154575c08703c2473d5659c04022baef39bf4fe787e7e0d8228198f9f29089e4090e40281cc07a8b87fc089bb7bc639fa015ad10782b88764aeba9adff58196bb3b75414d710f7518f739acbf56d60b6586b46b8f7c49773d42431d2e29c64150d46b7e1aabffa864308a26c29e754ca11901180000000033110030302c188f886432c96c4a7a553714800377c06288569d49a3288721849c31c02002000000000000002000d692dd89a2067f7b6868408e3cef9c792264d6a9893ecb9337f547eb263b8f97f54c86315561b9af52f180927b3928bb8ed6b64fc379229d0329e7ef4f1d0bd5123c5316ccd7a42fa5fe962db51f80a6364c218bef71d9802ca7ac1b03567ee934a32814b2985c97aac948a27a9fa1407cf43097be70896858a65dacccab0417aad0049f2c5032fe0865e686883715965e84b5fdcae6a94a193bdc42205a996bb002b5b2f1d2285723d172634ff5c379bbefdff2fc4396cb92b4d533f16b0a9e3cc01e14d7801312ae61756c3b234ae4f231dd9b38795e28ac6d6c4c1c4800fbf44b3ac03664957aa7100bd196d044e9494ad1a70909ee631401b06a2b5e18a463501a1781b35319b560ddeb94ee37d49dbe0c64f8f6a2a5e285a446ff43a164abeaa0ddc014b095694f76b5ce674bd987dae255e07ca50f7d361219dabc1322cc951c5435786746b9c1903d70bca4bd3de12919f4259031458abf4bb8d5d9ab27b4898a5e2df74190481f739570342e47ccfff9c25c4012d27e95939597204807e26ef580c429348e7251fdd0139bbf9def2210e8787b7768bb077004baeb212a0406bdefbdef162f660deea2f8f91f2d8da70f765e52cc5832a4756b3684bfc646930a113510e8eef12c50399c5561e11a72c361b48a5b8c5dc704e1d5e4c8ea0d2a180ce46c350434917d4eec13cecc98adb182d8005e12bf46c4cdd21ce40d37179071eb607c25857d15b3337e16155a860716f6de7743fb0e3b70320801387d5d96267d9000fdccab6b97a8bbeb8c3c5349f06c34ade9d55e478f81cf4c953b5934f568925651b39fbc1189ce152e6ee806b22c5e7228d32053171ce65b73a9a6d7123cfccf7213cbfc25588d19e4e9b461c4324d9a187277e73bf3e7c4992988101f2b10a078bf6931c8addb5a967977d9b5cd8da716e2cd1e9dcb72e9b7c27dd17d1d6ba01123c2874bd7b7880e82867db26d3e06c5c781dd9ca7658f5570345ecb37fc5a30334450e6605eb604ca95389613868a9db08d3ea8ad11be6ba665ee423b54a8f15d6141eb13e674f13062d694e73b333cda5c3675f4116ae51d0088ffc0c0d573538947e23c1a9f468da6754b3d537c844458a7774236bd371a690e1e207ba46bd6d36d6db941695cdc27f32faa4fc41d2a2407a00da6839f2a3266dfc4e9b8cdb2363a7f9051c65dc0ab40946a59774037094f5586975b7c00fca6dece8d16d04ae44c45483c7aafb3f439c2b3284b644d3e9ec26763e9731996de31b4dbd32d991aa9eaa80f8f2beddffe196a3b23b017d4448882024b0cd9a0cd46dd4fddb96292ce6f711ed2262f5289a3505557ff459f37ed732795ef85dae12c369b7300314bce1d16332b1298136fdab84903ef32f5ce1f95a2e217afc9741b96e17476853659e391c1f7860758f5c7f2b7478c1dfcf2b941d9e350476aa7fe7bad4f8309219c304495c98eeca0f59cec3a247b242b173945deb09e7cb36fa18386962351fc38dd2c9603252194de5c5d53dc0b9618c51af3f8d84e28deedc1e1ec0ed5bff7479e2dd16308e459f9f9231d684756250f0b6598ca40a318f27783ce9c19dfe45eb6b1a66323a9ed862650c7874bc3942e1c7cf22d91df652d0f529025578b4ea18a5f6877e226cc74b627dba170cf7ca4e5affe79b45a9fa38d35819d6906792f99eb1c4bad48d8e15664619dbdd46782aec32a17ac2d0ed4379ceae582bffd104a0c16e4fbae119c9706f852bde270bc1f530300aeef99bab4127a2e48124c6f9cd6df15ecbd751562aa42861b6f15b5e4ddf3c043061cfcfe2d961558b497d965eb88d77ae3de2898e0e1bc43a8955f41478aac0b73b34d04c0ad7adea8b94febfa0dcc3bf528f9d15c8ce45bb309aef887b25cd9bfc4b0f812c30c352881eb7a3a97a424031c85b5a65f162c1fa24f3917568c2d31a77f6e9ed8f333a84626584156ce6eb3a87a3ce448db525c8072669dd6b05a3a2451eeba631781cc2cc221d8d93eec7236bdcacfc99790598db92681842e4e81c9e0b8be7d75af87964f38606d640832ffa6bcf08e164962e524d60df90587e0248663bc1968e11ac416acc60ceee93536e010f638d28cd350999fc4d30a5eb05695fb7c1468b104e680d2713c00a338df5506a4a30012f38e463fc80a8c406f3dd2d73cbe528951181c316c0f79a79f5b96a7dacdfb96e9334b9db791e42618cbfd378d0f7891d46c6c0c86159163b5c94ddce1bc71634fde9c1f13b09b6fb40043071ff639d4957e714efdc8226790f68afa6c176b39a40529ed207b66d4f81c71518a4b6ca03cfdd2b1dbf8ec998581e0469abe2eacc3469de065e0cd865953059a6e24014ce1caf569ffdb333b2868abf01fbb42e2e0e512c409aead7d76d906d0280e151dd0b43f3ad491ec7903087095a3c7f1f175983020bd029e912a7f2bbb27803a37535ed42e9cad87410f0b115b864630ae285c5c7924d048c7110e0c6ea9af3ca215edf2ccb7c3995a0d3de5992671e4719eb3d9c1819eb16e9ebd8fa91f813845c532f8f0f04e76b31fb2ee172bce5c3f637f32bc75afd2a42797610a5be64427be1dd8d08a16342cdad3799aa2094a52f07a2fb0ae6a5b9593451ba1c4f84206b91af30bed3d8fedd2ad3bc2ac36655b539b07841801777e295f8b6a748744b08239b056a0e9976d4057b36385efb800317c07f726e3856156d5bb43620abf7b8f0e4a73f3a8a0edf4980ba59cb1473cd846011734061cb871cd393264deabdd6b4019d8b9bde92a56c08ded488d180e2bd1633e18ad28fdb400888bc0daf858edddd488d98100914dbb3f92f8510904172cc9731750c9d494add9b5ab7b66bae94c2ad31f9203d0d333cc64f70a9b1e244e1f347052e73406ab32298a26accd9a8b8c3250c6293e6e84cd6f24fc938a5e03503076185c4840b651bb9ae8b623100ffa6c170e818fccba81fc2f07b822e0a3383aa802231612ef81e0542ca13b2edcfd502279a07682ba47d5cf8617ff750f7e718041eeb9a6254534cdaf75ef291d72e7b8dd0fbdf57676f3734c400d159c385541fbc36bbd54572876b727fad6db4501cea8d5cbe0cecd41e6c28f3f4b19a5069832c0ba05d85f1c64d940f0785a3b294e4566ca81d66e9ae38e27e49edae11c4849fec4709cc064c8ff54d931414403b7d7ec72ebdfcee3ec27c360f091bb0e73dcc7a598c05812631a26c8d84af20a8ff0756a6e4ced63785e79c3169aa533c108f78555279cc61d7612276f8e886418efb8d951992c02aa0e131ecbb524ad68609d25663680df767aea52523482d78ef6f2da448bc51204f46c61b7c120a4c9f1e305a61c73044febc879f31ce44d8d1a173d2691ce5c6ef093aac95245405e5d63f6e5ce8c5884a75313826d3b824cdf636d496f457f4ec94e4922068f0c282209532d0b23a696f4c1c4b9fb8b1815f732ea36bdd06c1c374321214922d31233a500c9b46235f97f40f413188c717609a7e33308f296782b3a9fcaa10f27a01e7e8ae498ad90a81522d06de26c91a800c3099a615ccfe986fc466e232c15b9fb97dcbd6ffda675fadc5f21724bf1c90410aff2bfcf6d765a0475326c5ac1c599a52c79ecae4ae2595dd1aa454b56b4f332d81ad75be1bd4f651064a0ad015244d134cb321832b7ea7b48a89130aaef2e0a3765b517e05f29804f028d192519677b71c2a65ae8352cc71a311e91aaf5b480dd6c620bcb96a0582c95cf9b845331e4820ac7db96f526525f3863d4c65edec4255d6e091a039268caf0f38fcf88f4998aeb39f8d5321cabbd7060bfcc8f1580336c5cb6e8fffcfd00c5c0feea9824252e2ab5ab793c1cec4ba206e962cccefe55d55b700e5be40d0617f52cefa172d2a25474d0480a9b44036a34e1966f9ca779b374451c3ad4e05010704242a017b33e60f9ef88c277b9ccddf0c6d07adbf319c9b428c72fe21406d19b95c5ccff68aaf8e9cfc066245943bc05302e53543fcb7765fac3c5a684f29b1b3d7ea13404b7d905dcf85c126eb1b63176dc3f1ebf4d01774a9c0b95049163346d172b77bbbcbdce79338885ab3751e8a2bbd98aa40c435d2ff3e0f7b8333faecffffd5cd509d6fd852e63354d234d24a54f0d16ab89342be0bde77a0612e735c52f62ac18c1b557a850ddf85b689a682cede2c646ff4c57e2911a800e3db01a30ee5c4b20e876aafa71489c7c18e2049ab20cfd82522c210a160416fc426c50983101753bf39abf65684e1fd1da6e546652c312eeae89f6eab8d1722d4d4c5516877f522024e79a38022844bc16844fd28238a8114b11f1b6478e5d82d224ecde4ab18abdcb1584aad43f6bf0877e6ce77717655fba907edff2a6adf1672871b2833aa4f5786e468ec7fcf87f77f5a5cd0bca068ec62b7f1e50d13eb16303f1fc9ad7c1ec73439a41248a2424d0af2735298335c619b9c63b89dfa247ca3a42e8d04334cb0239258df2fe310c6a5578c4793df17447986cd41ba1a012db8edaf09f0a74e622ea01d893ff3a67249c9e0bac52b734eea15c422a8fa84004fc3bf91dd3dd004334d4f61e700a19ee9934803449b5272c8594c16a4a82fee224c2f94b09cb7a59309e29bc97d613e0fbe8876fe0b449b6e98fd207db11278c2bcac673ad076e4dcf9b4690a0318ab7c885664fc355277360d80107ac9dd00166da455c52883fe224de2c1e58639b5c72b45502c91ac2b8c5a0e37b5fb7b918f58037ead859dd27937fff82daf8fc280c6ef60eec708f3d16607292b6b566015f62c6b9347d71ce205cedcb41eeff61fbbfbd43f457ebf209761ebc1e00dd024a6a37065daf3e06aa5514d470a2b2dbcb363f4eb37b5e351595b7612f043b9f72af906cd725e5884fb73f19c201e625df7468c089242efe7e21ad677e56df6e7385ee0224e2841034398f46f58647cd33e1376a2f3dd665d6f3c20056c8c80a191bd015d21452e4e8c7c2a43decbe279af5c3d321b5b15112aa1b49882f1bb6eb604303ee11cb1c5ba5e45322d89e3b6d463028915bdf4b0155f47d127483af7238abf5ccc77ea30da2bcb5bc0688b4a028465dac7209ef3f59b18ee676930680818db0d00e9bc1f2ef747efa46fb74dc0942ac96f37993b345d1cf0ce981713f4cc0882c313139f32ba8aa0b8c79296d210d3d6b3c4f6b6e65fff1fbe9f50e1f573b4ea1d907377c9b6c87666aebdb9f0e34921dd45b509fd5224243a4ee17a6b500a69dd2b42417d2abd954754c3abb6d24668f99cfbe4ed879265bf8db384bb25bf52c9e010e7714029b9c8abb735130592a33191e8e6f739421113b8f1347d2d64fe558ef084738c390622e8fcee36875436742264c52d6749f0239dbff42c936ab380a136032f94305bf9e5b828231aa82a4ad801e0a56c1837fb3b761168e84db526247b7146e43f3bc39bcb4d956b26e78bbf770d22d8460019579af65d3432eb21e84b2ce4af85ba5ed1d4e3fdce89b7a1495c09665f5f1d8b5fc5e414ded8ddaf5d17ede24c172c633cab581d69613b550bceae86a243b65a2aa2bb5145fa1f2075d23676d84989c0ea7192d28d30e5cfb611addb1dfdcfc38247df832f02a615bffd7e9090054979df5544103d7c009eb2f0c97d36f22afb67f48a3d31b9b19372dbe81791fe6bb51e71ca9a2cf50eb859f8eb5d526fbbf8274c18db9648687b676840916c314cf498609f55db69d86cb07bd428071bd648007a187d04e2fe65c255feffe7723b17fddf02b78087df57864f36d17064976402f61c3cfbb200dc7d504f6087bd5f8742a673a54a7bedb1064543569159491cb8e66cacdadae10a4fe48aa854d3e2a3022ed38b420e42e96bafa616399106c6b0fc1ac83894b45ddb6d88d49a3f576472bc7ae1e887b0b09045ec44c14b4834fd6b865a47a64f71a853c84d1e131414a941ba5ac509cb556df5ee452a46895626506979672a023a8b3e8f718590152a7654274eeb772d68f512d7eff1a80a91399436d0d41e7d94ce31dba3131b9062a13dbf2e5be6987900e99ddde5bafa122aea35c210b77679c876c74cd111675762a84be7631a4fd9661eb0c21a4a0301cdec30275d2929116a2ffa19f50cc1e65610ea94b55114aa973255216f7b83bb7edebf092963a700b832493bb8620257cd16150b4495c90484e6d8536865f2bf3a7c06bf3ff79bf067df0c1e9e6a70bb1301a99a92bfaf9bb8bcea2b20145220cc0afc0f10cce828396e89019cf57071638856a966c84a40e9bbd741a4502b4e88acbffbf39c8e3e3d6c2458016c678fa588aeca103d20719cf82e358890b00c2654358361a021f224c680ecd596cf725e973af931e74db1e8eb73b799c3fcb91faa685a201c6a5336404d71b9afd72d2b74d5be80d6a0c52c00bce4b6d52b412deff49da6fe558563fd9a653b3f443465856d2e7a8721d6745d777ce6f2d6958af6fe91cbd489580905a639d20094916c0f171d72136874e4c3c2244c77bd5ac10cf9dc20ea6f28f818af27451907f0bf02320830ac0ea99aa58da056b01af064940a38f32507f03af3ffd773f84e270deb07a7bc0f22effd3e14fbaf7445abc51191556dae1aa1582a3897b75430bf7df88f98a5577f9cea29117be6a1d4d578768a5e0358c661d52f3b2319024546145937467224d2fbd9a6ab75764560245d533c77374316f89bc7ac32afe312e3bc0e102f7e74db087e70b7ed29110aa0e6f1b3e31ecf8699769baa465aa496ac453828b7912e36769c9ba06fe99e12f2c17990bf55ea20dd6e225aca9eb106b9300c8180461e1168cf025c28dfbe6c5d13d200b4e2aa4b81191c4a801b5783a5a46292bded8b21ede724351570094458e03dee6c9c9bb75539b86d22acd600fcd075ca71b0b6458457a8555b6413cfb2403853e81307577ab586e49842ade485779c6853fed15cc1da2a61d2e5dd2834379efde389ecc9cfd99738893b28bae06105ea9b72d9d59cc5898b91e93cfab75c208897245c7c4ddcfe864b72d39de6a96f082e2177d50f5bedec4a22d44f58517619aa814ea747434893c8a757f645ac97fe79de2085bcc9d0d9aa6fa407072c9a3cea7ca7f863792b42dc5354a7120168c5085d6069b9a1b796e59a76e1b54123654b0291f90d64ed25eafafe81673d35a682a077003904d9e5aa194d3e24649c3990ab32b176dc58381e44505ce42ee792bfddb4be6c093fd42321fd83529d9ad1b37843a7392c3029a4a07f004cf179e7b7b287cd477a5da187c20d971679efa0dd2d02a888146fca9036134eafd9236cb5ff7407e3ef1cecb60a014d5efa4a68fa0b271103d584f258a0b7a8e31f8a5d692d7f91b165a505efd59c2b63e9efb4e46e2b33426c70594b9ed7309d676c96b9ec4ce82113fda531e46852e25343d65342fecfeacace8630935b4a520f340304ad55d54d0a11915563a8705d265f404c5b399ae313be65d41de0e074a1876c7be57cac69139c0cf42855097306fc1e930467cc540ca0ce60b0bcc47d172cc3a48cb72335713399636bf6f7191f53d3bf77c2644ad2da57838256b2f94f609201e1675d1a28550421942e9e7d1bb37646b3cab793b4f10c9342105312ac5f41551b0085c4b460664139b5820041a64502fb14f75a4680e517adfa42ff7ead1de5e4754407c42cc239fbba19f41cd6e7d3ce50235f084d70e0930c03e6fbe4769637cc0996ddc9142a7be9b9077a758057a1bd9fd15ea85598a6306d574e851a003eb124d01f227ef13c6d67392d0b5c14903ee672ead8d6ca558ff0c4e78024c888763afc1f731d74194b7933f06601b91c728801837952e683bb15327e9815b74420a84edf96736c59d47fe5953b82850fea506205627d2a9862e2b9ca52d602893c6c66ab85843ac046f2835bfcf384b15309e1eadd7e40c54db38ebde76736d7a34f4cae109fd1571c488d26c1bc20ff47563241488b9700cf227db5c10585b35c76c3c1f445eeb5c9121aa8ac0bbdcd95f35a0ce8b4f353a92cdc680128de035b614b43a3b2ff2b83a4841e7bf63db986ce1a6d8a664432f238545b160c0b2442fec0a8ab389915c3ecf0606afd76f105300fc505cc00d533634a581e6803154a89b9c1b6ed49be65335b7021b4607fcbd0ee135394600f3ec68cdf530ec3f1f914c74ca5d02770bab283e297583e629040790b7a72b8ad2e5dd3cada93ed5e878baeb05215770fbccb2f250456d8c8a6cd3e54c135f5e16ce08a7407526dacc992fd8ba0b5b7d1a6ead82fadfbfb453bbaac76a14b5c5062436b6a66768589dfa7de18a75bf74f2e672828e0fe166d1a148ceae954063ef922a0c586dfe00da81a82d060437bdf7c1731a8644e552c4b3c7688e13ea891840b7f7b1171cda475d4a6291f4383ac25da4bab0802dab6a8e50ce03d3d91b280a65c6eb141c1cd32e4d625122697914e9e90665f66eb960274903719ffd75992c97b82ceb31a4ee4c0856ff2dceb058175f10743c3d8981e79521b3d1552603c440446311e3170d66fdb271015af6c983a3a6b0c69920e88b388d83789010877aafccbc8c92cb42c6bea2c359e34ba9ac82a1f49163a545bec01f6242361bcb9bafb8c6c5c482ff672d1db032361e8ea805ee1e4d949fe486054f487554fa56aeea972a015bc40eaf33804848889effa72d6117b33ba0947c13e9b06426095264a4e3914fd7764dfcde39aceb7797a0d2374db0b335be381acd50ffd64aa375d20ca56ebc59d3631fff38f0d42c93f2a9f7eaef12c9a1a7dfe11105c7a86b045beae61a9123239c2f725df263d154ed7cdd0be06a8417cef1a9af0b7c745bdae38cbe98dca6d8e0bd546c8de3ca47ab0541b7fee0eea3d0a0c096c8dcf95b6c34e4aceec201d85d25e0d9c460af3a17c9eb0d1807fc2d871c877ac8f556996ba3c80a6d43f8858187acaf866b68a143db8601c3daa06cc3bb14a73617c3c6cf6a6b77c7c152b82b587bb9a03f480b53255ca5dc86201436023d740c13c5988f7766ef155ce320ce0fe77f718f867011162c4c2ee5864ad41dfad3fdbd2c36cf56cd7c468da0f69203a912cee4608f52d9aabaf8b81d5224c5a3786c1c601fad2d7070c45973fa8448957be63bac6f50ba3685521d04891bd225e3abbbe5442cbed448e050b870e1362576ef10108ca0a70b8239f6a637a0462ce1becee6b3a9c800c37c86f8f72a549f70a0575373ea6e01170d4df75a563c1caff18268dd36d50069a13c3225d5b2988a306fb8d7d934a7b4f67f671f39e00f587fac140665b879f005e27a6b6cc6524141377d0c6191e6e534172affffc9976124701a3681a2ce395c7e1ae7aae5c147ca799df11308f16d98c186f6e0b1b59e226ab43d90731882c9a8ce361360e299a0174f7308a51798a244cdf3518329837edee9cd701631e806092a07b2cb87b321ae198250a7e3235103b136d81619e362783364a756a0f8bfb3dd1ede1afbe3be1eca091b71f2c437f1e8a56ced8479d48830488575029c59d72bd9b942be5a88ff2bb9a451bf8e8d4263e4e1c0ba85dfd0591d9ada146f9784c35748a3bd05f7104962012ff6e3aff5f65eea6963640bd6a6ccd0c09fb0c9bcdfd46d88c3cfffa16f09586fb6d6f20256ef4b2d5f88c9d4edf57f26787315e78efd0f5a808913bd3c016d753504e3f793b6ad001f624981f5704f764376d9cca78f1c60408c2b3469ca016eddb2ad279fc8c5af5de0d90c69dc19b412ef43400051f42687dacc64d0367ab8e1dbb5d3f76050ad93f0e1e9262ebd79cec9d219509ac0f21750283e57b8c0942e38af600abe4abf2132ea67c904c610da4fe76d09b104335b6d67bd34ac676335d857362e7c2c564b6e0ccbc7271f92a57372b7c9ca079143663c05500820ce372429fb448ae18d8a1d7c5b60d52418ee9c11072035b779f9158082811d473001bb0e46674dfa88d47f39301818bc15b7e9a9a731ab2d9ab621646e3ec51aa0ca1d1347aa852efb6eb3e67a2e19a9ecd364edbd4a1b6747034c536cec00ca6c90f7182ab8e8c00b719665ddeb231ab2ca31df3e830881c7ce8c1d2da603c6cdf1db1781a9cff36a1d86a798b2250f9095885816c59b7ae419e33543c35ba9533dae441fd109a46d036c88f0f468c0a6c49bea41ec18f320291d3b274dddcda7b170b7712cae036b4845e0c652078f69e7651d9bd97c7fac8fbf3e533ba4a757da34a73bfa7e2fea8f6d950bdee5df158f07174e22a6f3c9392f37275426dab6240b5e06c5671c3edcb50dfaf6246730408b89f4bbfd0971dc8d19c4ab9b7e6a9d4320bca1a77efb05083e29d040fda88883789df0281bdd46506e13c0062528648e0e0293cc40e004a4cf342df98f8d4e8286fec94d5f6bd40f804c2f2b00c687af67e214ce2e4202da16c0cfb6a68e252cd01507737c531613a94be624316b5824b089cfe043aed0c21677d251ecc05105c29d561e6fe6106be4dff004b18c6e3e7b0777a2f25f5c2ae29b1ed3825c2b8bf7ce331f5890fb64f32cf71a94cfed05cf4f76dc985f6f84e1d7d74f29d508e5ed32dcec103bbd6e1e1acf5bc23109a3116a172fe275320ad8d681214fec5ecc5ebdd0a18614e40da19d8f370743c61cb8e8911d008df0915806210942103874b4853faf938b694f09b3cf753d7918dc8efe665955f85ecfb239e0bb0efbf0b83971aca6a21fc7b5850c502b10ace0a8d9afbb069ebf844eee01c7191bae6a68f4a2224fcaf6e23eb58dad1631cc113e2c67b0ea031af5921af81cf61d4af209ccb4c70521ef61fac7a412db67a30b4014dd9da5582ccdaee4460c45eee091d93079ebf993c5efd0e4837b719abb9dde887e95aae9316bf1edf08c626bb3ab2a98e67ffe55b0ca66069460c74bcb37bca42e42d59a233b7e554bb27513e32958ebfb04280b44ead9bbc433eb160da116c30f3693b46969c572a9da5ccde2e3e36f85a5c7a8db98c072a83fb4c2904503ebb21bebab497e1f89aabde79e1db4c7d8e6e5aafe633ba773cfefbf1aa17647b4a625c36bbf0b8ea929754b67d35439b71bb345b871837698b54dc303498f4804601737296d8ff7a5ca884581741bf00b761cc0b171f50280318f6c54e31d8c648b65b07efdf28220659b05761b00edb2b3f734fdacf25888d8e194596b654cda7284b3d57110fec4d5bd05be07c1a45987272677779d7322ee6b107c292f973e786dcb092aeffa9ec191a3fb01df002e3adec76a73e6a6b3243d77a83e37bc8bc20856c1f9658fb710a6e43e417423a5c5db093972a83733a4bd4752abd7c1e4ccc97baf772f9494426aabd2988f060f70226f9ad32a7129f9322f5f03a05ef01a7764811335a4f57c47518dcc69cbfe7041c5075a8e4fed6eb510f0a7d283d1951be4c6bacce8d2927b03dde1d38070d3faa3b26e1cdba50d90dc641a78e78eca96a4979ab6faeb0e1a3837ee9a2a1bc535b0108dc8cc321601946fad79d6b6fa2c0e22aec3aa911bb208e61289c0a1528cc2a3ec824d6d17881e51745d4924ec126b607cb5ddc3ca4d33f7805bcf7f1f369c4f62fe5a7ce0fe53282fea88fc676cecac58c96641e7f22e1eea4aa9aab2a4b97b6a197a2a2370fffc791c5cc2a0b2d33718ddcea4f97c11a490d454145bf162a2117dce86672afe6cca8dc70f961bed2149f694680ec8eaeea075a3c5471dc2f0ff6d5c8fa6c31a074a0c7ca3f07d2ed3cc76fcf22e3175cb5edcd57dcd3d11a763a5d94f9b500c006094a1bf0e7a7f32a728cf9e83283636b19f9dd6419d320c1d18c3cd3066f705adb6e59ab500f0f0d992dd6647ffd76427854f61c85295c61d6f035e12e0c8a041edf77e6b4e1bf8bd58d85785de72568a32c6782de63c489c1e615cfb6feea25a16e9ecd019e9f0c416bc3f205f035ac43eb239f63b87e4394ba8b845746483d05b7744c17c6113090e64619231b7a41ede21d115cd64b8ca036b3765522fd764e55dddf925087013221353af6193e25c4171887334c8b45a86f814651b9986fa2e75d9658052058f6c1324a17fa934194a72964312562a47b4c4b36dd46b373f67f1eee87dbec414deff0707c240b3b71824ef42210ad8bb5fd282817374d07165644e4a24aa3f43d195f0c85445fd951317b265b1a5f3ec013927b5cf44aecaa24060d25a26c795953cd0ba4dce3251d529cc0076eebe6bad17d5efcb7ccd9b21c1ed9efaba2e8ef109b5cdf949aeff3444b2def3dc7eb67452d93582b9160445667703bcd5c8b2155c0b69c6c515581b4f433621eb2f3457b0964514992490de25a7d911bc2f4a534224ec69c019a8065d2ace735febf8c7db14139c890983fe19e81d8300e025e24dd9d2aeabf22bf16a183e71af5e4bdcf2fb5edd38571829d907139755c2abe51a30ce629c271063d622697f4764b7aa88cf2b11a666bef68f03c359ed4e0401bd3a117215c84d74d9fd56cdce188383c1182eacdd0149cdcc56ceee64bf45eb35ad23ed1499eb744755b8fba566312992ada51ff2dc136ef3f5cc666e36f05c8b0ad68d5767073542c63a63441016cfca9d1f821aced831a451961bc27af3bf1b22d60a6dd286adc19005e79ec5f916fb611799394a334795f41e1c27f214ab65e3ca5f8798701003711762592bc55799e1ae4a5ea0f75e9b15e4793f3957315206610e819ed558367fc55d6b6c7db97f7c676302a6425aa305658cec8b4e261f1703e096e1d6563ff049a6c4b2ef33db3779ac0bd0f435013d3c9224c445cecb3c03ccc59ba62cc46599412317ced2c212cf968759d61f339d71de3f35eaad51ba9471a98839d8fbcad2b60253f275e6528e6ec972c54edb22cfcee39cd7722fc6b3021d2e8b588e54850a72a3f620c390985f2d4ff0d171a4b674c28161884778268cb7b93f0bdd600a0a6ae84cb8d7e3c4f730c867900396c23b13249fdcf70f69e4e5043eda095216db6e5f5bbd35ebd6e88c119e320774a9c0baea5cab6d866f822ae4d79f88fb0d4567733820cf7883da7eacba9976844b323e1ff8980d0d62be90f38d3a8bb526436c5190592bf08c4d350d3a54d85069103cd0b28604f083ad047793338e8f852018571fef004a0248288f6076c84933032cacac02a879cdb3010bfc487cc6361352717c2db4b8d542cd67dc761ef3aa4ee88faa46d9bd3813d3ffb9c9ba80716c80f966525cbd60854a8992a04575f075ae0423c36ff8269e4c528bc46dd1b67c73c258431078f7af81602e76f17a045f47e32dca309fd5de35fc7d117d0d617cb84be88c28514a0f816a8d37bbf50ccc0bf7cbe0d34729b8c3740cdb4136a0b4d1b1146b041da8882a23f07dd932385122ca069bde25618ba96e867c7994bdcb774475ea1c84654bd88f07e170a0c3d3589dc4a78f0fb3c49c50c1b600ddad3eb0c90ab0b50fb86d4ff11d6e0bd155de7370eae3f9c853223f30af395e62ff84d6b63829e9a1f782f67764cc8a9429ca3c059e84c64096a7a34a7cffcefe328547c025a9f79b54fc8823b930ef078e21c8f94e0bd38fa98b5bbc14ea71c6c70e152aa6edba4d40add7ee3171072d091ca9b63be6d7b3d015fa55f1fd3ddc32dea2a70cc289f15f63d01089ff56fd4b64e72c33d2a0dc9b0426eee2762efe234ff54d89b1fd7aebc04fd783ef7c0d5d034ba8337cc3b9d251ca6e523afea8e71719cbf2bd85ad0bbc542287200aaedb865babf5e0c0d902081e6df944155baedb24e54d3436fa2fc8608cb66001ff4bfed3633ced17b38d34301206df25f1cc6a8945147eef20e0516f14564a1d9431eb6682eeb2f6fa6fe40c5174beeb90ed3499afd894b1593f2d2d7d05da7fd5e171327f5f492f8c293afd11e4d55cd7f573dc8c621d3c4ef6a0ff81fe0bc7057f3b02239ae521773558560becad8b4af2ea5ffddcaa39bcbbfc4002ecc370d3e05a6705ffe398331ebbff0a251736d848feb922f8e185132cc8998153847a18c9c119787cafda1717b5d3181a9e37b5f837240be2f6e56537d17e776db5fa263bed3b7792b3c5f1a6d510bad1fb3529eee500a51772b6c010d1624c69bfa9d5a9f766f7cc9ea397c3a156f058e2a218b78d1cf49265f11244207632a212705b8984d3afcf355ac33f71aa0b227eca9f86e27daf0e2862f885264aefa63628c187b3ea09525e40b5aa30ee504d6ed2d9ac4013eacda90411f83a4736209166da428ba68a1aa56dfab2cc1aa1493840a1cd69b6a1a51fae0402146b8aa447b52cd0024663f9a7a3082915561846b787af984ecb90c926f968cda8825e2029cb627f699aa87adf871b23fd14d97af1540d776edd03785d7aab90c4914417fb8190288c1d75de49a306a5a4b48e124feb24c75ad0a4494c3278627238926884851c6985815d184b218a32e700bf0374d538d8e4a70ae455552cadbabb450ab7d8db0d2222d559876eb8688f5c4603aa57149ba99c2b1721f96ef91f82ca4dd1b06be0d9144d2b97feaaa5a1f16365861aabc1a9c332721cb4b93fcea6aae849570d5028d36b82a1e9ca24a0ffc20f05e862cc2bfb2899becc43ea3264269bf4cb88f140b8da2296a201057558966d7c039ad296410b5659e1b55b6e33883c6bcc6724f98c106770c50dd6c555cadc4c5b07d2a3a81fbe1ed672a4c2776dc8f9ac45174b5671ad6105d0ee6938cbb2055a62244726d70952e4e2ade2dcdfff0ed176916de34570153ddcd05f762c79ed9d6dfb82391296d91002c34307747300ee38ebc92236f7d4246d96c2bbd18d9bdbe5a76363988fc0b67639199ddc7053e1ef9d338b3f658cfa32b12df363a4ad87d69c51f0c0eedb7c0522bab02bdf2dedb835adbd91f64831a582304bcbabea915b6fdaa16edf708277c1daedc343b4c932989d2e79bb340d1e3d6bc1830da8e03ef29b05e1162666505231af48249bce78a562e12201edd9dbb4062380757f76dd9f8e052165e78c7478033ab7d7d111912861f7477be502b7f839e14c02bd7c3622e09ce8381f3afcd884e26fcfb83f4752e78735813d38ef8fd9a21c0f2a0d6139c2b508ffd20c0c3f5e6526e02f25bf1e0afbc84b15ef174b227023e605b9850af33a9cb2d17a4e040defaeba4ac35ec5f3d363d822f680650ee722cb407d022fbcf524fee25114f218808d617fb676f0bf762f77e253b1ef1a5512edc394d328beebdb972f7cbd24f0c6dcc152eadd18bf56e50ee0f3ac18a95244d06b016b221d128379d41d6cc017b8ddfd195fd1c1dc9f807cb75a9872d0749b85e27d8facc5f461103825d149bfd516b32182a769e16de3673bbd8db2bed7f23dfad6f6459446e6a276531e4a161b1469bae6314bfe248617329ce6c1209bb8f902bd8d903b2278a5cd9f367e441683bb81cad4ea6778240685d79d1b88113240bf0a97172c773703f9158064ea64fe4c2f4292f3d9fd2082779dd282e7f9aec53c882b41b40c4d42e2d100a8f651e6db9820acbbadfd8286bf802b7724978b19dbf92658f46f265cb15cee4175eaa42f364eb5d66a7b2064a26c10aeb381c443a1a717942110c1cc67e0c7533a1d2d5b653ad3930f952e45eb7311acec8aacb8ac6c6eba6a4c9bafa27cc04c270cd7b9678538d5ff2302b3f99aa554fbdd15a4e209983d60e4fd4c6c12c216cd8d770acabc0551a99290b681d11dd58c6efb199091042d28c665366b4ed0ac35dbb3846c310f52f62084d82c55b0a92558893926c90d8b32fc7960b197133dc2f666a9057469db3e968e36802017fb801836fb26131b8626b3a061fc73233cbbac745d45124fbfa36445bb6f3bdd19f8ac595f1a60c20d7c872eca07b86f1fc20d2e4a55ba38d7f296d78ddd6771af10cbcb93d37d35f4af67e33a32043e1dcb1a787997069850e609b74d196da0992076b9e404739ff38af40c94bfb1b88cee9f984c993d11532826113c7344c17f2c593048883830e7bbe8750204c270b00b4dd384f93a406b5d23ce895b7243761f45517b3d46fef80b8143aa0613417c7f71a96e80cec9f7bd71b36fa3c64af1d15b0a9987fa66ca7b443d5f00f39d2ed8000e4c05c47a67c2afccc7379ae6281afb21111f57c47490fa7020fcfcc25710dd40a6b084a7399d7a7354538e7996a6b4126d4668a405834f4e3686ccf45cde00aa9cfb2618ab4a5ad8899ba07d79cd85c79c42b7ed9f3c267c50e49b61c0264b22d762314c73e77de76b5ff649825e026000c5dc68ed967c0e6d652d4c26e7fdb9a3be8c64dd27df6a7c1b55e41bf8dd9254b31640c776474d3b04094357e60901dafb573c9c6da05ee60d54e506e31c785e594ba693cf7c20138546e59e912908752284134dba3e52014dbf9b48fd39800841806dd05cedbefa3ba386276064bb1570e07728b77e9eef470a6766883ee7fecc3822c4c61761db8b373e441a102b7b1c032f667d19168840355ebe1f6ccea31a7c902c8d60c4cb015066301d5af094acc4c04c9d5b75bb52e0b5aba0da9ae5096bd81b5e325df69a7e1b0ca9c827a4902fc4b5da0733872d4d8606df5a2ecfd9d9d19b9f7e351ebf2da402aaa03a1c77cbe16e222894dcd043f730c7b89aa36a8b585eec403b69a4f62d0578bf9b3c0cbb984ca9a697a73a47c205612092b3105f6ab5d5aea6fcc7465591cdb9263dc0330351085c787ba0cf192ae0344783fbf060eba3a7bdbf15a8c68ddac44c6c5c6462e35d8be1ef4cf0ad6dbf85b75eb3581173089744257f98494d9d65b5384b717bbf8e7099a747451dbfba52c60d091f7b3d77ee41b6ddefe1b8d86d5e266ba5842a616a86b94fbc9bb757ecdf0433dc992afe08596d58da5362410974ef0a792b5f434e2d8b00052d8a8ff5f777bcd789a4ed9f619624791093ec9c86d012b09859d3276281991ed5dc5e18bcac27042bc347618daa3b48162dd2482f9a9c225b7fd4eb9a7b7d10dfe3d4270fd32cec23b776d0be60e0d2bd6f2abea0feecfbb8439386d416db73a38cc73fe648a58fdd823e27763b05955575de47d855943863bb314b611465614474834c1c4a7f87903ba6d2ffc5132599c688bafd58ec6f28b8e717b5ea0bb1653dd517c15c00420166ba130fe9e42dde84cbc6744fbaef5977bd17218032b22b0d4807a23ac5bf220925c1a7960c3468fc82383bad9020e22e491974a60869883d3db8473cd5f505b3433e858f30b213d7b77a261526704da34e2cf722e0d0a4952bdcc80c154a580e5a7a027e698015829caca8b824d551d45a082626ae71ca263de9d3927298188509f64d82b998077a587363294f0cba7bc35f12f461707c421a87947d44177356f6a13734bbb10c7e29e6bcfb0c4531f45e8fa293efd48e78fd515335d6960a5f71784460846bd6a30687163dbaaabaa410c1f581af9bf6b3b66ccafde309c4565deffdd24b6b2e6d1f2d5f9d452697b563007cedc5155f5839d6c211690e8f82f0cea22e42a09adf21ea86c6b54895584049e6617b41fca16a97dcc4ec09bfd4abab60d6e65d9403ac8836af7f68ead51456a7605a6d14b438f2bf8a2370cca0df9811a7e1d966256a4b21e90060c3bbefb1a8148fd48e4c160f8c11b58100ac11eee836f94f5ed150c6012ade08da277b3389c53f5f82ac8e24d62576da106b05e4f307bd01f208d83f4319c6a0264250fd61e5a3b58e2df578143d1a9db5f8d4ecb10cd58969975c3025183f4e701773eb7ac113f1b31befe3eb1d98e11d462bbd40ffb76e61860b0f35fd3bbb72ebeda48975df67bb60e2187e13c498c1bf81d736aeaf9e3b14582ab5a6b0e7d511f69f099cc17b1e816b0c8091a51c96b85837cc70716114d7c7dd71af98b2beb54c7157e7a8fc99307073e4ff45c09f2e1c45b6c4ebf9841aee17cc3626ce99c429f1c11e9558ec644caf42063ae5d11b760b7a724e2ab48bbd4cf1418f7edab664ac7436d65682efcbdca79101773271f673900e7eb83e6a3867481b9de99bcbc6aa854134063415821b1e04666dd18e52fbf4360ce420c4418116941a6e8fd6b114544377069ee2c419a89069e18591246af36935c52bdfac49d973757206994ec669fce20b3bface0f25a69964b02aae63648b753d8b296cdd014547d5e8d69aa8cf7179ca81f2d207481e3a47e510cdd9bb7930d5a46a5a17f2f7e7b079b07a85d15e5408576daba48656d013c45dc4cebce0f1dac1b0497d703164cb57ab687399d148dd49dc430942c759565c0b056945ee2a64c97e67e6bc4819b5dc89bb408b59a9765bfe33f3bc6a08f5da75b847579b6d533e4af9ac7f94b7620051e4b3640e095b6d3e282064aae4f97631b2388bfc9181f18274471ae9ee34490921ead08a2023bcee3e67e25f4b115f5bd7d9dcd6475dc8784e44cfb58fbb8ed660e352af9e467568aa7a6de8fa4e6de8c785cef2ee8c6e7a0b36e4eb9bb53b7b7321a037198c4d30129b0c0f638b0d5968983f0e138d1c5b45cc6b39720900f707d59feed717256cc2341cb28edb4b974ebf51fac3fec9edbbd572aa5fd96f73290f8fa39e92216a9cb06629c8d79083a5f2098a74d112c3e4016d9a2430f9529dcd0dc05789b4c517ee166fbf62b9c21f45027245fc452a3fccfca450c7117e23918d012fda738a23407fdec53882a80f03431612bd3ec1e17ae8c87c2268e7cbd18c763cf9b075399da6b9ad494102f5ef8531ecf130e81016467fc79ffd72e7d52a6c18dc275dda76278558b7e780f102138deb0dc90bd66054c7bac7037e2707bb0b972d72786cb67dd7196b30e7275255dd1127bd6d8db72532f13c753182b920b8d346c7723046036cd52dbb316f0f829aaa98595fa86edd1662835fb3294ce1c819c823948604c563241845a31d0786be7957ecfbf0e87059a34fe30a5a7344bd0d8786f5dff2f0685853401ff9dfc6667805794ed40c79394b764298df48011a521f90e346138e9f69749a98a091bd087be9f94a8a26b2a4ec9e5030f4395c0c0808398054e77179db13ffe1744d554fd437d70beb2f51268b91ee315eb7cbf96960a24f1f32d2216da8ae3dc664a929e96cad0ea00aac094da530521a7b12c52aada4ea5c2ae5acf8a3d349d2591547cf8ce2cb313ae0517c8aecab31b2fb4c755611a9f07d9c6b10d4f2799315b0b0ef8d16027b26148479eebe0f348dfeb922cb8a61ff11c03607f98a86202ba4e4f9158ba5561f9bb00759ff55a9bf5590c58b593e3ece55f5ebfed04cd9d128c381c71d72897dd94c4c6ef4f621d7bbd79267fc3332de3f05ce3b3859df76032606cf32fcfb7d68ce6597311fed4064fe87e231227dcc40185f0d7306c5b430dc83462f03b7a847019dd583a4df0c52de23336a980d84dfb2af7ba11c963ee8d9d72031ea9d818d247a2eb83a0c3e8e27856ce324cc6c78b0b3ffd4774872a2150dd301e14e473bb8248acb86904274b1987549b01cc033974353547435b51b747dabf3c348db65cd701caaf62a6b08ec29ea7ff119674acb8cd81bfd186ed1319686158684d484dfe69e628cb05d0c5ec9c1e63c6f98d67e48a296977112e2661188f8a92789170d3361f4f6f15ff930b9573e5549bb9e68a591e13968d68ded6ccba9f498735d142e2ceda1fd5fc8b9b306162dc327c3a26dae9b42f43bb79ccf419e82d0a80c701b709692881f6efa7f00ee5ef4bddf95cfa8c36432ebece689d3f113b5e513dbd8e10263d1b79a98bd5f9a1bfbb0b315e37168d248b1d4cd72b85287f864eb95c903189785c5d704cf3582360934cf29d9d775636ef971fac1545d40338771aed5c77ed2a620a262b58913335da03f148d9ccc07ca94612f8368b183de65c1395339150cf7c69a657afdd20c9f469f06633be92a7f469ebff3edc82f13e70e0dd07a0b394461b8c1991079a52df31430b873db1f5d3701790fed938c0b2888ece2df23a6f44e70e580809178025cd8947a47ad15eeb07772477eccd366c11e043f5922d9bf04fc3450d6aecb4f544cb4442fef217c2f7db6b51857e122ab6e58c39dd369989ede7f0b69440d8a6d0726e2c8328d9896d304c790ddf09aa610b9200d70ce522edabc6123a89327a60bb3e597839fcc2da3b4a6a22155ba1cee8eb6224d4f7862b86c75b3bf518d22ff061cef0f01a5ef68a7b92948a182b59d8fb32ea6e6a1da86eaa1df2c370448e9d93a1dd2bd5593daec6ef0990c06d8e0300ee93d635a0f9d53408f4b806e7e38bee12521d309ab776087cd9a37495194b6d32c3cb94a2ab9c8ea567eb6aff2edd6280ecd1d17793837a3db2da9a9c33d2fbfcd90ebdc08a5199bd0164e058a1de38d45a0ecdbd67d6700962d530cf4baf5792a499b43a2d2c383864624429d08f9a0c1ff18c1cd18bbbf4208cf8280f2083b3c1e897f3e7b8d56a96857865a0637150062bceb9c714dbb7f803cba8f1d7c26e00c4c73abff5c4442b0cefcba549dafe6f0da63d03c09ef20351cbb13c7a0237a5d83111c31b55b1382c4dabe1b10af440c4115ee23f6b3ec1c233b9943220079ef2225046dcab25e1c2836bc3226364e3da6df1f1fcb36316b3a07170a36ccdfea5f3d9c0f3d5e75dfdb32c130645f0118a245ded62cddd065052cfcf806422b7380761620c50010b97bcdc7c626fc0e93ad02dfc4a6c96292655eaff4f90532f2c24b7106b25f2e54c7e23b5dfda345b26766aebeda9ca78c93855c7e20aaccc3af00689bb1f1a427e7df7b4e9b37935c61b17c6d9004d6809fefc011f6c060d7e808c793e9de35fa3039baaea499f8c6048b0166194a1fbe42daa2c4842026bc0585f917f540fce614512aef1ec8983ea0bed647d0db83ecc27a386605ec94bb7627de399262e6fc603c374ccb0bcc2a41b767a9c32a7da16b865f4f10d9c7f611963f6f7e82d88f15290b313ee0e338ff66b722f01117947d1f0fcfd82d74124d1f7ded47f54891f10e6e59f1329d487afdf9c2584918083a7fc7d1c38901ed14df02657ad3d43f8dc38c73d50aa271547e5669af7e07989d6dd8aab1161d903a44da8f50f1cb535b42acb1aec7d429f10bfde9b20a246df8cc3cd97b2149b22e631ddd2336912044bdac180653dbdbd9e166f669fdf93b1c75f1e27d1ba010b67c51154db4c1546189c17b475449a0c69f84afbbc3786a2d5ab3e3fd6c2bb7c7744e35b6587753c4a7907ecbc8064e3349328e1a681497bc8abd956963150b6fb125ebec489b631a4d5f51703ba77ae4bbabf8f1cbf5fc248aba904813f07b1ff7193a893cfac2ad1b11b481400f0a684e518e1901b9e154d87d6949cdfb72700f0503d08b7d10025ace1c5884c3dfbb00d9ccec88c4103a2b8a0b92723ddf39950f699e66c853066486a365b10d51ec75223e92d7ad4681173b1dc79b4967293f3f413cc8521bf01ff8533b001c380a89b8e86f7f47161671b44de5b4ae1c1607246c27b71cb027eadfaad1ff84e47df05588a0fbb98720e9137f1e7cadafbee0d86c30dc175b4135b9a3a005a99a2f1b4b5053489099e7dc81d500a700bfacaf324c0a1bb373490ae3490e289508239ea7074aff54f1b9baec8d55e4b7b2627cfea5dd491243b3d34cd47dc29a711fd01f6da9e0b057c6d33f8f1e50b96a9a76c4079baa2107492c4da4b1f9d3938508345504f21a93bd4b5c4ebf75a55b0ab25f123f9f46e985f7e58490ed05d194d9d084b79c6f4a6e5c4d102964bb13cc576041158364bed5470c03c52cb60e3466c2b06a95157e9be192ad7f46b947c47cfe2aaf60da08a8befa4bd67eddaa9adaf4c8e778cb759349ff302a8d530b32fb1a5dee688fa70168cd2b90a43691403318f495b6397bd794ed5d5e3beda7004313a2986cc07d9305851e09b30a4ef2895058eb0e9ca22e80be677a15e03903818491d66d17aab5c86c207344cb01c679980eba63ff75df7a074351385bcb1b805e393ab9beefa05a746de06cf5dcb1af48cecdaee0f0c18b7071996ed7b613b6d0e850a7ab4b847352d8bacc7a9a00d65be27094f30194c93b0d2528809658412583caac8aef4add0059ff81a10d3f24dafc58739dd06db8a8c3562a9b21854a69a68dee22860fe192be791622f215cb5891ea9933aafeb9015a8400f2bf5c98a203802efb29fd9eeaa70b06ff8b3d7d1c140bde5692da0e375d7d233b02cdbc5b067ea6691dc42ac7a470db5d236d14c2bd227b171de4722db7b912ccb0f66aab8c1a44b61cb255c890ad765c4371b3396cdc86f198e3fd28b0287a2b2f35d4184b40543c871fc63a6255de5a766237d6db62b8d0845baaf9780cc3ddcc77663fada52390fe35be01154407ce2b5b98c64f0306a8ac4a84f7667bdcbbd2bf691931e51155171ee0766fc602d9d5ffdcfbc6e0a6d0b2f5585d80559309cbe1f5eceb4908c5e0530c0ca6628c480072d32259ab078951042053476c84e95bedb0d50fbb3d2c386a7c0cb6e94292dbc28376e8a2809c8302e8d6c417aac250e1f75a06c54b71ec1578147b1147b365efb77e269c370084f633453a29eb9f73b73d76d81ec6a1ce46d5b929572386799e7f7f1087ee10a4c6b7cd0a8aaf2664d367b0bfca7ce9e18c79f372fb3c037d0e97df0d68246da3ca98b3c39282c7a9994d67ee67b89709f7cb396dee1d99e7ba219de9c18eadb9c6911215b55266a7506c1950c76fccb2e41a75f80e595e4d2ab0786f15e579bf817ad3c4a6ee00b2f908270af02571c135d92a6cc59b9db66753fd32819f73da748c5c39a77235977181675e8fd2f9ee5e6d0d67786b48bcc92a448cfb4bb32d04f3f560cccc0fcab7c20ec7b4740a9db580d493a12520127e1176144cdee11427cd944725d2749c4bb88c1e6a021f6306ffcfd9082b652a274903d438e117ca7e0dbeed27adf79483382d8c3fa7a8030e4c965ce9f0a23411e76d80f020d8a97cee04311b8a7f87542b335d7098f26e70873279a3db4f6c05859c9a52c30a8b6501be30a9057249791ca95725ebe971e2c68d50cbcf1a038497a1f2e3006ece13e65c0db13931a939bf0b7eb720ebaa72a04738f019730d274a50d19a2e8f868fd5f7867f27fa384f1b509433789315b5fa54db8741ff86e1001e04a832b5e42a3f88afe7d3cdf692a9264d625f3d18516e96cc6bc050000b08334a46ce491bf38e90ec1900161cbe50ee14ca9558fe161ca327cfc46c3f35ccf0e6cff3ce613af9bfc66bf5aac736874bcb16c0b6972e669e89cd603571e026b6a05d2abd874349c1bf035cb2543eefb6c884e31641a1310adfd1c9f741655ee2e582afbac162fd7f0ab7de71f4e139f453576d54e2aba00333ef7cc1808ed4e593481e6894c75f8e0419462d348f2515c25ff81433c3fffff78bf74fb8d5757287fcb14c02cadcb46510641c549a5d34126eac0074da99deab907af5e2032ef4ea28d82a76134ef3cccf741bc4df7ce60e0e5e1b9179505a47fb439afbf9e2eea04a3a4890858a6e152e11110227184619e00d3fd1c1f3d2915e73b7dbc71a28e4d999974a03657ccd204225be76bf09407ea326f27a80dc8a8a0332a2a10e1da25a59a7caa01e455e8b0c172512b78a4565bb71723a3298f102d0eda9b3938e6ea1a9da0d43572cfdb99edb087c9e3e4e91a32e9fb2f05cf55e996325c66225fb4b234d084d164b3a57c969f294cc25cba81e259d193b9dea1a5a0eb69b19b60dcce42fa63e2b6bf596c07ce8ae596be540571f7574f3ebe464ccdbf4a9019d8f8933293b4bc32ece653297247d3f8469235d33008d10e471cd1f49bc339c923905664300b7d59856c549213ae290b35aca4321546f87ddbab92a63efae8559fbbeb1367fc5dcb3b86612a9639fa5b5e39edd37a0618d94b310406e89bb77a87a311a04ae3b91b8837f69df2a6219a45208ae8223ad5beedd0b671e2a4051e3472b1481d221a34e3475f33c02fa376ab003561b56b0b13103655f2d5203de05e30e5c041b9ab15a96be4a5c6f793e6d7707852ddf36c142d0f622ee751f6703c0a71bbd36892e9d9468818945ec12392c69a99d31b61c654a7f89fde57e8a3055c90c00c88affa4384987929b26c09443ea8e1ca038a878bece09e8d887d9080b4794ce048297c6f203221d1ff699fae68e68ce4da87460142bb85f3c3bd08c23309b5e3b5b165233c54aa5b574c3cf1ce1b16c9ede0e236fc2b1495a450caa2acc1d4620af5a1b07692498df450f9dfa36a64307d2743c5698a0c3a78143ce0be0fea427a37c0a82af743233dc1ef8290b31543bfe1efe8af43364e168ccc826c49e00cc6bdba1976e7951314be087fda3bc769c75b01c3f9c753d43eb49b416d025c23346edb31ed7882a80075e52a0506ab684bc2fd437abe907ed3fea3df2890cf544971afd75211b8c48242469a424e299016a3a728b85348feb9e28bee1972e8321fd598f764323a5ee3db28b7ece06d90ba08bd5c72ca9c804ec7fcb4ac1c6bd3bb0143ac007889e97023900f906cadd05177694d3818e08b600b40bc34a02d138345f415754f601d75c1b5ad74e500b709adfd94677d72b455e36a74c7625a5720d77d396a02eebaba8065bfa57e0b286293622e0d50c4b550e32b2f683fd806958618ed9e6dfafa2999e20aec8c0a49d3a7479b2ea153c81343bee58ac66224a57f81a036ea4eead46e7fbd9b480af637ac312bdd2ad1cd0937092efdadbf5f31ad44cf14d907fb60e3cceec5d14aefc42a7020c0f6c0f2f41e1c2bf210742b4e1664c3032b63fc2551499ec7de04d9b214de0443fd6e14d9651b4057494a16ff0b17644552ca35cd0bbea2e694112c50f011e91359783c27898aed31694a9340f49060b60d8174964c62a7e7251e109a7bac249e11a31f98a7f5a196629ee403038b80298d789858a4e8c435072d6dc79244b5435342dc0a718634900b7c2ba7cdb44305e8a005fc4e41185217109ed3a0fe4414ff91d73a58820762964cc58e01c7b16d34b391922eea680969ceb05577c48471e88d9b5fea22f421e7ed7139f138f62bba538dcdab6834b8e8857bd1d71dfa0890c73a76e6313657cbda9a87c3706739e4bb532edcb277aa6779e214fae8a2d6ca75164e210fbdf21216b160aae3a4a66fce8d69f82ca9750f7c06a55f4593e353dbff8ca140e189ea6ca3f31275dc5d7f59633657320e60fb4e29e3cd99ea6cfb80091cae9285a4f7644d0788a4bb870ce10d42d1c6ba3b06add8d5461085f379d7057d6fd51cf32ab8505bdbe6280e1262163cc1e308cb09f2706c563d9c8ca22994c08f276472ac4417c877e5b4ceadf002ded60bf26aed2d840a030d0cab904be4abe98992673b481a87a5081ddbcea8be408702190f2172f79c8f1df5163314d6ed2c40116925d52787470850d53485a429492bbda66882ce34e00d078b1c99d0d4d02f092af514ff48acc48e003e8571a9e7443741cdd0d21b4e680ac26a753db9f4f25b2172e22f86e65c00de0b91d57e772f1159d3f60fe2161b38482d08f40caaacf52fa0916eaa6f13dfc433331285c9667221865461752fbb523d5de30a75e4866001ee29af227a5976d7968a7bb2ec9eb6c9cb591afd05b52eb005b427fc5748cf98679fe30748c117a055b4df4ca591e8000626a5856a1a2ad00b2ab9bb6e4039f16cdbe9e1281c69ec73f85b1e075d9514f90fc9c164160758c440829727604392842be1db7bc719fc5d1b34784c7a408becbbfd8101832a9ab314d942d35dde56f98afb8e54eae3bae907242f66552d3da82a1710a53e27c1251f46ac44c8c4acc2663dd0cbf56ba33a705971c8321a43fbad07c8c950f5765e2b8069bc5534cf4f252abb37d15e98fd901c82000f080f46f6ce2aa043296299e04dbef6da501496e83e0926722dc4458d3169b5aaaf00703e84ec99f698dd165ff07e644870044c0af4fd2d988b842075966bc14148350874146d075e76073b3442bd477e74c286d79061205c7668da52feb339d47a331fabdb5b8aaeeb0e85655f28697a052e699c51df596a0ef7fb0da54b3d0e43359ce4785954f3b9b009183837b9cce775ac1c4c5311953f81357413bce0d76879fa0c468c8a622d181da4461c9853a002c252e599441bbc045424ec8a98b8577e765fe8c87577b3cf42af5d1db5cfc4e6fdaaabde7d4e4f52b7a15c9d9dd125f1566c6c8a7cd7264597e6690a21f176518dcd4c1c0eaa90f15cebc065b290438de01fba71e6a4bcf62f3b651b4a4252741b17ddfcd7757cdd4788ce90e9fbc09879d4bf6435b6818b915f50759f5d2d1b5d102600215b190c40c6dbf26b70d2ad95e7273dc397b091413cb91cc79d3e6d3c99fdd06f13726e03fcfa9271f76331e4abdd3e0f972b51f04d87e87145e945cf3e4b3994fc72173e89a9af42b14f717d9eb727c525cf41a0e0b3dd70ad9acbf1235813c5e452cc97ea09eb763c20021452150258356bf6920c42b65c295e6de4e5a311bed4f4c9bfdedb8b125cfad0ad4cd9e53c9b2cadb4fe3edeadb08158b49821c7edb70dc138169d7f01715239a5cb9d821159c5551526f8bbd873af240d55878516839f0a20cc924912e06bd19efc319044dd690523af2f2e4dc16bcb1142168fda488da43ca9914beab340b13a5848c6916060fdb77803d0d391d1484a3226b111aa703215c4438b4d3a79736da8910e43d02a6c3781fe94fb813adaf6a09286aa79748a82d08f614c402056bdf71d77d8ca0c24315729a407f326c433ed6b830f8b48063f1c7ff1f5e411315957b93cfff3cd52f55d3328748045b2c9068f116d9d3ef8ce6e133ce86fa3b215fbe6265b545a5f1fb924efe335da16bc34b7ccfa8c5616bccf506636da3f0f07a170d0e7af4c62aba2007f0a8aae166e0c1dab14230d2eccc601d35ecce958138485b390bee6fd9d9147888e15b8f8e0d0c1112f78ff5799072004c7f17c1d82f02ac2738b6ff7814e01590adc44680a8ce38e2cb07a3fb7bfd63de4de4fabef00f75a6d371fd88f24e0e254e87bd5a102dce3cdba1697da1487b37cd8080112e7ae0c22231190be88c996b7fba16a2232ef86924149ffa04a9ae6281bdd2839a92e3d8300679e94698c8b0914383b391b4d52fcc41d3196517f0b0d6baa84027ac13a5f63b3fc25800c97788fef1d237dbecafccc85e09b972ec41f6895ef536fe412c4ce758127574e20083d8f4b78059a6e8d66a36f07bbc047db7c125cee9b5f4ccb649e40dee6660188db9d6654275ba0113ba6d3201bcebfe2b9dd721f6555a0fd0c5d1000374ae2fefafbd293de7e3917b73b44df518c984c1059660ecaa1bd2ec0c660adbeb3dacc475ac6f0deedc0402a1278f4a5009739d028717fac6458ac0710c04770ad399fdeff3fea4e6c08ace59f8a0b3b7308c4d7b9d66881c4f8be2ee521ca6a5bb47793fa6a69c8e15180801af9b7d8e80eefa92752c3732ae82464f194eb1806ff0fff66da1ed875fc01a7c88d0be6b49da93c9fe45ca662e55302a5bd8b6be86d3ac3182f7235a33a4e4dbc932e34e8f48c0cdc37062dcfef36e0c302b7cec88625cd0eb2b270a2e1ed92f80e75ead0ebce901d50e60b3c36819b240fff97da9b8faf45d663145500ff179dbd85824f400682b60faa6d2429fc240f605bdfa0d502628cb63e07cd0a67a1c625f772dee2f0c96823da22e50a12f2e8cfe378793aeaa216ecfa353de01e30436370f9eb3960ee029ede19741b3fa5242ec4049efba96c288c4b32b24d1e6c179a018cbdd6e748f06039d95359ab91aedce0e58d9379d071758b7086611e13a54a3caf6b284d6bc96ee38807bb2dee819d36040aed1e86b8014d67f11f08b110893186383e48d19b63e4a1c375d915b005e9ee77c190e46e71dd377483e6462aaf5ffac9dfbacdbd89617e95e81248a6e5ccc76332b0a06729f460bacd2454a74ca2c9a3fe440a6bee708f2b768e9658ba66690e10d0b800b1c0fd08bf3497cd0598b56e597b54cf566a5e63429d1e00ad96c6979648ec215a38262d2c4c6a28b1a03aafe582456f9c6fcaa9fb61250da0e372079c3e97a23f152060af0aee0e8a34ce048eafd954f8fdaef7891e9f9b977889dcb430a7a3861b7cefb056231e9e34891918bf3f1ebcb97b60f6c637fa11972b528224a7a84dfc1bc3ce7f19f73112e8b85a3031e1fb782d1709307ca182deb8a09a49951f0e24aafa75da75e8e282371e0e631b7aaf6515b368ef8621d1522d3f52b8b6175a384934db47ea5c0ed049df5db3e62a177ac37d6e572606114a388cf2b62f7456f29693f2349285ae42f22c343c173edb1d555a77c065ea57f8598bf88f3dc40f55ffc11322159f25c24762ae58a25ba38977b27e4018fc4cb97d77111e72755ed7257dce66273c5fd98770c9877fe8b45fb734cb1e0b772bf7535ff784faba594ee78789f0f5d11c5a0ebc658d2020c8bcbff1d1c062af2d5bf2579b640be1735322dc2dab9cdd950a4b73c226e8a179a8e248bbd9ba4be8f9f4f33ca38db4ed8c4d192cf7074eca1f15827ffd15d17a05bb02fdbc35ba0904cf147e8238e6bf609e59bb1c298a18651134f5833f3f9af793874c3396d01de3908dc17a62fb1009f091676268e55e788d0d7e6f8a96675c04f6ec1faf00c0684f76bb1d4c83f9325b5442a1fd777aab8ce5e8aa57f4680316ec47a61631771ee7aa872d002b00fa29a2409e038a22f430c180b7c61dde3bb964183e64658b59edfcd65c8b4bcbf05fd98f6649cca26165773ff0ae96444219d4d932741efe38b40e336112accca18d24c1c4d2fc5e27f73b177655da545cfa9b74b9a5a7a60d1df66cfa3f6ecafbd14b57537c46ee461d34d30b1ff3bfa67ba5d90bdac1b26a89845cda9c3094bc69e37620aa5ab5b79858a56033d462c9ad3ec9798a231a198be66de611a1c7dcc79a21b5ee9622d0b2bd6628aaafd9f0939245c0f22e8db9cf0c1e9b87f8342e864302fe5435c18095dfe343333bb6575d9d8335de3380e9f463da6f3082c3bf962e8e09a97159bbc76e69ddd94feb261b22b960885f8cb19985dcfd53663a7fd3e2b458689b81dd32e5e3f22adf60046fca248d24eecefdac3a3930cd76fd04db592a8cb35f9e3e6341885b74babb7a406f3bf97e1a37d4c5feec7bf015dadf9fc788f9af39775499f87c5179f93dedd9df2b2cd3a917907bbdb306041f72029a9b5c23973e7618aa6300f98848309c79897a2c57016d4f2985cdea8bcf912883c5ef5b89db27fe8c5efb6eadef06129357c7cffa56c18517da52c36a23f064f5cfcc0fe59d21bcd476af86f43e03adee0bfa60f3ed6141642f31f1e101996bafc99f9cf9a7f013fa8e607339c8fd1689440b061c8a101fd04f0150ab6aa7c4ee0b1f9039b9919ccfe110b25f0d5f9c70f62312988d0c58a92747cd84c8d5c3748e4593f0547edb141a62c988f9bf4bfcf0103eac4a14f3b136a536781d73d7815f5e352b78ba9ac76465daaa577688b7ddf70eefd7d8e557bf5e8b8df7a973a18a2f503b3fae94326cec6b042bceabcc305fc6145d6afd59adf02721fead2a95f524a1eeabb0c94faeffe35ea4bcf7a13994ce92bdef7a547ffa915c3dcf43d1932924c3d2e5662e92fb440a1c69cb5657bd88cc3ca32acb861fc7189e364d78f7fbec1f977e5e93232c03783f658d0c2e56cd38fd1f4cf064e7abcdb9dcc5177ad1e260a42e9cf4fe13492c4bf4f7dce62febed15dc67a8ea971407d236042e0770c177bfba5dc8df3366b643a0826e80a60e241a6bc876117ca53b2ed6dfe8227fc4c6ae7d149eee82611046e10743f8a7c894621eedbe986ca1470b265d9430e4187fce5e4af086b7abeff2d1b0db7df703769776cfe16f90e7bd08f7c0cf0db148e532f1e4e21edfc4aeb7e90d03399bde9ad3ed470f8285533e7252fe79afced2914de96df568f01f2bcc3f440d258d7da53b1f729a47088da9ff1a5d97daba6526523fb6fc3da71b0fdcf2c3a5f933e404e60f1294da8ba52f0cf82db042376a71e55f1009d414258f663f3bcef18691d9a5f0ec607fd56fec814a55cc466754436d059f4c8a3aff605592606510bcc83ca3c67273d58babadd226b7da6c2ff34a730e77ad80011fe977373ed7f11d0bcf36fe73fd1219325f01cbeba900e9e7f8dea516a0cb4e762eec91cee36015ae35fa5164b6ac6ad2e9b56ff8b52f0ecd30b5217955f6470e669bdcf530bfcf953c606969431fcf6825d550c49c6927497f122ff0cb61acef46e7756f46e226a1a698ea7845925ffe4200ca8b4272cad857dde776ba84015fdbfb9f0370e1b0d5446cffbc5df93919396125564cd16332ad64565721e0ac67d223c0900cd67b61199a656946a0270c4c0620129b537a6334e91f5ddf1c6276d2bfaa7342b1ab796eed4d7d6c5c18ea05d45c3944b803dad3400e5401d8374487270edc3ea4222f574b02a9deeb29a6e178eb230698d2cbfae5824943575d0767625d6caae45d133317c5fd94f9f92fd881cf0b82490a72e314a9b6f31c96a9b9496ab8882780d47071f5c671cb97d2f9221b01f1681429eb70f06282d3f7e34ca06b64b7369172e77d83c0e03057c63228b70010074497ea78fbe74a8c1a922f8d2cc17e36bf6e216d355f2dc3796ab40a2ba4302b26fe0a23cc8ddf78aa27ccfbdba9356abdc9f5fb494c11718c0932c65eafda926e107640ce1dbba8a12a40bab185b05c2c5853cd1017d3984020c1db9d614dd4dc7d160ad8a484d7362c86900272d949ff550812d80e329daf8e57d7a653612b84c8be59972175beb84d6b21a8a4288dcfbcd81e03c0e192cc021ed440cdc301aa6f8b5caf2622d3cec3928c122c789f5ee1041c580acae24c485a16175a6ad1b2b5d2d6e1783578a6815645c88aa0c91d5dd218ac268b4bea0a56d562f961000344954b5c93b56d33ab9a2a8e3617118146fcf82013f34c4cd1119d3999deb28bee6422c04cd2fd6145839232a85d3ebaae4e3710017840a78ba582c132258fa4bbb27bd6ef6e207f7b738438176e62fbe746b66918c163377de5c171f4fd7537c70263244440e0c17cb3016cd3e9a222d439b3a1251acc8b3e25dd6a2d85d1ed7122ca9dac882c1172bcd02e8d694e3877472a94a0b5bf6c3d6dfbc882866287a6c61b154e99e960750bb0e37862c72e9b9a262c21ca1567bbf55c65fd0f9ecd4cbd6e28b422d5c46c27e17947a4aabe4755a289abe8ce720ea554cc256e1aec55fb03406948e6650d2d3842fe476205562590179377b73194f1d80fbc8c3f7afd2d056b05ee83dbe0cba746d116d90c5708029b9dfc2c20692606e90ee87f83d4fce2621648c0fb9a587836af1a2c6b422e26f12323552214e4ebc023ac474dd555d0ed02e913f373787b2ca03933146a91a93c130baa6156aa96bb373415a09ef16d4d6f9583eb7ac7c460e6ca1c28ba40dd8953439e012157b92c5f1b2e305e860038f8ee0208a62091b85a9fe5ad088e7530249bd04e293a548613489953f2461c132f9a12ab8261bc4535d6e7f0e150c5cd3067909b996d770985ee8808147952ac6776a46240a83f3cba900086904dc7bcfe46c5eefb8b8e8fcd914ed27b410274e82819e109759ef8a366cef94ea95ff58adfc82a2299e382e13b1415e2d4c7c395d683b5b39f245a508ce51c31057b11f9647c3e301490f10fdeb909c1c00ee162bf057ff419e60d8a0f80b359e383f8f419a57b60e219703195b20a8a6a9264edcbeac280a5b9ca87ef02723d0403d8e761faa3f0b19e9399130d347659e99d11ba0e0ff0edc9c8b7be5c983982af3dab4f6599962489a1e2f82b940a02b64f3b2cd34c51541d2372ab6b057f95490c701e07cb46733b7b71223a16ee65a24a1257f0ddd5934d0e862804698bc35c896b108ffb481dd2009ebc9db0d111aa4e9c4652e3f33d6fc967d14a0f0d4e3b7e6306884446319449019c457a6ec83abb4a7d197fe96b3b9549910799dca51362636b30469114f2db38895c3ae7dbce69410a18beda545e0a92d731f636e04abddd971d4082e48610b314cf213cf9703876fb27eb0c3ab3f70c101e0c06e8835ffce03b0190577e13ac8c011d1c9a4d31623400d3df54400a24c740a974f7d25082c1eb62099b611c4c47a7fb11c5dc94fb5ac99f5d1adc3bc6858baba74f3800a2b66f5594b9176c2affe078d4ff281baf3b4ccfffaa19839e963c770bce10b62a7aecdd2a42c3256415279c73d5062005ab5fe834e4103eb511a0f3a013c7072a6930b3252884f37aa4079d39eac52b6366d94a3b03d4567e6a47edc2f8438b2563981bea903b323c0c60c3aa4242eb7755f5a39c26dcf05317414100c57a07ac6f3d4de0d6ecd7e6cfd9cd7f2bdee68ffc4ca360fcdd236425526586b9495525fa22b34decb95b18be4b0dc272f3dfc2114bec9b9580d0b0846e57d6a4e122f00cdbe95e8feeb9030b639a48521418bda43de92b2dea0a9b5108c7df43c893727d3885160e9652da9d8bd1cda7731abf4b7675d24a624419ea82f2f98040a5f374f98648fdd6205793f77d843c744928c317921556a4ba41e897d0a7348a991b15df0f14753ea6f0ecc37ce69ce61f44ef4924b2503a0519842a366f4ac81a79e1a97c92043bdfa7403b9cee1e7e6922e53da2e60e02c6078128278806a5dc338dc200652c05094973cb152d83ffb46ac6e1ad6cebf879e28eb6b6afb13ad359581e6e7dd051c1a3b4606aa078a75e670a17ad6c956400fc55202c0e2fc29f6715fdc31524d57c0f34ed7c75ec4952aad65e75e53905bcf7e1e14360868248273ffe9b15060a5b1a977271fc80b1f4e66b5ca4852c9b8f300b7faba05a19a06b3fbdbb0cb91b79e5b7801908e98f042f0b26425f2c23541e0ce7197d11cfb90cee99dbbe45cfcb20f5f8659602d3bd7487276661a754870f746a40658bf1f00535059dbfc810eeb8f8ba6580751891f4f13fa5f7a9a2037e67c602e8986fb149e5555d1db66c0ba72d078a0bdb69a0ee32d5e4eedc8148fc8bbeab4469c04bff49c5f746632191a55ea485ee6d5c9226156c647276022e6d6963e8b03f225315cfdb4f09ec54e976a148c7e328a4328d84886df869b94298b02d21e1564c49ed8076bc1736576f317085040a4c2d4481276f187e980d4f3ca7484425087f5836ec12f34ce98e107ce0923206204a0cf6c51b43bfebd0776519c886fb21c1297637c7222dcf47a44c80d618ed7e144b44d49c7d0b5f9058cb50b37de66621fa34da89121957abb6d984e013a73edc8e971d7664cb9818e614dbe29dd692a271754f6e191a83a142099718df86db7cbfb7b41f49a62c76e0c034c0506efc9d5cc932272a2c9b59cfc803b673e8da9d3501063925886b4b56adf6511607ece176eff08b47d262965b70edf97822ebdb875839a1d100362d0103a64391c812f078199bdb3107470b533c014b85426ad548c4159c51e84dbc572f89a4eb1c6ec226901638a1848aeeb28027f9ada36685846e91efa773447403acd48a00d66b053971cdbd87380b4eca5125b25a8af2758d6951b74a35b12f677ba3e6b6b6d5c56c4a88a98426d1b9eb0da88bc057f9502562dc4fa4fe73685ef318ff32c36673fa4919f965fc3e0699216d18d60176c5a9c7310a6063cd4ea8abfd57944bf1ab3d8ba865f69fff105f6c97cd7e8c11706aca015fccbfd1327969be2aeea177a469c19844d2ac92051d0c99063de06c19c2ca7b0aca1a9edb86a3595db02f65b962807c3829e80460d72953ff07343652cb5c549040bb019e2c1aeb4d597acd6b971f15b6818abf35cdb5f2553b998491205742cddc6d47a387221418b47fbc7e1cefe919a39f8d554a058b08ee29f175a095212f2d41204b1b5acfa5de1677c6af70d6193f830e10d438fc0fb31541101244f50b38a584d30584ed4d406c7f70759faeb81377245495f019a37e2da5d89f60f8ddb537d3661a49f7b4d2cbb29a1bac547504dbc8dca5e3ff3c69de044f2f6c79a9d4106d9a46077da4e36260bb42686e84fece4e7b6a4766eccd21b03f2309f24193184bed4c6e390a8abd8a70d5417970c9290e2251a40e8979ed02034fa657817c9e3f1563fe98ecd83a6755e027204f5eb02b8b7ba9e42c132594b8f77a2dee9061001770364684238834f8543b8c1daa4a03f0022cdb508a5a217dff39afa2cc7d48cc3b97f76774bb2d6bf9c432776a5acae2d01c58b699cb023bd29851e43d0166d6d97ab030ade74aa9b73e1734909221fb24c55b957ce62971252c2130deca751e402031794ec5fdf160496c685c1baeec70769b1396122c46e1b4f7c9590831df02dc264052644eca7d0403b3aa896fbed9f5f0bdb316521732ca00b3fdee2dd26ab2b9bb9fb993035ddd2eef59ac864505cf88f8c4e4a4ca5b3b279210a75f96789f48f5ed6a1f5a403e7a749bfdfec456135435dc9eb9f638a61033641560d3e14e50c03bd55a722cfb595cbc73752bf2fb0e3943709e622b649e1bf32667633b2edf77650f7c6729a5537f03ccd3607ee9d379a6999c9b133ab0699095e1c07349abbfb0556a354ad783134aaa5ab7f2e36332385d56ff1e11c45ace283d8e58666f4c335c9530b96863dafe5ad75e5bbdcc2d681536b888b87795afb11325ae6d8c6a2ebf7de806161fe42f3a7afcc289dc9777ef9e4f8e2dc2905b6ef8358e47f85963c6746ffc57c342f26d33544d073a6e7cce35f6fed121414fc54440b02dd9c6885363df63d948a479b264a2410041b06cd44255ba6a53f6a0b427bf7f2a04ed6dcbb5901b4e3f52e9167aa193c0a446e64cfaff9d639da55d4f433245929b1c5482f05c7d9cd6bb0b049a46583c42e2a7ab1d5604420588b921d50d38bc5b2e8a3b920969e2b4e5371e09848a9e4927b5dfcd5b988de333ce4a618f6384e5b24e874b9e238278c6202c2fc47d25e4871beb84b6d308e0871c7d67118692e72fcc9671b2f7187701d44643d3dcb40f257f650dd2945f8f56fd5960b71b206d1308d66d39987da9ec6f07c36226bd01b061378a574f728ed7ca964ed385eb8c99d35cf20781cb88e5f20c91969e2f8e5bab707b0a21aa21691121f6a69e54249ed5398bfa51e4551ceb6745acce9ec984132b825c085018f072a6790a0c956d6167423710950b3e338e23773a3f2d4a93d458034323789d22f9ab954480b927254e715ee3dcd0f403b116aa31bf4d07ab5b29dda079acb2ffa7713e356eadd4709f672eb37a043a21aa7a204fbc77e6dc7d653878eb1ad34ee2bdccf38c221f5e7be14dd27424bd6a59aba34c8dd4fef108e477d88cbdac83ec55715d02eb5acd6a98d2a6235e54b33cb8bd2bdccf86cc156bfe949186423da9d9455b46eefa17285ba1f00e42e6cab008107f130ccef64322b89b0d57d3e51b856d6cb29936f4621ab1e39476cc690710b10d71771c47bea224ebfb6794c88c50e11fdb9742f634b26d0a94335678d2bdadacf6b54249d0bc12b4afb542ced06e8d658d1cda2c362895b4a37c5ae6e181d888dde24ba2b967613746b2ce966d16db1c4a51ec294cac8a8f544e1da58834731a4aa910c60ffc53b2dde83edcc0f214845c805fb2875fd4aefedab573af7d0b45c9d22072dcb508784072552ee9608bb4b425194e7209713c992d4249f73b5e947e32e139dcbbe4f8270e36b5a4f470db0e67e48d79bbc64ed26abb4890d785268ec800784e5004c6d95688214da12a315be1654a9f51a0f6360062a35097d9509bd1f1d5664a59930f9d126cf95571b44a89e00c664305ada760ac26461c3e8db02f58da859013f52c07c062a26b847b67c5ce669e91a0e80161403ffc0da2e1a522e6bb03fc68a60ed5ba1e2784340f90fa43e78132748d509b3a823571369d74dad1a52d8173e93f18e4d3943fe434a1475d0a230fc9a85f42ff41b7a80aea29bd059e81adae8a2964aa5ae525aa928b596a4280bdd864ea0abe82634ab4b2b354aa9a552e98aa2a10b742b9ad46595da4a224a459bba10e79c42477095306f7e1ef7cfcb2bff5e291717a211d0d8fd9a27bff2a438a4e9b83f8b705a128bb4591445300bf6768ecf27a7bd29422f85ba50a7247695525f2b90c86114b2ce08273166bf6d77143dda681488412970748cadd81c9a0a72b2e1abb9d58a1edbef9d3a3a355be466880a851c1873186b42d9719de885d29f4c3eeef75e725f559ff1e5064d19e7c35081d9bd02e5055b4c54fea1125aaab3045c6828850a202b9be4f07ca845e6545d65deebf39c11b459d6169380e016005dba69671957b8d6a5fb08bd4d1358a5576f301c0915ac3cb12a658760b74f112f9b1abba40d598472bc70541b1a18c65ca2c186c1968b94e385e1f5c05854ed767d0a8311e33bb62b5848d762a9e197624a7f919f2ef09c79f321ceab20205df491499b43f287afe641d233efdbf9e31c6c3ed034e14084ce2ba35e16ce075d3dfca146bb8850822585e6bda886c1eaf24b08de2758791f9d5707d5c711cc83a068c8a1020306709aadbbe5f66ec8317d08aa2c401ce030f4e5dd101878093bf57f847e2d296dc27e832ea93a1be75e1daa553aa4843a081b217e8e2b13c2f920037e7780a6da5d9e8e771c674a3a66cfce263a5f891302be59d60280a5c2d8e92c6bfd03ebacb091aa043e20536cc5493ea67f8b59094b8fde8981bbd45369835a56726a902d83af9603fc4de2cf19eae53f3642689b7e7220cb82f13a6afcc6038e038bf8542967765bb5f20f5e51a9a280975b0d89569f4c639b1bcec1083d739d0a0907ee25945982b51786d5b272b630ab65caa3222ba04192ac89446dd1ed7e440e01e92e068020d7aa59af47bc9c93ee26da6ebd1adb642dce0ab29ce9a52804c3fd89a0a141d2b2269b9e91a1e8ddb9415e99afca280a8e7e732af1ffad456e6c2ebd45f9af6669f6d0a0961246293e1491fb6bb9913d997d0342a713abfe86c9051382eddfdb6cc2b81cfaa6ac86ec98b796a57cf28993290c1a7a4e155fcd454c6b53294e154f0e6d0cb4dca7843fd9a61e5e0063871e47fa6e7c1cea8d5c83aa52325252f470c7d84e07262b046d2d97dc5ef2ef874a815a763703a627c6e00a96daee982174f6c515c28ece7828c528d498996816af9760556395a213fce64981eb15fdebcc2647659279e1f0cc9488393c3f4c0b3831b26d002dd005fb345b1ab79de85fdd79a6a9b191f3583f4dd5352965f617cc2cbbe39b6fd5405a044f7eb5a09ed65ddbbdf41f37bcf81a13b305ea1ab461a2018fc062bf310980f4609887fb46310b1713ad0f8b1d2380cdb129fcf96c13e2677a4e31724b60480375ef6818fbec2254545d6ec42a8f58293b484bf385a4cface27ccb4597f2e25b86cfeb1c20f22571c2e63e768d6fc505948c924ed631ba3451408189d092110d2283dbde5005ee4b2b6936f195f53d98c414b9723cbcb63d42688256503448488b038dc2edbf51e5d456ceb539f1b2ad507c23459ac9d6a469e39b965a465f2e86c435af6fd32172e662e579b072ff002fc32095b207646a27743dd22bc89ca6f3f2e53d5341bac2c815397e5b442edd5c231609d85dc9c151eee5399f2cd974a73181ad34c8764d90eed5382fc1dc58370d57effc630a301e39de2ee4cc0ed26451c17741c69879f6871b9dae4aba1f72c6f5a279e91d1b3e70dad9eab2111df1ae454f72cf0a5adb3991bdea66384c2d846ba3a2c31c87ed3507676cbe22fd7cdd041e427d902a4583ccc8406ed34d93e990e9b15a1cbc0c256c6dc3e166393cb47417eb88c2539d557722668c96893292113b9e08b71c0109d4f4ea5649759a7dc0378e0ec44addc948c04b395d740b6c2d1eab4b4fde135161f30aa6e762894b3d4d53a4044551cb41838e51296539fd0e697123370cadc6d832a785412f3e35072d8c9334fb57de398d3ee0569f58275286026f9993fe004fc70bac486cf1b2697a9a314f440361fc298eeea6506d8f639a9cb369573deab1336f31b0f8f7f24b49faa2fa3c9210d8e843ac39b7eced03726dceaf7a350f5d5a7973ee723852c72e2fa35db66929ea92534a975cb45991974d32c228e228a58e9ce451b9f57e9cb51ac66e943294626cc90059ce093bbb3a20705a49621ba7f455b241e27ab9289f08293fa172e06cd56aae43c75a8c2733875f1418e4f2b1498c9d26ff16e23ecc93540c700daf077737044b06b19e591e34dfa643991030d9f95f3beecd2be18e644b8255b1aff366b49792b68e4b465d7424801c974d321183b3038834e37b583f854dde9773c65258b69a0bcce989e44a3ecfad9eb52eb702b38632e873b77b56cf95a2d191680261aa9156b2fbcdb2c715f5fa065705feba0257bdaf8603dce4c646ed5350668c6bc68ccf1123abea00940702ef9046170015b00a70b68f00849e1ecc15b8f394e06528d1e92c402f6a5bbb4c1351cd88c2350d95ad31a7408fe7d58f991705668ccdfcd1a27c692bbf23c64568b129061325f1aae0a8ef7e92ef7f53fc54822bd68bc3bdf29d33426c7337e85765a4ce3246cec445b9b36f13f6b26fe77f00d88f5d6f87ef3290fe1cbd17d6ef5086450f7e4ed673375cc4f1af5427fd2dba82e31d9fb748a84c4bd7f455ae37e4f9417556acd1ac739228711546258a2b31cdb65dafb24672c9ce6c991757f9f66750e529a1833c3b6bb2c40b6a34411ddf7527940e4a5f32a645edeaead5e842a8ed58f40eff4ed33dc485aa8981970fe0c61619c99bcbf3abe750c88b10463a159482a8a531a81b0a3b254a464d5172b6148121afa6b06f1ef7db4bc173932c7946f7d42931d8f2b7eff691f852e1385c45e4c248da71cc29d1ed4ea7e4ffa8ee414c671d67b0db054db794ca98338d59bd38258b38fdf3029d823b672b0216f0902ab4ab4cf95a37f5adfafa5fc507ca32d3243192eecc30bcbb5875c9cf0005de4742802db12c757ee1132024a1685ee8e593ba771673718f441b06830ba71b5596d8d9af5e458a96da6e815056e268c0c044c9682c052cdfeedf1cc84ce4a3194a976c140919bb987b564473f81449692624c3e991b814bdc816e6071ad70d29950876479e7783edfc4d0c3324745867b857fc4048ee1da162ff9128b806876d034cb902a580a5df95b1a0cf2d650ce995145a2a5e4d2d6a1dfc6d97dda676fdaf5e79e795441012b06d3e72c0a0df6a154be4f6a3c945502186e1aa77f81f56ac79ee944fdc74212472f74ae03df733252ebcd6077dfacf443ba6e6f0f37f4686433165ad11af678d61806abd21644eaac9d85cbf16b9ec8d5ed39e099161de7791a66bf3992c369ee0099a4f6308d5c0bd5243f5ec671247b53a780f53643da83179f27cd655666f4fac175bf0ba4ec9437b5c3a485e727f2f493a5a670ebb34b0fff07246c5d00a5c3197334842a70055504abd3e54904351496e541510a1636d608f4f63c3e83440c12afdb39ae7bfe9d9422d8b365c0fc902607b13b6e82d71720d9a6fb45654553f19656e8cdf222c0b0293035172b669ea46fd8f1323b3064c7de0a8ad94a0f5b6e0bc1308c9b8774c5b4ef718fd4803c678db3291c89f56af0db989430517536ea7ae335976027a8717fc100c1936703c400d6103c5673092120712f1cd24b9f186824c4b0c42b81c4f6fd389e8099eb66d8949a0aa872c74d85c1a8eda6676eb8dcacf08667e0d82a1904810d9bafec2e6489b518e6ba35c1a5f8e7842be1a2f4779fcef99dd7fb89ee5c1a0d1dbcd3aab940eb29b84865be2a60bfb627a434f53b5b83a854e704ee0b8ee86b526980a30b36f86b01d913346c061ae6a9031f1c055dc216a26ee0920b868cb584baa46c19bc4c971d2092c9ce48614da27c15f4c77508a129a34fcd5928b12929f921f7e374f311212183d0aa09069a498b8966d297b91b0e838738fb2d662a1b6d6c190033ad69a92f58f2b8bc9397a7fc1645dc7901d9ea51d16e1220052a7803e58ec35ab0125d013ffbcfc95d303c9aa028cfdad92dac829e245ed32b94812416d4a79b2ba5587d46429b488cf2832fd3f3771f9c500bfb4699647a1f0290c5475b738cd30d449ac62f361a3096a4a5a6d901a895da1f982d690da9a63c79411bf101550e1156076dab504a7d604f73c2c2f4bda5c19ec137f4c9e8a2a240f14548e37b16ffe509c62c180132a2a38aa5093963840b32013b13eea95d1973ce4c216b4102ced405059a8e29dacd144df34cfff2df89ce61611ceb03c903ec9ec59ae6402b0bad4dfe3c829d9c1feefeae1b12c3fb692ccaf088f8f1dd4ba11a2dc3a406f72b024447b14244de142e389dd9c83a24304e6520c762da41a09ee58c19de18b3d78d89226c303c65dad3778c6a7d80320ae03d35565515c4ab27c546f1e24eee4124594dc8755951e46add99e823a449408bc803b42517215801fbfa4a4253be2b3aa1544bde71cc32f2bc5e5fe78c4c54f3c0686a47158352211717fca64713428ac6e1f66dd3ea397878d283dbdf0792d762e04f9d711a89366740a40268b1d5d13aaeb5c283af2dea84be9cabf063b06d6a7c2f02143bc4f19ba569acd3a3285ebaf051269c00e66bb44dffb89915aeedf4c251d83b09d9036865ec86f6537526c8b5448b73acd594774d2277d92d85bc2e97d106357bbea24b591ae8dfeb360ffe15f49f0c1c2cdc3209c301ddfe921014492da429c4e1555e31a783d8678e446859f9f00c74afcbe6a7f01e6fff817fd3ae0015cc804da2cafa6551048cc381d80f3b9d4d11d834457e1d7e0b20710eb5a011870b10f40ee0daa4462f51dbd4a257f4ba5d922fb5fa146d2ee26f79785fcccd446386708fcd3461013450a43b88a03f31c750572ad774df2c66d8cc8a6f209240a630a37980c3329dce0055768381c197a4ed889c243101626d0462fa1a177d874778d150cf8418b09ac34571ad30310e39b490550e042c3278a93328ae8ee965118ada4e2d3eecb28ec3e49d2fc1ac749c3f7fe482b4792ce70cd8ee3c7ee574a13e7fd71ccd65e1274f75173a5d76d01178e464ce3741a4d33823057774f698e262729c7d349a530c71c73d098c0cd90e96e77e2fea53285d97477019a9b594049b3a1122f2755e55643e241c383338575d3e8d0dd33549c3feba699d17c775f519c4bca1ddc4c0d3753e266ba9d386a27d39eee2e71dd34abeea6d25c5fe91d1e2bf196783929b1ce2b42378d0168a0d0c0b0c20c9019ef5294520b073428908302d7629a44c5d9342a394af87ab34cefc4c1a4f590ae8d79b771e68c21e4d0f87a4852291a1e0e68531c20e81966f8698e0aeb0d8fd0c33ffcfa3e531c16888304c1387684208710da10c2170d85e54df34692854d6f1a2a4a414c572ce96ed40de6953ecae84ed60c53a22824ed0a8d629d42344c8966780a61fa53fb95687d5e76e790b5aebf41f34e564f3dfa7a748bb0bd8fc338f27c15da62dde6f846387f0b7f486f513d32f251dd609e1fa3c8af9346f192b4b04fb23deee171de4f7a8c6595624c892ed1e752a4ad1f6595b65ab1a25c16e12e6581457703d1a61f04a16f8fe4b61afd08e5b2487c1a7589d7fafcdfa0bfd68725ae8494247d1ffe249a298d5eb21bd08331b24a6dbac736f5c086af579f269b77a6832485b1256b8ac434329a588b0fcb250d5f8f46b3a19829464aebf81bc1ca96f8a2c823fe91910f0f986859a5a8988d669b44eedd72fe4bce221cd5cabd1f15ccb16d1279f7490fc90b8ecb91f41f95d39bef8fca6d689fe98cc14aecdd27438a67cfcbc09b6a69b6341f6958cbdbf848743cb98cc2328aa766dbe7893395d9ec6e045662236304acace14f8a2a9d3dcc6da6f93ea9f29f6b83bed68ab25dc1ca95f81f94edaae5aa5fc5de20f1c57fb1d210bf914a346af510fd181d89f933b64319973fe2d7ac588154d8b34da2d036893c9af1df462ff2d5667a4b9b34633eed8f3bcde66c7bdcb3d46fe9f965b749c3a5bdb5ec8f5fab03597a7dd27eb566fd96f6e679bac56e452feded6b560814ff5529e87586f67e153f721bc7f9f7484ce5458a8c8070f0158f90cb8d805c3c40463538508fbb5a4744eed527edb4be724fac288c5b98dec66a4110dfeebcb9522cab769c20e818856331fbe2bcd967b907042d1e67690be02008ba0fee8e72d40e8dce5ae4246a791377771edc7fa424cd86b6822008e42ab8c599d692065168e0a3bb3d1b1bff44fa42e1d85fef6edb263522e07d6ce25cc2ea87486129da9b2bfdbe599bd410e2e1520771f2b88791423be42eceff91552ad6276d4078685e20f181be0a6de16f3d4bfca027f5ef8f381689229dac7981d038ea468385eef6663046cf59ae93dee9338ed3c7287f8bb476e57ad5fb48b73a81dca332c52708ae10e4de2c9c7f3ff63fde2dd35a5a544ecb3dd40de6fe77e639fbf1ae8dfdbc40f759f849c71eae65b2bcb0f992551a96e25f70de27ed252b05417f10f42fad8cc6aaacc654ee81af943b7110e6bda7720ff4eecbc41f021d05da5ec41f88f2944f01bd526a83dcbb51f76ec023b649049efc063c726d1078729c7c677e5ccefbf9659e55eecdc23b1ffbedce4a61e56dac799ee423392e023d461dd7470ae7bd271c9bb79f5101bf8f089c12d61bc613267ecdce7c92781ab917bb19df60d582549cc94b56e9bfa680fefdbcf37e8a662f494e9af3b8f777fa0da695e1a5a1dfeebcd9760b63160447b1ce19c65494d5795fb444392af76ef302b52c0ef59fe57c23d612ac350bba38fec9bd8c5f26a33007af75816129e2169e17089c82471f9f3355a68e55feb38c348e23d2740fa4e2284ff9bc405340bf7ff381422e16d0cfab004645ae964a08ccf7baca66f7329d79b52f3a6ade77db8bb73afd069b721b3f4f2a3e8d466f318ae7907bf7fb40bf9f64ff5a22f748f0e6e4dd9cf0ed91be0f046f636d96692df517357e2cf6d7c6fc4b7a73bb3dd20b83494f6f46e1799d0af87d33dbf206708a639b5c4b5b451b5672d25054ac9f1f63b2666f1e366b9db553befd13f75e9cb437e237e29f50600ee836c754a3bd76163e76a0209e564a4a511497632346263989dcc3377e4b1bab9d7c9c333c3f7c283e1ddb64957b7e1b6134e4714f7cb1dad07325720f5f3bce17697ea26c57781ce9cc678ab307d749b67c8ec4cad3ca76856345d6352f9058cb20bb12abedc12c9e6c57d9aeb6006d5952a97b410653ecc517d78b097811841756bc5872e398a24efeedd3c50eba10c3e7fdf9230aff2d9b4601dd4d6b531659ba6964a079f17770265f856272d2fc6b262ed8e8a611bbbb8626e482092e14c0850f5c8cd851f85ab2ba8b262ebabb66ab631f66f878f00f04bdd20f088aaab5020a02fad9428be721e13b9f24278f7f33ca1638ec785bf8f89616678ca1c5175a3871e3959edc2b75163c66e7fdffb418f23c5d8b153c8b37ea1c497cbd91a4d12c7c4c2190a1bbdfb380c005c43815ec2e2cc43416572c49c2c15992f47ddf7785077a0914eb7a22b742dff77ae1ebe5a452df87c910d8d0ddaa29d70b31a5e1e01053dacbd6a60f7cc1381867167ea6d9d08395b34c6538381f26739e799ea43311ff96a24fd307b6f0400efe218514e98e239d8562b5300ff8e86e2c49ac318ef37fe68789036e74e3ebc1521cd8e96ed5eba563aa828a55edab0e0bf8507340a19a3869e23736919e72ec873ea35b94633fe4ee5e73e0c16d227dbd4cfcd70e1e3b46d82143184d765cd051a6348333ba2609980e225324e9ee176dfdc4f72f091d4f3569e2decbc467c20126296c30806d8a020cbe1e0e3969226c618ac287c6d72327cd8a65cbe70a4dd8ec71d2dab936681ca7cf387dbeaf87482d94efebf17ddff7627d51a4b31725e78bc4f8611376edbd562c31266977f6d2f950e5a889df090c3a3a3a3a3a3a393a322c89010625495e40a2b3337776761e367b761e3661d6f57d2b389ebef31f7b25fd25bf2f0b155960598010610222762062004388f1be5a9ab517fcf26670b4160682dfe7026f30bfb6e8ef574a4381374fb32dd031080e9145b737c42c1c4248777b54082e8480a23d914e9cedaaf208418410a76a6f75e6fcb0712cc974fbb5b1283e4558ba747b58528e429a5fc3328b8285863b1f0b8fee927605cc952cfa0a11f5b1acda1be58a5f0952a78308a0c16d9231274eee571a2bdaa94da31d9bed79d5e6c52f1b0262af20bad4d21404134184ffca8f9dec840fe59d60db24c22d7c537b1c355a0b3bb90e80c401c003b8a340f778ac98d1ed59b1e2e2b5b2d30d440f80a002db64fafdb56108440b0822deb535db4a3d759b363f88f1fc872cba7f384276e70fff43906e0ff4418d54b5f5e455e50313ed89749c3ecc72e90311db8b353cf5a0821b2fcc5f4b474dd8a9071b257b58d23c8069f7afd6c4438b072448f7e181ecf678106a0f8a657995515c854c7797978a55be10aa0236ec5afc235905dbf87a295a684b7ddffd172db47d1f2db40981012122d0fea1fccb8fb1f8585c58680873bafdf3be965eff621b66fad7e66b48ee51a15440f1bf6fca0de6282ae08f227d559b678f7b54c0fb2cebc2f302d926116ca272621693ff4f289e54c059a91bf9f28d04b1421042fcb38e7271c6074fc37f0024ba1b536a7b6f1a295caca6bbd473749707400d803bc08f8c2df9334c3a0a0a2618ff688595283e2b51ac1059b9b182821522dee485f226fe42e187620a4fb6ab719c3ee27ca16c57e3580665bb7a424edaebff66d8f77932a47e48c10f53e0bffea40db1e7f0935e48f36bdff7121f697e946e1a39ba6986d04d1347378d10babb068ef6ea742b827605fa885f646355452b896cacaa90c2795d2d28a26a257459f87a38a99758e70bdfc279434b7bb18716ba8b54b12bf1b35d89cfe31ebe30bfd5787a8cc42a495af5238d95a85958bfe747d8e75bcf7dd6ccf3c7ab969234fb7fbe556a9b73d2e67dea81954e2210cfd9c7f2c474d66edef4fcb7db2c9c229e421f54fac8688fb52edb8b19267265097906ddcde505544ae481d76bbfc2b49a1dca3cb24aed0af3e8eedb78d78821861dc4c480af97ad35aa4da3fbd9bec69c5fd5c6fe8786aff77d2ca29f3992f87a2285a5ec7d1c5424ed0ad92611adacb472659b44e2db26d10babe6cc85f10fdde6f83f4996659b44b649d44d23813b855eacd959cbaeec7d1cec7d1c82ec7d1cf0f566780addc42565ba9b0799eeeea6e14110babbd291465d62e5c9f8938a9020d45c0f1534d7434a7323a8d1dc083331cdf1b0f1e8e64420a239118234b70389e67678733aa0e074e43457934597686668667600496107023a89233956142145036ac4b084088898f095617b018c154f5041c5131ce8a691a28a6e1a273610451354503185145140f144378d13dd344d74d368e9a6d140374d06ba6930c0bdc6702f303417e8a65982468917182f2ddd48a11dc379e5057b4971eee5bd84747b51dcf33c0db0836e6fe6ba397106c8a2862e2dd144c98952144d93848fa612032a6674fb2c53ffc0042e20c6a9a830a54b19e0a810a552292f895ef24517702d74392431e37218bbfd8b2591399cba48c674c87fe69ad246ff486735b2746e0a14dd0de371efc5295670ec2f3745ca14af671c0e26f059ec96290eef1e0b9c32c55154c03c6bd365773a3ec2d54e9f13c83d6c43b2a4b376b163fc21be39f9d7fc6be3e471ef2f256d99ce9acf1b0cc855b42a5118f3b8370b33ad619c6f29ce9495f9f45ad26879be406fe26496e98f6a9277e6faee2539be4fa2c4fb36dfc6e9a8da4c2c2f19c53d7c29fe1a0cb3dca35191a278dca372eb79d1fa80537cb0a5dda44e9e6def37f53f2aafe3386354b4348f59a702fe2c9c3ee014af45a17b182427d1670b2596c402e9486d25cf9c214dfa4a3de55f55f98b367c1d60652b5b283f45dc100fff6cf61ffc6407dc932c50fe656c594faef41329fd2405ce063036a080b30109ce861c3aff751467c34edb2080af42b18a0c3e529dd1ed9f6d1241d1aa2054334ee5eaf6cf05c7fe7d15da529d542570426c74b77f98ca14210f74b7cd294e8886eef62fa77aa17b17ab583c3640443c464199ce329d4e6e4e20ceb62f8baa2ac808cac366cf0ce580b80072a2dbc3b5c7e7220a4c38d315dd343574774dd35800db95f89ecdfea3f2594efd65e13c91dc9b8ea188f5285b965de129442b8d5e365962056279b711c4df874b7babb7f1a9ec47da977eab739c59fc1b8ace7219dec4ac47058c15d51fb24d22708ad3db384e6cadcc79fc65d3e6974db286e78fb091de60572f9b2cbb32ca76c5cde0a35aeae3840d5a918c38275abadba7385fe85b6077a39a73427ef9b77186ff06714e5c68f1fbc23501e361637477acb92643dddcce986e5ceef04e583b3355d0ec74f74c051a566212767874977ac031814017f11e7a70f1bd8913efa107bf3961eafddf181ec7e9f37a79781c27acc4adc38a0fecaf846f8693a18c0c626450c39bf8383f47cd88e16418298084873f69fe187e928b3f71aed4b2808efefb422a7e3d12c5bf254b7c2e06bb04067086a710e8a8e9ddc0a0e3b75b3ecdd4d36866d92651ccde9c3c77c191bc0082d7e67006d52f672ef740f1667bf2f1ecf1c447026f6260bd4d3c6f8f74f29b0df577628b63e3b7ec4aac472cbbfa1136eb51507ebd5e383772142d4d7ca3daafca964e087412d0dd2d20d61225ad168dc590dcbb652379d2ae0d5aa2046323be4449abe532f76ca2c07ebc47b221c61336f31467780ad5f2c5d19ebc0fb7e03310db588d51bf39f9e37106b9072279a104c1f2badc03dfcbd88eb89c65b715046b1ea3e00dea04e2bf311b73fc98d6390be91d537926a3a3e39092168794e471e2dad9719ddc2791834e5c3bf869e2fc8b4b1d6236954beb56e6d9569bed71ef762ded69a94a7d42b1ac58a52a2f1de58137334fd1867672f7f093932897e4382bcdd6e7588634cb2649ce9f7d23b5f771a876e5f353ed2a87d6f52aebc2e27ff864eb6973153ed9d2810517a44777e74c6086e76c95391b03dc50c4d9ecd8e0d89c6c52b0e961c3c346846ed2fa0d0b27ff6e587047b1e01f691dc5829fdc3f14762a535a28836bc18b6eff6e4eaf7973a5df4b9c3f7bd186dc0a5bb8155a708de3f4c1d436896c93c89f465dde0dccfe7530f494eb80270743b094d1184da2378734633a52fc30a01e9e1ed9bc9f34dd430ae985f1c82af5c9788ea8986d6fda8c3fa44fb3db3c5dfc9c8ae5e4e8e009826ef309e5592769fd4c6b56c83d4c478c6ab977832fccbaf8361abb9136966dad51c015a8935a815f6789025fd58237d3b34d3d553a47d26f77624bde273d46fd26366f2ef76e13c9de9755b0058239e02da37ccd519816b9070ab96a58010dbd5c2b20a21a805aaf5591cae57364e46aad8a7c5e46403fab23b0f498957deaa3b8178bd9d4fc286eb40aa787635626fe58b3152955a90d53135bf296e4ed4e7c3f499c3e6ff0f87f7d3a9e390a877446ce2bb399bcddb0d202f010d1ee67cfd7ce7039c62a95553ac26853e6d7c65c45ab32fc96abe0de915cff2bcd8a75de1c3b3ef56c4fd2192ecd84a0b59ce59904060320f1903e8c1b4286f723681a1950ff9a33c174165a1288260c4ffc1d9cc92d7f6ce21b2681a1f41875265faddf604e4b0243e978ce88e8eed91c9008701d190d663bb640c7d7e338305eaa529c31dbfab0d9934a650be52f2b96c4c2d7fb6040924a3d8c0332c4fd3001f7630aee8796eee67eacf02348b77fddfdfa5be2a72ff64c1be922ed9d4213a087b490f6d140fa4797d024748f223a4637cccc703333a49592068c8ea0610a397e0540a52454ca192b76788cac200a1bbcb91a258e4cc067a4580117194c53ce1b33538a08c04700bb1b498321a3892045388d949ec9f2c509424960b81a214490c4063e4840c90c453485992c5f74e16aaae0a000483a4447886c516688ea012a02ecb0e9191370310a6968ae860e99c9f245090c5773244408089321d880e4e940bad100cd980c14e00757e342095c8dfb1881c8ea32d15ccd092488c0a347ea4644136faea64796d902da0d0f8ccd52a15921c7278ceeee1ee20caabbc56e1c7e10a40a0dcd95c804377819a179704878680e09d91c12b13924539a43c26a0e8950734868680e890cddeda36b009c8e68ee84a5b9d36dee74d4dc8949732754770b216282079a332189e64cb8d29c0923abbb7d98482841473747421862736148692e8c55736130692e0c9ce6c260a1b93050682e0c1ecd7581a3b92e3c68ae8b0d9aeb6246735dbc34d7c58be6ba64d15c17269aebd280e6ba08d15c171e9ac32475917486593fce90d659f8ae9186b5b43e3fb39016da706ee410ab1704b568ab38edd85d5222090b5400caad0300d86d45f2f6edd0e96e2adda120a643618c0e852e1d0a18a732256dd8a150e4c806d45da280f822909a1c744418d0e38748648a5653b19bd411396affbeaf3be188eefe1212e304241081234a4604d14800020f28c201a5062880e60025069416d07d73aa2962c8986e24dd0d61a2bb1b92d30d39754352e86e17ba1332a6bb6f4e3727dbdf9c50379d90d907bafb87eeba18e0ebe18c239d25e8eeb2bbee84413c613b7426b0bb33b1d0dd9e37d25c8e3497df87d35d10a17e8c64adab4b39219d6109a7034244770744a803524207e4ceba1f23e86e9bef7bd91489eff9fd5c5a7722aac28702fafd5ae79d5130c644ee5d9b72af52599d620572140bc8036f588e529d40f74a4115c80253fe61bf819ddcc395facd3c91f771aaca3d679d30fd3e1cc3344f0cb2404f8d9407f5e5cda0f8b47b23c551af13f835292078f3729494138841bf36466b98ffc9a3598f1edbd12757fcf6077f15daca944687b08fbd8f83ab3e593423801788d1de0de6ff313abe68f30dd14908f4d4ec013de5ded76b3f10f494ff056f6e884e428eea7194387f7602fda321553afadc40e4f87ee80e816ef22684ed0da29b59015f4f4912ce48d2e88b92134bd746c0c1cd1104ec5efd71af89e78940a0bfac66c54a6bf67a36463e1def7c10a372a5d36dbedad40d968ac5ac4db5977459a5792651158b87c7ad1882d843c019020a2b30dd4d3617c70edd294e0839e8c62ce8c462761c674c08a7eef6af39d0ddb53938a248a5b27501a00c1825ca885d90a941f7b5f70229a0bb6f73647e96e08290c50e1e8cf63e8cf644a3b5acfbb5e2bf416f802127ed8df08da12fa0c84192c2a3b564ea0d21f9f5d4bb02409840372527ad7c1f63c4748fe9625228e37c232549df37c798d267fa832d1a5fefc5f9808cee15e641f282e883246a3e187d20d4ed1faa847d1fc647ed0506557a10c7e732d32856465910af1e2471f13f4ab62b3c8ed3a71efd65f58321427bb85a7fd8bc258fcc7bf790aead15c0bd3b4972fa9123b3f63deee1197076d0f3b4b9128570838999aa748cc5446b6b18471e548e597fcce31e069db87644704eff1263ca0396e17c6c51a0ed57e04867ccaf7ba328529a8fe38cd566e1e441b28e6d441e1abac30c09d3034c0ec0ace1df8d7f27f7cfa9f837050727633a64c20198ee1496cd04000738d5031b5edc60fc6283310d470fdd3dd3830d6aba7be6f9c3c6c5b566eb137cbd7c3fa9891a2400d53335106b40430d96b8cdfe7969540313d608b3c6083cc7b41641f1ee357237598f320de948da80d648a2c23c2125ad2b7f4b56e948e775d1a00d914ed6f8493f445a170d92ba6dacd24e428d2e24506388a6080b92e8eed4ede69202ba4b09e8ee9a5296d2104f6fee346669e45012a2bbeb57b17f83bc5889642dcbaeb25df51b221022828692ee4ee51958e9f6cfc6aa6a064e3a08dfc229fb212cfeebb52a52b58c80a0bc806ae0312a72b55eaf0f5fcfc66cac529c970c86fa5bc18c6e9a146210b365da0be3fbf4de092bd2dd3f9a834107835277a3d09c193968bf7f513e48d385af67c6c90c1b3352e8d6e2890b8871c7d72b03a90c270d45052e20c68bac80582c1e2137028202b4f29fa1a322a196b754422ef7fcda187867244d145fa49da91c1956705e48c2d2dd5dbad25a1dd9f092c24364ab5f4b5fe2f7b5408e16fcc08a656b2648b66289bb8a167423857684bdecda5cf95aa25855e52041f2426d1a892adb8b75963615bb4995a66237c928c808ca0c4fa1202328792cc9796b2b1800396fcd6dc69385ff836e46b71be80c22bac56876e1fa48d3f5d848b4e1dfc499ebb7c44f4199829f6e2cd6c763983e8bf38dacf7b35c837b5f1b615456cba097cd77af662b12121d6beec5acd3bee618e797dd49ef4cc24398c8478a7b37e338a9ebdc4ccb1b100625481cc923cd11f6c43d8c8faa0a29b443f83fa8956b76a8d5b22b71f6cc9e37ba9f34c2663d0a12ebb78eba69c61202faef0346d0a5bb69a1ed25d6c7277801770215e017c17023f638cf87e5db3941342db48dc00a1b3680a37480ee9eb122042e4e74dfc61c72664ca3f9ffc69afbe2f4858f2f52349a440e384a5b8ee81f61305a6340e2e5a460a20861705b58e8ee9417a417d30b17bfa5705db00185eb6288eb228748921360a03201213f4177370a615e1021071d38a0074a0dbabb878ede5103a561186341cc6c02c0d494910289110c00c42354c1c1a1224698729c7a4036808a6e1774370e4074e1c5c6853882d4506201a6fdc30204fef5e01f163ffe61e1a3dbbf2bce68ffae80c2d62b48ffae48826f8f14822f2110bb3b0e102ca01b042b7c208bfe80d0077cb47f1e30c3035ada3f0f2ce9ee0019dd8122bafbc57560a7db3f32382b462b503d72608c7f1c20e2c58115ba0a30b3e6aab055b1a4fddbc097ee0d14e1df0686dabf0d10a1e20cffa880c2c6a8d899824cfbf79a020c1d9a9b823545104e0a32fc93e2886effa458a1fbc545914547c18a4200fe7150a80145b77f64b77f1c144bbafd83a2c63ffc840afc7b0209fff013a8ee76828c7f4e2c003be1f2af09315c13593471a5dbbf1d5ab8269234a74505ddb9246dfdc4d933c71c73d4cc90e00225ba4af70e7d460690d08095eeb6ab1a0ad41fbd89132767f8aa7dad198367c6886362d65de2f17ad15624a9a737a748dc610656e8d6498dd35e9a545f84d20e0ccc98888309369830c187c4d3d1f17452e127e9d84273444da94433c30677811ebafb06dded43734bb4d15d9ae96e1e64ca3a456e899c76fb333c48284a68d1ddfeaad9ea54a6dc608e23e2f9a58ac5436ff6feda1a8ae23287f34f1ee847dcfdc35fd6b23fb6a969f330cf7702b98794a3e3797ed7e63a2ba55931272747279593a3e3b659765a893ff131acc49f7210836eeffc5ae41e9ee1ebbd5e111042b7ac84f9f48a403bf398751a1bcb98cd8e2758a9cf04a0bb939a3ba28a54aa68e627e28c40a23be349915adddda4392358dd5da48733c2877fa5c841608b96552afe87a3ad8f642facf6b59f4fbb85379cc5f96124795a3cf2b887e944d14f12e964fd07b93c6c3326291d49da04419256c2dcb6dcc318974c6e5c70261fe447dc05ff8fbd4edec4499a5ff947263724cda7709ce1ab89e71f7170282ae3f28220e89eff0d49f3c971ea36d6f2a656a0cf6aa9ecaf574bdae9363b0882d85a2324cd97261901c709fab5b14cc792c6e37f6d48d2ae90acd26ca1fc20857688c593e948b6c43bc53a738be6079a2bddbd4373315a378d0c3cc4df41c75d701d40670252df711d40b0c5620df98e53b0487c1e91f6609fb1759f857d5e56a751b6630b7bccba0a4d1cc4711074cf9bf6e6bf3a9e722639b8054be5d8e4e88814766f52b0129f46073222d677231497b694d15c5ab2ccf5ef8cb9c59ecb221128db159eacaa62054e9620d12977beefb64677fba28bd49aadf1514342111566dddd4e687cbddb23bdc6195a277a8a06d0c820d0d996d4f4e81ec7f942b2a4a53d8d8a7fff052848a0d042296518e5165a684be5cf36a987a0820ee3d05d2554349beb9cb15e2fffecf7e191cefc3f1f36d146743ba881af777f16e649434002ba1dc0ce8edd0e3cdab661cdb0665c4f0855a1855000b410daa385d020426ec2167233d4426e92747710213eb485f83869213e3c5a480f0d5a48cf095a48cf132da4a7012da4274a0be981a185f4b860e331f41019ed21ba2fa33dae719cb4d6bd41ae4a69627729ca0d4a3628b1d15daac1d3662dadd15da2811adda53468b8e0ffd804c699ebac7d12957597d098c119d7e6fb25198ce30c63509292f18bdd345b1ae7120cfa3e35a3bb5446774902dda517b8808c4e871c09d4b480041e9e351faf14e8ab5d79a5d786e284d1a1eea62e5015684d76947f347b63677477778bd0dd0c8c9915ed9f9dd51c3563402e6d3733c04cd5ed1f0a5f8f9ce27c7532b0c14a5faf3a4330a6466c8ca236fcc3e411be5f6b69c4b2fd6a26013341b060860122c696ac2ff22b89c0021874ba3fd23ff663b315bb505818c90b4740b77fc2226a65dbaf3ed31f5c4355cd0b24aa78c46a7b2a25bafd137cfb27b77f22de591371aea5c5980ed9d80c4fa15c5f28db7e8569a1143c85700fc65f3fcf21a36cfbd538d2d9ad3f84438a2bc58fe7cc368944550e7db2ed7f24e97559d7c726ae47f8f64f5478b4b6171fdb118b63ab067c6dd07df16b9685e705b2fd0aff643be2a719d3a18ce790acbbb40215a4600c31be784141185dba7482ee9209ba4b25e82e81512241abc4faa451aeb7ec7218d24d6143e5c5a8e3a7168fa2ea4745ef8b28d1e6963ddedf49629687c54fa22cb1da1e0f299c30d82d749bf1cc769569d47fb4a929ffac8a524649c1deaf92f3c4a05707417184d1fb359ce991233f2a8f5937921f1ba1b4fb1676cad87a37a83c4ffedd5a6e5bd6ba3a160edddfe702b2b1aa2ac2938e2f5a22fc1f94bf35c2e667bb420aed50be769c47375f4bbe7044da489efcadfbdfc2e548deb2752b7b846c40ff337fb4a34f7db2c8a7f62b927685de25fe1b2149fa3e5a28a51b1a3314a669a16dc83514c3900a6efb2756bafba5b3a49b4812dd3e565deaacf44c962f807ca0fb08866e214c46c441c487f6647ecc518930f2faf121e90a0006554516564638c1a5862949078a084202104400396105338ee0843b84142105183a2cc1a140091129f0a1552105093a2136ba779c7eb9c38baff0934a1b681a09744252babd70c6629dd04efb77857cd0d8743578a981033534d1dd2eab34ace5cd8ec2e338439c2036ae084aa2f1f5be2fd50551099ad219d7d21ab5a868254a5394a488c58a6acfebf562a9627f59f7937e857b8648970aa2bbc5daaf6e309b3d9cf11ce9bc798e344f54aa5a5a5fbc964ce5d88f36d323f96f47fcce98e3e937e2b527c7f326633ad6798295d8718d8d7346c7597ae2cded84c517451ecfab5e6a8e25ede6e39e97edea966b697b6097467b91781cc7e9e3e4eb4e813e1de636b9fe8fbbe02549f24f21f1bf1397962625497227297f2169c8bd6a51a2caedaa06c84905dded93bf25be85f1b48c7eba2f04dd2704f6f0389368778e3c9ef8b396955a7cdfaf8de1e0fb48b3e6b9cef20677d523ef31be5199689b441eadbc393908d24ad15f366177ca7c8e34d60a62a9fc5a2769a5e8aba2960d181cbf0f043df6e2a7608e2aeb9c13693acaaeecaa1eadec8f75c92a9d65bb9a3de3580689780a65bb22f3d3dd50d1dd5d122c5d1225deed915c7050543d7973ddfe09385fd582b747b2c17816529aad36fcf1be5829ce2b7cfb277675fb273c76d5e93869d005c6dae80e53c60badc8ea7ee3c74c00ba9c24bd442715d2fcb414897188003b1c237c3d1ccf072f7b523aefa7c799edc97d7cff40d08776281a3a14aa43a1bafd6bccf397751b478ad41d39c18f11bac728f2040a205e6cd071c3d6dd1d845aa182ee6e1e31cca0f86102102001e8dc20eace8d9eeedc48d29d1b2d74e74690eeda28d35d1b39e8ae8d32ba6b8304ddb5b181eeda58a2bb36b074d7860eddb5c10a32a401d00109e2440430a40538ca36c1f16d8263a84d70c8d026388ab4090e1f6d2ad3469bcab0a04d6544d0a6321f68531926da54c6016d2af3439bcad03695c1a14d6582da540686369551a14d654a6d22c383369129830c176d2233459bc854a04d64b0b4890cac4d6476da440605225d778400ba3ba2a63b2378d09d1132e8ce882edd1961059020270081499b80706a1310506813104468d31820b4698c0dda34e64b9bc684a04d6390e86e1357c484128876343724a6b921349a1b324173434d3437d480e6866ccd0dd1e68672686e68d5dc104f7343495228120002082085165448410718dde968a23b1d0ae84e870edde978d29d8e9cee7408e9aee68dee6a5cd05d8d16ddd528d15dcd0fddd5c0baabd9e9ae8600dd9584d05d498dee4a22e8ae444577ffe0ba20123417b44473410b682e08371704361754030f1f5958d05d96137497258beeb258d15d160d74970502dd65c1d25d96dc5d96ef2e4b01bacb724377596ae8ee127c002181041e4450e8b084a03b2c1ae80e0b04bac32244775892bac3227687e5a83b2caaeeb0c8d01d16af3b2c46bac332a4bb2b737477654c775770d0dd95167477c54b7757b6e8eeca14dd5d31a2bb2bb6eeaebcbabbb2eaee20266e881334370417cd0dd181e68660a2b9211cd0dc103f343704adbb83f87c69cea78be67cac68ce8789e67c8a68cec736820f93194bba3303a73b3356e8ce0c0074674609dd9521477765eca0bb3268d05d192ee8ae8c1274578616dd95d181eeca60a2bb328ce8ee8e840e052236438694f0230827c65177620875274693eec4b0e94e0c21dd7d79a3bb2f33e8ee0b97eebe3cd1dd9722bafb42bbfb0276f7e549775f60e8ee0b0bdd7d39a1bb2f40bafbc2a33b2f3fe8ce0b0ebaf31283eebc8cd19d172fbaf34245775e2cd09d170674e72577e745ecce8b51775e68e8ce4b9246a1738283ee9c8cd19d132d76cc5081e66608a2b919c8e666d0a1b91970686e861b9a9be1497333d0f083b3d2a33920e6680e88379a03024c7340c8a03920c628d5f0280901226689e6c424a03931b73931617362581c8f1d1ddd31f941774ccee88e0919dd31016304127a744a88ba53f2d39d1226dd29c1e94e090bdd292140774abaee94ece82e491cdd2521d35d1231dd25b9417749cee8ee2e4827654977528c742785eb4eca8eeea2e4a0bb7df8e02107cdf1b045733cacd11c0f2e688e87309ae38104dd5d0207a46b42a7bb268c74d70490ee9a98e94ecb1bdd69d941775a6ed09d961674a7654b775aa8e84e8b05bad39280eeb4f0d09d16a401fc2801480f1ea61c94d0a63062da14064c9bc2ac1166056d0a03469bc260d1a63053b4298c05da1486016d0af3439bc2e43685d1a14d61c0368591d2a630ac36857122a4041f417c943968ae7c4173a518cd955f34575ed15c2945736512cd950b68aeb4d25c999b2ba50039811b92460fda94860dda94c60bda94869736a5018236a5f1449bd288409bd208a24d69d0da94c68bc8109c9bc33934875bcd6127cde1244146e0f103003e82f8e0c185076de292469bb88cd1262e5eb489cb06dac4454b9bb848a04d5c1ad0262eb6367109dbc4e5a84d5c7cdac4e5a64d5c4e68131712dab4458e366df1419bb6acd1a62d2b68d31612b4690b166dda22459bb628d1a62d1168d31622769cd0e950d19d8e13dde950a03b9d20bad349e281460c9a432305689ca03934ba28a1336aa13ba31fddddf0467737f0a0bb1bd6e8ee86177417a9cca864d467eaa6850a91080000000000b31000303824188bc582d1805846a5f901140002609662aa624617894914a314420618038001000003000000834309920a57e5639f5b9345ffedd4cd68d6c0c19b77c8486438460023d037399665f13586fd89bafe7725a66221bb533374af2a36ca09872ee5509e6a6a6f3dffa874a5b882903e1f1321fe13f0c3740f129b618bc3c26748f93dca8515badd9a1e3c6d86e3a5d7f418c0179c25a6e37782e3ed2e430576cc74662500d984e006be07a1303b1a5e717515aba0b07ba46d37869e1302c41fbbbcb518c52dcef09e4a0f2845f392ad5da7d69a53244c7f867ac283be38fd37ad44ba7834423826600241d7c80e09c31bdbbd2cf9e81c99139ab1c0e3d260c5851617b96aa4abdd44fb71b66f204d3fc2127c534a688cb97a6c09a522833496f39ef1ce1ab887b90bbf0dabc57897a3bd2ffbdf08e3afd408a7f3f150d9c399de27a1c289a9d174e9940d4f447f4f325c471aa6a672a65d945ae4926f75a148feb47b70db0cae3980b1a162b7e172de00a9c983a65fa3b2260271925103a7e4b10e184e0aeeeecb814bcfc8c59d735940448efa8b0e52dd75e39cfb75503e7e3dc586ca985f2c3fb1dbcd965b4de979d108fc7d83dceb911da33ec72ab947640c1bb11f3712117a53f4fbf57d43406b1f6aa4905c1c294bf7bd502b784c9f303dc5f485cba169264f76cef16a86fca14030ba77e20eb58d286ab86f067a603955f8b58b130871eb21f5ea43c2f951f55b0791ee2661478fe59037932e704a0110815f51175a0a68ed83bb0c5f0e39d9d32977b42182db6437fd074590b996a7bd4c87921fe25aec31199a0f8d8ccc0f537f4f8b1324ba7b8befc89f5322e58fc2d4e425e3fc8746314399859a4bd734b822a2f547706d66e1caf1bff456aafe69aa7666c6513d186db0fd77e82b0da53044ce7ce25fb821e1c736d2c83838a2ffba7b3e86aea173bc126ea2fb0cdb42b7f01b785aeff613f75782ee11235d80dc1b137017548f673e6ce49bcd3fa16fb6c66b9afcd2c0c1ef9f7fd789ff09d91b42f6ba4c39c4fd7d37dd71705125df42db4f41c8e43350897ac2ade1e130eedd35f9e56a19605bb0db89b351e22f68482613d8228141bd8fb307f12ec1fc671a8df1940ac5ed2b35d7c362ea4aabc7c96109f066ab7673c77861eb4663bb848276c47b475bc9376a77da5718a558c82e81d5a7b9df5b915270e615eb0759abc8245d7d4ef8f8153953d3c1b0df03c598ffcabc085fb59667d66cc27e5a12d392c0d9097514f6aff3e62b21baab6a54871b1df3f32aea491704deae14880738cb28313f4de3e9fe7c6c79c2337b0265f957393f2ed6392f6848fb95ca41ce8c90bdeeb9278cfa77e3dabb152761065346e9ad6e338d1834eccf5ac79f3c753c4393e7afd7cee93e4ad1649a3511ef13e45cc947b753bffdf35d23936453d3ed1694878cb1fc0997e844565ac1a97905a4003327f25041fde0d93aed8e0cf059045d626240136ec9c12c7342e166590a2fdef08636f3854d333bd1088c90e9a2d106278b12719ed49d252d5136441a91ff58fc255f502f141bf4fc344e0942c20b22a6bfb18d8c83f67b704ca8bbf17a487a86bc878e042c67eb98ba062615506ae546087d4c6f324aae086ea46e2a1a49a40be43d32c6c21c53dc573c3b2db0f0b02cbaf7b8ff101f57830311a5b250794ff5e6cbdb181932bf1ead39dc1356aa8a3432d53b78a4079c866a3a5eaa29fad82506c0fccf832d5a77fe9332dc9bc1220d57fbfbe6b4b5bb34e23cf63836144b799c160fe9c201e9e650f7e0a936b7bca9ed598f28564460bdd06e185a20cab05027956f3e7ed54acb0e57abf5f652210a7c49259e4951c6d45faaeebd77de7d92a453a09e42d4a39a84f88282dcd24a420d9bdaa1467f6915cab897d6d3b31e18d92c8091576c845ba2a32aeb1ba9c91cd45c556a550e22970230b385cf0bc527c010809e8816b89fbccd9df7f9ae06dbd09f344c6444fec1d8535372beec2c3760ba7b19d16371d945600066b72e313405b57515eed30238642f23ada7328fee909451724371a3b62e82be51a8672c7164f0a0a1391d41d441bc69bc6c1a244187965be29f180674d19e1912f04591260008421a66f9da636bf74c600fb5cae2056c0793c192fd43dc906f1bf1f8e5e4e3c65c640599223f08cd6e2da729989bb72fd697de8c12ec21d9c92a1afe53384b4d8d3fd173931c4ccb8338f19c777cd46437cc0b501fe3e61fd20fbee96efd0c5fdd28849e2594554b125eb44268194ab3310ff3af6ef78e1ad01da6374b719471ca87a5d0d839ffff5de11c0f7cb0f2dbe1c4c021ef2047b699a02426ee774c6162eb0ee0c7aaef16d512c19dd07783561077bb59cf45a15e7217876a80df76bb804716ee097302cd7ff464a597436d73fb0443196b360d4975a9979e39be158f19f0f8f947fe178f4ce6884483e66012b1aabfabadcc6dea260f4a270e906f30702109d02d5cd85bf5fd4bd96ff6dae244dfed366316cb4f9a3e90bd259c6cc2e4b699c244a38c6e26c10fa8f3b8922c4645358e2299c72be95c33251f10dd21517dac1890b4a40546dfc42ff66ec594709a5f060ff76c3c8a07ee25c4f6610a6fe2bd547406e45062d4a746b4346acfe450bf73f00db7974b486703ed40577a8450a598b98f64467aff72f77858464fda8e8ea7e09f578e9827fb905894898b1d40fb6130cf068fa87b4bf38220e397217afaeea9bdd51c15a5af22e1920aaf0ed12572ca55aeccd73818ac8862883f3aaf7bb84845da66c9ef0925dfba00110b3940c229efa20fc6505465a12409c458a4ba22912e17e532e29fe065336542e22bc0b140198154e7421354302f0dcc841ef2d8ad31457716b063c6f8755586ed9976ea30a3ceec25b3b52b3be0ace68ee80c6e4bbbf84e677c4fe700805d3c964a67e8c27c9372827b161a5d8b9191e262a962354d1c0f7d683b6e58d671a891c1df22fa023a8a0849fa597e1036f759058e5c8ff6758b9a215fd110ad6b8458f84aea9b57ce6a480bec8f8198087ff005f2dfd751ff3de033b73279a89d30f1ff297efc2a3bc9cd49469f48114e03e7c77e7ad71bc7dcf7a80a26afff58b6f53746f02da1a28d3b337aba9ee9b0a46ee74c8302963204c8bc9ef9c05690bda8d12f127701a9380866d700d08e34e6665e2cea264801adfcdaf769fce3bac75dcfde455dcf5fb5542355cb8306ddee4f33e6a5b466042c77b06abbcaa192dc6a02d7e39d75beae96d9a1c716894e9014b65b899fc872f812d8dc392d9e7a64a89aa56ddf1f4b8e9fdbc123093a21140af728907e70b5ad054fb944c887147aac51f02eb3566e6afd790682f7e055fb30d482273e32a1fcaa6567e1cea4f0de82cfb2b8e7fe2f743faa296570e32d539cb14f92b9e0d1f6d255ea44437e7268ac0ac69286509ac56b8ae2b99a2cd80b2559a2f085c41318a1cca84a6efd19b1cb07420bb83ff4f9b36b0f34edc340ece18cc316b258efe83c2bde118f7fedf3d77e2372e1b6236edb9faf25321fbaab3a1907ab68eff2c9dd12e3d577c639c3888bb9fa231ce5979ce4f1e34adb3d443fb7530120bfd0f63acbbd2da09c95d428356b83b0cff5b3af0c9718871b9bfab2ce575b71d1838efa0c50bcb414063e60fc02b7c70b127875f47ed461cbd14dc8c9d6c7a63a2c93b0aac4168f41feebeabdfe7839e9638fb401c0989c5bbc02061ae81e6ac4b2804fa61b430f6f40724857c04443df436e0008681b87d516d6bb8dac5c9cd9fe10fbc2b87cf63587ef2d53164f4b39248403673e462b7dff7baec28718eb5657734463bf28c7564577fc9f6dd112e8d5d7e13f4f799d2653bdfe29750142bd00861a0029cd3e9b710897688c04ebe3ec1016357d9b9c6c65229c1677fbc73a2db1175cd1dd1fdc73339ad395e18e0e0c7fdb48c798d19a6d550cbd8c1fb46d1e6e3c660dbdcbcc0b88885c13b8daf943f2dbf9e5beb1646e8a84d6dfcb9f3b80fdaac7108d8101961cce1c05e2d9e4a9f30bc77414be2bf6b140dc476d346783f44b7a217cc308af379e021046da59e2973294c1d4518c0ff76b534d40938bba985c2eba946a95148129cf641b635b0594386e929201744ddfdacf2d66118fcf596f92a5ff4f00fe32226d89e6e6093bc0ef65670e00f6853b17ce1397a4c1a7fb6e80afa521f3d5538de30f9cbca0fd74842711b21c062f6d5c7f51ce866958ef6b4eb8e7cf2e035e6668ddee8a8e2e2ab0a2cddb205b49a49c54a7c9966b0df3b5f7d976d34498477b05480248ae8ac8800767cac3628d2fbd70744a3ab16e51f6a587f6798e67a949be389ce2253122e477f86885d957f94f7fb5692373346019dde302d3cc243a94495444a6f86dd9d835ff63ff2b84a24b580181b1f7bd95941638af3fc66a81b985dd04929e89369d9064fab54e320e1442c2b7581fe67ad04c2056904fdcd65816c4822cd5d8b529a278074abb23b978b7bae2b5c93be9b514416591d83ad789bbf2453b2312023c0691f5aaf55c2adbd2abac0185d9e78ad34c2722b09542c1612c5cdcc2324f770f63df1bbf775c616f26ea3cb42f8c4ad68e3c183a0f6884160f6fe5f011b09f6e04b9ce082c77fb323b542c3310ac4a89665c4b58a6f2747a71aeab644a87eee3655a56509d32ca144be292cf9a0e1e08f19028dc91aceb6fa66b6041f0880db4530e8c2bd80923a224828976ab0cbb3689402242ddc92d08374fd0bb75aff3c84bce5dd64b6215fe1353a93ce58eb9472a205e178afdc28c0c23c8431f11e789af69c47ed80e3404a71755cec1d2a43b081ace7bc3af160fe6396dd8f1072ce6399f27ba07592897fcc42ea25664e8e3a9176ce759f961413b4878d4431c97c008a21a080635d0ee98c4b4cca9eb84bed17c3fa8992b9887282528a69b479d8573cbe6c8b383f65074ba7344ad2ba06026599825119cf840b49cc30cfc6d0a8f9115ef95b3bd87c02c863c932ce4a382a3feab064839322c0affd334c05164e4758df06c883c4bd03f4c7fbb9d615d7d34751741b6d93ca8397b81d72ab52395a06e71437046f3ddb8bab175b4277375c09fcc610ad75770acfbc60a24fb72809f426f817a78e656bd4aaf1e6eeadd6756bdaf1b1d018c64972dd5182224b7307f8ca0b90305f01d4e3fba825f43eee83e0dc59c207668957caa025ec37f4b1e1100c59265d1b16e0a25634e4168cdbf3d37f063cb117a6ae893ca0b008eaaeff72e0791bc24d535979475215a2f3b16a326e5f6f895c99021e6204b31734a697ddefb0583fce0c45b6dc5b8ac0ed184b334f03ad735b12d9759f0a0c64d9a76d0dd6a827c67208861304bbba464ae923d9cfc813baad71ac471775ccea3646c92d9d6f36e729202086ff9829b3a845177ffd99b195a1fffc8a227c5729b78581e0dfe4febb39ab39f7746fdfa9b158e29c413dc2a4c13304475057bf596de5dca23c557eb607e5306df23e937b1d31daba48df9c04b800c7c8582793cca7e4103d7408bd544fb2f85515be12ccd7ddb387ba8aa1762079a2d0154ffcdbce93e989b016518a18fcc1a5409e258c28e494459d6b05386ecc019399b6c8c148c3823082bdf5df8415735ce863d6fb8df0875e316042cda95a2379620042cbb7483cb2ab79afbcf3dda6822ccdb0d1ffa0ef8ad836bd58d11badda7dc4104ea60d1b596be5ca9b21ec7caacbd60d99a4ab2adb39340fb428064f3066a03ed995fb2ca946011aea6ce84e849f517a3b340420d4324704e37f787db4e4c2c470635b321b7650c3e51ca6d23f8728d73b7a38db91d5bb4c5ea71dffe1866b3bad51fa0a64eccf7f7faba042543a0fa7c9cda84dad6ff59d9cfd0a938ab810d824e1d6b51a1355d418d34e06b03f47236579c4760af997bc7c5b2cc5e957afc055f5c01c0cda8aea679cb2f804a4ea757765ce07b6a73b2f239aa3c42b75c46d0f0c45464d3ecff48793b32363349e30f605abf19112e229aa80f55325e237a4465087179e846b12efb062e26527844f2c4f2a751c2cc1900d03f047516529509229552f4a9f7907101126b9d9391ee12c6efd716ee650bbc89635b5a795809ba0c46308c542d53f839046b37fb1406f41d29e32e852e80a0b4f1d510222391b49dc88d9f1e64c04d8baf08de9f2190a572b6c84646ba81f54beed944d7baa34d49c229adf095c21f3907f0f9fb5cc9a120ea13ff7c4131e95aaef687215bec1c22eaff2472ce9b359e97e1584ae87f7b3a2ef8b2076ca758d71f3d24cd905eac2cbbe6e61691ba36a5c48474402256272cda11cfbf4d3e4f1c404f32a8fa6e738d4e4702214e435ad19921a1dec233b04ef658e8fef41d1e5d190ca82c23a87b63f2219d9d9f46b4fc03c1ab04380404bd1253dc4c50f6241c19bb31250af81f34328f7a1faf05fa7f1c03f96d1683fdec3034c830c4f065d131d681c518f7b8f2604411fcc0b3f508fdbd12da81235384c7d9d6821394845e0590dd87ef9ac8749970170c29e080b8e5e6819309ccd39febe47ed6719c4e6ba0995a49a4668991f721029f43f6dfcdb4fe7f1408cf2d254fe170ed05ac3a601f67bf62fb43aa0b5b3ee30267477cbd87f6f6fae6f0d96d9119e1fc477b5f98ef527a3199ee3c552acf0e84b7faad82f2bba08970ef19293c8074b992932fe43d5ee869e439c6d921ceef4ee781721542f109aab0f6eaa47a963ac60d4cde780eaf981045f3310a8d96a77fdd143e8a727fb81fd150dd0bea9ac61e5eb26f0789ae33f790c190166df3185e18c1ef2f674f3af889882f1412a6526e58359721d1ea1dfe7ce5db767883b1adfce51e1206048d20be77504edf970447885ba51f966b4f2bdfe3b778b7f63f0699c70ff9fcf6967ed1e17c35e81cd2cc15afbfff1ff61fe2bd44183e7f5237e9299e45da4590ab5a04fa4c9cbc7371b3236ed30abfef3e3c0ebf77794adaaf40bc173d1f07b30e01f7cf9fca94fac0437cdaa9b77ff44e3452f4f4b2d3d9363a1c11c3c3b48e723f846ca3bb1c5cd62943bf6e67708e1512cee5dcc343c909d8d3450cf458c278e70d1e6ed1737d2285e046e53909405bf0ca730546839918ec6d97f20f821f367fb9e4cdeb562b798e39c214e7ff3fa4a59f131d6beb4dcf8f1867d21b6f8c95d4e3a2b51ac39541d431cb074e6503cc2ba1598d5ddb827860b6e72d93e9f6700d5d1157bfaaf2c0677db5c538c079c7f683d02f8932439c5fc74c88424b1fd3787e3fc6cff73147196ccb21504dafd2360755d8b14f778b0b3509e3be00eaf9352e29b166485571ef314d5f829a5f6342b177ce9c7e738aab7b0bc5ff1b95783e340198b79491bf9a224311780bf4d881cf9ef2d8cb45d1fb461fec0570adf17ffa0d9c4f5f5ec71ea09790aaaf5fc0edade74633b3aa0e67ae07dc8397390cd3e7cc59e6fc71909f9465cf89dc2316f80bbf8771bf76e1db6036d6e89c63ba634e286a52178cd4286e73100fb8359995098ae0225e3bb3c538f31f893356b1162256f70ad777c5b5676b0046b4d42a969335dcf454eff6023fbdbc9806e6c51c67964990c0ca6c8b07acbd111d714065146c70791d7ae7a651be353bf57d06b8d777384bcc8da3ec3b8bbb65546bd9b619caf0be9c04b7f3c38445ca7ebf40841f5e824f9bb90418dda334179ed9398c7a983ff837a4a0b55167ce43fea1decc079b061f43f28c9c3f3b0606e7b130f4a1c626868a970e542a1c55abb6706f729fc8a4e97b1e4ecd4703bc50d64ff285fc1851644c4e6b1fc60c6fc50f4a26bc995a64cb568242fc403649fa3992e650035f7a5b35b43aa71c64ebcb09912ea4f0f4c9cd00a857fce4a43983e14b05f44ae0cb20ac484f866650ff78d72eeb2725a56e7d1a0a830f8df9beb640805b5dbd1058e2dc380c73d58dbbffd9beafede2c53909bc617672d2ae317fc402058571343bbe872824218daa8d55817fccb95b1e4b2daf8ece6b87579c8627f005b4a228843b2470d54947fcb7c03727ae4c30a88220c664e9d33c0e9748c9a80c5a39e438dff5e0dfd08d236a130f89c326081d914c343e08e15c3254d720225f92b9eaa61253cd19903e8e1f9f8d6f0bf587a8a20e6e0f11738a06f4b355e524cea79bb7d0d2fe64e41f5952eb406c95c2911a978b8bd788c1922401e6f4abed369cb46a329eebeb64ad8976632f384254825ee941477c44f174e4ed1c70be635cf4506e17e08d3222826e5cecf5bb5880d5d20e53e778ce73259254e0525c823393e063340f75e550b883e628d133e86dde5d40c13eb38a863fbad2220870959123deea5bac66937b41a2fe3468f403502ae8b03e27ce335cb305694a5fe7895277ae249bf00f9e2db224dac0a05120182f58773899d643bb5880f74c25afd12bd9afb8603aa4fccc95f324ae5f86d2b6e3a1aa017b002cabdbe25fe0d63f8191609d048e98bd60d81fa4d66a10e287b4f33d4593ea2e326a4f516c1321d9ddc008887fef067e4dbf0c141cd4ffe5a6951e3270a09762cbb78fc6b9b58795691fea4d478e2ceac866d0f9d350844ece0c159528aa622b37a85d247beac06787f5fde7ec14b8152b942615493523f15e53457516acd6c021e7c766ff7c6ea2871b64b50151b99304fde9f456d350ff2ab93dbe6aceae9b46f27f1c705c6349acdecc1153ca7aec9c831510c7b38afdcf29a94400c2b113ce6c32a68a28ac05ba34f5cefa54658c9350fc517f1f13f96320514d0d153f299e96d1b2e35589f1b2a06fa6b3d71d29c4d6c0aa58ea1e0ae910ce1b63f9dd7a16ba1c48a02272a306570e68c3ae0f9a09c7a6de9a19ebb95a5da0642c441720c806edcada3a01d94a653d5738c720d58417adb24edd350e2cb1daac54c13ab61774581168ffdddddba71012e3be3bc3f19c03549905076ebedc98121c77709c56ce0998ee387716db907904aaa2fbdcb8cf6a853a61d32cc3bb8ffe9d775505c1a6294e52b52d0d3121ba5db7a3d354fcf05e3422563e396cd6e1f2f91934e0d1db89e7f1ffe98b4a8c8e3ba53ca743e435a74959b4d77f826d69922815f2c6bc496e094cfc839dcabed12bf49804bbf454c487b66e660956295064a367b5995a36b415724ec88c0f11116e6ca55c77aa1c36188ac200b193bfacd48f431ada94ca6c8e103552f739913a7519836bcd252dd07d4fe819711471671416947d787c874ce9a58395c14f54151f9dea9350dbb9942ccd9309037c5ab1da2b1b1089d444c21abe0baf853bc349032303d744652ae10cb26ed5ecb61425be40b271fd82ca96961a10196fe35aa3917e919b0fd949795527a3b4b90bb30d3c290c4e99eb5872deb15034cb6fd02ad823b5c2aa9fdd12c7db8bd6308e0b33819b3f875f9e3f19fce17cd0dc6d5adeb8f64745f24f6f254c5ddb901f9dd5b958169298f67e5cbff44225a3ab692dd63cd451089c83d7a4f31a08edc726a793ca51e4c03af30691cea619a9892cf2a289934cee986aaabca466b1bd2348534dcd511c177ecc411fcf85498635a9615a9023b47e50a464142598a2638c73335a62fdfecff3f4b25924e755cf846e498c15fa48615ca330d363976bee0086b4e3441615ba41a9a5ed608ae054ecbad0e26239b8e2233540fa0cc8462ef68f8eeb14df7534c774c1c8abe51a93f818b34255c61ff2a01a3c0fdcd97f0c2b10f7fc1d86169edab7c2f6fed3af0f9e633eb7c5ce3b1be0a322f0f87b1383309de0635f89df4dc9205f7d37671e07e04411af2916c633453f24ec15cc9bc544fc78f7af699ebbb10ef9e7ea8be052800b7f56bb68257c4c407bf8b5d8b7bf15c19b51e573883937e35d2449f18584b84e21780754c901bf11d728da0870d7d7a45c2ae6715b612be868f90372e5e4054dcbe93391bd55f4413030c461af6ea964412deaa07db79dd709633d366caa91b46ecf4c30e7a410f94c2b83168778cb44b6f0c41ec8e18e7d0764c6f8e503b9e77610d639d08911fdee066a384550e30ebe38bc063a4babcad8c972a56f046a751c0c3336a393cd2083c04674a6aed22f04215b22afbf58e21c31be910c7d530235658780492f5677df8a5de7945a92ca078aadaf57217ac802b8604fae60ecfa544af7067be053dc8882c967dae3b61effba521c798d6cf7eaa192671bae3715b6a7922d8490ec23d8624454c1c059051022e805acc76bfb3f1fce0bf5de4f29b927fbe021b9e0891b18229c7200c07f85d065e4bed746fa94de0a25750fb5fe4283b57d7c7208b1db46b8635e20e35cdea4942caf0b611dde31e5ea3606ef99ce22fb33e734434f256c75a650da66dd7d9586e98510051d7a12ca72056459cf1346960e7433b604aafb0006a15a2084398affceede9c93994894a86a54bafe18a350bc6596ac7c5232c964e22557bf2f207a2c6c855211245b28fa84bc232d552bfb6505f73d96133c4925063402b766fa19534a0297a83c6307f0064f5f99222facc5d925f217c5ff5444c51d4ffdbd648d11b1974d15e3ccfc860744fca6cf86565dc9bcbe1a0d29812a2f36c85f859aa45fec0636d8400f359c9b0a8f4563af9ebb516b860076ff34d156ecc3e087888bccf8d17810d6eb8e0db8fc012a12ebf25e725091515645697918b96544bae6918cd633ab6c858619b085b6bd51027fbbc944e02671d8134cf7479cb50223ffd88d6d41914d3123fd089d6a5d012059732848bc96daa4599c17ca095c46f4162acbe175058c2e7ca89481447885817bf33f7815f13565fa325a5bddb2eac79903bd8e5e295b4ee20a961730b4c1190edb6e504ecba300d8005c40edbd6962e5f2691c8cd610f20a5f5b32a194b0d22f6d8f0d99ede2bc654859d1502df1f4ec45218aba9ec0a17a30a5b91324214cf16061e77c1ed3bb11fc16bf0ea46872173e139a8eaced493d5720630834e5c5b231d7d3fa9a78232cfb9fceac7e8d0b95285c08f0e66f070a59b4fa9f13cc6c8fddf2172eb127b696de14f5352922206b88334a0db78c55632866d07ef59e9d08e602b1e8d6d836b7b1a7238d72cce7b8ca11e29059c47c171759261078caef753368f41223a56fd3b48de1bb64c9ee3b07dbfc3c4843b5f08b77a425f1bb485c55465f537e13dcd5386f74c28a67970dd11b061a91c73c4fcc2677aa3795e0159d13a6ba914d4e50ddcb1c1bc4ee493e34635855d98f06ae360baf05993d501f965177e22957ea7cd481a4a7b95afd02574151cdb8c5d85e086eed1e14d6113a7e1eb528b1facf37220742c206999b5a15fd7e6277252c33d46646736aa7061ac4628734b59f82bf4435208cb87355ad2344a046546f5429d1018239150567d9a747b60e60b1d19f2f1fff55c17f67bc8ca6d50cc02da976afee6cad5585bc8c707f7fc9259ad80f120aef231b7558cb729a6fef71447e57b6aeddd6bc13e5f4f82d58f9fcaf5c7f58efcd5102e180a1dca2cf4806505ec56f2b2b05c5aa250f2eb28e04b3120c771ffee5aac0d397b362882d03840d3db913e03ac2fcc9406e7c80d6aeb9c4ce0a08be214db9b26fa7a09846ae903221c9c62072efec4cf7d31e4e862196f2636fe45a90fa017782574af6c7dcefe0f0d706178dad3a3c494c89a4ba1dc158a8c8dfc78f4b614d80190e32d7abaf9f9a20dc40deac5431d54bd6a5b730a183228cae2718bbb13cbd973a95ea07522184bbc18530767e2d2f3af3fb6b476258c40a48d263a75ef5d81dfc2e481e49b03c2f2d3fcf83f6b78e4f712a38b42ddedad4961df0fef1f7997c2ad00900604265280a7cf35457b7901d8fa466dc1e725c3d53b37f57f748b6063581edb2f77bf5ec7fbfa05cb3d8db5bf176a0834064851d57c4fc3982d124729e044fedadd181ebf035c22697588a8e9e25483db57a80cb35045c53e1402c86d6ffaf7946d0b5ad3fc63e1cbacbb479c8309b2ee17108de40fbb666d0a3c6e01035c4dbd0a0a47f55c31d62bbf7a532c1d1aa231d258c37bb767d068f6264174c328510ed359e58760753f2e749eb74eda7c9c2b289ca154362f4e6c0c07a03b98b55adac6bb8ff19740247556840af80eb4ecbea9d54989c22d2a62df40c0fb783ff247570fb5a3c2142ec055f4952c53d45d3aef2c2f6fa2b27e76da87302ef852a63ede2e5b58469166083020c06ce1b62788ae52bcb16fc29a71b6e256941af4b3bfe37417582fa5dfec3f71e6c736c3cc8d81abfc8cd273f129c825caab7eb1b0a263b241b525995f8c40b3a3ad1c7693fab5ca9e5aa2efab194e46992d6bd5b96e25bbf2ae16289f0a2c4a23c64fe4608d05f5d9bcda17c0427e1a5fad01662abf4808ecac568c60da63c267e0dee3a1d73a54922b1ce48ec8c75afc8ab0da93ffa8bb187aae57582f65b6a41e07f4f672cf08a70f21ac6f0f94e745c6402f11ae5638ccee29c477be216a0aceb4d5b743d70867e741393a89511ea205ae82bfc604c4062464a35fa02fb946374bfa6e469262ff396f1f76a12c9a87f86c83c7ac67e9e08598483618c43f66d837386380306d69cc4f5e7f5507cbfb26f00ef8811abba53fc9565a67fe46144f70b3709a24cb0b315d64a881c77476d6a579ab5d1f665d51814b1b2234ef81834cc4dfb430f4a343b48f92b36439ae497ee3504b41d860326a827bab02c98c03f1a8d58067f7106c023ccd460abc50ff2b12366d3f69bf8ca612a411ee50dc0ed1aae9b1574634bcb0ddc8ecc1159e9a70fa473c0bd89adf435155033313ea0677733aca31c73b19da001b2f24561cfa56a37a3e751d1c4105cc0936cb0aceca14c751d1019c9bc192b555485200f934049b15cd84979754d00c02b127f90664abc82cabb8b3968d7eb44657880098f328b150bc8a939a5ccb35c07c4d8b78a2ba56125589ba39ee19fc5ec290364d82c61950d4d1de5b8773c048ee304908c0fd11147d45aed9489d6bae3a97448fdd668af511067fd291cb8b1996744f89781f091ff65fdc1c09a789ef918acb25f7f060b109c6011196ee6720a825de760f06102fcf13ec750f61b51a97ed47c6ff3263ec682375c368ff280f72c4c8575e60c4f561bde4979df268db83f32988faad10ed7dd62a173dd23bd9d13ce67d66200439e313a7731fb66148ca665cc1df2d9d6eae3164a2a88b6e546f3b889ddefd9e91e1999ef1af21ef047bd7390d61b63b82b59ce503059ac0d707b1fb8f9a3e974f107755a7297891b601c237b8563235f9d1ba5d98f369c292dabdd8b97020787d2a74f8257fe872a90f3e1a70513de0770a843ea329ad7def16577e816b86fdb0a0f853a4c6fc492f77b9859cdd4c07b1a37b83206265d5661ecf6bb2ca0a47eb19abc15d7cd18f78266a69e3ed21f409685b9dc2635a9dab028335c1952f06b8ff8934b83d064c8f876b0311084cf33b2ebc123240e7b36a463ba517a68387faa0713f518b31629e215eab8c1b86960bfa0fe63bc3d1bfe8372b207a950c05c7061f979ec312fef6efc75a856042c30acfb8a19c555415418dc734e4c390f0eea91a256952a5886b88c160aa30f6d24d9037b9c4cb328fca42d16e7d8d75bc61bdebe91c5706f8cbbe3620124efc477eaa144470d201db015520c13085d7277fd8a5f5f3022cbffbcc05ef9102a39684662f1a880953e4daeed7429e63147e364bc954c509d81271277db43b4cf45b4e896d17bfb187a390749db02bc76166243d36581722b4b65fc36b7e174831998dcf5c1a2e42f48e709d722b08e88d9a485fc978f0036f14e2ed3ea80d047e145d543626ecec4e2a6fb3d386897e787108ded6f448b10c589be0f3ee08df3888a79fc3f36046bf32cd4fe433b8cd71102da8805ccb93fd9217010d12c034eb837104b87165e5587cf953284a1d828d6b0e0da5b40721729df88a369cd12e158360084f46b00c88d3aec9ff145d1e2edc23b2966a714124e216c57aa5818e07ddeb1703650bf350cf1ab886304e93c1b9bdbdc8e1d4a012c28847c0c443dea4d789f7a0238db5c8fb9d453beafae77e3c1ad68ed7b659cd218db7f06f8014e77fd15852e99fd4d5346e9f55741a8e1761df28a0e5e38f9fbb5766aaa520b2173e31e806be87245da5b30fe921ced4214ee5e8bef370ac3c7cbdd4331b0f5aa92ded6dd9e761a50d6e49d9d5eac2af511c25dade8bac70600f9735b096610d52328d1577694ef801fa79b44c9c33daa80fe8b4e0679debf80fed7b964fe13fd3c9233dc7ef4eeb9ab65e63ab7c58b79743737f42b9d09550f35e6e407f79bdd96d10eb07d58694991afc691be9bb6eb94f6ab3d283dda89a971066c0b5f46c058e699ff6182fda03bb54875816527d6108b30b86cba205c274edc0b9eb11d3ad386ef41ba2304a22655352c8617e8b7194b8dc75277d3f25b48eafcbfda58464806bc34c1f25fcda87d515b7520c250cc827619c37e786050a277f1e77d29b2ef331dc5c9774d260a669b2e9fc13eb5f61a467f3582471a15d9067161d09a9a697cc96eeb5bd9a07897584e6350e01a646e4aa5e7daa65d63d5194d2b51b1c6e777b38d586dc01b8679b6eeb65700cfeb0cf4159cfe338d1e04c5fd670ad1f66bc581f0f8c2fb773f066ef4822e88c2fb26078e332b93d31300cc252b37466fdab5361a8a46336f3cf1a0475bc638f0ebf2b9b5ed5060ab3b7661018ed007fa2b07adcdf1a05531b3f662a110f0d5e878e5774e142d7e29e94cc73e2f008c18029e9fd85c55c611cd5222cc1fe076616be02e0f89bebf1268d5b45f41e024c2e9872db2d791a97c5935a7e6d2b66e2090dfce48699b149217ad2fd3ceacbec48280a7e7258eb7682fec4f7cf964fb84a6e7f02380b29ddedf59823e73885a0881d5b30171aaacda2decd918a8f15b7908a1f5adc46b314000807e07a6fddf4d3443a9201f4d861d1e7abc09500595c3e3b9b37acff105acca0b01c1faf4c71ded8ef1b63db154a6cfc5c6ee1ea580d45280d59e8da831497a6f73f6bfac36dd2c7f71334b0e3a6be5d9cbc3adaa5452526b532e09c3ea318298c684079beba37382b0c4373309ae664be5477fb477df65740df72b67b04d0e90590b1d7dd040f7ebd65e1b133a0d0f04051c1dd2533290493bc88b69ee3f3e2b3f591e9f04d267bd9ce2b438b611b0cf45e370c5744b6abed45f2cd512f75fad2ddc641faa2f690bfb1bb5ebb89d0496c9c9c4e5bc323a6c524686d4892dcf6c654addb8d68ddab36bfab7a9db3679eb0db8df15b98579b766c74142a217835c4679f08ef6a9fc5173e42d6bb7e438cdeda6a58229ad14d2278a81f4ad40dd65d772857e01e3f7fef6707e86fb846bc796e321b87c867641bf35505b4f6f96ee4b6ea44eda7a97f06588d96588ad6ec47744e780b75b3633aec815e9e4b8d9fefebf8b393dbba286a28eeb86054584e62cefc9b430a75c9ead330e3969831e2f7cce84dcf14f2de736b1f286825f4cb9a053d808589c30cf3c61f9a23d99e67793b1f8e8b3f5442363e9e3d245c6f913a2c0e48eb189faef662f8e0b029e88f4b6fbe0c29d03cfdfb45d73be8e4a84e3d5574e72779814c41f9424e4c0067fc084686b62a1a082a2398aba7b35cddbd3f4e18761082f9c0b9140200e0ca6e3431d734a069aa818d7b3033c84540b52563b7a67dec11c83bba033d2c76feea55bfcdd1b2dde85db74ac8d57fcc48d68be2bf5f9b854a798b61951d7a942694bb8632ebdb9fbc63e823309bb3b02c5a6321653f519dd00d4bdefeeca5fb31e6bb1a855fe7f2c72a44f2cc638f481d95bac6ab97d83a75e5ad05cfb9d1b0d7a93b46f443782edd82165c02202761b2acd9cfce60c309e95b5af8ad4c59d77f7aa9917415f15d29b56c406350124601ea01f1095d5720fbc4359cbda72c57c5b61e8bf1c5558b21a8a28a9fd814ed7410302bbe3465010b6cf0aafb8b373a95831448994a9c1d93453705d147219397ef238b69d1b2227a7551ed0be15b12609bfed7b511a8c7d1cecf8c53e5944e707e170786c8a314a6449f197cd2b4b9d7b0404f93bb2bef431c8fc1f07a74eb08462042b50174617020e331ab397be036a610e90becf0f8d0a4c66502caf73da2a9a42a153460d2013647ea86d6632d7c4ad3917925b4b30ac5715b57cda60530c5f8116a87a7a89f25fe406a8d4c7e2a1cec29d7322cdb66080aed4fe230e528501162921a10c9f0f5d93157cb0e4565619b18d71fce51890817bd39f530280b5058507f16d1cd74059ebac6b0c84725cbbd9b17f74e14e11ff2319ae89104ca36e8ee7f65f10200df7cab55371946b6aa5ee8800627e880e9fe04cbdf7ada9b6741328359590eb01af70ac0dc5aed8273c1bc90ca0181736466ef09d807b5e508debfccaa53fc1139ef1b3987551ac98382cfcd7109486e00cf8548f969981dc99b0f468ab8503d30cf541ddeaa00dd66aef254933a691dd9f43418b499e54db2634e6864d5959161faff71e460ae8a707141aef4e168b1016a693b86637e3c0924a33a93c98d7ac028f983c52f122ba6ac2befb64b5edf75482cfb7f4c7d8e6ce382d67d5ae21aec0e389a19f00e7f3bc7113e952ecfed33684859d26a5c8b17be659d0c8e6b740bac68966f3beb453bd1311e32a327165a2ceae0983df46cb130c3f9194474e7c46bf7f5f4dab79234de6e0968ba4f16d2f52a6cb92c54cd976cc84a1e2958db7a86e310db0b0ac24c10b1dcabb7e0f978462b8ef0e5cf4fac6b0c9f48273ce2d144360cf8e3ad8b1d852619b448d4bf01b84f119a53f316d1eff8917cd5c4248553125a796ee100204329c4a5c8d6b36bb857357ea2d69e52bfcc3959a01c2139fe05111f88b136fd076706a5822bbd5f6915e4209b7b885e49997c3e5b173b1f932c40a88fde3cb4bb73508ae369a23162c3c138907a750ffd2387c12e99bca952b94ba469b13e2c01cd33416485701586e5316779dac4961cef5babf706a90e1cf6461a89d939c930fbf497f1556df2f9233368b1a79b1d8ec4f29d5629803bfa6312bcdd8cba48970d92e74b1466fa47891cd1422504eca9a438d2b23854fc2971d412a1f4b84b01a06249d0aaaeed28ea1e2216cbd03f65de57ebd13bf58bfdf108a66d2a7e769015ec9b201bff10443864f6bab91639dd8315f9c9bb1aecb26032fb65bb1c5dea1b2bdb84ad0beb7cf376dc796484de51832d3a6055d30e54de8fb3c4fea44d784a92e4c33e7148b0ca8325943b9a6ddc665fe7eae2d8a49e078af8498e960cb1423d05656c6fbb7059f10288d67543f46b6fc7ea9b0e8b518bef437dcad17ffb8e2f63ee4d18939047b4a61ab49389d0bba4bebe29810daca5dcf927d09fb13f9352d638140226878a945650cf7a14d2a08b9220e45857edc16cf9c0113d1c3a1f95319e61935ce97d98ee85534f18ad52a98150920760a5eb11607c9f3167e087df8b58afe41fc524c3d32117c7654d424d3a7496f4bc07c22677b9ae3edaa3453457632746071c8b41fe1d65c51c2a29151bd2e57d12d1fa21aa6d78b49992ed759914c298e4138917e67f1a49cb425cbb94fe111db70f470021cee1ab1977e5568e9c0ecf49ded764d3852a04150e1e55cd177e8b856adeaa5b26891581caaef3284e8f838b98c2959cdb193b66ad046559d546882747081ed6d2983c9bb41050bd3639a743f98896711bceed68b35c6661c4520d4c8b704d5a45231c165036cc08f06f41b7985879d5f58daaaadb85c67897660439d68fc59ed7ca23c5e29beebddfd3416cc7011fa1f839421f0cb03c62632007f969a0bc825d1d8db4684e865338dc0ad177f70ccd1cd3023d9536e6d4846d70417fb21af881cdff073ee34a4321f4353f32646286bdf30dd5f64899d206928c4a0dd6f33d6140e4d01a21b1fd16c07d2170489dd245fee1478782aee1e00b0d84347640a0882db1de91c87b3241d2a5957efa08fc5abe909e91681e3a41966c344993ef9b89a1042076c0c9ed9e024350c3801b31ac3b6150503d673839a858af2baeafd9c3c5c388510c90784fcd708e27d50bb1767a74cfd8db58e0bd67eeaf0d00417c87cf84e0c1e97900700a5c2a03a653ec4ea05ea9c655e63cda0b2ed8ee8716e8e572b95b631333bcb43c0f0c53ae5ed43a9a9d6e4e2263eb06aced8e17f994d3f2ff644eb77b2023980a4e3fcd87eaf20e14f81626a63ccda8b4f48ed7fcbaba6fd408296a30a94b6cd2dd385508582f4b4ba86e67784f1574c2d5b6d6030d6db14e072a69d4c24503fa02d331fc8221f662eb8fb5cacc473be6b360423d459654a87bdb9225538ca5184cb5fb995580612c1faf405a9e6e41cb5a1b4a858756c355704317bc1ebe9a79d1c30dc7d4b3b59d7ceac3d607f2e9e3e271584dae1df4432036b6abe4316b9fd1f19683dbe74ea8cfdfa62856042fc5f3de9ac13307ed977319adf29974141c986a46f6893f562eeb72463397776cfc8da1273869bc7d76a83838bd6321ff53a5ffe767286f3b77375b6f747abe4055b91c11b176aed6ac29be7b91c32971bb530cd595705f6a33d96e57571b6584054f2ee9e484bc9578c24420c9cd681f79ae0f795799346b3d34fd88a95ec8b51a9b3a9e05245893a721e88090c788ca16f3824f5e6be5fe14e4d0274b058c928208dd461676ce5a1de8867b214ccae5156733a4c4b43818a0a47e8f2ee283dcc54211bc6d8b7f91dd737cf06e70efb9bffc260bec09e40976aed384e45359f871e1b92dea4b9571265fd2d2099630c57d0d322a5e86c12bd592fa007b327a1e281816a7e85f0cfda3cd24edb27f16a2c42d342a9527f0517db934e45f414fbf086720457b8f0c9e36c04438f048616b547df19f58ccff3e9b555841f90b4d17f2e8a42e80f3be03c2277593b065f4fa5cea0a1b503421d227b0ca6a19579d2eee4b9ac8233023c413d116d94f3075a7ac23c60feef13cb484011c09cdd6105d05205b4b5429dc65764bd2e47898807cab354e17b41231dd81849d0b04094416c20c7b0684c65fd65e8d3ee988b86864a7071f58e58c2ae6db80ce552288eb199f5004ab7b4e9e41e0a3911b542544fd86ad26a59528470c3774a1ce71c463dbf5e2be0f18655396bfab8820be25217b4d4219abae733b89437b544743053922e176b5bfb34870dee20b84a852ebfbf0a6de26161f9e7042ac4273ba95da9b94f365c9a70f8f046fa85c329ff69efdb06de81b8f6b459838f791a1da2b317b8e3a4fd6be33af364d3e09a167f4e4b56dbda793432d1717960321d8a23a999165f29d11d71dade6db1ddace6512ce170c352f0c87681aea09383e25f9435eaf055a6313dc9e4a15481617e82119c2b34eb496a1d7a6339872f323afe8317c05a372031663a4a41f01dda7c4267f530b9e82dea4d58de591df0ee8fba05b9b8e87ef0b8571973b5e5551a4d58f54ad7b6fd88dd73226ac4047d37f41571c26f041b18a990e8db4180169d426221d70dd2c5a10394a961074c0cf27f896376533484f2176823fbcc1b2b281c1fc52c2b368ce4905f38f09454f54aeb0ca926504392d1a4834399189332d4ee75bc64d1fb1251f8b55e4c5c616298460be291ab986ed78d99cd29b66a9a46f2c29f445d3116579c7c655c6d54c035baf0d5d6eb83be83a95f1ad286e4578d7d26c8b490d7bb2a6e4cd6a08cdaea5890ab6dc953855bc001a9ed0c7a841428a692da6ec243c32c15f3a592ee6cf072c1bfc1e671e0fad43871b98b895154827951c394a009a0bdc8080ce421ef34a2a028470f1390905f172dec18c495ae2ade9b789174a35678d3549f2e8d1c7d42f49d8d4acdb6b29be6ffb1436e7d29cb4c1cfb1fb3a76312a8899a93f0706bcdb4ab569d04bc1975d7e22b014f7e98f3786180c5e8d5c1abd91392aed7caeb3b2da20ae9c279c2bca013a1a8b75863eabfc5946aabb1df5213a95c517acd2c396e6dbde5036ff36ba826d00370a88c64bd2b9412fbaf779f0a08fd01e6cd8c18dbc3f18ff740597d8f9772df8c654d7d392d09252477f1902785e99c6e2681a56f5955a8813a084e4102e104e18cd0330980e52fe1f4035569b036027e091126e59840f999bf8206c78d0e702e2a338e4bb4d0c033d70ba51c293a490e8064ab82d01917fa4d77e0242077cac40afaab951e1f7460b5430a3edaf11d4486941e06bcc7c8c7116f6417f1e2e78650b5489aae312adf110dc36c75b0589cf9785a5ac6482e3d690e0211f244739080212ce40146b0b8c1151c018be7660b924c1523d3af4dc80c6ddf2dcf26c26cc44e74d9cdb73cb4b811bef76d760e224de938446e4cda2025b018f7065b4e487049d0051859830b9ede40f85b5fcc0375bdc196673d4f74824a1411018dad3044ea55051e5aa5eab0670e7efbae48ea51b25c570e36b85274a97699fd90219fa8602593c248166e87d2ea8c64d57c796f9770e917eb825d283b4153a5f9618b84ba50b6d070b425f4e8a77b4f158a82022f67f9b03fc1f8c38785d418ed71c92c776e475ad9a6af7a922acb38378eeb13a66e80efc89c55d8a255691a400a427d61b7e1077886b6000c0df7b62c784de243bc727b61a15b7d08051547aa3f5bb2ee021089528bd1f4db050c0d7428facf10a5428c35551ddcf23bed8ced931b86c4c3d2f4df343783448c716edcd4df67e20c11a012a0e369527963febca08acccd86fc6085877d18c7ff152604697d278fcf97cba1882c2c3e84ca4c8aeb1bee089bd770ad06877828062386bcf6ee7796b7706bbb69dd29091ebd347d7a58046b67b9cca346da21180453e8743ebbe6fd362c9a07ebfa87f2ffbad7dd960f1e5a9d22fc960633ccf3705501e5f9a9d08dc6aa8b0d072db296365f2a6f59f99097efddd715847c67be7c49bbddcf6a8dea79449c73c669a2f8fea32488cbcf35b0d803fb37d13fbead5929a3ce05a3d76cee5ec100d7b0f626188a7470fc85b0f4ff1f592e4fbec41e043f60f906bccfffb56f7ee4ecd8796a48683850fbc1d20fdbbd29299962e936270afee6fcc7f236cf0e0096f6970c8fda531408fd5e3a902380a51e07e0c9d761d05fbb1d1e9a56c14d8cefdbba2c8b5ad8f844aef138a5a9a58ca91b96816e2b3c0e62bf53e0321612c9e64420bdf37bca02cd2cdf78f60664f6f90128f5d55569e67fe1e9f5a862bfa7f6b3b069db9f1dd3d6fcdccb052d8a957aa7b00f4586f28da94da704b2c0406e0528de8cded497b0a09801ee646bbba8ace0467b82399b84d6700512e91b911f5ada6446d6cb83f61741832a390dd177a9fdb9ea47bebad105cd303bc3588180a23928af8e6df208287b03fef6da9d274b96a191e0b1bddc1136e16d3960f240f6632487101274039a5681923d406c73768bd8ec2e447ec841ed6048e37655004ab440e3284e714f4b0bf8cd8f3ffe6f3707e1fd5c95ea5d863e2074d78ef0209f2b7bf88cf2590606e8288e2abaf3c92db071c3dd78293f64b030a218b8bfafb8fa868946478e26c07d12200505948db3b00abf45dde5513d22863a14c70757ca394a15a7f558e9d03a7a05120e400e489883ff247aa5795f01042b592ca8144db5e9288c12df9bae1a43692bb45fc9f218c460ad70aac1333720179a957b42de510481c15feaff5e5c171670c2bcb7742ee01ba457f5ea4bb3d4c80cf9d13bc1aeb1f2b559fe09e68a3de0ff91ef230f12388cf31e2d4b0570f95d70ccffec5c3a69939f598174b19d16ec3dc615a5d8f5eab80b65faf3db0f5f880975a7382c9d21cf39cce6780bc842e249c50427bfc55f101a2d56c9fd5b975ab4e96e6d03620039793701263b4db0189009c2607e9f8a2b968961644c02648370938fc777e77276fe99785cdfb5152dcffee36c9f80fc4cb42d27797c7e818eb3b2201be219a067af033be32090e49044fc7db8545904a897a4f5df5c1998f4d2ac3f8c0bc3d3f82203213b4eb6346c5577370b9d6e94101ae095c78584fa272c32a4e9e33397ad273e3d22fcbcbe4d8e49c3383e0237a73c95e08be58f53b3aadd4d8f743806e064d8874c40a5691142feb021c1e889c457849121d6f4874c30fab86e83207e0cde39f9abe600f3becbf5c82bd3d91a8425c4516c284db98c9996b672ae0d50bb30e28443fa19384f799ecac3cb6bcb1f6b5fb39c47ee25bcc8db6d50aca5be5441dbef2df3f1add02462c3d1c4d8e76e7840b1b23017af18ed0c92939f3eb6dcc516336aab7d31bd37ddb837795f607d700d8d35cb5c4cab26be830d18900209e4547262e11a72f6507af8b2354785e7c8d03027df6076fbed42f1c7e577a52b5bfef7b7c9d32344d82195a5f1a2cd2c27eb7e8ed73200681ed112f1ab8547caddaf949043fb9d6ca73c86ce273529260c890f123e481738ee6f2e979bc9747f4d491bdaf032ca60ae12f163be3af029da1bbcf54b58206c4d86c72c2b544a3e842f11babc660e7472ae877bea243d366841b19cd6960333486770cef4fe4a3429803987fd0406b5061cdc7469faf7a0f8861069c2ed8241b2a79610ecb13ad1508e5ec46470f0e3cce1ac6625dde41c3cf1f0052f0af3fbdeb7bb9671240154959b6c19d61f28146b3fd3fa52e3cacf69d9536ff3dd52e3d24225a7eebbabd69bd5596e1ecfbb2a851d8b32ec22a99e682257d9067ec1127b1cd20fad809c0450f966e32dfdb61ab7b3d9f14c05361bdcf8fee2e1dc0008176dd88911bcecf8e4dbb53bf2bd162176fce29099680b7481b4cd3349dcfb6ff2c2544369b7f56f98a6a26b65e65313d17db0b2547905b238f01fe45880b1be2441333902dc15072223971452f969189a920a4a81c12ab535fa6b0d8a1e7cb470a31241ca16aba5444912295609d5137bf3275c9e04f4ede1f4f13541a18c7f7c4e6b217b3f6b7c60388e2de350f2d51ea429dd70f0ffd05be00a616dd0c65ad5f4105d5b01663bfe81599273624bf680abfa90bd33f63ce8b8b46bae95297a49803ad066e39e4f05ada03d4ac365c32463fdfc93d65bda754c251fe2771041b3bb12fc7a3ab2194205b1ea150f5348f8905bed5679516c2a3305af5737fec21cb22f8bb5056313b1e6081cc78be4956008db5331e9029edc5505f7ad15f3fade4a4a4f2de91b33cb0e6ff20fff2b7befcc82de26e7810f67ee8a437014344eee8007c76450e58ab15eb16087412b5f4809e39d0d2e7c9b1007ae3b31fde6c1aaa8e257e90762cd2000f8f766827ef114f53f2f2af9dead75606dbf3dc7c360318b71cfbc95fe1303aa172d7f97e84cb4d03abe02a74b6ed839bfaf31c343829f3c5a07099783895f735ea1bd69f321f363a4a5678331a1b4f61d6729c7e6c501905e28602b3a7149b44b105a8c4644717e3f9c325ea85af2bc311ea0ca8091a80de4c07138057c6caf9d4d80eca4f27fa355f16bedfc85df5f9dc43b53b0f058c38a633bc16d8eb8dc81b69b173143d1b15f2a1e1a1faadfd4dbd083372c8a35d042d3057310127a62a1443647e3bbfa8e82e565c11611136f880b2030e870518494363ffb20ce0eb0a6e2a7171269065b681050028193999763ed3ceb14fca79b17339c67673db3aa7ceb85881a7a27543f945f451a9ec4c9c86ace8a84a5de1a9ebfcc298cf3dce81f380ebcdcc5e5ff8b11e7335e77a7f991611727b4ba124e17fdbcb0fc97b157784b422b0bea61f8d6095c088d333bb4fc4b147fa7ee53f7f13e86e33c3b1b58618a8ef5c85bba8a632534d87385c283de451c41fdb49452d6dc284cd059d81379d84f6710f465f7f014cdbf213888e2dbd26dcfd655f31e6aec0ef5df0df71fac09a94d06afce5cd23ae732f3960b9220ce0d7349b10766a53951a02348e00bca528bc8ddbce02d81372ca11a9d751a0fb290b936bd864f19f87dd02d3b5100134fd8f86d05a53db87e684569622180e579738a80fbb8ab08dce17e2cda7449ac2ad85666c646ce0d7191bf4242c3289f25c7af22337ddb05db5010c543692ce7325ab08affea98b542eaf7d286cfd502b34ba69f40fe7d1bbf6c270183fc6f093056a0b583945d89e39be75ab40b563aee1bc48e89680e7ba4f5573e2d1de6d9b20e3ba8dd3dacc6c9d4918e3652ecf3969c6d0058eda49ce2ca830c7dd991612eb161b9f60f15656e4eb3ada95e3ae02fd88411385c16deea0baf428324d2ed17048aae1abb460e440d049a1d561910a1038e1af0be4c338342d185b6a93cb207cf7d857407a365b7c520ceb275893e28e602ba70ee1c0c27a26916ec0bcb21c4ec43f57166ae8a392606b6f295a1e7f37fa4c58136552c92e9d2306f2d4c9085041b2377c6cee603c08ce3db49b49307d9b547c0e447196a377d50375f687a41a2e385da0d03e31b1ff59c0b63568399de009b02572fd42e19dc57cfcf0811e3fca9ce8bf0e8dac16c3f3410bff6f921d2a9c0644463667bd54a7cfed38d1f725259ebc68665ba0d918052485873dcdd203678efc63332d2accf9115e885ea7eeda49a7727122c7b1cd0543f6c9b4a868bc8e14962ae140875e2baebed072283575bed8d36dbf59e1efff79ed3d27ec05d09c422daa9ce89c1bd1670822c9a9eff37f25b8554282f387a7c78223e90bda0d0619a4a9d8d339e23b8ce52d53f20777644d49578ce345e1839688cb0f3996d49dac68d75a6e7d8c966d7ff56f4f17216aa92c952bf9b0867b6c59f02b3d28cf869e317340aa7ac45c5524ddde9b87556dc29d55809ad7b4436b35dd2894dae2a6fc04d537d3665b78dd5c6b5e5cc8462500df71ccf70356a0889afbdcd9783211299b849fffe2588d0ae2d3921959156191762ff728dc9467e886f8f8c480067e0107b90d632fdf487bec9a7ffeaaa3f1db888f16d8d7ee2c2a8688af79a6ba46f4b06881291d8c6c16f8fc650e48a9ae0c7819dee75a0cc444155947001c52ed1b5cc273f9e3b5a541f629dc394bb33b40cfd52be022ceb8e6583fa3097a29468d4ff4fe8065ffb6dadb0eb37cd95ea6f639db3e0a9c19f1a589dbbf0f3a77c15edc636f8858301e01d6923cba4512769647b4a63e814186b975db8cd191014241fbc8caaa69ed739a2f166312161c750c699cbebc9ca288d8d74a29acd4ad49a7f9092dc39fd8ec373c014a762352d095bf222761387f2e956249d46aef2f9abc2719c4fc58522623ece8b1e5b11db2202c6da8cbe54ceab5a1d7df922b96d7b6410240bd3436d971045989320c74709bbc516792cfc453c0d4f84b05d0ae96eef634110d8ac2622029efadc408d41d0b118ba0c62130eef353dcf938b7e354432b322f78cc3a47b5c6110d9b02a398e469b07e33d230634404e3af65115348221079ce56c64051ae2505b95f54c9b4d0e4dea8e218deb9b38ee2be60746becc353d89cf6bc175e962f6994ed62eeec91850d5429992c2a783592c7d1b28132f8b4ee8a8cea22fcf1a99e36d5610e31fedc6d98618ef59a80d869848c6f1c8cb4a218bb328fc0f87b5fd36c1f779c7c65dc75bf0b934fb5c03b8a5b83928651bc996c36308a6c9670d2aee5400984b76a8a7b9814f04aa6ee4fae5de308395d6320985a84a83072f02403b3b8e8696c0fb70b83100eb0b4bed01eebd5ce19cbbe0c17ad47fb26bc39e1a4bb7b183c024bc7d48a423cd71fff8487514a2beecc8006f9ce0616f22292f1ba71f0009cc24fe86314dfab9c709a620b3fd116ba6d284f1a057a9eeb6bf2002a10614aee6add1eb75ff323aa784a3cb2e615ede82e344c804be57c76c4d233e7baab476e254d7ab6485cb20a7bdde13de9935c1b4e5d5acd08e558e93ff1d725494ee4fe694c6518ab125da9a04b4c2c286527364118309865c1d3dd4c5f155c882d606e6ef7555f9553b43b192836c864c038c2124144e5f632e30d5310cb6635407d6ef8027568c8df152a8ec0902de1cd2ec3383b4361c9a1bad081a88b174da7d86268d1822f2cadaadded8a688898e1fb8762b00ad48942f7f32a28e980bced32d729cba5573f0b3db44952c7a192cc56232e830f43ab4acea33b520cafb17ac4da247153c8ccfe86e4a888c956948343f45b52bf19dca8511535c09d5f1e5220fa67c1a9045f1641c6b1a1c317f3cd5fb34545ac6d405da18bd3af36c1d4c565af3efab040945abbd7b7d0af0c72290cab03d2a16367387179fd1198622b87172f3605bcf515ae42560cbc9f670f328ef0a2c52f54309369e226048af96a596c0c3abebde913dbfc0e9f02c2cfc8b7741d036d0f1bd6044bde65c86e477993dbc22203b2dfd37dbca034628e6d8ee9280c8e724b943037fd0495682108a6df4baf5056dd991831edc49719d80185a262f3b5ec04a06864cfb61d07fe3c6e24424fae25ddb6508df9772992df3a507efba4dd14b5c52d59ee2e0a302b9c6e913c4c6a4e183446c6a7a3f3d9ca325f62a86fa9347161ec83bb1cadb148da9b42896e797af176b60a7bb2cbe20cf2ca056250061d6c882c584431f1f6c08a482617bf48ec9656c3442b5671cb5a0211c6675bfe7bead6ecccf20f02cf53e05c5250c4ab96db5a67239e7f8acae55e1a47ad4858151dc07c3b2fbecca62b896d75a69b08cbce99cca1725017b1301342c617c0cba34d195333209951015d0ee682bf14141b60aeda17e6fe2997da65adf7d47e7e3858a51533d4dfc3442d3eca21a5feb752b7eeec9a0c5497ec67fd1b131c5b6f8233ecce4a887982f8ce9c35e32d95d0e565e95f7f4fe41f1aa166907a0b1b3c59a72280d6816c68bccf553600372cad8ea56142f00e9b8fdc70f1688b2491eab0ace10354a284873eed197d6ec7117c7c0fc6b83d60a4056115b96d2312eebaa7805749ee674f26062b55ff71a5198fa46db34a80cf6f59a5b4cd2aef36fbd856c010716f49914cf5689b30337694186787022f7be551110da7211da2a1607ba8be6dac2d86434b9add96715a1d62b45fe90692c8cbdf6f4d1d980061ca2241af7ca82ffad0a6361b11d65b535446f259cc5040804856b2c414d11e81ceaa26702076756bc847fd96bf9e1a96997b2742eea9219cb233be349909cb5a02f3b236c8a184654ad8475630a8ee597efd6e8aa9055b2b2ac97b4afd7ad498f59afd3be16589ed3537c13795c1899330a87f1b9fb5a046b2bf45438771eeeffb0025f232ee6d77723b9d331a56f970a3c8d958ea5444012c7c40387d4d3b6345e74a2d35f5342d919ca3d385b00734c43351202f7359a4ecf5bfc3aa7b068614525eabde95d157481fca6a20457c0fb588e54196b0f44c255f74660c57436155bc89680d859543baa8069a4eb957b901eb811660833a9d70098ffdfe3b118804be3619014cc3ba57dd7353c466ae0f5f686fe1df1fc1957e55fa1fed6e4a435f9a5647d2b4aba1316f161e996d0de1d28370bfb488407bc2cf95938e7fe0a09dbd817682a70cedaab4f03e2e3f09db1e24b707c273979d183ac0566618b867648d5efa233a9ae008fb70895c5984840d96e29160bbad83ec6724d74487e90936087b84a74a4162e04d89d04b0d5f8f0a17fda02d34a232d7aadbd68c811322a6eec025367e4839ee1aea634e4b29630488d069cd798fb5da57b873e887b2ff24056f66fa23529f00a8b989a7b69b26d9a3936977c91f9bc7c9c80141d97f2151c0ae3303e5123cd58043c5245c0e03022407d2b4146ebe0f960236df9846d1f5ab7de14e4aa48c16f8f928e20c533e6ec3a54259b6b9092581dd294f5426ca8bc43201dd722523553dd640740319b4bbe93bfbcb83430cfd3b2cc60ee6383246f4cc1bf5822a78d7310a92a0c1a497e603741f78db44a4a09a470e6ad052900c37e40db10e2d38e2c8069a6eb874e5b301023fd258507041150b17308a94fbe7cdbcab512743fc9c9df32f6472a72c8809511697209ed5f260e8bd56604b7046213f95ca9de0a9e1cb526d62a19231ff4c9e5f0c75a919c1732438c75300af9a1ed1aba3e2051a6e84136192e4cd0d4592a772b978d6352f3d8f9fa57f2c6ffa0809bf9c32452b3db5e4aec00933037aff654a4640e9d8600845006d3d928c9d530cd6752e26adecc47b0b056cf0a2bb233c3eaccafd32be1d23984003c9960e946329cd13e9d9c6376401b6ea96bc4328f7126fb090827c7ca73a92049822d6968a648336bb2d2e5a928304b1f3459cd3c11ea5d24fcc3b9acef1b5fdc57d84566d56cf8048aacbb32be748ee9b9136ef6a00b4d286fef92a2d3e408fcacdfe094321645fbf50fe48e3b720cffcfb3a17ad22c305ac078e2675038018d3fb0421226502a0e2808885bd044c2b78e9d03a946537302ab009b90df4a3c86d48b5f2644b7b563b5a1006d18131949e46c5bc590370e09802b0c36940ccdd74ca7e28eabb19b749e61d03eb62ceb7c242be6711dd18ffbf6f4852c0a7aa2c599208785078acb4d3c7e23403ce3494de7f0a0088d37954508d3993c79be9e138c9311f4ef0d79b67024ac3c6f1751e7ab21f5347b2f53d1c082b24d5958a775ea6a4c3d5a5650bf9ee0e2dfde83defe78244f4301e24f13b6722b8c5ed97f556c100b241f9c94b8b338b94407cd9e877024ac16156723243cc298704e73dfbf82d7d72283197c009b448a2f318a5b5fc75bfd5cbc5de516c039c2f2dddb06a1260eb9832456e8de7d3c0cc51da176acdee7bc4c227173690927a76c2b13ca9afdd7bc79a155d587f23ac0fe9cfb332a3ac9ee3ae7161fb558903b45921c1eaad34fe80fbda1b7680ccc064ac97e5a46046939d578e765edebe80d7a5ff8c3851d8d325a681c93e99e2ecba94c20670fb023eebfd1b591288da909e029353df1dc663eb27b32068378ad8a39f38155b0c293c5417024c46b0ec74e27746d87b431db03d4630c7d2ce6cd7b8441f7397b734c1e70c8d21c29b28d0db00b64005580310bd1b2212f4fec35fc53ca31b535efdbaa33b36b6854dd1f6db38867017de13ab688ae174db07fdc4840754e89a3a8f7f24a81807ed24869f9dd9193c03463ea3107186cd1620686fe6ce90615ec7185577fb40fc4320603a917eee798633d324e21c4cc4a8860b1d045c3e7c27067789086c6efef9d554623b40272cac7dbcd29985d52618f4189a0600c4661b15271b6d58e4de831417d7e537197f645cd81a069e81ef809fd76a304f034fbb966108ca1d24a7784f3b7b8591fe58f5c7ec86272567a8e786507f3aa67e272eb7f8d1b063354c88f0079e010db85f0b6153afd5756f2b18016eebb4852f35f9e7162ac2372862e203fc37e89b71115f1140b7a198819e6b0865400d61c4b142754f7000d5e01c95d69d1364c09a28ece3965fc389cdd2b53f0387f0fdcae6fb5eeefd9e5cc9d0482e08b06520a3cc4c60fb32f214389599e901107bcf9a47f99180e5074f009ab16d14bc311018ca03b0ccecd4f60804fffa2b9ed59297ad24278a7ada31e0ffced5b86033ea49029b8214cc14ece47072f42b1214d99076351be3fcecb10ed13368c7ca88bb6e93505c4616a38c5af7d10552e6785cf060925f0e7797aef8170f021fff4f2cc550760b71f63efb2679e6f783ff3e406bf147d6413ba260edb661c01ae6f35bc8dc45ec7f030959610ed1cc62c8874ca4fcba8b57867067509cdf167b34ef5da8523515a6c635bbfbc1b5ec1ea1d2ba241d00d5feae71bc9a4f160f1f7390d99e255d402c197d5b9d6afdfc0f546eab8768a3fe78ad66b4ab2616bb9658679aff8311d1dd7868043e2655a749e38c72d01faa29f571d1003350209caf303da7f3b19dd3d39c06ef60910fcba537180d79e6571ab0b47f16b92bcf077cf07c56a16e0d80b3f26794ad01c0a1d19927cb078fb25e5296fb909d118c933f819d743e6078727619fe5e727183fb5f14ae1f85a33fb968b96a3d7c72e063ca0e686b7ad37215049bee88fa305069740ce0fc68be65fd3e42d042ef37b79cf3fb1f81fff0ee3c7844b4341d684effd5a8fc89a026b783f092645a9e5373317ccaff2c64a67fe3497bf80b5bbd6bb1ca62eff8a19d9311d1895095cee5bd113798e497fa8f6e477eecad06e52913d8b75c921cab02fd6c263f0e42efa46bb951d47300bde06d6cd6a686748b7de24c123bfe45be025543a150e6d2fbc7c7dd3c17668c0347769f48d703f972c712af4d1324e0c8e30f4651b0567ab4fc2b3ff0ab974bb0d571b259bc226c49052c74ecbbe4b5fb37afe4b703cb5948312a79b3d8daa1d8978f4ecd0c8c2b7a74e0302db2314838cb4a0b33261c5c302c99a21c7409c6e95632e548d1f324c02b8bb0aaa6d22d9ebd3c9a5fb1e50e17a291693a4cba87379f953ff5b3c441a68629ea512576e4fa52d30d3bc1676c7da150059b4d47529848403b4cc6af5a96a90ed8ff66d88bcd41f2f32c475585391a3d90cdff0ada764694a931ef6c4a47e6a0646bcb1d9118a9c6c6714c92bf63dbc6cc6de93c257c032c614513931434b1249cee3a0114aff46c1651ba4b5017486cf10eccb579b871799bdef68869a86f3fdd04cdfed6a5f4f7c54db3a11d09ea37927a1daedac52fde9519bbd8b84fbd5af71dbe04f2e7bce25eada84130c3d1411fe3bf6f1287af50b596778dce4ded2ad4afb53803c2c5dcb3b3268bc0268293b70857fd3050d60436352381f4955af88c44413de9f00e3c6d26410218f755a255aa97727efb617d7b264e26e8599eb1a31caafca6020f067f251ee748e2fcb5f3cf18513da11a241a81cea6ffc47c594ea2dba2667c3c441f9bf113781b6f40c2930da29ef3b0ac9951809b81dbd26b0b50a0c38d0263b5e6cf7e9c8e43e994f743978b0ca0ebebb804bb8a3df37e98fae70ab2e93bcfb5fa7985328f6497011c828016254bb7189e262312c746f0bd62bdc6ec33551a40a4c245b8fed9a247abb8a4a9070642f6ae48eb2c7dcbd334828d35c86029c11637cca5cd53fb6c3a2807b2fd341860029491907d89cf804abbdb187fdc18fb9bd1ce5f67a73bc365ec6e1d7d4bd819a20d55df4f5995448ba4feef4317afced441dfbd3b45c1378b81f3cc0790fcbcc36fccfeb0df0b332badf633273d28e16623f53ded6c5bc4110e826492e240a7f4db66e8344f82815ccda13f30337f57e167122f32f371abdce9c07133435c703f79c133578024fa80ae6900b66438fca89b1779e8d635eed178b4b1772b558265b1531992da5fa16302cfa07b46a21c6ddf656605e31aa219fc4f9e9d77cad815136f6847d84e2d95f2adab6ae059c00811d5d5e1b739283178129e849d6bac04bf8a61a2c6b339c612be1b12ee987b236e4962e8b3c81473a88e9aaae51f709d6a6e5506d9b41343bbc2583639dfb153268ac2666a75d82e50fb3164638cac33a8841ec05a796424f1edddb20dcfb353e72ce23acbf16d4dc5a4f8c54e13d802cb180bca18c9183ccd1720e6b01a1e2e849bed92e69ca3149295d76e4bc3536134082fdbba727c2763af50b1b84077edeefacf984acad2d8df31dd9800c984295c544864ae74767791b4fdd4f4a16727f6458dbffd4e4bbfe51d222cd88a4035c076f9b4c4e34138b45e3e1c9b2940892cf30e599ac57228bc16d768782002ec118d0861824fb10260ea2fc5051c4c2785323448344903d2aca7b598acbdfa2a10dab8319659a0d4611ca8c482a29646b5c33feda57aa5112aa506831ec5ec410e7f69195548eaf87060c4b731aa48d633e0bad71a2b47bcf138b4663aba863aeb2f4e7d65ca36727b1b82c36566539338e1299bfce6ab018ecd724d6f00053fa2125560ca30ee1fe50e436c9de57dfae887d08d5115de756a9c514e86d2c74123f4805cbf054224cad1a28ab12a3d57b1bc9c9523421801153090a350508b5285a9462c6efe8451619e9dc01684310da8c0ee55109050c54804f037c1294843d65bc2d65d5c63591f291b315369fbd9e82422b5acc7724cf64454293012d6437d0aa4bbad1a6094ba04ac6041d904bc397778a9c5b6fccd94f1da80cf69365ecd85d881e4c8b0a2360321f74f0e2b3fccbc011c79fb28c32a988d586cfb1d73b897c113f2413e36cacbc1fe25263b7683929ba1b03d052336f12472e8bca0d4e1573806dddd4db8f5555dac6caca40297088b4612ba90e0ff0252b08428f38db33b7d75d51599de8ba087195b39906ef0b22b321ffac66172c5e91b5399023a9f88a34057b672440a098a6be91337f5e676c985922d926eaf58b9f01d4e986b52b8acba3ef4279a9be9242d1d6cbf337cf2aa30c721c0905de9c02e19056a16512ce0b3d3d579d404af11526a36eabd7a083d166b1fc626a53de85e56d4b10ba9045ba20bc7b29c6b06815368570b727b31d32ec1c4d0e743446797b32f30a8d501b5561b897775e64c453b1b7b42ff564380cd422f141800887b0698b0bb0026660f600159f92ed1a238f52dbc42b37e99ddab981390ec6faaaf167a99bbd37d87930064ab87e710138458ac01510964f8624c9dae77bb283744a3da846a876514ea7c0bf3137248ec744a6aafb6522db90222489b7eda90c0b9d6093033153e73dec541e6a2e50644627467bb6258f9a6ea6626cf81f4f7b19424694e5d9fbc31c02885502dbf233a7a93d7fc53865ccb11169bce715529f6aa0eacc0d4605713cfe8d08598c3e8a81d0fdb8a01c1c99d78e615bfa1a22834a6c6e817020998c0aebcb2c3483fd39221ee7dadab2d5952e93833b870fc7225e45284c770f888d0a963d91c2d4d15d7d39391f27098e46be68747d1d33aa417805f9d95b7d899d02140b94c81172fc3d79ae1dea3e03bac4c4571c0b72d1a420bda479613deacfa7dbf6b4843c1d5116496126c1813208356937d60e12d719bfe5648a0f7f72f07408394a1f75389b2d7fe0aa904f5c7c0fed77a28c6ade1bb1499048a8f02e223bc5fa9b2be0291496a7835e1b7b8b9a3a7759f7507557196709c2f2d51f9ec88b4482afa64195800857c909c6d006d2d7c4ab64533f26a3f27914817209420e80ebe8f09a20e27e16cd1f019ce78501b2c9c731fe9c860097b491a583032e8646925b8bc9b645369a25a093e12b3083c880a96d5c5258eb05a4608f0399be9ece916011a1a400ad420f8236fa543c26433ea938c19c4531e05252f99e440010c5d10b53cbdc2ed814ae7c251aac8f8239a9518d9b24ae7d75d16271c5a48d271040a7ac5e7be4d5c2ad130d5ecb8e710beefefb91bf2527366058e12f4fb514f8bd8f5a1c44a0857f3adc86e2f34eb29d081b1848e7ea62c513ccf8a5c0258cb20b4a6601dfcee6bfa88e493e836f35642d1e4b2d3e032c919fe0ba22021de0b089dd55b051ca9b90caf1eeeba700e345823e92c1169d97d9c75eaeee55d1e7e2d0769b9fe2f34fddcd448dc563e54552601d65cf8291accbf117ece2ad906573a52dc020f004b8daba9a62de2c21eab9d5262871529b86393de595f782ae216a330f78101c93d95514587d369c037bccfe2fcef3303c24d001f7d81ea76c68d6c28c7094e1002f82bd0a1757b979717c6306b3de3d3fc4588b1023fe8721fa3015aacb7bb83ac3ec75c53a9f55fee53ea84d50c70281f0ffd0f9592afd41f65057293100be03c9fd7fa0b28f613d52a0f98bbd6ce6c5eee477e680d037bf315e37622846c4b5173c120f7a65d23b95654f8ceb59722c8090cc2e7a7b3a1f1265f4b0027e94d925a2109970e59eabc4e54d7c86a9a998e9cc08ca121df19a94460b6045424b7583793589bab38adaecb81e42360cef437980e685b549dbd967aa89710de5b99a5469405d56a3eb7a99d0c882e7e47420b60b4a794487be2d04bf9cb986eef644e8ca0d8ed139f713075409c1a1ba08aa4ea2532ffa6c266cfa4b52f5ec45e67cb07be70d0003b49795f15bd9c708bbfbc7f4621c3475d2bb0a9c35affde49bc72b00abf023d0f64dd29a4651bfe68832a4215cc0a61a7aaef7b843ff570ff14a32fb72c9a1e6a822a89cdc098b4011a9577063269cee391c702ef67e880c312e831368a1c6e0229fb9f34d7323c1c940fb40483b852d86b5549fada64d48a91fd0b688bf437166881729154de2289931359520b4c0f7421f0e15737043c4b3712bfef60a2e83ef9772706b1ee0fe4ddba895636c195e174140b450572bde16cc4ef5322cce7c6b00c7be23f307bf424a743f7deb5d3d1e5f2b6def323a48d05eb21f411f43b45593ba4d5ee43df59299e913067ce909f62e1ff62be49d15cc8ec17c649daa50b97e2d9cd53612ace05abeab7ab8613e145cf54b01b06bd837f98193f139f1a9a80733c66c2d52297baee344040375c67f077d69978d541103565c6d0b8fa7d9fb18926d95451836478229640802386c824a9ea12ee44736a36678064614a30790964ae04718faa31a16e88e1e88ed07a58be39ba3ae2000f43008aa76d98afd564b6774e84968fdd8ebc0dcd7e7004c2ef31ee93d65871a94924db3b4c7057cee6e52b5f0e01e6615d8affa5179eb6edc994c2e05c3fc010b3a4b19ca1054d0c000389520f5ad4ebd82bb3ef34081bd7622d00fb43a481a0c08e3ee872e38b3abee215892df41023b9a36be9cf13e25e5d266c3ab183b79b345a52d8f15ab3f045ec71ae385a47bf5492907c89e349ec8b430e4a3a73a8afc4b56a4279213a3de40d080804c104c27f1057745bbfdb0a884f6efab326f032e4a1e210f8dc012c1b0d31e3ee54517431a24d76c5347e7d5140da543314c3ca2000e2f1a1c87a1455d8d96f4a7b98fd801833261197af23f50520263c11dcd5169943c906bd7254acfebc75b6f98973fe8c6894cc90dbe9689b6291c625eeec48523e910920492ab4470f61335475e59dc6ccc2bbbdf16a00092961bf488900694b8c10e19229fe60aaed92aa73a6ff5c94516490279a2f4851bf5e89e7cdb5df5e21e0f8c64b4840ed2c595307c2a7ae4b1470ae404f7736d932d2eac00a5044966ff499d8ded8699163fc90542f3ed048017d2d86956a6fbb51609b0771d4a5456282dcf63681729f0c3bb25ea5012f185b9f2074bc19fb10f4ed7be0873443d3f94a62f0ac3e2b5128970ab5cabf9971dda7d50aac41bb37532c629286ec7b496e59bea8109ec89384df70caafa5492468aa0895795e3ba226688000d35d957627d5ee0ed103a19aec243f17b52e40a08a0b4a1edabb55a555fbfa050c36dd8b1bbd89e086529869f1030e2b1ff5a8f719e3948d2dc2c36ea99b56c22c645bda35d921ee398f44131edd4c50c0217ece13935016cd67aca4cf72caafd059f8eb68ee517296bf8dbda08d7c9328e643681d8ed3590d28b18758ee76e04d35aec4cd65769fb84ff510f13ca44ad36546e8713c31b9705f115954b8c7e00914e28ef411f05d91d980afbb32b6df9e043f19ca00b4e71104dd2092f9649f3e2aaf08dfa1e347742afe613638b5e5c74bd18b1e2d91e06e9f50bb7da5657b8032661838e31f348d40ac15fcb4c80fc6074104acaaf511fd0c27da4534dd116002870dd98ba42e35073462b95efcfb378be7a9d9b09d6ba524897a7bc6b2d2f98e8f042649e7dee4ce9e57e116a86c18e0a318317c1c554e1f6607154038cab48517b0d4881b1b0da9f37d66b69a7309ba5c35782bded400af1805aa2a54045cc396e32ca6ba5af19c58215eb7fc7fe42fc72afd9e08153dab07002abf80998feb32413ff910692469551ddca9fa0932fc664ad6ebd29b702570ece51efcf6e11c2a746272e6600f2fa85d26a4afde38db90bba29bc33573056b5daa3f7644e8af305bdbacab73da49c774fa65bbfa930f0689cfa02149cce3dd61d4bd9708f85cb7ff0304afe93a41f8989a556f938155cc0a57eb5148eb004e178d500d495a05e42bb4aab714f6558c4c1f1f82642b410a1c2448f1934e715b50c2e2e57f7e08f8e87a28450028cf1c4e6775bc270a695db9f839521204dd3e7ae815a1e943381c17c957101c4c174bfce55446e2b78c268d2a6e09cd02a641378e489db6a1b8f41777a86cdcc9216f7768f7b3565392bf93fa7340196978eb978a1f3bca4b0338a4f9915113d9fa2bd525099340ac02057fdc4fc00e62c8e41db9597baf4e0a780a4ed7d2f8e995720b3f5d0f573dc45d2752c4efbb7e6d46862c2d52f133ca8d1d49fd1df85102e036a6d1a57adf40fbaaf3944ce2406679451ed402939dfdbce8eec03db1f2d71112e27dddf100807549ec04b6d711f6c8f51e6d01a6ea0c7d43f2ff14aa56b1cb1fd09239c055fbf897573d252d4a23b407bd41dffc5f9c58be3d8d2116b5ed826c209c596734cb5c56fa3490fc5449c38edabb87f56014800f8aa250eb6436bfa5f7def10813bda0e5675d729404c72572b09640cb6aca4a3d2dd6345177f3067bf971d35af725a9d20d7acb7372d0db1e07417a4506dd425bbb903bbb50f38b8a8fe4ce29b9e105cdc3484f090fd0a2b193150cb713fa534fbb809fd667897a9cd67b7e9ae64bd84956faf6b6ead09f37bd3e1612a35c21f49c5f2141ec479a7f4b60a80a90df5288f628339ece80fa577a007b180362fb4295f418fedf3f3260c5a55ec1726dc66dec961abbb86c44ecb478f19763b316c23669db2dea5d7d9a9f50a5ffaef8ad96376a633c689194680568d29dcf7c9ac627935a107617282f940ceea89b6ec4166a1454d64ef6601ff011716a42b9ced359178976b77d1a6feefe8455ea62a7e5d846d9c8a0053c7787a6a3ac8553383fcd3413af2a83b5bf4dca287f1f3e14db9803580fd0710c95560abc3a03d1158aebec3ce678b4edcc49aee94cf293a088562fbf2b6b21a727d2633d4f434d1b4430b8410dd4acb1ddeb80006ae6c5576cab65702143c4d34690350bea4c503433a774eb5eeb5f73fb9cab93845dfaf3ccd1039be89bbbe1827e69e6609ac68d596155de634b7bb3da5346e04baedaf1e3237d614c5fd7781e58dcf70f95fcc39c084f5a1ce599046fcd6d3ee84cf076054ddaf562eb7e111f824214b365f46013eabf3fad7f2df3b2757ed57bef2358b1fb3f446d904c2af059fba709665e50564e24ee219e46662ee227e0729bd8dcd478a10ff15d0725de5d0a2da23b52ea3dad919ec3e3b701ecff7a477150143187162fea8697018cbc53bb9d248e3e5523cafa335ad743379bd0316469b17fe8810ed228c228e79844e75b748274681d9bf2a30e43948c6262d12d1fe802e9d16223ad5b1d2fce7fd44a9fef10addb78b1218ee33ba80bba67b568cd4732470f9b9cc409eb67ff8a59b616a843cc556c5f7ae038e3aca221cb75024aac481c534f3205fe665919b8fd97da4dccae37f67404f3f7bc220849e3922f08b8a512495c76e0f64f136a3201571c2914f15069bf87f23ad8c14a983e97a11494ad982a7dc5bce161e02a3c50d9f9e60bbab2e42f30c4a79cbc63aa0d008ede05f84ba9ff257110d0fd1796160758fe9632703a113e8f75f7fd58f21c0fb1b94d20f341d9729983933d33fc74a3f3acd86ecb3a279ad21cc540c680d919973aaea522f7d27536e6cbc14cc1dddbcf8c2e606e7d76d875004b6068b2cb5334493d5e4112d76118b2144801396a25792c0b32de5784d4e1d58ed898651841a359bb189482c772a16e115b2fdcd688805757cb1b11ed3a9e7da98853f0454c2cf4f8ca583d356fd8ca240051e4ba115d6dd4f9ecc35f7c63e8740c586e54b7b7019d6866bf8402cf84b0bfa8ef934f9e71317f3927cfa6b8dfc960f0c1e64f22568f4c909110d8835b122be92153eaf4ce01628434956446054c31d7faa86855e578960a185de37b4b91668be4cd82b73557f9e83e22b8562a5674219a3811fb569f6125701f07027fe62c3ac1e93f905501eb867056443a46c83298bef0e868bc56f3201a356017bb109bc5ebeb73a0b288557c1cc89883d55e015bda153622e265f0e28d62ba7fd267ce26abe86daa46981f1057d4c970f76eb4a27190257f333a5e3e77b62080c2e3844a81352e089faa7841cdc234eaeba20cf2a139d1d537b5cfd4f1e7fb415437ff259930c3ef8c754415ac150ad048627dbb1a8335096f6451ea9eeaca74b853e8a17ae3a2572a78b2158377f1418a1b6dee3573c46a98df12ce719b8b852168e0dd829bc147c807bac736a302ed60f46ddfb0c8dd891cfd2d9f81e39a2ba7d6048e3d35ca6e820be106be42f6181965a7a482092f42e8d00591e482254ccea7107ca442c1c254badfb39210376c8ee223187f0a06af7e8a1e2c25c8d2c99fd03afe441ee6cdd7118796a19d0849242f27825e34c81c1b1ec642fa29d8cc687884cb16e459c963d36a3b6c34126198d00906942d1f171771bc226764d0c291063e5927eea180b1e4a52c0bb91cc482355e9d7588d035e5059fd720b202019d12a1c0e76fbfc3f6f566aaaa402844fb0043f7051275ffb3b610a1b2f6b850eb7de0f3052a501cb4623af8bfc48d7210450794655495056e7f964c1d2e5fa746ba04c0196ef03761a14e2a5f69dcd450c5e981424589404c7d76e802b66c2bb6a90e5530aa2c1c834a4ce33e0b7339224d150e130a0f2e16d40e5ca5ad857b6f23c31da77950475a5c6263aeaa5a6442ded4c28b3d861b4416be458e32e22110fea2f66c62ec21040226540c14052d58267770482eecf4e93024a402adc0a82072f2ba7533135473583fbd2c8360b79202bb36a7ef836a529a7f4061eca4f73ed603da7868564ee1441bfa5e2355433b6db1ec81ebba53884da63918a973a3fe469c2e0cea38b2dea32e5f85a49a04c0a5ed79cea49d366abccfebc4e65b9e86461c50529815e1be49ce3941126002824700a061a3e4229c0c0acb62768c1d4ef74f51a3bb23999019267c2ac33b991db4395329b4400f87bbcb0f5e35d1c95a0a68bc03cdbe16cb3d789347d83b4f32fcdeaf0eda432c522f7420e53d0b592bd4901a8ae6fde033cc093f25cb8fa4b48b334a70a8fed0b26641708b19da179ecb6cbde197d7838a104219c28039b66a7fc987949c1d940faafadbab954bd2ff57526f79b1a594a1d2286e7d2a915a0bcd1a8cc22ff3903a10bacdec4c568920efe17272bf672109cc4c5557f0f815a0ab7beb8d4909bedd12adcb0fde5ac299e6e713bcab9ccd1e21428df8de0633a61d1d9d97713acf07bb530b999633450b6bafdf16862cef5e636fa02ea326e0c63a793d155f69613545030e1acc85a380e4b2ef2d2bedc4671622ec40a3dd8cfe8a832d0c7f6be95ed15e867386f7554fe454d9ec8b6aa5b4f810cd72fae0c2b38904b91976fe335c88f79db46899057c479350864f869116e5eb3b715fa32b9f2385c23310f4725018314817ad99a075973b44a836d346342931e577deff7e1e8fc04165a4d3396064728cff9abb8fc91206d70d88209df3ee9fd74c65b5105df0611af067630181913c2c0f7d53892f9569f0494233eb7cc3b60555f27249d0a71d260970e2270fc46870647a7f3c9272502935433541a507ecb4ad091123c20a6826ea733695a3350564ff438791b401e7e5e878d31c865f032357632aa7a22eb5ecdeae41b351edabf0effcc546e176b63d734895037ab6208f01c253d19bfa79db7efd775e150df5b0ecd300a9bbb9d3f6d9337e08ad142368f5125cc79abf5a9c2a60ef52b62889e47d9dbe2a167ea7b964b7e2a38e0062cf3f4618cb847cce32c641c20ea9b26ba616e9df47ceba2f631e7dbd81f715d76c1ec3cf72c4e23b9c8c566994724b43ba155214c617262c6a7eaf0ff5c570f070c56c7ae7cba5426288a4ac1791108d2a713a2168d1611e049673da9e29009510671e01b8ea929f1c005071e34b4d2dd8c3133bdf129b7fff19b8e7e61963f0adda7f2f2af3c59929573314433425948b917a0a19351898afccca67216a5ef7e61ab9207d93265a0a2fe8f4cd1992b84fdff01e800f516c4db607d8eb5ff1afbd9d70812e6b3f9a5a371dfb7fd22aaa5a9f479cd7a8be6e7548d412ffee59620581e399ef5b1e5bcef804121d848176037220a89309ebe9aaebeebe553181e915e53e85b98314b8d10bbb2e59a75219949bced1a5bc35d08c969d1e24814e9a3b167dd1e9bc0d14d35d74a15ca9882f330908d405aa92f7f2a1da63d910df66797d0dbd453bc53d36e3763a033da54d65ba0635415b1b70434cb274f8745107ca363b0f6140a4582a5b03db02a72ba4cb5e9aaa515e861ff8aff2d97c634b08aacfb67ff40c1825dc6878105097cb399f57af40cb14ba3aa4976308f61080bf1e91d7bb5c28aaae4349fb908be57df8c4108c841e17978c9adab3910c9e6c6018e05574d9e9ee021453046eb704440e471098459336c0c040a3d6434f5818f0c9b22cf6d53a913c6e81502324a391d6da505bc995dddb293e0c03a8fac0b24088227a58fcb2bbbb7bb34999229d5dc75466e1c2ccd0b71dc910320e010d5884c136586cb6c142036c8345136c83c500d8c6481ed8c6c811d8c6880bac0b12eaa5fa1efaf6f07155538fdbe3f3b93e3a16151347b2eee3fbe158d77355d3944397139a7238f91d72b9d5dfcac618638c114208218410c2f7de7befbdf79c73ce39e79c73777777776faeb9e69a6baeb9e69a6baeb95a6badb5d65a29a594524a299d73ce39e79c534a29a59452ca18638c31c6182184104208217cefbdf7de7bcf39e79c73ce39777777f7d65a6badb5d6bcd65a6badb5564a29a594524ae79c73ce39e794524a29a59432c618638c3146082184104208df7befbdf7de73ce39e79c73cedddddddd9b573a6584cff9e75e154504e4c2814d902a1863b7fa29a400836da46001db485102952d3cf0b98fa4329227b601c2836d8038db0069826d8030806d8030c1364052d8c63a826dac20d8c6b6c136360d4c1440bffe50424249aeb7ac96cff798f9848a50477c58c654967cae0a0754b460d6912c86a86c80cddc21d40b632a4a9230c6546018639a238c31c65490a81cf90a89bd9e277fc47ab93d2c6ba238d70887268efe497f74f533f7c3f9dccf1d71a18205632a46185329d20203c6545e185321c298ca10b669d15730a6b20117b6855de282a4f3c3fe28e2e3c5763a7648921f458874b46821f2a164ae88aa44439af090b930469e090543848e7880fe7291a13e3ce8c8e543934cc85a231f19d8428587158ca954c154a8d05fdd1117560734facf45c203e6b2bec7be3f64664fd52bb92610e8c8f5413cd6c888a8489eaabf3f246499155030c67244a161ac314d11aaa00cabe8c0000bddd0049aaa6c4dbaa2420f0c0d1b2a3cd5774c3b00f0b932c8ba4e3894907bdd1f9d0f45e199cb84e251c5bdae664c452565c3c281239625b22aaaaaec0fc6545054348c59f7ba3f9a7bda454f9412c6d8ae9ab0b0ec4a49915d2981728bf7207d81723497c0188b7e6946e75a3a3f8f1c3ce848bbccecff1ef1b20e90234a74a805df1e9ad1e301034d9793c9f668e9e14a801c5162312633f1c8f1388a09cad1457d2ceba23e560e28471c1d508ea2c8408e28f9184172592f6364574a3abb6ae24c30d64a20ba22abc8660a20303661eabce3de48fa888ea8f31194d3144e50e7234d1d26a60141a5b1da10411b44c0010b58932b363b446c2433e12001b062a3e30bc63e1fe949aa378208f684554956a77ad146878e4b87033050040cc48051e74996f0c1468a2b30c6c282012818b32aa9a3ffc9b43b22ab8531d623c92687c57eb4845a36505c6103850f52eac006fb5495cdd4e7d3d2b035e4028320c2e6021b60cc021563296bcc8185f1441a9e5882554b364f0cb9a229662e3acce108c7735d11e7f3696161d9acd880a54c2234a1e2848d05d6d858c0033ed838c1c4a60913308e1c988c4ec886330536842ef0c0494105f470814d05f4c018eb3c691bcec418732eb51d3b44a024325fc9c8b430f6b9991a62c9542db7ba463e04d34704aa3c1b09786023810c5c95d67f512ffabe1027ffa2ef0bd944c0061148d940a00e10c80193fea29a58d789c7ba423610d862038125623cd6f564204a8c70eeadae68f3802d30eb4ec1360ff8820a6d1e20a4e5014b30e600351863317a32325d119a98747868cbc5059424730192b13a1f8ac2d9bd51037a6c18b0b26100130c6082310e0b753eb2ee16515efb223972ed6b858049e6c0cb912020a03c2068b99e8c5ec92f997302a264c9a40513101c79302130b201219eedb94498582d727c4097479a429258861c491205479a7991fbe1162ded0f0f8c0d223292248b249e3c2da9921c993e8913bd64511f1209c30507b4f00cc2c2d32204c9f595cce5cc60171c2ed828a00d1b051861a38032360ad0c1460134b03e32161e15e8e40005f2115c684305e070f590851a2031c6133a0e20da30d156b08735d070c3049c4530f98c7a5c4f2cc8ba593c93fcb94cf2bd9010614aae1089ae48743b2c2c1b04186283802e3608d8ec0afd14fa2115b5955c0172b91e897e1d9aaef80a486cb23140caa6004e5827f49f4e27ff13bb9b18d1a1e90a1194238f75857c280a8778f0e0e8e0a15d3a3cb48bfe7fabc383078f1c5154915f890e4d5720d1a1e90a3df1d02e2e3cdc1bf1d0555833cf44bb34094d577c0e4d4cacbf46226b09679676716fa45d84f8606109000c020001211eeb0ad900004401c61eb1516983f9610e8cb10fb08d4acc2645114c0cfa372967489b942752689a9ca454b1b9b1871c53141caca9cd8d2aa46a73e3011b94456c50d0d81b941730c6a0601b14cdc2a9a8bde32b9109d846a386a68c8d66c846b384b4615bd8b02f366cc8f5d5862d61058723e94aa481b3e32b512568c0e940255c2ad17870382c1c8e136c80a31208a844007050c2101c1d1c4a8c8112656440070e4a0891383a28a1b22761c5240cc0a25feb07a2bfa22e2492208331c6246125eb39a129128ba8de88e79291627244c1c20213c3a1ae98188e355d333baa37627dc5c212d3014e2887b55d38f7c925e2e4439dcb1a813a9c113533a2667458574f5493cba12e6ce409cc11e999782e4b743f1f39978ec8b1a6fba21e121227aabfaec74e70ac0b9a389bfac19162622e1ff737be2e14505c4e45714253b56387384f282730216a141303c3912c8e745d0e68531cd07baec9c9358db8906242534c4c14319c4de968e1485fbdc7c5125d22d657a3eb5a9c99ebb95a118e745d77e25071672a10b5454c4c07383f71b68889e9803551d7a642238a338339928e8ad271598f6338a2d1570fb2a890cc9db40e5d3b5e8f36c7cae256562644554e72114f1e11a128986be4f3190161727fe6535dab8701086293872f04a20d10e7af90953a81786be2688e0efd15132615e58449a63e80900403c41638a1175180a00120520088108b8ed88485c53561619944f76238fe50848ada327f600063d80f9a31b663478a1218630ed071b9689747a2848585593e34a2734dd88a2a461c0b33e18310c6d80464f670c6198c85ae08498b1ef4c0f250823c8c40094aaec0831d581346eea01f0625741540819444c884a626526ac0580a194b04a048455595a6184ba1016329638871461b0eb8540ebd937fe9811dd6084d1f2555b0c30d18b38311096bd4e081963a9c810896883ae8b02ae9006c5c818d19e06023056ca0808d1184a84906efe05c0e0218634eb0b159630dc6ac08fd87a343c602ade1e8b004c71a1c3a54820e85608c55c170d0c1094a8430c131872bb0221eeb0a718284f3fa72724894c5a17444c1917e46749d20a17cdcea1af9f1a1282332a149eb1fd7a8889eee1bcc8079a2556aaa6ee8b3c541c2919ca53967535e514e387f8d3e5468ba9e4ef31135c3d1d19cba704c8c355953458940530c27445d3b2c3d41019aee47445dd3547deec4b1aec96af97c6ef54d2c1e599787a3e3529bf3202adfcfd7b29a4c204a474c0c87874c753d1f8acad6a427275768c4f9cfc789075d99d0c4c47242748da8eb5217f542bdc08046a049ff8fd00f79728958dfe40ab9a817eba91f17f512ba3e422f2a5215a99e499eaeb8a8978a62624d47a81e33a1960f4519a1607a9061c3382c478a1c3962394d34d1841a6750e3098c75aa8e0e0ecb145647871a6170acb0c20a35b4608ca9b1a2c603c6a008c661094dd66505631a2eae18c31bc30e58889a44f73d1c960fc184c4258d277058d270018e344690061769146139240e4b13fa7b74ae497f07949f88010c31a4400c23e0b0e48e07b868012363084dc882198c3110c311861446857376581d2a1c10bc08a30a621802181cc0d88d00b047300d002ef0852730c6a41c390a0ec659e04217345c9064469803f25c5345c97c2e27e643931dd2a345888f167be425c9243495a82852682a1113e4c63014260ce58322330386f2416182a30b65c8c85cfc47ba702f6b1ad2851d5c58438af9cb9a86c470ae9b0547d2ffa14454e6709e63018e94afe7e870a7a339a7a2384d4f9cd0168fa3c3717478076238143ac99fb4e61c87baa66f42e1cbd1315072642ebe46a2cf272647141d6b9258582c99db6307c79a2c998b774c617da66b34458ce813c32486f3f9e4700e069e5c9094a32305678b28385658c1d9c23918e030e9408c8e3c55d783a897e15c1fa27c702cc091663e94934b874539b980e0ab450b11169618cea674e8529548e6e2175d1c3d71583a3b26d05b1d8e357174e8175594058596b9b8ba7ae2845a7435d22e97c5b13ed3bdae3caa6e0f998b6574e8be682ac4b146435e2a690a504c01005370aecb094d9d101582f91ca242a2ebc4ea40a10bd6381715b22ac99bb0b0e07802179e608624499c8adafa9f10191b85260a0454f54bd068038d32a05106c6382c3268683102612178c1189b49c2188b3896d08614ab620ce5105cecd8a1843d304b66b280848a582f738d58b7b221171f936882d9457611075c8031266238ccf0006348ac99af2820d40eb984ae0889e5b1ae90904511b13efabea7850a62fdcf5c23d68bae132414102b025542fe81fcb0ac9f2a0a0835f9b0f61f115d22967575e8655aac9f7611eb87b58bec22d58b46482a0a0845f5b0be326259fabe90d05796e812691922737b5cd63444263415b1f008494b450171f22f445001bba6d0280707031c782b6a534ea821d4934b24e43255949307425130d48b35a23e4455951d61e1841af2d7fd4151413e89f5e4120951d305841886861f74c198e882585858587eb088bfeea7a22e0d193f20007b1085446602c1571c2a1a87c7680394e1304302f7351bcc074db0911e7158867c88fa61b5507a8444cffc157ad23d6803470fce601c4a8f9058b743e911a547560f9c31c612c0832f30c672fc68e69944c152f6c018cbc170f0e0048c735d263cd082071a608cc3c2b9eecc3349d93b00c30e0250064c13280778f2c4856287282020892206808223780660884230c10227d2c0002cd08032c6aaf0c318386954a0063d9680e2107e5802021798431a9813444460103908928302e420004224216a8c31160197323c8cb18d093230882b30c6363b88c4166630c6981ca3038e605625791316961c7cc19837e15017a722e28223070588030e1ca4c1188e1b48425397435dfa521fe962c65216c058ca2605a4df9a58585e67c652703096a2000368c0067b48b991925f090e1be8c051832dd4600835f8823186e270d4c0016400828c32ac4a0a51d385830665b40089792492f52e2e42c6d8c1185d30360587e5832f68d484c22d631861d635e18e154d74588224e931461d638531c6b1a2898bc57004631c1631d610430e38c40802632c07a70a4e144d70582eeb7e4238c400430ccd3856f0e070582c3134c0981812601c16315066408819881863d60e6b87feb776a07421045d608c594da84ab27e5f4e35ca997aeb3f31f995c4bccc05fd35b570249910f5b1a6916585a8c91aed50889a3820eb73ff7a99184e4c8e28a2b8de8ab15a3892f5219840d325aa804cd515baa04742ed90cb03e93c109de48712e933dd2bf41ccbd211bab7a23c16870a711ebb48319c7f8bc332f3a9be09c599b9a0109599640af415952fcbba9f10d5e4f6b0acfbf1a18ffccb45bd84aee740f517a5e4a25e28180af444ecf5997ae8cfa7c58893d75f08e18b2f66fe8a98cfcde1840e8d769e6246e40496228a7cdda91251954814c3a9a6095794be9ecf877ad99592904b0b057a223f2898197d2dea054855444f3d2eeaa54911d1f5415130216a2a12b2211b72a92e108a82b9ac6a0242ed90f5d38e1d3b44160a8a30c6383d4e9006564953ece8585e80c19864ea93e435f5e20223737b781131e04505bc58801706f0a200321773f46fd1014e193348490063294ca41c20c5005d14813126737b70a890b99810265803634c92b998a3a990654d1f1c2678c23ed3d513e571c2c2e203a5007a28c11349238812e8608c713897046d304ba34c3848e00346e120418cc4c508fcc0186b32e118c115248c63045d541c2300526bc521821656450174ba0ca360e34797aea99b98ea1ca1060a56bb4c61a315cb871b4a77cd13e06e8f6afa1a7eedc28c3dd3a19c22d0f45c344eb037c38ae38591ba8ceb7d4db0af7fd318ddf3bfeae685311a26585de1dc744a7c5f7e0e3f346c96db3d8cb0f97651e308e512ec9c18ba6ccfcd5ca7acae042b9fbba8a3db78cab963126c951a6fa8ab768777f333acc3bc65dbf83918f17e29fd753448b04ec7ac31a65747e7da8c22519223d8f8f0ae8e33c4aee5a7f3c90ba9de0935e4031a23d8dcfeba0de3ac19cff8ead4a379405304dbaa7687ae5d1ce3eb8d93489224814621f9b2a4833544b0f969eceadbede5e6fe310ec1bed71ef7735763ffa8bf53a3460876ca361bd6cda1feece443af7a24d585c47d5697f5aa260896fe7b3047c7f7e656dd047542ff993e23a272741d472b302b388e56dc6b806065d3bbfd6db051d79b66a701cd0facacdb6dc75adf6ffb5b7ed843638675b16dec707bd7e17dba5ea0dda9fe697c609fd64f52ead7b9ceb0beebe981bdf866ec0fe576947a9d41343cb0593e18a7abeeb59bf1a45e5dd60eac944f65ceee1f218dd4559755869df5dd87a586f3669829a5280c5f9674846874606b7559679413c64df7cd9ee9a20bca81ddf766f74fe7ddd0f7b4a64f731c58bff331a538cbe92dce6dddc0ea9aff1b7ee8b5ddbc5db481bd3b53d71c7fbbedba4b610d6cf3b97dcedfd929ce5a3f322caeee379d79c28b9fa3dbd1c0eaa751c32ba53f7d69c5d16ac6b014efad1bdc1eabbb9fb367bafbd48861fd46e75b561d7fbb1bb135037b6b7e38fadb5a4a39217d61d858e77caed5fbf42774e9c0b0dadb9cdbbdf8ad4a7967a7239d0cecc6cda5d4336a7723f5e799eea8260696cadfb369287d579f128a44231858dd74cb39ca58b3be5a46cff427efe954ef84fa44d7bcc0c2bfeebed1ad5f9c147eae0b2cf59befcd98ce37e97e6f818dd7dfc3f1b508a55339a1e60bdbe473ed0fbfce279f939ee9fa8a9ea461818def390de9ccfe1c965b7ba63bcd0aacd4fb3aeae2cbd2d51aa367ba4569e8b1ba2c8d0aac7baa357d70dfb6b3db3805163f7aa3df97efefb62bd6a0c04299ef84713b7c6ece173527b04f5dad33bbf932d678568d17d66d2aefdeed494d639e2d0b4d17f6337c9f57e60d63cd7a7ba67f6e25a3afc879f517904a4d10299634d237756bf8a7673a753eea5ca04d8194c0be0863bd186fbf9eefced4f9eb90a0e5eda8ae6e3aedefb2673a7585a60e94a3ce5bd51541078d428fc8086ccb93c2fdee67a5957a135d22b48ac036faed5108f7bc717b082c8d3ac72cef7d8ce5aed5337de6993cd12542e58c759b3a296b93f9d6d974135d22f4899578e7e77cbbf9dc9e2f5ed634a43ab10dc69aa97675ea8ab3feeb296de2304f7db78675be97a3677a8419d978ab7bbd9f8452ba9a75abe2b2d7fdcefe6486ad5ead9b65e9750fdbbf4c5f432db367bab4a2b2fe5a7d18cbe65ce28da1677a44e24e2fd07e5c5818dbbb0ce55787abb7d8a2af1189ca97251d199175dff561fd36aba6b8d6e7f22b2a3bca62dcb096355e28a76cfb4732554b8d2f4b3a5a84a84bf8aeacf86795f039f8b2a41303b2d7c5afb4bae95cc77c6f752a3ebfe7ae1162f8a0bbf8c2c4e6465f83fbb986cde5083dd32d1d1a5118043662fc6a73f77f5daed83dd3a38ec9e6e88dce7c69c5184ed8746872121a51a10e75168fcd396be8d037c4f29d5611687a58c662fcdcbb2f259e54e6fc2edb3aa7f37bf355bcb784fbbabc75fe76bd7ee97e9cef84d40eb9e429748d48d29b2f4b3a5b5b97dff2acf06ead6ba453263431a92d5b8733c6d1b5b8277cb44e08b17dec1e7df7f1cdd5eba4cfa5bb763ae7f31d76e7bcfe949ee9a1ff74a48bf1478c75f4b55cefd6f8b5dc66f4cc8e3539af1dfb68a3126287bf3af9707ba64bdd79d07b44b79289eefc3595a7d0686ee003d66985f1757d1937e9f13dd3af27df9119e1d71d793dce9ad5f564b885757837f9195fdab2a64e9f7c59d2f180076cac73df7db36b10d3a7556af2654987031db0f9dbf53b23c53edf9cce335d4f9d17cd5c730526c8ca4ca8459266421746be97251dbbc44ed772d57abbf85eefb93dd3e305da17e0c09335d20af56b19fabecebd36d2c25618738c34df9fcf719e4fb4cb0acc90154992244b44757cbe2ce9e82cec6cfffeafce31bbf610075132ef53e80eb56ef373759ee92b30415668f5978b0f49d23f89a82c499624557f4d408eacb8e6d525d2fc20c9acb0d246a3934fba196b6bf5b1ab2ee68da5ef8f907aa67f0e51f573a8480888a496884202635bfdac5f95d5b9ac145614be164042e1866dd7ea6f664ab3bbcb114867f3e6a4c7595b7d9ee9ef0a2cdece8eea78b5bf87733bdf8011f95e6e5a9b7315666faf3a16452e6cf7e1db309cda79959ee99a42f252f17d5953e7d05fa3ee5a534788b88f2e1bae58ba2cdfbdcd1d19626184b9c6292bfe87bd5dcf743aafc83fb3debea58b176fdfcec16cc052072f9d7a36fcf47eb079ace9d22546095ddb58de26e95717fa26dfa140542572874488dd30dffb153e776b8c2f7aa68ba84a7b0b62db9e91eef82ed49ac68f9ee9f99b74a8eb39107b657e8831a6d54157a7f64cff10f5c99decdcad7d0e4fe9d29b7c59bb163dd3698f1f165f19e3bf5c5dffc5707aa62449d28bd525cac247a4eeafb984d1b9d92894d2b3538ab7fbc3f5e5abafa2b6cc08ff8f8f0834b9081a85de05da4e7a587774368f32b6fbea762df6a196afeefade6e34e32d5d34601b6db3359825d653be47cff4ce73979ebf49910c58795dc36f57fcbfe37eed99dec9d5752f87662cf883876df0e1db22cd544ad83acee505da4f5a619bceef9ffac38be184d533bdf96b2a04a37b4b15208aea7c74d5e908800a2bb75397eb96b1e647aff34cbf2aaa01160ba1a3fbdd74eeddd4587ba67726ad364f37f1c69aee8cf586d0339dfaa456d71bb73bf7d93996727aa63ba12a998ebb69fdab9bfe2ddfea17fe65498ba77651527cf78b2e3ef44cbf40bb268936be5be795d061941acff74cd7a14b69779303d0be97f3d5aff3b1935537cf748f3512752a6acb96151f2b302b304356f22b71728f549ff1654967c8b3d7df778bd1e5da3ec3ec995e5d4feeb4bfa62a0beb66b1d2dc68e51a8156801c59598119b2d269f16549270be72e657b51cefaa874f95c4e97404d3e1fc9e2fbd74dec5ace7aafae927481b634df757babae784bd75ee3eaa2f44c5f8109b2f22198acd10acc90954e68ea88a84a4b575da2f71595e1cb924e15ad638daa4e070253389413909e504e2e0aec6072737e263a64741c0c38f770a4d0df91d175a4c80145143aa080e202fa3379728e27dc8acc643561819967d289c289ea89261c88ca93e3be49c799c8e844f92d1d15b000053a9d2726d07972411590800cf591a13e0f88000702a007f8575b020ee0342007039c588015c5260a1c500199fa4891808aba6ea7733d790b30e14e2080ee6b3481038046210378e73d9d4eb62690040a000501ac070cc0515405010150522ca1ef57100800050070bdcc03542c09a47814379c132811d078e7769ebc0458154060c9431b340fbaa114163db8803102b035a4a00d2d713042a55346f89cb729a41d52e488028a0b3cb16201279ae05480021390400420f000073480010bc0a180043081800318a0000418800096604c40b10463028a1579a30d04606bf0a28b1646892e524cd0185ba20e84609a4168e6a0c182e60a25f8a11252616309190c618cb9b00d09604002cf86049e9c0116f4288109be08c266048df5800765b0a045053cae8a4d3d385438ce139cd07f1ac78a2638a1ffc410a4c108452461093d701006184c09339281993200408819a90a8eca1a74604c650e292750794307949f30a6220738a00ce20deca7ab7a1537b4c1491a94e024032a6c5803632c8c261eab922c35a0c1984a1a984c68fa8caceb8c2b8ccdc536a22f587c00065506aa0a95227c2ea63e68b8aa2b624ce50c4b98a10c337f450b1853990219669e099413632a6a34cd98ca184054880c151730994214916b0a25f98ce19305507ee2b1ee57948fd044e56b02421654a632754487feb23e0bc654d21003634c2a0a480cc2c0189be9c1980a18bec0988a17bac0980a17b68004267f13c6b280852b6c40a007152b30a652052a3095294821743d305f51443e4f9492cf9df2a4471bf85893cc0fb1a1241774add11533a116d784854587a62b269f2e00ca4faab746d58b46485e18538902cb9388ba18538182ca1318d353c709ec7a02ca5ae8ff5012c65484a0d2041526c830813115345496a0a284eb33b26ef0f98c5ef427a1a2aaeac960210304949f9071860a12185339c21bd45086cd85cdc6c2664f81a9c4008c22a81061088c2161ec09e13ff8ea0f25f9dcff41bd3cb1fa33a2b278d07dc92f7a623f9f1110ea458792886e05237a621f08f5a0e97e7c505528c95551a21ffa4309f90fbe2f8ca904e1f31901d11f4a929fc81000e527d5e863e4132a32f3577c9a9bf92b548000e593d721f7547ea0428619b7003185b0401023859833984a0f18735a30a6c2831d30c6184341805580ce12e694e84e013a1a06ca4f9e128b6a31b5905a442da0164f0ba7856bf1d50bf9c0123e1004cb6d81862dbe80a94f0ff7a4531ce8cf9405632a3778c6546c5003fd453e1f32f47f68b08b7c3e2d9f4f0b632a63588ca988111a6dc65466f005632a61303db980f1d7573944f9604c450621eae53faf090b8b0702d0014930a61203f76020fd05d40570e6562df882b15012cbbd262c2cee356161714d58585e136a875c2c6a875c78847e088fd00f79d07d72893ce886ee75350feb7ab44be835880a59153559224b7fa62c7854915f4968b4b5747a55d7c88ca67a5cd5156997194df5e0c1c3bd2adc4b72e9a0a32aa8f3111dcd3c132847937b231e5a8040dfafa01cb9261d968ec8cac20e9b2cd490c5167270583afbab28b220c246577e25d6246ab126d1fd884093122c2c1827940f168447921eb0ce4fd50593840e63ac022d6c73640c6c73e40bb639128431d6002aa4a840dd1c696c830520d8068b25b04d9456fd996648d8dfaded8ab58b14cfed8fb037be1a377653664765738eb050427ff351a7afdefe8db0df2494f1377e7a5f8d9d115637ff3b1d8defedfaf422acab74e3bf98527729c68ab09a467c73db386fafd85b22ec86b7bea7dbf96d3e9d4b120c501061f1dbb7cadfcf219cd445234356e408e510f6b5fdef49e922c6ef74348485bbbe9c77d4afe5cef015e24d29618d113a74f2c5e9e0ccf9697698b697b7bac484b0f452badd73f5c93c1f66cff4ea2b4686ac482b3a1c84d555c37f72ef3adf7b924e4158f77b4ffc8e27a5133b0d84dd8fe2f7d41dfaaddaa37bc79f155000615dc23ca7d4f549b71d6749aa7fb0f1c936e97bb95dfd176bc79f80e207abeb9eb2fda35afb8e353b41e983d61e6fc477be973574d5258241e1c31ee29bf545877036e8cda1bfe9dac9d8f67618ee06dbbd287ab06dea889d431827745f6b1e6c960f7f6e583fd96083120fd655399fabcf61dddfda06e2f56549e709ca1d6c7daf46279f7a743a57d886fdf9f4bfe5a71b3b9c9b1d6c6bb8be1cf16e33ceebaf0e767f9b3ad628f7c652cbc9867df79bbaa86bc4f33637d78093521addf3369fcbe7a0cbaf9bd6e7d863c639df7a050a1d2c7e30361ab7cc34370c9b244912d54c01650e4dce5a9bc72725ac4fbebadf5feda673136af7b1032872b02efede58eb8b237ef8bf76bc39744a408983d5ee395f5c5d95d121fd8b522249d27c59d211a1c0c17afb17b337e7383e7cfa0d36df88a786f13df98e9d76c374281b74d8a484b5c6d6e4bb5a567ab3be3f73be75b7c16e77f3d6991da55043cf6cb06dded70fb1c6535377db1aecd595ee07e3d42e9b6b570d764b579d3b77e862f40de30c50d260b184b15db8f5cbafd04d499224daf168453458fcbc365cb1c30f7b7d7806db1ac5b83dedaee7e79a51cc60b1a6f7a95ff9d34dfa50868152060bb17b584297df750fff254992320a19ecbc32477f7ac2ec52ef7f99d07f3ed793a31af6debdb7c6f23508df431f83950ef3def5c9fb13e20ad3bc390b4a1a96d698f7e74bb79675ead6094d328f29758ea4cad0f4a91e245f9674288a18ec75ef4df9f4779c323e9430d8df9e677d38a7d68efa9b56a080c1d6aae36df735cf9462975fb0bfe3843736ea60cc8fa9674ea2db792f4b3a128a17ec7bdde884b8e9bca36bfed97103285db0f5bdfb18ce78df5528437d1e0a17ecde17fef33def7bf0bdea992e430dd982737142dadc7cae515a6b9cede55cf5ce3f3d53ddf0cbc8504344d48b24c9509ff8aa4b84a20537298475b62963756f90ce569bbcb9e2d89e7f75d0335dd4a1f26549a705250b166e8773d6ede8942e3f2c5818abbb784ffdaf4e78dd156c8d5a4e0a6fcb0dcfead20a36d2f93484ff784aa7b3ab428db23e176bac74b658a1d7e96accde34c513d6d62e15ec67773faf732fe25c698b60a04cc1bed44d4fec326ae920aeb50c1429d8f8ea7efffa395dff522c064a14ac9b4eeaa871751b5efa7c800205bb6996377a8b94ba863ac6f9b2a4e3417982f5f7bb5ff5ebb67caf66da91018a13ec3bd8aeae77dfabf57cd9d3a336c1d2ab73c3cfb76b90ba43cf746a39973e509810619cee39950eab8b9446aa67cc9756b827adda9f675a49926a44c3560c258e50c3e9dae3c34bb0336b5ab38c373625d85677943b6e095b7bd83e09764eaa21d5edeafcef9e3cc33e95f16186b73eaadf83936a5c808204eb6a8bdb9de7f66e361c256976dcf9cb92ce0cca11acfb94f0b62cb7dbb2ba68041ba3d718efdbb2491210508a60bfbe4c658c777ad59ea3ac44b018625873846efa75af710856d38d5b9dde5ecbb4d52d043b61bd10c7363d4257e50b82f556e17409e7fcafaf518050e16d0f6e9721843fb0ade918319cf4eb7ef78f6286757a77ce1be3bffa56977d601bf6ac33ddeeed86b3a63db04dd3adf1d40dbe79a3933cb0f5e64d279c0d3fc75aefafe00a4c10941d389d6e3af86295d4a7cb09a7862dc7f75aeefbb26acf7499093fbf46a2908b73f70aa50cbbb3dffa6a8b4fb6ac67d32e1dd781cd324a27bfd17f3fdf274a0e5cba6bd04527658befb953f8983649a1f47c9dcbd3331dc89115575da2a7040507d69f7c137fa5f061fc3a72484b8f22438248e940506e60b3ab6db6c772d62669d3d51d05f95c49a2b50b141b5857abc3a6b796f33a7ec16f9600a506f6e926e1fda6b59624a979c7b33581a04c020a193656a7ef5ef937d7173dd3c0babf7cf5abd5ef7679c2316cac2dd3a8779bd8abbc62d85767731b6a4d31c4b3350ea0ccc0c69bf7f597d06de7d0c130acfc2c71c553ea28b1dc0e0c08df7b95d2189bac8f5609676e4d62edaf6e7f1419d81a27aceeeafdb729ceb0c6c04a7ce9f6187196783eded4baa65b5df20c1418d877a57fd4144ab9df73974519711507282fb078e38bdf376def6d664dc9407181a5aff98c0def7c9fba7ceb7e7cd41aa0b4c0ea1b69c5faeeed9e9ed23dd3a91db266ae11499224da718af285adb746d89eebfd1e694575ae97814e67101416d81971ceae69bb8de68b618f151f2b2dd3f5f890ad05282bb01a6f8d5b8338dff96f6e1558cfbae1595b7e75d7aaa367c20c59b1a6c71f2829b0dba99bdb5dbfaf3d8e1405f6e24627ac94b6a861845eab172827b0d23dfacc7e31d63abe2d49f46549a7098a17b6b9df37678f0fbf8475d78ed300a50babe76fb8ebd31bd7a869f64c9732039a4ad8b7bdc128e1c35bbbbbe9824434d2ff43bf68a45fbf2268286175a33f1f95534b4863d33043de246cf577133be72ff3d4f985c6d048c252d7decf08efd3325f7c6186ac4c303491b0db63ddf8dded4ed74cab04030d24eccdb5c97ba9fcfb68bcfa1136cb58bdc2d8e06c4e296ca1ae90cba57184755bbb747aba87b33f293dd3affd9f4ee7aa28ab135d236cd5eebe89bd4937ab83b1f9555116648475d939beadd6dff1bd5b84adb2c1ab5d6dae23baa0e93315a58ab0f546dc689310c2fafc3ad10c8c24d50e2d439308fb3e25d6cff13f89f3db4a24a979c72722acce716b19bf5ea7ebbed29233976b3fd01cc2bed4b039fab9bd7377f820d10c8c24cd5c92d4f199cbe9406308ebf65fbde9cc2fd677f52e84d533e68c3fcffddc3f6342d888b5c4efb5fdce3d6239085beb751ddddc2f42f9f487da90ba2e90151f2ba24b44924417e49a0bc2d6f6efda9bb966fd506f178fa00984757f5d8e32620ab58b384640d88bb3deee5b7ef9dcc33f58b96fc6f9622cb7bef83dcff42b34793a1f82c98a31fac13a591f6e0e3b87d3d1996312347db08d3ea9a57e776ee7375f3ed8bba384f9ea5aa5ce0ddfd7ccd0ecc162d864ac3ace99af8bfb453d58b79da6b54d89b7abb079f31868f260ddbddc78cf17ab4b4863c48395ba55d8f0bf99a17cef833bd4159a5e4519a1ae908b24b51368ee60ff46df7a63f7dadcd81b7425d4a10f4d1bd66386f7bec732ef19a9d694e77a2293a825d28886c60ef65539dd673765d4f3c12895a0a9839d98fe8e6fce077d6b4c914812f42692e4de71e84d1e1bd6e5d86ad5f775d331b617e51a96ce2a5df3fbe24f389d337264a51d59f1b1d2b058313264c54a92247d44a0496a78a0a183fd8df3d6cddf7b0aa38e4c3e235cab22fbfe101f2b4a567cac5cb1e2634592aa67525dd0fe23afa91749922469ba6484660e565648e776f03d75d92af64c0751d5865f19912410550191a4cba11b412307ebda94b2dde8e8bb8d21ad2f4b3a1a1568e26061cb55bf7ef567bbfbe16029d454d20cdf95f2bebcdf60af7c5db77c9e5d75cf19aec004591151d50f491251956e1a37d89bf76eae4149e57db80d36632adfa5cfeaf46bf1b2c16e4d23dc2e7f9e75e737d76031a412de87ad6d6fd3dd33bdba541590fc22249294bf096dded19ca15183d579ba0863a412bba6b469d230a34b07a38cd4e78c3e9d378d2b8538faadd263fcad4183c50d537dfda7cb7ac2d07f3a54a8533dbfa672cc1dea67b0ae758c50ba6f714247a914a2a44e87be2ce970a131836d6e6a186b94fa62d774037264e55597e895c1e6b8e763ea669cd0694906fb307e14d6f99aabefdc55c3e2561d3619238ef7e5fb3e3fbd7c13aa32224972bad5713e09cd18ecc6f5797b74fbaecf697db56eb192a47f089a346cfc5b5dfcdda6ce1a7b6e4ec5607374da6074b44aece0969ee94cf215c12849d30b4d18ec6baf35eff972bfb7eb7ba6239195e4a10183c558bbbd6573f5df749f9ee95c7ce7ca710526c80a17f641138c0f49facf85479624d197259d91e60b75d6e9e073fea43f27db742d5618a76beeeaf7d7e47e764766fa7c5eba271a2fd897718e6fbbff4ce1bfd32b345146e0104d172c75744fddf6bd7eefa6ef99feba1df1519dbaaeaf2e6baa2a8c860b56fba3b24a3cfd9dd6fa79a67f46a0f719119124ba06cd16ec9ef941ec8e1f560d31f54c67e29c50a2a885460b16fbeb57e547af51e2a953716139499224284792244992343532d064c16aec9a7cee7cefa7ffa8673a75518f10cad1fbdca97a4bead064f29fabbf4935cad25f96743aa0c182a517c6e862c38f3e89efbb82bd4ed74865d6704feca07c59d2d942630589777d34ffbe53ff8b585305dbb0c6b0667c2f84f4c646052b67c3d99da3b07e8cb569a6603de356dfc50e7abc39cb9114ac84b06e077ffe0c3b48b983cdf35e3a238cdff4dc5b7aa6d3a8e4b2284f67125d6b8c9436ec8d70ca7777bbbea55bd12549923ecf5c9324499224f95899d97baa5e09911649f2b1e29e2449529e24a9e4935f4b92c822400b52ecd0a88c59e3bb3dd3aba9e33e6152ea60f39b18378a5bd478ef0da363a362c7d5ddd590e635ac6389aba34ef574173e6d410a1dec6e57ba7ea7b47aa657175d8109b2925b7cac54a1070139b23253c1b8f8b2a4938246ca1c6c73d7b3bfd32d4edd60f44c87374891839df94109b78cfadd8deea6c4c13629379e323f74bf31de70b0dfe474aaa5cbf23d0ce71b6c94543fbcdd7ced36f8a417296eb0bf37de185e59a7f37a771b2c9c517b7498278e373e6483ddb76977e7cb4f238c4e6ed59c4bca1aec76f2b1934ee97ef90d7aa653f72a52d4606bd37257ada77bcbb865e77aa4a4c166b775d6b5550a37a4fe32cfa513844a4183ddf27fdfec4e7d42bfd59fc1e68ba1aed7f17cb8357d9ee92ff39f4904cacf45201f461e1252cc60f19d13cb4cdfbf37df9c2ef76987281f3f2489da920463829432b43cdf6d774d1dc63547eb65494783821432d858ff6dfcdecf9ce77e77922402c91435ecf69cf77b74bf7734ee36065b5fad58ca48e1c3f73e9a868dff93e67befbc7262872962b05afafcafd76d1997a484c1d6862f748ec2ebe4ce1ace9802060b6fae19bf07a5a4f0ea27540f49d2ff84c26e7ee1b584d8bd08ebcceda9673a04418a17e8c7ede8d70d9b769fcfed486e87942e40a7b9fa7eeef2d6ee28a5254992669e50956877b4be9234dd0aa655575d22943aa470c1a593d8b9765b9ef39d674a1288aab624adc00459a1710e295bb8587adcef71e24da98e5ab0ad3de9d37da4fa41bcab67ba24b91da464e1a386f4fa7d2a9dacd36141c6dd60f62a6b7e7d85fde294ee4eb9ef74dc3cd357f41cad80268f253559c173b4d2a015a0d68f237c31be46a5ce9ee9d708d4f97c6ea6d788480848c422a50af645d78fde6ff95bfdb83dd3a37b0a156ca3534e59ab3fbc5752e7991e2d4af4e2dcdfcb920e929429449f703a6caecde9edc1f8a6cbd06d1ae7f629efbb5aa448c1ea9f4ed6ec4fe7745daf67fa8b82750e71d3514bba277c170a36c6cfde5ceea7ae3eaded09d62b6e533f8f314efad279a6cb10a438c1e61c77d37e9fa637eb1782c9729ed204fbb6d3747aa4feb03d779bc2042bbf51ad61adb76e77cd1d0d1b1de6b804ebedaf7ecff0b9ada3739fcff5f15e90a2049bf1eb58617dd16712a2d709a7cbeab2b9e79ca49c61e19377bbedaaf4ab6b7d2948b015bea9dbeb8b31cc2d7e4555d5a71cc1d22d75931352e7bae997be821423d81677832d4ba7637c72d32258a8ab96f1d5e6ad627c2111ecb7bd23add0f38b3466390aa50c81462adde3a7b9e297d14a11827c50c2592195d4ebf32825f45a5b8eaeb79e75d61904ab73ded5bd86bd3989bfa500c1bab6bfc6ff47f36cf06bca0f6cc62fbfe7f08e504e7d3dc50c38ab6baf52d76a6dad3638a1847753f897ba79e1c7ea03db5a93916637357d87ef7ba6531e293db0d5259c99c2fbdea3d39207b6e5475f6cee77dcfb6998b2032bf1d3b3c2791dfdd8fea59461a1db2deb9af1cb534eadc148d181750ecff9fe1c8ecec1a6afea1aa93248c98195f8ffe148a73fb8a5ab0e0716de3863ad1a53a8bded7b034b6b76dedaadb4fe76b8dac0be7e7862e7314ed8aabf1ad83df593b149f9cecd3c9d8c7bddc6efd5877ac64d039b5fdf0d33a5f81f53776b6c2963449fb0be37e574d249fafc4df8f7797bf3c514312c762af1de305289b5ce50cec0c629b1ceb9d53db56fbd619012868554c71731863fdd4138c1b050bf99fdd2ad21ae7a3b507ed2526460a3acfa1d958e3ec6b3c5cbfaeb0e01e5278d052931b011ee2631769bb638b5969204841418d887d251df4ec65869abfbbd175838a38bf7b96b3ce1762e4992f49a77fcf96b428a0b6c9e70defbd9b16e54cb2a4992e49a4812754d9c9b91d2021b5b7c0ffa6db46ae8365441ca17563a0a6f9c1f3f43f77d535860f7dcf5b6e81aad583fd5292bb0f8de7b7d6387ef6189af4b5181c5f475ccf5c9863d4f083bde454a0aec9bf8394ce77e5c67d328b095c28d5bbc38c7b837dc27b0b4eaaaa76becafa5dcd90b4bbfe29ff365ea974e7d53bab0bab6989de30c1bc4aeb94a5848e3733bc2ba299dda514ad8f6dfe8e74b33a5726bf8ea359a84cd17b7f9343b17f7de5b5b496ac10d4958df4e57092786b5662775246c8e34d256ddc52dd3e8141214beea5e95d5fdcd1aa9d388e5d4cee59cf95b8cf73dc2d60a5ba474d288dbf3fc92249d23ac94b335979b6ed335f86823ec7dd1f37b0e697c35436784c5994e8de957ad3dd33b33b8d364d2d17bdc588475705ebdb3bbede44f473dd3afa97aab53519f997b75a20bed4e471196b64b65acf8fd4d848d5fabacb5ee0769830f23c246a861bd58df0bdb75181fc2d2f6e0efb6e3ccb0ca070d115d95b0396dee39e7b3d2eade863f5dddee6decfbbd10b6c196f56e75e64b08eb627691ea26e7c337e134c18d41d8a91bdd524a7ae7fd3c2b1041d87f92cefaa0bf8db7cbec2bb811089ba9dcae3d381fc377f812206c9e77e2e9f4ad735fdcae244952ed38bdc18d3f58b72f6cf3522add0d3f58e74dbfec74c44ee7199df6c1e687f1db5efdea5d2bad7cb0cee17d387594f2d6e96d0f56d6d72a9eb2bab99d8e520f16b65a1b94ef9ee7e74e5a37f260ebccd0e56c72bff67a3e1e6c9539bf1ca9d3b1b536e51d2cc6174efd52d2886186af0ddb1e8d7753a9df84f96a9776b07b4ef9eeb50dbdeef7eb993e733faf231537ea60e7744ddfabf59e51d2a83dd3eb37a9463ee2cdc00d36ac9ece497c5f94ffe6c4bf8695eee78db55d9ae3cd35d2c1e246dd3dc2572fae2dba3958e7323b9cde9a5f791b96836d35c2e9393a775d377c6fc4c1cee7746eb3d557f18bd16fc0c1ea396f86546eecde63279d4619dc78839d6def1d77fe2d659e53df708395946ee820761e9f74fbb5c1c2e7b9b9d72a1bc5cfdf0d36d808efdfeb33ea776fad8f0837d660db7dfcf8c5f81252ea1c1de3861a2c7e39ab74beb3fc0bef96a4daf18ebb9106fb26a5ede2ed3acf4a9b43839bb5b9da28ac4e4ed93c46f748b7f6c754d38af78efa0cd65fae78cbf7efebc78a9970c30c967eae97eaa8759418ff96244992a4da71f75906bbafcef7e5bcb061b7b52683a5fbdf761f5b93bbbad8d4b01bd7fa26a6b7652a9bdc63b09246985f6eeecafaf3b634ee9571d6e9ea6dbbfeab6278de7cba39278ccddd94d5bdbae384d8f79692bafd37c260718dfb5df48a5fa4504f305898e73f9cf3a3bedd9cee0b76df77d5a33bafcf6bf41b5eb091b6975a66da72d50ebf1b5db02fe69739eb27b7d6aebd1b5c90deaaacb2c629a96b2fc249a3638f5a468df1fbf9e28d2d5888ebbc15c32c37a4fe9e0a6e68c1d20c5f6aeaad6687299e59b0dadd3c73ad2feaafb3b91b58b0f9c61bf3beb2bd2b9fd6f4c615acde57c3f9748ef5c1989b15eca492d6d63ce7b6e9c4efb95105aba33fe759cf3831cc17afc004f93173bd2ce95437a860e1db6ed388b76bf1edb8a760ab86f3bfea7dfdc29782fd37bfd6a9e794adca1d05abf37fc453ee1963c4170a563fa7b5ccaee6f7d2d127583875fe1bf3bbecaa7682cdb256fab7c12c9b9c4db010cb0cbf6e47378d4d32c1ba19e5f307a996b565f768d877ad52f85b6378e7747a09366ad97ccf0a6bfea795609f83aee9e6a4cc3edfe72458a775c296a5bfdcda7bf80cebda5f6b95c29763dd8f04bbdbddade926bf69baf5116cd415c7eceef5fcfdf11ac1c28af37de7e43b5c1d17c142bfd25d877f43183d5622d8bff0fdbe7e8feb747a0ec1c2bbb3ab7052f7995e298560dfbcdbc1765fdbdbbd0f82bdf349bae9dd71bbfc40b097eacfb7c147b57cf8c51f58aadde559a76eb945bfd00c2b6fa5fbdd86d851edf8f9c0423aefcc7246a877a5b707f6e1ed1ed6fb23d6d2511e583ce97e7acb99378e74eec04a4cf7d4317ed30e7a7465d88c778d9ef36ed255ea5c07f6ba1aa1c7e8247df0e11cd89fb5392adb7bd9a5531cd8a99d467c639cf7d6175b096edcc0c6166b9eda69df57c76d032b6bae10e73775854ec31a58fc3abb5b699e0fd3e7645899e76dfbffe77dedb54d03eb1ac6b1c928316d4ebe1ec366d77c36ecf2fbb765cc62581ae57450c2ea1f1f3f3c03eb5c7defe93c356efaff8661a5ce3037fdb9563a271876d3483dbbf84e7e83b9cac0de989fd3d2b5eaf4e318035b63a5eea8cf786f7d8dc2c0fee787317b6d335e89e70becfedbb0c718dd731fa70bec8375467f77594e59630b2cf4bf384afaeaa4983ef985dd124aac277cdabd5c290b6c84f2ee776fd6bf7bcb15d888a99b0e63778d2f842ab0573f87fa418d65c3db630aecbbf7e618a3d30e3a5c5160e56becb1d61d7deb4c4f603d3a9cf2cdfd1c74ef7961bfbea6dde7831043e76e74615f6e504fbc5dbae7708395b02e23f6ed5fb7a41b6b4ad84b9d8357435cb196314fc2de485bcc7fdf6c7ae3f6246131940ea3ce38ba7ddd47c24689779e309eafa8f431a9859116a390310000009c981b007312003038241c8d05a3d18054b08ceb031400034e7e62aa4e3c18c963c124c7511044318c410618420021c600820c54383702793513a7c91280b511ad6d9522735c2a27fb90867409efcc57c540f375e0df93c56a4aa99b00f0b687cf290c6430a2c704aa3713da25c89357278fe7aeb8ae9831238410c75c8156fb3c0aeb32f7272093abc6ffd74562a6b1f62a2d66c855d36359165dc2bfbb1d3448f276fde3125139830313506d8b4858696eef3ec9130110aec8d2f4598463dc699a0484b7d2ac7e029f2da19398ccfd9ec5bcc6d76f7f76200eee0489a088b9365e455de0523f88925cd55faa1318fa2080be3dc0800640606e4986d574e0d20c65483a7f9d834ad9f82fc1755e186ecea81f4ec956c6a16ca63c983909a3c5785038f4517bd0eabce68274c0ed259d38b641179a77ea3a8f5c575de2402aa5f4ca0821f7404aa342ccca0685a32e7851aa47ee15a5ef917434fe4a0e1cc7926e52a154f11e639645053d2210db98da3041a373196d1cb787b14092e5ad5d14b767377b1b211f649a3282f60f27a4f066abc76a400abe786a6f05a5f69b1078d6b235ec9a03cb42483835160b5102533cfb5553b55090a90f4120246fb80868356dcbfe4fe9284069e3c54af047d54085465254f8d745299a9faf708cc33ff2d9f53a887160412750c28afc215e41ac7ae23ea32922002e1c4d81f58e14804efb764d6448b4f709be151de2d7563f715bc62c04c0582c56072f720e96770ccf051f3952080c60ac05e67c2b75d1829ae8c6dcd9744da0434cc3c54824af50d409b510196c0f9fd95e776178473d06f990e10d40c824e905316cb4582d439cd19012e60e75788d83239936be6c6493b5b3247dfa9e84d4f8ea8750b0d166d3b4bb4433f091e54b64f8d3c2d7a24e8a2118b20c8cdd7b109e3a9b3bd1e18f3f3c262278dfc5aaa71379f7b7a5cd50b25dc86233b515ccc85a0c371a7d4bf760e9872a0c36582aadaff6ec64ff6d93c1065c8a08e35b8c4100fcdba2f7cbfdfa898019fa1bbf62a15fc1a9281bf1450d7b634cb1f4ee5338e7db74bea9d551f5dd58f9487ed6dd329ca2e63853c5ba40247885a8b56e7ec513de484e2f4e4b8a36b58f2e53c91aa2485244342e87685b102a77048e605202f7a226b1ec97b1ee41e2b0a6925055cbcb0aad792f9b12aa802ad172a6b900cb17508a031dd99399d219f2cd6e609d9b9d902d970907a2ca25ec65cdc9df384c1376cdfe783be9fae93bed866a6c498ec4302f684e3b66a1a5a30ab709a72fbc6d35959bca8655ca6e4270cfd6dc7402b81e23531ca8925b869d6397cbd7f14d4c4aa6f6e6616017f45ef52fcfff988d5f6fcd68e00c4c93b88741f012db69f1c72f655f1a4e3bc14101016e0f3a653eef6ab5a23fccd4f8782f126c87b36222b94af66af6cfbcc0f813f5048447503c6428de763159bb58d1ab927a01f75338954a2f68efdc1b16a3c3787721416ae4a1b676598191c29d5b160bf1e243d16affe6b0cfb5d154ecccc1a43a857c0876cfdd497acd49ee672d57f166a2675091235ff8f6b720734cb7321ab7a3f1d2162b4857af567f3916151cc5aec76886e284bf0a471cfe129dd6659ccee403eb5854d19932322edc84b6094050f0bd35ad0c498139a16496a11f738f1b235220028fd169f4b6d6354c9c10dedd3d8d50f1605c91f48d2de10b6968c9ee5f86566b694051855b234b5c69e25f8abf930864a48e39226f312ebafbad0446fcf0f02b719a89081974f24d65eaaae7baef2914ec544dd9562f59b4102da6f4a4a0e0e34cbd7c79a8682b6582df639b14947f795f5321e3cebfcc765bbc4f5bfb1580953458ad428071dad0ffc7c5bd079134fdd3e49618450e50f7b263e0029dab5fd56d5b9a923623fb5c52024e9b0971e35a5229009a948ef4f0a3429838b5b80ee476689e07b23131a5c25067dfb62f971535bdbcc452b63cc9b5399fe475f93a12a17b9a4cdb0c131155044f5c42159b76fa99541f80b9f6a00b0f3defdf3a69abf1130be6fc6590a531e2ec6d8445dda86ca3dbabc958f62cc0890846dc3219e6b0fd0e7364bc45f3f2596aa799cdafd59081485482ce9704172900e0904f5066d2d43f1e4b0681df5dea48a39fd636747e06ead356548cf52c385109ea9419dac9e3921ef7b4034ef9aef5bd59795f48b63db86d615a12aba3051f9bdecbe1905f4f743cd2a5d84f5cc562b70bf037623d719bda0e98e96420c13509c40cafc9c81d2a1beb8d8a682b2f07cf11a1c4f26ee88492a4efd6f0e138a9d73617a1e60257e5a3f8a175d85f3cd7585b0aa8fe50ded5bd36096b4aefb2df450a5e9d814da5878d0849ecf35fc246cde79196be9053da8379dbeea9644f0ac0f9b16ffa9ee264f56893e46a38d0f3ab792142ac01c09800b0b02de543031d6329132bb9db4e465a73cd6a0e93270a7a9413b87103a4f8121d9aa1de54813ccd3a39b0912453e244b31a13361d6012472ac43c5f1f5d7d77dd0c3cd246d4d507843353e0e2ed44467ac0aa659702e9795bc23dd2920e4865af9652899f80c38d77da4aa6cd1cc0a52493e73b4b311f0f694e63e71d7d22c04d8d27948142a758eab8e285741978573f782cd1f35cc3b2be4d3b1cf5dd6219f7d927893f83b5b6f9983636d9ca34d1a8c47cd03722701419ace2de470bfc31d4cbd09c3c1f83569c66805b74577c5ae85451b3d2460be611f7a32d8a1a064ab0722ef688ebc402795973692c48925842fb8cea03eefcc7a24b38f87156cfa68f75210cbd99174b8b0e2cf728e2a342fc30ab83d3076b44c97e78afd4b366d3a2920f95e4a0d2ab9d73c93c39ddee2e53f6e62d849a3cb9d7591663e2a6bc7b83e2aa90dd88f5fde5b9cd7861041d17e8fc4cb5a6eb99241ef2e0408e9475b92f4d918bc370db807fe88e2ad34c1cbf2bdddc629761222d2b629a5bb70bdf30ea19f46a7b9da61a3007749374d4cef4937666ee8328b7a7dfb5801d4434ea57c3d44703b47b6a65d1e94c0055c10720aa1f5cad919df032d1a81e20d2d3da024febe8ceb87850832c3531d32c1e4524ce0810ae93a1f7e66b171b66b48c69ce96c0e734b6334d6f7f74a15ec7a7b8fbcdfc8164fe1c01b089c41eed818d025d410edda7fed860c3a129bd86b34a7a7309da8be3cf0814d8f9913591dbbbd1186516ac455da3fb0fbbef2cdcae681a784cc447c654ea1e1c71e1c24ba02f8ee1e3d0ae776e8ebeeaa9d9ccbc62d04266e317b87f9c789573871b3b07970b2525a943f1346c5811125ee30b3ff98430c545e914f8783b0105a6f371065e58c858e0c175544ff7e47ba0431b303f85627f63a0c76e2e68e3aadb7e6b3469932b7aecec02ad15c676e330d29d3bda62ba56d69566f36db4683f1b7a687437f6d5c6bcf7ac344833ba73b916dbca62bcadecb466136d6e7587e6d5c6baf76c346863e8ae11ee466ba3ca3bf271b3e37507661953384cf331b1c6741647ee1d2b5b659cb6fc49ab2745d6bcefc394f72a0e74f6bbabd6367652dccdbb3c9e38d0d5efe5daaa58cd6d3746d9afe3c6d3075deb6e66ad6ad7367952c49977fe3045d79bac26db67f107d70ccc4a28100e796de497ca0bb45f1a5add4c8449c737e49a5c80d4cc953a4eecffa4f2a0e987d98cc1600e26d015d22da4f5e3dacbd6fd4988d0f21d5eb8f1e2930e34f12405da45c889e441887416708c2a9d9960dc04948fcd2d05e3dd0d5930366d89a7b946463902005062ef18024557ff428d5ae50b26a0859aeee721810bfdf7118366747db528f63b64987663661e4acfef73748d955d5748581aa49f5e6dc4e440a8c2cea011909ae288396dd4d73124d34fe8ea10658a84a648c17390fdad525eeb71958a289fec1632d286704f91e99b42f17921ffccf887ff96ceae4de398e6077d18c285bdc70889613da721eafbb940f3b2a3a3f2cb8d0708a607db79a6f530b8055d8c2c94ea47d3666ddc3545568bea9f7ca609f0e19c29d51502a00a9803105d98d6c2a9aee04c7327499e9d344333b4f8a6d0e641f1ba3d7235b12c6b231aa699208001809f0299f019051e78dfc9079670099cab082d2245dda47e132701f1c4753a61b5485f2a740b65666507854fc5558941f582719ba5237dfe2c277b2551430f9b16890d596d23e2a4b4115d7b896ededcaa75991d178485f7f352cb99a0df0d80b9e25c4cfa016861053ced9048b757473f1af2f14c1bcd500af1d9dc59846552cb2320dc91e715d5190c03da1794d7965954fa157e453fb7f64e5522eb9f19bd8a2ea3573f1a437d58ccc43d5391b45b59ae3e89ea75bfc89cbcd995a5d38dd35d39ab3a0155c6bc0bfddf1209401e23aaf9728ce6d5d9d8382461a856852153602d6eda42c9fea3acb4bff512922c85c9aa0a009b2accc7d3231746c6bb179a8f2749071e2712c8402205b16dcfb2c4aeb40f186d0c608945f20f84fccf11ea4707040f5c37d25098a0870c45eb51f73d3d9d9d26472b9532ddf5851f055b2ec657ef597d38791431009fd343d4ba98f5259a659a24d588f99703d858befc39cc1c9077a0120b01c4028be575683c543c272f2a0423fb21270be2ad87020bbf5b436f638db3c28561f3a9a2b773afe6395ec3307b5ba647af7ad57351593a5b8d9012099acf38b4d4601fa16f87d335e90f29b61f82969189fa99e18645954e0905bc3bf8ffa4d32b781ae41e3b4198ba0819a1d393a85e05c98a6fd56185be131e01a2775afe6a7d76717381f88018ed8307d435f916b502209fc7268e438f65ff6551b569ab54b6b6312e59aaf670f971c11a065e26bcbcfd5d610b1326f353477900780028153d277b09fac131bd8343531d40b8b73ec074943065d27aed712e44a850f8bdb3d34b3d1018b56071a2686403a66f00abd25a711e687393034e29b502f8347ab3888258d436086b512a12be70b13346633679607626d0f953c39fc847d4c0c0c3543b0c3289b5fe5a70381e2ce6b728a38fae2a81b63c4133a6ad518a8e0f1d7ac9701612144cb4bf2e30467f9468056ef7e2abfaccdecc6a4c7e5c58fedde0b7223729bf79cb0d27979ad06012786d9366303bf430a439c558f4d53fdb9593da1e6350210e4685fa88cd547207548de6b6e20f6f0c4ac1f614e754499fe95d198725e73e180b158cb6c457ab65c578b94fb2971903bf7d602e6959f0289f2420c652728d8db4111bc541407e74c86595e14806ec684235d524ead9a8fde34ffe0c324f547de9970c6f8bfc71a6119b33dd14d155f2a4b5bc3bd0c3e9f0a90ab707083804c08edf6c1460c5778efb31d3d637529022553b1818be6b6bca62a8f351d81500fd33e003299f4a6e06cb81489d1edc68a4e164385c852a8ca44a14659d0f9dff71266cb0bb2e734f62968853a0b02504c22aa22e29bda8815c19e462181223edfbb554fec8c949f3ee6a22de385a9f13a93e1563d987cc90937662027cbc9519006e46f3cc330815f415655a4b6de936183917a778485d36abd1b639de4cfa8876c6d7635fd3f682bec27a74d39feb2ea2ee81a2362cd536265c6092cae4261f166d68eac46cf260f21a60ab5b32626bea08a8104b9ffb6ae61fca23d28d3edc1df0f38f513863cb3618ffef3944090c6da5e3d5662c090426649094612acc4d203207ddd9e2896f0170d5aee8a8e2110d7d4700e0bf354cd351089ddc4c466291601ae76683342d5f99e101d01077b0efc1d612f51f60bbe247c09fd3369f4352ed134f0837c7b913e58d41ea81de4131b2fca2072dc09465d8cf5cb05d913ac01e55ff5df6095b4d5c0da916cdaadc3c8a04f08147ad6d21016fc65013fea71612f66a845f6ba7bc2062fcab7373ac96a311ec9eca95bf76022548c6c5bd64e8246bd5be4e6954d8fff0ca8ad0318e95f1a054b92ef4b7448f96a10c0593e8c424d500fbe63bf06ba96f7dd86ca6d30d9b58996c034dde42d1f72a76d0bc313ab81496eaa656b27b3ada7003e0ef06183490627554f4c4ad4aec9480626570a321b0d26d00a8c3420123b9c64696ca95ffe1c429db52f09c07963807d3cb3950007405a75019681fb8855649cefed86225b02e805635cad7ff005548bd26c574c57f368635f606431ccdb6da59575d7753980e56e6fdaa68dfe228310d437d847ad119668c15b05d5e4b3072b125692b37dfdc604a9b060168944d6abec8220ab9f474626530f35f436cccb85d7c539b1507bb7504dabf68d916253588760bcdfe603c2bd208f429550934bced60889c119b7519ad602f42fead85a7e10923aeab41582bf2ea4347a91902b90204c94dfb1d9f9cbe25e1a5ef06aa0495f3ceac8b828ad2163ddb248f6dab047cdbd01c26ac4726e9301ed20aa80617fc5855c6821044bf2805f0fd932bc6ea9494d85007fe273cb38b36742a34b719b13d7d2a714ac073962786b319d10f9ff6877eac0b36517bbce71477b1bd6e6db658206a2573e0d2473dd5904f9847cb3166d74c3ad13ad19b36a337ddcc4817a1797f88e82c2abab80331188e2c2a9f3e9289fc88964276ddc97ea8704564fa7fee0a1b1230c3292c5f38ba4d0f065d1b898bc8bbd7300fe641b46e902240545e3f923d54583f25a2bfad1a5ce4d122ebd3bc013eb277b77d28f134dea958739a46dfc16c70870dcc0cb3b5b5873312378e0dbaffdb04a823ac499a1ab6200e82633a55488a07b6355834c7551a6352cbdcfa846689decfc447bcc6d7498ceaecf89bc452d3f6bd3c5ec97862ddf43b1460c6ec6fe3fb7828590f6386058883da9d6deba3d947be3d3955570f24e01dd4b0d0833401bbddc1bc70cef5a0ad44d5b51a925504053a6dd01781f91df85f35d8ee4c4bdf70a6ffd68202277ad18bca07a7ccce43b6fc542020d34ad20f02e6cb6af6dd370d8edc5de04d77faa771aa0416c226ad561396d67fb5d63d35aa1e0614dd2a78a0cdbc34144a925cd383b7eae179a40518540fdeb95351814482209c1838780f8ae1422cfb04524e1e0924cb03262875f9fab569c8eaf45a15605dde2b0a77e3651cdc238a314dff4aa6ea8b218ce4b3b32cbe05b967a052c7761ecaf9d04c9e6e35e5ee3969c4a17da77c9a46656122286a1ebc851274586613c385c886b3c80d3700afa7fd2d04fc647a896b7a38465ed98672de9ae674e5264f1ffb534bb5cf069e0e64154f1ecb5b9de158d0a1119b63b0e4ba071e637a942cab89c9202e068b3e0da06851dc2c631f59707963ac6e1f9dff8de90691244371b246f9c9df2dde81d6e620fe11469720e8d23bd48dce150cbcacf14f03be4849c8a605374a18d6e26ea9ce9919d4c04baad165ce00a55552eb526cacc80c9097a96a886866d7cacdc5d67abf308b543896543f5f7050199cc6aa81944115dbac64e3f36e15cfad801e37b9fef4edde1ede15d5925ec8c1db9d7e4209642a9365805b4e40f146709e1a07020a805a2ad75790d1094d246a980326fc0ad6ce19ea6a5a2e9abd46d2a62b861a07febe277820599d470293ce30b895636280443c7c2a330e0b75c0207aa3479a12c393cb01c9898a17344675e299ad7ad3b1c518d0bc8bc9ded1de1afcb31b05ac9dbefadd5f82e23320d728da96bd8fb878e956decf6488e83414128b10d353f0c83078d32f99da710f3937fd8523b935d3e7f93006a8f3c620c6cc87b254b656cd95988142ad89e253c319d417aea2df56b1c4dcb20dd046b19be8cd722ad48fbc47beac459501bc01b0547c1eb3c0c9124799ea35cdf41a304147808ddf5e3bd92d51f3fcf3a9634cb8beebd712eb05c6cc58422dcba67d0c7cf9eb49c6f6794ae7d841e469ed1f96cea13e0c13820941c9a6319bb991853aa62259d7e7f7c0a4e149117fe7c37410178558420ba01b622504a3242742e6f96e6247896de25624b0cd24e45f90b608580c79b4381e3e459315929574b707b88cb9025ac4494d54c23f69e00d43b16bd1b7fad16c8bc725d92010bfb75bd9c02952f1d67d8de2e45023b31a72ee4fcfa1e3bc2f6a4b7ac04cb2b4db983d44e50f1f37d48834b8432f79e543c29cc1b743f679b37c76b08340e7b98771fe3e1923e871b761747c6af30fd289a59c559ddb490407121ca5d1c64a73fcf85ec115748dbebabd072c01301723b0090b0227f9ffe63835d851742092c8cba1550b7c9d6b0604bcc5f0e24560c33b1ae10d03238d2752babd8baf89ba70ee978cfffb0bd1bf8efb265357487ba1272cc8902329ed88a6b234e22dec346d240dc08517bd44d663b407e8669245a25d8a4b25f8a73cc6e792bd1120b5956080ec508a180d55562660836299d460eac87968bbe258ac7a59720951b8a919562e7e20b09cc693bb45d41eec1f4f5410a5ce80a60c692b302bf829582a553e7e13f548809335e9d34a6ea3dbfc2af295099e28987fafb9447af65cac9c64cfde2f840bb5719592200cb648846eca88f045480afeef76d32e12b314cc76e058e77a24811972b05de1a2d41848b5166451c2410ca5767aec0bea4f5b334db61344d4f87b3390ed355e98102ad5c76321300456f9358c251d5341d1c36755774c36a8746aa7b7863ad13bc00d59bb33ffc24825cf6054c702ef2b2e34239532e23c349ab70b492331f13cd32a4df0ae95641e5ad5c021dceca41a517b4cc87e71f11fc9d285a7c957123547746ea78f86a00094ba4f62f3fd8841085fa4f716611c6f016674db065de55aa15a9ebec6ed1a704f7bcfc0fc57fb146ed0563040d4d037b77022c5135392246584c204bacb313ddad640a767a77b82b21fb721c0b5a8a5c8cc094269ea351058975613d4c268b147086a8025281b1b165c6e01e85fea5d8781ec8e9023a204ded0beeccdd228a2073e15a1c023be9f568193aae64aa41ee31952845ebfc6283d0f5fd0e7130243ad3d5f0f0553a062583caea3729e70e5f2891c100bbf7c7c8da64252f6a7b48b4164301abb8a984b617de792f9ed9a69033cc5490b00708e288bb402d43692ce15b1a13b22e2912b91667240808c872d2d111e4a1d2aeb5118739e5a9449d9156d871c4f50f6b33092e558145bf4a19d4e8078709d75a7f88bdd9981947f89597d5d158a81dcb265e13b3328c14d820490a6b2fd1c733ce08cbf501b12a02a0f54eca8263409966759c364690d83baa2438f1a00f24f203db8a50d7ceb1900d6161061052eba5fbaf56a8560ea377b8331fbb64d9e77c0ca4c1f22a8827a65d33d48d28408b7e26c4fc885ff6856c224c334612f51eb0ff45c056fb776bfbcb5a5e0d4fbca4fa046e0d1f7d4ecd29d281a3493c7dd24421ace52a4abfee7100676437ab565794a5ce713a6e92044937dd3dcfa39782b689b004173414bcf67b722146e3390c334ae26d699014a7362040930b9350702cde3265ca77ee9798f2bd9f696555476205dcf8533a8faebb0c04c90554cde7529e232e56cce0724147497729e8363d28aba4e9bc5d96189c52ed2cde3f4b0542177a9a7e6ea9c3072027a303d832cdfb61079f849d2351fd71a46b7e7c75f6b8caa93ba0eb9dbf76f1b96bd3383f60d90bd039fbe7fcb6f8c0cc4c5ae35e1f7b2e4cd3b35cc9ccf9cb96ca4788a33fafb1a45b95620f1686ecce9301f9de7126a8b03782e8f356d7e2df1a1ecf5aebe45d740f6b79cdb565e8e64a10284fbb2e41d958945a585791227e83b6f1161f62f0e049c9d702fcec3cecafa074aee256d07e04b196e376905cb474ded3191330a2c5d3ceca6a1eefd05729d294edac1fbdeb367b326d970596357f5b21ea5c0838334da66fef77ae6be61bf37def4846efed2f4abf51bfa498c65ed13e87c4ef3efd806c00916c66f00c08f87d907ebcc1f6eee6b9424ff8ed9334f3692387bd3a1ca22b1b0bb8c1f9af5113bf22a90bfa69021195b4f729dfb82ab856060ce321270af04dfa71619067c08a9a18f28dfcf10a9ccdc783beff6d801eaf741589f579bca49e030a5d3ee9ae809c7f0a76408eee03df83c998fa517d05322df3235a7cd6f739e16ab52687f02e83e06a4d1c1ff75a00e7a901303bbe751375137c7752560c48960cde80b3aa3492f295c9fc0b4dc98451f9650047cb54195b2c72166c33a1dffb185427e46d9e10cfe675341b8e36f9eefc29a792688211de6d6e10765435a801eacd3fc4684edf4d08ce9a38998ed3ba8669caa0376314143c08d8f682c66d464e54ea26b232caa6b1f71db09197e558c2b4b076fce8ad7e3104a3e37164c38119939616c4e400ebfcd75e0667a39aad2bb67fed0590301278eb95f285640c00706f503fa3aa3fde4c6ee4e487c7869122433fe3e12a58deb7fcaafc621ff22149314114d22466dd3f3a18ea38dc955392a140dcbe0a41cb0c07343589debe9717ebb61879450d9f6bcb5193bdbbf829ce737b3e2f77182fc5336d91a32c89bfb0f7313ef582c023353794461b6c0c599ca23e8b92624f53f9f5207c8208ff1af3e2d2e0d69754033fcc734ed20258fdad9241d76dfb498de17e8f4b19840dec658d354dc90379fc6f4b7f7053cb777879c5952c7763f2bd844f51cec05d1a8d8ff99048e42c71850316c7a14c23b265b7d0424db4bfb0304a0ae25244930886f36b304a66d68dfdd2421a4e566f4dbd4aa151b9a432d511ef1f08ab4f879b5e09217dcebc5fa6b188796e0c121eb6379145d07d2a4ec54318b515e5854f4423eeeec39a4685b754fbab2139816a0123d5cd22bd2dfeb0369060903937d0d6c0e5a9d169899f8c4b261aea3bbbac96f5e10f063dd9f2e245dea01d6eae6482d43c570e65fc53c3b7b42290e31cf30f8f520069d2ba0b146b5cb28dce0b514668a16f7dce4c24e6895b776e483a85f6f72b9183e9ea9974abb080f7fc2c19ee77fbd3936eaeccec1bacde75df40af69a71344d579ad8a84d14e8c00f8d832a7beb24672030fc2cb4b26e21a191604b398e6bfcfa33d471f240ceb27316017b31cc4394b25ad471e24eca4c394858b450d0d5ead804d9d8e50d2a3089c2fa751eea7d9157bc110098dfb1b9ff8e3084d0990a9baae0f28e87354ea0e4ccb10144926b8bf4ff0baa6768300af34900c8f3b782c76c22e4f64b1cd5a79c94c8b9a4c79873c6ee11f2c4e666debbff5acbc34b8d121ec2c363a1614cf3631f4ce2efbaa094446650a428fe5f6272b8256cb2fb2a36ebd612d34844eeddc5fe4815739bd72330a71640f62080cc08faa9c6886edcfe68971e7acdfd26074943b77dfb7b08c9ea5ffe3e1e147b7481770228dfbb042dc3cb995a29c773da4b7965c29caf050ffc4065017f92b0f4a72d6fc0cc7f2255806d7ce6f7390f93526709b23972a57aa569f635bb8ad1bfce84abc5b9001c8c30eedecbaba9b2fa034e07005297fd1377445a66cd93a31a2caa068073eabdb32461a9e3cad949bb15ddde5d8025bef1ccde57ba0671eb284db6dc3e6866007483a2c87ea286d610860bd42e335678d22b01f8cd451e110a5708cd3fbfa2d0608ee647fcf75a607b851ab7a735107ebc8c7ee739a50033612a34f0f183ce7e1ad4fe7a13e236ee5fdcc7273a32c44cdd70bfd80d697c241583275c28f6f3f001f9be8a7ff3a68c01ef29e7333fb1ae435a1bb4d7daaf570ecc7521a28d21c2bcfda89e9c630f2fcb8dbdec4eb120d814ab4cdada240d252303a2adda42b927ef64b1bfc1a71c6c89bab1b1b770b13ccde68d867b09b4916a30b04ec96fcedd8c5ce3fb8a51f7f3527cdb6eb96c9b0c43f51968656c18b5bad57b2debbad2ed732eb704087a3b830b798d0ce480807b6e00a5e9b35d76ec55bf2d9b985eb2d37d9f72dec506f95ceb5d0cc38a25a258c86b735fe3759e1ef1c22189295f53a610dba88238259e30a213d4306d93ba8131c03ee6cd51f58b8c14218ea0ac9f6d161ad936471d1f20c3be10587a34443570541b9b010dd04592d5ca196e10d46611e37caa3e841372f03b9452dd3e31fdeea79cd1b1d47b67041fc450dd99355144dd46cdada8ce484a0fb1c3e69f97ed7664be60a8a854d7fb381ba20bbadb2cfa7e19c28b022ec02e4d673fe1e00c0abd7c53d5fc9d8fa86ba56406ed8428a8590ae2a96cc6841cc1718b9cad47a5f190dbfe1fc0125198151e99d955b065833bd68650e86d951b141b28c08851a23ccf2898f88a09a0d4d03995de5e97a0ebdc5ab0ba8ba1102967924b10a78a977919a3cef5511d88eeea965a68fad121fe764ae223c6c7bbf7080493fa00d9f86c36a617b82d5e0630e249c403bb99134649a74f495e66bbc9955a7a27146e751283c73167f5c8c9061d06fcbe1d276a1958157f1b7af1363764516ae090c2f42d65c0d79888163094bce8e88145f23c987c944169623dc8ba86f10ffd053a4f969dd33dc4f12454bcd1d8080e54260499db40c4d04545d119f989a40fddf7a65d3527227901d4a24da809aad9c6a20f17014c6ac92c942b9c700e494253f12175a9e2e44eb5a836699efed6a3ed9a07cdcd2cf037545a4806853016bdc27c4916cdd7be912242328954bba8f909259e4267f4030037659e05085e6d996620e5782c7a4e663e635afcee0487668040ba91fc8ae19d8469110fea340a8a7a01df41dd594e3dbf008c1e8fc54b3e27ae0d5d3b035c1e9a7b4d5a9632fe153a3829ee267e3169f519dd60f0e259ec59b2c2f7d0b5292b726d4ed0e962da5b257f33f18d49adcfea068d1fcb6ad79011ba9fae0d0e3d839c1f2d7d4c1b97327e483a3a2ef7907c356cf5096c61f8ec2df152bac8f7e0d0c4b17bc8e589b5a7696301cb4f71a793ca5ec2af86063fc1cd8c2f3ea51e4b173c4e643aca2ec76ce9869b6eb639a44dcb6cfe62d372cd1b6b1aace612355dc55fa9ade9216414422fd5d678123822e17715353c0c1b91f885ba7a9e068f22f44e754dcf01a3117babbacea3b09109beaba8e759e8c844afd4d5f6303c02b1776a6b7b0a1a8df04bf51a9e858d4af84d553d8f0347137827ba895c69c6114250911ec29ca91ba464ca2f3418f6fbeef0f9e9b1b679a670a9afdd966218a02c9f9c08e9d8b17caf03f7d8a6482ae9eb154831d357681805ed777cbf03ee1d8aab64e93a2bebc02029955b3c7bfa7711b803380ecdc3b3cf1b5131cde100cccac7454a9f6e0301c5cac9ee63c8d06c6cd2078f21cd44ee1ba2168c3b2989ed2959d40c49d06b1e488703e84084a918fe181e6a84e4160cde5c3a18fedf9331dcf2e6cfc832720f7f672fab0ecf6304b5b3b224b7a517a0702dce6a09530cf3fd4f282a5b50842b71a45babf81b31467ae62373883649b0534a8cdc625b4348857076190aa38d14b82f5ee68fc741a361f7293ab56d9bffc7b2a9e3feb20577554e4e50417cc5d57727bdd73831473628289d9ace1148c29a67cabe3bc8514f1a40d21713036db8a05cb78ce399216b7067b55e15d698c2d36a5b0825b673ffd78ccd0aa1ca3433eef47d06d1ab4132734f6cf2ba11c783e7f75047763dea67e92d09396f66750eda688ae26ada64ddd02f19efec8dda4ecd05c1eb9f8535acb46e271e0c75e8351ab4906a3d35c3b1907a288b52a9b08744b7c16402938f669e95c0fe2631f2f2cc11caff01824213a695a6d215c221e9e89e93409d38eb2394dbf179597e48e7ceca4d0210fef76b36dbef2413b71cf430443bab29808bb97330880db7fefca0a333e19f4d857f842d5707a201d1754d4bf0e678a1ab57cbda0f8c9a6b7a9934695fe8f7b770c2eeab3f7341c46b914bfc43cbc5e362192a581b175586e3a29564df5959fdaffe044685896489e5a103edfcacabbabd4b304d551f70ee1965c4862e59d09c43756f0e0e99038fbe66d5debda60b344ac4450899e546059a7e6cf5f214ce1f8c4858baef651648185b1f93998526d14194a8e99e92ae80d45a9db24a2cc871cae5f45011b9fc01289e468b533f0779db6830fe83349c55a829b12800e9b46573c84d8ecbf5ee3ed7fd64b07622824a96e51caa3a4e01fa979455191e0d75a3494390a6f4bfe1dde47817551abbef31f587c96551b71d7307ecab4487c5e461b8a027a582139ac821ac303d40cd9fffcf1f8b2446a08b07b0e6c8f8e061ca5800fe6e058a1fc8b4e6183aab3be87a12fdd93498855c2f8a3746b7f6989dec4c0ed433ae02de0810d4d136df9638bcdcebf7d872de248b262322e06d64b5a7797bf9b38a8e249c2bc2976801f52a8d46feff8455751888ddb4098355fc18f7fd883d2ecdf10b7322c44d8ad3fd0b339251ae4ac3f021001b00c710a48db83bd32d55b9b998de7c2fa87ac93c99bb93879fb078282a82c89478072ac70813c53946fce73cff8378f6669a80236f161cf74cb507b9a29509167247a60f314fa44cba4c0c8514729919854042c14c277ec0614a5f437eb00d52d999b56a3dff72690e72b21402732eed4911092a024ee1793547ab0eb3d5b54e033587f729ec2688d1702f157cf8bb844378fe0ac3f261ca1eee5c65f3ccbafada603065cf7daf35f9e092a12195d771f49e80553c3131dbed6ce3432189eaff451dfcc71973c6f002f987f9ca10744af5d6bc43a28f1cac3050c845d9a9c0ed271781cb299604f3c5a8595c8622de59d2cc165530e8739f51df3fd815563b254ce91888b70f8f73e124751821114661c8ddb50a46be157d39ab764c4b15134ebd5e8a432588392043c3189447a2b0ccc1c4d74c5a74e1fc888fea255be9ce2857c8381555a16da5902934af36ad58de9334d17b529d6c7b23ff3f149b8c97f65ea4138cf77d78ec8b2f7e6eb1e280aecd9d30e923575de827f1909baf3f2c70857f1a8bb4c7fb35964eddd5c695bb64bb58888311835bedb47da5dc4ff515a18e7c970ba780c473c65473640e1f3e9032ed9c875c7836d15b46107c3362fac3e0b4a31d3621191ddf6b73b2f963362cbd7a67b8e687001ab34c55bd55d9e752cf1b86e8eba61a52b5bc30e8be19c3e58b9cd48c98e5fef2a639b6d947c40875f6a4acbb903c3af4e4ba8037e58e15ae31a0c26c2e87e5846076099812ed65292be56f97a988e4cb5c10fda2ad873fbd7acfca3475ae9509cd2140ceca897458cecb1f91d24a461f54bdcdf1b425a95df79f9b71280f0985f2ed1f726cbefa916f454793374f0fd3113339252071311bb436e6cf26b864b7e9e6ccfe7e84fbbdcaeffc89abbc64c4ba75a063de028752b092eb96a03642f933b742c43c5e783c2776cb26e0b0c101c624c3759c9ef05c3ce06878d415b6cc8148238f72e9e50ead0c09dd2eb50db7d68d1d9adf23ca83dd3d6bfd51c3e28c9db8344b28d098689d1bfe44bab94f3d566bfea0509010193ad62805eaef6e00988f00f28dcebd07f678101807824f8b55ae3b2e366b1a685836dadd41fa3e97e62c9d79804070ff9acbff366792a5c4f2ec7f3b24f3f3bf95021b0bb492a6061fb47827046f37097823750c9b77d8a92df4c3477dc6aa99a4a79ac2859ab165d7555aba7229a977a853f17b90eb196143cec4cc61c1d312f24c303502d1aa8970c3bf7f88bc8130dc028d8b58b338b1cbe0229ffd308416f676aec9b429443afad1c4440f092aa3eac920ae3542213264238f4a93182e35b9c2d7c9574812c6ab934ea13a3090339266f6a3c401165d4627fe56c8b6c4577c7a49bcc7608b9084dcd7025b45949bed19991c8441c1b81ba0e65f842fb721710dff1369e144eb3fa7dfaf44d6d22ba6cc774e1949ae065031f86688f19f48b33bfd4346f60f50e4b4c734909f3789f02aa60879bcadb32be2b3e83c28daad90077158ffbe79e8caddf7b627792c1cb74b21e39a41b4b015ad774d9861db09e48f519aaa6ad3dbbb7ed54c34b4297e1727433f385bb7e46bd9510dcc3fad3d56d249e0b62eec47ab02c1ef9a373ab57c0855b0092728a469fa1da0e817043244261eb85c7bbb04f0d3b22f6992c2779b19a5b750a7724f03321eae55faadbb4c818284922854da6d6cfd4368311dfac42006f58b66e39a064322708ddd1da9e5f82ac9480775cb1e16ca37372b33c2931a7b1d3d18de1237aef6a71d13f28b872e6ef50c99248fa57dfd2a7bc7040c941e0ee428effda06d36f52b54550326d67d71fad726c3aaa726e92e4ed5cac8e9d797aab19a259ed415c2ddadc463f55eef98f2728bfe24726ee179edd1727f2bac6f3a274663835ac2497d1e42211ae8c90044f350a4bf97355a8be49bfbcdcb38229cc26850fc297f991b924d3df5b8115ca3be2220187780a1a9ccacad0af65efeee5433108360bdae2458e9093a8ffa8b0896760f02b7c4c4d6dd1acf43aee5c26f3056a43cfb56d4981388f2d3ab47b8518df5f7a55265f283daa7304474bb3de1a6265d7ea7e3bddcbe07b84f1e31cb3aa9c32c126829e137c6aab0f6f658634719a2e96a5f438891f78cd6afab39212059f23b0bb15c722177a04bc1339b89a41fc1503d27bf7bccf1fe7db41fef7364f98386ac6d4e0f1d63d93923c9f585da88ab7eca1dbc954a52b5fd564ce28c4d7bc3a7486dac979d6bcb9a97a35a3b47add727f443498cb8998a6923e6dc78f3face0f09c4e819916cadc8b9bc5812e13fbd161897167ac7f85d1334f683eed2fc2e731fe4b71c377b63ac8abb4f33a541c4098faab7a4773abda227f65cf8fd10d57d295413629ea9008357742206b28d4c6100a6c1450072ac52766d580d16c253e16e57e4418490f5559039d92108d053d86d231e92910185de0c6522db9393fdfd62aee0a5973371ba7637e44f741a722ab53813b428dd7f2372e62ec9523dea8765624ea65e698c45bd8a0abad8a669d191f5737aa6409f96eef7d7f95b3250e5ef745f04f8f44a4fdfcb9e0cdda5ca1d4c9e23cb372b07f808b422f274235410d0c5c25a03adba156f18e722edbc5b26ef4988ce90ae4f965cc195ba0e32dcfd3e9855ee03136ad8f7fb25dc48aceda482787c5bc1cbc2e314a8d72b042e571aca7d4bfd04979ead16098420047db8e32394aa6754c56c47d0a549967cdcea5af1c46c35169ee121436724f976b4ec83dd3fd8c237b5a7e91024652c4e4cf1a2fae336f5bc5276cc6a350bf0cdf0fae07c5102f85f3dcf0dd6d312143eda9aa5ee49a960a53af4d34dab428b918f0eeecea0edcf452216ccc44613400d6c22cea339d49639321d67416aabae6734db0a0ba0438b7e391340602491e1f541b01afe6c35a00177ef898d5f8c703085e346e05df4406896f18cade50852fc130eeed0589dc9eca9671c136172332e07241842be47aeee33daf3754017338c7518f75b7373981e99c78aeb353059af6b030e4c607a31f86c88bbf0133cdd0b42086d0076cee68985c74fec1d93359fc3252189f9c34c9630d04867afbf6e846e389ba3fdb6377d6243eb995bbee3f09de1a406021606f1306caa852734f18795adbfcd7a9e2355f3093966ac0718b812c105f0d0eb987caed73ea55e035c11d37ef2c48f09c840c359c294e82a0808089cfbeef400d87bbcfaf433769af38fc19d1eb7ab439c15a9afb4e3becdcc861ee5b9475a458027f1a17da5fb17eac2d66708f237c758c47d5edcea2170b9e4f74cad5a8f6eafd93eb61e0a81349f15cfe8f10b1f42c873baefb0726a09818e53079c6f27e63117c20c2ab06ea1795f2df802eaeb3b1536d3cfb7397a963ae1d71e127fcfb5b6fb3ba2ca12a840a492032de8cd698b21534fd50dea84fb812afe95008914112d29f278b9fe7cb83044de9a358144cae3537c00ce605d1429e9bef7ba3b2229c2ccd59e5173e9b620eaf603bf661ed45dab2d7e6825af00e910a8a3990b22e73b94c12807ca0716b5de89d4402712f666a846a3aff3ad01628f522d7815178115ed2d1035a8d4f702fa4ca0d3253e4f2426e8b4e8f703259ab51e60347e5ff746f06f42eb51474b4d6bc93ea6d4064d046682961bc3932a0e47d8159762addd97fd1ac06c08e5c2bf594db641e9061860f14a02ec1e5d35154ce49d9197488004ee354ef3d0c8f092a19dd7cad02fd0ca7f33cdec684972a339ba694010b14ddc1ffd5f7717d298daacde5de4bc4c006fe878d531d78d696b90a14599c10978036ab1648cbcde6911a78dfa0e4dfdbab8dcdae56fca06f556dd75b3b2be043ef855595f20b09618e206be2a4987cdd34be7fedcd9411db2506d83eee0b9b7b5b43ff19459027b899f7ca6a3b4a1dc08f78e8a897111acc455f8281f80f296e82b8650ec1e2d625f43c0143ae40c15f8bd3c9eb063dcfdaec189b21f95c6f1f0bac31a5c49704205c7795bda28396fa7baee3579232262a1214facc07b5698bbadd447a7c714dd82bc863754672afe722683ac8e0fc7a95babb2c288e8ac45d61f53707f13f3ae3812102b0fb7c11879871d6a8310c0470a34febea19c72e12fa2f2accbee2dce7da5c05810064800d3900a2ee3810b62758a43f8b91df5fed942413f5e6e231a733b254cbc8ef2b96623f75a0c52d5b54d6733df6f14f0abd374f75a7d8adf810b77f7805067d472130fb921a70dc504409300b4aa0eea154392c503b6721b56147a4ca6f234bcc2376be27cfb09fa27721f58878d66ac2231e36114baa0506da92412f3a8c5f8f4549a8a99f2ef3245c316868660645bfc578285766392577244f2c4d7735d37e1bb6e879b3183cefdd047b1ad25aed046b80f2eb7f8d01a2070004758501ca245c3c1361dd166f6b255d7218720e4aa7793293946d17106641b15feeec1dd108c5ff616352306ac4e82f6463eeb81d14ef50eaad9e4941176ee900ae50170a0b6c54d4a7fbab1b42c5af16b8316864ebccac868063a4dc27d83c3c36a4274d45ba2fdb9eeafea711421fb1440c8a63429c5c255f56db7e58a33893f91f3fd9cd2664fd413aab7b948f3910c2ea2c7991481a5763b700316508342db76f8bef3d24116674c721ba6f6c9b9aea7d71b82927b9a137a7969ea5ff70ac10bb5f302114c36fd50e96ee5049ef42b879825d73df1035a93b1e179c288060b26878101725c1094852e7dae06db36ce0f805ffaad192916ab077f6ad6c443c82db1f7501338e43aa7733b061dc739c970cf1145d32030781cba955999049613489acb3536ef03dd5a90179e8ef78e23161e779c175bbecafbb2ee627a77ad512c00ec668eed1fe6092156c404dc78823c5d62460a7c01f16f25e3094e59f511a017694b95e2294740dfd9603005d16b120c6160950b3d6a90f4110b7b1ba949991ae56741935771b024a8397ab3e9c23e8d77618670273fa99666b6d3d851ab3223782685de7aa3c617a92ada5a9dc98d10b78a7969cffb0961ead3b3eb0ed5ad2600a19965c568d55643e0d35759e1ed21d152a44cbf0c569fd6cc9f9ca5a2f81866318e40aaab5124ef7caeca3fe7f7df413736e4d96d8b0c1f4c654e4239c2c9906b47ac868671c39fdbec5292fe9b7c90234001983527fe752798d311efb6fa769fffd3355c37344a98826f3e9c4d6fd57a09e750f2478e022885b48cd300059c67f60eb297b2ca49088f2714398cbbbe106c64de7dd7fb7c1bfb032ad3303b16991e7b6c30aa890923ae3081f172e5de0644fe4c528728cc94b90b90550644943ea34e9e7c78c3a888240da26524dc5f67fc460242f4f79ca10bfc0d9222bc58b528fecd19cf09e48f364484cf837592eb3c8fe2443c1ed2c80bdff153737efef0f6a0f8f684ff5212faaee3f0a3dd2ea8e8bfa80f36d70bf9ce786bef909a2d94c37c47fdddd0e3bf32c4e92f85dc3607b39c4fe8b76e7b72527f6928ef0139f9f8404b283fe55dacf40b6f192a5e1ecec1e672c2cd2f7fa932452c46743a5672a1bba62af3c1a892d8b2363cf2719965f7d0106c8694421e5cfe4dae0f294f71d02230e80eb3aebf84ac8a7da52433ea05e66774efd602a0e5c4d804bbd7d776f485f176331931efb1bad80f6aee3c6b4277a8ba9f4f1cc7da4148a7f826e876301c4e927a8644e32843e70e7560bcdd29e24cf3eca24499bb71da440ccc831288db73b8fa73f33956a0eb3228e77024f772fbd227f8c818e8ee0a1cb05ee37ab3f37e002881fc7799d1995221cd4dceae4e10df738ea815040c10f16a116362065cb159e1cd019f8f3d12c717c3db15f4f0667929d4c4e97fdac5036f9ee3101752792fc00e6ff1f391663cb881878e7cf0eac818ce4bde908439431962c79bf3c3c9fd018ce55c63e7d0254619b3028f27e49cd3285eff08f2086c85b18974646c3967e0d32588801383f9510a0d7d89a46e138bb501a03ea8be809a013128190082e256e9330ef90381c60161bec78efe7b8da1c62c8c7fb250bd71988e9cfb28600a48ccfc80c33839a4832f3b8c330ecf3da44861b6a3a37468ec1116fd800d06ac8758dfd7c5b4aa5170869386e06c68eeb86cc45358ee8ea798a873efe05310a3f2b470a0eb544b6e26cc831fe11eb3de2067dbe212d686868a328367b8eaccbd24aeb4e5d45deb5f3f36107db7da07fa4f1cc030930b9c0922f72f339b897c505a3efb284066a74b6c3e6f45c5cf88eb87a0ddf31fa1b8e36926aaec98ddec110c764cef07c715b216a48d9a61e41103d7de33542201ad6299d7c53a19ebfabcf5d45d85e73e089b2bf493504de334324160b4c012224ce77a3c5e394aea91d00a1d7bccc4a9be8923e3d7568e994d04fc5b876e1b60251d931ae44cfa28d374f1ee1f3fd4dc2a0e95314465980bb1151d6bd3cb26715018915c022a853dd11ef5dd9db953eb6f9480aa3458f1effb3661eed29d9b24fcf9baa19398fd9fbb07e3717e5e17432161fb278d0a8d464c5eca1e1310efaf420a9769cb819470976946edd6cca63e2b38a7a4ea06c63be22e45227cb3075efa6fdc24f62ca7425d8c0d2191ffb0f30ddf3ecacf97d472bfb2be7dd47f20ccc90387fef311d8153a79e32daf8b2684913137e777f64dcfbcdb91cd136071c50e714511a3efd3e731aed09456fa13fa9961dc093d722527c6f61cfc59c0a665079b08f34bb1edc3ba1d91041682cbbe4656d408c9843150bbc04e34fd7ccee36e4f8b80dc7cd5e5510187db841d80677a023155ec042b9464933aa804eb93b580cfca62890b368425bad0104a64f73cdac6b07c6d00c36bd919cbf743fd0e42a91af98743512352313b0d275cdc8bda81b44ca5724c4f7f6e19e63c3feae7d8ed9d1530eeab32ff1f041fa96ddecd7118d3bfaf5e8aafc3545a7e627a968d528b1281f2152f0c1687bf9e56ca7e23d77b11bfa113e69c3f2997a6eec1aa5812b90698c6cc7f00c8057982bc51115379d22d4085f10465b03747d0b9b0b47b834a580f4ba97dcdd22a2c1a3017150d32204275117fd7e2c75ed356923292ea34386d5fdec8edf89c19116c31d560006a1493847f22119c66085bdced7c85fc9b604e955d6fb9d99828cab25ad723088a71d1f64e064bb0837dec016b1e9028c997013e27ad4a3cdfb872ec387175b4f0c62cd651a396078d9d8b5d9d873600928e7d75aaa462f23bb546376090701801d6a7a3c4c1c1a7b76a6240914658d661b1c293925327e0bd10d5666532a47fbf599e65ca86943319e740dfb503599149581d0f0d19548aca10561a3ccba8ea6722e260eae1ca79e4fd398f8424e6464a912c270c836fba4ed438cddefbe23c92e272996d0521273036272fd5f21a2c3c1bf32170d94096aae6dbf7d0003f039fcc0b8e7cfe104066b71693e4057d366954f5134abd0b48c25ffd36dfee0601b72d921d0915892222a4ead1bd63c605c790f414259ec9ea7ee883c83579358134563511a0e570e95b97046f8df4bb002d9092e1f4d703516dcde7084a3cdcdc3d4345470549eb8e72ae9046b3d30c3ea471d915bb9f673fd1a7bc23b09f9e2c1080047a3c306e20bbd2a7314e4a38fc8cb393cbdb824d4a7e411525c230c9abdc2d7ca6ca73b216a554148c0ae5445424b84971bad083322997fb0da8fc29bca9dd20c8f642ef825a7de880248bfe94e960803381e0cde36dc5a71fd9b053f6c8d7a19e54ab327104658a430b018426344f1dddb23f8fe64d60031ce0cf4a1019d2907cfb3d4198c207a9af60bba635aa4caec049fba537dafc2c098410761f1a0fec9165dd119e9f6d96f3ae6b3eee46daa66d7995f7f7213ac826966c33aaf261c73b20a40b91d0517bb9afc1fc6a3a74faceef666a4074aaee104c135c7f45a44083c0d35fd13c7a2842dd37389a069454793eb79b5823a25202a9a8bacfd1e6d5cd1d71a7fd61775b426d1b0c17ac6d0730b8107c248edb807bde1000419cbf75348140c26b8dc31693765e35cc251599510cba8c5415ca9deb3d5d4c512d4b2c18d7eb1dbcd790ef68f716675703bc785a395971d77c3a5bf81d804c36d7bcfc5eb372127b30c90a6b38edbae78a3f53322d55aadfd0f837e849f90b2ec8eda5ee519b8be19a1aaaecfd1e98c635a0d5038bd234c58eb10b3ee5ce23123f8454c586bc1f19b2121f30e3bf15932d6068bb52cc0691f24bbedb566ba458cc5b95ffd4187edaa63d8b1667085e06d4a5d22e3a5cfa2c162586d05a63620a8b080e8eb61243c0d771a80e17cdba05f39a81359ee619f6f3cd42ed566b087c1c1a11a02871a1324e47680c8e59ae17705ad5b1ecf505c191d3561877317f7b44d255ae952e81f6bcc0e59e0c401ec738ac01a159d42dfc7066b0de86951e2b77317719c3d88177bda7ac7159a65c62742ff582e91664d130352e48ef13c927fefdece2c41192bda9173887749e2ee26efb68d69213a3bdbbc87eafb47fa723d806d6b45333ce1a2348cf566a6d975e9d52c664ad93c4b050325f868a364fd2e8c89f0db9a3347c7c53b4edaa71268e70a28caa492ae34ec4d9570454b596592de9641d3f7b624b0f45dddde2222dfe8485d22ebbd65583c17211246951fd3f809f1f9a3ff0acf1e7fb9ea6b759e7ea31bcde103afd35f290e48b944c380a4dd3ef669aa49c98a2f01629c1b2919427345e27fc0b29b36f24c7212208fbe36c531e73bf2313ad5544a76e1812adb662ff95486a6e73d8e02f5bd52bbca26ef0b499ee09c8d7741a1fd0b92865e27e73dd4f8bcc541b1d6e9ce821dbd8e1cf2c47e31d4fc81df97a3df7268f4bad1f56db0509190359f71c7fe70ee313d49be16f6976ca636d801a52c9a1288a5d7fae906e29460ccd6d86b196a65c5cf1c6356870a897ba030ff73fa03688bcff69c1fa04393ca81ba3263b117a99a84ddfef97b0023ab0fa7d928b5dadd813dadf27087691897a9edf70740f81d881e306f118f9b9fa445f7d108954e9b39df5e5630128d7be14805b8f5c817a2be64484bb12f07f08b1c7cd06557959a4b7b12063b6b0b5647c1964aa074a86ca043c5d20f1a272bde11fd475ff133ab2c3e561fb69f2a38322ba33a150ea6fff6efe2e80d51754946e5abcd4a17da47a2e026046d578268862e78b5891fa442ac16a2081f232631e00227acabb25e9630159d7b16e613d5f86d1827f9d195e6fd7b883de7f388efcfc60b3ece61873acf55bd35a5154df1067f367f8b553d8cc8a34be71431a571abe6499629721625f72def0423920baa11fc414a6a0a60668e5e90f0a37fbb33635c7e4613ea9da64a8598448b464727c549e4665069c6354f33bdb8857c1721c78834313b1a79e2609c57ec3b80b90827fdf66be60b7a42fe56bbb94e486cfc3c1f437029ee582864b5b713d5493d2f326fbc595d38e523bd9dd412adbc27bdd8c05631188242261c01b3adddbd7d9400d5fa3e6fe6287b0c6ea7ebaf72a70b29d18ceab746d200b1ba8ec6669f6c12669c240e70372d8339743859fe111c5d2fb710ec8f934d15e14c909030fc719ae936bcb71df5970e805e3097fa2bae76cd4878edc6a0f62d1df707190892e330b9688b82e5964b469c2330b30f1243229591c64553f5c35b91aa33f694eb44cd370f13a3368e92954d04a0c3811da854cbd88f580f0be567d37e35292919e197b0df2497af534ab9dbd24150732e7a6797290d7d82b6f700c4053bf62ab7963c19329cbaa398ba0c63367cf3b88ef06b30214ec3b5a77b1de8d858330b58c6e5e6549a9200d252bf092e38c252b918b7d30eb96a727ffa6c503cfcabcedf12c4150b3b74c9da6f2faa908490d73815bdc31d2102f6241ff1f8071bf237ad2de32d775d0937147c5b8e4db2277743728af110b8e198a18d347edbba689dec3b9c4ad7415d1336d672d7d57b2ed2686bf73e45958e31c85780b853b2c35f156102b219bb72f91b253ff69405fd51da95c45c00a15fcc512779ab51f6606b33f895467449ab5bcd4987f54d7b94f320b056eab033cc912f2b72e8ec588b9a69433cd6378d39cceee621d5e9e65b6674db1998b7808c3cf7e7184c84a232d0a2bb2fbcad0b69a5155c4983057a34bf802e7162cafecd5501a4aa699bef00c1427102362a8ee0c939405437052eb7795d6ab6afe7028aec2a30fdba416552a6707aacb7170f34a704e472407cc21c99b3910df1e83e901f143a2cb403010532b56578dc00a89670cd9fe0b32947cb546dcd472f35ee47153379b2d6d1afb0dab18901a51ab339a1547bf0bd6e7a8f453b0773335b20ddcc30450c38d856b29546c784195e017bbb6ebd2f18fb980f95cb2e17f34427923b66f8eac1c0a5e00628e4f0e6ceaf7f2223133c751626e0cad48b1ebbd40a9d3f8451a6286c2484d96312d33c9c663f96ec3bc7d7a4b874b3a6114493d07447e55465f87a686d76414c9f8d41fca0110b8f41a67488a849df41a09a2870190032e6beda58ed15b395f94b5eb991b750453ca8fe1ac1c45d8d762c1af8399df75c9eaa13ed143ae5fa1d50720dbef1e25249f13f9df9355e3f7b7f01c80145469a51dce75cadb9b971beb1f7cb8b4bfdfe93d8f4d000e773dd876dc3f21f83ac0694dcc7d3415804ae94ee2974ee5030ef561611cea9e37af168c2d5cc82a5ddbcacafd8414eed8424e1db5bb90130706e3a66979f7487431ccd5d77dcfddc9973c9f4914bc1a69a00e89d42b42cffcb51c5b0dfa7544f3076912f0c86694cf3f9ddd9d9a2dba554e3a0dba44d7ce7adcbb544155e9b4755d63ba3a9a15e231ea305b8f9f8e96b737dd5d54202409e9fb9078c462f6264ece361a9100cda0a13b30a2ebb3678113e69b658dc0dac79d1775edf30ed69459652c508cbfe026694699caafe0be51f9258a294506d5a87f4a6a0e7b92dfc1cd7c588971fe782c896e8574b8a08d873384581d40d46ce9b2f60042788cb456813c5492396e0ddecae8c3082a661baf294b357372b5e9a2a598e248f68d28868d479f22c65cb7beab16e5cc7dc0f862bf332c582639b2e0e7220d2292710e8834e88066c56c97a5aad6d6eeb052a217ea88203a01d501bfa1d2508f6641783d99cb3050470fb18a2e3578684d8dcd87b85b17f67e6d6ea4540b40895686107cb4ce002aedb8f8d4c973525f032f98d9c982254bb6ad5e736987e45e351d934785faf8bf4aab7613ecb62b9afb418e4cee10f02025870f4074d205ecd2525c82cd35990cf449e342c82295ab8629dee5af22aba75085a2489096754bb4816a3f1d9432a5ad13a4dd391c3e23e499521c4b8195b70c7176ad7ecd9c583aae92cee1f829af01fb2217fd7eef27e64d8e99818164b80375ced2c3ed0fffba81703610afe19034cb4131074e3db8752672c2cab30468bf1427817623dc7071d01eb47bd2164051828ff43a77f5714a2c4d352757fd4939057bc8c035c51986116857f914bcaea17b378cdae49032c5702927370d8bc3599bdc931e397a88c3f3df5cb95ee34d52891c3af724f7be0de3219b189860a0898122d5f7eab63258a0d221feeafedd7bab567c0978141fb340c0d4c34ae803564d95c7c2cdadc6cd336c0f72fcc303e813d4a08252312a9db9bb90606c139608ba8a135cbddab032710a7cf22066fd6cce4f502c4e15766e446ccbfdcd7d251f64c8a559a21aa4473458fd25fb93a0302cf94d205af18d0c780f3a6dbc993e0b023ce889cea9971532a2020ba1d38c6990f1920360bf2f5a29db2c3b8fa0942fe78ac3d5b0f55ff1cf3ed0ecc5a05f147d84712a8a38109581b464024b738ef21217f610922fa399c9d2886135430420a711ca9da665d81ce954bbb3f4b7720100c233c2582cc4001b12b5af189f8980a3c5f85ba9de928918c1a3853e09fd00de8163cef1484e0a97fc82ae7e2fe1b4d4ff8b2e308c20c8d3358eafa7eff2ec5f2ddb6187a9f9cb18b9666d27819ac8f527a24e0916a69dbdbfc0335d29878ccff9bdbe0cc3e30aaa16d48fe5c12002a726609bef45fcf3cc4e1cc7fa57bb37d575b2fb9d6a4a920b346992c9fb3d840f6c3ffb087786288fe2e0168f1fe2040e2c30f54b10dd92aa1968e723d5231aa469e5faf0107d6f5f8ed0dcbd6897774d785e5566b381ecfb99ee9e92dd40a7dcfd958bf02277b2ddc9cc8dcb66c3e7406fed30e2288a68b2dcad8fa7833110bd5f9ccdabd5305ef01009e9f682a4b75f7298dedeb0701de6e23b816823121be786a364dbb354f323637348b56ff0001cc35b6a880e3254d05750c57ce50a77bf9a3150cd7a7ab1a6b591bfd6914baad0d97fe7fddb750cb3a3c43f91163710eb1b229d5b98bb5b2fbe48a368146c181325d16d018a54a8ec7b1f7e82c6ee76355d4ed5db9502805f4482a2c2945887773230d599dd2af2b7cdd24cf5ac719b2a88c2147882455a23f903128f8147533cd9c0ac57e64432557de6f43b34450e2d93372881097f53513374f009071de6ad8e74091e5d8ebbb23aa49f85626e2f5136199c8acd9fc2d29e45677f4d575361aa760f38afbc3b6f46acba5f83f2afa6e1fbbdef2ac707a241700d9e3e5eb7942be4db30ee7befaefa715d413fbdcda29f39b66d4f528ef49c507fc63e2bae63b07485d9a733ec50b3c557f6a6f1e7b21fc6ec3b0a46d704f059e09b77952c69f882af484d1df1f3ab0d61ec0dadc8ff3c9aa5a7549e5bc9a1cc9403268736fb5b880c2ff7441e0d642b1fb7cc1ceb62bbc215118d0035e80fbbd06bdb1e5c807e504721701d413cf90c93fef433d3cfdf90b971ad8ca5602da2a158523553cc8103e451a4d4481e366fb694bee73c512d11b0c1466fd032640c1dcc8ffe367ef10510f6f56cd9ac461af82c84aa9c29ffbaa08772b0834dc7e3c8c94992ccf3d85f9c30eb055897945fe3f8f5c20d075412270200ede7ee04431cffd05a3bd6030c6519b2e9354274183d3bebe84df615bb801f5323b56866fe6724c71389c59ab9c8e5659067289db9309a50b67e00dffdf9491214e75fb039732712c8713509ced0131c0b4a70195ba4c8ec0b283a22c7b0dbf1fc6412ed2c4de82859e6abd3f51180d0d804e499c2ee45002613fb99f968590283d52786289f149ece6461deed0759ac6e676a0a9b298aa163f0e24c96a0a98e0c0852029aa42dfdab437bda93efb23edea1a740ce383cb35d81744fcd9a6be9ef47e2542f680061bbbe4975e70d160ea6f6f4e737178e789e45eade59957130d30e5aae84a40444da2b6f30c458054be0608abc611221c80d3a194cc2d2566904c4acd1ee8382caef84095c2e80f4ddbd836fab2a862108b2adef33ac9471aec7765a995367a901fb3af6b40309937d205777154a7262d31cb03b48f16438a9187b742410d097dcdf4807278fc11c35304fc9fc868ef696323aa5f91aad21ece631fb45dbcca5d43f5c9ff259d530c306e5110677aa345a0c11dfb973ddd11a4c50198f826ee3306febb5c547a17816183f00237edc975b99e3288bedb4c40a9b91b95e65be7e1241ec820eea49089dcd61019cbe44f6869f6be914b33965f82e20c672815c3e932e2bbd637e38034572e01b9c38a9b80a30eb4af10d4152773487211da08141226a60f818a1cab2304ce7f435e03154bb801491fffeccff1f8c0c02236c5a52201e7731cb094fb0061d569e5066e1c28f37f6ddbf859dfa58b4588a93b1213981e291efc2995fe312611349407e3c6c9e27cda85453f72c75f611bb62bd1d664df72a04d9f7c54434f64561a4279373b901dcbdcd9e56a20630d838b2d76ccd5112389233ec95006d87476c9e3ccd6c376f4035fa58e8ab9e1d60959172e6626dce3ff6db707678e462f99579557d2dd4b71b353fe48e9ec7ad04c55576a4971e8b2bba9426f56db399d1d25923a3c71e7c0655904af4139a1aaeef2453ef0d6420becbce48d6e5041e0410423e9742403c92db38e65cdb7dc290c2a92f63380f85ec463a07b28960fc40456909ba96e5d40816b2e1cff8ce8898871de7feb394c739a1520437ebe9694e7119a08d221019cf12846dc58c1451bea34307450277311b01e2898618102670acc8a388819becff18ae7b9e900fe53e894b380a0a6e60a897e910d81229d525a9180029147f02cbb0366ebc698d4d80fd0a18697e69f883d6dac496a5b6ffc42aa9763a417db0a37d9941c116c311e04fdcd96f01b84ed058c7cfbb2a07763927e43b936d3e312eab38e802890736be6303755f5fdd8ac8be41842987d5d9f6d0afd87006448cd51b90ffb430c93e5e0692007b82dba29bc0c138c6ef8343fad430a23146ed6df1bbf1b36df6dd18056e31bf29040782cebda4e26c9ade103a369bf8acc57d07034460f170b6b80a0d90708f9e0d6ddfaf7996944715304ad3e42a5cc88825806eb276aee9df8e20e1b533cfc0b9f9269caf8c0b32d8056057ef670b96af062537027cac8cc8bba92c5a0da4eea4880358eb62bbeb5d76e792e1c586d6837de51e42629d15a493a874c9feb8b7d84ff5864a8fadc03367c980e5d98e6c5bd3383c677e485f0c0c9dc9f49fdf2edff43e8ee514e5000fe2423f1c65e437c4426aecebb0bca3022b6324f219bd824d42c8b981564c802993bf3844ac9703b2d2fe32d6f0d555575df68cf1ac49bb28cc564aeab893942a2acb4810ec39017f7df1fa9f276a25ae59dadc7e298ad6e40b82c1f79e1fbcd49e01de4e754a311f4df428b31bb2aa251bc4fe3cd0be4a23c32b1eaed0c29e930a1161cdaf51e8439452bf928e0a600a4b3048c52c00d1927fbdffcbda35015ba1c93e1331c7612243b4998151df56e69c169678da810eb54cd7b4566dec78d3089be15016fe9bd9e0784c7e94e44039aa2941a77afd746fe51e152fd4963479267a3a1c4299ae0ee2346dc75eb9c3d06210e7b4394370c59cc613e0af1a5f316228fc035ef1027b34b8cef22fe179a3c345799fee6932d953abedf3e53653c76157beed0c142f8a1d8ed079b03be5fb7bc6a60c62cac42e0a905e0193c4a9a74a128772542d53327a93b30e8001efe9abf705c9410bac1d760b56c387476481c1d0df996ee4147c48026e7f455f0d2e70b4940e000c30c000030c30c040701bc4752559a950a60e5ccede00be297353923649d64684c6c584c6c544d897280dfb0c000d05ed5499fcb1d38535a554176aa11e68870b6b94665a4a39d336ce16762063e1289e77485a0bcbf763b06a394a867016f6a0a124ba41ca560c16f6d090524cc4fd87e60a8b98c74dbe98f1038d1536adbe3c9141f0303155d87a6433da870e2467a8b0e583f45929b443be4c618b616258f0c813d3228575f3665075932be31a851da4bfb42133c5e42814f68e8aa1b19369a7e813b654f21bf2857558d4097b4a9bf667724e8b6a135675f0e3d739440a95093bca9cd191ee66ca74095bc8e819c4ce500fa712b634d1247476ce679984451c3df4f0649f538984e53af94dbc494f361e6133ef1053e6ede41434c2de536279e1a25a148bb0aa7fbef88cfb954388b07ee78be915ab264d86b0dee76c469d84b0c8a6e431ea2058fa82b0dc7f8e270f4b293d20ec3874ff7aa63187fe602de99c29a59136c407fb477218728c959ab31eac394ff97ccc5be9613cd8ce2cf5aad442a2b5832dc7a4b75329a399a583e533234bff9841c8930172b0fd4f55e8983efd840c8083e5bc1ae5905421f171b7582d47c621ce655c639c2d164bc761364cc7f25aecddd38f52861ab369b145e98f161be57cc82cf6f848ac742ea31f2f8b75eb51f288561d8d8fc55a53e2d7a1428aecb05852089509e5601ee4bc62739072d347470fbf2b76b019e628c374f5add8bee4f45148f2b164c5e679b36773c4375cc51a3e690c2162e287a862d190d97cfe7399eb54ec91a4bc7388d628d4a8d87e3b83c9b08f297d8ad573778d468d1d6a36c5ea481dd7a50e530f2ec5a6910ea4322d334f8a1d260797d636a35852f22e4e44bbca1851ec69aae1c86842b1a79cead7b1b73e2fa0583c273d7f4a939d2b9fd8734da806a2e7a12b9ed8530e15fdf42af32a9dd8434f07cda9441dad9c5827751fc7910faad14dec2867fcb02ecf63a99a58b3a763ced80f39a29958d671b2f0305486a59858249a477e9834b29397d8c637d287c6a88aa625d61cdd0f5134c334c94a6c15b1751acb623f92124bae7cf995a1e67f9cc412d2776a5487710d94c41a5592f92627843889c45e9f699e515d5e4c0c123b88aae0e7e9d693c41eb1559ee4e0323d4c133147ec99e38ce48a9ebe41ac119b8f748639724a393f63c4f6d9695e9363657eb6882d8e87cd8b8b569f3345ac23b1573967ee5bcf12b167383a13f3731ecd0c119b55eaabd4cb0eb18fa7147975693aa7cc107bd57d946b9c9d725921d61ab5e429555c8a6584d81a555cc9f7d13a5636882de7adcf61bcba246482d8f741b050f952c77a58203689fcb70e33cc3f0d03c416ca3f47fe154ff1ffc3fafb4173e77da4fcfdb04ff0d987d1326bfd3eeca82e4b4394f59fcf871d6c4e0e298a8778fe1e96dbda33e9cc49e1eb618d670f3523cb98f29e873df49283941482e4381e36cf0f8bf92476def81db69493c5d5c6edb0d5a6bb543db9abf13a2c9727258960f137753aec18259f8c7ce28788cf613d9fc69b1646d473e4b0f85ddeff10711c3d71d82e35e2ee79180b1e38ac99127426de7a65e70d5b8cdbf399d9fbd071c376df602d754637d269c39663dc0f590e1dc6cd86cd6a3338ee8c61d45ec3963a1e8349b61a36cba01bb7eb81c5390deb48e78d52c93c9bd1b0683786a9216fa283cfb0f8fa5eb81c331cd99861dbb416222733dfcd9461d57a64319d5694a892618f9bb89624fc9ea56358524d4a8f66f1d24f31ec3f2529634ebb1acf30ec3977c671a25c4828c1b0a7e47e102155731abff044cc5d3ea917d65bbd9c3982e897d885a52c83c88e8f9d4ae4c256b93bc7875e1346dcc2f255617ba2c4ca19a8853dd4c49dd5ca8cf3240bcb967aa43507192b040b6bbc4751663999577285fd73520f19828578c40a6b380a31e2a7d5ff5558cbe2e4763263f4478535c66a2a5c5e68ce4d61f5600ee3b2f23a7d52d853e3c38771738aeaa2b0c69b0ffb413c8dc4a0b06dac987346b292883d61998699a28350966b39618925317743c918aad5843d775d7549c4ea9298b0a39d108337c8891a2d6169904c3a2c342eaa843dc5466fa41c27c624ac9df341485d740c1c85842585c6186a6ed411b6f99fbd14339ea9514658344c741ea4f7638c2ac296d2e15d296e34cf136199b48c3a0f618d31fe31ba861d2c21ec3096c3cb39e37482b0566d74c5ac0fe17820ecd92176e56b3cd73fd82ec64f396348c3a0fb60ad7ea41227e142da83451ea61033720ac08325544d8a0c96a2d95d801d2c1b3fdc4f28a94ebb003ad8318e9956536c0cba2e400e960a1126963bd267740170b0c6e4b43197f76a946fb176c67b96b9f63ac6b6d84c2576a73e5f655c8b653d4ee70c2ff9584c8b1de30a911752a46ef02c96480fd9fcec8cf6228b3df23988c6f7917389c516e3db30733e896481c58e7f27f67e87ba4d5fb139d0941f5f3e134b5db103d3f91424667492b662ef0caf4769a51b0759b1fad4a4b58c1ae7435ac5e2e11beb40a28a6d2e39c83417835f24156b4d458a7ab15b61546c19761e9cf9a71c3dc5969eca27363b5c77a6d8636eea2abba641578a1df959663c8f437c1c29f6f975247b711df2a3d87335c7ca7361cd12c5162b678e21fe61842c14ebda4efe74112c3f0c147b4d9cde7851970efbc4be13e42e478f647979624b0eb3663a74fcae4e2cb97445d3993a2a8b137b9e079b06b1bc6edac45a963c4ffde4a6106962c7f74124a47a5c7c502616bddcbfd21dadf44198582c4f77dca43d870ebac412ac3776f9c3ee14b7c4d2a5e163b2bc128bc967eeaff59bc829b18ccce44d886b933a93582b6e58debb25b185d0919a364e4c3947620da39bf5a71d6c65482c9db1a278ccfe8dfc88b5c43f5d64c6114b839fb0fa7c639569c47a295a44bdb39c7761c496f158c81fd52ee28bd82c34869a8e50b95645ecd1cc37755c7314d6446cd9207cf0d40fe5828865662a4b743ed3cb432cfa71fb61868f9bd210aba7b85f617305b30bb1a6f8a3f59fba4626c4123b2af56fed1a3c883568aac7f315991205b17f657c1a92a8fe858158a3efc983ca30860c882dcae391bf8bd5dc1f765ce791cc42e50e113f6c96e366eee5f4d4207d58fbe1c5f015dabff2619dbc6a3b261e72c6ed61cf30e7b8f126421ca787c5566206b1b63c2c957cc77c754d420c0f7bf8943b6c712cf6c5eb7c55db61f35ecd9206331eaec3f655b934e3dbdfade8b04c9a989b6993327e0e9be7443bff9afc1539ecd034348d58e59d71d8b2e124d1b81c3ac261adac06761d7fddd11bb68ef09533885bde1983006ed87322d89ddc46cd8d418036ac1e1b3b88444a960408c0862d4543481995976d0ca1600513d01f10600d8b0319db2093fb779a1ab63ce65b36aa21fbcc34ecf126c48498baa48d44c372a725b6197d4f86e619d6bce099a387ceeee3cdb046ccfdb9a365ad46cbb0a5f8112cd53ee5873964581b79c74893fc316ce3fd3de952df474f11c31653ca19f129457c180dc31e72c8c1319c8e866a83614d0f7d43c31cf2c6a45f58a42c536723672e632face93398d81c3b6d90ac0b7bc89342c4703184d91c2eac9ae26ae5aa0c4254b6b07aedddf5a418e3fad2c2163545cb0d926f8810cac252576ab9d16a83890c16b6cbab1fbde63979feafb0848a948408f99cda5961f59433c80df3868fe1afc28e7392182af67174f354d852bd26658a2893616a0a6bc67ac31a3bc7791f52d81b843bab8a5d0e421d853d2393fa0fba97620e0afb6e7a1c62901cc7317bc2de20868df9d2f56f8613969ad114a22ba514626cc292fbd51399e7e36764c27e1ab1bb3db621265ec21a628c68a59537295f4a58aa73ef61a93a46399f84f556d622747e3ed33c12b6b492379d6e78ae0e1f619bfdc87916834e679411b6d3bca4258d2a348c14617b942a67982274c8771161b14fab9bc299e6c9c710364db964b13f3444c684b05f8e6de6cc254d2b08cbfc8649588c81b0d7f8846af4e330eee6074b8a21a709d98d514ff4c1323956bec6ff1121a4f460abea502a9eae31e88e077b8c4b55191deb1ce4110602ec601ded4855172202e860499b9252e13fc25c740402e46079a81229b9763f790a0170b074d894d21ac78f1acf5bac71a4bea76763ca61b4c51a35e432de18a29bacc5a6fe95c36426dda7a88b2477010b8a1ae0010934400603a0c59641e2c579873497fe2e924810031658bd008906cb05174918c02cd65f8fae39914f196764b184de182533ccb8514563b179ce04d10d916e7463b0d87724c5bc21f2c6c8f52b763cea492b65fe3421870424a852c107b8e0e2b8627b60bfbf73bf5569d245b66000ad58ea42ca182b4e5acc1d566c92e2a6484448367bbd20cb0a0358c5de51d9931d43e3b3e3820b2ee8c83000556c1a2fdc54c678c31fa5048901a4629033a34da83cfdd56100a858ca833eca959df92e499e18c02976508f3e44c84dfcf1060330c5a28d43ce5f49cfd5ad60052e381b0ca014dbf5a410cff5ab0fbd0b1898600624a8810b60408aad73c2e4f8a35e1922198511e14ea52b1c7cb84571c73aac0c0e73582d4331ccc04348040b8f195d2491402b0e0300c516631d9f69b0e0d5e84fac132a95536708d2bf27b698fc2936bed00d1d547430804e6c8d62431bad4611ba2e41924b209513abe9570a9f112d838cef22899c02ac30804dec1f35ca490899722caf8b24a30201176cd8d93026c01603d0c426391e43caf829a730779194d48047a59c647a25aec5527fe9b36be5f77e5aec31ff8659cff711f3b3d846bdfb2667fb4697c59af3e86cf0c46219cbc956ab33241b168b87c6385191af635eb1748c1b1f4d39e6e9b862b58c8268ce70b5fb56ac5a77feb0f1831066c53a1f63e83ecad4995ec55ed538a7c9fdf31b55ec13f395d12f5f2653b16846a978d428a6a8d852af466654351be1536c51bb73944e9e6636c55a9f1fc6bb20569f29c5b6f7b53966902bf3a4583b37a7fea38e4f65145bfe89fb979b2aafa2585546f6470dc512bd9dfb3705c51e12e18d24c61c1ffa897de24f9aa54b590ff5c45a91b1ebc852cae9ecc46a5ebf2144c65f8de4c4fe513dc4c6c84d6c7e214a324cf98851138bf674c8f834124cccc412f949f22e6cfa0431b177348cdd19677a849758d5373b36840ccb134b6ca124a6fafc71f34e2ab14c6ac817663c544d28b1ca58aa58df603b9149ec3978be4ef96a6296c472393b7fc3d91d4b24f61836ce94cdc89790d81e6720df971632788f584dd4d374ee1cb148ce31e3f14979d93562d5b4fa59131969ea18b15d48c6304dbe936d8bd8624e3925ad4d114baa0e87b192e6299588354a82c6fc78b43e64109147d499c6c0436cb9f25583f1943cc4107bc7cae8e4d1603f2ac4e63f9e7191552127c4fa38e61446a3366dc30c62b15ac9e9c19c9e2c882d797566673e106b5a70b8a13e20b693b5cb7c12bee5ff61499e522ac731ac96ef87a542cab519a4f8efbd0ffbcdcce8898a65c7f9b0398e347dd040d53f7bd8cf51aeaef9e861cd31628d67d967f0c9c376174efe73f00762e361ef0eb6295ef4dad577d83c37cea441fd9285edb06eacbe6062bf31721dd658d1a38427cdc9603a6c17c33236389fcdcd1cd66816b476ac268e460e4ba5c638492a5fbc4b1cb6df87979b1f776b81c39e3592b78df2864d42ae7c9b232319ea862d9949a4998841fb6cc31a196ec4e6c986c5c3a5feeaf7e99e6bd86fc5d1399028614935ec1bf3b73e1766d54cc38ec2c7eac73b4234d1b0a8c77f18d723c68f67d83a95a743f918d38666d8d16dec9fa95f0d6119f64915334c32068e2464d892e7dc17a28a448e8c618fd0f827aa7374fc8961cb1837ba685b09c3baf115352b0d65b602861d68482fadc6d50f2b5f583f2cdf84a34891afe2853d069bffaba9ed5c952eacb7c972f0cdb5dea970618d2126db88ff9f9dca16961c336abda6a2852dc5eee77f0c246ea86461e9eb0e15a1bc3ba382854543c7a1a7ebfd6e942bac9e32d3c7186a217f2bec21dee57421ade6f3555844c23fa4b39826fd545873755aafb89515fd29ac93529a87be558d7c292cd9992b792384c53e0a5b10930e26b936a70e14f6d56d90b1c3c7dce927ec316d0ed9ef9dcfb413b60c3484495d3761afba88a9193bae6a26ec388ec95aa545a37a096b8ce5ba5b0d6f1456c2de1f2db2c2ae3a9093b0a35ac993cbf9338891b0361ec9cb1834bca839c216ab2992e28f34678cb04c76a68fc690f12fc29e365a8f873f693c11b6aa10266cc6b13e9721ec733392734873131721ac5fa7e297813548294158aba2c9e7a3924a1520acbf93243da3b7a7f283a59269ca41e24bf33e58ec41a6a9dceb9bd3832dda4f883c2977f0280278b0ff5ee5f4c8e7955104ec608b19c97c5d97851045800e56cf4ebe9d6299738a801c6c716386b312bb41a508c0c16af17a93a64f92ff164b94ebbb9aa8e39fb4c556a16725324acd256bb1a4eae30fbd239a91b4d8828626fdedcbd9c859ec38424cbfa375a991b25822ee57aa3439e283b158d334d07218586cbf123c743da45a5eb139cef738cd53da892b960ed9cb21e63851c3562caa3943d39aa3641356ec239ea7a366154b9e942a1fe454b147cf1c5224f865ea52b194cce5b89ba262cffd382bc2764cfd145b2ae98d8e7ae41753ec5024efa224e52ec55af1657bd9513384146b7408212d1bc51ad2591ccf9728d6aeacd47741bcf7506c8e73e5301a3bf9028abda2846838213dc027f6888bbc1e32ee8b911ec0136b08d188121bc132d2037462bf0e1f8e7727ff3ff4009c586a37a6f90c73307fe80136b167146df4a327a131f4009a58834e0cda251d1eff3c4026d618a283ce31430dd1cf0360e25cd1559a3c7e8965746f1f68f949d82db14666485cf1c9a03f95d874e74183f8bff93e94d87a2a04e90de5a13e9358e6335dc836b0981d49ac12194d324b0fad3a9158435fca641907124b06d950a695c236ce23b692b80e0fcb31fded88cdf6e2679038315cba117b1a7b1cc239128d3523f6bb48760f6c337a5ec4be92515e6786e96256c41abd32ce4bf14146e1442c5d95923be39d451811dbe5efca9faa0a0e3ec4e62973621b9ec96e0cb19f7ea67edc2863630ab147d1185b497d326208b1effe4c1895988e5306b1d876678a91d151b40862ed2889bf890c2a5902b1d874434d21d7e7ad006247d3402d7c472b2a7fd841046918aa3622ed87d547e3428ed13e2c65b63983101e68a87c587eea91e7b29b1ca27bd853a6f054b929744ef5b065fe6dd00b396ea779d8f3d443234de261c95ddde06294e79a77582ac3a6b046da289976d8b74e4d1dc38e3dc93aacc11ce859ac250d493aac79266ef525dda8720ecbd823094b87e96694c38eaf2e73c957d605e3b0a9eae71c9dd2540ac2614917464ced33e804dfb09e45eda05b13e34337eca1a9438947a8aab00d7baad439847a663c13362c929ea2e73cd0d39035ec9df283454ffa713e35ec9dce2a04f5d2b0c34819f94af09c3e8686ad4fe28e5e3890a89d618721671425e59d5eccb079f8e47839c6f0c132ac19aed9655a473f293260f1315ccc498d61ab5249763a6993a4c4b05c9fc5ad1022564d61582e05bf702b816139cbd9d028cfd1a32f6cea31392af7331a79618d379636560caf88b20b4b8889c550f2bdfb482e2cb13fac9ae5871b1fb985cd3ec3c38ffbf8f3482d2cb3ab318ce6308f31320b5b4e9744c98f852df25fc887edb4a9bfc2aafb99992167f5f456587a52491cd3d4cd7b15f65a4775eb337351a7c276e2b03b4e3e85354c8f79752c8db814961c42dc466cd0e88cc2f628eed677070f00852567e5a4691e91b7830778c21ec74b6e5732e6d8c103386149bd13ca77ea31b4f1004dd86f3b1b6a3fb45c361e8009cba39fdd94da388f8d0758c252398f5264733e8ff1004ad86e3a2e9cd458c8311e2009fbda4ed0289ab2418c0740c2a6152ec4048d1554830738c2de207de7c349d5bfe0018cb0e61c9af267301f6ac1031461091f62ea376f70b4e20188b0e6da8cc23d1a8d18c5030c61d194ceb7a50a61b1b5ad0b750661fb8e6143c7bbce198130a8cc907e55fcc1127d3f9e7bf28508fa60f5b5681b927e4851d2832568df65b47121ec3cb81fc79bfb77b0a58c69213d67c3e860cfdb151b7b3d400e96b2c94857e223e51d0007dbfd48a89e3ca972768b7dd5f38ee39afdce6cb1a31cfcf427858f19568bed72ea39e9ad897ad16293f39861ca29eb4ccd62cdd395e4d46b2e4e288b3d6f9e60d2e9cc73c2582c75e63166bc19250d212c96185fcb9cbf9626e12bb69c733226e9bc5284ae58e26a1fcd442b9d085bb179080f7a67e26667202b96f8d15297c370153b0a8d5453ce43890355b1fc8fa40df3eb1119988a6ded53658e1e3a1a0351b1c84f0872c1d2b7f2a7d8422ad86759340edf14cb8547319f8dec69bc148b65eaa6648cc7d049b1894dc67b2144f0948f62ebee4ca331a95fe5a2d86c1d79fe78a9817f42b18e7db24671506ca9f6fd199fbf95f38975c34f94a67e8c7a3cb1060f693431e6957827f61cb5e3f943d6d6e6c4a6d73d12eec46ced4d2c55e52867aac760d5c4269fda8de44c2c5965d921c3fc39c29858536c5fd2de5c624b522b49631bc56f2cb154ce5f1a3661276d2ab1afcd9de7891c7e6228b1a7cd172773ca24360d2158fedddf6d8a24f68ce9f651c550566b24f65a554d9b3435c50a89a5ca1c84e4fdf853f4118b6f04d1305147acea20a9545a6a546923f65c16733ac598349a8cd8c41f36383dbd1ccc45ecf5b86625a78c7ea522d6d47fb19f730c5a6522b6896e9842c768dd48442ca9f364975f66f8e3219692d5a0a325653168886d4f52646da7a8060bb18f8664cc2135981c12628933990e574bb627835852c56ab89489a113416c97cf5278a393fa9040ac9b32c6a02f425f0e01c46adb9b72da8f19a3e40f7b9e67caff5ffa7d7e583e2744b4b895337d7d5822ca91c64bd78d727c583544da4e92f27ef4f6b0aee4c438793e76e4881ed6d0933d92e7618d25294dd9a7fd0f1ef6483e216dcc11efb0f7895dfc9439d8d861eb7e541ab623545a8735a409f61ff61b11a3c36a974e3b836a0a7f0eeb6a8f8488b127c672d853488efe99b451340edbe795e4d168f37170d8c17e5c6b942759f5863534ca75e4b1ac23372c3f52792449a87e541b3687314f88bb7131cd86fde397e4dfacb0f21af68b5137aa4a3b64d4b05cacdf8c9deb23250dcbad57081d1f693e090d7b681c2c6784b49e9f618bb6beda2985ca7410332c5d8e3393c668ee65d81f6a6f49e8c9b05d74905e8e1fc30e76337b636cf8ed625837e6a4214489162d1e861de647a99f622b630e8625d337befc112b5dfe854d73de65c4950ef3f1c2623901c730620ff37c514aef2a52cc2296c8ce69424e1a45ec0f75a2f67188bc9f49c492f930fce9a790c36610b16cd09eb234de4062e610fb7f86863146ca81650cb149059d8d9de12ff885d832c9e70a652a51e2845873566d79dac66cf8205629499fa17daeccb720d687299c4d705c9f7609c41a9226c79f9769765200b1f4e41b1d89e89192f287256dbeb55011ffce2a7ed8614446a15921e51c953eecb8e1a4d1eff061e9895c29ead54e83f7b04684e80e25b1f662f4b07a074b41336c8798c9c3bef317d3e799583178581e654926b3e81d96067b3fd1f234c8286a87f5a2247892681df6b878d31d3e3cff74d8b3635a0c63153f3e873d23f198f1e54c43510ecb74f9e6cd30e16c8bc396d3a598b995983282c3a68f71bc9442649cbe619d7895f2cec3ba1aea86d5be472337693dfedbb0558a0731cdace4e4b061b91cbdad98699f2a6bd8d226cbbb7fa61af69c274a3d4ea661fd1f8719ce4e37b81d0deb679cdbdbf29ee8f20c8b7d4ec6e1b0ce264b33ecd133c6299f858a69651916f9cc49d27888c1a724c36293a17fe5f5cd9d8f61ed5a9b50e56863c3c5b0e6a4e1624d8361d8a266d81d7167be3782618bb5db195ace68f1c62fec33293936a485301bbdb0a379dce9c2966b4246611d1bb5825cd8ce2ba3989437132a6e61e9b8dca892a8af03510b4bb060d62103adbd0966619ba8d28ee9195906211696ca46c922437dacff0a6b55c6f9f92c6f4e6d8575d3fb1e63183dc67015968c4b2337373f480ca1c2268ed4f174660afb7f0a957bd24c8f2a85ede344d3c8eab1948cc262de9db224a7be0d42614f3391affcec234dc813769c7bfbe96a423b77c20ef3520acb9c262c66bf377d1f1396f9e495750d3245be25ec713a1983efc7b2ca296149df101d79f549d841fe10294a277d4591b006497d65124d37e38eb077659857e1c633a233c252a9518458a8149a22ecb5b35e0f744ea226c21aea828d444a589587b003c98c34ca6e798c11c2525f31c3f40d323a084ba6de182e7f8647251096f1cf30c2564c57f783351b6ad4985259a1f960db8956a9bb95aa523dd853f014a258cea011321e6ce291a324cd6b013bd83e47cda386ac289e5a800eb60cb18e838447fbe15a400ed694f24fb49c28f6a85a000eb64c6191c1d37e77fe16ab434d66162ee2b3b7c5d2b30e3dc40549294eb5d86fb3fac3e595be9c68b19ffd87895439a2159ac5ea67612b394e165b9a4b1f2c796c4a9158ec69995327e386c620b058638a9e2b2d6af27eafd8f7611a95d017519e2bd6f38e07174a6d3c45ad582758c7cef9493e11b1623b8fbeb291779bff556c2156c8884893d8b32af689dca99a3aca844b2ad675bce17188a062d174c171943dbbbc4eb1df57c50e490d66a4d12e83421150802996fd30d628fea5d83b86c50a29b3c3e749b1a5b90af97248079b1fc5d2f854373c66c8e78b6271e0b981ffc79c1d0fc596267542ed038ac5e3d1388a948629e7133b0e1b37c73a584d8e27961c711afd934a659c4eac1b620c9d2a3ace7173622f930c2d641e4fda9b5847524cbb18e283ae35b19437b8ae8f924bea4cac65f753d561b177c6c416f3e463b4ff481bbec492d342dca45a62b5d0fce515e162ae12dbea86f558bdba8d12db77debe70d560229ec49ad24863604953081a492cd28f91a5ab901f47622d4d1548ac3dbbbf31541eb1464694aed9d06177c466b11d526f32394b23b60f9b62a60a893732621d0733e2218b58e6d641aa862a62af4c964ea74fc416613e469024229647d2b0435e6708e221d69426ebfc426a730cb1aa4daef1e4fd13420ab1a6899f642f78c39e106ba874755e6e109b7ab83a890b6253db911c2fe6759c0ac4e629efc60815c2d70588c543e51ce3868320d71f765039f9cf4442aae587358d993acc70629dd5873de683bcdd49e2a9e2c35a25bb8eeeb2fa517b582dc7545efb180bd3eb613d0d4f07abba51a2cfc3a6c96ecdfac482831e0f3b8cbbd05fe7c13ee3efb038bc48692e7658f62794c50c09ffd5614b13aa33ea6d108df174584aba629c9677a7e7b087f8142ba3fc992c72583de6ca8d466e373e0ecb8d239d95780fd370503c2d74a58abf615bd10a731437acd152def4dfbf29da86352aaef4639832946c58e6ef2b88e79c10f2356c41d7f72b6546891a96d4e5f3fd795d7d1ab6afd06192a4c9ced1b0e449de9cf4af7a67d834e7d5e0316dde479b61a994277aee285b269761898a0e1573ec1827c372314e63d8558de231acb71dab3f3a859411c3aa62b1715f09c3925386292b3560d8b6f4f3e53c29a3a0f9c22a992c839a8b3fa2f1c2d68dbc1e89478dae74616b50df1fac324c58b9b0f8c48bfdcbc9e1935bd8917aea14c4fa2f9d5a5826340852a1324c9a59d8fcd2c68dc91cc5142c6c1333ba88d7711f8257d82b2d8d4e9ad30da11596d3a825e93a27c9c02aec97fa3987daefdf0915f6bf58eb4e21c2563285bdf303d51c97c2f20dc38f66ca30c75c14f6c97b287ef2d59983c2d6f0aee2ab7bc21ebab327373e98ec841dc4c5ba3039358e69c2d2158f626ec6841da3281d92c954a86c098be6aad4133257c28e265c474c51cdd3e549d8b781657f389f102b47c23639237385a89b6cf223ac327be629a60d31496e84e5520c8fbc242fc25622b99d36a529464e8435c771ae49da1cebf021ecf511aef38370937a212c61eb8d56ebab3a1e846d73e2d759e38b290e8425c5143267dce391fa0f169bd0e05198d59e8f0ff672e4f13cc5c5c7b3027ab04699afdae827d559013c58f326cb191d6d928615b0832d265377e3ccb8152b4007cb360e8f10436ee6aa801c2cfd38537d46954ca20ac0c15e3a1e739dc7c993de62cdad3189e5a91b9fb6d8bec2a74e6a195f2a6bb15fe49832ef75860d69b167bafa9b4e31ea338b1d754c8988f37d18228b4d5384b514b527a42416db49ece7111f8d232149c7c94477e4153bb85d47121f99c7882bd614cd8b7e0c3f3d482bb608b5bbd98f157beaf570a531375e6f155b86abe937f5559e9c2ab6d8d4798f5652ba4bc572d531b9277e4e5da1628f9571c7f4e19286ea9c629f90142b32ca147b0c1593a71c078d97623b1d8dfaa9d2e69c144bc830e7c60ddad7a1516c71e3a428bfcb4d9328968f1c954f426caae88462d59c63a894122a6fc601c5e6492e45868fbfd2389f583d4cc641abc38def8955f536cdfbefc472f1626c459c649ae7c45299bbe2fda938ee37b17c4afb9c51ae893dfcc606417272203999d822c64fce9c422cef6062fb92780cad73892d244f51e38f4ce6b425f6198bdb09c9f6c25d89fdd2362c4544cc375362952947d99dd1250d4f62ef18613ec7b1f41396c49e4b42ba18e28ec41239e7bc9b361b48dc9058ce3ce78ca99b9cc1fd882dcca61ce5724434b81db1449a8fc89d6ed26fba116bd84c4d89916357d38c583a864544ce48f3677a115b08291ec66684cb29ad8845baf4538670ff38a513b1038f7c8ef26394cbd2885852081f5b29967358fa104bc6ca3039b633ce4a1b62078e343772daa8a37621682039729da784d82f454aef8839c44d07b1e6af3efebd9cd25410fbc44aa7cae9df280dc41a6c52fee6b28c7902620f5a9bb3db319d27ffb0740ef59989609a4e3f2cd16023a9858894d987a561a75fcc0fee82c987fde63ad7694d5724f7b0449e9033a9f4e62cf5b0c60c3f458b49cba4ccc3aa17938a6674f778c4c37e133ea56eccb972b0efb0c389f5892926cb19db0eab4857494abe394fec3aac5269438ee9b0c4e694abb9215e6c0eab7c2ecd8e97e22f94c3e2683e38c8eb1036240e6b663091f13027c361cda41ad3b86a92e70dcb8590a16e5969c4b8614792172ff7cd4dd8866d33aa935fe9fc216c5825a64b521a7aea352cb99f41bcde6d903b35ace1a257f4f81f3a9786fd6156686479fe618686bd2a8ccf9adfe7adceb048fe34d950ff936d86fd4b3c87d775984c65d8420edac82e4fee9d0cab44c83d09f99b312c6329c73cc2579262d8723dccd049a395637418d618f7dff5201efa60583d9437a81c72c2fd8525c5c7991f529c49df0bcb8587f1fbbc0b5bdc3c1361762eacd13f39ec324f2cbe85fd626398464c86e1a3852565d31c83b0deef6461ff181ecaae465d76b0b05fa8b2991c827c4a5f61cd949163c6cab3acadb07de658cc89d069741516c92f3fb3a9b0e4e568f138e3633d857d7767a62fdcdcca52582afef7764ff62e8ec296163d8ef72e86104361cf981a2cc661448e79c216a7123756e5ccbf386129698c27c6eda7579ab0caa649394c4f532a4c582cec7f3cda941f5fc2da25219eb9e1495c95b0c4e954417334093b8a29fe420a364155242c65e5252a61a38749028eb0384c162a4886a1159200236c7ed2d31bc276d59780222ca923fc24f756e3e3041061154f21aea5ced2cc710286b05752cba87e552e739c0021ec0fa4e2ee324a548e1310843d1fd9454e991dea710280b08414adc9387f773a4ec00fd60a5a3231a74f998e13e0833537869a71875f0a1a27a0079b75ee88996d0c43e304f060f3907108870ec23fe304ec609ff9aeda061956be38013ad86634e7f43974647c710272b07d59ec7c879c3ea5380138d8bec3f6c7073a3927bec5e2113233c47c1063886db1f76a01add89238fcf81cd2a39dbe00600a2f58b163f08fc7539d5c881329bc58c516d71d33e791a8624991c2c31c134242f924206178918a4dcc53dda48e8f1f47e98517a8583d736292c6a1a1c6f8293655efcf94185277a74db13fcecc9052b0b0cd5729f6a8d1232944bfb263a4d8a32b422efc8f7dce20c12816c73087bb8c57626e85043570010ccafe8528d6b3549231acfbcf60d4e217a158258790e1743e49f00214cb5f4ccf547a86fd2110bcf8c492fc235a841ce73e5078e1893da4df4ed468a3d2e82e926250a4f0a2135b7d6a282977c61b22e582725d78c1897552a8186b9f3a7d215d249d2319b8c01d056c0e0b2f36b136bce84a2911628e9226b689167e3ac3908b6a3951145e64624b973c85cda4626219079e5743e4fd9ed5451209000e5e5c62b9d09b3187e069a2c7241885841796d8e72fde36865136fcd645920a4c9723bca8c466a93f766caeb8b0124a2cbebb579d396359407831892d9957ca9c3ad245d22001f0c10b492c993663cf077f3495466291f4d131b936191e975c7801893d4aa4a4f3ca186bd7472c8dd2586cce2d8bbdaae18523f6699c61ce8c3cee71f20c2f1ab1d576e40839e646fe388c58620a932c262783ab7e117b9c18d7334a8459add3f04211ebf9862bbdb449c47e397dc8609365a4e15210b17a6510657cf37d69fc105b4eae8de5302feaa986582bc46c824546131e2cc492616708562a19a4d458a001426c5a13bff142b8a4497a41991783d8720631e4575e8be4591749242082186dc63087a549aac12e925e70825e415141c18b40acaae1d693e72b38a38af002104583177fd873f4b3953899469d7ae1873d324c35890611e6b33e2c613425c93036f3dd860fdb3786e17266906190bf8b2412ace0a4105eec61b3cbcf61d2ea6d8eea610b9f0b639b1c85f54e1749e71812ace060105ee46187db30e307cf94e0380a4810033cecc11c64a03313e793683e787187e5c349ae9fe87a1cf50c5c0524a8810b605088082fecb047069736e2790ee509fc057a012eb8185475d87118090f7aa2a3137791448215c0400526a04ac20b3a2c9954477be2c40ebbf8094c0ae6b07f8e7c716b71efec413c7821872da7a3e7788afec6413376f0220ecb4a04e98ed520ea3e5d249140052b18c405172f40010a62100108a840035c70e1ad02ff5f01175ccce1051cf628be212be7d18ef9ee22a9b8e1c51b76d420a73f43927b90d2459209000d2fdce0dcc3fbfc1479b1c28b362cfe295658c5909b50cfc055c086f5bfba2f6c6688fdbce0054ece021380195eac61cde82ce34e3157aa8a6af1420d9b95747430e9b0348c5d241d2f46bc48c3f2f062d48f8dd58d9f857881861767c0426692eecc2078ba48fa1590c08c62811996fc79c2a414f57b37c661b0021990a0042a204436881765d86ac3e2a71ad50ce32a861764583c3f1cc4f0f74943ed22897ce1c518d6bc35cb104bef942c5d241d4f36bc10c31a2fc42ae5073f270a5c008326410d98046158bc4159f4faa7b30c0d0c5b659c3279d0989c097791645c40f4854dea33280b1d63cf372fbcb05d488dca3f1ee4adb58b2415ac40b9e0e2052758c10aba502eb8501970c1450ab8e0e2008087175d584cd2f6f24fba3ce3b1a3820f18135e70610b67f79d1aa44fc9e82e921c059c14e0820b2e4635e1c516b6d310a164733c3afaba48520ca00bf23ff0420b9f58cec0e2a701d8c18b2cac1e2a7ea7b047673a0a6000037f0162e00516b6a435938385751edbbb487281090c0bce022faeb0fc5428875ffa1721e7820b3222c20b2bac69424d9a2a999099430297010a56a035680dc18b2aecd01fe4db70631749480df0c0051ae06568784185e5ae3a055deb8731a6acc0054f822e5e1003160caa4091c08b29ac6129e586f4518b1927853d5987bc39329c63e8e8c28b28ec18874d953cb42b99264d1abc33c9a6f6842d8aee49e465b4f2d50b8a69e18513f6bdcc394622ec2289a80110680041a00103052c8881071ab0810b34805e3461ab5fdfe0eb0fe278a68b2412bcc0044cd8a224ffd754886078b184fdac34cf726aee06a12e926a800214c4e08b9020f042098a75a5acd095a156d2486ada7934e4460e63a4035c70c1823cbc48c292563a2be6dd5d2471c185111256c9a0b31ae1f4d1668eb0686d860e73a3c4616060108314e03b073c062830442ff0c2084bee78d2e9a234a7ff226cde5bead1a6cb40032040667841844d2b92e778c86826f5212c976a1a3f1ad56ff20861d5281d2b66488bbf38087ba5ff10162468ac1d08eb4fcca7f6d9153b8527c00213783b07b8e082c8800b2e880caabcf8c1ea18fa654e0ef4c112bef32348ec66b0b8073bfc1829aa5229ae7a78b05f8a85b27cfec5e0c50ef6186308f590318d4d8a0ef6338b39f3a7fb1c07f1052860410a4cf082173958bb1fa45c9e3b3eaef3841738587fc256f8fbf81d7331e0168b244f31194a08ffdb6db154cc343122d35d2491801ae0010934200529a000962e8201b558755267e9c65d000312101dbd00008d60002d36ddbab92819b398f259ec912f622da98653ffc8629d349662869863baa8c4628dbfd1a27c4a9f690a8b55fb61c55784cb07e92bd69473a24f34dabc7974c5fadfc143f4a41e520cb66251fbb815a1222b960dbe39a7a5345d9956b1a6a53d7e307529a7d145920c4ea0380906a8628fbd9f3a3b6a6f739f8a254226dbc655411a7550b1ae75557ceae831fa29b61869fec6b4c2d366536c39ce678c7fab1bff528a1daae50809b98c272a29f60d19ef73b84c6739a3587d2269c69582a25822844916dd5928160dc9931983b8dda8ba4892c10948f0c68f406001520128040340b159cc104c63084b79f29f58d2a5ac1cb9d51043de137bcf5834ceda10bdd29d5866afbb1b464ed88ce6c4e6f3703f7c2791ec79135b7cf8594aff68f36f34b176daed1e073963a49a4cac7d9bfab152e6a8c860624f36e97208cf25d69bb8306ab395528a25f674f16383588651334a2596082595419edbdb0d526253dd08192dc3d998dd24d6cb18c9c69bc3068d2496589f54c5310cd131060322b1e59cce51c6b36477372416dd4fadb8a27695c28f5843de0cb43b928e5835f4a50c53c69b4e93466c13ce6635678c581d3f8a1b42855634c82296c99f19eef9d6fca614b1a30c71120d53a30429114b0c2b13e75513f3f288d881c5c9fd9f64f1727e88fdc327ad1895342c850db1a7fe4ecf28e768c9510ab1e70b0f378689c3092221d6c69f39194d5ca9944150da9d628c0c15c4922bcd675cd8240fb140ecc1b7af6c33e8380948ad800180586387a812cf32c3e3f41f96b9b0a1f633d64cbef861d978f9f3a147b9cbf461cd1d2e46cee70ba1221fd686b92af626526f7c7b58e2585f8eb5e9306d7ad8c363cc9b6dd09955e561199b3f4751442e4e78d8d13d08a376375df1bfc33631c43a2bc964c4c70e8b8ee68c227ea9c39629ea31058b871e4d3a2ce697d9694fee53c739102c4f3a327ca01c5647291da242cc518c83123f4a9ac3a8e0b0c69e9061fc9ede6afc1bb65aef4ffa3192eced6e58735e77e7c7c8a16c6d58bd7ee341c64b15d161c33e9b3bcca488d7b0766ee3dffdd5b07e880db5535506319386756432c44ea2924c336858e6fbcce358ece59433ac75b521e5ddafce1334c372712232580b29c3621beb62bf716458257756a48668dad0c6b0c7ad3c917037922a13c3bab1ff1c5fa7c2b06aee10e65265581d074393249e2735f90b8b7fa806990cf52cf4c2be62e141a3415d58d28710c7ba739c89a38ba412a8c0042f70410cda5d4002a4129c9dc0202a30800b6b79ce0dbd6a2ee474749184f40cd8c272392a95c687601e1517780a48b082a3236080164e0fe1f555350a8cc3e0052438010a62c08420f080527e56a082634016760c6dbd43deaea8cd5901098e0a0c096860822783410c30400313bc0500080cc0c212c252ce290e4b36af2403222081081870852daf6e860a9ed67f7334062403222041081860857d3e9a8ee6acfc9bf22aecf073fa509f3bc7ca5b790003a8b04c06217dc5e0abea2853d81f67b4dcd9717a7d94c2fef5382544bbc9182451d83a626c183a74c8d98603180085ad3ee3854b9a538ad43f61077f7b9bfe710626b11316bbeaba9c223cfc7c69c25ea931f2a829ca578c3261cf172dcbe7c2252ce1ff743c592cab8e28618d51965358924bff86041890842deee690bd0f3673b091b0a4a39875e93b837b94236ce981a94e88f1de4c8db0a30bd921ac995cae598455c43f74fd451b4d95084bbc990df96c7b42cc86b096e58784b0a7687e79ca736557461036b5082162f2e9067120ec20e332cfdeb578f80fb64e1e0fc626c689b40fb6080e6ba363701b323d584b2e4f0e21dfda5478b04ceef0a82bddc15e1716ad73c8d570ea6053f1b11453e8c48be5e0a918561fc3c73300076b6d3eaa9a90b18cf1b7d8f3a4f0f90d7463c76db1a43c0a2134ea9474bc16ab8f75facdbca7233b2d360d52f7fb17ed2ff6596c71f229ea850c25322e8b65bcbcce41fef44ff158ecb3a9e4c4237e7574582c758db7a256bfd7f357ac8f61e54d39b92b160fa6714b4cc54ef256ec79316568ff3879aa59b1deae6d8ae44689bc8af574673c1da8a8c4a862c7b7f321c5907661928a1da5aa4a75944a3a878a753d23d9982be568df2976e418a79d1497d4a3638a2d53d3c70d19a7149b9a68a6b0cc99cc27c592529cdc4a8e6289f86b192693a9ea8862071e345dee878c3a1d8abd52ca7d94c9d16750ec93be6193570a71e4fec43af9d5e13ffc66baf7c46a395c5fec8f144f3bb16ea4cf29864e6d3827f66b7495ab1f3219b689a53a348c9a2fa5fd686275dc38c6ca8ccec40e45d567729e31b1560a193c367cbcbdf325f68c7e42da99e81e0f5b6253ff1434f3757478732576188d2c7326cb7a664a6c92b344ff24fb3ac293d8cf6b2e56d4d2183c96c49241ce4146277caa184762d158954422df86943124168d9211f9e02b558a1fb14c54c6a6d0e91c8b1db1e359556d94aa4ee3a6116b574c6333a3dee88881a844c7c3c22161010141c1e0e0a04060606074ed3a43180800000463419023511244e9031480023c1e163c16120e1010080a0c0a080a08060a040004060604080006060800040400060608e01193106e00025a44a1e8520a8b62820fa961834b99f6b917f1673915de9f0ab5a9bedae966be543a985d1e661d2fe43cf5c0b7316041545642de9af1178bcd3a801c76354a272f2985d2145e964ebfc952cdcac9ca79ea314e497b453aab2ed292cdc6f4d16a59f8699717ff12978530f93597ba65aa6292af40611dd1e312c801988d1f10f392e8e73a92ef9bae42d8298dffc9ebe3098265d241e826f965f620249a02f5cf29669951bb3333030e16f9ecb2710fdc5bf616ffe4187b1d1230ede51c38ed24864727d44c2c60229aa9d42be91db70fab943e4065116c1135ac7f3a270ec9274c123125e2b8cafe454da6c05397b2f88224f516799844975a5a704559d38320c907c5677b31e95caa838515ad02fd1a81665f2030f0fb8c0775cfcb50ec89090e7a50f6410b6908d9ee0f50dab9cc6cc9169abd4e86bb2410d4f2995c8b151bc64739aed26d05569bb6a8c7040d03a81bee8bbe3770e90ddf517a9e72436171ee02fb223bd84dd046a6a1d790c65ff27081acd5e3555781030b011751e6c067d0822a32907841844345b29e5eb04ad13609b5760159546b76b43dc6b264c7f25920a5e974f0d6589c1b0828a08ea77eb25f4b7ddc46f159205cfe2c4e0babf8ec4dd9045d83f25b91544aa74694a654201b5af50b73f860fd926a576dd4235eff7719e0926b97d7a4c52b667540efcf0e611bba3fb3f24e7ae24776e775ffdc15f818dafda524faf0590ac466fc69118caffedea723b5c701b802856118596fe05b83c97ca796223e14727b99730e6e5c0e1225235c55a5cca7710904e75f0ef9a65d2e0f71c55cb5156ca5eb1aa6ca12a57acbd594b9aa7bf62abab3ec99043fd20e89ff796852be7c554c637d8e37099aae14be69500467e674b03cedddc67ab4948b1a7a087fe014450669da4a1fa39666a21c0c4ec60974f58d6313346731c5fa8d8bce872f2716d2baa53851f265bc155a8be2b14ca02594493294026ecc7986b0bca5f33466acee0d8f0e6e1bb38ac2fe2ae9001c1614a320b4a6df7bab1c176bc400c313e9a9f91d1376eb8d4fa9dd80721a8b6043f1601a42916ad2776d1be8a16e2e29a4ab0b6de6d4a08f66f6a07a04efff2abf12c635db7b5ea277f3370207f599577a79ddcee44a71132325ce1b28b01894c200f733990b6b7de23aeaa7df7b37268d8d67b0e2f56a7c26dac1d6ef36bcef370ce5b3ff2d8d245fe8a15662afbb8edd0e2b839fd467bc8d5d2799acf3ac25d00d7ed8660d8ea7d8fb5fbd20bba166424ed0e82d8af1b156d682519c32cb61ce161f46bc9a14a7cdca9e0c7f4cf6be2d0346a3f8a6afc8c992e582832729160f1d883c5743ab756903b850c174a98005b85c4674c64d680927758fb36f8affd40785114ca363f7515250997d7d47053c808bdd1dcc091b38e119ff75cb7b87a4336ed92c4174f3f3eb4854fdb2dd16460d8c0004fb28064e56481e89b16c08e715e78a93304dfe2373a8ec4d63afe24f06ee9325bf18657d85b8b0d4ce50c43da93e04cd58014e4d6ef70769c9466873e496cf5154e080e85b86888622a3ce1715022b5f28b40a0a7d7a172ef0b93756dfd66247e4bedc84c7941a8c1b07fe0f4548e696463d6e5c86c8ade04de1b8d25fcb6e10009f0421304f3751a47fe2133bcee87f89b063451a4b58a6609286b6092f1d639eedb5a06bd1dfb996831bc4276d691535a5c2403f22dc0157f16db7eedc77a050c5a9dc37e389f5bcd28b1e7c0d6c442a7c4d8a09ff83dc51f899aa4db139344599916ca6a99b5df28fb157161db5095393e7deeebb85782958fc748016b340150b73e9e80a88d0d0aea3e43183e74d9c9808233cc3e28227acbd538319e3085a73786bdf5899337f23c1370287a3fafbeda6f94e90af02dd6da13060e8e06425976a8e60c9b4792df36ddaa4a9f2ed55135d84cac94bd496ddbb36162c0cacc026af234ee9b28aece305e1866102a48eee0fd41fdf2c030aac4cbdb3d40f84acbef731830dc11a388aa5a979e649a5db2ed3a9cd080bddb3b537b9bf29f89b3b6dfa4377144929449c214ff4999adeaeb23e8a2c86329e13af36db025dcd1d35543f47614d2e459190b6254fce4d2a7511ac1a857aa98ba49469fdf7855e152d6a775f6eba0c9cc50ae4c18a191d67a7b783e905a2c72d79d2e7ea7f96bd11f40dbe97c667dd7477f8cf343ec3fc526a6f848345fd45e8860627f294220ef0d02fc659c1468ec1b13fa527290b29920682ed980a75585b23e416e7657fe9c241ebade4978b6763d9874a9f92ab3745e29660438934a555ba91af89c5dda7f9e1e1e2608c4ff0a2f2d8cd93ddeb3337f8af9dabc0c218022ab52f63f074e6e4d5f3fcb0fb0eb5e4ccc3be0574c23c2fde1ac44e6e44483d6256d34225e1878e9fa09f26ba86f001aa38df59fe061792185a7157ba18859355eed26409bc5259ee2958f9da64323abc85fdaa02e2e406319018e96d587127345377c92bfcd7a568a511c598af1d3b3b2122d15d5329791fa9e4ec68391ffe94e42b9a64f1da904d428f6d2a2a2eedf952731e43071f2b234d14a35fd310677bb516d4e13ce22395ef116b42ceebfb24813f29494cf25587ca70c04384b5b2c1152ea2b171cf78c702675011ec7b9fd0e82209b1a43ba06cc80ea044cf82f302e6dfc797c208f29af17692230194209bf5c5742a9713b95df8aa8b90d677ff893f70eab7efeb9a94a5863a3ef936e4dfd877391f2fbd5d25cdba7d008ad1ad4e208965f69204a1698dcc21098b1bd3ef48e5e4593a92edca3193643b95bcbad13858a767992945497c4a5750da47a97b4a6f94025a5b299869fb2b85299d0e57128bf4350f7475b19baa2a8101b05d042b9b8e3253aac3539f273d3d4be2e986e72d0fa0b987ea53dc771fa1f050a18a540d4b209e878a54274eb56dde3b4e38924b3a4e441af9fc7b73e46a8f4a55a69caffc41995206af8c5306aa2c34b2fc9d47bf7998366798c195f7ca83cba6c4dc9f54f2830e562c9cba3b8452670012d692b51d110fc57230352c6d69c707c75a0764341e8dbfceaff16ce3d7cf1ec39c856fdcccc6ae77e10a2bed316f24876153e50f8ed122e95e00ab6d643e9d516723b3e98c32f389c5b3148b9a31704ecc0e2d46a36861083199db4c73b8ca1e82897fa8f5df60b51b150ded2d60e1fd42740c5ebf16461c67e250e58685d1486bd89db70ccb62e0bef01ec344f185112a728e53902e8c05753dfe0ab540cf02a08f852156888cc1ef0ba7048621c64c91d62303b93cc3c8fd68f01950f70b2378bfa181cdf419ca53cd822348033acbf3a25289468de8c19be0bf0269ff3269c4794f4c5fb2549b64f00da4df843ee2219713f3ea986b5ce444b5aee9d462577ce0c2e1d72909347dab80f2c5a67ffefb1987427568d3a3adb6209c21fe07c946dd8bcd853828195edd6e78c2fdc51324ca9a0003744638943fe40985dcd21c8f8640e6b074cc02caa2cf5228f667d92f633bb49d14c7f10b08a9028a1eea4b7d9af2ad99b38aff75d4cba87954e9eab9f47228c676410dd16635288de73e3c34664cd4c8e364ca0a2f184825385507a6a296ab5e9f267035961b363627f566522382ef2ea365ea33d14e3f27570f1d07366e5caceda4341262641e2bd17e6775b758bdca8a09e86c424a70bb25dfd6b8eeaf6bf045cba9b7abcb9b49f8343c916100dbd89a90a221c581811f03172d44f4c8a8911019009e9c877c681078f05216f69b35e1e2c7c6c84f38175816e0dbbb1d9d3157e889fac3c443a44923f7ef548ba9bfbcabc99eb7d9ae2f8373d3c65e814b92ce29522ab05123a226ae99ef893bd5720952049872ec668a3e16e884c8830e15775c9cd4dd368d92b95172d23636db4bb4b3de94c1108375b57a2d19d539120d418f01047d56fd99dbaa866a5f589afabfc53ddb1a9ec8ec62abb85f39bb6eb1a31436a6207633ac37499bcbad1d9a2839361b0bad04e6596a1b5f99b7719c87513f13c31041a69d380d4a9c9aea006e8e2ed7f7966c20976079797d787fb9399c8f0bae5524fc0fb1f8134fe6512ab9be4824bc3152dcdc87f3e33eab111ddf13157edcd93a4b2accdd3a2041a66cbbb78312332bd07c6ebd30cab5aba02277e2018fdcd5c40b1b4924ee17572707d7f6e969532d8abec0fbc50903641a768e014445c20d86b2f53cf77f92aee3a3e4480b2d146ece0d1bab5062a6c2ac14aa7ae5598ac9371f1dae6f2ef7372cf917a7ebcbf0b0612e4fa572c7d0c3f2297479db9026461484c5bbcbf699557ffc3dd1404e9b545182c05bf0a71122941d5eae5f6f53a3a54e4991e6707bd3483f3e99f07f70ece8fe70ad2d504aaaf787d76776df2528196055bc319273c724192add06b1844782e6f2de3fac77276be3c231d55ad7dd78f74747d7eb7b8539a01dd8939410151102525a0464884993458ed83921b2e3cbe9c9f1f4eceafae472df449838a3c8f4abc0cc51e53c29062a1c2a0a405932251eb16758f93c7e7c3a42e68a29cb383aa60ddb611a0d56787774bfbc3f5e4e1a445ff2930a36f1fe747373bfb3cc1819d61eca90fdf1953ec5823133d3e74f9c333f6376e284b1f95454a58793a0368717bbf9a0b1534c7859664496b2644a34c95a0d50c18bffef6f9999bf2884d0f1e5f526779e7310cc1ddd3ddf1d9e2fef0f361878c2c33e748ba58483fb59e4b05ddf7b0007ac5db52ef6171d8d4ab08fa73aa682c1483120d78af89d42f5e2e0ee70263888dcf58a87ef9707c7dbabd3f9c9b9e4b0cc6e0a4337075683689a600b39b83d9e1dafa7c7a77321a35f1acd29449b92300922c53e797e308e0e46984859793cbbb85fdfdd5de916909cdd9ff4a3cbddede5fcce1a957a383f381aa024d1a04d91ae927f71beb9b890cc2cf2f80330323ef7ee748a7c3b3ae43d23d09b88f91de7992dfdfc7a432483afb74d4566db1f9d72d86e6b89b131363095522637614306a68c0c1f1fb15cce67699f5d8ececf8b7d43ca830e5efaf1f5e0e0bc3d3a1f9f9f9d9d5ceeaeee76fc69e622aa081ede2f6ffb8d052ff23ec5cde1f5eef678f7fa3a39391f9d236b5d078f3b1fbc3023a4cc6183b1a3925f5c26b6a36d9a3de2c5a91d7a12a4b450325b2c083e3a3a3e131eb66cfb2668880d45a5709319e2a8a17946c60e1a99333f7ad6fc900307e921b6b48886e154c22bb88f43789e8307a7762523cd56a46834ea7faaec173b629484dbcbf13196f4296952a0a2e828886c77d40d09ede4c5f3ede9e4fc1c35faed60c3c279ae0c29378b4146144205727c48b68fd58f16dae1d19d313357cbe683f3cbeb4d6ed685d3156be7e4beb8399e5eddefdfdfae6e2e7757e7eb5b16ae645d6dbfc315d1a772a3d22d302878f0a85403321a35c9089dfa35155449cfa24753c984d175e1f0f87674757d797fbdb9b85e9e5defaf0f6707a7a3b3f3f1e5edcefde5f61eda92b5686782dbc91a9bfee8767b83ae0a050d0f33f7fc7269422121a3d38f4c522fac0a196912442a9dd92ee76a881376878757a7c7dbebd3cdc57976f6747c6e9408291d4aca34e9d1154a17d27b1025212a3214542951a50f4f27c787d383eb6e570742d9a6babe3c5e5edc8f6787f3138677f5358179f1f1f4fa3a39389e9d3d1d7523331c10009d7b71beb8badfbbb4659fdc6f2ee7d3a3f3737304643f7d500db616a24d58c98e3e6ceea46488047b639963c04b458a6dae5c10a6234c8e78767e3e3dbb5ddfb9dd5fb077c93a2a8ff3d37716e48cbb6b0b2afde4707c723abec19e02b5ce1ad63bd52bfca3036c1f91b848029d5fde59ceba0d0f866f793db6cf5dd9c88e8c90e8890713f4cc4d9bec1df5229ec093e6cffc26c838a1e9b7a6b8a8711386183c4a4a650acc788fa12c194a3a99affce85400d5731292bc635e8cf69a0621dc5147107430b453cf96492615c038c0e460bcc3a431a16414ab18d55b4086ed4ac120c0c060f2618260746104c02c3153649a3015613a60ce60fe618e605e6132603c60d23121326c0c40192d8c7018258c441806182a187e9833985f9803300f987ccc7d40866c67e2f8f08479c260c37c803912067640cfaf531d411a110aaf7e341e0f01326f6e22ec1f72426ecd688f689e63a3b95b82595a38fbc86bd2a8d7148208b80a7fed0ef236490be9ca14c22c2a363c4ce1c1491be2d9f95f404b98c1595cfe6eb3416c82a2d581f86048e6585dc72c19387f7636098c888170688adea8fddf93300f993b61bfcb3824270b386fe942b62549293f22855e09e987abfa351d5d3c58a86ac2f5301dbab4b50c6c8f0e0d25d4e0a873621631c3440359b2048f50f4aecf00d6ba37a0e637a02523d2b356ca9e9d39918c4b88a2e768dd1478ee317523441b64a184b9956f59bdc9ef867dd6fae5143914d1d809f143ba9260fa0ab2049eb60a2c40be8a866426f45964011b45767b5d84679c417083cd5b47373236c48b928756f04d6b814cfffca634c85ea25c4ea1f49101889019331249ac308e4bd7e14a62d9715b1b0a9bcaf804bdc33006ab1bac6e9f1dfc1f57a7b9143024272a27ed3ecb1a03d95af2a8c0523c49dbe0166cb4f8a5b066681fb88489772673010dd63f2dd1dc5e1b2ba1e79fb49b44cce40813884b99a0b76719c5168673ee51dc2e507c9e182a4bc598cee1850aa3e9e3e8639e4297e1142e645962877e8037efb0c198ffe9a05a63fbccc3b2658638885227721f513946b5f5b58ef6711f36b6cbe301b68b07b00f42f906509e66001c4b19eb2299209aed6e7f26f9951637611c330addc80b4c8d7b15a0f1399ec56ae51a7c4da69f83170a465357194bfd6f97c182998f3717aa4cbde6ec15825561a4ef1d83b6939b0764b31e04973a510bc5918558068813a386010a428e5e7190813bbdca99e0477b7f5395f49f024e6884460b3660b46439330f0f0f0f0f0f0f8f1c341352db36863bc82465aacbd52715719a644a49a614096726bef47466e2834248b2daea90200c107d0bbf0a3f0b04d31b445d26c4400413828757c9ea501fcf4330c93e87b4a2be84d29212420c43706b79fef77bf739941f885108d6479a65ddfd1434330bc420049be95992fbdef45278b6821883e0ee73c5cf2482902af687d6aa20062a48cf134deec701238c3f14c408049f84d2f8938f1880e0449bdf76486dadba3eb4c23801d020c61fd8cbd85fa3f7f3456d90cb8183eb6211c30f58a66b4a2155a55c9a2b98ed4589a723efed05001bc4e803dfa5946aaece27d7b4e60bde8005e01031f8c0684aebddca1e91ae97ffe2020030458c3d702674c90841490f6c0915cb245c447574f0f3c076f4ecba9c60cab5475f7491ded1175d38a0468df731c4c0039b722e19d3dd5a0789c6b8037ba537940eb9b603a3b57fbb9a99eab4ac1875e047c99c2a59f0ea9cc4187440d7a9d7d4687de478cd3322c498031b73fa4e1eb445e618fb62053852d0457b7162c881bf58316853192252fd94408c387031a909696732a7519a1a350811030e4c8e2125b99952d0374bb2b13570548c37309276554458b2eb9cfed02a165c210662b8811339b424bd177234951c428c36b0265ba2f5a78e3f42ffa165c35780436d0b0e3c20023288c186b486a474d8e5465e808b2d2ad0616c2047170c28f6458781a3dcc811c64120c61ad2daa136691efd5b63e00531d4c086b81e62f54bca3d211f5afa91238c479986537ef1d14df79c835c10030d8c484127d5e952a97cc1f002c7b9b100ab03c43803e7624a521e51cdc0594e29377f78f89615a30c2955b1d664f1636f67b6e0c0034cf085066ad4f81b606880587f70d11f5cd4a8d11fa76f680c3270294c44cecc6f18fd1f26c618f410cf62ec1cead71862e043545de5ec90b4a39ac6458c30b01e428c947a3fccb2e1457791e34687610a880186d247244b2eed3eb470d84041ff0d2f1ae30b6c4a6ad2a41e59e771f702af9da285794abede5217b8d371d2684d2217d8a8db6d766a7273fd2d3039c964d59e41923c951698745bb9b4049511cbcf02ab5f252a05d398d1372cf056393a4ba5068b94bf023b16263387c9cf685b812b1122a28e968e575215b85135e1bba2aa3187a8c058660e6921a6da4841536093a992a331660eea7529b097c44c5bb3a490e189021fc3e34ed4496a69d450e0eccbee74dace13d88fc954c8d7c1d55a27b049b3797c1b3b1d546c022779c553a635abcb2913b8f3be9cd3c9509d447409fcd7d5e41c39727b25b0412fa8aefb4af2c926810df1d24f969062882b12b849e11a27a5c449b23a022bea43c5cd9da5439246e04e9908112fc44e3a761178ed2d95f4f847ce151281ed9874c86fe5f1f44543e05253e7b7f3a4a3bf10b8f2b4ffd3247350c90f021f22c974d7510102a394ae6edd248f11253f60ff5782b611161fb0d9732651f2c77214951ef017723adf10bd35d58807ac6e8acc6699e6f9bf183be05424f5d59363f2ce493174c056249184dfe5911dba183960d42ee656656acad91203077c90317a34af98fef28b7103de52fa76532d3a6cbd1836e022689e2c32a5f6d2b11835e03da878973e67468ac5a00193524e6a447c1d9f189b051f2985f2ed2f65c107bf2c31ac8f055b6ee32122c5359931b060939a48114998eb8ff50ac6c72599bc1d6b5129aee8379ed457ff5bc1a52913d5d198163ac20abe528be8a6d12a185331bc82bed839a9d7a10a2e2bf533ea9ff649928e541cd95247af6497640645c0058fbee8a2468d2d3840811c2970000c5ed002fd41072a4cddcf4bcdcaff6fe408a3e314fbe6601bf5324c654cc1a7c73f152274edc47cc1404729dc283992e5b8a15df7400729388d75e92f9508cf3e8d821fc9bb9a5387a524f3a260d3d8a6da1c1e3cfbed0805dfa3ad5d418d6e24610728788fa2b39436bf361903015a4004366c747c82c91d849c9882550e161d9ee044ea8a20440a32c8cbb3a3134c1ad5f92124a8f86b8e2e1c2f90a30b06d4a891a30baf5103471860acc0021d9c60eda45dc4d1412c947043d1b109ee5214f541f4cd4ea63fb4ce0460131d9ae0ad7c47092deaf67767828fe17ad639c5bcb136356ad4a8416aebd08109d6d6467256f2282af71f5a557ce8b80423dc5462aa0cc28172bc09b45882f7dd30d35529c875cb875617613429956072be7c3aecc60f2d7294e0325f3368cad23927ef43cbc61760d8c84970ff9e525257fe29e9ca246150e2dd16163da7f1838b2d120d02356a4482bfa46d3d871053bbf61f5a37f2025be75970690111d848400724b8f033774f3b49a4463eb470982c743c828ba739b3a95e8c76a62318e997363a66379d4ffaa1d5885346d36d1677b4093fb46c2023381de3c8097696d38d4e7f5166118c1c097e26648ab82e32448722b88e51a485c4a042ea89036983e848043fa2134d95a7effa2822b8dc99e2e4ac3a4a85e4e5a1e310fc87bafaf68d7cd16d3c741882af4f5253c52075ef3a1f1d8560db62a6cc18c2d25660648d1ae802356aec133a08718b10bddab123a60f83ff1b29c78d67c1df3070e8180477b1ae4c7de4fd9319213a04c14955c96a499d644d203a02c19f320d5516bb362d0f086e2d6b59865231e44bdda1e30f5c6e34addba6d13e0801c00e1d7ee06488189ec94e525f4c1fd8d0e5a3ba2d6ee4bf3bf8c0a9654f7fa5e627cb1c8d6ce4b801468e3e5d7871872ae8d803fb1ad2d3d8954af57b81bab0f105186a81f70245c0b0a1430f9c9bdcaf131b3f4a391074e4818ba9933acddef0c08da44a1d63f9c7b1a4bd03d7a2692b8a10ae1df80a66dda24af3a5d775e06a3484f46c39a85f45075e3f645091a78642c71cd8aa1132e5d5aa5a47ed0d1d72604589de98c272960e2283868e3870ba3ca914254f77f30f0746cb3d698e99dba3c6e8193adec07a76ce489ae75763ba818da927bea15fb2cbc23630e69b354df48e58fa2a6ce0437554d71fb58f555b1b3ad6c0bb999498b32f439250193ad4c0d9a55f4ef70e3abc948635d7a7d2da776dfd436b0b0e3c206fe40863061d68d074943c1d96d2d3c5fca1e30cdca80c59cd3658d66b06de53d0b78e23f7ee8365e082cacf4aba77c12d880c8c6e0ad716e57f5dda18b8084208f51ed5e89a1103a7134f926f454c3555030df8424718b80cb9a2e489deb9ae57173ac0c07b9ef426625db0b7f20b8c8c3e322584a4c73762bcd0e105eeba438c49bf46bb9ec9858e2eb01d3fbea5f47e153ac22d7470814f9f837b7a3b9d31695be07386ebe56c29dbd36d58e8d00227c146865d08e964be6e80c1454716b890cf539259b592c820a2850e2cb077a94984944ee468fa2bb056f1f428175159626a054664f537e549e47dc6add05105fe4f7abaf44f8391c8143aa8c0c48ab8d93a482f1dc40a43c714b8ff1a69b92dc4ac9e4a81d31d246b0a4a59c53b21d01105fe2686c81c3f26494906053e746c1d4d2241759e743c81d1c9fff57749abaac7098cb0d5f3589362aebc37811139a6605e3967c9f732818b1a1a3d44769ec7940314d88280a163095c56f10aaab4365ba4046ebffd54bcfcb2ef4a125833cbd7b5f2fc681b12f8d5dd683a73aae3088c105a9234dd9a3f49aac308fca41482b79d6e3dff011d456025c914fa37e930e0c6d04104fe627b321173ffe9895da16308ec96d2df24924708dcd876decc14496f073140858e20343169bc09faa27e1d404873c99442744fd1a4297ee8f801377a5b2eba42be604aa1c307bc7fc7f024457750627280025b180f64d928c3025bb55874f4802fdb8b13b57f47d308012543070fb8a4238ad29126b32d85828e1df0bf15fc2e548f1e059d6303d745870e18db4c61b513b535a673c0c6939f792786365e7023c761600b2eea705499a003076cf48e9ecd5489630b2ecab43a6ec065351791f81afb42018ece61e3adbce82fba30c18dae80a90974d880d76413db7c4be65fb5065c08a2c793654e6a33892ca183069cd0a583fa175b4d3f1a25146016dca80bb2bdb44416dcb57e1d0b5ef775344b50124d5558b0219f8e17f354438fe915bcbfe44cf5e61a4fa45dc1e75edad4f4ef2afd5bc1fea8265193af5e93598502b0829127bd52a80ee1080ab00a46694d0b96217812f368a000aae03d2ba78bfebc2145c81601e6a878f164cc33c1c6317dda930e9245e598e0f57ced2be774d5a74b7097f574ecd35b82b1ee8941f763d2ec5782af0d7ee31b3a25f694e03d72d64b1541758b26c168a43832898f69ee48821d753159e505fd7723c1c8faae20c294c66b21c1ef4b88ba1da64d691ec14a52916afe9ffca48e60440c1a94a9da083ec52d2f5756cd3219c128df5cbee1b13fa9f422d8d4229e928688242dad08eef5ac35868ca823441f365af05f1c130c9008f625f6c6906123821fe59eee1a82ce54e94370d5ab3fe9df4e74922198b4a66bf5f773f72f049774b449ab6a9264040310821f15d15f8d6a396510dcf65ec5a4c6fbbf23084ea346941cb9b4da81e0577faf444de2a41c105c8cab162c8aca49f7073efae91025d2e4aada0feca98f8994d93ef09b162992d4f081edf2ee90ef6f9edf03a35349cfe0a3bfe2aa077e3c44c516bddb319a074647e4b4a2430a42a878e03c477753f1256512de81b7cf49f3438e25ddb303a3b953453ca14c9d6cebc087607d794dff636b4b072626ef31110be5f1da39b0e527a29d4892036366415850b2d674290e4c3c597ec1cc5573090eecc68eb973ff377025d2940a9153481372037f3a3d249b90eb1dd4063ea96c67e2a672d60e1b986cb72754dcb417d93570d1b2c53c35f03189121de2c4badaa481bd131293e9e9ca1d0dbcc555cd1938dda1aac64c6306de42fcb41873b61fcf9481b718c7cd926b0cca3264e0b38b789d5fdacd791d03db697abc4527d3e9ab18f8a03545c9ea583a8e340c8c7e4b48137d3345a460e07cbbb368ac8949d5fa055e628b8a9344c5de56bdc09f75327353119469b40bdc64cfb395d4126d552e30c2f26dfaef8f9852dd026f71b546639aac9b542d301ad15c545cfb1047cd022bc184b6242ab75d50b1c0a6e8e7254345afc0061f4f5a82c8daa5a915f8adf74f5fe2b56baa0227d26d3ffbf79999a8c0e58f57b0b25c4af353e0ead376c414ba7abe147897241a3fe507534f14184b551acb3a6e58070a9c4cf73e3183e510ea27707947f28e260b2d5a27703ac64ebbd72efa671378fdae28c9433a3b9309dca85548cdef341f97c0c8188296f81a279645095c14535a4f7d49e064e9d41dd1a0af3724709742b552fc088ce9674f9e35d3ab32022b5a32a98f481621e9fad6218e9e08fc6584d49522f2a1b53930c010584d9e56e3d952e62021f0af2939e7b248b5a320f012276daa241544040181d7b40b21d5e7078c12d3e731ebe76c393e602475d25fca8248a2f780bd78fac2ecf387cc79c09fc54a6679ef80499944a69cab93ceb50e783f53e36d750eb8fc92e4a91444bb5a1cb0316da58ee419d773033e93f237fd5cbfd7d8800f226dbf45bd28b9ac01674997ceeb8d393f67001a70e126b34adad287565512b498059bd362361d72b2604cc44e95ebfcd72eb1e02de8e96cd9251f5a36120bc2b091e3f4176f0a169cfaca93e4b5b8980c5fc1660fca7288952bdf86aee023db4ff2cffd2b2a6c057796af2a5a0459c147f7687aa9eb459e56c1aa45ab2433472de555c18ec69c2d949ee89a54b0961a5425a5a4238850c127d5289625a5e4163a052792a7ce21454fd26e53b4ef9eadfdb4a5e0eb7308a9229252ba2505a792f75fb39a85acd0875618675a8c829ff45992455562881105e3976df94eb388a8a1e0b2d3dde34791ae8282d1163bd31552a849f9043749976dfaf81f774fb09154bcd510f53aa613fce54d1284d29d524a71824f21493c84a46c82fd4f293397af092675dae892f299e0fc740e3a6da48f108409ce2a8250fb25187335dfdfbdf1505b821f553a2be75b093ee968d5f15e478a28c1498ac1ac3bf4f23e093ec554d5186324c1c9ceff29fe1a09feec738ea4bc7b4f90e0762d24a193a5bf2b1fc1d7644d16e48852330495de6904bf7a6ae3ed8c6082b632d5f922681317c15dbfa608f6574d4ad63fb7950a5a24821fb718728352a1a73a4430da22d6c591b816876093de8aa94292f7137286e0c7e366c5c89f744c8560f5630769b1358f2511228716836023aaa890f51704235abe9744b3ae8702c18f440f22eebfa91f40b0fbb152d095e4f875fec0a9318f1e927ee094875c49b78e0ccffbc07548b5137f4bc598e583da9b1bdbc321e51c2cc6a492693a045ae8818fd9af7a2d4ed23998075e741491c654decc100f9c9a34653b52e385e01d3865b9fa4c594515153bf0b1b3c8fc21259df55207cecc3af669f7986a313a702e9a9a93de1ecf98cd81512e2aa8d35e1599991c78c9f9f3ca92d234497160afc39489e910ea3a70e0a39da5a8d137b0297abaf8e72f1d750327f3eb65f698d49ddd06f6db3d57acd9c07d9260e9bb4fbdb9064e45331552a26a40811669e03b85dc63b14ae49e85064ed88fb6d7926b1aac33b0e5e957937d881938a9a17cebf6ea23576560fc23d6e898a6648914193811ab0e55419decfc18981462d61cedd22678c4c0559031689d4821a54e18b83411bd2a930eeae3606063b0c8922ff5bbf62f70418d593ccfd376dd0b5c4cbf1b323772c77817388b234d921e5b372d17f8dec91272faf4e8e916d80ca252f792527f530b7cbef5e815611638d71493b64987948258e04dc97cd954635ea75c8151aabe6b79f72d58acc0e498f527a355e0fa3d44f28b51ed3a2a70dade7b2cc8ef60da14b8f34f22e4a0720c5a29f0c92d96c7aba2c075eccf5ed741bdf691a38b166479d107054e5b9a52f1d34f60ef3a694cef7addb972029fd6a38dd09126b0fab993a4d86b22e6cd045e63b64ff1d496c06826e9397e0ca141b44a6045f27fdbb99f04f6935a8aeb223f942791c08f461babea1083d6f5087cc5105cebc33eedc98cc05a5dcec9955dd172faa1b50fd0a208eca6de60264d746948118153ddd39b2a6e4e33915d408b2170ba6a64daadcc4d3126d042088cdb76b29822cb34a81f5a7f63056198175a0481913124d539846801042ebf2849ca3ae507fc697fcbd12da95b8b82163ee0a4c78b9944599ce89e1e30218d8c98a2e59f74192768c103b63fe73f9dbd73fa10b40336f97745d04207bc26a1935e0b1e226891033e7bc4a0a4989d088be2800b719d94d495d670c914b4b8011364101d3c8d84686103b63545ce39a6f4a1950dd0a2069c2719727a309121aa03022d68c07bd87da45097c474e5434b67c1a9bcd51f21e9023164c175f0d4542a84d48e4d20462c18193ae295cd62b5e71f5a8f0316dc6accd11253ffa155afe033fa5daa0c12af332688e10a3ed3a458eaad7713df0f2d1cc55a118315bca5dc904aa612a59ab120c62af88c96ad52cd847c0d7e6899a28118aa60d74eec47448b05e6458c5470e942a50cee3978ed3150c1fb66041dd51d740aee09629c82133a4b483accbd54670aaef3d45bd456ce60a55230a653482985e0bfa63e2938d32429b88dd8af3d0a3e849cc7cc93d0912a48148c7bca964a6bc938c2130ac6b4e60829c74c9d4a07051b21ae898afb9929da4ff09ea3e3a931b3daa027b8efab14bb903ae9443bc1ee788a05fd2fed6be104a32267a864e229c45236c15f1ea554cc9682658c26d25bb6a3fe920cc6c804a7bd2c05b529bf9fa99860345fd2397758aeabea430b7d189d021ba81819625ca21c23a914f2a706d5170e1c7fb6e0c0034ac5b004f7aeab57b264ba51a20fad4730c4a804279e5b553c424e13744ab06af71b62e53d09c64b6dc4a4795983144982534f7133fb7f6ff03312dcc93c794d5f82f7a60e12ac794e9f3e95f608364c8d778ef9b385987704971b3435a7dfc70b7623f89cab4e7345df45ef19c1a818b362f97f9b4c2a8be0e2e6a819939260999d22b8d3a045bf9ef011ed13c15801e994b9c3b380113c16c1c65cdad1ae2d9e9dc543116c2e8fe796dae291cc148051812db8f8824722d8cc39bcdd7f63dd8f08b635724e91dc82a6f7108c4aaaa3a95dc94e22670826a61275c22c79f068290467ad1d3176cc3c6a1282bb4f3a597d8212d99fcf01060b8a0d33780c822f135e1523f5e66b26084682ce1632b49e0c3194038cf40804eb9ea97d848912952d4030f2cd64496f55fbbdacc0e30f8c7f8bb6e8bf39a71f79f881512a37c7b2b5d4dbd0078e86c0165cdc78d4ff91ead1075674722ba5739c0f8c59bde80e1142a491ee81d5bc10b4e46cea818ba2b294f6e9f3aa0a53e09107d6ccbd538cf69bcd843cf0c025fdfea54ad4d9c78a0d1c78dca1d42c12f3a460c1c30ec50e4d1d9e29b44ce9521ea20bfe8b2978d48195a06fdb6dc77ddffb020c0482071d4c1d83be0499e43cf098031f2d7b04e5515c0f397091e2c690511c60a42fba401c7fce024a297777777777666666666655555555556b0111d818002b3ce2c0e7935c3539a5943d6f8788584a29a59452cadddddddd9d999999995955555555add1c472c605016ce00107c66d74c40d225b79d0be81d1218b52f24252e929f370035715337d88071dbdea36b026294733ed49da95e078137481960d7c4a6dd12228fd937d8d81c71ad8245f635996eea1062e33a7dde82a168f34702145cfd221367034291c0bb080086cc8c0030d4c50ef41e420c16f63cec0c752fddd9baae2f67f689981cda582a6d8f9542999b61761a4e0b5051e65e0b67db4e7100b3cc8c067ced71cb2651aef13021f381a021f38fac30113d8828b2d2080c3630c7c0e2bcd6d21a877bd376eb0054460e386871818913aeaea7da38bf91e6128a648c2444c3a33040f30787c81db187935585ea3461838b66cc0c30b55c30b8f2e7027712f293db8c0266d7af3640d1b13da17fc043e703404b86040036ad47064230559377284e1078f2df04982aa0ed354abd975408d1a356ae0e8818716d8ec2c3d62a2cb834cc902db56d1b325396ede211e58e0d365882245fa25f5ca8796a60be0594004360470038f2bf0a25e1a42557712325bf0b00263d972ca66419a54fd3eb4aac047b54893844abaa236bee8a35af0a042298fa898315a58089902d7d5a1ea6288177f1b5260bfafb44dae09959dce8247141811e61694a80f0d7d17f380021fb5327f091dd2f7877c68d9b86156058f2770fe1ba3051f1596f9a2df8b63a36f74181e4e30ff8794256ffe3bff432b25306ca0e0748102b3068f26f0eb5fa7e11f9ab1ec0fadf4376c28143c98c0554e173a223a6e5970091e4be03e47580ef6d9a64dad044ef98945be9df4c12309dc066ff56c1b93ea344202a339f4844874cd273b7af03802ebfad14ec7d1b0d14d8dc06e6acf5359a392834711b8f24a0ddda4525ccbd5387810810f6d27e468a79231533c86c08b0cb2bc7644cedaa30f2d05c343086c4a309d838cbe961b02e3989dc023087cb2d8a53ca432536f910710b8a89ad27d693395bb8484c70f98949d3629d58c0fd81c4292ecad9e36c2a3078cd656883967da2bbd192584070f18a13b24efcbb8762ac563077c29d7947553ea0b0f1dd81d456f341a004178e480517639896422eb5fc4160f1e386062ef46b07c6ed5c1e3068c6a66ee3ca9216a49efe06103469e8fb41293bfb5690d386d77bbb416f248be8a0e1e34e0278b594c1bf4e820f159f0e9175b447fd498265a830c59b09b41075d766927c8520d3262c1a68b119389dcd3033260c1890e2964a9c49c40c62bd834dd3a1949dd325cc1a68c5e4982b68d6a221f5ad60a36768d4ab7d458c19f1279641c954766dfaa206315e96c262f97481a2ac850051f54ac501ba4a9e06386e829760551c19b925e962a654a66b15370a15534f2a6460c324cc19659ce24936ba560738c37395e34c9162cfd820c52b0ae112b692b2df6b9b1a360b5ffdf6c2c7fbbd72590210a3e624b4e7d1f4ba7a0f30119a1e03a47ed1a797254243f1f21031464915c2e7192e50e055facc08609bee8e2868d17a0fe1b5a9fe04d8fa5a4d0195154f4a115c67f0b7054056ad4c0610150840c4f7032e48b9f04991e7deb045f979e1355e4b6c97f192083139c6de974b35751d15d199b60d3c49c227834c15bd7dd4bbc904162454626d81d611d72ca4947d09cc4049bb946dbfd6d4edfa3bc04afaef7f93bc492e9271f5a5b708002a907199660625e4dcc29d5460bd14a703e964cf89feeecb212e32083125c5a0dbe296be8e80899049f74c85c5141a4041992e032bf6afda424093222c17f4a3a658d8d57c40e093220c1fe569bd68e7916eb3c823b0dfe49b74a168baa23b8ccbee96934ace4688d6054eee4bca21af4540e23d8339db542ba3c41d43a05198b603b5688e575f1ffe4f6a1e585176d6323204311dcc9de6f4fe9eb767a4c046f7b7a2be96f0c9e768e760ac840046fbe673a5dcad433559140c621f810238527e1915a4c936108466565cb1123662ca310bc6d0e52a377974e8b2c136410824b5a2cb87fa8a047eb41309a440effcf923b952708f664acdaf68ec9080497dedd42f22c32820c407017a4a7b8276a635c8d1064fc8109e9d3de7966164f1e1064f881356549eea4353bd116197d60846d8ae4f676191864f08115cfee792c6fdc8c49d805197be054a9dcf9734dd497857a602bad8ad075091764e481abd2797eb983e83d0f1ed857134fae1ddb32cd92051989767e134b0b32ecc0c51ff1ba4e42c60a32eac0895c2a2619720aa14edd820b3a705b2acdd5da44529986828c39707e1a5cd734be5a7fd6041972e0d547fde69d9c64ddd1403d41461cb8cea27b530e95b1b5c76181e2041970e0afe3996975d31c826c0b2eb6e0620b2eaec87803779d82d488b15479de0dec28bbfca9a48fe5b4816f8dd77d2f2906391b58179d93a879aacdd01ab828de1d324cc68c1c35702a9578f260daeef334b0a1b73b4a369b988306269e06a525620cabfa0cfc8ff2cdeb9dd3a4d70cbc8be7491a8465e083d4f494ee918137d188391a82ba680c5c6eade039bf572f62e06b93b85ea691266261e0329bbe9cb3fb8350253030aa3607bff1bfc08b70eba032c80b5c52da4759deda309d2e706fa61a29bd2ce40e1738d31872ec982ca68cff1678cdf335ddf77f417f2df01a3d585969b3c0a4f0d6cbef0a5f150b9c8c9a46c85379f7ce2bf026d4f9ebe5bb4fa61538cfceb4203aba2e590526070b11cc829abf4705b6a4e9111d9ddc253705de6bd56e82c8c9bb49810b39a490e29ae797581458ff8f904e459896eaa1c0e84e9e7bc15310abfe096c9d9d4a7fb5f15bf24ee0767b7265ea975ec93781b52c3992498826a2338193591a7563fbe9c497909e145c2530d2d5e3a7be69bc98243049e5893caf20494f24f03909cdd39e75948947e0bcaa73480c8dc004ededf9ab3456a61481df2e1fcbd8ad712c44e02be6cb93c52749d00d818f64228a090f09814f955fbe6f393ae45010584f6f166c7b842a19020227f33dd6a6e0416d433fe0b652be536bf980d333dd1126e46711413d60a3db55bcee9165f2800931fb5494dcf1b3b403fe33ab2b59f624261db05f13fc3f8559b99f032ed25f8ebb796e4138e0440e326e1a492ad47303467dfa4ca12ea96cb50db80a4a7b968d4ea15403469fb4d8bb2ef97e1934605b3f7494c7cc82d1904b7b26b7adac9105ef21c44a9e31867c31b1e0ed7458a5cff51115166c1a13159de72bf8fb9c73ff4b869c82ae6074b438714daa886c6905dfe97ef4ee54a74861051fc95c0517b384a02594ce1a9e2af8b0187289a43aa9e054c6f466691d5430f233d3988c3f399d4ec15fde3ef548aa524ca6e07dcf825076edba9d52f0f13cbdf89e5f659a14ace811667563aaa4eda360749a0575b628989c639bb0d016a96442c186caa1a12c6a5279e3a06094d4e4edff962b6efc13ec862acfabe399b4e99e608370aff6f47b428ade09b6f5ff4a47c70f0d9d13fcad6615dd8f99e2c537c1e5cf1ba23d082bddb926d8cb90123402c198ae18720a410d08d62e555dfa9341e7ba7f60628abe971354fa11cf0f9ceefe4925c53ef0d9d74679c7ec0ef181cd71434413727793957b607594f77e0879eb31470f7c86a452de88631e909d6fef62877860cbdc4582cc19218feec08a6e9a5b471e3b91b303632aa9cfe9636a7c6375e0458fd229fa8a08ca5374e04b9366520f0f53ca39b049273d316651d39003a75c37ed2c84d08803a79dfaa5b9b342ab080e6c5dcc39efe45bf57534dec0c9f4e9638812531242ee06fe26e6ac643a525bbe68b44151fdb14d24a55d5727d060031bb2c7ff8a2a925334a540630d8b8c222adfb0a0a1067e93ca194787fc3a4a9b038d3470fe2987949fa9076ad450a58106ae641addbff6c281c619b8d1dc1d26326d50495fca24689881eb8e24cf83280d992d607491c3062a031b3a4b42d07bb71c6c32f09d2d6af2a01b2e493806be3f4b2fb3a47422420f460e3d0d010d31b095ae335ed2b10c34c2708c95a379549e95b6468d74830537d20d16dc8d33d00003eb973feb44481d3bfefadefa05466f23c46f33652e711a5ee03daa9976515a97a2e443ab58036874614b26258ed89746521a6870413d791b7c27869ed816105e7a4a77a8795006400a34b4c0c6113245543ce420ef00d4804616d8147eda563f29dd22d556d0c0026791ea4ab374b6e0620b2eb6400058058d2b30297bbede4c1e2b7017e397eed17c7b5977028d2ab0f563215ca04105c64b68ef1193c614d852be9d95f4a510b1f5c0161ca0c016526094feec27926ff29324f4c50a1ce085170be800fa6201356ae0481a51e07c83ef77b85785e61ffa5e78d15c7ce4e8e20336684081ad929b4474d2255d251a4fe0bc336e9dded0c13549c309ec9fb9f9a6642a814613388bec7ae9f626059d3e1a4c60745fa3b504258d253016fc5554f654095c69dd14f5784269cb6181461258cda22bfe4b8ee636228149da6ef5b46f4fe355051a47e0ee4646fb9114925462046e528f055bb5f4a6361f5a29b071030c1be8bf304117388acd804611b8d6e4d9c3f257fbc60534885069aa4b14ed9492867ea03104ce2e242926833ebf8a87818610b8d87dbaf92e78051a416093768cd63d1a3765030cb4f5021a40e0f347ef2a0bd50f18a56ce377d22d1368f88089e16974c5d7bb98e4a8011a3de07feb22e9bdcb537ef3804997a21593bd7de8b903367704d5a9dbf49bcce1e822dd4043077c3a7ded79422607fcd9e9ab10326adea938e0ba368230a1466492e40db80b1a342b45fbd0ba0146187fa3a0b181860db85c179692decc165c7061822e70bc81460df894630e691de94c3b1a346084c848e9ae828994cf9805af29fb7259ccf298643364c17efa744a7d5e67c4824d6acff24b8cb13d68062c18350f325d53e5158c2ebd6ceaa2549094e40aaecdde84867a9138d919ade07fd36cad3cc60a4e8520ba3e7956e9cb601666ac829316ccd49b50934d8e3666a882911f39978590fc37ad54702ab2ebfc6d9f810ac69446cc340b4b9517e4f86205572d98710abe36e8add48e23820a3fb4aa0f334c418e685ee1a271e0c8f14517608461e3061a624629d8b0a4224308cab3a6f5a1f59fcebeb840072ec0010aa4e0051d86e11f6690828f9424c58ba61a9a320a6ebfda52b5883344c1a83ca23747b1d82544c28c5070263d2fad94d9e6e5d80c50b04985dc4ddd1235c493cdf8047f9f624e74fb4ca6923cc1ea49bbaeeda04ea051b3051de45a3338c1885ed0a99e3aae6e76c626989cba2b72cc925a7ecdd0042f32a5b49b6189604626b8bd55915dee39488ec1046ff2aed3d896fead9d81199760337f5ce3a80a8be0f9d0524bb0298e8a1c159d4cb50106322c98510926ed5eb8e9fcdcb0f743553083128c90629541c6f4a1a5d436cebbe00bc198310936b7a8750f9a5a29671f5a36106a62409821092ed6a9904c7afda185c50133010b02b0831991e063aa0921a94376f1941990e02e4f4ffa7e6ed64faad261c623f84c2af366b6103289a02ac30c47b023b36e7fa7688561462338b190435031062543adc8083e9b8a52cd4e178448c101062e82b75c25dbef93ffc88961618622b820a93eeade29a1b24f047732f5ef4e9b5b6b66ae30031128987108b652efb3a978a4c298610836e75c1d7fc31c1ba0c08c42303aaaa5ea87cc1e51f01f4679c18d5f4106ae70ec0c4270ee61fa6fdad24a6c808131983108ae247ee4d1397474c9ff0b30ca243043108ce63da1a15de27f84dc308196b180086c2060462078f136a56434fd432b53f03922b0003eef811a350e10fce937a5ef69f1acd63c38ccf8037779622e1df378b258316898e1074e575a4b2693d9074e63ce996e29a253b06ad4d8c20c3ee06d392d4735f7c0957bea694b59d2a4d0f4c0459710f4a7548d1a17851979603ce5fe967249fb1e84073ec5c817b3a9fc0efc5f789a9e4c71534eedc08fee2c298dbed48191577a5bb6a1031b2c0611838f2c259436074e43fe2492d96d7a901cd80a69d94ac51c925ac8066ad4a851a30933e2c0e776a5e89dc6dcf40f07aeac946f86f44a0bd137b07e27fa64d647fde8bb81f110a4a765fd0df6c936f09174882725641f69aa05c30c363039688b23b3ba3ed7690d5ccca91964e4513289781766a88111f7bc937eff3430d93be7d6490b5144101a98e09b54b2a89cc72327c7e3c091e371e068525a98710626f578c55c328d7d9ca819f8fc1e47e78df6505a512bcc28039b279a92a9a9d44ede050e30304006ce334f74ca0c9683ca47c0046f811a3570d4a831630c279821063eea696bbbb7242b34230c9c55e5dfaadc26f4da1b5d34066a9412668081dbfea4e6bb6f95b4fa05764f249be8be5d5b671b6678c10ea1361253cc7781ab102fe4303dfae31e3135cce0026fa3b6e4a61ca480195be0bfa3e897e72c26d2a3052e69b1accbb0189e6cd4050bdaeaac0433b2c0e6ac71737b98fe901b3bccc002bb92840e9e33bba65ebf00a30b626e987105367dd5bac72039283d5981ab204f7b664c1518bf13cbb8b15e84a8c077b4322d5d229b58d014186527a69e213753480adc25ef28b69373486f1478d3365ea91b63c4140aac88b85b59c9f3043e4427652ab3e304467829b53d794af9c79bc0de5a5aa47ce59334ce043e88d024645497c0f5e59d6d59b49c4525f0a694f9e4d75c5b9627818d9ccc94aa18b525d54860bdb29b6b57fefcd111b81bf5973ca946e0dc46c7f16411169d74b89590086c5f92dc69164a2bb83386c007f5699e237d454cd91942608245ba9843fcf879db1941607312cbba9359253b660610b8983fea7afa5c79bb99f1034e7ac4f7329997a69b193ee025073d32855ad1989b193de07334ab246f3463bcd31766f080dba4843e1163362ba9d9019b9245b0909374c0e58b46b3f6e480c9563a42ea1c074cba8a183d96f2d518bd01df51f399a8e02b221b30bee12f7af3d4ac643a478d1a2c30336ac09a567b724bcfa0013bc2337eec1cd94ab3e04226d74ccd64aa29b2e06490496bbdeb7790652c38a95127ed7710165ce8145b24085522eafe0ab65c7365be64df96ba82cbb8ef1d622a6c2dad6072ce27428c9b929a8a15fc6ad2bc69ea3d720457c18550ba2d795d25758b2a58db6c97b285647b7f2a9890f3b8ae97870adecbe458e64e6bac8d5282c729b851d79842f48be8eb4cc15f2991d3268b1b538e9582330d22e6bed348c1c44ad72443b4b8288d822d1d5293d02551b09b2539a9f0ea607d28d8344b3b93dbdd220705a3ea72ad289ddeaefc04bf397a4f8aba59c1e2093ea99074c671ed64b9ea04af75e6b15a249ce0d2f47fab7d69135ca76589be9bbf93724d70fe399e946dec902ce891095ea36849cae48f08e9c5045f39df9952a14d786d2ec1ee2895f304cb3b3ae6e90c3c2cc1b69daae78b5ccdf9af0497429a9df00d3278e45082dd572ba12b7766c8492eb6e0c2bcc063127c04ff4d5f5f9204df31245f59cecd5ac21a356c54223c22c1276dbaa23f7520c1694d297edace11697d041b3d47595987183cd28ee0c32cd8ed4a3209aa6d047beb96c482e8cc0f414630f95e4bb5018dfaa87470c6e25028100744c16010c3307c625d01f313080010302a0dc782d160a448d23c148003502a244a282812262a181830160746824018100805046150201408854481504820516b9db90671c09953c3ff104d00fea586362b38cecec9445044aa0a4ca281ddce3e486c0678d35135c259486dc1bb74c8fed6d5ff3bd463c4a6c50a504555056e23c2e9c7192efeaa0a612982df0e8b904d972f162419298ac77027d99444e53f450ed1135dcc41cba0d9619d326d012b65833afb40ec70e01baa7a120186a375aabfcf87a7a23f3eba2603196357ac0f389d023232e5f8b66a49778c742b00cd5aba133b897241428069ed9b4b1bbd2e1317b5b9341ea880a2a32905b70b39d21f98b07136f58c70e9519fb82151005ab1a277142ddb283ddbec027c22ceb100242e780f78fa174b4f35008b97855e708c0eddb90fd3f91709a481dea4d6d52aafb7040a31e85c8eb153ac29e84c923722efe921a6211336db4df45b6a43b8fbe1a34d1e87a5a5415a76fda794a08cee2e4c2816dd070b881679812e3f47444fbb0f02a6c221058b1effbe44a2106fff080044615dc9d963569084c9b3f443f5ed648248c752577d994b8b638af5134417471c8cf4fab456e27efa89a3421eadf740d12f384b1ed83ec46960881238a0939d7446ed081f83879228a65c93285d3b44c7cf25502600a128303e884b14ac43a5b9a356105862fbabc62658c92581bda1011044592eec764c341840db3e845ce61f51f0dbdaeefc575fb6f15d5e96df9f9bdc14c32e3405caf196a8e5fff0fb092d3532eead586ddf67dd359741a18f356b4a54c7c271e0f6c004b2af0e5b2294d1b98053c8cc10611eb1a6fb73bceccc9300eb2a55b77a0b3555304b1913ac5877f58720078bec2c7de64e98f6c3b90c089ee25d7b4de69b9f6a9d9443099f77f96aa5c15a6ffa08155d4b7b44be316f233810756f9793ad41eb39bb5dbd4cb803cb84db18f2b4f3e9c41f6d1252a4bb8d783ed61e3b2765666daf4c528f2d48bc2dc80254490f8b18c04c7cfda26c0c6d4ea9bcd0a2ec5fc75c9e868ecb0ce614aa098e4e6046ed61d49a9d78fb3fee61cbc4e24f0ea590ba18dae721d933fa054edda17cb664c62fa9622d2ea6f1ad4638af0423e64ef35dc4db046f451a90262b46c1e263b6ceed43472720a8103589da56455e4f7c175c9b8b9d5ebbb3d7d6c49097c338a68ae8f607cc0ed9fb547c892f550cdde50409f4503b8d1a5e19aad4dd03d4637aa4055f5defe022ba2967389a4d138e64d07989661306df9c4c5818346bb6b633dd99065e0cc92d8642ef6519dc1b6b2f6cd841b6a2bfa3d66e0c695d8e1603484b71000af7d81da913ff2e147142c4c2e7c642cf1be37c0061b3fd8a584eda3f3a104c0a60f2cb14b5293226056a8593014b4950e3bf1eca4a7cc00c2e38a284800fc1a32b387dc20a8d97b2bd49091a7a3d80c5f9f4475ffd13b74515abe0d53a41cf9ce88d3df9e9e2d8512c8e1735675d7eec7edc107270057a63af1b49b0aedfabbe2dfc8c5a9dbccb7475a902dc3c06efc57e2531f4c01a619f2988b8314719404a9bb119e35966ce8a28b1f06baf70c24778ece25004df46d380e78452ca7856958f1b65fd7f047c27a5a62a126c1f14053e25fdae7b43287cab1f90c8c7eb60b19519673bf735e60fb2ec49a60575f4f268258278204908eeacaeec5da3f24a9fb7e007975710690750abba1739531228416cd633d0522a515847ffc5a4b89285b0d6f57c182cf9f1bc62d2aed976cc91bc7940f30e336168a8a3d18ec33a859ac0678d866eb6674c7354b85a0dd78156a01a93cd094d2b429deee6bf07108e4e5c87ec2409ada82cb4a14f2eb4cacd7ad71dc1471b25c4903935386089370108d7a9f2503580724093b98ff2778353f635d72a5aa0f39db6f1785d30329578ae80b49968d31941774ae6052a42bc5c0461aefd76238ad4028c9ab003f5acda9a7d97f90011b2c3326ffe97b7f8f5a4e675a2d0eef6d94a3e4fbe25ba24b65d769edb2b02b4389d12c329ad3e52e8587d135355f048e498cc171bcb8a3d79a78995a7820be964ea809f65fb0c7b830eb4a410ceed29828dca0f17dc081c17521c1145d995484ab5cc44654faaab8191985c43c5ee37bde7ab1237f4726758c876e2cd56c2b65828e94a65c7428654a159e273790fb1d1c37272ef8158d7a647b55ec8e3fd42e07b08b91961573286ef5686fa610ff29fafb8f64e7cdf37adc40fe15080115162f8e93d3d950003811d4adba50b3268cb34422b65394ff059c064ccd4a2158543b335b9688426310273a3f29f7d07b295f3d4fc0481a391661f1d135900c9266df5f36e529a66163d89b6818f467cfa796e273f5af0f2e58ca8ef2f6cdb7c89e405e6ebcac1b501d62a65d542cb1e8682d552945ed1b34834548b938a3dbb387b127d80d8beda4e130bd9ea48f391556bacdee887b736768391cf985df19906d42dc2c99dac3642384e95595b3688c969c57c95171945aa5bbabc883e8b0aa6f2693a9a14185a540e1adc4a40d382c753f3ac6b43e0f34105e6b5c7770bed5e6becc3df970a2ccc958cf24369f26db8e112f8f317102cce41d84ac03d8ff9f2425f6f12ca1c093a70fdf94c998991f4498035afee45682c884c871575395f9d045481e31a0504fe6a802e48c2cb45a2da057f53a952369ac1ccc9db427dafafaf37a0900595d8ff332302314023b6f52280be63f258e1feb3155500337e70cef42c77a555dc56a5679cb371e61fd3d0927b00fd7656769ecc78876ef20ff2c28a41c42258a88d7536c3bb2503a4b63600bcc1c4faaad06b12c042284ae2c21057088b51345965fae18ee323339b08c7f7921b82f0a2198bf565cec607202c8d8e0da17c57398adf9e4012fdbfc1ba420e6ef17270d7bcdc1e685636e61056630a86e2c76a05a07d563cf731b944caf91412711c2eb17a26004932a0b9eeb6b4a32504a1b1ab50a31b14a5a2142175728ef190c816a2c76f5c47980de15c8400d97a2927907b086d581003be50825f111227010abcd950c237b80234c92debe9425b33ba6c38971661bdba0976e4b1c172ae82b5b7a563bbdc4860aacdfeb499b1109660a87026c7cd40d2d64f696ec0c08a3bd9f1c4c49902b9bdba128222c4ab189a2aad5e19b8ac08505cfd1ef8ea8ca1ceb708aeaea2e3c3895bd88bbb8d7d64e8c0d48bda453aca201abc5327d5e0e205c7115364564a214ceb80cc0090636b6c5240cca98699fa3606c9ccbee99f7164d4e3f5bd4a535d43a92d3724a6de1269a8efd5c9fd0d92b95b41ac95fe66db8dabc01f4fa9f8ede3451fe27e9f3eda4bba9c56218b9a62387d0ff377a36a87505142ffe3d8b15eefd67a582860fe9baf165a70be8412edd110f5595068a5de4757df737a9673ddc6fadaadfcd7741b10965b68a001e15f35975c8e31379ba1f9fe818bf7f17d92e0e24aaa10403e4e423cc01743787b1a4b55141a19b44a2185212faad04a1f1d24cc0f6980129ce2f02684f8eb45a1711ea7c10696822128cdf9fbd07c56a86a638191a67c6dd89acd5219f783c51bc3a29ea2c619903dd01d507c3485f540c08c3ab752a36a800a397515a90cde3437366b2bc3ee43e182ff2b0354ac7fb28265fcf02cf16ce759eb99ebecfd59d219f76f37e25c27a090b81dbec97cd20b905b94413938023a5665582f60469cab15985afccb232aaaa00c68607f1e6a7a179678bf03258ad56c9ad06103416e9b18754798cf9a33a7bc49ee2f97ceb2c5428deb5386f3812a086c343dd597e763a4c1422502c4772b10ccb439a18a5825cc7aa5ae5fb3be72ad168636214d6656192f486b85fdd1d716268adf6b289681ace3b317d5208ea7165e58adaa80ef59dd53985def1ae8247a6da51508d2b169e714185873ba6236d98c5695ad0c5b6b6dcda9e69b94f12cabcfc5c1a8a38483129b03bb9498e36c9e45ac698ac58b11e0fbd306d4e3523dd91cadedfc62ee2f3dce3739febfa5c9d863434060548266286590b2e943091ab81b28c323cec734f7a532ac56646677ae1a49eb2808718221acc6be168d087980de3034b26802a10cd861c034c5614414218b92cfe0bec11551df9833e6ff001acb508906b4cd08873a6932dc6ded81c94d13092ba10ad9d0f8d08ebdd490181efbdc169f5d79663ffa454ea593942248d6cf5ab8c86afdf4f9a7485053b318683cf0587038b98c039790213de8c46e659f4c115b8bed15c7de0791b79a183645ab0407b8e2419f6e0fe2abacd5b07854eefc94b63fab9cd7d0af28e16899a527f7a790807b7271ad89397bcbb0de85ecfc31d3d4ecb1330351a16fb005f26082d4d9258cf2b5c4fc0439d328b78ced27ea1bc82fc3c0d8df6cfbf9c3573dfbc5ba9f6a91e9e0acfe0f04ae569b5b2e3dcc5769c178c1c69586f1d34dee7f0fd29454f3b749edb0bdfd5870a7ac05829b9410a0e50909fbce0f7039e988247c1b42a839549c63cff5f8b4d796fc3b3f7fa03073824c707e51f46849eb276244b9eefee56a2f5ec27a28012f402f21f6e13eb4ab305c93949ac782911f96efc2d68b0339ba816cb4461de7043419afd9d004c8d616c8080aad947c6e6dfa1d3118510bab20614eadf51945b0d10a503151ce5af6236a7011145829c4d7e9809515f63eb18d8c55986cd2b21ef23df30d007439b121ecce08954f32616f6e5d4a7283209c47b48766ad29f3d036a8e80bab92748e6df41b2d08110baa2c612edaf6174190910a5631895cdbf52188ad43b1806c3581aa57a4408a1ab7d3174cf09586be2af3574aa76752ea9b643d241bd935f4202de6dfb70be87b8c9a8e47ad4a985887fdf63b2325d21707d850364348cf80271cb8bd357079ac1404e6be451909c809322a4d316c255b4c9051fff2925b7e3e3f3a3b684dafb14f4259188ea01a870cfb626daa30e1bcfd88fb48e0a570b0551c5731e9051bf11c126b2fe6ecf7ed8ba83b6b7f23102934ada797279ab4aba50accd2afad3da38165405a28f26382ad0e615a572c7b9b660ce6d585cc3f114be7619f48c31ff0ba3ad1d8a533497e79c81ddbbf035a34148b708f8650f3cd04207496df515497cc0ca3cb5dba4dd52185b95e05e10f5fa2ec6b09725b038744e72abf6667fdc243d71b042f8a620d7da8ee0f7a4438f8557ad7dd5376b8d8028120a2a964e15b3cb1d4d7489b56097a134b3552eee43b302dd7ba1e2557e57d077af7c6e5dd2390ba2da1df7a82b93895a9657d9283b4dead1f4260a1380f9681103bd80b0c8486fcb36580a087cc6d83c9b4834477c3738b5d51faacc947d58281d8aad7fe0ba097dda19e6528ee76f8a28d144caca626488638a5b53432d15bfe621bdafb68eafef5732614bb89fb5008ec5f284e20b04f70ec4a23f477effccd106c558d4b7528961ed1efb8d4260cb52d3fbf7b5b464492a59b1b6b89ecb2b89821738c5f1f4346ea65da82dd1bb2b6c4cc1aaab6dbd29931f4aa28d640b3c75c8715ce4b27740b1d21d91fb18353d829da93991ae9401c52b7cc10efa66074ca0c55c9adab29182eaba080fd268d5aa27a606a8c8044810bfede14391b0159f6fe2f1b5e3ad614fb840d11a1337edcc3b14e14e334eb5ae9e906a7a3f727324c7903d69e5a06d6f66834dc55e002eafe4b62e102bf0d00190785bbb50666223394995cf037a9fd6a4d8e252587113952dcb53168e7afdce3b4391422051405721324461c147173ebcdb2da312ee322724eea8a93c0c60bd01c5b2ad24b730ce4194dec0c4887642d330e65d8d5ce3a9001cf57676cf8410030cda597dc28a5db60ff1f8d362ceac28453e2f7d29142ef9ce2114f91995ab4ab90e489c395e324de814952a3fc5d42037cb81ef4559090e02cd96fa1661275d15b90b0ca8ac6767265b25d3d73fe7e4d3906890801aa08ddb45a01f3e9117bbf3e60ab358efd2c0f1d1d5e2eb954f70756415da71eba7e204bc54a5809b4729720e2ecb74291bdb02d647d2279b06f05f1fc62c1df57c8af658b2e788744dc72995bccca4a843a00245b21bbf3387649a3614a904465a19c02d6bad4239222943e5b74418243ebf135975a51cf7019453a60ddd1eb68313a266720f3fb6ca69dcb875a26f464fbb0ba77c640f822f7e85076bd5892c2107f9108181efd56e152d7da11e2135ef215183e04e0340e8e30734c49c00c093c688b0106d8d2c50e049ee6c51b4eae27f71fac90af2a67dc89e6d18dc48ed617666d190d3e1a942501ac53d4c6e0001b894aa2fe0fc67e15158513dc63e931bfc13594cc1078a515a97aa2973c6fff1bb38e0b1c9b3c0d195ee7ff0e93d8ca57ee1390661031d1b2b6e1ec99a250ebf336fc4c68f1af6eb48d4f7c9caee76638c351585287e0cfe2b52e27801d845759866dc9cfb444235bb482ef72dc0db2a7594aba409d403c86a99d7c95fda41ff85e7b8177144e2b72a1d395dda85a06ce9836df559f8558ab3421d084351adf4177208f867faf6136c55f9f6dba67821bd954eeb526abf45bf84d29819f628336995f4e2ae3011537654913f478cddeb70b6f664452f1e58962c16f6b1b9918912e87ba6b53c9c7cbf2e587f065c7be079524a075bcbaebe38e21b0c3c48b9db5960256e430f5a38eca08740f362fa4500ff6665613aeb4bbac517cd4da283983ee8f399e652385899fcf0e043cdc6e1c9d4811b56baae5d1c13ceffe7e3bda7a184e1d815537a4bc7d87d7c0f60455f0dfcb502453186945564c1141b93b233133671d1822738901afbcb8e1d3b0eae4dbdb6372e07787e874b019088196aa785b4383d0bdb7ce1aa0d86422b834d5b37e3d4901f8af6d14d397ac8069404b98a873443b1bf53f248744791af015bf4081571549b992fa65048dbe96fd209b4e228729fe1f6eb07c938c32b53b33423838c19c17c044453767577888f52e72486ab91075da28a86047aa355d74c1bc4c5dab3af560ee7c937b78df01d828f166480a6937950b21750705552d1e85c2df02aa6168c8282353bf98f752d25e3f99f92f17c844df8c40d1c650a5becc793f3af4683c28efd6078cfce002b12f5bc0f0355e003214122850d29320c32af2003b5355a5e49ad767110b0a77203522fb01254baf2eb290f6a45688cec6accaec892a0536d96724d9ca274942f66c8c603ab316b695092c70d74aa0961a6421763092bd024014ff860bb0932156b32a39815275fcc78b4ef9a47d334161b9cbf31372273998bda3985bc1f0d6d44d66b369addcfa4712b2ed5495f453c020484c1d9b4f8a46d570a923d4d17d48812c3faebd77090799cce6d6611cec7e5b8cd0fc3640f8bad70b1447a69bd50a21cdb4d5602fe5d4f6128b9f6c10eacaa281609eb3d0e844f758a6d2a0063d42baa5a0df7c09c801bde26f48d1acbce83d33883235562505ac6c520fba8b7ac99df2820bd35e1c687f00c1ce601558ba14275342b69184b188a0c3abbf9faa2a1dd283d62112cd6f5fcd5681b23c3cc5c4e5969f6e360e83e0f25eb476d67a6347ef718b465750602b10dbe5ce3ab07004173777cdde3056aead6436acb193eeacf78f7abc3b621fc7b77a70d968806924e36627d6f7f6ca3da787ed373d48cff077faaa1feab2bdb76fcc4b883a3454d39730a7dead11ebd8c64b89fd948dc8ceb49db458c44b8e94eb82ac02e8acfe439b58d785085233d86af7c561292f06bb781dda017be72ad39554d901c4be5bf4007d087909a7d3abebd4f39ab0ce5a9f1e2857f8d0f312ee016457f09d3b4dc6fb0e2b732ade2cd0da510bdc72ac37763b8c863d147a9f61e8da4f236a486da979b549bbd7241b8db85cc7fc0c91bc036879ed593b6bafb5a2b6b935462f35c05ad67d2dc55c68ae7a2e27a1ca3bb0cce318921275caedb677d5e572df213f179ad691e04072eef01fc0170e411fe891e12b7f06cff8ffa0ab624e5ace757d93d5dba2b1e61e7f5e8fd7cf7ab77ecd1f759d5e77cd5768ed316d0fd2c0883bf7c64410cf8eac8fedcb7d389c2fb44cd27d434b7948af36e3dc521bb47123b0d1283eb88eb2fea9cc9a4b9b6b474da875b5488dd6425a5d436a448d58ec1f71e2d3bf5072d6429bd7d2dab796ad456ac7ad4fbb6d6f5a49abc327ca9d097f7d3b803e190d393df97f665d65b29a6a955b89c8d9b594a1055bdbe494a1d76e5e2dd9b376a06c6d43a169f76414376a3b1bedf5b05a5b34f41e34bde4110f38d96c53fb4a7f463e396e606f657d43ee1cabcfd2f0dcb1d8672fb705b92bb0514161d9cfe029827c900af52d3c7f4a2117f6bb86622d4e59e81d64365390d09a14208101f21c158fee11e64518ca1a8c01d14f063850b07a8636884cdbad5a7a4d1e437bde1ab646a44f9dd36386d536b9cd4c4b3a08b8b3890a4e20a48e184d46882c9b14738920f06e9b07a2de3ea79a1c96fbfeb01417e3dd0257c3ef2bf7bab55ac6014d55ce2776605e486bd3f0e97c176c90459f4ccebfad0eb5225ee0f8cf2bab27824cd99c7f88a3290372a62f4baed68ff3ea7b0095199c0e44c37e7a2e01a99c1fcf7785a3dbc9060a84a45ce7733f6c71c7c36f58e597a0a66e17b0794cf0878a10deb8c087aa31e32f17112bd030f2961169fe15d92f497de993a850b3f573a6fcd287529a40c4b113b5cf2d8df3649d101b8ebf562bb22b8128ccb9ddbd39a87632a105bf04607f23ebfeac015205115c5ced692b693bda08cb57636a73456bb1e93ca0395021aff1a5974fc4b49ecc87ecc65fd5d11849517185ac84fd99cb73cc7d13a10dea53b42d34c2bf4df4064d69e5b420eda2856809ed41bb6bcf5a59bb6e5e7ac80be090b4303db7cf4d5ec20e74620a7f9ca6c219e32b33438b40cb5ca15e0f399c8bcc54d3230ea58db7edc5c7466c1a47a5698824270b0400e9cfb1b3fad1ba4892d7ef11bb3578f8d71a266739b324295096769ad2d94affae31a4b83507974544f29768935a3e09f0932e0d817ed744f735379f04f8aa47a814690392b38729d9c2ef6adbc6d5a9c63f5018db5217b6da72b0816210b3ae8253de93ce7992fe99c8bec06559045333f394ed4200227b18ae668809cfc576f4e4843ab26eb54618285e21b52365625fb9168096a5f01aefc3bb020de372da8580a4e9e6c5eaecd99a415a7f107cea08217cc2b08c440831707036383ae0a936c800dc3c345260c616932a9797e079784efcf222147223f8584775ff098d1375a0ce0efd7a27956e64568995456120910ae00781893fe35a97a3092e6ed116ff994e136175cb24e3ca16765f6a7cc5795f1acd95dfe7504c320807483c395077f530aef978f66c2b06cb9cd506af04f49155baf74636ccf0e2167d73f2b82e26693eb4a1720ed0286043c2ee753111929098a21205254009d09f8a21140fd0137ddedd3ad4e567969e0cc0bb03e7f36abf8f58cdcffa2a4f2ecc6649917d28123d4d64b654191026aab6fe056445cbd1475dc994e39e1f043be3a88598b3a0556dbf894e0f42878031a66be13601fc75d561cdafd6b43de415056f50e21c38c80e95d805722f7da4e73fbc11883df950ef7c789b0f7bf843bd0222b7f9b861bdf421037afca39b40b0d71fd13fc8923d13c012670421a732100769fc29b3f139cd166ae3d5b0d4c409bb2c7fdc5437af4bece30226eb454b8752052bf91abb1f45c51ee744ad21297779cc27a3c8b2cabbb58859d51f424d9c58627a5b6b06ff419f1f28050da7db27722fb5931aa4e865952c681422137d31f0211f1a1164372dbb84f0e19746184ed30bf362a57efd2f9c1f0437d1028a7a1e343566049640d3178015080a544f3313d0912a0b7e84149b453d6cafc14e1a2547e167320f7b27987443022bc8f2f049a9e8c8433bd07605b3c61974092abb440480d2e3e408c83365a50acb3e12fb86b77b0c329725726d56b882d199d82814c995539acf380a117523d9d18bd7b5c2f361e09192ede1a3573f486bfa625daa49a65221517548b60e6dbf237dc6e833162bbbc3be59df41aed2ab573cb4aba8dd20c908b29e30961546fea57a2f57cb687070fc26d48686f973a1b31108bf7b5a89bcaf05ab75ad721119aa3829ae44cca0fd639a6fe64e9d849992f3f1a5b9eb20c8f31fe37c78561302de5844dab0220fc6caea10e8e82a7b087643c8eec32ac173aa428dedc0e24c7138a01bf9f57383ab7f9fdf77fbbf79f2d3347b27cc9635f29f8005c750bfa46e9e1e8f0e726551afc822f669e45c6b4c97a743b30ae54e447552ac3dd06d9bfb66fcf619f0d8f28373c87e2a605db71633ae50fddebc98154964fe9d06804d3abc5277a3cb6a4c8a87065940e347db0d622bb567a266252c8c7833970fc1842ae10b00cbc00e4ca6a0c77864530ced6ce1be5ff0da1f88826fc183314c4e954d90dcd8aa7c7e54203ac1b8af22a7f541f4426b8cf32ad48bb27a5caee1b306a3a0e431c04ff4c286ef60464b1964b1a123cc6653dbe3954e771e6a017dfa4a554048058a3c2d140104e07985b8eb3c485dfabf245a842340729470a7f8c4de2b95ddb90b3fc3e1b95cb3be2af561ae66b622807600fe357a06277cdeb8c16a8392d29cde82152e4e8e40848fb8704bbc7432b1ebd2de0c543ad8792d17f5d764fdeb1c8981cf913a93431bff7d5d090c59f49cef89cd4a518568a192a3c1abb6fdc825054bd4c573cfcc033189254eaf3ca651c46560adb0a86287f471b2edf1a462d0288f73450acba92af8f657568f896e6d705126d0d205162b31eba5372cf27245dab01e0d23e11eb8422fa6dc3608aae30bc49778a46d603dc2be5b0b1065557b84e48ca2afd2153a2b56d58e290557bfea3f4b5e2581e95642b635797fb6657792c66b16cefcb6cf31e768681fed91bc454b704edfcbc3069e817f65e52861c4128ce22bd2b7dee7dd20d96f1482497ef54cbfc610d503ba68cd6fe4809678be64e9f215a91057ca0dc12a0db24e28dbaefb3d5e140380022c3ef403f3fffbc6e817a82bf5458da690abb680d3f7103ecb65bacbb51a86d6e38f289a2edb763e1315067a2e2eb041cc64ca72538680a09e90ad10a87231f6ddb3076af7794135422118ab0beeb22f3c6820cf88dbbe89d91fba72d92b476df60060e4b5f43e20a59ab30038b0c15b6b7545477fb76f8ad20af2930d96e6418411644b9b655300e1916e39a5d95a8658a97890958a07616955c4620d205b1708b37631f86c79bfe4b3d133c1c5911234a3dc82ce29d5d01ca40e9a538ea043e5193a1fa1057cf04d412400bb13c00b00d2a4642f2db48610d29ce82e5cf9e9da9f252f9fb81aae537fff496497b80ef963265c802c432434a6990b1f9f2afb5105a56af86c619d0670f8dcf7b443e6d3502bdfa3fa86241c4dfca4b6da7463234df8ba2f6aa8bd5825b8e0aba27d8ff1dd16ba820e7206db36fdb11c8780568129077ad8c41d6f92f2dc92036a1b2d6bae6092179eb5950f93a6f32f7387c0414e87e82cffcbb925d63fe8ad58e6f164c704e442f515810852d3b64ffa2f18bc825995686d884b8995407a1afadee0c90b6dacc15ff944152faf00b465f4383dabc6d51bba8771497ca61edaa267134215427fca7935a3b69b8623945c121f31c2791e134bd2f27f4655eb04a9f2e612f5bbf18589760eb9bdfa31aba5e1c77d277b96783fbb1369a089b169812be5872e7e664930316976ec9f5ce23466130cc9ffb2e73728a81decbfedeb6309a6cce6d9c329b4f554b6bce7827e9ed715f8beccd19027034aec642873ec274ca2a0f3ad83c480193a82e9b64f93c60cea05ae0570ef36ec6b28654da989c2ba23d92a8e4d33dd0e342593529103975cc045cb1a2487a0986a964ae4f0e296ecf28f648709371b1f6cef56749dffe25f9a30795aebad5b5c9010f1bc047ee18ed33a27252bfce0d450fd47f2c6ab8aa639825e49dc60262fa4e687ff22512340a6f9ee55eb554f1005da0101d5169120f400020a8db9d4fc29ccc027da88d6e1823de7e0737c00863d560eb8647c253093ddfb325895ffe98bb85257d46f134edd9093c98c5a86c47985db8a87531ef088416fe913f23af53aa04ff36ce9ba4b5e875d07f7329d48be80516c8fcdb9d969c6be203f1bca5828bd9e3c15d693a0d1d818e164f6a5a8e92135b1e6ab8facdefefd226a481d2fda8f85393f95ac26eff5e58f6a8890742320283ab06ef742484aa991bb8518adc3d737183209f99736feb9b6af47c38580566a323c7dc83c86493e4fe59464adc57fe921ade491764a505a19dcf8f3bddc5d62616382333b2bb6912738804de0403817ee5f489ecdf736794a44f369148f6ee5ff86b55fbd811cf927d64d5da56ba0166962526b9b965c768d78783e007dbd16da08a9a2c40ea536295094b628413f91735b8722f624894d9826fb2707a7a96a08409e0d038b191ed390466fe2960c37939aaa965857e6a98d16d62b0e9e4f6124a0668f56921b27c3f56d153649e83800d9642fefad6dc3ce75839539cad08c8aa7e9a1eb5656529fa2e5056f2d6df57ebc9e6203f01c243c66c1254dfaf390c061c2396db5cc370b8b6f36716d557fcfb1d3157a20a0edda966d4aa8608ae9022f92993b630a9833942354cb008e5835318d1b3d5481248c231c96a170883d759495308914badb17ab570b9cf99258def046fddbc207c5cfa1a0ae27998f1ba9467ace564ec90dcd2802bb6c229fedea82fd1566fe33f0292a8845d1fa8108eac63475ffe698d790df940296d02c2867083f4acbfd8946725101bd724cf3d1abe2605dbe12f7a11e47d5f9e336f8125f6e079b8e2dd21063da7401316879d14156f55bbc69c957a1e1555c61a1a4309120ae8f45992f724d513d63a076c8ed11e65467df206ebfd5c458d0789b67a3df0cd0f58b4df1d390d8a274a2ad7a3bd2f7e8333217b023b8960a70beb9f28eca20b5fbbc91e14b7809bb49b7220fab838671f26c4314e971aba26e2f1ae632d8d68b8927908c14a09695e26d4649eb0b31888d140bc83c3bfb8bebf3b5e31ffc515bd01f7fa15aa8eec78c13490c25bdb24b51c7ab537e172ef932d598b162efd652e5cf40ff66c732b67b7015f2da70da6219841bb6c1680407f1cbbc9a87e8911ca490b15cf24d594c7ea0020acd3f7f5d8d4ecf1d2a2fed909576ff5235a024472940d377c635dec7ac03e201de21f7536d29535bde74cf35947d418036644f22563265cdaf8400a32591cd99225554030935af495df074ea6b0ff0d79991e98647a169ea43d2489dc9cf0862b78beecd57bf044039b6da167d7a6a74336246d413084b45159f37dabb61eac9da9234f225492eaadcbdc46dff2e404ea372f6cea4294c88369d4f5bd4e4641cea28d70ef6f0d050eb3d7910b461733cc6921bdf241313e441b1ddc07b44065b9593a5456e3cb587af1568f738f552f3aeceb1aae1e11857ec9e7fb0a4f956cdb16d9bba8b303afb84b546a9ac28f2bf091db83ee0691e62a348b71d8be86c3d3ca1f5e3860cab25be3b25262b7e17db076308de42f392d3e55601ae3f8854462c343310e4573ed5940710462e20fc8b351514a1e7058214db871ac7ac484750f98d8711fe14e8a4a2cc477ab2d2775dc15f6f8ac36c559a678313d97e74bb93e8b8816af731eade6eb485111b0157c2b254bb3c6729758596a3e244fb43a754706edffa34d9eb04a8743aeeef20d012a8bc24afffa0442b43e240b6091b0db882186798f699a07ab6dc5fec039e8b6802e05526c66b59c4c1697c0410cd89141cdccd8b989c279f0bb53182421e3f246a4df53176df5304b510190354654388a3d629e34263c890b8248a35fcf248ee12c554290b25a794d8e4ca046c0990ac8e6ea41e0dc85648912b9a952e13a3b7d29623ddf4d47ce21f7574ee80f24d56f4c554c7e2b2e9991037641c9220288c65edd16e0d2f2cc14cd956c613a77df4db331e96e5e84258b0bddd03c7e00d4c2a0faebc317006c7e487799f31ea0a047467022e1c44ab0a3540b0a6d0013c0c3c0c3c0c3c0c2c25e2b73e4d7af9da90524a8bd43b3c1de2c04529934c49a6c879c3ac66d452f21bdc77f0139c0b870aee0a310a854aa762d20892003207dd73acbe34c2e4ebd741e4a088d92d319f6495c491c741f7f2923a9d7cec32e1a0c834cac5ee3ec917f10d9ae456f2fcf725694b03e206c5bbd3bdd5bd69fb7806206dd042e652a68389bb8f61f0300dc2063d3e434b6d8d89a7533f7a74d90d40d6c0688955a3ff6b6bc39115c6c80d1ec90d7ca43ad6041035b401240d6ad222fc4eb824a8fc972c40122263e950c93ca6c617366c60dd4005c819f4ed7c5b328e92a43433090a6b006206dd5468083dda366efe560990328090a18c41cf9592ccdd1fb7416cf400220645d6ec8d5d856bb0510e1e61308f202c80844133cb7f5f96e498e27cc30718fe23c78dbb3e808041edf13af96df367d0231c593a74e4781fee3dfe0b9a5c397d0ef9985f5d738e0e63a418102fa8a779f20591c13783205d502f3ec5da33613ac50947d60d8306102e28a3f9bf5a1ff971c3ce00b205ddc2b505fd6515b7651c59c540b4a0c9e5b2a0e84bc29fe6d62432806041bf6c6964e85b6ce966844718233d6670ca868d30805c41bbac3896d9db4e92e11e09078815d4780d0f72378c23ab0afa7ff925a5e48cc8970a9a9787b757e63b49467a4718470390292832427e3ed19795c4947b20191029289b24bd212b2eff940847d68d1b3e121c685150debd47787c2c592ee2c8f21e090f3046f8c68d3e5b010814cac608409e5036409ca0279917795e1fe34e0e47968f19243a3690f5029026a8276bda52a54d05bdf0880d6ef84870201026684a496afe734a154c6084d163248c1a1c9025b00044096dfe3e7e8ce8d091ec0def51cc4e0e2049d072c36f65e5b9ce998223eb86ef08a3078f2a5c1024e8259cf09777dcf652ca7170f2858f3317801c41513e173abdec49e1bc94048811f4f36c9739e8f854693644801441319de4b4ca4d7e002182daa62f7cf25879b32d0e41afaffca9a41c1e5377425063952499a49312574a5977000982ba9f93ee75be98f01004089cd262d927a3a503c80ff4aa5266fae3652be6417ca09e2a693f77a86ca57d2fd45282de2ac1e3ef97ce0b3ddfd989f2b877a149e5efd77b4a9235dbba504ec5978e27732e349fed8ac144a6379b71a129794f85d2a5ae4f12be85266b2c081da19795846da1a7fc4fee3ae7192eae85ae497c0c9ae7d242773fb9f9cb7251d6ce42532a46c57de7e43926b2d02b55dd78be66e82b89855ea663491e0fb14987856e494e2513377deaec2bf4fc7d9663c49de833b94237edfb315f4a501ba65668b9742c654a09b142d1e13c8312511b4e08ad42b17cea243f13a942ada052ced1a6046d73a642d9ad0f319bf5a7c3890a4553790ede5e9e427dff9a93afc2e8fca6d036655399f76b47d9a550b4648a29db6de7a60e29743129732f957ca8d38d4233d1ed1b71a1377651a83966f8937193c53f149aec5c17ea3ce54e6a50e841e6bf5f4c56dee8139a5ef99e8efb29f1f3842627fc6ce3640db37542df6cd3aa5c194e282a29fb96d7d826d43c935d297da6092de6c82044c62561de4c686e1b2be4c905994e4ce8a5f34f85ddd28c99ba849e355c4abacd74b96f094533097a1793c92ca64ae8290973b127587064ddb861490945886f8ca9e4e42e773209c53ea86427eb2409f52d539b244bf75d9e988811095d2c7e50e1ce83849674a6e46ee1f55df22314fbce976d634ac229b523b4d1f3ac2594a811da66998a4f5a67849a33ff4edf8e129be38b504c4fc99833c594795184fa7992a753594b63a612a16997df697193252549661103118a9097192c7699958871082df46696d898ef8e3d9311310ca1c9aa79fd8d27a57cf91b310aa15edc984de69210eae6b0f04b8297709af71163107a5cdcce509e3adbcf59871882d062c85142b7fcc39529108a6f968c6162731266b3430c4068bffd9ac2de27b1242a36c4f8831ae72f96e017630751f231fca0cbccc84bbe190c62f4414bd6a137a8cad7797f1c5923bfa31021061fcc6e61f468923df438b26e90f4b8e1fe670c31f6a0e9cd202fc4c8a0bcc4c821861e14fd49febdd1d121461e142df5db69bbc2e9330b0e31f0a07dd055496c07257d6dc3c6d91df40afdb6a0bae352109f638a1876d04eb7443ba5aa734d8da8801331eaa0e7584acc9adde1f359e38be48b48c4a083be2789927dd93389883107bd832ce94a4962fae4d7430c39689a723c2567cf1bd796e2438c3868c162d649ee41377e0947d6485f1562c041cdbc93415dedeee78f72c47883ba23f325bda61ccb466588186ed0ff642bc6d80b6132598388d106358bdcfc88cbef2986d8a0689127736b0e7262726b50c3bcafa42c5342570a11430dbad9999843bd8c85c5d3a0a67adb0ddd2941c4408396bdfde249ca5492b8cfa0d798591293e6511e629841930df2e4922ff55d123cc42883769e5be393f0f457a58e1864d03f84be8c7349ecf01ec7188316e63efd8566fe14ceb1375c47ef4870941862503b75f68c121f619c63c020000c214618b454fa75bf259afcd4d6871860d0775f4eb8f686764cd71c627c4193b2c71474578e79410b11a74c70cf5cb2635dd0cf24f9ab45bfa90b31b8a0d56dbec60cda29a81c17626c41133ea9aef23c354a92b286185ad024fdb8a7d29c681c3f636441ff0e26ac861858d036680aca33bce43c7d05b53d56c99b51f9253231aca0e860d946553a121ce7811855d04cc924425c5e7e90a51b31a8a02929a7b798bb6497950a624c414f2a73c885b6d3374d0c2928b22e6f443bc6135eddc8418f1fa5cc8011230a9a8a4997ca27c3f5a9180acac62433e992bcbdf4c4868d3c448c2768233b9da73659c4b6ec043d85ec1376b931956413d41c3e4e924a774cd0e653095399742ac558821a3c5da6d0f6f01f39ce470e10b4ffe831e23e5260c34628622841ff30f661d225193a49d0ff5e4fb864fb61498f044d7909d1b9374bcd47d08476b93ff9ffb7736e043d2eeb248b93929ce32e82a694f68dddf21f934d04cdb3c7ab3ec443d0fee38d7fee08419b131774bcd0de650541933be1535cbf9b5c18085ad89f16d34157a8fa07ea499b77a3421bc3076a78e9747a96fee4d8f642998d41999e6b79a17d988939446b4edf26bbd063d6b895e4555941892ef4fedaecff36a12e95e44213ae662bc9ac27f49f70a14931bbbf9297a0e6f65b683a9f788bec6da1c91d6ef704192cfc9e6aa1664dd94f58124eb624d1420bfff93e252963a6529a85163bc5c9b15292ec5e92857a423457d60f2f56c742db54f632a35399bd0816ea7b2a2985b6e8156a49f992cc418968d22157e86ea2def292f86f06b5420fa6e193492ae497ce0aed7484b90a45e3c77d0cc25325a95485eeadf993aee01597ca54285faf5963de830af583984ee26e5fb0d23985229a3a5bd29d5726774ca1e79cfacdb94e29f4123cf6937462182588145ab06ebb581e4a8ee32894bf3f6daa928f0a1e8a422d5946874aff71627ea1d03ffc28b9dfb66684a0d024a5b2895d927892d8994f281647872939782649f784a6b4e4d16f7eb7b9c64ea89b426e68dea446979ca84c64689bd035639ca066fee682a609f524415805d764424b42c8c73b1f73bb1826b492ec94b09cf53d9c5c42d97039db2b7512c42b4b28ee9e63492f42c95a57424b196c2e3bc87639a18426e6cb13ee4b85acd22434c124933da71c49683a4ae4ec4824c9fc152b73ae4042cd549b3926f9c40ea17f84fe5ff5a6324999c4ab1d81926d11ee17021aa1f559ccc8fbd1fce96584f6d59f5e3eb34d6a8dfb0823f98247a54c427dec924f2c6313cae7d71d1584af09f36e6c3b26994ec7d94e0e6464c224496e5b4a5c0707323081d0712f07f997c421e312c6860e19969051093df35e9924891b541e1513c8a0c4495899f65839c9e96e063226a15858d22e3188a7934b7064f1e091fcc8480f12f8f831a2c3c7156b850c49940d37c8884442a61cf4bb32a50c3e8e2c0f2026c88084625a5ccbb6b249c2c7c8788426f75e0e77ab3cfa6f309805a57afce0a104198e281b25a3116523063218a1cb9c7815c3de245d2e42d1d029bfb28fbe5b5011ea8953f1429669785f3212a1ed094ace2bede460930c44a859692c957decedd2ca38847a61179e3ac9106a9fa04cc6a432320aa1be7fc9d99784109a123af7e710e56e9b3308e524d9ff4a7b0a17640842f913132659388fcb3c105a9c11a2275e1240e85f4a369be5301efef983f66e7d5756e149939705197ed0aa33bc99ce7bb14bf7412f31f7cdf01f3e203a93668cb933197b50dc2d3be68d952a147cd106197ab09468529654a88c1b84a60bf64987699091074de87676504a6df00ae14191d9957b4c93244931e601114441c61df4d1295f7938ff4eb71db49ffdac33425fda741db498cd5fb7ea467e121d3425e5d225ef680eeaa76022d47c5be82907cd2c74ac2d6937651c1479d29f9cc634547770d09364e289ea246c56ec0db95529b1f5f26e383cd69fa05b6e83266eac8cfb41bbc5c4064d25bd7d929cb5925c5a83665bb5259aa43d41a706e5d49b92299934baba34a8a1b24a9727b1910d1ad41c3669bef039b3c6f81994372df9beb65499cccda0e524dcf6cd2469b3f232285a4266781d3de92f4e06b583f26aeb0a77221e833e4aece0ad49e7681331685b614b3e53183431b9c4d47573314b60d05c6c838b9d942a73fa0b8a6e3b6529dedf79d75ed0474e32f94b7517b48a25b246cb8f884a73412bd939f5bcb988ce6f412be966d375da119fb5a06c68ce5c820967414b72777df6eb91f3612ca0ce37aee237be82de29796a11a2ccc4fc5a41f9182b7fee2b49967daba0ebf829d9bca482a2a32be67de4959ced14d424937c79620959722f05fda4509225e9bb6477a3a0668ba3a7d932fe29a1a0cb9f2c3bba4d643c414f3165c78a39bcc43191e104459d4abaa53541b7dc8d1daf4a98a0658c9f4689755a82664227e92beb42e7392941376d573979de943c494a829aa4fc5e2a49262468250865679752ffc9a42368c9b4e7abb7a4476c23a895eb839ccb65655c04dd6b339d8a39e4e88988a009eae5723666f724918c216879f3f6ed9ef86c492443088ad6c82b553229133c484610d4203e2595a7af6f2392010435285131c7db860b1692f103357fac2a994d92aa4629c3078ae713945e78fe98b2ec852247f8869cc9e185a6c3b89b263f49dcd2d985b21d7bf51f3ce9af8e2e3475274c94384adcb29c5ca8d9af63e84afa35e61117da07752f2797ee1473bc85224c16b14126415be81ee4cf49792a4fd6602d744f31279c9eaa581ad242339b51be751b7ef29b8526931ee557329c7293938526c444fb09a658a8d94c2ad9e4da931882859a67628971f9717bbe421375299868670c973c57e859c372f06b7f17e1b5420de3c9538925c751e1b142d3e6e39a3e5bd056b955e8616286ca9e2cdc6aa30a4d4e922a19aee3f5cf26159a6d8bcc1bce73f2924185223b37974a9d5d548c3985963f57f2ce639beca6d0664c5b3a39e860e92e853e722577a8203e889614ea87e5a0938e173a996c145a9724bc779844a18789d9741c6527fe69a1d08328ddcb95639f7c1928d42c268c12bfec92e7d427d4f8383a7fb4f284e673f2f535f394387742dd2e4f62cecc094dfb34c9b9c74de8a3c41ccc338658864513da888d31c4b44c6871e63ae7dc944eac144ca897e7e393b8dffe4e5f422b490675a725cf7e344be8a595736967395382be128afefa64a1eae2564aa18416468385f8be749ae94968bdb1c42bfdd141fd48126af80997e2999cfa3b13094d3a4d6d6382362569112434bfcda6c35ce611faf5954a88234c1742c5aa342a25a4112584113a74245f2c421113084944044210716301218770de31b2e386488821141052081f39701a302084103e3c470e1e186040c82030441035420251801040fc2101217eb87180903e4420840f28640f21217ab8918307066884e4c1870fd7211282070384dcc10e0708a90318211840081d1e1032871322871feee3461c6e2020040e3f7c8ce878030342dca08090362020840d387c24381a10b2060784a841022169981182861cec8d3398a10c3ec020c3c8cb08198318b8022161f01e619110307c0102215e78404817768ce4e01181102e846c814688167cf418f9e163a403202159b8410e1e18e8e134e831b202068460c1291072851c3c668458a10a3542a8e023070f0c3420640a52f0b18090282420040a399811f2041f32429c3023a409040861020d7844c7014296e005085182004292a0ec0837fb947749522624a89d4b10f3163f4750636c3f29269d72e56cbcc71508428ca008ade7d9db4614f43049042db8f1454811b4fe3031094a9874a72c2144d02b864ba7c424c6bb7221435053880ca6c438b252082142b82ae74f76334111b4e0460f4282a0a7ec0c32da0481a0c8ad6dcba23d8f92319fb88ec483901fe8169ff4b7999d9ca10ff181da9b4909dfa0ee85fe1aac64f39452cb563a7673ecb8918c00c20b353f637adfcc17e7cc5d28bf6757e9f45d07cfb92080e842134cdcfc4fa2930bad5a94971c93aa0d73d9710307ef487a6c550d147020478f1f3778f8f001082e948f29bca60a9d7763fe169a870813c284c7246cb7855679fb1f766c949cf45a682af4a9aa4d7a2fd34d0bfde4c81c7a631273c7f42cb436d17c52d92b0bcd3a93cc2243b5273b8985fedf713b097e9f354e60a1998eefedf8a33509df2bf4927ae45d083deac473857a49e5944975d989d8b44211facd24b1db58a1e67f73b3985cc4696d15da9bfacc1bada942efb6af1b1574dc184a85a2174f2cc9456997e951a1c9cc31c8cf5f82de703985221f37e265769f2336856e6eb2c8c8709de2684ba16752fa8269119fed5b5268212e7897fef6dc95c5cdd36871f9a444149a987b92ec736ed74d120a2d5b0a1f42971028b4a0e3c9cbb8be85ff094d8c9554cc524a558c7b42afcf8a59e64b5f077542b90db7259b1c73722839a15696f925f9839fd272137a92ad245c529a9729a9097dc455c89994529cf16442d70df32763f7557e0713fa5e7c3993bd3f5fe8127aac5026f97789418b67092d466b0e5bc1249584570945571e7dadb3d849779450540621468f2c7d7e32935084b02a5355b2e2e94d128ae9b07757c2c228218b84dea9c2684eb290504cca9d739217da96aa47e895ff317492fc74ec38424f5adac7e37fbd5605a4117ae6247e5bee0b27c6082d7d5ef0cd7862ef912fbc474490d87b844b6ddff01c3d7ea4085a70e302208b50e4ba9389951fff4a0cb3a077f8098c0d52116523116aced667ffbb51b9734468594e9665d13dcae37d08f54d2a294bbb089d1d0da1081372f129e3e62c2984b6592deae492648aaf0e211425efe7a67c131c800c4293bfdb2a36fee960158820f4f4268fffc504428d6f71728e38296605d9b081c347820310fae934275e09ee49c7fb07cde3d3ec75ee1b31fa41ef124a8ab1c4756bde3e2489d212258e1f3b0c1f4a4a7fb860a5754f6838b272b0374ac900640f7a99b4d9e289d224b72f12e500440fc7cd31d4ff7c32258eac1a2400418d1c02481ef6132d154a5ee57064f9e831b2011ce4f81f1cb861c3068f14e8486c3002869b60c7084860822f4e00d60082072df5c86cf2e71277211f207730103b249790ed41c60152072d499933b38df8c9325900840e5aac2fb92a1d698c95ed8e34da31a312fa99c536fba083501a836c9841094d8965f5659ba48310c291c563e4878feb61d63063129a24c74a928f093349d4304312fa5f92d118c3e47023c69135831d397eb0f3c081a3f2861991d04bb2114206a56297e6cd496640a26c1c13cc7844096638c21f0b42e67f3ddd98d188198c281d3316a16df8e9e624844a1d4f7064f5b8b16344115a5c8ad5a77465f37d80c138b88186198950c62d477f78539d7d4684f659cf928a2ffab74f0ea185373967ec5e5efa922134693c9dc526332f259e422816a7f93e7d5092d6f908a18689bb7af37751791c842685ad2ba94799c9bddd3304a1cda8f6cdef49c593c47768126604421d1f3d42eff38c550c106a752c19de22df6e7bfb832e724176d55c75f61c8eace30146f2c3878391c39c30c30f7a0e26ffde44449b3cf5413bb71b4f928e30830f9ab9c98f1d25bfee896fa4cdd8c331068d9952652a0bd6413c430f5a188f2987af1c0fccc8837e55f264c778d9b267061ef44cfff69bd96325569971072de5932544f676d0bf5d2f8941d8898bd7410bea3f67b3183463a6837ef2b493f0497a93da39e8a6217ec47e2f07cde2a974b22a1f074d49a9840f11257f901d0e5ab565d17163c34cf437a861fc7afc43878ccfdda0496249496ad3bc0dea98b527398c901f8bb3418b318c78977b78d0f41a347dd38a2bd10b66b51af4b2fecd1afa171e4f8316a676b33ebb68d04a9f9cb9b47dfb09da3368b2155bb69d19f4dfb025277d1f3ea9b60cfaa994e13bece5d12f193419971b2ed78e38e5183471e37f98d34a661e31682a7858270f933068e26f54b9a8246050f3257562684a9f4696bea0c97c25530a2b7941933663d5bfb9b799a80beaa63eabb13a416889b8a0684e6209febe6dc9425bd0449be0f6be4950ad6b412dcf1f3c8307cba4ce2ca841a58d21f245c68f492ca86153ce3361dcb4c4f20a5a329dfd35894f4abea41534dba045e9511b5e7a15d42bd93022d40913642a68e299ca29c98e915b3a53d0ba5cc4e7ba6a2c74a4a007a1a537dbc84441cbcacea5842ec96376a0a067adb11226c70977e3137493359db21a11154cd009ca8b6a934a99b0095a2a6d39f9e8e9b91099a0de99e778c2a7ccdbe01294374d1b4eb2787a62a704bdf43f6cdc14b3687549d03cb79cc76fcb265c0e09fa96e4c9f63376de6f8ea0c89361495f4ed7a61b23e8c1bcfda47011143b8fcb6d82f0bd96087ad09c7385097f4bca21e82264aeb11cbf84d0118226059b1d79b90fb7982068bb5f234ad05def0341d1b145654b79de74fa077a922f6c4efa7929c5337ca0982849d6a912eb853e72949d249dec9d4dc60be563124c4e72ea54776c17dabf85e5fafe8b3d9a2e34b9840a2d71366f36960b4dd0c9eaad93185449315ce8b5a97cb369cca14bea169a6455a764d7166ace774e165c2e4f580b4d8e38d9cc0493cb52450b4d9e6ebd3a9d472f3d0b65ccf7bf4653fc14cb42bdcc23375bcab261120b4dfc2e07ad8ce1e207165a8a99bab4c39db0ec15ba9ec69c6496fc217785a235a762b8ca1012d00afd62948e999b8395b88b90005668257c7ef68a9fddfa2ab42c63baee9224890422b061830448042db8f12301aad04d89b3394c38155ac793249d41b3466850a1c9ef687e0bb714db9f421384c688d6daccfa9ae2ca702756c7949742fd0da7f4f387149a97aebdac31c6f7d7a3d0a4204c7fe598b29d49149a6cf3b4593a9edc16874293e1bac49dbbf8d94940a15e12374f09a22d63d22774b35c428e9ed331959ed044846e9edbf2f0c1d4092dc3cb292194f8fd9a137a87ef78e2e41832bb9b5093e42698590ae2bf26d424348fac3862428632a1c91cbfebed4dd0a7c484a667fb4edc903d1b73095d932629748caf4d62c812eae8abd39354291dcb4a28b293d0b12ca7b8cf0e2574d161a595db9b8496414c94969124d49493c6a046cf98de98486c7db2894142d13e717b8496afa418324b786ddb119a8e3031c9f8cd1bb711caa864736727fc2fa518a156ba1894a758d52e971d0958842698a5b0a94f8ad03c5e4ac224e194dfe889d08498949f9d468426c89279bc663e849a239bd4e5e6cbcf0da157dc8c31cb6ed2a9c34228974cebfb7674aada08a1de59577e53ed3907550206a15bca783ff63196ac5e109a29b1b537c5986413f64068b245954ac265125ed380d0ff7f932cfd41718d493ef95e9377c90f8a8e9bd2ee39585e0cf7413b99fb6327311ff4373b4f9bc23d68a5c4245d923fc5b14e0fe6ec77f69dcae641cf9952f6a4743ce8a553f0eb1753f9e13b68f9ba52669d9ef4257650b3694ac2ff7f66c7923a184a8e25897739871fe1f891634ddd48001db49cc44ca61c47dcc473d02c276da52f891c344b4927d73a495292a01407e5ff94e0a026716c7f2f36492627bd41dd39b919f12508d9233728174f7ecfbd501b14b5a53fc33e095adf6483a2e5e4fa9c8227a14db906ed64c7cbec9cb3767dd4a06c9ee6934ad025a720a641d730c1e4913188064d36d9d8a0a772c7cc9d41b30bcf0b9a54d2261b3328f2ec72ff32883b212b837e498e79f30f611726832684be6066a71dd4a8c6a0e96062fa6352c11d233abeb0612337016250b67ce7820eed79e40e83362774dc7c379df2de0480417f8ba1ad4efc0b5a0effcf1ce4cb9cb85ed0c4bd7069948dce25ef82fa3d2aa73fedb275422e68a12d660c262b85cdde1634f74b9b93b6926465b4a0e909153fa524b2c93231484016f44d15c455ba3c16d40d5ddd2332c3c4daafa0c91bb48fcf5fa7206e2b2832b2c1ccdac2c9555093bcaa198b2f6993980aca2529a93c69be36944c41cba5b64e127b4f5097958226293965a65c924441eff132135d92a0806eda11b921db2768df9682de305ec27cc9098abe503a7b2aa59117d404e5332bc70695e674944cd03a336b77bc7f4dca5c821aab92149abe5482f619ba24931f93f49f044d9b684d39c8aa127f24a8d94d3bf7fd7f4a82ce11b4249f97ce255db992c7087ae56c3a164fbe7dee14411383face110b1693e61041139358b28c9f5071461c8296c13a3c650b85a057e78e977c5b39c8170445775d503949a7ba6420a8b136b7e4f67c5207fd009539967c429d26013ed0ed2441a5e4415bee8ae985764a8f0621175e282707b74c25c5b4a9b35d68a72d5c073bb55592ba5073c96e494ee28f8f4c2ef4da5ccadc2b949658c9c085e2b22979f2fe4d95958c5b285a5f744a952c7cf08b0c5b28b23905937f628f901735c8a88516ac24e1bb5c941021740119b4506e940cfab66983e93d0b4dccf8c83ecf14eb3e5968a66f4e89a50d8eac630119b15047334b598c5fd22c2cf4d14966ce9a3d6bcf7e85a2e775bf4eb8309a94aed04aa8bbd441e79875a715fa49d9a4bdb0b1b5c302c68d1d39921fdea314b242d9986fcfe4f555e85aa6e6ddae4d2cb755a17e86cdb4f14ff7254985f6ae95b3092d41859adbe4a04d104fa1bd7e1eb1db30696c630ac504537ae4550ae59352e22461430a35ec9496effbc9b65a2063148acca5831a954c5909a215c81085e2e6a6735e12a6849e8442cf7143a83f75cacc64648042dfa4a438e13447e8cf2712c332999262b8f0a799270a157c4c448b230bcf0e647402d1400627b4f8023974f88f1c386e30073dc5b4298986f8e8a493837682de9d8e7cb951c72193dfb32363787050de3da96465311a6f50b38406792989dca0b8c5b6923cfb9879b20dbac5e592c3a72094f86c507393cafcebbcd9caed1dc90d543aa0b1062da70fcb63b93f1f94d4a0f5f66fde24deddbe491af41b39569e3288d80c1ab47793cfebca847bb1cfa06ef0f1dcc1524aa3c49841dd7fd72c11d1942cc98d3a8ba051062db3e23f633f932ecb87839188c0d48d0a040d32684a9c3331c6207325d363d0f7cf84ef28f5f01ba6470fbfc1230123eb0234c4a0e7fb92c27826d1c1ac30e839fe8cced26252ce1318b44d822633415f8dcaf9b9028d2f68a2fcb7a4515692e0392bd0f082265be5b5c9f0ca40a30bba6ed6745662e4eecc3b5cd04b8ef915e3ec87c616b42bb55fc292a44fa8b1c240430b6ace494425d9f3c4895216d46457165e5ac7d2854e40030b8a5d50c2f8c6cf545dc681c6158c8615d40ce11e26d0a842e9c4dc7d19c6913e72a423d0a0822654787ec7fc7064dd701d33d891c347190f684c4193e9c4bc15962d576e181168484193b56ff1fe047541230aeafd8c987c2dca53071a50d03447afc297491b667a82268cf8ff64a3366f0ae9487c8cf0e0020d27e8364af2d29e2429e5679ba0de9e0eb541bc62de4cd045db6989490c9fe458db1b682c41b78d5f328bce589d9494a05e7bd89c6e5bc692fccc814612b493e56385d83ff165773ad04082324ae87810fa11b4fc939412b46d030d2368d556aa24993c455063b2aacefdd9a674308c113030d01e3062a04104cd4d8ebb2054d0bd7169c0232018829e2975886d10e3ef498560a0210465b4fbc59445739624bb1a01168d2068ba55c1fa24a51dfa03c113443e46433c347e90bca9fadb3a5ebc638707bea871a3060a4050a368f840f3924678295197356370649df7f01d366cf858fc83482fd4ea707a7eb2c70a4ae485b64169124df983c7be204264178a9631cb79fe614cc9db1e4474a1c61d13339f9d3ae4960b4db8ff70620a9627639ff820820b45868961a9c44b723fdee293213a496ee2c81f232326f01f232228c303115b68412bce2cd5c8ef367164e5a0878751835a684afb644a92f6b528d960a4070f1c81082d1479794ddf39c746a5e0c8ca1c22b3d0f4fffee5fad8264fb7cad1030533d851acac4044168ac921cc93944f495fb3482cb4a033f65472cd16fb24020bb553a514c3dfc7d75c0a22afd0ea4aec2c49363942f33088b842392574d55ffaf3ac39d60a4dcf7f6326995366f722acd09418df545275d7179bc82af4934cde2a0f23f25e52857ec9c5d49724c9a5ffd3059154682925cf6d9795843b2954689a83fdd8e8d315a2738a94d4b59df4c92b49396e60cc98640a4d5d0a8f2f6d954bff31a2021dc98f1114d4f8a2868f1ce8d0919442f1a04a744cf2a4d08250b22589dd6d6f3f0abda4ace17305d7b39645a1e80e22348b1b0a3dc6f7987ab4575d0a02855e26c43c2e66372b3fa1d94942d9dbc88de31d4f283fb715cf53d7092f3f6486ccdf38a17fdc701d2bde832ce94d68a7c424cfe8eb5c357a4d68724adcf426e68fbb3a138aeacace999d6315c498d0ce669387123fc6c7b8c825b41c3c67c5d767bf8f2da105132ad397d8754ab812baa8cc8bd3ba4ae13d9450b4537fd2935fe4c571129a077db1d2bfa8d3614928eac44cb15f772a099a4868d9f143ffc8f064260512493a8c98bbfaea72f0830718da3b727ca0c617353c0c1d890a6a7c512307fe8146a8bc20f208ed925516d7e42dbe7147e825979426b1d00e228dd094991cf1e7e92ab4ce08fd622cab2d290917165e841a94a62a9341c91c4414a157dcc6d820dcc418df4722b4fca43d65b16041891f115a79d073ae733984baed77a77233ffb7c8108a264ba599820aa19e26cd745a9384d082924bfcc87110ba65ffdddb174f721205a1ec27a5c3c92313087dc3644ee94bee181d40e8c9c42c95836566d7ec0feaa6fa12762fdcee587ed05476cbee1a2b227d504f25db50d93b6609973588f0418df3b02e11e149d01d8e2cac81020e341a44f6a09c4e4a86e59631f144e731821a5fd4e031d243033b4650e38b1a19b061430f5a6ecd22724ff897e57164f918493550c0011b360c1944f2a09cb79e0c3bbbf1438607adb2e4741a44eea0ff5f882729a72d13da413ddd72d7bdf184cbba0e7ae7cd24349e69e7c574d0468f2ed5a9626f3ca139e8314e6f0efbf3d9cd23074d535e8a3b715c0dd4f8a20609dc06236058a941240eea9879e7dbde24efac1b3a92ee24ad0c2270d0339f66bb8c77b2f8e70d8a2a25336ed0c3a8ec254e4bc6fc961644daa0271584d55e26ab9c713668e29a2c267163d757bd06b5aa34a6b34de14cb646440d7a7e0db29318f3cb09118eacdee1c69840240d8a52594b7bccd0b129354283e48795590b44d0a0987caa54976e88926bd5800d1b366c5c9d415359dc32094a689635d261f818e9307c9841f77caf5562f09c41a40c8af789b9254ac4850ff7c061c3860819b424f9b999b88c75e2c70a22635053d2b1b92fe5cc41867064f918e161b820220645e6a42e4e949c3d69587b0b2261d064ebbc9719b3fe6512e7f0b123c7221b44c0a0e59f580c2ae87ba592c817b4136e43a8fc4ac40beab69b92245562c8ac1dc408912e28ef1abfa4ca301c44b8a05dd2399e8c28d11ab41fc710225b504f763139c85538ddb17c94d28236e697b4286d725031dd238c1fc98d248864c13f51a344369f902082052da9ac983fc959534e572a82c815b47416540ab2f26be671c70c729c20044610b1826e25b9c711bfef29b68410a982729784b608cb53414b499d943c743261df0a84c814f4ccf2d85e2e16df495677109182e295b9597ef2547c3f0a9a9864386933f42971311414cfbaa727681df43a4686ffdc25e904bd3d67d9044d8f0e9eb5043d35b2668222536cae3ccab2681b97a058da13222fcb4c259b0a224a50bb933621771ff3f44624095a097ecae2e5bcdba20409da88c5c5af125ef425891c41711346948aa134840c1231823e7ea6a12a43bfe90de540a408ea57779c2496799ff644d0458c903fa2a487a076fd9d78d85908ea9f12de20a81d3f89db9c4d2953920041f9fc71caf265c473d00f3449653149dca0880f94cb7faa82c6ceac782ff494bf7b5fcf753f7bbcd0629f2468cacf4a5a5246464880bbd0435c12aec43179e92fbad0d39bd020535d9b52995c28d6994b86fe1617ea770942278b99339df88c5b68d226e1b4492fca3f9966d842b3f22f0b2d622df4785d735bfe9b213c38b28c47d26305366cd04213af4b7b94269985163f552e9d64076161862cd44da3824a9ff4b69e5b8519b1d06eb38df7cdb6553ec1424f2e3a7ee4c9afd0e382ef88f5e90a335ca15ce9cb964cc6d7aea45668a5e95a4fb6850a3358a1872f492f09d9599e3b1466ac427993b594ec3e69c20c55284a0795bb94797d70532a342f255d7c0925c9c89425cc4085163ad678978af313944a98710a4d186bdbbcd211334ca1cc5c296d76b1ade2efe1355000821add6384dd04c804624629741394c8519dc3eb9c1029b41bdd24f39b280d3346a1e906ad11323a6698210addf2c40eeac6467672c13023147a923166bb0cd3f1abe4c20c5068aaf4840cbb4f08667c42d3174b5912764c5737cc6aa080036dc346f200a3cd0c4f6829976eb1badeebf3744253b1c1736e903562c43338a1c66cf71a36df6383199b5093126d23229b478ef07eccd084a23aeef69618c6919583cff1636487598f199950f355fd58e8cc6d9e2f42f0458d15b4610626124f50713f9d97ca30e312bab9f8a7f6f976b31c1c39624aad4e30c3127a028c02a8b44f6542692c108983c150401000902967020314000018141a14064391501487b1b27d1480035024264834321a241e16141a140bc6815020100807c26050200c0a8401a140483c160514c51f2a0b03b21b2907336d4d86b1b3357316ff74bc3a89be68d11babb4fc3139e8b6ed9afb5377d70b290a7d1e78112f0e279636b09344c54a306e772c682751ffae301657f81a6bc2f6c02dad2a7252aa095e98c3de30d44d65925d58dc8144291b9ee629cb93487625f78486ad8e3d968c5e31ceb8dd112247166988216601ab2caee188600e0f956ece9ebc32a66054eb9a2be905dea7190e1b30a907f7713755db4fae420700e5638065575554f83958b3cac301847e96937039688df8d0e8ea6c2601f9da195a50c0d5c9bc39e422460dac55f1ed92207e79da3df21f25489c60cf81a3c4aac0e235bb965a04ca965bdc2833078a6b52ca50dc4c5ca93ab323b68b56732c0909d2846fe41be491912a5a31dd8607241d4eebcac1fae35caf6cfdaa917a83ba46d67036aa7f082f3647e101b3995a35b0d4408e51287333e97c85a87a23e86dfd3c5daee58d18985b6a013094eaee226b1b015c798bd426f1c5802047ff5827a5476ca9f178553fcbaae770fb30a8c1eff39edbe39b4eb3e2e4cd856ef2032dcbce2db8f1c1c751f369a6e66535ad76561a0d8d58388669d5b7de337cd92d3df4a80f4304e0a98dfa5ce08e58ef71d997a3e25eaf86b7ada391e9ba8b5211c3667ca574a8e4511d0238adb3e12c491970e0e32e0c0ef91f81de1d04a9031c79c3016ece8eb604c5141cc101861c2f0721a526d81b5cdc6c31ed2f54f251f27d6008bedee7decb2ef955908ae1cb0422a7465c2fbcb1214452a75a1c46e76d3c894818b12c4940620e50d5cef6710073566e967fedcb580304eb438e61d6c2e5609cc72968da8a0414aa072dd63632d97c25a462f8c4cf0a0cb68d67e0df97981b2208d983a105635546f26b2411aeb96b4387975bb0fa4b0b0ba0925dfc1cb8e4f871c8aa3cba8c78b0bcd906b41ea0b1b09472edd069933016070e3a7cce5835facdef99f242997e75c422344765b2fa015f9807cbac0d14c4e80b456a0bed96057194da3129d4b1d6e81b59f32347933b4cf1fc927098fda6a62ad940db909df320758e2c2cce080f2f434b3ab662a87a53d8e5fc48355967070115952a5391576774bfd5d64219e0dc8071a40abe439731ff72cd60b3710ab439079d8f5bfd57e5f2cd2cbed9036c3112f2c7e004fe2418b55ddb66e8afe54d69d97adcf343f4e61b6ede9e402925f9e1af7e1f5ee5e50c9c1852e653077e4694f73846600fb4f3ffd195fbc486fe395c8631a888c5dc862b449f2762c4aed3e6c496974ce265474f66231cf55780acae835de591e5c9c987d87a12c43703fd71e5ff03ce9c86ffa10cc0870da0184f4f1e93f2a252852d16bcd986eda0cbd6ffc0ac60ec0d32488a01712b2905ac750047e67a486dce893dcc7088d1c77624c955413b009caa123fb2168877d6970298743958d22edfea9626b0884450f260f1440b3d2d076bf91fea0c99d9bb8b53f7360d9ccb1dfc10627452edd4a94fe9840ca0716bc0421973945b8fd3c1a2557413a29db4c68d8963b45a3b251026d98fdec07499f72c4ede494bca1af83d7ab51e2f4301015102c4625390624da23ffa962c9e7d68c268394cc38d88020290487ffea81c3aaab90a2def116c0cfcea0bac18c213a0b1986d56f751750576cb468ea5017896fa9622954e285c476cfe3c3c51cae0c7a0fb6e81c166a061eff73283947493eea8877b3b21540959c9261fcbee5651797a68d78805913787cd19d84adba56a87aa6c9a1af312675670a838ff30e109e109be67db8a8041300b52e995173950849e12d9043d9c180724348da84052c746520dd18e455c6a9a21ca69c3f5393cc45ce943fc99fea851e49748e989c47027260374a81194493c885479a41d4932455279e32bbce50994f219373859fd4f781d36843fe59e7f4b52fef4f9d24d54921fc5e7dc9adb5ad502bc6e0eb284e9d88fe61c04e03901353d87e46bea3f27c71232847efaf58102c357ef42e6c2f907be8706c9ec44e295387f4951624656f773d064103fd9da6240269489245dae4e4f1723c6acca88aa3ac183bbada800a35d037c0d6eb334e2c57bb0855a7c699109495b5eac8b25dbfe98990f89178037f53e5ae8bbc596fa7f083c1a00105f84335264afa8774c3786615e5e1de817c44438e9f5f48e2ba203a4960f9f2e2a22347932c78d1675553b3f22a7d3a50cf7de2b39d1a345c3246c52b31518b12f00435ae20e65f80d13b44dcdb6837c6dcf97615c6106f793f549defaa95ef4f2d58b474b499bdc36e55f06cbb8f3996b0e560fb93bb777adf6ccb3f5af9bc8a2980ebd136064e51433b0af367a6b90ed417f5164c836ffcbf865c4c804e26f6108ce03237a924f9402f78cf8bd60d5e43a32e35e88d3d4263c9b9c36e9be996559a6b5bc7a6abf496280a38804dbf933312b64ad1791889b3396c25e3b81490ccc0550a9c190b5dc4e7eb20ba6764f9fad973d7e91ecc631b41bcb21f85b8cd01ebb60a3e9b285c5883e427da7db511eecf1d8d28466a635e28916614062901385fcb0ae8a9854d91b24d2cc701b86aadb80daef95da16f6abd15809733cee3378082e11d8b222f9351ef98a0ed9c1ed5e3e550c6cc201d8d80c2b6e304ec3a6de951cf812623f59b935160785de776820e35e363a8b22c3b2b6f08a7e6f56e8f2c2230f9b70553723ba693761d03273605da017bf9b41a21e68bf89886504cb77471404d6bfc046e752506fc16c57d0a433612496883504ca5da0c81514a2d6fff03ca0569e92bdca28390710af7e80a7e21602c8002bcf8f2a038511b708f80cf1e6be3f80ded122e082ce4e3ac0874da9e981b0a8eab198ee8938318f3e354006291945009a5e7a0b03a70ceef3ff9cf96aee7b5d937b84ac0e4f63891442ec4e5dae090804cc930a6d65943b72015cbeda2e47f8845c07277d1154dd4db9024fcfed6bb3860061272e21e1b2042745694c6f344d5309f204e006191207bc5693415b9ab550828e43fb586f1d42e0eda887f86eb07db352f56223a0896b2749ab01b5ea6920052f39132ed15ca4cea1a343a1f2170da464437b1b819620cb398589a6c352667954007f135b8a18f8fa1593cd0b2601a3e1a8a5048375a8082eb1d7a93c706e069f25533a1621d46953735cfd8e4f456ddffa0474ea1eb534df3eb1816168b2aaed4f8d625842d40af1e5e17b1a4b43b44e099e2d71502b480727b70c4711dc41aae6a2f143039415868ab8c3d8d7b46f542643b0cb30e4cfb04add480d9454e025e401bdfd26883a78776480d78ee463789022240248b7c84b3d5dff9ddfb939d13833fc8899746145fa8d9d405fe924ebd867ff8ad6cfc6dabd12c9e8606aab6f84348e3d76c8c790b9b004b390fd0483c3bbf1ed8c98058b1a9a05533083e45db01012a135f6cf1cf16d3e1fe92cc4f38b9e05524f4cbb2cb370fe42252f6c00980dae4d8831f0f754e68eb8c27377b00cee4e6683736259a94f2b06fc95761397ed241820995c236f7cba120170aad24e8b3da4958f3ca56d87274f075367221bba823c7cc95f15a672d8049040e1ea4c45b8c6731010b5cf47f0830059862af2f7a93bac90e61a12e0ac42c76bdfe9b79941645d7126a8531e3b96521bce1452a1f409130105072cf7a94f081579154704b5489a0679b382daf6b79630b495a156a82ae61413e22bdf7bc86822b30e1facf24670bb4de644fb48e14d9d8094ed02cf689334d73601ac498aeb4aca97131a7846ecd02b11a0301b0bb2d7556162a2cd728a721dad32f55135df965955f1ca31e99682093cbe56870c66666f3144247571c3e8f8142fed0ef74fc021fe823f88c7c3a29762be820917a41519ae5baa25c21ec369546af336ca86caf177a86c24003b02cb983df6484c6bdc1c32fac341856c1882318ea3d835813e2a47fe4eb93346090536889c11f616682154343420a9180de08f5abe4bb8d1ee23c8f3a358a53f6006655a24acbcbba2fc546a66f0649a8c5a0cb49a33b7504ce804c343a6bf715871b8096144bb7aa3a4328b9424bc0dc869b271defcd0f451d411c50c07ec40fe686761a00b9521e198556f2258a65191590e1fb8be71625330032b56d7815561768c89ad6aae70ad74aadbdc7c3c8251c85abe1970ce8db9eb7e382231e6100f542cf545f49315c6461000df04ad13f8ceada5a60b3e0b0b383ef6d9e38669201d2dd43d8f25f180c7e801327dd3d46b029abb31fe2fe72187740f2689eca214d6849a4721a1fde78c44373124d0bbd7fe0734a734f3ccfc1d68bedd02e943cad8200d12808ddbed06fece959c12ffbd6e54fdf5525d10f1702dccecbf72d8e8b617c4a1b227419b853342cb4384e2d89331de7b3a113c2b82a9fb025f7289cbeced3df00e122073a54bb962eeeb96a335c74e6b6b7f912a390fd6f8c0865b1071eccd433ae65e97e6eebfa75fe93df789cd2e43d9ca38a42dc50a6ee6d963b243d563be9fc931b34db65b845cfc4f6e28147878d41aa8a19420a8fa1f0fe31f93787acdd7d3178e4c224e0fb32d16d2c8e1827a864bc26961482a234b2165a87bf250fb7ae53522c3743436c8981c20a87a8c0ee8e4394e2efc614070417a5860956c64ecf698692f0f26d587768fe6b2cbcddf13b7576b8b7e175e23654a90a2aba0398066d860aeb8d4cd100bdf8efe8b66deec63044db3b73fad48ac600c506a40e3e59bb8c0a39ab92800e6818597086141f19b534190d0d8e48d4a0872fd6ff29b8ad3464038e8d6e1eec39054de17c9a277b046644f46241b4eec20e19e97847b6585b673ac30d71c1f52915adca14f9179c0ec6fb8b91ce717701bf9b20a41bf741e84aa49b78fcffb48734356c29266b80f6b12044c6790456d981712c64ae1db4c8a24e6abeb55b6ccd5010651b4a2bee6b286ceca4820de3397193d31a38a46fc500de80c7a415358e30e2e1e33ea807e41a7a617d95aa194be2668a096348535d8b68a24aaeed299ebe8d6ab50190ed4192060d28a0391e1a318a5be28be4e82a84267f401e582464d43aaf56879341b4d20cd738d5643a0d11c7aa202041e61142c5a8dc6e4e812b334027a8f5aa264d16c3481e646a3d18a065dc28b42381bec1595b5973559ed011aa52def1a5d28030a56994151b3e835ba88fe4597d1fb04a5260466da51b58b2aefd2986be9d62a6bba6bbf6a09b68cbe0346411fd7e9df0571062125a99ef58d55aabe5a947cac81e0097e2cd4ebd01ea38c3bf4da0ca0af06ce497f1707db8916d0b8074545e6a305c19f27b3d20e726e88d58644473427b1a697918704b587091ff7a994081a455909dd246e4b8e971d918e6c8ed81d191d811e613b923b521db939221d64324d2c8390a8255c9e731d09ba46b54ccff29fd28102025cdef1b1c023b2eb9d5b3e3247604ba8831cd384a0b202beb88171ea474ad20319130e9827c3d7a3608835a2da67539b48ff269f018071c1f7d2847187382ea21ed918c39000890025339079a430cb97ab45580c50b5a3ac04eb11cd484c30d63e9c53a008e0e004b50a327b797a78110c95192725d0980325dfca16078412d295adf8737a586f98bf7550d680259a96b10db6083a11647c3a3e7c88a7dd16045802dc0c817fbff28d8213ec03fe079f803b3284e15f0920228254c0f2e099c37be2380714583a85558790c11a32861ecd314883415367431565fcdaa07859f4b84406af7d276fa2efc5539b6f59936164676267dac8e2d80d0fdd4b0ac1903e98d8a69b8d4d3629eb74e8a61a4e96dbcc3656151c35b89945020c3e16bf993beae5e457b241dbc6c7c6b68d1bef66304017b5a5a21b62cfc98553cf26459bae36d56c727933cc82357ec5ae0d41de74939306ce2c35f4abf05163426d86311a28811b6728371bcd390ece2cad9a7f35356b3203d3c611ade3071122985c9127ae0900538819d1906208608b491ec169a610984b8e2b9fe53a551c2b01027d957c543a496904df4b42638faca11de353f304f16f3a17a288bd2c903cfb16fe2243d0346f5a483041f0b593bd60cc27882f6cf6d8cbafb9e634684ad6a72efb69beafb781601c28772c11a7cbfbf194aa3f8950ad731d04b3021ec20284b720b312994f52a1d4f8985674d5b82c6cab4fdc084938d1e642e861418074bf1c5f552fa02a97e42bb0df345b6888225888318b756788d28b1f8b6a4be3ea530c3dc928eb45eac923fd079ea4f56cb424068d3c349a30a5cb3d20f9e158f1c11aede25b180c7e428a6bb58195e94a1fc7ef0492015948ab5d1596bb63076b8ebb0a7d67a9ab35350d850f002552f19bbcf180f11053cbea22158215772abe736529cb7b3ada6f04764ef0b815401168a1466bef78baf7cd7ace53b5982e95faae0a5180ff08003bc880f4610c63ea595497e38a2ce30c68ba7d1c90dccf0e51882b992430e1165604bcacf7793cc191b5cdef43b4e27730a323c106116d4581e7fd292abe7b82623d912a631e60ff5a00ba69017e379f9ab6a4f23b98e92f8b0a89a7c93df06dd606da70349c0bddd32000060897aef56ad683e4e88368d3a8e3acec301b22900a6eec7c984e62d943bfea7bc240d2e82e374a9fd216fc5fcd35846d4e170ac181842208f10ff99b141948219a4b16a20c765890a813ac1f13f5c0a12553ec4374e6d09237c282aec5c8b0626989f3f4d4284666fa3cbb1ac358b230a105fcb5511347fa44ad5d6a0c4158b7d496510535f3c9c20618c729bb1050a0addee42dc74a1c8ce7a995b38f301570583765499aa65912cfeb0ec332028ded76c942901b3542788651b9c3d536a5c148adf45e94e39ed638863ff98a1a19252bd1b5f84c08be303ce0a51af96ba388504c7097f14978e5f010b1481debb23723645b3fe367d8dfd06d5842187b980aacf31abdac5e9caf7b617484138e5eede8620c71c0242f7cf0263c41db3db3f7ece3200cb270814069d036f0d6f91e37cf49cccd63f6f46aef92d195326005597d9d0ba384c10b1e72c547b5d54de510560f0221030fda7441b9adf7980229f9f59ea347b17b1b01f69b34e52dfbf119c682e5bd9a2ebdebd3a5777dbaa8ae267a1b21daf3300b0fd22bebd579895e7c7f972e8b8d6b28deab77cd5bf4d6f7fbdd38620e25f5104dd8038cf14a79755e8ad7cb4bf37a7a51beb28455c264301e78134abf9600ca209b57c50be9de023da2a9e2e90367c3034ecc43f3e0c21518c88681a0c0f7e810bdd8d6418817b57758b537a7d9d8eac51b9d8d28bc3b82fed86bba3947b432fe8d4e7c08b1137548e50edec1fc66abc029bab4eecb9e056ee3f8c33b24c90a782254d3e050cdbcd479170e7d901a93e7164e07970cb325016104261c7d72ec8e134e0c8d7a0b88a3b233deedd18ed13a3a7d458d08633f06ed19fbd7ecd397d9b4ef6bc8fc06822596db0e396c582009a9a33cc19b77e4d0ada023b2602bfa6a12eddc9d837614693a137acebbb1cdf3e1d7cfdbe2d18ea99c644b93f46613aab4dd5e445c34f72620c5a5b97a6c5f3e91f7e910623bd7c69d0bad5509da3b7dcd2fdfd7defa5c8fa940e53e483d0a1707ee21ac053ac32706dfee3fa3d6b9b52430423c0c2e626718aab7db6271cfc7156e24dc3116c01606e27593e49daccfd337470fc7f5f5dbde4a91ab67df6c199661c8632646106c6f093feedb0e6af37bf7ed664004f5346e6ccd8e411cde467317c945e5834aa499ca716b6f9583f26b81f8937be724a2977d4f341e097cb84a54f37dd87cd25d43a3f73b4a544b3c880c8dacf858eca3bc303661f5f881774bfb46185d787c1cf2709e91799b61d6c5b300ee18c0b64a9a6b6192f15a3405017deeb2ba3986f33e02f848b7a5b1a2555dc7e7011ca2aa4aba0970d6139071e0671a8e9e665a43431c345428ad2f6be9248d720fafe77ac636617c1410980664a0181fe9aa0aea86d804a3cb191e3e2b9411ac8f02cfd9e3607333cb48776261f90278bc63513de7926c2e6c1542ba9278ffe52637e78161b219b091146222f28996ac7d40d693ea8d49716de5b444be99b5ac47be0d58d0a7ab5d5c03a8167e401199f5b39214a01fc665d150d5a89bd5bcb63d62b25dfa97492ca7d9447b4c2f09a600352573fae1dbbe7c20c068d0969c76975839e09b0088eb3506bd3713079d1f3238d418040556640ad8109cb4a0e532861f4ea376ad4164d1153ac40e6cb50fd57903e0a1fb0049099bdbcc308f3cdfa4c28a037930627175f643486f472bf70e5fb5c062a2864dd23c058104a50a262a1f4c10f0bc6a1d30d519725e29abe4b15a461c91afc81cb29026d9b03207ce3e12898845aa911224b693faeaabc4ea807c88b8b1215d195123a151424278f543da2051f02bc009a480e21f1bba1780398cddf1363d207af8b398a53845dc098bc25f614df8799827ce0857c282f0475812eec7a16cb114a1d20835c3fd893c3004e197530804869c735561020ee78ad890500ad81e62664638dc634cbaa25bd3daa63e4b2892d802d07fcc6acecfd2d12a69fdde7a75ef78218447a39d9386bb067a11c352389f6224f00e8826490b709777967a0abc9cc19078446423d598e54b0564080b9169a157cc2c025a4f6079b21876ffcad7c9e811c522cb8723209b43fb1dce718882b649398ce1220e1a4b7445e76d4373990a04986e76897bb8fe10d44cd7c7def0e014a20112bd323b0bb5893132180b105d812d8f634a43d068d86e886f78f284b843748f57ff17184852627f5d402adc092ad5f34016904dcf928bb9845f4de6b4c8344912c3c84b18e25d6222d2cba12d302a032c0c4b4f8bfea1461b26b19b503cce78714784c9b036df4a79561c334e10372f08a8e744820e7a21b90351da009eb44a7d95bb47dcaa7ff643da2592fc89445f43f8b5e30501d2d74ee4226d225b2fe799ce13dee84eb810bff4f4d4bf0a8441e694d6278123dc85f1bdb757ad96b4739d91221125090f8dc87ad8b6db19f77bf3787cf695a3a0f5dbe4d384a547d6086b364466c87c24ef118c04a4b475f55305d5f6591d685c167e3cf14e74410668d025da5c3cd1f5a458f4b5ae676fc9d395356fd0400883b4c00e4b8b12612ee18b94ba03f8d37e229384ad250821e93d825d9fd40b904628e5812e8611e83d6065b077abc7246df0f814da40d2e9626e4fdb4692a6babd72906eb5ecdb6b80b8d74392ad90d825bb64a5a8cdfe4ff2e470075dff711c781e05065d1f43aad017fa74974b2a72b0621e52e2d70db693a0cf3cfe59e2f3a6b0379e0dd50c592f1eaa4087c4d29a04d0f2ac20a56ddcee1b694a66580bf246c3b6ea4e3d6546a85c668c3da391ad888d4030f78df098fbfd09d6d76e5c3c4adf646ffe866f1d7bfb1e8a5050a6f8338f6583741b5454388e6f40311001bf510693f294bacf2a58a5188b22ebf827a95d5b2413bf4f320d3f12aacf676d8a3a21c21824d6464860f8120948b7717c49cfd65d3831485d939da9bb9b799d206fdc85ab497590c467ee71ab401fc74154477a0f33e2d9d89a0ef734584b1a04029c476b02e1cf48a881d87837b607b1e81a2e5a50400ef37eeef2df4bdf5fb513b42100687b529948b9cba8676a795acb347a25881913d35bff2505a26ac4b6fdbcc7f48ddff25b83056eb688e197de7d37368f655579074bfe228b98aad3c8087391e0aa0c60eb6892cd5cd7cf95ab90be7a99675e524c3f2d54b5cdb31473374af901c361a5ccc01334b5ffde371079eda096ed64f0b02cbe7afc993613a2a25ad8cbbc6cf06c1985b193f9ce4ff43ad02c4cb54c5aa406798290170e11c12fa81cc844da4e22d45b27e16fa93c41c64ba525e9318d6bda0f2eb679043555479b5553216d0eb40588836f79a04351454db044174d514f2befebc1b2456fed8a413852727d852fe8f1c93223976eded7fd13e34709802c08736d6dae109bbcf789240e6f156873c3212cb9feb1d1ae45f0f131658e607f6dd93d3ecebc08da3d001e20658e3199ffe3eeef560af2f118b50203da4e53208f3962554d0ccb47563e54113e0216097f28f431ee6f7ed49938a952d403671a60d44dd015a162076df240136b22a9fa6fda13fa39440680ca19539bccb8fe64f8ad5a696326047093130c2a0013ea282c1ec457a8b6137afb957785fe4269b950642449ded816325ce8b3d00da1a5fcd06c66e7ff6b9bd00721ca422c1c226b1177223a42a8b4d0dbde28f94393d0dd295482735482e510d22d74c818aa5ec72d470d870859e495a8be502a0d754a54bda3768aca50d4b1a2742acaad8e1401f83a944b79d089381b3a0266ba90fe6ea835454211653314bfa2e89128b74e961e4fb52000fec40379d6803516704dcdb8faf870459a1156fd61d50d8605c94ec018ec4a1e2be885ef55e3298c92e1698f983c2282c2f8090b77dabbd260815c03d92741e61f1996ffaf859c5cb227d0e96014e68cc9dc94bf8dcc3f256d478783d7bffb8178fb73c1dcb046f42cab28264fad098154a90c33f43c54c1961bb6206e7f818650f3ec6bbc778cc6cf964586a45af6de16f5208504c80375c5179ee9d24edfc0c5a8f139a3ebb064e588bfac2e980935b4b92e266ff1a3f44b108eac472bf6aa232c31d4658259e9e098ae22cb3b47708e6c3649b483334bfc00c731f264fb9280b515a1d55759a922e3716560ea4eb315c755d49a122a3199a0d7c457311fb0b02a05d5a07256f03aea6e12d0c4f1a563a5cc213a51f74e32d0fb9d2add8af5d45672c4639284c1c7c3e0eac0740f73948be82091cd8de125f55ceb550069d9f20e1705d70355322c880511c2a8177bd84e6f385fbaf9ab2cd096b3469c91b87180595a0c621b3561613a388cf265c51cb14b10824e6cc1ea331dcf8c07852644d06cea3ed078146229e01a721ecf62f6da953c4d05fee4d76b300bd235439e57041fc4dae95b0c52ce8c52677cd6da8a30fdd302d7ba4ff6b7ead59a05dd1fc52d726cd3701c4f4f395c8771085b8408a64ac526bbb49c71f03fa3a6e2225ac462d58dcda60be753000cd9b2b0949a17af0b50b9dfe083917431477764e18436fe3195a115fa701b50b1884c6e698b9be83469417c17affd3959e0e064367c74fa746b44d335c56cc6952773d4925051b3f90e979361d28eb55438dbc3eceadb60c0e01da1ada008117099a9b81527492554db9c3d1bba00207e94eb1328f59b2d61acd4a2e157f8cb440ae3dbba744cdc38435eae167df2da716308abf45742f809cdedf32d386d0bc9fea5bf723404efa203851768c60766bdd1acf9afbea9805f3182524a84c82af9cfa28032dfd49a5d553da6a75cb5b8dbdb26421877b35b3d75374258ddb1d2411bb113c3dd6e5592d2e40566c35c8aee449e1e1e1648a86d01ba135fcd4362bcfede1387f5f5c40400c76f3fbac0e76004c1dd15913797764d795dfcbe3377c15c8067b78e16625d582c27eb49c5dcb5c1b64699e3ebe49538cbc51751c3091ccdb936c81d94ce666ba609004d62a9a90d246efa0175afae4f6500e8f8801bb0eb738fc09f181235a362c4bca2a2a64f364f3ec486645dd802170b2939613efc1ed21a326a34f83306fd0afde51ea7fb5b769f05d30a0fea525bbd4cab691858caf236924f8c1130b04f7a62218b2edb12f3496fe11bb4355e4adff858a8568e1eb8b645a532d084beac38d253fce7f1547debb5c4b3fe22c2b4614fce0d7de157cf93344ba82d0b3af8c08a05916958b3c5116bf2d47ece637339b35108b50f4e5a8383b20f1e81f00f06f9a56b05be0b1c8eed162ac3d515d24edccedde11f36bf6b3a0b8a631f7259f2eb5fa25fa558d2bf74d9952aae8e8261138d2b6276c22a94f95daf66f9917d1af074940025fd080dc710d94390a5e61811b23f2cc2f903e62673932377eea58baf5434f10949f7f1284865da1cae6e4b91d065e204a0e1b32d60cf54420b650bead31b41b47249cd9fa3b9c5051d6d913bce6ca23c426e9bbf1caea335807ed66f98b8ab889db91733399da871f5dbddcdc5a0162e6d07381e72a08eb505cee45c9697cb002335f5524297f292c6854fe4a64ad1c2c7a27fd4a49130279efec07b34235b922bfd158d435fbe92e6db700fbd359a8154620c66da75148dc17d00f24e282dbd2cfe05a4bddbd2170bb3f4c9d64fb3704f90694577618ede99d55d1cb38f360a6bc3a5d2295049f105a2be2f29786cc4b870f551ac38c9dfead41a6922bd2298632c207d48ac4902aaf8b3a13860b46439330f0f0f0f0f0f0f8f1c1ddd08a98d7c02a932c924c9921e4b2db325c994529229929ece70b1db6e7b98f87466e2d39989182801570a080a280a17f8303474e4809166a26e2953144d29d9c08d2e68a8a02390451635be2a081d38e0e2b7588aa7534c210483c60d5233504001a3808e1ba0bc374a0e2946f3aac8205d74d880b5329dcfd2422899ba7340470d8c1d94a753daf7633ed180cbd11de1173972f067c0f78996c8abb6f823197032c6f2bced343aa463c09f8a9713bc279592c180df9ccf36d70675bce0d815ad72f24f50d976b8802f99225570512bd80c9ed39584104735c30ade2fe6a9fd2b1399e52a98a86d6d61b5c93eaa6043ca2a9a49c454a4226a568d4a4a79083850c1f6a6978b5bffc4ef148c2acd0e4956670a5ef285124169a560d47b98caa7eda96291821d153f988d7dbe9846c1bdad6a5e2a192dc78882b5bbcabd8e9f739da1605762cceda9645249231ca060a36d7a499a193260d4a091bae0c260c0460d1a0bb05183c61618b8097c004600eec0f10936fdf77fd0bce9a17749048727f8f8dde29a8400b8034727b89c16d4c4ada0b2bb3c46707082cda9abf27ecf543c15ec04c726d8aa9821249def1945706882916ab23e4b73cd049f7fbcb2a4c5f4acc9220b0e4c307afd3de531cb2dd3f3392ec1e6c7184ccbb625a64d2dc159eedc9543568db89bb2858c1b5d7880a3125ce8cc7a42588b7fdc500b1c94e0947a9c1c6a524f3312438b548163125ca54922b783d28edb9004eb163bb3edefa88d158e48f0a9f5b63e4c24758cd210c18d2e68c0a8f13752c34083020724f878a5be15477f3fe378049bb9d61fd404339d238ee042a307193a6769897a0cad1b5dd06804fb93640427a6ff5490da496457091c8ba83cdf95adc99db41b4570e9e2394410c5d0328e4470d953fceeba1a1d6318434b91c0810846e46bc81aa24f57d0cf98d185081c8760dc93a8c81579b4c645096ac42041e03004a35450d513c1dc7d5365078e42b0d71eb207b51b4465afe6c04108ae64dccb5b7d1a049fa74a87be5504c16e578974fa59154d1308f6c2f3f37e4d23c9910310ecb725939d6df9037b3a44d39e34d7a75f86c30f6cdfe9cd1aa28e068e3ef09d22f4248d9f4608720e3eb06d3adaa592b68bba468cdb03bf9de9441051a52c1394006d0f38f4c0e56071dc425f478fa12f85230f4cf0a473da1b2162d03c2a78e0bb94da0a7529875111f8d0e2e3021f5a7c183b04c71d38ff18f3e5c8bb61a27124e3de97dc8ec05107768428193c530e071d38213c83c83a5f060c159835c71c185d13dd89571939701ed2f8e65ae7ac93230e65652eebce9b02074e7889c6985a938a5831b462dc9081827c031b5abd4ae888ea2538dcc04591f94e780afaa795bd4a70b481cba05793965c95bb3f071bf837afcd50429d8813df82630d9ce9ac5b5adb520c9d188d34438601800b1c6ae052c8a64b94085a3770a4810b7a54a6ceff914e9d0a00c2c081063e8fae47bcfab51c2d05709c81c9e693f479997cd30b963a7098810d2962869d5ab19c3d1fe02803d79bd38a05e5a71d1978d5094945edd06cb9bf81630cec9a6a939c83921838695bc254ed29256eb181230c5c85baaad20ea5e612303041866eb06a0bc172b4c1f10546994aba3d66bcc0485272ff745c4f9dfa337074812f1d6b3b948edc1282830bbc46494166beb6cb169d2038b6c0654b9a18e358b01399f4038716783f699f357c93f0af141b37686c6103f9c0910576f3e64cafd71659afc38a040716d8d7fbcff5bdae9dd457d8f35269f00e8db102a3f4c9bdfb8db4215e4c1558d72dfd112de94dd24205b693fa50b5496bc8949f029b528a5e5eb514f8ea50952d88769ed24781093945f95824ad9322287031888892495350efe92774193a98040e2770ca835a3da1fb44594a1318252d620a0ff5d7baa98183098c8fc85d00c1c0b10426779f9b6a532b7d1d871218c99a9abd429f042ea9bd9cea2ca68d7f41021f3ba61c8356ce14f4b6058e23b099293fe7efbf0b5293050e2370327a8a9147d2c5d46963058e22f05b23714dc7dd98f12702ab6642ee8f09e521a22130d93ce6bdd15a086cf2fd72ebecaec011042606ffece64135e8242070a6624bb677d30fb8d54ea50f586b8ba555e47fdcba078c08f9dfa45eefa9c703ce6c4b56b2242a16eb1db031cdbd5c2c6796a80e585b0da52b5a1e8f174281a402470e1865a783899c3236050e1cf0bfd9a244cf9c2570dc8091b5f6966310396cc09dfb5bb999f2b353e1a801a324866c9a216920e0a0016bc28350d125399f8763066ce92416294d76d4f148e034b6e800870cb8bba4d72353c8fe8b60860c0e70c480b1ee58a51ff9185ac80103367f7448f6ab2692462cc0f102ce3c77904909379d825025c0e1022e7b65d10e328790658aa1653cf0a2155cd24f4a7f0e1d224c419700062bf8bd90a35dec12321378b10a2ea395ca654a5d446b94a9820f79fe39e6f63cbafb185aa9e035e99a6a8b674617da8117a86023a860a6ef239e82b54d75ed1b5b9474510c2d1b68461709069a41e3c050418d1ba78117a6e034bf830e7943c60bda185afea82ef0a2145c56330f51ef2e2f48c17b58564b927e4f9df15cd080f107068d1b304840a3ec28385d2ae9cd1f4c7454ad17a2e0f363caec5d3a4b726aca5e84822d1dbf5474074191a634b937bf983ec1fd9f7bfe68a3af49e409be84d4f893532df2ef9d6023d5b9e87cadabb1c30936f8d88d4693be92de4d70234bc7e8d17f847257139cc864a9ff9dabc4a399e052f49893420531c14ab2fc99d6c4f7f4e512fcc62821bea6490cadb304779a3c6216e9c1844e4ac38b4a304295be982e4a1691934507b4f8d8c087161f1840c0ff02d0c320f689179438ef7b6825517a4fe8b560f06212dca87e04bf1064f4a08ba105a3b048824d7aa7d378a8e98ad987161f1f1988c087068ccde14524383da64255b07613df8941825fbf0a2aa748316ae93c823ffdd274a63a82bd9c34055d7d1d6a9d4670c2355e0cda67694ae70c2f18c17b5a64f7d4680c55418d1b551f5a68a1821a1938412d82cf2e31e7a07e62aa184570d92d77dc90f375f2cebb8c2d6cf89f00c60d194713c1c934d16b6236a152362182499ec294c823c754820ec1e6cdfb1fb4c9d4c17343f05152d24acb9596fe168297543ad72b8e84e0acf6525ceba0244507c1452aa13daa2b077821082e5f554e7a82a851eb03c15edeff4d6326bd3f258b2c00c1276b8b596a343f349545165b022c3c81d1e1c51ff8f10dd139ba882431c70fbc7b4e27515392d9d5ee036bbaee44b2cdf281913ff9fe94c7ec81bd49fee94a947a60fbfb4496e0ee1d1ae6819f9819fea3bf1778e0ee945e13b523ffea7b71072659b42439a4989eb731e0851d146dd749e5ea59cc8b29195b60e0868c0494c578510746857c36b6fe1943ed1774e0ce53740826f574f2620e5c9956ce21b7c9f01255c0092fe4c0a94b6fcb599b23bb1307f6775cd3d6c53c2aaf2fe0c05ba86c931f4bef4632092fdec0d89ad00a65e757229d1bc8228bcc176ee0924a49a974e9c545a5112fdac08d6a88dc3152a86b644005fea1c5c7ff023e3210810fa388176c60efce32c81695bc41478b176bf053e84692d47af27b2d3eb58d191ac87aa106aeb7b725772e59a7160c1b32ac108d09948ac08b34f03169537d2b4a77a930032fd080d2d41673a9cf258d1767e02dcb83dd051d748766e0e379f88e0c6a4706a132f0aa9adc75e2646062e5e849fae578277d697b0d7b0b0d2e607499e20a5170fa9fe139726ec836cea001c3466fb1058d0a5429ae0805dbd59162fe741af3bf4b842b40c18656980955b24424c9159f60d3d9a7f3b3d6ced35ee1093e0625b3e48c1d561902852b3ac1c4ca2023c69894d0ae73829f5461c22f879790e0159be093a84baa6c52aed004132c3f9e3e15bd086a74c1050c1aa898e08a4c98fdf783a5a6941a7339b80213dc983c0da121b546306368d950c1938006bae2128c720b4968548f2598541a6d6c929b0c3247aea8041f4276eb85549af27994e037ee8598dc4e05b86212ace7f6ead4c963c82349f07e2aa56aaddfe47b24d80e4aeaaddf0912bc05f97b225cb5ab4d8fe053799adc6772041b53cce9463da90ba9d408fe3d05ebb32d9d17498c606257e55b532675b28be07368c8e135123fa68ae0dfc582d29062267d2582f1743177a89986783d22b88d2523e4b38b69933f04fb1273aecc0ca54cf286e0e4afc91cea540856fdca74909bc4439e10bce44bdd35d24e643e086e73745aee08828f64ea52558accd10e04abb1a387582b39f405045f39299612eef9039742df3ec50f5ca508aed9f2f729ad0f6c886b1674121af388203eb09bb729a92e6dcffa1eb80e094147f6f4163d7ae093ce1d4dc5be3cf09f95d3932e1d0f9c7acb8a647f7a21f33b709d93b4b899d2d74adc0e4c90e631e55778b6531df8ac184c9549074665cba5155210dfce1cb8148b5e1aabbf4c39f0137442ec1db597db38b016e4b649ffe0c0c8fbdc79035f32c818e9f3b4a8cb710323422c11b3a4b481c9994743b65ca27236f0551a93e6ff77d3c8590393cd44ac15a564502635f0a576927df654b97f1a981083ad48cb49881c4703935a3c3d861c9243e70c7c474ab51918cd0f1dedc32e035fc97bcdb3fcbec22603933d548912cd92aaef18d81472ae1cc9e4e6cf5931b0567a225ff0b318ec0d031793599dbcb08b965e30f0eae321779c9c64b8fb0524d7a7c9ce7881bd2043f3744c9b57e90217227345996ed0967181efb3ed94bc82b0a0da2d304ad4a7bb9bdb7a9216b8daa49daf5f22d79f056e736a13b699d53c58e03fa9ec371621a778aec0a768aa9c533f8e69adc06d784c15b8ec98d62c260d1538ada46576ba29f01dc44de96e568f9914d8785e9bd4ed73d494890227ba2cdb53fcac3c3150e042f30999d784d6d23f81cb417d3ed18cd7277782e6d7ae368137a979934fba9ce32a13b83c3375099cd059ee2992f4c55502ff9eeed2d7abaadb24705b5a16722599b36a90c07769e48c5fe611783bcd7efa4383cc5c1a81b78b5c71641ab178c922f09354104d2a7b3c694922f0315a929d42ca10d80b25a647f57be92b85c04dd4ce6ea173570ac920b063675b79132b651f089cfc4ac97523498a3f60bda4a94dba2ab11c1f702b29c6c8abb9ae3a3d607465b5dd85c803563be490d9941c1109ee80d56ce7bbf9a403f62568d2185f4f257d0e583da162568a1fd47a1cf019736392ddb1c6736ec07daadc9f57214751db80cbb7ba11ad32d7c6d4808919c1b72a86067cf6e7fea4435cc9e20c38ed39a2a2464f4b940123938ea93a2f065c106e395b7d4ee3c2804b0b26376becae7801efdf566b694ba86a77850bb8949299885a933edab582f5dc0f4134a495ce8e1524ff1f95dead5b05db21778c12723295d4a982ebaa0d9a6f2d3c28a58293982b9bc4ce21c4132af88e1f256f6dd87ed229b8ca5641a525eb137a5330495bcaf6d43b32eaa5604ba7ae936ea7846749c1897e5bef4a12bda3a3e0b4938e41435544c1d9c59226e4a8c9d92aa1605483eadecc75112705147c59d0d7c97d82af20920e3f7929a93dc18b5e6477b7745af54e709deda292aa34125c4eb09d217c2b2da49d36c1259926961764aadf6882bbcdb425f96299605452dad339c730c1c4929eff64b25392b24b705a4c8876893c39059525f00ad78ea5ef4ab0fa9bc74c3c457b0c2598e0a24b548c981dd4493022a74f4a8dbfc71325c155c57affefbcb9ba48b09fc4ba7df27548554182fb8829b3ba72e7f9084e254f929f3ba6912547703769e37bdaeb8adf084e86cebb5c91a47b9a118c27cba0d29dd2695416c1a9d3d2e5a7228ae04d5b68d9e6fbba3c13c19788ef113d29bf1a5d2944b0a516479f521942ce762955a7e310a89c3f6d26ad37c18371c37f8b2fa6353a0cc1c8989bfc2b8a285d5b472188d51553ae98992d5a34af83108c14bb203762121d34a804fd356e60a0c6ff16ed1d8360cdccd5cab2998c95a41d82e03475f88dd5e7dfb004823d4d32e68a9a4ee507299047e80004a7f536c1239866670d091d7fe02769d28a9fb6634fcc0fdcc98a51db93e49844ca09ac0fac660dd53b1183bb09f9c06ee648692f84001d7be02a646cfdd1594a8dbe081d7ae037246fbaf76ecd9d5542471e18cd49be564ad7930836a1030f7c57ec8b216dbf52ba63e8b803b7f7e19ea38f9e6ec60e5cc6f16c5522e6a99246e8a8032792a8d251fda703177eb5495f4aca1ed473d037b5e7484fb1430e9ce7ac26a49655b84688d01107ee73c6ca2dd5bf1872e0c0c7586a495bd03a15d42e4cf00af0df401659bc8109f2534e92d3c4edeb7003dfeb39344fbd8898343506b2c80246093c05a5b2d0d1067e52e70675f69dabd10e36b05d2997b04cffded56dc71ab8ba2ef37c4993e518a21d6a60ddb2e58a9535a550ab230d8cc9ce1623648d79226da3cdd9053ad0c0887493a405bf4b4f39039fae527e09c99dba7733303a66ae7ca2338578fa04ce7494814b615a991e5bf25afa67a080060c1a37b008023ac8c0a9202db774794dca76dd1838f5710bda84b288a6150357c2a3897888c433191a37b850410dcf8e30581639820e3070d9adbc349fdcdf3f7d814deeb132774c27e9e35ee054d5a9b5f7a8219ada05464834b720ac639650ce9001e3468db761a353021d5c60b7af6b8324e9a34afb3568dcb06166746cc1d21a59594d08e96f0103358d2df423030c405bbc8cd4a105de6ef472c77893535a6368d1b821e3c0e0c206b6a0230be898d2a69ed6bf788da0b1d0e694b33d23336494e00add7699a68a6c21a36f5841bdf60da9efe26dea3baa6059165193b119339a0b1b860aa5ac912db43f8724e3a2048f0a283643469780064a10744c81bd3cf7d551efe3698471c3460d1909061736c8b1b1c5c9f0e7c2c695144a3d3652bf17c18caeb1828e2870e61252e54f2f14f8d3ff79747aaae45c660a3a9ec0c50e1e439dc8e9b4b74ee0b2c474a5496a3a9ac0291d247ac8a629d9c9fd025964e1353a98c0b68daeed3896534236860d195b9c2e96c02511bb10b2ab8848994445871258959822774aaae367d1231927602d2af0a1c5c7054af0376ca8000338810fc01080293a92c0da26e9292108099c92994734e7e8c9d51e8153114cab44a932f0a1c587063e2a10810e2370228db4ac103adfbd45e0f3455eede744e0f2928ee9cce347909b8e21b07f42e8a0efc6b4b60e215c1616840e2074fce054229b3c4b9db51e1b30b8b071dee183ca420f1d3db00e1e70d1ffaa72e5654b5ec70ef8be4951b3c4a4189a75b00b52a6d0a103745ae94d10030b08089941e44c21b85eb151594aae69c71082f5f3772bfd6339773a0826df5def9afd498a141e602108ce724d909793fa839653c022107c09655563dfadf92f2058d341db7fd0a163f2fb0f6c86a04fa8f02b9de5f98131939ca7c2b38230953e706d39d9b727496397e703bf9bd934c6b49493577be037fb4dd00efa19935e0f7cc8dd3af194fe7ac9f2c0ff4608baea43a37a89072ec748d22477cebcdfefc0283da12327a92c2aff76e0b3a7d98ffa5607d63ac9764f4176955de8c0678e2357d25fa648e21c580922a6102986c881eb984c569e8a395fb271e0277a3ea1467b10b11f0efce7a6b03135327a0a7a03ab957547fba75c5a5b37701bff2b25db531bb8ca6e5ba9e31f399b6ce026c620b455af6be0dca36b16a1d496696a7280851ad86fb5cb4cd31d9ea6810ba2e5754ac354751c0ddce6e9de3c31ff46edcec057c5b81938a5f58204193b62faa50c7c7e0d16344c53de7892810ffdcc154cf787f2c7c0a549d9fae6a546db2906762c4710416990a53d250c8c8d8e683a49f2df8d8281d1b912bfb4bd5eb9e40b9cada47d0b9e7981578ff93a396834937617f8d2fd1972375f26ad7081d1ad52e963ce6d01911973d56dd6b4c0589910faef192a31cf02ab9a8248d1b3b0c06aca513fc7ac89972357e0438520667bba2e4f6805fe3ab3084b52444b24abc09e77ff0919a454e05237d3d5cdf45afedc80c5147891ef21a4cedf5f7d41010b2970d9f3c9abbccc12da5b2ca2c0664d2b1b3f3d144ca521a5570b583c81496ff79e5ff357c57702afd1d6cb7bac2b60d1043e83bc98844ab6ae923281cd31636a4a7ab48b0a9760b29831585aca992955724f356925da41870558288153f913438f4e99619104d6ac9212c964ceeb8d085820816f3b114f31e890db2a45c0e2089cd614f7fd63c4cd31c908ec8f5ecaf51dfd6ed92270b9275d2c2f75501625029772e8750d323904ee4c57ff5a704fcb50084c74915ab9f9633ecf30086c48ae8c19520ce941580081499aa65468baca77610219333410e3860c0e7441a34601018b1ff09f4b259768d36f16f201ef7d69e2bd254fa5dc1e709d29e6d51c736d0c010b1ef0766a379eb2b403366b68d60cbe7f3af63a60bbeaab1c70218368ad166d49671c077c0e22ec93c9d40d7877ddd441c41855c4b60197ff2caa4a36cb2a3135e032db778a5731550a190df86c222283fa6c065c3c59b974694c6b6ec9807b1349e9b064c580cfe6a5c337b7e7aa30e0369d0cfa5308b194456080c50bb8d19f374dccb921ee63e1024e851cd32d9a23e718f36845ea57fedf780658b981072b3859adc12f3776d0cd7bac8211f5ba1e4baa7877ae8a5473788bed910a26c91494dd77e5810a544cc9f2ee15434b055cd0f09de1718a75842e75167259ce14edfee9312584849482cf8d9593ccd476b2871448fc5297acbfb2c551f0e9d7418bab77f08fed073c44c189bc976f7edbd16df30805ef5954f6156dcf9a030aae459fdb8518327daa57011e9f502b9648c8c172f0fdadac2710315f5afbd223bfd289fe56bf37c595061e9c285b099dd6d26a46b0041e9bf0d0047a6482cd29a851d142dc132ee0021f66000f4cf0a3552a098929e814ff127c4ffe64379edc94cc2dc17a122a6b5e51594d5e8963faba0cb1ee43092e8f6aeaaa20e396951e93e044a7b47c7b4188e8100a9c068c2db6904102f5808724d84ba22a7869c40e6524780bda216c5377fb4a23860d2e7a868d19324aa066c303124c0cc24d6e88cef6e6c5d05a8f47304a5f503a9fc960fadd185a30b46448e01cc16afe10ff1c4f0cad3f41db281af06804b76f2a552dcccc3788114c764927496ee69e1c5b0497ad777784167bcbf901c243115b8fa6fe6bc77c6851fce091084ed55a2a3d2948070f44b0bb3a7e1e2a72886b37622e0311f8d8337818827b53e369b1a25a083e664d32e6903323011f19884021047b3b62164c4a8ab92f41780c82d3b5b765c96214b315e9e021882e3c02c1a57fa46bd5fc1fa365e4e001083e95df25efeedf08528f3ff0b124a87aff3d117537c2c30f8cae131509d9d6c2cf220b8f3eb016a947877e6f03c6165bb40ac1830f7c458bed92fd74f218327b60d3e51482b688e9da84dae0a10736e50e22e790224b25cb1b3cf2c086286ad4861a6d89371ed8ae2aa544648c0d1e77e05f734c3d326976604c24e74c2fdd6b9bc43178d4814d0d2a58b54b1a9592c4e0410746fe9d0ee1f5234f486478cc81bfccd0d2194fccf427075e63dccecadfca0b82d1970a8f38f0a1995e5bd22d3e86d5200500a7f080035b19da2799509d949d6fe0d463a41054f333438e1bd80b2294346db5f95d03058f36301a3177be2c965254fb050f36b041729c98b2e6a0237d960b1e6b609412b947e7566a60d2e8d22b31e3af28791a38ab71d11b42ed050f343021e90ade2984604a68cec077bac82b315132f82a630b1e66e04ac57cf5e22996eea4f62803afa2e79f43349efc4c073cc8c0e94839a65a2c51175b1510a381c71858db893a71abd42ad819788881fff829c46a2c58e7340c5cb2cee295d524a7918381cf9ce0a2169e2ff0d979f9659af4029bba27d4259b5d6092b20d15fbf2c532e9001e5ce053f6db0cba390615bb2db0214f4c66114134a38b05649145c1284d7868810f22638c589ddf2f52b2c008dbf23f594ac6a08405f66d3f6d2c4d497550795c81dddc217fe7a474e8146405f5e8ee641ecbb792f4a00293b35987b0507f8d4504784c8151adacab0f9922fc6582871438d7abf6da0bf1b48aa2c0656d49771b7d99b74982071448fa3f9308315bb4f82014f8d0e2834ce0438b0f22810f2d3e48043eb4f82010f8d0e2833ce0a30211f84038783c81b74cb52649250b13490f3c9cc0dde90b2248fbbdbb206d0257428fbcd3715f4bed2cb240820713f84d3b4ae764bec712f81b13f184b66ac8537b28818d90e4785dacacfaf148021752f5e4d1be1d12989c2625966d527d263a29781c813b915d52ddd26e92ae11b83d69eef5dd16810b2aab7bae591e4458a3ed66cf69538f2130425e4a96827e45fc140f2170fe49d389085a6b32c42308fc6435e191e2e8999918f000025b5e963534a495547d0cad46335e040d838b2eee041e3f609259d613f2be734e4231b44860a36f901a1e3e6052927ea9a162ddc7b4075c27199205b770091e3c604cc8984dd74495e0b1037e3dbb7fb0ae7895643ae0346445885aaab26a6d3c7280fa87c89ff63ec60a1e38e0c44de7516dff98d972036ec54ca6a436670376847f753e93b7f7162c78d4800f965da2868896ee9b068c5453515284ca63065c8f9815020f19b0eba3b3d58807b7ba39e011034e87c79cf2e8580c2d187f83c68c6231f080019b34976b16a5c70b38113b2449b5a33b3f1943ebc6dbd81b1e2e6093fb2469f5bb69c115ade0b353c5646a7249af6005a32949c5e0914cf85d31b468a02a1b57ac824d972f42fa1f8f952a31b468a0e5e20a55707e95238d8a575992c4d0423066c810c19fbb2215dcda899979ede48a0aae40059f4306a13e7b506a3fe714ac5a89ce8ddda0710215d4b8a15798821141927749cb943ea5af28051f4787b6b7cc49c1d56fce12156c1825a8d15bf40aae18059b0d79e073e76b51bf232a95f0c006993a92a7a40bd2bf03eba1af6208db0edce5c574f1d25d07ce2ce9ef1dff1024b87460e37664f30efa83773b07bef259bee5bca15b5b397067a16f44c4b32cd5c6810d13d56b8d1cabad85039b52d2b3afd3d1b4316fe0c47e7783bc5e3bd5b8814be9f91144c6d44949dbc02955e5a174bfaa69940d6c5ff018cd43d093e95c03a742dc738a199e8226d5c055864cb2eb539b8f99062e6ed09e22a79cb4298906f64e2b338a8a67e0cbf454a46bdaf210cdc048ba6c9d39f3457fcac0fe77a51b2b61a25932304944feb4e8e9413537063e8af868268ff99b3931706de56dd1be0b03934a7f9a976a056d3930b06d31afb46ba8b8e5bec088a023e7d039b5798e17188f9f763f49d5e0ab7581fb53d984ca271718fd9e2a4cb7afe95be04fe6756eada0a3a44c0bec07d179962c45104f16588d316dbe1aedadb11b5d94000bdc55d05bf27ffffdfe2b3076d9b28d0995dd64c80a2418401518196429aba0f399be3815380fa97256acd45cb19e0263a9b347fb4a6308610052e0d247d446518b99a451e0d276c54f6f295a47870277e9b33e94081694a89fc0a964a372923e3142cc3a814bb66ff9552a791ab309bcfbb59acedcef51c304b6328a9ed610f9b404dfc612d8149194c9ac2b814931fb7fc4ed24a8edd984a61b91c0b7a7a495b4e83c41d7476083cea6d3b4e99f7dd6085c9e20da23a77b3591290297736fac98fa2a8d9212814df13ef628a58352691b02f7b14595ceab58a511022347db4f866ce6494160938838329708da64b2bae002088c8768d2bb797ff5f23f6093deb3d01ef29936910f18a1546ec4ad3c3a47de032e770ef6956b2a09f5f280b3dc14ca4305214adc1d70ca628e17216e74c08552394ae9cd39684de6804d29d45a893ce28011bf1095c27303367b907d4a9e0edbb3d8806d0dfba0ad6b74da3560dc7a2b2506eb0703a001ff1352e575d3a0d7f60cb8504927f9514d984618f05d6cd127c01d800cf8f6acc172aa517ab431e0b46753bd2e21f2ce84015762424a2e59d9c2c62d603cfa2eac1a30801730512c85770a52826f5c04351010e3860c0eec0706e002bef3adc47c71f2d10a266fe614b407510cb5ea02c60c1aa564ec083e58c14a9069e365cc91c9f2555416e943157518f84805139404d1498fdcd229523e50c1fac7d19899f2970499b2027c9c82f76426a25b4952cc66df6805d028a6c0d4894a173fc330c2f0510a4e0711f4df69ac48e183149c505a47638c96b393e8071fa3607fec5d3f74e2e48f8b820929b3291dcda6e3e942c18812ea5577d55e3a0814ac9b7a6a095993bd7f3ec195768922749a56d0b82718952cbe28cf124385d9095e4d37e207fd6cadb11d7c7082db7135d5d9442e31d5c726f80f919cf746f7c1872658d3f608b1bbb353ce67821092c8bb172bc5061f98e04446f40a52fb2a89d02578cd1ff474ad64094eed9b99eefdbd5eb7127c08da3ea55de91ca2e683124cb44e275a2dc6838f4970f26f928824d53dd49404232d8f5aafbb23c1ad7d0ab1ee36e60bb5103e20c1a90fc256bba4650d2139f87804a74e997a1e193926e539828b62f655ae57426fdf087e4524041d254670265c943e4b9d4570bd591f6fc7a208fead73ec34759b6c2d119c049d43d2eb8d082e54c7e837eea1b7ec43705a342695ebd26bb49221b89422c73f4f2a87e4ab106ca69ab08fc1738d6409c14fcefc1cbaa345d1f72078f1985bef7346106caccad79c64a7533a24105cc8197940f0ea15a286d8fb1fb82be9a729fc22a8e4fdc0d8a492e895b6496ed60776fc4f09d951628f88f381fff11033d3b949f4dc031f399ea63655e9b9463db0f1b22d6249ce11f39507cedd3e63698dfc963f1e78d53c2ae418730726c8bfb64fb264072e2ff7c53c5d06f99d3a707b497b97a8470726474f11b93be90e1634072e5a485be54175a44b0e6c7489f959cd1207464773ade9e8c181b1916a9ea37d033f59946dcef92a7e8e1b38cf18335f636766e4b481ab202d458dbab9d5216ce045861835bf275d56fb1af86c31a769b5a01a78f7b498be924c4969350dac7d94f4225a77c9333430a6f49598d2330fc13370b24d84a8f135035f3282d68e25722f5a65e0bd35e9ecf14b7fe84a062e64c6aed17b595fdf18189923b6e40d1203675fc2644ce139f461e0644e39a91271639dbd60e04229a52ed742bec06fe61c82fe94d62152bcc07e9c20316fea3c2ae5bac007116c33e89c74cc762eb0a9459dda4f132184942db02164e98598a916389dfe7792560c49044916f8641a3725ff94d2670d16d8f461b2b4c4d1619db9021766aa64b434ad595356e06b4c349569ad0a7c069534f6a6a5d15da102dfed962c7bbca7c0a5ebcd4da9475aa490149854425aae52f9826e370a6ce82e6191440a14b8dad2117472b2cc9b3d81c95eb5a6a7544fbecc09dcedc60b397375bb3d4de0be3a8b54bf99c077e4245334dd2cc97c094c48695d35a994a03b51025b3a064d22a734e2499204aeee3e9ae605d30e151278b38a9a297fc811d86c49930c3aa71cf48f8cc0e8e991e3f9626a6aa5089c0aa63939e72e917c1381911163f7e660c2c7ab21b02a2289bc2f3361a710388d185a82106910d8ca48a7828c1cc2f207089c88e74e0aaaf699dc1f30528369ce67a9a3f7e7032ea6124aef88b29c35a407ec9b10adf5764bd2823c602da4f13449a6ec8057fd0edf538bff1dd1017ba956ff64e9e449c2470eb8fbbbda943d2f287b71c02465712c5a9e99f8770356e4475691fca7c57d1b3029fa6b05cd7aa577d78031f5d1ef4d9f96c7140df8dddd12daa4a5a887cc8089b1e28e74d71c554d19f031758359e527066c9de80a06dc8a48d041f9a70c217c01273f7f76b1353f5cc0e6b825738654bda7b782ebcfdef696f5528a145630b69293298bd62a1c2b6d5a446dbba2a96094ecf7ca3d13156c0a7549c4763b05bf7549f76db5a660df7593870eba52b0a73a650a8fd9a1244a0a4e44d717211a44c5108e82b314754be95acc9d2da26057636b49dcfba42e1a0a4eaf266dce2e41c1644dd64987c84906937f82c939481029d9dd3b7f9ee03fb2a7d0a72753077d2798205bb332ffa720630a2738d1ebb89bf29a9278d9043f499ad03129fdbd26d104a7dc5643b3ffd8e99e092ec48af95444523d398f0926a7d1d2796385975a976094dcac7b135f4b309a214f361dda64969c4ab0b153e6355922079d1f25f8516e6a41de65a89c3c031693604496972691dd92ce6212b09004e39df43da4ba9160d4b4d2266d1016b46627304830a2566b2a65fa083ebae8ac4fef9872a53882c9bd7b3a3fe5b74ea6ed01168d602ced4a2e7d59a2df89118cbc189645f069c992d9249322f888e6c1d32389b6f789e03d7e5af1151d118cade82bd91937c71ca3032c0ec1870ed31bcb93d2d1d48660f73529bd078b59a8746f650259341288040251381088e162de2300031408001034288e4622c1601e69baf401148003512e1e3a2e2a141c221614161a148983e16018180c86c1a04018180a0703c100421e44399c1ecf3621fc13368bb43dc1793085894982986a70654067d06650cea0cfa0da206a506e90df20dba0c120c5a0863c981c2b691ad606df1ce099d0809062504334d8177b704c3b836f06980e1a11aadcc19884946d6f1d614d8133076594b099bd88c9b1323d63f7555b15d2800e423bf476563f2859891c3ddeacc1fc30d8bc0a504638208ba2fa7748601cc025c015c09380b3027ff78da2310714e50e4c0160c82694e5c42aeb259d0236e423d941001c401d401d403340e901fd0b54c5b0437737c0690600640002002c00600dd0c293ab513e02f0de00cc29520997b10184c326db53ab40ac005f0f60aa140307735f66cac75da310a07adfd85652bbb31e09124a594099c2384cd9801f7a8b048e3b7eb92fd889a6355a1b593928302fe8b983b113363fae1da64f4db427f1a6dd835458f880cdef902c4d9b5e415673361a887305290c1a94da7c0b14b46f6dcf1bf5d7330f1076c8b0646ff8b1801c68d10a5ba43048b39da9da42bbf6e890f567b4fd539d02ee507fbf2c83ce9185583072a16426b80802833941ba8fc67bf7a2f568d019eda3772a8f4ebf57125648eeb22a351747bfecb3ad58da24850709176281e0a873161770c2fa6b08415dd32926b91b7a219e2d995c4173e450c80257c1a2de2f537cf5166323ed1ab3060f16b7790d949ea5a1b6a9b5394db763335d74142bb413304c40245ebe683fb298cf5faf90ea6ab216c17857f66600669b1743c7e2aa7fb1c7e8ad0f3043e6e4600363158aff284e29e0d95885a2b5c8f05b0f28b6150bd09d47d7d7c7801d2ef3e2a7835a9780c6b7c3aaeadce158f5fb8011791151e1e753f39e32ad6123466247541c44a6528dec5f4e1dd55643a5d26fa238a3e0123d1378904c073106eb25326731055f4b7e247b6e38a455729beb20a1686b5075c999d07cfcec75bb8b30a61bd32458bb59a3a4ec541fa0f03f0a0822511ca5f2511cb4cb7c46ac48914d9430a902aa1c849a625284845982223f052cdf40cd439540850b545fab3bcd61110a1ea180ef44284579fb437bd47a184e62a71b4a18d427d415d415d42bd451a86b8b02a2c1a8908403aa2f1d6743d4826a6fa274a8e4ad890fd57194334f017b4674c4071430f8d5f5d61e8a769221e4511fd529350df500759a46dd9b1f4706e081fa037575d45598ba371457534d43d543494339c0a29abbf5d2d651ea3fd53551c0b2972edb10a026a0a0a112a03ae628da52f33eac81ea85b280aa868a41541f029c6299076a0187d2018744497da178416565d4bd6f3df4bd0a3505050785e251b409ee8033a55641f141d540950a541cbe953d94289413d43aa81fa82b51a7ec541cd98bc19838141b546aa82e543d54f4a3fab0a0624531a839505473ad9353544e4115ea0c6a1bd41ed41bd431d49fa38017121c701e8deacb78f970f2df14b301e54228e013f304a6734290aa4ba380e4105c894a1410af53be5995026d8102c6ce7f5c17b20802454301a1179d23e943019b9315d786a180e4b4f102d3a368c3b206ec0b8a3f940d5415542404aa6c85d6b32ea84528b050b550b550b1504150bd50b550d183d2d1bb67903002e508f50a14f00f4f5a2ea4c8eaa43e5dd3aa06b3dec11e269bf23c7bdf7f40183c34c630feaef1c0a724bfb12354a0e9fe1fb3f29628ec9bb754af1ceef1b02a47668ca534e370a78f886b610f65000c7704d3826ecf14172aa857c8bba7e076ef6c59d9296cfa0ed97befe9d67646c33db5e4b1b3296cc32e56883afeb013f98a145940e48624b6b249d119e5aff5f39528acd9517c24aec86ee12bd2018e4e46a7f1705947251e9acb299446846e5e7e5e745e745ecc5e845ef45ef45ed05e08f0ebc99cf85ffcbd78bdb4efd7f56f9ecfa37b4178c578257925e2afc5c7a924b6e9a5cebed0521d6bc6972582b3effe8c32ab1ac211c477f5ab0ca58a246da2bcb2e548fe9332ec54558a86160cb057c65f31608d5e895e3dbd6ab9d7936cf80bbd7a517989f2eba8f33143ffbf1621cc030d5caf35fb3511da187c30f362f02ae295caafe37652f297e8756cb2ff38c29c8abeb26fa0a096bfb810ba02919eb461e6639a95c2875d3fc6acf7122c1bda691862a591b05db357fa66d6d16117dace9a1236aeb3338223513ca8c2ef889320fb8681d180e1e5c35fae0c01d99ccb581d545ab7afd2d281f0e5b8d682b1c6379149fc701614157e1751158ab67c5edbd4e7ed9e782b7e4499a2657348c211c510f5103b9f38b8a5e8c4ea5273f9f725992346d7e63feea1fb81e99f2cbac0ba8202a304ae5be0c5fbd02ce420009d40e69c56138265692f72978717ba72a743389246019663f117cb39f9fc8743176f0387c1d5b25ce26903aa4f676cab19bd526aa8ce400aebcc18904b84bd39880c52953a44004b04ce5909f480d6d5840a17acf033a254c0e58d0a6bc6977d15faef13986630b26fc9986a108d99f16104ecf5b3f35dcb4d44fa1b377c498ca0443445b18a51bbf880fbfad91b8b3fdef860b0afbe061c173399c00ae791c9008a039f5094fe1207a6c08f36bfd9308b8ea376a1ad16768e2c7f0155b6c897a220741a13a496ba139edeeda09130f8da532091ed6d3806e3c2a0623f800677adf312143ac81e0762d3cc2864befba4b14629011335d81fead98c69a744547948f10d977500f515fd3d08badc967aaf793276e10dc199f78ddbc1d811af15c164dad86a708fd4ee7e42d6af1bb82e5d5cb724003113fd360aad505a9eb86c0ce861f94c113d87aa5a148569c455a53f252b7d35404a0ca69af4ac6e5a31c616eb730582b18be988440ce1501e795c0d0a16020f77517e6f84745c09d9816b3b6d63ac4e5050f0f0bc077188ecded05fc790e7926382ca3af3b2ddac2f52c02b92f82124b39956203e88333eda90f3e907137d00bcad1f943f48cf21b14ae75bc1bb9a78e39e9b34e51c866c6df82ee33a68069f1404cf46d41c22cb507b7fc46542799ae7e1bdf453f8197f81031a69725f06688384434e656d70817f1d6fc7eac7c619fb43421384f27278b3b8204eef7295968e0939fbe58711456eb9038b27d3719afd864427cd6c2b7766d9944e4736339f2db39c7e39a51946c04aa995430bbe0e74380b189881029652e2ac5d66a81e508afed713a76d6e9baa2ca14eedcd17481e1769cd23a146e4958ea06e6ab4aab00e90d31c47dda97b135a14fd67e993636af726f47e1967f828c7e265d9f98b7e5e1d374de306bc8c245504de9fbe8924ce83373ca3c1653e6fe8f0ee2e2a54780ec7d992b0d43605fa8c39d1c5f15414776263a3040636919635fbadf36ebde856d8c2c0e02cebc9ad68019631e9cc6894ea7c4da0c9245acce6012841c9d004947a389d7240177597499d9e6e1700a19a381edf59556101e5b8597d981369af489487d700fa9f9e2da10ab5f44efc86d16a34853f2fbaa7cabbaa3f084552a46d349af8abcc804260f6ce43ba17cbec89f3d528c4ed9e17ec57375c8ee42e72a4184a9bfbbb48e76bcb65916ccbc6838d8cde355e0e8be1459058195976d4e400f695c561c271b72fafdfb76e065423e492688b78b5a2d05671674700b7c8096dbc0e88d2ae4db209ffeb99eb4b9e41a1d71f4cfce865e0297ef39c2dddca0ea9f050879cab4af6212ff2c3bbd751b6e4549d959f2694ee4f252db9192ea0f13cafbddf1b0999103eb1e7d12401c480defce89cc7edb1ac00ffc1d11d55e04ac55594e7d7a5064c805e5a65337dbd495bba123c56d06ae304afdf320106ed5e21b6e8a23ed1eab0388a172afcc1dfbdf3a0aaabf17eb4fe0c7649210398b3947c7df6bce0be3a19affeabb5706282367b163403b1a6a58dbfa60447b300bb718635db3c6990e03db0ff36107f0d42b9fca17b40e499c8659f9b25238f187db8c41760684af5a5383412757422cadab5da0f59c80e9b8a1e03b6a822f4d179c0a6cf1e0204d63dadbd94628ec5688c7f1564ea7b9e8047122784151f7081328082804fc7d1a8b20887999f3cae091c54ac35b609d1afbd728cd256b56d5e6ed3efea8a66d66d8a3faca705da88435c1895ab0f5cd4e57c4160470f51b36a68647004de59d20abfe9685cc5ff3d0344964c6d1ddd9c01c404603ad2eb909d485a115dc1ae7c292b15455feb70af5ce3a6b469407efa09e1e52d591a3ec37d7de609ea64ad73f1d40f1f028531ad123c115fdc20b2ba5eb7ac14c16e36c8168e6946232139ce7b4406fa0a3c8542444b98499bc1fbfbacc8b45cc102935473ec3afd721d1ec74ed393453e0e984786eeefb6ad288e622d0d668f44b2d92f309f2c49ca5c22d7a7891ae448ed102b7b5e20ad5448eb65371f0e2b914cf9543e1c76bac6ab484d5f4a2868e87ecc97d5f102e3360659a935f1e040d82c33ab2aea48019506aa3d6ef953c5add18476f563d60072967426d756f1b4f1803e263e2d072377988fbc2dba89d3f58689b30146a084dab04eb41e98f3b4bcb2d22abd314cf41ffc169ecd2fb9b7c86a188bdaaa11df6694e594f6cb3ea8365eb28d31c95517f9518343badb38d06b050c1b9e007ee837fb1e000eb8e303780f161f5237312af388b2969fd2db42916e6744fa8104f54fb0d1146346cab827c8d6d7628492fa79101ede960211bf72390958809e8139d7bd4386a606a7e69059a9ab232f52e6c253eee181c6425dabfea8d79a75927d826b2f06ef10fd4628e809ad3914568d35629c7c656e2013fb06ca91497c458ec120d9585cdbf18035120101d761c0a038005d5cc1666ad98f1745400a4175d048838ede6c2fe7df6945d6456839dac46e6d9714cd5a8ba729f9e9f2272e1cbf0412a3782ce9a2bd965dcaa68f72e42cad2e9eec0040d6f9580148a14746a32946695d9bd14ff6910d81901b2aac38dee6c2b51a7ed474f0d020aa075c30920d5c1837693f27be836992b929b9f7ea21beccdf7eadae08251ade11a35f965fc8c17a7ab2007bbd46aac9fc672f299523e33bb845c678e317b93f4d2d868e44afa9663965eddc13e0ee06105f5b22439f82f998e31cf529588ec8749d98332133f90abdea3da267fb3008ba2802e90af13284385d9bff0cd166f5dc77a5e5fa4d7b6a0c84eee8780f3cb37e5c3f1ed022ad0039947e2aba2c9a87153efcfbbd87497ff1ddb1e06dbf5ca243c5545aac95b6098637246cd193a408eba48f021eb528a2cc895dfd53747d592dfdf5d0a8488f62a48c5827a3227e099d737bdf8d0adec1a2b7f446edd8b8bd99ce0bd966ffd8dced97ae45ceb4707c560f43dd2cbd6a890aefeaa4df71a01bff8897d432d45049448e51cc613a4aea029f28a01866016f9f747728acc2ea797688c747e2657d774cc819780f916b7d01db878d0f24d712b5f967397e5aafa90fec3891078e4f3f988643ac2ea713fe85e0bccb544ae490c2e2da36b64babe21628b32bc9e02af4179d76896f219ae65edea0bfeb0547ec2f38be18f7aec050d3954e86ad7c2db481d943419417eaad29bcbe0e5a43fae0ecfdf27c3f213f9aedd169e0947796552e2783e0c182bd13f59efeea5c6b607b2a8de9db3731b89d850981d2b444e45e7b9a68a8fd61448077190d2c1a8503acfc9de694211cf10b562958b501bd57cef3a453b7025ace16a001a3413a5cdbe815d1f9ba5af4dd91235cdbc459b9caaffcea6ec51027b88a71e9a1254d020cc8f29d409e6745030de01edd4a6ad08560831a42067087eeb86d901493d51787eaef6daf77f2073fb99eedd8da562e88d95e8d694869b36d79352ffad39e21eef1c29b8c128151209587aa4d2057569ac644ee884220cfb32280fe7fce417095ea64dd6deba87787579d5d7ad7ecc1fa09dafbb865e3a0a2a122b37fea3e2b322063f3c05cf9cce9277774c8b91743567ff195552827687d5321ead36aa8ded6fdb7d7f6ba87a6345e00b9eefad53e138f51f0625a3e16fa00d3207fb67f1906f5ea53a4d22a192df25ac1d038f4ead5b594291da548da0982c3b310283365e26540c7c9604351b5b4451b66e1315d9d7faed4930e44c759096811f19a305a2826e36e7b2448b6e477b86b9a48dc3cce6e4100279fd4c64c7693c5e05a2c9e2eaf85caaa88bc0d1ff4dd74d9d261416d3ec89f8b780a9c6e522219fed7fde73a831ac8b1a199ee9d411ff4c17524450bd84fa4405283e5c39c8348ad24d02778b7ea799f4998bc8b568308c00c01cd74a1114c59c583dc98c68bee81656303d231d0a67ee86554c1563177476c065d12500e10ad7072e898fd309b6960d405d91acbc7a31fabcafc4593f717439ae7fad7390b1e25363c87496cce9b4931eabc92121ce8ed653881634c47156c41c48aff5510e8da5378810c32c64aefd160c12340ce4455b6c29bf604133c9460a1092463467a37cd64b4033dc0ecf039686cd577cfc67b45ac58a25f560592bbe2990883261b7b39fc03c9c2c247418c11e18b72e25233261c7b1dc4b20938c0dc1827c33c6d99b40d581681d1158472e364bd8b3c9649891971f181dbb89c59679036e5c3f11f578f7b462a6cf8aa24582b632ac90a70d41a8caade04789b6dde3e4b276536af0f7ab6cd6587ed9707d335210646c958b9c8bd28c326da35f1fbd21d138860f3487ec9dce0ad3ca85b8ab872cbf183fa5118861939bbf4cd6d291ee3c353619b1ba9d256b87e40bbd10b142be2d3ed6400fc9dc4aba3cf40a056c5e6b021b9281da68905cb8b9e371d30f57a4528e960fa3e43bc86fc437b1c3ce824d53067e9c5141b399d2951ce852f0146cf3ecd96a4e22b6ec08dc0790b63890c5a0e6142190b683078b164579bb1d29f820c88c0dcc7bc8a5bc3aef229a8484fc7082370dfa46348c156192943a1f8b2412e0a0403e85d5c98e0a1eb75b7f4ad0422c5b7eabbb16c1ce89c71591a19c42425626b5d8066449dbddea5b3522b4f79e31c3ef25ff2f5330fbb696a2a0204bc9a7b7df46de83fc8d577da88c59b385ae6762a6675f2c9de66d9ddb7ce8b9505ce0727814cb06b7052832237c6c33c5c2207100ecd7bf26ae292d11d0184e170cfa154b3327b9360e0326bdf8460519a48cca6dee901a92df33b7913e5d0360a2e94dc175a04fc5b39e052f4945909a670185f7957a6964c28c35e6b3a250403ca2d0c5d61007c50ae191f8041149035dd831e6116001b51631575ddcc851b66680a9872a757a8305e988506062bcf6241678a6b0af071db832bdc174886441e1a40a6fc9177b8042c79d93409b17f15372670dc395b93184ef642924b13f4de5e0a05c798702d549b42a883da678ceaf96b0afb188301f9509e60fa8c4020665d553493c04bb496eab290e270b3cff361fb031e138a92a87714f9bf4dd6838a814c77be55fd7660c9318883fdea12da67f6aa768927f4babfc35d99395438cb7edd1caa1de02cdb40fd19eb29561b3e65b2e910b83a146ab3ad507c454ee67167ad8fe81a2e838796ba6ce2d78a382052b9e9b5a218d549798d6b5747d107e8a419a46276ad3b8bcdebb37c08d05ce48faf42dacb43e01b7637952c129ae596364879fca85bee6d8c7f5628332024f9c921060f8d3f5398f4d5d5d55b68fd263b4fdaf9f223881a0d0e9e574939dfa179a5987be194c7fbff03c7c9c7d7655f668f69e3cf1b3f0df59ed40e7b2d1567627503970225c4eb0d75f3ecc09dddb41fe5266139a3cda8978b33c3fc488d4d7eb3fda7af694c762044a016a8de25207edd8fd1c571e661061003b0a2618e0dffe08a3515d54f2103e593b2d8ad6c34eb136877476e6c0ca167cf2ed3ea0bb103e6e898361fa5805674e60d10b83ede3685b9c92d7c1ecc65e04b7a64dc046e954ecbb57512424a08f0f12d203bc7ba52e0a646c058fcd3b52fb202f01aea8ce0df99cc9eaa292ee68c4ef5dc408fa66c6e06c658eba4ee2dbc52953157be27e987ccc1056e75adbfd5c075112ee9e5c6ea844b02db43e78b835464df8b26c7207f334bdf8a23845ae6cb3ae0c4b8ea8963f0d0fd48311606571c4770b22ee910147cc825d4a204244d770120f796d2e7346c590f2cb9b28112094637d7a417d401505cfba9f0190a8aed59bbd67b4dc7b4b4e0fcdfc0c5153480976c12bd84985f43b99d13a28b989bab1d6016ab02461b453ccf8a05ad8173f62806fb50ab689f91ef66ea1f9b4f75f1ca6389f6c4f6e9480e312359a29b00a7a1a41fea454b47555b2d28464efe0ed77a0efe53b309ca6481914ec0adafe115c026c72213b20be76b16947beace79ff90e5c848e8c5c2152cf148c9b22bba3ee3a556c87005d49f268c7349306317a8f3f9077720340b5489b27e52274db89e6d0ba570591b5ff17ae0101e93fa9f1a6024137d3b079c0b312d3a403941348075daaabfb8c35043de75949844e2ba3b1529023bea5d8ce0f7f6dd11bdc6c1abd3a7af574709c256cf61904be356c73bd026a053f24079d474440c39339e2f0b02efba80a636bae759bacf9f9948181c0d60895ff870425cbe59e5ae710de2534bb8f3f7de68cdca134a7d94ff4469dea045fbac79cb7cf1b522ee2f90337454a386c4b097830210ea31f762daccc424cf4ac822548a98210ef61e3bd42f730da373f834f32b0f362784a85520dc49fa82c15bd266f30544ccaa66cb13ed2e3898a8a3f3aac826e94c608b497827786aa8c25da2f5600ca1b01901452fa8d87d3c587af771832e3b4ef3ee866bca201875a44cf54a0912a0dbb5d6a56d9d270e482528cd8ec243dcd1b23b53a3b11b1a2dc49aefa08095df45fdbde26ebb751415405de50a10d5791d10efd8dbe5bc9906f24a7394061ddce5513251bad244455199f503d81484ff11fbfe4e3c9bfe93dea10bb5812dab028f37ae5c39d5a645d72c32c53006881ee69555524bd178af4d4c512d283ad51c7f0a4c26deaa6660c93189d0cd4f35ae130abe0bc974ea36b919401409bfa28505a9eb5a3365dd45cf3ea9411f3fe74113a7bf9b5159893b0bc1e4a366245824eb8c02ed05f676baa6717df6aa8781263018af539d7b23320252e1b25b6e33509fdd9a34d67ab0f45f9d66c6e149a11941cf887528616f5a721e60e2397fd1f407b7bf21893d505c0b82a3bff0837489e74d2e56cb8481119bd8f5aa7cc167191d70e6718f1a97d8f629b42de93fa2284c33f42d5e44d20d39e2e147544592a469a8bc394511ee813ddd2887348ed23479973b1b62b58133f05f487fa6cab6382711cb3a351aa40f562b165bb17aaa5fb931897d0157ce76a9a2941a41ba08a36b816486e9724615223ef4fbdc49cd4eff68ecca28814eb2780a3293bd355b3a6c9c67a16c9634dcd73b8dd5207bebb8c4a8c95b02dccdf09e3b9aa39c5d5d6b494d3f8b2d1dc1b45e4dc0ecdd9eaf74f8fc4593222e68c56ebf8389963c41dc8d8165d325aaa11f0036808347ebd155fd324aedcd2f0a63e705526a15efd59e331ed97fb4cedd5796db744e2ee51e4a28f614ccba63e6b71ce4a105bc23269148c15f1727dacda23aa466f515231d4f26e1351da4e70c9376e4c261326334a614108941cebd7dace8341751ab44553d449251bc56da73f3b102d5adcc409da1b8b0dd6ba9ed841c4cd44e59b91d1f0744ae0befebb853dd42d4509df12f8417e1543d15c8d206420101fea167d28aa49f19174b435ba50f193615fc7763c0f60609af547b9e1b8fa85b2d1cb7124531a8ad8a3b8f1b8096ffa57bb1679096dbd13de15b1222467945f80427cdf351c4a6ef384e6840610cb0d22e88e420edf3629640c4021f3b3ec7b0e94c7904d150685164ab1069ee6f7ccd7ddb6b7397714b51e63dbd05dff21047de3356c3d85bc01ae33fda37790a28d2ebe69a7b1dae7a7bb940db87e4165840b3a0da3a65845ca72b802e6d6820b1dc2ced750bb970f98ce1534857a2950dc876d1e53fb5134d271cda1d4a2268820d14fd798d00950210dabf2cb29f1aabde0bd2f7a7ea71c36db020b54baa037406a10f290c58c6c04c9dbcd969c7c0c89ccadeaad5efc4bbf26f181f77384b0b8bca61227fa5aaeaa29f17e3cd7c56846cd964797fe50596d607d58894d37b603e7d2a6fd8c1cd9d0da9284e752a972c55e0cd6a5522bee50e2565819f3a0e5b9ad1482842bd978cb8a079e71f2b631f8c8ea789136797b119dbae23d92e4c7436cac1cb5caef920892d51a095cb5e301c6970a106cf76ec668ba006878daac83a3fed4be9db17cda7599232116638674b8ed64a2031a1ce04d744874fdf9cf4775eea52ee93ceef9e8eb998ad1a6986a243ec27055cf499da0739fc70f235bfdfce9fed2eb7527a03dd161dc23d89afdd25d77cade96a78be6d9201632ee86729864614166e49c1f0d047ab206ffbe8c7d918a13da212f2f810942b8cb8f775dc8994389037873c4651ead3cec31d010460548bcc127cf63f56b9eef8a7e8f9c0743a82f0599bc14cbcf1b190795a18b500915bb0201d8d7536e763fe40dabee31924ed85e8f09e5741e8b46c3c8b42865ab7c74b1d6a07fcd12690d557ecd6b9cdfa7e9a1075135e39eef400a23c83ffdf779d6b9ff68925c69e7584075813393fd6376e47b275752bfc9b76c364614358e98b9f93067b131b129b818d8ccd171bfbb00b50ff4da42d6cefc5262846a3f7287ceaa602b98f7e6c4b10083927625a49717256f1ca9e92d2b63c0ee50b6d757f742e04cd39294b608a5fd8f486bf0313f69af348d1a5761b6915a212918092d166e3246df3f6ae405618b686e6aa184ba5ff15e9dff8a908c31d05a053020067f3d479534507aa048e55ed86340c87627dcc015d7332a37c984e723ac0624ada9d6805f6eef8f25441d8117f0845be44339beec49fa8c735aa212892479c89ce9979839006d014ffc9a7d4cce3584692187e1795042265cb4f9672ddc25a01b849088efc664a42e635400899db12e577a29ccb3e1220b89fce1732d066acec716e60d0140356509e19f7edf6624cc8decbe0b157f3331774fb5bf45d1a63ed833c5e0ed712dde89e952924e96cbbe3d6743887c3b2350b86c8f663f9f7f9eb54d019641243279d0710eb3ebb255056a21b963dfa0ab51b25bce9a738c7e3ba5cc2b957d3a80b1db3525da812aefefd0ed5734899aa18147e8b740cb2301eb58166e969b5420d371e1fb1275851361b764f7196fe34e9f537ab6e6d835c2a1665035aa54d14d11851c138a2b3ec708a21e22e3b10761d60526639189b080fdade1ee52e8d87122e0ca3f37e8c32f6b5f1a99b91021bda98dbe51d38532f548d09a1cdb5dcd46658fb76dd36334ab15be947ba424c43386c7a0080c5f44b23da6fcb963a75dd223ea12209ad779f61a72246ea9ccc4540fea6feeffca7b9df83493d502feda7518226a359829ce0477311dcb99164b4ff958869cbab0d2df5260117797ac97d6d4410dbf8bf6ff38f2485fe9e821d6944542f52794dfb212b43cf865f85e844e750f6090589d6cc7e7da68cce627ca1ce9e7b7832e2ac89f700aca7cf31dff3736a601a9dcbc1ac5a4160ff4229701e7d163d2013e924964a424cf54ea74c4028f9813375fbc48419fe392862ad47a6fdea7e526753a0fd3424e84d57f0e259a74ada54a5abcc1b3131161d65f33b15265d35b173154e42d251119436b5816a8f5b3e924b36cd4ea3a85eeaa86cfd1cabc94b9b6fc4b7d0004cdc9c9ac7cd6c51d7639b5a01fc35027ace779b3a70eea4900330fcf0c30f3ffcf0c30f3ffcf0eb6c867010f2899864a5f53bbfbaaa12e07c5352529225e3ffcd9afdb58192b58192b58192977301c809ba09ec09dc041a51388a318368881355a537281ce4a489a975abba2a963ad078c281678a68e7042bcde128d070c2417f458ced1fe9734836e1c8ab8348975dd896cb84a3ac90528610dc251cbef9db55aa38f9bf42071a4a3870dded8e3192241cffc5ce5c59e3c4949b31300e349070ac72b1ba3fbdc43e4738f6b40c2ec13724ebd3084771ad315fd7ed5e4d07071a4538f64f997f626c79df9408079f534c44f53895e319c241bea8bbaed1df95c34238baf6fcb2399b37d008c29187aa30297badc518ad25d000c251b6da75d2aca41df70f0e52d9a494c2fe56bb436da0e183e324599e54e37c47cf3d3836fb0e99fa3c8fbf448307c753b177a272bccfadbb50fac298c0ef0a0c2cc08b118401460abe088302ee0ad8224301347670f86d5bf93a03c38b2eb8e8a20c2fea28023474705829931db1ba39f864061a3938cece1d53a64e1a2345c6400307c7dbdb2dd9624b688959e00b2f4c199e002559a07183e3a01f793a3d675a521dd0b0c1f10613cbdee9bf539a6b7098fd5cacfd3f06d194185e74b1c51662d0a0c1e169b0b9b0b9cfe028e594ffd2b6cdd52eed820cc380531a3238d28d17374e3a06c7a12fdaabec2777ec6170185c3527c99025636d1a2f384a5fa9544f1b267dd170c181e7be8d8a752b8e3cc22c44c6d3bd25597110fd838618e65a12fb2a8e3f86e8c857a9e2a8bb66c3654e638e792a8e5b3a6fa7246e39114105111db7d5f33ea720759c8b7c9574531cbf67f7596a67cbf629c5417c38d11cbbda181e521c4bdca60d369fa4da328a8318d5d6c3edde778e8be2c8e32f3f227abb2a1b8ae38c5e19aa5b06c5815fae10be2dc987463f7118249ea7f5ac1a91a3278e37c7e43421afe710cc4e1cec25ed4d2bc9737a72e2e82eddce972689eddc260e531a89ea2995ba99451387496e2fa4a46ca163cbc4b15d566baee9f1d462e2e853dc2cd3fd1247e672b7258e4454b2598ab1119daac4f1ba5ec9685429713cf152fb74e50d5fd1248ea742d6185583258d39ca82199238ca27392c67a9eb98934dc18c481cc5f7f017d65f636c0e240eb4b354ca39da8f38eacca056b69d230ebddf2f86d68c097d69c4a1d4d5665c488c388eed39e782c5b7757ec6220ea2c5f55d2eaba4bf228e3cd6aac54c7d333b1371bc99c973ecbbb890d50c441cd444d59290b3bbb855d630e31047ab9a1635db45fed28b2e4ec005d5126618e2f8e5365b6e25de7e5d8863adb4292d4fbeb9d210e230ddab425acd64b71c185e708134c61661c6208e63e608b2192e7d292988e390c4726d4d6c2e99e00e6604e2d03f3b62f3b576a42c200ce311b5152efdc3917dafdcade58f34d6e960861f0e3edc55c879b3a7caedc3819edae585ca4ec93d3e1c455275cb6ed916550d66ece1683a68dfcd4868598f1e8ef4ce3ccfa2bf66b9f37090824e7ccbabf07020dde942fcd94b293e7738d87c9353feca4acd6887c3f01424746d5787c39a4da12d4987430f579b3df5ae25324283197338928fc934989a64282113c40c391c5caa6fd7e8751ddf8a718130cc88c3b1ba94a5bed411fb61381cee5b878c99adb255e50d4726c9fad7226279e686a374e93ca5da6a660adb70a4417246c4325b8cb2e12865c4f210e56ae73b0117472e460a3030868b218619630334630d4712e2a41599520d475b71c368a8cd01c3c510c300291803032a989186e3b2b5dbd8de561a73c0988186e3eb584936c53c3191679cc1142554f2915630c30c4761d63c429e18f2e614045ca181321c65f78c776e91cbe292e1d826c56cedcc6c259d318643ef0c3df71417c3a15eb8301552864929010ca4c08c3186c111cc08c371fa178d27613fbb2c60388823a5913fdf2f1c680a121e36c69c1a572ffc51ff428ad9b40b076fe2997261316a835c380afb13ed1566b3764280195b389e8938a9dea5fd3205ccd042cec8c20c2cd88c2b1c6f4fa70b1953dbeda60bb2c10c2b582f155656d1aec271cc10cba3946dc5149d4185a3e825d3eeb7a156df195338d0df8a613d74e2c8b9c5dcf84b148e2a7bd6226c9414c30b858332db18aee17dc271fc93919c75b256ad4e380ecf3dcf39984d38f2983bbf8fcd84e392d9d4f8d12c395bc2a145da1295e99470901de653d6c4241cef8b5c05fdcd4a63876006120ea345b38aa142473892987c2e963e4f9ec80c231ccd5f4ce599725cb26d46118e474743a8a89d9d4184a3f87962c4d3b7bd75c80d3386701ce5d7c724cd62fe344308c7122a9475e4db88a6705146185f9041e802338270b4712d2e9746cf1872188514338070d0957feab33b7fc6bfa398f183a310affb21a7dcb1ac77a154a898e183e310d54a9164f454564bc58c1e1c6e52d51cffc22ef4b6d8826a060f0e3ca7cb4e69a3329c0c320c174766eca048b699543fba020157943106152ee43043074793bbfa1fa7cfc1919dec06c9d291c2a57170e89da583fbcb0598718363a92ef7fabd9552cf06872135723aead1276d336a7094aa43dce68f1049f2193438cafe5292c3b6e97bc88c191c7647f35bcf4b020e0203c6d20c191cefe5b0d9a12e5ceda70a4303553362709cbff22de494cf192b46980183831ec9e7912e58678b21c28c171c74b6b8aeeca40c672b1f238cbe805960860b8e55fa3e5c5ebe1469314a508693518b452b0ec62ed2737e168bfc75a144069162c18aa388b963ac74a5efd757715ca1f19db9557e2d57c5e1dae6f53f3b1507b1a5b37fb060db72a3e240c73eec36068dcf9de270e6d3f6aee62b09b1298edb737df4518933c9528a63f7d47d1a1245d75b52b0baf5f12b257514873abd19c2ce298a0399a929cfcd122262a138ae781d425bcefec983e2305d4a9a3a68bac5479f3876971855be725ac83d7110cebe724821fed175e22885a4decc9359246d06c83d60c1092653fc7787486ee2c0be3d9f6b7bcebe7b12b0d0c451d8478ecbd9629189a3f71d71a9aef50a5860e228dbba4328d5bc948c52018b4b1c458dfd69928f9ce62c712c12161b3fbc953848de9d327f904c11c90a5850e2a826a564b521c60d396712c7c92564fb5871bdabe014b090c471987c7943e62f4e2a2eb088c481f489a58b9ab579251690389098375de73fb7a78dc5238e937e5e0ca55f712a8485230e76be3ff67c52b77c5834e2d0276626a509352a592c1871b41b3fdf8589394d368b38c89ba2640caba08085220e364fb21039ccfa053711c7156ccceeb25820e228a78f1cfd439ef05ab138c471e7a78ae43a626188a38d1fa298449aca21195814e278ce25c49a24b1c6a21a032c0861b49887ebfa8e3977a19474050616a080086cb1051765f8180d46180820a3015b6c01868b208c32b820c3bbe832cc08b6d8e20a81c520120b41d41669012c02715c316d45962f9f109518b000c44168c4f88dc4d8e4fd0f873b3a93f93256dce97e387ea908093926e193f7e160bca67aee2d72b60e1f0eece4a34cb26f9ba6f7709c51b36c3e8d583bb51e0e3dda2464edb902c5d4f14206c7a592d2535e772306d85aaa7e083617611c33c2060c0e82c445996dfbe4f2e161e305c716e4c286a0125762aceab0e182e3ac96d3e3c4e83db915c73329b769635b3b3dac38c8d1f6e34ae73307e90e3556a14f879aeafca22a8e4362f8df963c99ea151d6aa4e2482384a94e91e36b8ea3e2207dca4f9f776ba8718ae371cb496fb255438de74cc52adb7e32821aa53870b98b14e3fdb4e69453831447fe1ff3e65fd653737ca8318a4379f34df1696bdf3936871aa238b4d777d9d149a6a146280e255b0e5972f5559e078a438d9d577721dd48ced5f8c4f1e430e551328e4ccb353cf1c712579b19895577a164c5458d4e1c6b44ce4c13529ac389c3fb2f359fa96c7241f2428d4d1c564e1f7b36d6f9e5790935347114dadccc2bcf52cc452a13c713baa13b84ad6a60e228f47b9cea9a4eed145f3441d5b8c4d199c4601236a68ebd5be2b8eb35fee323e5264f258e2b58985429ceaefd4289a3f0d3112a9ac673b44ce2b0b2a7dfa04be228947fa409fdd12c66240e434cfbbd1e41481cada59c923d498d471cc745ced92ff78e38e891e90d9f2fbce802015b6c61871a8d388ae8d192a43a31d5c8888370933d048831823118506311c7512521de8615711c23630a8bed127118b5e22df27888e620e2e863b4354971da620b2e680ca23ed43844b16fd925e8668638b890d917b9558d421c65b6cc38e177421ce967399becf40e151fc461d4bc2e2e3171fec3823875ccb10ac4e178acf06c31b946a580b8cfceea65d63f1c65b110abf553629e9c1f8edf2b59fccd55a30fc73efea163eaf0e1c87cae636e088f22fb1e0efbbc6298dfb49fd37a380a973fa887b314e39787430b1727630ef36b13e3e1b023844fbe361252e70e873bd39233bcfd556a8763b9ce29576c5e52d0d4e1207bf96910eb4c532d1d8e7385dad8bd8a7f967338d23cc1c77d2363ba723854977ab5ef8ae12c8cc341be9bab5a7e7038dedbe8d099e80dc7394d75c4c76bb8e1a04d3d9687aa0e95ff361c88f77bfa059f0d871b345b48ef49a6d5d770a8d97a13cb72351caaff8724a9b6663d69383a598b1e47f744d368389e9c2f597e7cce70109521449b6ff7189d828d6d88fb4d97e1f02396e7df6c93e128c532472a87cfb163c67010529658fa8d21846dc4701055634d8b59c2701cf9630e995a51fa5c301c556d76c6fbf40b079e5f2155bea07179f4c271ce8edf3bf18d1463178e92776b97c620178e63929e84e0aff6f56de138e9869c5a96da9c4e0b073962ea31454ebc3a0b471d3fe7ce28dff063e150f7ef6388664c86af7018f3fca4a5f859216c5638923cea9fc43f5d3aabc2d1cba46c39db4585c30b979496f348b6650a87f17ccfea3629901937d5870945e1305665bd4908b9734628e0841a50387c996c91ba50952dfe84a3b4f927ac63f4387e3be1205d45f65fda84a398653ae387dc92ae64c2519a14d613a992a6c8985063093594709c26bd496cdef06076128e572c5744434d420d241cdb2593e91021644ccc165b24a2c6110e63ec7d798e560d775da00b320c03b6c4302368400d231c77089751e4bb752fa70ba5d43dd4284241f466f334590a11ea820cd3450b6a10e15872bbf94f495d1c2ec8f0130618554609260001f7620c0c44a2c6108e72689e48aa1217ca2c01185c7c185c143ac0058c12033584701442a4d8926123d49b65841a413888b8f296d3e7f89714a10610acc60f0eff33f5e674d91a3e386c0b9749222da446df838308d1a7245894681b91e145a3c07970fc9f4683a7a9608451480335767064725927fad96a7661400d1d1cba46f0b8f96fc64732bc80805aa0460e8eafbb64ffd3f8565d5c5081c01c206be0e070b4c76cc257ba02030b2003015720e08a11340746d0284841d4b8c181ce861863746517ff9830be98000afc9049a0860d8e7ace3dbc2f6ae6e732d4a8c161ef7eeeff7618dfc5508306879a73d8c8fb35166acce0306454d1ef490acaa0420d19d488c1d1fbff7a923ca163c8156ac0e030e7c64af91023776a6bbce02845d98a7ad9a328d470c15143889938217a1446185d70e15f1c2faae440a31587dba6e19b4429d060c561be3e310f32792d3a739153a0b18a2389902d87c47fb8185d8181055c81802fbe30c01508b8e20a045c81802baec00004ae3842484315871f646d5435dead30cae0a2d8a1918a833edb7429345071d449ed3f367ec4c5fa1487973729f227e7943c6c8ae38db1a93ba5e9d130699482a49f3727cd9e1447616f8fe2e8628adc985b3e8b4514071be347a59a90fca2a1388c1cd594f2098a0309414270a9a0f1beffc461e7f348df515e040d4f1cda9bcd67080ffa7e278e34e588bf5f9d1307994322cb8d9b380e9e36e25dcaf915714d1c74b6f20ddbcf1cda4c1cc4ac9c72a2b59321260e2fce7aa60e5eea1f305c0c329006342e719031db8ab4b744eb8e250e5c35f7c7958694a3af5860d0a8c4816feb670c6f97824d8963d50916ae159244a52771acc973db54a42571bc7677a3295f6c951c89e30abf7142b6061247a7bf633753f5ee96471c6807b949a92cd5cae28803cb9f53af4efa5fcf36e2302f3674b46b95ad282390eff8f198451cf465b01c62bbac2355c451468a41b3dde59a9f88e32f8bca2013f31f4e44f02f751bf25e52e81007d933cbdde6d21007f9537db3536fd9948538ca29499d7e4a65a424c461ca8c7fd13e9645080771bcb7ba6a84be4b3182388cba4bb9914b547302711c1b2e4be53be2d20788c38d512da79918d467fbc3b1f8f7e68743b50ae9672e75f0b90f59fda64cf3e148e2be47ce3a27c37b388cf163a755ce33cdea81d2ac88112d9bc46e694b6331735a5a1a7938e84acb1ce2e3e6070f87dfd17edfbcc35168ff878ef1d9e1287f287dddb0ea70909eb94bf32ceee5890e8733229f65253a334c7338885e4992c3a1c65deafafbbb55e370e85ffbea9e63789e70388a8be1a266fd247fc38124af0ad3792923e786c36ce956a3d47957aa0dc777933b9494ae278974a1f485e93020a054be30ce001a6c3890dc2ab5b85149048d351c656edbee564abf9e622168a8e150a26f5f6ba64d1992693894ba370f99fdeb316d1034d070947749c25dd4dc8c92331c5a081312566e62de6a82a06186630b952a345f321a65384ae9589241da527fa0418623cdb952c8e0395b9e681f688ce1d83ebce4fcb3c470e861f795c9a3bb028d301c7a4c92942bfe5c555f78a00186c3b8e43b9dd2e6b8b5d41d687ce1502e877cfa59a33d5776a0e18523e9918ff943a206ff74e128c7f1e95c325924d24fa0c185e3d6c9dd1472660b473ddbb17b1a936c8c160e7cc2aa9b84350dab6864e1e0ab53be0db92c5838b2948a663d10685ce1e07273ecbcf217e5fa20d0b0c251d4df6b5ee9b0b81df5018d2a1cbef8a7b55cb129c5910a47e923319bc685b4eb7e40630a07e36eedb26d569a39522858bcceba3505ff08b562ec237b1c717cbf9f5dd45463da4e2308d1e5b2456eef9411c739c4cd9c38d71666594466771b36deefa688239b75b9fa34713c3e8697e105f9175cc89045228e275d67c7bd8f88e3b0103153f38738f0778fc1ae2b346537c4b1e7f1b8a7655196ff421c76ca7c9fe28734e631843898f73c57cbd11f561bc4a1ca464e2e270ae2b86b375eccf96ee90fc441dc1ce2a5a496cb920b88c309f1b7f442f787030d2512266462852cfc70f4912466f1cd92b61c15b2e8c36148e4d13c9bda436f3e1c5584cb6f2bf71e8e538c9242f9c5cb1c347a3872ebb1903bce29649187e3ca95cb37a7c6c9f778f823733e79cf8fef70d019b723a2f67638d45039bfa4742e3ca70e66d188fa91f2fad0e13866afc55c58f988f21cb424933fe74a9d28a21c7e491d267b860e9a389839ef62957e957587c371c886247759bee1307b947c51f5fce9a31b8e6d4279e6a9fbce93e342c590451b8e534cb66dbaa1e3f767c351fd5d48db4b9765fb1a8edc83a678baf799425c0d0753c942cadc95341c7bad680e9573f6b48986a3902168b29043fb3b7886c3087957aa524e91309917b230c3f1b807c949e2a9bde4cb7094f62fc242eb64384e1b2d660d97c770f479727ebb8488b7ba9085180e4ca34506cdffba97301c780833daf9413786070cc731c678ddf3ec41f2fec2e159dbe518c3b5536cc43023302164e1858378b1226972dcc686d403ae40c015b4852cba508aca87fe5c20ad66e58466cb6f61119da4160e5a15c92f5976784e16e8ce326bf5c1c293653d7c0849f2397d857334a70f5f5b414b8b1b1727882797ab80578e4125eba496af50c1168f199ffad2296471e42fcb7bfe4b2a852ca290c6c4f821426558a0c09d4b2e9f1c29f3e6134ad2154542e54caba1135eb58939b2c7bc3781e8f3e830010b51c29c47ffc92de1e80fb7c430114812c38c8050164ae824f24892a425d62661496732f3a97a4124f0ffd2b9ad53ecacfe0887fe9e7e26669d560c3302338215c483844a112a8dcde9adf3d7f94984e3d7dc1de2f93f0462ded3fa678cb13f11c2d1e5e4312dfa6948bf8390471ccfffe7934b201c44ee78994359d0989a1f1c73ce88ef1f363e8961a8c43023301464e183c310c627e374787e64c53011200ac8a2078719dca6d345b4f5869590050f0e4b935f8e1ae39f67548e90c50e8ec542dd7da4570707215d57ec85c866b63938b4ac97cc36d13f5f2c0b1c1c59eead8cadac7fa96f5017c8c206c712f383060db211b2a8c171f0bd903b711331d9343890dccc9a1dc52c66703819a12e6ad6d07b1bf1200b191ce5a8a9623e5fd765450259c4e0f03b3e46d2e225ef1f06ae86883291f80b8ef642c6780b1ed43d59b8e0f8e24588776561333cad38ae38ee12be66561c78da7b8fd7cd2a0e3504ef934d2b1131ab8a239df8254923a74fd6a6e238438694ac3e7bbf43541c8a465df5cf8bf7f24e71641df675ab62a638a8ce52d1f98feb77290e5a3a4e72d25ef20d290e4354e7d2ae7f6a1cc5f17f8d864b88f4ae4a14c7929b5fdb326e6ea62b104043d808c5d1e67b08dd8f31467fdc8b313000840d501c7af6e99308fb13c75eb9c23544d0f27cf1c451862db795b93a71f439447db0c189a35c21438b474ac815c1266c6c02f7ae1a8d6d399a3848371fb7fc6236327174ff5e1f721213ce6d7fcc921aa15ee2482da3dadd9f77e66f894f633d4f5e34a5b21207617b5248ad6da93713c30625485e492ba668967a0e9527c58e21ae863cd898c471cd848b6e1ddea96a0afc0144071b9238cee4f312237754c4c546240e424e9d57622c4d529e0bac2b30b000481cc4ec9273bc30dd73b90b2511981194016c3ce23842497fc4297dadc9011b8e403c6d46cc2a13361a4165c48edc9a236c30828a9418c26511476ddbd44abf4cd8091b8a38482d757f9d92a55bab0b2531cc09c8e0028c30d49ce002604ca0c060231187a9233605cf253f1e93820d441c7988202924d94fdfb00ba5431c7587b7f31cdd5b47c086218ee3b6db59f478751eed08360a716463a92b5134edbc49888388c1628fe5fafc772645606310074136e78a5e9f0c22f7628c32ca86200ebba2b337ed53cfe60371a8fa7d15af9b2ecd03c4f1988fe69c6270bb0f75a104c6182528c3c7e0028ce7620464981370e165981d60e30fc779bb32e49430ca00c38b30ca00a30108d8f0c3d16bafc686cc9a3378fa709cd672fcbcb27615637c38d670ad1f5d2112427e0fc75145fa639818212bb8a18783f81a215351fa537784aa4660ee6394c19887a3b0d7f119c52585d137f0702813c532e7247a33dee1e8ca5228f95f759d330a1b7638bcad482100034fd8a8c361e5930b66b7d77e5117ba4107fd62630e1b72b88d387c71f597434cb30b2513b805b6d8c2043e86d118658831870d381c24bbd408db1095dfe5c2bb68d36294800b118411c6175a812b10700504aec000040a895102118411c61769828d371ca54edf99899812c3e586a3149952c7b451fdd8461b8ea5e29378c4deb8e0b3e1f0fd6f3eba2ba6edb2b186a388d6f1acd06d194236d4709cb62a67cf29de85d2175f983e301450b491860d341c6fca1db5245ffd59772c60812db6d8620b0bb802ba28c38b0d7c613c015b6c7126810e701180196c9ce15036a6cbeb36792a8e8a880d331cd5879e44fb66888d3294a2aba628eb621c36c870541937e4c771af6c5a17aa63d818c351dffac776486c9ca87a61430c59a7541eb9c984c446188e2bbfe65ec9e1dad906c371089735c49bd8ecb869c4c617dcfa9a49d974ae0d2f1cd9495db089af8b3407b1d185032bff9c75593136b87014d264ab562b4d39c7c3b0b18503f7aa0c1bd2ffe306b9d0f262430b47be53ad1acfe25accc828c3c9e0820c343248b09185839c5233d3354264cbf062045e7ca1b58185a36c17f364fdcd9ec7eb42e9ca031b5738d2368d3ea562bb096cc30a47551e652d2419f53a27b05185e3cd1bff2a567bac3418a60c2f38c130c00615a83eb031850d6c48e120ccbd6fc4f5603617ae022fcaf0020c4346148ee44c3ba4a5c66ab31cd880c2517a5bcbb0b5cb30031b4f38b6904a8be2fe86138ed3e4911d17b509c729a55e464846974d02b1c184a30ed1b9db431e09f737967070c15add50027935b5f744e1b09184a394db35a5a26a3e6d01400b1b48380c2106d9cd6f4f175d0f1b4738ec2f0f71f1b42b1070870d231c7d8ed48cd9381d368a706cd123b5a37bae4bd15d010db0336c10e1f82f8c26877094e34f2cf9ae741aa7f2c186100eea3359ca60317c8535061b4138f61ad3c8da6631edd38552d960030847d52126fc4d48b0bc651a367e7078d9d61f924dd20c1b3e38966a5f95b6b4d29ceac1f1a66c716f721e1c58f0105541f42be244c3c60e0ee4b54227fee965fd75908464912ebb3595612307075ddf9b2df9e85dcce3e0705266518f7a51bb3b17366e70a4f9e4375feb4362b4850d1b1c746af0d9beb58b8d1a1c7b4feadf90950d1a1ce4dad98e91f62b8278c0702eaa9eb03183a3241772eac91ba38538b61c430e218e3a4eda85dc64d43f8823cf9f5ff553942cad200efd23547bee609d6a208e73b28fb9b2dc144a401ce67b8e78baf51fb60f1ef5c371bd9b59a69cb69ee43e1caaac078d9af626850f473219d2e9bc8847b8ece1b057eb5752c6ca13d74376bdf1e38770f3706c1722a9a7440c77119455bb09480402c0c391590af183d84e5c8adee120445cf675b57bf4b4c3e16699d998d4cf8dc13a1c764af5a73e221d0eef35cd4d67a227787338ced9fec37c7c64b9981c8e45fd4dba2bc7b0d4e270686a2eed49f33eda0587a3b594ce2ac525b8586f38c81432bf3dab7ffcca0d47fa90192278d586434fbfbe9afe39569c0dc72e6979d3b3e9fabc868348b969530c799962d4701c63f927a6cfaba7a4e128a864eb56b4447b091a8e3dc5599c8de8caea194a618200cc709452a9955de7feb05418045086a36097e29ee5dc8200c870902eab64ffa8ceadfe188eb3b52d623369cee28b21552080301c4b444fda49ddd6b407c3e17ef6982a13c2bec7bf7014736b887d1173b4b8170e2e3fdbef8b65cf90d385a30da51d3af675a4ce85239d57179fec9683d85b3808d1abfa43b01444d7c2412e0f1ffae349eb270b07e313536889aeeb2c168e3fa5ed226b854ce6150e83dc869853c888b9d80a073b315b16cf3199dda60a07eff37eb91e2a1c47ae98e52a2667a9a770a096b25ca572799d8b14b82080281c581e0bf36351a2d20285a3b4ae0cba339fb5ef138e3cd7d4bf7deb84839a3bcf8aec1b35679b70e89a1e524f3e091a2f130e3fb56a5287bc90769770147453ecb3144ff351251ccccf47b08e7d351d4dc2b17e65bdd67c22e120633d44ccf811729347384e9ea142e6b3f89da6110e425fc6a9cf482f5f16e16832b28789cb20d913e1783a582c8b380ee1b862e8aca9b2536c8b42384c563a9ef3e618a1c4201ced5e8b450c9a5e3404c271ae54f937e33f380c1d3359be5c2652fbe038e44ebf8926f3d7ac0747e79a576f26e647cd8343b7b218521ae66da91d1cc56e468b3f9621d93a38eef0f09250520e8e2d86692f7bedc9530802c0c171a57ccb46caf9463b3738d4ed4c7e29c4c9b2c906c7b1eabd6b9f1a1c8418fb556f7e1317018200687090c7375dda28ff1f9dc191c549cb46f60290c1c16a6cac4a91211db900627050377a393f2adbd72d00181c9ccb84dc506962620be00587924e3d7d9ad5bc712300171cdf7ec76b780a6e49d38a83db942e0679d9bcf9c28a834f51c6e723969ba9ab384e1b61f935a93b7a5015c72a16eeb2bfef44c3541cd8ece578e3f23bf9a1e228cb974c083dfa397ca73814d1f87eb14d71ac11733e64d5965aad1447e173ae7c0f51f972487190ab6343c59da5d0d5288ec7c2697e96f0db5e140731c753ca1fde452d148a43df9c8e6f313ae74d7ea005288e3b494599b8b93b4bffc4714cfb9669d1633eed78e2d8436593ebb5c65ba71307314c9af5b49f2288cd89c398dfa6fcf4673ed59b388ea32986060f6d31c89a3848b1c2f52c993892d048a9f9ee7dcf60e2d852fa2037f21337572e712c9f247464a994435c4b1c7affbb9ea85ad48a56e2404265980c7195a6494a1c86d49e2c6e0527716ce13d224e779238f233d3ca5e31a2a72271181b2ad9c7ce49b3a4207160dda2f351723add896af188438b5d5dc9fa71c4f1a48a714f377948921b712439cc6f366fa6998611471a3ec2f2878b38cc15e1a288a3a82771c3b78938cc39d23a37aca6fb1511871d72df6396aaaf8c1ee2a083df5bddd746c8a4218e6225c9187a8285380adda89dd112296f23c4c1e888c479ea920dd9204892ece7553b411c7d0e1ab59348758654200eec36dcec66251f0f01e238b537766eaecdceffe1c077f32685ad9b684925410b3f1c49dd5897c7b40beff7e120236c48be7af3e13866b1b1d6eddff89c3d1c8a4d8c9c7252b2183b7a38e89832417bdf2e375ae4e17066433a06cbe0e1208799feb9206935297738ae12ed942f2475623b1c76b0fe984919cb531d8e2356d60afa6d5d214987a32449e72a559cc3d159b4f42159ab679a1c8a4921c76474ffd20f681187a370c12f66cb294fc6eb085ac0416fd79435ff063bb3d747f4dda0c8c67aeadbb0b998f8ffce865bcfc42d89e5ec6b3827a64aa49025e36a30f676ae054f73f134e8298c7464d2d1e04f84fc92f3331ca8e56fe690c1a26d6e062a4f7542fd46b14f194e77cdec519d31870cc6892198e668318627b45ecbcc7f3d5a88c1aa30b739a7b71661b0bc27c6b9c140dabb87103e97fd052605cf0f963eadec0566f4829ee4cc1d2b77817c5b1d4fe6029e2c34f4cae9c95b28f684c7c9d0295f8cb5405cb5eb94fa353fe12c50626146cbe5eb7d838533478c61b3588ef93657387cd287b9e8b2adc08ae4f5b61039e4520564d52ee9bcd5cd4b05de6c3eee8674b92964b6f9d22fd8064b490199a45b9a3da4c46811854c23c7be58f8bf40a134edda3d398dfd5c9eb0db6d8cd709e734217872abe8952d4d30a56fab182ca6a58509e6644d87a73c31e525102635f59d9c89ac0422866db647db3c4d12f8efd8bfe322e1b0b3657a8ece123a5c2eb438c2eea17eed3ba56e8df077f028d94263cad416c1149235fee7ddd410216dcbee901cc1552d8670b23c8f3abef1a91642e8642e5ebeec99522d8270e65f8a9de4b6974e2d8070be8f97e47e67ffc0ac9a318ace87257d60e467448f75d7f6608921578ca6163cb073a76a3f679a9fa9c50eeebc4e99f37265a9850e9cb9b09d69e6c0eae41d9752750707c565d590df6dbcc11943cab72c0bdaa0d457e639895ad4e0304b56aa129e29895ad0e04b3a3197e6fe0effb498c19d431aed8976f5692183f29cba8ee5dfbdcd6911032ab746c829e197725ac0e014726589ea1452ac9c162f58626e4ebca22e8ba7850b4aaf3fbf89edd7b5c2d515950a413656d86f397a8cda2a0e5fb319b3dcfc97a68a46bcd24f07cd525108a94c156e6f2164a83035697a0c6143f7750a6fbcdb93ca8598e3650a33c74497938aea54299a1416e3666bcd96278569b329fd37add38fc264f1bcd24417855f975dc59365fa864291ffe4cbaccde58282cad50c5149f737fc04122b5d33ed7d4e21e4896f7ddf6b346f759d784fbd53facee939e1a4fbaed59ba0ef43dbc284945813c6e011424c33b1578a9b4298206d8c692e52c72f4188398748cf1294b44bba50258c6351f53743c948082576fbf288eafbb1f2320926ce44952d092ae73dcf712b7fa81909e37e3edda56472fe42e23869ae46c81334b41a8aeda8440ea70279301689c4e16040144861e171015314000000001414862281402c4b637df601148003512a1a3e2c2a141e1c0e121414121e100643616060201083c26050200c0803c221713132c5d503dd27811ecad464223f1da44db89bf03621e5089b6644bbc918837db09376505c91b648237866b0a960e9e03461135bf52dc29a34c8014f20171c2cd79c5ccfd2fae43303c2d22332e29cfc75303abdf04a0dfe0cce518315c246d807d380646066d0c120dfa09a816707fbe20c1521e18165091c27e449f0baf91168056a14d2ef517f27a0c79e37a55664b352fdc6d127d02f59c5518aa7142605b74ea93a9d3401dbc3a3a68ec89cb6701a9b91d74909bc2f4a48bc0987828112a23767da76e06fd2a7546fdf58bb21efd36fcde3bc95476f1039b82a685916490e045c656d3d0cbc2438340037aef9a856cb303e38336f70f6c02f827d071f08181ca824bc9a1043421a42aa81871f6c1e2ac9190d4d98414658e1a0bca6b7ec2143dbc6257b83f95a7c03c57530b909e26029379031b83760668035b822837d26a180c1cf8096c1d9e0f541924f1873b2f397c4da80cdc06070f50d263b4ed6c18c09ec08ea1f182108767023844dcc776b50fdc1a6657847ec5c2701200864ba64d9933823c844ca4194f186f100c68ee863fffc59ffdbfe0aff8b7e220009c078806e805e808c00fe131038aef12ea9080416d017b8362046a02d004ca31c3207bbaa1e6c1e101ee41ec11efefd637b5e887a8d21d2eaa1e861e4e1c9e34e1fa7c849c626351fef106447e9f18318e4018fd33f332b9accf120492569abe8e407bfcffe64973a8ad51448a510093770dba2162209f766cdfa23ee46a8f893f2919ef2518450f853b8d90a7079ca195b5294539c73c59f901455dbb120a5185c61660b117e70cc28702436153e0c200e619f05076eeae11744a488f0aa62f769ca46756f8b10a28db869e25302a61120856db1af0c02a48e8801f457dac41adc94b3b6529de4c17ea1b9922c3710101ef9938520e9e8eeefb9841465976d8d91eef24c1384a6645ef5e7a8a3a3f0e3cf48a4d16d703fa5a2c2f9d0e187dbe7e6decbfa714f730115f7686937cf4d8ae307a63e4d6dd0fd6cd9811f2d5264f634cd52d59f71e58d9313f3c2d5ba10bd9b0cb294671ad99be1aef8f27b3b2b83b1cf21ca9fd5f776054bf9b7dab508ea3bf45a5326092e26ee24fcd06109126b777f7552e9edbc5ea5e615aab5afb0badf3b5908219e4c8ee04b24e84e7ed72d7a1802b9996490dc2f59e5052ecb93494c12ec2e7700a5d558493808b37596dea30a74b96219bd170ab05aad9ae07590fef17c49d99567a4b6eaeadbc46bb4b58f2ee3e7fda11372933b515ac8be15cbec3e565bd3ce2507c481dffb5dc9758e82f74946f2c34863162375eceaf1fc5dc9e127b49fbc3fee17b9cf4c72bd0b26f01aa2c02f6931fc0899594f1aa9721cc124a941dcbb87faddc8e8d34bdd9b274ee9ea31aa473e81dfb0bbfd76ee1d16cee38e6325008a9c6ca2c74a1795139abe71e0d6890753c9cf6d92f6ecd8d4c46f4c5381737779c208cd219a422e6e2a5769c9a72b84c46da759c2a180e3fd4774756038896e236ab5637843f323f97df09fdf032fddfa2beffa4d248d7e37e3994de1f657a92aff65d7dbd7f34befd7bbc89b16ee79259fda4ac9e883d41d2e5b19f7e58e7ac9b10eefd041cf6719cf67b68d1332ee51439d87c0527a3fb8ca37801ecff1c6d6f2b9fb64cc641535cbc3c0a8fb49a111b74a2cc7a24cf60ecf3a68b795e96cf6915b41d621fa3d893f8e5f001da51187b51101f7808a581d22946a6f2901bd16804f4a1368529766b6f5a15779df16f7fa1c50578bde9910ae397ee16afeb241bcbca2f340bbaad7571c07262dc598c1b1e712cae5a5f593c8ff390e9071a7365e7a60ced4cb0b3f8b5d240d9757857fb4cc8cad00dd5a589dd7849a6ea10b28559bcf44331885d550587a71245c29d293b740303a31ade02ba5e367bbd73dce3aca60e4be3a3ab6c4b3b601c0113913e37ae7799e4fdad080d37488a0d1ddb8f69cd2e11ae160b42b65fc77e9726b1c82f1c327dbc7b7f87cc8742940203ef93e56fbdc8e0bba11465855168a01401edbde726381707b6c90098a27421e5bb004a18989f43fd18c481deb706837e1300d1dce765fd09b1e97262aabfd470ee12edc4c4bd091bd44618e9fc083a1cc5cb4c64a487085516390502d0aa0b0c35b2b975f331d52fd635f1a3a0d28954812a48bbd6c1b790919c6d0be6110fde1ae09a8bf42fcbf0e6745cc200a00878f0d4f85c6d82a983e24db7bac0ce8cc20f7f1a6413f5c353ccd22e6e0bb1b093326f2b76c1abb0cf2d077841abd0a11622305c3e88ae2afac8681940fc8d1e3b93428d0f860b6730ae026fb2508d3292a279edf4c3432a3379e4de856262cbe5a92386e499bd0dd9346c5e5013d41c20a54dc3edd423afa6c6b3f90b5e14517ab172bd6b7ce0c92740c41ce09a2661d64238542c267de48c5d8e16fd6c77dd4c434b644b08d0ca41f2f6160a99f84a9173aad59328ed18a7865b67b4093a49f93c776e758e6681024d4c196d13d4bf478d459b1546d6d3eb97fd3f84cccd55878c55c445b956918bdf068403366118861740197a832f57338d8c719bc188d596c009d5635871418c704a5a6ca00622ce610c90f4a213a01e848fdaa8991443e6f69dccbce6afa502f3d9271da449127959b25c6b161db1fd9ad4d2026f776aef0a5ef5a2a32a1c579af3ad85c6069109cd5cbe4c7f0ef15ea8bf4b8bcad720df2ac2eab5a43973fbdf9accb66d8bf6c7543c56c63420dcac4a58761815382cc091c8d5f156bf3048069f8177c1581146110c10fe1992600d4610ada589560c0c2370bfa0aaf113831d3f31890f290398f58ba0bc92b33de29035700cb5fb4d0ef66dac0252c2ed8e1a84e62d8df365dc0da7fc8fe85e7c6f64fe97f01fdd58b41fc6e59ff0302704a7e6d91048032a95028e81a4e9085959b03b74a6fc81f0ef4f460f388980d17149c4f99612f8a00cb10bc50898d9da235c07a5131242e6ca3e0b08f2e6166704f1fc477d463210fa4c909231d62c92c5821c57c157504e3d5436e2b9de0f1889cf68eb6c2a225cc6699044fab221f8fa75e219d545199aaf515c6d4a5ee12447f7aaa80143b51d4f01ff622a2d4af5bf20eb2fda988e25d2260d8314e5eae625e8d331b5bf7383a5135b6e09cf45c9835a3f3bccdf59fe9b35eadb13e1dcdb6653b4d9a94008842458d40f8e0dcf8446f4ff51ed07490bc047df61f5af3834ad28c6001afa4f62cc2169f8f053dd088da2760099cb9a1daa11c1f299f386725c2821b538aa02c657a346e259c60851d08a7c59d739e098ab8813a1436de750253df2ca4381cd60812eebf332cb7afccaa3e1284aa36c2a3b34f06614fda8fae05f568795a9378e31e9b274d40257c66d91d44a1f3e474bc00a0dcca899795c165f0921842a63937cc355526c78b06b10f5f2c17828acbd8296ff346606ac3808de57b8b3b62920c1cb71fbe8433f4a5a51976f78efa109a645fcdd04bffd17c04c31e638095295dd80457144c3adb9104ace2400896e813f27a2352f4c809fa5f458e4edd0601ea1dca3226202f0d628410774d66c426f217a48033d7a858bbc408319c35889f963acd33c6a7d1f213c079fdda76d30bb0e60e2691640b2ea708006413252dfb896b17403ca512394b0054d43f60254605e547e1e33f35d5edcee8f2eb4a81b7c45007872ea944eb5ebb12ae238dd0bac42380372b0cb59edefa12878cb091ad584a54bc12420778d9dd5836c8c485eca46f917c110a57760c3a1627aa1dda02d67d604972cf1ab771123311e80a1803b5de1b6b67536cf7ff4cba8ab4150254255c52cff51475aa03ec11b232cc686e7aba3cf5889e91f0ff29d847d52968fe6f81650828da4590d5bad1c9dddeadb786529d6108ae2f28e51284a1c0675b52994cc2e6987f014bf22fd5200655713e267463a371af5c5e7c8594f4b251c431a0cec258aa1dc4e63ec2d281693fc76973229837cab2aebe61d0cfcb322e65238cda88278322a67c954f06ec413c256ddef1e928ebf0319f046d1b0c43ee3c256f16d0822a1291880c8098b8f735895aa42c4badc0004aae48ca6b45f2001bd5e4cc3f7ea130f42d8f243502c62b02396ce759e272ee60c189c0c1aed80a36ae3c21778e3f07c8ab3db012538a894d5332b3ade3f7735415a5827afb2063b79624ea56e56e925cf7f80abe5bdeca6333bbdb10cdc9056d588b15e85490c869be8ea12a38ec0fd1cb87eb98b8ef3e76c15733a144326fbc8d412efe284b91c1b86f217627d2d0d9865606cda32bed71abb95d41e8992ee4e44d5c754b90a671701c00a45be2cb36c24a4eb95e48976332a56f1401f59a1b90712e9d9c039bb1a9805e1151dc55b97806f127c1092566578c3fd82b5f4578c1eaacfb52807a42836e86f38728abe82c2e3ed576d62a29908a353492b1c4c98e599b08e8d80b02c7e538e73e6319fe593f02975677870e5665485595ca0f6ee48d14c9e2333a6d50c989daeba0e80e03ccae9d2d0cc6a45aacea04a0982c485af5aa40a42c2f1e1758606694d39cdc504404064185fc16157b5326eb911827f41d7d9c6078c3b8723c657c9b5580c13169798871dc8cab07026dd65dcdafa36920192c5941c4507ac977d5a062e147b5a39fc502defe9fb049ca45e749d3093b95a4c14f6a3984da382fc0b7ee5c3c605f0bc4760aa80e3f9661e02700892590c5948106357d5fef4d55fc3830e518f1a6c7ad8c95953567e49fd23ab61e4e1f2c3e6b424c2404f95dcc39be5b25f81e0db5cdfe6aea333891b71a79f26956d5d83ef12fd04733829084258ac78f533c28ee80a0e2b3d4b94cd940e319292f1e06596feee67bfdd49cfa855428f6831ff20e4553a7f58d446b6c5d9cfdeb219428b4455196ecc5620142fcde9aa518316dc458256768e6e099e988ec075eec9f88bb8f3cef5bc594614cd6247b52c1b82b4fc25aac7479430fab9f8bccf0337582730510b7b8b469a54d1b6b347593acb391dc0fc493feedec1033482544641db7f7092a678a8469ce2895e8e0a352ae6eb81b23c51ee3f9ecc10b2f224bb8215d78bd799b2274a693d377da9fc52a1f80200ba6928c8fde84b4152ac792688d833b5a5052ebfaa15deca2a67a270881adb166a30ade07bb55239ebe5f0eb0c1e4a3f02a598dfb58f74b09f8399689346b9fb5c18b4bfa96756925c2665d35de089713dc7018adc788881a7c4b1033a2d24b6bee7ecf91fe829a0410e80bb48f2230d1b801b6360ca4eb88721918c8d0251dc8cb99b4ad27055fac3e872d634cafbf87afbb13e3e0923df632f968f58b60d8c9fc0c3707c6942123c0f87e3f4c8bc54760ab694701bb85a914334cb9a368b8baa9bd047af4c36a5ff154020f966688fed0d7a65737993553b59c0947edcb880374c9e1b972870efd733e65dce1329ce9a262a90307c592b0f2ebed554bbeabb3d994ac6f6c506b368b4b0c564a307d85a829231624060300f53ea0cdbc12ac53c7412cfdf08e07c4f367ed79f59f8f5e86a8c6d3f6e64b1641defa0e7854a42e8064fddcade5ac89ce6be386decdb7f790d823569fa985493be0ab5c122a4490eb249b5abef836a6440db64b82cb478e2747da7694ddd7209c7810fcf214ad4a74bb1fe939d4d18fd846c604f65674bba2a32d4a04129b1f87f6dd734ec393dfaf717ba9f97e403363d7736d7dd4640ac4fba7c0ccf2ec2c81ead9326e3ddb7a943a0bb0288cd9dcdac90d11efb4e177b4bba2d27b6d4f415708961a6242b703696b73587eff434b7fa373be9f5f724a90aca72b4390ca8829478b40e54aa0c0bca18abf53f99acb17bc8009c3218f8fd28856c7cebf337a5033928201315652a7eeb88be8e72e59b582959b3d218b61a3416fe7d39e6e69c24a8f4538f512bdea90b45ad8361a341c6548936bc380e98e8a2f452bc5d2a1e2d60748dea2d155b0267a3c1e15c8682d08a601646bd9f32b4f7e37c35e5bfe8cda7b019b9037e9319944e1bbd12cf7ff62ddb100693d708f77ee7ad8e217d8bcdb21749ec41d15475602d06af27fdc50ce04a643d2411a9189b8a1b28cb4467c9b87de20362c820b567cb38dd8d49e57e9d8d2996b0be992096d604cf2e3c306667a97eb69d46b807466876ad96fa26cc3e3f7f7b2fb9c9339aaf00a85d6d1a6b7c98cb7bb621831216afeb009eb9cde0d5a447c6c797e4e3e0493121abf9ee60b0826a14bfc39d164e259c9a6137a133cc93549eb2511261540a23af6346e62275181240f35432c51d92fdef7a195e09eaada63496efac97af7d8d7c7fbccf89bdee203e1909411b28487d3294d8fe43121c54e12457abcefae9c087c1e561e3fc46389544a4e308f63f67847d6d49b20e3f1eb31cc1e23b9d4573324f4f0f6d8e58362109c917b90668fc6f26309f9575210f2111b2127334fa90290933a008be2db1ea73be36091dd406b34e9c27198cb486729d6b88a8da31d4735bda1412f8dd2b479ac882b4fa379736b1e9accce1c1dea27902944685554e1191811f70475497f26ddc7816395e388996b7f80279d651f836a68c9024a0983bb08f4309761ad01682ae2ba614b8683bf1ce9623f97516600d282d36db8d20f91b0940e1a4d6eb365c29824bb20ee6f2077f20f7e89f84304858c26d01ac57265cf3504467aa693081dd0c5fa9b557aa03a411c3eafc41b138a0c956ee4f188ae38c8816ffe2023a59d5c547165c3f2187ad35f845695a95a3b76374bb15ea26336bb40524c506d3a8e091405736f1b4f6f3ff7ce871071d7435711b78572e0524a9fec1dc469261e9cc54276a5466c3571fa14f6bbd1679d819dacd2db3fbc178e916dd07074b3fb23afcec126313973568d944fb152fe8d5d17760dcf0fa296af4f33eb4d676ade974e103192ce317c1aea447f165543be8ebc11179ccd222565ff03c2decf3a2725d62e1f0c529838d9a0bed5b1e79e9cf316a23b4b39c5f71110b41a568f45246d6393f70419725757a480319703f587707a1838754c22c258021605f19d8b8f39f171cf93caefc00d3cd249644959ed0f9af9408ab6d210ad5e543ba8a2c0777ce23f3b1898d0f20eaa8f7cd742dc46c0e91842963eb78ab9abfb972e36c9a3e58cd10a4ef9f96c3f88f4229b0ea1538e40f934c8a28ed66ad1423a1e01cc703686f8325823abc051cb364eb4cc192dfdc89bc8a6c365d1fe3f1efa61f2cd1f981802107d39fd912c234f056808a688eebad2002e85dfba2fb545b093c3a1284c15efc8d0d576d770b7a003eaab3683b77e2e8e8ba3811f85e1a560b41c59f1ac035090534284975bcb65a8fb2132f7ce6e02bf2ddf482fe4cd25611d60adae3fc78d8df4620b5ec14d3e07cdc0336da2b108154d91ac94c4678d0e23c1d399d32f73159f06137d6135fbd14b93788a2e1fb37266fadf75bff099a65da7231078b4c86f79994281578788a00902c215f467d7dc280e877cccc92f3378111fe64a46fbfcfb9ffa4eb5d2c8eebf3b646bbfe4f04feb2415eda1ee0a2590f81c6cf3b7e71d84c61cbe2341ce681d854cc68582b14df18bf789fb4eb175ecc1bc2305c6c076ac53bbb9ef6b531589dd6505b0ed2044af82e049bb04036875e93b90b5bacead9ab1ba79c69992d3c9804a8c7b9cd17a561a4c35fb106b160b8bcf0d5b9e4a872e0326ac41e636af0695d8f6a52ede33b312479a6876003e84ca706c677438172ec0f5c5f71eaca8e7b4ca0e3ee6ca6b51546b953effe36de0f6553a9cb20a9c2aaaa6d8252801f3efb884ff75c494ff40a9587bf0e9c177142a3b9c78044cd79370e8c4f8a21f26e72c70c8f9153adcc0ee988e2a0d3c985c7c0c3fd41cc589a52e36d8cf0ccc69602f3ad49f791f1381b29782dfc11d227771ce62b9cc468136be8eea633bc1b92e9c890541772b7a97de07c91c35c5100910ce52fbdd6900314a516b561c878ed1a222b890178c1a1d23525baf61aa14358aed1b695988ba955087ed67c55e5b672603b6399e8e2d5cf7247b065ac99d0ef64d441ab5c7c6cdaf2ca9f5e09a0410f2826056b1243b504798443d4916795395dca3d61d06fd0c72677f412b560560d8c0b870aa05e41fb43f4e79a4c59e2e50381be8e0cc42d95f564c9544fbe55ac43041da584e009dec7acd8cac89abc76971cbbdfbd858ee5d84f159087dfa00b44b6810d4bd1d119738bb8f00ee28cae74693b9e187a3b4cc9ad7442645992222dac213ccdba62a11171c95992f53e5048e30a9d18b74bcadbc1bca24906b62b08a9b0ba87cdd5ac1d8f6ad414a0ca6e6059456ad6909198cd020f06b0fc83963fa88cfd4c9fb01307f10e0837de74787db13b62fab28ea3021396f2f0787e2f5246dda4328c01f7cc2795541a79f02f971a40d89e68897a092487072eca84b46d251a510524b186b3c5e46d64a9bbee03fbb7df308613424c577dad82d9ad600720555b4d3b3629e2d4d7327ed0bb8e3d8e0470eb8666703cc42841de9191f2f6ab237d8471d028bcc76fc195400095e1b453c2a399c4599ad299497f2c96e172075916f40453300159a7d53a401908ae4c4bd14f1f21484a29afd9388cdadb8a75729ba110a89ed641ac02363fc533d59f1d31f242028e3b964d3395ff0400d294a53d9a95265e79c9a141ae695483bad43710dc15bc19a1139c08e17fbc3bbcfb29adc241414daf705230b8a592ae295225ab0a8c085b20181c8a4d0910c6752dd06b012a89728cf3564ea2fdf094fb8b289b2c61d93b504f5bb67c050fab294ef779d33e473d489ae462a0488c0bc0c8015afd5f707b7022359588547f5adea36c432542a9b29b3a52da93dff8264e58200bf9435d888e532adcbe000cb4e1af7e7c821bf53ac63e9e2728892747621f833c328ac884e4504e25a69da60c85428307709e38eefeb6e97023765955437acd6234c5db9d179fd28339154dc6be1cdce57c6e9109061c4a41cdd4d3f8355a40d87e63e5d0a52408fc07176b0d90e10a37473a258076d858120a77f8a4c59cca0182b475bb1f5573d463fae8ebe634e3e2c02d3c55983dde1100d13540f3dc31290bb31ecd2ceb1d8440730ccc8d9082bc7a7b1dcf441c0974b5811404c080a05122b0f1c8bd60f0094c2b6c41a6b1807a0cee304fe13a8dc6f8a90383805bd5fab9944d8178f9d9a8e743f68074560328ec8008182ad324a1cd4801ab844e0c4acf421c7120b013f9a1ac188643063e7a46081d5c6e8e61abd5a0daeb82975345bd959837375907dd1efb5bf955a57d3210f2c65688dc15321872aefac90733dd4a394b6de8008a082a50629cc343a77eff84ce76389e46dcf5cacc629dd4cb28fbfea41ff8553f7e481017c423c91e052d8f1c9833c93874e15223ab32eca3abe39292b34691203f87f3332f5fadd98876428b242b682305224cb43e438be0aeb6a43e59d7bc35bd6c6f1bd090b9cdb282e42ae0dced789384aa2d01dfcca3e1134fb09af7908a4f655492cd59800f4b319d627f2dc007717837654a985319fbe59063f8cc1a696ebddfc94f71d797332dc919a53e186471caf2ab80a4b1a1a534c23eddf6d9ebf2eede844eb809ba6391da3de765e41ba888ee68ec55e603dd554d4150ba54880903ef9a602512abc2ae1acb2ce81bd6cf983004cebdd15425734b987ba603593449a4d9e6c136593f2ca3f92692ae0a3a737798680255d264f3c5a9349204062298d59e7005ed49881eb7a8fdb225551910630b00993e8a2dbbdf98d5dd98f5127f36c25a03a9d38e83a8c0b6045b3aefb95b8fd87a80b84486e38d44a0752635734c6b50608220daef1cef4bc9a3c4ca66ea83475e79b1d367a1f05ea417000d8a97428bcde4758e3a21050500a3855a003330d44279eaf051753b6d823c57d3d62011ada10b144c8a1977181242b2cb5ccc92566ebbe8b36471283dc47239f0933b272354e1a818f903a4e7e663ac8b72a911da030a4fcf75cb641dbe8b7285dbc5b55fbec626432fab2f512d15dd99fd0f5fa6dca6f6610a4642fc4591cef01bb9dd3cd976d4092c4db8621776e9ceac44315f38ef006dd47580454c068546ae7a01ab5f9486a58b81eaad422ee97739db1bd02c97e6daef4c4a11f5b228382cab1adacecc4bc11d85e1a399d03f209ef056c37953429a70fb81192ac00ff0f24d40d282239e119d6c06cb14bb0eee758a341ebc4236593cc74e0a1e115d634e56b606c056049897b94afeb0b010eb3a53cdeebc0e08cf5765b111970f493b019432f94ffe7318266fa1adc147138385d52c137194f76f3fcbee4e160c691ba8f0734931a38800fab6ad12bbba14aa516fc03246682a85c095f1e24e51cccb9ca453a602cfb5b26df07796a8c7b1701f791da2011ee4c3b6a2650b266501d9ac389e300db9e19374319ad726a84f9ca885ddfea18e38cf18e6b306202ee1da226de0e9c38a507631125ddc76da756c86f14437cd7bab541514abee48d2868046ac3a3c1c28bd889aebc37e9420a8d59a64b635440ceb44cd19c7cb8bc47b0abcf30939085a2248e5a900d8bcae36c93d9db60fe1826a120ab81887faa9243069e65c4e7a1cb70ac245f714562448aab28c6d8ec9e17ed82675f00cef408094df71563ee1106f5132f55cb6e40cbee7cb3ee61b6171f5da1ea69a2ef7cb08ec70c7d78295578004ef0bb989107ae0c4746d36c2c6913d259393a7ed3b8c1f183119f5135a37791750a279c8c4ac46a7970958c631bbd3866d5d89d476f3964f375156de041987b68a08290834aa40c7b8a74efba82e416b0d653c9b0a034d8fc14881480d61a9fbeeca975831c345346475315395d3a0c8e2bfef4c2bfeb1512390d0fb7a80e7adbeb2904b20d2f64f89102e81749b80491a1ecdd0f1e46042dc23de92a80b0ac8bb4ec6bb11c1ab20c086ab5b4e7036f282b65028749c6915c6bb778811fbeb9295d5e17c24b94d8f32a14ce251456db1c0a865c52b8a6db97e70ee76b2eafd42cabf3fbf3dc30802cf75335b100151cc14dc0cbb97f26a05b24b40033027d8b17d1d088dccc4cc62642a7605d3dc87a9ea9dfd23b276e96a60fcd73ddaca3861f77a85bf4447b25c7d94752468ab2f23b9871e3044c826680d5abc3b4fc7d72019ced1881b61b4e5cd2123bd7fe384409e2dd99ded6f6b6ff6a141c7704773c03cf017130e3b7db3df62487024ab02d3d683ca1ba6b865a9f4368d6e52cf63e7d1fa0372ef6f9655499b227a7414f0ca3288612562450eadb4b5f73ba1e265796183113d2129a9f5186b2e12a1add7c94414a39a0208046b6022657ea9bcf666d20119b086dc4cbabaf53c9d24aa2fd0855b0157f6ff036f359505a4920187c472e284e2568db416d08a32ba4411f0c2a0d6c06530665060dd06019e76d4291c8db544c1c47027ab3c7953870b0a490033ccff33ccff33ccff33ccff3a4c3f82cfba2012ddd95528a4db68fe4787b654acacc94767bdbc079d6064ad6064ad6a2972c173709e90906096fe0c326d323471ee89987165e7091812e8c1714d0d098e105175f94175c7ce106b6534ef5c12aa859693092944ce9a21a6d604d2cb8a7450e11181c34d8c0a69021c71392639cd4a0b106bee3fc8e27a923a93466a0a80d1a6a60eabb3dd6b81e4f48510d0d4368a4818d93a38f8310a9e921ed002cb4c0a2015868810503b0d0028b056881850282a08106c6cf53a447f5719c7f730626c70fd94166df0c7c6aba8a761fe4fbc82e031329a525c494d52003935352ccf7749ec12391a03106cea326777f485911aa1134c46059842af15055c2d4ac2255cacd62843c41230cfc5a8ced71a74ad9dd6980818f2d66dfbb0857e30bbc57cce97b3babc5cf16687881cb39770e0f935b5dca7581cf7bbbd61c6a25cb6a704135b6c0648ad261ed66010d2d1440230ba581056e23e55b09d3c8a0710576928795be9f1558bdf590277fd4dfe4abc05fce1d586a123bcb9c0adc45d85360b3f92611894b810d096bcd9fa28792de28f039cc2a2cacda4e5b28701d713aac723c674f9fc07814f247e6b40fd45227709bde92fb2c47d13f4713b89052eccf2815426b90099c9f5fc668ab9cb20397c0789c2c91337d68a239257015e3aa98c476d1ac2581cbbe9f36b790c06ef4b05c9a5287f67df162bd660f6254b402533ed03002df31460e42ac4e4d993f81171ed0280223212de264ae602499e782043370031a44e03aaaa895e81c4a8e1c20d0180253961a429d94da4b15070d217063f91266fa0902d36b19b1376288521d2030b93b0e2d6a073d99343f60cf527f9e6ce271a5dd077ac78de91e7039aed4ae46b7acee20b325692fdbfe76c0474cf3131ff1d8a3e88049dd2959c8154cabb31c301e07cfaf29830356efa3f4216add80d58fa38af162fa38ac0919346cc0791c4808cf8e7f739c1ab041cc3d4ab569c077f6facd0f351d3e03b2a48f21dd960167395a58e8e6a89cc6800fdf835a87390d18301243446b115fc187fca11fc4ebb882cd4c3e2989755ac18a7a9c232973c7c80c2bc87457992fb7ba23cb2ab868d93e2a91510513246285942226154c5eda8fc33899f5f247051fe5ab3009effe08fd29d8d50f5d93987e4c216f0a7e3c2da492a6145c966c63712f6a5a4f0a2ee6b4a6a0e3be9a8f82c91dae1ba17151b0ed5178fee4f9f1a91e0abe3b4ae594afbca27450b079ee152d1dc729e4f04ff0d51bc72b6bee09deb5725b8365bae674825bebcb99030fb2959c60fb737bbcf3d1eecc2618ebeff8d2de45cfa109fe53c8d1744727afcf04275231bade8b09ce5f6332ddcfaa8a964b70191a52e2c7d3bd61b144eddbc927755482cfa167caea37091d4ab09fa9c3f1c9ae14b23209734eabe017edd62209c6efd6362ce47ec44482dbe49fb14a8704b9b732f75e86b6d21ec17e18729cdd2e7a67ba1dc146cccf412a9fa021ec4694cb03db3082cbb9357e54ef4bdb16c1a7e8bb2966f2b073d58ae0529969f568bd552611ec8464493a36bd8f5310c146aa37dd1c07a631b287e0aeec33846e0825a64f885721d89a541ea79a7d9021041fc79acf23c7ab299641f061ff5175fcf45d1541709f226f8e730776b90e049b5e242b8ab9f77800c28b1eff7ba8903bceffc0ea76da6f0f2f62877e60cd7255faf4d79a26da073e8a389aee23ca07c632794e31276b857e0f4cd77a1c5c4b3db09731628c7439b47f79e0d424ef8744120fe46fbefe0e7cea28e8e6702547530f3b70ebe1244bbf60d3c1a30e4c59e705f12cd281f1524ff9d133376a9c03e71de640cbbb445244b453485aaf9b348d033b113dbbc34ba96c85036f9562471dfb062e749821ba7854896ee062ce1135d7f48510b6810f2c6c22a2a71c438e0dfcf988f649c8ad8135ddd448193570a6db21b35a2cc24f0363532639da4c13394703ab99d3e4ffe50c7cb486142d5accc05df6b1fc8fcf2b65cbc07ecedb710739b41e910c5ca6945bc8098d971b03bf9252c8f6415f6a4f0cfcdf5977af785c71b230f0d92dc5ac223130f071d420751e4fa5b37c810b413fdac3d60b7cc6cca9c374163c8e76818ff2a6a5df8f3a8a8e0b4c87529ee3fa6d0b59effd65ebd8a6ed43165ae052a5fedbe4120d992c302107962262d6ebcb63814bf13abb459fdecd15184d592dfee6a59da4151889e943ad60f5517b5015f8968ec96d3799b9870adc6578dc2b8931477f0adc9dfe6aaccbdf624a81bff4f1a7f40995d19128b0b1a3a421fae4654879220b2870b93ab61452d6b37842b9bb52fe68cb7702d37963ca802c9ac0fa76fa7f4e31223aca043ed2a94e6fcd8a1d57592c815d095539deecc98ea612d8e492dd512445fdaf64649104ce76d52e4eec0f621324b0f93bb847c8e208dc5f55be4c6963842c8cc0df079ec314bf3645acad0a5914814dad51ee5ad61e1137296441042684fc5635d92395854360bb628a9cd683c7e88a10988c979d25a7b3eeffb20802539792393615089c76b9b9bba959fc80fd1ca68ff4e69162c7b3f0011f5d4e6cbd98b42fdd59f4808978c1a7efdd93651546d217db45163c602bcd3a6d6cff20f20641163be0ce52c78ab9b7534ae21647163ae03fafb62e65bde6f08491e4458ccc22074ce69f0ecfe3d8573d471638e07fdf626d86e4a5d11059dc808f7b16d473678a13a92c6c4054b4ffa05248481259d480d33ad7cecf9b43c762b5210b1af016a2071d07dd6731033e3c560bfe6927642103366acce1eaed7928a1958108862c62c0c791985bee847538b1222d64010377daacd202015ec1c7ef1f378b672a893e1908e00a2e7614c7243b8e6c528700ad209a076a79a304600513a1afd3add722301700030156c1c791d346adcd174d827d0201547179fb985ac81f74ba54b89b5a7cd3dfc355543c659ff2f8e7b39c428f5323e8e6ca080f9ac2fac83b996847da4b81c4dfeb0e2d52fcd61d27744671d03595923253145b08939cfc21e9070142f178243629766619014041d6209635887ef009f08973a8f92dfb3a9c009ee036af064d1fe49de04bafe3d4714e1781009ce0573d2f63ca994db0eeae5193c55f139c87a196c2c31c9607954cf0ad1695d42b68ed07135c8885b4a9332774d825f80f4d3c94456d096e3cfac8fe104d21a42bc17ef697d841524ab04943529446ec8bef31093e8e6e24244991041f4b08e581e46f971c4682f1142121da7290e0f5aea3b60949bb9c47b06192c3d3e28ee06388901ed75f62d01bc1c53efdd46d31fde3388ce03a8ace91379245709aff93dfa733d18d5104e7ad5f153dff89e0adae537e88b839fa23822f0d2179ff73dc9bfe0ad87d18b3638bc101ebf1df927f9c2db676033e69645d9e728d48d980094956398888c888718e08901af0ed71d8dd92e6620b2206101a64e5716c9e69191625a1d5313deccae36e4180cc80499f4b721ca88664c1560191019772b6e4a569315cc8c8c01724067c90f437d2f6ff91ad5d1018b0c1637806cb1c09621819f90ac42f4ef96f7eae735dc16d4a6f3ac61614d868c5e9b96e4368c998333092cc062bf86076b92ba5420a9d55e829aec65455f52055b091b276f49f1453f79f0a267ddecd96089a72082a38f33c0d9fca39051ff7b5d84a889c2998643b9e9fd293869c2635818d52f021eb7778e8231ef331ba40076c90828d34c9f996a38de9dd517029512f744ac1df1005d7977ddd1ff6c12d9711630bd3051724e8828b6bc0462898289b7897d5eb3fca4b1043c689c0023640c1c590a31ee975ccf11a01116c7c828df61d42c5ab2bf4054692118162910106601181126c7882c9d17bc4f3e9956fbbd1093e4aee61fbfd6f7082cb083fcfe9b1a224cf26f85ebfff2855721869a309d6735a0d2d95c17dcf04bf6d6621c92d5f678f09d63b2484e46b2fc14d8476983d5c2dc1c6ae8c394f5909fefe2a5fc78e1f2c623092483728416563122b898d48f05148d1723c966024998fd1c5160686b76b6820ba610312b8f108b6628896db6fa37d593547602945f4844a6321193166cc30ee2798a1a131c388806670a1c5db09b0c0a2d409ba58c17fd1245880864617e68b2f9a0487d00074b0d1083eae643ee9283bdad812206c30829fb2f47bafd7d7546e2c828ddf1b35f95fb08c16860b1919204590462298d4396bf2b8330779d31b8860438e5d24f190ad51da3804a2eb3975903bd61c2ed830041da5f56eb2bbacaf22700209244001860b191950da426c1082c996a349fe21e6d0df0c82d194bc7c697cf7c34bdd862098143f3454dade3f991b8160c34ae2f925cf6a4152850d40307ac9a34aabac9bbc0346d2a1a131e30b2e62880001303c86176cbaa0400962c858c005343434344cb923003dd8f80357514435e74c1da60fb561c30f6cafb77e678bc8d63f8ca453c1461fb2db8e4c91c2879154ac88a560830f4ceac89124ff405fa7930058c4c61e38f58faeb4fe96f4b9406ce881dbf8bd1da5102500017bd8c803174347297ee8f883d537026f1919d8c00397a33a24fb24a13a856670617407267f684dbf8bed512723c6162da3bd283b3092d7e369cad9e6d92d62fc151836eac087cad19ee39a426a195fc4882163b7b04107be434b478e6adbc717f35bc478abc2c61cb8ced6105457425e955fcce04204b421073e694fb68f42a4b011073e45a5f562a59aeabc1e62030eac77b01aefa8a284d878036f593f26e96e491e39dcc0a97e5a4d9bd8461b180b6a6945731cdb6003a31a39954f471fb6ea83d85803d359faaa3a871e5954037b2bf55d1ef77f760937d2c07674c83144f3f2b081065e542be4be1472f0c8fc62e30c4cb5875e8b7d8e60c30cdc2531b78b0ab96c7306067d9b06a4c04ca00b0a6868cc681965e0fdd38bbd78a051e22336c8904f7eff30cd0e46d23962630c4ceee817f3aa7d65de328c08ba8b2e810c456c8881296bb728355922453f0c7cac13928859469dfcda1536c0c06e8966ccbdee9672c70a1b5f603d98d64ef6d3f1b47a81b1249dfa2adb326c74818bb8314ae68e5f3a54480c1b5ce0e3dde4c7efd4ebfbd8021f49f5eae724f639da68815fbfb41b3c859fda071936b2c0b6684e08416c3c7f1e0b7cd83aeec9450fc3c61558577fd1f4493bec5f34dfb0025777a9a7c9537288b0031b556033bbc37c1d5a46c60b36a8c05a08b1ddc94f818f42b0c82147bdffcd772105265d787e60daaaf98e023be671981a3fac1834bd0105462f871d78dae6474fe0fbf2e8fe7a188ca4de1c6c3881cb1ee7acfaca8191d404be3b9eb416cb41dd5bc478acc10613b8cd4c192c7ecc3cd571022f96c04b7a45d718d3836cb0a104eecc43750f546b435ebe3022a0dac14612f81cb9474f9a238b1f76c048da220612f8e81fa7183bfb47963730928c8ec055e4f31c2bfbe7a7b8451731340318e8820216803a6c1881cdb4cbea619c72061b4560f5ed5f2d5b4cf6f16b5c8b2d627c31430b0d8d2fcc8c197d28e30b2f0410870d22d4c610f8da2f8fbcdae2a8df10026731599846d9871add185ecc3032b2021b41b00d20f0dbb5298690efc2cc38096cfc806fdd501d45b51b3eb08d1ef0fd1e065df5305275a3801b2f3090010c6cf080d31c6991e57e606307ec454afb30de8729c109669413cc381d3039f4a3686a5357d2c148ca015b1f35a6e6f8fa5b53b888f1050e38a910e36be7899e2b3732086560e30666fecbc6f0628b2fba7ac3065cde5ef39c4306234941b05103c6247d7986fca17b98ad0d6cd0804b131dbafd7e42c81e5e703182193360dfe31cbb674b8191340263bc2094a5810d193071f2887bbeea70425e0f8f3cf2db850d18b039fe4bfd6ffd5141e315bc4e30fb4074a2ccc32968b88273ed8e3efcd257ed38165a606158c00506ba0250d068059723092b984e116f246eada0d05805275a9ff93a97879f3fa85ca1a10a76d27eeab84bea643434283552c176349ebfca3b54f01a31dd3354d0dcf147151aa76062448a6ec922962b33858629d8e8d0157d9b552c2224550a8d52b09f7353edd5be7d55aaa0410a3eceabb6927112068d5130593a0afdc1c3cc9e155170962468e84e87826d5d5f41c1861cc749894c7e82cffb358ff891c4c9be274866d92ab9e77acba14e706d213d457ffa40a5c2000d4e70b7e6414f4c2e6ab1b3096e42ec4b9df36d57520d4d18a7f2a69d0ed7c8441ed579420e8385164a1a98e0325f740f22728d4bf0913eb29af4b91c342c711a95300d4a70a3c1a2eb473c34ed4930923f858ee5a995b205237325c1ee4e7425df5c2e4023124c67d6bde0f1fb5d2630338a14011a90e042878bb507d6713a341ec1abfe4ba88e1dc7070d47f0c9722b25af1ac125df646693c5ef427730828fda3395e7dc3516c1b9a4b68bdbd1b1050d45301d7dfa452d7920f52a163412c17bde143c79fc89ed1a22b88fcf3dfc737308f683eed036ba87189ad7828621b8b158ed13b35d084e35a87f68e9d42004eb6ea6fa91466f4e798d41f0b13f487973491a82e03b538721e528072349045d8c8c2d62bc462018b7bbcd10530523493140072a3400c1afa70e3f8f04a9b8e11f98183ce8eca8530cfb9c1f98ced9e17d347a9192260a8d3ef039b42fb57d6021b80ac0420b2c52a1c1073e8c75da6194eae8b2c3038d3d705e672144bdbcba21898516584c008b0c44008b2668e8811bcd0ee3c721c13b8422e8820b181990612aa00fd0c80353639ebace727a477ed185713c709a3447b5531309b8281a1a8434eec076cc62a17f2f2a40c30e7c94a45e8277e7f4c84d83461d986831666e32cf1ea544830e6c7ecb71f54b688b188f7534e6c087ffc9c30f91aaa22107de63c8f9d284783abb68c481abcaecffa3954d42a40107264344a8dc4b5b12aa12f8060c09d664154612161960c020a8126cf4bdb5865676db4705a204f7217f98cb352f3387c3487aa3059a047b75925325b7c8b106072409f6aa6af3e5b7782221e76246978a0413b37d64676223081276e5bafa047a04db9f73cc1cb2b3725439c8116c889683643a21c4185ac3f0620b3a1ac185d0932ea9dc27530c122398e415762be9032d826fbdeb8fe95fb254ae0826c5bbaefdcd6c1828115ca4a4aa9fd2e6204508768110c185a60a39ba2479274e0ec1daa4785b52d519e961000a6408ce7b729c3ca72e8186c6175d981210d24230f16a34b7ba49081a4308de2f43c5f0ca6fab318106c15bece8125abb20f8f036bd05cd716416b740705f1ff880e053a5b479b40dfd81cb51a7ee5845223ff0d9eda3607dc93b2f657ea03e709239d99f239b0f4c5d4cb17e4b5afae3a03db01772b2f58f1ca407ae72182edab107e581cda17b300f2285d402080f6cee9876561e861c7e312bd01db8ca5b49b73e7790a3253bf029c68c2b96592dd581d1aeb28a5739dacbb61733b6aeb8203af01fed25b47b8ce6c06777e4f074729c8cbdd101480ea76039b6e514d59213e3f5021407d65306530d562e412b2203101cb86f0dfe1766bf81e91ced9dc8b46d1b9303b9810f1a1e8767394a09b8c800a281dac07de4da3142f0fff8fe19880dbc4884ecc177fa3fce5903efe6e52979583de5ab813fcd2d5e177214d5e3d3c07e89dda4e6942c391af8149196733b3d036fa5ab1fa9c6cdc0b47510b5b1d6831ccb32f0a271cdc6373742f420031753de38064e6fdbb5dc72ca8f1103a31bc93c92328d395461e043b87706d3af541e0303e337f1356bb06a0dd12fb06e1e6e46e51615cf626980bcc074ea252f0fd9247fb60b7cce22116d4d4223ab051c077ce12de30b15307181affc93317424a212fb2ad01698489f6b3d8ac8a142ad054e22e6f4e039d87fa859e0a7fcfb5643720b9fec17080b9c89667eaacc0f335957e0cfb4828690e3c72d215e202b3051272572471d35e7982af049bba773da1646125181cbde6ead8af9030a0b05b5059a02921498fab795b6caaa19341405367e8eac82d87dfa8d5619080a7cd414636e36c9a178f813168f71dc63eedc09dce6ce95721cd216b3a509ac0756bb1dc5e49e9d66026fa11ea1a72d2fba5c02af2e759bc3e2a8888712b8acd192a54bfb417d30097cec2ab669dbf2a78b04ae23e5cfc89bd53e6947e0525aba8cc00689a9515a5d3af668085404d6a3dcf73ac4cc39bd0cf385037c4044e072730739c412dda0608b2fb82809041a021b56b7f93b640fe347086cfcfad461c8b105cf05814f73cdd9de464b420c084cc89105bf8cff807f29ed8e7208d29d2c27900ff87409e96f17af3fd41ef0a92dd94fc3ab343d78c0e4b11ce610a364c60a0c0476c0c792f387398ef17733ae03de827ac7ec38ce1cb39203ae925d264fd36d173f1cf0d17244b3c73b594d764037e0f2fdc4f420741bb0796e69a123bd065c879419c13a9418834a03366a8e83befcb1860e429a01933bf6a88398b70cb8b0c9ea75d2bd69121728068c5f8ca9a3068b60c04a6df8c7397ccf71947b055f9635788e95524a7063405cc1fe7938213fe87a5dddc8c84002b8405ac17ee84a3a799233b82801ea80b082cbd2db6dd7b166f1cf2a989c2ab7f3a474dc9d57051fc46334a95495c8a4e2a83aeeb8e1b7a382dbe89837a7e3b8ae7e0a264ea5d8595542cab74d71f428c64f9363e6a458a5d8df6a2ca60c0984142403328a14053b62ee5639aba1e0fa92e5a0627c0b21a8a0c04a2bd7231b8fbe136d817c82eb94932677f38f90739e6082bdbe670e2b27dbad137cd6e6987a226a24ad38c1a5a9f6ffbca14db02946f1a0593139209a609358cee9e328472f9a93094ea53dbb4287470b3d269814db2ee468f51492e5126cf20fd2c7faee761e4bf0e1992da587a13287e94ab01235c3f52c071d7728c1c5d7ab099d4e02c97b1f8bebb892e03f6709e9307987461b093e489734b84814127c9ea85c5fc9adf77d04dbc1a33a67241dc17e9aac93af2467df4723f8d05b438accf04df160045d7b9a3d658b242ff0880359046b39c7328f2afc3f3a456c193950130f42f542b25d748a0824117c99e5eeefa86fba1722f88f3eced1a3b01c82bbfedc5dff5183e98660cc72d0da91466a400ac158471d897bab79b81e42f015e92445c871f4d39d4130de933427858e20b809d2765eff397a318160bc2ff4ff23ad50391e10bc76aca123ddfa07a6a53692546b5e44eb07263a8f78fccf999acf3e309ed9396d47aa18c4e4039b37e53aa6e71ef83843578cb13a3bca0f3d301eeba6ea0b1d218f471ed849269a25d4e5403ac403f781a5fc81475f9b72eec04e6ad4e02731a5aed881d1e4f133796a75e03b7a6cef2a9bb887d1a1adcab55f97b239701e927b11c39388587260d7e2fe44d0a4515ac5819b4a697375648eec8703d3e935dab93624fbdfc0a6bb1b49aef71915377096e6faa1a36e8eb00dec65ad5d30fb78c5233630fea1c774712f3bea680dac4844889ac34c1b2f6ae0554f72693a0d7c1029f1930e926934f0b17f7965ab8eea2242c5017206beac2b34eaa57c621f33b0121e976fbca9bc8d2903179a6df3c67ffba41b32f015bce2a4a4f2d8ca31b0aef7c1f72c96e4efc5c077f4d921e5ab680ef930b09725dd67c941ce610e18d81c126a1525f4c4f205be25236fb0885ebf8b171849fa696b24ba3357bac088e85b9547e5d3172eb09d5f42ccb14ee4b4f616981c62de1d0b397248b616d8c98db9fd773d472959e0bffa72faa7edf68ec502933bf2cde3df16438ebd029f636c6d8b1ebd3b45adc0c4c89e9022744871d32ab0b9d62cc7202515989ceb63c77cb5be2da7c0e7649a28214b29b0135288f49fe6fec8230a5c656e59bda79f7e0714d8ddf0e491997da80f9fc06ece3b81b7adb5e4bf9a3eca36812fcfc9a388fc69553d26b0266da9b652fc8fc55b02d3aa91d1b6b3d332a6042e48ca1e25f645f0cc92c087e3351d7aa890c08e4fe445e53c393a7504ce34b354f6d83202a31e58b97b300bf5a822b07ebd390c75eaafc1220297a472c6b897a287590d81adee5bcb9da5d73f0981730b8fd4427db25928088c7e106d2b59fee86204043e4e1aed393c2e55fd077ca6b10f35afae07711f30b9625afd383d6072fe9843ce69924fcb033ecc3de9a963cd79e70ed8dc716488e0b16f3a74c07db4dc71d23f55793960da0607b64347a6799fd717ec0d5ca5ff2c792cd8a769e6067e2f072155f5a598279583b581b5bb6c9303b3c869b6b1810f7e53133c5ef6a8ec05d6c07a4e79299ac5ba4d7dcbe80aa881bdbd0a71cbbcd353c6d2c0e49c223937672f4fd5d0c0a598b356b2beec0c7c87f6b1e3bf471d3f970033031bf3669a1ce68c905919d81c76f83132701ee24f6d5fec487fc2011b031f420af983fcf3906b17836252e90b037ffb418cf5b137c7d08161898ec3ae96d8914a8479b7bde7d0edfa025b9f3be5fc0d9a17d8b8db39af8354b7a176812dc979a382778e23ebb9c09e6b8e830a8fb242dab7c08aaef956eeb5a7e85ae02a8b5ffc30ef9ae64b1658899f7ba3c79f1823050bfc068f2f5aa8abd6745f818b8ec2229d8715f820dad2255e8c91c4a30adcc76158b6caa151819da01d2af2274deb9f4d814b165cc5f753f6d4a40093029ba274e728d6e4ef2c11c1a2c0586a53c99f1f94752814f8e0977773ca1e95c6d69ec06659d84ebc8934c1e2043ec8f464c9bb530e6d6b0237c163ce0bdd3381cd219dc51cfaa310f55802aff539d0948e94709c6e1eb8b6c761b6aaa7b687b4392f2b596e49602c7c2cf6a651bd5aaf6048e03ed774e4df7158d6e4da11d88a1d37c724ba29416246607220ea21fa9ddb33e5820b9fd15bc4f8a288ad08aca587794fdad3c7d685c188c0c7904aa3ff524ef13a8d86c08418cf624e71eb367721f096f91bb2050b029bba2985e5282d32994060e2a9ea4dc574efb0c37ec0c41cfde65297b0201df3017fe741e6ba18faa32911c1603d60739c25e4cfb7798387f180eb6439f2b55def38d11ad80eb8eb69e98fba9ce9804f59fd63771ded1c8e96838389e520451cecd7c943f4ec0dc89ce3b4cb91794808cc0649cc9167e7f0bc950f580d923a499390d180148b6ce95a216d1ea61d48bcb475761de26fc666c064aacef1338b5b45330726032e7fc7fcfeb8bfd67532580cd8fce19feb8726e56f210603ce83b879b173cc4835d42b78c9da19252f347baca4a15cc19b65dab1542e7aa7562bd8c9da71dc6aabf2f68a156cecb842d417d70b2ffabe50abe03d332333cb5f2f942af8514ff9514bb22a15acfdefa60e721433df4705531562c4b4ea9d72903c05bbf79a63a48ba66033a3693291d49d1fa44ac176e569d9644b396287144c7ec5b5d3eab6942ea360ad2648485fab28b820e26a7e7b71a042c1dfa44eb12daee8550e144c48e93fa305c9270889e9418e52cb924ccd16735ad66ad7137c94e891abdf5483ea04af5162dc4f95e6445e9deb2e44886d826bed382457ee9ee690d2043b31e40e428e9d4cf0df313305c9794cb011ed3b7d56e219f14bf0e18636dd8e2b5156b104a341f3a4abd7a7d46825d8942ce657d987f92b4a7076ed418aaaddac21a7a58f82052fc98824b80a31dc3222ad365b1509d672189da34f6dd341c78d0a1812fc4753176e1a4f53c247f0215aa76095d287acb412ca11ec4796f6524a5289508de07245cbcbd17a18c15b9288d28cf2e4a1bd50a845301de88be998ba7b7b10a008de62da5823798301265422f8fb4d6d1b4c63f2c85a150a11bc7d65e6d68b9f9b3653a843f06186851ceb86e063f4e8641dd5b35db9842a04b711f726ca2b6aaa1c02b408c14dfeb753cf4a6a1fba46a84130adc9235279a0174345105c48880e3faa0f2a76f431840a04973a6ed671be0aad1023238616422840f0fb6184accbfcd184fa03133b6f75ea4829b11541175c7421022e662061e00b6f2f4a10438be302e507aef7b6849134a31e507de03fe67a8c929572947580e2039736453f77f6e64c933d3031c5cdca8f2b3df01f4a76e532b1913611055579e0c2ca7a2ae55af9a7ef048507c6d5e385d0c922e409cda83b70531d87ea1511428d47d981bd4e698face3a896993a30e225da1b6a752ca7d081f1f03c5448e6e8ddef39f01322ddb56e85b9bb72e0fb27783a49691cf8bb24314a6a120ebc6fd20e6348d91b188f7eef501a5ab3a3dcc04f587ae574543127d5063e568485b0c9d2dc101bd8095937eb725a0317377f6cb1c2ed63aa06b6eec3fda41e5140a581f11cfb77544e9e9a0f834203f7a75521647eca95fa0ca4680df138f2f4282a06dfcfedffc9393330d522551f5e249d94920d55063eebdf674e9af227cd2d188a0cace6797abe5bacd059d518d82c2152a24555db5062602c3f88cc6d37b679f9360d20541506de2ee4cb61473e59db0203dbaf2a39fbdaf5055e720e4c63d4aabcc06a6ad4ec944aed3d2709d505363f0e9359b63c8c242e70bb9373ce1eba72ca879194b9053e9ee6b1cc315ad9335280a487d2021f7ac77bbfdca134ef2cf016573a77c7103554120b5cfec0cd74732821abe40aac787e475449b963cfb1023f1e27b65bfa9c737daac0874c3142b742052ef57853e03be838ceee289202372a2a11ea3a6349260aec5bd4f18b1c50e0d6b3c34deb717a079fc095c7af129af73fcc9cc0648bd1722cbf31957413f870a5e28771254877cb04ceed235967bd943dca1278cdb5b1e3f84395c04fca1572591493c07eb0315f0b93c89203097cf4b1f27d7497e33875476072afeebf685999a78cc0e43046f309a12a027ff13f56b43411813b314f579ac78d410d010f72acba3e42a83c0e839084ec1b53ee5d0723e90433b6b02b1410f81a9f56c93942b444eb076c44f2acedee0fb5bfb7987122e8e28bc6005941f9808f73aa8a1f73f4caabea81f93bbdf54716e701272ed2ab1ded0ef8b83a74b490a00eb89decb01c709b135df92f5bff3738607af2fb454f6c3cfc1bf0a12db6e40eda80b5d35d8fea9e9bbb5203c637b333feda6e7e2c0db8dc0dd123de6f6466c0c4a90e22cc3c6bc8910117b77348ffd1c52f47c6809198c226060b96275a30606a3bbca81b8f5770992a738578314db6cf154ce5edb8f3a51b9b94b4828befa669f2f346318d15844a40ab2055f0bf21e27d5c16a2a40211c042c6175e3880527118205454a1531899828f5e42f03e099ab9a314dca5be3deff28c2958a4e0442c04fb48fba21a8c028d828f6e9ed365845c59d287a440a2606bbdbfeed7fa0385824ffd29e8c79d452b3c8e0f040a3e3bf26065962aa4f43f419e6042d4d66ecf39ecc5dd037582eb919cd27bfb69cc4138c176e7d4c72aa14db0b1d3efdb875c2a129126584b1b528ad95fa44cb03f962247ff1f3d5b5a036182af5429657fbebda04bb0ef933b92c3bce3e593257893ce928bd0a8a45085f27824100904e2601c46414c721f73130800182c288d46428168248e747d1e140004522c1a3c342a1a1e2616101812140f44016128140c8602c13020140c0343c1b0404020eaa07cf2cdb1e36203f813c3de3996eb261d7ba03988f65daba5415ac7309a1cbbb53e1ccf24af984892e28bd2bd81a83c43302efb50865e1eb751907b48fba9e3ccbf0c1fec0cedd9d0ea3054529cf2272947349fa71ecfa108761e8529f6ebf5913097f7f1b444a1d8ac5847961408c3650bcc215cf4de721271cbdbe93a5bc45fc6bcc99b9bbb01e190ac368f6e7f6cab7143178dcf8da5346537719bb90264e98677dbcc8989fab2b497185428977fdcbcc88d178cc54921f2ce43419817aec350de4b6d6b639e4f49a4de4ac901bc4b67b62223cfc758a4aa373646cccd3f60a310dd8d5b141b73910921c45a8ace8f152ff4e396a3469228f46dc289b8dc1559aa9a29a413b4a394d50e98599d3e67d91039a5b80baddcf86c19a1825be8b4b2a4341b18859a913bee7a0bc82435eb4719a1710873a86ce199adc9792669ad9c035d5cc9019c0eb73eb95850d899e4d7123e81aadb6e9967016a91fbaa14e677602a06f05ee5e7dd75be5ab12b6a1b9fd76ce6184d4dc6acb1503b41754d661ad73b9af2965b00efc9d71f4a1913b3f065d9bdc77cd6c651dc5b3a146288d0698f8c7748ec4eaf68e7c0af30f71a97f02903231d93170b9f212f2477f87c9f017fce5e2293d1e264062e1b5664a62d63dcdb42d97eda47d44fe32ae8408130c866779cd82a46e32b1420722f62234775666d2ed0647e405614db73d0541f0a5f4c273f71f34407eb0e4046570629aa912ce4321f29a10b6121a86790d1215b4cd538542fb3255a76e4ab35f5273f052e1383222464eb435e407d0f88e90988a2ac0a65cec823f398592cdaddb2055ef7c21268fdcdef345257f112977fa513314faac5dd27636fda71a142d9e9409e54b04ea3c9a6b3231d8ad7a4a9c6ed3f1e672cc05422274df5e1fbd5da0e5c16978bdf5ab0715b11b58d2a3d41d20d3f3ac3b9d191ce62889065d22ce1ba3ce8e63af6a3be36d5ac6702c84b675f4ba56a77690fef264cb038cb9374d92908b0d5a1305048c5a28fc0689b744af10385dded6cefdef0c17455f5a45b351fe6a2df7ecfcdc0f831079e40e9433b69e7661a23dbd0fca9df94caa9a4b72f2d63ed343ad702ae261f6b2a10c69e322961f487fbf815553cc289ea51d441b67571a9b87201d869e7a823d8acdea099a00aafd8b40d925604c99794576d5e1e7483ea7dd07f93114ee0beb189164433d3930151b82fc9dd428397816d6c8fa39262399e2457b5cbd98b1bcb6ecfacc3423695d5cbc7570ad4a4b933967f8421cd53328d1ff908420e3c32dca474a8b432b6ad59d8e4d0600ad5e009e1d080c2c6cc5c5e399f3789f26df418c0c3263cd5bcf1f7acfe8d08a2f00e9ea5a35212f38227d1cea24f511f14a0440a0356ced3b2ea2c09ad4084c0e70d55ec642ba70edc676af39deb1f7868891de5c68d1e55f79d84b0fc1413cab8581a8f13ef8f16476d4145ef5636e31aea6cec40434b9bb331ed941bf04dcec8613868eac753c316b0db302918665808e6e1959533dc9e0a51fa0a6456a58a4a4fc5c6e70c9cd7e345eb819e113068e8d97d04a71c21d7e1d6eca26ea7de34e4672e929007b80ec184ac447668a4236c94afd068a6690ca66eceba90e62519af45bb513a4bd7f1c8e0632c8063c0f9138d8d111acc94e2bd4c06db4dcafbd844480c1f89e18b2bb70b8f1178f870b82a1099f0a3fa3b082e80af977b4c914d0d511e99442c3dcb14fb30f64d9119d852f8e8a9923834663082864ff4bfd8a38063d9dd2cd06cad1a050d7432d8b1558343059d99014d66e40b4795d54fabd8faafe7fd138ae98ff1b62bad29de7f5e2cb0dbae3ec5559e1b470cd5312ea59dcc331af14815127a397eb5641e36f4d38e441151ca2b458fb657e16629d0f4663eada38fffd37d144049d8f417a1bd157139c9c5b1aaf03f53a899575f029218e3b696911e0697ee9a58c335089e3e6a923f2a26a8805cf6daf014ea2672a234aa8b325855aa1ef4e274637ad7483643efbbe2dac0fdc1d02390e62a1acc238e83da6589b02fb1a0d3487563314970c1776efa4b271192fca7ce2e8791024673db82223765a51313f0a918f91a51a77706704b51931006d140fdc744c3262b00c1209eaafca20851b54778daee61cc88461ee872963cba644c537304502f80bc8c301a60a7af9a331c3c63765864ae0824740bade94452d706fe60bc3ead9bf595617812fd99b66f570ec37f62b8cd6885ee70e6cd09a42d54bda930ff9f765a0fb5398baf1aa92b00f63fd011c3b1374d618e64bfbf297692fcc29325ada3215968bea2ff591aa1d347afacc6da39238a15897490371125e40051ea7c524718062f0f02abb97a24fb923c818b1cdd865f22b2ea0b4fa36d1a823722b2f722e0acaad0e03236048216526a777e6c994db330e4610e8613a9b1c2e35e22f9414e0a536c44c860f03df8999021aa5ea8374c7c198392074a085e1dc9b55e1174ef144d8e06225c14dda309db2014591291cdc2240f06854ca5c955651d2c42f0392705d2d45d989f966d2583053c420658ce4a77cd320fb83f2d421664763968af5f36adfd0e05c54b8b15a80d3b072dc368b1105dbb8119d7a880813caa8930416a4f85db91bd927a9a31e6ce8d74f88bf4496cee8fcf351d066395b0464403cfd394274e3b192f08f781b89647b40b8303bdcc0122c7caf2423f32873e7d0fed35ba36939cb903a6d47795a88836104735f2d42b26c50a71e1baf2886ba2b388b8e1618058cbf64630de7d9fb910676afc24dd5ff3728422b1d96a44ce935569431b2ef5f0d674314cbcd9961d998ff6f697d7aa959cd02406012866b63a81ef468a420a050d13b21e2b98935db6697f1592ed3f511668eaf98abd09fa16471392c29f85a823a7743a7be343c1b6d0630c0ca730a99b54221df5fc758aca2979454a75846b20e9c6aee9cdd53a68c3381718a7e47488964125c87727c907dd1fc2a4ce5f20ef2af931f1d15a002461a3de26c92dcb3dc26e3971b4cdead392378be78b4498c941d864cfcff481e7c7d5f491093d9092cb0b00eef777070c1d3927a738c17a280af858ad63a8827fc7a7fd4b7a3e5a2a0dfcc4e8fbc7a57d8ca433d4f7305791205d13572177b01e3c1e738ab25d30ec1140db57c3a1e49a06d7718a5b193402feb69b5dda5159d22c2012e3a10f21d39ce6000acc3b7ddbad10779b32338f92789c790c868b03429ed1bf8fa14cb1f5f62d6296b5013d4b6d9f96118ee4a9afc2295a8980385ce5fbfe72541e06e3de475025dfc73b3cd11281ab2bb237cbde884b76f84183d823c927920238724d8d048803adb332eb8ce4a3f6404ac1c52fc1bbfcb933bfc31c0bb3cf81fc30079873a3475bf518de50411633ff94675c93d794ecd4289846f96f5fb7422c8dee710834b65f89f45a6895a565b8358244dabacfad2019d90f3e4a237d63e1bfc21ec358e11c1345c744913dde614a4e052d3316727ccbdba821a4ce84dd1f1981eacb1444fd8d6692ac3e2e5602ab6e50b081432f30ac86dac657e6b98da6e4002e830db0e111cfc7b9f22a04cfc19b70012928d186c517bf5f355d21ccd28872fa6ab05a204fb74b8f967a962f464deb2609b1b6e0c651e822c7cf9d0f91815a2a03f07a6f425e36e72a5a8585955685a26bba577e4c2fac1d38a0d6223cdcc5a17126f92679e7a47d6797c44b8a9c99531abd5561cc947c0db1b8141c0b89ca5d22a1acfc442cbd2c3d2363ed1d703f443281c96c96dbc0e8628f2b489adda89a3609d401161472a94c1810cfe82634723cb744a063ce9c0b66c9a0d7ef4e26dcae0a8e9aefff143db0e149b5dfdb6b248603e6ae0aee57e47720a77a3f28de98ed19992a28faeacc5919c3edba34a2f0b58202d2e6986c0c8d567b4149d61d2ef5cfb68e213c5d306f6fb4619cf87d5f99ace70fd28026c52c79fa8d6148c8eaa8314ad9ae46ec6611cc40ac6ec3023fddc932c3d387c191f7eaec2a61174bca56083d980191f4bdde1edb86ddc4891c2c2154632e1862df5a4b3f19629dd5344b0d2e0b14a6ca106473870d87017e5c21e791cef5bb82b101669e2b3c0a92440c41701ee378c2ede02b5dc120c799c6b35612a174379538bc7513953933ed7baacf77db4c88b0ced3c9c6cb06e6dd8c811f2310f08d761bdedc1acecc4c1b1c4056830a24337dd9b46dfc89c51e52c8c69cbf26efd2a000486bb4a40e9fb40ccdbae4ce94e168aab512a0f578ff421ad60a08e2ca775fe598f582d4e727a1cf6233a5bb8b20ffecf601220f7e3cb6a394a0b526e0202a44eecf8c31c7ead4e0ebe7ba719b21716fe0b20755f3706df507ec8360baaaa1459f55d34c87a60f0b2cf08bb3f906e9dbc393c1966d33873aff1a74c521d77513fcdfd1518dd31097dd25e00ce21b83dba07b48d2edcfd8c3d38f4979b61a68e89936527088d10cb4a7970450d9f80009729cd0434f56b08b47ddeb128c4068025704fb0978127063411483df10682060ae27da27bf4e4ea0017de723506a4152ebdabfb8af13853725dbacc062e84b137f707aba58f24e1c62fd9de9f4ae4ab81654f82121d5f1c581f96d943c39ac13ce513ab81b5a69bc6015a0a0acdd109de4651d45b220130fbd93253bf3ff90c52bdbba1853ee4569906916a325bbdfaa90a43a527cea257a187e7ca7565eb1601bf79a41251882377c8956e653048a0580352fd9bcc553da0ffe070d854771d306c81854e6e4736240724a6c7e3e82b14f1b9cfd87ccb4965f3ff8eb4bc0e8a3bf1d829087360343167cd9946391d02e8baec3f4adb718754a4155c520360fcca4f9db1c5a38393144cce0d8cefdb3ca1823fce4311433a48d849a533fc11d6dc1bd0d93ed1445cef95b1fa390f1f4c50da9f909499483e61ef0932ae1abd4966cf805597fb284ab487791528e0f41f0655f8519df190c4db9b56326ac62feeed85764400b0f40332be62e3499cfb60b33ead6f06a929b4362d8e7e32ca48cd75d860d6b6d9dabba9121f45808034cb8a02f0b767ceced61d4d5fe69199d78c9c1130f676f3044e95b0238511832996e2a32ca75a0a4d4827a8a1e44ca8cca42693c54194a593a2b865c2bbe59448369e82893569023bd89e44f15ef9531a1e5ac841e65d04f545bc114a7a84a031bc2e79edaa029865a3c797a778f79b5d13fcb93dd761624b39cbd684e2186b37684b4eb59baff1536c60e25258194aafe28bfe48d80063b156d2420593674d0343507598ef19c47584d2b68a5f07594f4105e19543d1e8c8e7289115acbc30279974b7d1785dec06ea33bcfc1cadd9c26afe23d670ec7a21bacde8ae0d9036bb896dd782efbde10c61729dc791de48586eed16e33755409e419b70b37a2b76691f1911d47be20f91d8bde308b3b62cf7a5089a01fca6ffa8f222c24bb2800cd9dc81095498c22f62ef6ec1dd22ee5f6f786b19fb877b567efd0bb14db8d9bc40eb19b608b0ad56c4b9549c8ea553fcb60a7223df41bcd38455fd5ed454af26d103526f0d4337488ba283dba862b0415ede40db42c29658ee73d0a5509536217518d604590a3072b6d3addd6f6f89345172098547b64e141d231a663837dab537b4f8a6d0184491e8f7b3e8a74e7da549a63f7a0f0e0253245e355ef891fa7d9212302d41bf8c75a8011eceb5a827e53c0ff6b782134c5d47d3f35c7d4b6a778aae084cca96732b5fadd5b3408801de52cf02a0057c5619ab06111df936484afbd192a537f4d03d87f0f03a83dba5cf490460da26d88b3b9fcde68da611f5f8deeddca0870bf0fbc73b884849c29f86514bab08064ed54f24df57c43289d4dd9101ba72a47aba7a3fbab705023e857bc6a445567d2de401e56e880d2e33171c0be7b55a12b6773d86394873dbd32850c584ccbcfb4309d247f50e400849306150b4dc58336c436c98d2b07f8bf78df1996998015fa3181ba6c40c38ad9f61ab4c08eec5a0e210090f9a23259a4cea55ef4c397b6679cb689b73ba8040690b473f2461bc218d582afa6b8b884d0783c0970bf524b4767e09e240ea49f3124aa82bfe232ad98cb655dc201346165344e27f12e5cf60cbc856913213bd44e51a3e950e6b5daec25edfcf42ce8de22a18754fec05efcee94f026bb8bf8b9fbe2911e568586d73d6fba54dc2ee490f60c0dd466785ac31a947c86d21552e96a496eb8a21eea37780a0f3da57230e5505d7639db0065a33c811b33ba3cf55fe3346d7dd240b3669a3dd92076c180926dd860689ebc87cee31021746fa2e2beafa94d2dd9a0197da10e4ddd6f39945ca4ec6c579166b67cc97c90a37dc2a5027bf477f061851a9832b9e1782253f213e14da4a8b2d19eb564374ecce2983af85bc1f17a9c58f05ec7c6de59c8ff5d1aef7ec120b1400d13b66b71082e138e2a13b311cf49161758515a6c5c5ad085a1b2509f92288134edabdb01758368847f33c97cda82b0dbbabe691569d1386b13fc95a95517a3d33d482914e1a87e8e971fb3ed20090951e97bb02f25114d2747c33a4b5e33af88995e7d458d8d66259ad8e4697b098679cc368eec48bee8e08838ab342edf69a15791c115a140060c673d4df3dda44c59f905b83b46b72d7b6845f37f82fc52e921a21abae8875f824142f455e21d3693636964c2b6451b620c43e47fc11451b4772159786a9c4109d39059f35e2d3974b5a7602e1fd25bf33090b928104e5307b5786d3ab73f3dd4a3efb377bc64898062ad8f15c4c31a3f30a374e5ba8911bd8a0ce429e4ca73aeb9876cc366292f74035189d8982c920a04e415975e8f6365f5196204d1096ed8355e0a3f4bec795e961a5429ed47beb70f6327fbd5be641f8e162f87c31e3a29ebaf1098243786e5940ce2776cb83006911aae69fe807bdfcac108f6dd0e4bccd37b95d614ab8740694c0968d0ad9a3c6917c2a26b6ab58d0e271cb04c23adae4bb58745057620c9fbd8f69cbe997397f9607241f2cfe3eef7902690c6fa77e1efa2c5d1d00fcde4f5a6fa57bac54a2b6d9054081e48763a84a14132531ee747949f95568d304ab5d234b0d1351849506d5c445ae589384d2a832437e11d7b129154578117339edebf9c8b0abd1b999d5bfcb742265683b4b9cde02bcb82c2d9560d6792d99d5bcf1a1c24d9f2f2a524631b02a8e23ec2d570b2031d5c3f5e2b6813cf0e2610b0cb67d17954f5845730cbdbc2aacc933a430854c5ee4d04a259ea36983d3c8c531c8049f3107040969c3f99db999082db86b7e45f5ceba337393569b6de994bd1128ef3d3d3589c2c15bbba7e2602d5057d9e70075438dacfd203b3ecf235a8518416eedb7946cd3f2c1773f4792264e7fab9139e9f5b7b609b68d53b6b637831506beb659824140154eece0efd13fa02f790a19f4b2fa65612859d3c213d50e2e8eb2db839811e20d9dcd1e5ce2489c7177f265943d2c15d3987542424e1da8a45606a86ecc0441670011712630fdc3fa7cca2a951cc6819da05916236c78c5772c29539c2010865a7468eb63bdba52904c065c0edd9adefaf65f15e755ffeae3a12e706d42d0e371874c1fef8d21942e7a0d37ed8553976821b6668fa5b4136caf77036f30856b9615b7571677d8dcf1ac3008a605d5b4e8cd0f9153400c3e31551ba0414a7d49d0997bdb9df4413ca586a89b673a6327f55cc6b5848289b7297d21aed8849564e8ff8544992779541b89599fc287fffec52364f0dd8f927693d0748b25a74a0c034410038977008e8401cd369967755a747713ea8ba26368cd8e223602378755757ec3bb1b9f56a933edd130c73f4f11dee373ae82409c1cef937c1cd080e1c326e4c4838a0ce49bcc71c879098e90d2e95ac39be8129ddbc0ac0f1aa31822dd8bdcc8632cc9d9943b2d8e8624c4008ffe565d0d584e378e637602ec268cadc8d6408515ad15240cec75e253ff53c8e7a5c70e092b0113d788628d66d0136fb430470c943835e061b4e865c1677d9e1ad2be0ac7354487e2e7eec5070e3778988315ca02590762c814db2b273742a84638a73f0459fe24ab289321a05c93eac64d65ff3536cbff66899ec43a81e080c0acbbc114d7414953db6083c1b0b006fca3453c03d03b89a0af33f0fc28436b3b4e33977e23fbf3322c6a939bce512e555e4821ef61aaa946bb33cd1a746e64ce9b910e594bb0b578e0571d5c63db0e8503e5efffe102221bc219cfc4be2f25411d3ecbcaeccf8c34a0c97111d89ca1c2c2b865aa18e71ea04957f7caed9fc4a92c9324568bc27707444153fba68bfe981d4311be0254185ffade440d93dcb2a50168859bc3365258fb31e275f8ff99257d5e903a822b12c963ab6b2148232fafff35ac7e3acff2192e95d8aa4c144c606f2862884f7fc6123a2b997794df98f1608335a5cf635e9a669b6aab023242e5f432b709822b542e6028347de19383f6b1098dd6a0071005715886abe00bf319abfc79b87e4474c69c35041d58815105e477483aae9a49d37714a8fdf81e2d463e0419a9df50211a7499126bad287c23e80c4003f120ac41d8f21ac17dd94990234de1e43ad28899a8837da3638eb1c937b0e35cd618c2808ff702d2319879ad980dbfdf110e4df37ceb257b99a769b5e5629ac52347ac0632353d25adcd0ead6fe9077a390af20a5e451b1f4916a0f51e328f8573ca98b63c86d9cd88141f8efacc78dc4c77e5aecf799f8e39c3e41e0489be672a7d5ae585ed0148759c89b8cec9c222910a1c44a0dea3dd0495fc7cf765b9c28d102d0719dafb6079ba36d1867882b8c899c6749e0afc9542f4d4656fab531974c7867bad5d6adfa250ecd4d826a0058c73e1276f6ff023c094ea2e1e47f0cbcc54e81a2f304d75bde5d2d5fefaa928a06faa114cdb7253307c503c50cde8bbf9eed8141d1058c0a936bfa2171d149eaab0fbca2f371c9a0d241b928d541a684baf8c3e2d4a942bb5c2f3fa5ac620e9725088130c7ac4315a05ea82c36aac1f64d65112427b5b8a21fb233d12aaf82d4459288c354601d5fdf38ec72c3d602736e0235a273da40c67aa371e3411c388bd6714fd18c3b97066b851fcf90b566b64f1ca976b725b903f0ef0063127f281f24f07050703d682d901474b5411e8564953c4082507d427ddf2df8e3d2bcf8c552a383c22e4061f083a5a983bf9fa1ee8a777d6579f4659b17762c2844ad140528ba27a737bf393c1a755c931c111ab34384943dbec967a282a19fb5e3f4f5cd5454e4db7cee10d9a491952a18f3a4c3cafaead3d52449ebb34039b45a0f04ff76ae4e0295b31e01da7ba4e1a748bce51618c3e349f4e96d64a641910bf845955f92d231d331cf229d7c0a84a05f12346ee5966c85aec3bbbce73888d145e65e4c7a5756a34ecbac3972de26fa4254b0f9d08e2850337a3cb5e77c1fb5c6728005cc87653462a5996ed93d6462f84d36315579d98d1bbafae3c09af6b2b8805891e3c832eb964188734610eb59ceec1266efab71623954c294e569d358d7d91e587611e4ffe7cb7d948521eedf7113b361f3283c75cfcfdc1dd2194c322a5c213c816cba08d5657c6992ffa6faeacecf0d7ecb437104fd08b655305c0d5a17c69870de6d2b1c526f05583e4d01580e176abc43fbe453c454c511310605d42670dd439180210130c6077f8e0ccf3251fc82ba3418222362360b7fd7049e09683dba978f45dce7844a885d555e46494b989639eec82ac2951cc165d55411ed37c78178233397ba3649f175e955e6c3315add70708445e430adde5cd5fb1acbdd12dc73e5e1f8f628361f749ac2bc729e9a26c229720e3dd927554613d48c5c7b0d7a83f9d6013c77cc799f145f1220a6eee63349409534d015ddcc8a793f67621176f575881c98f540b23d1387bcd10df0923250e53836a542bd287a7cb1d722da55a5e479e93645dbd9d7e9ddd131bd2788d658b405b887ff177a1f82ef3d3277e141bb05d7b5314e7eb13bd235732eed451a5c84217fb759c8c8c1a54d659b98c1f218100b5d68c403631cb05dc4db536802450a48b5770b0031a19551b2fba68ba105a897b9572a75e15178703d406f56552f99c288f68c43883bfcb00efd55938af14c65baa02d040c8214586081adc69821ce2d55181c068a82ca0f456e101ab3e931cd72ab6d93b9397a30d72fccd54855d9f83a1b422f0c01385e6c832bb87a8a9a8a74179ea5ad4ee4a01f1178dedf808360f0b4c6b6028ea1a423dcc42f599a27421837fa83b04551c29602c4e244a15a12540c13758df4c1f6f7f127457f932e771b26c345fd882a9e631f977ab28ef399d34fd796151de28da83a02b5d51e473514e8a2503c67ac4d72a276cee39ad6d650ea52410c48ea561ec1a547ce1d73bedaa2a58fc627ebd83b9f254ded057a5d497843f77349fcbdf608722fe2bee7ee4a2c5a9e19eeec49a44374ba3ddb632e677a1e50ed2fdee202c945e36b75178da7b73ba6e585bc42fc01a1a97675bf241f718f1e6e21242fd25ffa7a0c4098ca86c7c89506465d9dfcbe078d59da708439c619dbc0d1116e0574fa2e2fb39d4f18d79916115b9907bf009e8f811fdcf0462a6111850e18f84c9d50c3c80a1e8c73fe39224106fee133b2e1d59e9c051ae667d500fe2fd22534e5dc6d2a27f25069db667eeffa98b45f11a3c7194169a9e314dbfab7c245ee33e1fca3eab3d6dfd3d7bfbe5bfd29f479f599d20f02f54f980798ea9ded4ff757708a946da14f5753304f9f29c0ce3d5e0f38565b7270943e43e7bf81569a080caf10ac1669ed9642e75a4c19da6358de05f1e7f2f878d9309555fdf30d64b0cccf2a92ed49e623003e9505bad11e6eecd33e7f047fde970972dd3b90ea065ac07441e2a119174be267148c0e314acbe87b47736dfb59ea29f289608d72234d3e71c3dc910fd2a471b4d36ec5cc4043da117ccbd314dc68770c215d95b75fc56f5ac5e446c77b1ec9c6c5ddc86bcadff35fa1052025bf5fd55bf722334cb8a46eb616eadb01eaad5342d0dc290bbbaa378954f22dba6fbbfbc1d76ce44a491a7c556074973bf01c51c2e8caa80b541754ef66e33a8d66b67aa3b95759f62e778d5b9c45dd0975317507a8ee6b8d8bcec58c5deff0a2f9f796bc32ff2a6ade7a364ddbc49457352375e5769f05692be8f396d132c28544dfba9dbbc69eee0c6a3ceb235ccc845775bc8afb6d5e1b4d9e46b8a4d4dd8b5dc7d4a77d6bada3b91eff11a079bc41dc9daade7abc77ecd621f6e31fd2fb5ed57128d2e00e90d3aaac30720cf6bf19f74e50bde7e8f666b317d77014a4579f73e4d16ef38a87eeb9ef029563d7dd6cc57b5e3640b5feeef5c2de3adb878ea18bbad98a1a7ed922c668765d1774a1d76eb6c0d407fbd4bd5137d07d8dd0ed67411f811608e25d9efeaa5b4ad297a8bff0eb0507de7a613348f33abbd9b84012a170efddb6def8f0d6f5037c05efd3fb9a15dcc7e091de55f58eb757b3ded5797199ee79784b4a7bcdaee1e9cd163ac61b915cafab7ad1bbb76e8708a7dbd4955b1b844a4517b5ff14e1e8e070a0273f1dd011409233af1aaddd18f96da35edf5b23f5ce893798bf2b796fb68b672f05f5d6651b6f2b9e1c0db8320448386a820f65792efe5f06acb70214e00ae84595304a788a0f27b742551243b580d02331d1ad25b0dca62c7e2d10e5045bb31835e83346d716a4aee499f812c0173cf1e048461e1c71459e4d286ac2b424ae15a8830f7c27b3a90437fc3c4331f13b62bcc82b37c472bd19be8e507d2f34344089327c2a9e1289503b48368a4b55fe803a9b681666d953497fdf6f685a830e063459490d16e0521ae6699e4d3f06706f77bdfcf34055c5c37f3482b29367b1d17ca3add2d0c42b3ababac2822d49077e79323d866bb148695f0815319182540c326cbb40019c23553a683b44936c172f2742b84da9d32ec753cc6c776bca3487007b190edd78b026380b949b04b544c1cda4bf707b1a542a3919fb68d33d21cdb5b718d1ef935af6564b3a313f0c7dd1723a4ef034ba107465f92bbe1fda2ae0378e8e46ac1fde2789bb4d5823eca0a4421275d962d117633450c85531bea80b4b7c9f108024f42c1e9199240366b629a03202400c2426baf08b30474cdac186c933c6c616bcb05288e74cadd1981233a28a28c9ae611d7df6447748d284d0ede01f3599c23ceb0526189fb2c326fa65d1ef6d3a11ad483d656ae5b1e1180270e0bcd1cbca1acd1925cc565deee5b574bccb1dab4deebd6a448e3f6a33bbe722afb835da29133e39e61b84634dfdd02d982fd671510f3c097fca68a58aa4fd58b3e8dc461be3feaaf51de3879b2dfa4c2cd0181c089c45769d8c2466aa7bf8c051a2d8bb1bda9ee5892c9087b340f9e69832845f81e7440a37ab43c640e23c5e0a007e90514427e54323bb8669bbf0f9a3c013ad0180519145d2914001080ee63a54a530fb8dc9d9235657656451257842cebf8f3e86fd8694df5f4b8621717cdd51e70d5f5335c7637fb2e0aec8644de0404e36e64909b19d32d903dc4dae934278a6c198c89a10ea93c1dd07694bf83d0833ad42c428560c206f83195805ac96d0c0970e66842e06720502d426e349cf00b8b4e943d790a5aa8bbe84e5577e5288b0842708b04f831988ae2bf918503d83651779be604042039ddafc086fadb602fec504090c2f40b46439f003fc003fc00f00d546486ca4f5dea2943291872a34966a7ba794524a29258d9a5f618fdab7563758d31f050c890ba50bdaa5970c368472a4cc816347f14098ca938cd31910c42432c733f75031eb3469e8e817e81ffa0e21f3e5991f48d2acd4264f59ddb974f481a459713f43c9d0967f363e1074a99176f641b79cf88aee81a0324744c38bd012ab1e0af5b1b464b0e9b871d629d03c90745af114f91a97944e062b1e0842956af16016196c9d76a46163c7197720771062f27f2e470daa33ec40ecb6a05f6baf037945cae8a59bd66c99ad054a8774c996d12c22d5310762cc6d672a1a54a73ee540cafb5a3aa50bb31d1a196c757120aa78cecc2d2a3dfe4c3810ac931261e2de5425cd8e1fa033fa0d041de3971026be2dbb8944dd404a42b8c825cba715d536903a5b4ccb531e196c37cc6003e9b26fee10f6fa6f1b0a740d24399d4d1debf255d540f4f6a4e43be775d8d8a10307193f407b21d03410cf45c5d654a532cab841821a3570dcc071c3061a3a140d0cd0333472d49d6a4d15161d65201b3970d840a39861a6335033e4217aae745c1ee10e1d367494f51d66a4116819f6dab1bad5d3fdd8d82e8d21d62947a78d5132b86b1f3bfa1e72f1e6418c089d8e8118c46f08afa07245fd37524a117ce00366e8283ea851a30b2a06e2c78eaab0e09673ba61e0be633f45cc52af5e3bd3a3c6a4b3acbbb56020e934a1928d96fa05923e1994bee6e097d2a65e206dd820c3fc6dfccb942f03da05924c5e315367cf0572e6f914a6f4ac5b20266d8b265bb1d4eaa95a20accc55e768e65dffcf41b34010a641a8db942e6b778a05c2f59850531b446faef50a4419958416617aae4aa45620c59c938719b13908eb5401dd1bc4af54383c4fdb5e633bd5cbe54429df6cab383729ea1488731523e635533a4b3b41a54078df909ff2254fa3401c594ae62b7a5ca05020f66f7af2687f1eb38f0a037d0249f8860835f11dc425c960eb4ea3d509445db18ca26f25833681a0275bd1e349d19e7f3e823281a4652ab355e6740904551ea6479766e693512510a4e6c6286d49492088d85213d2458a0472697fe6ed6496693632d023106d456a846bb75c443bf57464cfb45406d51fab4184a618c4cd1a7af43abee824dfc0f18235238941ccba39ec37da68ff6f021fe430c815ed3fc7a42f6110df2a3dcde6d4bb9c0c06d1b29a8cff99524cf10706d94d8c145153e6d0f10b82a7f424b43bd6be206aba13ad27568d1a28472f8863e21734ba7f12b9b708c90be2aff6e5cd31f56ad63a84dc0549fdf49a3a999e6006367690ba208d75e62f9dfe2ad6290d3476a48102cc5cb8a24dd6c5f77141b48fd1ca6e4f6e32fd16e49c63ca417c3b5b90b37c686a4b41e7a0d4b52086986a326161faee4e5a1c35f8eefdcd3c8b62ce61a6ea74f32e8bede56bd6d5755ccbd43d6f3e68e64fc682d829998ca73bf4b452b0205958f65bd22b88c953e756343f5d41f88f31767839a599df6c05413b948d921ebaf3476bd45042b282f8e9978329a5bd348f70ece809b40004385a50a3860f70e4c8b10a82503166ad9ea40a62e5143206b1e184f4945490ffb2cfeba92c17640c2a08c275d5dd4f94a88fc390a720c7fa243fa5a6759694b990a62005fd362a8858b9b47c66214b41ce7ef3659bebc3e38714c4fe70fb2848a79deeb377e69aec884271ad2e75bb2ecdca34ad1dfb5d913114a4caa1d5b2e7808220e593b4501bfa57e4999f20e5a4f72d7b05336d9a43437a82a0f39da95741e6ebbe13c4bdbd38a17644e860d6a851a3061012420c848450738258f731fb687e6c46cd264863d5b677ba2ffec6344190f5a173b2ca4c902d74d43ff9204c103de9670ab364b2d6b904f9f2c7a07aa5640982c6783f7f67a9192d9520eaadbdbfa94bab16a684ab7b6d2936db21eaa5f3e92c934e234323c84910bc36054df94979e5daa69092205667f8e938daba8219099218194329d12a32fd270909095252ad499ab8171f4114151e548c8a5962b53b829431eebea74adae7fb834236821cb64e6d3ba8cdb859a34615921104259f6f4de5466ef8f8224849d5c83b5323db534f4510b48d46d3eda3a5211341361d3b67b8a86b0d890852f670b5f87f7974776dc84310de82de20f425cb908660ef63cf6ae4562dee435b3499a65ccd3d6721c8369a9dd7922c0941f4cea59ac74646093b8d1c04e1c37ff80eb58c95194110e5346f762ce15e0a044966d1cacbba39655f4090cfbf46aaee698d46f30fa4522f723ebde5b9a0fb812052e3c68ac80b5b671fc816c446e68f4c1defe303b1db34c57baff84178f640ee94a9f3c68eae1de3d403492651b27193f2f0981815335e8ee381987d76498fb8ef403ed3df9b92b8ef3c253b1066d447dfb01dfeb9ab4396a2baf795dd9917a759d51aa6b2d281346e2553326161addb39701f3776eef965395696ad927220e8471fdd70617ec405d1d071977120a9755caab89d45d130e331070a6e05356ac081982e624ff54030368050061a8933c8375c296a90634a293de07d763ccd0dc45479ee9450ff78db408cb54adbda7d8d1a356a241b089a8492269742caf81e835c03c1ec949870ab133f911a48a7f4adca8476f6f8c61969d8e8c18dd31bc834103e5abb5e5b4ca6530e1a083a5d5fccb4a92eb52683cda4a1e30ca4936b42d6564c11eae39166209a4af16ebef36f68dcc8b1434719bbe38c1b2ec8c10d0e306720cb40b0a4c26baac7b49a3c4192816836efa22aa82043bd1d67dc48830764e41808a284ca4cf7991103d96459ca202e571e3d4f8681e8ade3e999c49b868b196020e720e6c5733e9333970b520bf90592ef664ccbc9644afbf92da41748e9d4a6f352dbd339b30b244d5984322f9da593960bc44db72989921d349e9a5b20250b3a5b5032a65bab520be460b2632619c733ed260be4aaa062874e97c402514ff505ada42d6474f30a441f55eda5de6655565a8160267b3f6ac7d0157f568124347b92af8b97296f5460b3c43ec52a3566e53a4b4e88f6bc7d42cb9c02f92f55c905fd859402c1920cdb1f64d6ac3956a38617320ae498ca3eace949065b0f6e1c1b69e0c851972b82b6152414c8a54de624d355d2fba2b6b1847c02417754c8523b4bc2fb7402e964cc9d797f9a60b09fcf9cc4e74c20a5119d74f4ad7c749c4b20b727ff186aee5402f1ed636f688bcff7d10e641288b5bae18e347000a194914820ee75d4949dfb3c02b97565449385d30884cd31b798fe9d8f226423070e1b682260cb81ba1824f1a04ae9c89a12f71f3156fbecdee22976c320ba58dc6c4a16534b5a4647096ad4c8814e0e1c9c041406f13edc466586898341d20ee73ffa473676e4b8916347e7d8a1031804f5b24c2a5fb6a472f35f104d76eda68b73c9d3bae10b8272abba4f7ac254f47b41d0ce3998e5c5ef9e3c9717e4f4a44f689cd7d66dbb204991c9b53ac76845cf7207a80b8290c1dd2be5cfe7b9823ac05c9433f98d12dab265e0c061ca405c90ec842caddae06edb271d69e4b0a1e3469b8e326eec48e316885b13b62dc89d5a1e573389bea0af0529ccbe27759eeee37fb42026edeae2e16b19f7096660a3e02c08f79b72d0d739a65596461928071adc280ba2bff9b6ce8dcedd07e88cb558903cc38a9814259b53908c1d250549c68e82460261c725c282a0f2d354efa85a9ce7152725fa3e9fbe8f80aef0d2ce643ef5146cc51d2d3372e0f8801939702420ec4056ecf1a965ad73f65a318fd214fee44fc68e92821a35c8d851d0a85103083b6ad438347015248d1fb5edb327bf18a12ac8fbb1a131a754103669d337fb410549dcc46e86cd9c82b06a5f632384d40cb229c8a9a4974a571afe93b614dc99ec7db9a56e5a7dd6c659af8514a4b54f1e5b4c681404cbffbe2c3597621705a9b7c3e383e8aecf78763a8d96d4e442501054122aa7ef9ece2ccb27889d22fda456083d4192bf5277f59d139ec14e10cdcbd3aabf6a3419cb0139414a95e6734cb39ade933641d474b229a9769a20a86439c78c10d6fa5526087315839d7e7b519d8309f2ca8fb8f50a1fa62bbc44666e792e73969a15e484e798f4af328b96207cbe24fcb7f208f57425d0d8b91cd18ebbcb3a3a36479c8a174a10346e9cf0e4e224482767e572527af62c896d984ae2cc7b522ec5284682b4bda1c3ddee7a21a851030608095267fd7d0e13a765001f4152295c43e8ce5d1a7e32d80e0e336cf4e0c6e1d573412a3a821c74ca1c84144f9549acd80882f00f4f0f42870764042966d2a3ab821061a7838b2026d3e3a645a7db075404495b96b20b3d424c0459ed8452d2dddb032282984cc9a54d2b196c27c04310c632cc461bb18ba62683ad8e056d256b0e9ee9acc38cb3206f8c1fbe2b5cbe4559105cc4a5751363419e97ff182d68b4d2c1829869bda34e9ddaff5e418c319d1ccf5629beb98220ef3389d4cd2063ac15a4d3cb58414eed2997297d41855641b84c4ad367d1dc29aa205aa59196d5e43d9c0a726fcca8280ba182f4962eaac742a720e668d234d8fb5c523205513efe53366d4a359582a453a687b689535b2205c1437c5768d02888972ffe8fd2f75d17511035a935f50d2fd50905295e4c2fa92b32950e0a92959c4dedf527485a4d6cb4c69e20e776f8d5f67cfaa29d20beba9690bb4bad1c27083227eaefd904412df7e652314d105c3429f54da5396999205fa878ad973a9820263d1e536c8c49ab752e41badc9fbd848c25c8c9d572c9d5660a329520574cd522ca4e996528418a27db83be5e2861990431d9691765154990f6e2894bda8352a28e04c1a348cbe0516bd40d09d2969213279eacc4fc0882dddce989bbc691df11045de9831637cb7fda6f0429f7df722cf71941708f39f557fef7d45f0441cf7e88f051e3d97c45904545abd5b0495e8f9f0862acdb14e3daeda1840852e9e46341f9e88be910e4906f320431cee7e41b4f58f07c2108a357fff6c3299d79429044e64d1bbf7932fe83205f774a3957ae50b31104a9dc36ed69261044b998a73626ddb60104b142f7fe27fd67fa033975257129ee072f65b9784cf7816049df94de9b0f2499c64c07bd29dc650fe41fcd0b4ace7a20a93d370f861297725493e2816c3986f43842cb7a66ee409af5a0977f3b90d4f5b8a639d58124a3e379b14407f2aec630db0ce6999f0339c7b9a8a1e32835bf1c48c22f677378beba1863e97cf587dcc081f01d83d20b973710335569d695ccc5c50dc4f63a695f9b2c064b1bc8f37331ee92d87d9d0dc4cfa3fe548fa6737d0da4ef6b93d9aa1a8839b7c12ec7301bec3410f3560e95eb294bb56820eab847134a7a78909e8120c469d7e5b598819875e4a664c14efe57ca407ab9d24ee12b64208b985b870e96d35e650ca4984f51a76fa4b655c4400c2a4267514b3d161406f29526d3de4af92fea3e97d20f4289be40ce5f428eb787b7d37b81184c9f9fff794a4ad305922e95c5ff4f9d073117c8f977e64ea7ff52e12d90d7c63ca9b09be35f2d90b2adcef73a69cc6d16c8996fc4e37a0665522c90827fd063bd6d3a46af407cf5d94fe623f3aa5620c8e8f88ffefb23d42a9052dea4695029943ca940caf09a57f79c02e1bc2fcdc25a769b5220ff797acf6929c38f1e05c255f43b2d7b8bf1732810b3b25a786511cbcd9f403639b97a3aaf9bcedc09a43ebb98c6466f0261ec5ceed774909f092459d671f1dec4529640121d457918b957655202399b98ee11d77131ea53fef02081245c2fc6147304d2bac5b01108eb15f36c4c2906b992ac4eba6a71de420cd269f5344ab4cbc6f430084ac3e26c270c622cad619f95ab310e0649e4e2fefa0b0cac42f429f52fc855a5820ef63adfad2fc8e133abc8cda0e3aabd2059aa32a57a362f08a3936aad127b17a478d25c6430517abcd605f96e7365178f317dac7341ec2837f7a793f2f3e08268326387926a5bc2bf0539c8aa68a67a5b10ed4cd7bfcfcd94a616c4179391e1839552a205316809773d4d376dce82a0e9d932a3e96541d2a0c4792719c782944fe78b41ae8b186141f03b195b43b5fb0a62d7eab87509a91bb4eb8a3679aa309d7e2b484a7e8e9bf37ff68b6105d1f3269331b47898cb2a481593c95d564a5b155590e2e8f3d0a9f4c9d153411ecdae29cb4605c93e875032daa3997c0a82cd555bacac29c899642e194f952a9196822c1ab272deae4f5a2505792cc958323457267514a48dada4535cd0b6e48a826095537eb89aac186e2888d739f462e5161424137bf1544c6349bcfd0431d489ce14dd43cec91364bbccba8b712f9ea813a4932fbd65329c20587e5e55f82c1f6336410eb253a7feabbab26882b49a2ac4e75e6f2b9920683b33dba0425def9820fa584eee79c4e5e79720c6c50b15ffb60441cf5b67858f94712b416abf52a61eb3a7922a25c8696bf4de4f25b1a64e82742e6327835b8e6ba924aa341b3cc9b33412c4d6bf4c1b8388d7132488f39d2c5338354a7f1e41d2a3d47ffcec9fad7104b2ac77353ede088206f70af1d123bb2723c899f4c4b3d68b20c851df39a65db55a459044bdb68ba7d76e8920dfa6381627db7f2922c869b2eefbe2865df210e4cd9c62ba3c6af7350439de8f7c10195e55652108d264b55650b2661d42904526bdaad20f82f851b7f4658d20889b646faa58024112a64eaec7fced8f038224933653297cde3eff03f9ab94526b613f9035dccbc6a99231c57d20ebaa7f4aa53bbb593e903367d7a42ea8bc9c7b2006dbf89e643d90948ceeefb3add4661e885194ee381663951d1ec8311fa36536ec738677205c080b2ae9d881984bc6f486a60e64fbf0111bf1ef23a703e14f7e4edf06798bcf8194c462909ff4df4d2d077207f16aba6c3cb41c07727f901be99f729fe040ccd98446b3209a83f60d24bf10623d643cbc75034169aa8fcd987f94da40509596f6dfe19bc30662caa5f3a792b249bd0692f6b7f9b8d92b9fa906824a5aebd62fdf6b990692a6e67a10292a6f4403c9d433952af1ce406ecd98454689ab8d9d1988e71b833e93958198199ff3be2d9b1b19489a5fa6d3f87ee8756320a90f1fd9b97350729d18089b625c8d135739ac0b0349e42769f5f184fa2430903cc6ddcf31285d26f405e2787b9e0f425e20cf9cb0f3d4d1ca5117c8499f7dab67b9e0395c20fa9d572afbb740124df7d142c669d66881604a09cbe9f12c10adf42c5d732c9043f75e73b6de5ff90aa4bcbe19b7a0f2a6a815c85b1f5681dcad26c42553294d5420afc811693987b5a56c0ae47b791d4f9314881e2eb6a8d2890241c6b051cc35c62003058257fc98838ae8a69827105eb35ebacb9fccc609e49c4f8d5213481b4caf7e3d69bc0b13487ef91d57354b20b67db5e7ab537fdf73e2a724902b69dabda60799470279adf793fa7f86cd11086a7492799dd708e44d967490ba79b4520c728625ebda1c3c7a490cb2f5ce9ed0e33008ee2fcabb3d6110c32bf496824130e5315faa97028324638575b42d7f41b892d1a2a5dcf54cc928a82f482a05a5e35c455d737d7bd15cccb8f2826849d7736a53919f71dd057bd71e7b9b63e6032bd0c5a94489f272ec402317868bc263db4cefe4cbd66c4dffffe618bd0541ecc7f8f2259f6ab5da8214efb4e70cfd5e416b41bc94f547b3c5e8fe3c2d527396e459983157b173b1ad177b973d3aa58be1634f5c64b1856b95a959a988957ec6edb88a4c6341ca499c698a413fa8496141ead5242e87783f191b3b500e72e0488776fe0af2563ccb9b94d6a5ae20878bd97d2c08fdca9f6a2b4839a38cd00e9de332489515e45139ff294f5f259e6522741564cd244aa51d154625ad07356aac400438727c20ad0798e3860d3474a4a92ac8b9373b9d584a1d94a6a9209f9fc7f8d8747d99840a62d62d59eb9d34e6844e41fed038ffab9ac53ba6205c766e92d5510e5a0aa2e8bf5cd1b020ce6511282948b132e5912722578f827c26d426f5f3c1f26664b08982f06126324241929f3f86ac650c0a720ed1d9a77142a8ac92c186876ee4d8919f2089bddf749e2d3a3c41d00b23d4c4e63a410c7ac294527f49dee89c20955cd21a73b4c711ca32d228091dbb4d904b657c8a97452b658c26c839f6d9c3c2b7678a6a26887e1d378993c12a7f4931410e9e27729e847a0962d62ebbee58822422376ca80595635a2b41da0f955184ee1cb486942099d8caafd1d286dae4e0868e3b814e8218f24e9accf3bf4b8214642bd6c4856c073f12c450dab4546b4619d3b191781412c49341ca85f250eac67b04b164ce39e7583932d8d21104a5a2358772ad11d7e5d1ffe799716584ad5523662127f316eebe2e826c614b9556a7ec6da21ea03214410a9d3f65d3d8397a84a38c1c9c71230739c05146228896928ea652a6f67cd91fa073c60d1b6926504490535bc7d021df5f9774085297253932658d214c29c9e41943ae85208839dd99f67c44e79010e4b8ae146ed388b0940e822cdaf5847988af65c60a826ceaefda1a93017f68d978548120adc76c73ce983cc650812862639cde8e61a3dc1e53209b36153f684ee59d9692ca99f27a4421cdbccf1915fdd0b11c3da040124ae52cd67208956e8f279054c56b3295dd0944dbe42b9f723c9a40529e2983fd688d32e51c3c9840b8647aa6b205bf64992510a396b053151d5fe3ae04e2d5e8171de4ed91048236a59dcd62ca5979f3400231c920b6dcbd944cf03802d9e295e94eeaa9335369781881ac23dabda39ae44ef56290b265e83771f22da8d507eeff57b4d0518741d28f2f5bab68da4e9b2e0cf2d85a507f353a668748f0603430147f914e9f23772dba3c4d705ff49b2e674273017082f7c26ae0c07961356e17a4da37e1f5fa93c1375c178caee65d99d6ae89bc7b4ee963dda7f8792e482a9adfd66d2abdf9202ec82175e457fdccc468b7207d96514ff24188f8b8db82f8967b2184cc5f972c1d580b62c6a0aa2bfbfc8c5075064e0bf2573c9ddd4bf674e7dccd8274a64344a998bd9305416b1c13eafec1ba4e77b12086f9a80a7a3dfac3098be26d4ad3dd2b08aabd9731464f217c73e70a72b9968789c8ee5a41dc4e953c3c68ee58413cf5d173c7d8574110d777b1e4c54cf3f7f5a0460d55902afb63ca183578a9207ca6d92833f15041de0a17eff7e19d82982b2b2fe6309e2948a15c378c1ecfa6c388570ab2798ae756b7fd3ed639298849e6ab5c956459a9f10c1c67d8d071432f053e0ab2458f27377d9faeca4e14040f4fd22a7575a12085b00f55d14aa970f9030539e710fa1b534e8988c9603bfe09623c254ebce6d19ec13d41ead4902237293d26bb2c837782207432d1bef24ecae504c94fc82b15543bdc5661f04d903d89dd76136dfd5479c13541acd8121953c9f34c56f24c90bd4acc5aae909ac131412af7f0aa4f71cf63e60cbf044168664fa94a8515598ac12d41cc9b5375ae18273f9b64f04aa45382a0692c46a78df9fcfb240842c8e5666bf9bc7a3925844b82d8d59d99428e4c0f51dac1234118addaa3f3f86a798d69704890b7a3f6a57b6966adc344e08f20a9a826177b3263071533d6e18e2056ce6bc1849039f6834e9f0ebb813782148458cdd9a7789b3d7b704690544c2ded39ebce231d86be0892597eb8be9c4b051ba9c11581d649cf7162fee924024f046134fc49ed641592c01141780d3a5a7ab3752d49077e08925ecbeb68feacb636dd10c9bf564e23636ce085209dd4de2e5de153bcfb9d1055bddc79c89197b43976a041041fc45bbaaf3f9bd2665073ec40c30541700ffbb1d33589fcda0c0f443999a7fc1602046e5fa9326ae7da69eab27a1019447afc0fc4af7effbcf5f881a0738c5dab10fb40beb2ec8e11b11e543e10637d9c4ed329a74d7e19be07d2a9cbd822de4456ae5c0fc4f4aef240f0bdb5b4793c5367f0404aeb24c36626dd81e86fe3a7740addb4273b1045f34b3be4d9f99dea4012b75c8be1a203d93395ecd0d19a97990349d6abe6d02de23f2e07b25c75ccca1b83cf1d0752d46d8fe29fa1d3860329584e9d84c86f20a9d4adabb4ed16ad1b48793466d968a5e449db40b0e0e619326503a94c4ebcb5764635d740acf472c24c5403417fc924dd3c94862e06693a8e06e2cb7c979a8f0f3ae8fd0c2971196433be66207fca315fd920747a6520bc69553c15c5faaf2703b95743a8aa2037ba3f066265b58d49566f8ab71808969dcb6a4b13067210975fd5010371bb3f75f3abb28cbe408aee5ba23ae405f205d198be5665ed77817c5266ad820c17c81d5498cc9bf4a9a0d9023145f5f67c580bc40b9d4c8f56f317390b24ed30333a69b1408c9992c9a44aad97ae40ccffd0d2cbf8e361b182212c9c5dbc8b5781b461cb5cfc762a907b37e798694ea5a64f81a04dfc678fbdaa2f92025153c55c4afdc8dd942890848a31e7641528904fe59615556a4f459f40b8b09be2e2677c994e20a5f8398ce95c2c2d7613c86e9d367754261054caaa945f0251c5c2265d8fb2494a20e8092581d4f1fa3fee3112c8d735d2adb3eb47208cfc665d5279b45feb46207bbda9cf894c793b5a0cc2ed8d522a5f07b5192506b1332b3f6c59592e0d83bc59db2a6cd68be1220cd209952153fb6cf2381864ad34aabc030ca22597d139c810afdc2f08be612cbca678cff105297f4ad18467d90b92e9cbffb959f282dcf147a91cca3e9c7641109b44f6c8cdbea6d105c1ea93ce1594e5b44b2e487fa382b820fb26692ae5740b82cc4b9bb5185293c916c43816c32a3e2bcba8164437cd6831644cc1a3b420c6d45232a6a710b5de2cc849db94bce9280b82da4dda634aa7e962170ba255b0202f740c173e2c92ef2943bde8af20ee25eddd90c993d7ae20998c12d6b7c2a46445d6ac20cb96d0187dda2ac8c1f2bdfc25135a3d5305499c5ed22965a9209ca77bc614d4c7b951414ad77cf9a544b6cca720d8788e39a7cfd3b3a6206bba5e4e3257a520c8bf956d8df13da98a14243df22dea92d997aa4641f4eed3105aa2f7ed228af2b6acdadc5eace3433d9bcaa1a55090d365483f5913963cdda020e68c9e39dcec6c92fe274896a9b5d19e20c6264fdbfc3cd96745a13b410c0b29971e7f7382949f49fcaf6e7cd09b2085d2a1b7f671bd5ad604b3592f2faf9b2e2aaf6f898cd4ac726682b4a16abd52cef1934927c004514e45f524ffbe04312e6c4d98702d414a312f7c0e35e2d6ae4a90c46793b86bf19cc4f3018e0e34258e2a2ae78afd397a12ab97c6e688dd78c7184fd4cb2d0952bb09b19231afa7a78bd09120a89cf36f7fbef841a74082e4a9b275764cea47107407e11ed3cd74acb423c816f52abd424f295d3682b01fedb4debc997f8611e437f75251b2baa01741d2dd5839784ca92248192fef29fd9cd7edb8910306356a9c4e04d9e2aafbdbd998ce4d238258b91eb7b6b38720a6df28f770f22ab99f230d1c2c6843102be998f9a57d0f5d08c2854d53393c8bf00b2204b173f014f73feb315bead083207710cd38b2648ffc0f3ae3865941905b4f78aacb4d8e1d3a26f081154ce004d181206ec9146da25d0e52a346c9816e34208e13336b2adbe2a6ff40907e1d5ee1d3089da91441fb81e01a5fed93ae080dbb0f6dcd5c7797657dcdd8669ccf88695b9a0f84bf8b716d2eedf8a8f64098bbf0fe63592eb41ec8997fe921ddf258280d1ea092060f48e581a899e6db3fd56ee4e67820299d61d4c594d2d17720ac86d6aba03734b968056e0772ffc970a6da29e5f31884ae03395426f99af62342d3a1b6605a4554ba760e7c502a670eab17125a0ec4bebee4a2555f695b1cc8ff63e16732e74029848603d1a4881f8bf55811bdc10d849141b7a5e8fbb42143ef361047efdcdb890faa7ba341b3e192a541274fa2a45cd21ab8f33457d793cb96f93465fed9eee9154438683590cec2945eccf1a23e990682f2a45f2363644c6f2cc8c1193772ecd09146a381a493d8b4fbf3995b7dd467205aee60e97aff360341c74bf2e7531853e7e128410eba0c84194d7e229ff97aa6264363dade7167e53632cea69c76b374ea942007ca410e7094d163207f0e63973786b74a4d8b81a0ad964c4e3f1d0682f6125fd7f4f8643718482553faadf0cd17c89db7c17f562f103dec586fa59915d5cda1bb408c97b2ac4f27ada5c2058252b2bf6490a32d10355dd42066bfc9d25a20d6eb9c32137156a5d459488610c202e95c64573688cfad9fbe0279b4688ad3fa512af3b60229889a6b4e198f7b7557812c3ffb75bb518120933c19ddbe140f734f81a8ba1a3f6bd229bf342924b7612d7255a61d3a53fa7c263633bd1d0552c89f4c2a26d54d27289044b54c9697f4d2a12790d42fdb680e9f749c40d013bd29bd6f02416c2ae56926107fc7b2657e9f497d09e4bc37627b5d25903d9dd411b7ec717712c89b3129bd13238164edd69bf3db4720e9faec70aada8458db0844fbb34e333391578b41161563aa69e877391331c8a7e29cc558a6611034dd955229ba299784516eaed798350a0631465febb424b75b040c82a6cae5f9cfda72ce2f889ad2e99cc673d8cffb82f041bba6d3b1518fe90539bf776cb19893bc0c2f48f1c942bafd78ecf82e882766d183cbba2087951f13f95332da5ca4e46e161784f1a0c472465e737b0b8246d3ddd6fd0d4a690ba22621bc2ea5c6e8662d08326797b71cef61262d08673b7e803070460e6ee84080057460009561ca8e34cc58800504a003e548634741c9c6022e00800aa061c00b03787512487c47f77a282001ab715cc322f03b74a491a300010082c1800200b043471a2b204000500e4a1a3938a394810001e8c8813e8d8323071a09300100000000000000023bd0193b74a01d18481c484741c3010b581d37d0280a08c02700a04387a9410001941de5d4284000ca8e7270e4a87100000ce00109c8816cece0cb0e1d366c2c00000168c0018080c6a3016fec3838cc3803ded85106193a8a0d1b0918c30c68c30602c628c301c62003ded891830c1d65d8b0918031c6b003e91003ded8d1831b270d1b36123046188816d69470118d0ceeb334cecc40396cf4e0c6b17190db8e336ea8600c30a061c69b81cc30c0185f20e8dc79d39fc89cceaf1708a73ee5dc271bef63ba0b64994b1f362753157d339019bc63708124c49a6fd64040e3cd4066ac19c80cd471c68d1d65dc48c3d8c881cab8818619389ec7d802397768c6b31cacecc007563001c5c4185ab8f262b372f46ac618592067326d9bf4be6ccef1118c8105763edfda4d4f3635afb5f35cd7cdac538e8b79c1185720c95c5a4ec65cd9308615484a0579425dfa649c51ca48018e510582d4747aa49ece630c2a74a3f9b9b6adaf2aa6962534c69802d93cee8acab11cbba61d40e0c01852283eceeac4e958ba41860ed781060e1b65638c110582aa1653e62f1a030ac45b339533bee51e43378cf104f288fc494f3a7bae99c8602ba31c1a610c2790dcf49ab9566b9a678cd1047218d9d3b1b9a45926c76002f93f7488ddc564b099eb608c251094e672f5afd678f300dda317c0610c2590c49cdf46f7510f6ce8480249a5d116645f38c6400249e84bf5fa0ee618e308e44bda7749b6770ca192c1b6630c239052533369c88c63070b4e50a386192ac3981b677c148394794e5ddc26fd0f70181b3bf852867154c60e93868e3dc10c6c50e0831804cb731bfb339ca71171063e8641cca3f36ea53cdf76b63048a5f3bb3ba6390bf50583ac633a837a348f5a32609037e9b8b1262fe7f8d52fd017d88be305d12b988c9f847eaedceea2b40ef90c1b59af58d37541dad4fc7f49a598a222c881768800e5200732015e0eb4e3060d3e7241ce5a9b5a2cac54460817e458fbef93717fdc22f18e1bad4fd92dcf1fcb243aa9ceb388e0c31624ad171fa488ef9c4e5bb5f8e4586b78eaf8f1410be2596b4aca46d6d73d356a04e16316a856edbfb834c70e34caf89005ebb194de0df12c5ac1472c3e6071bcc85a958bcced9a5e4134d963c2f3c5ae2065f52fcd9cb5561065d49eba911b35b7fa6005af829d1bf990d335af9456e16545679ca361c67fa8821c1e64c95aaa956f2c15e40d5e6a541037c8d1b9449c3e4e9152aa53e5d914a98ebc9ddb7ab97b9669f7eb67cb9a72e8efe6868f5290720e6a6327a1270531ee737c17a5320a82d6f4399fdc5bdd7b51104b27f1a4dbd4342ea1205655f8133eb796930e0a62ca4d7932e73f3e41eebdecb94f79e9670c196c4038f30439c7a3e9649d4ba993a11c3e3a41f8caa1b4f4e864edc90f4e90d3bd46cb87aaecd8c72608fb991d5bf5624e7bf9d004c1f63e8648afd218692648e1a3417b4eda287c60822033df8cca89eef9a44b9092e9cc3949179d4e5996c0dd52fea6f94e06db1937ccc00d7c54826cd94bc89327b4107c5002a143b33c5968b4d828a3dcc72448a7bcfaa266d78b9f5b093e244132a9174bf55d1ef8880471fcb545456b360f2232d8b8031f9020ff952c21fc633a56c70e127c3ce2686e296f9a551b2a7c38e2a311c788fd580429e5735d4df946d59f1f8a305667aeea544d2dc5650ba11d94167c248224fabe4fb73268563e104132b7945f4944a814ef8f439c21ae1056e38310a4946336a535bda74aa7419074109de149853eb59d2048a59982f8abe823101f80209da650b927ad8f3f580d3f10fc84921dc4a898f4693efa6035f860353ef64092a139ede9257de88168f5f9c645e9cc29ab7948eb2e5de33ccfaaf24eaf9227fda50f3c10f76aab4aa86f131f77207c4cc2faa2ad1f76209dcaa4b25d78cd9fd50dc5471d08b316e29376d5581f4407f27ebe2d71154fe2630e049713337e3517a39ee440929babd5152ddd2d1f075296b1b958a247a5a7e1404e62ecf6e2b51f6f2026fbd7f87e354277ee06528aa2efb25b2e9552f7d106821ea135cdd7ca0692c8f4b71e9ac2f1b106625d2e5329cf5c8a22aa819c5310ba54b5f343bf4d0341c7abd3adfa95660e1a489fcf627dac31ab289e8198f4b48dddb6a8ac9d19180b99655c7efb280349a98aafeb759dacd46420c7d9ac9a4176a90cf23110542d699805216ae1430cc4f81f5e4259a792d13bc3471808bac13d4ded52a54a26163ec0407cfdda2edbb1b0bd7f7c81b8bea34bf8756ee80b6ee1c30be43c0b23a3a6743edd1c7e748161f0c1858f2db0e0430b1f59e00f2ca4f17105e2e69ab63b6d41ee345650def3b3eada3e3f5545db543e65f09c8f2a9063877c4ae541bc6d863ea840d41474780a441721c75e3c8408157d488118bf735fa768e2e7b52810454d9f7291660b3ea04050bf79a699f9780277aefbb26297651ee2d6da1783f2ccfc1de1c309e44d152c77877afb68f968024183bd09d7768c0f26240e3e96401e91d916febc73685f09c41621d52ff7ac83d03f9240d4a0e362ce8e955e412410ee4ce858f44e0f1f472067bda074eea9ebe87f101f462027d9f9b1ef4d448f6290ae754f7452970da5e2f02006f1d33586e9cba4b3591968987143479fc06318a4b469423e93c8d0a582d04039d03816780883203298d82453f2e4a943069b8d73460946fdc98312977f040c721ab57e49bbff054145b6b66c967d412acbbf5eb1429856e7d10bab8135f0e04542e325d11d2fc9c8f9051ebbb8e793bcfb67557f051eba40f374c642d4dddee1910b52a5ffe0a9da3705d1e082186ffbaeca32e5bc7b0b7267d18c97f79d3e856c412c7751cffd7baa345f0ba228f1ea13fde915a4b4207b101d57419cd0b1c6591063949d89ac7e859179c88220bad4e5c8a0c74f055d2c882995ced46ee2312a2c08caa4098b13d2f22ebe57103cd3cb3d43e73c5c415e8dd760314aa9cc6f16c1a31504959358f04f6e496ff36045fbbfc92bc5b96f156455d9b6bf96cfd8d5a982a0b1f4f5a83ef152417ed7b09f53389fb71415c4dfec9c63f46cb1a69d8218eefa4e68ec9c41a83c4cc17b65a6a59db8553625aef4681c4d7729c8a63d8aa97ad2a3a6f22005495c37e5d84dd19b725682c72848663d1ef62a03050f519036b869e7a02f8d672714c4142d544ca5336d52a507288817d73475cc6f63e16d82c72788415564cca42ad883f3f004496b924978a7453d3a41f6b9d2246ed473820727eafc2b9e6db4f6d804313745bdd3fedf53b28726cadefdb153d2a426830f356f7864c24ab9a284125f690b3c30a1566cce3bfb27f081154ca0f3e07109b2c655f1b9d936e119a804c88c72821f1413a481050f4bf4c0a3125b94207caef8f3a72fc594a1499c2ffe4207d714ae732441d0a699eee7f247d31f09fdb4fb3bd38951810449e7d89129c8683258ca2388f79d19c5e64437c81dd1c5daabdd65765b7d79e7ec7f41de3e66c68b4723482aea76c8ad476d9311445ddb4ec972fc46d78b207caf7bbaf476f192154116a554543a3bf5bd6c2248dafd728c9fca7d224490e257cee6858fa9510f411e8b99c383ec39a193862068cff0979385356aac39223c0a4154cdfc23bd5c47c61221484287f8242b5e09130f8268e6e94da5c84bf01004496b8ea174ca8dcaa9f408045145548cdc478bd7900720c8415ea520e393b65f0b1e7f2028dde953bf525e0dab871f8841c9a6e0493ece275d0c1e7d20e9a7a926ed0d1964d8830fc4f8f3b9298392b99dd380c71e8816542cfb7dca95cd71e0a10782ee5d586d0a3f56ca03e1c4858b3796c60329b553959081c1e30e045535a5e5fb82ccf9bab303794fc9b0f7acd37b9a3a10740a9584e9fce05ff2143ce840eceaffa43da7c8a0931e73202595732d737c10791d399046779d1ab9216c94e240d698bdf675720f381034a68c59cb2f99b4ebf106b25cca3699a2a653baf3700331ae840ee257b781189a733983ee3cd840ac2e95af4dc7bf51298f3590477e9af533a9871ab4f1ac5ab9d2b890bdefd129f622f74803414ffcf5c85c36163f0f349082ad9cacabee710682852ead7ecf3ccc402a4f1a32ca82d2e92c1e6520a7e7ff36152cc728150f321cc1630ce4a09256ca3978cc24f3d3808718c81f7f514ec8ce120d59083cc24010dae453a8fc98ff520c8e327260e38c1b64ecb8e1033074f3b1f7b2f99d9a21a3997764980c96f43370e44836d874f817481ab43b7aa5663125cd5176d8b88123f0f00231fdcb092927fb2ba7e82865d8d871a30c34747874012f612eda1c3bd0f0e00229e998f94d5a0a3db6401221e641aaa6cd6dc6430b2415af4559b01a3bf0c002b12c7335d9598cfcf415089f1ad393c554e2ceb50249937ec7c5038d29a8e4adc5620269381a8903e290200c6234cb0300531308001048260d85a2c158a0278a2e0f14800265281c32322622221c12101a20120cc6816018100c84c2803018100c0643a1504044932bce07066fef0303c11ff11f9d3889dfb30c4b3f4a3e670479edbc0733577a0c4bd77d5ee85e670879e8d0b770cf16223f7bc053f6b195abc85909870887b294a546888bf39175b7cd72b90f667cdae405902051c8365f4dadb69eea9403f2776c5704abb428ffd6f1c626b596a5e4bcb8b17aa8632e22fe70c1521dfbcfbc3af061037b4f467a220da0af29db8ba8f4a7564c1fa6d9cd901aee26bdd1ba2cc481814c302857da5619568ad7f1e4a2e75a200902f84281f602c92e46d636ebaac596af63c0c1da93cdd924970a4480c6655546a94a93b46a025740141e40b539b62065d686510d178f736baf1a7fc99fda72b77557b9224f50f4af7809f9e9e8d0d28da65a1da0c48cb64829495fbad0e112e280557e307863af2f410bc34b8ba5d2b5d0b1f5e3a96dd9121660e9f24fdfc59752d1424cb5ba63203741de0839dca5ac9a0972342732ab0967eb82b3fdf6e9687ac8dd4ec0276114ba00c5bc11c4327572bb3bd97d8c1a9f692d2698c68d37f4104bbe61c9a7303b3ad6a8f3914a2f25d0f105fa6f664028a01840da1bc71814327c36e8aca0dc813e082e1b555a3af6631a06d16202de3446ad3834666c0acc54128c381352d1cc02bf28a777740e82b418d1270261295e5eafb445276b01c269191be79b82c588e6e6c030f8c1da4cb67e54b6c0b6d07b368beb2d9ee1c1864e2e519d4de8d7ac2043c3604a861fdbdcc18c7b7f5180c9b936bf7df1911822993700952889173d61aa8f1a4d404fe5ab316d8473cd2e058dfe1fb231bd8b52810c976e243bb6cc4ad072988c91762f490cfc361a9958ca01ca611292c5fb5c115b41046422dfc4a246d3d57ff53bdca185b3044c0e7a20dec3d84dd971b2385e9916b654d8c334f8111b270c4bd58d4356fea8202b91709de3c81ef38721cee1730fc4b70daf121d56434cc08452a634c82720616516d2af59247ceebd3e4121b2c2f70d2c190cde740453be5b687183949117cbb135ae85e873aa98d7943107a7184caa1468a68c2df6be6b692823cf98267ea235d193751dc526e9804798dcc1c69b63c9206d5f068714ed37312519bd4771721a00b2215177291abbe7265b850f4d685e6f5042049f1e11846413c40edddb9923a4afcfb0ad89d9112a54fbfdb505339abefffc0bb7bd50c43e4719521aa8b2c2d0f3a2ae370eb8dcf76a1b78108122a1f994b610710cc1d5be206024814541c471b857a16ac0c00ae6baa4160b1f32593cdef769e5d642d45ae76adbb12e788e922062e5826bb7b798d89531413dd1d7b2c08305745560d4f3731d10609a1f60f24b5a140565355b8f38e0945ea476e91b71c99ec9aaa6868b74476f49054c7689ee155d5898f679f7ef830e44fec494928e6d9647069c7cc1f05e340d7adfaab8cf8d38f0f1a812853ee99c88af0f453d57e05d47ecbe2d8daef170d53ad76d8a772e8dcd905215ab7844ebf7d5a8a49d420548221ff69c4bb916be28dda17117588e456d17c22a35038c6eb3cbd9d257fc9f9038785ec4bd7df15d6a3fceab0310cb33ae23e760e52c66027ab73865a902a01134cdbe39b6ad2776e555b489d44f46f387f51efcca928070cac0d6dbfb85136369e55949746fcc81bcdd7cfc69b04616f54bd0edb985a158f181038680dfdd581619aa18acd7d84a91ad6e50bc7d8663b42a72b8c8ce419c624d386fab6a3a944431afa3ae1fbb24c027db5bab92767c6eced47d3e73a5a03adda3e99085286bc7b273f1760be7272ff2fdcc9a9b94ec28df682d6b517d0146767cd8e7d93021729d9777945fe2027fba39de8a91b146370c98d2ccb5bef184d85cf3ff24e3f171ac240a4594cdd65c9c443dd0d77dd53896fe0134160f9547134422bcc3287fdddb4481cecad4a51cf45feec3eff4c4564cc6b29fe867c7705c4907c86cce85a5e6ae79c799a569c5121848da4545ecb8ddc4cfd16ba30830ba32ebe2e497f034234b08990edf62351b8d700b2394347d16268c0a23777783ddec430992b2eaa9f40bf4b5d50f611dbe912799d0904186c284669b6912672ac389229047fb954d5057994670a618da7e872381f8bcaae9bffbe3d3ae97f06225fadd479e2965fdb4e35bb578809721ceda25a68c5756440baeeebd75a4d604db0ab993737ec22e5976b075c7581a7eabbdf34108ab28fae0a75a27feb878d4bf340013581fc9550915f98a3d2d6ecbeebe04c3975905267c75b7a9fb078e8d274383225346eec3ae5bc34e6042b9bf8dcb507f11e3c2b487e758ffd2583b9b2cda72a4cef0a55fe15d935a35abc3acbda8b7121c6dc054c465ae62a8addb82cc8c823489440196ef960297a90400b38d4c2b2193dc082cfecce00e4d3e9ba91fcb4a4920a63c0dc3ef60a72cb31806f0e410c99b4987165926b760035c66ccefbdbe094a59986be3aee4be51c4d16e53b2b5c08797a08746d5c000a7afc0c906e960896299cb0d4bbc3adfb6842c67dea212c7236527f5ca00f2ed44ebd53d27bcd44da15b6a18fa45496aafa8fa42ba0de9b87070fba47e2a87082c118cff77c54c71892dba80a573851e51700110d28c18c3bf81611729d7b7deb34badc3a1f1b4f358c0c2e6df6867cb9d752824dbb9f647ed1f5ee74f5e00961e77630012ae8360ee681524988902cf8239356bc613b9adc5d11f1b6f5da2c45e8b5da092d082fdc1a98ed5b88107a315e6390c596204f17b9533688c91899092b1ec76b11c11f27188b6dbea77f675b64f6e43217248769b8126141db2d7af336181c2f0c8bde9b2710b971e07445845712144f58b81a7fe47549e2b10c6fdfd0d545ebe7e21f5ca831bd0fad8f3d26b0ea4831af98076ddf6472ee2a532f044426a1b90978a5069af43084d048ee86a309e02aa5a26c228d2711461468d8b2bf25bc2464a2962500df72c6d300108d9ecaf9ca596b6029e5152742c9e2dc0abb22ee890b98a1294a5eb69444e46760c11ff2dcbb2190939ff2c003001b1946f7b6a82bdb7dab6a68d1415a822a8e6f5514b64e3e8489edeaf0cd5932f12675e1515631bf22911f4cef040f7e915da379964e66e9a383933015bf39cf4edd8f217debe0d1fd2411c83a5fb0c61df22c43c481ec2b7df0956b86e597117d26c75a4a3f934bb6494f978e8be525f4aac458011292dfc5a85db1b11b1fcf68ad2fdbbeff640bb60bdd4c881220c82d140ec3deea901a6db38d540a3063a92e2e3d8d29316417c39bb87d8a1f2e41d3702a1f0fd27d36d940bc6acfd16634febca0caef30234c79f295520f4eddf7a68be4195f569440f4e62e3a9d26212d88f4c73242c072a29e94f5b36520c9a9944173433b44e97961a5babb38a76d8f67aeb1ea973434770f7190d65bb56bed3786ad40eb248daf410e57488492d8ac7ed9050b846e6e6c5b99df6ea3e155110e218943b99df6a1e78a70ecdca200bcaf0e47b4fdc5eaa4f85fcb648890e6fc51301db6d4e6f71255ad2aed3eab5932d47d66bdd7a98965fb868aa0c27f811310efe56cc8e6ec7dc087a9b52584d5288c28d14aca24c3341259a4a4a68c86ca276f855539c81e9b65e22f67273d1c7e1eea0f7d609b5c1f420a5648493a7c82191e8fae335643f2ad93455dc95113c506ebe6186525c978724c5d8b0a4c6d9fce0abff4fcf0f3379461c111473a9f36ef9a5ac616368303861d648005d9b8e7845454ed5d4903e1ddaf502ee6aeacb4bc14fc2e19651355e6cd365239c7fd3af535a2ea9ded3c2b1a3fc10ce0580e9d99ed881fd647479120fc36462618259ec23dee403869393efb9f2a903f83902608212ce32daf72e7d6b011e23ead7895e7c90327e60d3b1a5da8323f2a5f6dc7de754373be5f383bcce2fbcac543dd3bb8dd9a8b777807868eec247d2ec7b01d517c9e33e3354e3445e5a85a16ca6bf8485aba962420868b8fe5dd17af3790127e95136d51b15ab0ffde8fc186d56a0a354d21882f3d086426e03711c695b5d5b2aae89422d9230b0c464b5c1e35753db9c7e6768f31a2eda8b1ecdd7b6277dbd10c7830f332e982867bd9191b10c758cadfc5f868e074bdd7902432def49522a0e442cd3e00fe22a3e9c008a8882cdb4bcc001e074802af8cd022338cb60b45064424c5667de87414d37fde9f97b656cf8a9e42b6e660709875103767455fb1ad31f899f706fd729c0c0c3d69b703087c6a43367989fd3b74a7c1807fa3dcdc677f89e650cd8ec4061ae2dfcad7183d00becbca6e94d0dffe5410eeec75335fafef9958a92cb51785cdbf60deb086023123968e0b642be2c0412f45e4021055db6a5966ce57a7db88a068776ad98e4818ad39c21ab84342d1ac04504b94ad97006f07200786c5c7022135f190ca6d7ab13b1de7bee3d47510d73cc42cbd487ba677d6556105368e74b02171d61a766b9e54ddd720edb2dc9eda484f6fedb874c0dca7b0b0809ade5d88598fa15a74a1c7246570586f2450e966109be4dcdcf6a7543143b3f1b6d942bf12adcfddd5e927c88f9dcea2b65f4a8796484d912f6e4b090a016b1025fa518c092a52ac34e9721b020f5892620c1be5abafe8593374e5892b3dbac34369326b47e02e88dcd10ae2f46168f814e5da8c567781582384cf57326c48e81730488de44b9a8ec879b3b1d0898409582e7f4c63597944009f5d4de3389097644aea4a8195bcf04f287d6d2496065902990b0ca9a3c21976421210ad5b2f3baad261a9912a359722935686a265a417d65c1340e41bd86cb8fa8b0e195769952739517549f02018406edd99564336f0d68e1114d3a1f49d023ecfbb056e13c886f3ace5985c1dbdfecb59bbdd33fcd6aeac504a4176fa0db62c29302885734a1d333c44b6a751c3a301be55ccba68b38b0b7d23d65635a1f11c7c1cbcc296b8ec0d864c1b158e36821b187ac835fc6b29b4461819eaade0b47415f181d9e576ae8946d35ef7c93ca80d6c619156a274d5099eb3d0b8ec06e473f2973f8dd74a398489da11b2622c776c753c7f96b14584c9f0f44def1e32a03a52e3fe4cc481ee7c19a0d0427b5b7ddf10df767c68210c7dc1f1786cf99bc7ad45e99404d1e4ac79d40cf56a93a83ed4d23c746a97bde8408f0dcc0566d3a2ae39e2eece61cbd32864bd79cca0d2491cb67c71f8ada966227e0b5e48627f6ffd45f9900d60519e3d3ebfb7d7e8364c91328dc963924aab88801ca24b4a56dc74a093dea79e319bce210f7cdbe7e91da78645369d5eae03da6bb17a2d3b0a5b2e6a26d55ddbe843902c2960683353a97d3bbfb2e41d668a7203f6549f4e205c6ec908a5da04b5eb93b93891f74973cb58ebc320f8d572090a287f5531d576fb3a95856105aed3f62873dba5ff7b8004d895be3a4dcf0aa128bd4eeb3911724c2746357b02dcb4c05901652e8a9b5fa03de23ecac378f438785171f3743a4d1f7e23d91c6bf2e94197665c28b574d226bc136e19674e9ee66b8ba29274997e12dfd0eb7a4d0218c5c6342261c2463e0e0c45fe1c50b8c64ead59f263f528fe46a765b1077a8580ea9c496a290b6da44b7cf415ca60e624db40cda020ff6258e2906a9c53988a1175a776667369348808b230b52bacde0ddc4901b6a98810ed765dc4ff669b2d3be0b5ac0061a707d5563ca126cb0cc8d44c0c04154d113f8649504e890306fcbcfdb1a631234d0d3d7113fac59b62a90d0ab8c071da718b97d8412c64a17833334a905b15d37e1b9e10d2e9a4b83840ae8490a338af30e7d6b3fb372a9f69ada74bc4d1579f478dc6612e6d9cc956a0843060bfd91c14f74b29ee532d805b4f483c0be262f471ac3ce8d11940bbd912694d94a6e3ef7357f0baee5f9322cd7568f1ae26c276d1631eda438101f0e53bc04aeabf6dc94f10c85ac3b522c60803279298c060740d402ec4cf4661bebb273669a2243b67ebca222d676bc2b99dc71112ebc4022bee6b70873774f23ba665a84631592ca7d1934ec8d083092ba95a16aa5d04cc250ec923ecc6173b05288d2e132791f66385212f80b7b66966252e064e01384b748cb4130b45513980ac92589a71914f94f549ac9e06dfc496926eb41be6378ca4841b9bf0cf7cdc39ec5ebf4024969ce9acae021c27a5c1f3a5d993727c471b29dd499d23f42a700d78855c86ce0cf2a6272c6ddff3331d3a3b0fdb340704258b95b4449af0bb474da3bc5818d2de2574548d208911e8ff18574347faf4f3b217d4492ccf1fc65ff75387d36ecd3a2498221822418cd149b06624deb422473d8dc30186eb066080f602511d444b410473b57889ff92cc84b3617a93669bd329ee5814df7facc80358392b3f149787eb8bb9cd68d4bac2f8ad8b9626df7a90c1de6ee575172aa93dc460227c6f2e01c7284c6c2840b93f3ded9d2b37ac3ed340dcee67f8fbb43e3aca7095c44861b888bce7cae1ca96374e8e993fcd4cfbf5ef482b804106d017d582723473b12adebdc136fbd40b00d642e7fd0c88e5b3ad36b39b807fc5c4f40178318ba682d5b26c9dce39e4672406b1c92b80b390f0326656444aa616c663ac39a5a82215ae784a3f0a01c05146140098a98d5c9cf0015ad791dfd48857b25f082eb6b22d89ad3a434ceb1e3f44d6b7d81ec12e2a8753559ea13de01cf7ada2699596203d14d2323c3015ac0bb948f1d6158922358d5bb3392f0a0842d79f2320eae6003616c63806bde99a45fad3d6cc0e4965469cf5118256b1ee049d7d398e863959878bc6d1adee5456c8a0135e0ff118f8f192d84e93e42ae9d3831522d5fa1fa65467a84c207b06fb66df9e7ce9d6d058c8e426705370d1564159a9ff8008ac239a73a9313feadbdae2a54bbd9ea472b5ca9f033c46c46119440bffeeca85081f94b214b69a3f64d1cbd82e2d44c58a9f4f031343743430dd4eaff2908067ef30b12fe24d5fcfe798577cb590afdfe632167973848ea10986f63cdeb2914d9cab14434c2400320083ea62ab529ea8a3bdcb48fe741c4ee6013029d7ab0e6ef3b2018b5255c5802805e9ee1e1ba40551eb7abf5126794a0cf87c9bfa7bc6a4b247ed3a7d266ca7eb731af1c98d9e0f4b365f03225a8182a6843d23f2b139aba2fd3bd7a72b6210d64484e7a2a23b5df30a7cb605de1c941f778f80961853e00bef583ee941f79c6ed1468c742662ec7ce6237096ae3a1e8cc3bc42ac31ec427e3af4ea5a355594792fcb693410b0a9f4b5467f683b90cbc35af7b601f60c6e1acd003fcf1841514dd57c6628c6c093b61f460fa755ea7ccf4c10c8ed88872dcc697fb3971e4c0f683d6a9758ea0eaff74d06c71647e59a418fce529d916a236d006011a4a7ed5ac5d494093c66ed378b230abcbc7a805d45aec33a552a0118313ef189c1d2a97572ec7516465c660bac060f45cc21d2b2882edbf36c83a22579ab2f958ab1a4b510b6dc9a478b3ca95e6fdb1138a57fcb0b3a387894072cab46753fa3543e28b2720b544c2a6fcf737ca0978963768f7fa498eb3dd6f177976c8b465438a0c9bcaf1af2789ca1787d623018a461f70687cafc4dfbba97778989012ebe1e7dea188c274bb454001da9be987c1b651c56f01bf50b7e49abca086c5770ff586b927291b67eca844ad9f523f1008b05d14542206646da77204b999afe2351a6cdcb08b50fbe4fa2d8b5d84ffae31e495d694bf248763c6a7a028e9883cc2a53cf62a2bf22fba16d3d6a8466f707107bbb9e1e7ff0c5c94f7e46ab148971b8ee2b8cb36faad4b63100bb6ed1ecf93e49e5ce419beb13533ef161913b8e657ff3c9c43da07cee679e77d190535267805851c9522f86f09aaf4919dab212a520fcef3ac621f7159cb1c6157689b536a4da9f766a71030ec5a513bbf1fe3656b53cadc6233e519e1e1d79a6257138b0c1c068680a9d6fa881dcf740f37e60a2fa95eebfd090a2afa929c930b69232a23b5c6bf93d419a8135d27cde5e5bcf8ccf24aac8fde9ab1e0663920277876366c179e60609615301dbcca487778607a4a179700c31e1749372b0a6f8dfc5309ccec1bf0d29425075f28e6cae7e32251bc89ac1ca3572901cac1c5915151c6b67e06ed234725c98b3df4e7e0c27b9e3ea59461664d0ad6e67fc5df815379a6b88f1889fb8b5f8bf338af5e846fad7510404928b335e8fd00a50464552eef3381984f0ee65d9ee6f37696dffb937116e7eacd39c133d46b8d9ac9e6e4c3301f098d5c90d19159204b8e33524954924e6e35c5af4b3d8f47284c143185debc63cf543251f6d0a45cfef84e2916fe7788f91cbd685c040e864427754cf1856dd7d6312c715584d036cbc9e529df8f78b58dccf47848a64a72813295df735af681bb848d2ee7ac85a5a6790af921d6fd8a3839702aec6958a838a2e5d830db461fc27970f56a9ff6cbff5e61913bf2b5e0fd30e35a17a49d52baebfdc09f8ab9274f461f497bb6eba4d225f1b27aad56b34d17e28b709217cb7db9029f59d4d15bce65983f52243fd1471061030e591eaff0a96c9107120d808f81aa76ec746d70c49d35d626254fca62c34f5558a688487d3cf19a529b96cce46c58261c1a58b16b726ebe0fb44e571cf49c5ffd53867d2c446d200c92f1d2b2f792627f3c1991012b2f5a01fec87c244ec5393d3f7699bace9b59872f514a9a9c2b37f22282083a6708e497137d0a5619ea7cf3a64b56645fad3f0134acf724dade07e42cf2222b390c05720d6d0a46ed6c0ae5b09f556bd1fb713dc70c4b7c075e49eb5c54da3622d652bc72d99871631fe10b2e4c6e2396cacff617e91d8c3eb05bf9a73c65069bf2293ccce31ab2d9c57ac028b246dfa1323de5b0f35429d313a760f956a5929c82600b02ab660acee4a0968f55a822b6967ac6253f0d880fe23dc5d243bcf3ec2dd112716798c51065c67ef965d46e9bb79806134e1aff2a839dd02fbe86d58bf46e245884b52ed46378c1c058a897e4bfdc8336814033dabc5bb8af792ec057b52fba2bdf05027bd0489daeaeeaa9ac11aa0aed9f390dfac6761eef6fcafcc18c3df59d70e6e1b975e3974d1af22920d3deab24f731ba74c199382151ffb9fc03de46fb77a68fa88e797f301bc5ff6fffb8c748ef15dc2aa02afbc66818e6eeb14c37e114cbae2476962dbcd66a9d8807f71f60297e8ca89eb7e23e0157da7f697d426a748adafab0bab1637dd3b0b553f732bdbd274aea1dc9a2cc2b8eae52495801df6ebfb4b63f271b9d309f3242c4900e494c1ed3d141f612713bff316c6968a0199a43549b2deb429de218ef86902048e1b5cc2944abc4c63eef25c2ba1bcb680ee3b7d78c7d6168973a32df5a428bd499244199c66a91ee9ee068263fa6462ba799a8752e723be31c45b23e6e40c73dad314f2eea937a635769f7da508f1ba00367264748cb68a5a203afbf3b4469045b9640a119101e242e7db682e77c367093b39bd9aa0f3be17eb095d4f45400a552141777ba522caddeb0a8aadda77a41b920c3561f9a28f043436c2dde10745e4ce00b74741aa44c94b67e612a8423305440bb54a067c35820066773643bd2655442e291b085d97f65e1ea864aff1093a7eec6eeba2242f82d0b9653f84179b6b6cfa1efab84eb403d83e2a261d31db7dadb0814fbe4fa64664eb38519571639ef2ebca2041324471a6e631105f338c23497cea88cc4426d64709ba2ead38d69931b32da2ab74139855d33247d9dbaa8c9d351ce3ad857bd1458e44583759d3fb50d16da62d508dbec3072dc92154a91be59096668a4102f6f09dd9199e4bd9dd15f04b2d9258737602584f3b7cfaf4fa1ffef459870e874aa52436ef1bec08e6fe2566b07c191fab2c019eff5191b3acd8813ee3551fea999863db20b5f894b5553b34f85fc9bbba1a8a490e39201073584fc4eed9873fb85c011fb80ffd5d7d6ece18d878ac0d565db715f84a809e2ffc574a750e650bfe2b26f855cdfb3b6fdc08952732e78e64c697cf041bd00d50bba26751106cf581dbb1bf9f69f05e9fcaedbcff378cd13ebfc4818fa10a86fb1b7112a15ddd19a5d1f765f764259f44ec92df0d18ca9463deb4bc5694f070c39d3e581b853f4ada70a353c00d697b684a177ec7e4254f2a497e45aca8eae11e706c763a5d2010bc9c53b02466dd6ea4df68bb03608aa6328703d0caf9b4232f089bd76c188fbe4421396082f4230c183af89e58981954432d444c8a345a463ba21cdfd067542e8ca671587e422431a2d581a7432f711acdc9250ca406da4e20ba8b560e4d2b50ff7942a5a2f17aeb66ccecbc51bd599efbf63605fb8df38300914f811c2fb519a1a182427bf9a1492974d22189edce32ac2fcd8e08572b78401b46753f0af5a9501342b5f73f4bda4ad8d6a1b8bb1c76c798206519de02b5c3593dcd1faf046be35d54ea47e6914d01bd4aa4bdaed451d0894a8c2ebb99ad0b174eec3e194e55dc2e5b2b464bcd05662c9040b61316feb3f00203879d90b06e05373433e85ab8a3abde181b123c625b2a7db1f2e496cd6d8d5d7173ed37ab833d4d8172d29efe1e8226f6907327f6f4b51876438bff7d61a121706f78954cb01adbdb3308a6b6c3db41282f70c9d3892c869dff43a3e91561b199344068f7385b08917c67a42653dee7510fd4ed25954ac82c1f2261f9e484dc70b525392a64dd4c3e260b8490f8207f7939e45d42ab8764e78a8d222e9d8f9dbe78ea57921b51b3e1828f66a1c6cae8393a159a7c705b43f3b479bfbc0884d432a45d7c158f2c59c40b1584b7e85bc2b42e0cad3467c784a57038c89cfe69d7bc99fe1b6be71e024844a2ca4016e73150a25f67861ca23d2c92ba0b6112218e9f5fdebb547c933843b9c7b6a9899179d2291850a40e7e88076d9f7be3ad8e75b42da4411831fc8c7c786b4c0076c26082a44b9bdf4683ea83d88ddf48028b1888ce18c9e1bccb9bd483c4a07b3f311788f3c7812111e63bd498cc0bc4dbc588a32ab218d8074c54fdbc6e9cfaf07aeaa0032864f0bb7c101424c504bdc332838642edb67b2d04a1c9ee10ea60a3e32fe51b5b7376de42f078b1ffebfa48378b70407d808a54b835f188f4be8d90cb962a2efc34855d66b93167828576ee54cf895a068edba81f8b46281250e09e462a7c4565e315590ec525ccf8df45cf9e55c6b1befeb1de10117408c3222ecc6508150b7ff4207b90e3d67ef0719749ece71440eca79f2af172738795e0267d199f76e81daaa19569323b64d86b4aedac7be78771576c429fd2ce8c86f338234c371499603bb4605a808783acbc38c4929eb5adc22ec3e177b3e4ad89f6bbf9b63e6e2d9d1f10b9eb0432fe428672ca5db0d7948d9dd36314ed7e0645c9e05d0e7940f2a748061bbd0ebb23d0c032aa9e01b13a099752d9973c9209963112a999e2830abc2bfcf2e9448a2618218cb9cb9694add0cb852fa13e86f7748519bea86fb98f7e8714224220a0d8cc7632c299ad6e1518037a6bd83266560f546d43c14a98e59d332dcc409f0d131f679c8708ec41eee3a57621bc9b1e78a5daf1e4f1816f7ce68692581b3accb433bbac62b18c6d92ee31c5b904db62af3dfe1ecb541eeebd1fb06e500e3db1e03901df7514447eaebac56bf0577039e89807594c0bb5879e2d87a82502101c4c46043582343149bf9d062c35fe190f329be6fca881252623f451d823f7e6dc6d96cc2f202a5e17bf8147584e82ec11acde393672cec0c7b60a9a0b86e99fafce1d61e8f3c6e11cdf109ce4b06e2491861feee21e71143c9a82730c81ebf045ac5aefb6d1748112203af1aeed4c06a289381feafcbea4a602f65371d4bb91920baaf105b10ec1d8aed012e98554783fb24f8c3e757b89da60de9cde2500841ba217fdf43d39ec66041097b6e84c20090c23860bb284a02660f080c53c13b9584bd1cac9e3dcae9d051a92704dd5adafe089d0b40bb7fbc537f892dfef6f22df8200a55a9278a93339c448adb0fcd6f190ebb814353b471d6293abdc31dd88d6008a53d69347ee9e411a10ed2a5b322aa0322e0cc1acd92d0c6d5a5bd3e5208cc1fa0b487b6fa2225ba454b2dfcb8e83dac4183f5b6311c96f53341d237bb9e993b212bb6170712ef5a21cbd1990c4fb675aa1c5077808ffc518f2a16dc253e1ca65a96c3170f338939c54f5c65728e7a608e41fc74c75c8c44ddf06cfe3dd4844a2b3a9610c765145810f5fde301700b690fbc4a9c122c01308925bb33a89dc237fb8e985d19370aa7fb5f54e94c5220f4fa297a8e8824aa41ee8bb675e9be80a66d3451db297ab9b4d0b6e973ecae4b014662e60df65b5ebe3e565af545a01b282d41e803b828a7bba8f4202a18c22531fbdd153ef08e99f8a24f433d0b024ad59213bf1d5150c849004b3aff41df0ec4a10f9a3cf213476a81456fc0031a8d37219d185878a6f90d0ce7b0193aa3e2d12074e16f4a214d70ca2142c85f50059f41a30e04fb1e7b988b2fa871969d3197dce3d0d47773d179d3a5f856f795c0d61cde365c34699bb2c673c346b2d75296b2e471edb09164e42a25e7a4b3564691669a6c585bfffba718796d0f64033488ee54b7c902375c7044aeb3d77e58f50e46faab5ee720acc6c60107529bc08117d48207f40773b5553e56959e34fe01640854564bd6da721ec652e9888ee24af81bbd4d0ca6d5278bffb798cd0c97e6bfdf922dde75de337275437f5f1bd733ceb98374e4f83900bdef5cd09063cbd02bcd4c0c385174b05058a116a2a0bc155ded02123a647b9f21044cecd3960424d70a66aef4b36bf408b37f49d00a728f5f7f4350b71272e36667130e789d27aba6b66f6e37a940b4d5a683a6a9716a123262f55d2116da74309515f25766a5473ea08ed1b8b1e417c80be254402a8e44d8ce8a96cac1207408847c547aa74114b483a682771ce5f9330424dbf8da2e2b306a8a31ceb4428272aa93df0b069bbb8cc7aa8cc2b6d94877624c59096111581540161b73998ebcad9ed0935bb06f2927a337dd763a1d95c2c4bb8c656a86460705594c6c0fc523c6a7829dd432e5e82dfbc1b0c4c858da77bd50833afe2bace65ea28dd3b5cf70f3a63dd2003201082f40323e9d103b85542266ce1da1bca00413820bbb0182599af116e00896a8a7cdf36d15c997fc03a1ab301ee2b6daf3c0a55e5f88df85989a1ec298442fdbd03157689aa7df5b29cc5b32c4502d890387c900888887d23af1e1b07dc0d4e8ef180158fff5f89d8b4d093a6aed2f3992a63e820fd3657f500b403dc7fe7b4a48bb97bd7e142d6dcd614cd67fea9b120fc57beee57136c945991c931ca9c4ec57c30affa2bce01f02e6fc34cb83c945b01faebb4c929a0cf519b441fc1870997b319ffbf6cd2884e2dd3734bae1e3ab2937b1a2a43c36c5e24850e446d3447df4d214d2aa8a29e3cf55f71e4d2742bd0919d0dcd4ee9af06b717bd71aa657e8075e0fc440706846812e0a0bc351bbac3fbce92331d37c2bb230825e880282a5aeff880f213dd821db2b37b6fb485e16872ea5190e1548df147de29c9d72f0c178944cdf86ff14908109fb300b1d57f78487dabeb62137c3fb6b254b2f1bbb1ba60bb8e5462c3d0e0f68c16fde1f807b0800f254b42a9d47b9e1be9f32912d149cc3320f6e6e69d52b19fb0d92d23c9fce91f1699a603e82497f530c2a5255e351154e91ad07bd0a683558ca681b9b874512c12ec7b3d2be9d75746a14376f59b6df816bb8dfc7fd7bec4ef79f8ee93b1bd2890fc6fc8da7dc6fe8fbf737735ac834ba99798bbc838e25506c79d048f9f656c7ca29496e7b6a816054a0ae46858ac9dbc89d97f967311540ad71508954d4d90e49c529d4cb3065f08000e747c88ed9db4a4ede9f042b2640698e3d2ec24b13", + "0x3a636f6465": "0x52bc537646db8e0528b52ffd0058540d061e1308c819541050e938e9005f822fc197252fa2ed5713e0ba46c46f094c0fe2307326fb057d60bbce8bdfcd175f1feb2bc7604d3068f26910799b2f5ebdfc5148bbff93d098c88f368b8ee8661e889a5a2344ad1142f6de72cbb41dfe175118bdb120c23497929fdc3aea901fbf5f6ec5254f62bd59323b7e76fc0f30180c36cf35e4cfafa724fca1e767a5f2247e3bd43a5ec62ddc3617c3ae39462e821cf3b8db150a63cb17f9629075e3b88be0ec6e85aac4324d45eb2b34294e761194ed5dc9ba317da543ad5095086b2a483a9ebf1e0d13163d251face33b2511d6f11c590cb7bd712be4d16c7cfcf8507e99b5e724e8c2c797dfaf4703ff89ac1bb3f6437c14e300b805fae263731bf4f1f773e356fc9ec166e38be7cb73ec2591317a0538ea782e76128cbd5eac1bb3e28798c16556fc11472adcee845f6b99156ecd0fb7de2f032df7f0f7dc027dd963731bf4711b91be8d0591456f2c88a40e53cd6fa13706041acd5e92a22f7e63b0a4e62fb7b6f327b7b2f3376e6df339f6926c75a34a0145c098b59d9d87028ee8b23edbd12bc05167e7629781db1b189b8b5e762e038b62678f1e95249359f34abece1e3d19b6b3af97649915761d3fc41cb71eade151d36f60b8f5f60c0cb32fb3b60fc90d0c6787f345b2b5af97847e88396e3d59c357cb6f60f8de9e81e1326b7bb8cc0a7fe8ede1322b9cd2dbc3eccbac9087de3e2425a8552aaf96cfc0ed0d0c717a9e8b9d066e67e0f67a34cc961fe221a62015d9f2135c66c5af9744d6c9acf8211ee2211ee2211ee2dde1fae4ebd539d2a23482db0b7c1b03c28b0ebfe6b3b81576cde7afb815b29acf07c2add8fc8f5b1b03c28ae6db708b9bbf0c145d214ef3b98d59be8d01a1456f875ff359dc0abbe6f357dc0a59cde703e1566cfec7ad8d016145f36db8c5cd5f068aae10a7f9eb29e00810accff61077dcdaf37787eb9321bd3a4731c61170bb13bef9dc067ddc027dcbacf06bbefc7a49e4a307c30f30180c8896e7b85b6ec9ef27b7e2f7eb6dcce20fb1043b66f15b5f68d3fcf8f9706b3e67c3ad65d69ebfe2566c3e0eb7e4f95cec56dcdae6af273fc4433cc12b396de5a863bd59b275fcd6b1de2c899f8f9fb528b6ac9359fbf592c41ac68e1fe221de1dae4fdeab7324630cc3ed05be8dc1c674b8f5fee3d6c660b0de6fdcda184c4cef3b6ec5de2f03ad2bb4e9fdee6c7df25e9da31891702be4dbc7af895b6ec5de4f6e6defb9d4722bf67eb9c50fb7de4f6e6defb9d4722bf67eb9c50fb7de4f6ec5de73a9e5d6f67eb9c50fb7de4f6ec5efb9e8258975a34a0145c098b5cde7a18023baaccf3617bb08c65e8fcf71b7ab5200116698b52dcfa3d9f8e6e5e3a59724d68d2a05140163d6365f82cb2c794e76118ccd1e7fbd599759e1d6f243bc5e92c92cf9211ee2211ee2e815e0a8f9eb25891fe2213e8a312281db9df02dcf6dd0c72dd0b7cc0abf968f5f2f497cf460f801068301d1f11c77cbadf8fde4167fbfdec62cf9218e60c72cf9d617dab43c7f3edc5a9eb3e1d6326b2fbfe2566c791c6ec5cb73b15b716b5b7ebdf8211ee2095ec9692b47cdf566c9d6fcadb9de2ce1cff3672d8a1deb64d67e3d25f15c437efc100ff1eec8fae4bd3a471ce30db8dd541db39659e1aae3b9de186c4bdb302b7e71b8dd541db39659e1aae3696f0c066b1b66c52f0ec7edaa14408419666d2fb3f6eb2599ccda0ff1e270cb5cd117bf315852efd7e356e88bdfafa9631216860f4edd83ce41abd13a68327a072da6cbe8a5f6a2c7e82c9a8aaea245d04a7d45b3a09f68271a8a5e419ba051d056b414ad82fed253f408da4b9fa053d04d74145d8266a2b168120c1d61480a4346186ac1d00986a0188a62688a2129869e184a1a126208690836c4652888a12c43450c6d1902620889212286b40c393134041235903c61c805487c80240b243d40f2c41009864680440b245420790112162099029215201933c4c51013434b2081028919244e2079634889a118209102923343251892c1501743490c79602836d4012450401285a12c5e38c10b2678a18a17ac7881042f3cf102140190c20b1d7821891738f0c2085ed8f2c2102f20bd20c40b5c0270e6052d2f30f142065e38e2852502308517b2bc1002a12d2f80c0881823608cc8c0481746b83012331203235b18818191258c28612404464060a48b910f18f180910e1849c2080e8cdcc0081246928cb4c048164658606405465460040b23293042032333307285112b8c90c04815464660a40446bc18a1c2c81446a430128511288c3c61c409234a469a30c284111118d18091238c64c04811468c30328411242129084141e80da129084541880d21324241105282d018a11e080d4148084263082141e8084261087d21048690184246106a430808425d08c940088c9009845820c485d017a19810164572504409459650240945d628f28322658a04a188108a00a108128ab051640845d428924611342217518c226414b141911914b9a248098a3051a489221a28e244101482a280248a201b048d0962232808414a415d044111a44610164132080a139482201f04d12068064160826a105446d00e82a20872220809413a08ca411018414b41610489116482a02f415904b1200809a02858420049517900a4045406680aa0250041f11346eb07401c58150174c40f095400c12a06ab180f183c39e02102cf10789cf003e907179e1ef0d48007053c38e0718327093c25e07901cf183c51e0c182c74c4b07ad25211bf0344128072d295046402101750454191796c0c21a3f63fce8c00525fcc8e2c21178622eb481da82c81b2e3c41c409750d17602e34f1d1c085215c08c20511b82044f5810b4bb8805481e08216224aa8648834a10ac10522883cc185225c30c28524178e28f2c505257e3ef04345902578967852306bd03242cb0700d0004bcb4f976f8c1f2454434841e1a7053f4a081102644388078418d1e241ab8d1c6bc82708f940d0195349c816211a10da819023841421444b3542103041dc087283204a0862031e292062e6071541ba207284202fe081823ac6852d41b8f831c50f2f404c0419230810829011b425480c809a20b20422653e190429838514e48b54526a0341c0d049d221426708f0043a45e820059142903782e800080aac20829c2088143f26e0e1e2c7169e323e4af041c20f08843ec003854f0e7cc4f0012386e1f3850f0e7c6ea093e54710d38a59029f297ca41842021f0e0029021022107183e7083fb4b0b0041694d0eac124830519f820a31261853456f8c1102b2a1b1f1741b4f8baf8624162f5072ba011248b6f065f0d5618c3e2c21a6285355cf8000e332b90b1c2182c2282b4aca0031c4ec0e1068e25e068c20a2c5841052b60b1c209523be811420f1b3d6bf4008195a5e707ab2d5a68f08029728691345a40c287831f23f8d1c68f2a3e227466a012824e0c8428810a03480f524008d9006a0c9d1da890e573e2a7043a63a07290030837425c042e2041478c33f121015103e5858e18214ba496a013068f1428307472a0f3058a0b14193a660849ea59d29141ca8c1e3474702064089d1a0871e21b42870b214a3a6ae4f0018f255065f48891a30729188f171e12a49c90638c8e0d3e2656374829e1a70a211950b1117482225d8474d14123a5861134844cc183c42304cf123c43f06c8027032b9cc163c40a3950010c0f123f849848b49cd032f393c50f172a28a1420882941094041e29a800fb89e2a7091e312a00a113849d2738072fa080c9603478d0688520880c74cef0193a3dd04943e70c1d1ee894a143868e0e749674c0d0f142e7063a617468a0f3021d30421ed081818e163a2ea8661089029129d424fc90c2052e3a42d42054346a11826c51d3f001061124b890258819d5093a5b884881c8997a847a860e103969d428e49c51cfe488a96fe4f0a04a21c70c1d580e1a750a150a393dc8514327091d0ee87840a7034156509f20c484da84ca843a835a4695811441ce167507f104750c1f2da82ea82da85dea07aa076a524522080caa0682b8808e01ae01022107991c43e05923958194065e30e22ae019806f0cbd0146017c0268066402e8469035c02404498347093c4cc821424e16392ff021c60520829ce1c38cda868f307c90f1d1031f3bf021860f1df858f2a1860f367cac71b3e5468b0f20f818828f347c10c1c70f7c8ca1f162b6e18307467c80030a3e5cc0e30394192d245011f858c1b7850f27703081c70644924084093dcce078428f347892702841880b585b70a0c079c247042a984027081e58f058010f2b8a3cb182014f153c3c3064044143f06c2124043c2ce03963c71ab3055c021e2b8034b083044259fca000350321483a2dd0d902e502941642885829b10a010b3d70818c1026503400fa802a08a830281c0829037503d45210255a6c14f900aa8b16115035f844e04211827c40052826098480691d61c7085a53b4d270c1084536d073860e135488828519804140f1a025a615041e18fc8015f1800b43f09941cf98a012b4cc407db1a30a1f6078be1072049e32563af8b050418a4f0539d40032a2550625c6f7448f194538803a83052f78beb48a10c4033c34d089f98801cf0a7c6cd11a426b8d9f255a40a061680d641142a490460ca922c719201200788206073436a0a901cd0c50b11f1c4c333c4e309ff0c1802788ef053c598814a18a09c2021e26e0016285c42a690531448cf06941a48d1578b0eac203e3f1658532563063c5019512aa107c6204694155a30e8105848f1c1081828f327c8ce1e38b0f4ced4145c21783cf8c8f8ccf8bef8c0f8d2f8c55078a8cf9be586d60e5812245f896561f5825f1811157f025a1880f8af480474b1129725890b3822152f0bcc1d3021514aa27544ea894544da89810c225f584202f3c64f068d11ad31202cf09789ef0a382203482c4f084d152a3452648972244f894f840f07529e2a59679210531073eda78a10924357081083d6050628286904283c708423f0842c19fd013868fa4a0275464503040bde0052780422089288244d099941b2b2e90d840a806b209159c10c281540f68085a67f04c1174c52a8c1ba41f227862b09a0190078a74e0e70b214de4c47eae6829c132008b8002934a4308172a3ca142132a28adba102ac20c41cb891f1b08492375868f2c7ec2f08c19c2e2678a1f2b86ae98492f7409ea814ce24acc0cb85086b9985c5a55ac64c0c3c62a8c0a5d540862688bd5172b1b04a9c0c80f8468f0a3082148a06c303520991082042439e03933a484a4053c64864c502489151873073c66e8fce0c7892240f020e167053f60a06200d401214fbc80444e0d82aa081a411011281df0986045831f303c9410d281a0229048114404432f08ca80500764077e66200404487080dac150133a63e6153f2ce091411130b80beac40f0d907c21048a1734304df033022149acc07c8919048329a22444cc0b53acbc102202236adc3c010eb1c2811023ac8cf879c190164243042d41052682489033032430f8d1e2c70b940c7e4280440c242e688901444c91a4202e48a658d5e06749880c90a031e4e587091d200cc160471143219847f478a1e38322301f12f85ce163854f1540ca40e245881a42a210d2864e179405130a730a14080a9b676810f38d1905fa654a8166092286e60bca058dd118b89084173e20848a1c19d02d80940002c18f0c78a2f851e2e9426805422ef8f122d482940e84d0f801c48f144265f8504a8991c3450e0d72c0e4d8a08523f050f1d3c5cf133f2910d2418b8c1f43f08c8047053f30f8d9e227c623841f46acb4f889c18f0b7ebef064f153039e19fc40c1a3c68f087e4ef07383203378c204112148084145085a419011a9314156041d91d345912a5e4812f2414e18540b788a60042674c6678b10117eb0e0e1c10b5f5059a888b03ab303881d30006c00001c08a2250897205b88c4887441840b16c06061898530762cedc8c10e318884217203223658018a15a458218aaa4415415da29aa07ef94cf09de0fbb283cc0e22ec18820a6178005104043c82f834f025ad0066051aac30838f042a7ca102182b7460850face00115622a74a10217428620a4084288507150bfa85e0c616288d290265a00a385a516c200bf00c300c1b801c18d123721103286901d0821a34709134ccf125a88410b5cb4104b4de183a5ce083933048821b016d66821082db041640744c41029c327083e647c84e0f3049f28f840017442a2007c0284c18c02dc6226e1d3850f181f19ec18b3c3c54e173b31d00ab004e0152d1461d5849513401e80678066ec88c18ed88e2d7686d8296287081e3178aee099024f10785cc0b3031e28f0fc8007083c3ae0b9014f1a3f88e0698367093c5e0885119a22688d2032738b900a261bd306431b9861cca529c60c33bb784189223a28e2c5ac628e607a1112420804930373035388893487104a825019d904e903e98664824443fe400a412a410641f64002418a91652412e419d20cd98654433a4192916bc82448366411a41939461a411e41f2400e41a621972089506449880c59027985549220904ec8276408e412720a49858c427a911f9052c82e120aa984f440113124103288d8059fe129b014f80d36023381dd6036f8082c045e0297e12230190e02278189c0436025701b8c84173cc038601d7018fc057bc13760308a84c151700c380601f6c22a602a9805bc82225ff009f8056c02c682afe02a780b4e014fc1246017b0146c05b78047c02828b283175410651081107f108310c1884b4422e210718ca883095cc921aac0872844e4126115f8a189952a0f70000e1250800d09880106041ca0061a6658420025321069e167c80b0100400cc20b828bbd710719134b222b4d26c0644a13221e9830e1a2d4210a111326271f9f1c15e800c5890f13b8c9c162898a9a1055c921869d9c140cc9410114284d728002a589004ec0431105a21041f9b244443b309152c4a488070a3821aa404f8e09d60a14274d8a8874604244b4c38f9c12ac941da2386162812a443e5061e2644a174521eac1024d6a78ce154b94431429519834c9218a1403e4d03d72acd0414a0e443ae4e49060ad5880e889150b102d4900985385152703683067042ee478d9c9a1626972a6582996871ca44c21bac98962abf84001273b449192031327539a68024d5c3872a0f891f344508e13ab831326454456aaf890c38e1ca5b542e484024c9c4ce926537488d2a44a0c3e729a28fa8128ca4e0e1316287252450a0f453e34c9c911c15ab14204a547ce1235394a84608ba2f8202507263b342182822307045ba5871e7a982195d345859c0fac0e445128e0c44a141f98e420e58a131fa810b5723cb0454456987460ad38b162811d888826c0c4c994b6c00e4444ae1c39496c911529509854913285a80a0776072952aa4c6132c5090f56aa1045a980142616207a02e66c60ad10f160a509142b4c7420720265ca9426517cc8c94162ad1015f930c58a131d72e424d51c0d2c5195294c88aa38f1810a5115265676b832452727035b1485a807a2a226455676b832859573c45a212a9272850993285270728c581eac34e181890526c0a4082b5088a24469c2430e4ca6f4508507263a44f141ca04a23821a2288a941c9850e9418721d64a0f4daa3499c2a48a14a495b2038f1c21d64a5114a22b44395c96a8a8890e4e7488d2240720395b9648072939f4c8d1b255a4ec6085c84a96b552e4c394221fa4f0e404d1830f56ac34512107886d52d444072651a438d181a8c88a132b5588a6fcc881ad15a22a52726062812227509c4ca00914274dae34b98f336b658a0f52aa5080890f1f53582b55a41459912243932a4d6a58f990c256c0c994ae42f4a48a1406d000fa786389887c20f2e10036e84044010a34b181051f51d82645527ca0c2c44a14264ea63405a23879d2a42801383ea0b0528a983c61897288d2044a9309309152c4c44a51142752767c98592b3a54695201a22a4c2810c5890e5188a6307132a5ad409122a58628529c143589e2a4072906a83e9cb0569ee440c4430e4d582b455188aa10f110c5c97d30218a931d6e7cb8b13938b112c54995a21f88985800ca94294d985421d2018a131f5c4f729002c585e363096b85870f256c1326383e92b03d306952d4448726454433a87c94b98013284d9c143989e204870f24ec931ca440990013a2221f7220fa8188c6c711b68a1401741b89a04ca04951141f76605294035115273a4471c284c98e19704ca17d21e388287a8fb88dc1601d8fe48ecccbe2658953a2367570361c9c6dd3c1d9b66ddb984e9a6db67c62668e94329572aec44199299dcc534a69c3ccbc316e8cbbbc91ee4e9632ca8d4b296566a6bb9b9cbb94e7d2dd38ee4d5c6daea489579bd9e4ac9392661acb93c652ca9394cc268d4eb9f4a3cb1f4fc99327dd9d3c79eeee049a508e73755667714829e54637ba946e31524a4d1ba554a6b4a5da04b5b92a497160c964aea675734e4955544a2a699492b2a473ca18bb9daa8ed967b7ca65cdc98c9200b310639494258d546ab31bc272638e41987723c0922c519297e54e6d71d089929287e70a524aa6a66566a9c91865a7824077dab873eea472b59573abdbf2d87d00b3a4da7633959adcf1d464c7546adaa63ac99407903959f260964c1d207969ec32a9c98d9b940db8214ac92ba92771ec763491294b962629358d6bb4c9cbccbb5152aaa2ecc93853cc92535288fc4e3b94019399b56e4ff3f49d16703a514fdbe44ee66e519379521959c3c13fd68615b0492997999929534a29cf9e7657ceb9bbcd39b739a3d4b4a9f1b6bb4d29e5f4a494524a1a66d624a56b434d0d955ac709c0a194fea09e4480644f4e8d0fb03f9ec73548a621ca3925ff0c611b96924e969272dc9d9e67e35596d5c6f33c03c49a1a49d7666d3c0f07087a2849a5dc4d63c92c375bdee49c34d249299d9c511a59f20c426847a746299d944a0aeef6581e91ce2092f2ae941a53a65372645e9e3c234f9edb4a161740d2c8949952ca319d94d21825dd6c728aeea4cc9a94332ea13c270e3997f2eedc9697256f6a575bde5d4925a574521c934e9f3929a59c993893b4d3648a67c63b774a6dca5d6d93bc0460254c2365197fa4a6e4c98b8399e6b8d965cea2b632f2025919a39492e2c8c19429cd6edc3565d9eeae2639721677974dcb6c32994c6bda35adc9c4cb2b354dfb989775ac8ed52179994a2a7923f326996764a64b99255d96a8ddb18317c53b98e58e1dbc2c70e48f23c78f25cfb81c254f2965a452d33466c9434aa94d9eda5cd6e69474ae9492512bc3c648a5ec2265d6a4a4b4eb54cc1d65eeb8e378a2db89c66da3943b1983a6ed524a25a592eeae64de9dcbddeef2ee6429e5943c254f2979ae9c92275366661824cb6d37c6dd8e57ca8e478c34d24d8b7105f9ff1b9d52ce69a3699ac633351b4d4ba269da00a63605a031338d52b28cbbbb32ee4ac9947799eed24957ee6e94bcccd44577761c378ecc94a9dc58ca4925f3e4c99ab6946edc297929a573cedd49174597eef25c66deb97432f3dc5d9e9a26792eed96e9b26439996564e6aedb9d93796ea4cbbcbbcc74e9b6514a7729a5bbcc734e6669c351ca96cc1c99797799254b5e39a5a4cc2ca5643a44a5ccd1344a376da3cc2a243d2fe4a8664e007a7226ddb64d45e9ea083522448bc46d53c52d6e5145378d529992945219a35c5e4a996e94d2549026a726e9dca4a4bb94f2524ae9c73393737653ce49b7f3a49452d28d9939e32929dda5dcb1ee42e658b64015293d10f59001e940548548872a5298b45c000091932a452bc41e767f88aaec90831428509ae0dc4ce9a1499115a21e9c14ddc7047cb0d2436485490f527488d2a44a455961b5582ee810a50913a22a4da6f42085c807a5490e52a0ac609252d4440727509a5c616245a7072745517ca85275ec50e4430f221e9814457152650a931cac38e90187c80f1580a8f0a34607284e78c8814911141f9aec40a443cf0f443a4471c2248a93263ce4b0c30e5288b47afc20a502453e9e34c92107a2272d1700f01c4100f8610200a2274da04c800905a238e1c14a131e5ea54991951f35567600408a942a3c9ee4d0640250a048a9b2420b4d88aaf0f041f48449d10f44517cf82822a2c08e1c45569cfc4084934971529443132b519a54296252e4a4871ea4b0545800fce06407a22a53aa8efd69420425879b9afd894234654a132644146852454a91151c00e800200a059c580169f6c78a05889e30c9c1099409f830855545051d88ac5821aa32a507293900710b802a4457a4e44054e5e749cb05004cc981c80a901d0bece0a40ad1159d223f2eb800001d54e84154d4a40a5114220a30696245871c889848299a62812a39e898a0105d2182c2e487263de45c89422451fbc3248a142756aa105d61420129509850208a130a50400a1426453f10edb81285480e49b980579b46d2c8c8c8e884c366a6a3686474b47538ec91917674448d4cd2c3e1281e9952464653e270148f5e47f275344d381cc523a3232323898351343a3a9246464646469ad1d1d1d1e4705823a3a3cdc8c8e848ce2323a323a3a368148f1887353232323aa23818c5c5618d8c38e270148d220e6b64746464b446468c83513c8a381c45a3233ed2240e6b6494e160148fe2913ca238ece270148f8ef868e2b047474712873d3a621c8ee251c4618f220e39643888bb1b7bb0d2640352203595545fd9b268645b86dc6166f4c573d1c3f27171c16030d14b4265c2603b666641d1c8d6d868249241a3f71c81d6b53f452313d60bc3a2d1f1dc6adbb66d196f9b8cdb4659a8f86c8c1c32465ef075534411cfc789466223e1f602df3eec3a7e875ba1101b6e853b1defa3e33b301dffed4e9c010505d71b93a24bdbe0702b81728cf0a50d24b634c18b0eb896d8c0075e6030c517d80c5cfbfd67d1f7718ba58035c7b6a9f2c56f6c29e0766c2e7a4926b3e29935cfd5f0ad7de31a16c98e37dd865b5cc665a7530db3d3e5b90c8ccd9dc06556f462e8d19359a66745b24fe7226f94a80cdce68084381d2f8ff375aca1c6c91835be09dc9014519be6ec1194de52d5f4765375ccda6196bcf6334bab0b2e18c6a61257f69e3b5abfcee68dc3adb73c90157ab8d3a748a3e0f66015163666f16d8c044b7484f5ee4e1861cde78094f89e4818f7c6aa78a363c7b3b724c27a6b18612d93cc2f7865f67e824abede4b303c6a397fa3e4d4b35249f57ecbe8211dee990ee579c1f8c5b20bfbe85179cbcb8ac3acf80803838b67fede8659f12b6e85ace687409acfab70d5f140b8c5c31ea7f95184696eaead9b0ebb0e57cddf1d8e1968a36b982c3aa7370645978602893e82b3975bf321abe97770cebdde7cc2970fbf87d9f95c59d627df9442d3059ff0e7a53703cb86e28d0ebfa636210ed727f294be5bc51ae5a3116e39c390def589f20a4ece2f98e619f8f2092c9a2f9f18a3f932353b09862b74bae9d32b00e5cb4f700ee993fce904fe34473bead1204f97dd3bf9d3e99203e34fa17c7ce62d603b96ad62d99e5d3b9775d25bb275d15bc0e6002ed1b51d0b97e8cab263c9aefd86ed58b61bb66b334a1074142dffcabc27926879497f7aa67aacaa676096edd929687472d1ef0a69cfaad1c995d580643aa5607499c02ba8204949f94ee7a2fd0aeeb0938b7e3ef5ed27b480514ecdbd03959c509f1e0cf134dd43f00914eeddbdcb0e8cc2ddfb908ce0360d181eb52a3e95fa07765faf00b1a6aa0f5f8713068b479d036f38cf092f1aec8d2969e18416bdd31b73a28b1348b4e3c01b94e7799ed671e00d87026f38cffb10534ff3967877424c6bde9253cbaf8780756535cb565f47ae53e5a23dba2815485a57b90f35adaf8c5e3365d588d2677f196dcf2ad25dd991ee3255a3ad22dd452b172424ae2d472e7a7a2d935c7da28023fa1b6e1a7ddbebfb81d61bee943ec67ac3d17aa4d44c695dd9b31965bcf580dba8e5dbd8115d9a635398e9ad3bc2ed4e38a4e7394edde806d7b700ef4636bcf2be5ad5dccbbede0dde5760778ebb194ddfdff0c2e2aa36b0eb9bdd7a3660e1f1ee58bef3f87a36f078575fa87ff4ebddf02919d1f24dbcd1f2927a36d45cf50ef48e02b1d41c75ea3960c7bd67a00d3557d517ea38be2b748e76cff90bb5e35e7dd5bc4381eba201b174dff11c10cb8ed71c0788e5d5bde61a181ef552efe88d3531a6b9f59268a7609453d36ba09253d3e338c745cf01a8e3780ac4827aea2af085baea1ff842fdfb7a0ea8f98e0f310ef0957ace3bf0a8b99fce691d5dcf012fd5bdbf52a7f97a36d47c477d7df772402caf97f7ef3767170d88e5f5ead695025fafdfc7552016f0587e2c3efe32c282739ae3f86bf5578ebf6cfe51cf06d455a7de0ddf6beaebc8953a0ff0155da94a411b50f4aa8ae5bbea9cd6496f01dd77542cde51d7bcacda50732cdd535f812fefa86a8445c7736ee86a961def9eaa462797ea1e6874727dbb42b486439a0a24d4bb6a747275cfae0253ff402fba6288dfbede02befaeaee552ea85f91d52750e8b567577d88b91a0e69eda7ca1e0cf1f21a18853efb908c59765c555fd1552b969bfae2f197ea393781db3b30cb8ee75c07f85a5dc7b9ec08a55e3092b223943a3bedd94cc47ac5e8d8c317aec2afe73cc288304dc49a486a02a6b48492154c9461620c134b5d47c19bad2e3175f6d8a7d6c8f4aea191e9ecb2b9d753b26b7416002db1f9832b609d5debac395447c11bfa0dbca155496737f5d6eb2911524617b0ce5312002d31250b4612ea39f5155d2fb0e67c7f3dc7c7578d70eebd4735c2b942fb771c4474bc0a44ba4bf51b10e9aeee29d028751ce7518dbae35055a3d453f7be037c1db96a2a1754bd820a927e126e14126e2c09a48ea7df8eae158874d76b7bfd8574975177ef35d701be7254a3ae3b8ebf8c688ea322dd85ba4d45baaba61ad154a4bbbaca4555b32071a9deddab595267ce9c39e30a379604ac632df26858313ad61e3e303aa4547c6928bbd43f526a53d71df5f995409fdfbc05a09efa2781b2a48eaa48aa7a45f623d7bce615e0a8b34aeb13ad2ae0c8f5b10bf569f46daf08837d3f6cacded0a3cee52ed4b387533aab37b4daf0c58738747cfc4aa054c5e2bdfbfc168dc4facc73c06130180ce5d9d01d555fa87728af33d271b4f1d7020e7c69f953166b7a52ea258ab2cbde5d7a34c89f923a7a06f0e1eb18c1a2afb573270f8638a47f7abdd3b3f0a8e3f6cca3e1f430f693f8d376e2c7f074fef496645e122a617cac9997844a9278ee9cd6450f86989d8bde4df7ce4b349a28534ae9a5e93b641d07c6e6d68be1f41de7c052cb9f7ee37120d6cb6d5df76e33f180c1f3505d8c3d52a91b1f57f2ddf8e8e1c52f9ed7c3f3c01e28eaf5b8a9072a557373d383c7b8b9a19937cff19bd4d7c5689323cde4dcdc809e4ade78d771ef9c07de58c1ad9bd3735fcd131e3f7d48d77830f0f8e9d45b227f3a47d331773d703caf8a92cec7bbef4a52dfdef9e8de7d35a492f2c01e958a51df3c8261d781b1716e6e3ec43d62b397e4e6d2a3813b3b0eb8dd35e56e4e6fbcafee2db366c7e8c110bf7d48ee00c3d83cbcf30077ec00b7573a40da8559f43940e906b33c100c5fad02c3170d18be5060f88ab40bb7a234d3f451bac163343d977527709bf34ef54689fc93cf6b5f4f86cc0a6e79a7e73ccf3b7b8f20d14d6fac8b3038308603653800db40990d8cf990ee7af79f5e5fef9a7ade8798f33a6f49eccd74d44d47a14ecfa11a753aa5fe755d1525a713f7eda7d3e95b0db90e4c65e009dcfe50a813b89d42a14cde1296f778af462b9845ff83a71fb018fdf5b5c27e1004c175c5ed041ebc227bcc3c1aa89764634778e922ee534fc79a69c12c7af66630f5a98615e0170e462f4977a31f3afe603c97bb5ebfd10b8a24da80b9c0c3241a454802e67ad5c2e5ae7fabe1e49e85f1db43ba448ca0e927509e03c31fdaf4f56660b5e94a4e27503ed3825ba6d3902ed1f42690979845c3ae69fcd2d4093d2fc52f3462d1d4a6e9bf7f9b3e5a71fa8e5ff8e9f46c00ff4bcf86ff55ff0a9ed62759ac57c7481eddf00f37c255cbbd1161d615762dff188e5a7bd1bcac6111b792f055e5ca76f9a2f9ece1a481d5a151d3f0870ef71b4825a7b7af4703e52e50d07207daed87787a4964bdb2550da4975c6ae90cf945dc374b9aff0952c9e9f8ea8c3e0b6546f7a0f496b0ae501a4eb08e9764421ebdb12eba34b744b19352cff3f87e8b46b42f2dcf030cb96fbe2b34a453e7d143f86e3ea4c3d8371fe25da19fe61ec2977d4887dcdba3b7e4e621b7173bd630f65643cf83a148effa6c47fce8c170d41978d411bc790a0c799c716678ea3838383812c707ce39d9e1e07c88bfcf870f1fe762f7813e7c9cbd243e5229140a752e762910858452cbcb887a8fe7e8706c8f21ab5b5d666d3fea086e60181fef3d25dbd0b2c767951ad1738b9c9704f514b8fd81db9c8e2e7af12b2e7a06a0b1ca40cf6d6fd01eefd1a3470fda23e7393ddea3474e8f1e38471d0785e2b818050f308c7d73e9e3a8fb088734cec39bf3330f06f99bd83847ede0c17128d9060ac5a150600fd906a3eacd121def711def11720f1e37351c8aeb4193503d7a703d7a805cd7e33deacd92d5b9afce9dc301abccc6f90d8e4d8645eaebcd103b3bad4743cf8ea7bee3a97329903b0eb87554ea70a0dec3ca51a33431b17ba062af97845b82036ec79b6e401e1f923cc0ed1da03606b3e65760f68559f33a406a0418be4e60f8ea30c3e2b5399e7a8eba9961d67caae2009d7cb2434d4ccf6f66343136a0938f5b1b835b31c3a2e72358033af962675fb8950a6952cf73920cb754aad3e9de921f7d22c3add327c7cc614e672fc9e90c865bf1f3dcf77de76217c1efeb0df1776e773049d985318afe2ebd24df23b8ad02b7bfca6098351f953893299a3e4de0b9a3ce2238c4dcb9254222a97d7a634963901aa83786c4d20696bad51bdb4097a5c6c122298aeed11b4bd2d21a70a3717a631a28a3399a4e3bb71cd7adb7d5f0d5db23187e1d0f824877815d04eb0bbcd1c9b5ecc2b69de33a105c5704e7b32d9ace759dc92403e532f0267efba86f966ccf1ec35663186bf8eaf8a38e5e92218e601177bce6d1d0d3b1de2ce19e3af754a546306b729fe7346fc98fe6bc73dc454f49fcf6e829c91ebdc7ac2eb3622de2ee50e7d64bd5d0a853cfc070ebace33db08a12efdb95d0dcfb726bab611525db5557f27dbb57c3ec347599e5dd5b6ea96a4825b6f7ad86cbacec5f0aec2a15a3ed0d0fdc4681546273dc3d70bb0339eede125673f566c9e9a69faa24c3ac79d34f4b70cbf4791ee1f646cf9bc0a8c4ac798e870e5f761d74d0e18bfd44fbf6bcc6c3c9f764fb7628dbe8792e761c8687932f7e6e356aa00f5f177d9d552a90ee7a31164a5f380173194d325c84a00b17160bbc8e5c3b1762888bcb10d715f1d4086ec936b8157b89de0e6599e6303dcf5ee848323a1c865fd00963143d1fbd5406536314fc42fd3c8f1ec217bbf476b8f5fce4d64d762a90ee02bf3759b5e183c160301778eed8f3cb2f809f8fe02a0a89a7208f05124fbd193c1beac14bcf868367ef00ebd2a99fec898fde01d655eb267be2d73bc0bac0bab2277ed627a779d4838520c1c9ef4e1895b865baaccdc617957a7eb778d363353d82db290e49b92d4fe77607790269873a4d7e77e22cfbb6fd74daa84703ab4ff127b07b066a59f613486b763ad77ddb3c18bc9f2ec1ed1dc87d486edc9e03b73dfa3d0a0c63113773cb6d1741ef26f06689bce9d2744e825a0ce9b94ac547cfadd7d5f0d5dde90391eefabefcc2575f46a92fbb70fa6bd905f9eff2f1eb296175fc23c8bd03f91fb8ae147845772e825e0d67c777e076024d1e0cd9e325783a076e1f92a7edf343d2b4cd6011776cfacc4b429f816111478f869ea6a713ec217c51a9b7a352c7d9105390611324c1a9fd8d168cea8d65404b841d41a6776353cc7950e0e3ded8114bbdff38d6ce60383510e92eadd3b4fad26e24a48c2e602e4ddba6b2edc06a2e7651a9885b2ef9d1f2546c1f625ac3a3a60c26a15d2035abe5ace1abe719dc40a4bbb66e43ba2b7b56c3f9c2565fdb8db42fbbc0e70fc9f946cf73dc31b8dfc075ad47836cfe1053908aec59a9c83367ce9c690d5c7621dc9813687411b712b756d2d0d3b24625ae5434233ea29c1d815be696396ebb23c9c3e3f69c16d1041dcff10824ed8d1911c5342289ce7a63461cd15e6fcc883052ad3756c4133a9ecbba05a3139fa9375644998ee7b46ec118c5b7b122c674b8355ff6c68a30a34fbdb122963a7ee3169f5b2da35372dc0db5ebb367265031a9dde1dbd810647a7b7b7ba77c30180c881d62f9e8256135af50ec7d1148fda36516e339dacd15a2bd9735943eacba68958155a8ec99e617699d9d93de92545389675a7e7d42f9ed5cd6cd15e25e25f43306794d86b143f9790dbc5942cfe7fa649ebe336fc98fa675d7477e322b5e825c6aa3b05ac6cfe9d1b0665a9ec128ac9635ae0f3ff392c8478f0656cbbaebc375d3e22401b7cca5e67727dc58338b5b1b4332b361a247837cf6e825d967e0cd3e8b4f7cf141dc0a7158dce21f01c240d1c53fb736568416cd746b187bc52c3e9f822c66cdbad3716b574474e98d1181d46150f3bdded810663a4802ed7012f692ec308bcf2c66f2bdf936dcda4b707b63bd3a4734ca28b8087cf1cb71510660c0883508f3c520be48e54de56bae38e0518c46c2adc30d68720f7fe54fcf4d109c0f670c1bb3f8dc7a0bc85ec3a3963772492f89fc905cef06ed597d1db95ef2ec921af83a72c58e5b93bf12287b58247bd68e597c5a27b3f8377cdbe16cb6c1c8c5e50a2a489a3eba26286b187b9e82a1ecf90cd43e2427b8ad81ec5acf06e98a1f62096e67e0ba26036d2e36e2a3c90c0306ccd3e370ab48b6dc9a8245b295c4f80916c99e31ee80db73935bdbdc6df492c87391ced3cb4b2f89ac145c66499039d949303ec91147e6c26df86d0c894cd3de181252afaa8d38eb567fe00cf0312bc5c5057ceb11e0a8e7ac310ee0052b05c044a2b1bc7caedbb9d8ed9f6ca562d4fb901fb72eb3f68b3121dae88d09e1c51442a9e5e4b838bd021cf5322b9c7dd491935e12ca5e018e5a76193d38bd1862671fe28d5b3730c4ce9e6dc75330f6ee4c19590ace00313e01bb8d18178605faba9ecda576550a20c20cb3b6b3f3b96ecc92979f34e3cb0ff172eb0606bebccc1e3fb915d23f91e7967cf68d5bdc59d7433cc44731c630dc2ee0e35242cc021ccdcf73a9025031eaf9f9f88d3deb04b86529a53c7f4e29a724e2965b1be3f246cbef7e412e3af171bd312e4974fca2b8dde246cf67400b060673ed61bd9f5c6a722bfb3e4befb95d21d439eea83b0adcf5e96ac825a1c21d0357436eeef11d181a75171b155a316aeef3a7ef0a998e5a1f540db9cb7b3781bb3e5e0dbbcbed0852d1ce9c3933859eefc0f0a8b3af0743ecf921e6c0ed13f864d62bb1b32be1ce2ebd25f35cc3a3e66f738f60183b5e7a3064479d036f9474f462e8beeb133f2487b803a9c433bd1d05de78316837d530b6e927308c7d3a978161ececdea747c37cf6f592741f626e89be8d71d1d2f3d9b9e5b85b2f06ef5c0d677392af6c8d3aaa464fc9ecec1cb71eaa86478d7a075ed9ba3b0786b1b9ef0a7535ec0e45a8777db8731f921c28cfc58e03e5d743552ab2b327c9ee8161b6643e5b30b0209a3b7d1fbd18e299eeeaae4fc8552af14c73a75f4f866daeee02315d9ec06d13189f81db1b1861eb43af81213f03b7d7e30ff1912966417097405b52ff57fb961ccfeec3dfb2e3a80791df3244fcea42be1268cb8efaa2b9e4f12d39e7bedf24d096215b747cc7f72b09b425477de5782af51daaa7c0e7f82b477da976bee3af1cef9efa16595fdbf6afbebe6bf22f595f5b1d22feb5ddc755f7beff24d096537d9dce7c6e477dd56b3aff71d6bee32ffe8efaa2f45f7d9dfefdb5e3dcb7ccf3a82f1b9bd3d497bca9be4c07b9bfc073f525e55fdc6f5ef37defea8bd29fea4bd6578f9ffec97f7f75ffea8bd6fc45df7315fefaae427dd9d81c477de1b8a6dd477dd9f8380e0dc755f84bbb0af5e5c3247dfc65daa943b06aeaabe63870fca606078e7a9dd3e93e7a9c4edcc904e2d89143253f8d4da71c72e370d014483bde76a852bc81da27bf938683a35d8e1d393630a5a2279349729f8643d57d394cdd0e95c61b9f5220c521298e1d72fbb1c2c7710ae4ce824a85d38f1f353b3869eae9f98bdfd363ca91a39ef56d67752bacf0d7e92bac006a5aeaf53ddde93d94c5fa0b3ceb076b4be1f85ebfc20ed557380b7fe5380b3d3d7f71ef51a1e72cfc65a23f7e70e0eb5914c759fce3c78f15fed2be427dfdf8a192674105157afcd5bd87e9f53d3ede4327070beff96bc77b582c9eab505faceba8f09ebf4ed7f9ebab3bafa9e11dafffd1a3c7757cf8f8cd7be8bcc75faaf7d8fee340fe4a1d481c827316fe4a9d85b8731d160ee4af1cd7f96b7b0f0b07a71ea7e7387f81c7897f71c7b90a3737d7f1515f3deaabc7757ee3e3377f75bf897fd1ab70d65fdf5991e7c75fda7fd417cf8fd7fae2b90f1f67fd255fff321d487dadb0c277eaeba6be6e5e53739cfae2c1e337f585f39a9adffc85e337f5c5e3e63cfeeaead0f6c4ef9c059d8ee63dea8b477df1788f77ddeb5fa7d7faa2d179fd8bab53b6279ee62cfc75aa3f6c4f3c0bf5b5421d22f67057a1be4ea7dbd497cd3915cefd65aa3770f575e28e535fa777a6777f81b586ed89c7f90b4795617be259f5f503c779eaabd657bd0ae077ea4be7aff5b544d0f2042fce8860091b407281620891441850404208b688e1da027e6847ddb6271eacafd7e7a8bb3df1397565cfde478f1dc7a9af9bd579d4d7d10b5250842531535401c60b5c3b8e9408c20c24bae0c113c434e1daf197aaaeb6277e477dadeaca1e213564f5fe95aadff6c4eba89becd9e7f84b561eb6273e477de1a84344d716d56dea2bf59a3ac410d716799afa52a19eaaaf2329a8900215529871c3084970c93da34c0aa0404209335d3cc1b5453ef5d75783b6273e555fa8bab227480d837affd2ea90ed89f7ea4af6ec5f5c71d89ef8aebeb83a04cbb525fba9be8eb0408b2398c00d1d942181cb5487b86b4b0e174d50410ccce0028522b8b6f0b5bfb6cada9e78adbeb2bab2c7a786437affa2f5db133feb277bf6fb2369d4c33e67b6c096b44471818f7f6eb1b815ce8f5bf23bdc8a2d6359c6b47cc72dd9b20fc4aeb0eb706bf9e5d67e4756e136227d1bcba2d41b0bc28d0e532dcf42cfa265d1a60d5dcab96a69264df0d2fbeb0a1b6e0ef20d8f7373751eb1661d5fc19a7f1dfc98f4ea7572e03c07bf86916c5cf34bb32c23bf34ef388acf3af5e5bdd683f5f5ddd4d710c79d477dcdd8aabea68efa92af32f65a1b9bd3d4d75c924b3975269d56dfea6bfaa8738cec31fd33f5c0a9af2b6cf0749c4f57299dc6347f934acd386ee2f36feacb3b8f8a83ece1e7e0d7d4d710d9c3d7ea8b0b1097f6aebee61759467e913dfc6547e5325fca569e8e9ad57c7f71ea2f3e4a2635272dc174d457f61c35d2d4d714d9c34ab287c7c81e56923dac84a3f2981d534689da643595e62fd35f48445c273e8dd1d497e9aa1a635f7dc52fa9fa8aa8fa9249b287bbca4bb0f86575008327244dce545f5ab874ae539d7c2422ae595fa61ac7c81efe7cc6a7f5c55be558cca030032780a1021c00119762172048218432a8c8a219710db038c106c4784309d7acb14c19a5b994b434631316934af38b2cf3a58cfc9255da658c541aa3442b4d9249f3212f6967ce4c810765dc4089a4592912c7e211766006109a0863866b5d9273f0811db440882f8ce05a97ac14267b981fcdf8e2430a6ba64bbd3a46e051e41c55701b1197961dd7c2a573cdec5c562e7a792e362ed68284e3d282ba162e412ed3a93b17968b3b971dd7a6694162b9b47009727dd7c265888be65c582ed5b9ac5c5ab4a02a97952b752e9f0b754f0b1796abe65ab86c2e9b6bd1c2e573e5b8162e77adce65e5d2711c5ab8dc35f7275ecbae0bf15ab2683b2a9721ae6c7fe2b9b05c74bf027dec4fbc0eb0c7fec4e70071f6271e07c8637fe26dc09bfd89af0173f6279e0644ed4fbc0af4f627fe0353fb139f026bf6271e05d2ec4fbc077edb427c07e6d89f780ec4b13ff127d0667fe24da08efd89dfc0d5b610af81dafec46760b73ff114e4f6277e82a7fd8997e0b63ff10c9af627de6815e506b86c9ecb74d12191e5a4da663ad1ef3b2aa594ac9d1d5c57b207a7878f9c2967e43132e9f5cdd3bc84b58cc15a1eb6ff7cc75fb8d8b7fa92b018c352f5b55d1bd3923e2bd3f2f3afaebeb80c7f9932e433a1945a6ee7bed3524b8f935a761f2fbd38e915975e1b936a78b112a7e23119adaf58e6f14b6a639d8499621ac326ec8b75434c65b42ff32be37d315de3b963beaf8b7bc84aded7b57d95e8c30ff570bf543daa6e4b5e57575cfd38c954bfadae968c6a5c5add5c597d4c5ad7ac2b7b58a68e229fbee076278c65b66b19fdfe12687e4fc14f705e035f38be812f1d37aa71699f7f5d614377edaf8c7bf657d29ca7a8cfd8e67dfb6b658f1235fdf4d715367c37ed189a3a8d4b3fd51cc75f57d840f39a3127d54f7f6d191cf5a5858b97e33ab4202171e13897e87a5d6183cd71fca5a3be72542ed18543dea64698ec91afa9af3846f6c8d3542ed175aaaf21aa3a45f6c89bea0b07d923ff552ed145eb2b2ec91ef954fd0b55b9449757a3d2abab5ca22babaf1a648f3c576392eca14b33a9a992e9618ccda5ec3b6688b6654e0fe39813fdbab2871b3355a31ad7fcbab48711e6daa40666200557b2277e82973d31da1c45d696b8dd09b5322dbf49a0f00b57e14356c7be2af4d9f727d4a5c974aa583cee7c3a71158ba9eb2a9653eab1ebd84725b616667de4d7b5a5fb0ba90557aa62e150154ba76566323312c8ab5b3caf6666648f7c57b7749df61846abe1b9ba85e3eac6620d57a7bae5f42cdbb79cea66217be4670dbf0e3333a6bac5f42c5bc592259e715d31bfae2da61abfc81e0dd6b1af4a767e14f37909e365633608d359b614bd7891405b7d6d5f2490b75258ca4202755b4c02719f7c0c23814ea68a659545562c973df148cab8e429d8b16f9edb1a462af31dfb60d8f5097d427ea88589918c2f92f1694a999950531213bd70875a182d8c048a5e648ffcb67ddf6ad5a116a6a5ec09df61f402d394b4309ad2aed161b69499c99600d06106cbbc6430fa858aa15f6c3a9c6328d21c73ea7026cd2c9268873226c9c82e32c66564973065580916c60b2b99f112463343222cdc7ac50c09b79651cc17cbf862f3c3e845db8e28a38ce076087165916366ce1e4102e2ca22dfe0b14790a68b8f2075387b04c9a6c71e41c2f1b1479076b49a3da2050900ae2ccce7126df6089286638f20a572ec11241d3af60852ce6a8f20fd70c9faca8ed4826b8f6841f27165916660f25c326f8f20316a8f209d527b0489e6db23483c547b04a9d2ec11a4155c5c5ff4482d647b444b16cd8534c4c5e7225d7b0489bae41124cfb4479070b8e411a41e2e7904490597ac2f79a416e21e41da788f207d728f20ad5c7c04e9ae23482c171fe1fa9a37aa71691a67995657947eb2be905a70c953a4165caf1ad7acaf2c521ad5b8905a7071fd8db238635c152977e72eb3180728051cb9f858e4b7c82a0412179fab11c773f18b9bad0438eafd2bbaacb072d4fb2b6a6c61bfa8fd99f34787477433ea0502b89d820b10520617675cfb0952798232aeadc2168ca4f9d0d4f2c77e3d07fce8a80320a00ccc4f701fbd2537d9570bd2e6da6eba06226d2eed0b86463630ccb5dd0472097269374aa252539ad51ab46fdbf0b9b62cab54524d2b15db51cb2109eb4d0357f6845b53e62420262688345df312b4e173cdef4a59a9a49a8a39c1953dcb1c9b5042ca1996104114c204d012df5c29026ef74c022b3a7684b55c1ab8e7655d303ceaa5125b7e376e808b1fe8c01757b2b067904aec573c8a1c008e5702690fbf4cab2b7be457f64cedd9e5794b72e300d3b3dbb05ddb4eab0da667f57505bda95ef6c82a3664dfeaeb933df2f30858d74af6d04c9e5cebd2d69581eb9a60c86ab025cb27b8d8219453cbcfcb1aced34a4536bd18b6a940baeb0a79e92d31f5ac610d2da5a9b98647a1027a63121c95d87cce4a6c537d126fba0ac6e890abc4f5a12fda9aca9ee97e3a71f491c3ecf42670cf2dd17cf735bae34cbc1e87a625f3dda3b7a4bbe9dceca2178376ce04769fde92edf1b1eefac490abe91c18b2e9cad654e4146061513cca221361c6f09b4a69b40a96e8ec72eb6ec021056166d3f81a6e20238f866471eb26fb90a6af815be1ce0ddc0a5938f0c0ad70b5610a30845b1bc3c24bd39d0ebb0e378c4e878bc672eb1d6e1b40d4159ec61863163766dff8a2ac37f60eb768957d51b68449f333fe462031c993cc2bc0573e460c74f617162c469b11c3c097a6bad5507e1f663064974bb28a0564ceea9278fe8a5bdae9713e9b580a943a03697fdcdaec540a539842af776681ec33309ee9f5600b64190644c7b32c63aa823b92fafee396f7bdcd0ae73b2c6e653fea13e85d038f38ee74f90ebcd16eba97d43305b09e379d5ba2d8826f632818d3d9977ade4341999ee7ce9dba0c9ce7b8a3286f3281948b1de5a8c8e652dc9fdc2cd94ebf6da6eacd70da4ca84d3b673a7ddb74aa306837ddd45d036367118613bde974a261fe549fd087f3568e3abbe6d1f024fbfc56c3ec5d353d8b9da540c95c767f5c5a52e7b2fb933dba8664079e2a95977c0a5c17c77529705d27703b3c6a0d5c62aa4fbccf244de6f31e7297537a4ab86735f4ced51beedbe9d953e2d51bae2ed19e9dbe69db136d06a96da61a7260d8fdc6f4bd315518e8b973f50476dc4dd993d3b91ac60e331ab8baeb53a9c433a64b2ef6c904c68e447ac3235b178d3010bd470d09e296348a4727ee86e038198327c3d210b9149096d3b55c2139ce046e8c99e34e762670c77805981e0d725dccd1e5960438d2406f340cd9320618ea2dd5dab94851a15112cb30d4dbd98b214a533152d2754e6b1d7b04386aa2b773b29b1e0c474a4d0587c88c4285464abb40c2ed994780a318648fd7b6eeb4d530ae8b337527705d26705dec29e167353c8546fde54b67ffc0cb2a6b283d1a2615d94fa456b31ae593f89b25a1059abfbd5e12ce989af9d2458629811bf159b69a96659a96655566670c149532b0cad6746620ad38e066311e818b54d504b7e06caf435da14979ddadd0eeeed230614abe2455b6652f3f7af2ae4fa63ddb9f5648abe1a63d5eabf1a78ef4cbd935eefd8906ae9ed68723acf9bb3ecc4034addf0f2d32175c6ce28be7b88d30f8e6a7d411ac4d2317d92b407706e33bf08917033f3e721b53f06dac045ffac485983e75778e935df462d86efa13e618bcf1d63b83dc9ed6cd5d9fd4e919443d0586fc10063eaa86913d18f8df87e407de2ce1a3ce4755f066c9a9f9a7e6ca637da4769640eb9267307594e6d170eaee3c56288cddddac8f7c5779a03ec411d6ebc5106154a83ec49f0452d599aae1d6d99ff04f0ff95b80a3189c4e43cc4d969e12fee9fb04b53ef2a9f591b09eeb235fdf8401d1de3913e7d5d4777d4c5eea281318cae68ee25e9435ca03aba052dd8738d51de5753781616c0e08574d3ff52e5569f56356566bd36a73146b4a70b1891280a09b284112bd3e2ab091edf5428423cca0144f90526e8c746bf8436f3c423e9c0bc6aa01cff3bceedc3dcff3bcef8ec75a388ee3388ee3be3b9c144c269369bb7693c964327d774c4dd0344dd334ed8b4800b9e831189bbfdefad08d59f4f1886f36a5f7562809af1019d30a25915f22dcc62d9fd6dab994bc94524a29378b6163c6ad37ab04c36dc158c4b7b11268697a5696813164533b53914aa550f7de9d7b2a954aa57ac071dce9a66fd7ce711cc78dc1ed0261bd0563586f7db46e7db4473016f165a7e1d69af66e85f8dabd15dad6cee08e66036ee50ea9d91d1cfdb31a76cb272318c2ad25e53ee5d45c8d72e2900f2536a1698d72e2cf1a9ebe9dfa8a359af6e9dcec38eb535d6651309c9d51e99dc04869a56c3a831c8564e766cc98cf25e18d35d770a8f99ca9a320fdc67a635744d1cb45739dccca321318ce0d0cb596d7c0104ad7f45992594d9112c129d13ecfcd6bf39ae9a6f0a8b38dd3a6a681db13d4ce317f7df6c936c3f6eca61a1eb569e3b618e3fc16638cdf267f8b317e63136fbcf1237fa618bc998f9f67f0667e82320c698f1c7771b207039578a64a513745090e0458200b0606dbce6d60387b5e9a6a152a5b0606eb229ade2e6551d7db4f5f8f862927b00a1524cdeb335f94f5e96195d38bb2254cdaf41c2a483aaecffc069aea2e90e9c1409fd5096e1bd8fb2ab36e9a1b929e93e7a247c108c6c5c973dc516f31e46f1294ac5d72a5f25a4945768cdaa9e068e736666da66b60a84d666d37691a95f846cf67a64b3094bff235940903a2c3ed54b4378038d35736fa649ecf5dab1bd8690fb7ad6a0fb753d9b404014457b99275fc15adad1cb5f621a981d937707bc1908a56a6e9b30ff156c43d6fba51126349f8191843edd919bcc2dbb9e9b7af07039557cf2434945103afed23f824560d94bcd5307eaf5d89ecd0ca51c3b0b33e91f5c99e1f332370455fbc92ecd933d37e4d5fd34fdf054fe067caaec4ceb258bf3ecbc54e7b778acd9d3ea44d8f5e9258c3989d3b759ab6243b5753a6472f32b17deb8a597b538dbdd94d3fd5f0a84ff1a60fc9c87127d3b675bc09d4b205c2a77381300cb363a5f26a7913287981f043021cc5a0e302e113e02806bd0b8467cb53912dbf26308ae053f231b8217dfc06dec44a25b65671c0c060cd4273b1db409fde675b7034a9e729fd8f0ee9f636d10a5519d254ec8f36088fdfad59d5c2c5c7951da9c66504b76c7a1e4ad30fe9d0a6b5648f5dbe301ad1f3e1b2d1f3affd277b98b0040b9a60c1973130982b7be432d8244106a008e20918b8b470f171c523d5b8f65ab8b04b3bd20baef80c447ac1f5bac286f8570db2673e2ebdaeb06148f6cc6bf575850dd9637d5df6cc6775c8ca9e582c3edca56d821036a0c2086654e1831cbce73b08dfba8e3ae0050c9860820b312858826b5dfb70880d87c15cd1086efde8199398a7135c0cc1277b725c9184154d68a1509e7f9a9fd3a8e5e31a3d2b0db379ad46c96a981d8a3c4199a635ca4359c35776098291d4197d68d461bca48772b4446b51168ca4a60f2fd09956a3ec1a4db32801d0126b5a97bc6c21a48c2e6af843cbc7fd74c01053f1da1ba5ce9c39b384cb4405acc7115224a154450525138481154dd9359a0a989032ba805d098096d80fb00523c9b50f2fd034885dc365aab05dc3b50f5f4d6b182f5748b8311294a08b625301cba1c609b20c0106736d7ded8da230e1040f80780306736d1516cec7704a4b1b543e50638a296881c15c33d43497809bdf9db94b35d870c3a2d1f29c9628cf0227b3e46f8842e46d60967c0dccaa41029d7be425b3e42ef1b04b2d2fa17caa70c7b47cf82e031f8d70cbefc8b33819576e8f3df94684b9993501ebda3e2f7bce5f6085e6e5719040a7cbf32081a24b7e8a04f22eff4334a25d9ea3bf991e78334fe0cd3c9da26b823570d7e834fd26eb7e93d51aba4d3677aa3774db4cdb844184d12c384a3f6e6ddf7f85342514e4be5e0cf4f334f272b35b2f49bc2909ade151531b908261ec2bb1c37825f69ce778e3f2449dfe245e5ebea867d881374a768de64ecddd70eb29d1c83457370a09b969e495a88d42e8e504a174327b569ff47edc1ad27b1338a47fb2e9281895bef815b336fb697bf4a86c8db33efb0dfc98b5d7c0afcfd6adb3cebadf7c83a3df9d702be3812fdc62316e699fdfc0708b3fbf85e1d6f6f970f3a2e7b928beb40abdb128909a935108117b9e5270ca37e5b76f60625b01e8b7ba858941b69804da92b8677e6eb1271ffd16db9298351fe5a3f54609c3602d6f0483f5931ae2e82b7389869542ac6985427f23c336dd4ebba8978846b6e7a6d4f3dc9cecb4cc4e03b7a49e5b5234c23dbf25c1ad8d450144cf6f5db8257b9e8b92a3443178c3a7020989cbf4d8148cad8137095897e937fc8d4501eb8d4171a695c8a6974d432322ac10fdfcb62481b8cf6f62245074cd6f632410eaf31b996864fb3c97fd86be025e740570d028f0863ebad8c58137b41e603b97e8e2fee8a2600ddd3730acc0179d7d362739ae9ca8f0a86f6a38fd46fb6cd93707f07ea3d51abc9a65cf98317d3677ec2196dd8159a28bab3759a5923ad354201171999e2575660a2e2ed165ba96ed54b36867ce9ce15eaf497c046110bf95e9d531ca8e286b64b4d1e1d6f15b156b747cc73fd89aad0fc7fae4d90acd31554451c51249324ae7e5334a29373beacd249964d682dbce5628da78b111a0d136dd08b068f9ef5ed89d5b1248bb3c101c1c66d9acd6bbd3f2dace3884c95e12a619cdd6474ac1450e7cf3f271031f9f86db22b40db3621fc5e8829c13a48f51a354a3944e9c3884c9f4138c3d9f559c39c1d893990c2e7e5ba158a3a841db304b7e5b21f97d2413d76725d765d626639442c66d85e8f71c95516e97d96576a95d7ecbe465762925a78138ccca380893824bb3c7ec37f3b1b96f261bd9a956719895d5b9adcfc69ee08ee41c70fcb9420cc6bcfca06d628d40e8e3ac4f8c6738866d2af10c8de05c9f98855bfab942d9f7748522488459f4637a08b3e8d70b719a5e86dd105d87c340a7d31f59a1afcf767a20dcfa98b59d3ea867fb0e036ddcb385371d03d970cf76fad5a243224d7fb342b12967027198b55da631c4df2eefc54baf98b5456ffb8d76a369df981731bd312f67b40db3b66754669b2a0eb3b6ba1a48d7677d36f6c623cad204dc52553c0ca766b99239d2c065e7b2e82539bdf34ecf71200c471d763f695fedfb0e0cb5c773b137e6658c5d1f0f0690ef81da4d606c8edbc0edde76dc1a6edf40de1a9ee3ae034ffd132739ef5bc3ad7fd0120410b0aed275958a95a3363dac4014a470a6adec929724886853ed6ab8dc72b4db40e63eb9acdbc0f3a5b7c4abe10fcd7dbbbaa71e0ca7eea7ed27a7ef562aaf0e659fbe9e92adb9fa643b87dbe312fe762af14c9b3e2487d8046e6fdb19b8e0e4e27c01b717f8e6c355d3efdca227c2ad95172b9a1e674853facf664fe937a6852bfa766bb8a5aa8e593657b8d14c05d291cb508317a459c798a7d7e85ba3bfc0973d486b859b0cdc0a3f1cb8a5fd08b7deda6f18a3b543805bb2b515d31a18d4da975b6087ebc510e3700c6a4bc410b4c6bde2d6c6a8e8c271258a4a3cd3fb714b5ebb0db7e635edda7747ab4fb68cf422a5e4cbe3acd0b67c8f1582815b1427e5630d5ab6605163cb52d2961aa8b1866b65cf961603051cf082cc139cc0856b650f7f59352bb358f1e1d621ab977bc2afa750eab9157df4933f845bfc49f146f36d98d57ca4597edd6eaaac76cca2b5eb8d4d9144cf6ac3acc851e06213df64d6c6afea6b09e42bd3f23612a7e51fc0c52d3e36416f6c0b2e9a9be88d69f144b37a632fc88192a22c653a3cd222ebd0072468d0fb54dce2935df4c6b248ea08a637b6022f1a486f4c056e442f86d317639a0a0ebd8fe1548689a66284eab0e8076aac9ae8b0c84b13dc0f3a2c2ae207b4432b3c50010b2e58ead04a164bbddf60b00983f59ee94dbd973be0a569195462cf7313a4b386317a4be4b9863228d3733e3605c3a39b25b48c9ea7657468e5a8e7294865cf9c39c347cdb44c73d1a5c1069be38e82b48c6630a7a317c39b3fc12b38622de2256ffe12f00983618c219e9154d61b25f1f231c4cb5ac475176d741137ad21ff4a6cf9a396604b106c2ee27a7f44233b81138ab03ead90d0a9f7bb46360a994fadd04a01288b3df1b3865b87d9101763accfbc377b8d0c71918315b23d6bc83534ea2bdc14a8123bde6473fab8aedb58fcf560e0e6c7c0cd1cc7651457fef2d5f4c6805044c7313e50c20719f001d298316e488e3b51374a642f2771cb447ce08330bd311f64d1eb0312b4a937e683273e36164c6f6fd017256002892ec840a28c335c14075720e14510471821082e1a7c7143726580db15279725551bb31eeeb0ea63d60dfdc6a6f046cb1b5a61889d49a2e7831848c6f84305b841072c9a596d4c181a415abc3230180ce6ba62636abcd1e12ea9e145878b4673cbde320a386209500143a0012a608831db4533171c0c47b1e5157084d2d1562a321c66f1571268e3ac2ef7ac54298088a43438353ab0a375b85cf4001688480d2bb57b01b4b9f6dc1e7d1b1333a655bdb132dae8f5c27c382194a0fe67f3312bda302bc665630b1b7cc006660c5103194c0604a14b14699c40074e08c335270f54d0f31db7b49e447aceb962c50f68734520dcc3925ca406dfaa01ebad37a6c6111dae3afc9624156662d0d1ab8034cca441268d35d8d41b4be38cde581a63a4116693698049c305d34c1a58f4c6d288a2c3d89b4608daeb8da571c4a46848010d24a03104347a804619687811ebd0f88246157d52f2d048a2eb8da181943273861bfdf5c6ce58438a30bdb133b2e870f69e61459f7a63673cd191a33963899a3392b0a160646fb8604616d101527c1b33a38dad3766c61abd3133c6e870ebfda2696fcc8c301ddf7dabc58c373a068de0dbd81963747c17e3eb3a805ba0efbdb50ea648ea556ca1570753c03a1e08b7b823918e5b871b106b5958a0550d1268ba76998fb4c2163a7e005c838f358408b742283b6d533b0ec1377b6366a4a0571288c53df1317b53130045187d07b42eca5ad6d668460900d0f29bfc3b49111c7c592fb7b2e6adcdf0926d6c8ee176871bb3466f6ccc181db2172dcff5c6c6d0a0d98ba69224462f3e34eae8842fbab13ef26154da317a633cd0a2c3f8844f1e6881a219d343243248b9da0a999140b18ced916779fa90d5d94321bd2b2444b281918af591d7c008c5b2e4658846a25214222fcf2b149f581ff9dd9e504856c345028bd6f05f7d5ce510be9b254ff8cb45286f46521771cf2bf301e8f596d09e55c28428a287c16045746bfe8683205e62074a104d1436e04050b70433efb43cb3c4c922096b40d991629ad019155c964d6e65d1867132117cd951154a3421082cb00111c29c717d1288a703496ce186185e9ac0c2956de716003a3b4b024d57f621b476cc9a67e2db9eef7667b20886e69c2b431007828ec42c0392d5d5764414c2f7d559ad0583e08b603a666d9c530cab8ff47e6885a6ac4f4c2d9121adfa3c94064405c6e68d66fbbe267c41aa8ebbd3f9c49db62f457342bde589e6f22c1aefc4ad040a5ac2172e98961f00b7ba6d6edb2e0f64bbfc10ee92935082fa74e92da189c2061be8d3a98d316b908100b3e29752ac15d17de9cd8e704f967537300b02ccca768dce5ec4055f18912212b7342fdcd2c0d81c05b7b866db4b44257a83045a6d9d984d4c11305f761924d08b7bb2675df6e84696fd066e75cf0e011cb8d5254332825ba7678f49d96312193ffb8b5bf15d7da3b36e677df8145c318b4df1095f7c78a4b3af186873657ff6ad66d7a89ccfbe3b597d12bfd0703fe79c73f78b4e90a19739f0c54309ea5dc934d8ec5aa869d9b5ec4fb48c6e966559986559f669e0c601c9d627d3b4a865f5f1e1bc4689accf3ecbaed52cab5bcd90f8bc70cb2dde5a2720ef7bce047212be09066606429d9347813bdcd2c0706b69bad6312b7aa00df7c45393f9b29b625866c9ba52eb6cd34e6770e7d65df8f5ace12a76df8e111f713c91c0edb6e6946c84f94995d845cc112ce2163fdccfddf0b3ee7a4a260c1665944270374a8a6687db43edd963a57d7aac8ff54609f7f858c31b25b168367dc83f6aaede28e9ce71efbacddbbca50decc00de4328e7bc6d56596090ccf69db766dab32cc01306bb3ec34639e40684f8e54f20ef7911727144edfb7002bf45a9f687ac8eaddc0c48744e404c24010e09e08b4dacf6d15c47d606cd662415a3d224d4df8584086706bbb96ba345d1b3ac2adedc8f6763a55283b4b70b2480210daf45903b3e253208ae5993a30b67703b74caacbd720af0237d9d36d120808f7c86b219196b18d2fdc303214a0061bc8f4e9a6cbdf7002e335309e879d63b21570360c04847be2379e5b9bfc46277ce1ce0908b74cf452d2cbeda6cb533d7df67aa65385d2f566dace52700bf4799f1dc7b4696f030315b10cdcc3f5a237888178e01ed351a96f00dca22b06ba41f6988064903da61731e3dbcec198a58559a60f71111e985ec405eb797cd3390f8c2a8e4bb4e9b1f9218649a01dee317ddbbef0abcb3b6d52c1a2e0469b1ebde01ac3c630dcbae16f8c81e196155a684338b008982fdc2902e6d31e8df0f16456c6d574bab5e906316e702a668e935e12ceab45b3190766f155e01acdffc2a486a0c02260768a80f9f81d08657df83248a03806f7986eda4c8f4c30991e61dc8a373d6a8948310b6e853b6df26205b7be700b0b6e85455a7ba7373d8ae19677d3e318dcea6e7a1ca34d5d8c15ca2eb5576773e0ec133899e5321d481003adcb04a64d5f718bdef44d02c99bfe49a019c79c4ad0f542e96e3029a57477f7457cf16210b13c05224098b505581f1b3a29a51f0476360065e7ccda775b125f7c18d473a565800b17640d7cb18a7cd16cfaad374a369c1d6ead321b4a50f3a12c989e3feaa33e6a2ed29ecba736c1b458cf9a358361d72b969366e16c1a190966c658ea78f6a2e3105fd8f56a1523912140e239a8e3975d42daa5950c412dcf5abeb06b0eea3965aacb17768d624f7693a3a7cca475365dcb6af3e1c469b37528df31cba667cffe98359bdbcd865bb37bb7a5c32cc0510d67cbca427cf147cda912ecb61d4bf9294f1f9f5039ebc6290c616d5a87524a29b3169a8febd3e17c71d29c5b6b5e763f915356c91a0476b240d9e9f92c725b87c383a03daf7949e6b729a59cc2407cf145b3e70e0eb3966a9aa669332c624e0b6ed66de92efd3efec9f225fdc4a1a7200e4d3f410ee28b9f45b4299db34eb9c53e7bdc6c9fed9f649359f24372ca6da50d77e05b1a2311b838679cbbf16836e8978242f8fe84d6d91b13814607e98d95614573a970c5e7d6c603c76b60b89aefc068f2c0e51e6aaadae9cde94f4cdf7e327dbba96e2cad863c347d56b7860ef75056cdff4e2c9562290ef6c58e33c48e5fca5862074b3bd0d21c173bba24360e1df7c21cdff1158ff36836be27aad3702a107513f8c5abdc68d5bb35c818438ee146cb31da6829b36e3d25a87f57729afbf7cca381e62ad54d60b86a93c994aa04386a4ef57d99f5fdbbea26d5516068f33d01723ca502555fcf00b1737c8855377d3ef366409de62a30e4a155cfbc194cffbe0c64f370b379f8b54dbd21c051dbfc4bfd3b8d95a34e551f72daa6de707f92bacdb9d46d9e4adda6b25235e4816553431e9ae634577d48aac0d0e699ead49321768ed38021cd51b5d9f8682a0d39aeaa4f723c559f74577d886d4028ab56fd03439a0a65d539aaa98650563cc070f6ead25be229e9ea6496574fafaae18ebacc5a7d326bf5cdf0d530b68ed77cbd1974bc4607181a758d0a945d738e7626b0e6d19b21a4b90a87b691b2a33743f89de62ad93a6a88a56b4e4fbd19b86b6e9ae13b4db5a9217d91ec9a87935926138e1a1e754dc5718ae3436c0271a8541554351b5f9154fd04164515c3be9b25b1691e9be65ff5cef54649fcf7f8af86a7fec027dcb773d153726a9aad0c237630a6b9e8cdc07ddb408e0644c56f6480e9eddcb9e5689702c355a76e03863cb48d4d7f5f6ee9f84aa5faf79b550dbffe9ee33ac065568e1a7ead7a0da8fa32d0cd73e4a8e1d6aa1ae2b8cd6b7e032ef7d4d470ebaf86dd531f9229706f0366c7018650564d732536cda7a7849be6d15b124ff3ad86dc69684054f40870440372b307034d0d63d31cf51458f30fb4b90a0c57adba4cfdc9779ba7bedbfcbb4d5d66a99e7a4d557d48d280dc2a30ecae35ea3420f70dcd9fa8fe9da63699ef4689eadf557599f555efa9ea29e146d527dc63d85528abe6eaf6fd3a24c243120a6b28abbe123b1e47c7af38c5846c630d08cc33cb27720a0e8da663628c310ee91a9845c5c418a31766ca340f5acff315ad9ff063dd3a49030e29c639c323de18679669ad6519a5fbf821e6ef8ce71863e448797e829c446a91720007b461d68a594af8429c1f191a800cdc0aa1ac5a7e2651b03bf3c96f18cde7ee03cb7ce1cf0c052e6ada762a5a6b463db32ed9e9cc42074be420a9a5a7647a200aa1976790ce24a2107ef492d0ca1e8842f812dc76c54b3e389915199c493f343d83f21c7734bb30eb888274562a5a4b593b666d31fecc8a59166e7722123e286ba63766c569c3ad048c11a659e88de9c08ae652bca56876f679fea1b7d5da744e1a9254b4de8c5aa39fda331085ecb34f709f816c441432b73292066e739cc4acade927c849e090a4a235a5d97c0652baf121d7ed5b9453e07627bcdcb4ae77a2a20d0e17c32f5c3557ab4c28ddbdc81e58d2344dd31e14b4f37daa237b1b9008f7f06b401af0a4ed2ca97842c149e1e353ba4b1d9332f06949f18ddee42e691915a60ff19e977bc2ad358e4908fa3e551130615704ccc7ddf40fdcb4a845ed282d6af7b477da230a0c5721ab8774ac55669fc0f05d34bfc848e08ec6d0bc686dd36078a27dbb06864b669ed36ab8645a7bf8a11eda780f57bd38340fdfbb4305d25d381eb26a1e02e97d38a4379cfd5181e3aa1ab00898cf74d291c34655736669e7d380b306c4398141ccd2ae0364e51842036e9f584324908dea7c9604c271be0a5c314bfb070e314b7b0a1c00b3b4a3401b98a5dd036f6096f60e8400b3b473200eeba31d07b8718fb6124806eed1cebbd41a0cdca72d8452350a4e1aa66870bb33bf44b37a634b6eb41863f48fde981856740e6062acd19cec681453492ec15d5ad33aab4974e5246669217d16cece1e72cdb44b0f86d8279b673544d13cdcbeaa67af5906aa79769b1a16cd4d02d55c16c936ddfbf71a70b927751a70b9e70b8b6473cf52a6d3371b1faa16cdd6ba83cdc6b7d522d95a77afc6f0247eb6569f74559b61d16c6ee32b921dbffcad61fc42db549ff035255c9fc4d3d62857e9a54703ed582bb7765a434eea2c034f52324bee304bb2ba556b8fdcdab34f1e1a4acf2984ef55873c6854626735caaa677d123fabfcfc102fadd1ef8d851184e62c3ef33c1a62493d9b5ba08f633d1b28ab61d16ced337ee91e462c3a6a9f9a119a764e9a5e122d3624a79784665996d4935b948d884616895b19e0246e694966ac359006ae93ccca485c6b153c723a3dab27d0548318892f0cda3616ebd5da275829277106a290f9a9512ab2292d83e2cf0b778408103091e5a46f7c479815631d29ddb64ddbe8b3ce8e749c603a7e88713ac618671db25bc3eff4ee16adfacca2aca659a6d5f0a8837af787ddbad0a6975959982028bbd43316e10b67470d15fed0cce5488ba737e677b8aee3c255d31a9e866a58d43284d2323d9cb29ddbc08e085f10b33ea0e553cd8e308b33133899a56535360581f404c35587abd5fcbe55c755f8eeeb59b7db704bfbf68d8156dbb6d5b941dfece8cd59a1ac7a0532aa20a3a5fc6c596fe48ffaabf9705504cc17ae1956fc0f122875d4c3cd7bf8759fd54c0d1228258f1ab37964be4eee929979b94b605d375ad6100aab23cc4bb2b2fec0ac08852f2ad123139bc4d0b8a465710a9f04c335c3140c174c371bdf82e93022f107beede1c7ffdc685395da4d6095d99c4623b8bd2d180d08d18599a6b3b9cff33b70b9c74c5c323197c165a6efb7cf3967d1909e6094a0e63ec130a86750cf4730dce9c87d192848f670500c0ae223beeefc30a853e76eb3f970563b3d51447ade9ba7a9bacc9aa7a3400f0c8734ad5566f3393094a1e9a597e454b98eab5076fa95451280e065b6095cd60c1ad3ab73848a530c7785f693ecdabbcec47135dc38300c6aee2f6e4a7345cd716038a43766993653f7ee0aed27f4f340d315bf31d0c660309816577c73e7be699d77fe32503cc2170269be693bea7c22dcdace50823af5ed747e0afc98c57d43811db3b87fe08a7bb87be06416770ada308b7bf4927075fb90dcbe659582b376f30afa1997f0853bf4bc4da99db36f91d20a25c8c80867ac60c98b61f21765c934ad4f66dd6a973103c1f159cc9a4066a6adb6ceeba8683584b2d3d969993599456b58447b7bb655d329b89324fb46c5a8e94625369ddde439e352d4aecf3cce3f66cd1a4209ea24eb456a83380429a1ac3ace56b2021955ec00ca6a367f8ae1b6865f6f77fa30fb66a010bef8ec3c39e9ebea3c0d8b66c7ef65c0452cbef85595e96cb8150e1912c4401f62a0bbf8321460856ae016377f7a914aae25d3928fc3e7f385acd0fc69ee7035a4c3aeb9095691af7265eb3d95f715aef79c04630cd69cec26e8a3b9d94d904773b49be0aab9ac9ba08e1ccd6ddd04713467ea2668d3dca99b604d735c37419ae6ba6e823fcd79dd04873487ea26d83597ea26786aeeeb26686a4ed54d306b8ea69b206daea69be06ccea6c3d14d909bcb61538323878e5aa5e86b21fb58ef969940848114d708b7f339dc1818b1ee76b825048c249a83f0faecf912e4f5d973d264667a45a02934328d0ccde4c586dac2e49de0947a82f33ad0c90d781b11a82f60a95313bea90495ca0734338d9a4e0c9b530d70c43a9ecbe1450b72e0b0a9a1517d2994d77127d3a6033524045c5ca3e3f6898f1f7d9abf5e7c69fee4ae11c0c5ef4e945f336474ecdbc7ba20958d1d591d953e1fc584bb346bc8923564f51823be984edfb69b4e9563646ccad0b0991a55163695bbc4ceadbc2ff59540ac146b662fb287b3903d5e207518cbec524fa42454974ee9a45446f59951fd3046a582915121a990caa892544966be2eb2879f458713298c14c270e1502da95435626a6a4ef31c39eab218078eba32d8d8d0d4a149435353836a9ee5ab79548a4a613892d9e298d3b7a8a218edebdaa28a4b1ad8b12f56ed31cc6743b314c38859da92e5bbaabee6355b54cff2d9542c352a558d64ac1c35c7d6875335fcbc1aae3eae863fd57065aa216bab4a1c5b336674d0022742c04612a0782d11b6641143461a3070bdf8096e4c0113023602d74b8291451044007bc20b5c2f0ec3a50d27106184332e19546490a4a04599a42e133695a6171920c1c5ba41970e27120e929a63ac301268c892040a12238186788c048a359f151b237b964c56c3ad0cade1870333b2677bc80b98ecd9fe82629a2db8dd0967acf746352ed55559d0d864f1c5e65f640fd3dca6a66251d5d985662ac52533a90fa9059a313bae834ccd55aa8a85c771dc2655b764497dcb0ae7aaabcedf0d8ec683c7cdf6954035b5e63c4c5f09b4a3c6af6b55b1a86a2a96efa7c7a4d87d2275de27cc435d9a913d66d84c1996316dbbcc62335d7e319d2ebd9c3e64db988c9463e6e9a598ef5952dcd7b5e5ab2b7bb2cbec1c38bbc4a52e4bcde71ec625321d32accc901bc4d88c04622fb287bfa16ab87d5e0dbf5557cd5433cc55f612615ea298ed5b5a4533cd0fd3252e7551ead2a54c98e632cd4bbb2481be94989ad3acc6d05c870e32aae7c8f12c925f58bee3c0f12cb26249dda6be6cce9f5d24d06b556b903df135e74f2509f4d251e369feca515f386afcf7974d8d4f9d3f4402d55496a419126e2a530dbf2f5c694322ade1b7ea708b97357c875ba38e3c56b1c1ed0ec79929135de18ae9fd0646d78ee9dda50ea598e945f6c036a42f693f6112e84aab2e5f12d2b67d52cc94528af9b22481d62566cc24d33cbd7c19239124d0962cf45bb46b5e4c9c1725cea4d4e55b5e482db84ce7ba2449a02dd9b350ad4aa48a257b566592440a2552f3a5981db391f9caaca41909c425ba2e7bf8524c128f21d325298be673920492cc5d9a3f2966c5493bf842f925aeebabf0eb188b64c89489b12fd14c982c604b3146121346f6f06338bd347f7a91406c050dd460230419b8818b3fbf4820d90128bc4145154f74e1e2cf2c2450e452040fce9839b303177fc624d04f0d40f083335cc0b8f8338c048a2c7802079098b001988bbb343fec22815ed1753a9bceac9d1fb398c2f17f9040a72a83ec61315cfc089340a65a83ec617e449240f586f36352c5a2551cb0d0ca83ece1f386e1924831ebc397629a2fa564c9dfa42bfb3257b78aae9abb903ad76a7be2797be22ca31d49fedcf881ea380a96e329a45e8ae3df529bab685ef33076e9fd72cfe66acbcec91a24d00b751da9d473d4e845ccf71d478d5fc6a82a97e852dda6d6542ed115c9d0ec55601cf381510c189740560d3fc81e79ee546f903df21b913626f1207be4c62e739796c2c487512964356bca0f99f334a8bb37743af72cf2f23268db4df7e2bbba7d12e8c5c59feab792402f53fc565797402f2d3eabb4b2644fbcdc5cc0ed4ec8b178f970cd7c3edca559c3ad21abb7866ba6654ce3cbe8b178470de1de05997e7a1895b46fcf22b1d0670f374c8751a94c876bc64c87514902bd5095257bf8de8b7b9deaca1e53fd640fbfb6bab247ab2bd9c3afac86693ead973d652450993264c88c690ea3d28a690ea312c77a758c4e47cc9305dcee8474a9f991075f48bd741809f44add8b04429d4ff9340b09949d4f6312883e05d2ec95792f0f05a2be9e02a47c5d6183fcfc4b96693e928dcb742190b84e2f308b760fcca26560168d8259b4fada2acd7c7c9b4a730cbdacaf59860b10578f0b81c4f5d5d791155d0891aa2f0b6c7101d2096e80c519d74b08242e547d1909610933ba7811c30157162da84ca8542a7335da584f928e318466684613001a63146030482c188dc843025dd4d4071400109fb0545a9f0ac42408720821438c2186800100001800184dc000a600c2c1d94553a2a299258205e45a745b0e0a532622fffa44a7ca3ce7ba36d808847f4fb94025b5514101edfd170a477ddf9bec2a9ff3b0fb520c84ba0a6e9bded66401f6c18b9d2397e62af84663026c1f3971e67e95202bca8faee684fd786305aa7e964d2a75de25ba76109d00aedebd41023dcf25a542524f8ef8db11074156b3eaaf18e433f3703ecd49e04812a5afd8875919c4c18881dd4dd11675ba62bb8b0576cb434b2d679d9430265fe522365e9741fb8f2b283296ae624a086caeb04516e678deefbc62774bd101702884cb21a23d6bfc2236d491e0716f800a0d8ddf2f1f87b9951b81df69dcc02e18c22c5a8afe2f6d62779aa69b59fafac618d224bbfffbc0760baec0050ddf8b682d452c2fce5d1c374e3a38c4f0fe7b94ea55ff4e3f5a69fe5677b39a40bc2b62adc6ec64f2994ec5bd6a646e78d89b02be14389d75a5d8504a423de9e4bb7f230c5d8534dcb9d4bb26214b4481a62aa2567ef300376766e7092216b97eda8b5c1d94cead18e171eacce317f79ab331bc56bf09855e49b85b458a2d938599e876c0d831ca0d289b69e5094a8d887c839b7df2cb755abdd2218c00a84f9699d528b75d481aebd03ba745b1321357205e85964dcce3f32e129e3306e5f0c46b2cef83ace0094861f777a27ed1205cdb559cc43fc404a260cb709773f47e730857001a8c0772b17e40d17ae373ec51f004da9f3f08ca4dbacf07090e2674d08731c485b6f5fb722feaa48248e6a581b194d8e1413f7d145ef591533b1efeeaf7a9eab9aefa69b615223a60f0b961e90206a0b20a1717db7bcdd458871e5b370da4adf45fe95527cfdce421129217fd7534f00b5047bbe274a617d345f81fe991e51d4c2ff500432c36ce02765cc706d28f1339ca8c2fc26b96a99b7bd50bd6679f15ffdecb87154da3e63878ac8963613baf92d77971ce201ad0f435de65b0cf6887558328e437dbf177acc9a1d894e7b39a5838d1a96e6e4393d77aa7cfc0ca570bfe220a4a8d84daa76b56f760748e6c80a734de07bea4fc44ed10cd97cb83783f4c442f5fb3d2e63cd8f93b03849139c5f40929c5c8f8fa8e8c3599b4fbfee879bbec1dcef2631f7843598056e5523c43c8a20f664c64c66eaabda986a8f6ce67fb2c7ffa6f4ee293266f56096292b981958c46c72fdc31af6a595ce4e75c813736124a5cc9840d877480e3b6d2b6b390b84e90ea6cf12e26740d102f8dc75ddef18b4171a7479d6580e7d9758efe5ae5b1a5c25c6e2eb19c680fb003583232b11c45b406ddfb1e2c28d5294862c8ffdfd336425cb80c348f7e34a012b41879f69cb0cbb8856ae9508019bca9af8e2041b6aa5445dd1d8d4ef9b9aa6b4620ef94c61851d4f9d55e866746257ce17729ee96303ea2bdd9bada05f9ca5bba1e707349ab2a14b4369e7aa7b19528a1aae7b3c46aad879ddb4817bf3468d6d395a96f159a23bbde48b47eb6a1c3aaf6280398e27363bdbe45fff1b96f053d687bde70b5a5bf2e4b643ec27dcd1c6558eaf4f982ddf1e0272cc2e7eb1b0af278e421a6676059b102c0ce9f8a36a88ab855dfaf808a4d5623b87be742ed2450cf6b5f707a644d4f4bc8407efafab476d81fed165a8510b251011097deaaedde8ef827dc37250074950b15920df1a8f28908afc9fea0163895a3761ce54d28385d384627ade7f781d819affbb9e3fc0124810da67fa5677500f5fbc7704c145abbd66a047d306e5af07c25847b3e2ac763897d77cac82b8b645c12364aa54e2baa71939cd679faa3130fdefcaf54e53394118f5763c95d7f5d167f8dbbd01c16aaf5543de4c563da6d769a69930ae1a34056dcf8901072ba252d51225cb1a76de7920c2052d00b07c46c31885ab01e8cfb31897ad8132248444b6444a5b62b69b98dc1bab790717917fbb5566789f062ab8eca12945d48ae1e719dc59ce3871cd6b0a72c64da714889571ca5c3c7e8a9e166978394315b7a3674af2c5483441e4834bb2fdadd570c4e71452d9969d502a1c1a3a5271f6ec07ac4d5b4739332d4098efd5cdbebc9c746136295494278ae60cf07768e725a22444e6d523e96f707feb14d76dcc9201cb66049c2b94e0fdf32a57057faeb2f2895aa9c5473ab22814395df5f31166c603b5e3de54c259891e1b283396f1ab1e140cf0439968e66fb364cf33e8328ea7eb97bcf1cdd13f058d750cd5c6e4149f5bd516927805a5700f995a35a3a3189d1a3a0c4c4f667cc4254cf2e0ddcc044cad15397fed22f81e4f7dc2bc1a9295ad0346ae5fc45c5a5fd9b184ee277fa462d59852bc661e5213d11c74e65d2bfd3627ba4c909a50da87690c499d495dc4fd7341c9c0b8bb3e27d0c3b6e70cbd3095259cbed550dfb406133a988a31bea2cbe5c20104d4b922b33719c36fa8c7164c5c65959d4eee0d69b1da935988c77b95e212df9ee886178d68bfa31e59e3f01c3b87d819a1c1210dd4facd2da5d425c48e3423b7b8bf50d9a87d8aeed26ccd27775812e335829d39080a3eb4dcb6fce58a4510e4e81340049ac22576c42a0562f164c880b9f32f6608424768d4491552cef8c307ee04ce8f81362ea88de1595cc00c8d9540006774816f9d7715d1ed55022d8ae809ce2a18c027b23b33b99957af39a766320af27903dd45244e56f12e4eb10dc0a56181a1bd967577b4a32313b23c1e1a030500a77d390e4c29721ebfeac3fe744a2bb91c6b34b328f010f2e2bc82a20ab75623d8e1d7b14018ea3dc0aad1b55a0235a8b1b1891b4343ff1971f9d6062075489b43c4085a4d1466bc4bd599def928bcfa5882a200549945d52a89cb84e6c0410184efd3a525ecaacc1248499fbe7bac0733fdbeded0628bbdde65a44e0f3d2e40a34fe80ee2091c9845b6e06828f9c86239d3c2207bd9ac2c7be7b49061ad5a47f9954c666505ffd4f1b1c7b27f4981790fea1886f4387096be84adce097ba850e9ad0eadff267fc1295cd43ad1464034aec41594704a559a2493324e33cc0df1b47238a81b698c012bd6e8578f6c20685cc6dc80c8598daa46f8da266b4897015ac9cfb8d33317bf8a564d539f8ea87daaf0bf7df89cb5b145f0f431c949429422e6317e586604505cde881aa913e77ad13017daede493cb069361105d735a49cd85ab782425dca4ccc2c500756ba4c1a17e7d763cbc0dd6c00366c6aff0e0c7aa8d4f51131c7372a6466bf93338c76531fb1535b787da4d3440db369302d4c31ddbf3d556558d5cbd91ab91a409b5d5492972fece24cf02e3c9b4fc154a2b9680f6b31e6c47cebcf41bc539efacf12a86a208eb386aa6b3ee2b2b786b09d88f7a542c15fbd6dc250c13730378cbb1be4e3206e5177fe0d43efa29d8eb407177190951563d5e0d67102548b0e9ad5b730a192eea74905d0e79cadbd3a479f8aab92d2709b1ae4b66bdb5ae27081c0fc858200458bff002db2269fb244e088768bca09eb693068363e2e3d3e2621d571b08c85b05e76dd54004099c979af73b74446c1ce5bf634bc144bcabc3887090722f36eff26dbe869fa016fffed61c2c13018a90695cc406e8f5f249b3cb07aacfa922ee5ce86c205239bcbe2b6616f82509a551f0d2b17832c7548531581f3adba1890312874136b7172c823fd47427d794407105c9441bc37e39002fb8196de88795870147e198fcd99d50e32d660b49b5fce164421c98285b55a21ede77da919df09563048614ef921960f4cd94f4b71d350b164ee2c9ebb5fe0484641fcbb87579a764a2c78a30ad507ed1053d5bf083cf206729a5420199cc0663fde2caaa4217fec92eb740038455cc29703794a3717880899667b02e8f5e82f40df4aa07a898ee484ddecad3ecee20f0fff3999327d85e5e2d91da284ff16f0a4eaa5c92cc48c5363e4dd90d2dc80cffa8577447ca50c70c7e2cac82ef7d0868bc3694476d07079b6ec58c93aa81b14f4c1fe8537997ff652dee6a79321c23f44e7f19f663656bd01accf39e0563f2c0bd16709fe01004c314dff27c85f9ee6de1a2a0778ccb566a0cd10b1c77e0b59ff901a8142d2a2273f1a8d24cd2d39b59b3b4d488b24dca424197569d81def01ac52d83986b9a2d4e028c0d507657be5f4942901483ab9cfa883ff864256bc3e7c452fd0b526ac4870b974982251c111412464622d576c3b2e497fb3e9fa4b4b4fe928d02f73f4e16b839bb091ca092159b6f625081fb2f38b7a89f98725cef1884b29b17fb06546441c5fa3aca4f9eee1858e2fe4974e4b5030d22c729b544817db2c9e287ec556a5e310977e1ee6a001c2f49801203be1ea7af19cdb50d920d4599d8096bd974f1dab3d1869d5a1a2b027dd0506700d07e21062b6c8700fab0b2e81d5242d40064e4c85344ea656b0a08f0843aee614d541d49b4d9eccdb6a2e553443a65c1072325e9f2037cd5f61bd4c352e93688348f5b47fb9a1567703f32ce309dd5267824fd7a402eafb8ff297257889f1b626d7449c0365cb3e9841ec278a52817672b9bc8521f859c74ef003fde958d7810516d1a14fad4d69db290d1d3bde7f394f057998148de17c9b704cf18506c187f6d610e6da0a1ac1aab4c1129c53c3e2bfb40fb493fc564ad38b2192ee7f58ffe3a79b17500571087cdf01b18633460f084b54cc30bbdbec173ed94517ccef4873cebc47aa3d02b99e6e190e2617de04f4aa93ba673474444321a7e6af1d474bad78be47abd5addd8dc5137050d353c123934d0926de88000266f9df0e8f5553b6a5e55970ead7d4c10a9bbd6f7930a95467fce07729b1ead57c07a8a5384f8fb58460295701705845c47646d6a7bf7dfb66ab5f3b1cd349a04c78f653e12b3e4692c5ac18526b9d586f27251f09b0ccb1689406b3f69dc52c372be8f53ef41a3d067d8dde47afd1e3d1d7a977c366f05b23b35684fa60de37479658adf4723896505832a0857973d286ed8ef3f536eac6c5f14a064a9a0772b4e323647687f978237d59aef8cdb8085407ddf3af149a5504d6f7bf663ba802dec1a5235403cf043c8c3d8b93101e88511d88b7480bd94e05217d4ad95adde27ca12eee5efecb42c25d8084585b96ba76117919d7864da9604ef33387f1ed823336fc118b210838f4f8ce4f98e172f48070aca1f277078d6a3558a2e8def2eba321bbb94af7908f62f0027650c893adf7761953cea5c4d34c8cb261c889fd7a8fa45358a2596b64e20c6f930433499b67c3f988521cd65bb29a5d9b380aef2aa0554176b211c4edf28bc403154de89b17e219864c17ccaf098c4cf59270ef9535c1bfe21e059be34ed89bf1c13622eae8c07a3d8514ff7f82373adfccd49c2c5c1a2ac85301e41b12a3c871461476979b278b294e4874ac86e70161b8b8daf838727c93d54660031d3b5686361f4be57955604dbf97c400d1452734755cb22f75542e2e8ee6ccc5fdb307476d8e1d7c9a4e0c1a87d79163cbd233ef349fd984fa682e5507b568de97ebae673721a7c87d8ac61787bd039001483d63c1ee981bf8e837a49e3f3f86a5dfd5cd639def58d81093c0f0f1e5efb0ccf9443754a8fae795f2517be6ce86736097e2e505b76b1d6703cf13d0ff360db06d890c3ea7232bc7394f45f446cf4c9d9c4780ec3ff3d6eb18220576d14353456a30eff2fe189ce334c3357ad2d6c7e652dde9e164661267e96435ab984a9c8d5d72732591d31e97f76029c6f7200e02925e975a95459d7dc901a56a53bb783ce74d140e66fd590e0c4843407826829f2dda521fbb9ab5e9d82f0720a542988435eb2607069a2616da17c4d8b5af302383ebf35593266232d222b40f47a7a2200fff6ef8f2ee3ac3a7e02b7d5dba90e13fde67999d916ffb95d111d10ddd853d8b0bb2d72becaf860a167a9d02ae0a66839e67c67ae097b43de063c1e7c0e838234c3b3004660aa6782df3e93561f4930bff0d810e1fc4675c0313f3a131defe4a844efb55e67f24f2cdcb15b16da0e8d569b8d310b26f89e678a2b82c60c7f5a803e742b77e5a30a5a95d9617042071c18a4e10f0f49ff5586cf6312ced0e58cb139f53b1c43878821d96b18395228adaa2241aed62964f5824012fd83a0044941c56a5eb56752121576d5fff7d8c87c82eb326da356af689d0087cd97d3509a7a16a81cea6af8001cff1dc01b565116f04b97535775dea4c607d2b6e24e594f624416bca0f19dbcc85aebdf0a3344400cd6ccf3751e69c236139abcd570515eba886f5ee3b602b1b6a98352366076c83fc72c13fa1c6ca9ca43abb684def62e785863db795ea95e855e11e9d6eb43c421cc51e807dde4a03e3030019b23664bfadcf4ef308c965a0f5b37f134ff449d10eabf6594e3f04814eea9428319087322c62633d093f72955234d19207b564906afc674beed9b0dff19078b17823bb20dc751b220f96329fe6aac63371c47bebd271a58a758aecd988ab4544392d0aac6bd9bc334891197f55b8fab42b401bcd2034e83c8334c35689ad256cf8ad7d7675024f372797e10a48a8f621d840f83247e8bff480b4bb613d0a391ae8573b3276430500cc1dadddff5d8fc584dd13804599f67f2a5cb1a2055000e8a4411afcdf785c109c3f6e3f9c7505f95232f63b2d7a1a748eeca382cc1a2a549d1393c440d5fd78c76513946297838b9a442c8b529c1baf587b6d21feb031d7cc91e863c8ccf86c61477de99b22870b500412de9a07037822327f37ab80aec8255d3725054796cbb537694d4356d81cf8c074f27caef892eb7a39ebbc5f52f8a4038f237aa90a596de82e2b1a2bd8c56cbe6bc8a926066725ada42b0cd139bd1acfebb46a45389902673297a9aded4c2a28fd3035b67115c9d67ee93834f03baa9d35dec59a73abd88de4fdd9619b0624c7971b7e62d32ab56a93a3698c6d25caa9c3b6538b17a13883cf861ecc74169b0a392991084fd74db5155736ba21454303d76e412a5962075c123fd8b94dafb32e30ebcc358084721a1541944c183b1b4e15e910bf4bb40eb395d3956e042cebd5be1ef91b3b626edcf7a2b11167c2c03af0050829686cd38942234a65fc0ea11db8f4f2bd9b80948b66c80e42d2f09d04f16fa2c49d3e154b125fa90d65216550df6a4f738b0b94c75734d54b2e60a1175efa7fc224244221c15334095f5b5d8909f876f8b31d5e6de6571d4301bd4387b3ecbeb2c495a0638db2e8eba1bf8e5eca4a23410387d46406cfeb07ff9aae02179dee9bd2cd8ec925fc04a21bf5d7c34a2fbee2b640a88c191355a0475153d894d65bd49b6d1a6b012551e51689f81862329cba2c47644a538a2dff90a768e9bf1b5b372cc5609af46a883473a1560189a62c284bf9631f78a52a02c0c8f2ff0334ea73e2ab3594f49a05dab44af17a4715bab152edbd1ba97cc33e404a639e53f9d4af792c2347926fc165543c1438453a982ca0c9b828a051efe27bc0df9d17a1602a39860d8b9b677efd588cf7b28ef71657f4e72507af59fcf84221f9e4131bec7a12b0a1cbd8833dce1874dcfde89200cb534c6ef2974a34306ac8668090f98ae4f37064bd1f919f4929fe882e4b13ecdb0a6e362c63aa100f15bc471f52bea26c820f4cbef3a187cce388354acf5cc243f6ab0a584ac796e4cded40a42d595ac4eeaf44b9b787c108359bbe0ed8adf96ef780c4ffc592ad4547db9263b724dd6aa8859f921cdb4545467ef16528fa8c960c15524046709dbe01d5a2b6915ab51943f9e95bc3ceaa4c51d6fe667d783b55bec041e0ef5944a2eec42f75a4da4e130e2dd9ae71de824e6d16bf87ab092506aab4b6537f6f59f3735e17c80271c173d520b12bc96838430e9d74063ae248d576b66c58d0e5479b210d1a3097f4e75be43977f8bd9b984bdb68edf60e76f5a9664a74fcb2d8bccbba37d7b13f1ea4007cb4a24314a5db55204f4c5b1c2f836ebfdf37af0feda52cbae3e4c4627ba5974489de886c4a44db9bafac964041712011cb28af0e5c5f8d25edcf170c8534e56923ce4e061c3556bebdf5ad0d8458843f55ad1fc19a0f4205ac592ba1be3fffdf6b1be62e745ee044e840a15cd80938369c6c7e5dad9e62639da26e60d206880f44d841fdc2abad2c2b576f4caafc1a6d8e8ccfc70dc005bd861d74a1dd0fd26c2294535114f7518ad18df70cff1d34f313408fb8e20875903bf271cfe99236b8a1e9b75931b8974c483c16eb91069e2d14f8e41fca9da15f6dc15868a0df2079f5197623c7758d7ca361026d7275cbb3a0d8046226d72ba19e63f1690d618046eeaf6e0721a9c20d0c39ede1ae2e45ffa28db7628cd5c665525a1969e85f86dca9a93335d1303e4b1a836b6484e4f20e351568738a109311f9e9b35a4cf1c61d2ef2ce22be58e1627b9330c1baa6d02d4e342ecd95c267b94a1ada8c80c3355b9080760bd49ad58c4806d92000792314f1a265412c50b6d411a292684230b94fd00f16af9c69bc5c7907f1055988b9ec9aaae4c6a5c063c016370ca982732ae4bbac36c96c0df0acf0ac2d9e6ec81cc2c13541ebc7f327b625fc38c4318985dc79502d60a4a6510ae81abb9d82332ae16d7a3b2f9238dd5ae29a5662c8d9b7789548c17b6a81ac47a391517370960e51a9ec7d524dd86b2752648aaaf57c305c7ae6e1e695d0455489ea8e28aa59e1ea6dd423f0e4048d4d3d740ef1f2e7942ffaa3046796c5c5ae3abac74cd75884a75bdd6da6e16c69b50cafe85a5a1688d12fae8ea5d3dc6a762cce599c9fa5ae9d4eb15da26127affabab60e7d1f765fb200333989d36786097f086708e35b2ba837ae8d8d20c7827a51143ad73c0203a005bf5819ac9ff8c18e949876d40791193cfe365441a0e6346ca7f0962bd208c3d16566091fb6af22d0a79ba4f81816bbe3d47498c195dfd0a8f4860bd032d6556379026fa53f71037d29918d20595f3a6826872efbf69fffeffffaff2f96461e27a7e7fa5b50205a06d92cfd66dc0b654fccb16f5b871c06467cec8ed5c359e9a63ea40a67924987b63bc777dc68600f2dbc3933b0076307bac4b5c2e58e2ccde36ceba948c6491030a489fe0b149ef9d303f9f72f9b7d409c959bf602fd6756ac5a34fee2b3541b12c97cd64005de2cb87021bdd88653e68b4564c0bd34f9085e120411f43cd6e6d708d6e238e44dfe24450dfdea6273ccd841bc111cdf390d1dab2ee1c2abd392e04f98491a462b3b56a1697ee050efd4c15759b7ae7a43b365a6051bfb173b739c3ac89b9a8df8c47e65ee8f22d258920981de746e780cb8c60d44890882cf30e4fff9019d11f4e482728f96fbfaf2ad2b320a3a43e02ebd04e1d72301f56f402371f86d5a13fe2f5e20446e5af2d0af6978da1e86deeca4253540d8dd3a31ad99e9cc778005fbd55f3183850c2a2262bf39efd2e6ea6fbc8fff02c7a6a342287f3a320897d332a200551b423063ce7f81c75185165d4ac0de2aa6c1bf5bcd6788d1a9961d385b6112880e4e9e334e9139465bd6ff313c42963797178dc1a25df12cd0fec6cb620ba262d81cb278568ace04ed2d63a022272b1565c33aa14c503e5e061032bb25014684eb652c9befd37920852c385a937552af17c79796c809ad25ca21edeefbeb3caec19be603736fa08b827eba1907199d28838706c42d6b34a9a75e28d97cda5a3cada69f78e3ae1c9866a4d060f84fdfb6719d48f0698e1d2d08160d60a3993698df5eb2e260280b5c31e2f010003255fb72e711152f19694db11ee11e522f2c444c280b651d01fead712fe2e0f49c6c467d843713b5dac5e6bdcdba7e09eb592b287b5163e1e80ccddf78d337960bce5c443953270bdaeaa3c03be5e616a87d2b6e5cf649e35e208d829f07100bb79c8545d53910f32cdf6f514c02c21aec8434c4a00ae43adda04e38ee4af64c89a0015db5a8cfcc8563cbc1fdf7945d23483505994698f90969fa8ec2e0d4852c5779ce720d084dcdbb4704a208dbf9025e886cf17e101de33148af81701a36f0eec0b66fb8929ff9909b9c1205c5d4a888674134068ec013c32158238d782ebbba488f2a39bf7b0566b3744e2a40b7b42d0c63ff3d14b5f70100c5686afaf4ebf4406099e42bcde4821b0623023ff06a78db3b4dbf0cab54a149c1d88d6b71fd20a499834ea207e66e5de6bbba14460a287d9a4e3814a1128e8e72988c81f05fbc3718bf90ccb33bc7d3e56bbced2ae6c1c7ab1ca20d572fb5af1320a74dcaecb797d78d035850d1d83c304b85dba4feb6b2172e5fa5722f05855a2841e745b5dd98511c4e44d82381a1658a0e0687c00206ee75ca97c37175a6e117d6a74258848c2b8b061caadc6906cf4e59c82b0c51fc4f06b296943be900401dface811e24cf35eb5d78d338bb1ca94c6328de0f5b0e1c1936a7152aa8b028b4a1071398f912b7f8b55c3612885b07decd99e05faf3eda82462010234cceb44239ffa22371b0ed8a5afdb416c1f136e8b7f4a18d3c9e000ded99c0873bae3e1d0251f1c301d6b1b0d69dc44ca61dccc19589b093a7901bc918ad44c508adc2426010a029df19aeaa4bdc5168e5a511dc7e08e11f74a1569a27ce4aaf1215eba3401020ca6f88c421246f7d7dcf71fe02a0f53ceecaf492f56b874883e299dd4e0f1f220acbebb95f6e97fa5b588e9338a73772750fa88bf7d0d5337440b87e693f8010c0f735d290b4987d66ad4b62bcd36c570f6a411ddd8e3fb5ed99caf5b42e765bd2373143face32ba12078bfd8aec4e07377b560afb020f4f7d983fbc2a083988ddfa978d34b11e774bca35b07cb7deacfa5eafac3625f90e8c766d50c12f83989302dee826d7a0649f1a2f73148d89f134c2443535cb35ce443200eb473708acaf1c10cf70ec87d816c53d7ee26eb123861d834e33e9713e0e42997f14555ff63aba33744820a5209da942470d46c47d782b693e0efd0c1e8aa1619637bf4f41f3e317e6f148000dff08dd4f1339e937e9688f65659eb16f243a0c3339cd47de46e7961cc92677927028121b37059b16bdb25a72878a8147938d9581b8f0b782d297eeabe20a0b3df0bdfa4455f729ae75c8e7a8edb34d14dfa09d4689ec6f9e0d2dd6cd658c20dc70e69ed2e27127ef8ec7e367b0c20ae618239fdc14f91115658e8d866fda06a15dba1ae7613bed668dba260355d15078cf22dd63490cdb8bfdb803d09fec65011c817c910f9a380c7cb8241e99d066efd42eda93c8636033adf8ec2e4e44ac067b80c9eade933bbe42537d33e71e193a908f2729fbaebb48d740ff23cac85d243ca59add0fe6c97b264a1ad3f44a0528eeea81a4e32c81217287800b893f7a1ddaccc19bdc07093cdd7a327beab932eb1962abe27bcf908d4ee3e4178ca2cfe45f5334f2e909d7ba5fc616c8974e0de790268f1a091f6ee9760660b5697efc305935e45e90a1540838b63b4bb05369f4656ab1ebaa388506a153dad0dec203db50d0fdbd49db126e1a5de5fcabfb894aac824f56e58038ab8a0eef60f0238f93f0ab3de711247aae2e5b1001a54690bfec2667b9dde76070ee80d82e9d471cc53a478c6083a5e5fc91219769ed87bc1afc5a417bb3f7d015136c4f997a0501d0da90e5130d8e00ea651c6dcf31198c3202c9bc61548f89d6d91f1ed300767b5811882108dddb0bfb1eb808e0371aa4c6fd3e19be1e4ddc1c266430b62e7e677ea8d27865313848e36ac68423b966bca5468c9126983e933659e4ad83f332caa278b4d42c05a34b3f26f4046cac49c1b47dedfab970dc013c53f2d59145304d108380764712c038cb05155750df8481e7989cd32c22596f3348672254890ab84634918f63347eb09fc3b39d82050a655090f5ce0bac673b5b529be849784f28e907ecaa5085f86f2e85eb212327f50641185ec13b5f43a035cf832e12896d63f24fac224754426230dd10fd69788c4f1c031b26f6e7a789013439f6d9be14ea8946302b0e0694f5c0ffeba4719ede724cafaf606543b07afd028075a08ac631a3921bbca44a824af5270221c024063f201fe1a8df9ef4769023d96b27f14f8b77e604ae5cd2be65e36b24753f0079277aa84b8a87e995349c1f2372a01b5ebe25b284ee825a0df6d4e4134688c58087f6ad9a7365679925c73dcf9c2457a9b1f363ff962f3fbf53ff5552ded9a1d63da4acd5693a853e6b089c2e487f9d7464ff18fe8af1f0ed5753c916853dfe7ac890b659b5ae5aa4874ab1c2349877b6781208eada1da28f75b6fae1dfd8d5605b67d100de821981a0a1047401eb67de32514974e11a12567e9da9c0ab3154e751ff87972d9677d06c73b21dc696d80fb5e0fde12dfe9ea47d816d18335eed2f041e680120e8848515dca74c69f637331cb9f0db443aa3deb69e981f1064618cdb770889eee9a25beb9e0428b9bb1e0194c62a5845944b01ea08e7ce1026a17f0cdc9ebad2a050b3306b4bb3065004f11ff6399307efeaeef2ea77f612c91c9e6b1392aad4205d0f7666b4b24373e5ca910bda3aec141dcfcf60d514efe01016d2f828c1cc01c3a61487c23673907f71bea8965ebd8d140cde667426707228a94d0171a71002b1dc212de099d6908e8c8878a4d8372fa48685d3aa11d785d931edaa552dd7c3687ee8d2c3965562981aab8c2b81258f207c1c8e459c6c65b4da6b8a6be13991a427f5b826f9993d2d9152c7c91b2e9e9475d52da8c2cbc1d40c2d0ff5c0012ae8db1fb9436c74c92f09fa99ff5c105e727fd20532b8dfe91180935558ea44d26b597a6c7c52ab1cb9bc4d47d9344e205471f4e0d46fadd966b2a3132967cd9cdab071e78feb8ef04471642c2761ad032664c0b53400d2caaa050b75e23b3c6391f1e8b82c78c0cc38d3d6374f613d1fea5ff3a98d46da12ff0aecdb5853249ad77ac54944d39ccc087888d8dde2a099c40350cffd0935ba2e1b49dd0290e57f3d6c79df1eecc77a3517745a8a4fca4c6652996406d700d7d17117d755f96e41925811770376c29c1c36de2894e59ea4c38f3e16234cf144a80ae24e11339de07208bbc02b38236b842b131338430eeab02ff9a6fb79deb51d8ea10a48cf5136a3960c2b46e3cdd1aea4f9d202cb82f138addd254505f741a503a8f221166072ee0a214165d6a99024e0b5aa6c3f3f10aa60caf7368950b5be5e9b9cc8c6a8925c6f8b7f30c8ea37aee239aaa248870af9f0c3d9153c08668aba2448754dc003bfded164a207110d23940fa826aece5b39af807b7a4339a3e2052bbb61cf9c61404c93f7a9d10a539dc1f40de3cafc38bae2ad5dcdb30b40abb61c36ac17409deea5da74676bf00c25c45acb9621219abe297451c325fe43f1418b3d26d52134ab0ba3baefbae8afb3b28bed09457b59651a51484e29c8f2fecb57d1bf2072565455e3f899c2df4d09a05d25c3f89f3c9ce75bfc30b1155332abe234987f882d469c0ff1a2d50d622f4154619e825f4491c876985307ad101c496a63767328cdadfe8f34c300f6fa077f41cba7ab69fc95dacfdbdf7b24b61ce901fd5eabbad1ff051cd3573695cad87dc65eab1712032ae72d74457df78771b114e1a61f84394b287594e7eee59fa49ca2f39823df67ad3d4444727ecf6ef509314969a2f14389c1105a5e1451a0f24b37d08ec8d738f89b50d6787400382a4325e5952911147028ce9cc5990691306b8b9c233727a841ddf9f5c82a3a965310d56f833d8d7963be6f292c41d7122930c30b041c16439620380b848d724356c21253100bb1c3292126196f2e0ae81801c8f9d10970e1669dbcc304b0744d8d12145021b4c1fac23620234063944a1a285f40e03c16b66a39913c8d5421983ad2eca9020a2b6594262c92652d4f9833986a4471b6a485f653328b547d105b4bca6e273d2ab7a3877494f24663982252992b5ce69258f836b0b09ceff610a350cce368d824a0fe4294f542b34aebc24ead0fc18ebb68d632b40d9028eccc2466872dabb6d2ac939552b7c296ef2473d3a9dc3bfda868324d6beab3d29e1892ad36c5ff5940e304e798c7ba554a2f1665d1454ac5368d4598f0984ae368327a277b2d010088e375df15a7b965be9413b63ad8a0dd7c42e1a6e1d107b21c2f39ab5005f380f4a3cd8f33019b26cb11b00bc8cd4ffeb87bbe82b524eb3c6509141f797b3d8c280fa26746c7e4b21071ce75bb170150f4fdaccd10e680b4a23ff1e38b565c2c0789a013cf8ad20bd0e1b4e353bb08893e1124150d1dec00943214c11eeb9c520bd4f66daa3ff7cf714c9080a3ff68846ac382793c474a5c57e359556c5f73e9e44c20fba63a236beff3c368ef8e0bba82161d9f59759490275c54ecffd58bbdb8d8afa833b8892af33ecad8e3b663c028b150d4971ee5e2a15c34ceef6f5dedcfa881ac772e38e5820b1bfa9b733bd0241a8a26bc7634512568326d78d8d81f9fbf3a6cfd302a2a6cd0b730032345db65c9e5f5715ad5a049e4f9809103474327b65b91e40fd3a9013f46be2cd0511af37f1a91ec7f1a2066c546644d77b8c520dac1a800075f4d7dc990262dd19aa7abd07333c5a7c50b62ec15c75e92d62848ebedfe91fec81812d937e0874e30fa0feeffa7cafadcf3a840c33599dde4e27bd065a0208b05dca334c85266a50696927164e058db26035fc37b43208254c537dc9d075049fc9192a7707600e05627ceda09d2797f5d9e7853c4e3c1ff0b1b04dfacf1547be49e80734aeb4e9955296d480592140b4b2625195a903f4a6ff37c21650d8172214a54b87c33436d9ba814cc8a7f92b7e00d6cd9dca21ae2f27bae9f784627f1420c1546739e4ead602e3aa183ffaadb26077c54495b4648c0170c2c933fa605e4b31b8c193ee043fde5001e74ff2ceeadb797d8b99b493c31192dc49b6f3a65bca627ef95ee0e80d2004a1f987809bb8043bb9fa293a8809ba369b03a2bfa2854d1624e48bc50f89ed899b79322fbf652a82335e418445588006a690c8310fd413d249f242a3fabb912d47b80f1275ed897ee6b1549bd6b3009483e983c6f2240197a8133d355fe98d552036e6e332f1878190bd9f0c55960bf9a8461efcf50ab6ab075ea82b306a3a726482ec30717cdba75c34827ea2cfd72738deceead79fe0d8e9090baa34e30412cc56786bf20ed46c45ebc5a677932b926fd01bf1372208b7d9068f5d3df0d36448852ecb1ceadab3ced064a6231587856b47e334400413683873187861652d58ed20adcd3b7bfbc199a64c60aa36119f8811a371d00481874ced6c2e5748c8bf3885f863f748e1deb44534125badf88ea4a6eb7e3155b641f4a5a4d38c0d54eff58739eebf32bce4783c0a9d39e2fd2b708c01ab34496f23c1aaa0c8c8c999d355896a22b84365402ac3ae28b4e4bb897fe72133bea0723a7a102523a3052b0780e6f62551fd3c66b45cf05cf6cb9e707fa4c4426974a6db97c355b9857b9b763383c5164644fb91767fb4a6fa731f5a056e8f9948ef5d91e56fdf6a610daa6e5aab976572004530d5b575c111270f9ccad17bec6a5f6bf4c0ccefe3ce79728115c788578ba521af714a923b841e99d08fd48b3570c217a8fa8c922b6c1ab8c05a754a17022de53d3467c5a75c2da6575e48bc3997415e5c307be9a83e5c2530e5080fe8eef911c25e8adb4735fd043fbda5cc3a45e239f8bee642ece317fcb68e7ef7c2d59df1ccc85c66b3b2b8131c37b441d97e4b7d6163348fc0bd0e72f515ae7c7888ec7d08a4bc87145135f58f47566c0d47e2b33b09c566aac2681028c20f6c735b0d0c442c40c1e1ed25a707ab2936dc52911ba73cc1f042e9c31860de16bade416710e36548ad37ba67df0d265b008802d13351f8a82602b6912625324b2e0744702d84f3f96bd4edc419ef00544e8bd49833db5152203e2314c91aefb701e3affee534af229ce0379f9f510d1602869a13dc218f1a87927439eb149efb53ff67ea6c53d8621fd6270c8f6c1bc00fb611a509bcce134f19498c8f985226f2015593f5e2c73c64da9872a822b2a079dcc6822662452c2ad5407bcd1a6c84381f60e9ea7a36b03da2a969d04732cbcbdf7d396d8b682ed66ce325f03f1f5e66be9449db8e0937c8058e4087b89947df90b0215d842f8ae70ed0426431bee794be4a118ea8a794ffbb3ae40528f9ea0431742898e4e9af8e1c48ea4a12c4acdf174d7245d3b9089b842251e7be0a0134ddff33f42d93820828e7d6f8613a8fe5520762d43f69af7d397c14bc55d1a8ad03d89e8774f895eb074cf3560b7758f261354e8cb6db1c3edf237a89c7ee3a515c50d76a1664ae862cbd45d241f066547ba7f962c2a7d62736481ae7630dc454fc4d950c7732e1be44c15d6001e24ba123c165ea4831d929dc65bb4a912afa333b59c229ad44de6fc7c1075d01851d9189ba22383e00675c1812b59f2b1ad540c6c5aeeb9ae9335fd5ca0b8e58b182bf1d458e11911ddb1f04552943483ec2cdc0b4493abc96b4c0db91fece11f4bf6a42231ce68b918386ae8020ca2f19753edde28905a0192c80ea727033af785dbbce56a71560f79277311daa1df66a9dc47825ca4c5100699f9b4aebb438705752600fcafc1a8c08c0004ec1201e2a48f0df19ff5d839abdc53f131a021762c5550ceddb59c5fc49dba4a363414e3b0f6d83c91c7e86f368d2303ae287c1c6e0c969b8ca7287ece25a0dc84f4bbeeb51f7e1073a534f1db5220c36cafc9f0d32b2f396d6359e6102b5c1f7e460d60108632cace2e802cf14eb10c826d081da150792b349560f4989c6b48ac00db2ad048a093bd122a82422a4b57f3be7249cde9dee199493831f0f888393b5671eae062438390dcdd970ea079b4806d175c1110fdb41cb88f217598dac84f624e01d1a2b1ad6400ee2095dabd5631beeca399115cae986fa5640e8e79803533fb9d3279d8ff8c63a5c99998d1ebf844e209960e6041638371fba1746df7778a1e0e513e6bdf0641680cf5c330b55e96377860d1527efda7697c37611a5be64935f0591933d96fa53b313fa43bfd10800a1f09806dab9f5f4db1448c7233b04e0f29d6cbf4f0de9e713cbcd46405702bdbe442758a934f28259899b5e28a0588eef5843f1f0414be0ce49f46b7594a6e030daa7b2c4fb226c057b8e0db8cd284c497670814c129397a39db7058a8f8e187b7f23548f90d1fc93398993807f69958de7d8c07fc7d6c47709e23c84131d33b03c80dd5e480685e55632a96d1136383ef88c2e44b39286fa1e3320c7223a004f9fcf1088037c51ac1058d6c873cca07bf9e0f29ba09609fac47921d4065a24946157a87c7f56b3416fa34fa1a6a1342a0860d13ccaaff835799cd3414cba1f07daaad66cb9dc6ea7dd9ae932389dbbec13ab7ac612855dbf8579e53e3b8dae13f5811c5865e05e772117ab6e9316f1a8e8e348c5ff74b465af58a8ce23bc35802a1ec64acad61f3132627058e68235062f65278d6dac7159bfa0980db6ba32a7066f9181312e4e0f85ed4c6c0c5c418d43cb0a5b8fd4232121e282d3a5ccff670949ddc03bda198dc608c7c87fe0dcc86dac8cada140244443bdc52322b75210488be01e52b7c530337cccb0f89c53d418d00ee3ab4e34be97ae8df7420abe02096e3b319779a982fd716741ab8ceb31b39a7083d3887f38257ef8b18a9020065fe8f3bdcab0bbabad8a07d643546070c34da088523ec9915427aa1a2f0dedd4930df81d1f3851404c5c8e8fb4f1b7139cf599a5e44a930dda8f4894e926e10be980020bca06de2affe6ad35e836526bb274a1c34d434d24dd5e94272100882363d3ca1b6039c530f8fda7ffaa46ca44887482d609e938d1c186929f0dd2c35d1ff8e0184af21996f8ca4cc3b11a04fa4d0581f8a989dafcd51311c29b7872fa708b37f9c2128f4063e433738dc80850cdfa01ce9a1ec87d211cb484f0ae49a0b8c1249d42201d4b1b3653351b25be4f0bbf941b84ff10c8908c85716e6c8af17296be3a892d1c87b2cda242d469a622f78771b962b09c08042b87a506247c19722b9042585375de00ef3f9f6fbe073be1916cd064384eba032a6abd9a087ce8464d25f67e09399e3051cabf10c869e54dca3e774c28e0e580e0d7697db4fbe61c769b8327d28cd595750695d729c5eb86466964c0e5a51c7d6830cff4a5bb2c0db40d37e9a9825b57d1e5a4e68008bb29b06df4e451c3cb608f07278c948c7d059ffc47f4ddd2212248182f6a0909b70e1cb8e157387bdfce15bb532189015256a0a53acc85269792539438872a5c5e992e3eb92b4ea95e45f99ff665cce546b66f08c4013a9575175a2089fe115c50032db4f7629e038b541e4b8af56955dd047b79abf2db6bf6d441ce208a616e7c8b9e44028f893dbaeab6ee88bf11eb5051889f50b5442472eb6e4a1b484f24c5b7b6a250c399d5c0a82c58e6b7942dc0041ca85685f103ef646591f8e249b6750ab6fb9a3cac145e484215285ebe4b1ea11da0a05235f148d646166cd17a534f419ba10f509a48a51b0066b92006da95be120f753a8a2bb606413c688992d78972a3e31e32aba0cb8e672255c0dca33fa158179cfe29e355c62813542474e683274c38debfa5b4146182544961e17f2ddedd491c49aefc53abf61f6a3483a50dc724a602e57b30d781750c8921b5cb2ed844b9e42afe90bc411da21f3154d3214878fb5616db361e74a0519456c927dc6e28e431485e3dd8895dbf86f7923447791d2368199009005cc515a1a1f0b1b81e956144a28fd647d38369c21b7843ebcfc00d05f9474be87aa63a086b3fbf3f931407711944ed1036a72428635e1d03e5f80b9e4145f5d0a73319205cbd5e431824b0e05a55f75fb11b673068e82c245794d5e96c6378d597b9eb0a8778086b20b06853c23433bc610c0ec51785edcbd7001866ffd70b40a31062b0a706215dd32fa97567052fc956dbc13395b57d7fa0d51b2ed35cb1e45fa701150af8c0da68f83123b957e94de757bfe4bc5a92efe21b195ce41dba784817c1ae2a3a1483a464a86c105c2d9047e8168b226b1646718d0d7599bcbe96c795a5496d45e48e150fc6182a4d819eb72080c9200b76525d65aab2bb4d84809342f274db4ccc00bcce8904017201ffedcba0c62611f072718e184411ac999f246b14c0a97cb6c9f4e4845e822e1d1d1d266743908b0263bc69d839e5a48ce9bc679abe5b85f3c10d7fc05a48a0ba0a462e336b79fb2d043a3cf3f22491d5ffa1889befbd3bd0b6046586f00f95a2b502bb9100a6cd6b4e65600fee17991b625087afc690ac27410a359d8d602f0c8c4899b8c872968944414db7a12e719c36f2e9c5f75615e4599946201aecafa34de5030dc70c7e74f67182eddd0b2d64ce5d7b72557e491350c17a8791e99d96710ef1aa1315d3aae40e68f5a4444c556c0d1cb7f3c446d8f9115ff875b7725eb70f689acd81f32d819849f834e3a30ddc55f292bda2f98293ba01bb6e73bd480e53aefb698d2f76507d33a6ead61dee820d181db9c85610c91a826c01dbe73929a0183bd695ec26883151f6017d776b108e26f32b8c14389eade1f9890861510485412e3a684999dc5c058bc09b4e06eaee0b4a24803047226a9b437761902067304c6032fd5555b621ca3990fc894de5aa3348c67d2843766abec6984d207819f890100a12c23ab34002aec42b1fcab63c252a701cdf08c119e3ff9827dbb6414229860ddb1366d02527de8691df076ec49ccbd0efc6005e48dcc79855c0c6c070d92b79cbbaed10cb5d5b5b1fc2c798908ef54f273bb8ee303a3ae7f45afe80a038c1776be59f7c331d3b0d7deaa45302b0e4f6956f4c4134a83a7267807253d72225f117feedc8c5747b4aa6fb1e3d022c2c357a773178f1462274c1d151d2d3a6b28ee80c381719445ab092779b34a9df97daa8857809dd663eb6e84078a023bf2890087fa9934a904a25e377b7ac4c4966c68dd645fa969f30cdca309bff1bb2c6fcd4977709c843d7da6d49ae7610d24823c381b0f512c42211a434a8256882b34575adc93c6634bdbc3ae20640240ad7e7c19e107f3162e671c7a8d4db51979e7a87dd9bac4dff8a7533cac3ca7ec9121a1de6702640171c1c395acfc64a7491ed81812d53460e4d31cc286f24c841442d82711488bbfe9bae6005213442a0424ff8de878c2098b42407c8cddcc583723d81c0a7e24cb558f38c5b88fa1cf2502ae22dff9c32d86b9c70b88839f73d8ccd63d3bca8ecabb8455cf53dd888f73944bdc361e12b6583d954dd12a14f43d71f654d119e4d3fcc2fee2fbfda27e8a30471d388b656b209ac6eb88aa025e9aa7e9e02cbd83a87ba1793e8e3d6cbc99e08f74794a63e94aae0ad927ffd060ae66e27a1a21b1994e19a15038c566cdd303954711ddc5f6cf609e4bd0d86602f1418120d3f213aa6761032b14d9eb242ba1108b33b65c75653236a77e6271161c3e158fa243085f8d61a26618822be0065c89baaecbbb8d122b206956197251738cffb6258beb53448d969b60f6b7dbe3329dc840bc4c578b87209fa33bd24c1991a2f24be0d191b80158b4bac41264a2cfd9e846fb510e6b37fae82fc9d560fabda67e2b29c9bb2a5c6b44afb3c0d28e0efceb9cdb58ebb24196a40aad70433e4b068cc695467ecc1c43d6637532a55f7b42f784a34792bde57242b4ddb72b801efe2663db5aa011de1cafe4332d37c7ee7f5fa4e526fc3fb6b1cd8e6b5c3cb0c7ac7aa789ea9d4a4d0b45c62ff16ed24695a760108496248beefc5f7d2f0513595f5541e0fc402592c93ea6c9a160e38d5009f43417460254670978d967c55e600640dd3568620306f5800b0265510c358c935d68b3a50805be39aeb44fe74bfd7249065c9331d914c6fc0213be24cd549d7769ed68f8ecdaa5c18b9d42559a1290512163b0b414cfc26d08096d582abb8846a191c7035281df2edfb85899594e29af2e28f269f6034783e939aa91ff560a71ddec47e43f2246191344b596edf24c5b3c96135cee105d1b63fe00d5ca88a3e19e49ef0c21e0e5b1477d966a9d3ab09e26b77c1cc2d79602643b4876a493d86e6fe61211e969755461ef008e1814c222b65ee5a6f64959fc5a5271e9871e5cea808fd05bf931791483a2cc86db3d31ef57505e5d293f73fccaf956204d88050023a37215f9fdf7a723bcc3530002b93a323d7c511593685e806a6a82c41758742f132ec3fe46f9b633844bb99531871516213b80f0cd8faab289a228dc90955464056ffae3fda62d7e78261d323c0d010320f84dc8fbcd82a1d66e77002a3b6b04e8652776febcfd400444fefeee08b11a5f691e2a0f10a99b11596c619a6b8799302c1d20fd27f3613d39b029832dbfa83f6e987606d5efa6ff05437d54088ed5e12eb85d190e6fb7491452136c53b39b8f3494bc111be9caeb9043bafa076b6401ea33beafe05e9373337e20cb60365e4644a4dc8fce41851c58a9027afa91e12bc9bd29cb4825c89990e9ef3e3e3c2a0f8875c921d7450736e449b3a4dcf1c6d85b477d5f90605e96f972aaebc740f57c5368b0326ba63a60330be901db8702c496dd55073b3556b49874b95054af146347fb7b0fcfecc5e560dec0a0dad267f82db0abaa2602cc90107972f25bc44d8336e340f68666aa720a2b3473a032642bc565066ed69e48fbb4f1b7b6b25a9209791d014fdab9f644d4929408271fbd39fd6ea8014ce9f8c73cc0d3eed727b58ebd6aeedaeba1439bcbaa1ba087b76ad83152feea531ef7fc04154d52e7ffb84688b8a32703b49497ba8fd3ca0fd935a40e80b4656e8caab2a661f8bf7f64060ea94eb8a017601b6b65a86fbdcaedf9f88cacf6c5664f6cf3d327ef7970da3a408dde698c9adcbf288c758baa3bec6c56e039ebda448a5a740d702cb51c124484e5fe067c9d84ffd7d74fd2c35a1ef9f85bf1ef0b19e9c4e0b7b56a5b0efeff1b811b8184c906e630cd6e3b0cd0803253dc6df6720cd826bc7968a4fcae01ac728500993a9bf43dfab089b957612a60946ff0a054ce8b8a22574a3a2a3741bc15cee76afb1a7c4d2fb30188f19a5a5c97523980a8b036fb7a73ca9a4135da9010e7687344a5696667371872d9dc7b0f573e83a306b25835acbd6d82fd4655f557350a5926aea9bc9001602bfef78219144125ed36dc718d8f68dfbc221e32826e75ff202b509f05d46223414473a1cef9c62401fa050253d9dc427d080e83f6d1043795b280659e014320041c1009b445757de9ae7d05094c793c065b272812ac2882be5d8ef2b24ec7cf5b0b19ebf457f7cccfcc78cf4717036c0c320f1aaf8329e4a1cc9918f774269529194a7c61d4b98b57817c633689d2dafa74b16e83152a5a4710af737b2a8bb218b88b217057be1b99f665954e916a95aa147f1aca11a7bf2a53981c16209a42e43f74ca03f2cd51a5ec3f096fb91637786edf52030715f8bb05e42ab005737f669343987424198f180c1b1d091f19ccb01e1be2c2f4dd81ff156da744c982db9572d101760b06ce8ec117932187011b2870b698e4741a255065a1a7bef743d7851f25ef7af88b05389afb74e4623af4060f27328c60862dd03f60e2e092e75ac8718b39ae3825d8886970e69b46040951da1ba18df44ab2e9184a5d11505e02b57af3764ad41d8baf6a09b418cbf1469c05a3dd4094628866246fc2acd9d71d11b63429fb630121f97290fcddac3ca5a7759b883a6f688c7738120e4b703000d0e90e6d01369fe4d4df01918d5c7ed70ec13e03403569106defd3e231153223bcd86911c860ac127f8c517a5d5e6ffce32ca921e301d2d93c30eb4ecc70dd42f42603ff65f32fa9d0bab10815d7781f08984d94665375e4afd2da520cffdbf405c6ee79e35054cbe1a3055e5d438d5cf0bb58ed416af6180618e2bf6961976a46ecd6767911180faa2fcff356cb86349b2cfb0678aedea53a41da34d30fc3ef8c6aa9a0b3482fc9dbb365d14e1350ffcb6260f91b6e18bbb4a7fd8d5bd2c1976a3e9d88254290ca81d90430be1dfe007c03982d30ca8231433003cdb5e674d10f0ee6df4c22daa4b8f059094114b940b509960be05ca97decc9959e3b919e28140d0770f62becc7820f6f955a57e6a2b222323eb77a54bf3074c0137e8fc4fdcfe08b02caa60af9c5aebcae6a4646b7d19ec3fb6b7a5e4c01935079c8372e129d66ee4f6e6160e04a940e3076cdc3ac60a1be15c7809ce9e1652829c6356d54ebf0481279d654cf244cdf22ec81295709c27b612b382e6a447b2ce161f648ec7a0333da72c7af7446b199c5b78182b65628a394ce4293b6e4b7decb9502ade7a252ffb378d4a9997044ceae7f16600e2a27e5f4cf317bf782698f5e8ab93b5909407df7724b8503ee1412a0eb6f9d54d1db721192f8d547cb61aa55b0473670133b46b2e07450761850c48d3ab4d40a9d43bf9a9100c3b424a3c5dad9900b02c94506a46b95685bb615a42d7de25c5e80f3ee5d2153cbcf14527fc0c603b60107c7a80adf718eb1cc96405113b8d02f07f16796434e9eec4aa4230f17aee99f3f88ac3171217c1d2c5def9b5e5d7a567c314fc5641cde8265150c2d8c396f836540a9631ebeb65158619a6cde19bc7a0917ee95d623130fb4aaefd70e24a0718c88e75711dc19983d1d00a9a1f8a7429072f2575901a56c195d4ae9afc1a0ac0bab0807938b2432fd4d26630230bbcc105aef1ea5c5965e0e537dc385da2381efe09da1cdfe872b3e57ea74be5f811a55a4369038dcb16a1e87122a60b3a5e8a219a6dc41a66abf6af59e4697bf3f7d924ba11bc8dc03614d14bfe6c70f5763f6a9779444a3f196646c1139f1c4b21a813cc9a80d39e61599850d54c002cfab648c852e85f893799f78d5e420e8f2cb312834dd4c82146dc456cb5d07662934dab65dcb35ebf1ca2b567c4940ee564854f6ea25912706d42094d6a23dad6a150ac1884c810154fc633670fa3852988fd6d563440cae2feb35047ba409286e2af782b69c1159c08d523acca4582e26f29043decbde4876a9c3f0c4ee5847bb9bc80d70171717f3a4bf8d005cff35c7080387ec65ec81a24e0edc11b2306a396e93e6441b15697d910d9c20203a970848a938a2ed07c67fb82dc2c4e37312de59aa691eeb67a5a87f531f74dcb516fb3e12c0063ed69b80da8b07a0c61e89e84ff62d2999f32bfab192b4a21b81ce097ee6f0541ac82a0db6cac0e6f0a5e2c8527fb7455af2a2d94f0e53f553ef4ee635f7cded4c485e0657df83ddb26112fd1499e08d8e1337572f972007b30ce47136430653802b04a1868b24be6f07351e026970b573bfcbe4e706c0071073a40add46ba4db1019dba8c3689ef64d6a401cb2a8099acc084652fb0eca614064bf2e79a1148e4bf7c79ba4f47c047f4a704ebd81b954cc8a17caebefc4d765c7febcd1418fcae664eb5b3840acbd326940cf0c1415bf79aaa02b7840a8dd9e18ab513a1cb48a006b46cd79b3ee72a0b3fac7715a40cae505f226d691e5f4b5e12aafc9440c46afa2ea1e0a9ae73c30f32063d42100130b147954068942d49ddf77b3397ded414bf3a1df622a8e4b0fc77dfb4b16f01f52f91e506b30c93433e0b5af633be49c9f40dbbc35bc7887797a99dfebf252680e2b3050277964f1a93a4ff8d35561f84aee99dd92d4087884d8ad1c6ab936c0ffe7cf4a939f736b42efb8186f97fd09a3dc15c02422ce3450ea4c5c191a9f6c4f856487a396b4b6dbb0d18cb939803fb918a757863b972be452cdb00066593b5b55190e52babc19e490cc40b635c5800798abf3a8c8896bac372face9ae3f40857ea06deca74542ec9afc8de3ae3a38e869704671437a91099995d0591845674ab567a6295a78abd8908ae2577df728ca7fa37e12017a474cf94bc48145ea3e87b24b7609101264fbecefa12dec3a92f63425ae08e70fd92063b04490b2dd1b421af24fefe4dbc6c9e0dbf452bbd94744a81d2c4ed63b18a2fbf9c9ee112e5025f13704959f5587398239b3c11f70ae52780d4de66820a366b14af60e580c75b4791b17a737fb79a008c418a93839abbacb3f2198052a2f2e86bb176136274e37291f48aae218477176a085739a15b92faba87af389986eda11e49600205a7219aaedcbd116d1ab4f4883460f344c3d28749520fde3c55ed5936b8e557cd12e74155af547b7f8101a0efa15e43ab49261055766b4d6e090e6709e41b4d62d72470f69456159b5af0b49b6182388fb8cd4337167da559e5e003b1974b01c8a88824f1c8fa4439c0199489878cbcc12147f38a9b9036bc53702c5c32bb3405a4e246433a279b67278ea2d1294b0402692e3ec064f7b24f2019e461e87d315692f0cd7a80ebb3d74f51757d9afc843dff3f4c8168c3edfa1c8b890d305b70a992cd91eb43e630dd916cf8c1ebfb0f1205740be7a7ae3d79d6ce6e6cc5f239ded7a8d1ae01f0517b10d4d7cfb41f5e10b08d88edfb7379cb8b14784d98ba399e24d8500b1eae6afe3b53fb43413624744a163239e73fce9ad202a3d965386babd0b602286480b07e59da8c0d6bcc71a1b0e0271bb596fa5340ee4758d6be1c2791f9d6d6fe169277f74e0af066a59ce4325365cc90df8c6ab7e8bc9300fcf3b9d33334edc38f224723d79a85867081c4ccea2ce550a5eb973c01bf037a69622970c357ead46b867bce4832d39e8344976b0f2902a3b06bd8cea4981ade0c8bded2e235a641a786557648f0b0c4da389a04c8281a556827949d03987eff4c32ba24ea2fd70bae8476580724035d024a5311b54de73e459528d88f20e70a473a38cd48a8fa96b826bd079a2c5910e3c6292cb937bb9804b59b836bcea6cee87cf35d74216702a3c5a90604d971c939da147fbab620600bf43f6336e6260218bbaf62d320ef1ea360df02a7d7df3b0f8c3e472b2912ea52fce0eda3208dcc5256a6dba43664c23abadce7cf6e906d2550c29700ca43d6b23b36845f148051c1e0adf85a178f3c87d6b9d01cdacd7aa8dea001ea9d1ce24591321ab518883b1e107a7b6d55b6bcec93356dd084e879ff22d55866397751386bd01393237825d30d0ce005c230e87e4fd0fe22a6a89eebd7a10d04d780a5624bb2657b5642155789bfdf0397372433b1c519532db2d2046552a13c574e64234e51e14ea2206122a069a638694d0013db363d50e6c5f0858ceaa9fa5797bce9e2fe96b3b07b30d7fc66fedade73a70717977f06947be0c539404daaaf7bf9fc07b24e7654da4951f24ce57a614c23c19f1b5cfcfc62ecae6a7f7b1db80963e802c7754f1532e53b4338ea1eda9e8975684fc2b7b5ef693c0afe49813b5803ff894acc7ac503fced347624653376263120f57147801c487b7d06b4a489c7cbe8a4d257b80e493c7581e0abdd1502d9665f6f7669a059a27fcef78771b153a3ef2cc2aa3c86d8422f9869962c2bfef8d8c35a9ac14fbf08ebb2bd74a1f0e58efd97aef23a37185f048fce21294de9dee17f1844dc39423e8e80fa46ba88aa9031c4b0dc05ae7810e12acac4399974fbcbc870eee1bb8c9737c5bd820c1d627e8152d1dc7c53f2e4305073246a70e38fd52c5dcd7e888a9ce29b4ea6591308ab30bcd61c905873b6ad781edb7c69fc33679f23cacd96f4d93fb543dff517a83452b78d366973dada30c3ef667f3b77180112a03a47ac61aa7561cbb1377b35f944cecbb70f2adf2090fbf36b355a4ba110ecbe8612680c2c4ce1c3b3d108c927a1295739eed73ad2344854d694aae5e3da8616514189cc45afb38c5c9614163f4d3b49381df57c06b1bd6d3b78f95c596eb5b4592e336d87a76d84b365547463bab704720a8b54bdce188f7a350468f80dae2bb90a4f693c8e59c3a06926611a94e6f7caa5c66de3cd960db34a7d250683e3ffb4210f0906b8a05ec02303377e66c236eb2649ce14e95cbf510a951fed229fb1acc07b2cdc8524da3b2c4da53c51c573d340062cf759aaa10af3eec1950d07f86f839e68fe1f2b7b1c4393dbd848c180ea8906036acf219931c7ab4b9537ded65be86525e3f6a2725e17f4d2ce1aca6388905240387c13b69b51c938800743a3328d6842bcb4ebb7694a5f67ad7a103ef716e18229cf8ef83ed27ff1ae9f5246285de14df42e59e92e19b543e9709a00cfcc068ceb545b0c3fe29c4e940e70e0b7c438e7f33c36d0496feea47897890fbfab388102efc713f78388cbdb800c07b27c7b3a4b250565407866b1ee8c1030d7807f21d00226fed60bb6107c39240c6daf0bda5737b0d050dd313c47d6ab2e418f9a858e2aec06d88c17176de2215065eda699bd94f15305e1aac8c737a89c682dad746e7719f6abab762eea51a7738ebc1b0595438f00065c7c0a6e428f3b42b6d5061e80953cc3ea3aba27849349b4d3c59542d59cd099122bfff13ee2fb9a512ac2e1d43c84cfeb06953960e735177d77ae84b3502645e06debd2c75a51fc6f27f0a060ddb6593a6566730f23ef57ccfe40dc8905d40104542a10ae070cf45a44ba4b20a3849f6bd550d52604359c9baa2720ee237bcdb6d8ad87ed0c53615555f5eaee554485dc77716eb237587d8d1624ddf7487e9f21512e5489a024092d35af1d9101f213dd1f4b8349ebcecf88fa8a51c095384b84cb8f951e445c55e931a169de92491f730ff5d7cade355c54ad03d5153e90575a3b9e18760ed877d247458c8395536316a5265b34e475f9fa0d8a3851eea3acf47b322b92d54c66cf7d1da10bc7d1b1b790e68c45cc1cce1f2c66667c603a40aea4d82b6ec9a8eee4f6ab49982971ae5a0d3d51b037102ec1e65cc9fe2d57efa3adefd13858ad4706f0e057abd0292a901850940faba635b0f4601c3cc47b17808fad9531972cc0098aa4159f7cfb67a240b216fa94d404b40624a77f75426cd7838c14c1c660374317245dcff8748cc5504f2082585bdb41e748fcc890100b5b5295a711f1a43b961a3bc63e59ed222f5586313ce2acc0957845b82464d2c530e18e05c0c80d37c83f014a5d2f52d7b3aeadebd85a392a8c47161d255c207447460724d8a09042f2463bfac902c4bb555a0679344246c2a38c06e4c62b3b184338fa586a91cdcfd195f8406ff99378ce481bd3846dec65a3d8984a2152070511d844e1d620d1a2e213822826a5585bc21d0f750e4236f3933616248930e35f2a7f7b5228c440ca9d14ac90aea63eb03259a4085e7944d571b3cf2dca973a37b3514db73b85fa396db54034c93dc7953708368586bf8c995c86cf867411a200bcf0460f7187d1bf4a433bc5bc3f41f1f84d1fe7790f2dda83d32a6ef038253f81fae9a1e1dd5da916ebb7086592ccbc00fe06046d9bcd6da41a414121c1cf135daeb76f1437adba486f9b559f36c90b30fd2cff0e41215c70cc5272d027e429e7bc70399efb7f638e3e91105462e3325afe56ed24f6f80709e5b7312cbc81b1a848d22325b8041185945e6aa623d0c5291d8cebf4197b5c6df2b8d3578dfcbb1b36e40ed9519107cefc1f59977b1a61484d64468935f94086f47638eccf9b8d1a43ea942caccbaf9ad423ff5630d0ebf8a5af5448895653d1b538032a12724b1e05046be492ecf54c70e1347fcceeb7bdfe9d40ffb5062cb125d42e3c8d11d16110b0b3ad5dd90e94e65526ee708da8a5ea4c6e89b52c6736ff2e83572e2679ca786fe1f47bff89e9e089c73d30102783aa15bac1a0c4f7d197ca09d4a03e29995fb331c4a58bc765bd021f5da7004922f647b01599fdcc1295e792d1a49c133dbf3022f4e44c9c460f20c5064fbb843667e2fe8c41a08f1f0c9946cedcbd0983401f7f0c09ed9c993b130681be3f18725a391377260c923efe3164347226eecc0c027dff614868e44cdc4f1864fafac190d0c899dd993348f4f18321a1cd99b89702402176d8ed08cd393737160602b58efb9ea424064588aeb9dcd3d0acefbccf9d2d1cb897efd089b92a9de53513bea44653dbc598a426124a1d28a60a849adcfd98e0eb8723f90948a50bc8a9ca635611b22a08924f28e82fddac4822b1bf4859f3114bc9a3006eb83edac35a1588056d143f7a2b1f182d75337f044500b34ca75f79a9d80aba43dd49789987b8113cbcb6871f8de7647a4dd6632d4c5431d84fef0d755a907ac06a2f112af8a9e4a81327d9a0fbd68d6045bd21bc680b381392c810224615e9cda5fbcdb9e5187ce45553770611a53ebc66adeb05a889cf2bafa71804bcaf0c98025ea2cc2e1ed4c8581f8b5d6cf7b1bf2da2f12f598af4650f1cf73c658f2b3fb0386b39a5b42ff5c7bbb50fd9fdf307f50f9a6fd33b6e3f7ae1a217b6dd2bf422ed17efa92a6014fb251f69c175cfac92c1779a5b878d1290ac9470412f1c197e74e92ba1075ba5cbd8da2a02aa52ab5fc21742d8b78ff2a0ac98b7aac7f0af54c5ebccd96b43c8b8a6e2e8e9c5aaf8cf1a0b47339a5bf4b1b24891607c0efb4af46289dd51fef4f8aa47a29ff177a5975c89270a0e7d3fe61bdc35b535a44d48873fc88ac5e422bfbaeaf32018bc96254e3acf82c67c3b0e86db87d5c868305eba5480a880b39fdb19377727ffdd30a2891ca8d00af120cce40432170e9be084f244cb31749b6e6c2ee08a23521cb7b3103f489afb54c10e0fddcc6e14abc47652331ba3e3fb99426e8c03c7a1f340e8ff2bf29bac21900dc21882e26243d8cb4522af1ca8297a44a715b50a3c6a8a44be3c0ca08a6e1a2c31c50524ac848e7ceed9cb9663a002e8a8316b85dbc59d6bdacd066e42d88b2c87f2dcf0e46d27f659b3b5d9a1f361eef4b6c6ad71d53d1812024e0c3ef54acab21bcffcf3f254962720e36b709857929ea4ecdb0bc2a3337d7abaac8ec8a0bf3b8a969d59c9f60efe919754387c3ec241921f30fb72909846500975bcd80325a73ae87cf35c298bad1899ec899901cd1c43dccecd122f6cd71d01d34b39f59f683b394d536cb5e63944fac5ecea6f48a6963cc43775fa1553b7990de54181f581e897d6fae6259a1af9c50359a0049543c7e8f80e964e0e674214f35978804ed669d8039de79f6b2430d83e91cc6d30555ae1e8b6413454a7d297964c8f32da9780b27f2610a8583dc79492cf66bcc85dca6567376f429f4c7430c64daa2bad8d3e601738c6f970995b126368eedc6500832f164cdc76febc7c70a9cfe1b22d37a9be0d22eba8e30de33f6759006c4049628df72c479c13c301182c9be1ffc85f8cee92d471f20d15e8e58cba5b887b271c2f74d8702a40d5dec0509cee3b491bc689733310fd38caac13b1d46328656a70d50ea709de4eb143e28000130b69b30c081bf6864766003a2149d3443d6a23059a5858e0933a6e2c7301c0b917e6af1eadbd919595e616726f5e3ce2d2ae38973ba31347227db324df30e3d9de8a69fee0c0a4e7c0d30538ead3398ed480636ddfb1f11cdcee240e9eb522a29c7da30140ebbcfe2a80978f048508506848778112bab9e3beee0bb45d8f9240628d74c0cab9a62afc18b87b1070c6473fd4cf7215c64371b1c51367b7fab733e287e634e7e8417514d61dd433334329da8c9f23908647fb819220b9845c2c9310009953f8bd440869605f4278e1fade0fb337a8f90fa5ca5c385efc069f09eaf672b492a3753d9103f7dfa81522a7138a9462dbe4a8493b1d85b0fa7e6576cbe37daac420624159a8280937b6ffd261db124ebb9db61df40f72be264e9697ecfd51a910e8601a0dc9eecf88b8228870f39a6f3262a4668b4774987fbac3111219cc38d179d9e2dc97ccd7d103cc5b9a82a2aac398041a47cc0134242fa21e7145aba04e312ac1673a17a44aa883625155dfd99c7775f06202c5bbb84db5a5126356c7aab42d88e424b1e10212b3c65c09558a1f7617809938f641f8865923d66db25127875d525ae08018351287aef06d30b8f1716242951b520a41e3c3674d78602599d137b6fe08407cc01679dde82bb8a229035c00c1f251c988bd5e26f52438901c9e95c1935a01845e2d030c21553be875b9389710830df98c21ea60a638e290fd674d208a9e08eccfb5953a69fcc31a4a334a142e3d56d6c47cc7ea08aae7a644484b8e7c7486cdbd54417dae90c8bb0cf056b36dd3dffa75d8c6c04690c2b381a7630254882a787ea7ef3fd6c094ec220f28f5a23777aa0f5b52940610ac604483b65d1d51ff78a03e06d2b265b7f422bddc8dc664dbe8bded1dca79075765a342021dd040f115ddd990b11e8ee06782788dea5f2de027116625947b120af12a513e0a71c7a6ac621c905d42e32ea8394e04f9c124bf325325841750f6b2c8c4eb0d46497e899d24f050bbc32648cc5022487dc70cfa02f314afd400dfa4752608c18eb261fa07950aa06457c50f73f072b122b9b4c435f3700b1d475d740b97ec925267e5268e479ec31962ae50780ca522dd44ffc8c58555f729bbe38b920c4c8f12be398773f06692549a0499c82356739b9097f50c4aa6835f2b312e243ddd3c44a7c7bafe1ee8f2e6d7c3202296288a533254bfa68d920d6148a65e7a24147c5e6dd22cf42a1f5809e764d5c699e83b23bec8d26162be87ad2ada6fd18f8dbfb53edb0b20a1dd16c66f713d5a09e1150a4fbcbd09703a511870916832ae9c7450d43cdd0403978f2a22fc0ae4b1f7f0b024bc1a2465708409398407f1bd3f8162b5de7aa20eff2022c0e653166c52b2f056f41ff0d9139e13666e9df3c0a7eaafd9366d3ac8d0f7a3b9cfe3139c710edb9e3843c153105c0669aab3fe5f416ab2e34b486d833c8d0b1b35d3ce46d9192fde2da681d6c866a23ce9341d9658795909ac9f5cba0e09e90420c9425348bbff2a22a1f3fc967e0b1e7de4fd0accaa1338c49e8dcffdab5504c870a6c224b2d9b0f5fab9c8541c836431100b4b9ddadc856ccf0086cf0b4afff256705bcf5f3d780893e6b5408708247cd1108977fbb03891655c26263182cc3672b47f235ee6326440431e347fd06fa85929c805bd7a867a9425e3d3144b4a48231a8db5a23a2c9a46c185ded954a911b2da6fd78e4e3b10a1f6905ede3bca93c9d5f5359ff6fec822102a2c3c00af0bd936e8a8fe16cee6ac8722b1356aa57b52cc2799ab7f8fbfc3dc8b5a4af253a45a077f857e36fb11540c3a58669cbeb476162ae49c54d67626be844425c540b1e83eacc14235201ab2f70404ef53eaafaa7ffa09c398eb8cb2ec6b408c5d19a74033c2d8187fe3ae1757aa901af08b6c62e36d4c6c600c466342462c14af56ecb965b5e8962933c44f84cf5eb54c7c66c367744d25acda01d3851d5884589cb8862d5f55daede91dbcd2108195f54e6c055d47719acf669a1b4c4ca3c92cbc1e573c93edfeb937350ef4605a02b486b3ba1e7a9e0fb6e01a4bce23c3cb434785793a8861019e06fcb200d07f329125265f5f7290bd654ff08a542fcba2255eb82539114f316f03f21bc938530837e75b631a02d6ead629cdbc20bdabfd24a0e174a4f6244f1a9c271e0284f49a6d970790347d8cb7109d1a846ab50d536fd463a47fb991e094680d6912d612afc50da4e360a3a360f53c559bc2d7e54b41602ec08927aed604e736ba57dfa84c1e898583d4aafe1598d809bec11d8fd83bf41f22dd054f928e1e2429f6bc25a5f90d66ed52c692aa7d130becff018460037a55bfb258200c5a351d575f5c2af1d94a6492bf661e4408bcab4105bead218333e18482f41d74f4c30b0a1c865e9bca379d7b5e66a3574ca74b6aad4657b30c276a74be5ebbeb03116804cae3131a55a089b6ddc86e6b7b6f29a59429c80a8e0a3d0c349f5236be42ec4ea45b6f72123d88e653cac6977527f27a10cd9b9c80dcc79b9c7ebcf426a71e977993d3cc476f728a79e84ea4bfbcc909f4a07c03ca252dfb4fa6f964a29e5c2b736d9689649916cb377722b38fb984e57e6552ccb776403dcc62eda07a931398c9da01759cbb7650dde966b176d041f576271b7d618def2b99da975ebe24fa52e84ba02f615fbabe74c302ded28d30ebabdf68df5b0781a99da9f3e92f677ae593487426319fb5d099c27cd2406702f359565c33e17c92d7996e3355b7b56bcd39829ee65bc5d13763571937425fba715d747a03f4a51bd85f7e03e64b37ac8f7e2346bacc6f9433efb9f1e3e334bf1104e42a6e08f912f51b35bf41e44b342fb1b861f31537a82fd5acc4b4b41442084b365faaf952902ff9f8d2cc97ac932ec2cb45a0de7f83fa12a5f95ca279f2e4f96a5b914f225b3ebd36944fa15a3e898054e43308289f351f5a3e7f7cf2499bf5e4b39ce5b32465f98c91f924ade718fa319f309bcf1c438f3dc7d0bff2d9be3f730cbd98cf90870f9758e4c993e7713e730cfdcd67873cbcf51307f836e708fa9a6f44f402192b7dc1c8d74c4462c2017ee84b05f81c34a146625a9a7d8ea0c7484c4bf673d49ae65bc55130846522d82bd762a2b7cb448b94c3e743a41cb00f9172d40f9172900f22e5b80f22e5903d46ca013e46ca513e520eb1916e769f46b2b9ac388af4a2b6cad855061313130e1c82306f1745d84be6ede448ca62de5ef6943ea3793b4df63e34c701fe8fe308faa5d9abf0f61af940ce94e3be0ac7713fc871d07ea9006ff376a22a830987cfd79c0907ec859c2907f836c7517f88890947f91638130ef1573891e3a8fd927d16de7eab329870c89e29477d16b9ba05a6ed22ea2bccdb45d4894cdc45d46de6ab8ba80f996217511732c32ea25e33c12ea2aec224bb887a90397611752013d645d469e6ac8ba8ff98b22ea2ee63c6ba887a8f597611f5d2ece922ea33d3a78ba8cbcca02ea21e3381ba883a69d2ba88fa68fe741175982964d6ba88ba68aae822eaa149d445d441d3d64545d4afb9a28ba85bd30293451751d76101b55de3ad324e1bf6fefab00a0594bf0eeef8f671a427b880eba2c884e38e641eed251d36fa68631dab5183f4a5d9bfbcc642089df45be471c44450f1349f2678582c9f3674487172d6189d2e00d451c3d70cf325fa95dea7394bbe7a38a7ca5797fafaf59fc0f3c4d66ff0ed7b628627f373bc7c75108c89501dac0fd2b7277d30749babd3dfb717dbc69982d5c1bfde4bb307fd0c9d08f339ee8335acfd91c6b08722cc1ea4ed01e5ba7a26fa38ec9918ba2317b41c01c31263c634d169b0d8c069024c1074aa705d7971c920e483eee85edb82940f3cb02902e4863348be00f1c40d35fc600506ae212497929f1eac966871b7a06fdf0aa22e109f889b5e5b2bef08a9652d0657136fa576d65a6bf319c39a49d6cf18474915c7864b882f5fe09aab07aeac3f7141683101c1355c520f825a537cf081a8e6367e98b2810b8614de5c99e2a5c9105a5b58729e184209130d9bd7191859064f19cff6b3c74f1f3f493f657ecefc2cfd8cf909f3f3e5e7e867e87e827e9e95e63f3ed26834ae6ffa306ce554106c744f8f564f4f4f564ffbf9e33e3efebcee8f597d3f26fdd107867d4c6b835ef998f47b4cfabc2eaaa992d755d21f63a4cb7c2449522693c19199f4c9126c0e068bbd5eaf11e6a48f3018cc4792e41169d287e9425ccde65eaf570983c1e8bfdae6428c310882346c0e5b6babeebd5436d74e69bb520efb515000e4afefd80897c71b81f2783b20af23b46f0744df89eaa0d552c912536163d0826649d27cb8c1ea2a8e103e298ee8806272c5051a8e0c61e60913752c135100f1a045c3ddc66fdf124ec8ea66ec5bcd2a4ff1b958a317f551ac97568582f30229970bb41c9147af3a767b77019babd608e6d5cbda0833e92e346dd8dc0b279a5a361242175dcc268c1eee7a37521206820df10573317498188a2efa68365921813201830ebc9d094e4d4e2f87f9989d5e6e82132cf4b05655ab97d9b503ac65839ad5aae26895a76ea3ba8d04d15f2e86a68d84d05f1efacb86db5cad553657eb15ae609c516c24fa75d73eceac68deb12512605efe748c6632d17cfc4533997e68f48a72a13e9f17cdeaaa3c8af5d4cbacf594723d751f38729efacf6b46565026731bcd4b1fd1631ecb26ecac93602321e63dde934dd8dd9e6b7b7209b503ea369acb5cc7aef431997c448f551763a2c7b20dc8676095d503651b3c4af5d469a60da8a72e33a7987e9c698904985bf771a62512b0bfdc271fa03fca75a6129a42071de625348d3f26d38fc7bcc6bc562ab36d8ee631d3e6e3a4ebd88d3f2613902f31916023013bcc61d904d0b1f72ee624d84880f9cc67d9849dcc1bd0bb998f346643e6346623e63f26fd8ed998e5ae1dd09859da7cbcba8e1dcd3c6b95cdfdf8086436a0774fd8613ed21809a0630732fb613ee60a6573d461d946f397d3b0395aa7b26cb46ce3ead8fd983ea60d9dd5719dca2aaa19bb8e1714ed11363f982146bcf7dedb0498bff7de7befb5f736c1c2dfebe2d55f27b3fede7befbd14dfdbc490bfb2bf4d30f97befbdd68295f6ed5b62cacfbe7d4b80017b3873e64c0688bc1004073748d880c399af5d3b4c0933870918282a2c4c905982cd93e2d107a049e41547dbbc6a6e2dde1a67d0b0b6664bcb84116f9928c2ad3dc25ab5183547fd9a3aeb349fb75afd568deeee8512469478aa815446caeb1f2f5788f065413dc96933df47d6e8ee0800049233bf213b8c59b36bef0edc1ad1ad5673d47f48224f1277d6d49288228939be24e6bc0e0fe814db915ed16fe8a059c9ba78620f4fea30ea98b4b6d62e7ae5939eb4e9411fcd137b08559388f36ef5d56b555fbfda1a5b80fd933acc5cb21484eb230e4db2ae50bebc17f072d05ff9c4d8a99275d1c31808972c69610c843037ed7900101ee8f43b06d6c00ee653c93a761ab38e4da5eb57242b8d99ba91824a1c1d5589e2d1086e21b839b97704374bb7aca567e8a2571fbafe7a99f74979b1f8620efa34df1cf8c14c86502b90f1882824a27a37ccae444e9eb746352b670e10394b9c20e785283966fee7db27878610899c2950725c7892d3e36374667c40433c72c91c3529c568f1f98822a20e981436308512375b45a264f8c126492c8aac0c8db25696466865a9287fda28067ed94a228adb8700d03fa02258a475c6cd9d29769ca1a18bf03286891b869022c51a3642c423974c596b52d2ca078c01f2c44490362edc3941159a24a03cbd918202cfe30f777cf8e10e474dca32f4e6fad06f18866158bec0d568255159d6fc881fc01564b1a8b5d10cf1e52d6ab71a91d788fc56731ea26acd6b44332c9803901934daf741cde7a356abc5d039514db446b717ed9b41a3e6b823b4fca9132b9e62fc213b478d74946251a782fc9226a62ca9d7ce30eb2a8e7a086e7f14a3e2e8093cc230745dc51d857eea62541cd5592332d485473c7dd8631786614892d8bcd14a93acd51cca53a73b2269442abe7d472cf9fbed3b82eacfdb9582ea00a4ca57a76960cecf44d1ecf72ae39ea108d7c3bce8a1115b1e2445b37a29afc3407cfd450b1d966d35c05726dd8a4aa1d7588dd0c5df2ac3ac143ae8275971b1048039ccee9928ca087aadca20a2b51171fe3a7623d47c8b6f5f114c7eb4b52ae3ac8e495acd4338ed933d0ff851956b5909f4eaa2d3b07962279d66259cad91a9f2bc4374089616c148c560f1b83d0ff8c1e5c9daf38028ae8aeb1f2b79abed5e6bf4e2d1da47049e9bf524f3c591f2e72dced39fba0bfe8cf194bed9fab37d1de6a95f5b471b0ff801e70765e471d43fdbb7f5d52df501bc8d2d007c6af38c7e51bd4651f69f942a0cd58c8aabce426936edae55e12db7204762dfd0deb993c5420f60b44e406277d6becc834d8466698d54b0c40c912966861831c48e96ad1011f6fdf37143c5c2d77d48f592f8f0f5b80df1e1e5e9e6a34b8f9b1d727db0f0e1f7cfc7923f75595b468ac954354f6dfd3df97e3d76e80991b236df6c73d47f3d1e7fefbd17ac8160d7df1fbb7befc5d9fa8831362a6b8efafd3d35f1f73a79efcd5197567341dfbf2736fffafe3d65fd59faddb2503ca4c0eea2504c8307c403f6d8f261a9d31d61a781dd460f288f9dc4f8621ceaf0edd86f78ebcf178f1d742e6b71fdae9539c4bf16044110f479aa4317b5878de4f31804bb8b28982b985b3473dd56bdf5211fe1f7af4798cff251070300749c0924b69c28e2de3ab54e175947ba6155e822eb95cecd548d74a9bacc7717f9496fb654f6a9f4794b659334525b07a9d1ef38d3392ae377ac695cff297b1bc3f79f3ebf634ce3a807bfa34c6fd0556497ad366d7b94fde311e7cf1f8f257f865f7f3cda7cfdf1b68c7a57fdb703cf53acb73e5a1fef2f8062fd8d8940c52cdd9e7e89e6a158d483feae77cadab7d3288d74833e3d8dd245ed48375ce8a27617dee6259ae7b11ae9ba15f3631ae9a46f33c5eaa2f6315dd44e756824eaed8d64f392db3cd66bff786dfe14af00c6aea0d7ebb69a43a82f7ae84715f412749ae82b6baec11a98abfe32c59aab2e86f7c723f3ddc3770c841b682b3de2fb8e5da7d8fafe7dfba698f2e36c6c6b34b4c2db6990c01a5d6f22efd1db67582398b77fc01a65e0cdc2db56faccdb2f608db277ccdb7420eff612acd18f3706de3dde8eb346427ef3f613582315de2d62b466deb20b87e12f3cc86c917bb7167e81fb9818e45e0e03c7b9ccccb907a3c8839c34cddcbb20bbe92f3383dc2b0af2172e9a2c720f97816be0a169cbbd6cfacd417345eed940b72651ee65a081e77cc8ecad70d059500762e1440ee6a8173b0bbc347b2c72948b5d4fe62c88dce6a3d923ca5140bb9ee844394ab6735f917b435eba90d91b6d0ee434b36703f2153e337b4039caee7a352f57f8cc61331f7d458e2ac2666f96a306b0eb91ce62cc51446ecb51b45d0fbbcd7fcc9e0b18394a68d77b399117e52871d7b36ef36bf6827294cfae17e4e58b1c45773d205fe12e7214b8ebcd7a1ae428dbae07ba2d97a36ebb9e90978e81c770396ab6ebc59c856790a38e76bdd0891c831c05dbf57e7c85f798bd16dea3a76377418eca60d7bb6ef39ca372bb9e0a2f732f7b94d9ebd1d3b1bbe52802ec7aa5b360e1b0dc03f21ecd7b3fdeeb711f6f91a38c763d9813e5dc03bd87bd77bde7668eaabb5e8faf70377bd56db9c722f746efc1bcf7f25ee8a247d19dcd2d307b345f917b517447947ba5f766de93798ff498db726fc87b42deab792fc8550899389b6baf99366cae5d8579029b6b0f326995cdb5039934536773ed3f660936d7ee63529ecd59d95c7b69cecc239b6b979917b0b9f69849a16cae9d34471366ceb0b9f697f9019b9ba25c6cae1d34dde6dab149c3e6daaf49029b6bb726ad26f5d99c4f8aac3fdb8767ea71d857a25efb5a111583f8bd79563084f6751781331b5d44fbf7ad6b233a6573651b512d3b6ba4ea35ac29df510dd75a5ae67d3a658d48d039eb5c535c535c4bf47b67a373d66bb5b2ec1c9d1ad24516f7154e7952adac2afce60e97ef1f2969a391dae6acfabe72a9e6d4af0f59997588f2a45d55c60daf443df4ea144f95712ac9fcc583f9f8443a0d2ae64052330f9a2a5d85911e17f2ea95aaca383b8f8f0f79f5baa4caf8719b535efb6c665d5271d587cc4a558dd429b34a5528b33e999547f1d02e2b213f7df4b326fa98148b8631a9cf8c99940b69c24c9949ab50ab8aa33c154f415233233e4b685e9d42295dcca7d8f3e338d7bc1fc86d2ea13a05aa6f007bf510e0a8de64bd7a87f914c77c85724d451010edc7a7a79cc964a76915cb94ac581557c3545cf5555cf51266caa5e2aa2f81995ed12d15573d04ea22504aa6e2aad737e5ad5da55bb27695ef2bfb2f5ea253bcbd51747dfba290f3e3b72f8a1f9e5a5519f6adad55431466678446a2be347319056aceaa91dac74ff12ccf9a10f6deac14f3985bf0ba0dc3ac04826e45312b85a1db976725d1dbc26059e9f5723b8e590906734b9259691cddd69a954827ddfa8b1bd563b96a559cfdc94a34573c1567dd3a69d62eb3ce31ebcbac5b558e59e354381557db08519ef5eaaaca962b2e5bbc70f17909e3c30a43062b8b925153652cd1ac24cb54cdd32c3ae5496995b74e9fc48a83aa46e45435a2515523a2aa6a74ab39ebf645c559a780ccad5f20e6d63f10ba7512c0dcfa0948b74e79a08bee934ff1e53df92c7df4329fb55916e10c797859a65a15d76689cc74ce9829172cd3ad57a6722acefa9298299c4ce3549cf5eb215010cc14cf5febd7a45d6f4aea27d5fa1e2a123162bf8efd7c113ae8a19fbad7196374988f7e1ec5ce2499cffc6c9f9f1de6c71beb6fd01c488507b90a6fbf425e136d3ee4366f27573891aff0f692855be02cbc9d66babbe9edb5169ebd85b7135de037bfc0db3d03c7c033f0f69bdfc839ce73379668565aa2796eb868b7d14837a82f29d96ca38ba8dbe8a2eaed2e34307115573d67e2cc5bc555cfc0c4c0bcc0bcb530b369d2589816982b4c229b39640a9935156690096456ff31bbe27accd2ac3e336531d2ac3e9e475fc5ea61751d388add707d755c97cd556f6b52d29760337b1d04a6d98c52a5ea7350a97a21c24a954b8d84b952dd428329d5ab5254aa552aaef6a954ad2aae3259bf52e0b1f9ec3c7984f0f2a752adaab83acb6798270f9e57aa612a4ea942a9b8ea5d3deee3e28f877e6d4f0f2d8ba437cc0a1443f2c2ec0b763d7cf1592f10933031bca08bde57ebb3445829d6b0125162c1f2298af92ccb309f354cbe782b2b2b2b2bcab3a23cca6bad1244b06cb1b588284fddd75a15d65a73d52ba8d3e9743a9d8fde2f11c49788927ae9d56b1556e9b22e8fe5b346d2ae7a73d75c8815a7ac5eabac51d75a556b55ad55b55671c92a52d61d2c779edc597247ea0ed4959d2b3b55769614b1236587d785a7cb89abaead6f5f579b2e345d3874c1d015a56b852e245d43ba9eea74d5915367883a5a75c8d4f1d5b9aa53e5eb2ca9c3fbf6d1e1a21387ce0f74d4d02143070a9d25df3e3a52747a747837843153474a0276e4d869f3edb343c60e183b30d0f142670b145c76f0d8e992402dab95552bc52e56abb5b7d62976a4f576bf36d7dce4043ae833ebf5627722aa57b4eef4725cab5edd07dd39817e4317ad3bc168d7ab3b890e8e8e9d606ebdbdf4995dd1ab3b61077b5e1ebad3e8533a8d3eba53473125f301dbc562a537f980ed64590673a7d7d8631dbcee84bd3ad4d06ee64dfe72a7d143f701db95b9070b596e7a855e4577b27e1d6a681723f398bb5eec4ea18bdee4841dc35e59f42627eba23b857ec55ca3bb26a7106c72c2d7c9d6ecb5831e1ace305e4b80269b430ded6c6ebadee403dcd925164e210f3b9b9b7cc876d6a1827677895edc6396076a6867bda9070b1f307c730f164e310ff21eb3a1dd10cda7948d3de48c8816e453cac69f594f2dc88756ca46a09e1f5a10adf4112ff80354ae08a2f9c8dc89f492687c85d89d40b75156d884bc86bd56cb3d58343989309b90903739c1aed8514ced888682683ee5e84ea4cbbcc9076c67cb3d5808d57213d4d04e456e7282795035d387a3fe2b5beb45600fcd8ee15a31687477b5d21878ff6663796434dc2c386ae5f1783c1c954d962c47544b8ffb425689457a69ccf800cb11406e5ab00411a5058b0f505ab090f98105873f7531fcb0f070ac00e4ea8715863c5169c113450c3bac8499618a3ae11437cb04be049162e6496f0923742764edf8d1238a0f688c807185f44a26834f8ca13bfa804914449e88228919b24c3da9818a891b3543523802c48845770485453324ee8645ca12a8ac52fc60068ddf55d7efeac9851b28b8e4b1e2049a205220656b090b555255581883cdc4e815197c9488472f5851229a79216761e19725c8dfd7dfa317c4daf7ef8a1c2c431e0d58c503f7ea77250e9caba5bcf286f6f85d61c3468adac2ad85a32a6dfe88f28af88af867e5ea31c64e9618e32857ae6aaeaf7011cbbfe28b5d29433ec6186317ac58bdaaaca0cad68d72b4c28d8c719434054b4a0f970915377749d9f3fda342e6cf185709152f7f96974a0b54aafec43d19ad3541b7d5c84e5646d06ead5c9dadbddfda4bc95b3b6807c1dc64a501bd33017431f3c26c853a98dd52a56bad8b40fd8e95b420180504b309b8180851dcf451f69b50136dae6957ea6475dc0a9619a9a71182ea85bed3c0c9fa9192d4b435a077369b0dec0de81dce24cca2e08cd4426312b0d398037a877313cee63a1605c94749bfc966e3c9e6aa779e3c361b0fd0b103bdf3e49981d4426973a2cd75efac503f4b6ada44a034db44b04e9d66255b1428df61b7d570db468928383b5919c175ead83b68a73110a8d9151785e7043a0671d417a166a5364a18e17df536c58a1b692cf3ac5c77b262ab71dd319d234244d14ae943b3840f74d004a1050226c4dcb91345431d39547820151fa2958b04ee46015a3a4f5826b0833d0fc3300c432fab8c30bc4fca30a495157793b8f7e22230ee827eaf5ff0a2406a485617569a2937697678d2d56bc38605345ae06f4a1021ade2250b657f79cbdb4479c12a4a596235e527a50cd4cd64c5a9509ea45873d4a5c420a5ca9fb7ac41ba5a4a4529ad4ea9c541bfe65b716dc3510a2dcc698147edef8bd5860b5cae93a2ebee8b2365cfa9b98e82a7e644ef6af4564f35d77f962088b50f410c9c51c20a95540c2870d99db537222ee92d59e20914aaae8ed85171dd11f653f73174f85a49fdfd6b35f5974e6924653fbd2e5cbd5c8872e1e9cf9acf4df540f983b2038a114ba0f83005250c11285ca4a0344922fbfe4199da32f6edd48de0f6e7ed9b5e1a0b4f08b949dd90c5f78f851f0b587fde667842c38ffa64cb094fae9e9e44818259e0f204872747509841e38327bc232b2471e44aad1084d4950a557cff5610b302973f7538c905729321d2171983c9bc7d9499743733e96eec1803cc9883a6e83393ee640710a919336326cc6766ef6426dd55b36d4e141d3b688a7e4d985f30f46bbe9c344ba21387c561df6b15677d88b7c2556d046d2088fd453512e2b21e63067eeb254cbdbdc1b13c282fde925c555e6c15956dd371de3a88ef2dcadb9f512350568f40598dc4dd5841ad1388df4eb8708c5d473a46073423c873c5449d2d4b84817265860d982d3250698102081f175e3538f1d204eb91d4a98108106c9e5838810a4308993a73c40c91ddfd392133a32ddca75f93a7c7e0fbd7448507bf7f4d8aa0b93d6c6b35b5379cf9a2e2e80834aad1dd65057dff986c3191f367abc9a11cddfc9974eb52bed4fca94bfa528266fe4cd2d1508e37fc594be202e64f5d2d862e7f26e970d8f2a72ee90c963f93745aa6fca94be2a1853f93745baafed4258951f26792ee86237fea92c0a0f06792ce27f5a72e49cd097f26e9d030e1f1a72e294b8a3f937463bafed425a579e2cf245d0d4cfca94b2a83c49f493a1de2fca94b82e1cd9f49ba353ffca94bb2a1873f93745825cefa5397e403993f93743360fda94bf212e6cf24ddcff7a72ec98c973f937461b8fca94bea61cb9f493a32577fea9276a8f26792956189d59f6252159740794a4aaa7066a04f7fbcdd702fa807ad03add5889c7ad0583bbef2ca937cb2a4510f3a871d5f79a529520f3acc8ebf7ee9e3fc4894d6ad63ec6fdddfba49bd1d8c81407f6c5066e7f57ac1eebd972ed11748a9122ebf2546b4b2aaadd6caac14943a1803e1d545203e40ffcd9dc54e61a388e216c5916f86016c3e6b6f71eff0d431eea90a5a54447cc76cbe555c9ef26cdf8c0f6820c0563346c551194e085f00a108c14e7a57c993ad49a87ae86a919eeec8ceb8d926917a6badb5fd2a40f1b1ef9f0a72febcc17aa8b824901dfa01a9cc45a1928845cdb622689cd15e21b620d6e303ebfa23885121bdde134f5ea0909381143d5049a105861f5fa03081cd7181073759acb2802409da8245052fbc28587260e1a219d3e48e1a3b4bc6a8c922048a206ea2f0443d099a6d1962840d5a9290d2c47767083a4594990a026a85263e3f346419d224895f90169a006235866a880a3df450d50408e9881454b44c4981b22601509858f383889824779c10dd4033258716be440184120f5678e3c4af0715dedcd08456c28f1e5a5548f020314502d24091022f081d7c1461c2c4023030bcd0c389154cd191c3011b9e9a227200e286c99226a00e2b728cc852044a0a893c3854f12184922b2778c9418993320f0b6cc63c05e1f1b3220122a898045901c91457123b64a42a8c0d73b26c5d71e0c312274a9ce061ce122a5413e01003d49621904ce130048e8fa8272431ac5982aac98c7493268b192e3c3c4ac48ab05242448a26e20481e4678c982c687e49ece092d268d2701541018e0a461c71c4c9e8e44413659eb4f1610a991756000495d6173b56745218ca008829425841e2491e2592f870b3460e9316de5c19b9208a45ad052b3c6a7867a4927852a6c7112867a058028522f8491220c45cd11066892998946922830f45d060040a112742750b92284f576c9454a1800c528e1841650c11572830215b4b4c0b6d8638a2cc8f2c0cb0e242922d2c4b4429990a8bae5000e24a1169aea4f4d8a27acac22407224c0c51d171a85c4922093148764c21ad2912c788ad3149c608e9090286168638e3048a136084aaaef88268c2862e4e82d4747cc963030c2eb0c1610d9808fcba7c3864c5604607a9262da2c4fe7581238313407ee015d16f58e841cad31c1bf01401c4498e7afdb89945e461e287993b4986ac11418b0d46144125874a4914ed3561aab8a9d383480f282228e3cb8282c277e7085413a7400f364ba2d810a78834318c10a9a3250b112b302730914521d9c10a8fad3339b8e9803703151588bc61e3820fdb093c7a5841959625a23cc94eace07bc383181690e8355961f1a8a00c0f5e0d539288c346070b62c844e941091e6ef8ede893bdd3e408560a6a6c5419b6d63627d416afd8556ff5f6f447e5838feb18e31b365f603f6f8fc3f90596cd55a1c27abaa3f2595babb89aa34ed57bfcfda3e2fd59d3adc18285f6f813d7642b0729a286484115d99dfecee369963344b4e441e18cd4133b03e850a5840f4d1a1e4a762fda2421d2840a1148b4b0a3ba17bf6354f76276749541c2871d98aca049a53b7252a0e0a2f543618528bbf6f6808c97835eebab127c24af171a2c776e3093c50e103ba807c11f92141e74d1c38e3556a2d8c2866b07f26c966a84942329b71bc298f919416344cccfc817235ba0fc49fe8c18c1469e605d45e414815324eb69111c7e45b61481f22bc264fc153152048a4817d753274799acbbc856d1174aea422e94fd230227d4c2fa53f47dff885cfd49f68f88d58fdf3f224c3490c2530a556cede4876febdc5dd43f2370be7f465ae0092dd713e0cf881dcb65a9fc84e07051809a32e225ea6e81b2d9662155a0a60871c1c714214e4e980206b9f3b3ef5f90ad3f7557c66e9fef5f10adae7dff82f8dafcfe05711284d744df3fa938a51a502a8c5495506a498b3afefd03b286c5f70f081721250d42ad4aa1ef1f90210f1b654b34cfdb6a8cf66d3e992c0ab6fe50a0a24a7e3fbc70f9fdd8028191ae500ec1f3ed5350df1947fdee229c9a1e71a88a212850994aeb62addc159efe86a4407f437e50934a29fb07c4eabf7f42a678ea24fdf9fe095182fe8400f11261325b0dd8b7d7ef7ca2e07f80d4d629a0cdb58a2bf20427b95144a0ec8ca81f503507a37840cdc050559e6ab6c80d6fdf3fa820a0d4884f63dfa88d9aebfd0125ea85efd8cdb5da87f1f2dafca2e61b91b2fff682a43d7501e4505af0fd83daf2f7fb0775f567adc280020a74abcab046d5c7e3f18cecdabbad111de98c6a04aba231c205420055794d9efc9d70e5cfd63a61eaff6c39cde543cd9f3de76bd7574ae901ee53a392f6f4698cd2de1ad1aece55dad7c69db5273ea3d6a200410a86a2188254cd0e9452300cc1300485e05b1f854b6234d5c208c09192fa2d12c5b22cc273f18b1a0d1874a10343f1f5124310bb4003861af41badd6124a138a391c088a2980d106a25896b59a7b0c32e20ba7810b2f58064e6023d98d84c1b71bd53870516bce3236d205df3493b1db0625072e84b66232f25619b60551ade2c694d4cf9a6c969bd8da1abf7675d1908f59692231d2c2488942d943e9e8f343762359f0eda2589617f0f04323c52a83aed0008592fa59d28088e8100af51774010ab2ed80d5022bfcba65032282540c85d98c8a9a908eaa2654dbe088032ca121156bb2b2c0af642acecc6188c43cd888808e8003870141bb3a65731b94212271d60a0b7ef274757d97290b58f8d4e1e2fa92070befd9c08e9be5195d2ecdef7083071cb8f8af5315c7811b33cfc460fc66cd9916031bfd9cfde9636e5b96b59a3b0ea7d31d1d7d0c36b905d98d24b37e1ee90080fbd37318f79a3ed3620af02f58db576e6bdd71baa2205adcc86ea4581a2a5f6f45746e179046350f9e0317a25896b59ad9e4020c48aef7194aeaa76390016c4d5611960c70641ff1a7b7cde0abc3f9db0cb89cd862ccbec1030e443f5d88b96b59d66aee385c949c06a4188bd21c20516ae0822cc083615896b55acd8e8b175d006fd14618e73a75c37b505d84b92bae7917559f51cd342f487ca62c22db7ecdcf9777066d0482b9623f8d1ef47383b7fa9aab9dba0529a9c320bb91ba08c60b182e34c8c1c06580c105306e2d606418304c87c1c2821544306c432a846a308260c0800144fb81e1d353ce60c862248c11665f30441821886fa595278311ebf7fd1758c8d4fe44de5da68dbbf8af0abe1d7f7b8d7517dddbf9da9d8d2d40d6ddd59a4ce014d003fd2932e1109ff606d871d41e3b9eb246b773422d7c15f9d8b105fed6306953fbf82e39f1de3e554cc580ba0b339eb2b9ea2e7828dbb1f51a0b21006f7dec0a82180441aa42667377d1f55b6554dd30f6ed84f1befa482b14edf2ed974b6751ba3bf3e72bcb5ffd8aa7f975d545d501c0654da820295619b571d81b4c416877d4634ff3c5bb9192a1597754e6d4573f85fec43d46986773f5f26cad86799f2bf0d6f35b6a6537d3b64678d73e86f85619ed22ec8d5fb10334112104e0411fdbbe603058552103737711a630de14235d214c95a6d5db03260a36128e7a4990a93e689e5746750b92167452c495c420e07bad5d6267f6e2b2cab058845b033b76259ccb2cd246ea5ba3467a0394bfbdf0ea97cb574ac3bd8e95b08b37f7ede98a237bd736168215cb8b7337eec40e8aa0025ce3be12e68075ecbf304b1ebb8e1f2f596335ee873e5e7c7102689ebf99886e501d8cdd24cafa2751bf9f2f6ce6a81f2ed9bf0e62b721dc5c823c46031841bfc6aa572a068bc715428823215eb75a4b8a179b295f4fcd94e2533365f8d44c095e33257e33e57d6aa6b44fcd94f5699992fafdb3e7dbaf99923e35538af776db7befb5e6bdf7de7bf1bdf75e7aefbdf78234dacf91bdf786f74d8b5d54efb5a7ee4d49bded12cdd3481463fcba17062bc10c899778b5bafb14c18bbbbbbb1bb4dd4855c4185f9ccf7bef751b8aa01886a6881dc418bfeecd23c6d8cd7bc33ae3dd61879af5eded2188af3d753bec9055713687106431e166ce1b25a4a8080d51658a246bb0a234f9cd99cdd0c50a4e133bbc3077a648b11aa720e22bc20992264776a00d3dba50190206227468e0fc59f365fd29d688fc66b3217aff0895b783f9081bcd271f473bd1a1c4ddeb35ba689a309304b606f4eee54deddba1407414bc9c83bf3cde08d4d6d9c62bdf6e24ea41ad94cab07e99eae3a81f45f4b16f9ab27f3e5f0d5c3e2e35f06c6c84cadbbd1c7c9950e24ef46ea428a29fd6436b5f3ec3becc36cf13fc0541500947fd9b45ff117d4615f34d42abb529c5ef1f982e20c040f10207a60921bf383eae1e92d84cc30d98df839982e436049822486e435c9fef1f981d0ff4fdfbb2f5a72eabccc5572f8a6595715eeb621947bc59a9661291299ddaaeebf88bf301facb2daead395c5b78babcf8bc84f1792183c5c5de8b310886e215455ba98841300c45f10592a128be5e30d8c885bc24692b2545f205838d2349c6e4c8ae4c662b9569c1c891246331996c4683947991f9665ebe7a5992f9ea3d583ed7c7c756ea53a7aa54353255a5ea920a05a74d1c386db6e4685dd12a5bae68152f5f1d73796a457978e813e5e1a15214ea04368b4cb7a16169add6de8bc10b82b65290566befc5180c6f18da4ac38b41300c45f105bb3098ad14168aaf170c368e64ecc662b6d2186c24c9584c269b95b72c6da5654c369b95654f8fcfcffdf9b195fef8fcd068404041412a6ab756b395d67a461fd29a3f443fa435694e23adc9741f680422ad79bef8ea41b103d0c7b58aab4285ad54857873ade2aa038932db8daf722aaefa0130949aab5e83a0644a5ce53aae82a1545cfd1343f9ea953eae5265742c84157fb1a05419d80b00045623017d754cd5487dc50199366daedbdf17327807322af859bb8a47940318c56e51ac06182f1cf1bc57dfde1edaa96f07dbf1b5f5c269b12afdbdeaa2f6ea9817f270a9bd6bbabbdb5c43b1ec45c51a5af0627cdffe5d53c92ba7bc770dbd724a4abf526bc3cb068b7ebbe876cbe8c6d1683f340b9257ebea5056f3ac91b55a59b6d37c5a7f6bfd2d8b57b2e6d5a1a46eadb52279d79cf725b3d578bdf5a69ff1c6eeeeb3bbbbed69adbd6bfa524b7677378f1fbee0f0e53744f9c507c35b17bfccf065862f535e967ce192c3971878e4f0c5ea4b150e3718b4b6142186245956bf35cc50c49fbafba5840161cd04b1e5912ec611172e56678d441b03551575a5489672aa6867b01242f1e84517e348862bf1fa66a0fa5314cb19a6ac87e6ad0b9b2e6afe749f0d23f5919a21c8dee6db45717e3454796bde4a4199ad06fecbf4f637c39cbf1405be2b8229edf7af8b993fef9da1acdfbf2e64ae6b39716f755d74b0ee3bbc75d1b6af4b982e612c132516c11786c130c63886ac570c5a332ac618638c3116b348c600e7318ea188c7b84ba35d22d84a015c3aec5095c5fb614b972bb04b0c3212c2e47027c9133e50d9da4229a59452fa7a1509c3300c43afc160611728252c555851400569626a77d63e8c41ce87610c4b7c08002e6dd25cb103440f2a3b2d40fc7e4794524a29a5e12b9ff47a29c3b0cfa4106788224bb6e8b0a4e90b798428c3a34c992670e0611782385f1aa82e88b7586981610b113cc4f2fa295aa32d3f44e1b894fd341aad36f4fddbe27bf1fbb785cb9fb429196eb37a2f894372528241aa7eb4b7bf46642d9212dc0ba426e5897b8b7b61d5f4ecf0789404bd3d46c559fba2e6ace32ace3a5255d9358b339293b22bae2bae2bae1ad5b2783cde0e4fa23182558c58d60b58b817aefe6c325a2f3c59c797d29b9194945c219cb16f484acaa3b276cfa8b125fab15ae5650ed26a1d69496954e69e34446c7d8f5ffffba535ba80c7cc1bf4635ed22e9091989467f9d5faf878758bddda0c822f1f1f43b2b48ec4a4ac17b04665024aef2973575ce93df99a3de679fdc74bf3bc6e4f1d3ff3d9cff51f9f398dd59865a599fb789995aef7388ed5b8dee334463b40e936cf6633d367a40135fd8c76c5d91fef07b23d3e3371d4efa1f5e4dacf8d2dd1bf31bbd6b18f24098b810096e609661cf57d1ce72841ded628287bae33efab8be1d66846cdd51e25e58d410d1c27e5cccff6a98183d4a43c75d75a70044dec1663876198eb62d4c7b5eaea88c4a414ddf7f2ea1fa8325e3027fd5e985ff33ecc613111689efbd6145be6336c2c9d17a8b4ea570c4339c91845330218000000a316003030140e0a85a22409f354dc0314000e7fa64c504c184a034910a5288ac120c6186008008410608c21c620e6e63a00d02f0f6628fe4f663dcb2cf2b3af3207de05498e9699d9778001f217d830512723901306cb869636d449e149918a201820ed51f456529aff2f2e9f5290f00dbce8b22352950d0786f903d637abb0fff842641e736cf9c0541f3338872af34e0eff60de850722d4407335f3b33cdb2c3bc778338c67c935eb776c5db453fb35d000016ce95456fdffd5d93cfc502cc194e54c3c99fe462027bb2deb6c7778a1a2828144e7e372dc3f9e89d95337101e8989e5f8e6528ef8772343058c6b631c4939edb9cd82f69e977c16860b601860fdf191bc19150a36e6b4b426b8134e0770d4a105ba131dc63560daf28803f90861c106da250a5eba2e71dbbad49c7045176598534010eff2bcbb7e2457df702f5290735373c666246780b6f847b9c22d1902daba78b0bea6bc1402fcafa03c5685da295fc53f958bc41ac7270f4c4d60a6f6e9b4beebba544a86beffb3212d9b9f4c6a3059f1373356c0a4f9f4cd59275e052eae2dc9efb3e76d8a5760797f62d14a3da3372d66a2406b4a7164b917017353b10122efb7aff10b9e8eae5cd6ee2e7961ba5dedb7bc0de788f3581d8defe947f45f453cfeeaf944a6b18e47f92a2ad001837c08db32e49ce746823214562a69a7f0b47f81388fdd242ec3a448ae6d92acea08f7618387d2568bbaa492a74c02eb2415e8561a311e696ba6bf6147481e8c299032e2531f5c3b5aadb86c2991c16c84f0340724c1dfbf5316ee5115341b5779d02b32126e380551b81ce828efb1d3c17f7fa723ea7bd00f7bf02faaea34d4f703026ee48f9be7ccf34bd8b7323a1363c32fe568341c484011bf76e3ea541c44218de3e015976bde6b5fdf43ca3065df4fbd4363c05dbf722fd706ae7555207a36c4a4719bd54e6b33ca7eb6b7df49b7340381fb77542b9a227787d3f02550b5f92df7af1c03104e024394d619844349b440466ea55649444c65a3251f4183153a3212c2b2f131094da15f565078b64dbe27325f840e2057d7809e7d6b6bad08ccd46c5345bc20acf29c701d59c518d84eaa3715136d9dbcd9346dab9ad850d40f04e176fcb0733acaa1d6ceadbbd2f8dea50e52c0e87a6248d233d7ed859cbd6527e0fa25fa0a90dee602e9315036e4590d0253506e33fafcf88c7a2c52be7f6c56d03159464453939c803663336784822c2b88c3ece3b063edbde959a2bc7e5d527288cbeb04e8b44c156681d07b86d708835e24440dd542a403e84becc903d377534d90988224a114b298919ac8660a14a7e9a47ecd4754193268bcb0185db0b4d7bb998973d5841fa1da9316876de27abeb10b4ebc8e9d5e5f582817bebca353a117d3f7f433ef3898ff47be9fbfc6791225a9484f2a0eab9f30b1e7368114a1bec66952054ae7b885ebad8865c4c50557687351ffd59c74f52e93416129ca9805a6746f1690d7ab6e75db42cc610a0660d7032426e0613e6cc1841cd82ba7ef8871d0131649bda1c5e663dbd3123ba9bbb679b3d192875f6d20136e80d4484f04918217ef409f93668b182693e7e068e35e0d5f9ca84fd10355b85182baa184db53465a53241716625bdf3aa5d5955a8627601cdcc7584d56535d4b7b3501e70db0c27977ce1784bab5b7bed15d5253ea77281642d8277940ae65c8f463a5b9e904a7930904fa08dc6015a304c04ad58b37ec9c972dd1f1be3ebf56d21f38b75a3fc5c2a90bf0a509750bd79a99922757362eb8dc1846e52a112520e30882411ed235874bce2b62e1983b39167073a3b7027f9194e0258ef4d8f97779eaa0c097a1c7de58228203031405a5c1c46ddb021469246244f61b7cc41dfb26731496f25b3803ec342d3f0a76ba8457f61cd7aae1ede0e10d61f071ca11c979c76397b7b644081afc3c2a4ffac03cb071a246728972eac0448b8c5b1ce28398461dafae565f67051cb39a73832f6534d3e20632de4a382cd13959bd7579beec91525bbf980fa2fe8ff20021602ce7c9ee03697a4043b6feab85431300c27d7f3b6122ff8ee83365dd25b08849c70a3eaaa350312286a96a1059e358e38346de5e8b3d12350ded24cd734a53b5a207275b0793efa1acfd86db90f9fc890c57aba3b03bcc8f5c019cc5f6bc584230376448292c4a1578735a7bf7dee671bfd1e6a123134823c14064f41c288ff1c360e40e37f54b09f4974ac0652b81635e07c8bf03d7b0a6af84cf07973085d3ba607509e5c6a9b4f3e329f54796efe99a3e3aa1532dfe72676918f4ad1cb688e2d0b51845db1b242137534104326726cebd6cbb9417d1060eab48f952a6dd64a03fe8ae68366a590cbfd810c062678413f97f7899788ef8235396f46a6e10ca01f7ef7f5d05256a7da26317b3dcb258d4b7651c58d6aca61c35d64f163ba9184d95759f57e398d93158683238bcf93a47bc03b08d485baef1688c2c1ecf65ff80a7b65c83bdd0cc83ce9ab8ff2bbc4aad31a7d5639e96165f13e5ec2b0d67d3465cd421b0495d0705dd8921402d0df71332122c71456e819b597409dab82048e684d97820b7299a5971525731726b751263935db05974c933e2828a2ab0b586ce17545df097abb3205dfd6f7408396a6b368a5ca130538465c97d784853686cedd0fdac5cce05a21a16ec0e65545a7a15ba637821fd415cd0fde1045e455a99587c08f3d0600d1ce919f803a243eab7ee18abb58356f4e6c2f76e3ccf8fb9f0442ee1d0ed3df7972fe2d57e6a0862b5bfbad58fe6f90a6a08c3097182a020e2e45ed1f3cd4b40db5bc0fe5264fa938985945db47a243f7cda9015f61e8684ed6cd4a7009dcf2d50583355406a9700790b2b0e8a6ed4ebe8f168570bfb182da75d732e2b7b95b40c21a603012e4595aed63b0821f79dbbe580c7e7f8b1410c8c2a88cb87e1e2f5d5d79eb730834a98892cb9337b4196123cafe97ace8946b06059833815e6029f964304c923f409b51889debe643db117d7e0d073627ad84ef712fe5e6999f54af81cf193371778730027c419117168acd3c691e0ca6f2b42bf651e8ade93a45485d9f378a4cb70eb7219387f9d9c18e2f4eba14b116e603174e3f50e6f19065a2d09aa86583639e3ef842f7c3e41d8500c35fe38ee6c5bad57dc9ad6ba01dee4b0298fcff38feecaff2432d6503e2c5462d1ac0c9d5e34b7ad5810160474034c4f90c163e68ebfea8731f07c9d682ba832250f8798cafd97733b5edd55e3285fed213f50030824ea5329409b9cfa6c2c070c6cad777bfe1f367c89b1855e32896d3a72f731e380bfb598148e9368a0ccf8b871198b3dbe60842d40b2a6d2a181ab8dd9f1faa76516a0eb0ebd06103319f387dff194dfd91743003241bb99f4706feae2826e5f6030b402b3f757c42f2be352566503cef6a0349d9ed96cbd27b02400c5c750e2f9ca8e4727018aff35136c46f07247ecb0ee432d370743d37ee83e37feee20ccd1103231dcf9c313ccc584736bb99bf34f476be212f218041276838459e39d2f87cdcada9d713791d30e83025d761fb882264ec9ca025821d680e6058679540ac983f705230d84a806dddf70d29a6e729c4b9c2dcb6a9cffaa05a8a5961ff85c47736417390f063ecf80721973261e3bc37dcbd5a172f63de00fc10996fac801518eceed60db19a9c9410c0d9a5b544d701d3480dca6bc4be3fc6dd02e866451d89f38eb5f81fd9a1ba3a3ee8d10c03c5c8b8451a0a6a990150cf5b437733549d1a92f3009bba491ac7b05374426b8310809fbbe3b149cb2167f80370f477c3ca4faaa0691ec79b05630d20ef4e0764a81454729a5592881d59b9f9bff01cb169a3203017f7a27ecc9eba90eb82efcd40a134dd521c33c089e76c3afdf057e410286d976df5d78aad852f07ac016c67ca12576bef27d90d7446b38fb424a8953df2fef9e9ac0c6d91f7622fbf6aedf7af15ef859f6eff430b1b8fb6733a0ea40775faae26c48dc9dfa0c89ee0135f99ee290b10043a23e22453ba0a980f9bad6a6995b3a2945ee110b9b1495843f2c5697c61f463e2788e071269c57a7019b31ef05e368e1dceed0ced29d9b561f1ff82043798f6a09c2a4b3f4d7dd94800ff257007bac758f10bd777697632ec439e20fbc6d89b5a7974472964f3f507dc6ac955e58ebdbc6e4bbf1802348fccb1161584fbf5870b38ba403aa5b3fd04e0d753da47d592bc0585c718b968c54b1955bea62ffea0532364677631106dfd7ec4a763069195830cb15a9c991970f37d9a3c9e5c182300500a44f39834512548d64132f40e6dd53840b25552bd7e8d584c6fe2d10b79dbb8935f2833d03f8bf04cac2429e2b8b7346dd5daccd0be49c07cc602fe1d928b2b83f4e44fb310df47d49cd2d6f5da5859cb3aa92812bfa8d3a20bc592a93b6d94b15ff6636026abc06b8184a80bd860efe8561fe79c0044aa92f4605d85ecb82043f5103f707be2b342597de812f54494d5978fff4ef08a00ca78c6f1dac0cd67a58411fa581049a84f78ecbfd24e8be91f92008d90fa0dde13d736cf2b20b14889401cd539b201303366c0145cdbba0d9fdcc936c970f683eaf96ea7acda96cfbf5c74b83c0b7d78420f52b882cf3076a74d653d2be95dbce127607569052c3e7f2ed168a5ed26d80137f5217197688566387fad3db31519ff325aee39e1377865f097edfa63d62e4ee67401abe0fbd05bae4e867434e3e9fae0d3e65c467401abe0fbd05bae4e867434e3e9fae0d3e65c467401abe0fbd05bae4e83d57f49a2e09e47806674424a613d9010ac4d4cabdc100f59428eed12dd8017de607c81373e13d77f1e31d9b390ac7f4ffdcaa5de600d65bb21a4d2d0dd772f9f0a27b1dfefffc9ace53437a82960d734d33385bd2fa6f905a8bc15064879ae49ec1ee127c04fb0e486bf9c13771129be16c24f5801cad86072f972a515ebade409e425b723929a2ed21223e2c37e031fbc319b79b8de88fb6c25fb5f5ff87c1ca18e5a35018d0bbdef2d928a14de10fd1dfef7e5e0d8fece61e6623264bcfcfd2c9591573b9aa931bdabfc9de3c6a5aa847b7a83de9a81d0b50015bf748bbbda368529882df5d67212b4e230cbc00d357a7a3ecb47c6ba2f30a74ea6031da2b10f68e65e8fdb18829a6282bcc18c39d292a0e3145694da2b004662ab84c5cf58accde0f6cfafce3ef3c67bf1dad7c233a324bf0cb1db4900b6fe4b72449c4e537021adb266f08b1f99b42b7313bbcce2a7c0a440d07aa14fbce95ce84c812161a3a66dba03a5b70790a233d5c7691794298eb24927d51d81d91871d7188ca1f429f64fde5ffd97e99e75f8ae98b769966ffbd89e05fdee1fa59da9d9fb12ec319cb784bc109102d72b6fee325aa48c58079227909055aec4f48e0f435590b427be9f4b0ca14ab114047e789ef900ab7adbe2c7163e9f7048de74e2f11cc95b9f7935c1d681da932702d78d2fab830b4152afe907fefd397330ebde9bc15406e9ba140b16ba3212e663b8154dfb49e73fd7ad98089973240ff37a7ce52d2fba9c0b5cbd4bb634bed5da3d44665300df1cfa0c30cbbb0b566df748bcd724655f8810f4ef0f15ef420f9d6b7c2e17b52c00c3acdd424d099374faa549116440bb2d699217d4c703ed4ef74a407b86a60ea9c9c50da93f68fb6dd9144d35fa40ef546ddda07aa4833215a2e062a9d501baf3831bcde74124c4363964caa29cac6f4ead083b2fa88cc9d0f1866f18fe6f134b059d78335684c8057b4251f6ed23cff0a7499c40dc707b165430e7d41a716f2d799095b36e015d5d9fe825cd5682a19a8c4445a13c1441286315c6760a87f8c1bfa590ce53a41c4fd8fcce51eeafbee8ef6fe32bbe4f0219091e7166d961cd4db631bacd8de6e2ff5c8374e2685bc5731db9b81adfa778239d68286db92c7cfa5bb8b3bde5443d9e64113d79a5a823a843f4fed45398c49c2819774497c0f456c7f4151141be7a5e9b6c8bb9c2d8dea9569373cd5b8af20012ec4babcadd72f7f2f4f29646ea2c728b58b792fd769d5f423bfb5afba62aede71a9d6fa20beed612da3e087124006b00638f1fd4b336b0aa87bc234e580b84cbd8d6d8fba5ff7632a933c38d49d6199650c9b0aa42b022fe10a54388bf561ee9b97e727e1aee0eaecb13481aab3394892a997b4d6b5d8ee3c062507522042bae6c18b931eaa330b823b1023d3364c48d054f279bbe9d933e4e705b21e110e005b68e07e610b7881148d6a76ba42d2ddfceaa681b55a80a6b7f70940b6ec0b25d062dcf142dd7a36c909fed63b684801e142a9af3555b7ce585af98cfafe1c77e4bede7db4d342a15e1739b57fc962164d1b1956010392d1e2a10456ae4e7e48f7ab1599dafce20a9ec01da48499a89e12792613e69dc2727993524a1bef2ab81f012fb3107643d51422c202610a1a1cb023730d56b31a37f8c46b6b6129519b45f7cff5c00616e477d0c377f81d55453773e9757635cb90ce52d80a76c39c9553138d7244387db211f55e868fc79da5d6f6fa80d09f561538b1397257216f71a5183621dbea5e35800b0082199a36d1b831f900ae78b61ccbfb32ffd1e6127a992187b2749a38de088f46886e3dfae6b25fc0397361fb16cb2a23df8f30a2c1b07183c4f2d805149de0b8813e41dd59e60b257c927fe5291b0a4d6c0dcbaf1edbcfa2a5e25fa02e9e36fc4f3a85a0b5a3dd73398854c424eb81f62354ebd15e58c381d499c9e533acd86005413568cfa39440e9327fcb797715e2571c2207f362b16c69cd556240e12a8a37a24e94752764fe693d98337c7567fe9c642197e4a37b231fe00fcc4eba8007ad5a3acf4f72634e5c13e6d9240afe1d725e1d2b9ed79f9fbe3170a77b637e0dc54887db3f2e595a30a1b4d7d661c0a89731a7469fc88bf1def88e7eee9761ade6d199233d4f41f609e6f67b96136a652c448f9dce358cbff35369745e6ce6578bffd92168f2ab91e735d2503cfc7b8e1ef3293e0f09d9d2e4c5588987d868031836d2d63e39e8f16a7248c5ac599c9528686a97cf19069f0da8586a9dd02f6e9374f486e4dddac473b3f3231cb1904c89288f366fd3d101108db469ac5b6f64b653079a7c5cfe9bc4b9e5b9fb4f577488048589313e7b94f0f073f452bc9cc93662cd2d7eeaba488d400bfdb09bc2e499779e2bfb2dc35b77ed272b82af7d8412d93aefaaf40d811a01a5ebde3ee68e3adc55c3fe997b9b2f19d87351005449ef769d2874463be90ca73444d45b61f71299742aa18fbd6be8f586554db3cd14668e0fbe2ed54e40635d59c0b99331bacb0aad34073b7eff0601c87b8daeb87bbbf457bfa432c6f4e5e8f0073196d05e89b760a8d46bc554cb547268e7948e5a00196e6588130f6b940093d5fd9c757afa824541e58057e306049da16956e811ee3cf72033d6a7629088571c77d8c629d29ad47a790a230f6106d08c081c76ea46eb692404a17623ddbf264e051056115015591eefae1795176f62afdffe6581c18886d12b014df7de7dbd1a7f88e1fdfb559a04213ce6869b724a3b313752aa012e91cccc02f4575118a4eec20c37ac2cc6752f874374b1c64bac3d0f6e6069f2d3b2a0ecbec6bf2a6da08cbd48f41a6874ba87ed35bdb2aa7c656b3155c8cf28f1265110a34042c3681d0a5ec5d918912f43e5a5a7e9c1a5a6b1956c7818b3fe59404d60038f498b6fdbf084b4681814a4b57b88c6114b9595699582324a12c4dbbc4ede92fbf28fde15cd54b646d68839f9ddd6aa689bb4e1182c335915175830be7f1bc5a1f5e5452d5360c496e75eed11873c54e740f55d479c5a3241dd74840d31f427945b7a2451d57086e70b7a701cc4382b332eeb1ef3b8a90e5149d310a52128e37c0439602a3511368fd84da029b779e455ae05a3343cc5a7b7fbfc2c5f3e4bb95bf13da8bc432306adfd12d56bd60c749c84f1796f472b5c6d106a119136b3f6742e0c90e7b1e1827c9367195b2bcaa83a1573d11dd4c0097d0de395a901f3892aa830589a8ea827f24cb094c5559afb57f3ea626f7f239c500b10d09a777522ee1ed1f7ccaf6930692abd3a349d50f819df1cc7958f406ae5fb3738ce0390cd763e1f79d4d251b0d851386becbf156508ac3da591b5a9a58c176a518694db4d3c5780f2b98afedb95a87565a37813a19523efb56510838f2c14d9ffb444c07a06211e5cfe7024199e2337a0a6cdc54c42d3a2a666646cb05a0745cd4747225bb60e87e6c6b773eed0591cd3ee82b09309a218f37f2834b6e119e2a55b561c880a251af4b759d7602b420a8662a8257c74adb2937022f1c69bd45ade89c480511389549cdb7d053e14e0afaa5576b5266f939cb607c6374e7fe839ae069cc3c669a8ae589d040c74cffac629f6c55467282e349107ee50678af8b3558e930248b591f9348ad7db9e56f059a4e0639920f80d90004e2860deb94ec34f09d3ba343dadd2f99c5861e654e147624ff9d6d844e444b6656dfb12f14ef52fa429224171b918c8ef2f6011775002b316ee4b9997f330355231ec4f73bed5b502c2743603b108be41f27000f874c79a3d784b819e8351c7fba711f6fbddc54aea1c4f53d063ceb6e21c4966e5cd86f125bc2273aae138f812b9d1f36dcd8b72382404e03c18fa0a400e00a9691a2a66e16a38e8ee063887afbcd4b22623124f3a8aedff1bfbc6527c50dc24f0042963d789e085a6c579107f646958f94e4c74ac76fa56a5969f7b415d157afa3dd653bc1d01f91f142c8157c666caef210f84adfa3dd9bda8cf807741aba9489bae6af0a91efe7c4911df6132b9284f863acc4bb22adfe1a433e6a685b2e6de274c25f97b031b5c15697bca983c24d9a913f6103b907f635b1a98d425c4e81f8cf10acc7814800eb17b408d44ad89e36d9ee144e5f000d62f1bce6dfcfb4ceff98b07cdf4c287f4d0d9cf08a34771c5f9b1d8dfca3804bbf58665370ce801dbf78abac39a19947a45ffbb6dd4ba30df162878d27212970c9281115211996b755f37581177bcec14d4735eeea98f55c3392b4cff31428d6732872717b365ad1b58d94a9fb9745768d10a435755090d5e14e82e08e3c72ce8b29be8b626a1b8b87aabe309f77eb23a76794bfec276ebc8176e6631ad018f1f2faca2712de2bc9ed099ee66ccc622f0f6f51a0919db2ca45aa1a390a78562a3d8d8904d37a45b22afcec0e66db00a95d934d7d2a562e438308892e8b45eafb1e2e6f9648291c3072f3b93d6f8cd2f13479f835057e36b4d9d11ca4273624528c69ae125a8e6630507b4ce2f2fb3d729eb23eeccf86ed201671c6b729424bf2e57b07b9df97cf6215a688ed4bda14424cf3c2048144aca11fb0e59d113e5887e9f271ac949cc6db545d7ba5726d6119ad5409f3db2c0ec4edadc68b6239a576afdeb8cc1a72cd40d971b74e4667e8c6a2b0072f9a90c1581f7f8e2e4b2894a2fa046d9fa83b01c932aa74469133912351be123e01a1f0494e4fad5a390a48c3fd3680e9f5e4f95ea7cd1669ed305020012bb9d18c22bd8a57aba0de504627a981452b1966962486ed70f9544214dd7c7a23c837f44aa3d9ed0f876b75a45bc04af9b803e3bf2e5ef7eb7dbdbacdb079461afcef21db2b2df3350959e04b8e7d8bc24f22797029581ee414cf6d94bb8a1b814fd162d2726bc519e91931b7fc61a2fd5b3226b88aa8f40e6888ee0b7d20736b156a4d44274e33e2df66f02025e35c8b6d109abb67ee256d2f0a5e2ca6304a1f236135a66fedb098c13a04b7b781bced541b00ce90ed63b709fc6639ce69e96181c5d9b0d592fa1d10ed14487b4763684802e9eac833ad59e3c3718afcb0fadb13b5afe657b355032c900e7d8cee78e62e1834d98d59ac63476d7afe1f8d4eeda2ffde00997aa45e0c0f2190be32840203913b6e44c9270a2d54fa00fb980dbc1e5658a53ca289e79b9c09d22b74ec16f5d3337220a867a5a0d01a14f068cb110abf3455b4bf62f464c3c15d1e183e161077ca7c8dcb27f80f209204582ebc22c948ea1a55c92e21fdff9dea713d3688dc42253ba8b06bb24d39e70cfaffda9b1a7a6efebb39f6d09a9fbefbfd01c787e751afb75566deaf26101daffa5061735f7fda381836484cf4853f511172d071ee874594bf113cac49474cbb76d20db4aa5a658a4fac38aaaa142ade4f6a2b0a03e5d6cd0400cb65e3af497761e4caf434c259c509115f4bf26ba7c7096b72af27f5bdec0021fd36a8c4ffaff9a3c74a35bba24c826fe9ad61b60402ef010787c82f8f19903508153e9c142a053601c859a491a3722e362dd9798263a1c4422dfe7186c4cbd1b3a63083ca0075f04bd6317a310f00957701bd1978607f627c6fd5d4beb7b1514956448a602a6e0f576209692753b0c06407613b7cf5df9447ea90665b091ed93741d0ee345662aea3762aa64bc07a64aafdccd96641cf50b2ebb23389dc1c801672ec7c3f6e292eee072750a2d968e40aa20c5bcb93e10d6857b0b17301bb1613d61576e67beabd5aee4258242045ecf4a9afd956b1b97e11f1e6485e0bf5e575f5d5b48884566f7b5236a649e0ecbd5a433c3576d8583e1129f22f6eecd77b2e3c4db57eb59608ddb5e4a507bffdf214a566e8986667a59db08596c4d036d95ed29542c642442e231a7a0a709f557f760e48116d436c6206e396e4df8848e3005faed501f3d0f262d3bcc9802bf03fef9eafc4d6e0352542d473bc87990d21403466978ffd29e800e8479e2886790df18f5d37f60b3c36b747b7312b7c44247ca05968e155c400211662cf3fc7c19dc27f9e15fdd65d19a991c319b4ae4ed7e918c0c6a100c328cadb2627a7944318bf732c4fd410fbd93d8a084d2066148b5a22cd466d0f0815412ac986bc89feebb14c80bb7aa06bc33c82a76e1a76ce00f3bc1b213c14b86ef367f0a92940e0aa61ee18615316faa81205278291bb828dd2933a0681d2fcfee6bad02e612013620cc6b289d7977f387e70ee5834e11de3029dfa50d4df6f0f185e70e69740f2477e5a0ee247ab7164e04e0d59651edd9a68d6e6c9def6e94285dd651d120feaeec55925f93bf0137f77bdd126efc9da4a21415497f87a317a202f7f7f14ba642ba1c0900cffefe7f351087d4d4cd0fe4536620f48a55bb535a7411873cf4d6cf40e24a81a616448127bb69d0d46748c6274420a89ed01013281152e09b8997ec2dacef645edaa6ae8ca360dc7fbf1002e60fc6b944b6d0e24df45ffb975250390ab53a412928a714f40601b53ccf4ba4beeecbbaca0d31f39dd8dbe5fc4d1f078644e3f9d6a7a612868ee1460746b4f69192a18abb1f7403efb1fc9db91d373f2f516335612e91a05bc563f51b8afd11c88b6d22fc668e62bd107abfb1144761b2348cae47c0042803bba41538d1907db12166888414c214a03d9f00679fe527ad525fbc0b7710d18ab696afc4d6ef95bba2af4a57f1f563e5aed0d6b2556cfd5e7157346b69155f7dae9c15cd5a5a89ad5f2b7745bb2aade2d7cfca5d29ba64591efa1bcabf3de860641f7a9727a973f674048a1b8abcb2863883358e096e5a3e602bbde2d2bdb8018c0eaab4720bb6908d7cff3835c98951863d3585d6f88da1447c0a8926a5cd559720a8d4b169755d8722f0d7e5762a21ef3b1d19508a6da712f1b5f38652346f8f730379f1d1406efd209cc55ea1d3e406ecd22beb1214122b0e564d04127df2722aaab0fadb96fc2313a5ed5189fc3eced08c787b5c8d11cc5b193210b615a0872362f17175622347c2e64806c6b20abaedb0df33b11bb71dcac47f28051913ca378612f929709453da5c71095eac0cdfc195566f07078a229babae5c68d56563d5dda4c572485ddba984e48f48a4650f2bb12cfa2d0d64059591981c3a1c7b2652abee88236fdad16d11d62afd1c7a4af1898df4eaba341c81655db7530979df4191f1536a3b9510dfe980a0787365dd1c618b4d89b60a89a4392b1ae1909c0457ee2da23beb94eace459aa024ee5745acecd1485ee23e6c3e6a91a2c9602a979a1b502d3fe369cc2c8dc8a0368a9a1f947de0ccd9bae7b73ce6bc7f34dd943c46d45fa6786ff485c6ea76e90b436ce4e0dcb620b28c8ed6de48fa7421a4b4296c54284b9f9a9c537827211a334ff7503ce126f236405ea0cec6d5f1d333504e656cee795a7a6b7c521834c2badf2af2ec144d7b86c81aa9ea262455d7cbadeab1195618725048cb61b03a9329866eac87a40c557918937326fa353ae4882cb5ad7a2eb81f83d7d992c0301fa97baab9c008b54e8abcdb539e16525d864f0960f133d4cba702f0ff0cd00981105e93ec297d80ed17125fd55f9b7fb16dc99a2515e8d0b47349896f103d238ae7a6e5fd1ec7a3dc43239afc0dd3347c5ca643aad40c5d07e46fa6722cc172a127d2ea60afeb235d7982b9a94509db7899b9a96ce9d66dfa0209b23f892945f598776d116ce2af837851cc595ce1f70bdba864289c44d6d3838baa063c874d5e43b64c77e59cf4b55205713827825b5846fb8cb75e803d5eae7da2f882bed0831180fe0d8380c01dc0df8819d665338ede81a086a0a8f94241682560ce5dc4a0ae044fe037ff188688d182a9b725091828ff9b1fa7993d8dc2551080a1492ccbf434cffe0ca1986012ebd2df789a02d0b2d8ec912171beff3fd73290697f020b2b6e7229d52fbd473939d3170d1012edf1d9ef16e92c6826b4362867c1355d4e94749055673302ac4fc53e8fa368bc5f42e24cf503f6c6734bb0054678f3334fbb4ad60672328601f22689550675f06f512df89aa1d18537e014886fd4f1a5aed69ec39d3010f39475875f8d2c63129928fb272befe097e71fc33738c775fba03fc096cc1c3a8021ddb1e3cb2d5e982b433fb03b99d8786f5b6a0ac3015999250cadfa87c3efdd16b4a55b945faffe7a98af6663c3e50052c4670e514e3ed404e77a333d9c6027d82436b854b113eca247d6e313c1402dbc54820329b881d88b9b32880f68810a6247be716b9ffdee1b9516bb0cf4b6b85f81d80e6898f6e4a61f9ee0db6810a9d8bad70065b699b07bf7600fadb4ddd2dec7721634f8015033cc1dae7c8683a72dd8d331d9debe06a2043efdf6372e272b6bd730bd37c8285a17b11be044affdf5904fd3bb3b8dc358a05bf53bbb3674f28a67c503d5e1c352a3a1a8d210708ecb4e1f3a982687bb92adff297c5092306b2187deb2381a6f5d47f061a91127e12473e3b415da5b5a0a1065cd332bd9904d60ce4e13778b1d096cd1747ee0abd474136e9bc967df0cbdb7c513f1f6c6123111a13eb79071ed03fd960be57b8a403e8eb11a8261cefd89b240663907364d866a1082cf08c7ab5f707f6d82a0fdcad678a7ce7ef174987d50cb80158c2ba2f06d2ddd68c040ce935ef855d33b661269949cc2ea799e47265eb389953d1ebe2e692075a57ecd26f13230d165419f077b3a88cf442494122c9929d1ed4b2aeb42846865977d7b13ef4cc917429f95155b6135e0692afee83000804c6e81d75881e52d9c0c482f165ef7b898373306f4fd4f6608ffc84c148592540065d4d6e3d5edc6a7ca2da8690db0f2921e827713b4ed4ad3e178d0b76db942d1474f366ef04c91b4cf8be26ff565dd66a18abbe31b9582a7c69466dbac961aada20979b3183139e7e43329219eb3575fde2f87d87148dcf188053315188556808f62f286795f0e0174dfb2c214282483111874a90368210fd62e16aad17db3ee0333fc420659e8afec3c0d10a45c212f424a5e47408892b7bf1c58d1831427276a0c9ea3dab34ec1542938c7a2badd253910b2218038ac46a00a23d97004e2a14d91c72af1c9671a2f39e31bb08f6465af25253d968522a5c645a4d121e120b1c057eab4e9dfd0e805d77b3aec96912526bc4677687e516522d353a56a62b768c650f6105b4925de0cfaff9143f17b2e4afb767147b8ba3a45c8469c23af2060bf212dba1a011be12f3eb161ad4180fb85686f55964284ea52a2ff03fb40c81953cf434ac082764f16d2570e3ed71aefcd423f7edc4d76c4615005b6e8f62fa9290cb054624bf58e0206a83b60231e6807e39eb65809f9f0a2e965587f8a61d1cb4043e7ce9458873a02635457daad1ef2cb99cb0c5935492fe90e25cafcd8b60a3116f0d5dae8ee56a02a9b76a9da32c702a60b78ba33809a2b56fad85b90b5966db8b17e7d86c7c3878b8ef450052aaa4c94c144074556a347b0d93c7f59e36b802c4976b04087a75759b55393a92c080c06be5e7ead132b56efa8385ab76a97e818d15275a8fa713a847b152bfb78a9aa149559e051dd417409e8f04c708c1d682b315aef29dfb38fb37ebe48653bf42dd0e55c708b6f415f8e9b43e74b7862fc7f03accd0c499c9e90d60ca24b1a8ded878157ea9d416e0abafd3c31568da53f979ced027e97d4be281958bb2acf534c4e95741b4330e93e86c2f272adb1d46ec9eb4eb2b064cc67cff0aecfab24ac7c9330fcc8abc26156340fd22d31cc8e34d4d68fa5ed306752af2a6c47c4df21e0fd370ae202336f331d9b3da7773699e68ab9bb28fb5d652ea603307625147875eeace403d1a4178b8971e7989a6e375d565eb0b27dfe9125f004e149955966fd4406cc2c50931564120cc8ec20a850d78ce8ffb8bde1d520d17820018e8d788fed8ebe72ac857a489f5fc022564736ceecfb5f9b0a47f2d9fca4c0101ac3bdfeccb3912dd2e3d9f0d4ec4003181029fd92892fc24c0961a8227c19c33ece671533f74e7d805337801b1078604535833f2bd7dc214e9d112a8544c644a786482365d1faee01a0d870357a4aaa92b757c2c2850358d3f34365eea5185de32b4c4fa8f35c7aede0a8e2828b51fd1085e21d8266569cccdd030ac50fe51240a7ab04e0aa4231fa1c0ea6a69dc4de1ac7b654e829117d250074395e0245fc5000f3f6ac2a02610ad9e21cfbde0cbd7aaa0725316cebcd9ee380123bb7e8d3a2bc6606c8fd03133f9af47cbe5b4af5fc1bdf7cfb4f41b9fe1f56fac7882d75dead1d1d60f7d65943f27bcb54fe22514b2654400e45a5009fd43fbcfc9c18be576e485e9fe9878ad6ab0c84147c3f919e2150f56fa10439fe736a48b0129f7a23e56c0eb70434b10e2980998fcf4e921a3f702482af9b3189efb8d740554290df97f12b444ffb7ee3533149197e8b741b82011fa6f73de4a15613de757890003e58d16dab096d4ae19e1d9535ba9bab4a94c6fd42d3a1d840e6c69cccf6d342c10c90ba2bba71566b91f4fcdc1f9c687d3ee922d11f0449ed25027206b215d0d4c8dbc32d255bf93148d3cb6f05da190d22df8cacb3dc1a0473bf33b968bf46f507ba71e76be282f15078159db617d11126b0f002bb268fb617f6fd18a535b5925c1a82b0da5818bf025aa2592ea2af10e29afcde00df0f82eff30566e916469772a27572231571d4574b330434fa1c01dfaa5d737b8719ed9693a5c03196e1f24219982664139bc8898961b80d4e8690a1f9ac52e24a62c9e1b4b096f65c3483dcdb5d9aeac09f1cfb52aea76bdfca0d491dd80e84f37bfb7dfb0464e6cec380b028f50379fd7300df4fa3786a96d564b39659b9b1955bd14eb785716196cf05c6dc93ed5f7712a73a2d14f8fc19a1e28ac475cf9829c3b4bae78e980b71f6d9e2167b1f2fbaa8cb7a507551730298c34caa1850cd9607c45055922ed0354663efd8be50aaa3989d49fbc90b93a31d78466b3d1cc18bfac9a771e9cc9d529df4348f875e86ece6cb21ae772e1d15f62d52316fa7f49ad89817401939582c771a461d888297ed76f78e33eeec23d03e049760023bf747a2010d9fb1a295c4328019093c478662446bafed8895449215e39824a570e11119c02d4bc1cdcc9de08c4951f27392453e0709a52e2e424bfa0b452626f9114830a176652a4ad445d6a776d0629113135050c34a89c35fa0f3d858daa9fbae007ddaa558217f262a633eed0298dae1b054f8f76e162f8fd7f84d98256c9f272052189475e1137253bef54105e5b268492d61fb2abfac306c870df004ef9e40e5b6c8f10716e1be7f0285a399c0c24f3684b44617933afb6615bf7f55ba30c2568d18309c2464b66a372b19053e0577eb502d83c15451bc7e2e5ac4825b7943eabfb5af27b428a35a8ced9414b65e53c10b6d6621949951bce2692323950811262d0632e4ad82391d92eb0da73062efb7a2e092790dc7a3bd2c07174554a279770a1ab819e81401069d60142d2d2ca6ec3623d92d354781e59636bbb0cfd39b5443dc51428b0136faa94530200f62683788f170d16ae765735a1af3373dddeee6e3f42f91528040ac8c7dcd3ffd06147a16d6bf877f01d50066ae04bc11a0251982b49aa31533bed7821f8ac87f0794c0fcb792d4ec086c21e9bd4cf69365f6c5c5acb825d12f3db7c7ef5ef22ff5c448642e8ed6e3faf2a51eacc5c7f788e1750659ac83ae9bc1605b7d3024800286d6d88f66950b0cf6eb9f9de8c63060cf804065fd4b0c76c1c59a7dd16cea365525244148a34688341c42f795ce19fa39ef8488d946caf8209a75b01a86277cd82c0b2b1c8d8bfb821a0622a68b892a16074f0ce0f0d80bb8b0c0cc00673e18bdd807e42767c3cb768e34ba5d283c0b1c53f46299d31af341d3e6b68258dd803e30c5fc24b7fafd0b706fe5c556e48a59dcc7e21711b37fcec6999e1b500a4e9f9b1b7e8bfa6c6cbe2d1a1b36c2525eb672af9f20e1aca8a7021649a4c6e78b4b859123021c570a921a4a9698d21d364ba2eb1b74e298c4458added19a2b1414e1d68d7d8c202d419e5367c25c736e038a9848bac0c94110e6b5cdac3430a5d6b3db1c8d917dba6897c233fcfba7e7bce0059c6239caf5bd34f3b0fa5cab70497d27ee137bfcf44c2799c7507867621b31abd02d4e45529d1e5dcfb3854569c22d4bbe0b678380608c5224b19b55f2a23db995a763886ee2a8abc4444f79401ede8a3dd3fc9fba246de4bd13f01499dbab03e568e3fbfd3d7ab55bb1458a7b9df77a1bccacbf27617d1d3c83531f0c2e9e50438dfc61e5352abecadfb111549c2e46778baf3f38621226ba56a12192cc72aa52a187c1f07c89c4192a5b778e33ac8729632d93350490e30179bf78eb12e8c75e6fac119dfddf827c86f00a4bd1c70fdd3d118929d07b192f10395240400e6d19381fe87a67b59a7143c768669f376fbf7b136e11db8861e904690f009cd8a2bcab93ef3479b0246a5f8b3ca5eebd079d962b29527965c66df3d6e085b69b55f3c25a56ebcbaf7fc97892719be30ef30caf0c4fe7c4dba4a0182c76175329ec66fc0b186e24deb63adae5f3c914c8dc032bab5cff962cc41024f26a7a58bc6202fe0fff9f88c21d576660c53499531744bd522e3ab84f95973abe4e392209f344a660397cc8817ed76bdc79c277374560a5c9c88a87143a3414e66a332d9986b17ad0828e62f6717288ef88e036ef075061e147be73e829ccf4abe3120e4089a6ea46dc15fee2d291e463bb3e035ade4a5057256e6bfc274595da425b3b1946b228f5bbac30fd3019cda9411d5086c967c24331300d7f3beddbb5527433540c2b83d7f834a85d7840362e61641687b06ecc7ffeef6216e7c18c92bf36b347463951265963f00657a8ffdc688306dfca6784699df62d5581dc9cc461027b20d0a4d3e1dc8b8a5bfc5b20351fd2c066a8f4785ace1a6e57a76c1e26bbda1fd9d2a19ab0f313f9027356c942e48b90eb1bdfdadc58b6bfdeaad6bb76bd72ef89c2a0750105a97ae7b358a117a3a397934947519a296b272e271d24a7962fcaf06f35cf8939655c6376a6dce9ed4a7399348b4dc669fdb21a499aeb8550e898322d0729339f831f325944c60945d4efc78764f74837c4ee21a43787cac3922a8b3f0018c2d952dc3c30dbb7499c6cdd1667d5c398798ea55bcd339e20c35ab615791009b15ea92966547c4a5cb1ea2967b097a8af72c2896d8bccb4376f9420fbeb16d854a48b4647a19908f812d5a33ae8499d35c1a1628c06f5130675bfdada9f46dc28491ee9fcf1db17056ce9a1742fda3ab481a038bd4c8242ffc1f7fe05ffe512eb16c0382a997485a8372f5faeed5e2e0ab3501f93d309d1c698105706af0acc9ec8e0a053964fbb62857860f2d7e7c2efd074b60e812baa4662287438a1fe78ff70f65ad3fb4a7cd4bce398e661354946f9379cd0a3d8ae0b88aa3ecd2137d57dd2007474334813bdfb6fe6ab7fb33e029790dff61c8bd6ba338ad0240084fc0b7e5f28c8278f02da342ac7daeab0b7f5e2a17052def621378d635d0647d8a84d6634c68ea7c25435a6067ece4c1c3d84a90e43a5fbd85bcec8a9a4d633d7d9d0ad1bbf2d0f6095051ecc6d28b3a333711ca9121b491986743e693196547abd14dfca34588776f21f198f63f0d1c6c23be0f2bc4ae733dac024c330713cfa39e0855192f00919d0129a95a766485258bfe1e9f276adf26ca9b359ac62d2b328ed60fb34cc6b92450e5d5a0fab559c131f081d6c8cd8315c9a75797e06edeee4c9e0a46e07444401151bf4ecd13e6da91c4553ec2265f2a917b69ffef2f1e641fbfbf018f6a1b8583300359c5e9e90755d3ebff63ce37289cc11738cf26249328887186eba367416141fbb4f11308b849b51e630710328f526d363f6183c20a2f4a67abbe170e343b08961cd9ad8f32be54942a3b0aaaf44bdd4ae5b0b179706f4d3242112436fd7022ba8a50997ccb191aa2a87b09f9ec01e341084a3c50ac81b1a1a583508b5ed344326622a6ec07be86d97b0c75e49788efc6b163cd6c851d9de03e2544401ef05a29416e75649c018b5074758ece25bf659d86110f72692f989763bee194b7f456cbdaf00652e4c089b02c0215b205507ef9c9771a6a5db52cbec5734c60fc4f957496297d663afc4941def1293cb36f29c517cf3be6795d3cf18d15f4676190aca741ca97972c0f22c24a44190bf11ca06bba843aaa9222ea9ee235b696dd28f380f07a0ef945502f9d898c21cc25689b8d6b524acd5e5ab1d4abd05941a3a6ffd217279a1ce48a6581d684924826a3b5d82696fc59b10c37c7d96376e7e37b6dd09db9472c086ea53bcc63681bb7beb931c37f350773a22ce4b6d68c80177ce51f8449aa88e69cef2d5e0bf83a1703ea6b617fcedb70018370a0833029779d0f33ca0221ec69b43a53139ffb865c0e5d6cff2783247446616274ee44989e4cc4be241631efd54aae245feeaec2213cb0f489e6724b8149db159a0918820dec1233149b7f5499b78eb1aeca4bdf1d971f798ba50445add82123267a85a1d6d2923fde7f6cb15e077c42fe2881de0ad6922a78412aeaf04e9e464e4a185e1ada36cabbfe391eee12d4969cca96284500a6c9a9cd7f2e45e6f20439a6a4acf7e97f240b5a686547cb80066e8e5997c5d586069e56a187356430706f0770c0d870a2eb25944351904ad6e2918022199d8243e3c89cdc168ce433d91814ca9c319efbaca316365d6a06dc250d6f9f49103ed158491243a4d0a60d8063c46265a14c061bd70051c97ac6373812b08f7f924797be2b72e1530d1c8e5621d1645489e06cbff39c42abec17181ee3f329124cfa9265887c99e44f06a119be82c9673b56f8a8208fba88de8a0876cc673e04dd825cab732c1f3ab9fd9e8d5a9192c7e28f6b99ecca73af7c9829f2b50b20a4325253f0463e415b7e3ec8c49f7368e308f46869ca416ca3541af0b506b76d64ea8fe0bd329b23838bfb44a66404726d4ac2666da55f2c09c3c8a1680577e80a2ca7fe2fea21c960adae0a4ac02413e4bbef228c3d6e6e69bd673f2979305bc0c554932e224758870671448811def58d9c57679043ae142fd859b824f96de33ffacee2a8f17931455a0b7ff98e50e8fc8e2e124d427460a60a877e441cbc837cff803fc2e5ead135a34af7c6063a16f356b35407ca40e1e4acdf2b0050ea3cb1b7a144c814c72e81b86255b2762e031aa60d5ad39af9aeed75869476735a999e9ad0ddd87cc342f783cee2ab638a54c1fc2d575b4f5fa1811eed27d71426bbb592a5a986c384ea591e6b2f294890081b38890f4e34ffadd19eb69b313f43d8a615860963d8852a21162d10b99fdca8c895eb510608c4b7e7673866e9a5960bc9620471f0708b5c328f2da64b0631322c6d14eec3584bd3162cc3309fd4c1de9964d53b64ab6b7d1e16418e438348466f62845b75c687662fb18ff5cb0d57b0fa7dee88e14c62f629315159a393c0810c7f2867cd25de292e34879818bb1db0538491579f658e887d6598ee6d2d31cf7d78d2707bb052036f1eb6c5a34f56c0b7a263723a5438abe766601fad94a2519e3ebd84c0b4e84df4cab5402edfcf6dc92bde6d123b18da1117622bbc3f4d8edd586709bb26146b740569944591c6b67b14d92712aaca06594faa0f17ee2bd5ba41e75bc062771cdfb85f5d068a9d9cb519c2320d35fe6ff5d392c07d64adbf5cccf499a5d1de7df9df42c8e39efc19d0389b94f4b0c74a87e81adcd4231f295639c518f9b9a08793bbd7634b5c0416fc027cc612e7d96bead6f2700bbde923eb5d4326b2fcfa807512faa44012646872377c16e977fe4c32516a11ec7ac66a77659993a43a871d7a6125c7cc29e4a650872903f0e703afb0f10c04b05a9cf60765eb4a6c0cb6876247c13c9ccd10b10a18d68f16c0584b94568c687cc0cd4ee6c92e7cc661d0e2fcd32f6d6d0f39086023da07ad58baabfd465143549e2f8f0c1a998410182cd21db5c63a77dd34cb9bc2f43c8b63d11f642377af89f2e662d76772ce121b112b8244285feb47d931c845d1ebc5cb6134dfc17e8bf38574c4436364508eb1ca9dcf81e62328ea0c11c24c97f0210e0086fa32f12b8fcab7fd11d44e890bfa8dbae9cbca7f1aec51aae008b2344ebe861ab0ec222388975dd5832be4e6ed03544f1ed43245789777d595dc3015044a09587c57d3425201a0990c0807e13828e350a1b27a22aa452e05eaa1b8d0e4aefb52b8c8a169896666ab22ccc96b967738b18d6557644ab1cf0c5519056f87b8dc7fc009b0e3949b41606fab20fc3b4e67844a7d6b35c782d6c515dafd12967a9dce80a8409c3eecd55036079a4d1795cb414a737cd8be5f4baa7700b7d405e5c488bc133c50326c66478ee288ef1b7d31779684d7861cfbe625dbe690ae06428627cf907209b35abe88e09b556f9dcfb1dbcc5b3439420aade1d0c0ddbb4e60795815a647486464af4a2356690e50406c1aad249f7120e785a631637759fe115f9db290079398d73e40eefd33a0b9d2e169b731516a19a65d35e15f31b4f6761c366ea0f077c2997980beeabab4f9dfc5d0421b79e1777340460990473b9f4084923008ff4932dabfe1838eafb806b6d5b01ce51bd57fa60fb374537e83fa1f597f05c118c67f946454d8d6fab9084e12f93d93900b191f8b34b0c38b34ac9a2b4e417726da23a2f1346fb192b9309a293ef30dd2c278fb85fb1ac5d1251fec9e5eb84fe14a404930d0ea6b473bf3ffb5af1e3ddd32a0230e90fc245c30130b9303d2b96b7c4663473d88073aa8b3dcd5b21a96115042779250274ce4f9f9cc08dddbfda35326130d16bfaa88dfb9aab99cd4f8673ad69ca7cf43eddc9978d06ef16307ef1c2f61334a80c7e9877a33401daac6b89479a0a99d6444de12a9fcb58fde7c702de0682c796a57731a26ecae483b4d890bbc8850bca88aea65bcaa20ef6cb93f8c05f28549022153c488cac41ef27ce575ad1048b543d14b086ffcc2ec798168b662c9e99c917d99128da979e88697f915550d5e142b61a651b1bee501ce9327a7fb0231dc1663fd11554f4521e3f05c2efcdc3d10462e94ec1d688be57f2719e689efad090f4f00a2189c40a6d4bc8296d1b50f1d6815a7e90f1d183fc119e054a8aa82e0f18d8cb30b7efd2f9b2f2d4de2147ae004f9834837066712e4feb4deaf485fb1390b7cb3b2fa703049c391a2b4b4b9165e9d687c211edc94f1899a498c4a9d9a63e86c808bbb99fbc5a66c08ea83945434b464f482a2044d45533b20ae4a3904c82544cb9f226a16ed72c78c7df5d7b1cc8214a840bac78218768fbe0a89520357880b0208d0d9072439960c52bb06d26c7e6b8380e8f28faf38d5ea7794f83858f81c878680096b1f074c3195d9b824122f89fa981b9d826a35db6d01cd22bb29600d51ef231b4c87f43c2d683ac059cc50918a28350310cf65c891310d6f67586540104aacd341c0ed299b52ea12dced2ba63f552b914e9c1878d0d348af31d5d2d38869ee621c327ba93284bf1b1ca2bd62f614f4688576144aa53f3f756de315f563676d80eb36d22b75d233da7cf556fb58c01adeddfa0bbb263be29b4d8a295e4919af0f9567191048cb57920e06011df526bf12a64e8154a4565dee2fe8cf23db4a694972697e9da1c3b5ebfbad712e5bba2e3ca54ccc96ccdc77bd9d57ffaf8d5bfc7eca9579e8ef92f8f7d88282f3ebf30c9c0dca655643589c015369ac5cbcb25a14b19666349dda0e5bf484a777cd48d8901701056d3ae90662914073a26471d0139790d3cc6a86dc59069a92139ad874832bde631b6af2d167060cffe11f4372c27364445527ce3fa04eaecb83007681e56935ca8d9d3f6b8fb9cb206524f187849747ec117e6740937f80f91b6659b0aec951259a28373af2e4c1b76616204d9b845c97496621266071212f7fd4a9b44ccf1cca7938f98e4478289cfc8f66e626aa2b7bdbb54fa94cbdc551938419e28272600a26ef42729623c87c5363294daeff93339e7a3f15cea2e5f11aa4b904de41457812501038e36e3a00a07167ad8106a071e75a8196c65deecb6ccc3257c3b8cbdd65b79af50731b5c145c58416cb91327acd49c96a7814f8d9db8de8c644fe6cff7b3b8afef4e093f6b7dd6eb4c9de5b4ab9035e113812a6131fe857bb7ef388dc0bce9ceb93e39dfee94eb7d3ed743be14e3d77ba668f684e2802fdd3d30254888b833ad1faeff6b1eb290d3a52c8c9716745121e2fd603b7e6c60ab2869e125e0e75ee4ce1e1e24c09592f067bf3a28d881917093e6f56e365e7012960011904d6ce41cec46a8f0591e465e79d79582c6aec393d5305188da746859e3da256ad79b21ca42c08d574329db0630fa84e9cc0aee984dd359d54ddba476037cde1f69d2c88fcb9b7477c8e05d1b6400ac8fde90b30775bf7d8b7ee74de9ab1a9f64e16c429547726de657da2694eddf5504f51e10ea360048a533318d6b4661990aa322d65191064595695c99abc0781e9a71436851ba8f5d6be53ad3fe8533b6fa7aea2a708d6cff936bb3ceaf879e8e938b79e5e9442dd50e3dcad4e7f32c869f1b9ae2c367306304560a2b6602061566f05628fa69b017d79d479ed9abadb3cebb5fa5cd9e3e9ff5b73503a613552710eadad8c936855fa025c77d1aaf4c46825ae398f562189e05ab4416185c2a222ad2e960aeb118fd357a299eaae4c73842bd413d50286df6e924e1fd54ada6cf3a6a9e679172efc567afce7929a3f75d24ae4a32aad50cb0b6b54dad2eab45487a617a6d5e5716258cd2c95a5f679d4e6319b3535cf6b1af13ac3ea04a5694d7aa2ba439c569d7ba45de73cdfb9475ac8c1ab13561973510f4fd7b9bc2ae0ab73ded3badbbd59d5be3a776239c8bdc9029dce874bec0596b802fba8c5d50da3612d6a726e58935eb49ecb4148dcf19489856950f0d42cb573ce7bf83944d3b0a86cb39b2aa6c1f3526e71e53057d027845b08660766312a69080cae1a0d8f679e61b4373d9fe5b4375da3e5b3b565f144d35c9a5375aa6ec73377bc9535dd5cd91ed0dad3ea71bde9405b5a6f7a6bba3b7bbdd9f566ceca43d3dfe0defac0bd652aa4db9818d998d8991918c6bac239b0f015d67ad3d1acc7c9bca6d9d6dedc4288f210651671ce5a9f278ab3d6e789a2e989a6692ea7aaba9caad3ed762c088cd71d6f5d59b6d70372b78a57dc629f6fc53fd374b76a4e308786569308bb4179885d21ecee1304c66d1e9ad8f1670a4f3d78542d90c703c2599f680a946341a4e7ab6bab638f27e69979b76341e45e359d4c732db2c4d5a278050a0d81b4d94d7607a69576bde94b4d5ad33f68734551b45928a4e65254886d85565d9587da4a6b9d85a9934044aab590edb1479ebb851ccd189b67cf349db2a3d84f3f75f11c7ad15c16a372ce49f94d09465513d5eb118805b1f4aae9d4b6c75f50109ad143948976143a9b3061682825222242894e9d3191b9f6b6083ef7b736659cf367d76d107b14ca39e70d50144dd19ac209194f30cf9ce7170499ae9010d0501e1ac2262ad4b6137ca6bb5b20500381198827b0470f6a1e169dbda3ec43434444c3a66311447ea1a2d6c8e8e828ca584442d219eb88888040e3d1431e9a5ec482c01f659a46461b1c3bc843d38f5810f983410aec71e8a3cdc2b4259af2cbcbc4c249b7b710661d3425991939c4d166e1c67dde1456608fc03c743597a2a76b77f78ccd1ed09bf35d4e28020b5ea051903d2e2169338a4d4c34dd748b8c888e82199bee5e4d779b6d47ec00cef628040207d902e0230a2e1285d5741d45d19ac2b642057737bbd875cdb4425b81e501adb147d39d0581dd56686d9376b459a8959494b2921256327dbddd825785162c242529295db8609a4b4ba98524ac942404c4c26190360b93580e942eb047736969099f6793c69031e025f6083414ee10eb635e7e37e7ac3dffe996007f0662628f39da2cdc2b860c4decd1893db64f3807d41e872c88fcbefe897637e9f33776c163e15190890212135305676262728d98988a9898746a2e45999a46782c7c49c825c07f9a4e3ca004e857f3d0ccf2994d40eeb1b1ca04f2359b8023adc20df9279b00a2c742f5b1708f809ee799d1f33c518da6e7899ee7b077b22086804cc081ee85a0ee80de8b1e4b80f3fc0ef1da07e034c200ce87c06be7edb22ef7f608de336fd519c5a69a4b575dcf74fc3956658f2ac61c985e02ec59e717fc693a611f52753e9bf04cad31d6da4d1745ae6606a7e90404638d3106a14108fd888cf1162ffd83e1fc79cc260008bb8ec3f3994d40fb5878f401d07bfaee3766c1ab9a4ed82f3c0f88c29cb83f7fb209307a2c544d27ddaba6d3f3726c02d0df23bc8ad901e85e553111bf6a3a9d2ff893031e900938c83d760ef263a1da53d95e2fedf572bd3597cba1bd1cefcced74cee57239accbe572b95ecf6452df14ee1184f2d0fc17e01139e73b3c6cfacc3cd4a7d01c71f6c13678f8cd93172604c6d19b61569652a6177bf42d2ea01c596d320f3f64aade0afafc42b8e54258d37d90876a0766312a28692884271c5156b8bad65a6bcda2beb225c0ad109887a7b9cb4d104bb3a7bd2ce4f3f97cbd2bedce66d92ca3e5b42015f8d3193f685785db58cc09f7f027ec097dc25618e46e0f592845955e26101858bb3118d81899188516e8c3a2072385e09191fb109b197fe7a488b48b6bcbe79aad0728edc65d5dca2fafa131aa7814f53b27d7e62c3d6865e5e8b9a6cfb89c6367b95caa69b3d4c8e5524abb71d6169756f0c8c88751c5e091511136dbd82c83adcd69e363c4ba4afe5cb31715a5dd3899c4ca7175e4c3e25153539415aec254e6af18d66e8cc4485c85a98e5aa0370df3501f6923ddb640a03b5cb1cf0a724d53da6dba916005228800027d689e1e040aad6ad26f6ca6f672b2e9cd2d84a99379785e81485d0bd1aa76e7248f1f49cd74f2783d374d1ebb735fce640fb04355b4598629a5cd610d732a6732b1b90b7738c1886fd7292093e9e7ebefc7fe4e1d17f7adf003269e1ee484f904f2d668acdde6f24f0fc1032134f0c1c88b7cabc0244cd4be733d0fb591f034b3eebcfa9387e9aa3be7f8d379eece44420cd9d642c8aea96ae14e7acdb22ccbb22ccbb22ccbb22ccbb22ccbb22ccbb22ccbb22ccbb22ccbb26c199028e998a89da7834442afcd74f0774e86484a43fbc0ccbe5c2e97cb255cbbf3d26de7245bdb5a9113f95683c03c648b8880ace72d11a819590741ae6906f3b4407315b2bedb55e8373633831e825cd39380bbf5011e0095ad1090a7a77cb70e87bb35e7d379e0434f1aea7cee0946bccf8335b7aeab4f888489a7bb9ef2c0f4e2070f3ec8439d04d3c9a11c5327b119910b6122eb3cb7cd439648686626d685acab6608a031aa689a424843304848ea6bb7c544d6f5145078662676ab392b8450d33069826bb6c3377acacc4cea8ad3449c1e040e0d0dcfd379bc74c52c8820d681c00c16b01893e9f49d7bed4741e614506bad7db74240de07cd747ecb73206f7bfe33d903f03ae860dd44af739e939ae9f401cd303184f0b57fd06e07695aeddb04db40d881cf8139a9a7804c268d3bacc2ad6aed3ed761b3138c38fa7cc295e540c7c5fd4ee89878fa073d85cd7ec29e10a881420f74f24f3fcf3cd05379295c32b968735696da45cf91a54ecf5779e94556bb2a26b2a8af6e12c835f71ae4ee10ab1e72859f3ff5092e565dfcba9f8bbf87df39507d1502b3d4cef06cebdbc2b3314ca7d377ef593f32a7f2d2814ca99eb31e644e1139eb2beea09398783aeb2ccbb24565cbb242605eea296ca6994e3fbd156ed5e4399070f9a7eb183e3f5d2771070f30f104f29d755cdceb5d01e840e654d16fca8875ed466ece6462fde76a73c87a910b6432b10e74596f590762855b04faac037906f2cc1e807520e19a875ae801ee00e427d05bf70977fe6d9af99c47e4ab603a015d2093493b906b9a44ed446eced4e630e7acbb0a75ed6f6ca69eae33b5ce0aca58858e104d7fbaea66f174ac37e0154de08877b7235ed379b915f2f4b76eb6ee069949473d2adc22d23f5de7bcfc28fa6183475fb04db7d7792e013eae6ccff770174df5c39fabcf47bc2cebad7fc0aeee138ae0f3d547bc3b9eb7cef3d67bee11f69f8f7881dc232c3c520090f7fc0320ef39f69e50842258f841cf7f42118eb0b79a29f5116fcf4538c242137cf0735533a5de7a90500411823ce837e205f211af9bafcf77fba94f68be2dea29eb9aefea9a2fcf1df1eedc112fea6e17917e1676e022bd68b52adc200f732e928ca29eda2033a5befe873c4c3d4f8bfae9a6d999d5ad2214386e03d689c79ce2d6447dad6538535314064b54d91886ad2bc21e567a70527c5a33003b374d0d7e9ba669f2d622391e7e6bd77af57d7a7a9ee7e9a85063605465ecadedd52905b42a7951a1da15438c73a8f4b5445c3b958256618a24a1b57843bd306185ca221c5add3124a2f568c74901b812b9048b56263723a315ca895a74b4b654c0e04aec43446185423301698d2aa30a55589dd482dcf858638d35d6588305e041604a0d79bdbaab9bc513aeee97cec2ea142597b4267da9a8d2ea6e9d17560b46b4d65a2fad403e6a1eae2e981dd35ae4e4c418d6a4a4d65aeb0c1884ae5718e129dce08d5dbd885c54954f3f857b1dc099334e7e36c1f9a759e74fa18833ab23fe09799e290ff866d09bbe375bdef3526c6674cd6e06b42231b935bb515cdaadaac05335a66b769372297ae6741cdadd9ad7ec865d697b11f9cff5793da0e7f9d4df1aa4e6527500bacfaeb6bde9277b0afd08bc4314b56b1c22bf3dce28ea1915669c5da5b376abd93de240ff9987ed9a5d2528be35bb4436ed3e7fbb3d7af4794226385f443ac1839c6b78fcbca13567f3343178a3d49b1c9e67eaf3e803f44d3dffc62f24158af082a8e705add92de268b79a5d282ded56b3eb6669b79adda3ac769fd9257669b79a5d263aed56b30bf5d56ef5c8349db686379de94d2cbf4f73cd9bfbc80353336179a53fe220ebde34d59e879a4e476f2d364da1065eed6ef7081f5cb30ba5d6eef3b31b65a6dd6a769dd2b45bcdaed9e579ae3e0f57795318621d91872e5ef3669bcb82c05f021cf73ce19a5d2729ed56b39b04258987d1a301e4ec4e781ece6b7637faeef34e9df1b9d7c7d9cc4a6b764190faee95d0576253cfae7ea554a8e6e75d58b30bf4d36e35bb1bbb26385f049a5bb4b747fc395cb35bf4a4dd6776f739807d9a239e9743ac26383f04f04473a6dadb235ee561a6e1d205a5240b1884ae57c88044c1348347464540222727f54fe11e017decaa3f94254ddd4c324d8df3f1d9daa407f4d49b4cdab1b87531c7b8cff6c174d22cd0f2d0cc56583b5f0358b0e5a1f9db04337d6757d5b6cdc847851d98ee870df2503bd00c292277da7da618f59dce59b0739f7abaf93a4f8f54a1073b13ecd50981c3f3ad3d85bbf866978e88b15577a7eeb13c20b4d5f972bf20a1094344c022a3a32005a40aee0a2db8c91e93fc435e3fe42fb138abefdc10a698ba0af101a5a0a2e6658a7d7d30c1e858f09d2b224db27003684b44dab5818736d783d0d5eaf9aac47ce4f0a0d58191ad82d12be86093468c6580a83914a29028f85883d0b6a4f9d4315514b6f2a0f8e6a8183c1ac29b400218125650fc54f841939ca226a322203b221f6f464234bd81307c231a028970e88ac8d824f9d4430831649b40129b09494313b6d4d43f0891941682bb05f9ce15810a05fdc87590871a08d6c9f92e4d859e873908ccd1ee24dff9ce933230e8abb30548c21243ebd39debc10d11fc54e801a01b1df07d3e1f5055733a9fa3ec5157f4e97cc610427650dfb92184be6d5ba14fcfb3fd9d70a7aef356e8db24281b646cbe45db2612b47078e70301a9eb8af2805cb3479e88f38180dcf345ac6d7abe7343accfb2ecce55dc41c5c4b4a7037e2a24b4d7dfa9bf7aaf042fc8ecb117627d96e7ae6c014c30248021e1d91e2b5cc1ef3c4db2725a18d2ee356903f599aeaaa3ebef7cafbf3a6fc544e14e1dfd546b2d14a15f5bc0422a3cd3711ee2b54e6bfa6fd14f698ad35c2ec5c00d33f4e9049c22aa6adb3af939d126cfe554b56d814027689aa1985375bb9d4ecda55fced25c2ecda93a9d9a4bb5a4699a53753bdebaf2763a35970ad991a6692e979690a6384d711c8cb3a48891e672692e979a698d934ed2e454dd8ec7dbe9d45c3a254dd39caadbf1d695b7d3a9b9b4469aa63955b7e3ad2b6fa75373e9952b655ac8942672aa6ec7e3ed746a2edd93a638cda9badd4ea7e6527c264dd39caadbf1d695b7d3a9b9940c4e539c53753b1e6fa75373299a3b698ad35c2ec53a9e2c6992a638cda93a9d9a4b7190347d93e672694e5573690e3bc54aa93e7b8a647bb4cf67479154cbdf28169adfe899dfa8197a86a6a16b4ddc7ea36cb9df68db0acef8dcb86a132546dbbbd12a1031ded020b3268e899877a3492024570e2d778e4489f16e34cba8ca8b2873a6b8e082f56e74cb032d6043926895f892e2dda8f2b3bb28a17401848a1a9777a3609f6798443c23ee731f8c7562ac13639de77972719d7df61399a5ccb026794e33bf4facae734cc4151a293ac0d8a851f6eeb32a45e364cc16728e8e2aef3e9321d071b4268176d36e703a6dedb36b329ca990e76f4d95f65b636d5de6a9a88173040f932158efd66692a0d02211e7c58dcbbb75d20340d6cc5021e39aacbd5b2bf7993d2aa0b069c146f96e0dd60093e8c70413f739f70121b3a165ec14d7c1c92462dfd8cfe72266c36e54bf331599df196bccef8ca6bed9339ace5f6470254984bdc96af2ee5cf55c6cc869eba28c11c5cabbb308686b3b966530b0c87877ced282026d3944451d1fefce5b0e4803260f1017795468bd3b2b7f042a8e582569d18602c6bb33d8e33e1b9ffdd4061b7d9c7d04b3036a12b1636933c66b050d275578bc1b2731b88073a27c7246ebeddd42c44f14b7253d62087937d663a7c656122d3d7f72bc1b6781e551f3b2a704197d8ebc1b83bd73bdf9520349d6931eefc64a31bff1589807f3bf3195d56717a17553b77936957d021a087332e3733efbf2d84b131f33246825d5e0c4bd398c5b111d52be9099a97877fbc6214e7e20290b23f6e2cd42fa8461d901870515b3d7a8a7462861c18385932279aca8bc1690418584305d7f926479817f5ad74dab8146bbd9b1c7be0106ebf5d83724dbcd663d7636c926c572eb97df429f73d3c4e7ae7c8e8b90b5cf51c9f2395fd9630ed8a4cf638f52b67bcd20d6ee95cbd7632fdad2ee75ebb1475d59af1e7b949576afc8c78ec147db63c7d0a3dd3cb4c72ebcc1137bec421bede6753d76a19176f3908fbd35d2ee1ddb632f5ad3ee9dd9632f6ad3ee9df2b1177bb47b97f5d895aeb47b57f5188b5a9247db4751f7a4a61ca5a2edd48837e73cf6985377ec11351a21dbad737bec4637daad437becad8b76ebc01e3b062aedd66d3df6968476eb928f5d89acdd2adce3f55333bf839f76e971e5d3339fba0ae453b339699f76f181e4983a0617668f1d438b76abcac7aec444d57aec4a4bdaad261f3b51adcf63272edb9d637becc2b1b3c72ebcd2ee1cd8632fd2c81567b43b0765250725d6eeb44ada634fcd52333fa88eb3573aa24733d2afc77e74d5ee74ebb113b3a4578f9d3886f7fc793ad093cef374f5dcf2c50cc3a39e9332c190f0a9a7ec313d9e462826688f1d4a49bb51b0c70ee407e57aec407dda8d623d76b44a4fb1cb13adc2d143b2cb3ca5b250696f8f1daa4cbbcfe5638f0243f6d8a3ceda7d2acd9c5a8fdd29addda79d769fefe4d66e6df6d8dd1cfaebb1bb38daadb71ebbdba4751a83dd6948bb4fec4e5bedcecac7eecec15e84a6b57aec4567daa425ed3eb12729d1f35a3b50bb27e5a9acbd294ba1aebda855ededeb2d8f6678d44ff6889a53f98d4a1933e47bba6a4e99ef6904d353ec123b919576b3cbc7be59b8c7cec2b17df2544b3683eb85ec92658362e37aec506d5ae09d769fd8816fadeba52d5ad2eef38b94b44926da7d7e528976ab8f01f27bc9372d8cd000673179d434158ef082346796c8b908454480be909c30e72f30d11ca142be2a7e4dcfb9684e7f54c030daa0277de820557ba1265d219322c785451a0506ca24854eba526445063a3008f4c122e94a98170f1349574edd9b615e347e17cd766a3c33ec8a92573f0b81cc26eca6ab7b1d9416ff067aec26909981d9009e99b4b105e126c15be009e0fd0d1f3404a0a80111004f1e9c3a34659001030c46a6a9a1d41207cf9e01ee7021cab36bf001778032c5bcbec2daecabf24b00efbba7bab642c0a0270d9b8a51460f1b34f47e434648c20b189e36486570fe070d1a00c043870c30304e49718892327ac01d36f8565793363bcbd5f51f02e09eeada0a01839e346c2a461935147bbf212324e1050c4f1ba47a01d00000450fc40e4f193861d064cc3085418a89c3306a09cab36fc01d2e6cf0ec5246dc4183871c5a5cdaec40595a01d00000eea9aead1030e849c3a6625491d8fb0d1921092f6078dae0a200f040cc0003e394148728a80d4fc528dca1684c624969b3b7575800f0d0c13dd5b51502063d69d854243ef57e434648c20b189eb2ebeb9001064f46a7a926a90c1c304431410d372c69f0ec1870870b45cffe54c41d88519f1d53593d69b3ffaaac3a6480817baa6b2b040c7ad2b0e9c9a9f71b3242125ec09062607492e21005b541439198f4e4d9578091696df62011301203e3947baa6b2b040c7ad2d0a9a9f71b3242125e109a92e2d01495010ac306260dc3e212d1b30b71870b4f9efdc21077701a6a1179a8279040c4941407f754d7560818f4a4a60cbddf90119230c7212ac3060d45e2139227650fc103c52e6df6210d78804314947baa6b2b040c7a060cbddf9011527689a03668c05064220e9f969c3cbb11ee70a1c9b323e10e4a193e9800f14a9b1d08c204a03668704f756d8580410c4cbddf905176550d45a627a7a62160307b071e6469b31719c0030d45a27baa6b2b04641af67e4346c427a761d35206cffe131a02e20e4cc1cfee6183296df6a30f1b109f9cdc535d5ba1e152efa7736a5ac2d06b858ac6246df66094d1a929837baa6bbb74a1975d0a1930787675873b5c187af65e8b3b2c8510faec494d606d76a46153060c4ceea9ae1776ec9add9d9bb8039367cfb8c3d0d51577b800f4256df60a41671a2eb9a79abe2f79f61477b8a024e4a4cdeeb6424bae8989d92fb81913b32bb9272666a1d0b39fb8839267612e4269b367a1aae49a9868a2295a8dfcf97a165ca1ebba5bc1457229b841f7c835727791bbcd312277c89da05dc8dde6db6b0f727fda7d3a99e3b5f7b4b3eec65baf7dd5ced31a58ec2084152433deca53e7dbeeb611cc44cb09b7c9e6960a3746566d8c750a37eec2cac74d633c338929461bd447ad3e85e7e968c6214c31ecf5e5a12822ddeaf2f0a7a7450fafb556d4d081218c388995e6284c9587b8d894e4c5156064d39f9e0e9b42e8b724608861086c491fe8341d54cd827f7a9a5bf50c117ced28f0755643008bc610422b78114942adf67cba88758bf07acdc3f5b5d0791a1979694d4cdc4329cc9256332908cc435cf490a5b6f1b5632f4609915d688069f33a1b0285069c8a2c2f6eca0841abe395eb52802b55945084845511a3c345cb49091f584aea14c999996e41e03861134be304c6082c3a2948dc11c34126a74e901c972fcaaeb01d53ec64a1657169513b03c4ca15313c725b8c4ab4d83242040d8c4f1bae132e5ca83111454f1dac5c590c3733625e5a902a7ef876e489ab31040d9f248c1c199a5686cdc91732435a14608f1f3b2bc8901c695167454e0b87195e71ca00b91a4b0209230b53478d8f11b43a5459be989c2dc9a2a3849517126ccc117b6202caf20f960f9298a86a41830e95da0677bc689cd07203881bb8b1203194907d9dd9b242c7d4a26cbba186c5151f66ea5c19d1040905c68e2c269c6819d1a46a0912155b5472badaac4c515bc1c72a8d8bb72156865cf9b3b5a5146353252bc04d0c6bcbcd881a31261f1c27aed658e1d155652996dbb2068e103960f60819c164cc59982f6caec66890a1f25aeb2cece1f5c6ac871cac2a291d59632f54a49153c2abcf5ebf3aecb5d6c53ca59a6a3be1cd30213f7e0385d2903c39c295c48894183c58250f56098f558cc7fac6637dc283cde2a182871a1ecbcffa44d39caadbf156b607e43380071e08415595a5f59587bc7ca6ea6eedb5269045638f382d0ff35b1e62b8b13c85dfde5e7fe5298c9699b2a3897d76dd95a7f097569ec25958790a5359e5290f648dcc5306c84cd9bf94595c98ea8a4c2b4b6d65ae2ca5cc62594a97a5789e3da765b6fc96bd54dff96bc87706dbf9ce6344be33d9e77c06f49dd13ee765916f53ec739b91efecf63bf29dfb7cf6252fedd967cf39c4f05512e7ace1d6977667e4db67cf56596a8b483508e62aac9cd36ebc86e6e6816dad0d280a9f76e3b1af3323d998590f6cd96ecc95a58ceae2f26299ec6937a6faec3847115fe124c65a9dacb5db7c6b5a81081178c3af76494cbb430c5f4895bfc109640d829e1d8410b25490670feed86310abd59e3bd61472e4167a1ce9d8a3cf4fbb0a31720b3d8c54f608b492d00ab53d574851518e3db24cda608e05ba42806ea1079037a34d4ad99d2b84c82df42042d9a38e2dd1360d850c0dad5f6d5451c88409ac93d683d11522e4c6d7ca4c396729db0d7ce72c0b3d5abd7cd3c20b74237ed937863f40cfc2fe84f961fba5ab3609187460d0f310b3958193e345989cab38644c6039a184a3e2a14647074ac7c786292b94e461f1c5cd8a341e392a30b13228b0ccf071d312e4762600606af4c829f103cb8f2c6e7c54a890b9519239d9e18604727be1418a04808091518e596d112bc01c1d5d5e36ecf4f19ae3a43767cc18c5429c2b2eecfcf0b224cc065a8444012386c714397d74734e708002743933b64ce993474cd90a33ce11232d94c0d8fab1bc726ad1f065ec2097cba93937ad3e97b32247c6477d0923314c5d8a01047a95b367df0cd3b2ba4286f787a793399904539319d8c2b901972d5a8bc7dc345376a05bce7552277512ec05606e6e6e6e38eb054b33333324b2ebec6acde588ac3387dd50ece6a66be3a6f65bddd2b82b89e5810e861809e7b644332b1a8140cdb6443353e3e13e8f273c77a7db1b9e69aa5abbaf1d83407b2e87e2ac9c737aa6a9a340a0aaa2e6f2cd344d4dd3d4a88f48711a8767e2676bb567f6d9daecf8c46606e7b3b56606fad95a3383fc6cad990106619a692e97cb9d39d46c7b5b84cfeea75d2a6bf19b53c498e4e1faa2dd182c4c88159d36480f863c2dd09bacb69776a3fdc2a2dd1e1664ecb79a21471b1684ecb7faabc9e735f14b2371dbc7492412d9e3c518638c3146c34b074b5d2d30de6c7529b3d02a9c6c3116f26473830b418fa966681ff2392c1a1dafeb893cd7e292166bacb13e7750d43ee56130531d6bcdfcd13498442249a8a58eb3305632758cc4c8104c93cd7413c27d6a9a996340635b1caabbfd6082b929ccb1c714ab7d969ed254398b994cd981cab64b536d01b1da645e53d95ab10f7a2a6b994c39539978cd64ca0e446bcd80c6b6b887409d70035b55b8dbcf685aebb3a74966644903a695a53497ca1ed18caa5a5a60bc51fbada9307ba6ae838ddaefbca6638125cced771653a19071f33b6be5d8236a8524a2222ccdef4c759ecbd4ce89b536bff1da67cfda51d600233e4575175018cf4cc2261846eabc6ae3a42e04d5b37fc8797687537d9b6c40b4d66c9b6343e3a3a703816d0b06b6cb7ac1128934978f8ec8423f9ceedafd35063be3a89eaa69eaa9eb5c751172aecb7ebe92c8d77342144d3361d44c336134a7407866d246978fe320df0483c3652edf046bcb7a9d3433d060a6135e407eb5327769b7aac419bee439d3857cb117f5d40829d85780d45319dcc8b205867cf18817e317f7ac78c99244be5d7aca24036286ccca8cac826212844fd78b3d636533cc86f35263c76ed8f15617567a404f69a566c2ae7ceca1058db1173b08217cd0531aa999b08f3d76a39ec24a33532735524f99afd9a2ca53a88559882e5df0cca4ad9147baecd81d70ba168e201c61849e67e1799e193d8b9ae9ddc09e500b4510a1c89107da1760be1a887507a47034e0e8d0318644be2300093f68a6b4272481e9cf060bb3f0147a7b3a906f172277d97711157a00260c41339dc2118a7c80baf611902f1c01156236d8738a855988939a293d5da7cecb4059d9518f40765478a473d4cd3702d88184473ae191024e47dd01a7a3c2118a7c805dfb08d94f77801ee1fd9095780c2b7b6ebe63471fb08e3a2a14a1c98b88da9315235e56847e07b0ac10a369a6d4311b46c3277498d042b2e349ab35d1d8c484e1b942919a294de1f230f50cb45afc1bc31d29e0f4ec0ed01e50b1ee0839a99952df79f9c882d3c68544be996b2b2b79f4818797750f2feb3b677deabc9e9bbb3453ea0fa735dfb14f3d8369a6d477eeca600e30ef5c818302f9a2ac5b91304e9e2491c897c7ba457667bbaabb00405cdefca07339dfe9783b9d4e98d3d0f29075cdd76473c27cb601acf5d4773efbd4b39b9e1281153715627dcada58bca908a658b1b31ce25582c49b6a305ac47c41165153f6a69ed9f4d4882bb3336331962471e2e5d5c8158d977a707afe23f5338b56e7aa9ba6699aa689d903e49eedb1e918638c716641e43ea7b11efbd639e7ac5910e9e7fc88b2c0a66badf5c982403f07f7d8cff3445910e7e7d823ca023b8aa62c08fdb96da2a5391644fe9cf3d435c71e5116edea3c5779bad57577c20d823f95a9ab9f9e4a10d8abde83eca80bc9cecb790842359dcc73d56c4ee75217820a4da190537814c7df99c59845323197cbfbb498799f3b7bf4a96f6ef039a144e9448bccbbdb575531afaa612bc1caca0e9f207d5e550b9857bd027b548dbe75b3c8b78ec41e5b35789405caa35a5864f1f1a853608fa8bf0dc173a7cb94386752d2304ff4c28a903d60618c6079d329596c7cea41f698fa117bcc2dc11ee8078a077223f60894e5e47beaf7c07ccf7dd8ebf950f1bda05e3eebf57c02bdb59e8f3bdff3f5f2979ee3a49e52df9e63ac2c657e0fed159148a4899eab7aca449b8125eec41f206a60de5e1b384a966b548c69827c77fbbd3278762cb9b30409901e1e2641aeac9589238145cfcd9ef7cc1c8fa2a8b73eaa3cea45ec11056acdf4da5b38afc37a70bdce0a7bed40f6a83d4dd3d45327628fa985cf65d5f89c0fb1c7dc04f6d833c79ee5a1e55917628fecdaafab975fddf594faaeab3765a9d4572f6a230faa5f3dac0e4296d2befa04cc35b65f9d043c9efcbabab971d5af8e93abe3ab15e7c059bf36e972560687ebaa04dbbb1a695164cd09581a20ef6ec15637b709f72b46fe1ac603c6abaa07b14775c40c307ed888093344cfdabbdb47d12e8fc68051e64d0a9a2661d05ef4ca9a47fdc71ed1a2cfc1f99cfbd8634ed5a3c3ca8d071821a7d96b192bd494e420014b9adbab9d4cca6b6fa5923edd01f6a903b1c7b4c71ed72df6782e5db68f7b7a07dbf841ef5c9d50d743e621d60959b83cc42e15d7de31de31c6fd36b2704616cec8c2198d4afa18b9fc366ef96d2cfb6d341a8dcb0c2471d165cc971f5761de6d6c3206cdd5112a5c92bcdbb82487d80e2d232f4860bddb78012f67cca4ade1b2e5c6bb8d137041470b8e14b73950de6d2c22c3890a275a64a0bddb6866cacc14cef27b6a39c536b59c82fbec53c8a9a9a9a9a9a9a92a5255a4b0fc9662c7a4d83129764c4a6a899514155697949494d4528749d411f799039bc581cde2c06671e0c08103599e62bd582f0e1c5e7020fbcd018b8396df1cc64694b0268d913125d09480f66e0e40f0c8b142430d161d5adecd21f9e78819202a98a8197b3707a5dad9128ec98f353defe6c0b688625b44adf91dc526a3dc3e47c17df6286454cef23b2a63f91d95c77e474545452db9fa1dc516d596b4b241c7445b111639de1d55658466c72d88893b3aaabc3b2a096587891f59ac7419797754d61bb82e7660c0c9e2f2eea82d1c65695bb29c68b2e6dd51ca3d6e2eb660787d817b77d41aa835506bbfa1d8a0d8a0d8a0a0a0a0faf4813afbec504b74405df90d65e5375495df50634df894f0e1b5b5e6c9bba17a79a8f09825c58455bd1b6a859e3b39943ad0e859f36ea82c5646520b8796650b2aef86da22010f9c1336555890bc1b4a7925c7878f3d2d5ca8bd1baa6c43d90635bf37986d30db60b601eeb36f18b241ecf7062abf3784fddeb061c3862587222adac0b42cfd1c79f786aa2d6dacd4d49accc91af2ee0d490b98b8b3a5c6c8599e1fefde9055420c956411146a3cdebd616b6dc5d50e1b5e7e2cdfbd61ce1d175556dec0d1f1ee0d2b1093b80289fbac61ddd2b06e6958b73468d0a0812c4fad5feb97060d256898f25b03d86f0d527e6b18ebd204cd94235762c478b7861e5baa9c8179e9ea7ab786e408f22c51c459ab62f6e3dd1ab23a50c34d5a1b347edadadead616bc50db12329809c71f26e0dca3765255879c930637bb7063f453fc5b1dfc515595c91c515592c168b64796abd5aaf8ac527c528bf8b507e17bf7e17c730d861832d39c3099f16ef2e569d58a621221686c657dabb8bc9f6091f367ee4b03823e6ddc5acfca38e161a5866d0e4797771ab4617136e41d04ca4787771c411382e4b5270ad2821cbbb8b604c2298b8cf4434221a118d482412dbda88679f9db8840af1c96fa293dfc426bf89639fc17cc9621624cc1334ef2656ed21e1860a2a1540acde4d4c52f95263e72ccc16ac77132ff0756487d51c2079dcbc9b3800146f66bcbec43da1f36ee29b316fccd87a542961c7bb89459e8a3c59f9fdc4eb7ae2753df1ba9e9e9e9ec8f2144f8c27f6f4b464ec49f9fb89c9efa725bf9fc6dcde28c981c3c81be5bb9faa3858d3838e551bdc9bd7bb9f922576f850210547189f773fbd6c4c7839e1a1054894773f1dc08513a4da9d196adedefdb4858d46f28d9d253262bcfb8967c324f26cc47d06fbedc4cbe1d4f6bc1c4e6f9fdda9cbd06f272aac2e2727a7a5139b1f93e827ee73130fd9c44336f1904d4d6d9a94fc6e6af2faddd4d4d44445d56645cf9f363ed8bcbba9ca03578b1779500069d3f6eea62490b41245b2909133e6dd4d4a3b4a963d5a78f940f2eea63526714ddce70c3bb60c3bb60c3bb60c1996bc6548f23b4309bf3320f99d2143860c567c6cb418c246824bf2dd19d8d8f073450c450d14efce00e58a4e9a145f5e5829f2ee0c59187c2d6133068a98225befceb09580b715253801334386cbbb332885cc6833c3f2058c8a7767002bc350860100bf31986130c3608601eeb36360420203060c183060c0a0c4242a89fbcca46452322999e03e3b13932453d76fa623bf998cfc666262625a5ac1b9d3c4879d3f6aef66328183c5902f5a65cc20dfcd5425cccd1909aa2246e8bc9b8958b6359694422287897733996e7c669c25bdf0f06af16ea6186e5f5fe2caa290e07a3713d84ec770a76398c1efe12e6bb8cb1aeeb286c3ab21d570381c0e97bb1326717722eef3d2ae6a6957b5b4ab5a5aaab154e4f7d2d2d2d2d2d2920232c2e2e0a9837687eddd4b5560b26eb40842840cc5bb9792714c629cb8cf17dc2eb85d70bb00f7d92f30f17181ebf70522bf2f90f0fbc2d867bf6076e142da85b55f2691209532c628bfde7da1ca4c0d1424eeb0513363e7dd17925bb4e2d468ab8387cfbb2f643db92ae3032b2bc9d6bb2f6c6da06dc50e356282fc81f3ee0bba38ca3a7161ec8cdd78f705304a6094a67e2ba129a129a129c17d7625264294a8b0ba9494949496504c2294b8cf49604960496049495e9f9386fc4e4adafa9d949494b4a461c2cbc48e323375de9d54b5470a1b3e38565ccd797752f2f3579d396a5daa78517977d286137ad66c59058181e2dd49402c00b1c0e1b7852d0b5b16b62cc07d760b4cc02c08f96d21c86f0b407e5bb060c1c252049858193a606af448bedb4255da18db962d30c844b1f16e0bc927634adc108223c78a3cefb69005656d0c4d97d80eb2775bd8fa123882d0f852e3c5bb2d2811804589999610e51c23efb600a66b21d4b51046fd16ea92425d52a84b0ae13ebbb04ca8f55b88d525140a85cb11379ea4a9f19ab2a68b89770be1f82023b2162606981cef1626ef98c43b719f5d3817ce8573e13ebbcb04cdfdf1dbc572b38fdfaeebbacbb2b2a49698382a59deed5691019b9104a245898977bb491467fa2ca9111763cfbb5d655b92ac2536a0cc38f16e174ccdd57cc36feff3ea5a6e7b75cddf3ebb3359e354585dee6859ca7c4ffbece6f6a5b3a94a2aa84a2aec0aaab282aaaca02a2b54a850812c4fa966aa59850a4ceef07e57e8f1bb42d6ef0a3c7e5760c01a267046ba945e24bcbb8201a49c81b1870c0d3a6cde5d818b9693b63437616aefae904565060d9a8e1f634ade5d814415ade5913d26d2b4bcbbc20f2b355c34d0fc20a27c7705b50592da026923a949a424929a4442424222cb53aad6463afbec4848a0df483b7e23e9f88d94e337d298903a29e4d4a87273e2dd4855cb352a4e9c6023c7eddd48c93b61ca12fa20a77c7937d288ae3137d494fd21f3d5f56ea4173fc82cd9b1670c9b9b77238da0ec08133e6152ca28df8db4c624ae89fb4c818d021b05360a142850e893eb43e1ecb3534052c0f19bc28ddf146cfca6306707d8d90aaa1443b4de4da12a831a2c303360a0b921f26e0a2d701343e6cb189b3c5dde4d418d989a373b5c288152f66e0a28dabca1b193a74b0e907753d8000b09144468ac0951f36e0a504c2294b8cfc11c58300716cc810583c1e0d95930a8c2e87710eb77b0c6ef208ddfc1b6b2146368725e14117b77b0ea8e8a651cd59430b57707934f040a181c3a30eef87977300b0f17b41650ca66c8787770cbacc2a64a18395fec907877500964b365c9e3c90d3159de1dcccd3089b919719f8f72584739aca31cd6d1d1d111599eca71e5b88e8e943fd8df4779c6efa37cf5fb28cbf87de4228a9d256653e67821f1eea3ad3870662eb8cc4c59f2eea364708c891c36c4800511f3eea3ac0d48d4dec468f225c7eadd475b31d6d67e5475a18d79f791f22a0755123f6124c8de7d14c724c689fb6ce466e466e4666464b4f6d98dc8f2548e2a476564d46514e3b7118cdf46c9df466344ceb0d4d24c904979b75195084e2489f3670e9a182cef364a6270828d4d58094b5cb8bddb284beb0d0aae3c7fa85ebcdbe845580f1e59d4d4497bb791f2023ec698114266c713b2771b9599c4b2b8cf45a9599119dc17a515ed22b6b6cf5e94965654a42c7af1bbc8c5efa216bf8bc66898a5415251c951e2f6eea22a0274894341024e9d296ade5d941ca1420c16166971b06e58bdbb28eb4fda893a5ec4bc64bdbba8c893b82376e6bce500f2ee22351751e2ca6c4499e2f5eea21488494c81c47d066e01b7805b402010f8f5050482a1bf8156bf812c7e0357fc068ea500881c18666d905adcde0dacfabca38433234fc8aec87937d00cdbf1828d96b7256bf6bc1b78c5c55595236b26a4c47837300e181e267aead0a991e6dd40250b2a3d5ec9333ba0bc1be8c724fa89fb4c9422895224518a2422222222cb53e9557a4544a4ac42a4e23751d56fa214bf89d2deeae820fb91d6f56ea2aa2a1245ce3c9901e4c8bb89929fd3b8e08c51e58081e7dd44599fa9d6ecb03376660a8c77136d7d7e83a6051925494ebc9b48f919c98c25666d64baf8bc9bc88d497413f779086d1b6afbb6a1b7cf3e543684e2f7d089df4354bf87c63efb90d9d050dad01a9d2524d27461f3c647cfbb87f6121d2548f8919c23e3dd433f2a2cb4f21c712b8184770f1129e2a2ac4e1a9a9f2aef1e5a81111b7d84e8d9b365f5ee213e6ec6789918f34325ebdd436028940928940945bf27a0601350b00928d88409132690e529140d459b30417936219bf83d2197f83d2193f83de16843c5933c6247aacade3d21051a3f4e58b85993e5cabb27246fa4d811a60a991695774f48337685c5978c2b3d72bc7b029aac2142e82c8b5c9d79f70405a81053640a9bb0af32ef9e30c324ce88fb2c846209a15842289690909010599e42b9b6d0d967174296f9ec4219f95b28eeb7d09fdf4264525ec0b833a6c34f9b770b554d51f9402ba3452dabccbb859247154ed2b4e29ce13af16e21245a676f5cb0b8a0b9f16ea1addd1d3841eac8b9520295770b29bdec8003054a1c1d2cef1602434f04f9f913719f83d0aaa01d04f7d983907e7e07f5f91dc4e777505050d052a9f63b882da8adcbb28a932b3f926d38de1d84c1922b78e2b2dc19e3e4dd4120e8326749458d09d7977707b939f2e6cd969c2b5669de1df40124708e587ded90f2f6ee202c33e47cede0f1860bdabb83cc984433719f7fe7f2f73b97bfdfef4796a7ceb7f3edf753d2f9edf9fdd3f3fb07f7fb7767ed2b081f2f5d5633defd83000940622cd798ddc8f1eedf08ac272cceb8bde1a952f3ee5f1293225f56c07003a27cf70f03a41de59fad2fb418effe69e15ab2a6c6441c1a5ceffe2931894ae23efb943ea54fe9f3f97c64643e9f728f2fcf6f1f9edfbe3bbf7d639fbdaaacd1da4182489e77fb4e40a70d123a7a528cf178b72f4bd89cb73e507c3c897bb72f8b429a3831b6a0d07245e4ddbead26557ece44994135e6dd3e73cada1b1a6edcd4f048f36edfd9c2249e2de23eb767b26dcf64dbb62d599e3ab54eadb65dd1befd6eedfc6eebfc6ec7248085042467705c7e66bcbbad223249d145d985230bd5bbdb640867c4c879f3c20a9533ef6ed98021b388294de0f9f1ee76ab03111c493a5fc2aa687977bbe683471adb9eb8175adedd6a200db4813450dbf7017afbec40318080808080808096406c6526b12cee73cfac67d633ebf57a3d36b6ded967ef69f5e8fceeb9fdeecdf9dd1bfb1431b8c8f4b9ba62f5eede8b124aa873c5cacd32f9ee9e0d2c7e9428911104489b77f7b2726481b186e32d0856d8bb7bc82a1438e2c250f9f3e2dd3de51e374d76a801c391f6ee1e10930824ee33bbc56eb15b2c9bc6ae7d76962c4fe9afcc845d7fb1679f9de562e5fc66e3fc66db7eb3639f7dd850d2d002e3aaebdd6cd5672e2c2bbce8c9c1f6e3dd6cb20538d8c68018f10292e2dd6cd6671663b2a898b4483e79379b876a4814384f867089f16e9645d7971a619adcf0827c37ab5b9844dd22eed7bdb2fdbac27df6b5499215ceeff5cdefd5cdef755d572956c4906c0943333bf1eeb52a4a143145be909044acc4bbd7e4e7ae3d389225ecc191e4dd6bd602667cc5b982a4aa079e77af5bca3c5957e62851d2c4eaddabf28d15b3b12835c40079f7aac724ea89fbec9bd7a74f66c2be796ddf87f7f6d9794e7854583c1e8fb7e4b199318966e23eef96bbe56eb9db89eda8d87eef76bbdd6e99254689064d4e172037debdcb425ad1852d2d8db20bdcbb775b4a4ca292b8d76d1d9b5297953a9d4e474676f6d975481d559bdf3a2c36bf756b7eebc61eecca8a85962b2ee0bc5b579585c8d7da95126469dead4b7e56c1a50d45dc902c2fdead03c18d961f3564e840e2e7dd3a07f020434369620f9a12deadf32165c68a226162dcd0f16e1d58d66112b38eb8cf2adc6757c976bf552aacaecfaababc93f37327ce7fe7fac0e5e0727070b9b4b5cf9e23cb53d92a3361dfb9b3b2b42cf563969aa566709f3d5d4bcfcc8024dfe04923e184c8bb735b9fddd69475b4c84811f2ee5cd6daef5c57eef73b970bf3699f74edd334287150503f60e846e1fe09d90e3f35486cc5887b775aa5b45c3384c4993044c4de9da2658921c18a4c942f26de9dda3112864c8f903327c2bc3bdd42011991396b685a56dade9d2a392831a3081824da9a14ef4ec1d4fc4ec7d2fc4ed53e24deaddba07ceb370df7a79fc8377f9e547f9e55565739fef4334bc89fa7d69fe7d6c9f5a7d79f5f7ffa09d6d6e6cf53eccf73ec24fbf33c43fbd34daf4742724c027b446253f2c1603018247a30e8c6ad0fae411c4107214b69f0a04f208814743318f4a08d3b5780488141624a7087561a9b3a24d4e013448283e406a9cdef28b62d8fe42792ab6e863cd29bab477ae3e79190e04c7924c743d82392f17c0d1aa6b065d96afb2db4fc1d7ca29f44221b374f6c03e6896c823cd1b110f6480cc21e8339c0fccf7fbf9f2735652929ff79511b61fc6fe887f5fbf9047e1d7ebfdfef47bca2f0fbfd7e3f0dfefb59f8fd7ebfdfeff7fbe968f316dc826320ecd182060d1a346870acc51e3550d021e42938fec11e29a8442291e8c3e93bac7d07c73dd8630724242424242424242424c759ec11492a87899772cc833d4a05836a7e5489d5592ea7a40583fac6078316f852a3b3c44a8c1d3f6f30ee838e77b0c7a00ef6f8c3a1e37d3e6de37deef3249f476529f37d6e14f23e9f0fcbe72064a9a0fb7c02bed3e7731244f1215de5d07a9fe32d31ef0bf2f91c8f6529a2fb1c93f9cede9786d462461a1f6ae0b0a8c1c5c99012249655d0d4787d5f57f88c91b9d146c2279547cd4419931c5dbcf87c3e9f9b3e2776792291e840a2e31cec918884e4aa124730180c0683c16030e8f8067b0cea1f8e1bfffb85e1a8f13fc736d8e30f8b3dfaa0b04e3c94e31aec114a7572a0933b7952767272d5c9e1de69acf83fc734d8e3cfe79bf23ec733d8a3ef8a3d3a199bdc04fb26c732d8639315af7727bcebbaeb49ae17dd2b45de756bb80e42964272d727e0fe5cd775d7c49c1324e08ed80013e39a91f18227c518d79531ee94d9ff7eaeb678fee738067bfc019190683c92ab4856b03c926318ec11290ca829eaf4b94ae27dde52799f037de8b3827cdfd7fb1c27d9a3cf189cf141578362ca0f3a7ec11e83ee823dba67c17ff2334b5198a1e59f1cc8e39f8cfc93e316ecf1c9fdeadddde7ee6faebe941183c682cccdeb674dac70a9696952e7dded8c1fef6e9a799f9f3ec756ecd1c7823d3a13993acfe478057b64dac244c6a3eeeea817b5f1cea3a89b2084e084ba4982268f9a6f5549ac271475bca5e3d11daa63a0a86333241475bc4483280c649672a97c28ea190b7542d1a0a3e80f454df8e8a166cb09103938de1047c0f859834384eb883966c259a1c2468c093c6d666f18182dd420b7d0507b37567ee8b1024cab4509384f5053ec4916da924a5814258aa2fefbfd7ebfdfeff7fbfd7ebfdfefe758057bfc0575f2b7f183242ce3a04902c5cb8d77b71fe483e64d588f2c7d9ed479f7f0836dde2469d322636122187cf1c1a0922d4be5972548dcdede60d071157b0c8251a1221646c517e68bf2f97c667adee7f3f9be50bdcfe7f30f675adee71da4789f7b80e57d8e53b047df97d589286464b8ba5e9cda05524a191638deb69ef4795d3785bceb18057b74d747427215c523597924c727d82352fbc4a5ea9f1c53b1c7270d5bc4dec9b109f6e8b4e5eadd7109f6e82a09f68866b3a2d1187ce36e7ae3efa8371a036034ba0a43cc1bbd05a678a37b0cb237faf0c51bbd28a3cc1bdd680cbbba7aa39b35dee818c91e8d4918df7adbe2dbb66d97ad1b5ba7164eeb206429a3b73e015fdb3a09dad6aa75bd757cd5b66d180c15dff65a6ca255dfd6b1599632bf0db6adabadb7ad970e2d566a98f028d31239d2a556030957d5bad9626552cd850ffa08f6180c4b6abdc075731bdf75dddcc3775dd7755dd747608faecfe7f3f97c3e9fcfe7f3f97c3e9f8bc01e7d409a0509da50014911c50c1e2f3f2d3ec080bda11225460594ac9db9e9dacae2c668d42bde68c4aa9325e52a47923e715ea3d15dc01e8d577eaffffbb9b983ffe3d2f43fffb9fae77f3f07baa8f23ff718ff0b7ba116d6e2c8ffbc054516b0c776c9cd37bfe42b608f4b450716dd87c522162f5f041655148bc5b65874b5380114784ca0c1c17903576c83c22b0f15b32865452c2dbe8825ebdbd655c01e5b742ccca39e02f688a2803d164d37f795d2f0782517c11e95ca64f934adfa344d5d4fd334e4a7bd34459aa6c1343563e6d35eaa51a4be2b639a2eb57cbaa63f4fd3629a3a5eaaf874283df11999a9d236dd3999010b295db880a541f9f3a64a4f82f001e2c64b9e3da90a301746c274ac9dbd306a7ca9922cd345459a162547d61b332ac4de6dc22d2551335206450f3457efc6c854c8981a39697cc01832e7dd98edd31e40be14f101c625f66eecf669dbfe0e367d1bb52cf36debaa1a8e6fd5c87cebdefab0f562eb27608f6daa4da0e80944dd51ff80ba3a6529e65137c1162af33ba8562c9e49f24507a279f14577346fbe6806cf17bd04ecb138443595e9e709d80917407ce8e19282c9132d5e574dc448f95d79439219533623cccdef67e27fee74fe77268c89305a5c606f30de9f1938ff7312b0c7dffa46a319ab37ba59c21b7d04ecd148a44bb0f94b1a8ef7b9ea4b73f13e17017bf495f1f2410f017b0caa6e1921ef7a08f6e882803da619cb5fb8e6cf0b7db347a19a14afaabac4abaafa73555513f62aab6a12aaea211455d54950e55527155725b3547b954305e3e7d5a0aa91aacf5515557117128964a16ae00758da18166a6c8479d52c7073b2d4b021117353a5a498f11137e5480e1f6a9f3a3666bcb519a35255d5e8a50459d698376486a84cd610794282102e3578de8d95afa2c124b1280f554c2aa87966c6e4513f5157d58079d4dbaf471dd8c5cfa3ee5ec01ef5e1dad5a35efc62e551379e553dea1fd6d01ef50e743cea1eac593eea1f608f28da8aa7f87c6644dee753c3e57dee01f6e8d3e0f71a80df42c19d14f6bb29ea530f6a983f9f7afbf5a903c5f0f9d41dedeb531f92f874ca182a9f92a1fad4c9a7de01f69802c5e130338282c61b197ca8acb87144c58934ed081d2e5068d9914c9695b5bf6fff7ceb4ee4db13a059a1d24406922f4bde764a181bdf3a07d8635b5473f545df007b2cfed258f99f6b803dfed40cb04715832aaec7c031c01e318803e3b5f6f35a1f19e720739fdf208410d453dcb84c3ebf31c6147ce31c386bab4e98a2df986bcfe3319d6a241279423b5edea981f520331592ef6c95b1f6e41caf9168cfca2cd5baf6fc55c17716cb6625f259667bedd92dc36529f3dd77eea3abe4bcd6567a2b4bf95cbbe6f2adbd5ebba95d83e9d1a1c5e07e6bb4d7ae97594ae8daf59a05dfba4dbbbd760d87e2b5ee93e7c43ab3f6a9756ebdf6b36b8f9c138ff6d32c4b29b9f6f3ec82ef334dfbc9c6270fd2efb3edce6f145995a596ac86bed12b14ebb5a35960a8d6db6f54f9da51b02cc5e4da51310cbe5132d4ecb5a3687e7ebc46d3ecfc46dd5e3b0a9722b394f9197ca754dad36492f4aa8e6e72eda95776f29d7e694fc7ac52b2d7e9f2b5a76c59eae7dad3b627dfe95b0ee9274745477b2e2bb795a5cc27face7175bdf69c126927f7e5f63b67f6da736859aae8da73691a7ce7d6726caf3de74602c8ebdcdb9cdf6ad56b57932ad606df6a8eacd7ae6e916023faad72c9f9ad82bd76752c4b41b976952ccab77aa6a2bd76756902c76b752d8e761d525795a5cce7e05b67957ced3a2c5d8eb6dfbaaed7ae53662929d7aefb9af2ad13d38dbd769d19d5db6bdd199cdf3ab6d7ae73cb5246d7ae7bc3c0b7aecfeb1db2cac584df3babd75bb4efb6765d19f8de79bdde295ffb0e0c8599d73bb137bf7768af7db7cc521d5cfb6ecd83ef5ddbceedb5efe0525c11fabdebe3e6372f89950500df3cadadd7ceebb2f19ae7f59aed374f3b0f4d03dfbcb4d75a8f0e145b42f8608933e5d54cb2a2f01823c184d5bb5b2a624ab47113848e1822ef36d9f0b0a3f6440a999b8d779ba6951b6060b8f8c95286e6dd269c9196da8d3148382a66bc1b1b60085b9a263c944ab377e3ae2b35155d6968e0e053e2dd784b959f382c207ae2eebc1bb3bdae1164481f27684594bc792ba3e5a54e6aacd75e3bb0b419437691f26e3df63a4d91316bc01c5111e6dddaec75559f3229967825f3bcfb44be0ef183aa4b8c136b5b62e833509a6c9992a4488b779f76e2fab859bb82c46dcebb4fb0d75b636eb4889b530289779f6e4954e0d972d6674e5c9c779f70232852c2d24e16b82247de8d6ea526be662873a0d5817b37daa5a48dcd2c4d151a1e6ade8d2e5f6310a38d0e9d332c9466de8db2bd365156c4080b257edabc3bc57a6d9665cbca1f2e593cde9d66bd4ecd5ea768af1370434d091f52ae3c81f3ee5cd56b1b3de2f498c5e9d1f3ee5c7284b2b7125925a81841f1ee1cd86b23ca3657702ce15202f9aaf598c1640dc98d3f64de9d837bed315abc91f9596ba37ab78a7c4d45cc941676dabc797bb7daf5fa4b169d1f79be94bd5b55565892c46a471435b6b477ab6cafe39ac41992a78e8cab33ef56dd5e57b9b2634e96e59e34efd665bdce52a5c41a38246dcedeaddb7a0d825615b03eca12c8b4bd5b87f6fa05132743ae9cb8f0f26eddf2b59b7b977ced3b2c13e4593333a35366cfbb77634f6061aaaa2455acc1f2ee9d590466e821010d173c70babc9b877cad33e1e6678d95951927efe655bdae9396640b7945c69977f394af8dd4a8a3a44a0e153eefe681a528f31af899a534780dfc02ec5103f504008a390f000f813d0240c5e03d68bd07b7007bf4a076e8d0a143188a1fdfc12bc01e3b38007eaf9f0195cfc0d52e9fc109179f8153803d66d056c000033f317015cc63e02d0661542c1e039f007bc420c8d8e6b7d1c9c6123025b4b84832e3dded1bcbc8a8a9c127489994770fdf28268f1c3034780881d2e5ddc5371ad9bcd11dce1b159034c1a2889d2c6e5d5ee39f37ba04d8a371cacf2c05f55353ca9ff208b0c7a9b67d2929074ab92a156682eba51c02ec516a7d0e7e72082b01e639c43d0707813d72689f3ecac947f903d863940a05050555e4a1dc01ec110ae937849148f11bbc01ec7183aa4183da6bd0a0210c19e335f807ec5103b0582c168bc562b1587406b0c72291482412e3823cd117c01e894f4ffef4f4f487ec9f5c01ecf109a8fbadf96dfc5f89226d6be43829f1eb61768686972d4ac83079f7f07f6a304ef4c0fab106e7ddc5fffdd6fef787caff866ed069c3c26dc7932aefef8f94ffb907ecf1e7e434f54e4edec679a725efe409608f4ec0a6a6a6263f48bec911c01e9bc83e431f319fc10fc01e33a84b8fc1c6637003b0470c5b4e097ce06459e531f3eef69998d43c93ab7a4a045a9890807351a4edc4cbd467c6337901d823930f877cbefc70cf0f9d00ec71d82e2d2d2d2df900d8e3d2853d3cfe8277c01e2fa84a4a4a4a7b68bc9283608f4aaee593f43cf924e7803d2661b120e62dc09dbd853c7ede821fd9a305a1502814fa06ec51e80abd1b7cd775d5f5d675a09bc7c6bb2e00f6e8bacfe7f3f97c3e9fcfe72f7bf4b97b78776ff16c79c713e3dd9f3d3ab0ca57b8a3e42bf807f65841cdb569da766c992306093b597ade3dfcd64d3d05a5e6070c1f6b5aa4a1b56d7bc7c8b76deb01608fed9ae5b7d02321b96ac7ed91bc7d2b7b243b341ec935608f48c025f58caa0e5f5555b5ce9c5755d501c01e55a92e177e277d4a86ce904fbd4de9a0f9b44e971b974fdd037b4c87bbacf636c17283c4923353bec0a8e4c811850b1bda5b5619143c546eac968fba57298195294d4e98585375e445dda23cea1dd8236aeef529380557cd3c852973924fc133608f145ab4dfeb07a37e0b7dd0cfa0ab6f1f9443f6c138383ee818b0c760f08fdaeefc911bd9e3d1147bd46c46635c6fe452ecd1482d72605151515191ab45ed988e2f82f3e886479d037b44b5d65a7b147bd4ce1e8b8c402b0ff40dec11a80a3d5146f3444ee44944445ed4533889442255bc44aeeaa90e596eea2c6ba85953f112695952d1d2244b169b77b74fe466094fe463ba54f8ddf4dbc3339530529143c59d15565efbd0c66b2fb250bef60f562a5ebb06f6a8c7720e839ef96da235800d9989342b4cb8d29ca199f32626264f1d36ef36c73420068f0c2b3442dcd478b76996663355781ef50f55708fe2205c32b8d8a0eae1f6a2556e8f7a913da24b227b24f2fdd0d0d0d0d0d0508d203f94e6513f517f628f288d32afdd893d6a6f628f431afc841b577e8267608f136c50bd90900385843c290b09b9d1869917f22024e4131012bab1e4858484841c5f09090909090909e5f900bccf31b0479f0e4551144551398fa2a833b1471400dfba99f5ad0fd9639b9a73f6f08bafb576bff13acc868cd7bea43279d52fb04755556321c30d182e1a7dc4741a148fad297cc27ce401f2a6585e9fba127b4c3d893d0aa57d909b5c1fe416d863d08e329f734f6a2aea9c1baf7cae9723937310f494fae63c8436977312707d2e2897c7e454cfe57cb99ce3ad2c654e29d3f1b91c5acef11826fbe5d03e77a4cc8a0c102625743979737ac020011245d9a5c49bf35c87ad3827bc547cd92acb8d808b131a62d6cc70e1c8958591c94203cf94322cefc65d9f9b42d6450915321849726e8efdcfcf9f0bd9a61da854289b89a37916635231c86600800273170030281c0e8a666194045914e30714001666a65a60561b08c469940331638c21861103000000000046461b0220aaed11c9557d1adeab008fc3230558a7a4264c52638115267ff94379473bd865f49c0f6976ac4eb694c7408077ac2ec38d8356af4b5499c5de89d6e9885e320458ea9010ca51b79f439e442d39881526d8a8a45b03a202b927ed25934db68358e7b6e585775113b7a76d40d5a1ebbd88111c226fcea58435b183911804b450ec404054ef77ac76b53a4ae27f442b933d95f57dec830328128d993ae997b1314926fab47417b3507d7941211642c8cdb21f87bdf9b825cbb8d7030d9551d956f9723c5e10c2969073f383f12ae64200d226271a138c435dc02d9c4cd0f58732071c13f1b3486e776291599d71d545cc021a7e2584d24ca3c60b814dd268a084801abc2fbac9136db0c66676a67038c37421bc72053566811a31a0c1afd21871b1fcdb985ffefdd7204ecd821f9b534fbda8d79d422e46e1a4c88e942ec7cc974878f7f2f98500269d50b023d0f471aadd00935249d27ed3260acef98362f68058fae17160241621c5baa04c6199f3218e33ba2b76ad5e5374a4b1766b36040201d0f2cc989f27b4579b07d7f70e08010ce04a7845bc11180c4a0eb1f131deed03c90fee1198d2f3179ab88163aa0502982330135c7204be17f3fc73e30394bb7562a7da9aa1fde770bc2b45e2e73bd056c0e080b804761b01940240bbffbe21788006ab2a9f74504dffbfe46c4239b2585f5760161c4ae71d9ec637c4bf36694a08ac7ee8e9129abe06c21514538f3b82bb4f3878992ae1e24e5c471db1cc2edf9c993bdce6488cac5b92918fef94ca7986855e8323e2e4c183d6f676a928df1b813d35f6729e9ae5a1fe1a36edde2bd6cbcebf5b0bd95469b83c09d92a5c8634baf15a8ebcbb1d2342c331249e70f8584f20ea459dd84125e83d21265e0e468d0f514e79e9e056d763947b1fa21c75609350a017785c7f5389ccecd3110bb637d8e7bb69576411233177644b859a97419e645d867ebf13d1cc4bfc54d16c81f635aa276a09572946de08af912fb76af9c940f086077caf0096e5e026acdb9c50fd9504c292d811bffe6fdb45ccbc96db4d584cce9c7b17331a792d297438c044636742a7723e7cfeb0591b473c6db8a630ac5ff95ccf364bcadb78528603d46e59d542a077e0dbf483cd69b1e8261502c845107e55e8d5c872a4b551ba8589698b805aba57c1bd5008bd13f78f43fd432f5cafb021859489057593183cd8d9e8bc3c306f0c35662312925cb0ceb44305072b0be7ac8db6b261154268a3338ac2662e2d95446770126e436777347571a710fe1987afd6d89deb436e7d04a186b23b2fd24637436431b491b515d90a816e33eb04d64be007243bc209ff012f1a0bb9830e4360fd1be2e311ba47463335a5730382adb522dc8df38ac4dde8962e6e1ab7859eb203fea233956dac77d8df2a09aa7ab184fff3554f611d69cdaa98012a1c26b13202bb627a11d8152ed204606e13a2d48f2e9d7b3eaa2da05b4b0a5ca0f5a5ee15f46a36c8fd5d4a2e6988511f160d50b31d0881766125f4e550594e2a0e4ad7a0e66b49db982bed80300058caff381c6086b7bce60135508037d567ca87b30154de23b55ec714cccaa4602af577fe3905800bddbb74208888fc0c0569114bc51977bc9b60c6c992457bad9c280a6d4ebc8ba14453d97c66b6629d0ba917cce8f045e5aa65f109502a91f1a4a9cf68d656ca9528c5b4448f7d17793c9d078c21fa21567175ef0f8cdcc8f1acf7cc2547488be12b70ff645d9f5321e4b32865a05169497150b73eba763a0df89c1e5aac82948bb741a360c97bd5a1034a39fc276fdc25c0807edcec56b32f4f81c8ec82c5a3812115de8d3387269abcf81be9cddf3fbd2475a43f3025625244fafd85d577ed18b6d2cb42249bd7965de60efe7ad4c77ec85a50079b6cb1cb7e5644154b28e6964ae5fc1f4c618cb332823bbe6bbccfab6f800fb50f867752b8324b72e819a8d4e675025c864faace2a0b0adc45b0c697df0b3ab6d28ce1faf1dc9805e476d2f9acd5431e4141fc5a5905a58c1649b35803b8984aa9070c697d638acd865a97610275ac57d1c4c5feb602fd085dd2e9cc57d1e32cff3c5c015ca958563c7fc3c53dda808bf0bdbc2ed47865e6d8463abc392c40b62cff8b738dc978f58161b028ce172b06bd24cd40901ac80ec4212fedd031fb1a80f010891a27cb30349ec1641ddf04067a62e06ab3a21d78cc364f1bc2a69c3a9f009968949c30fa6ac06714919fac86014f260bf1fdd28e3e6d09f981f9b3a61b3f12f9c34b905d9434237860a857d35ba985f6fb6bafff05b19899e34192aa3202b4cac692add4c488f14c1cf26cc9c58480f2a4dbf125e2537e8c98b05ee6b8a37881ba4d2d7976e10185211e7596c0ea87df736364fd38b8e89d7945859a91ecef9ead1981b50b359d743db1e51072104071302aab3aa6a6f9530b609dea9541cb1e53fe07bf42a7650e654eda5f11db55e891bb580e31e891e469f3a182633c06954a60aa8cefd85aff8156aee406e4137077f38509c96f608337e2a45d5084c589a839eb881f5b277ecca7ee9986c6085b357a23d07cff492702c8c9d1685cb8fb7d50b7d152199b548da2fd3475dbbce8d2140c73d41cd66816933a75f65664d21f6086f031de4fe5a70632c18fc6fcc5a7f9e09e600b072a6598c1d9ac22707323389a8d6b2143cd4cd00114de82904c18c9cea36bd52daee9a09a3858c16a545199f3e3bfc5392b87cd9ee1aa4587ec81d6dd240985068a0c6b9b5318ccd2a8316d3b08eb2dd0f85cb2b9f9510aa9b0cba8ba4566ff9a9e8950e9ee1d5b223f849979205dcb7c32dc469d8fa8737538574be9a648d1e60e41f7e77b5a02d28f160b97eec5c623d1d009cfdc82a91e8a8f66ef336d9c2fca84887a4b8d790d44b4343e52070f4279f82c48e84fea5ddc1618bf8d4971e189ac45d8cc6aa09a3b6410ed0fd54378ec14182b179fc4070048c9d3a6c022dc3d99bdceec148b83421353f40e909320b250fa00c567728d507700e0510b4daa1f325ce96f44bf77d1f332a721db8f51b358a5e51c7fd623ef3ce1ff89711dcf034902fe948c8eab202091f596c6444d77926e6b302cdddfd223097d9ea83502faf1a863de7c075efead3092db949d104ee633b5fab0021d05152e8161a0a5f40ffd47b66c8d70d2944a4e1867e3128c9d58f0a027750394a251c0d273a27d279bef8db0d9c9408967126a00774c0cb5bf905edc88f2998018108b688a52a722e37542717ec26a4a5f17fa3bba68f2a3e8b6be86bf8b58599f38b54e8e453a99c7b7b062d29f424b27893819c047294b196b3d4842c06cf6617b1498b48eeadefa58049f2d0430155bf22542f9aeeaa3e4ce8995d185c8b46b2a5693963c664ea98127d79aea5bf72e4e7779f1583442ef9bd3b901cac0e6965f8e0e35d02817503af74137581e4df7e157f6cfaff6f86c72712a9ddc8fc0e47d06e9bc85119ca963a37863e0882c32a7c7c5b29b54516f5c8447b490f8c2419ca13e6f329f742f853b802e0b7a2d3d3e6882be60a6fc161fcce9fde0fad4c581296805d69f7ada3e08a2f4fdf3fd855e5718dd08935d25b39e871ef5a7a097e1e6c6d2cbd1a2f9bf0dde18ac71a39c5494a6e86dece599fb5be2386205edf527ca7806811416fa19165aeeed14ff569f7a75613373ad34f9f45aa935d24ffddf39f86d92c608be41df6ee3b695db40b3579d88bd5c741eb4779bf7da2ea60ba450d8cc931a162ca5e9a87aa587254a5fc4b392252130c14407366209c65d0918879e086574abf0777dc04a0bdad365966a0011d87acc4280b3e57b9aef02f8f835f074018e9045882a7192139920764a58e5003a11fac16af287c1f0d6d0e38eba3885034fe1e676c57be1f71e8742c077630c098177cf66185c4226068a96e8b64bef8f07d7f81adf4d115f4deafb710060481e2a397ee0fb2a82649da69a820dd154b9fb182f0dcd4d9b811e53191317328bbfc50c0ea0162cd272743221be3009bfef7e76e588c6f58053d3443b55c375e391a280af63c3694044ae91fcc6fd20b5637361c6b5fc759cc2112d3ca118fdae049c8dfea75bd7103c705618d868ad1d04ad6607d1740b36580b2063d9820ed0651ddfc309714cc16b6c1cdfdae7f72063b767477863ce0a931fcfd236309f708fe7759034135c58fb7c0163f411dec380c506dd9652c181b65a0e42c5665c10cf8b4f3d50051714cccc46d637d514c3038ebfb4e543af61dff41c743b12e1144d1865664a8f89d5807e2c7bef4c64bf3aea8b6143f56e793ae6f11a0e1b472c3c278443f731402d65585d450953490a97878c1c02cc4e3afbea16b5d89ddcf0e63b5209a6086dc20624149317c3020f8f2f475c1d6b4e8d88fa681af6a8940acbf73d91d85b70d189e7abf1a5c7821c3407a2a5d4da5b4f9815a425eceda52d23510d081ee826fad14bd639e1b77a0f45658a8e640f4879a38bcce71c5fc664cb837d9c4c2ebdba479ef90ffbdd33a71de2ccb35387de76fa586f8b8a6379ed86dc116724274e026ac292d83e8e47e9773bd4b7e42619c900f5659c98922d041a7247c90732ba2724715abcbd80695964cab26b681ea91516df9fc823e227917f9b95c403ab15906a25284e1471c7adee8920fbfe06770c14f093733f3f8206d3983cc885724c084d514ff38453403120d18b9ef25a9207f29bc9727451f9bec1a838949eb2058f722f643416833515200b96a2bf7b87f57cec5e2c1ef4e10783a90e5886c0b9a2ab4404621d1e0c5e424ca488d705304a5d11692ff10f39936a71aba390aa7474e1e7f47c67744eb4356f65696a96cfa14a97e45e846309e9f0450c7004d5e6b2bb9b3c59dd3bbf5df08288818c0f9c55dd05063702e71e03c9d60964ae1820558d020830a664a1aa99271ec6d46e70dfa9781399d14aaa1c6d772752f65723e216a2e605e523f9473f3a92f304daa1e2f10e78e91457f167bdeb2be15c386f9dd3930bbc4e923850ce3d49c577a0e7b8f5c0831416607d93ed1c0d3c4a417e010de9e08823bead6943e2b4bb311c983cd737857044665f2dbf38389aff0f713665244b43c82be774bbc450a5da28f82601772378f0ca922d4480112e61d998dece437efcb38d9328610183c688410abea5e4dccc574db467c6741f62fcd8d37d0da2d6482c80c94a029d2822c5232535906511182b566e46a7874c8a55443f46e09dc36e1d59cd3cc35f61278907f430eb3fb2097a31306c637a5805495abc4f4c71245a368b3def961e1c70304a88530635e83bf276ae2024b5b3268b52c826a5710fe16f087ac69b3d44cccc8ab98595943156a7a86c8188ca5e5716c47b8d42c2868aa0103e2e10755b06450ec7e56e79ea9e11dc25c078df8a8b071f92faa292590012329d13794daf84249a2b553a462ea27ed1311122f8cd977d19943e92d9956c64ace13e67891b830042542a50e981f9ba6d3ad6862d514609bf21e3e5445f343c688b40b15e001d1588a7b3a92dc8348d196b5b7d79f561123bd130279dc9ab4fcb3493e597ad7528919e915a59a840eb600cf0818eb7d36ae55f9066f015f027e20799f081573ba2a8532740d11a7c6ad0bddb0dfc22b90db046a7173ba223a01cff8ee832f828e938eeb6629be25684ce8ef0fe82c0535bba2380c3c1f3736d41cc56b14df69cb04cd97737d17eb813d2f32dd5bdd57942aa90436e54a9191c25d8d27bbabcd6d2ec873ffbf67bf16b79d3e3f57d026fc1e0fb2850a14355585cfe67899b3991466bb68c1fc723c10b205f50323dfa86132e5955cbb183b54c582d2117d98551a05c3bf91feedf69411f9bad53c348c51b5fc0c7896b4d76701a0356b910b3958f6867896dec68a5483de32abeaf4630b43c6b05f49caed7bb4b308fb72399905aa478ce1a1338dc1e6e6fb80d12f1386d9904f4c39ad36686006aa25a01617edcb598794ac15dbaea2f12eb809560c1ba4bb382db68ae2bea91cc28283771c6c81ed4f86a42d9c7549466f571de7f2c6faea2b702608ad8308175ac2ed4de24e3893e612c8566cdb4fb99423206dfd303f83212df12df15004d1a3ac04be53fc92c96f592942754092ea2e9576a0c349c1c1481e341b16ad2bc4525ef4029dcf9b444a3e9283ba4ea0ca4196e3b396afd4391ecf221286c56fa6da07f6411c48dcd6ca9b37d9d2c5c59ec6502de29cc5a661806f4cfe0dfb4197b21b7ddada80de407ad6106181c61734136e75de6bc718eadd425685eb22d77234e1f5914ee5acac9d607f0325726818d2289e2c87bc1a368993af2c0b3909349c8cb96d5ba613cfaf9adab44551a4671a0d94ca426f539525e3314e58cc570bf7fbd3ae20c29a10fb1fa1ab3e52a5a2e475c1e3ac558ddca62ca40689f1941ee64a02478a17387ec47e8ea1c249a84f4f727fbc9534a7903e213e25cc489f138c49d6edff297116dc5d5927c9bf3e7f3b1fee180b5062762ee25fac08b3cb2a88e7e0ec36de7674e757f4f33eef5d38a6490ef61c354e86a143566cb41b09ccaebba22304690d50cf0d2b2dc943d750ac86e631209e005943c16907ca4ced6a6ff3c5e481e8a2e97b3177c48160b89989615f325abf4f1387b0de0cbbc0225d76eaa1d70d2b2a8a175592300fb0856101eed9673f7c0cc5d771613970ef203620f4b82577292419673e897ea31cbab1c721825bef367fe80490208c6c0931359f10ce9b6daa3e68ead12946262396bda0414c453e71621438d2c120b92427038f60aa74a53fa2e0bba59efabad83345ac8516cae55c2aeceb4c2aea7afadc86356eb5dda22c1e7970d6097bbe3feba034d934e985eb9a48b2109fab92b314d978e4c68f6d08796479f40821152dcf9bb7c7f5ad0db8c81dfbed7509eb04136c3c62914696a12e311c592572564f856e7629445a3cd773c91f857855d52688a3045ec7e53c2d0c4ecf4a4c4f8ccb9024017860e3e8e15f8934b4a93fa8c4a96bf081ca684d285f254ff4fb3bb337162d26aa5fbd7372fa01a0839a3d052332f15e7412c56651d9e91b897c124af94bb8803319d71e3bbcd711051de0ba36249ce892b2ac30caf7248076e5c67f18cc976942149fa8f7151196229be224b2a8ff32988271855dcb8a892c89b694428980de8a6c95609268ec4c03d6a10bd46943fc940433bdd67886219d1578aa9587e7c1d3710558cf252d8900b923dca7fc215c1ba006c3a98eddc5ba46240b374a1b6cf8a7129cddda826707388fea06e0642652f399325f49f0f4613e4c7e032c28e55e7c339386ad82c2abaaa007c2b19ba7b8516db3011e5340fca5666c7add659d2910af25349c51dbd6d322f1faa3be927b1057df640527af940c4362fd46d6d2452eaea02dce8e89ee925657234565acdbc236e032be56012b422204930f184d1f3c78251bed095b66014b1d40c56efe8816c78a3dc185ce5ddae8490c1093c9c4e6596d7f0fcd03045c430479047c1b849409e7677195f84d1041ccb821f7472db7edcb0509e1b6a1a7e138239c69230add20bd19f2f2b2069dcf8a07ea63bd85265b391b819d9bd55c4eb4aad4d587395802c6f5a5ad6e2a044500aadf6d59908a302aef926d9e0bce28c10f1c52087359d79fbe6cfd4cda070eff0e796650616f5f886a3160243b5bb0655ccf21e241e6aae9234f024f8f0923852672880b096ba468d194fc68853ab6b9157b74b5b4c528612b9cb8365d25fb5008ca963c8c1a09d953777e07d46b870456b6c8e3960933e75882de6485547024dadcfbe6ad0b9ec94f9df90b59e72276ec2a89576a2b822ef65d2a1e08a6e32ebe0a4c6b6082e0cd0014b1de9ac9e7b83874903b41436f33f15e31f592c0cd53e05ca364b35443975d8ef55ed84d04df5469823a81dc2bf64b681ca50df1f543c109ee2ed5d89c43d03067e2b949c802820a3e4f41e9c597f341a7d1c723085c0b144b84e1089000e2d2405c430421bfaaae8338f5ab49a7be6829df9d0405478b484bc7f916b0914342c2d039ed86690e2d55316e921e88f97723a582a0ec809be9bf47627e1af6723da952eb513afa1a27c4c44576aa12e50293a12255a72d54037797d87a4c6c0f008ea349e5034207ba4d9a0d79d243894eb4f30866ee8a39fee985a686e0db3a7327a91eba588bbc45767d59bbda81f8a8738d16ac024142fae4ea6c9612fe0b1ac0de951e19799d42478ac8dcc787abe05854a43320e2b2bb67fefd6553f33c87712322d7d2276efc313da859d134766790d6d832c398ff764d6db617a28d07e1b58e8a4f8b073cf331aa87e2cb01aaee4e4bef5f47791e08f0b118735059a7f453f2fb9679eb6bdf1d7e380a4f4d67bd44f20a368257beacb6a8e420aa2c01f080b133e124680ed7885a0ff0619b140a7a98320e4e4b5b8f62f292441eec41a6e9a41940fe57c518444a14e131162879c9ba27e250adf8c81c61c2a4bb888cc1f6e1e0363e91e035d761bd104b4ac64860663a4654938cfd53fb8513c5270393eca75b08d2b985e9a6bd06b71d9433dc9b5f531d099356026c05ab20a84fb7b6fc4d84d8a45df89f62a3198d70d8ac9d0452b2d91df5ba7b68d18ae429f3dba08f3aa8d00f8563578fe01380b00f08366a601c24cce7aa5dca2b49829a21b65cce9156789e41dd735ef99f4fa1f149eefb32f9e94c9987aac5fe442c708fc0c152e56d8a51f56cc44009aad093a36dcb44b092fb98b68a52bd9fc778d821003cad0c3f55770495b78aa2ca7f605cf5b77c39f1d12f1e36033445c00c081dfabba904a9cceaa3616249cc5876ebe660eab27f1f51864018d8ba41f3411a324c168c739848ad475a4637fb5464fac78f8496bb0a9402bf7ec4c5342312bd9922b2550df3826b7648cb480cbe21ea763fc3d48bdc3ce9963c308e037d8e4660dd95433e94ffb5b017a974aa246f217afe19f241b7f001ee7692d8e1e99b648cb8c7c3ed9a7106094c03db9298217213883bad9928f1eaa7d58e44d6df4e06bd521f1db4324df63c33c7ab8a8ac00add8d3ab1940594189f142391e51d0cf169324e000e3c93ec20dfa637f135dc63967f44268ad5655a37ff9ad9811b4373ed81c4899ff09f8319209caf2be0d10b36c8403e5305bd3d6aca075ea511f3ac2d68c2d91693ae81a12586e9e3b5075ea5f5c9c6b8917459f6703c774fc7620165776d7708505d46e1577cec9a6935963895b7637907fdb5f1b29abd952803e59ae9cd3761d402f759492f425df8d28d0db700016b99f22284ac81b3b3234ed0fd2d626501e7bf552e11f71bd43e0e38964c4c0801cc7616cc4c1a093c49bcda61bf7713a25be6bc17c299b22fb12b8a28c5c85b6b9cc88cf605921252e9c815c85a47ccee784679573b245da23c0f9e982ad417aed7f023d8c05251988f239d44b108598df12022cd8de8efb8dd824731697e0af87fd8fc3d2c9c3252526cc41230d9a70583c630d02fcf239109c795c02728525d4ab6d63339d605877f4990e1d657a6a9ca9fa62bc17d6421f59b1b8f2842f00aa7e99ba608a8b02e7c7710f9d2823b25a7a5d5c7e3eb0defdddaf87ebdb8d2f9fe01239041eb43ab99491020a0fcb60da7ac902c7cb58e43b8ed6075c07c1f2281ccd6bd074c2b733ffb73678d45b779b94adb93d7f7750e28cfbd20abe5e8d71691369367e72f4718b04353698582d1d612a091d3fa53da3f12a24aca13312dbe46e1612cdeff3d51d3ef48549dc425655e22a5a3bbf4b1c843ecaa6277c8e648ec2cf88726a0f98bd293e0c6add597bcd79aee9cf57a9758fe39d8727bb3ba4d807d091a25c0ae47584f3ab48e1c05157d0712f8b424e23d5067910371dd29c683b10e948e9c776f1e1dc0e0518a91001a30a0c80d5895492360786b138bbd2bc0169a9aa884989837cc8e6fc4ccc946851405def2851a4dc11fd7fdcf455086ea84a97ebe0dd467f260ecad51da8b5de3f149a7b5defe8aaa1822553dc25bd85d754c3017b04e2ec06687511a0fccf4242ad872e1d2078545ff97a78ae5440bdf36c0eb481f11cfc843f51d30d664f69727ef530e246e036a224e7277c54d32b2f7b01e61b74f24deaff65437d12fe3c7ce57241c1a6e458f0effb72d7a697363b256831fc2ee0aa11dca8b0b6d6e08d2cce5c44766d8cb1890a7174d82b1e2dcd9ac2d31df0e0d928b6f062ae2e693ed2a6ba8f20210304fb615fa5b12de22951a5e6b94ff2521760b85f31a65d863689720572f26b94fc2f4d78a88567df6eb6e0bec6b76d72ca35660bbe17dfe2502cacf6358b5debea86cc2f4c5aa8d650d3ef919d8ec24557e1b65cede2c4798d08552238dae89bc7cb494f08b7121d7dac0ab159ed6605a433f9d176084f9c364bef6960086b9c647e121485381e9feb4c77636059e4e07e835ee0a25d9610225a4b5c403575207408e4c65cc6ea6eb43dd319c76a80e7d639a3aed75a596cd49b9ea4d3e85e85ecb115876601f5503c48eed6937fd63e2d4b0f1c2a7762911e238cb96d2c5624bed1c78a3ac4d313df2ee46f9ce4bf0954851e4e41f193531b1e67937131b0c0a7daf115dcb5c1cf9de10af1edbe905afd94dc63c31beeaaa00796dee01393f8f0b977f3a8e83fd8e2131a705d5c6d53ca8542605b93221e291ab46dd3fed7c7e500ee4651aad014965b0127176dcf6471e08cea59f0dfc72465a28fdce6f8112f8632c20a7b7ef6f28ded4a0fb458649e90b8852414b0341de418011a289d345425c5b4da2f77ea5bf2cc2395f242edca700b212550ac5051c429876ccd5a8834b1ccbc6b50ca2774b33b063a6df9eb7e48149626c4edaf85b8474012f4903a6ce4a0379004f256fab66decc9637e52dc53512b5831f382751fccb0f4016771753cfe8a14b0609821016369acd263a9ae3f05dc3ac447b65cc1f914dc0d8bb724deab16666b6c6b329c956de5c4ab6bc4d0c646ad24b2c0f4d43d399c59529c88c8673cc77286558ff2e3371c37a2c5251f7a592bf350fa1a3d05a71baa86df1275a22718567fd05683199635719980e44d27932a3cd255cb535cf45ab36d9e09e24d3a22e2fb946097d91f052dc6e717346372ff0fa7cb590ac1a0d8c45bc1de6731c4110b1be8ca7e52b99f38271b99da0074f6607ee9ef9010fd2a60be785f595e38e59f0d88722543c2a410819b5168c96dd9785c11906f518b253c600a112447d436b4a82de12d7e2dd9fee34647955e482d664b7366d76e692c97aff602eaa50bea40c75b5d3e9eb93f7570f0d75112872cca092b46852185c73a8f3f121b56b6d1042bc67ff06ea6bb9c874bbf725ab6de1580863f05201ab48a0055f7616596423e66cb4319d323334fa6b56352090fd1dff001c45939a280a875fe65f45c0d0c4b2b0e099f4b6bc73d1791c161b7de5fa9c8cede97c837b9caeb318d404a0fbc8606e0d29fdb9b7819dac810aeea4317feb87066561d526812a05f59162871818b1af1db96453a22cdb7786e82dc98627fa0dbe41137abf012ee78436fa3d9a478aa00577c71a719380a13262d4e9d177d5efdb8bb952abf55346068a791bfe7793a839c08ff879ade277085d31db1db1b2cf93d72c35447c91318e110fb0d2d030ee339d60dc7f8107100aa40e47ccb8fe33160cc71ef38802e6c1e2c7984b41ded5ba4bb49523acc7ec3dba1a2956e5a3425fc4670d0007f6f25abd680592326089adfe0dc4f8a56a2a294dd519e4a17a68f141125944f0a041610236d81120cf81e47a5e3398c64096230b49ef19fd8d894d7065a68ed1855224cf540f5e3689955686db3d507cebe413554212dabbfd0517d4a6920605708a0b483af84261c7436388f63553c3f261c73ff6d1400f318d3203dda378b01ecd9b3c367eab7dc75da75342305af508a0665de0e1ff420859252bf9dbd6cd8177e6ffdd7864e215e3de7ef847890c1186be03161d8c63cfb02e9da888a6032bfffb14adce3bcc4cdcc632a22522cde4d98704008347c1e6750a829199212aea8b78689ec803e9291528302b708305fb3d790d9d852c8cc5e25a114e9c7e4a48224a6b0506a3ec08233fda0969ac9e64f75ed9495a50ef71e92c0104db383a12bb6fc3bc8b6c5275081c664c96eb83e33a112e9c09c7a972b747790449bf8e9494a910e56e6653422637dd339aee8b01114d8f9083f7f4b63a0552ff5998b0b4d40176a411326421a21c7a807095dd1dca12b1cb2ff44cd45bdc67266eb2782e0d26768eec38cb4d303cad38ff48e388e0ee3cf7a0fbd43efd03bf4827a7f6c9934f0cc92c9cc9769e6cb24f36792f933cddc7f66eeff676c9a919b6c11cc8550f2a21d4895e61df66a3ba1515a9b6e620d44a50dbb44ae20739ff075ecf4434a12806ad338e006176d273c550a66688cd096c21a6cac494b52f0a37a7e47c99ec5b76d7be04ac9a2dd0b2a897376f750305706815a08bbf31c11cb5f8afbcf72898a93e1ed2bbcec2962d5e6fa22258bde9aa4238ddc4562983ec8cbe2ab7a50339d8184d09137ce67076e913f45a31124b10357113095b7c460a5a1575837e348ef9362ab5e5bc83fd09764f2017f33da2f1d17d9e8e58dc669d09b3ebeca276e97502ae6f085bedab9306ea2ecd4cb0627552ff71d8c86bc30d04d618ea47e665cb8c4d0677a0d8c07ae96c9eba995e84ebdcd57f90440b2a4b4c54729b050874b6236c8c290df153b8790e1150f8cb938eb885de75e8a4c3423882e5a87df0a024b35abeeefe0e0aac5e8bacc29f5dcdea8f99c959c6e55a7ff2492a352313e5dc314debd485441c2219c3398cb27d53c78c9db093b0e36a21de32cd2115c17709bed8ce9b14b1ecb8684cf29533bbf901775ba5062a811a81cc054392590bf3bc6ef06f56794f9a46ad035084706e3db436e9a4319b11ff3ce3e3a0de45fb45c62b6169c89a2b711a79c5b3a6c0b8ee02ccdd5484df38ee090712f8390a033b5c622ecfa1f5e89dea9b40b03f4508bd37f8fd9e0486b3bc6c0dc4609cb3f17130d56767612190f9dc5ad740da851012212d08613f2239380dad0d55e458944a3ea4b5e161a245f71d83cd5f223d382535dff81644a11c117da4e6916953fec4ccc8c292294e93b51ba166412075fb6293df585c753c9f4fae18510c1041c0155614e5cca6ea673e364c2b4671fe8b3749be23e6ec339f9b579198b8c9e348b8caf8020686676803a0f73252ba23e14db12473d53976623953ae5c8dd18aa89d1614d8a5d39b9f4ef0c9b5e1896e04a58d25df73f5f25619dd0dff3d69cbb4b83647bde837f5195514b9dd42486028ac8807cd005e9cb1e4ad9f2498317a2acbf14e63563ff4d31521e6a2fa7c0b3836f2fd60624e6162954124523a3e9a97bf856df747079e00595fa88f14679a16462c960a1684c1a25634064347ba7aeb7f2156ebc0b4f4e9c425548c28c6e853ab0363fe23042d6f540637f2f17ac90fbd675efd5c09a926490f909499d45ebf4fbe817f53e63c638d1527cf04142c442e1d5dd5c5e0cb9b77274739b9827fa6520b438693ff2fc6a441f64821bb1ed444ace94a932ebe81e0e63897d2d2f91969280263ea207847af03adf85121c4075de74d60866ae467d9cb194b8307ebb20c1bbaf0b62950f40ce8070f375d62832f16f01c709ef8d29bfc3f8efee9affc1b9feb4a4ef323ac05b2771fddeb61f3d40d264453b64c5e27d4679f0100a8b0a38d0819f27c471a03d819abe7d2f0d86523d644b858b1b61eba899ab6506ce2678a4cae056ef3c7adbdfa72bc39a671dd63ed376468b63ab2653388d19794b6928bc4ce7c55cb3503d67c26b0b06593705d86254eac1a8ce892c8a56363a71ed4137d823230a13e64e13e015753f80d64de27f8717648e7742e9c046f426c1e477778c6d40e691eb70bc88eeb7168e44123f74ca238791eae40dc3ccd88691146d0864e57241847d4f5967936aae19202c752594886d2c501f43ab92a0336cf6e3a1cb2b72c381c650c12fcb65a5ea899bc0d2a7b1c3b41465a57908a4f06071d0677499a55e59f0a66b3ca0e37cf13136a9afc6c1805cba610ff10bf1e50b29c9386b4b11a5bb8e92260cd2b1defec783893e7fa59af4d325c1523dad75b4193461c500afff8238c60d76d52e93a6e34d94341e41b7fbd1c84628dde500c969e682ce428c99c3d4ac674375eee73e780eda124ee6b1f246a0ab6f1456f5ae075ca7de0a27717d3ff46b35a3c8b922bb866d79fbb0424796044b2586800f5d2bec6b3e7ab859eb46881cb6574470798c0a1dc616247644b597f14a1c3fb68a20755e57689360a3ae732742e48789d8cab27fea48c99c0c565b655c3d7e92be7bda3c12fdf1af302bd20cf779de2fe369399e47ef46aa89dd98902d0ce6282c585e7e81557218371abaeb038c3d8c841131acea719a819498155cd740795642c4a33fdeca6d3dcf4220639846eca18a214d2e31a5c6a34f5130529d19b1481481ca323c68e8f8b3eea3b05487f25065da5cdd84d8e873320db517a35eaa3337ec53bbfa3a7802360d653714e3fa721dc97595b7de1dc97feebf2c02e842b776e2ea9581b72076f87add3671e00f2bd6af8c348c2b5be1dd64a4de0b23ebc7c494636cd49148fde0cbc0ec11db419166ec43fd903fb8f3a578ba0941886ad9ad7eabdc4a92d63d1aea547d02d9796c44649f0b5fbb9758483fb4c2f043b12446cfc065c1f43071455c7e6d434aa6578a4f2ca618b096aa2f86f5d3f068336bcd5f8ce8651e28c89dbe147f0b1c1fb0faa003fe873734a027ee86cf873b5375245b9f42ee790279ad0bc7e152d0848fd3669bafdedee9c3f2a5cdb838aa0c357ba787dda554ec8e20342cd4fa19608a4864b2e949c3aab9ab0ad617d71bef6c5554ccfc03b38cb69a2bf7d605d95c46a4558fe6510d44db28a8cca0f5fc6f21f4099b5d38ed84935a74cf009b3c49a35bc91247cfed0c9cc4648f7d29658900fb36ef846fecd46f178bb95a64834e6d84f7a5785cf741263c13a016ebf49afbc90d0dd586643590c795190e2212707c785fa417144dbc9fa510174845d1c5eff259fca49f7eb7ac3bb774ee8357155dc35f067ae31feb51fda0f6363ef2cd922d016addceb1185d4bc138e92dc99a2f25a9f2cc04e990096a15317655c0cb7b4d8a167ccabd598e243f306d66161fd4baed11d47031cd6b4634342c9bca1150953ce702dadd083f115e809f84a6fba02c8ada3683493909a79b4209da91bb12cb441aaf14c366f8e2f6628b81b1b4e44a824311a7b87722323c723be5d874e13ba47a70e5568dabba48c81f4e67e3b4290e9461b809e9c4cb980f484757ddf454efa86a97d96f379967911e6a904115266c28da27fd471afc2941ecbf440f89975ed38eeb81a43f6874d52b63973a19f8dc0709e13468c819bc46c7ae45906c49dc4a8cbfad2a663395a0f71abd4c3a289c239d1f4643c7c28d6b34be4df8df18aa7d63b358c931328a4e338bbaa99434ea05d29db25853a69c5b1160b9c03ffebfa484290312d747c932ed129f6b39e83b9661015c742266ebfa61fab639cc4ddcc80ba8eec34db93c07d99e58388ac81036970324c22e31e20fc2dedbee00a7d7ca00b7ce7105482e01eeea6ec60ff3ce5883f1311871254f3a91304eb5ffb621363b9ac55af773cb59e14ef54ec0ee82927ba1df5c242cd7453012b03a9b60b915e36ec319ec83f65caea46d7001156c6c7f86eeb271653544c43658bdbdcae623c02faf8c788a1051b7ee0c30a3e21ee2cd1465be31d491c68d8a30a6f62196347be4acb356d8ecae73967136c1b258d275a01f954508ad58c5cd741a6b1c896c1334468e7dbcfaef757c3ea314a81c818026a084d1a2b76b9f5e2346f3ff11911788f83c71b98e59db85c3c3b62da6742d72f13fc4f9c1339ec745540f16cea6416a2ab45f37ceb971a607f6e22f87a18c1479f2063d1cd8c63ab7c1e0bf98e68b59356f42c5c4b4ba4bc41722cee69a4c66756f4f2df6c915c6c24c50472385d13515660c3eee88fb162039eec0445741c423ac616b0364fb942374ee7b866fa7edc4ad31b91a25e51e0e8b08dd36f456e807a9dd7ca0ca3f23398f14b4e979eecbec72d73ecbe3fc5157abb1c3ab514ed4b8ecd4b708e62bd4020028976ef425fbabdd8d2bee63b36b319d4437753a952b684e0f129c09acb1238e9ccfcfa2acb575d4be3d78bfda28c25d408a0deef4bd3491ef476c1a6a70b4cdb1ef5f941c3e6301ec95243eee3122c0e5b9007d86d503cdf4e693b2555e9b6e40d1b3cbd3f0291b402a482fcfb0a8a2d421f213b3e5e436bedce40cb1afed6cebde59e30803c84d35a08f1c70b3817d147de168089c0b8bc02184271d990c580f781c0a8f41580462272a13dbc623435f9eec665a7814502c0809bf0ab29f9607af6be7cecb9496506ef3101064e46b0c527f06c4d86583732b0649523b172ab2069f6e696bfc3de24b0ab2627eb67aae9d8f4462653dc943974154f7fc646c836efcefd9413a7d655195930de3604fab02a2eca1bfc45c9a6e48c97b8b8de289525c2326e8c3d0a483e5b15487f2da2e2b99f62fa752f7b6ad3e4bf3bb4e63346a2b4d4e6ac773a15352b803d9196f72332a1ea9cd4a98b4b26ecc56ec998b3a9b1a79f79ed1cb9a4e2ac6f780b41e6cabe870dc0ace0ef71358078a58dafe7fd8e851159de221c0ff02fcd6f65b85c10345c18d30970478d9d55faab1bdd569d1855077d7e94a7f37550ebe3fac23afbcb63177455bb56f57022dc148d2607ab64ee116bd45857f17ca94d08bfa27572e0433aa8704d99813ce07bb681f02ec350d5c254d01ec989d9f095dd7f8821a245421c82448738a7f10aa5d374d1a081c1d13f48686212aae66a767fb83165f278258ac6782813eb18980138ca3f0e2fe3bfd43b997c21bde9369bd53ac8dcad7c18498a9d7c024ad5d760c59d164a3d07a6df33df891b12b24d1d52716ffe3909057a7e734a62e1326268c38d96a4b162d16e9078b4298376f13819471d421b8ea9283ae96923966db1ca226e0353d4f4100ef9eb907a65f8ded0a353de0c157b105e248c26dd818e2196e05192cfb309ea58e7a8098333f93ca9eeb392543cd215f8c12a49619461d83b4e29c9194dc41a8e47622d045b67bb7d5d5d5cbf425cfd2d55c03fe607470321c19ddd21c11b0783bc38316c0f7bc11fd6f7307b671d04cf2b5a3f517079d28c6eff84742439c629f4f42e575cfb7a267fc2f9d16ad903029205aa06ee2fcce0f768a2017cede35e944416351e2e9e14850510cb473a1ba1619015404daccdce24a3404bdd2441ac8f5e1c0b8c1846bdecd682356531b72ea24a6c20430f28301060834d79ce098f1a150e5ae2c28c7f819db1db5c1e555f6c67fa7da3922e45c10b1b1d52ec700be3a4fc6503ec9d2b96814281ca4c4c79dbb88910613f324593d7f365447885a51687e2462ba4dac516d646d188d0936ae12cb8453c176228d239bdf152c223ca54a87231aec3e7311114d7bb0ebd6f501fb61afa1e52fa1d322312112f1b904b1d732bbaf77b8137d95953dbbf4e844e8e1d05b1cd34a297557a48692a855236edfd75eae9ef9bd8af414c1eb1d2e6f79aebaa6ac7144728eeb8f84a4deab89f4e76a21c52e29a972d9d9ea7852891570facd3fc33bf0ff28fdde5f61d50788c2b1e429e95b3efa2cbe1ea98f2ff692d82fb299bc08cfbe1ef2301da15f3d241a156945c676a8a71bf1436c0b090d143717b627186934b995e6ffdf6db86937a79a5a5557eb5ebb455e9930aa2e76b8050814803d349df5734957249448f12109110a88958a5e4dc5677525ec0340ee75e7a210c4d9a277efa725f07f6b70c0a0323354849193f85dfa39f930e3947395ea7fa042a3f97050730181d00631a753d3b26d73a4dc066f0d78ff9a2701ba36cffd7edd3cc50b80f3ec558fbb1dd2811320d384425b12ede53ad42a6b11d3bfc33d1ab589e65a34cf365626df5c5083158b802980305f731266b5292ac8989f06be43910f1a40978e2e0b28996e39be5ac602d55bf0c12f754e346881e680b63e528f31e836ba016af1e23e482b849c3c39993a9b039961bc675483184b5525e3f0f10d3cedf7e3cbc09b2fc26500d9050061597f73ca553711667ec9df5c4abb519c5605e0d896061743e0d6c0b9eceb8cf52fa833e35a9d52363425e30eaad62f5a81e1bebfffb8bc648e144302a60d4553a81124e7e003b8f63d0430a8472c86279d8eea8fe9b80fb00567e153ad6e8a6b623b85218340e8033802e766a87b53d0a52001133d4350eeb91d3041efc1d4dab7f09427605545f68bb48238783da2a7c0ed752cea01f94d558b47dc51010215a158c934b95359ec1da07c18ea002c8fad2903562202a82a78ac6579d9f54007b9fb82d6161753b4a70ce162a1142b0238385ae957f6bc0482f9a72efac0b7268b82e6f2c7aa019a847c3c5e21d3656a5e82853c420f7ec58b14f3f7f254650b30721da0f4c70b58674fad814a98a089ba7372f575ee77cacb618e1795a19bdf537a8ffd6ccc047da690167f841161890ae8a44232d767eccf538d8949e253ac26d8f2dd03712e62be88a117667401975bc29e03e5cab2fb9f42c5eac607723acfc644426ea09ed67a71e505457ada4cc4ec315c2fa880b5bef5a18cceb33d5197204ccd50a819d2ad5a746c1dd1c30cfa2cf66b34864836cf48b303564521a8be50091a0b15a198bb237118ba199e230b6d1056d2a1f2f4aa5b3940b68d18be643cc5cce552a6afef9a9e5c06f1f6fba97d93323b567e6a44058c8738839748d0fbcf338fa85c0d378cddf31b9093e07e5c43a46f830138f8398a93dfbfdcf49fd136726b1271884f5ca13983db6815313e6de49928608ab23967558ee2129914e037b7f42202b8ffa03b72b0abb3ca9755d177da097706c6631143f6e00dd82d7f4e3bb633c7c824269e0b2ded6f4d46f521b828ed3b0a10ac31ad26aba789743e9f2b8174b2299c3992b2225acba2424e3ff5d79a4d9f8590992911425a2c7b6c7df8f050bdab7c233a5a79f212e8c4da866cad637e6c341276750725f4a38fb80b9c3dbca2c0769467c036204c9d326167a3f354e388e29ad847e5fddb338c5d7bc9473873aad5aa1b2a1b6f49ab723600fbf0a8944ea1cda3de29f21acc4c109667fda338deb46a8f885b5fe6de90f02d9f1c5c44414807618fba68ff3da1603a0b025360558aa0566a9d03e0241b0a993f904dcc3aaca145670a03ac42ba5e70e423eae93940156393d5e3f4459101d1303464f9d28d05704fb4d0bcfa4b95ee90cd50186ad0fba0a767e04b4a4da214997200829ff7758c93e28fd9b71518a4a64f98104dc21dbd887b6c04565647dc5a6cad0b6587ce117a1e105edbd1aaeeb7ff091ba02bbd4e11040a5505bbd319235ff5056ed74e2b4543ca1ad7f9b94578cfdc8163b8f8322833971a56118d22c29ae796d354167a9a2263632a607b367de66324730deb3cb0af01316909f0dc7fe9c8c2ce78dd4de75370b392469acd17acfa462f5b887e4dedd24ce787e35c50bd6ca51d303836e5a39d9f470897ea19998b9e6b8a1d320807038f65598f45e329c3e2b719b14c62545d7072be81bec79f232631b5d7944d7699ce7d12fa6f93676e5e609a9c0926d37f638d0b891e3ff884fc0b72fb70e4a5865db8f8c3abbf238cb0e0bff6e5b84e0449c957a484ad3899e419558cf162ea76da74de927e6f4aec994bffabb1c5d43a249c91c19acd7071defaa3b45df9e6e6a4e26084cc8331cfeefe06dd7c8bc4f5f75c443350d7c5a2b5ca0877c5ba74489583888e5a3289d064bf61fe134444a08990f19d954ad072309ed1a0b6172b28cbea90960a75cc48892cf895ae5548e056a19ebb3d0fd53180e941eb4f3cdf087030de653a930b04551acdb9785d431748f7f62bbfc43adf982a55d51f4ae57cffadbf1249a545db35550f73033248ae6763d7151f8c510ba45daf0921f56e35e7367eff6278f0a80b59b5be4f1f1cffdcab5bb39d15e9a34110b884a978305bd80a4889fcbed67303e6f4d4b51a04ae15d7a901252e429d4f4830b39675773bb85d9a29ba0b9d79240c4b2590bf6d1d12b3fc4394f94d1f29eb47fb2bcfde00256f75da6f82d876d51c7713ad6357cf4815037f6bdf78e476893f076eb60a1eec66c833de97c0096a1f456633100555a789f17bb38e7ecf0b3cce2b480004faf23a18283d3a19b8ccf4ffd4011f0b9919038f618f1b1859b78ec6db4a3075fa0d9f84da750aaee3498584cecdc3da5fd6e6df52a7866630a4137f28ecb4c136f3885462acdd0a517fa3f30126a6dbbc28c3fc7f92b375dfe3c5bd0525d285656012aab798d00050236d476f571d5a6a2f74e6dbb37606a936dec68c87ebde78bc015d89bc9cd1e0f496319002c3a76d5f56250cc23b9514fe225747739a0e76cb628d71daf5019f1b1dad99df682e04b0819f3cdeb5217a8ebdb51e302b8a78b6cf1ba8f7a5523fdb276d45db631fa941af7e49bfe31e74b25501dd8045eeb901c84c59d106fdef78616d8774ee0623aa4e69a78702b903d9dbf00dacee17d244dc22c90102f61a8715722bcfcd64e3303956b50b4ddc8f756c0a4511d8cb206a331dabc82d6810e81a7c2d75ccd6f51414050fab644dca41fc50a1d7be7d33f4b4ceefa882b21cb6e6a62268acb2082f7c3cd5c6de7357fce74acf07bff79fd8f9d88e267ca3257ae06493afd7ab8bb5238422dc4d55fb64791f547f17407fb1e190703abcab819f12da3ef1a8924295763fb08432011bba42a983be6518bf266ba7ed2ac55b443c968161301b160c93d1a962bc84ca4ad98b7e3031320f84979586cdef9546808df05a5096f8e3072fa8a7ec53697488bb638c70f823ab7cf7c89742f65941cfcf07cb8d657cae622e744e1bbe16930d0f732e2a7ef26fda0acc668146e0d6bd5c4c7365772be7e850f8b63fe7c8e627d5c43bd1230b471f3337f97200b6fa4ef239a237762276867eb01fd04ffada2ed19acbffd6275892875e3ee87d74d826cc31656b84d83b53f1037135d33eb28849feda35ba86a3c05ec1899ae20b2e5cc6a6e9636a11f22bcd2a0135482130d9fa2e648b6a93e4e7b0d0eea204db28c432cdd11d0370eec50ad6799ed83241719aa8b2adb4e29d861dcf041b814a92fdb91885bc316c679a5f4271cf1dab3456085e95e8add95d3224cb689744b1cfd8c6ae9a3784d400c199ffc125a3863ea659e705aea822ccf914a6d305daa9d613077b9f17128c1f277771c86e5d41c526e0bf07d8312906ae0d3c8245537dc61f1c9c5972d9e66d5ef964537b88580fe445ef641b497371b6c589f5ce2b33c3c1b7bea9f8a136b17f231763c4cc5b433a00ac7f01e40dd14d78c5838c293941d2fcb98b69b6691bc46d9c628ff7047626bf472019a63ed4611ddfc4d94c7a2045cb43688375f548fcb9c86dc44e5a4edf7f058bb7b5c31120ee99d79e58ffe8fcc2e413d035fc9508feb3811f9b33d7c24d07022131fcdd0f3b90af9eea506f2388eec402e02ea5e69318bd8cfe28cd6a7d514e3c93c187302086375b203a430df22b6f139e66bd9620ee056881fdddbf7a01ebee2f9cdeb8c84223d463d46209ad264a44daf757d2eb3496d0ce8a1adaba4aed5ce0d8ad282daec30c28ded196f0c6be9e787f33bd1899d165f6809c71e3f19673b33461bd018524014f79de637ec6f1cd0a1798fe3e25b4bbdc3a08cebd12ebe31ff43ab9f01d64141a6bfc30159470f37a576184ed5e9b65612a799d0a5cc63ff8bf48d035c78226b70ea3a85b2769cd72ff96106e5da42f73abc159c0d6eff79659e7dde1267f6a4555fa22f3b3c562a0a538951d26cfac031a487dc8804f90e370561638b8fce47309d067bec80236ca2aae4b1a02380e3757a31b49057488e4528d6e34788f8caf7116d45ade38bac93039bd484ab10cc6d680cd111138543960feec38e2876e3e20efb3e7d63f4f44bdd269241780e608df3a06b392c81416c45e8f16c9b7c389920fbe9044b5e505172a45884a203f7d812064d191bb20bd78d98ff7615b99817a79457f7fb6ef5f2621b72cfe546aecc8fd2a0b8802e4d110e2a5852d60ef15a64f6443e1882ad3c721d93be1c8f6b400bd47dcc57f27350205aa9f4e689f2b1e33c66ed481f472e033c48860f52a15b145ffcf0027cda9848472a8543c15580c6f912dcdaf977e27a2c2bdc013fd25a7c3eeef874b0e0df4706c0b0cc3be4927dfb7ed3dc25e795eeb0d87bcb7dd620c264ed45c09b8b569d26b38c2d3bbaca1d7506a161fadda2dac7ef8c4d3ae1a2ca1bdeecc1f105b019f3a8b2c380408ce6f4a1f6eab5b290a17375b40bff549713cb6333bb873226759c16c67b98f66e4883b8586f3101e22eeb21401fe13c2cc657a553051ff7c741bb4eb73cd0f5dafcb732d062f0f3f6973a98fa895ddf983f3a726cb1763ed2975d3b58bc83bac937f96032c73f4904b16a395989a036c8ccb44570beac0863828ee35dbb7b83c433d111ac8da7e3eea41d960fc5fd826247bad5fbf241313e643891f4bc9883e3ec309964ccfd12c221bd4dd530ec333e401087392a2eb04ba93a675e25b5ba82bb3dec875b6e3439d146c51f4df859c47092b905cf05cfa474fa598fb163d66e360954adf3147ca1340d3ba412f34ae9e8a0c495fcd31386989b2c35b40e72026b149c04f267473648d39728b49ed54dda17bda716106f9fa949257e824d6558a52bc4f6a8cc987698c1ee9dff02cc9356d5c1f66a37b0a05fe535ed30557a8b9ca304386ca606e887b53b792b7347a26f69407f51ef9fddc6ec8452ac7316762e78ded474849c5e265ecb8890414da9132aa58c3196f24d81d770feae1d8d02d74e368af7783f79409e79a05998f598fad93eec867181601aee4025504ca776eff79489eeba834f590b53b11cf9cf241b8443e351b51eff901dae346d90dec496c1c5bb4201f32090815b61184b510e2bc0e07aa8baa8f0cd222436ff4aff7792c0c96a62ab658dc41d399b804c65a403954aab10025112bc1997534f3c3a3ebe6a3b673949a7237c8981b5872ef00f5f5366c7c6a05e97fae62487531e06d2245ff8d221f8e229052a4ac36c22f4e14a53a917308c31d7076d2a849bd6fd486c1d1fdb574f42748606da2492b4703617d5d9d7653222e525d81b4b5dbaaf812b05121535fd83d4ed0b1a8f11ba3ff22eaf4e93be37faa8d560ecfbff2af973770279f6ad8c2e97f5dd83833141b9b07f22fa657eacb365b94329b73522639d98bda31b514ab174994bf906bb7aa79e0b6e3ba45fc2ba1bc1029255a04ec87d18094e28f2e119d89add3c8df9f3d92e1118470e7049d08ac573d84be47e07d13ce9cfa091755110e434d83a2c61a3637e52ffe9ebd53e6e609760e211eb0c8be42f57f572f795004fe1b75ec11dcb09633377aa77420aa05435aae574c9cddecc08470f22d25e447c25b77e93409723157cdb35239a825ccbeea699e3b7f7c40a4c61b5175f819f99a8ac0b82140b9d4c9508898d3197c54720d8ce097f2f8850d81d28424819c0c3bee386dee91e24acc61b261f91c54566bcbd63f833d0786539dcf4e51c1c6042eaba0fe51681ada03247e61ca2614abf2cd74c2d38cce4dd0b78d162fb40029e033b8b8fd33cd8a7a6816558745c7630baa4c255982dfd20052ea05006cbe74c3d018000ae0597f567679d8665905842f307664a83862b39d6bdd9a51b906f71d9bae9c06650e9b52d688ab8101d9703077632017dc702e737a7c2fa9bf012dba320e73c34b9cba13fbf8078292b2882fee0014b84b0c0a3aa04b88f8cc7e7016b1217798c35c8bff9422c423d703b996d13ab934d74b6816f09d71a168f860ae7114905a98bef343cbd46fdb4b8698e1ad1d76ecd19cd658c7fac99586fe4ccbbc7d1cc36f606878d1be673dcd70a460830cd949b9a5ac9143697cd987659133305b0963c36dda85d726e4c1e5e8dca64044aa1d6da3eb0e0dacca948f6c52322e6704a1c00ff8baa6e9b63a4984a2d5be1468fd26c2aaa6c0b0913e131b02e8c56ff2fff94c5c4236f9bb725b347841fe6d71d97be95d5d9072dac89ae92e68cd1e3602ba9d109dc40cb9667c682f547b026dc8c720f365ba6eaa1d4f5f5d271c5b4d50b3b7a344dafceed8a68783f6fe6e564e04699cb44ad607cf80fd8215125bfe511070919a07111f20e69094c508686104e380c12766c1acc924202d253e7348bd9896425c96deb25343f826e2fa7f666f2ebaa9169759f76d0d7d7b82eddb865257a747fa479cefd8619c7d6d2c4dca9827509832574c11c6ff347384af967c4bd522a2b7a7ff06b081022c51886d3a732a2056550b99d8167256c285a48bfb8ac90ba22b96ea08f87a7b147c4ab2b5db9767ac8e57a88a222e29c0e8bc1a81914b978eaa9cf77148e66b8ca0e8ae671f057a25ca3c01568558d279cbd9602725a354e5338a5999fa3f57abca0900530bf1ecf59efceb7763838286440e02e930ddde321d812fe97969ed38de228dc6865241764afe740ca0b59fc5b1e09c3101e132b80ca66621d3df6982d6f0e364375002fe945ae6f886d98e20da9fa7003795d70efa0ace45606a56846861b6c2ce66868f533875db4a2c8bd99a7db3b7fcc1d1a6ab9269ff4815279f3ba0072ee595d4ae9a7827e22b32f72fa47adc4b21631d7008e853d01bbc338b36e080d7223ca09c40dfa5d6e216db0c230328d215fed59da0f574bb53707b12c769940994210f36cba7e4e16589616956a7388bd840b2db541c54fc5609a9905dca554966d4ef9a931fd400cd2c3bf9a02ff85da6e20cea059f95935fc402cdd6ac7e6bb96d54e3666167c18906f101cd6cbb81d0d647402271378d20de5adc0d20a0b5e918c3b028967fcceda928555850c8c5282d44dd0eaf853786b678ca0a9c15a66ce55ad86763f7f82bfc4dc011795e1393e388f87038880f9fe7e78cdf4ffe5cdf2d16fa2dc27d17fa30e2fee973b7046d11f0d602ecbe8a71516481f6c56bf92653ae50682cedc3b8d001849f17f5923b3aeeb0aa5ec81ace7224bbe204137319e897a429849347ef17ed3320d2d0fba33b2d0f326dcda1d3f80f5e151f6a5687453fc6457a06cf0a716618dda400cda78cc7f0932664756d02a444509ad83d4844adca85b787d7e7aa7b48ee05dc894e163ebef76b82d4a0ec177137d412b7b38b2974d74847c467c431d94f7e9f04f9c47e0b1480df63a3045a8c7560d0d2152b0a820acf4700e8ca884526b51540dc5f9ac21722e5e76d0e50a35e603d66ef6a5507a8d06a077e50051f7fa417fcd527ae91e69ea45f8b85fddd941ec049a597b54932f7eafb6281d472b9802230d47f1a4ead80372f68875e60005bd967062b44f6164fb3d6a201a33594ce037243005533946894678f0969e5223fe7f07147c2e249d58e39671ac56bc553a0a3ba3530e7311afe3e0da38fa4735c118a0ed8ec1a0b8186c4128dd9f26440fbedb1412e976ad51e55915bf4056c9f642c85942c7d1942c38c31175b86adbdb0b3213754ee015089dd53573597e5958cbbc4e60b60647174bd11ce6620fe9f51bac81d193daed36145e3b034930e02771a19a0c4434a088f3338796b25e3cb389a104b07a4c0f3d096f3476bd198407ed08ace09a645f30eee1ac53bfefb3f388f0ae00a54f2008087b95b6e4f176a8edb8c49623293b010196c4ffc4c7ef8cb0e9de83c7d4401b8649992bcc1b89eaf82c86eda14517bf7a5a1585f603f1f4681026c0b3260ce95fb88daf287ccea9a36394acc10b3984dc9a78f789d79355b65121df43a87646e806afb54cb642930e8b1c784c39a12a0ae7c417ab17decbe4cecb019f457a86cb896a5d062685bf112e01da507880620d60b81df79c053ed4e656c4c52e13d0beaccf2f30b44f91f447d9c395370cb1e6b9fa11e27424b0a66c4bc51841b0ff2024eeb093177a01816226662e85699d74c7200469e15d533a23d390754515715f603902cce8265fe4970c33cf8b25ccfc5b95d4b17eb778c355bd07d32b3386786f336b03bc2cecea2609559c0ba38d2d3ff7d79046bfb3c4f10f55844691c49fa4175c57df3b49b4a37d329e8642c52c8c19871c8deba48db52f8caff1b3a06cfc027f72045a13b85db6d1858c6b10cfc59a0d9fe9a8579f81a379d01d214c80a2770fd4185c4f22bfdfb64a709cc6a41cb639f3a91a3b3eddde0b5b0bffd59991fd5d34d1f11099c9aee4e60731b89ce799a1551651d4ae222469eb8459f13495ce90d652342222b78427e4c562488e328c437bffc65053a1bdd01eaaeafda8fc395dca9435cdbc6dbfb17ff391b2e304687ed336aeb09f0af4c5e2682a57ee75b8039f4d6e79b4b0c39bd04df84723a92d37941742e20f8083fcfc77939be849ff1a37c9c3fe14978323e0af9e62225f3f7453fbd7ec25590091ef055fda0d578ea3205482f253112fd07425621905b9f9469d69515e4c868296e41b8166d921850b79d4c2c52e83c34ef3dd3cb62805b93bb6ed5fca37b0deb0a624237804c12f4ee5a31512858a2b6ad958a01e216cb35b8f651ccbee816aacd558589076e8b7bd047ff1a6efcf00c6018220989036e9b7b5259752057dbd60bc5007123a871cb43c930c0e51cc9987810976382315c31511327bb016f2d7d5231406e810f41d52856945da800d159985f85dd069043080ef992a5341be64a51859a1afe21ed41c6b7497e9a367b75be6a725c11df1f2051fbb6f0d4a3fbebc46f633c75232ca0e117f5f6f3cd6b0e1fa9febb37b182a7fdf22068f7ad0f32889b95e06b48f8b7e7f5f6e0b04147a64cf3ebcc227df5b9883feed8960dec068c4e259fb1fda3ef81fc0813a26c188d3e495ce5394f073bd1a5d0822031491d7ea87c15321a4386cc2615e90616194092b82e63057c0104972b7641702a7eff811277b8f74da2449d323336b0400eb7812fadf98654fb63add759ca35937e4a541c6019f14a3ddfd429183759e40b180a75d007f22ae09bb8a638055343712ce5bc244fefe616c2a1ebe3527319e6d320cf73e7858638c678f249136896cf663a1557ce1fa82a06a51c7c252efe7721815d554e5b1982d1d39a66046283757cee56cb045725b49ae4a584dad68791041e4f10115fb5c8775bef0af5159496a1695541b5f645ccb43e93b160bff3215ffbac485e8bb11d028e373af25186707c684a2dff8d00dfc6ce3166905f5940979180a38c98cda9d4147aede7d82b83c89df1ca0be5351596990fb602b657b20416c5f3a016a5ea21ab4cda265738ac357f1244e5755f1bddf75552e858ee1beff11714b2bb98701b80d28c3f3177f346ff4dfb47c6116c3c5f7a87489fd3d3c14dc88bb622998cc6498d1d2b2d1fd7fbfd4c198a7927ae775c6923f2d382787aaabb1816402a697c4c49e303e5e37a742d3000893482f263091e93f55550eac408bd26759f0790ef3094cf7693d1bd143c21245ac802e98f597c9873279655db9565daed00e69973d41c796122965ea717b61249bc4dad0c011d34f4131a1f2b3dfcb4100ebe7a93c60548251a1e286bfc00f9bb130c7ee526080b50251b1d55d2e881f2395d02d45514bec96eacac4c8a64532163501302cae4c68e959edf45b76dfcaa7df1d537765049c30384bf3ac1f42f3683b080efb892c6c74a1a61fee027dd188acb990a08d90f52b6d04f68f048e9f92cbd4c0d85316513ba89e78fd2eb067e03416d9f7d2babf375a8acf181e7990e73f07f298802b0eee048a5fd13f809cc68022a05ae745630cc249e03330468f56fa1ddf1259837991668d6e5f97785bdfb627b2ecd7fd70fcdbc332ee493aa38ab8a30490b183eba4e35046755c42bd110f40d7266339020aea480d1da4f891fb160eafa2db2b79432a594640adb06d50677072dae3fd389e07abdbd36747d130b5c4f36c1f5654f0aae2f42747d5ad4c5f566d00aae87b22faecfb383713d92bd0b5c2f16e37a39dc5a703d94a38d1d8e777ddd2ebade88d1f54eec645cff7cceb8fe093bf45f9b0bae871b4261a233721aec30b8fe2e7f68695c8fe7a347d7cfcdc8d5b8fe6de79ad4bbcf2114263a23f775eab56f31703d5b7f6d3e77ea1b76555e10d6f2203dfb9c9ee6bd37f1e5a7abfff5dbc881f08617086824f71ac98d21ac0099daa555a66ca4d65aeb9c73d659679d39d02f6bce55ce55cef7de5be7af89daf4e3fddf3a07faa94fa77822bb24165d3efe699db1d8ede69ca6693af30a917ec678e8a7a9cf0de0481559e1857b8ee41e5961efdff106ee71b000123ec61b3ce8e92f70e867bf81431844fbb3071ae50febdccf9ec589414cf8d90b87bc0799eb4820152211ed8d733662239b8f3963228be460ff75d32ab79f77aa91da2c0076ef9ceed4a835d5d71d8348fdde2a8c5a21074a53ed4be065554e361a39d04ed32b15e45218989d5d56dfccb021b1c7c9491285bcf98a3184646faee09ec856abc597d518427a87c2ec0aa91279f10502dcab5e3586b08bb2903c2d6366d9217971176521719044cea08f08d741c9ead674b1aeeff1db7a732ef4902ba0a044057b7d215790f611bfbea9015a0242b62ef14de6ae13e358d8220658fd852166df0a5d19bcab8f975ecf9f1a4190a1e260a2bf5b82eb777038d1a185cc100537c649079d0c4f1cbcbdb82c7c195cb9c0edf0d3e1cc424b11a7c6d4157e42e5a4cc32ba8e92485eace942d251f53c91bc38b33de419b94a61aca01285e445163664bb36c582cc90bcf8a2876c59774bc1624242f222cc0eb2fdfd58de125f8e4b49149217db22c8d6bb58df8480f9d49c3c902bc8435548ee43903036865c415009921b71e6001761b6ea542861768716634a646b74b1be7949bd9eea53f244663826232fa931ad8187ac6166809a71659eba8c0c0c2ed6370448cab547328d8b91d8f7340021a8267ac4984b2257003c1b42ea78410076fb2987b36512d91e5d991944a6feee8f818b41a9779d833cb28a71aab5d6e9fbc1d0c8e6232641fa63e27a93cecf39bf198ad537331aba271261f211ab9919d8213714c9f281fbd663dffed8969fba00714dea81be4ddd0f0402811adc28be007df6f9bbc517a00ffa8d64d1d9bb3e457aa06f62f0ae4cf09ce871820a32bd6bc223e9a987935b1732f5363840a06f5b230b90d5fe57dc3e074770e307c7144765bffa7711db68b0e592e178d225e5f4ac5da06209da911b932a2782451c5d937ab76853f4006f48bd0650baff695b524f0b28d024676a48100cf151914591bab144a649d69438a488d11921d32b393a92927cce6a0421dbccedd83617d7e27bfcab36fe8a5e9358bdea3dd06c91fbf5f8b7d6b99880125f1b3f387eee35ff38a835b0d1871f2fa9ecfebb7b166bb1c73369dac1c5506bad3108ecb377c11fdc7ccc427ccc43114503e00dd90b9907c0c7ec626308bc8106adbffe67aebfdf0fdcaf436010c05d45ddbedd5eafec0fe8dfe36f8d694eaed91e08737c71d4633aa30672cdf6db5883d4df740928dd2910f73bd57eb73a3822fd18d0376eaed97ec8c274a206cd3ba4bc84ce9b459b6e20a3f6695104c577f8b99a163568d16f5e989fb3cf2c51fa8b93375dea695af4d463a59fa61e0683c039fbb7ff14df9c6049b706858c098909327b22bec155cc7c9ec8284a319502993dc6370a8806cd152599c49ec8ec597c630266d19a143ca70e0f64ce416d1ec65a07db352023b1aef12087201f53bd37c6183bf5ec658eba703ccb1271ecbc12da9f9fb5b1c3891ef310f46f96ed9d65896c67bb678947622be7fcfb47591c36fa59cffab4e9b3d1bf89ecde29ce670190fc2c0bd04f7d9a020720b88739a41e07a9acf84825969234b97043db295ac2454a15424f50aad0a890597b58ca34352662d829d5a3c712a69426c8377d267d8d4484f1141f4260496b70744e1a1084891d123bb81452382a994cbe40e6d5f8d8638c86c6b4842485244a847cfdc7744a3d407445763a9a486c63021c32c8c0c0a0f0889006d037b82ded6ecfe90614a92f244e3bd156e40991125f091f203faece945544f690d8a7391fc0f91ef885808210e40f9ac6c7471f7b0fb0d1c7be639fcaad40c964120bfb17dbbbdb0ff387a0df9e987dd73e6af8db8307623a7f3b319804ffe2320ca4f8dbed6fff62393a0bfc8bf3f66458a53913fc9bea08fd6d34e3ef250afe4d9ba088fe4da9b64f95cdbf53a68b7f5327d8df15b64fa36d7f07f78e4a269345c837a5fb3bcd4bd2f87bebf418fd9b8586947fefa60c75c1bf992a1369b17306a3f16f2edb3e47c9805b2ed3fd9df3debcf7b7d749a4bf75cedf5ae7d53d35fed542db6ba4185d7ae96fdd04f577067bb7db09a6c1bfba0cfab7d7d11b7f0bb796fb3bf998b6d90d5babcb123f2384e53976110a7409b2d39c6756e49c73aee0d28529059ff6cb09f541c8df680810a71c8b3738d5d4fc8dec2fa7586780c283900c49facbf2230eff720b769583969cd31403591cf6afbe8048ecbfff8f0e9a1ad558fe41c8bf0311a8040dc6df0ef7d0655f38f1b7fcebfdbd60509ce11b33b1f3b7adebba41966030e8b6c05f905d555ef33b74007eecf597c1b8033ff0bf2040ffec5f4864a2fad5dfea9d62bc7556598838e786b87d10f2cf7e4290040b933925bf75d95f04e91511fc6cc45d980966e4c2feb682de5cfddd2f1d7eb129f3d35f560219c9a6e90765d62aff6d8af7d67be7546bdc5936defac5bfe1ad8f80ff0ff0b3f85b969711f0ffc1f1f361fa31fc0b3fcbfcacc138e33f56fe565ddd5cdcfff8db9f9b8b361f6fe8f07191dfb66e2ecefcd66d81c01fbbba2ae7dc6d61c15b6faafdd20721b37c6c7ca9f92c5659b6f04dff8c8e85980b605e2e547099215290e94263d16348310dcbcb0168b2f11dc12f91d39636e090970bb607b8d7fbc74babb7174cca54fcf7f8cc693be47535ddc5ed99b2ea57555d55954db9067eef09c20f35fede4c7b0539ef26298ce8ae520e3f4d27a06fb6d1461f3db1ab2ccbfbb681423ffb6d50f434e7654e4ef8411c8dc2c0cb514f932618fe344db7cf46af895d6b9f72a87992e6d4488b673af89973ce7ff6af0be71cd7e41bad8d1edc68ffe26c4fec2ccbaebdab4422f77e1f8f78cf0317ab9e46a55963b5420c8275530c82e5479bcecf5bb6fd45f8d8eb2d3837c520f857ddfee57aeadb3558805f041442e1c79ea79e25480283087eb9ded246f835614800a67ea842876a30f56eea23a418c4faf19b15918eaebb2048e69038d8008c27057502c7d363b90489fbda7bdb79effd87d30c5485db2cc34e7fb7db161c0677fdd5500cf0faab819a403078d2df0d6d5ec5e0534d821f6f89596540d15f2cd75cca60a3bf5bd93c6ad15fad1462c24a7f798a268ca2081f2f9b28aa60cff251c959f36e74277decdb8bfeeabdcf5cd3d9ce1aeac74b2674afb14e09cd171958e981019854fa89b9f407f0f192cbedbf4820014eb49c27766aa5aa1ab9b3d58085918ad8d6df6d618ee5aebf6c06b822517f3771aebfecc74776c518ab18638c31d619638c719a3d5b3b0210d8bfa37eea5b0d74fabb53e3547ff7c720145fb01fc10b369260f9d8afbffd20b0ff8584fed888dd6f41ae3b002337926b1628fd657786b7fe6e0e827af6fa261be59a6ca4a3fdb1457f5d239c937f1b65547496070b90ff7aa52ff9b39128a7f2755df79aae352caf0a7efe396a9f68d5d234e56a4a33ce384d35f62f5adfa45c33fba7de00543ff5387d2ef5acd164329944eac04b1b62fff5b0647e0ca67331023b6ac508ec443fa436820548af609c66af7fee92c9d1dfb6938fb7dec7dbcac75edf74a8bbe48f2076466498ef4eea47d18f281d71298822113a8b6212a995301acbb2b29b2ba2e3844cdd3a60dfee125a543e57ce1b575d6d2282aa7ef8403d71f83051597295fd385908b97441213b6bdbc3bb824cbdd6421f0319a1a0f988bd0b507f37d8c77e26a9cb40e91d90f4772b3ff6c29cfe6ae5c75e835c7f798a8fbd87b7fe6eaa8f7d06293dea63bf9bdafabb8d3ef6febffd7b7d83f7e084c4b9452da5b140a6fea86f42a8533225ebab2c4d0959626789f2e7c69a8b2b360b00b9b165649582eb0532f51694f477037dec35cc75ec65eafabb733ece79a8ecdafb994ef440e7a22eeabd7cc4792789665dc6adbf9aee635505b085eb0364871a112454666c35f654a9ce9554a1ee52dda595b9b81bfb69d241939e92cabd3d1a6a1d0b208ece2eb146a054b0be4e0177949d957395fa6af71362db7e4c4531829092fd27c4c275f7c8cc49dde93f29608ece6601933ae7e250facff9f6abeb1b8833e95c49d5a104faf8215991d8a675a7a5a13ab567eddaeab4fe00c698fa1d01f27062d77ecebe42ad4bfa3ab5ea7496690398d6237cbcc432fb4df9b56895542220d5d24be957c483871b7c2362c5045089ab070f1d74a25f3f5e7aed78dae52e81dd1cabbafd6f57d7f78399df81d1c38facaa0a30abf39ff54b88e9e3c88a139814968f2c57860f2ef5c987332bee848f3c1c7d03f1bddeca688d3a57628574976a05a26c7fc25c145650aed6db8f97567a6c544ad8acfe4bb6f50a3bc0283d68c3adb3516bd8d56f46e74aa1ce36815a7d0d637ffa5ab622e96adaead57f4a78aea0a8517aff787945a56d7696c5cad3d9a5150b0baafdd1d7a9df92ca4a5dd1593936acaf1f2fb1ec5aa9fefb78892505a8a3efe40f4767ffdb5b2afdf75fac647774f5e3e50f18ffed9f55f9d61f8c342e965d7cff3d7ee098b2cdc7f9245ecd47f147a07ec9cbb2abebf7c29e3fd733f15256216deb7abaa1470bbade8e8ec5f5635be8fa28b4bbdead0d6470604f1aa95053cb5bfeba62326d55b5f055555555762b8598c879ba4a2372e2e24a8ea5233c24cf153e655f1d73c223c29ecd31b709b6d4f388202892b687b3e922d9b6aa95d6227e9e4ca1a490450ff1da11e492953f162e7e4a751dfaeb1ad5b597f35527a91222de6b9a0d51ebb1c4c6095cb60364c59415a4675d9218560f9e1c2a253c787c7c0da564930a0d233cda30af918418239251450b8fcbf973922494dcc1c3680b8cc4909caa925d690b7e74cc886a7a2b92e25382e22b8fac876f2fc78aafea2f4c62f9cc31c683e8ed6e6c0a5757934eb8c7ae40f9188a1aadd0445c9a634cca829a46564af8d041778346598c2a492467ee25837ac8504fc9247888ea6a386f40796d6d3931825326b19155e5cad9b48690223705698a532ba5341c3123a9aa6a8acd5c55c522904411bf0a1b7f5d7df7d2572c9af2afccb8236f483f5288a879691075a5141d02c3cb62a2a56061a65d65e862c2e0b1eb5aba7ac539fb39e79c8b50b1e7b21bada719e5042487847c89ff4452d5d1f13994831f764bbc1c4796d468b65055555555d589c46ece1cd2f40680165d3a38e79c73ce7908194e97e503c239e751fae4104786ac381f6e1fce394fa1e3b22a9c5a058f11ef31b222cae7dee59c0f87c3fd83e1852f07900e95d692a0b6383a232e3c2b396c435a290b9aba5a78354531d98b3bca18a231a5b4d493e39363f5f97175555555555555114aa2ece69ae1e4e9abdeed790da94d00337097978ee657b355cf4e459f216b0ce8af2eb992a0ba226a25f99c37935a9f73dff39bd5eeb2ca6ac96e7d5dd7352ad760e494ab5c83ffcb762b438055e4dcbc8c997c57d86595156b8a82f3486596374de268006183eaac81e0450fa0b13214534cae1f99e55f99cba5bfae5f51ecf814aacff9ce1a4388e305454721e76062e1560100414d1637d2bcd29804c0a90f8fca468c154026fcfcd5bb5b3c4c1138e79c730cd4889166250c2c4c6b03a72c1e153e685e5fc89ea0600f8d16ad446b39e7bcf905c49eb59c7d4ba2e333b60605fd7a52327d9e9c3ca1d4d85c3e4012be16c2133681ac2ebfbc4909b5cdf0d1f32a8183a9432fab8e0d2a88abc7aee591026ad109470c3da35b3b537850986ae8205f6291dd57d5222a5f2d56f57d2d1541029484d44170082bb908f888d2f10971f2e502f912bfd69a569b85cfd7849edc9c4f2c21231ac8052a2aae8a7c15f938510157d199dd93b1233a905c3dfa5c9d85471c191af6755dd7755d4b31e7c6c664c9c98c11594d781481564187348f20f5e6734ff8834b858ee61aa2e166b5ce91b4882b251794ca3a4588908985f4390f72ce57960b3fe79cf311543abfdf5a6497624b954bea08e79cb39d757b92260cb7cf391ffaddc3fed6097f5dd7750d51d5c4395bc43c3e96885e3083902ff107116309a2c6723169d38b4665fd406a7d83c9cf5a0f0ebd173c902f310a5d320a5f16989c9025a190a9962bb5073121412868a539d0d556b537b4f343a985138a243eccce52e40809922014b4d20203a102cecad1dd971e5e0917615128526cd1274c419c44087265820ff68e056bef868a3c262234b439235f2f54e080c252a2975676acba6ae5d94bbeb220168ea825b135253423a0bab3a58d3126cca5be255996cac5c2ab6b2abf9ddcdda5b1154941ba3253a737e3ac89ab68acd9f3424c4f4169585e31c16aa9a3d70ed357ed7252533a5634c5270849919c0847509aaacc50265bf4384a45404199507d2d53c78e8e8a1b6107c4acf2f3d5267346cfd1b7259859cb619941f267dfa61e5c76d2ac370002015e7d9d8109bd35d0d03b91e8fdf168638383c37a08b27907e19210c9c38fd1c11b32a071d5c605aaae1cc09cced5c373cd1f32f8d8973db313fbdb6054fa01357429609bc1a5aecd1f308099612ba0708335598dcd470cbc822c478ec10b16210d9d9c5ccb052d61c79039c4f5960baaf1d9126186edc0c3cc0cccf0d73b91e8fdf168638383b36d8c224890112af3114cc2d058a5f835b4a0e8c63f8b37bcc8b06082172af10623132858184af82cde50934721062b3bb0f170d43003e3c644f58d360a951efecb6af82f3bf35f16e6bfecf0bfacfb5f560b63a25a1813d5c298a816c644b530266a63f3f30641882e1780f5142e1560d4a050a152d770b052e1e5c52d1aed5fa84c396cb0e4a5c2c77e2b7b5883b94078f5d97c6cbb2086481ce219bc618394180addb5b1b14f85745fb4c0c3e4e3062445e3b06583d2887d8598688c5b162af58d3676ed5f0b463ffbd782d0cf167a54ff5ac8f939c6bf31793fc7d0099d2c2b540a9542256785ca97152a5f9cff0a95acae71512283f387081f7b3528d4822f54ce68cd5c68c9c7a70b9d3dcee01b16ebe21906617789430f739cb1d1e0a1039605d2530e58c062b6501913152a6784ca9ff3070e8e34182eccd0c8188b9ec6024d0c0d0dcd0534343034341368541a0b86126822b474210d4bd0a561571abe696858bc217b9a20fe38c862103883649a3f00b52e2c760627de3c68b965486b73411be2a188f3c968a34f0dc0c5ae830a3938cecd010642c70b426838c85d301699b139c2b041186b2c82c5bc0ced0b3890b130357abbc2065a2e5d0591431f850dda580b3cb00ddd7aea256cd8738b4bbbe55c1f53af8dd9983d0ef968ca3a345ad5da10584e9ce492203d494b50a20811538594ad2d39573c6b7a6c616cba6f5dd7755df594ba06b31b376310116a362faac90cbc2e27998da4b6271e54583672f0924d3c167fb5a2b73434ca51be7833ca5b10ef070645c91c6e4a36a4d5ba21d1cc993566371b95f64eec4322e744f5d9d2442e4719b122bc9c1e500ee92cb574b08010d9012472f583af2aa9e307c78e94aec2b99044da15129fe65ac63361148f5647e936c51a23eba8be32a12939e79c7b71ce3906241617f28b0b802a68e077e4b4cb5795428153ea523ad519e9d9925992e2fb7962f2a449f3d1c0f024774188c98b49c857e51c60a72407457464a52fc31b19d4d294269f1395a3f5a84918e20e4965459848aebf169330a1a3769900fa6aabaaaaaa8eb062c76e5555d5561c31eb510666a5fcbaab9b32b28516036e6bcadb0eb9e2109f996ab906bbd1fd4830f388bea5eb9ddff317c147a975b04910331532964cdd95a8f2993284c9d68c2515abf7d6755db78442d6301fba75dd54a99d9be4a77f743366b06956c45d57b424a111b9156a0763421d7659f9d14ba56875d947f753d323960c31c0079228a3a2a11d566a06585cd591f1e89194a3a53c81847832fbb0ebfca47efe2ae684ca6a3fcf7770a0e46226df089e456df0a2a3c1236585d21021695c4894a5c885d65752db1226407414eeda907811a5b560a4507012bc8eae2ca4772e3f4efd0b8a8a0892eb2774ac423f5bcb2899d6755d63ece91acc027f1540f2646c4d2bc60e2b1b08c264c95c185a5edc0d21d58c5e84bc1b55a8f4709ca81353a263a4026d48df1eb4452bab256f840a1745a07665307040493a5740b102857536f78bd21a6f35abc039e77a8b734e5c9f0ce51a8cf4a4a913b5d4a2d035a1b1e24a4e9c06aad47eb49892452cf45d920e61638808468b9efa82ba2d77185901079d6ad2493d7774884e008fa21a0ad152d02f55855d2b0f904ea6aaaaaa467f3f16362b39224ba743e77e7aebd0ee00492ca21cac2234641cc08a330c480aaea792a88e8bbf6abbcea13689264fee0ec958bb9c446118f668556f31a9467b739f73ce39e7219e20fd7e6a5d8bb44b1679d188cba1b4421504f912bf5af6d724123b1e70625d65c83a352bf75adbd2900acb27bdf3356489e47e4774c11954d8a191bb534582dee2d941b175cbef26137e552c1bf3ec4eb6c2cd820fa70dc4ea274c47af242f995ca35555b5695dd775ddee66dd2969694b533774ec9031f5465454c3a70c4a3b39ca3b4a167c411aab6e9ec8fba551cdbb1fba870f0ee116e57048c0ac3d34caaedafa33528b49e79a2ca8ea63432ddac674f2fad292cc8006d9d0ad552a8a17909113cf3c253aad6c9a58fe38e711deb20836e8baaeeb5af64d409901d1e36164eec7f53472050a2a055da6d22497d08152650a89cfd29914852a623f4f369660cb287433a36a314c68e0353bb5c5534e18d56c016da36c3c3726d175d5a50c767585b5e8b9b4078d0d78ae5af0883e25e72d1d98817579c56863526a3732aa2044694355b4dc2a46e61a896a9b5c96888d1e329e7cae98a0827c899fab458c15779f7bd7c934c4b682a7e9461cdf493134fa49434093ab05205c534878910512668134ec3555c08e98181224ce0af225fe3bde6421c753438f2d67c86c091c1d930cbb2a9e24455ea44559477a7c62e84c81295151f444d06feb2a952fc068d2a9881aca8dd71f52544a43d9124f4ea6b0a51c3c33921c4063aac80e8ed9c64246f2c794b103e3c64492fba92272aeb8cee22c51214c20ad3472189928c2c4bb71a285f0c4515491b32a2baec85b0cdd66021ae1869c067a0926d12339e7b254f657bff52fafeb5aa53ec9017f57cc9d1b3d6b1e50fab09a5cb4704271a00d8d4d2809f484a9e3f3d389a1a4074ed5c96189cac261f34f4caaaaaa3c3b538e4ca0b0cbe103f729d17252b239b7aaa235ba94c35ec249c76a0998912410d195ce24f2534287d511ac1e41ceb7156c48cfa825689126460f484bdb1b7bce4d9960aab15d6b9948a80f8f2e08b46a860a5ef8480b7ad1e42468089a508e42120a4cc5e9c1d5f0da49f204e36a4ccfca8d3a3eb51c620a2b254bef6b68d446799ec4817326e3685a8138541e50555535441fbb79ebe502c593ab98a7270b2d26fc8a00fd70b88e8435c3645c794282a82448663479d4fa984da6d993d5696c67dd7ea6a36b301faeab50c310664884c9c70d4d723e8449bec4786a8dc3451285dd13d8724995c4886965e588099cdc5aa5860548f41b7001508ce4780a515a3d594a325376f53cb15a8611b156a22cdabaa5e6b4e40ee088d2978625e3ccaa04d0195971369c9a74ccb827130ec85fa1ebbaaeee1913352df183ae07c555901d38a910e0008a33e265a4f404c9741a02c452e2ea33a91440aaaaaaaa17dc006cd090e961a28fabe9a96345280a05a6ba68482df17a426126a28993ab2d2eab7457744a358ab38d4bbd6ef0f9d42c15117d72ce5b968c2d79229bab73022d11c447550b2a4a446e43f4913d44a8aaaa1a426988ca57552e9d265f557559700d8ab1380312a1808263c9cb0595285328ae10617b63a103b9ae6b27fbe0a5e4a32637a5cf24073ef2a09c6e705154205fe25ff1038271058656d0d6d99214521b31a1dcfafaf12605047481246f506761513f448a4cf56611ae1b5da48f6baf62ed1131f68c3ef79b7331bf7952b1ad1d78673df0f87e6ca802f684892f965da8846c776639aa0cb248200020800083170000280c0c88235118a6599ad91e14800e43a85260542610c96381401486310c02311000010000200040210cc3801c8a74ee099c04023e740ba02d7477029d8106b027b3d2c49c1a08ef0c828d294f402640101423ce81da13b2e24dd0f7ac279f7660aeb7cc62cf4c1769484e3f435b0317489b959c4f3a65ac74feca770db9ec1e40de4e1e7c8ba1e05148dec5263105e540600e8316ffdbec659f3c04cc4b4184c3687e1b9100646f638608dffc4ac0e98196bc21c97ca1c8035de0907dcfcdf0ce192e3f0e439324e7f1ec54bfe88e76b5c4e99cb850793cb6ac3c719d9f48d0c78b405a4a56ca4d772927ca75f26a8ce2455ef3e2edf74591c87a19f05902ff5404be8cb991c51b5d281644e9f86769b1599123d504ba3daf8b3a153fb37763f60cba5a0a24cdebd29890040af1571a92737404b3a36eac8ef82921e49c4ef4df427004c48d643b5af78680de0e68f7008a0e0052a3029b7688c9258422c6392238bdfa8c4e9091dbb938600c10a647b40695a011e0bd9431b8e967cd7c0a256583583b37576d08ed9203e316c929784b213ae0d528382400b9970035576535095fd01caf711fd8403610288ab5994f5591de604a9dd8ef491892b83bf31964c91302ef064ef0d4269fe954e4903f27f8e3f070369223803ab40ff5429e156b953d2fce96b85c1352d2b1d550cf1b4a4398d29a60413f1593f5ba2febd8dfc8badbc517df90adc3f5a0c6dbb448f1d3d50ce15c41db4a15f11e38115e5534b636e93b211aedec2fd83030a153cf2f7fa9273bdc97118142074252115828fc65c5287e1d2bf97105ccf2e23667dbd23b9067913b89314dd35a77b2074cd38c57ec99f183a17d4d75ffb9436a4b3aea963a478a3b32bd08da87c66422c75ddc24331e38170232ba4c9a09e028e4e93063e033cb095b64742901131771798eb7ce16f25d7b57389b54428b1981e0b516787854f284357e4b0351609b34d0717f84a3a1e22a393308cfbec2d337f032095c3c9a99ddaca693bbb3c8295e127af5dfeefc43cca13a6ca28628a50ee5b20da45fe90a1020d8670bd750782d46a08135e98e3851863f898bf16d1ed7afdfb0b2b27126a5dc4dbe9c75a6704b449df76918cbce615fec354b342f9480cd10fd108c21be0f3df42f7d49069bc594e2ddc66ce37538539ec783af3f6543627683154fb445041cc03b987525eb7885539696e6e8306f0593c5e262d98d465d0576639617518225d34406d1d29624528ee3f99388592c58e1042035a0c4390c5f1c49ce04395f5612511d0271d6167fd7f92ff1c6cd4445705264a38c7bfb13eb58a79fc455a5cca6ab3ef207821f9014b58ee3e39716e76c4342b86e956a1dc3165e54dd5e982628bf6ed4859d579ee387032255588717465a0757dd46769e959415c0e9c9aa3350b06ea1c70a63a021e0f4a47a22319cda3b0505884e4b2a763846bd0c429be5199ff92bc0d5a78be9c9b599fe045897e6e53a145d65e989418c3378be13ddf909c3b40a40c041f80b79a53d32f2c8137b98bd4e48b3dd74004a086b6c7432e8d04d6e2a885f2fad0b02a070a680b8abf52d9daee51dacd9bc6970fb1719a2df53d7b4437970e65c95253afeb82e568ce7b1e761ff4fe4bd3b7a5f14e58c629ab3a22479a0714d05904101489eba24a0398d116c8a6d7bf7de68931014a42038c804114aa97ac3840edd9ea3448a389ef29bbadbe0d6895e3ad7c982838eac638620f8cdf41bec9ba2e2668c0ef72022ca1da33914fb5817eb8780794e3b069bdd289f10370fd63b90c38ad752ee6e1cda39b4b39320cbc5fd7e8636b3c292ed435dba68ca0567727701251d33f2bfeadc843737a7b1b339b7d75f58729297099a334b3697f41762dd3816ae5cc817affab829c6df686394fa6fe7fee0fc085d9828f8ce9dd0560c0cfeeb4ce0a7dca1919016b4a6178829b8f3d7658b1d3c33832b07fe001f5e147ff2441ff9f79ef53140b1c2c039d9fe091c33809c4d962481a2253c1b00f2f32b8d94130852c4aaa1156a2c93d21ffc6e5e3c77df90688d75ec2f320331f0b044b65c9901d419c7c7f73baafa180d6fbf9225c2a506e6a230919a5be9576e809afc03adc15d833976c70b713c21f51ddaaa659c53df6d842a84855ae61f2c7038937557cdc49f83cecea08ae288d0cae750a00c22832f7be3974b971c4814f570ea006f370227dc550d60d2ed35c4b8bf361b1f9411a53696ab70b7449f13721e2bbd3fe5f0f66caf628dfd28d1103be3e227608c7f378c2b0da0e66f8b5d8e8543bd31aac3f34c20eb6c6283644f9cc64a97392b5aaf77146882811c6944c8f1bc98d96108ce719a551236a24f30d7c8aec3dc6d503ccf322fff67a64d86432995c15e6ed6c8031b59a1d689ac9a0416cd1d51274a2742de84428e6465880fc3d0c91fe79157b7ba54f99c852adffd15ac30d08a4fbd98b3cfe4c57d5e43ddc8b00fbf1d1fd3ba13b3065e55d948da094018f2a509e9b68b86eddbe206940b4a93d96cb005913882491ea0c69510b78332e8d44fb304e3c7fd7686d340a1fcdf0c145fc4c0cea3f3239a660ab8405c83506bf5637bbcf7ea80cef058968c6ca4cea422f2a3df95e2b76c546e120a1b95f67a28c9ec3a4d0afd363ae28b86451d3a13383407ac0c647b48f4a855c3b53e3f8607e9614ca87288cc78a9ee4406b0e47f5bd05864fc33d94279221a753ca209d000f8d924d40b67f02346540c821631a1b9ec38f654bb35594ab0339bcf2a77508be235ec77a6eacd25629b36c94c377417b46530973d362f47b9ef6303c5a91430442c52fc6fc533fb52479a7c1ecbabbc334bee909b4ff901463c794bf4f689d1374424cf0562de6cb05994c655ce41117a519461a26050f24cc40596118d35e94fe12e81cba4afa000d8bfa26aeb8b07792b8ae14278294121c742809930969aac872aa977b2aa2092d4861e737a20cffd5a6338e79db4a949ea615cd4292c3226e9b4ffa8c086d2df4d4c43892c6826baa890c697fab37a0ed853e45bbcbd046bf94546b1f906a40eb3a8b5bf1f9453ac0fab3799d39c7c830859e7361fef2cc0e678b6c6b94a9ae50b67ae59695f0517ac55b60a2e5f1662a58603b0cb23fdb06df44dfde859e6b7556aef7732d2cece5ea31e0941409afc2509005774fcbbe08ad888c89c50fab922566651e4ab2b07664b7bfb1f057cba0049b419b6b4ea8e7cafebb8943393de443685924cc72425389a7e6a86bf5af3727521f8465c0c5d065ac4694a5ca1fc4dc06d999d1d14a72c97faa5e353ced3a00eafc7cd40be28e4cb2bd600c38a7568280a811b4ffade3d6c87dac54d9e7144c080e01e4dc3a066cc368052b1423be208bffe3bc701a12338eef7dc496f051f8a90aa413e1121d26f81165b62e8ab066bc8260d9ce5aa9938c190dae2c2f9f31d70665a20c60dfb41bb85254360f84a09d20f3f1c2e86fa34bf46c30c2c9b8d1bea8df76ec37744e9c230382988b6207e8962f22bbd84d25cf898017c51620c97c516f225cb54d0a13b9c610b70ec101747d5907546d9a2a2f46a12d8b411c77e43cc8c162540cfe91a6397b68fab1116b7c7c173314c3cd8af051fe6d5f1f3e0cb2cb6b91f4730417df311013a600646b35b322210d3f7e262ff9b635dfc587bf7ea17c839f66cd05164a2ea3bbf1c809ad3000c63fb3bc35b8ae4310372f18e07d05d4deef8c807fc59408635cc6322b2b911f72a76d4574968c20f5ac3e2729150e889739435497dfe004e5282a1344bbd0e47119fb671200b6ee08978ae7c0b1e3a0ef728d383f6a441ad5a64b3adfe60e22639defd82a8e6c57d87ff16429eddcce5fb0b4c263d179c4728166bf83ce7244e23a76a28c2bd98cb1bde56c001c5bc4ac32f3065ee1364f6511b69f0fd7d7982e0fd69139ac429d46b1a86fed3bdf6c403de2c41674656e9b8f694e77d92a503cc86c36f5bd9298bbff1c08a9ff49801643449a8f27dc87879fa96298f4556568463621aa1e829e7968e1417552f5f79e0bbc191480eb1ed1126ab5209b56b7c2f8a3de6e5c5938c7584a0f35477a1ed498d38bc377d20211d159209d861fc971a63c5f53342ce81eef79462ccdd12d802cd956cd1df881ef86493a82776585b8ea160a68e94171f79c13898fd843aa48c73ed4448e285a30e67866982c7fd2cc6e2130d2ae12dac7b1282c06f538bae2553ef4c4844dad9bc73f2374cb6e876c191804aec326e7f487ce59e9d90ac00b8cea24945dd05a83a89eb66ff25ceb483ea340db81d988337c45ff0206480d95b2e1c79d9d533acbcd0cac6073490f6373b5b5dba6406da5f4e04bd41fb10106a2f81973ff4b2a0bf4f9639e1c72ea02cde605bc5ef5fd7f6355b5aac77bfd7b4f7b6c2d3a443bd5c99d88b04e2a23d5cfaea32fda8ea7cd54ce4ce32d95f010ccb47fbc0dfbcdf51ece489d1214d767a2251c481f0f1955263b44032be5448b1dda3d70a923762a64422b54d2ddd3004aec9986cdb28697ebf0a7c504e692eff9792932a30b9f319e4f413a98d508f233e55c93d7d1179aa91081098a41e66c4da0cfd878516b1ade6cf41641eb4e75d0c3f3147153376180081588ccc7bb11b44e7f0b9ff99de76a9ab2d7211fde321a7c6d332165334d3c83f8d8876c63e7aac7e71ea299ad58a3569cdc31b72f0a30abe2ed31a5997b5b4369bac38d18823e0f121d91bfb1fb1d5c4a05c377971f333e207c6475bcc22ed2609435df72303e9a323c97d5683883bf4caddb32105afb2d111459dc602ad2e26e32e3269bd8cc01b2a33c972da6d14f497e303859c4e9775bf9e07f20da772f449fd8080cd1e4b1c87a416eba517d01beb062b0c8c02d35124724525f0774acb3e0086079fd922afee1ec3355187725d4ae9122506dcb8efe4cae810fe1d9015f1e26101fefda08c9d9cea1dce89f87349eef6a92841ecdc5d6054a7522a24d667ef96ddaafdad2461e39e9326c912ce6fd35198fee79e30e97efd4ceb455409b135bd0934e173a056ebc8515a623d8b149819758725c2e5e474fffcba471737f1c616d0f4be1d4c6fce5f4405cd4bb327bf9073282b0f515156c050eb81a43f59318e98aa3a9d13b681d4742e7f0e3dfdaaff0e8262c731b4ef3daaa34342d45c83d2cd4478a11315538cbecbf01dcb2348a69941f5a76597164efbdfcfbb7188d7c1a01e60ce453258918b2419ed295ec09c0dc8886d00c9057651c284314e26beb8dfadad2e15b5973b9b4a97f6866fdc6fb46930cd3c82cd6403429ce9758d12d2ebf780ab872a0e3f86fe49d3f26c7a21dbb17b2b8b5b6575d09538d33fa146a93faf3bfcabae8d6304bf67d23fbc3cf6ed2fa0ccd826be035e352b3e71241290e6f2e894b8519cabb38e35c2f110a2f2e3f5647c62c476bb78f935034751cf6e96acea5e2e6d914482bf6c7c27d66e3c7c0cb527edb8d476280ec1725fbca6187339104240a535901e0b7a5e95b2fd901923ceb19cb7e381b43aefcebfe0c3add476a00aebcc447b1b84ace25321d85f688e0ff50dd6b40dc2fa77ff281ecf52cb35735204a643a970e2babb69c19e0ea92a4b0427660ec632e46d3a24515cbfa87784b69b846f4e0be4ebbc11c9b3e49bc99a4e8b94ee48e859817797c695e82cde551c3901789a1b6c0cead10621c73ad2869d9568710ab109856113ac2e74b63a00cb1c31bb6614c52ba9652876c98a6e60385bb1cb5e4663477093a6c5e6777d9631a5381c6a9da5f528566277dd3a2f1d40402cadd2f7444d87047477a6ddf8a37034914f7899c832e861383813ab7053caa06bdeeed2873e7a5ae87d1625bc0f49eb24ebb6e776eb3c07f3196ea4f1495163a3bd702716e87bad465fa02477ce4000e92f16343ab18402daf8dbda70ad1aeafc05bc185b8af7089fa4e04e296ab93000acef50e6c52c2a25af13b5aa2414a9c8da4e5da0346825ef9dfc24b15fd6f9da04dfbab52daca8f681d0730df784d6b3ed0eb3b281626c966a8d9ca09667dfb5dd172bea0fd872fde9131d896277e24e81728d2c551e328c99728038bee1400af2114b9eef0134cd67a081b3c81295c763b5a87069db37cefa83893c86a4eced2c8b3b464351828e1562f5cd19f26f9099c7bacb415fc4245260abd7a83758a37208e305d20b6baabae7b1bfdd3d918db915185cc066f68ef3f037d790c61f2716487637f8e1bc465b7bdef133c191dbe6cfad55da8d0467e4268ddb5775a5015ba65556b6d2a03a7b1366f52da5a4ecdecfd7e11c5ea72a4f4c1c69359bb25bd0f2efc97bb4f77c87189bde59697965c62567f726d68b3bfca034abbeaf2f544e36f8051c41a1509e0c8ae69bcd01410266065b36a4b1462324b976a170010351175351cae0438877ce207e518b96d752c5d9aa81c20114b232a642c804653a9b14149574dd5742c5e2631fb987334404fa842044ac91130ce12dbd39377311e2964f32798d44155188c2720d480107643d7c0f41055008d228fc149426b8a4fbc414825c4cced3799c49c036b136236f9c67ad8cfbab537c4528b236ddabf457e54698cc81208f4ea0aeba1a4af172e0ed918c98ac045be0cd7cc2a1058b65c782ac117ab63db596e400948ce63f604ed2667805430fc00b5877a0f671ab3ad98149e2af8c8e173a31eebb7d7248a24e1895f0f689e8bd04a959e0ff11b0355c0460a6ede5b344f98d0610cb44a89ac1dbfa02aad4486fb371d2926b84d99afeee58f0a5e36ee104ec1374c0056e0f5709408dad78a613f336158e54c0685b875d8caefdf9e2409eb49dd742c7047402e5d74b2152be20007b9a80489fd2370306214825ce6b96c0127cb744eb7184dea121091de869c35f2f2600eacdaf20af049ef5cb7ae1f4b467023b9cdefb520b09fae1bd1009df78a272ca58ca6419303a803806650c57a79a998ee9cd50d6820bfa3047cc8c83b77414fcd865a8f2782c94ceb6d6c68f5449e4835f9ea7450221dd03263bdd266dd7b76362e0ebb0e8c894a89fe82eb259ba0bbbd0fce9fd8b3817353f938a9bcbf4b3f22bb3b64a4d7fe18d63ab9e41f20a0449d5441545a623c6f093222de8d455c60b70e39de811e9e90ba0b9e00b385abbd6b1ee597208d0eeb94b44c1061eceb528260ece507d41ebe087f08ec8a935ac443651bfef5deab2044d09f9bf74de4ca273abd7149198550fbbe5563ce471fc86fb7c13ebfc08e30ec454915aa777bb27907786ec86300316febc93fa07c86e64f21a78042cdcb2941bd85af3df1cc9d4eb0daef49f006347904925318621dc021a7f570d92abc99926db61cd434d00186b888f1263fc1f84e693587063363210b37550e0db9b72af461822a2ba80daadff3525148afeb5f1d1ae30c6b710ce90603284ad4433d65c47fe469431461a838dda6197688beda6155231bebc8d08b7f38d334dbb14ec44364142c54e06697680efefc177c12af44e6c775af32c200e68e0cfa14b0871e7ad7a121f45041e8fa63a198550175ada68521a640cbfe6cc0d1f5940ba262dca7ba188806705b9d9eded26905f1f62053b24a9b2b50d3c2f910806f9b2380c5d70a2c99b5a2c1a41805f788f9499f6c9412b88e9be32eb0ed0aa22e8080bdb45945ca22c5369b36a0acfd64cf33f4c2e54ea4a5dde32c5b9cdb3f2fe9a3f6f3b04be7587670ec6bed52740a15943c885b9cd2701db582af88560a7853861615221108793d878315fd49d00c47afbebc453807a316e5aff08417f3ba6141911fe323567036c37488296006d0ff943199c92e42fd7423845a6bffb80adf92a7856d490038e516e9c992933dd7fb80bdc4249725e40f16422fd38d4f9374adb927918166b21c74913eca3c74118e662160e8347da56b9fd6fe99dac63a96a0a01ae6a1e381a73bb124869710279ba323503676bcc1251e1e6703ec9e85c3635beb7bcdc045ee51c0e001181ae700d668647b6772ca0fc950bde1b962190cc935143a145fd755054bc1231edd493643126580b08a2fb2b781cdb8b9b954e31d1ce1c7ddf6c30b665a4685f187f814055395df50122db27e4ecc482f40bf1a58f5a8d5cdcbaca3be12b637b71e41037ad6a6ca7edbfca626d742e8891ad6d1c3c2c7e9a2c98349921753e78288e20def0576a1888ffd59fc6c4e57364c43020bb373d0445fe14d9322e23a1de58080f9632ceb57d1e0beda4898317d5db2d6641dc9af10da1e78c2751ba5b51b0aa7ee1496dc41fa1a268a481980aa251bde11cd56fa14ff24ced58ddbe33e54674333b69a4b2e23c9db94018dd14a61d055c4b683c155337ee6fc380db507178b5febed59a05be00c3ffd0148b69e2d69d8c99dd9acdafa878c2cd000370d09efceefab9f075ede159485d3536658ada15ad3ad11ee57f01c96709ee02b26accd699faa321889d175a6741a58020bd8a9cb7a63ed6ae125965ffc97057efad0e551107f492356cb8ab212e7d3084b295525c3a8692ce943171eba2855e50b981e9cb30ce8ab22b072f62df474aff1a5b44e928fea3cfddbc292dc91a996867a23a6e3cff947668978535062b33701771aa87aca7bb1b6e7280b90822f361366ceae45c504d8d30e2198193b01f5ebea5abd19d7d79c4dfc1b7369fcb14f1ae05f5ac14b0cbb3d8dd5add0f506bf0bd0d60bde5ab470a871c717046500a45f4fc885017434a2c42708306e6b7d14e92af65a11e257da280bb41fd154793c903b392a3ce12a9853c02c3b5cad3019d32d71093197da5b6653bb7dba90d9e27f62ff4ff58c790dbe8f8e8e68c90b260c670a2bc01b19cab53f94a91f0556d832f5a7454c5cd5d1e401feece89ea046c5fc2b20865c1b6a32d9000a286db83bf8ca4a35189f2b3c2af2b31aa24fe5d71f3506817ee551475c9cabe668fde3e28e1c91d910ea08163a3276bf5591fe294f9a36206d8ed6a123378bf7228a79c05b1448b286856025f091183f41507208abaebac280e6edf828429a1fe7e5a889c1930481571678b82e15ba1554f71a25151591aa8a0578f06e732a7f20982598c06cfd2958252b9025174ac986cfaf35c193c74dc3ba523cd0e72a4d36def94af62d42da754996a823ebd6aa22bbf47927c2a6e60a98144eb23797c0073d9e9ea5ac1ddc2d0a2838b8912e82242e77450a8b79aba01394dc4126e948bc808aff7c07c081ff28bf821fd19a660db88e2ac754b755dece8cd67330c6e0a1d634f2445d3f4b078ad614d960796ea12ccbf8d752a89e9777bfbeaab41fade4fa759601712182c4d10a2a9031ea36a57ac146b2272cba79857ab8a0e032ef2c0d52a8633304ce5905dacdf0a18bfea83e781e6ee1a1328103aeaa2645dd8a4016283cb1227bc5fc958ea68a874e90089218de4db70f60931d8a2c46c79f5bf04d217a766cef59f59c29f8c3ec3527cc80c71a2ea7f2c133e297d5b440fce28d7fe66393f9e0611a32203e194a8cfb2b19c16fbc024e58f9b8971a26b36074ab85c1053b686756eda4cae85874b9df112160f640571cc8341fc96c3c501c9fb1c280ffb0fa3ec36286916aedf61b3dae4b459a978e510127898157b3c86d209fa6d12f73c88ec06f07c8391c2f1879263d09c7ec6b2caec6f04edce1edd409e0dc594e730ac6776da81d4b054abc94b5beea8d751336caa5b636ab8e40d31176b2f2f85012efc47e20baeffca04c62decc2698e1dac14f3e0a58d7456e3d2db393efb2f6ae286c0bbe089cccbd0c7499d6a49345e7cdae5f466423a497c3c3d7212c68603d5213fd255be703fac3119d031f7bcb70eaa3278c7a3cec8e4cdff640d0a5212feb5d175a7aca6c3042e71ed4d0d219e6570a901226c1b0a3bc25de01886cfa482cf470879557fd06700c1f3d4e90b0f8984eea3d9127d6f9e7d5f783068d7108296329b04914a537eb6f428c8b599e19387f919c79f0f8e01661eed53fa799f75dc99bfe64d5908b689bb3daa03bdc5f1dab4b9baf80d0d22ede36b4be93e1e724d56cb0a185045484bd0a351d80e4e400c40195d287a5bc368b1eea1622f43836d4029f31ca23ce27567b4d82605da006220026456352a1304663036517514eff8d336a3530f25bd5a3a532ad61c32ba8639eaa93e6eaef8973ef3b20583c9dec9bbbe4cac2379095b36c79d55f964f7c1a2928e9982fb5dfd21d5ddc649e55d79323889609ce3ab9892269de9a0c922782c7b13d032f406202b124b2d0a1bd694169f1971725787a658713f1d5d0c4d52df66a5f0901af0603f49013c4b1cf69e4c8db9c06cfc0664b3bd01812d76f10a98f0c144525b11784c9cf9a0cd243606fbc68ef5f5a285da380460d8f4787bcd9cd82df8f539cc574356c4b1ebefda246e3425d58b29872ba4c9ba1a0b602c16d63a75cb84a88605a05f5cf3a9b21119596031a4e24bc7e33021295ba6c022222f31a0d48646c3cddf27be23a9c89c994d03021d0016372dd6998b260a636ba4ac6eb1ef2fd6329da4ddef69ab42c3c5de12f2a5a35c801dceaa38ac8a18065c49f7dafd29bc1e2d49441c54f4fc0258249c250eed3acee1958b8abeee64573738e96d0b7b69c2a7c0fcc89bb69538277c9ec76c7c723c7cf1c90075f3578a25e20bfc4c27593ce4687554189806accbfe8669dcaafa871072ac84d3918dfee84b878a79aef7ee9210c565d62ad48a0e4dafae0136abbdf4a48b083d82e9ab4245e1136eb026cc1e9e784dad0933340b75ee4579fe94432fd659107acae17337454e1488ef103defd2eb4ca4e6ff9d6165eba53d3c48415fe2c6a2d5d507fa53beded45dc65585a74ef4b6451a051d8cad7d865192064d289743083a224bff64702fcc323ad716257328b172861b9ec86e1eaa20f212e31def9be0e79757ed75609add853775890b62b3f89f8ac55a7b254462e26bd293b00549f7c5c4fb360cad29da9d2ba39b6bef041bcb224cb923638f7a9bcb0048225382bdda6d4fa8fd0238e6ba2a7561d273b12aa770d5b930c7e7ea549524bcc899af2aa243232df7608e712ff6ec7121645272618d67bf99ab7f26f2459e1e017fa96c46c4669ddbe6153e72d56d4f6a4bfa81b7b20954f9f1fcdfd588e5bc75ecd35c70398ddc5fa0352041d48dba7580d711fcc9024cd1d9db7a8dc997ab2a054fab250fbdc115bafb5f43a10beb16657dd69efec0d760a3dc82656bc361aaacbfb7c5325bd078eb09d7bacbbba8f472dff24999f73ef32d5f8f61b67ef0fd000bc525f38d22f2571a7780bb7c37d5781d65204a8757e9b6ec05f95aecc5abc9beaf948af45909a9a3858be4e5e67f198b995a03cce8163f55708856ffa4f64cb19f698d1adcd7b315831bc9ba17bd7a4ca5801b982e679b905026b4dda98fcf8f657a44e5fff7ad33b6a985d6c96a6f0c25aea32200ea1722eb116cda658a1f5a3e325b4fc65c08984b886f5d822d60b3bb17dfe97309842c97c6d5f388ee7f8c9b2768a997855c73bfc1b3f570447a9536339fd2ee17946e6bef6d430989a04125232a5ff3b7ffc648953122a1d64d7c0964263e26845c36080b7b8a5c8bc9ef1ed30b0d2992100e34530c690459381c67dd0504a2abded4c39703796568179fed1d35f8e1ec067a61a7f58ec0c69d172795fc2259fba7da4509503a0fc83b07f96c7b8b564b5d9505a152eef1ccb9f1e9ac56a4e2935306cdce0d0e18ea00fe86b952f5cf262111cf2412b5e430a27fc63722544f32147dfdc8b4c1144db3d82fe6abf7384bdd829599c3db011690420ea4d947b602593907a0761cb886c3f4b232790aaa274d18205f9a4a2ebe7ebea660715320a126d1a78244ec9c8b486b9d73209bd863fefa91ea32b85a9650ba3347ef040bedc277e6bc5a63fcea24df3d6c96fbe613da1ad6cf77765d162cda83a989820b18a39435ac11190a04fbf683294fe06fe7b450daa622d8180e67e7d7ee09f52d2754e2866f091488560b7b404eefa9b32da9f23b3e7d151b22a01832363623100f7d043f2a0ac418d84dc0a7cd450622ddca11f9bfba739309b1ca97c935badd37fa7c1de84ab752dcdda39a37cef2c8c9c625b1481ba7d5666526ffbaf08344cc43a26273b4a92bd1392af9bc42cd14efd58dc91d6cc6f5514dff15c5a2a93bbe59cd003a4bb0c267b8a11e1ed8561f16cf1f94057296f811501c6707e690afa07b61a3201210a7afcd0db04777338635c84679e262169563dc14bcfc4b7205731e98287b1d0053df4a54a1b94c3e5abc5adb881a61e8296aaed357feeab82a44ac596f521b06e8fb52425528672e08e9bd9cc1aa8f534106335b15687b853fc15cad6cfe6271379f952f41059773330e8b1884439ea519ea0323007bcde51d36b70b94c910f1705277d2acd16ec81cf3717d247d842a48929df91ddf3c925ec5fcd57555d0af1c22e787dffc7ff6f0235c4ec496e9d4c859d88911bf8c1322f5c29aa3ce851d3ad7d850437c16fd65747e2fed6285aa68519b9bd3d070e3dc48ebb4bbd11faf191bac8501789088f27541bb7958d004775f5f6e4b2f507082915b0812fb71a8342f5332daf767033a75d3e10a7c8939c77266757c8f22fb33903658e03833f5cd51fac21b51ba1429d32a4d1f1aaa9d28d54c3ad5b5172e06b150312d3a8efb5b228877a30f7f76a965f28f39ba8f1472a14c4d0b9a6fbd0bc4226c7f864da90e51ef1a285bb0de66b30bdee34e89021b905ab48d26590fa6fa532215779c5a45710596e9f09feae82796c505ecc3c30b6f8fdfbc73ee568c01d201a2a2384ac2a35fb32c5696f97ae08cbf5e77a0fa1a5dafab6950649990555e33159e25a5739ea086b324d39eec76f24ad4c6068c684feebc15e2791df19521b02cdd59408e59e8a35956d063a295bbb200c448d6371ec41777a80cda9874dd4c74e9dd01dda875a53789f78733852936c33f689be47692b805b8698241fea8c4d00abb14150a212a2b687a4c0ad46a8efc4880a54fbb8480a9f06dd6dbb01cefdabe1e508b1e3b898451225c49819cbce815c42451f83e503784e83d678ab777214661d26a279927acfc9988d2e18fd95d1aee8c573d417ae262a20f2327ca127968489ee581818e493f93903d7c7112af476c1d48f673359deb96288b0642d841f8ae88406b2a2e05b8de44733fe56125e26cdeb9550e2f5089b64a7be809032684304d85c6aa6bd0a19511cac79a0a5d96ce006c0c044f16dff59fc8e19f5cf559f0248d031c0b5e47a499a41fc8ce33b131b78500cb9358ba7b5de3af38955ec3cea2836887ed673732ac16f007d13568d9e9332e75b0913185a6f4ad48d0aa4814b60df013eae193509cd60fa783426785b4255e98d7e928cd8b41e189fd5f2c4bb8cc7b497ec286ebb8f7832274086bdeea8d66990ae9de9cee2b3e0769ff8762ff32796bc96b2fcd41a2f5a49068684fd530bb0a08b428b11c4e3addabdfd5b258a04bfe51eb2336a9f3030ae47714bcac26c20480d97915a705673c46de58ce8783a6a4c38510d6bab4957e434ec350ecc1763710e8be460351c4049bfe876e9a9408515f8347c8e39351f5575e00e13ed4f893925c65064fe260710066dc1bf020f74597a1e2de87648896db04bb969a5a9fcfbaa9b62cf8879bc56c9a30d96ba7950fc940ec9914260291eac414a0d5b8b5176a7ae2efaf7be17f065649ef6823c8a6cd5233515bb4c474d3ec4add7cd42c22870f5537a190a660328b13bd83f93ebc9f379b25c3f743a5cfd557930d45e03f8f426833a85c36cd5e2cd37dbab582d08b8b8f28648310b4b47c084128f4e2f30168b27485813f69798482ceb9e08c2a62511a88cecd8aeecc1b06115b2d1293d609319e511a99ec607fa256a2c9206114075d82b3f10a2ba4c0dbbb24c95a415e986c383b5a608f15494222a8550e5656fd36c2fdc69822469e154bc4a565d5c39a3f3868b89f0cda1172982e1784144651a7439ae32a3ba980def3d86d57452f112484a6c860cfc147de5d2932923792fc19bd464b0ae89021d9b8c9c1b95381e8d2f35c8ec5a53c82c60573f93f64cf51957f029f3d99ff94f7393a1225e482082ea1cfeef3aae9938a23ded96953eee4f3868c33f06ff8813c495158a6b5385c9999e06a9d391ca392bd20e1e88d689a634491a7151956064cd7cee4bf9ecefe6f8f5648ae7cec2278ae76ad6a1492fc222e0077412459d18d6533f9281970cc220b150ca0e6547ac85cdc133296c35e624d114a8f1f44d9ff47905e1164aa6fb54b2827dc9d40b18b84d0b4dd9a56cd6bd0f012f462a9f76e78f16a29840db216d268314088496a4f4890885423c88224d47cccfc7e43a7317a5b2abae7d603bdffe232fbfbfef23c24d6a9143203628537a75123e908011a53239e1942189434342882eaa8165e753cbfee86c63208d7eae1003a2ac323154dd735ac83391fe2aed361bfe591227ce8629cdf2b0722df0b00afe8df8ad7098e31438dd3e7b9a6169302a3e728b62273abb8d202d690f8cb2900d9e59f85588ed4294e1e32e98479f14138be9b61ded19e57ceca597e67735619dc0550e6fef43d2b9354f99ab88c0a6ff93daa29731247a9474b08ac7be663f74b7725fc352a7ed757e8c9d1f867fdc248aa3952eddc547318ed2d6449587ffadd8bb2fa42d7875ddcd3750f120f0cd43e0d6a85472a7504083a310b2f6e9c65af60d66bcb7ab17ab2edacda3a2ed8c405b30c8591845baf43f01ffb10f9f7bd745c3ed8aa7ee140232bdbe48fc4af335413d93e649b14963c532de96c03e1a79dad415ca8907eefcefa7ab15740104b78b538ec5bb2243b7ed26b9889f08e535492d1aaf5aa7b2a90baca078fcb84557a539edf5e54c7141e0312736237c151653897ee481fce1f548e5e580879377abecc18c882697a5775c0e914b55e9f7b9e6f75b46dca64070d75e83a31a83e11b5bef63a0fd59e81b56cc80038ffa18747ce862cc3e532953196d233642f0f296f0574d83b4b4ae39404321df1f47325e84f7444ce86b222dd1da34c1b2a6fe83e48508f58a3f5e14675be470a2deb4db01553c84688bd904b4e74ed59b33f8bfa9ca6c267080286c306720f3c1f3e92288b3faaf171af1701b323e28565e26df74a42301a8be568dc0d0166a47704fd78f6d5eb64b85a0655d6f1cdfed809f56ff91496fe3d19fba1195f1d05d2e15d09af310f5c849c9f4c06c2d42c84c9f0f3f08ee073007bf370b13e1b432f3884e55a254c980b06f0ffc1545414b907c3ba80c1adc2305dc4d13ee8c51c509807630e695a02bac5093d13d69757fb99f8dd7c48ef108d550f6e757c6bf67b28be7f518c1b201334712a85aec3471e08fbca221372186c7945f0561d1a32f6e3d34b5dd4e79f9e9d52607d24b6b0833589c7c2087178b226224642908c4691b3da4efeb56b16c586154e5a1a95ea1958c0da2ad59a77349eafbd1c317e280a43f35eb07186eb86024c31ddcd162e364f373b8cfa0136538fc436149166b8bd504805dd7967840063871072f8f258301e4f3cd6fd3b8c9588fee3fbb91c008d27c536c9cb7052cd26fdf018274452e490d7149446fe9a58ccdf39d49cc2a16756370bda5cd3d9c3e0228c2e17c948dc5f49b3d81f1ffdc159985c45d7debc7970f1a00fb20073ce364333167dcce5f3a8c2ee5a1d7e94e69798d47851a7e5b197c32ad35be097168be7b946fe03d30b3990abf889c101e17055d8c6374809bf16b45a0f7678729dcc5ee905004cfd4d860c9a954d4f20a53a8959f8b3c44866b858e6c5881386b94a53ef33b432ce82955a355ea0b36b329ae2e731ed6cd5f9cd74973fe4bcc76fe94a542d006e0ffc993bf76c49ca199ab855e2c450e9b5a88090645fb5cb5ee130a3e82ff523266ea88267a8249a933f025f010b0780ea7f4bbae8ac62fa6eb94455879b3436674c2a0dc69962c71de2f0e5c742ec903d73d15e312880cd03da7890b7c68c2e6395011c48c70e07fa2193230d3a565f663f18caa574625fe8a7e3a584133e04cfd1dbf49b4a1dfe6666f3348e0172d852f97c66583b1ab8fdf9a38f1297eb0d393ba52bfa0107f7f58a59524acb4cb240f4d3f5c8393946e94e0402e2c4b92593b2fbaa0a427cb56b56d10af30d6f094eed88f727ea13249d0465711664810a60e01a5e7d62a6d7baa0e465e157a7d82f46c650ab85ea5b11242dad7a674e871aaaa0983530700a6356b7fa636404109292e6db063900df1d2d308de276ce8516db2c8602305c587f8f89678127e7f8be4e01f8a1b09217b958d9d6b6035a25bc5579d090d4c62516f0b66f39888909b325b9213c3dd113b917617c5aa81f0d68e47251dbfcc0021bbbb910686861063e9469d3ec11ea5cd27fe82750129a30c2cf74e48e96f3313ba9a95a9374be37a95edaff2c4ba3fb7ebf1022f734f5b5f4830b292a748ca41266e9ab0e90cb4ea4c0fee740bb44b9f27772115cd7398b3e10c52bd8c392ff15f5677ad1ded937d9be5d4118323a9b7549498c585ed84c7979db0d4657235afd23b412754c3f4d1b15c50a7ef978318dd64945db8a194b73115fa7e6df7866954600b279d588b771e0dc68358a03bc5460130211ee2ed69c92f23e9c3e0488e3d11dc52d5ecb23687a8a6cca36e9b3503c1266bf8d42189a2f9c84dc14078544f86873ed86c3c0d31cb233cfa80e6a54ec32399d33fbfb7b9aceb7bf0ddc94bf80556dccd23b423ea33d62e31a429879699de2c61eb4074b3332207653a9a8804329e150890987fe373fd0e01b2de141483fdf1a1e3e11bf0147e7a87fa0df77035fa8eddc524d3a451ea013345a02a055c406ad1a324634cf1486218218bd4b3c4886f49c15a8402e1c1a5a0a2a6f67d46c9ce42317c6f3f1ea7c08b552862a149d9d5917ca64ff13c66e85704fe6de7e07932fe6d4fa6d58c8cfcb00c52b9cea4c73334730420e05001d7e4ccccec47dcb10baf928765d17ab1c4a806a0450cc3b194cd391c739bc4bc0f19782f47f29622cd9f95b2da1e3ad8a0052bf4f0013cc3cb99eb21716007abb27327ac665889f3eb124692c802c64e9f10f293d9c620fe01e4af983183dbd55817d2cdf7ec5137dcc115939b3ccac642f0a0af5b4f41e02e3b4c419196464da4142b1193f057d59d13750742d1436be8053882651abe9d8ba68f3149330c0482e743dcb23972de8644a83d736cc15f99f8da99f2379d8648f2b53c719610178479f0bf0c5829e67e22350d153bd7b1c1e6e6cfb6d4a5b81cf3cf7492ddb9ab11ad0ed3aa8b6adc4bebc7608eb3cb79f4c03cc36012ac6602d546010a9e9e73900081921e3ffa53201989880240a83e913ca1520fcbb611a191018a10010fe6fdb4040a40cde4efc41b22b6db85186bf68179d6e8752f887e4c1741f87a6ea27b4c9a6a5399fe786b69449eeed16bb02ca02c102dd0ac43e19cad8ec2c84c645a1870eec8cf6303a1083ddc09509c1b94a99db9b32aa43dcc5c163508fe958120799fbffeff4ca2036f06dc419fe908233498ef1586fdb9c7327eb3f39feff4f6245b8a66f9c73cd763ceecb0fd5b5edb787ecbd7739aba3c3d721f1e5165f7b1761dd5e03645459708c2d57cf2aafb4caab4b85eb6c39c42cdac004526cb76d9ebbd1db916bf6aecbcd1ecb4fc922b1f42d2746ca21ac24675eb2ca1c12265a615c5e30b9c85b0877a9e33669e306f4ad3fe79c732d65105b9386ea8e3e5c3fb032c8f3b8b2138020dfe8de7bef1fdb6b13291226e53d1d0ad31eaa6a6134e2342c8714bddd73f7ef8099af0861f7250966ed71def1ff0f04bedd649c35d5e8e4e008811e19f16c108ded2022e79c97dd80315039a35fa127e0af8594a69ac95368269479ea64a4db846b7b18690fe31130ba9c467db84c8d21c5cd18584fd410262b7138c46067101b4d3dfa74fe5984907db933173b3e23a611933555935adb1ba92710ca9fe7746d49f853b54adbd8263ef07f7e95438642e9f0b89f1a75e9ff316b650f261f31da023f5051b26f18f2b9245a7174220a7f4abbe4f8ff3f223d92a1fab21225529631a73334556a16553581c26cc6a9c6db24ff7c3be28476816b350ecd7059512602d712ca8aee11699232f46ab8edcbfeff7f97b76ff3f6857ea8e9ffff8f857268f0dcedbd77edd10c62a3754bf557a7627979948bf053b7280cecc54f082a414c35c1b29619bbc48ce51c4b002b4e55071373185106b18d842169dd9887109fa3e98e73ce39a777103a161344554336030dca9345b80c1b9b41b4e3bbc769b6cd8d9919a3222388cbbb13e56524a55d6a614c01258b7049ebc6bcb69b1ebadcccd63a50d57e775d0e216689db1d17a1414e6bbab802d69c680731b187cc14033119003cefd5439785fb769fdc35b757881d4b7bdb7bef3da4b8fd97b97137f4de67310d02325b6606df6e26fea3fedd01e630ff7e02873c85b3c78d7ab8e3bf9b9ae8facf4310bfb6e69dbc8a1d7bef3d3b83d87aef58c994df1dd93b27ebf36df39a0878d487563e549a456840be8d4f9d8c7bef5d0c4a06b18959d1ba11c084a25f51d3a8b037ab41f245d3c422b48d244e5b9a003e4203db09f0d5789dc8c8de7bef50539b29ec889dda2316d39a8fea8b2f9518261d6db530f1ba136bd79d5db862d5f99493e7979f9517740cebf312ad951e108027ab864c926525280684b5074326c191738e3678cc938b050ca5ac284b48d88576672bec2df1ac31383b05ceab08956b35c0aa3e9717469f1d1f4277fca3c6e96a0d4f88905036b1f7843153c29d15e61496d2ecc5d6d50f698b6cc7374c9c150014d90ef3290a9545a521b9ebcb27d3891331c0fd32361ca48c5dde7e78d472d2ba3c5fdf162e3125358e8c50c5330e54a7148eedb26dd8bfd6563612407ceb8170467e323bfc8067189aaaa185c74a5a48cd2cbc20665031a5d4955552bb74768b4c0405f667a1e26114d9126e1b53b42b8a880a4a43c760a6901595d2ba596162c3db2c25b2bbde37c400e7743d8654ddf49a89b819d8ff3fd8f676fbfff898e48a19e09c734e026b7bbbd5b0e09e852d558f5c5be38e57b73adba79427211ca6a5bd92a4ceb30f0aa1f12834b4b17d9a6ca93009e37d9faae8f2d8c3e34c5c63f9ffdf849d416c34ff4de227bb9535d4945c4e665a0cd611ab066b46f70575cce7c016763022e75bade01514ab157a8145b9d07a368f532654aead625b0983f43e80627cc5bf7c414e602b54ca70172b065153ce958a8d828673ce7d7a223e401deeffff6b5aaae685ac71e2fac698923afd7e4968bf1fefa75ad0ddefa00d4c83da04c3d0b07d999e55777d58c27559b39a32b9bc9d325bd93483804ca8c05793a0aaa26b0a9f13c1b59f7d62c48c89183ee215f68584a798cc928f876c660c66a3c8f5128e11c55a124e540821a18bd9114c8f0e2f5cc9434657c60c1c95d763d93a02be110bfdffff0067101b3d74d3c1d351d5e2c805cb128a198322ad52e33e19317572c8af19d3c06d6ed79bae434e96ba5967c7246400516002b14133195e972951c95fa5d810c3ca6ab1120dd93037ceffff9f00630cec598442339a1ad282b1e29712a55a3ed22db794bbdd76cd7228887c6989c27281a9c9f21aac7ad815541c8a028b12db4a9e69950601d9c939e755d9db4dd6729d386bd12a22cedab0b98e30232f2c49eb6afaffff49e862cc831c61053e777c4c3e2ad73e62b0052c33265634dfa9aa0b788aaa50907c952cf78dadd9b19447ca809cf3ad98012e5895d70b48a5528267870b2b48050a74db1c6d59c8ace58e4fb372f8ffffff8767101bdd3fc7c3144096c65664c75c25d4a648b52e1dae947afe79928cdd7fee2c443c837b39feff85353df59afd8fc5b19a92e6cfaa1931deb65c69447befbd932d9f47d6d4e59a20e4162386cb598b73edd4d1da4b3245d4c98385d3a43ed14adc48ede4d39d73cebb5a64109b31a9e3c3a293e89af6be819754ada3699aa6b91c7665629242caa2c1f4fc14457f9e485ecc5c5df5ea55b763d7e8bec606586fcd8aab24d85480d6040a78689d91c6e352e78e6f9aae02acab37f1f725e2909fbdd97bdf39b9a6f73322626e06295f309c911f624b4f4e463b62f74f4b5da5b0fc4b9072369580cda445b5e677e924054544eab055fca8348a385ed99573126f0357dfa49ea41419a813e03e49015123a160c9d9aa2ad1b4914fb34c2e698ea7ab6d04092aedbd07771d00b294183516a592e9c609a8c6d7e3ee9c18410d6b2899dc9ef9a02faf51f6850c3c2bf9008148624316651b77dcf85ebfe69a03ec3af7a8ebad8bec2ebbcd2eb47bd4bd76b174efbd772f052ac239acc63786ea6a4739add8a7c79504388a852899bd840b2410bc4086e9dc1aa893e7e66e6645a2c81ac686507a3e1e27a4ee620015487e6a30365c9dcb9d44d23378dbc07ac789b1c99a39063d535690667f325a4889cb4d1403151dedf8c7e6263439498dbe5fca359907eac66946486d6a0f7d301cca3f1e50b25a572b8b5636e243a3ac820cca6bdc2a3962a5a39b16d5b0e1bffed8311e5f40dc83b33db66ac61cac9f55b59ed2c692552a74f94cf4d0444956783b4c670b6de4703ee122205c3316116efbffd756b14c0e6a29a2652b77756ac051aa649520d9b9f628739e5cd0823c36f416838c802aa55d79aaa1a9b2e2f42b533712925c67dd24199e951df47151194f55c7a0bce22ace39e7f4ae8ac3ce5e7d4111aa85f4ff9fade9ffff3fe1b0d9889f6b2b4e06588ac150dcfcffbfac6914a654890c16d78e782b7cd8852d77d895530f56f14c39c3db405fd6c4950d6d6812819c73ce390f7981d2bb82a8710acda854f185016fc0a4d5625adc9cf00b116aff6485676f4701c21def92531a48e2b2114bef61562e6e0da085227befdc2662d48c6aeafd0049a95c6d4970005391cbd912571a0c6ffb346baccbb319af700827b0693b5098b52523a8519480fd9c91b82d18284e843a69e1133fc3ef0ae32bcd9835b1c3fb2504db199440d8fcff9760f7ffff5ffdffffdf374321e218ca6138b7f49fdb5b7ac300ddd2a19ab24123d20c954bb26030480310ba6d4942a22e69a8d6d5d4241fde7be75b9cc80f392f6531a1d8762ad6dd787a9de687dd12e7a39b7d2f21b8ced68308b7a3b46137e32dd2ffd3ffff5c2adc1c45af9245d48428fc43031bd3dee781856f761b85a1d104b35770dd9cd3f9ffffff08145bd32b33b83ac5a636f4927191c8bc6a5ec8b2524a757550bc78704ec0790538cb0f04c3fca3eef9e63f6e9ea5e49aeebd6efa62e8103b1fc0326b7140b32682c7e683e27c6a1c34cfa917369a345b74578a26bd37450553b44d45dfbdc39c6d337f8a82d83a5539b96f9501760e876d03608e76ddd3c652eff1776fef018d21a8d48f767d3300c403b318080400c44018c9034d11e50314800315b488ac843438303c3c240e06c36040101006080001200008060340814020082687c88a81d9004b7892e68b6ff32ca233a401574e9cbdb25ac87aac7a9c21a03282d12944e83a9fc24a51229be433fce0d89646b189f012a5a2f16c622ced673669784eec24c0b1b6bde025317cf510454dcaaae98b684312a9dd408b9448143ca452b3c0d2f4c66ce153d40b5b1c328c1544349f36478e889c4f550b351d0b1d0506b1a2a0a23b5bf079f7294e80ab1375bff77fead98d6fbbd32785fb34c1c88cb1d7832b8586bced0411dd7c0cca60a1c6e007e8a5a22e5a6326973b47854815fd6a5de5202ffc56c363f431f6ab1ce4895a02312848138f9362e39ccda71b15bee048c3a8130b3c73c5d84656ebec0431ad06dc409fca8aba16e5ce3c68dd0466ff8d747c1c2f243b9b423401a6e5290728d174f7d1a1bebd90a06fe82816f2dd31a5be458573851e407c60da24a33a3921cfd8d621fd7efb74b1fbfb2f6a2f092f0b2229e14831a9d21d242f8b4805b17e2767a9de813c8d1c4910c5692f9fe23a189f24a22a913bd8837d59ba9f8f9b97e5b955bf9c9734442ea94c84a79b9045b8d82da8a0dd2d820905a278f718bf2c3f0a985df55480699d0401a021b34ba93e84f7c06ab3faba66f71835b81cf6b2b30ccb6183712b44998c9f6b4233a114c2cc7acc9d4150d413abf13900808a8ad5b86a946040ad26a9974db9c26500a338fd221a9f1e2243a35ea4a56645642638ce0e4721f55c5e648e3e05289f5844c926364a16dca6ac4b1900e253e5cdb1c854c4dca11bbc85bcc20b82f9bb3a3778714cacbedd8dc8420d747e034b44f60f2a72e61079bf7e1da036530929299839dc8dff3f4f84b572fb991bf5dc2a5b146bdfc4d8523e418256ca1ee5f1862950e6c896a609e2f9a36f31b9448433e0fe43e83a20b709f0d8e37a57de666a4c73a3419a0319e6499ddcd5590c2bfa8bc7ee611046539002dc5ef79911baa20a8e2770fd54897d4413bba0112bba4cf35a652fb31c8594d8f068df5c64bea435cabee2dd01ce1cc825e2a1c1ca1a2bca4073db489e81231fd43fe4449f74fc1974b8806dca4c153541741bc2edaa5081fd46d1a1431950d2011d54cef26693fbac08ecb4d310f14e09f73cbd26adb9f28d5172ddec7614d23cd22da423a8ad1eb1aaa62c21bc1528eff46bb4fd396a3d3f53e70922844c025322d57d3b4a14859812c9651148e2d2b0133df606ee2f3ed7c48046816aef724632035e48f3f25823ff1068664881129da7009641796fe6edc395bb75289c2643ea60e2d501fd66b91198b8b14771e2cd93e5e493c4f8a7fa00299259edaf1c1062a37d234d00d2f5a6164610175eed87d9b5e157b306b8da8badc48f10032805e6970bc654692380a23719e4d2acaebed1fb8c9b0cb236d4a8365ad56072d74ab6baa84183d17455ebe50dbf2e111fab084ddb7968cd8a5a0699070748f4372493366f2b3aeab52aa514c04807fd32cd11294c3e42c43b03640ad413bd0aa6a21bf8a3a6feb2cbe05458a57aae6eaaa26c962aaf62d273122f5a18a2ef8be1988174de4ddf22c6bbe7919ee1a07b3361a4f2c64b22d972659b2d30750de21e2f47870b818a0db48d6b892fb7aa8db9b17019b72ae2f9869558c1ab69f1fa868d44a5c227e4e3a07cd8c191c85f5a264c9c41694f4b36a69ef0264e818c62e5c5ce4bdcc27b2e60e67aff0d17d17649fa2a7af302ac8f15afc9cc14009ee9a649ea5b81e2b8fe2410c8fbd71c03102491ad601e17b02b658e19e1ec11e0a822d1aca9d5d3fdbf94c5bb0e4f92b8132208fbada6b6ace7bb449f1aea33989aece1f28e521df3fd4a44f4595fc34dd82e17f54f27c7b291aa8f82b4bc9fec76db016ce9a6e4869b5a566c900c45953ac70e8b87791e413632cd8762fa5adda1862f78c35c8a3d33936845825454be6a77fafb61a922ac44f0b4eac4333962705fa1932ab3e6929b3659d95c127582d703fe67218d371981cf59b6f162c18ba2be9fe18797081de33e5e9cea3cc7c4f600f9b9710174368fbd3762d3bcf5596c10cf45ffa128887041c16273274a8745bb6fe8a9e6cc44fa70091629e3104ac06a3ea93d52833e358594ee14b4b82ee07d5f4cf963c5bb397c655e132c3ac6c30f792e999962bdc10c684862d560f43eae627b43d9245645a77fd48c98256d0cac7ee83d5e2a2b1d10653763c9f6c82cb807845ceb8bb9d4ac4f5753d2a6ed4111b1bf1dc871403868fc66e13041f2324114e33c8b5913a109b2872ca18a6c17018bbebf6bdf94b3cd73ee83c2427ac3adcedd417bcda125b429465ca2e63b8a81e8f97ec8bd84327768883e1187ff9dfcb55e04c66333407868cd9ced33b215ca31af490eec94634c8e5b8ebdbba5f573fc5fb5727334938cf78850c60a2c3312f7b9a9ddb0cd75c836d077a5b172890ca787a88dbdaee82e60b0c332ae8333df9259ff8819a61990ac8e716f5c2804d814815b7667b8ed87173e77fca0e1748907e272ba3236f21fd1c093ce7b9e351c4054bffc1c90ffbce9a85dd6062af5c75c67cff1a77d9a1db7ccb8aa048463a75c7b89469a4c62cbd82c3c4752d0b1b1826955801c56d2459996982720df1b1d75eb9d267753d23ede4789f04b2b9af258021a1ad2184ca83755186364fdaf9b2ebbcb52d40b4d10608be2327c2a34a6e04e862f7ac2ac6944e9b9e66d42e1564a4d615179f5d04adae7d27760b8cbf23b9b65648e162aa3b76db3cb72f9d9ead24c42dd61763f86f399e5413d4405a2c82c6383e823f1cc4f5f2c9cff3e3c51dec51a9da30adbfe5c19b208d0700ca87b2ec40377493826d42d858e274d3886136e9195636ab26b822e2015ed57c25a791ec35fb66d588ebb6c3df99693065e1e8430929ad402fe22ef6643f1d1890f628d152d7a3e0c655ca6a6e1e28e6adaefe6601e7a373dc2624ed5d9441d7d4a4a6a891dec10177150413c33e21739b4d75458134df60d1c453064988d065dd5fc4fb83cb0f59d3d024f33c01cb50b26980963212aec4a9208b0103e0c6630f81aae9937a8a6dda8a2a18cdb3b04913fa97f0f9358c0719ff577650a563026120629ebc5b679239b8e6bffebd45cea0ff9a0cf7edb56366e5e52eebec1e4e3c3456d4a91bbb617d5fd21f71354b409f9e00a0954249793522e7742f168b73bc0ad4a346eaf573086a56de51369c51f2b090d466d5cc0ad8d40c0487e8743238ed29830e4f30581a863a2e0843d160d04ed0c5fe7d5540879d1ce333a6d509dd9b944d6cad4e4f7557323642287a78a27f621ac3a105f4e8f052743923345f6281e41400a5240b6340a8724e1af63824044501854d62c560d6f842d03c630cebf84633c63f451d8fc3d1c7bb8db5d033c93e2863a22792c800116dc1efa1449d6e952f18a0ccd9c2e62b21dc2c70d03379d00f0cfd64f37eaf765ddec429d031dc5cb0272043a9b9b872f76d8b226028d069520495a64e08aa87a922a86bc299df72e7befe7eb6165217e2d3ff1da59fd13e16005889234a480ba3a83cf241b49a219a308bf7a790100e6a4eb72a41b779aad4699bea290f5e6e4a1f60f270f4feb4c8f54b353b807bc551a99600b28e648c7f41c8167afc60b2bcc99b5337f5f538dea09f239c2a25257a0a9410371bdb522f57d7882e91ee74ad01d6d1d0a13d552c7d111ce38878bd86156c674592d5c14aecf1cc6a99af9064ee5c448a49242fc27047e3ae0998518ea66c6ecb25827f3e3d7befdc64b016c1f1f4488cf1c93515513a78c7cf0c23139cb482da0b9f8ae47cdc188801f031fd857eac932da7dcd7715cbb562493554a7282c711cfc3a6de89994c58ec948222d1d9bfae130f4df8c0ae96509099db8e881aa3489d392fe1578acf5e7d7cebf6f5263d85203fd072a352e8cb2fe8995b56e65598b54eb20d55a25e699f86d0cb3313d04105c54208020ed87e2d8c35240913628f8b206046924def1c11683c69b5ac7203871a9c6602a9da37f7790365cbcf13bb5c583277a23ac39a849bdef6b1b9499842b2d116e8348e38b961d2ed4fb3871cf4292b8a43d3da9df6a6293ab8cb46f24e05f988ea42aff9aa350b27e9b978b04fb173f8a44cef6c1749fb26a3a18e98d27e1c1b798db7926e643dbdd8e31f7e74bb3296e8a435cb81d1a036cca8d04eeb0d62af2426e64543586409037a53888af18f69b50e0d41ae959b9d2f098fcfb5a6502454112890d078baa5d68bb4a8b8227d0f6aa32f6245725380722065413f7318089c8c7f5ca16d0a4dffec0a88b65e203cc72940d2ad5e7c016b6061ee0731e10e34d27cd85e31f4784ffd6450b839fca3cc5a79b1c29ebcb0427655c074a7912d30b153959a311a1ed3f1d71d321d781ba911c865c7fae6427b5e38b0b70204538d439f22476080aa8c0a5c1e4b7e73fa085ccbc639294ec49123e529592d8b291a09022f003f7c85d9185e407ea848fc87501aa13ca4261d832f4052c4f9fe3d9296adc931660964580978fcc17e8c7f492de27c668ec7e9192f11eb47fe239be02a7e185ad48a30254954e0203c39a06028ffae69a0065c8109cb04d90dbf94564917efd4f249c687d37f321bb8e89cf04727c33580ff74c394e6616e7ae9890c918dea8e7c250b2c85ef70d443f24cc630bb4b9061a8fbf2a19cb89911ad099d6ed4555926ed648b5d117592b2246ac6b0833b14840b763b6d2e49ec5641cbd58f6e63de7dbcd55fa49322df99798b66811dbd3f39b80089bdc4f7ed898c120300cd65b098cc361b4a28f8595ed45e88cc0b882b4601848dfca70fa7c7d9249d689a7177b3fe20a00cabe1c2ceef3c2b0261b30d620b79adc79dcfa48866bd521890f83cc1a5a0cb0d4319bdfe854bb12efa800cced284419099dff07840a2e6e584f11c1ffc6220a59bb9dc3e1a2b4ebd9de3e922c2e7147776f1af89929c9a88fdf896fae040063b1f3c6c3e4702e31b32e64b078282084e6ccfce4d904299089c532db8c7740119a459aed7870e9f5f3f2558c8e5c0b80b47838cf848ece8971347e651193a7d446c4b879deedfdf6ec08f25677a304724ae3e3d5c6ff94af6e562bb2dc4eb2ad6e1028d3442d93aaceb4a523061a8751c49f81f06caa1986a78d50039adf280218213d2850bc6f363d21c0cbfb70cd4db61ae90a7ea263e3694ed65b92d977c7355be5f4064c82ce2f42f103aded94785ee716bc3eca69b86ce396f045465bb5783019ef9dd325e18bb61271b0517368ad976953199a9cce42fe5e220761d0046eb2e7f877b9515250ebb8c7d558d929dc3c60ca0fa4d58cc4cbf58d785beb2780c97622b0040d565fea91fb14e70e380740219360c0680779f25a8fc139c298425dc96ebc3336476818252df5a72648f4ca153c40ce2ba749ecb0a2bef726250149327e6439f221b69a32ba1c33b24281c6f4413766da06907243a4df10ec811700aa5fb2bbed239a13557555f9ee168950821658bf84502d1a9c6d7c597b2d510bd35c7a2eb2b2cd19461ee13a176fb133400b4dfc6bb13d4443886c0222081f168048d3e3a3a2fd2da4374bf2c63a550725227c0409ff68451562a289aa812fbc310969460486254d68649c08f40befe4faff6c22c18464ed5d20b84534da15ad70be6c810b6dee0afbedd72ca9589c6c5f1074a3809b6f828f5ee50f5f89a8a14014c44d91b186d097c6f6db83d2884b07ebf6615b60ce4a7da53c2aa173867c3f01fcadb3698db343681b765f58fbd2e7d635270a6431cb893c7fdc01b824c38586090ac14da51ae45548979b92494190604b6a2a60d2ca31985c6c7fe39791a04fae0205ed93582369ba480b9c030ca53fd38e53b02dbd5438cca5b221578f949921a2adf3f0401c4ef34cca520c2925cf1fb52e22e737f426ce5488c4cc4d88671485455d03ddca93e0d947598a29e34af95b1ffa59909ab00819292c4222e2ef84726d815e410a50bfc2af8ec196a026c1012b16397a74498df975c013d956550f45c6d481f311db6140b0173b4b24ad46638f4c381871c7cbaa179b8b161baecc81774a8e726660e57977cf1d9889dae0ee14a772add93c4bf4188c76f88c5c6d0244602831308ccb708dcd177c5064c1e758126dc211484ce6bc7d66464b1c51afbfacb297ec8b4819fa768db583a72c32d678bd5c71fbcf191325fde71ba728c795634695ee646a7a366270d0aece502c23c9fee9b3412487d0b6ad7791a9819a2ce6da9233a20b44919346f7de9a0326a41e2b44ab6b53006b3deaae56db9d5126dd428f42e23f4429c3a17cadc115216761e240b0eb1eaa8200e93e7e8d4aae4e2cb92776c27f07b541b4fb8be97baf4f770e9e28b298ff02540d74aacb5bcbf4310094996e864bd69d919f86c90f9b39a3aac584b3202474846769378b85918b2d3c9b963c75197cfd9c94a4899d2ab54c61b58102c0455d02ae14de2df6a4b16157b3ef040355fc2176f86c2568a96b406696f308e8ac4b81e9d247b3f1d02a5df64dcbae3fbae5c022aac8892290dde1813ab4f74f196ff5f242243690f05d0c09223f03491c0bf391339f695e23981140fb157a4b7a4de2db870e3038f87b8e3da61ce1877c4aad8b52d8b031cd628909eaaca0a575ba97011f8d2e8581b5f626ad5a333da22a3d56c7a4985e7bc4748c548f2c6e70823f617c6400b9329a87df522a1eb71f6a3542e3cb71b233af4d3cf2749702a7ff40d64b21ba55b2850af5a649f67f6df8c93efa433092b421f2cedf4afd141dd21a445ac9ce2244d5e31303b556c1a02e646b0812f0db173ba4824865c695fd67b478c73c0acd5689ec03ac538448b36856e077b848740d72bf8edacb3d73d79fec4839d1998bf656e923ab70088318af0aec1672a5baece9738e830df0f7d8b2294dc7780234916b76992386d8e65e1e8be7314b8f2efde416b322241b59a3bbea4e8ba3da242c7df30aa876a5163029e0f227122723897344b1912e6dd3072c07ed0e624e23cf83f478ff02d81632b1c4ccceec7d05d0dd8d9fd3782cd9c599aaee6664ac4d2b2c9155a5c4280f518e7427b7b9b99e4b1deaab88ff4ea48658ee24f3bea8ec01683ca8e78456901ab1c746fea953cf46e1442b553359d21f97bce1e4de7efe00ab363751c7480ed133c67b43303f8d10e0c744f3758e345ad9e81a7339df68124a9e183242420372e30841d64687745b4934e1df6260a9184d2ebbe2561940da2c08c16cec52024a7937e5372d996a4729095c01f2fc0c02a10328bfbeb2c2150e44fc8bd8f683778704ddcd0481bd5dd33b745b0bea50cd07510483671b2c6a7b1cb2f8d6e201609d4879fc305b7c9bd869fc80b190c7df345c767907e6bc165bbe38473b8cc326d32d0df37172b50dcdff74377cd7d462e8e36b520dd00d9fd7303f3bf398e422318ae80635c98461488b727080cb42376a55270e61285e7cbc1a6e458b9e3bd4198b30f124a939113216c53d7765b298b70563c9de88b37adc6c24f1a186b5f1acde3dc673bd27e644689961226b0c2148a94404b2cf4d9dcd9db2dc26d15273dab6969a16d5acb99b019d56e90b1d3c0f6597cf4c39ee39ac71bb62eada7d56093636bc0a2f4eed30d8d6b5e33f37b93a7ff29fec7c0f66257ab170011f5f4913b5818dcafaa85da21ff1c3e4bc0e9c0282619e662007b26af72dc8faee68b64574fab6b57094d540896b51ce1193adbe85688938a36f56b48b2e49f496481668051e391635981dfdee04c39320262e0e76186783e5e4cd8771cad996a20e2f529fdcc94886820d4397bdf72ec43e28a842472385c0e3ebec541b7a716d3f2d66b760872ec9278814620360ad8211b7c43ea1ca6e480c8e62000d9252667d05e0ca53e3a8e05832025849e193b3194dbca864f66828fac6d182151a40a4cab1a25ae48c327f3795d115c001c3175856ef1260b9c8f7d24927f72ddceca2190b4b055a2c11390bb4ce8a34a91b6e63e364dbe65e6331d810edecba1ce1047cfd3ba5a05f18a7e40ff0296627b64cfddb1550e76857fe675f97e738a0d3cdb27c746c08a8342885c0bcf324126465bab36dd92e8341c091b4c5371e0341a3d98e561e47a4bce390c7130f0bd812687042874551f1593a4604c31d1311c093f19b59c4e7f4a49b010a163652c73492ebc02f30b5969bc3948e9120061d3ee4e69cb3a2e3895f0052820449408019de71f33b9000d2604398859d7db099ce0a8f96d44065af280ee09a0e8a49d9956bef3f49b9b1675cd77611806d655400a3b9f46c0fd75a00efe2f1cf5498067d550a2c88b716e96700f504bf6ed8494317fe28af0daab259e4cf13a30605c8d1dd04b2c1019d8461c4fa537f1d1e5c65d77f30d9be688d11375dd9a552fbf32b51a485248b84e28ad4723488c5ad945be417721d1531294cc4d7cc17de8db8c344f522b7d0fe3cb15ffb9f988a908724a39b35277394355c70ba937bd116e39e89932e352763135b427145a20ab2f0d882a0e5f349c70e99428a5e2c00ba48730c23b08e80404b145e696e41796262c1b3afb05372df764eb110df660c8ad1a3a54f9338eea2aac89c7cfca7a635842c9c7c692be25e0ebf56dbf8df28cd90a4b84a866a183ba5c556c07b4c623a6613b47274866ae12d62023d472dee8158907a47199f1391c1dd7ccff60281ecd88b5e8eb8e8234b2e4cae2c52d2ebdddbfd14bb5293903c63b5541f6c864ba5214b52ba97555980d4430cac5b4c4672a28e8cb0baaaf8766187b0a92b04029df9c076ad25b338e0a80f18a9792f1713b8e81d75e7f85a60faf267837baa2c61a981bcad46dd2f3d85893f57133130089f64c1437e398357a6a01436b74712a2e0843b9af0636a41901b02177045019ebb954fa5bb4848e1ad4db26c15fa84b2de35c454d279ada346aea4dacf10c3809a4d5a1124b09f762e235c6868aa500e2b35f5fe7d4aab3df3ec343907c659a10c22cb743830d9137fde32842102674991424187d59b2eff88d175e4d9d9136e48f5583ea5f0584917e30f4bbaef97b98e5601996589b74e49a687d90acd469a198f136f4b511e79bb292fde23aeb86b98f4cbe404776b5760894c8e61e112d22bbd9c901958306829af23ccba61090509489f9f74fcbd24d5d35b988cd3ffae2663fb7a2d8c8754ba491850fe46432eeac7600b254e93e26591a0217d95c8ab08f923c91e8e1b614fde1cadd45e1fa98fe1e4fcde0a321721ff55ff36556a1ca017a5c67e464bac34f1ad414968f847eda2f793d6d4c8e0a60558a2854acd31d9da0063824210bea28ce0ab7492a86feed13d6f56eca94814c6cac92d1d2ef25422703eb715d9db18ac7d4274906b0fa1d5f96888422118bb78d48a3585857ea51631122620d74290d969040980a42b11a5e75378ca1cbd88b3a71237583a6486488d6791246526638a904cedc548bd90f3f9cdc38be18fa617b5797bd6ad3291f92676f74dc098d39d15b74b823f3ddbe86c9d567ee1b52cdc45d48a9369c2a2eeb933046c30e705c872c3921b11685021aff86fa4ac98b0e8f12e1eea081edc51e6a53c345c9b3e4045c00ea3361ab0058031996935e20ba25627338f69c5cd3438a291e9901a4cc2ff939942fa8fece8d2bdcafdd537cbb5e9250fa85c31b5c0e48bd0fd34d28091d1082e59d89392438910b85e1ceda1c867c5930a48e832abd31c8af87738b1cc55af8df9ee173595d2b69ed76e26ea7c75e528886f6aed2403d86017e6cc023babd01eb30eff338a4e237ad03aba699e400aa9eb55d1411d93f270c2d2070c974e50c8509b398835c74a6235379c3849cc5cbfb89039922847c72c721068d6ce2c9500580a4320d181910912ae0b7a1fa36121ad21359c2101daa37c2552704c6d751430a4432c81e1274c3608672689c4270a4214e175bf05579c84f441749b403b290023511bd8b5640185c594a80d964c3c363c5e5a74507693df5c4f943cd2b928927bc69d65fe76cb94a4dc7b074e024a02330227482cb09f251ccd97a67a5d8ec3bdf756669116d6f1f4f5de7193b064e91967a020ff934926b2a498a8532cae495128792ec2944aa329238aa89e82feffff3fac816c2d18562a1db2520a8a555d13992630ab2ae755960de42d2d06c8c9f2a553e870e038dddf83a4ee0a3d04cd683ab1431842ebe7bde05a931315224a3145d0a1a10371dcc212a1f41b728246e1e69593fc9ab430a5c85db128b312ab45151c17665b28304678b440f4090e0e2fcb4c818409fa21dc2d8ebf3c259ac00805c388a5cb057577af2263d8ddddf3cbe10cf9c6bca6b4cc38a794a823600f1f19e4c1cca0bca9b0aa93ca2554e27f2669dac8eeee4b310cf55b825270ffbd1bdc9029dc9470eba1b8d9f6de9b4ccfcb52845b4ef1d697c6677c1105a84a6103418007aa3da4fbff0fb451666baec0476a802377772b3686bd497724a13856429cfa43c2ee6dc20abf7b3bc0d386c0db7300518c0372de9168b1c22759d86982b030db116b910d4a8e492dc471098308e343c7c61789bd3714442713fa8975181e82fbbd83d9a36ab916e2de7ddc61b519f28dc5d6504c8c3a09c66870879d8c80110fbc344249c8ffff7797d1ad5b181b9886355d0b0b0be3bab300c5cad972a41a4bca3211674509a34a30b2341d81b022fd6000756375aa613a99666d7164adb80015f38157800779672b7b73307bd7d68595151e1a3107e9830fac9f5cb4ec5efb0e62bcd970dd81e94445b3c5b0102f5e9473c0360ff74db8af5eed9012987413d0ffff7fa26c1151a8c153da58105d1ccc882912d5a9b0a7251214cbc6e96d8b55aab923b9e3dc5c360b160444231f4cd010b451e7d4b013c0e24a7125e38461624477edfdea90872ab0d2816de3650124f982ba37fdf86bc528695a9e8cdaf5c94caa7a9dbd58d1bd68ae9d973ad0dd3d1ac35238cf41c1b4bbb751322c8509511f6e8c8ce7ff0350d541c9431ce4645e9525d521d58a7856c6ba3e584be8a815e84300502812e55541f4b2b7935c865821da9c4595e85c04b15c4d477ecf67436f15fdffaf80fa7c667a0db956c2ddb57223500434c0ab6440e6859816cecd8f870f8ccb4c510b1b21ad950374e6d566f35789dea6f28150dd5270e362ca921247edb0e2e1408f5d1d53da55d26a242ba9d391130532f394cd27e7d616d2c48954a2c179d5916039fa32b40a1d9b20905ad5a605e7a7aeadcb59d5c633d3d61494cccaf8d058754b2804dc17cb7f1f559d943b1dca46a3bb09ef53aefaebeeee7145df48dc5188b73bfcb64c33bbca8d0e6d04e8ab1c64081cccf3fcfffffffd5fcab648f46d506aea9639f5fd8640a4c6debf3723b59709a975223ad1fc5ca4285331f86eb062ff7f811a22d587a611c4ed221212934f5f73753bf5a4cb5228ff3a83e8594d8c5e15f3274cc58a4a686af584d664f53339a226bd198f592b7c9c80645ac4489d6ab04d153494c90cfa70f7feff7d1b88c09703dc21cc160d6114dd2697facd7adc1cb3b5edaa92745dabbea8d02702284585372b934caf2861324040c714a314ea14a6aa69d8d11995261b333b9c115df52f0a6ad587788f4bf223d4ed8f5047ce3e563907ea826be5d0eeee2561c8185e0ac394c3268cbfbb7b490d3686d95c76ec882750acaa4e684cc9cc990478c6b51752371ec6f074d99b464472a4158579efed91e2e2e592e3150804eebd7716f98ab4ca91ec12a923e7a510a2bc1ff2d2b743b8f7f0e568aaba06667702b33e1a74a14a6a422d6a50d020a1931c1dad00c114dd8f1816bac4a4c9bcc405fbcd4c4107ecc2dbe1ff5feaf3810dbfd64ef470efbdb77e5e91b668eb483841b7315298855af1fbd5105f4b87f0840f08dcdbd7625f9fc6a4e6294602c9650dcfa8fd3a5aab47b83916bdb968063d561454ea0c1b1c518d27a2f2764098b8a804f554c94dc5103b52d052571acc2e06a87ccdfcfba6ba84eeea1a5e72303b435f36503acaab3717d91d63cb887bd4438be5a87b0b77bf90db600e4acbe6507fd518e2eefe5ad257a4ad5e9f440bfbef83e3bdf7dedea4b69544fa90e584a6f7c9ac3b2789272c1f1dc6e1568da7ffff5fa7353384d22664d7c15a98de4b51cd0b9906cbf1f93cdf78614785cb079298f7964060cb5bf3fffff215699bce6788f446cb6465fcd537bb9796827b67bcd720d01de8127df90de18ce689864dc76a0409475b62331f52ec14f184889515f417480d345b59aa46993d652c025f777726640c67ff8d687d657dae12f8ee0ddcfed36f03758f83ec1270d57e90af938ec6026960d79c59ea8e1667b1b684e9e8fe5a41bea310354d59314069332649a5f2e6c9a84dda53651366c10b76515ca1d4b901d8ffff95a0af481b9556af254ad8dd80317677f7bdb770a76cbc2d3fbbb8f305aa6691160ebaa930ccfe4d1c40eeae3db21f978cfb11eab6e8c179f722d9e2166d04b9fac90c10380c6f11263afeffdaba23328e6d963bc09c24cba8307682e33473cb03b35085a54375c4bca9c91982936c1fdabaf74be67c39d4d5218b2be43a987150a40a81e512a7b4a3b26878ad26a47bb2bea51790d798a18cc40d4c1596aa6204bd9b131c1dae3c2a9d96f31efff7da976072a8a747a716352b981db9f770ef8cdf684407264129fcdcdd4540635844d69da6eb48aa4bce9984e7a537745606b6c774ae8db8160163eb152f7a593774aa33eb893b8b4bd9208d57ca13cb94d3224bbbc624878eeca6655c1a5ea331ddeb34e8ee4077f766166961f796a88203f12b465da6224e7f99834aafc7a55bbe8937e381ee06b9e6feffffb7c39582e6b71ac365174b24c1168570fbec292ac82eca6d4f6fd39430c22c9d00a1ab3c4cdf9138f451dd51dddc16332532d1b702a2c6c2975b6595fb90ee49b44657ad160d6331c7281e4b1c2a5e54622c9541a11b58763d2c2a467366672f86a87ee6fccd29dbd234fc3b958927ae1a5e479de1cab1dcc130e74dcaace1cf2cd2920193be0960925834435e8e109db585782eb86bcb5f100e06774c8f6c497f5dd70d6dd692e77ee68a60610cbbbbbbbb270518b2c21093b1b04b4c057492b7cbb468c8dd9dae18fffeffbf18ccedd43309ffff3f9cf793579477d421d47b19be47c1517777777f3ba38f807a089fbf35a7c206cb523c9b52c731ae1aaf180f78d434b1144dddf900a126cbe335364555d92b827bb366ad30987316f47479008ff24d2eddab6ee3ec58edd370f303c615ec8f044f269bab5499d74b8c96a8c41038450291ec08a31808040d0451248ef348d0391400020eb478bc78302c383c342c200a87816020300c1480c10000000c068383813020440e9556223b03e123c2daa70b1357dea207bfe8115cf0e05991b2004ddef243c08ad2566aa0e788c1f03c23a59aac2edca5a0dc78b97d6331b10a4e8970aab7ed65fc71db12d4ad783a1177eb172f2f3a1e190ec404a9e64dd93443ddb31370aa378502ec08da93a43309ee4e829b753b90d439241ad13ccd7139a4c6fe50796352db5ef47c17f262d26b3ec7f588fbfbf51e869224184b2496a014ef86b5209e3b56e844b1f74b7910ad4f1881d15469959588e43458aa58b3d5a40d3d7557d32767c070f751af6188e7c7505a1f0cd48c1dabad8fe2ab776ea515de522483434491468eca381bccda871885913f280f3cadf518ed0d23d0759197a9b213542b6eede1a8c3b6000d569758c848370bf64812bb5908203149205cfdb95fd98535dd86f18c19d779674397868b8c5aeccd78f6ba70eda73293a95e689430af3b447a0276a9fe124ee6b83f44cee75490fe5f425a194e196a6a580d2d4b654105649481a81f5843b6e656e719b8f018774c50d3476cd5672a0a1bf56b75f3d68867d69f989368f483fa26caaa4189ed9c7396e4070e8568c513b5785ccf0f1c0c14816c9099fbe10bc9767acb0e530b89728f4b2c2270d8078786042bf03a759dfe20fa311a2b6eb001f63ea618e47262f84a75b71cbb471fa8ecd0982bb8452f3c2b90139dfd51bdf0f18e3232c4be073c6a5693f3364a1d332abf5a902d0ba3e070302592c6326c7ac60baa671b169f9db2dac29f60131ca109d58e4ea2013e3b335ecc9acbeb084a938cc5230e33075b9229bd699948cb85c7f4821710868fa1e42d6744dd743e32e9c97f2dcabb4e02f663853045019284c9e160fbae6fad8c8b3e8c97b432ebe34e5652e659ed8f907d4fd623306edb507890245a46acce424cdc8f32bfd768c84ebc23a8e6c692465e69fefd74c170e5ee35f2f8d433a00870ba6ca2818312c604c6824b3e48004cd96b18d1b6a359c8d793559a3829e032a2c59d55e25a8514531c9cf9d69202c682a9d591126f1e5106f80a77fbd9c0fe9c89e5dabeec70e587f2a5e41f90918b92c831d0b22e56675ffecd713ec4a0061d16ed84bd00906e2368b219b2eee5bfa990b8f4f81565122e566811f1d747f3d00c20a6fc2d08786e70c1a71388069453738439f125461db5321bb2216448fc29c9e7fd284956171c3e408b4007a9bb9a4ed9c8084df003c028a9115c1b39ad79411364bd8c053e82db0de4c522491bf9eb6e92f32a8295e7d0cde0d24db5c734c16e6c8e42180ef4da844a72d4ab717fd90f820dfc305349f94a5fd2e7223d303f7ed023fc8f562082c6c3af042b628935add9d3e4b938dd2c11468cc0adc423cbf05b253d6e70f6b1771157785f929e2682873114a1bb6b52e3b810c360026f310b5db744dd3c16367d4015448bfc216db1375bc4e283171d082c90a64664042d5dcd5e442489820c0cce1065771d573e6f135cb23f5ff43f769803285488385edeff25319fce93b4e6b28e78ebc630370079ef10a68e498b236efe1f11843e4e4310b91c16a73b9a7b6d0479fe11eb11b2b420ccadaf5302359542fc6c62cd248bf34c936a0d6ea3c952638b63227f4facb8ef2ebb23fbc5a1158eb5944932992382f0129a9af435459d296f2b484c915956eb8f5497a3f765bbf3c1a64fe97bf93dafab974a82978ac5f0464a14c6dd3e2302fcf4bd79b985172bcfb94d0fc50f05adf5c66cead0127c2c2287e3ee063ae23b36900afffb9b2c46207d2916ef72ded728f6bd68e04f2ace81c518d6f44cbeebe4319840d3724a258fcfd398b056c85a420b617b252eb00bc55525e650aaa7c361ee6729f9cb0b992c096f62916b838ce1c7272c4ac6913aa9d32140cfc4999626f5ce2116c1a4898881619635013afb274d1ea535be1484e60e9648515282960bdee6d648cbac63f6ba05ba8b372e95329f8c5884c6103546528c4f1eb45e62048d1845684c4b7aa0b259c6fc53a619ecc11fe1003d2204a38c79f71e08aecb0c18b886fdc3d4420f02741d6cc7db41475eb5e67aa8dde1444c2301e60d14d7e0c04ca524010a582e9351e416a19315fa79f3c20b71e96a02094989ed832caad3be3382e6b5071a2f344359cdc0e65e6b3ce991407d099d1070dd1b5ad2c755e0a0bcac5a1c18eb5f2af84c5d39959e057c997a4d1a18f490155d55f2a55f793e64c30e1f88842db2d5fb32f3f6fc282d80b405fff9a1428961dbb302c940f774d6f03431f575fc8dfb5876c4840dfb46e4f5627bc3f9b8ee9ff1a06f814d00d1c4ef757850e40519d68e5639022ed609f024059be167b5e909fb978099c7f2613f8883e7a02cd466fbc443dc9ab4fb3bc7982644f6660e960895fc505274f579ad05b8b9107c2a10c6c11ee824aeea0629bd244ffc77bed7367ef435534c5c578923db279d0878be2493f9398839df092123df615ab25d6ac34a3efff966e9ec0e498a0dc71899594f7ab9613d8449ee63120fd38d0b25a7496fa5fa9334b3e418e581150eb0c74c1cdb918b782a04b34cbf9c54bf8866f84f01e9f427ff319c52944b6f3455d8501bdc3cc52cda05cea0255ce2c0c74e4000e4ed402aba001220bf3ae1adbe9d086ff6aa6698441e593789170bfb5990a2116a1a4ec732f7bb89a9f3304c086e4ef70953830870dce8da135fa79121d19e4cb100a601723f0b0e5d88fa5752b5133fed1006440fbb87fea2d33d8403fcd8512a863120dde812edc6eb1afa50fc4e941581a9d9fb323e77557baef5ecb7142a87ad8073c7c23e52240e256389303870ebd9e7a21a2faf44004927b9c898f8d063fa1e14b72b3fd081fd076ace5b665abeb5a0b1df67071f3ba4dd1877ade381015e8570fba5088a99ca75ba85239af944fe27e844608565b81093d41828d448ba2c3d768f85aa2cd31d1b30a26f22884770e47fb2c44067c28c4b6c1be924be2cce91bf6294df2aa7a2c8979969a69b7c8f24347b783dc8bb62a7a1ceaa980b485254506fb6357f3b59eaa6519466b3bd240e0b367ce4eaa0897f7464f9b60c084c6b43b43bb0dd3a190d5a72d95481855784c730ce63ee508344b4395b5759eeec4811a24b05ba535ba6f0b44389f1a93b8d95a6ee87a7fa479aa74e37557d6d60bbcfcc516e003039922ad670d58a9e6d2306c20ac8567f0cf863dd0dcd0981b98658724e72b51e6e21204c6ba91f77dc6b8f30adb4969adef72583dc85aeba0c25546df9e36be311ad5f474300cf3a1426d183f8bdc45662408571747818552c1710bd695f20506c18a312616fb6c7a2b6746fbf52b9b6eaf6199c277c934118e820c8317d0a1ac3d17891b360364ee7a8b4349e80713876ead37276449e9c8e30bbe4c5a8844ab83957e42ca7b9a2290c4d697c61b4be4e8ac47befaba086f6551e371cf2b6bdb02cd267c544e67b9a35bde49d3cdc4208e78e06ce07ce543d31adbf44247b3743269c8ffefb392b40509d768588051474d13803bf907382ca91aae5fe6b55b2960f4b49c820899494e8163fca3fb7531186991c47943a55fdc34c5612f9da7fc3f338c7777dcb503541219c78c9ba3e3fc840205e8447bd1ed10feccd2334d4ab5e901ee5631c24fc7f37264ff92c87239018fb30a47e26f70aeefda49bba9ba951faee6020b65cd297dcbc209dde1e908180279d38d962a4d3382a4d58afef8dc8dcacc597bc7d2227da090a6df5481c5d2d1b01cd9ba4c54647c41254e469a31ebd96f99c1e78296c2f6df4f19951571a070c2dbdd1377f67e863b178cff157cf0e03beefaa4ce04628a515d35bc631e36f54f4a0482cf3f3fa13f905c1f585f2bc4d2a8c37a660e3f3707e389480b456d3759ce253e9708946e44a0ea62a89c9469ad999f1f5cd48feb6be225e73dd4c12c8347e3548a095573bf961f5f3054b6c5818417fb21d337451cab517a20665aa7795d0537d07ec738dc8e97e7ce38af1b3cd7f524af8b2c8a62b2703e2c2a2b562190f368b5d68d4f60780e628496c219f6bbdea6ef71f1125350c4356c70fde225a73817e8e99a10d3d190b6abebeb5068cbcc3682cfdff96416dab13305641c5a0377960ed32a836b1500029c7368a5149e741b5b19683e5798aa0306ecf251a6394d5459d97a3e8601b4580d74c3755e0d3231718a99c6c4c5cab58d1b7bd50765726e0937e6355db47b487aa7076e4994e00c30f94bc33108f03b0e85d619fa6909a18f273f172ec2f22b0eacb50444b4163e629b988fe236a38ea11135a525c3802736dfc24890e68774a80014f7795bde717ca12b07c0d382278f858f64fd384fe652db83a5809004a6b5ecaca0ec85a26143fa3f24ea6af618fce73dfb62dee545ef25bc087c40fb5c337633df50b006b2c91921b8c411e4fd4b6be920f94c6c86ab331271bd6316dee1f8bad07e4c1aab89fa666724191d8611fbe27ba5aadc7398533a8c8e587d20596fca24043222ce4a9b1c68a91164ea433e8c9f690300c7b769935b0310439d67ba44e52e0fa8f15f69861a717ad7c50071762f67db6abe82cc2efb3a9da702609070922d13c309022faf3f2e4e601aeb38c2e34e86f3da2c682646421e167a0f990a27e67c7799c103338457fac27f8eb5171c574ab3d3989c3514b1b885f10c221acb742e7cba15a005432383653675501d4e5c0f05b2b78dc94e06d911d791c3597a4878f1f2466bd36144e5e3188cc3ec3c9570f81a8b962c73e94e6a764ecb0323e4c090e09612de265e9b9e395d86fbc824cb25576f46f444a1033be12e9594cfc76c132a82ec6e98ceb821e611291bb3dd645b367449d29bfa85dee45389881a02efb454e8c9869b0c5ce49512b24ac3f73a6a612104d4193950ca81c46d46553bc043697c59665b185ec23be33e72f1b6820f6e1d895e0289cf2c7771136c122021c51b59ce9431a35c074a23026edff523d82c9bb19c5544e9c77ac13741adc452a5b7b23e0d4b6171faf60ca252b1ecf5d728ffa7e707bc78d4760175fc270b07dd41b88e237a10ca041e299d4879072596f7c3a78e1c12688085e66b93e2d3cc89619c99b28a65a46933d0e62e9fe422b70530a67086bfd4451f6a898212296b666ccecd5500f4106daa05e3e7c1f4ca40dac84c8c5fb65a3116803a651a2b761113e24608411a33e221681464a6b72225aca4876de70cad5f671588a0e32a87b1195c9d9af7cdb5346394616aab76b201e5b33402660ad77a6e00f20392aa46500d12933bcd96df3448b7fec3d08004b231d2ea70ae863340e2140829176564ad2ea98054236e6c8acca6e1500014903b137ccd06e3e8a710fbf9abebb274bc69daac9a39b32faa2ee64e5733bc04df589e286b84bc8d1b87a1274d60e132390080ba37dcb0b8f1f67654b345429d84b136055310a565a2a6af2daab7b4a3bdd6264232a969ccaf63b7b7e2d61c70e166b7acc79fa4c380cc8dd2f97abd212ed20262a849652fc6519493791998cb3941ad710ca8c584279966e508c3dc210ca55e7d052eb07ed9856e49b403a2641708f2b3863565c514a98bb9af7902171c55a405772ee57dbccddc7c22e99cc940f8308a178c055718db6adca7dd24eec6875e42417a4190d914d119555941270da2bd320c1a54c090bb23269396b4af4c2c3183330c5b51469840126444952b7f873532769a116ce7ddda9d47356167235e6834ef76a8a509b5612b951eb98dce0107db6414ac723c383fe8c6d9633afde69af1c639d2c6f257061d92b0f0e820b78e8b70fd01f3b561e3536e776e4abc26ef97690366724996c113a24858aae813a2a130bd44fbebe8f9819dd0c1245c872d682096a4cdb644dbcea80aa29d8586bfd494c7cc6aa0d97c16d681faba15cb5d7c12a7feb82e236fc8ffcb335928cbff6ec9e9170e3a239f95478430fe52fe3bb3d8248b1a74432274f3e667447e9e234ae1e014863c5a21f6cf4e6cace9aff2f36aec04b407b1214943147fe0631a93c58d7329c7f145862eeb663bab852019a4e67979c0aaa63eed49178549c3c21b45c306bc215b000b977255f8a422e1b1e01316a4249bfa844267133f6a2d296285f1f1666c93a45edec20bb76a944516b5785b1543e49083a84570606b258bd36b7f1d1da64fda5a456538d69920c9078775422822898db91a42c7b8aeb0eb9232257871472796ff42cbd10bd25410929841e43a26bb8c6e977c54b6c41c2ce025269c3ed734d6505e1e1761820bb0859f1117d29718216a26d3ead6add9b5bc25024b5f63dfc10baca5ada81598b100343b3caa751a24879216646069b5e742b1692292c3e8de194ca6deccbc1581abe04003d916bae9376d1df6f81757ae077fb11a866fc60b9e80a0f3d6589de3efda9606636f893b39beb0d0e5dd615aef66db70d91ca71c2c219c2886e6838c0c80cdb46d4df12bd481af94a7ec0d3c2294cc80a4778263fde87ce7baac11fc37ae724d6344f7e55148f35c3414654de8e06e80c29ff94eb821177347932ea528bad86f0157c3c1e9fb6e1da16be60425abba56e730bfa2504a62c42001272d80f10e158851c416cc8695121014a71eb6c1313758549da66121071193c9d8431c00929726f82d846ca4e0c4f7608bd39e38e65fb2ff379a36307b7cce32c9e2ec61ab10782e53228ef99f9c520a5b016cff2c0701083455c977b8057557507cd4fd508a077ec0651f5dd527548e2939be298e6233bfb26376c89a96e6f22a8ea659c682347a0c96edc9244a2249a3c341be432346a66f68f93dcc3e3cb8f408780f11d6b8b5e9866ce75770bac55a49f4fbbe6106c76679409f273890655ec021735f93ea7c525b924924470d2a380b0ac35e8b02823271a863f97b38fd1068b6a8cd67e6655c8cfdb4b5e55bc5755c39a482af539c64814363a1b0804e0c77ea50206a3b1ad62960232bec88a22f24e83a116c05f04dd6dc0aaf554980244e92392e9abf9f76620215cd42c8f2430a4879a539f3ca08b7fae4debc3fbe51e5fe9cefb25373e785072b0d86da235cb28e161c2eed08deaea9c7a7576b11d6731113ceab7be9aacc82efaeeb0c0a71b334c8c2360a0cb99b0e4266c7edcc8c361ac529562e89be663820500e3ce64bce23cc3bd425f13b0507759a439631d011d6cc21eceb002c7e148db683e692b90d0651c89ca6fd153836a0604656a8dc0084eb3ac39742d7c121c39b373ab569bcabbcbb2a7511045c8504188e31f1fc20b72090e8e8b73d2afa4f49a2c7118d6650ab6c3b104c5d9b0975c04e1e774e61eba0cff4ca81370e99bba06adc66e81dac3862e66fe4be49282805dc655be0cc71b9f828723bf0c9c656297ad67ffc75084b9c1192e7d086dbbf9eea58f1f513409734909009091c97843223ae655a0b72132c5f7bcd136024a12e1bb8974de4b0160ea4a6f6cf5bd5bbf8f713089cbb082d1041b9d0aa836636938ff239debd63173ffc0d89f6b2520b175456b3a71130c704e6155e00962ef8bcc39c729576120945970ca367056e64595534e0c821d84c5ed7e3bfd26b4d3461b5ebc8cfe7fc3db5e164c0baf26d86eb5fd9b8dcb4d4f25b3b968478f03af5392f801af3723a608762ea7482b09d3a56552beb117c52aaef5b944f6383e5650af8ee68ba0a4f934ba1113c22fecb2769220576e05bffc5131ddc9e854c699eae93eb6208451fdb82713783a72eac079aea6977b035961f3641c07386646f98bfadc789822138beaf44531fdef08ab2a55cf5d03258e0853f7c4c49e260026fb95a41ed4c5a2f85fc7679eb46312132d6aab80b6163e141f6a2b48b319ba83d08aaf8888ff874e87e9691f18760ebf156e403a031a425978603e046d829c12c06b445c6499bec40f0f88c859b334d0db2686230790f8d94bb080f417583e51172a77aee6cc33e2ff002c6d0422e4fdbd62c22a32ff7da4087026154d884dbbceadad2603df4197e74c912921db3f4d90277ab4783ce71108c0671167e5c93eab4be09030802a336db68dd5c26fcb183d157fd8d5c0ed2d14388b8ac2872482ef5ecc7cb36105a1cc645109837d91872b0b8ce364dece481888fd1b7213f702ccbc17e91497e8ae268679ccd640d5b509bf1a030c9128802c66da888b7a46b1708e605591909321386185b2184361a60fea2ed267491289dae241a5216559cd5eba06085b5cb61f684a231bd1bf8ff352892224b93224a104f16fc221e9fb2c2ed5fd9938349bb5a2e929a47f3614033d5a392e331653cb253343c652eca24bf503822ead70e33e6ffcbccbc608dcdca64bdc0d025031959b2cd132cf049d672b2fbef33117522fbd938b482af261f52c5e72ce54f4fbfb2d6b2669ac223109f4bca1c2ba614eab7c080a57635dfc64bab893d1cfc3ac94b7597f1bcae2859f82a8b632b10aea13b787089a1995c635a015d0186cfa10f1369f7a7feed0228a4d208aa23171877d24b77ffb440bfc87995c631b461bcb1f9bc42228c00d0c40fcac7db415cefb58152c20ab941a765eec0302444b526da15121e6ccbf526d64ad5d88af0ea7c299ff98d9139df7371cc1ceda08b6c125c851b494b2aed0d28f8c1ed0a432c1c24d2a60481196eb8fc6df315828fa7bb3089d0359aff30a28012b83c44dc5ade7010a501fe8b3b81b8d079099a71070b594693ae2f8dd6cb41c19a0d1154dbeff1468f22d84e7a55d94528bf6089cfaa447667e3f4e3634ffb45c39a4d54793273b36d4ae76cde828207e3a3677b0b6d68a6cb7d95aefc2ed8d426772d4d96ba346896c343ee4dea8e87d8972d6877bf6c3c08f018eb0bd9b02e729500efb742915aead894974820d0c5d32e3f18fab0846f4f91f9e938a76b0e80621772c6ac849eeb7d0078c932f03f0142256433c1a53d213dba6354f7e749aef9119337ab0bd279d39814fdd2a2505e2a4ddd75955e419132534930ce026fbbf88c25d9bc68f200a45fe7f4c1a314e6d9276574f552badc3164cd8004a4b8aed5f36993f15b3ebe4d12ca36f3c31acb9b6fe1674db82708bf3363400a1d16010e8068f4bd0337dec292d383ff7e481e9e34859bcb144ca6c39c974ba0921061d88312120e125321fe7643740d3e2a1a665e8d461db94a28e1a05e67a6e73424c50102e034d0de3be44d7fc09cf991426a8ff3942e408193f367b63833e15aa98f5ce0aeadf7557d6da4989d42f42260870a3c546aa35346bc4e53b30e0e7187e491fc9288b8df562cdd01e2022f8453e6e5dcbdeb8d0791378f3af4bcc2b7759815e95c4b6fca31733ee7283d6d8202dbc3abd05ab5fa0782f45ec962b0ced590d2822504ecf18f232a36c1d86ae97a46b345f935269dc7671097d4e42e3b145db93ffd2ae132e447c6383f97978a5ca6e13b00f25ae1326fd00ab536215427dc5c5aa4902b80f8512841df5630394543acbadc8ee1547e9261949db0ef008dbb145f442da081518cbceab58fbfbe5ab2281a340bc43657cc42b2947d8940495c86f06a290e3dec6393e41fd0ae6c99f052d4a5df0e4bc8686d419ca198e62e5d9dded41dcf345560a6f0d3f081192683c46d0dbd88e9eea0642136a15757985133286fe988d4435966be4b82b17ee90ff08549b48d815e9dc01f4d4024a023e61594056daa4030568cf1d9112804cf091fa34b5b068932f27d255b900e20fc1b61beb49f6349b1e72e3030f1719bc40d73374cf46a2b9a10cb4f42a523587f6dbe20529d77037d0b25c2dca989da7d14a42b6dc7b4b99529252ca7606ea05b00548d8739e758ffe80aa29de92ed0a698c89998df163308a8db00669a828e5142aa7971646e1a4a8ed88c9223de5782b5b96a8c73cc8eb8a320f6be6f3975c7835d633134199ad0a42f7dc39e79ce3f80e8bd70379b19960a187897da3e1afb012116afd8bc01c1f85091346dae0f2b913d2e353799f91a2b17caef4b060969991cbf6f3f4613999190bbeae2a503aaef05b93add18e13632c343635bded220f086c9633f65b6db9324c42fa104bd863f9f9e99042dbcb1a0601a158864f288639bc335e0df479602a34027b7c007d1a4208a14fa9041f9813ac57d8a48520509803ec7951a638813d3ee450a27ba173e012363c2147609830b6067f1efc49e457ae067f7eb6865461c2d88b64c912cb95fd2b77af41516b3c9865bd4a22365fd6dc1c0636a9aeeb753fe7ee76efd9df8da48ccc2ad4f4f1e554ab9ef1e5b37523a16496d6cd7bd87a30db8a848d750c41f999ef63c26ea8076e0c2616fe6b3ce0f318d4d5e0ac1be219a8a0897443b6c1a12c3e329699e57c35193fcbec65315be1066d440603323e4343ed5b427f96405852938ff4e1e6934563393439380439a564ee6766e6e6414eca5f5e115c47e6265472c18f38ebdfd8f5321adef68d57666666669679999466c7ccfdae2f924c73c91a51359c5dbfbfb9172692edbe42fbbb351a7f0af30c4c586b3de2b325845a89c921ee65eec9d9b11a2159f7e824cb353ef8a4c976d98e3b63bb5db7a43105db31b627db6a6c6c281b528e1cf6da58af570f1b305683b372d21999238a208419e93a0c212925a5b731c1b61f2ca914725221d8f8d7b1cb92a12d5752e3017ff4822b62b7ad9c94bf4c61fc3044fb225483217f422517fc1d762489ed775d32327d71cd431af8ed959152970b3c1a2090063e9c2cf032f8330a755006d431f62deb7ea600dbf840207d2e620979ebb535065c249952a90d391719e363e1df7cd1c1ba6f3ad63548e3e69c57ec2f59498832146a40c7106b858541dddf2aa8b907e4c5e0ac1bc7e0d30bbbf16aa4bfb89e16dc60bbfb4b8c8f0ffd8ef432c8ddff6e1cc6ffb02349acb347dc25d3d72523c3af26c9f4fdb3deab3199fe7b5992cccba010b75fbe7b8ed27e413bbab50025aeeb64167a68597fbf1c7ed61018c284096303bf93aa9fabec49141e004aaf9348f7ac9756f592a87a7faa40b2de52df0644a368ec5e7688e4e6e8f800b65d570c1cc0ea3018d0cdd6a4578234f0bdde9cce6037ff9bea933596667e401bcbb6a181600fd5c8c6f2fc5bb29c597e12fdc6f2b95e230d083241f99b15848eeab52995f8ad7a33fe59ef57157aed2b56891214d65ae65fc109ad1b6676b66be397c1d9ac2337d3cbf0ac2130b075aa5e24b6df75e51fe84bec87261f03ad127834f001016842dd0381dd806617525cc038843cae186840965f26643d8fc2423d8e04194190c1240464ec40869306c6086ad0030e5da000e8084c04fe616e5c8064163b58022125d18bd4fd32064f081fd865441df1857ac26405a74513e10b04ba6289185da4cc408a1fa4502268b2a1620a25784045075f5cc1627012767aa62980785d8ee86e4f810b0971e7e0eeee3b474876bfa1bbfb67ca257ab096c841774b1a3b0d27fb544fbe8c62acbe7d28c2105e125c05a5a57b727777c99e8319d3093de9ee6e1d749964d00117f4044da028610b21aed8210b332c1268e1431155c4a8010f1cc67309bc988e80af0750670aea490320a2602c4480450e4d2fea63c4cea275627abe70a482070731880098285828e14a0aa6a8428c2abc38420a9c0822038c18b8149f254c469c800026d8c1871b489d1bc824ae274c0508312a09a63d11aa557ac240020e54ec7006efe0c99719214f84d982090f3e2461081e42777777379992cf78c2518085055488f0ae544834594118b1db251943287046e8c2c104e0b0e47a620306602295ca9b881d22fc528d485480464ec8bdbb1b0848d324cf1451c830234a16504411ad38c3860376a8006db1224c9428f88b6e17d48472720d35092239f1815edc508c311e0169da45db083176cc8b4af468e131c6b804d234e7eea28c2ecef04204a48b32e10535acb0a87725c61843f0b18c2d95114a10c6155ec0507152f2928326549084162652f0206710f325c618c798f2689a12318c7185c40d325551e76283fe9080255fcc20020ebe5801451548dc2084df20e5d241145caa0ced4c414116f622c618b5e0e91b2d80a04488f9a131ced643131b53254690439fd2d34e069e206f3e3a30c1142e3ce862045660f0138130450f152a50bc6009260083bbe8eeee36e5c7ddfa6fb9f6b384b9f010750a53c0dd554ad9ddddddcdcc2ca8e0e24b4eca7d6551a3a3d1b0161d37be571a00175096936160e73c23265a507e968fc91d59f84f07d6f00ea4812f9989c6037eef3031f10eeff08eb39799783a4c60139684714c2cf3b0c0c7012cbb607987e5bfd0f2cfb4d99a0ff92f3cc0f5f8d962f300f7027c34f069bc6d8ba46750e81ccb206e91341ef0cfb0f0278c02455e06bd4aa0f180a51004715103cbe97e6cec7b1bfbdee5bbaf66d53de52789aad44e5f9aa5aa1481408eef51d6463d16a3ba2e67f6e7cfbd3266ddc8382d118ba23b24d0f932684d7f595153b3ec2e928c9c5eb44193517a932c851acb29ce67d21664993967ceeb5a0011d886e655c4a4d705200da4b982c2e616545151658716e47ca014cc5d45776c010cea8953d5f3673b5ecd649692f2bfc0a3c97618b19961014243948750fb8d26938094f2b9114bbabbbb9b999999a96867b6b18c820a5a37ddddd463eab1bbbbbbbb9b7dfa79faaa557176733777bb47ef89a393005a37efab6639b981221331324602a78e20e865cb7cdd81dc657e05dee3788080f09e09831ed25104e57f172ee1570616949fe51b824b465e3496af8c2714c408f895d1434d22bf6392fda954d3d432ff6669c0764f1b702d73ff80edb6fd1537f744536d8d87747666eb30b8ff7baf36c02db2a822e5373619c20cd658dfdf24ac29d9f42895a6ca31fe0a73315818d668fa270d89d4020df46215108259fe8a6368e951bed611927236a0b6c53514b2ceb9243ad625d1c1ba2349ba61f2b1d77b4d497b2027bd177d19b45e1d989927a86b0560ae81ed7572521622e3ba785eccdfdddd8cd9d0b17de26e4b085bc76c78b15e25925fd6cebae1fee9b9716666253d96954cb1fc38467e05bc9a2290063e84b09a3efc210d8482ca592403b086b690a4246a88662539344464d402dab648a0e6e9e2121e6666ee2e979c94b95dc9c21c9b99f95f6466666666eeeeee1e4034cf10f1780750b316099778d690185f3eeb86618396eb0d4e369f16b3924d8e03814a797d562ad9d8c4d0a84104d65cb5068944a3d6699ae2bb295ee923b75c45afc99033d9cccc8e1df2e9f3d1333baecc643bb067fdc0420d4833d90e49faa26a336fbeeabdf71e5f231710d8d527ebdae533e9c8f6c8de8c0527575f72527e97e51e2a08d9bae7b70485dfd57e41a17b10c710f8fc5c711872a9d7c8b7fbec7bf79a1b7f63b225ad2227e9e272c94999a77d11543ca79224acc727ec254df2c7c6b885c618493fb329026b622ab5b119954aa22cb3fe27895451da2e10ebefd3594360b01e9b93ee5dc6cf7cdbfa63f7039627bd7e444f8e28c28fe5ca135f0b61f6bc2bf51a7940de3cd63d087aac03c194f75a07db6f5e2f83eeeaaf91cf95f480b8e0d745620de5d1c06f9e2d949ba75db1b779ba5818bf79b8799aa7791e94c805d56407eafe524d2c8ccd33e9f580200e39ecf0039a3d4c989ef925ac8939fdc48449ec590d8831c44a8234f04b2260399d5bc2ef71b1a143f90871292a289f1faa098a8ad20e1d289fb6c51338503e3674d8411dc9133edd01114803ab499660f35b82128132ba642ff2b6959e2aa258ffdb562cfc16ba7b2c33618509cbcd3d961a1202c7e96fb4f1afdbf8b76d7c6e3fac8fb0fda01fdfb51fa38fffda0fd1c718b111e61a8f7e11f61a8f7e0be3c6a37f6215d64fb96d1e37daf6ee697b8a1c3311ca6c322a5ebfeeb7d9d125cb2c8e218c836348bf3f89ab8c652fa46cd079bbf742dd7b6deeb9da2fa8fbc6ae9fab39611c176666666666e6eed6c14333932c123a87b534b611093b07a2e7709368894634a6923ee6d3e8041543ebfd6c546f26a256bd3693086c94d60bc4fa4ff54a29296dad46fe636f45ac4becbe7b741e39bfc192c62dca89aae60c364dccd07eda4ffb693fed676a3169636943030a144e6c96b013efab9110ef1be4aecd61ef9bfdf75c85ce3da123bb27aa9a16911cf767c9cccccc369679d0cc3a15104f25192bdd0d05b74c172e9ab9bb703c724a495b9776c5892b5d2ea08b74e58ae361d2584eca2d45c78e9cecdd3d432e27aa02b2e30839bbbbbb7bd03b5098411939d8c134702cde9c67440cf0bbbb1b7ab7373fb8850ff898beecb90af9212491de7bd2be27851f14ede57c159bfd5776a52f931632cb4983b8eff9bbce775c2f08216ce6e607c1cc18089c80e7ddc7fa167e3ff7f365d773f5a2ee65ab91ef9abdd31a32b2ee1f5b3771c224d620bd5cbd976d35852ce89312c257711e08f7c386d1debcb96e6fefcb6e09de5cab934ec7f14aa3c705287197394cd5a463f362db7cc89faefb5da52f6bcd820de89d9649a4bf72a075bf8037065565c0c25613bf2bc571ad71bb7fecc57b8637ec5858df37ec5666e66feb86ffb9f658c44a1c063123ed8b755b6efcedee97b5fbc2b5756f491b540512009e475600eb10605dbdfdd44b4cbed72f3ffe9d9e7ac9f21f0eeb5af3d13f6192e3bfcad175cd62dbbbf2b2f6a31dfafe0109c16facb91eef7141ed75df5ef6d8ba7f38eef9658f051b482c66acfc4a3e1faede29b68ae34ca8acee63956fdd7beec9971969571e0d84b21999cba6bbbb999979c70f3a2bc306d6888890d223e0c2c420aa2d349a36401069e3a8bd5dbeb6f24bda3bebf83d57f80e0a61f82369ccf78db6dd76dbf90d473f44dfffda0febfb49fdc48b4cb167ddb08bfc2dffe95ff95393bf8ccc0169bd73b4f5b80a33337337172ce7735e989999594eba855e2c67bbf023c4cccc2c677777fba0594ea0eeee66660e02cbf90333f3b39c4098b4b1e4e25c73ce39d78d3b4adadc84107657503d2c5bc7f2573aa450156c8f9df3760f43587eeef125ad63450f16d2252bd8aeecd378c04701073a84bdb459078b1721d0a17a9ea0735eb2d136311bdf1d9b59904824ac02d8a4971bc16c87608809cc7205426376f7be5d1521f81bbfbffbe68fcddf6c377333d7799164dce342ce6454352d51cf8a12593f64006828034343436644eae48ff8fedc7c341f7356b16478363e63d637563db46ea6af22864306db53e34159f5da609b8d3df1062cbf831f68d7b6b96ad79e487a4f2c5e56a0a308dadfdddd73c4c5f4d95872bf32da097e7a3d7ed7ddd33e53a1f40494e5642c26aa9a33b890849cf4875e2ca70b3582b404c18515382092c452aa2845275a2a954a2ca70332c33d3ec2ec830a6335c43f32f9e4ee2e7bbc24ef07a1eeee6666662f8de5135353dddddd56b25053777777b793d2df795b49810c000f94257377773777773777777777b733bbbbb396eeaede91b9c1781302c3c02b90cccc3cdf647e5f2cf3401a58e10f6cc205f248c84372c8635fd0b31a0063a0ea1b8234f07958417a609a68897243132adddddd72522ef4623979c71035d498999959ce2d266d2cbb2483c81200b6df7bedc7f434c618e5aca8f67732b09dfe5943a46dd9eecd4c03283dae59c80959fe796d31e92564619003e3c0f8c0304ea8fb0b8360100c82611c98492f27c4503881e284dae705ddefb9bbbbfb1d49c28dbb4652a1a44703ff7a01cbd956d89b64794563497a6198999999bbbbbbbbab682f424d46395136fe2cbbbbb334960ce6e57b4b24b38a32c6e891a3fb835154cdb9eeeeeeeeeeeeeeee66669f6eddc8772dad85bd230b7a7a8f11632dd424a5fc67b5c6839da5fb3f2b880ee912daa047961e59584ee61f2b1cc85d26874f3098e11231b22381ce9004ddcc3cfb5d4bf3d0dddddd2d279d825e2c2763e00054a094040066099631b3edee9eeda0a2da5dbac7ae0c952099a9ffd1f797a474d9484622f6b6b0d6deedae243e4602ca14ef4142e66ff0619f192b58cee746504103586fc13a8d75cc7a0ad663ac4fad86481614fe45f5d21a55bd998d9fea2d9df05ceb093636366a6b34b7d468b562a726e4cb6870fcd49ba618fb45d9ac581f0935c10403cd8a8ef5bc898a7d6666878c5389bba710f128ad1f2496d580480472a006ca66b21d4a30bb5fb91c78afcdc7002dd0448abd4dbbe2840dacf12ab2e8a415a5a8dba902793db248a005fd19cf72f23811eeef9d75436af759abda45acbba95eb6cdde39bab99211e444b53b3333cf04f10c8442b66099c63256cda9d5d01f4e849c5a0f7ba985d6eb0c8d077c1f415017d3b713e8bb6ae37abdceb28288bc7d047a3eac1ba7ac9b5855a3776cf41426820f637c20298afa988592188ef54968707c29df291a35a216f702f54e23cab7e255a3de67adbf2290f577ce558b72f2ad778f42944f551cd6c31fb9bf3ba4dc7aa1112802595690eb7d5ed07ff4707455b152315e237f389ae412d96e2dac59e9eed05d0992183f66f18fb18bbd23d127b1d0521f7f9e8fd1c38f593c6eb1771481bc277a1781461fb58ca818eb8d4076f4145571fc451f5b14b6ff4eed478d8ff51a19895e747346ee6f89461fb3b81efe6e05113df523cc9df03530fa2860369e06367a91086bf187a3702ce61d8da930ca7af735c6596ec8f431e6632a0ef9a377e70327b63f6a712f60d60b1dbdff84d68d5ef4d787ecfc1ed5eb78b2a3bfce07b69f62b2f118fd09588334231ba2a825be55a316d7e3276a8111889ab066a35bd9013b7d0567d4028d5c230dc8883f252bcef4f1a9970c881456e5cb7cc84e1fb1698a51cbe3a1cfc61730f66dc332441096882fb6641b16228eb0433cb102b00d4b14285decb439fec732145b00dbb04c09c3629992c556d6fd8ee5aa3d1fd4a2be7d35e1cff97ac9137a4f64d150596759416e3c7c9e9a9d7476a675f37ea07533d522d0468dcfaa0abbf1a4136c7c8d8f79eee1f4ac03a70702a79c87e18c2699afa68975a6af1e94a97e7a20efb91c5fd5fbece87354de81f0afab1527fee8497fe5097fa90d068cea745fc5317a5804d2f4f70a9fc23f0ad88b70fc45830142dcbf770f7faa1e08b45ee8f40effc6b482e4f857e5805f4485bfd2e2f8f66a7060f5bffe0af5cab7029ca8a9e6f8a934bdcfb1820a5584424d41fec4b623b7a3db01f7defbaa55eda6c94dcf3a4c0cc55eff9c8773e393d8875d685da5f37ce8e05e700f2f3fb1d727208f2d1aeeb337deedd80b9fadfe4e53bdbc63bdc6e47eaa38ef6ffc346b4c35268710362137fedd9c86d875f606db88bd77160d6ddf8f6ee8e07ab88f56901b5fbd63ef65b0f90e73eb6f60cde2c0ee63cdeabcac3f857a25a95e8942bdf4847aa9a85e928d7a4957bd5fa3de2ca6de8cd24855d439e762c5a17e7a473d6d817be1ba7bf08dde1b559ceae34fef5f41e71cf5137d87d18a437efcfafd45604dad7d5b1000fe7efd4b62e12f9df9ae4ee767aa6c166a83b53638bdb375d5c76abdd0eb3f3f5a41dce354a3778b8669dd3b9deadbd53baa42d6bfabca5f875be05e68767ef30ec6cd4e58bb95b70396fa8ae7344d0ca86ae51e7ca2fb014bfd845154956c25e6b805ae8777c5713c2a3c15a218c1c57bfd9e115b8c08c288277600b661a1f2e5bdf7a2f7a27ed17bd11375fc07ada82d1994587b5bbdeca2f62217895cd45ee4a2f6221cb6ee0efda1a81e81f3afe8db379148d43deb15bdc8fafe9bd376f48ee32fbd8657d2a5fb5f3ebd1c5551a53c06a358836d67bd4aa86b8a9e8401123e3600b6614142075b8ddaf3317dc5cc38d71f7e12f667aef8ab23d05e675dd47fe18e7df2813ce8e4a7afaaf9b1aa6255dde92786437db30ebbd0c6b72e5b37fd8c3f2f7c62eff439efa6aa47a0ad6e128b339ffa2bed1dbdcb69e76abc73f5beea6f4ebbbfb01a188534ee69383789eecb71b4e63c5b517f4735e7d9e85e54af55739e9d554eff9ec2a013d763aab15e776f93b092d18b3b5482a8f4d86ac44060c3dee73ceb2a874d51c266b66199a203151eabc3362c4580b155bbb46129e28b25806d588a9862ab56f1bcae5e254892bcef0b02ebbe6b831662384790d8fe661b76211421d0f2bb23d0769b6acebb70c75a51fe55effcea658cf16b60edaaf16d6014d244d15b396ff4570dac411a1a58830d62ed65a36ad587592f74d6fe5751ef4160c5a1ea757d73daba7f93fc9bf31e17d6897b21561cf7fefd5eeba4615aaed73dacd089ebf1ea95a4958c9efb5041eed2e213db2fad2c68b316161487bfeda5d33a713da2cb9f813bf6e63c1ba47980362c5280480d8b941febec834e5c8f7e67c50a75b027c4962b7402ed0c2a1ced71c8e0acab479c75f6d991d5ea03aa3673a96b3f468dc77b3743d59a8ff70c5f90aab51af85a6bef5e92e726f0de7b0f42c8950ae62e0d039d73a8146d5aa872a788060000080083160000180808844282f19024a931e37d14000d6a8a465c4830140c23922409521845318c32c6104000208610631052101d07f36a525cda76f6833a87e4ff3e405b5ca6ff8147162a2ae847b235868e6c6b3c1e80bd0d9551084c2dfc1cadb00faa9cbc93a82e8d640c66d260e544d97e88ba32fee1282b491ed31a7046de09a098fa83c3d12b752b570acdced491e333bba026762e6b2d7cc199d0f835432041aab2dddb6363fa72796451bdebb1a5b6dd99421f5c81c9636cb3b2ef44df5ca0652487ff57872bcdae7df5cdebf645e8e456c4bde46234b1e3098df2a7b80b88b5013bd1e1de6c4e50ec8b913c809b53d2ce29be28072133f8d08c4f9381335253108b05f15a8ce01b5c53210b41334c2be26b4e194f268c7694b1b04e986496e801b1a53d705ed47eda370ee10c71a7fe1234089ea5c849768a1fed418288c2f352a4bd4c52710b2b97625d8195b0732fd8dbb166f82a700867f721b89b14d988d9c5c5c5a07a15abffe51b5153ff64fd98f5183e04bfdf77ac527b3497e25ec2eaff51f851c07f52f42124e4546358f5f2fb62aca0133a0028ce3cebd5f063b21d5b9377d62ea89f1d8a01a5e8b66cf205fb605cf4323b3247a157d3eeff2b698bb8f7da9fd1748d56ee0d435042eb1089e57f57030d9ed5d86551c1b2e1dd7bc1d3cc5966748f4d4cfe51fcb078adae8b757d0d8c5a32a547454467a1b45443bb7216172eceb8645e7d6f7d51c438553cc978cc33b6468a5240e9fb55cee34a6153e8c689eed18ecff4298cbc7073644fc32febb0fbdeafa4cf9883b5c1d4c01022561aefab1057dce53a1b69d97d8393e86a48e6fc444562a4deb8e14ddb078f08964e5ffd37629c75c25dd98838d50f075ab48cf2bcfcb5e5cc7380e0d818f132b1471fff63b8c86373cf3a74851801d82c0f2f8a9bb7268d18b5645861edf1425a3758b934bbc483ed352c89fff1426f117be779b1c8cd30e863912b36b0ee17ca5d483198eca501289f0438649ca5a12431aed0a1e8abc1a4c72b997c2b3cb2ef7336459568d36d77c7fd8036713dbcaddd545657c227b23730011fc3c5b2d8e094fbf3931b086aca6901670218a0884968dcf3fd3d70bf4e6a481de3a57cd411ba3b08693f42f169a2104da1a807e1714aadfe6f295c9adbb118a7fbd294f7d0de8fb6d771af8e04753dd1d5f375539a41ec4d0729044912f432caab7a5ee893024806b72dd43bd7e14b40aebc2b1906d2e0e14ee06a6156690062be4733c6ef525e632f8030435f2b0a49bc91e46a8100448a180a3166a708d664f5b0a6e824b2c351e5d8e70f07ff9e0fcb9667d41647d92bf3d528eabc4ef69b80a1b855bfa367fb765e50985d29d6a9f640c50a7e3b0d503c9aacbeac4e17cc85c5659821ccdafd12de63abf43397b70dfce2595f1dec2854a1ff1651ecf8bada494025434ac41922ea61584c37d134951cc715f96b56b8f8693abb8976080701043ba38f5a1094ea8b9771b1b9bc0496db7d6fdb16464bfbba1c80c6ad1db4e263d6a8d60c6fe1169a3dd716df6654ab6c194315148984b25f9358211c9676ec116f873d0a2c153502dc2a162d1e0f0482a796db49ef52d8069d6970a1b543c9bcf8cbf90dc20b6a3f3307a98ed7058a1e9ac1820be1821171e0c6fcd0772362aa8a8276f9d6b3da1901bb9328918202511b8fd59f51a7b6a7f38bc6b02fa3c69c3a8fea3eef508c7a5eb86e343a4c463d9042eaaccc493a872648bc18ec398e5614ad811f0db7e87cb574548787b29c6743045900694e24c117884bfa6fddd5de2e0378fa7d88d028a87be7e228ecf6b2a39aa5c12e911020589db15f8be64db95b71bf0c4756775b239b787ecba9a8371518442569b505e63227f5db5eb0cd2916573ddcd7de0afd6902ad3ae8aad4dc33350eca218be0a4a30bed231e88011a2c3e0f35c53276818983c688d2a8ba498f3c1d11b93a237ff16d955edc002526428031d2f689c4e22cb8533c929dbeee9f5b88101c6331f2cb986b24ced3444dc88a24677661af615482a63d6917951b1c08c0ac9120fa09b32e161ba8eaed15c7e3d4b3521b02476805a23df89bb8b703cf47f0e5d0a8a417f76c41191ec6f8a340a2e4df51084aebe051df8d9d4bb5f44e2eb3518e7c2030ede6c2ecc3a0da05eb38b467f22d1f9b381a237c37243b7b1dc0759f317588e823e994e5151a7c0768fbe8870ff0ba8e0fe6961ddbaf1f118332fb5a9de6e5671f87c24cc1bc73dacbc0bab5b6a1dc2bda45759de22e5d10cd6fa78e2ded304e2a288387ed3b51c95178cc0a06fde85150036640200007c581cfcc9eb68f704155bfc832a3b462e94076370f2799d75a8c917700194dc5b184644aa8f091c417e7d0771758b685621f7e516596840e8b836e8453e8f8c376d660c0bdd0d2706085750a2229e966b3f36ea71afe0f6eaf2b50a6564b9397e4cd32a8ded66d89a17b9e601fe43568b1faee63f128281c49c6b3caaaab67b276173d058e578ccbfb3384b9597123aeea4592d85e3fb83b7d5b54f614a89d279fbeee00ab515c144b08e29337cf51f3e275641363bb1c4738919945332bfaf2ed61a03186876713f02ada1df41d798ab793bd2541b52d41a009862b53767ead53e6eee18535c65d01d1422f6509a599a72ac7ed80c94dbbd73930859e187aa9c1a4403a338064758b76241388eb7619c352fa0ce999c0d62db27fe2961c306c1422f17eaf7166e91355e2aab9e68fe25d04bfc9591db373fc12e55ed99dbd6c433dc7c170db92f65c8ed2c540438f26b6a77b7f7a049b63366d78af1bff0f418f1105bdae699ae84c2254af9d81671595f23bf62a54eff2b40075df837807c8f428705332427c5cad915d60e03c1b9f0d57f6a5ade305add67c02116bcc39be75e09fa0a8fdee7a050901c1bdc18b5c188236a3fad2656926754e89ae2d4077f54faadd29b25eca800052d284a8b314e652c4fb0fc130c7c8c8603edc9d5790aceb3f64ccab86772401a019b7de4524e654aa8289d77a9faa0e2a0873b4d1bb6d4bb2b152b6e963f24e0700fa62743fcda5a5742ec6407ec4614a292bce57b02a4608ecb483ec38d243d99e095872297af9e19a9046da6ef416c6d4ce7ab494e18eec3b8f9360e1bd4062a343dfda09445323dd4cea18b92f462b38fb3f039b8a6494e040c83cbf6229be1d58148c641ae960f18969dfa0dd463e8f44716af7642d7d72b1f3423aee8faeb671e61d49e57c084e3035b3ecb05be6077cd748b4eb0273c0b04140d10ee120ea5ee235f21c01f84b89a1a18baead5d875f149d70484f01257dc522cc7172d185341dc5205c9150efd1154f529166b8a2b5363a8ee430cf8bc509116a26d0a1171d157488e6d58a43e3101a948f37469414839154473bd45c251b1e7f6b7b64534aa41f34a01d11e36f7c9531a11445511cb41481ab85bd6e9ca83cd0aeb5502aa2ca0c80b4adc38a4ebff4d33d827824b84a58c606f62dd38aeee14bf1f452449a6e3d8ef3f321f141af4c26332964d95daa64d2c82ca8ff919aae5527ab394ddfbd455806614a91c37727f0f35a34880d8e0c11c54a6e72bdfb68b975fe241cc40a704c4dfbe11784d0812837666a8fcca22e63e9068e9034f7651a7fcbac79782e3ed79ac6e0715e4fbc1dbc67e81c94e6522692dfedbd3dd3ba712e5aa7501957891354df1bb7a045ec0463dccc23f8086bf46b08f12fe18b9b5b042b2989bf4a37e5c73a25ff4e59e91a66a665573506196329ae472bc9cc032dcb2eaab4d1994a8308520c535fcd2a345285bb25c184fc6aed6824b1a0bee446b92ad25f44c055c38f74e486c32f83bca7c809710575fd882517cf70c09c9ff99b017e50a2670c84e068fda2b5bb93e89875a53411e2254d940d074ee1ea507cd6ec02fc0e073bbaa4fc32f4e8eb25bd5bf394b671d8aa74094c505e686bbfaf9bd0f13ccaffd1c1e7c8cb08ebcdde8663882675c9a9c2434b48fe43914c702f800ae8cb50fe13f107ec9901bb23b3182e8842fda6b972b8ae095e89bec34b68d7a0588a98e26f2b2cbd536449e9af0debec463133e1f1f90d800758a32618a339b081bf973ec0e908aaa2633ec07092d9baf9875fcd019aaf7052e79ae491d25ad053dc1a959ba65e2b928d30e5c6207d0cfd496eb76297a6b216d4980d119d6ce31306015006521ba7a108b068811db4c1de0f1bee778780a3b80a270e8e28cfdf2c8c827ff9a2b6f52b9ebab5a8be4af5c45460da3cba7e25002123cfb522631a8dc828b39790f0019d7169d90a1cf1caa7b853a0e880337172bb00598977e1a13180e7f418336b5cb7eae541e8cf1b7540d7686139a439793c57400703fa3fb3238bd7302b6e4b52d55e3f0416edc6faa116f2beb75d17aa7e694fdeddbd7e3c16ea6385f50d08894783faae27826e84e076e43c858d8643740dab7f70f00bbd608d8aae40121e81e34840f40067a244b4d2712848d039275771790f17fb2330e80522c1a1ab40ee43762c4c2ba387da1ea2146dcfe5e091902af75988bc1907596c8b59363b848cbd999f7ffc7a7d98bdb46e87d54467c6615f1078e4a2b78a151c420d727c7e6579c2fecfd9990e04c106c60dac3cfde03a27036d0d1858715fc6ea581c75c53ed7105d4a6ff260d88f21a03b4a9ed3361549ec19d0cccb93e87a04ad0fb188a35b3ba25d8b700b4861a6af32f6f7bf2015d5fdb506eb9484aef16f08a1f3bc881ed03122968fa130dc73ac4fd123457307e84c94346c5c6e18947c14924a1a6e5ef303bfee0634445e08d90acb6de5e5f5412284f568653e46fad9449c64fcd295a166fbda95d7eb408653ae6ee44b1ade89a0279bbef752eb7fd47d2568a19c2ebdeaf4c0fa8f6b76edbee727df7818a4a743a7649d8ffb7b9fa33fd3de70499c9da35250315bac60c9a298e76069b9c2e928b2d875e6122400323df30533f432077ce8db4e502b560c1e46b36a7604a180817918294a9c7515915326a77be53932edeedb8157cf08b53b60c5f8d27701e6fa53eb3d98e4c17640db818d0606e5a2725a7f56b19428151f6c9a51b8531e9088f38329973c6e6dc3a8115ea8860ce2e6523403e6335985de31dfc63957c57743372f0de9826906f1c94dbc3d9642d8e06cecebc6436622a50fdb5bde07c00025f03b98f00aaa16e8f153839caced58e9a28bdb6271cbe0c2ae33454b7992c8ac11f88bb91959077d6f3bfa863fcbe86ca6467585024322802b461aa671adc8e159f88c0d622b12a40a0c2d540abb620e7dc5fd8b11405af21ae7d065d1ae8f8f7ac64d9d3bc28a96174d34db59709d6f17b260d0e0a0ea2259cb9a8f91f396caefaaa1c12337b30a66c7b30fdacde1a3e2f859e2c452b8e860935a2da7bebd0323074ffda3a0a28a270e760d9312a0a0e6e19bef5681ae3cec3d24e33641896e08283e6eb707d2bd33f128cefd6730020cc68f9e47b405f2a282df012bd10fcbc67066d5ec9076d9b507371f63f52395cc6577c4cfeeac4c8adddfcb6c10bffa85989a2de370c9ecf2f8a1228d750da8fd45b1666c0311ec948245154b5185d6e8d8f18c68cbecaec76613e670db01854518e7476f1505cd128d5b44d811c5613a80c16ad1af20fdb098e94466b47e414f0fa7d486a7d183cc49b53e66e9a06dc7d2098ab08506626a19c027f076fe4cf5bab14556b56011ff18ffbf0489cae60323a49ae2ff2a4a5672f2f2c04d72e7a45ec30fc9523cbac4e57459668e870f9a91d0c3e6fced15f5e9dcd843a4d32cf0790497df230c05ff39b1ffe8662cdd9376644d3a18c272c13682d06af5b4e6922b9e97fe16a39efd120fc285da3602a7cc2d4cad7e186c829ad945452c859b9940a805fd6d63d8e592508e35c14a55f3dc10fd44659488f972ba50ca4d4fd99a1b55bff427c8c9fdc8c805f9048b15fe79c79054e54de102f1808a8e0c2139ac649b38505acecb79903d1b327573d2ec021f1f7c4e78c4dd8174315e9a8d00ef90ce45a8b014a5899a782b7be3857f07cd7fb6994a3987c0d452fb63a3d42b71dfbbbebbe394b90dd8ddba65c3f0b00a2ae8ab4a9ede564f69ee85c300e68b92d3313d5af261be446292850446af2ad9f2418ffb6ba3a268fccb564efec9bf416b74d0f49a42a355b200567bb0e7af7b0341a888813fd30a44d183a7b5afb869652de574777a52147fe3254592f4b5424f9015992612ab933a447964a71a897c1677a0d5c030d10481b210ddf1f5790f88fdea3fe1b1c964d8642d90ac67ffd613075b0511bfa65ad0ac8572578e706aab1d0a85802de6f2bd181d55d91abeaa54e6009f1129f2123f530111ebc4f0cfee23bc5d1e9b85ca335a024687db174893d47a3ab5cbc63ba63de460983b0c72a09e937d8603ec2034827caeb01ada8bf68e0fb7552b5c1f4966fba2c4c7aa4016fb50ac7eae5a59453d7296e75e9054ae38f3755110c338d109434d86c36dc8dfea4029488ebd06b6ee7a7cf40a53b06fd785ee7109059a31ace039ccf5e440b7b52a5695f006c8c95c5362788e62adbb8f105205ad8703ab3debe163f4a8a61902be91354a625124cffcb22ca090593f5e08c937c1ecc4e1bdb78f5504cc4f934bb7b78195ef0aa07c19287e8435a56bfcc115f78692e4bc790275fbdee1c8ab3ec7b98861b6700a0591899ece597fad9b871cc252dea684d7a6801b81d1100c091e2330a9e2b0d460dbc0cc612cd519c0ed87ee541e29a5c3ddb142903909d36c172d85268fcbaf1468fd27db30b882ddfb06a50d75c1e351ac13282a97d2b8d258f28cd7d1c0a202a1716578c1516b25050eba36d163f6a3590f01533856e5a66fe4a208571d2dc2c774711be4557608746e56a105571409ec112c0f13608010d7ba789695e795196959968c8cfeac8efff2625bc3a17ca33b0811511aaf213ae513a2a554496b9918a76c13d9dcf93fbc30ad034e4073138e84870fe6cc5372e485cf9e7c8c5c0ef114e28b0959e206df908cb2f69166ca623a540092220e9354a886e2cb0440208abf8c4be2791cc491fd8785c622832daa6cb207c6f520d05dc82c1a92ad18af803c1530e3bb0d65488e2f2ab3b9a33868a82e949bbe378a939ccd7f16289127b5a81c29ff88cda2d91b8f923f8c908042faccdbf3efd7f13adbe18e505b945d2d23a6b0bc23a63020c920d5ce36e6609190151a7c901ff7f8ad3ed744ebb8118a353378b959f025cf7abab48e81f83c2971b97d418672df9ba9f0b6c8d8d34fd285f8d256d22ac660e0081639c1133ea7e7d3d76ddbe8c36ef3684165b4db8674b7698a376a20795401e2e141f884712a7102fa553545c73bba36991a7afe5012d858d6a7fcee55c7068161de500f384f6330abf0de7adcf927ea3bf090978e55045eb9e5bc1fe394ec0af31788c1f210d880a94abf08dbf30de99aff1e6d10f2153cda92741af7cd0c569a2c1d7c7556b42496c5a543751dcfa8c2f8d801436380769fd453b084882ed318562347717072c68e0434dd84e42776d8424bb3a83a49831c26b0f65a32d13f1030ce083f557447735f572825476ab04d48bc55ead286d3279521079879d2e5f29d8196c0a97014fad16ee4940fe71afb19f11e01a8df3ea2265fe42dbfdda51c7d08e48c0bcefd3f42405f8e087875e40738c1a6ce6b95648a120e03b21cd5944d019e1032d915cb838a58c7ae0e41d6201c1593d8be5fcd1a07d043b763b0493d22108f758c8540d2f7a3d04cd151fc51b281a3a1cf57a7080947f10773351ca0aa6818a48a40cb1d9db4c20e0413b10c4a7bc3b31f218d5ee0c4e8764c7ed3d0623f8e6542d0d92b4c27e67e043d0a143c8b0fdc1260b6b9f4631c39ad48eec35318ba0781321cc449bbef00db253054e397e62961c03b03a619a8c27a4147219e0c19b359f1ed06457f20e7e57e1e881bc47a289163ae63053d1aa1f624bc094238b96dfe4a6a36ebef02cc51a4412480b81718d48466d44c1d284166bbe35803581a449696b1db2eb05ac1adb83a41e1d4c475b7b2e9e4600d366166568cfe21072d2c9ea363555395913ddb9c2f63aa5e2321aaf71db0db4afc5c71402cd29d4ff7ac5d959848ea858090a0b72c70702a37727d6573d6960c928ed0135146f6c1da3b1aa7bde82235db7125d4114efd6dff72ef9b560940cf2f6711666a8614ef573572ab3c90d2d7ff761156bbaa6cb1820f03baa2bfdbb9d33ab69c8d3eb7a50c862b88d1de38ecda5c06de0e75cc40adbc9d47140fff4c6b7594c2aa7a89a4e207fa4c1eaa7b2934d68ecbf17d17bd0cb51bea793ae65af27a97c01b5a45ef8cd7e0160b56dc6a7f7b9d5b29b72d06c54eb0fababa570fd7f41aa60174f6d6350239240216488dc756124b6f2ae1e0729e3aa9726943b286b6a6331763865a54e11c48ccf85a26002070a90b4f506c16851cb76a30cc969a4088c1d2a63378a1f7155b2d2cadd1b559780e70a3f4fa1a170d828edbd6661db80e17524eb5d253cb800dbbcc021b1ad225c30a6ccce4e2ae72cb3088b686741f0dc3d673131336d45d172c161722b0a3dd0aa912bf8cb009ba09ea1a81087f25a796db497c6d6ba2d91de941c2b9992d07f274a36d5c40fa2f0e0e69d34520ebe13d27b2a17d9de424493e4edc8a2e4767a78a4e227c0c99679b0f9d63926f6090732ac2c7edddb4ca8d3f5b41d9489884cf79d059ee24001c5860810da49194d8879c047bd606c3c7f70813c9333f3a618c74cee5078e250586b6933da4377f0b51704ae16762ddf52592dbca0f62ff6b80a03b0ffebd7a39472af8af96feeb628e56f2a6ab2bf71f9c750a6b96b49f410d043d9da4d596ea6ac0592f076a5c5181d7443c39ef045476f74d07960593883107f036c09f10383b98b3cb00fff8bd0b6ef8343d3581dcc45f56b1ea1e54f5aef1073995a02a69de1820e06494bcc9f9554ba5a469b3fa1c00b77b0839ac08cf52c3de4a4ef9844bdd7a342d27854cb20d67b03041c7f79fc649b0f5a81c083ff586cac7237e3ebe035f5a9103ef10bfa09e81ff832b80a4479056154e8cc9b06493cec914cdb66833028fff31de86b834545fef14271e3d30c489cc83218381c5d672fa4714a8b1e380e947d1cd64814238ec862a870bd8de5223979bba0c74e485d9d11a3752fc5b9e1fe207b41eccc46acd9f97cb0561896df97217ec8bf8d750a38e7f1ab0057a5c62eaf2e1eb4103d90608ff34945ed7a6e941516d277e278bfaff87f41646ec0cabb95257980cded5ebbb8cfe734da1cd8bfa5999c43352248933eb67368d690655091c746ea757305f6c764e01f5b6788661c58400ef3597952438547f91576800f023289fe0985e874c7900356b7984d26f21e11e11f47352d564c806d75cde7beab408554de0f29b9acea0dd9cb71609c986d3807e87eaacfcb4ede9e7d737e24b6e03c1b0f754e041f5629500f40e5cddc836c4af7383540c7d29eae388b721b15d490e72cf9464c90cb353f3eea0f8fb8c1bb52affdff3e06f10dacd014a78c8fac9cb862899edf663514e8106f001fd3ef92a58c6c09564c15a07e3e0cfc896659f04656014760d787547446bc56ba2930145b1779611fe55588ca1414db3c828936004fc4884788685694b6e745b89bb499f8e4042b7f9d5827a547614efbbabcb51bbc26008fadd7507d3a35ad6bec76b246796795a0715ecd445207c29233d25fce3aa8f51bd706fb728180980d8f017028b2e8b1cad70c5d1f1782e3605cd88476736e168a04e1be77268116d10e7b2f53c1157bbe4b7829ef86f21f916942e98fce7d12f7afbc80fb515d7acaf775cba1bddb5c4e951e9bd8a8e9afcb618a379e19ae92359088cb7236955cd20cab06c41f8cc46d79fb0fb3371b1daf7a70f9785921d31b11e50331eb2444afa7740e0211c22c67fb48421eb5a319f301a152825eb06a0ad218d460c27bdd93a7776297afe638cd49200244cd10faca433ead78af044a6047e2f6ee9c876b25a041b84f5c0e288fadc99417fbf536af3394bd6f325d6d9901b16dde08d732efe5e174b018729fdcbab7253fb7fbe09b0090f6c9f8739a21e0f42b4a5af8a11c52306c8304657bd7312a4cdfc46eb2ab0f5f6bf761556bbfda86837fc3bb999ab89f10a8be58dbcc8e794d37ca91a8008093c4efc05f8fe491cdbfd7a1b62dcfddbaecc291661a4576f1cf4e97d700c1161e9ab2e310a570bdee4ddeca2954a58ee905bfeb8a90fe1f6b639e1bbff8cdacb0f8155a1b9fca187e44416df75f94879f8f27e9d9a308d2d06f08a41cb15ec96ca623ab094c2e9531802d101c4d48f63033f347ca3656c0129bb3ea60850dfa9e411ad362284f75225f881794bb663beb9bfa4b980019963dee1d6efa6fdf1cd86f136d80dea0c9d0a939518a330c60461e590186c57b51fde283d30f9b42b1b14146d11eba2846f6d3fe13e32585260f10ad3ef77dbe51d947696f3721df4f52f34b930defe50347d6f16f8131445a92091389aaf760e1811d94e43617c298fccf263580dd5de2ca5cfdf2f52a2b6330626e63afaaa8bd1a38cfc5070678e6e4a8dcf776de8ae6c9e7a053b5710ba205c37a1d1209d492868048541da5b7d6b5595720bf7147106931a4b8e818215010976bf6f52c3a65e83e1258601b9dc19692188537683066c410b2243a0ccbea0953b7866df2341fdc2edb6028d14d1fcc29270a1f5ac2f15ea40c20f33013681f75f05a5bf86c902570c2a2acba15de8875fcd397a0c7011cf5ebae802fbc59f278b7f27b96e5126af88c5914806d579075b4f61a2315ef495d46c496379e4486e07686554bac8c5efcf7eafaeb32d09efa08ac83adf7fdac520ff349e235f2de6ed6d3650f6390e74de79130a562fa53ef23e771d3b3249ab51cad6832c45a04ec50f362dc00ae353d4722e06d8f86b258b7b0f8c48a523f60185eea692386209d523e64c50a2bd6389c00a695d37c94fbea37c194e8c646e65c87721ca64ab01209b0404df438f2b535b972e4b2bee3233e4800db3f690a5af630861578a96ade9ff28e5e0379348bf1b78e7963cf9badc6082215c9b90ea2c4dd65e7c146cc0020990102b4df4c28e2e903a87c94573914e4c1542624b08b9850c24f4fa04dba9921a48876592800db17bfc93328636ba95934e96545b528a099dbd90d98aad25b7d55d0027cb12c3fd860514096bd3fd10924eb9ebc76c5a0d89a0c3a59573a74a9358d311f3fc18e794220762e197edf43f5b55a08502945e22bb64a04677abab6742ec045c7eef5d9f023f79b0ed73dc6a3eb3c9ee994fd582f0c0e2cda8af7780901bf89460109c957527d60321bd690a7aa6866b6a7d17a74f2737fd4b3e4b9be6593278b6087d8c5991dc35f0430d49ca006534c2de610eccec78a00f0dfea3121cc91fc8833bad69e9ea11bca6e281e4b00fb28f3e386cf9e4ca9bc324d5976d732d068662525f1a59d467ad62401a65a9d6033bf29d6fb57f67b19003a03f815f95ba582890589ea5c2603b13d5610857a66031fd12c2c16f405e5c22e16f669d98827ee5df5bd474f5ccaf70f0abc1aeb55b1b5cbb231a0ba8f4662b6d622d30de2eb3919d6e8a542276444b674b14da542d9f0ca5fda484c1d65479a001317a0667d130d74ad35f1a6994d96ee4f6521b408b858d7faa33479272b9a7bfe952da009e55fb246f4ccc91a290f824e4007d71906885e7767c918983dc9121a8c7fa31df3fe7134f4c574769aa92a228a161c47f52977cf7d43a0f4b8418c20b2057dad18f7e73a6006e45f95ee8f0668294a9ac8b71d51a1f2d8763bb89029996c0baf47e1df20e67034bb1358088ab0b2af0e816229fd51d36f64bd11f2810d8182b7c59137329efeffdf268cf93bf5c7563a0227a1fd2a141e332a78d58d18a71ef8308dfb8e04a14d4c768602f50171e2631bc000bd3fc0dd56c5b7c879e0c4c0c14d7b928417dc87e0be4aa34a4461f0294cbb70d9e75a26c8bbabfe9cb745522c7355f0672b9067c8789f66048b88e13e5d833869e07c18f837057228c1f121dd22ef7f9cee33c6d52ddf13133c82ef89fbe658706d071f612cfeac7993de28053d9aedb529d1c54342374be4506fb4a9f1b7d3af71425206860023a3a6e3f280aba3fec42b5ab10831205d0246c1cf0ebf039d4d1aee40c6802ba34f558627d6af9ff5bbca31014e0b48183f1ac40feb5fcd63b6e6ef70ca8c4ec4ab6a7d28432237fdca6e426b5a787eb9069dd98440bec27d06f0cde99ead295ed872659e3fe3db8b3a8fc425fc557b112b11552728481c52603aed4929d2b1706144d0028b73d0cd98183c09b6e31b027aba0f1c6a593a4e4d46ade17b664c0d826094cefbe99276ec92ff721524ae689a933ac4014a2fb89c4f92f3f633d4e5bf4238a7bea76622778a97638d08009020152c0e290819d42118310030090b1f8c8eac8476f445f72c09b82043eec9b81b4faa8d838c06ab9c4e7578513f7c203781edccb25d8948dcc5d5165c9ee90cf4b0c6a8238f4efd5711392a97fa1125aee05909f80c5ed94c251052c816334e58a5cdbf67d8118f49c15bfb00803a0694cde08d29931797dcfa09d4cbcc393011af2c37ce134bbe8daef2096d19a8002f86e823720fb200b69af40735f588b42c85d2cecd4dbacd25a124f166f142d94cb2a600b9202c1686e8c28e57884d268209f185d9134ab9a1afce693dbc58585abf5d6435c98b4c4a172ae313dc3f5dd606a927ce3091f08530b0da68c5f1b8de90c0c5fe1c27fec2722a5d546511b394232e74046a0500b31aa438ba4f23cb48df590d388c2ab0e2d1fbedbad31d29d5e77a832f6bb222dee79fbe81e8c95c3ea6f917f0429e611dd89aa4c0735673bb68b264fdf180f2f0bdf50100956d3d071c4f0ebd9d68157ade97eb697244020570248b2c48f0ef9077715302f8014f85c8614b8fb3a5edc56d1aaf05064e69b43eab7138241103cd529800e9909c12ffc1fa82af7bd764964d2376acc8eb4b3e32ce0c35d714aa28c09535c527aea7581514cb2120719af385e7654061b365c796df8e714d4b8b8d79c9db5e2701478f4fad6580d5843ca7429d652e753d0c1344fb19e5b422bf7adfebf626a9c65e800ad1e6548284b096c692ed1144c5d88c663143a320dfb59856559a9384b2fcfac1b73dcf580082cbbe7917c5b935ded98d45404c4a0c6ee93f470fc2a2bb9c6248e0509771798cdd023b1ed2bfe02dfa31ad1e70881f3c7209404f6d4245f2f39dd71c95b9a11e659e4d7bd6984021b21c950a8f4890cf689dfcad99257750be0b9fbb6a127d001493cb959c7ecd80f54e37484f0da000bb3cda89f59bc80968339b3015fb23413abe72b6747c87d86c98d9a995b438796d1e0ba4992bfd887397032c81ebb3eb4fa977ac3bd06f60586e1c8ffba0e933835603f91d326264ecd35c0a1f591a0743b88e08be2944e8231139f0ef65b962a50a59138453be4a73e945b53cf63140f4918fe81f15bdf352446d9628f81ec80a66755f45df32e2ae8684f190762ca45f2b9b001570f6854696d8b9955775003fd619c3698a3fc30418e0271868c4d34456aabe2bbad348f3ca38009687130149990e3477c27c97c93dae522f911f6a674cf7de3f8bb635b7d2b76b0a78537e86a03aae1705ffcfdccc562b2ff9fc47a7962ca24a328dee7c49076a34fc36bb7348bed581a94bf29896d018a39979905590a69cc57bdc8ea2d3dbb027670f35237267aab63e664fd09945b4353985c7731177eb5cf7357296c3e10e6f2120cfd9307ae06344c53fb8d1209a91c81a60fc591c4bf211d23c80f6cb22099a92ec438cb41f36bbdb0b1a8001576f66aee22a0e69ad535001456eff2d07f846bdccb5158dede05067eba8505bddc7cff614b321398e7f1570e9f27bb65594de3bc238596893d962b7e1d5dc9ff3d47833bd8d8a274c82243e089817176f177737788c61dd6be2c774b2d3beded655f6e9a91dfed754e44cd285c8a0a2722abfd3908440742a04d79ebbeb09271dc9c30be8c55819d972d0c1a4a60d424e1836229241adc7ab572149ac2e5a01417c68168f66b5d254dc9bdc44c75504b0cfdc8c6d188fb8f70b4b0b32a8c54f13a7a5cb30404c84f5e67ed80b615d9fbd27c7e4b0d55ee08d5556ae0cb8502030fb101a7eb7280a5b263c2d94806ed0414b823f2de1ae964a52633303909240520befa1336433b46a24c82b249f5f657785225fed5c35a8b17bde8fa07d6bef2b1c2945aeffcbe25c6516ae10353f8fe54b1289d1634146a856623b894616873fefc5a0a42b167d1148eee22acc72927cd98d2278eda90a8e57f62e407b47d3f2866f2c57e93a9682f575c2924803470eeb19a36f71bd9d6caeb174b9bfd31afba3343adf594f9145b5dd00448820924ecbe6a6cd90a78bdc26776aeb90a7669416725d00593ec32e5d12fec7e6003939543f870ea04efd4ce321eb2bf65b1a5e4c19090c00e3d24c5d4ce3262df2d6668bd69177a0d6764ddaf371c6fdfd1ffc914890e2b62eca127b5d57c45bf323012c544e6886a40bf425c04b344f9146711ce120d7859f6d3e7bf95ac2c0a269ac69a7b0fb7f81aed86cf0d154d43690fa8b56a5a322b0041bf7f5b62fb239c4279f211fb54a868f3e7c825b383bfe660b4fcd73fea5428913133853fe98363006651a1f3f7d1b1ae30ee909f8c3e71b26add2174f164046257f19c3cd1011b60135dd615e39712ebaefccc04254ce28c7ac189d493ccd4c708554b9fd1c04885abdbf29f6c101ea21f44f3594082fdd2af92707611c01a32f443b07fe90552143124364482fdb696311198c20286d3c843eda4e55109f81cde1f4b87ba51e1d53b19f0a84081d2743c364c1044b7f175116f825d9ec4d0ecae0b58f3f255c439d0358415150b5c0c250b8f641433454dd9b801255512a1b550b5fb24cd38f430b6c58709759209003025236ee189a4cab30ccfd93f9d1616717505e6cc9ede3a4605f3426c426b07a38924dc526b56b38923fc4c74a4a0b6708c9d5d6be24d46430cd3e5a0350266b4fdb5947939c48bdf495f1b7f09f315d1040e2f0b7e974c027267cb40b8d97b7a9b36948424c01fec371b081e82b4fc2510c1c78c70167a6cde6fe5edb12ac03ec2825bcab0165680ec59136270e26b7f4b91c5f88b45dfaf97fc54d23b6bd615969acb7483eee8464afc294f24815301eaae2b10d035268379d61051ea874201c9d9c513a7c9651bd72d8851e68fe2b17941eacd8ce7bc56ccda8554f546c56d2bf6bc84bea7c338322d2dc316eba31e1e92ffbe8be45491f51e08dded902d9489ca8ada5f49086493d5b92484b1384682f69982bf14976eaa953c884c39498c7bf43bea8fbcdc77841a487948c56d7a90cbea9914b701a5b36db9cde1d5593ff6ceb3606da2c05ff6d6973f545c911796f2c8944cd5b34a9fbbdb411d40d1944f8e01ad03e31291de9f2324c7896b064fc143f7e1e4611216d3416a28708d9091891dcf1001f76754416944b532ef29e6df27aecdd6e517f1884286afa80f3f23d8618801acf14987152a1238583ac0c48b2fc974703c7a4267e815bf7479c635b54c66be3b4d0a2912ac4f961107e062d41f31ac1b6530b907bbd7da073b011c93702575e0916bd3d6219fa7645dbe442e8e47b00b55c6bb1c63c5e9427c2cfede5987237138030316f884840c05be7cc558624051009af289e0ecaa5f7ec70b925d80296b05112d71b124669eb27252cbc2ce2a1fedb8b7ea6b966c9a5399dfc44afb646f4cca1862d6f2eafa9b2d4ece360275b7fa38296f6156aceb2341ef33cef30ec6f0ccf260e7d2ccd5c22066611a2b74bb11298094f8825ed71c8cabcbeebee0b52cabb821de6259736e977b4200e6ddafb6be61653375bd0ef6c52267186e62a65d2952887db5728ccf0ff98d2a9fd05742164ed1278ad4daacde6e4e1d9dfdf68fefac97dcf6322fa2dd34b6ceaeceb4180454434d775dbd54f3fa0737ed0ec846194938a01f1edfe282b66d05a019cd293f1f685df5c851258fedeae110bf0d11ee0750fd38466501536bbd7a07184b77d508f81d9383fa1b37d190e7937887aadc603a4432186c5f389b700d548a519b9c39fc3ad97b2e9482f987359a54360bb15e70ed0b7c39b464d5e4a453dcf3f2524710e85339a72404b4880c448ee7fb5ebcecca579ec0920fc3f82480c95712038c23a87961b86fc4659df9ffea56f473089ece0fd572449c045c6e9244a56e6a4ebee5915767b1e41d78e10ea52d67d44177e7957b50d344cbe0302a1c754c348bf5eb8f2ae0ba731cc0a56c7b3d361b017d0f730a841a4d4542eb317c2f690b5e39e5bc2c6ca02b177b0db58d3834c0a8321537eefad0777ffebec418bdb78bc06d0633b1bd7fc01f9eb7d14392a0f144ac4f43cbd8b5dc50dafbc7081fae504813150fdc98b474d5ffc727f3ea8f61b3b0dfee6739b07d3270a0edd59e8ae523c42a92f1032ebbd481017549db0b26976a2d0e55174f8707bf9b71e23d7815c4af21a8aea08bf516365c7e28fb4ce2c34166470a0b7512a2e053c5fa043dfb7eeb3c0fbdcce71a561d3c36996c170f6ad9fa0be23cd1ed24252da3891119f5d85200d5edb2bf208c95d454b48575278c3241b25a04cdee9b16451c585d5c3492510799821e25e1d6730eef477192c5dd9b382c914080050e0ca0ce9043b742e61a7b7960874571e5fd0fb82ac8cb4aebe992e6c33c30250888bcdc0fce2c8ca9f096ff188f12d77dd290ab044242f03e4a0df9cbc5972e2539ccd60395faa26300ecce36a6dc8d7fb86326a57322b99fe28fbe20e566d1eba2af5a162809a2ec6b18521d9291b68e48c59575b9b617aff88e5b239462e0c0e4b6133085e4317dcfe231b1917d462b9a4412d427869e1617f69848d3b1c34ab35df6ea2eb0af028ec9c0936ca0de6be0e6c1021cab7a764ae64ecc48b52b0d5460d707b8fec7fccc05600e3b4b0a8689e8b73bf61c300b062d3aa232e0839aa49be154363c34470b5c90d5c58c711447d8d4f726b401146e39e06ea3eb27021634058e450648f98ef730f2e4fc89340718a7a4d2b4a25149755429f8cd7e9593cd47b78870359ce6a6608578d927b5e5c10734be9165ec4457d11d19719eca517fdd7795490effdd5891d35221390f649adf71741b37751422ecbe4ed1696bd2900535f08783953b9bf0c16e6d4813c2bae02543b105888686f8a48c81f8625c61d07b783126262fde875f00ea00245e13561ef031d41f12440ebeebb0e4fb4f560a03074701d490ef3d5b662c639edef8375ea5269e328c3e9f4c0928aef10f8139a792aac67ce1817d6e26ab00371101884d75e4f60146f1ab45a9500a2e470ec6ae39c01ac441c52040b1414999b555477617fd9d01c92b2a48d2a479ccfe38e27d0ac191c1c07c326a09c0c05bf0dbf6b1898ce37f0472c45b6f8232d03c4cb2838dcdc4d6e413d3b6780528cfb0ddcb18d9789bdfed9e79fd2c3059bb82967be020e566c68f80acf212396da752e0599230e4de788249eee0f098696881e887dcc9bd8acf9fcb1cb90fb361e839b84ea38b793263e797a2051732dde839658438d6f326a9c86e9ab13209775415fef87de7d3e95b9ec5cc14aa3638a249031411380251feb66526664fa35c06e212dd3ff0c007a5d1655589ec010459a86d33d4517df62604b025b9e1d4e3bac73a74251ae617bc23f4bb482f79c65c355e220fa45f4b737ad5584c44f1f4f347d75000b738e631474f079d98f904b1f3fc44f5ebd1e7242e095402ad59348b5b6e4a818f222a7aa91b312155dd8f4c369f874137ed0e26331d3b064918ba427d3a4f6b5a7805e76f395b1f8fe6ed0c9b7e895c251bfdf98fe024a1941ae6664adc18a7e15be210d4898eade7c6162c5016ac51e31f93f2c3c660fcfca0c351ee88221237589def032be44b25489830aefc2107c7e57e81af3fd4c42fc064fc0d1bacc4fdbf9ebdad5afd80b35ba97e67e370f60d83b73e6453834fced0fdbaf26f497c9eb9c5f202e0840de55ddaaea95070d8753cf3f71c13d76a7f21d609234319579d97d9d37b9683ff5f147fd5e1aa96bb4a00c64f8f909b246c3bbc1427ce5633bb9c676b37d212673b5e94da0790c3e379a031bed2bccc8dc4fcdc33fad9ab7308034394df9dbc860db70ae5a909dbd858f5b3ca58617620f6d46823783903068574bce3859c3f5ecde8c856b0ac16e1125ca25feeffcb8ce75196489363c6fa810019ddac7a22a3cb74af4ada7b070998d1a1b2142b47c220315974b21bc0b698c5fcbf792b6351762638be3e631ec2079dc29689d1c590f0e37fd2606c69a216c96376aa6074e376a63911f723115f657186f330ff1f2bbd3002a288a7192dd698bf1d7f63c0d02cfb67dffd2b764ce387a5be7633314ba9b97dc5aa53c28f83e81341f1bfbb1a49de69225f0b5339e1775494b5c62072d0116a4f495de4cb77d256740fb60f69a8338776958b9b1b1d3a8c4f842632c25e063bc826012f73d7acee438d42f9d8b26823e5e9a043bea0380a186de162ef8cf4774d46a9987f9e18c5c31fe204fbbee3f89338c555c89cfcd2e074224c00f4de4fcbeeab83297565b4410b6907974fd08a4ca440fd8e639263d60faf48b793c82fce79d78f6b4294d7cc1c6cd817facfa1b0957ecd84baa2211d6d067bf80772ff5ee0918def767e0e81a603f65f79c340f39d2846aaef8e004a9425d16aef38d1790b3a1bce27ecd0c59dab8118caaadcfcb12ec1fe222dca5f967bf164ae70134f1a73e35fc14226af4599b72f028d6a105c02e8c6bc27311581dc5668cf6e8de3d9ee0431385458450396aae22de8e16cff61cca3d9282aba7af182a9c60134e7653dbaa5cc00e387e82c6dc0a560601cfa921851fd11d4fb58495dfc2b9c1e9f5dd4f618aa274ebb113f4239e1bc55ba616910ba45b9a90a3dddaf686f874b1d29dc4398bbf860da27e8c2d92bbb505ac70bcbba7038fdee22733e925f4bc04187dc9020151ce20a9b849e981804b0c41ec9d0295adeafe159ccf52147aac1f8c508bcf278b14ae74cf3a2bdca28d38dd904b14acfeca6df13867f0c5267ae008f2dbc2346b63108c4222c2828c923f3fb98efeb487025a2fd9f6d10b7e47ede102c12041565d5ad8497c19c4467f9ceba4ed1c28d562bd353c3a63e702ecb94e2dc2f3a952ea5306f346dd00f21e3c488a567e7af2d01aa6c25e4bace1088ab416bdd2d3c30ec34c4c1bac4346f31ec0327bc2873a68cfbcc2edecea080f57b8491fc3e9213a0b692dc065f18f593e0519c9cda90bbae747db901b7c600f954da873fdae73391e3528ed4473fceafc557e5e8080a51d43f1d63c862aa0b9f322f4f1f100238c157d3fad8a5ca0046a3359f7ecafb1751e5af381c106f42298452fe9b8a07e34bba11fa2f8658c45f14a4ef7f5f3b9c33a236c7d4592a82a85fe4f6940f08fe19454b4026cf79d34ced981ca3a3d297dc95e599492e27b7eda4460f26d6a98c9536fbbe3c8b9d1f3f6221d2d39f2e573a83640de541df1ed3a0ca6557bd4b591541058a409d2fd80ce2078a9b1f261c68ce16342596cb66407881087d53ff3e39e27b5cbed175f2da66114e5cf4c7b507cc23d14a7c6945076dea6e78eb16cde15652099c572b903f45d1197735057978ee58d45b566b4cf94c42b21c97ab94c9f2afc56238f9ac9b4cc82027b6c58a39e5593dc829351bb04a508614072d727229ae15cd1813497270822b834f6a6eeb3286e6edc250f382600c69751cbc7b6b4194bda9afcba18a752aa70407fc26fc6a803b92f380f0baa4f0479f244f044e68b96d882b7cf9b9ab01f35d2b5f227b1907ce3e0d422dbb1ca5eff2ce16325bc348a18ccad2699a1557b79b5479d40c876fffee443cec9551012bd18abfed611d47e4e1428df0179a933ff275e625a76911312ca07f0ba9723c3561916a7f108d7356366f3e9469fa95859a94dd58f649620a7749533697a0e32e0d39ba182b4630295c190269e3a6972dfd9c04b92878a73a5c8580c6fcddde569b8b122f7b45c968eda2729f0fc878744490876e76922e284b1b4d30b83d0d017688cba93e06c0513d203577aac687b4d05ce454b6e7a5db41251680865a75fcf6ea4ae54270fff9481f052ade9ff2b20ec22bef9f363c4d0e1b54fa4e8defc3537b3b8844ea37195222bdd0dda06389b477f5ac815cbf9af74ac44ab40b38604e55fd40ab41c4094869ed5f2dfafc2e398402b2e48519732d01e46f15391f947d8601960d1ba4a2c85bc9429be9d96c8e79aa0e5e1d685fcb7c20571a505e5ac49ec63d75c1b628eb53489cf188e293db78d160d3538626c2aad4cb8596366bd36d9bf84753f138ac50d0d2dd09e850bebed26d97fec199850f847356cfa4d1b5e7117b8b4eb33027c621cccd68ceb94b92e12203c9b99591b71fa12bbe87541aec143e56c763dc3aa65503552e70b83f0c01b77406f536914a48610c0d62d182c045637486ab9c884d3db11646b7601112892d3a04c04bbc33b755d6b6faba642d8c5f11a680c7be8ced62d8534d18e83e97c998f9f0e8aad6dfcf4a9a2320d4149d6f5892bad5d4361cc2b0f442666a06766ea7646a6dcb234ddf0d5a4a620d6749be239cc26e6a198d9caf873b9ca46c95f66cd8c032c10e71caeae035581964d7754f160fcdcca0166f439f9877b7b99095c19054e8349a8d46cf20b3ab92b36286e34b9520065c3ad670abeed8784c262b37a5d809282abe4cca798c5d4d4bb45aa7a95079f4c771f0c0546cbe86b63b39a333b38a2942654ab03c9134385bd83412ce3455a311aa41dcea6fb6341fcfc29b53f4bae30d4fcaa085a254a0d007770be24cca00eb702d28fa0545cd8214cbd7c328c4bc6360b6b293954fd9dea9517fa61be42a3bd61330d5cd20ae716f21392f3cc2f2733e1aa59b3d5403afc04c26ecbb43e89442282540508f0c92770def2056ff8b8c873863f525bcfb21324f6c31787756a891583fadb0f52581b454fc20603dc3c91e74a9903cffa48b50441e209a9ae399eb997ace63a0952e140978f6ce0621f75e9a190f6bac6c05d5a79a272bd273bc27f178cf1a958f572f3cf929e2debeb5ba7d65fa6d05950210dd1f33a21b3b59c41c8a69ee42343e31998af52ed399528a2d911edf1cf3c93745818c398f5ea4d825c42c24cc87e2a3d147b7f12750a8d6673938f1e3061700f019c68872b8836409e97df44f4784e6a4e71d3c222505c64692b1718fab92eace095038516b7bf326a17266ad5dd85e5910d11c485a7011f344ac838942c5074cf33de88981930a22a70f0b817c40bce24f133569851c54034fc8fafaafa2ee96cf47e736c6af5ad883c1fe2856e2238d05f9ac6c88c16e4bd2af9a2c2cdef2011133dfa0c224c62e854df310ab939e8ba4dfc0c84def387d043e65fe1058c53e3d5752227cfe460dd2b228d4ee226f1f8f84423121fee033162c2da585a819dbda929f0226c532c4fbc391a6e19a18a1cb609374aa794bb1fbb741c8b64aed42d5cd8948b6c712aa13d10fdfe34aac230d53c1c054dfed1c8526aef10ea93de0a8b7d2e8c32e02e571db7b8b3490168a60b89e67091aa6775788d5b6babce36478c522f15bee6e69de2dc9abbbd369e47f02718241124a6193eec11385093e5eea094b2049f015c9b837583d413b922dc43892b9818f2307c1e700c7f203f9b1c05f775979890e958d7c7503037ac91e2df6cc776bfa27de419a8ff61e064cb235cbe4976822fee08db83100380ed9b4daed97184f1ee484852c68ff07b3d327e261183eb158c82315903f2516d5b1ca19798d4c4bbb3cf37038e85c68645d3fc18e9858a9fb0739f2496cd7cac4b4a50e2d8dbe8144370cdee3c4cae6996373410d26e5f503ad2b4a3498799eb91a256045086cd2d15db9008b08d5f3146d5cd1235b5e595e7a1435e7fafaa17ac2f18830426f3822c83a201c500408b25e024e1e98f10f20486b89a6f861c2e4d26c3b6fd488caa2ac8620a3bcb44c21cbbe72a14067b74603454a2d5d184449b35b20fa31bdb1dd240dd2bb7b522584db49b943096a6440e4fe63d23abbeffbe08ab278d376f30054744c55fd7a75aa2e132346249506ed15c2e6d2e2fd35b9b1e844dcbd11472cb2470b5644ef7290295a4090d358653d70d8e1e50b569b05f13b1b67378ca21fe2419bb8ab7f78bbae92b5ab56722f332d888031776e94fd8b0115876288669021a23bb9cc0ac118652f1117c60e0b04ca59b8514c32f3194788d0ddc4feedc5ea0715e6f85bd663a56e681904a976398b8369cd8052baa1caa8b2ed5dd8933ac15cc6a010252614ffc5c3f155a6966c22fedccfa83ff9891e16bf0edbde97148dbc1002891220e63c7f1f994574fefb20108fe46fcde97d7365e631f1f8037aecbef1288571acb04d67b336057ddb9a4971dc3e28ebbf7d2e59c95355f07f8831887174d8b0445b835533de205285f0082fe8054c200e8acb6645806f3d8c0b46ac93e37459a974654d2e19171d7efd6185ae4ba459678fc025ec8d3f26d884ac32ce8cfa5f2aee3e107306d9abc502664c3878924ca720decdca8ff531ac0b8dbee3107844e5ee0dae52dd243e21900b0db14157bdf01730f28208ccd4bb68304cd052c030a53c97a5bbedc69c857cf213f1677e74aa0c0e727ce57a2c959521b104fb3300c801e75902caa34f0ee3293c9bde3a49c407f85cdf1c59a2827364d7d6ea56609cb9842f8451f4b44d2acc1d2523f4201b0a81ee1dd91d63caaa59be02cd30c6951148f4003cccaca01369e52a8559b137cffdb6cc3428d9db8c8a9de9cd34205858f9335b847cdecf36708f4a991d41b0b33a825eccb0e2dd6b6adb43a4948a68751860fc0973eca05b6824e07a9aef0f6f184566ff532316b399f0caa21808ba50383f28098026e20f57149722c03055cfead293c94a93fd55774004a9cd32f795fbb2590fd749d9ecca7c2c5c27d2465d2114023d899a39bd0ef10d9e28d2e31612c7ca599e5bc56370e109f9279e32ccceb5c002177c11c9c545a4ef667ae411b3a44e7db4f26372a8ddcc7098d30b3b41c5eef0c9d8855bf9529a58230d64553dc28d772e9410d5d711d4c2d0683e04629a2198b24d43a8055f819202838ea1834d8be1f259e5cccfc90d548a3e39e39083bcb158189a9a23c9fd463586e2a4778e9d319c98c6e88d462eb797fe32a6244d402f204c459e751a2f241af609c3621dc34059065fef41159d2d1e58682641a450e1209a72fc990df9c9d874367f2e4d9d211527515282ec23b306b29148a0486fbdd92607e2d6bed4676871aeb9a37f29fe55838fafdb95c7960add5c1c57936d3e2761a056ae92bf2ef076191d160d9da16d9b683d3e851c4cdc5806c23cc6ba89455f3fe5fd0d229f3d8ad7cd0a571cf40a5285ef51820c56cb86a23ff5c2dd85f5e0f6c7279199805bcb9d59c007983f2ff929139507d42ad5bdf7dcbb938fe6bdd18828e98de5c67686cfdb204f4d3762101f3b939f6ce2a0e0fe507ec583931823885d42b0969eaca1409eddd9a37f34bcd742098171bbabc998e2150b6b89bfc390b4839ad2ed4772d314b5679347ce93cc6f31ce6631714ad41045a95e48f0c002cb1bf3db8c6d487964d93cbc016ea2048fc55179ec031f8f83eca2bb42a2c287d99078fecb9ecdcb001f5dd40d1bb355c8c29304a73e8d7a9e73cfc980e8f8f4d09d9ea930f87fd153c8054e883f24634af512fd97d4e11f9494f744f4c33c52edb604682036f117ff9160334e624ebbfd019744cddee1dd440708c7c8e6126d2211cd668c79e68d4d27707a9f33b2e92272061ee2d23fbd2de3ca407bcf941d454bb712434c5cfe037af10a895a801615251dc336f09eaeffb4f0b08228e0b4134705dce0a6b58445a34df8bfb045ca637248d771504b8192450097d3e628ce85bce37c0cf8fb5103276f55c17f62baf2c10837330f2dfae2ffd65a2384ecbdc9de9b6c22a524010f0852088e084de3ae711ff728dbbcce735eaf73349b495558a3a11ff7f876894559caa698dee6e52b288b745eafbfa855d19e3245a6eca42142e752364505d58d97b482b2168a14be2e85d3a3607b9fb0f768e6269ab2264db31a25306c1dd96bc9deab30cea365897c3c8723b4ae0cd47c5e6213f00c03bb854df0641aa3c43490ca9516f0b361c0cfd0f50c6430a2e6847019e43be552bf2094175c0821a493fa75f83a2fda2c140855e18c5afab93eff264b19f237af919af966f9c4b2265cf5dd0aa12accbc0199dc2c6c59ad83ba286a32370c7e9f58482349e6f7391f4b8de610cebf47eaccefd6b75254f2d467ca9acd3487d4a569189acb3f4bc246de30914fd8e71d6c73a8d1702aec433dcae4e470260dc55ff391e5dbbdfa44fb52f95edf8c879f8f93433fd4f70ffe7db1ebef96e61f6c7e049b17c1a22e99f7cc8de6da5b6718ebcd6259dd22231527fc5613ab2a2c5f8c147c177754d0cd319c4c889cee7372873fd83a77d3da9a5f67dabd0266458c8ce3e60a1b79e4798cbd7cd7eb425597e85ed1a7b604b5310088e712675a8256e6ad914cac6e586666e6f8eadcccccccfc806adf74e9a784c863605e01435132ee23558f6c4c0c17d90e806b666666e67e88721d801868bb3939462c51028bb21857c0f057c0ac80d920788429e615309b8267b65926db186a3ff2be013eaf53d6af0d867723f1dad9dfdfc800d8fbbd1c4b6c0ccc9a7005006c9e629b6398e6c7ae93c0400e03667d04f6711158e71f8c73c626f991911557c8bad3107e314c513ca9578a233c877cb190bdd8bd5adaf3201f9d3d275a96a2016c0dee216aba8c9410b329dcc6acc9f4f9151bb3329219c2e884004e45ca10728c00b0a844a3ec11c28eed1d55bb4ceef1710a42c6110f323e40465280cd2b0a767222a5e593766113eb781904db7cc2aa3bcc723c3527625a3d9f4fb49280ce390e7514e21c04090939bb6fff0302211fb4324f520642dd344d137c7f2299a6a999de807d421e5fbd6b7ea21dcc7bd03ad7afe22d6cca090199713c0e7d2202235484d6cb43a7571f692ab27d0f5f8389c4a69b531160fed464fc8ba9e7fd6453c5d83b604808166510c6951619c0610f5a1fb25a4d7c9ee2419b821f7b46b5cee2d776c96af5934d115fedd2da2e59f5fe56e86868baf5e58f490445b6a08dac4f8ca164150cb140d6dd2b8cafa241b0cd3f30cd3b58bc8545d9c4ac28025dd27ef52b89ac92488ab37904fa040e5dd2ce21e1a968f55caeba38bbbb5b55bbfbe8644d38af6845c938f4f370e813245dd2eef15c1749fb49757d625975dd7a45c9e23758140d60afa91eba6075926e1410ab28d5c99a4c8f8f4e62bb38aa4a13c4324843af3760d93ec618e3de80a16427213bc2040c776671802ad777cbdb90b37bc344336cb88d711e691ea364e6bec44233ea30cb90377768487e76f6c6a6e0f7079410a4034217c7bea2c896f6b976641f865015fecc3f4208bfae99abe7d339988c13022e7ef3bd5141aa878684c087d8823f83447acbb99d91534ab7d2225a1bbb8310476268637f989a399cc3c5b13736858baff37d5a97df4d2b281bc97a70deef1b18c0f972aaa47272d6c69a40cefb937b07b30e1babcee1605176ad3cf56be5ee0d48eb0d5266f1fc7996f3716f48d97583bc418232376fcd4b5036ed8d49f7c69a4cdf1bce2d8e2a9a506252b637da4a673f3e00f2f71886e43cce392fcd9368ddead2a5d7a28c61b089264d1a1a8d62f5181f8d2b2ddea57d975eb491a47d94e07e34786bf3b7a19533788691eddfa355a525abbe7d4fa22178ebefeddbc7ba74f7defb4a2dc60623935e817c2308563793f6b58348af4912bd300d06f21e6ad2a315036fd2302184ef9d5df00e8f79c8aabbb4efb9e01d36c5bbc4ae451a5ae9e34fba6baebdc5b746db5ba735e941ebddcd1aaac73b6cff81cd7730cd37d875c642de98e70f7357d1ec82493812fbc04759ac96b35b715e6c8a6d4bdd23a41ad210f527c5e67c310efdc06feece2f36c5bba3d6dde73dd8e62158d4259b77775d83494c72d1aad2aee217efd5e7a461c63665f0f5897efc039ee49e94c147f9c59a385eb9b8f3811d9a1d97a24d3155a6499abe6362e6697a556577777ad235df487dda14dbf81a5a1fcf69d269da214992248364a9044bf9e951a6a1bddc14d69f54d9ec493a49d3a6d8e59ddeb4fbf64dd3f46953eceebea95a0b08b8bd838e914919c3c42ae4f1129be08e111d16f268e423c2c5c8b15d5c4307ef46c4503b91f6380fad9cb56704ad2adc2cf3c1d1f40747d32cddf1d355f4897749fbc8474474aec2f0293e44ce1ae039c228e29b9183300c74448423a008faa12334f60eba3b324cc3689750886398f88611bb05867c3b867bed8e914d97878e42da5485655c48480ce910da2c0d23e44e0493f760d5179be6434218e620f45d1e66966916669669967676af2c9359f06e722a9ac5d166619866e918149cdac88adc40b648062593b2ea9d922aca7ece1ae437ca5edb3d8a9c34eca421928f71626656e1090bc5c8629e367f6cd1d0f468bd9dff9ac6a2953346c9de86aa7055e1484fd6e47d7af4134f5d6a5f5a19f0a57835975e5132ea1293b306f9a52189d5cda89f540d55e14c7329a959437b4843ebc2d6f6f24d1a28992c4ed3eeb7adb478efa047bb4a57e1104fad51076d8a760ac59b6868cf0d25ab2a279b82fa7b7c959f93c6d09eff5e2555a16aa42acc72f791e9c99a80d6a4ddcd1ae4df256c7f61d42d6cbe61d255b4c4f66453540cb1cff4288b74abaca29fe9d4a54b2cca4e3645bbf4912a65d42726693c9fb4c7533fd914118592496dcaa6934d51975b03daf749ee0d738e6653a3276b22596bf9a0f372c89edb913d763ad8041002efbd5e12ad9eec6dae397f70fed1c12226e1d0ca321bcd6555521f8662bf599aa5595e38ec6248af77575abcf7b5f1a4d76d7a6d5a1c59bff73af5418955149ccb47eb0d32bb5e69bec1a4aba21c2ce2928a56b44a93ca9044eb0d0ddbfb7b63533cf7c94d928627104430d234b198a41e908a60a6b7e51e69056555251d6d4923a4deaf14a4292929296d05124a14a3685a69214520a9b3698a5e26944699a669faa31e2fb1884922ad5246d12a4d34d4f4e4e484e34a3ade88f7b2a98a968481c42bcf7453524a8aa274c8ddc7795848c423e5bb1443e2619e3d2c428d78221f31972f45e48499e645a849844a28a0e647e4f2ee2ae429ea3d271ff246848c903c425252d2aa225192fa444d54d3112a2dcb9a22225894cd29298aa25cc8a328e9a81712e271f2ee5194a37aa27aa27aa2288aa26ea2266aa2284a4e11f7ee30be07b3de180c9730125fcc556e9aa6698a2fca4743f1948c4e4a4e4e475114255d3c75d10ffcbcc7735dd4dd47dea45913dcad93c06078f47d929fe424279526a1e0d62518120aa4aa6590c2a60c5214453da9d21c85c5484928983c3cd243253b0633d386ddce757777bb6676aeefdc748eeb88b7e3f6c4c89abae866dd6619d1f413efba1d64ee118e5d8fa0aebbbbbbbb439e81ac596a18dddd6037d80df2f6430edf215f3963f327acadaab7b5d69a6546ddda6e6bf2d674d339e7e6ce0846643d308801b621b227af237bd9a68abb38b2218268ebd225edbdb4497047dc938686bb282289119f91190212a3831072e88a0ea193f03424ddf77c710c31341dd976bf5fe1b157778c5686e918e4aff7a36ba45b0f24a45be23088d08878403addef86dd0d4f2286770cd093595766d59759b700704aab871ea3f52ad19f6278e59778659818282f8d41c532ecc7a011510286470d004ae96234c636449bb2abbbe179078d0821129263de4103028973d3f1a6239bdeecb9b4ba6fb7edb6dd56d2509fc4f73552953677ee6498f72e0690784312e7eeee5f2468ebc10e48dc1d8b67125894599b03092c6a2f4c02031d41eb1341af8c8ed0eac99a8786d04a92813e5e50649b8d3bbf6e3c926e5a0f9a87c898caf3eb6cd9f46cbe587574433fef120588e49b439fd8972e6947016a92cc73bdacf5c0bdee2d49b3265c8eaab42cb4328a5a0f36856c3d5893e9d1e36977abada3eda5f520c6a6a39a2b69eb01b6580e627c40bc1ef8c5aab60508183b60e7c0259099d9e361e629468e5c1e8dd7039b8871d210a9b42f1cec82ed226fe48e7f2edcf1234af18ef247bc0a7e34ba690f19f76643bf1cd91836c366d80c9b61336c86bd3424cf79c7eeeeee0770f8f1f3f17d0003facc1b5f0ff5c959433c4f08d8107948bc5e11bca6a2a8a04a525f3d10320c1b1d356b880f393821e0d2671712148611f036348cb4624004ad286805f547682511a1f51e5a3dcdb0aa1e101f1fccbc2b2de2737933e2b311ba2418e3737933f6f900fbf59055157e34faf590c56f3651a545860c193264c89021ff7af40071eda84d471637f1bdebf2787e12920a82af28e27556995a7e5cf4d17833d6a4391dac7a73b0f9ab462fd10bbc983e1798cc7214b4266a3d1acdcc557b99a25ceb11abd6c2f489685f3c2d170c76810205084442f27b3cd7d5fe688cc8d7f692393a4dd57b1e496b7bc9a6dbf068bc428102048a1106e6d3737934aaeaf5302347d1892823a4e0a3f19245005811b125b6d0d299899b4abeaa3cf3fefa84c81fadf241f978864dc816f8e49bdc841042159e58e88a3810cacf29218786acc93c7627cf64921bce57f84e474eebd72b94927eaec3bb3faa82a19cb3f3e0f7bd7ebc0369d684ebd58f0921adf0e38356d8999007acaa16cbb2a09430f22c2385806f4af9f7dce1596653bc43eee1e47ccc434a5a792673737ed23adf79adde91af15959772c267b1cc9a3c0e569d319037167209f33cccc16c22f681affb6b63ed37afbb791bfa81bf345894318fcf8b664db8a4ec229eebee219ad93c26651e6be25e9d619847f59d34543392c7a638f7abfc94b210e51e157958cc4981067e767c5c46663e2d6da487d3c07523331f191f1736e1dad5a683e6ae7bfbe38373ce7d5a3685036976eee3926decee8f0c07d2b48ef4e8761f978f4bd6d7388da6379b35e16a9043b89acf8e766e64e6d3e23e3eb4732333fd4f4b7f66b88f4b6b5ee3c7259b3eef2eef689d9cc6715cbb911efc6971b2baa64ad906d38cccfc20a95f9571e0701f191d3fff9131d2837f683a64ed1f198c83718cf4c8a48338b27a03e3f8c8f8c81899f9c8f8b88cf4c828f891b126138ddc0b8d96cbb5ec0c75e72877d5889961131445a34861974461f5caa87594a3dc791d5551ee517f9d2f573454bd5357c11cf766e51c5d577dde3d60561dcaf3fcc93947bdd7f9c4bf30396bb8be3474617533e6cef5b136dc75e82e29b9a5aa2a5e21424f923bf5a05edd99798aa275672877bd53afd35114f5aa9acf5da738987c631f973010775d9a578da6aa621ec7769a2f5669e8c75515c87551573937e320a4163a8b3922e0c854f20b431b420eccd68090575ac0ad0143f119c8e05c9890afe39e8fcd71c6edf9787817a7a39f08b235984338cc811b07391cce2104a19c39a7ebde1a3041b084706bc0cc4866991890d7386583448979da9811466e8d98bda683cc713ec65d8bc9296fd97031315b6363a494591b319ced7881332d8c4c92348f110b286513289b68caa680d3c4024e2936b009d8139c24c8dddd2acc58c845b39b99d3136ea6e99a1755c1f01c5a3987af9c7fbcf63f6087ef5e3994a6ac09fc04a769fa3e6201bbfb2d420e07ab9bc5a76c8aadfdce445598f38ffe47d3cef410a7a7a76c8a89560cbc494384c18e7982109e058c7a64b55d050b49699ae2596c8ae9319269b02398acaa70caa6e8b71829b46ed10a6fb1bbe05b9413e4c68ec59a4cf00ddb6fb0f80bb33eb1ea13d6022f41348e1c2f3f348e1c2f41e4681c393cd8e6d025240878dd4d752380a4bb9b860878badb43a32e897abb5f72bce478c9f192e325c7077f0c21ba96ad076946bb300f992449b463c8f8fd34d10632894cbfae4f22467ce4ef9ff779e72244bcf31198a7f3771158e71f2c8a46b00ead2a4d048ba29237ddd3b907c47378a96520af2acd499732101a7a076149a16b99ebd0d03b08031e05597a5592a3cd32f5547daad27777ab1d642c13817454340bc3348c8e21758c666118e99b437bdeb04150b8371665f57aafcf9e0b2ee9bf47146ce28174dab60ec8bb8a76b7e1d4a3ae7e7db37f5c1b05c075d125fdbe28f5501730f41ecf75b9809feebe2edebb2e4f7d4651ccc0247d817dcd02c21f4a9066260424e9e8dc98adb1305b636376a6656b6c8cb4353666675a36666b48ef715ee10a4d6f59bf472692453eb0c18e96c95e598fe4eeb057337630eb1cec7a8c6224a55983fcbcc320a783ed54c0e3dcc23a57d11e0e167507036570f36b730ea6e9682a40d2b90870af9bbe2e8187d8fbe5711076f5824aca47730523a07a47ef257a639a84458e53902c796acf05ef10a7e31d56ca85352a39636549ca5955e417fc825ff00bc993163e2d5d4d1aea7d5a28d7de9a57296935d2432ef58f8c8f8c8f8c8f8c17a7c365cbb699a4a464bb545252d4ac34575f4b7187396cf1c64dcd9234724aeacdd22ccd62044d6b6f8626724dd3ae71d3d368de0ccdb3319f86be477dbe4f6a6a36b3331fe5a676c99c8d4676e7ccd950d7b84fedbd1b8d55c9ce7ca498c31bd6f0c5164ffa2ee9a3f1683c1a8f069cc1c2f06c578c0b7349077f5d516ae24c9322e7f17a5591e226ceb51135f01bb3311bb331d31522080402bd440974721223287a89668ca038e725ad28d5c9c949d6ba202549622125295dcef6565ab0887a8428179db3dcad95d75570dc285f2d9857d0379a6fac6fce9187b5a25313af9d935699929292b226bcc2d94907936cad85aabb14b96e979ca921754af387d56ba585fcdaa03458283e8a9ee65d43ed8c7f9beb92b2646b5e67c8e4ad4716651415e5c84b4eeafd88ed8d35a1e0a3b54ff0d6da14a9f7f1da31565a304cc3b03496d530dca5b92aa763b410908de54236b47a3eb6635d1b0d5561cbbd599aa5599aa559fe7a900f3ab7d2626decc06afb03c8ebe2581c7b63a545b436e2dab0362fdb4cb73aaf3364d637b48232eb92d450107a636fec8dbdd138eb9c60b9e01d98074bb2a44641078361f00b7e5159960bde8179a8b0d0a4288a7a355d15ecbe4a2e5a43b3d968f805bfe017fc825f3820348c9e21350f9ad72c16c3340ceba2a85bd665715e5fb669699d0f9090ea21201f1d4bb39ccaa23497d52ccdd22ccdd22c1990562e764f883aedd9e8ec9bd1793dbc1e1e8dabb3ef74ae8f4ee7b95c7f33aee7c3d509b90afeb8426ab3a616f26a518bd6f632d21664d7932d49b6a06ca7b790eb55f4de87e4c9a4952a2893f6b2e8a3f1683c1a8fc6a311bd503934f99c73eed3e21e1bf5e919c8dcc6d8eeb0fa99110f5f3f2e1f19779d9516d63f2dd5bd8385aa78c5e8de89ef38ab73157c55d5e307e79683af6d7aeb58b73e6249f0d56a1f5485b30ead1858a91c7ab9f891b1266eca482b056987493e32a6266dd61981aaa494124a591d442359514e4ed6445e5a2b2daa83e4a3abaaac8364754dd7452b4a2635933c591319a9e9e4e4e4da4908d64a0b163dac0852947516562413c1443029299b9516967516d686aa2ceb14457d63559546f30afa47e775f30f4b433bad4a4949494959e9ac8b61031db27d91453ea8811059ed7ff87f8cd54a8be994349d122254e15b04294a9a5c0fcafd7a92dc98c74855d5c2549c285b8ba2389c692bce55b0b59fd5add7cd2b5855b4aa7040fe515daf95c4b92caa524d8f818f76be316bc26def74cc6e76ce39762b2d9cfbf8c0cccc9f19ce398692efce705e7146aeced31ae911619242d791ce0aeda268b389369b68b399369bcd4a8bcd66e3e222b7d9dcb986d1d266b3e9189bcd66a2dee69be9b539df402755960b712097fbb05ca772d6ab0e6773bd83455109cb58d36d18be90a80886df4a0bea2ca847453da8179da2288aa21e45bd57b9a9f7defb837456af904638271a23f54a4aca2929292973dd8b76dd2b2d26e8e07bd14a8b686decc045ce39c95d6a895a1c0e4228a977fd72af34bf5e1de5a83527ad8e35f492a6db447a83cc28ba373af262d7857f9aeedce42637b9c9496e7a8fdefbdbbddddbbda35f45bf2f61a1f62873fffbd22fb514457777ee6fe71cf5a81f92f8f4f7e38bc4f9d85ca0ccd1aae9589c8fcd554d08b2b99c7320ee9d8dbbe6729a5fbfdb74403c23227e182e803f007f0c7f891f003ffd69254155a6c34047d08ac28d50115a493c21b4de75369a8b56f5728dea48123c9dc0efb5f7de7b2e7887c73cbcc73b708cf7de7bef8f9a9ad7786d3493dc4cd754d2252d8aaa7406695de1179dc92e093c679b73aeb498738598937bcc3ae7cecc39e3946faf5c7dbef86855e9e9d7545d98452385ad8d37d18de9c8c90e09cc5253d1b53d8a2250048a4030828f32d810468710be400842012b840c217c87f15052af32d2bad2aa949d9c74e454035723731f9791994fcbc787f79e3544e6dca3fc9239ec7d8a6f29bdfb1f191f191f191f19ae46db42b7eb7dec9e565a3c97a8a347d973d1ebe151d7dd2f9b8fc81d9037adf2ee83d68b3bcca1d5a3a1f55c3187702c1bba6903221aa2ed888278b446333f76cea3e804fdc7a3e804004a5ce4517422867f1e452702f011ef241e002c8a4a62c0a2a8a404f60e002c8a4a2886615154722c8a4a1ead2ad3495018684531825610e8434568fd432808ad9e0fdaa1f5e2d08bf6b99a91721da25a7b91f6d178341e0d1838428161b00bde817958d7ce39f96769a8cbcd4777cd34fd72b1a4aafc45aa2265ed0c1fe517fc825f486e4c68cded4c738e9d5b219a9be99da175b264755db4aa486b63cab8362489633666637ac5e206334daff624bdd730daa563c4f75ec8eb03f978f5c843c969fea8e43d4443eb0b4cd22dddd20e3dd9b66992a4f648147c550c2eee9631b8f82dbd26751462c4120a0a8a949d804e669c74504e50665c4f5e3fc4a844057164830d0d24710a8b12222a1774522e175cfc2a65d293120f7e517486e118866b4cebf223f30b17bc03bf2061926eaa6a01bfe0170ca305173f925efb418c4ad4e6f2c226963deee3f271a1ed6e1a99f9b47c640051e5f591213f326070f123e9b5b6ad87189568925a8843b74c2b3c31bf761851d49f631889bd4ba433263d562cb8a437cb12602f5d327fdbd666f7885970496f471b2236ef71688b639aa47349a3fb6c6fd85893a5a0869d49ba049734777ea2450572c821871c10e08123606f2c01305a573269ca405d69342e6ed7f4901023d536203dceb4a34f76c151cd2d09aeba2e2e374483f2d46e7b33d6c46d738f46af93680b26c9617568c126a4b83a4492eb82e4dcf3c179605d7041073631c4b52e1a0cb83cac0b9b888fc69ac0d78383aec7bad81d36c6a3f166b4f85c5c4407752c1094f4ba3059b7695df47bd7e5f1fc24241534b9c8685054885189ea5e64a4238b2e42561a5838a304576d30b2e0e23c6c3b3f2d23331f1994816012253010ac0436216122a9551a8832a97d6674e09a0e044c16ae8dd15a1a0fcda5cd683db009f991f171a90e08198c16a3f1f091f1699123330d061059c368ad32101f19233ddc0e58044952e2728d465295438b10c655a3976c5ae10ab9371390ba1e772fd8b65d45af8562612866b06688aa1c2ea9b5105cd32bca0c56b836539180053820021458d1316aa404150960130b04ca5956bbaea9d23c50878867ed8c7bb1858df0c515ae908b77909a3162f37061d664b786c43c52c406aee9d116a416d363039494f00a949431338d6a2f21430c8c935ba3c92649d59336666dbcc01cc4a884ec5c273cfd28e985853f5c1d115c1574097185a8b7ac82320862132ecea022010ba80ee9daa0e8de982548649832445e8832a9ed0f20b8a6d7123208712d0845450216b0381ad580004299616facc9ae0d17cd1932da286e9072c715247c3b7c61a5cc0e55b8422fe551540a8b94aaaa3850555f905a6b1cb826d75e55515570ed55d553d6e4d197f2288baa4a717f92a650efd0d1870309db08b4b012451b0115ae108471ca865d52d09a2ca427dda8899a1cd5282d480d45d3e19a5c8b1405a9e05aa4a8933589b49d80d644a2a44d511b3d91b20743c4b34b3e7ac7131960772e8da4e6c2524b2b96abbe679461e10abdb7ac3ea3ce261caca8f741282828ac728f264579075e3a318f88ce14c1265a244d5c90a689634c2eaef6ed889858b836ab25486400a1b00969be695d79d633bc840cfc6287375d482f5628452b95aca93d29e8906159e4031ac0d4f0a145d1b328f26cb730c9d2a5d23cc2b5547a6c42468ea612a24c72fbea03d7f4cdea252712aea5e2fb2f4112e94a77bf331fcd481bc69a4812045a6681fec21724a9c226767549bbc4fe9e44214f4b7839793979397939b1765f4eac5b8fe65a56cb4b8f5ea401e6f42a65271236814c4852925e2c0974a22208e9c4b2ac130b6c26dd77c21c664d8d08d28e0602ebd8aca79e3e725d7a577ed3260fa30134ad28599d7f7c8f957adfc2a247da688b5ae593e9278e86dac99a48d494eeda49afc3a48671b6b386f7e913b60d93a2014c1357350319759f307815fd9e8b06f072f272f272f272f27252adbc91ad588b56955ef1152bda8a15323156440dc6f99c3ad28a152b56ac58d1de3587914c3641687d6a958e91d6a944d2780c3e823434ef260dedad6d8e924f522b22a3163e36095f612fd86c3a99fb355f705d05b73901cd39ef4983bbc65d45c7495ad874179d9cd8744a029a732e6c1329cc7de74435924ba83b78ea13ab9d8c3af5893d26a1bec124438e0e3290c17b345f70dd6134444cb222287871c94ed6dc207613420aa27bf0ccd46f3fbd4fb44a779fd1a757a0ecd4f9b0f2a747d8235a418eaa701645547ebebe4fd7955c4a55389b769a5a94b1987ab6364dedd324b5d63a4ab1a1a7d6d19be48c7f7cd8f49def8ad8be3d62fb87b5b7af06977d625885cd9e0a707f190dcfb5a052775dd9683649ee04c24be38234440bc141c8cc3c78cd6c5e1f888c3a7fff7807c1a2a8e471b00d959a936888a2926bd7a5c30b46c83c669887c433dbc2332d140ae6c132cc83675a9807cb300f9e69611ecc03459fc0215228ae78450688b2f678ae85d4151960b3fe290edd8f8ffa849cdfeb51d4e0540075771caccf47f04e63555301d4271cfa443f3944a43dbd47452f7a4c69b2feb63033f30cf3d8ccb4b4b4b4b496d65a6b992c3a5a7474668b8e96161d5884009610ab2448d860110220f61ecf6bb0c725cea9689e0a781a8cf30a03f9857d9070b08f974847b4a38379cec1460e8285fc031389cd730d36f20a0bf985892c0246443c214cc2c11e97c07f601e2e8120d8e62a1804abfe815dd76c1e0805c50c4cb2d76017f62ed95b2d2d2d2c7325f28c11a53684244407c13d5686499c35b7be5fa736d13b07d3bc4fa7aa45f7d461559168083e421a726f59a41bf322b8321b333549461e11d2eb90dc50014f27ab3774245a424646464646c63d42402606739489212313039361aa326420cd1057bfca9035f32f13c1586c25e1a4b5d640281bc99c804e50da49039da09cb4d61c15a4934b7a50b2ce3b9955a455aa41d2ea2a3a9a559aef11eebcbc8a9ed87b282727d0876885ba39ec0e6cc2440cf76e591d9a45a3d16834dbe16c56c5e4d63596d168341acd898f7fd00f904fb4be2e5910caa19b6f0e0f5225b2386ba87eddc2368b1eaca21c38932bd12eb39643bbe29bf50bab5ec3a6ac5b58844924328050f6d76ed8ea41ac424a8b6026c992a248b2a2261966214a4d082988eec1999336a33654f2edeeb5baa3358299f6f1b95b8f4ed11af1427e5ccaa291a22148cfafd599abaa3d1aaa2e2b4953aa943591a87bca9a383751555555d5231611cca6442c526ca852aa884594624355a52840debd611ddfeb92ae01dbac61138d98c4bd5f70d1884b2605bc68bbabf80953d1f249114cca353df05e2382b4a381c03a7e681c3fbc745ae7e55d8f11c38ec8f4918a29a4233a9d0e841d08691475206c1dd8ddb9ee2e2a7540dea9ae815c029168e7903a47bfe4782f395e72bce478c9f19243922f5995bebb2bfba583f054951c8de387c69123ac38a8e4ec198a6aa968400000000033160000400c0a060363d14494043983071480147a9e50685298c7142589410a19840821040c1010000100121200000db1da1b6931cf903fc47be11cf835387576b7ac08ffeee476bd26af6401ed9f15bc28a363a326ca55347ce4bf19c54351c88dd2cbcdfcb1adfc022a5e35bf64fcb1998a91447fb9bc3c943705b2c06a15cc963626b6325392fc1b62409129c8f4a37ef507dd4086cb28876bc38e875f653ef9b39c3febefdc876815249d5e4f52bb64d4517bc9afdd006a6330c02b136548463291d4951f9126ce87a2662fac01f0fc812a370b94268685396f934703239b70d785d4ca92dbc6f2320e909e3447ff3eeed5ca276ee4ad780d8a447751815527468cb0edfe99ab51a14c68cd5a843600a1c5841970109a9d45843c3206ab4d7e3fe61a1429e731945940d99249294407e1e6d25c1a7e8551e5a1c00705107a36b1a87d14af5d1be2e1cc0210d55c1b446c83e61476edacd7291d609b2f90162f47967465d36b399f77d5219f88c17ee28d07d1fecc578e1ca8729550bc8d1a15272fb26405669e321927ac869d77e16443897755427f5c5a6c0a8461517bb06d0ced04dfb456c5cdeb7c3518bf01b39cc1d26ba5b00e4391843de8d8019f0546ddfb1572194d6310e0fb7ad988cac250ba7cd384f612ef67a40fb21c1c659f39587dee1732a735f28f89dc4274bec86097d90af6f8c3930c0ad9382378b4d273c34d370c7ce3a77198bc268bf3cc053293c0e4a98cb89799f42724d6adeb0651b7273b8d3de36e163d282b1e56987a8331d2b4067059088b1c60004eddec21f5f1eb586a9dc1da8cb06d37b4e686d69bcdeb1e49ff685efccfd64ba74c9a1e2b5ddeec4844ed499667ba016cbdd2dc31558edbe681a577c28066546560a3983b77aad7ef7f9f47b75ec6195377a73e7e6168f63601a5f83c44f81f946f770b663875683fe5f4682025ce60f61159c5cd1c5b891069fc5361375d8d2606d357be57c062ea4cacc3986c98f939dbf1030c2ea0bcd6a7a94548e2b90be6a26725b1b90110ccc49cc6cc4fdc6dee4a2f98f6bca912937412e5f2606858eee0d44ef21fd0b6a885fdab10db6ec3ffc27f4b5afad5e25bfa924fe1d1eeb25ad6fd3785666d12626d93d6f3ef2ae12abc9bb2c9a0036b7731ca82b7c93e4e0489273c1a69fffcb41a2bbb9769bc9ecbf96c3d1b96e76db1982cf7a6df66efa6c4ed9a4049b1930d1fd307e74729f621711e7b0e44e329a77318a1f77cbea58361b6e2740eaecc1c419bfd5ba474aa6bf0a354d32e53c8b94083b0a2e23be2c0ac5b7686269730bedeed8123474aed9a732c87af4230fab334a7747618b3fd3803e8c72a827a93e803617f5353a83df5be1f14e6d7756b1f3a40f4fe0f283ca3fc61a5e468ba54fcaccf29a4a4364bd3417a813bf869cdb61b627a448378b4e517f0b2a12e461b6912067928433c51d60ee8f58728c6e241b99e634bae4c87cc946fb8e5dd9db83cb14878a889236e2ecb4cd78d669ee25fa3583774ed41239805c4b3f683793a0af6d44f6dff93d9f38f9009192cecca2fa680c6362aa92a9502e1a2f22ece5806f2026093c2e5640102ec0a1a3cca301307130497a3cd3ec8207861efa00739d99474a72613014fc23c199d44411426cb1d839273f023dc5c52bfc84ffa94f800146a11c4172683270df33cba893d842a6e3f5c76ac309fee12eb5778d59133985ddc7ceccac7738e6a5885f19647c8834b382d98292cc0d220efd235b0c9e5eed18448a71ad4387a39c5330a8b4b60fabe7ee5bf571dc58f7e834c409525ce4f42667da7c27221a762cf92a24297a361b9a1c08984916838e2b90ae59912e0328bd177f85cc6c0105fa358b5cc3c3ec7c7ca4cf5594470de845c2a0bda887bf06b102ab4d4546bad86e73ea22a8ad22bffec041e056ab617c9d38c9b9ba05f25711c0113483b8499465f30afd72d24562e5f06ff0c18076db2e1625fd1dcb10c47150ded4e39c172dd361629b7fb8eca0b11d6ff5f753a012b07c06140bb8a494fba4189c3b5554bee81c706bc071d086eb3a708003e46027566d7a510c4a32d350a32c38d2f46aa1d0d2f1bc643b728d2625b8e8dbf60560289cce997c8ce84195fde66df9c44e86bf465662a5e14dc459dc4bfe52e5e35a71acb79068789269c5d9a6bd569b9e2fa954bbfda3b7e92a3c0a0888860d87e82ab987299250a6ed9f803c918914ee886524999c89e62111445b8d7faab19c590f20924bb086bcc8fc13925662c0885885f90b4e01d46d27e9b9728930040804427acdc74a4a000565c9b193cd6016b1c729c20253a5604fa73414a179d42a910790d78f302bd44c1c0cb72dc1dd8735cdafcc34ed50086570360f1d14a8e1a859fff88a7a67277153464311d8a2e75c261d5dfae5a72f5c5ad1a1d43f59606ed283536914ecf2db04056886f6e4bd3408392849fb84901059003a3b4459ba2c28939b05730cc5f4436058318e6172691532d400f6b62feaf20f6a76d4f2f3845f8210b41a24c9ab3a482590bc51a84a846114b3c18152967b7270101bbbf62f1971d416f15e3ac9d585c195d5087ed86ac123629cfbc3ca195da92d4994a981dc975b6d16e641b2f571d5b54e4c1a6173eacab89b6092256cb950aaed94828a0c12ec871fde102cf8e24691eb3b8d0ca0eee9928a4a15c1367c289b0c113d447a10e2ee0e174d840631d8f7e397af6e3474cd373ea18c56549b6b02339a2ff69a0a75ec7d4d6ace58921fb64d6edf0cdcedc22e1b83b591c4b07921c0a8fa5461b164ad7fc22b7a5ae0544a41ce377521e928572437ca884d9b81cf2b3ff2f30666aa34d8a5950ed879546469101a2802699c83c203327e98a64aaed438903521d9fd124d025592c9f489c1b5e4c747e2443adfe1250764ee434648c0229ac589924c9f210d2464df0499c20c2834095e9163e1108858b7d31591892b7099f16914ecc032871a3032640934c2eba4a3edc7cc1dc220ab421e3ad17b432ed53cbd0e2fdbac8dbaa3e7a2cf272c99c8e07143c01fe0701551001935d972a825781d8785c1d1346a9aad4bcb500d13ba40c456624b6c004107b369808193e73f39c78c46dd03938e0059787ba87e86b6d564c748e68c2f56f14343c6280b8f1f0f27ac36be9810d3f0d58457020c8dfef9eb903865bec315982a9d5b46f6b8e4925da7a352aa46743e069e32d3c411bd5047814482e8fde00644d8d760ed233383ae1917581a52b07dc8a6580d3209abcedb4f17c283a1624acba2be17705ff70708b9529187591b4a322bbc550a84255a1221dae3a5b04d1b96638a8ce029b034b28b178fef4e96d81b1fbbd76f382d6e44afb3d61183f5ffb4234462a1f8cebcd048ae1440d04cdb6839b90fe044a95adb1cec8cf40c57e6bd84988c2eacec3d2704744f756958a6d09ad633787d7c0ff13f3848b33feea64d5008f18df8d9390dc066319800e12aa7bd3e7ba36dc7551d27f98f6245b9c9ed67278d90083ca3f84a37c100bc90261720e2137a575eddcae26cc9d63d26c31b75235e251eadd563e185f179270e2c18d9a0e8a8a79b03f30f52d51dc338456cd42609998c83eb81ee6476438ff07be23f18e6254cf8ce2a6c5cccf15f0822815983d2ba8f2224715e930ce1a20afb895a5f6b02f1a792c4e93e2bff8c1630255bd8792d24e16b35470c5980919a716af5ad41678280d5dc21345bd0a12d072f99022275f5d0aecc225e592a7be5269d3bc4545fac58c2c61aafa205a0feb619aba5f6885dae185ec3929bce58376b47e323d290e2fd4a16bb5b6fa341986ae029465dd54a1b9a6da4435c59f6dba278f1c8318c7aa3dab486e8bde7e6d5aa62aba853d1cfce5769103ff4bed30b55017e65fc350b60f9180091a9b0422cabc2b89d1e77ad433a05f82dd98e331327455878ba59b60c0fc29df10b2b9024beb82fe4c47769ba127d6477dc5f0e8e7580da6a7d61419224b441f12ecc69a907371e27f55df27a1e81a6f077fdb99ae83221c297ba593c5e6c175e98359ca45c18fa911d3c898a14bbd217c094512a437616ee7c77711cab3b778609bdedd1b4bfca9f4d6e33d9a4b01e05e9826289872ea41f9ddf3d6aa5be24a94e0cb1b4a2efcb9b298fbcd9f1b249ddde7507897253fc4607f593d0fb20ebe865f04a4b417a9b7609480e6e2582fba781871718ef5fccd0d5b18811f2b8746f55080ad0e246a06c8a9ac496bcf994da5369d84ceb95cb9c6bad4dc07d33d2126a90e47b8c015fc0dcce634985574f7c7078ac611c52343ecc1657b53a4449e2c8c3bc55153d0b320f2730214b20a3e7531d4a965dc101eb0ee38142c69af2ac49db06938061b9a8707df3d95123c3645b126a170452a013ae318a164a835b904248d66a1d856048807d598c67f4046736356df1632c45421fa8907b2205a9173f6b684427325ca9aba322b8e45700d98c1465fe81aa5d22834cd799c463f9c2cb7f11ec7035aa591d2b01d0ed9bb4741a1508fcdd3e649cfbb94cc6a4603231dd2cd87552aff2e8ed4ff0554948be6e9bf892c5afad1f81144e0192d50de89ef12172f3dad380d4c36643769470c167b20110d0490ddfcb68b37ad2e0cc7be9ea015b2ab10cdfde5f918568704cf6420c3be754030a82e44e9cd779b5143ce2b7b97df0ef24a39dacdbbe5db7e2875c0a63f4a0e9246c19b5e2a0bc1e6768d902f5ac759b94b8bc628aa2fd7a0e27f91e7e28a3f57472c42568174ed3aea5466ba0d141aafbd08fb97f33d1c1bd6b078906206371e73945e973074b2ec2e704d9636e939e86f59d4786d70b95d3aa7a717601a646954c6fa29bccbaf461c871374295fa69b0fc6481dc209fc97e95c3123d8efbc529411260adc03e0795102dcc59d4c42a968fc44cecf7b10b7d4b6108e859658964e79c271d4e80d8c44d085fe2b412ebd911effa28dfc176a3480f946030c1a1130db3060e8a5cbd6ccb77dc180a599aec5c42fb9e79ff8f55f96aa54d10fbf64301c9785bfe05cca19cf6777d5cc024f66a4e0ae9ebffbfee8ac50b0e26286f757f2cd690f8bccdd9dbf1a521152cc37844cbdaa379e2eeb9219d5bd12aedf7de2f1628f7817ddf5e5ebf7652c45ca59c35c1523ef77b56c5a63316364c4cee28639c0855f32e25af5b01726e83062019fd603bea6dc99461ef15fbf0042c2a20fcafb254dac172d63c07af42277d31de8a50580c0a9477252910b4fc2dd04a4f40d1a97d7ca346097c75e63cb9e22110b482ce3532d7f065fe78c6b0d9f3aedc819a82ce65ac62c305d66f884908de6b50be2bb6c4529a7a7e1c60c29872d564b1f4bb973e00512f7b5187d604e74f5fd2172cd3b614995e3ab85131f7d4a730b5ccda2aceda7616dd062fef87526df3efff82233a8034702f07a86206dc521052016d236353802e0f5110bb16d345cc04aa921731c7d4302c098b30568419a273fd769a2d2c3b2e00eb671605c735ceaba0609f9e2920c37a366d4c2913673d03ecdc010ada0f9fa9210625d90bbe4d6bf514c50eec9c764287f1d6cb51c125ee247720402991129e918ee5df442e6ed64bb0480977a6a481fbcb865eb8b22066406ee7993fc4b9cb55c88e597d64358dce73541d5c60598c7ebc0f66deb1adbcaaffe3413001a5b8cd927140646e0305940e87a98a96195ae6a0cf2d2f1cdffef1a5c5853e4472731e67e129078b778fa65a362a443369bec1e28286e1c1497a69159243b5c8431079357e5eef6529c85009648ee58bb520caab9a10ff5977df54d995ca6fbdf9c98525781428c597510856bc8a7f4854634d97064a8ab2635e1996ec44258963c6a2d061bed92d12d0a75e8b705e8a45686a377212fc1d0d81f4c0568e3076326f02cde46b1197130a175395c4af1ded2685c9227043a3742132ef9edd7a893f7eaea605048b086f37e296080984a44de5c391766cca99e37cb05be387647c007ac8cb2d8b78a5083b947aaab72986680c42b41a5fa4fe9aeb04d37cfd9cfd216f005e2aeeba6a5a5b72acb98cd66293f03ab5effc98f70d5a114348f58499d4e99fd4485e2d20df0204e0a85ab63366f5a2026bcf5fe6a0bad5e00ac2b49aed0350c9900faf24452c6fab8034e71a54a430614428b080f70528346456c4d3e22663907e95c2f8dd76f1038bcfa802fd109d202d1aade0e3ab940f488830c97e17524d568c782c0956259a7b84ead1d1c6698b67fc001b1b721409fe8c35ed5b21f8d9cb71ed728f68ef883bb7f225aef60a343aa106c73acc476722a20e371b85c4ee4b360ba5731a559108a58f2d1cd2c51d7f9e493708981fc2bf29fb70518c63c133dabd53630dc7695d4fe5e13ce216789f2055cb33e43a335a6e624ca2de3c8700ea9463922eab08590c281c517d9e73e37cedf497776e0dfc8b2374decca073d9f5da7bbad3c8b45a6b21b65b79b35a8d15c7b06c961e822639200c2925dfdb168b5813bc251f22e6ee530eb95cd10a295ce5c9cfedc1f2e2c718f3b45d82b97cf9db3e9751817977466ba131e37112964c00f6cda91ff4cad0cf45a813d412c2d39c128380683a40f2761dfdf5fadc4e17e47f876bdbffd1a92764051bf0d32c0f4f1f635eaf3caf0d2e81ccc26780b9e57443b8914360ba4c9700d7788b67d8c346ac2940e3413162cf431837799e80f2a61d141c2fc41beced29b0f3dfa8337e18e7a74b89f809ba6336df23a650a539cd9c41f8269461a3633c1bb15a8d9d05775aec94441586b7ab41e34d51cd809ee39547ace9e502a2d298e79583d984bcbc871fb9a15e797bdf081ee3ffca60e816d07f52478df161781dfa57db579425c161dda48f37a824b9c841b1eed767f0f72d81c8b5155a68c26abddd9a3eb59deb68aef2564120887b70a276d0abca538efdf01bd10b2df9359b47c8188f4743b35264202fab56348ddfb6e53023d254120fa423bac7b932233e04d81987ecd36240f8b13a51ba5a5cf90ca1da5d2db859b72b5851a69d5cfc796b5f3128a35dc5eeb4f7cdaffdcaa2a67753cc62a724499c7f30bdb5998531235a2f28fb7e82aca7cf2f6f66963663a0f0bb3aa6967da43284be65bb67b459355d505361b56f5de41c00d6bc2c0e1e50f2e69670c6c2510b0b78fb2de505d14552718de048154e25f15ca5d601d4e5709152f21442aea85d9f9ecce541070319701486a5b6de6d0b68fc019f4dacc341944d01881f35dfbb5db15d5d536407cdd48a00a08f6722fee9da62ca7d5eb1f79c062e37e6043ebb0d574a2157687047865819842d0d54b9755ae819d94f21a74d49a11cbf1fa7f46c7e4a240790f0838fa277ee526300a42bd639211c5c897e27d3dd62f0810419ff91d736c7705543aa6970b5906a00f0528c331ecac3d65132252e5cfb738d22fd61abe59fdecb47f2625f71c0a7a4e8f2a35ba319710dc1bbc91e45b3cae514b1d35e92474ba5d00cbf58ac81b316c92c046a737ab77ba3ae5f427f5f99875a840600f3a251889c06c69b35dd93c0748abf2d840221e175b59575e24a0502379a81d1993f2385c22cac6ad0352c5a7b4569fbc8f24e33068b2069ca51260bc83841394c7c70377419c695a2ea57830fa920697fe773af9386104b5867e9fe77dc031d23d324f5f103f8918cc0870c65745e92450363c9441d1358a09e980a3406b492e8b56034ea45fbda1d2a39d662d89f30571482774596511a76a216c787d110b0818357eba85301346025a85bc7510f7db4326f8147dd948b7990e1c4d0f417a6773cac38759b84ba54571363b141db3f00ef6391e817846440e79bf8b6a345e785ee7c1c970c7faa7a83f169aaae45778fa236f0910ff93a9ab30b450b06b17c4be38edf28ed54beb2dd8b400f4d7149ed2491f086bc73bf4ca10b2ddbc54e0bb7a7da0f31ac09ef3918709c175e124808a3999ae3068595913533fc596adc97de00fb0fc60127713d3a753a259385247cbb4a8d2f3e9e6337e04743302cdc05c3ff120ba03b172d83bad44bf9d0c43e2d14fa5a4dbe26bf3edb7567b46439cd5af8941ca941c9f00a78bcf12fa5ab04a7155f7362bb1d7d70881aa6c49d6a84fd9d7bed25cf12b675a580188b96d7f4148c032769bafcf4488e9a22aee8cb2b223aaecb817e44fcc186499da0b442d045c74977a0182d657194a57d0b79022689d5c4032cef9c47233adf373a370598b61083019a09061e14381e7b5de3675e5951c2284b91f1d536c01a96b80d681bfe1c7342cf8aa13c58f7ee588261cc62d72ba03608d4a6c09017ce6178f4d71cabe992f1720ca6ad41ee7e1a471fec179d122fe70ffb2ae91b7122f7fd03a19eaf171852a7f2f01df6aec0cd211715f88ee26c417bd4f755bcdeb6bb8af7f11e21d23cf1412cc40fdc5249fb91718c328fd791f021a569ef2a0b4360acf1cb30477152e6e8960e73215062a5469d683e17d5c9dd428e7617b9f2b286d873a30aefa9616cd6a50eb45923b145d2dc181656dddf352848363793099ae70b7d148f076f75c876e663d67aec832da9acf9cc4e6ff47042b61f25341ea74cf75e05d6f6fe1b2c57714a9ebc86bb83785c384ba7f6ffa5ad508bd56d661077b46b122abee5efc7d17928b7d8c9f438d6348344fa852fc7c6ebeae4ecf73f21ceeace43f09bded1111ab9310ea9d110c7aac70c95693cbd679cccf2f415fa98a68d0b977d788049a2acd1b32492184c7307c59bd4ceb7938e29e7f2228d807cffe217e8f8425042bb7b8fd1d39c1d104835810ee85d9d002691ba31b315d7dbda83c2488e9998caebb5a8214d5686eb343db95293110d5a403316c62a68805c4b110a7a0f58cfefa6795f55139d461eed8380395a36a9a81b5bca5745838ad69c8a773c5dc9bbe52cf4f41d968357383b1011eb6c8dc9206c453698d6eee7df569dd3062ed606c41201d3c9cd5fafac35c041c6dba1639f679ada6a6050387bf92da6283f65a6b492ad7352d0d6e60c07e82d965416bc58bc7fb9c28b32c53c142aeb741583ad852539fc8ca7dcb6aab73d58048aa53799b4e7347ab61b99437722dd893b3ab8537192d0b48e1a6ea5ce035161fbae233b09ab3d7709a692144b7afc5c086b75c710890652102ea8103c36832e3af03f1a3675ed4f468492037845fe500071d6c78854ce9e5035cf0908d42af389a7279857025223b5129734086d9fa073e819f579612be1088baa747ad6a04482593c80d7b9c94fb329b6b584a22124b0b8f4c8f1754d2b62787c9d45b2802e99503ece3524a8e6c937ec76378eeb205aef19180759a8ca585e650cbcad607ecd1e2852e64c944555872de4aa72ecdcf75e070ad5036d5869c2dd6e69d3a49d1abea0ad63e0da33874de31e7be95287e8445ca7d1f21662b2b521284aaea96060b7dffb2c53d4b48169ec0ad79ae4ab61903c4b52ca4c9e5b780fdc11436f720199391c2a152609634fddad933ba2e5d9a5cb2b9c74df4bb3d24614c10bedf6054156908f7ce0a1734fbe00f94669951cedd5f840e9e35115584c20f83b5c32564db895c83cec66dba0e755ddf7a879263f8217269f8d9b6dc7a5eb9e036e4aeaf81376c352c9d856b0bd0c5da5e16f240c5397997d0f91c03a11e58117ecc94183a38bd9c499d58963f1ab53ab527f205f30b5a470e9071a60c26fc104025d13332bce4fa8612fa0c08a5ca40c59a974a74b6cf415cdd1ef4d8ad139d6a698140381a0773843e1ee27100ee834271691c36f6e5fbd533154a520ddfcff167b6814c80cdba2a4d5c8046605504caa6e68f58fe91331c6da7f049c47fe801a059685b37a7538468e141101b320aca9b15574e3cb40c0c4f63186251d7b357c14b3939ecee0e8b06093368e31ac552c4beb14926cc567df061d557efffbc3d23fb9252ac00d98eb3e859f0ca224b49332b42e8ad5f48ed5e310018deb12e138838782634b0fc921322584eab99d2b0f64e812cc434af76ee9183d7ae3b2277bd1c3c8e40e38eb47153666be33b598cf20a631cbf7d4a33cae5df5ad6663932200ad1ef8810274f2f74158630f448c0f2784b9ed7d4dbc9246b781d75431ea1d5b24b9d4f06c705e26ac1564fec6a56dbdd40971d2ac5bcb312d1e7df8afc194644949f963aadb5179e486bae8bec3d3cd9e7f34eb9265ba15ba2d418d127d10f5bf6932d9dd772127c402861284d219b9a02b5604c5a63d229ed490d86cb65284701284d66da7ce01061ce67e57c776ace4eae8ce73b12d28c8cb3fe8c68b93760a9f0ddcc57576150cb9f1be5500aa1ff19e29d507c00d304cc259f8f78ca64e2d2a3a6affad81ae29f5e02a4a75b63452a6986e01f6008e8bcd2425c572da25d6c9de12654d30925c0211cce093df0e3306b306cfdee61b9b6563457dc5f544e8a4313ff58442117d00f965f4caa82632ff86ecb928b91b573b826a911268bef3e737767a7481fab72c8847e0c91990a1be7f9026d23a8648d4b292ff5d91fbc31b16447092b4cbdc11869da3331c873b4162775b7bbf8a364dec86255a0898a939af086951ec2de9179b13fb1d9be0c61a2c27f443c80bdc5932ac03d8e54f63a32251a1feb1ec64926eefee9c00047723f0405248aa58a009480bd4fe0789d28fd2c20f73ed4cbabd2cedf5bd6a01b5d872ecd8ee3af1c63aa598aab739ac6aef0a472fc30db39c414fa2dff521daaa0a0f16ce0791eeeb11c2691c14613f13c0ca4180ca0e36a6a241c6bbbe6aebd2969cc32b67a761b52387151423981010abd9a5cd265b48a891ef8d669b78365aa825b50ef0e939e701b2480eb5cdce5d3f6a0dcc5b40b850db4a85734abdd0a9c84638e01c9abbb63ff533bc2c1795616ee0a794693855013eb5267093c36e1a8bb6de3fad2f23a9a4293348659ff86d3485c371d42514626ed59909cd260175163186752c5c96065ff548d6872f9ffd3938d5920a0f9f62478ee723664e3e991c8214584d5497ec0680e9a1054c7202dd8a91af6639130b17b8287509d6b2b67a4d58a99e06ca0f8477d7a58369728625b20a2d9b34c75e2325199e5a1c95832279ac6afaa0b26fdda0a29c844e387a124e0bed0ff36ca615e4c943b08dac0b6d81b052e61c2689410f71d1a73aa3a0d98b497f3ed46398ab9e50f117f6c14186930c421faa6c36e027e783b7eda66e846c1c1bee85bf4bbecec6edde2252172e9eec97e1a0b4778979e17bd7cf3bd7ebd22c7cf6f141bebc51966ca6b614356e2fb14f68344ae0b2c0a6b63567476ae568ca02352381a4215cceb990014507c8d8fdb72395c10c2241fbea96ee2217e1c84d02ec5b9ddc3152516ee5e8d5db8f8912d878d80be9dd40996af48fce439c096b3f8a98243e3fc5a4dc5e3de5e395c07dc97f1aac471e035d8e2bfe15050b82d429cfb94ba3159fab44c6ab47da0a85250d7c744106e30173eb1999f7c0aa744e1be5c48bf9a7382252131af09378e7b30fa0dc931b038640ec914560898d67672be58016b46744c26f40665f62e3df19d8e06c678596e003970d8ef27d4ccad6606c604fa35ecc1307b6636dbb9e2e0bb2655a2e6853da0405b46b34c8dd896efbfa8232fb76ca72e9f81019cd43b90f17258c83b2647cff6edc9482c2bc70f8f06f2b5f85ada409645c2004e4467e860bcb94d9515ad6ec6bdc5805e64fb61d370c78d8521810c4beeace647044caaa1029895bc081fbf144429cd43511a617168e6c284f59637c3e5a4f5a54026c7b41fc033ccc4a5eb3f5e755bc53c78a242485470f89a75d3886e3f3084e2fac63687d909301750909e50ce1d032517ff3cf74394c0745fb55b9eacaea755b49ce3d7ffbb5006e772e44c515634ed070b3d17b12ed00bc804250795e366acff3eaca9fd10253d85a7e42d910a04aa4a9f6e4b444ae9ad38e8aa55c7c98cd28a62d77d6c2f8e11e68256145969a64064afba6907db245101e8697c7ea13ddf006ba009a0317ad1f13b9a8b8e093295b36c4c60b63f69201bc9f80b0dee545dd1424b7b5c6b9e86083d9944eb657fb52d3f31b9cd685fd0dc7b1569d32363972af0fa79f9eb594703db03666a0df809543a49cbafff6ecca44f7c4b060b0b0e26e82a14450e01fdf93721f4426f6f0112b8c6f142a8e2b36ce592b71722872b97f087e6cd032de86d7d37ad077239ab59cc4fc1fab31b1707b3475dae35a549257f9ffca6c91803436d1578ea785983009fb0ed6a260a78a369808e7d9443ea72db6064ad3d81dc570c439a75053eca6c2818f64de745bd038118e9f8ad1d9c121d6b9692ec03c357664a032601f14977cd42fdf80b1ad8acaa4c2fef26abdcdfce576767b43392acc642596ac0d703a36f703bce422a882f09530e5fabe2fab72e532ef80b191d9544c2ba5945c7e64bfef8380d8443a19134da2ec89c6ae51d0a3958137b6d373281bf2f32295307b6910cca3cd1a5017e41c3aaf4c86755dfbdaa48c63bdfe69c9cc5c19f4f2ffa2ca9a13e0bdbf65915d7dc51f9915df6cbaa72f5b7ac449d7631252862e91acc5bdd8e2c06a45add2858dd1ffaf624fc6dd02a309d596aee95761ae64656e98223cdc0a058aed3088c39825e494cf737f1b08f64eb123768dc17677965a736bf361b6db278bb5b94670f5b80ae3d92b718fb3257f07746ec6b973a5b9ac9145aa4865755890c7341e800c2bef8f1e94018eac82ecf5714797b646ac8d641daab482d364b1d96ec139d535fbafe990274e5c0906d33fe54891fc8dbb44ff5c0a70d115368b53bbb8bd97ca1526e082e4ff9fb2ebd9c69453fac817ad70a4e6d6fe3695678bba6b33bcd554e122530a042b391a5aaa8b7d842fd5cf6c85a3a48b8079ea9f921872464c996acf9291a799a62506181441d713e408fc49afa6cf72a5bea0bbeb9eb092994f6f2b7b61258c81d96b3a88e3c40159c42fdaafe69f74a1270464f13b9895f265ea42135da7d756f5a0192c29fe74a98f30f14e80a86f84bde46224561f4c6376010a0921e57ba5ae7bd5cc91f91e90255533da8b6ce3e53c0f6b61d4f8e97b29f10f32940890ab7eba61b8d8e5e9750c7ac36c947e5a273d44911cca3855801e7aa0587fd597e32fd84d509a7263cd8b877eab153a602ee62862bb0bfe81df77db6c25b1af86906910bcaefd65e5910a14f04694e004afb59283cacf30e35b8502fa462c6332bf3b8eacca80600a2f5c6f9816f267960f456a5cab919703c4a90e7fb79fb246cbb2d306a94705fa00caf84fe8f9027d24656a9ab0f5f9a8d4964c463a0af65943ad80b8da53136f2ba348a1e889df41c6192d228c1f7dd862d0cd2a88314ffbb0b4883176391d5db90df09755b1a78ee44e57cd62778b075977a671130c4c442f075c55d3d4661056262633fa54aef6e3211cddddd7f3c05d1dd7ecb42eb713723133807f5f0ccd79c24e2a83f2c61c42e6887d4ede88567403e3fde8731127c1c40114013f38e7471b56192a7351237a6cb9a8f5bed52c507d1dec36719f7610f6cece89b34b29b29f469a8bc064aed9028b4edbaf02cd3f67e8df868b0128c721e38a1b878f6c111a2fbd5c6eb20860ccac7d72f6e4522f76c5b03d5f83a46813febad77e7fd3a03f24791edef1224963674b91729ef6fa7a65f234048f206f0f5efbd71e447881bb6ccfe1a153f2cbfee84d7c0e48bd015f95d2a8faf1f31fe37e185c6ba7ea31488f8cc2c5339f144c02c5c022462aca0aae16111cf4ab7bc363f25a16829483a562f48d811320305c2a702bd85d25e0ed2ca9e55adf352f9c45bc1eec570d7ab822484329406b8cd544ba7f6164b817e25f476c54206218db376b3d2a59bf7ca72bfb6223900c96ed8f764596fba8e3b03ded4f924626b7a8612765af59ecaad4d60e18766a408d48b8750e0012f6f5a9b552063dd685012b59fe8d470a059b4755db3f25634f0a438082a947cb09b1ca8005ef53bfb2c673ff9c91bccb6071c4d96b1aee2b2f8fcb05e6223520844b0f92114109b492f0f798345417a3ba0108b57da5f5025de22c44c2bd53e8fa66e8776e99aae07ab72fddf0aed78381e39dd60b3d5bc140022629c4150e5f2c9bd4f5e0ff5d308a36b6bf91809741b0b246f9784768b071ae995f18f5524645ce2e3388b61d7f457f1ea0fbb74b829aca1c82f47e2c1b746477f3752e24a1ec4d3fec588af7437cbc54e4f15d30e55df5344fc100bd01c72e47b383c16e097bcb6974ca55f163dac2fca4689e64d06002e64c3b85ca910541237653b1681805065f43c77ec9d58fdc3e328057a4e098a932877650c890c6537aa2d8ae022dfc7075232a87fb999dfca52d325340f62a9f6825cf2f57634eb1f2484b10d72f200cfae32bf77c95d2940048b5f89dbf461c5b0ab32b936dc8e76c354cb8bff1bb089dd4cb71fc78a25afd5c9b8194ba7cfd68af8251276571fab9a2a214409fbf8c4f9f62a87e9925e049594af8c21e92509189156c2628074bd2d516c83bd4c4329754cd0487cdf6ed75498e7bdbedc859a730a7f7f132646d50e024c7ce42491062123ab455145f3900626a70c65e9f71e78104c5177332a35d4abc3d3ca7dbb9c09967e326be7bf06889699c3f08f2cc57f313398a37072d7b775f3f907158cd7cf26e81020d1b79d8931741a107853033d403217af97f8643a4472b41e4124d7d2dd66e9257952e44c62b97a6a0a41018fc15bebe7eb92c6253f3d10249e4e8762d80598af47692f0408d88142698d222e0b7ea34fb48c73e554814f7f9c305f996d5cc9d74b3a5c7d221f468a5f6b427b9cd618792a25f97e520e6c2d9ff1ce8c6028991b3cf79ed0daaf5880af5a54ce2b5180b596cb2cb56703e5b373c704b8f813a66db036a332e2da00d2fe3965a789789704436f755ee31a2f7245368a0bee5a17a62a02b325cc0b1ae6119998d9a3fdb2804e401333484e4b67c64758bdcb45c67a1111226e1959b538b30b3e0a87a12d72e35d59f0893901dc1826385fdc6ba7b628137397a6a9304c74784252a6b688a83c70841333358e07454d202f735bef6d4ceb38b744aa22a1ae634dd144bb1d448d325aa4260ea681735afc3ca06d71ea5d44c9ed22f3dcfd797fff7441fb8a2bf7740d2a5b6dc4c7f31a5f0d12cf13095cba14982e2cdddfd3f2a76b98816ca788465737183214acb6ea27dcb421ae7fe3bcee22c953cde01c3f3bb3f2e6033c7fd4eb766c9248758cbe7446d78d7e73a10f144f84c6611104e4401f4414f9c2857da3acad1be29c1d53ff1c1532d70f60401f0c0be24f0ab2790dc11e4ddc24b34add8a1c1e4435f90db714d19fa5a09aae39b1ce2572d09e836e3f5461383abb633e12b9d2ef7b41688c59065e8503409531f40d1796593b6285dfc8eb796c680427881a3d1f3e708efba17a82072f08e100029d60020c1959abf46fec4d1e09e81266c34bf2c7a868e188b43e06cd1d00ba7b0445830c5a7157084772bd1d78a6f288d50770585704e608884f81084a1314006c7065e25d5115e19b2aa477f93c7c3556741b841365718e0fdf95a9e359d1815586752d249d50de19d180262c0586532741a2a5b23157cf22ec71f6434f390cc0bd9b964d5c4d4f771cfabba4835700121850592177247c56f333d78eb708a9ee8ef1db354817688a2d390f8174d9b25c900ed96c4bad95ad289899722f83f0c67524c93728eb379dda7975af1556017c247e5aad3200ed05abdb845cdb14b5c8d8a3209ac3abacf3b876c4330fcad27f6e38047284c8d36e442e887a87bc6e043cb40bfab7e74585fb28096dd12c42b09eb6f9aedb0656e75d33f5adaae573fe2df8af5b8ee3f9aa74358729ac1ef63b31217e589b53f3fd86c6e8280ca412ae09278de009871e1241406138638e82558efcc1aa810a86489bb6a459d46e00e8b47c182b42d536489f049499daab56448c33c9454c05a9bde55a23da8b2b27c01a900588b311db1f700106c6f33d05e8eaf5ca2af61efc0270ccb94882fbeacfdfce810ea082adedadc1468baac0b6bb1a08108ba165bc4f71707edd2448e3bf2c011fdcfa770dfc9851a347f8367394d507ba466f6b64562178af752408f4081c3a998c9c8f810caaba2cba021783b75df7237ad0bb4abb161403e741e6259ca8c83d6106b0f007ad5818999b45377e258539507504c0f8454a97748e950b6fba1e08626aa0d79286d44831da1d0c7c12cca8ce0dfe0fd426922c3df06a6d6aef202480f38aee00a8a8eaf49d5cf199a59b5cd3f9e30e23e806c22bbfc339c64e1f2790eb708f49720d0af75c330751384268f5b6e712ba0ee2a4288beef7aab2469336714dd765193976ae746218e6fc2b75a3f413b2468a60238c6929a5e9b1fe24813f95b8f03de93c79a522d4d9261830ca04cb7e35317044af356e6940161decf98494cd3d82a23cd4113e7c98b8cb6c9ed36c24546c1eadac466c83010cca630e1fda2b81446e70ea1effb5c114c93e88151203f4bb4e4c2e895dd47310c80b93c7d8db44d9d41860072c71219e7651bbf5d3f5cf6ca4d9c871de7e50431f87fb2380690704fd11ddefa4ce3044a57ab90e9bfd7426c61195644ff724004b871ea141c721a6ee154744cfcc36c85774c32196df919d473c7e6ae145ca47f29c38519553efc5386ed7139d30d2765a2d691b5e7e932ee224d24d1abf58ec8154682e1a245a3adb6fb24ab5c453385a4e3a63d46a2ed7eb923a86df782c74e3716f87812da472c91e04852b7f7002ada2cfa32c61561112ab25b45918a7c6c161ed42dc5625ff670e765e643267aa1e886971a9bf70c18df3c73bc1cf864321685047cbb565659a208c7a349398edb48dc8844d9f5088fb1d0a60a51e1d9596980b9fdb1ff807c03ec024c387bbf8d8c86d4ff4f51dce3507172c8b1c4244e16340560465bc75062ad451ee64ec290abb8919c0e257c886e8500b0d3042eb4bf07b45bcd25d5d79691469522728064267fb81d18eeebc05e5a0df6712cd2c6881f9f23ca4ef946af89882cd13daa03f30e669e1bb2d48289bc3796271efc21dec004c2984b3e3deb33a0b4a3bb574b7d300f7bd89b6d01c72e7d2d3b391f0c9209bc6ed207eb8fb03323d9777f1b4228e95d9572670ce165e71363d040bcea587ed209270461dc84439a8f8d6225f1eedaf5222f5e4d4342aae9993f1aa64e6c30dce482aa7582278cfb66b4eb071f258f163371561a1693b0866fd0a6bd1a87699bdeb4b3787d7fc76fb09b6608fde1886d0a35488b0866f224f6f1a694d48b3d2281f42700f1d847070f1186bc846c1e737d99d51b3a38778b9f417e2823f1702806fbb555899912ed4e5a0ca8147efe442f4dac3832683da8d87230e33e095f21d6265894f002272419cdd48d6c9809b48bdab975f0a93382c230d244cce03181b63590d6cb61785ecd01b5b3487db762865583ea813c696a0ef9718e79c7c0caaa6488a45a2ac8032c179d105fbe85606ddf96e8861a48f57866b6ac0ee0b04729811c33220a6a4e25f28209a2e29ab4aeb30172de98395774f1556ac756b86348dcd37f86915b4bc7ced33bcb30b56066ef96e6f4bd650775617a210074fce1adb1b480bfcfa40b680a2ce011676e4f34c15c16d205affc2115b4a1e58ab201264870a5fea983eababbe62e5818b757e1c7c03b3e71ac8d702ea4a24f4952b485f8f6bf21be08e3a3ce0ab90daa8bca833cf1eaf140880c6543daebb9fca75efba097f7cc69e12480f2f02b195a438f412ad4a64ce71f623c5c7fd4bef74793e3c43c7768101dfcbc81eebbddb6da996b69332edf90b2c20c1a8486145951f07e3572d1d749e93c3df877168d646ba15e596dc0b0a5b3b29052cfe8bc97130370f225706c6e634f56d78f48aa84be647ffb24a8884e7ef32f5e4362b2a12a173507a6c0d8e7a5d13a654ed687836489320109aa34fb96b7895f7cfd36845c1d4d740d7f7e3d97e383f6d1662ceb9fc3040d9657dc39ec6ba8e5865bc4902ec3ea1ded22f605687fda7c41a9d32c64d34c739fe709ff85b4c6c29209199951d6938d3accda101d5b98ef332a495f532ea1f948cfac70b35a97c6a9de484ca9f88753bbb6330ce796402b7963c2a0e19d89265961644fac5c4657a9c5a2f57f1bb797caf7fb8a93cbf7c36fabd577281f04aca21bb4fa03f3fb44b6df8f0d073835c4b9c00e783e61b27d983d1c0e3d98b69f0ccb3435403a4672fa9815626259326b14e2196b9be3c9f065c5e541bfc5baf006694fdbc4471707e5cf9563e8811c800f0fe1826b0edb1dffd7eac5c01d223446aaa790dfc1de8fa379035e60a7a4d3f0eafb19cf858ae34fbfa7c6c177a45bdd92df8b8aa1365c1602a810c60592ec3ca42cede09233a03bb118ed1dc8ada103b7c11ce0f5bc52d965a67cdbf566e8e48bfc5d5309ffa6c2b445d401fde66abcc420e08b80842014a027348ec764003d4d5a571f92859aa2d3cd92c24852ec8d30268466950ee32de8676981d1cd7f10306381c17facf004a75e3c8f990af28d3c93949e026bd5d0e106a5e22d300c300d6ba3341fce88aba86545339c439533635d23d7f366bb3c30dedd3c5a9f0cf582af0dd58ae02d42020efbc573e56566b5082dc896301f0865891a696e940a5290ca8ae72a64ef7b2f68e0579afb751e86b8081081d6572704ca4547c142950c4b799671e9406b26aa120593df506b429097b17bd14f69d4237c239106aa023271626005749a69420b8c1e4d1a64af4586598243e364acf86a96f2dc482727ec959787ef8709c37f67fe7047a27f03f821ce91c4ae6f8a9e976eda6481d3d334a65f214b12565f4e44b4dd9ca99e61c592ee194b5bdccbea48990d4a3e6b1812c7f4db00c7d220d7488276622a16c4bb8959d211efae018b3b150145347b0076c2bc2d440aee2643401e32175e1ac0d46e03c180288a30cf18d084c5ea95568eab186fd3076156fcfcda8c61d95a6fd5fa5158c4f468c4bdd8a0cdf3f5dadd98fd4cf56d990882ac2659adc70eea0a515b8352e55cbc216cfd3f2f3d07ed9d3961a8d2514c12d8424da5f64ec041ecfa86314066f4cb822b84038bb6e9c1e8e981cc9c32d80201f60b395fd2adfb9a4e7c865729f8aa2e945982d83d76699ac55674f7a45de18a48f7f79f02c95d05ed06a880df3aafef0096336ec9a4023fc518486b068ef272345e24b35a85bf250ebfb159a51a66c975b6cf99f146b54480cbb642ccb54be44fda05c0db63a35f5d1da873dd522cbdeaf0e8110cfd342fe6a04f76d9b94ca8e12525f52fafca091fb3baabe52364f19f4d8238de9aa34453cd16c97b9e6a85e295b0df0bdde411765423e54f4923462bc4b91cf6d5e746d19cd23fc15d63fd5becf50072c54214f43817e6e4d957f054cac0e9c24b93b665820ac208c3fd388df7ec19510e4884fe23f319ee2265aacd350ee937c72b738741737cc06ccc86eedbd1c77ea9679f9342a259a07934a5e0053225f32400cc6bc542b21965957e4edd091a5a2d3275be4da9cd22b0794ef65f2ab0fb34fec7a42f5da64f2540a3f0baf66f29fbdda4293ffe0bbdd6999689edc50911d3dac3c03950230fbf34d84d98e9e8f00b849bf9f7f9a78cba53988f3cfa3c97ffe0dafb10ff114d6a7e53f9fe64b370a7d690e4c5ff90eb69f72332aeb73e0018dbf32d7ec1e453867fa810dd089d743714388d1cdbf555dd6a7be07461baa16fb81914dd4a7a629c65fcc69623701afa5151ced1eb80420a903921115c9111adcac37c4d8940052bb647f4228481cadd93b6b7f226c9008a1a0139403b5a84a4c89076782c4468b19dd9fc87d9bf411fb3562d5429d18e0fc3a46a58629ed7870008e8a277d306fe67528c16dc4111aeb0f67130652e430cd5c9a035fa86f94a5a7c8b4e6401f1cfe55acc9219bcf9be5a485521116897f5cf538d06983ac1ca10008b0c457824952aad8e46e923e1b183d83890eaa5fe593930de4f9219cb9a84997d39e04ae69a126436918823a273b8b4293eaf1e7cc31ec558e252c7bae682db0a0e0a8d4aed7f591e90937a22dc916850669e32686883f18b0ebe11dd21a988200ca1d3bd2f2d4d805e35e61534ecb9338cc45df7fe7f1a7872d1400121f4405505bf9f1ba2deccae23f2015de635718b8ec8d9af27e676178fce24d6343f8020903380c11db623b88179a723e3df799ce186e592f7ab0154b063e27533a2ffce79a4d3bb7f044956152a0277ee2deacbd5786c55cc0cafa4e0c21b6b3ae23cc57b30a6ad04a9c78f733d4236c846ea0e5d34be3798a345fb23ed6ce9c41509f1fb2c130fe383cd424d21289cdb16f7543b0fddfbf68e4f619f70b6db8d77d89c83e547503d00ec32d0b5f74a2f127cf14280451e6c2f3d50330ef64c18ab92e5d4dc3a05dea43d2a172b1a6d369f9249f0dc34b890eefe7a89e50de7c1337e7dab467d0c7c4e7eb519234bdc7c39e30c573e0c2fc9e2497ed1e4c5a608f571d9b49d02f223e75b0614a352e3e8500821c15e2a8169d75aa17f7d49e3dcf5c6cd99ed7dbe311efb4f823baf60c463f6541d0c1cb0cc3992ed7b35cb3bd9b8eea10efb54baab041c39c95f533198792ff53f161f970d9e7d763272c9768f3ea7dc3fdaf6700b93ca58d107ac1224e2d71982e6a7d4f3bff62055321b123cb052d433e0ed0682e3d6935688a344f6e987156fe23d46968f26e32fd3164afbe1747852442f85e41358fc41f07651d6b8dd4714adc6ba495ca2a8086c375ea30ffa28c0a4cf8fd0c70b8affbc42e88d82f8a9eb559644b097c876cf11f01b472b9dca501f4dc945f82806ac739b8df1a3ade6ad9bfe9258e92fcc5aad4899ae86b495646f40259a0a1c890968fc9ec0442fe42b466297790252475725727b13587f50ed0d85c28641f235aa690641b15e9aff757eeaeec12eca4bf33e753fb84e3046dde71ee355074ee7bcbf3c8a9bd6af28d6f446b80b7abb929e4b800a261f399beb1eb5a1cbd44767a2914798755fd611f5afc6667d0b9a20b6b7739bd46dbcadc42719b5a72861a5a041f50584eb392151473dad296466827eb8d00f970c7185c426b5bcf52033fecf822b0dad49b93b04baa7fe58514108c2c0fdf49880dc0200e584061337111a2b37e70cb6981605a2ed8e898c4ebc2455832df02ae46c161c74086feb8faa3f87010b6f696fc375b88b6b72c63da9edcd2aee19d29c70ca5a4bab65d7343c6ad3c6be93ba709cf8a45bc393b5801e12a188e23bc74f71cc7dd25414758ef11791771781f8f3b08f20a84d32d76d6e9035626f2b2fe85ca921f9b489eb1e3b72df0133c002dea815fd4ba796172967230242c8c6ea20575b3c31de623cd6a279a8905ea59cbf00314298a72623f4c4ab7cb9119dfd96dff7f8545e75f6aa99e835022a6c01706a8a306e6b18776d5963de4bd0c61785b84cc160bea3562c2e0360960bad3689d5981db4c93de2cddead492351a3aa84ff36dac7583580527e9de4b58d89bd8664b5a7247a0c44ed38cef910576e4a10c1abe656755221cde6565d20a819d6067a1cc81b4c8762c70d2646039005f96bea7e60988d99f96a7e771a0eb411b9cc5c4037bce68d08c476f8fcb5d67c71124854b27742304a5177e9ecb39851fc845a956572b7ab20e141888e60e8a9051bb5af1fb8ac8a855a1509b9b84edc3ca8a3147d67ec02e6c42aab232a9156a78ab16f50999e079246c2aea5f63e31ece0438eb2f86ad7d62d8ce13ef3c9bbe56ecda1f151a56427e93baf301beb005450451ac890f5547f80de79a715d514ac155ccc2822869c8f5aa1bc40948551143745907b6f508090100b041d5ba2385be169dfdc9e1714cf5247cb76c506e7ff9a4c5feb6f88b8c1f8de44feb61d495871cc08d821219127d1164e3846c56f7fb89fe37952f3729ba436612eb3d43378662a05a3e7c65dc1cbc44acb179e667a99c850b94e65779db71f2c2b64649408d686b50b8e0d85700db58d1e8a7711638aa3f9e12a89dc61408dc52f128c09bf390a7b47c42423b3a839a23be96e606c959f6b849dcb95324612fa29dae4227b259131cca219bc82e8a6f83bd1270293e5591dbc1ca8e727350f51d361bfa9bcdde56792c1812a62f0eab2dd069cfbe9e480a02cbc52806b08e4d216ea057eca2cd43ea0e99838a982f65030a81b4610a2687bb66f959d5382646228089231892973019ac82e42de86d414879004f5f2382f2cbbf922341f41f1e28ac565bc455c9ac9603df8b93b670b0506576f4e5aea5f499d8b0ac7da7c46cea32b2383042e4290d1f6e7d900502f960188dbedde27027a0d2a88332c2b8451ef2545f003aa03c3f865b28703509fd6f5da87fb022d2db44cfa5bf2132a8fbed6588259607ddea8d401d667fa0ff16a8969fa16b527c796921935e11ab9cdc276c417762a655b66a1a24915089733a5db389b41adeb15549cb13ed77446cc81433fc56dc7b8d7215841981a8304434423e2b09855c11db6d85c0ee20ab8939ecafcbfcfd617d64236ebe561efd5ef17c91b10b72a06952a9ec717dc88c488b5426477f32e2a7b13321f49df60d61a016c42691f6815adce1bd0f3b42f3f71ce07cae44bc143fcafbf13656a9f299e358fe82df016496877e3bcd459de7b87815e9f88d5f7c09acf6cfe8ac973fae0530e45dee997a80af2fd0418bd9fab6e0279c16cfa4e0faa9db0bbd585f58a6042ffc700f9a77c8e0c3520f5e6c073bb426a195e67721be4dc61ace8ced95d7be69d4bd59f445788b4012c2aa77e3c76c1878b6624b40ea7ca969ca0570d5f528798182a2c5543025d91a5f91865556561898358e7b3b567242d5718f4a4b836afb11ea1b05981d463015f96e293e846038cec21a893b2e0535b18473627161e53c67378614ba7e0c16a2d434840c2a1db315d94100b552253249cfa9d944899004160db803aa86c92bc07670fd0f82f6ef2f855ebd9eb287042758827c8390a8739091dc50c28f401c686435ba6324294feca9249e75f2f86c09e77c12daf6c9d0cb8c625108408794d8230a2d7ed032694b4536c4c0954603d1f22a8af9232277573d12f29898aec7584c8c7dd574b7e6c5f32556c56db57f5f54ebda419ec1d00e4b38de54403e71cd560754ceb93a98f7f0f8e1e355f9798e7f5c75627b0f4342a660584255e7175061d637dc185e0520559d8ba899311c521dfa0cd338e50bf32ec50015b9fe7aaaf26fdfe03c20442e77de90398dbf8a9152990968cc23ab344012bdae77346a6ddd4c2c4342c3f759ee8b22910dcfb713a9f978d7a8a8896dee51464762cba19456ecd68e42cf0e3f9edb34be38d098e1c6ae79a90cda1cc35df06ca4a777b4f99d88fb062a7d29079f803a241ea39e86d67d7847e21b4eb2f28e04f075fdf8c60f4ac20dcb69770911f17a27ee66089f5b9ce5848b28139cd60ace09a77a5e1345542a4b08b8c9f8af41354c806155e7c49e98255733f24f0c039b24a4af454984788548e74d8c45850aa5d3ab8c4681f3f3e1f074032580f9164288f160c069a356276e74e122aa4bdc9a5a353480582c02485a86fee9852802d02c4e3f9a92620b65ec9d6c88225276642cf6501dd69bd898ddec94671976d740b448cb9a68184de73d71eeac2ff1d2c2bd03a3513199738095f404a5de21a9314ab2b5b56def8ffad7136c56e6e0ade750cb7019ca7c38f8e12024c179599d01497d6b683a1ea029b381cb905033b3b741a6536bfacd648e91956139d4fc3c3e162d75b087de5111936ecc2721efb2e1018b577fbf6d340793efff042f45e564aa71415dcc43dd8eea0a603f9549372b77ea3f37e8bae26ee8cd1b03a8111e7eee398553df187740d7800e2387eabd03bd56d422d1cc5640a854d2d09c33c5b41484d1f92c00974c79c871c74b26e98d944df014215ee8b0c368d7fcbc6eb1b38e97e46cb715d12ec6320e021c95c2d11a51ad287c2f5335027138b18c635c1d05815585bbd900a95134321588bb6334912f3c61a079bcbdd57876fbe74b98577cb89ac88764586d4f27aad7286cb061d95c358048e37d54cfe004dd7872551003dfb87bc498db894834cf6f984bcc2c1c3c10a5fb833339be96e880ae009ba05160a4715cb58bb690333a4107ccf11f1d169bb3518c523e8704634ee4d97b8e54376b5d9430029ca07b81bf2fd41d0afe6883461ac54117ee313bec9a588c2c76c168f6b125183088f880f91cf212f87b52634a0a8a4f4df997657d283e1356c8953a6e14326d5568a5b7beb61aaae162c335165b84fd43da6286a558c33082df6d6473209e5bec819141e17a16a7ede2f5a16931c74189f0937b164ead88f6c5a23153184a26605eeea3b522b1a2612bd867b90582577844b518ad65d3fe7737094ae6ccdbac1312b920139c7d2f8ab687643ddc2f1c1e40363e0eb613273a4548318ae8d46b08d06ddc5014a3f6344dd608d724135d8a473b806114e7c7927568358473dab37d3a01711a6d2af82cc7f4cf4bed760c16500bd56201cf6b956d773f586b28be21f1e3cbdff8847efcbb587f1d5dfd62e6ed8ada613cd0a6b9bb1d3d77fefc81de6030c6e7fac164815a6f46535dc3d35ea8f52c88d7fb124c4d6028327576b976c186c725762fe3da8ff3c5b4edca130546b6b90205265641b514b7c8720cb3d393a799a41b7a7df37178dae1e5583c3ed9dd419823a1c3b015e7d969dfa87e90dd06f8a00e343bcd969a3250780e8ed2d0cb11cfc5d079fe169aefe60bbb1c258a33aa77dcab34070e49c5a3b6ba5d793703b2be43971a9b5ef1d21f0bf18c48a4104838d1e009a9803c2e84a9a7c6f3cf9efe86c773b5e60681b6f430552ec87c1fd5ab34ce44e3bb23cdeac0c44b0fb0155aa649f50f604c10f924d4b4b99230af81aef428c125ec0f593ab73415b1e1ea9e080501f21eda37715a05231e15b94f3a75ec9e7d9103d23fc5889bac737b1fc8e25ddf475ac05fd388d189846a14eaf18b3eb7f64a98dc0e47305b2660c91763e290e43f9487e4c2a6916348c2b1ea16ea2665d411938e399b63ac8b7f98f7ac2047928096d8f47af9dd0808b7564f161a33bed9672b09739294508e9805673fcbb3075cc48ce410b9588f1cb181b047fbfbb94f6704853dc6ea969d495333ce9e549b297c900b8248027def361ddb84f318b5484a2713cc4c2ef3aeb792c7c0274e69e8b42b68d8a479fd0433931702bf5493f35d20482b6a950822dccaaa0bdce7d44dc9bcb501e1c87885642bb69de76abd57978c7fae1ce09792103ebd972739700ef805c29f45b92ccbf22f42a9a260d96398825e70c0c2a9798acbf548e6333438a0c4220696058ab0329d9498a019f79544ab79d46a1aff90f8ab7da8d1230bcf1d01c844e63459f2a14244b531bd37987b87d065a3fdefffba6cf010cc5cd5daf91211a03df5f0d58f3c8e47e34ad9b34d0ae2598c3583cf0aced862bb3a6bb022337f6503049b38ac1d8805eb75d5fd2f81439b00c4a6078d2829313306ecbeafd4e34c5a0cb4c0a33c64da91845883a36fa0c3da5b9909585f84ead6c60390789f9e160b09a469091fde228f07cb7ba48a59d4e1e6b202c6868b0a8998bf021e0e433cb2209c9a325c012b9545cfab8da300b51d771f35360d06b0efc8e41baa5c9931a4f1ae7710177516a491f566dc7f6ea6197740547968c56ffa4dc65b4fa594b8cdc8a39b72216a33ed41c0c6011976808f3e52a59ecb0e49aeb220a6f70094a4b80738fa0005cdc47ba6fe53cffa942c03be48884014a480361cdf9bab9dd21e948c600208a59e1a98796af00c22b12461afc11bac615f70f87b3909773b87938eb6e650ed8b553436acb8e39552aad97ce25e97e937f6fcf60f1217425556031c875e4333c9a79279aa67f246fd9afeb9b1bbd2af95dd18be074bc008feaf1ffa298bfd7280889819769f20a8fb19a65f096042a0ad2f7c7cbded4eadc018b67328d1a994e16e8fe56e651806e586ae5b6956eaf646205b2b798370387ce4b6af691490f287992ad4b65f6fe03d09c087a8e0d4e74aa324b5bd45992315b018376eef09a8805836a53491542b2dd96635c56441a70ef476ee0d598e550925353a565459ede45ea52698dce3dbb4344b24509dc9c6f9317c8317b2b7aa41e33ef3c4ba05d278dd41726278e4dd0c5c0aeac6490efe4454954904871d508b27869545ae56fffe3ac1d6c201b2b40c48de0465fffad239ea660f40d0c3fbcd732399c28840d3da4e0ebd65d8f3f1560cffbe65eabb539dc19aa9743dbafb1aade030fc5a39ef220c439194d8f42b9be8be8f3a241b8db5d9509b579911b34f7110d8d33cf98598fbd09cb3341cd9cc3a6647ba8185929d7dcd34321af605eb8eda08ceb006550c30b9f6aefceae20d61c27622c3dedb861b3ecc50119b34bc50f8bfb3c178a0c2b91df8bca15f269e8562f1388d0d4384c5e03af3f011ec666e540af879f11080a9cb540500e7472a639464d9b14ec360f6b7542c700da44ffdd20d07a62e107123031fb56cc3edcd0da6bdeaa4e5342bda43b1d9b032db54b0b6ed68eb6c4f75986bbf7e5bd6183a65c49233ea6f76a5ffa68fdc9181dbf558ba158a9c74bf9555be17b47085dd4c8424db1fcf060c0c6b3211eb993015a635bbe1a40690ca4a216c0df8641c76e62a093644309222942edcabc3b4b9b6558d29d23d8f7b260b0435d31dc7efbf9585316119f8b2bf7410ddd37aeaffa137628786f492572748221b102de55610a09d194191948f32beed9ef51e28e0e8428d558b7ff630e604ae34501150609b3fc26b3d8fb9567d447dfb4ad5aab6c3f949c898591db5f95b7cb41e6565a53273d054a8ac6fb57724740b9090c37da165c7047b1e57b67f4c04e708198cd7ab052b5107f95ad8572b4934459dc58d589393a2a600af0c810ef03dcaaf15dbc7cd32685c01c2105430611cb92466291caba299b3acb998589342f1de55ab04ebce3ac9b88ed6ef1e22c3e373b50a19babb773c6eb0d0abe4c00a974f8ebeb8c8256121a9703ed659ffc759c8bd1423d6460881f84156095e3672db55e58052622951ac52cf24c141fda3e45c9b2f71e0afe8951bba2ba0b74fd6f135efbe28c9114594afb84a678d10dc33c45ad3c8f112ec3ab791df744d0f79a64cc3b05b38ce84053b35873bb73546f6691f0a72d2748c3ecef9118247f88ee8f7e868c7195c1bb14190bcd96cecabcea97c9dacec40212ee0a6505a4fbb62bd2ad6e24017a863b40ef3d5404bf189880d74ca42aef662769403ceb83bb409cb4f08b7234828b93dfb19cce424b7a8e0528fe6f65e8a4f74f78665a11fd57c4d9e4f13f38bae878a1887aa43fc41b190ce9a7822520747abe2531666e9d40d85b8efb3191d9d10c375f729c619a331e4caa851a197b860efdbc64db3048f58d796d97e82389e40f3b8a8d4367196e3d4e8a614075e87afdae2738c13dc35e807efd3b2a27b2106158828765cb50fed8eb3f49deb0d22dea1298f69a8733299976dfb8804226c794551d72cdd5af8bd4b93d3dc2e85079d4729a01763ca2e5a3b291f7c87810e0e57f32e4f0afd7338f130d45cfbc2f8c670674f79f30e7689d798e3d80a44254aebc81372bd4794c67a0ae6cda1c808b2e8deaf5dbfe1c18ba77cf0d111a86b0e4eb5d0599376f94adcd64a0e9c6218f87b750f8628813813c82eaf4aaf9b826ec39f0b4d34435a1aafa73c343376fc66234df4e4d7e8dd9e9b132498e36384d2d87ae08894027be94521de3b174f99fa98728377c49a5e201134470481fd411b72b5ce56533c43e005840d4300d8305715b27497195c23020ae989445360b88a2f135758df50793faf77edbc2aa35b007e2536eea3699f593787e9a740cf72b24fd0cb37a1d10220c7227e96df98a325ae2a65d705ab449682c1520e516326a88349caa752bac30d81892fe490833294df5b22692952bae30c3110a5832f7792ed010f39b90ca85a86cabc316ef5844ab3f06311a8d17dfbb340650c26b89124c90c5ff85a612e265b0f570224ed07daa685156ae5f782fc81f18221360cbe47dcd2b221ad969fa16756dc953aaed0d51742b30f6d3e8a5d13edcea43182f926f97cc5465d6ece253381011d75f476c4feeac01a6eb39b1cb4c75b505539d3947a2d2074c8ee08365f49e29faa7eb6c3435235c7383753ba320efc81a3bd8f29f17b824ec40cf11ad090e66f700d2eb21b6ee947f6206fc038e89bd20d871fcc7909d9a93d7fec29bd82bcc5f75a806fb849deaab841fe8beee9a6907850c0e18656aed070d34e98e6dcd432966259a4684eb46a7f90e70f457eba8a04521c3862629e8e46896e920c658e721a2e8beca34c8820c391fbb764b980811b553c6f8fb90a1927151bd4e0b63bf970c2751834e9f415411d8845291c3ec6f4fd643bc4c164105a2826269c07c4a86b5872d51d4294202ebad99ef7fb7b61ac2e8a4d6801107f0e249570e698556277c9b732f1faa90af9d913e539525728f8a919ea6a6efca00cb1ad9a7bf819052d8a730fd6609d63c3ab44633145ca2a86eeef57ac0ffa96b4e1a7e154ddd80c2a2fd0e9276160c0b0156c28345a462b30b27c169cca40f52f67f1b6f704fbce0bac49a910c30acd6762dd0254e960109d47ce79eedb45f9317bb8420b86efff6d85ef82e66f1dc7e62afe91461fd9cc3a300624307c5894e2dccd1d7c6be045f94df96b23ce022f60ece3311d022f4f405fee02af5baaf7a536ff67299d151696eca5d7d1b55d6f01090ee691b7c33c1f36bf12948e5f64fc7f3a5925b26f2b802dc6dc48d4a62b9f85ade5ca1808d320bb95703b845480a6bc13e46f48b15429e9bc97540e96d68d8594a3f03740d9386e0ced4a346370ea7409ff0ab1233b38e677daaa31c16c573176c2e0c57a1e1bb522d8d80e00b6fd82790b608885720e1937d0c3d275c235b48c50ad2ddc8c70a753212b49d1bedc487f86993185e0d00b85dc5920a62ec9d8591e7c9b770ac9d540aaff0cd83156c9f448cde38efe9e5ee6b356c485622f1c2058e8bf1bbb7f6c30ce29fb1d608c833d883ac017e764d5f5072dcc53ffcc338e90c2cb5769e5510bd99b16a99a6725b43644aa37324cf60df7ff07fa3e90feed231369d7c9c7b4a74eae3cbc2e269aad4c5198f6a1de7cf9b3267467e3526454bf95dfeffda0298c97d3a28852f9b04fa74554957aea3200a84363ae645b3f5a28f17f1993fb007df79cecdfb0a1319255ebccd5115e9b4ab85fce317e912f9cc4d618aa558ec3d4d26cb9003ed008a99feda309629af55440a26d320701589c3ab4c9ccd9fa01d763c21c1cccc25a5e7aaac806a2ffb5091b0549796075148ac7edfc9588cdec24dba4b93daf6b2919119fd74a0def7f1693b58157f4ebdec4035d6e28172772af1d19a18f9cb8cad148c223fe9749519dc78c9d1f03bbad70c8a97fe79d8cc888fc898a9ceb0e5527bb8a2311d06cd4afa51f6c16efa3cb1386a150355e7178964dc3238d21fe9bb2df2f8034308b85e549fb741c74496fefb4d936a3ff6e161eff437676f8e39ad449311edc5310c9cbe66e63ad804d201a4fb20a5c74b3f4933c29a30adb127c46d6f0f8bf3ed7b17a0a0a67111c3e1d5f4fd495ee85e1d201d257519dd721727ed424623f1fff1e0835b910657d30c778feae630eecd1250b31838a329d5d476d9227cf92c4979668f351799792616d904620058f579cb9f81391adda937600f4a58c8cfae428a4e22d076d0f467f8d22df75800767d240f063868a1a0f02f9550a76ede5fa3d874108626ac07e3f6e87bf0b616f99a9fee2765b50bd4c069e477db200de6fdde3c9e6d88c4a3a738c880bc3b448d3445f3a797dcf0f7f28251186da79018d9c70c62d8b102a3d9281bd578d4d398e18ac4857be3307ed37592837a21491649fe500732ee5c720c513e0f30a8ed0d11c4501009fa74cc14c5aa9de24c9522b20ac139e004b176576cc5ebe8153cfc1a215cd6920415822e97cd7e36609ccb795e98547d458eb19f5dfe7429cc698993de36d030eaceeff63ec1be8af7b415bde80106c968e0095cb57f61be53374b770b63696fa376de105977a411fa39f450b02c78967ed4e4de52e4919d64d188458cda89c3a7adac8f3870b394138656497fcc52d88356ee3735324ef6afca03d405ed87162fabaeea47e5dea5a8b4075888a6c89da771af5bb8f53cc8fa8f5e7e8551757fedf58777d6f7bff89fffea055a0d27d6f8d341e314a9b48b832e2516dc069a6e57672bd110a0dc1648b7cd42dc710ce1a82dc0a6704e93edc6d5df686aa2bb14f011d6f22d94c6fab38800eed191cafb554afe73769fcd14bdfad2f907fca4a80dc6d1412612f083003a670c16376e183cac597b774b05fa4182e6c4f489afe77ad0c6b599d852d9f22feaf4e5e91eb8d452dc5956b7fc5b1874dd15659fae186debf29ce5d1a204125aea3d806e48053f8b3807048e36ceee745883549953f06411d3c363578d1bbbff77027e31fd74a3df182b31392334ba8f2d3248818d8d1e55272a63194850e30a6ac44adc3c83874033e52782227e9f516cb53e2ab5b47816ffa5d7c7cf001ef6a150ee43ed03d17c5e489a9e8bd9ea088074d07ea197b648835fa8f8fbe6c03375a0ac9506f4c920e91bcdbe96c312b94bca04856a1e72a289d1261a5647a18ef91dcd7de532a3172ad468941ec2a7170812fab196547f10c8e3923b4fc13658903600c57fa59ace928f6cd9a5e1ab4c342699739a087e79874ab29d16aca42cba088a0233cb264551416a0b2f3019a75c525840a8f0511a060932679801e34e646938af8ae2d99162517e301bceed4c31b1475ac1f2aaa84843c3fa69d58d1ae7f3806594020d6b5ceba95219dd4c3448c4dce336d561fa5d10c097d1ab0bf43eac41365dcf3e460ad1b3e5131a61270fc2154ea455c94806f2b7e64ea1d8bc4b772c82434ef0a4f4341ca1131926824fdbffa90d634b096d02c2e8a959a5c8675dde1b08426ef988d3a6a495d3cfff33913bab086cdd0b152b96b6cca79559e9a59a936f69933acfef18bd016d7a8030c0800c8c6f6841f7c3040a16e42b19db86c854e41cd844527ad2a1256cafbd7fca4fbae8aeffd3b4050bd568bc38c45cf7a3ee903c2356a71f4156329074399c28a1cdf6652beccd40ad19016091c64ccbba18be77644ddf3fe2992a49365f78dce2b0e9de3cc393e454dccc4a4b6ec4ec5942f2f3001249fd8f68e8ac966be8453d804dc994f347b23598a76dbc9ac43f372376220497bb0d9e8ce3d8ce4e5aadf27e121ab693e581c3a34269b25a3ae2155346c5ec4e4f901b4090b2379b0491be512238dfe0505475ea7250023fd6ee73a11a236684721646f86367bc1cd91a8bf1aa1ecd5d919dae8348a285873d6841d3b297fd95c0f8139ee38577399f07829d77660b0f7d2a037604c38d271617974e4066540a382ead132105f0d50c69e7e4c16746ed2cf0f570dca216fdd7e9b1edcfddf432ba3cec537392df37f0dd464189974efa5bd74fd77848725b0ca992e6886ce6a718e1ed00c040050c9eca061c09996a066151b541b2fcdf63ecee7ee06748a6e4c190c5d2ee038dfcd7ecd08d93732f4879a33c322830bdbc8255d5d22643b61205c95e29cfc18d90a270c6774b51c1a68b64c52f5d39adb85c277805d97ad3ca94f3aa14f9b71357e2f459eb1359cf2d6b0cc2f0ecbc041dd9efdeeea63850ef7ff77d7b08dfee9205fcc0f67f1e159ad114d83dcaa4b922ae4f661be14f51360339432fa2c0bbf80d47e3ebf4756408971c0c1d6076189e8f3f3ede59075a50d9d1089b1e1eff662694eaa492756a71005a883c3363d4c594c13a8669593373fe011745028758f5e4795b5bde3c7a90487d4b6e1d860be6ab62e32c90b4a6814cd55dc73c2c29557dd2f06c954715c1128f1333bf9dc7dfa3dae02a4cc6872f19c2d21a6a1c62bff49fe195f6a369e17292289bdfe4372e82da2efbb6169d64b844cf2954a2ee9661beb8129a5a7a43133e8c03eb04c12e17999ab4308a4db67787c464550d4fe2e4dba0c0cd6db66270a62ef9230eff0dcc66299c11abe69d8fe3a50e29749a1f992bf3f7e8e9e25559b1597d2ba5dc32167e000c905ecc6671b561b241beb9bb003b57dd00cdd41c724776b70e57b995dd5bc7c26d1040e9ad221ac096cb6e75b414f72e4f6cab26d0d695cd7862bfb0d976a097f5f1009a12b0d6944d5a4f33c6b472c90087baa37b2502aaf8dd26f5405722e546ae01f2d12278c54b6bfe8ae2392953e61fd39faea2adef2cb7c3de965adeeebd9c83db8061adc851e706186c8f7767be31ed4147f910993ce7efa51fc164209b4306ed7b2722f30292abe3fd2c86540f6ed78d8168586510dc14088c7eac6b9bb5a863736b112f55dff93116812a4477a4b33526606e58d68c1e232c79a540175b8f021905a1616030008fda52ef258a7a3efdcb5fa014f66481b4afaf445c4f588c28eb62fef15c4c92e00b0807abe92edf500b99613d34664808f1efd162845b00a2357bec38a28aecefab7c7614423fefedbe6f125788c2421c1074b1ef6a680b9edab258f8a17503a4c40364d3bf40820d4746a3704f0615180f9e49d77dc37f8807b83dd1121f095300f0463d2e55d680fd49cc390ba09f667a0b1e3c4b5456f157972012ccec0db1705dc46e9d2da009261fedb9a173864dee2b63f009c253c25fa4038affedd379a16bc5e0e4c020e66e6d1b849a0ee3bcdc58426146b025ac21cc98648eb19983792fbbf6a6420cefc0b32f065d763c05ace59d13e6fd02f09c2becd2d78ea1f919650e90155719190377755148bd81ca1f8806d7b71b51afbd388a881b4a1913b873f2db80ae5ca065a76ce55d045a61ce15bd4a438a210fc29707318ac4cd2c27c3074f0a3dd237fc1573d03c65e08d7cc510e47eebe326501ce9bc7153250baf15eb5d9fc6ee4e6ac816af919ba262cde569c950214e76c82742082704f8741a45ef2a42097d0c0de681e9d57b86212e5751045c87522551f7361169418efc47a807c1238611c9f530000210b2ac7e68786355ab34c390681dfed5f7edae65e11b0a08a84784c51ea26379dd8e7516c1961d530049a20300373266cc04048ea964699170f18a2c424e50daa7079d30b0c6455e8671f201cc4ef60ccf5a193d61d8015a2d58b536d1b417f0439eae7601277dfc8f75116754949fc439d6fb2640d4813cc8922a314230aadac86c2c8181e72f5e5bce4ef04de320d35b59457060324de8000862aa6dcb9e59a86f7488b010953abaf7133cef51eb55cd054dea86615fcb1e65d76b0393343263fb4264d2693d6ddeff27659c9b6c7123cf61efeac10f4665eecb9ec1918a20c1d055a175ce015e2a58621be766d0756ccfd080943909ec5d87b748dd37e8f26560c642c3fed849929cb2a1dac6ba1a0feefbd6cce3e51fb5cc3ab352d8efb5466fd4591038ebd238dd7b7bea6116ada4d7a3f40abefbd6e7f7816f898195189797343edf92c1ce3fb2e1ee3de904919f191cd66fda77b0d7a37bebdf3ca88f871d90058cbb8cf047f8011669de472c64e786f196265281bd2e71426c4ce531ccd4e1e206d787cbf424df1d3bb76f118fe862fca54f7b9f7e77c1313955b6bf922c79e5985e0b33487f8ad5b2881fba4452a25764064d5ab6c6bdd9d9d3c761213dc231c79d70afef8dd6aa86b502b3cfd10693dd595acfdece9b1dad5c386a6c3b38d5cf55e6ffd1853680c8d046ad69bc55620103b4a0702359eda575e176e9f6709e78c135b30b4e2883dcd189c9d2fe0b9ede1fa6afcf521a19531eab28aed581093d93647ca3764780f4c79ca08e451839c6a34ab7b691f160ef6ba4942b6dc7bcb2da59449ca380caf0c4f0c0d5e2da956a72eb7482e5af5cc35dbee9b90cfdcc2e24f7c81e1a1c76b4d34c5557c8d4312260bf9ac8bf2c153c97cfb64ac412bb960d728cfa4a16bf8ae67fbacccef249706ad5f4f6e69d0bae6859d63471226770ee443b9e5ed9406ed0b1068f0ba6bc66cd08dc555fc139e80211491c47f0206505c4520afd39907c4afa7f9e645d1fefa149bf90b0d4e69d03a0b29671068d06e5e0caca752657bedebc0f63714f2617da15df2657d4a11fb519149170d178bdcecdb3c95f493c717e7a150d84f1f0d27c7d9e38b06ce3b5fc0e6f9a301e59b779bd360e39cc7577c71d8bb4f25bdf39e170f76d4c739ca5de01ce5d2519b771f0fca37e7b171ce7b5e3dafd8f18839d755d27b5ed853c92f0617b0e79b6a21be4e9e3f1e9e987b5e361ecf17176c1cf5f17c09bba07c01520d27ae80bd501f0ce5a8af061ab0e7e9d8bf3857f77a984bb8ce2ae3f4dd47a373ec9dd7f3c25ecfcba5178228d39330ecddc7c3336586b99a1e430bf165a5850e7b286171a9933226816241b17e893d94731cf5e41702f9d435cf4a3f7594278bba185c40f9e9e3e139f9e9934353129d501e4a94ce44c996afd8c90f27e6dccc331575b9d54f45bf2874cad15d22cfe999f530cbb28cc812d4299125eecd6d836a6ba594d26a29b5153f51049d5448d22f4ce13ca39db95b1267b6e2f48d119c734e6be328a2592c16ab084a299d55055c2cc2554f291d2549892e2973d59e3262b198e4c88a2e168eae3cbd196468b01d2365da60337dbb949ed43a6b66b67a1f2562442a9573dca1e7ecaef25dc95570be22252949a196f330955d6b3d1c5bc4b1e224b2c4c6598f11e765902238aea41f79e9ddb2737a159cafdf7dcfcec8134eb08fdeb149bb3c217e74b0e2574e05f1092ee1925b91cc1472fc4f57a15d60ec3c1bd7ee95b2e699aba84732512c7d2453f4c4d7ee89e62afa917929e62b67b1ec76b2d83de9bfe192c35804c618c19d1d493904c1d8c4faf4556c527dba91e89a4afe7ad8e45d609427dcef6aedd9678106dbaf37a81373a65bef63cef4eabd62ce7470ba081057d3e3163fbd4c1c459a091dd99f5e716df03407afb86a39e33c853d37888b21faf5582464bdfcebd4d2eeae5570f4b878ad6bf1a3a5b3c198736223478faec612d7566d460790e520577e59fb11470a60e06588312c388342153368e2287683d10daf36c11b15f6dd9def96ad3e9221d3c5134f918c7c246374c39f969041cc645cf098881366b54d534c50d021839453f9c84732465ea230c1876014edb1488f5a6b8c35463a298d39e2e8c5673eadcb9f5d141f6fbf50049f519f5cbd3de69c37b3746adaa6695e7c75eee288a9c7da757a2aedaa3295ed5a29ad5405653a9d1e9d4ee7accd029d597b8247f79899adb3efd5ee7512e7784aa72d720a45f0f4cbe0681abb7bae6c2dac94b46f7738333bfb5eed5e54fcdb2d948c3d3d4eda73564ae7a45305e59bce399d91d218959c4211484d561bb40cad4feaa92c9d9e6ad36e2629f5a27d2a67f418bde716ea5546da196756da9e1751214afad453d9aed6869e6ad3ae6c6badd796cf49e7384cd570715e99f46a890972640f97fc7423b72360be4e62e4f8b18b277942c35059e67efa49294737418ddc2e3d36d97e3ab7033c02d636ee97d5e4305037a920293276b8b1830d9bdc2ddc753bb4bd193dbc9d93a8e6a95b354f274ee724fb54516cf624bad1371d0bd633df2e3e8512f8ccb9585b4eea9dc29e243ea36e2beda480cddc2ea7a7eada2de5cd2c9db3e79c737e9785adca4945c4b5568f2d7b7a19f5785599749595aea2b2c6e94d3ca58c229db2305d7a6ca7d265678018aff75c3995accf8be5898c9c41d9faa35ee684faeca73dc2777bec6fc69fde1d6d6b9db6a79a6de7a435f6f4acf0b4152f5a9ca3d3e8338aa6336d7c4a5d7606b853eb58984f58df9fd7cbc2fca8262d15dce98b7b9f4432de8e99d6a3fd3c5231404f95120cc7717d3b0fcb0c6280bd5fb16b407c751f0dd8e3eb155f9d979aabe95a3421354598f93446e6322cbb273cd4afac2dc4ce05ec3629c3ce69586a639c8c70bf50ca6b1d0bd5ad632f94f2d7b90d53b72afa7642d158f88b73966556ce38382d09e36cdd4efe22c78faf76e9dd2b668e73ed76b22ca31927559aaa3357ddcc5ae1792adfd24cd228d5a9731dc6de9776ce53b5f7c060f1c5cdce4924238ef9ccbb7332c26f99f5ac7bc2aa747b833b25652a6f14ed6ff52cf3ec37024e8590537d4005ead60b103f30030886bcfda8707e4f65e4ea5236bfce79a1e655b6e79c935d94ec492ca30921ccac10cb68428832cf6ddb6b9b5b16ae77d36e3a6dedc6f9e6a938bb499ee734155555d5556576e33cf95b2633b799ebf4cd5cfae44229f68b2cdc6e65b1e53c850af84c665cb8ca99a06a1f023bf648dd524f3e3733b719956d3d49a9ab2e95d28b99b432e35bfa7515e85912027f47748ee90e95d54d80234b0f2ff690e81c5311c2b84598a69761be6d306090e809c34c1b58d0308aa580bdbb02f45020c6980276e23f603f100c79ea3406d36391cad33d595335d871eed6c9b13d792a8b4f217decd50b3bd73aec2a0ebb6ac3aed2f0e9ab159eb727ebd8da479dc2c854b0532a377621e6b922eb787da95ec3f68a525b10e2353d762ffc30534613429829a389a017ea94740223e348c6c7e0df51c14e9d43fdc971a6ddcea97a2aa9d513cf9fb017721e6e1e5aaf9e8a536d2aabb94a6af5e4c9af9dfcd8759f0a0af6eb18bbf58bb73fd52f94f29dfc10fb46c53a75f93d9bb471709b73b85b9c6f1bb785163e1cd530c7d5df7c763b1be7859d73aa6e5accf39d4f8f8b1e520f4faa5645159dae3a4ddb795678de5a99d7332b5f769cd72e0aca9dc498d339e7a1be50869c57b79cd37047eb9c70de8e372af75345c99cba5baf93350d773fd38f5dacaeaaef5ea8796855dae764fbe8aafb39d954d9e7647b95fd9c6c217d9d29ab5b5141a94ee5f75cd934a0756ca08b34b420c3670c184478600ea135ca98a2680a19b841c787b18887337438020526282222871dd62c051104c5134a3485b1e80da7830cccc477d7e143a5638d1d5f4c6aea018d177c01050eb017a02022882ac42cf102a63aae9ce00862089d23051556901733fdac5112871b5bbe6cd14112610861b18231ac38e328a9891ec422560fe4f830164dc102209a804881183578854c84a0c3cc17305003cc165ebca4df8f9d7c434abf52b248d04ec0299c71584b983428e1c84116a20794c584b504378b0539a698e3092c583831a6670bd10c9ad62893c31b4d3449b13559d1230e8cc122381947d6122628744b5e8c83f347325a78f161ea430c068e68c5098ab0388104130db0e880e6a80a2e5600461725b6203383684ae1064a3c71c49a1d90f0e2d5832586268e2622bcc08e5ed253d2a3f42b3d5585bc22a55fe929232a86d10e8cdee8410a3396c2a84087184c213d4abf6e248139c28833d0e8208bf902328d86f640288d0e55a441861a46f8d00507242272b8d2841839309a56488f577aaa93aa986d503746c8010837d6a891861a59f4b0800746a851820ea216f0a093820a0d4a37e0f8763acd7cfff8b64276b78c356831744cd15da463b3b44023fb8b325d7cfbd562ccfbf848c6065e6857f418d22f655ac096164c916608a51e76b8c01452c8e0cc173f24bda0bf901eaff4140fc8b4c0c31847cce1461354ecd0460a311042820932603ac43040d9d0c670c30d1fbc70b1820b5a82971ea5dfb803a39f1f6cc00108c6032358193556ac81454c163e6b3c2009130c41041d68ac01224b8fd26f155d80a0838b3137f8f9c9d274090a175e9ac8c227082176f08a1e3380a2d54ecfbcbbb36806893276a083a12c68de7855b96105455a9811a444183fd8204b799072385029a4322a603f5bcabb334fc3b6f1dd73e8bbbbbbbbafecf6c8c537f74d833ac2f8eeeece6ec6f22057629d145458a15bb20893ef322c9928d4e8b44ea73c4526066b5ef5914c1465de7e2413c5984f2ac39da0c8d163b6f342831202ce43fe74a4ab209d259d89741007593afe9ec423337eea25c51195c5efceb9f8a954887ffd49fcfbf57c9649eab5877e12e8a95292894c8280dbd432b560ae3b95dab414cc4899ae22d914c2d1a2458b162d5a84b6b64953ba253d7e335ca106b32bd4605669ad538eee0fbfd47b64d4534ddda74be5b3e7864f99e2ecf83c9e3cf6173289947a7bf5bcbe5c2412ead2250b570989847e12d63e3f5d1e4dd7945ecde9f25e4d07f285b12995fac2b8d4633a8ff9dd7ca9d317fa077ac8ba9f4ba0155c2570ae122bb8386b678a529c9254da362ac14831e4904c92626c6017298652175b69edfa6536a765175b1b7186eb6196413a95732b6f46cd552c92df8e183395a76ef3f517defc65d4b703c2b7e3c4f293f85646b19f4e8ff9e6389c3232fdb04bcfd395b51ed690c1184d00c9c1f492fec27445a31ad471821fa22b7840c58b0b3092484a020d3264b0a507054234a9a1c1115f986e7849e7a8f5f627f60be9670f490251d4c783f2fcf1648f47414f3d297bf145bdf6ccbe70d2c828cfae33c34c5fa8d9f2d4da1047a9f5d88452b75f343a22f645624eec6ea7dfec12c4569474ea3418e9a45ec1cb6292722a29fde2edfe6eed6d882cda5c238eabcd35ac0002f5918c153e6c2469379e89455c1a5ab7866626751453836ed6773c325ad21a8d8e111c49698c90ee12178b843f927e3a041a9cb5be50450330743b28e7783a7af24950e2dd8a45b0d329db525fbe10a7b5763bd9162d68e9c9cd98603e945ed8fd7170ba90b86421f96427759a9f309fec3a0d648d0ca48e0d26a5b6466b6a7066e992c32c68c6a62b894797d1e5d04f07e2d153d15241ba75728f2a8fceb557796807e2d1873d434f453aca69ed197a94a3aa0c51da97a9bc6ca903aca7729d7ea1f4b00aeb35bfda1776f5aa0cf23b10931ee5d50b973cebc39ed85b91df01d6a3be50cad78f8a74cd4329afa19cf552fa75edbb59ec7e5950d6e30a0aa40b1339bc423fb464290024b215ca30bfcb8fbf90b8f4a90489b771e9d5b779318245a63070881c5ed8756db1c53c0d164299108e72b8c5c22c4c4861af01a51f43c8ef49fcea2e3f55fdae50835e1a9c242891fd7fa42067433f82c886a8caa7f6851b989fce79192a93430dc605c8123954b9a47d42e9f4855dd810fbd8656c658edf0099d30669f8e884f6a365d180342d5a90b6a5c1b9c309a32b84d228fd5083d12db60935788532237ab3d04c7919a2f2ea5529f241be0d48e56d3f5ae4cf6d7cfbc0dd2913ea1a1287cdea1ff8100f7b39aea4c719648b4dd517b2c02de6110422d3069d5417e24ebb9d0f847c55e2d1bb676afc03ff3226232dc8dfa7e26c3c53f3020724896c8fc840cec8d4a53402030f332ef77b125faae4a735d56f8335f803881c6eb11f0d662687599812ea08a9979f99fcb2a031d93f7a21441b434c52f810c41a6c5c01630634b89245186abca6f7b08117b06661504e9f876b1f9789c9c4047989633457558a3498892113e667511600334c4b1bd28fd560b189f4e99a0dda0df284ab65e91bd7e92c4c51833353235bca98bcaca957537e991a2f4b23e64ce7e2102143ee10a7a793e7443e108a00c0b334621335b1c9e9a7733d98c8e1f643c59841cc8626493ea4cf24892cbb871199ba01a8e3f430410ef37b2a484df9705fe621f22624bf2df6136a30a6ed4788991c6e3f4d5f2505d29a7ca69a42a82278ec76565e2b087a1b503d528fd46fcb72e4db7e402ffecabb47d74c83d35b4864f0a6e9d574d0d3981a9c2ee9cbf8f5bb6bac68f279113e1a9d71e2b9c66a94d21485210233e4e5c88c918646436a503ba36dd182342d1a909645fbe982c4b9d8b5108bae0c200986e4db6273158489ac39f2d3372eb1c998d8e403393e42f0e1c363f4e160b551c00e3f0dc60777f8903526946b30d027e8391fe8216830d035a66eb54faff55e4ffba9f5d6fb693e0d4e0db67169359137210d06248d4caf9aacdbb94a6990d0983922023314e61af9eed2656af0c70fdb505193fc8d8b90976e5127dac2748b7e97c90be7cb207f8bc59ce935899833ddc81459f584aaa0f4873d2a2731474c51984bd4e0bc601a1c1202264be7a4a73deda27460be2a8a74eaf20bc17ceaf17310d78b616713da912e8250ae397cc5e173fcbafc362e5b0c05997acdf96ed10d1344a6df057387ec1b29ca424cd4ab12958c4491a5c37e6eb14d75bf2d264489e80f19f4106eb76878ffc71502f23357d37f08cdd57420ce5d6f2bfad9b274cb884fdf80bab5ca39e222f874b99d20d7d9edac7c7656768cb813f937478423ee447e8eebb42a8af4117c848fca57afdec625c7db848e88708dacbc2d0ceadb62d247296b3f9f066b7047960c7e217ecd43f8c223af79a8c136a406a703c0dbb834381d046ff3e26d431b9806a713f136a206a77fdee6799b9806a7bbb71935387d88b71d09f1b63342c0e4fe3053f3c117cbed455cc32acdf17d556664f4d3815c18ce8717261443fd1e5e789f8774cdb3a26e85c9c474cb5351af1ed33ceaab52e4b924e9dd8da7a2be29fd0e4f453f27fd5b4c8369405a9006d37e342f0b924f3f744fe24d869a29cc90aafb87d5ed3a5d6ba54d60692a25614912bf41d392c45351b93424a74b094b4a29599e4a52cf85258ec4b94befad26c0681b3eb7d22cd6e0cd8c342d9422f17848f0251f3857499cf5f128f1241feb4b5642a45a00126739eba3810447f28149bc251e3d2126d9d02246846e853408088b166a5a7eba9452762f207196c76e014b3e3af4d1a0b9f228516cae2609dea6c48b7395054dd716bb468832259aabd58449a5b99a1a6c22792acee5739e3d15e7f17109b0edcc6f48a725f9c25f241e5e968739898729252490e0c55e29f19278acd8ab29471aac1ebaf0557e457d52a9c19ebfae2cf216f3e45252b7ac926d9aae243e3dfb99aea8c443bb84c4c30cf61910eca3128f1acdd5f4241e3df22812cf88975cf4f7362d015a2368f322251dfa49345d5f86a64b83cdd5346a707a51130cd6ad3033f2e956f5a194d2cca85be11d7a170883c16c5882c15ed3ef50b78a60b02701895e2f1acc434cb4f43325a7f4d343cc35fd749a4493daa50446992aac6601f3d36358b5fc54439baa4f0dd260dd0a31914fb7ea950a94c32d4695681a255fe41c0431a44412b138a21a441c91830e40ace162044d43951a4c52c2c59431b4f802c98927704064c21a686039c2044068b8206ac1c5193b24f150c70db4c42b7af0218e1c52e0458c8bd774eaa55baaf82834383f8916262b1bbc800131268b1338b14501451731639cf18312d0d24f12160b766613035bd260d34542bd61ba90f8f40b9b2e257ec3879489064d170febe361790d9a0acaac61f4fa723d894fa7b1e952f2f120f97890b81227e15321896724065989f7a50ed52f8c627e8b19d1816b3c43833c0d522aa5f6cdf049989aab25b196d0eb55f3ac4825b99492414192c8fda12bf1e44b76d7b758b724de62dd524191b77ffafda634e8bdd0e0a41489a77201c916eb12a623f19e170a8d1c6e3196a77281e5493cc9c793c459def3da62dd4ae2f1e02e6480b8e255438f1e72c0f48a5d42d8699278b28b0d329843e8a5339178f1c5f2e24b7a1a6870b2bcf842423f18380a9b2e9ad4ab7961ddf269577c252971230d20242fde48438c1444a8408e13fca4f1821b7ee8e2d5f373c4450e673c61822b4dcc90868e1bd830e38727aebca6f7e022cba60fb7981a2f5b6cbaa450afa60f5db911659cd2cfa5a69934cfb40b174d9f683ad6ada02906cb6bfa34d347d345c5f8027b2975d274ddd7f4e9a5c1b44b13030683c1c2b44ba6595a82bd310419b0d7f409d442334bb7d4b42bbe846233c8a888680e31fd5c337d7efa168b2f5d091a9ed1152596f0d20333c0f46059430d9fa3352710428828460a30571869f146181c72e0c0e18730aa9001134bbca6534f8a0b0d4edf86a66f44d3b7581b398c4d5bac69ba3623e26afa123017fc9c1b143fbd69bae20bf6d3405b8c2e4d170758f082344d148105961d5ed369d374ad90450fca3405e1c68f0c5ed369d274aa349dab5b6c8bb5cbc8d2f44d084cb722fde99b191ec07e86db999fb8c8875bece766f433dc8e7ece57b821fdf44a93ba155e21aad4ad5083fd52b7c20eeaa06ec9a506d3744b760b06fc214dc2f9904a4a95a62be5b109bff023e9484b1e7e5a4aaeaff4109cc816ef745f74d612ac751c87bdda9b6912a8814e4c99d3a2bd20e37b3333324ece524b83411268892c53d50a2e1609e912d0c7403feca1a11eeaa31e6a1708404dd462221935621da68dfa4c2375520cd6b476a5a442d3c57a62882c3028811534587a692a4dbb4e8dba25d42e000cb5d3a130dd3a436368ea501a653ea460be5164a870e385d218fa909a0159f215d2a46fd7aea4b16e8553e9b974abdaf02d5551faa53fe99753e9de9c5329f71e9a4a2df46b1acd55fba90e494474d116c4557bd315c8557b3b5d816cb140bab6eb2185410e1f765dfbe635981873861a6ca7238753e97b2a754b4d3883c4338da669fe24bee63d7fbdea85f8eb0caf94c9a899e3a7f4c4f08638930234ffe3e3991414dd4091e5091b6c471a597e5d542ea0eaa8a38e3a5ed3759a873a0d374ca79f6a01d5a9d38f06eaf5fba2baffa25f9e2be9b29332bf3b572fa925fb87398ba32f6d30c1030e57dcf06a07a7abc7cb14368062091b8c41dae2d54127f082cb1a659c51e225821d04f1c311195000ad79b5b364770e5c3c3232a2e9e527c3b48928fce0305f5fe417f65ccfb1c9132eba329097d6a38c2e949f3cd4320f6d3e7e29c4953d7d666e04c378e685e99244c495751bca2da1dce2c4d20c62d3181816f2066fb794602972094cafc25c31d94ceacc4b342f3dac60882a50afb25c2d79cb4b2e2f6198ae8eb03b8f905e1ebd741a4487664c88e8e52b898c97f22553a9d71cfa5738895ebaa43f2f815efa646a977cc9352f612fbd12b52bbec0800153b5b42b4a2984c1e98a2f59372cb89934d3203518d11c7577d3331fcd34185d32d1222ac6cc51d114038648c8cb161a036a30522d47dd1dbbbbbbbd5a91df718506a3ebf834487f9ad67c9c430f66aa6930cea59e2a2d8fa4b7ce65de49294bef9c93a9286577dab4ec5e89ba281bd4457d594bc949e1acd05c5997351a0093966b8a0f6fc30a1989b14836c9e6b40011867cb0a305154e0f1e37794b9a2e0660d70b4b9aa6ab014a5c0e60014dd70346d8d22e08ac20345d1110e29200ca052db33ab04b3f52f71a05010225052ffaf9f9f9f9f93132d2604b9c9a6c6340ff09bfb0a401668ede3a18cbe10e336f8b1ab43bc4287100eb013e02047c8508ec18d24502ce7599808348641f539cd368b773e39c8683add174f188f5359aae9ba36b748daed135ba46466ffdfe4cd70ea5fb737feecffdb93ff7e7e7ad14eb5607b175c34444ead68d508336c90a4d178fa299f4f2f022c0c37c002bf4d699b43ca61d03f8f01a3c8aa6eb001f8fa246c0d7af2fbc79073d6e72b5c1998ff3e1a5bca6e6e7a48d7d0a6b7817be4cc614dbf970cdf3e1239fc123c6834bbb26f0c55e9d2e66c2d205719dee8adea67e781d11100f33290d3161c26281a07b2a9583f490c2c50fc575fae668ba70d35c59ef84582c10744fdd20bd85f2e1a51248c0e334ee632744f38408f130131043bcd8e0fd3ef076c0de7a0b3e6f5de5c506c3eea713e1c34b396cdae33562ceb6134704b8155cf3565821bf01019c7dec46709d1e61842b0fc04d6f9debecc78ee53acd7558f3581ebb1d162c3be0a404cd898794e2c2110faf4c506072a3c20a46dacd0d8fac75d549a148bbc959db01dbe123c5eb32ee8b291648a2e011f0050820b196b01ab0a40b1e12061996f24c054969a08a52f622fe828691784898f48161d7fa399bcd8b6fe784bbd5cec0a3752e5feba2f8f8ee0b45f0786a5d330ed7690bb00971beb3e1a668ba30d39ab71ede18bd75db39a18fca321e52fe64e93c9315673bd9e97463b7736383eaee3de5939f9cbb38778bf322b55ef40dbddee9c4692e9fd3ba9c73c631d33c73dbed64f79e344f75d2b44c3b69a7d377d24e278ece586b9f18e061a65ed9fecec34c9b8d17376072183992c182e9a3512ccdc7e7bc7eda65526a9a952925aa3b6d9e159e5741916e65ba76513bdc7bb3c3bebbfe363a882e2dc9a6a95bd7ef186fd1781bdab4f1d6b310b1b5c11accd2aeed27c7ba15c5ad672edd5ac1ad67a1e962805bcfd633986e05c0ad67a26ea1e0d673986e9de0d67351b79ab8f52ca65b26b8f56cd4ad216e3d9be99613b79e8fba5500b79ecf740b8a5bcf48dd52805bcf68ba85e3d67352b74470eb394db78cb8f5acd42d1e6e3dabe9d6086e3d2f752bc7ad67a66ef570ebb9a95b2cb79ed7740b895b1f6eddc6a75b4adcbacd4fb792b8759b2c3640dd5ae2d66db4748b04b76e13d4ad1f6edd664bb75a6edd26d6ad12dcba0d976e0171eb3642dd62e2d66dbc74cbe5d66d86ba15c4addb80e9d600dcba0d51b704e0d66dc2d814d988b131ea9610b76e63a65b29b8759ba36e11c0addb9c894d566edde606f10415dcba0d0e62eb895bcf41b1c90eb79e61dd02dd7af6e9d68e5bcf3fdd3ad2daae44d07a98b7bc96b7be0529bdf55352b712e0d64f69bae5825b3fc5a68b1b3a0575eb03b77edad2ad772648ac23d068a868e84434741a1a127aeb5dd274714b46d38585d0744bc7ad7748ddc2ce020af1929f60a9a6bca4f46177f4d6f152b7f27461a2d90d75cb006ebd03d3ad03b8f58ea85b2cb8f52e4cb7a4b8f5aea85b0870eb9d986eb5d0398b09c87230e539b57442234b4fc526a1ec3ccd7144c0f10fc8ecf5c72e868ec7083cfc03f2513d583dfc0332cbaa4839719e655996659914e74e0638c093feecd787121ffe0119bb187652fe01f9f8470bfc0184c9ca9fc407e23acdc56ea789ab027044156400ef4fe2c76ec7052b4e3ccbb29bcc9fc4d8edecb877b743c45b73bca3715eb839b7c5d738ce6f76efb65d6d43656210010367c3381c2782173f7622b84e779e13fa1e650547793b3c7878ec7646701b6fa7470f8fdd0ecba578ec7610e09cb7e3c3a5548949bfb914d4f685fd9b77ce79a12c7a0ecc735c447a8edba478d7420baed39b15f92db460008fddce015ca77d2871eceda4dc63b7b3c4416fe787732d5f793b409cdb61e2dc9113bcbb9d267ec48bffde4e100f80eb343700e712e0ddedb8e04e766e5e0e229177bc1d21ce09f1d8eda4e01c0f5c00280af03a588fcf5d48c00e180c0683c176c08838e703ef50e252f8a6c8f3bc05af13d3a07504785d5183d6a5785d9806adb3e075440d5a3f80d7813180d70d1d11b93922727344e4e688c8cd11919b2322cefdc00cf0ba15bc2e4b83d6a378dd0f130070eb374220b8f59ba1225ec48de0a00f717ede7ab805bd756e68ba76c0e6cafabd39a752ee20c862ed80bde586de3ab7345d3b9426169aae9ba2b943895bdaa1c42ded50e2967628714b3b94b8a51d4adcd20d167aebdb951b261e134dd7cdd15cc1ba75231441ebd6b79fe9ba196a2d69ba78c46e4e397873f41613dd0cbdf57b734a4b0281c3b8008ebb1d284ec48bb27bc271274ca338615fead68d5bc74cdd7ab975dcd4ad935be750f8c6068c2728ee0607719dbee97654cef9c03df0102f7fe01ff887c76e27a5e254d887c7ee7e4efaf307d8c693ff01965d0f4779f26df0ea773218fe09e976709c0b01731f5e79788d98635d050fb32191587fc22346c46d2ae56126c223f6f623c2a3082fc51ca510564694e9d58e134ffe7bf28f78f2579e7cd0938f51f23727de0d7192e73062141b1ae23abde344c09d5cc64a048d0660119c82a7390144c0428464348e60215e3c624414425ca73910f00b37d56ee7c606871c7ce3c59cfa914c1754dc7cf09ebb27fd1f3cd0089d0b3e709dd67154f7a41f67c9e190a03e1a197104f601789a0b00090e12440b0b07616991431095178de000789aa3708287d734f13a98d7f934683fbcf493939099420e95916e47fbb21c2178f259ddaab3223f04e744c04c3ccd5d4a301020b90908093b3e1a19f103e4086e799a974002fef1c3e7c7122323603f72f0124f731296e054ca86540945a8498d8095789a272901fbf081a6857db4e0f0d1c2d9ebce7d744ffaf3d77998e90b97518c8dccc22c4f73242edca347173d98dc8f646e00eb91048fe0699ec304f3e0816402e6e14513b28f648ed6f0709de64cc03b3cfa448ef88fee09fd1d5f078b39d68f787829074de847a322da78224e280958044f73231e6e6a8271703ebc64e345ceb813308e179f8827ff644696aed3dc0958f3b218d97e348aa979221ececd89c71431c73ac8238b71e15658f3788869904751ccb15eafc8b8c9431e456f7dd539e9c74b98a941eb26c8917d098733627383b604754ee21c4ebee79cdb3ccd35cdb76e475b610f6d1cdba03ad035075720f7a9a0701a8742a15cfab471f9d38643390a9583f36b3bdaf524909528e732ceb911f0e669ce69db46679c93fbb2f82baf1ff4fab1d71f82179f02c00be783f0859d0d6fbd88170325e22dbdf5cf0bbba2b7ee796167f4d6dd1be2f50bf1e27fe0f507f1e2abbcf840bcf8b18717bf7f0714cd37e9dcc9b7546c723a75ce79fd98f3ce65b7d36d7e551ba77956e6f3fce68536aeb24175270ebbe6d835d79edbb20acae69a6b7743a1b0c78e05cdb1ebf4e661bf19b2d2732a3649c51c1c1c9d566e5e4e9357d3501e761e9e3cdc9c73e9a950dd69cba4d60377de6907391a1511fb900718b47312e5f84d07775ed7fc7ea1945ebc9ea671dc178ae0b7eb996b1ffd78703d525aeaf005a7886638611adcbcd42ca3db903d218738611e45d4adae3a7c3b6a48e9db5160ba25bf5161be1d270c188cda21f7b05e2855d55e8a3de43c547598abf6d24bbdfadd503be44a838c2bd037ddb634b587156813dabc6c431b182d9db9fceea2f8f8ec0b4560b72c0df606f46d5a42d426f48d42e990dbc32dcbb787a8a16fdfb26c409b9676e5867d6ff9768aa325f60cc528db63b7f7bc2a0af8ed2d8768908bf227472314acf9688402352fc247231dd2fc4d7aff681454f4dccca44f6e62bf2a28d46386abe717d72c73eab81e207e3be9d84159bd94609476fb8159b858c42828f6361f8d82b23c277167d6ab7399a779cd2147e7248eaeaa4e5d551dfccc6dfda2809fe94c2f7329dd3af8f4a36bb8a270c8d56328ab8720033d1f5f7650eea5623f95f5ea5465bf28e05707bf7e6083311609e5d0cb09460cb18b3448acc0082213d8200b971258a1822e6de04046092aae2852b3b0987467403f4e5cb921290d2f4cfc840182074f98c00b2d5a9ca14676861bad5a82254c5000f2918c165bb4e0e1816068d0e808498632ac5be2f4c9d23d15140a83c1b0f868e6630745c2607fc5112b7eca2c8b17191d2155a121a22d5ee5bb9265ad48494a52faca182d4b1eb1d9adb5d60cdf9b69b5fa90a48f9e752745acd382896c0ecef842c59ce1023a7900f3edb4c374517714636c0eb208e37b4716519ce13854f44a51a7ce4326f1d334edb331327d8c696c98658c6b3cede981d3e2694f0b7ee62461017b20c415a53909f809c2037e7a04c3fa94043f5dd29f1ec37033906ccce83166769b51070f7925856e491556c842a847163ebccd473259c0d0483a9bce59bdaffe546acd497a98924adddbb3d2eed94f701d593863a6657b6da6b6518371ce8bd44773ce39abfd12c5a452da3a6f967977aee49cb251e0f86b29a753fa517c69c5b3d3542963adb54a4a294d7537f8b160f6d79eb5571ccf1aec0eab809d71c0b9c3911966ba94525a6b9b075c8c2594c1328b34d618e7cf8c69add44bdd3461b7dbe9c984098b0582dd03a0f48752a323a4a44c68a8bba8b3ac6b96654a46f2288946876920ae2cd06043e08adcdd32ce53a4e16f7ae028c69194a398d654663db670a5e1e421de0cd30ca76badf5cb33e3746bd669bbd2254f6f984de7ec76e8a4f35e2abf3b69537ab34a7d6a6165a419b5b6d2ccdacc567abbe532e644ea74465aadacb5ab6c154c195053e8cc1abdd4fc22d8aaa0d8fa55c1b3082ebaf28e974fa76d239c54e304411206270641f2210e52def121ce7bc76030d80faf7982b83243444412cd9820aee2eff81a3f9c20f40b32abc4100789474ea968d974c545c69ff5a67c66b1a595524c69cfeb34a59489a462f3b1ab36762a0bba108b5ef7f3b992b98da034a3d7d6fbdd23567a2d12579ae6deb3e9165cb76d3aa3adb5566bad4bbfd37677ada8cb4d3a27fdb20696e6fcc25a5f48fa486d5561aea267de0c0d46d78278f91a87e9f4a61fd2a792468cbb453bced3749da6b2e2eba2bd923e35ede5773735d9b1e9697e3dc5d4d8444a9a533127bab59987d6663d1fd2d983569a691aeca40671183166ced82d5cbcd09a65599665a9d4bd2864d99af6e92cad8566dd68d2a861f221613eba986be6cc47efceb22d718df49159a8ec8e34ab99cd325b977c741a64ce944d0f95d6196348e367a404b96b77cf2ffcc254df2cbba9eda66d69a5edd9a75a4a2995a19b055e69189d46b79e6b74ff2f080ece4fc7b552cf7f4b0dfb696d2991489c18e7a45efea6f58ba1c7cb507fce9e2fa8d6668c837132c6c1c138631c8c536666367af6e1dca0f530c6186908627266b3cc33cbfa6bd31eadac3293d2d66ce2b6dabd338bf5d35aa3f87ead699bf751ad6a56d3b2fa31cd4be974bae2110c06f3e1155b521a942e43cc913e6db2228a32a66f85e72f7d1cfb5501ff0bcd34bab744871cd210aac8b87ea12ad259269323c09129f6b075e9619659cfac53c93e9c06a9758a735be1d568e6797a997c51b75eef871b5c82ade70627cecc387a094839c45d1539c46f371ce73cbcb7fabd1f4ec655f0636b8b7c54156930fa1115141bd20f65c0a1def3b58b4b37f770f330a5dbe6746edbb67da1f661cfa8a535bae86bd28e437e9657de0fd3d487f4335ba374cdf9c5336836457eb4d65ab194d265a8b8521d709c27514239c619299d9f9c7376e1ba5cb7de025ed785d8182594a97352b69cb3ce8f31c7528f42d0c8d9cd19dfdccaf7e757c7ddbab9c6a01b93434ce91453c6cf868f5e5190716aa52eabb40ddf4a747e58ca0fa7c19e6d6b566fa532469b1b67ce8943299d4e854edcad5a67d3302a9df299d75abfb849a933334f86fab2bea4d3059d14e3c4534a4a29a5544ada30fc516a60aeda979462d39284c5a52897967e989ae4921b59f6eace7035a0a4a494a4032efacb4c8232294a59ab9452ca1865edf0db7962cad14309e4dd8a2f7c07a5d65b6fbdf58b111604173d19eac7482fa5f3de54ca87f8b044872ca991121c993670b75b32ce8c02e72ad2e90ddecf67ed56419329634c399125cd6a66b3cc566a468ca9318e0518b240f8424a69cb3aedd82476bb9c5e3799ddb2e79c937ac7e3834a2b75d9d309fdfe32a9ede003476393fa418c5ea32b82105d278f391fc312360f03c07918c7600f23169d87f1061fbdf8e827afc3e0f5c2509e385dee5cf44f023f7f7632e6549f14cb8e05af1d144ba3a4f494d5b9432516d9ae5966b4318bb15614a898b984b21a8c4eab9dd99c5fadd72dcd94b6aacbae421a8d317e617bf79d3326344454ad56b5feb90d94a3df8fce3953a939bf5073fa454dd3b448354dd39294969ae69c3395a2b118a3cb59358dd27b959672fda6fce8446d91cde563df2e93baa5ce238e1863ec21f821eb1bcba2798dbee5918cc1a65ca121a21fa0a01c97523a0d9b11e9c82815d440dd5c421a4e1edb87863532cd965884bf507241f3934a9faf6bb64431618a7c8540d6c9ec081d1d9d6e49d796b9d53c6e9e05a6b020969a79aeda897461cd55bbf5ba8044ba64e93a5dd433c82ee3ab697ba43dbbc418bf9ed6e56d0f73a594c65863ad2d1b6bf59942aba98e95b4886b189e8a0c1453b13edd0af57086cfbe10fcf87befbdf7b35281d88c91a3c7ee5a91d6fbba157a8e84d967857a68a54f9742ddfaf4ec7eec5a882ff9c5b80aed67a57e5da4f758399be0c2ed0b6fecbcc3e95628037d2ad8e3dfd377e574aa7e1bb4f8b3a279c89dfc7a3d9d4e1f96ec1df759d11c86cfbe2e28cfa84f8753d7755dd7755d773a9d4ea7d3e9e4359cbaaeebbaaeebaad3ee743a9d4ea753d7755dad5e6f6dd1902ebfbba5ec9eddb34a99654ea775dc6037cfe334d85a72c8faf6cd711a6c4781355d77aedabbdb639742019143563b4bd64a83d0a86599a69a4eb5ec88c69a5e9110a41e16f93088cba52ab314ec23cf22cad2290070c8451a948dd3411a0a2e4f17fd4218be37a79aadb5d65a6bdd3eceb50f06549e2e5b6badb5d69a655996655956c3193ec412e34a7a6c1d7cbcb0d450b32ccb28a58e039317752c3cd3adb5d65a6be987857af6ddb98ad65a5b6b751c98bcea87a5bae54a2821e4f9507ac7488274eac59824ecf9f08b318974d93d91df5ee3ab86882434079633696e40c79717cf97f63c57d17b640db7372f38ea5ea87de195dd8e148ee7c3c845dcd8797a5ed8b9eedb60fda8c8407ffbac84607e9711e0d849c1df951ed8eb0a4f0d754801060fde90638e3a5ed8b1f4bcf087a5f3f859096178fbe12ed83baf06092b8a01fdf8dc60c3eb4aace3f5f3e3853f1db063a9014bcf8b73cce485bd06fce5b99ace711ce7281f72fb7461a921470a3296a0010fb43802e9c5b94fcf8f8f8fcf0f9317f61ff085dde727f5c2fe735fd82b11ae3e30d80b7b10b017fe6ae8e982831be26022052bb0c1062f9f4b85101d5c5e3e3e38dcd71554130c967a5dc9d6c0602fce7d70005f57261db017e7383079711f962245e4408b9f2f597cd8e2f5a56fb28831262905539421e635b9f8d4c0e708336bc6387a4d1444b1050f6240d1850eaf944d818f7c135d3ab248d5ad25e5ee231933b025717c777777dfa08c3f9229a3c6b7cef8f679b5639c6e7d61952259b3954e9d14545841e654e63e922903c68720124958a42d7c7a90e50d159c404889962b5e008b030e2038b8c091a948420755dda1e22acbe4a0a84c99bff948a60c9126c4419975d0f1566697301f9deb80182058f3ed610864d02da554720a7b843431d14c16df552c7dbb93c88619b18c30df0e46115fc851860c221a2fdf5d7c116b00c53716597c7b175e7c1187956804b3e16598517062f085096098b043add9298432c68888450d90d40064e3db3f31862801ae01044b0d6c503024893805cc8697a171bebfd0036728eb14c220854d10ad2fbe65f78453f3eddd39b95ccced1482e0281be3db67e7c49ee0fb491d621215c06ab937f87e32b9503a29a5744e4ae9a4b206a7f0e713df0540157d37f9febe67ca2c0917503be43012f6f2c99411fa48e68a18928f64ac58fa0aa65bddcdaf82a9b5123558adc815a85b6105f312f69212f63aadd341d3c59a49d2a99ad824be7c8553493a3dd32efa6a2e625e7a0cdbcc4b8f619f79e9316c342fc356f392e9e7254543d3c8353edd59b4bcdcf23294a1540aa823a8840c7765490c32a5660680000008002315002020100c09c582e178344d04c5e20714800e7a984a74529989a44910c4384a19638c31c000000110019a196d132af7690120ee74a835c5af9be19f9ab647821b03d6d8c93d81b6b8d0a8cd4c6d06fbb4a2119cfa6c52f9e3813a1271ef9647d05724ca87f16151dbd7b7c4223a63696629984669c69f38f53d083e156d27c07cf1ba6b95d53be78e79bee2b2fbba80362f430d4e537a93c49ff6ce71cdf2536ddd8d394465f905d88135bc4899a30b62666d361b0df7d8b20c7d9d7e604d99835e21fef701cf4592a79c7a7550aa12ecaf725b5b1990148dbf1cd14390033ad09bfbfbd3845c951a6de8939708953ba52750998ae77c3363dbf1f2a8e9b66abc81b66fc3f89c35b100a504cdaf22490b2fd49351382b9d2a5367e802e0c204041202076b0d740aa0a2427b25af83b6616c3e0f5ed9fe3831f54627a60243204bbe87c0b96b56764e66d2f5bb34fa6f199040c28764f7f35fb2836d16bfe4d90d8aa8682b59a6fb6ec007d3ec2a81d310fd79fa72f3705c7873489e78e4feb410b23e32c4dd5fa10089d3aef07e9bfbdf0af5d2cfcb3d3156276e003b36d60ffc1790ec48f603a3027b4fc10dab4a76ce11c6196c33d258730f982c59f912161f982796517da77221cd58bdc4959def13f8238f2d17af2d758491137dc458c6b324471f094a206f0d69d77c890248013431e872a448c9fce8daa3f103a58925a134a39f51046fe4c9809b1834512982b978f672d4002d18ca576fb014df75328b1c05a223ec62997637942820fd612f9c846968ffe8b9970c908da5a001d724df66ee82f6ae9c349d888dba18850782f2765aa6b694decb1444d696d17ac1f1778b0463bc48c0dc70d48a7179c8452401994164ff82c706441e495ca8f72df575626788b30e498145e43d762eaa2b9d8e24a90176dd16053c79ebd0e64eda77f59cd6f8b7e415d8fd4411c73da76d92def7dd538f09a508dbd347eb7a36da4ba1283f9eca17db05bfda0ca83f5174ec83a1478df6911c362d5a111468a3630229dcca4d6439c8d08649723aaf82c8c5ef77bb7737ec56615eaff9d081144bbad34f46f1a510131f9dd6dd54ade4098d53914e03868f61e4e657a8df940c9dcc7aa1097d2e492afe783402047f3fcd7bb37120492503a0eede32aa9a231809318e137624638a56f4c3d8486df41840852b7ce6d135e143d6d03a4841c8debd347441dcc0c3a01c62f3f41a110ccac370cefc95c89580f1868c07aa9d59ea58e15b456db3e37bdf3929415e405f0a0e26ceda283044a413c53c2f6d8c33de84e25ba8a0b4658d3d7a0cab6f8d82b20983404bd71a76ce813686217ba15196a01c82b9a517a1d1ebc6151fff856ed13595e67117d2bc05afd12a8724f18b7ee874f61bf95741cbfc8f22bdeafed76f2d672521cf64932d487c223badf4e917dad47c5d0844b767d9f6a2628a55577938f18928038828a4a28609adb24ab8a320780015226a798eafb9a769d6bdd287cfac5e0cdbc431e8d116cacc8d3011759d48a46802d84c16fa4570ec5c55e47c61d600f1a7521b5288dd70aece09ef11532042cc9de3fe71af8403dc4381aa0e1c3ce178a9e760d3f9b5ae0f9c6d267593cd9c87ea02414d9c62d09f0b20a073c9cfbc6fe0529743d3f40ccb5421d78e80b49242f4d8cd1698f520e7066ed94a4dad0e44e998afba4542eca6586511c070b32ea39b8f82c55128fc020dfb36d0887fe60a796c88f39c0eaa8ae0124c4dd2255239b84d6922ea65ac4f0f1daa3554d73b4954cf6706f789c5d7aca6a3d2e3ad26432e829ff14176ffeb3913eac1784025a7033c49d027485b7c0e6a83f8a493286164037c23f3e35913c36db6ca084c8430692f9f950eb9930cf0e66096cdc1cdfd68d999b6dd11bf18191dbca081647486c6c41d74ef55c0086abe80e3cf7af17dcd01c8c48a04d2c77117dd4ae09358099789c9a319b24d816e4a55cc9de288879e492d11870b4679b7c71710953c23fbf628dce27a4d67f851ad6ab9273149f52f78f90f4892f9a72958fb1432fc4400e62f589f21e8547cdde573a5273921281a46f2fe2cc9e132445f6553f0daaef0508d4595feb40256447cfca5ca7f608ba108acb9ae03d39face9da4c84bf32fdefbc3fe47e63ba65ce96f839c3b25f55102f805d039a9389d3cf117061cb2bc9fe5678226b5f70a0183cf10f0eef96de4b81b74ed21f46d359b9acd31780b8c9a9f879abd7d2e67569a48a7f1c36443518dc02cc5e05920082a2a8df06c9cc5610abc080fe1dbcd110ac256824b67358ce09a130734c831bdb4ee9815b9b4881d8bb29b06666bdf9c5cb0a999354841eec7d1cdb09777560b07cfee03435c606041af95363db905b029c620a2e1e0720edabb218b9eb3773494605217ca8ec544ab0ed64a9d7d5fbf161f1ab0bad61ff1409b8686439e4d678a866dcf5c95e6520087ca106873465e682d1d45527122dd0c2ee1116b23e1e7b7d60c5a9a7605f5815fb1879a0e1dcbc61327008fb634d82c80a3fcedec5aa513384e66cbc0fdd1bfc804acf24c1852037e66fc080ea22481ad1708272fd01962ff051d6557fc3d2f1a6226d133410c5a903a03f6ec4ee542b27054b4bd2b041a98d81c09b6f0017b0651e328ba7333a32de00de561cfce4eb75e407699ce0aee926f6758bf491b3580ba16dc4bab64fdf641d2a18e68e3aea0d5068f1177c159fdc0ad58f2d0330f133a1793c1c100cd4b1589f172d2d1827b2144d26fa79e8a7a2d33de7702a11427efb04cc60d309743dc7882f1d26049d73fe9b57b39f5dfc9bd503804ce207e29948c464bc469853cdbb5d5aee8991657bee88bce4d3773b33d0faf8c576af72908e1e80b50dc1261c86bb731815f4eb1db39c57850f3f243ee525da8dd5804920ec4efdb35453b01db8b5477c61377a59dfdfc49e377c4590dd024190ac6ffe24727c677023f7f507990843ad5a936440c2874db33c4f90b084806ed1904896bb6b384795ff54fbb186767cb4073b5be25b6c9305902a8d8fc1f90e4a1f29782af8df46815621c486686b8caf86791bf76b036fc484ad0f3f3fff31b9303775e2b6465d9471084a295fe4058d7fd0937fb02ac775e58f28b44fb2af86670bc6447a392d6527492b83ca34affffac9f49a4949c673354605f5beab7b13fb30cae04e4d4c67f80bd0b8b6396d03cb4243cad90a5d76ec6ed8f3e0401fd1bb16140c7bff5d1843047e0d0fb727c8b15f48b768f356abd6767d3a958148198ed40917290359595d8ae6ad1b73eb444fd36f92156f7735f29bb337efae7103b209e690fad4c51ae294ac66032d014498ec7fba5684219b6e4b1df0bb6db8785dbbedec9b3193c8d12baeae4f06e720dae026e61b6d5b68cf282021b50f8685e0a3228f2e6a63c0ad0cbc7bcd705704af91c88393246aa81896955f8e431bf45b2aadd7d40dc188d942c1e7734dcaebcc34e922b1d13edd3d674bcb6f27db6efafbcb088f9b374f329702a38de9a5d68379e9b2c1dd964e7f932604acf72de1cc1bd0b8d5c29d6b7853cd380bf6d4727cf94643f9a44bbd2137b747ca42b71c255ce0f2f483f4506d4c76a5539b905dc8fde9cc5a3a2d40c3e4418013bc935f36a24a50ea45c626d2ee3c399986d10420eae5a5de6c92af31f2366242c9d8e2fb1c600912477390722dd556183be27327492b5befd4744d5a0d8bb5a9aa3466e8c32a418f6aae1bdcbb01a8caae310743c2773badb0ce818808af43da320c1fe1aab66304dd0e2298cc2c43a0070ccb04eb265db263a195f18af9dc2f87411972c4de59d871db004d6c234e0674683a7592ec67c564b04909f6c4bae702dfa7d656ed4ace9b3a0795785f9c45a311c9853020b82d909bdca360d4541f634fe55ec01e0282c11f971c4ff69603370f8f84c2118adbde8ca943595eb69ea300d1388bfd485979623a3846189d8f41447190e5007f86d2f3f9cd9ca7da0ceef708def0bcd75763ae857b560934d3aae1a3d5e5d25546eb4691431961e61fbc670727cc04db429a1cf320e8a2ed92f6caefe2e3b4c8a09be85dd7720d472cb8f935f6b3ccb1e1665efd1333c635a1c56ea545513348ceb295bdeb66288dfccb26c4d714266d9fc883bdf888f22d8bea17c3a5c74106d8a413645827e313463ddc29742216f2d2276dd41eeb6dde40b38353d8ff78216e11acd9c3e290d54bc13034a5e39c9c08fa7669f369b4e39c80d985bc02770bea5f1167ef7da95cc0c175c49a1b6a912c3df508f7ab7c931a4df52570b7bb2dd3abb79b3bcc3a44709459e9cf8fe2129ffc21cfa19216b1a33deb94be114bc67f34011ca99dadcb0c1cf411f10b647003557b382ee99ce1f3b2cc19fba595a24f33bca5e12bdb78bb361f1e1a9607b6acf2d71a1f10b6205211b9724ae51a1b07889606b18e4dd312f3cf6b58c26482286915bfc9041c6f94d7ccfc019134a0644c5c6df12a7728e8c85c24df6aa038f9efa566201f891d0554c78963d3ae0e674145f47d19ca1f9f42ad0ebd529873fd38b240b295400ed2c49b4d22d3a589cf8fbb841aa7caeb0b9c0fd74e30f398d15205d31deaf11f0fbc62fdd326d22da8837c0d8eda902ab2c84b8b75f8bbe9cfca0d5766d534c422158d35a2ebbe16fc49f690289f467a478aba93258b5354d5754b4dbc9b54bee2034b6a0e9f2b24f1ca016d018403415c8c6bb5ba0dcab708fa588a86247e63545fac311529fdd6dbdf769a6fef1426ea94b7d9d8e153c3f0371358b364b4141a7dec54303badd439d3112cfb9bc067adabff78974b4cd78a6176f42415b338c1e7a8513bded7ad95fdd612352dcf06e8b54dabe7fbcab8c1801728c6641f132f1a3f102c936d80b2c488d45b8212a2d20f2f74e3672251b0fbc9d464edf4452692aaa47b1d227ad14823d7a936feb014b9cbc3ef6225467039b4b82f52895ab09734393003a266bf137eb7989c83091f4d9978cc9228fdc959dbee22e3ae038280c960b20887067d3bb6d6dda33ba56e455ccceb4fbf62dd7b0f7bd3bdf5c2739e94e79754b0cb8b68282a30b2ed11b60fd1cb00f2f92b4001a96f170498089cf61e090abc3313325253c3bbd7a71a672d2ddf28493d2d923cea6018c5fb31e756852e285f0e99249ad138e66d23fe102b0296b46eb315a4c5bb3ed4defddcbfcd1b1b2716f525141fe4e405aff7ce31dc60a3aa489bbdb337ae54bc2657b6ca74134cde0277efd6a5278e26cf53fa0227f05840b48070eb8ada4c6e6bb2f0ad5c5f04a8689df889b81517f35668b9fe339bc0bd7db90e8a4b7de8f832d79506fb98a1499b80bbc3613f444920ee2b5125147f0418d2c6c81e5d58322726b39aeba30a3eebe2b13e5b7b741b84926db838402f68998e06e91de091fb037cd66cca79fdf28e70d186b7b04204559a065ea74ac227565cac8d94519649a1f3e794719ec2e5a35687f2c3c28d1b825e9fcbe7c7476b61da07c3c08bc735f4ca199f3f88327bc53a1276eb8ab9902a8cfd166c2e650872b619b70f14b87aaf13efb09c8300127e92178fe41f54a94c24b61fd4ba8aa6889022575d117853126fb0c0918e7223a677652a7b3822159f45924b4209b5d7e52e8448e8bbfafc3485d50e2b4faaafd4d7a44920ac55474bd2043c9dacbbf817dac2ccc008c8c9ca9a07b1ef57afc3a19678d2ac74572e6fc46a5d6c769a3f36a7af78a039d0020ab4e63a0b137d7b3099fec9135247d4424e316afef94f40fc6c331d0a3cafe121c50034d2584028d24dea06e7ab8f4f9fba1f855548b6838f11080832aa540311b90ee97a3204eae1f6c8edae815ef312091a8e3126d88e6bc7d449102a6ece9283800d8310dc789d99282b9e63df4167371d23d27c0089de42a3a398bb44442277aef469420d1fa4b22912247edca2994a0efc8fe4a285e61daa0088a24855ffd75cd38a46e265490d3e2a1fad8fd597a291b8d3dafa7c30f72ef6bdc9e6d64beae386a713bb5f8686dfb9956c5052f04b17990b70ade29c60d88da320915c5d2cb0879765258b5ec304f84cfadd3892da0e8eac99997163964d7c55e9b83a793415638b7391002441b7baaf3a5fa59e188b72856f481e73fb400e50c73e8b5abbcf984932cd4a2bbaed26b24465f9020c3188274fe2afdea5c6dcbd5d351c1e7ccab740e963a3e51e9515b0b55cedb81308ddd46c26245a978a9fc3912f02632526c022e3e4ffcd1ece6fd6d4b1d5207e11fb73b3e428ed7fcdcaba102ed7322f214d6a83da6ca50089546ac1f5effd806b79c542529c93de198298bff596fe3a722bc435f950f3ebcc110e561dadc97ed9a486b18a138d38a848d65256f5fba945b63456b706634a76e9286006829eb4cb11067d0826686b3fab5795d27b102f3faee22c1d169c172dd2f5f85cd75f8041f6a92555941ed226d38be3864297320f9239f77d31fccba73d0c27b870e1660fbebb85c7e47b66cde7a5a5a66937b8bd671c7f362e88973cf62596031a5ff30677202ca1bd00038b97ae1b77d15d22c1851257937c256f41c87f633806c2b9153df6464320987ae2786055320d224f5855741aa3c4cacbc6eb8c15b0a108dd3848ebec19197d3e576c6c78238fa0a3919493f9246ae7e54c43c81024211884c098625ada13addbbb381792a8352c1b4073c8cf0492e1cefaf136999ff7dbfd3d58a6c1ae3bd83c0d2aea164cba0f6ea3161dc97283fde0123967f3f8205d727b2d908b148a3f043b0842b3aab7250c4c90f33726da76180c10114e1030efba4fd58a10adb92e68265e9c13ed1f5e842af22b3ee2efc4f5e0a990f260248169b70a2b99c4d883c8e7c122177a3b85bfb4e7a703f68eb5c77230b38207b826bb9e9bb11047088db8e2d588ebf093c51c82d82783d008c5cb11dc309e7f6e394f3bc98ec192e394f23769ad60e1bf1370dc0787c3692d9080b63ae4bdc36350b64c6738b5a6d53278a928a619cdc9aa8a2e2a465b8dedc2605188a616a6596a537c02c31486348889869f90000e0457bb66c2715fefe69a057681708f4060296fcae9de18c9fd10b1cfd2dc5d16e8fbf3a98718e51070136d283a847aeea6ca7a30c70772cab0407062f1b6480ced76d58eeed07d038c1d72a4b57eea93ec11e47d1b78c46796cfdae727a688e9808f1d32fa10b93934f0e18c54c874956d0f9985b05493069e8145377567e429db321a933cda4df80b80e6c66bf72ff21c3b57da471004e49866c5a195ba8336a239919616f9259dbefeee94a16ffc078b5c6e37764d6c2cd659bc67e2568f36190585bedbc4170acdd50ae05d5a44a0be9dd801b8a2854960839e67da4c8e665ec69e17f9ed54b5b762d03881bb25ee483ff5e0723436a516a65092a18c928b26267e5c86f91807bbb7cf13bdb92b3e47b2ffb424da660644770e6527ed7386752328b29aca840016a929bcc1e2b1b2675ba001627f61863b99a7452d3f83383143807c85375026b93e52ca050c3bdc151f944ff874c400aeba31c43cfc851fe1f3c0d72fb65409b5b95e4619d9fc95fe1c17191fa86411b38b1b246465435499f36d67b415674aebd38d6d41554662ea6fcd88d9f96838df0dc68208af894c8117f46607ca25aa07ecb9be2f208f2e21a3bcad2fbe0fcc11694f89c8c0393722db074b8ec0db63c6719f6f2ab788b2a82288492742ceb883d4f1d425ccfd61d9917d6b3b62d3aab62fb78cd96c8b1a6d2e5a9bf4059196e4941186b7b4674e335139b95c6497ffd885d7eb52b7596d44088a86a066a013b958108a251b98bd636ad100a0cf04540b398d8731a24d2a7629b35e91deb6bd09127214d47806d1695221db08583c55abb7dbeb84a8804cc1b8c606884fba5dcb783e9461e6c49581a24d263070e4ee29c2129da460fe876614748aa9963193cc04c29551825253fcb710b8079c802431eda07ec559a4b9071a5362838c0bc7c2c350430322c4877dfab0a2a1b0462684b4040f5ea1d3fa1aab374927ca5b74d8e9a287ec700d7e2f3a610fc2b83b3dc3e8a090390b25de9ee9633b16c146b11b1129a20801fc78892f2462b3809166c4b38470b320450b7fd7b178e5c83da2d6ac8cb84b34fc2b3c40c858f842b2bb9efdbc8ca2c250b290b5c222a3d47f056d8297f44e1949205685c238c6a984240c7d18b2a8731bc0200a0f46ecf4fba91f499cfff2fd83a82ed2d83b66148e2bb2cbbaf0bbebecf15f85810af2c53f9a37265d60cb11984132b8c9352925f24bf51e7134eb1d39df76dc10fd0c661502cbe42e90f56ec22d68f796a0771caf230a306f1d27712647d0478b156ce46509354663d4cca6aa4659acae27b2a2a78e45de4ca732fd7177f4749dd3e45e2d435dc29100357ed8a07db50a7d8501441b8808558dd29165ca95c8ef7805a8951241f0d5a898f4c6400093ba8e34e5724f515d58aa83a21a8019dac09c94f24254b483ae71445a8e6f8f886cf04383ab3058419217eebc495fc21f5e101f994f512b7c36cdf91b3ee4e7f7877efc5bb3ba610172f419344390f850d87eceab5e14b67bac4542619b30084198d724e589d2d12685aff460a7d3dd08232bf227544aa536021f0bef6e8cb584c1b0b0e35f45f3ff117fe5d00e6ad1cb487f0fe289615e262bb74eb64d1d2f6081e15e4e6b875c2bf8af94f2a68a20e238959fe052eaf8ef5eb98bf607010abcc757b32ef3811fde6fe207f918e88ef397af786ed769b0cb24e94eff0a0e73c97a3540a886b9ea896ec190f5e2f605db1615408ed911b6ad7353919cb3dd99838d4ef22bc4ae30d3aa5bf6bf0a9ad2219fe8ab3b085f29ea23696e27d42f92102007554ac752de923a302822e932b915960e9a6c1403bae166596e724aafedcce84fcfa06ad1f94da719815fab4cc516ad7131fc75508f403ef0d78cb8875c640c433180d6cb43ec011e0fe5bbfcc87ddc6763c067c5664dc773478ab976247eb2a3e0d55bd1da4c1a424927b860f93ff5e66aa4e194bb65c676418e2929280aed8b4a811c8cd1090ebdb6012fc406c0486683434dde646660f5e4b20852c54ba9e7a3dff1e2c499c05b8201219a0dc2e104a63b998a87abbae24b6b76da59a4da5fb2c1c6f62f585f67bf6810f54b245c4db5ab912a494e95205414451bbd5f3f901fe9887529f126618173b04b962227fca7163a09b5401c545eed4b408ae5af042ef8f0c083447c4d7475bfef383a558c212aaeb2a6e816653236bef7f6516e22fbf9a788b89e979544e0ef1b42ddb773c1819e592ba7c06297e22de4a9d9c03fc5d8f52924175fd752b0b726e4d4dc063d371c879759c35e66cdcab8dd38dbc61f83bdadd49a6b563087f38c79260684e5966453fec96d84782fba5829a4b3be0e69ea5b0a1a282be5042268e923b6963d03d6f70bd04e8c08493d7ef03762997adea07a1680f4155c2870ef58600a1c314841f28ba9590f345a15c0b0de396b9630a6426d65ba63920d8d9b774bba71b7445d987d3ab2369e767e8d3a9eb013568358e403834065abd2956de49a18ff0d42200144aef7ca9f59f3bf84eaf7c20f3818d1faac373c99bc9588946df384595109522a2f14b61b65ce12063062b5fa1789237fb10ba4212d0c365ecc227a7c744715d77073ba8438938f6209421a80a1e72580f93fdf6ea55b8ce91111665c65c3f20cb3df35c29511508592360e0cdfba0de6d40967a6e92931841eb65ffcd53e471042251fdba03222f77fbe46030db11434e287b4483a1fa1aff58bc46d79381d59964fa48120720f453eedb3ff7df18aa8ced48fc7087a092f0481df97093a637e978b3eef81d165cbbdd4fbb6aaf48ce45d6f9b2402349d66084ad9063b7372c6f33819c51329f55a13a4b1898776a697d090a4ce4b37e6a62500ddd2c0b103aaf48cf4a15675319f91fe748fda8bb10456278b0d4f6b03ff351b31b6bfbf68adda1ad090057744acc58c2cded3a9c86ca3e4300f590c6f4f373e047278e3c8a2fd195d51a4d6884af682ee289ab2a37dd5df5ae758ca418fdc10d78891798fcf982c75ca8400cc49175bf32eb95e354667a70ae588a4bce6f06c711a01f9495d6319e3e4ecfeb94cdd88b228ad70b79260ac971a6eb571e5c6061fac598090a9b5af2952ce8dc21f7403c10487045c33a55fde73fcdb5a55567addc5281fda44d9b2d819fdffe692cc576a17f83309376d4a79a60499e7771d28588f90b70ce9e2ccceab27110385707fd3a637dab289b593a8ba147480ad7d8ac0664db15f4d68e99d26457fbb31e512ca84a70cf9322c7f0026e12bc3b43e7c36440c22f5bc895153bc6aae9ea360465885af52bbdf92a3c83986867f8e66537a2240bfaf665fae04ef1cc49b70660f5197290dde1ed33255caceb0194905c829566907cd21e6360bf2d681ef45fadc7b4535f65ea3c563b4a726b76e911a87e4576a8a21e2d562b660d6a4e7ed6e5d11238f8e050148df5b4b0760967f3a8911e69183213b87b82eddfd97c14855d8cac0e186a36f83461f6ec09e7d556966e54344b679f92cd8d64e304989e3739ddd13a36468e0cb1493cbb8aabebeef8d070420d5c318542210b35abfce11a119d6add007a778fc998c7cd06ea0e1098ad7cc0ecfb79df8d1e1fc356f17d433e31a886f809f7258a779dda564be03fd9c0f5480dbe3e43719a31ee4bb2f7a775a4fdef485b7e54524d539dada14fffbea9cae32e0237ef987185b6afdc027be89729da8034a4132f31201883360526fb645c68e1ad04ed15da738889832bc4983da197ff7b1e351b503fa61a319eeb348d8bce23478dacd82a1c78673412517de7c6dbecea802430c52fac4ba3a6ccbb755b3258788da50cf139c22abc413448abcaf0977bba9ba3649fa0bd5ac8beb76853dc30b5197a0b5b1943757f8514095eaad7b1ea65af98b4c93c039a69bf44c801ca72d45a1563dc0edffaa956abf126b25432002574334272e4332e637b2cf9e2b150fec429639ee52328de55b6a206b85eeef673ee497e71972b5370326a166a0792d3c7c294a801a8533f89cc5ed0bc9401465c0790c6d9ed358398fec184242339a9d2e6b5f5c15e86bca0c4a482bf894a174d8445abbbd14bd62c1b3eef0ca51a0001536a5c9a596181810c39c4ee0a2e1236d1ed57b809d02370a904fed10bf7dcb63a4dd5701433c9a6ba7ddce5386087feb1931833c23b1fe5146c7a9d1be6ddca03593be8ade5e7747395f8063996feb66cf369e3a1431f77b2442ce82ca6d6edebe0173f67109c73e044118b93e77faa95fa89bee0d16e5000ec26e65e255c454a107e44f950943947aa455d2d48c6fd1e17df870eba241ffca0559e4497d82448b31783aed47b8f5f5581ea45ec75f4cc80905230bcec9b973f3081a5f60e815b328c9327163c380183eb2ed921827e11deac5588655ca22307207a2817cae4bbfdb24f4dbce02a2374e641bcdcc00a2a0aa3521b170a582f510bfa3a949b265ea67c321b276a4e71cc33c5f24e6797ee665fab51e6783a0de5fbba61984bae89a57931abb558b990daaa48d8e5e1f5f7f22fc3ca5492551b3361b31cce1e931e61d9cd755402ae62b5618308b343ad2ee81e305a87d1f255c1fb502d2222f2920853cc54530de502e33a084cb4dc66f4eac7f7eeeeff81efa57c196aa6c514c5d9bb10034e09fa9e4853292ff718724c7c7e43bce5116e0c7d27be3640407e9152a5790ce9dfa90a7de80b26851bae693c91bda9a93189953167543b802d3aead4f771b83d72e902ebb117c04570a47f07033b1726d92cb7625b017513e32312d03e9cf2d211a0e8c0e1e5169f92303c1191cd9872b698ab010229f3f944a97de7f66ff3ebe00da58c5152866d2e46730136fc9896399ae3b48a4d00bdc2f289dcf070d42987658ba4b34b1eb2dbb474aef0098a8a98a7d5e35d0aefa1a6033406627201c0112bc1d49562953de61e06bd6b4b6312e00d6b831863ced0035b6170e081c4c5bcfd76059d76f9a61945aba429ec60cb8101bddaf2b301e449ef452e43e15e2a5ed93667027cf683be5d181811ab9bdf8a20e55203a1ca404de2ac8596d845100c2db1d07ddb955e8c5be5acccfb8bdb0ae6fa73d3669ee7a4877e88cb2bad19446d7c1623574cdde4281cc35fb24a1560558e6009c17a60cb1cddb2c70a167021b8e45a9ec57e8c93a8a7116f58f02f7e4c7c02e8dcd1d7f1bcff997943ea2ab5ec447747ac271632bc1ef16e84797bde38f6ad08faabba60d61057fcf4273ae7dec10457cc47c40eb07e62d0176efce8822914b654f43691300ed12d42d1339d59eb9bf3e0dd620db388482cba7469fc02f016eca6e5d294d4cb5304499f2340ccad60509ceda35aafc66ec2466fa4ff3ff66ef2144b1e0119d73e8e2f18e6dbd74f4eb54548ddc00e545ff20e34204319bfbdd8a497a1925d7f2da10f6da8cfb63d7919f364d24ba5ae6bfbed356ed3eba081f815e57a0bde9991d8df466839b8dfada5822d1102b7c6e17f08f57a677db14894ef3585d8aeb0a2201647228eae687d7240a891faaad596aab5cc4ba1f352e9022e87d17f14001f0c8dd9bde3957d451192323bfe110733e3fd4bc59364817dbd23480eab0ff2d5d485cacb2535e4e110f96134e1136a54df0196c866413ebcf544ae065a4eeb2e1cffcff5f7d18794a2cf4d2c3de22458f3461a9af3dd6e0b4a0da85af499caa9812d45570ec307e6d3c4b0b4b82ae35a28a42a30dfa7342c3c5a6e8770c328f296ee085394925b968d1441c6b8489652921fae941037a5ce843ad351f25db8512ff2d0939696722f35906392af997dec2e67df027e0c9c20189021de533a2d5a65abb80c0ae86e8dc6c258f34030150c273dc4e28a986e93e9907934a1006abfe0409f930de4fa480535403504adc14fdf08989aa0a65ed7e464978f15a3292d7a0a4e3dc392cebd7a83214511a3921916e8ca29c754c01d174ddc5d24faf236007527b1a1657e5aed19a6030ee42f936dcaa54e78652df7256a5f0503a01a6e8306872aa8f4adc8048a2f8c1feb25eea77a29feb6f3d036320711d470bcfc0b522265c2b0e27f4912e53b357ccec905feb266c1478dc7467d85ac233312a917e9586108ae7db9686e60b1179547191e17e9e5b2565e96c3613dcef67b18cbeb734506436c52761ea586a816306de4895c1d72d1fd6a08d31ea50fcb05d4d28924d66beac6727ee8fd5b69fbba12294e87e82296224919e2c2aab48364bc4458e9c32a2a2baa318e0c1fe909dd33f074aae47d55b5820f42a408c6da1d08ecb5929b634d9cb19a3cd4663c1870a56cf4efb86f764e753ee9c97eea38db806b6996aeb8bc375bf8f9dfffdb55b041ea254ca94b771cdbb88ad9b23c3604d0e67c455a9c7b9e6c856a0d71290f008736b428e5ec90bd2efe8aadd5dc035bb49b6166197c8a81f66e66834f1d45cf757d626ab116b075442472c1cd1e4985e4d7b474e5f39a87b2bbf2fa99344f562adc9ea126d0b6b53ee6c92d6a214e33fe483d7a772190e4fcfed5de7058fcbb778b536f2c1dc7150ce7380fc590284f20f5c0529489552d0636e210cf7024bd0563101f9b8e43ca31c1654b53ab0123384d0647302ed108bdc14988a5805d513c6cd2be02b9949fac87064655e6e2d5a907a8b4cf5a013e69e4a324e12d275c96dc8fff666d5ccea35e6519b0790a64dfe7ff07395172b724a04bdb6b1b75f85c3229bf28b7a69044ba08493158131f42b96f2c0c3c63c6218ba52d0408aad955fba0a05afb0ae5140735002050ce28b3a830c2634a3b819e5bcd3d699f13ccec6118f0be5f4a8e04462a46cc1a4b2d284b4bc3b3dc2957e7eacc9ece4328060750b818fb0ee09072a94114731f3c5238a2b96fb5f9c4f78b9139cb21f89216fb5ae556f19d3b32818c3b46f561cc932e75fb30aa314245de5a8cf51bf2ede6f10bc6c0a165717337904dca8fe5d38e865491b2ebe4987735879711d929b83afbfef9154954840364bfc88eb7cdee9da3fe618825e2038af73bcaa3c6d6531842d0508a1e8317ff7003b6a07eedfcc014c50778c0997d06795dfb2a3d19eae0d34c2ebabb707b47722b43a9d15e164efda5e19eb20b441275b9fa5c79b3774419f4f7051a0baf8fada50e224baf6219dd2784276cefced07983838c30b31b2215de615c2b1e41dd8a575f0c4587f4addec0c1127775159303403c2e328415494055a38c860c25bb49f5173924a229a37facd6a813b9b271a96f0388a773654e8822471e4846d02571e10070cc9bf1a3aa32c8f92d318ade89688b0d380002bdbc7dff1dd7dd61c547493388e215a51076233b6946cd235b8ad40d0da77adc288332cac6d8f7816d5f1b00782efed00e973710fcac08ee99b0f90e10e7bd55cf02574538947be99f0d4d084a72d00ad1c99237c59155851d90dc62cd82daedfb261354334610d546f9ab1e83370900f6e8054241f6026d47224372dc60e544e0ef81ad94afef1ab86712d0cf524141a38c109500657b1dfdfc4a2b1c424409870b58817bd7f850cdd68948144142ea037cd37b080aa474d5fe2c268f5bfdeb580335c87725a367ecc5610192c88fd42e36aa56ee091ed6305c6c5dfd1848b0a52a2a051d644e706f644880d3df89e265e080a4f8cf3dbf64ea4790f84238ca73581e8ee206fdb6ee8361d44590a76e67d10cafb6cb0807df95b27d7ed8bd79b23ab56ad5c0d5196a45eaa5487d20e59fe3895afc05f8c78be87c40a68022b5c155f4643d51f67a54095370d12e5522deb08b426d900e91c9b408a529017411c6ed3d62f2d26614ea2077e0584f6e761a92d8ef3b56eac0850686d83912d5d60c4bd0bcdbbbd425656419060c4106a0fc145ac74071bcbde85f0a6ba08fe161abf6906a06c6afc1614e06bf952302b9457077dc9c1033e76780266d3f5788b805404277e585588ea20cec846a99c9fb20fb82329dcdee0c57778cd3b3cebee5f407762682c5c867eb9885b4a0ad441eb48043feb3cc1c04bfde32ec0096525306cef688fc37511c1b16a8bd1df78a8da68467913779aa0f8d9ee0452b06dcb62c8d25e7624262f9b40bdbb4c04e6ed5730a526c060b881dca532088dfba3b43aa12216193cb9afd58a964ab646ecee9998342420ff8886d893c02f648560fe6758e57ee6cf9024117d859ba3e9d7766bbdcc4385347ec0d607d3623a15a1d1739454b4469349daa11b993f8f922f12e3b1b70d14f6e0f974896d5a83aa00e5b8cf48eb6b7b3a961ce71768c711558aa0152e7a405925d625b44146582c2615a739a3546fbeb3128b034ace74127901b2eb69f335a9ae21eea5d660e89c105bc43e172c5b4b741178fde63fce44a78004c29e106fba7dee054fcc8d556e3809227e381633928d1ffb12ceee68c4e0aa403618bd2ac25932dd1c9921ddc6dc16211c558560beede0fb900ab122c2bf65067b4a19923858b3e6c32f64f70c402b2c421eb60b5c02a048114b4005dc28278fdf5db38ab2066debd4ffafcfe59cccdd24f9d5d59ef0e17efd7de66afc62c070c2d2aab84df66311f1a01fddd47a27d9b043fd86bba4ab8787ac6d8dca13399c36f36aa8b7f551d9cd752b81e8df5ca42c42c7becc0198dd97f71868859c7b1fd4a908e3f95c43bc24358077cfca76ba724dafb765f8ba350ad872d6bb81f3712d70324b51a92ca7457f9185aabd35d0c9cd0561516972afc7317c34cbe865eb011dd81c002e8aa4bb6701e4e8888c9d4e1b303d03703874f5406fe1f924e8dbf39dc1de98329f8450e1fa552671b9dbb8e216139f4c3502881dcf352eaf38b014f458c8a7dedf05f9e371bc0d9a280863023d8234805e211df73e70faf1faa6aaa081a7783f7a782fb4e8a55cd7f6951f17ea456471a15a934e765896e0d1707d35c84747c094129ee2109c420e2288c90d19052b4090147462bc845219f9e8194f9da2820cc51f6ca9218ea9a2026b2538b0803c16665f48a8c23c55ba8a43178e2f22deacaf6334199caa8f72c83ead47f7bd9c85efb2873db88e1bec855ac3b1dcccb8fddec90091ee8464cda2dc392c352751290fa830b5a033bd6da14dc894227889591bcaca45ffeef989f5657d1b76721a7372328105b9eec537ab5be8a6d11ea66ac8eb20786e3ee34bf530a33e0152662bdeb1264c5b967d8e05117752797f1f1f5a02518d074a53fd726dedd6346bf8a502d8abe64a2c34c752884cf203c3769b136b356e831530923e9f668879b8dc91887fa614ec4eb15f0eb578739a762da68e17a9bd58c663fdad82b5452566a821aca8d4d64f82ddd98cb62a14068558c7e4426eb973d728d8e89300313bd3b57f87eda94bc7ade937c7f8aa1882927f73fc1d4f1edcca1ea3970903c46162114ce772c2ee4f51c81311d8018138869af3313bf3f9defb11dee59d993dfdb4d2c42f029170425ce101a53c9730c98d83bcb37f261b48e836462fde36a6fd40901db6aafed91c9eed1e347294b80e92a19356397cf56417f2065a9451b4d87d5b1eaf0bf33dd36bfa828ea5a8bcf4d8c6fcec7bfdb2e7c2722ba57cb1f536bcf46c9548ee4621886cab0327148ce22336ad7b9389558c47d16b479128687cc1f1449192a516625c2ba2f884a58a296cdb252a24c7acf62665dc22d5b5d2e10f1f76a7fcfb697c7dcd02012d2b526002a1af26fcb972e70e51103719830fa9e6e41832cfc1d3461dd9d7a720dfee77905448d4d0ce45fe70bbaae09334f855e859c7f5c5b07bc75ea2c12ce11c7f8de0c8729e99fb813d0f7aa98402f23921a31f06e8890f03ec13fa6f09f85e53b0076130abf08f5796fc6468f60ec343ea9044c99f023aeed78e1be38d9d8cbd2286dbe6ce7e59e0f6bcea60af2d3888af0ebc5306adad12b868af7208917e1a2110e891a3fa9d80957423f2845440b908d4bf9db3a49b7d60d78092c5bcddd88d3e2ba58cbd1993fc116360c52a6b97d3527c4365e81a7c94adb92680c3fcab470908b951ab76435726cab7c37eab48e72259f3c2b91a77100756af2b57730454f6c704da5f3350503567d3b8f2a17f1c4b45be8499802fbf06e9c2e442efae4bafc000546290705edb09708047504687de1467c0240e64b7bf24a050e775d062a969bae4ae57c3644e1804ddba60d7afa59e16a4d998054f5b55d167d274a66a95f6fac44f09f6502a1d1ec1139489f98ce1b853b4a705c49b4dfdd8a38e485560412bc87c69ec48a47f59651408d96692df9043b6aff030a39e9b3bdb8708a234d80f698afe0d7fda71531311ff32b533b107d84dca8b1181d3348d1af006337cb49fac0786646b51389bdaf8ba2d8dfc4ebca4dcc7546136b907e034c8076060c30d4db4ee6c3fc663507ffebb939f7a3be06bf7da45bd9cc514c87ca13660c9c59edee3101fa6cfeed58208e23069eab1f64654311b786e58116e9fe9c8f5c42698bdc6dfd8d4dac751018b2ec418df31a109338c1c8fd0f7b8efb125c59c42889a8793b0fbc678101f8db89c753a04caf3370b014f2de400237309c542abfa3412ad89035c1c1bbc687d4f22b38fd2daf44d07b469b1d3502818f4919e675bcf501b71120e807c9a9e2f540a486f8140c7cd15a4c68b7524fbaa92c84912a1878e87a32824dec1e9af3e1c8f70df6058629bf10d9a47be50ca3fe588a02c5c84f06a21048c4e23e0415250a0be221b7e23cd2b0635640639b6970b8d2bc02062b040cd3273c8604f37c203745f8ceef81afd24effd90daacf954013350e504f29a66a0831463e28fe684cf17c38501fabdb8df1f0d8548028d0ddfcd2617d1703ac2d73da00ebdc1c843d18ac355b286702ceaa13a795449cef25373bc4770d100951129390a58ff558d12b31e74a7c66ee07ff9545aa5b9be6706489b03e18b337914da1f91b4c570931755dd0be6411878bdbd8fac7357864d6bddac8832d2056ad5b53eed93d0ae048ddd2b664544617ad267f8c04795fbc1ebdb0e3929a8912e53c216445b00884f21d891bd194d2d22251ac7ef11a6d9376607840682f9a3fd9e6c990b78af8fbca90329d6ef999dc8a1d092487701f553ebbbd2b2423c478e11e0879eb26b82a01fb3eb2735a16fad00484fd0aa25b1386309ef3d73cad932890f445740261a2fb65a6bcfdf2b3f12c571726f2e573f5637deb9a2f14a23f0cbeb53c261f54fc6fcbefadce97ceb29095cc08648b4bbcd2578a9a65b692eca395a48a50395d5fa9167eedb48f7d7b31ea4b183e87e1958b8eac9af05347c4c6b67a73303f15956ad07fab6537f98153a2accddce3270d2c6fbf4db2de80661cac088a708bbf80a39b0297d0eccdf920a7d5cf4ac1fed2a894c49dde6a02377e183c382a61010f3cd96307c0c7ab5b6b70850fb07682da3be1f6201f4b223367ec0b6b46a48d2d98cd425c615515c1e8a114d00e96af0225f214f2786b2a524a49767b0bcb5aacef0d1e296b6e90869e5c89dc949e913c7d5058dc971e78d10cd681522a880cec6a41b28574322b9c9e2a714ae20159c0d57ddd8c4c0c74580fea153c2b085dd264da72755d3c33186bcb2bee2af021ee3957a85c23f77f7b862f278c05699757f739c05ecd78d5739b58c37e61b2c915087924a563d352db8f25a5c4c85700565508363e97ec3c25e152693df70d7979a32a2bb09def87bc9406821d8e53893405f24cfcacbd296b60414463213660dbb201314f439c5501acef7c0e72307d08cfbda5388e9ad1c6818169ff2e0bdf1133c2cc59e7c2f112acab35daed1a22f103ff3c4a49b0a1a2b7fa0544983588d9df3518aef363a6e7791b717c69f679c5d7008e6436f0864f9210f78f4155c0308712a41df17498a96a45a64f172189acb840c606a91ac09b51791b617a60df676523f699fd56ba0fdae09273ee6fdd0a21e32b57f2164a2c547f8b9c612fd1314548d143c3516b074b57919c025a037389b0c949ba970e7d6042ca8266b8993df4132abc031cadd2ee6a6f5a11b703d074172581e2ba3b2e72448ac8044e3106dc17b90d134e0995348935c922535307c581012dc7beb8ad0193d640d5211af1a52d19b26fd7b072116a1013b8758e1793566a409dfb7cce9acf0e92065274ee90db7e7499f67226141822a31673eff2803138e357c33ed93a7bbc1959655ccfe3e2914352a993415c6b86ea76ce9650afdf411911ba6b757364c91225f52a75326f29bab8491aaeed06f6d7b2b380981aed75bbf416183c40cb10cdd518f7338fc0094f77f26a515c155949c7a80e8fca0f62db6e328317c02c78f9b87de0d75ac0bd1d6644161613c1014c96f8881d3999a8faad6ac1598a145ecb96cf3bbe125f54c617a3e32971f098bd8309aba2ada623632828435c1b86a745b08ef787daf349c54262b6d0747b5517cbcd962c9d9fb6cebd485eff458807496368f16507e4e714b2bb1d35ee831ff255c99d23c770aa62869ff003517632fa552cec3105ea04a7b0c01919cb73554739e8ec18ee444e6d639c4723b121b42ccdff9118edf520a26c6cffa10e25dc11ba0550302ebad8eff1218df35b3cf1c10d4fa2e45f0840c32949b49654c94b921d36a4159cb1727b68613d0a73eb18cbea3c13d6863c96583943d94386d5221219943ad6ab8a95c846fbc3c2363e0d3fe14101232d236963b54247a8619806a3fbd1b12e5390cf40bb45c32892811a0f88b617ea52c16a445056a21a1d0d1131c01080d09afed6870779a8d152c0ed0629552e4be780f7612b451b05c8177b6534ac99709f541b081168a9a94db448ced9c8e823b03e77410be720683f3ac40ff39920914f12b80341091d41ad53956d9e4b69d39837c11394f66a7fdc65e31bc184d18d06c958259cc5455390c80fde3b9a7bb743c40458556d6db5695ec26b7d351dc1761965c7433113ea5b3b7b1007ad8a341d41bf223e95ada871e28030d8870d83e8a0a8eb3b9e491bfb6bce3c0cdc78a23bd4c7c7138765cc2ff3c00335184fca90568f975d432c0058db419816ee5d6caf4d7f71ccab01aa5f2b5320bef6c66acd525dd0b0a0f9230f755788bad30d77b13bf2871b26535c02a88130323d469b12ea9b7f9fcc3e4a47d03e19bba35078f37c57004fff591bdf86f6d7b990f5dde86d16eaf89380e0fc75fd50cc5ffa140200b42cdb20204e32bd0894653ed5438c2b9db023359f1b3b84227c660e3d12321f74e23c45d0860f9a33352340455ad70354c638197ce0e2b07b9b348ad190e7ef670fb1cf11c2aaaf73b573b180db98e65949e6009f6d944c8e623005d168e4c34d5b00b6cfe48d4840896862e9dda1fff7236fcf9c207936539b9834a0c602a1d19148faa4a42d6d7e7ccd20805ac611803d2b3de0d6ed03176be670f75e88ffcdde348714d803ec1e8d93395f9a3837d18b26cd40cf813e96d9d670c210ed67d617382423f0a60dcf7eb0bd0ff7814527bb25a905c16c4a097d37c01c81fb16ab4e586eb82350217eb9aeb7056102d8755643148e0f7d46a291004c7df1f466f68dc45eafdbcbead8c680c99309be6a380045101ae0c0fe8759454e77cb930b5c3950ae85daa46c0f022c21493740c89b68505b781eee929862d916025a137ecfc8ae438c035aab9f9a84af1de8c3a8f0c55334d156f250b9d3944c62b39b4df81b0c4f7671c7a4149cc512cc9a0972975d936ae5f7f9566a0156661230d80a4e296e1737af851eeb7d495aef218ab755bbf7a41225265b0ce6ed20b4632f391f8e42e1ad0ac93f107426452d9344e0ba8d4970a1d5631aece246e35851027673577818b6284c905ba159507f0a14eb8d3570051fbdf00cb6383214561cef8c928e8582b27dd8b059a750df9e568740cc5a9caa77b249b00a5ef0eeda6134507b1a9f19c6fe2709a5d49c5a5a484e549f1c2e1bf166cca16437112dea3696936f4490c6b6bd9a7d6b1f53b6c1bb6a52328113e2a86681678b5ad640d3452dc4d2232fd10e7d27235e876634d13528817a21cbf84aca3d91634276a31b1aa01c467141ed38562c47f516cdc6bdccfbeea2bd0fc8886911163575ab7a5ea555b8878c9a4c6f91639c0cc94764a3200990cc5614f77d165c09b21150ecf1b0d819b534ec0d25522bed28cb2d5618cf8220887d7ea420a90f906843d1068391eb3c5982666b03a236300dc604ce9618ad774a54ab55d17355d05bb3123c460c261f390b864f8f3ab0f206e8afa40615e5904f0d4719c0e9a628f8cb83fde4690b751e609939a519c17cee0f8c39939305f5e83ac9d220385a9ac4e72ecf9fc50696250d625481218c5f55130769c83d85c3dc83e0ac0b445ee7bb589238696dc2fc2a12f41dac991dc1b0693001ec0250e2a192aba0a93e0d1e77bcde246a915bff1bfbefc05a511fab98d425055073c3b8b337211d83564b8fbb93351ea3dfe77f70d67426070611f470965d9f3c21ba1255de19e07c3b90ff04f34aa5468ed81573eee83ef05b6e45461783df38691a17ad01ea8703050a007b89e350d920bc796702ad234965c6cd3f04e01ef5872a1cb3a070964ebc4f9fd810c80cfe2b1414aa63c21f0ce4dfa5a36a195cbb3497db7ba6cd162463601b170a3a103259114871224fc078f746941ab0b5060d155e9946684a95ccba37d4f9e9a8c8dd3a8ea8f08b4928bfc0ebac520ec199e5193cf524a533b6acfc83b38400af369c815d3831a941f38b8a86480999b97159df94cc4a8e3579a0a3603d78513c919d6df2d059167597a24633a00214a115fad22b16a03cb5780bacbd4023960c431fadd214ad3d63152a76ac98315147ae924775087c7332f85564a2dd6c4a0c9b8e5a4ea04b5f68271634900eed27170e78496eb2d2ccaf22148200de507de429bf94fa9cef36485a11c8f9e33ef447b309447b1d889c5836e06127a688e6575688e47778a5ee38e1664725ac2d243d0d4f2015e2d31b6f2e9c7a442f73f887e9f7ccfc19ffb1b10df047815a791ad1caf6a957cc892a397e63b9f1ec2427167f2370a7b51d877eb3e18b9481a6fa7278c348bd88bc99f5f07303cbcba09d06a8ccfcedb94c23e5632d63d683a9d72e973684828efceb0fc9040fb7568eb1aea4719d93feed0b02b54652efa696ef98d8560135e5c5324cf641da60e06f1b2e29bd04f97bb4810eab6d2a8c2a0d0664ec5e81e6e95000fe4e894d805fccf811503e6097d5169360cd9b3d8f266d77fc04cf7bc35a355534b1c543331c0d9d99704fdbcf8b7c17440a60f7842a5f62a731aca2dd8682d2ebecc492ff74fd040f09261e6c69eaea70a01cde5b53fce31a9bf2a7380e80713be8989b7bd0c69c3089b68218b570b026191948b6e5cba7feffe0707f8e4723542771dd54c2509a1f0ee916f2b43a52e06faa0edc396a17bc7a0981526f5c58e9a03221ace1ae4e302a33c47e33d72658a96e2591d0c63c10ec0879ff0b2545e446ccfc7e460398b672c077f9c60b5e937f3d0eab5ec8b9114a7f740614f40c59089d19b17e400f2ff59120c17c335be6ce36ce6d701142b8786cba3e5745ac796aa167eaa1ac9e855678c9f856a41e440b9b2fdc671c53c382e3edea8afd10bc5d7c4b679c2f0267e47447a60709f26d53eabc2d9c7413b2ac4795d92660f3edc8db2587814ebf653f337621b71d48a438a1a52f16083fa9446351b2445cae8f949085edcd8304d90a628ea2b17372823d75fa57554d68d3737abae054a55f13d79191f6f25973dd4c092d9dfdf6cacf932879804c50a373db106c09138778db4d70455fd3c7fc5a5032d8105cb40b0cb2bdb5cdfb18b36d0a026ed81d5963d5b7e1ce820c6845c128d7862835d123370867ffc444eae70d695ddb3b5db7ba4ae1463868cd922818098401ddfa7c4537c6bc5d3c5aefd8a8c569c85a3eea46548f71723c1efe67f517a007bfd3da97f04e3c04def39cfc20f781d7c8d0305a322c2820b4af80d13047f9af446dc5e6dd4503edd4c76b09a310f6ac3f281aa3f089237603f2bf13265fcb1f9f2a93e1f7ce57782bada895ebb5ab77edabcf047229910fa9460d6a7a3656df94dafe927496a84429b4da25d03a52f733cb16f962c0bf5536257113dba2621f962bb661f23415ec5cf22031d0dd8cc6498853425bcfb1545d3e3b6a7076a15fd4a4495aa94fdd94219f152ad12ab3546b355fd2469535c41547a4c05998892120ade3c5bba7ea2ec26473cc948d0117a372b0f6bc59a58ad8713413b5c7fd86b909551422537f53de655c9941f4fc800e3fd9f9b062ac3f5677758362623b7e2778b83a9e59182f9c23a5473320f638d2bb320ff329b1d1b828897753a8540c035c9bbfc001fc322c6324f98c2792f620e3f0315a20c7c11e58346b810527c706eb6057b38ba4d419ca2473cb42b69f80242f3092c2f84392e9bdba2c017176ad5206ab0a9990a58e0d02c6e5ea50edc02c1994721e626f4e06cd03f8f2db59f3cba2f40e1e95df322aaef720535fbf51362862556d3cf4cc3d0e2690d8892da54e52a37ac5aefb91c76eacfec7b69354d92bbb51249a111ca58dbd1600a0ce5f9fd86efc7e3766ec221a03fa36e2cb6de37ea4d076b225151e36f7a9536553a1b6428d43361591175b572eef8de9eae8d927f806e5465acd0e168898dba18199909a91c96b23613eb79d96c90371be42dd74bb36f06831c53975f8967831ceb1654641d1e293dc49b6c8b0e679dcee7ee52c1b644944e4f087dec8c5c5cd27997dbf37f7643940454c81847b5ad193572166434727c6aceeb3dca2a001898c691f0065774597567ee2b39bb8686fdd2887c627614cb5ce9df2e7f43f1bad50de049bb5d290df9544a956c290769a5ad94ac1ef1db1ee0714bec59c3ad99f8295952e30a61db3508cbe8d2a7292e7186cdeee52c9d2996bea163290dc11614bfa216d58ca3ce6853f1772f378caae8565cc14b7f7e3221808f8316417a1c84010fe113814acaa516651944fddea5221742ba0816eec085d41ad4b1e9fbfd671f83bcc47a9b78a19a9749cc22d7e4bf6e619a0d5e040614fdf752743480ab25a13bee50011ee1e035462a19223ef3c521276323e1efff70a9f37acc69c1ec18e1ba74e63e8ac56f1a2c5f6cc2287add9c11ef4f7e0c35247d46428c3b23b3211fd8df7154a8d1d09bd050bf6e85722c2217e84e9d75940cce86b4d6d62511ae6b2a9af7e752cb04113979bdf2003f6cb575eb9cdcd4d2e6b5c98768cd2aa2321dbb7b508dac3f1a9af362211298e54108ca5dbc7447388cc268a1010d2cbae40640fb937d65557927fcba4ce2388376d95b93ff7d988d34c69531c1ddc969af4227e0187a142b0817851ecb4a9decf7a69b04fcf9f5a7ed40a0e738c2b45a196dc678a60923cc20f444a10f77715632c74373c5c7c0566948802dbad78995ae372bb9909efb615cad2e1ef140f2c1a15afb616a17db3e64ef07f06776cab33b57362f2853102d758c2d25d051bc990470edf97c8869cb2886e860cc73596130e1905e82168088e54f1450e65a125abe5a7afd6489296711c9c3e35b7a0831a23dde5c787e2c101b9e66bc734c71d1551eff6c298f151c91a23ee4c78838e48012ea19c5627ca4adb5ef0b98307f0436677eb1d0ebd96fbd15ec7989144ebdd4d258221d8ebb8edddeac278a62954034386529c8e2f80d752a30c53e1e63d120ef23b079cc519b3e02916a50a37e1292618b47ac7b0e81983a9f200aa7773ac502ef48598e41fd8bb0982a2bf7907c903ad765aa752f2dbbad340c0ed2f2612495586698066b7211b95314dc6adba2f3fe6e48c829d19658a83ed2cca0abfe5881fcb352c2d5a4020b888b4a9e18fbdb449c2f40b32356e6fcd4c92ef744f3bc0f95cfdab2a54e454f63a41100ae67f753b39843252cd8ff221e9980942a75d966946a2b7a268ddf69153abdcd0ae66082bffb5399cb666b7535c67d4c2809530a39b51b1d7a761cefc9ba19200061de2bb429da1b1d7fce6f1b0b4cf2aae421137f3a79791aa41fa93c70f75ec8c327779c394cce6c0493c65590b3ab55ea40b7963006139a8404e3a3c47ec7ea41d274705647d198024fb1c874e650e67e77194f2a537aea28d96d1d5f4eafd7677d6f4ab031380773be4842d550445050784c1d910a8a45ca5e3ec817ea6beedceaa14ca0cfd923370e297114cb1054b2a82352f412c9ad5e8ecc59f846797f5bd6a16dec1eaf39cae3470dfbc371191852396875c2d33b8f143d8ae1778985012fd66973313d08cd319f2f8233029cf4b5dc1b6088d705ecc45f0a0879763108032ca54a99f7e9b6eb56158b924fca7414adf9dd00d91015c789d5c29f35e00d6ead7efa074a74fc0333fcc0c2bf4f3ba3d60afcc0a2b2d755472813dd4af55d5337c417132d75d7616657dca7efa7913f1d89c141f797a4e31300c647acf9a0446864a5f868a67fa87a90f2b73237adccf6f544a7b9308af27960173efadc1df4dc134199bfc7bb359fc37d4397ebae6404d8b272c6af0f9bc9459b5a2b0dae9bc93db1b330d57dcbf421f28402dfa08e0a456c64672f9e713fdfd46905e4faa09877b1863043136626327a5e742cc0b29093919f9159b5a383d2d8c515055b75563bd49b281ce9ac8675ea8a36e07a542903ad1e4239083ce369f778ffe63a0357c455449c397e135025874f6c099aada8d754363af018779f072f9b23b1dda55579e5d16efdceab115f03c054b34e588c6376d53048763f96b21e24c1515c8cb0a72c09637c85ac805b06287881050aea752e527594c75788707907af7a8b9c3925c888a08773c00c832a96df730c69c771420cd54dbc83e7fbb1069ba86ca625e279df695c3ea214f9ae1a8dd8414b8e9e42692df84fb5c3aa4de428c9a60e9f8efc38c27af1cd39e3284c3ac70f07701c66789bad3b075173c3ba994451c83e3761d8d6936f48e7c2aa6f05609a060525ac94bd73158793efbadd086e8e98c0808dffca1422537c70688c84525590021ec60876239673354931f60b5a8eae939821f69b9289c3fca093edcf7fd55b060e57b2b02cdef3e0236d5a2fde2f6cbd104a148c449d292b99cc1afbcb70f77c2524b97ed5a304db10a1eddfe935048e8449fdb2210bf87dd69bf5a63a0eb53d533062bfccfba79dfce0f222b6a1ceffc617fef2880334f1f3241a09223ee3012e32b1f6ffcef1ad568ece0fce3569f6cf9696d1078d01a3bedc4bf7420243b703faeb87528160e5462b17075db83f53bacead30442bd2fb149b77ff816e4fd3e96674c085e5d790f160371aa1be38cab229d7a10822e15e32d2c476e2e8e832507876ba2f4e0436b4bc9e79b5896deace208f21239b7e67dc653ebda0d107ad8f0a3132e0753411e1a073c030da578a1447cc8ec212447c5d8256c405b2f1755d6103c175b6469bbd0bd32d0dd7c7e17c24216cb752c337bd9a13b67ba181009a72d5d20651b121769d457e470e751a572575c4a5297f9d60cad0b4f408e6c1487e2ddc1f31aa24729fd68a7cdfb9ad269d1caf818a6b11023b7adbfe05e225f468d58ee4600c11ea40fa1220818396de33d24bbde5d09a340c8e1c276230a74cde00e218c81335fe25fc6aec38bc0a27a539196226527ae8530be67cfeeb8c365c7f5c2685005ee3a95208e0e25aa6ec15358a4cbc7ec17d337b1a893f30e9c85286eff545e9c40afe815abaa788e4c3fd11dd917fecbd69813b2a00d991ef52883f17f79161e5617f346868a67a9e53a7dc8eb5df303b22d1b149f1af2aee0344228e46628787d2cbaf699499907c5eda0019664a133cd27b9268e41ffb94cabec9e1fea5a3d603f968a6573783fc6564ea4528db127670e01717212443b50da4e37b5de4511acc403ca60282ef5636b816436cb607d4f2dda2688b0f9dc2cebd3521c206936ba8e69e3732151e5d331bbbf75d029f8a9113da7cbff4988ddc29292afbcc3fcd3c733c480bae4b0432aca9923a295df83f14941570ce9d579b083f0c0b6cb98c7a3d0da7e012e9d7cba9d333cd794c82c04716794a43a4ffb11efb93283a85e903cc9a8f6f547313b56922b5e0613b4a480a0e4ef27bf2432844fd058504b424ffea5fa7f4bc10b9ab909d14edbb999981c3b71e854295745979465e068a06af28fe6c21fbf6bc35b5f6473b076e5e203a57b3fd6be2ef0dd22d9697146a4aad422c9f6d6134852ad8464f32331f8db8dc0dce839f93648f6e7621e775064cc7adf394033b78751388d7d1739cc13accb3f87b03a8b15ced82bbd6339485f20a6b8a3eb629ebc32a96341e52643cb456a41308c8691df54e358b41f1becc6b4c1c94d979253b382ac2a32f3529539acdbc950694b01039446228995b9db4d888221ef6847e05714fe892a99595eba13f599fa2bd26fe7709e15cc51f3c5460cb3ea68a01fa4be64cc627f04c520384dcc7f3d489544231e8e1b93ea12d537ef1acd010ed3fa880f6bcd0cba26e5b44ba6d8644a718a48d914a6b5984754a6a4782723cbde442e37f563a7f48ea0e96acba7aa4a880010f01c258488f6faeda1ea47f0cd196d619e2432f1241b82b77b6839b81c6518092e41e1a8ae0e403843d02151c3ba5c80085931a93786704cad33942350b1d0670109ec03bd5551cc9767ecff7dc055716965db6cbfbd0fc10d094241b98680ba2c305271b0a27bc0569dbf733ac98a20d9e7e42835bc4da05603b3aa5dcffdbea0ccf0eadcfd7abf0e0cf42795f5d2f6c2546f0a2c12141fe19775cdb1c8b758d59cb764e011f3d0e365610fef3b3effa7755c34b854905e1b1c6d98389138ea56e2244d779eea56b124030edcebbd197ebdf145a4f4bd819630236cfd5a0b2e7779770a981d2076040329b23291379630683dbda37b4c88df4393ef27dbadd1affdf0ce7ec9a088c49799c3080b200429570430e4cc358bb22b0aa96549e5b37d1fdad1af4b473c673ae30dba5d83da653212bd82c24fae307c5147a15817498b2cbf5ccc8501c329df3728142032c8240687f471ce4f5b0a7652402bcd363c27302c0f0e71e34300cd0d3c3f7c52086cbef27305919cecd3a8e63604bde1683dc8366ae0800a90c9334edf58d44d5fca73aefa22222434d0e54b42322d0ff4b7cb349633fca6bf657f5d447ad8d88e2f69625bfbfcbdadfdd16a9f84bba1fb1f2eeee378bf75f823793ed1524003ec4981571149e14f0002c9540b82315617416d3d3c753ffcbf16d1201c6dd4e2aee044f56de03ad5a1a323a16f98207703b620d7a2e833dc71b2a3e8d85966c69fb00d5c2ea9f85970ee7360bc2f72141d3bc375478deac24f500779006e7e9b68493b2fe7ccc8c1f68503f11c0901a75f0b535282a8924ad306f1029740e205c80f9a061a21d572216702abe1d10105d1704adad3d96b09722182c25952b48a963c6bdb522da53030008409d644607eac373c126a3cc0868500b41d2c5136fb147ee86e9e18504f803b3df5bd74944b527c581c003eaebff36bdb9e029e4b78aeaba9830a486a4c23464f5de075f504aa749444902e62be651a8c8c70ee5d53e0a24181c7b9f8740863d0018c0212a8c034e4e538706be532bf0988013a4390a076ae87662af24a649a94a4099086cba361288bffa6a5196f2dd2150a0f8c15da5cc36cd8a4b68482785cacace7330f1bf310f4e2a5c09daad65e3c9e8a8a07d80702724aa59fdf66583b4546374bd533b714dfa5d325d24b18af6a09516686cf9a24585ba5334c7b0c894290e6b998a55065a701e32eeff77a477c5c39f9d9d18284b3cd7d0431e068006ba39c21faadcb0a6c1979bfb65839d4fc33730e8694259161b9f520d094032204c61766bce3edc00948d5a06c21e6c4d1ce55660dc630f2bf27aee3468404222d9744a9ba8b915b1c16505fe704135e1b661e6b45f4706f68049a798cf6972dc068671b6d68d9a11ee5e6a2b2da6a2d8195710413544c74abab9b2d47ea0db00ed566262cbefecc40bdf40fdf81c874f933c3b5147d088611c8518e97daeb8d5e98cee6e2da9147befcfdb6d5da8696f34e86e2e425ccdf3b25445bc808ae796f34693bdf98ae2fc55dd92c9adb4994785ddf52001d0f781ad170b33fd871a286c261d77eb1f1f5f9eb4ecd80a4d7e6b2621c16e9c1e0d1f888f0ae37be9c15fb8c1f7e25f1b5707119b0c715c50814145cc3f0a5cf85b98d59d79cbc6b3621d7db2735af2d6b7912722aaabe5c5abff19eac601261663d4f1d461d5a09aa3c069e3985e07870de7f13812e885bb062857219d3196b12ead18921612ac9d729da6f3944bc847b82a92e645e4be94c0c73191de9fe0730d835a68487fae920ea71172263ec0f299c5ecc67dc45575c681d871a0c1d6c59ceae77bb0c9812fd33e9060eb7639934a9e3c8be70590c24e853d73a0aaf9cc8cc2cbab38374859f807dd50509b01b0317f75185aa08ca6b86df69e2dfbc46e0a76483698d650ef3c3d2ea2e6c6d69cda49a2e07d84e5e0f3e4828ff5d2d4b3ed42039e554f702649ab0dca9c223d8c35df2b4e89fcf27cc67e6ee598ffee9f2341e99cc07433eee4db3e56a44c639baef00a6a84850ecf0aa783ffce73d0ce7c06c061299f929d02151e9f8d63d26bbf2c7f542165ef19e876e37f0d8d1f167c531c95e5c9285847b5d0b3894d75d6a378859b9f2596139b824ad6d5add27ff539969c92a3d24fdc1481113d7627a90f9c6bd2591703c0ecd1f15ab631e5a53b15848ea0b3d087584e3551a4ea58d0b08eff90df50fa6ca5560762fed23130aea97fea5be9885c00d2e7a1dd34e0ccc882f75d85d8a664556e56269b18365ad5e6091450fd3e43aadcd4c0d8af4e459c01f47badf539a0699777e7ab802e31788bb3b08ab97c8450f05a50f977969a276dc31c63ba0eb91fe3558327225967f0293f05054bc0ab1c4c92669941e372c0d5662697433351ffcdf2d1317476aedc296a72aa496645c5cb08eaf81e05cee8aa3f4df8b1a6cb0023fb35f77b4d9a6cf2e72221585c11b027b27b87a0bcae4ba87337f5a5604d0b4d5cbff6c5a1db325ed3fb143eae6ce194954a64e3c0f33adc2848cc3c4e212031bb95526dfb1422f5257b49c95c5f93cf923aef5e0cf09aab1487f9ce742139f99601efeb696112a7417f301c390cfa82be550aba7727f303a93bab1d73f2341a920fc89721aad8e9fad099ae10afd624ac55141a58d5d8011157b5ba92ad56807a4b93d88c9af9230ecaef20734cfb67214bf2181fdbb2406f46c4f159fe2d6bb1a1912bec2a6f2ddd6858ada309b65ee30ff7757e5459d35862a5ccea086320c1fa80fed0a1ca75f5eb57f299d449bfcd3067f4a9655f25db0f35f10040ca00e73338006f1842ec1c26cd279866f0f64aaadc8f30b3abe01a585e8202ba2c5f0a14b8c410b36c6273026f8429ffe97a53e7ef3c3fda92c42bc698e09089d97d8e35dbb5095883c7ff0cb55bdc83b14e54f40628f9eb06ea94d21d2c8b686a3ac031967c845e4eceedf7fa2fb40a8e4fcf48c98bc40440f239494ccb3859ead4685e6802819812fbc2c99d5e1689d09fe77d08c8c1990b39e1cad52685dabbb5c5aad63d3386cab88fd6b90bb7bac587c4fabb1f6719db715a8776e48d36a58f07041cf2e024384dc3e9e8dc2f8a3c306d955a9897fd7c11e68dfb3d85b823dd074cc627f239cd31e6a17c7c1b74be7eaf265d718e35baf5dd4069d2049083b396828c6cbb830f7167da17be2528b4f45612aae4d55fa1d1107807647a658d4896d6159237d6a4276569509c4ef3b525d03b5e46ccc3b639db21314860f5c7206e37a840f98802284892209ce430ccef53b2c56143172bfaf0b1a68e808908585ea5d53c25c2072e27e1bf64b145cc46bcb4e43a43184bf8dfd98c443f8539c932024da3f704d874d0a872b81cfd70009be24367598a659a33fe58963af77af1b47bbe4e8de703dcab2a8e968c15eacb08d08c2d860d32f3b7174b418062c8a8f6e5ca4fe2367a175f21051733fad91ea7c19b1f324db54b5dec80b3e7b23eb84ab71088177dfc4ecf5730e78f8406c928d0085ffe06e8447cfdd832cd1078f0d19b8f608344c789908fe2c2ad5bb609b0af29b87f8713004bbc07d090f25fa6ba75cdcf490712520dd9ec99f6d7ae79b1a4ab54e69fb61003c8a58dae8ed3366c841e1dd0a08fdfe47423538e1a32c62d4d5f03da59b6a11d7f6dbacf956e9b50792ce6fae8ff9204a26bcab53d87d36fab885031d8df8ebbd8107e4cfa1cc3a4e615bea2a2e6d0ec503c326480620847e10edd83883a4e16b064e2e2dda1d420d37dca596f989fe058e7a9a16c49dfe4ab02c109b2f1f6c36926c178dd728d87a41be66de0e1c0c1095e90aec3e802a0cbdee2d59b0207409493c1a96694ec15d359ac8e2e032859d4319e41553758286368dc06153fc5380f9c95731e9669bee586e0a2a415cd5496ea211593216aaa70d8a0942a968668e08319335cf4512a430e4c75c185cb294787f81088ef350e00b407dbf77415d493b2e1a2ed429a68596523c186152ed276fb92f010b9f4e788c82401954a9040ac74f989172095c3a8836a1d93be7f2f0c367dac2753d47bd1ea63289b2a528e3b8bdc80a277ee4f6d58c4c8a99de4521761e6c97478edb0ae8db06295231b3c37375fb471c565a301f1ca77083a69b4755ce67282fe639aef7db2e7edbf1293a4f2f8578b289c0bf931c37954d826ecc7e1df63fadd8a6f25851739963f120cb28890c0cbc56086285f8368c8b646bdbd4ba4ccd6ffa0d13394c2451f4e04181ba2be68da784bcb2d50a2353001438ca235407d6a9201e1a9887be296d44d26363d70eb7643ed4f7920f956e6950e869401210c2789b9eb3353f4e2f67e1069ce516a2cda111bc9b3ea9b60af809d932c5622103ede20f634ed0dd6db3be47f38856277a74c457da030357313f218e1ee4becb38747b3d1fa4135520280a7e5df2b34d43695179a485820116559b8209c953eaa7d07b9136e597d5ced59be0d83d6afed47eca031c157f220d6febceca633a7973ec322752988fb6db084bf36e0a025f9aef5d24beaeda03cb9954299450f3e7e1d04592f1957f5740ce940ddeeadbf114ec54ff569baabb2d12169fb8a852315c68f0d7f40f983534c623ac3ce0bb9262d40e4ad120f61b122f686e2851c10d59c59a2bd485ff1dd872b172bd736f974861b3e842ea994792b05a3b70240f56efda2e686774f4640a694630ba149a5d8b5daa3eeafe985ed999faa9880315ef5ba15b90880596bd7395b1a9d7f3e1f428f6feef9ff605e9abf69e48d452b1c18a1b73d0b8cf0cc6b2cf267f9fc7fb0d7e4110a6c8f656a68d1b713b40d8606f5057029b6cecf9949df2991e800450a02ee229700fd93adf38ea44c793cd2929247b2f92e2f4d0136f930313d521b6fa3185a6b2e12cdab53d6eda9febde50a1ebe92278b8a0326cf9efaa2047bbbc72e14438c3af0377b2cbd5b36e9da69624e8a146f8add316a467f1079d83a3d44ac0868cfe1375bcb588fa46658c28bd81569173dc46c7e28a9ef1ab6dd00c521e83a029823e779f14ef818d6b45ae6adf3cf04401d5a8c52345fa29cb8b1706d3c14c81598e9db1f2dfc90cd237673a9e02e59a3211150e25b5bad75a1f30b17637f6e38b23de6af1158ee2e3a317c67090cad7f3313c3aa2c1516dfa556573a2e04c64598809ea67bb54050a21ea6440e31c6cd028facd78147a2d7fb01fe05dda560dad74b1128aaacc875b1a9d37e3811e53401459ce997b10888e551c8cb88a1d04919d645d1dc6433a7cd18847bf551ab68679f5542957993bf2ab8bca4313b19d8a4860b54b2b93e68274d79fdebb9d9e32e35bae079eaaafeb05425a5071ad77c47cca4fd9ca4d4c72f0c6ca4f2765d452c930a230e40aa97a42a2acb8492c02226417715209034bb4092dafb1f206502adf63c02f08df51f83083f131befad2138b60469f3ad3510e2864bd5643a2427bc3f783c844ddbacebd73427430c00251b5c9ead75239454626d7db4addbf0e136acb28201aaf3f8731448ad59c262576c82659e8676a5107bab09cf0da6b0a536280387546f6a0526132e0db582286f9a83076322608f4d8bec94546b203fc0581f94379dcdeb42a9384eef8708861c503285024a728b132ecf7b6ae47cd1e866322c42f1e08b037a49c30a8bfc1f7af4ed87aef77ca050825d36c3391d4794dab2179271b3975ce6098c54069c74fa35814246a943e13024e84b1a1b68e1f422b109cab7b29af34b189be4b0be2649052d701ed7440d32a9e59b339eeb8ac2ec4cbfcc1a2564af823d17cc482af8d7097382459cd14678cbc9c2d51fba31d8d57983c6161949d5d66ed439389813a9d6ad1aea06a2ca7d1d637f5db0e22b825324ccc59dece9c5d752e1257a6634ba8ff0de94dc7df0f05be5ec3bf940d458c3ad56dcfa1110fd2d508c651d9db6d45aaaa7662a292258cfb277d40ca46cb44cf93e10a07ee2d66babe552365762b0b419213679ca101a7b0824d9890423878b5f8c94b65a8e3dbf7e755ae092f7e4b74bae28221197a333c937a203856f15c8037d61730f3519d856a339d001dc311d08fdc83a8f0fb170df6e5951c8061b74594ad238d2161b3ccd71df512c19b493c9c71e66d2e1412e55486b6fabd6a5c9577b352851a4f363230e0547e6c4d59597af8167349cd8e05dab48146b3334609c70dd6debaaf53cfa3cd5232de0003dcc53ce31e12a8ea74366d8c16f1326c886ac69664386d1d0868c64561bb2e22be481127e3a14c6569ea92a1f32af52be0217d52f4661b8465f0841cdd16e611b5482f2d6d2f7e4d00caa1b0168a501db551084af4b9f372c10b741f4a2cc7b52a5636fcbf134a6d1fc2984a0881e536fc2cf90bfa576001a398f7037f1c522721b6444c206b4f74e24732b8018ca4982065591046ad21b61738263c837bd4f307e27a82c04f1f9c941c47151ac8267a8023dfc452cc92e8e61f5034b5ccb5c310a402b910bcc16b9515bf0cc423c482ca8985d7d82f582bd192d64c8c3f36c61ec98d1400dd1d8f2004e25f2a56690bb30324445fcd41e03e6d2bded16b5e90476c66df8bcad67945827d89165513ccfe637a2f2f6ec5f6689f39b3d4517459f4b2ea114267dcbaf8e78a622101ae0a88a939f19dadd7a4807d32c3210df383a25bebaa2583e957792a2e4fcda564e86b7ed3979a808f2bb0f28694f478def40346988dbbfaeedf94439305c3e8e9642b2b6bbefc4e63b58805783ad9b580555f6cc5fc87c31c83caa7adc63a79c9253064dae4b2c3264b13be455ba3adc91352f32b2554d4418f94689ab9ffa3397536cc50f284e80833ccc6b0b1329ef2ad0384bf3e7e1fbaf3dfcfddb157f745b4e0a9357803e7ebae1cb932b8c1dedeaae5d460317f03da0a9389fac945ead1d36e691b5e689870d615bc3224e35e601f7abd7a9b34319995bc8a4f1cacb7bf0843bbc395eb751697a96b34478831b45e3ba6c70e747940d397170d4885850371ee779119ebca1f777d66d8acce3da7d9c700c62de872b3dbd11084b6b0fd3f28701d9e85969fa743c2577fc55486793455b8f83b3200cf38bd5f767ab931bcd3f2bf62c9207e214c5fa31ef4f712f53cc057e84d3bcbae733fa635a47cf593e56237fe9843faa980af2c6df976daa3f6c731f761f985203597cee09b7ce86b0ec42a98d2a01d41e935a9469c257e80a318bac2edfeaa1fe314905f4a8030ad10a925820d03a4e070f470cf6441978ce0061291d62cd0b043060d28d7c9ef31c7c60edb7977f581038dbfa6954361b179d4f83602e40bbee081b180254438fac6147c6685a1eec214f2e64bd1385dea390b6f7de5bca2da54c52065a0910091809dafffae7057ba0a3152978d2f17316502c63dc31022cf4fcf9f3044b628440cf3356f204bd5525ccf49c7fc14043cfc74a2c8561869e33ce982043cf3792421217607057de4d2ede82a787ddf18e2f58a5439f3aaae36f1948e185f9fa3e86f94abdc35a2b772eb4ff9eaf70ee7890241208888118d6bfe1b5370cc33338443776905f4869613114f249eed7df5156b5b87fa1eb09e2a4a82df7983059b1f624f940954739af899e2f2593c874fdf6e004c58a08bac061cd125794c01c808828485b867802c10be0d0a2cc60a71e39a5a69a7a45133c441a4429a3b360d8a0fd7f9c56bf6a3af304573569e9862d87a6898cde5166b96842c38d26186c4d5edc702f873b8ca3e35213154d4be81d6a317a01a9eb47262db1addb053205f6af4b38cfba735927d35b6dd56ab5a17eadb022307d49209ac6dd739cc194220345db1813c66a1923c6d620368c024ec88438020a24941003b45b5f860842fbff17233070822a6040c41059408183ac878e4b5ee2f0420649d232d39b9ce9086f67d25ffc15c500f98f6f97e9ed21c192a04ee5cbbcc888c98f1c698c5f29e34a4f30df914f65e62bbafca23133e6f4c4c43446ba7b931b35791193c7664e57c62895c1227f32bda21b311dcd8c64b248e9e94a19a431464d723b9374a632364a17599fd0f6376fbfed87ac967f2938249fb4cc5bfacfdcd9d1522f49f1e5de7ce08e59f4f72ad5c7ef5adf0153f050d3f11beff87d6b4e928d78a8ed683b9280107f77b071f4dc9f9e5fe36bf533e75e0e30e6915739c69d379282bb76b4f634fa483d59b00220acd0f3e9cef71c8031eecc25f827f729d950b4678fa0fe533dce4f90be056f1eb29a67be0a1cb29a6e19a6fe84b81f926b74f733c78fdf446d03de14f84d621607e3a1fc2dc3d4f767f6314356df21abefa76ea064fef609cd9761ea1b99bc286bba8c316dced8620415359841e5061b8517322eb6a0220d1a65d8acb10110a110372842aac19a2f40c052b003154c4ba801476cca86456c08560d811735a67b09b3c38e5b354b6d7704972d0cb6d171c98b1448e0948e4b5e96d01b6b7aad911492ecc0c20b117a877426bbf152f1d5bab2b5c3be674f65bd0c6183a75af2705679b8059ea23916e0abe392971cf4f628d0ed8109f154dea6e3929798de2c59181a23adb5d2e9458f8773b624a5d3526badf5c6b09032a3153f2d2b0fc368697475338bc5fa11b23c2f58c5c298b6c6e86274554dbb744a3136d9762d32ed2ea34ed4893ac9e6ebde1966726ad27e2fbeff6188449d9034a4f9baf70a56d21ec3a2fdb5d87c59ab55a7f9b2b656d97cd93bab48f36535a71516ac64eb953b069759694fd7e93a5da7eb74efdd2ed26f17090929cae2dcf20ef71683ddd88ddd98939393934c2693215d24a4b7b1f9da6e2ca61f48cbfbd26d8b79e8aeb8c95254743e72884c2c10b3e80da58a26318bf66de72091399ff634e7734e9f5e355da766fda6afb69a553b58f5138beda6af05b52119d7acd1feba067937bd5ae5cc9a5fff4ed3a6e7fd646e4f42fbdf2f683e12775342bbfd905489744589ce26a731655c36639251cb53acc86842b1f2fb40cf6ccdfb7bce2f0b2cefbdf7d6392916d98ca922d54b29a573de8f1ede2b2fecde278fcddbe434a68c53199d51264ae9f7b8f75e2a69934d518c59b66b8379acc0df09493861dbaecfa6ddf952bbfe99da6e322975310e4606587e1ae9cdd975f2fb1e77d118a2502f3dfc7ddd36a5f7f1fbd4cbcce4fbef53a8efb70fe565cafaab9970c4ff0f6f63f31f186103b2fe8d00a38bacbd71de6315f7def7cde9cdf73c4f6219f1dce93c6efbb48f0ec69d5c8cbb521f7f686792fe05f4260fdd994ae04c5a496f67aa3680b153805609b44bd8272c162bb35aeccc72f190c943b75fc034d92b6396b0e14a1057b4ffc6244517598f557152eab436d1669cf3c9c74e937ac803db46bf20ef7ba6acf6765e6ae3e2b7501f5f7edfa7c01f1e3aea0b3dec68b4823b9697c5748f9187fb1f8fdcf6940be232f510b4825ffbae604d6a59e5a115fcf383223018fa4e14acace3e107456047b915d345d64639a181b793f1f7320ec69dc464307a3b19ed5f67dacc070e954b65f2d0ebcc43ff50092cdfc9b84b8bbbb4ffa277f53217a987d3e23bfe5c98be34817112f31c9970a6399987fea933b0fccdc990b4bf87345f28997745bba7a4dd9f93cd172a76f1eac3964cfb7bb1f9fa9c9cbc2227cfc8e948fb774ef3f5c9e68eff1da3fda37f27f3bf33cca4fd3ba4f9faee15ac8445fb7bb2d87c795e93c774a4dd48bbd715c91c2543c5260cd66a85e1ff44c5262a365131fa439d9c9c9c6432990c090909e98b7db12ff6c5b47f03de73f29c3ca7e939698f15e584bf4c5adfddbe7f434117356d8d61f71b1187fa328d3c5dc701bdbd0cbb8edbb64c2b783d1f45fe74a4e34f305525c678efbdf78787f12fbdf56af7e66d6d0fd5d5a1de1ad6743aade6394a9f30f22891e608944cd39433d33891a68d1b3520d0e166166046044f2f400204559238401b4a3138c81c2131454d951b354c50c9824b136d5861a3045bce6862cc0c62d006136fa49122a5258d16a8fac3ea572aa59553c705cdd30d4ac8d65041c59738c6a0c2ca137144d902884bc4aafa0045972b96e0a1862fac8040031770c18229045fc2a0a1e2d184d1be54a7a8c01b812d63c2b18ac3871b9b3360c0f183ea0d1bb8c301850d1c59c0218607471a374c9d84c30a4aa281061642e440022baed0208a119b128233669c40093364a05283538d5677d5ea02c6c700a30b1b2b27d419ae32c325470c66b07d2146cc8c0b18333801105078c1218d356f446941980d099bda039a0f785f6e1c2af080ce35d674c1c28a33639af0024a15613851023262d4d00414606e1c62b82a258e373ce96e8da49064f5ab1b1d564ea915442d2d1eba2395193d30219ecaf3424b14676eb089801b656851461955886164c21561a401c6165600610232506cac2a0f0ec576a6053a54cb8f91948e4b5d54f0c4024d62a0f40194d22942162c7fb7f40fd64f6bad55516aa7101ded4b4b3f7e4ab817541d4e357b39cf7aa8b75f90951d71e5e18bfa68a5e88176fc8f8351bf6491cb1377a96268f3f1a34d0c5ad56159e18f568fbf767c7c181ae0ae1c1fff01eebaf9f831b84bf5f19bb80be7e35b400806b1aa090ee8610ba8c0eb3db901a94d0674ea6568833fdae054ea05df417d81bdfb791e0bb0aabeb081307c411608ac4375802f7c3c60d6fc8fe1fd7861b0f7de7d2f0c1ebe065f70c17b4154f9b64537bd68a5e881b88f8feb476b7fbbf6a3be4f9caad081ae915ba95a80e7df7fe215e0148286d90cf407da2d8ac270427ba006060d5a98d14afe2e79bbc26ba01525790609a4e42b6865499ec181943c05adac906798404a66de7e45c74f9241f040d14df0bc7d091d3de6a1db4051c14160818d008eb31dc0c889a46ba703699b9ac6e5ed7f5fe6edef6fb7b9e948026f07e32e035d8b87977b47e32ed7f51d8cbf3a592de3ae222cd4c88bde3e4657544c0b35cce8ed66b45043a6f78c4d1b749d5174dd12c7137552d1f52f3741c9715ccc3ef3b0fa875ef0762ebad61c24fe928bbbb4afef5fbcc95df6ef77f153019c010a90e759fb9eb3f2650f24e1245cdf7bff9ff94402f265b6e2fdcff4c024cb7150f4e6b87750d3f2b79550b483da6f2093a10cd821abad7d3d6dcc5d5ee4477ea5e6fa29f0c61d7f1488e38e073a185d1fa41a0caebfaa1febdffa3a96f044a2375ecaeeb060c85261cf53e968698385458c7f29e512a64b0890c082044c18e0065684f8c01645557801aa24404117346cf980374bcbd8d272e98c10da4d034519377429cd174f5e687f8a552afa29f898277cd0c19a1f288185b84b3e8c15fa8b02fd78a3072bf4d21b66dc484f45b3ca1535cdb981194fc5351d89da498c74e8c990d5fe5286a93d6ffa50a674d2f9778e81c0df122633cf9f40600ac5e50addc7958e50709c519942ebe838a382a4af87573aab4b3f29c170e80250344bfe0f2dc19f1fb549ef04736e8c3feb103a7e747bed3b2731c6af31339179c8e6cdfdcc4372cd548132994f33d5f170d3d7b28e06640a6c9f32a1afcdd79e097d4bb92dcf3c64f5cabaf64ce84b7f979321abe7123af3ede105d8e59c32473ed552c6d471c04117589a80066f8a753cbc3947d5f287f9bf7fb8e58997c5d331c650b2e2f8183b392b65b98bdb3e7aef2d8129dd401ac3aedbba958e6aaee08da5285780b1850e67d020c011465da678230b188c918226b4287a5423cc701d1724f0b84801126ab248810eab6ef52b379a564e9c957ba7b8d14523811b4b493abcc29f8e4b6eb040ef906905115c451e475a451fa7de6a157d9c6eaa95906b51cb2f484aa1f9f32f93f9dacdd1ce396bfd822aadde25338537eba41b26f098b4263cac6af5c0a2745b0d2a38214595347ec892c31917a4a011031dbe8461021a82f88e5855a41e99755c72a3c8cc13140048026f4b291d97be60f15106c7f7745cfab2441c68663ddc60d6c31a65cc7a689acd7ac07265d64395590f51663dd83093626626458d9994a69994d94c8a1533292b9849499ae9c0349372058592728a60524aa92a877ed59bfef198d7744ee43bb1177ba81afa11863aee1a62f1fc8c5c48e1a42b381423cff65ac83337d6f2d659591bedb7d72cddb4fa3f5e87e8365073b2fd93a9b7cca4fed5b4cec7aa7bad0c536b79d73c64b50a5c3efd4ede8f9167ebec094470fa9e408c3c92462da5bce04a65b19cc0508c3c3c9e877ea3b5916f2398538bd095081dbf9aeb0874ad72b504ab08741dc282f59dc87f327590cc43566726f46f7d19661eb2324c33548cfcfdc3d90f487adf4d312b94cd7c50f22be7474d295d22bf66a7fb48d4324c2d9f06aafa61068dcf6babef4ae9cff92ca4ccc0f2672ba506963f5bb0b0f5e1eaf1ea524a351f3bec4969e4ae08cdb80d1ec5dd5d8c3badd3dddd9f05adfdb7247d4787216807c1a97b6de2d3571d88a2e9bb7f6a0d37e33e72c0f23d07899cf16e51722aba0a4a0d8e3c5349042fefe3bf4fef65f5fec7b5098a00059eda7373ce79bf9343f293461b28a95c0f05d8bb964aa3cf04586584b1a4e23b958dcfeb988b6920a5b660ad1ed8184b460b24289346068b0f1309a992294208171a818c9289f2832cc248a88823c76bb42184101157ba355baab0b618d1d2d4a3c197d62081f6a77e2fa5d2094d9750a3e91b71d7d5f45348e2c20b346a4a29a519fb441986472ff4fe1144fb5facc692f65f19a1fddf9764c0a44614eddea2f2dec614cf35a63b6da9717efddafda9d31be3a512cf977c98874e427a3c9c9f52ea49925ecd2adff157c92b6230d148e948430d182be44c97e30b8a859a996a02b1b53c89fdae745c22830a324ce0441759db46e90334b88cbb3a982ffbd3cdb85359e960d58c8baf74669e4f391f470a2c1f4709cbc7c982e577c0fefd0e24d5ef80f6db772004a6ba0321b0ebf864c4745c1aa3cc4bc7a531a2d0b2cc7cc9d92cf2cc2f81091c3d3c42fab0f52367393487e69c0178cfbd0bde734f9fcb3324d1ec02f75d9e81cb39b4fb193cefb9870274bd19674869cea829010c8c6000259604126a38f104155888019a506ee8218d152c29cd5c60051010142c81822cbc60e28b2320960f587bfbd5eb4008ace958020a300b120d2c5f7e3903d07e7b17b4df720efd0854b30bf66fcea13906200b3895f1d87c2f9a2fcbcc974ff32da88135c0f26d94a6774a9dfc8b29fd5062d54d4bc7ef71a655e386610bfe600fe74b16aa22d0cf7d99ec47f6137de22cd3b30496bf7770aaea86ca48e79c6428bd59aad2c05286dad3ac812aacbad93ee59d2fe3ef39b34499663267adb55aa1239dd1eb2229ad9abd1bd7a540d3760eb07d4854da1ed9db513de9474d9b5fd0dc26cd94bafec008efa3c2deab7d484094d761c18407e2c41dfa1d48b55a2bce7c1c3dbf43a5eec65933342502362777330c6400a8676a73540d5229faf8f8f8f8449f0b024e7cdd596d2e09276469daa2e3efc0228fff8f9ba0c455a99aa8886887c520f175dfb33cf21d8f5768bff2e88322bc285f51ee6c498403e44b1ec91dfff87208f99245534a1268bfeed193b07c58962aec872466b99452242f57cf145b9cde3974fc707a7cc9a3994d60016c5aed6103702013a200b105b03c9af248d54453242a0d14a3165ee818c3c8a229ad42d397300d5667d462e4a1124a964a9aa3b848737dacc1dbd34b5d7000400d38fe9547a6981a036c755c1a438935c6954b63bc38cc1abd574f17a76ec7d91b2dff5e57b560647ea85fca4c7bc1d0278d29caf4e2e43b515f2f637c27ea8a6f4be6175f0f7b31a3ad79958c640be619f6c5e8de2dccd1d17df7ed15f405cbdc89fabe7f41374769e37ff50d63642d07b21e7bf7e255d57109cc18bd5fe65191d9195f2ddf99b1e02ecd3b2ddfa7e0d043d984a56d6679d8748591969b9a2b74b820c09e8e4b56a8d1f2b51f30a7e39215663817584183788f80719a3b516b17d4f11df9958ae003f678f1155c68aae3121820f45ed129a4ebf88f1e774530465588f223488bdc888c2eb24ee001ffffff4a156ffdaddbde73e4781c7048ea1c9d0d7a7a4ca22963a69b6378f880f7535dc1f953f7c0721c070c0ae7998e668e929b5ffdeaa6de804e82c21b473dcedf645645e526f9c5c39aa38732bc5f4339d25df45105ded3e8042938e7b5aa71e6ebe7cefc09c2cdaf6e7e957384a8bec931f2e4448df3db8f74ba1b5007549d20027c73138493551ee264549338a6fa6801a6bfa79151cecf9f54dc75f3f3e7d1ea77bc24d20cfd2595e6cec4517ad60d381d8babfea6db015224d46fa9e45f908ef76f2868c70b49bdcae1c1c10b499df33fee47ee8a3bc01f0fe74b247984bb76fc7c79c55d3a7ebe944fb88b839f3c1e498e0a9989c6c1015921073c563b401828a4e6d714c7ab389287f371b21fbd2a6fefc70b2cf047ab0726043492c23db259cb3f3ca4a0d7827da8e32e241d55bac8eaee7cd990443ff5d13506933acc7514d45e769a77bd97e0d4184c427d77352d9f7027bf2393071c787ba2bfafe0f6b65401f554a39f0af62df800b0011fd8c4d3d7fb54a81986fb50f44d1534c72095c8345a03370251300713bede97c0ad0bf5860cdedf8d3c1e0c30ad4a5ef0507ad3eb07bac8da93e620b19a3ed51f084a40039629aaf00014c3f5a3ded6d071f601244d6591bb6addb2280619658646d7298ba4a7699e4a180b8e1ef67848bfe521fdcdb23a917e4825177d7074ccf1ef893e724be4a95fdf845886ae61e85abdd0f5f7102d6791a7fe0d1b78fe963369c35dc21d8ba63f5ff6c46c0aea51fc15231997b359e6883155a8e86a83ae9b34732fb7619aea38e56cce970748b1588c0630ee1a23cdb82b7641a3a4ab129aa9a4d4869c7d485e3421456fe9a4ebc7275d6bfd29e9c4e2ae3d9ba692bb6297345874fdf984bbea11ba96602a514aff88d4d4a38f0e2c9a72a015ef5347e0ddf30077755f1fe62fefeb1bf11e77b9ecd78f61bebe2c8be64e0583ea49f5a4ee45619c8bbaedef5fddb9379bdc1567344cd1f5271877e9d060cef6dd472d8beadf5b6f6880f76cd25506e66c59c8b5742a1e826ee461fd00ac81bfcaeacf59fda9547f62a93f9b6c7d7965be2417dfa9ffe582c1524cf4c13aca592b094c269495d2af4691be53ea4c1759db22598dd6fbf51b0ada3e1fe32ea959ff7263e8cd7a5cf643c9db4f74e2cb956607522ff43aafe3b87c2b4553634ff489a2f9429f3c747f57525262516991b218f18497b89143582d8a7270340b2d5040a1d8e80eab5fc5dc28630bd31630378b2daa10749cc5bad01ce8388b4131b749a54ffc7bc1c8e3946e795e77a7ddbc52834127bd48a54f39371d796830fac8fc91c7dfa9ffff4fea72a23ef2f8ffabd1d6604dc7598c09ef8722f46e69ad068c759cc57a680d71bbeb7998c6872b7be264f08395c936317ad05aa0745b774b6dc15a3db02aaed83551f84085b260d15ad78ad16cc15a3d30596ceec4bb468a104256c4d4bc118450154d6ac218c198c7debd8e6fbcd436af1a2e523c4fa805314f65eda6398f8e4b5918c9a81b343e718526a50bac40410b9a3569b8a89182468a20ff1ae20be2a0d2258e33347d5aa4b51041d3bf35d03446e1c841d3a7946228b2d878b23366b47f3cf384f68f568bcedf63eef2e934bab6ff8dae3dc3d1b54d70a95eab13a2eca36b83208216d64ea801f043fbb7a26bfb3cecb5f4f83cccb57df29e0fcb7bfe9632ff9fe08ff6d87c2df9105ebe477117de2a1494e419e46f1692a3d0c20af9778f2b390a2fdfaf380a2ba050f4402be4192890926c83924ff2217ce843c763d8635abe94492d72e6ae0f5ebee4e22ed6cb974cd269abc0df2b9dcdf2e077f8a3072644c2f032012f5f78e9c2cb974af3c5c223e0f7aa003236808f3dcce7e5b3e0ae204fe4e55bc05d455ec86fd50a85df3a3fbf59fa7708f4fb8791df3d41bf6142bf85e81d65f27bf9362fffdd85f33c5eaeb48e96bf593b7e6899f31ba6e52b01fd8a9b107f09e857e64ef491b73f113d0cf376a50fe70d45e37790c8c2c02020911d02120189ac068b8044360824b2134c401640de45be43923791670d09f233a58714817dd2cc7bfa804416f649fe30e414f2eefe834c748fe44de439050cf9f2f67957807f12accbdb7b4e01dc0f51401724ef21ef09f02e135d2eefee5909f83e894be5ed4d4fc0fc2447e59dc27f09f8a42eef23cf2580fba4cecb1bf533f5eef3309801880cf9203e79077998cf27c104f0453211d6792379229908b33ee9831f92b7f73e9f1424efef612f044440ee2921b7a089bc109bbc857c909ebc4bf820dd82f64979c82709c95b080a20911df24941fe851c80bc733c98892e097917f9ed00fa266f143ec801827cd2901c79dffc7680edf5017210c95b7f1003dcdcede6b01112c400423e29c84dde01f81c06f8a42d6f125e33c0f6499a4dde395e88cd0741e1871029216fd5e74c7483eecd2715d14f0485bc89fc10143e69882aef9ebf09cabb842f923f097c9db7ea51f8242279dffc90ff010b905b5feb7f26ba403e294847de45fe2713793879ff3c91155a79ff03c944b8e60d6485fa492dbdc20f104864f527117917f208ef4126ba3c79ebf89b89aeb64280bbda9137d0132100914fd223e4bdfa4b804fd291f7fd2002ecf8241d45f20e7a222daceebd3a707ef22ef2445af8f92422abbc47781d2d7cd2cd9be76b0bf9061b922a4ede3afe07e78900bd2ef2dfca441748deabebc127ed0802cabbc8eb4ce4017d92febc5bef4126c2abbc81fc8e4c84ff933cf8a0bc570ff44945f2def1fa8d8003c83ebe470f235fa4878fbc7b3ca59fe443c92719c9db88104864833ea9c8b390c3bc55b04b2c0fa12fb2a4880a7987f03613619d14e66dbf83251d7c52cee7ad63798470edcde191893c2399c833f249453e84bcc3cfc9445827d9bc4378ba42bec17e127d0ef2e6e08d7c128fbc797c914f12ca5be8833291cdb93dae8f9c4ce40965224fe89382fe47de3fde4726c23aa947de3ebe834c84b51525f9861e9fd441924ede3a2ff4493979e77cd0ff4c0180007824e0cea7008af04740105e083ce183c0d71b015d5f0434e181c0135e83afff015d4f0434e151004ff821e0eb8580ae0f029af03ee009393e0c7c65573621f78000f812c09d0f0028c2930082f02d10000f04dcf91140119e0704e17f8000f001ee84a0085574fc1040108e747c16d8e33f003bf80cf67810ece01fec91a3871e801de4e8a14e0e073c563b74e0a86e72d86090d32950db214b9933342a5d96ba7cc08ba227a1168accc430ea18433a02a327ea2e2e41f00e5f98b59a60087ff8a72083dcf717800c2237eea5fcdd81d4e1fd46bdbedf5af7f7b7d32f877787dea1dea1f7d5e0d4b2f280eb4b163cf4aa69da6f22dabfd3fe6a6f25775fdeb71c98c443e76e76f25277dae42a275fa3ded59685bf3f3cbcf287879ec4437fed65b7ef6b6ae09b37145bb7965b39d461ab82add043ffc1b90da36b79f8fec2b3fe76ca1381f84f10480cfd7109dadfb7088368ff1179fcf10df0fca8fc6e7a32d721ba0a0ea1a4770fed2f1fcfef6a8d41734eedce39a7f676ce59516474b4e1ab2925053b2977cdd9ee9cd372dd47ede39cd35aab596ba596e766023318072145baf8d849765ff86ccea64841675396a853aaac749c4da9c1b533d6a84c9440e24b2fd16510ff18444cdf97413497415c172007311248d45ded60a503a5e3c7ad59fa9ba678c0daac71c71d47fbeea1a7bf056504e24fc1198178de364620f76304b2fd2b137ffafae631b06727afedd7a1e84776d6f6a99321b9e6c9d54344f4cd32f2d49f9e0b008ac6c04a3f5955d79ebee61e18b5f701cd0ac27116022d9a7eedba6d69c61148fbd24518a6af69339e1087064a55d4a4a649a9792250d23ba5fd13e2416bb0e2b17dc41ac4870442dd453b6c03bce3171d9d32e0ae1d9f6670575542fb8c0a17e9cf8274b564e8ef32dc01d0fef7028940fc7d35821c413b0923e0323886df23686fc00368e024a5fcd6e8226bd3396b8d1295c6044f98018eb32e8c26b5e27d57ad37411c06c7252a9ef47c79efbfa22ee058aca332d289b2d23d9e0398405d3603472d5f9313533aeba4b5fe9cdbb553abb5524a41406da269bb9012b381dddd316766153da62c9d5e2af53f6e41141916ce9fba362814ca5a6b8352a07dff52788d2e05da8e76ddbd369fc7711b8e9d97023119de87b76fc9177e413865e3c57e29ef46c725309474fc82b0f7e1c7e9eef7e1df42858aeefc46c72d3fa8b9d11d8742d95cacc2dc8d8d4d8edf3ec74d0ecff3beaff33c2f8767f3e1bfdb97a3fbc08802b7a731185339529f4aa5501eca4bfdf6a99b9b8e4b7deaefea0b4a712b2f258b1cf0a0f352ada192525ecf5d3dbcc763738fdd3078febef183d03cd4e76d1c65904ef3d9ba8fd65a8bfa716a93427d9cb49112f51d977a0e0cba8f028fc4d57cbdd0d474af7d1428356a0dcebd14eab34b32305f120b96272c4f118c08447b1b508a1143ed259615c6a9df574b7c032cfff36c9a6653939681a6f8a4b5dfbeaf434d1d9798ae78754b8c8abe6fa78e5b6253b4d5374b270f35d90406bf86bd14eab3f9ed6db00d0a65ad27c9d0da63707b4bb6e7de7edfc671dc97fa0b1e89da3e0a04b95fcd170cb6b2f63bce43a1c8489d0265e79ed4b0f99247b7fb302410ed3950dbb204431ec926f9b45acda6c883ddc058e414d1476a2fe5a80fe5752350d25bae991eb481bded6d0fd4db03bfb8e35ee419e3c92034d69a759115252ae57d1eb7a1502914ca7ea7799fdc40d41af3deaef352286f43f2dd0d7aa9516c78183c75f442a98c9677069afb0be67c1f75a7dd975abbdb6bdf922e771f4a0d6c0646e9b8c485167d41d75f775316c44e58ead805162efaa274ec020b15287d7328e43a856decf5eec5db17646d529f427ddef6d806775de779b7ebba1bef82aeefedeefd4e755da740ba6ddb16b47d41db831645c6756797b878d2516f0fe89bdf438d7506ef95f63ad1476aed579ae7d92a4e7a0391dc5b9487fa3c4e4a19676bc71029cf438ad1c0f4e9c471aad1a1a9adad740ecda07354e85e9b60f53934b5cd41625f7b5b6de5b8aeeb3acaf91744238f9c3ee7b4765a6ba7967317f3aaf667fd6cf5d01f23484069e953bd4dcf46fbc71fdfe675ac9adadf638c3400a8f97d3ce2a7020f5d9f1e69929f905b1da998e950c7a529b2e80eeff85b4e9c3446ee77fded2798d371d5b75ca796df91184714a3e3c08e7b50e52e07631463f336ef3bea7160fdaebed77df71d8969f4f673fb2e4ee979526e997a2a0f23f71e146de379673b9bcf334a0c8edfd195ce4a731d5575bffd37d5f6fe1a13cfaa0ec7a35f90e713d6609c9b4212ed138a6740b169c30336646ccac03a389810989667a8dc50d9e0660365f80945329a83f2947b0fe8f8843ce7a850df7ffbf838df92fabec3a3607dbdb7cd52ab81a80d0589ed6a575e79af9420500ecccaa446ad510f274a0dccc1142947528a78e0e22b3d67cf8a872b7abe4e122d3d3dac2a8a2d776d184c88bb260f4557424a2925a329fdc8a261f0fde18f9fd0ae0381f8e0096ce0e841d383e018c1a8a71ca3f38f2c3c06de57e3f8d38a9eb32854f44c62035dd4d75ddb3d28ca67326394f2e76c4212a6db810cd5b4961951b5b2963a69d2d2353bb9ba8933e9ebe1964863a434461a69a431464a694881f183564df3136fe2e5e829f06ebc31c6e8495974851ec6a714ece2c47463e8f07cc54802a8e51849d8914b6a0abe9f63ffeb9c7326dd9c637fd2777777f707010cc8ff8619b8228c8042881054b10512d00c34e3b92329a594524a3ddf101d6b9aa6699aa6cd1d39e79c73c28066be21face84e21ea8ce05d1e9ac9ac4f88a3ab31b9a7440d271a68391de445cabd4eaf810d37136a58c7ddd017c8f323f7c279402fb0dade0faabe979185d7417074a4de508eda3bbefe8f7f4a3f7fba8e739a59e97f7b7a1e82ba3e6985c24ae75f77589cf9737f7f3e9139abe4b6e9683961cbe68fadef77d20121fcdfdedfed24fe83ecd51e1ef7779fbd7edeebb7d7fdeef3a9049131fcd650af868eeb9ec84fb2757c7c833ffdec8b3fddd40f9bb9ee962173d07a96bafcdf9f96f8deaaf8c962147ca7370ea4f064dbb13e9a465f0b4ff7c943f8e69d732502f556cd04329a92516d352c10d640a4c3fe608008af687a29f487d5993e2e0051b61a4133c3e6cb57492e833b57b5e8668424287c524ab34e0bbc84156e9131b0c51460a96e9adc381e401c7990e4a7aaf3c79a5025dd4917a6963a643472f53a2c8a1a31765de50e9b8044695c8d2c1c405a068fa51d3fe21b937fed6c202e88287f203b0464cbe17c9974f01a142a8142dd784414b15aa1901000240015315000020100c0704e270503424cbd2921e14000d789e486c569e89a34910a3280842c418640c01c010000c18333343b40eaca079ea411373a8415f7a3158055e81c354fe32567f3b997988169e0b612d73fb3b113bf5c122e364fe9743ed6869712f133c18b206823d7a961684d70f9af15f6352d16855c7ff404a7f6921179e806cd671a4c4972cac046321dcafc5b6538a0c3c97f03abc9540d84dafee2866aeeffcf2f159b74fbb4e3b47d19e304d68762a2b94a3415013303cd9c4465387e715bcc4e330bd514014ceb02a80c48c35acdced215636be8ac880cb0ef25963253f0d6bd9b95e6386050438a80eeb426d0775acd1fc8a71002360d1be1a1865a9a5d953ae243df2bf537f3dde6a7cd91993c7a2cc203cf68bd0b50cff10492b61a02df9d5e8e3af1ea9ab1a9d57a6a404347ab0b83e8a3f4a6d255817814e8ba8f1716fad58e0d5dce9174a1b0eb6175b4cdc2138b69918ce3db1d40033487861c215547c9ea5721aa4e39f681666abe3b875376b62b73c0e0607dac702b360e2e1f6d992e67906582360714b0209572c0b91a8f64aa5ae7069cbb5f119ec5d31ad498c93477fe80dceabec21893a24e192fda31b53aa5e2808334d983001c97f25b1a0adad898555b4e2fe8b5e53423276ac10ce2e06787324c55ff7533281c67d7f0111b2f3f596fb5ceb4eb1e326e1ee2f4345073800bb1cc63a8450558c1e46417865bc92d9aadc7e453a4f6895380466be0ef71656f611efb69647032cf4fe2d467f002d6824369cebdbb72ae5cd929486d752c73c417d7890d6682518127a38abe43176a3902b5f8849b1e21555c756c8c443e4b28ac7ae042362677e841d459a3de3506a854b3b211b0ea8bc728f22b65b55f44140c252c0d3bb6e9e4f6d97ae2301fdf8ae81646ed40356ef9ae54c6c9f0dd8530b5ad14c6e7a388a31c8e1f2f1ecf1fb68e7bc5e1a1dc67f162af5c5f5dda8629ec4abb37bde1dc43d18608c29b91edee03d195204f88c5b21fae113da21ec3e6423f6313823073cdc4686eb92d542c5730c8d7a8e8da72808200870641f9b706662ca4d0d5bf3649bfd52e8b51c2b669dc96511c66cc25b1535128d730ef694132d47261fcd35f2aa7a8172c2e937c84bed2c6f639235bc673c0193e0f8fc2e6fbb3b5ff9fa5a84c966bc237932abbd5fc10429b51985037c54237189a71cbe77bfb9e4b1a7d3670c96e5666288786f204ad76e2dfdd1aa393ce047f47c40134c479765a9fa66c867c0d3dd62411ad34b521ad6f511a9c6ae84d64260fd78a718f1937fe9d19b184cafecdf9bb30b8f80c52c432f63427fb97fdefe17310953f4f0055321a9229992de80c6445385d31ef7f3012504a8125b2ff83ebe37beca00a25d5a64ccecfd97ce621d05a25a62eab2e92f01bcbb6be972302eb3bfd71b44ff4698e94ba8030b5505735be55a70959bdbb59600c793ba996ca2d7e294fdb426a2ce41dcf7ab36aee388d2dc6857e904c0a0bd2ad313a90daae5a545763e4dcbe4703c996a06285992e712a6b1f2ba0853af30942350705222f5757a8fa19149209832f6c9e7bd23e73a06499404f7e861af9b72f99770d12c30b839a6306a08ddcc1ae6181a039fb3fd4333f768e3a221a2c565a58fd35afe72142b561fd09dfd232f33b7e842b9dba04c534091b742dd95bb2a576bfe55a4665018f8b198ce6f2431dc35ffb8555522c6a84fa3092169671a0a88328a979394302fca1541a5e760e7fd46b839236e59b207d1b6644284a4312171c9e2c2d524ba38d0ad6baacb4939d05b3b6e060b5d17ebd611daba431b0f4377f126fe76fe1c8eea6a9f7db18a805e2985b409538bfe26c94ac7c850f93f90eecfb6b4cfe0fa6b25d31c838a8a75e2c27fc2700a753ddfe57c76c2cff1fff10329d7ac26280443d67fb0adbfbdefe3f40e3f7ebaee1238a21aa60b7e1494e98a3cc6b0f45b8287eda556d2389db39a51fd2d5ddc830954821c88822b7aaf82ff6ce923c9c0367e40ec4e57387f3936f3f888cfe1b778a3e70fef45a3607be1a801a1e361290c15e9e3a90a7a1c5cc4e84e78b7004da6b8cbcdd89fbdb6e3c2179458003fc5ca2c701f387a173ca5edaed9c0402126ab16796d4b7c22f985ddc1aacec113af10a0fcbec5dc0c610f2b66f4517d3bbdc6598a4cb3ef90917d95f124ac5c6e32144a6fee24fad77211eec626af2b32bc83a7d72bad75286be15dfa4bcfead4fc12becd1e51316fc2bc2c5d4a49af69f42d24e1680ee12e0546a01fc22dd4a3c2b6f9ca4721a17783f446a6d71ac68c2204635482ceba36e95e83b3c11693c2af7f499e9be762817c1f9b08dd065cb2c8dc3618a5ff81ea7f7adb4cf7b9ac54917b8d3201b41e3ed181d9457428c9c16cdb61307dca0e34b7388610bf92d5bad65a1827f840350fdf9a391a32d0ff28f69c04e5dc1bde6e1d799c37fef297f2440ee6093c3382b0a9b38d24f83fc8d0162708b712f9593eb9963e142d784e3ee6c397fb5029b2935022dc3bf53ad74881e7881cf357f7648da321325311e4cd52ad7a40b1dff98e0acda01e450040446fc875314c74d7f502c06d6935f616070e4b96b1bb53e67633bbad763a6b950232de14746ca55684c724cfd5b9d1677075645881f5c344b8f1d4101d5e81c830876218c38af6c17c91fc3ce64964ad588a88e158e541e1387306c99fedceb0d4734221b8caa90a19968740db4deb8b6d6853f123a28dddea9c16c434d0477a0b3f789c3b6b1a1eba64fdac4812488ba88ea2730e1b4b0d62f9405618ead415066c188807809fd21cbe55a2c6a46e37595803e2fd5e4db387c04cd8c77d5053569b8bb374380eb9043a633d632f88158d7216c6e9df7165285e4790f6dab0578a8af8d736e42ec354f0a435535252cbd95dff79220a144925ea8a103ee40b0c8bf84f723dc9acb0859770a3763710aba80695fa2a33255433efaa0a02ded7f5153c7c5e24eaa947622fd18901bb819c5506ee9f7200631ddbdc38e0e83dfed239b8143904721892d49cfb104ed392d141977a073c02e53c19e3cd4b83ee32272eca79d9a1a763c925328e05e7d5914c08883e5625eee4607c567bb336ca26953345f3077a86326271226167843b2055f10cfbc7cc71725b9be7752d6851721ad7ed0523ec5af9c2bfbd848b06884c5442147716dc63cf30096ebc1007108449f4c6988452b087db4a60c81aea93efd6d11eaeee81ea2bb94ec0214e46f150f39199a4f5f28c6abf14198defa338e7b36d29578254d603fa3c9fe289c54fe61e0a833f73d322709b7f30e6871246799c31d39d733e4e108dd3a10a2db989f34684aca9ea90fd9caf51da571c4c528aae66241e0129d3acd15e9da4e164bc378b0f6415b091bd4b17064cc6e91a787aea7fb947e83c75a5fa9b3ae1b34f3abb3ff9592714d134d769aef68050a44a88b2b6521691b9ebef47823b29801654208562299d8295134a017b26210ae481627ace698744ca6e664510260c8b0aac63ccf3f85863ce1f3466131e581446b191fddb4a1052fc08f824298deb67f07e768c2bb7e9b2ad1459ba95a646ef1c64e321982eae620b55fec80c46322eb786546cc5d0653a9f32901abd9cd9adb10dae342cf772a0849d73cb475488991ac5736a2bc669edc4dc8c9440e91a86a4ff52e670655af8efffe8b7405180019f2227508f5b188283a21c778f6f757f5738028ae51adb643da9d5cffd94439e07fcedb0a3b385475fef4764eecd820d68932660fdd6cce3a203e7af54e616938e3b0f6c9a9b62a5081146f0b0cf2ffe952adf3330c608398ec1f0e13e8b5ad890e3c265183a58d8b99daf4324692179ff0f1f3117d8c91a62259d5d67ebc34a5badb33659f1960d472733399da66320447b7f7bd200d12e09e05d409418053f5d91d00d8ea8f9f4674d2d4362a8a45a4c40c31798c2d4097220e3c68226062f145c7f16de80748ffbde87fb8cac7b90208f69181be632ec856ab1d77d06ca0fded02f2d3e9a7288d3dc6e3c6ecb2a6e993b972c193892a83c281a951b3940be08e2609df2290f8a227fabebe47de3415b07887cf6a0c16e3bf0048f8795ed14fa534256be747aa6e2b33247564c8b01f7aedd0dfa4b1f76733f25eb5293f72c40978831e93fe15476dcc8157538828c9e63d76b623f3fdff3c19c793ff1fe86806ec662ab907729b03ce48a8bf44187c905ca59737e8f188fe73acb40c3279123dcc7bc3e3417192710ec71f1a0a79a33c2b037d0ae58622397fc398ba539a5a2125d21884ef3ec4373a95bb1241df5ebf89bb85a8e4091a5766ce9a8d0aa2d4295909f58a2fc9e0cfed8feedaea896534f22c430abf0e0d8c83c5d9e58127aa9aa4b803a22c729049ca98f94f84dc0266a4db194976659ea9985cbdcab1e9313f00784bfea99281c41d5e0874c326d76e30f41dc7f11d72983bbb5a5083618cf036137cdf30c4fdbfd1db0c03407b86188407e7c12b62feadf018bb8fc4b186a91309648ee97604f483f528d4900ad31c59751d3caf4e6aa070715eca56cdc5ec5728e405d2f8529c9354c0c3177232d64e174a43ab9d4b9e1045a5fca2baaf4ab535f5a5b0c077cd5c950b20d07ca8d916a98c296274a2c46cc6dc51d93985acae89a24682c5f2858e4c052bf7c9f2c5f6133e3dff6c51e499686f1092859e474345093482d4611b1cce760dfad2e93c2d186563e1ca6b57d06dc7927161918cc86a8942460700daf1319d1585011792b703b125067f598ade0ce686db2a31855612ae02073d891aa313b97ee34e5d842e05b70e545f600691c87fc864b04c8703f5e5d18ed78f25b85399c505a3ff119588e615f63ebb19ca80df2917cd24e1c88ba3b4dfdc4056fc1d995880ef807a9e2f8b1a39f39d5dce2ea46a5868bb8dd88bfb01aa2b41572b30ff05059b367e8cb37172502edf6b42a8d6c650bb0272ddd16e62f17a8f506080c30247c672461e15e710d1919d9a171e692e1ae67416d2ab0af03e2fdbc9e630030164bb3322dfd39adf5e254e69104fc0a88f7bdbc9cfc926659def2f9d65ca2ec3e47a1312ec03f6148d8515d32f22ec7743fc652f77e006a116c2a5d0981226fddc6f82caa94a301fd35349a8b6c4e6254508da5f20d08de3a883fd100bcbd85607e662e8e63311308ee288950d751e091457652d1307432e81d6e843b02197bf72483e27127b019371b344650dc67b30744035bbccaadbfe11a2da1eadc147c8d42d63fa3becfee78e43ba69a8fbca6437acadb90fb15bf09c6f6deebb2926f2162892091a60ed10d05f9853175027db03e234bb6372a421c24a83b4983d27da6559e8a3604ae5e9c92a7b23b76edcac62e65b2829e0981021e35376af9e09a8ff62966576cc49fea9282185747e538b53f069b4f8d2db3a49aecf95818ad4d02083766680c734aa6071b4fc0d1f971ff3f038da21d415919d41bdd4a1d0659bf515846f11099687aba822f52970fc53e407ff333b5e1ede3a5ec99a548138ae028e0d050be137577b97621018a7a53f0122b9c7ea47a045c04c946327fad53a660d416e913c62bf7bc58ec93f6bdaeb0f068f20200f751dc3812ca003afd185ecce5260a64d7b438704f72e25d2cf2f54858a70b4d1e0eada3480944c772cb25bcd449dcc1a941320f4ab1557e7cd47cb60f9016d49f47529fbe06874e9e6b84d8286804f1dceda9ce718539c09cb654009c70ab09352e15e54532081fdbaba52510c7edfd4915bb61f52cad058320734d24c9534024f6da2beb53c7132ab05204f1aea45ca5f1bade3870f5f950d40f26ebb868d88489f4e340aac51be09423e5de01dea2aa4b1fae23ec0d91ba032352fb179112d6530d22edfa1e8b29cfc46721b3956296f489532f626ace3d138c3dba10f9f6aa2efd2d0766b0c6e59a49a285d9c03217edad4f07ca229f43ea38009228e2c5e3340766990e7de0b22b927eacc100b1e6305a2a34035aaeb286001e2b52500a6e9b8bc24a8a9faa1b8f4946c67e1c3342a9eb08d912fdd9dfec9221a744860553eaa661f25759361fec2210878f2c429969357068328fc918eced434e64cb1cd7ec56bf06d753a369340147eb90647ca9aa4498525da14daa649635ac31ac8f883dbc6611b2e99d1176259b1327d4b6f4e2845a31e52caf2eccc0cb82b5b1d8994203ee28a77116d46e5abd585a47e4dc0a45efd7d070f4754e81a16a66fcd84b1c19e6e6720e8474f7e85b4013932bf0d849e67f13415ef28ed4e7b337957cdfdac8d8dc4c70d0e16fc6800e24a7359f47517f06a8811263264c722b4ccff38c0ea58cb6eec2f1a057552655ef9d01574252a48d33e2d8e8173a2868b2a5e9a7dc8cd469478e30652263b27d0570d91a37d21f06ac3ade92f64efca46daad3e26c4e978316bf23727687257bf49732719408ae446f45f738176e3097908b96f37f779da0e54f4c52483e4276ada9abdb965883ea2acb53edb061efdcd1e5b1f35a07bcdb843d5cf5c61e3dc646c2201927bda56492f0db2e4d0d720d1633691f8b0b1acd1e810963fc954a6fba5e98e7c2e7e1839f75434cf25a5ed46b0e6b70797a0b371c2388663b27061fa2fce8c60c0aed457d668d907707d776193483cff2e143cbb4dceccd85b573ef16e1c4af47abd9e84669e1b7a113cee4191198edd3dba1da8a661539c037eead686a051f2e9310a7bde4eb6170c06165b5304c85dba59d75f8da23736c475239f6c9ae4a2859d8b5afd0909f207b732ec62b9878b62732a8c1e2699ed3c016eb65511fb0abd5bfe6b55d3071f30433d1850e101bc5bf37d8acd90421bfa5d5d74e0b80a1603fc0d30770dd1c5e077e206c93d8af83b351ce878ae241c39cb70f2ac25ac70559fd7cb690e093d67c782ab40ab0f02fc4b67aa406871b95d5175f43ca0c1ed827d9eacdffa715c8053607ec6c42d82bac1d23eff30f39ae21f1074001d3620bc1f8951794f3541c308d6b0bfd8ad841427b9385e6d60da97177ec8ba81320bdf463c2e8a8fa43818b913d7a3132a6c2a116574cff87d7363f935e1fd397157a3f38d06c5725bd20f54cd4375743445997132a22271b083af3da3d500110085d92550dfcc7aa5a2f561573baeb49229c4c16f194e4d52a9516f04041eff082af02a077fad4776091490b9864e0c8be244ebb54fd5de61acda4964a1b0a981b430565346a500df23c133c7a3e25f510b22afcca279dd1ea62d2221377a6c0f3a227b877ebd71da10920df4734d1a8022c6ba266f3e34631e5ac8c24ca3338e706f646f24b3614e5113a1c51595182087d2c905d8e70c5f21ccecb649a5b46965e5557fe42dfe5b2dc3f090ece67d5bc63cc2b3d9408ee5e1ebbe2930d196d65e708e333e9ad06dcbdd1c4889a36b8225b4df7f20223393e26a2b7be90d00e26e078f6692478798fed0c0e400e751c32a56d0a602b948162c165f6f63e5f6fc61b19c41225c8ee1829ca954c2158d3e23c69b2f8b0697863bd898f23e336431f2fdead1473fe0c4c64804619b614a4cd447b9ea41611a7a217fae260457ca33822f0973e60853834d300d238ce205aac40d87cc97570a1a25490644c21201384240a4b8fac43f0a21cd930a11b1886616315fb81df6f0f127709c83acbe4266fe30ed0b7ae1d11b9bdca33e634fabaa4fe34491a5583bb72144e05fd06561cd05cdd3223f95bde352b1d8b37519db577536a4a2eb9722c7b305df63f69213e57c19c413f814cac103f94b970c509ce81de1f55a29edb529dd91c14a83c0d57f683acf620ab6820f5c1a450fc387d5c27d47bf5bc066aba5ab2723d9d6cbde1a713deb0778967e48896ca2333ccba1f026a1a69c09d7ff0db5604be753d2375a4e77d0fe5f7bd2cae027d341beccb9439333eb04314d6b4218708ebddb8ffce4e5121a4055716ad0595b0231cbf7f0081fecb53d99a1ceb9e5201134b43ccd4bfc9fbe88230319fa0d8f65bce32961efe8b910f414042220df178cf1ff27144b6736080d513982a774c5b3b644f28e8a4d06a1831b7aac18c5ff06b04f87a4c68181eb83a164cce65b2649867d9619d15deecdf9eba6dbd9e6794fcd7c18ae69f3a1e57738da40379a56d77ec4856c284294cb677e1c55f988a20d236e2de787d5e5a03d05b2003327ca0116314299dc66c798bc4c817d84b13c65cd6a98c4f67966ab97ae1bcaf136de59cbc9f4a8b63607cb268d29df134e2d7891fa94a65521b6095b26adca8a89281d265b83ec51ccdb0d2149b71a868c587121815538f4a16fb4a58856ffb2260bf0b81611f9fe6427cbbca665dfac3eb4031dce115a0297c69b621814758b5ce0d3495b6f5bdeafa8a9cae189d66831b8c2b4d285e176b0bc02f8184f7ebb9280dea8b64dc1a6edfad3e7a0e930fd6634a1eff84264bd47c1e050d0e7c6ab7a145253e29bf9f42878f0f7186d2ac2e9d919403c85c71411c13db3e9c2a03d34190385a1a636c85f5183f31d9a2455a7ce725cd931c7ea2df366194123f09e3f6b445b320582b2925f5f3c77d9ad941aa63dc8defae621d68729ad9f0d3446d70feccf7baeef73972f39f5ee81519eb089915985d08ea60a166f9aa972c5bea2baea722f4468e85c725b3c20631748adcc1b678fd824cc586e9255173476a642664adff449fdde1516f5c0a8691c4f2d27c695fb262e51b7699d9bd38073bb3e54bb3b7b300bfb15cb4d3ef387ca69b9fea6631f0e0bb4823b5897737eb15f9a799976023cb70cc5cc1419396fad7e6f618bad3fd9d216e8e3c8db18fffb2264c4a7404f1d7d0d1fe3e3b315951972825dbda6e97e26900c9910e2d23c5bcd4f22490e8b7d90444bfd73e9d0f470806a123e947d36553b11b7a2963dbbedaafcce3ed019211760553aa3f06b29e25435afa89f5263233b76b019edfa964a041bffa487cfd1438dfbc92daae2ba88e8a3ec7a413d7422b8240d0819bc3f31f69bbd8715baca7629ff8afb1abc24362c5b50cce633d6ac193ba0de3cd649fc1f981a760b1893b135dd756e9ba404c5d179560f004e27c9c2011ae3c7f08370a55028c43a83ba9057a57de5a5348d326f27d9cd67d40904d3e40f85d9923422049e1b114834464a5411427575d94735912e458099f419b945f8cbd6d0bf827b978f4c2d25f31a42334b92a5ab0e544f0787351120361070a3b1077216381a1a3ce5cd3f8357326fa1322773d81b31696f98b3ed700c5df1f72cb4ec094e4522c65e54b5907023455d6615d67c1b106fdf4946d28e926f031c9cbde98db1e17cab70bffdefdf67f56f6295b45942ab9990ea7439df2d9c181051747c03d4ae6481751f7324e2614a0eed3a7225aaf4db4eced89b453c06e6603075774aee161003fd2b361edc64c566f1159079b09cb426c895f3d685d0400c240f40ba8ad7c95287ac3b8bea0743fd6183d8ca087206f1209a204d574182f9281dfd8a78660f14988f23f85c8bc208bc9480ec46105c06fa1eb27bc6331ac7951aa94aef9ba5adab7e5aecc6e02ec01c54a84f8884072867a8c27ca76b52b18df1b3a1e7fe91430c303b29d75ae9fc07395c3c50d879d286bb585151e3d52676039b2ec1ab1cce3f8900fa89b78ad51f99eeb9cd45c1f9ea625886654a167f7d5b57e14b6bb685186f40438b6a1382def289e9fd2e877033ccc6982233c7087f1471c29046dd26a5f8db2e9ee07fd8bd0668346b003f98bbe9b8d0e2d3f3452d060e9ed77d2b22d1e719d36acbc817675f16cbe8afc3a5f617a9314fdbb504ccac592e671b2f72284078753cda99cd560d55846b89952bb48a969d2d614695dc704d9109f56c6aafdd62eda573e269f713eebdd544f0f015b60e07893b7fa634758fa57c088aa34f4224cc408ffb28fb1ede1dcbba7ba88e740ca186a2d541d11f0f69c27a73536c8c1bf404da8dc875a2e0469166bf25971fbe0aa63aa2781aa37bc0ac26eeee0ba7f7aa88efeaf22b533b0fb59025cdefd2f3d94cf87e7061e90542967f594eb455c14d24350062d6a7a720bb353790227b710d9442d9e2f40da77ad47d844b10f7da5cded178569ceedbd6346197c942ca7c3d6f8f3fc71499bd883980af57edf8381e37a876065d278006b4e4016ba821dc012ced5d88904605a2867a51d82bde3683f91df1135a9ab33e536fd6c8b1208cfd7dc2a86da952849a0bc5b1470af143b60f9dd905ec114263e4086fd5be5df3c5acc49e978b40307725d289242ff52410fca6cbaee4b02eb9b90b50909a84fbdb63661a0e057ad8fa5472a7d08082609d47c285d0986efc639601925379525faab53243550c2d6a5c780f10ccf66354062c7988aa07c092eb7528fa9404cf8fa542cab18fcd4800388219006c29679d2c7f202e581e44acefe237e68c2b5b7157cff28a56bec38035457a09c635bf3896030b27ecb66cc4973de2a93113f56ab71e3afb815d12cc095e777fee1d30aba518fe4f5485186d623d128ac1f2d3e50abd9e178d2f233c9648dfba742c674739522ce5c68822e012cf419c7e73ae2e69b0549915cfe5b478849c2e24057f71f11e5b50e56606ee50fc7ea0a40c8c140c9dc3efb250d2b25615057d9dcb4bed7ec33a3a88dbc013d8433e231735103e9adb319826b6a36c943a2773ece080ec2a0de6618c3cae96d0fc80a9a7ec09e6a3a2bae7718a3d7ebce40ae448590763d13464ec5fb63fe95881fe655cfba41f8b6c8d41dd1a8070d068548555167b8cc80062cba75416e7e6bda10d8ce21dad4d4961cf24110266ddb630a4905e4835bd2b0c049031b92d96acdd7b68fd9576d67f662b60b0399e9d28f1abf07e7d6e801aaaf3f86b2ce5c8290ab14a8af5016032b831ffd3a8c40611b51ef3bc1e02dd4e1f4f240104bf94ee2889307a1fb3f30ce6f36dc4ce9a712630d6a012cd9b835b644d8dbab899f48e1b083e124173ebabe2df4258db5a2a70b3c63d439430224a30ee9073cef827b474b0e08aa7b402098e402414110d1e9585c9ae047f9697bafd00f584d6e0fd899167e5a2951e782d1946f94fc6ce6d01f572581161b08d8c53f6d8a6f2716446baec573d3a4871dd2e5f0632189f8ec73988c7617fa2cac9a80b617fa042c4c4c6abb606b5011b43118a36b9f4aa36ec555849027939d15175ab5082ab118edf1e485a1f671f3aa64ac3b695e82d2137936137d844fc1deb58aecb54f55485bd1417e39ac68a518fa610e99ae440f9099806bd0e21990e1f7b5accbafc76920d0684ce16bdd336665060b7662c929734f706b2a7742cc92499056de43c40ae7d2a64fb5a8d086c72ee43ad4b5d16670d92906de02c0aef00be57cb2f1d99622c3adc41e7c5f33c76813093db2e55e04231d4129adac69b36ccfaad26c49764c854e37833eb5304edd7e37545b30c101777c8e93f4ddc00480b563a4f466e6e2ce3170a46d3dad4e916ac80f1b1aac22b58ec1c8e28f3d20c3cdc173aacea127ff085c942e283c7dba50d56175d5e3eb2acc04fb73cadc500a33e85ff510baa5cf6521596f8036d133e9635788b94dca11b398263ab0f348d1f32a9eab8a38f5b894d537d1d1d917377582bdb1102177a5615f2fc4963bd700f80d533179be02a5b691e8888dcc8d37e8e588336a3fc989bfe892492af2a92e901a093402a2092c21bb919de6d103c1ecf6e109ac5c4ac7a8e66b4a3054db091d41b1ecd4119dc9f40f0d7d00343343035e72b44b100c54878d519abf57ca9154bbdfdaa037921e9eb8e7a8f8512482609dd0ae5a99050017652697a77529e53c334a71f040921bf293600375ecbe547a13c29088e4d4bbd5c53731732801b7298036e30ec4ac7211b36c7f36323cf0ba201f6d4ac50c837e6299bbbaa384f17e3b469fbed4e2425ccc4c7dbed85943256f9d30106d6c99389894aacbb87e184ed9ae612a38f24b6fc8574444ad897b3e98718ed54e5245dd2b14dfb49dc772a73a3e4477a74bc15efd4e88c46608cdfea157c318975b08b499a3c2ec4bb2afb6e2acc09e454b5abdbbf3274c3d8e22d3e5a880bca0cc1975965461bdd513e7d179536408197c10b9be6b4c7cb3fb39c6821bef344b31fec7bb42dfe78bde77e36256f2a14cc744809a6875dd8998e6db09510036c362c2c24e277d1acf0ab72d328158a6f34b9bdbb8a500184cd4614deeac719dccf416838a75dbffa29ee45bd05c505569d8d96cb1c74f866c96da4b0f344c2d71f251104c684cf930b7101a6b10ff6776cfacc49bddde43edb65607d971257bb36d00a67e4cbfe756fbc10c08ffc07cbfb51c56132fb0862b94c37cf1fb4282e36453d1d4ee38a0b94cdab63e0bb9a08956b8cf03da543ad9f866a59b590053a53af404ee35a26683a8811792b5d76df945fec8690100aca8d2d0015b618f9e6c17849fae1b13fa2b7dd1ddf101f3ca6127e647c2bfde3d96121dba7936e031c01c70e64b8cb0c2b04fb4503ff0fb0c58cc0f6579fc5129368156a6bc534624c5d07e4eb20a4ac1e15c468c0eafd8d544d55bd20483b36096c8be5bfb62b03c07e1d5f98ae384a29f60af25893ff80b8814c573ad61ea9f6b8f557294713f0fb22143554280ed3a3b34d4f5d84474939b7d2c9f7cf205c4ef228cd34a68768c3b5017dff75560a52b948d85be50d4978db3323269617e53554e369ebac14441a683f059f055744b6e6170171fbdec7755f7705c79fd7ede47f67a9da7d4c6dffad7ec4f64b83192273203479e42b3bb004c91c19df282f5c57944a3a5cd2722699ca258a156c84a58acbf890ac0fec296328a1d65e18f92229a2ded082312eb29d1dbada4af3f07d66e7670f679d2a2d71a45968611b3d2ee4a530c76ed29d3c5bbb42199fc83824d11ed71f89c38a8e699ca745684628aa2f1980d547d20fb4beaadea7fd83ade331aada570d9201cdf8ff4ccbb7b2cb518fff63b69ea76b957d9bcccae01cf6f64fc403ad6fe91e9b8a766ead699a21694f077cab4e231424be8022c6ba1b2ff52fdee1452ddf9cf9a4fb42483895dc8fbefbf6db171bb9bf4eb0270eabc66b1262495209736bcc67be467896dbc27e95712d9f3f209695271cf6166e3c8b03a6a6ec3e84265098769f1b1bc5c23d67a4b3d34d781ec71f60fd599531c520269cdf52401ebb17499cf9d965af15c4636b260ff6c120b0ba951f82e0b25c94a8088fe014418044b8c8992c757bfb20406d43be1f6707e6bea83a7883cddc26628d136989b63922f3cb25916ec701ab671eb1e91f708bc9f28e2806c8085f4c9c82428f8859900fd55e5af851f9a8a12753942f3f13a07d704f4c5bf0da5ba5a0e523d6c046233762632605fceb6a320c9839714d0a1c950dd31f39dcb8f71d1bdc1041a100ec28a38563492f69399c26fe632b03fd381b7aa2830b6c1210b24d0ad34154b22082b82696a025ef2a14a8784b9cb050d62b1c4bb44e7ae09cd029b7822f792449a2cab0ad0eb80a91ccc70245545de9e2ceba97c50102264833de3498694d931e6628ff6edfdc900f89740aa6c919f8bfa439fd21bdbe73165433673a6616a4d6b40b56688d0e3a0c6e0d4f4070a9337c99b6506e1e46242bb5171fdb6f310415a5bf466f480ea6cc8bb7b220308a472c999b829285afaf33e0ce46d073bd9e3ea117c5e07a70ec21ed7611ef58769c298cb6c2df9b23282b427fcb91fc62fe82e97cf3d7846e5abe50f3c30beed49de6a66c45e42c013168e2743b85d99184f982a2677c699f99f8f9d2704b1324c1b2308cc5b288f86672b1b67c8dfd969ac24c64efd82600158c6b50a4fbeba067f29270155aa2c03fff3e8ddbaa72bd5dc9dbdf634ad63a0ac04daf04dba889a2ff327eeff1d4f697b2a86942736522c03b3238aeedef5f42c6f32010d4d412644c36a8257fa3750322729fd01b6c79a25560443d349934bfe7f44da4a0576929464bb5e356f7f16d113001b9b90ffd61574d0a643197a36d7467afd8a20ac223d0db41dcc1e8991d6f0c969207b593ac3749f89ee61f07a7752fad7962a1a26d622d501cfaf6f29db67244294643cdf47a190d4198279aa348a07c07a1683022c5948488e957244752264b46a813ad6daea984d13ff12948dadb173b2cc3a34012a03d0aa321e420cb1cd8f030e4308583411b885dd73b10ba4e03910db10198f94191d2dd1919c5e9128a800cf050fd8d82db0b3d8d7f7911db4445b3654867a3ab0d0bb2126ba3235e5c1d3a73c32794a999d2c90131c2ef344a23e52ff8ebd7165e2c62214a127fff6d28dcd52c214a33934062114ab12cd7d2a7fa2ff983e900cd626e9f9f15f0127307b02205e4614f9bb7c3bba2b2989e452b53277b1d0b86ee62038cd4c83eaf1f6d1c4ced27dd351db6e0c808c8af606b44c54c6368a627ca0263a700a3dedf47b499d2a99b20d88521039e2ee0eed524eceed01d66814b20cd43612cfe6a388fe223af18c0c28d253ab7cbc109e39acd70ae146145863af286137aa820853277cbc056c75bba48b8fcd64f901027d799d0d52c833c66388acb9e65b2dfa8956599119c064fe85fbd9cf651dd0bd3a5827c5d2f88fa54eec05a2b93f2ce6d547b8c21e916fd7f6512c8eb63b907c37fb9c288e13e604df58aca8628f47b1783c1ea85b8a6887a651810130bd8ed65c1b53bd705e9bd6b72ea7d55938e78fc5d215b9a7d1c9b3237876e4a8551953e636c4e8e94e92d39c2834142eb927a186305977217f157c750fbbbb8fe054d3146d99f883e8695874916cc3b41139ef74fe2e11be3ee34cc9ec7eefb1d19ab4c0e6741e3ad4a0d642e12679b48f907de26af3d160f0c925dbcbca36f8c62425f7bd7ddd549d2b7745582eb00e9c60ec2e5c1b6d44457c6a0e340934f4c90a26df0c179933dfacfe0e8c94aa1cdd7e220324d24bc7439e078efb5b1d529cb6c2d48756e52243bf11d1401c782a1b4d3c100872b32088285c751d8e31588a6b0e48dc91b46efb78324418ed83fc543db089616b6a701d2cfb16c8626997c1662f9c745c1816300822183475551921547609e0d07ad1273886d8b34160a031e628426b1b8cdd96a0349baa81b728e80302d985519847901409e47c6f4470509cdecbd93e3a1bb491ae52685bd0a482a26cf441d4546a7203854c74c5af04e9fbdcb81bed3370b1425bfd5d8addc2b72fda93f08b6681540d71b3265715f88c6a588a12ba0f9681de65fa550007715ce561582271248088c25d1b1428908c61ee7c46118e9524a4a5649c38faf27622ab018812940b57de913bb9c88e070cc3ed39cd7dbd873f6a5b8d39edfaea46033d2538947c9307c0270d4ba493d830cd84112d05a38c1dcf2e231b9d0ac427bb27b16dddf0065b48db0079df21f72559bd0a7379cc6224f35510c1129eebca4e5874e2702323a8a1686f304ec843017de5b44fc6413385847f7b9f162473cd17446583333abb9b946b9779aea95c250fa5dd78174af9c3b8fdb4d18412e09ea4fd29959d16e4e8f240d541d2de6df3153d91abb55af8c8251c212ccc882cb8928096b85fbf4a7412a1d8af7cdf9701e677a28a68ad138313453544ae1335fb34cc9e89a0d9bcf800fd62eb49283127be0c9bd059ad64985f337260d54530576d41131565ce9e8db98f666f5e46553c2b2104ed52901194da3866b3019c968d664a0b8ad064e51614a8089e15759bc81541a6a347216e2a36814260fa66bbf731c4f79521af134d15f01a8e45327eedf90f27f8758969f94a573ead6dbfd69e4906c8309248ba802577c5ab5726ddfce1620ef52230f2b5693b54d28d237f9046f57420dadb5f111f37aced30c4b4d52808af318afa7d29d4de2b0784803760659202c8b378b59efaf5385434199b82fa7609248f7873c51b573ddd96f1b87488fa0cc24ebf2e65dc53a3650ece109045aa9edb601f2b0fbec20bdfd2df163834b11030d2f9e91cb4569485f18be27bab2085f17ab70afea8af990b63118a5483b8614986c0e149502ed955fb858e49407f2681caf6291ad107173e18678b668a3bae97f1e52aab8a6919aaf532c6ae88109114338914c083692a0a71561dbd1414a7cbea0a3f17c7e797f7c215197a3e6d6abf5eb240a2e0565eef22256b13b9b5db65eefce834388e7ff9dca30bbde1880e390d533be1a3044a9d74db52ceaff674841a3be82882c48c6ce3b95c7a5181caabef92b3ef482c1d03ecc70b852a550e621b2bfcee9100485701e9df4b901cb8c0114e0a2d50ea52272fbb2c2694be36d59634aae07ec42afa2acb26624787251d315b8d1aeb5c16662a1629bdae25bbac9cb943eeb27f84bad5636f9bca3aadf8401bf97afedb26315632c9640dae2ca2c88ef20839b8bd7c83efa31a749988ea897842c35ba66a1c4d40a551d652dc900ecefdfe749d033ec45727c9fe52d083403140dc507e7ef8482f1fbbe791004f435edb045d627f86de1bc4474ec18a331b7f18c76554e724fa10ff20a47a3495898be773f4bcdbd5ab44e50bcbaa4aeff036a048a3057936e14f96040656221dab8dddc468b4fb1c2a5689a7fed6466e01ed1f273c92b08d9d8c5efd84a11c5f7d51da960e5466d9abe1ec4988962abd9e5140c966574d7030ab8f68f832a18836c5da52589a493dccd0ac38b77fd806ebf0858db00d891640c4ff201da001147d67ab1cbe8d7a7b9ec8f5f8b66ab857bb7e13d4fb758fef4af9ee804255bafdf7a687b582e278c2061f320a17d4abdb89708169bfd9ad1a45c432fcefa0610e8eccfaab288d2c9153530471e7c350eba6a0c0f807d85deb847df09704b000ee855a52bdb09365999cfdd5631e4c7c329324e29b98c0fc7cb2f45b666b1322789f024a0913a4a98f646c5da44740c8e6d7859701f47a2582c77011fc424c2d5a1a615e2887e4f8792452910143a7eb43dea250436e1d533140da7297a291913135db96a81e7544c7c6ef6ae18cf92c301db82f6fdc52cb19ea77128e237ed22365fceaed0a7256c33c6d4389b51c1158b73bce170cd561876319854e170d4b376e9c5b8c4c2def56c1d8753d053d1ede3a8546c58158c8b47b117c7e02dd151322dcf9d5b2825cb20ebc729d2fdd680152f91d451441775da9174bc8e45924237a28a3426547e028ccf6f7abe9a8c674af3a2b60ea89c77f4e5b7046d567e1a2ce19fe09759b6aa2f0bb4737a6cb1af6a478a9206402bb42ae9907a053bca24c340c26a846143968af0a6085048304d63391ab8c38b18eaf60e5c8690713d0e88f7f32822819fe08242609afb159031d0eee7bc61be5354e3a962f44df86ec5c3374eb336cd8427c831db65084792ba95aab226531d0856f2447f54e1db354ce46f168a69c598d797701a45ee476dc55949c372600ee40cb7634ab61da140b010e61743c81ebcb8bef82d4867110d545f43c584de29c19e53c87f477f22ee2c02b10def93b5bfdc76d3f869c2967ff304f1ca7079184fbe1bf765643e6833e4f2c6e04d8fe2c2c59194e2f18543a8c90aaf3f8a0c747e905b79b7a8f70912b905a5a68c1eff23e8f219bd949d81e67bcf0e1582e5a80ecdcf278c6c878127d7b1cf14fc90fb4a3ed817e1c7b45a6ba452b0d2cf3dc9b6919a4ba206027823abe65887bf5606b814d49848e28f4470322844535be84eebec4803c8c92c49d562858ad9c410330d8fcec67df637c75fbe6efc5625022c008275dbe62e3c6552f33c6b05038451486b1989ac2467c4f13b8261b1dde81c36674dbd5220bdadf24cf619f3601bfc3951d869d505dab7006edd41909ac3996ecbccbf1a0248c8da4d140fd1103ab88732624470b0977d6353b2814e09b97c4020054215dc73ab4d90c9fcec30bfee714e0a7a5e365108deeb9792e09ce8d5fe763495ae979d3140e974003d8f26118f9796a42c4e3da94fe9cd7db82b484f640d315dc1fc21013e9bc3ac2715de4a077d689b73b4236fff681b73d05c25cc1aac5b99bcfa0dd5acc5a4188d91a114e6c01d29628528528ba803b148bfda183df75be8fa81a7bed21d6b6bd9bb9576f4e3de1c423acc4f043e0c4adace62689c0624be3c93d40dd3336c7eb799739a46f1205a954d2dc7589b5b8d3b54559cdeec2d55e70a003f6c0cf02a65452a51162a055e08e87d444cda692e2cc26ef29a94f49fd622a690f3a1b0110cacde6383d76280cb00940a942a76ba10bcb53da2696ee7f0bcbf1ace8a03c743725c2ec7e8e7ed34e926514485ffd4248dce08fa9fb8cf3a4e200d1097b20e1d73c5f817042653f00f39eca6b0eaa4bd69ab7804d59ee0e9a9f76598a010adfc910411b05cc9b8196a1b142433bd6b164a91566ecf1b087eeb6ebd0236b6bf57f3f9d250cbd118888e763c276c3368b040fe9f3fb0f60dc178b36a7f624dc0ff00cdaec6a165563b0278d497d508f94fd697a0ae6f35b7388d30de2d2149967427e123a82804d1d78f6172e7abe0756835893b935c6e81943aaac79a3c800731eb22658096b3d8be5bb8bc987deb3cb24b99609a30766ecc524eeeca67c28a5f95767a8062ee660005fad0f973714cd1cb0f261b62ab7b8f08bd93e05cbdfeba2f2f268d9f14a850335fbad7929b80212cc079867286004039b5d64c066bcf1af5909f46b76d05c2bcf21aa14bc2e034c55e096fb36c101228659ee8c656474ed2516393de250ccb55821ec72759eaaee5e50a0d5c459e653118c07c6728e9cecabb9360b5ffbb0b66dc2fc235925656ec6bfab6a87137ccd4ff36d0ef7bc8880171bb935d22959b9de72da8eea9473c6734cbf236734ec9d3dddf204387186fc0c5b816a423676c8b578c248e492045de3a687508d894c8f4421c75677e9337f94766d7bb26063c6bff59890666afdfc8cfb82b58ba241dd15b6e0b685517984a5ce762c439cde5c2327636385b27ec203039b084f5a30ab0f9512a2f0442639d1f5a258b0225bc3937fc34e32bba3338b270b0539c3341213f3b195bf4ea8bf12e45e77882ef16b1e9983b7051231bb4569a06e9f3528a231b46e59b966ed961262030105c5dad3724e6f4afc030d05867399c6448a1c9c7de5abffbb942c9b4ddaddec2e8f341aa1c539baab28e2e960973db409c1275ed80341266c038096e1bd2c34d34d620c0d4e2e9246ac066ace3a29f684d293bb396009cc0700af0b2cd6068705512bf2d4b80d76264b0e514dd388e5c04f726bccff16157ec35364a093297ec7e56e3dc55d86cda3e44cbc54ee9ff3a8b94b20753678f47f2817f9f0f1578d52cae6850387138774ed190c313ca90acf60d260e2f710fcca03c568ea2ee3560d741500c7ba9ba66c68b171ecfb24ebf98b0e6c845cc22eb4c0805445bb1b8a1895f4f7b8c37086a55c34749edadbcf0d472b57a037dcbe0717b2e99c246a4bcaf4bee1eaab70c72109fcbe9cc67bcda582bd1f5d65583c32b3da4751bc1c3f04d6eb278837b3d066f5d80f4d3866172e4d7993f6a45ee15b55d116b034fa83daaeb57352d52a8e1f43776a060d10b6359b70b691137178fd89ee9e7582d9c44c583540aa82832d09cc096e00949f8e1ce35edbdf95331604d64110d61f46dc9f52c841a07b10e33dc67dd9a25faef39c9eeb701c39cae38f9ccd84ec7d2d897794a6e172907e64b287e0b7cef9a57ac4deda862cc215213acd21d0dd7259ee634232869506b0db9bea7345de9eb90b280b53cc23d57cf3eabe0432d5062253c9db53e11d5317187c86f725f4478368e2f41d4dd54c3e72135e86f33914a1ab23cdd57396ed553028350a3950add4bc30019754b47250744c6e6962453d06865cd854cceaa9ca7eb26709dd24a4e2a118f9680da6f1a7fc4c920a348cdbc43a21161f256dda7fa0fbff9e27f56f806403823a8de2bdcd6a77d08e74f3c1843fe11c9d958ca25d9521ac4ad461b3b3be22106973d0d439f0aae4e3800908d279395dc1ad9008b138962dacce90572cdcc41ccdbd96a5b5de3382ddaf951c7720f34d1e3b792d9054ac1d0da4df0158a3e5b3aaa277d4e3de52de7319778d72471d1b379a83e514e5b7ebc01d349d70029955f958a303506605a5d7d6bcdfd0389a6425db9beccafae4ae7eac5e27ff5756d9158d6b72b828081efb41dc7a71477a8cef2454c133ab2bc469a039d47159a941ef1573ebcb7f04666c0f734cd01b21f2ec9d4e4cce8e02c58c1a6e07f608a76dd11dd7803b3fa6bf3ed0c9402f32d8120c3f6646ceb454293b484a51d5deaacf79722f7a7eedb8cf9ee8264d4f97241261ec3ccf4a7e64fa070afee7dd2663b567455084c13d58be4e7cdeceb658ab5eb7e4575e4e5434e83d098afc293fcad89f2cc6a1ba53c441e48f940cb6211e8604915b5e6d869a41462418a7b2869314fb16f2cd2405291d45845f9fa9666070ca79a6c377418d4a36ed8cd23ba5aa5602c7d1fb7e060d8608200ddb1ee1a1d0b4748a9cc684ccb2450dbdf3c50c1946f4286184d8bb99c6b2e6f6df21ca4aaa4369d48fc1cc58cb7a997d1703f29a1e9a3a4c77e9999d84ef63f12eec118427e0ee572489cc7a851af96b540591fa3548b6a64cd2761df07f870bd60c51e3249cf327be22938778df74498fc9ea5ab39d3a997cd78ae13ae3976e52d63aafb04c0b89f556222d8f38f938ca856e0e23aca78ec01fa148cd0bd91702301679634b2a0fb64a64eabe2437fbc4aba08e8c9d2f839f4b10372b911aba1840bab2d7afdc6f80852b450948f234d0f80c0d62876caf69e730dfa8a46b49c94a92db439642f2aa9209bb82194b39a11b57750da38215f2eb48a7598ae9e0d5bf690865d8b692bc109b07e5104c7a98ae8982d5c8a6e887790ab2ba67201175c3524cf500b5a2d906b7d8a4085497773516ab50a0000df7838f81a6c9814dac5859efd087f0c94bd2c8791e7056641caf72eab597a600fb4eb15c3f85a679b8e370227633873ba1f1b96b040aaa3730ae1e3e76cd46ea3415e03b8c23b7c124bed0116f3e6a16364a051d5553b9bede0726b5b352177c71a59b99f7090dff2850a2eb5263d292b7c96683bf0e244231ac42e6c1dc61729c4f4c2be8647f8fd0a455cdf63d6a00276f002434b110d1218bac2f310ebedac12d9a12e6310dc21b2ed4e6ad60104fcc517091274e952c9ea83858fbd48cce056b22450d347da1cb4c80ec50869abf3a892b4a2344c209e374fbfa7e6e217f6ae43cd05c2cc1351751d8bd92a6b43d8975acb7e323d6a791638e6dd32f864d1b46bf5ea48207c6b1c981e5b1e9d2c1ffa9b1d90c21d57af296537ea2fb2aa096da8fd09772982b25d0967abb1feda34d09c504cba510876f50377e12cadb574ba501447b701a0dcf944455612984dc5c26142a439daa2ee43f70528c55e1c3462f428491280e34d7859ff103f3fd43a5110ad5b5c4f6e732c4929500a4e0204e4e387a095bfb506e616be9502eadd3811f9ab3547284a778f9d630d58324cebeb2128a945fab89f5b88203175ad0bf6e193d1827402c0ba48560b24405f42581132a5e499b2411d8dc17a151275520d0a28a61c5d86abd2ceb0eb70377e953c340d616c183cec0e944624a06b3759e86550c6717fb10dc5dbca1188e4689edd35ba6e17c97fe6a6a496ec8b810d186f8cbec7ffeab18f58fa161e62ca4e1ebc5b8c73e611bc625f95c51af0c88ae3bb5a037c907ea0c4160ead7cbb0e56e741637ea934940f46637686e18aa9afeb06c145f608cdfdf164329ad1f3109e0bcf0cda9a8c1565068d2c3a16e6607a6e9120b88a656b3759599a0a267e658d55470315ec2656e9063d554c84248440e751fe3f070a139f433953d9bef24e11f5753c8765d8c2a08ea4677c75dcab8a5bd12554de8f3c6cc1c1efb96d00f5c3bb09816854b4f648ff2192e05ea2c4a2bae4615efcb12ed67b93493d11a21f4ea9db8b287730e1284f8763a61fd8ad34e711e1c7776283ee49acc11049680308b237dd4d54e7267025a34e42aeaeebabe8b3957eb796de2808a9cc37cdcd6846b7aaf2e4d035697da175c28cb3039e5c6c19c86e93996bee421a2a67d0d6a767b90ae1eacf0905d5e6c8e7c7131732425d080aaa5a10a00480b0d75517c6ad1588938c6aa2d229ac377dfb1074b0c596100b59c3195e55e49f9c833518df9a533269f2b2eb4d3d88fec5b36802828088b650ce4a8d4410626b6d2e96b4a3e7e0ccaa1fd11966a975df49d9ccb11be1d695277051c1f54c14dbf7dd2fcdbbb60d26fde9609b78862e1d9dbb577a2d6931bc6a213492f9b4a0130946b4901396a58cdcd633930c9f88ac1cc7855c86ee235ade11bd9c5fbaa05b2cbd12a1d5dd3fed496793b325bf2fa48118f032e98ca7d3548fc90f3544635d5766c4657be37a2bc41d3e6817257f1ecc1823ab8b9e22808756434788cb186c5c3b64abc2fc197211c97460894f3aeec1eef0cc1054290359d98a001637a3f2cdc25cf7ac5f05fae5a11878bf4f4717b3bebdecacd925e95857764de181f95108d52dcf7ae3c8309669020734eb2c372ef21df6ec68eed31db6f8a351ab7f95c84398dc7f8b3626c4f004cb3a1d4e2b254e4a807ef0610ec8b099c8a27545e57146022206291df2210474339ad58a0101532d1757d16a8a7ded9760370a7b2888fce5f70d94a44da477a07d86556568277e01d1c24a458ff563418b6a5faf59d7c9e62f9b245c167beb5a2a8a16626aec453124a09f9e6ce0993ced93d08f7757394198938a00cb7c3299e75c46880820e23351e3395109644e1304c46c5d661ad105e2954cb7462ea00ddc76a9101dd748cbf3590ad4e6aff51545c4b6eea9e6e684cf3021ad42eb265a620fcd593aeab2988614827774b37c89b24ee5f97e5a103029cb7ebd4b94a085c138b20a031e1f08dc6581ccea4db9750d24751d092a00881a5b4caf770c5181c4110fbe4c5240841794c8c0cef2493e4b9bbe4be35d8f64ca4fc9bb839204ee44b7058035eb6584742dc47bf36b9de1625e4cf170147c768ff73ed0e26026865cee0675a9a7b70353000df263df23a08f1273db4b31df8a95e459bdc1481b181930b2c0243aeb0dbab931048f9166b82f4f2c0264b5a40bc6312c5a7fd4ad75aff1cb25568f62bddcb2aea60bcaf42a67856266e7d4725ef9ffa9463cf8578ef9d4baec3c4431d1d9fe82733a580a479068351c4af2966d4066d3d6b03a8cb5350073f96ed1a3f2a16468195018cdfd4b2b8e07cefbcadc6d7c52c9a44f69df2e7b985b423073bb02f051534923a081940b1b3ebc025c3671ac1a5f9227773e4878cf8d20b0d028a94ad0595e42d57235e19af81ef512855fb6d3409502ec25ba0ac302985daee5592dfe953c32da885ae07e0d0ec7efb4329279a4b25a244999085b8eb4409c8ef6fa552211de46f17edf326fef5344b28022a8c2110390bd9519fec17430271df681dc811dd118f48a8134c22bcc6effe49e1965a39465c8641641b2df61966352f2e3e74f883955d078ef65e2a908d350c3a7ebc7d4124fb79deeaf9784dcf27a2276c84a11789724f76a66f956a89239b9017bc71683ca2a593b6028bbab3c37bf2e11cbc5d5b32a084e16e6035ae6739eb74f365d9abaab9b98ddb4ea8c24976ed6df7e635929ded8ea2d82af3f8a36258820771f4592ce10e1e6cb9a44223c06a99cac9a4307ceb9a3cef5806da1fb9c575f5ca751f3dfb30f7aa445710bc3f22abff51e66ce1ac5ba6a981055bb542066af9a3618317dcb2776da3f4911d41bdedde3658d68791fd1d4a9801d04a81f644b8991bdbf0f9955c861f2b6c58b1e9fb39c6e35b318165722436ac9c68be56240b474e26b9ff8cfcdfefa48be864e23c0adb7782916757cd05881ab73f1f650df36018901838073806e07c708420334467f04710eda98ecc16d0eb027ec2ddacb4c1a5477ccb907f0b2c719bcdc6323b180e9eb2e39bbf19d2fef8167a00306800a652a3b01080369c2546d79e06fe028e4b97b45149d3c18153b649d43df9cfc74b4200c4f5ecdce2596e9c25c53885966cf637fbd2c1f19870b22ccc443a1f0efc7188748ec61092a8c8db62779ff70b24277ade38676e8a3a5c30859a293d4a5be2fd9363970b35268a232c3dc6992bd55b7ad5f4390bdde56516e1355ef179fe15da6162b98c4a6a6aedf5ac8c44d0902cf203332c704af1fb3ee41be46820227fe015831c3d22e484fcf6d38bfa9575e36412b84d4d82a8cdc4209f8a1a0f1c401ac47d83a65a1fe6b0bd8752491c61a2726918d8b02ce0dc053cb396b3c7e4dfa8c9b2b99827f0289a7fc0ad44c49045a7910b7b3e03df6e420ecf9544cb034da3a3cbf7008280a65fcdcefd04a632e80b93b4fe35a429e5ad791f5373e43af9beaf011a588175cf409d91be14b369409476dc604df51d2585839eba3832fc98f663929e0100d59edf24c1acec5ad046ec80946fdd1617d768822f2c8a655c678e338a761f85f29dd5ae340793e9f8d003ff9fa2f5cba2072aef710820a7baea8e0a7560030c701e12510982c7cf0590c6380607542953a9b1d4856c26cd7224e4f9c19c0ebd227aefb02ee66db545841b9e46a3607b912229c791b9a41ae17ec073d5c592188fc82af09aae5d7d3e487714a85ccf6ae4daa405aa60301161171ac209521b2aa123a4e59feb3f23abc461fd0ef02a10da412c76b7998e8cec5e8abd08a07071bc44eec0c53c68aae23b7c289c180ac9c697ca9f9135cc5887f0f9ba8893145467d7aec832bbc741fb02c5589014c38a4feebb769d8c5730e5268845242802d77594bb2bb6557ba362b6eef648137d51b40214ed5d5ead733c99c0bf6f0c7b312c02d0d62ce79e88dacb8a8cbd5e64de26c6325dcdb0ca42f71c17bf41d70a7f0cd33267b49ca7a48bc40bff81f6a2985e6587af0b86f9640348fd21d157a7a10f1fb8a6b7542bd03b719c8ecf4f57ba35507065ef9bb1d707729b3b0a46d782d391f47156603d7f08aa3cf3883d09b4e311881fad1e06ce3a150ccfc47227395ff80214378d681bf2c1511b4f7a01a9f5c2fd7389ab1caff10ae424507b75e7e95a83b07b0b4b93fa051e48ce8312507a47d3d62f3ff8612dbaa529682cac115af1874a193533ad22a60f3126ee6c17e4a505d26f07fef7f1acd6815360ab38f4f7a374b95afc09ba80aed58617476b0a535b845c13f298105216edb737d870c6a7f37ff0c9f13701251924c10272663d0283978d00634da9ebbd4acc1d8a20bd1a324ea623ae25afa2d52406833c67e9734910cb0bf3882ecbdfc86c81ce47c0366fc3ede48c88114ba6c76fc439c5485aecae365c9de62d77d61fd40116e0112636e540c90c031822035c47e104613caa34285c90e3d0b14652e390ecd38e1a94af82ddc07d13f4c860a44385953bebe51643806a16ace5d43b3d72e24f6c126fe9031136ccb3017831892067a53e0e88e8c6bdae0da06a06f13c59b4704a85628973a9b16522cf884647100278f678b9d0679fececcd576d61391f04bf78839e6042859271837e2e4455825cf1b9c105ac8d43d3d165bbf239e0107dec7fd6e9ecd20ad1557d3452a85568d2968fa3491a4030f0ef90eb8a34e17c4df69fca9a7060795cffcf5a5cfc5b4617c4bd79514eadff1871aa8474e266953fb53817bcee77682514852facb589019906b8e870bbc62b8c350a4d46ed550614a43625b02c40ebb14066ed30cca9f651fbeac760338821bb7a977b7c54f97a9e32b57d2ad0feac00b707e298fda3e6650149fd65119b33036dc718ceaf23566aff6904c3551d3fc193bbf4082c9314c8429c023ca19e2043867529a1f2e98e9b244e150b8568e1ae45f6cf5b144325b72a6861111ab3903e37879e060f5f67f88b5c4484dd162fc2a05182370ad0d094463fedf3f51702e2cf9a2379cf8f1103357098b3e984e92c42f813a9acb5f2140076c84314c5b383783bc17553417cee2a700456a0b66770c501ab4a63427cb7e99f296c09a8322fd1a7d7cc7fa34df50ff034f549ba5372e6ea76408f542b354eb0f0e2689f24f96bbdeff96d8508244b41d0fa6a62446dd2b7e1ec75a22371a6167ca6b66c3b5890eccbbeb255b4c554660b897b1a98686db84fd271baac2a14ccfefff541c66819a3a4686889cef325221f99c7ea59e7c36b92018716702fe2f909c98617acc3c18e9b8106120c652985e00acc36fa946d8703b0f4aba35ce2caa56709c09257efc925eaed6cc9c283ac3c712369bd338cc58ba08fb328bb46b67e74e0878dfe5ac82cd9e54cc30306c7258925aa7f5237d3d729b303d4afa799d717c22a09d9d1efe2cb78273d276f91d8cfba78d38fcb4ebf8d52c20811188daf8ff1c79a576190da947d736e0d6160e87102db4c8aa016ccff392b0df52ab645a15f6cc210465286bd4a5f9029b50cbb686f79fa5545ea7f3d18e61e594a5aa56203d99cbe86c57edaa20fae69af552d8a67b6fff4accfcf1dad99b0203808677a682406c5331e4ed916862856151023b93acbcc8867cf333e5ce8f2a52b1cb0e380e646b1cff78f5447cd003b0a0f01fc334d0523a82e40b543eae08a1a8a1ac836f9b53a9d3caef151cb6b35dcad4c686cc994bc641c237f09cb04e33d276b79a5c982e3726438c43b6c4b857161afd452f7853556bacaecdbec355f10f570286dcc730876798d59f138cd05920f680b5feed60757d50e25b435edc80ef485836ff6337037d09540a3757af938f12f140e086eb42041331465ac59be6fe5e5b2367d396f692270d0996c193296b87b268ae5623f28f6c79b4045afd9e8d54d5cd3496a529dc8f05f33f1e4858099b2e854e24a4311341cc10f5d190f2149f265a7891a3f2725096d8363504383677a5036ea8d2f31da5952a4dbb29b8923d76cd830c4fad417fd25b4de8ac12c6bc6d85320f1040501a5535eb772706c6dd6d631dc867caac94fbb9343aa1492df7bb237680d9880bdb01d99b128b8e449a73baa4cfc1b45f0ce75517aebdb31358eb0c6e778c94639f9102670878548e6fabafc29932ca5f928455ec5d7bf467dc45d5762464538e1ab27aff825a4ffa07df6716e2c0a320d5e5448d95a35c43b2b5d7ccd1192d8a1835605b8a1e3306e83b2c115a155e3842d23fe74830f928acb1e98b61cefcdcb783a1120553b675050d11750cfadd13bf5b601ea0f71f84a542d7d6b337502acddd7b4a33b05bf6724fec9af92a5ebf56d89291d99622b071394bc05c9d1ea4a0c61eff09441ae2a43ccbf4382dc9f8166529abf7c91d5e756252c541ea699fe1e0bd70b3bb938c9ad2ee86d50256b6effa9e221c75736b8c86772eb0fdc67d48dcddeb8ccd6bfd0d210bc2d9dd7552b8c75b30b201dcf5d60ba4ffe920cd4385087c91f1733df89339ae313f91847123919b36f45b4c1b817f789112940397852096ebcbe45f801a0c7b0bd718413e4fd2e200525658c5bf49b1404530cf3037efdbd43b70343f6585ac80e0d9bf12c26d4250852d21e3d27db342164dab1c90967b7f584d34c464fe9e2e911da123ad11386a4210246e189a4010c46af321488a1bdbc78d8484ab7bc7e03d5849fc726790482df13ba7b7222cba280ce2b5fd2068f2eb4e6933012ee4d6b3902153b874acb0a46def82344c360dfc72a5a1e0fb09b6c252c397353bc08fb6f3ad1ce43f323c9f25f69dfcdf4f00c06a64fbe38e94fe2ad6a32c0166d0830c59e40ac178dd863667c8d593da4c804d9c7e8d37d21126681becbe56de1cc15013a1e502b0c63deb08278cc38daf1dd1bf70078e2d3e59bef461cf21f3fc84a6effd4a1cdfc5fd9b6866bafe0f48afa90a1b09388cc169ca6e5ffdc050f195c812b03780ba101734003c409e992857be0c9cbcbc2ae575480e6d9ad334e847f6641ada5506fdeb9e225e10ee23fcdc572e6864e0161eef8f5248a29a801af8729639813b12f8a6d04785532144c3daac17eae820476c6100e9ea60eea31b373fd5e894f01b80defc24b6c45a37b9b81eb9aa918ac1b0f83266909a21bf6713ab982e6583c8362e2e853dbb5c7d2d8242f48ec6041f84f97614f0173424090fd0b24ba3a1acb49bac01b3627fa6dcc0c30c5e012ad424d8e6e07eed847cb99cb0f23652e350d105f7716a59450668c1893046e847b403f19d98ff5346207d13843ab27bcfa331c5acc6e174f52e960e664067779bbcaa8b47699336bb514d72f048dc04ab132b536bbe181fea7cb7cdc30e8c4c377b17c8baaaa85ffcc9ccb9d7792e7d06e3ddc484a0230dcbb5c4f89bf212b4eb721e694f17b8f6b43c5b81f815b6036e6d36b8487e30232e5e77f580f989d9988b8843ffb9fb8aab71e98829c26d2808b38993ed66802858636f4e13af5615367ea0c7312003a1af03e093780bf5f511e5719df5bb319cb5debee0278272c1460b069c115bf1b7c1412af8c5dd9d02bcecddf5d68c0401282ef71ca056f23d79c9dc354770194ac709a4a3346cdbb5e3dee121c6b95016a5a2ebdaadc7afd0f519b04027133b3ed3a258425cffd3d93b8f965c610b182a89a87efc04a2360f3e8e915d088442bfbd88977db16612eee5400f3ac543c28460813d2b3f98c7ccfd9565f7c11d29f10151916523039766eebcc19f3f59f5be411027183a1aa9431a4e0f88f8054a198355f1becc27b02ad6b599bb6ee66776b81807368edb64e3038f68da68b4ead5cf2e565fda4b13b91003af528f62ac10c34ee57bb803133ce04a3091a02c3c84cc0e0b915d1127207e29f1cf1634bde55452b2088311bca41c306f53eb608b919ca510ac3b1a909dbb8b3fff5745556e51750579b30ce90eabee6497ff402d641d2e40becc2856bd2b9937528f235c275ef147520c670e400d069243d91fd589d732d0405dc9554ead18b49ba7ec944f87629c486e0616c681e028a03efb2ba762a76eef2d4e67d17abf15bbd03d6fa25cd2a9b13bda55fb4cff8d69cd6b32d82067f19da5d3641072bf83c18da031c3cc0778f8e2aee0970a77f2cf7e0ce5721f25a44479db6e820baf11c384a35760fcba5f25d791d49e94073a75a610e431904b88f00f50882fbd8bf06e51277be9873063430890486d48c39f9c1d02de6538908bada4d5ae7e56eca04740b2ae4c84cbfbe2b4b668c1a01341f024a80ed4a5b505a15a50d39c504355366f199948ea23885f50c9668723cbbd251e5cc8584ceabe00a25cf6c362eab2e6e0d5a55b67b608062089c64c6423555970abadf88a838f5ae51c30362b14516510ffd2a43fb4d6493c84d24b2bb7bd30e6c049e04c20436b896f92f68728c8854234452915a0ccd45ce9f9c5dd49ff3ab7ddbe489b49339d11b8a7632a159c96d2feaa28ae8f3c117bee15a1c976ec0cf5bd0b5175b283f396b179a26c827e55ba4bc8e9759f12c344d90fc3a5e46f42a9a46c7cba8c8e2d3eedbac3eed66363c6d7eaca075bd9d411909cb6af8e793b2822261c876dbbaec0e5e37281ff31af06450321264996fcf176915da3d1a9f0c03226fce880d3740173bedcd1d790e7b3080f0b497a14883a31124c1cc2343086f0fa39c7f0fc6f75e7c8f44720d39ab38f8ae6d031b6622cc88bcc5fd36ba698683cb788c4e678cd5cd56774824820ce373e9c13a27df424dff06f431af445f6882dc7711deab6f408f1f8e94f4589e0dc209cdef49096b9554d62a2b29abf516a5d37dcb04441cd0b25e4a6b2ba6d75f5f7dd259ab6a5e4bab29a7b6de927252907503ca488f4593228c7a624c69bdf0521a4bd8b510466c5575ce29e7b4b2d6789abd41c818669713190a49028f5d3976684d2ed4d8477dbd3531c125ecf311872da6af6c060989ac3f27528b01bfc235d02d7392874bd75b78cbac463643939ef6dec4b0f94f7bb4caff7c26a552425861098adeabf4edc99d5aca39a1db1fed6635eb8510c20927fe146c5515d229259d77ce89b17d6bbf82e6db0987c8d9db8cfd5e7e2f4e7043b5ee70777fdbc35a6b2da85a90b515044ac282acb5d6da7fb8e292ad1ea4dd067d6a0581fe56f75a7bef5b9d92b10b5b6b2f080402555012950402a8aa2a0afaeac7a65f6d37841e3e76f5b4c2409fefc56f2fabaaeeb5aa7b2d7661cbaadee4abafac1bd238e0be6f62dd6befc5185fd7c51883beaa2a7a2f06b29f4fce39672266548c70910b95301deefe26183204f58319d8f8c18d0f144693ef1588101922c48f2142a8605b1f29ac87517d777deebdaecf65bd756ce5e7fa5c178cb884c37e0d6ee380df82f8635e65dfd2fe2caeb2dc44f64f72c4de5b21c1c8c6ae52ccc397e2d2fbbe17ab187e9886cfad744e8284276cac3d7fc52e092aecd85512537862576f73a5f6f9bb360c6cadfa80b04a4f2e2e55d775522bb56acd6e7faadb9662fa57576f7d573b3fb6db17cd2eed36e643c56e1dc24614c51345f15f78957e3276fe96dc84def54de87128a4571ecb7ceb184a0565b3a7b5314fce0fc5256bafe352fe7cdec60bf1e76d57e4083451fb36c11f89ddbf8e987cd529d8bbcada6b551ffcf9bb9d10546a63176b0dbb54e7cfa88c69b6db0951a2091b6f25d96e57c40850d8f42d7633fe9cccbb5d11233cb1e9db4b0317c8e482f087d65b41d704c34c40f7deebb2f7de14f7047f7ed614f7edcf473bebdeb729a5d785d116f0b02841bef7b15c2f5c38841551e728cdce519d726d55297598629c5280e9bed2af9afea42e535da5acc17921046fad9faba7150eb8b34ec9f8da6955d7d7bfbe7eb53eae3ead324f76db2971d3c416d1f0767e9a7c8a12f3223600caf5d7d7e7725d55b6e5d835bb9664f75357f7dd475caab47533916b71ef78b6abaa3cadd729753a5aab55bdf5ae9ace55576bb5eadbea2c2bab545e45d8dc05e84cd80b6b856e9f28b203ae6bfcaae357f2e54b2d0add87f960f9928c6449deeecd56522a2584904629212542b33717fb59e83f5dfa7b8ca116d83c9989218490cab7733a3a350f4f7b3e03596e4096f723e937b8014f06673b6024b8015f38e02cef7dd84f04fbbdf42032920db896b7c3147ae4b4d99b13512bfb4e7830ca272c5eecf7db8a9c85eb6eac5bd97c465f4a64b4ec36abea134af8f213e528bfbed4a59861ad22d7f45a92614662df08be40c059de27d9ef371214b6b3c27eff00d7f2fe866b91414672e369ef311fb20d1b5ee460287c3884676f2e8afd1ed2e7ea7b2fc405218ed8f3dfdbbe3f6b0128c90e9758829043ae11216f23a723041222a89f7b95952c060c13b27b98cde9b28799e8e1743038b89cadc3db381c8a1d71d0a16ef939ccfdf684710cbe6f1c2e8a2876cc82c84113e5d304f1d7a1c177ef2285dd1d88cdb1ddcc2c003f3e8f80a5d13192d1f1321ff0286482a4d050778e9d63bb8f6e01d67daef8723055e790811c3b071c34c776b814c56e61e30abb425f46a41a310320c001eec3fa06c8c2e369b092318f3aeac283d3f88ea78968763fcef7de93fe64b6c392bccd4851c004f93e0dba6d460c84fecfb3f8b419a416c4b7e3f178a6bbe10d39ecf05c248cd5e501b7d7a326d63ccdc7a301dfba94d5d65a6bad94c65adf5a6badb556167b3c0d42b13914faf1781a7cf854bf9e07059c793b3e2fc89b4301c57371f16843737e64a763e231edecba9d8e0965ca79808ee96402b29d8ea9663b13101b6fa763a2d98e8047dfb3ec2fa967af5691e83d0743add9082c243f67d91ad430fcc576f0dfcc8c3f25acbf00a4909fc3253f226f2a2a2ba4183566bcb84c10eb48f0c58180663b1d1d40f6cb763a3fa4b6755cb2f15c66c418f1448ffdbe864391f63bc9c5e5580109978385d47e5fe321b17fbf8fe160e0b6f2785e129450a2081326ba5d11267450224e3dae18a37b8c1e9fe83d27d3f7ec629f33c619618c32468ff2212e418ff4cedf28a55f69e51801a3bd8576b2dba34d33774397cf1963ac2a95d1b2ac65552fbb8aa841581d358561a12cdf39d4761cc83231f881d66893a025c0019e4b7e571fe793c1878ee338f46db6917ae83b7d8aeaa13487441a8d34ed5f34034d94866674e6ed4b3f17b6dc1d6bfab6d22d2a8128facef1475cc2d8e7c2f1c82681a0f69c3990657ead398b44ff9a361a45257bfec47e9340e890a7cd0f69aa93536bce22d1bfa68d46dbccd9f37186049ce48817f6491561222c58b2e963222c70c2c634a33bf00ca5b1ae0a9770cdf8ad09f6b9b0090863ec628cf1a4a04bcfc7f446af7e17c6d87d17068152a0a05cdc8299bd552ac09ad24b48ddba4d10c294e505f8ee8b4a26866fa312ecb6c30ec82173a38d430ae35c22c24a90e16f195a5978d6a9b4a8d9ba2aece2dd5b2f819ed2bf35484fa381827c7f239dc87a6b0d3567faf97c3e1ff328a59f9c93cceaa2689761a13225ca5b2b89b522ed322e740bed3029887a234aa16b5c92c5d4a1bd4ba43090f67dc17741185ba26757fd40263530c9e40221210454df0a973e353ef6b9db8c629a5d4e647a820f5d6267577f3056d6bc18e05ae6a35caa53bc057ad0bb5d99bcc9bb6d750a0dcf6dbb628926ec7a23ba4179abe29ec4d18c94894b01ae09d96fee09a1dfbc07ed37ffc0ca6f0e8293dfdc0530fce630d8307ef39bdfdc072e7e7320fce6426eb88ea37678760072c2c9a9f11ddb4d355e53e3364a70526e8627efeccc9e9a9ad90359660d64c93a86cffae1e03c9c87f37620cb7c3d9065c29a9d9db7e35e53536b6a7626dc812c13f64096f9383b383b383b3bbae618b4db5105cea5fe5481d366cddb812f15b553513bf35f0f7ca1a9d4eb49bd9ed4eba9812f1485aa41d5a06a70e00b3d9d704e38279c3d1feec017ba03e1cece9e0f7be0cb4c411f0e26fffc87d333610fecd95906172fe4b6706ec73168dff461475454ce343b81018676216d85a660b8e0452d8626c3c7bcb8610ee593b7d5fc95af2a19429614a9884e422193d7d5044e9b9fe913ecf9a819ecc943d260229f585a8d5826263aa7f8ac2d3d813c6d3e48cfd7b3e669f3353d61d0d3859e2fb40ea2ad3d0cad8368c3f815ad8368af3ca67510edff4ceb20dad9575a07d106d9d8ecd8449b1e9c8bf6f3e78c8361897586c0b9c0f8f973878389e167ac354f209ccbcacf9f2607f3e2e74f153897ece74f1738977f39236d204b8d8381e1e74f1b07a35fb463338b702ea09fd2c1b8f8297920cb7c51ce39def36a6af6ac3adb7b5f126aad24d626b13789c549ec95c4cecb42fba6299f21732e4345fba6945294542a95aaae088542a154dc0b97688b98035f280a9583ca41e5ecf9a719f8424dd206becc13cf89e7c43333434d33534e69939a2f73e0cb44491ef8324f2edac0179a722cf35139a81c54ce16e52c796acd34355f9e5268df2643a87c4a906233b3a2d2024abc8248d36460d1301ca0a05818876f160fe3619cc40063c58aabf236c5e4a668dfa1172ba7d3e904c3052917c6e13be5adcaa5ba9a5668df263064ba9a9ee69ee8b79c0190b9c7830613d955f28ab72c2ed5ff573f0b16208cc337cadb16976ad05b5cb20ffab800b56811c2387c8bdea6b82ab4ef79822f1525caf994d5d3a5ba456da1b315f20c79ab50a4f6fcaac773d9ea129ae7b2553daa9af9d58e0ac55ce22eb504aecd9f9504ae9ac0b5cc6fa1abc9b5f915957f8a72ce6fb38ae6699347a966158a6a860ad9e7bb50c1387cab785be9556be05ae6db4a753da29e50906b8f141ed5948287ad9f900986d94a5d0a8be1b6187571be054948aa413a39c93e781ac9d3886b99a1b72737d7fa1597aaadbf8d422626b5d66ca29e36ff444ff434ff8230df16f4b6630cbba1266aa2266adaf33f5695822ff5345333b5ffd2156bd326a289ed36095ccb49881a2406f534c49e4fb37adaf33fb8f29842de26aaf2d8f3276a1a91a26b73f6561151bd781008c2ba95ad3a79f59bfb0112560001d86e63d1121b55db39293c1dc8421a59d936d2b47fd1c8079741e95b4f25fc410a3bf2401f7c06e9c365bc278d469af6af13757c90d4f2c8035f68cd5487ea501daa4391b817a94375e08b0402a50f9f4122e132de8bb690abb01f75628bb204a2b39f44626fd2875cf2c312f6469558b287e06414c1e9b89619509d132852a9b6a23287b2a45a0ccdb2e40fd7e2b8247fb89657dfe29b1dfd299dd24cda3cedbd0e7ca1447096f74650024dc2e3da396da349ecf7124891fdfe5122b88cf74ee420a149a043844087407564903749757ee0cff5246cf656d12063eeeed5491309d54a77762d32d4bc4aeb0f36ba751d8eea631e0ef6e9c7bcb90b283e303d762def4550679761882cbaa1d0cbd95b4889ec60721332dcae084e137b3e7cd485f115803304c6874b49885b49aeb62b8283da95ac605555959cd7c6c39e598d8ece3985b0ef3d0d8c60c7856f071fb529ff7e942564f7f006fe25172d58a8a4ac4011a9487112320161f973e16badaad229237c37f063de7b306382cd7492557d5b225186d57b3bf8c0a384488f144da4522929638b91f6953e199dbb6c2d52b8ab34e67db6d50de1abf41d8b9307e38a9311b37f1a8c99b6e98721aeac38edff35389d8200072719b3f25eb06b847348355aa5f896045f6cd8802f375c8b83f5524bbf3a5e3de95fdac948eddb7232766aefe1b675f3f9aabdc78e97b91ed3343a5ee6fa07dd4d19d7d43893efa00ec6a5696f4e032b454fca9aa59c9287685da758f92996fc944a4af7397dc619e743e8526aef61ef68c6c8aa2eab0a7eaa164373298358c10b2c106e32597ce5909cbdf9f5b14fcfe07a9f81282050a8f836274b581b2f94a3a2b382723c970dcf657e7cf9bc7b6ae303389628851a7c01fdfbd7b411696343de8b9b4059356272264c4d60b566a953eae44738ce63813b066089377328432861bd55feca57559da2593fda7120cbfb4bbf93dbc059de9b88e040dc06aebdbf2107fb3d911d42d88f07560d4e27223ff6e654a0369e0b8cf6b1f801424a2db450baffa63e4cb6aae857d423a5558a252774a7d42975890d20afe0811c4b3a50d50a4935ab2aca5955b172277820c713f13db0290db54e1e3ab0e97b759f6bcbb1825d1f42f798122b8fd1b2248455156315530ae02fdf2b5adfab62b6d19945602b0c22b2c826db53c69d9c5a2bbf567c7f817b166e06b77119efddbbaf6af98ee7bb4b49a65fbd755195363e83077132de7b90fdbcb20ebe256e63fd2a1dffdec7a513023cfa281ccdc0de5639630650611faf24a90609b3277e43023b6e7d34d243e79452da702859ab472d86267d56afe3651ce7d128ddca55e002f2e9ac247ed737a0bf380a99d2f8d661f9b69dff6cf419a729803fc631cb4d64cb5e0cfb98274b9685a120bfd84e2705355bea7ce488dbf6e4620dd23441b0fcf288c396d7c0b5f8e9942da812f2b17e22311d3f6bc779daa341ae70cc2e2732b5212f596fb1102342767cabe2c4dac16347c65b498e6f3107310cc3b047df618f3a2771894bd563782bc951668ea3c2e9a36076071e52a4c97b98fc3d951ce35f5c8a37e4f0b4f7aeb32caee304f8c78f568cd5db5535010a5c17684efaf46d8a1bebc3ca666fde8308ed73f8de8c260ee445fdb6ad3456af799a0fafa966742097e2527d3a758a4fe94ee9cf38a7fb74777fea3e8f78da734933fff1b49891f8e9693b2fc99bfff01fcf055af7d621a7bd790f54541ccc8b70bb008a8074a5e460e65f98c6d602512f9c0d29df8fa08df73b5ccaa1523484c88f4a3921a4da4f4f7b514e29b5185a554157f1055ccb2b5da05654cae955cd625681a7bd1d3630e960bf1fd83c41b1768fc6e63bb08115f06470e6181037c01737c206ae6dae83192fc2b53c07e244de9c920a5c007fae3c626faec48a8359713070db97f281cae6de19aec7bfc18f8bf51b0cdbc5707f733e00fde68080fde68498fce690fc6f0194d3a8240d5a286a0a158d0400401100e3154000200c0c08c4c170482810865d6f0714800f6d8c4a6c409b0a64c22487811004419031c6180308018018008c4186868a373ceb889ab62e7f4f3c07477f6c2aeeb7cc32c893a3036b6c62352f04bca0129a77ef0cabf71f802d43394a46efbe749a06bc366826e0d686f21a2b406e1d3ccab70c3c151127c916cf3b8d4825ca1bb11fae046b392cf563366a5db455117661bac5b6ac3ddd3dbaa744009e24489406c87c29e2229b1283235c40cdbf00d95df90ed7001157b4011121876bfabc3ad98811cbb04d5bb0065327b485d198a4e5a9b24185871c0f8e930ae5a2097228a321e8c082d6436a0d0bfdfa0e041b1a9bce2e31462c78e425bfe1e8bd545aa1144f1db7159ff8983626d49337a1a090b2813bad3483e8002fcf8ce3b4e833705d26778b037caa71058d0e33118419c4fd922cf84dfa1163cbc9ad25ce4a15f6780033b133f4f598c2067db1f9358004f6a8e88f09b2627092807604c9e7fc7fc67b5d3be0b696a4d9d708ffef83bda27b3df82a9f60fd03c83a7cb24fabea80e999ce1502998adf61969f98fa9459011cc4a9e24c66cd572f4da29975db435cc4a94422e732b3c0b12ae69ee21d98e5e50ecc14082ff08c3328410ca6f2ed42d7c1dcd650dd25c2dc64e40de4605d86681afaa6fa0bed45f1ed026b274ab37a169c80a1a1049e50f189e75dea84ba4487e2f31a21e07bc0e19281957bcb20d71117ab83c644eea086d73e3f4e754a04f037c5c425a20a4158405e43660eb97e3d5c0149f24554e2b379c70a88a4ff0370a9f5b9e4b1529ec921b0551f503a485a0db694e2ac3d20fe91bb6239be4fb544204ed92f204dc0997b80b4e569a689cef3a963931a7f4efd3ea0d9d83a019314f9011081135c9348bfcf6d907a7b05a2b37cfed4074d5ae5ddb3e1f49c4a0ccb2bdff94bf1c40c1a82b6841f53ff7f4eb138b8a07054ae1b9d829f1db0329764bec06c334e1b5f6dfb9a9446877912a220cf18a8ee39eddeab0fbd1c37547dadaf80fe88652ec950e42aa20d7a72c4e70b65295c9e86f8fed0f0a20534203608a21fe93ffbd436e35b150e431ced0ba822272813d595b30dcf3bd3e9f6ed4381c6149421bf37dd148cace07d2c66a5a82cd51eb5ecd07216a4d85187bb23be0c6926cabe8f80caffd7a7af5af062e93b237901e02b60fb756c5addbe3bea6d8c1e2e95d5f1a1e08ef0824fc40e140d13e78c4a7329ac513e017adc30904607ea2dc5ad315f11daa130e4faaa7fee644c59a19ca17151a913a49d9fe7de933822722d90848c38bab2475bb50941c661c08f6d0bbf73831697b0636339951060e22625d483ea343ce33868322d16ce53d9d596e100c661b8a51923d8236aa45f2688d8d4ec98a8b7d8689caaf837f8781e36fa7387c79099991bf66138d5ee4018a73b6ec84280ebb08f8d6a5f17eca4d1b1f08ce44368e829bde845eac8bdc7497bcb20af037bea923a621aedb60d95c19deae399e99cd6c1dd64997d661c0706b43b1433dbc4cd0cdbff3c2173ae084b7b010bc7118aa108b039dd5b61b695779873c0b8e5319b8ed65c36a00637f123246314e5cedff23659eb47dc9684c868164733f1f96e84d211a88a66d6c7d5ac6db0972be4cf9384dc20b43e738a3e769d0764304be9db95861325240ffe5a01e73c0416d8b53580cd977fd010ea93c427776f1a71fe86c7f9db27d6ba38e30b449c376a3814a5cc0a9f72d1d322f8c9a1439cc418b2d34ada2ea969ff29fd3ec6a84556caa597862a43a5b47439d1b15745715baed5a4708aa1dd5f62532ecf8e22f05bbaac09279982720ca2252fd4d3777ae479ce1da694fe75fb8f98c07a8c3528566869df9b9e5f8c6197d42293a3c305b1da24ba1ab842516b480016070d0c2296024bf3c60b52fc377766c088959cf70db764a2bef9cab5ebd663ab646cc73c8d18cfa647029ad8a7bb51439f039f50efbe1db43533f01f9fe09bf60e90fdcb795e7f3e9bb1743c023d47e9f4afe8c8f12a0cbb5a2c556f3f09dba8370d18c83db9eebcd8b881de6acd0c1c6c3453a7cac00c3526b138e9683351f00d87c1f71ec4b967c181686348bc346138dad3f27edb4d1bd2f267748e6acc96514c5a61743e926e1e933a62bc438ff37dec10bd15c15c6f0d92238c3b3ddf412474c4f1042b6b55e6a0e111f58a8ee214bd96ebcd93f191b5b0fb4ab3a2fd0e813e28a1e94ae822131f2dd48ff6b017579a49405d9d2d4309f845e161714b681b1c37b507cb1332bf3113588fa8f71999fa8b903fb3aedaf66dc0d845f27114eada909106ace09a6b1579704ba14f3c326d9f2e33a0277b2c9ed0755db45635fba783c1c9d432356bf11bd80136c0ae7ed67e1f95f0c4530179ab126305c3957b51b16fa70afe4786c066465f59ff707396e508aeb5b30493036b031f7f125ac0f9658b86e0019cf34078e109192a2a43f3bc64e00db846f7f41651f1a582273625c643f6f292d0a70091c0b923f81ffa14cf83d3187e52bc5419cf8922b2fb1fd72363eebb7486aba1f1fd9b2f7a7d3f96ee746df7486f4b73bce5664083b7df7bd396cd44989559293f2a0734cc3d77804613c828180efbac6f0e69b2adf797fe64710043ce58535fba064bd5c980a5f2c7a750b155149322c6eb361d2957486aa1e94b7044d5510898881ad0228519ba8b808057b38f9e2aa09af7e3d82140ff7de5a56f3379c91a62b5c3e53512a1d3ca26e2aabc21dcee7c2b68935e993b2500784ab651afccdc1ef90f31b3a7c400058e5bf36be02d07f250dcf102bc52fa921377338c048420e4416e40a7f83a7373a2f2ec0205bef7d0b663ececdcd9ae78db71f886757c41f482152d0fb1ce383961c435e035101b998782a7fb2b310463894b02315f1dcce191795f026986d08ff9d415d2dea7223dcedfc0a27dbeabdb9310fb8bb11f9788b43b5c187889705c826a34d8be826b99c1f0ad1b05c155fa63d4d853185abfa69f7907f0979954a83d2d589d73f8980379058cc71be7c2ebbc5f6a183eb5565646e0453dd386a6bcb74ccbfa7b052355b9077e1ed2b58f156fb455691b3693923fe31f365b932b2d847449a3d89c0f589a16eb476cc9de8c09311fc40f988ac8c6d7a87aa8319d41734106a6921bb207363fd9f77057f39052e9f0846ba34e5d37a455e836fa964c1894aa3043ca2041b2f71523648b7283c7ad32a1ca1d010630db6d975063bfbafcae09261544cd3bcb0a4314cce609f42060c052c2141e1d6ac7b1da40549fbf893d07ef27a3285b355e2e1c78cfb8cfc1fbf368538e0d73b567a0e9f1323f244178dcfe53c46a906ed029758c18a6bc5343829c7b354af4cdc9c212e76cb19f871a3432a06f4d47e3406ad98299b60a238ccca64829a9aa0a66d0fd834112a00c0bfdd4efab4c10112121832f79cbf614886e9ff5df8435598dfadb3c551ab4122cb80f250ec86b7517b445fc5b4945eae6ba08a64545370a6e25ee7aa4c51c19c68340ab610cfaca404b4f5b4aa0a032e46d641f36a6233eb0df827c1b9d78904b482096cd9c747ea3a03a1e1ec89613b572fb8ef406704971250f932b8a89d32fe8834f89c22a31745a177ff0eab68eb8154f77a23f4d8f492b5194685237f3e8824cdb901ccb0ca719e40d849ab0bca44c9a8aedbea6b0d480fa23e5d0e8101cd7b06cac46c3e47899dcb8c5d48ea10a9716ec876b848b53615aedbb78caac651c5c80713b9597ec14911516a5701741f2f3a541a8e6799e13f931c159a382fcc914fd5b3160f31ff247d4989a20b8517f0ba342744c17cb4f567e68138e736d0462a1979cb8744398e2f5d81b1a28555847e2661a030e4afe5691480f364ff3992abf4bfcc3fde743c11e35a4cb241f721257437ccd0f05d151bc1becffb0e372723d358448a4ab4eddedd598048aa5893143a122b00a28a6deca0de8023bba1ec1184fd846448ade72335bd62e80f4ffd6f28cc1cb3740fb5a199238ddc09ee424d6b10f4fa9a2f5ab923c927f9c3b3b2b32ffc45418c04b41c5733c61e67b3549697bf3591c67a73e03c6361045427f4acb495433e06889880086e4baf9b44f54b6775a574f68b3ab9189091da6ce59843b416c636e15ce52eedc79afa5778723158ab00447b2d9011bab3a4ceb2e156420c85b7cca6a804640b318f8ca5bedc2ea9959de2710bb67f37dd36078e7be747ff41cd143273818c4d9004b6e15a8d8f513e2621a8729177eb58dd03bcfe7eeb346cc3f20c9cf762df8afcc32afcbfd38aeac00d6bac789f9745d7a12b79bc2cd0986cc6e5a2e8db8a9b143b2898fcced2b83e3c5ca4fad55098207553c0b1f6cce25b0d102fb3ab1b1d339062b090b36a46b22aa1082902057474d86f398c9e49cbff79037a39d398b2d290db17b27911bd880e047eeb49c6f3bddce26510e50a76647b4ce67b897082fb8964ad672455198e9e0ff9a147e29fb1aa88c825e88c40d3a5646d49dae200a24f9e1c37523349d592e7ed226dd8cce74b31a4420d410af150471a475ccb1e244b3767e0d28d0b1f5db56ef34847ba9bb1b035cd6b607e518dfac5fc84160369bfab727af3b19d3a2055959f4271b11f464570441f28c09907862ff087556d78e49758c0fa663c008f9707dfb250c00c3c8c47c77fd920885b1b3638a036e6700e4db1320de0f5aab859c5cbf18b4b77d90c7c53c31760b7c142ef9f1c08768f3768c3520cb8659b7c82734881a73d7e2db4ecd6f611e21196d6098fee9584065e8a3dacd81a0a95ba39553f2ba99aa5e111ab7975a30a066d2203a08076863ec77e65792f2dbcb713185a718bde649c107d178d777d3d78230eb6fcdb205a56cc0b4ea91f86d4361790d13ee3ee647cbe113f23f6083c20cbc6df6a2a464a4b868e469f313d1b4793874903ccb86ae5e593cc6744f5f6920b20f71d6834997eb1d9cc2c89c11444bec61de0c7dc710cefe6909369de4a8a0e43d578d08e7b628c84ddeaf99884b682ed9607d6ea5267e92f1c4273af73ebf119c3cc4d4f010de64180962566c1663ef7c322eb567da0f96e1ed12f243110e1f90bddd08c0d8750e45d37613718171b7e7061730f66c10b64798e1055422065e3a33b791e7d624e5432d21601fc81f61791f027bc0fd10a0a4ac6b3a8809d196261188039169cf35eaaab489284d7cd1ecb14cc19806345c308f532022dc237ad8a7b3bc126f06fb25f2b99348e6aec6183a2c97ceefaa6496d971fff5f2b1940939bf46b06a2cc455e255f9c48ecffeaa87c67480d42541db3c4fcb47136e9c179263c5d0980be2283993c928a05a495c44cc6449338592b5741f6f3c9344156ff1c791d55d766c4724d807e591cb6da38d1cb70366dc4733c91231fbe08a134dd97b36b706d204d45e3252930d636f0789a5148a1679f80a8dbc4f08d926c58964c7e5385c0ac95b63c9196ef1b1c65724aa7bf9e983012a64ee8816cd2f4ab27e5926f392bdf145eac6b5f9d1a8751647f927ea7b2bcb79bd3071b71c13347eb1c09ad8693d6c865dd88fe8cee09d6dd88b7ce38ff246f870049b7c5b5af8c8251b62370088fd8f208d15f9e090ed8e2e822fe037087709c320d8003ffabfed9fa68c2cec12302df112af47fa053844034d811add844d2f7c6614cca61e303173b59eb96dadc3db381bd824464569a69398fe99537bb57f4320fcb6e00747c2c752860fc251701398d37b3e9e8b2918f06583f6bb7bf43d9644706bbb794d40c675b1d6e73e6bd347fd4489ff9c844154c8a63748e0db0b177aededf5629e7b7a6b984ddb319eb83f852c1328ff80bba0fbfa40ce2ecd0d10f80c0c3f31484386b08fe0893d1ffe7dfde3440ea44df8caf88f99fc802349caaa7863b7f11031042a930c0cc11f244de108c559033e0c8cfc4ec7a3af8209f305cb2144ab66316f8e8595659002040b2fd6eb629b051d86645666ccac6866f2bebaefd86a096b3edad27012bda6ebc5d62a6afbfd6540ada5e235721510e34825a8f72d67e23836cf36f505c011f3b5747e1ffb4ed4846d230ec82ec6ba274a11e7180ae1ac3f0173efabb17b86105c52f05ae0e2470208b9ccf444e0e952791956e3ee33ebf1032fd13bf7fba73b0cf57a7757f1f84133f004d229bfdc63b81996839f5b302492eda84056a01a8649f81400d0070e618dd062ca6e15e15b425c2ed0f6b7c16a1c35e8f45f529b0b65695c7a781131d86357924f45ad0ba70c89f5bf9c9de118258d112775b87601a33294b007a28dc4d10f217ce233a90230f72ee3661766054eb2b4e891a13f1e211bea653749d67e4e1e916cabbb19f21961c2c8b77aae9172b0df7e2c96e59cbc70579e442cef270b281a34ea4dcc4d7a6e6dfe7f694c447b6c777e8fddae9f45da0ee07068835c4bba751e8dff57e3c399c13d7f7099fb3f1f6c9f49ee71f6df7279381f9c48822e72d8a11e3930fbc05a27e1c2a9aa952853e5ce6cc520bd4bc1071e821274803a3ff7e04823ba2bd4ef97c4119ced7a551522f3cf6ebe918bea12d05f80763e16e18e15b1812f2348637dd3e6cbb5551d8e43ab12507967561afa534d5093263f612ee03c1ca0ccdca97331b45bfa78135669d4f56efb6d6c5d1f0a2b28437888225c2f2e8d3f320aae8f1715cb7d8957cf8a6f0ccbe7accea70b08f4f3b86a23ccbbd29cbb34086fdbabd0b1c5159a515972c3ed1b33f8557e21a89bc15a9cf05f4a86b47892d7ef40316ed426cde968e788caed2171098f8eccd818b7fffff4644ba0005dcecf0c1c0b19eeac201b42283ba00b1b0e11cbc58b1d462b0f82c92098ae6b1c0025bd567c878eb6d627b7c0182002149e173561d0fd346103366ed8d2442f8229a16f9978876537c37588efb28a4f35bc355a5241bdc69c0699caea0a793227b41548c91d697a505cc29cc258fe06e79713483a94b7579e9606607faac010654efa8b2638f65af4a0af25c43d556e61eccb60f4b775d5e6f2836d6c4e23d33919cdb31270d50792c2de48a4e49cd60c376031e6d3214935f1654e2d48bdc3c05a1f19fbe7656cd4538a944a6651c5f03944de7034f76d96046119e5afcc09373ad7bff9c5bea1e7413c26cb86db3113c048f40f3383c695020950a7394d8276c917157e14db269b110bca63b2a53f16d46efc227ea41706b1115b9766058cdc8fcda5907b1ecc03cd85fc15ad95c357d33cd4a6c9ba7da08d37c280e2d73831e9d75b233cff7071e6e17dbb8a6999029f861aae3bad64edc143a553f8a93e2521d547faa2e1a3a4ec0050dbd03129b27e8216e2170f92acab6f40d55e578916230449616379ff48e93ba2097755bb7ecb55168d02df29ead7dc46400c48673598654c4c2ddffc8be8017b83a264cef84a9e36eb874dd59ccd28ccbe4d8382a8840add548c9ed8464c2a78a82d1d8de07fd504282bf02539faf085d487ea7668085aea8e97342809c3c7dc3d974b4d1eff23cccefa5d06d13eed781079a79581273f7d4b7ac3936cf5e6c66cf005586924c86b43f6f25c7e947a13e154625a11051ad6a0df5f87275cc406b502a5a73d7042258c72f1a105136e51c99d9c2d99a2370298263188f1724406d380a6c12dcb1454785cd67cb5804f07d407f0b66e46f99145eaf37ef114600df27abf703f0ddf2249190f1240b81c48bd7bc7f1da8c82368d810d70e3d5ff3778e21b4711ee3fa5403b214235a663cbb43d0d4581f06b8137aa2029433a3a2483101a708d5922c10b7941755fc67073d64c7f0ad49a4fb42af9242d05196651cd0c8020ec54c40a19330400a199bf867665a14e8bf3c903fe1c672920dcd3c08bb512ac50fe6b0174bf0ff0abe4e3201ac707c619f344d652db3104f3206ab99d6f9cb3808b840651e233381ba9915a7e560f09cdbbc2ec153453ecae8ddd478c2f3166db0facfe5c5511a5956445e756046504bad261c07571cc2e221f50660f84c15193000dd4ce367953668d453aa385921966293a14dc63e0d5a7be42fa549df57f7680c1d110ca435c558b48702dbc83ba44096ead39b5c2f2b77df54d29f88e214b1b3eadbe3dad7cff04af8d0ec031ce0e24bee0132f8e31c1c2d3bc86801180d474c45a4acadfd8e828b17ce6ccb95d8590cfc2b5cca6abc290b2b895776ecae31d9f082a440380a8589dbf21c53498c97ca4409cd8a780a1460244aec8d4215a42a8db6242a80af43b9944db18b5074f11ac54da65824a8f4d16a59605e5c90e1e4ce393fec98dc6ee49f214d638c6147c7c181803fe1c4382526bd6582734d264434176f0fbbd67d22f5f76b74300794ee4fbb0b506f0439aa65bf83b4d0abea59f338d22f809658ab12af9587e4a765e34692f79234c64223806e0e95ef42e149eb15de4ba434cef498b8dd3babe925120fb4f1812a27342c9f76d192885a29bfd164230eca0ec6c04b4dbd6d43857d6a0255b5009201abaf38c09e2b6cb05c4c0ad4a87f53587fac32f19a66ef9841e42d195ed08ca0d931c4c563ecfbf5ba0396a35123b4f29f6c6bcf92deb17813b6011dbc21567eccfba2a53c5e378bd42f33149d69dfaaee0384377726aa0bd87f266dd41b5c9322db62842d30780021855e9638255d979579c765efc104254a9bbf04d1a8a2d1249aca311e20aaef558e5dc6ecdf249988e94a8c8a15827f012151d940a2f1723f16fc6394cca2f420fb27c004a10d129c659e82910058b8ca75cf65863df217665e00ee3052af4effed34ce36a3638d7b7d45b1c1c0a8063f0bdd196194589957147fdcaf41e19b704e88bbca560e6c0a2c3c51148c184a49ac0d87a1229be9bf5801bd57aee47289e78751391f40b74689b9b8e7064d2c4bc337d43f316a9069d5ae65d35041f3d4918845a048c4226182d38dbe05d9c0db78a6772e9cfbcc4b946f578acdbcaaeac0c8bf89e8e355f68c9230610be001b5ebb082eb6e1890e350d45d5868c047a52a6bd338bdec1a41b0f30da0f29087730e8dc2b35c17436d4c97660bbb41481f6aaf0845be71b1603a702c1a7fcb2706ec3a5bd2cb7ad85b7eb7eb39f280d2e7fc1ca497e03a0b63cc9f81a6aea6569128bdc2969a99db0d06a5900ef05b5ec459ef5f3b3d9b5395f219c051fe28b09a86ea992341c7e7d0ce58938ab091ee37b2dc331029b5567bc4ad1e9d139ba1b43ee93fa011650a0a0363d2c6cd0a989bb2056f44bb5de4ead30875a6eec662ec85fb93020d82cdc135a00775769fe8e0e6365234a9c7e37a1df9891a7d838802dffb3c4bcef6e6167ce93e4280ae49cc9bef5983d9bffa43037ebca40b072ffa50810a7814e473b2b6f63d151736a9f9b63f856109e74fd254b863361db2b279437b7c9f5be594f3458eeb9bc3308b66b98f8539cc3a801bc88cc54863eee84a847b046dcfb5ddfb04f76c206eac0ab0cf071e01e9d049433fa23f4c5667d2cae9304763d52063eab41df92b04618a48e957b291a72d21e793eb282a32c32f416242c606ff3046d1a3603ab3c5db715fdb138f1172936e7970a240e4562c1ba186ebf677f35b0214b1b96ef5d7a0f940b38efe025b7bce767c89fa45e05f04b80fa594b2817a7c4dc636fb709cf59b1ab8e1b6068264b5019b21dc76a4c34d0d28be8ec949c5d7824e46f7812ea852a9463618b380c4262949c689afd35dbc5d48949a3a6d72dc98d258181e2347a4822d93b2ce23c944c99ce26a8ec2d23ca25590717809ce943fd4d8a164e19d739492782b6f80a31bccd0bbe3f88b22cf108c5922ee1ee087c057c55725088fe3e73fb6fb152d3581100c14f32614554c69a6a47cc326c11c902149ead27c98dbdadf14ee513345a00849b93181c9a7a7bc4178dab5a97607d962f8cbb0b8b848b270e53b84cd3f1ade4f13daf224361464988de08430cbf16bcf48f0428deb12d31fadd5a3a80904c874a910e4a302550e2b22cb4dd8439f7998470a58b07d758b56c6f25122521f32433370c74b5fd402844279ea1149a65aa5e4cfd8c55048a4b91cbbede05e60aad7fb5a2e069def983afc61467b55e15051c237a1e41b207a618eeecb8f26c248449c56fbbcc871811975aaac57554645eea191b82df5991b5441c4c4234ba4e6a4604fb682b127b49ed46228ff78dc8035c3a71ba87c7947947780630dcd5b59641e3ba4a67803d1191463dd7346f518a077a8c290b9c7821b49233f83ec48f5fe1816c31d839c32bd37ca906945c443c0b358647f9abb779a8d0439eadc95f8cf2e1ee772671c814f0714e9c04ddae173fc7326e9797c42c93eb0f7b7603b6688fabad86680770a4ddd154de100f8dd7d005a361f64f590e671e1e1e6c1a5eb06778970c0da71acbae2c32960f4850fc361027a2a1683fd8c0342682aaf7354af709717b97411089268a0224285ad14eb60b3e2575ebaae0e6b39eef47cf0867c2f3bb1f288a417e722c102a6ee69bdc612cc34ae50444546a1feb8d4312feb81f5170067da4c0a6602e0ca1d3a32a91ca9e4247403242a14718e19b9531410a961f52ea04283ef1312f7116ef3769c5622ee205917b74e963dc75ef34db98db726b3d0c292a50388083174ef261c8ad0ce7ce702fa8f9cc6596b810df4c5e7c198c867312ebedbb4c07c22a4e8f565607328c20fc8b00533e2af267e93cc0d8d6de3a639961d2a7d0a0f5201a3dd578378c0985a6dd73228bc2ee09d46a2dca9def2bdfb12d414488deecc65e9c27eab1da3f8254c31c1004091d900ec3057c3153765c1c43590247cebda1c4717b009343e32da4c89c134f8153ab3df8ed10f030acc4d56e961532a8470b55400cf20068bbaaf5632c4114245aca0ce203a9b416e427575c0b6c8183c4209846c486f63d3f7900090443afb6dbfd5355c48764fd07176e7f0d8dce8636f03fa03ab04ac0a054bc26850497c4b601e1d889ad76bbd27630a914a4c43f7742fefc2f0ad5cb1e93caf1cd324d2a17135cfe360b57411036b6f6c9054951680941a90d95c070caa52ea64556e8324bfda4970c5de48604acbd1f3c73b6975002e3fb757847cc4507d8888df3eb24755bd64ca9c755be3dfce99bb8f7ef5c1cd5af786a163ca146be3b154ce807e77db1e43fb09da87653f11fc5dca7974807a819bd7bd6d45f5caf602b84f82a7b233a3b5739040e3d5cfb5090914661db9a96eb4d584c9bf2f570e1098abd7cc142b679d8790be0277d4d2c9b26bcc4f30ed516750e180cb6279b919b75cf56122a74dfc98a6b1de782ec3856baae08452ba7d23cba17937fd58b7d40039346f83927ed802150757c245e5f25ac167f7ea239c06896c7ab5b11121b06c4c4d32803094d4d5ca4ed57a5684c3119e5ee7ffa48c2c4734274cc116344d90edaf5a3c07fd48d808c1a61f9650429121796b049e735e16385375597df28fc4c54726137af58d2ad9bc403669ef0d55bca87952f13821f71f5853b8ea2d984b76b6d9d4610e8571e40a66493daf581e78c7c21c4e6bb1755cfc51bb1f6345b4833c10d127aaa897b8ed7ca349e79821074ba88700ab49ccc59c76d38d4845af4d5d4ca084c58146535846e96ed071d208c8871161ec4089abd1f27ab48fadb2df76683d79b564822a2b04d162b39de19dafef42a12475d43ca72c42821c10712dc788643d73bcee71175191d01eac2551dc0f52b489278ad8de395be3f6b9d78e68ada487e6b14a1ee143528d44edc57eb881b79c2a7691bfaac26f6825630449058b52571b8a599eaa9ac34b1ac412f8d351423856a89f723ade9dab383c1de5bf93a7f2508cd1d9adece7cde64ef179d759ceb4a5301d7e22e06c205ec89f945dbc5d0b9aee8cc48344a43dcbe2386a6ad65fb01d9f6c964ddacde71356fcb745412a58b2c5f2253607fc53bca00727906b17a3771f879cbc6db2e150e08620aa4d02b5723a3dcb213da62c55da46226a1128373ae7b391ade590b2486cc308bbeae73593e6e63d6d6dad535126aaa1d268838b44f2cb2780c4b2f54ed6db7c1c9457d0da34c2059cb2e2729586c1fbeedb34c234eb7559614aa215c2a63cda0fc99bc275d39590dc6e8c2670554e49c861166c9b99361a0d358456569f8efa10ff52a72c229e5ceffd4c51577bd1b30f994c9c3023c2c2fb620389e7ae1264c758cdb0573a7d8200526e37381e016092314a88f6ec188220d380c32577e1ac499f945f8194097212d800c060328194ec6ed66ebf27f910af889ac4d6fe492b6cafe95305c430d85d29c38c1f65f7ee8941673f39981cf6a27455780a811045e7ce44a029f8c93bbd5b2cd26975995df3382ed2717c993ca1c7854a703fd74d937b0b38028740bb54e273690c9f90311147aad506f3b9d182ef3270563139422246ef70daba1d93358ac50f4aca492adc11e09abd0a48be88e249e946b54c3919636be54241229b08e18917a33868f42f405c7c5e10c7fbe00837ea73ce3705f94b0189d9d280f580838c14746e28a0d350210dfda3f7eda8d395099798df9c38b5df9554a5174bbbf3ae036a01c2c892fe5d59f1f72da94f8f5b717b8fd4b3c98c1ab5869421f7a573f2bf145e6ccdff0465770d236ea52e2bf671b6d59f2668231567a037bd425bfe8003fee661efef2a41c247891688a43071be4ca0c44388a8eecd78eacb8eaba49bca04e05dd0f41df8e7393612033588ae338d13e4f80536b0559236b7606db3022e552f5d4afe27f24cd4103a1849f3f3fdc81ea90ee012a218c9ff49d72a3691cc4bcd1f8e1dfae4770b9b0a25eeead38cf3b7261a9af44b89c6f7b11b8d9a5ee08c50c8cc940dce6dca0b56f0091ea60c091a88e8bbe4bbab21221a8f1981f1641ee216cd361e7ddd8f60bd5a2e503a3d0086d583bd76177d0d4a3404b35e6604793b71a2ba924e543782d64e6853455e1be6253ae9caa71490f98e96bc9e8b1bab77460602a3067fa907c182d6d54104881f5c68b203b2f2082301863169bc1b60f88e945a721a255803d4ecd13411af58c45f377c0b7da53e578ee1f9c6a2af820da589d15eeab56ed20f3a4acfb43547ea8f0fb5acfbb01cefdc417e0dfdbe91839786a760b0035065e4a31c730ecf766f455bbf666ec2a083fd8b10c3500856306ad916d64cb365cf8c1dcdf70fcf4e3f887ffdbccb15e6d45b02c22de847ae2b69878c31c7cb8cffcd8f44852bf397bd00859a83e47e8bd440247a72a7484e02fe9f1494fe2cf1ca021c3c4e01f7f1da4e11e014a22bc849194dee1a8bf64f9f41bfba24cd7926be60253096d699f9829c858a1c886b12925e649607b2758d9af60a412083498b4ffb0b3a751228a10c0ff48d3413653751d1eab6e4f51030c4796e404ddbf6c227432359a4f8b58506d239f8f843955429e82ce6d69fe123ffbd7e9996a598c2358e1b503e0051fd024ee86ce78bcdc84f80f0d82b8b96cdf44968662095f7091579d0a99710c10e5e42d1e3d51f031b343504f6e8bab35273c7c2425ae8b596a899238e062fcc1d993508f4ad5a87a6c439ffe836b7bb1bebc797c91a3ffbc06c30e8f5caa221bcf866731f3aa1d6f96ef8b070c358d69e308c6d0b8525f418b7ecc60c36d06396b07d7c205919cb33084cf95931d222ed7aca250a6c768a7cb0324de10b2a0c44908f4d7412d1882b4ed00695b1d36ce56c52b301377f967f29aef7690af7c6be74402d670f96cd37fb526cc9656340007db472f8d8478c388250c5bdf9f7ec3665d23eab78acbe8b9c812d18b4243866ba0286d6012288f1f7885a43791d206874648aaa78189c16ff07148341e12c7fe6a962736835090b849569b1019a0a7d569d978f304a1d0909b2359eb15fb91cf27932d2bc8da820db5da6f374b0c2d349584a3857bb90671a6fd01f0d77f673442493b54651e53f5c0470559cd7764b827dbe8f2c0776356262986c46ce2756a58e646e71e9736ef344803f304d026807d412c583026e4a7cddfa33f6a58dcd527f130502726d2add09f53ec20bfc4afed58f4af89ec685182ce7b581dd6500d36ab8817d066e81ff87e205382c6337a67254aa45efb9a626317144735f8ae110f493446d1353265e8699c821c73bfcbf41a6d2dbcbfb3c5bb9fe9c1ecb745e20be2a9c074159f43f1ff10edf9b98c5ae58abf1bc87b6f9d1e0130774dc484231d68dc8135246e11111e1541da664c9b0e92c2d7095b9a0e6830ce630416792dc87fee6f8e125771dd2b4998fa1c773eed2cc0ffa15798eb0ef59fedd8a51efa85188d22b22ecd9c5503c51dd7913d4424d2bf82d9037ae83962be5a6c588155796366e0f07f085221e57134fd591c6ffd7234c07493adcadb793e5470197c0d167ce0757664040374f65e34298716ec78c71042654260239bb2152562e21e70fe917397db20c65c23944989d8aacc9812a168b457cd40cfe718b7e45fa6984f277ab739e8c241a2c698228a8f1f2b73c1ab111267be65cbb10fa2dcd073594896c96239e26041610e1559d8ea070944073099580d9de4e18ed705928d5a1e49db585f04acac3c75b8540fe93ce46d8065fb4d92562a8cfef54c4652a44f988149e82452351645f245e610758e00664d1856ccf10af5baaae296ee6e68c8ecdcb8a56a2102fc18fa8a5d77144381925084c8065bddf1df12667d5dd8ff157c61c722117179d748cc341228c96b94a85cf280742e398707d34a812cf093171e25900e6d57881cd90b20b080e09161581c35c4bf57f5deaf3d02867f296809a211c76d9142d43dd297eb33012e59741a3386f7dea106162dcc5d8a641534e6ecce5f98ae889d1c4fa5db53883862342f40cb207a3a7701f9956ad16d2490c91ab1fb45024e12de63e9a9b96105d49ee109aa9f6de0aa006fd12909203b8396ca3eab13aaa6416c3d24fa77dee93126ced603220eb08ec83ab9bf5f05b1f4f177084a86085a8fa109f381af96f5d45371ec77d5a113b63b9165c9b123da4309c8565115b5ae002f61ec9e7e1f6698204a8204d74d90ed26c7be4544bd766150f061f816adca1ef95b158ee1ac3ea372c62be6993db0c5a33d104741308c09e3c33c5ba4e958f7878f3790ab435b3016e4f66a64b2f54c2552c05b22e848ec4341e078b4c3c473e6cbd587e28adbd5565cf4bdd57dcb3356f0660c958c61a330baf02a193733afc4c50862bc8ada4cce5dcfc23d8274421006593f8b308ae64323f6a3acb9f8ab229b1ae64dc24c5c0805dd46a8c7eee3534db20e780e7bcd1d00c570399038b0c933c04f0360242bd5f7057b4da878b6913eb417139275e8267a013e1568ea21ccba77f7003de3b6aba80a49b98a63961b2831a81624103ce20b6b985bed2875424abc416c0c9f0ef06c85222bfe478eadd6f1fbc6c4f23a824861108f589b9765b26500e87db1e4fd7137c794d76f86c14201b194da9cc73cfb1ccd2c9775ddfd5299560134a191cc0fb2603a13d1aa350b2c11e90d3c49b6015e40bde0e0cd296efe443bf097efe1204080aef5fc675e89b0447a647f113086d92c368e1763eaebff1a0d26e346f1f5900f25b8425ba3fdadb1c3bbb252bae8694742c014dd4e7bedb09dfb748a6611a1181b3890a1f11ff1524491c928d5c02fa6e9bd17c34c80e1b0043d13d02f869f74956884bebbe4031a7dd362dfe4448a64de96c8c7844961cfae80f1e52b3e1d930da057763a1eb46b3421fb35e4f09d4958fc111ffd368bfa63e10d59761ee94272dd1878075020b017ec52d5b017ec351a303e2a167d15d486348f72c2d1087683e7d7e52402cd8b046a43d0532e7f9f9ae5503daaa70fd9758e6b8b0147d17bebb8014f880f1dd6f41560c422a327bd10636edc096da433247d26117f0599e86b020962d2c35fcac47c374bc5a0ae06300cc610b2db265013d932bf194cf64a0cbde1a7a9653d5f985395d16b96db8f1cb5b3b6cbb3d9f335f5ebfa2170a057c6476903c3953312a8499e65e6bf55e7c2a75e9ded541bdcf19653ce9935a7a9f9972e55f11d3e71eba664cf8d9bc3f768295293f7e7143ef2eb24e6656eaaf53ad2484407fe974a3356d3382b0d68aaddb437b23338573425e3c94dca8b47c242ba9dd402c22f712c08c54674feece5dea7421a498e9ec4937f54d60ac7126efac65b7284bd297549dadd1839123e474c29d4424b1052cad4baaa4cbaa2971fbda19d3d18b5eb6c23cd93a9cfab399d0ab039dae39c3f7f299602a93b25d9230c2eee7aa39d91a76bf80a572e661f3b87be529ded59fb32483ee97c6edccf44918c477ccebd5e31dd72f308f211b6e21685b0a1ea560a1391ed2127b3c4f63583c17c1eddbc3cda3451a48002fa0cb2e32a3f30d58309afd375d298548b30da6801250cdb82bc926c69b6994b50e50f1054191efb1843a54e32df24ce9d7afa2fc4bd6ff015fc671677b4fe77f4113b5a988f870eb6650401050a847bb7efe4330a2ec7e5973aeaa632d21b11474921a2bd4f836a6f474607a3fcdbc20bde9fe6c509d28f8ad21f73b1e0a9ef6dd6643ddc84bdcc0c3017163892f91eaa7d37217a02f040a27e0e594436b541b516cfa434566e1075d988016b958ccacb70adcd6514babcefd5880e4aa20c291dbdf6f603b247995f524b66aae22d467b7793cd504ca1415fd04428d9e3f6d001522b0d9b761815e393fcda1463693999622e8ac9002370f2155d472f617612524b8b3929c0dd21b551c777719f6c7c9fd241ac91ed2906f29f825fa45874a8801b524ee428960d59225b5599a2c725bce4810a8ea28b41fbb66d13eb7a32420648091d41d14f4d62d90da44324973dbeee1e1abebb4f0d00a10d3af309fdd3fe4e4847f68cdb4644ec86e10f7f2dc64a7ee4445856752a1c43d6daac15a7fb130246a827261606381b43c81bf2a7a389bf837839527f9922ef5f39899b6e907618b780a6277d4bee5b3e0e8b1ec62b1761e2cf6814f6385ec53ebc915e34e40f8d5ac4d1a1a58766361fb37220fc24a4f1a1a5c9f75a4de6a39e56925ebd7f3da6a38300d9b313dad5ade83dd2ae6ec02adf835e85483b5224f66b7c25efac203b062d115e2eaa70abb4e2a0f991dbe1dc7a91880c08a243c699eebb47c7fcb8846f00ef031a2c99d0e87b90737675c4ebc9e27560bf3819602f619d06cf693ff24fa92639298ecf537f51032a8053a1611a651e2af074ddd8fab9f0191f64cce9409ae808033414da46da62389fc708bf15f0a066e8390379d2e21786328695587c2899f1858bce7781adcd77940a19091944850474404a1415940f3d8108f8face2ef22b42bbc7b7a9b46415f888e2aac114d4d79fa317a5e6020bb4004944312191279ffd935ff5a86aeae40ef191e91176bae7993fa10e0dc6898585a71024f0c9168f80d9ae940bc54ec89163a5ce02f19491860bbbd8843769a8bde3861190487da85f41f8abf5625bfea049c4207d553ae114a575f97341ba9b7be28658ce7c1351b238588cf82c70b4e1fd1742c3c9d0684130619c81e93ba34f34b42763dcb1957765c3e03369bb8764c2a6ae64ab9f472b6e66636f1240c3307963acf819dc91173cce1c45350ebc21e2e8aec2550edace2102f6f9ba8dc5a4a240538c0badce0514581aa308d6d4aabd4400662f29e3740bf4db90f81559722ec0588ae7b8c7968851df89bcc0569ec6e3e7ada8c1b734929e7fe0467711513636a9fe9567516712ccf17a7c9fe2216d35b2f69ddc879e9ededab83706402c5acd1d190323fa3cd2dff3a889d5b0f02d9b950a801954bb02ea5bc2795820d855693af915f34d0ed387460acb8585a001dc3f6488f7934dae9c26dfb2d230f044011e3590fbe29f0d4030fafaed3adcfefe9b2ea64d4dd702237cf98d548267b313fa7b79befc65eb6fabb68d9a88d052237bef2d03d9075d07ce0739c8da97ca4003b9848a4ca2d2d9ae03dfada440d4095cf9f695d40a0882281408822b9eb59d65016bf66e675592265e5e969bd7dd9ae5077edf497bcd1fb8d28228f9258190d1b80213985045169678e890052074ab7377cb325d71c5115660748422c4d082229aeee04150fe17085281cee65b5d4686cefb420b983a218a2546cbfb4353c7e57d59248da6cecb1be61df3de797feadcf765125307bf67de34ef9af72593a933e32dbe5b6f1aefcb28a6cecd7b86b78d37ce9b863700de97574c9d1ade97594c9d9cf78df765d3d4015f17f2be8bee0079bf9b936e59e8af7b773bffb4629e764f330057e65316008cf25c99438d2743551baecc286b83b6857655b09e2bb3cad663539900aecc294e009b4a1bc09559d50d80c3472bf6862bf38a7743c7a201cbe6736566f97cbc185cbe32c700f3b705d88d57e6d57d38e53482de17274fbb2d1e01aecc2d21014e2edfcf95d905f513d214c17a775732b35470a05250a8f470e5f8ba400f2a29095c390a092281d40beac3b192f96525876a0bedc2a8e8b832c3b0e85861f1b41b9302ba32c7c4006281812286a7dd1d150e57e69d55a7f274eea728e3f293c13244b06a82ccea2c05b832dfa5002d37c6876325f365e5e0821201cbd32e5e055d99f14b106b85c44ccb876325f30c8c0e2fd8091a17035c9969620c0053f3eeae64ae39408c8cd7dd8ef12670e508e49eae902620f315cdf8876325f38cbbe3d7d3ae18c3e3ca2c621e177bda6dc9ec70656ecdec80691c0157661a340898f1b4ebe3423e6868b6e86209b9bb2da45d9bfbe9983901d8e6460a6abceef615125023c3d3eecd4c8f2bf3cd8c1e325a42ccf0b43b038d02aecc33880a98f1d540f4b46ba3660157661bad0588610f5a9e76716430e0ca8c4383012d1723d0f0b44bc38c065c9969a8d1001a6117353ced0240e4e1ca0c001b1e6ad878daada1e5802b730d370eb00187b8f1b49b43e30157e69c191e7073246ed480c095f9860d086c61c3d32e68f3e188c00b8ed76911b0d11444c6f1baaba3b34c37c3c675de079e42944a4ab5c21263d5e2c27a818991f9c53334353266882d1a356c6e6a8037fa26bb173dc81d8fa75d1fb742174ac013f0083cf7145e2091fb83801743e4fe1eb0fa42eecf016117b93f1e5c8c90fb6b40d883dc1f03be1ae4fe16d0ca3d851584c8fd29000443eeaf87ea07b93f04b4c820f7b7c36a88dc1f8f2e8a727f3b322eb690fb439a400b16b9bf036027727f06582191fbd3610a5c8820f7179455c10a790c597e05b83645159a90fb9381c93d45157098c93d45155600c492a2638b2ae48ea50a096c0105520f5b1481a3850c3fde17045045615c0d21b368e083734f4185a31b68b818408c2a04b0f2440f8b1236b854724fd18424773c0178e7f2b0ac73e50821bcebf2af950d99f5accdf96f7cfb8d9c1b356a0c40f36ee822703b43e0767ec0edec80db9987dbb901b733036ee705dcce0ab89d7bdcce09b8330bdd9911703bef703bf3b89d77dcce13b83d1ee07636c0edacc3ed1c743be7703b17e076c6e17606ba9d75dcce396e6709dc1e71dcce3fb733016ee7f176ceb7b3cfed7cc3ed3c80db5900b773cfed6cc3edcc733b07e07696b99d7bb83dbaaecc6dbac9c8d840a41eb45be33b57bb8c8bd4c3757a38906b9424c302af80052a7021d72889a3c08350e0473efef8eb1a256d13f80526f0231f25402383f7462b47ac6106006464140868a8c1a1b1313303beb91905820edb3c8761a82193c330d088c92810b460c497192c242007af8c7bd725039161810adc9e376a5a68563984321303b3dc957cfca2ca3ddc54ee4f4646e6864025774d513121cce905e4380afc38ea045fee9af6709fb9bd07bca2ad6c0212b83d6f70f865e3b1badc3575e172d7b4e553dcf21796c1c6d058b2154c55535465a264e885148b5727fc0282f09593b31c57f3c88c35c9af1b346bed66b5cc23e26122400912452f2bd58b76d50b0e54ab17d54afc0dc29777d58b17365181054d5f2815e5d70da167c3a963431b53582fb4deaa562c031b765d3a220aadd73c950ebc50e5852f3ae69257ad49342dc114e508a52d3425c9af9e82cb86143b905f301d910455e8a9848859bba7228217aabcf02b1d84afbaf254d5326d4ad08e28c2344dd3340da394524a69d530ad0bd6064644d142925a6ba55c300226842b180981054cb5663f59599b82480b986358f3e9ba688b1e3544f812b97e911e779f49e9edb1cb9c615cb515b514cadbaf4e8d522cf4407ff68952ee6cb5dc69d826b1ec5bb5db0776dc96dd6edccd9e5d1a3e9cbea14749114a10048360973a60cfb06f57669be6e91c85239ad82cd3589acd3aace3366b33db988661dfbfef62c7ada4ac5995a0e536cd76588759387c9fd5b4d76aadb4dca65969b59417a7c6acb5d6269124bf4e799b5996d9ce6131e6819c1da0d267dd6d1bc35e2ffaac6a745a6b3bbfb2fe9c147fde8766f75583d4776eb93151fb2a115e47fb90bd36e885fc76e9e757bf5dedf4aba2a8bdfb4c2ff3e6372390b85c3838a2f8af5661a8dd20d434f1db618edefbe321470f9fb69c085f9e0fe53e10254a7e35175e56aa7622801b99de644a6b9aa679b4d3534caf9a224e13423a5f54ab7b206bf827297c7997c915bf7a08769cb2ced9248a1d2c8f86d2240a5580818820340561ec6e5926b216624ba660d282cada3405d315b9d64f8796b38f4767a10927241d4142055c308dddad7a6a73866db5b3cb1457aaa4eba9c3a24d710e62a6a75894d2a60586248aa4248922050539070f294760db462b0e54c4719d865ebd86bd0e7b7debc86efbd617c9b2fb2a92e5acab41341d341ca4e2202c1cb063580cb64e62143c358f3d9d40b07940f0fb9ae7fb3caf793cafeb9aa7eb38ae79386edb9a67dbac6d1e6b9bc7f2685a96354f966158f36058df64afd5d2e6f94e3f9bc7e36e7968df503a9b677a77f64dd63754f60d9df22a52b7cdc33fb464efd672c71e84db2c6abbe5501c26e28561188661185a7b4ff73524d377f70544a638c8066edbb66d28d4c6a15028d4c66dddf5b31f460ac3300cc3303c9d408628140a8542a1c2300ce9e9cd5e43f23deccba1293ecd18473a9a2048d83d9dfebe63180dafd2615372f8ced29cd139b97bde766c37fbef2584e8f61235c9fde59053b2ddba13a91bfea1256f14079b89d46720883df620f6b4ab5d67ffce62229b15a13c4ae5a22ef6cea7a2dc7d13e21786e93bdafdd4bd9bdea78328d7bb64281de661efbacd039966465d862963ea411c69a31044630a376d514a84665957bbe1a039eab977dcbd0c10657a6b33fc438ba559ea767b766b5f94a6408c1482944aa552a9542a952a954aa552a9d48fb8c6d43d90c2216d49954aa552a9543fe21a555b28a4993e29a57c7f409dbb6d5edcbd1751931c4437c83c0b872dd30bd1f20f94285f21dc2ea764fae1e0b2036853a64c09030e1b7e59a4d4e78774f431853dd04c63120b875cb352177090e5ed174b594a89012d6727caf3c301cc19ce302b87ecf4990e3fc85c2f44cb19c59e54992a35e830d94c197c678e3b91ed2f2032f8dd12e9291949e52ff0dc3bf0725b7c180672e7301083dc7610bc2fece07d2886023111fa1d7ac43e1c20f6d309c33cfc7d860f77a07010a80f118d28ec5d9f751241fcda91c1dbd3e927ac9b64300891edafef3fd08cc401d43b733b50a80b4134a2b010a9871813a1f788c829b98a2364d91afe95a8a754f051cb88c221405d88300cc3300cc3108542a15028d48fb846d43d80c2216dcd300cc3300c7fc4358638b422a43b73ce09ce2e041289e769ed042f6864fc256691026d0303da4676159817944c0ceb7d1f3f9ae754f3196fbd3f334a629af66d1b0c14a47b9fa9ddbf139384afe6e2bb2e67ddef3017e9fee5b6ae511258e3628d1ff948e333ae5152872f03ffc8c799c75ca4a38fadd75ca3242b9e46fc918f33b8fc5b44fb75c145b61c8601fc766d9601d6a071d40964fcb7fb76b52c030fa12d998bd47a87676ecf1b1a0632775acffe63eaa09ebd75c3c8ae17b0560b0fa12df10ecd56f6194675c8143d1c4269392194d6d2dc651c076edbcb8ad3ecbd45b40f6584d06a9ff5f1c5c4645f77edeb0f07f6e19039b86d208eee1a9885bb1d467e38640e8231a8cb097a27103caa2b456029a50cb4427bb285c115f95657e64f7e38b695a45e4b91212db7593899571ecc07838552d6aebcc75d560b6bf5ce5d8643e6daed8ce2503131f7993666d3de8591e587343305164f727f4858a3026ac3c28aac21dd18ef322e9c82cab72258ee33b3eeb86ddb4299235a40cffb50dfb61dad3e73e5d81243951833ef420f5f39ce90814ab5e0772a0f2573b7c75c20a6988560d478dc8c4605d4bd72acb940d056769afb0d41c1cab7bddc77a92e86b75d8f25e6cb21738c772aef7489f44df6956f48df646f3921860cfbc409e66e7fb940a8a8e021458c1072b755b619de8605135965bbacb3b05c99592df8cb2133cb3b176fbbe1637c3886ac1471a1f972c8bcf2aeb9cd7620056256b01d42db0532c51f7d937d061684406457195224f5a332a0209617cf637d3beb85e5e23263b90bd2742d33cfdc1ef1ed31465d79c9a21e53f7e565151438593e3bf367571f8e15c86d2b9f0f161f2ef6fb34cb6d9b64610253eedc31645350c343425ca4b5c80ef02133837d608df7bd00497e49137444acc9f384a6138a27b39a651acdc2dbd88783b336b01f13942a9050a4431561a8dde994e258b815efe48228f965a3080b2c8ed00226412d40aa2e40d28442f5e4cd06a0c58ce3388e8322a90465b697524d7616ab9b05b7efd2d971d672d6a2ec59271668cffa6cb769dbf65dfb770b1434c5ec9b0f11aa8042c18fe3388ee3be5d8e66d409fc3ebbc5269bd80b5eeb4e53e84f07cdb53b8137f74d96bd450a952b47d505a2adeca9bb83b6b2cbcf870856e59d4a154d647b69965f6e2a888842d6be1c5d85dca1b66f7ef2035f4419e8cb31732bb178f6524ef45027f00bbdefa35de7626956b93d56edfbe8ecba8f66ca945f3d053be7e6cdcb85942714089e4ea8d3c9cb49a7d76831eb70f5826a9d7ebdf6524e02f8002d41f16e7891587e6239015aa7032d663a4000751d90380062eac82624132368eebe4bb39d3adbbf0fecc0203ad873ff30fae1f8386e0575fa40ee6167b10fc767b5bac2711cd77520e6bccfda6db3a8d307721cc7711cc7711ccb954a662b7b27514b082bf6811225e5776d9779dfb5ef2facb9cb6ab40e0fe2d459c014b3c6b1d76ecdd7bb3577dfd540d409a45d065a478ea0874c1d7934c54c22914846d034a79e758ba967aa67aa7f2b5836e99b4c264141c1ae5c0a3ee4a175241148a60fba2393d0bb724944eb782167cf8600312ff540f0d34e5b58395db9c4143d2c9348254b487d57fbe77da90c4ab90b4a2c1ee1bd0b85f7be87e043fcf0de5f218b87f7ef49dc87c27b58e83b8887bc7f38f4c29c85b0476efc0ebeb2b89fb6ea89c6f0b238ec8350780f0f85b45589c6f7080621a78c491c9e7d63bfb02a6daf3b7035a161895692fb6ac92f54e6b473df7a671edd364f77ae489683cc572be5b09100042979fbdcbefd5524eb70a284f2892872fda69dbc1bbefbf71eb9ee7b8ff01f3662c4e3be83b8694bbe47162739cce2111e7c8ff020369264c4881ee0432c91d0563d884f5bf33d4eaac94f2589701e8576151e1dd117cea703cc128cbea98f59124e3a2f97eba7039dd247383b6835b959d23a8370b9c3ac1cba6bd7d1e12c73f835ff83b69dbbdb278e0d2b3d31451d5a964ffaa67e5e2ccfa3a227e88e1deba5927cd23c5aae97452f5984c4089924d7375d62462122ccf0d014ab58af72040645d20285ec2708e827a8d63a2bad35abb36dc8548cc0cb2d850e5a905fed248a13356caab5d65ae79c73ce39e704aad507a8e27c4ca19de2ccf9c97985d55a252596dc4b544041a909e342a74416842f9a9c14810a3c50a29282706a35cb5eb3ac52ade7a747abb5d65a6bd5324ce585248ac014250b2665f80cabf5263683052a6900235c4d71aae457731576a6396032ad27caf5062884f206a6509e8a393d3d3f3d3e383f3d3f3d343fb37f7a7c7a7c7a7ee8ecf9712109e72715214dd602480b2d1c30757a7a7a8a10444f0fb60295dc4b54206972e28326273e403f3e4073ce39e794724a2a65954a3f800861526aca09cac9f15152b25628bd5a290b29817e82e69c73ce29817e82e8fc09f2c9f911f404c8b5e3c9132054247d3138d24433715c52bae47b6cea33978feb72d219d2d965d7c7d5e3922e9f29a974f9c81cd1f52ce4a4227cb932b5f1c9a2c7e6278b2c286d572af752116890ab93298b706acfcffccfbc41f3af76320f34451af467aff5b3d65a6bad73ce5ae79c13c814e9a30c993aaf76520488a1a9f39258c815e1abda44e16207e5e2c7121542a832c0e9f9f9097202e40afa0972621314f403e404e827a8d29f209f1c573f79b515289df9d556a880b4a1a58d79fa974d7605ed88e2fa71e2a408443809c5905fed249b828d6bc7a762977fd58abdfe27e7f23e1748ca4c66a7545249e5059a22bdac3407995c7d1a87ac3e40b807e3f850fa3175800861529a732afd4c1d20fa201aa5fa748bbe69f7967b890a2872c54f3c9103da447772666be6d44083509e4ec144965b0a2854802101401898f44113ac9837602288237c10050998204a41156068220a4af8c209162cb0718515b658f204282c5002510e6030022bb6d0228825444939618913453041c1020dc626e4a00627d081133c504209511421b0020eb0e8a288055890d244144b2862a2044c4f2021ca8747e048810c4bc0200462a841113c04c1648215dce003433861ce9b01397db0215f64956de81b99cd39b10f35007d2367005a949f5f569fcd895557dfc849a79497a73b338270c4122a5c30061e1c511c84010517bc78d2832d8cf20a5e30297af282112021490eba60833208f1052ea68cf24d23595091ace45e22c20c686e29769082fcca691aa2698818b99786c0045718a5525969cd04c02aad35579c6bc52af5a918f66cc55c3f53aca712fbd0cb79a0a983ad807c7e5aa9522a7d8070cf14a9085be90710215387a9befa7418bec225224021531ca50b2a71a8d8fd61fa6063bec82aeff40d2542a748c9724a2642a74cc912fba0bd88cd37fa66beabf846e38065792bb3ced8fd61ce2abb8239324b5cbb33965f39d9956d5c53942fec14e760d85f39193bc5b0105b6118ee8942f660393d1447ac79f615425347e6746b7ee6d89c55eea51f4891297e85399ad44430bdba6d9d56b55f0b67cb72cfde53a74eb15ed6532d5b4fdb9e5d95eb69bdf6752fdf7a82a4bf421fed54bb210d4d94d21d7a349a97679a477434808115f54d7fce9f66b0408bfa664e1d30b936e99b29a70930d9042b6a1e9a84fcaa4d34911be72ec2da04264b5c69d842286172ee22a4472b7932cd682194af4db0a22f388079016b324469f082cabee18850b4993bae1c2861bd2a87e10d4d84af9c1d9b2932412795147c11e59cbe99a7776699336d9041615ba2598145a7a4c40aadc31fa0a025254b5db8baccbda48449ee722f2949227bb9979444915f22d3096cb05841a701254e29d3d7d08253cafda61b60ca9a64faab206b92fb9f0e702a865f5e2c8e4f11be6cb0204153b6993aaf1a353e5f46104e99676e9af981ae693a53791dfd7274ed0a2dd5688a529ad26c778c5ea94352eddfc524b6344555941ee05295f2a1da272f65633f6a400aeb31074cd15a6b5f856461ca455b99901f407ecc1d397e394420cbff002244c33ea07e3d4bece3c79190a9f3924640a6cee9d987482317ddf9d1adec7605bf6c9872e54c8a1ca01220822753eccc852a53ad6cf7b6abf272164e31cb56b00aa7f0eb2ab7b73b9683fb77f9e9a057b964e5803a3deab4dafb0af3abb978d58c7aaab99a7f4969b3bc968348edf57a59a6ddfa225816ca300944f342f57828a9b1d03cc543f443f3444d3ad6c86acce2518fbdc79c98d546e62b66f57baceff166791c7997fce545daeacfcbd444f8036e099c4eb84196e5b87ab6c98439953042f684252594a0441319cbbda40413295a5c51832dbed0021464e0852e884ee00525902085214409c210c67e03e93134a1a088221d0c118512c6453642092ee8c20790306232f6db02f26d8940c5d048c822f7d848c8f28d3384bb1dbbd9b1eef56ab7692a541802a6a3332625ae2eed18ce9962cdd18e69b856ad6a5a4f4eadaeaa6119566badb5d65a5f6bc52a56979454e045a70412ec5c6677ba2b3f1c56d629626f0d958010486c73e19c29f6c85b4cb3d6f64c11bbbd3918e6c26ca665d87b300cc3300cc3b00ccbb02b744db365d8e9d06c61ef23681909f034fa761d28b6a1bec1ded57045f89a46598ace349a3a47c78832ed1e7ed9305cad7e511c6a1e3063efa617b3249cb9ebaabd8ef983ccda3fe93df319d237d87de88e1db1030d691e2d63b7985d1d2763328cbec1de7d9b4753c430179969cf82641fca241269238a103332c21ec3b095b5525e8904cbb24b4c66364332772496467892608ad85bca6b1681cd226611d28679ec5484466019966559964924ddc28e61198665f8157e6050fa01648a4aabb92486dd5e3f934c2553e784ba977159b530c9e2e5af69c4ed7115b324c41eb324cc668e4fef4386780657aa7224c3905296d09e8862e2207515251ce4fab9a4752492d94cb25192ea473edebcd2bc7e2ed13c2b97f1eabdb2c82635f8e6af79b444ae46349159a8344d0952e90b02f879d76e912cabde498fe6d278cdb5f9cc6d1ddf1a5fb9da279277913066cdcf9c68545da41997317321fc199a63ecc9a8b98c138d98358f4f341e7d9c81c5e30b891f9ab9f88985661c1fe321fc192752a930d28cd7d49c68a4a1719a0bd138cde7696c5e83876a6ef3219ad338d1882f6b7e86138d33ade30bb58e3f8ff150d2c442353e031ec2aff1a199b74e348af7e61a1d7d9c712953946153e3d2b0ad5bbf72b52cde19771611c1642e41d284eec8a6244bd8ac65d5ed2c9bc8f052589240054b23a5d028579a9ad70fa9a19939fecbe69acbd22ed25c96867d10a279cd6bf0d08a0687e63de2bf441aed3dcefcb50a8f67be7fe6c61cdffbfe40eddaa62df95f991b766b3e861ee6764f5ca728956418539422a314dda9648af52e5736512497b36e53ee22c5f87671cb3dfad8f2550b6e7af43106964c4c96b496c1dbf9b3b91b5d6e8f1d43c37309a515516aaa0821fb084152ca9f29ae40993adc549a3a53cbaa161d2d1e01861b597a6cb93dc2dc1eb5517e3ac01cd437558b5912da9cbacb7bb4fce5a9bb9ce526bdfbc42c1c6612963251ee1eb4a35e86512f9beae593fa956bb47a8cabae11eb2c87b946aaaf787289d55d9d7593b6b3dc231f61be7255f7e823cc3b23a638b398629d5ae079c514ebbf7bd781227cc9a62b5a473671a2c5fa9984eea85e2f9fd01dfcfab9d43ce1eb67135a59c0d7cf24a60eea5532d15613ddb9af32af471f557fcd25725d527a22ff749f2cbb1aac085fb2285f36350f1199a9d03c2ab78b64f9243f918e8eb4824f1769e63567b92bef41f315961b89390d7e12f81e2ca7390d36b27296f7588359f3aaf778f47106d35cf51e3457cddc48ea34ef3173d555d848cb67de63374f278c34f3bbf21e317ecc7bdcaf60232bbf8fc1469284567e6f24e6f83dca5cd6bc8cf7f8cb9a98c5e3af790f99cbc0465a2ef31a6c2449a8e5323792fadf23cd3dfa4873d5353af291e6471f67661220cbbd32d8fe366999e6cedc9984b6eaa5134d9ea03bb38964a23b5309df1eefedf1b74799db234a934c4cb99e45e61a88083f2c9960a984be5e1ed19d98d7cba296942cba96b6ea636ed3d45b58f362cc654dec8390ea2b5fc1432b158eea3db6fc25aa70927d8fd62869ca03a13baad7fba03ba9d70fa9d9bee5ca26da7a22a14c236612534c72535746a1adfa953b8b68ab1ea6fee5ce26b455afba4deb596ed316eb32c9f52eb7692bc60d62c80a4f1dadd35d5fa968b16a99bbdde36a64b93daedc1e55b7c76db4782ef54db5d9c7259b5c2aa2d34481a19fd1f6714db16708217cb9b087452af6bd7b07dfc33b887b7c07ff1d9c180747dac01d47dca8fc0e30bfdd8543e422ec2504a129f7129cc8a2ab6f6903c3afd99f4256f22281d8355bf47473d9ccdd9636aafde69a224d0ab567363d33c32e1f17e683613eaebe3dae79978fec76f934c699e2ccc2aee67401c10679d6fb794d5c0b3a7a6bedc67def4b8efba6b5567bc67df3b1c336b17868cf2ea461234915c3421c16b191ba35cdceeb3aef1a0eedf6ec46be6befedd985b667f8bb867fba63443bf7fe777de896dd5e28bb15b5732b1c6c2449de883ddd31629f5dc83ec3120b6dd770485bb3db6edbcb92d80721fb6d685a8b93e47bcca2d4a9858122c91588293e31451c6d73bdfc42f368afefa695604ca529ce287d534f8da658ef33e911a64553ac3a50d0a28cc9a2790446f380b99e8649c8cadfc1cfbf6811dd69307610852aac308621ba1065ac57698194a9c3bdd6cfa34ea42d7910b3b4a10fb3344d231a59f2e189c6efb224e81df4b40b36f8cf7effb076ef4423a761ed43a2878742a229c1ee1bf9cdaeebfe099e8e3a0985ffc20f7be7b010f8fdbb3e68ab1e7577dcd3e9df392ce43dc443a87ba71f8b07087add245614f8f9fe0e5ee83bf8590f0fe1d056fd879bb666f7d39dd3673deafa049872a8a46b1a277b20640ad10082001040005316002018100e068322a1400e4589acce0e1480137f9a4a5e3c9709e3418e433108a230631021801800003006c0d0c8ccd44a002c65dd041ea83b2308c735f364618eb383e89ce1e02d893be5d87992424f33ec1546d066acc7fdc730d63f792b07f19e486d8f8975b7da02038610a81a703bbbb4b4d09a41550ca7b0f45d61668531d8bd72f1185b83291795d18171c4feacb5519f8307d99d8d003b1a63a47f180f481928379017936a5dd81dddca24755933f9f7cc0084083255281776248218ec974ffbbc99f69bd0b24260dc94ae21e62309a1332ac2a8756b0e2d8957cfc7fb4e0b6e3bd4baa95a77ddec4395a552afb66f7b1d6ce6ba3ae6a93e476eefee046ee93b516f4971ef5bb0eed8e4100f3a2a9469f30b0c0711ff8a482586d9192b6b3101cdc50c8ec2920c2ac8fb7eef6f2a5940491e0fefc1cbf2d753ff08516e6a7b81f112b39980a83a5f10481418d5cdcfef5e34ce826fabba8bfdccbbe20e79d3f1c8a8ae0db05b74b69976ddea87349214b4cdf0887f45342d79998b234b2dec0cc8210d9996d4b6d10fa62502a580c8e7148b259afc9f099669ec19d7d506d137e44a987d455af236bf1bbfec23667169b994bb0b254a228f66422b95ed16658e23ddbf65747592ec2b61895e8ddbaa110410459f827995c8950e025c04175d1ec8ad316ee9b164f9006c81924c91834bc99bd554f0fd5a432d8c76e8ee3091ce99ca0348f15586ecf377c4670c01dec36ca0e8cc0d786db1d34243a1fe854239ad8f5a5d3b32ce656ff466aeac9640081e7b2fb22ba06f3492be069cd984f3e501a26db07f156c8630fe8d9366b6b6debc38add52eee4c3f172765eaeeae385a860b92959483c69beef86170b13402f15219df76f6bc8c8326bd1e6d9fb65a82e05f25e97c2a9691da5408bfa53299f4ba1999765e4e2e3cb339679f2f16587d014a1959249ae3e462072b7148f3ea1b6591de41ee8ebdd282c9ead76c0d6af053ae0a314be355ed18314133fd2af0b9bd4a94fb54b2e9dc7939db1ac95b4fb5106db533859c8699ff9e10dae3d199590877f451dc69411bbbed3b957d8e16f0025d54c1c66b6a36ca200c3c8799ee46c7e337a1101f5e007c49ea6b5d4ccef4d2c51c62bf47e40d00f1be94db968259363f1f7ad6def77808f11a64a888a60c288cf18701aefd8d014e69c8752843a5227b154d27ab9a3a1b70733474562dacc8f76af56b9b15d25f05df375a6d01646adb497dc18c55fe5b5c5f4b4825d1bc0a5b461b7d2a2e2e539cd10d277fe32f3cc81c9fb9e9d77a49d870fa666a1a1c11b43ea520475b3b092a37269c1bfef91159d97c9838e50cf38a56489e7035d48104445702eece41d12e30408be05528da907933717341ccca5af76955d67a67f4077ad30d5250bd5e9583b68b46ec106700ddd5190f8106c5631347a001a02500d225d1db5c4a71f1ad35f8ad939f06d4e6080bd9a8d2bfd92bee95b6e6f20a9299f29dae41256df1544835d85fe6a131c85aae022dd5ccb7a25d026dd393d1a89124a92ba51b560346520a29253fb2c0c224258b1d747a0cc741933ef0d02b3624139907ab89b90baadc0b609364b8ca7c55d7ec80f590948cbb4fe8cccbed92a25ad4f74f520e805b50912847bd324dc882610b25fe772e15e293427e967eac6a27cef7f1f62de1ed22499941e072a50900f6d43dfd210e5c1c91f63593e7c37ecbc03b6b7faeee63ff87d39d44c4c61df86fdde6a71fb2b8e36b150ddfd3d31873fc10e3845c6b4a08c606a8c248a08a67bc3b1995c284665793929aa9ac17deb02a071cbaed4996f12856913475b29072856e168c9dd56f20d2bbcfba1441089afc097deda5e16d4f2cb029338872099b77a099daa446909fbab09f61f9ad0555fc987a7424e669810d633f07ebbf3eaedf83dd92b36588b442786176e45a04ecec797739d0e6e0798c1f825a3d56b2983b590e42d31da286e17ee71324427199f4fe41f938236634ebb96b394398001204a998546eb5eefe6f825a4d5828999c1196889542bc9c30bf1cf224bf5f8a1fc4768f7d6214843d189b918c6e0f7840c5866ef3eadae8317c60afa1fcd82afccee472b2747a2dc4adb666ba92e490c2d50a05823feb90d2e2491c12646bd6579c91162582070123a811078c262839a8603285e2f9d0871218175d13d19c108c9168c6613202f2f52e50545ccfa416c8e27f717b087edcd84ddedca25e4a92e451a1b856f72d15bcf1b0e76a4404017b0fcfbbae4d844e77093b0f807803bd9435bb1346b429e761417f9b21dd4bf916ebebe788684a75190d8ded16b1f6b7ba456455fae21dfc1d355be2ef69db9c3101d9b1a5c29979bb9c7f7e8de125fea325c66ce689555ce6f936f04ed3cc699fd32c432939e4209bc3f3347512c1a7ebcd87e3ef5249fbcd8edcac926425e6a845386f5424ac6426d5b047a62945e4a17a72271fb0f7215e43613840c254a73b974ef3c205eee795ff454085907167e711e8a6dda2fbb9a1b0d6ea24748d8ea0e6c987e730288c81c21f511c0977b4ae550db7915bbf252a7b0de300bc602afc7d5c7a2494dbc39c64486a64a412efedcb37c8f703acf3eb848d5ca42bc13feeb302e5029047bc7a2ba426479c1e1a6fc65fcdf90b8deb9cc199cbdbd98f4c95b861fde76b99eedd482ea3b407acb3dac9c4ca027771729c12ff14699ea8f827dd504bf99e592981916c39b10c7755130f0c5dff71c7420e1a0160d39b7da0b90db76d19315640b40945d4ceb0ecfa8733cf2b18a4d81f20df4bda6411f8cec0c5ef891149aff4327f52dd0d2b44c77932119a38482683cbe195db621e75eca548db2315fc8761643819127b238c5e95957471d9f692e715abf7e66ab77346f1de3c2b28a2224a22695911c1ac251f099519c42ecd6e87136d19d9cc377b0c0a38c3c8d736bd6ebd16f509c4c5e1d6fc12a75ff8a1534a0a717425f53a7161b4700651981349cdfb4383e475bc393e9eedf705b2b5608c261ffeecdd70681b91e146cd890e3d55307e4f48f6fe5de0167cdb49bb87f1a4768838a71a6943e79994f3e6b68f9752194e19c0910e2bd74bbc134abb556a90e12b2abcf962db5f9bca26aaee0233858b52363465525eee825da2dcaaf1ae96b39e6f58d3274f351221e966ec2015ae0cce0341e68efe50037385ce872451ced3bf05dcc647121b5abbb982c51886213acbd1ed18cd8a7b5e64f4246c2e2e63ccaa8a2dcb7e096bf540431547dce602887f3b060d762638e968ab5f294a191e847b16403d7f8abe42e22380f205b1f42aa690dac486aef47090c4ea2e34e82751d970115f7c98e420ac404b2cac3809317f79524286acb16ab6882a7ea00dbfc5b757b98661b20ba6a764636221937d16097eb4907178f532254b19b0df7e981aaa2c364975b579182aaf425f418e9c6a3f9fcb00d7b80186ab3238a61b020cb9937e2a68953007d4a5f249a4fac27669c1742d6ab54c6aadd248462109f7cfd2b6c91f47e9c7dfa04fd644cfd00e0f72cf51440106e3838235d017e33210270c58c6727c1ea419cd7b593aafe7fc224b60d92ce6dbefd4467c14b46445606c6d350d03db69f2ecb133e5e0e75e675249ed783c09bf0f7ec7114c36b6d5010418d07b4c61561078403d05d1172354dbcb54709c2ca970bced56a429def50a3579668743ff8a657509d4d2772a3d2dca74a6f2c090869a09769cf34d6cc9b1f42a2bce795fca00070a600b29d711253f362ac9b491b8bb14c3935851914f9276060fdff20ed1bbe6677655c1e8c25df96149df6cbfa427d108a9cbefa1e0650d56d431d1dcea367df3de3a46e688208054645fa264ffbd5ce4f1e93d324147aeb597e3600988115a6fafdefd3041976ff62248e814edc07e61256251f1a59203abd2f47ca9a305b0a6fbddeb062ed1b48f1f2d688c8782cf6da61065dee82f132fa143f0e499d9825468f0e27aa70c08aefec8fb6eb481166e7de376d16a507820d06545dc62655af9fc2db498522f6a07a33e3200bde0eb94d48ac74b582e5c76891241775aa1b80375d3490ae526ac7fe0d03d4428a6c07f4764507ce14b8da1f00f7763afe0b3f61600eec22b9e75c175efc2d7a9a27401b36faa4026a289014819a61dd847531f95f53d8fd856b4a206db52ec134ad8c7a1872a6dbcde2d8d67631b5ab94331d63f036191402274763449b8b4dd5037d142d838d6207aabbf68546bb9b4d9b42e96311e06627ea809343f6790f6bb2afe5544142b149efb0f1821dc546fca108af61ac02f205206813d6adb1265c6270a78ddfa19fcbf55a84875adb7be3ae07874dc49b386b2fb9c859e6420492709346dc90bc161fa1c5e04aefb4410501427cdfe9f1c1cf530af46cfa7c50d4303bf3f60e57c51efc207dda0dd690f71d30533e8299a1f3fa8d2d9c82eef3b8cb4c9ae130fc21a436b0ecbb02355f16bc250ece3f0d8199f5b5ae1226ac71223c2fb7d24edc80d108027757068e4fc5e4e9c62220ecd0d2365feaafd47568bac33d742a161da93749bb3cc0b8e0dbc6a97876c3412f7774469a3d0067cd91a04c5d935f4f63606b738f854a61ce6308e9f6f0ab4cfb91cff06af9062889b12e8481705c4b1309036e88064188a9235571760d3d9100a2e7496290d2de215909a59d915c80a52d37bb6f5ddb3d206e7bb42d07673559ddd5a8e02c5f955bd035e4eea3d6b6e61b8a9376d3db6d6218d4e8a0c9df1498c0a0bfbf26171c4cfa01de43143549f4865b05aa479ca3a2537390dd465d8fe6a4507c57e08f6ec09dda52460097b008d94e0e5604d48f1ad4a8803d4ff81ab2e560efb95d95c3a5e717bed480591c335a4fbc01e68027c25bc1b80cfe2956e3ccbb8053862e647e8eca6e9048799449bcb356d9538f1e3808d0e4a9d7df6e55a2c6d573e7c68e95968b01e4ff93b100b96745b344610a1d3f1a33e0ea402ff2484a8e42ec66f014502343b4ecd7ea91309dce5d36d1cf00954e3b21218884cefb38e165f8792cf589c8c9eacc9eec721e5f4423506a02f99ea9f3382f2c57799cef7d715270e568276a0f968b6b82b1871acd05a4ef5f4a94598811083bb26b1c7766f08530c496e90635dd045d9b46083636e9d714033bae491840638e5a9f814bb82a807d403daf6939c810d350845e2dd7d3dcdac3a8881af1b9b55e6eb3bbfb941be4fef7b02488a4f21c40179eabcdafcb9d60dcb1492385970f03a03cdf2761a94618e81c633188c6d2c33f88ee94087d874d005c41d3f969747767b0d214c05cf96ab141c2f8fa6e6440f1e0b0c1e4652bde956f88bebc699ded1bc98c03ca9e259b5baf92d96a82557880863928e9292b8c564f586296094396c2f1696c92cf317e9a6171bed72d258eb9a447d636ecd532580693ab721513a37e6ef3a13322e32c88166cbddd36623095f85ff2baa6dc22b3028211b112069323a29a011fada08194fb2bd78fa5be631afc50b8ab33df24796d3a778ce1e9ec99651c515ba2714c16d61b79a2d7cecbf7a7fa4b8ddd243fcad7bbec56ef897308ad3054459ab906adaddcf3696746a52851ace3081c3b136cb7ed7e54708b867a1f72d32b87507a70e1010a4039305b3a196b74a5a079a13af8c7fc2fe48f848fc0464a045c982ea50fcd0248b85087419d6f14bcffbe02c5815612fcd2cf1e586312c33681b2f18576e6b7a28015daf6d5acfa8e44775c97464a633c779f28f9e0fc135d0d15ba63bfa65f1b72f526a690c87d9a1ba47c9f905255b6a022c4268a0ff887979aa2279516d6b7d03a30796d2c89b1d9e8df9b914417932b170499566cb98f3353ea723ebe69b8453e94b802980e2ad5dfe543b24b11d8515e441991b28aa02f6c87ebc52d520709e8cde6ac8b5b5dc70f44a9a9b969488f45a8d3459e4aee655c6cd96a5c023453b24a15e73e85455d1681a6d2ebef04149a6e65000592ef8f06c3f0f1b8a3be05f12653348b44a49f925cb44825bc318e3c9076e544347747899eb2aa23ee7a58b191ad73f03a9e3f25f61190d1746c658d59acd44dc6ef32926f4902290589ca18867c15c217df504d750028638aac618fc8e629571908804f7eba38bf53b5ff21f8d5f1743cfae96127a4d8d249c54811827671d0e00121b11d199b328c53c822169b80d2a3b490579063dab849c70b28b50d8a53cb9185ad547828fcf146e27ec1b3e999f39c8134d67287f930b37f976080379d5c88f3c1bf84465b569013472f600d8ffa9c3dd69923d192fcfd1053e59e7b590cf08a3256f01e4e5e9070fdb329f5b6618c53841e4ce87b15120b1cea3eb7c67668f74e5c96a04d44c5b74b9f9edc434b8dc1d714ba6d358e7ff48a950c1332123e5b2e846571a2faa6d42c3a8edd9609897a04e88d4a19640b746c155e77a332996a08888008b06ad988870fca59fc1802247b25c09b20ffc0fdbce4b13fb548a6c14a68a590be0bc606eecaeeb7bd3cf989fe8d38a5d769b40e8b1ce201c23f17f057c01ea6cb747e2c655d2ae7fe891403d71a68124da323785c4a2a321f9db972200dc5890dfc566b4e83455635abe4f13823f71c80e45dd091aad9341dd899e959c74b9f6d3d3263c251ff92827b6ee24c14ebee653331368d961f0af052183b1354910b7d31ffb76d2897569cab6921599fbc54bc980bb3c7f8420fa4541726621b144660611df8b828e8ced6540c487b0275699e37054c52b3f12be37ee2a825b36f5627c0aa99958a63b7073c49d5da1e0572127c3abd97003e8864465a051fdabb8c38254751bed478073192bde038597b32582874d5aa5935831e1e8a2b561586ca61da547e9f1f35194a7414ad90d34bba681d5e671e1c066fa034a8957d40398b99759657fe67a53c2370fe86cd23448c81a98dc1192a7ea06a9483d9681de3f5a43a10e68307a0b77588fc140aef301c59babf091e21708db785fed0d99363ff69dd4aad16e4494d5696a2eab7910ec70546f75e548990bd769f725339b81e2eb408a0b166601a4f302e25e82db5a831070484e8e9b35df61587561439f8949feb5809ada43b0bf5622052d8068be5cdd20fe0e052f08dc2a37f6a25701ee978364547223b95a87594ba341913162ec5682f874153f43ee93bcdfd5dff376323944de596b6c67cb2c01675c53f2cdf89529af70fa52e171f80b34c7b138f210ff262feebed9a356b55bed9f83d5ce8ad2478345ca8b761bb392d02765f82494406d4d2060ed066072c04f55cac673935c500c49c49bb1ae4423fd9425df2f36105474b7a4c862cfad34246cd299987cab93e61767a2510636ba9e4f59d249bc0dac773f37b04fc14f244e0bd4f30cf314ebbf8e5768ed92c1c7b9e2e42288446e3791bdf2c1fc031a0e3e4ed5b3001fb2211c0f02c399087878eb0c4bbc52bf770034684c002c58caaf75af70564a8b7988299cff2eee35607647fe4d1f087dccd82b2b003f3b38c20ebd11f8f4be5691c9282a2e4a762385a3482b33195d35de78f42bd8c9b2851c5f05e67f305053454f762758727de1cb3f610540efda703328e0013139fb55a01d2912b2bac3ec85b9edddebccc5e5c81d1244ca3d0a0f303988efc28d5a045069ada140ef6065fce485c3a57b2a7ef624b91493ce65b77bb83f1df79e6922541ff6931fb8dccc8c52778b73e2c556829caa5ef396a273670ec86ecf0141aa49eb2eba6338cf56ce53bbc59cdc81dccea8d1236d39696bf8cd781484a7e325cb39b60f4fd81734a3680621aec0f3ec25c337bb34a31ed516c7fc437edd92ae9c2d67ae9cf25fc99f251d7450d7c0d283e9828427d0bdfafa64a8d2bf094907253b64132b77a4e9cda3dadf089e70675da35bff0757578f3349b748d6fb8b61b36ee3e662ab98cbd12792d623f444d9a2e04aad858288b8fdb6527b26e55a2483bfe7fbb0b37f62a83699eedf5703dfac6d0821d878878c2efff78ca4f35aa23a3d5f39ef3ba80fffe756d1b784b667e2a2d72312f5f885a1027b45316902844a45dee201dcdf64285658baa847a25751f3bbb465de7c817064369e36629a9e0203d2bf92e937c05487357c07e5de84dfd50140f3c97e1ab891d33016a6d3ab675f30283498ec5be96e3b73d408c25de19d136b95736b565980081f0b94309f0913707e2339f0148be8634f7dfbb4bdeebb3a08dd88adb915bd26eccde393ef53a758f45424fa172656ca40445f4598fa52f22ad76259dc60b84ae6ddeeee3a3a391e588f8fa7977d702b9dc6e84377b38de729c81a52703db177b5233795fe4047c6cbf0e472641f5a3af955a4362c44226fee3a94b34d9865d1a06d68f0962216d4551759bdc2a3727a50451e87e81fb624cc2792ba6adf222f07cad9e327a549fd03986a069aa16b10cb6cf2d635a137259460f17730f1b8d495c9af34dfc0c00841fd1fc12179a8c3788782ef19b2b0a08dd84b673dabc8d887d9dc0bf1f812a9d979884ae836640ebbf5bf286142555d31ef225cbd0f7ee8007575022a707f6d5e509367d62f1ea34d92a65075dbfb3368705d09d34c9063b9519afa331f02c00ebd6ceda9ed1c92ec490988d26508fc13153f3a9084a593c55ca5135032cebed1beabd130572bb286d33538a0d748dc0a44ed023cf5cb8798f33353f670e72dd6f415c830fadedfd91418180ce0fb931996901cfbfc409192ffd888e78ba20e3efdf681e4399bf5d86fc0fd34be9e06a478f7dc4d3afa58e1ad463bccde5603e992ac5e08161679645f060038188514b73419d8893d31265a3ed0d2499fb5328902b6c2406562a43dc552ec020854e3843303c7299fd70c543b9eedf779452bd89ec89f38e9dfe41fc2b47b1e1108e32a002556523f083362491e47324087422c0c0ae3b90e81d2f683e0e08197117ea7dd5ec9e90e2a1504c9771867f8fdfbaf222162d38ba60ee7f282458cdad3f56e8f9c482629167e64bb4113e970a8568fd1122911d4960c3d08d91216420f72a0348942c986a7c4d24b35f053a53457708854bb95cd10348c5a529a2d53df38dd440a08d57b52c2e67de1aef2d231c0d1fe9bc0d0143b88540a3d3251283e59f3298815d2e1588a90335568a50f85cb51e5c95856702a609fbd417aa311db7b5e50b0d8c8387f4828af2f7d7c92670629e808989a1db3ea050626536b4efa83572dc5c21bdf57fd58a509f845b3193fc9a7756b0816c9ca0422cd58d4050eaee09260f66d46923ebaf037433da44d6a5566ab849fb7c225157bd487aabab056c972cdf787b0c6f6707bc74e66d7e60c0140f7f2b164fb3269bd7b798337a1343c533f0231ae3a105e587b65541831456bc95b5710798ba23f069a25ac08ba7a998312262a70ccccdbe0bb3076ca7d6ac58571aa182e6228769102d8aa1bc2814718130a62648c68bf8a1bf308fa8664fc490eca53742cad34fd8b017b8d0920821ffc94cafae3493158046113810c058058d117c8ccd918d0bd180416fb7f3836ab92282de3f9014847bc53c35e08ace2973d45ed5f219cb8297d2922540090593b3f1165365a47a61505a939e88da5e8ede378ad366fc5906ea395fb72edbdb5315c543f820002ec4016d45fbe48dd6e0f954b408ce48d432799041878b9c0cc0b84f2882c2a720d502b0bedb8310b0bbb8c4c5111f93a299cd433c74945232ca5fc6d666146429cd938487cb6f662d037c8fce78d229be7a0b7de41b2c87e69922614934fbe2841e837691d1198cac4be85e47a27f514746f4387087d9be411b32493a1046e876a57db8a9f4ba7bf2a21b321943a07a000eca90d5ad6e4bd905d428690648596499ac91174e24ced6f4e03948a9a0cf20dea612e664e9c6c7300d4cc680951f3af1adf087b1f0badd715c674e33b90cb48d57565a3626aa905992b7de543d1fbc2d700d519f00374cb9f24f9bc465fbc2f125e4a143f1b5462b934ba3b4eb4c71897eb57990bc4348936069f643bb993c495eb4464e9ce4d307d80b43c3544b6863f384adab62b5a0ce23fe7316934b42e39c7028a469bf09cbe4942ebeecc0e70f8783e85b062681dae7656622e8a415530a57edcbc90610cb8ba51f6c00925972e75087362a78243382a90ceb91ac0defb19bcf033f7404d08cde7638d749877c0dc6e8123c8256953c5b93a083ac074664a3aef32cffc780b154f638b3e4522b05c36e5e3894f20e9b4a8f42f1d95640501cc6a6d18b02f88fb422fdcca874792b3e990289b870c9acdc359a6cd835a531ec32e9ca9a07d6ea8244ba30e32c41978fd11709be308d18efbe258290d1bd1bec064569bd43c233e22f3e7c652c4e38adefa9ef6c3462fea67d40aa19d7c381416d7efc6c68810c291143a4ff17f98c2a88bb64fc881921a3aa982f2048b4adf6bf689114680240665c0b44d9cec6ff97c8f2dfff50cede76026ebd3fde72e46dee52ef645fee00bd00aa239bb6586b6641d44376190b6df1d4e8d324f6bb427e4a7d1a07ac90ded3e4f9d5e4656ee8972560f8c3cd59abdc5d089686dc5124ff3eb58119320642bf7eb3858fdb8906fe222f8190f8c0c1a3605f8892c60e454d79624e7bc0dffcda84b20a3fe0ee56936f2deca16e7bcd081bf3c9e8cd35f54ac4b754d3dd2c8d521fe49611340115b42a3665a4e8d246c4d937918cce40298712df09077432fac8a6b747c89798b0e3fea5efc368f46b43d83413b019c62cb8319c8b4f56d7a0bf3ffa7cebd6202b1da2ca6bdc296a1dcd758f841ce58a04d76049362542e4d21b83093823adb341df7c13ea334cb0177c591a81fb0b0219bc108bfcdf3163fb14834f19c597151f1fc749e17dbe2a2ba38232cce656c4dabc50505c6c1ce8ecbc772eaccb8491f80054bce0ec627de084c7c1d8eed2e027d60b715c567ea37a064a1a219d2af8f55fe6a7664cedc11c25ca8c13690f6d4a62593163cc25de10b3b32a5150e0ee0c628b07649a820eab595003a58ba4ec0c1f73aa4278c79fff99839a59e96e7e6d2f6bb9be2ba2d72075693a99a59555b488778777f5855c8268d4f783155b31224054bef0b3f1c0bcedd00a2caeff16995915465b3d22ce318c367e1ec185ea7faca9ca9326a95999fd967a98a53dc60b8f3be27e2128a947abc3fe1b1b29eae227c18f70c6394290678531a26b0e7328e5292dc471906fba4e2bbbad6e9d831efb5e91968084822334e0e28c63cbd007d66846c72cb6b1d70d4d3e9e69ee70acc37cf0829c5f22f08060145b81c811dad918d3ed001eade417ffbc88f3a9695c068736b6425fdfbcce410e4482c3450945ff9923e5af661ddd249cebfc76426d95e2cc22e3453f14d88954172c731a8347db10cf08f077d81a5a0301224c09f060945b223172c61be93a7a8f503c1ebab3085260e37cf7ab574f821b058b03cd90372bdff837e9b016d9040a037ca1a0d3b51c9a4683e09bb28682b2e2acaf865e413c570aa5d70bef9358f7ee455418111cda2bf3ce15f4037420942d6c0fea3ee610149e426a43c421356430d280d190b6fcf101e1af650aa84ce49d108b6e31a7160bf43f680853460904aff046c9712c642646055e85dbc2ee9099f48db546a600e8cfea1d8f95e3f15c35652f41e261aafd41053abe55f96a2ff901aaa2f733be85eff895ac15c8dbe23f08abad1e3d2b1c535c4d9edc06956ba63aff0533d1f6347927738837d70a83c713b82fd9749ff990d0e72dbbb2f0817bf6dd5019a6daea339ab585aa4b666965f4ca29d416d685278d1d653edf9cf38d2be134c4d5eb3692c1caa167c3f3a591084ac4d352f1c602ec2351b6184953b255b9049ce7bc6bdd44355e042ab8952d503896c0011a3f61012a7b83fbfcc2dc597db5c60b5c3702dca0a4f5d52ab6474e559adf0e1cdd6f74cffc4ff4808432b8868f40c7bb0319b6e622da1d67ddcfee8f88a5c250ce6595eb9aa15e46d8af82c0a7d12ccb4961f71683aad2a1ab1aa5a09e6a3710b0a555870acb2c251cd292bd2ecb35b46e10515996d0783fabb82db59ed2fc45a5f69820087e5d9b2c1d39644121735ebc166ebb09ff7719eec1827a6bf518d62930965c4a66274b79c59624b14d54049a2e5a21c07c777ee968c2d298f0f2dabc43657bf0f4125b610d52e3e5e503156f2875789ed8ee4035b832c9203f78681445895853bf7ba3a506f8605081148d4b0fe803d87ffd669f877cff51036da7273d1ad6df22ea8d13a4408bc20098b7615eeeb968688aa7922f3921367d2288a47db71f694666f361ff40023931d40ab835eaefe46fef5180c9ce155ce39e4aada4115ce7ed23591706b159887b040d60228c0ef718be24af9417ab8a91df82a15083196f93f3a0a9da0159abd7e6b7c56479c9ba0bef692465fdce925124da45e67fe5d19a2860b23478b9b476de912089fceb0b5d39f9c68d85c15fb1b36829801be101156eaef7b2eb1f9ec48ed078475cb0ab92852a0e1f70fd2da22959d571ef4094ed29c319a2833aa1101bd03292d827d62ac80288c2777b9ec3341ed1f001f9c0901aed5ade0629834bfa060d2536c1d84c77ec49fb6517925a8aac57e793cd3b30412e3f38715907d5644ca1a7d617e702a5ff7082a6ac3970938d02c5c3b141ac92a2aee7a7abb4197be4264193042ce5c541391223af08adedcd08463d6b5f39b1065b0dd167d24b62128c966f5fb74b01709d647893bf128116c20a2c077da435317a0359d4127a730c1e93e14ebe5cb9076be301c6ab90cdd6c0a91c8124e385868333884c160734a63944a9e6dc64b7fe2eb71fced92dc9c990809bb052756a66af59248c75a61b28c85bc7e90e78457135a53336271188030d150a239e67e74b3be160a901a73dc564d6ad6146459acbc05e6a13bac9a577347e35fbd484ba3d49805b4e4a1e67b2c897159cd484fefaafd1d136d8e4c9d1ef2c5f0178e9e4ba2e54f0f801cef0a8659ed8c4a269ac3180db58b949249cc523340283ab083458cea6a050ff2c8bd7b5a16507e2fc0d8ed868bb0d8417aea05f65899c92881b3f22a8714e9f317d0aafc01f7d0147c76452c6240fb55de87f147997f64d32809edef7a24eb9b5017d941d8f57216c4d7449800672b2f63fd7f6f2d8aaab0edac40e05a3ce7e2bd6bef3d6cf5c12a6c32c067cd20e7457d884bee1fc63615bf7653c12d1387ae02763146d0a953f71c7bc0bee12ff9f308ae1aa101cbb1a36016ac927811c8be7a7a93ae6866a426d0942ae66a99c023db1b806d424866ad91881bfe29f016701f536f3b2955fc35be3dde5a9e2f0fdb3402cdd7795b0fd09bd2e5b13f24c9674173dd77fc86dc233ff0e97de3e603d2192db3dbc577e03363111c1ea3c08b5147ac37da7ab8d33f3401abc72a77bed5cd48f95322290c4038bac2ecf1afa143b918aa294324d9396e2cb89d13df16474cbb40a23b8eeac420f9e1e23ebe9ba4ca083dc3427099b266a77cac8d21497b5b81a0495aedaab8708c0dde96a0b9ca2dd539320ee96d7fedaba23acc805f12db1fad9083906fb8e2cd0a081bed71fa9d285fcb8d599c5e82a9554fd366936f1036042fab798d2bb2decaf863b8d23672d6802b31da34e502796d153a183b40bededf2de388c844ac415236e01100a98608f0cda0aebecfd68b33841716105b120729df3d0109fefd8ef4d26311b1df4f63fb37927bd0dd191494400c4cc56d18d475a1f201a4e1f6a6c80b0c411cc172e3005732305fc460d333d680d1ea43416aa56d8c13c8edd613af0caa9946fdbec410361ca699faca9a1768ab65ed021d905cdd8f284a1dafba0095e32a100946fcba3903699c1f3b1010e327726aa5971af683ee49b089bee4c5a6a0f786ab52bd8a3b29d559e78a82463af18ada2ac1a29d1fe1d670d476d1473c4404e31bf412eab96340730d2be7392c29ac557050d011ae9976b3e17fad18bcbea0bfdaf36062a36af88e56114f5108cebef2ff71b47f0cde528428cd170237b95d52f3649417eda00d198a9ab376ca406bf8e1802ccdd2f6d799bea21a5161cdc4c0fa880d16fa274eaec35593e780396438d62633a909f91396900b16d4a1610fad1cde0ad2794ee9e2b724e933144cb3e746d0be377e3689e15b0cf22a5cd3b1f102b44946483987bf022c60b61858f08dced8887d28f05569caefe1457e673a77685710c75d0a05ed8073933d8808d61fce4dfb609a08b3c9935a8799c746379e352c07481f3e7aacf401a06d5edb84b6f0660b0da68baf5c0e38942ec217da7e46881bad5ba5caae2aac0555f3b17365b21cfa0315a89d858d8f1b426b2bfb8303d7c18b8f97dd20160916114ed8c5fb36af1b19b9b8f50980a1ff270ac8a15e2f5856afe94845a27243a9be93b471c4f4e4aa1eec402c7e26afc7de69328db10cd9d618e2aeee6336ebedb49bee284cb3a4a91fd248f03b4145f8b667ea705c0f0ddaa0d1af8c2c2ced6a2cfcb77b595b675c5f5b1bbeab2dcda0ef69d20bc4e34e30d367bb6cc4b6456ee23b22fb54fb664b49458589c83d730e2af1f9350ec119c04029152aa698953d4abc94e2b3c2c47899aec4d17e77c86f0a3f8089b675dd60a13f963feb0a4e9a946e3e4fedeff365d3e478c9449fdfc5eb72a5dc936ebca4cdb85b5ec6c0217bb9ed4f21ea778933b573a52e8f7ba97805bb205f632677b75ca19c95256b67149a72e113492f533f721eda144ec1b2be49fd97e79aa12c7706ccb4f74ac6c99667088352a5f98350dfc48d623506bacd18367a2ab973d06e586c7d5eabe61540c9091f1c591cb689da4dc723f75db4e8a9207c83d7f8e05c487b02689a1fc867197a0d1d38ea1ec5f277033961f3658962aa51401b3b2790d2be9d117879431097bec3efd6df76cf06928b000834528a6dbe574e532bb80c8eab0db8e04a8cb9ca3f81dde363d7f20613c7983bd5b6e06c105ae6e2f535624a1f89bfce4312ccf1334e4798e15f0aee3752b9a052bb4e72ab5ce629db24b82fb7da0c7f085606936f01aec1c103bcc7c4043ebb606e55c5d874867b32beded14f55b25fd6b6a9057d16d1e5a02f349962ab256499bd09bab584a4037d6fda634c16add62758c95b9db7d851d8aa4d4ade0bd8760bec1c94e017f49e46e5b8a363c7ae71a9a3ccbf30b6f0542cf8029e94566f42817eb3a0bf06db76c7da1a5c62af838ecf67b6fc6232a378f61856d65bf8aa0acbd6750eacc0044d14b85c831b1b4367a05448790b96cf98f4478398782e1fde71837c881a047e0e872c5e57b3b337c5204e42ef3d2cdafca83de825caa66981b1df67c1b7191524fd0b0d5159a0608baaf5cc5c9b938439cdc8e20d3607b3005f677b01d74023e5aa25df19034eb4d914095ee1a468db53e23dcee53b53ee136425c9332c7cfeef3781078d03fed60596cb77664e4cb7c6279a7fd137fab0406887efeccc08d419825620c30d0d1e0d30c58f8ccfd0c42e6712a82ee6d3dc1cd83162b7769f6a3c9e2161e83901df99befcc576aa2a6e0e17c4ef6fde84d5bc27f03e8f0ca905e09937c95cfd21bc6ed7e43af57c93d08371f8f3f402970414ae23e9cd5d33c5598a6104daf9fa3c262225e4a68bbd30c652560d1a4c5255e3ee9cf5f3095005ceb76c9aaa76ca83652bc4adf0bfe1e64804e11626e1ad83e43e6643546c4f9a95a5ea3c05b029c2f8d9585a86b51dccfb66285a28f06acf295191b4da83beaa53b43221ecc30cc60bd1553aece2e8fca800d01844387c9b98853229eb329a175eb2e6076962f058ca597a85a934e941ca824a7aac76c718163e76c86970a6a938956ac028c270c9dea4088b5a6fb2c65ec14651e330797276e760f009dcc0ffd116982130f566470d44996db7b03dae756d4f341c3c12fea3893aa724ba3d7671758540c8e85082d4c00886fe482ad065d42b1b9560f59e1552eb3b2b800a1c211cc8b9d197a8668d398db495807f5b28db4afcafa29c91be82f269e43167cb1d987c93be826a758ef807387f73e4d279d4de01d87002427d7dea254c1574baa7a2841c99d1ba370112c75ecf29be4edf44627de91265d5237abc86c3585328af84b0211d642efc2c6db71db8addcfba4dd665831de3fa975edb36a28bcf4f73b9b6f1951c2845421aac15e779b1f3be5c60d3391e36c8e827efd5d1c6858caeb93b0f1d14db4262934d14068b31250c3ba83379ff38e29f1834bd458f8639dd8fb3f192503a858689b614d824f647b370d7ef1cc54061ff07d850422a4e5c76854c5dfeb0c9dc1a84415f609085af95d25e905ad9a4cfdd435ae6cde60e67bfcda5eca213be2c327a2dea209eda6b6b64ba99ebd9d85b1accdfa2545f88dcc673ee2fe16dd32a32a4c6f534194b8f24f3dc47f74cf29fa6245cd73ca3d6e9962bb889bcff371209f8a1f3068af50ca672e2e2ba354aeb74ec7415739d16d23ec4f9cf7231ea751e0b583a39edf92f447b3fd90cbf2ff6a3fbb1996bfc71968ecc8bda32559406dfaaa3ac03ad425efa67cfd884007a34723d272ae08af7ec4cbcc94de0064eb6737340be22c3af54bdd3dfd5f8affdbbd94c7add21dd89ab90d3d8fb6a054de0fdfaa844adef5917594c3df70ba36b1e1684751fc97e1ea2a4affe2bdba832b09c0eb90db33a1361e58b390f167fc31a79d46e0ca41348b7dfe23c00bfd8c51af14b12b2cbaabd28f6233e7c2d62a0a48470f746ded6875b18b5f74c33517843d964408a6209d9d1f9af302cc01531a963d29b24cffd7b94937a4255084bc740cc58bee5043832e36152ce41b8ced19a4e08312cdeff31b3d1ab088036ef5a1edcb7187cc6c554c04042cc1588cdd43c6aa77d16b285d8e55b86c6c09bf020d1061cb951a479f2758189a2ba1b3ac30f1332dcdf411bd94630af229c03596fcbbbcdca34514474ddd33a68e3dedbe35a58d95f82a24cd0a5e0fd140ea49f56a2b34fdd50face58aae05d8e2d98088a5b3c934bca3edae61aa93856d4962df7467483793d0f3bd517a2084ad383e3e31faa23861dea44d1a8ab4d6cf56f791721e19cce53a5ded0e272d354dc8d0ca6a17b47414a9dfaebe5c57ced0c60a9d27a9c2962ebfc7c958e3adb3a355c843c401df74fd683061d6aa402f7b5db008d917cac217142f588583aff9cd76b957ff322c839154930c471ad0c907357163cc5641033457ea7e08f90bc6e44e5958fc539be9ab1339ff3f381db7d037e224a601c61c1a41325bf04b1ab0099dd15e224de0cc584ac081c611f333353d68af554ebb394c7322a4875977958f779e709e01ba22f675d2a7a7c8fbe1fb9b5398cee09b3e2a19e55052334ec048df70dbcef2e4a3dbb318388ec47e560bad15b8c1871380e12a74fd73d9e4fd687de7061a4ccd181f7477ce2d052196b72d3008afa94e3114115d01331501e715b9f15726cc42071368649e8751c122303da9a2ca7a8f6f262508adda9647d5275b5c0b11e22e16da65f48fd3859e5029706cdffdb7ca110b8f82727afd3e6b7e579ac39a5fab3c9a838ee61ddb206336be51320fa018b2b9d248b5a0d7417b41e43d3bb4e18a5581f9de36891b45e696d897763efc6b6f12f0fc26b9b66cf0cc9a9f9b12b9bcea97bdd920e02362fc7840549b99052ec9367f5b955d578583e37f414edaaa0493b6635b1491ebed388b1dab61aaebb9235d4c5439a23e7cc4d5dd2a4ad02784c50ccff74fee83fced5710f83e5569dfc905cfecada97ea1acd41fb2818252921e43dc751f99a0c8d0d8fa8638be4cdb2108e812eac6362af6f2f0af4b48f9f29c01161a1f96bd9e52168baf475aff4972794e41e0991b8b1bc974575c6e607661c607983f445e3b93b22fc4479ebb0d17c1385b987a80e86b0e1e64e0eb16d8e07db89f34aac4d7a2c122bea1662bbbab82f5333add2fb1847a41b9e944a0669038d1c136d72461d4d8fe02d9e7930170cfa64ccd22d6c3c465fa419649215069da16fc25ce18a78ff47fd2ab8ecb47baebc96122bd7da2a64826f9319037f566955f2b8b586d363312aeb129464fa2d4f729410da20f5cf64fbd68cf54d3458060e3e0f4d5c88446e0d605756b10975d585fa3b8d8c5fa1af9b80d680914a1e86b24c435e8705a59da6d11259fb17742a60aa3c4520b7e65b7d13e52e2fcdcf7bb8288f528e1cdb4f1265fda6d5dae6bb67d6f6a71c36e6e4b725465c4571a725cf082d5a8b9e07952f4c34d43529322faaa623ad76b673d7b23bd78b7de2547d1175c9359fe2f68786ad351a39d1e78807bbd05d1fb82d3d487ccc57548e2a9520f20034a5d0c408afd21f7fc1c3dfce8a393ed11a38129837bad0c99340a24e744ae27deffe76620b4954192605b2a5f218020eebfdae55ad9198a4fe91fe08e7aaf06b74bca749a5528c568966cd13e092ba2dbe1c02d21464d12f4318c17192884ac2277bfaa5db5b91b60c17ceca47af58e1acd01ba9263518f1f78ac7b3de8f6b2033d095dbde378f30ea86571f6b0958453fbabc95d4b941bd66035813bb9107f23853ab7a73a16c64ec85f2e9aa81bf47e4c53c9c8ceeca4458c45aeb9264f46cec4f47ca7a36d07d871c0115a784a2101f4a338d54d4cee20cbd78a07a7cec348f802bd0b05b3b873e0a08e79f55e873cc3ad1ef47b45253e454568b08428338abcac7dcb19a1c2d62f4988426a64bf82f2830ef428b3308c6a13e96361f369b391eaab083e25cb8304af3ee1d039abf49e748f00a582c29e46804a5aad60421da2c8e9ad21b5c5d6a8caa988f9b050096a24241b6d8eacb41c916563ecae0581693a7662016b929e087b8ddf9d067ad05c0361330c424e0bae5625a42335ff5e417f5537d99a3b0db616d23e657fb6bf842896c3731562364c6849891eed795510875a4b08905a333996475d4d35e89539909d1c49402f1c74febac3055183c59c2d1459e98a8c320e82c0488f496d7536237fcc31d913395bc49fdb0718c0fb00c688a777ae222e4deb7b30f60ecabb2ee6ac41e6113cab25205b186ee94d7568c4b2d17480e1b94a7c0ad9d2774df1543306540e6e00134a42f83f711b283e8661da0ced3038fc2cb9297a25b3ff083c0f4ea2a8276ffb5d6a33dba50573d7d2cc9061cd1fddf895c9f7ade25516667099cdeaafce4827b00f81776c68c2d9f9a57c2e38fca382255b78e116f56142778222aae5efc11ad026963aae8380736688c19a98c0d2f80af9a58682649094e6a12b13fdde99ac447df5e2b3851eea35142fece8f192c3fb226f6d0e0b79874eed9c125a002a34cd8bfbe33261284d3ba119cb34f99b0058a4d28bbab4f3b21d85d0687ee8ad65c3348d28c3413b8264e9f0d31106069fd63511c90682cc75e5d3b6b0a43602f2c6c499796e54e6b0e54417a6a5014ba38e848b9c68be11a323efa403b82a1a652222e63dbf37bd0c889ff8384d05476042a4ed217cb0121f1367df956e509cd93dc76f693dec52abb4680e8dd82089ea47cecf3cbf0c2b4e2a9ff2008dd0ebe706074f69d0d0ef7b1b9046a6c059902385931bc62d30f2e1d42657ac4509d8f568a93431520f773103e86d909a4bf109a11f34f45cc335b82bbed95a81d038c916b745dd76c6712bb78a1601ddb8108cee60f7215de7d1a09caaa8c319005cf8b155988b1d68fbeb0d4f3a63b1eda07b63b07c37aefbe58fdce13e933178958d6b54c43ca0e477c5b5f037a0fefa10dfacb8c3b1342defdb04596c86d027bd457ee61395ce9963039ede4633d158796f64dd3e4751d8acfe38e1323ea8f61661b66d84621920afe1b055d0aeae63f6e96d4b49705e986b74a20b1e8d5db0adbcf3103df7a9bba87bd954848eb0317a1bddcf1b87364555e1c5235b7e26c02812feab65b0de35e2586fa2044561b62a9be3c35713bb1647e0c6ab194527460b5986f56d024ea83fc1729ee2eae0b6aa7337e35c74000159b2e73e100ca0d12bdd04a80998b8142e6146179d49cd1054ba0a2a41fa2abbb0aa73f72f6e36225221f81c4a727ff90a173468b2c236d5049493f5bf5d313a63b292a66721d12007ed8b2951cd0322d1425c2aa3aafa3f09ab0c1b68176aea8a92e615e43463275a88d94033c85b07f9c81d5e7dcee5a0f2cf76199be3405d79de8fc316f54c35ffee6868e221989a9268bee91537487b3fed06e04ea66c90858e7660036f5a3d070a60a1b19d62af2647c6e57594d2e42aaee152234528a87ed620cefd225b1e1d8f1a70642b3814609b14c7da4a132803f76532ec57992843fe7a90662259ef7733e5298de50d64e2698292d8a38515ae08cf2f237fc1f520c4ba20630841a2b2a3f0b8319786375eacaeb60723373e007487c2a3fa422e04c472ee2830480cccca2342f5936851cfe7ca4004a4e5c7d154a5232875610611a813c4a98ce9b698cb50bc2721f08680863d6935b8bc45962b2268f0204ce4c058364797b0a70f60b716d011e4abe7ef60d65cd49d49a77724f279715a0530ac621106aa63d425b3f3936462df70ba25b0dc6ebe4f0d0bce762c70cb2dd84a3111ddbafb631422d7898a097d768c5cdd7c6b4235cef0d6d119fae78300df0c0c03aa1d566a5a4058555107f92bb2e84a0782b915db14579374935010c6388b820e7d29bc8b1e7dc1fc761f3ef00c4431ad76d790bdf2e2e276c2b89875c61be0af819a1e80f691472a8342094f5960a4ddbc8e81e83f05c4ee12cab6a54c29a572067c06a206dc8bb8ee392e94a9dda1666ad350559906fd5d9ef29f28e6efd47f9af5d4cf3d330e0fc6611d28540b90cdaaf8db2c0ba8facb5bd5fde577d2b24143b6594583ee8c3211819a3407ca5ceb1656e5c0cdbf16085b28aa9696abd592e26ab95aef72b55a5a2d2d57cbb502ba5a525c525aad95f3e53308dc8ff2dbddddb8bb312e689793bc32899eb147e886b6eba541f798184364603162620c69896132994c31626486c8c4c4888901e3d2fe1ebf6dd4187222454cafbc86c95931434ca621439ae342e736d480969c20c2f6c4e5a0fbbea830febeeb832d0a663f5cdafe4b4b830de3bbff028381c174183f97af058389d99f93d25d5a7de955d83368b4a5a5a05bdff9dadf5f51046d29d181b613a0e5a0e84e2dbaf22f0b07a2697aabe2bf8209aaa2c4051fe0dfd8a8503e770b143fd0094ab7af73be41b05591fd4c83ad8afc46b5b8d096859483e23a3bbd9a1fe7772f12c97775c772683327b64820a2a3b62c7ede0431685ff2c47da717dd7b0f23f4a2af4654f32386fb7dd584befb4edc475f35dc683f57c44783f241fc758e2c07f4cc3719176b594efbc869103f37620162c93932e69e06a5ac5761f7e0a357e16c9d5e85b287ee216753f267e7744e4e08d5eda4e4d2389238a2266ac512946bb9c5a6488874c78e1dce6e726766c93b5625eea8718aaaa257a7c511ab2108474c36a3c9765cfec5a54dcaa66d907d9d1486a0f2675a95f8279ea92695b02105493cb16212abf1651efb917da47f6a1f71f5022aef2ccb2e0ba932cf35792a7ea76c81c2644bf3d967a0c11935e4f09adb7ce6b4fe390379cd83862334f41957e33b2da2f04045dfbdf771f633fbd9d4be16f49913a97148e5a8c043149ea8fe71dd51281a9ef2024dc5f82832e6469ecf96a59d87d3bce6ce233441a0191a85f3c7dd791a8c338f1ffda656a3e3681e9e6ab5bf69c6de3b734610efc8ea9e471ad51eea33678d7e6e08f47da459a3cf797c38bad06f58f13b12ef88748efaadc607452ef492771a8272fd69c1c3594ea3a0190fe751e3f3a80557fdf3d9aac42f91cd6a7c92110b1cb8b62dca3080eaf19964c422ae8a7f17e2b8a148e2e78f77e4c73aecc324c6f589743528254d7e943722456eee3e357a649a9434dab22cb12c8602132142631a6c59ba4ad04bff9808ca0fa884f1a0ef0403fa53ccb3c4600839b3d80bf4d9f811f6b0e117e8611020088fd7081c8063f60a010182f07881be1a93a7e4f4942440101e2f9115441fe829e9001cb3d77a0af4cdf9e23e1cb86e2485372af7c15c5a9ad6c23edd9c0d1c1423df3a15a5ef4459e59d5eadcea98512ea4e51a38bb8801a472e40b75589a85542ad61597353feaa65e15f623764408d38a0079de6697e31df7d367ecc2fa6fbee3bcddf17eddefb4ef39baff835dc28f7205b83b1082ae43e343f0c3de8e35b08c53db7d08386f4c43929e550a8876f0d16693072219028c4b7663188fb984883311609238e4dc5979978a0a8a02fa4dd4fc0fbd653df04683c155ff4ada7dc7d25497e2a14550e28385c8b5ed0dc9d121908dd8fdfc21c3946ffb8c2bcf139b6377fcb323333f3333f3323c153fb0ba9addbbd110b5b75556e830d687cb6f1e2a49371d039e90c9dd3a393f20d8e8e5eede8da9c71d6f4de9b11474c2e88c8956a55be7cdbc7b51fd2a07c122228db7a551b52a476d7296a1cb920d58ead8afc13113454c38ea9962596f8a0cec5b8d39e6e981ffad017e5d79083fe801ec47d1d6b50da3c274583a0dad6400fb26930860271b3592cc3128f2cf154f9618956e597783625a5113b6838423bc75912a5fd4bef3ba42f7d8ca7f932de8b5e66f45d09758a4ff2fb22a14ef14bbfaf0e2506742b85c1419f747a21fad2c3107da9fb1afa9de28bde7bd1c3e89ee4ab217da7f89de6f742f4dec7743ffa47f981aea75887a724dbc8121e505617a8948f8418c0a076f5975308b1038a1e3528420b3e2ff93b82c04a83f24fa6aaa26355368efcd621bf63f2db46be775e53b94fb52af297a0fca5a03428bf240794524df6c805a61fd425865f26c64caffa6bf54ab732a25b95f82a76a08c8a953bd7b274ad020843c7cf7334e87d1cb120b5f4aa8504041a82f4e3d3f48ae4e3db009765324ad68ee3baef74c3e8e5bb18bdfc1bd5462dfd8e986bfa8d7a102a9ca9f45d4e51de93a0485fab41ff462e7655f6e5a845d7ee73ad4a7c46795d41848a40dc216e7e2e0dc6c8450e55a3c1f82f31ca28638c31461028c61863f497a86a30ae14ae58e39517296031d670893246f985747938e60541da5104ad2526df8d57e90ba7fcc239e917523abfd0a46ab025042a9700d686851caba4394da10f26b180830551c45edc772a42b9861e04b648951face45bf7890a55fc025dcaac90d1485f6030307352fa0e7b81890e833981cd6266b0239a409b49d47069319226b1a05b16ada1726576f7f89cfcf8bfacee638c3554b9af16a1f6e5f2d03a13d46b382bb82df7d9fc7cc63d4b191e37e99ca1b3d9ccc51c4bf6a14163c486bfd7323067b3399bf346d58ab139ee5d4efadd8821e86e27ba65556e5295391ff3f81e98a021f360752c168bd55ebe02c955e8bd565beeac49e9f6d6fe876f6aff04e1e02adbd476516fc9dad2d1d272b572b8dadba78bbbd5e2f296ab7734d8396ab77ac8f1d1b5e6c8d114bbbd5b2dd917840879e9fcbb1313942b9f98a0f2c315f282f203253dc9777bb2d2d2b2663cd4fd084557c59f04a5f2947b9f6b554aeb05545d1f0fc00a287044e662b7db6d865236b98dc3c8d4f866c65994dee82d8891ae413a9aa30d3dd024800409c20654567b51b1daf0f3d26354ac23a7e108e59b04d4c681e3acd2f3ccddeb4e4428a9d2a04455002fa0b1a4464195a657d185fc4c0d9e34c834ab52517e404bbe9a1ffb35f449bef4d59cbcc96f831ec9c7d06f9de4db2fe6e49bae2e79216006943678a3556537c15a324985be4451de0bd37f073a8bbebff7f68b684253f7853e17beefdf4fafc196683618c62f3688faedbe55bd8f280cf8632014fa4b0f6542851db811fa1ec5972889fa2868fcd06320f4fb1808c55104422ffa4cfdbd3f2667cd10cd0b28e839978d705fd234d8b1065b7e4bcc643299686cfc48771a8eb9fcc48c308e7d9a6e6f5a901354effd918d9a440774561d74c3363fd0f9b347e94bd4858623d49f7bc0ac651d1855ddab3fab6059bc3729117210aa3303c1a41ab20d9d41f55fce41e94b3e34b9b4cbb2f0fbb35816a360531e0ad57079f843f901adf95163f2251f7fa0353f624a7ff235256ff235a53ff9f827fe18932ff998932ff1f7c2e44b1e86c967e3474cc9977e3d05e3e4537d36a4133f8660137b957c9465f0a308b1d7be7ec4ef04d53f3c40e537c036804bb00af0e792138f6d4a5019002b06e28b9e3f0423103f7ef75da77a8272157df8282eabe27f5a0195b56b66e98d2250802a7ab6f137996217a50bd2f3f3f70dd28700c9f3bb2079fe505685fe8d136c2bbf8badfcd51efaf4037f43f44fd32bd2b7cbe27de0cb387f2f42f5287d87ea51f2efac928f6ddce69d155ffea0cd113a1ff432f4dcc7360d32ceb373df9c94721fe3b00ddf30c736cd628f363978649cc5369bf25ff724865023dbd05909122c159be25f9495f8940a28bd9af1c4c9dda896a5794e934945e55e81292a15bdea979f424f50c0e92050fc628352862726cfe48386b1ca0fbdb9208732a84f0c6bd4b6e19e3b8b8473f2292d138a6aa565c6136b2024e69c3070829260089cf91d776c240f510879ab52bea36057209b0689b45c96cee166c771c88ee4b4143cda888e2e329b47f0a043de70bc5b0e39aa4daf463cecce911c1d38b319ce461c6779453c233a3c297878477270c86e767066de0d6723fb5015e0cac9a7a85a2d4c823373f4b856bbfb85ba0912b93a358ad1fe96fa81aefd1c6dd47ed912f878410982da2f2510bd76ff1ab35bd2ddbf5d99ad064128130d39a0e14a48d3d2d22c128e0b4c8c19b421b722467ca400adb4ba39d9158a2099555992834a1b892375b8e4f12d0836285fa6f4989e9af547a61bd01004439a1a7fc61eb9b32ca0972f8f884e703855ca77217605da6950be04cd3cb5b32c364438902a7b746e3e40b51d9ea3234551e587f2889c1a8e681cce68b62af21935c22162473c75a757a32316942fbfc7878d3680ca7d249f55915f830f6800153473d62847a7e4efa0f550f361ab72a47303d25365ad86a2994f0b192a7f231a9ca022546955b8a4f24b0dd4e69e6ea005f5937bab59d4c7f52223c3a7653c9e6cd644911a6e6d36859f1a2e1123eb53e57beceeee26017be52f4966de211fde56a8cbbed59d9959f2102768e61218507e67b9ebf2fd02a855d877c178b652eeee7ea174b9ccfc5d5cbb1edd05f3964fe5cecece0e5658bb77777bd7963958af4eeccecea327bbc05e6affe7a6065bac8ca0fb735166a7dcf48386a6ea02a8d139dde4041a9a5a856fe566f56459fc5710a15b435ebfcbcecf05dbd9bacc981f9a18e0ef1932994ca650a8bbdd05db8fc647bbbbbbbb27df6c0fdfdc5477cd4ca639eb68d07974f7f6c6f11107473cf58b3ef453f4d1f0947fe87b4ff977dfcf8d39faf930ba0ffd7aaa6d8cbe53524ab9c33bd179c7e78793a34637e8298973526a32fd833ca30e9007ea5bdb9a487fd7fec29adadf44eda6d71f8c111f40117ba9745e21d18f8eed4707068717fa3c29dbf6d9746c3f3a3622fdc3a2e8fdf2ef18eba08819c85e215531c42b345596a5a18bf4384b04d336ae8ee6a3f040bd1f3dff388bf43efd678bb8cbe929ffc93edce3a9fecef3f8c7597b22828ab8f3189b3992fc1d99ec40bb6156c57f6b4788d86eb69b73cec1dc6c446c362237db2d66fbb9f52aec211efa109db6d96a355bcd660335f5318d405dc029321a74d088458d067dae66fdcd0a3dc74967bdb4fc5ca1f73ac57b84ded51ef23ed4de871e86f721cff3be137de7496f5f3b92b4c1d30a68d730451ee008b41f8492316359e6fb5f60571e58d0bf86284423fad48834687c686868d4f0a1518386064d911a5b84c6c616a1e1e3d3e990040f537662fe7accdf17c85b60ecf2b23cad1793c9647a6917d88bcb8b0bacbf5d7878bc976787129c68b3d96c211b0db1ba8f7fe76e53dd2405547e08a771402f23fad1cb784f3a750875ea2f39cdd30c7d353f62e887be86e4bb87117a9337f96ae8877e5f3e24dfbd0cfdd0e9c5e84b1ec6e84bbe9a1f31a1277d4df79dfa472ffad1c3207de9ab097da7fe4ea0efc5e8451fe33de94d5040e553131b2a3f9ca1ef3e641f12aa6b253ca0ac2eb0adabcdff04a6f4ad7b647c9cce1c91acf2ec4484ad3a086aebf490aeb5ad6b2d6b9b732a55dbbad643bac6c5aeb5ad777c48aff8bbb629ffb95deb5a09d75e918eb198c335a609c9a121d316c522a89ce3d150670dbd877c0bb927649f7effa571d6e8fda4f687a1124aed0f0350736ab15aa36fe85ab34d54cf5915ff8e080a1ac5741f23fa913c0141630d3947a693594f8144df0c4f71557e29f0c1f1635a8d99c63187db1a8d8534e8342ed63c76a4358b5946635aaf8008990d01e20364377e4c8b813ac4c4a92e2d8814dd8d1bb87a0d396801ead2788e509b6dc081967d3d55c38d4a29db69ce30b0179a6486c1b08bc3c4f8f4b8bbbbb36034dad2624b9f968b0bb602a39452988b5d2e306f17ac65013ad09056531025ea7e396ab8b3a8c388279034319d2069e247d0fa81081d422411c40f52e038ae9b5684175020842042f4048104422841841140685c7fd692339abedbf4b329fcdf1c2185eeee96b31f44756941d082b3bbbb33373337eb08d90891820e777bb77bbbbb77777785a0b9a0d5faa1882882e082266e20057fb0bd511a8cdf52ada87ca5d551d5f22f05a657fc31d8fd552a55123ea8a40e1e1dac9c7cbf2a7a7bfb8845af9c749f3cf32cf13f7327d0847023052472b013eb55820722ddcedcfbb55cddea4d71b598f7a3b75cdcaadcc2ccdd6af104a1455237884e13356cfd70abeeeedc7152f5cbda9714c91df2bb3fc9eff462f4dd57d38dbe93ac19bdf779bf2f7f1a343333481e0d9a991923148a8c76ef3dcb422c5b16d1fbb30fcb72c94a3fb32afe1e8a63a18f715ccea2c08d09d5c3bddd6891071777cc70ce39e7bcbd8706fd7907d75cbc36c3b7ee26461300803e19484f325a77932fa133944c9f0ca86df0e433416d83255f0050eb43bfd6f444f30b7f7b22003ab444175bb865556aa8614b334bcfd5356234ee7f59a7f925bfafd3fc4e2f48bef430e8977c35254fbff4d5d49454cbb295e34a95633962c195a0685a96854403c507ca95e4c404ed1ab6d4d824184f45ce7b128aa2485071f4a9568537dc2bd4580aad80224a3925b74c10a8063337ca1941dcce28e3d3e855ac7103e351761d6a41c74372afe86d1fe162f2a7c120e87c297fe4112ed6abf8827bc9174ba186a1464dd1c845d77ea9036551d7d9f48abf3003b2a7f2a3e48fa75cbe767403e334c8bff5847f9ef8f32815e87c297d4202901ff7464ee48ffcf1b813e99dc8b0cb413b1d61974347f5ef72fc38cbf3e4cfcf0b86b8a9a1d7f108e5e852525264cccc2877e3e68cb3e6e7f294ff9c9e02e32cd1fbda5c292929393af50175693d72c414ae614a4aaf28b00af0af61aa15581567c908f7c68d5a906afc66ba177d4de8e7d7742f7a29faee6be687be46f4ddcb17f3430f43d4f17c18a19f9f8d1f31f3450fa37bd1fc4c9ef2ef219e108357878279c910eae682b970f97accffd6dd73c1606c333aa0dc4d25839b99714b99e19a3123e3362363c6cc0c77ce91c1393332e072d6cc4d0855b6d7c3a22c890e0557f653b5548bd2f26da9561a6cd54a6b57d5da1a4a8c4c0cd5eeae6aa685ea5f485542c4aa730c9d1e253067fd9c347f1a53eaad8a77f7b2845810589ab79e07b32ca0ca3caa87ace3257d1249a8f4277fe3e5df6a9d4adf6902257ff231262fc3975e86cfc68fd21753f2279f8d9247f46081d95f858fb8d3f965ce8d73e7c690e39c5b7f62094b80c10da0312114052d488b58571881f6efeff3f42008ffe8ecbf82896e71b97477b75a72880d31a04d114488219c0ec02477f765462fc23c1004412fce18a717bd18bd49631231b6125fd0820d39463e3f9630041138b1d88a1e4ab117d47cc115554bc5324a299da5bb3b0341f973fca0e64ff8200733234fe0cc15466294eeae069bf3158e7294a31ce5382eb6cb05165db0789b7116a514891800b1439c02072b92d048ec90851fa2c5e5e2ad96d4814e1226f8cfa13b53392723b3777b777b93c0bdba2b8e70840f32c7bad8da5e9a0df6e0be87fc960699bfe52cee9b9de297dff69c3d9598824cc28de77edc8d2bbe40bd6166f4e28b078220e8c519e3f4a21713e3f4e83ee8ac18410985b8e38821ac2c41fabe226d77c9e8f2f66e978b373b3b3b278393931545281898883cd8590c34ca96f21b2699d991a04be341edaf3fba6005102c8a52b9ae680245a9fefbbfab5d30be7b7b7ba3fcaf1137d58310410d3f881e31c6821ef0ca4aab65a585b6b2b2049e952b4361552d2d57cb39c535e79cddea96b1dbdb536a7fcbd662734def6eef6e1a10d55b5330dbb0039dedc0ae524d5513343e3333333333d3b450bd85f883e00b09896389442231fb832a6701e01d87ee6bccfa120121b1e6e467f81a19def4a697e16b66f893af31bd0c2f4f7e868f91e14d273fc3c338f9190230c3034086377da7f8fb02c00c9fc90b3b702304abc99b7cc7b5a4d4a4a4c4c444e4795f52a2a865e1e15083569ef466bafd4d01abe21f512aab007f0fa542a5ac8abf0ca813948b50e091104c016fb7db8c0a142244c8cced769b959a0485cec77dbf1510743f3ed713ff8dca1f2a2e8b951be2b7cd0b4f58c1ce11729c607bf5cb38cb460c083728f464e1043a2c14559801e147144d38e10baf0310a1044cfc20d18348175efd3cea01fa9aae9002dd6fe96ad92b3098abbbc505737971cd66feed2c64832e4a998cbfcaa1b521dcc845376a21bba1a672a8294341c83c1cf75cbd61a9108be1a080f8354c957fb02ad1b98f7d5830fefce6deb90f87f93566651f5625be73737e2c3b414056ee656519ebd41b3c18212748167258810940dcb81162930228ec00082e94e0e5322346e8600b498ce106af48811ccca004b49b4c0a9c570c55ee452c3b1121fad0cb88bef54f8686a7e2b38e37e964198d31d2e9cde9d149673de2c57884a7c6e723bde2c9f29b1debbac0370901ee438f001cb26bab57cb32bf189f55a0c829ae3927bb38e98a1edd5d2ed13dba3ba703f7a568848d486ea765ad23931cc7011e031b5916ee8965b50f46506c4446431555eea7a96d306779274e7eacfedd87be43c996cd68b21da6394bf4dcd732d1271275229148f4d588befba8f75d37db71236ca4e2c051d658bbed5d8ea4b0a6caae339fd691edc88cecb876643a3299ce8e6c877380f42a74f7ef1e5ad6b296b5ac65251f507b4ef0edb8a5bb68214b70c3c9691e4105b11aee1154507b686863da4a66318f754fdfbac8caef9c65e9387b9822e7711cc86311e4b5ac45a1d08b3eec5bdfda6f7c87e7901e8dbb8b5ab605ba9e8279ca1f45167d34e81e731cd7e1b11fa8cc53fedfed06f2d8b2748ec7fa4336259ceaa1eb60e1ce9138a788e3f098db78ec6693939393e3361e731c1ef358afb8e831b7e969d0df63319bdb380e9bdfd83c16cbc9f1588ec73c36a35168204080d86a436ab521dd92810001c238a827bda2cb22ab7f8d994d35a7f99c9486be292b8f4c76a0dbe08a2a9d71a41c81986ab55a2d728c9102a9ce3f2cc5890a29a460297ac55ea3b150103a9ceaf2ff1fe51fa64e4f52fd632c0b57ff191901d0a1a28e6b44916a8c3146067de7916ef52571088002da35fc9f2316a467d4c6186344ad93808652472879a851e2ac4afcf842bee8cbd10bf922798aeae9550cbd27039a39c59fa7f8c9c4007df731bc4f865ddd6f078a31039299911112e374c136d8806270323336d0cc8c4c0c9b4c8c1999199b4c8c1919cccc32369b8de2d01e243e0820c18e5c7415fdac4b81931a326d131609bbc4748246517d8aea23166984daef0b67b8c8a81ab2762fbb6f8a6ce081b6b4386e398e736f71de52a95c2e31c618497ca6cefb542fa9cbe21d4e79a5e108a9faf36c59222f517d91507d9b50dd3b76733af8f4b8692e7a8c31c69728528d28ae3c63204c00f1e79d15ccc75dc5e77eae37472cb85768fa741c8a6b8fe2fb88050e1df7a7aee39d66710e35e7ea4bcb81109ef5a821f354f76838f8410db986031dfedc533d6423d53b11c71cc7712199180dfebe6c402537838134e891771af4998cd90e90086416b91d9e6540f28e7c199daba8b46d1815b5546a46000000400043150000280c08064302b17044a06b6a520f14800e7c9c40664a99caa3419643398e72c61863080000000000c0080c0dc0021c90f1e8fee07974591ee883225ee799f6579c7b8f4cdd3b26b935214ff30cebdbd31096a56a1aa7349eac75beaee90146392ff22aebaa3fb1d195164bf88860526aa4538d73c3e63873c6d43e7f12288a3237a1deb9106b0751a21bcbd23d8d87a81b3f2094232001ebc36d346e4a4e9c77334c3748a862a4e81d71c3e7981acfe211d620acf10ea9a9eccb93009a9e9b8b494500a128c366fac18cf497e64e1c983eae22553197621edcb45437d14af7c09b8ea869c0f63a0c0fb35f98b9f5d4f994fbd7f1cf54abd8b108e02f6da714b7be8fb7a74c298c3089c295ad24516212ae91811311d2962245d3803855d56de92ca55a9045ca0990953229b98c0b90823959e4e8512709eb0d762edea7fccb36870d4bb8f8bb82227a8900eb859ab02fbac8c39ac52cea57a805e2c1d6f85ac1d579705649a229141d600b8714e056114968937e1b5335855f43373d883e01390c0cad7b67cf49b9eee7e6cf43017253fce404b22fcc4e4714139424a29097d6db32bcd6739b05a14592b58cc53f56f4e8e259c3a8218b6984b39e813e441972c5b2403ba12c58c7001c9d78b55a9f4090bfcfed6fbc11e023b839fd9622fc8b5985ad396b846e71890acff747859f71ebf20f10592bcf81863c04322f76add098960a5d987e4a165afa31727cd0d23ba617f55699cf01af4bd8f72e15de2aed42b8bb3a464295a5ab0a9659e184f2ba07c8a8820093b0e64a55c25da4d59c84b02a6feaf245c5a67c812735ff179ea41c31a1bc8b3dd3f5d2fdff9a8f9c9239b37f3c0bb32401f04071baf142a03cabf31c97c625d79734c0f682a6294bf45c18b2d40dc478b876d452f55b8e1197929dda8323e66c6f6ecd2181a9adb09b5fb4999a7664c4a1be44300ba51d39a12bc0f862bc7e9288edf3f4cf39f5faa56ef6bd1b47de47e707ea0d3a04aad543444862c18beea801fd19befeb571e64ae0a3695e0ebb8f33f5975493fa35e49ed5bb1726f5890c96e5a25b4aee7115d10a832a36a331e1f961a10bfd7260986cf2d65fa96d21478bbb8c20c74979e300950c3d880c4afb9b214b9e1994bbd09934d01ffcb6c86adc53637058d346bfb1322528647d91ebc32088bbc57e53d28a650af6403b19f5cbd8dc93b637da5317dbecbf3b6d0e657f4063f794726826185a13050c95ed3945be82303b39a304380aef8176751172b05197b633ecf06e49490e82185a2e2101e4a3a97911185366c67ea1388147afbe82db0792a7a9d59416f772532a4dff91ee3715001f3343aba8ea618fda22024fd81002941c5f2fcfd350a64e3a703c8ebe5d435414b8ec405826a13baff13b27e630ee1cca1ec243e59a7f0e617370851348b46f88e4c85e0c82812091443a61727794ec719b1dd01485dbcc39a6d63bc33b17af7a3482bd745bcfa890e4328d6140d01d49398c5cbe41e74ec261789f7a913cd1a0f539e0f2668971006e8d06f8a63a132c965e1e12cf5d0b287faec8ff7a018ee6a2f8185cc6c653a19bc4454bd09ecce347c722aaf54b44feb4afabb8eba769d2fb2bcdff49e65d5400929a7b5b9ca2216edb7c04fd1b6218a948378bd47dcbf8ac447a986720a7916bf120438a57a360db1978318b75eb71dbd94439c8246dad54ad19be49e84bacc038617a21a175a86392e42332e1bd98f7da43ce607ac58801e29fcbddefa926041179abb5343271f5dd9bb590db070e870aef63832b971ddcbef8b82ede2dc74c1afc502e78cb043848560d70abd35af4669e00a4d207c0d69555a714be21c0416e63d2e00876c760611846b0b067085da947e7bf4b9cb3e700134611a8c7f95d5cfe8c019ce36f265a23fa4b18162b9ba37c33ecf9215b91432334c1c5879446144a7b6a6860d2738784423e7eec5b340ba7802ef7d52b57f73f6951a3015dc442dee060770840244805a2764bceafd0c3bb8b78a95882d8287b90fcba423192af9612f52b8731e9ebb2653e7829a067bc0bfa6235194936f36c85d565f81a6a4d15889af37e70c1995b74372c57d881ec7188283068f763cebfbb7744cb5eb87c8c22bc6056e310d4d4b39f5f368a42a0dfb4ff983a793cd6b56147c9dada78a235f7e0e773611ae56ed3dda247a8f1c3932e9497fd3cb4b68e41e1a3b070025a214479da89da37e2f9f762762cbcd8904d6a4dc6c994e7d2a362b1bb2270a1d29f5190d9ab67b06d51f45962bb2da5f1e411b70caa7cc727cbd1c74ff7dc079987d20e07552c75c0878d63a0c32336c313df77f70a48c4b7ad30920a196d4731d368ac6732121be1d58860b650ca905a886245f905e71fbe03e58312f31cb48b235be8fa570b4ef1863e094738419b10e660ec7c0ac6dd508f5a6317a475a5a7a082ede93938377b4f6a4f21e559b01c074243dd802ce9eac4c514438d627b78836068f2c7c61f4bfd82e6c89e19636ba7653463ce79e6f9c645947a71ccde1424666a314ef1fd28157fe9a437c58399e514e7643cf5b2cd8b0647d6e5fdb241756d3c75c2de27eef9300d8385eac217b8e0f1a10b76847dc0560af83f53381962a3fa4996a3294c30d43ddb887da330137b940dcb14bcb1d2145e73e771f101620b9d1eaf2982a918727c1444c555bc7c850e0118bcd0496d1d011df771c2bc65592b5277abaef71cb768d1aee8486a538bcc7146e8c1cce9364d13d58c860514eb7e041e9dd1496b3929daedefea8bb950231387d5eda9cf8d38c916751d7d2ff7d608051728ffc0df8b8801ed507edb02304d5b746d032f69fbfb2cf73b18ea8c6f8b21aecd7a341b76c423d88ab25b596d2a47d4749f155b834d07b7533c039608314c79b9e2edabf1f21432945190c1e0d381123485baf7614a5e97363b9da925a408f0109591c7ece4e721c3331b08891c03caa6bfe5aac7b88b684ce7dc010ba56f647a19f6f3acf8ffbc164b9208a0f0550371ad286a08bc5e93c4ce3fc910927a6820851a09993e480596297132493058c56ebd8f0066298e2d545a5cbe9bdd86371ec1f08337f79047f8c46010acc50769268a7c93d2ce158360465a1c026115aed6a939b0caee1c6f33d6cecfbd0d545a1aa23ba10d2329a4f8d7eb32875f2f19458af25eadc548b3cd170d62035ee17ee30bec2b31dec48a8604de49cccd56fc29cd99e20dcc6620361fc08008c957aaeb27bf9a7f957ca8557bf936329dbae16c52b661c0f1321cdb2b3bc4c4d553d26b7e1390908a9be35e7d248de215eb44ff1a1993c1f7af1b638ff320d4877895e8419bd0e516f383297c4a17147d3a641ce89798738c7b1a75ce5f819cb73ae4ce87022a58d2a6e845843c03e4b49d1512cd5faf8db14ea7137c1521989694fee10e76f070fa9a55186093226045e70ec84064e4eaabc1785272c2a220b34bff4d4babef354b4bf23f8ce4ff87f55d9f53e14621f1d5319309a460257d89d680a5625fa9d4de003b74d6353b05b5d3dd869a8a9dce1f129831c98275d32f170a89d7e43d5fb815b492b0984fd92877b231c5d342ecb37a3df31714d63f187e2ba7f0519729c038ede486528e08c4876d0928cc09e9e60a0b08ae23e3a316575aa56e35f6b2e0ba0e242305f222a834416a8bae459f3cb30607cd6da56d3b8d86a4455f14454d7a5306380892756d142feb31bd934ce097a39485bfc1d6ff64d6c9951d9b16e7b9ce38ded2b9c94de697e69c119940410256b00d1caebaab90eb47fa979035e3c151e15f4b00c91e91eb979f8c06563e1ffcd6a5f4b84af9105f092648ffc6fd0e5acba03408826af7ae784659e1b7c288fac7f2fcdeb809882c5b57e9e58a58792bb421d9db27e95d35631a9f0df826922489f27060df65f74ac80dd62f78dd0f7def8943c12a526af1d23e09e6d44745ae618b4467c749c6673c85dd04ce543455e0c193462248350fa9b669ae16314a3b4f21e0988beb86dc787340d9e4fd0c51dc2c0c5522562e735fbd033d5d917f7bfd371804425a8cf789dea45002fd2c21bb6160a4d0cca9f36d5780dbf29b97555f398c6c730a59de9e0aae89c7e805fd939d0a58ce3935c7dc9c9ed763d570d3dfe42fb679c603011be00c5795343e350b554b061a2034c86cb86edf7ba76d400e460037f2f1653325efb4b2d01b8212dade81b1a2acd3241455efd6691375a91f2efafc527ffe7eab659d861e22f3e614bee6f4338550552fadbfd2939f9610c4430667f721bdfb3a91074b13d1bcbde9a53172eb8e24cf155e643ba3dc04491e42cbca31ddaee51e2454f7313e965b3b60d9e40c574651989765f2e480240ccf9d18e28975a75a0b456e54c13ab16d78f67ae97e519551c5d30d23cb13e92031e37a5530289b610ec811ae9748dea94581cf50022d38d501388915bed35a588dad6e424c4346e19c15d655ccc0e5104d9424815aa0191d75ac1c42c3ab415e884991fa750d61fe836f94dd92d4f83294f41e5874faae3a46fa4df4be90930cf9d10c1685bb3a20cefaf575b18a15e20fa73388d1c22317a99fe3db20f7e508160b369fa0f1f70581823ef13a5f84f15991279d6a591033bb586fa06e8365b94ab9d08942d6e454cefe5d2470d3a07a6f2d19a0aa8e495a8d29ebb4d20b0728af596721011c7cb2d94697bd8e2f09de010ab6021b5802a182a7e8b647e7615c0664f5795ada322b56bac7af01717a47a74b62acf5a0dfb1945e3d68a08445fd04b8c0caac26fc32e518d93d65a6a18315120bccc62b965931ab11cdbeca02135a329c08425e4027411ae65960cee98554a53fe5c1541e8dccd47eeab5f902d54960313bf0c99140e76a0ee668616a1534ff9df555246c10762ec1ccf828dc202ddbae41b248e97a028718bd4ed0e72b3cf9356bb4f7899d0916e3470affd5e924d6b346e4fe88fb512631f4545654263d91cce8677d26b2f54f923a5db8f2093a521da1a108fa569f79e173601128c2646576d835395cee8620cda02a4e2019d38f202e7da348350e5481fd3c3ea3d72bfa18fd37851e07d72980e64de8678a715b38ebe9b747bd236e1019ce3e860b3a2a18375137ff17f921067c4b45225606261ba0e6ce37c6f144e3b306886ce5506f0d2074b029aa1601d08e3f66efb240a56e02ac8484f3d7763ee9047a749ab3ceb6c9033226e392bd01574a0c51cb92cfdedb0f205b46df13f5086c29d8eb623482373f497408f9f35522dd72997e2ecf930cbfab184d49adf211fe5c6496e23a8b0bf12974d231e2015a52d9bf038878a8c22bdac75e71d2c302de5f04e141a6b095dc16264261145ea27a07f6975dc197d17e48d2a6386867679600257a83ce1e50c63d572cb8ef8295e21a0046c45991c9ec13e1bde69a89ad0e584778d7c9825fcf25f1f7bf0d1425607903ab9585bb806bec74e41b790057579ef6067177ce910532364978884f9aecd5aba3035fad31ddc6de8a0304c2f814428128a880a4cf8362a3351b4c48935df994f99cdfc0b476203398c09b7e6c765c3b5852b6bd4660f3ae7f460049be6c8835b962d09972813efdef2c9df450851f57889b5f94d1380dab47a2092d7b3609c386451900f28a376fea555e622292d17d1e4f7ee6c909a7a8c5b2452b165fb634602d0d26fea17516b2c19868d3e12f6f6a98e980e49147d67912bc749858d5745440b899794d178103052c92715f65c3e70459523d118df43f1d3560f511f81e25747bbc5ebca841a479f9826de86285ddf1707e058c8ecc63bed6ba30bf9182f9998399abb5c4ea45b3d2ab3417092df78dc93ff9a574a62fc59056cda0164616870ed6afd2bf2b384e390a7e0f222bef784fa2082e1b4751ac9ba5fb1291db08f2c4052b029ee4fe77d300817571cd067e968c81621f8dbabf4c2a0c7a6a99a71cc74ae64673041891b7ca384cb0aed28c4bb34e69e0c109fb34f2509b371569282b1c1a3812e009c2f33ae5c7aabce350381f15adb4e91e18eb786d1f7fe86f2c5bf059c1fc96930f99b8822fd493c37dfff636474f6ee04e1f63c858614a4332dbfb8522761d0106799ba457570983611bb213cfe71f520428f443cbc750838ae8c5af6ccd41f15ef07fda4591feb7a2bb772a335b627fc5ea94cd674cae8afc06d2c420fefaf9ea5b5dc8902f9370c4f62d90442413473e07e792a0ff6639bb292092a5db3dfb4de2f1050bab78865c9899b3ebc38b8f526aa7460d55765287b72cc8139b3c67ee595a004c769f073575c52eb61236b6c9a3df5149348ca97425011c2db014c7fa91be3e588f801a8900edd4c9f1f8b0c903774f86ff6d29c42d7d37c2edad7bf8ce0827b4fc9c154ce43439ddf95f235b220ef500f345a234c158602732aabc611d396b4dce134b731ec90bdb33bbd17de45724998ae91872ca7311be87b9f33839639ca73626f44c86e4c5bd048b03935ea58a6d6d78a83bf5195d888d77e79e1ef9dbf2ccf89d650135defc71799c324aaa9d84d34c87811478ff157ec001e5070c174ca1aeb58b526bc116df0a27772d810348e8f18f080adce23e6c5c624ad4c37a3b8259f112481ae8bdb92a12c344753ff06cc7087d0e859488b19f060df93260e96ef0103ab392510171e77187d1ab450064e262d9482d5619fd003006a5d874545425c2720206a970b92715fc33a13ad33257e5303eb85a89c62adb16da62ce15ef5a7bbbf122eb76be6a81e0c568df064062310a14db2d2872ccf8380d53fa32d3ca11baf15678d9aa2c4d30717a12dfe811437e315d6490b58219a2dd1e9e07367b46757d9992d7d3ae8c00586a8a188e98a366c242bd3673e2fdb75bd7b636622b8e608b77d09f1407782446696b1529a8b5966adee225d26611ce5fd4ee4527adbcc58f79930ce17ac5f68bf5e6d229f8594177f85954eb520dc9a1c2ab23e1eac89af85a1bdd836f1367e78ea065d22d2c246f5b2abc90f00f326c38a642048928840e6651e1ac2d7cfd3bf1a12a616de8ccd24ab632878df21811454f964c0abb3b321b37326c32f3378ee05ce23af6a19a4ef76324c4b26d6c8c59e9e63e6886896a45dbb8346094fb19a21012e7ec7f115ce8f522b32529cc52517e0ef5f1eda8a9f0f8b83aaed64d4c100484756e0a9785ee5cba47d23574ce6dbcfff9f4e78a7b0d8a4cf45222a3c9b4236a057db11930650634f3f7516a2a1b7f7c81985f6c7357032a38dbc19e3778d1c0e42a84831e48e763e7146e1ef7d188fd29fa01043d52003fb14d5e0acee4c1881cc495c5dfdd85bda79d4f993c4e5a662cb352990adb151761c26e76ed1c7117260b4d77dd607d95ad1f0112d6688d07f2417f015afafd6666e3382b4524c464f0dcc3b35d368d0b86f1027b139b7ae6e2182d84d80d15d7e12cec3bbd8ff3569791efb1ee31c366e5886232ae3e3b907e131cfb60d0b6e23470f67140ca406431194c8526cbcf3ca1b8c14d790f26636bc8c16117fa40b17d732c1d0ccc70e5c29214ede0995e43e61eb9579ab034f135c09a62c3219b6d8db0b1893cb7c8428a117e51f839c6f3a1e3b02de240ca387a556754023c6fad64e920acc285989ff92caa73592fce5ff296d9664a29743680de770d46c9d0d6237b7549d329a938986c9ed5c71d1f9126cea5a3908802c69b676863b9fcc64a72f30882adaf35001e7e379b5d3d7293a0df64529eb16a4ec1fdfbb9d5cf07ff0dfb1943903001d4b4232f623d500f7a9bb7e4a4b73d856c3ceb9a17a2acdf78b564062d6b5b8d9531d1bc68c220f3e56c46a2168fb70be437daebaca75109f277f1de69e39fc3ba0bcbe2d3bc9cbeafa88003db8d870144e049ec05b40679382a1fc206d6d6686806464ccb917d219f131bf63008237ba481692c90129a055e925c62bb932e9cb60b7c5a6542e1e62de9d2c4190e9da70bb112edbb737d6a644be00f1ec90476c2b2a239d0dd66dac72dd29fd607154b06039b59f5598cc4b9f7f175d0f34d6af9a58a0dc00e542aece3870c0b72c05e7e144df84839e7f0077a566f6d05b48f39eb63615ff245114d3f980a2590f3dc0810754a92412dfc8d99a2ef59eadc85c6e59d8ad3b3a498dc2c974392f072a4489d5a03c13f4e1f03f17887aec9200974cafe05d91a1cb3f2aa4cc8af4e22b13f9b233eafdb82c31c33fa34971e8ec0b94355197db40ed217bd1c77419c1bdb772e5a104764f4f63ef011c484ac0792f0fb9399dc48efc9f84ec242c290b8a188bbd66aa0c9407967bdf0660e360dcae56fc88a4d835dc21b5f8c548c80a222b66d518a10e9694368e01f8ae65b7d611afb2d4dd0c1b1af0cb9624031146b7d4694564ccee23104aea52c03727a2821ef78ac153e9914330aaa49887b11be2b74c3c80525dfb3292ba8152ca77e933971698b0ab42f118500eb5c9484cd45722c4cb52d32839fab815a9e4c2465b002c8ee76faaa221a838f5e07c88768f80bfa4f00bae766053c43480682ee1835414721ab6c7bb113e3f58f3d7d779ffceac9c52860f0399bee76aa5f373b52487c97caa98153418fdbdfbf29d80db47789c5caf85a1404d91e8b17ac6fdfa754b3594ab693a9d9ffdb735d59aa2a7907cf2c4eced31cc7d35ba27627e58d4a9e69a01dd5c8ad292dd4d6f84aef7922aad97b4d1771d80fe710b806fb2f957fb2b33f7cf02f109550e6729d5048f318991cae3aa1c5e045fd48a1197b780c87d5a0d94e1fcb15604a74fc31011e1c643da09ed356708f44fbbe4d138c31e03e0796c3b13c77e7b3cbb9aac86eff3eab58b2f203ad6ebb405432abe84a6c075a36018ba0b75d58a3ceb41ffbcc99c191dd575525f2195a6f38c95224560898101d7fbea8cd0ebf844d03d19c49139893c6df14419c3c10a4983511b5c12dee3f5abd0e9527fc8d4f45bb526016624c160ac63861b7123b5965d08b2c4143634307d639eb0d23b093875f1284e0f51e8c8636681492d3e11b6598038cfc2da167e4e8afd61b379127772b71b7714b97a78dcd34fe7d6a107ec05efd3f2d8ee531354780ee2a72afbcf1cb0c93872ccc6b160751e43c2ed4c0e110dd2059352b3ee04b7a57f16a4b7ea86676f5211aeddbb387b018d80c60a17d26d9ed067efe108033e7d0fbc3e0a13ee3deaed2fa9be486043a37431d7e2073e2d8e256ee5ea9bcbcf495a5aecb371faa94f40b96beb7f648fc9245fa7dc3aa7d4100960a25b9b040e2c4224c89e08f5883c41130f3a8de52447e1846470db03b1508bb43ce1862e4ef835f17e3aa87aad222aa01a624cc271af1f8e1171d7414ced8afe5be04a40967b6539ebcc2bd9c10b37fd109a57cc44823dd99529a4affdb545e73c6d2f3f423f123e8533d894e52c27c4738f6c0c845cf4c19ecc15b6f9fabb851e7ed5b83f5ee54b06406d926557c721970dfb0146768df6a083fd7f57e152f887eb3941ec873c14cd6536c09209de6a1241d3783c7af9215f05e811f751c50651b7baef491cf6a73d6a5cd870778f945288d467ff8fd2af42ee0da397fcab7a9ae01909e846cb9545b7a89386b90063878a66ad786a5a9838903e03c359fd7139b4fde5393935a11193a379fa08cbd4b06d44aa3348e769e3456758df8ff24a6f07914a734787f3ab8c7abdc4bdf24dddc58925ed72a322573cac38468718faf90e435ef1107b2eb44355dc31bbbb67a75439ba963202e31c88b76a95d47714210b1e0c9281c9a4afb104e584cae58fa9a5417c83fa23ce084311ff2a540938a10d31711e1289182c20e58448dc97f87499c4184b8fd72e16cf95628bab0998cb938c234f1e55c506cb5e966ee897302dc7b7229629a3ead39c540f4fc103d7b45a2b3f5d4634ddc730277ca6404eeb5da7925769d6e3d36c2e8b972257ae5a48d5b32ad027ee7656f11e8632b9d1d1f378faf5d3aa5e236bcb96c25b0ea400f9d12046a95b67b50a5e0e63dc85d2c234e6fdb147a1e3eaf8bfa5427fdcbfdad59303e4b3560768a3639d91a7f7df901ab13a2c9dfeacfbb34ad953bd144a851a9b45b38e54d1c308ca75bc5afd3a31579c4d945598b8635725397d7d92f2f208a566f1d4ba092aa5eff9635041a31184f1084c010498126fa6a66943ce64f24e603e95663684e3b4df87d0772793a6300d10f7672a0d1f0c386243bc495722d9005401c89fda6711f824437c786b345d8149818ee3fe63df89f50dcd943cb750058dd8ac75378f49b6ef76f6f9acfa36263a0bb529f1f2b76d029216e219b0d8328b14acaad2da8daf8664a8eb63796d6191173fb5f06f51670c6a4614b91aca0cc0fce69078cea471da2c4cb0f04140888426834202d56c4c51e57d94170408629e6db1876027804c2f9de2b6114b1970fe84a1a7459624230b077ccc063f188f6d798d7afb9b9f5ca0e37ba54b8d9bdca9e5ca93d21493301daccdde07d1327073f6acab331593dd29353d8301a076a7a7f6515044590455a50686ac28a9b916faa266dffb2f7d326a0c09621cb22cefa13f9b91e051167b847b1d07d6e7753537a02814b995f3dc69c88b3fb1bb0395d7a6930cebdce54af6f310cbe3b4933579354ff0883c32dbcf9e9c174ec9aa907214e8ff7a61f8549886f32f2edc1546ade10c0317a5019e34d98e3ff247c917f67c1d148ccdfb6246370fab64dc677581485a2f9d2bbc53b73b484e865a1c8914eba1a5ae58a0167cf840e809d12bddc610685b453edd83236b4fab33ebc046ae8ca9475b2162a393ab2b15fa271462f2151cd1a65d8c462ed5114832cd10499301b86e138f7e6ff59f7d786224de16537b3ea87c50cbd6a0f74c1890a503bf82fae9d28d905e8a3580070ddc548e973baee6e244b433e40616b38ed93cb2bfefe65e2e354346c502b47640769022633d38ac59e49b7088df7d62d715ad538c6f6ebd0a32cf2903d04a3ca01fca37d77c9325136f0aca385df6e4f043a3ce0b9c5f1158b38b95ba9556e2482f28d76d3b20e908f948eb915b605eb57ccb6a65f311b5144ff400c767c477c761ca876c6398ac51489b177f0e5f5140f732607e55bf832e93dc7474867964dc788d85d3506342ea9a9cc0abf8476042e17754450ed80af37969a7c390b4bc5cb84a629eba4ce661f7d3b07590f34a85d146d363e717e80cf3740bbbf88483eea031a81da28d2384b152a55b3230b8b44b60bb90cf392157cb3552a999fd1c3ce04252639e831ce98a64cece0233f75c7e80e8f5b09f786c2219c3d997cf34713223f808ba1b84fce73f2b37eb396497872bce81c7ce47dc353700cb4f0b8babc3d758485b9bb96aeb0f094c262392550e52d269c18a9c54355864a9c7f39275f9cd37bbe04f3f7c511ac7b08e81b24ac236404468888e799e3d3efaa301798380a21e60a7eb1822082ba0a3d522781cdc39fb6ab0f3c8167b48a4f146bd187d5cf79bc025d09cab4f5732eafbb9bc235664829b6aed467a7608b1345bd600b9553cc2bfc5f6dc057a56fb0bf60540f3f4e5157fc5b269863399de0ab0073c914d24acbdec43e49bbcf829933593c07e7c475d486965defb71198973a46875a414e643de4b47d76d0922748c5c66d71e7a5c390205aef2a9346e5cf3a32db01a3816a462fe35896cc86ba92869a3a4529461410dc0efa8306e9c421029d63d703a565f1fd42a02dc26959961715d2adac1bad478a10445639d92e8e67e778868ea9b931076827bb3f6f984926b439ba695b6180a59d6584d45dc025692f24c0915af498ef213e6295bad86095a72249c2ef3ac8afa8a1c5b4da62f8f3abc1013da360b06e9085578d758251a4032d461ea717b8b27fadf3410fbf5a8b7834c656805cd3d1cab0b0f72fb37176381927cbfb006571323b5afff363437d62fb8f56477ab7942fe5b4284a048c7d8b42faed9f834c20cbc2dfc794dc10026f7e6b5a551578a5ba310eadfc8dce52eca544e7e76c4b2a4f00d21e42ef516efb0d14a3c6ace7ecc52257444390550daeff823058291a9116b3494c2a03065fb32cac431946e8d1e2ff86258c44a5dae9354eb3503ab8b1882d19c50432b6c7faf466850bc23daef631d9e249afec64767a67c556a6918f17271fe01432444d560a65b07446c1af7cae3c4ee23707ec07fa238bb8e4ec46b69c2e8eb1b205077b2c449e4bd5a340ae6a2ba8ba9e44e72f1c64d38b846ef074cea723326b8ed75ff0a09c9882b725cd3e6e0a8ee265e2fe77de86f9ce8e3268869a00b50e021d2701639a24d64d55bbf45d40088e1a5a8138264a4b7cd0abb773c75cf09e26ccd79682535edcb345669391c58a8ccf34bc37054cfd6a27ca15725023efb3c369bd93262dff7e3438b7158a365c68da10f45bde9c929ae4a60a8c25abc4231f5820858406eaa3f75da66fc58bd2802062bc828ac2b6d8e49cc02c65012c7c449e3d505b14136f624bc83e761f0637b7f429dc97622a48cb91b6ae91b6a485179b9633333ed505e4709ef13f9978991cc6b11318eca9813b750a9c2eade76fdb3d9bacca1b0bbf38ce40ed9ed6a32026271d36afbae4d31fd42856e2437d848ffb85e2f2958b311d6f08cfa56c368cd0d37317cadc65a4601053468f80f00c5e574f66394770cc542c6c38ba53e9945ac4f7ff47f0be05dbf2bdfe1e3ba91ed002b2aa6cdeb86d7eab910fd32d891cb3389d2b4ef7a30ba956ab3fc6fc9bf874a1a916d68987c206a31ee626487c8363be5e08f7b53654eae4421a0695dbd8a5740bb028952f6bc37aef7212154f52ef866e2f13a6057a8f8870c3609a00a4c1fe261be988d6e3d3dc8e1d14051c111af9c1f8c4783e87c85d0f45e146a3a81a0d50145ea87cd0be49748b82c5731097ef17eeddd0e900572cee64a2b1e5976583a2ead3814336326052c460f5f1e617e5e3926cded1548b6d76376f226102e4f1befcf860269d3e3217cb7a9cd5d2176bd84b98e0deadefdcab62c58448ae183784b703bb67012691e526cd1f28d2e8b7ac2eec8816872185a735031b5433fe7d93bae4a00132c561f687c60e311bbfac831e9157281b411bb567e78a38db08294b2bcd6b9645a779e06db5fd361d06978f0c8623e56c5de3a9ffab652774134c0ba6e0675478fbf78e482efddee7c9dc5ba02ac4efb0c49735cc0781af6b9343173cf07745dc591a213fd10b3eaf179be30d023b89c1638b5880064b510922e7300dbb947fd6e90802dfd65194dcbef30bd62a90a9e3c95f86ba13509d5858f8fa12145cca8c6c8429c20b502a29690936c34b1b522071a1bde25c6ce7f563799efeb0623705676d31e54989e6396c0f63984f04b548ddbdb6e62c7df17b8c01fab4b51fc330b756bd8bf9e0e2780090df621f0034a5986ba8ae48ff53069c766febc5a2d80c04567e42b2a37f98439286b02e43e4c43b6823d0997fb0f941376af0157e3e659c1bc364bdaa26f38af055cfde83d20aa3653963fe116108e028f983217198f670f832111196c25884cc5cb153de0d4307e354a4aa0c5cd5460e7075e1971193a63e03e92f8e718905fd93a2c557ba7506eaa91b0d50cb0379708c85a944dc910ef3099a600c08f5ec04a3804bf3092cc0a6176a96612d83de621fbf06b8175861fe81121e41b8bd11c81312f3a720ccd17926ee463d8328d8a9bd131cf22c441090cac99aa101770a93403c4a7aee939fce5cbf9580ba3ca11517259367b1b75a675b8b284c15404b5118473551a89de3bd775b34d8748073878bbc70f47fb07d45f5dedb9833dcaa323b34a8b90436c0392b1e83821f6f13265b86b435e495376683be1f1e357772e4c4935471d5fb5539b39ea38129f095307d679ca6d593105c4ffca1cc532381172ad40756202cffc86405079c452b46c75099b01a4b6711e75edfbd2f3004de3b73668e801057b07c58e24ac347c30db4e59b9d2fffcb84c85a2bb6020f9894c9ec6fa450ce401c0247e1de475f8e91208a86f878239ee948c253cb586aaf9a70b15ab8bc503b40c07c887d9cbf4a8b4373f50e7a85433baf4cba34e439e8d57aba48a3062d1a9fab4ad6d583b10049a0efe2614a858c34b23f233b61b21a62f09d91019cde5a0f9b38fda0689afc7144c54c7e2ec683e27e6008fb4631e202f9e3a02e513568c15500e292014a41c3c48107ad6396e80ac9207323142710cece4a57efb103c2431712c352ea5bf26954769eb61d109a0b48a36d7b1179c57845442923d0f53886845545b03692437cb5b1046b5e0c2b782405ca801ab9ac9d3c879ba5c4a28ce072bc7b29ac22f5e470f6f186fc3af4b1144391fd15b29b9564e4026d01dbd66eec5d241d0b512b4b6feadc25a938f1f37d2b0278f30bc2a4b6ba60d21d6e794c553f736e2a292378490e2e344e38dc7849dfedc1fc41a1658053c795d922e22e8b4c267cbb4f68d4da7baf878c3a404162a6188feb1a4c38bbbf3be855e41e28f9f4745e94c9fc6f8f4f3305d745cf9c06bf8eb6a8c796e8fe98c49f6cd3fd7154cd0a83af3a072b0d9731e78f630761cdd921446145a2b2b0952c90930eb80e2a538f7b9519fed2327c829731067878fd11f6a507f0f1310094a1d13cbfc33007b50c4f357e0daf584227fa366c0024d5be72598f1bcec8fa89f4eacede7e6c6d1a8c157065088ca27c72f197be5e5bec5289989c7465088fa634e2a42b814c52cbf019f7a7998ca31347d42e3e308d06fe8cc5cb958b2def8092ad13febc73b4d62e28d338d4320805be494f927b18037c0c488d587cbb259e852e9d880ce01fa3b0f4797c50be65a07378c5f4ab97897b97a5bf47e71b2d467a68c456dbd4c5caee3c2776d7da4968a1e26db8f7bbd4bd1b5622110fc4e32d9d974a12f91a52c373278e5b1dc68a6dfad218a17c23ad922cfb7f157df28924797e439726b8695482195ce211057a9dd966a48b5fb88b785f400233799f48e1097c76ad773f1e6e118708f3663528a0b7304e11bce009021a806d2fd3f11afa2da6dd167c834b55da3136fc83ccb858eb93ec46a5c2a5183ee0770bc02a4a316d18a05d9c1c2a9e00ff6d00937f54f2a6346255eaae9123a8ab33442558606b17d54656a125da03dd539b8e042301d5150ef32b4df0e99d70b781d697469cc3c878500d8192fb07125750928432d121b02ed2409247553492a74ac7c906ebcb971ee4870fcdfe84497e8fe34c16942c7de52f9e890d8c5e8004aaff43a0496b87b29e95f893aea82542f055fa015238c48bdaeba5453c0c18d9da4b34570a17a0dd9f2e9075f90dbf551a8d98b764e86699542e94b4de2580c7edd29d801164138eeea66f5c82c804b4996b0402892b1701c1abd23d207a345fe11c2a431055b4c2f9c3e69dc64745fc00940ec40e68db90d56e2f1447124a907b5cf5e99ea2cd6aa079904962201a6275961601c5fbd22712d265097fd072f216acd4456947cb15e2a2383477a68391e79f3368208ecb9bf1f1dc2d36dc6316a190dc7e4437861f9449f737de6d7c5caa6a68e5e813179564e1d97beaa94cada7de34d595378e5747940c52120e323e5149c1a5310dcb9e19023b5c2e51b9c35667705bdeaf688029d4a9843797d09bd97277bd7e483fca6d2b0002f71f2c114e6c1b7ab8b544bf8f1479e013bfd762f942013e933955a4ff7a6689bd2b07aef097a77724a3a537a1c23e7ddea4942ad47f9b4474682a2a83685ea095b71a552df8b6b899021aa7921e89484687809f434441d6d8ddb3b159f55707e6259dd621fd38b7a3b0321be76970a281e293e39ee8746c1e56e0c393fb6cba15de64c76e97fa77f68ee47a321456deafb4ae25ea6c1344825d6e5aa2b8553707ca32729c02afa0b432263ee72ea3d8c86c6b596cff4d081db8b85d238262d298404a440bcbf296814c072ded228a1dc762853152c1b7bb83c01a83407c2ce122dfa9f6d2916f0f2bcbfdf1ca5eecb9e8565d10ca096f0fd1d2595d8af1d9befef31ccd0567dc1f8a20141fde7b84124a42d6e6bf83e02b53f9556ec3c086231733ee9edc462e0b412dd42b73658ed290721b4910b9a0764b90fc7b4c584e0a3d3e50319d531e0702b1c5ea7ab0bbb6bad806328c9394048b9468461c24c78f6d562453aef6e121a47e0a416b637d966f57fc42ce0c1be6e9aff70ed7661c0b2b8ac5fe846765b81f9289e58c2b6170b09d6675f19d01db87ff1eb0be4b5c6bde49fe118b6dc13f6e766e72466cf9ce94eef3315b46bc6bfcdf4c59bfbe3da455b901ee00879f13428ba34fb5968a7823af38e7fec2a9925c0c09c96cd6532c211dc9eb0ad455474223bcf2e2dfac8817937003a9eddacab5a215b1f457c9b4ce1370d0b6afca5c1a14eb35fe5ccf399af6921819f304bf35f04dbb65e1a5504e42b6ab38e912852fbcfe92d8097a248cdc67e90629456a9563cd342486f1dd48e52be159bde34ce3a623770c19fcebae6027058e3ad610f11cd1ba04bc919b190b2d7ebd2af4bd64d2306faf0715b918766e6d798f74a9650a035fc0bc9fa892f528650d7df0a47c985906a17b773d20bdee9c69288a1e69389f66a93f74ec1ef8e2269e386556a2c7fba7b5e70f78ca2c18f15a709043ab7f418f5193b4ce6676379b2a59b241606cc57e9bd0c49e68156f04af8a80e5fa32162b3c73f6340eec9d7d54b5c54c54722bce84ce4de6fa1375fc5dbbb988dc7cf31beebbe29d7249cf23ee160d4f526c844295119fc053e6943425c956d30f9ab80e916f641fc4ebbaad676ff829fceb0660fe47feaa4c2d0e8b38bbb99134dabc296ce19c5da630b5afe58969f791a87ef38420518fa8e2223ecd18d0d2cf5374a0becf646b899e60f4e49b78366692130cd5cfecc1dc8870c933bd0b37d8ab4ae7fe6cb2c0414a9d44a41cbd9b347d67197c3467bdc8da351ba0ef19c7d315e732197f0e8e78491b53121fb0d6c4f1407b05c7e9b9b6fbc47c2bbe1d8803048de943c9e45d1514131387a847cfe6d915aa1e098c58891e28dff4eff314f7ec516485bc6b7111be681a085a929817299a8f2dc735fdc18eef7de0befd43096aa504f3b919c47180b9158901bf4a2d91ecc87bfb6f42897141570f4d014908c326beaad8f919b192eb72f1f87ec8c7cf0231932c24a1a94b8012521db5adf04eff27269fa19939c6be411dc23e50513b8fae7b7da464e81b8385b52080fec931fee04c010f489a5de4dd1f329c8a1f4a1dbb0ca41fee8d77f95855fd73040e42692f189378ec816595debb0a10986abeb056cadc819d531e72d51397aee59579fc9e3f0df13760e4c073d93d818d1ddac1cb90b769fa9157586bc249cd0935930132a3faf91daabbb2a8d01181f32ef073e732c6fcfc3020933a86f4082b964beab248c7883644b45263fa61b618a57e2775745812715b1fdd15e6932ad02b2c0a90302482ca2c38ebf15f06de22013918b159198bb2c9311bd22930fe6510f2c3a173c35673b0bf1f06d8ecf6a873f05c5b860b85b55069da36b1206e750ef5a7c06b4d399f871ae70be66b7fc2508dab98c631e66ed37582f35e4eed2ab6242cee46203f35a17171ba09817efe88693dc15980f0e38eaa48332bd0b2eea763b3d5349c58835b826ca37c22ef0084e0d7161eba50a1fe19bf87157fb803cb81c7f8bffe53115e40f4fc19daa81ea10ae58d73672f6052f2191881f41e3f82dce1a2ae1871c32f909a6e7c8cf4e53bce22e38ba5b9b123c56d3737b853497799f60eceefec083cca118a27554c04736acc157f8eff18c41345f956e16bb5b07779952a32fcece1ac76cc90def49afef160b026cbcd34b4f57b9914ecafa8c2b9494395861b164dc27dab3e892526f3305f8f9ecae458cc75179dbb7134006c21f1a829f758624d27bdf96d88342e6500306d26b004c2cc9467e29eddaee7804618927037605bffac69cda460690318e1683cfec2e5a44b3158c539fdc79fc64c23f696bb3bc9a81282f76a70d4da94804cb2b623b19630e61f5317a6d975f2cf9429bcb6d3074c68a9f32cb1588aa46181ba56833dd8b5ff792d428e8cada61fd1796ff407b7d7cb870a37b881a4309867f03dcb1f89523b75e5b6a1374d168a042943b74f6438e0d220b0dae13073914002e049b984b70250cf8a2aed9c9432cee6d520038da9e7d9c74a18d8615a8e72dfd8b54c32645a6acb09c2a02f6768b2f56fc175ad0fc6e41d082514acc334f8fad1a3092a22478f780d3fc3cbc9974407c8cfe65554624abaa02dbe23b3e80295154257ebe0efa91090714bd120464c9d52efffa3421192804e510c2373267d7f7338661bfc125adcc77dfd66f09092f82f43010d88d89fb9ebec18c021aa3bf9688ead928ec17c78132256bb88ca3ff7a2547c1964e73af730cb69ee116937e3a211bd72c91f2c57d8b864fa1aaba099a90368a64d92567a5c35cfaf06e4b9b81812c95a4973cff165cd4f2dfce100dc0ad3f3625532aab05cb29899968cccdd5dcb4782d2d8e3b20295abaaab3776336e8c476a54bf4a32534a118bb25c55b26db6b9b08cde401960cb4b28ae9c0b3da2bc75418e95072332096a0f8a94f146db2121132c82d842c3a1290fceb500d8548218e9875cc98864e261a9f1143812302386030a6f8b6ea8487669f455d0dedd3aab153c169d3b35fdc861dee24cb993e6bff13adcec278db4a390717b997d4db6bb2ddfbc33595989c9f44f49013e49eb093c03100000f47e90901ecb1fc64ab2c9e20f812ccea1f6f3c709729a0a67c3ee061d62e27f4a73a0ec6e624ac1f466b851e3c9b049fbb7c13827f036563d4e991362486581e96f03485209a1d4f2611c77be257a4f8a527d278dde663e8aac5889f919a2d8ed342fca86ace62e41f72f3be6196ce18eb7046682fbfb6e50dda64b916ff71f45a60e498cccc4e63945b5a27a429dadd1ddc9b8494ae9822cda57b8c7996a22a2b7d0f7bcfe3c324706597b087023cf705ab9e38fab9e30c6f3c40f802c421d3a5e2a0a995a40bea71704aec7cf485cbab745b426c1d6056c4299acb50ae409275cc6b368273a38e0fd859f6d54f616bdabab70ec60181ed4634c12065c3d234aaf93b20b03fac204f19998de12bdb52cc00b2bba006572c23889e518f7764c3ad8f97c37647c295f77776fba74745571bfaed8f738385b790d2fba634a30c2b8501cb9869288cd072bfc6a042824b72af9fdb0bb5b9e6f8e62fb4607362665c91680815880300b9f6033043ae76427d878cc994699ddf000e433d069366193673d2d029ed6ef2df3248df53865abbaa76d19ff4b0eb05df444d58f79a89f69b288961463f05aa23932c8782682a02677c9811c04d1419fd475ccde64cb120510ce3310ccacdf6e589da10bea368f02709988015f432e489b802845474b4140cfe4c521fda86ba7f55119162ac1cd46909a65bb9a3890f189438a5fbd5690d6f7d02763b5969c2c52f20591d066b216ca16459be1438f2c87d6b4d7c27198105373d7bff656427742374e9555f59bd5e59853e067ce05ebdb503834e2e61ee4d7bfbdd597ec466c343fb4b75791fb2735d5cae446e27d9509e049e2ddb30a04581d6e4fe01602bebce9aea7d0284e58e714dead15396da25d0d042527c0d1a3445b67f8170848046c7adda93846b866670280a24523933014baf83b5d827d03d40189e3c21ec30a8cd02caa84e108cbc1e6aa18ab53f43fc03cf9c20867482652d2be6004d30305adb7c2b66d949830bbbc762f2692254d0bc754fd477c1fd1c41cb3b87985364b8f401d761fd8e2377069468f19861d91b9ba8c19d8513dccb936e84fad23e84fe5efc7ddb5ac517d0d53bf6d0e3d123855dd2221d6ea0192d33e0c9163c012b03dd174dfbdc691100f7e150f548ed892633ce4337e6dcf8a7fb906e7ed1cdc03c96e8004d784cfbb1bedce2ea08f4de9bee27dc56a1353c72d9cfd2ac513a708c93b1e458cad2971c7e4f545b99f6c6dcd38243a14829940d264eabeeb1481b61625e25b087ecd136513aaab326e82c9edc45fc3c70dc670feb69f5b56fd979bebfc4c27ff8da39c0eec7c8c0aea74ce47944abe3d8a3502a7479c448f30ec87e2c954a3fc5ca9abc2da005fd68518019732cf8e6cced8520a5486b0b98db262886d29e2da08d8937594a565b05016f31b66961972b6a73bc82a0a8ff6e45953ee701000421da47fcd4139e39381bc9edb5152d3ad4384d411a7477fb4101f14ef0b9a5485e7c34b9965faca824c99298a04fff132b885660d76d6affb474ba33c9eea8d9a89068fdb29549e2d401994af6e97e1a47f1c66ff2bac848d642597a02b3dd757107091061bdb2562b3ccca0fd5adad56dee5e74587c553fd35432aad4ddadb4cd554f29ab10980f201e4f2133018dcbd72c86c15711e20077ba25d349d233b18bdb0d8cac531eef12dfa851fcae46bfc54124e17833cf3923048e9e385e53c5fde45cf1b8a04b2530676cb62abc745f17e4b10cc3110c8ea049604ead62be6b98b8ef7dc5931ee391e4cc2b14e616d85d9284a5755348bbbf1e68b8899864ef07ef7957a8af1b1573c607e2a957b0a969b89be352d6848042bd33e7409803af668474164b7b7fd46dd8b6e385d1bebd92cf2d537ee9b4f6d322bde67d4e01c9f34fadb3947da22610e2524045ef245a56a3805271f18779f700d6089020c3cbd027a6119f6853b5c95c58ad0d552802f86509598499b328cad70d4422c414e41db30dc49841e8d0012e0def2ad4233471be412845077bcb522592f249056258ee43c147bec5e56424413dc4f5ea133b16c474c8c6b699db1d3c8134adcd24f6e518854689a5138f71c1732a2696c8ffb09e87ba24aec05a4f149d37b0348bf71d377ddcefff8b3170f1c693e2954ea65d875ae1abcf0c415069e6a508ae78b0dc6aefa5c4100724d49f5bea4039b0a98cffc926cba78df361bd19fb95e650393645279a713d89c604513bce14ce24c08b06570a9e98731174dc2bc52e791faed47fcb9b3c529f07d06e8e3d687aff4120dc0f637b8fab4bde341b58e4dfc70c0b8f634cd22f4b600607a199d1ce1e06ad6771208be15810b75a39dc02ce93e9b6ecc9b3ba00eabb2a60a6de8828d0e758a02a02210d56f9957a5ed573cfd246efe1c2d1e868b5838747c33195758590645fb4a1f6ed056db9d1f2be3f3309113eb667cf571365553f243a5812d47a58396356b69c9f2ea8e7058fd1d926a990ff37d9cc486fc1d8fafe2865c6f0e018da7d8677c6fe87d14fa434b1b59f246e0f289641212f6ee0527913828186c00e1582c52438e447c1457fe5ac8b166ceee0070c58d786c1111410213d5b4858afc5a496c78b8e8bb91566a1ac4029c3a2087709c9178df19da41a958cc003334396d527b9d85bd4721e2bf396209353b2fca04ba124b886b0c70f3eef2ae441479ac1c821ab16f30d4f0f3752341d61f196dc2e4b5d94478fe7bf0cc95ed1b7f5d3281518c1088d42aecb4eba2801c80622fac520f4a556c353b107ab2a27a581f1c2194cd9b0f405dc689b55be4d46f79e82e85d5aa812b11f5d09e4e3a215fbb560f6de903da5ed4436c6ca76800194c0340ba0fdaff4eea81c332a093481f9beb338eeef970ce600bedb83ce11f39f9204ac9a9ee9ef3fa926a3d67d32bde059fd9d120308601d405e9eadb5167fc0bc42e4d10f3ce99f5fa84a0463d5412e7f44c57b63c95b08d2149daf056f3953f02969bfc2bc80dad0bb1d3604dabc03fe5c655ca52ef552939f07df4e1f097824aee755bd1f2f08e67565eba22f12b0fd9d71a5c7aa82b2cb671d0ae6c535303e2cfc9d58b5f1aa144789b295c8ee212f1129a6537f84a8e7ce5400a25e221698c2e06ae4d934ea08b3a1a2dccb5e517b8432e25bfc2f5a5b377ad9397f4d91a4250279da3ac19ed6fb26cdbdbcb635144abe11cb6635fbaaff39bff9b0a818d5e1c98584c6343ea5090e49af7a49a730931b9fa644796195bb013ec8d9a99bbf5384784b91b4a6f65355797a27f7b8856eb8e1855f3c1807a4a9528c0f48f49986b1fc31c01f68f5e4ee268234efa30c2bf7191fe49b8cc80c9c936b4aa04f75b654e1d1ba549f63e6874daa948449cb443e4369cf2eb566495448fa52d3da8468eb0a2974fa99b9345d327bc39dec6fd25450dc24efdc1389246410173735ca780829b2fe88ce06ffc04f423ad607fee7870bc303b64ec0fa828b6cf3d1829903c7382c83b5e04878c34d215db34a83ab2b4619bbdad94313fce97bb62a1864324710515ba2f1a792bf06154d68eae99b0ecc66b1ff55f68ab241381580bc19a73ca1cded0354e42220edec584152b12b098c82128a428ee7885e68f6d66ff73c834971523b6793be2b86cd60ff3a66cea0284d8b972b32db9888887ae444fc396a55cbc259c9cc380c37641fad6dcd9f14310d1d265d37d08eb176e36518b5fbadf63960e2abd901cead710ae5e680e253dce0ce0833475eac3bf67ee2c84e07f5c9972e05a4a82d278d3e288362778e9a730120d19c6180136201b5a83eba1ab4566e96f2e6e18a15ab8e7f443ccee43d462e9f1a9ab190ce9668c5f45f70b2543aaaf00f88a9c61aac89d1519fb4d22a4937909e070da6278a24e23c4e36a12aba73ae110f0273a289b6cef5d380762dac269694964488eed71386e7fae4301ded599bb2f45b828ee40a2245c652f2a7c96d51ef93da0aa48b47180236e30b2d4606e7f155345d8a211a62cd4d275188171adeee6c6bcfeccb092cb8a597cfece96a1d4ec07ce12424887804bf1fd56a285a474384caa322a7c1a7a54bff48a7920a8b179d14022dc8f395971920ca2c35b40b65204d83867f7b38c8a0e842dd16b39743dfd2752657bb08b0af965fff00442b120cd81d3f4d5d2e6d9a14cb8b29c97226188d10332bea092a4174ac7bc2e75fabf87b4be1ad22a2fc76608c1c1fe8d7875822930c407fda01e1bbd1e1022e4c9fbc229c0375d238b08e883854bcf3a64e5c868365dd67199852d579d64816144c83cc5a35a9b91c55b1c634fa4d1a05fa826f4e63440d90dbfe733b41922bcbbd892e999076149b73bc1401388671dd5a2b194f12f9b259f4c27913191c3fbf483f26d26cd20bb40e4f10f120dcb0bf1613a29d665242d314fd71d64252be28681d9752545748ba7806f8459bf04445f1259204d7cd7cc724b1f029c5ea135f3b7dd7f7dfa4cc66fe843bb6216b5163534252d3fdb2ef0a290754d545eb68b69a373cc950aac6617845b7c3892c0d7e6bc2bc09192c4ab2a646f3700edc4dff31921e76e74ef58448a2e3d0826d63b8af95db75704664f97f6a54486df5d8a971724757aa3fcaf3a38aaea79e02a6e2ab28288ccab5c7950cc315e396408dbf1cc338c95faa86620394876d0210f06c70a5d7593087632908c4bae40d80e889f20e7584545394223834ae253327aa8b157f39fd403d2271eba3cf1d9869af49ff7c888d638d09af319e07d698d27c6447563a01c5ca55b61b256d1f54f523a2f7d443397de84dcd3e97d678e95787874a682bca9bbbf127d2df4716e892ceff2656201315c3393b7aac4c9580184d542c7f1ae4802503d8d41ed44009c9585b99eedd18a4b5a8050d4bf9f6f19f00e718949bd53105f651e51b6831b40c92319fb2b8283825c3ae215be1bdcb0500424247e0cc65ae34b677eee7d79e2b640fc14bb731936c6dd34f7fcdc6b0d02ddc3cd7f57aedfcccd58ac9201305b9a0a02e3117e7338cd2d4fd63f1089cbe5b364211a9ae5e236f137fa4fbe5562e22c05a41158a98b7bda158c0785a9499de69cb6518e305d1833c8f07d5bf9f2c845d89f2e167a0aa40ce474b5053647516e2c7c353990fc6611d882b4bb4eaec189e8d2a4473d73bcf588054105c59d67f5a61249efc49ac92831c1531cee0b4ba1e957e036a3e24dd5d54b50188ffa8c214f8f093291b89207a24e8ad72421f85e1bd50811a758c4489a29388ed4f136a65f0ec1f9c1a0a6f7f0e9c4974d0575fb3a70a6f5d6254cba74e92e486edd9c7738db622a6975c3fc0ffd48baafe90e814fd622adf7894500344e046cb7fe5806904a7b0632d4e84be99e826e5272be06213c6cd8dd88ac0cb2587275f6c29da42706850190bd29ffba32ceab097768dd72cc3bda0541dd221cee1609b9ea160525cbc189b220ec8d9b22d2b20b2ab745f4692601758efc6f2b30b99d376f47825b3c7f5b1c5fff064222f0856c9d27d29669d70c1d0b706522982a9b42a7532984b6481e02f204e80db79921e72f4728460c7ac79e5acdeaf2f4e9239760d602a299aa3b592aa97615da8b82a59c2c06232dd12dd7b45a7e03f685f22f17cffd2099a0600eca92967d4a0c6bc81404b1118b1f7abacc5794197ed61ff830cb6864a216d313525c1bbf18526d2de58e3c024bbb501b7804198f168be6ec2094ee02325f9b00179725c4c3f3ad4a0e34dc0fa2f417a4060c26553358114e764c95a78c818559e2481693982a9829d7b5891d7992450b41aa6e7a57d05298571b6e812fe4d5d85a3d10a18437e68517015666d399c576ab8563455ebee5b2339009620a5808b6ea290da2b28b437aaf084e0fb8eb2f289eed640690f2b1867d4d3dff2dcfb0d8676e0134d3ef49a4e2e524582db88cb440f53877cdbb36752e2cd3adf0c3126f889e21f50e0ddedba1550d7df95e2ab5ac55ce1389e9fea99fe5176a587e736603a540fc1d4f8d6b9ea582c7917062454a3febf650412a95149db2d5ba10d4bb475041f3c4f4e3ff684b0c14b1cb51c50b2ac459cc08a788afc17325f79e3aeea46839fbc44809c877e3058acc81bf2b831d164b94d3fc3ef00d8ef76af870f3ebe1d14b0fcd5ffb32e4ef370c499827c76082cb174c3033f3734b5605990b1477e1d9f99ee9e7ce2ba9e906f55736a216904860f3fd2025b01b133bc51d835d0042fec47a0e5e89830d20dc1efeac4fc09eb86bb46828ff809e7d4dbdd8d8d809ab2381290dc6b50a6ddb1dffcc43e00b026401e871c801bbb39278d8e457525f88866d5f50e60a05781ee25f09fbb26a8b75e27ff1d37dcf6fe24191d3c780ff2d5f1b7ee8295f9ba1e0aab96f064c1df0967d43c570622f39a092d256613f69ecac4f0cffa453aec8e0964684c5a369cfd0a3495b1389791a81583e9702abf1082d701b242267f4bee335de714c8b7c1ae3f3f29c6fbf29effb4827ff69d92eee3afd207896125f35527073e11bb8e08390b4469b763aefe12f1b7590bd0ea22191d7d51173764fa8f14e6274f58e13506a0741a6dd8d61e49b40a9ba83795615dd95ade32c80d12158df6964c76eb8e37e2ec52f29f178179c333017ce4f69c06d469a728383c7fbe1b6cdf9d4bd40f0956edb7d0e16c4955686bd60f1c0ff77aaec3c725292797f9d37a4eb0047021c5de3593cc64c761f10d56d12d4c7156077d159e837abfe058b14fbc36c5aba46e8685182633da287167aa288a852e2f2768e9e6e6bc06ac01f1cd382d1298451bf2a539d7c4da6a9881c69bf3a99680ae77f31ffde16ddf74f11481465b0bba76c2d43a5f2fdf329f7a81d076e10c2bad04ffd60a72b5958a0d17074c4c5bf31d02b651bae51d14d18aca473019acc3c2650709c51d2017e29d1b6921804d4f73200ded029d99aaa0528da31ab5a116ecff63735ab51f14e7e2404cf1b7bee886100e1e5657ce7a771aeef51009dd6175bdcc6842f321952901ff6166d42884c5ba693023f0217023abdd44ca14cdca31a19a974dc38803a30db888adcca20a807918f2b908f930f08897af820f271a21e3e7efc273ab55a58ab496c69d775dde944a433cdebaf72afebdeb59df777a889f252a8cbaeeb5ee0598245de7bccc8865f5ebea2f905cdeb603167cbf33ccfb34eca53792a9597f2bc94ca53755caa5b711ce779adab89106575f10ee4aebfa2628c11a654abd4aa634dd55c01cd1b1963645d08152c8c55c27583116f3bba68316adacd0d3c7133d0a433a5539ff2a7979aa913cae35428146a5e50bcf5fdf6c897ef9043c518e3f5bd0ae87ac59bab39638cbef226432ec5c2f30e44a53c957752459597f2bc946aefa938cfeb54abcef33ccfb341490806de81a694a7f254aabc949752fdf25410a23cae9b1e8487107a9e0ae1d9614a92eb0679c995abfb5c2eb6596a59ee569b6db6d92ab5ab5aedf52bb5ba7677777777cbd0414d6be32c76dfaf5fa6582cb35a35b071c067242b58d0b0945c1f58f196244934d52b4df09830250a105a6248c2c41dd51d75959d3b0e85ea4e4143184025140ac54a824245d9218466faf4aaaaaabf4eb1b1a9a2c9bd7e696aa31db2dec4f5708021355cb09c6212ed74f289559a38394175ce4583e5c449eb0c6fe179a10a0a2bb851813a20c38e2c5c98b2101e4278588447090b09033e578152c29627a8805103d6b02cf502e42548c88b096904237d695d3a21840233c5e01ce73293fef91624233119770c61324913156cc88dfec45593884586081e2253da9022e6ac84346848af1a9252caa12021a520a1a1a021a032b42025290f9576ca9c4b9860f105163360d76969751d193bc428729465092fb03461247bb264c507c5a19742851a8410424d91ba703c00ad82a67451814704cdfb4278ecc2300c5b6c775b443e7a2c292d0d5999e23b4c0285a5b76fdb77c17495c76cdbb6c9246ddba4847c94979931fbf7ff9b8a09737201611761be635b03651de6270c7629e6f1e9677f2f3722dafaf0f881f23c364618e79c930af82dbcad8327d82345dbad0807827f973812c0ef52877c0ac2672e1f8e04f02b0af2ad0fefa8b4fdfbff1d4614b6ed1c6f69b5a4759c6a75dd932b05205de9c284866ddb1393cee9b86f759dd4af0c834abbbbcb7128e0a0d530b9ecb2275f6c6c3efbb76ddb66ad5116adc8f499ceb06ddbb6fd833f6bf10149cc10b6c4eefbbeafa3d23ef23aeaa35d47e542d8799d4f5ef420e430130cb8a299d6a839618a858b9d3a6e72d885619e1cc4b0bd969b8be2b8a5a9d42d794a4b124a6e9d384d9266f91dbaaeb561b87cfa1de3a22cfb28cb3a2a919094945a2d28509a6813b5c13e2ac43af621b28eca252b29e793923e97cf98fdfbfffd39670c930edaf80186a88bd0d22ac9832716d7994efe15479aca035cb06d779d942c69dbb66dbb859934da08e3c492521321989ca0464a82972f5d3e5f31cb944386ffff7f0d725d23b661415369ae887669a9b66ddb4ba9fecb79f550b344337d96119ed4b66ddb595e13452f086d92a020dd3384dab66ddbb6b568b66ddb3afcaa2aaf57fdf5ff557f40abd55a86c64867315b0f18b7cc86a80dec62615f5aaa693737520e3dd1ea6cb0a839b191524a4ba57fce29e5e9c4713ebc03e7bc96148c3a09c83a40de81495c109050124a28c618858082928082848084bc99529a4049495aa02439290b04f3f9cd09460b13982cea15370f31d2a5af68fef00e3c5d7f35053ea61f6882e2f365adebf56dd5566cedbfd8ffe7acbc6a72d02e69f90dbbe63c02872e74ded8ae90d2b68989a2454e4e01f6b921c03d36f07469f2399931fbf7ff5b8c19018e6834101cb0503e4b018e6834dafa01530e785d7a5d00e048f07d2bb2e0ffeef76bca4113418e6f8bb5a942530552502bd90a18d1f4feedff121efe3fd4abeddfff6f2946b48883c532f8ccc1e7ef230245d8b68d25e90182bb7ffbb67d39ad00297d30810f34b56ddbb60ddd08a086eb0677f9d4cba72d0d2208f2e910a5d0f51337201efcdc5d0eb7c0185a11aa5bdbdb0264681deaf26dfbc64898e94a98292634cd99fa6f33d05acd667fdba2f81d7e0c9694ea936499b668391be857841394491edff5e14c78d28cc777f3ffa7e1216896b7824791d979dd5ad7ebdbaa554005aed0541a2a5c5deb7a7d5b555555f50ac2f47863f6efff373cbce968618f11da25b4aade6a55952a67acf00a151ac2efbf48944e1d37cfddf397cd4ddf1c77ecb76fdb8f21ac5cc9fdfe7dffffbf5c37b9c9cdfff2dfff0398f1edade03963cb299ebeefeeaee5ee97c49a27046c41a4c7098460d8323bf6dbb7ed5ff9d7c63b31eab84c1c3c6da8dda3b80ed519f5c4b3b8ee818f5766dbf67e77776ddb46038123e662befdfbfffd8502456cdbb66df714b160a24863f6effff7ff1fbad02344969a1d6402449653b8de5dddffff7ff9c4b74d45c6ecf874a4a05a7de3990d4766dbf1e9d0f16d0ee71d95d9b1072ba020f855900dd28a05c40a12621d6a3370a60b29a52a4d9216e129ca296d9a07fc1835ade8e601db11812d9e38fa316b66523555c76cc3545555215408a1c20dc156abaaac91a215715fd4bed130a1c33a970c442adf91f8fedf7049b82f53abda6adb9ac6ec9c8607260c07b0470bf88ca4258c4f39cd60d0b8e1ac0cf213e5b30d67b72022be1a359044f30f0e2981f02094c91899c92885646236990d88cc80384affc848b9d98683c9191c6cc3b9204a192994c94c629b5094325266030200122df0e0c60f488408f98932c88f7f62369c5ded4072041e75004fd75ed7d1d5e83a7264747421ff890c5d46f898e9c278845d100321cd214f27296f4e10c26d8756ad6a21ab23064556095555f5590c361345a24a942059a35476ed36a7a6d1e856248b668e8c9cf78967dd68f246cefbf8878544817f667e66d4e8105e5ac96d24b66d2646488c8e1cc960db323933a7490665bcf8cae818b56dc7c82b47030fae817e5b638416b36dd47270449a08e2860376f7d9d8f1d8a05d62d9b11fc9a2688ee3f837d7b0e6544293a499f5d9b66ddb36a1e5845cef7777d70abc20bce4552f6d4971d0b06848608800470ad062dbde42b07df81fc24308e75c4283039519ee2a1a942a55555555b55aefc11f4a10420855c110c19386a7503201e462fbf7ff3b82d1658d36d3c9e97c2a3b2611e7c28952bf1c1def7847e58561d8628bedb5dbe55a923a4f68453335bd0c82e778474a89a4fb56cad3cadded8ced6a6b23e5fe0b29a1eddfff6feb605a2d0acd644b850a55b3394d39280595097b6cdbb66d4b99d921261b9b8e0b079169a8544e1e758a0600488204331808201008825018c90239d133b107140012455a3852422c342a8d04e44069281a4d411c07510c00210060200618a510724caa3d3b743183769bb60ceeb26d0534b614e6ca17022556e12c87d9abb9a859603f2c4621fd23cdda98cf2b80e0061b73904f2263353836308114d1efd6cdda80f3651cd9aebae0b26375be7fdbbdc7f78c105f917fe8209398c5609d4b273cad4b2ced0aa1fc6fa55748813f872f731939ff76850a762ecab0e0a436cffa1925ee152b521347224774edcf18fbfdabb9f2e7bdbde26728a0168329a5d6af17e96337b1294293f39b456b01d4d281e9b3b8cebd03690b3e6eb93f8fa60195aa2707d881f255387860a9799bfc93650945f25c3adee06393046580c56dc46035365336b49d68f37a8d3e7a56b8311367500494a149a925bd1566d8c0bfad1d69d9c950d8d913b9a4e9b77a781f2a99b4ef35d640c7c8af5c002ddad0bce233ba1a67213ba3622c080147a10cc0c28eaa81ac207bc59ece3a8a80806527b6a750075e65dbc37aa67a25e178dc0211ae40a5ea6aebf8445d53c9fbe961318fb601d831953db8a44104a24ddba21b63dcd2f5f54d7f6800168e744511b8d8f8bdbe2403a157ffee18801cee1ddcf578d3850d7fbe5a0fe8979c25a14fca4635289cca689472d2fe4b0a773467f283600e9924f18c49c1734fcc3683ad723279393d133b2ef01b343599048cdf09fc78da121babf6757a202dfcde9185c1e09806a5d2e782ca3463483f12b43913abcdbf4d82f977917886deb650f50732bd2599e0a5094f449d4a08eab119ca5f3af50b43a90a7b0d535b22709bd693a2db2dccf0011b5d37b2fac0ff1ad644d8d0d2a27b45023f8f28898ee5203a514c629aee94a235c48e81b33c09f17501881ac3cf40ba5ab0a83141b33fb4a237d6ac5f21d5076ccab886c68fd144786fe270356f1c36c4a040be477c27554ee5f7b26cca82baae92f204324419b0b1a909dfdab97591b2ec4f269039111b98f5f57009243175c2a311d2168086f70f132428a72ee0c7a141cc727c236771b14557bd211c800475c8454160cecee0e278311bbb42f2b78971c11158ca0496b433660972bd85ba5080b0983c53cc5239662128c83e48d88d40ce6e139ecd943357fa0743114e7e25321b67d2c23875b4dc5df2a1aee952f35297401614154376d9fc8042a62b47dd86460348b40e00aa9fb058a2bf06a31b27accaab32149789a91e77cbbef41a7b11eb8f3eec4321903764133ab2bc782d43182e2eb5773248ce420498bb7ba003d6069bb820e553d93029ac9bae1ccaf4ed218b8eadd0a34308248b85b88b64cd93d55f65faf8d4ed9369d5a7dfdc7ab1b7935701588d6df8d7c63038dbe138a5acc77ac430e041eecc236118bb20abd6de11a466ce36186cb4a352a65fa33a88bcbe056a371e7a0a9a6a284ab28ab0a402d5fdb08670cd17a5c9d94fbea404755db5c4b49fd78d6b554fdb03b4bdbe0cb494aad3f7d29da7e7cca9713d1de2997c499628ba59b6c29fd20dc2a9e53011b9218e30eac35543d811e65866abb37e178af99a8b5e2b650b4f2b9d9dcccdbf20ada11a7084420d4745418b0285d38dab5abf884affc7893e2415a1dd0424d3499b50f32c47e3a3b03f65a9124311cd74d0defc293d36f70f7b93d4032ca8def9539ced1a33d9ae1c608df450c7b781dfeb698fb275e0fbae56af03bb394d791bef25d7d93f15669a06caca4aca109d1ebba42375da71dc41e1d7214b290093bb6cd49de04582c43a8d7df9d8cabd9964dd8d6f74fb32e5e9487e31c1a5f8531576a7a38330980ff4ea9b5dd330982b094655f67c4cb582b79bd3163350983886c072feedec4f1230575588732ae1602a5179c6cf117713a008f3200fa6bfd35e6b2ccd958edb28e02f7ce1868394cf95808b8fc18e85427afa9920c0cfa41330ed4c7e78fda9d8511e772cf72ca96158ae3d3b28dd2a64d0fc10ebffceb4730d969c425ae140b25a467d865eb2b10c99cb6b998fae8f7930227584332ef1dc085d0f64c63e8ae6f34321f9e1006c264fd877fca626be00032f5ecc40f8505e5e8cdf740badebd5117033a075f6bf0b9994ab21024c1e251b37cbaf31da0c8f05cbc46783a70aff1fdbee7f483c24b973acedc9ddbb7681d71c8fa9326085b4855988375114b292d34263ba087e96e22e4c3d994504212c2d50400ae6e9ab6c3edd115d4232255c881722b911ccc422fa1b0416b148415702a1beb3c4a7e7b6a938cfdf2d869420cc91947d847ce3d5656f6c458bfb74cc77ca247fb10174531dc431c81a2ee112f3e7af059b6103e8dbb73ad494c6cc50ae6fc35bd43163ae8e8b7e9efa9d2f4d1597fc22152d87250645d99843589eda17fb60b4ef935e8cf9e0406dbb7cb31198a41234868a7f7b28816d7783d52ecbb30d041032f3451c8d8ec1976c02d08fc3c958e05ef6c5ad4e9206ab15dc81bb8ec76712f69d3e7b25bc7abc9eecd8ff7f2646985cd1d7327119ae6c6a35fac5bc892ad3c0cb1bc1c6f9a11b3ff9f3fb2fe92ca16dd803aa9c477cc8fbef0e04fbab11133cec3bf71500786d7777e04e61ca4335635afe12d3f2611df379e11fb203a930f3466abd27056a88a5e8b442ac3eaf2044e243118d7a7192919a930c4c294522c90c097659ac5e324e05d5a173a02a2347bfa8befa4419aec6780c7919fdff1d255644ca80cc1c0ee4b569595ba56ccf4ee4fcac6dea1c7cc4567ce7c028607ff81b1df21516a7c83adbc30c03c6c941fb4cd598bd9b88c6442f3dfbbe277116476a60eecb5d0d593cf18edf9bedce6fc91a99c42fbe6e4c58c7afeeef01b41addaa2f569ae1b35aa4d110d2ab04688ac9eaa941dd84dac451c122cbeee5c1a4901714e20c40fcacb0fc34bd8601e5d7ab5f061e8a7833a43eb71198c61e759e2d85eea2b35a79e9257046a8cb47dfb4926c985a2451bdbc6d0f574cb79712685fea63d5393cae17e5ef054e1901876fafb1d444fad7071a369c0a3a6008f96556f50c4c35ecb29de3f0b93ed25e36aad52733f20d64266c11b7e278c4dc4b197b7ddf91c9d476ba9c48b74664e8175f9cca64e59e784b661544f9f5f2bcd8244c44c15b9061988b01f01d81f48ef7523ac4a6c2e6081b03aaa6ad3252e6af69c7b50dfc3da48934ff4b3602051b45b84cf0b66c4d07f93f96db354500470a8584a56f6354c9cb02bb9f1bdd0a2486779e60a576723971e8cfa5ba8b2ff0ea51a454210a1bc73173b130e8442a22939d18ef5595bfc3d7676cd6541f7d0e2ab82342153ac428c80230d2ccd83781acacba99954c63a72b517733b014058dc404321abe93c976e8b98be8c175931d65791cab8109dffaed6963ba3c1b751d51caac761cb660396c7c08b0dc6c30df4dbb60b516045c0ac6ad4de50c57e521b0f5157f44e30e6bf9df49161f1670bd3bd415c260176a3b2a2bf72242b9d5ac06fceffddae16ba49b0237155fcf6d8185143252afc50f8d08de8df4e44b770e6e14894631611b899f039fb8c7907584b06527456c1e69160ff517f85d847d61bab35830900f98568db6593e10f2474f060f034a411942a93441b9221e8bb3a3a5f3c5530bc56191816a47a8865b67a2d3caf5ca611d0f2d271e1cb23ed10b760feeef7960f530b83c2995f9ce870c4bbf8ad980190893f3b163efa746dc5f84e7281153f8667db8d881044d609c901d1ac02b1bb353cdbeecfc2bec312a0cd0940f52b4274ff97d83824cc4340dc26ad01200a90a8cb1b74f70c9f5e3febd05da3440b45484b87e9b48fef10504a44d43a441d4e5b7c848ae48966cd7a81d5325e3bd3c4bf0dbe5b64060cb0c4161054b67dab965e0978067479ae7aeae6b7c5dcabdcc6dddb554a158dda0d6de51e7aac45e8cc171e314067183b5b5956da4c6056983ba3d4824c503d52fb304b30de9eee2a1de79883c8e6132a8989318f538968fb6855bec8e1a85c109b087c43d1bc0699ae5760ee8ce7cf9a3356955c3efee02d4412d0b4929044cf09c41eb407b7c878a527afc37baed98cd04815e314439e587656f19b7903ecc7d813892c05f38b8b820030f785d66449a6ead43401d2961a2b13a4252e1858a58f907ed9a6001b6c9c325f4753dfdb966f4e4edf304ca61605993993b83a2652d9d36914fa763a01d11ea53d4d519b74bbc8f50b3034091558b0cf3724f1b5d5188643177ad6667231c4faacff0e2ac54e4591ac6e9df68820fd575d316f72a7e7a2231eea589c0c5db733171f65f0067a68387d42cab69e63750ee62104c4be27c6b8d297921710990d3ca9dee5239ce6e2351f1210d88c6caef9c9b38582422d70c73b342f30c8aeb94d4325c80344789e837ea337811f131e4cd9a0b3880becf6b1a5df2ac188fc29a04934dec44223aa4c8289a5bd7e051f012112009a128f19d7ec48a6e881ba4a65bc95a19ab647cc8a246be503d7b5b0896f4def0140825fcbb792e6c6a3706d8bc173f6a5c7bc901d002313ca9712a901c1f746261ce549594e6292f87231366da1cf29381a6feaa5d30a7d13ce7c06a65ea790511aa82a617646c99bb0e073489ce6dd6331f14e250b03943b4effdd840c867a32d28ac851ff4c997173608d0f0215169a7a902917081a83175b3d55000421db8f40d75e078d0303cca5a7783673e8450693647f6f213d540a741811b7580ff2188e615645d96fd6f20cf315e4035eeaf8e15afe0557dfba0c1275012b3c993b26456e0134def41f02c42af7e63634d7fd0c4022e030b34bd6c2eba47e1910d451c3e00699b794b05ba1c93f46e174d2371b201f9f99a4ac20b79934391a751c577e531d0c40fdb6292b442fd9d90fabba974242479900a4e7c9feb27aee6df095608d70ea286cffa02f7d902eeb3e401381d13f2f5b55be11a6baacf1aed75c1b47e2e94c7454c290bbdcbef35a977f3a299005a2ed6e292d5f7aeea0ff2f79a8abb7ad4d6d13e72abbcec3ad9f0690369cda670bb43a353c847cdae36a494614e4d6c8023f05362365835207fecfb51b53a47464ccdd2aae0b0aa106ecf33c370ff111ca1710f3b3293c33ce83a9dc8d7f38b549334ebefa4877dc97f7cee578092c1b4faca8932338495805f177b4f1d2c40cf61cd4c5e7e3f5e06d4ec444bdfaec351a98a4ca21ac4194695710eebe0fcb6291aaaeae00d1768186be6f34815047c2e3b9abae599194c6621fe48f25bd2c9d7e5366ebe0360d547543fb96c2680c9fa07d3470efc9b6dcfe2c29c2f4cd78cd846615654e6180cbebb1864f1f60113cf934cde3f2e2551da8214fb664d2900e845e28e9d67fa49f98417674b6527b96959d9c4ba5631c471454b21d598686b2d0407d2927590b27ec88beb57e96065133517e2cd6300f63495ab509070d41dcef79d8a97329a469bfc25cdd2aeee30e24ee4dcff53238717309036bfb869c933a1fd93cb49cf4dcf0e1e464db639ef6ba38ffcc157887d1f2beda59896d79b81e86bdb76b86ae7dae3b12a910b875ba10eef53360988110cbaf0319d0fb03ef2e578143d6c29974b797b4605475020033e46abbd89aaa22d232f65aac96240a6aabdc829bcee4e8167ba70207cd7017645580e06b23391c9b12d3917a8996cd020576e013930038a046a155cd7196e981adcb81d9e623224fd850e6a8339494db256a51740f360966f4c4712981827c7b50780ad356d6df0ee1a1a87eb92c601d1e1090aaa82a0b70bc22fefdd92a80175a47cf7310688a1447ca212ebe508496d854a8886a0d3e518dab2ef7331ec191c29873d5ea9bb36afe05df3705c329b9341c8098a186b9d619c0827104a21084d72b9a4126e51d3c3fd273c127c06366e770f47a4a8fdb9b19b38ca4762ebca8970c819d1f8f3437e4adf64774081db8b3c1e9ebc1ef26b60cd48ba1e56c6eb9055ff03e8751a8701bc6a43e7733eac5a2cffe3824dbf37726178496da00c5235fa1ae27201037aac3548552263e73b342f6eb34a709d5e1f6e1c8f3afbd1e84c4acfced9349978029f677704340bd60a6cdfa7053715c5879d0896af55b36f364f7e244be3359e766d13ba5bebfe9b6ffd9cc12f9a0d6d0c42b851ab735170b97f9ddc1f68acde38c6a542b19ee711d7de94aa003ad27cf7d8b3af9644109b8fda4c21dba6f595ff53ef494bb973780481aa12ade54defcdee97e55c094eb0c9d80d526bb52bf2bf06345091d730ee7aeaeeae7e1e543bd6524081466347b08ea98bd7cf9a26b0989358f520be685e2e93df711ee9a75183bd7b596b0ddf85956197efc9c04122fc80374fc9abb8f96f734feb1c9e05c73c1612127646ee8c6fe4e6c799e2a695161353f8195222675d9896c9dd00d09e738da2a085caa856d5aa52cf047dc38f4f0c95dcd721931ec4e56d98b02c6e1940e78d050596f603ab22c0ce19d015c55cf1a6a9b3c7848cf17b63bd8c1f4bfb438af47d15a3f35785acdc0d771c0bc7ee28b1d6df80040962253ffb3e7a4669b63b2b6f2f7c4a26b13a4dfb30fee23dca204449022227fd81099e3bc70a489809301cce27015e6c33a9dc5678a1f393bdf9f2933db396ee68cf38b3d5714cd39c45b37dac783f14dff0f2bc54adcc546d617bb631aba6b787743e1007c561476cc4e9f735d4af50c031edc5078bc498eae92cd40449145158b9eef94d6ff93eb299ebdb35877341f67ba002c458b5b129466b6382691f55c181f927ba57e910707355210e546c01e8fa93510bc523787b34b65ac0a63a406b1b2feeef7880721c5fcecacbcee3574ea1eab81e10a87cfe1639b156cf40c9815cd71eb0abdfe7739151d960d7b398ca821931a582641ef074bbe961cc7ad07da493b57be7619736b2904c8054c44739090e72ee34be5116277e24d00a86087adadae8449394c4d743b459f38de05cebf0c0c9db6d1925c30bbf95a9d09225560d9c31cb8524f014522abdd64ff6b6c226542e597f8767fc2b266a4d13f4965d920b75b7bbe29b23a5f17268e5149a202c8800f1baa96feeaf186d0ab4390e4bbc97e5c6ac3a4fffe587dca6f56aaa6928db30e8675b03e238872693bf3899ba6da8ca1967df35968e0f2373e19c39b6fb8d0c946fa9fbd172db13f4f90ee9d68850fc8797e7a582931ab4c5ec628d285dc06457bdea10318110e88200445eb794d81374fdf79060c97400770468fc283ca4ed7d3b891281015ba2c3a45ce76463c9cd83324367ac70e36a52ef4ed6ec2d7aa14a5e317ca3b00d99dd6914afe0eb956414937f093549f18598f21560a75c23a7178ae6c4ece7954399ace62ff51b22933c10228d9b32da1a2352283953c731577f1d384d53d9f92b3e85229d33356baa62b813e37f509d1127959c605b0dc4eaa121dc243052144151b6e6225abee6c8be9d277546daf3bc8a8dd7ca442fff8ef355e2a6e7a1fb78124b4e4d0e9ea35a5dfc4824a633eaa405bb13044875c912730e6887e647433cc82459f41b03281fcc627b640d73aa04ba5b46e15892fbde12217fbe835df90ff3a32be3355e993207f82c1c114cd0bc978a161529c5043137787d4b7da193ff87b6eba2b55e1e32e31423e936af5519e7f07a5ffd77ad31cc8b10411ce0bf92a54cc2652e9f410a35a18aa299babefc14613a3f107fbca52c6a76c8be54c4e25b9d7069fca4a7bbd2fea6a01d1cb0ed2f8461559d164c5b9b5ad733fc0a7dbe6778d8a2ebac5eee54ab23f7f0db36b614a3adca4372c08e4c68d9a1ec7b5602572558c9b9de9bd96f0552c5bdfdb8103c83cabaa467e433dfccd83d053ce6ff42d818a4eec2cd89bd57fd4913fe9fc83fdd1b6f90ca244f5062a556e3f37da13b6d396edfe28a1a1722127beb7e10b229649b7ae6b6d7e502e86633882709f09e2d4250efbe4fb42a03e765dccd06094ae7003762e9620c4113d8725522a86847254bac28913d397a8f1f03e2572b0a3dce8703a2ef3b5be8beb930c4266070226b2f83fcdda6b0ba5b31b062f8d7178f12140aacf24c297e51d20f4ad8d08b62164c76a96f3b0a2c3089b057d6820769ff68505acf3a6d0514a16ad91bd43e5a11c312c04e1e11ca2a7494ffc5dd3754afeab1035b2809ede17d0fc4c35296ef70377a91283a17371e4c9c308cc9f130236c8fa647085f14ad0a96016a1fb6cc211b3ca3885cb83f791170767c39e48b5a3ee6f308aceb90a1b4b338140e81e258083a098c1a13352361ddb735191a72cc05ce6dd42eec4589e176dd5330fc140e750b4fe1ebc5b5a7b355e91a519b90865d3aad1fbb34db8c410011122195205e92e58858c8670c4bd75cc9865e756c53163ac70d5863b85dc85c6e9a2385714f7635add098d3a80203fa047d0d5b0f360ca89da93a2f42c8a46585c5eca73e145364327649c97f20bb3d5fe40fec7bdb0be5223b535e1284da0794665663027f7f6400a270b9e0e5d52311b02f8aaa941efd44f7d119d9183cdd0231e27a6cc1dd0879facfae89e45ffa70b64615438aaa8085c2e8d2afe9d6f775fa3ea4d5c6c4accbbd326cd038072b15244d8f2b41ffa025306b675a88d473df8c020a2636a490c58590558aa2358fb03cd53afdc9df51ad5c9fb51e39d4d6dbc25dcc4b46e0a67f3beee0816a078db00c20f64c04eb2a88088b83e4a376b9b693a2633297d309b63d230d464bd35f07897a746917d36598c2b8e8de1df4999209ed2a3a9937b38b24ba52d9a24598b248f55e2e5b4d9bb69dc44a704cb6a92ef5e0399e90528c377e45ff6fa5ec0837414ee335437e12f84cdf879a90686feafbbcebda632d85ef11b5a4505fd6e21333f9bcf9dfb55a4a30d5bf3d9540578b569bc7c077737faaaf622990a21c1c5589f8d5e574ac1188705d10c75841b3e9a8beb8227c68f27b454ea4b3385b780699b68a40f445f89a83a228f5161875ea1e709c24087f541894e8f70e5996ec38ad7ba9407b6633a9978042731cfb9bad3b4b3f4d2812a7ef205b74c3556e6d2e5f5ece6916c9de230c5cb5706ddef4de0d7d18c7ce71f198f8d070482e89c77c82ef50a20e0db637f91a2249cd707e18bb4ef7630a61441f4ae05788d773eb7d55099e07000783dcc6663ceaa24a16a4c0ebfd9995702e45d9504d885ff599848a731a91eb1c4728bb824e6f15201d1b21351b2cbdac2eecae29acb5e04b7da20bbc6d6fb0a61112b742452c17846ed0961ecff2d0507b724a0860fc5d11a1866a5c1a2a2c5372304c7c2d161b14bec99cea6cf4ecae8340ca26611439b6e6cd4d340f70b67fdd78b30af2b87dc080faee824f9e3735aca389ddab03238a51693dcb26198a6281a6ef3d8350052ed549509b4cb8ef11fc776fe0cb2c78dc7683c321f233ef5a53c65a54eafae4133c020b181195dafc7b9a790c2cca1b9c6482a0d9d5cababab85c184490c11504b8221f3e4b55f9aaf062b3315a8cc6642983b4898f64b523166dd766e5fa1309a0ba4d5b1ba4b1c259a52bd8c6eb2bf9854ce6937106b3848d8d776bbd60ffb1801d97576c71fdd5901fb5af0f48bc97755052f498d30aa03bc46e0c8e81c582c8c1dc93209cfe067372472af83fd74d42731eed17ceb0e9ae7de0cba8698eea619416b32b44a1dcda5c0f36ae46fec7704027f08532bc4da5fa9ce003ae93867be82fa5b7fe3869b6bee779ad6ec8507f6ac6488926de9010ed72f9329e1573cf42eb720ce2c55502be1ba15c8510d863e2cdf1b95c111002cfaed922424b99b67e1b8f3fa215580b9b6a85724bf6045924af3e7a1ebd18f233439886ce60d44a2732f95f67a1919aa1751b37378eb64485cfbf6214f70374d88480d3ae7ae39d0560f31fd23e0de2512c2c468114b7403077fad700f59f7a9d932b4cd1a3468bd8bf97741ce528f2310a426f9f344ac9dba51132163d4065a29082e68a822241110ec7053eacbed56cc8a85c885efda8e316a0e31cebd767a1150b6bbdcc8ff400750c9bada2066eb1fd9753b61aa3eeaed879b6c1b99627678042146395dfb022c55fc072f7eb27bf607a69acf4d58f3c09eceeab4ce05a9d799f3725b8f3a5b7425a208b4256bdfa64ca3cf16c7c09eea0ab3c7af9db178b1d6ba879dbd624b1a796ceab66f98e632208a80d5decd66f7b7e234ec85b842d496a23285707ebb6cffcd0ab479555e1298b72432aad10d708ff5ad575a9917b0e251ce5dbad4f9b31e43e953911d747e20cea7455a5dff4beb57b8a1a3f63a7256f62fe7b777c34c19a985a25e2837eb3984449e79beb013a41e4aee965223c925e59b6357df5d8dbce34f012dfe75f87fffd8648bda66e01fca9983cd0f38971dd9b79eda3c253732d8b786e5e094c7da47f57e2b72b3cd3c93140877ddbc99e7837c3959d9bdc2595f0b77062802c071c317953a17e293d72fdf925d5cd442592d8cb7412390c428df0bfb3693ad6ae6ce7bcf69c0d56798e20cf8e95df8be95165baea88c73c62811d41f4ea19dbd16f74729a428b465c255ddc56d03e543d5af4923925041222df388bd882139c47fa5ed4736f0eee2b74c5e7986995e809caafd761d7c39302b215024dd66f7ec060a78e4f77ecfad22eddc54c6a16753a37f3550d920c140c2c4ef42d4a5cce8a1889f4ad9d30925d6791731d4f36d87719944981028c6cde5a0876c316b85d3c7f1daa223ee6c0ad5d8dc60f203a7a3dd35ca52cf3efb6c37751db6f37854436aedea3aabbaedf4949aee82b7984d354a5d7f9b0daa37cd62be4f9431cc75be154a1d4a538b780e28a5549a32ffab9eb4ebf008a331c4f917c16f95d7efac6e633e4b993c0b8607888ca43801d6cfacddcb11bbdf33419243011299021426844cdcb4bbe936655dd342e12eb339c0b508053bd875b36fe494a7f09cad5c9183000478d4bf5639c0b0b04c04c1b003903f993be019e86384999c7a7f9f203a6e31db6cadadf4acf80c3a20e400d7fa596cb6dda90447fe8d721405f8adb5ebbe80da39124a137ef10844ac2e488cd1f6f9a1616b10f08c444ab513f6a6f85c9c23e68ef6ce3efe9078d7830e1a3caafe73b54c17e5aa0a6778c420fc9b26ca3aa6106bdf6eadcdb3e7fb53fa2d7c66a6c60b2fa0b93dcabe532620fc137dbf97438f70c68e4923640b5d647244464e613f30bac374e9fa7fd9a996c10849887da6f952f7b4a09d0861265eed0e6646764d1fdddb532151f105b89b1eb160751465ba8e65a920a5393fb91fbcfa3da53c10fb4460e14c9cb0c08da1bb40298c6dda9521572f0e1d1e1c1e2b05e99a4e0425c72624e538553e20c8ec66bf2f06ab84aceb84875f8b7a13020e144fe4c1f95e09c7240a8191551fc17ca49873709760cf8bc18ad6bf613cf2260f14c60f262b917969ad08267ddc0eebab180538e79257d33a79a48746ecad0799c327af213187e4d189779ca117470d2d7a3b7163936bcf6e6c3e8ce6377ed696b017fbb548d8c464f760aceb231afc54fcbbdf77577294e66b1a82e9722942f677c0c39a3c974509925b183752b7f74c824c48d52b6c26ab11e6bac3cf4407086e703fb84efce4d13b26a64c2fe015c664f77845573b7cd91f3d4deec393d224005d56f47b9b428e09deff4fc842a30bf60bf8e2d16d9ccc72791f42576b025f0ff568eed1c40857e8ef4d55a1e669ce8ba0ad7674774c15e59e802e197ce7f1f0a9402838cda76888b6de83cb2ff6aa43354e50a38dea12ae84593e6e28fe388b495eda62d21850902dae53bfe3b666c57d9dd75399fa64ba3e22233c05bd85dccb6cce610f3e52c2cd8826199f00f6e7ea9e6c4dbc13d8d49eb3b0aefecc094c94fcbd2e554ba41f2143efaaf7f2bb33f3cfbaea76ca696312122e46a80d8f2a42c09e89454aeacbdf30cbb1e5ea4d0eac1a8d8a8cd1cc5d71012f7c0b2c0ef974a71cf15b6675bc62302bf8f4e6671ef019e5fbce26a5c73cfff307f40e1a7980cc4abf3de5aec3cc86100252934cca592620a87f3cb2c7531dd2adb42a5c6ca5062d5c8505167baf4bc1194068f8a12c6f0a60c4831fae4208a2c3e8f0c5b847bd6d94196a613d6101cf9502231cd05dbbfab5812185cdc37abd51407c26a766ace8c46dbc43d287ab0f178e208dd3975853bea23223bf742c49388d42cfff2e7177d28e260cf8378cbad06a75c68e9df0ea6479333f35bb397820ac12047e9394382e89644c51433c921b4bf48e4528dc47f175658402bc3b26c0a553a5a615d6f25970af7debf14b717831479e399a25d88280a2bc9db5693cd1ce74332357af2c2237c6ec71557990cf984b3c76971cfa9919beaaece107140e912c54272fb710e9b81c7e37efd27d4099f15d1ac28d3b69325e40cba3d4a3a19ded3fd2e31dee35fa2c87517f118b8f587fbac4f772092c641183dc1e6d2296de8f9a8736af014ff4bddb1527172af22e564eaeb113534302a9b7c0ea3672d8bbf53f12ad4eb8a4153b7e289ca91a66298d10209dbb47dae92718079103eb5cce02eb53e208b4d3902cefc9f2780f5e85cdd00754dadeaf9df18275c8703a602ef68827b521063381087213eb3b63a77906db67ca0fa797376650e9fa1e66f7802d7529a154de8ba28d7100cdc427b01830401640c63176486803b593a7ca2e95d98cd9b8c3a7f50800de9cf10e1303765e971cab953737ee9457766dc8c98e694fdce30bdf0abec527c21813a065e0fe5f2ad4ff4030bb1a6ef485921cfbac8f109ef58b2d284e97c9872e0606c5319e78a0c8eb2f675b19172b604cfe52f70ddf3a3aa323d1f0438b6475ba88559ad0f26db4f83c318728331d2c0d0f095ec078a498d5e082a34a008e7a47ff515d4d7e88f4270dfb66bf45d013ea6019e1f29ada4893d213aba1fb48c863c5be505e1ab19e29a81bfb9eebe281ac778b41d53019964cf0c8f735a6fc634caf8ce4940dd767ac860a14915b4a4ead0a9d5777742bc2588d92c1a4b0cdfb9bd12e1faf9c3068be90fe3ad020233901a1bbc29f952773838560f78c5dcc6eff2d914aca5cdf0d336444ec1cca5656dad7e2833326098041b28becfa9a6b3c9c9e99191630e885b68cef7dc003db52a670831e20f106e8090a6c942eb6b30eaaeb9ad0f2212d2d4c5fb53f05a1df46968303b8acf55a92b4bb33d4cec275d9ded49f53d76e813dde1d13d861372a85316a2c8f5c791a8a0eb2e04e044a4b35265c7a09a7f3266c05813f8d4162490d1d47c55d3a708120d36001572fabd8c2040043de8de891e086787ed11d7e3118432b81248501c611d2f91c63967a0ff48f96d765449f43c41dc70c2eda1e03796c04aa47b1dd7c64905bd036124b73a1a01942f034a2816705a20cec24a079d0e0e5889797419f8857ce0caafe084fe7efef64f02aeb1a0fcb1bbfb9785e5cc2173fd6bea4a6868dc4970b01b3991e4630360a1a68aa26781203857e92328f8b2732fbfc2892e5a9384ecbd09917b6f99524a017606c6069f07301ab087ed0b3d8c46c71c06fb5dd8af9922ab4648fb2c0c464545a689f0b6e73cee7b37f76eebf6411d2deebd754792adf73850476b2bf2afcc3db3bec592d2ffb503ed64dd386e999979b9df4dcc31eb5e72b3e3e4b6bcedca5d76264f8ad7e2b28cf7babbdb84ca7d3310ae1c87f35c50c7bcf541ff481abf5e823a80d0fa7ddff77d6394202b2716bd1e7ca06e105e0fbefe0b9d66d8fc8d38ca7af3deac7d5a149a821eb984b8c7d98ad439e158cbd97e07f79bc838af818cae55192152570dc41bdc01ce03794e4fe388b38ed1b709698b2042c7663c6fa1bc234884116684b379a8283bd6e2eb15b6de157eebfb40d60ec1016bd6aca9df4356a18ec140e77793e3faa863fe43ce718f21a1a1203ed4c3879b99c160b01b1572daa5a66da0db2d116159a8382e95081d5be25f5187c728c57106b50f6f36e2bc7931c88af66e906f06acfe2c8ddf95f002b8f274c1c2dd19e1ee06ea60673292f1bdc10f073fe3c759c1dfe620dc209c35cfab47a4c609c75ac529ea5e46b8cf20ce7b2cea046de57ec7564eac57b5da85a390da79ce6b50ab5d38a4a96a10226d354774258ee3e277137ec76c1e66f36df3b2b109b7a76108641da72b1c259871c768a7fa6f22344f7f10ebe78f3b25c214833a26d475b0eeb8eb1e369bb339e7d2d2d2d24e69d0e0557bad321fe9139c68121284d5faa2edd71be2faeffb8ffce77b90e82988ffb87ec68ed683398b92415d19f7ca674b73893a42e0f731336f9be46dacd55d21495c24240297f6dbdbdbdb3b7e902b9811d1d155ced1ffff1191d11591d111d1118d2b222b23ab23242ba2abffabbfba6a6af567b5becdbdbf90ff74ef2f9d26cf28deebdedeebeeee2ed4834aa8c790d090081d731ad5ddbdddbdfdfd3bce7b73e2511775ea15cda9fcbf8d5f7120a11b55e576524a29e5a6c43a956ce2254c78093731efaee4f52e2ec5853ee552de45caa7a438eaf0e8ca75abbeb436fa39b19f78894f6dbc2ec5719ce4bc4bc7fab940718182e202d53e7e2309da715f4f61bed257bafb4a3ff5d6577ab7aff4e852cea5a7b47371a9daef5cfae98979093bb804a8b31fea2c8b65ebd741e9b3715f7a72cbb1c96df36df3ddb027078e179879977777993f6e4de16f3b96cbd97706008202712c5227974b8c798cfb421dcec7d61bc12ac76df5852e1708be5cf45f0f12515104855cffbd055e50d5ffdbda2190bdfa00ac8e44d508567d3a4febbfb025c63a26c17069b2f691f102b8f77751d631e9524a96df8345dcb7604644232f77e0bd371ac1aa7f91ffe621b77307fedcc1b666cd237f630be6e8a494524a29e54c4a8ee38d67409c434ac9cc2ca54b295d82e1eec8d9aea71bb57778f5df9ddee716c0b5fbdd9ded8dcaeda2cc9dfd061054b2dcb93d3467b3d96ce5dcf9a3632c472661c666aaa4ff8edcf9bb33da34d55e1b26364c5d68b3c48689894df75db7dc87a92b72d5d77eb67af06b34ae13bb8fdb3eb146db7e47095de7e96c986c98fa6d96b44fd77e1b26edc33d94f378d0e07fcfedf7180079691d03deaf8d5e9b250c6645aeea585bcd5f1b26ab662bae623055555673bbadb2b26152c554bbbbd4fee72aae62ae6271a45572da34b18e903110bd632bf752284804111aa0f4b4d980c93eeb9352e729b57989eb00d4d0a11fdcdcdc1d827d399f96fce8ad92b40db776770f394fe380c201f918faf1a3bd7d0ef5d00fdf6d877eac94de54f287aaaaaab68a2e7933786b02ba4b4421b50498244b44b1c493845aaf4381a5b5742cc04bce2354c4799a4a0f5108159d0974db0bd98488cf494bebbed3d9664645384989938894ba93b6efcda527291d2529b54f7f23b50f735292f75c62ee095bff35eb6b75c3d66f61eb39dc9698c35b16b78502b87f76ace7fc5100cd975efed6221dd67ad0628eb5d1d3c2fe30c08789238ea8e35a8d33080630604e3a6f4441f7d9a348d81f44cb85c8d7776eef4a4d79b7b856f388d971bbbbbb1b14192ccb56e8a945fc2c1652d75638bba05c59217011cb4d8787fff63bfc37f14be0ba7d8be5e489b2f6d39eee39668e7997777799d959dd7d315708e7dd7b55dde7362d74dbe64686762fb9d9719213e3ecb22ad589f540cd12c511c963dc0e94fbc989cde3ef5372322b590fc7a26cb63377776eb9979739e6ee2198a8edde1d7925d5e6bc59adefffd13e45435e0ffe102a3d5eaf44e442eb01abbeb8a9d1ec0d2f5147c8f53a3dc0e787f5ae580436570fc76710f6bfd043d6ef58ab9b8f1f2404394fbf2b5c5f5a2bdcba81e1d2380c8184f56cdae250f71c9d1db7df064d7cb0e14c165b48e0e9f06f875f980026ba28740143112c44b658d17ea491210a244e50c1428ab6bbbf3b2b16c946e06dfdf96744421d5f013150231288c410c8fa5550f0a32cca62ef14e6d36538509721e054ff8fe61dc3f232ffa9c1b0c4952f2be06206633cd1e1b483982564b0c882865653a18a2f4fb0e041064fd4508226222f3c3922451854b419e5a7088d245ad338819600261a441762b6e080e50c184cd0988b344c38a104102b64c181c64ff9616728fdb9aa5123e66ddf7ae0aa2da41631ebbdfe9e7edf16bad5f1ab2d2b8f0c02f7db3196c8485db79caed20cfd3acafc67042838810aa8a622a0b8d0fa480bb8d0c10827507ca8422380132f0051e5042c663852c322832d686090064a6a0b5ab7b02db1de262c42c5c56158cf51fd7ddf5b3575233f75cb49df7fdffff8be0fcd4ec16654169b7317e8fbdfef0b53e78ffe048a5dd09738caea4f234bf94f6c7958cf2c66fd93047538d9bcc7415201a66a807a7dfc7ddf074ae0eb3854c16729a6627e96ea1fd7127701c3cf55e0547e36c3cf67180d3fab797ddff77d3bbe020942bfd7a1f4f59ea57f8a482b1ac8742153f9fda97f6066fc0a97f689ea9f22ae27a929aaf62940e57726da67a768a8a2f27b9583e177ab7e7ddff741d19daa21aa82ff1564a9b5c1ef74f3389628283a293ded46e4a9e6e167d5fe1677e1a98eb1c8524bf83d2f64fde7f1671336d1bef06babd562ed0f50982a4f5078028a48175aeb61fb53c3a2e5892b544e38796181d6faddd6cf6db5586a4a3e5556aa1c35fad3d26b8bb73b5c1b88104e87e33677777777afdc26a5949243e81a0a0f067bd9a572a1f8046842c7492985edc872d088f5cca2a4a6e6d756f8b382ca2fa14770c94356094a406ee309bc4ad9dcebbdb1ec96524a29d5c8624b3ce9aa8eb09a43b7d0f1cbc9c9a111eb01fa1ab31c75939aeaf2514f3ab2b31ef4ce7ad073c2601f4257c55d1b1c182d98923aae733f41959dc81b73d93d1776389a50e57bb79d2f27a5d34f203afc41e0da75864edc3327d203284924a49414f6b3a9e3caa9a0fdc736362908b10a44486d1a474971773717326da9b8ddca92e4a8e6cc82facb2072673b5277777372e5dc29a463dd494a3f545463ae6c6826b01e4c0007116e9aedcc646e1b9a202ba7f49d1cc599c9fcdcfd83a0e91fda37b6aae3a4b02db3937c93ce56a2575757bd396feedefdb3997298ba99e655fbdc52904bce5445d5239bc9a44b297b65cbf6ee656e666ea6f22ec6e872d8a0389396dd76767777e666e66626306a7b671f0005f1524aa95ca00f82a40771d36eee6eee4f06e62a66287a7aa89a28a52abb6c25c7706f5fdf755f77f75d1f327777676e666e9641c6d42d5f61dadddd999b999bc5f897deddcccdcccd4a5d0e5b0e1b949c9c28e666e6e628ff6226c70c6856038837de80663ccb0104d4fc838804a3a195ddddcd4ae29b8cf5b43337b73333333373f3f7ccdc67de2ceb61667ee666e666217677767c7e999b999ba19ab9a7999bff6689282c6f000ba827a530d8733f1537594a4a4a3a41842112a42c555e30959939acc011abd0dd7d3b1c6b9595462f9ccecccccc5eb8340a7b1a2f6d99e536039ab5ec6eef5eb940ebfcdcc44fed33c5dddd9bf9caecefe99939b8e1856ebf1c333333333333d32a951b0c0598e1967f179662f1144b318b99ac074d888efce7fb21b8c0b4502a95a5384b49b94230fcc239596a3d70d120436db8c5023d10f4c0f97d727aa0f716a0a2055e22fdef87bcde0543c3521cc4feb013555cc553e4aad70ff99efe10d7bfdee63dc926943af37bbcde254e80d2773d2854c4c81b112a62848a6fe4e5a22b240a127356622e43688151a92e859754ff25d63318a3b19fc53a62f91fb9b39ce52c3f2232ba22323a6239d191134919491d214931d1552c7615bbba32d3d566db9cf18de2a66fc7519ad6eac9c7faae8be2908feead1a5a1bfdcb8469a8aa4989a9a9a9a949a98ababbbbbb2b24a9c8900f1264b1a029dfb068f367f0c6dbc25148dd18673f676b759b7227168bc5aa96ccaaa9e289a2ac6f89e34769b38f2ae67e4355357c0cfda88afd686a6a6afa31e4a36ac8c78fa11fb2aa213a54d5d454d5545515f56406a7e22691f3152ecb1533504657b25c11b50fd7c9f302dafa11666333250ad1150765cc983ce3f5325e49aa06dfde0fec6703193fceea72fd06212c9c394fff109521ca9b1ba9c1cdb66d9bfb2671723c1cd2547342a4ade2c88e754c36a3fbcd689853c7bde2244cc4f302da12c79c3ac258221b9d214222c7eeaecf7aebadb72322a32b22a3a38de808e88ae8a80a8634447475c5af5c5df12baa9c76f5e01dd7c3711c3767cc0705fe31ffe997f5ca8de5ca1613ee9a767b3d90dfb4eeee0470de0e0e30a107c3190830d8149b2abe48b2aecc49be6c1f9fbc62c454af3fde9f3d62a93ff091a4f657c1576ea8e39734039719a254b0d2967d3622b5dddd7f47573faa4872c78aa9fccbe2ec41c5c5759e6f9e5e2c7e36f00517637e50a3c44c0e34116490020c9e9c5c184384d6dd09e12d6884bfe4c26f19946119ea5cf77d044f32b7cfbdb75dd7dd89e37e095cabfe5be8bf4ef3739a879f73243fed580f3925f0f085081b64a0449627de8a0c284c31b28408121affc73aea0af0882da4d3e34046163a7eed35b46d3ca1f259efcded37bcd0af1068e2c80a585600420b18224823a587291da86471c56374023fd1041a95222307a3055392d12691821924d5297ec00324af45ad47f2cacf7a8f7545b9b65aecbd7b21ccdfdfb13f45afde6cfd0c29d2563b9146c76037b2f4cf723a27e784102011f58220d094b1020a9a16a0b4900393941453b4feef8fcd1cbc0d8810657444924febb675635ffefdd83edd87790e9efc1cf187068df6019db675031441c7a7f265fc33fe8fb511bb321668095e8bbc56e76ddb37df6bb55ce1f69ef75f0886e128a4ee17b63644eafaad19ce1008af59b3664d1d6b3b1dc3d1847e182cb268ea210c2d5b90d0d806344d5e70e5e58a16a0a0f1efe46d89fbf847e0d1cbe258a08ec971dc823f591c377fe4388e9b1cab9bb3637120f8afdf401d2f8f2b70a47a0fba7a74ccfb97f7ae1f5f2fef5fe2f8d5f5bcfb7abdc4d1f5e07b2e7e90ff63ef85da07fcef5de02734f48922748cff8c0f24fe39619b6fe1c8bfa20e6ce44aa363fc3ffca7264586a51f5e4015059927b415e3258a20c8a4a08b2d41d0f885865e4c7df076677bfe20fe23dfdb429dfded972643eee55b60fe268a4358defe707025d603a48495a5de238e5279876c3f5f864358dfc9e71e03db4f2a3db69fa2cefe76e110f99ca8b3535362a254198105c90c34580c473811c55496a81a36c949de720b6f777eb2a0bf6458e92888d1a46f01f92e69cfdfefd109a30fdb96a580fe02a1448b105da6f8f2250bad5df01286852d56d8220634b4fe9d1cd2b5c1b28bc7bf3bbbcb01c93d776d34a089d7d33ef29b71fbd7d33e630ed9e21c620c949835582001838d160c41e405342f8471268c8ef1bb4f9ffdb0feed9f34785e2d567999fbf34f4a969b4b87476571bc409d5478511d7b4971cb6ddb36261cd74d281db08d4b8df23c5007ec0375c068c7c23147060d74a4513aa4ead60c10857654ddb1355597353b6e73b9d8b5325c634d87c78c6a535b1c3950abeafeb6ed6fe08e29ab368f95a3a3037774386e97ba3fbdf975c88271abd5dacdb5dcc148ebb2be1b26ca0277b0f65bddddddb52cbcd4f23e0ffcc0d981dc06822028416f061700aeb104d5c558cf00ced0b1a767264ed5fd761850314945ea6a05161fa05861460c1a922e5005981f946c40e108171afff24f0f8a97b5254fb43843268c24aa2fec059429767082a48b134dde4b4b2dcbd392192c6a564822a586e40a27a92d62c084164c30e1f18eae085042796e800a628a181958e9729454a5062952383c01066f1391ed7fe5d8fe6cdc921953a5091d9a7ce142191d4d5990542951418c20ba703acf3eb785b15026b4dc0d03f7961c6cebe742202600e169002eecc50644f0c3f8772af175abbc3efc5ceb6cc8957a3713c6a16652e69f302b74a4d5a351a37d3a07b6f3de0642d0ad11896246490a5f9cc810d1419a224ab64461815314099e92445d7183164c98a868d2e187309ea4989cf4f69649c117464ca1e0490d5d9ea460050baa389284122b767b9c2a5d1d21f960dd2a501b4183126084704a228ca9143ce143154638a912a6055778bb138018c48821c45598316ad4d440eb2d549254493ac207275a3fed87d552f0c518576bb48872a18b23be70a2a4431659ce3cc10fe35ffe6924db38e92648d92c003228a022713765b438524493224ba664d4d3121ec43c4963c57700013f8c7f8d02a0258c142a294d588185c65310d14107196e1023860f788f04172829446145ca1315377021a50b162c5439020a8d7ff927087a7bc5f840d5a62c59e2062d5fbc508184c62f043106922bae4c4186c64f74b1a4872d569044191a077420a287215cd04313332378dd401ff0d48255172546a831c2a40523a42873050e52a468698a8c918598334f10e1c50601c6952d479ac8600505bc827eeed25dc3c59d5814dd8979b7387906cc56fb3ce55cf6596aca3e6799edee9252dddd5d3064ea7e10333533e128fb41fc6769483dba59a7dbe7fb20f863fcf4841a961fbc3c89210517525c416315d668e1c40718be709ab2544b42010a199ac4acc0c8921d226298a1082d509e589841c50853154d46b48c792985c1a40417279eecc74a388a326286c9551229581ce550068a1454584a03f52f3069a18b28b640edd06450a024c91054656e48a28b24351c69c2821ec2c812e64bd31543249d01631f26822f42f0b0f4e504235fca487169b282253088a85014802c505145a001e2c9548d19b84085252e3481839a08745133450ba817c028e322d2650b31495ee02109c9db9d1b52e853d8cecf80b73bdd228d3acf972d49a89c547171a40c8dc348618111399051d3021affc754b03e6441424a150d2ee49006cb155140d952658c9125bb33fd0067c600428c92169840e28126b808838553920d6368cc636dcb115f5459192106aa0c6d9fa47ce143176028a939523bf2c58814667488a2660a087c214673b382b739e79ccf2cba5027ee079c92a8c9e2b6fd722a7fcf4fe37bfffd3c4f6c85e3c60a61a10ef7b272393424751d763bc9fdb6cfedae381a75dceeee6eb76d5be77289305fd1fbc0b592f56cdf77ad70e6748c5920277e40b62b8ecbbd64715dd775ddfc6eeb58531c856a2716ed17c9e7b871c551268ebb2f7138912bbf9617dd73674ef798b3c3fecdf9b27f766e658923eb65f040a728c59f322350fb6c536edb16823feb77f8d7ea9cf2b9ef6ab5b995a253eb5b22ac73b834deb6beca45f337ecde2bda9145832b771d0b74a4b0f6e11c1a53dc7eacd52eecc465fe183fe587455dada0440b2f62e800c50c3440260a891a94c240620cd7b1621caca1deb736f8773d0e8ca0523fb27938f042f74129b21ea8d78614747c56a8d3fdac21ee58b975415f62bb2d38d5c6c1843907b908f44154f7412c96330deee06954ff01721abc80c951fe63d79146e54dfcb5116b1e5e40b81dccdaaa31b9899db8e2071deb9f951381b06c6278b11a3bfe3dd6aa8f22a8cd108a582c166b6eb5eacfb933bb151878e26824abadefede9f75a40b87adf216f6fc7de09fa39727c3ccef13f719be7f33acf6bbdb3def33ccf33a1cef7c271639a0f84eb94eb846a200aa613d24c09838688da0c2c5cb1548507335167683c0417303b80015565cc0f566871a40a19682073048b9d408045d07f193dc810f6638b300f8b7a47fff61ef6cb20374e375228ffd651264324affddb07997256242fea9723b408ebd8263ee730a6b1b34edbc1b1c28e0c2251377421051a158cd927beec30a6ca1a29860043e397cd2467b5edf7e8d80e756cbfc7898ecbc450057969bb3a1368dac837ce00ed07edcbf667564c54a1a1d3cfb57f96a6d3e20d2ff667fbb117a868480fc012f9fec926fb407f7660bccca596048929c67c21c30a338c41e3c00b0c2a38a1050a0c5068fcb2a82bc87891821037d0f809258c40c19234505a20a1f1376f5b3c6e652c507e0eb61b08fcdb6fdcf672ebba35ddfc1dd299dbbe0bb76d73626db2eec4d1e4fb63dd4df41052eb21a4b6925ba2dbcbbaedcbae464ceee060429f99e592c7624fc7589664ec798e2b92dfcf8d30cad2c89652226dd2fbe5f6344bffe1e62bde7f826401f5c316458e58c1131aa350c4911c7870c116595841e3a7b01bbcddd9b6ffba3ecebf6d329c2f9bedff7e2c0787d2bae0440a1469b834c9c2a5823552699cc68c1185b6fffbb16d2d56e07e7580424340419e8321703be35e5c1407f6047d5e8bee7bae3008e883200ed4b11b080205f1ecb69f9fc85a66392b1c69e8a1bf0cb75f50023a3c44252a340414d48de1bdc422718bf8a558b4bd73918b5fc7645b282bf1605668cf2cc707e2a42c67f375b8dfbab1bef55ef87d32de1bb9e6fcfcdac7f594fecdd3df7a238e37efddc8e081be7ec11df4666c7923787f234e2aee8da820d90cc92b9511ee84b1cfc1019148aa5f77cacb14551cb9de6cf0a3f3b0dffee1e05daf136ef3b87e9b07268eb3e2fc06e1368f4bd4e161f32e7194f1fb337e411034b879ef46748523ad2efa74a76335e88f3b35d631c6619c671c9b1f6f5ec6dbfc5617cebb705ec6cf9811da841a843a2180bf0ffe3e0ef8f4bdfe70c21a3838e288e4b21d282f28819b1b1d1e383feebb1ee7b7d2d75397b81dcb11c76fa76bb86edef52008e2e0e0fc0eef71be566938ca4a5f37378f436f429b5f706b756d5c4f5dff0ac7a3eaea1e0ce7b7c29182f040eeb1c211492e272e8e16d0070a92cd26ac41229ec7157122d2c6ed76ee2292ac45dcbb3fc771727fecdf8ab697dbcbe7c4227f1edbff2616f5fbfbfb161b07b3425f06e4bd42da31df699fad3de04bfcb6822028e6746c0321e83873e6e751013e17debcbe7d3c195c28cef7b76470a1e0f7b7fef3e9e6013ece4d48c3d9b1d74b1cc16f89db311b719c558e00bef75e2a17e654cf1b5f620876b45ec73e0dc7a34adfe33e2e348013753d0d912475895bc4a247bfdfc2223a02158b582cd2e1f15b59dc8e7defbd0e4fdcca5578e158abde37a8c3a3ef51512784d6d3dfd17afab50a86a3aca07c815cab1c3215dcc1f76028c3f1a87eac6f85932580ba853b758452951df316d0af32ff993b950db39c6c5d8d36fdc748cd488d266b349d0970df7d0fce5f480ff99b28a4a1bcdf80887e6eb6473989be2c8aca0a4890ea3f9ad055174711d4ba6e72ca6240b777b1c8fff37fcff9b21591eb3372d5f1ef97bf5289929084152f447a28e2c51ada4e91840bcc34e1248c1c54a05dc089195018430542a4608596e5cb093a8c41c60b2824fedcef906d08951edbcb1fd23d063ab131b089e2d2a89a072f3d90a99dfc8d7b3f43b9f27b7b91fceebb0fe1bd7b2e44f2dac91a1d63b9d301276bb8585305c50a62a0c4b0a58c0d2e88c1520cb2c98e86db3fdcf981b6079dbfa8848ef7a31a2a44368380200123150000180c080503029168401c85a2b47d140010818c426c48164aa46116a3414a39030c01048008008800c8400dd20e70b7cac5c7e5b16ac6b9267016a00a732f52813eefd2ef8b07dc574cb4c391fa7652eb888e1dccee86410de60448850f8985175dd12e9b92d863c5d74038a3537bdc79bbdc00175d456b5c962c5c740fc256a98a8c15a78e5a0a6665e438152e18b110b22dfe9f7bdcc36c5e191552ba22a4f8e30abc8ccc2b929aa3a52e93c5221815b61968575457534155ce6b6986c7e24d483580e06dba886dae928b07cb85c73e17c351cb68c6bff58ab1b177fb2da9041292fee536f41b52e9192b80bd4ba93669322afb5f086f60bdc512aa568180445959940cbeac1d75f984b415832cb4a318b1a36a1b8950aa385262d5133d247f0978febc704a15d5e750a876941850159381d1d3efef4ad6a0d9b3aada1e61c42c6262b6a54c00bfd406bced2630a009b344d20ff4d1b76a5d7abd7c66746458c9da96985dc445f7c5705f19f2c8360586ad890bc0dc93caeb6ca77f42a1ac90502452da5d4a38acc5f32f344dabdd573a257235856139fc90c093ff93e04756c587d817c2fbf52ed2e082360f78336c6379cea95c1338d2e152cef68c081ca9a836cc405fd2dfb2eac3698ed46e448ba232c1aeb372fbb0945f2f3d672f768c49f90715b2abc4a69c621321689bfe6e368c200d6ce8aa0155ffa746137b99a6c356064c46b6d27a7bdf077bd86497bfaaca51adbcbca73713174fdaf03ffe8b164966916c5996cc68e5e5de61fc10237467f7276f4ad2aa7712a703253398c8d8bea52beac0a95ff9f6aab53e49b749453681a2b26f4831510b7104d376c1ce986383287d53ce7228877e5b20365516e53c1ddd56d9ee6e1b9c515276befaaad007a4395968d79b4f8b50cf2ad7c5d522cc45296baf521ec46059c7de6e47bc6fa10cc761e4495df9ae38a6ace7ce312455cdbce62abffc65433b4a28bdd87947bed0a59c53dd9851efdd1e1d2a334af18597d06e1359d32cdd11e5a3c2575f21344b824e0b11fc6cfa45f30a4625a79fd92f7afffba66267c2be148448f11ed9bd0d5095aa7d4f7984e6b306e603a7a6f8048a2ca83152e2eb403418384b089d62889bac320a9401efc6be5f7c693db4687f320ebc3eb40d0bcf5c56c0aca02ca19170e760af31d1d7458db45f22cd77d1d362d4fe459cacaa0a574cb71a82d982ef0174cfe9a43b0b8771947ac4614b9b79d41fb74b50a99fe86189269943ba98cc225de0cd912eca26df426ee1983e10f6cd831a22533f28f9f8249ae60e1cdc843f9252fd484ad406555ada5160c010acd2bba7d030dd784755ca7cf23eda3d704b70e438626cbfbad6b0d216fb5b3da91730bcd37b5d5509c6f209857ef1e3c65cb6e89596efa05633fb585646c731607a6ab107eca266df8e41e27fd113756d124f9984c973ce19247b35c204390d149b5f23b5731e5ae0352a8d466934d519ebe5fd2bdda131d8f7372dc352b6d2bd86d8ca154a2e065a63ca08b72c03a90bb83405ecf71d7b39b78a2b42f92741feec1aa467b597985e28fae05aa84ce1da125d0975a6fc941aa8a9edc4db05c9845655d79e5fbb5fb2ad13086d5d4d412d896e92daf3d735032223365175e7d369fef150c72482f1396ed8231eee73b0d1886d50c8ac8374d9c98e260d85268ab2fe0c5c30ad85d60591f44fbe1232f95308eef0e3882bb8b2926073bffafabc1ac482eb9ab5c44df81a1fd5c16fa649150dfb6e25e00c22d026e284aa7e0d847a4f5db78c0140819539403ce8045b472b61f50557cec9746fdda4b4bf67f09fb61b1f6de43955f3fe58217135a06022dea638442694237e270d3c35f2289f34db282f8a020faafb761e9c10e3717956677eb5ebc5c0d2aca1d100257a471d8ea3c3d2a4164433dc20086eabe5b7aaa751a032c0eacd0167555489c6ca510b8626d40a9a2c143f026de9fa1d71371dfb2ee113894558d828173e6e6fa117cde76fc845a887ea0305f9fe523fda27790da90daafaa911b0d43628bf0381963f446b2a09f21cf819c8c62b79784e4ccea26500c73617f3a2c585f3b52af09a28ae9b21ed24614c2c2093a0b31953cf8c06ab51c6d338bb70313e00a61597d9014f837e464f75efbae1a2167a58cf9f6a92eea369d46483d6fff3f547c611154a7efa8fd4c26a036524175692f533ce980a95b28bc6318d81311de5c116d7d590be9e3337ee3cd2715de86f8426c20b3abe31d5fb47935f2c1dd57a47ff197c0c88fb87340193d564997ebf892bde409615084d87bb88114daed9081e124f70bd316ad41782856e0de16a24296570d33fd016bfd23924cc1a31ffbc8c1f0cadd586ed1ae3e1b8cd7ea1b7bdceca7b886cc8f87fd4f8a9b79ea5d8098e6c5e8f8cae319d92c7ef6e5d9372ce86110f3c63e8a744f1059ab6354eb55cf9456aa01ced2e36303872b00eaa6559472f4f2a6412bb98b75561be11da102114990c1c59356de57ebb9966b22bdbd63ec618d816270de5dbc089a66a859ebf6a65fdac6460f70fc1c6dbdb3cebbc74b42eac7462f6b5ac79769db233923471134404189578cd762e53228d37c11f54e3a51eaf9ed584c7d0fab13e8362e60347544ade70ad32410597e6ad4cef6f9b2d6b9495b6bc51c5bc7d16c0755f0ecef11b5e5a83ae20f39a42f2c61457f8b66037b8695c74b1cb1061b454aa5d0c3f71d1e3d24524a06aad67afd4f1011ef831e7152a1a9342c20ce652fbc1d182d1dca6f6d120af82f115fafdaedad776abcc8e9ae7fdb3fe47778f838ff225166aeeb7b5cdece2b383542a4745e7d9985431270123aba27416bf0c68f4b017e5958cc9597f991f914307bae7624339e87d54d5052634743cee9475694a8b8230fca6b2ac5498c75cd07cf6d7a5e54c3ef528c4687c78dfcce05d0d64abeb4e7aa0b9d60e0c5af20c3b3fdd8be7a73d8cfba11259a6e8748d0333764c0fac2a8e1a7135abd16a4a8b652d10e52c52017fbe5727f86ed8c329f76458943dbc5c6fff8e85e008befc058ce8ebbd56774dd1b8368d11eb05b0b5f70ca0495117b9d34467812b92ba20edda4558ce6b06c94af168c816ae2554c426fe1b7aaa53a7b771a687d2da74351f76a2b712ca6a0065d6c6cbb0674b0b53628877da827c23bb3b48339123d715efc8b062262f76fa70d6d4744ddc82b7d50b3d527b4399d6bbe98689ea7133e2857dd6e97e80e6ab9ad27715e6a9f579d7ecbc848a5b4182d7a2f5aaba71bab1a914846c2ff1a831418b21a9a8e786a8d7e81fef410aeafef6769cde4e9b11b89a68c19c09dc25a1c4a98eb57ecae9addcc2313bcfa9f0dcbb5aef84780074ff76ae6e19a2a79eb75294463ade551610897dac7046a4e36905ae49d9f6d27160becafc1a957a2e2969121b5e4db194003dcbacae428ee4f1cea94768c566e2404ccd188e85f7c9037f71ad0590da8fb0839bbc6c385e77e930cbac9f0ecc026b6db8eb0860fd6ee07f18be63b9001f8e884f1448cded68309de0c507a631bdfa4875b305937b77524dce4b59dbaf827146f0f5b826fe07244a3f9df9e468e531b075c81cd95052d602a958911978c45dfb5d44455bbe02cd1507d49bbf280402e1539cd5ab958f3f006c6115a548d2ad9bc07431d2b518829531afa589f2bb05562e261250ac3432ff0b31db06fe40d4a7172b4383d17ab44f096a5bb6c5523ec5901e2af79a441bba5d4d78a3738c6ba447d60954e00c93ccda65199630675c03100f62ef9c3aa4fb75efff123c0d8194712d8e916d4b1b5367655180661b20770017ccb7658d65054fc6ca689663f19b6bb49ff363e0824db998db9407ecbd8280a710e6dc2efdb4d349dce54c7f36b0425f9b2d3e785e881e6b5007ac28ff51285646b1fa8d53beda19f562cb9a831f1ab567c9e683dec90551e0d0d512039705ab70f7951a15a388bcd552dd94c884ed3ac60bfab60231c6db1dca227d67a2d65624f4db647c2d871dcc6aff4c7a1d9bd71da2d48033dd614912f1a045acf97c6e667414ae7284d7ce5ba9e86965ba83cb25895638c8a56cf823c0581bcbaabea49b7ec5996e2ac9815c8e1a0cc7a8c03f554ec9b28c35697a8036cff7e24b874a973c7970fcc7cf2c0380c9f2be9e5c42a0934945eab2f4479d438c8cf2545b165afa1289943c05a2944d30e65100323ff7f2f355e25fdd2415c0b9a2a13a5e43f83d3302b0fde4d2de851d89e04daa38f4e3b8bc45cb486d1093ea4553bb1d1a7a839bb65dcd7490144120126a4f30f9cb3b270c8ec7aef71630a7138f856cfedf19780983ba585a8e813faa331c91e0adca3a68107d09383b8029684102dd96cae36adbe33af974a0872534088418f979bdecfabec46500ce62d10e50b16da148cf0d4d91220e78b77a5b3ba4e33eec261a8f4a009a1719e468bb4ae27b7ae758d8aa18c8eeb64d379191c50141b16aee47d5b6b7073da95ccda5532e2b6ca5c22c150da580b5a552ab2f7192213c531362e1c57ca6830754f95aea5343456e1f0d629360744917462057bf25b13ff1c404867941de5413dc8d1ec74bb6d152037dbeb07f7a3e0c6e1661edf102a8dbbc1fa28eac2c832f2539831485857be5ced2f6b768cb4e35c70a2553f934c084cedcfec1b396a8fa6d616a0e7360360e4bfdf7f814dc3cf99ebec478a180503098b9c2f6c9117bdff0431f29677db0377b13397b765565044f60da13883f59b15c37f856bd166e8bec06112e2fac46f6c81f89a666fe8835ecee5746950eabfff856c1f98b67ae7d76d0325c637c77f4aeb5078505c5be4e9035c725f64997187c3705e17058a9d4cb2b3f2a759d1e2920a1c6f1e15d052d1c40c25dff5b27198ea7948950f14e648634c7b714c26d0c4dd057091caaab282c1329b63f49d92dcd855ef60fdb4f90321feda8fa9969f5e709e1aabcbc1f898593f64334bb04bc712c55093f749d5df0f5028d0513704cb8091d5b70ff676384108decbf64824792299e97a71915438b889bfa0ed85ba558d9f8142f3dcd0b2506486ba83c8a7c288d2e49b63194ef7ee77f35efc44412c4ce451f29ef0f50c94b95ab1f62a2b4fa35a629a29e070d21b2f4812a7f6db8a1465731e62ccb589eb803b3df9b15f29d684e5cedcb48bec4701c320b776036bbcdbc02b22687bad9585995c396327c62c59968127d6d8b6ea01cb690ad9121842c105cb2747d016fb3c8af87369678bafc0411cdd6af9174153078417ca9ea4ca0fc8d59545d41cec6ccdda3a3a74578c63c192423e8543785c845f1184078685f09888889d7ef351ac70688e539f24bd570202d7fc48851b64e87844959f72b533188211ab6c4478b4a83f8e61c60e1d136f6631acd51c8734dccd221eea809bb3dace0aa92621aef8e459b76d2f2956c63719a60490bae9702f5be136b45e7a42e978cbad7d803a50d53ab66f030bf0903700eaf1c58ed2c7ef6912b0d12ff1b426a8a603dadd78518cd6ffed315171f2bcc054c7cd32f991fd1d8b4973ed1dbcb71992048a51d805c3a32415517c1e1f1c74b0ef3c15772850419ad3ed1f47c28cff7b3800d5799ae91468fa8905b4f4324a78f1a588eb182f3256b80cb92bffb8b8cdd3ade8df81dee1704f56096c765f9dad9c4e0bf5bd37524d71e12d3da133a93fee2064813a05429acc4324390eca194725c3a5e9fe16b3a0c4254c50a74b624c82bc6c944d5d2a13731041ab7e35115910c94658820fe6ab31c25973a6503cedda15710cec55506843213fd3e1f28b3342806dc42415401abd064dd01f6641b62473d60a91c846c39f42333d1560d662a84886a8655a34283ecd6018f106b5219590db645e4c682d694d87c5cf941ff6302cba872506715379c5ce4861dba3767ea247bc6d634ef416d65550c6cc0d90378706d7861a9b73829d7b1574665ef7600a757d2172aecaafc51ef78dddad6e5da2071b32b5f40396eba9ece6700e301d0d01641221746e8f334c6f253f8fc8c0b688cd7c5f73279d7cd22e05264ed424e443f0ceb1f4112fc8db91078ca37194b6224cbb849e38081d58bd221340e06d5912df301ebf093e3057b594477ae9751c4c61358bf526e3fa6126b95549f2d757cba9e257ff83fd9452ad0ae5d05ba2674881443d29bc5ded2070c60e6586e6bc2a7dc5ad437bcc191434eee60e93ad4251f5bafe090c3a1178e1f4f6b4b1368f331ec6cec8e7b6519f57c0f0a585f2e5ddb703fff10bc98a460f8853d08d2f8329cb845d8b9ee58e80f075d6009f9a1f7556522b4049878f52b7ebecaa1c74c1e199d46c91cd98c0f2733c2d6d30cc5713830f70017b77ebc3b078b2b1e53e98f1f157402301b9795d06085f7f77c876bc4316180f6a7189f4611669726b008ee84f197b5c71e7837e62e776e0d86e8999d0f8d3f97ecf91b9712d13a74d90a60eb713ea60a60743f600e2aca1172d0b2910e7091aa494e7ade4fdd6e62eea62576882a702be0b7812873381f9a7359d143bc91dc6ef1e95e89941e2356f1ccfc71c7d67a0b8609d9a247cbb4c1173debfe734b331ee66b5e8095f588dcc7494b61e8f5cfa47bf630cf2ecbc12e12cae4b944b25168214dc248912fde1b204b07c1d54cbfe01d303f5aa4c321cfeb98301334d1e5bedf12cb628f2fdcde27a6778d33f2709c66605bd070343ec047fef84018580692fd814b0c6765760e09f230303ee88996cfa8700a5dc61993e84d554272c676648355b946f3e3c6221213f65d54de6580bbe1163633ed82e20d845a8f90de17084bf1025141e4c0361a41ff0c9b7d463c6610738f2a9d8327dbfee74f2517da95309bf30f184b8e96ef7b835a6d9385d5c7176263a8c7a791d024d3817ac53578ece2d99ca449cad90696231d918d23822eb8310004e28d61eb2186168be09122f981ba491ae97536a7990e4a2c68ad9c9569144fbed18e41ff4fd625e298a4450dbbee6f342b6e9629d442c3214560fabb931cdc51e00f3ecd6ec8326b025439597d0ef4fa15f113af074d81496d96295ce9c6edcc251aeca9ed4e2077be0d215e2cf1370783f8c6edaf0652ff0efc9b7dbeb7e1312a780a35323f76478b676b626fa6f3302aba5222adacf41820f7f01c44e98d42a40ee12b52b475106948c14da5db3b3d591316b1963a4f1e75b00f8e28419263d7de38ca248cca1ee95d8b4775b459029589201a1bbe72402ea84ca1728b623732af6fe01fa0711abde6a650f912d5b0a871bb5f9376b74650937897c944bbc5e6b161ebd869c053a0043e81c755a9b317ddf2b9cb608b67aed16dfc508aa4e9d45e9f97d38c881d82e581534e6ddc6468f3220d75e10e7cfd0f428ca5f0a79ccc7229eac404dc3982eace869197e7540be81743bfc37881555c81e6a11591196a83e2c122d7d197dd0779a9775c45d15d79118c921171f27d4e35aa3333845a31149ca0eca5d11f2a22327863d922e53b3c20cd233fd18f558ca8b25304c4aa801728568d582fb511d6002c418878127010516c7eadc3b49d4e984a9b48557966ef8ef2046af07a7c725c431561812e02912cd09595d9eb11f827fcc0000ca1677fade4f04d8e98c3dc380c3cf32a86394cbed4b94618f6397062e9ef05878183046370fc757967dbc93593024095e2f25c933b0bed52be69cad5080bc2b194415dabd1ae60c5acb1878991f43c5b102c778e7ccb11b9bce5027c319f8851b8e5d7475d7c6ac90a29db7aa19c3efc13114296e3681e9d5a7f1f105caf2cd83ab360f0425520b729212f8c87d70d1c319662e3e74029f21671c6ec55794afbd1a7572cd07b1f7475ade1e927bc0cf402b9b3c09e6ad8b67677891a4533e136ed5303cef7c4a2b82ef00504215d66b1eded2b7365cd81a81a4cf3a7664222a7d51124000b781354d2c9c125c6a919c4ffbc6f0886d3e177327fdcaf59a1c8ecc9b6487f3c0612637b1db608552b169e36b171c09637dcf9729bfd1dc5608806d60a5fed581ef53967d759eaf4289e1779b1b2c111c41d2329dffb52ac6edc516f3af40a935c9fdaf121d8e3d283f6408927c6077ead2b261bb86547122ae558caf4be9575e2d28b35c4114bf8ebc3f9b9f90932f629a095a5989c00e65c3982cbeb1a9337802f4c5844e2990579fcee5224f506f7f02e042a9381a197da2a5799b54dc185d8e882c7a99ec919d0fb4a8b0ed999beba5860c2b335ed909b17b8fcea3fa0bc2278a30c1d96a04bda0d447d198e1a2fc10dd80d327f271564a3382a927bffd2ffae149a5a487dcf38ed3801568382db9867ee564d759abd61d774e77dc2bdd0b25599ec6332a52e53514ef62d304bbf7739d1e66d35f7bd62f444266e98ea5d42819b2d1701f32f138a1a8284c0841d7394d13fcfbd09702aac414c3b396935f8390ce1ed84c357f1820e9f3d7038c5ee8ab2f8367546bb5fc72e0574f43166a16237bda7d322e93fdcb76f995421cb90f8be3459849279e417b68b84bcb2ff2cad267f8dc55c53aae47f4fe0129de12b4e7aad63635d1413d4a121e2a73a2b00674a79a98145be392b625473c7aae2035340c6be23c8f2124e4919bc3c089d924e871fc2754a9abb505f982ff5c974e8a40993c0715f8f8393bfded8bd306640af082a495bef6d0a95e547fbe72ec21a09c60b7df5f1e20c19870337df580474c415b1859964a41d7e607f665c3a68f48a30f530aa06f60a0b32134770b7d95a98def19780656b97df90ee93e837455fb8d530e10632d0ec881a0a4ba143268e8161031a48adbede191824e0fc1676c45e3cd89f04d43b90b21594ec23315fce42d459077bcac9410b8b0a87e4f3399e0294d971a4f67102865f78575ead19425d0780d8651325028fdcc4ee812c9215f8b04868a0d79098d6f6bdb8990a7dec3e2d2416f86dd2b187aff013822effa1f577a041996946002895ffdb07eed1004f8ef247135d33e80794cf1763106c160b3e7411e023bd97ba12ae982c703868dea717ed0281ac8fba7a515fa9e8106450f41bda049d04779be995dfc9057425834bd71b8d15f7afcb47151b569fba9d5ead7f41003097b61ad7742590e4edb6a29f7aaa90f59f6bbdadfa4b74a9bcfcf19082eff6b209f8c7d28cd0a6ccaac2a8ac6915a382421365b642b4ccb53cb04838d8a2d8dfc20c573a56d14cdabfef4820515b830a6616cd29fdb65a711db1ee6710ed441b7cfd0987810d68f3760020fe7e009139ff19240b63c1515f84eeed439cdce057e077ec797a6673c4de376a70a61fe144a3188999f17812a803fdc009f544d7d8a43592bf643eddab61f9a586bca94102e146006b79b8f831856a1c46ddce831faa86210228ef717fdcf8e0693802a9c6eb49977018cb46e4b87cd33f7b740caa5811239b2e5087f20cb649ad30a909218b59d5d9b119e03515269f60ecba28fffef959959f40407b6a8d5a39c2e6875b80d00d85969ada0992ec76f459719e29e4f35e8a83d31409bd811fc9ececd13ee0a31e14535c3b2234d0743b3a331561f8d08a36e45ae81a804be4d75930df7373090744d6952f817146b7ba3a070c9f73baefc6c1d2110ef300529d771c9effff0b1b3b9b7390c1fde8c415d958469dd8d691aaa708dab674d960c88242e23ae9a5884449cb474c54d821ffbd8beba00614d9dfc1e05d2e40d3778b358eb05624ce8adc33a2235ce324503dc74d6bda9bc1ae5b0419639de6e69e86d1d076cd97be88c119e6eca22b4194a25b9c9602002a0d51013b4e64807ef2b90b3d80e84936888fdaeb28a07e8430a6fb97af3b10ea27456ab43c2321d5eb4668129ea7633ff827c4afab6b687e83e82cb361df559588fdecba713ba0a928b2806488641f5eaaa10bfc2ba139bdad94be64a837de738c3839ab14b0a906b67c95741a9ca1d9235d674edfe1d82f150ac0c775e38f53559a6ffdd4375865e47f8933a3fafa58b9e5726388507e21a52a85943e93e68c299d28cc484f07949ee2e06f7b38a8f976100ed65b3290825c1cd041415451dcf26178e3b51acc0bc147ad7a03e4b721bb1e2f47e5943a6ae25a5301c29f494d4ee3d691d0f7673db6235f58c85555f42cece7ed95a926e28c93b6e2524b851c515a11e432f1c4e30d223687a3ff3ef64c46222c5eb20f2a51dfcbc654ec7d7e7a24fd20ce8312429cc10e1fb05ad0fc319ef9afc48b63067c09d8974f0f0ac177088fbcf75092dc222370f2fad0f5fa94504eb69701fd91a0cd43ade34118931daa0da13ba5c05de9ae61165af698cae050011cfe0ef6dd31386d02258963d9e05dca44a765d66990b9f4020f1e63cc6e6b198c0c25f41e43bf99d9ec9e8b7e7353bda953b11de734c6938014d8aa9b9b43f581b2fb7508287f73551d0181a70313526b454a483fa5b1c4d89801b58c791821dfc5e61e6a9494f0fa4e5201b5f5dcd4fce114340ef2c4c31c655c3568d5a4d5560765d5c4c734f81d0f69c744683bb22f9043b12a14a7177dfddb4523f5aa189d43840e9ab39662e35eb6231728cc828374cb6506dcc01497347d7c792c4d17d8337b44661541b03054d002f91d35ae90d04cfbd56aacc9090ca19d597b97da773b9c114baf24ae96c8357b1edbe2a9f4b2a2d6fd0e105887ef6e04557a791ee4fc8dbef76de1a21e3f0d4079b195a33c1210734f04dcfb8d0977a4f02bb5fbc117d4f34a5ae03cc9fc6268aae26946ad51d38401a3c2c45c44219feacfacaea3372860968ec46efae4af8018e7b2417c59d79f62e37bdf2f234ba82b36c6ee974844eac9b3fe0a6c33c7294af51856a6e8b7d7589085dbf345714fcc70bff94300b2c90859270f58c6514f4c51bb630843a978aa7f311b4d007873099675fad1fc02d4d936b4fc5b8716e445ed42fddfe1202326e8809dd553d7945f10c26051660128a6b40be6b032efa012fba4b342eb384156ca83166105b17cab6d617965363321672a46593988864ac6a942d68a04e85a2aa71e8f4a0795609842868dfb97e21282d013445a27580df6e4514a419a8503d68cf466b00998d9abef06f6e742555d88eddb624e4dac7ddd15b8f2d7dd2ff20672d7c00c6956789bf07165d5a76981418775a1da5260b1f5c0be3a2da01a1aa942809beac2c06a7696bc10fb4f438002896b11660d2bff4882b92249bc88d9e012b2c726c972346b79374c79be54fb1da94d1f06f62989a2f22b6fd81f33c9e1877c49adc9f81056dbdc5793fb0a902caf055ea01004d3f563a122dedb44cba1de9577023da1d55456e8ca4a109b063739e9e2eb3ae16859f2b5ca95076c957dc356c94d87d82a4960ec07b6456785a55ca0faef5484be05d88a4a2446f4463c019030f1c2b9836bbc91954e1394cf405a423719600e197d62fc17da0732ee978f577257a0279c4be37e4d098a3c6f4f0bda14244935d709d2670aad028939d70c47fbba12ab0616b42b9d065274270fa225d8dcc671fcf08e80bdb0b548e4cda1f245f59df8d07ba5bb6b38e01a5e2b627b0437f0700cdb89d50b20bc2f3390d1b92dcf0c6bd7dbf2607f28840391d2a306b71bd42ea89b779baccfb93810fbfd7f19585722c613abfce35b4e3b557dee7b5f93c98cfbb6826b183cfa44fbd101bf0d8a563896355b652eff81e7aa2a811ee8de30fed9411b44b887f05a3e91633c29e29dc1cb9bf203c1a2372cef8baabbb98903ddc3c1c25a25c44ea1c2e6fe982ea1a324f0f22256200f5272823198f2ea1cf7378513ef16ac5a2f4ea7b28be02736c1820063071bbe8a109d5b98cf9d81b55ca83d4b45e7cfb194c5af2102103d1ac7113cea1fc6fc47906385d168f1abc346dba98c6d77bd12fbb151991c643ff235508abb4be8c74b91d3fc9f8692dddd72c30114d61e8273353ecaed08383a70dde745b14cf48ba29817b029f4e51cc8ca3aafdbe807a20319c4ee61d05805f6e14e09f1a1d765419f13d4a6a75093e7da94e364f124d534502c0893410b5852779c1c8163c1e2488c0529c7b6cdbdccdb490512f23436d1d8577ba1cb81ab47eb22fc46a69dabf3ae795e1fe4ef344c9bbb4fab17d8d730e59fbb31cb70eb2005ad64b79efb703f69d71a67d1cb63583f101d13aa1b4ac20849a44c663595dcd6877841a40e839705b5cb041c65cecf5222f543b9dbedd4568791535a5a6eccf7c245c706b42e7d2a3dc0396a739a45e870443c9ce0c6abaa52a960ce1598254ead37c6493d30abade5d9425ff810738443e9b5e623d3076ed4cde42ebb96f0af75626b87de20af1d8f59dd2176d4a8a5a752d0c5b4c17754bd7c8df0ff14f57a0c956ec3a54a20517e11ebbc6787d8cc00cf0fed904b25400cb35ef52535af4165fcb61d8aac8567ebdb8e26cc0c376bcf7ce9e1de7ddab3009251d966cf886f192dd229c39c8c669d781a41dea7123f93dae416a24d5bde950ac44d79ca171b5166754edbb9775cae3a605cbe5c4c6479b99fccc5dbe265065c94e1356dfc97f96c718dd584bb433b78a4ee5bfd53e072baeedca7a7b7e858739aef7d5eb0a758f0c5351628ae11235c7023cc5e30567f454bfa35390ea3386833d6a6814f05bb4f02259751ae01252eba0b41b7f6f5ddac1266ef6a4c947e73766506d8ceaf34edeff75353800b071f1afe84aa90f2c2328076e763b5199ed6d44c10e5fc03e094995122257f9f5206d08f81e06b0072358b882dfe958b59aed0582ebbc793cd95983843eda693c7fe37e4037acf3d8544f02c9743f36796e97191d86f0f6b2fdc627311bfb85b62922c6ea815e59a14fcc151fe03f4724e96758902f47670703a651885590b8fe616fbd355a5cd306beaf183214f6170255a1921713541eb436b11514531640d1920bfcee682d6fdc1d681a72e83d2d203b787b16c209cc10ef7ed7663af9315536e0859b0816cd0f9be2f0940f2a5d57bacf7d75505316332aae896f826a10646c6eaad36e6af7f70e548d1fd4944dd6fa77d9c618e6396ed23f59de5bb2805120a0f87907335b5e58674e56e50dd7a7d6688160e2177498f2cf189388566b9ddfc2ec31ea84b612a00e24ddb2c3761e8e216ee72657e6525f88cdfd0b284e9f9b05ae832f8fb4532861b486229d84908dfef4664499692a720517f21b2a91f0f6501442f7224849a9603960f0969f7645267056dcd1ce74172a6b60999bda6cb22383e65ab2ab22b804c1833a89147229b879754094f09d7dd3a88581b4e6d26505627f3356391db00b73ab49ea7722fb8800203f497c1fe9e4211eaaaa0bf5ed88943328ea4a4ecb08ffa77c708016407e8f185283d4b2751dade4d08b6b9943786abb2d1e801d4a0fa851d74c0b87719cf6dc3602e20d2b469776a33fabbdb1368c431596bf8a08ad0c4926c1407bb6146d7cbc908f2099dc9d40d009f982f81a04bc781facd793265a92e8bf95313cc39dd438302621b0a2436ca1ee9cab2d4e36bd8520a13bf0fab1698b29ca1fa0dc031274c9ffb3e1f8302668dac477cc59850ae1828d2be1afd13fda4432c353fc6e189d02bec1d948cba98a391025f9523e269c837ab48ae97c356ac809c41e6400615d778918152da96745cde8d81940817918378a7006653c0bca82d948c0218434aee5f9716da8ff8c3e290681473dc6059c1a485b5b3d08a7a87076aba8365d6ed068e29a761d1380a26695a7b8706994e79e20b32e2f5d1a0fcf71fa2a7d29f3a4a7d27f509d47bb63a8e8eb3f57c69e00f4c47941b17d4483accec9c0fbcb9bee1c860cff582af199587c7b6053dea41799a19e82a4beaf00612b09320a66660776a861613d120a7079b3315737c94dd6b99216dd2c8cc42cd7d3008a2a27ecb0bf2c36c6724e4e0b29a89d1d6c228771c132a94b1bc30e8d585533871d3cba38c1b31639969e584455b5e746409b99b251919ff52380f62939a55d272fee34079ee7fa42fe6bf1313b31853dc0d56747a0b35bd2376880f36a710441b9d0ee1f51b119ca78556b1dbd0c3e1c86be2bf464577d0ecb8294405e9fca377eac589c89b874611415a8a97052b1a2dd0caa360cb2f818ed9749b8469c0d3a78e0d963fea781b8462e51f88de4cd79017268a8e1f63b650e6e262c34727a767a036a995b7adbacaafbf671371b7487c6c09904b52541daad10e43c9a973242dd5205120a07dc509d72d254a42728b0a6621e364c22abb1af64711677e9c51a8b999a4cf4a90419c8a0e5381f9b25be886aa7cdd325313006cb28b78b5fcb879119ccefe5ec75ea80da6f20403d17850fbc2c42e1183b008ad7a39a792c7c852d911f88560b254e0b377bf0eff5c2ab29e567fba6ce5bb2430ba68b23bc63879d649c67677fd866939e6812e8fb96a23a6e293a9f070836b7264f6e0fd746326af849fad800067eb378aadb8a0ad800f8224e7267a5043e6d931126a2de27be6421830d06c4fdf70cd6b6dca018f2b8310b5279d2bff58e320827205bf93abadce2544ef0821accec66667cf30b7470ad23f1aa8b6636cac137d67dd08ebf4175ae4bd05bbd688046975391017b89e8a94fc60a061306621f44d564e8b673330d7a5e0855d77d2e09022e02896b50f99229d3a7a35ea381ee38d5378631383c2e9cc8d95409f21ea287d79c4302aa3ae77320267b20b4e089689c9f1696d45a4b679b4109794ad177421e6da072a6d23ff3cdd93516294ad236ea04af1be64ac7f48354e75827d633ca65be5542d5429c99d66f3f734ce123f03d4f9c62d98de0ce4fd46c0b965e2438f741f59b982f76f84343b0b739be82e9a58c06e89041e179918e811585ba8a34fd63a77850bebb1007d8c713bb183322e066bce3d2a2d2ba06712148fe9452bf040b3c8e03af212ad075e78763131410ed85b5f2e76e5c769165207e1ad9fb4781c10074ec2184446b93f49fcced99593f6cc27cf598d538331c9cba4c76a8117079e90469863e01bc2ca667acc313b46dc8b5acce21d1befa5cf91b86d8b5082ca0017e90c491f0da0c9a3a26b8fdd30e6190a5838e15d0c50788a618100157652a4f11ca0ea48089356a7dfe6044d9ed6b241372a13c0686aa74101134c04c7d4414c9c985d5228f5782d4f871b6605633f0d66486496672eb886d88bc521dc27f66551b70ffd77e0b0a531c36fe532a593840e82d0b71418b31aab8841a7a7e17250af9a908c36923e65ecf10b4734852994b2fc71be0f3d42e5d854de57e8c0b9cfc0ccbf53db059b51df6b6a61fb8b7f5e23a9f91c3340ef66e3f51f8584b16fd526796837da741e7799138d573cc52d4c2e8629dc056ec6dee9301e6422b5f20b45c6cd90dc690b7f13f793799e603aea3a8d05d743ee9a510db0740aaf8cf4b93f10a9606199c175ab1352cb5ed258477c541e8b76fc3d8743706960d12ef6a7dad04ab03cd217bfdd3358072a017465c0fbbd3af26a7abef5befe511056d3ad97e99290e9497e919982615a4f7695f4df53cd02e975395a37a2fae0e2a0bea78458904961dab2b52a8dd2e3f3f9bf9b9ba403ef0a1629d1c1758a0e8061411a71e42e0c5725550b07bafbec1e4b0ffd2eea64de54070e3b9f854de9f5c3b51eb1e050327100c84005117c0a2f3eabfb58e35636a89b4a653075273dc967e031d4db9fb6ef81345825e5a3b399928343d061b5a1981b577cc13af025057d81aa79eb1eadbaf58c3c7323caae34c8fdcf8d6c70260aac18c84d31cf99b9700b755ff945e42bf6af31fd61fa0d727a30552c19d0dbcace52172bc01ccb3074bc79d622656ecdc61dd5958fe7dc366bd06ce46e374a959d9370401b524608b7c8b9fe726c03e07102b72cfd1c8e9e4e34cd405dee8a873364131c80d908b9b5df3c31512786cbd922c31d6d56982b1670415e4a20bbbf755452b62e507f822aa41b5fcebc8272563d3df22dcfd54629d8e2c13b9237fde6e785d84d9d2a2bdcf137459aa6f978706892a3eb59fb4769bf7048c6880382d8134a9edf4367cd8024525f64c69302c7c792609521983cc38dba57b4abe3d01e111f80fa641ab2b9ce20a1cd667b7ed00a4ebc1cc2b2c91866d77e38a4631cd8fe3611e28e015865a71a150acb2c2acc17bc2742f146f8b9714e1629a1e7943997211998f00e7a17fd8593ab901bd01707f68e64326abd67a63d263917b4c62f507c470628afbb66e0f1d4a735b6ef5bea2495c12f6590c8e660a351f80223694405036e4508f88e9301f69d524c9acf6a998513d57b470201fe03dfe2f2279525cab36e5522e44d2fc1cf5eeb8147be1924d6b03ab41a2c97e83bc4415cea546253c62579cfaf0961b80b1be285f92ffbc99027e77054eccb291b8a86b4b28be20436b5fe4be7dcee85a2885784ec68379edeebdf11403220454361228241b2ae957f5fa120c1a2e2f51eff88249a27ac72ed712b7fda64aab4080351b1c19bbbdd1e471bbe6b44767625bce519292bd1f4384b6bb31afeed7fa5161f2fdc47457854aaf1c06b2db1343abb0639dea8cabf6a4c97fc6067b8615fc5eeb765102d03242f412ff0f29d79154888050e7622fc234ecefaf1da232d75b1060f94479ecd7d26d2068aa895a027429d904a82f68252619d4d42ff4f5b4c14b5ef414bc13b5aff3870f8caf723af789d44e1a237250efa0c81fbde9b7459ac58004048bc79abfe86c05b95a2aad4f38a56f7babea0fa02592959b15ce1563a9377f5e61e8ee27a889ba13f63d0d115d34ea13f414d5c6bab253bfdff039eae43292ea240cdb08655b30e78fdc59e868de700ba9461a96076074868880afde3762c91d5ebac59c7f9f73df366cbfc7e2ed43b0521e71fd76e488eac76ad3ca2d5b67cd09adc42f298ab91faed878b4536ab9b5b2265e5fb5a1ba04f4aec3108c09086e50e97fe53eb9a4e73830dd930c26e734816ddbb004570e3293d958131421adaf0672182a90af76130849dcbee5ed4819db49883605fae220057953543c3258530fa85ec6ecf3bbf4352c94055837288ba2d3a650aa560fde30385cfc1bc8501e6990f2d0694ff4605b81acd11542f4fa911d0d629d41a8e0883ef46bcde64409ceaf45be9ab9b1767b8f928bb09f16684dbb57e7f30c76f6257209e577b00fd20f4ef08ca76009e9793c8321c4f45ea407bf0949445b8e73442ca1ef9ab4ad70a81a5c5b2d9e29475d9a7a9b8653f98910ffe8e62d2937f948eb34065f4d7bf7c0a2286d22bc219926d86fb9ee7fa88af7286f803bc90136fd1bc99776f550d501be79400816999e1e3f159ebe022f63f4ad8f8066b073c297e4de78f0d1440488dde5d387dfb3b053042f40d5e2f3c603f733d71296c98d793b9bb479ede71f4816d497e3ba75a4e52560ea5d174dd4b2d9e0229d0caecceace270f22a4335a62dcd3fbeb46137952e8af2fa9b801e2024c31332ec61fcba79e88a2919f8a10650fec1066ddc951e15736d3488a500960769361b3a990c50559f75bbf4dfc4c21379dd6df7e6409919c128aab0185230841627ba188175d3a668d4c2d131b5b2688f06f9621bcab650dcc350066b2b12a9c39f9d8a724ccb320959a0ec978c43c303d91924328c031d67cb3800b03bcee78adb2d01fe180f82593830679c7194f77877cb93033a7821cbf098eae16a01afff29fc2cd7e6326216bed6ed8d76d0278f3f5e78d87d091fa320c9e2f5e10d0c3ffa053993351231cb5a05f795d63e998645c219eca142a7b8bcafec5e7372774d5f8192680305fb4e847f07522ba1bed2a5407409008fad1165b8654b562b41d9e9958a49aa9ac393a6ff74fda4ae1a0b2f07ff662283e1814532a7b87654eea9cefb08b0a01a1ffa09c3f2e190eb235583fa3af816b1a43d1ae1323783ee68588e23323faab1a1e374a9620d2886f3c1d2dace6aee833e8c389f102db71a7c01d86f85f2fd478b0b3fa5996580c632940889c2daab7d051bcece605288e0616c9f0e4fad067e7da55874936bfa5c2bf22602980074ee13a4d3827b3809060fb61a838dbd11b92d1864a6a4bac180d42729c83319a38f716a404241c88802818679bccad1ef2ba024e69e0b5e7dfea0227aa2e068446347fa017c000a3047a71b0dac3ae263b9a7aa6f68b240c84e2ba74d8551813e9820c023fcb4fd8469fd3c91467803724b451d621b919e4a9c1673b5b15e243a63bc9954f64bc3157c9eb8e36cf9b6add7bef3b77332bdab69295138ce68c6ec0a277fb0405d5053c608ba8f81d84f3f43c382b4d71dd4966cbeb0bde3fdc5b9f26486c0e287cc15e6a546c9c612fb4a11c511f34a42dd162b14483a5299bedc465969e4cfdeb2fdae3604e181878d8cf19dfcc6bfb5d32a7b83572d630b45a1e3732fc89d8fd4176ad3d0d34e3db4f330afce9a536289af8151aa2ad6e4cfa4efc62d65f3edcbb031856604d753cae2dadb5ff0d8c313510ae4ea2532cd31b0502a03c2f5d430c91dcef8379cd0af46223e50773b28de32cf08eda958577204a517c829b10ca6643f0a07e225aa5ee4774bdbe8a6ccff95eadfb4c3e27e47a39b2ab7e277616b2e4a92ac0ff165bb6d211d3950d94160595ad65b41c15fbc7bda859511eff2edcbe737ee15900510ac3be64d2ef92856f7c5033776ab9109501421ba255d3854309cb95640daae4da8c8f9762ec5f7f0809aa7faabda4e9d4b86cdfe6ddc4e6c94c9d6b1b85d41f6ca208b71c08704a70c2629ad90c2eb3f207859bec92947ff592f8778d711c346441969c294ba477022d6a4ac9d981183bd2e4a8f01166185b410ff70ae1443464c415613bbe70748197798e21dde6d13e549de481630dc0cb50fec79c1a6eb28aa85ac21a8a842ccb3fa204226b28f89d2d8e9b788a91ef9d842062441e78affb52068214278ad4cd4a9c01d5b1f687dd958c7453bc46d3cc49dec2c0b75e403d75a3d0c1bd3413e687ce1d3e4823ea24d62cc94a419fec122c2d2821e103dcfbc94e42add44e1d905003c0281d7b459ad2384657d2d59e34be1fb6568d203d079778a5cd38ece6fe5fea3f8c0072943b37b638f4c203a2a702e67ff80085d604da00769ca6d029e3cca1dfb09370be3f596efae809c83603cabad359b05f9a1217703de523a75f05fa0490e99220037d90150c1aa78037a9f8da89a74ecba363b8b9c77977066eca2d62b30cb63a83dede5af33d0bd21af7b617af21f6db5e04ac545a3d40168ca63fd3ab5c26e9f02f2ed48898b79348341be501f9c317202dc3d2385319e240dabdf9726a99fa501a1a42312d496b89b0c287562eb7f16eb128b11449f6e83a41e3c07f67437aae25d0871502a0be477abbd34651d7ce76ab7089f7591706c5e215230751bf01bcc36294bf899131d55ed94aab32da5ae1fa41c2b3ca2df5babbe227c62ab48ec8aace8255f1a6616d16cf0ca988f8cd2a53b713cdd73177ba693f15253395d64979e8fa91901fb2cd72b7a534e6fabc1e08cb048f3c789a46e2f6578442a5067cdbc85f7d692f7b8e293a6f88773ef44fd267befc30956c686c60382093687e12b2b15e5b408bc5a389ca7be42a775f46003ddc737d1a266410bd8d0c8e9792dff60c2b5e36e6ee2b315a8405a72ec74be332bce234420cb3a3bae8389affba5be1f93ef9b45668acea1cb6bd12a02e99685625a27e60435ac6cfe6a19afd0f473fb5d9b015face7c11e29f6ddfaaecda8e7db92b7c32dd988af0c1f6c2791b094b3ffb4a289f1e84d2acf685af24ad2a0cb123465c180886ecfa1cf00fe330fbf952c28b176dfdd63e0f21c89a4366bd2fbf10208ff0b2b11f4f2afb4092c54b48a083ba1d0999c9e0baf176de4ca06f07910ba08fce73a13eea8ba653f331636993eeef516e1bd2d69f45c201bbc8f46aa70421e1099d7218b09f7aa7fba1c04af17d1aba5a4b6b19a633c3b547edd0b7151b60a886180edda3757b59db336b9c1ef3c50745b53eb454221dbb49612cc2e5c9df8098ad9e559e966f081a0581b5cd30735e6976dacedaea2d42ba7c8b4d4dced584b6b14b7e457aa453edab51472adf693c0310675b4d52106e0283cfa090d3096d63b52d124133a7e1ff80b442ac64745f6a96270d31b15deef859d126e5c5a22091f0104737edcb6b25dc4354c19400d44b7494108dafcde3d743af8875fae8227ce9161fd5d0e3987054be149c69fe648879bb137c157ca4ca180cdd0b641c0e67aae99fb461b530456e2dc64ef81ef95e29d148a7d7f4dceead5ce1c320e7855a152a1452541a80e5c2ac758d1d6a1d6532be6aca5b642fc15e210c79a9aa5f5c238bb514a3d40b0843da12cc728c89b74b5cee1fa41473d430ff09cbeec2d378014ad5f326741f1a3c1698531b0cf04c8757b45a2022dd9d03d72e494aa702e5cc4184c91b49b4e9cec8cab394531a5d45033a5726442882326c8c75da0aaaa061b4dc1e7ecb5d32a011f19dd260d8b34607163343f53e67705893931c4837465efdf48cc195d60a703a45b88798406d1f4c9d8226751f5e7167a262b1b819cc1bbb3e129dab0fae5c21a9a91c39c71aa52b695955fffaf53fad3e5d9f981b8274b7c951be57c6afc2efaf052a9e52051057f9977840fb1c9963f23a207106cff1b6b0bd01fe910d873703d517d0bf7a0df7d321b1fd046750d1bb39861fe1467186f4596119559fa57c651ffc718c6e063b3434857c0f2ed482cc35a5c1108480efe74bceab60e2550d90906cb53c38ba6178dd6383931d61f4caf440c66ba118f6bb8ce6e1e1982bf2ac85e0aefdfd4756d2de89e87946675d4a5e539072a93a0eddd0b4086a75651e4472e994a31e5cb4179e714ed31547e9007c3dcfddc775bb945978c6b16000d261242f46533d2c50a091c3436a84bcffa683037ba10750ad2d9c65b551fb8d093391e27f84d249af23cea278efb55802342f880365d44484d7d9a1fc8261bd2400de81843d8bda241856cd2952b644acc4c064e64132a7a4ade7571029d3dd39513187451d7c6857d784a0f407bff64abe9041ac81b28756c15ad9b4710ccf57760bafbba11910e52544aa763b530376fdac83733393a9c3c9dde4c4d3839166f36a5bcdea627eaa06b4d4029d1cf5f102598ab6165d41336a1e796dc905d18a2175b89768724ed962f8810a38cd8a9ffd4bac092e2053f69f42357438ef04f85a94196c195e461996fde2a9d00b8347adb3cc97efb27feda1ab28d7178119cdf47c78f863946368f9f0b0f221b378b100bd833a6863eec267763eccb79f65b804cc2395e693c0dff4c41908250299d676731cc554b1bffdefd07a93e30aad0e6827339c210a51202348bd0388afea15fbf62c82a7cd9594617d501e5c0b398861b2d8811da950d7b8521570e4afd4287d2071cbdcfb5caa98e1d892c0a12220535a5f61142f9c1ccb71c525e378bd9ad60d68e90c302d69b42baae3a42271866dc990cb3a0a1488f1d76c3cbffd40e67a20b406704bb34ec9413f124d80037906af94ec16992aff9ea68bc8f1a19a878bfa03f511f9b39423d1d898f858277bb0e1c5517da404ce02f28b9088b9f7e6ca525012bee2baedcb3d802e10fc240361856092a1c49ba0e86ec9d06549ed17b26bb81e8b55939c3408aa8bad846542fb2bd1420093541e99f317a405ba5c109da80c3ae22e2e603552b88223a68a6be7e2f290389a78d66b19d57539ac960c5ee4f27d88afa5a5664bde325ebacbdcb32a20e22cbf30f45148f9b08567e8456f9b3b5668bceba53e45fc9d8e17989de90a976e70a7dde904d6951a7107478dcf2870315bc906344b0962e33f971f119b895aecec8673bc3d0e06d9fc0cd2aee106bbe61a62050a87f1bc4b596eb18b2a50dc2b6b0fd038401bc236ab864e250cbf137d4960ac3e8a6064908939f632b916aabac854a3a0fdf44bb390b96ead9c1d9d204d71fbb8279e523297d07c26ee5f5bfe02f4e229b2c5f08fe8035b6bd12b10a9d2b83e3841007d8b8528aa8e95c6844464ca9f482a6ee00438b509bd3b762a3444279dcde278f4c4e30edec3acb28f8e8a70c6524e1f8f8114b3066958b2d3ede32599f01599340d8c38dc7880f0f81795fc46bb241ff11edbc25bd13ff3cf0da4dcd3e9ec0f1b2e9e1c3ddbfd54e48b7dc11c910377230e6d1438d79f1852c840c7d6a546b3b968eed1b24ffea6f235409f34bbe0dd30e9d62fb9e112820898d288d2addf7c66b47b2659b753316744a215384abed31f08b54b4560d6fb4716be4c331f69f81e55521eb3541df8fa1e5344c90f88e1cbc14106d0a0115930aeb97743821a2be361898a02d8a2904cd52349e5ca2762f537582beb4138231e380bd1e0b2886b7e14581fa5bbab094195e1ddfa87d089cbf558da5494e9e6f07f17af2073593a5cd5f7e827842301a90a5b45dd81dcd1302d926b57347eed2169a3105b995e8f47c9b96181e1b1ebc5b612eea9106155c1b64b09517370d2d9c1ff854869f243f59d678194c0e1500e7087690de76117e947acc999fb4bc91d080a1989f20a78a2383e86e8ad3a7ffee8bfc7ad1118d76796aecc96651b90b045c2c312767a3ba681a63e7a8bedc9f7dd6b2fdfe037ad0b56cb8fcad7cad08eab61a5380b6dcbb56905264707949a6ac10db63fce3d7fba9ce85135c19a017138bf7c90744979c36ebbba72cd7a00237005c919e9a2439b7cf38bdcbf06db4e32793d950b30f45d91fbc796f7c5cb13258d60033cf1b93b643a800c551c57e65e4eb8a059a8ec17f96e15dc637510b0ea4af6cb372920c5776639508f319896d644d316f15a1991a07ae33051031e1438eef593e7b32c4e558d269f0355616407b72b30f9e4fa81250a10cf23d57c20880736345f72a357c191cae15ddc88fa05c70254eae07690830b1d9029393fb2d4e91450260cdb9527000d15879f023758a4dcc294db0a4928878f7c062f7d934de64a9ef568c86f5940cf977e61b53b2a38448a690fd41484626b4e3a34d4284f519cfb3200a82908c54b8b36bb13d80cf4d22b2488fe75484828162ac59a51b198fadc3d5894fe10883f06c8304a32e9b4e39511a65a1caa597ddba78c6110f3ca20c697e8d184122e0d983fbf8bfde2c701f6074cf9b18bdc2d8b6481aeea117e19b8a1ca3423e7aceaceb6d007c3bd7d54968ab990cf25c38b74a194c1b833d014b5165d4b524b30051b9698f51dfe014b27913002b0e207c1cefad5b2638456f0a23c0fc5f25147869b4ec6e3012d9b28d995bbca00e555ea82d198cdccf1c30dc2adb413651366ec5da661ed30b48e0aaa7835379523c0645bd96458eedf255b3b703ab85851e8fccad70add31e431b80087047b85de7e982d8bfb00b249d0fffade98b9315e0883d913b234595ae1696426a869406a0589a34ffe525115da3eff13fe1c586e3924a5dbdbf18b8075bc5b775753a8ef79dcf815524547e52e39529b212079dfbb5eb8592bb7174771cfc3ddca07fca9076ef149a7872511bee599f3028eb08bfbd7668b762030ef45fc21ea73a1bbe55cf8578e0085176c987fd99befc4ec42674fdb3b5ec12f12fd553663740d95a7b0099b228e129b56fee2708048b4c6ada085ad3eff5567502877966bc75620b2fb5c27cf60b56add8d9127b1b0b05f6220c3d749f3671a0fc431eb534423189b3530cc43fd1d10843ac925d8e1128d93328b35f60b5e5cca21fe15ce21f98ec4423e4b9081454fb20d897964ec2fdc5df7787412d75d156f130e56af9580a5e6d5a18dba0abde020bcb5a64cf767022ed865162379976e68bff59dd97711383e38e1c197ffacbbd50e5af407bb921628815d654a377388b58e8990b418a52d94e17036a55f6759545ec8677e10c5bcb7d9af8cb1d4481ec5599205ba8b0ed720be0d965bfedbe6be864ad3ce306248bc1e872c938a158b42c2a65ee666f2c1c405abe2709005156dd707d7a9f5d3a1ac319602eb989b9330a8dc7ef8b5b3ce1bd068ae7e850bef3dbd886544e4ef88258a54d2f1926e1dbdfd60fb10df356092c13f47efeae4139f72b4fc48d306f4708d61c695034c3e15d2683c9fac20b12268d699fdc313099819e35c00ce78933923e674018ce26cc4cc50c52cf0909b38069c08a02aa55e30068d1c0af4b63d069e1320f658a9e7d06fa6fc4e9cb3d9f3a6483c726e0de7c9949ca991e0501c528519ac2be422eaeb7767272d5c4f29c9caeeacfa163a5c774bef65d798ec2af9600d33a31271f7d3a9b4e435ce995184da4b4b0c7e9c1d636fbb610f6e3720637cf8d83430a6d9c11becdb9e01bc681ad5219cfa8eacf46dc1d8cec9ba6ad58f7642610117ec5bf62d5ad6ed1240af0380dc09a93ab7078cae8921f86f5fc01bc9ddc6ae48340c3705f556dc414fab792e0dc5d9df7ac614bf01843e8b20bf68f0b88bc5705ab0d8c5bd9925b71730fa9e3aab241232825ed8c1c52aa5ef6ccaa46cd324fb22e788f8fbc732e0d6cc389a82468204cc867ce9e816a8494d26ac329ad77475519c2ea1ba95acea301c107eb4eb0d7f78217e3ae409e27ccfc88551982de028a601989a9b470fe7181fe4223ba6037260f2fc2ed2f34659a2f5a7b39816e2da3b942c08a8f07c14f85c8a251f09daef01290def624ab9e44a3145d824d4df9a451ea6188715d18bc26618eff3f0f7b0e402cb4635023b01a9724ce5592823c250fcd0aa627721105a1b72d1460b9b25105419abe527ab8b18f5cc9642ead1d3d8b47084d5942b0aba48a030b0531ca537b056caa7e8693d5bdd88a4a2338c02522c16f1bf3be07688df98f5a58562c180d8bd66c2cb4b8b06ce96c8fb92c4122390cb158a5928cfe79ff07e49b91b4bb3a24d09485eb4c7c15c06d94d104ba04179ebd13a3b9385e1710eaa4139e95a0d96a978f9acebbb7953ca4290e07ec08d7b3f08956393d6a29776bd7d07ba4e2d0076e517feba13af3ac9440961ccfb515d64cab4a527cba88b668682d468a5ec612e4c8d76f91a8b6f159244d9dc61a9e3260610c107df1b214f178b77f102740ce050f391ecd24252f371bd5167d6ee1f6b8053130c06d6660d1520f52582c8f2f498a35d1259c5fde573b5f2f64107237940b3edd45950683e022fec38bf210c309d2ff2de25bf1c9e4ab9243f383d82c175b1f49dcd9dd381ca36fb1b14ae078b61347c0502f716702fc4f42e2f8a077c38bd6481978fa8e6bcfd41182e08a8936a1766066e21ccf1ff3893156461be608ce85931bd80fdd1b8200895d5c90400f792f5131d3e8116ad4fc3efc77c8e23457190c3dcc6b53293fffb5b7a794f08de6c0608515667bcc08d481704577aae225034912e9f3b10c047f309a43d7bf8d2f218ef92aece286dbcec82d23e3767a959635038d74188ca9416fbe41c46457c88f87633cdf1375c505101e6a78e075cbd40e170e4d958e0a44bd8e579baef1a9da61dfead9059012d6b9da7ceca8baa4e00adeb1448f3e602e76f8e920893443227e2f2edeed5971163ef0a68a7f6e9fa7fb61e1229f32c341ba6213704ae4f67e7e719e4b9042c50d8d9046735f4db92058328206d2d3737f1bd9602aae85a4afc561a404a95789371bd8571579c0948b09db8283de6d368750b1333979dcf6cfbfe1545c338846b6a51c762e7f2d9a5d7a7bb2416045a9449983f1436f69fa4cc85fb19229cd273ebb645682404780b0090630ca1bc0fe976d5eb09f729394401c2282f5650d058e5cbb0fc6fad1ec8cfc5eb0bd26b25e16df12ea4be23ff7007500b63eb1e0272bba354a5a794286e0e97650c7d9577b9233196e61fbdfb27496f89f0e69745fc2addd12003798e0e0b9377ca19f0ed45a371001bb25201a0ba46993e1ef792b1307cac970c8ea0b6fa51fa611855961bd5d11ca1d8743df4b19fd82ec2e886900b4ad639c2e43b8fecdd0916a25781ed387affd998b95e8fd228129137163786e20346f942462cd9174c4ab6500104c73da75199892eecfd1ced5fc8aa195f8f23258d6cfc465042b3ce75ec423a49ad0562fcc86f2f5bc7a96371ab1ac3a77636c72f75acbdc6bb487e9b9c20ed5353b3d41e1d01e6de48c36046eb0efc907e2fedd4416fc7d5b7608da81c80c332c5e95c070a7c73d118b67e4fb8d30b0d555a96b07babb9f5b838d2b5654a834634afea92d278dd029abe8e13b58c16bb7327e07484e4bd969862dfe2a3666287a9e65998b7bf775b47dc2cd7f105dd0eadedc7c4dc8d20e6d358755b5e7aa38c812f56899dee7d8fc18538b44d83b2aeb968d332c40f7928a1233b5eb2152625a6e02f51ae39b9887d2128a6e668ec99888876e51206d7be608762b0d97ddacb59366d085eedccc38eec938ad44b84286dd479e6675c56c34a11133ef11116f23666800ca9bec9514bcf65851054f7c0c32d6e5ce0ab95873cf35f9dba1d1d26de085cc4ae31b6df5fb99ca45e2e4fb3c5c983b6b524572d3fc406d47d2e67b47a7c55bf41c11fddee634cb88df09cf317e26621aa2699108b6c26a55b7584b98bd19f143db1d7900886e303d56cad45a4db04ce459c58d261c88880104b0de021b60c60b6f18dfa554b0b146d866507815e43434614f935402a8129d0f3534dbf5026942f7711417e28ae5b262d66f101e15425f4f5c53848b9dc32e8a7253426b975ef4ca8fcbe37338981babb66d628180240d249e68d512912097c68bc761d820bd6e65a43c6125d08feef85f4186da636b8c5c410b78c3e09d25a18856c8d2e0d65a0c2c4c03ea63de8456200a693a1d6f4f3550a4a3ab45f9ece5db33d8fb680cf6db769deab9587e43b89582bdba62305cb792d97b8e80800355315cf575d7ebb64518ddcf954e52d52ef46ac7ac9af6dd438f80b3b4192242f6de5b4a99a40cfa075008c108404a68332047ae4be2e7856b6d87dfa63f0ec498c822e1f7f97ce799fa3cf8f1155924fc1df0bd1211f9044979c70ce63469e04b6b1210eb9c4b7ce69c4decf26ff9ff1fdcfd547ba45f57c1d69ff36370808d4bd5b1bdce7383d697f2898dffda265fbac09e01d8da7f8f1eb975df61bfce632d92bec612092a67ce315263afc08d4471eef69aeac818a1daab35ead28ca028b3dc9b2275525f5a844c912d7b05de59bb433e6591ecdf0db4ef9be5395045d63acbedacb56b5c01284baffddd1dbed9e36ab41deb0ca0487f4953e97d4cc21edd5d6a5b3b34eebda8ae3ccd5d4fcae3e9f95cb0f03bcfe5a9e39dbd10427ffa9475729e67d927200bb463978f1a013b7c60ed93b04e3e6f9f8412be34b44e16de5e78fbf3f62f9775027afbb74be86d76a96b74a68bbcc725f6e9ba5d0ffe187ebd4d2cd3705bb21adbfecde14c97787dd8bf33ecd3e5e2ba34b67d139cc984b92bd4807dba56566d46b081609f4a5c0f71964a1353133eb26a143c89703db8fb9494de5c0a6e5ba7da6eef9b5010d28dc8a7aee97adf30a8ab03a9f7ed7661a6fb668fdcef5bd7f60078fd5cf85d3822d79410a2b6d0e331e15acd7df6497b4694e0e9a9ab0bd730cf3c9b44686adaa9f7cd22f98dbb700ef4393ff2bb4675611b8be4bffa7d0b32f4f89714950efd2e9c1ff99b9c14fff5b68d37f4487d98b2696312e180b4e1c2e50b08d90e1368b08061cd7952e462a4c7ca2bd57134b45c1e82b3748f8ccf7cd172634d8b355235a0a48cd9f2a1044a728913b12f263a2a700a702c82a6f37d91259b37c497ece931c7a70dd1a7cd0ec6af3967b3cc399fe745f326cd871a568c1b55618abc819a8a92726683cb13241c15d6f38ccb71ed4603231492295eb6a00d1993854bd23e1679e166fbff038a6fe25e7ce108e3fdf08a44f190659da435f210e29606cc8e9514b24829a610922205102f2e2699a4860b4b0b2bcf3819343c7a2ec993c6c60aaf236d7344c25cada1c1a2ce1b0a395d9acc974eb3c1666595538c8c16d3b671e37ffade8761db23112f44902c76f68388b05b8454a892808fa446283f7fced9be098bb34dee8cd9d458990d40d521ab36a07c531dc11111ce377f04e897df007304e79b7604aa0ee1b7c1b2fc11a73a84d5a460d3904da69f0445c34ef1c794141c583918b0e2c71d326d7c78f570a00812fc4df01fc1ff02fe3abbe733b4e747ea8f3e1e7a10be3b512c7faba3d8e59db3cbf2efdb2edbf67a93bb544bf38136ef85d41568af1fa4fad4f5f4f9d2d49e679aaebedde3f36d1f1f1f9fd5b72ffcfc9aee0b172e00010161f8d5b781327c1666611652d7f34c539f0a026bfc197eeb672faed6b85a6372b549a1cf6fbdc26291275b638edafea66fe026f77aa2b8772a899bdc3aad739d6e4898a56ea4fa57cf4210b801caec59ef320fef4a9eee5d0bd43d10f4d6aff597e5bb99bde84b6eaa3953ed326569de20435242cce4451f52bd38f462d89c276c66aec4702483e8092cbad0e824f15223e86fcf6490f78456bab876def668458b0147f25b9ece4748e8278880d004232698608209845c4808cd0ec40074c1f720fc16910cbdef8d3448f0f7af962f7d08fb3e2eb449d7bcefffd6ffdfef01f01dfcab0fc2ffd5df590ba4d64cae6dffdb1f007e83ba9e7bc3ef3c06b27846e68d07795c239eb5759d95a142adda9a7bef0bfddd3ceb3e5608b5426a07be85ee7d14e08a473433163ccf110d7985507bbe596b6dcae3e9f1763a146a73f80a82d0a0a00acea320f3fa380f879eded1dfe1a3dffb1d879fdd1c903a704042e280d48103070e1c3870f8590b44dff68e5410f216528378b8c29edfa5bc2b74e07d134cf852875f9b8456a0b57604873f52d75348eda0aebe8da21cd4f5ace08f844448ba6f79475f41051fa4aebe0dc277a845ff56a0aebe9d1ea96bba5321753d777a3fbdc5bf197e8e5ee879d01fe250c15f355f4a1d38c441edc03707d428140a515c2359dcb8baaea84dddb1a32fa5fb4a16e3be98c983f73954808ef0a5db665fad26cdbe288abe0777a312ec2335888707e1423f2507dea17be0dd212abc52be84fe915210fa41e81ffd1a1414f408403f03412f941474040ca2206882a01141ea7af4f677475608b542473fbb712f8415ca2024a4167bdea26f1f68d728f809ee8607817f6f7b1e00407d0dbfe141f86ec34fc317fdaed12f3b50c3ff7e1950ffdf7b20a8ff7f7b08f8b7ea0ab555f4effefffdecbe3df577ce537f42aaaa4115fadf61de3f083792e0fe86df8aaa25f07ef56aa957c8865fdeeacfee9fdd451a7e7917a943ef0b22fa5d1f434241bf0a0909fd7a8b4241bf110e1452d7df414240424242ea1af4bedf05fdae90df2d16d1a0103ef4d15e01a036fa4c172ddee25def70f7d7c2dfe209a4fedcd3826a1de8f317bf053f291e2415afdd7387bcbdde61cafb0d57f444cf94778bf76fd7150287e44971c62e280ebc503b0a94e88cbaae343e5d972ea2ba2ecc84aabbd497eec6495952bbad52a8ada7b6f9c6b80ddc564d4a97bdcb3c0b56e9aa8b5bc3469116e9be4e48d100ab6f877b1c94696188db0bc18158bafa6ecf034cb448f785db7cec01fda7ea4191967b50948f24f4d07f41d0d775615dd7b985ecebba1c78df2bfdfbabae6bdfd75a982948ab0a9027288c8c4d09ded75d988902c413be6899b2150349f0be2e6a213d46b3b8735c96f93dff32b02bcbcf0050953484b3b44055d2fbfa774d75bd3d03e83fdf96b683852bcbb22cc3c01139f02621e9c083efe9206028fd19e87de95f26ed9c73068640b0bfb38a2185f4960fc27b97a7ae4d4940f4d43f9ecf77cb1b8c73ff83fb494df9843b5d600f39e77cbe2e9fa735739975ce59c629e745d4e59c73be0f04125924ff0e6fe44cee44d6c9cbed70f595c30e15952ee115189752cf304b221543ed8ab8541604cefd02a8b84026ad68ed98cb70650d303034c9cd0e1dad373bb0eed81f7326e5100c418285c894284c989c56605b6911e2188e3164577c80f11549f31bf98ca67e9a84a0648a1531868d619a920658d68fee82230c941b5c6b4eb2c0e1a2829a15ce8c39520566a3a473ac8186a402e72c8e0ee31c0bc816766638d131943344c336e30d1311266cac9c49ad10e639d272bb85eb419e0922c7828a161a2754b1e5d0f85642e9786104489537534bb458b04a579dd6c681833d48b66c1ca3cb80acb4188af18b56523ad2925ed87e2f58a7aba8206ac86094b541a1820ce3d90f54d559933750b89445bd8d7d01dc5049f912d5560687f19d184626161099f3866ac8962f2419117398020c2770626f725b2c60fcf05941ce2b899d2a29607dc56d9fdb0e67915cbf083aa8551327126006b59ae223ada09b434cbc1a02586866cebc99f34ab32595b146cad6a66d47d6989c565b30e79cb34eff8608331e91b3a548f10d2e5f1853407979c1b1250173a638259873ce39c4080ecce0ce0870be8d9f643552ea980f2c3728d61012a74c9c2d54b67421c58c0665642cc2bec2c84df9945ca4364e595c01e478a3ca1014650b2f3b0c6c4549f1c6880c3a39c2e40c5590d1c21246c6d4f1c204a4cea4a474419372270c123165d28827541953b29002669ec61365c22f618ac4e902b3facef4937c6d1183c71b22374e182b574881a2edf18a8c1833516669b29290bd173ac8ceb478ed8071aad83963f0821627ca97953039c19c73ce5a2ce32c29392e2c65b4acac15e0ec7852272ab8fa4a296793627556006ceaeb881a1634ac385d4d440ad507f9d4d934262965aa525fdd22148478895971720c3bc944ed9c7308881ce370c11882f9ea60f437b3b836ed730831b3664a853227a8c16c658a371590226405982e3749d81045a52b6fbfbba56dda783c7f1a4ca9e40b264a17dd522ec7f01327689964d3dac0d952bcaaa2d675264b14517efc0465f05003244e05acb160ce39e70e160945bafef8f6c718bbf06d3037c9554f7e2099cfd96c5a94a80b62d7e7388d9b9d9f001ff812cea73b14be3e76af06c62f5b389eb06989719ef8c57ca149731a2a589aac708c01e5c7cf9259bafedc34e7c981ad06167df3bd3f6bde4dedfbe69a48abbc9ffbeb4fd254bae6bca6f8ed38d0f5fdbb81ee43ed134b99ee3e60bcdf418b4e3fc67fefbf8d526b63adf5d66f55124359b55a5b67dc5875a3d28bb2d65a4973e661ad15e3e160bb8cc7302fcd8efb76f665adcd6fadb5d65a6badb5f8ed3b12eb2954cb5a1369edb51a6e973f5b5cfedde5afc98ff0557213c2cfc6ef4718e824e5b9f5b21db6faef25da5aa8927be56d1f1ab24ef6c879d9813c3fb1b32fd93fa313662deb24bcd822eb581476e9ce092962273a763626cf6f1fabbb4ceac8730a790aedcf44de3aa7140a216fc429ada25a6fe52dda2e649b6a1bbe11cd38d38e16ba96554de499d4feaadde6ac13ce484bd34a4b4b4b4b1bee58efdc852bd27053a0bfef52be24bc76eebdf7de7befbdf7de8be1afd0dfa1bf70d77783ae4fdd0cf7bd8565ba6b336eecdb75bb6ed755bb6af74db8f7357045b820d8a76b753d34318d48ed930897ca8ffccf332d52d794485d7d6bbab7b5d65a6baded49793c3d9f0b3f16848630bcd9f3a0dc434270f7c96104c1395506d5a730784073185e63fb7bd61a5000c0dcca870e74a29a90ed5d6a16dcca874e74185c3e6ee543273a0c21733cb7f2a1131d46dccead7ce8448721a4c96558247feb5416c9834820c17b404bed4bf0f3a17f8f2a752aab55e4e99ac538d5586b3fb2bfe23b474f39d0be7b0abb0be272d63f346efb69ceaa9f70f736605ccb3a69f8f3aa53d6a97cffdce5eebee6eeeeeeeeeeeeeeae93bda1fbfb77d91142cc2a8fd122f95f00577ad1f67f236e777777771f1ab76b959774a0ff0634e9f5ef1996479d316720199135af3950926b82ab6f6725585fc813c298a489135c9376ce397f3e3dfffb5229dcf9cece5f613be74f31d307ce68115e3161b2c5cd003a946051c58093634b30e79cb3968ecb8255ba46045db34e1ab28a8ddfb1ae05142d29921b0f2d6a3ec834c95a018a140cc02c4329722eacde7035c1d293c93c31f2dc4d55e39cf5e75f0927cc07e1a6699aa6a9ad887e6aa4ebcf8f8e91db34f9b241152f852246b92a4970d45081c95c062a6c564c117e0df101c682b7302ba927708831ec2c89db4121890b82e62b07171b50d25762e7245242142e5e459c34f131a44e12373e16cd0d181629fc4042a69836c4180915171d7147ac1c31c674363edb98b7f18fcc56968db82e2c2e8218638cdd5dcac82c5d5dcaa57cca996e5ad0dfdeb40dc2e1fcef9c2f25b19a33f18c97ed8e31a522ae5b900b8aff1d3a930dba1f8d4d76a4b48b01e8107b826507961460a669ea39db04dbe61320471c1972c2315da438d0ad593ecea6697eb0cd026cb33471ceefc062ba85875b6cf5f8d9f84fde65ba46a1504815b43899218896b129727265c839147894503bbe20e162c3cc9db81c2651cc47d69a2c3bd804d7749b3f82699a72b689246b9b3cdbaca282551c92264474c8099aa6699a9f4dd334cd131de85d002521a9deb82c8903765aa83946c1b2c143cb99e9413129b3238a9c1634295246461484a5ab9111f0931e3d1dcc91a16ee31fd4fc715baaeb6983d889e47d3194176f48a215194582237ca0e318316efc04f025a08d8d71d8b498231775054c10630f67a90739e8deb563b32e42bd972cbd578403adba92d0d65a6bad75fdb784eb2a093e5be9ca5383f88978a97067f4f970917db2d6437eff214a9a92ba5b4b74550d2c124682b100887829132fe23cf6fd9584f3d8ee5452f75bc4480c6216e4187fc199f4bec5d62b83135277777777771f3bb7cd42c449db8f2dbc6d16246774db1e8d30f92a66235988689dbe64ed953e4d3478fe2c3efa597c14b4bd10169f28a1dcafdcce62a6e0f96bd2b6492276f957ffdb775f897fa7f9f6546d26c1aa3708854f64bf5ebe4c3da6b9ba341526fa7defa3b275a2208b3b6292c1b1d2494d1a50a9a2c282cb8d0e30a3c3ca8f386eeec4c151a6c0f9bd19c9c0c238891293ca6817a7b95b53c45878a08e822b34b8ac15665c65955f53903e16582553309ec9e195257fdd0c8c74a46a1cd95c542d29a14c2172c15641c1666c455714b0325d599e928307fb1931695832d820d940115611b2bd99b90263bd9e4ca1f1430a1c154db654a85d5160869a28308a7356b2dc84a52726582773bb2eca8d9a12e55da7bb1bff62e72ccb49e4fb51e291ae3cf7eb1050c1432a2e0c132c686ce9e44c2c851bbee1906306a78d7f6045a7ced61a5b10336557ae937e6087962a517260e25411ed0e1aa8a9cfc8635a6c758624e5dca40df1c0480e35566e70518d9d4d983c41a990081946f1aa82834630276b0ce3921c6181268203fd4564a5abcf976c4e3a9b1e3b5f63c125858218323fcc96e438430b4aec8c4959a203cbf04a052bd2353d9bdcca93ec86142fc06ea040a1460d990a3518441764567429b9949cbde8313403a284c5dc1a152c182672ce9044905ca1f142859fd959a37503adadbff7e3d9bdcddb1af62edb7c3de36cf2f0fcac037b28dbd65a0bc832a51508f7b9779ac784df621545666ba9c89923e279fff16ca535076ab6ad937af888f4abc4ad7f552a6efd4a43252b25a22fa1af5f29872ff1be676bcdc3f3dacd81facd817ad7b583b233eec6eeda5e5395a8e640fde80f5dfba16cbd0ef0eea9122053fd44fa3fccf830b44ee73781edf26d58b5a5222ba32bbc5f8d90bbf745595bff6a8462f78c84bb57f4a6b67bab04c8ddb3b1f5af121c776f2801d86ef7feb44f13c8d8bdcf5d1e766faf3c73bb87dcbd07125a270cbbf74052bb0734b57b2f81d13ae5dd7b251a96c9e747faf56e73404c5714892251356d3ede10b7b5966e6deb74c9adfbb56788dcbad719ad13efb8756fadd31008fb96bff624b7aec8d6f96ef4ccd83ab7b6ad7bef85d001097b15087f4844faa96ae2067b1e2aa85fa9a8244469a844fc61eb51874e076afd4ac3fb64e54b44c3ad5f89789f2690b1f507e2d67b6d3a6ebd0a00b937286efd1750a5bf83b6e2f038c30685478aa07ed40d3341fdf082ec827421a60290a07e14a91f5d1b3a8f7d81c6063ef62a802b5b5f70dbfad70fc5adbfc8ca978e8e0e2cb261978ea858305694e52b7a3ba2f2e1e8e84b1f9ac094869a078505631dc828b2d741d146551ee19794f7631a5aa4a28daaf799864d46eb54b4f57310965edefd1bdb6d6b104ea43873f67a74eca068fbee57a4384d468b84fe6ac1d8d6cff3531a3a50bff73c00da1f8616493f075ad21503b81503380ce0ac9305a09d8191832c6906c60d9cc323b44efe46f67a744491bec4f31a888722d7bcb557a5610732faeb4006dab677faacd3cfd6ff59fb2eb8ad1be2b6fe5337b5fd2fd0b0541786ba164e6e6cfde5a35c7b551a22b736cbae554fad4ac3bd811610d5ce73c6e5eb371a0a416ffc431d6057873a006ebcdd5abf99c76e0e5de990d3068ba4d4933b6da492bc316d5b59d5962a38608eac389edec6b3944bb19c764ca1b7948f614015b86171244ece1492305b47263c5ba7878f355165beb8789059a82ea10a51418e5829b3460e8d2340a2e074b12ab58e45761d9888a922b2266e0d051e951b6788a4a0030d94343f822057a8da96c4d88a43e19823ad4d4a95b63847be9cac2240eefc6b36ee4ca444c38f5c956eb8d010831b52ec2a911c59f45040ea8eb0eaec0d5c9731364166499e309d24064b1595112c35407079c44ccd96592bd3a6c59b2e36362323a516e96ab4dd48073deb8cbc70a7081c206bd8cc61193133eb79211246eb8bd7132c2268723cc93a6de0ba8055b515310b9b33a3a1359c7332b5269873ce59e79cdfac4b775dace8cb961d6fc48808f1824b2266545a59c7e49419526ee0c6d2d51aafc294d1b15036c6a7cb6494792983d860a9c271870d6deb1c92d683ba818c11258e8835034d09861aa43532c94245650e07181642cabc746d6186a898525206488d744db974389776e4b61bbedcb183a6cd6c0bae8d75b932204044927857665d5fde905153074e19a42c47dc0b3a5d6441aa98d508e69c73d6528049227e002942260b96266580944da154544d6688c9f106c50c599c0b2ee642cdc71829b22546d27e90ad918a71e58d155c922c453df668c0b8b10109620687e5e38a768b43e64b0a3314925867e7f62223ac9d59612385c6160b7b02d91417725f900c7db85961692c07b5dc7d8a8b12272d880b2662650f32283c0ac08226ca17911658aec26c5085afaa3239d4de72f020db2a8fb4c048a25d09b3c845e0021649c9ea02d6c91dbfc071642b764a3b4a9ccc2ec850a019637301034e74c4a9985206c7c4164d0bc7b314451c452e532ad0d676816c83c0a3e7aa312b122ce5b1b3f2966339c3cd9dbd48cbe103e92467cc56ee188bf253a56247199d3228bc84cad2d58e89f0e1a31ea90deae4bdf86b0c493a3636448fe53063337ce998d027c582d45a6badb5d65a8f59d24f005fd2b0f5a7fa815a6bfde98fe7ece3a566feb384fb19acd0e36addf861a30952c68f3358a70e312f960c052130846b7351327ebea4ab6fbbcf22292149579fbd5a63e04cd152539124498643cc5886a31e73922dc280a9e0f5363f114301488958a241fada92a5460b285574648901412d1006470b878db9b2a9eb2e2686c5d3629e1493b10b8b1b5aca9ae7640b2c4a49173a67658eb77389d78a3637729c41c172b12435276cbda82aa230c6a5c411c6a6d545c441e58c591c32df91710a782dac0c83ff05cc585119434af1888115b6c4e7490daa2c73595d5d5658d2372a4c4b97613b7caed6b0d5597bdb7242bc01c3020f39315d82a851f380d02a0b0f38584e48814b62180ba82859dae6b418d2c5ce132816732ad4e0e6e6cca84a1b701940e021650487d98c23584e5793b1e5316ee75b64ced8c180850917ec2c66c2ff6b5a423406fd47d42688d1cc7c990afaef022541acb6462413f45f063a8226ee8f1f3fea044fa05758fc80044ff464a52f1853c113570d931e557a6382277e849870925194113ce151c8be6804f1fbcf040f9de0090ac004b19a4b9eff4c10ad099ef8911134e1264a284426c3a0891317c6540f34c1acf23c00f74f5caa38301541574f0fc0fd9de9c6095cd07f1ada04af18211b31e8bfa215823b54c7b3426d0f52354418f49f86a9e0097c3decf24e7ba32ccea5d096d9d7665de5302635beeff7718b70630b1b4305dd480e6ab5a5fe213aa0d3e9be84126bf925987bf73ebc75aa75a0ee6dcf003b95c867b1d0af0f08dcab6f63219614fdfb740acb379fe7c0a635e97a85a5ce58602bb658a77c73f8b5ba5bc49f1f381083497f97bf10cad7ea90ddf9022be1c698e908c517210d322b3596e0bf42fc774a6f7d6267f50216c9ff26d1b89dc54cc124f07d9998afb2551ee62b8c71d63ae78c71d0cc4e4ff9aa87fb438c0f535ad649c3872921bbb92677b7edc9ed6ff55197e9316dd46549daa88ffae846b796706fbb636ef26ad9ab75db4eb875c25869af3983c8399b468c01c64918600c02638cf10e449d9d8934d34c34f368a6a5d6c9cda3893491593b5752c220090325254b42e84d0f610d1185dc4e5fb2426e43451cbbd3f7dfdbfd4ae8f3cc1957e1a1273d89ad4e64a8d3cb333b7b9fee937e7b3d64de79a2399f6b09d7e5f5f0bb1efc7af0d7af73ceba2ccbf75ff90e74cf596ea78531c658ebb73dfc74753de8dfd3d3d081ee9f31c6daf594752a9f9e303eb3fb2d51e81e0c5929061ae99aba181fdbc5e4d8febba4dbb6c7e4da5e39d8fe766cdb63d26adf1e08250c1efb3e10b8ff6d06eefbbd1082d0cc28d9f76f8f77be3f30f5954ca9cfbe5b0bdc2edaf6a805b9773d3ec0d4e76aea4b21b5bc6def8429e2240a0531a499e0f561c7c9141a65aec4a811bc9fdef75d773f628c31d65a6b5d426f2bc281f68fb6a4173fc669979d0811f803cca47bfb9f04c26238672281041edc451f552f0946a3f15a0953cbc367a6404abd01487a9f047bd574a0c2203d1c770aa19ca55992529306676906472c7e792d81c2864c16d9714b982a1f69d47ef891ed17b63daa55a949a51e3c79193dadcfe77cde0f03a8b42c932fe1bf976780f37939e79cf308f4ed900f03a8d61c688fee9fab897d9e2a91aadef5c71aa1e4dd110fdc7d5d9766d38a74b5c702e07f9cfa8eeb276d1109c04c66d04f147d133d81deedbb92964322e8a0ee7daf7707d1a9264e0475af9ea5a6080e54cf5237833a55054bd774631e55d759eed881a8d2f084832a1a8a5a6d831c07549ae0e8284b5a30b4359df179d393c5c74d6adf9a52644c197b98d1b22565bcb2e1c5a5c40757591914d50d322e78b419526709932c2b31266a6538b290956338eb09d79db413904a56a880c54acd97569c189b768c830667cec60daeacaf1b295820b760594992460c5f8cd9cc563032040d2d6ecc15a8e1952e3fd08c4c79890bcb6ff28bb335498997fa988c9a34d8a67ddaf729b04a575ed35e49346dfdf87fb670600d3906c16233125c7d48beae92a80d21c32308b671fe71e07d5e586a7753921fdda7a00afbb6650cb514582d6ae33ff1b957f763163adb4826f4b6d7123e4414721bc2d2a1a4a4b48284d62acb9c9f884f564fc3a7ab27e2131187feb2ccb92c4becdc1fff92ae878bc1f570df04100ebc2056a89db399f1fbd26716493e82042260253082037d04205a7b25a1a73e0c3f507d98fa10e3c3f0c3508ad63affce7c74f76b7e9daacb59f72ba1b7f9ba6cb5de69adcd37558dadb495f3f4256d9ad7d4da44511445d1f3bc497ddb4ecdc468ccdb4ae88dfef9fe3aab33cfb73d54ddd9377f596713131da8b369dedb2bf3cae3a545b93939533dd697fc72e9df5a229be6a9b53eb5763704e0cfd9df4dc88eb3cebd9ba3f8b64eabaef6cbf267ad7dd35afba5fa3bb3f56da5abefb1ea81ddf687ece79f6fd560fb6387db3dfee5ab95cb526b5d9ee763476fdb79a2f887cbfcde0b917399b37efd3bacb5ce658b240a58051021c28fd7910a38bbddcef6cac7bff24cce6d73d8f6a8b664e39ebfc5f857969ff5f07ac0183f93cd7f96bd1037ffcdbc6c5ebd0657e2ec3b92ae497b63bf1934c8192c92ff051a11f5d6990c19ac93f564d6d8eade8bad1c57f90f0f3d89abfe6737b659dfbc06eede22f75eab111118a102463bffadbad84a0749d7a4db66bbcf81f9e805dcc5fe2b5409e676b6fd84cddeb69cf36dcbfa8eb91eac4d5e0f778403af6ebb6d59dfb82b5493bf6f48d28e07e4d99196247ef68831f729b76da6af744dda61b6bf068a49d7240ddce23bbbb3b9e12e819d0a94a0fdf43e01f18fefdd77d7813258a48b811ca8d7c1ddd8f38f45ba3e35da64ca46a150e823e8d8c8df9a1fe4ac6dd6596b6db56bad33564b0861687b60b70f9d32ac17c21f3bc63e80c2524bf742941763a7802d5d7d3b235f5a49e88cdb37d09f43d89d69ea8c3ece9c4b2d27765bff24cd63678d560cb7f19de2f986a4aed3e9743a1ed32d9a40eff06aa9e8799ea5d6ba9d4ea7d3e9743e2129516b4be129075e2cb43b30a6c252f85ae5c070e771678d76bab76fc2697928ba966f5ed2b939309fe7799eda546f7247da76dd920ee48993e227e14bfe4e72ce39a7256dfc249248249148e27277f726242e893bdc9ac41d92b1b1b33bcbb3bfacf496655996abd65a6b9df6ca377ff8b3f9e5af03fbe6979f7ff6f50f3f5ecd6ca6088186a32d3681c45adb069d6fa854ae341631e80cb26800000000a3150000180c08068462b150305023350f3f14800b68903c6c502a134863b1480e23218a82180842180618620842c428e51c232b00d2f69bda36e9e97ff6aa83ef1534edbd7ea56fcff4133fbe27404419cf8bf8e5edef787fe7a78feaf14ed4a25be9dfa51044a9279cfe19240b24f5d4dec95babe6980d56cbb18e46f7922846003927f9dd388836ffa46e5f59b22f019b01d801fc8aa65e39b522097b95f318ed3c7d205725e5a351bd15024ddab68ba475d1513044e9a6ebd55dfd86c085ec5a8ee5548515957a97d12be50233930ecd6ad592cea4c37a7027a2408f012599f7704c6b04ce309512a08816f638e3f007fc9118006b48f6104352f5bfc82945a19cbb8f5d1f3de297f7639076785b2053abbf5ba4fbbd5a1d5e5ba185f89f9ba3b873f11b9e2c9f7c34aa3311fb10f6b334bf2fd59447a337f601f20bf16fb045cbfffa6ed80851b1e70797537a616abfe016c3ba2d5c053c0c1fa1411c470de0404515f212415dc275c6847cc1b8b81bb133b25e1cb2940580be013a8e566c23940c5638a7e2307da34ace83e8bc97127f90656bc9ecaf946b856f2ababc75b177bb7e8976412e02845b5790257e4d5de1b732a84e829141e195fc0ca64b9b6f2a6998133e90298cb2a634f62ab2a432c26188ba4962dd0c8b3631b313e01130aa13d66b0618d98447411530f22e242a23880aae1b9249944f26b84d16608284216df64eda96eee26a064c3166ed845cfcedeba69c6fb77383b2e65fd6c87a89e700e0ff658ad8fdec1a9c3d9235d5ac50d539aa103f0afcb160910050d95500b837550820df01fe604673e5cb2ce7e297cb03a445a30113e0cd7831d769207eac47c5b5bf9ad121d4b263efbd241d6998fd3c5a3741cbb177efc0229ed038486102e42e26dbe3946c9dc6a41b815883a5040e100ea8e46a5d90f2d9280aa5de6bab5eb0713c17221709bb9688669faa42347088b97f95c554696055216067157b84757e7103a37d1d1e98a6ef7785272dc7721ac654a6be96979d26c92c42b170551152263f087f82303df4ab6bfe63c16008b20ff2b7251d64f2cc94e277265b5bbe623ffd9ce7cde5db88963398aaab15748769bd3e7daa178899a72a91da03fdc522e1133a905987b62cfc1c53356b35284ff9334ab314f401c2202f02b8e2a606278076760abc2b32efd2d440e6318cd3d52ed858421ce3674542591405d5704b80686786491ecf9a1ea7bd780bb1abde746e3fe6b904ca3e56604f7eb68371a17c05e40349ae700566b22b3326bbf404438a30ff66b4151b44641aa3bb5248893027a447b64294141caa4d1a7e4f99f4187539c275dc1968bc33f49134ccfa325520bc81ce040de9e5150d02fccdc603fb7d26e4b107b980ec2a79e14d69421898db8f69f0c7cc928ae9e958748ab0e59099a6b7695e71fc9805c6ac81224247d3fb5a25cb58ccbc670eb5e15fabbfd5cf8e261868c2141872970c73f5dba57ebd48f884268259d6fbaaa9567e72fa9fa1384be2f7043b5f87ac7e41f688e60e36979a9774a9d90a8236f09ecdca20776886f8df4da5ca1d11a5af9230794a77d7be06c368549f4b4e58e28b7ec94f1820a2da872cb0278887bb1e42ca61363554cf23a69e0c5591ec0c8ad040ab27f0a4026e9d6c7d5cea7c2d508aac5f460a48d370d1d71fc260a330046b0238680baff0321d9787fa832c50b350fb6eb7d35727a6069ea62330209055adc5ee9d4316cc260df81e5c082d6fad794053edf7d04bb532134f4cf389e5e0906b3146e9ecde89d8d071ff258c44bb72087ca74e6317bef249690509f8807c5b40829592d16d8b29778b8d86f7907f6d4b1e317e121b3e8a714261f59dab011958919d88c3a31e1a86c94b339c5dbacfd4081b60d58e5b9d6aa7a9ad937c5759755af9c931067b622abc0bba016e86c8088dae14ee54dd76fd38b57876ab102a502fc87917d2f5e331eec59964c3791dae1a4e8c5b05951b9b5fe6cf393aeb8c0e70dcfb39d6515070ef5d9dd299372538445c558e80dbf27fa172fdb86b0c57c9869cbd22a4bc15f079dd8024e26c90c229bfcb6b3a4f4b82489ad34e8a43417ec714c5d39445bcb43a725fdb0021e7501bc94155aaf177ad490059c1794e17cdaeef798e902feea89100c39f4c977a8333e1c861675b373ecd135c4992168fdbd51bda4e4d17bf03837ba9ba3a26c7385f674e740b602e79fc2e22f3f5c85b8973ebd8d94bbda7f51f552b658b7f7a31fbb68149c77451c127bc3fdf3ca5ccecfc07576c48f105f9116e824ba4e300d39197c8d009c1d9386e85903f6ec2010805ab997c05272748101e7042e923592725c7228609a33bb213bef9163d4c5e0eb64590d1433b09aa8a9073f921b265bf8a53a2112a36a0250f421d10ae80fe7fd714f33829620038b51c2f16b21241f402ae106dd676302978141818f894c81f4239e0e8c0b038ba5e9f8b95908d4386208c0001547279fa39cc7f654dcaadcd21fe2c69aa9fa3a28b299f23d6ced0afd38d70ad699aead0c361bdbabbfefa1371b6fed32ea051b199b0a7f22e4363d0777e58f5c2d8ff5781ee04ae50e486b15870712de8db36e6ce854a1015c461ece0d8508955bd399e6c441ed6a36016b3710a2fa42bc944f4bbc015c0669e54b4f6c1e57c669e5f1f0901ea14a66656923021e3ecb30ceba4eea20ac5f95616c70e9046b9785f97363b6d7546a4ec459ba5a78f2e07c66cef9e6b2e064f084e019bb00adcb7e43b6928fe6213825e413224a1f31deea484de7a0cccc11f98589e66723df2a345084f014175b045795c25bbec6c3d68a76d9f31bd4fdf9e569762a3e1da9c150ae15ef4eefe29354261177a643de3fb761c7dcb60dbc809f66d9f43a4e2e44c4f4589af5291f584a29bd8db276b51f291fe405112881a159746f8e03901c709fea6499c5dc619295b8e96cbaa180f40b06ec06d8c21638724997aa1fd74c9f1571da51771a0e881285979d55f9e952daaf24ad6033c4f8ac6154dffaec4608b0e3b7226af5cc223feb6a34096c6fffe2cd7fa56eae7934637397347ea22452ec83b3098c7c71e1a98085a689d220a6257e652df1ea95bb0304e9c3a6ec8e80b21f70d0d0fd9131afbb552f0ced40eb37e257c5427fa94912596b100a847a58167e6d18b2aac9fd1388ba7d42eee645badb6d9aa09a0dcc5c956008d8a62bbf5543f6ff1599fbfe2d7cc8b03a3c6be9d68578174f72dd8cf4f66ec078cedd1eb99c5d0798fc71921113f50ae0c4434970698bc52c89e493ae516253181f9c23efec9835d450d717b2ac8be48f49a98c8da3ee7ea48c9b518ab93492053b88c273b0611fd59decd7aa961381edee7cc481c4b9cdea78ecf5d4332c8cd2bcf1544be7ce008de97a87b37db6f08928fafcc8f693e0ceccc61ca68f3fac7e0d2436941b9d3e0fc6c3a3607fdf255cb4b55bba38e43e7545051a0a9e8cd2800339bd747a02c23bcb5ea51cf2c0ba7e19dc50bb3998c7e5d9b11df4f30bd884ff0d7ccb3e7e9cde62d44976abee45a3453c4df47e5e3198536b5b98928c48bccccc259c532fc7342959ad3306174c6ac904b444279de4a5a59a99b7595a4d36d7363c41a2ec4feaae4cc3aa2e6a5665ca0d7e3c4ccc0df2fbd74cb61e901281fcbda60d5e326b69565b32af5afcf6c02974574d0d6ee8c15aba6cd5480c7ccba9a36aff3c31d5b2c28a8944001c40f8da464593c9e0dcd29e394def83993db81de0607ac82752b62daf02b8064439d32ee202884b5081b3de35c50fcd72e70d6d9d86daf46b0192c9bc677cb7a1f322e82d4c1a4135bccd2ee4abd7d7acc5587632aa541c9f142f186e91738d3420aa11283409e347dddd671015daf7d2e187c528e1d980fd3a611f2e0f2e503fdae16abde6df9527b440e373de5b2578c1abdac08c8b81bb6280d7bead2514c7d3caa0d598bbd82da1c7e74102bcc09cd69f944527a30f09b3ab52697a5118cb45db67a897f9fc90afd741ae58c97cca1a06a33eb6aa4b0e2bac05dd7cfe103d215dbfb40a83d11e0ac30a64643eaa000b8476eda0c2dacb1340682ef425b64c12ea9c2998cff586940985518b4fbd9899ec1aabf2e6bd966bbe312b43eb3b5eaae0140bad8b4264a324798259e28ac6599bdd6ac84fe30751dafb53143ff924e14f546788650ab90772846497a650f5e4433f98994e6c2be785eb03f409cc7b80efe5cbce3e3e7935d68f98d8efa689f18eb6ef9453e8516dc5667fbcc07c8c4a58249edca72cb6a2b35b4406206853d2cf8f081d3a9f3a04a5be70e36eee75a0cc179e0341ecadc26984f3eaaec908209268d6c01e81684581030b99b649caecf7c8c71ea62362361081f7e6dc424902b40d9df681c1cf6a0de32aa2347b44301b7f9df5dc07d89c5253444f4a60b98cb2c4a701f010295df27b15214ef975dc851861f4b8389e697e3366a1cf8f05517d67741b923db57ef4f45623f359a359a9b4592a4a0422bdd15673c857225ad41190566b1536a57ad4bb21b4d7b287615a04fedfc85a4a70ece7cec8616d76e9b9a185a5cae0c17081e5d24647601533949f6de5e99ede6839db96017ff20b2b1bed0af5bad5d32348a22c03be8a6f561b5e12ca4d200b57fe4a5ffe866561be26d3ca54c983a48823e2fd90539cbf9310bcafb29631843ec9c0fe9226f19e51bc1b6961ff922412f1acf5812e717d301283707d11a4360b983c5fe0faa73c9ada6ef7b4d8d63bb9fecf81558974b75657928612c6b6d6e0d82737cc55475fc66b1a9550e7a384e9c041423b07de743b0ff94304c45f77e6a91b6bc25e6590ddd4e311747505d73dffe9eb131878a5e568928633a03c240cf0f49fdf6e4258505a24337f650f367a9e8d17fae567fd436ebe3afbc893f0a1086c45c4d48f8588380178d060ef4ee8cabf70aee0e1a2830cae8dffe8fbff830a1831287dffe60a68161c394846ccd499806d8ddf79681f527660655027fdbba9cf01cbf18c6b2ade0e4e88070a465130e72d901d279196787c6e5d68a15286a71bf16586fd8ffe1abcf8f37295c484a77d531548aace9f7541200424dbbe50aeb39e56f819f099d53f17f10a0034c849502f0dda532b4d47c974d2684aed50aeaf2906fa45839d8b8e7c19c27227bcd7456ea5aa636956c5306394408b2e83ffed42a1e63f1265064eb6d740f243f5bc5bf988c23ca2e3eef078ddeb7b17580e74f58ff035275278e05de501e55a03dd67c9dc4b2778ded8296fc14445913a8e35232dec0d5dc48ef9b1dbb537630c9ab05cd90f0d569c25ca5faa9d3fff1d36d9a1a1a755255fee582c2c9df0d4000c1ea813489204d5087fa04ba94607faf297a14ab01e0408851046a94dd9cabe1e5ccf0ed56e749aa4b4517cb67e0defd92f8bcfa897c3835ea8891acfa6320c110fd0b773109f851258518aa96023249719ce01ba2ba1e27f30fe4e655897e2f151306eac37a576c776e011b727d6844cbe9a59820cd044c365c3d7d28040639c869cb77a1d8cd1bc1f9f03e60d317591ff1348677c356fcf5b131663bcd1fe9303bbdad57fcfad84460f3836e35635e2f965b8c6353afcda6128857f5d604ad7b17689cdc74800f819e95a3949f9bfa86849035d72fa3a6ae2b31e9996a4ebfb813d795fcdb42eefca08fc9f9489133514f9a9940ccb9b0d336ec8b98481a21f7d6dfaf1ac45d60eb8fc666353f8c7d5e0c11b00c57f3bbe03bf8902b5ff9e5e64643cdc994cf0eade6375cb31df1ea5ff2ec4bd33e0f4c2cf759cb911f75bf601ec968872e4bdc3f0675cf432b66540d841814eec6e47d638dc89156a9c20afeecb74dfde02f1bc0cdc4e277c74e239055faeb4aa59430c4d709371fc07ee09bfb5c65afa97dc1fa48431426efa2a1b648741df92a87f550e2380f671e89030ef2b9212ccb63bb4380416f1a22f449d12c8232035fb4c03d98fdbc77b285beb6d400b1417d4ca6e9754c92f948d00f61f34ed562f38bdacf438a9c9a4bea63e786290e1841cea579991a9a40c146ef7a2e35487afcb8f8159af90128d75399c271ec6e4c01b55a215cff61b6db91e1496ddbd4da786d2b1b1ec11888e929c52241d394927a122bf20832d9933a62a64f057480e77160d882095ebb334c81ac4fc669ebc96080e77d4efed75e83f2bceb26de1aaa08136b5a5ebd36b26b1622a843377e930c25823fcf065a925d5f11606797105657f9ffe906fb08d58daf6843943755b4e5d60bcceb648ed04d2d9b15be30b7312dc0d3d4d433a9328cbb7552cf8b451f7f50ad4b657c71c47fa704b4b5382621fc6fa0611decaa8e88a64a173e65aca640f60b12032a068808dc7c4b83d009dd7bbe8a0dd8360b819e8f39446c215a580ff1ecbdaa4d0179a0f31cc3e16db203e9e33e8a10353e2142929372ac40320d2b284bdf501ee9c6d294c6845a8b0133f83230c30a50c465256aec27187481c5ab8a1166b746b82c413b83f400dcba44c0733cf9c3acd3946e37a6936c9ac1d9ca4985d7ab6b108220587f19ab7519fbcdba85b459aac42ee355aa62f25b7f4f1ed92ca3bfb48176a9ff5b49df9b8c570683d2366bd3021850844eeecd95f1507c6dd58ec6bd37330bad04efb52a7defaefe4a6b0949d534e7090b334e732ec510ed7d9b7f00b8a86153e4a9298bffe6a5e320abd21084eb01222230e86514b1d8ea4a7c93ebab263c483549e0f63992d2a72604be87379769ea9744493136fd23251b1cd81dbf2a0f3ea51700862a5271af583b2935b30b0ede4b2dd442b68d1065594b2f62183218e6436a94abdf4b0f2b4401121468ff3af6e7ed92377f0edbef340432ae11c63fc11ae266551e2f3615a7c7688a13a7b445fa74e79cdf8b31f6725d200b7dc66980a1c445c6823e2b5c2aa5b535919ba916ca10e1e27fb863955eefbf7a7340d2c7bc7262fb811d7f71646eb656684bcc8e3c87fcffd9661e7a887a8f5f9f1b1328ffc36d9f9f8255774663387f4e6902419a4a1ab3e5f50012b007d8cd4be38d6695c2224ceefe73f6b2121a1c1a5518c39de93360b4c0812d553601cef05a89c64c2b4deb24b0d27f96464f7e31e4074302f95b4a5c2b9c0e485c6bda7d018c93a426fb0e36b81d91c21cfc7b51a42c12098e8ebb802279447c02f66faef14ae0caea5293da252e2f287780fa612b8f6698964f89b88015fc264ad5bed91ecaacd579d039b207c35622ea4de467f4049da37118057e05100406ad9a6bc0e24820434edc94301e245f229211faf5db5356588bc310171090a17a9911e1aa5a20e2110467c36abce85f7ec96aa850abe9f0638fe9ea19d5429beaf250154a546b90ee98e1a9e99d6835618ce0e05e16447438817562ecbde555d3fa0509dff55e6baab98e29c9bb8324aa588fb421145cb2c84482f46e893f8b23825f089c9ec2f382d986e1c4ceb10102325c6191e416541b724d3d7f39de4603e0d0f8830490968341dc3b6d065fbb20bea814c8c7cb152517a0c213e78d26ca967a61a6287d53cc67eb8e7cce51f2a5c794ed5a750243a06d1723e3d11ba2ed6093f3b623d4322464a54be29f7255bd7c2052f5bf6b12c9817e6a48b9c254409d95fd8c653f23a69898ed89a4fa0161beb18a6481bee7fd8c9fa121000303d5e30c76a0503bd8593411cc8ed6ed0881ace465bf30af430c9710c35b3dc790c68ba49031a0c6bcc51ba97d7bfa5f3440fe39b2b2fbff8709d798cce4a9e79ad515bcde669e92c90ba2a06621195d520b16d87177044a32ed703d66b11f1b8b37a84b8505026a49365e40b0bc68c5a4cce0e2ae407f51a4de4d28e8f76bb6ef68497d9c621d2558976b004d66f8e4a5f0d2480ce74b71d14719a5133f553e0aa3e29851143f298412251db983e3a8756063594193472595ee2dcf6d0b8c2a55c7184074fdf070c911ce420245c7f98514fc94ed4794a766827375b8a0c43cc798301ccf982780ad17410e1605cd677e52f23576988317ead5f71327ca7da549b99ef61e83ce1d6029135a38b6ebd3f91ef73617e2f2978a9c75e8b0c530e42e519e9d2791ed4622e8adcb80d17ddb6b94cf870cd27aa80458a86acb944cf00a7a84414814912a58f5d485e4cfc1883ea798352267ff639cb3636b2e4aa2be6c8c63663ae4621c7e3d884b312e6dded3755573aac3c397dd40128c3ace7fd8c1658ef67e7825cd0aec802a471d4cd49463127cea865020737e0a5496bd010648c05c29415964869be13b01e0e15fb5516e0b86bb130a31f5a44762833c705d2b3244e9398741252ac9673e9da982307c4ac45bdefeafc6d544ccf7bec4063f886b44e8fa7069253db855bb1d1d935507c625357118a0e73690533073585686b995da2ae8844d30ce14032a3fff2cd09fadb82d07039207d1554e894099d4caa81d0f49eede612b89665d0854dbf21d08c2243e30b0a2acec7a904722c59c19176f97b55c6fbbfee33c34c298d11a56c341e6d99031c00ff826d1f7029968db2beaa0f17279a65d70b57d991e0d28ea9754b2a7cf79b78bd2c817be699636adbc72163cffd17b48a81a5ef65c55150527fc412c6f6ebf3b60d3970810f3e2f49adf626d0dcd985fd6f283ec28659c55738dbd3eb7ed3ada002cc232fad04855bf8fe6595b71421fc5df6917884f4296f083f0e7401e3c6897ee45fa877d383309013378dcb9f41ed1e5e4b792f5b0cbf2734f753e543b52710b406ede855f4a55e8330fd0d3ab562d71b9da4a104f07aff30423dbc4a23a6dc9aee33b97b84e73c2bfa585e3b5ee154e516a20f78a2d1fe64a7b5c95573033c0206065d5298957aa3931c3ec89f65b651296158f95e2a0ae60aab5f2d410f44943312ebd8b75cab82d1aaf961ca670b48bf82907cbccf909f83279c7fa8de25792fde8222cb0f4b2fc306f77939cdc96375217a543a811581a6d87b9f89f0950abc29d84974f70c2f96fc22962d3927e447a4a30e53a25a53a9c74a2aa8b5aeb585d8ae1daacdfd9299d99c30b224111df1a2280a11417319bc27876db2a26a88b0e3e0c52c88ca66143f4db7933dd1d7a63ecfe705f15ad26c8cd936d3d7e5bed5bf88e7756ecaea205347a877cc2e5c8f255a3578f45315f9b74785859ac74f8f6e49ef692b3ecd49f30d790e3edbbbd206207234b1e35d297323119357608d94315a6894f2cc3460c82908412796fb2b0d071201593a96ba01c07a5c7ea21d11510c9c954df28ee8b3409c019cd5e56ed094b79cfd4051cee78a7a90f3518a7e5785391852797e27bc5c358a4e109dc464f9fe3b712d929df990c4c93b8289ca9c27950355428f3706801f3e43a41d2e0787653fbfd5a7d7cf8d88992694802a522d0ca5cfaf99efa405c93748de63723833c6b18e92c83f7eb3eb87c08b60048f1bd959e611ea75ea18cf2941c995c33927efeac4aa08fca284f7bdcee8c0b6b7f25a7baca1909d56eae6a1b5a135793adb1dd11fcb8f9cf728ac3124722d102673e79ed7eeb43871fa14bcefd00d95252e7fcc4b357c781d643efae1e9a655510a1bf26d1f103dbbb28306e82e9b517dbe21d24da95e048801a180d5dccddc4e7fb31ad0525926da69de554b49901f47605066b8beb16bccc7dc83ac3cc75a12bc8de55df017e9993cc309d9268599132c8cb2c8aa7f3b4936edb2b0c873b5655cdb56d2195efca381d5379c596f6c7509f8c6d2786f7787eb86fc64a23cbd78ec14aacaa056ca3af4782dd533b955afde331b36906bec0984b008c121055993b65a31c5ce4972022d67546d21759c2edb20471f5c79f0b0bbbb3a7be0c48fce7a9edb838fad3697fe1a7ff5a8c45917e6c1bfca202030fa6cdd5844d9c1cae2d699b22eb81b71afb3f20db2498a0751fa4d123e6a30f9192041debbffb427c210d9cb90d290b354a71b19e306ad6f1b1d25837db2f55ea714271a14ae420213bb00b20c9ec04a2281856c6926a236b50971df014a6e9823fd183f817dae50578adae19d0cf7ba66f8e5d5728aad8816d79173640140c35bb636ead955106d81f9b7dd8f8239aedf1524205371f4e34a3f7d391ab14e1dfe7c8c03f7d28f1437c749ad8146f9f899f19445c86e458160fe29c57ad32327ca8d77343168ab8e03aea68bacd803056a7cafcdd4296bd8c5d8c329baaf852502ec5d206a1d6d5207af6c54427f907fbc0b12cce82adb00e278e313abcf4092e4c03b06c8ce93a169cf10a753668407c47e0bc7b83949a52b991ea115fedb74a0984a918b96a9712bc9bd124781db705d3c18d9046cb9924cf9258a8464ce9c77346d763f01f36022685dc386d3bd85757433640c88537ba003ea02453a0f1683fbfee47079ff366835f480789584b01378ef9f07bc7f5e382cf107af825fe9452eb18bdf0fc2dc0b027ef00d9b49bc6e5712c60a2ba74b669a917744a894298c8f9d3f79c59929ac297a22f8719e0b32cede5e8b46e5e6d0a803b497fb7e22e2ec5a1ae74370ca7dde14eda18450b5c7d157cdf03fa0688fdaa6750c3d9eef2d048a39cd98fc6b8e8268b510058cd0800b3f0f158c959dcd68e1d0c53bfedfef9e1d2e487550bdad2191ab4bf424a21b551be3ac5b868d899f58360aea70120ba374007e32f680944aa52049c4e65ade61f1c4584673acbc12bd0494f7e7f7709e03414c66da54d7cc3efb529ba7965f6c4da75554918595f03eba481e0b72865ba3d52d72230cb67b5590c0dbf0ea2060dd351c5ad3bd7d431c971434f1df7a132a4e284f1b52e2565eeff67de9faa7d93c56792ac2b69da92311ff9c76238c868e39df5d1ff61c94ca0e5d64e8fd6f19ed1d9a502a5e64865b18feda86791b6093003f07759b81c4ae371554464175f2be47b9a90760a1bf69736f5ad6d5f433380d56e630a9e46e113fb9b1dd1ba651cb41d3ac969f9f167399712be667dc404f296f2ac4843e3efe03bf4627c74f9ebb8bb1b656168c20bfabe5838771a4822272f68cd5b989fccd26af896c2d5aef0e447522ebc63e63f43c2d950ac83246d6bdc50ddd9a9aa06cf6054b4d11d1c9aba49859d5566d57b9eab81cfc6adedad6e19397c1c7fcaf4087e77d320b632d1c1d43af31bad522a0e6accee80ec35b531f2d7664cd48a2210108cb894d80aae626dc063ec40b45df8eb166f490b3f0293557cd94decddda0b44c92a872370c65c9331ef388b54b47403db17ee30a0b6f97681398e76790dfb2d4d1f6d256b34ee4ee7b6f4094c411cbdc70d18c8df25a1cec1fc4372535df2a69d555c43c32cff64dff5dc2d00b6b84922aeccbe979a1bb22661ec88a93facbc237fd35c1d13795cd5d3ebba6a5a8ca8c9d6f8f62b3e5faae76aa4211242f20f424d8eae014a11215263de1bd14e04d46f1e862e5e48ba355c843082f002c7820e6ebd834a0f33cf627872599eb081914b0ec26b666b7dface2ad41f8824ee36328b1002460ecbf6f4d5affe08b849b48307746913c67e058a655a9aa5b848089d3dcb9e9b644acd038dad392fe89acc480379b1bdc6ae154869b3b4ea47ea5648eed70a86355101928f9292478ff34fd06b33762e2a6de651d6794271f142eba5c8c16e6feb411df35e64de23bd251ca009d0c6bcee8e750388a3603d4743c3c998a11891ddfce1b1974c9a8aae280b1b2a96cc98d471c8a53b83e5370095d1c5ec73e456e427d695646e2754ef807834ede1f16921549e2675b43ebe5919c24b3088c0887ba89fe0f19c8ec4e416de2384cf7c57be610edcded406cc6d337070bbd746c7654095bc04ada2d7679940e439bffd9dc0edba590ed68fcf06ee328baaed9852d19820211f9b278422216672204bfcde7539bb9f31698b959a79854adc2737cb553924f900820bedb22c604f71a02193dc821bc4bb8e00b381757d4520a4247fff15944b16c6e2fb5fa100b7e879566423ca6d55dc272c0e218644d78fe443d4be92b8d765275000366949fa5ec6b682052739274f16e19700d3fef394edcd0a2e3dc506761f68e6439cc9176c62eebabfec879f64557561dba00d6c8b4c163971842aa0e7f5003498a8043a26bd29a4e87661525f5318d80f08e97afc6ca239f2d484f3faea2ed10dd744f07c51354082cedfc2c1f99c8480a940bde7f883c9e053d2986962d6c5aae7e8dded4ba0a52aa5926c54356202020d4f97ed7bfbcbadd84606ff46039dcd8781d5da741926e4439bcaf54a5f3d35816affeca86d8645744e573d30b863bbead3ac28f7a927c87a6b5dff7a0d723d601ed37551fadc30db9d27318a51cd1992ce02e26982cb77153181d7029992aab6139a15ffc3eec640a972a24502f07d931311b3589daca8ddaca8ca53ff8150ad99cc80df1de4fe594e0c76921b1c11e543b96ca7d107e2a5061b76fcef96f47c4a726acbe81ff262357078b0a634fc8b6f62802140f90b44f5be0336cf67a1a20e4db9583b9a41bac7071135005f6cb851be4d2ce173b0669d710802f43780939119ff6dfc469296c7dec8a4f827077f12bd724847d2c366f6d50f3583be400fa514a83f35ab4edd5c239565ddfb9a877e87bac002306d5771a2ea9df8d0a5ab4a1bca523185db467641c8c0fd2f4be1b1c0425a2d8c80963f514f17950c6541fcd9b78c0aa4a9955ae701d6ac16fa665f6571f36a98ceb8390da545c8846121cfa0360348e5c4fced1556e501a41c651dc1fbc7090d5e98ed1fe2fb4e74833c1a9d1c10eec9318c133d293fe44f9d83ff7eebdabc8426fa1e23889594aff6ede906046342078f2b07638c382507515e008ff02dd7afc1d3d53434cf9454030308af7ef48d152bd14032a16f5d3f4d2fc2cd3a5d0a16a902b7fe767926ebe97372b1b93c97acaaa10f4de1c9a4fdc47dab741dd740017bc223c9b1168a809369b129720241741d27edb8de20b4bc07f3102d62cee1ffc664a10d29a50fe4b70b80a34a9f5611cfb013e6eab85fd9ce6fe6bd7f39d2cf8f016f121a993e5ed9072fc9ba7dd66395cf720be830587ab4ba63686b3d29241821729c277a8b2345aac068c11ae7f611c9b4c87f21d9508b9cf6ce3fd3879aef59e3eeeba222c1a5594c0b5174b536d144e67c507f3ce978bc8c4ef000494ca69ab72af3541b68310da348bf09e3f3edd60c81978e9d52a91546d6b49c2c58dac7a204456cea9c64d26049e0af81f6eb2448b5b8e90e455efa434ee71056f0394adc8c1e470e677f56cd4959d4d9e9aa84e0d88e15182d744b6f64662ed6c4e4a7cdde0f1392ef5c9ddb7c0f4a69298d69e1c7cde1d4b744d4ef299ab990c2eb1b1a7ff93e16fbb146941012173f03f988d4fe3481d6022a410131f798ac94448f86280c6e284f14cce178afa1dc5d089d739e64f11077125b496128434345bc195a7e64b2ad17621f32c9f397365fdb274d5a33ff56aa51f9fa24eae98074263adc8d9608bf4498f97ab7fb83198fe298cf8e7fc64367c93b51899f30cfa86c2d415ed8b3e9f41a3af31ff649667656f0ba3ba1248f6406866d669a4cc6cf390a8c937eb255a546f37e5a7318ffd36963ee64e7fdaa2fb999ecf0142b3d5975856e54177ad9c9b042208ff0fb9075cc24374d5b732444ecf8e96b3505d8f6301a4237a08f260819d0ac4afdbb97e873d5f42b4e5284dd71758a642792722592d63634c663cbc23c9688cdc37a13a26af9500cc24627dc06c7959a13fd847fdcdb3890d967399061224ea19a3203304b52d16ba0ae932c30183a089ef350fda86733f958b24f3bb4b847126006b70cf1dfd000a0ef743d3bdec348b5d6f92646511b62b0e5068b8739f7d01b278d080b7b421b064e84343f1e67ae23a2c0fd179271740cebde4464ed0f420d664e99c984dcc47f89f1d55e74fc44746da0ec77703ad06dfc08016a92bc7f228892ff87152731fad85200b2bea75cd3d1f5b1dd420bda641c2f305e0dc0be25b1013d2c9e328f9e0b08064dec0215410c6b52db1553a5ad99c330f41ddb2a3e9d09e533ce1c90da1422c636da61c8e77abc7905f51c77cb5101745a052f6a97b7fb5913346ab7245eae4f3242fed9d61735bc26f5318e7b04dab2640c56af74ccbefdc4c2240580a6a959b25e8b1d74a770e6d1ee0ec941efe0d595c3fd26cb61e55dfde2ab9d86ef190e36b5e7dc7476c22a4d0c342891ffe74678cf1b8f3dd808d1acc42a54e76ccc2233a54b2cbd0b6636621dad79360058fe92f593324442301cbd062a46b036769af911e44371f7d8cf8e168d14021699c7fcb68153c18267a0b144cebd5ac0db96281897dd262e0e4d9d40f891d1fcabf1da1a5ece7b9070c224681b3b99c539ca2aca60d1f55ba8d8d2d1528c83a64bed8a592bd51f6b76391367324686b4eddea1661d070f9546cd69d1af8ee764b5fdd58dc5c4dce097d440b70b0b02f6b5591bfc138785b914ab8cc8235229fba7ac292e27db40b03f9c249ea2d5ecf3201d09364b4b6f55549c93dab4edbcf509fd5a9ad4e1592e9972b3448ea88a6945336559566220bb11828a785e982e80b8a61946c39acb91a9d6454dc37925ebb047e53ffe354b34ba6220b3df753b81fa0af558b3587915d993848b0256cf0a90f64e614a8088122fb59497a39002f463da93dcbb769b4b0720df287d7db3e22f2910b3bb29359e62b8df7f93827a6532833bc5e5c859b403df66531422028976299aa4b71a797dd8edb31bcc599a8e369ff530f4ac7769e24d7e452147cd55835f52155d8fd4fb75620baa3e04a3a049011141fa9e75af926ecca48d6913a152a309926f6a3a06c4778a849c9afddb9223f446ffa161718bf0237126a0ba4be80dac1c93b1a25f1c7b88e99517924457e04aa7c0a59386ab53a13f63e1feacb6edcd41e2b22d54b39dd3f584f57e33bb7ba7bc42aaf0017dbc0567315c86ac28ffe6e798c91b0c6bd8ee9820884432d927dfc2acd87ba20c39322aaff8b11aef8054e4b9eb89d5078a0da13e52c271d31b10d077e3c5ae0a2845754d654b4c8ed6f0168649972f119be129e36d22008319d36b8b081c80a3941dfe08cc876a40bb29f2658006ca1bc70734e04db3aedbdfa3b86a12e4bba870e9a3dc4ae8b7caadebb69b442f8e183e9c19fd35b5bd04e77d8a1a0d8a38b3a20ec2162fd530a8811b15abfbe8363d24bbaa31359c5e251d261a0bf0714cfa3c6039f9aa33059506f11d60b7420e3aa0faa5db2bed6ae00bc17934e95e0d2ae08fe2fddb990bc9d2bd687f558027ac5898e74fc2afb2c204ad1b01345d74fa2a7d0a84343b5bc8555668fea312ed57b8cd3f376e06cbb372df601836bd7c2636d2435432390c5b308ee17613fb5784518025506711449e7c69c72c7e2b46ddf2b35505492d4c007f1ebc0730313ddf08da9e5a18bfa936046530f5a701a16ed068a52c4a6ab23695c5b9a1a2f5118515bfa45c7a93c1646695d4970ed04fb0999f1cda7d7d923790c0e2a0702a8f87d39a5eda9eba61a4dce03aacf8f9b16c1eea53a58bcb9c8a6da0d1b0506d938999badc73f04f6104bc8a70e29cb7811d125608b8f867ed264730ac1ffa4a5798075088092348a08ee948ae1a84b68aa66700f7e4be528dad6b5d912dbc2ca33411b23ef921901e640c75fa12ac4093be2fe4acc254736fa7dbbee92ac9244a01e258f127c8a61d92e2abe4032bf9e292ca76b0f0cb854aa52045b756f442253c03547fc9b2908fe205c344b3009a7495777d365544751fd753c6e7967e16bb4e77fbebb22e403a709d6a348f46a7c2227793a15ea648a3f1b15e1623af0911d8d9f093d3694db00e1cd4a573df5933e27d22f9bb450be8dfe5ae209448eea4186b4b15e91e4dca8d5f25c01a991f086bf2c7c393e3283895445487bccb51b42f83a4c65dcc3a01e50258e3084506faf29b75ac5370ce1c7ed114cff5f69f705961d671c1516261931c6c8afd804b594d242ab1ace0d260582926ad954e45ecb9299fdce92b3df8d40f85cc8c46e2dc0a0a7a29324615075cc01e1d479d60721ec50f217f46e62e15066cba26fcccae93209b5328557a3b8de006dbe7f7f75b530437d86f7ca7c46a247879972b624448698931211c6354117c82cc29251c828017e803382955229243f0a6b5659bca27fdee10a9314e96aaa29efd945ca220d7801e245baf26b234b08b90eebfe66db1378cca05f1221564273f03262375499a9107566bb7f3970d2f2a295067910b8168fb0bb6bd382ee92ffed8065a0d25ba4a6218be9b0a1e362fbea3390c9bb301d66dda3ca33bc0f585e3f6ae1ea09c69378774e0cf4625448a2c08805ff13b2543da75237133d28d0dd53d8a15582bae7542a8c2b7717801bbec88fda388521ad87a61f5ccc8e8fd550865eaa0323c5eaeeb63ee7950e70bd541f97b6dd3f7bbf64e33da629bbf9a4fbe0a32fa5048d12ae9336b3a5a7c302e72408c80eed5d26984ab1dbcc5f90f4e474d2e1f284b9302cdcb377ddb1037497e617bcaba838d9ca96e2970286a2a0f67f58e36f638e03c21fb8f93769cd5cad40d7fd41e2b2ecd64f2a3044f74ae41e3ca0f2cbcb2396f64b1c7dc5e76e2e60b9f8e8d891a2f2b1ceb54b83218989d695effb604cb46a85f1e74125fa3f909fb3e428708c508f60a7f6259391dcfba1cb84bf04cf93c4021402df6e9679194476a6206e0c3e115728fba5ff681ba79e7078113b27313802367b01dd40a69fb334e0898183369c110a38ce50610619646d8a66a51936fa09a3b21115ba041214dff0dc7831940e4aa80f0cd71b6fe2703d75d72d314471661d5de5425039d72c194fc6f847824a031616b4464eec74a624526dbb48439e07e68356c4137fe66414f2c767f6a7824bddb5860e0f6299271b35d5d8ad5f005f3d4fa18919fac4b2adb5e682de0365268345304b2b35eded08c8f31643dca6028b200a5290a2bbede788caaae4c8d84e94d6e81ae23263614188b503c3fc6b1d795b332c14b7c63c218c7dd174b35d6ca3abab323b6e69f7c7d0449d0e554ba00b515b8b8f1c557a3f1721b814ea5e2523f7afdf0b31b6d882bf049d6196d3045ba66255f427a79a3c64546df59854b1fe87d88a8481752b70f847db5da9e125c31a2acfe584d5df41e2b3db2cc9e88a8e4dc1b741eccb872d502e6f238ddd3c19da158628e3a92a222bd66e948259408a4f0b548f87c05393b6b6ddf75b7c82e07838862425c52daa026fe5656cc13cfa7f7c5922df6c9e896d3a4c15e9fed1ecbe39e5b3c607f19dc8eb5170bfaa3ed63714b894a39f372660881f1a195e1b3c8e47e8e41b1d4072429313aa0c8d0900539fe830018161e66cdc79eb74eb6d740a52ab230f71cc0fe1a80be1ac6d27de6e214a2554cb5900efd9fc7b2e576801b0df2c32e014d9307940b551cd988f3fb348e309a70d504e4d49d568347bac6e20e15caad55d037b067c8b5e029d587de825ccd8dce8b96ee9e8d82c7a1dc77ba277a75d93c3c551da74dbac62110d3c151d873bdd926299e56a6b5c06622f2390143e2eb28496227f796551edae14e45b7d07755c7f6ae0f9fa735646ead498d424a46bc89c16814f765a3327ccd2416266aea9a305f9d8c9292a8fd26c9e23a6214a373eb82549a4de269e5fdf0fea2b4cc9bd884b57e68c3d655893fe36b5a57125906145ab940428859e1d275acc38ad2982ebbc93ad7ca571473aff5295bb063cf90f120551423dda82a84a2dc0eb0f10f45b1b58754d53769685f14e538a3e8bc50ae8f92f92e4a2c24f485ad5c7250b9a1cd856dbf57c72ccc4ff145d9cb69f8b5a46c4c7549d0b509f69b847a7d6002f1db9985025d13b26d6340550da09c8bf3e9086eb5b87092e9047923f6b0b44b2b3e24a61f81f1ad3084c3d2bf6658bac443c09c37e31102227ed2bb35a14175818ba73fe90886d21efd49d7cbce2e9dc3ad460abe63c3b6863fa1c0f8ac231c65c6b916e886505490bc39cf33836f3c4f6d9120c93c8da2cb30c3c704acb4106f7d14d306a585d449ec32340c6277dbe5f04d08d0032e073568725e210690963b114c7c5f846157d0a4b3e7f7afc6769f34c1cab04bac40b98a941b9cfe8ede51e7712f06026ea38758196a702107cad2d58fb2c5218f7e7bac0cc16807ac817ca1bfaa86845c12656e2899ca9726fee4efde3a3f875a5947943497da40316465046afa8318430e06500c4f6cf830b46b858521324d133d931e29325c4d132f0f8a618774affb9f752986b155ed2296c999869119b73516eabe1a3b91396ef89d50810e3a27c27b9566833e1717ec08ee8c745812c5ed4f42d519c563a9a8f152a00c9581b788ca3897a8048831628255fab1ae079e9525b594d2ad5f3edefeec8fe8a6684751d7e8244d007ec4d9bb69bb48c2b09a19b2ca28cb15524f57598427f83f8147bf547d871a8f3590f8f9bce7e76708729dfad14e03344fccb0ceb694bda3e010ff86a7a5d01f6637944444452ecd9e7029702fd97141cc4af01c648236987f72a3f29bdee8172b0ab8cba548b104aa3f7dde2253df8e0b8e0293300b8cd0f2c0710a0f99e9172f9f6f0065ad8a8c83633bdfc0f0cebe9e4c8a45778a719624131ee3a6994f71f6fa0ee8a0c7671af1c89773a859d008f5bf1c0a19ea30f55351101e60575fb1c3c9a60756f1a7582bbe3fb82a27b0805add050d2e6056978e72ff0a396f20b253f8558aadb0561bac25118de01e09e96ddf68d05b8fbb884ad24e42070da39539e44225209112096d395bd3bc9cba647f30910c2e3150065adbcebb97164dc219fc23e099e4944134e029477469c29d32e85fa2c523fe5d32f9afbffb0c16c13bfe845e8314c94fd5a76a1f7d9985d09774051f2945fb1f47b5848c26a2f416841ad79bdd821166b8ee63a106859741f60b162fdd12722ffcdd7e089ec182fff838d7d6132b7baee8255c847ee79822c7a43b7bc0cd5edde3dd7ae0263a327416162d448712743618f8ebf0b034cd59b213e71d26d01b2fbd5901d3bff513e09b9d003a9f00b180d9086f043ab79d419d5e9eeea753dca1c4640c5112ca7e955c4c3ce0cc9096a9b1c41893922d60e826fd4aac3ba5a7b49b212a8186914136f98e4c0d3fdfad389745d884c4e0d8452a509f2a39254c683da7718a4b31972283fe22571f8c0b7d857b43f050b7da0d96d72658c2245769d48272b4e3b05d199f67bda37daea8d1af79f1e8d27617db01836b6441c28168342ace009a7b2c190219523b15e1b951d6bdc930a8726605a8528793e36ba6ec3b04ac9c068a37b3cea9e465137bbd1c7ff23b07ff92832a64b37ebd6c4ebc87595f3acb9d21ffdee8ac5ec83d4befc042de62cf37d3e9e1215dbefb95bff57175007b4566ebccf0d4b3011fa4578f0ace77143611c857721a84f6e1ac6697c8c97a2162ab142f4478d7c4988e1f24bedf8e4ba4e62c68d7f6814f96768642ffd9aa5465bfcfd890c48d3cdde8dc9ba215fed86e52adf9fd540fc5aa624e998b8f67a09fd8e77247b26c84bc2e31bb613201c13c0b2de9ef55bdce787ad1a42335b08ccc4bef58935ec6d978bde83395014a2b0359225ea3cbe1e7f325e53519d76474c181d2e505c64c8293d38c105c2d08660462c7ba9f4d518188b9ee105d5a602ab68eda64354022d264b8dadd649927c676703309013bc58056282951c700eb3da1f73de6fea824cae9100fe2a059f2d3c912f0a31f8f3068c372bc9b2fe94c1f05cc6bf834769af7622f0dfb8543d3e0b01da2a7393ede3eab65f5dcb1c2d7b5e4de0eb4735869f7029485d8c7c93fe78ba16f080c40e48f81f781c043609ff4448cac8260df5bebec17a5de992570de7d2bb14fbcf07e8bcd4e48bdc66f03cbf8138ec314b04ebe069d950d34154418347b3706bd45f642d290f02aa430635c8e3b91c8e3c200e4a38536d6d6236446b7f51346f27df28ecbb2937e647482f91e07db04fa3735797413e97b732b4e3d69ece834be42a681922ed406c5f67b5950e2e40b3237b09a827b6af0d4ce51dbbaa4671b3d586ab0f1f4635dd4bbb0bd61966d1bdb9eb25e36a9413f7df3990047c81b3736e049cde12e79dcdc9dacc14b38ef6832a2f8cf9a82b3b66b9f9800fcc95fd3b5e047a09979c76a0cb691dfe9c4dd4bb0cc0f6846bf54f9b666252874bce69fcb99ad7d7a1b8018e18757f91b5be7d50986bbf452b938e119a4189b665c1ecc759afe06e46846550b07add9440e698357188857796734a15838c7430123193ac2374707c3b1b7b61992022c333a4de4b3ca0182195a48da7d57a08a4e6f1524a015723c34b8f07ed21c7e18a547d230083fdcffb0d09a054fe441d475331f1d9e068070db0cd5c6b54b20d81c823bb33ce19477b2d19650f30a1782770ff33c5cd448265da07e0a8c8a007bd5a4f2a227188d382ff1b467346d780634cf0c3087ad0c9f5b14627e044071a41c71aa150d82586fd7e62caf30da62058c1dcff576096f890023a3c7d4716b3eddc368f941b30d6c2fed0719f452e3a09a5134ed0c087f6c4222ebddd115ce668847f107c4d42b1b0e3b22ff60bb86e1d3bd3d13b07771b8d3f7a33dc5459dfd4d77293a66ac3a1248e4a87a19872816b36ecc7a5a6e63630b43f2fc1dab3cffa2ea858de67985214f213644b40728007666851882145803ed21defb3126c5c0de5492deccd2b34be44f1a3a0d0fd04f67c6435bb41d33e8622f4439a088331c91bcc456886cf5d1a544b7bfca7cca52927d43c0f72599e41bcccaf7702bdff63102f6085ca12571e658e51b57cc078df03c67fdf03ec67c5609baf4bc7ce5a27542620bfc650d4d9492bc5b485d533d87f70a9dd174127c94f4eedb1ddb3df7ed5ac5cf6f528ebbddda04102628c7d6004163befd5f9211063c5c1813af98549f8cb475ac18e32aa62417862d385735af4bd843f435ee739317e5c0adffad88e5fa787418dd33ca4b545e75b75cfceb30bf11545381504ef651150e606e00ec210fe0227b45fc4669aee42f51f5a011c28602c5208adc5109587bda4966b19b97d64f91a76b08a366b8d357d9bb44a115862ea810ce4bf5282230842fde044d1879550b8ac0cfb5dca4627947b6d2c0415a56d01d6534834ff923fb7a04d949d358d463a5f0cec78c9f44ad870e92293a707619bc43176e4448facbc47a65b54d4c7eceb97319e0574ffcfc79ff811a41db9669bf2d63b2627bd5cdae254ec317409f9773382c3706725bb2a489daac5cf10a00180a661ebc02dd337f85a9810316c0075c173d0d50bf81b6c3d5ff0a1159077c5a56a50a2c1ec88581c1cb7d3b5591fd6ccb4f5455480bc59dd58a5d3e1df557a910934775307b6f9f0c785b062f774659470dd1ce2d059b87337d26d4a78811193b974296ed8b031f05e3a819fd8d0f7836b84a02f1986d2805f918e56a9119df0b6cc0b0c75c1322beee6d0ceb5a15115f080c29ddbbf027b49702d7b35a2971f87d75b4cac10ddb8da0687b5ea9bd68326c30f901264453ce8bd241c7dbf4f8967fd25f58b9d94037e67b5d09bbe6b64367b99d9ce7298d1e532f03b4301f89ba095c452439b24aa8baf0dcfd3478c6a2d30b6cbb3ce6db65db5fc487fb1d47e951db5617506e092abf06734d244f4266a52472adc07f0de2e58581493cfd5f5854c33ffccfda601a1a9ce10b3d8605e0303fb4448715820eeb24d999f2ceb82dbbf5bf0c57be6f2a00f20597e38f715b7762126b630d4a747b2b55d778d6b34e956d4e9dca1252bc3e5cdb17635c67381b7329ee1c22e2f98599a86531f2d0339ddac19cdd024eb63a4c37a5fe403099245bf3473f4167430b4163943f4b93bef6082e4f2a1906b06e778f383a7d4da702b1c1871db52d3e6c389decc373963a53153dd4bdbae5c4bf2f5e87883669840662d10134477ec1ae32c9a45d00cf7c34bd2c258016a1d4b8c647e0024cc4ec018e115d975f95da706149f7ad3d4549fc0f5c275fc9e7afe6ff39bac0489693a1bd4a57ba7e566d557f8496cc895b4efe234261fe1f519a5c8904543f4db6657b6af538295ba6bf761d600dc409fcbfc12f2f7ed5e83ce21a15512228068fb8454539fc10d80956049649b4a4a34ebe39f15c49200556640798bb1725cc355c61a4e19b47880e4080eac53658046b457278c2a50fc844118ec355c3794cb9134ae19aa2846168847707bbc8049f23ec269d79389d62c19356d93790c090e873090d145350b3725f30474298b8e13df8cce75fe736fdd9ff597e525083d5f10e89ff03fc7b0500abfb8ec40e717972385081b869d1f6503f23883c4e4e81b799648349dbb5936093c8e91970269fbef7c25a06a4c65992cc62f0b6f6b37539dfa193d41f069f55d24b959a8171032f11d4e80c524c171f72baf8428116075e8b0ecfdf19941f4968e339a73c51e6bdb5d8a1769753e04fb990bdea69bac48f99dd06b86413b811c89bd9fae304f57bb2524819e38911f20706ebe9609bb5db4903547edda05802816b72adf97052991fd02ee8a52c2af5833bdc90635bf6cbc473016461bcfbd8d23c5ea91f7c845094d2caed964dd81fa84c0365bf45cd1a4fb310d2baf92d7de3fb6ad67b3d0ac76841fc2657e75c2220520672c7fdd7b07c283cd8c6b4ce4efff751ffb616749a5c572bd77b956e0cfc37f38d3ffb8bbe3b845981af0431b5d62aa84f2b156d01912f465c538624fc401d7dea24f4d82538b8f17b6cce1642d8c9a409f81b526080035e0cc5a9a0e633f5610620f30183d80e9bcff9119e003a6954340dffede51cd032d5ee06769832fc4493af0e97d4361b1ff60fe962701d57e3495ed0e57ba453e3a08b2623c7bac66832cf0ad8ce9a56e359b547ca35d74098ac89541219aa447d368b3136a572cb7bb1a425a3d0e245b5319be360cf88bba0db18249f8be1c1e8cb62a523dfb8c49b5e6f883af47b0d72f540d61cfcd8ccc96667ae1f91c474cef8236a389a9d100d48ccc95ee0b823645f0c5c2456a98b34e351da828f7dc51d535695f4c5a8f201ff3c7796e968257806b2307d35c1b0235ca8c52c55ba3de6b0ba58668fef800999484f7516c7e1c41c69644e3acb772445510e96f9a21ad8d593179c5d3cbbb3c779ca5552c29ab3aa510a9fa295135e880749a391ca36c8d9875031f76db684ccb21601ffbeb8fc4b64d94681f912a09d0080ae50c3a8a08cdc99ceda4d5f5ff431a203fb80c3a0742da698bd663a4b9f757622d3eb6d0b66e3487fc0cb3479f12d1932cc62c7c2ed9cac3339cf1e56152b07513241d7207f8562c7d7ae33758f3185cf870b62232c763a93ec7e14d2e8314a611d947c04df369932ccc4869fb341d452dcd1f618e75b4b5251875ac9a70b19b7e31b6459eee263f81651d9c782cee8215268190da4e59b970d89c56205188266e37f099f9b6d427b78cab992c1d50f78c3eaef8566fca228e6c16a7fbbdce2b8e3c12449153b49db843ae5ea8bd45ff5e4eb876f492a0e15f6a0787b49f170c4717cb92988e42bece588e4ac24485f63e0b3e67acab7b7a1bc5ceb863d3267d05d0606430b280179c580ef468cd002d54c08d189a6c3e74019a299b7b30f81df90fc132fe5051bf1cc1704769dd980d4739e0d09243ee576771d7c90b10fbb26d004076a6d80535e90bc7ba484a7564c08acbf0eaabe6b9d85441f8146c0ee927116c33417f03f480c68d9cb500764ed62a1078d44109b59cc43596e1224a3bfe105223214a381a810c6c7bf5ebeb1b8d1ef008dd71dddc84f416a539d3f0f56c26c91598e3ed1d00d47db09cf0dd9ca4f1d2767864b4e72956d357e485cd0a6ea6923d928adad258cb8fca79c4e63415c6942ac2721a6de4811f7eb6c45990820ff7b9a3f4b1d0118f5d30ea73545ad2c7f8e97cd93fcd8e8572ce9c65371472b2d85ed9eb930b59eae0dd5d6ded3daf8909c759b73714bdddec987dcb9a181c354449503c165a8605db25c519a6a07b19c4f4be80fccc9b96fd00b1442d5493b925725d0e406380f5a61f47a4cc33bf77081a8536d635f6ed380827c292b9ef20fb2e486473709eb975f11522920759692bd42b35cd17a08278c076cf5646664de9a01650d225bdd8ac1a44103b40fe1ee82f5ad01c14919694ab60320512ad2a909995282e18486b031539f50e6081655e634be7e5506351396351448389cc8e8b32dec3dd40c8a6f67d2a710fa9b24bbe6e211790a6ffb60e8c41aa1fb8404e520af1d7f40bc2e0e374c6c98d959c1458357f3ff8d4fb7fcc1cf5cbb4bb0299706d1b3205320a1c2a283207b8776a11b900c16535375bc6e28cddb475f89afd25dd3c159ccfce8593b6fdb3989f5615f60a3054d8cbf863fbba8307ca1aabb7f469baff061141a6be60798c764be691b076d33dd6e3f6e2bb26d5373d4be3196f4bf12cb4104edfdd5b7e166c599c30b56c2322fbbb66c21e9161d143353aae68654d5605f87ba886d1ad7d39e9c48564cc98f4fe86854f81bbb232b996a332048e1fa3b6e6aafb4b740396ca46bfa38f675d6cda008b1d9e23f50031ecdf8e9d427887f8e419798931beb3df7a771963a5511c52f6f439e91048cb9345cc3a47cde3959aa837f98f022f78eaa726d1089b8026fcf2e42b267be6246af8d721fb986618693a15fcd0d4270a91b738f8e540f22221d622778bf20a99184cf6ddf264702c19d46fea7ad6225a18ff6c169344046ef932b062459fa9419a70af58ad979565759a6fe59dc63864ddc5d811b9e93b18c2c7f8549dfc0ba8c18a0ffc093386b8589743c223416473cbb3be5d16b90c8a9f170d1848df34b650747e5802227089052a02e11dbee52bcf723999e1ddc2a4ed7762d42321de8e067d3055e836877e1e8b768b58be8d0f1f6113f5fe434c4f12d39989f37b456a1f71fda15e6f6768b128c8ef4e6d548ccdaba6733ff6f97ad3b4677abd77684a0377c6fce86de6f08289dbd8475768ec2ec0e9ff5782f03ee945ae40f71e4f1ff03838f980cc6ea091e13a7905c269e8bdd7341725ad0ad9cdffa57564f235e391610b6f4c0b85cd3042ae39f17a6ddb2c34991461c56f98900db119e474710ddd7e1bd4cd7f4bf51503849f939c203d5c4926a8a49a9b27db98ff0af7cfc08251470c8e1cfca16490ef644cfcf3ac63bb3ba27ebeb2e9adfb48b24b3bcd0846f302762ef3212f33f59afe1dabae57a3925317237fe34b501526e451d5b8838cebd1b98b9919cacf9782288a1c3c9ed9c015237244bc855e9b9acf9d8dc9dcab85aed56dd71d3e15be15f12f3ebfb3878638a75e422411834fa08ca6a66e6aec30bccd0bf8e13bfa25303134b16cdc0c04ad579f8d7420728131efb0ac977aee8a4e8a2a79d68281f7d38dc4d13a37a8e1f60ca03b68cf98bcfa6d2e693b349ee2e735385cc0f57e9c0ed023aa8bdd9b4fc12671dfcb50484e8abef81f8f16d1a8c8b5c22ae6e3de1f84e4fca2299995a8d4df7b1d584745d7c48b6a8e153be6c533add27a3231e30fd33e3e6b9c0d52e07320a3085fd89c1f63c031014fc5394e83a08f3bc708f917d780b2ce929f8863a88d1f3f31118ea734bcb166944b7a5541dda35e256fca538b3869d6812819bd8001c3e7e01b0b79181b3d2afd45ecb6707921a0187e407574b7cf6e4ba8875bfc4d5a70b113b7a2143c3fb1afca6c92a5c8e522fbf389f0d0b4aff2c8c0536ee8481a59dc981e78706a2cd1e0831ab5ea239c109fe1f33800d13819e18d6650b494f503831f2b5c6157cc8d5546199b3e6ce12c31771928b550245f4da6f021e905273a3b5ddda9989ba9ce6cd4a45dc904e2965ee6c153412ec0a8923ecc66c320cd9b545af167ed88970e644222a2b13e185c9d4b3ee8cb1fd7430576ab1e1b85c6bee88fb2383d26e0d98d9a7e11faf90593594553d6e3189c6c2bc2d914f83dfa78254425542c421d622fcbae093f537d92c988a95098d41a99eddb7a1d32c987e208dfe7b00b43a400ab217e25ae8045776e34b7dbce26b514ecaf8f257680ae2198e20c72850ad6c28465204fcb80e257ff57beae6f33634afebb99b17fee3f062c240fe35bdbaca5a69bcf6e2465291becb26f0c14184df1ac6e5a26f8a2933b080eb4ea55b6043c820289803d0d304419944ed030afb369c5920ccc29a0e7ffb4b1139f89f88ec9015ac404149f11fcdc0f3a9f715ffaa9b8ef6436d01283ab8013b9f0ebe3e786f60f8c522375dc0782bf7bbf858388392bfc74db7a4f0cc8e75df010a55711f21d1dade7bcbbda59449caef099e098a09b4030e4c0dba0318f4b86fc7204d98a8a334b88b27e7fcf482cc0e4ca1cebbd187d6f05dd218847ccf351ec63eb6f6b1f9f868d094a9631ea45cbdc2a60f99ba6ac6e143a65ee6eaa9403fc8fca1ca966ad68ab38015db26d7e4e9f5e74d56040b2e93bf9f37190c209a376d7cc8556fa8b09d13e73750d8ded46240c00b543ede3cb57218b67ac828f22550b794bb9fb63744bc17328d9f36376a389a1b3452307982f3116c6c68bf4879aa36b438a4a21b281b420196f4751ea447757c85508f1eec1e2d589bcea34bad0b203841db6d6951e5c4920bcbdb5dd7757325572d8ffbd54b6cc5d2fbda5388e58cff66538e72524010b6a6290eab2ae378c96dc0e943bbf62c6a8ed39991814f47036d3f0f7cd692364893765695ada760adb5d6ca39b6ad300ca997214e5f8e56967f477076d13167fee868e0ab5358ce06bed209bbdc07bc492bb5b76fade40fb93a668dd124d2ab607bc8b4d6a69535eb9480211fa1e6a7cd4d106038a0210e9abc610989c9e64676c3d41413028430d9da4031210089ca471b1b277a0eb1ad8d12ef082826ebfcb4b5a1e16b927b7edad88461858d14900f3651d84e3a8d7c4fccc588b73f6d6c66f8d255cb015b8c2d959a27784a7d2af5a118727e9a0026c89a25585fce34dc12ed6d6c5a784a9d3cc55ef0a4d336abb4bce7b68306f056f676fc6e0d920e7332d03efcdbfadbf3b7f4c148fe7a2643eaafbb94fc752fa38bbf3eb178320054318babedcbd6d73a46ed6bd50b63b86c548c0795fa238f7665d06cb17d0b8531a52521b3ad1d31b46cd1f196030fc2b0f2f689b76994dea6694a93464d1362d02086156fbd67c5c33e65c17911411146121855bedd463e6a920317525096988c589961986c01c3182688a8e185d8ed0825e0e4a1de6330a27ca3f9f2edae158fce4aa4c135ecc4724547105513aa32689cde9e41f3d677563c2cd995cc770fdf13aabbbb69e02b0515938a2acca4c04c1829c0724687b73ecde0f0d65b2b1e96ac5f0c91c30c9a5b33a8135f86ad76fcc59b6fcf65b07c91c4b7ebac78b45f11e389165964b092056725cb96334852b0c316313b395b11523890e5928c512703854c18df9e6382312978ebd67ac64eb4702693c986e0d8b2e782d98107f38a0562b24cb93085c50bd21499314cc68811d3f4d6592b1eb64609c4ccdeba5dad78586c8414182ac539d65ec30b32be5a314874e1b236b76894174abedd6b77f5936fffa0ad10a5c9643222b1f6136e2b1ef5cb568f8f01bed431afbcc5e203f0d6711ef2d6ba2fbd75b28b29de3a500dd306262acc0e6f6d6150f0d63b2a3b801c174e7cbf517261092d573871a22156e6b77506293e80d800362e7a00f3ed35efb8c965a883dedebea54294d0f2611a5b44f10903de72053be7f82a613a763c1a8d60f600ee5806f9b27d051ef782d7762000998e9d84e97805fb1ea04f9da49e5d4d06ac3e7de8ca01ed75ce497dc6daa7ef9852e4a345b2c2a66fa05434ddc774a02128236c5e4d389f31ec835267c188ae4828f1bb44921c1287ba2d206eaafdc0df0e44fd46c5a697f969fb6943c192072910100a967e9ef969cb82c983363ca10af9a830ea18d3fa260461e1040cac40a85f347fa8ef4033ab42139830ea6398d0d0c8784a29a54d27cc1f4a9dce28d35293b32682b00084f38e930ac202f5133030c28cddd188c62875a9202c9c8001eca56ac0467d0a0540aa7d09362ac68d4634f62a811b41e7dcf86a52c50220d57eae8070def5c4d93991f40adb31c5891b4054698a4d2abe42a04d5e40dc8e23f0a377c01d5f408c6c54ccfa516c4abb09d7ed68f4f2185961b6dd84a10aebeef6221ff50a70fa800250d30dfafc7c66db00af1246f0ba4e634674c626ce952a226a8c40e28490d83ce2c1882190a2c02287375562d3295d89784e994ea98b06b63061d387fcf4223f8fcc2a34674cf367beaee3d7f5797b36bd99a67773b3919a68d974ffd07fb82a6c86e26b041ac33ba6642f6a5a2bc7711cc79529b440914e55d8f44fa45415369dce3c912655580aad150935864758552e5b06820d624809ac3cd7897f53687d259bf46972c6fc89ec3f9b4e99a653194d22c1c6a8acc26ca0b22a6892b400c40c653029e36b0853c585162da4886ada4a4a1732493fcbf8d965cc0c25d82a62af12ae57afe30838bfe3ab89f5195b01b9ce8d46afeca2362a3663affe41dd04273750fa41dd04ea453e80c41d53f20fea26502ff2e13293ab0eeef9bdedd44f4deb262826496d1dd4454c0ac58cb2438b132aa7a9258e28812186202d84ccc8281903cd2c877a636fcfdbed8a474b7962d3443ab6d3fc41937d727152a6cc1151415491431762da1cb181091cbe0c0115e52283fd5e7f62339a5061d729926ebaa49d7494bf48bae99276d2519a664c3b4de49d1d32155590da18e74c674da5a672cce415f0bfda8fbec71e69ec3afd32df42456db014a40a512e1376dd8a317fefbd146afedc59bf89a24b155074a1854decf6586209544d4d981faccc98a4907ede7edab450c288c630b043432e291447a3b0f320efc540855ddf39229714ea557d7e57e713329b164d7f6d5a3885321b172c487f6b779380fd8563af1f9e7ba3118de50d947009cc341559b3c6898b270ac870860c97304eb520305085f028b351b157092378b96218ef98e23a4a42cc932fcc243931839879051432a020328312b42f5624812aecfa8e29a405c090d1a1062eca04f14206a4b8b2660b106eb08cb9de891ed41168b9c28b530b5b940123769d4e55a10b2081c35412a726c86013bb4ea1aed3a8eb265cbf6067bbae76d57e3982ca5a6b81582d45e2072d72423b332acaa68326940dc9426571f313ca56e6465125ca9734cd771ceda64d1b165afe3a5dbade4b2e9d3dfa20b9d47a94ec0891a91117905a782cb035b9a783286d89e06a92d28795917bdaada5e0b4755656b533dabb4b9fef3105f24370d6f1fef4a15c378dd642369c5a8b1569eaec8a215fb693d5153d7cd94f56b0f9b2afacbe6cdb2cdb4b5b0ad690ce0e3c405e276f1d36832e1093b47e671566b91a6ab1e99dd84db35a2fd6d25a9aa4750a579ab45a92c84db38dad858aa50bc796adb75fa6be4f79bc4f55c8424d226ab34286b747319bbf022fb2f5a2be6dc919387b6ba57269a55e69a595565a69a595565a6975ab855ccad42fa55e69a595565a69a595565a69f58ed24a2b6d06f40a07700ae54ee2645f8117b93da90a35adad8b09d35afc30f9caaadf79a994f3cedaaf54ad46fd2269a1d934eace28d49dd1a73ba34e4d43482da53ba34b570bb994dbed0fa82a04649d4c4d49494545d96cb5a156aba7c7a7b4b496551895aab0f6a929aa1e6dd9b4a7499c8c13038b824b2dd6e2c441860f34aa588b946a0c07554011156bf1c524e6519e20a24d911809b292186eb1c748ac8a465489101c9c8891c06373b390614d9418663112d0d0218667ac8a46193c6d998a91c04b32b17013aba2514745c1a485180974c2c4f0ecb86bb175fc257d7be50b13c8622d7ab045ec8892a0bb8bd49e8ca4a7636c9cd27cdd690acbec407d5c7af8ea447cd9a3044d0f6dfe54bfa26da9f6d4546f40cd9fea1b5075778756855e691a56fdc5a609c949e9e9eb52edab23b17de5a1417d75fba26ab2f28839f387e32ebd33731bf8bef49b7dcfb0cd9f06a3020cc54d06a52c5fb2f7f326839030640303e9d3cae10c73191db6c2f0e74d29055ffad4aa28ed31cdf20029272a4e4db208c309342e484106111fd0d4f0a60c236a704fd42f5e130886016b191c55d840dcbe2b4074b9941652a4ef6e3a4ba28a6f77137c7b5114df7ec215df4e6561682011ab336abe582b5dae008b7073bb7946cd19ecf597a20f7c24a093784d383f6f4ab3c73f6f4a49989c445dfff486a21d746353510dac5b6f2926511d1b8cf9631d29770e4eda818e0c8c5ce9ad5d27b91bcb29055561d6738ba9c886aa426d73a67a97f5c6cac4db2aea30936d94266dd7d5da75e375ba4f38aa72799d5ac8761095b57e9deeb55da7fb842f188be7bdf7de3be7b5a30dc725f2f40040c973d4d1443b2b8c6c7b249728ad9aceb324bf9e3a493dbb7c641904544f1dbb7a6e4ab2a7e18b004e1f1c45e4e9e0ce955c9b44fd9c774e39f10584c315463bf105a4738fce55ce6cb2c7578fb9a549f72ae19b5ee25f61d52da250c7570844df4ef4ed28dcded2446645a2afe2dcc284e95b0c42f4d33ff1554238820f8baf12b8199b2b1340efc61790cef38e1b4df83ee7c617100e3b178eed5461d45def409f17eb620280a1d650d43b8a7ad7dad652b72d199eaca41de08495d6a4a8065626111d9b8bf9d3de4438b5c93cbd342c357fb6a022e27bccb7535cabb0663d0e37b9bcb41a6ec297869fe60fe7458d6bd8463ba8de8ecb9844504ca1fe62c2aa680775eca9f10302ca20031c385eaf19335a4a079a5cbdc44d4ecb4ddfdeca21e79f5b9c74f91277ad72decef425f9b88673ae71639555d8cf985ce237df493d3acc789d16e01cca9fd36e6badadd576df0f07193b52447571818b1921ded88022250725901051a2862f3b5772d95ffacb24ea7f0101c1f1052474d0c1d18885e347e30b08e82b5f8d462b07a9e388fd34cb25d0c415461d0794acc37154651d62ae30eaa0083341aeea3438c25035550b1540298818d5d30661fe4fe5fbafea56961cf9b902e17e019482f896fab2bf7c91e5fe52c4162e5c94b2343942060b381c0993030d424ca1c5a8030d51c7b1267b1502ea14c0a1a17e2ed34984bd558031babf0f8b5fb93a817aa8cabef66c204223c2649d9e7a8bca909aa4159c9e83989629b48aea87472a6b92264da82160867cf1af2906272f4364ff8d25d03711a92f2d139128bb24871779de862cf9d232292d3df5f996a983e62de9e9a95b241d44b34b5a68f230c9a5556a0310c92aac90dfea307fa8db2378e99394946ed8b2770582e75f5df1e038da752050bcfaa95cbd498c572090abeaa0adee7935002d7bdf58e676abd4413dd2a4a50ec2a3cba7059e2539741f59fe3e1ea41ead819af428b4770e7e636954f51fce5b1e1f726999aad0caa914c839967d478d5063abb1a32a2872582c5d65957aea9f98424df250f4608526670c526f999e3a759ad441b718a29e52cbd441f5732c7e58fc92be41ff7a889f7dce8baa1d833439cb70c6945c1ec98e5e074f0f795aa7b059618079a230c309740803056cbe300181335f348961e2a48b2ebe3863848c10244d4c64a4a727a2928af082456cfa340098a7d09cba21298a2ca40c518a21832a4c58c1c5ac4c952936b22c31051a318c5cd962819b35557811449a2732e601c03c8bc03ca7bbe6f439f1fc1b48a976dc2d960db96c91d513e0f2f1a3d54f4bd00ee6778d88eb9dbbf097ae0a8e650ae4473db716ea49a072d656d6e6385c811ff5f6dcfcd0973eded2eb2288e088162f9adeced7c0d0dbeb24c5648b985a0000055255d4ca43fb841647a0a5ace432dfdbd47a9fecc18b6bb95aa762e7dc01debc61f3d8cb233c7ae03ef5403f1d51b05e6f1f51abf5b45c3d3a38f0dbd372eda885b75cfa1f00e3307fc9dd5e7c147d4081da7d586bb313398aefb00553ca611ba9d0621cb20d2d8e809413b9ccd6f3fb1d2dfe9c86b3a97b8e02d7f5e0466cab1038b368b9cce50af53dfffc3ff7404f0bddb217e4d61329f53ea72b1edf58afed61c7b142014435d8616be50009b035459edf8222b76cd9628c318d1772254dd8e036062a561d08d7d96a5d9129934ca9ab8500798ce41e0f481fa010891b0c696e309479fa27f014c9a525eb0d02bc3836abe7d94e2877ed1dfdae1367ac1b5763b2ab0a85de6a2e746eb55a3908edab951fbd27862bb1ecc250fc1cf4a23efa6e85fe6ff46c9374d5d129ee9e40a431dc41378b2eba9a74b1a0b87868c8399e1dfbe79d6f364cfdbc2d95f902fcbc2d397997e77849821e3ab52b1e20cef812013b8e83801dc78fde134ba3f79c25aefce83d7185fed548b9a01a805e412faaa1689bfcc610fc7193dfe8238d92a953ceace6868033366badac21f2bc5ce77d843dec796e048e1e38aefc288647ccf2a398e7b30ab11c08e8acd168886ffc4620a0b39c351a81e351cc0bc559419086a018760b63aeeb3a0e7b1e65003931b6b8c72649ce894dc019febc5fac6c7e4965162997f9c3495455a05f65654df3ed354dad92512ba36e386861d16582214edd90cec9bf7ede64b75ffdbcc9a87801821c38c9d44bfa2f22ac8a02b069cf6943e7a777dcb5239d44768573c5096b9c6fafaf21eef3a759dff5415bab1a106c9b26fb3439451a0fd24b45f1c17959d5bb667b6bd33b2fcbbe42e8923a68ad9d1546af7bf68eb8c226753599265b5bc7b906042f11b0bbbb5e2f6abb33d65b1fc499f58e19a4e012c9d45d44ea1160ad5583202cc5f124e3789229b66a32755793d4aaa9b5d66aeb9c3f15066bb9ea9db5d6a78e41340082eb30c6def77918880e7bd85b92a92fa11db73a733def068238b4ab5df1e8b0e77d383838383820d8dd79ce89f3d5964c07c0943c6d48c76e1a34582c9c9c73727466b45a3468ececd4a8e1e25c2ed775b97466b45a04e1aad5e4eceeee6edad5ba5c5c721d694c4aa3eb462312b05a3834728dae5123d3c8d9d199c1c35379789a6787c7468d1a2e170f8f0d1baf574f8f8d232cb0c0e5e2e1b161e3f5eae9b971a3027751aca2288a3caf1b53b4312758e3e5ea693ac5320ca758ce3274e29e5508f6f1fcc93c5a20d01b2b117a2ab8114ed102718a2d529167883cdd330f71ec918ee3e458e5118eaf78547babdfee7e6f52145720d01f71b47c702e58f1e021f75831c00083c600038a010e1f9f0b2ec000030000802461301f9ff0020c2806175c70c1aa477ddc2406380058f198244952cb2a8fdeeac8a03320613932d0f113000d6030b771448e1b15e4c86181e7c89143b49123074f8e1c3910f0049c3e6537d563ceb9ea7342614067073e968a85157c024a28556295dc6b6f951f943851a244c90f4abc900b9076b597ebb0f781d97b8ae2643b88d29ca9439fe85393e410d608671582d599c119e1ac58a84262ada84ca6449398e8aa099d5127b46946ebae1084aa4523b4368526fde9538555e004fa54b9d14ff09d59e3031f50d3ca97f4a9898f264510306146d5982eaa0368a84b2ad2a7096b9ff469feb40f4fbf5a611cf6ac70136ff2603594c4655746ee19265f027d5d78c8210c1e96b00d3cb8e041c91e1b1d3288a66bca393f6f3b48755576884a92c19fb71db65c2b72f7f3b683137709679e1da6c8b003c6c9b543132334a26aec704391d6174d3b3b1099c145158d3274b8806a4d19c931f38587193033b21534642f643a5b9470c8d072aacc5864aa32122356535138487e500ac3d458488ec8008ea9ad9008b9e11b330bab62f0cad0c02f64c065aabe2a96ba2fa83c1da248e26878892297c798aa8e08cba38b280e08df74c081a9020d01713024a65661938d0e5e4c7571248c4c8a225349196797fb04c1d4420e37844866f8a0b2fd796b81880e2d94200d1bcf4cc63f6fb2344964ba3799fb799381c9f1f386a4830cdb4c3fd3263698db427de8c81a0f7a66021c17b63ca9820a9a11555ac43e31d4acd12266e9a685ca7220f29ddb0e2200eea6ac055f86f8cb11a44c935062662af3bcad8e99baf8ea9389962718247670e2c5912a605035fd5147af54a635294678ada724565d0e31be9db34864796b2d0dbaf6891b0e4ebedde205d850440f3330863c01e648072e45543de1c54c0b266254cb116f306daa42ae3a96f85d549e522b6463d4863718f99ee27683986f6fa32444603123c614267a8895407f5402284c9c481195248d1431eb449b2a8c42612d0740e4d2f5d4862a1b5ffb9ac210739cb7ac58027d99c2f7e4791e7ec2584a14294f2ad815ec6d9380f943adcb8531e71dc7715d11c7dd3b663cb1d892e8eecef3075b970b634a622c86b8c3d8e5c263d8e4ed2a57dd76d71f4d7626ad65e1337eef3bccd7aa30b71c3d1b10637a2fe62847db67938dc50df2d4a7c8f3445ec1da2d6c6da7d57a75b9aeb52bdcc775cec979d789a11583a3fc3def9bdefc3c07c1e779dff8dee8d7ef987b2fcf13fb1a81c66685e1eb9605f5d15e2194f46fcedff115c2ebfad101b0c8657ef1ad78002c72b64edf73ed909b73dc643ff7b9b5e1fd3e90e33eeea3d6fa5c71debd4e29a597f3aeabb6e370bd9e42ebef1820772fa594de79c5ae78cc2fa7014a4c2cec7db5fe24bb56ad17f54f215a5368bd4bd934e074ea2cccc98685eeb6b68ecd8325cf7176e5fc35028d814e82377ab649908566aab0aeaa304a65733611965c52aa3473a6d0c2d55961e4f6924e551a9e3af54a25f593ce3a2e67720f793afd79abe10bf8c5f54d864cf51c5bafe23ae6d872e7ab3ab2c64cd724eadcce4934bfdd7610eb4bb6dcb59575e7cf12997a6941e0f9cee7aaa8b995083c970148e09c44b98b5c7fde6ab8f2f4f5f356c30f4f6f46da3c9d44f4a7f28d9fb71a863c75d04edb3aac72856f4702169169fcbc19990a9b6e46aef8c2c8383f6f46a0f812e8399b9126b82319ffbc199992c5885308469a3a2336b860ab2a6c3ebe191162e44b54191c6660923ec8e2a98897d9075f6638bb3e29c21872eba7adcb097ca8613039fc69eb12054ceaf203909bccfdb475a1dd3519ffb47561eac2051408ded6a16300b64cb9cbd93b76d3f9a50169577bb9ee76d872433a3de9bd5c7fb5d1cd9a0745385f347f9432f6a2cc793769b3ee5874e924b245f6032957648b662d6872459368aec6507fb092187c00fe08e357f8ac3ffa1b08d6db6edb2da8a48e9f6a32755c0730459e60141014490cbe7ce9f070f90adffb79391a05ed7a391c2ee7e4ac42cf177b393a2c0f8360f819e5f0e4501d5bf18c165edd7beff57eb0d6c85aeb27f88c704ea256888d66a536ccad496367de11a8d67a2779af570faf4210c15bafb61bc91b827d9006a79382aef676d803c3152be7e8cc6871393a198705b6685cf05bb13e70b56285e02a041aa1fd39a708eef8941c08b9b5e08a87b53dfa819e64ea259038497bc103ec775d2520d6c01d74bd0fd049895a1d040484b1cf0e14bf495a67a9f089dc24ade35508f63f0f80dea4cdf2c63b7fac736f43f0d5297939ced2f20d24d5e39f4075a8d6fad28326bd61d469d862f53b6ab8af970dbef4f99b82bf6eef9d1df177a6c4df2234fc2577bc156ae9a00187afd5290ec0522e7d92f516c994eaed09a82b7938d7384245cfd731bed67a9be1881b0d31bc94255fbb7c75d5315febd7f925c6b14bc34a6e35e532db5a6bad53cf29a0b35e8680e9abdb9ea1459e5e5ada385e6ce87f3e055b4c64cfa9635c2f96efa6ac03fcbeeff3a20eaa53dfae03482a5faf07d04f77555c5723dc18e89ef83deebaaeeb3aaeefd48ebf23074dced022d7f9d362604bbb30c41dc518638c31c63e5b52e48e661d878e3d8c31c61893d83db143d2248e558b31c618638c31b621c61863c718638cb167b177d829c68e31c6187b517352185f7c1dfb2d3389e863171edf368fd53c2eaf99c71f0631873bdce10e77b8eb3a6adf7a8e3dec55d0ab18638cdbd2ae2bae5804ef55fde8abe747ef618c1d638cb1cf954e984cbda871a8c30eedbb16027d724e5403912bd3b08ef538d87061a61037ab30309388ce999aef9c93eaa0dcd4e63b8ee93b2f3933ef2d297247eb40e79c3a24524e524e524e52ddec85fde83b9ad821a1617550a4312cd2073ba62ac44d7533927477b9a46295841a03474e6ac6986c43742173b3ce3b9cbbd9779cd4fc996ab2f31639304eb4036e8ba941e75d17f3a7f33a969c11df2935d9cd9aec92e64fc74935d93927726048b831aeaac23a2f6a28b924af540795e1649844d6bb0be6bb3bf5ddf5fb54712ddb2e140876d851a0cc9feea9619d73454c0d3a9fe5517fb5b80a618c39ceb92823e7347f3aaf6048ae5f724edf757b1ffdabe3a4bef3ce39aaceb9aace39a9ceb9a9cea74f37a2b04303afbc2a1892bbe3bcc4f9673786b38c43da5b07977830bd0d95265152380b973a68f244c9ed208da95c825358defa16aa29de7a0956bd05b378eb65287bf0cafcb1427275100467f3c7963d5c5215ba9cac0a716e5df44255a13b5561d6f385d2f2654f395585423a96b88e535c8c1bc3a40ab351d93a277bebe0ac83acdb57ed2a81d30714c9e490c729f7bd4e238020061b5718b5549a9cd6e23c35393d478c4cb3b5384d15268034158c1ab6468ddab4c6a481591df8866a727ad300dc5001ed30e4192297df0c841bcf39c679c2a182d3548540c771faf9cd683fdd46c7686c257a1396b301cfc18ae74f38c93b59c0f61abdb538b349d4792d594d7c75560b4d91af1e8269a19dd56c124975d0ddb129d556484f014a3a4c2d206c058724394043401c0c5555d86ca24d0e4f4d7c5122d54492a9267ad0a1879359132f20e91144546d8a87592d8b921e4c6a352190f47822abd1d003081a1354497a08c1c48417244e4c3cf9e1072626663cf46892b484191f7a34412d21450f2292968092a4c710b52578b0a1c70f511690f1995962081a2c5730b18291a812442dd7f879ab5203b843ce3f6f55844c41050dc84576fdbc51b1020c93777edea89800f6f326a40440736ac80534b33502e420c242c7942f572421e596c419258e7cbb2bd1e5db492a4fbe9d0544c42cc3a7a80ca608e1d1b9bb6d7737162abe6b7c7777dbaeb466f252a85a6bf5a15a5d5f6badf556ebde8a87a5378b071554504e305192445923fb763fc2f6ed24100ddf3ea4c3b7174939f3ed3e64f8f61f48487dbb0948b8795ae2dbf154186043b1e1e7db718662e5db3b9719b0c70818bedb7136e2886f774121f2ed9c47d1f2ddf3dddd5dfb5a2fa8db5a3d3e3a3870eaa20826be3dbb9c041a9a028b299e54f17d23028ad30cdf5e5d59a868c289986f2b86c84f6ea0c20b21664c641922848c7aa6c9962db60083e444ac3bd60e81eee6f22dc5f6ddddddb5db2e4181401d423cd1e0dbf14d882cbedde544866f274cdf3b687c9e76d4291b30ac6095d42485f2d2dde83ab1a1a29c9a6c6d914bdb64422593cba64175108ef338f59ad4412ea75e953aa88653afb30eda71ead5cbf662c3cb7e6aa15e6a18f5eab9a3b0e92f9fbf9c7aee4ad3653aa586cd1b5eda3975dcda3aa82d15ebc546b135abc542d928fb45e7c68d1b376e2c9165707ec397540025b7acca396fd5903ba90a59a60af5d371ecebb88d1cef115f3a3e7f86bfc4dcf3f9aba7e7250446d14269eddbd6506ba27ccfebfbbeefebe1b9a5916e72699b9c74d08d717ce1f87c9673ce8d2f1cb78fe3158c2fec368a6d7212456c21db70f1153afdd03bf115fafc9583363cdc71def9c7b9df70cee7c4d3e7c60ddb5485ba671ccbdcb429af690ce0fcba0df125c24b041bceb90d9f8fbd3cc51d2796aee7388ee344ec9fc80112ccef460ad524f52bb6272aefa449eaf474c90c5a9e5f36ed8e1b2c61aa2dc04c619104161bde1c1d51c4cb9b29aa195c78a1913ac8c668937844faa549eaae1a228da24e43a4524db644ebd4a4689b66e8e4ecb065d13ac16189d649004956a275b24da0689d8469a27e65c8b752d95af5d37150e54c6697a5fa89e3a8025a011617b64048b4806343288268b3c157e7ac0842c9971eb27738b3f8b2d5748287358d01c495af6e5d6148254cadb5d69a66e08c5475f10515628eb450012b7c8061cd0b61242113731f55080aca542b57a11e1c40e8e8a01ec7e2cbf0bbf58316dfed38e9bb4917df9d1820cd62cbb4049972c09f03f97bece100fb0f54beb44e6523f9a70ea25c144fdd3a75d0bcfde0e4a9db281dd4964a8d7350fc5ae5e53c6793789e73ca83a3ff812429688640419b3350130b1750506dda2c29a18109893775906d2591973c5d8239cec5f992a55698bce472e55ca92a8c7ac7d4a4a565c91c12b7b419497269975e7883256c31b57df7dc73cf7de765d33a913e155500c6e4924ecdf879fb41cb736e83eaa967a6550c2f64fca5fdd9654a565d10c3e64beb54855ed46d53157a753e63d9b5815276d22b5515b2454c18f529b5aa0999bd3da5aa423356ab6449d57730e97eeaee26ff2abeb0d36ccddaac937d1a81c63ca72b8ec3188f25779b9aa46ead9397911b49cf3c20cfa9d353b7316fb43658279d2ba0b5d65a2027c5d43acec338bbfcfaf5f943eb12e844d6f97963f284cff8d34685915a657fc84e239ed28692c96436c4a8630ad69e027ce953ea809a57707c39bdd0a83ed3cc3a4bba84842ee1a1ca572a6a48c2c357f72468be3a497bf2d5815af8ea43455cbeba0fa9af372527d4f0d531d0f4b587325f9d851dbe3a952529f93a6f3ea8f9db122d4c96d04aef121d237a906244c89212c862659e630081e6c815538ac8a214e39098c2aab576d84161fe1a5544919cd0da1c05524f5345357f5c9cc861f1871b55108b9cf86af7fc286634e2d167e5381e3f5c3c5fb21df3fca977c63a2bb618eba80a7392a9d7cacd86aa10c9625d299637618d97ea4a35c8e17e7a2ce60ac3ce89779657e227be383f8ad55a85610fc51737fe40727a18f6a318fe516138f43c6cf7da71518561ffbed108a8c2b0371af568e41586cbeae43e63d8df8b1cfbb0c78d27348931506118fb8e25d95faada2a764f64a1c2308b8cfc02e27963afb50e7a9130634898265518f6d7ebc7e724ccd83796f079936fa44c1586bd5ea11dd0c76e67d5a93e592b846c01159b315a0417225c28d354d2a46bab305c9d1e4f6e46bb636381e69c33db19446bd580cabdd67b1b020f54e6cffc1078883261b6b2013b077b462711920e6aaf0e04f4dd532b0890d4b1d3247be20e917c456fd64526ac03c1731d4d768f9dcec4fed50972d9b39ec9963aa60e2a3b29a98356de792b7550e81d8d6a59077d47b1ee7581e0788e5fcf198d86b823909c1c37b28ee347b1ce7d96e49ecd1f1f213247bbf3ea0b4a9e0124432ed341ed9dd3a91cef9c4a51aacebb889129d413369b442c2722dab123478e71b4614347e7fbebe5c7ead9fce97c2536ad6715d67928760e8a9de3889de74ce99cd2a80efa1ce72794bcf3f339b8923d24589783875cd2272135f9ebfc13a95293484d76ae817923237b6f7cb97a5ce0cf263b7f79939d774eeba69e351394fc7d093963d5778ee32504a9b0ce338e7f7e4215cade395dbd46c8711cf7dcc8fa3796de0804c7f368541d673ca1c23a27754c22cfbb185e85fb2adc177b69fe7478ec2f72775032fe699d049a8412336272a0c02f6aadb596b5d64a6b596bf5a1b83b8b2d67efad96abb5eb5cab75d55abd6abf4c8476b59ebd1f8729f6728e934eb69debbaae92ee6eb177bdcf7e6005c3feaa0bc8dded6857acc9fa3e967b0d24c2416afb030a369d2358dbc75a7beff5796e7cae0ba968829f569e3e948f0f7048451c3f3e7d0ad4e4f49256b7966c4781bb0e02ce73ac4c667dfeab8e3f7ea88e14f470e7794f14cfd25a6bdbed74ebd65afba5b5d6da6bedad160710d65a6bf1dbd9852f25ec64a3575e3164ea969614480710a4d31010955acb82bad5bae5c6177f7e0351afada3ac1cc78de4cc2126cf2d4d66efeaa0b98589ecdb7bb6d0927ec67e7c3e1f48cb62603bcec162128e7dee89482f0cc5be117b128e81a3d77d62d250cc7350447a01c73c4f1a8a7d380cc32b965d8ed3cacf267e7e69bd7ef0bdd7711e08769cce0cb1b438de8e5927b43a1e86f2f101d80a3dc79d7b22de0919d07d07709e738b0237e2ce41803ddb6e058476ab971d7fe0b11b872a8cfb5b7d9aac628d708ae57d1e3ccb23a0db3948559490552e8e13254a94fca084d2a2daa8144d96a5412b95b2190000080315003028100c088522814024ce54552c1f14000c7a98407852990b846912c328c818638c318010620c010680d010d94428106a4a255c887fb0cf0ebb545c860ad3a8aa843968fa20f1c07730e5307ae4c04f208fee18cb16180ab9287cbcdf58368678dc43e092447eaed8450afddc60d9ae429f5825d5c02589fcfcb12b209d4f3da258e9fa248c5ca1e8cf12eb6d81965c97448ae4f513eac9fd837b04daf30a2e0974dbc548562469e446e390fab418ce0aa6e4e1553b57c4f6aa696926836b6d05ba2a33eb6c617115c6026c29bb15ff0e979a982d7e90c9f70af49303c2586a564ef49c551cfa9fe68dafc222f1b76181cff814823d4c30516847349e3dae3255344535835ebae7b68af8d41b277808e440ff283af4ef2455d34415bbfbcc453fe8f69d50e21c255577038dd0bef298b7816359a68e2f486a03e8fa97070bdc93e4fabc1fa5ae26cfa9b4605ce446bd51d58d9439484a8029b1a2cdf7a23574d7b9f09a194cd8fd14de73357d9a3abc9bbd46026a184474d88f156467b4b4cbb4d2224259e1388fb1f12b151a14d200aa1caacddec06b719ed16bf8a2f75bf8e0b386a27ae21cb13ceec03365bc6a4a9fab2ebb64e9473c069bca99472ce7057d7631d517e61191c6a3362ae0cf42b32a327f188025f22b5e716d11397b16e2bfa5798db03c2405ae5afabd44a732ed2849e42ead75e5579ff675edfe7abdbc80c8190919972d1b52ab098451968cd5fa6812f19a9596dc2f2c420853140a8b942203eed13bfb58399636335d215c79aa020c2d8efb35596918a2367aeb896ee71f492bf491d5ec67ba1ff0a6758883e41cf7be05ccc2eeb1a7e185b395127d1996c1cbeff998f0a1c0fa5617d9782cf1de44cda76c7e75bc586f650f2638e10ac9aa5a2b026328cd0f7729b0b84e356a644688d01b3ab8fbc3201bacd876aee39cf1c23211bcfd7e06677cd1bd35f038b11ed42144254fed530378b117c14d05a65b070f15a8c0872bdbd1b8d8a0412fb4fcf6d75d855c92b1d51f72110d854e16e426d05a7bfd878dc8ceced32ffd39c4aca5bad1774880213f695bd0aa8a2f2f9ce8e2e0500ded7e1d0580de6d619a8fd25102550876156951909e3c2e40c4f072d3a2842dac57bcb833e36e87d1bd95e2544df25c25b2e0ea02b38abe31fa0933758d2ec5959c0136b658ea36ee29498b7d266976f92e7d0c00636e2835672f36b2bbb190a2fac46be3289d22fcd4b251a5218845eb8f9388e69c9a20c439de733711c3587d194884902e5ad0af330e52132c7df40548fd36e294cece5932a939daebbee47f2ac3d26cc925182afa87de7385813daa1a5047cf070726ab44e009263b42c11cf98bf443e7e418574b65d1c4e77cedfa31fd3bd706149c4d951559aba57b591a3cda9de7e8205e89c31ca4a3b3c4952e844b43a8e0f3f7f8bf1700efb599e150a786cdba8e72ced6d3e7816e5a614536c0a1eec344cfe6d6000a8a313c7beed013a2f8d7209a1d0dd5d1b98f5c9fd8943ed5bf602533cdee82c44408d1e8ec5bc2ea3084ef613e9f743aa6bb2bfbfd1acb3f5493b8b308b22ec721392a83ed725186a06c66f3b451dd3558a8c81016e18275a4405883f432b5726b32d20af3f43e93915f9220c81ba258ddf7c5eaa38a7ba26a549cc643f6034674d7b3323693d265a83a885a6f784b5eb801ebd8db6f4cce00c8281af8f81a5f6f2f0984b15fb695053bd6d8a205e3b02c138fee08db5035f1627302d60962008252daa3274bba62890f0be715705d9da047d9471a3375a005930e7a303425e608bd6557dc41270295a06882fb0eb2a03c68b658ac4a3bda0814c1f54d85e59b84b6e2e08874e126a54ce0cc887405f13da70aa9e4895ab8be435a5d83a39695dde913c5ea226304b591f75d1b00fd1380e3585fc6d201e072e724ea1cd4c1c6435d9c7a86e02b13c0f08ec1141e277b3cb4b4cb50f832c2c439e975f408f33afa9afde3d528ef3ab631859997ca145220de0c3ed0060c4afd6c97ce9f491ffe3adeed84b99fdc4ed02773c55265a36a09536ae808d6f55053211357bc01bd3887bb215617f9dd6eb0cfd96ec8f6e216abdd10308a9664fd54d6d0f29c6bbeb34bc24074f72494a9cdb3620be99d176d073ddf79c78202058b11303a8743573c365ca5af9bd0c85e4ecfe19dab1aca1d11ef8cc7c43bc79de29de5f51406c51b5daf096c26264e7f32a311bcd00cbc6183b25a8c2de26059438ad2d09e0f4399279877525d37d5b6009f66c16b6804c2e2db79c4e8dd2052d48a4b2a4b5646a44ac5179d045f3f7572dd0b7641d7626e18c4ada231762935923b64759287f892aa5895066d6b63045547c531b0b923268f6d9847c78166c4a6cb8f529ea6804ed1cd960207072d850a13424eb0845526573cca80cbb68e18d0175ccbf3ff8cc980f857b4ac754ff9f200e081526538991d42c42adeb26cb71aa8ba76d1de9288412c6b99d48e305ddfce5af619d60a074b19697dfd50dccb86f245032c01257a31ffe4088a84611f2ef6063a5f5a9b4b5720b8910ab7de49a0989f46dd4396c95101db1401175b8ae5658551b9f295a1f8ad298fcaef33f4e63ead7e1c6232baf748be38632bc32379af2393910ed96aef68e7eb62de52f8d67ba086388dbbbabe5c385827604b3b81e9845f396365c28c75aa6bfac805826fae06ee67fd87e356607db2f90e5eb562997fb0c24a63913a6d8b32f2dc1ce135640d024e2a5aad6d96191f1110f9cc3fc6cfa832b2f3a44a206bb8e14dd8a03065e5e444c673c3ba8eeccb9e6a712ed8c0a105690f344077dddc4dc55f7bb09360d13fe63e833c995b588e756e0121099e0703bd1b3038d3e0d7507bdd2bb86541d9bedbf33f773be7a18f12a6030d5a07a2fbd9d923df4ccdfc740e5cc27341f539803a8ed52a93278ca02f98a3420b825adeaaa6e1935c1685690c2c5bbc88076fa66813d970e4512f10f3b7dc4f3f0e76c2dcafc8d5c20de3ec9a3e118dc76192c0350b4a600f1f8fd5116ef14ddc52fd38db8c6b744bf3bcc9533a6f76064497e960c715f1c841edec7b15d82f641e1dc4ea3a0771a1d4023fd016aac9f189a5ca8829d15eb4f2529fb59784b31b8cca083a249ae1e4a304d41570cd47852a375f1e4185d08d9a6f392ba1922fa9a78a330fd44fd2b53b25c0c1918fd85268da0011b74239650694d3e401770bde933349642206bc41ae7ed5501549d6af20887f301b3c9d9bf0f978f0da9bfe4b0329a4f4a6164eaa1ec7d2f340ef50cd5b0c56057f89d1f38092c8c40bb848d3722ca1dc4414bf21932872906824161ef65019a30c2ddbe1236cce7c9541c409508efb9bf1131b065643314212e9595a04c0f720e603c3153e6df4ae8dfbb1c0f7e61edcafdbd7def87547118eb414fb341ceb68ea6572b907c9f8753400454e4bec2a4a89a72dd70825eedc4062f3a990187785189b291c24de61c4a52894268c0a286a166851ea96cf602c6697e72c3a42d0413a459e2bf90d7bfd35a8654fc87c724eb17f5a8331e02c92c45ced17092deb6a757d1b7e172ad71ffb87c62a5f2193099900369c2e78db59c1b870a8f818d16600091a66b0e28d612bc32b2d710a23b8d744df730a8e5038acaa235b9b74678e7ae364d7202c2acc8d2cf7da5f0af7aa498d2bd04c618e621683a3c3a9be0893414e94c9e065326979776fb81f36e0c3af613951e8225c34e2011fd3c411d4c3b4ce9776579b1a9788a24b095a5712548246d7a0c13a722e0a4a80efab9e0d5d23560c43e7c3c1869cc14217c555c10603ba826b026dd8cc66faa70828b5318371213e878b4f49cb291641251a7083f2d855690852c8b8c905ea85dd1514e31bcf12848135c36e69a111dd3f6fd8f776678563ceb71367a8bbfde26685ba1ce83177ea59dc76b535c82a1e93d4e7dd2f576945b5224fa4f22912d79eb94189c628b71cd96169890734507ac7e865eb0392374d2eaff0070dadf123cec2dcef5334c9c16eb9fc161f53f92a2bebe2ff27749c06e27da799aa9a18061ff02ea69e1c0ead2cded3f700467ce2e49894eaf995112668d988ebceb20435101faf5329be16def2516afdbfc3b0f9a1d7cb393b1a1067aec5585b00a070ed91084bda79ec10812d7dba19a924761c08b3d748422dc961d53268f4bd887a17bc6f9fd572836bc2c54b58e4eae4b1b0feb996a0ed1f7691e1a0ebfd5c9139ccaf7f185033d382715b0dd66f5240c3a751da1dcfbe12da78be81c00b86f0b89f73f2f5dc9a04c25f830553eb8e0954e6aada2dc1b8ad7cab2e157d71b46171eb3b664657519c67dd2196aff766caab64fc788e580606b93ebc5832ef29076d78223f9ba48e0b519e4187f3a4ac124b5c4b7631a9238f7731901799e7e56dcf1317e48cd826307ae254b3d9aafce3ec7e6b3b13f75e110e302a43a6ed8b9992ef1844f34e5c42d7df322dd7af62c439fea08592753218b22a2b5173bac46956aacdfa14efea3f14bb8df39bd1a814ceef2d3bf4cd0f5b05b672f39f90212a2780e754eb6cac5eeddbf46f21bdb75f46c1905ebea3c3084c5fe41802dbe1897bbcc17c1113fe4e351be7069b19074c8da9943768530259f8c21e2f31c23fdc3c09a5d380654a7c00a5624976f62309efe2e1903188b2a30cc19f9a8c7803ca4cd2314b89435022f750701bb4dc010d4189645af599b9980a80c87f4a83fe230c98b5d6c4ba02a92ed6dbd51abea17c0f8dba0b78fbb11befc3d0b18b2dff8b995d7ea498cf398e1c002a80d148977b0612e4a0cf76671404a05ff0bbf1dacb2453eebec041662b2671d3dd19d15220633149699a0dc78ad5c78594d3d5638eab996734f358060099eac2890d8daad07e92a96599548da104bade2f92a62efab17c4d802ecec47a50d74f056d3fc7e48ed4b217c878624df6ba54985829ef36ecfe2811296d8c29dc806193b52cdbd6e675d4cc6fcff5f1f62e244dc70767e1fea5559c57ea569b4fc168f051e0ff7856beb4c4dce5ffa8ec33b10312d4e14c1b57120768336719e4d9376e055cba2405dc9909d2c2fede9749bbe4c6cd551c622533cdc47afd68761451cffd612521ae5668e56c7cd326efd367499667899b4202c5e0d48859a9a8d358cdb7bb6140427f1443e4c60beaa5e58ba1e6c67e6546ebd7ea9191710f4c8ed47eadde5f954cebf83a2dd8942d0573823c2a2f8c364741cb848eeb6876d6c787a5ef3fbe849a5d4f1647e8f1de6e5e4359382ccec07d1a98799a6e4aacc8bad91d9ecc60a6f0b543139c74dc8e272495118bffdb6371dd6c256859b092b282609ebbdeb18ae3044e593a9fd2d29b278c8569536999f6f0e8d6c45c46433d906daa315d7d30be1692d0a2f81ae0d18cd8d7937adc8c4d62a35eb32a665564f73f3b99bd803f88ba497ea4e1354194eac2241617b82de3c7d948898e106bfef06b91410db91162806291c080f215c99d4ba5007f5c6d4d9d6ccf2bc16cc465607b51acdd096b8abfe654df22568daf7e29486c8aa80eae8c6e13b809b6df11311f4cfdd282640ad37baea58fcafbd106e20990b2497888892d34f6808382f11b465bc013b025d16f7f6e65942c80bc8e98d744bfe9e547fa996038dc5aced740b0b6c7004550c494f104779c1c116e59688724231acce1d5bb87042847faa62deac005ecaa153e815c263946bf6a22c41c98d4ed0e34b0f731b08557cd315d8950d62f933da82c95a46fb67bd95d43723ed792c21c0fc09b584d05a2f629dc8a54bd279af7057ad5e3bef80d86ce24091431b9a51707d639509632958ec9368dd93ffc562e00dc9a0f30e0246041f85311d28848fd41c162f3b93ec8c1f473b42991c8e117b87cc259725422a7e84eef33bce0f213ded72ee3e8df65723f163f277f52f4afe03c7773149058d73600d2b279c9f0a1b5866a70ae7f1740f363e5567aec7ca74d83f85ac3216cfadd6b73f4e53533354148831dbdf724be86d1bb2c8c49d59d8d4036b7f61c6ff42578220ac589abf7876bd32025d0e2ac0bfd2406c8ec8c5a81a9d13fcc296d7b1d55ccc5b671eaa9f4eff66b0ed6049055c736f5ffed5e0800b1e7728a96fa2d7db19885972a43d8ee17280d6d531308640f2ea35a66e66895494ff719f03b676a5d406ad3017d177c253c576cd16784a475e7f84e74fddd17414758195a1e75e21c0ff0ff0f1c41bb83f1b0ebacc36ddcc1725353a062a1efb093d862ef035a6d56f2f489280f86932dc81dfd4670c35612eb263c97351f1b8a9b50be7b293f8adf07e3c4549b8fcba031d9060b966c52d6ef19f126509e587f808d6bdf208f2444cf0553605097420a70f3def96992806eebf3e4bd063d5c4ff88aa58be2be3598dbb20fb88a4b7650aeec982a6dde9554d08542522989a450c4ae002047d78ceb4ffcdb10b930ad76746b0d105838e44bfc167fcc757285d29b0d41af7b117705c5bc0ac18f79a0cc03081616df43d80ddefbcddca7a29fc0f382c6988cb9f91e28821044f456ddb18755f3b6946a7f5b485ed6e01f4365983c3c8331d3970be5897b52f8c56490c4a3f313013e71338f9b82d56e58246b69dc8a1e76b36d4387769ce01f5bce79c5e3991c4550051dafbc81773cfec5f17a5b10b6a2e467cd51ab72954bffc76194bc896a40449a6dd018d0e7b94ac835233a3f222b9ae0827140e66ccdd723b19b0d0c1a69885549d2543a424e017c63227121fc5fc82bcf42451f0828fb44a59e25fdd4164779b76d41b997ebb4c4f526b84a34b7bf36aaba28be9cf529dde84fc85a6e0c8251830ae74b903579368182263d446a1cab81e33a45c585651b90d6e77c5526679ff4adba319535d53327b667fc272f2d5442100357da7d6ebf2a3623f059b0812abd98b4d3c713085e6bab22759ac683af9789b8cef20dc7d0ae9d457dde0c667b6e093570899c1b58498e8924751074b7002f2c04f8aa6974c427f2af4f2b6c5ef2aaaaf7d2f04cfa1b6cce7f8f834d7a694a6c3be7372171f18fb973778ec37c2673613adec0811a74fdfd78bd683c81148b1728d6e040a6b909921d36a2420a45402d62fe372bc2eda5527a5e661115d93f8f88527fe6f0ca5a2eba062c1d5d1aff6f001cb05493dafbca39ad28ab50f96442645d424afa3e6ca88af0e5ae403351ab36fa1c1d4413810b491479bd2d28d4e5cd31ac3b1ecb9c6269704af944c8e198f26b336d9108b7edd904c26fca24a908f16f068308dd884261835805ddea978e68adb3850b3c66e5cab0fb422ff3035dbb12ffa1b88480aeae302fecb7d2f92847389a90cf1f6b27af76aa09ebe627ed56633273b9feb945ab049c8004214658834c0e6dfbdb15b55242b7822da763083025fe30bf92709873df1139e1d4579206539ac0a9a9b9eb9905688346f18804c57aa5773ca4ebefe8a996e9a0a6bbe84c83d013e4fbd2d1109a30bf9000fcca8a258a707c7ab56c24698fedb5a12e0cea2db19ac57f9af9e3f5eb2e269a5d5a813913b922a3426312cee950bff0b8a0109e7f3656f315c3711581f0bd2723888e55a9ba6a0c599c184bf89af7685270e72b3ab38b8ce5508a85d4f78fca8558c4718ede1e6e797648dbeca36c68f6824d5c0a01430201bbd570dbeade7a3ed7c61f1ce384aa39997369aa1d769338b88e05fdd0fca7f87598b85141eaf38eb76607d9635c79b0432eb45ed969b5042e5c4e325c7543e7ee24ff5498c40a1f8b43a9baa87c9a9c67667c731b8958f606a98dd6c2b687c980f3341a74cb85de1711ae954e2cbf26bacb09b7e6270e0ee1d183107e55c436a689f62f6f5c8987c944d0ae53b7ec722e93c4aeb3ca0c7c504ba7c9947c2ccb3a5a5819983281d0ec5626f3b854bb94fdeee735915a3b6d36cc4d27a78e9e896926e8b29396397d22b78e7726e699a8d38e5a36664daf76076a264c4d21b74e9e894926e8b0d36562d2446aecb0b93037a59c3addb99805d3cd62ed28815ed2c4dce469d1590a5e2922dfa74d9d4805797754679a269157ac82e97af9b9f638332813ebd5adeac45864963a27eca43bfbd99c2674104be95f1bc7b985c1942297171cfd37757b13b30bd846a186fe146e11d96f86689e41731ea129ec05f28ca8fefaf02b422b41c7b63ff212d4e8f035d715d0c067ae18a74584eb641840dc0786553319404d7165b00423f939adc327a2d3a10249237b7c446e45db03cc0b43d486eb4494c908f7114151163655185ba17f446e652e44d21968f5d02b6142ce2b3e0a29a2a3c926cf65d0190123737ca396a22f30e2bfc7e1ba8c8cc4eda0962e6c9550b0219d14d52ce07a6f583d71e72cdf5ac84c37a205ec55d4ec27d62257786844bea5ce5a2a5ae1b94dfba998a9474fe838e547aefcd2098d03437c8ffc9dfdd2f64fda2495cd86a060e9b17fc3ccee8ade3e52e8c0557811eaef249fa9e8e0d8bed2511eacbcdad200e9cd71bf05f195f7514d8cc2114b53f02d570928f841e2592ee460c5280f4631ab7fd689854eebe8c38cc452421e6466ece862671b2d1e6f5119858adb634993f9186239934897845bcd08ecf4030e771c411a9d22a74119a27c032bfbe0fb0158ec5fec85e6ada58fca550f042b4427238728309ce25280e840b2ee27a478b215ff297d30403d9bc3fbc883a5a17342b1eb1439b2f7f45fde105660a77a7a577b6b579d97aace681b06f6538882823022b2e0cf822855ff5aa2d806e3f3342d118e3a8bc96b65728ef655605fdba1428e8638dd63839c9d08940fb4daeee52c2833773aac613c1a9cf1642f663d6898ba258ae45a0764b8aa91db971da8fff79fe80517698cffb11d90b18b00a70de10585f5d604dcca4eb000db4f8d5f06ad0c4545bb099e154d452ebc9f59e9396c2a3b0d074a67f03d8fc18ab21aa4722f58e0dc10d34f3390639cfe0df26cda27acfddf772e6df4fc241386148437efc4d9623767565d93280ec3d946043e4e8807a8dc207a6c913a323780521163117274a0ba22556f213b183f1d71170734d1456425d1521b4c0ed8a447bdbfa82c5eaa98c188c8c07b7886adaea4dedb1d217c3305e5984d2a5c11846d6faedf58094302cc593011ed9d7b9952f57758d5d778dea0b90bef10084bd16c6a363aefbe0b669bade302c24f8e1d1a367a34d13f00fb7f8a0ab1c67891a8ad359470ac3760350eea386d5e7360ca5023f72d703c3329595664e6fbae6ece273bee67e50e2257e691f82b69d71f67366130e9c41a664440cbcb5e444b59e9c553f8fd5c72ad2bb7145a37237cd9a48e576cb589f8e240d61cef0a303562c493ef0b3a3fb1daf1af2b43b5dfbc545b40ac3423a967df43907ac66c59508bcbae8cb199505200becfb88360105fdb449f2d651c0e6a165f6f53bf9b6001aec9e323550b87c9d31beee459e72ccd09c2f134188d90c5cd1bf41bc66fcc721050990818dfade288b62ff14faee854abe3dd997d9e8836f23cf4b79837e42cfa78613ec29d5c19e9dda41bfa8ff609fd3da1bf999bc511cf6e6eaa2c70dc0d20a3c254c7438cc80bba4e81ca45be86e2922f5758704068913c31c9648b9e3d11ba2e78ad06aa9af6478974ce4b83ad3c1e9195c70a16387d7759c39bc6869b9385ca0cdb8aeb0c8ee509f3c71a2996a7911fac45aa5892cb0de5aeb3d937e4b55724ae29cc3b654f163deb9cd6c3724794506e644bd6ff223a0985f1e25427ef586393de000141d5d4b293192b2338d52f23ee2b9c5067eb5de4f2977a078b9d712e6a210625c8809755bf13462bd0a7a69b812d42ebc50913619c22af86a5e94fb5e00a5491a63e8e2183706b30fc68939ddd123caf387ccd53a758300b4de2ec89fc97a91abf44aba456dd7309be74594d5bb6004bc82272f8dc2219c522039e822e4fe54bc1fe89588b4fae7825aeed4dfd790aa73bc2ef0e90562571c6f9b351d8f17784894692c0e812634f4381fd143f800bf71d45570474de61549bda0f2e22e792d8a3779807fe7f1aaad9ec22310ca23805b45dcf62f43ca8f0cbb3d539daca4d8539deefd97e22ca93296dc9d4d9ff268fb43395216192a8eb8716bf82f0a24686561600e5df760f6a967218a9b4129be9a2775896a20a312dc59cb69d9d0b2048939ad3214692990cf41ffb4d0ee0b61d00b71980592403a0cc647201aee8b12a18d96eff421373432a35b9d820555dcd2a60f8ab1ec4ce8039b5e8f5f0c9ee9bb8eced84e260c02f1fedf6920e51431a30ace0f911a09c04e5fd2fb567eaf9014dde998bd4666e6b08fbd406667a7fe852a3b4218ee7524ac5889ae18bc5d8fe219c554f826a117222617fbc5e81c2663643a0381a58510847e75adb7e4b95a2acde6bacb72793af71ec60022b68a68f062fe42a834451c97b5351548088a2b7c8cb9ac40455321977d4a2c1720bddeaa32f05bb07828755acd6f75aca2fce53704a8d12ef6c171d8f9fab2b09fefb2f6c868f3999f199a3dcb55350bb6400a6e2b9f744a944479f8a6783f6bda75553c6d50a104780180e4826bfd1ed3e52abf172dd10bd4b0d90b90771f331f0904c682a41cb06625c721156b9f3746b56ccb01d78bf62a0e92b696ea0f4e0f9344aa8535aeebcb9dc23f9884bbc01e9b9c2a1e01e1ff2cd2628a21f3cdeaae31feec357d78d00127e2b275b74856dfdf22debad18a625d8599aa5fd8578584d4388722f3a16fcbff1f432037acf75600fca25e2df587032ce9246c85cbaf0c976a5605db108463339275ada0be1aa98c8e59c57d513b3e22903a0664b33d58298546353d9ea058b4bdf4a24d8f152986703727fcf4c9e6ff17108c3af1eb4bdd6309f13afc2035331b242d01c22ceecb33c7d323875271b945cb29aa037231aac0c563c162f57685d894c4be16502bcd99605f54c86eb0c20c9c2ff2a3802797f811e38e4baf451c58ba106a1235118f31ea60ccf0c8a2513a0d52596969b5195ddc574dd13b91e88a3883902491c850a1f5121f5b5858c93379563fdcea0fe4826b73ae8bd69a3c37af0029034df87ff1155b5960967d1b4c53ea6c51c9db23b1a70dbd3d18e6910aa80b26867e5328129b0bfc0ef86d9815ce756c0a6f766f6296fb1ec6c730411b6c74076ff6cb7ef416814f49aff67fd956efe8ba4a65f4222dd4d4588e91a6b61ebfc83870b801b5cbb6cb65c57606c8352dfba89865dd82b6a11afce1c1f6353324919766163a90f6137d71521dd6000c28854069c4cd8b6302e438abb0dcfed13d2781e45c2b411c00a5905b939273d291c2b2f3389b9571f0f54ebebb0349e32032c4737a7c9bbf23d5c43e802c272dcca9c1e382396fd682b77916dc2d2c8aa6d9a941e769b60981ecba0a76ae15c6fa56e01abd322e0abe1d894593decef5f23a61cca2d8d80570b18a5dbbdabd663cd726649d9dee089cf52e0b563838e61b588dddce8553b6a473ce1279476fc18f9fa680c583dc4c3407c14ee3bcd27de1ec5c7b4ec093c24b36ed0495e281554f0a2934c3e301f3f7fcb841960949fa88fd5449f228d303831f6d6dcfd9d94ae035adc03ecc726a2cc12b2376696728f50a5cebe99cd15fea6323800a0613b1f186494dee0d1d4dbdb0e464896de94ca58a6e44d6fdf503a3c5b0c83ea67448a80098ce35809b4efe4436bc64c15c5cc1565100610e8750442265dba381b38a29af159bb5f3bd4a2a268c01881a921daa84181796f7cd2531e46b802969534274dbd134ae91a0f13358d43b97a3c3e7a3c59a07dc2f60f6d72bef582dc602f932bed13d5fe00d9d52763550cb9c474336b53fc287517e81aa8d1a10c9f91f5a53dfd947a89bbec837a811eee62ac7c89206a8edc4721ffb4049f5d03469781050372610f1a337709799bd6fdc5f5c015e86ddcc7fc618f2cb222dc7fab5fd4225417b5d797eb2b891f143909870282f2e8613122aab2ed1bd36c0a17742eebf4e0734fab6b09f93f5b06438b8dc74e24b0581cb9a78ab19bb068a8e5c7d4fa7937dde898f586db2bd425e001aa91058c3d5cd49d3db05867df997655d8176e37286b0247eed9855f39d8ebd26a0463f5694afd68ca8f955a409fa22c96f8c3b77184d9b6eb09ed204b6d59eb5762d48bad9dde94b89875983af96cebfb2041f0ccac300c78146ead2d462ceda09c235187c4be385f6bf716f1762d60bbd4e81a625f7611b5e2a7a7abfca0ad36e61c17158ee47d7198201cd49dbebe1419653d21709ec01dda4a69ea78780c56c8ca6c24e10993bd04a0d258e42ecb0a280b83d8b74e315130aba6a4a064cca4dfe373612c15e4befac27472324a2ab2ea59152162182b17f627ceef0a84dd13ce2fa11b8c0996858d50bb048b28156290654eabf39fa2af7eaada34180755914f20c6d5f0fda33909cf19e177fb54ff32803ea1bf6e928181b884f7395ebec20943ef1da1be1824079da31f82ce92109a201b674de763845cce53bd52706ac1bc3b08df0abf7eb2b5ed1c6689b587bc59db0e827cf64fee229afbbbe13600373a424b42f84eb405590f5a009f1ff59eff78347aaa43db7139093bb58329327d29c073f27630a3d32010e558201654dc2be09009286a4f0c1efa46727f9e33bc8e1e298d3873c3fa6bb3d44824dae5b18bce37de0a4e17dfa2767aaf182079712005702470817efd0f8baa75ba5debdc40d940dc0c99dfbae0e8da094e4b02fea6245cd7027140df3ff0c0b40196a2a0f429d27eeb5eb6c5fd00a2a2e28f22fdce21daa63e61f6392a5c2a285c53a2d28c2d1d6ebb89d8330be4b82dcce9f5abacadb320b6c0d18060d39d68a59b12cf74a9c99f62d8034700c91de30dfc5b73f0c526f70d09e259bf705302db20eb9c57e6b9823ca14de5898bcd7d08d77246670cf2860719669243d2e170d411567b9e8e99e60540152fc280eb8488def9733a7da4226ae1f0e74976f8381b47c49c9bda764f3fc077a138bdbb648a1d6785a28c75debb9e5384636ab330babe919b058e0d05eceb707b860bd116954ef7275dca6406935690dc6557e4501b485d3e09aed589cc15c18b8e1d6067e288af2d8c0e230f6431e1d0dd43f544e0de39cd221f0cd8d247c52de9768c266f2fcc8587c7d12beadad04a4fa58298462d85355a12d6c775f1187b88960609789e40da5fb00956cefb3fb3d0de3b720f9de840837184a0248249579eb6d9c0b387ca3772b6544a96e799129a8c0602421707c856439fd3bb15de65cfcaf161b6445059a6323593bec418a15166aa95d74e29930aa9322463a88fe533b524614517ba14b7da9ed89b76f832232d5f189a4d18563eb1f63182f6b463ccbc35f12c01849ff1865d78f3a2f1532f84bea41637e826c4ab223c7a60b9ef4efcce2435899581d17c4f699b85dbe845f10f97c06923ff5d19e5fc7b6d2e1a1e7f60ed35f81b175a351045473a201636f1c2396c534f884d62b33bdbe28c77646d44d6944e894a49cf07bfcca12fc09b2af606c7cc4f095737d0fbfaf3261ec89a6d64954ee0cb4f2fd739514fd4858da06cbd2ea665027e143412702a5799fe4c20b524ceb45a2154c8309b92a719286dd016f3510e8c470a8fef2fceceb615b3b44fac133ece4fa3a5b8e8b13e1b65984c1b0f432d5b456ab05fa13da06814c1654e904d9c3c32da8acbc712d18bbd2852c5e310c8debb7ab8619a117b55665454e50cd7f5a43331ffd10ef317538abe9a54f3bd44287bc550adfda80f368254b7ec50ab9a234103ad1c5f461857ecc04fc4428c18c35fb5306f39f74018391c8ef12230f8ba20926e9d6db8699da12f8d477f00a4e265b1dcc5ad60e8fb8d519bd6345996c3ddb15d4cf8db07f8f7e3c198135a5518b76c58d4d56bc5bc41a0c926505242d51ca75b2f9b102429bd32e0e91d8f886daf9caafcd9121d1d46a141b6d195a13e1830ba027e22851efce464e77e4350e4da9cc7be0e08f5548fd42c58ef566b8c6a352264ee359a53719e98bec0b2397f60c855e676b58a27dd8d44f4060960fa2fc1544d0784ec5447871681b011e530a44f148a312a41964a0981de7794b9eef78d8fe2ebc90676d1309e85e51c14dcc331743be931c955bd9c14e7fd92df93d3b839e623060de8bd056ed1db03e2fdab36b7415443fa70e6909492c6c0ceaa9325df2e464fa9821805761e7652313b2ba748b5550ee03c80e8ae96f0a6989ab7a49271efa6c0e5f7c44b0c9b3154d2447c55aa4114da4bcc4a2ebf1b2be40ecc4c1de5ea22a1504b24beef086661043441443e4244417bd33aef415c22f2914ccb1905d729b4280e1e7e14eeb278f29cddb68d9f094dfec97d1dc1f327dee87a7f9f4c698d5e91def675a7243ee0f33bb79bbb9d637d4ec5d8c1a72588643ea8e469ccbd6f047bde415fd9f1ff63cb473544ece9ad910b97e793a89e1ef1dae04e7de97b72de7cce341d6229875b00dda95b9a5f7ab8131872478f3322137c7393a3cd6f27b4a3c7cd3c1227a36b435b33033b10f45bed505b54686572cd335612394ca863f9107a593b2ad1efe64394af5eed725ae00b50b45da4ce328ca2ff3ff1a1435a7f17e15bb17c59b6c5521153912300214355504456a0f0481671d745cc79ebfbe2ac3553d66444786202db8106d4d1129cb2861d87aef057ddb1758195f3a82d1bdc061e4c9e8cc5c8d0d63201bceb5dd0f151f018d9c8d2daaf20b11be6f27a8ef7e36cce28c1a60723015a65f07eb716b2fadec22589b5fce71c208175cd65b1eee8479418a5265ec33508eb88e85869490fa9e28fee1975ee5274ab61035494f593e246dbcfa4cfb4aa742a1751f8408a487df19b68d5e07971d312d7783539564911fad73ee47a81e0533efd3d23be0e1ba494829757206d1dc5726f4e443c935ee39991b7b144933fe8543a62f201bfec2df0a1816048f16481a409b05a9b1244901ec84e4fd7fddd53ad2b8851b0616212e7343b17d56d9adc4400c8b2b53d2305e28418ee48d79eff3398e7861ddfb245b40ce34f3bf4ed9c619dfa03ddcf2e74819b71c3b47714c7cf371fc3322fe314dbd8811a722b8e51f1150bdbe172c067327485869fef4814fcb5543e0ac46343fd730002f23b2853233a39d417b35dfdec6ff8148f38d5b35adb736f326118021ac351123a171b06c7379618bbe0f23ea02a34b1a1c8041f31d0b759ba2dc659fd7b0cd5103126562fb5c5856174325d2c7b57c192d1b047e5769648e0948bb9420f68c2a8201c1f064ff6875be55238e402ef08a7c808203ab2aa1bb24dcfb53469ea61abebf8738604d0689b1bcccd98ff42fcaae8b773193015b9c305dc9c8d6ae6ebee154a8a2ed593aa803baa41275a28e787c52e842c49331ca0c10331a478d2a849c3e740b3e5663c6c7ce995ab07865c324a123aaa247d1e435e357c5ce702c6cf37a3edde0e1e92088f5f054c926f47b4c5b3c2a29198aead413922196db265787c6ffdafcc359b0d95dd902b4632b5929f93103edb60906c6e5cd782c841e42a20f441328cafd62d41dd483c83549881dde36d96c7eea9b5152d559d52406768e5c2f758ff9a19b8e32fe0de90cee25246917157fd3e2f863b3109221b0550a6b59e30f9e46d3846702f2c359725cf64b5f9c973531abf692134eb7eeff0020c699d6891316d2be60f0d1a44838342eff6e7f7060f54684f2854472247c97a5308cc3e6d416a1083b16214d93894172c6a2b95339791ed30e7b41ad6d33dd40e1b964f6fbc2a2c439a686f986847e771cd09a46feca3de94e1b39ed2d3f535473fa97b97abb2c56fe2f77d27083dc1142d66c9ecb0ea28c80eea9bdf266736393983590fba2e5354e0d2e2f4b540de0c12fb8d2fffa259791e21023c2988726116b4c9748063a204d91958e3d2c33334a477aa2cbf1b7e27c2dd295d551f127e37b8e765cec48a2b615f0952aa99f8ebc859c68bd32aa19640285c3d9e56015b9b36dc1deb484b28e886afd7a40108f75742451e75c862e92ff213501445f19d15d4802f242a4b9de70f048f504f79d0b6df5ca5899b7bdef16d2f1fae8dd2a5e24418e75d7d0e1517e34eba985c2e03e7649da7f38dabd442f9b94ba06093340428e7f02c6d95ee2ecc503fae5bce11f91281e7c1bacfd9f1500b6688a1bcbf918a73bb10b04add32738971ca65d344dc32229677c2d8958e9d9b79cae63f270e607a1a560e8963efcf5a8dd7cc1f3a28a85d7aa3fb1ac4b5f163348abcd3432cf554d1ef65f085911a9b05d2b1498f2ce1a1ac91f11cb513b4fc5f98c3eb353d627682a0a4a5101061fe39f30861df3b1addcb07299afa13b565e598a1da1ba522794895a841038268b645e2e0c2433560fb2d12af7e69be03e7fe5117cb94888a7d269de1bf03afd688bd0fc99c2f03638bd5f548ec671f4ea185614213f121f3c1e30135e6d8a5967c56ad41b67519e3604de5aa10878b8774de3de2a14bf4c51d10112434128c7b68471338895006474ebdcd4b99604977aaf7cd54742bafc32e1ec5269605a149a0d6461d454949ea1b632d44d5446e12417a16c08b2c2a8a42d447c71a1b9b32d2a10892e4e35024f301cca654fe75e6dde06e71eb3b1a32add011da1fb11f576de5d9a5b3f95dcda833e98a72a03f2947acb9568ffa190d429d233be1ad125a13eba89d619d418fc8440a79648ac6fd0cc63b997e4a0d27ef35e72149ddd8e02f8e518f95733081566da0bfffbbcf91ae0d28c611fc3b7e1981a73b9c8f232843240d2e5b665d8bae85e19d95d615ddda8e8a1e5d4bcfe0a625b4dfce24590be7771a9961e3205260c9ee48346d31f6a0353f5c5b984565d9f4fa73d6cf15b9a2e438d1cbe880155dd4ab20281713a972028fbd2cadb37abc3bbdc9ec01aff65991dc8a2d8fd8d49a04632c4be5a50f50a823671232e7008503fb4dc0377813000e8f74695381e54d154da5b891b48d135b3d5b61a0d106605dd0e21fa405a0ff208bf84eae2d6bf4132bf4445473a9473a3091ff86d3c1ba734c4b7890eec7d134c4a83e87f818a457b88b8da374ad110d1ec80236fec0c087d5e9a8a2fbc4221ec8f898314626387ff65837fe2727dd37f1b1f755951c66fda0207600698d467546f4071741e809d67542d3edba8c238911a73f64590f1e1e4e4dc642093cff7568fad0df9128544c2ccb9653ffc64011ced45ed855b0ae2852e3d3181c1c1e2cb58d2cd7af7d4f00a993b7587eff48500be3af179e7844e969e123aab3a32b5799b48f99c0ca6a7510dfce9e0679ebeedfc164bd1a56024564c14f81c81855bd519b42cf04e11255802780cb6258d87248ee3ee5c5f197218cd07b7af7618afcbba080acafadf492c70fad2e682d7f23135fae38ab6ead387d2ac8f7fbf1e5e71ad6b5fbd4f272a2af1e7378e25a99a2f343baf4637ac9333aed06b470b998ba9c8adf7904c6e71745700bcae8031ff18ef0c53c830235927eaa3a6bdf07b86166e8f5c01f8ff2cc7eb88efb50f28d7313b8be0931cfb940a0c5515635b55346882233ddd254bbac7000aee373c3b773ca50fb68c8dc4294f1741fa3f2bfa6e4beaf803f7b4550e5938f17c25538bbca0f21bc885995146a5564ba560d050e7b6bb1bb40d1fbc549328b47016938de00148792d6f48be26d2f8801e53533c338e0ce93be3427c6213a4507bd01bb9203ad6c2d97662e65bdeb76a89f1a0598c4880af365f50d53a651bf2c531fe009ff6f480aad76f4d58abb8f022c1676b5da7825e908136d288fbc0c954197f2cdb268b414a9bc1f34082b7af971b5999291149cd6318be0af50950a9dd35ba7f85c63430e227d0222c84301480be87fdbc57c247f62e3b5ce21e3ccc5f8d5d32e205d46ce81cd275cc9e4f082bd132954f0c94591fa280e26fbd0beb73ef6ff37aae5acad41efa4c643ff790e0b56d05c277011acccfe0839270c015bf9cf80f946863afda32688243a206c4f698e5c88f428afcad7ec9f60ad17ef711f6d61fd048c25eead90fcef1f4789c4bc4863eb97e0bb9833cadd9ea2ffcc5a45a49b760f4803a6a0e0107ac9a7cf23370a0658832db0ddb914f339a1caeb9cd516bcd75462d2d96ecaae431547affdf04dfccf003f6c784e87ae6ee31884ecc99d6ea332fe4488f72659e0db23868ba8e1901ac37f88b10cbb1fb5b51767a402e40950dc387c9f701dadc89d3505ebc70a994ff1fe5c1e7be076f884239b7883235d87c9778655190aed1a4c14e8b939bcd5890ffd44e2ab0ed8c9cc01dca669448f6588eb790696ad3e397ea6426e8aead32d7da32e54ab572531fbd7f39fd48617ada910f1c7122d21f9c952acbb51387c13c2f522b629968261be8497136feed2973feda54b5e1fb9a571378147b824ec7451c999d3f2ac582553e0492d9fcad5a12591bf6c40e40e843023a982d63faaa91a5e5553cc05ef9b517732df5179e7810c10eeba1269fcb2acd55f78c8d703491f5e2342ccc1b58e42a775a7bee40a706423243304b45794eb5ccf550f4cfdf06bdd5e1e41f98e8911f81adbdd68b3569831a30dfdd072851775f0f7031e14f89ed083f8a8334c2c6fb34b17f6f9b7c6c67835a12e5aa890c4e6826993d067428a8f60ef8ad030739b7fd865d023f21415f3a741c8b42cf3ee80670df9b3f00c3b6d83e86f48d0af8f43ef249b38674a024e7a5f74733be4d2c62a6c43204c0ade1ba9a5fa5b3ff3975ab7c4823a74d8c7ad3c2d08bd19391b520316d15c456a76a9285bb3c867a481a0aec898b4735f3b70dc550aee9cca19fa94269c9b898667ec22ba47a850993257b4a94bc5ec3d895dddbb44e2c74a167d6ba707d7af18ffd264c15589bb31751400a2da30d92239001b7b651616324b37ab99c16a4c00060481bc16e290e6f967854712e5c69c28640d7f0d8c5b5184b4a04f9cc2071a9014e9829a9116b63a389888fe582ccbc706f2280119ebe199a0242126bc056ff78c0e6807ebec489b86a5afb8347bd4442ecbe4efedeabdd2766b4d5295796f9bb5799988beab20e8015d3912460d7465a512a812e47effc090efb6a22b09b10d20b2123b256921dcc0a0f9932ace570d138bb5295e583fc35ed817e99f20af681d73d379f56a1a01489e53bcd3b1bcc63d43d152f0b8605448585a63650bdd5a3852a2972b29fda1271fdbe22323b05508bb3f6d5c272c1815385c8e94a0b1a0f2f69aebb44c1e60c854877200de81d079c0527dff955503b51af4c19ade9bc8f006efda7cc5e3ccd7b4b1c6a305ba08db9f0bcadbef3df2cf0506dade03e719cfdf317e5652c05e9e2b4cf78512a557e71f4684a450a21e41078218e081ec618a74a48018f784eaa873935c95a512bde959f22ef4f11e97afec5fcb40c3bd621a503f6918d17095b10ef285411acacaae7284a5a3b69fdd18a77758549f0a1c63a1f2c63372eeb7124868fb4df1922f65ef3d2b43f411bac190518f3b7010cc901dc114ffc94f92995411d731ae758a48e6649a06a8aa6692ad9289bc659715b56dc024a1c613f2f853b20580dd722c07391fc9adb72a7229345b5e754bf2cb03545b654ab908e28ed8b72eaf69d9c9418e99dbac1bcef06c1558536fb92a52cd139578ba4b1b141c8870f5c8cf212a1abb8329090292fba60abbc4cd85b5a5d412556daa84d74090dfdefd26bb056eb3a4084e57c6dbf4dae0610b1be1e0a79831e700be0d58ae96b6c27645b8aab24fe3caab30a03b6af17267c9970b3c2b1fa16a1b3b6d0485467c6e6b75755658dc9805302c4d9c8438a8418d7fd0f18e1c21c51885101cd549f6d61d410368ab68a005db029d3e70159d0b4f4b0f258b083e5d0e0486184f58be182d8832cf145d14fd842b697034e5b2c12709dcd22514faa9b014aca4246557ebfa73c02c92102b67d96bdd3a986bd5df291661487123ed12054f5a2c3c7064a116e2b8c907edfa4981ac4286a1dbae2d504273e51d3c41205baad4ba98217364701e085bdfeb59325ab68bbb5fd6173a6b80b4114ad63d188f04a1069089c12c092c6dea5abd028d266c8ddd9cb59d32679ddb5024de70b10a772a4c32e789013a766af3b8fa7e7b62af719641a3ca52c16872a8372319ae0cfdf01f521b184c0ba1c35f9710531d7b610c27db4bf710c469a5191121236dd4a5e39c4d584abbeb947ec263510cad32808aef67cb904e77eae7652ce5fa65f6c5bd30450677c20c5b7d181e16a044ed7a712f4b82a1c44363ab587a049ac7a6aaddb37b51baa89b5347b7403050fa90f3ef211415157bec92a385209c8a3a5b28ab7331c1266cbe00dc1b24c68df04d4a6d95c2c080ef4ec2a5f24207b6e55e8b4dbbb8b40c61d9d9b63b16603fdf49bdf564e27866340cf30af5b3626369612250c37b51f0037fd72cd12dbd7f9d106e91f16af44df18e767e25b9c8d23aceefc8355a96740abd36c644dfb3faa0983cc5d3ec52bbe629301af5dfd15390514c0e5eff2080daaa22dbb6b04bef24105819eaef5280ca9de7d88488d9f7394e92073f0203a002771268c666735c1956525dc1a12b7c50751167a5ec9cc6a4cf25a5060ca579822ccec1259518a67821ae35ede1ace053427c1302e0cb5f4dd13171561d0296290d91712d857f1902aa84e311ad5070e806245e217c5fd5a1aa95cfa42f58accaba5a48c61440ba3daecf44afb2b15522b41314d82a4a1dc860213d6fa05bb00096808795b9ac55ce7188f8514001f6d0d6431d88160b7daa963fc4a1be434613ad1d6ed1ea484b1a2c6aa38a72b24b0165042d4f12b881577eb91f5a34818f09f8f7fc225902e058e5cf89906f844cb44a84e26dac457d74410210623693c1dc9dd5d6dfae01b41f9789705940b37f27531aac89b7a014bbac4b4e1b48f0af99a2dc513dae6d13549754fdb9334fe10669330fc78669b9597823f04354c4b366c0eb93658292f88d034fbac561b9547f9e8b5915a08c95dfd3edec9d598be98288f6ac92cc2554c3a3059c547a5d095e4792c28e045c8e91da716501e4a28aa1e124ba03439f6af9f31a096a88aa63a7630468f8ba05191ee9aafb5449eb4be19091fbfbf5a5dc42ff62c203fd8b5387caccdea246b2fccaf97fe51c232984013681ec0108f5bd00463e1b21ab052fd9d5dcb1759e44be8b280c283a76811a08ab146ea5561a76f9cec0cc369715ed86598e3da81e772d70d2cae6880428256082d67342e1653eb4a95d352ae2f7240f97738eff9747c2822ef19a40f4f0922118d9d9b8689f6d20d104b2034a968efa0fc9a58a00d0d421b008e0ac3737c4a07c1ad0c138135013030c17fc4390fbb2cffb9b8dd2de25ecdb89c24d5b94c39b2f16164b145e6583aa76616b79b085b6effc249ab7f7126cef4c06f841f982a2113c2e370bb024d39a90587c52e7b9c8bec24ce8c2a3cda14e556c3ed16c9f1219b225a27e45e19ffc098c12142104e38accd84d0273bec6a74ce111777245e35871aafdca1be13941a86b9e45349e0ea1580ccbfdb3f3bbd9e68e7712c063b6a4e79ca7fdff420610e1fc8e854625026d4cfb23f2621bf54bba2219ba31d0fec9ef41712042c39d62bfe42c95e0ce25fefa69ea5ebf4dddcfef837f7bc0e4dc850cbfdaaad3b45c121ca4edf7cb82bc98e056b0d0d1822200d252e88384d11ea307c62b6b30c54d5180cefcf9732775d59ded3dab09f8ec81825002e15416abce455078453d08d7753901c185cdf8eaf6f8d7466d0beaf83424c7a79bd28b78633b458175564715b1126c5af8b2eb6fe99d60067cbb03298b66562ee06e82a8f8798a2ee662a72df7cde0bb94dd408fd90443097321ee49a6f8920be8a884843ac702abb8c690a85ba4a891b80a4a463036e15f50ade8a47be6019f438c083b5e631cd67c150b784580a02bcba9d442569da632db2a1a02176bd2d42102f15243eb57f5ef2dcd4d15641836ca8751f159e5e3f8befa49340cc27e66c7d53053c005d70df3317e5760a0a195f823d4163a984503493b64327300edc29abd3037e63656a9a7e70834c8cc92fabe1b3e0a9f908210181c448e3824cc649043941bdaa3de1c595ab14587f587899fc8d008216df2c10e979759322dd7f5c14220e97d4f2e5bf3c54955ac8517aa80d340acbb8318f82714681d68e17cb51d2e08548638a5c84ed4388d582a196e93a7fe9bfd1d23bc7f9a752407508cc485b1febdfe487c5856e7170f41b36c817f6c922fc7dbc0b5aa03192eba184a01a159acf7fe2affdbbe1c0c183d536ed1485bfeb8d14f1cfd81c139b7a3f6d5821944da9ac9d62664cec9d8486be8d7794480b4def418694d65f0d1a85176eb19ff0cc1b3a5f4695a7b54e34ab8da7e2b3422b35b19d5b074868e601e14b0ced83093a15cd1d1d7290c8bc0d8b8c52360b715592e34f403f5236e9ccc219ef9a85ceb6637e8aa889e024aa60f9f853c963ff396f20475bde40f3eb82d7b9561cc1a899920705903943828a1373131837d2fed5dcab43e26fa89531f8c3fec33d0618769ccd556f027432bdf375e037df1e709ce3fdcadb905434333601d4e77153f19dfa8018f9dc13a28f033b0f938b4cf4cf10b21e5a92d8bca7b1d73aa6aeb8e7919cb7af258a8c0d7a0a9127b4af4c350b2619d79bebf28b0101448d74fc179edbe2c9ea21d318b436e789f4e658c16a03e52a53accf60b7c8913fd8211fdbc3164c4811c80e1677a18784be18ac962dcc79c3aa2db9bea074c243d4c5d7724d4cbc5e44587e7ea772394aa01140a2191be695aa05e0d6cccc15a3ee1def279fe2fd3d5ef7dca774ffd112e4a1abb315e5b3cfedf32073b9c78e63ad400014429064bd274272fd91c675526ae1b46839e5b3425805e3a61921e6c8fa90de46229f03414b8607204f679751bab5a7e944a7aadf0bc5d35f9546daa029af1cc4135e1e60a0149bdad4527a8d0e97524f430f6e287212abb69f952ba15807811db36313ab00e7d28960b6fade2c417ee1fb8022cf381a358057ee010fa205e095a9f06e26dac320e2b83321a2ae228e979f5b72a0c533d352c5ca83daf3ac9a2cf494fe2c602a6dce0bbba40c23e98abc2e7d3ac628b9302877349a129a440bc18754e0517b80bc52208d09c85075dff8c2e34eadf60701b58d7670c793b35db5b26ea3ca0b5d6bc3443ade064571c33f472b48dcba79f634ff2d9a78c937a7f3eece0c9c44418e826b6d4f793485cd79ba51198b886070d7ac7b6f3290251a5912baf62b426d5a4f323b3213969b77bcfe7bda87dfb878f88bc16dea05e7253fa4a4c1e14a759d2680353cbba0e8e50be696e4018e203b998138400b70f909395742af9911c248e309a03149fd932f6c6f0f2d6ae16eca2f23802a45ff429e7e922f0dc4ea3db9f2f73ddd975507334b46670cb02d3eace0cf93542e3afd40f8969867705e681f6968ef314c2d6e389300abd6ff82e0310e1c993dce44ffe5ec3ca1b0b5447fa71853d60e7a56e033f44a150cac479e57b2482fc274b0a05544b582297c2a527a75e42b4543168e75ad96cb6b824d9a19cf22d1468c61b72b049e2df8178bd3e833799974fdae30bbcc9a7d5ea2558d8d5cb815f3b04e4f35e0b6591a889a2c494a1122846ea9692836d0eeacd25a905b0d68afcb7d444eff1cfb81bd7782a8c20611ab7a4e41ce1b9f30d2390cffb21d75eee24e6f8bcee82412e52f61b21fc569b7f3a17dbb97b4c5daa59f3590d34f1597ced42a41c24b90ddcab646dd1ad759c650571225ad89d69d763870dba1307ad75058721a0a871ecb04cddd0105b96abbd4e53440258351871a41cc9254ba79ac81d436b0af77b468038629808a963f5582dab8ef55d1c60c78ad3223646f2be49eae40c196e6e64adca43dfb16a3ffdbb659663d34c4651c51c335990a5a78d1bd9df15d90053ecdd1d8346d1bb00225f3cc531d4181bc8362f0f8be2b2935259fae58dd972665ceeab8dd3ac6153b41e21ad1f2e22a84fafbe3ec9efb593ceaa959b13039acfc33c38438953a67b78647c75824cedd84a346c53734caec92bc81c304d063aa16abd99b47bd1b394a0e5f64b321cdecd663c70b7572f0e0f5dcf3cebbf927ddc4cbb10abbad8033db244e0fa26a36c3e8665181b63361df2c23cb473fdcec0df7e0baeb0c46e426220a2b638b9e4a1633628c0dacfa641172ed80db384751ce3d0aa8064f840d64a4d16cf185066fe07c46e56d992db667272f69ce5a9f253ddcbc51aabf20296247e9d6f7778584de4a94d3d1971d4f0499545bc7d770f5ed6109e3851a74b56551c1cc5e66f4391355a7c46894acd00aed1449d4a44e60b7ce737034e819ea5e3a2d00318340a0f21600e7a0da0800382186e204e311623d81b99c9cf0f67e3fc107c79d758355fbc0f79240f451fb1e3b2c7b89a4ee7106766ce45184dd1f468d81ea69f5742c7ebe69931e99f2f79ea461108df091fd2c5ff942b0efff41177eee511fe9b146b30e4ad64385400a4e8e34f70075fcdb411459fdf2f61f6bda7d88ab057c974febcafdfda88793b14d53f0b7da900d70fa83a58d430580b6d35e8fb9966ee09d2ecc0f4df50bdd55dd406389674c2c8979a17527a70746ae185669ef224cd3aa17adbd576741634f185e695ad4933d6f8019b937bcc00d1126a5148482b646c3be54feef6565b929b8338eb54358027476b643c29236033a00676740b3debbbaa14dcdb40f75267e24dba38cca4650e9522e96cd146388ecec6f0e9cade0ca26abf4e943f0acfe4700ee38c0c292cedac00a84c4d78da0a1cb5da92b9ce09983b9bc83eac518dd7e29f23968e0b2afd924ebfa8774fdce314634fb830692443eee4b2e727474e4e65008e0b12b4d1f307ff135d8f31df277c6796e85f3bc4057dab665588f94d94c01c3d2278ce0fe31c7226c2e06fd5ea4edb008b897938a3b8a70313e16c215de2638857468c76d4804b4e3aadd00b8755f826b5a3aac350a7fbc8138e0673e0e76cde780ee05a4b837a16b4071b0870d83ec197721af033c7007ba2a48f89ed981dadfbda795a6a8d736e2aac4804070a42cf1e6bd6eb303053a5e0f0a8e276d45902252d5cd4dae7c5dbf39e9221249de65ddfa247a4aa1f69c167b4a3f141d6f6fa73fc19b08a3480956bac18790c35cad0e8e92e4fb72a405a8342ebd079eb6a7edd87dd4754f7be06cff00c182aaddd26611f12282be58fab716f759f8eb410bdb88c68edaec07460a58ede0a3aeaca53454c13a6850c938eec2faa02a5704428a00c3a1671e5d7d42d0e4f6b2e67e36b931574988d9e432c908b1861c8c86a79d86eaf5b7cff15c4abe0cf670d30b7272b112cf3f964ad4b07830d8a1dca0aff227d05053412c371b435ba7af31c2126476579a5d141b5f23a79e36a0207f2e5995292da2921433737b74426b1cd1ad37f142de1e48475075049acd98cdc9df8c3dce187d501c0e7fb22d57656cc33c6858538a156dbf24ceda25ae0b6af456bd7d964bccd1dcd9e5b7ad70b0f4adc02e378c2202f435ed3a3f7da6a3c5b12f8245bf6f0ff634fe0f1956cf00941fd94825a9305441168b7d1f1f1d30e0d1e0b76e0d6a7fb400b89138e8aa8304440090f590b63400e2bde94289e8f8e8a5828a1123f8340db955632ef7bdf4c3dbad4a3380096026c897c3b15fc67e58320f307e518bdc70f29371399c6e441c71b65b074257139ce2b6983f0bd1007a9c74545fdae44eb3fc24a41301f75d48eb3912feb3cc9d033f11e2749fcae8e91e3ed05e7fb0d9669fd23a01569ab54b884edc07fb88a03a0ec1580f2712590929eb7789eda91c49b57e64d3e54fbd778c74a371657e38cf4aeffe579c7e32b31b04d4fa7e994a0eed280df53033ef8d21d60b8517d40ba09097afd3057146a9a7108d1d5494f96b387a6a76bc1944b23f2773df55c07916c3f4710892a2a0ebf0ce4719bcc373d31a0e068013552b0f7075b6eff5980bba3ac25d2c5f98d12948bf63be280cf14dc01d58d22885c2b8abc51cae97c064bcf84350b52dbabfd6471048f54307114f2c98d33230446726b8850aff7ce2b0b41447c757d196f20ca0d3a9139fcc2e2d536c8f8c5101226c288dcfe4b5108e8611f06e2165d1b512e02746426ca8d66c87fd2dc44a1d96ddec9c4c4a2d6ac790ea77c1ed6ea2f481c37b70d6d27bd7fa298e0a8e73343183f85a416e0ee44d9675ec6c1283db0447527a9383ca2629a05498ff913899569edfee763ebcc5b2ac8def28665e63a936176cb1876e640e58d66a312aff98b6af460f91cd739eafa53e825c87720814d9c8d0eabeef12feafd29e6f12a28c43f39f5632890790924871da6f0b2603a7ecb6d49e01865a7e6e37a639be29bf4a428f46aea3934bb82f6aa0d2f4524aa8b5d1f5111bd4fc2f6a34dd494e7a19cac0bbb6beada9be9cff25c92036b9c865cc252c72c2c68fe2a340fd0b3bd02408babd7f2e043496c4c1e157bbf1c7bb0f904c5759fe8b1e34bd65a24dd6c53a2c0fe2114dac0a6598195292c0ce49249a108611c052205c417100612a6d418224723222617267cc752288880a406872a7b019009369a20a2959f842008bc6e7701fc5b81365384ac018ee8990918ec208adf14f0430816555437ffb809bc2d337f6d5657e586fabb953603fcd0b507f57c94bd14ea7fde7966994258ed4a84d20a5102ef51a39afcb7bfa0bc2143db8e2f7913b2b21a2b1c985c63522b16786ce2f03651f35d79087349025683f6f4b9eff3a170902994176ea1eee284d124ec7e0a710d51342bdd1c181a56a0cbdd165f9c3eb2572c83425b343f701207b68b883de259c869ccc601d0e73ef56d76f7496ee073410690c23b6ed325694c1eb437e90424af4586a84a87be4910fe0eed07c4794b50b0ed3927d68d74501b2d1162a6483416bcb14f6f85d393647633d0f3c6c8ea1c5f17376cebd1e762076c97bd43d66e1bf9d212705a5149854232202a3d9a38bd1d3952e9e2400be1d96f7cedb2af84b2f2a9e971daaf63a38b96865cfe04a75296ffa7a6a5d8aaebdb0dc550145b93814459964264c83eb58aa3a58b676ecc2e38bb3e30f02c15dce879363fa86d8faf69b52af83ab70a4ae4a31d3abdaadaeb0f9da450121d19fdf3509027f47e01d33a66ea1f970bedea7294113228a907cef206068fa48a6e00f89f795cd1f1879114b1137effb28788799073198b4179ec84db5880870bc5d36da34fd8e7420821ba73da895a8136a017b35235ee5253afe3b1b638819cc67965bab711d7d2e70a5bc0e45bf0d4ba96b6e7d42a99407f2a4215edd164ae38e2358902c6eb0572b69be44d855f168e19d84a56eb7706fc5a1bfd3a6f340dc40c3d00450b36a8e21174343e58252de017884f1ea8406e45ed71c5216a65a5f2393a9615b1529fbab84f8d794cea865d3998a8aeafe06929eaee487ac2ed2f6944f066fbffa186a328cb8a26f146a2fb10144cb7965ad010116d0b09520148c1da454d9119474165715187f467f0832b8443147d52a4ec45b27596cf67a596c79c121760b866ab989a6a873aea307136a3f6dfcc61e0eb120299373711a5e1f9bab6573a4c7c4ef0b39372642ef768b2d8280c52c68ad0a5b6a0c386c86852ec5f749a12c53b516b107b61d69e5551048ac9b921113d10b7200fa1ee3afdaa8fe750639b60ee2b62c37483dd90f0486ff0856c38493c281cc08a28de2ecd58b09f3b30a91e402173bddbc955523a499927e3a73af96d2a20ba95fc53cd8d40ddb060ea055e04319de4200f323339f14127c687d003cfc1747686bfd39452a1ffea23bfe53341ae754e5bd9d8a1828b2ea146377b0952b2b89ac54aeb3b9da4d29bba3f8e6704aa67c365cc1f1339bfad5edf819eccba82cb7bec6ffcc21f695de61f2160d9c0d9b98f44dde66811dcf51b4cd8fc52c7e27a54d3043aa43ddf784dd0cbdeb873fb053518371ef0221a0d7c97501640ade7c0382aa6f9a4c18af7870368be120d719f65adcf6447f06ff04b2bbb167e8402b2cf5666705b2555cb2943a346b72865f32583700fe72057facbd092f6625363e0e4faa0fde8fe7769bbefa8767f59a142973ce1b610ae2f227884cd2f5e289a07d93019d71789d681b175afcff7f2100fc92e6b953a06adc826a9a893dc2c50521fd73c4f0a65a81298918b1287e73e2aa69ced155ab1269f352867465402ea8c36361358598d03011768b6825f32909eb25327b1f542974e28aed5c5699cd00bdf4bf8c1897afc217f335eb9e46deb5a5445dddb645a1f4c05ae338588c693b6ae74094aab9b0dbb1c75fbaff94be9b214164343384ab6246dac508158a906c8768961a6478465134e05708c8bc9353a1599d4c6952314fd011b35f1750a6a3f0eb849754cc133443d478026f8e1708d9a07d64d6aeb2248cd93ba4e21451f8aeb13488e9736593ba074cd11c27060e51959b5dcdbed415a8b28ee08355587b1ee80d7918df41081c62a754b379000dc610d8d79552e4136586e56e6abf6a0e5f8afed73fdfc1d4d57f58073c051a871daeadc140e70a44dab8f7a0278ada4235331b849c229d94573d5d44e521fe6a712c25bca8ef25baaba6271672f51278ee5756aaddc8716b0a3ac8d7577863851356a9c5b5762c077fab9a7705a1d3bf8c5c742c28360be5d1488efe441b04f48cce67cf44bfa556a1cb15da43cb06a54a1fd15ad464446edca21a3eb280845a642493b4e0841406c1725229438ffe89f1e42293047e27709b916dd16b6d4928c2ef2f960bf411074f1cbead8a65023985ff11eb840760848427bca7b12d4f4c2bb9ff57abaa7e901d46899b57ccfc86fc0b7eda3bd2aa253025c276c41007f081e962faa032319e7ff5c1d45af7b1942f0258fa09587c14e41a5bacf8247d93cc2c93f8bd7c36ba89aa080f088e8d8de75fe183ae603603a183841f8e7a3f28901c1911b1a2ea885f140e4afc1957290a38118aa1188faa7733ac22a40b21f89e3e5b8e2fd263af3eef8a605695014effc9001a6f0de07462052a601b920c0272b7414928626a2bffd7bfec1415eca889d820b7f4f882a0d688fa894720a61fbb51daa8f05127eefad29f8cb55edd1abd14f3c1d1e44577e9b5ca149c3908fa81a3331e7e734e2b770b8bfe1b23401695fdaddc1686ee6672d2ebf43e2742ed03af0a280945de2880a13b3307a2f34603dea01fa530000901a6f29dd3d5793f7d9b14118a9422a855cbe972c9b726adc0d754c0f8259c04922cd771c2d0c6d6ffcca65ffc67ff61dcdaef19fd1c519e323e493a586b22838c20d0ade18d66201a1ca1b34f966770b893b113b45a3578f7f037aaa859d65d1528a4a4a44563b1348f5a015220eaa319936f7601ba1750c09d348292cf3ef8448c20acdb25345ec970d3ef3d7caaff6f30b7c522022f4a848019a9fa16375ce5f0996139579cd984bc38fc541e889d70f7a2f7ecc52314e00f40461c4db3e49b9fa34af3e5568ea067df5e80268016a8f7b27e9e11dcdcf629d027b48fa04ea579c2c246f5f5e4801e0d4a8ab87ce45d6a539797fd87c889293cdb6050e1dfa8a8ca66e5ac38bc73af490febba73f392000777485f67afc9fedec3bd94f1353b5b665510de716e19e27c25964c2a938320956d54c4fab34628b7d42f9fbef8a344d7ccb2cd3e35855e8d2d5aeabffd1e1ddaa19d97796816a9d07c655b555e09696161c7adcffa7afb90bd213d793930984fc83ce5f6ddf9b6c2f7345546a42f4e225b0fa9f3b7ba54fa523a9ac7733dea907649310b5b21ffd258dfafef57f30b3a84ab9ec4654ffda0fd5d1a2b92ececa265335863d402b8cb153634d726341d3b31a2dc1db7e5538cce76031da5af8f01244db702084a7ca68777353c9fc47dc1b5680d1de0365e7b2af7fa43caa4cf8d50225da7a2d9288528581327774e4d49633fb1fb9b5d5b543f0d7e154f00c48050ceb7cbccfacdcf617c63a38f5202dfd11d7b7b27f6234e14bdf92e746fecf3bc5ea437db2a4a612216f09854065b11868fa3b82f691c5709de3e8d7c1225c313d7f1847b3c2abbc2768a08b93443619d3ef88f96c54e0dc53d8382bd84899cfd2ebbd32b95a42b434d2af43b0bdb7cf8c5655b5f9658c1535cb62ce6dd061749ca5055a6b24436687b7b04929d85f06f8af70d25b309ba0e3f608883ea538c41079d61fdae854b26c8a167c99b56bae587b22efefe7bf456478c0a90c4deba949bceb38671d8e77d071f64acfddb870842fd9daa043c120d41d7a91a67953584c0eb0a980e3f8a2e0bbe74fe8c5ae1a09a50acc1473c990d4513b9657203c0635a77bad0c91fbee9c07a56d64c4da129c2fa105110c422c75925fc31c66516f023e71df978db5d7db1328a2ef257aa1920b3a676f7f725ca4fcac5d9214276bb767e1c5fd690e907591711e0ee8fbec8e28ac87e8d877c5a72fa57b7403f8c38276c02d1b4a0e6d73b0e9c2ccc4f5712255b601bcdb1a69f5ebd9f9ba01438f1e2658faffd3cf1f1782c256bc207aa236ef07e09669865078534464536f02d932ea2b9f17b35aaa6912348d74e65614b1a6c70f62203d6ff04e6444070592ed5b78fa0a39f4a4a064a26cf8554f6ea585b5f9756d012e4701746aa7d76a01eeea6b8a30cd37783251d5d35f7016acb7bc138ae77f63a1f1e09357fae0e4ecd05f0b14604e84622bde5cf710f425f22caabc29420c2b1b9e0f4fae5aba3211c0bcf04840fb9f1047c1eb8093810809b521cc69daf9f02c1229258aa410e774b038b52ba88962b6e6bc77c1cee02da87268e88c046c664e210e103db4f59d7cac68cd562ab1462a379f4a076961fcd16d1cccfbaddb58165c6be1790dc29b14c414f3466c5b8b2a58cbad63125b838a4319e077493134b931aef34e2ea66f61247a0705be162f342f893d95b9aba95ffa3e2d6ca582b6eb939972f55997c4c946e5617fb46f92a6605272667fa28559343f9ce21d195920421904c138a6c904e006d52372d69ed4c1ba67ac0278cfb4d936412529c76a9802d86099de8824ae6288282178ff6afe37327c06669c71ca0c91cecdf9b5a3931abad1667c6575cc276c04ab4eccea7f7396d63e1fe5b77616329e406ff6863153823eeed606ad9389aeb73143bacef9175a00ce7e39fc2b5d0ad6125fd95f2584a2c74618b3660489e759956e5af7669853dc3ac6a28429a44aee246f2fd2f78b5cd3514fa257ca9d9c9a11fb75e34c56cfc7714707add3f881eb31dee8f22da9b847cbddaf691892bfb6debed9b75962b92d336e0389dd4ecf2325d4fa035adb2a935920d032930ec46212175c0749db10bd930a96f85e5e0f981f3e1f3085191e325ea7b301be97c42f7a4b11cdcd29ef05e07250805073aaee09c74707f04725166ea4a9630aabadd9b733f0bdc4828f24217b6fb2e5de52ca9464380918093a099af676be8f74b396bee526a77255d79df7ffd6ae5ee2341996653b557778a5a5043a744f94be3892a85c90e4a1b103f7c45257c5c82a29a99810626b013706103d682d58b263d490a43e31b54de5409f28d2ce60fae2c8084f9c7018c189a217e030421353ad296bc410839a86143190a82206241b0d628861090c6af00003152650c8000312150f3ae5800ddab728a8f62a3105e629099ba72a620881fd6910c696d717e44a3c2b601c19c17082fdc13072c0feaebf77ac312ab158b2c1ab355f90e7f882687fd144059e0fda24289a2fc8a98f075d7c91039e7fc12c4ee0f9335fd07c777757e207ec17bbbbbbcb7c414e3d9054b224f1620a3cbfe5d44117319c6f747a40b1f284e5ca1357ae60ffc78204f61fbdb801fbe7c48062be206fc2abbcae4ca1f2822faa1c5539a28ba2a62ebe80c11330e8c20a1254a460f50202152578fefd82e616f04a942d9690b2c51b5c7481fd59f74e0dc134ebc10c365450c414614a8724533cb57184946ccea97191c464ce39e7ea0b9ad96bdd603104167160ff9bc515ec0f3a2161ff9701fb8f5a8091c3056c4da9827d8b2b8ab8a20deca04c19292081110b8cce285ae30a2b5af0030b66479c685b90c0eb971e3aa740c1f32fc805cfbf57c6a81629a4b076b8b9d56ad933df5e2b96b082060c4af104fb6f56a42019b17bd114033b850537a8a86aca89a54988a62398aac0f3e7fb20441c6d38c5d186ab10731928e102ec8f80d8e469b562fd2790d0026d80e7d3f96d8568bda2485501c4184711d4c51c6c5cf932545c39fddba9383a4cca2b1f94728ba7d76b528a375677e2ea6fcb7ec70122b8fb0bb22d76df3d2bfcb19df4cfa70609d335a0d5fb73e210eec2ece1ee57abe7bcff1ec887f0170e71ec89eda47570df85d906730f34554a98e2fe5a4927d6838b7d8b60ebfa187365d5da16ad5ba0ef43b876325037a6c8ed8f99e1b6d014e5094b2c58364529829ba8e882a927f3c3b53237dc6f31b930dfff36e3f7df9797b2961debaf749e8f01447ef8d8268c00e710cc6957b259620babb005be42f9c3c7165fe2f4c764b95942750671cb28dc2f37bf30310df2a3051194dc87d274e85c32a2ccb7be250ac93ccd0f7d63c8845aa22b85d6ca06208021a3f9219a1f92c92266fefe26e66043860a7a67c41f0ea30fe4620b39deb82d13ba6644999f81f921592b74a5d0fa988f11855e68c8845a0f233671bdcc884d642f70bc84f6869e1bd73fc70d36995068c7490f32901111e18836a26434df0a853e1f644462cc90d1884da6f57e25668b5731456e67a3c485f998db6af98faff532392f39aefb99504ad8b63d953bacdf582fa1f45126cc09250a2d1c6ecea11a270e716dbb415862ceecb2fede3027f6c3c797d0568dfbedef775ba8ca89e5e8c47ca4f73731b7e02375c1dd7e04e9fee56f98a910defe4504f29ee1b3c255f8859f7d2f1ce278aac22139b11682f88e0cd2c20f1fe98ba0040ad307a24f02fd1cfa31fa31218cd4cabf1674620e36ae8e0cb59fa1d60d998d6b684b706cc5cd07c09a3876b93fc4b18c99baad229934ae7c192657ead0499b4e7a4f50ce2a6bfd82b6eea9b5dddec77c31fb7f407bc588d1c2944ab976deeac43fa0add5faabfe95a63dc5dd071f7ccbcad7b39aae86dc4bdfb1bf7a6a57331fdb68f52bb1ce7cc70a739ab8ac9f79f9f96089d29b0933f5617fc8488cfb7d6b56594f5a4c6eeea49f57eb98aff2e06dc29fdf4fbe23fefc86923efd2f25005eca57f772be9ce06cbdf41d98673db9b9937e8260cf3c6fbe5703be9c5f1697f5abcf2d64baa43a780b7e370c73e3f0c530b35efc97ca46cc8e55ef81981d8b611876966e3e88bbef40cc2000440ec4e9b2a0982f8d98ef8c9841993cbe8879c45dafd8501267b6ac8fbefac24c716e51e918649f61f6c1265a4f5a624a529a89eeadd1491bafb25fa374524f08ed9cce7a3eb4a759081e42a71c1beb9860c51b31c7c41c1f1df790383506885b5f2c817e8b417ceca7172cdf46895ba42826b34f8395152942c3cbead39023d37efb2232741cb226f369b0324b1fe4ee0c3783f4675e200375f305250e7d1be690304a801c62ba23832045c81f60fa302e7bae6212873e9ddfee6474d2a69345dd4248d8acde8bcbedb05455ea0dc5d2d2142b50547081e294e5298a8b149e4f5dab4a4c949e58dc33899b1b57252bd2e78adc017d7442f2bc2b39b93c0b3d923873723fdf97a63b75cb09dbc41f13c672dabccf558c59ba2f6edcece1f94a4b4a3ece239a4495e8114552fafa5d59f07cbf22c7f9ee848449279e263c5d0a3c3f8f78b6e85624cefcdbea25ee8b96c1e1ca97d9e1ca972fd374e577364a5cfa9aadd4ad1297a88bba67d2ed386172c268b8c20c577e1e8f9c8d4eb5b444cef9203871db874eda647a84eb77b27b71b934a86a1486ee092c9ba058c18d8f9c0aa41c5d687ab8f5ddc895d4235c5b02b911d78b7c1cebb7c0b8d98deafcda4748ae247d24ae2d246e6e6922b559e2dadfeaefa0e1b6ec84892e94c072c22d1feb97c072c2fe391356819cc3d2c8c59829de0b1c37b7b62940dcec452c96af1493e5662f52c4bd48c3f21bc9c7fae2722b2d617e2b99583e88ab918f9512d11935a244b48808ce21906d579ae846b81a71b98d9b1ed91fbafe996509db99f334d3914c7a724467505880b32bc1734524c311383b12142457c27342c19309cf77d9d3bfa01c145cd708d282b0e4f6d3f470b3cf90f88e1be1e94b73ce1f2ff8b7d57d34df91e6bbd17c1ab6aab8d9c620dd6c59188ac499dfe10ac700f1bdf4b4a74edae4b62da99b6387bb0a85fa061b2029c958dfc9cfc12c42520b0f5c1cc958437c9c9fff27d32463e46609f5d482ba56f010874dd985e8a3ee6ea9f8018a3f11887d6d041bbbd3f3fcfdf7fd270e117272ed67d9e5051fb9979f099e485dfaf8c3a90d9287d01f3e0e1112e2638c969ba515895558210556b8f2b0e5e32a945792a08892c9ef82596ece4961eab8e8e35d2edac89ce0bebed0fa7ab6fa753ae99cd4ab47676b7775a57dd2aa6d965375dea77dabea75aa158b5615372deb4e6aefcb7c698f839994568e5a6fdb569e67b574926b6bfd4edfa667dddddda7d74a35cf52ec3edddddd77a6e65313e974ebeeeeeeee4da9ba33303a15777de7a3f5eb00f6ca51eb59ab39557195eb2a0296e73bdcd701ecdff5819c0341270295ec5422e5b4d070e56f5fdc1a2c9b5eb0450f97a60596883b33846acb0b8c9278c10c4b6e0c964d53aca1b1e0b6b06c9a020c0a86b533534ca124e649660a27d803fd04d7231fa5704fa9dabafe54a5ea547daa51f5e9bf3e9d418968d1949a539b931597f49086b23f27f623e7ad9626a59473ce6c3f88f6dbcf1226d6826c6f35cdf3a4940aa05f4d682c02b15f29f6f7a762ab05be5661a6ddfba77a0ff36dead68589e5e7ff805c06d99e03930342787b2efc4c105bd60a5f4f5cd932944082d4d7347103f5299d49c1cd8fc719275a746d40943e46f9286160b82a2c664e20b9bce73b79a83fe923c52ad1fac8899e8f9c9855ef59cf7256256eaf0a7d7b0fb9df8238778edbace52cc75465c969f577798b221021c13a45f742b6774a55e106ec7328d4b6a0777da3a1c46d05e7c0b2a98b14f6cf8aade4e3fc4d9c51136a3e31dd77229168be17cd6fa9f93d355bcab6d47cc2f3a5e6d47c9a5194080a44e2fa4bdad54e4a1fc71df73d170ea1d8ebc22c04e74f94cf8540ba211477df710fa4ff13817022105709dd7362277e12e30d6af3feef8770988570f7b6b96e6863220bc155f49744f84b4bdde8a44d9e52d5dd7fbce0d0d10ce2f8414a065548a144e6370d282ea482b881890964fe4e24e54a50293529a59452d6de4c6805501e4cf7f1fb8fee5aecb8f542955d9bd2ad583675394387db62adea5ef076f102e7d1a9e6a0c57cc1104b9a8accc462cb1b559a6801850f6ac4105eb1822850da408242a20c55942c335069571a77c1827d005836155103abb06ceae284655c8a1581657e0289379ce0b04618455099e2e4040aaa1cddf084ec5a6101910a44e2e61bdc3dfebdc82f19f0d0850cca685a03ca0c7c98011bd8f39d2560f0c27ad9dce8a481843d8d26d43082fd4735a0b07f8ed413d85fa28105f677376ea6394e39767ab0cc3dcc30d28519639c3144d3196c7039c2050a9737b07f7b1e5417505c71a5a80434500200368ab0a031c31860ec209bfd3048220616082eb8f9e6c679a8acf5bad1d952e4c5162d5150444d29238832a6b053c704fde123a533236a667736121fe957d105828ee43337a28f29cda11fa3fff447fa8a72bd9ffdbf384d2268d55699484e5799efd835845b58ee7c457945b92dbbbbdbb7551ec23f5eb0bbe8fa04d7b16ca2410db85faea81799b9912d44d85fbabbfb949d83d645b70098e8b8f8e8523e7ad4749a30ff7e8180911b346e9653d469f2b84c5403bbc0e585198be5e48ce3bf9cb24b97c9e98942b184fd9b29c7c8dd7ece1348f0d1bb2ebf0ffaf2971c2999de487cf49ed51cf14d25a55271ef33df719e7eb24444440483f477248efd5d8913f6258ea4e2e609be93b9969a301f4fa8e2cef721a5b50c91b562067fc4aceffae8e81671bdcf3d43e23b8eadd84818b07a6b99f07176b7a53cf6d2b760b859b6de5562b63053cc604b8cb1164614bba7205eca2c608a80133671489d0fe44c6143f1d1bf4e5cf2c27e27145a8a68d66ecceed2535ec48b1a8af7d2e411e2dd4cd2ccd2554105145468e2fa48e166268b9b737a96e323502ce76c6f6f66de92a1c6c8cd2d65edbdaa2589f346124b4eb47092c9e2bae1239154971c3adc5e7298bfb5bdd456248e7f4c979b6f96bc89c0721ddf21ee8d8f73b6a4d4b7d58637f1e6c677a4cae7093c54865fca89bca8a5fc7b2ae6069716f9e84b325b644d0eaec444fbea4ca40f0a2a0091d0627ab97d6b87ab34ad28717ebda25c7fe1d7119542a489f642449ad0efb8ff4ce8d7c49cedaba2cffcc8917ce646349c71723325ea50154ad7744fa17b4f14bab6135d0e90b297d1d0b2eeb39532a19675e20c969b7dd6df81213ca7d84f46ec4e67fed4c89f12f9d3a2a31b5e51eec42c4c581437cb252019125c97c4e210de81e4beff0bfe2cf8fff06f61b98e3bf786f0949e7baf28f735d7fc1e52710fd7147570cc47e741060afe2af80391708132b0bb3f0b12c7bd27275c4c14242959c7c529064ed4b1f62f384f9b21a57d1361ad890c2358d3344dd3261d1aa13d0dc9174fa46476c2b4afc9e1d2d780a6f6c2b460100d489ffada0bf19dd790192a7e08f9d60d6e4bcbeda680422079dec280b56b03d674c0dac710e1305a6e7e61edb5a58d8bb7842bf79d90eabd97ef855d3461f5bbb08926ac3aa1e03bb9a51b2a541b212e6c3496983a92cd4c71fd97206d4abc5b824bfffd0bd23cad3e0d55f0b152147880516d086ee10b0c62490b24990cd1b5b66aaf7958c813973a15c13d90a350dfda9bafdbe41f472bd4371c0d4124abc1a1716e226d6bf958bfbbbbfb0b8249c3668beb9f6dda884ba7fa5de43b8ee485731369978bd2491a0aad5ec8fbee55a1d0f7aaef565fb4ba5c896bb0441c4cb22f943299248c9081724121d57f52f37f93354644297182b868594ef3486b8ad9138a79996f8542332f24b9d0608b1559ebbb99b091de28c34876c47d6d14c786b81dd6f19dd6f7affe763356dcdc6a8d71b5cf2dbc69af7a4dccdec3fcf62d983a13fe3081a348860437bfb6ed7720b91bd0f6246c9fb37d6cfb971b37671a21db3ef6225e31dffb891904652865ad50ca3cba7d67095d263896d886398887e94f1965794ecd10aa595c6144920cd3ed9779e236086454316a25b9937a7ec4c9dd63407de54e67a3d1dd2d65b56b97be9a620c94db3f77e8a44df70611540ba95a4bdcdc4e0e83dce9263912499f9ef47574acbd1704dba999382d4894643169dc4e25e3e4e6d6a40d87544b35412561fa459852da7445a9d6b391f84e23d1aacc39e713283b14c9bc0a289e5892cd64715b4937cb284c9f529129bab98b90b44562c31f326ae6889bdb8936154c7bb410207bb4986e0c113eb4105605988ab993682389433fe68ddc464e64b4b8b935bf454fe9e656abca9d475e0a984870988bd2159ca7951cb52044a88ba0a860e7827313893e352a24c41871f338c6f01643c4ed16746638014dcfaccd6aee558a198b81a0b5e214e3f66f729bdaa4da9c734e5ae79c73cea694ceea5bdb39a737e79c533ecb0d5aaba6695563c15b686f6a4635b491a390c9b37a51f585de883515f0f672d46c56c0dbb79cdbb77d69674b9cfab8d3344dab745220f3a9a67d37e714bd6f55aba7fded392bebcefbe2491551455067df96ae7dd2faa37f489f8e85167e3ce1582c27671cff41f0dac891be90c9d3b3d95401d797237db902eed96cf69a46297dcdb66cf9633e8feae5ff50852d8789d7da1f5e55799ef63fa44f77e98f2d047d6c0551b17eabb9f27e481f57899e83c4b1bc1fd2a7eba4151a214c5df915cb26244ae4e6ee1bb574d649e974ad4ba076d50dd13e69dd6a4f3d9856ac6d7b56b80abfd0a1fc69eea00af30bd3bf79b98d7fe29530afff3d5d7dd6c1540c7f22d1348d0489bdf721b1277a9b2acc8f552afb9caa622b86d99fb4da4435082a7d67d3b4ed73b4dc4c31a5dd77f46fad9ee7bd0f7f4f1cc25ad885b971c7bd6a48c5d5ba512a5dfdaed2705a6bdfc7b4da10d61c8a05283afa43ddfc21bc8551d75f9b3bb40e7fc22e5ba90c373a292a2aaa9fbaa39e3a2a0a0f608fd1240c2b9e8c8c8cdaa8710d949b299d12c7dfb3f961546105165a186d5edfba72f338aa71411f7d6ce3e6f1ce29f5c6c80556822836b01cb180e096d302397a77fae85a4617b83bb52074b979c4de63b4d267250611a61e8552ad87793e61f72e431a6f603e615fc22e85b3d011de404b61959889cc302702a10fa4be96a9985b0abf70c77dd775620ed252b87beac3e654b9ddfbe7a325829e1433fdeaf1d8f99eefd0365a82c0e4563147915bdffb828a3009a97f419ad74ffa583f6db32a8f864c8290248eaaf3be1678bf4f5382673daa46128786f7ce240e7dc1689af612f38d3494f98242a5279386a669e83ba6629600963eca78312d1a4fe6036540106cc5c080e0cb05419005ae3e10044140eabacec5dbed3e370d57d14a9caa537368d5b4ad568d6a967a9bb7b55a177cbad65a0fe9f5023f8a9b46787e279b5ccffa38e95c652078669bc37ade77bf567d109cb817fc9597a3c9ed2ccb86354e1f2f7c5f5e606aad55d3aa56b53ae2189898971bc35a7d5e4c4c4c4c8e9596c401189df42e47910b76d2a54030d43748e1ec7948dcb62e708025176760c1c5194434f160460749d8572f57d0a44b1632221d84162f8290b1fe0b8542b0414664662663d11a5e0fdc6029e5607f2004e85071bf5f7df7de6f3c8e2e3859525abf277754df1dde29d7e952f111c97e419525e5a33fc792c29b164a0915c1128b5e76c51e2e8b2dc5bafec6d747d625f2bf45fe2c297fd6940bf3810469e1296e802a11056e11c8fc8f25c543c9cd2ca90e9236d893cece4b6fe63b948adae7c891e3b53074b97ebeab046d7e0be96aaffe829e030e5e402e33c5d55e7e0b682c86ff7960f372f2f47cfd0f8178f012d3305b243e56a3ea12c3dc58f47ac22aab0973e39aaef2abc9c0954d3820c11cfc374093f5f0f89e509b4dd8cc36df6e7a4b7cec90fabffbb0f35eecbeefa847b3c4471a241f9de2ec587d08ab17c006e3688e244e68599f61660da8322fc71237d794d00f7b98986fb2363bc2b0f7bf09bb29b0b071e7747323764eb08ec98d9a255fe35f33c577fefd6b9ca40fec6f3eb3b08af598e60520e6a7d9687e87982fa6d9baa909f357bd7f23b076ecd8f106f81e3b441464f0f9d8ffbc8ee84a41e77bdee58a00cff7e83c90775393076686d34ddd889985736780b0000f0b6b8a248e3fcc6cfafdccc2196606338b8505789f30f606086b60e10afb8839a262618e028439a69edc5c73348bc2fed5c9cd51c4c74714ea21c2a4d0f3b18f89423f224c8fe842c13542c3de6d584a92799126a66443329d4c3385bd2794fe0e82f7d61cbdbc7c070b1d77edc1c2c63547d3da996b8e60a16714ba604f4436d404263a40ca62cfe363bea35e4fe8d47760a2d613b6cc9b4d9e29f3f78ca40f4ca4b3ce95662471bce7a7ac471422228b89da4c2774c1be0726ba10019e8f7d0408f03d1ffb1dd84b99d0eb892cf63da290abebe9115d1d1589e3dfd323ba601f135b459c00fe3a5238c3d04cc1c4165158e4ca7c8699ade0cebcfc8276cce47cb67846c7cc003e837806fcdc019ef98e8af4c179ff8ec9776edebf9be23c3eefdf2df19d10debf43f21d01bc7f77247d60e367f0c784f97ff0d9f1f752fe7491d6e1ff3d8fb0489b4d9e9e0f01f6a9c0f33f2f3ff9a5b0f33fa2908bc70bbd9ec87e5eca765e7eae9b8fbd503b91c1248b89ae1d381f7b21d81638acc862afc3236c1c0b3b8e2225d94fd84484efda1321dcf13c428963a190a4410f7044c988783390fd884d767cb7230ce1bb96de7305db1116a0c812069a3c950a09ab7f05ae9f23665b05d7d751bfc0f5070085eb838f53df27ac4f1c56ffa6be00c21a425861619d499caac46145faa7ea2075d4f7ca04ae3f8a1964826b5400c4ca03aeff8198dd46cc16d7aeb107626eecc1d39e07f2fa3de2ffebfb630007ffa2fc46e82004f2df18685289c3f0261cc21d841900af13baeac75ee7774257155dd08982451832219d271243828aac09fd9edf791e15dc5c730480af39f29d0c0b0300e1983362c18168f39238268cab7d7e4580e77bdebf0810e063ef5f0a3bdf230ab9154f643bef5f0a3a1f1385a4942620aa90e93cd0ac19c260983b0877c24e0b198d36ebaae43a6b85d9c67830da8cc3d99bd5d8e0cd72855275f0b459ee98e41a2daa910d73d5016798990b75d61cd5244d1e0c4cf1031cb32c69bc5103997f8dd2e4f1c00c2827888cd020e58accbfe668f2c829359488824a0c6e48c30532ff1aa4c913022ccc4041142d5a445de9b490f1ec8452d6b5b73301118ee0424a4600d1ea84525675b8d9c2ba211ede01101d929b5fddc4cd3635adc39559d89094850d47b89bb832e69249778d8e5553c4ed9f41c1cd39d84e3be382dba3cbc9c989494a424ecce783af077b68f5c1d79863336dc6a26beb9ceeb286b044b1ff0a4bb043d12736a4e01980c05932b1c1046749c58a7caa74da60a178be0f8aa78d8d0391901323b20222712518c61582e76b21902114bb4ae8ef9f435cece1a3fc29c67c04c3b8ed53f4f1f29d1c9d988ff2fbe682d22eddc02a018890fa2e1380489ca5cbbfb194924926f948646f8b12d1a22935a7a4947c2792ef4595467171239b60a1dd022b58a059b842b6522bb59366a25b899ed1f992ea2b134afe648653e5488ab835445ceea7b8050c94600160b9c5164cb3b18c16df489e6c49792c1d21752db22045104c829111b37c9907721ff4472a7e17dec984d2c7980bf5f2f761606062c27c710c7ea12f61ebe52787b06cdda7f763c22c84af7d98b0aa24cce71bec3b3916e81f09b3e5b67efe0b7df9243384652865440bb48e97965c82f412c2c0c084ac971f9d491c0f7d899111937b7f267d247e79f91be6217cdfbfa0eb32617ebf8ff92d524a5f6062e4108e09db49eb7861fd0d59ac59e8488e543dc586367f23021137c9958e906060b8eea1bb9f9113fbd1c2105d9ae93c34a2cf1ce63f23d21913e20c16373fce74867d47da16133540e11e2c998a889c70bf277d4a98af79f6a2f9c4c77e2042e6bb4cd0dec5bdc456137303d17e729ef52221dabb4c70201b56f231d682a0e87487d289001fad0541d12758a526664b31085a1bb6ffc8b7d31b0399b2d6d112678a58bebb67c7f27bce39e79c73ce39a5c491cfcad2b54f5a35aa6d53d69e1d58c2b0fc50f2bce4e4f4264ce5152c1f4b1ea07f51cca0682bd7b2fee9077d2e8f10b07cab0245076a1d2ed6a3db6fed573aa95daa73d4f15836f51481802ad0d63749e966a9bd4824295fd2c76f20c23d9b3c2f876dbfbdf04bfaacf0f6364adcd5b366db03396bfbd5f6ad2337e7ccea17e498f36eefe65e12677bd70e5773f17073cfb20b6f9fa554fdcd5240a2d03ff2017247f5db4b40cacf69cb8db374f25ed2879312c6799ef779dee77deddecb0f05570a53b6fa295b89424464abf744ed0502372cf92871cf1a0eec899e7463b05cd242021cd69995382ee9337ffb4eaae1afa5234b9271d588d580bb87cfaaa89254fdf484fb73431571236e3404ee7725aee44f1c4a7626dc6f3baaa5fce8fbbe9735c0dff7fdd58109fe1edc2106fcbdf7057dfe8417262092795ed7c25df7b4eb6634e06e660577393c81bb577d411df705a92e1786ed81b7233ed8c7f40a2b05d0816b353204ae46d6c0550a0e52683002d1e40a22197d2be75d9a6fe7df2ff094420220f0bcc1073c9fa796d1444ad175c25f7b625ca5a533d2e82c314829d2428a0d4460b7d771e8a4cd7ce9ffe9913f614c5a3145112c7ffc2b79a4cc913a72677b26099309a8c149c224c618c8431a52293544592f8f17f4356a9892020a14073636d287c3f25d3bdc89a5cd2871320858fee7c8f1923929756c0f9330faf2833a9fdd540173f30bf2dea98a523afe7c2075f4081cee441b89d3af0ab930c8c8612bca2b30b5314338c5518392144b6660ea62446e6f5540df77efdae5ea67ed67bdab1924c7a974c2167f5ecc819c0837647d36499181084a0a26fc8a4e8a3929a5f4007336a507a8417476d610cfef3929a5b4e7fc0ea4f4f9a4f43a95949c757777dfb44a3d1f65fb4c77efbbfabc8e568d9b2e8ce0788a2cdc2db258da665b5cadf04afac8954fbfc42d7edf57bb764a254ebbb77cbb5a751d35c10dd6a8437cbd841127049d6bf4b8584a0c4ad6c0fed655584a8961079c034b2930b4b144b734c670cb4721a602dc2f2b604491130e35d8125582a6389060d9148794155836c5b104ffa6e1dcc274c98a28a0e0290e71ec0110e717888888f01010b356520bee7c549f3f2c5d706188c52ed4df24ce9ccf85744e4cb710678b359cedcfb5b871b6138b4e3a0f77b91c58c70a86bca6fd37b1316d5336a60d8bcd89ce26ad4b5d70ad4c354a8552976a94caa403954b40404a452fd2c72afa6ce647dc48d1119ff98c09d8a426aa412daeebc8650297514d94cb04aea319d01935a248e88c26a1463fd8238b64912c1176893db24448d81b72681e1df1c8e1318fe6d193a9b4b4e4e35c5a9a50cc275369423197e6925492f23b20b7b4da8e29293961423a51b2ad55d153d433eb31d253d473a46746839fd98fd10f929fd94f921fa39a195cef756345eaa317f12827c3a19c0c8ff228992457a607efde2963aa48cd1997fae876041da8ef63fdb6d977ef569ea554455fdbea043c714c47a5038555685c4e07dbd7ece64da3e82837ea3156abca71ef514adf7eb92bb54f3f1f34a9c7a0e0eb2b0b267c019aabfad9f76c8fe175523ff54f9411ee42cf72e9286aed10ef31fa87b355ab3d46eb481a630aa91f236c7f98b0fd49d2fdb75269bf127357edb9ef7e663f493455948a0b149eb92679dfe51f25f8c708d79f24dcfc9fd90f12a35a7f983077c6b53f460ce8923cfc49d23aea7707a9493f491afbfc49f233fb49f263e4b566c45e4ed4b48751bd7cb6bffa9ef53caaa59f0ffbde77d282af7f118233f7f737204c1f687257cc12ca5d8559276f39d2bf7aa167cdb81d100f1efd935b157e3f4719501f685a1d5c5f93a19336597584e777b1336c7b96b0c548dbc7809e23ada331eb57abbf5f43abbd676f7bcbd5209f26e6ae3d475a07f7b43bb205b9ca4885e4862a25af428267ad1ff734cc3d487a6698fb8d76f37b8a7a8c70dcf72ce12e2ce3aa7a663eaabc086f6f27cfcb7362aef673905a84b9d7eac3843264408739b1e7c8f6b3937a8eb48e7e20ef29ea39d23fb26786fd55476774d226ffcb114ed830b9a0adae148456475896649a6843570a55a8434356c55b995c6ae924c05311566435ecd090790f33e963ceef292c168ba6bd6f5ad544397dba947b31b7d7de7b0b5bd6ed39d1d484c9747871e5e79ec22d61f5053ba5987492e7d6226c71287a2187eeef0f4c7912a40ff79e63ceb3facda5b7f781a0776f9757c0aa970ae8800a61958a7bc9d9489cfa1fe0fa5225e50a585239859ec0df25951aeae4a4554e3a6b9d5aad4995cea426f8a3e1e176104b7a3f55e3ca6f15b488b013899a9c445a984ea9260a854c98908ffdc20e1257be13612087c10bf4d93da597f8cb3b3969ad9ab66dd6725c93de5a85d4759ef77d5f5077f792debabb59fdacfb051519c1dd0261c96d10cbeeaea6852dad5fa65fa667667aa6bee3daad968ccc8cf705753432343434ad18181a9a974b4343c3a2597d343434ad5abaa16b4cabe851f5a9d6ae7508fddbaadc77773767fb35fa1bf02e18888b56f448d0b27b57ac7f9a46bffa2f5c2971f3060501249cb0bdcd54f934a2ab8992473ed28e42e24c6702679f8227d30a6ef628963c0a6bdfbb56777feb4e6741b0fa5dea58fbab246e9e2d1d55d81dfdee7dd0efc421ac0aed7343b8436981266dc772465763a5a629d570a9897299a07f5a7bcd8c6ddb680d174bb3a66926681d2360da5c479aeb680ea1d9fe6931ecf3d0f0b226f55fa5125d266caf7a1fdbab44d93ab2c52afa2acb59516b1db3ffe994ee70743f436b7fd57d278232b8b576b5ab2478d5a39ed735f6669067a4ddbc6c9cc7de1eabaf955559210d2f6be26ddbf67d9fb51dd7bd8a136992d6a139614dabce24795ce3b0145fb0cca1cd6d73296b3dcff37eeec0026541471fcba752a461dcecfeb8bebfa669fddcfbe8e7ea6687301de255874ee98e86b669dd6fe10dce1bcdd9229facd534ed7df86ba2c6fdb069f5becc5fb5aefbdb691ce7cf7157e344326ea678dbb696efac7e7b6a552a158bc57a1ffe2c11ea398e7bfb792ce0fe389b43819848e4a67a95083edd0c62cac2b436a367a8b46d7585450b15a201000000006314002020140c8884229148242293a54df614800c8096407456980a644912a42888318610830c210401008c01404343430400aee422c25c1b409928e20eb26c467c0e4ca6384123f21e09cd806d82881b4866fd25a7fed23b9acb61b290098e018edfb5bb9e21cd89d7ac1df6bd3347ae61c535983411fec740e701ce8e3fb0cfa34e2b99204ac9a302c38dd8a259c5e964b56bdfb10125041e50fabeea92cb5638f112d6e3873caeaba44b0e20b41cd7ef3330bfc28c4fa9cd75cf28fc109b8af91b5cb5907c933d9978380b3b4887e7d2728d18e87772fb6530beab6a59d51a72f8d93591281cb80ce7fc0a04dacf3a727aafc3f0399edb85b204f5c549a310d11a1c9b5dd6e7c60e4d358cad0d4a5f5a3cd33fda48c25def7975aeecebaf42ab3e8d50893749ea7ffe0b6cc64e05019fadf336e93d7cbbcee33491f23c0c47ed758366db341aac0d641b4fb8ba15db828c9412bbda9a1cf476b9ce011151c04ba06f966686a4a6ebe61f2b2940bba816e0b097b35df63cd01b5643b928bf454e46a412eeb093caef3b0b66afcc3c5643cea24a06056b9fcdfa2e200206261a8c55cef1fd4a8083e73ecb08876a1b0e590d302d5a8055cca152aa29dbcea115a317475ebd858c22c0f8e0101d20063efd3b15bf4189c1d696647d9dc16b69e31ee078410370651cdfd79bd7eaba7f00e486eb46568d16c967f040c54f215c588c8b9141876e9b2161733610158167465636dffc128422d80b4d1ad0baf3e46974ab82c18954d0b278e48754ad93f5606e8c3df45fbf7e732995d52053e372620a9fb041067f5b490c2905ed1766eaccc06f07868c18663c104ef83dd33a60e59aa4673b1d18a572c508d0aa2fb983a8db685abb247cbedcac8c08d53bd2187d30fef67432bd233578fc9645ff8651428ac1ef08711adec4267c74c76b42c9a28e40bb44c4ca21145826192e130cbacd09015225b02f4dff4fa4def57f6a3ae14a1498beaf29cd5c58ba9ddda438c7e0a8b18b6e23f43bf8be5fac35a57db64802cdf2cc494353b67b446a2d2af8b9dead45b252671aa86feccff95a8d56a6fd35b1915c9163a8c9851cb712e8b01bff87e93019fe2bcbb3aa243c6195e46bbe92dc8208896d3229ef1bc1a7369c056c73b272cc95544a8d001ccc0ff817a96916e667ebb3b1f5cbdd8e06a90b81c6a022225a07e826f3425aadbd8a36436f78e96077010642e9cf226d2db07f5a48d42c895d4669c2c494603b60f6115fd290434849859b3d1056181cb7778d112c23fc04aef0e956f05ed8f565773d2294992e504c1bc53209c0d928843211838d22a03a85041b11196ed8675977bfd12d56a5e538d96882458d6a4bae466d354830b3b634e47dce4a20d15c55154b21ea646ff767a085cdff7cf92086f4c8e943fe67d4974b10ba6c28d49a3fc88d11aa48dd3ac3654ef6a51b5834629eb151865858997f3074d67b7795c2b78f7fcba31abaf0893225bad87539905d63908c9d79f3520ca655b4cd85a4715ac94542c407c3315295104458f2ba05c4f8d4d08e4429def6b97f83ef2844abf2a67d29744dbce9f04dcd950e150ebfeb325ddb6606dcc98f16203f30687c5fa05936aab142fedd9e42dffcf696505a4a8c76e24652903024fc2ce065ba9d7560f0984a920434378dd8d28e783bf809d85ddf2633d67d914eca9218ed7d2b580f3b714536074b1481e0743c42bfd2dc6741380e01d697c2b5415bf2578114c3bbe1d544b0a7d0911cad4ccf1ab60f2d3892632851816d678f036f7e57967a52b43c4934ded092c80ef12fe14513f0458894230aca858b3c194b35f23fa1ba520523f0a49d6816553c27ccd25537c2586d8cb8eaeb1cd68320f5db5528fd1b055d11e892134d331ca5c985967ad7cbc70b5b5567516d119206b66638cd70be91a4875b7af422ae1add03662c3d9d6c849ece67f94a56b8300a3d882df4f45899ea7566a67a6216a74df40ec019040830582e17cd7275a5668c2871e0936baff0d52fa4e8e69f58d9a75deea2116157237ddf1d7365d682a056db73cd62550d54290b809d1525597a9fb037fbfd4cd1b80f1956a692acd31f89d0ec09e158ca6aa665ecf4c968b47e85221a705932383c4a37869b088b4fea63ae5ad8deb1097823e019b55b9d4daa4beb1e6514c12575db7c674fb4dd2afe1a472dc3c002fa6c2540c0eb92b8d91cf00bfc5869260cadc32373791e8902814afc644cd34ed76df5f8b1b644fee5e142e4d6bfbc0fe5f265a52f3aaf0b7c5fb0dc41775bd0e958503c2f151743dc6f82c4fdc409e6ed5fe69d519c434461d0bf58010665ca1f9dd567c9819cfba2b90e40932dec918212672edbd42d1112db18c64021298cd19a7c92f55a569b3b32478087576e2b630f48311f526cb00b5a91cfa94e7546672a84806c030c3da0e07d1d82dc5c9861ea6f9b1c59caaab286728b20a831034988d6702d03c6f17c8d2870fc0ad1df150dc470232a558bdc887a744a94919be00153ef2d02f02834a7446f198e42e201e921bbb00252fedbe01347ef0b2cb68248b713642484827323a85fe07739d929ecc90094de9b45de055d651e4f97c4caa2e2468dd42da3a803a24e4ff3573aa4f050f6043f551d4265647bd0d8b1e9481375274c1464a1ea1d3fe4b13ec3a574fe9df3b53fb48980cc2ebcc06956fed453d3fb16d743fd4da5082e1afaeb3e817422912ed3bba69834bc1539217d583b874ff4c8d1eff11133568ebddbadc7ad813a9ae5978064bcdf79f4ce3a971666696d907754148d3fd07c6dad2fb831f2f8ce83ae009b00ffe8763fbf180823d755784853e96450dfaa90518b1b6fff2053c4d3e987786e25cfc962a941ecaca1e8ca51e65ee51037cf8b31e3c4514581a3f2065b3d174aa4d9952551d83aa06c220adbbca35ae8039840bfb0044ab0ba205e1f4c15b107343242f34adb20bb7662a1aef18fd68975e9e62310082c51c093c34465412a7f73ead062e09b90f3a6e08a0e8e980cea89a662ab1571400caf84b803b1028eaf2ce6eae6fcac5cfd624cec951b634f8d3d997a2eabefddcd302c7e3995f76fee067faf772534f42f199161e940aadf538cecb8eddfa562feb9d7fcc3ad3b0848943c2414bb7896d9c44d6828c1e07131f229093924dc94785a1e6a6ad4950642c23dd6510e9751ea8703dad3b5a9c9f84b7cf50093acf6cced5a7ae14ecb4d61f2df8ff48003f171d62eddbb3f8dc27de10f5a13388f23ff4880f7b55ecf0ea045b79be4c886a9e070afbc84b2bbcc63d8b821079578561ad2180ada681d20603b1caa2bfc11d4bd68e05b40b363fcb86e5ab7913fcd82d94952c7d6a6892d806ea8ad1bfa2059b55f26521635fa55eeb034a9e2e915c4e64e9f07826570d51d6aebc25f2377ea937a705042fe0565018f7e98624fa6b2c71e958cd3f587a2b74b64056288f8492a2426cd04e093ca272cb7743b7760b71cc17ecb1b7092bdb604278725e47cf74776b05928854b1615cd5586c668acc1aa4bc4b50e3608c6e73768f81f7d9571a9135c18646c2ffc514cc139bbb90f72d73aeae6ef34c252bcca1b1cff21ac1866e7daf216636f489eb34150c73579b6270a8dfdbf5abba30dd237a85bd71aa448d7a0acf0e7d7d398d14d5314f169c6e5062ceb6987180f30883590d8c9741ec84eea12fa4ff6640d791d999a948d6ef5beec0a82415d8689c55e0933f5004c327ab367527dda88912b607c5a15eff1a7bd4b854ecce72f51db5452de780e4b978344dc2b381c44ff774a80454710d161431e74c3d6d7702e850e167c0debb2e45bf9f7fb7d163fbd895dc86771af436641f81b981bfabf82c5d960736d798b9c7983f6e8d910d86ded5d11aa409f503313cb0db36ef6f32925aa9171c5740b9804b53d9eff0ce06571de0c3f4b5b8fdc8c88688daf418731bbf6335183e399d655f4217c994669ad17e52a76f2c586492c12e51baa4b3b3fe6bc4e90963305e3c9a989db7762d0fc0fa47f51e85ee0f752b1e2cc3970b5477aea6e236661567a1dd698c456b4bd78cac06f6fe2b6f32cf2eb1ffa02f420094950fabbc3b4a69383f49fe2172d5287d4031f99a9e38c805c40ee340ae710be2a85634dd7683dbe9c15d82204e46ecf5d9d490c6d1e182ca6377ed318b693798ac8d81d7a1d3bb8a83980e658f059776dc90aee5b725cc80668fda78c249db8a8c0841b3bf12005f9dfa3598bd9dc81ce940459e25187078bdf572154986990022df610ef65daa4c63b967c0f43e0ceaf00d2df3631215830e39a020cea26936834524a697d39a942d8948fd8940cd9b4403d6d7e7c736dd50e4ea9bf357d2e849cfbb77ed13c956aed8ba06a4d32e8ce4e03a14443d0010cf8fb1ed113b29da6bd1f6b5e533692db9d789085ed0f148305232a9831d89899b16fa2af2046f8b03ca4547aff8ebbd528083941383c979986cbadae1776afcf08a15ac6042845f5606dbbb695dbfca71ab2707c0ed69372c87cb3e41a94a1c90dfc8675bbc544c4df9ff119a6499d0b9904f4f42fa8ab957b855d4594cd4e5d0a6ad61bcae75da6926238e1b8ec604b7a7cd2d180830bd0cb19ad4b1512cecb9aad4c572f1353b22cbdd14947be4a5c33a0a8ca9858eab510520fc0dc34d12438bc542bf1acacd5ea413832a1940d3a03a8e6bfecec3c509d5d99caab6f51b4ae2d274bc1371ac6de195dfb49c82a44088f01ef443c060b270f5090c59b1f4010c7c002b89b10818b1a06a6842824797aa02db251def55a77b253fb3e4726d80726ed7f7c731dfd28de177b51a2da2ad053c6bac834b5a0d0a77faf3ace420908064b81473e4dcb245d9ce5cdff85528101d5507c00634b9e16c9bc75378c34e87e4adf8645d93f469a6a23894c6d733b4217db0e9df422e12275acf9ee458f468244af767a94eafad59aba631e4cac2b075c7571ed58d456c4489ec37a9890ae283eb948e1a3b89d5862be3f4e8c862aa99cddef698b82c33c15417ae0a255a1ceb96330b392799802d8a46e7c8b261ee042e3ad724e164788d76040acd0603da03294e2508071c3e530fcb8b58da6753788aec434c12d3419ad3ff8f8c0e170968b1ba7138b5cc1545845839b332e50871575ce10bf160e0f41fdbbc0384eb43928e557d38707c0c13d6b7a6c099905a8acfc2b0e89b642e805554a922460cfba5f068ca9e023d75fd5a85c3388ae01c747417386102a2e7af995c6f57076f9a5f9bb44b4c6cb3e151bd707c867ad32a9fa8402496625b0ed9228d4bd25c12cd1b7b1791139b069858b4af5d9cdd123f08f104372830946c62d6c5a005e66a71c8ca03f4eec93b5490d9a4a1c182a4216024b3b6c727e3ed8dc95811074b93ecfd9b974ccdcf468057b21fd6408aeaba20377614c9b51db9e9f8cc89e9d0f436b332ae5f26db18d9cf42f5159ff5945416a5e2417958d6163b5271a96f80ef40236be2ab7db8e437a2d2ac96ab5ac70bf393edc568d822b927b42486289edc42d159d5fca889949060c3d7efa6e0c400dad4466a2741bd18d90ad59a96f062dc3e79c0a39dfe53ad5d984bb41aabba11bac60942c21f34519942f3398ce1e7aa20283ac9858c0521b0fd663d13819fa3375f57187899b0167b0689ffe8a5c361a55344e0f2e1bc05c3bb22d6af9b8eba2981502fe6699debb8da6cccc85e825ec7402ecd86df099debaaff7fa142046869cf2d1152dd1efdac35e1b001a0518bb88567e1ca99d428e288a57e0b5a6b841fafff2ad2c108fa2fc2523dd871aa26c94c98e16524120fca53badf3e8b00e968a4cb587200bf61283ffadcfa5ff56ee806088458029716b83942e042aad8227ddd662b456cb15b00cf1cbda8ef12a5eb17cc7fa6f9246c4ba2a04bf2fc249c179b025898d31b98011443ecaa253e1cf1a7d0e0d55ff67e3d1ae2227235c541fdc5fb31a46df1b8c46b521cbb95f6f5d0ba830a81b18ab2610a8ee82499512540f17a40b22386f581cbe0bf23e611c72c78aad9f3abf7d85c019d4bb62c868bf2806a99ba86ea292ecfd3c6cfde936a26f9fb950f90f5288764957696109423796ce9963d9ab4e19802bb65d48cdd56152e5f643f380c4894aff50895998446461dd5301e1d7f5e6f58bb334401878284220a76f03daa3171ca1ddf8db8290cbf05ba75b3b3041283382c86471e6c5182c0dc7b9465cce2e561e91999a7c51b72c5304ed27f8a1640d0d5c8d9d9ed983bd7790559c1e42db2b2619e78b9d76a3de1e13296d5de8519f53518902b672424412815e61fd93b6ca60bd698c20016c22df33fdf9c31c3c52e5a662206e13056b9e3a4183fd5d4976946aa3a3cb6657ab094217ea73550b60d192d47ed7cd074fc21b6bd422e3abcfc3962dcc5d3d646dada5dd159813f73574754881af605dbe640ae465338528e8666020eddd7bf68ff618ae46df250c4f3e95614a7b031b61ce2a08821c461a786cdceb411bbc8d04a8f07ec238175fbac1eaa1afd6fabb9a3f1002f44aaf1b124da9732abc350a639f4b99388f98f44e5a2696c7040cf5b7d506c19016c77c52c97c7a3c20fbc95b37f7336ceeb3674255157c051b3b2d8914ec9f6d149f2f6fe733b2b3eff5bbb7ae9d546f4719689d2f878a812a465c02f0141735506285c2157f1be28365e64e16bb71548a903e6da6529df38d3ad94ef406a251b8493df64327cd325aa5726ea516347ec64fb68f216393c283f37c87150fb657197202e92137395a4b09e8cbda36b43bcc692b979879d2e3b8e42c96844299792da3ab1fcfc37bde9c39f6dc171f4a33e65a1983f428c670535d15f77ac26f7fbfe829330826ed5bbcda628a4c19dd179d128e144e91e1bf86748723666f33d06a59ed409f2440f29ed62394d3bd0826cf724f3f411a8e0843387904aac233643eb07e2fcbc5374f7fa3f242a69d1b861e4c4eeef8d3bc11ceb00d62eceb32a20aae06662fc05a56d85926e842b2b0e289b03661725bf5325679685df8e452780458fa1939b48ab338a43fed970976b0366ecdd566c6b7dff6ebbc0209b8e6a8026ade51a46604a35556b0242887b5adec84049ff69675593c3b7a9f9ea57f4543bc50dce5f8eecdc7f8ca263b4f513193111cb95d4eda3e43e63c63a63e018d9dde38d1e0b839aec759e98b6fd0aa665ca5b4e9b31314f3a86f5a4939d6bd237f7c71fc4df9187e7ea9136f81d6349f7e8811ecf9364b1cc32d6d1dce58d580dcffed40912f6e77f6d38edf1966062515fdbc90e90e0d589cae75202c7f71df37eda04a1ebdfa75db33b06730d5f2d15ac19082d50745f0af0e379fad9f45e50de691fe3c97ddf2921897fcecdafdafe0f28376e8e7ac0898abb3b4025896b504a87e758fbba6e94e088e825aeb08569cc191b3c76ff25168f9ce5064c4c7d4b4262a2c25a6dc483a910316781e43d102a9b46c89c3e45570f11fe32cb44bfdccee25e729092819a5db246a6983e2693391236edc243fa36c41f09ac49f17e54779e5e6c59fba3ca25fbaf76deef123278e164c2a2e512181de16ec1e13df15cad237c8050bb325080019f6bf9503fef2c349447b0a219740b9dd0dfd59ec9cc703ebe1766c30e7c5b9c5f698684202a4f810c175c8a82a8315e4b943032488f1c271d4e38b991b26593e4213819ba9b6a8a94fd910191dadbc9909dd208840a8f86748dbc38525a045b34feb36119da90c53867c842a125a75315f7f72cf03caef6a8403a3ac80f7b13435028280989b1b27bcad96a69fc0ac1ad7144e6c933636ee03cd3c2406e18084ba14f35100b8b93f764ced4421dd39b19e8537adb5b92b4bcdc12ec2510a0175414b949dd184ecf8f5a51bea43e01ad83642eca4450700fa2ae5439389dd2087a879e6437e211429cb8d793ba0c7a8343f66271b962ddc50df45a5f4abafb0a4e422bcf343dab330db7cc8956b3339c573108a3dc22084931bd78f30c499bfb4cb83a08b634831b82bf1c289f0a6353516839e5699a11785dcd86432ad2eb5583b1844c1394ae606f037f63962b6fa4fc111bfc2fcc1a4addf1b160143758a482826b368f0a170676b5d6af0e99e9abdee8127156fc8ae5127d4635ce9aad329a073ad3415dd3ad5cfbe3f78ba0fc466a8e65e1e0ced4191f5efe946bdd44690803352a126fe0517bf702fc8fb27be6929ba301b743df3a248dce1ba2a7ecb0e3f28dac4790a9930a856b5088117658161be4be3faf0c3717e5364ab5e985c65360c50b3e0e5faea08977cb9e0ef5edaa9e0e6a66395fed0aa99c1c1282ec66695e26edc6b1ba3e5541c3fe8be6564bd99a2194d8294b9e47c1c8de121e466b93eb01f7e95bed99b92ed747ffb574914d383ac2dd9fdb35baa30c80dfcb109b841855a592e904926d42505f2b32d0bcb2b197ef12be832202f3a252e4ba7a00062c876b0e8a04d248d392c7519cab561646b742a2b4d82a441c59471facef7b7c9646baef74c462645f3f3b9a2a75c0f4c337205baaa817411190715325bc2d487c70721d1cca2ae134521bd37aa4d798bba709594a653b0e520907838ce9b1e92dcf5f46a965fc34d14816fc2b030f2107c41014928710974e5626d9f6750a1e3ca7e187c99018424f2085f012bcf7cc8407146af5b71c924709513a1a39f5db4c52d034386f5b88ebeec20660f507275003791a873f0bc1930c9969a71fec72c5126d315220e185cb8c0a98d4f122f3098b863b3dea7c210735e182ca33c3b904320a831521f490bd039520ba8af33cd7723b1fc87eac7f388f9db5765d446d479611e9ca6fb8071215708a1045cd8da5aa543084f2d151b0fa174aa9227005f32028306a813fce3642c56a29c53cd81a14acd56bfb72a744e471784c7cf6feb345f98c4d7d4c328ddab567f041d92a739be86a59a10c308777d229b4761224579f0f9f07fd64ec6cdef699e7454adcf10c6c75e2073b49404ba2b599b40f45460adc241144876d5009a7a49617acd5e7537852622ce2d245bdfa6a4243f4a69722852c764ea56204b2484c0c0b74dc2eaeac48c848b2271d90ddacbfb335379fbd9cbebe8cde3ecc51f46249a1b4a8f28bb73535d9aed296a4d3f7a56d712f9566d8eef059b3116e2f9a7ff71c81890a776f38769b5241103a93f1738d0b036516bd2d8a9c23b702e4c8765400a516ee70b01b1db4c04eba50ab336d5abef645a6e1a6fb1c402ef812358c3b2ab86c4981b140046337f47b12c51438da2292b7e8e80a22db7528eb425191c9e3f47c1b245d51334962d66a7c1a3d49c9afa955b2f983f00c3f8abb975d8981b85473c7b70ea2cc9bf639176d5a8faa700226f5039a806ba157a71c6a21cd1af0d2fd40c4f03c3a3404f98b1d66b1f7f68dcedae8912ef4961e13a0a596484fc30331e2b48c77d22c5fe401f30c4316d412f6dfed24d31ab1210c6bf62ddbfdafa516c17b51cc8fa9f6949fc53f7a87ada6432210334038243b8a43d5128ef6cf12c84fcf483cd2497ccd6da4551eff76c3e3a5b2980286cf94523d43cc294adce323eaac5b73819125449fda5a315c002b0f528a4f714f0daa2d217d6024654ebde0c37bbeee862e24220cd43e3040fe850614c216a43db89a13daa22bc2daea7e4abfd96568dafdf958568e2bb636ab03157debb5a2ba74820a8ead9736c2b2edcda111922103505063e746963aff20235dc77d513b4422ad97bb8a373cb93dc3b8ad720fb70897bff6a518cc3a05bedbcedd82db38f7fb61e7636f6aa549f4ec7bea03a6ff8e42c862af9cdd34246a9e46bc2ae4cb75f1c6845c4b014358927bafe774add24f5e307b85dc649ddb78d37804abd3f39463bd6b66717e44050fa24cb7d2794deeef228ada03cf70d3c6bfc0d2175550ee119c021fc1d70c79a5fcd675cc19d1a2a9e509809c884099c780a0c354c13b581816727c9f45f2e9f4613f33c62f2e1dd3971f7e30e7cec9a730afed221dfbf73d4b6b02bf6bf40150cb5730ed31541bba4a8bc782c3f567ce0d094882eb2d6b1f7cc62bc71e47b70751e25c01dcb8ab49a0616967bc702b18e31c3bdfea34a9d3a3085b8dfd7bff0f141d7f1bf0160fd6248d94168c7aa45faab5d9108af951b764daab5cfed09719b05e8559dc2b0bd2f915c94fd8de1f9be9daffebd1df301dbb1c67601ed83e2df9b15d33549dd4907d7c86187735b3d20823e787558e14e66f5fd4da8c327155bc181c57227c6a60b3d2169994ce20925e003ee08e2afcdf41285ea8c75a12973093f65d4a9cc62027917bde4b4deb5bcb1363fe016251a4730039ee42302a5416bf3e532d3ac3e3d39bea68a513feabe57f3d61741a45ae02437941b33331ff400646acdf7cc1584fe709a3eaec3761af5d8b9772384f7a5b4f1b24f25b5f60d8a7677f0650a28aaf15ab90387f12e1e12e5c7b44fa5c97bab3224a5320e2c9f2f57f45b3b5527c9710f742e2eb62abc9beac2623227052ee8d459adfd83a6dd2d7c19405359ad6aef4be51335229d7c49b1ad27b5ae751a105451ed0d06f0e74ffe6459907bd29df06a433b86d2f235d4b36c1dbc2ae3f8b8adc1b91e4dba5038106397575f086093f8a06d50ab3b17c563f791e9d8ca79bb3415b5a9ec4cd082ef87735dc5a9681ac20055bb03e6347a1e33ff0116872a83da120114ce9851eff87b038ef558e1bc35cede5c7ae5c48d00bf5a66dece425a0c8229d3296dc57b7adccdcf8672b936a02c07a8e5fdc7ba1e864bb9aebf215cf825a1b5864c8688f0461eb4b412a192c475209ef984f2a9112db1457501d6d78739db2d59464eed9d1c1752963d7d46da2047d243bd7da79906a1d7c9178e6320eecfb4909940ad4f25c54d398b69f004e018dfb95a8a57d34245d9312990da20ba377e4631840280de6e8514c23f5b12d2e0b721a7e6750cd11da8f4a4a1654aa27f7ad5538fdc4d2198d63a8552cd7355e4ba8076fbf4e70d0b865ef3bf86f3c598fa2544dd51a2e390b676dee7eb106cde76634c3e6429411c60ae414c8df480fad4d951808e6a8415119187f4d551a9230c9ef9bf8be08199c6c8d143e0bdeebfe81199966607e7ea44e15632b06857188dfce1b5faa4abaac8962d54db08bca769d49b0b016a9036595ea2127dcfb24abf8b5a2dcdfbd42780a9aed3b8b24dc850427079d493aa4a18a21a7b177c58b41e1592dea920c1f7d94ef5e596ad5229f9f8ef63baae55b8b309d58d00eebc9e33819b990d9cc66a7a05cbb93df6b584952db14489b28300ee6306c633b78313ba23feb4d5efff64f61090ffbea52c957d132bc21b35d0c06b290c7478b3359f5eb30687d2b9f4942bc4c029876ee70e418b5ee639bc2aa1439b28adcc0429b794e851c62a7d7a89deb2dec1d18b07b245544c6f4ef7da660a880120b71c2efcdddf48381b793b2a4cfd757efb0d2505de7812420fed223180aac2eb3a11dbb8b77329f392a78aefa4e462b4207ab417d76d19fa52b8969a2641105139371cc99cbb095776237fae3b5a5bd45ff4e8733dbb350a5ce12d09cce8ce5866e7021e40a1f19ac2c62a18265ab52a4018ad825f0850aa5b419ce3048b1c017fe22b0409557c2908692b49819a56ed92947f0c714a000ed6ce05ed055a54170649f4e89cb8db4f7d40a8be6c9805bc5bc43c0c53462ad3d16ecbba7f8b71334e667eb37b5fc3e425ef157e80d0bffe5adcd0f9a40304e703a1c5322d1b26f78a6c973322d93fdd9f15f4569680ebe64b350ef44065ebf5a5bee72e695f4d666c9409a9f76653fada14c18213b94b43d5126b47d8597b3071f1fb81cadad7339f50556fab0e5e96043417adea35e2c36df8ded1ccde8596ef0c3f2841aa0eee481da7e4f506bd1338790b8bb6b7c8cb63c461804ad72ceea2e753670e6172e96990c8def287183e7ede12f904133ce74389e9cceb8032b31add1c0b1b0c81523d3a4103ba9c551f67877597ea9c72680383a158fe3f46dfbf53c468f1d2ab480e74b685d1a75f725a01c71bdb7b85d5e0935979e5f0aaf37d46aed0d6c60ca92275c7588f2e5f5d85b5c44e291417945fce417d641ab04adb30afb3186d3e39372e56caf2dac77443ec2eee7854ee226ade8c564c9f38b5371d035f4772ed7b6483adabb008afa78cb7b14a27857e2fb2f7deba0c45d36f9063c2ccc83eeb7eb2d3fd9ea678993142b1bae166b457179d99f9526744cd663746aa949975200ff8550c825b3be630c91dcc7aba7b7bc23ddedbe6ba2d8ced831e2f697377e315bd7a1cb20d484a33ae78016196570f51c728e73e5b958d76b2ce32bb1bc6a42c406f71f777ecb03212de2c6fe107f5ab56ec65e1c067331292f29a6bd37013ab47b9c1e08a68bdca526a2f6aa91a88ab4bbed003675564ceb2645bf7122885006760a60ad29efae8b15df6afaff56cc289996b2bcb8916c4874594215b9ff6363332ce1aa7a41dbb08403893d472644d095a0b8c07042b1a985b265a6709727432c9aee8646052d896119356666ae01de1a3fdbfb56dd31bb761b3a496503313fa5349ef7690feb4706a374a706a200aab6aa9b3250b482799f4f61cb30b7a93f969c5581ede95a75fb7c03bdea398e8a1d3d7f158d46fa82a6261188c5ef45ffc86c9aa92699423d72f037168632f21984cd2cabd2cc3b7d73513653e672ec6bfa756a4369db82ae083a1cb0be5338f0d77ef1f9a2fba5b6c5d2daf2c70dd686ab97bb9692c22071944ef011a9c1809869dc625d463d3afcce057a9d81ac53904549a9a0f81e2083b59c79767ec759aa1806729cab141e0f956c90aa31af875e608502ac8d30e1f0a3a2ff5c1ee736e9016557fa52b2de80774c41a6806c33ed42e2206712fc1ab5c5cfc1ec15ece64796cdec08d0a4930ba79f3884b195588a3f6fe5fe9f3832a1b7af239389136f9a4f13b7e4a39ae151e806ecb88d0789a56087b1b57918673c0042867d8e165c14e771525022744272dabbb0b690a54cf75a5866b1b99aff5b9171cee724000267e8fd5641baca9b165be0e0ec89be773148de447e396c457926fecc0d268097017c6309d21fb2d9ba4c51a223871e051d67b5027efbfc1b6072cc49b2aff51bf45ee43790c13d4b3200e4b4c63e567ab068a97f8c2e104e60aad32cc26765e6736c1bcc5dbfa4c7b7d06dd3df1f0b2273a17d1c2ed4efe319af4c1c75b3e9db9fa091f16916adee9dc904b7d098442f04f6903be6f57c0ff02b64f2dc64fde3847867f67b926a49e216b0b8a7f95dd06889afeceafb764ec59893afafebfd29a729bb316342132edda6b82acc900931afd7ca5961a71d8f257fd2146cd008be2cbe058f0eb8c0ed7412d5717129d5ab894f36ce8d88f5ad98d88f38801776ece2f5409b6e6a60080714d758246adac7616fa07442e474759af259b90e6130c8d74173f51b38b7acf4d7304dd4a73b5ceb962ba1c0eeefafd8004d16944b764ebed35a661736bfcf126391696ded0ddc1cbaceee7341b3ac93a92ca0e0389a9133383eba74b48ff92f661efa6009e1ad7f577d85a364ebe7dafb4ace97eb81f40a0b550fae8e7d8bf2f82db0f5718ecaf267d2fdfae7bff409de286136e5984b6ed9bddf1dd90c82bc51b60fc677c4452406cd17c22136c6bbfb988b124f59a8ed28b2afea11fb1019d989a803ba6933ae28b46291e31ed4497c26e75446c536ad57e8010b931056c3db399fe1629bfa70ef5ce9798e41a096dd92266bc322c03024a8e7fe08730ea24731447a8bd6fdaba5860534e1a5a653db0fb267cf727ec22727489c6f0f928cbc293d9eba86f9494a0e75c3513fa3417a2b1e73cc517b4c8795660b849d2affe8c5dd6643bee971f460e06597392ee3d7a3f55cfc0f0bb47549026ff7e7d2d71277f1c37febcc8a970f6bf97e575c59187fa440131fa061922660248c870adfdb904cac8087fc31555c23e0e2b28cb5dda57f664d9bcee46ae9cdbaf4f6720dd332a973e3dc4b4bc24ec00a2dd2a104112f8cdab0c4751bf6db2d04074f3bc172a45bc672769d6734814beb915069308133d3d54e197c0c3beb90d63eecd7f07de539d63c038a12c2fda6d190fe1b366b35c755584ceb151943debdacad43cfb8b7aede5fbd6df0944cc3de024459dc12ab7d8f725d9652d64155ea037b32c516a1150a92ba052c780cae29d00b38a3f14ca4a9d5fe5dc13c8310b7ac7b5d43d6e5922eae8545e663157aba0a7a3967965c4620207d9ec45ec5866bf85c4d5b327692435dd744519b1249d3e6cf478705f009edd59b0725110ff521c35c0a274059e64b3183fe2dbf596a9e08c92404852448920e351a0772a0f9d6ba74d9cf80dd0b3042f2bdb267463afb99b28e48695ef3f6519d63559950b9784cd299c671252ab59af537158baff82d7bd37498d82818d71e20d95e851dc4f639460c85160ac8d2adae230f4dccc3d1ee79e197d0a56cd2216d1b7bb8f0869e02bd2ee6770ef5d4653227795f6291421174e83ee423635ba6f80f4da4cd8f940580688807cfc7c08199ec62af11d52e0743b2bb07aafa493b36c7ce06efc63812abf34ceb58cca7a356fd977895a3701ac29e3456a970b47c133f147d3d24cfbf44082563aa93bb200d61e1d64baa996a5d44f0699a4771962028e1f48ac572ceb8728184eb501e26295c1602e05509b28583913a8595361a165f83d6c30e3f24ea5bd533ac28b9aeeb49443291409b772dfdc9489ae4ebb91be91d7775c2531eda23dd1a2b16c0a3768f692ea8ce0eeca52381266fb0611124e5f995cc1cdd3f6d28c627d4db13e7d4dafdb8cae1c72c18427e317e17fe5f9cc82f8cd2c7639c288344d8cddfd44e5558636f806edbf028b0adef454ce98cad30c6137af05be0b26eea1984ee84547aca7cc72ef5ee810d90ed4fb7f20e5fe439f96b4643d2ddd22f4dc2315e2bbeca7c45273f0b2b88977d8f521814b6af96199f1be19d6f24c55730953202de688361c21a1be0281e358fcc696bda63d5bac35404fac77acfb5ac9caf2a5d4dfd8e17ed5649243177792fdb129061c9bc0bb9ffd63f8cdf76d007f482cefa996b42dcfab15ad84d2fe4ab3048a044948eaaa3c23769982df4596016a9414a30379b3a4721a6963167184573d1c63a629137ed4137d81cfe34666f6e8a0430ce1401e5481a5b1c135ef99dd37a739196c45fae34ac4d52b8065a9d2206543db42ddeaec865650bc8706b1eba88685209b8177241691c9861d87d5fd98fe4222a9212379d247bd6963779b0d76fa983a5cdd26a077fd60ac2e930b8a6b651cd7028fa5e543cece6b7673fc2d26b2bab24381489522f9a5d0871b8226c91a6ea944ea13992e41b1ce7194fcd41b60ed84cc73f0b1028c9ccd41cf7a6198a8eda1a8932b6f86436fee8a1b3302cb29625f1d4733ad61b47422f2110e56ba29396309b73f8b8b57303cd740dbe149178ae6fc773d355de3c96f594f027f93608f751b2e6b9d0b9b4926738b93dbfd9ade89bc4752c02227939a8ed400f8d6a5547dc2adeedc65638689da9ec4c7d474237da31da7f4d3d5215af72e68bd44437a96aa3dca961004bc3c5aa73c6b37cea15f9878e4294442db40a33315cae36aabe4033672fe140dc5606212e01830c69f5f9420c7ce2695673e362fa6d0dfff07082bb13c660f8c89b90f9ff5866ca1cac1e05ddbefd3cdb9a45d24660949156a8ccc11296981325f33081e9dc904b891f9615542430b1d4a8ed5c48c8ace2ecb400f7778d3201093fbdf95c4a0b69e68b5355632c599d14c38def030e9da40e300859f391a2b243a6decff44b7d4f4c5f919d539d9aefb8d99e546e5b5de2f8a3890f36574d8370977a7068bd05559001ec588d2454d9e5ae3313813db28ce4dd862e61d48f6c22592b460111b9dc22d1b2065894e216d2b1a4ad7f9b0218dbefd9e92dc1da75644e2f371822c4366604ad21dbde36d00273c6e822667d3718489974a4b612f731fa42d1b65955e936bb709bb518250ce3bc9e1904c3ff28fbe4ec73c6388645c3ccc9021bbc7625356033a63305d99ff977ecaefef92c7fbc3f8ddf9ce41c79aba760c8ac6c80768705730024491c455de47537910ef656a4f42ee0948424b4d4b85777a46beb431bfb50b884e81743fcda2020d5cec1d8386718eaf2fc6e13bf07b3604d8920250e8f007bf5c0d5cbdd60e37647d110747578bd82ea60debf69acc45e19482d1fc3554d4b28b9d038d49ba255f2adb8311f0960d2afda5a51644442b4e40aa1e41b69e6c7dcc5179b0f95826153a6ca9486bd128aad58b0a336568773eaeb86a2bd692ca20e62cd5e038c39f3c94a3c9801288a1a88dd18834250f6d15c9435c1c79e84edffe718de1f35667d6f2a3ae7f8a4b92d8ea5bd6ab04b8050c9f96beec53e651b8a7b93c6488b9cf54a042da39288c16cd509b0a432ea019b5e86f000f254526f8b0b5cfd81baab0557f1d3e9cd23b66a632f6d7469a468b7b706d54e07b6de02dc7ee18e8bd010581db5fe1f704ef8f096e472ad6eb6ded8ca5cfec652469d5b3ceb6a0cb082f8047fe02c4f07130be996a5ae60ff6c26907e953133483d3add1ff4b225db144c1399a04f92c3f6a898e7c7419d635a49b9ed30360d9e28331780c7bce7d4e144c5514cb0c3d585388c49bab4dd60c004e6c356d189f7e4c050128bc1f68ba4dc7c38cdc448fff26dd1a5fde07a2e944895c691d93ad751cb3791ea7f2a765ed4aa0a80a86cc0ad60ac8f991206527ed17744d3455179be059593a08763bc60d897d52601e8749648c5ccf154c9ce391fd0d471d14dada550208a7a13c7b494c1be566e9ecd80e2712b299b8ec4fbf8f3d9051266fed96ce7daa366b8018ed4a4ba912be0a4a836e97c5331eb903875a6c0769430ee39a64e41f86978df19fd6db13d5d2a4b2315c2760daa13af07352597978e644984326de9a1c9cea04b1ee64723de5f04cc04bc64f9e9c8f68ca2cc0ed0f9fb183bb24f3a52bf287b9fd15abce51e10b41a63044a7a96957b5233689fcf7fd81d134f799272b7721acfa8ce57b4124c2ba32fb6fac6b4ed6e8640cb28c7cb983cb0cf914c6439decdd0089e3f2ac97cf3d8b3031cec86ab8fd2ccf2d88a7cee8c0e4439ff04c46784be4150842405f53208cd8566db055e3414c39707ae11d11eaf7937aa40835bc5440d71826f6d6a8901e122b307452c94525d009aa8e34a5a2d6726b39f1383970d20545b3959638a33cd9898677cc55f51e90ab63da394f67420942aac0c90309e28870d286770927707582295f4328a24ebed40758d469cbf79449524862cd6e882ad193330e91f1fc4d3b55893a67deb7038d2617b389d5d01178946ccc02d0303c2428028150837a573ea31bae26d1b4ccc0f493d427f819ee9a27914fc2af7e1327d90bf8f55fb62784123778c7e217abeb49b5d7c9855013476c801277f1b940192910d03acde165dde32d5566d05d23a27c29bc470cacf6a624a3b053d1376541630ca3d26eb83d69e586e52f1c36e3c77288d503ceed7683d3c03426574e7d6fa6ab93176cb4583ef3fb7ee8b78d2ff003dfe8657e66cca04dd07c47732727c2a8d9e86a0e97d17d96b1d500631462391992257f5a338231d8b53d2cb8b60ac28eec36e09e4d118431d6560d4ff682878cbce4136304b90389c70732078f16ea0f2fd0a5b95f565d6316834f5a804a846233f4e050ca770cfb73c7e2804ad15c882440dca6726d567b0560111d47b16e9a55e56274d0d3d83150ca198263c5eec61b6b0b74632f6594faa551ea6da3d4eb11a88d03289dec191b23a24693e8dc5e001813a1fd839eaa00dbad5f63f6da85c911606eed051a21b09c1f5aa01ca12e3498cc9276842a090e1dbc3658be82093d029cf22849edb709734d7db1c3a335d9d31012b732644a4c9e8be9cc761865f870e2c783b0ce64d81f967b5c81aa742f75cefd9aa1d4f49eec1725f31227178d28d7185ff74c7c68d125d908b50844d1f661bd09f01339c01f6c7c4b7b6777cc4b34e0f3c0c131fb1ba7185807aafbef88e5ca30065b937ff51a12cd70d840401cd6f8cab4b4da2894e2f3c565d83b969a7978fe1ffc340774eff05c8234da9fbaa15d74840f0c5b186d6dafca047f579b72c86541a1e5ea8addbfc87270df54c0f846ae655d1f3374a75f03e32d60390bd61b4b5db276f31ce9cfcdffb989943f9e2c50d896ad37e8e65b47d5cd2c1fa2b8ea33a0e53223f97b93ed240601f243b18245ca9a612ed240e778fd746b1bd5f27122954c880106c68501289f13412c21fbdcaec8b67d46be201949d9e7d5ee716d1fc54e63dc32c40e2f980202ba52c458a0658b8a79244ed32d88738bd652e588b88b71b2189481e45f1bd89b0160872706092373208ecd8dbda5863d6dfbcd8a779c592d94618d6d19b6059d0257c6156301a17b658e1db3f9ec11a7b436d4059e1e7bf6ffa0c4edc58fdaab92da6d1ab2534edad60459f8abe3fb40866c327109cd30ed0c4d96c2e4b89a91cff62a1e6d9d7d95d0b41b205c02552a166d90d5a5f398818388fe0d19f0b49f19c5f1080fb22020de7236d1a7175e7f498aab30bd917af5b797f4c3952fe777153c6eccf15bfea8bb3e61956b18d2c8afd529071aa5948322845506dfd53553c8d8919950bdd8eac5a7c3a6bb82404566825b031d78441980c0eef0456c5d3f94a3876bcbc9b3083c7f4f510fbd9cbc1429ae5e8090b24fc688e022c42630873b17c3a05028c6e651bef0250676619d0f4f215e9aa28171a194e41729de1d980b9c5ba441f6828615728955f1a25b5f68a1f835dd58e65a8c7427aa85361b96b39d9e29d1f2f27fe30a820e59f90ab5827215dc4eb43a3f9686ec064cb73917a807bf656bada45812abb657a124a3f2747305a03ea86ef6fea4878885557de88a12139ad50cac4c021953aa55bc2514b000735dcb1745162a8fa94b4c849ba76728b34ce6a2aa72d5fd5195fa2e62613f03df02d2356068751636617dd0fe2118e32052a6313e821d36b79c0b0dc33bd5048a27a1645e6530f6dfe1c8fb74fa4ed2e8288cd50b02aa518b1895c4be43c415d8e226ebb0d3bbd21614d74df1891cd0c803e3c98330fe3f630202081e58279f139fd9c24bde714f84a7804ce3433894eaa3ca9064aa876f853025672c5836a82756556e143dd921508bd012efaf2c2f7d80d5505e830dd535d8eae2f6314fc961d294395035b9e8c07e095d7a208437a53d919079607900f1471be98a0109a4b4299267ba204de47f1aaa9729dd0b59fa1c28118c7c1d73b6ce368624df781d44435eb681e673690a8c0ec88745403e768c801aeb55a2b5f36790ce318548afc4131c03c8aa78d027060018e3fa7e0857db8342ffd1fe4ce84d01a46923d845dec3888cc1e1f1fa0f41548b637ac6575ae2201d2329baa1ea6a12874116a7f3789b91a5d9fbb33e15ad7e8cc38904ffb936442a4dbc4a787202b1fb2a6e1b5dbaafdc8837687f839089c4a00e1c86b97a3f1efa4c84deed87be85473da9e2b6922f1cdca59a6905088eb492aee2b5246fabe8df73078138640e3433b07bed3ed6fefb616a45355009df14d561dcf25c7797e6dd5a214722523428a54cc0924c766458b4f10b2fe9704d1d01ad4892162d4b190edcce66125e964b062306a451fee02dea0b0b3c84a0dd6a96f632bc7c84482cbc3cef598c62bcc0fbe0a497e5344a45627f177ef6e03f74539d8abd2dde11be08296b5ac9217040b20dc2b5c747b789353b695c5feebc25b351e4c7738cca4612bbfa9b94e8c4839d5d445c6cb210e46f7d447e13335667812add207737e42a93d729f0607884910279696f4e0c1a3e8e72943c1a0a62e8239543a9710892d1b6debad168a91406479bd84613ba414a73f43cb8be1c7b381e75f67404ee2a29eecadd95e8bd1373e8c5ec037f74e413ea16afaa197daca028aa2190f959543091cd346dab85aba379a58c7461aa9926fa2ce062909d48ab1185a5fac3e850811acb981cf6902e278ecb0568a8771a7725658a19bf5185adb46ff2c4941e1397c65ea126502ec45e59449e526eca96586f9dbc5c2f998a40e54cda1584d9f9a47c6d3b023a8adb019ee77298df9e86e8d1f8e19b69e5f4cfd0d662deb057662275fdf147b57d7d66658d2fd2102e3eaf3106ecae7c4acaa93f2a09bd6054e7a42c03f95b37d48be90e571f383553125e4c00525dfc130795d02b1a640e02eae025ed952e3a39883f3f3507499856c13e45c5d73d1a4d7390d7b8ae1ee1b82aecafe446f0a71abddca9f188cad6ca24bf1f6c598a38185f21e63e632a11ea2dd5181c76246d75c68788748f2848115d9220452cdf5b78fa873960586d32b1dbd380b89c0a2361dbac06b46dbf8350f19958dad72db492a0157453c2700a34ba5f71359e880ee34a347c2d3919f7802fde0331850fc87a7c40d7970fb013bf931b788531334d5921cd15dc6a15364da84684dcebbf5f77d3b30aaf460a737aaea3c6a03cfc96c23be01105abea4d8b195a00ca5957e93de26d65006bed80071646dc92399c45f107a701cdd63be1b791420054f18ae27079eab21595ee6fbce7d15a322b7823fa1d49a36a3b8e6a0a8402b614091b24bfd49e595b08169a84197d59a1b4a52f5aa2f4f62e07eafbb0ce727db23ed86335c035e1bf402735534d5159f39ee3048a4065bb3c2d9ad72b01db78a52fed5162244ae10e642cbc8dbae10da7dbf47b49c77781941db7a1569b0e8f2f831cda4c35228080d6cfa588760b9a599632ea579992a3a228ef485c96a5e82252ab38f0205bd526c1af1342d73f491db7d79fe1e8b4609ec7fc61820230b175b01893e04b1456d97d6420261e10bf59c60ddc8bc5b52e61480663592c7b35c66c4ff8c0f84e289a301be70e4938d85891393ba12710d823014c911e134ebba88bc42febe7b01c42d1288354e33e60d29d20bdd45b81f6dcfbe0a15dc57a0736fe4f898219ac5f042a30a9be4001863e79e741360f9408e17373b759b37cd2259b0e90ef23680f069a1fc45fc0b83d100a756d241f444aaa2ce751f8139cc7f96713996aa7a4cd091c16bbf09742725bb78ea190c12b188f0d85a4dd1cd8ea91f07a79e4f412ea2729b0b1e2d3b4cf16b0b95899499eba2333e3f20543b546844d58782e0811bcc62ffd31310afd184dc223b698fe37017b8f9695c14ef710710dfcd948d62cf47ee878508af643ec0d111af5c3fc8fe5de6c2c6d62a9cc55b67bb5a728180fc0b4d45380a480074a27879e5531d2b38e1ad3509bb9acae8e21355f93147ae979281a5b940e41e641b27d79d7c63e5c1a88de36dca4bc1316ea1a52c4139efaa8dd2cd93ee1d33bc84b33a72ddd88384eceef5a154cc445221d509bc0f507cea22a77be90818b2f4ed0c437f2c8972fba1dc56b2e9c2371546b2e453cb17e8336c5a0e9ff5f945646b83aeeac41e527209332c884e94f651b1494c101b827dff1c1961ae2429e045e28a3c3c72e44c3ae2732eb2b6ec8270192b5f48b51b12c8561f37dd2ed3437075302a8865c82903f38ef3dfff9e69db5d43707a5402495147bd43e36f1893c3e904c8f8611a3e6909ae71bbee8b8da57104eae2cdde453e97803d54926982abbd664a8018b4b71541a7b47d33257657e262e1adde9632e1ae2bc02cda831d081fd128b72a2c073e5c34778e2a830cc7d515adceab2331bd440ad5b6e6348fcb64e377c4895ecd1a58a28f435e99caf809002e336f5e91f5ea9bebbade3491a9ebea2161ef9873bc2fc9d9171248003dc832f0cb538c28c5d5e45fcb43a4c566b610a1742b0b558e5545fe61e4da34bc49033876c5d1a0678a47204bd1f1c7df98ace9830252ceae23c8754998c2e921aa80f727dff3651b1914adb4826869230662998ea3ec3886e1e27280128c0b752e214e9abca1f801e694f4aa2bfc447421f04ea965715423291f85a114f3d9e6c54e112be13e84e07181c87259ef427215d18932aa0051fc9fe4e393a5d5c3a7129f42ad73e7a922692e2c408f8d07bcd25e43a498a85c43cb26a8f8c682954638365b1e98257fef9a31d76011c7681d296808667f104379a61938c12a5b4147976ddd721578dec961ff6d13135ffe97941e26b3b934b853127aa46c931f6d16520a2bb8a2ec0a2080c7c2598c154a694f727d3d8da49a44daf78b70b46db05e2089d8b93589c2f8edee8605599f0448c6c58731c243c9db33b52cca9448521be3c3cbe0d1ee736db881b390eb6a0e98403e9a1e2fb86b43e6a9cfe957582662beddb9e8dd3b9957776e632199523a58c4a602da3faad1897be8da9ce4cb346a4e08c5e4c7884c947f0f2ef0ae453d1356d9dd1634812223c6aa0ce04d9be5686b0d0c7f95867489a5e2a7f1c46780ea07b92531db73afe93268658a4a4d83adb71b4936c490242c938dddd25d31927ab8031b85d4db02acfe644e1f1407e5ded7a84d419d3aef2ddada878d43edaa86f35e07266655f9f17c9c92c4f34e44060b5a16ad16c57abf238c944c9939b3fc9004274e33b031ebb8b853230720da5ab7206ef1a966fd1fb26bcda339bca3b193fc419c925a9ab417dea124578343db4dcfd62125552b66ee9212150c956913752ce0b8c442b7edc0ec616fe4ebfb0bf7fec41cd5855d466edfc94d5315287e4f947a64ab3ac42e2cb305a872af516fb32c8150815b4ec0c6237d9d43e129412365732dc86f41020bff4b60a5eda911ba91346e47bf96aad9221f54fa7e92ff467f5756a98e6a87e4dc2504414dc51e55899f0e6b4510e747193fd2a259137a9a5a28d8927c1c92c27d8b723d5cd7bb2bac9afc487b1fc5c1f2a82c79c062a5c0b64ef0fcc36a05be9df004b148f12ab9a1ef65a7e133954a1beaad6c5371ebbf14e5bb6e7f3ffcc783ea1b01d22d3acfcaedd70edef3314794943446a9f0729112306021d01e88aa8c67ce008145f9c9ce22248d79df4f7fd5bbed62c398aca0a93941c241e91434f1f1f26422025dc965b550ce2078011b1e36a113b4e1e2b44cdec0d5af558637cb76086dda1e89e8c8882a7d061b4e562e605dfaf8286643c460dad8fa855d73f91e01d33ae4405c8ae20b993b7d66238abfc5664454988e0fd5f21e3f414494447533dd8a012ece713b3a7cd7c0e3decf35919ee2941912b3df93c92e971e14366649427b7683e21122d31c2797cecb18e39b74a1f29a3572e93c73c625db802b03451f5d52b4debc90b5295eb2a31650a67fbdab8d27d97e13183e201d3a8e141f69309344c66a0dc003c7fbbaa4ec6fd721098edb3e63206f074edc801eb23e1b799e5e6c242c782060660063622ad49b509d089cfbfa923da2df5dd632e465f91539df4e2c5d1f0d5a210d13091312f642790b355b3b7fb1aaa866cda9b9e019f60a30bc9f3b8677a18c103e676bcdda0b5ee2453955aa5120bed97e8fafba11351cccf1999c1810a9cdb91be032e486ec4dba1ec0a60a77ad63d3cd0099302a966a345c6fdd2af3231bbc06f8e44deb7d14c5e9daa2e701a8e2201384570b740377d1e60fa7919f5871de87c850de6a6c5f2ba74f9b3b3662c876fd7600a24878458acaa3cbd53ee9f6a90beef21c0f20095f349ff192c1c9fb54ad566e08648e029354536e68931ac1bd4ecdf6f907a870ffe3d4fd0ce9a8608d06c0481fd63af169df45e6253469ff237c551c7b057e9c16cb05b52de7f2c9267d1126b7b834b086e390e08e9ee2f72311fa86378ad34ef223006093db18efcbd94b445ec0ec0f2ebdffce8d82bf17b3010a89bc1c3607cac5dc831bf99bd409e03cf4615664dd6c7d6f663ce6b21671065d5507ffc6396ca6e78e5cca1a75cafe1d483dd5d78c36ab28413a7fbc97cbec1921f5086a2fe1672d3a8794df6b9ed50031b561bb219e652801f645b2b39a35aac3f0b99a99bb5b8c3830f7799a2ba93c83bcdd2e0584fb8e2c650b78b40e3aa1a478503c044a8fb13ff231a39166591ba09431170f46d058b7b245549427a8049a90a3945817d32f73b26c34a70d25e40b9dd65116317f89549c8e5d0bbc0a078f05d853925aec2523785b328ea93701c3c6e2f7603cc62d0880180c7518a86c0d4459f0ee9d14df19ef1189ac07a430205d9eab7710b799bf6b2ebbfc593e007f9348d1bb2bf496a11bd3bde1053d1f83479c77f599cacd37ee8d06a8b4d9d98a9ff8083c02f6446d50d67854b1bced55ae8517458f17c160e71465ddeaa0bdb3c1c0dbcc4d1187b2786f5ada2f3e1290f120b236fa99d3413e523e07667d9724e503e59decd38e0f0f2208edd2e0a6cb46037ae0f608848fc9e4e026095e80056682a1b4941b70b8fa2e2de689b31aa331af99a02ea6f4a961ddd9d8f4ba04a1c109e353b6e366f7c8206bcf2d2edde14a3b7a553efc74cbdeb4493828c08d860b8c0203d7a5f0ac375d7723b0fbb1b97d4405ce2d1e1a9deb70fa4bc0e4a52b9243f9af69d9b03436f0536997d436a4cc9f8fe04ccbaf3494a8e5836ffabcd35df5983aa9cd0e82a1674751c095fa0b1eadf3fff8972e2f26dfce3779f5f28a8f1d736e26242c0839c87303f89e10c4dca456f4db1c4411aec5d6f77a07013b8c94c50b716b6ee346364d19d42fb2c2fcf0d74db3af0bab81b69c40453bb2bb4346463792e7f8beb0caf2b53e692fb3cc2443e10c45d031fe7bcba3e7b9ab9547a730d4f15fd957f8ffeb2ad49ff2ab787d328e9da40a370ded07245cb9d60d9388b8349527d40a23edb7991d0524cc9bcd95ace7fd91d23055974af3ab98eb98743f3ec23a5b748d6d7434346ea80c2478763d060c3df89043c901162b384fdcc699caa4ad95e82f2e7533cdfa78b1d13be18d42cf4399922ac91d53e4ead67e36218038c6031592a817f568fd13ef0f3f17ebdb933797c79478ae7f75ae371ceadcb9cfdbff8de4b06dcb866f8b8ed2bc5f4324909ef2cbe6883db806eac29ba2c97139ea72591d8bbf83a54e11dd46535785d32c3c2a7fd18086c6db8cb06793d3ae79b5bd79f617c5580847ed3b403ee97c2abd8e1c531ead760651095afb9f633a42521b7170fd4e3153a8a4a289aee06b9b8fad26058845315f5a550aa29843c9af698e084f7f3a2f341b9d05738a15893a87a80bd5702be85749fbc493912e242532740865e6b5e9636c979f66549f4e76e1c48ffec6e2d46ab2a4e7e1f9e11fbf54375f34f4a23f731ca0e950890e5a44e0997e029899f9f7a782ff7d41f075c5f965d1f419830fa3876ba15e9131bde0954ba108490190b5876d78eac45d8a605481f9267592554afc5a42df4c0b823c1d4300c2b38b99045d80d89b455d887fa1c737e10e30e40365521c5a51ea9dc61a222eb7c22e2ce0191458642f0989b5e72761928afc169fae55dafd4a41cbe4463e438b6058ff668c9b76d3fc5bad449faa756af57b817892ef631a29818771b7cc79687a91a19108e00ce916c195386c0862749190ab7808e23093215b640863f79328581180b6f5264a86d02283c922043f508f09c9290616110e81ce03cffb7b5156af6c56d5b03f4cd49eaa2a48956e8d46af19cc7486ccefad04eaf22cdf58550d02c4e7bd5cc856c413f667ebacf5b1e79535480ef0c6537c2474f7a9a8d8ca1f0ce40d9649c0c499a14b23382a5df2e9564073992f73a632fb97c933a761f56b057fa4503bb9146a7a34369bdb8495614f44c0fd8dc075341e10cbced916d530405db3ef8d43499364ea36b1767ab25bfbeb1e6d3eda65b2355e3a4d9e09d3eb9c2ddedd72aa154ef00cb3d5602b3060668a468f30059b01ab1e5a4ba96cf937ec927ec9ea678da72142331f820b3d2d2c01789eaccf9d6b49b0d8fdc29ddf4d6b795fe1c2e05fc710c6378312fb422692a0723b71001314ffccb20f89105755a6ca91e6365dde2ae21186bf0973a2c745e016684859f0cfffd9ea4f0713d456919a658fe0737fcc17ee47b386c5f29da1c0ba94496b5d86f63261bb80d755fdffd19fec7ce550356813aaeb56999f989b74d82a29c257e2a169fdd2014ab53ea4e04c4b3542acf2ce0ed8185d5275dcda4eaf82c91a613570ead10d18e9ec78b078e9501dd011b22b8b528200c57095b2915d80865adbf2ae6dc2482993def0f1d596960e7e06ef535eabf34f0ef2dd18c08eedade7aa5d284c94f9af90b60695e7917acf1a79286baddcd5d396ce35cd8fe52c6a12ba7609ad77f9a4ae5871a74fa4a878becd33586b492af82a09ebb561cf2458c257ac1001ae25379ea8ab0fe7c639ab216040393dcc64efdc04e7a7fbc31db518cce84db20369585d46b1655a95b8f1750a98217417ac2c63ca6bcb84a56f55b58d84536b59e387d2e18c96df18339aa59f65c94b43ef67d9d8b72613a181fd8e096f0506d434679cf2eaac9758297cefb58355db95c484c2c16b8c98192ca39db549bd6f60b7a19848cc1326c34c72de374b43bc034c3dbfdc9e6c5471ebf7668d657aff301395416e326e510c14e8abc6f4a8ac12380a17ca1e0b54aa972fafebdd79ae8337a813630006138e6f57f07693ed179bb1478f61555e80cfa8b82a8cf25c78b89ec5529fa7d1df547b32bc647e4b936c821ad50412adaa015949933cab5224a7c128125050bd2b78afce7756a2908f5a627b5302a25ebad2611c817828f21161c41ad80ca669b6410ef983926e5ef9b7729786169a07327929054122ce05acef4fdf6c1aad90a307c0abbbf45967856987e7ecabf7016129297b10006c245fc2cee18b1c0afbc1af1426218df677bc51aa98e5b514850f4ed0c1a0a2288726c08211dc6169a6ae27f7c65aa10470630a0d44f828282fd1b9da4f80b8df22a664b70036534e0e3c934aca71dde5ac130c7e685fc752775ac05b0eb2b82ce7e1260a4c84cd16f4e26c0ffa15bf093bfd15b9b54d330cba17a78f7d64d89b6fd86df26ea086477bc04326b5e0013b8cf7ea8ec731ebd32056fbbe76d52eb05d4afa9cd8417c9fcd3ab1d1b18d7977128c10155d0d44c4f9ab3f6f7ad732976b363d54355732417d7c1a09b4239a1313756c22b668267e46febb93719125c453c253f2503c525733e45f9f7dbf3c7ec7039541452ae04f1bbc0d5734d8746853dc8eabf7979f0fa0c8c7edc1462ba0ca35e5db90f15073c5e5cbb82a260158a54a7a9dce719bf51d7a900489ee970ab546fbdfecee29a04f645daba667cbacb9e72e1b0b724d2467c900d92453e43a804da9530c6a3398ba3a3f021caffbb21637e5070ed270fad5c3e548c30203f878545be7a638e37c7261c90e790f4c2a657abb11d533e082d63131970636c66ed04efe0f539a4fb53f7663f6ab61f1e9740b7372f56651f749148fcf9dea59c113cc0cfc02147b1463e4442244bebf82267b1a8fbfa79305cd21a9ab40633e261cb6711944880543f82e18878e11a6313232249fc1e84d56110c3e1f8cfeeed4731754e03f73c1d41c4f4034b2c865be2ef21967653aab2d4ef7920cf2301b01b4d43f4dcfa157f6e85915303bae4a8c3ef47bba44e6297440d5cf2d94dcf25ca6190aa1b5c9c9703692d4127397d110bea856bcf3430b6579d21626b0bdba52c1d224570365a22e5846aa8e45549629593c9d27ab91279af1a6c22ba1ab61653366b5c51cefc06784b24b9e922552599a74a5e8bb22a11f89b924f7ea90b27ac3599e42472b62731203b50c539dbd8ce0133d96569ee84d9ff887b56852e6e2ab6b8f682f9cd1ed9cb582b9446f62ee765cb3878f6e86dd5107f225ee0463bed900ae57293365f83f2f09eebbe54a44364c5f1203ef3eab19882fffd8e82ee8a5606a9258c0b82350e350d81d3ec9215a79b920aa7f6a31773aed191cb7d789802cc17db4373e029c2c42c1630f47eefceb6ad5c821420f2b65b47ce6bdef77688cf07b721c4d6a323c0c6f5e86bed55a6521efd25c241e6ea5dc6943703c69998efdbfa06fdb039a08c824d7f0361f874c671003c986c1d374f04bd830ad753d54b3e5a87f502cde3fc2c9e14b9465faa30a74b19413b44cfafa35efd7adc95a7f4ba1edad324984a00ceda21b7e3786219c8e1887e9ca51e1f22b25e687a61028e4930fa5e8d07af39807a68ff9fff246c5e470525ea967bd228a23448ffd94279a7904d07e18c899109a1c3939962fa3a2a2679e82054c5cbf28d19be861179cd3f5d1a8bf33299a6cf1c54a74b53b17ac314e57aa250789f24a7535744a2c156d8743f0a2bd6947d9a64f1fda6b92470a46806eded6a35a7509f4949df79b737c93ddaa199a5d7d1659767fcb8743342aacb8f57fef73de58418be820a4b16861014a438e770de85ae000c14498ab2cc7e0e0282f73f33a36d8d87f73e2b3a9960e628ff5a953e47cc9470f3033b858d2d4688fa83cb0f903a076a99ec46fecdf6b072a3f6e4b81c66adc255c7c5bdaa2ff992abaa9c6ee964d441b7c38639bfc971c2a11b4611ccaa186bfda4772caf9ca60e804b1ea491e7405f62ab1bc25ebd83b462eea1f76a695617f84da648c90f4c6f69dc4427efe1a12b10f1f6e70affdc70aacc1c809c4c8c050af9123b2f6ca3d3b187164384fbb72b2f4d911d3268c74d98c547124207893f54a39f4cb64181133f04bdc185da4d3247ec66bd6d6838b03704ea86d6beb3e7ddd1c43dd6de18bb7e69da7c3209c20e7cbdc9d05dbaa6ce7487b43f4089f32f0a0925b6120f10f4ba818a899c079135476bbf4955350a5dbb33d262491cde7e4e7f2e1b4a6d2af1ff39a1b7584a91fca0deab246afd411da56cf30dc1776622b5d207aee1e8e863d957f11981ef1694625c47294d7c7031d06eaedf4d56c697483c822c00824316a5d631a72491657c9d8e6161555ba53646e99413a2a34d3356fc391207be6b206e02a0fa0989789fe7c3c4caa65b98895e2f70e18a7ef3e92d42e91736465a10279c874ec4e6ce66941629921ffa64f2115312661e4e4c9c24811aa0933ca1570b2670823bbd68c3280b8a7aaf3fa8cc927495e9f9cc07e21058dcf590ff8362bb216a31c212f026083a9aeb61f9fa82b21c34b77a9fd409fe44d4bf134c6e721c5b038c9a5e4c2c1051d38bb5cfe8286a053739c78d98e2a71036441b79aeecc8185382eb79201b3186f05e81ffb5b07d3678cb8d039fe8ee07e01c1bf1e3b4dd6a6154543d6829ae7551142df8b6ad96660294a3259bd8787bc59042798d99ea84bba863590cf635df7416225ee8ebaaec3ab546c074261508817074b90cc64afbf7f58960f723729ab6ccf28df458d9a6ef7fbd41d32a361cd63a45c3e4d3e50267fdf830277308c36801e25ce42fb911f098af53e7b640ea42a0e67d9b36389531ea644ae57071260442027e1ba6fce909b1a7542348acc07240ae31e7f51951e12b410f1fc692fa463694ee1d9d28a0fbc7e849c0915c79cb61dd6a994b1f578e1cfbd72958480ff629ae15cb1846148c29d42000ccbc9331ce58571220f553b4ecf598e218f93bbe9499c50f539eb9a2fd69e14536ebe3ab672a2cd52abdd182a444e31bf00290eb380d632c995b77ce1b9d36953371f34ac2cf6b8e190fdf7c122bc8e4381114fe7508946d408d529a2296293726a90b572771b70ce9d3d5eb715132fe4829807db98e5a4d3bd7b62900f7b0efc56d2de7fcc36281927a182f2df492b66b6c93af8bbfb5275aea97ff9842309369d2f05bb10c8c31f16d02b7defa38d8e4f0b284c5da31f2d020bc8dfcf232528b383a41a6c3c94c88aee81419e1fc87be4dca58b411395a78d95ca9e25311a5cb0ba727bd5361149d058d70044050821b927f41484354aa7f54486596ab417889d948bb278cd5a2f39b2a9f1e876a012c4ce4718eae9ff6d57485a44fabe08c6c8f9293f5a863ffc990ac1ee55854c86cf3911fc4620456e31ec2892ae7fb154b3abcc57c5e7e4631f4f4b4aa801ed8b78cd73e43486556c18e6592b5adbe1cbb939aab698883421d638b2526752aa10ee724a80ae04fb21e1316a03aa3f5c09dc61aae6fc7919b156012081d0951ba23f549c0c092fea4cc52c73d05db53214e3f083c59dc76b2e8d7c9a2f6543dc0c704eb076b26308c66aff75ab799ee2e5910f4d941e5ab638a231927d90df446db478ba68a9f41a005a7bbcdd26699a903e16d8159c870b7f695b5f4f6ebb8ce3e8b3902080ea6c0d6f72b908ca8e60a3aaedbb897eda80b45f8fe7916d3ead00612e46fbf6232eb36814d0445b960f115b627b1640eb42ecaa201360ef60b2c5c0426cf30a5871d1a11ab0b3516fb48e7d97c71e4b549ab361fdc18477c1b2b080580814303f638a2eae917d54530aa5f2c295103ba488ad898e778002318f34426223c99dd65179d6e4b8d43221404c2f11a08ec3c0d4b36fc491e74aa40f93b362a82bb81cdb71bd622a95083c12537cbdbfa972c1e3947ffefa7d0680ce882d44a8811b47c5d8624f472829a25d18a8d3d1adc4aa7047bb2691c3eb6eb0e0b1dd5ead171dbf3f423562888dd0f66be52ec055514e4c745b06d0f37358052e1abef712f4a26bcc7a8b0b895220d14faa8ae7a35042daef35d910fbf74bedfd47c0e51cd76840ea24b9770646865e0e4c3c415cd7541cd123ea765e6f5c98a40997f8a4ada5b36f9a8f705642f71c8518483f43c0fd2052ff5d7036d412b2cdefc02b3b6bd99778cdcd62228f2ec8a746b7ce18dd52d09000bc99cae49b85a9e3515a45a4a04d1d72deea9077b70709d9918885b291091fc4c51cc30e29f63f382d3a1ddc34d7e5c1f11128d1f2c5c8406809d63411e3126175e522f08c3e7465da6579290ed584e8af1f89f6fff8106e70e84847b09fa22a359965846afc0e94df61182e2bb8361b1d22740e8ae4560541a5a6744af97bf8bcd29d24961a8c59af70b5d2cf072c074cc0ff37d43a09163bf28a94cd4ad81d671821d4467cc34ed69742a1e255ee63281cd9b34f11d9a679a82595f8ccdd895d80fad4f538c18d36ee7eba11cbb80f5098a1dec42eb3dd885d6494486920351499e0afc5a1dc2cc6a5b160ed4be1827633d8336244680291c84b182c1824860b00acace00b3455f717bc95b01ce12cb5578fde310717c6b029325eb20cb94e13f5d64991c39fe6ad890248611e52feb74c979a201f202d927b0bbc0defc74e69ee18e950844e312a7a52839430bcdd0891607a1a7c0d3f6d6b9d01c6087f6f6406ddca4122b0c6618e10d552301ab75f3be8490d5ab4787234a66d2042116487cb3e025290405e4e4c994f28b6e082aecdb0eb015862e49d343d45bd7d48d6507a2dc06ad5984093d46410cbdae2923982c2a4bdd489516b23daa8e77c509ae8ffd785f10349bacfcf8ad60d6358f503ad980506fa045334e7e72a5b5124f9804b45952040b562d1471f07c007f7110a1cfa104c2b6fcbf53913376c538884731926f46f8d46319767d3f9110f1e4021790c317166a1f9d8b8ad0524711d210b3f8ff3de3750edca8cfc560c0da978d05e7132483d755ab8792bd9bdc019e194f3061d5e9f77143d2f4ac3aca93f0432958439da2d155937d261ba5e9e8ec85e4a9816ccc15a0181226b5607b00ab8f73f6df0442a66ff98650dd633c88cc2eb935acab12c4b63b7ddfe6cb2d29c73f027b3dda52c8b6155dcead499d4912a56773d1425a781b0725fd2d37148f6292f50fef0be74156a51f0dcc738babc3dc131a46ec33464404386b5c8302c5c62e15e0522dabf4d1c034f13e15803b0a3e6ed083876bf84c35f63898cc7deb988b878394eec03456230abbc66eccc680cc7c3adac8ffd84d61b5279fdea0b7bf9c0ec6d87d87ce496d4c12de7be0948d0ac59aed02af5d03f7a1df9dfaf99587160b7f07d9765f6cfa51905bb0d190cf5e0ccb007ca646fddf3a9945da5b211d9a15d7b7c1987d709a09f5ff02698bcbc81cddf1e8b25bccb0576f4f6c55c1068eac460ae6ff3294635a68d78e78b458fed54049fec6ae5a22e508ad9365f268fc3c518f6e0ee62ba7d5a89ade4eb2872899ac0e61854fc6874b650712a0eeef1c03c07efbc28d37e794c022900edc4e2242683c416dd61bc484eba0e7bd9e4f2990baf692b3042227cc146318d43918df95b75785cda6dc4a400e14969be52a42e72fc39de61f3f985d5ef89f26ca3a2da8e1c2164719ecc3786939901eb74c5dc49c41256a23931f0cda3c286f073e97f36f0acb318fb6c34e23e947115007229472f1828d47982b16c7a5e8cf4a6bdaac8562f17399405ec7bbdcf4a7ff0dcd4f07e6eb3e9b99cd49aadcec877b56c7063f23c36c5dd69f083a9b66bf866b8fa89166e1252bb92707581907e25be8402919becf3463e901c6b97773ab1a08f52c0dc1a0a7efce4c27291889490d8f7d477f808d3d5ef09d374d94569ef0aacf6cf091098e2ae693f99f2b131c5029006ae9ef630827a06071b4716fe2fda213079478b6f2a40f0def79320152d6d86e5aea6b7fed30cac9b3a45d61bc19001aefb92bf63a93a6d7d53426515884ab75ebaea4a37131d744cc17f309309f785a02d4f0f192c0d19f69b80447f840cb5e0e44e515d81c9528187dda1510746f1bcea23ee1f5739fcf4282026c811aabc47612b5b4d646bfc8d715c476eae62b671ff2c58f93fb4c289b04edcce9b1b32352b4cb2bb5ab54afff6be133e2190cc6afbd3ab8e6f77e8c335b57273da05bf64fbb6d0c8b4d2090893773c0ef3c5c034a4cfa765a3016daa80309f7fefdae7bb055ba7f3f47ba44b63af77f502ea15665c62c51694d0500c7624cdb0ac1b20cd867f318e6e75de71b635e8de37676ea238b1a1abdbf43ecfa8f32f77393b9266d1e1f3fc492bdf7de524a296592293d072e079307b9698ccef9cad40aa98550968f6bb48d83352c5883004de0f8ed2629b023dc146337741605881814ab294bec0b2cfb0b11d963ede545d9b75bc69a57f36a88f404df89021799d6a919ff2b1c651b3ac0a4183c35730cca02dbf880c387c1e264044ca5b3001a6981adc8ee57b2bfc362dc14ef699d2f1ae50179aab58eebfb1def5f3ef416fe1bb2372104ee40f9815ff43ba17f0149f1f38f1b2e227a542911b8237a0c9222488a01e65ffe070c0825be0ddee387011bb4e1fb17520cdee3ffe13d065b9e5ec05893bfb291c396dd8e2ba905908d1cc69e924f91b9498ac7dce40e7353ad6d5cfe21898a5f74f11b7013484f70f41e2c701857abd6895fb44d91222b4f8118d9e3ca4a6d476cd2a8d27f185f0dde8b3dd65a6dadd6bd56ffaaf732e5813b42525e9dd16b2f30ce7193914cb7c7c9a078f18bdf1ff546a421b0d7f0c13403ec600d0f81717c00b4604011311e1e6891422523cac474c97e2fc6a3d1bfc9d4b2d7cd8dc9e492e404cbf87996bc7dca24eaca3b6553769f82169c60388a60f85d89f4e3236549755e89f4e3eb2027528848ed7c2029bef7dd0bf9ae486d3f24d5518fe4043748e71cfdd7c30729823178eafbefbd47810baef1138299e54aaee4cd8dc9e4b31196abecb227bbf4f16e8747d39fde0087324bf62c2515e09922703865a329f315fc290b648ed399d404cf1c9a60b2c8248a87057bca3acf1e70caa6b8299cb2d9e338b239a5dbbe1ef33f080c995bb0c421060ea7ac25a32dd994394e96517daeaeb7284b9ebbe9cd792f06b6b85a4432ecb0e367477661070358681c1a77c4b62277e4a65186eced7bc170cbd137ee5e4eca7b6ff732d5b5785c54ca8e1d2a6bc5abc0b0443b69fd5074ef0d6eab02cb422db7dd18c1d073a5338c9e3d87377757999393234fafee99235173da0057598f29397ab7951d726166b084050e73b2b390e3afa319d03834e6d09e1c1de4d44a6d8fa68dc6b9ef1f5d124393e4f8a14fdf2ef7dd9cde9cde9cf37b99fab612e591d236323ac54d31476e45d423d6d608c83c1f86d8f493436a8c46a80fa6b9ab20c9c26ec19ebb0a922baa2099a2b391bb0a122332931c9a66496cf2de2b3d2677cea88289f1daa8e2d1800b4323c87b791e7ee7fd8e53fc24e3014fd0db89aa163089e29312225b10ab2205f34ffce4df4dd9cb3b11987ff918e57bd307c70df7251a2214f92f7307dca997c791b7ef5efceb21fa2159966e104c7f8a80660cca25dc4754da521b18dffbae24839b9c03232cbeb8e06d6ee10c38fc659825262f5f99bcbc7c0179f460c9fe29d4701855dd7be738d11557339b94601cb9be377db2bc91d2fb62fdbe1e3832fdee899b62a9e3138c599e0ce190588ee11024194b23592461d8defef6f631ac076fd6bed7849f37969c9265147d2c6df6ebb16d943e7def43a570061cf9035f00792801875d0381087c012fef5fc38ee38433340d7503cc7d17462fb27fe4894bdce49fc21538ec9f97529cf9498a8f0b8830252895c9cb6fa517304ef1530090e0f046de8c84c03c242af2a41084c3280b5b369b531c87f648e138db7f815ff7fd08fbac1a3392e00d0c67c871589620e9da18c9b264073aec80a787942ba1a2074c088308294029ff28a39982c3f8f28f3d282236d58018e316638c31366d8b607cd920c16194bde4d706d8b8008751166535005ce942d03dc7656e8c2e27ad934a8f76bacb51b4b9ab34c79f2418e20fc9325b2c59273331a74471cc39e73b0e4d0ce59cf34682352e2d9d73ce9177bbbbe577774ff9a416b6900694b2939e3f27a3c805778bd7eda4d5be8ded25f62987934aa74e7b544a1dee31e67829a50cbbbbdbba94f367947286b1c214399cb4941c7e32a9bd75b3b74eaac506ae30e55a5b5f745a8cc3f3bc6ffbbe2f7467ddec7dd559e766afc7754d29a5b36ef6be2e9d777610b173cc69839cf3be6ae7a0df35789b683d41cd723e4c8c9c3535e67dc5cc8f91326e639b6afdf893d6ef795f95caad52a9c536e7bcf3a3bddb9db4ca174752d29dcb49abbd1bf7f5a0cf598fbb37372af4e4708cc3a675bc80a375ece33a71482e832bc4f076f3c2cdcd6667c53836306c2010e3f03cefdbbeef0bdd502824aa691d69abece6c6f7edcdf04a5d69464bc12bf244221c3dea98d7f4fd232cf3795be7d87e4e6badb5965ee9f2fb85d0584159e584818991356c8c171323657cd6b0218e94d2992738e9b437524646867b594dc3f4cbd4efdf5a078e392e0d2c70fc8e1bc1288b6094e54712c8975e6409c6b6d9b69742b27dd96db3fd967b88fde1267f207e8a3a22d039fc8124d0361c049ae0f8dcacd588810ff672574102041798cb5d05c991cb83b7dc5590ac381d7097bb4a0f63541ff097bb4a0f352099942bbb5c151d544cd08c30a2c4c7499197121d5808c20583150b3288f1b062c1355bad726041c92a76f188e6aed2032b871fda625b6e555e77cb84136890c39b1a0427b02c0e628c9105be61fca02509b8cb4d450c2d6ea888f183160071371fb0979b8a1851d822e02d371531967001a6b9a9889184037a5859bb552764725379c20cf2cc5dc5054be47024f33f9856cbfef2c399a0ec4f03032cc3048c672b7f23368224cafb07402dbb0d57f6678013f845830b318da3c90177b13b1402bf091c5618154564b3eb9e87c724ea0349dc0f4985401207fa2082679806f3507e841effce0e941f2ffffd0e941fa2870177448fc11d0c86c09d96a79d0be2d9157d68fabe53f8c351e83b85411ff224f2c94c5e98e1b0ca2c886761956d205d65cbb1726822816d0e2391a7200986fb348850f1f0ee96a69b28489a611ad0cca7abc8e18c1225539fd6a913966305a3cb0341e0012238c4b31ce99478967d36fb3b64f3d010baae096f72dc56b5e3d18d2e787e389a738e7a7ce7dfd7435ab035ba71226326c30a8bc5922f5b9b25518da71437511adfe6b2fc842feb22699d769c52f6bfad248db241f2e42f7360595a9044592d6c2d071b6465a14ca5e0f0b264fea244e0f8a1bf2eebb25a27d2238d1ac593ff4d620aa29bb800dbecb008de234847f065657f5b6f08e004d36f5bef779decf2b8c925e5b22e4bc6aca32263c2137d737e736a11795b6a5990e045169157040e2bcba7b61c456b2e47d1203fbda02bebe5a8aaca12754c9022a11e691cdac5ac2ca0ca9a4059806240b11ec464b13963b1586ce290e7e343639e4763b14ff4bd44b1582cf689704c147a79997ac11f6df1b896bc44b2cf4540885ee7ee34667870a446709a6791fdbbd7dcee064e3ff9cf58cce1a47403d3a685414043a362eb477d43b728f530c6bc8a2a7208620e636c1459ad58eb24e98e41746c921d0c3939e7ac776b9b188bb1dbd3754d68ed767dd536be5ac156b0150cbb0c870e5bf96ad53a455a27be731c0c8cc3425f7994b681b58dbfafb655f6cd9be80be25602123c3b2ce18baf71be0c847fc8fe9e2477f1ebd14dc80e7b997429250c6667db6cb2260ff2f290a7573b0f594c124b3b4aef25c168b210b2c72064ff1e2d7f79ec058b32727f30f80d99febf9c732e99ac8ba5eb9ab073754af244852497fd43996fcc510ac9a863c61cfe977a1ef53c29dac63f447d2896ec33ea88ef60778e90f620fb532b9e494e3085f9e9097db9c96bd039fc99cc5ae992b68982435aa34b821c4567ae7214f5f15318adc37b7f5a6b9d95a328cd4f1e487bd039be681c4aa54dfe6e6b1e487ba664ff484b38e0b0b6eead50b27f786a55576dc9d34b2601cede87312dda2512dc5c1d3bbe33f43d0fa7318ec6fab349016e398efc2a1382f9b1f3484e7004e91237d51a2a79aab66aabb666f2a51fcee4f07a200db14b0e95a04ca053a2da0a9566aaf3d8d467e803f1cb14067784a44460cb53acb4457996d02044952be8c9d4ed5c9e8b6ea032cac47dbd676b7c29df4d2e33c3e1e714ee2a32909269ddeedd6e0b170c672e6d381c42236bc133b44f0e3fe0fdf6a252034a107053fcafe4e3c1d00379c8213b5104ff04db1c7ab9034d3b39b4cf8122f00cc3f3c39fa176d30686d3beac4f30c531060e3fffcbb6264b7aa260ed200bd8c3e383253e8009007bc14484c1226cce396788b16b2df94a543cd291e512c5ec12f5f1e45f5393e329bc81f9e867e3423051701861eeb2b463bf7778efcfc307ca03232b8cec5fbdb73d73560d6781cd8594031c36500c3625186130304c8047a153681cfa08987fbb39bb299b73d2168f0b06c39c7f58d4bce8afb941a174ede6a9deb95cb608ba9212d23db35510a9ef77280f3fa484d0f841eafbfeff4a39be827f4729e5b81554b82815dac65f052df00b3d366470ae953232054e66768d32b4bd731cc7711cc771dcb5b1e785daa57516b1e4b9736f7aad5a1500c50e043c812d9018631c8d9018624a952754b8c4d898d9b0722fc6a3115699b0ea656a1d77acba17e3d1e81fdb97610296a9ba5a2b0909d21038e468d931171c62152692046e49bbe50cd110bb641941d882d9bf09c494fd58ea7217bf0788b8b8c9ed631566e11656e195fdf838c85885575f0c326541ac8a3102abbad648a9b42f53d6b6b00aab6ccc3a2b4259e51e0fa52f37359601008cc3007df24f0096c9883492e048bb06d804b79be4cd121d5881658ada14489acacb8bbbd7788dd7b84ba26a6abce646eb44240820a26212e2c95f47c71c210c0c97c3a825aca9b552afc6889a2d77d4abb9c9ad43f38c11b87d64d4c2c2a1bbdc6ffd584b31b2e4290412208d7a8030d9004846b058ebc8f7f6f1256de3ae9c4929fdeabdee72d70b8dc3d275dda53b55bd3259cb64375f0c9eb29901bead3ec5a7206cb66c1e4082584a2dbd31524aefcbd4a591c7a501951f7bab9cd48a946c7d20255b9006cb258bc03309868fc9160c517053b0b3caa7d6dabf17ac74da79c150d2c85d60097e40beccfd00cfe12de19b6dfe807ce9a62f0c65c73563e0d0da4983185a4c16aee9f2e9ba9e6bce2953c8fef3d53a5ff69f4f1c27e2e8804397655acc966564c6a66bbebcd6413914ecfe04860390437f1201fb71e5268f443c7e192849f6164dce8d2282434e6afbd54d71bd835bc0ea5251c0ca94da3eec1eec9099aed284cd7881a5576bafb5d73e0fb7d66e2f53db666fdbb4785cae181ae7444d4867d9638c52461965680ab8c5ea0267c115060cc95d2b2527f36bef95ee5e655382787155b68bf7b81597b9cc652efb524edb789ffc7ba8134a7da4038b85c5a2755a7e927e94524a297599cb6e9499c9587975ef0d812338e7e380495bf64838e0ce336509124086438ebe7fa8266aa27168cc45b2d6994f9568937f289a92fda913a12fc27a84ba94689cee98e3d0207a5ef96f9b982638318910f51cc90ec604b58d3f03aec0e1f7489704e7ecff5f660646ccc28b2a57b090e477952b61e4ae72254b6e09b610b9fc92a3e8b1f264b665266507332b2f77e18a9eb451376a664d8dd609fde444fa618ecd398ef3f9f89828a35aa5a452d29c99edc96ed3f7ab5b5b6bbd60e9b6cdcca183754444498368175a9327a735896a5af320a29c5a8e44d12ffae44db8550553040ebb5548578e2341079f8211a38e0892e05225346a64b3aa2ac84ec80e8246511a061a95237f64e81db49f1c2d8274abeb5de4442183807e56124569ad5b4590d6b69c9c514eac31568992e147f64fffcce0e8825544b8647f5aa34134b410f3d35ae79ea23589eaeec5b4d6adba55b7ea56d9493ebe1f921292a235afe44cbe4a59485a3c355aeb60212b2e25597e3f6ec0911be4608727331bec9092dff2af942d7bd428c1d29b66d13da303a61fc1766fcd5c2aeb7944c016c4a3d1bfc914defcff9cde9cf6fbf3617978582535b21a265e534e191b05f30d03de1995c8ae6c110ffd382af2b82ab40abaa12cd9b5f06cc9212a8daa301f867cb287ae20c9317263e2f2aa19fce4aa504f9e69cda86656aba8a333c292a80f47a20f3ff4a1e99b51792a2bf0b4aa19b0199544d1947f4131877f9df9c77af06ce4137eb4ecefbd1439f4b4783337793ede8f476b9b2c406e3a228796c7aedac66d913ef957207ba402654fc18056a5b22ab72b1818181870a6070e27e0d68c2abb4a5523c3feb1a08b5ec4185f1e6ff7918d9403ecd9e3129e6ddbb60d6582eda6071c76d0f7f1efbbf44a343e60d2f643f206ce2cd9c01a6a84c09d5b9e24d841b42b3f24c9fe3b2bc0f27321b298601ba0c4cfb3f7a177f06385c06e1fd412b08fd740b38bde73c088c44ffe219efb2d79e2136f90d41c601981ce92637868495202c7fff85d25b0ccfeb124f30dd99ddbb66edbba7bb7ed7edb7697b058b56f8a16ed092c4f004d175642a3057905a179b41fe099438f526a6df7352a034dcb2f281e316ee172c12056e00cf4001e2cb8f003e9756e5f4a29ef9cb369415c56f8006146162870e15c8e638051ad7506408de49022e1428a2453249c8b7b15c1e1e55cb246090e39176d39e7e25c33bce8bae676bc6f77c0be03f6ef1ca50d1538942a1c6b6d0862fc1ead5a27fef6f2a58ffc719cd9d336520a2c59ca0c20933819a0749a517a912a227e922f5552155525180e5d4b8f6bf1da160f7254bbf7384e15a2881343c8f28796fd474ac0db73cf813648c9c30f9004f6211f887c1ef25f903be038630a9649d4a66ad9b24b49c0e1c87de52c378244d25e52d5257b772a55cec35b890621f93e0dd15a6badb5d64e4f4aaedb46dc6f922ee1728320486edb77dbb66d9b94dbec400ea4ad6dce6d4e54c93f927c8051f569d847e5340a95bd398ebee4699b735bd23e4044b2eee4cb0e58e143163700197179c1a50a2b74b08205136eb0722943edb500fb01a3053ab07e6022c8185a544065084e7228522b07ae5c8905a18758159869095ab2588293245d10c1da39db41105114d1042798e4200564f645cf154a68222528e58f47f70e40268513ba50828b275452fe9364892f546005079e6ddb46577e602d01450f530891f2278ac0250c16912955ec90f2c723514886da4d5c177aeffb3ccfe35e4fdc24fbbe28220b0f58557e666eb06ef090fdbb17cd7788c3518679c13460cb1910cbd30cd85de1029645123533ebee9733b30e0c7f66662998230c4c676a3333c72165ff199fa82366ff991fc7a14914fe0a86a61ccecc2418dec870661667b0e0ae71a56d10e08345ff7d38338b3839b0a8c3db81844c92d611a5883978645c32add6b93e0022ce423289aa41f2e4219a44e10fc542b150ac445304d7a090128d82016d0d92600d8a6090fc7a70241e606f147eff0fc5240a83333ae8933f3dd1506c060a39339b91d236fe3546e017588e8fc1298e78e508ce605b52b2bf6dd99628c797128698239ca18368ae250f9c81954439865b8ee3cc14114d334864ff7087911cca2cc9322e191e99961451874c121920a214af1c866a1d92c9937f68e6a11e4f613014932757e53014e3810c7ffc2a305318637066264f0e846766d9dfa59418cfcc666637582187d981c543f692a750e012ba3ea7ecdbcb8c2e658f5f0bd5da3a67a5a54ec592e7990f9610a4e4f0e60891f56f02aa02d452dbfb8c18e0b83d123f37d072811d19b114f71b5805074b72aae040851d5ba9fde569248122f860d1c40b09134a8628f10418b87a8083289a20d25fd3170ab060852a41113688c2e3a2010d944839ac5523e20a26c4c821e57f2351fdc5117c48820b1030c8a1966a40911911ae2574b1c511523eef9cd7c692676b37f0e6c60b9195394319fb8f6496c0b76ef1ebe6e45ea6b8edda8ab1e807114d94050a5c70f804485929bbe56bde3b4ba71bf94ac0f6def82fa25571bd92d9ec1567121589109911f948a46dc2f8722721812b2b5f22ad13494360e786b01f4622443016c73e3815f44efa0c712f53a357cf775b7757f214ed91a8d188f68c68cf88f68c46a3d1d679930399785b4ba646dcacfbe95e2aafcb9128af8b2f7cca893c9073ce7ba7947b848645c343adf5e57526513535b39ad956aba9d26a609589ca8f909bca185872ac3d8e1356268e13565996394e53e132c5715e4f1cc75fd9b1c8a197c32a933132691db73838e0b0ce6473c659673f5635ab3e5187df6057b5d6708ae05aab5b1c67562b97eca0040225904f9de580635eb97003bc8104df60619f93df2a5d90fd7d148151b28b4e02c1e45002d5c82e1a55af0001ddc001bb116de36f0120bd83935a6cc145fbd4993cb98f042b2d827506f3f3e5b086db2ebe75566915a8ceaa0fa5b4ceea8c86f53225465595357aa25010891285704480113ba6571a1e8d5e60800276b4ceb6835433a37574e798604893d4e0deab91c3d1684e17bc73617edf37e7d7719b6c0a8d16648bb2c844500d3e673745333fe09694f825af2b47e6c4992d709863adad350bc63c1188053ac86734f2d8e209a2b3d2597fde6dbb96c75543a7c2e19d9be469ce1a1b26b8ddf42d6bbd773665c24fb775ed096822a703735480e2c3518c3196bcebba8e7b8d5af0327bb1e22c16cbc462fd777172397cfaf5f8deb276e40b6460858b9410a9830d5250480f0073e80e059454e8af96b3bc0533ddbb6854f42fbc0972e5efa1238d22cdb8476992637e2381b1fb91a8b1b75aa7b64ef7fe1ea5513126631a83314fa28968852533b3c1d8f08b5f9ef529e4d0592990ecff90f134ff63f4314fa344f3334a311f49a4df91f91a323ea6347a99d20e941f313f03eecc7cccefc83ccd5f89b201ca8f9827bd0d34a00d507eccf8d1db40e3657c8db72106b461c68f9ef4118c41c6d33c10194f03ee40f941fa98dfa1f1354020a38f0177663c89a644e3634a335e4a1a33420fe490fea824a3d4f244533fa6d4a908248160700a3fc2581481640e90bc21fbdb985cc5f22c8b9b68fee326c7e2ac92cbe4c95fa6e4475288f24da4b39c0504c46a9d2eba811a28da18ad8d79998a017784a4626c4c696b9b96b39cf532e386bc38cd1318c360b0d78c31681e9e39a7b5132651d3f18c47b44e18918a1b342a27f41db287be82ec611c638404bc45bee2fb30ea207b1f462878aac0e1080544721ea74429b0fc548f5a688a602012951331b8816164c5558eaaecdd411f185e0f8ca70e8ce104ef08e6feb5b0453b8329889b5c861ae0308707954a29a54b0a0c560bf96008b4aaa25d62087ac88f4fca8094946ea06db604c90193e88724da5c40d5a12805f4c97fdbc21da4ec240aeef05cba82c3a6d198529e8254156562cb1656dc1cf7e2dc1b1fa068e9c195430ec6480d59c28a105c7001820ac02092f26fffeb7ffb6edbbdf7b64dcb4d3c42749287ea75b2966e24ca036536461965ade3ee9d9451b6e326d8116e72e130d268d82cd1e2389116b3d0dc80b7681d241865f961e422cb5a470a1d518bf844eb4422c4fe6078c9b20363163f398d86123874200f729c30c2f216c701d2e23835c7a130898a341a2cc67680c39b189afb9335f9eb01862ea594b2dba6d2dab57685a13e4d0a702cd1e45a9289304cc0e14d053cb0a53c5520d2684037ad533f47d976d3ddc892c8e291cefe059239449ac768add3c4a572f3956ac170f4b9b0d5ca551b5badad6f3f6b294bb6786834160c96ee87e613937244b758b52d33f40b5dd336b755918bac42860c79b1cbe5baaed7cd8dc9f43f1a614caae159fa1a6621c93c5a078646dd20fae4df24bbc3a84ba26e6e4cd7e532c514059fa0810c9c480941a10860a43e2a9c90922693cb715eadd3a45141e4c9ff46c149646f22fbcb20c1e175455587df86eebd173dfe0a881ef3f0eb6a1bf7ba0f9b865ff440bcef3eaabc5254853e3e06af2bac2a520d4730bc526ecc85e42ba3140c5f4a2925f8811a8a954a4e7292fb80fdd835140eb960289f860aabdfc592addeeeee5d23cc4d6e2b18cb32155712d57de81ddca16050418518aac86acd2ca1520c0eb07f2094f8a94e9ab2602f77048904a149da28779dcb55876c0e0386d7bc10b58dd1466e8b92b3f6f6b5d6dacbc35dca6bbb678c44a3156480c39ee518cdb0f8749ee32687aca78bd147edc5881635a9020d879e0c4f1453136d4829e59c1d3bca392795e2f29c00c382e141fa4ca29aa652a98448fdf8152b683e63838771dffdf65cc94717e5cf7ce62687b9cc7b645813dd64adb5763683d9ac04e1ff5fa23cefbdf76450fa42ce9b22283f49e93f115d177ba56d197ee1ca645890c7152cabd6d6dbc2aa25c42e1dd4411d54430dd2a54b972e5dfe67598344794abaf491474aa9055a0ba01b206de36f0304ee1fe57e82bbfb5b8cf5c438cbd131c127e0484e0a7262ac602016a0bf6d2f2fa4488a209408aa6e5c8135f0701821bc5a4ba5a4f276500daa0ecb9c4d2b2dd305d3afe993ffbd18cb1a5a12705893e5bcdbb710fba3a147f72dc41c7d071c76adbefcb026d36a1ee43407a2d1dce4b5a88a2b10d4403323050e6b5ee07cfc00e2a6201bf00018d64ca95e9c31ce393db045a3cdd90d820d7e7a884421a5462422f48540cf85d67129a594b6a99594058760a8c0918806be3d03ada33b47a4df3ab5678b2b9f28a8a44dd725b5758a4600000248b3140000200c0a8603229158482e9645393d14800c718046745c3816c883490ec4280832c4180089010400408000293335b40100d688641f47bcd21826546ccab075a1a8e40fc70265770515f872359336cdd01c4069ec4512aa6d6c9d8a2fe940a17ecef8b88f24e73888aa5a24f84882a84692489607e5a92705158de306af000358f94eef8037ac760cdab4ea0b9303d82c68f994a4ce9026c3534814d8bcd0632394651a9c15e4773e0e76d863a1f6fa40427bd0feb955288e2f4129ced8f99e55c654e8cea9c3398e9b7175b3f08741a35947f3319cb03ced39d26209ed2a5373b90fb47f46eb79c4f82b89c48813c0534200edbb5ba0e354d505de83213eb90dd4381dfeca8a305a3185f5ae37a595780d4f5976c372c2a5e85c33f717a3e530ed7ef514a9b609c56f270f4cb9c909b6630b6a148c5b17a8e9989a410fd3072bf135e8919a5490a075acb95b41803674ce6c29f1097ea3299df8217baf260d87221483947083f36f59bb5f56072ad780b5ce0286bc067481e51777e485f89d3b9885231b70b51eb28b43e9f1d73460707f2375cb40432d07381b5e500b9004ab20e41c4bbd71c3b5f0948eb01c487d173e0d3590c167b31d09612f3a41ce37bada04dd82a7cf26359fa1b354931b378e347efd7770f0464f03d0f36a14a64951b529c4af6b7dad80d7db2fe51db636beafdb62f23bc9dc58e542ed9601f626f9cab44b23e7004178f7ed87652e4840a779c03b41e4e5862d89de647cace1fc23993553b173047092be24b4b4c3b88072c01923c3c540fa1108566432f9d0b540843de44a893d818027dbe44deb39f69164761e45529b4c327cdb905b3e711aafcd5b6d2298110b73002d6cb15fc5b40a766eb8c3c2a1ec811faf3127fe9d8a4e7e7cda067b28d7f8d28cc78167a5f84ef4b913112abddee2184b99a5cf4cbcff73290ce1206fc2b399af441e77e709dcc439584153b32ea0f24b655b7c579958836853d8ea4bb5728a60842b7a9044de041169f0e11d0c81669841f9302cc31473090855cc9a0a94d149aff24f0dc1be3ce582e1e8bb0c2fb02499bf19a7a48ca794f4195fa1923f36e90f817fe442c45e5cf8b14a4b69618358cb6688c960d0a18f7a9d088c968e059208b570dbb8cc56f4d6d1894a712ad1d54a6f1ba29f99e7aa63d28a2cdb754d180815996955d1add38e291f516c7980c60bba490c015d1e52af1082a356b92f228264128bf33698b00251ded7fa4b78cbfb1bf0007ca1339b82e0812655b7ba5a01c7f14d8033570ac20f25ec59e6bd8f41390d5c918321796590de27a2f72ce0ba2183c06ac310c80a4d2c1363b3c69783c741299b4b2a32e6b3d27f77a7e9879a9aefebe08e445f4b6fd3c326e342f8b4e7436afc39e60a2502416567f3f0d922cd12afbca64fce52e2eedbef851746e24cd2d92367bd2018a3f8eb4177caf23a3685ecca07179b0e2779baa8d05f6a0026a9e19395732ae811b3eae3df3086d3662e90ff19a58c44114850a6f2b7917e91ff5c763244d983af00750dd93c582de5161a933ad14f44cb54c73f8934d3bfab484625573e191d85c2a78a7d3a7cc991ead503853329dc6c60777db4ff2176019f95f01bb1865994cf0ebbc889c5ef2a079db676b1d857e736bb810ef929ad607ba33c48539d9f9b4915b9d5d4e7b424c2549afae460f37938e8245189d8881f4a1b7e3f7ab34efe09f94e403fa02139b6dafdb5a03d3e19535a8d6afa4f588e45b780acf615fde77a73c4e93a9fd2fe6fb802bbec759cca4859609bd035c15556deeb8c60d9e7600b3b9903d0693be27d5356d1a11bc9d1468d559c843fbd53e00c04033c253ea97d2bb6473a50685a3e91a8145347e0e5a6368ac60b1a1abbb278108d6d2453b84496235b07ab788a64bcefd24071189b312019618b18711b93e0a9064c327c2af049ddb845282695ba6344e612744af88e12d2b520fb388e0c44f26066fa81b8a410077849baa3836b7165a248090819069fa37f0eb0df6bf39fc94d311a8fe35c40e9943d108c39b1f8d90e753219ef567662e5c138164d935c5740b81b15a15e8d0f934cfc7bb347b39cd40f4305603d10e143b023009ce32eeb8779a68b7c28795a4422af7c2ade61d02c48777f8908876b6af88d36beef580d523978b34ad114a205846595704d75112cf03cc91267038ba05b0323208fcc83481834bccc8320e69e62d27e6381c5c9b5230c6188f2ca811ca1e262edf937485928ecd556bec2f6e2aa213298efb33ae2b93f64166bf2ca8612882308bcec3a56702292353c471bb9aecd489361f250816446782e3e344a5fdc39b38b58cf54405eb0e40f814714de57c124bfaa5b22c81ebb0110b084469d0f374b8f7c84d3f3c4cc7375c143a98a0ad931278f6b984233b517539d15bf992e21068f8b94488aa924030161355afde2b2f778181ac49652a4a49ce191d188708efb3435d71215a95995e51eaff4ee420071a8ec4b3fff48e95617483f45a921a6718e9a83d5b0084e14a403141f92f86244ae54b064eb2fdfacacacf5a7227c9522446ccf6b13969c0344e4b208d322cdb0d8fbbcb64af2ba80f430f64708a344e342a9bb7b884a81618fcc60dde9b2514943659de373f426c75ec4d337a9b68a1ce57bd3d1381b835774a0ad92d061d12531a4a90f19229f1443bdd01a03e923e85decaccec5bead33dcfd6b8b3a0a09cebd5ade4fb1f5ea80d68916617df67f94ad1a9e6f8fde251208f4e788e3c82c184b88d08a75fd1ed2580708fc4581d7be87e2ff9fc66436be4573a51301a14234c05c6a827f05d010d43b506215e6b8e2f472c35a58792489892602a16782380b268b45fc9f71d4ed213bf295e3e1660f6bbda389614f4d72ddbf1aaf7a3b2ed65b53498e575d2cb17db6d3f04a445e597beb4c5663c3ed2b2ab18173ce831d7f9995f4616239f8b113a61d13cab45b6b6e6f042ba0efdb4dd315f49f072260e0aa6b46717b3984594e181409d48e06ead633a2cba1800ab734c1208a798fb2c853d5266e6d02c621e62f58bebe25470d68feee9b7bbd89a29fd465713042c223061fc736acc6d329886a6e06e4c9f556033f17220821bdf3597ac639c83a6162d5225ab6402e71ecac874221040269c0bce25666786d29801576a52cd3bab5c19006b716d166ce9cf92e30740d82d49b0d8aea731738553b97afaa97ef39fb14ba08824eec8b3d88e9f21b39ad3780c875c3ff654b64d60fbf87431a80db87fff918b60bfa709080cd22c771df7a985d96b2e5025c04699e8959d91d5fdee18241bcc7d548d8699452f74e8314b062ec8ca50fbdc77b6b9c47ec642461587aacc2c912dca872cd4ccd1c7a91cccc5be0c8c9826c9dac57545685b7922e8bc33d590ca145234b45a6522d3f60e369c0295508a84e5e09dfd169cc56dbaad13ce5d09c80628c78ddeeb964111178e9920b8975612ddb44dc8b9bef9e4f7abb357e66ddcf7336c963390c189ab5ccddc86a8612cc97bf1acb91745c3b41976e8268751ad627f33947ba0ac2d1c08c77d65f72a28ec45c82615bd5f9aa339937aad951ce0c0903d4e0e94a0022f3c24536c49041036603e2316f2e80635eaf6edc8d7a5853b8b8a121180cd97acb32ce297425f7a3823a39ffb52c8ec5120a6f8f1bad907491fcabdcac761b99340d167351636888c5967f2ac38235cddee24923e1b8f1b08e4b58102f4dc2dee028c10390c92f6c022fe130d7d78d500dfce71ca001506167a0f48f0b8a21502c3b0038933bac40ac41fe2b90e8ed15944e7ec1adf1e50250368882bec25c835b0ee69675f7837786774ae0790c0f36f08326112fdc5dc4e77e252310d776de7f6f1f7b039b644b9f2e30bb4159cf2bab1418e05800eea487f146611611527d285f0b1bc11585d4c90625bfbc9f85ecbf05fbf50cd069bfd319202bedd47e5fae40abf2b3d8d52eb9e5935e5419fff92b7afa98de79a3b8adf422c05764d4f3682799caa088b820de2457742812656994556fe6131c50b4c7743cc30d0c0ab657314f0aa65e1ce1cb27707cce9e6411860b3a6393bdfcac561736c1e201d300b3c734972e7fc037afde6ce4358b793e91d58782900a258172f22b058cc4b2d0aa4b68688d7449477435b6603e2b57003a210688024c2bd3d85847c5b70b6a7835a6117787c75cfe2d74a4fde455dcccab22c0985f3c63432ca8c5559c975c336512dd2d209683c2707cd0cf16b726306accc60ef6fde709b265806b53435f894e224a8855c970c32b011c97605fbc24a21cab18f0263c6b14de5a0ae5262211021072d4c956e1fcf3745ec577f6a94367c2e51c49a4ba49b5ffc266d1c28f2522602aaa6197ccd41f637c356038f5ab036ce4525107d5bdb5dd39b7851e7ec21a804fe359120f958aec48d8b7bce57f145c33975b7c45471c9a4c3844f6acd9a8aacac254d6367ad6827dd29bc8fce414fe40d193df5171046ce82f8ac06cf62e489c99685410efa245e8cbeeed9021441e6fc322fa77559f567d01b3957f436764c75ca6f5334b151860421c6c5c23ebc1c6ecbe0aedd1c9fcc692c0e3b26107e654c49b983c1dae1c358a83b48d346e22dd9626c44d659da1bb5d30ded39d2f4adff0c4417073c9c2701096302ca5d87a0928caa05fbed61e3770a3ea5f8771b19e09c90d27211ddd494cb89474de065412fb280487665e911c85a014766239b96d104429d9e269cb163ed1ea6a6bf6e049cecf20f0cf3318fa1fdc34136ad1d7edf41f1246ed512c29c476a6bc5b4e57e32a160d13e16191c7455dcae89be16327750939918bb4889c297a71d74202b59ddf4107cc08088898db44471757681c1b811aa9b10d1c31677c5f799681ba26449f77a8b62c9ac04f7234d3e9fd12f341ab7ee46ba2aae34ba28c0888a30016f00870d63c6dd866560d5f2b48f1b99477daa210573e64a16334c7edba8fd4ed8c8acfaf056250e0578f51d049f206909e128fb3bc6d6d64d33711dfea90a717fe79c8d80e1e5fe97802f50e9745c3bf6d04b5252bbcc2bf72672bbec909cf52f8a008003136f07cc273f51fb55a0a870f4be318aa72bb18ede2ef44f68cd4b876f8d63ea0d8baed012c0972396a6862c87b04a9982b7d5e3bf48e10f4dc0a8d6fc07ece1c690a0f66c23b6fcbba495845654bbcee635dc96b41c66028c327c290575de131145b240b4ab7557dd3a54590f3b9343cc3ce84009873188908fa4b43caf240d2f3d204c155fc10021ef72265e613607bf8507b529c13b14dd7fd52f2e5853cf27a314384030bec71985069820b5216355ec061a3aa884a85ca454dfbf55c925d61840bda63e294314910085d677c14f933d922397e999d98c6315224ad8ee47a16ad0cfebff0bd74706299187546e9c4aec563123c5d69e357e7a9671b38d2c654f428b6a6a148b0e93c285759b1dacb88e5972b4d0a9a635bde211de3ebe444eb0a2763e7c8d19ccdbce9a7577a4b53fc1be40433ec23d481da24c6d3369ab34be671ab7f86ffb246b6810abaf6d6872729199b1213f21fdba4854c4fffb38507124851437f82b2d58f7a4d1ad0412621e5377d420ad070d853d823508beef3b1ea9f4730ceff30da57dacdfc3c4c3030fc5a9b9983da21f48890a9cc9b21866a482763fbb0bcdeae7ae3bbba26a5259ca6c08870ebc4f3d71721dba03ee07995f3fc6c6e4e06636de8e79866fb8af308a7f1b445396894354f23c34690878f52ca5c41bcdcddddc81a7f57651f2c161c8964484b37a26de3354ccbc02d0e0960714fdd3064f9626cce14dd8a23cb03f76e9d729cdc2d164c93e4c8631de5b008ea536b96e465e0a721a22e8528daaa2f1f3da0b353425f59f8c779a09781da84539eb642bf446e9fc27043366a73fa9b1f0586ba991283c0d43f36d8510445cef97438fa26c2f606954f231e63d93ecb06648e3eade6108a4834b13c047a1d5b8367f268d7db14381f9ac55aadfa95ef728d4292b7ce17ed3140ffe1132177e59cde7d05f67bc3750ecfcd85bf22509de4fe6fd346ee2d3cfa99d196a2c768e6e9a62f13c225ebe0aefffe26bb3e6f06ab0eade9a1fbbd6688aebfde0cb7f3b48b094431c03a75fdce5f4cd5dc61c76b963dce72fc16ba82cf69659d30302a32705450d7e4c3710a0e756c816bdec780dbb56e747cece6f9ab7bfbf4cde77dba4eca72cd4ab94c2cf278ff05454a900317799f23d0e97dcb2a26f6bc21aee204b23977db649a4d6730a9e720bbe103491126ee72868893262ac452d236c1cd53af46d267faafd5811d2a004a4f51e3e2203d5998921c59badaa7e865dfb6f50e8ff5e613a6f1eb000b06a7b0e282afb0136315fb54284dbe72d4c0091f3e239c49451a9884afc2d7b792480e9478b075bf21f76654f752918c01d9a5b9255bffaee98264f22eb7d15b91e2262e5ceb941bbba6ecc76e8d580a04a1434a95827ad2e00dba321d7829b6b42be123213a4c651e3484b5a701b29d84110cd20512a9de8e0e6516b192f9302f460b6e609d1fed27b90d20ec8c3412a2d1534fcbc41a0c764626472ef9468b8ccee473c11571a3feeb54d43665dff34433e375d6337e605b9762d5200025d4e5afbe76108d361167d5f830320ca325d8c89de0e101e588a4f21dbdf35a61afacaf2c8fe0f020b131f4fb28a88697d52679800c64f34761e5cc3b03c30fe0da15b12379cff15dc7a602a912e1952a1dc154299c53258294a0cb824fcb494be923522db6849990998b220c8832997feb10aa0da6cca0bdf369db6d0c674e8c7bb90a89411cb2217ff8fc6e44c13e31941762d6cb1e58c80e549ccfe3662569e2b729b58235abc658747bd9cdb6cc5cf27e21871ad63f4917f75b7d050265c54904a17cf4b337c06ea40f1767d3168246f131b0dfdd88a79cddfe09cbb1ee7ed428fea281b8d9c7ea2016d988ca008b273e3882a8bafaaa3c8843304f315021a2d423c386bd4144efb823862325774fc60426c10633f78f7aff77b278258838431fe020583a823d13465aef2cfb3aec561e4e2c21364cad9639a316eccfbc75f3d46f8a7b0613d367eede409c9cf4ad06f1d20e5a757f827527db092d255b3811ea240feb85e63abb86264325d34a7786a613cc13335ba40e8b86934e95f78a4f949fbdcdfdae182f225ab3c5787e45f7d1b46c347dc866bf237061d5c105816612e5ea3ed07840ff11368c28ee80b340b17429aef3ca64e647245a97c889cf51f60519449fc617cea311fb92e5cd64a6bff03d70785bb6efca340c6f15d912b93f2a5c960a7a5362cef8464569277bb1134efd42fa67e0e0c4e3e36272f79879e520a7663b03e1758ce4d1938bd17003af7725fe2b21315d242a543fa2d29232b5383ca260e78e5714cc4c43837ddd35e71175c9cecfe38c037d74e4cff607ddc1e4362f879a5069c2ab147e8888c4c8c25318bd76b24d1b5839b484c1a4b446d08ff3290292029e56f114a4a6f00cc5bca94ce4b162e8051bc71d37c8e6f67516b5f19214deac66d24402e59e33619a8cbece4b81651ebf2feda1e2ff9df438d93c0a41945120c536de9bce40b186c9c59af855ea8c7f1860f86f627cf6e8ac5d702ef34653bd30edb2f4017dfb3f0aa5e3983729652b159ba9c406d9cf5a1194047bbf62a795b9ce36bf68d336f005b6c9343c7947c1f31b7bbf3db979b1dac18a2a833e84ed431265fbe4ce7e94894257b5363d90a08afe8237ead1656c7fe28e7756f2812db4f39598f66a5a6842247fe00e14262c72194106f9f4714bb4f0367b9e9a06e99521921866e126c10498ba6a0992be6c42539b5bab5d462273b96aebf0c424d8bd839f8346e677c9597d2f15b5f342e9a3e371d4e4a27b559ba69a1ad12e797c52a8d06a79a89ce3c45ec3218b75679bb16ce1a201478cac04038839d4d9a18fa3996deef98a0eca2f042c9fc6c3eb18ae752aca0c7a57d7a9a849f4528e73d95e0979ee8eede93d6885aa5fca332392df00983d1a3c34281a005bb229246dc776b6d0cf5be9bdca415a16a48b4ff5e32520f4bc08c045e0777ad675f4cabc32b279181dc196330d570f8d534bc2cb242cb9c4ced58947dc957125b93de256f88b15103262fbcf71968aed0b29d7a684090fdb68382c1d4ee37ce8f0fbcf1e46d56c9948f287452477e2744d002522008147643465d08f55f8f0b835ff173d51a73bdbd8fdd9398a4b38151b566ade04a4ad25ad3e407579fd6372cd1d52c6368389c9671aff9ad7b459b8c3c226ceb36a0d313f04eda0e303452fd70667f3c31991fd10f0f0cb139e59c7c33d222209ee5583e920844e0b093177f642cc38c1fc8622f7ccc86d37b41e1ad9c73778f393220cca5371eb690116c6a995bbe65711b0c278f0a20497cfebd34719a903d64947b7edfe717b04b92d88f98fbf97ae58c35760ff88faa918cb922e3d2f64d3db176f9cbfba579fde38df7cf5aa6675c8e039e0b51d01a5f0d508649e2d3c01f7e4fa61ea049f70a053a6891ce88281a5b9ca3c5d0e2aa8d6dae142cdd121dfbfed072dd0ad92354c162c7d95634ea3f24081c9723124dbc9b40278a475117503c88c9297045e76d5b374b4cf3e8d2449c6e5bfb136ccf60723ebaac162c1f60583239e48ce08af76b34fd0979906f3cb4c645a8b042392fb7986003d1dfdc331252ed3f7b8e27bd5944e4c1a0093d7a84b8c8e600c8fb7381d009d06374770a930d55c7fc38b4a7138f9153dc801458c26fe0c30e91ba400839484f73f53ce391401fb44a880e6a8a681d0d225040307da4fd27bcaa72d47d9edbed3bf5e66332e8e411b104df2ca0de895eef674a8c05125e8e51ac6c8c485881a6ec0180a78ed0aa8d16fe1014de8ca714c52d424cba4c0b3b279845e10c0867d14cd742ee89ac125b078ece78c6dc62f3f8fe16688d5ef77a20e33fdc21a5effb6fd181798ffb285d20b19af70091507e23dbbce4bb92339fad8ec89743539576603da2bfc84be05097b18b7517d45b5e9ac027a1e12ddb4bba17639762ecc91998fb088418184fd875752e1dbe33416c73d003fe75723a4b64e069d46d57e9f46b4a81ec7c4c8ed19f017bad320407306f74e78177fee8a78490ca4c66cbe598d28fd75821ac341ef9a0b20413a787d2dc9abcf103370894ad864ca610ec3f3fd312ed91435f6999416430db1f24201416e26c9c1568b62daade78588856e3ce2fe3de78e3a6931539e3a894b91849d3b819f821f230f0a6a72972775adaa36818fa040129549ed502448e3e5fd2b644d8041e7fefa2ef3e769102f5cbe20fe84605d452a970c19fb9f161c349b4caed4db91944308c1eb84e31ed9e59fd9df479b91fb1b100ff6ab71a978ca5597fbe29f41377ec4098b5e6d9fbe753badb0ddadc6251722c4a56c761175ce582a2beb707c14986cb61abd1752f5339dcd3b32be5eb4bd4498f124439a77e333093168c64a26981d7da72ed46ad6c60b3ccd190d9db5f264e315630e2c0f1b11e811f31d442564139b1479e8d7eec48c70902b5784f423d59e03fcd963606549bbb7d2bd065550dadfa28565326bb01bbded3c44db465232c525be3210eec93ae4864dd36ca24e837c89e12bf0441ff828574358dcef536c7bf8f0f77529abc90deced0a46310e1507b80fd22e0d46ae25f8773a66361d036f3a686ef4d1b79f246746306707776e6f30a19151670a206c7b1dd99bc074f55310e4b25ef963a711bfc546ca5c8d949ca93c045cac4eaeb8fb619a8360e91bd5550462dd5621e3af1871af40250f93055aa3b064fe56c9ae25324e4128dbd30d1bd24b4ad1efd2e90bc53ba90dbe0e894e77026af546ed5d7de087f0fcf39710ca9c51ff8990a9567532ecc905622abf75e2a44494b7d788d3614ba0360da9a7313fb06c9202d5f36a2697bb628c1dc280d0a5f90125a9dc6ef7b1dc954b05691e33e020fd643bf8332bbafd4f602eaf68815ec7acb37728627d339c478346cc7bd53d9ad1cc487e27ccf11c24a6ba398219ae5ed3bf7da3c8f68c0040184b46f8ba20b41277e0592c37037075202b37bdaa3ca0886f3688c0c89e7e14c77253bd5c7ba380283a43e51d6184615120196527c9cfaba4b97c5f789bb5f143d19a15ca97e253b98ab70a2f616d7cf84692a73396e8762a3360c291a087f254d6015b48b225973123caeaac90f22161a8f006d43207c03c2b1e8f3361c4d6457004296c1cf89a474d7a271dd856b28beb449b040331aaa8e337ddc922716e7c51ea177015d56bc6d2ae3cac952b025464acc398cb0701ceb4d5e4f1a5a0a0f4ef51686034ed49ced0270b66865c9742f8d30e3154a1817e2f30b6e9266e6f39db00e0955e8e282db33a3ce3681d908f52734a9df924234020fd87faa8ef81789649400e16e82a993e7d983fe4397e4f0e8207f64a3fd4bb12cb11f9451a884b7ac548450ab0c34c6c859a64392c0e4728b48f4c8626fd307e3005c4c28f4d80e518bb17f64f4e4fdce48804299b066a5eb12dd15c959ac93f8983c6bec5d07116d642469edf16d401ada8ad015604ef8520966551edc4108e1f91c3115632edf254213e732c31f992e01b4b2f55d4f3c3f8d92cb1298bef25861038b1a7fd117aad5686df02c88b6a46bf51e23f42bc66d58300bb13dcc934cc04182cb20f505b737c1c2d0fb73df0c795a1d9260bf88739937405d5ed460e051da10ad722a98fb9821f6022c5d8b94f49f46e5eec0c8e82e9ee244e35fdd957d9eba441efa6e978cfaeb7e51f350bf15c4cb1aa57eeddfebb46bb5e156496f681b273312f20e7754bb5bc9e5d1caa74da630515461673a834ae574ce96f7615462651be17e026788d1f9129dc4711dccd849fd107b24835c5d6ca1c67154ea6f7e5137e3a8ce2a7e1deec25e6f82dab9a84970536f2b54fec906eb8d408362f5e0674c3dc2c7b7abd993e032fbcf3d096f9cfbb0e3a2844065aa1ad76071f5d04dcbb7fc983917871ec58e5632e01fcb6b4a3049d2d51d89fec00eccf177841d90b72e9e0fd9efb8dc7147df70419d9fbb0002518714144add4950a9040532ab222fcf903c0e70f2f7e7f91a55d0d6c99f441077561c67dedc5d27c5404cdc439c4da3b4544a042a04c91c145914b2ddba8861c25ac3027639af181edb7a5e96cbdba507392f439134ba936ea1f77173244126aa0586aaa8d6e05ad1551a769c7f9ec09e6f8687eb4a469f6675ead15d8a1df2ce8b44d43b5d4dc6c3abcf061b1c68e1368794b39d396f2e26d731092062a1e01830771e46d4b718a72bcb18aa6bab13689438db2f49fc95f90c1e4c6c63b17c01237b660b9405f241ef2a03dba96318b4e9608b0fd78b2c9955f2cf61b69594739e39e8dc904daa6264453bdbc2864728c3b7cf705fae7aff4eae31be7e2f6a8c52bc25218b533a0ac58f3d175baef3c23fd88acc030a3e20f91f8b2a7f85a1bd620540e40261ab5e2f4337a2e9c30e1a861876cf0c14e1c110b0b5ecddbe4d38552e90800cd65a9eda4c0f3aed860866c6a59dce7753372108d88ee75e99f4c70bcc1a746bd82cddd6d74fe985d78aaea4a01c1824847ec7bd49ae93e89e35b618ffd89371bc3585cc97f3fc90a69a4237efc4c2d44bd5d08c12291a7867374b129e340fa79e6f7a94cabeca2aa98e16a7bdfdaa251b337b9acca3dbb375c2f6a41088288e8b26d56beca5c309bb4ce9e95c8952995f996688f6cbc037535d80249b3b3b73afe245d71351bcbec1360dd0b524ca9941023f82037ce005d1fd098bc4b03a26bdbf4d0bc0a00761d9e220b033bd40023e29656bc2f828e4546d94c105321967479c7b41203cbd07a5fbb67f06c4b160a5a1b4835e0f96c6ee72d8bddf8ba459e630d0eaa3994c035537a35f41ce20b1e099053c1c24ae6480115e5f9397996a3d5f6325c0300c1cfc7f633427a01c1d8f0db0f0d614096c168af85bac6ff6f5aa68cb83009225139c1a199d62fe6fb19a06d016c7b030f3e60e3f0ccf5d947a133d1d731a7c1f63735b22c67085744dfc9223d5e705eac1df42346e2ecc495ee249572c821e3de0bab4f551ca7e92297e7eac6ea4f9e6820a82122d053d7ff068ac6e88254ca4db6f68b088fbe30dc843a45bddd3e5732a4d4288efed41422a347fcf4e8576818ef1c91001cdcd0bc4c03ea47061f7411c39c169b8f239e129457b7a095ab0daef12f791264a8ef44cafe967633b9eb1f6618e0a22fc725fba4addbffe71032bd333ba130e89d19b95a2a2efaba7d5797897f5507f13f0c421843017095829e8407170621dcc85d4927fd5041f69c0e0832896c6f08b41a14b1fcc199b37729115026d41426b2aac2a9045d4eebd3aadb9cee94c86d44ad4466afc881060d9e0d91c02ca953f52564c94b81070c10bb94cc4825a672ed7bf4ce899e850f37d6ed82e03f2645d01c04897ded0e271b2f72426d474b90b5f150c57158d162699c33020146f0e4604514ddef7daa0d28918c80d301889c4d70a979a15c51612283b8de293ef5283bbdc1a311d92f5beadb7b302a4aab1bfdda8e8ac8370337dde7c7ba17cd224cedd7e63107b3777bf704b94974ee710c4701d107bfc503496e0ed125ef8f81440cdc0f16786ed165a7b9baf59f5e3a0295e4403e1cfa620ccb23329bb764cc7efe4578bb0157f568792b876f7080b1a0e792b2b34904807a453c7c61d2bd6f117da1a2c7545bf9ffeddeba528289e1ec21c2c991c9b81def7cdd69130d44c092874022a67614a0774cca98b671b1fe5b6430654c03cf54110ca75efbf08ca75ffabd6831120bbc2dfd46b74e8b0e4276a4d8a12753734bd29c027d038211aa1ca8f96907ab33131da0bee071f8b07b8e68d7f41dabc615ab8362da4b77078c65a3e41386bade378936706a0b0cad2d9560de02030ae6f01a5a715b60b00628de7314a0ec3841c83d5ca4b550aa85bd1eca8011498c0ff4b87871a60872b07e521484bc34335546c23a529e6c8f1c2f274c9a9847bff3a8059271248a39a0cd8a0e6f6fd409b8bee15489dcf02c126bd1622545b1389efca129fef2525f201d3b33e3d86b51513608d08e9d2897ed685296eb71697ce8bd18a4eb1da98f94e03417d4d815f3e0d83f6eb35aa7976aa9a08945cfaa21cca2f20184a434bdd1999405d83a6d9254f915cd6e47be0f587259342678d29987966501b3f3e89951fbcb2d83a90d90cbfd54daf3840b29c791e1833300c6402d5bc44db09620e750bb5eaf64320a768c3701904a1a09eb0a9ca34e8eca3d455314097895a86967e8b3b701a859843b4404f76900ba411bba07f33a2b8798bc15b0340c4dd3086bcef9189abe8891e338c462a1673e940880ba2dddf9daa3851bb85262b4c06efef9aee82198592f24dcd25111f07512b05d27ba4f8822e3ce4d1fffabe84f75fc5de1756e7a0ccd0146f42c824925a47343ff86e8ca65c793725f18adf1d7226852ed156702715bdb6470ace08869a07a9c085a605139af7f98012bb94f2d0d5f27ce0436ba8e3dd3205d711b3140e38434e8649e28f0e8c38831f20813ab5309ebb50a6e1b45b6807a0753697881180c189dd15751974f0b581f631e15e7bf38427305ba7002fb79fe912298e4129203c047d2b7033f8def1158a77b355d87245f8fcea097252cdfe7eeffbb84d58e4785cc4fcbada26ecb44bcc5d51b626a9b0094a37aa4ce32ff2c5f2ad5d56764670cf40894db010360d32b898912a4d541a71c42b6903a8d370b17e7ca12913a3f9a06ff930681d54b718213fde900c5f871071f92e4b96f6a9fe76f9f6630e56c01086e3e0e3d1365f65f9fc99287cb855092a8e061af0719106ca03dc0232e491803a89f2ac1c8d0f40308bfd125e70099754b5f0685b8461987913c4ec9d1844eff61c7c2a96e0aa4143998dcd132d0adb0a3a440e60a1ad40e44efffb01601fbcdeb532cb48d71d66e0706d064820c4b2218567863272a3268dbeb3888143d94ee6ffc5ad648456205bce5aee57ca39dae8fd48003423380a83b2508658281534596e045c08900a7676c42c6a556b08338b8a9511225de887410f61b0b49e3c6d6a987d92ecdeb04160f6a1aff25b62cdf2fd9fe91579d65e36d19b3fcd3b641a907b20e7026c686a0a71776f0e105dc13e927e2396d725422b3a29b6e21147246194befcdabf90dddc51acbfbcc889bf02f53fc434bc0820b8511211fe5c5d8d1b2afc82bae611dc830a09526baccdaa7b0d274cce381ae1f4f245d356b596e74719d7aded4473105a34b9353483be76db5bd2897b091d20d98cc9d9c227fda2b0862fd23d2db863ad6011980e89ce7aaa0395dd4643a7bc600e054db8f9ea98c6529210b9097731cd8843c1166dc4bf4470e625150718b38eba91dd4e335d095658dc13a7480186b8760c98ed78d6037f8383abb8b2c39fde64cb2d2318ffc8c8c8c9257043056cd9865381f8c59594843dcd916021c9740787636e0275c015278044e92e5f3fa4ae2e710d66a382461ccbbb817faadc2e706c3be9117fe2602a7f840723b9f419ca809e71157ef7e0a7136b5f8308a07c4663f59f64bf075fe0f5ba60b861733820aaed563ef935a4d1c3cb473ba3243553c7bc588a6b3cc6a3275186b39a24b1c9fd3723ff9b5a0b20b208e99b915888579cef5eead5e4da33f1b26e826fddd5adcad7128352b1697fe3df7097b3dd5992b4e6552d9a979091fe84b7f2bdb2331db362afdebce4985fa14470ea29f00df639d19f8372dc0d3b298c7512b1677815e2096a5d05d4df9672bb13b96dda81e2033f2a9d14eb8820e88610bda15b2a9e1d1be360939b0747ca10ceb725d46bc83c04c523103ddccbd04d81b9e68829d04d70851a2f83c2f2dac16e04f29b0254d93bfd93bd79be4922075a1c338bb16e2d326353f0fb90915da7adcd8238abff15b9657706b6a110ce66f0b41c41eb140716f279764813bea80c11b56908c8f2d05f274a26b1e5a9a2c16ee130a832a7cfe4d7fb56a522e905a25c18f2c4e46f3d259fd8758d71d8f81c771ca906381a00873fad7126e9fa51e6bebe22b6c6a59f0e040323e3f7858b40e2a587dffbe3b944d50beabde1f77977126c37e42952a3929442941d82dda8050a03541ab980e516c55382556ed0157c462112a74a0d52d184a2f3a3ad21c29ddc2ddf4e1fa088d60a10ea4a912d52065457dd4e9aa3bc0eaee8f9c59b52bb1e75b37f0d16d7b993c0d26a1c4b3198c3d94dbb91a3cfb672f5c830796161422422900103afe34379d159b35c1efc11e6ed54a122b0278bbe532a5a4ed269dfbbd2b8fd489047066417775e521210bb260dd2c2c6fba9f11762ecc0c3e7c0f80f8aa9418b0f1b9bcbbb4e0289b57a606cc10cc23b46c1bf1783513ad73c2d97e809bac4d00e341b296df1405b2a84b9bf09885e0b5277c40e8ecb3f20ab23dd240b60a641b893f298466c8513ca7a7f7e17e4a63096ca28604c55febffe6324473a9788a1475723b0172ff81ab0ad220d4714749ac844e4383e177525156338736881d83fa76a56263ce655dce8408beb78f63d2832f80a1c5c5c2f00db5dd03745ae10604037e5bc3b23586ee8553636599e743d28a33ac8ecc03a071af5cfb35de8aed732134395bfa6264d97a2fd418b15f139a955baa38b42fca0c27ce158b19feb308995d2610d752aa603e582b8d80cd65545eb90e69813694edc5c96c6e0698bd57169fc0508772628e31d1f73451d2112df135e093f8e46439d6bdf5421080c1424e7963353ea1d6dd882ca51179b6a05064b5b51681d5d349bb27eb4571d12aba2257594bd8f0a9d894f08d344b8d2a24a4a69c2a6b716074381d4c715a18969f819b0627f3626d0e330db9165b952e6fd644107a7fd8d422b75f7df9ed67f5035485ca617c482d514fedfe72da520ccce30651851412baf11f83c6670e9935d1f4d2f563a3896a6bac0c5171206dc4a15c66801c8e546fe11f56009cda2d2b4553947c082800af5ca23a7f6c162777511be088a4921c003da18bcc3c5977e44caab915a9a1009351d7b9ad43fa58b6dd17153952ad4d14911d248e9e6a383d2cf2c3cd584d188edd097b8ab5f985709e79864965f7f28e7033354e11e851829fb69c06d460ad2b0618b30cbb2893c1915ac3fc5210ce91ae004f0628f18307559037272453bf4a86b7e698e6a7cabbf2fd47d111253ef061182b5b7a598de0303c6a6a56a750ac56b03558688ef65495a6652fc3839a65139cc71c8c428f279cb5109181f3b888483d76c944ffd18640a5a748cd601e36831344ded045791c6457e5be7b0175f4b94d21e2b93100da21e43c5f9c807e98ca7555d6cecadcd5d7511f0fc30e60b4029fb416f8ce3aa69095ec1ca996ab0f432e8bd6c988c078953fa19c2e9b30d5d942e6518d7779d5e42929bbf4cbb985b923086928fb2577d1ac2aed47834770e4286632edf825c7f1a4995f84abdfec43c1a16c7b2370a62e33871e018a1dfe91c2410bdf28419ad05c8e0cef4a1ec91cc19c53fcc2bedc5e8fc5eb196c5d5a83c14b0f3163553499510150f7c73f0778646f046a6507774c32b70e5c921c448aa24f8188940bc7bbc3111590b9200aa969ffbffb67e81f61c2037e25b4b55ff2927af8e21ff380382ad309881afdf57a02575a240ad3116af3ce7af927f256d51552831356e650f93ffe177f4dfa6790f2ebde9fd60634942c606c78a233696d33fe481ec1e688051d45e6c708ea24ee2a30fdb3a70ff3eb6e7da9ba1110f07b9ad929f22904ba8b6157bf476be0e6012afc6edeccc80f0111b5099d123431a39637be9478300f62f1a3652262d588e610753a9b386d5073114f2c75a03609ef1d77c8c6b428081cd39ddd3385329b358179237d13ab2f2f76a4b4d05a7cd9c5d39774cac0e35e36badd0baac2a011a18e18e473da38c7c21980185e39432ac11d930beda0068fdacb35f06fee7d8c239bff62552c3923c02f2f029cbd682b7e8341f772efe0c12056eefa017fabfecefffd942ad144ccf51f753a99995dbeab1fef220bd34340fd83e6f1f7e696d2166ec24440d9561b18a91f76d4fdc0329aad13e685267c4066b153f3c02255f0d0a5803d3d6133440246a56f092b9a9831b25b213bd426cbe20353616b6a8cb3ec4351cf176613365c29d74fba8ff53129a81113ced1ac7a9e1f2ce08a163837194c70fb4487d8a6f27f22bd2ef43ce7dd56d2316ff719b2ad6c30f928cc1343e53eff34db527a41b1c8e64e99cfedd9e9b56476fd2bc8f924c2bd80fb860cb43d12fc7f961e5058a792aa3eb4be472c23c23cefd8bd8bce633321d9ec9c9dbb3bf151e3d4528da096ddce403ffe32d4c9d71d6b465feef1e2e1d75da70359513f16c95480cb64e3fa15f8f91278fda44e9e60f8c5242a84e4cb13144480955a28c8c69472aa71aef9a502f8f6d8d27ba928fc1ccf7f7bfc0405b233aa337620fc4f6760de018510e5bd58208b59f846c0a6418d05ca47f17e9cd609ff63efc2305065d7bbc4c31e5000aca1c915398b211f2e260adbb80a231184d94508a0e97404bc228f38ba2a5bf6788519912b06eddfe5ee325a800ab2cbffe338f4107d663f5b4c2f02036c6a782c7389f91b199cb5a28ea28dbe121cd022ac2cfb7b2a8dca633220cc7b5964c91f6e25b82373da1431a1091489f6e6f372f200211c86c4c5c5c29d7e2bc017379ea7d2c49170f30b466f7dbef2c7bac77af5f099a518c4eea7b204746c14dfdd7a288e92a7e13b63e2677038470c45de6b3015f725e3eaffbf8e1a0061c59f15b720b180fccc817784f58370dd0d8916359dd9868f8523c9372318a1bc7cc5d1a63a60d1c7108a0933d901ec4a8acffe79a5cd1cf8334846f9f9b2284a815e9be0200ebec58ec0104422810f33a23121e5344a603d87c5012d40c1e59243431d57c6583e39d6e0536ee92c4e3e7c289755ab13c84271efe74fb5358d1cf6202cb1ca6ff206fe0002c8445d9dc1e2b306543776a61a70fc3936d72ecc69ae4310122f94a939b3512f427f1774f5c90445c15aad436e7d5096e99e674418ed6e98b7e0885b4a7318c88523821e5fe8a22348420cc3167f0a7c3689fb7fb889a602eeba42fb19db0e28302cd086389b2052f769e8a76dd417029bd976711097c686cd587982259b9db509a1bcae272c806f7349abc70746934ee5328f25583860948afb098641ab6328d7a63d4bb40508c63af89228c06a69d8018bdc9f00d4b256cd26b06de55ac39ce6a82384fb410bc3a3bb151c82baa607703eba5394b97b82954284df5a3294e9e7e5287dc7096b510a009332f8899001508c3160166ac5e41cffc1a0d10144f24e92beae5178bbcb75e4184c0ae90e0176d544abb14afac751caa5d2588d97719f9b1e694e245957a404321cf18b4c8dc9b66083ab3408b8fa07480c25e75d5e0c5bd4429bf17740978b3bea30100dcff1fdb0e173a1ce5155045699ff08119ff6349c69177c5067b4422aee0932d85b0ae60422bb8ea9e423d5f8245bb304a79648571a5c5e2011a2092f7298e6845e311dc6590377bc562b7b82adb7ee2e4047304f27b7a723af3a0e90fe8d5f039fb2b731ac0f4c3c457f370954e620e994c7f8cbf5262e7eccca5de199ba3817912f4aa7ae1e067981e7c4ad81f2cb3a644e367a43278b09e923106efab35b9af5811697a5eb4799a58e2c064448c6a8435d23fc65e49831f3cb8159431cc55be89201cf51b7459f44cc25a1cca1319ad75786db0caaac92ca2cc9b647fb0f0b3058e946763ed7aa2822f6463f11433ce16b5158940ed1bc65f98dea47dd75b63119d4b2ea7d4df67cc160b304a44d079bd8e45612aef6c435292b32ca15dfaebe06173e67c7b41e4829fe63ac05c11732172fda5bde6960e0d9a3fc9845fcf8d405cb7b1d37a928f0329a7ea1d70333973eda8b5572da2bde8172324c62eb553580b0c75f2341aa83d672831fa3ccad0b2f9b513681cc72ff75f8f5f4d8777590f51f6fc0c76badd80c664e35d0f64fc3f6c461bf0dedc9d802f2eb73513c38dae582bd716872e9d5f2866cdecf628adb30c3e7432ec36be6c70fdb4df2b5c7a954d001e913dfa7382abc451837bbc2680185b6a76920de227f2be8d5ce5ccabdfc57aff50084010655c64a8c6d94ab199bb45b9e13fb33970fe6dbfd2cf34f3da8713cf2663f4b7796e0a02558106f4321a39d5ddfe42c9ac5fceb909ea33f870169700057704e005ea59ee7c3f3987ca74c85dba3ef9f78a6e752df0d9b0c5b26ece3fc2c1303ecf01021a1fedb5c25f9b6e0ee810675c625dfdb5304977deb26d401cdd0a15211235f0946aa8e3ea1fb8296b98a1a1aa62d2460598d96f87a4bbd29707497b0d4a3ce891e6f3ef5b5f5d627c1bf37106c3ba0e4fbef9ac93bd4a1d1263ad37e5e6b341ab92daba0c840741567a1e8aaecb3a30961e2aa6ff24a375f33215190840837d6f1a879a71ccaa187954e6f4965673890e1a49b7b3a5148a36447eebf8dbd302b1f5e54869676ac174af1f17967b4374010347e31fd9a0b33de35f2906ac3e9af21656b3363ed7e07d7589f166e3f7922c9acd47bcc603f9eb6b0f7217d9df23dd59451f49b6de9b18536baa3ecb2cea8eab09e589be833b308390f09d4959445aad5971793aa7b721060cd47f40b2384cef1226ac8b6354f5804a0c77c946c41684199cc05afec6c9b3d6258c0a893cb83863fb7f5e848bae93baa31b2af8af538b25e2a74270e1f1ed9def763ac8b6ceb6702c8f7653e3a8296885f6864ef8b575e7c028cd14eba96146e85fd4523c8dfe8ee3705c3bd858e454b2f9f2a7360b628a0375a094614c4a0871433db1ffca5de7965b16c9af62e0e089891309a664edd81316d815cdc145df9e80457b3ea205cd656c2b244b4e000e45207f8b2c702b33213624862e92ff447df3563b4b8b3e6085a0bc5c1eb461d005583f9adb486e648c155e74ad9bd7d525af5995ea01b9476a0188471c9b59d101aaabeec00ce5ac54c861d5dcaa1cac7f300bdb964f89dfe49846073089fbe91b50c6194a98640406817be8f55261f7654e230dc9d3f4ed626ac32542c7b8316f5d488d3f4f14558df9987e1cf8663b6f2e2ec2180fa1404bc2895f04a10bb43a10808532aee42c45bb885b03ea6b5011d9d766c0891f4059322d50d660b4daa89d49d3f4abc87e6d6712084f2e38bc412d70c1a4bed0bc618d1b667afda510a89e741af9026d2140f852ebc4830fc455331a92f1b728077138007c298c6c9c94af079835f96b1c8ac4118ed597e7e8610c63e59cf01b919d98ce0f60134171221706d1733ec449a24ce58e63cd4604857710415ff19ddf0292d8d635fe2c6f7e3ee51d48939c76cfb79658623a2d56c7682556661d1e411f4d9e16b0e396e79011c5881423fd5c673611344d3e13e2576e765ff0ef8eba1027fa33a63043b2ec6f7c655646d386b27a59201a908fa361644994b2778c56e196b2dc80816dcadaf1f26d1f6cf6a3c2ea9731332e3fda0fb55c47227bbe97d551697c2a8596b9bc15d8df54e3e3393986743d2b64f4426a6eec3bdaff83e5c8e57739d401bf2dedce296c4ba089d4f83034e3fc97a198ae62c1c83724f4cac58b5fe1e57607b218a6d51d8e980dc30d4b06bb94a8ce4a309fd995c423137453016777dda588844c7daec20d600b2f0bb4783f8a58ff37845c0e0da958f53812f5a19431dc80ada2fa244febbb93e0a0317f904b9917d594f16d4832cf1d36ae72edc70a7177e68c8d45be1448fa0aac7d53284da693d9546448fb9fc8d86539a9b43191679b6aa9e3425d5f366a17ae63cf5246e699a15013913174013e657d2bfa64e0194c94371e21e499d0e7a17491513bd255cdae6a4b3aaf9c503aecb099f76e47906128c1ae286539aa1e383f520759fe8b507c69a2817fb803fdc5308fd38d17fde3e4aadd2d02394e54deeb434e981e981708180894af274006efc79baa0f1eb988303623af8b6c7c3529eee506e2f60c34339e29edd83551f78d3f8a94a6f3f6cf7702c4bf7150ca45dc2769e8359f7e54a87e75ff5e7ecfc6937f02b1352912bb3a75b07646089a01cb1ada9bff4a8a7cbce50495365746914938de43ce40df78d6c9a8ea7b6c56cf68ea0f107666d7977d97f58e7b49ea0d8510fb01c53f2e0883a45c7f1bb48b5227233859fc342b562d0c9e017e4171f4f990cb84ae8183ba071b9be6155c540f409c4652d31764896be1fc60173a1506912a16ed55f2053677529761a6552fc3fd2750645ee9f9c1cbc07d1ff2ad47c9d76cb411e52950c8b3e48b5bbcfdd45a4b4c3603c86cbcf4777f092d8456cd24781ee7b76141a7a5f9816c8e471502502766331709ca89453d9d7c647c7c25870b79d86a850a356daa341c95569d7a7829e9d841954b5a2933302f5a1aec5b1e505c735e29deb228a41e7139f80bd9a5a06904a0a2150e411dd8f7b277cc25f26724ab15bb2e1695695f0466760569463856f9b5581dfdc3cac46a1a680c2224bcd9679ab3fc26e41ed5f9a9ec00f1c38a754b6975b58a4671cb17b31cde36469232be39e716d8e516292584415a8169dfe1a139d7c7b443b4c19e953275f71d0808b21da44b14c997c8c26dda8234693139a34237c036c41030abbd380664b9015c23c13052146963c1ec209aaf3df54ccacadbeb536e73bd272ead969ef53c1c0669f8f97b41ddc030d23af660ba9cdf40fba3ff4fee588541dcab63fe4528f3cd9c7cdbf0cb171103ea92516159a11a426f2c35f5ba9e0e6e7b95e7bbf0e80d69833468b062b8696a380cd96fe9e825d1abdbe04adf7aa49d03b6ed4b3134e494d0022a48b205ec3bfbe80e0167d4f28b3a9af1b7ca5fe5daef1343edee89e1419a5a15d6842b0d0e8f5bbe0280e6eb420028bf80bc396012361aa18283882dba30e3d31e0dbc2f3aee7cbc63619657beb2d6f606a1205ff069f5944ee075684ee78e6fa239158ec93e574c00303901efbb89014b66cf755b717dc97304eccbf61fdcf849146750169b326aa342c078c52c5fca30c8cab8642918a453c0b3131f072f57cf030044830e1cb05f3e1754127aec31155be62dba239dd8acfd218eed046b6c7e8b730eff745cd9a91f6f3efd798c9a017a3302819153d394711b740da18950ae6deafe6d5271269e6485e7dcd5ff8b0e9c0bbc6452f868e7bc36d157123c6bc30a92d79a4541190fbb1f2f3a93e936070131e06d78f6f9630a63968809dc0bc0f8a63394438148da2c3cff385f1c3146f13672414d0888d6cd6e78fd384cd366b88233c1ab551917df64a43f9d533d7a7431b7d0e2c6b2ce18a25e7cf9fed4a4db79f4977923832bb222f6261ee4b37b733bef30f18f58d64c2989aeaf32c618baafc0f3fa5e6cf9a69f4676dd5dffb1035a48a34cc824cea29265c89b320025bf5e90dd1f8623497815d48faf5410beef9419856f9b4de99db63748b438294f331d26d7ac4cdd2e70fd5ddbd6b6b77bddc89bd61a7347cb74f8d06205ac7f8a43ade1f7b506cdf095355bf0e0368b83f82182bc2220100737ad1d1748f83df27e35f6c0a5500641b28c0ce953ac0972ed45652a12a7fd4d6577247126a56f1ec00a11874ed580f3c0b43b8b87dfb6a53e94a018765e685e2fe4b95525dbe9c121a006cd1295c063550ae9015383ab0b9e59dfb170b6768f89c4bbcd372ae866cda6646bd66e86fdd0045fb98dba0762eb8c7a687a550ed8167430e8cce6f3c1338e00d841ae449b1e6728372b525c43729750c83c404b6adf61bde2cecf2ecee863d0936ad0a3df61a322c1fd840a5e2761234033f2d8ae01c40b64d6122cdec28a864958e007522326c14c4a96c203485a2bf9ca347ac7386f015a20ffbfb87a7c30114b813e339a6c275cc0a01d7d771c00bcc69ea178754ff90b19522de6574af3d9575134d6baf34e7ac4a4cbbe4b88a9a39a1c90df37c4ad75734fccccd5c865926a87ae2f98a0133a02a716d8be849e741e37d81373fd846d47962468a515af689928cac866d96278ce189aaf40dd95d768d82340477a339d2516445daa8c30de2796bde548cf212ea06cb53abe29ccbb817cd18147e10b99b2e39a489193f2c7096ce7cd6a4c2600b5f6597ed28e4d61328c8478a9ac8a40dc84fd491547dc72f83189b7a9a50d8c88ec172a5a19afc195de790c7846b517fdd99e9c2ef160411b3a27c9b32ea893ff2fc78a53e105e1a7599e8ccb0cd2a4ba7bd1e8429f812f1c7392b8d79431a1f3127f78aebc1daa8951b6f3c9247a9f6023055520b301ded9f8b3dec31bc389451f35032f0ed274ff5543709dda4eb2170c567f6514bd278ef8ce12d1a3fa7b410167184e76f033f3fe118e771de2327570fde39936a28db0b8740bdb1a00d20765ff65c5cba1ce13a410bde982a33aa186d99036fd8af60964c29d81beb4650fb946087b032b6e636c0917f76365dcb7ca92942934da4ad7574468801f0d21c93cdbf78648e6be8bc9347217b78dbb0277192bf9bf88de1a2e6aa6146aed44ec6c1e5b51f65b413e39bcc26be9deb02dfb68538d3b72c615bdd5a1124e5be0d5404bfb790b35532cde77997568e43b434907034dcf67df178ebe672f7fde44c0436fdfc1aa6849466273a1907d269204abb82a7b740d9904434fe39ab255f34322a07a7aceeb7767a5987b7ca812c62b0ca7be231db6d2fc7733b531435da5c40f268f81053226cd18c2c07b500e6573d48682b83b2d231e67db5d8bb8d62c788e63b4c4a86bbfc55b19293852603a4c301a9dc134acb8dc5e848251b894ca7bdcd62a13c548a591a8c7411d26f46ea1ebfbe9d2b13302e66187be23dbbc52b9d9639f216bb3223110d7c8b25a2a769e9a2ad7813e269e19cf82cd69980af979617b9cd9c23e21912903da137f1c7cfbb4524b071efba69ac2e5a5474da937b514bd6c73c130743f751f06081fd67e16d3fadfe25c6479d222edfedbc10c0d727e5ea4128c57c8dabc11fe0efddab0fc1ae3422c33fad0a01cb1a49bab454fd4ec40d00942a34e5f2175b4252ead4c724cb4b5b4f15dbfd17f263ee229fcc6e007dc196af3f101126d512c3387f87541c37ef67b6353c4b319d890ea7e08eec8ba299ad0ad118c21ff772890836514916e006a0cb68eb236bd7222eb89b0f96d5a87d17c19e5483d94dc43abce1f87315256cba2a398df75df6a79c1c54a02c0a7c15dec7122c70cb6733c532e02495f7842aa858898dee72a8aa8f2730b8ad915c6552bec0b189e3d10a2355739eca4d52f0916b96cafad63c2ba29d0d65bc14654a8264f22c9aabe88216fc1cb85826e540a5170dd723e1e58a52cbd8217a7a1fc76f0f09b6b51f384561d142c66cac9729f0678b6657dba4c69286a768ad74bbf46ee6164e6e28df6efd445cb4897a02bec7b71a415007903d799a87cce321cf1df2a4328de371af7b233351c6f64410d170ba38391cf3afd6339b79d55154f7c9a0461a0e5938b60cb75ce8c96c35e0ba677f8a50114c4e3d1b75250e199827d9a7e874420582ec0d07b708f5b9d67483f1d7c3be26371a02c4ce7d52957e1a888d33dabd77692da05f86dd1c6ef1072f96e43ee3683d4240412836a9b1b132c27ec07611ff8edf033f97b9e237b0f7a33d50847ffff02fd2319b58d1cefe511d3b890d56070195cc67b9928520f9619fe6f0ca2ea9ef2b4df61123265741e527ee29f7801196fd7030acaa53ca291e5c1e02ef5a0f3ae6b0f88dc4e89383f8251895f9711160dd19a21e89a7547ccfb0fec334917389ca69c9f716518771ae2e5491ca47c75015c3360012fa8390594e584214a9f81560b070e11ef643a075c14fd77444174dc27f442e2e208a755c9ed85bc43f3dc008d22ab88ed9063e4e6d90448ba513b95858561470455b4892ef31b9a5770e96559685f65c288aa8f2cc7674e064a81c8ca08f0f7198f3d6be0092d8e084471411c85dc3c9c1b21e64bbea575e846230ea321b09e5c7da89e22b48366359d1df800136c9ceabce4f0371ba1b25f1672d1835787762a81212c2f9abf5a7542bf3dd8519a9d905c05edbe77d7a7ac3d4c4fcd74a0c68cc86ff4fce05beb02b918784b23332ef3605adbb6171cd1f0ee005cc0e59ea8098a5badc84837428606df50d994b3e5621b24a19c1dfd21783d74654f4f1bc310d358f1d3e13beadec64e3c22f42ecc8f766defc315a463102186d835021ad20e7a4b376913999d594099575ee1ce9ff33583522ee319f535507d629edb32f4865d5ab397e820c61e4c6cb144a0fa7e88c49d09416193a18dcd07979574559608432237e5ccb0a3cc598509e8277bc414d76a324aea7535042ec64389b6ed1140c2ebe5fac75dd2188e23e8fe8ad90f5fabd0f62de721e602e716f1be5f4696b8d67b1852e505b1a72c4ec58348b6c7817a1c66c61f36b18104768a31344412a3c4fadfb0a6a3ee6e56eef23f2fc799676c57c5fc018bc4caa5fe2502a3b489800d049dbe21b41da7047eba7156c3626d873c08d4318d2d164ba0c80bc81d3243c5c87daa071e2a2abda153462bd4c7c605d8d4966204e26e470783af856c10bb4d02032fc9db8f1ea53f4f8a8c97093318cd7ac864693774926430855344841f604e8e1c54cfa76bb702c06c8c5b1312e1a926e4affb3237a6de238d1c391251be8c4f79cfc89e9872ab213c83314e7ef7131bb707747a663a08bad44690442f495cd14fc307e51ff4a75f60b850032905a55267705fa23c3081d67031f710dde288553655248308d519dc6b4504390dd89b17f073d8041cc529c7965dfdd347ef8f4155e749f9f8210eae7413516a1100a85fdba766011a045aef4a2f1f3875c9c89e09af7acca042a2239f50c0934a42951842f5979fb76e07eab1c201a10eb47275b0843042d9f331a276fd7e085a08450a25f284eb4a4160f6e4852ecddc57785004cd2122767eceaf9f83862f2716934b5861d9d1f8492ba7edb0a05a996e8cf95fb7c06537524f1795cd61c642bfd9d03fc2c4eadbbd7ab136a34b1a7e6dde2913adfbdcc63b5e154def1c694ac40f7ca196cacc22ca23b18eef385ccbd4ee0de28bd1ac78abb450c6a0390fbee387db63746bc178718a4cf60cce4640c706db6173616bcd83c848b226270173e224172284980ab5925f76027cd6682fd266e3d2bcd6a2bb57753572afd7c8c8da92d94662f852ccf7fd667dc23b84197a61b4b087d7f50413ab0323e173297f449e0eb76a0ad406f497b57bd0d6a9af93602ba51910dfbdcf8cf71406ffca6087aa97fcfd4e15875e59095439bd3a02b5fb1fa7a4510515d9f93d4ce3280c72d7420c51d8ff1ac021a29f0af1b75c4061a8ee95b2d090b4ef6bd579d12f9b495335d1c15f42c77f6930cd68f348356560c14ad603f696d1672772ed8fd984b439107bae355f7ac8d9e3b20b80e872393aa088a3ef2d045118a0a2210a07301c12229d76e686434f6c87673632ae931680c8240e5964543f5f7db7586d75a7f78e8a208456c405842ac667be2bd4ae27e7f70904f09edba3d936f311ac4ffbb6ba1b0943a6eb8a46320ae66cd5cc62c627393e59210ac8cb739a4298732f90ee20bd9a9bad00bf14d68c96f565ca62b18832d13d08801ba6d95da52e56d1336bdc39c87e128d84a1df0325b035f086997048b2fec79dd271edce0c07033c17e4059a86f1c054c5e0bc33265026f9b9a2e8d4a6321feea8332e0a8c0455c12b3e4cc21883086ab86db9a311dc2520deca68994482ff12e1faead46569926cd2a9bff1631833dd53c49bb7a0a8cd8ccb81a57fceb2ddb3763b7ba8992247d1795751aa219d200c641b3ab350e03b5f1e5a044816073cc4bbe8b79fddfe3207fdd0acccb24eff3b0c4771a34c480bcdc4d87e3b2baced9b89f59083293918fc14d75c049368486e9e035193c5a3b90b339e8b9a33f87a1c48f7f642bd5934d1c49889e9aa55bd46f09f1540cc68d9981e17f076610cec0dcd1770714271c09bd720454aceda4d51a3ea1042a0fe91cea0851d36ec888b7c33a40e1a7e18d356a4953aa3ab5ae6a23246701a42a41792a01e442bd9c44aa328089d48b02c9230f924ed47d30efb5aa5adebda889234c955895714820b1ebcd5dc29674f58ccc74614fafde12708c0e04bf9919c69413fb4e9062a8e69caac937c09e5c4345e6f53167c4ace8f56d0485c0451a7d9bbc5255f5fdd005ce5bf062fa967ff305dd287ef56cc966055dc840d19eb11046c65b8b5ef9ed8d625933f0d619b38cf5b2791800f26c81b0d9df414691b4bf286e3c7fc8078d598e790f8ede22a35a66966847ba728dc5e1633c340da7f4bb5f76910f1201c39084d01ddca78c1c86415874c675dde890bed30782d811882ff5574a9f2feab062179bbefe0cdc9d562e85086f54d5161ee320e54d82b418a605479e33129cd4efefe8ee3045968a812f6ec30b8e58df3b3aae725d5f6df1bdb47092c56a5bedc83cbd38c5895d824d2bf19696d07d274ad573653077c3d7ad3d62f8331e79f7dfbaafd55af420fb73180cbdcadf898b1e786fad8d87cb67e304ff5c2d6fe549f4656b6c2b5ffb5b6e784592dbbc166260b330c1ebf51b0d6e164838e8b5385c73b54b4d96577123a4b177ff9cc3205223f33f46cc601b18a0ab69d0130647d29745682a9637336ecd9a6eec8d98afea7163ddb0aa4a8e70cf3b949523e0c5bce5a79cdf65898996f3289ef9d299077e8512446c30bb4c698b52037ce2013f6146861473f600b759db576940c9fed516e8fce7abb76a14e2033e91f51792014b2845cc5ec80734a134319b421a9084d2c696a189753270f8503c522c8985267329d2d61505f9343e372ccc7c316f820f446913f423969fd79949da5020f51a7f69311ebcf43b8667dc53b738e6e5e0a2d53512646386a6549c152ef4fc1f0e858645f75823a0428374d7b15a460c8678b2c71ffe92b7878556cc68cff2722d94712515a77cb3e1cf6e41d2e3102d96d7da0937411bc01c4d7798270dfc9eb7aa4077fc6f3f578235a52d0c8ae86ad1ce0457ce600a2cc303ba92c6865a2094aa710e392e36aa27a35b8535dc60d64c5f6d820d5d21de671df986511ae59f7ac0d7a5067d29afe88c290614608c113031003a3037bd7c45014cce4d1d05a1b881705dcda730408e3a3bb32ada5e7a6969932449a44c52065d085008600854242dd16665b2ad7513a5661652b25f51b5bb6f9fb427efeddba7b127f0edd7e079ed4d113dd9d2e2fd96a43fd113752772f53352fdeee04169ad9c2851519b8ad2010b91590d3a43604268c907a5d68cbbff6ecfd3a2bf6d1f8ab3eb09b038a356282b272c4f0ed893254b16d64a898a4938f341e1b880899224fb068c01319132c44db5a9a88ae4f311826d81868d0e58eae995eaa90391d995ee8504175c69e20a911a74641c115256c3902a99874b2b0869541922e4b5692f21331407bbf09032049399928f188d8868005fc8e08b98120ff2e5b6d4ea62c1177002b264c9b2b5bc60b7dfb61a1a8fa00c344b962c59f6762fae1ed511a28871450c1e23d56849cc3bbd983de5e024bf02430e14c6be97c310b5da545c711def69b138e926cc3ebbe3a4bf8ecc8a9baeb869c74d58dca48df6ca2ce6a4d5b9285412ade5e0a614ea0f363e20a84c10badba0a921dcccc1c3f637018b36f38ed7728436b995c9ad3c19191acb69e3260de5a68b24a5ddbc4a1842c7193aef38e9c59c0c439b79c7f476dc54b9959b38272c282d37716310baa3b8dc84e3a61c5c4567fbef6881c65a0ce1b2a76eb43127f9df3163978db9de8b9920ec8e17e5a47b310ae3df838f5d28147659b1e2a48b119af2409b9e59bd98e98a366d2c897631429b7575a34d2f66639eac965ecc8b7da9eddf8d954fc93e42d31d9bb3d6a2bcf3dae8421afafece7699cc49ab59cd967cb8697b2d265ad90db4f63a0fc4b5d1ba8c74d2673b3199b5e2a66d1c957cd8989bb28e9b46756677ae8d9be88e619163712bcec90f5605bef779a5592d9b63613b2e4934b74d7ac5c5085d352d89aedba4572e0865fb6b9a7635ae251aa1efc8b19cdcc270ac295272abef4665a4f43cb1133fd4a87ef846cad4a8d63aee78324bf2ce9b6def5ea0f16296e4f8d50585718c5d6f7ab1f29bd026b7c25eec888ead38969bb61abaee6cd38bf9832f37d519a8b2a7eab224fb3939d69a5eccf462d6a5086ddff462db77c61d68ed5d92e86d9bf4ca101a0b56a0fb2cb44973681879a0fdb91678e0561ca03049c4bc993d89608e1cccc0850221dc10a3f4f776ecc9e4011249d4c0066fe49ca04405a9dba6610de3b18bc554e2cafe278a41055f00c97ef740e9577f38ca5a8cb18dc1f400d521a27d0788501d229a1d3d407576fd3a6e76a3e20d2138098349185112b022c9ffbca2afba57a512498a4479c5b2a306be007ef4d317dc1f48efa5f77aff85f5d3b7de5037485219af244a6ab904a1f1a66068d359a7aa43ed48290c3ed5952539f71ecb4b4b624a2c90a417653673e0bfe580fd7e654f9ec395379a222c75b584369dc9f6af58ee2a673f2d16b1ce2cc98a932b0ab3c41231b6bf5932eb2a25a5a2ea15a229b6bff51759faf4504838d71e1d86a11e434dc564e584e52494d66a157a888d1354272cf1c0ae07664ff77a601e0fcc53a56a9ae6b7b6b86d5e1a1e6a79df7a6214c66d79470f0c0a4d9df4c03cb0ed1e9807a64ab9acd8fe22d35631ef2cd6921369a9f78d96d2ee9fe90e26b47b93fcdb6b9beac0c916b4d65bebbd177bac8054a025b1582c168bc556d66563f6148b51200ea4e45c7534452e8e867014074fcafc464aef7e55ac1450a4ccca2c521c3c291d84211673073f27b5bd75e33197792ba6c568e9263834feeec1372b6c8b022042770f3e11eda44944b4eb681ad915e6e448b44d97ed72a41347d8b31f101a4633e8f77c0540e2efe0419b9f013fc9dc14862158419058127720d1660984459bde02c5f1194798c6a347cf08be094ab38234e168e38d23fccdd0bdf743c0ffbcee034203b763deb2a77a73d3d2f541b1e67c75e63794e4bf737323476d79ccc3f0588cc2b4cad04850771cea36e9ce8d0e14c6653ef318ddd19139e9b11c1dc4b155592676659dd896c766b87a93b97167672708088259b5a38abbcbb57297cb55efe85e979f5238b7a96ea742c6b9dd75c5b2966c1748a54a0db6596137bbee4820054aaa8812f8216632fd8dedef944a1533b6f9bd609bee45add5df98d2022d62b6bf47a4e50d6d56d78fa0365e8711d0535569ffaa1f8e6c2e37c3f5ae1b0ae32a252895d1685d82d62748d87634bb5d2ddeb65a3f25249c596470c2f6df70a80c68fb6f399b147a7256ab0b2b602249a224ff182b5808a9d0e6e6dafe9bcb5979c378c31bc61bc659b39b6b739d98ca28350ac2ebbc5164abe8e5d512e8c99b8292fc8ab6d54b7b658c5d227bc24e70140c45e4bdbc9707ab3fc6f0aab8e97e16fd8ee6de0bd402e18072ea8fedfd415340a91bd56ab3b6ff67c79e40e7f6ffc0ec498b59927f8e69d96776f371d993d7b2a427e80f51fd40f9b43e2c2ac3bd7e6d1741f1a1b67f0b63e8510cf8bf26e7c66fe4a3729286e3a46bfbf65e1e39843635252d7ba2b695a3b15c49ecfaa609dbb59b5dcd123e424f78094a65b8c72ecff8c42beae5003f0c7673235e893e68ef4565bc7013de1e1b69de4b8444952c4e9401a5892ca5bf27b32702dc208a39c65083871b304a7fef654f1bd051b1808d23676c1144e9efc1ec898231440eb8c051c112265a94fe5a8c097aea46acc5f218c3a7bda3d7a2a589cfd39e34978b361104eadac31f8515e82528c9f113dba770e12b5c78a5d266e9b5f25ea96d47efe5bd46a9ec202a6a4d81bedb6ffd5099fbf5397adabe7ea5270795fc63fcdf9fa4d9349086267b1ec61853984a35df8a8899718a443179d476bc30d45ab91b5815312db4d0428774e941e36d7edff28ff17f7fd2771de96b71bebcbcb83bc6be7a797979799142db6dbebcf0a0fed8b8a0a6fbe0c75630eb940d26d12d4d36953dd172856dd2170fe06a8f10b0a15a80a6fef8464a234029404df7a910c08d3fd338b60f411403bd8d2c977fcdf1af2ccf5f5eb48b5fc00f7f0213081f880bb127f0c35104da68b3b2b0766dc743f7eab878154422b718bf9031ce5150a141f1685086d0a608caf6d7726e2872eefa9e28456c7fce3b627b485092b7528213bdecc4d190cec7911e72ca4eec62a3215c17b324501c8d9d6c549f1ba925914c2fe5bd37763ba377763bafb5ec9bdd13daf4581eab0015855d47bbe22fd11fdad70fd153a7e90ffc2e4aa2db013cc8a1245a7b685acb49fe39772ead55df268f2c279d654f5dce2cd6c52107bd420f93b4fdbb9d2bbc14cc743bde89c510e4110df7c2dafeee25164390f7256bc98d2c8fa55f9f163a6df8884224c21b683f4b0184d53def9d1151273920a45a4ac998b2512ef6bd97e3369cdf5a6bdd5aeba23040664e9e965ab07683dd77a43758b0de5a6fce4c7cbc61844e59e44611a5e4bee50640802ce0003309d8f18536e96b48deb6bce16dc31b2712c9cca0329ffd36fd8fca6c4f4d107c33dcf4a73cf1fa27795019cfc4dabeb8a57e0b95a94f3e8f142885a12e50f300228cb3159f886d3ae50936f61547f6bb1dda95f3bab03e58ffb3a28e6b69f97147979616af32d4d1e503756c71320cfdbbe41fe3fffea43f0f50119a8ee2a9b58bb77bb77a6bbd1ecfdbd273f36ca89688b43de5ac75cebf901a3880b74965d66b0e804519acb2a6080a66a0caef8b80c6e8a27c52ed68adc8a8ccddf53c6367ccc6dc05d3ba6e94ed5084d430432dbfcf62deb5e5a63afaf69de77941bc0d77af891dae2a1c2a5371404fb887982aa68aa962aa188509d1409bf5b4e769efbddf4d2c16522da1e23297e9bdf4de5a39ee81389745d287d830d765babd5a6bf54626dd8b860bc3b3c10b7eb0445984e620086e0851e64c5d266cff05bca0838dbd07db5df05aadde915b6a8f053829c449f5c7a63d5c0ad801a4051a012204d41ff7ad365a1127aa3000714dbba93d5c40687004385ce54b3e8f86c2388d7dcd5e3454c6dd9dc69e5e9ce4ef03d484f6cf34987b0f87d4af570a6bbe6d9be7511b549c6f59c4665e38f102c76459d689d96c369bcdce3aabb3599dd559e53ecf03f1ea02035d35f0058c93a3e05cf2e185a1e78521f670e879a1e781337819f2df56f49d31f6bc307c2f0cc3300c4593484bde4adbfbaec64a3ebcf0f3f13cd0b3578f40c49899050861809343f2fd883438a9fa1b9b6a6d33a6be2cc93fcca2e568cf870f7e87e4f37ee34aec8cbe927c61458a1459a881064d430d22a268410517aa98874020d0bd20516b694f087e4e58515c38b399657dbc04d8533959df142c387bd32946a0c1aeff794e4508d736331521a0d8f5fd3d6a8e60dba7db24c1b6634ac7b4192ad54a654fa21b6d52570af507960195a142657638d1fe3554c66eb7410710c862b0d7dd210e7ac17d6f4cc99b41c984464dd55a6b8c0bf4473d6b8f3306ee895dbf9ef5c74bede1ef2ff58701680fff1fe2b751e0aa5478c04979a1b9769881ca939a62042cb6595b3bdcb8595f1566c267e0d8363f55adb5d67ada930f254aaa510cd5099d7da9c95b46b6261ad9140ca26d4d61bcdd4212aaaaaa2bf0c508baaa54b1300c1d35d0da533084a3b5dff096f3b66dfa1a1162859cb033fbb9afb416894852a3c1ee59a94492ffb3d968a66b0c909acac40a30d2286b8a7c33e0a2a4ee826959dbbfa60835e33584f249f745c82da20042f9047fcc5319b7a1ded39e409f6fb4eaaeb03d79fe3e0f213e3f1bedec85e522d96eb35dfbc44c3f7168124b871ef4356cab430d5d1f87c49a2743c2f06b42e158e3f9cfd784afdfb3d566fb9cf785c41ad05803fad038029f9635a11f81348cee587e3548edbe04d554558950a84cb551d0132e8292fc9f3c89228a6dd6949d45d9664df90becccce280c4e4261b0dc53b4334bba36a2dd62a34b60c307a808a8e9ce2a0f5f0c0d0dda7dc1a2fdadb5b310ebf34f6ce5df7fef9f100ae39ab6c2a3a0424cfdeebd77c3410058017062369b9d36cff26c664fd9da3ccb337c3a19d3a94261fc5d2d0a93294c389b85b3cd8513859af90caf50191aee8472d053080bd7406d0f5d307b0aafa024fff015ae2125b65d65495174a8da6e7228fb26870a6754a6e2d3490f83404f7825473de2f9015ba1308ea2302120b419cec2999b4cbc0aaf5cd97193b925f19c6e32316a6371531237edf841fb9f30459bf8bcb2fdb1159c634f6ed01f9e22680fb7273c8633ed2a6c13e7e49c399488436dffea492284c6361466b6fd3114b2550f98708208a2d9ca8c15ae12f3c744e06caf3fa60082e220a8a96a5d88b408d9603b46d9aab5288c47a99a56efbdf86d8965b35900581a07002e005811ae6a78da534b4bd812d6162a1a6fb3a5254412a2ea0f70fb87aa30654f9e0f37d2caf6ffcea03f6a94da43e7937d312aa3d52abe343621e809c72c69436d29963d793625b66f4898db4967a0bff73c9539424ffacded87ed9b101f2a414f7ac4b1cf88654b6c1f71f8c4f611c75169adb46e7f6ffe11156f3bd8240c471bfd3ee4327c0adee0c2ce6134442bc1a7bb0958f70ec5f07d2895e07f926c336425240be984a2d41fa133680f0fa551ab506d33747dc4f007ea82bf16431465c1ff8a618ac2f87bc4906549de8219a6805216cc3008336ced5088551c4acc4224647b2bbd310cb7330e6d86e1199e007071de4db153839b4da7d400056ead860708a592b72ab924f1b5b0fd63c0510712da3e599a694c8c5c232bceeffcbed39ebeef3b3fed3b3f1495f1b6ff87c44df6cf6ff5b176cc49e766dc6c937db4525a29b5df91effcce20741d4dad85face6df69da318c61175d2ef38aafff9ed10fab7f99da9effc509a8895609425712bd8fe38b3fb79617830d30b63fb9bdecc9b7957bc2a1ecc9b79617ce7959db11dff404f363ec494dba372995174266f323759218a30f111a87d5a927f9a4c93691ac61efeeec5e0bd39df798e5c3b4ea587d8a6546cbcf0b129159b253bdbed73d6fa867aa0f1d337c1842f34fecc715c10fc96764fc15a3b77b99e4952bdb5b722b65b8dd9d80791187749e1d5a73cf0ae1b869a65d38f560fa98795c28041ec6e7132a31942eff9212dfff996ffbc595b2940a14522b52900a1452b73f21bc951f588a35afff3f9d058a3e33f5fd3f29e375282c411f8a137526a71043ee88d949e0eb164da9918fa7b4f8708c4923c8523b48e6f79ed39eebbaedb64c0bf7d10fcdb1bd9396f36d7907bcbdd244e7ee31dcda01ff443f483748cfaed3804f4a1b1a665a40fc47a445a7e8638a9bf9146f484362f4cb673abc474ae952b6ecaa3b6372d89938ef136ebc971f6b41df921a6dd1ddb322c8ed42354663b426176a8a76d874af26d88213614541420d1f823428fb4ed4c21058eb233bb130395aa0a29c26d5ed576a2a1abe751b9d43fa3dfb7ea79d38fd8fe266ca716b7d3b39ddb55c5dce426f3c22eec56d9cecd663b2f4c55b771abdbb9a5b69beddc50b04f2da39e5ac60d6549fe177661a18703247ae3a3af0ff4b809609b8ef28c04d8a6a3f6e6449bb555b1686d36a0266c0535692d2a5b0df6444b7a636facdd72ce51ce7307e83c80d05aaf740b9571d75a7b13daec725aa4d0de4265428fdca43dd5721b3d338f8c043934b5a49725e57864e7b99b6c5f456e3bd800fb1e9d6d3b188367b390443f5922693e4216ab392edb930628c93f032a6dd223509c225bf6800504a1325013c6a161e0e0e7b8e79efbba5db507ce02b637622a279bb8573363c32d14a605b7ac1045932db464e2a425c998f6c45f8c311c78d3948056b8f695aa6a4d65fc5e8e033dd1cfddc736d8158a2a83ed6665a23a412d8c067bd29fb51eab2726537bba80159d2a1586abb3aaaaaa8a8a4422914ae5a15e5cac8408c9c9114265424dd384f4a09de82a0e20087dc2a653ac78b22f38032d6d9a684bf27741479396e4a61ec80b5092675b45545fbb6f456d67bc6d993661a8a3452171f22452dad5a6c649234839a033b449abdc7d010c5035dcd070f06d522cdb4fb771d23de5249222f554af1015b1ab0aaa0ff5aa5494844ed583c60b70b2c2baee6b9d614ca3f0a414c7d54a53273f1d317ddfc35fce3953197a02804bbe6fe6aeeb4c980511c3ed6d18e311f4d22d4f34c5a1277a1b412f6d9676c94df72975a92312d18c08f4018d9f7f46ac6d5cfe406b631466db7ea030fe2944a1753e0f4a5281a83f9cb1eb7b4559b161031aa0a3a951b1896480ca743a0c5000f8fe1b7cef41eaf278acb5568711740db516b18dfbbde0e7752e9c1885d191398942b13a2cffef5e7815d721439bffff78db70ce1a0a0f569280e1e40b2c31396b2d12fd97ec6a9bf4e5af4b8373d65a24fa27c91291524c3d82a4885859aa6d90512a69b3e670855e513dbd42721c07d68ab74b0e74eeb6a721d1c2aff94a3126a84057999329b8a9497ec70f3b54a0cdaad2426baf430bade995c62187baf36882c0deb0edfcdeafb0840e81dd9fc7517e70d4c1c93c76633dbdcedb267d79b57a09cd7d850125f9f3e0010000e8d0016e935ed1deacaa92102a43376703079c8c71e3e421692485d11e30f20065e062e046adb29084ac29e30af66cdbb6791e887b94a854211ee6f06d7e9aa67d0350c11cd1d8ba987871914aadf40b95714f79f57b7192b3a5d46690d217d0365f464e7409db7cd9a69f7eba8dcc4a95f9b98329596c2721fb0f9ea03f429077367154a676e7f7b58b2aa55e11abacd153758afc668502bf8be67d2b6e6f5eccbd46b1ec5a6fb0d40b2e07dff91b6065a05ed40ed8d134e2648f23fb1b88a770fec61137e2c6511e5b9e835da2dfd0d40eb4495db782201f50cfdb86f1d675f5a39050b41c6bcc8090b7ad04400a2f9b586375d0022b9a288b6c53881145b97d166b5880a22c52db28b747010b7589d6e612e0d0d4c9928d43bbd050182f4355b4d9f2623d376849b5040186ac973d81a3b39ce4af3deaacd965e202412f0aa84c67841c1116da0650885ea093a0f912b1fd2d1bf5545752a8fd0195c154a6fe0eb60842109da1c5b05d581b7b06819e3c1fbee972bc114a65f8a66779bd6054460c2ab3bdff2d82960495b9277fcd414f3eb363d4938ba0684e5e4c44446820e84ce321a3a1d9a85708db7d664f3567ad45a2fbb2a7ba5abd56afd5cb59f6547372b6ba2b0ac5e19a7fb5d59c6cefb328adb6566b64c4d29ac6c244e46ca995266005b7eca52da1ad3af1e5b3993d77c0034a461a75343f99d7755e8771f714a4f17c6213f03b51634344e5327c8f6853833d612028c95f6b83927c6584178892d044601e5073a08680d2a468532ac95f5b8292fcd1108db1832b4453e43cb1fd6b0ece36afce7d85da7863de6bc4210885002dc38e13b532280c7e2ff4aa9759bcf4864db03d69665052fd3844405803d4a8a0305a159554df594049f5c1106da1651185e8c9ae30d8f5beeeab25e5b94beac5c5cccccccccccccc0cb5e00bde68064ff89ebd335535035a4a2da8c5ac33b7838bc807adc5f790bfe3d42691fa3214e08e772452c7d103a30f275f2801a1cdd2c889d6b1cd990a82b08806a030feb40063c40ce1e1062d8822832653e880fe6007702c59c3060ed715578e0b278b38b459555b09fabd495d9e42c2896e735e213be28cd96c36bb51d50f1f8f2afa518563a5e078df8e260934f6f47a7ddfbd1f08ba5cfe0ac7c042efc52921bf087bdf077eded77dddd77de0e78d4dc04ec9e7b5c03b3327e2c61dedef08c8f75e2cc41731333acf136bb93dd15b9dcbfc9d37f3f35398227cc7ddcb2951fd6337ac68292da5a5b49496eab6a9b13c6a5570a2474a2fa5f7daab8213ad891acba6b4950fda6e0e1f00457af00cd63e27699f0a4fb4de428535b4a9a5546e32bb2d947c122de5a69b6e0beae415b393ee935084be6f764decdb5a810a6d6a292db53da5a5b24eb8ad05b1d8d2a6c8b7a6699aa63d7ee1c065c5799ea73ddd7bdef39ee7e9f7c8bde789a232dff61a73e3e43d535081488894016284dc5c81831cdc98f3bca95a6b5572cf7bba5605f03c2f2e36bd9e08be584b57e2a41669c989b4bcb582ff89dd73defb502ab9ff3c21a80bfe57f46ebc4ffde479f3db38f88743b873c89aa6bd4290b71deb0a79fba7e2deb796e68d7bcfebecf5bacf8513fbcf44b8aabbe4f35a14e61bbdd5f2688bcaf8e76a5a0b4608ddc2acfb590a2ab75aad1cd35bd65a267f556b783c2b6a9f2b71dbffa5e5561d3b6f4e9a77fb9b83efd1e6520057cc939f4de9b7f19a66bbcf6d7c209715dbdf5bcd9c1bde729e3967662c7e8bb9d79e87103a3ff737e78dd69df5eb3689b59fc1172c97b7915a92595755654926d4196c7f1a7b1e41dbf33c41aeeb1b0fa8dfeb59a2497e8e4a153f08430e1808e18bb213429322aa280308296b94fe346bdcbd4b745a5f38f162c6c5c5c5c5c5c5c5c58a0e6dd3c5a58439749d43868f1cdabeaeeb3d1d375a7bfc399f2d2a1d245404dd62459b1a4c83d913d65a0c6b30bc82d1e0d39280d0f84d7cbaa149de2423d1f8bdbb39df9cbb9710219aeb4d727f23104bc2288caa2004b4b27b2fe5a6246ecabfc63649bbbe49c227ca9eb8d17c52f475b316a370b5265e8d55094aaabfc4ae8f4f7c7a6f78d4f370303a1af209fd67d4de48f9f95a6bf54a9bda534be8037afab90b1f6653026c6af6d8a68b052559a0a6eb72524361d3bf5850d346497f0e567f686358ed187230b19620d1875c823e24d6781471cccad0db80bee543e2bdadcbba4e9c5c5d308aedff49b1fdbd4b83227e441584f289593d5067bb03f6efb7885709ea823f48b4f1e14b4a5b302f0cb6bf0fa5925216ccdb64fb6f378a76a7a0a4ff121e7ea25f9eece65c57f664f6c4c138984cc6c1381807f3ed9eccd2ead62e9179324fe626dbfdb64d4f963d99b64d4f86bbaf035fa0bf814cd89df8ed2cd2294b76b60a4f68bbbd973f2b7a61ad32999b4eb0021a0d09e9f888a3219f96ffd899ddb1241de268c88ed7f13b463b1be5d7f13bbe451c0d21e15b9e84d1ee8ca3fc3bc67b634924cfe30c5e821e345e1de34d695468d393ed5c973773934c832f6490e8e575d99397939373bc9ceb12fde3680ffb5e4ea84387d6610ea8e5c3176fd9d9b2cb14a665a49634e360a69f9f7dd232b4bd1639f3db401c82d00d015abe27e250c50fd44c2275b6b52fadcd1d17829fe862907b71ee7551181373d7c571a359c79b735dd765eb174c6ced3d5e170addb2b365170ac10d7567e76077b639770884c1b9f17ea0f28ad97e1fd14b6b4b99cce326ec407b2c0a7b3389ec694bf957e846db374b3125181b6dd988c3ff5ffc7d743a94d0f8fda9a5d494bf86907077ef3a777b6dd8bdf679f77aeeddeb390903cd80c062b1582cd64ae4d68a4a3197654f22114bc412b1442c114bc4e2b2e8e911b878e19435454229382575178a9054b492289f6c229188e5a61695a93432f04dfacadc0602813a90a8811e1c6bc0078d23fcb4ac01fd085f8d96a00d021a6da867122a53043d695fb0e88c45672c3a63d1194bf3e2655dac6c71b6ffc662bd686a7dd5577d5d8c354d0341160be4b94707206badb5d6da5289245dfabaacab5eecca2e9b75028c50a206654d1102a8008e12fc2234e78c1394611ead2b0788b52e97cba5c3b92996dff60a6aa5b0605fd6a5f2549e6afbeecb7f6d8eeae2fbfdfd3e7f90efe66ac355b929af48ceda5099da033d696ab868cc45632e1a73c5b64bd3a18175e5d75e188738f8000ed00cd8ad06ebb22f0bb32e9b03040495b85c2708e511800046308145112cf8c1143908a37437c8d8218a2fd26041a62559cc8cf36a9ad644df3763684c4c4c0c1ad9071a5a2412514ba9a51cd7e56ec32ba83d70129fb77ddef6799f77efbd1709ac6db012444a62e1debb6dee39e7d699f39773ce2f5d8666063dfd095a19f484ed5a1927686550193f81c2f88b5de8aa83d5f97d1f57da5b94162a6ca7f9e7fd847958a2a845bfa9efce72a2a241088bc5c3c9501bfaadd7755ee7759dd76db8736e0665cc801002855c2097f775dac579e33016b712d087dea4302d5cdc35537bb8f77df7da25efba84051a132a635302ff1170dc4e0844030c36ca605f1404f5408320f8e007043f20b6c1281004416f4bd0db9366c54915bc824593e97433f5877606ed9163d3d8f54d04c05ebbbef6ef084f90488922a54a973349fed76a4f5ee62c837d424417595e6cb23d052ba0c7f349fd22b64a1b49cef289f6d788d883ae77db31e4231f103274def6debb713f884422d1b52227a55b6b1511a108a150a94492ffee34c4d0702fd8cec301ed181a58ce99e3a6ac5c1e572ad5d02ca8108306654d11179a6095e017f914e1086518a3c44df786ca68355549fe358b52375553ac1c77c11facd5e524fe2ee7a69ed074d7f1f367c780f74608dab49ed7dd4e86edb90fb2e5a0ed8e7b23f86b755167cddc34c3970423b4379a550b2fbea0271cc54db16e8a7553ac9b62dd544da536b86517a4a196c4715fff820fa8adea0580227553e00cb5aca92488a0a623a8697bd790f017ec54ce9b0db36ddb6eeaa642af100e4e489d10c4e7e379795e1576af73f9b561f9654fb8f4c83c2f0fcc33dbeef545615a7ed0b60530b4e969797fcf03a3329ae78a13676cb7b25de511c3b3b3412d80615bc45a7a60f644c4a4af17f8e1a71e378dea8f2fa61f1c4dd1379a7f3d2f8fadaf577de5df3ea7f6f0dacaa89cca3759955799b5ed9cdb9fc69eb6284ef2c7c95a682f44555e87dcac94b62b2d168571b2da54300ab363495ec5a0f5555b9fb1be3caf0afb7c3e9fd1f38239b5e979bd5eaf94c70a591076b87658b1adea59830e292d89b69df6542a91b18f89b6d39e59b8674216ba060ea4a0a46ab19655a45bac3b85261ab59db58abe6a2aed8a9b049044d7bda14c4755a15e6cd35174e352b5ee10a1038ab6b9aced5f738d983d29a32c12aa42555277e1bee904bac2380c33a1409bdbb99daeed486363f336fa53182257d8b6a136246eaa3b4e7a6d55d2a66ab9b4711bb7d38ef7841a68f3c278ac40d3ed1947f643eff9cf38b263a299a8a46d562641ea10890000000400b314002028100c85c2e180583c269a77353e14800c738a48745a3695c7b32447621c8490318438430080800080cc08cd38000a8b4525eaeb47e8f032129f8262d28602a1b1d6e8d68c5d56aa8de1a39cedd5a79988ee64d8591aeeb0cdc4147ef14ec4a68dc9f8af72a004680f2a2e8aab5aa6772736adee8506497ae966b6703627ad85ce7f5a8d575d1ef8acc33176e7d5d762b2c778f9cc43e03b42fcf6253df08b319c5ab8529b57b97960968d772b173a6b49209c12bcc94e42907b624e295d2fe93941c8e5569d022731f74a106cd57229713a763c73b59ec2da2408aa214b329eb0e0764fa1cba1b1dcee5cbfa06c412c25a273db4ce972030676995368a210d27ba79d6f2aee3258d47d99755c8394cab454a2682da31f2bad7510c11f134b8099612b549918fbcdc4a71173a4e517dc533325580d18722626c6725d7be107e15d9405a711339fdd60d15cb55e41aca131423a6fa7620085ac586feadb908960c50cb6dea0f178a29f9a22013ed6627262d719a941b105f5cd43637efb08d23686c0639b806afb5f80c8cca9d2b397097035f25281c0b50716159c50224a8c775d309db3c63242876474e86ee73f8151048b8221761c8b54558b0476d1622964aa86c5d058b30b23840f86882392a5f06090f8810de482604350746cf22c824d257f7141dcff94190503c01a38156f61067388eb28674a68952da4f1c1c8b33da925a8069010d80acef82baa0e085fb20d53ac17dc03b8c09cf01b56920b477518b687184159a4fa423e22cb393b0ac0d288ab5c55d357bb5c6a30fe2aa37678d0970b3b08548c6aa74efce3f24a4bc42ca64051e96b1e78a6f9972d6dc65deb11e06bc84725333cb3ca717bca6c04f4e2a68be6e07bbd77314b4772d5754c81f0aaa26da5f332b9b2595a590b2275e7c2c004396b2780bc58420545bd1932375ab5f6ae6ea45999e4268e05d55287e1e6c5d00163fc6ebfc3350712979aeeadac5a50f9decfaa4c8df88929bab2001c12cb378c567dbe4b672be54f3bbedc20f357208ca534e8b1fec52debdec085c6d84fbf907b5a26ea2eb6a7108e819547024048dd545e65d7eba73d7d4b00fe30018adb4ea75b48a5585fb1f22953a07955aa709f2d8ff1468c9463a2ff80d728ffcd76cfce577cd4f8c4462eee1ae8e7c2dcdd59ec90014c1c215a3c2d51e91aebb2ae0957fb88dfa2a000804339df7f744d2952bb5d7ed40f9c005cfeb14c3787e9449c8555eb86203de32f12dac1a2d4ce29a026a54ba9d866e484c4257adbd79ddd21c2a9c161e793b40cccb6db3d2fdcbbdefe337ea26a26e4ef6cacde8d63183c12dba0114d64b3b0135f453732aa7d6f2e3aa21e3cb7a69358c0f319f4ed2c6dc0cca99c8fa8b6ad9d8820cffeb4abf0ce824606618c2aaeaa7649b8552501a219718c62bbf41613134659b022f09306eb0cae28dba061dbd09b753828e1166f52c9b27ce060b06a9901116fd9e647c46bbcbdc5787b833397885914a9d10145297f5633cbaf87026f92b664afa5127a191d2c2d2d091a71677801ac6aa301f5c7567c096aa597f1312e83ffc18be44ae3ec0cac0c7e133f4f3eef9f5df07970713222c945c7d43153f130eba49a79d90456b975b66f98d6158bacfc0c8edd3e6383400d2e1eb669104e5552945c93136d4f04cfc9289dba0ee1d949e4a2d49f1950015be8dda18338780c24ce4bd3ebda1c1155630385a454df2ad695bf6301ea14132b10629d911acd42775fff6368a1a0e685207b116a91524e6514b272498d5f43a195b932772d1c02983d2688199ef76de83da4fca5828699f5ce373f983ee57b841c3458ffa7d65fe6b64f2bd2542c8594aebc80f8bc853d0f487f27b48c2b8b8f07b4c081c1920478febf4523a8bfeace61e3ea8e66747e2f82048405702dafa3354dcc7f359bfd8b73cca41c4eb7447880c5cb482456668cadd77c90c8af77fbb4c49f8eaaf354860b71b26bbb67f0918798dae66afcd34d60bfb707b65261251a339e6dea829d1bfbfc86289b0057f59680f5231ac7487d1d9f105892fd4c3ad05ce99541f4f43d859b66c05dbd2288a743a325c072160087eda2419bccc43d97d7484861e95dc03f952a686c086202b8be0db8bb3d706fbeb323e995007bc1eed01e09639f978afd1072e19db8e930e0cb07a2a13e08d4d9e702400cb2b10cf0dc83acec01de2feabab5a0c23725a8785807d28a8dce74a8886f20961c6df241c090787f0af50289698aec7e850d6bc22f7cdb1e045d89ad9f39413b5811a0519e2e165f5afd92b0f5932c6cba1c0cfc708b40ab4e3914c92fa8059db5081381a34e854b1220c14d80067ba7eda8f4264d1cd3efb92c7a020c513976c93fc7c7702f608a7580a9d6596098fd17acfccda529b7e2295ca9b8bed23ac751c588a59e2849ae69e5537ee30ff7a1643ac6f4972492d74da0c178cce36157110a57c065b2c03944fafdf3bbd9bb9e0ae8b0cdde4b1b664e2aca6f0c74049aaffd612cdcfd17121af82fb1151261e99e7bcfa171f4f3bdaaba77cc768055ce9e50f6aa94064a59fc25fbf1388316b9ecd6262281e8da9840cc4a5af8a5b70dc46710a0c4f291d8a157a06181ebc3ec9df61d9bf35600fdf34250f46e33e73924bff6b3c44eb0f47b4bd83133d9fbf8b90ae112e262a4c8cc45fc8179ede1b9f33edf9c8b4d96ade11839992fea9066f9012be3f744d624ce78a3c71a7922f0ad3af6f2369dd4fc5629d06b63a390dc3d11145a543e34fe6e659f58063d93e8b04c0de63b2782800e27825292d517ed9a08acda092c153fd395022b2de8261ef7cfa6818a780ca6543e24945a219741112806de9222052db63be6447fa345b339462ffe8296c5a8d084a0b4fd1ca6cfd3892b72d069d3ede803bb88265a4e360834efd52aa518608b7c51f019b4b04e440ea8d94e8ba7876a9e2041006a97fa51500c58bfa2cdd1e370f0e5dc49cd8870ac2685e61f99220630acd9626737d6f6ae6cccf7880d84f4886b24ac00123c707cc9077bbc4296247cded7fbf4dab0d217ad0a5ce12d5f47a90152090c93f810fc53585c6cf9059f236f5c21074e72e7543b444608a2308b7decf6f54e65f4a47561fff5c0efb58976e113bd7be8aef436871b1f2b8d99beb6b588c01b24218453a2e8eac59ce85d3ab9595c61f099cb2c819a0eecaaaf8785fc05d612a897533c02a6a4fa9a3ae34d313e8d26fefceeea4e52c6f66782d5c1f866e7b4a90bcd98eab6c077479dc789db3aa862077fad4151c72f9230db7bb32413296877940a84d759b45b6c510265b195a5f426da87707c26bfe47214e9faae25e8db70aefd1dfac0eba3d3420d3be62924fd4f00002182b41a2e031e4fe901c66dd93e3c253e03a7460384beae8129ca5c8ffba7e1a87ab48fa71c2bbd61cb1622984b518f72e3331245f9f178216cf77037cbbdd7f47255f2448993bfc03ef50a0d541d49a76ddff7b3591d6ede8f96f7b75cfddd72ffce7f0e3b109e84897c5c6e134dd00524af49e14fca82d32669ff0176c6537bd81ea4df573c1830e7c4861bbd28f41fd89e66d318a2b03dfaf8029989f0d7b0d6bd86fc05db1389eeb1bdec390c686f29be49f764d9a15ee3a2891621dfb03dd29cadbcd81e66638d21333c99a8cf801a8dd33a1a5b07c40811f9cc92edf173d61db2087bc449655bd8647b7c59d59d320b1684a12e02656b29998c97a6f0ea3162e9a001035a12a3f288dc4240fc5777b56af541a8ed969a76f792f089e8408d3d73c1d996c3555cd6fc5847139508f3188df179efbd139e4770dbb3687df87759301d3032b23a589b5d697f76696a4a43b5028491721621a18379b89e37db9fcb62ab4699073558730994c0b994601e664c2f7154028184956bbb09127b8b464c803205f2c4c6ada9095f0c31ffcb79d47cceab82bfa4c44d68ed5a987490a34fd5b94258e0885189b74d73b2a5830dc7e71c709a00f8ff09ae543db9704a735e303c5a50392bc6e1b3314a148a312a94e15f681dd10ded96f7a5310ccf66ddd510b8c19b1ae93ac00504f361fcfa478250ae28e5c7983a8ad38ac8203b28204db16f4078605603cb17d3213cd404f274f1c8fed346d851c6202349e2f496910429c96cafdae5c78655988ba004c2b052003de9ddf40e58419ec0f9674f3474de01c17d27f1c10d4972127f644e130b078961d782f9ba9ba416f1a24e557279a417767ac112a0e65d7b1bc9d38fd12113641bee88d1aa7931be1fb8e4929a69d5083fd347de14ed56064776e5e1dcfb5f44642d90a1bf7c0aa3df60a99ecb943a3d42bc23cf6341d7b695e4953027e47ccd3395b0e88049ae8f16c1506391a59b64f19c28d021be8488d3240992724b752711c45250f480b1b89abf0162904f8418cc439fd63692ccba73ec37ab8bc0427f867b628040afefd705ffc6cc30c17300c6c2bceacc2b972b83fa31ea5554abc238d416fbb7ff672c9aeba59ce04861a1756d4521521d41f4a2a3749a5414a6cefb19495947da748e23e921ddde5f477119297b09b000c3c5d24c72a6da932cb3ac93c64643174a7cb21eaa1a533c1cce791d62d3da741a0ba96c5451dd096bb7700e1ea99f79b335988bcd1ba88fc2b554e805596ea68c8806238370589ef991ee3bdee04697f10788899bd5a36322471433f5111f013bc5a83a056734ff81c6d26628a1e8ae9c4f03d7d2b35391e436d38ba639901f38bc2961d6029a6c1aafa628f8c3975ea647d856c60bf90030e02304158ef4f6da275379c474a0120932c9a1c3a49864c91f885224e7901eb565b877d9ec48bad0dbcab5c8d6c11491c8540fed4f2fa70c6d9f00a20a8a074814edb1cc7426f0edb4847c528ebc953bd2e4e06ca7c5fa9fb5ceef6f00632946d75c86cf4b89575244146e657087535a6c15cd9d1e5d86cc2561f0d021f982d8a74472c3a2ba4949934e4243eef53cfbf3bc2314261f63a94b091f21bd20ba9e2a020e92f63a7a58f5bdfc8835c64dd6d8715714a6561cd884ec6d1dd1aedf81fe819380126456899dcd8578c8a1b5ff7813c8a48ecf4266135caefd255ce95c3abeb59c6e6c5508169646b09747521ce8f24fdff328ffc68f9b56db1c7b818b87a3e3b40ca50a09eebc136f391ba85c939f507079f8da52381494e1f978090560254447ab5408ede163597fa208c4b1fbbc73b14e920b2ecc7df6c11f959948a7b280feacaee5fe7ee8b93e9019b1c875a1effa6a29212a62151b36d924b6b3a923691d55f26903f3f6488470bbeeaa87f5aa928cf355ac116f9de752ac3e28744624fbe2b814faae3460319023465b33016379d63b957196655816ba21775e9ce088d7b589a2ea1f1005180e7ceed609a744a34fa820eee916fbf16573a997d8ca2b2bbec6990296f1ba036e3fa53bff763f31a7d4910f20b8f0b558e78092693193198a9d3d49ca4106d834a3c24a05320254b87ed1e85d3cfd025efd948c4c1a9ff210ff21b83efd8af846afdb8aac168084a05571aa9c156a19cf7005988642c7bd7bcec260fb75ca8be00c41bcbcc4185a928a85e06422b61ef8d153f8783fcfa23112244e1008771dea0198e3b03ad939f4cb0b5c56a85ec8e29a0b0ee1cdbd29e0b35271e7a122a01f840fde62f8fc6a5080b15e8ef6ba2786643bdd99fb8be2878fc35251b017613047b1d2273b0473a453897ac52f964ae8e693485cff825be993c662649851429a982f33f680a9dadd48ca2783e21b10a7ae67b284868702ed75dd1da50c3a6dbb0714bcfd83d3a3e752b100c031701ef0e1e78f2bb24fbebf344676ccbfd4eb2a8b74080f29157cb831c01a498b476dbf2c7d9087da7d2556ed5e9357628271e30b30517a3caf77d6f4da3b2189b05c24dd8704e13f1f84077c42f8de3f446eeb12b469971882ec92da2e386f4512c37b74cd822e6138abc261c809306bc684e7867cbb2ca8cec0706efa1ccef811e3ee5c19c6881336d2c6af1d42611b456d4d5af83d725f03869200b36094cc249e39eae82a30c09df4021a7ac5054100dd6a39940294d54c822f0f6784087bc528d9d89a6f8bbd68cba51a22ace54cb860ac15275bd86e5e3bb83e3c01abd20d0e9bf89534e2925aa5efad3710e320f9f8ba700b133d3b091cb86c34cd80b1b2a2a0088f1153a28d9368d4aa870110667f20fcd04d9871ee0b0ba68676f326b8b656ebf834a0949848a73acff723a2aaf086525dbc21fb9c0ac018d5edda965d332c7e7ab1d6da50541e2095402a99dc94aa321605a79b9a7f56f67557aeac4fe89ddf102d91f9120dcea59565975c32668439f166b66f99a5b137f949198678cb3a8066d0726774793a8d5d336b45e919f91739e7ab66cf802b43e638ccb6c29e0055f2c4b5c04cc82a97b8b9fc7e0abeb53517708ff009803e7f6c3e0f441e68d20afd2d93c198db9c09a9d9ba7302727517bceaa43ad32d24eb0214dfa099ae751bee13f2cedb893382938aaad6529f0d882e672ca8b967d233a1a6964c24720aefe6d4e3e11bc8020bb044e66e45e2adbc0189400558230df19ea983d3557de422e467918a698142439bccc9945a358640c807eec9d7c118c57231e35050c304c6ef74fdfea1b4de5f0ffb11c6f0cdc106acb374d9ce23a3e8d87518d3e51c8f22d1f72fe8d3c6098fbb151cd8dee0816990a57d3eee4b31e93ae7de71ed91d5223ac2cada623454c369fdad3eb87c1a3cf1db7f78a5c18170a656f4042ea5ddb1292366bbfe86d4e55e03ce6bdad59bcab0e6eb346be8315d2829780488ba7b396ab87c0344de50657fb2d01966c32dbf2864f22ded43aab6b75907e7fec0102211e2207f5e1a2abb9aa7eb07d9e73cb173fdc7414c47ebe1bb8f43e88f849b72a18c8f008eeb6fd286dbc56a462a630e3bb91e686151579a8359c55287b68cc6e5c3c388f8f8719db4c38890df3022b444dbecd96930860463357cb1704db5a96df5685b5d06775edd7080fe92dafc0aefdd464244f051d5884433133025ecd16cc49f5f2f15ba3f21df7c0d45df5cd6cb6a957c58f84a29dc7b16e62bffae958d511e39dc13885e5c0c76a92f2e7a943520372495bdbfb4444c380fb0270f879f61cf754d0a0e8405ac72055c8e8683c49c60fd36207e0b7bb262c831f2e678e21c623ec7e0997dcba3826e6f9183521c8a9ecf925fc52a3502e49667ca7e26f883ca22f080f889a5160db9dbef2000f381992f43ebc6a78646ba416f5669c98fb55c4089b586e34c8005ab2fb8dea7006133e5bebe8ab6db1dd23d2cf61f7a61bf0491e3d7dd3a38b7435c2ead79eda483d2e5b63e0e6ecef724f3f18e2b25dd31d1b3348592ac4763e00a628feddef4898004af2f93fd622ac1c2f0b01c6a638d50a391920d7122c42aeb290256b0241fd94755e151cb65af5002041626c2bf205d83ac52e1e1b435de33a63185ac57e151f5e5bb38edeb53cc9f931e7f0a003e49b8f04072b41d365c7f7d4732a332331f6031da484c8053f6f665c133fb7295769a39795508e0f11ea0baa2b7a60a959443c9b3c9a2283ed90a8251b79ee2cd836b7b7ee3740662cd13c0c25c560d0a28693bd8de717f06be8fa333640eac6c438265f3a02f2452945236fac092693b645526c354faf4359dc7a478dd5fd3d27f327e57fb2efae7aff4f83896f3c1261d812e9ae7349794b5835caae21baf0bb5cd53b40a0d2f2da4222467e2e31438c2aed97277ecec529fbb487b5da5d106eecab0ab856d29336b2c1fb1d4b48003cb245c1548c129be12b4a71b689c7a315c9c32a10ff5e6679d0a5b8018dde18b217e72f0475b5135a11062352e8842bbd5d12e0ec66176c7f4ffcc8c6e6c10551a1e1c9d3d3d2d3b3ca7a30cdb0b876da1cf2c924f17a60b6328bbfbf2a543c04046871f87aadc0f540190a9a42f117d4124087812267ea6abe3217a9dc9490ca1c957fdbce3a7c01ed1810db43e00d779c26046e0b43f816045d4d4aef0a8852b22d1323d8022114ae89d0ae51ef461af8aa304b79d56aa45cd77ef72dfbe000886caa001288e4930899d89ec9f83cc88a6869e7e7ca220f19af792ea7104b8690e8c2aea7cf8c860cd2f5acce672e1e208889dc172975cc575a9d3724fc2d92075bbf6337ef14be43ca648f7523da2544a4861776fcd0c4aa715786aaae79c467bd97785080fc817fcc586c7a27482973d54014a93ef3da843470fb0347bc9e8cdede180545ea9671a393006529736a24bad61446e8ff9a1474b65476c04f5947ae94a8d43cf861fbcaa894f9d3ec51f95d6151a1044bc1f8aeb090c593d0b7e57399d4956ac977b019fe077d291b78806d3d4a67df8b7fcdbcf25a4b040b56cff6c65e6ff4acf4cb081e78863ac0573218bff8625b3b4fef5e714fc8e6e7b7700153130e27c6a6a3581744c5de88538bb408b3ebaa2974913d2d4278475b394248179b0ac78831d90ec3792b2139de4d69b3844bb61e3103268ff6e308591d1ee5eeb122e672993a1f3c3d18a639c831b33a3d17ec804bac91589df0b545fde721e04261120ff8e9953845635d38fc6cda562d36dca09f412be04c337f792fd5dc2fbdc90d5e03af88fab2cc325598d4bb80e1099d8be1a507478935268f51b2be2fc8cfea130a72d0cdceacb7db274587d9070606e896fde04263180caa01f4cdcdaf5c5303c8d06f5eb6d525588aff6d8a39acb135f59b79ea8e1c5946e190a5382e4c544dbe066881b5e57cf225be4b9e182f87c34b34b88c535ad483e981f8dfaf98dcd3ddfcd33e20d7c4f8cd78c6b9bf7fb5efb663c88b6a8e25767407eeb56c5859c284de0c67e507022e2f6688c7886bc0649772bdcda1a2953f396d57528c78015ed3c246408947b348ea49ccb8326be6380a8395fa7220ad1f24c9dbcc1708e3d4c3b7ef36c6eff074feec4eb45317adcd0f94db203820aab3402d7bbab4001741e2419d87166b7308016bb05e968c783822e549ea739c0d8bdec0629e8a6180ec50514326b8e1c53872cf034ad11f9136d474c4a231218b88f7fd1ca29a3942558ca859b53b311ba1f60f36ddf0607042d8115819de7509889c85a55636b2e93742b4d6f35e9b58e5ade70ff195c8c86ba4110127627567ca80fdd452a54e2b3ba809e929e9aeadbc1c5cce766fd48b7a04f70b36417e80baf317a1906698975506155d484bca9d2b5b168006fdf53e4fc18f4ba4b073045b25765311a90b84d35d0fd6e7a744937ff7b5d661e754faaa261b98d85811bde5c1c5ee4d3147d6e66b6af4a3074e87c2408c6bfdd89c78a7181832bb5da0762814b2e93a35382692bcd7118d625c955f57a604e20857ae03f3e3fbf3a9b214c825528cf743240023c89820ba7d67bd5d8a44f86bf06d522deccb3bcdcde75ff915bfb5f669436f5c47365b99fd24a106fb1ba6ac4ff6541b1ae0a0f30d22699eaaaacdadb534986b87bf6180502d61b469d6f45b4c93789782e062e0b10528a92874e5915c657955f28d21274cc5e7ee840e75532743d6f2aadd27b795f0e3d22055a53460aa358e8a340389f56c68f5418c147d5ea8612dbe89cbf88a85ab66a88cdc750bc6b4daefc30114e594bb5781ad23aec4bb0c23edef2a7235498ae6dc2434361a1a791cee111c161808b40bba571b791716719b15bdc449373d6f4733221efc0f45dd7f733534146d98c00f5fa1264ec69a349212ec5e37d7fdf4097af98b7b5726b8515f9c466efad9df2a060904e00db2c8975abdcedcc4c3da9014795753615d79b62de1534b448cbd0b98af27d043e619f103b4c22769526d9af2b70e29514eb1eb9a13300961f7bbf7be07e50b0a16d5eeccb7b9dfc5601d8917e63513e07e18b278a1673c07c819a04b886177cb73f9fa76b15eec6de26e8b383044c5dc257972ec1f03a4943d54d2968da7ac10aba300c6fd7c87541152b5fc365abbe4521cb69766639ffa131090f2e1716f65bdfdc1a2cabb38d0df3739f5f34454638562d3a4352173806f055449aa426b4435bdc28dc62ddb0a7da28948944b1ea2f0ada05d94e92f5d868a290a416c397c82ed5315133e764b7cffc5693322630a854a3fac7816150e7993f49b0ad81f27be568f043e2a11c54f04b1194775e8a31d148368f19375ed564ca3e8b5b33e8860ff30bf12d4b575fdfd2cadb0e2acb096ecf50a41814bb0967eb0fe2905c3ffab6223a2aeee537d7339fea1db1ee5e45ff5d2c4f5bcadbe0a0ed5e58da223c5335cb6a113f62c72f60b5503d0a56a418d7e24a6fec4befee67c9ab6364e16808a7dc679d2b862a5c26e86c74482ca18f89c6458355a649bb3a90886e3b0ab79b354c13a2a51684de8559433dff6e53a234d9e0095827eb10049a8125a477cf8fc0c1070eb1491bf3bf8b787881c104bc19030975afca95e9567475498c003c6c09efde7128aeb2985567c9ccc52bccc6ed26425e704deec189ab1185fd52a125dda2f7475a584cfc57186544107715d27fb89b69514a218230fb5a87fd8747538cb0fd4cfc92682d90247bba4faed5ec872c90ef1f8cbaa950047b8b6d53a3e762fad4d75564d464ef0a2e684e43d63e7fdc0309431b6881771fcc032b30438c92a41fe4112be8923ec9080b270fd93ec0483e805137fa5f849111eae65f94d60f68cfc89cf006cd2033213747d0739641229063a4e9cb01ec47b88492f3469f66e11de40da0c2045bc6ff952e4ebfc130a186ec5b539f4e33a00ea4819ca5a9ae2027ec7a734e3ae9823a541750ee7d909a4c48ceff62844f12798c621478bd353fe04ac48a013acf20eeea8bd1b3c3f15ef59ba7563a5150c553652c7bd1e06571f72d8f9639cb1c6465052709aeb8213966dffe83d5fb4e4b978ed8b4d1b3aedb82c1e9db89cf2e8bf8092da318d85d97a7c58270b20fc4a2de71f9982501fc48599db76a52eb92935e392bfdfad1355e018647bb4b41a527a74c52e1895feb704069b61210697806f32fecdef802205a50a79601c9e8232dff0052d2d61ceb6775de81aaaaf015e04ced6ed1c97e8b1ae53cd716835c9d1f424a8dc6e03268f8b026e472b561ad500d02cd0cedc571eaa3ef1f040ff4becc0a554ed464aa283566d6293925303723fbe7b266799f9a2139f6a5f86a39368f3c2e126ed1d19ceee3c9c2f27dca5215a3a5758b5a5417241030f1537502aa426651adfe8d4f00f6867865e41c4c39367e4a242c2a254030bb03ead777eddbbd393472fe972e736761e8f8ae2b891a239359fca35b83302555289aca9a6b59c2544a3dfc896c98438464d7c123e503d50dd13b952badc182a59d085ec2af9c257dd8cbe8725aeab26a0712716989c5fd4ee5aeadc606a192085f263ae14f50bbb83c5c1d5689bf812f2c986e011085016f8ad71cae6a5c57efdbb47398b8a14207da32606979e898e1c96f6fc593760491e4a091019bf576b7ed07bd411ec641e4d3caf259bee758d144644f3e6e9a943da71402e3c6176f5ff7cc0b02974a84d9cbcc645009461f49c35424f115fa125d5e29403ce9be9441dd37343f05c6d8a8f56cbe59fcaedb96f3306e97491fa69291acdd5a80d016220010566a1ac1b59da677af3cbf33362ef681d259694614f842efc15065e6a50d93aaba93c1fb3eaa406c27132327707790070cf8a1405cedd80d5178c325f2f9061f4bd9dc501e42a1f43d92f1ff1d41eebcc18f26885e288a035fb0d8ebebaf32127caa264499f0bd22ba565033068d8654fb0030b28949dd0181be9e05ee28a9efe351ac06ddd854e0fd4a3c63730f99bb234f0a721004a9c443512fbcac416aeb704a96c70648bc54da1ea91e6022255b9a848979e27582844bc96fefc239e1ff72869ccf0adc1979e2797f82a495df90c078b49048fd73af50409f1c94657f36280b6dde3dbf442dcfbaed2749ccf82a624c4bc450405d6fff7e747e1fcffdac69cc3630bb258e9ec3a61574fef4128cfc848c11c7f852221cf91b344736890722d5ac2dd591861c020e2e951ae71b91538a6283e43cf0b0eeff658b4a7c8954b8436dabefdcd2cb6758aa485cc7eb9fb941e6fcb0a6273f23a4ea95b355c0ab035ff5e54230bd35ddbe9d6e074637ce90535871219a8c21062c6fe8827527011c02275794042e7dbc1f31d3e2494877c5f48f2aa6e42044d3272307519ead9acc7957ba030d2da91229d80dbfef18c77eddbe133e4b4fa54883df2167ca20d67d87951be187d96a8979f39d6f8e3b4c82ba1afb3dd308b4a8f75c5944732992908879bb84d98a108058903989b73cdf8ffdfcaad7ef2231cdfb5e46f7f53491c5373339fbd48bff4459f51545b70d1f4f486b5894bb9b8255fe609e2473009d70de4fa3276acb8fa28234bd3ec00e886127d3c9973ae11435d30e1b0bb0451eeca81a28f41333b84614e980af898533249b9aa75534129dc92c6736d5159e9ebfba6e5202e9b15315ddf09822eb4f229fec984d6b4b17aebdd31e789256fe4c7e1d8ad664f390879ba17501f0152863763df641544c7c74c09950c89ac08a02e837f28d69e7b147822f500a3b5d3e0cddc673e039f8754577e62336943aaf49380316923fbd7880837fa5a7fd3a2a41f83f2658e0998061dfca634ac3eef0e839a64df2e5fff05c41b1c43e8d022a5c142e48352e65a3d919d50cde624446043a89d714e2b1b6b472a423e9505e9de0edaa82e002c800c93b618b7fb91be4e9e95839855f0deb34e863f2e3772bcb01b96dbab0609955db9c1bfd9773b891cb154fa338f55316d7c1e4b358f071dc0123678930234fd289c8bcb4b97e2ffa53c1427388ac297025258b756aa53a103ab1dce7344c649c421b90c24693c06f97f224cca6a7007ad7a7241a4f242b766561f05b7112e31cc7b085e35db0135d40a13f1666ab114dd7cf807963c5d0cb3dcda3701208e6c0b4c309fabedc28b458e45d9329e678bfc8910c98b78a699a6a60dcb024743afc1737c8c0742cb9d737ea1a8ac4ba95d972a97bc855f6c95316f77c1be3bff036a50e1408ffc2cff7fc172aac49e13c9cc3e62cdd50330eaad62e72ca63fdd0bdf04956c9762f70b6c4ebe09cb4a036fce190c93844778e0232dde4ba061e97ad60e5d9d48cf14a936a42f5d90a82f44c80e451a60766691034a781d4d86fa0e90501a40c0065a1e793379f876d2575051da6da9c3fafd551309fdaf2bb851ecba63ae0b774c4b0c5079b7be7ae46fd7eae4b3e53a9534aeeb14da95c7b7ed54bc2715d811b3547952a41641c17788c54519519b86a86ab1c8ac8081822b75bdfdc6e99075e33b7e0b799faf2b0a6798324f2c202f69f40862593b66a6eaf6a46c2b9b879b509b4398f12e156bdcf138b2666c5cebd973f21249e5684c974489ce803d56b592babf0f46d031e1ff65ea02b33f10b035959aea39c588774a28743f8410deaab34e799e34b1d380ef43e221ab40513a246d9ef060a2c8a8ee733147f9291288e2a507a03a2767416d37e992ac8730d315b005609ca90395d11a44edf0bfe378001a6932655c7b0cedf47b166f456d462ad46523df05346a098a617c5519fd93ce8a02ac7aee9d2318f72793623d579f6d9f4542e6ff84e674f0c78d1192a784fef960161b7442ffcfb523a7acbb5ee5e9023bddcc8be8d7ac308a96516892cfef267be4fe8675deb5f48e7b0f25cb048088d61cbe7cc2bee32dce5deff28b1bbc52ad481bd4f07314853dad43f6090f53d9f5fcdb355f3a3093c51909cd617aa4558ea67cd2a59e83861892a6b7ddf0ca24cd9f3280ce56d65e509fdb25d7d7892cc423131f18e9f42e79b09d026eb946e34411020a129f3e51836f9dccdf9f15b21636cfb620f2b5422944d24fb589d498377c528b05e88d1f17922c69ff54e3dd1ae8787ddd5fa01fd52d8fcb3827bd529092c58c2c7ed0c28bc56fee8a7e97856dcc65d25ecef8e4881574b5dea26040cfb2490ec1990068882ad608c935c2e1e94bb481830af925c4f99a74880a8762a125f9285be843c4ebf84999513cfe0d9c7491c741e0069f613cfa10a23cf8db69e66f8ae46aee89795cd8b566f4073b2b37f52bca4579e00da3b42d03c71ebb0462e4756608e18d1d38c1d42e67e490c07532b9923f55d33ed87dbc2513421915d5907f18ddef17671c140ddf11a596791ccbd74c96bbd03f9ed597434f728274ef06bed38129e176b4a9825b9bb5c03e14f5176922f58ef8f84a3a6b575ade0a3b67a9de098f9a41bb93b3d4a1cb9088c81a7c811e8f409550bf329e418b5d5cfaa2ff001347e839b3e0bb9ea30c687999e36f3b7cc54e6ec2de021e78a1833d1cfb46619817a5ebe5483058adceb47ecb89d2a30a98fdd4ba5dc47ce290ac3335ee4371f3858a16c02653463c6642ea7752f9cbee4dcd4d1a6381cc957c3b10c5bc53e4506b8e474befd02e514830ef8c4b1975f64c413f514406a98f42d991505e12b567b4401f5d944d434fcc0d1cbe3c53a8d958214667c6104619d330ee8e1c1a8c10379f120d2cb1cab07e060e0361a48c66f5a794c141a3ca92c9afb255eb1d4e301047892fabcb8c60e051f3c240bbde9965bb9fb360078126581e0a9e98d77e5090421bea07b82477a22ba6b30eec3917ea049636e1149eb2223679a5a8a2dbfd7aced3064609b46b37b0db25898b361738f44886c486ec392feb5c6263c32344f6e6e008c3212cb99ea88bb703850f04e02870c00129291e84a37812cd8c0f0311a03b6e2d67230632b7a0db409a20b187c1212b7af95e6f6cc2df0bb64c4e2f8460400ebdd6e461d22c08cadd35378402355a291a8a55c1ab9e67deb50c541ea32348b626f7b29dd89390140b324e39b5d61891326c871688f51456eb677c86736a40e75a442cccd9b70033f224dd43c6162cd217960e350a43cc443f53221e50b4d3e6e5db1326da4f2b9a9e5ef89240fe3b9a1fe2d71249c5ed36bfa5746c4a3677c725533dff358363305ebc45c89682f68bb4ebb38765cb80dcad025daa8073c5a8232e50998de9a87b24b8d0e297bcde9625b3b023cc098b8ac3d7c30505272e1ee9c06db6864dc804dec00b39ea1b65c48dbb76ebcfe64d8be30be11eb5c67d25bddf07fced703ee5fa60f7568b2972b8172d629fb2bbc50d323156e9483f2f55cb2af2965a6403221d45c4c7452c372f437e046069a309593b3ed9de10ccce36ab6bd33d019b77e5d17c9f632bf4390a4db51f043c62ab0cae15bdd7ccf345cc8c6cc4ad4c225a02fe35be338bc8332460909cfbeb0f731d6ca873d04765f51ee11c0f1c6d09d1d166aa1312bd900ae4e58a9acc81f8c3618d1c73e6299887fd1753589f23e2ad6b987ab1e85d0cb5bf9fad4c71efc6f2056552beef494cee7cc8a8391bf35087e1f19a7a318c27508836f4ed57cc144e5ce7c5e1765bc0b5734dbe5b25ea3003308b863df36349445cc07b6d955d0b03db123b597183d8e429c463c2191af5974c2a327a383d59324df32502c0ae674eb489bb0f85ffa27cd03c51d0771f0292662a78c37ba782571c37dede63935bd87357d29a23f72882180f2765cadf7e650ef9ee7462ecf427e5de3578304406c846ea1450a9449e9017a5c2f8881a487fb9f50a741b092c88400d3f909a026b70920bd253d54bd6a13ddb6725c9c0a49c9d0c0eabd2a3bae4d48726dd5f78d2d4f8da4ae343f976a20c57690612579a84bdf244c70ece9605a050869ef88250e96e0d1b651447ed0b05ace5311aa4d9ea16e6051cce3910448aaa176c28b323bc84aeb7ee12d4103ed260713a13d6fe4f099d5d7c75fc8edd33989844f826f0c96cbcbd908cfcf4e50afbb4dc0ffa8965a87bd41ac97bd3370194e871f7c25e61d1cbadbfafc6ea9af8993af84bb11bb07c8c53a904661d759b00b6c2c35e42301a8c9e7266fb6bed8e449d6cf9e96809f7ee0a1d1248a37f7dc5f5a1c22f0292ba9cb5813618d2233ba60edcde041aa5740e9143177e7a80b294f3fb8ce2365b1fba46f7db5e0e0716f175a26834bbab9e65b081c932409fa31b7655adbc59a8761f23fd461b85298b597af60e55c8f8a74c5f6239460e65679959a46458f9a1d0eceafd9217a9059f8d02156621dad1675b5ca6a89334dd0eb00bba5a3a918ed0c99c83dc9eb28642a71406dbf1bd951ff0a5c68493997f705691318e361be28db8ef1760f4495573e046bfdacb177d8bba57080ce71fadbd56fa83a3548f48e369fbf0957f9cfeaefac252150146db31109b3bec386ce0ef85e923b6d0b65fe622b1fbe7888133665cd4f6f745b2d1e7937df6440117cc6bf4c92b59fb7fb186fa2bfe96e0bc08e02b8d553576d1e29740d81321af4ad1d19503cbac5e9a303239e0c96fa0e6d41bb94d86a88006f13a7abbb5b76aad09296c90fd33ca1814c9d50a76c4713656edf25f6a495167cb4e9f0289336cb6b696df2d78677f6f26c91010321efeb0b5e77e73bc6d449667f03a47bbc9b35ba8c190fb2f958f4305967999be859216354a1c47eefc73390c72921a708529514621c0b647381cb090b015b3a6953188a342bec16b22364e1724e4176dc95137ad43717b19cfd161e4b22d0842ae3239dd5232b24ded9fd0d1d84acdced0c7b41d5625552959611e5a930b637f0b1108a52ee1d920a87ddec2fc180d55adfe8146b5a22d9d60a2ec8a9de2fe8c1412e2cef3dd6602cf1da9ec5dd190ebff6efb0c2753bd6260191dde8b04cedb932ace8856c6ce1123da802f424b840953a420c89f71bc37f8f213a1b41f6570ba84ff344565667ab499bde75592c8f377934ff6df4a2c4d3685465475f5d19bbb0bf8c907c2b05a68b3aadf6722794b10844fc6d1a3d9398a04872fbbe9e8a9c2457bedf0793e8b9a6bd6210296676f48e289d88ee88b8a875692088bf8bbd5d20497c0dfdf3577bf93ed6b933293db90ceba7d59da45abcc97319ab5dd53e8d9355746edb5ef391678c900dd62eb77429144cf7ba788d81c98a476428b12273535689448dd8daa6589d04e196da8a60b931b8d2b61efe1a637d884a96ba67b716627fa09bafeae308b5aa700e4eb86a1aeb8b72f07c9035546aa6e5e6a7cd39a67c0a907d02459c2f2d3139f0d606cc41b77b52b51b09e375086a05a2b1fc92219c6d6f22d56193900d4524c96a15eb341b7a7a5f2a8c97a71761a62cdc8197c59a77743fad27e339aff9371dd02afa7497ccdaec03cb9dd2324f3195e0f5b7355d60731b4095efce2a854074b0b6136bcca0fbdd5d8d3afb86c34c402b73981be51f0a522ba9060032869228256e6689a70ded1644079dd165f6d43f516c3d58e20b91acea86af7ed4bc538c154f7875b2ecae03b9db0392119b2c5430d409239d4c130dfc4fa713b2a6ffc0cf33aca05767c062c67768428ee18206d1512f8fc5de4c426130defc0a3fd080be2caae2a9af6c471a0053a40d254abed0ba8c5d64397500a6b4aabc4ce534eea950c09f25ba4668e95f9760a0c3bb402ca5a7aa0b3ed10b7e62f97082722102652b3c2db324519b03c016fb6e6835d29ef813d1e1e19f855b72344b61afe04ed05ebfdc467bba2aadcb9d60cef71575e621fe984517acf85c480471fdd1b55a30be90248aa488c2785ea1ee7fe22a083e24ddff4c80d48341253600375f72f80e966001a3579fef16d33b667abe86547a59df6febfeb5566c7fb950a7db46abd26480c2fbcea41fe30e64a19ea97576684c9411acab0d11dea17be570630179aa4a510338f62d82d8d6d31b881c61fbda0e6ca8414a21b53f905618d47e63131cbf234e2a2a51fbfb3d7cc51baeaf81330a3b67ed6ff86fad2cf3cadb27aada5bfbb3bdb75092bc6eed0f31fea677f236d08319085c7e8d01d332b45c50eb8d8e64b0c3608277e86dc4abb5836025174081ad7c5b1f1b3ba352ff8d09a991defe931adb7b0d6063742c848c80f4bc91611094e268cc7649be95a223b6856edc05e30d3b8389930be65189a22d189191b338a24e4c11ac84a1b6304ed18c6953f8054c2b5e26dd0f68684d062b06ae7e1c5bd00c1b5a2b28066f187bfa0d1b7b2a42fb467d0047c4e889326a846f8e96333a22a6074afe04100ec5dd700c0df2128aa0e4bd7df719241d794a138f6d9cebb7cd959703451488e8e0cd07b02be9e000c4b484f9a29b0b18c7c79fdc6a9c3e0154ee9717344b7a00752f41cc80505d193dcb5d6a61b12b7dedddc3bb4eb7c0a79988f4ae33577da0ad11b8a33db4ad19516d2690beb015b3a0515e336ee552a800b605e0ea451ff382a57ee1c6964f93fe58bb9332b4423f48045cbf6cbd544408465177ea8068caab8014d4e531bbf19235c5a6d6d25c6371db453ca5a4816ed725dec9012b678d37be1b273ea55a5eec141fb4d0453d106a3e8d2767541ad1e6c697c3eb205571f37ceac7e1b90d399a8c9567091dc463dc232f74e752d71e1fe3c9ee22c084beec6c9c0141c07cbd3eef41da0e4981be88c6d230d8e380a450324e20bb052b8801a783a241e34494ecf2fc66a203c7ba4db2aaa15e708511975c9271f994f78e98c86c498548724eb21bd9e601c00a56ba45c51e0c4a554cf47a7c8a19440e07ab89706f9f5c0b8e0d30a4ab4100b80dc1d8e5c04615ed96d582c769a0e1b88c3ff3e7caac4e9d377489c24644e371d5176f6007085acab6f575710fff0dcf09bed0b0bc31546f073d56d102d3345ab7f89cc0f232ebd80a279ce3ef02cc94133d428a2cee016efb30fbafefe0552e7eda8e46f7f0f24c4e387e10ee0fa43d7818e870b600365596798013071bc4a5802e06aa87240ef6c19731edb252f6d812533f81322c08f13bca256ced7c968c6e63f7456a4b4879b642fe6fceb8bbbfde65e0c8358ed70c7ef5f3a3a540b34c75012e8eeedc4cc7b412d8f2424c1815fdf2386ba4013240845b08970ca06e0b61e2de1096375dba9b8e4f0ac8ecc199354fe37cd269d8dc038fb43b737c4712bc930b30505d05a7efc57efe2a3dbebb712eb66a5458413ac2714a7c0f261360bda749ac4a3f305332cb75961c3ee7f5c0cc0e99e9fd42c5470e5959fd9e287db6c95cd2ced1db06ac3de71b5899b7225c506cf17c51403a6652580143e63b08813a1e84ee9cbf590c69226589006528124980a50c4ec2362004d9aad05cfff3bade72004ff900ee1b49c0dd6bc52b90d08798274b0ec144df2d01dfc488772fd701a9ae9011d7fd7ad5f538358c1a2d452b473fcc8172023d3f8ba347c48f90ed2637231b6650dd77514ee031f0943a3c90add59907adcae2182dcbf2518d5f1bbd41818238a864cf9c70d0d63c3ddd86222cf410ac5fc9b3d3a3694ba032f649f8527ac823253c2193928788c21c31a6a3195bf1448eca1c54f7725c04670034117868aed0a87cc1a806803f15dc9b1b0be3a8f21672299b514bf559f8f282c27dda1d5498f3a39823f0ac8b9632bbf163944a4155701d1e2b61013999cac463c0faa74c2360ca9df26ec8a02b1a117bba02e41306c52cae6e90b5a561fe4d7d66c221c94442a2d3117f2a4d73994cb374348edc18d6d66b91b2415f3018175499ba6a2041102158964b5e529c103af0f6a189a7d169c92bbb08b4006c6d86593280df41d893030c1ade3f3511a55f996c00a1478030ea60593cb17bcb417b589d18776f49c660f1ee3cd94dffc2d4c3a8381a272cac82940091e5efb083e4b942b90c430d966cb0f05a746522b5827becf98b724b2b0fecaa72a042af4692ddc1a884b5ec80e1c3fd14c5f34929c98694e3ef3943552907d90e8c47913d89ab0914f9f2c2e5c059c410d40c3a30f170b969e1752bc5c2b6a8646014e45c85806a56c3c09c30f3386069917c69410009c957267f7f498e5cd88e4a5cbd4a2464ca3f8717f4c2db1ea3abc3609b6c4773ba65f0c4c7c77df42b4a35e66179b52fd97a13f5fa01c65f29a317820c6b183a9ec2558021bd7d4d8403ff8239b7791bee6e2c9051454d11fc2c6532cd973cfb0c60cc23c0f1801520aeed6bd94f109a72be6afc9225e656cedbc27492662503c71451c63fe71100eaddb63f4fe69be4e55b2dd661c1c1d7810e1d6a33ef60ca8ed8d10a0bce5ae0e685a6c216b962aac687815128ed6d353b511da6d722dc9bed419ccfeafea861248b46f83dd5fc6e4ffd5d24e1f99f0fdf19ab339d2bed9b9fde07929de34f096c3a8857e95fb14cacaed37b2aa986febf6d964769a3633b37cd661404576cf772639e1c5517ad0da147c5b83c371a1bb129344735feb8fee4a0e48e7246943551aeb21c85fc6237c255eb7928d3e1b282ce77898494bd62caff71c098d08112680fd2f5c41a6e455c541e2436d56f613221b2b1c023a7f88ea7ef335a5507e260b7a4ee1e1debd9f1fadb1fc194fc16360b4b808cd28aa53b5a78b314b53c051c0e9ad92ecdc8bf48ad8f61db13d27bf395c4809d7274b5fd987fada5ede07fa875f63729feb1168cb76caa687c2a3771bda6143af57da4dfe3205b205bd2dd04b977960d03117ae20ac2e6b93dd94a819c6ef19a41f257102bcbde036257d05ee450884f6929a0c8db55621d4513214a4d7f2c19dfec70cfa27fdfd7dbfffbafced8d8a61a25b1ff9314327bbd37afab976d3e7ed9cb908fee2c33f21d21166bf95f39afc7a7a6fbf30b04abcb8065d8f8f5f643d5e80cd0a581b6ff5b3e82e8d4c4b6f7d8a065f81eb23ae69078e4c46c40524c5c12fa1e0c5bb9c01b4806c3d9854898a5fa93067823a088d9813f4de91492826b557d2405f53fe4859963f76864131f3dca2af917215eac07cf82224eec45ff4e03ace03879952d921129521156459230d6d58222570e066aa62929dc3739da080d45be41694ae8522c5e043b365062e5efe3da39d8e0bdbed3108e533e629af25846989dfa0a8b5ae4cd012cdf1c2f8d56ec2bd52603370f146c7a591ff98cca777acb7ceb8d47e0c40645bed63b1f97bfbe7b86d35056b38fa00b0207d4f2849521c3879b7935ec887f5a3d23ecccdd721d95532a3e80f924e40ee36f98bce7f3fd052449cf81f29e6bc2990a5e9c38901d69a456ab45e4a0e0382e6d3ee83ba4188103a33b62cb014560a7be500b347143ba965b670ce60aab16aab3a319ca5e0278927355b224d315238e56b742c5e7b7194733663e298d0798f896d1ac7c15f53df53e47e374ebaa2be94aca9b81ea9b1034db84889310ffde8003f697244a518073d875fc77b4fdedb48cc3654e66f9ca48bc155a52d632d4c94c14b1383ed5a781db47818582e984ee3b725813d5bbc609ad217fe7493b1fc8a0090deb67d9b67da0ffffa6fc031399e2be29035eb721f9298004c4c05efcfc3d04b1f79abb23aaa05bcec24250d03c470c74e20923801e10215deeb93e0cc819c6a698cd04f92a84cb70561457681816ab64b8a0d1b94ee43ada447fa1fad3380565d40f553090be8e130c38530479435d5c21e71623a18fb1f6dfb603c1cee8942bc212c8f155622d4a513380ae526ace371c74bc639599c86e1fb69514056b548c2bfd01472be1b32f8d55145746137ec212cf35b5dd86b733185ed392020e408701db55e259fe459c6cfdb1785dcff245010cc8282b6a95ec61387df5ac4389aa06976aad34e80f46f84d359e5299dea960291d3d2cf5fa8ced9ff6d178d8a1fedd5b3855dcb3d7c76efc88ea2ab503af5cedaf3040ea8f230b97c14496f7fbe5a1336597b154d367ab063028b17ff52b020512e1b920f3041c72d8947006c914633f506f14cd231b60a24428844a420c3e92d233e63d98924b4933a31d253348c3be477d8cb1ddeb35a829e25444c86c5a086135b3e16b8bfb17c6404858f899f1ce1d067634b78e4e12160e8189788a0f9bdedcceb965ab52a88fdcd087634eef8893b910c48daa02b50e655aad6429d34536c6d843b9f43c972880f381916aac7331750558d1371d0978514519a25f5a7e3a9c203ef1ec3f75fcb45bf69ab30f06e6f250c1858769bc0c1c5b7888eeaa69e98a3c742f97d6ad90da4b96832fe3a1c764285fd755f0f73c465b6d489d62b26fd1516c2db65ef292128f85350b70857be437e1d9fc85501f19ddd1a3671a107244672575042f52c34fda088a779a641da7fa9c801a2948d2bcb7f6dabc88063e9f34792c227b6c405403464df0b706091599c20dde2bdbc730c745aad03409486c9df099da4cc11c3176e89f8b880d7fb22244f40e5c24c6763964bc399180b7b6d7c2e419f021fd4cea3930245b9f6773ecf78e647b102efa5c2a6220db6a66b823781a7e4d8f4f6dc56c0161fb3a579c1fce6d9bfd4ef4434ee6cdcd30a3ba097e468f5ac5a7f0102864e31aa8a98d1153c4f892fb39909b55510940c43dcc98828f2bd097caaa7b8f9cbcc70c88917041e64ee753a70b00909346764d88ae5932f9ef41af0a4a91af00ed60a61963c2503feb4b298e33680b7f752fd6b2989fcbb0fe4cd655e8e9a6043e1645cce28598d454d058f6b1719e434755ed730a1f5af865ccec639db24243b5bb0e0cc86338386519a7f2abe5b958004126f903b3cc3adfc18a0c5c326f4c9908d13fdc46e448b1f230aa889e9e54ef7cec56f271b9746b53c96b1ed2258a96db84958986c83ab80f25833113851abfbdd3aa4982f82069a010718dcb7e9c6a02432759e17bb76dd19ade07866e3fe7be251531357950ada085840391731bc7338c3340912cb441ee128c6eba3e2ec444f8499698692e626f5b3ebbaba3a123b8e065806ebc388153a5693fde82a823ba5a9ac802342cbc8c2a38ccfd64749750b0b4f560f4418b0234c8d63ed0ba121085311c0191f88b668f79f63b644323429e7f1b67112e52d1918452b04c41acf1a88973142dd24da4d767275c78551d5c4fdf07e8d10eac582f618b7a15b899cb02debd005df96ce5a379f895b3792b204b9d51dd34121cb0d410263aa3f86d8d0e470c6e9d473a75bad3dd8901d939781b72e7378094e1544572bdc50b7547cbed1b73b4ad10a5dcaa860501a74d5082e019bf78c8be41b8d3ec38dc8b23fb0b5870ff8c7e925e0ac8d10f8a782e5a7ce72fe99c2e2011df1365c51ec1bcad618cab67ccdc72ec6c81cd830a3f8856c7eac5a15be7ed1c1a41b2e89498a5f13a38d108c28c75ee5125670c39f2db485c8f168090e40872319437e09e423d7b2508b38506b5613f2112cff75c2d18e019f297189134853879051291dd96bdcaf29da9eb6791e55b05018e415e03d0cc3da1b83784cac16b75f69fe0d913c37ceea456710d668e23b616e3aea022f4d9359f4bd592ae83de73297116ef4f8f447af911f9ef201010a21a178c1fb956cf9e548b23d6d1e5e1f1482840d0bec8ecdec88f8342b483c566881395a5e8f357664e85a9766f6a1f92dae615d009f0b6bf92d1c584c8dbfbf08fc08db87f2bfdb7798bc2d1722b1e21701154b109f705175f245f52ac467de4d43f59309dd457582f0120f9d1b5c5e65b2cb6dc0e20a52bf9b043e9073c2030adaae3c64ff00ffb5ac16d2ea0332eab40ac9b19ffbe68b2fe816ec9bb6b0a89fb3f93364ee03354f8e6d1ae4acf9e0cc7b2e22d10a8243bae41d3fbcee19b4e7ca87f5a730b1d8f393e158b7cfb3ff6ca28ee70fb8ce0ffdb0d388c60fc9dcb1e8d8a96bf139231e95945f1d2bd94a498eed689894d9c293c88cc5f8044a16c0c7cb334624143beea6f74924eb8664c4bd49769a415564fc4c2cb3849604895099f12fdfea6156264e8fca1bd4fdb8ebb5de7bc990225cd7a269b9dd8ea299cb70abe2c93bc90b355b3c99b60a40364064ba4e6d9383e6780a07ad0a4ba123b01673ace8f4ab4dabdd85ec6caa2977e8087f626b59258edeba40937a00f43280acdb9fe28a2ae53361f41856a01628584e02cad10ac745fce64506398a7b4241035168c6d7918e4883c7a47c8b0f0ea48f0fe6ae1a74ebee8069516f40c66772952e2dee3807c07528b49544a5a0aac4166bbd48257d29b9c6151da45501e852bc0289946bf49b4bc0c5ff15092aa806096539133ed3e05fb763a1968334cb8d52de7de04d17b33c26147860822b033aefa7df99d18d9b1ad61d30b6d2dfd27eab4c20c5cde4c583320d562dc0c37e29a74d6dc2d2143829e5803adf99c410e0202eb38f82831339d6cbee8046c9ad0d4668ffc368f2f417c30db18e2507a937c014024eb930d82f74f8abe096fb84b2724abf59dd9632e4c6ce056790876120af347f03d6dc2ade35dd573e7e6f301e849990f80071abf5ce9e5d0a0d17338be01c581cf37cb758d6cf525b5dfe18382f48ea7fad37825abd0cbb61cef9374901945f48ac2087b13d6fd8b2702a528a3f64e69a9bb83abd9f162d1c2dabcfee73dab21668e8dde52bd2d376a6b8c8083db605d703814033722d3203cc4956250f1b09fd1f7f2dfd3b2627b2ddba7af8c61d6f3f71f7be3abd5e7082127ad300ef1750e382bd8ba25458671cf4314306420a7ff204aca42dffec34cb1e0d9c27cac6168d664ca651bbd68125ccbb19a86ab58c641130cbb967d33888959adc594fb00fb27d1044cb0b0a16477e36892223374ffe480697e50a47311e0888e0a5048b6b65e68788740d3168d7e5600400aceab072058e69f5d318d965cb2dbe84b24d660197ad2d94926dd5053a00908c655031876d5988dcc5b025c40390f2072bfe0d7ccc520290943b23e045c51a2a5201782d46901d1962f0829732b2978c5670d79d1280a7f5cee7756b45fbd7c55ab581f13902e6e2df1f9280b1eab4edbcf7e09ec2fe0476cad96437921374ff352554f8ec6a41f7d63548497cba38d4fdce8c25df524abe8c521203259eb51fc6b5b55356dc4115ebe09aa962fe78a699c005525cf33137b3d4409e85be537f67c13ef82697f1bfabfee76da875b47b3db89cce289cb791f6287f30807b54e4e83f642910d4f67aaa0b188069f7b6d781414ce6529a2fd7144fcb7e43769a7f2e67bb8f5ebea63ffb1413424c9c9e23971b177e6bc74e4260099611809a291aa797fbe2e34d125f5c1d51d934cf1d8f5f9e92bac338abc48181d8ff1983857b3ac2a50fe24d2997c0e096e8244e34a9692393d6d068650ab4ba3bd37a39f6b6c0c215f39353f82c70269202abec1a19164deeb2f03d4f0fa9d10abb01b8921d3e76f5c0a7d7e915fa3b9d8afad555ac0c94d7c7b4c094aa55cd1c633d869b5fdfe0f7cbb40d214d47c881865b4626088d2816fb9e838d60515dc88d09f299d83784735ca8338f1997eef4a0a0db1c081323080f6d3f99baa3564a56b2e701b64a0ee5bf8a7579eaf30a670a11fc79df565025608807f721282440179e282c21d5c40f05a3f89939655c25e387e179f7fcefe94c996c34c1ae5b4d435a6ad59000dfa508291a8a7b6a4e5032ecbd6a391ff5411ec93d09f0b6bedc40e97c4d53c16b682764e6a7aab058ae55cc9f5de1c1188e291abc7b61ce7246b758e4a8b00b0dc94ca1e6e685220b8202e00dc8bd42d995855a4d1a3c9a55e7ecc89aca9994c68a2650caf7fe19d0f50749879b95de07f15a3fd3b4f380f4be2abf5ce8f5e00aaaffbd312b770ac2c0a4445ea7e5bf509c8b70f9eb3778582c769866637c5e64cec57fa4444c06327415560e7356d86c4fba446f5c23b645d3671a5c65e27158c6cd8eaf23e7da6de8af49b0760b0c41540cd271d68c761861beb5f05a022a3e28cdedd6c7166d296b4c9eb224b5c67ad1ef5290f75467bcc62b72f51113b0d74f9ed7eb2270d476faeeb492352b1bafceed3a3820a82e1ab0b6863ab34401b5cc21c69fb8fcf70db0813356042be382b3c41328b0fc3eb23fb4051f9401b0452ffe439dcbecd929058d1e6bd5e74c86f50ac0cf1a6eddf3098fef1d09f95d755abe75e83595c11f18143db2fb265aa4681f4707027c671a04ead6c016cfef1a3a98841b6ff48f4de90383a2aa2b2bb077f95bb300dc08ac725c7b4bccf7045ab535f98884350920cf84ec6d54aaee5005aea38cdef9c268af504549695f9484e65c89931cb47e2dd54fd21f948f4da250ea66e6a45eddaa64b84586467dbb5b2b6dbcd7e5bbf8b30f0fbb308f6c62c5d7ab9672a00e4c84ef292087a83de48ad29048353ada8449e7e3e80b4ba7186737b8e8d379b13944a1ee80fc27147ab509d2e79a455bf7fe6132fae14cff4af994a53a8dc93608a24b608edb8a5561047cef37643486c1d4bdbc495ef58175013146f893cdf94b756446e0a7906aa09c8330a09853f71be04c8cde8f6e715673ad18492222aba28c65a10a4e862b8fc998d37663e9522eb07211d2ee7807ab8f4fd89cc182fa98b0c6fb87e35da6b6af8dc9899c32e9417d332473a85c526a790be20189c2760e76ab79a6bb199a088fb82406415eac19f9bd9cdce712d4eeb6f8e2b0cdf9b44b817672729b4edabbaff34bc020fd03579effd6225b88b6323e43b8b22978cdba79169bf008ba0140a16c3eab599ca5358a678821731053fc5b9d7c45a38bdc6959ae270dd8dc09f2d28299131cbb347d37f38dd3507eaad2d7e8079c4cc89120736f5181d16a1c9066735164db6044b6882de0ff4070486dbcc3f9fdc3ce70fef4551b9f2205036beb8b1dfe3a7031cd94fdda66417410269687303fff3e8ca12ce50ae31bbcfaac92f391c157953471d537a0fab81280c61290e4130184d8e612ee609ea477ecdd055b80c9136d9de5da9e04153b5a5c044969c9610e5ee84bd48f735994f1b51a7366a5d3a649337337f14ef5d6779887e4f4909531673ee038b479832c22b145100b14e8710364bb6a15b5e0f55ba3f13b70fc19b572ccd89328d8f0f7477c327cd4a8dbcb784929be789bf425f8afbc2b89b44982d71301f39151dc7101bde94b13526f439fcfae20709a3d49624e81cc16ed487921fb6ec0228473aae5af9bdf2a997da9d705bb57bb3483f50386123dc809c33b5b5589a5af02f6c53ae3b5f5deec43a1a5385fb9409f26a69f65cecee7c790810b6da4066c9da9a33ed40f1dba7951b1a6bff9cb6bf5bb19227bfb727022f65a0046366385f278c88b30efb514bb6c2d4064b5e7df8124a1de99d8d94951fa4781c377892c7e0cb596e2af1fec729f713e6171970373a0fe8b2a07cc15a95e70fbcfa8a924a05889709be1743dbc89d445997b71af710fef22f122141aaa5c4fc9cdd219f74bd6cab9ed95eee4e68afb19765c67235100fb59cb6faa7e71d1595158b3f06d166dab9167b519f7dcd18c75ff4b123308040a9e71bf128a55a4b6dadaac9bd1765a705e404c0bb25a7ad42df4488adedd9c2102264c9d1fb3e99e54428a89816b90deb51fc42aae52328dfbbb0a3a23232af757f3fa981a43d3de05d0c0d3b367e7476c422979cedb0948143e61327fbdae48baeeddf9817c440231ccf7f94b5113c783a9a6100e120ade1474b286b25233dccac40e96763493e6abc38fd1b199bf21ed191655fae7e881c5d01b96e1439dd2eed9eb44d78d908b4534750840d7e0552a775fd9d3cda3603b1e46e1b863c9c257b3b1cd6491390e5a2bbe9e488e18f83556d01f658e1f359c6849ea1a9b2c21bae829243392fa52e4c355c0d9065a978e49d521e93869efae57d11972c26195798a9f1e96abc7a87ca3482a78d9a9d328bb51ef9fb24004d2844904de246916810db876d3757baea0774be0905a13726235135195461a13af57b7b9ff6b2f85ce18aa9a37eb27a54a20039f931f7c3c4ca928119e5c21efbe0ace3d19216a8706e1d6d180ae169a3c24e4ed1d3fc2236e207aef5bf611cfc79910d482451a83b5c4c74c8ddc8cde3299c37d089ab0cd86ccaa4fa214d15102245b5e81e202044358dc06b2344b7bac05ba3588d14635353e59c6a7c4be1209b282405a62c0dbf36053a4883ad704f2db3ed103782dc4cddc0da565de13c490fa190ecfddf623854fe84e668e9fb757345b448b2db6eec6d337a0689005063dc89754c1c937f88fa3fd2db0f1836efabb297bb66b48bdfb74f59710ab34599e151632fd4d1ef68243c488c27c49b42ecf346f33b7d05f6d79633d3264add091a1ff9cf8e5313581b582353b5737730a2652ee49a83609052d4a36ca30a70f4cd457049dc13a677ec7ceb03fcc93d2a0cd480a247c5967d9b3a22be882ef0a2d2c5efb1b061a51e3850ed127c442bb93e3e9e4baafa2298a70049f41b668b93ff5e711dd21f7f4f9c24d6db84fdf29e6dd22822a3881f68c1dcb00da4b64433183997accf134a66b2c63b04e9e52cf576a8fe9109644d4cab14ed0d60812058503a09953b25773579355e17f03e7a5708f2e0b968c980f033cd3c828987468f84d8a09046a74fe3d6c8e5449837c47917b9d3419bed6de4290841aea7bbdfb70718e6131914e7e62e5ab065f78968c44a06162595321c1ae3692642ef7acb2030b52d6571a7d3f8f0399ac2f13cd4018ac9c780b93b1e8fd24493ed16948847c92c681e34a0bd34ed41baedcd00b35ccad2efe797bb1eb2df05fb3a8a8a746c4a6d38b3209407d1c0a19bed56d1d1d3b93bc8fcb88c6f4a3ecfa43dc7c6686ccac0a585531f42af400feb2542b989bdf276bf27f0efd69e5773385661e6046efeb0e671f581a994ca74a7053b003845990e4dafac24d31ced919b28184b247a4c17f89cf798433596b81b380c9d52fa5cade950909461672d1488a733bf64c1114c65914dd1d60b28ef9536dd78482b9837a31fab3e3a0543897c7632cdf5ba266c70a7859a314e2d76729b33705f9b63bd581531d493c8d9bfe63caa589d5953c1cfb197ef4f648bf228fe70111921330aed6abc7ce0955a0eed505735b3abf2361d3c18905c80a28e8ea256b65e0157d0e35431c312266739b56bf501192c73d54bf3979836562ff2c0d230882996a5b2bc037d4c0b13846b13f68a003a5968491275ac270e048f9de9c614fff66d3b27cbc7b373880cc8dfaaee65d0fcc4e0856460cbd316763e78cb5eb26c48d341d8e66b9cbfac30297690fd1602f61c6d887b0e0d047c0e6558a295dc6217d82d131c9cf100abc7ed6a5f773471e2b0e44886c533d2468d3636c0729745f463735a9674352c01d8610c34c905b1a9bc2377e65c0a7f7379e5559a5227849a82472dabd997aa1799ca10e60dc0a334ced2700e22688456171c92c83def194293ec651eb5ca7fe504b842155cc0a4c96a4701f694c2bf31913e61797058068cd89bfcd92b01c3247f9e6e14c855ac390be838dc13552b2d7ff664e457595cd5c375d0a951d1fbbd56c3aaab317e8b89e8acebec4a047b8e002bebbe514b3b35c99c105b75cef2a1f0cb7ec64327c5321ad8a27e65b116d8482a0f28efc41e0c1184cb24cae00548e4c2b390c8854ec0495665dbdb3165abb1c98ce30e018be0f70bab4efaa590070a17e3116873518eecf0e565fd2543f9c4f7602a038d4484323cac5e2c985b1d2fe0369b228d454b1e48c1402b93cd5276e20449d4930634edc43883aa5418af20cb0bc4c1a9a3021f9a160ca6f95ecb23c95e28ecc962e134a845c7c015d919d2f1be249cf35615943a64c0eb841da8c7bc97456fe125e5383988a3b1613aee4a0c0fecc379ed2ab36bec83d5bf506b42b764c263208c1d190e64cec73dcadcab74363d3e55594546d3c4ce80349e650559a95a4ac872a8ae1d7d4b941cc0bcd8e3911ed3c463aee6e08915914562274850e762d14e839c15a24d0f22584dd7065a471b09fc012a5f88db1a8fc64154fcf6f2c0a5a21e28d336fb94cd4430037fa515522e3ab880208ebf3c28ca5abf1111d674ad3acf741e18dd0155f7b6dd151f20389b6692881bd7f651d6db1e47a91a801e01af2a4bd7e607a3815e19f7d3913c3f13967a7a94f0d8d6771a42fa3927145192111969ea8eb0a08e5cf81acf09d3c748c85201c2423ad4ac5761a885b221d3dc3d3c268548d318012f5062e0c7f2fe9bba66416a6e8b54d89443b2d5b19d8da814a3c317594fe90bc32a90503447d97e2bcdc249b54ff24f3f9c22db59823146098e402ef5e25eee64d7bd7e1ea190515ec222cfa22686160ee37c052d79fb5db7a7c73ceca70ba7c57b9ff9df2f916cdb27326e8b4d830260e4143b3b2464f96aa5697c4c22ce78b685f7eedb6e35d5c61645f993891846192c855baf1f27a17d1654cab6f0cdf5a92c42e94717057d590aadcce33d70adce701b4a85a8855a9ea43d9ab13ac64ac0f02ac2be9d2454ef3e0c0b388a0505eb5bece0340f6b5f99462c20098315c4c4f0b359ce20142dfd0a8f52a4b28d6385f6408bec024fda35c3e6222c1c21119029e689b8b120eaf31cd5db975e214287b1c0d77d6b14d87dcccb2add383ba2ef9c9db10cd1c7e6205c424d183d06e8d0815e708ecee1a0a57a883a2f11c59b2fa46f07006b2eac16c0424cc7ed99259a3f02a49d217e1c2923a3dfdb49974964979427210f63cb5c187742201feec3c552e02f3ba753ac5657eace354f08725688e2cd6fe08a29f9cff35ce91d77b9a6569f4c57ba99178b90e78639e809fa9ffb8468e2dc8781b2ee9783e79b2e90e69fddb1d26041926d9b6bf701230477f00555c85febb3204aebf09154ae221683bdfeca112f270f15f8a446179591f61f37e0ae23b9f6cf0d80d9ae3b30755ffb73e384593215b874570f1bb53fe6fe5de38255ec08aa23aa025a91045e8f0dffc70498e7427882a1b268a2598cc5239322ca469c44008b39cff9dbfe04ea4c05f4071eb34d6acea10c0543f953dceb5ee6b3bd5fa71f4efa256859e3f414f6c98455e43a8ef8f5689096043acd19b0c32aae369fee88a203eaa869d72578a3b26a21c910234493ea5d1f8fa6e90bb374e7b85634201aae0451d462caa17009f1509a057ae60c772601f82ff5d3c02e54da05a93ec09a6b2889bc38f543503ac9e173212121dcf3484d0ad4e40b2d1a5ba290806aff3653e2ad27aa47aa3df12d5432915994349f69bcbb6a9d608f35bbba38fee8af081763bf22ca45d4130c32a8c80aea4405f43f4f59e03437fd2a8770a122ad00e0eb49e31500a71d507e98711475c02216e5e37076acdc216a98746e7ca6eb12d1f19e741124efa4aa501601e8811a94636b1313df1166cae179fd12fe69e62182f80b3c14dd0beb731589ed532341a1cb8a355931aa65ac9c3e13dc9e34111716f19c0e69d2867216d9841b5ead5e1fa742721d437c26cda8aef364e7295e4a9a6123424ee6527fe166a14aa8dca3c9c4f95b3998b3a49b99f66d50109f9b244e9762f2084f4d7bf24ecdef7e1f1b726a72376a3f4ef58c8e745683065e1d0bab5f401ef311b701ec01a40a031adbe9615d3052325207693177d5b624c9ace738100869c0fb925a8154d2415847acecd17903a6bf52e4750042c726cc718e0e2062568b8261b8000431c68c55373ee4daad9f7b800f7ed4ec2bf7c3609355473d1146c41742f6de7b4b29a59449cafe05f305270639a8340885be1cb9408efa1de6a1d0d3061da7ff7d356d40fe6c0dd0ffbe096b4b2a4d5637b6a4e233dbdea21d8fef29e8258cc159c4431ef99d20af98f98b40316f600667de7298b7bcd53295423f5f15dcc077eaac9049ac51c4f6229e9a2a17f3df1d12162d5831dc21ba106e59a5940b9029c7419efc7968c27dbc05f3425c5ebf909787f9d2a6526663082d04ca7c21fa5d5e08ccbf3c0d7d14f4bb3c0a30fff2f3a3a1e003f4bbfc0ffd2e3f41297bfe7c584acc4387e119107d71ceb2f63179eb89a43057744b859dc5dc58582fd4f12d4ad9b843e948473ae66dcbd85bde1a432ed31384a0a0209f1a445395ee9c99c29131a23dc109933645489b69c43cf9a4229b49c4cc946ca0c51974e3c3437762a65288800ca7dfc0add8ae65cf94646248b32664ce1812ff264514c9cb4b398269b144a2697106ed4993277f39693287d2f89aa201d280b4293361d2c67720233003141d8c1993c34c2e63f298c97f3c947968c5431f439efc47a0b8c180627e018334e838bcf3e04da68fbf66103b68266d1c260763489b221c09ac06186cd2640934de7f4a215333a5492bd16a5e2cd1006bc09aa7aa1a30c80baa9aaf090a9ae12226a8608932aa9973ce49452460f9711b6943751ccfbfb3829e3d9f3f481fa794967449843174f568c4a0c5525e0dd99352dc2a958e90499860a92bede05bf1a9b5d5e4db6b80f4b0ce971874ce94f6b844585cc1f223d45732d9f662032d4e99cca9ee2670b1c1d85b66add49bbf6503eddaaee99715912991363d5a9459382031a0017963b388712dd689c5dce3388f721ce5a4cddb23e48df92824643256e71e12188fc3a10b1072f154f5a1a72ecbcd96ed412c164041aa202effc2dc8115245041b1dfd1a8d828151666144392523f1acd6fe887ba8ee675b4afa36dde0e41de8ccdd5fc7d9bb7812190a1697e5343e6e8efe55f5e462f2490028d9ef42f2f1ff3421ad16adf8db450e8be5eb017ecbe3e98480413c144b04ff4e27d7da2cba6e39b97bd50f7dfeb3857f3766f94cfebeeebc2eeebbe6e14bbf9dc683496cc1814887a91e334489b94d7e03c9ef378d6da90f3d8f083edfd5f96b0bd9b209ef28b36f945110f0feb82dea23cb5569a81b00ef4cec98f923fa948801b5b26b19d8b9a1c3af286bffc1979034486feb28815096405bf991f273be9494ba50815bb8b616959db7e721cdbc7221ed38929a259b095048c319e3be7eee3dea3a6997fcb5f75481b7fcf76974eb04706757474cc58066243760059a27df8a7e0afe3df83524aef9c79db728f0bc86783680485eea93d94ba7b16b97f18678c33c6b86464c4f2ffffffffbe49d838303cd053357f7e3031e8698bac6aadf4e3412b0dd5061380f853405dcdd2134eec8964826e02d2a4933aa5b487d548da389e9bcbf71d76ab451ece37685f1f7af21a4de9510a0e03c9300d327565dfd7bf62e000d5f0aac4830c87fb9ee8b58579e9401718f0fa70a0185a89a1950b124c424fbfbb1ec537c4bd8e4f183607ba6c2013176aea76c6b7b6c5509036856af414020ac942317ae2f1a1a99012f2e4a1267ca4f09123121b26045093da2843b2fd03432b7a9a9d7b47843edb98d960428b482ccf33476344d388a2bccc80c91c496ac91cd84c6d460c00403562356435acf80d0b2de4ddbd7f8d5908a3cc018038828550850d5b14d5b8b2fd6b4ca9f103801dfc94ed3fa30879639d48d95a8ad8fe241c644a34c43cf91bc1c316254162915e222144af0124a1c5118cf59a8144dec08c33583227c35c3123c9f6d73265fbcfc4640e7e124be66c30bff9a48c62211313d17726263c5925eabad81649ff3d016a5a9ccf855e8776a610a80217dbde9f20ab888191cf03dde9b7a308cfd6aa24004500a1a5044253239afbb8efb0273289a2f8c9452f0fa3789e120d8a60a2d708266d569a348291449fc44d10915a304e0433c25c216f44302da2d70c3923c90c2472660a894562491b237a1bc144afbf18ac3312abc492363436066762d2867b85469963ed10db9f7b0d795997b471273ee2db2186bcb4b1609d8d308616492c126b3b894562d998b940e16eadb5d65a6badb5b6565babb5dbb66d395b6badcd39676badb536677cb72c3f8ee3b80f4c2114147a19457cf4d07196ed7886b1cbc4d2bf6bce36b6bd9aaec53db8273f7e0a6410e3d975e1d90dc2b3fbf3310ffd6bbd413485310bcf6bba5692e0191e710dcf30cdd6fc660b9ed91abee2788667d6e65c63b3990ccb7ae88bd5f4c939833e6849730d45f5e005cd5bde72ce79c31bde72ce79c3db26b72de76c6dce395bf9edc8afe33a743e3e340da487f55e4cf1f7d01dcfdb199368fadeef009939f22a476e09c81c1fc815b82ffbcf51ec90f2de7b71a514bf9d98524a29a6b6ab9fad4f4da14d29a5f4dea79b10d2851d2072bcae0ecacb0fda7efd5a4b25d4113a983bd06829f8d41468aa565aa58966d0a2a4956416dfb2c2913974023429692e84a1c552a954aab5a6e0f2813bfdd28f74a075400c4e3048109af9ef81414220cdfcecee9de9e26ecb79cb5bce5bee9494b20c3a29e93451fa939a686cf8a0e9cf9f94deeb5e9db3fac81a0aebe3b1acb56ea7bc11ebd3d8979b624b4a62021bec20032a98d04082f1c5e803145b58118413242c5858800297163c3c146822082b341d6a28830995e37c587fa83bfdfa97d27dbf821b53da938db058a49452a2e82ae71c0b513024d0f36bad3c644c676475def44c72d3792fc6b6f3bcd649e7a4f35a2c6995ec2a273ad3e7b6a462c4caa65275719db3ce59e7acf98f48593d8e27a694730420d49c006aa2899f52ad0664e59e47299d3470a05802f2e47fe5ca2569a1c5c7e00f3d830652a3a1f284165b528102884d3f1e19a4a13f69b0e7cf9e26bb61946851d680c899813d79a004902db4f8b424f1bd78ce5903b245f1f1b0562aa33355b69af0bdff8ffbffcf6d195ffba2278997e8235a26874077cd9c755a5c6bad359760022dca9aed3e8072006abe9a1b35d4877ef14057e98eabb43113119820cc273e383825fbc4da27ee3686d0f8f3e328a1c7e8881671688d310e8e748c29258d44a31baae3f0123c87e1ec8b9cff51ee212a0cc3102655f4c90b7b52c671dfbcbe0099e303efc92b3cf4e499a6ea0620aa0852bd20c74802883054a11a542fcc2354a117650c25e5072dcaf1c9cb9524690599aa907ed1a3f0bd07cafb9487ae3cec5ea4ab94c77efb76ccce4433f5bb88fe0514e2bde88790efb54abf54694d4f795cd9508116e90aa44556df7bbf022af2bdb783d29cb5f6189d6daf43c5e9a2b4dd7dde0972502255f3cb201d9d68d193d028574899397ca544741ffaedb073529887f495c47b5253e53f33859e3f1e26113d0905668b9e4efbc5891627d09432611efa4fd0e399401efef9a22f0adbc1007d8d51404aefdda8f7022433e546d1b79463321c59ad562b9aca7995577995b3ae9141d32de69c39849ba919c32aafb81a19b4ad91417b8d0c7a6e31c73ccfcb5e9639730e59e5551e418d3cf9d7e001d4ae0d6b0e19c0165aaca9bfdd1a9489013a53470925acaad062cdf6afa12182cd8b384a983313666a0e2941e1b2c44ace80262f207736566bc5c3597c2fbe5d776ff75dee72db6ab5857ee9208056f019ad4084c673d393e338d26884da416270d0dc8f8ed0a2049a337c45aa62402ecca009346ba56d2249a2082c5c2b9518ce201dd1a2044a85a181ece06278f406fea03d590f99d30179f22f955c5caaab0b5102bd0469b9800d747f6934a0c2f6dcd39cb0bdf71e28c2b0377b4227ebf69886084d1bc081b20049f2d6715cc76d1bc76d1ff729f1d1afd00fa37184c55aeb53adcb65b758ad7dd19a4df34b8a43206389556259608fb050b6ffc8099adfd4df68aa64a97065d0baec68a9a8956e96e6a187e1bfcb25f7065ad748077c5fb268d1ba682a5b57c9ba00b0ab8c8816adcbe5728d5b13742502b5e8c125fa47f4faa74a7c2f77cffde67ddfffbf95ae564f140a856a0d5998140f633f320fadccae3c2e238a6e35827971d1a2900b34350261727ed1daa554d2ff4141a62474a6a75a08f2101a906c19ffbcc1e1e4fcdef7795dd77df7e4e582e7dc0a0e20a5960818395151385bb246852ba8e0a15b93aa9ae60e1f0254754194163d7f8649063ddfa250a82c6ccc22b1f24c44bc1d3676a034da6ab55aad56cb5b396bfd7fbff396b7bce52d1a96c23044914005ac2654415e2081890aac50e97f219c72031c5450b81771b6931ea85e1805db9736d29364b66e243d0c0c284ed20b49e63d1289f4544592f9b67f1d8f3149d5e8c524765b9b58b05fc8e712d1752393548d6246a351cce8a96a341a9146a398a7aa18d2e8c567940079b17d7e120504a50525934152a677576b9d4cbcff613f53d625d383a1e78b25397e53648e1ef3fbf9645f4ce6783f56216d9c03c5cfcaf6ff64dfcf179b39be29f2867f319054681b83630d8ff4540bd568aa93d8d66ea8e6daa21dc7d48de2960a4b454dcd16433520d22603f2e46ffd01aeeac01d3cca9176128ff4e48fc731040a1a6bf85e7c2fa5f776e34802f2010e0e0e0ec5c1c1995bb43d1907c4c1c1b9257baf9d73562ca67071d921f48d3535b3a646e6d0a7518346103aefc83e4fb0f0efb30e74186544013a0f4df9f098c3a8bf324bb7e60b640caac89729da85271e72df6d5b7e3c5af070050fbddbd3c76ff0f8c453dee327ff2ae40f0a753a994c33332e2e40de7a814d29278c8a88d0e21cb7cc1cdc344dd133e3fb359546107aca79637b1d474d9f3ec7d115eac2677eadb556d408a8191e5c8cb3873d5fc6bd1763db79b59248ab4e87871eeb21d61200162af13729072de78dfa9d87f2c675de17023f14ca0bc3ee9f2b9542336b6dd6343308245c40aa09a56502984afc91142d8642339ad2e1a1d9bc6149704287ae8466215a141a7f68160a856837a8a3748b210c1b08045c95411c9add9c730643169c6d175528e59d046bb7e0db037ab7a0f7dcd1c34390011e8e9ac854f140992fc918128320222af93920843d41396fdc9b7368169a91c6ef08574d065b66b09af1e1e383a6729ecd5c32d95e6fe00f3ff9e723f4cc59e684baaebb0f98e5d9f6ed60c17e0b795f1286d09b0f1284d0e25cedd47ef878693082d0fb954e9a25206ff85f5314dbf7a40ffa50428baf80ffdf388e9b5c4f192f2f8f628e6043801bdbbfcb1eb47910e741b57a90932173241d22533b9486ed056bbbb459803cd1641361141e85cc91d34433bd1663801bf1bda048c19d39863cf90fc934202905fd0a2eec00c939db7a6f2b28e8e5e58da0bbb702992ea3a3444f5034db342788667bbe6886c53780131a86189600618c2858f440441720f8c1902a5a7c51a489162a989a174f64f16305184838913501230748acb89841e5ffff8fb10e500a6c9db981961bb43d1ed24ae79ca552ac3561bed033063deb159fd2aa542a95acb52514d8160e8d26a104fa53e3143b3c21810f230d06188801c492297cd0e28a142a7f148ebdd7a25062f4f0e941dd6949da03e0d870c864329963eb1f8f4c832fb6b29752b6006973a54dc807ba6644a98f6de17c6fbef9de7cf185c97a70394c19b1a0668840571b61a5a6528d0fb6cd676e31cc7675b7c94d2838d080a50ab281f885cf07d5f6307034aaa88270a0a4a703d8ed4610ae595a0dd770ed074d770a999eeaf740c1d2ac145d6c167cb3e05bb434ac45da34b145b4959accc12f716d33d9be7aa1453cbbe2ab15b6e226f0bc6a0375e8f4a05fc674b6d123a265f28723b827f327c8d987cea7ae3a0eac5c2d4d12a2e8104ab6a2068083d78a71758cb10b2ff9a188124564560090b30f8ae6075d6529b77aa66ff1937b1637c91c5ec515d2c65f0c61cb79cc4f3f6de5f4f922ca7b9186f7620d13bc973b44f323f41f13d14b9d1ef424c5f60ff1649508f4414fde9ba62a44f3c39305b954ac5851bd808d5041b9efe974208e8f403840c040903973038d596aee592e25428b3e6e1103614b2b3944d9d43d8be8351fa5cd148ddf6ef1b36c1a41e86aaded712919c7ec1225b1d1c2dcf469e6772f55a1ef1e859010d18b40219d88b33d4702e40ce374261a1fded3d0a0d0cd9587413cf42f12c231d1e4ff5eaa3c134d06691ed07de851f8defbc01e29d0938352f5e244fb8b389b6f2c10494a25a52924be58a2882c4a54e0854a0334e0c0e48a2f9e3c91c1bf9bdf8ebc7978244fec8828b60d0f77f8e0e1e111b30f1d7a7aa23dcb9e3225b14c810410141c60314209d5fc924c491d70b14a62072d56662d5091b660420921ca606141453597206309d0163aac7e604435bffebda00ed78239ef3522c3923982673e9b4d9c03eec13dbf6d1b49e650fc6e1a51e137409826731c3f0ab57150e6295d174dd1d0ad7b14b8f74021a010285748fe4daa28e8628416f10ccffce65af17089ce8fbf9b14c457f02c3f7e29dea0ebe2233341d05512d1433acf6f5ee8ec5cb684fe0bfdf75c6811b585f8a3424f33ff07cd045108819fb5b6561e26940bb4f81ffae83c10ec329e93e68df6b8a46c4f6c0ca16b6a027093318e49b72de38dab95e36ae57a5c526a6ae408c67167671c7fe5795e08b5710664ea817c3f93572cfdd6bd9bb77d14e9de7b0fecc0d72147f976d480df76e3b82de79c77b830b64933b7238010420fdaa2076d33d4799f94d7274d3a9073e137f029a2b8d7e26da3dbf6dcf6f4f3ba8d524a73deb82de76d0b6171eda044d39cb52e95fe293de2a3c37f7e3a1d728f9868717e2efb3c57fe14e8c989d84ef2ec61ae6032a1cd15abb5e2b1d6ea68815e3dcd8fa7a120d8fdd318c19224ae95aa03834011a99199aafb0d8c36930e14f2f4e42b6a64a6fadefb509b0b10a5a3d6fa1171ed40bf445fd2cf2394a1631a091f6fe579dea42981b65bf4be19cc1c72de9041e6f830a7915982816ec1f609c45ce91bb6ebb0fd4751e898afec1654c48062a5cad967685d3d1efecb16bd9a37feebadf55a6b75ac9ba14e5a27a594667d8dbcac5c823063b1582c16f3c9f93f0c51a8d116bfc6621e933127aa699fde7b572699f229d29538d9d8cc17fa825336a578e8311c9c982bf682b97c4e1031b1a50344b3fcb2eaa4c0af20b67fe7b3b2d582a33a0a4797c743bf366cffd14c195ab4612cb4313bb3341bb3b219830ec310bf5c70001800a106d50b9309263590b5e98396555849b6e8c92aac21db96558e046d59e5486dcba7ed6fcb2a47aafc9616880168cb2a318c3270065a561902dbe2c3a06595213ebb0a11d6965588acb46c5965050320ee5a04e48563fcc993bffc648d08bbae8c903953c4b4e69c739a6297e6def9f2940c6394948a1878642dcbeb4ab8c5f9c2c137e27ca242165bf40a9044f682d13d9f07dd33a439cb50d6644dd6646d2a8142fb4b050f81bc60356a555630d8aee56e1867bce1edf6b8b4888771dcd919474a69ceab5a79bc2ca14539fa0d0678644eaa8479f2fff112c612e8bcc55a018bef74f79d1b5e41c438d1b685b344d3afb44afbf22bc220e5c00ee1d9eb2c8cc26074aa808a625ffe0270629fd80ca93e2e3117247cf5cea3e716b5afb6fc982bd9aece59572b97d8125b24d1b242460d7ab22c91c2d481426fd2a6053ad393e76da394629dbcc4eaa083cc99ff03319e98610558585554d2891eac50a20452c08acc308974368ba4b5a0c9055ab43dbeabb5b5d6190d80bca03e967a54baf73a0e8344c73e11e8b1ce03fdc74f6ead9452d6ea811ef3f07e3c421ba55ecc43ffe942daf807200b2dce18bed34a173247ee9c3aff5d34b8866c8ea5e6af55885d41912b556babadd552ebe204c7076b2da594d65a5d3838d24847730e496fdeb8b921053e2a6b6dce261c334701e40d7f12a48d7ba82b5a943f285de512d66aad35a554ca8f0e12199abe0ab200c202592fea07a05429a5292b853cf9db2a6a15b43423a2a5ddcf826586b62863b1274cbe33761aa2db4681b6e4bcb9b5ba46cc4e4d4df4533a46107ab8a8aee427313b8cd7e78e4a28d582f22cde0836db081c37e347cfa77969fae208dbb970d5fc66cc32d2dac41863172782137d5db435572ed77585d7e63c8e738bdffc589339d46ef1b045533b1e4d7d9f5de21d293862960848b4dd027e22dc405fcc40b7464f435c9adf88d46fc43bbbb37be5baae92ebc2e2ce78467a1a434b95dde2e11d6750d1a2ddb2459041cfa735a092fed287359eed348875472bf474595ad342591e7aee759d54d117a1061d02290bdce23713b4218186e18e3f6891b6a8de27fcf3c5f2d045a0e175658bb4f6b252fce4ff43afb4a8c83223c88bdc3175ab00ba63132dca51033b37d78e5f70de08dbb6b9ee78c718d74c136b4ba539a70f70e0c08103070e1c38240d0e4fe2ef38644e48e6e030e3c19bd8f0a079c86db3022d4a19c6987e0e981fb3d2d424b3a7c9cb64e8ef04fb230f75573f9a0774e04461d4bff79449996c0a216b72678d3583b3a44d4d269b4a34b15d0a59ce39739bb4f16a10f323701472e93a4a7a21913e7b5e1763a2f15e867bd2c3a0eae676d92f2d65eabee4c95fe79c7fc4bc0c1844e6639e33fd188dbe9321c998687e945ee64b2005a2d95ee64b3ff3a49f0169509d0ea8648e97f5b45433120040100003150000180c088542c17050402698ce7b7714800b62723e74663c950764a1248a711805310c8348c600430030c410a39431aa0e20ebd607bd3235d551718c8aa92791d51b3be54e6dcab6564a94dce821a7fd53f80f076c7b64e10cf5019dd0de5573a176599c504a9dfeb5e62ca62e5f482ce307270933d5a21da101be627c56a7097015b953d3b49e8b140a4b2f20fce815ac2a70b1768bdcc4fc3e2853787c02fc7d0c86095c0e08877db08fe49f514f3aaec8fe9527b0b7fd8039db8c7adc4f075130ba2498ebc974c84c419a375a9fb8dfd9cf810c8dd635acfcba116e4e5737d3dd91b5e0ee93d7f1287e8d0199fee1f4bc3c0dc859b7ea4f7b40a118874aca4affb8b1082405d538f8f8e3118c9c4dc4a8a68564bb1445f0e877fd462829de885fb331b978d4011e56004a6fb6ff83f62814f70f77c5c04b50c5b54b7b2c5022962ab0aab4b2e6436bf7a2c0c250216fe5fa7f6bfb7bec15a934d021c11fe504aff1ca980e2c48208c5f8f88682879ecd26c3c9e28812444950071b1a334f32b9d4af095ed5c48f10131906dfeee4c30263a8ef9c803021367974c2ab3a7c89ac385d0a15182e7f1845ae7b05616251f6c4c1a2c32f2b032bacfaebb303a880e585badb46e0a5e8588211c46e4960a9569266f637fce04de89f95b574408d220c455718753177579f7e7531dd11a32a9f21879d99fb3e883f0c878108375246f11b79282210defef477cd7f68faf62b44f35623175db00766b193962464925bed1b3b671e386fddbf61eb64fcd921c57dfefb3ec213539f080fd8bcf2478841cb2b608035a07c6093b04e3d348330c6a2f6062f70c368621fbf78fc5257b00dc5463dfca2ac217f7708614cc68f671f6fa42cb4fe73057baa550cea9fd025ac4445c2430f623a487584376a99a181bb3b0c0225700a982f82eb30942e048f5c21a33511819add08b0fc284c89de26c4c813a293250888b8cb62f72f79049a85dbbc1136d83a7b26f10ed02d20045702de0228540c7af483db3a66b96b70462d93e94b59d6515444258d55a91b5b68145febf38d648e5388b16bef71fd0087d9f48091ef50cbef7c46cd3b3a275df9d29e52706b03bbf86ef3e88f734918bf5f6e4566bf81ec28fe4e8337f2ccc23b0a6d89052f4fff70f67aaa70d961f3f2e80f4b750160dabff91b840e6fcb0df681f77b37c1c32f8ceaadedde4481f85d3ccf80d54d137ad73935c232d5bef58b9d394d2bc874ec81925b0fdc000b2e1ada860988523eedddc00212c38281f60621662cc65aadaa735ce838b98e5181f5c391b54e3dbc2e562d24b498d428237469aba32eb847636938424a4404bb5b792f6eadfad80caa812710ade98b86019c7383966d8d3e47e2673d28c660aa09176c1acf454e2f38752b98907e3570709f4bb08058eeb56bfcc811f182e8dac7cda147e41330df2971509024ccbcf7f720505757436bca927bf17c5c4c4e89a34b0b052101fc96289fc1919ba1364f29aad3ff318caca9b79bd3137a602136b91d974f5546f728bd28ffbef288ea384ee50368d9e978a32eb651cb45f6504e21454ba75c548c65af592d8e19b1c44535000d52ba2929c344c70701c26410b44c84cb683f9c245cf8a2c58a110e83d2c8f4084d52216f58420b76b915851feab3772352e3aee768a20d199c1ecba30527810f1dc9a6fba7484646b4d553872bc34c39da78550f7d02a4f29b14ec12e52c1c5d147664bd990698cde7300b939ab862c663dee5d280d5b55f7b87912a992e3aa2548394a97a76104af37ab5f79348375d55c6773e3ae4b137b4ab6df723af12231b6f4c12635c4e7116e630be909de6fe7291d1db0c9583ea06275f5909af14200ea3c3d0e50b8b6646967355aeb2c01a491216bb99622d52c6ae1fdfc606043c0aeee245130df87ba135f8a82f3101e77cda6801c39d77325cdd9034ba5d01a5688461700d61631b2047c913539a92b7bcc243997d52c04baa49b70e84f2d85d9bda04879c441e995fef27eada4cfd8ab6dbb18fbb94869e55e621fe0b50134de830b11519c864d028492b785d75c0727373be8a8cc3722cbf4fe11f8a25b69dfdd82c42d9f80a2359ba2725aad1ce8e67805f8e5139efedcd78c3cd3150dcf1f0d9dc020b3a27367002f87569fff25521a7afff2594765716420856e1e4807fc9be1fdb6cb3ba666d1fc6c4240de60dbffe4cf342c6a2e289e0002c45d6abce4e44d01c0e2f621025ba97ec0505e4c9c876056f66254517d32d15f73955d69492ee1b19b893905add9dcc1bdfa72f114d3fe1931f812ef302199099f04dc4ae97b0298f8bb29b94ef8588e29f7dbc424305d1d9ba51e4bd1d3facd03a05d71d02576a463d86f71843bc517e8e4b820ec393ee44c51f5b17f4aa9116ac356180665945f84108fbf7aceeeff3c8ed342041c0995d06418015b83328c8d8b051edaed4d14d9750c02e44bc833ad6f2f307e7545fde814218c97ece6d6d2c6fcbd5a6d29f09db828cbd138128f655db813a3572de2663c6bfaccdcbb506a81899815e8563d2282a4468ec7f7a57d669b527f84bdd08902c60f390c31e671be7202ff5c808bba44f562e011d77bb83799e0c249501ecc54ee11e2897a96351ee994f54da41c51595d081d3f08ec53b962578d3fa355e722a0f233d1f383f9d6f227bc3d29623615fcc95c4d29f0e9aed8fc14dc7e00cc88fe4f63fec7e5d438ef18c77225dc1176f068bc9611a4cc703a1252e79a0b961f80cac8d000a99734c48ade9f4f82ac7b53047ee78da5f4f1a1828b7175dd7f27d7a71866143393c2f594b20ef443d7527378057de297279589a96e7b342e46c74de6a926092a1098cc022321e9f64a902800d66a1d50e19b333ab0df76f80acc828c3ca2a0f641449f959548c08c6aa81d6f4ff4fd28707a3cb8deeeccdb837b957dc9b4a6b73c7eb012ec1073d6220a5c9e829605d79f1e4046d8e58b08cbf2995198657a409202616a824c9d9c7dd900758bbd11e000e615ec3935d26b363b4eb814de83769c9acf8e5759eb75639532055315c73fdd47ccd241a5ccf3a712d350717b52b2a76869621e6f9532955c1e0a3b8ea44cd5a3ccc49b0ed7ce4e36381d92d113653664a86eab7ce2c19d97312dc5e88402f1a64699fde244d076b15512724e9d6e212b903225ba2ab1e06a2b9af1c9f623f4d86fe619ee03c893e3448311f6a601df9ebf3c90de6c663bdeda79e1093df0748162417d416645e20e4782844555e1e222af083478eca10809699b4c62e3226ff1ed8e642efd05af8df5884c34e63471898e2a04de251d2933e74734b9c47a66da294f3c92cb8b38d40367619a891ae8c0c07f1537815af3c0294238f0719f2d1f9eaf40d9e91f1b7122f645b0163826bfe31defc41d55412a3ed99753678560af0903cdf7c573c98caeb8d03d2425bb36b67295a6f359003bc635df091277d086fb123e4cc5da0037af61a95039c8ebc8ab653b3f3f5cb19b02984dc3549590971ffb09cf85a6e6e61144b550375cf74058325fe7492bc161b50932176f9f1aeab5c3c3763ccc2249e86ed3509e1c23ff5d1f1318ddd8e1f951a7acac710e9ae4bc2542833f376560c299a23d686bdc5d46809b1e3d161faeb1dd8170d1497cc4cd790ab63f1c77aa8af94dbc178133760726a7ec12d80ed42aecf0dcba234c878636ada9d910ad00992e98c7de892ef1d9a1a61afedcd4fe1a5ac6813fb86860040e41b809a4a6ac27a1b2375e1b1902a12a9f90396b26ad1c0602f1efb10ca28ef200d5a6cc6a5f1c46abd07a46fa32194ecef2af3ccc4e9c34b6cbd4b6b7caddc52632a40626f9e1eeaa4b6f3566dc60c28d0a51e7ef14d7b842584750a1336835345849845aebb13502bce76e90d255f007375cdcfef003fa4bff59757f89f9381c2d97518dbd440773f53b58d1ae6f08873cac8638a0f35c177cb124dcfa94d28d344dbdbe2d0134bc6da537db839f2220a9110575d734d2c3d2d76f9ee3fd7d13cee580c3164e1ddad4213a8bf746caa350ef31918a7c20a4906076e7221570591d1c5b40ac12d0a34792e61fb6c97c17074317d3b2f67cee3cecb69fa71fe87aca961c96359b00a6e8933cba4c0c42315ac6c857973a3cc79f7720ed68c0b19afcf5012b56b0bac5cfe6d197da2bf26fdfe385412cee4f1439c58da44dda452a757ee88b45aea1347e483864610efc352cd36baa6864f98a857470be1c09d7c8a217ea76aa0d92b351ac0d6c1bb5b22d38177e728543f8d170807b6ad0ebc9a8212f30460179d2fdbea56ba86647a48cf38c18feb5806959c8234611ef6e16b14b03af73659f6ccd02e29818f672d722090cfb944ef65891ca00fe0b2f4adff2ae227471ac727d139895c3622bf89a805a79f2a1ad6c83158ba0ca680d500116c80b32944b658c2c24d1903330e85c2e68a81235a99e83c34f075ddcbdbf262d89ea76dc642442ae62f639006fd86260121efa9628da89a04c9cd77955b259cea8041f5a73097151e82492d425d89362a7ee4a7d520ef2da71283df44faa5bbcd54198f5398f23c33ad461a484734f2910d6fbc1de9e3bc2d496970265770f46232b303abe4950e921789a8108ce67f260643046fee6e7429a9177b8adebc064ecd5cd46c2c3cfb7ad0e24b87da4566980b0ee4e828ba85bc6f7bd0870394a05b12f64d01ebbe3fd8b1e4100d60fb91eab520f829da82506e03d9b25164c910288541581e76c43e017f80163e55f39a6c60a32fbf8053862b5860706c9d6bbb426b34d3fbb9ffa64fe79a5f80da6b84dc707f9d525277e297913170237d5d42de2805b2c65f3a21c4a92b3341811eff7eb0c9f7321a4d5b21e6706c55c7e0407f4f103bcc37a34dc326a2027d6f7b5605765e138365310b00be8781a566aa93e3def246300502b9eb93c5dd9ccd572344c8bc8052d1c00cfa8de02b56e45fce2a10f8f39f12e302fdc93881d6fc766fc342551f737c9ac546ab6dbe9958040854531e165c153b9154d2a7ea827fc0fc33215de9af328069f891173d07173749a30aab5f31e2533a98248f0e0a1b99f5af29edb3eb70bd44186e5f53ea2d78a51fe611dd64e91eb17117439b8360d33f7f5005b8df42ed13097e1aad34adcb02f66c22d199018758cfd447eed3414bbdf68eaa96c0cd5520085a49e525160f98abf81d0edee5299f3dc6ac0a6d492bd9761ff7ba86145179eb869c80004f582d4df9d29ba41bd4d9b7dd3c7dbb098d6c5527faa3ce14621627da5f140b196876b65f6e1c6391866ef62dcdca14f10975bcec823bfa5e9c9c247efd2a22fa5a31b04f569e318b6ce64f7c134eb63fff8eaa4c153e30857c5973e49b21e3c883592c8afaecebd62cb85f065053e16d64c3cf97271bef7a9157038f4c669d7c7d794245f49b8adf82c4da7b21bda4ceeed1189561cf19b3ca6b9a3c60cd84d6560610eec72036120f7adc1b84986bb16a6003a265f9f25813c3af63fe0cc7cb48f29c6168b7e26a0b172a4235593e893879a90a8c567b5676569b414be3d8da9ec1c108228ad50779d0e233704a9e1135a40e563b280906726126b216ec3e8bda48a2b622eb69cbd01db3b742be3b49c05ec6d775a94eb5952488b08539773d44c7985bbc41eeedcef77c9b842a5e6eaa6c8175c8569926cb75b4a03502e82bcdadc387fe8c43d6884f3ead40d218fcaf4fb7bbfc8f5b8db261f327b521d365b6166eb0e2e55d0cdad3681f32a942c2e1bfc0d22e46f19c23783a2bcee008855c94cfa13fe543ccdf21cc0fe10450b20fb3ff079c1214ead10746c73fc1e10b345dd051348e3a2ca5c1507181b7a0c2db5e97d813bd6b6c3a178a6b0a51a9bdcd24b1772366c1f10544bd0da28c15f50bd6d09ce0171b72022cb8bb5af78a3c7e9b1b074135e1bb4e5e2b67fd0f01eb7500d0b9eb4486219e3033d66741319fe0bd4484e54f845a8155c7e8f1c87bda8cfa958c8d39ba4a4de062c3a17f4375c07801b682de69d8286acbc91ac943dd1edefa53466e6050dcbf50a1622de008614707086078b6d7d7927c798892fba63cedf29f27a9801e578433e1da7705295baae73673330d3af02d8bd37f678305bdfecb53747bf545b165165b92b42c5669c3ee3b4301e795c73722aa8f95c2012ec285d32ea34ee1e934fe76bd9a0112b56c36cd8d0a7a08485fa4cc8f6c2dbb495472150b5d154be1882fb25cc32e8adeb96a5c8a39098dab6aa613eb89d839afc9ad739ad6e92e897d5607445362288c2a1af27ef21b87debea04aac61c862ea3a7dfd6867d0669bf4d42b04363bb6313db7548e99f693cd9061e9fa55edbc96115148c57d3331819e2368c0eae571a4c0f82de830f6f60172ee9ffdd8b0b344a1693c5e8da02d755b581e43897598755aba64c48b49eb1984bdca17eaf94ee430236f636ae764811dc3aed210a782b20b3b91f4366d9eb648256c342a205c1e9ffad9e2d1e64cf7dbbfb1e76cf385c2c3fc095919979fb89317ab23d60da4f2468e141a0a1bff7de8a0e1571dcb401ca63a7c7b267c795942b6e8b38c88e37fe10f33c94cc5ac055df7ca5aaaf82f68a80ddc0378c49d12c088847baa8827413a1a245d5ea8d712a4a5258c54a38384441cd230302e3805ad928a9664f4c5bf527426560f2009a6b21ec914daa411e33a86397987a199dd07952e5f283f57726984e0e30e524a38bf4a6b5787835016677a185b673efe12b6c658e6f045409392356b118835450c72bd8729cffd9ac257cbfc5a584f1b44a1565e43bd7df63483da1dd2f2e482834bc38fad800be39ff127048af019812ffb853e5cab853f680d18f5a2833f92df0b4b95217b97c659a2c030b1429acafc793bbb884376c17d22f23409f0f08cf609f0b7bb232aa0466233c16a14fa5aaa8765b8b73188f51bb6a519e87d0cc06822e760c0c21552a95c85e22d8f7ec0bec1f11b93cf2c1e61c6f1a2396761383d8188ef0e8f66a1ac3ab6fb0e4400652e2e56630bc4c0df68df2929c8502dae36492705075f3181611a071dc9b58b37cf1806f0bd0ce7892f7da028c0c8c274b6f969a63bd654e7daa59bd5a1c21dad54262a013941b311ef0823eee6f1fce7f2e2e24a2dda5d7058a7c5ebc6c735c0c6354806329774411617227f683267bbf96741853cf6d4e5112520b30becd88c74c5e1f9420191a7f5f1d99f28f07e58803f0ad2a816fc9c4e4c155bdb74dcc6a93de49d47e7273d83b994720ac55f11cdc1e211118f9645d259dfd9e0ede232492d233ce49710da6d392708e8105a1a53065658a92ab8a21e4468638b5861932054aa35130307e05579eb392b8907e1b9b7c8122598067e61fd96e04964672be3c3bea0dc3e25a8233f757b8b1af88562362fd103b47d77e47824a05469ecf7057b1a68e6ccbc16d1a9563cd419988e4b0a8b4a1e6fe61e82cf6120b13966159b1017e61e19d2f81be5bc9bddfd12fa10078e0412a676356c57252fa0bc4583c458aec0e199a1ccd452cc7d294dea9dcb0c8d50cad4aeea71b7e0757856df4206b2fd80a956e73cb5e45679fad8be5541b16298f9723f16718e8b27473395cf253add944e5401ee3c02af10abf3615399e8674672117b3559e20805e95535ae1ee1ca6b9b45894035352e4f92fd9637afd907b868c4e48fa9ea87c2357cfd1dce2256f348605b41409a4bb2a0c0c744d8e04b18b4fbbc9a973c11d7ebc9c3478b4101459cc5f88f728cd4f4468bb189f5b41a4935248a9b54d96ff7b88c2a63ce119f6e54b6ccfcfc52ea121b5565df062c30a44dab26be53e2bbb89c4cbf67e6341e013b5ac8c268d626a2895bb87af4a45db5d143daf45019e7bb9bab3915ec79af5d48261bc6b2f07154048e51da648108c464b2973c031dd1efa4b17126a11959f65348ae60ffa57aaf9885520cc53ec5cd45bd24a4fcd9559cc7124ebddbae4c4a47ca895569bab687f2ce08e963f76d0a2bb8a290e681a9941b5d95da0546d50a220ac5c58330497fba3e055c92ac5e9ea47ba6fe2588620184a60c64586565f2656df23990cb2aa6905e416d6f03264f53630606c96f843d1be4bc16c70caa95e01f17bd609bd7c1c7134072ae9c9bb98c2f480afdf8704d4287a5578eb83fc54a75e4c9bd02072127df62f7a4abda593dab59a68201c9c62e7ca55c71583c6eac5f387a6798ef9ef4ffe20ed0fdbe9db2969e1238aa73c6572e5a041286db9b76a0840c06e0c9daecf7121ec0a7133564fc03978751ae4395fb536ad7a48a8dcad775c8931b7b514fe6d37b5877b04a2ad9b3bda5c65194b4f550abd733c0f03e7dacb3957702c3f135470ee7bf55398747d31f55ae875b8bcf00c885b23d92f090cc17d7bd65afe77e8a41a6832a824e41233cab1d1119165a00fc5494556d5ed03b80fe9ad0ffbef2ea0b830a430f9f8664c60c995401ae684e18f9851c7444566bc5b88e5b34dd4e581aff5cf93f4a11bcc9fa43ba0a4bbd111bb9624a582373b23cefb1a0507b779a4088afc2a630fbb9361161303c74a75af79b541ac8ec0ea6b88ff14aede1277ec8fdb44b26380b209b42e200da83d7da344ddda3f7388561df297138a0f6714c6f5e13d858f6313bfa7f9ce9ab111eefb31e6a776668f45eca2dfcaaec43df9aa9f003036a6fbf8aa54fa5d6b52d13d75d01d9bb8ea144c29cbacb304392177ec9231a0fddd5c66ea173decd092c6525a486f5ba6a219b7bf79f497d3deaca34c3d20d6c83e050dd829c01a66469f469822efd349d7fcbc4f920bb1683083dd8519d02da3135bd56134f49f07b9ea5f0bd04dbd065955fe9bbb329b971a4008089c523ee7bc5e7c7bbba9ee3c159d90156655ed1f69c8fe3f06430dfab5bac2216e2a9b091be77e89ffad8b7e1274c2eafeb8d78a4e05c75806a5df8918912af742ac66856092a41d398234506afedbfd92cbbd282ee1acc85ae53226c68a8498c894c479e4ec9d010b80124257636cf34caf56a16b5af5bceb3b7c6e189637c24f709847cb5dde39eb26287e590d0cb4a19f6ed4490502654a6179d1f24bf6f30d1c7b1a67d149cddaede626d1876a93b2d43988944615626eb4934181844bde9ea671970fd9f16df6d9d2ec7c4b0ec1e27c6acb830824f2b43bb8aaa416ce43142dce440eae2fe176a2aaf5e49ad2fd948a686471879614ddf4eef62e841d3bd030517d9db15532f0c4bd7257f88a81c18da23c17781d528a8cbbe1a40472195235fe950c8a1a3b65aa1b1ec8229565bacf9504b3ef32c69cfec62bed0712b9085919754c8d65535552a1a002c5eb8f180efcbb5051d855312e40f2eed3cdd68176629bd39aeb823b034f07d08004e8c482316f0be7dea02c5134dfc6779831026a0d324820a360c6b89bb4fd9bc8e2c70d4fe4bc9176a2e9f70508b91a6cbfd018697608c403334e3b8a05bd3cb0bdca30de368c07e79d9501804d9f996e3ecf9c78291980ab3808553c798da3ad71e0697eb0c9d6cbeaf3aa33f7c539ed989fd4a8e02e7229141849ee3015cfaf765961b16ca7ac7d73735dbd171bea3f94a601e375f5c1fd681436a2e76b065eba1fb22d655e484dd145d73337ca35f0fc2540bae22bad92d0dce064b1f9b268c72883819254d16c6ee533af5561d7b133e878d05a6d4ff9427d8d2033a65ab1472da760cb5e2fbf761a56470ca9e491aa955716cc59376947e1d3e177a3b422d1081c66fbfe0a09a2600e33f4d43af7b1e9fdf2174e2a681b374d2b94fbc7731999f06ca9a055bbabf71f5085279ae7e273dd343e3c2fc3979b19f9dbdd6ba5d5b1dc002b97007a7f63255a44afc920787053643bed61c86fc21c3d7ea9a215c23e9407001766204723f17a614137e6ac4c49efac158a9b6937a8b3b8349c96814c7cd3a423faa141127a4959493d9c4ac0afdbf36728d25546256f9ad12a9c86cf57f4cfb5419a699a84677e2d289102eb0eacc75272b47cbf61ff02f7aae149ac02eee6e486b90b2c913f7df049744f36ee9633495168325b0e38d2b14b69205d98dd70016bce1436cc1aacd2fd3a245c508718246d4df4d63223fed6b5c204554442d84282d50e7d3cf5d75bb55a09c73c03581c95b3e036faf30d1116a8693fcda75c77db6f49102e09acf88eb764da48fa67ecf4b3fa2c0aa5bb42da05375f7c3724eb718c330c8373743ccea1a5e27490d90f8b0c98203984e9055cb449c7398d3a4fcd95049413b4812762517e0e7f7a248e9bb62be08a45d4839d98b6429e8e05ed80db08bf80f4cf178b3cd01ec5f385aef04b3cfd8f3a651aa97551a5c68b5f22646cda147cb05491924084490d65aa62a8d40f35356a510258223431035b84639098d08ab7a32d1a64f3d3f52092c72a6bef56f3d77ef9f974a6fe2bbcb9074f7eb85f48a400d2f5f4990c440ac84dbc9d2014ff760de64e7c537d1db240e99dd1e8850eafd7147a3d0228379b92154b4626faa607c7aa83b57d89f2bf39a1b5379a49525b3e3f88f2afe5dd5e52e2fa340302ed00329d58d807262587da641b9d586dae10f1dadb6da2f45c5b29b2377c0f74f3482b1de578deace421fafdc45aea21b0fde70aaa371cb9206406d78316699c549048848a47136d36ef17bd47ba3cd2b7470b1c231d4183d61bb8f5a1fd203e38fa84a152265616809425a54b335495063a809e33284068535af81dc9ceb19afae83359442079cf5bbbcb74ac6680516451b0ed8f891a8dc1724fa5b7f950915592278385d4e5cb828f92920ba0097e7938034a2b3caee57c16e6d6bfcbc1a87209e03967e440fa185ee85fdde4a083354f164c427edd2274279f80e150f9b370401a960478c8381ff13bf157f10bc94f62815ca70c7c0ffd59e39ac7bb7ca572464396e186338ce88e8907f2792320585fd68afd45a8d8fea29aed3b9c81c1ffdecd6339ebdd2e159d4d727f3130fb68ec8bee94c70ecfe53813e60f591a9ae2ac2fee5aff1cb84824ce10778d903cc3de37725f36afcf9eccfba08701334310159ae0442ed416dfd51be8613bec3e8fcfe2912be7bffee29a0942418612d7f50675c2d24f30a14ae9c0eacd62a3911994ef8dd32cbfedd04de9e26b2b733025a4dd937fa2989ac36878bf5b4a72c150998393392390b1502e1a29a8ec8f5ff0c6366805bad9e3c0d97c80064eb2d5b955dee05a956605e0173d094fc591515398c146d42ad0f29f2647ba7873247cb4ba50316339c02a4a30325962e447ad2a512cd0473a367a79de61f4ec0a152c4b50b429a6f4f2aed888b04010330bf2511011fa451a25bd6c731cd2841d801175a5e8de3caa24f50cc43ddc862f83d33fcce8d4008ee055d2c3357562e4e1cf6ab38506d7232c66a293a1f4025f8e9a615856548824c69436bba9d79c14859f96f7d2c2d26b7aeef8efb4db4c55f2fd89ea498fe0aa9c10a61a1282ba54c10ccb46c144a714aeecd69e1f9ebec041e4e18fccce4bf02b4089fc67864fc18ee108231cb855aa524683d04e7c73b069427cf258fe7acd5196c32d2a6f66dd55151c3bd80b0549c0fdd462710b7abc45d141cc910782c10c855f590136ecacf1530fd635a70ae6943376f461a4fc2c786346d8a96f7a4ed1fc49515fb8ad65be388bc81f75d1bc07dfaec0c041d0def06bbce1a22d1f1df40b6680f0dc9c0e064c69b78b8ea2445362b4caabfa4ab12bbca983b8d83ecae9f5b76d5df3b21685b75df3efad88fd29d094daf9e63d237819353e0b2054e86bc1be658df7ab5099f2bbd607e7071e9c328f09ba43c8ff942b352ec013fb82961a465fc43025629e6f0154ea8025a8f9281b5e561dfa9b9873e517cb1153ac49e820eeed498036f71f35380e80162230085e427aecce36614951d6d8d56267acad80d6965d9f82c9932137e88d5cf7f6f67b0e197246172f91f4909a43f136e28fd49d942961ca30009c1a20e8abd753bdad12908454c4bde0efef65b12dc4e368b856e742c4b2979ea021f12d1d2e4cfe44d8822352f9367113ffe25fd6601e8b06b4985bae07bb69ce2c1b49eba02106f26408f1cc4a4164df582fd48a555d5245cf2a7fe5724577b6806bed037dfd6ed2750f06aed9d784e5a62c5390862f8847dd4eaf728f1bddaaf549dc8309b392c4eef8331d0e814642e73d22fc35c117cef534077d2b9477447f11e6ea6f8960f47196d07246f5e478623e3945d48e7853f688570fb016d4bb954094dd0982720c455b174a66303d41afce39ca28d5aba0e3e96d256e9f28baed12d9d16a47cdd9eb8787eeb95cd4c22d7b4fe9a6d3331d645304fc8038034b53585d2216617366d8275fd9aa7279012f45beb92812624430779cda7b7a0f333fa915045c2acf254de1f4906b17932716956ee6c032e47b61125edac4aff728789f439e58c08a2639645382799615d3ce2a66e5cd2a0d157e60d7d5260b6d992a69b3ff3d416f3fcc1a07199013431e092374dac69eaffea68c714137c1f802ae1dfcd2dd8a461b25b4fd409c2c49bad85f15792e5a012822dfe3e97ac41717f19ec810ea44d13195ed3fa393a9598483108a3a9fd1d59d16829ce669aac768ecfbb3e2097a4bb6fc869c5f02045d2b84f746a44cbd6a9180692e5575d0608ae6155e8736fad000a0dedaae147b8322d4ffe60e9e3f101daa7eb53b27fb03c0bd6571e53d06456797821e7e9cf3ee0f74e11d7ea0403fbc5c2a81a24f274f20be08143f356079a5234ec5f3e574785a1f0a1b20bd498e3546dfa2a30fc114cab7f92d1b68182c06f4cb05b7135e1e4d22e65d02c0b7f4413947f9330d5ae711edc7103213599e3fd86b8d9564fe63de4d0e5aa33b83a58806ce247c45ebdc43482435221f4b19e6eb94ef6a75e01a0ead12368b609a79c5da8c5bcd36988c5d461b8c93532888ba705e257d80c72aa8a7346c5a4a3a70eeae2f5144183d35dd6cf1b98560da315c26da50b40b1733aa005df964563af47af1a339fba68b08c2a79c6b3fe72e24ae3701111216b9109bd69602092b26509eb4e11671ee128b2c8d7a110f452303f6f8bed62ed2fbaeeb4702765ad25303f8223ace36fda70f87ec45719ee6fb14ebf6bf9546e4302a044500b24322999f2a1ef94141b1baa50aae07a02d66a4f3eb3bb5d63d771c205ffb6516e46e7380db0eb4ae4936101d538add84d5e71cf47dd097a9b7389cff9fa7302dc8b9637c8948a0c27e02f9dc08e8c3279c2dd5c6772af2e564c3c6359aea30cc4b4f870920d9e8cd0ec82544fef86eef5eda043aa1454c1d95bf5523af4c83c3540a44cde031cba846a7f039a7a568e546dd4a3b765a5eeacbfc2c8825ab437033c0c7224114db24a101180806442094a0a972aaba04b01f5220d154f5e0072222f2f0475fe228b2d6122c516443af8634ba505c9b87882efc79ca4644d7180fa08b78f6d2ea5d1dffd507f3074cefbe7c2b9f1209d436db68ed711a1c228ec4c47865adb8e91d12c85569518bc95db2a93fa548d49ea8aeada5be1ef5db2bf26ee41a9ce020a506c14d4ac54270217389c8150924efa1a621b278712074897e2fbfd427f9e24f9740640dc4591e490117fe0812a38c9c212ab3295d17cb0a22d2b1940c3915049225090e62beb7f0653a6b4c254bc1bdbdbc9e3bcc2c67395f444c72f1134ff75e7820ec5de3383a84822067a9b17428ae30dc2964854b2208e842c68f0bb5f35b88c2420bcd72f5b126fed5e54fb31445c6b4ea2854ca49864fb887cb932ca296a7b828be4a4918093709272e44166027eee670dfa2e24b9dd197f5da311b7ae1e0e44fb0548a19fa98504f53a3040a7526bc2211cc6c99ca4f176105d5e938efac5a561bda53e6132e2fea8bf854d858c54c43c1bfb3c89b3233e123b33a80982f3b1a5d028f868b122675d2ad163c180afdf34a5ace7c870c8c3071aee4271914792fc1798a6b53d4242da40e82e22170a326abe8ea05a4d55085466d052d2f35d0ffc8dc1af14a998ecb8a015dda554c9cfad2a4c821d2a6b888821a7011e9491e56af4e7e7167b1a2df1e016f46439386aae0cc36192b3dbf2ca953c07c99e89b7546f77ffd128f0247775f28f69667a86438e85e438780bfb08512a08c417165641fd2a06602b850518325d00425e5c6216ee448e0c9786d258424a9979ef6119046aa2ff3d2deffe899f616b1112485a5784f595932c4dd4989a327d55f712b2f98dc4ea2da8e3298946baa8356873a22d57e282003fbbfa556a4d96e4c2c46814e1a58833aed0939acffdc9017bf8434e3b1d01055de9845be3c13417fa9e4619c4c96e6b8d1a262756c1a54dd9a43d5e7a46a2064e144e192354939bf50607deae599356c6af7154b619ce06e525c57b7a9f2d21f9d018e300b5b5fba2eb31bfbb04a32114a83a27fe58219ddabd79046903006166090124dc13c7ec4e1e2a69e70f81002b1e03462bbd73f79d231199ebdf3d9dedf3c236494043fa87023c6506f6e42f5a714f7768c5baf6ef2937513871554ea05f19106bc34b0bf4b03c21f3737fa36dc88c1a66df506252fcd4dd61e4d4f182e5e76bd20fa3bfb2ef8e75c206905a8ad874f4b6e4bf40e9fbb41b785572e308193404e20b764f72699032fd9d06930d4fc49d2b6510bbefee9cf056ef290c835bde607910d8c216e11386f67d26314487c22660487355233c6c42e0213c5c45ce6e8679be87a7ea4e6ee0cc343b1603de47ee0b7c24a11e63129bf82d5fc8c30afbc41341002b687cbf854e45135698723626f6a6d8b6c36159e07a90051fca4d8aa3bf7fc4fd79df284c23cc478893b57a89e74aec937b00bad88d9b10525db93edd330152392e1e1fdb1aa83841b9c212b3754e87b38e8b4b8bbdd93200f854011f4e8ce8a2e2acc44009ad4172df784ea0c6cc298f24ad52df0230ee46cf984581cc8b1b365e90709f193b2e5797b0ee67676f3e09c8cc4ce163c5e4a8b0984215236b490d0440e0c140cc72fb652555f7a360ec882f8f0b7687daae36b1fb2f6fc4911e1bee4af5fb291660b640af442342053a1148bc7eba71bd6f0709b7f6db17392f5a0fe6df1f15470b21f761f13394b6484f9ce0fa2b948cd7da4e3b0605a8ab60b388bee517f2899d513d596dfad290a7c20d49cd43149ab14c70ab7fae7b8096d2934919b9a23a073ecb61a074e51332edc3cdb6371c3a0effa9463380ba486e113ccfe40a52fee338b123ce4f4a906bfd041704ff987306da8021479e2ececa9e2a132182f5b269d1cd4103ef1c40375583d2967a5918cf7036fa61cc04035da83327210d6bfdce687e3c020e8842c81287ba0666943404f73955f09fba46032fece186a2b8bea3e09ad5e3bb37ae59f940dd66bf4de5ef7f48aa98b8ec48ea62407ad87be29d45df0af873888fac2821bb47a2cd6d58bf4909a3a3974959af21fe1691a0ec011db276a979e7a0d224358788e559d5be6496596ad2df7efff83ff00b13c973e1b10e150cce6c1075fce00687a66b2923a012e8a550a7bc155b6820466a415dbff6fa964134406045b170ba4651bab35635c1db4777c05ca49b67224446a7046a43190c2347e3d7122544b68299e1caf638d509749d1686614ae6c80b37f8032aef12f6ee584fb8c25bdb3d6da6fec0e86b38c0b4450e57f6e6f9fe7baadd658ea168b78b3c14ad897bd9a2d561a02125f4a6f8b99d9352f4fd39ef6a8ba4e79695cb557e74f9de05c2a02a40489e18c0770ab38e56539be8a3f58cd0eb3e75bf71547661ab7c31d8ab4890d0efa0db58552a183ad3393f375f294134f735cd6f02d4a294a9f9eb8a4dd9ae2e368d689a69aadea891a1061f19370d0e4e34f4c59587e5db33767b46708f9e6359b4f4375f4bfa6830b49754c4833630d98a5d93d2b76f515176584bce76ad3a02bdbfff06e1813d881d7bab54c9ff04783841d480527fca1bb9336e407f4e6c7629406226dc426ada32f2071a6de80e7aa7fd45f926d24512dd930c1f83297324cacbcba139738cc9fb7ad030eabbf1c658298e3bfe3b83c3e1e30a94c3086fb4ecc83f954f0690102670e268489f7b8bb1acf0c04cda7ba025d0bbbcff294f72fbe9ea72b4ec6cc8ca3eed92a9f1eb438de1462758e046d60e79abb3038eac89b919bd20aa3c600d430f03335f8add1fb9ec0fa6a348fde3197c7464a17e8956eb3c647085af686c950d91e3852cda94c30d532a0a1d607e8e2df5e393bfec5203f457d0ed3faf7ac80b150ade4b0d9a071dbbe6e5b4008902112f0ad4f5660562f7cf259af996a984812825f89017d44373ee7e2bc92a614e102b170f5bbf23344b28f7fb1c4b53de845466d74852dca9ca0eb434935682c788916c8d84cf5197fa148b50fecc360089ec9c5b3d799eb0fdf459ad723b4b09b26102986797850fd6e5c5ff134f86a8da02be7024841c1d3e90ad3f9cf57db77375e2660e4888c554bcc287359202b7c092cbd0b7756d0aef29ab35ac0733106b3d9833bbe9d609a177a21e0e919acc2d954277a0b5d610868720a4787dc08808aa389da7818cf3337c629eab05059cf2798c557230bcdb1aee62d3d7787533e4bd30d2816adf984aa5a9ed9ec3676f5231c5ab31cce14a74fbf40fb28e1855cea16096d489c2276bab8af3e41e6589f354d88b1fff617fb4abd2e890516662a56d0e99539be48a3926d3e131ced9e8a5e69ab9b520a0a643e6c89e4bb5c7ea8157f2636637b996d7b128328c880d5964906d8076f1372c86faf3736e67884cc67dfa42ab0cd65ab343229744fe807b3d8ccae5d7b5fee044b4b2acbe613c17dfbf7edc7c2ae6200cb275d2d8786a91cbe3d27e1c9a3704a474bde95d8adcfd8bd22a59c21cc453fea6a7456af6c2cfc7f28574da7b99f81d9a0e259f4d65a147ecdf7e891c0fe282a2581bf4ca909c9740e6704f8921c9f19b4e236384eb7d5ea26e44d70738956c58c11c6042b9b108d25188978b12dcc816fd0d3ec3459e2d846721f226da00085c2508fcd0ebdd38c01a3befc08c261511c0179d47ef70fdf60cf169cde401ad3d6b30ac7d4feddd46aa54d0912683e417e29a9eeab31604264c9708aedfe53964609454e57080eaaf5646f8c0ce31c1815747ea2bf752d2ac1c7353f351d80d1d843dad213eded5a0114163c08ea0fe95826dd69811b02462dab1d37d9b134d8e61a8b4fcb679cb2a65f634459238c71f5b86b401f32ce4ab4f81a372328984cb48b677c380657d3d3a92515d8a2af0b3bb98bb57e8ad9af79fab0055cd98965767ce1d639bb624f89b4c9bc0b62517248df93ff9a782dc31a40aa133618693386aeb84461e5dc2d2361eebdf764ffbf9ce0dfd9bacb81cffc7fed089f96ef323d3a718ae876926052eb9e9cda42cef5451eae41d216a1f1d91bc6391a76928986f711cc3280b68afe1f4392bdd8a1a0db7b33ae3622346e6530739fb2499cb24daad5e4d871ef148df5215706f8709e489b1c1759e100dd2a0c275959e7509b024b0716d6fe5f33fb5d4ea687945f837feee7d7e688c2ab35c10bff7dd9d34ed1e14fad98694c8daf1456213c48ff9f16f5de12d0883478c783159f82128a839279f3c0809b98e12be76a54cb0c96c0d5189adccabd075c14c8d045d43a454fcaf60707703c8d4b7ebe5f84e8ac1029df4a2aa966bcf7112b2253d1316db8322450b352ba3f78e164bf16b94f9fdb598a0b01d5eff52d05d54df53c90bf6c720de73c50455a03d62d65326c62832dfb6e6a1434be9e32aca355b605245837d0a8e5f63781e7b3f75debd8cc5905a90d4f4b59f8a7439bc071b5d5aceaf9bc625797d76aec43fe67fabc95a5e7080d5d58d998317f68ff5800c14b766d3376c2a22520ee727a8ad8143dba789399fc494d1dcaca6f1af047092231ee5095dc6b1d528677cccf0fac6fddcd7e7b09505ca129608b01feb98125bdd7d31136283a76ada0bc6f06bb5f1b8ad1971610b41cc625d0f636138435f399a1f49d75378dfe0ca7b29101443476b872c48181fbc918c632470ef9531781a932a0a28770dd6f4140b3bbe6beef3f35558a6128976d16ad2bc474ec508e26d6976ecc59c1fbf3f45f456e2a1bb7701c8342397c34a9b9da4bfb740eb0bf318b9e57f6a9b5a5ecc059306adf4640de7fc94c237b77bd67a02d47904fe45ded690f99531154a68cb2f13b180e0d134f99ffd2d5a182c16938a4ba0f78f67c937ec722087b52ced58a37c0b803f42a9a9d0f8a922336166ab61096a2f73fdba32d369dd764f6ae798f76bfae663bb06a52ce0cb83c3137e87c1a5b3ea70ed5a4ef804daffe90283ee3622217b965cb0895cb6f8b0d38fedb8004f84a04140f59c3967aa563003f05f7a983f8c860b27a8781e5f19658ec125c6087937bf25e72ef32549a6843828b94f68c7068a084ab2fa8ddcf7792ed25a97ae64f71a1b999f66a8b81b7e6c4e8579e1d9f7a72c066800977a6059a210c684d1e3a1e368e8e83ccf8dc434c70637758c46288c9bed244e09e62531a50b227d7f2637049dbd6b26296d5c88ed5ed86007723c25c11e4b206bf9bbb1978d1dd5807d9acbb698611f66478ff28312f03246e270ec40898a26ef9ddb828c9de127f374a50044880c1b6960eca6c2de6c416b339e329ec63f022c0b5d629e8ba71acf77e7b716cacb6d691c97407934555ed8bc21b4be8f5cb90c9678837a7fff06a458380f1069a877d9aaa800d287c879199c3507274ed694e34aaf803b1d65b22bf43166dc37fa7e021c56b66399f675cd4442eb04af3d551dab581cddb768cec944f0087f94c996b06c2a8d32815389dbf532ccd50a5206a3cce97eb86c8ce8ed2104c4654ab1db3b3b2b8c688e1129594b169d195f0279e38540fe92dd203d5e919268045ebd5301940cdf8a0bb3e3dd9fbc7d45628ef6dfa7b1fb370513ca588cd10f2483e66f33a2f3fa25eae63e8e97b70bce0db2efaa5ded6857841e7965b4fc221dd8ecd2d6b3fe0625ba0cb8ff45119fc8bc7997ebbae51be2fbd61de4d2deaacc4ed868e5d29943afe2cae6ead5aabb3211efcd5261e7336b6f50e5c8ee09f6a5fd312c108429c151da96ebb4d4bcc8f7125e8565709666372c85b26e59a085c87558357a1c80344faa06c4b081631416dc64e1f219ce7dc588fb653c1ae4bb20da2ace4826cd120990058903ae0bd6ca84de534ab96eb2cbab2498fc11bc1cda4d31968a325c9c56e444ba20e171be37d5374b300d17e4b09f9cda8aff3651e43451d9b69e44aaaba50d47f21c225437040fc76988c4b69c3cf051b44678aa5d3300ee2c8084a3b0c47a6fbfdac8ed808f7d7494c55c241d3fbf945e79cdec1c1313b1a69e4c088dafe9540dfcfda9184ec8eedbc892e3b89b2401e3d54008d6887239a9626f886c95f3f8436769e1329ecac033b24e1a1936f28c37f3e7dc538c19268b761e60df6439c6d7a6eebffc0572d992e46e1febb82126149c15416ca1a11904366109102f293e2e65e7f0579de10f9940f0d8a3014e2d5713ad12270d5ee6b9317c6373e561d27eae04deea4bf3654f82dd3725f6764acf42bb7e0ebc30eec7c9007377f970f22d113b14cd58ea92f452603cafaff8e4c69a319137d6fa331ff8b238f9065a10ea35da0ea4bf3037c8372dec0252964dd6029bdc339ceb5805f3d08dd529cd68e5641c203187188f73e14585b9864de54718c3d5a7a3d7bf11e9c7714e463a444bec9d3c37879acbf953fa74162201b4cf128dadbb23e35907cc30b77217af6f2cccf1c5bc61573328cc314a3583dae9d994c23d7e06345572cb86bbacc0e1896f662a108dc19f7eaae4605603df340e01db59418d91a52a9a882b4aa6ba84d50d15cc46363ddd1ec1968818289dd03314b517c65a56efcb906858c2c565176d5a266d09403fde40d7ba8dbc221f0dc8890ca247dd53705e8d6973f580ab4abcbe5407fa5f891a99d05a9fd4480653e9beab2ff5c581f1c76d26115dc7c52699bede9a84f0e6afb897175313ede3c4753a6bff6a21fcd44c7eba37ee9235a7722bad4ef86790fb53a4950386deb399d9bb3b1376a0d94fd40bc2df0c8f8abc446f78bcf2f85655cdd64fa7d4d195572a61db5fbad944c4ecc48b57014e167afd4dd9703d2d0c152d5714e818fbb97e69400d3bb1853515575cf6bb88ea954a903125f41e27b393cd531bb21e76e4cad82744935ee46990c328ea9173e816d5034e32414eca8231cc2cfea3ebdbb01562c982d52265cfdd764dde54884a42817a58ce683f0cacc1410c2523121ca28f20df29477b33aa00556af5d4ebaa4db8a98edf82aac26f7d45fe78f641c25c49c8eae831e22d5cdeee0e8c852351c92dac8453072863a9ae280b005a1020e9b9d547d1077d0d69683868ed8af520499f291f1c9174b7b6ecc69e9ef594b24825e499684b247fad9e1b7a3a7d221bc399da37825c95c41956f7784030ee13db9e1ae02c8b752151504de7906234c74bc184c913e700ba922bbf3d28d8ee234d2455ac1eaa270d14001368e558229916c0e0eea8e41f6adeb81c7af267d63736507f090521dd2565f68542aa86d0f3d84f045a178f83e4a52f11cbbdca8376a43e48ccca8f4a154decf1c425fcb9ce5bb1e16afe09c5871bfe3ce72099e86495143f8abe4e7b333cc191f13cb17675aac42eaa0a9f06b49f056f5f15c3d419b3d57f68b81b53132a9cf4475bcc145e3a403910f1e5d27ee3aa34567c2e86cd3a3fe60fd6a6cdf74bf7b58ac0ca6ea34b53a801fb11a400e3d4539ba7c7ae808e3dbce0a180fa644336e79d262690b404fc537f170eb2742d4291aa9d7cf8d549fa7da8cb0dc9b922570da1f7e3fc6763688810ebb203d675b9cd0cb570d5abc930c4f5299ce294732ef213820666e327349432d8084feeb9cf37541dfe09728b9d641a2de0def843ea87b5be8be64ebb99f75db72b1126f38d452f85898e0e4f79dfa58897891064ad2d4811401482998295c4da114bb95b1b08baa72cca35888e6950c16d8140d13da9c5da8d1158b1005dfd043b6513855371a13a2aeb02bc6ebe50e0ccc2797a3e51c5d227ab135c78753dcfcec24ebfd8a6a0b0f8ab104e3c1f107523b064a2e566704a741874738d5bb2dd292354e208ef20792f71bda3ec05bd6c64de40255aaa89e3644eb85bd2e1b30f035ed1042a3085d25ec2fad5f256e11167a31385b4a70ea1203cc4b5562b8eeafb4cb87dbb0d13574aad2eee5dc8965c29559b38ce53cae58949054502d2384084fdea675e56f73ec6209a993715603866062f5dec4903ceb38c5127633d9aee5d4e6caa0f1e8c7de72583316428fae38592618f2727199a36aaea3c2f3b0139316cb86c64af7ac226600ff63d71b8767f811d2bc86ea498a389a3a41422a0e75550e12c47dff341c3d23431a5c56a188cf3cbb9110411bf4442a04e0619f0cec11d6410b6d13e1b33163422b80e10a651e772688da8af68576f73a9e0ad3e14e537b1e1f0f5dfd84f8c03d9a75aa8932107fefee5a6f8e422a1790627b81b2fb3c03d3e9849c793359e408e09bdd0360fa3f55812f801b0d35fe839de120e0b76576818f5514b4aad745865369e49b3c8d2d212a211ada4ff96f98bc74475d4f408912d412c5906341e4a0111fd7bafa648b3f097ef7dda6d7151deaa0136cd335de7e49183cd283aa330eeb09cd01757ffd28781290c5f92d9132fa73bf42d7ae09ba32b30431a5d00afd85775b4228102c90d5d71d08509e370b37eb879bde7dee30d1863a1df493339c3f41f11a6d0a775afda29bdab2683b39a1c4c4b4fc3cbbbfac7aaf9ed601fd7c408a0d9f018b9e9e5c7b2b6f61e9b0bcf91d5aca4e0df3ac6f869a46a5537743b050c7eecf43c13d6342ebcf2fd69070ddbd0a94a5abb7ae9794850bd7b35ff822c3d9d15a146d66c27b5c996c36b4ab3363f67c43c9850813be3a3c4337fbb7e51c2259830eb14bf758c66bcf81ac2df8ae6dc86165845f6176f782e8c9aef91e1eecb01235f025442210318bbadc05a2b47b8146e012f7753fdcd9f20920f6e86a740c6d2b6bb960107b4301970db1756bee7c36dbc9f90f01d29a88ebcb33f520afd390a0503d2d3c3c92808ff9cef03d3fdeeae84a08a2b94f33564470b3a5e334635692b621ef170b3a1c105656e6fdb128ba70977c699b38e09cda2b7a348737bcb2fdcf733b083da653be2c34802650c647f909638a45654517d7b20ac2e8e914214d438f100828bd34017975721157d9ebffa545e18d474c5b52a33ec758c4d2661a46e99174064522cb242f65682ea9162c4c933cb8faab73ae869ccb2c92bf6882a1698a04245ba59a449fff117831bae4ea280fd39c458ac8f3452dc288ccaecd4a5c04fdf375c4ac0e828460838c7ce416e08741660bdb20773a481170b138e2e3eb1c8c02117cdedc5b96b64d80f77631ab1b5962e5f02cfcf9a4fd72066079a4a0cc6419bf115b1ca3a5a6f674da7ead0eba9a49e22d5ba537bd52090e47e529e2d66318b120d9ab158f3735839be1c58b5eda40a078b8545617fe254172cbbeedb117b5e757738e0e62f2a022e8fa3b97010ea1272782371b9f86fe4791736bb642b55e9d4ddb96fbd16c23a37532acf2af85c6302bec0d72ef8c2433067b6bbeb7bc83112fb4914c194f119780074e568f7048366fab700addb8b72d9364998cd7c735103a540ae543387a791653c81f598b287e302ebe204bf4aaf4dd6d76bd485ab822ac5e46abe2ea8006640284ae648e939fe8aac161fb360524fe827093644de162808d9fd14f72fd522f0ada81f694a798b4c57242de1e4df4c85036815bd78c0f58882faf4041837614faaf270f20971bcca4d652024b6a15586218803d18e15391d921113087e452eb079642214df6992922db3729dbdd5234255e9be0e11a99ea04f66dfb25159a12895ed1549c70d48cc8aa9ea4290ff7dd552049c67b81b0f28ac6df1a375cdfd411c6e834a146cf6279c80af7920cd22e5c3c1bfe55500294b2fe71f275c5732d37fe5b95b2faaccd1b4519b0785338886631bd45c28978175daf953cb8bc6008013f536f330c66524392afabb6438b6cbb1d2ee6bfc84e87a50882c483bec8d0546720f10bf8d0a030a2e9bd53a851b167582b1f2e3e5248f13975300dfa2873402dd56fece6e82746b78bafcc364145c871953510f36bf4a2f250ccf96da2f297dad300637a2687cb929a6bb00c6d7fdee7e9d93725babb9752c38ecc69de9d02722f131314ade9b7ca86b838e4feafcdb052440b61e5a524d636b37511a38b0213d783289835ecc4e1f86d6524e5c893ec0904cc7f59915b2e45670cb29c11f675fd0983f894ecfbee05df59943259f160f2036dc5d10ae4225b896181b110af612bc2463fc2b1c77d9763c56cda92fae19990ff8c6168a8f6d4cb03413a4a286c6518ea34c44e672385f845c3689843e229ee2141e4e62fc69cc084c55fba55a7434e0c01cc163aab7ed0ced3ee1b9882a75fa61faa6b8400b65bea8104300775344c08874b919405598aad29e7a63f8db532402a99e1cbf73f58009303fbcf6c4dc4094be7d8eaa2e45a7385343fcd37d4a16d09605cf4c733730ad1e17be26120149b8780ac058d9ffd452a91737d033029cd17237fd42985edabc89097857e9c1a22daf8b53a7c639c280912e0651f766cb0bfe424026b78fd9631431eb5b2bf142356e7f9af199d512c7372fccb793d7abf747eafb287d2b73c45f8fa5919d5be9f0e8f7437a9f5e7c24a443da67b49c180c3a1bfcd772e15c300281d33dddb252e0ca61ea6362fbdde01158dbcd41c7d2a1f07f0f7a4d1ac42bd83af7c30d16cef0679a847019934a7899a2c3e44081150dfa66cb7829772a51d22e1f0e2895f2b7811d4f6d97a83d60814f7467c09cf20cfe18a5c5ce83626b571c0d501a1145fc1f0c4d587755f424976423df5881f7a840112c1e17e70aca484b4cd3b8140af7b48bf9c088299340b0edf2c5dd2d2d2f891c636c12807b56c5a1868b3869b46684c1f61232549357c471496d09bd809549146fae886287f61039c973862bdaac4b0d3292c585e2a0a267acf757220ec4f069bcc95088a070a74812398b476f99ce514d42fb377391055e2f5f9562513a645e81ea234965cb1549bef3b1c006d815649e0759c8d17268ec20e4760a54c0281259f05a834308425a77726ed5e94bd877ad517121269a0ebddf51b4e4481600f6c4edce636b22dcc1ca201520b5192c26897269b2d35ca837856a93da56f40585fcbe5d147bdc1730ca10b7aea24b7aa42791eefdcd81f4b61c58281d21590ad9347a60836623b784cb13f82838142cee91e630b487912ea717fa84c9012467dc5ac7b9389f7ef467e9c9f5c4d18f60298c3b9a5017523989c3dbed73cb0b74402cd92e98cea67556f52cf4403dedb412a45acaa1159b33a52f38b646b2364112769110eabf2705056ab6d24d2d6eb41584ce73569c83971335b65554178ab4e5f2d2ce1e91901126314312debcec1bc826f7bff39caa18e65af03227217cf69ce01e5941e64db04212712d18fc7cbb8eec7c98905271042d1a50618b1b2cdc44cc581a40c6c2b77a0f6cfbef19a1fe81a75a2ee2a890123240acbe06f527505a3f7003602fd6d77014d8759b2eea6edaeb451772075e0bb7b3704915216a68423fc35b208ba8cade1e54f579bb33182ce357e6cae01dd2ad886794fc8d9ac6321361d62e320468ed70dbc502c3934b4ba06cf7ee8c1227e690ea69922cb32c2d71aec1a13f91c1b6c237307c84dbb3d98ee108c8565a225114ca87e5dd101d7d090991a0eba9fcdc107a9e4a9d89a01d8c8d2c43dab804d02e21f74abc90345a729bf98278b0d2e347eb712129af33907d9fdfa44cdf4063c9c58c96b12e99c37aba1b6fdb016e45062eb40739b8e1f12194e2f3317813481e6ab3bd8eb4d230ecdb22a9ab3a53bdcebeda612c05bebb53d6702879d93ded5cc6fba1b59a0c755cc830d969b8c9abb821ab6f4349e6911deb577670f8a8b063b589746092bddceebc79e94bccc548ad8b8cb4c76b08f1074b1c5ae1f97c9a06be85be71251460ef758cba438c0d01db0467e505e9adfaf7f9d7e18d7123fc96c001011689a8f2c0389c15f573134db0ecc36509e832afc99578148019b872c1568420c77c301846431abac7ca217e009356d79a31383476bd43c53b20e9f9a2cc0640782988470e64073699871401e65233d50c703d7469a7fb0c220cdcc2586ec6a6107b7d127fef1b8bf6a65e4cf225cca96330d712d13950964840bbb5687cf4a2bec9027e04c929bc8e01a19b8e53f4e0c43fc6a761193b42e780467bbc2fa9ca0365a696ec2db3bc41697c722b817075a2a073ca567b503c33d728d2e9a557549b31a2069f98e3027e332573e0a8d0a38aa6d0d0f1d6b3d5435ccdaba2f88cccc5866fcad3396fa85895270aeade9d7c8842d603e1660102ef1c6cfb9690d01b6604c96285ec2ddae5896b0cf10fb9426fc13c8842cbd7c73adb130df7b60294e4af7395b08539bca9b92995043b3905582af7e44d9858757950f1941c1bda5dce6eed838f6c65ee6a16280a95380fcbb726e3eb6141112247b7fec17e45d1b5bceeeb9e843222fede24a209b9aeeba2590beb884220538c06ee61a263ce277a024f2a27f68053f4980ff49ef93e76cc3aaa75ca35983a780a3f5346ac772b606f071d20a4aeb9456e9f1570058a0b430acd1b3796d71ebd6422da3221e15bdf508e2fc20069fcb120ae2511dd44161c5f917961106e76a2e4a48613d80c6c0c45862838388c7c95d224a88a863fc0bfecbe768c98bfa45fabc814ad80a79a92f6de4b51c99c6ca47710f24c05b10bc841b4eee2193a0df2fefcb54559b6cb9e0d44a6c5c7e9e3e9bb82935a1e2a09be458ad04c1fa83473fbbb66ed9a6c832de9cea211b6a0281b45d1ac0d89b67a02624ac83e17f1cc2baef319a36fbe6f82e3147c2ba4678fc503d2c25570ce43cc72d87851f436f33e212f199dafce14f473ffabecd10e549a587d8667cf472644dc421b540c0198268744b88abb06acea4e2815152f407557c79bfc3675584c3c15e70727d069d5191abba359af0438bdca519cee58f9cafeb83497fb2568ea58f1137d0637f68acae3e79a4ccac94924f76834e8c260e54b5836705f328e298c0aebef05c99dff94dfe8d38a318c709365e05a324f5bb7eab9e3efb41787e52c2c536095f32c3592737570ae4538c41f88a4d1a6398e54b6a090f7d88723299d2e5716a54db126b42a97bc6da366dc75d90a5c88097394c01b95c3e013cad048a70c3b05b30d2a29a0e4a3aafa070053e978671bcec4694b50d395beae8fa1cf56dd4990cdf3a2c24b84081e259e5c92cd1f63a5b61a208100c83e8f5999f9a2be1b6bcf2f15a1cac82aac5dff7668165a01a2b624837b2db9adc524a99a40cd90aae0a0e0ba947bdf7305f65ed5969e552aaefbe9c424bc951f955ca21223af9fd2ec55b91b40e7998dec764f2bc0f870eb14a8a4a8aca0a8b8d254c6c7aa231a74f578babc5dbe5367d89ee3dd91dcbd321cbef273fbecb0d971beee297c794d99e7ed91f0fb43a964807d7a60c8737d7799de7811ecba328708858e3bd256289388b0d5f51f114ec28698d7828cfd33befb3463a246289bc69624164459459202024dfaeb23a58c9ea746ca6f8743e73783a36411c3abcc14b293b5d0a11b993722425a8f39c2224738c7cbbd449214a014a198a9f6dac59f59f92620d8bcb0d67b95a5acebde77d5527e6988e83a7facc9d9feec34f9fbe52017ef9c1e1a2004fee02f25fbe2c7f5833bac46eb8ecb8dc68b9787cd68c4a412e976769a4c55b2e108c1de2a58ff5ddf013cb0a5652ca293bb14393cb7c4c6fa6a4245171a292d4a1dbb48f29933fadf2c40393727854967454a0ecacf47ca358983f41acd4e14e87ed799d5b1eab83e30867aba3633b5367f293cabbee744d9ee77376d3519e2d915bb799f633a156e85426533fea2ac557fbbd8ed58832abd3af769d1dbe3d013e3847a5efc1d91259a28e998ed492142df1bc35addb9cb4109ffccd42513265bbf46d13049c2d914dd232aca4b4e47ee7320646b9c933567aac447309037b3e2751c7e209cc79bcd461bb47fb7693ceb7a3527652b0528afaacf1dcf4cdf7fa4d9e0bd157b7691c620db5ee7dd964f2cf334b8a184e221d4e1c306e1d8729fb40ac341d54b2d6b1d2bbd2e3f860fca2c01873786ed3263fb9cdf438afa8152cf803f58264410b58f0dcfd0a461e224b34e46a0040a12ebdfbd1b3f7113712ad37274a9d4f8d8706a7a5a3531a349d269efa09c8b3a5552855a92e75cc76772335714105e24cb63692ed496dcaeaad22d120c6aa0eba5a3d9938ab837a43aa4a9e57e4c32fbba65e7f2b2fbbeaf5d76af9b51ab45e77bb6c10487f0d42cc41bdbb9dc9ebcf7bd99dbcfe545e769dd7dfeae5774249b0f3bcfe4e2f3b94273feabd1453a90a25e6a08e7ad9de21a52da99221e55eca55a99453ea26d870bdcd17f5d477eb90f660f9fdfa57aca96608c0fa906b9e12e1a9e713bede62505ebd9d804e3777a94a393c3f46806c50bd591ddb637d2c506d09d4b1ec3141401ed3b1c64caa9529741e39d3c97ab516c4b2e34c276b2b779b520f4f26ea1700724fdec9fb5631078b2ca1bda797dba15aea9582243c95340dcb7597568fde716e3f12c2e740bc62b938eeb2ac779d1058d7c32b97c778d34d6eafdb56f50ceba4b436e9828cf2953ee92a659ee9ed87faac4ecb57cf058d18a57bacb6564b931fbf7d3ad63fd2635e7d94d99c7e51cfde2a529f3687463b8179753f9a85d90177763ea9b70ae5ab4afdea01674bd38935d56927f4f568be80c0883b4f6d9d0f1dcfd3cec7f3698aa77e1a8a35ed94baa5756c67ca5ad5518e33931e51ee813d529ea7409c99b4491d7b42a58c38f0a2460eb511295dca97920598bf4146f1a47a6b599cd5a5a7965693ba821163758c930433c5010e80de04669a0fddfb2eea1b83baa5d524e9d4724dfe16bdfc56df99acf8ee6484d0cb6fe5bbce935f4b7a091ffb1be61ab49f1e991481e4239322cef8ce83810f0c76505e75f282235fc11b6e3e032c0f247586ca072f3fef3bcce453bccaa4a7d6b2be7ace3b150f052fbfd3772b9eb4de456f1553a976263d50bcfc506f755015f46c4e8749a0dc00d4003506786a004b5bb5c41afb019708660b82a74e5bbea5e5ed1029f687a72d4f693107f5ef088c3ba4a8cfab9656ab9f863a5aad5e3f8fabdee238eb3ab23a3d16c812b1462ccdfad8204a2dd153e76c1dea18a5d48a2193d44fba8757b757b4a87d7b2a45c5a3af3aa60a512cbc48782cbe512c842f83e85bfa993e88ba54441d1e29522de9b01e4155a19390cf49a8fa4c59dda93bd5a7f3ac1ae26c4fc77275e9dc4ef5fe5c77beabd79d8e4df9a61bf37c36a59d0d10b8f314b72b36210f1cfd4c21c59a14c79e1a4a01576c9de72a3463f02a96219fe30eea50ace9cac34b1e6238f13724f4edb20ad529aad037d29b9c76e0e853ee82c69c472aefe4877da6a478c7771102ceaaa18e495751a98c101de9581255916a49c724a8226a954f754465e44bf95449544528d5100d778e7295c953df8f3af49ea3bed6c9e37bf64fa6bb62b93a540da986ba257a4d55b450afb6eb3833ea35c9a5739cc9afdf586ba2f48806ea3ea8f3a03e43f8913a1733042cd63020e6a04edd04ea61147dd182a73978ead9004fbf23b0cc0a700e5f565aacb1f1d4eb51ac894fad447ae9d25bb536eb4629ad4fb7d879ea91d2a35a0fadd55440b500b241a9ce53af0da34e7da663568ca7617cf6621002547dd015599f145927095f3f9395b238318ef2cd9ad3fec41c2288397a091b857de2dbb3cb0fd6a104adcf4b542a8a35479608cbd3615b9f23d40dbf7341035beba3fa30120e3c4474332a7545f808095bcf5d510f58c75a0838c360a816605ec5f202675863a4eaf3e5f927306319442638e902f27357945955461ed6e411d6c4265b12bfcf0f91a06fafd6c7fa589fefa2a2149a6906247c742a533059f96a8f2916d7df8f15083c5dae684270bd81eaa8e85b75b44a00133c3dd7a25b51ac599994620d8bea68be3a76328a61c74e451d76f55621d19391eac84f456006a5eda9fd766b8476d1c5981a59df56ca6ef8b439c1284b6052c6ce472640e0f9027c64424693cf928784efe867faa194c69843b2f0fae94d847317e59b665abf3432050b465982f58c59087f823664008a0682d0c435503ec021502e2e4438bea56e72ebf9c7046042c0d4fb7f9c6a4f1d023470f1ed51666bd12289321e7daa59a3ef04f8e0dcdd5e39ddede790c927e8a3c30efcd161bce990490d885c024a1b21e0e9d9d66252ac59c51a966ff7b1e25ef22861f952e72fe7f30354ab79b435905842b29484c774440dc90f12a24e1a2d4122062f28c1d04c0713183d44b3222d05e00091d16f4779b4ecc433c37ce9373d4839d4a6c5672f55c4185f0491cf118a6ca48ec92cf3d2656ea26e2293de841e4c830f1e33c8eeb6d1d0b23a7e2d81adc3fa255d4a09837d6d9b2b34d2007e80a58c33d912ff8c22c55977a7f0987551cef828a10a0c9bd1d131f983970e4377cb70c6105668b102152831213b61c81746d0e0a1490f473776ace5316e42cf110dd27d48e731038d89b9d203a66dad9c1cc782d13ada298acd66b3c56c5346ad4b152970aed4549dc41aae08ad2463819e6b0f72fdc1d313aad361f3f9e968a61c84f1e2ae876f73dc1d82b3f3521a6b11cca63ed57aa25f159a7306fd00f5e907e3956b0401cce69cf109d00f93aa0408547c9644c6f8510284a094943b3f35982c31c03bf2a7431d9ce50ef501abb1485815ed88aff67b31b6110467b9e3f31d5b790257cf247cbbe5388ebb3e3f384a9cd169f211fec69858628d990e750b20bf9452da4d3dd337bf15ee10154b68575d6f0d4c135df5812e6c00d960628437a974f4e05c6db7da620de7240d0c25de27d27305e3dbab17310509ead0a1c38644b5504fb713948e99bc9f7c52c7b84fbedb4ed53665b556abd96ab65aabb55aabb593ad87785d8f8fcd6603c814d42d431973d898c336c7dd304c43e8cee963ca6e775212f53b512bc80ea0c344fdeaf0919414c618c650ae0485aff00c137cc4b85c93e326c755221f506a4a42a95bad9d8a33834b43e77e80e7fae0c3dd648c4c7e7574faf6b852bac59b924c21f572ca68543e3f06cea9db8d8686c5a29ead592223d4778d52094d393b35c4e41125839c996e9926d3b04eefe4b30b8953d2b971b71ba5b439a536799b4c263095bacd396b85194a0921e4b9e79ef7018ef2c0ce7f788f4281b94fa7d3e974728b3aa94c28e7509ee23a581a18e59ce7d50250600d9cb3ea1723d3e18e8f470fd081b0e7d9236a0157d5aa1e5bd35d9debfac98154571af8fabdf282524806a9e4af3a6672e92c170acc27b78e02f3c94d2e512c9cbce34c40ea731e7f4a2129dd65410954001e240a6704a1054c00b1032a8066b22646104f4c7044e4036acca4571a0fa5d348f77008b747d4b90cc1249081735cf252ca1e40e84f67e2a5c75a8ac0b565c396057fc4b7417e8c4b2fa5b72881b34b107611c2adeaf25d4680bd6574263df4aeccb9e99076820de292a43b5d8c716102b7a6cb5fc9e82cae8a605e8732fc61e58958f30316800b3c2a5796c0b99ffc93d87d9357745d6c8e75432d6769647528047b1dae7c045d10a1c1120d96ac6ee044064d64a05464bbeefa0de738b3ce2425cf743bdd9abc47e726976e026f8a9cc01b13d89227bfe93a3739ce4c7a9d4b9fd347c3d9306573f29853fecca09f92abb5e996675249a9e469198b2da8fe7479e428c94f8f530afd9444b5a29f4ea3e431bdc79c3b60b043261faad71eab8b7c5a3aab6536805e051b85e98835d9d48621c68d14888c8e7a8ce9a49437c004e12b89e2b4f58309c217944af3153d9c2fe972a96531de9cde79c9eae99f9754f6bcf46e201e6c6c48e6ababd0b1a82409edeb92aee598af49743ec3901c7dd681bfc836ee5805c257fad15ba01f25184f29318420a943d80fb85667cd70cabc1944273b55094db0741a1b10ef6dcf73cea9246f20d3f8e9d27f649024e214a434b765cf204738b74c519070517780b98f4a90d46c54d801036661efa31224463e8747b196050b7e08c30749ca98e286880f33a8e248075fec24e13da162c9906992c4104b98008c309c08019116216041953be4f01b86848a1d284172826fbfdd352548964022240d7a4513eacd273fdd156be277372bc678a334416cfd80e9929e07d22f7ba82fbd9652d6a674d68f764879f8d59c93fb8cf3d187599b7e656573deaa633dbbfbfa9c1c67e76571d65eea93ae565efcecbd9c35be355f0ae2bc4703e9cde913eceb9efca427636c59eff76a8b036f68a15da05fc11bb20e3fddbe7c9bc61d84ce75c41c52a6f8e0b06530fdd20ea78f00059e9ebd5ca9b55e1b08cbaa76ce39adcb0e25a53d813081971e3f182470fce17a69abad3f5c2f5d9ad1b9e43c82b7434c690bcd571cfae898a3b70e6d4926a48f3eaddf28bb6ec1cc7195e3bc82b5f98a7ebf883bc68193bb9cc33edf8f5a3c077b7a068e9e579646a3d1a0cce6e461e950a5e851d63ef3159d7ab4699d2eba949c4b2b4d2e4fd28f7ca6b50e5d46e02c6b3fa3e9569fb6466c03ce9336693f387a9e343ab1e822a55e673a8c968215d661750ec4b5ead03d47b0f32c4de35187f32cb1632d60a62d2d3c3a64b180f9c70d971bd2da8fc20c81ab5327a1086759c653bfc1c2625b5afce62526bd75f716b0078cbff80b78d3d26225ce9d3277e9d23bff70662fdfcbe75f44add04213b2ee0d25087e20ece7bbf6fc8bb397d802667cc3596eb41783e2a42e4117afac2fcba1fca3fa912518347172c5128a6281f3956561b9e12c2c6e33652c0e63c3c55b2d073dcedcb3bf74b5c016035efc7319dc4130071877ffc01c8af48071f71c70f88bc7d90bcc06f87d36f365dd3fd87c5987f960f3c5e22f9fcd34cfc272d9e22c2d2c2c5f75d697f15b1bd6e2fc44b1bc637d15b5028b7fcb8bcb0d67913e2abee2feb5acea06d8b2200bb2860458e53430fe3975697b71ea92baa4ee381cf40c2b02bf148f287a3bb4200eebd65f3e0df4dff068d3281650dee22c5f8bdff8f2cddf68f9327d16972cf076c8d2b5907216ab05cc3842dfe2d6fa6571e944be931e8bb758dc1d67f6e22e37401e39381cc65b2c608b012feedee3c51dbc2972c36f70802d16c799b9dc001dbc81015b2c208f1c1f29345fd45f1c67f602b280354e60d03f8f71bf29d2c31d87df14e9f1e2ee37457a8ce02f1ee70b06bc29d203c663c09b191c077853a4070e87016f7c80fe02deec982fea2380493e9e6391e798e4710603b21c84cd17cbe3ec05f4f962798e4a0c88b31cf09338cff296ef47447ac9627dd5593e93df387917512c60be7916d84b7ff1ee45eacc17c5fe63601c0ee31fceec8a23dfb587e3c399c17c3833ffe44ce28001e37cbd7c7136adc959bece575f966f035cfdca97a593a7aef26579047ff9beea4b7de075d497bf7cf31d088255de5afa4608bcf77a6b7762a13a975364d6e84aa572aaf26ef5f97ce51f342f3da216703b44b9c43dd8555454babbdf44c34befef935256b06337e1942f7baf026d7ae5b90af4d487571d6801993f813554e7bc5e535f6f99cf3d668316907909d670fd8231a1d721f51715587af5ead9955961c7ae530ad20e61b8ed52173980a3122b6edf450fe0a8e4086d4aafa78c5e0fec2a0caa1c3b066f30ca4b812d06ace4e08132e4a002a6c4190573b43dcecbd3a922c905705126e726ca5ae1f00c5cc1fc23223d0563f37054d3278240512b620c23762006921a0b8488a090628c2044927cb0417c760c9d9a24694815cb5062051353ca4725562079eea3122b8ec498574cf1e9311d4b016193d216645e767e0259f759a1b7773bebbbf1b17c36beae3f5687d46146707bc6f45b39ce2c656515fec953c07c7dbe4ebed211e9309c8e0202ceb14806cd39a3f4f1b13d75980c4be995929eae6ce0305fb52d640af229751bdfea8b71e58bb1e82f0e53c606159f0e43cb6c388baf348b8d6fc77cadc0d9a8dcb5cfd451ed1295f24ea6a4a4a4a4b84bea285739c6790aa4be0aac5bc81250b00e512850a6c31dd3947fc0e2bd5f8e4b56ff24ff9091999147b84f5af44cf4c053679a51a27cc7b227bf5fa743478752a660bd7a94329bf9fa017ef52f70f53c43b3820559334a94990ab4a1c6098c72cf559ee245522957798f94abc09b22359592c27196721c25ca2cce543278ae027dbeaedb7494286f3365edf182d34fdf0fd8d3eb204c103d20790ab3d65ab799d77fc0de9a6aa8ef9e3ce538b3ee3a0a6c9dc0937be04d911378e3f9cd7594e3cc6ca689fa9df4bd057447f8bdd54375ddf5529ddfebb09087b37080be73d529eb70fbce55dc8d1cba26b0e5c2f56e8795d6e460eade7d19766d66077bceef674da7fbc1886886bebb3a7f5df575b7f3ccfadb5dbf9d5f577d9df4fbfdc904847e5fec44bf778a6fed9b3c4720e31c799b71927819c4e4363d5b2e608f0b3ca344f9bc9ace72750cc7f465f04dfe030472ddf465a9f3f7ad75f2368bb72613f51a6f98547ef747547bfd808c93d21863a4534a4a9974d25afbc5a65ec3c0d461c079ea281728e84d193b25ab6c1b1839324a628424a9ecce6e856225c1322a3e5809911e3ec77c4b29654c8e897987b5561a5aa6b2f90032697a7e2a2d154d1a6966502c2aa9edfca48931464943236d38bf2e43bb047390de7ec11c8af490de397026d86c314a601edc0c53d68aa0758ecbc15e8fb3f899be70bee6b44de73e9bf99a289a0ea7bb9c6d991881912d8ef454c943a3d186cca4db948eeb7285e901abf88adb9830aa2fd7c3712b475c0071aa5896b92ac0304fdfc10459b98acbb0721550061b2e69f3c52347c5573ca25a0c507116efa1e22c2ebf1c722822411a549c058cf375af09ccd7e4281083f3a640f91d98f1d753d2143a20928216d8f85a66ab2fce246a458527d6d868da292dd36d994016fa4d2d4bb9f9f811652932c706cf9baebcdfbeeafe887215602ee5ab5f754a6faaf66a43df9ec360de173ecdca601c06f47fbde752c0c0803c260a15ac8f1e92e7753e915a269b36259a53f4d4e3ce533a979e52da534a799ebaf7c520e4e78bc18726b658cc0ae1e9bdf70ad10ba81cc87d15ef8074ce9deebdf7769e5fceb3a1431c688ecb08dc49419eec3c4f305a4021cf6508ee514ff5d631937b2ea174ccbae752492e75ac730fcc55a84506034e21d90bd8492da25e72d5725c8a9eb680473d1348082ab88af07ce8339e4d4ef79ba19364803de73c1baeeb9c3ca53db83a4d6cd7790bf4bbeb9d5fcfa977ded7b25133709e4815fc1a3cb0c579e79e9fc01607be209168b4e79c02381ae940f9eb9d0467134ae5d0199509dc7975ef400dc8cfa7ebf5e321b94e5df7bace73ae7a9e9fbcebbaaeeb3cce4f9e73d7797438c30268a0e1ebf1eb0f1f8d7a68f2f49172b475f2a9910f3f4fa7f79ee7790bf4bd4eea58eb85ce3df7c01aae77e00c1d52a72e98fcbac96fe702dee490d40324662e37375a60940417b31b188f28195afed27d5d44f568f1229ddfd60b26effc012d7fe9fcf479eefa8a74ce7d8d62e17ad749940b2617ae5f9728173cbfde59d40c32b4b8cb7bb4fcc523ea012dee026f5c5c873e22891fcc5c6ed31a9857becb7773038b1344b1cd60401d547a20c6cce52fdf8de7c5ec46070ac5cc05163179903a2b62bde56b6d81a99b3e1c3aa4ce83074f651329bea84f1d44598bd309460bd849f3824927209473bcd2e1afeca4be9df4f42710096be00944f3e48733719d73ef3d367127ce4fa7dad42f28511ef6ebdd07d6c0f975aeebc0ec79fe21f327e764f7755dc511face6dfa640199af60eef11d5883e779eef1553a9865debb1763164be8c20081f3443add7b6ff49ccbf4f344ca15fc21f3d7397002c94e80b314ea72bc75d7e5b506ce13a86329a73e835ae6e2b163f4652d38c7c55b52a7947b2bf92b4f29d279cb17c467455cac16bfacaee5b258ce9970be39ee5ef73aaff703527f82730893dbcc667db1c31b5e4d36dd62c32578dd66def8327d16b06dac3ce52e5f4ecb0ab480ccaf8035a43cc555be0b48e7fc54bd937b9e075a40e62f58c3c92f386dd349ca1773027c3de5294a533865f2940ab79623709e48b349a5913c53c60304ff497ee79ebb2cc19de78994c3894487b8e06f488b9b3e2924691dcb710163dfe897c267805842cc413df5d9744869a66c36e997ac05012da014ea17f53c9f3c75126ef807751a26d0b119e4a3337941dde9c45170da93df7befbd5647cb728a9c3c88cf8adc1308cb323dbe73981d1c3b8c1dde6f8252e8fb21f326500ee500f3e8d1086871ea3340405605f69cf389d4b15c63f074024da12e70cb37937a3ae9907a4369f1ebf422a0059c4dfa756ba589d42195b4db24620375202a7f28094a387bd46792938ee51f348f349b746c4787b68e5d50053a919e529a89481a0ac1d23b1ccff33c10ccd7399726fb6d397b64a30de003893fbaadd6d276b52c0040ae6387170317ca054b62f4123a6590185d8cc934d65b6fa5392693775de7b17a2e23701775b87c1dd42fcee56739eab64a9a8d0af7729ecb75e1bc3b9d6ebdf5ba4d535f5529e5aa5beee22d3758408f20487324389528cd05b8813af68269e8af73de412d9b368f071687711e6ef80bcbdd7968711c1e7970f1cf7968b9cb6ddae6298e111c67e6eea0f77007bd3a88c347006f46701c7e03ba3e07bd87cb47f0cf417ff95ad5631c6706f3b52ad862008cbf78f597178f016f5ad5f17c7137ad0a5ea0478c03c01b10673977be38071d00e0cd0d001c00609c2fce637066308e33f3381b610430ce4010e6fb70e4971d88fdfbe1c0b83e9c59445dced621e73041e00972be023ba8438ef3950fd5403044601e4aa3391d3b798a7776e53a5df9fc32f8179c6e3357a0ca57befc037cea534505cfd5caa2565899b3da58d958f95cb9cd5c7d9eaf7c32afe22a608adbcc94cfe4f8537da9af7bdcd41db8f35c873994d621e77408b879a68cd2fac571d26509a6ceb9fcfa5e8ea643e5ad3ba77552ae23707c5973faa97ea7438efbba04cee1739c7cd221572fa551de94963ae4501ffdbad29479fda2ceb94ca2ce717ea5b73e59fbe27cb548677d71be6ec4f9aa511e8ca36a98d8f506297b5a0bdee830b30ce0661664f9c8c3e7ab8f563d40797dcbb02da41f8d820031a9439f65be55464176f09926465b8c75298d65d8e4fc7e4cd007904859328c83db205301ce3288170d67162ba4e12648dd06e1e900a4a8c227670925487082d904f20117459624497a810aa6df3827d0bdb54f0b49f07b80dbe767e26b2a0dd18e084da529ebbc9daabc33a5519e0bd0cf4d448dfc6d4e97608641f5797cc517f55c46e017268c07eac31eab566ee8bb87aa12587ae686bcd6d9edf2766d361c1943a0c962e218d143133288a01c1931c2250a2fd41041101143a4600b5b0bbc2dc8f8c286859204044584706504d199a66e4293c59dd1c6c51c91623ccae1f936ca39a26d321f8d7670f2f8a3d10e4c4e48c418639c9f0a88a6a3e8624b5a777cf5fe32cd3715c0d3d753991c19f6349fa7d34f664ae9f4894365379192b375d2eaddb04c1853065e75d878842666123aa2d319bff8735a1db1a676281db0199a8e4dc7f42508336101a9cfe3eb3aeaa33cbcee641a62f2f90d617957e095734dad388221a1e2080ec91430484d284e78d105120b7ec862073857404146115ca421c60f0a2c1a2968d064714d9e3d230741ac21c50c867e08426896c3ef3098a0608b275bc8008bda2cc3525002ef68071beb63582e67b9fc8ca218c4c00659202d1d8133451557b4a00a1aeca084892e38272a4a021c2b5a4002237888b400028d9803244c20460dcac841171f9022050130a3730c4d11809ee5218a882eac8d745a6a4bb2965e8ed28e72d5a957b0063acfc0713a994e2f7732791df8c1626867dec2f0d4bb90c2789c3e1c5fd64d9fa5818bb2a6c4a475175d17e3ed58a6f68bd3ed9c94eaf00dce213d95064433c22089153915091485a2bb78a28b28beddf359d3647177c0e0003282e8e0054d82708312cc322ec210f6f6383b22e0e2a70647d4d01941f75149117ae09ab83e2a591ae306934ed2faa86449682ef9ac3e2a59ca8952088e4ad480825d3e2a51030731560009e9ac9689d66be708ed31363bb84f850ee5910fd366470b2a803b7080ef47256a143d974590182e402c7688e182aad031f9ed4ad4b8a259cefaa8440d24be7e54a246cf67d810643e59fda22bb0564234705efd8a83df2bb1267678fde4b565d775de42fcce71fe661aec69fae9c3f93987689b373fd0c926702bfae9bd6f45301a0d01848f46434001422aba011314ca38ba01cd064d1050a7cbea3c3aac0e4b034f9735481fa2e333138f1d2d43e01d33d0e8e8b07ef261e041c3043ad696da7458dd4e6be91d1aa3c7d239e79c6ed3611938a6baab63acbfad7b7dec00526badb5c6a5cb755b90857609c2c22f308d8e5a1d8535b0053390969ebde7e1a6441a9a6930a12195451c1cc174ec50428439eb8d084284aa2333a4f81c6b6940f91c97bcfc53a9923fcbf81cd34294527e0330f2d3e104ea704eda7c4db7e9962103e7f0e76c3a2c8c350178f93dc0942ef958b323e6901e3387a680a9a48e0e27cd844da129243bcedb8412639c13a8c3391304eb700255a1ca537d826093086c0acd29f4d32bcc66078cc68bdb4f289634f13322a163466fd84c944921e20b96bd0e36fdde0c06d147253d203d013e2a01c3873fd5ae7e35e9667d9c15939e34a5599faa549f5428a99a948b96fca44af549bf66d25caa499446693589b37149dc118734974c9fecf9e9b0c3e971926765099c6b524df2e9d7f4599bacd993474e6f5510ae8e7b5aa60a7da8c3698dfcb4c99e7ecd68ab493c1dcee93cd487d2a80e0d733e913c2630df3b39b02681b70e674a0c3f0c4dafd33deea6e2a28b31ae2c3fe5285ff954be942f461a1e0566ce81d44f79ea93284e86850cb46740c328b0f0e8db65666831eac30638df7bef2da3eb1cafa4e74170f67a3c2f3e7f38778ee4bc3d7bbd63c50fe792a7773aecde894ce0ecac1896eb26050b36c35a812b26cec88aa201a689208c089c59b22a7d8521d5d5af66c160713543e7172b108a018c144243580c0d19112262a466029ce950fb0011e908e1949f9a1115d46e4e88906e3c984ce087116699719329c03419bdac33b014c2354a816793a443082cc1b504f8032788418307273f78d7c1c232e1bd3cdf2ea58c5f7c0cc84781089cab9252c7a257ef9b93b9259f29cba94a0860e9ec54a5ba6473ac4bd40aab0e33ab2ef5ab9598c0b977a8ce4c5a1ad569409c55a5dc3ba6bc81f88a77f60ecfeaf258185c14f8d0e2550367576d892a88c4099b2a174081b317c4c8112f42ed04459c07f159115a2d06ef8d36f37af29b325c342b3a3ae10520c039d68608d2b14d800a24b963028f0c22610832fff0de358f626e8a0886e80d5c3e4d199946c70e2a7ebe1d062654d25813c1160ba7975508e7583491fa863bb8bd291891073de21449df4ebd98b05d32ea50c107dc43b08ed6118600e799191a5b0f4c31ae298c7cbb87924746596b489d2613765c77099c5d352764aecc50d1b7c368661a8576f0079c2f0a9d23beface64628e367dfb094e603f41099cef1f0581d2cb92c2c9b7bb622e653965d14b592e168bb2288ba2006796ecc6970c7d862583635e3706527c670a4483a29114404d443e81330592350f4b66864787881013c59295cc142708c1f9fa60bd8893389d9bdc178f628cfac4a83a5b15bc21877a82162166d19e6449f483c8d2b7dba0647b1652bfa20267b984a846d4592e398a4e56b23370f63c6c23c24be2612772e4db63642cf6dcf33cc6555ae0ec55e0ec1e23d333adc389e45cca2a82b337f3d325c1988a83cc5bbf710bdc4e82109cbd34702865b49ee74d5f0a62021f1b7ed4925427408002cdcc10387b302238c312009b2981916fc72e5c0185126cc707305b1138944c749e71549ab488c4809882fc8925b4c7964b7c7b1e002ac4f7b27e82a211143a42df493f917c963f9289280be38bba07663984464af14d53f08dc50038798398cff30c311ffd2378c3cd4f2965fc9aba7c3abfaead0e8464e88d36d84c9d78b2e89d537ae52ad04fcf61e8670e4664edf9ca594b3d2c02675a80251cd64ed3ee616d92000fb38634f976574c0d7b2cf7564ac062b1d27019020a2d2f6859633504e8db5949c8d0fb44135939ea7845595ae08ca98f004528e38401e725e8910067fc981a3d2134e373b5c0656419c44b9a5d5996872d0dcc9394dbc1f9c690e78b95134491a3dde4a75d2265a7bac90e9b300bfc1252b3699af6eea2cf0620383af522d7237d6b28414b2c670b3bc42bea784531ad74d222e04cbf1e9135947eb57bde6ae572c5c4c8c8cccca024d8b71b9e353a0b5252eb2cc89f3d478ae2b7ea7009dc9e2967bb5f9490afb70ad2f97696cf89427b01b4c0f9c29800e79594a00e749080c9f4e9e191cd070db66f9fc0132c057084a5872c1a6030c9ea155626f0e049a027a2784810180110be74061a78c099c20ce119a6cc756b2166c966a542134eb0276792c0d98399024f1a73543a832682ac4f223fbdc6395f681c2292862d880267fa8e032023dc9cb45a9f93ba9521120c530467fa3e91c8143351f4ed2b97fd300b09ec853c18b284ad56c677c76a4b1049b284b33799991829ab65cdcab2699a59ebb06807b708e16c8b2612f1d5dec41114738aef8cbfe9d349f345002f70bef86f32a0de97906342eff6ed98156b30fc52d2d60baab70113e14ac00c8d2bacc90b002a70d846ac2819af5822a07dbb2b064700fc803d8cf1259d7a2fc1d5e71b9a102a8456e9a7e8db63649a26bd355b131c6225bef3355ff3058022a0ff4ca2cba99eec69147e80c0d9ab4138378fd4699f9e1e1e267e787a7a7e7a7c8048003484aed24829250aed0420024f100a3cc20f9e09a70cf30c0db67dfbca05055ef5abbd5d982584f3cc0ccd6caa4484a2845011ea417c763dc6b4941cc7711cc7494981dc340aedaa17e04c5b9ec099d282e87282f8f46914801a8576500767dc42023c654a5dc189a78f0d9a40d3e767067d7b370023b89b76eba48cfbd63730b7d24f1a2d4f9f7acb41039c6d9067877c304a42e7db2f0ee2b3fa794d6780fb46a3d1809821e142e2474aefca992370be66dca4cf2c560a4cb0f418eae8d09c7cb74ea3d05ed3853423851a900067499b4d04080e73c618638c52c6e9d52b0884b68c00e70825d208453a5919f9d064ad94dacc3a25edc3e1064887ede4caa4ebc99b139d9cc598962670963a4b9fbdef20bebd958c8e903d1e6b0498e65f4b3a50173b80a3d1113b7149343222c9cb1585c9486983427b4c0ecef7852286fa1589708d55e4472152bfe20b45d8fa65d3310801ea982925861014755d0c427e6627bd6e62fbf831f860eb5864a253f4f1533108f9e958eb049576b28a25a210824c167d860e1a2c98d18c28702002ea4dda1a2a1032a39f4c16b3ae224089a423b3ce62f18310b38ef3748461c60766ddf56000e5895977bd8864872b9a9855fac57c114f0760c10e7698d12fe68bee16a3a763ab550096c0392669cf9e0a71464727835934d650d54393911039dfb567b231ab558738dfc7a11d0ad1c92670fc485d2c21381a8500cae75514e2a18b1e6324907ca263364fc7f264e2a54b9f3d1db343f014ec0a677c66088afc30c41b8500e8b30c8ce6a58e8f73f6fda5a629c51cb26df3755fca6e9df98a2efdc61adb3cedf39108dd05daabd3be3fcf9359daf7d7f2bc3fb6775dd7755dcd3f56363352aebbf7defc63c5c5d8f909753dc618633cf94549153570eea321232400e12c87961c69590c02110e863c61021fb2f86216cb30d2c58e114a5cf1248c5996495ec6d8349942e7d2bbd6495a26a12c894b1a045226a9902fe9a7938a8a8b0b080a4000279cf0b969349fe5d0cba6c9215982fc8670efb42ce5d24320706e9d3e7dadf3c53645bf3f5aeec42c7d7222573ffad9d0210e1dde504bc49eb3e5a3cb185b4e2f210a2ca7aca293fe2f65a2c0511aa06354d801c38e29f34eb1430fbc37a4a1f387fd6cf8804cd9bd76de6779057d9c7005962a47e01c06499de9324a389cf14edb958707bd1763162b4687d944f7648d26647928e951865e155846d9612a05eebc7569c5cfa75c48b11c67967a800d67f11e379c750394600f1b2bb761897c44ad2017703d45b5e22ac718a752296f217eca71dea6a4f8ca8a0ace4b1595a7a8dc66e28f76684aa5be4fc211b23f22129e27cf4d5726a52f149d44920406d2e8071e263b3821f2d173c0e42308a45f7a0c832841104c9c3e1a055144103b4ba827b5c9e9c81a01510382880342e802210253ca472320764e42968c8408e1a57b9d173f2321647842bc403579e9de54a283b1819025498c7cbe443e1a09f9f9ecbd91909eef3e1a09f1618ac07bce2808a28f46412479e971842efa8d1b481b59f42a8a39026a44f53e1a0df1c34bef6cf7d14808ce4808345eae7c3412c2f6d23b939110472d174e1c781e3a181960e9d1730918ede43cf7d18888a18f4644007d74fbd18888249ee5a3111139df804e3681551f8d840892f1a95d5773c6cc09baab89f0f4e4e8a86081775a366f4bb126526ff1b95125990e512b5039e78c3748fa03c443959672d80053a73add4b5289e65328d6dca66c3ae9179d3ed8a713aad321dde9900798ea7c431141ac699d2993ddb5f7722e1aa5d11e22ce4ed9bce9dc564c80a353aaf3d17053afca9f2d43e02c956a8d712551edb6656d75aa4379e80f1532723bf2947a54fa4c89d0214a446b4fddd656ea589e4e6ed427143a6f2dc8ef08e5b3cc71d2b1a8c40c1e5e004f3d4bda53181138cfc8cac0d9f5140535a4924ec71a6ca1d5de390dc6eed941210ddc394a4b1dabf488a58c941876843a8cff7af9b33567af78628cf107dac718638c31cece2e57ec24a531d1a78b312779a21d06a88aa8444d3576492c95a281000000000314002020100a064442c1703c20d3335df80114000b8aa64e78549809a4248831858c2180103040000040000004b37103ee0050510152ab06c334aa23d61a64546111202742d4ca06e3cfaac7a90344a8f04212d80820e20f4ee00126ae7d959e5b2c0de2c4a99fcfc2af6d2bc199a74a112ceba66362a4c6692c2b464700285e1b5d2c5caa73e1fc2b447c31b8025c30e11d78ce88e77b68876188c5100625c7b37dc2f8ef21c7b3d7efe63ce4144600e2c0b128f45960a10407781735813125f7025d69533fd841f2141cdcf403707a14ecaa26f3673b7ca4a6f1738fdce599ff8b605585e5d5bbf431e98375945d3a542a263c214840501aa76284d45218498c0bbc25d9db88a4c4e42e7370c88cb609ab9e6425353864c51d250e9f711dd3909008baae98d7747ad8a04073f0770f6d39c05b8359b9e6c009b0808199b5a985fe988c654613e662fab8053de07659379d31e6c20a8f5995c9da06e6ce0449decb1e5cb54d17c5c6a5be6da08cd6f42a841a772ac762bd011b71b5f2c0603d4bf2489691e9613efe665c634c2afc9c7f3e1fbdff9471c6d2947208ec35e9bf1823b90e219e0dd02c9a9d4832958a43d9be00395ef5fd04966a95bf49ea63fad357b79f70bf321723e288f375997f529275131e00e5641c4a8a9de59b9c1a758231767b99146eae5daa0980e58b3e391cb6800a733d64413222feee04385e70245bae7cf54816d1faa02de8dd4d5896f9403a9f37b3dfcaa95402b7035ee707782a509db6e11c7ee08d83174bb352bab9a11683b6bbb8aebe31e80aab5367a98126c254ae02a270cf934ca401ec686f36048802fdae075a3ccf348506364c44b653ff0f5f4546796b62006f312f2d7ee830e8721bea310344b6652d41ca221d55ea873cdfcacb83c81d3d064d6c4ddb0101414105aacb80321737ed9033c41d1f1fe8cf78cd50e3c0ec886d0d7861c992a081d7e6e44dfad88d61f5c350675e09d56695a11ba3730ee49567a11fc720c6af0273dd7f3d67cea5397c254e1dc4eeb130906ee318b18320f86497313056909acec7cbec1a65d69c9e5e184db9108108281efa1b2d7a2d2ee12b9e56ceaf387a72b0d45d2df7a8b08c01f9cb92f5668101ca2852ba657ad9c2adad6e93601f029592caa243d8823776602c36c391773654c78148246ccd12f73f9bda6a597cf2780602082520f7b5b7ac401aa68714b0c69862d6f16fd67a92610eee9520c9829aa9f69e94ec0c1563c849e6d68d42530a068e62fb8a6326406183055f5dded58f34f077e81171fad04315da01065b5c7ce11ae9988b11d760593cef453239f68651b203ff84ce05062cee38463a0438ce4b93c6752aba5b9c0c023e42cce57014ced8c187d6d670de8edde4a00ae52ca037d4a8edb868a01b26bcc6fcd7c8306db2e9036e938ce735c7327bb934c1ce4b8595c441ede18bf79cb7881dcb074ff53b8319538201accefed1ab546aa3073084d3c7a227da1a396297438cc3365cc338e3bf5213699c109569d419ff32fc462ea1c311fd4bd645d45e4a5f3973e447f242c0767439b8c4684132471bd6cd64cb5696d4e590b356d8e2a08c6449362b68d4441fdf3da16c093cfc225f724b13d4158d570980de17060bbf7cad3f8c67437b47ccc0e72802ccaf54326c048a442092f5628b768933c6d18605b1f6d273e112ff9a9c73be1de17e188fe293965a0a245568b9a01b4b76c0c0fa5427591ab9526e5dc1d62f2cf9c0ca205359f1b1768092db1eb9d3588c76d1080b46064721661790c5d09428a0eca93b977b7b145fe4889eaf4031117ac0b453f97a8114a5da362f1025fb04d1cd3503c491d1c6be2baa44617d60c729dee4cfed16f131d669f5dcf5bbc4d00c652961e3db9a8ceba2b399869fd52f159ae6a4a1047338cc02b153feb0904d14a73571ac440580d03097c2702982a04028420bc91037b26891d1084cb7539653767994e457bcae6e0ea63a00c65acc52628557b223384a6c4b2034c3bb17878f65e0d187df755e2b6460ce0ccc2e00cccecd938911a8516e994e8c3b0920bb24c7e2ffca4c6075ffc904db334e92f3482902010bbd6201fd48503c558ac4bb12d0e9d2538534124655ecb5b6e8a72c7df1bd7f87fbe98873035415235cc78805fb255c6d28fbca8f0f5b40080f1e9a127c855b34f9aa6fc46b2a6e697988bdf0ce7428d7a6bb9966df413cce8facea4a444000f7696c23e694213f082544587069820387238f2c894804beb80b7e908713bd85bdcd89aa5e91202e167b8eb94adc07c1eea8910e16051ca767e823c44eedf40eabafab2cf84b137ccf5af3538a3958ecd5463e4ee1417ee285ff7175cdb4532cc83625c734bffd7bb3be61e3f285efab380eaac44d0f49a331d0641bcd72bb3e87dc444717de83c2109a5af02c712bf80abc1a2086ad3418a9dd0979098163102caf714fadf2711b271cab8f375368715fcedc1a9d079934f2007d2fa51de76e577ee5b8cf05a8be1f325856dd0dd339d471e32f7472eec9cd84eb2d52ccde5f7cc7b2e033bec4a3ae5c96dde8cee2eef8090ed2e24b3f71e45d2908e3a1056d92d6329bb354cca141eb09c1796a336246b7c0e73fb1f29328267246dd18b2c5f75011d25e5ed878d847b7b3305cc593cdf880c6fb49dc17013c1b36890e9c0d94ba0e80d1c2a92ea9f6603bac5f690ca49eb9e58473c0e76f8d06ca4d8d25b311e3b6ff5ab519a796058ee7571795f7d8e1a54130fb45b72b3cd18bc1562b56d2814ad3af199a129a4e4dd90a337c3f341ad1041f60220acc8c89e17ca2863d2f6c39c4183883a8335881b0308b09fdab82fcf72190173b211eeeb19091f2c45c5a6ac3c68e7593ebf2b54dffd25c4d30a38d31466eb081417f577e31d4586e7f51c5d09a5c76d9c7516b95a077ea4642e113a68935ee7e033dd886609219db905d7ac9cecaef18260ad6acb097e18c89833c4c1250d6262bd868240ee9187afbefc3d0040210c233181857fd9095989b0405472839ab7b8cc19c55615a7f43167b1f8c4ec31957964f958ba4e1a1eb520d891e1875f408f45e551b148a3d580ab017be918a9d6d17250de757c37613ca89d487aa5d1b9b766d6b15e776caae3fd9f997a67532ef9fa13db9782450388d4f83d609c72f2d30c4ed8da171dd920b66b44a1998c7e2d2970c2e3706e447e1dfd20b2017ae68dfa0e55a52f8e857322258e918cc08df4465f61c36e439bfb974f9ba97018a9f10aa0b28475524b6f23e4a293579df6cb49294863ee02f480aca2e94c19caec88c582db19d02f1530bb042659a4c55094496527cee65650e01b35838aab7f9661220c06ca8eb47c7b442e53cc74b79ebbdcecc23a39128f46485365d984bb5b5c3787cf5f850be7255aff7eeeac9f8f486618ea1161394aa4cc05d65f4203c0fc4a96f69e29270a612ee863c4cb5e9311e975433fe6323c87001d15d960caf02f091a49f3e92ae46ea07761e501acf07abd378431fcbb1d59a1557ed3a8d5bba8b12bc973a466871a4f276b889577f64198d924c48db0d8cc9228727cfbccd64067035c66b98af946cf6f70157bbca51038b0b3a1bac9a08cc4e28e791420ecdec0c1f9eecb1f6d838addc70a46c50c9d776bcab2003254338e31cc43a71ff4f0ef3ab47c64560829bff6561ca4ba26764eb1134ae41aa8cae0d43098522c22d8aa26daa3de11546bce548cece909984ae6091cbea58a942207a6c1115093e023e15f9a7b751844c08c63ea5c156235161b9981b3f269864441002772b2c0aee031803484531f8730ab97a9e0208e4464b7df5a719a8a494da4797af23092b30aad71b47b0113ec2d5e259cc66bcd3df2d0478db57d4325c85aace7bb6c7eec74a2f3c0813efcc425e04460b2f18a20e44d2f3512b2159c750364463763335648ffd7151a2cdbcb203ac46a7b3037fdbe2dc6d47cf62a83fc0fa83eb0804d0a05f2e15467ff1a7d509004b78825e573106ef4bfb3af903b1965bb0f1f596898d22217e2465893ac3be1c1bcdae629fcdf952750368a32dcdeabda2675a3f4c4a8502464b33514cffe2ac59ddc1e97cada82f4ee2da428b51390916be4ea29aceafc2940626e9b7e4955a0deec73ed1db44e36d4fbce1fc4b69c99355e79a9a18f9e8f058db6498f84193e9617dfb1f552b2e78c75256000eb1c4c678e3d8848eb658483a652eb1c76a0f73554ba2d6ac637023d56b3dfadae89204bfb5b52945b5d4571e0c08e06db55700cbe9e8f2e8d175d8e915c821e56d2252411583cc4830491e6955733804abb6514739529b653dc673916416f2d4c468d31831e1236b78d53c5c69fa2c52809784892984983ef5e864fb0f3c09359a8380d80bb7b881efe345a42b6a0896cc84c1ce435ab9da8aea5c67eb78bbd3fb19884c10011cfe723fa460b342c13e9a588a43d7fb4858cb45be62253bb128d773bc1da5a379bc701258f54998781b3aec931e989b0dc7ad654f0e65c179d560928a845f8678134d7b5180c90a2a977bf49e7bd5f4380bfe294d177ccc8bc1c737bb2a81571b9da00fb5f239f4738b9cf21cd7df2664a89c17e933905784afe36d9d2f118266dd3594ecd272917a1850fab9f98bdaca79a58889a4907dd26f854b036bbb6e9e390bd091778b398a46de5e56cf23c1f432c0c7302fb9f8350b1afe567fc755ac097649b63695be4692298252f80b5066ea769c4b4dc1b1bf44527fca7181206b89a64239fc1ec9d61d3d9f921c1e63c8e5c14d77ead88d5e692d8403edb2794c836017e9cbda4b58678c7462451392072e63adeb2f0f62ac3c5d7f8ec695299871e1eabb6157d5d2c784260332d2e43a25333a309ef325e83e58ca0b887dd38e7c99056f20afb85a88d2a3c44c225fe14ed11f3984caf237a2b6438131715e4605454345426984b1a973da1e067c807fcb0289715af2c2216d9b9e954017a5c44318a518e9fa1ab14ae7eb4b850ecf55ed0bfed1ad3011222340e6335c22459e1c275bc3d7ba9d481b23920cc854812872c176b3c4e802884c8787ac493eeac6b13ac65770cf3b3dce24e20bbc1cc9465daaf5662a61420f5ceb9aa552bad3f5c5ecfa1b90f1ae163a043532f09577a1b9dfa26301a225382b0fdf62ba372c30fd94396e072b0d8658e66859cb1c11ef884a6ebdbc8b252e9b2d8a93582b52e5c3a0cc42cfb1a27f3971d257750b955793f3fb1dc4183fd789b8b98f2b3db5806dc3738cfec46e1a60a7d046aab4ee6d18089213a3ac84b7b38073d490d44e9e50bb16da1db4801e9f86de6700eecee467a40e69d5977ab238a4c5e02c643d5ef99821d3059e4fef732e78ff704f0b78ac2ee9b8e91e7d01c3e7278f0788366b82e479cab3444c365053937605e15a1a3a8fe424ce16466d1de658630229131f91ffc2418691c636071ac3be53bc5ed47a26578b313c5c45b9e0ca4a2ed4069dc0b6791041cd9e33ad45cfb400dcb8a8daaa32952a7eb9781b75f8d5f3b7b23274ffc1b040d77f469aadcd4a3122ab14554e2f97cee01aa3f057e23d65b92a96135e9a86e2430e8d25236de6b62cd50530d472c983735ed2423bafa68b5e93ade1e940fe34e149c9a3163201f5203a696192a9dd5c02864e8e446099c1f80a77020c29eb971be91c6ead19cb56c4b820f8ddb653418531df01d473b52e81141600e820702fe04e775daa18eed528e96aa7ce3ccff2c8869d33d9a6d5e946bfb90a1054bc738e247a987b74e6edde584a314e4fd3e53a8b781c1b530f70c954b668647c45dca929783dde731169104f2b27652d050a09ece1c355bff97d541a14492bb318c4498d0a8398e2dcf0590dff460b9dd1c99952bcabbab0b6f472f045bbf578b599552af5d0c981a72f5d0eb76c640ae5f1f6b9920377c0705d66e629dbc95deb6fcecc10df296f8c0bf807ed6370c403dc18bcb9bc7def68c02d7b9bd45ce79cd250b5a52c782a58238dd8b6ebc502bf6fe30cad61e0c53f8a9625ff34dab8def1f4f73e0f4db2affdb8e201901df9201a174a9ec27282c6702ed58477d88036d0b13dc4f482e7708f7e1ddc47527ee1757de3966291e5fde9d8e5600ffc825d8b40e9e6a8873b4cb3a24214be02edf12dc2b5a7fd8f7a096f99ac2e75b09604fb4c79714efaa28e2c4755883caaa182353154626f11528ddddcf1e948e643a754c8a7b24ef3fa3c95497e9fe4130009c3f50e8214a554656647747b93855879e7472d4c1b220af5d4b1babea26b2db3819f7fa5fe5843bb6796f75b3b854d5021e737b5da6a9125908836a8cf9e48987cb502d47230cf9385ca6f2a53eb13f8081024c605a0482c7f324bd9842ebbfd58d2d1c3595e393caa1673dc72a801392a43751f8494c3b5f0608bc61e209afb6c2d5430cbf37e0558c2789ed2b5daa481f02ea09403facaab28255dc5177bde700d5b061aa18e5cdb3db53938742b531a933f187b366cc0779b100d8a88b31b92b48bacf02c33fef02af021829eccca2512b8a4eee502943a6c9f8f1e2bd3ce0c22d24b3b1a03e957072c109e8f4fae7ae602e1408454f159256e0ffca1734d3c381c01c149742b59505f221234ee667d0d7032f8612370e02a019ba30e7c05666425e1053dab3a442dbbef54797f44855968db2cfec550bb78f656ec342f0965f04f43a889457424d50c3209fbc491851837a8070648b4999c7e7b47677d10c37ed2c5a368fe2fea7deb7aebe712b3b3a7b2eb4ce23cba1d28c9e5e0a35892bd05455bb63e0cd0ac3863dc3625bb944460ddcf6cff6312af02ba738e9d234ee32256ed904b3372dd1be6814cc9880cbe24bb06ae6f3923f86097688557e8b8ec44f371275abea94b8a24fc353f243a402ad6219f29784f9b5e73063e441579143941fb28940cdf34df8b65f656a1b5d5a4b19350b1685b9897595f6a44116e617beb2fb8ed51af594508bdda9bc5c0b396073460124bfc01837ec7d3f992439b8202caf4741ec692fb1b48361300b8d8878b49effeee0e5841162ac3978c71af18ec29690751da2c81ac0c359e28c6c47101cbe743d95fd735e332e9cebb849c5f0fca6c8a5b2febc401e4972f23ae3bcc94b489e562f7d7da62711d240c80d0594bdb77c13570386e329c03731c4c633f9a7a5758dfe49350b3b4cb5a930250f49700d470a36db27a0900f745b126c73c445e8bb82eb88dfd89f4ca959718138096c04494304601d28807fbc47c9930d6bd0143a541f1161312a8c70338272dc20523011bbc6df74d3f9448f0134fca516ebc466076322c3c48ad9f1763f0a729e52f1e9a4dcf02a6e0da28de962193168bb5a2da89d9daebb4fc6f2bd590008b34685f2b79c1fa2112680f6079b92c0d81bda8f136d4d68f0346cf594c4fa916e2077cd63c6b43ae37d3fc7715028340896535ec42ffed9c6e7ee02765e6f48ec3a55250564df0194cb089e6cc49ffa38735618bc5d219cc07be041b3493d95f0af0a8f860cc3360538861a5f04ba46ea1cacb8c14f5c9af6036c4458bf58a6701f3b59e04911996b81e49f71d37a27b8cf00316ff9a47458cb2bc45e133871a15aa91a0e61cd3214d650ef4c39614f48d72d2e479f08b3ceb4756920d54103490b09b57650c680db320009961528ac23b9043da40bb283c2d110bda4f9c0e85abcf6abae02e1872036616055d511273b3710174af3bafae5144787c642583b506c1f5c171484e02cdd2e23779274e770ae4cace91ec3f0468cde38676ce1d8f94a1982bedb5f9afd02415bbf0efa5f1daae01ed8b4436de4a5a2479f7a7c63d171b9075bcfa241877882383879d07d58cafdae8f3193e4b45ce0e7dcd098f0cb46950ca25d6d7b959a312b66e1010e895d1e43d7380951a96dc866aff51f03958ede9795a42d3b672491c91107c6bf38b65301913911042be013c89018b498d2b8008b53a81b1dab98ce75cde7ba199072defe5fbf8dc0035524d6121888cb54d8ac4aeb9fbc7a23a45da08fe1870cf284d60382cbc3f85ed8d3cd4bc5e8da013611fa3b06624eea6e9a4b472e012b6f5f7e045b0e4319ab1d3ba17d497bf1111622c49a5e6e1a511b0604b83981d1efca746df8df15a39d67f32fda5d0b9f17a4f4a933d793ae81f42c2137c7893831b02f3993e2f54c94db7ec75842606a9aa289e1dacc8809dbe40b4379ccc5109f895251fdaa7f8e64baba8265dcf9090710ef063d6883024f8e8c597af5dd2ad58dbef63c84dfdb54aabacf77f52129b90c98a6be76b7bb76607c18f38c29952c9e5b6ae2e6f3b59c7265103ad299ef7d280ab3b116db06078bfa3b4fc83088c155113f220abd8278ab24a0b6a412809d48d9d80bcea6c1f4e16a66f98b6ff0cf056d99bd63f66fbb41e524e4f92e22dbf96cc17185333027c728046c5748f40da6a6e64c8fdb8df1234ce8658c28cd6e2cc0a5ba4bbd836e292a8eff93e834d79e1b9855b3d764f292f7c54ee80f4e3eabe06359eda7370398e5155d0050c71ecf27049aa36715b30c1b7a43d0175c7b6421724b2b083435e189a3127e92b5882b71339a7ef047947e287b6c3058083365ab9f0620a053b77604051f825f80669b3baa2b3218ba59208702583bea93f18a790287ddca2e7fbe82d086281700abd6914e4df5796f38bbd5a1216fb789dd94a55e9412280583ced63f477f4f7709ce4019e9dad6868aceb02a1601459e93f656b15178756cda9d782a6eeb379fdcbbd4b31eb1314c839a051a6f8179acad58feb33c3488a60da715b7263479f46a14254616cc2732ee28f926e4c5f561928d9817e49f834a71577d21601b0e2263178ff4b067c1df21ceeb28d60bb24ca61f9defb9081000c8acafbd0ecc7300e32dbf7e8c52662639e486f3c4854c04ece8cb4a0ef26fb97b8c53215de44f63f8360e61ec23450fb099870d098bf9bf177d225aa82b42182adabb53d2f880c9b03a21498c56c2af0ecc964d3468fc5f14d4356793c3c44dd43a83429e58ea51e5b62674b4486525a0e2cddef739483e5159c9220efa9b0749a13892105d895ae709c026727a828b0eaee1f6b66f182908024270406000c7bb9840c0396e1852576418cbbe3e40161d29a541804301b29ff444a858d9c3168c9d320629e166c20b5ad50365c45200f03103ac12d62f884817084c2995f136d6bdba131417aab20e4a68ae8314ae72b61108d89a3e821f14c15941cbbcd939c7a53646c7bfaab4ad6cefcfe8da4efefffec02b52c2385cad634f8b11608cdca510c2e47d737fa785ee927cf8f07750dd325219fb4411002fb082e8760bd4879489a3a2d8135fb7686ab0b8a96a633d29d7951a6015810123a82115f061c0010e504e46f99435b809a55534582aa019773519dda85db9843151f9bce7631b94662e433d726bbae06c6e1f60bb7f3c436a3fa43811a5da0a925ffca6487ce748d4402a8b42aedab7877f40d5fd45cc00abb18db97ea372acd307545cca183ecbe7a9297e765c29bc119749a0499f9c3a5dade010dbc06e3b4892ec8ffa2761be6c8074fb804da63de3f9e9914feebfbb06ba629c87a193a6df4beda7097d23f379f5be6dade792b79e61a5f4fc5004df95c07c2cdca3fed2f7f26bad6dec8051fa5e499aa69947fcb02e90f23b0ebbeeed329713a3dffd4725e7b540375b031c2f2839d05bde442a004ed7cac8d93d89c160f2035c3d06af0567b2158e5fa0df20b4ea5b1ec196443ac6ecf852512f8665c311009c3f428ba520a2b16a18bf5a1076f49bc8b3604b9e7debee2b1697936b0ae0142824f8475c8e99b062c9ef3e1d6351b738444966b4840f8fe78c03f94442e4f24494ce0eb6d8c49c2f56b53d4ac82c734a2d5eb3a325216feef5b5c9f4c44b0d168b32f0d691d8a82bb2d98f5313df9619ecad8238eedfe7aa206256fa36b952cdaaed548bece4c0a7d6fff029c5b165c4074d0486aa739336b6583cd0ba62c20917e19ef7d118936195bca71bd37c32ca12ec861a4626a31e8bf86c87a40857697f4778ef4855dec802f44414f9019ffbbdc18733d4999f0ae561f26f5debcaa14ac5211b5c661f1f233c29aae603e0df3862fc5af0cd30991593f4ec39416f4b09083ca0745c07064c9acb924cb716bcbdd31aeb1714d1839b42c37693f830f09bb23e0d415ac2fd796dacaa276b4272bd7cd52c15de93563046c0b02a39e982d03d74065d17de7f2dfa7bee4d6da88b032ae958369a12595bcbc8a5aa3ddb93de9209f1bb60dc0bdbddaab98ea6610d6c05c891ad5582e9b94dcdb3552f031b0ae69fc48c4c574715ffe6e890a8d623e1222d45b2ac03240f98fdde005e25a38f43c99fe21140facfe2ba817b42777eeb51295c1a8eec5dc16d070f61b62b58ca2a4904152deb76e9937465d596232a2948a9ee36b919571125e4520a16274e11c5f2d5947593eb52804c3b5c801d6c698b85beb33f24e0f1c5c201723d0c7415c8c0f3c98a0d89711f089e6c6377dd7e3f90bc101078a46565d46d1e394cafae32ad1b20275a44aa0e7225ef7574f0f2ae4004eb5d89217b7ec7b17414febf6e4748ae328324d77a5488973592e538fa62067d8586df9d487dedbfc781ac65ff5952134cd730946d7183901a26bf21a828be2384e2b0c1dc8565b6a30a1cec0abda730c0a3c26bbc037560c786772d7bbf17941e15e67fb31fa9290be891f8677f6411bd6b224bd57061263ef083856c9cbc1d310ca43458daf4ed2a85d807ac4003e55ed4f49d6d0136c985132e8da9a099398bd51c860db1b9d06357c16f577efa798f00426d81bbabeef053988721568a9eaa95afb31acad7a8de06c5f10d90697ee1e364293639243447c669f9be4f4b2a83be33b1620ad1a551e34c7baf85b0cff3107c77b6a8d6239171dfa8fce0a878bd139a1419d5705f7160b18733bd8c49a015e827dbb531140fcaa12a94cca75009693007edfb9d1c2b152449c0dc8529bca6421e58b2e31e7064453cdd7de8e7d959c701406c0cd03f8a9dccc21e5e5e39f5d9c06ad90240a44b2d9ff30749c829c20d9cd8d20999333fe2cb4620f8664a4c5fe1007df659d3787752778103dbe45e812fc2939266a8f70a63fbe188307ec79b2ac9fe8373054a4098229249597cda0cd5f31044fe176d25b575a1948990ff6c21b6204f520fd7d504083c39ddc319f60a6d40c09eb18257418271107998925120e988b395a036f42f8b7e729661b8cfdf0fff811903cdfe118aa73af7a2a219c1d1ec131c041ceefd93dc82be0eb230311cc70032e71bdaebb5375cb463b35c1f0bf29e72aadbb829223d50e103c07392c1d10d3c607fbd0db7e95472abc8e03a5dc9956861ca3237c3dd75fa3ecc644a6865652f63224915fbee0e08aa8eb09dabe0eb3cdc5768127fd2f2a15924e7767bd5f7b2aa822a6f59bbb07547fe728fe9e94cbce232b18685e1789df02fcd1d7107be82f6f5e7f12ef17a74e058f1f00aed4e3cb7ec68354ea579200859831b8dbd269a56246804cf9d6fecbb6b611e8660bb2d58331abe646fa4b10fa7b89f1dc5c5951c77f9a7b4a058e146e63e29f47a63d92f69da1c773ed518f297cf6e95fd000ff73481e74e5fd3dc55562beff884cff13705ccb825b77cf748c6958b3e75d00c3336ab4dacedd0244372e50c0c454d38a94f9491b615b89205632f78ef76fe212aed33ba4c692aed1f980fc57b2ef7fca402e1cc0ef75a49cd9df92c3af916865d31dd7051696c94f7292293ca65ca73f9a6a1f14e5664f8e9f44e829c879709880f74f268f19d9276e36fac9a2d823aca9ca62d259704cac128172856fb23886681fb460812c457e388596020114e66aee282f0dbcc6d25fbdc6838253ee8ca3cb54b9d36628f3d41eb6af9629f5ed27dcb513b2d22dc0b52b00c254c3d39c19aedb5b14586bbc54ea825b035c5923069cbf059aae93563779e4bed2ba0ddce3a2452b075cfd99b441ffaf83f46b7841369d99439c711aec3efd64a0181b30fb88486982104b13846525fc87132cd201f4e4948f3e5f86c2982f0312d1ed7c99b71c12af5da2be0bd614f347d1f28662c20e5948388bed461378ad1602a88fca31469175bea8b608dfa3b31b6110c6576188c8751f9600f72073f8c40716390bc14d0be344b8ac1971b7e1f698155a21e48afcf5f817608e74143471987a4a3b3a9f45cb59545214e2bcfcc56a8fc89ba02f8b8c009beb8a04ba392340c8d1734db982fef3b3f887c3b85fb85b848c33e16127fbf015a897225198bd01b744d59a9598837f90e0447f103e1b83f62b7a2c95fa9a7379fc29ff94c2aca436cb796cc038b490aedadbd6e4a7a003e817819708cb378e7913b1533f5744ab22796a6f95c6864a49dc12c260dc1956014335f51ea84024296d80217ad083789170877e04e2071b12ff2c5e13605041acfba96253c463e6b427df16eda6fe2bcb161af2ed99c72909e6437153a4a633304583f10f9609e62669a7f2c8f84abf164f1f97234b526299453dccd1930f6e532ab3f636ec48e1d75163ed1b16a89ff83a8e112fe9c7e64019cc8279aaeb0cc496558b1cb95d5b4b74c5b767338cc58c76e537c7fb607be9d27d73086290843ed4751caf00162a08c342c327fabc44448cf7a81e20ed6b08292baceed0d728165c6a299e01caba5ed54a3963a49990a0e0950d0fafac2e10a4085615dc07108220c75eb60cf001fc00285ed75d804415f50f20439f0c2dfdd6dcecdea95d0a8a8618d802562f616a48e82f761ef0e96a7042cace0f08fdc6f9a27c4ac58d7678fa537ea60060839a6af0c45e57c1c41339a89e19f63ab52b15eea97d4a7a15f2edd37001bf8feff3449b662849d4441897882855b2764734483196990d9ef5e3ef7589e6a94e00a8811871d90b1b784d5bca59663cd0477486476b8ead193501c5062b761c4bb57079d16756bc8866ac1ae1b6c1c358d885bb80f3aa84672eb43a68aec5e1b003ed7925cd2d201cf3acc1501ac099245df859d3de19ece73de2bf6c38e09e4fdf6aec516134919012c575e88a3cb5cd1f47d59d0b33802b2f4769de57dc5424a8120807ac76cf625759dc0a83485994724bb81c1e4f0d92043cc4fd803752975cbf14cd70133e08996741d5757b3ba99f9bed4d77ea58e91da5c28aed608c60358024c465a9ad04046e27199c22e402494ee13658873d350fb23956422d5d812f04dcd98f3e9b8d2bc4c69cdf2112ca9cdcc95d5eac7bcb240c975d8a5a650fc1b0480314b5471495429b68728fa1bd71fa2ab9ddc65c53ee81a34914952878167eaed24f455c81730d4f41ebef9b3614f19b160c9b1bfb95ab6bb00cf461d786ac24e31153d4da49715d814e66eab10035ad257701704314b305f745ac4725a086efca6cbc14c08d25de4084228109ce68e402d5c9a896a708b98839e5a0d12561c1e1603e068f54deadbd6082d179437a22824f458ed212a5ca93714d21a763b537cce97130eff27b89174d9ef18b9284c795a9cb8b33d0840cbfcd92cd34a370ba967089acda6f2b2656e3a6dd4e8ef91ce8f62fdaa58a108f62d7abf4a7aee4b7f04b6f5d6ba9da347ec125066f19d20d3b42dc11e1bf549bc5ef6b363bcc573e91c4fd0582b0a181b7e4dd4fde85d716765592a66deb055d4a8e05608f36e67a1f1acf64e2034dc07a9f7c0a146c0768c421d47d1ed69a3210929e7ec61b990d770bda57af71b1ae98f8dcebdabe235096476014263d05b5aa113069e784097b4d5031c828f39840fc38f0d7a69b51109e0f8c441c7e33ac675aabd62c7e23a662cf55c15bec234356ef6bdaf64a854e75393e97b08fd6ad8f9ba57f79282396a229a1ec68fa906f0b5a6f49c182a94f081d02392cccc1ec755a4d103342caff80fa1898ec62a0171c0790e84ef5f39af825a0db528bdf97d4b2540a5eab0cc9c67002830db4f8c18456d1d79823a56a93f988b9ee943eb3941c889551e63888f4c264a9af31194f72e579b4e66b7cce12f0137b81be33e5b16bafcab0d1f635bda31e4867192aec1dccf6f17dbc2dcf282054e145cfeb5e93949dda5a98222a849dc0563328c3f6ca36a9801094b8e88633dc1eb7527f8178fe08b1c08de287bcf16c8a56906f40c13cb2a73248ade48879ee77c3099823db9a8ad4030ffe9612463b1e9e0a8e53e9b8d905d2b3c8be8ab321aea62e327a7310e24491e6773c66aa92262a940b2fa1bb2c626be2b05346a15d73a32c8947fc1e71c5870bc7a48364b99417b5594641727e5eca9880eb3c568ae4d9c437d1e36fb90b0e4cbb44035b8a602240eca9223661df00508dec3212e0e9f0a529b70cc1041c454d5252e1893edf46af65d7a647baf089ef73e3b6244e1cde6c9eb156086c26de767b123e75b40ceebabc1ba81d287782027c69e5a807e7840c0d692200d236b72061be52ccf89838fbf2eb5dcd7082ca0a130765d9d114727950346c1e0bf198d290b5db1d5132fcb9dc596891bbabdeb0ba45528a529dbcb4f66909179b11742e9feb6cc03208a35a767f02711cb5a02ef1bff0366223d155a65b9a03da55d9dd92b5e56dd242a4e9346c4158a98dcbe55ae41a524177e241ecb402e226d9447b36320ebc1072660f90932f0536e0e75c11bec8340b59c16e6f68a9265a41ac018d0f75b896cc45b883257bfebb5661ac85ee4db40a5aa1258e209540bf4d24bf68a9d80bb64d0d9a6f5a15235f81196e38c11cbc0d90fb3e8053a13a90b3438285eee6bbd741271ca1b733215e941b1d46b9e9cb9b308f1d867a254ac35e6e84cee3cb8d12404c12bbab5de6ceb924c3967ca420b31818ff29539b0c6181818037cb7557844758895337e5da12aab8f21b690c352a9de50e2fbccf5be993b4c05a3a700655926e33139ba042f06003c981c189a56325bb76af9324b469bcb309db3539b5c37f67e7aabe3644bd152f0137199967fdd7c2bc2285b0e60a3913a923e530e267e142c2f6724b4336b7baf2a9217f4417d588296fbe981a565fc9d591cf85fa728cc4d0fecc9c537bc3d5d8799548be41718feb39e28f21aecf3063b7e3dd562bf4aeaf5336651da86a7b02ed4b760c6033fae903045dd6bb7621d3963f3843d6584c24a4c6afac14454362949a3a05d137f91129e3d12cbb6d61dd3e491486c2234b2d8e9d0ffb99d9420fe88a8344fb6ac71df9e8660e0ae8fe3efb9c4ec3d1076b988bd9cd57bf03ec6973dfe987b0e21a1ef1433c00d17c6b1dbaffb1213ed87e49b2ee04e6d9aa9e55b8ff12b09d24ada6168b550cc38641829bee8f0da276688e82a91742af49d39123b65c08d7d29206b0c907d41d8557cb06fc5056f7a2e149ada448818e29e95a69be5a79753d3e1c310c700b69e95f4f9e0f107d4f742e742b69a8a3b7bf3cc5611646ef8cd74ea514a30ce08d980c88747609bc8bdd5663e1f6992444daf2ce3a435a5476955352ebcc843f8b677510cd9f8fe7c86b2bbe5daea3fe845b5b5ca0fc80e0e857559f9b4a7acf740bad3f73c0c19def9a165793fd44898e040406a800a58cab0d09469452e655b417759b3c746abb48461384ac95b41973c41a034620bc004dc4ddc8bb60278baf7e0374cb893a2deb86c1479674ffc41e33b8d2775fb637ca6bdaf22a807a33b9a0084a45bb631494c8ccb3e9b9d641812f35e1c1411623b02f639f4dc94cc3adb094a99f7175fac687d1a8f2b1c54f27a46ca8fcef8a88b997a84253bea8144c5552b7a43eb4905b15650f06d4ed12a8ab8fa2264c9ec840e1c4a8481b24de699da72e160ae9157cecc5fbb5e8f6ae6d17ae8488649bf6fa8114f0ce9604bff4dcd5d8b33d984d1d87dba02b09396a561177c278061f9092e857789a2b00282b8265c105cc463bfa67d2fe7cec0a5867bc6bf18dfe99a64aeb0cd41f784a96497244cb3339960a61d0f5065f8632b90b7dae69bae6268cc299d4fa3e3414150c5d39a9e9b8b0087a8af49801beae2e92f69b4504b339bc25850cc521bc2f8700fbba9d7935c6a515f8ef27d9f6d6028a55f08bf1b736c4c40610bb9b149b63533c27ab8cf2d821c6dd33bad3d0460458ad6ca024e2b06b458cc23e5cf041e46c4dcf9954caf885f1b9e7111f94b9a8873318837c53321d54fa5395e0f8d4e8fbd11a5701e370e486cec7477c69f68148ea40aec6aa1e09aa3083b09fdac2967129f02f92f582ba2696a958c42ee394caf0139945dfc083d4ca900ab58442095bc30dd483b926c9337192e1c09bd0e8e386389e896e803b5df5c64f662a4a43d251ac83d578b92c1a863b5b3d23e2f6b705b8bcf05de701e9f1c6f9e021211965f654226fcd5cadcbb393a28edfae34252c74ca4e4be46181116e2f9f53b4ff77f1cc108c0d6919fda26743573b0f82f1671a2ca0fb960ccd64ddc15c152b8232527f6b60311afe55cc130b01c31b85f30b585f69410c9b17e77c08ac005f16873cf3ae6d00706da08da07525eba672e8b6860e58488860148ffdca0112cdd9519db09f83a3935044d8216cc55c3d1603bed2f14735413e5a43438937e9ecfe1833bf28eb4d20979308826593f12eca48ad6a0271a821bd2dc21735330daf9a9be4a5a57606413755f0d1f8e9b11e9b7fe47ef0c252f83d5ad0c7f05434c582ff5d90ef192d8148632e437bece15a40546829b4b11aad6de0a2ea67b61405a2d88242c357bad8ca2cc388ce18acdb974ef3b4bdc17f3e9e76d55b2095661f13c2b94387663c0af76e8f45e79451d865e6dc8ec8ef0a3ce8441a46bad96628d2b60d614cb5523bc2fed4d111ab1a1d41ac7fe45d3412591458733a3c7d23b65cbd1fedcd0bb40d6b4a02ba891c71a147143d50028fabb05bf1d906bb5980daccc401eadb35915221660647c3ae8fa23928d7758b7ec530aed51462ee49bb8ee672dc25e78ee2a08474bd8621cf28d022abd4ba9fdc137d0fb14d867c9eae2f2fbb554eeccc9685dae37b5e93d73ff667b14f09b4b435b2aa294162a3078c8d7097d4153bb1dc17cfa65e575af652b341f11e2d6fd954d03745937c35a7f363e650990a447a15f39619f257a5ccb9a19160edb73540f58f4b06461bf96ea3e28d49c38549adfb74682d60c1fdcde7c05e363bc0d6a5458c96ec62b4e90ef8460483f33725c047c35eaadb0849461880238bd6bb12587d0fab39ee58e51eb0eeff26342354afe03079a6091de7b3896e8e0f42bb10798af7a2d388d581a98a5bc42c35fe986d971da53ef0be7a81128a97c9615d0b1b99403a6109b1c0b12fb356bdcaac5cc30152ad4ff1739e56d8c508171abc20eae9c17dbf36d72bda3c945439beded8c631beee7193077006c6d339e35d09c407619d796daec5cea3b1d1af56174befa69a123af057550a1f488c0c9bae4dce3726ab727e83a174cfc5fdc0b3456cc06f3eebdeba42526676a14aeeb1807be8f25e91b906157d7d01dda5be09f893dc066a554f865cbdb16bf37f420bfccbb6db6274a82383c6cc0c2663bd200108c7344862f4690e92d7c8f00aecd31d8c46172a1e64af0e72fe9f3185a57a71e814ad5f0f0d33f7db151018ff3cf7144c6ca1b5654757449ea57d9c165b0386105717498d620839c39f85b1d01228153bbf43bfe1b51ba9718f0108fe1c0a09aa23f9c3d83326a65d280bc6843c6dc4a3aff32e86443923dee6e21340fee839a99425694bf86d3f27490e877f87981767acb3c407200097ac2108093e6069b0c65fc1c8a4622d8f3553ab77213a68b8a65a53b2ddccd69111dfba6c35ad64f6bccc50c664f65cf77bb85edaee120162497022348d864873679d7c6991f3ae7d445e467dbd9dcb45927c7dbe358b5c31449ecfe0d217f7913e83497fe781e4d22554577eb1ad0b4162bbb27f8a32cc61b50d4822e493bb0749448100c30102a10e50ad2c2b443654187f34322280292a444e6a4f5e38a8809d0f470cf721e29b46be30e59018c863b9e33826395679098ac5285882fcd6b6e90d0e3b1cf3b47cab42aaf44111c25885dcf068e4311efc18606a885415c9befd0ce3144f427825a8937a257d529819a237434fd7b7593e567778962b9a195e0b489f86417d63e2987306850dc0b81511acb5b605d5831861dd6685b79b09fcd3286e7a4124989648dec074f41cdefc3b6e6ba2037b3956ba12766682f2663696e53680b2ad68ef66a182d721e95d4055372b9b6f0cb20a5e0a93a9fdc03e8ea9d90c36e5c1de148378cc8441a175f7fa2b132c8739abd90976904982db0164cbb92ad3d2a8311ef7d7a02df5096383aa043cfdadfa0decbefd8b1aa7be45cb49a9b43228dd31f45018d17bdbaa7baee1d7fb6a403536d288a72aa4a277ccc6c24cc44ec1ee699e7ed54bf465bcbf458b6b5abdcf988adbbe7e7c0781b7e277908ff99487d74ddad48ad6b0f1fa8b4084ae851ef522b40ddff9c43f01b1d2a7247ef8706f58e397a444afa382ffd05cfa4a6c3d3d3e089d9e9430b8666ea02c5e458deb0c974441e73008e08f45f678334fde926d4bfa5c3e981e392949b415e67eeed162ec6e9c23a1767f33f74b7518a1868f7988f142417575a151096074d80a48b25014be6e60344fac207ef408a087a7f76c08de33b718128de5a81cdd11a3428eec14926c49d82c32a9198c5d237e62ef6ab5ff73d6e746cb6e5dd22873f7e6cfdd19a9c3175975da1abd0f50319c20b78fc1134084460c4aea6e687913fe590d1af85329a8a8c48aecfbe909287b1c46efe93b820c2da46d2d77c6c39ef309a2248c219771cf8a138e448ec2a5efcb89f01044d6bf12da439636671931b1cd53eab02d753ce8604850a5999f4bd05547d5cb57e1081290865be4854ad50098b2c8214c04a39b7ef77d64fd9c83ceca301058494a1722bda91dbcb1ef063588686c82c4de671fb2e2b093e40ec616f5e640423f96bd3fab2b15f9dbee2000294b473e099de8447d0eb5309ea2af755c6023379bf91c3151593bfecd2c0cb34a8a97754f398b8b0a4bbd231c0bf30bbffa1b0c908dcf5a4696a517d7f144fd8ef82ec784225466c9b15f57c69449cb13652fe15378ac979f895e06751ab406b440662ef70db2132facc6ffbe80542c9059bbac35650ebd7b222d98effb024a8f0eaa81f52dbe2a46282a76159e1c2bcf1a6cdf3511bf8967aabab2e6ceba80b5cf16aae7f813c02d7b6890bd403533c24ab3841425c05bd644f4372934c403d37ce0cabc570eebd8c4db011860c4212206ba48589d8dcb418827efa7f311d2076566114f665f5cbc00fa1085af326100154a905e6fc322015ebb4d4e0529c7a703834e7eb6485dbb687dbe2249e701a27bcf42b49d7e92ec7e7cac3c53d4f82e89ddd5273f96d4ae5264923e4c91c049e46d16dde1ff21466b22012f1359b3d69000d99dab16ba700c752888dd6d8db2304ea5aa4994a52aaed08e5a6682f390e6154ad1bcba83d5688e90f8d41da8a872d9c077a97247a435b358773246143daa68098731c5d8137714b22e2454a9e8c27bf21a4680e65f1474134a99c1242c5b66e81dcfd3d2f451213f6b0897d09ee24f6b4d5bb0913467002d682a11170fb622f36b00406181636404ef7748afbfed6e0e3433125871840ab13386f79c6f3080600cd35bb9468eceddc7d8862506245c511ec4951a96193b4714357307cd78b18c99d4663fb0747c57cf23cff60c8149f56544503002668dbc16f59f2d7d01928626f95b92a35ad016c0a075cba16a5ef86e24ca79f634d3a9e41159c39747a101be661771895b37f7bb58b171488000035e427f5b24bbf7dfbb69d13685029e18a0ba5222d2994a44521865221ca64cc482e3911c8f2fb71184964c22cb39d80e638253fee90ecc7a0ba82215e32f395ed11b2dd140f393e53040ceac2a926feb8311a00f26777ec2df32f3670e486c421167a83381934a6d17848171a72f3feff6c20b339bf3764e2cbe20d2a801b3da4aae68e4994523288bd17f29113b1f26ea448002e71e267b94b2739583a05d7fc32e4c33d1121d2e10d2dd344af1e97602dd85f7215cc3132602c5540eb16d8738bf8b3bc80ebe629f16a887ffab31b03d06a7d0c05d876aed78e7a344c7058f51034e099ee11ad5c3ac1fba0e2300978701e420143426046c26309d6905509ccd0eb99257c728ab8aa077ec3656ac00b6707252557dd9fb5b4684d6cffe08fd1c3c7f5df976125d71fef7918826dc7f94daac9dac60841e078217407afaed550acf9acd21a8621087b5686134d04bffb6ee1a3979dd1fd0080b2c0c4d84af73d03f23d1538c82d064627e329d4b3b33c1763b2a8cc4bd944d4ae0921cdf0245382bd5d3b1c3b18bac82cb3c12fb9980eab3b4c4c928597dd39ad744586c2330d7daa3a51eece85c80a38db0c4d47f71d1d24474b33909a6d13d33944ee01303536e3d3e0580077c71d72ee432b3170355bd10808b4ede9999bd2871f99e38bb5c818a2a2959442d12cd031984288b41aa1474d06ea129a55a5dace3b6319195f370d31d9a3099e123e2be5b4ba7e123863f99615a26b9b128f7511dc4f8591c8db1142bf5bbc325848201de112bfadd85365c70ce7d2c96ecd8334c2c6efd6e3543fd153434e9815a138c1243d61432069b95d1372611802edee333960c0ad5e301285d1a02c19cf4255aa48f20ccbf0b7386f0221761e3463f442ce99a6d9ea3ded47bb8e9d246b5bf0a86eb161b233ebbe35414cc6cc56f6f912b47027e02caef7cc296df0dd66c0c3c83ba075149a27840610100fbb6e45273e6b6fef9a5f5158bca3a796b7c2d1ca67d021db0d13f13f5e07825aa682520db76db087efdf9ffb36f05686f3da6cf9ad6fd4689fcabe50ca238777b19f973219e5870eaad83824cbd7ef103ce2f584341e7f7838402d5d572cef013f2a6af1b4b52cca8d062d4d87509d2dec2857ce2653b5847a3eab69aa0d0daa24783982f44934cd93c1d56a2746f95859f493ca11f0e3f2cfa36e72315c7f1cfb46d40bd5ed9075b87814f1ba4da58936c95be06dcb2f1c3d547431da185f6d9615057215424b1b562642d47248563259222613ff2bf6da4d1e1dd2073dd0fd4834c4d6eba97da2f30115dbf022107afece16ca59efeded5fc8e981159c98c4f4ca87c1b04358e4c50d9469b2ebf56e15d2d2fc31c34213dfc4e2c26b516c3daa0a4f9ad8e5a5c8b4a9e951e35d3ed9c93cbe743c8ab1a773c80e5ce7142a20a88a3fcb4789d6ef10bce4071263b815777f61adca04903c39c886cdd3cf7c536c81ba01b9e39e2eea62d6c85ad44233fe821c5d9839a321bdbb0c6da9b40308e7dbb65ad02d9a64c29df75d5e9dd2c75615da99d7f6a41564d1c41d4a6ee973c68dfb255659b500f4c6b31961e60c4be5903cfedfaf316045eea71061fb05685456e8edaf4ae6bdce5e2bfd276d6096229136e53f3d003c89aa71150557b39b1d0607851f268a42e83a700117b927966166688129284d107f9a8c54911232e573ede366ad571171ba30952a23cc2c6aa86fa167c8c7917cd6e9441a50b3efce0c3badf71bf17460bf019b4e658efd9da783b58b0fa85213adb7f294795bf6fe87614a6e59656c061ab81525528b223f063c15866c1639126c0ce60424401591fa2718e3bbd620b8ec0c1a3506cdcd800a017dd9f5631cca001103f42a98ded3ff7b635544983da1cc032b8b2ff8aeae8f950aed424472c6922a141b004033ae6a66e80d3a560f3b25ca02c4395f739ee76b65d5f5dc1bd76f449fd6d31a71cd8d27500fe35496e7c90d543d1641a5bac190cea8933429f83d10d86c8b297ee817a4f625667ad0a4df32ae5f7d7e42f0fc388ac1c83a7a55ab5377a34e74335305145308f017baa3f01e0d7da9f2a3c4c645194612a7939ffc06d4e6b633204dfece4b7feff7a3302d7067d57f0dc2f1c92d22f7371f21387146649d900e79430e61201ea26f16190e7b23a084cda3ef38710568716e1828c30bc6ab5497a0fed01fc18f9673bca9c423ec9d12662062c835eb1d295a61b86b0699bb7696158a55077e55edba4606bbad29cb3dad7d61ac94c7b4b8d68218c25766c0162021720a8711dad58e3137ec5c787e71e39824a626e6b5bc45b44767752935bfaffb5ff2041c77d7350daaea85dc0d5b3e559a1f595be77cf275035c57050cd282c2289ac3ecd780e13c9634237d14452ff5980f1c8cd59129ec947b7bcfc14c833a69404a4fefb810c3c90d49cf4d7a20fb057912857511917c0076d9b114921823166dcb73cbdc6a9793162531fe61d22b95a7f51d7bcf4c16ce15c57c0c080974d1273551ea4b3a20f32627fb02630eb71ad75c0caa82a952eadfb7432025c3e1eaa235baf75936ab341448a3639a22e1d7478307b7609befc96bff395b134ed46e84c444311e7e59b21b858e73c6a189187eb0c587732c1dfd1424b07a64825a2e849ec95f052602e40d3db65a74bac04d965d9dbe1a7d69b9a713596d0b9109589d303cfd13734c518cb136cf0b745780824c063abe94da2030f8318648862b5e8ed633947c9c413f6494473566420ebc0b2851f8ca80d4849867d36ab36921bca6577421e43f5bcbfe9426a4584baee3e862df16efddc897c74923d583534587178b592c1d5808c9a340fa8f6455a0de05d79901244ba71234e5a8c54bb55978e16760702e67090975c35c281c1f91af2226f13ac16c8551672e342c68841dc1ad687073233d4c43c57706b0b21375371cc4d1c070d0564babe6b5fca49ff301fc9e834b0aada02c5e56244e30ce6bb97d0f999036ab8cae735cba4b7cfbfe695c454ca258ce2168121d214fd00a51e7c2ea987c6b50d8337f9505710b001a12c7af0da7537d692e74e93f984b364b26771cd2c5f586a43b03951c7a3c074a9b113b38f3b1c09cf367a9f0945eb4e641a8c1a7c3d91d2bbaa0a3088a6badf5b3f71e4c768408a3073dc809c123e01d1c325669c57ee0d35485e395ee628e60c60b5a4549c7729c7e7ffde6cd19dff46669b3c3e99be0282ab2b1126c352a98c262e608190926434e8ee7fedaa0507d6e72bc2314c5e5743591693ce3f4c128c19887e0ad31fb8b653771b2b54abd47e03d135baf6db7feecce315f493cce2f0c2364b90612c2e1123230b26caf1a1e76a20bf05b775b001329be18ebf5341db6e1fec7ded1911594c16711c6edc8822b9927e9cfeb10e16b64bf250e255e82404010108c5e79c0e9208a22c85886b9eb653cb14a3db395401e0be09ed8e63051b761c0127d8f741379f0add898ebc84370fd77c1ecf153a20a1055f3c353f558116e9d464869e05398a5362741780eea0a2e25330a2c97836a46adede1015a60a3450d62a5493db240d0e9074ceb3d61a08017981db12c3268eed50dd489e3ed72b49cd2ff8915689f1a4c43c5a12544eb17b03681696a7280c39f19b4f67d111000fd343fc8c63c290b694f3c1fbe9b54aaccc1043dd86910a603464d4573ceb4b1f3ce15146e0c2b3baa9cd910b42f56204286cd931b834d2b43373a29b6fa5eb80d092b32f53983ea42e744c3adec58303a2e79b29954c1ea11c17be2c3c2b4577fca347e2e3ae94860b77d092767a0d7ac56a40d88552ac658d19ed00f31bc1c1b9905530746242587a3a9fd8015f48312294e9494d88fa27620a22f81bc294197384804db688b3c1bff37854eabb9110808715006ad7a9c8e4aae3cbb66f10dc454800692265c7f449d6312be4222b5e3e2628b6deb2f68131b3145b81c6b95434d698715eb1226459cac362b2af7445f630f2a93ec480cc3b81bfa24bc6f177c2e60174f4a74d8c445e5151b4499a03d40171277243d06dbc5d1d064c4e327d158cec2c5cc2880d3e4389849ac5663b94ca976b991d68fb600651e62534aee4244a8044d87015611e28ae08211b144fa8662ecc0ae7d05e42302492884c645b76bacc07d3f141b56d9782b6d0d47ce7865cdd603c305bbbea7fcafcec2efbc4c0a8a8145cc0a2aea91a8717ca74b0e789c3e6347100126175a3b3962cca3ab08c7d3e13c051ed3f77bc39e0eb6781b7c0468c020274f56052787cad6b00b6309838122e651aa6082fa78f5f468ad81c27cc1fba672b8b5e51da18de77271fd3f276a31a2735d61b50d978684df9b33ab023e83b36c35223761199c003113ea1e456369640814952ea99c279c9373721cb49491741a612bdd113225c66c05fad8d01e00902bb56690da46344ced576d81e5322509537fea6c36048a7a0c2447ef63679f23ba7b8233bb02e00489150a6f3b3dbecba976c05479ea8b949d4865a1910f978bf82e3da0c2486a14a3aa69d8d86188783e7bcfb26c621f07f35cf1480e540cf0f63a1a2c56db2fff45bd8511588b4aece27319d97b0e429e5aa5d3ee7fe13d5c2ff69d54289805a1612a30c35e6ac093c1237e25bb5627296d052acb2c9e1ceb04c2562dbbdb544dc79ccb13249ea9dd6652117e67bc88c530e0241a293e0577cf91975c0cd3159366eea876346c3c730482448f43c9c085ba5ee3e4487a0e3481ef8acef9ecf26c21074c2669619c975dac97033d0e8f41156e2dc136c7111a653b210f7aaec3a00eb8d4f768e595c087163366704bf9da2d901c2e59d011d7247362edba989a0c0fee103ee00a9a7979d5de433565c2977d641ef2b53c8679bfa79ad2f7e93910137945c7dacb1691d3a504ebe826d6568cd18dbd4b09a4393aa5eef59da91aa777518664094a302d7def6d91eae00068861a6a4e0dadb30cccc2b6921121fc8c4af60febc7dd2c6e435ec19c446a6deef9c5000a2464c6ce96c0ee46dc9c7cdb05464e2ce575a19496753ecd83987b3c93f51919962b3195e33585c8c4df5389ce16b26a0c210fb9cc004569f456689c09d28daba2bf045168269b2d9da4cbe6f6a47573b14130adac730623ea4d19b05080c5f665e8173a1a310cdcba25fc66e7b84c7082611a2848bde9a8285162b82033fa96ccc8dadf3413feb59a44d235a4594eb0d26675684592f6f2028c9f2ba5e66810aad6c25ec8408cd7a2a981e215d525938d5aeb6b5b3b390e2faa109d16935e9cc44e818494830eda4f2aadc7819cc94b2afc2745ca9b3e105e4e8ac29e8ff1aaa16be53bbbc1e94d0ce4b68c388b88adba45ebcddf65d30ab90a7d89151d400772300446a21523aac9cf318f7ad6553d49cc61e494ffbaa46bdc42a249386ced8b53d2fc537222340333fb5e16b23defe96b0aa20110602acfb6b42e1886d89c33e8d33818c7028f41ed034d356dbe8f77db12c2ba6d55b6f2fb0ec2ad868e61e1a9abea62e7e9ed55923a5420baecbee8be368087c1cc8714b93e1124c5666d63952dca5f4657f249baddc6af4f5b8e740979505c15a236815524c0e973b553146ce727bcdfe149d499459e8869021ecaa96c09d0767cc2142792e8ef683885b39139424cee3205fe62bc6f0aa2c4c73a0ec3fe6b6df201a4b743af57ddfe377fd59268a14b1f7799f126adfc03095638fefe06716c10b5258e67bef3d268070d14916d1d7c66e7eed9cd7d7a64edbec588494aac36b1eab42e2c3bcfaa6e09174e4f87307b38e9db98fbecabb42db94bf635f1832de016132fec5c5f40fef4e56d4bea65ccb7c04ebc47404c6cd995ef6a54adb43e4af6793c798513c10c490cfbe88c68e0c4f127e9263cd1a92ccf2693313a061c908ed68b503527c96c0d94bbc689fc60f12a529f3f672616891b5dcc6f489033a571b8e88f589c6383f546adca452bbfd3d3527a4fdf14fed1c175169559964f8ac27aa2257fa5644f32e72175cde91fd69fc6132aeb8a14b831ba2da7deaf159442509f34ac8b84422a2c122176238c235549e07103d30537197c5bd55d928f52ca147aac94c7eec846cf6985239310c6a5c17200d2422f6b724858ad113c50adfacb1c6709d05229ca8ae630c4a585729919ff50c7362ad0620e94e1996f04ea2713a6761fef95c83d4b7cbf7c4d26a4721e10715c8423366befc4f01a2349da7a1fec9215640023e1519a57b988c60fe4c11dce5e99f12922385b5743ad71d14123b469f7409e0fe8f957942412ab48e4a9c1d6f381861083afc932b710ff069cff1e470a96abc4d2271a9b23ff22a585c4abf20a824574d2eedfb5fa1c3a56e3cc826fd7cf0f9f9094a74a083ebeda3b95641e78b72428a89fc7785043afddc3421a690066d27452ff9aeff9e4ca57d56509acd34a9160ac70c1156a2682b30e6904100ac1365e107bed84b6c0d7feb747822ca2fcf3efcc48f43972ae5c2261d01a24e62301b37069e3afa387c0384643eef2fe0b9e239b4ab44c68869e30ed057bf7859c08b8b9ff420a0a6d6b2f1996b18ac003da9d0cf18acdd44a5e6f08c2579a124a1fef977fb2efbf435ca65fbf069abf4691649eeb72f02d7c12976a1daeaf00f0b30d0c5dc084fb4553d8b28056db895b51dce5194d1d676c7dc46566b4152ad6d5c513ccf8fe19277da874d71e58cae2a3fe25a3218e478744bdb2fd7cbd4334fe8f29667ff9a61eec9456eb24b0fc25d808b22e7f6d6849d9adacc4d6c8fbc89dbaf02c06a61f783e8eadb1ea39eba30e5040dac0ec555e13ed8dfe590c008c0745a83b7b32d9a46f9773bdbe2a95fb96a8d5d2edea94015512393708f7b99f04ac04c31c4c2a4f51aa51ac3844930d3766cd8079ad56d7de2fcf61a2b1c84594b6b91c58bd37380d2e4abbfd10c82cfc6731811eb93e253d26d86db58fb9eec2ff3675e951321b7ac64d428f5985d6421b6d3618d159e379893543bd88946de334823e3af6f525c4972dd56f1f4b658c04ca5b7b3108eb379742d2c52a342362124968efb18e627671b6114e9de5c89a3584190a9a547612c8bb2ef7a8424757d1abd2bb3fb70a537d44b1cb1e666475e93f6b443677fe669351e8830fc56622092e0460e9c7b0345e45513abed7763655d44dbe0da934233a353b438eb70aa291739753fec79b17b7af67a5b2e978f6d42aaaab0d794bdf8338c6dd82bd2440a4a07b9a7e5cd4657c34130149c428664607c8eac8560b2faf9ae910c8aec63a623d93d9266a7dafb11d5067c0f40f2976a8582afa64924fb6e3b5e38baf2b80c496f4e3e9f7d8258fd1fa4d817ac9910835181b7b31afc0af2233d1db89a80b13cf28be3c6db99f65e7469e3fa7a5c451682f6fb7e74e5a0f7a4e8e2a63b477bf9d7f9c1a8eece86fed094c97a443a418d8b93ce92db44a6ddb71101a9effafd61f1e4a5ecb6b76b76388cb58d782c268256737396cd41c7f5981938282ba7eba85888307134284465c8dd257a9294e188e36a635c7bf9d08c10d26355f368084edb0111d6337755943ac840ae3a1f64b465b69e87891ce9c340ca183960fac0f3fd697e5ae11f28746c60f5f96622bad9f2547491087b6ea2186f75d66070d519ab8fc92f30ce1560fa3ce69c77d32f20ddffbc1121dffa66506037f688edf92431ab869689610a99239491bfcee6822f1bdb50be68d3a92d94b62683f371069700c9339a9f243c28c41e70e6a2d2bbb9cc2f96b52e889429189086eca5539f072669870c7c7f1831217df0105c59d558aa8c805e216bd97a978f67fd225931e7af767f4d922edb2e2ff0a651ab8eb2028675473cb13be984f8908f35511717c9e8d1e0bfb5861afbf94ffb06c94ae3e179a87ac2c56b6cb248d7045dcaf1fef53908051193d597c25d72fca44255029c166a51a2d3e772f6d5cd0e08225c3fe6569d01ef7c00c93fb9867e21f7d5341501a297247a44517fcffc8ef3ec27fff0cbd1423dcaadbe8d80549712271e7d668cfa11f694184bd0dfea86834a37fc0247b37a07f83982e884baa6627d2535068b5798b49fcc2462bed110590b26a4ca37e8a6a5438c8b6b0694b6e49b564778af8402aeedc72f554282223cd98ad21ea5261d33f78a20ef408a9310e6500ed6116c0ed32c8aa558becc934466061589791203e17651d9c0d0556e948b98b95664149306ee82e3662a5758bc79a6948f8ad90d0bdb843cd2f1f211cd426147478ef968b628cfeca24c483b9baec9069261d2aa5fe35443d67318af3d4135ad6781d2f94558eb5ed60ed21e0c52ad871871301f1daa6c4968b00b5d3ce97002287de9a1d10f9104a20a0f82f0c54f6268c70a0dc0716f73fbc75b5c9162671dc2a4052099ed2278fc9b147837089afc35f2efa973321b712f973494c1d6629995a8cd475c42f3b4034a57432c1b21a372b83a58602fb132c3edc154df331e580972a88923dcb73604123331855d4b669569739b6726609ed87e666f48f5e171359e60b8531621f6f76ef349023bfbe57b96b2a0a334c5af08469bb750bbf56424ba53e9fa006b2a212c0cb58b4f3abcb9c5c345ddfafd92f1a9d4242d3ed849eb0347fd64b2ea68b13bbb3e7bd98eaf03e0f539b2a5cd2aff144a53d39beb3004bfd54dd92a4ef71edd02e1f92e496f21435b9afe2406b058f79fd95626c16a9d483edfe2030233767ba2911fb73bdd535995af3f65088f73967d3896c7f23d31d518a292a2a0918a24fea0260d455aa5108ccb8ce48f28d7198d255eb33ac5be87cede16f3f1fc0aaaecb7dfc14ca53cb8a1826e0bf5d2dcd9c397e98cdf8711a8b78155a09995fdfd909248b779fa92874b15bad5824eaf650535afa1f72c127bb87489958834a4111bde5548004fb2b2c907a89858db4fbdf5504474baf96b3f81cb1da6facfd2673e74ac735cce461215dfd358372661f306d89f90a6018fad487662ac08a48cbd52ce3e726804092bab24accfce86e0065cddff1789c532cdfc535ee8b486ef845dfd8598e68c08086125888189334e60b64c5acdf117abcefb7f48626eb797faa96194221d98886b8a2948308d0ae6e4fc6926791a32194335d7e99f782595088c3fd2ac255d7ba820fa7f97361b63736c6ec9092e58ec815c756ccd4ad9cdf271213ef314fe2139b8c2ab8ab301a88f83d649fd6d5317d48f0fd6c13833ec0063b9a3d2122c1c0c73927e4e9b82e616ea41cd275ef6edc513ac495034c6453a9136b2a64167fa7e1208c5b79f085405698d84b31eaa2e9f35f2ae700ac2fe0c60d866eeec321ec709636fbfac26e11faa83c830fca5f8516938b7a198afa14dcc4cb1320f27a97cd2864c494241942d35ae298a5070b12094e51db52088fd06df52138b691f4125d7696189f306778d5f69eb378d888f76c76378c0ba211c98816826732584b4e36ccd712b54948a2c9d0a6923e4a3dd6d939bfdd15a29d576028e002ea5b2f5da4718a2a1b6c936871bede6f97c01f6f882aa959b00b322c9be72b4119f283043a31d11682af482eba698d382b92dda710bfddb41d3e5a0a5a6110d58ea595f03c46f604985645c7fb00c7a0e268cedb855e2a83c44bcc1de0445a82888d5fa07ca27cdc529b8a522e5d0869edb4f8f0f0bc5bc66b18e785c9b805085ac4866579c3d353ef3aef1c493b17d194c4c93c11971091f84eb2cf5e12b5edc3933738321043cdad85e25e559c628d18c884f015a4e31e83371aec50d68a52e82d8f7ffd5a30597805ed201fd2a268d231af0360cfe7ee77b8ebc801e8f3d9069088cc620740d39a9ec66c3d55de44ba3311f0c0c3d997f836e650adaeaad4c0d636222d9af3ac383b39841043044ae7a6ebc21ac4727fc58806776d48ea6115462ffcc47aa27d9f7615923ffbfbf266bd7e348454859bd16abe15f360d8f1baa9954447b9f72d3a342b2bdcf052044ae1e5ca403c011a1bb2164a1115e02afc985ed3d48596723fb5a905fc7394864f02b88341d5980da87865c7f415407dd24cead9fdb014799b763653b404e2b4719ad164426e7523473deaae54481c7183c25ca6852fe34897033d11afeda232f86d8dfce04cc22b0803b64fac10ae0cc2d49fa13651dc972101d11a52f732375a7c4d73ff8cd88e7e85546fc9720819ab37bf0379bdb37eeb433b8b5962f6e73d8a355b766944d2b7d1c9c4b444b17f3f6d80001949d5dda926244af2a41de1930a02375476c37954211ff04a3f91dcb362ba78f5d001cead8ed8f75e7666b723d91cf90d8cd470ca123fd776b80410c4f309f6c110df84ee160ecba8dad3b7557e9edb303475af673d0275df206ce474e7823abafde1540a16655fc0cd0211728ecc972ab0d242fb0717763d291d58b647fb5aad98d9f9a95037c128954f54eea2bdf81ae066f8538216edd0d78d2c218e924dfc631cce150f3ce0d9aa4634abb68c2d4be2554e80025f300fa03d9581e6b0df005bd6d5d8e010981f4ebde5e8053f3ef0c326278c777a9c3f5dcfbe3edf76c8bd7a6bb05d9f2ae10f46eb7e2311100135927db154942055d90b8739a5df17314956243afa91112a01d7283a2942cc394db810973806efadbb63d6b9003e91ccad622ee6d41a91ad659445fc3f44bba9b5f48646ec48782b14936d02f02cbb3397f70ee2d9dc0bdc23be46bbdcee4ec0f3c064fbc5940b197315e7b11376e9fbf5922c1d6b927afa24e61e6e4b59d5868644612bfd231a8d673089050996e1839aa9c7a1ca9f0f01295c7dec2cab7654ff4243bd6575d22aacf0517ca09c5748c85273a99db50232e370f8a3163508e267ab5866ad6452f85a8487c235c08aeb7e5c72d92d57b70ada96d249046a14634a1ff27e1741a1c96a7a932890b544f115fd355527dc7caf3111dfa478bff6630637a73790ac382596002ceb8fa0c6188f4f011527be1d880410b0751c94bb00f577c16eeff0f5738939610c7ed38fa77078e879480d2a8f6715212161cca47675deaae401c75132766f1edd2709fa7fcb8be1284e40a4996ff4d13d9eba4fe3b3a4fde1b48f5477c4f0124617a835e53f9ff27e646039029ff77afd80fcd81851c97d4561a06a0e021775943338c7766847598f329a6a0f45c42c6ef99621c5af1e96ffe70d40f3a0b80a5e083faf7e04fd4f0b08f568acebde7b0572b891635e0cd1ee98b53ba15f24c5edf152aaab9700eae722896f5703b20e011a4f2738ccf969d4f5694d762b925a8b93a1d57a8a91c41419bd23c62d9a28c48b3ff13746079354f17d6815fec59bd07099116240335a79d0ba74f6f7c1998326b2225188c849f3af89ade934f763ee2e9ca6bbddc81c3a1510840df3b24d1624d6354ed10318418e4c1d12420a91c76c68bdf46baf1ee459618524ab4de9a41296e791e49915248a4bc9c2454f8223be9a11743c36276b25cf4faac3d74d2171f63e4dcae9d48098e24c9904ce446b64b4339225f523537526700f85b66e391e04a8756333586cf419be957ac7e5ec6e16669427189ca21ca34fcf70cdc7c2a8f31c94a6e05b60673f0ca6395cad71185936e064dfa746a037a7c567407ce27128d35a87c36acdf996373ce02a04fe71b19e7d45e88d1f4450b8d25d98021029ecf0dfc41dc352dd5377ce488ea2721b4a66cf1ec55189d50a972667f0ee4cb3504a7711a0cb5d4c4908780bb341dfb767b002e6ec7ac289e10dde285c59a054e82916229d798134f058808f5f9c6116e895a676c30d5c41731874bf0c93c1201af554aee52231471e887cfdc18f317dfb908fd2cade1cc5e81cacaa0a457fdd8968a42b30b9d934434bcc61db27c386fe8bc7c00ea36c56965b9f96c0dee97879a67ea3e73a216b2f568cc8ac7732b03141376fb6cea78e03eba834939cc38aa3a0c84bffe6739716b79589e0f6122284b96baeb02452b5b76c8ffe4200943a10297755e8595a68facb63959a281d9f44d16f4cbfcbfbb70218544205d49c29e0df3e302621b9fdd8efcb1a741fd46d30dc6de233d602577b616b49b709ecdb3954cdf9032a59346b0239320d58ffa20d2e013d6b0ef4f8a41264e6af851ee7f46fe5b62ec9f2df684edc0555d8cc01113896231748e61541992158f735af641ef7296d6979229444e4c0815d5358a94826281944f0659a688264da578b18003f7ca2ddcf9f47c4a89e61f117146545901ee419aa9e1c78427b9fc35c5dccf93b28def3d268f609dae10fc4ea57ff91a81c0ce6480fdc2e612e4109d7977ee33d763a7767f937f2c79d80cc00ddf2f3df077315c876af8a29e6f103ab791a18914d2cf60970c2968c184d38a998ab1dc9c091ec95c5a71ff89884efc42f85f6c8558e5bd3b67d008f4cb3fde01953b2652fe16b682205d700d249e6859655e742b620354631aa6ea5c9d88d6f6728a55a41e8ebbb997b9d6b622dcacf0a7665c285978107fbece7af277881b73e82b0e90beb2a28c445b789ae742181a06aef6051e28f4cfe5d05c79a88e6d310cc019ef3d227b126bd8f6765e7de0de30da94f91dfdac3917a2e3fa2a19d13b6a9da74a7e9dcee3ed4b7daa794e0eb91f126ee9433081430ccc898d31067a4080f0ca7fcb6f598514d6a94718318fa46577eaa0f45a605f14231173840a3919e4e1d3f7cc6812d6d6596b702738f76d75bab6084a2faeb1ed8630d41071ccc705dac06150d7c262a6705ebdf71e5a5b8abc76ea2d53330d345220e19994da782c2cef5444a08a409236ad95e14a08b39ff1333b9a26feca38d76f953e480e87f7f7bc2c93323863dd2ea6169109824cbb3b009128f2df133940beea3c061a6648b2944d9f30a6cb5a81bb212260aeb59435aac706f3ff96dae0ebeb125a0261b0a123e412a44897c469b840a55ac51b4603147315ec1957e3563c679073d6edab1cb98de8fc254c9204c8dc18e618eab0ad37c4faba786296acf91e4babbda2df8cf3bc8d1ec547b0ebbacd1e49584630683391c714466ff7574a4900f5f9d51b4f8006347733de1596b7b6df8ac885ba64858e8d9412699abd7487cec8a41d83b2df2e8e81e40f1fd436625baaeeb50cbd8f1fa265e87e3c489cc0b66b8216cf38128eade0a9e00bf7c68bfff3b712bf832085420bd5c122a1fc175a06253948f72171221aa2dffcc2b58f28a50df2e55840441b211e50abee33ffed238a682328a7f6cd4012a51ea050f5b242591a466d70974762f0fc101747cd0987949848e30ea59d93570f3221491084c127682d18cf98c4b8e3f110eb1f51057505728ceae23ab5040abab6ad51eb68a14c4dc2326a1c5a575459f436baa1265a90d9c00a58d322b99c519359b764f3db6358fa8c8a9b310bcb2bc8ff8f959fa6e3748a931e6dd7294ec5db657528ab0a999503855e1e20b98302a654261e0bc1dd2407a9695b278c19234a3cba31fe60ec8c4474cdfd0a0707e3a95d0ad1d128157cfc1c1ffbea222f52cd0f34b4fde233a175a3cd82aac86083cc140510fb1e1c8f01bb21cb57c01e18ac8f00530eb871f52b55ae7649d64e5fff0f88926e740d0c993d1540a2bfb4e8c9758b4ef6cdf7567811970b4e94faaef192000200b49888c862fc9d65bad7c6c0f8d87be27f50b4be119042ed4784a4317845436190388670b22a93c645fc0657d2f350ea1c239a2a90443f74ef3550904e785cb362855850c9969bc34c858224bebc1bffe5242f04ec11ebfd534bc5f88c316c591004f1875f2bc596889ef0942c06d852537a9570ead758f490ca779c5988463902df32a49454cc655ea44d586b321a1251b42e1a02816808b58edc664ced8187b5876a73217108fa93c4357a00f689542be9bfe050e5ddb10e5e40669b90f7b5c8c86a0ef56f0cadd6374040906d7048b6012145b3bc6419a02f30ea8ece23e602c03b1daa205fec288fcbd07e88dbb8be62293ada3189e2a807cc3ebe94e2ec9d3818a8d4976016738815d960e783a10d00ff426b815b541ce0b2b34400c4c501471cdc8eeea03662ac4a7b9f5a6a32ba6a21580c258e1c5b76778970a2c897b767e31073b9fb804a268e9f18a3f23d1a8c91fc606991c664b14206c74acc62c7cbc5375d9a0c59fb9e42f1c4455fca840e2f653f0cfa45ae86931b4e3fcbb387e74e2548143033ee232f28717167a03ceaaec66557faf5eb19205770738e286a51f2b76a90aedbbbef373c06b09cb3a6f7689af6661a824153ee5a8ce3b067d6bde74de6a9d5e9474ef6ef39adf409ea131dd2681a7abbc493a400ca1c41530ced1e398ea860cd337ccdfc357ab9fa53f29f0bf1abbaf02e6158d9cddf7e211dcc4179e5f1ef000567bad7fed739d7c074384173f3d69dfd14be459d8f00ee81d1009d568f10e0702eb1009faccebabd0def3077dffd13ffc61af309aa88734d869767b867632668e8a14cf8c9acba869bacf9a37b5c822b685df296d8cd49f16f252f3eb06a758f882ef5d599e84d2d23e8025367afc4dd6075e6f59dbd1120defa08088f618051ce1756100ddd5e71622b27b3aac1789dc1bd4963b3b54596cef50f64795346f39448c5a47bbf8bfbe0c01c33b31ca57aa8bdf3b98505f5eaead16c0927f23bf99b983a3d84212da3d3e8571967849b95636df66103e9f0a7c6056def0d952c2d53a302f41ab2ce398176e8f0837a3d3351f8c3f218e7da70db13b34611077651bdaa666f426f767413d67f64cf675950af654987ae977f8198c131c67b56ac155c0e34d24818464092c39eeb9356a0b6a5f1864fe07582d3d0f46972f9a0ec46cfff0f11db38cb3f3ea594fdc50ba944ffdb0daee7477414e7588490be668d7f229fcb6fd50ece42fe3733e3f1f7f59c2e7e5101f3f60f8e2a750da42efb978b083f1551321e91877adddd203004f4397c8c3c5f4e97935f40e8fd9c63b5364d589d3cbff9c97ebad6b8af2f19de8d46978f817fa3860dc069805e1ad075f56274db8817641c0d6f3c045a877bcd037a0b9ff61f593c6fa2214e97c2dcf5ec292b215b9faef226a0962e4d4ae7e9bd026de1e034786dfee8b444773c74c94fcf4955561355472ee184871bb0d42dc7e962384375b913b6a8655c41397ff87e46f49b1a4c518d739749ab5d3f641085cfd85a2515073cc30c7ee354a980b7010f04acf742226d45cbcbf52cd785fb69f199e9c5bf243e151efc081b3dc57d58d9dc2722940c771586f0640cb3ef9e20ec5ffadcdd9fb7700a99787c5a08e00de42de32a821562a733dc6fa8bafb8021ad91030fa5bcabcc6b526fbcd50bb9641e0ce6b5aa15cd5c0a9a1424903e7dbed9ea411769a1a338981c2c6f7784dafc972acd76e3a1170bb058b989cca2ca66d9d2a074c606ea56522771e84070438bdba07749a4559cc04bd3b6a9262167a6ea67eb3e61a855c61c4a66d76814ba91747b24cd87199770b8a027c08f777df95c432ed4a556b7e99ed9101c287df42651e99371968a58eda98b75853af3d2970f0c31c0ace6eff6890a5433b5c928744b0adb1feb2bd0246fcb330f26727112c63cb88494a83622835a6f0921a087bc7c163df72b7c270a86f5b059bb43c8ef3f391744c64131e2d3cde0fa4b95c89cf8d91114c117801cfb835c2b9b066ceb7b3efff04943f17d17f7a0055991ebfcc6cb4960451adc70cd6d8199b4dce6c5d2d4c00921c4ef7f56def575acd0ae18627423ed4d2ee8711767ac17159a05c010dc32a429ffa67665aeb3592e63e1d519239471dc678af4ef3b926c30489b3bcfb7df57d061cd75c6ee72399fdca263404ff1feefd9ecad79521ef88397f7dcc2810a2ecedb1d6daad80614c53a80aee3aa9251027e7690dac000b9b8af8705823bbe5cc754c6df5e93dee6f3a0f4934c99be72e64eecc623d8b4a38b5812896e521e6076a59b0ec755a16ecb4b47371c2b247e5160e37afedc2d5450df0a649d8fd76205c45bec967ebdd4df13e3fa89600e6d16bd503e44eca8a1aab90e2981bd846d4a684a5b21a92d4f0fbd2e22bd9a63c336f9148f26568b77d71db85115255be86688ed72fc074d7eff109f0e8fb46132b916ac0aa2da24e372a959676dc6393b5dcac6f12dc0933c637eb223af65b6bb1393f149a78f904396477a76007bb43a16eb655194a48ef810e5961edec68978f5524fdf79367679bde5607fd4090c365fda7a64526fbdaf9ecdb3816f793b871edcf2cc656c72c2b76f7c1e05dbab30071b2dd2f2c9827239625cc4da1ce4e32c474b3ce900e1a4ad99fbde4e1266f0650cac1dffb0f81d83cbb4c7c997232a489089e2d81aa9de5ef42b7d5b04526e9f33d1a242d663714bab14464a8457756144c2d7e4f94ae0c7c2ecdf41a2ba949d756fad1710b0b341497f924133a6a75abf19bcb09430c38df327968b4a96617c2c88aef61b06d4342d1d4088f1a931644fa1e3da6ad3529e5fd332684c8ebc8093c7ac4a88d04666418bc03fd305a54a15fce8eb2bfab80b24c840453a409e419a2dec1b808a82c74d701e155229792a7d3cdae09f7fa766b63b140403f3c674a0bf84c8de726ac6613b4453e53159ecce2e7bdde49ae9b2a441954320364a252da4e8b87a1b1c7c1b3f886fa94dcf119fad71f4ba1af2cdd85fd68adcc9eab6bc3e12689383749ed611ecf2ba2821ed58657eb7b76d85ebd84b3aeaeaaddd31eb59f28d06d86662b8cacf759693f7ffc3eb36721a6fcc3d02e4f301b2a12c6f85f205b57e1e6d80aa5e2c9471157d5d4864b70057c1b134f301fd300fa1ab09f7e8e2056f240564a72276e08c8aad82068c3c670d97aaa626cf16ac1296efa217423580200eb643f972df16d382d217ef0452428823a965e2ab22653faffa73c9c25a5671ed8da07d4c3f7b1d69608c946a17d0049ba97af303da6b82d581a8b0ca62a8157287eededd1e63829209499d20959da9d9d0072926d0e42c3fa41d4250db4ed50241323bbe78d15b20460b998f136e07ad676c8f9b48b76c924c48f199ffbfdc836a1248418c49a38158940a49523ed52b9d02cca6110a42663f1ab9877e54b25c9e0145a0be81c7e65010489501de75b8ff76454ac3daecaa2176662e3023678bc47916db0c6b8a6d510223543e77246a87fb67f6645d9f625435039eedf9352ec56187cee28fb37ad07590de40a67616201d82da5a24dbffd31d051e9e2a960c44b6a406a0cb753718b412f0dee75fb6a3ff8d09ca56fc2c0095726eddff1c610265cf8058d20ae7f517495a0190302a27280b1192d96c133cc064bb797ea5eaec7fe9ceeb3f861e87610a0e0d9030662423d2359e5aa8fa3340808392961ce28f922d3dce0212066619665d462461a885fc6a04b2575a905cdc45a55f8a3cd31957229eb152bcab7675867d4eafd2fce0f1c6ff7e8a3c20c9db430362c0f8c788b7cf93f0d890a608013f4588e55ad39a3dfe07e75f3830f71dcaa4012bfa2d19fc1388dc008b47766718a5c17a8681a02cf52a918706190cd7fb0f5af7db3644021dfd0d74d8f2eddd6f21f250f375969b97e2e93a4530d22c82519aaa3860e914b0571b22cf35ff6622a506565a1a7991f64311724d6971652f92d4a570a90bb4db8011825b77d441984829ddbb6c9e378b4aa26808de7c0f7e2265d7b334ac7b30371a0d7bc7e0c72b94cc9c491f264f2675b38c59010d36a2ca7125a99e6e9ef31cc682900e4ebcaae3172a8119cba582e2962dc58b9b2cd9afa2af651284ef3803be0a0ee45f36cec000016ea3ff19e43c4a0ef8045f20f54abd40905b5d24400ae7f18fb3c2d5e3fd4557394d12f68b1379aeca5faffab70e12ee103c99c71dd40bee6deea798c9d7ddbddb5bc7835dfe3ce56a12415bdcdb43d500412b053b4acf23901cc264cfe3a0e5a569c7744666600de1632c4060b5a8015439b3cc42f87f683846025ce26d3d3b4c9ee597affb28705bd8c34ef0fd3893a65f255d807afcfc1efb14794072dfd3d111b1d3fda6638220f56763cb3b39d6139deee05b6e4b7190a730cc500ac365bc749ffe48abd7cdbb6b0f3c03208f5a37d33d29ca0facdbf5070c7307055e7bfc804152eb8622d286d2fe49de4e73f48ba5f5c6d6b5279d52e5c459cc934c2bc3445682bf5ca03c9bc0a7a85634d801798acb4708cf747d7b5bbe8f660e8fcafa4d10ac723f52993a0b060a9a5aaa1d168dce390e7fe54812ef87d7ce451be865ccaed774db9f48b26ae3e30d10b255f9cc2c10b2f979e12f6a0882682e1260d91044245df4c91ccdf2341d19c84bb73768a2130eef084520af779906ab9aa9594088f2ebda13f63ed0f4ee6fb1166174877d1f94c8b5f30af25ad8849c676d584789b04625cd272056bc63021a9429555f3010baa20e1bdf5bd0abfcfdc9e5f1d65cc0ab06e8d24e259fe54a60cdec343aa26c349795f33733b74af14506910f850b5481b8a66339000c4041c16a0a616b74e8a2b27b34a853b7fb166b06584b07d79b01e95c40ac6cb2f79652262965720529051e0516e7ba524b3b6773605ca99db549e9681cb1c954527f9e4ab229f313a1a705c73f7e62b80b2e420f0c2777cfd19d161d734ca33bd40797dd452ba54b9d2d1dac7f0bae7a9be74b80c0f0984f45df2686c3c4b84258022486c370fa3630ae106a0a250001eb8971c1e8b0dfeaec68ed1097db5698d2d9564a67716aad3029add3bad44eedbd374c8b05af61d740edb2f2f175cb3f0b989e92cd81d131ba63399167b66e49775842becf0689805d51a3c25c2490d6eb685b4ed22941523a6af3295dca45aa7aea466c939e9952f24c8b43a3c400a83ff7743647ebdee6b9f54ccbf50a078c60c6613a8d920315ad7badd3f5afe1223b60ebe4e51738d9ba6591c3827feb5a1bbb772e96425a43ea59b73c1461d03221ba734d24d62a25254d99727b525732583188bfc99153535333c526738d29c90cb7d81d52012db9204158d8995b9ef14cc95784afd4d4541d39ba73317e614805b49841821cd964ae79220b3e5611f62f073daf47aef9a0483c746bd3f1745eb0c95c3be9cecde11d6d56d2ca4ed25cb7d53a96e9590f7b050c75f2513adbe407cf2b8b266479461bbdc1c64938879794bc2742d8cf0a0a4c88a802556b8748550666b4d30a9140ce42aa58832944f7406aadf507cbca0f9abb41b8c6c355aada26738d56cb65aed56a5e4d68e32c8e577b9b5aade6d562b55afbca9ae7aab11a116cf2abb18fe80bcd150dffb192d8648619599ce7469fb95fb06f8a4d662253890eef6c7933ec4587f4f8de845d170f8b872dcb309b9e4264cdc4686dc226318ee48f69a213427615a56c3a31755284fe09f1a2ef85625f9fcb5b97a9da702252c02e08a4190e46a5e8a73ce0091055bcf0c410342c3521c9ba6b84082dcc408512a830c20635f8e921c7229ed84a1f624448e992a728123ea938d8103631ab34e9410552f4b0d4a5e99a1e0b3718498189932351bae02db80b1d62064744984cb8e0882894f4c04005382891c31250a030816152bc2596e8a40e144c90b083104d1c2142861d1c9078c10443284c51225344114438a460490d2d5c129c4a47546981141a8c48c2a566fc5e30faa5e2192ad8b0bf53245d50276b7a0d7423e83563cdff9bcfc58a0b66b05539f221871e3a050c2314d9d1a0430f50ff7fce4fe89fbb8e84feba5d84fa029a60e2031334784283ea84962a8a308102292b30a9095f3802c0f90c742e549609ac0ac6eafb966c12e3c220d8e700d1afd97abdbfb272c5183c5ee57436cb60c9d3dfb777385a5e471cce8673f1b7d161e9d3599ccf1fab08c431ed2cce9ded5052f5d2f19cc481ab3ade85837660790084c8e1d6f6d416c9b9f8c426314e67730a53a40831174c419bc98aae57239b2259c975f2ebd40a52af3158d9a157fe8030a4362affd5bfa5316badb5d65a6badb5d25af9f68e74525b6b6d487728afb5566b5b70eb72eb72eb72eb72e372e372e372e372e372e372db02c56dcbd26d8b79db82bb6d39a2b5460d9b4363def020208868d6a04f286e4ad2d788dc5341fcea1725bcff3c3b9e7e3d2e1b921146e28d594681c156399511d6a27ac38af06749bd5cb4a335b25f8036f9cab9dcf21e8ceeebf5a95422e5a107a01723d8ce6c122bb331d885edfbf3b940d62dd731dffdea79615fccfe5c58ecc2ec8fa517ef44509363afaae5964677be070fa1729d55e520e6403e8e39e80a2184cf2542cfb7df854f3c85e7c23bdc73eade02f5b3a9491275fd497f3669816ea7aeabfbf34f12eb4ebca46199a809ad3e1d690f5b67754b3c46bb6ef98edb9ea5a6d82b20f8c76af523f306d09eeca26f93b90cd965cfb7b11c48d5517b58abb3b9b779bdcd48b4496ae3d941ebcf6e11b31e888c6a2fd7d67fd8307e36f9321c846318089736548e774a36f9b2981d650cc8b6207ef6349bc3721c289bfc3a0c23f6cb5840b338e4cb5e6866042352d280efb97125fc8be1b269a73de18ca15a2dbfa8da4772ec987fdfded46b71140fcc33e7791e8b2f30a27c9eb7a8ebf320861dd3e90d28d6c9efe365486b485bb2a8a0573a79eacf635cd8a756ab85d49f9f401afa73f0ab46faf3cfd3d29f7b9922f5e7f9d2e8cf4fd4c6f31828bb721bb64862d7a5bae31dbb7c4e2717596d2d2415b2802eb2ce9e8021092b648535a18285daae8b87ff77ef585da23f87c9a12ef5e736f6dcf27e5de40773b2654a8a1420ce4ea5f070eb2f3a95c24351165a9699c692744f8b4391a834f5caef0ecb945ef965aae00da04d3b7d71b2b9d73aa19e9f38863d06fabbabfc9e9587281c448c426c7a5b629e6e903061d3db9227e02703884d6f4b683d7b34a4c06d7a5b1294b3aa06fb9ea3941dcf1cef98666cb06d4ed8f4a6644acf3c5fc08e90b50d099be4000e435ab99755fcc4c1d6ebab9f06ed50adcb744f3b569ee5ec14298bae77d02952965abfb9cfb9b7c9ecf547d7abe77d9b92dc26e91fa72df2846ad5ee22afd722c19feec14c70aeb033a2f38a98576c598e9cc05d2aba0f1cca28a57b44e850cfd3f15a96d3d62984fef42fcae739b52b1c60a45ca253242d40bda24eae6b2368d74eab903649a73c946991c24ef5bb63416593b6bc3b6aa3f2992b9bb452dc9d15297ae516f7d5969fa3a94de5dfb77725ef0e85a2deb7679feea3140429583b9d28a794f290d2bb7bad354fa552f4ee765cb7486ac26664b55513d6c9bbeb95674d6d49fa7ba9fa8249486b564e564d487021c90c36fc5e01f3516ab4554b4c0b383fb0f13cb9a1600537a8c416f0e0461b1a5408952aab603a9c1d66b23818e7175a482d0e06ec08dd02b4a656cb4aab330babb5d64a820e5973b823db4977544763802ecc453510e28804c1e1ceddf943a4b2497cda78aa082cab0413e37bf189a9c06295d80f9cea9ee789f179be4e7ce2338a4d628c0b67a82239639c63f948f6e1d3196532c7f090cfa1b4c8e8c9ad9a407e3407c45110219fe3e178541dd846bf87c5662c168bd55806bed8901576ed53e2e1b0a8c7b0cc3e89c562b1582c9663b15cc32673ac88a8eb320ce80a19de624884563e6e2743d031c72e3ca5571ee25e5ec8b99e508d54181122d4062b86cac566c5a6cff9478e0133a072c49379a88d950d4cfcc4da9ca735ea571cb2d96a3897cbe55cee737ad88688359009199db5cf76e4e172a66ec79497708f8725032446f8c9c73aa2a481349c44a51e3c974311891f1aeaccc972b30a3b4f199115139bccb973979ba572b95ccee572b95c2e97cbb9ece26962933977c6cef33c754c9dcc39521b754b918e40d22dcf495969a756405e7a323f7da007bbb0ed15835168b338a40e9f581c9273bdeaa281cca3dd77c2807ae5f9c7e6506b12e5b250467214d4adc89a313799694a46b6239cd92b3782b1ca4d661a3fa21d99baddc538080d0245ac00d7a3c7d2a675ab6328135657beb27e50c158edef3b619fc07b307f2ce36b8f1f0ebbea783cbec6ef5eb18a4d62d3b4384a56e35c3b5851857854c524c81933e8cef36b574ae85e64cdc468bd128248378ee37831d6c13a01e8c8d2ed8847289bc43a98d6e1b03c45b1724227e9ceaab802fb442c7c5c7e38540f8bf3c2294740d5ade094d75d65b2322b544ffac136d0a7da5c35f2d7a8b35fff03bdcd73f235f2076d0de7421750f8fc3ddac945aa5c24d71ae752b8960c2cacfd1e592751b5fecf5f5aa8540b55a475a8965ed2bbb779eed13e479f6ff39cf67291e38be4a38a6feda2f5d28ea8229c1d7f8a1d13d0c240e51b068375ba6593295d4a6771327f174a2995b3e39f6c4415e5f1d60c26db5a2e030c7fd1c286e11bb7a70432a81e39740e94cf9723e3e41f39cf22c6276eca3f41281eab9e5d1996c122b06647ef63a07cfe2606eaf59ac95806e583513a3a38364754e5e8082046072cb262074bb0ac5a499bda1400e6b43bb165faad7688ea34c58eb957d77f533f8ffad730dfa19330287f5ceda93d65273d18ce45074fa5533905ace1dbbf630a306691bffaaf027157871520add6dabb81765169e9cef31cf0a79c95b37256ceca59390361a50e2c7113dba73f7defbdf7f7977be9342bb136345a75e5a25b24fb7439086deb9745f433ac628da49362a5e5940771600cb481486c8e260271d906e2b20dc4651b88cb3610d72dc72e3d0371bb04631a3742dddd52faffff2a3bdab0d26b4d54df58976578c9e6e026a69fa64e6946d22da533bc9bd158e7a1ea78a7fb21e4236cdd29cd3627ff7c397e397e498e5f8e5f7e795d19f6e5e3168f21bf11f063ecb8453baa4c0869cde3df3f18732f63ee65cc69cf183fb5d60948433ec20eeaa488f9d3f2135493ad3dba93790e9894a4a4b4b4c4946dd67381b19a512e7a5a51b7fc69f949b6c5d8926cd00625fca7d6fc18ddc99c72ab649b96fe8769895a269207754a69b0e49c33de9f8ace70bd26a85fce9452ea1540ec98bfde9fa379a79c522e5a1c4f87b815a39f5a958e1783e0513e70ffd7cd073c3becb8ead895e306b17f9eab870d3b07b136965b202fd83549b695de9ba2ab4e5b23e7e6b512d21a129c89ab992ebb72f19be1b22ba72f3c17dea775a03c04f5cc96939e690af54c155acf5081d23353a4f4ccf9a267a4d87a268a152674529567609d478b8e77345842183d03458cd8e2bbb4859e6172a1679e78a1679c50e99926360c3db3db756557a2d812ede5d7f5339ad92cc711bb72f2599ad21db1531eb2c4950c0cd50b172d626058acd8628a521bcf2938fb70105933315ab3b4e85393c521efc5b62a0a59960baa8e673db9e21098063967f34a1699844cd3cca6699aa6699a665e05b1496c9ee697b379258b409bc4e6cce25c9bc979e7bb5049b758e9eb64085a3859a5c0cca970fbe86d9fd212535365e1feebc3aa8efa24fc09369961b60cb31df11cbe2e534461b7dbed7641769fa3f3dabd7638bc7bbdcd2a072bc43ba1f37aad7ed824debd8262d7f372edb26280c522f988c7d35fa0f37add609378477edf6ee784d2c621f98b8ff8089733754736982658fc21c5e757bc59ee42c1c6744377563caa8e14ccb66e3a1d9ff3ca420fe5b935e46dbed6a0d1fed8f18378d80f54835052361913532980830bb7247070e186444f76ad7e642e424fb5b5b440b1af6da4366a6d61776d376c435acaf212435a8205a4259ccc45401239feb038de0afd6f192022e43fa6ff8c6edb1fe98ef55184a21e707bca6f16bec7f377f9ffff7ffdfcb5b063389975dc23e0c1135bc810db29af595d7e826d5f5f9551059511b4e003132756e811e248175914508860d0a16e8087edcf0ff0fd43d0dfb5e291559dc7f258fed2e1232c8865c325da5527c3324de74f6059513c8b0526a3cb5201b398c82c2426231cca3e27c3322cc332cccbb1ac425e0128c37086e936a983ffc378a7460daed961933a3849f67919834d211623599651213c5996cb321d3bb2926c32cb4a8b437edfb6ba23db2ff90b03169b38cd1d66c22109fac14ddd28d7c864cc78418c89e961935936eac870d6c1185794f1f560b884b486c4ac1dea0b4216e3978d0e6a442c46b16f181fbd8468331c5e22db6cd4464d3a64457b7ed6f33c89101942e4737ad8a88d9a94e7864dd6d0c1dff759242a8c554460aca8f83efc19d9243d797037cf42a11b10aeef1bd051af5c87383b299d7c85327042338b92a24801063424e087235424a15284922d25d071934373769c68276fc6aac5a8082615826628390052c10d8caab060090a27546179484615156f6e743ee041da0181b423ea2f9d22ed76e8df29d2ae68dfa4f0b33833313ae5d4feaaab72dc2076caf5b8756e5e7093e4b338abcfe2cce0b7f5de2b850b2ed010d26a3f876c579e6388fa2b1f7702fd9ff2da439cbd4f25034ff62b3d7da85dd8955f8dbaa997fafff4d24b2fbdf4d2a717638c6fb5ffa997d326c16e01ca575c16f79f5e7ae9a5975efad4d6fd36947280c4a6515200d4a310d5be2833a04e2dace7546b0bece25f581586a1532f2b605abcb0aa2a63573a869e71e96f9199467f8bbc35fa5be403c0dae84bfe0d2dc698999999998921ae2effa72ddaa22ddaa22dcae94dbec9f181cc6539470e3de39f8e74a4231de948675096b8a23c090e38a04183060d1a1c88ab1a5ac7c68d1b5a001dbcf4a5aaaddae64befe0f0806ad5566dd38300c8c0e02aaed2dde8db0a73bc8faa0ac9cbc97cffb6f0df6e53a405fac5f833c7b8ba5ef4ebca759aa36f8bccd1d1d1d1d1c981a1a2345a40d03c18e34e29a5547f18db3e001040000104100620ae64bade81f2e9d104d028eea369b4eccaff2ff0a5edf81f7fb8437bad15edf15c403af6f5e3e55e0bfcd0473fe7b1600b68f7787c87cb03df65f880e7711914900b83c140a95040a8adc7737d6f737bf4f0e1c30049ecca6f6800940fe596e2fed4007c8792165af87fddbdf7debff765c2ae9c7699fef8628c29e5f7f2fbf6de7b2f79efbdf75e3e81beb3a2b406194a378cefaaee0b4a73c62ebc0f645e829cff3d92524a294d0df56d3362d8b457fe351c4a7c303435e09c5984a7153ad47736eb1ba553a8fdfdff63dad354a95496752aeb14078aa60699de9dd264a121a52c4098db9f6686a7fce9cdf705a7aa8b69b2eccafffefdf25ecdc2ae3435e8dfa10c0cbb9221454e7eb4fe8b29970dc22afa8a6e9158218b04088b647fdf6ccb0d3720212252e19c5b1b7fb6e70a114458885ab0028b93224360c6e284c910967b2f2e3274f50cc4c50c612901cf86b00441a404516c6868686868e865c51a203ed5db10d157912125980cc540098fd39c2f93a159f6fef38727f0cb1e11d8a274bcf7fab85d86907f210fc3560f8f874cc7ae1f2f1232ad56e67aad1b1d3bbe2ccf074c3e183ab54622bc033f82311157e19fc93f131ee32970127014781037c247c04f508203fd0f711378095c04fc8717c1f8bf0ac6ff55fe1fe3ff2a355adab1c88245600d2caf8659fbf7e2ff8b71be65b65f065129d1850a860c2b869e9131736f93dbbd8dce8e3a1e5adc913de2bca5b24facade5a2716154abd1d4506c6da929dd89910116c9006bdd721932c012cc8149604ed300106a7c82252db4b3590f8f2d5df4979cd2aebcd542f96825170d0dca472bd5cc60019616c8c26268982ef54f529292d2d212cbca5822cac668c6154de7298a2b1936bb32ed762b0d5bc9d8d8704083460d0eea924e2733d2c0a7064bdb64cf5ccde1c7377bdad39ef6b4273eb26755b2e357f3a50c69686dd240f968a51adab46103e5a395b44e9b375eca1adafc94bea58fa94ec1e153f51dd5c0a70d7cea56add5f23bfaceef667392929494969698b4895d2fe5d7a317a86a0b6ddcc027ac8b86dde8e0050ac96444b3aa84f6c2812486437be07da5492acc8300e4c83122dda19d4b40480686ac2ab56143d03dd07c841b7c3fd4264841203f5e72f44fa9cd529ba5364b6d96da2c35ac5ca17cb2ebdaa687d9539ba6c5f91cb0082c230096416ef40dcae7e21cf87eb76fca97844f7ce2f3fc8ef295414097cea8344dd9e62c64a30120200843160000200c0a850443c1589ae689e0e20314000d5c7a3c7254401c4783f14810e32808832088218418600030c61043185286b200bcf080c3a348d7876db866f6a26794e6ef248cea1d83a763c637ec943c36d68f0b39ebea55b918891650f9c3225906efab33c0e64f440dc7426f6e9d7126712937f6a1bf3f450f7d390acb105af172d3ad4e87d9b9a2388069995cd65978cdd5f0038ec7a6a88fb9aa379639c482a6c9f84db5bb991e417416776e16f0656da0fe626d0726153959a14816423bc979f8c5f060f21d0b4e1e397dd7c4383e6d686126fbeae6952489d050f8846f4e9e2d1261060b9ceb362b6a3ec027e47ec777d6db6b9b127f642a4c63b06175d2f782681322effa4a8a8a6f6044f133b85384a78be12ad50702fda2244670dedfa227d847c62e2c7b1afa0fde99a92df50feca93714c85edfd76acd7f34383b5c417fd087835b36e3c8e965e8550b3993e04461353a015f086a19a495f909ab742875b119d0c4a2fbda75b70ab607c0ad8c6e5fb8392e5f0ebdc005de02ed24ff6fcd20c997b8f6c6d7db1e430a5779f863d0c28e35a8f4cfda14ee368769053a2b5825a55b2db2d098237c808c0deed3326138fc21a9cef8aa72ad5f0ab446863fcdc2e2d35bd34f48075a2b45865145eaf84e9a21f15193e5755b24b519d2fbffa95e51a80019c946fc84d272c1482d221fe40663b2205feb86ab6ca6f1438bd2a6042181d17a806b13e27a9dbcbe9ee9a3e1aff829fe5fc6ce48973ee00700d57068d41e84c160fd46fc05168306816561adc4452673c011093fe32acdfa243db0e4272d120c1b4b3f83504df40825e786eec4f13dd0be0d5ecda3e5e233d1eb3318f07ba4a8022b42f315c3d2a6d0667215d52927eb4d770932b3912142194a6e3a3fe5325eff06575a673157633491f2d49a737288c49c1c205792ee1a24a1dcba011429682ef18e2ac93f8d6a445ee0b01f10f58c825dd6ca0387bf4748208b49e8210a353e1e63f30478d9b47b3085f6d50135cb902c22b5acb91d62e1cee1d8e698b2c6194a453976ff23b31c6cffefe04b7316a6eac62672fcc05590aa246f98f5ce98085956b3b02abbcd8fd26f818da0f33eb5e0c26b4d739ce0cf4714c2e17b816e7a6c5352da7126c9fae82b21043e2702f1f3448116b0a2264f595320db095ff032e72bb884a0265f375ddb5194c09e2bedf78fe98611ef60c5943c71ee658406540c315271e2d4c60f1652386a69cb9678cbcb227831c8c7c6eb30fdad87e477e5192392f90a078f73bc7cc4aa23798e5c9911240e01b995ba0a749f7d0984a9463209a6a9c8a3c63fc516638baa5fc221bd194ca915e86dc1bad2fc2a7891d22e6ed90e84903f595501586914bc7df38a91224b44888b404889bb49f2ea0a6bed066f725c968254acc2d97812b670acff0a1545d25121250fb2105020f84a3793996a62691a200d1df95bdece1cc764fc20ab3b2c5c4a716886e3e4300b86d628b4151a0013944c99c2b36a4ee63e08112e51a3904f132fd3b7e3a54cca77c168a297c6e9435e9e1d6871497179086592fa15cabdbadf60e62ca2ebe7d6c2e7fd9b56d407e71dc0aaf5d0455f3a31406b0584a63c3758cd0f354cb4ca58d7530bf3a28a9b52567f03e61e1b8984e89cbea6722e61b8de3d94d646684a442839a4dbab3c753d41e18f8e0facdc3a140b528eb648931c481d8980bd7a5a7b11046265370814837210353736fc46ac950747a3ff2d987aaf97fed71b791800fd82a04e6dccd5f12a1921367b3cf07496cabe7fa3b0d3e880d5077123fc6850c5482cfb922937e33175b72236fc3f1225555057e5f961344692f637e867b8f6ddf723a3e03472cf475d518eb58d46395b80f8cc62e1d61cd0da3ab79782fcb1edc0cf4db20db6bafc205cc8db0b13ac87360b9b61d0bf684151d9bd67de3ccf595306b2cc012ccdd444e169e191d3c3f9582a8bb17a0a68e171a3e3a414113bcab73c90039d36853e97b7fc9dac6faaff01fab3af7aa6d5989d34b4b6e2f8dcba433a11ee55170343d8817ba51d659e17cad5e1fef210495d559eaa64b2b651763759cfa6694705b817ab987185cb6e0cf024b229140c71dac1d7505efdf30a26aae4bc76eaca5da74e95a83c2de77032179d7697e54581e2a4c8810e566f07ee876be73237f32780efa1d0295bf16bc037a53ba0c7c853d5e85856027efec56927c659d8e2914a34f5f524985f2fdf49b4223439fca239facc0c81e0cda34ed2cb8695a7ab855f2460b68665d1163b259beddf852a4caeeb3808bfe8a7242f0c3ac6809c2a196182e6e377a7324230ab932f5553f1a0d3fed1c88688bcd156a0415ce8c8823b4a2f28b9411ba8d147f71430c1115bcf5845cba6156d88c9460e58f8b70b0806233e29a6c934c3047d5af46065055fce000d83033d4a7913c08bd6192c2064ce92de9675052dd4555a4828f236867597a9a888afecfe02a2e4560b696a2a74a947f5990cca3ad239bcd8384f6799cf80eb96b2c63cd1b372c6f1d17e633b6ae4778698bd040ad9e92a70ee08a0ea58209ccc39d9d9cede3037f1e63a58c9ff2914f33c5f14ce79bcb83dd90bbc0e5358757c1a0808078b9dddf23724bf39f877983ea03b95a57081d3e8751374de01eedbb87b072627070bd329931af602355e62b2f68a5514a1dd8d653e52ea713cdcc31d372a9a91f088b8f01314af0d6642343f8a9d05ac479d81bf27c14f1deb5ba9a9c99fa2a5f2ec7dfdaadafdb17a614934280e7c821a9169e5a60674062b443123b556ebbc7639f49bda8182409060a97101fd43e60f5e64877641a562f7883d322b809e2040025f91f1c999b45b9f2bd1258cf6156bf60b1f690f14533f96a9340c2c2c3ac30c3cb7ad602cfe012a428f4ea0993ff6682c3a2f3ab8cf36ee559b90f63a2c675baa47eb8d83ea691d4bbfc63d31ab67a46f385a46b5a0923197614e0ed0b6b6b92d64ae4f4843346767e61958ba0ad38c3611ffaa6f4ed21496ffa968d3ea1e4c6fe4a2ad98edfe3c5f84b6926e9bfb3cdc5fdb75a8da3a20c2d3182b647ce204e185ce291a7a08c28308d9de83f5f643e854b0f624da1993bb89472bcb84e1915620fdfab79266c70670daed2208386be883848a1cbe7e54ee585331d25aec45106a60c4add2ea3ecdf9252d4ad1ec5a61f42206f14f13ce6cbce5e370ac132b90e4757cbd9ed617db8b797158d1a0b5e476c694813fb4897d0f44a91a992e22c94d0fb97332b3002b7f4b249d48d6bfe1fd529d26ee25daad2c97a31d84cc822514a8a013b29e81dd3e36c4991cf21777d2ef38d426a178b654b849e4712930354d1dd12c0b3ca78d49c346bd09a7659528ae399eaf3537e0de931019d1647b0f12ed2c6307fc8390852c48cb1cd1e5efef4c40534b41448bca1ae5bf4cde71ce6803cfc02605548d6656410e5a182e1af9b955c35018fb4fbc115d7e5fa19620a21eb4d596e043b3ba7ac346b1acdd211c0c059b86d6ef80ef11559c0d1b3dd983af460dc9a3214ed45d2084551fd0dcd2c4efcc3912c0c6b3cb3658cbc1fce893a3e5625a8925c4658ffe46570e9618a95efea9fd47b76462415c04c1c3ebea66d163a1b89c508b02bee2aff6945c17cf7a9b6f3ceeb0ac277754fffe7c3b73994e19cb537168486fe3e5adfe3b2d3c212a70a4783da36c23c15068765d9e6846302be811e2bb8fb11600e45c54dd5a14e8e42b9a220a1b0d386cdc7a0b60d3ca1deef8eb32012f00bbf09bdff825606b1da6e995f43fb9cfa439b9a86f29c9be8fd50c6692f899082418d4e952bb4cd717a5c2bd9051e48674cb04c6814497468a9cfe568d3430c6781cda719d720da97d5c5211b48288bee2ff63caf7465eaf16780eb42ad96d70d5f5ee568352bab429baa2f7c6e89d6d9dec2ea726edd0952e7adab1b09d39b9f1e213e79a46cb6974523af05a116fb413d98acb1b3bdd583011ca6944e61718962ea982d7de624ab114eae4e3b13584f38f3a4636ee13de1bf898751837bb2a6e958b0eb4383369e99bf1c15c5371dfd90ca549f4fdd6cdae19d53099fb9b11cf532e0f62d2a6a1641319250695712dd124d9ca9618c672fbff0a60168d0bac4d915a9343dea37b632c90ecfc60ed55af7fa9be33f3c17ab562410e9deab7aea4fda0674080f3177155584f4af7842f9b98e4f7c815a2c8b75017109f08525f71221d1b03a79f37a96547483cc2f1c8b999cb5f4053c708181c194a3fd5c009495c3b16c5c65cfbcf8be71ec55b18a0df2833ee28d40f01b9ca4ca06fbf6fb95f68ea17b22b09891af7fb09ffc4bf0d4e5d8e817e5ee8666d8ed0207b2dfd83e3dce647c3a8447a07ddef6137e8c4a58f5505b02a7146bad60f9ae35e4727935271527d88c4a69acaf1fa9d6d96328c7072993e6d51fe052a0d2b91c31228f26f8c4926fdfd5814d5e2571b7a88f30bc5291b2a5443f4acdd325b8e8fdaebae0bc10eaae791606e6762e691f7c89c5ead19077e163dbf251b4f97894c842a97cc11168dfa6826cde37e89978763a841817c97a89d104fba6613f6057fa94928c58fc0ad60292c425061ccbfaed88e92ff7db1588612918c3a0fe6e3f672331f6506128b358c5225e8c97c34c3457bc4bc68500e0f56b367802ab40b5daa5e4674eef0a689df0c609ff6da39b4c53e9e54a628c046c338016ea22c38b62b3d953ee3138afd1c2b0220024512d1e45fc4c634580dc0bb960ce3c6fcea1c9a39ca97a1280402902f9d231c46036a79c4e60dde8385b0e75151f75d13132e38e975b9cd86367e30021d2910ba589198128e59018f88b024c19c010ca660dd3280d54358c718c05217d60d0358ad1069a1645f40f809e8940ba86599e2ef3ca8d4ef7507dcff8a9e1acd5827cafa1c1a826973a91dde5d8ca69be2e6724d55b0880e869d80374d601f98c0d745b1e10931d527d1cc6424f0cf74c5891f010c7e62fc38461b2cd372efb790f51007b0fd8021b52b41f1c023579af7b651eb67c899ad6f183840dc8216df717d896982102aeda7be0baed70d848324ce63bd92abca2ef024b67951df39e117026d4a8a9e887131b02e2e83ee0a64ef14f288bb063e3efde72c49f2ad6ae3d28c1d4c0649eca88ee686ce56380c24b809690a573f8b0882396677653081bf2214e2771d5b31ca10f09869d84e36ee7b519859cdf4adb5f860292c78dce3e45da269b4209480b1e945569978b566ca861b7d3fb9b574a1562cd00669ef1467076e3f8bc344da1407ccdd570d8d8fe5c9e00d4c582e1b50485df4b08b165025b7b54e3db41f7d3d62b3e248f2820117db23bf97a6d45ea2fd9bf736f9dbfc28a0c1c25c5db3dd9cbb9df965d75ee912d03468b049ae9cd8f5dcd3d422a36792ccd3099285312b5fcadd3a246a69d91232ac6a12572bbe7fcdc465bbcc5d3545436ea9e8b8002b7aad3316d5871d2f291ec80be0a67e5e4a681443714a3e14cd5076a59018468e48072a6c84165614919ab651addedc4b946035004b24871fc0b62b0d930d02b789856f42325d5855681c2efd568ed1cb21fe02f55f4379f78e49e02656a43d0ec9aed01486af0b460b7b02b805f77c4980fa58d27185507627c771a687ba137d18a4617bc8fdeb5ed501a3662baa64203dcd785e68a4894686f34ec754cbc869024a96734af951ba0715db1281a93872ad39e2393b08dd96fcc1408d07c9880c11a6c6dca5514fa585efa84c13a8e04e272c9c5932cbaea0018304e8d5e15dbb136bb85df35a41110186f303d78cc780a48499f981ce5c5aa13fbcb0c381c3a6d86953af47c555aefbef33bf85016cc9b09f07976f2ae4200472ac360d4acb7c565cfa91d180be99358b86ca51035573de782b9e810a84ac541d475705a0d68ec677d14c8e2120392069195971460f4ed1fd438cdc74d8a02499b3b035c59818062e85d690315bc0d9c304f48a8ffa2871952f628ecde5d1222be8c05fa9ac735a62d6319c6b716927864343c42d1fdce1b687ff1bd08f5f5f4edf150c05fe82953f8491607dae024aa8af6b1567d95eee63168b6b1e0e89f7427195788dfd90c8ea2d29aa31a249b7ef461da7290b657e73b33e416edb17b2fe7bddff9e13272140a1f7ca5510e224c3f94547567ec66f41ebe0df198ad23a2decaa7d1ae52923d05504d05cd985a7abab18fe8d75db8fdf64a55c9a68f367af7844e121f33c08c97807cae070723bcab10ce3539971dcb62201c0af114d6fe22e722640227b393b88cd469a51d9daa3f1b63b465e4dda1d1cf81a4327b97a9c3a114a18897a4afb466fe3f7680445f4cea7eb465845cc0c848c1f3d1b690b4cfdd42031585c5e976b2fba7b93d63eb34369c44b764131efa3412628d25601f052c3e5f084cd287fe6a52d0d16186a9b81f58b92cc02b88d0d73372897e15894781e36a9320ae27651adcd7d6beec5cc257f5109be5fba8dec9bcdae340802d45c01cf2f0c6d3098cd03848b270b826d0583bcf7730e7c622eba1a663f9f783c053d7f5f49a51b5e3ea185f2cac929f0f1d499011180520fe6982f96ddd443a0b4d5fc3d118eb36217866955b3e42a625349167e8db8b20a84615f27fc1d008030ce9eda68375810c4db3dcd0c1add10e48d1971841bf2414d2071fa743b31940cc34caedc32be528e533f6eaf151454812f5a398312d08f425209000fc23117a6717409d93461c6f69f9d90cc2ad43ad6beece31ca6236f2608e0db45ec388c19b343689bccc8fd32a6ebdfc9fa9c83e0bf6117178fe3351442865d4fe92594c3c1ebb60bf490c3508608a551bda22cac694c245e77d2ea1d8da8595f3d8884883dab45fdc0a50bf0893605310bf4872610dcd88d21e1f1717b3dc7005da1e939182e50fdfc874f21df0f5cc184c02496ecca431481010c164aeaac62b652eaf3c02a28ee640e3acdeaa16b6c6ee6c65595ea15a5aa3f02b1adb4478060684c365ddd861533d0d527bb3144365890dc3695235236049dd47d43a394b9a762bb2af0a19c249f50a75a42e551601573f0b96eb3f131c472f3024e2c4c917426af892c08882c82550022e73a0dd0b256c8af8401ea6f129b0086f8c38a1191817c8980e7ff314a4dc3775b2da7f168a18484d9d6708d5314b7431733f989085183a7e2b8c9d778b8c2eed8143295161b182258f976277476abac09c35770983683fa576267277a7dcc1990bdb86055e3b26ded5ab95b50c5f582e9f32d803d781f2079af5ff9be5adc6fbb6717c55562ea8e6e9cdb6b10f30f51e320afbd3bb3ae2e8988af3cfc2ba10a989817320e8dd0158e5898ac782f3f9640fdbf6e0454fa4efaa1d884650068bb01c002f943112301a575a1a91088e897989a069ae7a3066401cec0e89d835b40bff34931dd9aa5dc73dff33ed0d46e90e2923586a23844302a3dea333911854535cbb8fc8794be1d6838d171ef24fde35ca2baa1e710c476faa9e425033b3b357da12c7d451388ee46fcdb80c4414f26c24b70ff77f1f052aa6868bf97b503e5c364db2881dca2292caea2bc1e638de6f890b4926187dce4ce293f67087dd8232d1b8d522375146e3f5c25e4a8315ecdcc04d8fbd952fc5740aa1249033e89b7bc5dc15318993dee5a32e42a6532c1c6feeaaa642fb36e1d139aadc8073f5ac7ff2da11fe166dec95e2c5751def14dd1641464736d52c828fd137abbeeea155e43f534ffbea46bbf211564c8d70a5a87b4972040683e838efe101959dda41519253e1326f743e03afd56181e2198573025717685a290403ae800060d30b7b4e97021d6e7b5f66e77b7b4facd27be27dfb094f6aaa28074a7acac22d9aa5ef5651c818d797a41eaf47e545432011ae42131ec7b308a520d46f0622c53386abd2c515176729a61b722f7e6657de0798b00cf28d27fc2ac0583a0747cdb1e4efb2ee341aba3cc3a6e0e71870c9e1ca7535251cb99015df6871059f684435041a47045cfe8f6b699989d734e71175695c3a4048543174483e16a83b41b434c4e0262bd0579eba24a6fbeea3d0ab490b797b7c6e4e545379ebaf4ee621b578cad064b590aabb79ce22d2b68e8c2f75feef32a773fc5a220fe66478d3aa5deeb59716281de5390a39e7dea169bc91f296e934bc2624e1bc3bacf4bddadfb11544f41dc5eed26b61d7e5ff2d1714fc4af81c1a7b20065cfd81926ef1479719711669ad92d0f810c07dcd1c6709708a659d915965cf6c91c43d9a0618c9d63c05fd172ca8afb53eddf14d754d5c3e186e8c8e58a72d49d9a5aa4566435848261f4f2acef5ced9fa185668250fd31321cbdad7d45081f7ada37d6f1a2d2e9a8150afba07c5ba569819ec1e4419359eb9db10737ed6bdacf1e6618c4bee8e107a2ca0aa7d990942d2d207177112c4597616648c4f1291b6b5709d65bbc0bd922f4f0162fadc1f8ddf830214c255d6849a00f00dbb9ca3f82759dc77efae4e90dd040d75ab095a8eda050a07c98c0f3775428d686c83047578b2cbf94e4534f946e629eb87c5f749e41767409a5bd99d4e6eacd68d020c7a980b97bab13535fa8d2416fe6879a445f0baaa10ae95990e816509fd4fbe22c988af92ea5e2637cd19b7a19314e0a31e41307c4d028b33a27d1abd6442539e6843f6bc88ee5fb50fe3333d5066fa08068817093c7229f4dd12326234f92dcb6bc17eef79da276ceaa6d72ed1acac3dcb5f45faf6e2c713e893dd1ef87537bc19945bc22ca8f5525295e5e3fd04463fe0bd4cf13bc12cb7839a26b74c07d814c14bbc84eab315c09651a9607379a732818034c80ceffb3fd8e2e8be4eb3e6a3136aa0b1a889865faf2ed089c6c4f49ea302f4cc7f96b4fbfbde3dbc2963eb48eb1790670555f404fc9c290ae7aebc0fa01214754ac1db8e7caca7e6e510e8ce73a03beb95e689a548f12dff351238610eafccf355c091b07c929d082b5fb57ff49c2be674c34d2fd9d72ab0caf0c0055a023e6613082056e84c0dcab0dfdfa25719b499e15e4ebf747938c286aee8c5d4ffbbbfc0ab1c7b5541075545a368f289197481f086b00b40bcb20c2b2e398b14157c9b65652c31c3f85af9baba4f6b54410615c5c95142318a8736e01342c095e2be0b997fa2ca674842ccc013371d45403b09657ed14bc45e17e74cf25aa16a66b838564798391efc42cf29c1b72ea88d2b3b4d5c280a30ba8250e86de255b7b29c8996ab67c56e9c0066de216a5e086206533b3df17ef16ee0432d0fbabd48c5609a6b761b18a27ae4ec061367a370ceae5dff11b159a6cffe83efae41f1b0e4a8b3226a69d35b208866ec564f0105d9186743278c74178424e57e435cbc0931fddf70f00d47ec67c9150cb3046ee2fb15cba64d575d09fe71551f9a540f13c3cd0ca5fa8978faf650ba5e7ad2ea23320c6739da8687a6919a7331732e199e8bae0c932a4dc6b9d0036620c0e83fcd9c373c209f7e9ab3fb65f5cb66a0aba028100fe28f70a3300eacc7de46821ecc03da9b5889b179e5a01f885887bb4cce1d2bffd125fc70f0de79b2a3e9431f693b4977d394be415536c4eec417804f3ea40245e7d4d1ead55309c7803dc1820680f4e1b0e44736caa2d08b5f240ab84be2ded11f6aef8a53c9ed5992513b851e3ea2817043ac02a2aabb62a40541e126e1b2558151189c63f46ff9e735766c89442299daefebbc0c4f388f24550498a370ad14ed2ebe9d5af5594c6563ad40dcd5c92a5f806da52265d59a2279dc7b43393e756c0d472c108f9cf775edfce70dcec2b9a39bf98e69e4b066cd54e0edc35fc60c2703093b271e894b2882281faeae34112a3040ab5dc5c815cd17f4eb3de17f57f1c04b3e980f9482408dd5c6478685c8fac22514dac70ce58afc3bd27d7f18882eeed6f15c1c7b8519630468bc35f8ac3ecbff587db5048e42717bea2124340d4043845b5d85c03c2241117ded9a54cea2415a9f3a04330a8f3b61d1bdfa6c70c04a533ce4bf444914ce8618cfbe13fe05ec9ed13de4725b2892a9b672a1dc19d5d48fb9c1402675b1fd740b25e2dc19f147e1b93291253d6e36d9dd63018eaf62df462cc168ab2142ae1db8155e8761a1b6fa827b854e40af44efd52342047d74cdb48a3d1f4b52b983107806ae25f533282f4ea83cc22d0c34cb9575fa97ca73e29e758779c195ab3458ced87829e8bd1cb0ab1254900988fe6fe1c21dc03d393f3ff615a2baa0a53e83b15d8f54f97a10ba9589366c53bcad4a0152d62bf3895c0a42b022a01c71cbe83c6436c086c1a0a080605f5d87c71b40c4c817e064d96dc7339ee302d7e50640a9129806b6037657523c18351cb040d1267644feab24b8aa4e9c91b0057ea248103aebfb6f195d928f963eaaae2587362b6905c00b95d7b398e7f564c46651c023feaa6d7bffa9ad29c260cc2ae3ba97162ea5ffcee3c92ba3dedc087309a98f4964591ecc4c9b00e709b165f50f887846dddcb9d77dbacd610f11f40b800df282d746b46f48f2f61fba194cc4226c8166e0ae23d391b942038ad420a808b8d83a83544af89907cf381c6853b7e569832dfd048b6f2799c5a927a548a297afb363131daa53e9c7340ef43951f9fe9cacc1e4c2d56a8538bb81bbb3ccb383a3b9a1a787d9d8ace31af5e26e70783453546ead4be58bde577e472ee5f342076487a1f924df20f76dc3baa13b8fdfcf3187dc76841d2f9e88e3525503de569ebaf4dba27c060026aa4c2d85fe90d01d4679c07a02e10e045a4fdf883c592ae094f08bb8e95f26f7052be60a3fe15b5a492f03feebeff3edfcbc676288bc17cc049aec25611d9925b92a479f54c21dcb96a728ee436c6f052e2022fa78f4deb310a340986e90be3d1f0a6400ab14bdc131be914e2f90dbbb5408b2ec28eee610dcaac02255bb4f55c5df372e109d8e1720322593c45998b2166a76624706b3e8febca634d50f041c99d2234deb8be3a175169c732c6c063e99a0cf420e11a7df152e7d8fa31b3eda9d484b9a83184efba7553e092475afd771905ddafce6f43d2c21636358018c437d2d6106b646f7603a8477c1f44c77d1121637d41b5ffff13c4951e84d1d37a22500218986a17bf2cb5792871d42fe25af593063546e3546ac573de0ba1b7932eb14a521bbc81cc4e50ebd3269aaaa8d037659862d08c6523d8c208a153de1c44d30481b0505694c8e793e37101c9dc19f54cc4f5f4e9891cb113ac3045b99b5231b28a973729d2e80357467991b02622989ed63f3eeae89b2fa6d7a5eb47e679a7198cc8a28d5f4e921bc6b95e3ee58e1648201812c50a0802558f183ae7729cbdd4a0d5d60018786f3b935ac1a647213a3704345a539cc1487a7a6f4a3bea06531e171d7285c1c8003b3b68f26722e686e7e42df2668367b7500a705027c07e36b6d599e4a5b0b4f3dd54587cd40541031d25dc098b362cddbc8f9916e69646af2b22c2286eaa09fcdac4a6879b76f30be8e43e34ed444ae3664e606d7179acdb23f12d8fd20d77acb623f3f046126358b2bbf051119693b4a95e21dc8cb4d9fcc31368c519088f0a1e77ae89418ccf9f848f01dc6dd4285e0fb1050fa607da20802294cb54dfbcc70f2b5e448315591bb2fee855d5269195e941870765a106817ff325edfb3f483ced20bfec8926427d56805d7c93c5dc212de9c6b75304519520610c9b0ecc8a3c7ba7dbd003f6933626c3b9a2408da7b5c608c645dee3575043529d33d0fbba04eb7b41aef96e0da0b84d4cf6a18c3574581b46e4141aa462599d8c3c08ba8cfd38061ab68d57c84669e5c2923f08874e94c49a468c0170606695ccfcf47b27aebf1131d2eaa60685478e1a9a65957685bfb10f271569f3fa7a3cd584a7a1892ad6705a786f59dcf3a2f755c0a0986b2f29da81413677b51c5b68e127b5f86f51bafe4570890301e994c4cfe197ec5988d21208a75658c5f4c881b0a326310deaadd2efeb4acf3a64266903c054e2eb49dfe81fd9fcc95a6aa6ede5e4bf79a35c7220c78bc50158b96251ff46439315a280df215b5562d8c3c625726e6b507cfd26cf7b4180824758516e7f7ba3ebebf41aeaf0fa78304ab9831efef809f284ca2b2f4ce62e9125332198cb834b21e7f554608f530f3b539f555b37523a9fa7e3fd58f9577c0da3b847864f906d4d7affd3eb09d36482093bb78692d107a34ab364a372815532017208e549dcf82bdca812e405dc817c3e65558131c6f5b2ac68a6923c57be2ceb1877c270b0ed3a93bfec1c2afc569adb86034d9d2d98e364442640dfacd03e8cb0afd310af177d77614db45ed073658ea3a3ba19de4bbb4009baa8f61df86fd8d38e8b1b8fabfdc80d2a1a08d9cdef185ca35b6f5375fd07593357621b54010d0d0e54c0465b3e5018bd133172d9ca97e09cf3b3c2f42f9b494a4fdef461fbfe653068aa44d312b1ea0f26998e1e29d4e4ff1b1e30a814f0a2a15fd3e377c10f317bbc316cdcd41c028053a08d9f786a8a77315637ab0cbf54aac9241e488b7fa2951505258426860e64259401082636db4b6cda76bc23fb281a45b56d21b6a817626b0e6689ae1e9280752403ef9375dae2e39d04189ca24b78e2fca09caa474123ddc334ce045fbee6b2b05e19af7d25f70676fb22fce14e9fe754790ed1483c4e6a3240826ba23e206d32206340600946aef7c1071109ccabfa549b7431721db42f7e4532acc22dbc230d9c1b26240c7f6da57354141628edb1089a339b287954cd1f280caf0c5aacfb57cfd667ae6110cb8a623e07781f32cbb26c6b4007444830621ebbec4a950a2f2fae1ea418250c68614ec56526979a81bc80189e615d0aacaca2cb9fd5d74439b4a0210ba05cbc8726568b31d2eac008ece7634cbea298c69f5d6f042257b6ec6b8d018eed9876cf22e923fda3eccc313a7bfda08c82a06261377667dc2452914a04b37246a3cf1405a20c936109597886d6b03a7ccf723580a06217dc8093cb194e5e2ad5cf3e97f964021ae3c84fd1b7e911b224b04cdf4c0dfd2e41bc403f37949ff9757732e016ce7bb58ecc1ac992fa24606b4c5e10b475f495aeaceb8f7fcb7ccd01b2095df7b31e4690a3955a5a116e634b407dff34228732b070af1eb3acc53de94300031af1bbecfdaa84348d3402465bc6e7fe5ea3753cb8b23efd30fb849a9b0309fe1800816210a0bbb9c161da0d04dd6300e2e9a4080ba3700d84b4d0964aa1627addc007ade4b1f826fd1dc2c0528da0be062a26f3cb0e04fac27b2051d712dbcf22ebf0bf78006398d7cde5e3973533e6fa5c43d20b69f6f0d42b268c703ae535e407d71967eb6e929e7be04e72d831fcd436a2ce97ddb9299b9ca9975faa96747f8a772aa0973625d68fc91ed68ca165c4895bdd0f00afd118d9632dc57fb3550006444c20f86ea2135c45c92fd0b52c7c3311bf4b11f2eb6beee378919ada384eeff0dfed63b966b091735643244f45488074b2a9eed8be7d0f6658c8d158f2ee010da8b9f97dd6fd69dc2e82838df10ee2d72f449bf5d58f2f6c670444ab4fc08207f6338bc6fe23a30fea1c4871209161206473b008b84c256df44d6baea0823eb5b313ca80d279dbab5d91b652a0b2abe56019aa2cbc8f836b0f2d73baacd6d37eb2074ae9f1fe33a6bae7cd5ef0e4aad58f8670dba3a621b4b913376b7ac68f7e8b430e7149002d29ef521002bd6dc193cd00ecde3125d4b2365c763067b7c4c4dad30050ababcb7f3668fd2d2968fc069aa0071d29a888ab92ab2f1269526f60c1d7daca4ed2b705383022505220d65bd570b156eec26a1380f5b84c1e7e168864438229f0ab3ad5da0ecfffe72e274b6c4937417dbdd7820558404cea8de4ea6f1ba08867584d0c924a9722c73829eb406328858e56ad7d3ca2488f8452df88d7b80aea22a52f6f9e607ca9ac500125aa3acbe0487c6ff988a58943272ee31026b9bec8307a986f176139eadb8e449d1c0ee231d4ec9d239ff5ed192fabc4e36095a6f5b4267aee36ce98f8e02ac4ffe963b93241d8c3d52f00715809c4421a992ca2076e87462b5a2bd03f3062c2ad3674f79555aeb16633e6954d647e2db5668835125702b4a0ec7987c8541a512ded1e13566bbe1b29e4a01cbe6b83bd68572588ba22a8cf5a656a1679168ec01d694b6db18014d292a95806020234137f4e00f4ca3b06a7f75fd905dae5b9be25279f0a89c32a3c5c4a2e5b9199174692eefc10ab5231041363c17f83aa9aae8fcef7a87673025722294ed4310e72bab51fb7f8547597c9eb65ab9d68bdfff4b8899f226efb753b80c262715c18ad34b1a5d6a77aaec1ab9c523d15b96659f4ef108ad860435d80ec11c57381d8178f3b8443d9b55c1b10af7dba12be9eb21f32e54a60a2e81d0970c3e27bd23d4489872141da7cd068a80a5061272a58f94e066ae0b5895e9a1d7cda616025ce00e1f89b6a19451b6750332af182a7d04128dba1189aa7e95f338ac94d0802a201abd17b7412d6fb1aaa8d21459f53da8d41be488c764f39a1395ae03580c0ef03a54bd276fcf0fcb8cce9d2f99bbee1b46de60e04957252fdff54e1dcf71bb7052d797b7dce4eb75aa0c0fd067019a06308222333bdbb88d547339b7922636ea236e6d5a375415742c33a3ab58400d06c15d3fedc75ef7946672b0b8288c4fcca8edc00ee4bde260fba186bf1d34efb6bb1eccf17c80664f3cf38f4bde0e1cb9300583cc1aa9880c79fae2ea5ebbb6f73cba464c9b62acf385e1da80f8b49eef19c6a7b4807533a94a47c6fbd2924dd6ebd1a7736a98b8cbd209a662e0124da9c07777e0379ef8421cf10aa70ed9ad54fcf8f8f6f202453ca53fc30429089372fe56560a502d85f8b762550027c2512e8b024e35f682ae62db5ca47c9fb38653369bd9adb756667273cb63183c1681e5ef5d8ad88d0091d2e6bcf2a2ef5c6a2b00d623970e769bdf147d7fb3b4db51271df1baf2bbfb093b10d878b139deca873aba98fe19c88499b140ddb9d8e70d49c41b1f198a1f5f772930a32e7dc93376b1c2b4891e02faa0cda10aa561dfcf56fecc06ba2ae5085b7588e3945179707c66e9082605024e68bf9fef1c0431b18be6b65a53a636464f62318ee1fce256b545e374c4bc71ddb1d07066ffd3f501b934ea07686f1dd707d24d0d71f07363ec8bcde2e5214d8b3c2a7cbb2f14dfc98d82f7df30baf8e935ab7f1adcafa25aaf726923ba2ab78262b3dd0d34adf7844975e3d89f3f634e0c66497adb27906dafbec61371ba0211cc184655083c10b3e2722b2e2b268d30f1165fc7a31fd9f5de6feed7c06e7bea0703f95a903a2dea63daab366e6c70d649f14f36755022f033af95c70c01d947cd305147d0785cc8552a17d35a750cf872f5be86a5554af0390f50f31e99eac3bfa8d2abd7ab94556d221ccd2ec95d568d6fd20197a309bb32123eaed30910a56eedd5b83034ddbef2b02cec1bcb8a8e914c22012e3626eca5b472822e5949cd16791220b07897a48a7997b07dee474938011fe2c4575a8c5c6dc6634eaa9333a381d24c1ed34f688913380e7a6efdfcb226caa2664ba3c90f20cffcb2943d5a2bf40d42a49151eac1747b8d08274a58f93ef4d1097abce380d1072e455b31e96c827664d62221e3f6f5d825c83c9dcf491e60b1d78c519770bc7a43b20ce74baacb9ef70b576878b8bfe4407e075f1a041a03cc82fa114fd11b56873776c3d685bc961e9ed03ba4d4399696ad9251f95815162f42bb50f9c31017094d38c520cd78ebc10c051935380f7217e43508f968c5e0faae871ff75439b385455de3e6ce212d89964c77797895570ca790941f8d22041ba6d54894140737f2c2e3296cdb14815232840233e509cce401fca0ff78440da93dcd9374284430a504c65cd7ed8e64827c2661820c9103f0ab021f67e1bcd305401f62d0fd55d44c4886365f86a0e5fad49794ec4e9a08d8b61c12787cd2de3ddab6b8483b0cc537eb1ae05d5b7e044764053d6505d5e6eee82446fd3c161e1f15772ffceba092e241a0f7a93cfd0412a91751422b08f2ea198cc645146884ba2804d3e5941aabc82ba9b879831178c8640913491d2c0251ddd5a3fed3daffa6778328a98cee0d55133cf9cca66f2a53638f23da16f7c8f330cd499b2821bc377f20ff73c45693f364b0e215ba46d8d85280acb767db73b12a793449bf38be994003428a7286d9b91e40b84c9fe83274c66413e2c8ed3cb2fe826fc8731c68ada09c217fd61a49b962d54292c246fc11ebe7c821e46c764ffa9b53bff79e7ad1b3d20e3bf1d447e5b7024985ab7557771b47c8e518512fe86a28e671b8bb7d2312d54adf0c8213a6d2f6d3e1ca6099a5100bd610c2ce93f5bcf4884e3216026a428f8787acfedfb0c9f4f401acda72df8ccf64d088bb4df4413dd365619a107fed82df0b4ab7efb502ed5a3296452bfb9f2f6fb153766ed8cf42b15e741925c01441721b6a3e9d875738f58bb68013b47a7bb614c80860311fed3e58efd02a0362ab0e938676db6aad819f78338d2130f8d7012e8b5c5d9a53e843c7179c20d7b796a02aee8c448c93832583c55318b00487e7e2dd52c108eb5ca88722450b4360ba58de5bc369c11833aa22ecac51c3b21ec942387ea008ec02eed9b2c945b078262bb741b43471e8e6578b0b81a87a20ca1c9a520ecbbf9e77a9adf5bde8a123910fd80608890c301b7d4aa9e5b0a6120437e3e9e3024ba6a92bfb67451f6969578e639b8df8239a533af34e4cf5f7963412f8651507c231f46ec15a619aec92bd7063892ad9f2f902d34f0e93f8af976660d65ee0f5eb40ce94804bc7cb23b061e6df10a6e872034e33e3db4c4f5c60948aa2f248d388df7096ee98b82f2b12d8e2be1d7ecbe8e8ee5b8c899b29df04dcdc6042241388bd75427cba62de0e45808f58ca858a50d8fb623c2e4d53d93e8b932e2acb2d96ba10a632c5e85387d4d6b3f3ce16bc69a84e5fb11e26bc27581d379c534f9f260118ef9c41b73372ffb342cfadc6e65ea6041249a8835fe086b6cf0b0626ad710f437477f1a98623e81c1b6d54dfe3d78a3f954f1e350b38037b65c31ea13491666765b9748c0d7c402eca5ab4bf807af0f21533f5b8ffbfb3cebc4283f7ff63e943b91238f5d104e68af485ac2b237cd20fd092660f4912f795588fa561f7fa12936aaea07c810615088259321f542dc3e2846e211eafd7e141950703868689165323fe512de69ffcbd56804836b7cd706a0d6930e4d2b046c430a934618ec8b83b387363e241102b6c2cdb42707ed6a9a05d1d2ea544b540d89981774fd38591945c28b5afbe896d0e027d307bf6c67c5a97a260b7550a7b431a04e43c12f056df9d37b655b52352c93d0f88b6950936e9d89dbcca6a6628599942e3cdbdd2e31634e42772b9904b9c3c1902133f63556ca40869e07ea6cc34d5aa0c70973266190efbb702861660242523599aaa819b50aa820af018557f62092ff08b2e41244df95694fcefa67a8e4272c52a8936f067523ae14d72b88ba7710980a1f819f9a90b3426663f10d830eb6b5ccc60537d6d47350cfb6a3f5e1d20a843645fabbb033b39117e591f0cb5013f7092ac3336bd78fd3d72f72476811a4374834451561d62132b04e9137ee33222bbba93b238f399c4f064101cecc20ba21da38f5d8e4302d16421d2e574019ab61f4a22cad43c44d9e977d39f0f1c6af59aeb0e98d10962bc10c0d6d8caaf2745a43e7b4e41d938cbfba3e94f4e444eadb0758ae6acbc3f73148f8c9f37b44c42dd089368b326e5d375872e2e75291c1271d2cda4231e62220feb1187cd2a05154f027ce082bb19a734f22d161ec6b6f34be8deb83cbac3b41f4c8b6f5cee37c98b22503cf2f1908cc9b9f3565a9742fc32ac98e44d3087f6c7f729dbf19c9f96aa116111df2836b7663211743487d270129e17f4723ea2ba3972e006ec5b5010299855433fd8a8990cf9ef01ae8b3991ae32b357471ebf6b6bc142e548222bbaceb532a9116018467fda32e4c04f7fe75f536ccd634d8bd0250687da97eca9ebc8d44359dcb299e367d5901cbe25e9d3ef81b7a1c9c130feb324e34ed9c5ca328e3458be6aa6443c70accbbc85b7ad19356e71269df1ec94ea8fb0b401271feb29f217c7c98f63a012819427046b0fbd3255a30843e8cc9f3eddd9da5e9966b6c4c594070e49c2e9ba685abab044c61866e1513b42b677812964433631556e3a63e00cf037104009e6e68219ff10abe0678f6a65134be557a605b381be83d4367d280e00b579a2a0982286bb2e2cd32950d2376ee90e2fb793cb1f2cc541b2f8ba2f4eb3b225eefe27f4f378e76688132248fca6db21f50a4f3c6b22d43886e090828f77be192ed7e77ba2871b284d3e843fc9761ea5347fd79805362ddd592d186a4bf84d27dd0732789f421cc9e7da8bf3ec6a61b1c27d0404e4d205e241b177b85349f7e7e70d55c05e621b92daf98aa6b11dde1139c3dc01636266a5d317e1c07ede9216be2401d53d6ed70e015ede263187c6975c7f32e96615370ab382b64114993078bf5163a45bca6a0edc095278346ddc067255751ec2435b052ed190d01912698bae45721098a72d64db830b4567eef158bedb4aaddcf9b411628daa40166f033bf600628d9926e8b7b59c1c63d27ec2b99c11b7d097ba7c6a2cba050ab403e987b474105f5ffb7ca734bc90e2fb871b0fc73f60a722cd9a05c162922281375146c4ed864ae8b3ff9a896892c3cbcd06f99919e9440691be191df467d3ae89c7f686537961ba101a6cb5017e0bb1e8e3d36c089bfae85f85f26cceb7ad01bd8f5e48c5d6f0b6e3abc5eb3fd2fcffb9d6504f62f97ce326b93ec51a5b0d1014c11eb0980cf965d0431d6f70cd8e669d39d885b56ea31f223a95ce721d2b7e6d089f457b31142bf811c99bb7b3b7d3585a12ceda1f62ff19fe6894d26d4044cee443217fea3923d1951e330101eef901fd346d0f94363630b86d57821a243abe293b8954821361bf805c1be4138fbfe295d4712c11777386c3a2d47450c4419c88dd34a74990cbc6590d24763d4ada8bfe25c44856ccad9e96d7680bea043151d935b1c2b2e30579d69c6026e43cc067aaf6aea5d72008650cccf68b101a0ab12301c50b2d9df7d9b6cfb4d521a3295eccf1794e8bd7dce5c269d457976fa87c02ae6a9c3eecc851c88ab4bc75978937683e9a1735917e0b8c5b6ae1e463f94ec3266350b2b57c9b228aa2206f58b12f11371d11e067561695776ea951b54b467e3bb55e12b72c092abc36467197ee0b640d4ebbc873bb2c7004820935914176913b82ac0a18d892a0105dfe0196de2749b52f63e7643b1d38af662b49979b9bbb9f33d6874d987bf083bc3e8740b974334e70502b4c88350074f6dc6a883a6d7e8638b2582636beae4adf7f2b601fde96aa02ddc875807406456ec33874ad3b2a5d66250d05bcfb172ffbc015f49c2973035794fb5679c6ca8ca86b7344e2e1065085a9ab18e00ff26830998d4f84bb447c0c63581cdd838af510a7b90a0522af6231469f670295d5f3b80f03cae2d5db9b8e65154e4910584ca0e6fea84f5b945acaaae242183d2d9d794690333828c30bb056ded4a5afe43192174158dba27df9aaca985878285579220d4a6ed25d1094d81d45a66d0128b3d31749391f55d923640ad893fe99d67708b94f2e8c46fbab3d54d0a109d25017e961d73e078ee61213e3d291dec5ca8b3bf0e8bc2bda0ae9f69fe2f9e1128856a7f60b89e321b1a5efb324d524880cf68c8b1f77989f7a5e747f7a67542cd67a2d6460bcb2641148a2b07265684046632829d7ce05a750d1802f6929b6b1c94f703ae48e0c53a81a1644c6f5eaa9629c10af02d19db01ae1199047133012ebf03cc6a02caab89585f40902a5207bb9a143c715b05450c86029288cf7a9644eb1a04a66f7d169cc0a8188849c07bb10fcc71187f8f2427d8fa9e9c2e0da8bd437f80e68755db626b25a0a3ea214a1a812feb6378157b43365bc01e3023908ff62e217b4b299394324c055f059a05318fc90f7aad4e5752ce0b6c772169eb85a42d10873641602fcb2abd6c4c7eba6d82e0d855ddd72688cbae6e36dd517a361575d80471d1151b9d304a2f9b2038d6f4a244890265dbd226084d8ee2a83bafbc0c8ce2f052a912b266fe4cc43eab8d8499ed250db22b52798e68db56d2dcaa1a902ad315af44fa12905de5b154926077c9ab21db89114122b3abf087223b7f69665777e72fd12cebb6f297481e8dceae4e19980cccae4612521be4a136f27f4f777e1a2776e5c5b0f3d3ecec2afcfc3461b8ec4a8473e36557e0e7bfa163579e0972b8252b59c20a75ab902934ba9d5f2457b8fb24dd56c893c4b3493f3bf72021c933d24f9025f13869e6acaf957f65e72cda9209ed1c23d176cea4d7cef943d8cee7e923cf994db2e55fa1ad3861326493786de715243bff89a4add9ce7f82e513cfceb19d4f3f3bbf77bfdaf2fc5c485b8e12a81beba80dccc502704b06e631d94612f95b9ee57b58339f32b09d1fe370ce59f8f3e31a8fc98f496ff4bcd2cbb25e5c25189e9d25204b5bb2cf507409c9a0945e3b0bc96cfb2c11d9b924db799fa5d9ce25daceef559b6719c8ae3c1878663b9b609f5968671ececa1ff5986c005900b2a000cdfb8fccdfe71288f93140f45e09e44d2045a0ab88a4ad4f8511cd694bdb1504fce950eb9eae8b74d65afb23d8b4d01536268403c50ae1dc2c68edf5ea9560db6f6443ca7f2086610ea04a0aad417b9fdffffbfa34057cf1bf3fd955f8dfab3c154fc09f227a91bce4175af3fb14925e7be369d032be1202afe4747e27d4cbc8630fd1d3edc3ba5aa30d81d7d712bd47e2bc50d31295f95f5f6b547adf88c479e16b79ffaa6989de71f6c24f34f2bf1863f0ba7f6158ad5f9c4d1f4a34f20a789fbff7c8fc39fc921238e1a7b78400cedf5b20d3af6671a4658f5cd2fd89264aa9a63793e37bb97cd5d81937ef67f2035342cffbf28bf93df2f3f2e75c9e3ce65e8cb1c99edece5b534a7510b73aa59452bfa15e3c638816ed1943f4b7670cd1de9e3144e71943349e3144df3d6388f67dc38c21da6e00c0a0ebcf18a2ebae1fa54e3ddfdb81ece25b2fb571b1c954325dfddd7b6fa6949ef4efbd97d2ef746fadb5decfabbdd52fad18e31b28a5743c80689f40b6972c2e0025b0836e1b449fab7bd88578425c8827c48578423c21fed62fcede271a858e4742ea50a5e2c84b8bb357eb90f7d570298eea8dc07bef176a930aa6163d1a81380fc118e7d11088b1077afaddcb5f73595fd6ac2049f4215dab5b7a6f0a2e2bb58173285651a403bba2c79e7ff98a3ed20128a8e0fb237df4703b83dd1f39428e1278849e083533d4b807e69c73ce39b3108119745844d6d72d2b8e129cba5bc022af388eb3c35182231a8d4853f4fff3b7d6118a522fd75385eda65dfdfa7ba27c5d449eb46feb3aa0a8e386b9eef04fe6679db2e22851b9657ebf8f7d86141f5114ef0a3a6c00df3f879f77f7251bf023e6fb9225f0a8f9e8f1895033420e9266e6e2944ff46d6fe78d3788434c62d237f88598b4db2355105388e92ada209922eaf0544629f8da156857a308380b2cabcbc6d8ff9cb5e987e483a7d3575dd4461d8d3c0fb53f93e9f595678581e089fe176a134843188a2be8f0deefe3117df347e5595fa2f2acadafbca4579cfa1275e0b2d6c0b9c45bd66f57979812d3f54529d5f5ae1a13a7f06c00e64021588860cc4b9a3c81d377d3234d9878a109124274c045d4a4c90ee1abc99026250862fa8a34e9c0e7850ea1d0b4ae810809ed1205165a3412852ef99049a0431cb2145dc43ea02e4670a48b970746a73fa1fea54937f896d0a52b3e1bf48b11ac85fe363dc245114db85801e882901c06173b5074cba6477450f647854e8bfde1a0c54d8fe892e41881470901214e1ca7484185402565831e73ff7925b50112aa033477cf95683a93ae8b910b7d66ddcb74b29a2d7544a843715c1b2d630efeb34bce395759aef5a6f3accb355799c7a03c701a71c098a67381115dd45995555911facc3a994ec88e0d7b6ce8f303916d6b3498d0e61647106d2a99c83a840b3fb656893401d1023d2cbd89e505dc2a7d0bf78696e9594820e5e925e9ebdfec95bfd9fa6fb6cadfec94bfd9e2dfecf06ffe668bfec6fb9b9dff66e3bfd9f76fb6e9310ab4bf890ced8dfa2452d7106de088147d3a3c25bd2fc52c2c267246164ff0b44a246df9cd8ac52f8c52d4140d76fc8146035d9da7bcd8dd9a9a1af48977b0f3ffee304a097de2ddd368205bedc632c633bb000ce089f9f84724fac4bbefb1ab539f3435bb9a99ccd31755bf8e38b7300e737fb9a78a5dfc692e613616f4afecf324a0d7aa63d6741ddae94a599d6c7fd516c96811d446fd15188a29a21f8fa9225a05a13efd2aea9b356b925d3f87d5e44c0aeeadefd50bb3ab4b82b55ba5c79af5b5f6d1a528a6528a78ac198a6af56bedbe6e485e976f415d09f52ba8db1c89df3cc98fb3dc0634a6082b76fdfa225a0dc17115841a457fb1ebcfae656562cb9befabb269118f8867fb5fd87650969ffc8faed6fd7ffeb4a9bbbb5b7777ffb16b3468dc682cf7d2ff34fd197a493d06054be3fef7699de36dd0a60d5fe33317d340038d6babdf9e19947ee0c13e29a594babbbbdf0e709949ef3f9528c62805a2c251844979513969979516d67d8f712f994c251652cb8a8b3ea9bca4c08863880253a31822d5f71e994bdcc195e11ed80f424a71544a679829d69a6460d619f603f7e0cad0da636830e9a0dc94a4aa510c3015a2c4310546e5459f565c482d25966f9f9f5d99362db5905c564efa4505266544852930868a3e8965f807a639e3030f64745092af8a9132533e6ac37eb45a6c00d9ce0f520f6aad0e83dbc1a714c3b77acd1683210bcdb0cf8c440626032bc19ad9bda463cd5c82edfcb2e60ecf56edf4a85ed654e9b8ab5ed6cc2ad88669626fc4f0b1d6c66a8feb2a19238c1b3b3160559fbfe9ab6c255b2a9156ba1bb1124906a6b28d400695cdaa6cb6c4534bb19d75b88f4b5ddea504f2d1c8415b1252343aaf2eb99d1f248d24128dceb2686834bb1b383760377a78b8e143a3bb7163e706cfce3fb34f1add8d9f9d9fe45599b3f48ad9d5f9f292d9b12b0f0527d867484f199f18b0157c768ec1b3f378020b0662d43c263fcbd31626c7135a3060a32d01c4a0f19f1e3c91a3fdfb2edcb45e1e93a37d9777e1a6857fcbc046191e67e187791ff861de3ecccb8f2590fb2f2f8fffa675f298fc9646975f060a346db9d076fe1b63b6f33fd167e915c6f69967cfa384fc20c9854b92eb66f4e152aeec6e5aa498c7644c92784840ee244b92824824216b8e2c4922d148d28c0444a259d37e064195d24be5a965916e1e93ffd36fc9d2ca4eb7b223b99c45da952497c7e4bf6965d2cd9af97528981d90b825dd76fe1e92ce59e3e727ed9c05f3f94b2ebb327d7ed2cdaeaaeac763f28b0f43853e55403bbf25551ea9aa59333f38961e864667cdfcaa9f14abfad93918da4abc90ec1c38d92bb67aced66a67744e98d4ea3647c3c4ae3c1976feeb2c9aefa3d191606e1a9bb96f404bfa79b7b5d6ad4d90975dbd563b3641767cd0fef489203a9b8a3b6c82c06c82ec9c34b9cfbeae68bfd034b69d3f35a3d1edd09735e9b97536150fe045896213c46513c4b54198dfd804d1b126dd364176484fde40832339fa18ef8f7fd38221471f308f1f97405c1ee66f5af4e57139e33ef0df1288cbe3d2f498fc3470d0e6ce7f240a111d977c794cbaf8b8ff520229f1bc8b3ef0bb94404ab0f797c7e42745a05b5866c79a2d1a9d5d4de0667b29d363cdec42caf0784cfe17522645461778ea871ba56666067564c685737337e47abcdc9254ce057d804ee08fb32cf6da6ca63693ab999931c1ccc5714b230d31129263ffa811bcc7aca9c6e26224bc3755833e71edfee09a9b585ceec5429fb876bebfbfbfbfffae6123a924fac4b5215cf3b1313586793c66a41b05e1ed704fadb5e66aeb3163daac69333de605dfa7f5e9f46f9a33333516f7e5b46e67ee1a3366c2602316faf445e1b8053e398a5deefe7848f8d4984dc89026786019466d74a1cdccc426daf8bf16b26bd7f75c2c3b23809254940dac12a19750acc75155d080846841b53beed083ff3fffcca6599661afd7e797c78020e7ac027dfe2bf67abd6640fe45ec13c38073b89c3f671960affcd2d1e70701d568766591d8f32df5fb4276154413b5fc302ea9387dd2da08b656ab793c78d46a351eb51a8a96637233be3f0e25d77397e0940c326a0b1fefa37ddb8bf93eef83813e692d6804cfe3418d7cdf11faa4b53b941bc162962a888c60bc8cd3cce1f7beefa32daf9ea38650ddb63c154358635b7b63a0dda162ddbab8c3affb1577dc7bb1b803678c31cee28e9c73ce3bbced0faa943bfac36dea3087599a4e5763e58e1611e08970f6be941d5ede78cd2e8c62fb81d094d225f4d27bebad746b213e10fabe6317b5714b039080521b4e7180dbcbd5463cdfa5511c2cf6c3987535ca140202f3e058088208629f1f048ea5ad62b8c73e8d8964506339e7c172b91acb2da9af4cab9f041352cc20071e8478bd6ed8e1000c5d2e5701203c15a82e6b533ce8b3c692a4e0af14d8f249953ca047f55c2e9773393793c5908213abe0f2d4180c32d414c05eaffada395763390c8315af2530dc050f56a1e2fabda61949c07be2a07b468b918a9aba613c138001fcbf119aa6a686efdf98ada6b3167853a111ec6ca5cf72b1f1f001b4ebd32bc301937d86479e80a01ec14192aa6bc5f72b0edaf5f384d8f6474275195e68fb57c5b61540758e9b31bd725c006dbdc7d43fddb4469b9b96f737ad176acb1bbfd3aedea22daf1c7d78fffd570249a144c163eadfb4acad7e81cbe518c14b3a3fe20593333ced697d5eea5f1ebb3aa9931db3abfa2cd8d55823428f0636cf754fc163eae7b0b6f2f01eb565eb9f34b7ab1db32d52bf5ad64a8ce25cdc0976a52c9c94d80d8cb03e76458fdc00c7ae5e767d0b24b333cbf256fdecb68651c71ed6ac66ae6e2f04d6656196c7baeccb5a6b6dceaa405f955144571ea0975d7999ffb3af2534c5f1cfba5e2519b4f73c5eadabda95bfb76f79aeecfa03840de8933ad1a9cf420528a5a7ae6e6d0a28388b5a1b69088a89592c168bc97eb0a0053fb118b53103bb05e83f62b916a3c55037e893defe76fb31f3e376a3b7194522f7d4101c671c179c8134b006da7e4c3142a14f7aabfd7cb313ed67326ea507903e7d5d43a040680ce102acd582080912d544cb49205704300c99b55a2071d12269eb490f41b096254718f80baab061d6b2248d0f2d30b09801d7b2648c1cb4ca293290c4ad654954182df0da4a3d51ca79b33b90d500cbb52c995ad26ac1d62a7ea0a684be2f8f3a14f92e0a8618ad07a3a498b95e19658587ca803e33ae07087b23112700620a21b66d82076a24075a040d4350b12b18553481628b25f015476c1c9d9d9e30463d4c70a29623c728440b75db7eb8dbf645d70f14743bd125be2c2bfc4fc481e310383ea11714c715751ee2ec9424e26b5b7176d2db496f27bdbd6eb7db8d07a6824a6228e3e4990fedfa4c684e6a383bba22447c7a362cc3340e87cbb88cc3651cca8995271f29550b7bf2eb76f9052b618cb30223a1cf8cc3617c2fce8aef7be1dbfd408105639c15d8a5779fc6b58830d18d5b964fea8a540f339c450d5161155663a0eb0401010e1020a91ac0ecea0c8bec844784b56dabacce9c55c4b2446f3f04b2acd1db0f8fa021d42c0b7c1b92208c488f9662028f59fcb8e5f1090b7e664e7a957d403e5f65a254074632d417f6e947353d81281ad8023df4e0a27d18638cf10c139b1863ec79175fb3868065bc140efa3431be33a69b9fa69940470411395c0e87bbd574301ad0608783cd66475447f4a967dfd027c383199f0c0f66a04ca6b166fa3413263bdd4ea7cbd9643fc40ff113fb89c578f24b16628c31c6175f4cc3a1e75d7c710d8f883e290d9fae084a1659ece8171bf26837e79c2bc618df1a3c88904b021880a6468d5413354835a69a278c99ffc44972e05a0eda6da99e6bd7b74f6a4ce879817ba007bad96e365b4df6397c0e3bdd4ea7cbdde8379473ce39e79cddfdf33f9d4ea71c7f729d5caeaf3ca13ea0cfec028914b9d7dc97c83ea92de7d9ddb183a211514491c3e570b81bedd34b7e87df61a7dbe974b99b6b89256eb69bcd569be99a682287cbe170b71afd74432a9c0aa7da42b5854e25a412cae17238dc8da6b37d101f448d56a3d166315b1135e5c44ae129125c54101e7739e7d3cba8bffca180f868417ca82b44b6911370a44198d289231329291f95510b9df3e757e2bfafb682720129e56572d3a74eecf35e5cc3355c136dd03456c11283962f5c521938217941ed00a36464821a9ba4503f317c50a55e8f620199828295634ad40f1d8c41326cf00095830fc63066a09e30472f6250379951063484a811e69c615e83868c8d041cf919fc0c9450e28978225c5860714522914854452291e8ea1a149c75b21a2cb5c7a490645708bed5c1e0277a146a08a292ec805a71d220695bae65da7edfbb8b441fcda140715e28f3981b1a893da17a429f7a171b1afaf4129be7ec9e73ce3e9373ce39bb995d007f3a4da1cf995a0d77775c33e333265b123415121592996c2693fdc068b697bd2cd7322dd3f22cc73e6d5be2841337dbcd66abc9622fc40b9179322cc3f24b175341a1826297832951b2d3ed74badc8d0926b00ddb6a33fa61dc900a062a18d00f36a4830ea2bb3bc63639368c437777cfe5eeb94e3ea72cdb27b5d1bab3dddd3def5e9cafe7b94773824459e801d7f96d93aa06fa3c611dd69d26d3a75d4b32146ddf26272827284768834ede6bbb51176d7284ec2a476875b3c9b1d9e4dceed327726c9b8a3b6c72909434ac95a66b699323941354ebdbe404d955cd09cab1e520b126ddb5dae4d8ac996393834428a7669353cb09ca09caa165974d4ecd9a7557499b9c206bd2bd332c0fe1cc202424c660c40813426a35951d74dfafa10dad3f8eedd6fe576aadb5d69af6a54e6da595524a29b5b4de276192195ef0022d72405f30fb012816e78d7fe301a2ec5c9ed94687898d0e135a2dcda58d0e136bd2ad33e4fe363a4376e53a435b47a7e3c49a74bb7b9edbe8d8e8ec3cb4d171c24427e7363a399d219d219c356d7472d6f4d24667c89a74c772908b31d6a5185ab37e186a8f3cf9a0bd7ab266d51f0e3d6c84b64f2bb61897a0f751c73557ba6badda0bd8fe3648c5fc3d68057e9397d5e57939cbeccb7e00c3b647fab0a63f0f6be2bf240b16cb9c35defc74e5497f42cbb33ce9692b7b8f3f87fb398f3019ae9424ff1cce1a61d1dfcdd236b7619c688cf18f5ef477f4e5b5a6e8a9a8c3a4365c54020f6bfaa7e8a047f565a6bc1705687b8f4fa6fc609541b7388abff237a637a1e557de478bf8404adf22963e564e16eeae2f970f26faa4484c2f4f5a0bff86b37d9ffa5b9ccd22b747201580f4fe22d802f8d7d802b0bc7b25c5af678dedfa555421fdca9fc0f22da45f61f9962d56fd54dc71b32f0b77ebd2665141a8a1187e0e2bc3aec227a1e06c90821e5e16d2449248ffb72cda727114c51acb2ae94af8e1001c26ae735541c43e298ee6b68bf99e262ae4dad934b6631fb1870bd463806cef47f8475f4713fe845f006de1b860021260c080822739fc30d422b900820f458021144507224ad0cafabc3ffa50c462693f504118bd479e9508088e6ec213ca8e98c34bcb1bcfbbac1a1be35fc5efc50b6b6992323206975da8e4acd92b52c9cc8c0000000053160020200c0a878442a124c8d2409bdb03140010648442624c361ac782912489511004510cc0300060000380310019439132c407151766a0bd1a507a78ba24b1ef75afd4550f328e8ea21b544ada45587c1a8df7afba5a1ade1ae76c9adaee32c2354ef53cbe6494cc4f6290bfc0c3b8e3f445ef1093793757f4f87dd7d626cc980706064007f5befae2a5e18451721af138a19076b86a17a48f57e0d9c40173aba6b7aa8b81b3ce9bea96724772734a7561de30f6ad2a285d3ca1e1deebe01b74d7c47a6000fa02068f318927899d8a7f4a33a7d7800c88a7a9278442a4d2cb8f52df6a441bbf4504ee7353ac0b48dd278268fb0fd3acd823d8ba3552e959eb3f08a03df349aa0b7ba3a4ecaa0b01461d1beb92a52fc764f2788013a59c5e6ea9c45d653160a86b73eefa270d626eb04bc304a196cc763b82e28dc8da6043611930de438f4aab3255582e372f0afcac40e71718f974b147a89404c35457005d7c41ca8856c478d68aa67caa1f4023e8e9b339adec689cb7ebbf75e94bffe046b703ec53cb411363b9f047fbe8f1ceed31739010aa05b38f2e1d617b5031f7e90897d0a01350a7fa33b1922d2d39800e3b3769b3b1d801754cff9852d7fe5d3303986ef3d4cf4b7bb9997adf449409c08eb0568f51f374b93e63ecc8c6e01968df87950eaa239fc7736d91b02f14f76090a14c0bb9a65cf2e106c954d6ee2521d9cd76af6c0c34757b5d1a15057532a0886deec76c5d7e12f4ab88b9319e653d5ae9f1a13da886e8d17c839822e631497533454aa6eb455dc0737c4eb3f0033a2761d46c149ad7259410a6fa703058bd896e9291d49a5552faf105bde2f4aaf80d834c5e846146cfd797af3ea21386cec7981657a521c3544db810ae6754eb2901097c3449492fb64ae4d0bd63e0b8ecc3435f768710d31c77e4ee5f89a56fa2c60b5894271d71f1c2f35e73a7070974490c4bc9151a530b55c9518002c0cb0fe4b48437eea66a1d208cfba57cc069e7464bee8af0a182e5e9c4bbd932686df89054aa0000dac7c839c690e17d2c72022e338b7aaf430ac00d8cb3a69654de904bbe70a02cda3b6aa5c46189553daf6aa771c8b8371901380fa5e635925eeee1f1ec52f45e4ad4708cca4187735467d5c6ba9584fb1ed264c20173ab1076d585c0a1ee0d74a84e7a27b10ad3071b7dd5f554fa1ba74cbda4b9e77adcdfe635e9d697b76a8dbde9a7e5f4da377b6fab079628d15ec5aa1d8f8abb71c8c86be3c12111d41c5e1a95709cca7138b36693eea3501c088a53530d4ad3acc135b44d8b3934403ab286c268d60457acf47369d830ed3bc9c24e98bae6f0a4e401c44ce054b136f4f36341fcbbd48dbd08ccdee11a63c3b8c0bcb107429bcf0e6c888d360dae5168b67487268445d154b86e8dcf1517ed438b2a1174e0042c4633d5630f1766a80543535f6332cd0da666f327684686936de1539910c5f224a17e0dea0c928746262e71f888965a013a4811d5dad8a5eca2b222196084412306f1c79bb889c1ca74122cecd5ebd8f581ab6e6bb928c9d120244abb1db722ac382b2ab12d2368cd1326b13794acb7f17b004d31d736729db2a6d57a9b1047362a5d8f26d7d2d4b4badb08e1889aa00461b150827cf5826b3c1db886d8fe230635473194c6c5ef34667bb439b52b341bdeabf1e3609ae2564b93e3b4355add5d136ad14d562a1766f40e0ea643d23e92f03f7024bede7804412c5b89fa63a52f380e6cb0ed93f1fc78af51e75b7bb0987a6722a9ecafa1d4fa2d7d6b058bf4adb7bd7b97527afd895f1b253d415b4b18a1670de3b1d7139c0a7324e4e58d881a5d873d1b5b9951853d506a4a9038f1f7109b36e638ebe54901583fb3e4fc63eaf4d0340090c90919e795b768c7c47cf1c8988436e65904d171065a20196fa74b0e71b6018f8c3298e319268b2c9e376217774520f725d9f92bd63407ea9cb287a7a6cc14ae0691ec4d7694d20fbf83b6da1ae90574d274668c6c1f167f6f3fd4aea762fc13b1e219f53df5eaa7e1883807985726d32d80248bba211eaa758c5fc06d0dd5e5320b8a56e237706d7889e3f26cdcbc4c139e9b5fcd762dd560cd101a7e4f917ef0359497477690e4890a79ea0eaebbcb66a72c9009e44f620774fee5e0b2e2af3f6d326f424f2855517f94e7554f20ec854a2653376c1c7cad67a3633ad3705e88a094cb0ebe11597819da7fe0e6d58b6fc834cf429063bab198c6f23eaa26ce1039553a442bbdff4135beaad75bac9df39be694ed20c6e2bbe802337282c5713b5115efaa8a1dc0eedf8536a7ef8bf666ba0a7a39d0a169c57bb0e0172498301bc6aedeb05d5e9361d2796492e0574d25620f134e32a95b7f5dea1ad3f928d4d42e624c3ef42cdac9f0254e82ce0fe1dc52ed340305bd97523500a7721dceacdcacbbaf6f85d10a25fa8b18a0f9f60e4ab5412ec16afb4da3a5427b4797689ca735a73ab06e29f4ae722d60d66133dd421ada99e6ed60cda3387cbd0523518f96541ffc93aca6cfc683bc5af61af4f1f4b4de36d30d2ddc451db3a903eb964aedaad702469d37d3457ad721d1c4767fae4c695825400ee831479767fd2ac00f89d5cda0a7356ca180a14f8f5f00ba2e12d48ff9290d058169ec6d715abd86f0f2ed8082e6c2ad8979711ceb00163050655f791237f4685e38dda60fa84de87a8b40b6348199ea83cc304568eb11b1023d30f78543696182e3c7cdeb21554cf7e80133f03d6ed597a0f054c0afab8d34cfba362c75ef604bac4a36b7c836c7936eea087ce5d71cb67814e97ef72ac1e968910eff91515b83c77cf88727c9a5e034c9a9beaa39ad249400cb7ca4955beb792359330292dc9da27f36f4a4425317d3a2576624db503cefae55ad129f7300fcc4067424a1bf7954cf5f78ed39685c6627aa129bbf25fbd4bc297bfc20f1df146e8f415a998090deefe43afef7b18d54c156e9888d5b335d9a3495d3a6f13284493291c9c341cca1f34fcaad318a1a0cc0337f324fc1e88286295040eae7d0a17cd6d81bbfd7b968c24d104049e6a0c8b233b7a92d685db3e31dc311d5da41c81a01688cdf31067377075df45fe955563162dcb8a30e1c021d20585b1f3ae875ec4f65215c2dba68988397b7cb5fe51e60e9442501d677ca3c41d8f6d2485e09f726473b48db83a5c5fd991050a6f96807931706436137ba810fbb137882947627e172b0550af3dc057221a4ad8ba65db9a688af68509954131f392d852d8607534cc0e4d23bd8f8f9c7d5ec8a8a1c36661dd11093307ae90cd788d89209d22b021d06b38e35430cca42085d4546cde9e610d304a93688dd14a42393b817eff06f49c9bd6014daf255c4047008964a161530a43b8ddf142bf34ca735e08d7eb1d0cbd5c44e03f75240bc1594b665a1bb6ba9aeffe53b1f3ee28a9085b9e26b13dd8199eac284a32bfeeab5e4f3361ea3f67865d13d1473bf771a84e6dadfc3dca4f32d6c1cabb917c3a0eefc11781898754463c44826b8aa0484dd5400fc8d385079f5afbd9c6c1b9c9e302a1077434744ca98fa6670eee238e136ae64ffc007feba28263c47e95e535697a4f9343600c06e526c43c0926deda280c6b3bc0078bedd7a9215bf30ff0120c998f7d4cfa0899353e0496c1da6e3335963ebc660f23217234568752f2089d16420b485e525af88915d18075835ea017cc4b3357a04432bb6f131486d15571a46989ea28ee4bc802c946b3f0e09d937d342391dc1777375139e4d5819b487507df694d19ebc12565c7d07b914b14cf7afb99b5988a7dd0b4a0ce13b0319f48cdbfae55b31f47fd18a324e84d29e142e2c904e5dfb89127ab48332d59f50a6650eddc27dfa028aab5aaa1f3abd968b7b622dec6dc1811dc05074556f9017783ee8f6d1082941a07e9b1cdea1b7fde178d420f90cda12cc599f33e01996c36b2e41486207666b802328f424004d9e2712ea0da7f8a3d4c5ad31fd2d85756a7cc7d19add1234834580240814dcc419b4e871d169001800a8f0e2442610cc8c309eb215f51f2ff090c09c44c75cc955947c4f864704da90935432e0a6808044d3c9e9440f0f54bf4a5a71b3ebc9b091fb256c7c402eb6363385559935599c250ec62081530fb71f8e203a96fbe6503d887b701e7d3f2d1cb630cc0448719cd3cfa4abb5875c033720d5dc7e9e40833eae3978b227d838c1278b4725038f422f3c246b9e7bc8a402aae697bc2b0418f6a528c8c8a3a8eae38dca8124cce99910bc6b12122e3c4c05b4ba1e506d05698e3318ad661fbbad2fd489a4894e4393e097d913dbcdc044086dd51978acf63230286a213583fcb1002cbe7800d845029ab20dc9d7d707e17fdf3a10a337a98edf2830e9ea608119223967ff6a71919da3452130b5c2ae46258152a2e28b8fa61640fa7b6d3b04fd943e4705d2c7ba092d310791ce04fcc303b23551e106f2ae360faca308369f4ad56348869e4cb58b23f6c9ad723ce77efc6a1f4bc5a7b2c5d663d87ad367c5e513411e67c61a9165e612accca7b3895b6ddc37f49221ec4d73573284b82f7c386bd737030590f94098b3a35acf39f730f43e21e0defcd0d7895c2c81de9dd2e96cc4890e5eb3728553813b11f6cf4a6d25b59c43d1a2fae33a23ad6076b2029ad9f02e2f58d0c477481abdbfbf60a2bdb73ac2aac3920d624899a7b5214fd3c940969b54f46583342240a51fa908c76114c537040cf340201572367357cda10f7cbf178b850687bf23c2b2508acc0a4739aa07fe93c4edcf3ab136b7d1fb9f0583bb69c353c4fd57fbe2ca80a9a33e8a8976a9022b79e08dcd8239fd089826388d80d2e542a35bdba874e8618819b558ec2a83be682454cc795a2806d8c010738106c192924ccf352623798b0eda9115a0c33736c5d5655a30adc7f9fddc452c56ed576f0e727b8fd84ec2aeb482b07c0479c4bb89c32a8e42b9f63db211a8acf5bfcbe25efc07963be0f2e01f085bfeedfa2e8fba1c89e7ee590a7f4a778c884a73ac05d05e42515742e084ea1e270aaa2a1fb4a3b8b0094a5a46604ed863166411bbb3ce08e909dc6bec72411d2e1540130b74fad735d2c1f7b76a30b7c026aa17fc993d550a0e75cd14688d325d3bdb16456ae49b6cfdfa5781929b0d6ebfa7787c7f4eb659894ef5a3711857a27bc19ead01d7604e74b2ba82057253d8c6bbd33efd9154b42f8431fffabade9891342e8b8e85c2a3adb1df83eecd46215e99aece6a48f7cec2b0547c76520cca666974177d09ca54083144e0747af5db462f4785f71b9d45e4db5b57a350ea2beaf6db199735f3751a73c246f6e137565953c468a16a638d1a49207a0c6fd3246cdd1657bc8546b8e19e4c0dd2f152ffc78ccc3846a5a303a76925ffccd09ff143796f46577a68a89c15e433133e9dae2e6906c54a621aa178a235492247bc0bce38413f309a7480223f36023a23ac6ab8c345333fa904ec1caa3648f4720524db3a2e993fff49129cacd2f5694b2b0775c9da4d4b04c32d500a379828b280b90d6a302bf5e70ad0c96f9858a9bb0d3accfe295d6d721da54d319a6b89942ce7a1bad609ad92df50c0a8544bf9bd0b265bb859e6627a096f1cd347f036102a650866c581e843e9982f998af9ecc72769a1917e8f882feea796e142bda35623b4c24fd6fe4f40f38826b938fd4951cd4aedf89520ba214d4ee6293e5d688c40b52756e7d95eb670d15cfe4a7886b84af11f3e489ea7e6b7abae8c9bb10a967dcbbf91b631407a5353880d41888851d94f24537439ae4facf3b8ff11ca961e4376a92511b0553d55cfb52459822123815d9fefce80c8f4ece0d7e7dd4d0954a006e7ba95a7118a3c4cdae1e9fab9904bd8f16ed2795d063145eddee521626f210749e3f89f3cae85033d54c09507afa0b8e7c23b274bd98fd5fd9b92dfe6a21eac761a4f1f65b7f44164aae6112613564164337b958e59e5bf6c2a4e21c0682d025ee20892cf9140560e25c8ab226c6c5a60cb3c155abc4ad745e01827e4e7b7e66daeef0e0f9de4c9ec529f73fac67e077cc35c0da0c477d1b9ae3068608e09c2caecfe809ee7dcff248551a77dbcf041e4b32c2cf34388a5a6ae075b4326f9706b44658c9dedc4d50db5dd45f70b77dee5d7682940c0ffec054e56f74a9d1d48c3eedcecfe1ed4e55209a4cfef61486522abe798fbc96c7844c8dbd95e52b45a5ef8dd8d8de525893f1042e72f970a95895b5ab0fcae0a4198a2ad02f0dd2dd7a046064c60992109ae215cdccb1b45893523c90061597990f0c584682953a19b03fa59835f086a88d6322b669625841ce2729625fc091fae3cc5519bf55d87cc49164cb9240a2a87606a649c2bf4a95241ced6e160ebb939227ae25915798c3de46f7c61c0c59126fc3890518d5d58dd4a7b4303627227cbfa61d92dd232f13121ce968555fc8e0ec3ea53ab8ae5c718abfbd7e1f444c10c38e1632cbfa3484f7ab8d1bac840cd659301201b4a9ae82acc3e9848492b1092e606a98f910a94d10d7017bf12a84851eb3a4bb58a5f726275d2aba6547bfc9dbc4ebc92082f9c4432940d56ffb5b8f8c6873a7b4aed19b895a4c687245712d010aa5ee4d6a948409c000d1c5bfac1b83f5e4b80cc44287ca9abcc1ceda603fd4a02ae61212b2af64473ac3d522f7b628c7bec8b12fba44e40ef04d5f32881d62f13c76038c951cd2983ffa8908e54305674f35b05f077b8dcbf91cafbeffd7bf6bd2e3719b6bf43d142c0c3eb3a9098b369b0cb0f7911d49b163c32f344d9384bc8cd3518507fbf548dee7f590678b06e297e9d494ec61b9f0caa5831a57d0c473178207a186612efb34ba880704e82c156fc90f5d50800dc58ff40e8c83f3b4855f221d2fd606574ea082df31d135de8372f49281491f7f41cfd6db577cb9964680483309637a8985f6f77c798e2796d435d2dfb7de1a3d1abfc1dd9f6a456660c48a86018c84132873f67c0087ee43003080a74da97c6f1cf8f29307daa10594c7607e18f890cd1b51cad24b3fd87240b78f998b33a238b4a1be6d9301e2cf3cc6eb5757bc16af1a1a57b9d755e51e29d7ff09d743b951f427f8c3b2efb4bc61f18bc04ee1a83a818027515a092e92879680a83292d9cfe8ed956b26c0b596d824034703e687f02adf76d79712bdd2044e1c91d466a543bdb2041ff6359fc3246424d6f7f00a78bcc7fd15066ec202f140d20cf4a744a5dc57c8db1251bad43e44a1f3c0bdb64969ece4c7c085f7d2b4fc472136a1d305e1591e0033d4e2edf442fca8365e90f9e5f11e1e6bbe54780ba17bc5e171bb501040addc459b4eb9ec5f21509f9d00c1f1ade7e86ca2e2f0411ca25e8db0c42ccdd4f16aa47c4225943c9f0fa2cce07a1e2f8a4823abeb2e533b74bfea0bf0bc4b8589260c79062bd4d6966dc3bc054b126e96fd0b59947b6217d811bda0c4f4bc8a527f2e8fe8168bd63e913847d0cd9eb81a5fb8ddb833dba77f133cd32d92038486cbbfff9e4993ac61c8bc30d60b45067c3ac7ded4c37f72254ee69c07803394f219b9bc0577b573a77bb71d8158a3a34dcdd62168dc1ea5fca809ba9a8f0bfb3a02f0f539e572efc995a0cedfb554a16d5d4ca13cc4b86a3d1a8d1cce234ca6c6ef54935ee20b6d0f5adcbc79e16c60594f23c2283df098acf7ff5f1ada25660fc316f7166a0347e8abcbcc2810f2c65452132104555140b3e3c80ab5850b6f5d5bc059d636a0b5c8aa1939421f5eaceea7943658c807a0dae66d85553af2ac61f55b91efdd09b779c80956eb8719c101975ce3e7263e086bd11741da27894bc2252039e50939dc842d35920bbf92fcb75ceada9650591302abfe4543b93e984d5541786954b03ee67c033016c0149080f80403289b3ecfcf7f1f47670d84a7c01cc40d97b6725cd885d32735cbafa9a68b32ba7418bd9105e1cd586b4570b3c99709e339ac862c7358904ec6cb6463dbc227c654e66936d1927f9282598088c632463d88ae1a723e6bdd506284081b5455cb199e1c556caaf0520391c2ab456a0ef6c3622d31aa299a7a68dc996137608a4e10107a83dd929b8d2036720abb120c79e007cac666a99917f7c9bc7175e77b411e77597ee1f8f8433ec979c402888a4a955b17fbd2a619a2db5a55d6308ac5d3d5b9db28e1c525cba61b7ebd27a09c4aae0d559d6d5c26fafc0d505bef202fce81bacf21939c9c4dc70742a687ca305def397eaa90e7c26ce017e2bbcc30f249e5cda855e3945a339619f503250347b9a420c244f8c6eddb865d445f47ab16a31b669bc8d342029d0f524d4f6776854cfb3094ce7ac0439c11ff89ed96cee71894ff71e9fa7a2ead17e68c11379ff8f81369afaef9d8caf268128ff92777d21832822ccb3e68ebb47a2527b956d9ef8ee837e78cf70c359397b257c7973e1f95327ce7cab2d0e7fa9361895ea8c22453490b3c76c3ef58f93eac1c34af3b1fce73f6091f90fd30ae63c6d1fcc087c4ab3d93b2801e673a369624671587295a6382268312ad1ec8ad46a79e1cd20f7e231096232b6a1fa5ef5749995e470087792b2d2e4c3ce8a896f6c299b5e955b4f1e7e2a8d1793b5ba12a4b70f1bc0cf0263e3549581bff44e1d465ce724e26c0cf985c05ec56f34797bac586e1572e2d3f971b51e09ad46c3f6c81cfd70f28a667ab2b1dce12e036d9ba5502686fc061c70c5d55a3fde15f6b2007cc386884742df27697d4027ccdbd8b5dc26962803aaacebb5bf1786a93674c864c0a802be7b580e3c99dbb83412b74003be39ce9655570b7d34d5ae0943d9c9135c9c27a8859e80a7bff6d58567a75f1194d7c29622b6d7897bdff72da9758965b7ae95af74e3b9171d76a14c223ff29a05f7ea821f6466bd98391e9a7303a3b2dfbb42b06f5630804ff4a4df61054e1d8bcce2eab23eeb501474739bd0c983554010dbb8b0c8253a732fb17b7b7bddbb0c7a248ac92ffe7b6bbf69c701dd696e27d9c4b9c7190cf13b69ffe57f1394bf2aa918bbe0081e2fde566d7941d20419a9750abe42de7f8f9975e62aa4055bed98a24321085849586becbacb4a08f2f38c409269ef307e7ac97d99cee43aa1692b5e5217ad122ca15bbc0f8179bb6b28b0a1c36b843f6a110fa4b6cca5f21d449ec4744bbebf543a4aa91a1684815e629db98fc140075590b65454e06f6a83317d14f0a6380b3be392887e4af815f68ab348d9493237ed54166230c3aacb4d5073afffa620cc2cc65712b429b8ae9588062c7cb3e946fe5c13793443163c1e1cd8007a0141bc0e112786164bc4a599632461f3dfa972d6befe36aae8ff40023b0608d05a92aeb1a2fd145bd0366c1d403cede68559aa86fc0e8c32afe8cc9a9a1af7860be6eea2aacdfbe6c36356eac3e13bdd2a8f6ad38e67d1e579b0d03e8a4e54781c5f4ab8dd9ad7af6753b08f7a30a7ab53f364dc51824853ff2cae44a3cfaee0990a5aa8adfd6bcb8edc50520ca901cbc4d359fddf5eefcf93b7b32a68767c550fdc7c8992e86d1723c3a42b34f1710dac4953362bd07d6f3d5f0965c55b0bae53ed2f9ffdc2747368519d90145c457436a0b50c42fad71c103c13a1afcec81d0151ae0a582e3d11eb803e6def3ec07a6000d6c6afea786a2530b7490af757d8f19b8dcb0a56beb1a708812253e4983a1bda9b83461493eabf845e56e3373ea10a57ddae5d75e9529a8f57fa658b568158ffac501d2a67cb0f53d1b605312b91c986afed84b5d150a2440fdfbac91fcd60781b9e0a9b3476a50584983e5c958e2a6299c5301f04bb57f9fa48dd3cb6001d2efe452ffbdf47c9011a4c5c77811f5bfec4acd15db404dab6279cf9443b82e47ad32de31c7d324d2228e0ca43405a5ccb8a1fcdc3011f0e3f20ade5e8fbfb0ce0d8c4d62ed9446aa16513ba14bcf2db6165aaf919d4d0054b9eb4c5c82d049ae1c738bc3d38beb63baca3927e25319f883a2d77faa6451bcec1868251b1b60019d0a6b253c02338a49016fed9df05b0b8043fd707a59733db7f890c69e68fa439039447d4648c80e67c4dd5d8e97672750142a4f3e2c0846dc2f4baba20b0ffb4272e04770b1ad7a24c35fd1db3366abe5b9fa3197057a86bea278a531c1732b324d5047c7cdc8a47f517a0b8b48d9d57da702137c5fa358332232800bd4b5abad435a7fec438fc36d08a71d173bf9576935b53f4a3ec7e194d3aa88a1a06a0bc915fc894d76300b09f00065068bcb54d62472352d991b9294109b8d59bd966b338b34be412d2b80d93b1d062db7a856d6b725b05b2452e1e1ae643a1135b298806f04269fc4ca26bda9c87c203a9e775eb5d7ddd3a0ad487ee30b42993511ac4bd32cb7edf62051cf65e95f45bfb24644225d66e908f23c27e32fcb84c8c70db58280270ac22622d6b39f993935ae33b9dd8a9f21ee765293149b816d78ab56e11323f593b94a6464a05b25b7da80e9f609f223904857abb2d74c1956088780a5c7b6ebd0423b1ffc5cc3bf472b382c03fae767795c283be78d807f7ca777b70fd9e5333f7b5ff39ef83e2480856be53d2530d3931e5c4d86b246c7e45dd76bb212613a5c3012279dfbbda691fc50d9acf4b9e0d48bd7f65be63b5a6724c46124e2c7eddaed0ab6b9a5199d714d32168f3020ccdfb59aeb449bec696788c7681b3621ca3817486c9b80150b1c6d2c2e26ce51a98f17338df26c64178124a7fbd08d1218d68d65b9c846916a0bb11ea4b8a9efa102fe40c966f745d44a89dd690bf72b58e7cd4f91bca81555338dd463678c89d31dbeac0db0508f872e671709b89d98fce5816195a8198b5077236f50e21b925bb96832189a1ce3ad5699d475bb73dc1386157251478809870d340c14d3e45febe1490aecc2d71526e5c2bf168f34d44367285d18974d54b3ad46cd6a1d2790f8ea0166012bc9687f990578a1b5f16532d73821281746c4c0a0c06628bb12851fc70d74b7ff737fe4906b3679a64ec44b7f30078b5be78d849e883c8b7f404086e31f81bf98200c9bbcc762cf7474b0f2be93f1eff10d11aa02e94031c3287c9e6acc1ca389b1f3085123a6473f40ff185905e51e6391b4970d21e8111b28695d623a0a3522d0ff3088a2d8debe5150cfa7a995322695203b1f2ac018a210716650e1c8a6b64f2305480e39c06ee2657f9e7020d424249a0227480c07bdb7027d1241d04832a0fd53bd8e1fbe06f84445c4f6be13ce564ec4bde41fbd9cccfb108c0cdddfbfbaea0a224e3ad2b25b5a1417ba0bf275af16abd3e218b72f1145ed558f02291f3282ea2e41d2c53e0853ef7094879edea105d17b63dbcb76f1aab0406ce285b93d4b11dbd4493dc37ebaa59c87ccc30f3a7733d86d929a5fa058cbb38b8c25bedb2a80ade9f20376990e274c0ef5411208bbca6810e923f677d1c68520792d444ecaac95df7b8952b33285bc859b8de1039400404db644e043c86f90c19479d8c6161e782dd1739460d4b76f624685a3670d0891dbf6f8bd3a656e4f52400f7b01b147a8536433f9faffee935c33e919b05d17e1128ef37607d9acae33f9d8524145eda3a0d59ae5a20bb85a6cdbfd8f10bec9da7f14d84776f974a1be30e2c52d0b4cd4ee538846e2f22143b0ab820b3de22f4f6ccc7691a5a729d67a41f6b3b005513c65f5b83f166e8d81a7250666ee781209536d6f1c43cbda864afe098070a84ae56288a6a29e30f436b5a24d9f3c6e2ef9d1d0103eab371b365877226953073f7943cae8ef76aa0d2de8522634159d6aa4de2238b29cbb4baf913f9f2b0f0237012aabccc72f98c9c68c043cf58f338393af406e683456ea2dcc3738126aaa05f6fb8c2334825c9e350be024d6fd6f7ad271e4c89d5652384b6df5191bb3fbd91e681f788c0d304840d20ef0be2c7e17390f6feb34d730785542507f722fffdda367b0a6b303ddd7d73592aa6b6aaf14e1d2eedc654b06ed992280254ade84df76b553708fd27bdca700639d16b87bf4ff7a54063a7322b1dd919cf528802b61438b771298e9035137dc59380f8e828d68652298d75822e76b375028d6971611b627c3a8332d90601f7c7bc4107fa0747251365a62f6aa099eba421b636bc6de2eceb926c2a9bb29ae8e1f334db2f6d0a1adbd8195e82cfb177176119ef43df257e743467dc6a431f12a12f2e6461b9120d34dd1acb273c59a6903a6f1471ff5c7efdabaa324762f655b5ca91ea259e865afda97028fbdc0109fd25d9576ccd7357472dd58ae275eef01b306b8a1eafa0b01c958de9ee06f44e8d0096c7703677b90b672610e54a5d1dc085265aa06a9a86010b34dca3ef925420521c10443cc4443b82ab598439c2ba714bf808d3eb3cb6370089d4edeec0a8ee042e9dfb8a5677291bb9d430753b386c1297c6cc16c1674a90bf7b77dd41fa49237554a523442286e5df89955c39a733e11cf6add6310ad5d11b536fd38826317f8d1147e7d761ae7ad634b82f6478a4eaec042b718304175fefe118b8f7e61ecc1277eda64030be00ce20b8abc360da007cc6a7b993da71ede9262c5f49461e464b1117cd17d6aa3e88f7b0c86c27705c0c396af60ed3f938342005cddf0033c12d7612350e06bacdf307b527567d5b6cc46bdc533b0e19b8d2c44147f50fcfde8806ebdda4376fe52c353634946ba08a522f7248095800b5d621663f986828094e696c2f46f8a936c62f925a1145f68048708dc582cbe712af887d79683f946e345191ab746ca49b761fc894c9b52e74801b333eb7b4e115969618181ebd20fe8a355d2bcd804735e6fb107c050cd2b4b5a3123798094693839a6241ae80369a6b5c7d65c0593905eb075a315ee44117439ded624937283cf5afd8caad20cd61df2f9bc5473b7e70e089d0960d1818950495273c9cd888f3227cc22a50e16127b0eed5a1c74fe18453fd0351e1b880d9bef34b8ae9f0385e369083ad83bfc2ce7b0d212d2c37bfa00122c6dcbd83b4e7a3a8d872f8beb748cfe9c69aeb8d6c381d0925117adcf16d39c247bd7e43892d78af980fd4821d65a2fdf7e65ce2397a8c331cc575bd58eed1d14c9c914086d460be161079b6e194562a6b7b9f168a7f1c4ff083d991909ccea248d8e0520e7fa09d7cbee24858a55bc33c760a44f5010d8fc3d00ca7627cb110fd43679962c7e48e5fc7642a91c79894ce50eea1a7a6c529a94195e3f2b8afad2acc935dde1ad8a337ec2f7f668522520e05d4a432a10c837d0db98493c3414058761e0b2b696fd7265f01d96384361fc1731d43e608559a9b578c555da003a6f367f8d804eb8d982020e9f3986b7fa267135a5dfb72110646f1aef6a9e2cb51fb9cd1f4a9a852c435143efe89f4acaaf2f68987b43cd8b062eab665696aef9360cea1036bed788d56a337f1a7582dd34b9737c00033a636ee016e8496aedc139ab763c70418bcc8a97d3f6d0e9e43923f782cf169603c8b4036418a5b0ec03da6dc7455b0c74d2525e1b3cb038b73b7e1142182823256edb3dfe1eec52d750958b2381f116ec95d93eded692b31f764bfb3f729e09ea554269dd418225dd0edcc67675e8a431ae73109b6b010f07a9116436907769b4bd769605486c095c43c32f18b3a48b5b4a15071be2b0e5b8cd04702c9f5f2a541c3cd508bbe6022f5a0a058299867241b007c8059afd1dc8873f81ae1a7b9534b886bb1a3a8c1f62bb4c8b96d6744d5ee8c835d8f35a949e22e44a8b8a728a69948a28f32662611e28308b8813ae74c205085c594bd3a4c44fb90147c3a96b19c2dda1b43d3224b243e4e22fbc0aaf0055438eccc5fcf0279b8509a2033a0d9e664411d984dabc2a017c711219b26821737342f8be46b3b77f2fdaa75df14856d753be6e0b95c0ea928da1a868ab791bba9f6ffd5a32f8638f23f4eb4e1c2c54a6cbc993ac96eab4bf4ccf66cbdf1c2051395dee8769540f29764664999b3f166c51f587cbf70201c5f7ae4b03ece704acbb938bf5da4418283348bcaa6bdb67b5e373a41e1224a36de9e2a79172b4b7accf6bc9ef1c28289966c746355f2dc5796fa3cfafed6bd9622a79cc8177896e6f46927eb3c8ed473c76382507d1943ecbf475e3869018bee4465281cc533a2429547053a04ab82bfe9c9508007dd8d6149b67d0f287ce0cc48dfac771535a82c5ee22a0c0422140443c671541447c5715414c71e617129b7120b6471ce1242f6ce3f79b77026d980691cafa0bfd9168b6dbdde97bf61f0e96e90c3247e449c102c069901803b13b8ef3f0ada4f06ab9deac0a792017ef7cdc27cb1ab707e0e2d7283eceb08f2f67c6f082787ab500a0a8c5da05ab62cfca06c2ea0e4f06f913db33f3111488e676cdfe8c71c3aa0b3efe37e78394bf1b6918b8bfe9d7a35d09adceee3b3d613e004706b5609b9069f1ddfa240e9db8163c7d1bdb9a0a313bf2bed0dc99f1bb5f3df37d15abdc806f37f259097d989c064c37236c829f40feb0eb8d71d00cae5f6ca7240cc48a709d80f8d1146ac899251b89602d8df06050e566292950d415bd47f31e431e8741854dfb9db95d3be9f31849978263b2733125028beb38d1f2a8cc5b89f398bb9ed7a14045ead8d1b8ce36c497a5d3067708f2caef9b8b51f2a3993026aa104d46408bfcc0cfd9b41e4806072b7c8db23aaf006e22fc9e87a98649c53470df6de4864f41cf62f5d399899ad6f7480a489fcfb1f1a2f0468b8d43363d9464ae5a0a2e8dd41f4eee1864aeee5fad99469d898c4d562a13b5c1c0fa96afe267b66e60444800cb58d4ec581e5637f8cec7b8ef92340d5bbef65f6786e6586652d81d2a84bfc57ae02fa28d73fb213b9802862e1e24a6e43032085aa061a0118c3c89570693634d59a5d81bc8eae533b3f3523b35a6ff2a827180f97c7e0f48020c8eca925c6c3ddadea689e21d7d5391a15aa4355374c9444914d4f3e6843f109437d79d58d86e5c1916b90734c5ebf39d711fe1ab915d16da418976b828bb6f41f81f594798e3b895c28ac96fe6f8a44579cb14684bbef1eb978518e0c237ca6dabd2f97d93f4edc2744be33ce3aa3c2f88043d5368688facc82660109ea7a938b0b29f8982c03b1559e7143517f1d5114ed1a08dca3f8dd7a985f8c405d30312de416fa136ca21a9a7a1e6f45e2412c88e831c4e586ca126bd734e2b342c413eecfb6107504df82b243db86b03154b26a9fa93a30025c3807ad1d169eafeed6a2ba3927651dbe8de72253e9e3780e650613d0bca56c2eaab8d55d45065d8d74668dca2bbff28f469dde16b46510b570a7c32b5741520c351c9a917cc1fc025e4d1b36ae1ac90823107f666f43127ee399db4740ec8b01afe58e44b965caa190bf3c2b58d17fe9fd475e8848aa51bf56200b260702e7533687c6cb43ed477d0aaf8c59014bf5df6e0378d4aa31b36343c5aa7489bce9ab8f65232893543829ec51bb9cb0978e8c91698e468e97d550ed226efb2be4c8c5512df6a380fc50b1d14c796785d03840ed887b7fb5acc6366967c3eaab901c49fb98c616a4958deb658786f43e795ed6d9e7c23879990fa51d48ef72a8f8e125f340de2e0a80155109280973a54d15abc6603515ea702dc5be5893f63b15edd644c1ac160e64954dd29ca9e8b4886b061d8a581d694cfea916298aa18e9b369fe9e0e21e1b147131368fa817bcf307d5b30c8a65ce1df244fad50fd1e07a2f7c444a2758686bba1b4743bdebe436eb4255e5089f7a832cb98a60370dd58ccf5fc4885501185c4c00a50262df5169b7d47a241fe5f6c6add3dd54ea3d5ff40c8fb060b6950c3a1a071fb8b9801aec3e8ceb23b097b6b4bda01589b7623f4095db591f374eb92a9fa7e5e0a218065aceb39ab6ab5d065460c5318c5d3529e9f9daea6a84aea8e1a3bd6468ea842383932720f5d37914d08b5e80fd366af677f8fcc69ee522f0e768f9ad0864cd3d0b8a9ec66ed66d01efdcb1d695743101e0dd3bb1e8d15e0d11353e95070b8c0d2d36a93b99fea38cedc4c65ab888435c69b8e0a74d1decc5950f2b76101a42179b6a47794fb50d1675ee6d83523be606d41a47ad37d3699198cd415de7e5e359e86ca55648a47689375b3323ec31969d57cefd7bfd06c4bd70ad6e06fbd475abd222aef32b3fbea0577ac420a9f1c2cde1c97594b4d13492e84c911d573287d1f0885accded3b4967a7b4da5b78cb75430e39cd36010d519d0ceee7923356f3edb1cd3e8d95362a110e4f2cabe2d84a0b054d8188b4d080ab718905fbc1eb4d37f19accfcf375b654ef83b2581952ec86d9df5d5eaf7dd30efb5550da32e44e981de29f83139966e91101e4c1e19210a5539491148369982c3b24b63f996a92453a978e6e3cbc22c95b80c45fb625f5dae5305cae8b93e044f74622ee72e6ce3b1358d6d135686a96b993dcd5d762ef498ce608358c0a6220d9e0b8b496fb4c87485afe6105e75b172712ec2580334083da918ddf14d4777019d6a1c73e18724f7d042c477bfec1b98e6a3631b81c98c01a39418ae7c87856dd44076acbdbe04867cd981d1ad3525bbde49e72b2e1dca07cf95f3a5979c6198e7c91040ec60e3c7db219625c1540cf112cd3976e7c332780a8d590577a92c4c33ae84e50986f50ce115e3413902499a18e41195738e1f6ebc8aa7b68a6f53dcb78e9591ffeb90b86d8e502c90b0b0a7c69a1c51b211851a4296e5e1bc0699ff452f7ed2ff5872474d4a241cc97adfcdb4810f1ff0fdd088c0484780c549a08dd131e7560dc715aaa0c8d364cab31f04bc1f0352efd9667cffe101eeabf8755e63dbe1ac240abd5bf447d96a17ecce8ed48357d3b2e69af7794fbb284061bbfc00e6037b134821b93cda26d9e53bab59375e28e3cc9058aead2b62777333a56ab2233cd6cf99da16a215dc89a446af23d128a0bc5ce07e5dd2e5c99063a40d955ff0224577e240a949ba73fcf6854e887f46a5f5ca6757ffd826c6ff3a8734551298febb0adfa7886426d1389d83b2b4bb38aba7c79382f3a6977cd2d4af3c15e8550d64723902281ee7e8bf0335c29518bffad54064330ee24b3c5f17f1b38ba95fb043254e8ece2270f5a14e6d98aa9ef428c4e153ed402b1f7e26eb70eced661f8ea406c729c41367de0c05600206c095d3f6cbfbf72aac050bf1c1a0a7de220955ceb6fa4a59c7d0f1e664a2f024625e256aa88f338905793dfef6b34bf99c1f1106d9d9b759f23c7e863b70471f64b16a963c912b83a4d759a863b2cbd3e5506ae34e82c1524508115e17bd9c25270b621912e039a2a1c6af21341f1a1372ec7495572f01b84d34147e3b809ec0e9485ed692893989461a093cf49c7876eefc10fe159fd50ae8b96a7e21d0318758a9dd2cb3ba305444cf493936747f890c5f043f502ab964788c122e61ba5a510562319177b87310513902b1ffa4b3e356a5319c5727cc02c3e610fdff5d87f35ac29ede364021a3cb0718345033dbe405e6570fcf4ac1ea785b48b8bf1eee78821c85dbd1b035a5bfef19b53dae894775e40ea6d322acb368e91be6d49a0a8362e7c766258b455872d41318ab979212d07b2a617043ebb8c27003344947e1f7c3690ee123550822e94c284941acdc87a40e0201590ad5c59f150ce7e4d346113513a882197f4ec058a07e2ac97dc47b62ed27a79bc10c5fece222efc858eedf7a6e894361fba6627fcb2273715ae4fdd260ef7e9f02f2c7402519422813ade3c764bd25a522d93df478b4037434d388c53b2228a6c5a56b4f23978f55a71b0d37b79083f9be8f6edc6a7bd0eb1400551150459c172804d03409d629dd0096e9405a4e18fc6d81d2f5249bdc55f72d51443a38872b27e0678dff67d509289b03be668e42182043435c60c4d89948e1d4006642332670192a8886b91c91913c5b5206b69169a17e8d02863c422d5cfe29a950bb424a5d2558937c0464f25735300f2482cfb776af8d9c0e3e701de5018197d2ad70a1bed091cb73bd84a543ef764b3e494f5696a84af8cd0fed7bdb16abc56f1cea401f2ab0b0f82ff82041826bc8640a19d5c13b35218227642ab02cce25bfbe40bbe8dbbfbabfa865a6f39bae7d833b5d266b27004427cdea9b59fc6c37397ee2907facf64f7d5e8cfde026b57aad66356ee2bc5003e9661258be3074ea63666515023d8916e199a3bdbb3aeeaa7d8ae021b312e31f20a6bf133105eb30f98e265e16519482bbea319c8adfb1a41b795914d83c007b0c252a9d7a6e0c67d8bf128042568f46def4a199e58077f0462af84f0b462882f71308695e24476681dca1428e46e5e44faea6c3b03ea0838aae3c39116d16374c8a297649f2ac8b75647f626cae2bafac8be2730c3135cc795ec72a500c14864fd999b4a6ff08e537be2ac8c6250df8a69c7f1713e1bd45967abe42147299ca514540bd3b13561df26cac3f8e0bf7ed07f1b29d23f2ea500d3aafbfe6996c08bec7d6a1353497be43e13358a35d780cb0bd10a5eca74dfe29627ea0fa8213626f217e102a451df549225910c0d463967beef760e1b9d657cddf02c265774fd7441913c616bb84a7ddb751f9daa2ec531581c453e4160cd626de136de02f6e9792ec950863ef2ebf75c7c5189738f870490b16c672251c819edcbaf3811709878d4029182d30ad94ef7ffae71058332689b9d2435805ecc532d60860fb4f45b5b301f784d9f8f761bd644b2e7b289cd37753828cf200cb19d6a02e867fd4871f3bd2501d3fa62730b190cf66a9fc9fc8c84d847f64b135827ee02d989b0ab301f058d954b65717fb44ba337b43f8e6c827a2b74667bc54e739f5dc40bb90d26e195591aaee6456d9c523357dc0224f4752e9f021f5084602a00e1a4dc56f5b6d07a3e46cab6fd213954100b4371cf019df217fc8c2ff3858f5b646e0271a8c3bfcc7174b97dd346b63e47ec276487f4ceaad1e0e22581643da00ca3f45842d1f773b35ccce2a8bb8fe337a7710685cb2e87dac9302f2e20d3f6b3e8c0104bfc65f12595940a88c0e9c34a8d93361bc39edb91ee62da1b8dd5a32cc32245c847a8d19681422a0cae410d6f9d930f6c77a54cc1265763a6752f90b2fea7964eea19ed557f3ac25c83bcea5c8582abe05236fa0dd1fc359f976937b2b8970eaab08236282d30414508d0fad6580a0e45806a0a259403bb6afc1206dc4b04d40a2d86d24a54f17a179924c9fd03d3bf3ca09946b79d3b8a0193748d26b97454204aae9b556f104052600259b21a8141b08dc76748be1e695b1d99f4be90298fb39aa934f033c2d894dcf2f05f095fa84c7c58f6cfd135accc172ea010a7923dc4502cadf65f019ed39e03970c957e50b2e6efb627bbb5724ef86321eb25d0d6de7dc138c94882e3fe3bc060b5fde221532c6cf4679ce55c9ad7085785efb17e07c7b30a07caccacddae073755d0255361da690196753e13bc4f5bf4a11a2446c85405b75380d350ec66ad1893d4fcf001e57571da8594d66e6f5b2e0896d397f9e44c2a81442cd7a5b0be046801cdb3c13517441a267f86cde7a2387fae6ade2303c47fc9f810df23c5481975ab267ac3d1eb42e1eb762962d51bc28d424c8a691319c7862874d19ef0fd0b8fe8775e160cf80ef23015bece2503431a10dad9df89897facef26b29821f55170bd6feb804e08fe56130f83852371d2e89cfb69e8e6365ddf42ce9d69ea15aa06124e0d0f039b714226b1d526df07aa8826fdf9b3dd24a5462094c092c81e4fe0a501afae3061c8b24421dda61d03f386851cc6f068d6fecc3e513d8161f7d3407cf3510071f4b6f2f91ab733616ecc1b52b8c8558e2ceeb1109f47a3c7a2579b34533b8f9f957aaf472b69eee61bc7c45f983b66102311b6c0b5fa537264648b10ae43f57ea5d37d823dbe246dc5361efcaa7666a51aed1f159c918c44704ba29e7a659200eb39a0e9503864496ce0781081397a373e5081f626bb48b486970138a5cb96c1f63b32061d04ae55502e38aaf28700e3ea2bb58f8bf5e46225c181c73a808d409b8d5ccce8ebd74442385a7cc32db765b937b4b29934c01a10a0c0a280a14648fd209b2d88a24129226cd8a24994eb5f26e56aba094af564be84f7087f7ad7c6e63befda70d95fdc9f2853e4fa100a278a7b37029a42286e880343313a479234d3d4d2d25234d2da51afb1355c12b3a4f3f26214a424b32e4fa89fab979f97669f92cdf437440d817986d893bfa3cf93c81f1816a1737bb9f2c3e3eceadf2f179fa49d2496a25f1ce17306154610729aa9c4e5290229b5510e72a0a4a70ca9de0cc87a0cb365b5d6b625a2272597115b98c5c472a2c903c1bd5539b2ddb6cf53cf580e909e3f3949412737315b98c7a6a638709c729f41335f6d47ec9c7501d6f8fafc72ae8f31e419ee37c1688033597c4847d986d9502af0c0100ed068019cc067b8262413d7df9b1fd64f951fad1f2b3d462ff84f931e387a95bed62a6cf1312da10d0076afa3ccd964f94cfcd670c122155f893d4d99a45cd537da07ba0abc9b5e4d2e252720db9a6b8885c565a045d4edfae2d2e23571617524fadc7d6f3a5078cab480051dc4183a09da017068aa9c9a9e605cc17a25b9219adc54e02658a2afca52457dc91b724cdb6240911b20a52f90ae454cae8b2034d063bcacfb993dbf543f0a1a266eb8977dae6a57684949445a9c52020cd653fbe17835fcb8ae927ea47cc981f3db59e5a8f971edb2f7d14c7acb73f53bf5c463db5fe02064c989e5a4fcd0b5d45aadbcc0df60566e37a535f06aba0ea6210d7c1877a30ffa4a485a9a9c577fa32e4c526190a7f6e49662d761221285ff84b5780d428950f987e0169177733c19902af841e04fc899aad0e7fc624110af236fcd1e18eb5168240403b5b504f35fe09363741c9cda0fc945cc97f0bca9f01e55f50fe7cca3f412e0794bc2383f8b3666b82dce3a55bdd539382abdece37419cf78c7c13f4f115bc127a2a0c7f8077b62688c157f00a10a7a19dad09f6782f4810204080ac827a883071b9ea3db616bba716e4f3c43bed44be5c1797e2b894d7f34db0e6bd23df04797c0abc32c48508f10a5e11d2f10cfc074873d910129c609104a5f679eaa991b0345bbdf4b67f1a02fec0c1adf620e04f1ddc6ad7c192420a4d6e13d64f7f41946149a1c97d1c6f623fc749589a2f126addaa83633ebcfd870e8eb15ec0310c38d6c3db7fe6e0d88db7ffc8c1311edefe1307c76a3866e3ed3f70706c87b7ffbcc1311c373896238663f4870d8ed5584a0680e642a18f495ef8f624b3fe09bdddcb00ac1624fa0f466692f2ed243059f976a6222dbc6400529b27df5e13c3b7f390e1db6fa07c7b8f28df8ec10cdfcea2e1db7d0c65004e252ef04e7b0ea8e405de69c70195c0c044cb408913de694f814a580095b4a04488773200a5cc07c8bc83017885c623039d055ea1c164a0f7b8096dc00ed8dfe1356007eeef701e600758bf23bc02864a6842cc740333e5f0ed4aa4f007cdc9d0780620cb3cf90d0195e8802ccb00ec644168422533986dbe1eea8928dbd7bee9999ee8ad7cd11b75e01f91e0043fe18504a5763d163e4ff3f5484f68f179e227b2f83cfd44f5d45644dc91998e848055a93f900e04649a55f08a8e539d9084da6c7d19b7a17e84dd848030a8d96a0702c2a266ab3d047f40f0076ab660361bd48f833f35f0c709fc69fa296ab17d06fc31fa39fa419a837fbe7c7bff70c162cfd74f961fa6ef1f2d473e4f41409f271fa8a5f9f209d3adf611f3ed372b1058df853f29209e24899e9aea67cc4f1b1c83e2d7601f12967ea248f0d22f20de4e42ad5dd6078355900d7d9e5a6cf725eef8e3f3f4ed3f51edb2defe23e6e7d6ae94b7fb1cf9d838b6f2761fa47e3dd34f14ccf61305b3fd44c16c3f5130db4f14ccf61365fb769b1508363f6d683e68ac5508fdd5395045390a5e1bda11d1a7b2b2a44395259b5590759bd512faa92536ef85bf74c51def4fd4b7ab409b59cd2a84fe94736097aa6e67b31f6b4feddb53602522a156a5bc74a9456d8229d83741eb01e09b60f71cf8f9784574848460a53d6e7c66cb199b1a1e3b6864727ea8b478c2e909c0c0f365bb5085ce55e1e55c15dad99a1a1471a55757819ca7c0ce2938aa964a4879374b5039375d05d6003451502d51ef40967195d9d9ba5236f30e8fd205ec7ca5aedce0697704e8a909ed62a716ac3c759e35a40d9eae969c5ad8f223333da59752ea5c97d32e4adde919d6ca6fd072deeddd2aa8475801056b69980329470bfcb47969431a16650875dc3162e0678729d80ef45bf7b8e77c1b5ede913e6660a4611e35f073862c29c350f5f1d6280e8dd910abbdc5f9bab3d5c4a45f3b861cd004ea26290c08494b29a5ad1cc29d7df551e7439cea36b4ddec39ea6fc6bdb3e7a7b36a0357bb6a6bed38db2db99043f22ecb6d4f6f97ccfc35c82d82cc3e7d82dd056d174bda5d1a86e05f736f0f4c2b651e9a84e7c9cbc3239da77926cfeb088f163a5f4891a5f369789c07c64d3c3c1ce31a55a2411669060db05c85c04f6fce59dd73c9852fc40790fb66b5926ed18388940b6b518e28e83c92233c9cc0ab62891f794965c4e59e9d5840e2c74bad122623743f3c9301048d898da7a727bec81ed006185c6c4e78314518320afc00450b1f6420a3045ff4a492f410d022c61a4a4059411b2ff067271686be7b7662e1c98fe20cdde1153d13abdc0e4739e6ad3bb9cce1061ede6ab10438ab9e773cfb78762163aeb422776089c57583f8294df0b3a68a2b9d73e9234b127936988ccf954fa9346d187a1e2861f335a594cd5a8b537a11f4b09942d7de84f552069456baa50373508577a653a973c3fd42155632a19d53be0a949e02e5cb70b7cc9519995012cd965c9a26ccc9ea887898718958dc9a6eedbd4dd64843e8d9ccc94b8b4369786b511eeb80b42bdde39d1c1edc835d36265f5e0f9befd6a4bc67a7fdf3f90b56e621a1b1649e8bd22715c224075d43259283f69828f340968935d2e7c88dca84235ec864a66a98e3c5952f884334615680e50b6b4ca625dc0a04349ec6927dee8126cc1613d9923e27480ec698e241e01679b5c4b6a4a9548a53a9a992a1de01fb743a0abce3c5956398f00b20c0ae06b06b8628d4114401f6e8156fc69a2f2fd4408b4d81d9e2396748c55ce929323cd6e9d909b325bd136652ce66b33eeaa429ad04a58f5a4b85323485e8861ca6bc74066aafd3da13a4b35872850029b3ee715fc5a91d27a594525629a33a8e69ed925366527a9d93d10fae0f5eb64ba66e0dc13ef209e640baf42e8263320ade91e1f81d7528977847bace0d37e59e972517663399aaa12cb10c4b75e93ab20868ca9ec9312dde5a42cdd6944db3257d494a6f6943b954335bfa25991e3c3129f9fc63e60f97b6d82dfb6f34ea8e130a8abb4dcfd249935ba60b5520814cde66cb8c5b38ca97344c4d16ae71050d74fe5e5cee398bf96ad9ddc2c2820b16e339801af989ef313700d29b99b7f8b6d1e25697365fae742efc40130d00756ee7eba1381043e4a20b61b016bc20c4c212627630da420a07a0c0ca0db53a8ec6c4c0a3163a5469c289349a6048c24b5c9801650e315ce8a2040c08e30b972da20883082004f004d2196e08c1041c5bc8180c2a9ce078411d373c49b1c21139ac11154417562441e1288028820d26a12f9ab4ec50c336431162aee0c18827187218fa820a1a35c470f905eb22071f7c6062a826a403061b54dce0a40553f420632627d0486ac110548870412ec941460f4852d6a821c98d052968019824232f6250410d31e270828b172f7eb8ec47547901c905221664982531724245e54c32f18d0517be9dfa0bdf0e0483130bb49f3991672727603ccdb393932edf84020232a1cdb25af2853309f4de4b7d1ea87a5e7193b50df5d677c07047d85b13768029c8b76e82756bbfd0ba97e29fb7f992dcaad55a3a649578c77245ddb26e6d5bdb379a903b0ab9a216ada7a81b47ed4ab9f5281573ad12b7ac5b96f599242e57649d33e290a44fbb457aeb32be0239a316adcf80f6572157c43be013775ab74af60b473b5e2506f3aa2055e82248f93d8084f1587e98dba4be05b8d1ffb2152918f3d439a74e9de3b82dce1f475c0982f4ce53a00553ee71e028bbe7952d807c1b3ed41d61855705d9b13a0752bfe2b5151f2e3b7d76dae18ae77914d88187236a3bbc9094b4830c518eb85911930312332b5050926a569ea0b03cbe99d4fcbe5bc3e2811d69918b185862904644592bc408e2c7efab4981a24ecdfdbeaf26070a9da55a4532b3770e926df058879360da55571ce5264b35be7d5cc934641a73ce5a7f31a3985b8e215f57b6da79877cf5ccc53e824c306026981fdb49cf7468d95c447a2d1349744054a9e327143fdd3b4115db4f223f5db50a9adfa7c1176e28d581858d2cc0908d37044384b102441114242064edeaee6e2dbe8d18e37bc777777777ce4f9d4bc5879fce8afa5925053f9da938113fea8da81ea86041152a327085051eacb05121860e5d1048889914f6e32787d561cbb773af263ec890d4850f34081149244c3065453f6a3fd9b282080ba216be4f8b14493f6a3f1705924319dfdedf37e714e304d19c73d2f9394c11844a9917fc90e3d2679ba32b5b00527145c2406b286ec3823b368d48d3ba879e7eec1826d84f7887c6e38d3b761dce744aa4dd7eb338c499449a9cda4bdbf8d52c1a8cf64f336a467547d1a1ea8565117ed9b0a774177ad0463f7d8cfdfc21c7ed1d59b414dee92063d8ef871cb73ed33c95df5e5a9c9663f425269975b697a62d2549fbd03a4c30eeb4f65e7ea2468063d8c230a3c5761f735cefa9e5530c4fdd75e785a7f9fac6ef8d3bb27870aaf36f5043b13dc8326b97b328260b823f5aa6d6b27274eca555f7985f945bd5adbdf4eb933bea7c757183c93f9d4a59571c8d0262b0f9f850d72d077e191c37c20a3ccd1cc771b23d204925ed7898f5ad2e0b36348a2b6b79e41a3f9de5d06c49a516672893b2c8a4db62538b1d0fcfd090fd7924c303b45333b5387de469a5a3d99aee8198db473f7d839b5c835b330e25274bfda4e96714eff0fc9176cdba0ae228c77194b955d09139eef8edc8709dd6666bba8caad566cba89651dd93731982485c6eb1bae4e418a19ffedce5094bce233626271e4d8020a73399d361d3e91465d73337172e7bf7ec84831c9f110e6ad8271ccaf094b8ab67271c6c38d47040b2b6c3018827146989c381488659c451b53c36b4008aa8511c64a0491e18cf1118d26db6d8e230439acd165b24d515b686cb3d7379d29252c19531a223e38908389e7ef872eb3397a71d903c6ef728576b77734d290d2b9dd6721ccf2ac49c7336cbc54adde7a44e27dbebeeee4178b236538e0eafbbbb69f79cdc4e99b982312b576dc7a52c08d652163bda558ed53f2b3787a8568a4799d6ae4c7987e3ac4bced659b969b9d592fee93a39cf75a65c322b15eaf40fe6a0c79cef20394757b2ad5c5ddaa2c1ecb27bcf4e37e8308230430bca5f22feec9c1bed779cb596c50a298b5043ca230ae257e1cdaef96a3d79caccb086637c6fea861670e0a02c8f3da3f2c0788ec084a23acba305b5d77e97e3e1b14e304c010c71545310a5a3681250e415a32b48f6da94d3942319581c8e164cb758004761bac53fda3bc294227b59a32fadb8505dc1250c2394b839cf5cc2a8c10530ea18c186288eb3cd6c6f9eb99481c3d367271b86f891b544a97896bbbbbbbb656e4080f8ee3680fc906249e160011c2c984f4c3d2069ede9a38c2bdde352c0632db5541eb10b2f9db64be665d3ca0a211b6e640b4fa3942e59cefec79a1f73bed3f96e83efb6f8ce69e7b6f30bc47752d4f8ae0626beb3e1858ee748c6d93a6403ed41431a4f6bf6227df7f5d8f2d5e46061c3467e642719de80e2f4d32f0b0a0b7eba4759e2a78b33c4f0d379dac54e3378f1d36145fc74a0e944c3d2d79698e393b3d96c469332dac10abe6590228d3b93b87455a78a6fa713cb0baa9fce6404fe6abe5b13931cc450e5dbbb004870b1861b5d68d9a10b91981d84a26c41e3020936d272b4d239426b1774f0dd2570810a1b5892a0e2c60a3e9ce1060d528af062892519ab03a209a7fad57cb766a68927537c3b6d97cef757b342f2a40ff72bc8ac1621b58b296a0906da8fd5680906a31f6bd20bb71fab969f75a9368dd5a9d67e7a95b222c162a5b2122102d2d96c55af44b5878f2c236905e469c2ca125ad4a2d10cd31d2b51256ad7386fb568be8a78fd562991887bbe0128ce16750d6ea18cf37c892191301c2dad4e89e68b978a263de2d8ad5decf4c293af3ec7b48bc757a7b3f95a415665acf00329b73a5057a26e55af4dfbead5a85d335eab8b33549f017b1271d9447229031f65d3286ba3b4d5f8289f78ec70f970d9a3b4228d747c9448afbe319830427c6431a18f3c06f4510abd741f2594191fb9a902f111f653babc2f6de27c892d97f3368784a3cd201c6f0fbf0947964d387a4d388ae1c8b3231c61932af56dbe2ad16c4ddfe134e16869aeeb84369970b45d385e2e1c5942c2d1c37014c170e4f170844d6a2be2d3e96dbe8a8441c29175812815f11fe1c8d2c073c2f13a4e386d1b5cab01eb160979b66e3fdd479649a963104e5a7bea3dc29145fd261c9dba4d388ad46bc291873a8f7084fd386f3bc2d1d2844a371c59d35ba008ce78b14d284f5d261c614223cf18518c8779eaaa4a94aa443624eac29105a3b69f4e0494b7d9a2b3a9d3352e704d450961d878879f5d2584e185457ee71ac7c1c40e462821c30d60bcc826bf604d3516e74aae56b4c5d45d2de1c17d42a6f3789ea4d96c5684ac84304ec02dfec9c43fbd57d3ab061abca41cbd4053dcf17e09612cc122fb94108613cc01ffa521f05227bd84b1c49219eaf6298784d7eecd20c09b097aa8eb09b01304ca94524a5b5a99e9ec314f2ee4e9d1fb5ecd7003a6830d29a1b448e4873b72348e46c7b773503828ddeaa1a7c1684a9fce983bc290b48b9d5c80fa76a0179210a6c31d391a8d630c73a4bb5ae23df34e055334dc9273a664a8cf4f328701cda79ea5b473051271ac470efc944f6b58674336cf9339ab208fada5b4560ea49ded3e09526b6d4a824841aa2395e77ddf8a995982942733b304d967d867d8bd994f829786e7e4e979343bc41a25769b55d0cd8dbce15153632399886a8d31bc196f86ca9a642d9e70b8d23d29657fedcd49295d055df76aadaba019f738ae53492965ea4b7deea93e99b30af27815b472ef0b026fb82b1999947b333333771574efcc95595d1a9a7befbdf2bd1428dfeb40f99e07caf72c28dfbba07c4fe69b596dc04bc1531ddf845dbecc4a04d673d3b3cfa3f96a28a5f912e2ec937d12cda2f9029d7b8e29cf3ea5b0ab6f43b30ed3af399bb3293469f3e59eb3b7adfb4bbb661a4c434d225ba9f3062f8425e52fb8ec47cd710ee27ddd3703cab7df0cc81c97e2b7b9093a52a5f240b62647c3ada9a2ded404452ce601086280015b1a5e15087e717d74406977a7522e59902f9611989ef2ea408a5854660c3f398e9fbcc64f36e353e8388eabd2bb18c3051501f22be726f4ab278a85a6f3e43193a3d3bfe9f748cb4f4ba9b5264c13240064c723e52aa803de9975f4e0a77354fc984a8527d8ac71533eb2eda74400eff0f0cec7ee9ae18e6c9b73958094ab5c054a2a9eae20f378250268011ae284385d58423b145794bec97cea1d904d5f41d9f4d4674bba5c69f1dae9e3b0704739a58adbb927bf1a35eec87a8e712e9de5120810168b4e6f9a02174a33bc93a3dcf2d2050f32142f9d6513ef7c71473945690a0e3bff24b252245d5298992b90b22cd6bd4ab3d54a526e792999146935f84ae38eb0974ef305fb40312ac031e935582af787970dc4052fa5523fe11d295df2fc240b068d72ba12e68d3c3b5d41819319a7aa902f29e980628d71bba04350225a348f381607738c3aeb89cb44188ef326c3d4bb66a04038d550a9dc078eb1209dfc205f9308aac3d720690c1e78108bcde66d36cedb10bcd3de93b6c65585923667f247861a19aa729d074452078e51a7c06c4924a424423e31995466b85b3826fba88fe6d11117a655708c7a3b758174cd30c6b85e502de6bccdd9c48277daa78f73d63e87f8764642124d209d7caa61d3e64b9cad76d6e570bc14e018131c6b4276d1c51863b8c0053f3214474581f3c63b7dc43bed524ade60a95b32731f716c7efb16de69f7e6adce1b53226a34671469dee810b5428be811ad724e5abbe614ea39e513c7e606641d4e57a67c1701c3b8d27b65c20e0e977d07872b7d9500955b9f340bdb051de39b4251225a345bb7f9a243f08c835bed4fb09840e2dbc378f2edc4824089666b8b4dd465a751377380d2f28ef520c62dafb7704c8aa258857cd9d97281744936a4d8ce1a238bef37def851deb0c022eaba66b852cee4ec1663d6963b02e0e5ad83d88dcefbe215cc664d3443eaa72937272188f8b187da9ba5931050bee56c7291673b5bbcc31e95eac2b957c205ea2baa2b296f96e0a5dcf3156474e52a57f90a32ea6c53a0c8aa3215c879389af0b7650dca7721ae8fb0ba346bd37ca99cf35aab5e6cf385453ae7558963501cbb796e62b132ceab05dcd92a61e532a10a2a5f852578fe852aa46c8b1cd06c715c7fdc079cf3ea009c33e75e0a14c262bba65bdcad1c9690d522c7d525dee160cfd52518927659e71c4849579738c6cf711c076b91f334eead4f5c944acaed9e9d82d8d225881f2c0cb73e3b05c1a4061514bc605b020625420c1561b4f4c3d151105468576c414489124452104ea05c19329ae305a3a81e6ab400cc161d1177c7331730513cc1054c12528031ea7cb8ab672e6072e8a146f7ec70054e760f2ce5e4f913876e907a5c738a06033955950c97ecb5a6267310034d0e6c529f2795744a2a29d7ab12c3a3935a2b25183e50ca75573baea31da574d290da5a194cd341e7ec593fd936dc6aafdea1cee4a96f44352164d9b8e317ebe18618ac68c1ad4989159c10e2045778684389282e5ca1a2ca9d615a108061228b142ea670c30cd9c8d3b2ad81444443125120c9a833992f6aa75321a6902215c494499f462bf86aa24ce0313347c32d91b572dc9492f3c9f1ea00aa1e2e916c59259a2f1e6dfe3d0ec6d44bd0e6fb4e2c15b416a4b21a5ade9134b4aa90676bcab8e6bcd464713fd040136ce14ad92465825809c7fae79d0e34ed741b2dae75e9365fae741da22b67eaf8f9ec40ed294b737b82fc629fac4b33bdb854f69c32573cefd5025ae6b90a94b314a8c20756200542e8c1c5049a338e87540a2ecdb39391146b839391134e0988353a2c8060c1b5f6bb355c445951399aa982864f872499256cf074b8ad801862065595a38f071952569e3c9aed61a60202075ab743510a88166ce07838b269dc5095ba1fbed440955819e2782c172544514d485152c556040d4a76b0fd50654809955a0f5b0f13743c2dd7dd759dc70417328cceb8f7990b195356400614a5316e3d6cde9c73cec9712e274542e98485f408a5b48636d353a84ac3492533f39c734e50ceb9011a27d99356aeb32995b72395b2dec71213c601fc922c2f486a729674300045168b2539c62c16cb729572b5e32aed581468e9e3f1baac940428d0aeceef91d7c161f55c0d847c5b2725fc92338eabd4b94abb4a674b4b4b2b1e32337276c26cb5d3b05cce582c564f168b3579b058ac1b38bc310523cfa16ca794d2eef64e811bf2324c01a79bd4a73d52f7ba1b47fa946008d2670ef72934e9f9a540bf497dfb1e9dc3fb5acc69c7f1163548a31dfcd6cb265574aed3ebc6595741ed0c8eb4bb676a154453df9c93520a9b1ffdba950d9adee0d85f8363fd76ef7e0d8e9caa9b2a494929a5947295e3bc725cc7d916f9c894e29c737a900fb4b8d23b184fc74472c09f1023725a64ff408bdb1bb871a5f39c94ce1f57f8192269917d25474faeb32aef93a157a552a928e77529c9a24da5c2f1039d55a9c0a4869fcecadd93a1f12c47ebb74a7568a83c4ee5ad40f95dea6dcaf3bed5a74ae5b058f672dc0e8ed62ea5f2d0b8415ce8438c2bdd5a9756655daa38975c2a64ab84abe180ce11fc0c61fe746fc78e5510c763d20904c4834e24ba674faeb32aafce6cf0f5f38ed4a7a98e997e9ececa5de52213e9c33c4760488094f088e25c75ea047f95ca4bd91cbb62b19a04dd2a840669973a92f99ac9d940fa4ce7efac4a9c016540200dcef05495c554ca69751653de7929a7e12882b72c5b4615a642262d56da4df3d57fca83c72a88035a52d262af94b848dac575920c92a5accb738bac786af820851a3cb3d9ac851fa2c8481fb2781f06f33fd67cdde2eb1de354748545c4a5e8824b3abfc1153ffdf210f5b387a49f3d8cd9218e96dd2a68bb9cbd82dcc1947b9f9d76607ae9d2c5cbf2c1ab4e57225880ebf8d0c726f5bb5db6a4e2b1ced823eaada72aafe812feeb2b8f3d1fbd53d639b672f60dfac57146ddb240f08ee57c600eac733bfb136f7d6cd9a6b74c70cb7eee813466cab20234642a9060660575cc0b66deba7d01f30d1c85532e7cc1760b961b178d323ecfce96f5e96fc5bc0599ee68dfbe75eb06fbf05b0b470d6b759d246e17725ec314f102d1ccba7449c4a5682663590bb38e3a64a98fc3bc751b10a704ee832ab21bb7be82ac03714ab071ceb950059c1a767e13569b500576c30b3a8e642a90404608d51649322c2a5f41e6cd8fe7ab55f0d9c26549a602093e346458689c041d1541c8b0a83ea8221b5942c6dcb79e2a4a19b54bc6b9653d055fb6786bbbbc4dcd88e6b54f162aeaed0d081eb922462e09ce89b7be43cb1dadd2a5b3ab55520501b56b8dcbc3c709456fc832b9ba82b3c339b72e64ccd562c5b44bc6addb28abd4aef0addb13f08b2b9a2deb52fc114eb51491bdcd54d2dbd451d1dbd4d07b36357b6b9fde32d45b1aef58e78ae68b7bc22deb473c27e5adef0811d0322bf355cb1d2bd45b9b83cd816392885fb0a27bc41496f4d6ef54f2289440daea4737a173bbb45a00e75669b6ecbc793f8eb8fdab760fa4ddd12a19c0f30d50dfe1293fd2a2f50637b0849fa745eb21782118c5954ec3a8b73ea1783ecfeefdcc550278b65a7395801c9f0f75a973394b68ed2a2bd75aebcc9101ea2b39615d22ce24495e409c7352c02f2061cf8f1ea8b188524e0f54912b7e15a402d362f74085350ca1716ce6db716a75be3c9b746bbda1587c755ae318f5ea3a5fed7c01f1ea77be82fcf0ea3e84e61579b3cff1f1fb21b4f9fa111619422b3284c2888a28cd9711a87b7f3cbd48247d7f4246a03cc9ab03d070c79ba69b9a8f1bc76e3278f2ed19ac96fcf81afe788fd6ae9d6ff7a0f42bc7bdd9951ce75509e20ef7365f39fec4d79c1cffe12cf403f472c08f365b35f46e2dfad072475518d5d3dffc294cbbfc4b8b62da5543b7b578c40db224aaa0bee78b93b17fec017d40df33c71d69929e7867da7020f8495470fd29039a37a65bc18f548c21be897828f792e73f9c2fb20fa756ab0f362ee73edcb8952669cca541a2396ad7749aa490a349928902f06e4bee8d772aaf44a51ea86eb55f1f6c5ccf7db87155292b65eac6a95bed375e6ebe7838b5f0a609881036145605a78311f9708f769432c1a007aac8d2574469ae96885f1dc7a6f4e571c2343d0e98a51a10a776e5725efd87371716db6d9ce72bc775d3d462a5fe03cc096b5a6c362ecb7db8714723505f71bcfec871db0d979ba61ed3c70cefadb101c7f95d9882fcd1bb598a23716eb39c2938b5b0068e35cd178c882689c8d01d87c088be1d66054634644abb461452b42150860c8ddead5697fcf26eeccdc12faf28c6407dd3e4b90dead6ee63dad53d81f1a85a8b62bcb4d86196f0571f4128a0956f50c84790f6059c6213e23c8144e00c1cf26e351c6b8edd7c6d7ab71a9c1acb47ef46abdf38adfe23c76d55882a8b89db03474c8b5dab210ba756dd71c071be8f300589410fd48823e6db3befd6ae1a2fb676d1b88b87b7e33cb5ab265cc20fa65d50eda2f1769c30ede2111a0913d5ae1d210e4d6804ca4854e38869d7c5a9e18cf191e7c325fc2b1f738472683950bec33bf41de2ac42236272a67c8f98b007ca5385630f948e27b98c0f36eee86e5c7ad3d4adf6be69a249ba695aad085044c90854bbc6224adf6e04ea8d44d16431025544895be47aa086d0e20871bef4cb6db3d53860bedd471a5786a337e5a7fb50e3d670f46843681c0379a7076a723d50df411fdfa3179fbd0339ae378a1e084b24131902911f4088100942848848c44551048988a1105127031c5114451f434451148910c969c96c40d6f13821ecbc7d198e2378ea46a08c44b58babfd58e346c4340742b6d1081418ef667b2366b0cb8b838d8461973786c5761a7a372877bc69aa7d7b919b26907744f87ed40115a65f3add8289f9f611564134599cdcd1278d12013430e24effe1409cfae8dd727c86238fdbe6b4d526db1f2dfd00e7abd6aced29071447e8c0030300b97147ef46fbe94062eee8365bbba83fada47fb0128103716a38359c5abb3819baa8019e18ca6d0d8015019ac8ff885a9c374d2d22f1eca404f5f56992da35de34d1247d3b8d52bbc68fe89594bebfce089aa49b261c9b37145b4dc7a9cd970e8e4d0649007e9200bd6ce6d2084049d00e1078d42c6112c20044188100363705e8c15a61f0e5fc00c223e3bcd3ce79378ef36efd0a4011137d46616cdfde6d09313f7e454749dfce55db97767558be554b0a88426b578d3203dfb89200aaa7ae8028b3283350fc0a8ef2a908aaa7449e168556c15aa340793ae78c0225ca942843d2a308458145f9682934f3665876d0a495ebb06049a554df4a4666862fcd8e8f87d8b36bbee661f3754d8d8d8db4e1513363736373737353c363c7cd0dcdbdb9b999b99159dddcdc7c461e7b17274753ba3819fa274f4f6ccf5d9e34757982825f3d77798244019a7dbc48f7a95de3b5c2f7cb45ea17379445a95f4274888b6fbf4b4cfd12929925218753bb6aad766ded62a72496befd82b17cadb4cba85da34ae916b5ababf2edf7a85d1dd2b7f37ccd4041cd40cd40d131aa94ea139512c7d8bbe7237e944f78a77a07a6206bd2cfda69124ca5a4aaa994987a5429a99c545e5830f472f58175484ab1c1362e7f77e158937cb431a7cf94acb476d10a65a85dde142bb588d6292dca0a4555692d8c40b3ab491b00810708f2a98f95f64a1cb379e92a1ac77815c2fcf103444fe98c77643855432ae8e2444c172750cf5d9cd89edd3e777162c573cf5d9c34bd2480c7591f6d50eab4eb3aa9722e65bf7e798aaa4e2d7a21c7d4620a6c5f4156fd4e6f2f617a872a60a1ae42fb2ce15361fa175ebe1c5ae99686e3f71fb7d42227c71dc55fe29c278fc831ee39aece9ee35c268edb50965b9a2dce71700e303d012c9b21cfd6f42b33e46ab3c5491ff99c7ce6668b736bb3b6dafa95539f6a987ae3848ca87150661219b6e7388ee3869e73dbd5cb39d7e5f0d479582a42c73967cdd7e4a22c1c4c38a958548aa7dc534aa9c400cb98cb85725de71cd7759c4f9f1ebf3af7b0ebbace612eaa244b9972550a044885380890322f88c3e15c3e174aa32c3c3017797cb664eb2629114f5880e2ad03b5edb8ae03a773e088c2a350f35586ec4115301753291a094aab454de658226e109ae2a7bbae60b9e08e36057a53c41d91bc64630b14272fb9fc0c470a64873b5a7be70b0bbb6c9ab4b40e716c4a25aa4a554bbb3c975e97daf5b9f4ca54cb6065b9d54a5729ec8344722045edf2d2eb162fbd7ef132fc326e1d4240955134a46cd933a83219010918d8171e01f04e3b058ae1727cbb1d68b258e057d9799213038593189c6dd511b145194534c051c5172a3c4852fae189c8a90d27b87041860b1b329853f4c0c4048682a1b4b4832915452d8b3a90905c08c34516968b2ebe33e804c38a55470493e08517b72b6a6624e144c654544b32b261718615d9c8f36d83125e48b1e1080d29b215a84ca1a38d3027b0994007d9c8a3a4c921a4a112d83004d214a41e9c9090be8b583eb2eeb313d2ec53cf4e45c0f14f5fd3c7d3698b9f5c627f2e59f14e4797dc25f327c771cc71542533fde39d06f2e4f6eb34922b31fbecbd89437af9b1868e6fa75d04102c21225420dadb3bcc88469edc1106932f1f432648a0e8db67444c01fb6a5c58c0c38f5c234269e427869222cf06a2943a60d043dd9adab1fe6bcfa15b5d86287c3f9d82f4756c0d9eaca9e12693529ff6520a345bde45ba9c4de94664b8302623f4ab88db7e8408d41de52c47882571a8d3a7614d7bb07400e926480792ce04470496523aa5945740bc233d0842c7ca1de56ce90026003151a3aa916ae266674e3ce9288878f8582cd6111ecf6159254c4660b9489f9d8600038833664c501162020b1e7208e1054d5db4b810454d8c265a40a3a0d55033a33ad611181229bff86a72e6b3d3105d7c583c7ea69edc52451674522a93fa254651228e92609264d3104d3fea48dbcb465935f081cb426ad25e8d386a881fa5d0d147492b2b34b1a5f6c20f6fe8c055c4811486972e63c6b041d60c70c20b31509c1145136264cd2f58811b4f5cd0a20e3590640d85d251bb52b20bf91a806c75acbe5adc6a19f3000431c0e0479954c310425126d524c79c74eef99049a91038c62c9578a7bb6e4e0bcc1087f35982f4e91d903f65d3cf1d605cbef325bd5d0c4fda38c6b4d5d79ef2ee880be9a2e82cd69115c38c708d9792c62e59d24e982f29876c4997cd824d85360c895ed2c1592080775c33dc13641c1cab2e9b8a74495a4fa7520ec9420c61d7f0f20466676797b4763515294a97341c9b0709e5280ede911df05cd999e171a52fa8d44d9476412c151509008020006314000030100c8784428148241c8d6479f80114800a779a4e7e609d0ac42488511432c61843083000180020002040333302008b518c381fb575648b30703b5ee744a59546db74d9d1680bf733f87f1e3601945cdb4176ee8fc3c1864378a8caab7e439351cd30e563e42dc5d7bc721c30c2e5d886c7497f712f49edd65e27620c715b961c7804cc881349cabc486d51bdaf249f885d7455360a1a15d24fc665a2a620cae0dcbad7ff05b14376fc9305e27f8c20536ab8f5f0763351106c2bef84155da180b3275d54432032003c97dc740085d3442b41d4fa79d7741c8ac104efca4f3f75288badf45322d3c37166d91e0eb0ed6099814a2d7f29b181ce2f0deb1e28bf3fb4fbfcbea345497ef50cc43ab4629ec02d9a1034100f8d23258b796aef7b8db7c49364ef9d23385ae0eaeaabb8330da8650ecb996038b202c2b09c80dfa2f4daecb695bc483b1f9a7e70bb00ffe87ea278cbf085ce807fca3bfbe28d9eeda4ba126029a659d9a83a4a10a6ca33062e2ea31132cf1f420659498932488a3ae3c7680ce447139240437fa8b0952025524b8df2a28565eb3d2fd6a79d4c9fe0d06211796624b54b3e27eb67cb1acee8d247ed87404919d320a9b37666aa0d5411a7d52c408e6a1721314a1d5b7e9c7c120356f48c2dd307547f13b80c65c73428eaa1b2fbc36d70707c803fe4c1471bd9bcd6d46327b314bc34d5012c7af524d755789b82c40ebe2c43cf65a699a82be7491b3284bb190e30205dd890b39631aa5c64245648fea1070d753de74d3e6c60c072b71e813259dff4676b05a50db9d510bffccead67337ffa3f973994edcf03497af8f10fa36147441c313f2fdd9dd0189c5be3874bd9fc4f8058ff468c0424d33c681622bbf9a624ffdd28526e7a97150178087f2e6a3ae17e2fec2c13752e0e18cd903ff0d8b674fc33b51eb90e4820e3b12299ca22428238187bf7f018d929b635c7168d76be516da95d045b94a7a0fbd8bb65f1011a318e8a42561960226dd76a307476cab967ea18d8b832f0f3eb0bf55d2d28680f88c5c8e66cf20ac78b10f042cff1abd4add7cc7de0f80ec48eceb222c4f68aea21b9043303400a421fdf27a6993728edff5e5a2d0ddc144350787878f49817ccc8cb089f60b34a9f75e82781d69b3088033578f09ac3b0e9a86ee99d2bf5d312591549afbdb78a6ddabdea1fc3673cb1dcedc753896b92b7e31c2a07f04c4ad06754af0d4997173e57bbd1884cb64849bc892b91dad602e3d8e69fa630de71222e9095bd8139eccc84edb0691ba2a8598f9a5701b5ddfc0164c1e869a33a6d62edb4cfeb4f5bdea05f1c8343bb95381fb4171dccc61134a32a5a6d3378d0cc7c8f520815ddf6b8ef9580c90f11eb0c0d41ec0af7f22564d55dc88a7841ea70202ee44ab9f36ecc3a71fc98e1ba4e7b36353a04cd03baa13c74edc977ee33b6545ffa903112be92018d3f8f6a84bc59cc238241f297d1600deff980f65902ff87b23f128240e20f09338918c82a0d138136443d12472ea1c06b831015f7ab0830bb082948709d9c972acdba99888b73546fc48c3b8d7b4c7be3d0520efdc74fd5512076777e40010512c797a362f2772612a077e7b7a0b21873c59c32ffcb09a6ab5df8e3751889178dc47b6aefb98a20023e861f4cc52095797a67104310a2ead57bbac1f66c217620a8b0f924ae8f3b4eb2a8b798015e67a5bd0bf020427638113eaafb85e64805e8146765503f12ef0813714ed1feac8c97cc4a1602c41e8c9a296d8b32bb5ab738302dd1c6d96a3999701c76b8e508f042d0be3206a00283e924d3bcf29d7518811961aadf2143d400478159783fa6d7ecc721aa341b4ddebbcc91d02d98b3d68085f7e26d1a316053ad4a722d51d02ab360df4eff4905a38aedf6645bb427efa48a3afb8d93640c59967d8c103d9ba4733087c83287e1fabceaa0a1813f3feff3fb11042dc2aa1978b3e3dc6f6827fa1c1814b9a9eff829f9eeaad94c471c58427130b39d47e50c93e5f30edb68fa9c64058ad1076c079dcb9dc3568f946c3a06ffa50cc7942e394f91b316106f9b5b1fd89668a4312897b96d3016aa906fffcc68d37deaa321a2d090e5b4913b924b0b1d2b87c2c7380f299d4ea7b1efd85398dfad9a5e68e8daea39a22cf1838742fa55dccdca22d613d8f07b2e11e9a16cab5089da8c8a6650f33e3df1316659350cd836464a89d4acf6f4a090302ae1bcfe0a07b1cd75241d77e0e0ba29bc05987d0b4f7b1bc38f857722e1151d5cc601f99a9b98b976e8cbf37e88a7ba933d14eff275faea39984cedb248691f10a30cc08086435f306fb013a07902514a48cd42e2cc4a8f5ea4c9a6fc26a224500c0ff4a7aa0687659b3121e0d52ad403cc7e07d44f4a1c9bd3967d64da8d49d0d48c814ceb42c9ee902ba614e4c7dacad87fbc033388aea1ba93e81e543adfd55689d8493db581b6e42c7fcab4af7d512e940dd74bbf31f49ccfe89bb430f39c918867be391871f7c0d5e8198cdd1156207c40038f0d918547ff130820a2d30df0807cc193b40a9b5301bb6e3dd01a66c0532e383c2f108092e113667414f1c861b0fe490c7f8c1b4d888961dadd61c961190974e65bdc609071d042741045b4d5a40fd9fa3cb3ffca31f77822b4cef9d748fcf6e39f01c7c44069d14d7d29140d3811dba7250c7ecbfdb1e40c96849867093412c35120e6f706e2551b92ade4efb6d7b56558fbca57aebe7954542178793951d8634222c39684cb75a765caf4f7bf358a4ae676177565705b23c1e3dbf975ab208dbaaaee2827d79af1803572e3f095e52a701f82eca6a8d2ebf9a15c641e353280b217bcb2e6a182300e8d61e276c5a984f25fac986652576ca6d1b76d0b47f525737474baa3bad06fd40dd0db8b4190c76a7eeaf9d9012d299e35923d8635f57ffe46513df484b70797b44e04b191908432b4bc3ae6b1a9f670350965ba230a85080b5ccc8132d0c2205cd1c719238d9c724fdffbd9993883b2a98257d2f6057ff44fecb1f5184159fd28276f6365c0ede7bcfecf14f7f21d7d9b669f6a3ed3d02115a234e847cfbf5668f77dbf061df4d31788e6cc7855acd4218ecbdc3ea7451c27aa8450c6311041f4ee8a9996aa600d5fc9b268273953458fd24a78d63d845bd5b4fed17663aea245554a7cf2b70f0f5009e561ffda93e8356d4337e2fadfc74ca1733c587f8052a77b88c1879a915a8ac8ed394aa8337c9c5499f622906f7a243eead027c01f3397d436c1f7e09fc84419fa04f803db49aae79db8722a2a1e8044321bcc86441d24a6b135dc271229e37a2ce57e823ed331d9180530765c547e0bb005be0a1d524410eb3b5201ff638fdf74ae59f458ebfe0cc6032148294befef8310e53e2f65508ae2ecad1ad9aa2efcd0acd9b94065c704408847a6d9d7968c94703b56d01a8d80b97404cc5b01872032af06846e6e1dc00bc59c45060e2f3a62826ddb64edd1046ed46acd91a8d527a6541e8b04d00ed315da39e9fdebc4c3b721190168b0dfd95f669a78b9e6d863a4d5311d2c8944399fd968605f66f670a732c471309e0d57c697818e7b499b086257a2b736859f8a170a9540d632ab5bfe4fb2e081667d8213bafc2048decf45ff073d157b0905179b700d7ba80d47cc91e938b4ecc1b44c1f8473cd5057e6be8bc401ecd28f50cc3037cbf02c697a82b9da0a3a41b9c8afcd657b88863499dab8e032cfca1b687d1cbe31d3693bb669a90920f0f8a5280f34e25a38141b493e9821e421406a531a45126ce79a8721f1d64b348d1843e3e44ebe25bdaa3e7674aed49d9b6edb77cd3bd233fff2768a878770f1685e406264d865e4183db5d6f356485df6c6a4b8e67e91653dc0d614f76b6a5cd7eab0b3cf32ae6629f406e40ba179a4e0610845becca99385e1b02c55ac1ee93edd17a4a2eec2ee89b0f2c89e6c30191e82ae6a34edc5b82029902688bb6eac2743111d6ac4d9989148ac8160709c13b0deffea8146094ccdac916f2982b3cb46e8b6f23402f8924b69287e96a1ff62a4bf8ed959413130f5fc82d61966372b1218cd2ff048fec3074cab143bfa63d4c7c39e624979c21a3fe029fd5401f6cdee3bc08c0791ccbc0eb555cab49921f68d635efbc208a50a2588a4e58d553671f80f49bdeda49c006f34f06f5cd7aca013e5dd9a65daa84bdf6ae631c1ca5f212f8dedd6cf5a55ae5043ff57f613d1de01515331aa3e4a120e4efcfc13eb2cc4aef5daa5d8145b22d257c204351aa6deacc6fa743fd7bac597320f84238371cc46b3394c405fafaa13d9d6998d9fbf143c24406a8e7ba6ab8e4791f8b3188951fc4428bae2bbddf31ff7845bbd9cf0fa387e8e5f2e84482ce1dd105315571e1957a0aa2f971d064939053d8521c7cc99034006052c4b1b612ce330b6d6b5a794bd367fe147575403eaaed52dc3043deadba8bb9e3050faa93297f1d7194f65d6e1e70e03f7276e6e236b232743fff06670aa4cd42384f0830160e56b14d08583f09e8cc4a3b3bce508c005c0729809246becf504c45edd9d8ffc631b8ab76fcc2430b7c582661fd3431bf8fa4aeff2088d8c781da06acd79683418012813b873b8f84af120fae40da5ce65de42c7bf55750feb9062c119a0503cebe79273be5d027bce0f774099343d200b31de35b3dfa732802d91dbca4710747911288003f4db093e0956c556633b32eb16c5d4fe55a8551cd80a2e3af64a72a17394b2a05f61e02be9a5e1b2a29e303dbcd3b36a550674c1aceb18a193257a610235a547f292e13510491029855f343d79713cd3f34e756ce49984860fdff86bf8d47082da31cd30bee9442482ee689ff1ec39c7fa0adc12a5a3a21454a994825a4aa520c5d2dae3a5e2e6fe90e1d2b39168cc9a53e042962304f903af9515678058985f91baa35198429543693495a53eec5bbb102cd3647b1e2da1cf13ca4de52b6392dad2634c59a616b204f8fe4a7198e01cd4ea6b7eeb32af60e1905556e9aed64680f94dcd62f876b721e5beef7544c8cc6ca4223c6f8239ff319108110a2e3e37adcdea025f7f18292d553a62caa96fbd132e0981c7213b630288528fb316167d1dfff83c3d46aa14029458cbaf8dc5873a159fdc8e5af95e358af66b376689549b7c1363bc3357eecced98bb3cf6214bcc610379ec7850728a640e898348060906c4086623b6d066e09d27d78680d366d0b98e10a2a3a97ab9de36c9b8b6de5f409ef0820fe4b5cd117c915fffdced54912e87eba972c58ac39ed79568854cc93b40200e1ec204b9fb46fe2451d904ac03155ece641d0f94eb99f93700ced0c12e5d20e349e3136c2e6e7f00e2f2996d28eca52dbb2b9308a3b483ee7b0b26a744083de9896c64460dd2feaca3c3af0c620409730d2727412113724036c7629493b04b8987d1208efad90669879a6161a5e2e09be0b8e3664f4ca899679ea8e814f7e335db756eff0ec5813fa3971a83062f2567918afbf43d2b19755dc1d02832649a84678ffd9eb6b1433a77b1d62fd0fa55b360d64c9f55aa990021468884723b55e66b39f83e6cb7575ca88e41108addfbc1f55f5daae97d3ed267d7649d61e3a75d152c18ad152781a39a1acaaf7d02bda7b950f7bf2856650fd9ff5e180f5552496984650ace359010c982a163bfed4a8914badada2efe7d7cdf652dfcca1c1e1d41d35a96df65b3afa80ba3877d0bf4a1375117ca9220e63ee003c8ada11d06e823d0a34b089a6c64b5a7e609502b2af0c05b97597d2b6354c3eb0d26b24253f20963269ce41d5ebde401ff2898520158bf403228881dc1bb54d5e8f95e7b2332486b9a137a8e3d2d83a80217a1c495ec36718aa68ab8a657b928e254f7937aa6ffe95452ca59e4d40ded5023bb19c1709f804fd2a0305580faa4aafae769e2d090156bbfcbec546a1b306b3739d5f175ce3eaa13deb1c8620a6c27d2858f7122e778ab6ea01ed4438a2b22090ec64c53f769539c98fa5d11411aaee7e18f3f1829e722534c16410c6fb7ae74e7de1b1e58422c0780f803446b150570e4eb107ff8320194523ada88eca58df744a0b9780ab8c24582cfca2479ad06118de95a0d6dfbb92a9fadc649dce95df7cd0f13b097f9db0267160efe0eb5e6cc5a38dc6ccea865549b3969a3f6ad987243fe14f47363d09be341bad273ec32f2453128642d8561a5f958c4b9a9d32c1e4c6825395127f7eb209e593669765c6e335e0da1503b9c8114cead60dd90fa0a652539dbf8ee8d5aacd24b0e77c6c5e9daef4eab470f954665576fad550c0e6b560658719f80d5ecb462dcbc2a92ca68be4df11324187eafc09d35b2d10ece461e613482b8f7064ec22de224d5bc1933741f6b76bfac3bd9b3c27cf7f325a4d1a4e8e3118edc34724a8eb0420505ed289fc5b4890791b42d50e4cfc39323c8f1d736271e2eafe555c63f538ec4995fd59c6cb1ebb5f4ab9f09ae0fd0ecd7ade199d0cae90190428dddda1bbf62dfbdb41d63cfcc5916d98eb18fc59ce571395b69f76fc42859bb5c020ad89cdcac7acb3b9f05a9fa72564f26d500d8db411cef1a91c5f4db81b8f2469ef4c177a55cdc25b912d5b54bab8755d59c2b11cc5d82791a022c6503cfa493821e41cd4c234f6c25609ed8ece51cd9bdbcf89ac5b14763a971299654f1bc773ab05363cadc5a33b8050f17535988456f87e40b5e23b39dedf3c7338a1e803830fb00a59a992a1dbfebfc77bf6cd07eb1472bfd0b3ba59839cdaac31030ffb254c3ac9b2190cd841259c335a3a2d7e1a0475d37f51feb634cf783d8d3be463c6e83d6b564438227959c1740bcb80ecabd6a4c56d4fc2f3be7be16d4889a9792f8793e7f6e758385a253b1a04da51204fc7dc22feb5853de589cc6c76345218418ba6f66900f173facc88673e2ff196e8bbec1269c1e216e5ee25a64c9ecb8588bd6a7f8b7b1d8ae17f33ed2f9d92379517cbd523a7c8d23d87a689f7543bd6f467eb0435071a4c4e33a48520cd82da8aa1a3d7f837982bc4a5479bacf90980b75d1b88cf5d0c4f4956264c9869f2b7d0d3c35f04c561dcea846f56dae809a5c82185fbcdb33c40204a222613e7e59bccc1b992a73e7e327d524c00f43824fe704bb9e99ada040b00ec1b5f30d0ae1cf5d5a75349ecd79ee02c6425045dcad1ec999470422152b8b9d99cde31300e7514172ab45752b2a81ef0e16259ea7cd56282e11dc7e5487c9f14d37c4c776a00fd0097afcaf7af67bb184e6f18dc9a2ed25541ebfee4d79a4e2d7252dafe153cd9754637ccda7e565c7c30fd41bf4847bb43ccc858a9a98c0f78f4fdbaa9c5adc4700217c7465119c039b85f1185f58b434d072667c13a63843b8d2d9aa20044dba5d7cfd6f2e0fe5f51c7c8830763333fc6673e069b38d55a45b62d5162e2a1f04ad1012759ff3b0d8067d4f0feee6ac478171f9addc89995902aea1105b26f8cde8dfa1d1ac8074e01c5c9a44b1efc89144a005b0b2751473b75584202b6ee1ec15dcfd1664fbfed5ca77e2373200811fe9b04361f8931bbd1d8627a6f69f7ef92aea74d6642c8cf6c9b25aaca935aaff6ef55a26d849f6cffed046224cfae279cdc9cb7f9e350a30e65160c1ec58f720e6b412e6521533bca98f25b9884c038705879d274d3a6adbdffe8f244764c356b5650a2afa37257ef448c686568ed15a1d69c726a95894eb7a3369df32176102d06f3c419ac6635e7becddcf0f98c6b614483cd505ecdd225907a781374469b0a8b463510f5226ae5538de21fa2e09874a22084509f6994bd920dc51d4015d903f37c1663cee521c021204741f09b7ccc41c3225100465f7590a73c9d0a53ec527b366097c1afa20c511fbc99189b5d8f95eb65fc7a93658a098a5d984b3f5a460437219d65632b1d59aea4968945c0a52ceec277fb7f96398dc700efd9adad510f48d5434011308fd39fab81bae86130c874b56b09f95a98f65accc344441e9b06db7782f5658d0e40fe9bafbdee7d7537dca463734fd2c89e91d59f33b69ac4248450882562b9a21dece4d4be001c12e6b981e1cccd36d23d1023d9c090c65d9557c1d3d4ca618ee390caae0c6adfa737dd02691b1654369895bb13719c10a473ed2144b1ef8094e0b7e012a895754246e61d48721e38035e38ffaf33d2faab470d961c2a8469a89817d2417e7cedf6d37f32f078fb89c4f02bdf621952cef3a0a160ba8579d8cb6d48dd6f703411ad0f398141c5578f1f6e31b51a37486b9040357aa69366a2c0401d527e4e3a704d825129ffa7dc1e5ed35d7cd4965d79672605202da169eb538279185a42b7e77c322fbd558abf5a5e15af4dc602ce605063165643d1af191c97d5fd1cb55c8c0c71f34030d92df76c0a1f065388396a9628675ab8671e6aa7af8f9079cd5d34b5bca18bd514ceba8304c31112ca021da5a74a2d8a33815f54c6b16960a27bb288cbce20072be0b2aa1caf32d3c9ba139734baf1d8a16b89399af1f1bc27ade37581d19dda85e4d1d03c144a35420e6adf0fe0a524d8ae74b65b3e9818c3be37d780e11e78c11bffb93ed29bd56de3f22eb2d916ce39c54a5d1c15a2d0eb18c36966248a559dea227a5d13530b836a887729d3ed77628203303562088a0f38f08b103cdf5b32f6de0dd188f3455e2ccd02fd446199e46edbadf56bdb94c22f052cdafc8426b406afc09832f4b0da9990adc5249ae3961129f1339c583940e11c38e46d70a34fd74d6996b30ff541d240b01efaf2520fec7410409dc53cca0ef8519eccc7ad71d62af948ae96676b215576e242ee753fc0037f7ab69056edc60e08b255a0775275c6fef5fd3ac9edb4145cb19417d265d7887e3361bb3f70e9c938bfc4f752e09be832ef5da349742f90cfd8a6fabf66ab4ff9808a143c57baa2bc1164044015903142eb427f0b61ce29e489fc5ca0583b3f77f184954b8160d5e3af6ed867f1ee8e8ff7d9c2e09eb61884c21a95b5b9009908a4ee8b43a99fd5fd099124d434ed189563ccd14cedf91542f3000d31f4057905daf5c7cb67e8d6db9b76b83e02eb09023e706bc96071232d16fa9f99867df2810cd6e79c7acbaccb7f39a5f2b984947d751a6607a8f606420500026470794da57d035622ed5fa6bb5df52b082451da24947a9cf2f1ae61f875c149854d77c60449542093d4f45cd3e1901a6269046f29b8c20233024f5fd368424a0b1d1f47d103cfe136cc08f0e765961a6ca79efb1c713b905c4b62fc2f6bd9969e432c75d33544e70b29b5b3e5b1be2a88b19bf55645a930c426f6b3c8af60e876fb3a4eca64067090ebbef8e8a2d76d511a0f20163ebde43f5ff80a5111442fd7a2fad3979c062ac8e88e33936cdafcdf6b972abf9e37233c3b425e2f58590cff84e12d68bfa923278026e3c872fe345fb63c3527f58ca43508b8a58da0302a0ad2a9b544af999cb4cb7e832d450fc227341df53b52df19d81dbb6db6c3e40d9134a99012ba0d7c0248c43761e8bf2117e8bde4050e6cc8686493698546b9b4f0dff7bec57a0e078b69b6de87318cc45c3f0994c75a7e93e336944f1283e5bf01059a4d5a013cf9beee9af4570deec3caded706e836289d0a6135262593ffed843c629831acfdedd2843d87baeb183297ab14c281f91cc2826d4ddb0aa6c536beaca7b8f03a9fe41889644778e866a471c3fb6598ae6e5ba3b9ec49920989fea34e79e414d4f4bbe2c6717b280fe67ec7515b037a5fe4058e2a8ca658a71bb3990c577496f77d74ae3a3c32d5c28c2b6de4a66cbf1e000afdb65b5fbf162626c5d0745611d7852762ab70adfb1994b64c3f463c3b09c2cbe9a5f6310c0e5ed9b3856b1bd6944ae860417a5dbd6c32402dbc2ede1f800e81728dd2e54f167b57f8f8dcc42448f2798e39528c1e13431680a733704ba5e12b21fc8e5699abf863054ce46c19c0ef6b2066f54ece4fad39f4ef07fa8a5ef2900fff2483a5e5a869469881679bc46781bfe0bc7473a0ee7bd3b0c6d8c8a9f279f1a387396cae5715a2c0b9bf2327f3eb4f88a5b95cf077109c25fcb3360cb18be5870abaf2404a3610bbfdc99cba86ffb3a1bf8e790d0edf98c4261614fdc035c1c7292692dc26c1b690d874f4fd07d7395a8598481b5019ccc3b4e67e95ce8a61fdbbb710ea6f559f3f61810b61a8fa1578bcb5568a0f6c6dd4879208452afd222e9a15b78ddb334ee552d1acff70596f6de43508199e9b0dbcfb8f39b1ad056279aa8e24ece7730039b391702bc877ae05d531e621bf9d5975bc9f3de0a679f72984046691be6e87c713f227baf7ea7ba3c50c312d7980d62028b878426610a077dc16155dbc808715d5b95fff773231fd1ed3427865c99b2708a4a75d89914ae17a714cf84dc4250cfad303068741d2b023d38a36bb6f478a91b9d568675321119f984d913607aa1d5c8be3efa6e4b52635c222f93167e9750f7cff6c83879da80755de54cd5234e78967371559ed37fefcf55fd2e27c63fe7cbef4fe00949e48b275ceb293e0673113e3f666703727afda784cc641bc9b201eb3dee5ec32fe7ccf51fa32d5cbb0089c47341f9a61ece4167ff0b3e6708ab357fdd0ef990821cf71fb5db3916f945b29311de050d740df004e02d8f2a344320bda11ec1b2bbbd4c9554b6463b2bb687d212decf1d1b4a1f5ae9f6abd1b5543451cd4d3db9e7141ff80765025050a9d69d93f75f0468502b00ae9217620628e80ec5f15b4bb0fd61e27f47c10e28c878dbfe7ac1bf16ed4eba8d203233ba14ce744261be1b143d3489386bc4869346dfa06404baa7de5e1d1a5fd26cf45dec6e72534a3582c061ff9b56c8aa31bbb76e7452efe5a6c3874a2d24f9d103adb259dede370ebc2cbcb9fff9a67086184d88a1cb98bc08cedb19144d5fa6110101e605022e1939557ad4059f03665471b3c02d36837162a6c7a94e128037a3a60cda490b47f92f8eb5953c616c11357475d2c505d1610637f5a9f95413de165d8bd3bca2ac8d5db03274e9da1417b89c674be7d5e68c4ac52a0c2e5ff16dc08ebeba8847be84e29578451af9128a7220a80a37b4ef950d7e45b7234a465470232d3252d94d5499110a6e365f2712459fa84a2b3a4a4dcfc62ff853b1b64a8eef8aea9a815854a358204b74cb641884ffe5350315752e23ae0331006279c76b6277178908d4834bd64a31643d77238a4acd72917023bd96156c15be8439594c7855c5cca958c324417356134cdd43bc2b03e766800e0dee2a17fc40654778fb2fab0de10cdcb56f3c733b8eb4d8b59b338dac4971c8648ef0efb3277331539ccfce9c35a8fc546e20816a8dc7aa35a4ab3596cf371c80dc5c5ccc817f51183d43e22908c1fec301e62e01e6a93dcfca6a52b2426599e61b3c035e00c70d147220500a2a3b9f4ed359d622561160d30cf22c060bfb519be2b1f73ae62685d26f0ddd927ff1074fe2278d44b70239da95b569d085b20a5ec6baddc4efe39eb73c98952fa842927aa53a61a5c590bacfd248de306ffd67df6d4a64aa853c8a262b5707d8e21f2e0a021c5894cf6c46fdf3a93341447376e21e05a45509d34ff3fecca8b23832c3c7202bf7f7a4910fd7ee561ec3933f1ca07a86966a12f207547c0a8b48e2ffd49b00a6926e0432f25f26e0820d14ebdd66a779b310e51ce4f8356af93b7f279deb3b10bfd904435d724c6a8360b0375b0ce4c8337fe7892eeb6977d979929b535cbfe099490c9631cd16d13cf4d72d42380aa404ceaed6f19e995ac1186265d45c350513c8c98bfb79d016b119178d95a5751b0abd87f2aa2a6b47b7c560350695eb5bc998f5cc16259b2b76c49754ea164ea3350628d7ab053aa15634de1d5852aad60209bf9ff1452da49f6231453c8d567b7256a71f52ac28e225bbd4bb5aebcbf0fd6a2191f1b1914fd24e2d888f1e385f5122c3b40554fd565759be3d356ca67b252404c673e3786dd2c403b88f75e1cf6900ccc23d66cd30361ffe8f70521fe93569b64c710896aa6ef22ca3158e9d08c7928c33846741b869c6f30d087110bdb873ba59776aa4cba60c1198bf8da3a272aed5aa4763d4f683d3b54cb7141f38afce25e696f119e5dd15d9ea1cc8741c544203ca02a041fe33444a64d53cf6ebcacd253a9851859c2465488bc180a700acfb82ba821b5700a9c0e4f794a00948f39c17a239ba7d3f2fbc26954fa1b26047625e867c83e5a5f0e95dd0bd0837a544618dc348d77499c23696e08a1cdd02c8a240104bbc0c25589a93809d9a1125687f8a04c615c1c0a1c3ebf5b6a61313aa116d52e466ce6cc1170b5fc3bcda137c3246d2e393b85817f81e2aef085040d30912f3a548eac31a979ad6e108ffef54e2882669ac71638d9c045e7870d976729c3ab0b0790926f15679a19d26bb8c121f1f911cc900543e6c1851d4b4aeb63047ad8c86b09c51945db01269e5e3d8c1a13093b2ea8afecdf9e6722eb64f81457f67dbd4170330280d9aa1a0a1f37e500b4555b88ed83b3c13ecabed3f48120e35a3ef3244e23fd4cc2a31cd51d1f15dd4dfd41d38941ab80335dbe2798ab1e4d24762e7ad383c9464a5a674d6dfecf6b8c390eb4b92f1a85409dee788d4c72c1152d3c0bc8f8328aacd9aaa6d6ddfd201c283004366a0f2df7799419a1ae4732df08ec6329fa63b5a021ba2fb5c682099e0258a88e4e40b2e4563515ae10546e94c2502335575f1324068c5fdcf97f2aa6184451ca2a053b2fc60cef117e6d8fce906db061cedca027f024e1c815d7ac07d44fb125a28a735700dd4b5abe1985b1475c821b64ea0cc4755e3446373a21ad1d23c2eb202baa7dc2241fc23c3610514322c8f6a5186d227622725323f0008a5dd699849295f4be6484fc9be7e7834d9649be5e9560a344cec6912def95be64299aaa85eb1c4ffdd4b4d4f1f6af021335afd6129ad5e5bd35da1be8c74d3935e857dbe09cfdeb7b15725aaa6be55f56ace7a8bc7eac44a5006784600d68d8a34c14e04561a1739818a68d86b4444081a71d869588708964d95a17f0b6daccc08a08460bd311521781103dbc64498a013001b8d230482dee2c4eb7f1a95b311eceb44bce3e1d9140e6e599d9756422aba21f553da12fae86e4a2a964a6bd9a194053eef89f964d12022aea9e902ea08e9df13638649c749c5d9828fa64b9b56f3fd08ffaf386bb82e95f092aab42ab333d28c205a3040498ca6be240743e6a0aba4e514bc6b1c98a71ca5df880a1e68b500138c6df8983b1cee74d85c5f045897aa54bcba23bb47c97337ea301440e1feba9f351bef845fd184d3a1bb6db19dfd82bfaeca220225be5e80d129174cfa30aad0eb3be76b9f86de448403ccd50a369dc2f872fd75435bac3c7e67e35981f5a59406c94fafc2087fa44fd8ff0f02a2b78be44a699d08e7671bd19fbaa6edcf344fe41a17462334c2c71c1c150caad9566398fa3bc0d807dd51995ac21ae81d0e410445e0ee588e008f59e3dc7cea095b3fcf2c515df224db5b454d755f4dffd09ecb954adf120acfdd1103cf741c0efc7820c6d67d60c5bcb36f108c5e34b6c7d4a650d57c7d1f9570ef8cc302ab91a037333ef05e7b34193f60d443672c3c14d223d2fad42f646520700451430dc803aaba04c53bc199200b58840765ec4e38e6f19e9e179f67e1f2512d603a3329a6ddc391633b5510f61d36c8a440825dd9110458d50e0ca12192ef24b099dcaedacb90ae5cf30701157e781a1df0240b9acb74f922017d0d9e818664bcafd88761aed9a853bee41c03fca0508080ad895ade5b01ceb27caba8aab3ccfed95d2cf525c0d241c73f8192ec02d2e3fb474ea35e0b3f3e45d47885e58f92af559c779c70f90c77bc3a3652e2419537ec854b8f6515d447af0ad6be9fe5d344e82d1ab23b551dff7cb20cc013331d1b10aaf736e6970a18ca62e291979f7a40d7e04e777d1424f1f4c2068864103aa141f709438ca9c58e57f130e00bb97dcc12e72bab3c64e48723d2605c839b089b8fd5b330a38c9fd9016ee0f9280512bb2b8c19113334199f927f26962fe52bc39e1bed518f785adf0cce1e3587db15d32363dd281125db9b507756be3f67ccd0e95133e3e362dd52cc7961b2ce69de0a415876a23cdceda53583518852eba74958e9a6a3d14a4b12068f85bc619f27f32ca9c5d17fd9e6f0006357c430ec559a81deb1e177a16601e3efe9e8473cf0fb5688f868412275f4bd99c0fd927ff639780ebac27f75b04dbffa731892f6db2e0d905cee153c9178ecfb2ebf7154ed0380ed1b4580e6c424dd1d34eb2c5dd19e4d1bdd65b228376d08ea35e43f9152c840003b46c02848301ed9df2e340a8185a2400436c8e2e226a6a0e5cf128404f51cc141fe59b2938530d415c8cbec91e151b7020705b6a7e6029ec15b328ec62160eb2008ce202a7f1dc1a6e2bc05b4786cc461e959722ee86a9f07113c2dc109e128deaa69eada03b7f077ea028c59bc4533e8e43ddb1a1d6213d2384c62c26b253b351038764e5afecfdbcfc90c961ceeda12cefe2524f8d1a46aca15e4d5016aae6ab2eb4eab74b1266dbb95b791728c65b97cb794f2cf1fb8af53eabe027431813370c8617e0e7bdec37b5d6aad66ed02eb1f10572910561561252a85df1bdfc259d23d46e09fee0635d7b6ecd1d8111169cc126734e042cee72353f9b782b6d4695e2226d43d3ad1ab630b6aa73aa1a7d03d2c2ee7ca3e3f3a86c971f436cb3655dda71738a1a10b350d6778bc8dcf4662f3906f7ae8a7c7074465dc70797b09d74ac479a7a2e812ef2bb029adfc370473d31388a55e7d9b1a23297a5c2714c47c00497bf08c564f60e633ebba7143ba2f1071f2215bc0b8ff67da776443d6324203e50b9ccb87d683b0afb06da05be1f23994d531d3f1110bbf635809e7b5ffe2e46633d7708f0338dda6e40be80979c1d3d713c2f21ebfa0f8dbea85111476407bc13172338690be177d16a03b04d97433a3674d2d784140046352b11056cba60def56fba7bab5aa7d41fad2f1c6ebb4c3fdab040b920dbb15427bf779e2b5e85f2f2fab036d41a6117bcd258a9e7be6ebf29bfdf064f39404cf2117883234cb8dec315dc53fdb801f1309b7889725d2734514b72301970cd9a663c158f79a9a2ba2b9e0d13feeb7ca25982c1f0d768845cce4d71768e67b6f2b0a77c24e0fbbf4706b94bdaf020ee1173277ee5184a430aa9237d7b4b905677a8fe86edb77a1c40be06e8145fa2191df7609d060d0960c886ea97510beec072c321e6629b2c77bdfe80ecfce0d2aa2edc6bd66a6f1b794c4634aca61e3dcfdc7ab8bcd76d3b00fd0102b9604ec045b96bd81575b491056aaf2368d80e1797f60e8ed4be81cb0ced8e5b32f2302f5b6939e02e83099a6536510336c3b8c6f0248824972b8335322741e8642c7c9b1c245c7813afdf517e081d73802d5660f5c35c2073a1318a6800d19d65c222b544fe1a3acb06a21c2462372ca9c1f14d6627d690a81167b167770766f0cead1b2814b71cef3a0b555f391f611d8db3a72d80b03c75dc5a9e912f0067395f88cf39f7672dbf6f02ec125846274e674d15f5171edb0a1dbeb224422b55ad0297fbffdb453408cf3eb058a04a85d6e64bbf9114b1b5f027931d063e3c049f214770d9a42fbb9211651f98f5dccf06aba7f4a31c93ee92c5ecfe9988b203896ada622fc5e4680fa4b4537cd99da23cc0a837da0431c4e809aa9e4c1c22ef301a3a32258f62018eb6249d5ba1052c89500eec777472d8fcd90148001d3b40985ce3ec3d43712aacf6b1ea1a458a5553d1f1ebdc1f76c6a80c87b00b766ecd25593f8a8f10dfcfd0688874efccb4ab83738e25ba8f7aa769c1b700365341c70b0ee067ac22d4cb58cb3dde6ab0b670db88567cd765b7a1cac309cd3341f8d97d10df3b07503058704fa2b050c11a2edd0eeb71cd187b0bea5cc00015e3f870497906d49bf4b114054b546e08c5b782360119d30f68fad369d18072c2747d597426aa20efc1495259121c312a2134cb22386146a0249e37ce94bcffd2b3fa1b89a32872a450c6deff2b284eb15e789d6e5568df3a5937858a6a5df30ed6edb774f2faadc77dc321f499c76b7e80a056b914fefb64fdd419adf8949057eacd4a54b2e4ea7a7c2f44a480bb04415cdf10d7943e446fb873f598404d0b2ed35c88b1b95ccbd1b7e9c20eab4321a5c958884989359675f5bbd9ae0e6f71e6d9d9a4507ae0ab24e8aa450346e0522ac5e1516c742f25c066ae83229479731f8133b814258d935f2dfb57c7f95a8b644c1000bf372adc559530437c868aa721d50431ad03923ce10db9a09bb2f92ccbdbd0e47cf18aa7c6fc933defb97ec69e273258c314c56dfb1de01be3a41f16b2710a5a717f10fb4bbcb9fdffda3241b3ec6fee00fc125f6f96204ab52a7073a48748111e6c12447dfe790af89ed0fa5b6c458d9a187d56fb1ef72fa5a2cd425efe7ee771e3763d4d7681b4144ab0bff10b970d900eed35df413a9e182552f778561f1654a55c2562ee11132c471f588c26172fdef763ff6d1e25953f3c132e8dc0551af6fc3cf452dc62fc2eec3a49538c9eb4f4a304c1eccf7917164598ffde51bc1a227a64a4e43d5464be455a32173a0431aeff0064646ed02c5abb6a5fffbe024d71f3840909ad6bc26a4e8c120cf267882315804bf52b322b88925d0b4dbc9c20af6c17e90cddccdb4a99449ba08888ad1b74a8504582566984a7e9172b322c6e5e11a1e0fe9ffcdddd34a8313e7d55d608909355a5059b423747809a837ffb9688e950cc4935922c0c37a95d4eda52e998d7ff1f651a1c40fa66f10061fd730847f2fbcc85e70722a07ca26d25577c28c48c9154f52c78b49c4911b4f650218e08f6f5f67627270e103d4c7d41b1098b4d0b8d2456d05177a54b00c48537392163c313242f659e1612032b8d8d4649785b19bc301eff18632327a6ab83a34f452f3782d2286eeb88e95e4a14e452c6a404716a3c1001e3bfc2d7d6d7e8c86fcbced271f617f813e266ac4c4d2fe2200af4088b2ff2aa712e4fa58ca0092a37ef9363414563be783c60250f59a06876ce22d4e48b5aa4562d55ecd697089bdbbe292fc2ea9a02cc5b20bfceda679172e06fe7f6dc5dba4c48435cf36411ae48c8514d25870bd847d1a105142ac6747f5f4af371d80960cb6017318ecf0428723e717e1c37f3abba461d510a8aa28b6beeccc2be818b039236990eb7032a6e06aa238f1c9085cf19a5732534acc7a0d6f5917a898be430120b1371b7a1980f7eff251b29401d8fdcaed811965d2fe4080235638fcde074405616150762d79504b8628e4bb14e813de9a29d2291749b9c88c5ea71b47aabdfa53f112d4111278a88b25291975c389fe0a1f3e15d53a2171ae12086e25487a3e20f23e35f2f73711720f523141328580f675b00959643f1c007f0e1fbabd415d6ee16a329e5bc66b8878111445dae6b03e18cbf9de750929738ee065c1e57c582f6d58f29819e18648479b5bc63bc1c5697ad31ef7823a30f3c8caf716f7d431a59086bc174aefaf6ae92841f97f4ca01864174ec3a4e9916241a761c04ef06090fdea1d24b193a2bcd3dc1fad5d3d567fb944a66b40f5175930c591c4665c8c2851543cee6eebcdc0f298b67ecf15d965ac709f376e3cd866b203a2b8d3bcffa505a54384ae1d25b4cac916b8083739b3f67bb39269e431064b003c2f00295cfff35171a7e37a5426a9a623ac4cbeda97a0dc83572a6de8cc2a8e702b4fc07d0c6f71266260035be97e8bc52c51bd25e180afdb2be4b6a2845347c8529627338587be76a07d71573ae689c396c70120d290148a7e2133edb133fdeb69ddd94e7aed71dc7d1014081a7fd597b2e24770b62f178e4c17b624d222863335c8677d95e99a7753a17599880e778797c0a918867319705a7a55391871f04f8fcdc6896e19a5d504ed06e21e496daa8273c80cfb64b3b97f3400f6117ff92931d0989f3d245f47d7317f9c1596121ccb66d068d3f3bbd68056ed2684f2369f705806453c58aca2bbeeff0cb01d5672739e0884d03332f14628650b33d9baba59ceea93de55d09c44082a96622e52865bab581f761cd06ef79d9b07f7f1ac88f3d6922fff02b8f7acabdcae6863c39b18bb26fd4bd76f6dd2e2b8d3c6f076fc3cab5d0eeaefad4ca34a10c9eda4d04865b7a24a46567093f93b914087b68acdbdb0d7d4bf0923267dc8d90fff83a0f0de507888a077acb371c964d6070e8d6a72f78026b5531dcf2d61752da83596f683042e898f98d3e8d10c8d7b14c41b3656ff90e5fc88f0c560a9d2a21c290839a0bc5c0c0c76f0fb429b5f945474a1a4cc93cb90e29cdeb68b05b29ec09f695976af2ffdc9a5789fcdbc32d34f41db47557f6028279af185e44c8540e71e8a554e1cdf7e2f1d7046993e4f9940b6d106049e97ae68ad832b186dfcde54e0f183ecf0dff2409851674b3a78c4c583985f911382442f209c58df0e8717d541fcc58341772ad8c9ca46fc7ca58c407d217f2646bb7a340f4c62763387eb6853eea19ca865b4cc23e52ea1d3db602971129247f1c9f6b11b0fd4962caf30c78209142ce1b4baed82d38161b75ddd99b1da093dee5a2a057f145ab4f53198ead5912676dc86a1d049536e85e11bec0d635da4a90d9b376a722cfb08a5d89e6fd094377526838d6761b8a548007b7eff8d80dd2e476965091f970afcfe6b013edd983a7c4559320d8f4c202d721adeeacd9c8d30b8bc5d890c68e059a8cb08900695563f1ad9b2be836c28a2776f31dd1e41f12559e2853fd431a9791216533662db178c83a97761e3e43676bc0ebd0085935fddcd0d2d040f6eae94ff54fb2237466a6cca6831f48eb2ec4e301b4004691b0378a043c5d317356675afdea72fc118fb935c96ad3628890edf39a0abca831a6d5c2bc608626cc33fe93b6b9eb41d074d4c5e58da5fb7884e091f0ebdee4919a28192ff7b791f8e12ede62771f46cb43fb1fdba9be67d6136c539c4576c17703432969334ae42ece264d054a52000e8a856a63029be45750a83b25b56a800cc3414552a34bd4c251835bae6f8bc52825c4066f7c56e7f63a67cb5f908de97bf7615f0d0f202795f1fc474b43be08868c154ca2d283a5d16eec70cdd4f26b796b0514db3c30a6d81013e62ab456da1c14404034213a25bd53f41b8bcef94c958962f18ac1b11f8d3db4f63e45de81b1cfb50fb296753098cd5c1ec97c923d407cdc300e7ce0f8c0ae00582b7c3e84ae979c31ba1bc308c014e23b633ead6e2d09ac7ef294257d247a6d53791a2146311f44244401fe217115d517a72695ff0a970ec62cce029ebc9898190ee04f777f6874e1d623522153e3b8e5778aec72b55ea5dcb22afcf3d08e164e8c6b69eb0101e4e73d2a8d14d238ce65f03d0088ef9bb59e28afbae5f144ae231fe3a81f833fa70e252ef9c79ddd22bb41ce073e4b72b10004cdab0f4af623988c9a616e0827c25233b00bfb113ac468efbdbb0216b1c3c63996f76061fd5d5d47ba2448875f033fbfd255a2ed43cc50ee9c66ce51a42d3e1a1c19ba0d780f5ef581f214d7f4112e98cae546d6478690a625fcdebdf0501945a6b2cb9591dbd46869b9ea93f8d04699fe8eb9c8e98b0aaac832722ff1e50628b813707176e3171cd54306213a469433071bc500e8d2a4d0e1db813186a8a0fe505b91031cbd04fb10e47cf1259f096a341614aa8dcaeaeb6b2ef901c19a9179e48b2329c84d00bf37d8cf9f3cc5c09c9074314b3a5373d846a095e26c8d6d707a826626442997d3ae7e4db10995517c7ccff02019ad9e772763306157cc55b34701bde2b3aa62b9a4503cf26576c8376eb5d1da0a10f9c3fd9f9ef955fbf8abe46a02e6c25d1eb38b2814a57345cb8193a30378ce3f7191156b163edcb9669f887ad270a4518e909a774e51b8dbea046c439ff2b94077deed438335340ff22e94dbece15a216d39167a2cc508f2be081c00167426341c2bd43f8f3abd8276ec6479ce1d60865f048b6cc46e58bf466454d48a6cfe02e1998c683aa069f520a9db44c3bee54baa2c38537e253209e5a31869230cd9905b59fef48674bee95b16506f856ba4fc38dd23898e0b9384f6d25c54af5b05babc9665e7e0efc05e4227496d3367e9134da3ecffeb400bfa469230bf8d49afcdfd5329a7c7824ec19cec22b8a642dbc12a425c92d2c395f5036a3df9e4154f8261a02f5f70de4932a27c8823562195921c97bf0e31fcba2d00694e92545b6ac7c3c166ccd6c80b6e5b1ee47b7fe0241f70c625c9872f79aaf8687adf3a1b46489d3c1c0cd1e8841a54a8133dcdd03a600165d6ef53e9ab66855c2ef3171c1c1bb3e1f127d3f082247a7adff52c9f11ec93ffa7745c6c7137677860a82cf2468fe0a1bcda4a7a5ac4b69b28a85597038f8ac6b70eab1c8b01179e9eab1e0f65e838124dfba2f4ce421f65821e2aaf2105aed22f37c17c4c231bfaa57b857ac9918d48cd7619213052ae5446a0c30ec40418a02672d228d1248c7f9d44f08e6a863e9388f811d6a6c4eb34f7b9a32d65e608e135fd43ea13a51404d838a5c544bae9713ac9d2c0f65de2b924a1ff5d9a0ca548629c8a6c2266f9bcb6a0660d8aff8a75e96f11ea6045ce21f6be7f37865e00b94a422f21f3493aefc485e187c3d463d68e4c18675008a9edaa04120234b857c92d62e872fae61704ae4c3f3bc6a977a638e903173e1bc81cb9ac36f3ff70d5f8d3021470a6f8177960b1a53e4122f274c34647635f22d0a38efb9ea25fed7b81389dfe5b8868a0b90eadcdaf307d049613eb52b0e70bf03a27752b9a2fca3a3cc24c580d389cbf314ccc29558188f15bcd0e3f869da86693741535363a94c029373a8d2600c1740d5017cd0698d3c56ecfb4ae0aaf18e9c57fa0ddc30eafbe51a9bae206f495010b4aeac0082bb582c0f2513e66e3003c13dfb6e306691960d9c3b374395df6f4c52ed7951f70eab39ddf89618e9065480004500ac0d1171087cafc438c57d752298c0510c9ead219f85fbff7b3a874e0967b73346299926008dcfb3ccdd366a263f8daeaaeb252a358767397465f5891a28d6f29315590753375e669da4b7b3ed37dd4aad83e982c17b017e1f02643c01c1e054175512f0a500297fbb87fb135ab93b15500e43e9e85e3b29e3afbf463287ead63cbfe0f3e2d1e00f3750287e7d296b0681a51e6e1fa739b8f1797c141ddfe0505067d193084a4f326b7edf1a0384f90ee8af420cbecad1b3ce01f59ba381970166ff37d14a605bcfa68041ef04259f6ba8bc2129e093f7f165e66e1a1160ecd0b949b8cdea54c41cc100176ef5ea0321a3898010c54806787be889d545f89b8eaa3c040413f04e32ea3478061eecda786a65e55af79d613d2b59eb88f0044abf279ddb91161ce6f289f9948b2ce8772bb89c97bb1effa559eb82895777ca26f5f097d6caff039c317a2357592f469210a999d229d63f7eae16e233b2737ed100725ea58dae03cf8a4a54d6879c2af78a98f757a8eea8e464b46a2f7662aee33438509235fcbef9ecacb44fb9f77a2003d785539d7ddbc6edb2f07062d1115ccf470f9ce5ebf6250ebc9e06a327eb875ecbbf2cba3ff9c4464f655b451acdfd7dd706834dd61e7aad2576294d4be9cb89f6a34942b2cc6a01cc326fb159c44de5db37680b1664a152c3d2187ee17641806a9e6aed01cd1d70094354511cb8608bf25c3db5a3e971081cf95392195f49c7a0d19e7d5737a062c015de57c7eea22b2de46e79ea9a3857b6949449ffc851b50fcfaa9265e26ac89a61f0c16197e7fcd0f48d7e62af70e0f5e98907acce959e8e7030f5955e9abe495b3fdff77dc579cace5d65350df78a8d48d9782ccc959c92c4eecbea38a3776f2b806efb1106372a51bf49dfb88754a51212b99f5aa41cc798f7a1954afedf53176950e0702cfa08c8d786ed7d59db6508731b3e04e8b040a52926736857ffd4d1749565c39388f9ec534a3b677c4176aabff5cb7ab1bc4cb4fc7b94a90b11bccef63125d4734d48d846dbcbe91265bf749dafae9413fbd355f0c7460545fdf4f703e867252cc924633df9387a378dffc635c995d6c2d1307390a627d3427d76fb4ae1d4fe5b650fe3a1bd1b6c104ddb5316048d837e1094ccb507054a278f81b050d6bc39433443dd7644e36f3a47bbc3d9c898db1f2ddc7e4638ee982eadc90f2fe695c0a6c72f3a409d15c0c6155cee4995f6505ec1b196f0f981e721c5c79b75e3ffc6568f6eecff7639d860c3d4a494645a52848688549747cea90e80fc9324fc0bcbd077ab101151043b63163020848a1c562deeab235cde257ac2fa7912ad78e6cad8ac395413c9a6defe22ab802b1b738269b4186dac3eea9af1b0b45efe34f4d4a7ea18295f330df5975146761169af332d19ecec237929ab539a3a9507364021a307d884e266963b47a3e9cba5ce203dc616debdba5c032b9903cd61bd40a3f3f0bc477ee30a8ce09644381c4f0ce393c3407034144e5898b4563bbe9a2c0f3da73165776f1a1c9965bcc9c937ef3b5edc9a41c9240dded42e9904ea551a367d995de82caeff834b4e37be69dd2609ef05f6a17aa114a8c61702285f711c61cb3ce209307fdaae621ae429de4f5b53801048fb783a1a6a66d7b69de9bb5b3a6379bd5b19349571a5407f2dcc50dbb0734446f401c19af29e04b1c6eebc4cdf436a0b48ca4fc15c19a1e69fb2dfb783955e39ebcd06dfc178d97a8cd06613baa89330062bcfcfeb4e9786d9297fe14b23bdce39e3d60614ac2462e9ff4c4b90777a9f7286df16ad7b3677a5b01b26b1f07897a4e69f98899407bf7edc5685f353749797a0f88ce71c6f3aa0549db74950d77c6c4468cde5b0e9752e06ebd8ce7fd14541b4dfe5da0a9464554aa902e01dbb59cfb7780685a79ada3f59c6af7b267f77c393119361254ff49f37005f9d698887f52dda5a5e09b812848e57e4519d4a92393a73116b8e9bd2e3add004a30c17cd2d20baf24ebb5587f056f37a32d8825a9d5c40f44e3cf83adece53b04e134b00b51ce4665f41ad832de85cf37c5b560d2748d0d7d60c7e54f0fc2e918da1cafef4cd93a0601ecdd30390f9a598870144a524fd3c8e4c72b0d1734e2ff603635879a9c24aff68575f401f2993d89a75b94f77a948d835ab73c89b3ff8a7dc022c888a8da34dd1b0db6958c43ea6cd810c2d71d610f6250a13fc125f09b3b7f410ef80670235611555c8a1a61b62bce732573a20f8a54d7e63714451cdcb973fd4fe2fd994b0f10506588c98ed9dd3d0e5bafe1b5ff04114f9cef3e79bb4516513076e25ab780245344c1236030714bfed5e619c9e9890bf1c49e45e6972aecc285db6505d75eb7188d0fd50727acbf42e4d64c6c5969c1e2637f782c37d365780d8590ef73baed92192b887aff27e13c91cc30106fbd5fe46a1d285e1429645ed77e369f0027ead80f8ebe28e0369dd89360e49b4788d3f9488d973ea33a37ece84226ca61b72b73440f8f0e3a3072e32ec4bfacd76a9604b4e827a4020c2d5170303e8fec3f4e467ebb9f5a0862ebc240044cda85bfc20975a5dbbe2c7809a966186912d05ef1a6036c8c8ab3c373e39aaf6c76c76eb3e0dcb1897c625e8a305e5718c18d40461cc51f98ed9f1f929c3e358842b4b951b50396baf710c128959afe77b2f4215a231504bad5c17577ac59213847acb075ab7ec046824f9f4f080f0545621df8bc252d9e11c870ce15847bf1ae4a69aed9da89d7eedf472397365a778f5fdc2b03a87ab5faaf5c117bde0bd7501502631ed1d268aa81822aa9f1ea6bfdba6788329279d6be06b03b704a1c4ab73077149db4643c85391f3bf153b40a49003942aa98e37483b960bcbdbde3c49a0cb1cf9678c68eadcd71176331f83a03d48eea90752ffc7139ab2d9b0579fc67d158d2a680c68a5c4877ce7cf759e949f1e248c2fb755222117c682a33ca6304db30b91c1cd8abb91d9159df83705e22db6ab1186f7bc2f70832daecaf6910ca5a5958f4dcae4da5c672e0d35c8e7cc95d3d7446cb86c8a941b266710671aed0aa5cd00e5412ffaee559ba32b5cde89e8a7a95f32867b9e533dd04cfcbff4d56c21c277669ff9de73fd0b41c144f3f8bbe4a097d838634c4e6bc321f74cb2079ed48df74a2c0f598ead37b2389f4673404dc9e8fcb5965053bec58ed4d23e0171e577699ba5ed7254eba8d129c6734923e7ef46db96509164b348243058b6fcf490d86836092bad6da5647066185c16f77c28d5234205b76ff9e4c44829202991c6381eba973db24d03d45a26748395fe0852c63071d283912ea79647674b1e9add586900a865838495ec735e4210b29d4609b63c13d65632eb1f6417f728fd6f712f9a82c977731d25f992680a861db4a0a0b8bd9542e1adb906126612598d0ae736fe79e6889a7d8754a87088d2af2df5dcd356561ae114e0a974e657fcc69449ced3d4577964c50b50f9510a25e1b26142875d937c48768647f4ca5d0e899876f47981377ae451f8fff17fba3e817524a9c58233c70f7bd8f19a60afca05633cc9c176819d6a91324eebaeef93be8b0fb4ec7456bb2f0f2fd3bd96de054876f7182d8b98c40b97d3c13605c2fb68db7d468d42dfb5876c8183e61dc59fb44efe9e01c147abbd67843da6568f5030128b28c39c68e45174751c3d438f62e078667656d749699adaf1760e1fd670e1207d51a298508398e2161ee1023fb8b4dd12001fde3a217da2758416f1674012f1aab8affd7c7742a128771190df8c045fde00e9ae270adcd91408b299447dd01f9a92fe5d47da24daddd859c0ce2faf24fa10af842edf854bbc91b2b2d733f663bfb037492b9ec2c6e229cc8d734513bad64d5bc45c91dc17966de21d73245d9389b18ce9f1f0c06f3bf02ca4d2317d259ba16fcb474091f092e297f074f6ea0bcf9370e70713f0c5709522e83d6feea4f02c98315eeefbf8c91017ac5e790e6cf6c9ba89e518630c2fd8ac3a2b5a67106f267b21c7f7b0b5efd6dda7432c10fba9c71484308e8054ce1894e125897b1bb3f82166104405fca7d313172f92332f242887e023fcf9209adbee5bf7d47425825e4fb4792de6ca5bf227887ce331cdd8432d83d5f74e9b7ee1fd9eff8aa2f1a6c8ed657d827688675cf1eaa58618784ac438fa8d819b271865539d5cca37a4bc42b66d8b1e2810d270c0b9b4c6d02bbdf6f1ff0804216da50cdf5b7747fcb61308db3bef45b8794db62063124cf1468075697d79df7b3fe7d4cc63d4943280c17b7e092648f67565bfe264267aeb04841501ff612b32fb2d17bfa97ca05f6a70a4207c9a3237a6ccd223b5a27ea3688484a80bcd15491127f40f64fb899a8e8ae2caa31ccfe70f110dae72f30ac851ada9b53169be19432dad8f2c4d7ac43b9b2455fa1b6f51604b0fb03317e95321a8bc0248837756ff4a6741af7eab7c18332ddc33cebdda78629f818f0a9a57916f01a4fead34352ba9849c7c2c8cfc4b5902a17b7d69c8bd060951f8791a4fac223b9dc8f892c9895afd65ae0e14857deeb2e97161acb30aa5e5a5f4dd6564c95525477c426c99350b7bbd0c7122744063cfd042858e645065b0f65bc3e66e82e9121ab8f1012a13184400e1513bd028a08a96a4ad5790232452dc2fc2dddef73139f35e7ebdcbebee799274da9e98826c2d7c18cc8a94f0455fd090a014e3750f29f34a99cc3c96a9d38b4901ce5a9b0befa216a89e1736fb101fa1fbd28a18a68e07e4ad362c8161a405e7c764a2056fb6577664422caa9266441ac66d35083a0c358113e8568b417eb27fcdcffb174705a2fa7531cb3586f9aa218e31ccde59c9fa547034de7d8a195a0fcfd7b26c5c78049444d13ef1bea4f9d9d02c28d133857081864ef7e7385b9d4e527be93217f82f2b4702b9f7101d1d4e9d6311ad8eb0c3275217e126d138e33d145beb5dff8d7e36afc0b27e967e1ab36162e25e885533e3ea024fc648b89e21a230b62991399f7fdd1b388c86145b406be8e0d5c654a2db42ff3c5b7ad38e9610720667890297f3ccc8a9af8516734629c90a5642bfe94194be048e9408f487ea1b12865bec082a02e3cebd5627e4c6e2a1da1571f653e04805f2ff7959b6231b4177c35797ab4dcd14e9d27c8f8540bbfd31193725e56ad0cf36d71b7d52f63af17e95f331d6aee734723a9ca4d846df093537de4bb08e6fbf67ee8bc6e4090f595c8ac11c795a7190dc04d6aa88b281fa7da78fe254f682232d33d5f6bb002a5badfa76b8ccacb26cfd25ebf325c4134b1a213a94147c70f1f770cb697d75578a5f61eedcfca91285ce79775463964497a02a623a499ac0a58bdb9e1f69d93b1d03a230a1f9080f6cd5a1d19a768b43088b9681efdfe5d117078a233157ba54146c046d73226f89260c635f2e9290ae431154c914fe74f833ea4145f3f1fbbf9b512ee387bd41d086eaabfef892250a9a9876a4542c144e27d87d4d7e2fb859c08d3e9790765f9c11df0a5df63f2a0463d8a8e435a6600a329baeaab9dad680c6cedabcde889b1a21ee8f8e1848bf74e52e01bd0872574d9967bf1274ee175febd389184557fb1b537a9818e2a3005f630fd4b84cd9d0bdfa1c04a945d5bffaa0d6109cac9bb3823ae369d863291694e92e4f49c871d833e7194734a71f3d9ad3f27baa85aca9e4823b5a9e6dd6608a7be77effbf05c148e7b5b010c290e96d83a508b428240c25c95e598c31f78606d091e17584b28b80a290382cf5846cf131f3229ffee2d7c56ec8ecb9c360566dbac1d6d51b113634c3035aaac64e6e3c4908e7a8166739a8c72c36562dd4a69a1754208c74c9f4d2f2e58c868433104d80973dff93124944502b5d88b89a8a2383536744f506dc39734325f062d623849f0509c08995ca24be3dfb8da5a9b20bedb97187fd3687fe2c7e047805ba4a07574e3f16b1023417d048f1748b8af5f227b21ae50dc83a178b5bd14d4b89c937f38a601880ab6bfa8985efe2dffa1c6db3129642876050a65deea0ea565b931ea02a226db02b535ba087a381557298dcabae61eec6184235e765a06c6d09e4afdc0dac69be58e0beacb637b0b5f505b061b0d50cba8b1fe2b0bc38649effe16f575efc55534a4470d405f41fe84e93bc808d8bc5e787a5723d6b0e6a587a6a204cbb46fcad7291485a1786dbdbf9c10612a0aa7fca1cd221f210faf4d921129e5b56b2474675b9e6e083f4ec6ac6e6c15cbd70689a047ac58c289933381f74dba862453b7e87126465a8d8e15563505e26166eeabf9c8621d4900efb96943753521c8947e97e389c65d6f2f5a398e710bbd030403f0a4887c805ac2b599476d332a33cf1ba1c15aca6b45b269087a85a9e479faad8fb04ab48c703cf7810db853005af30502ab3e1817bf140acda5067cadfc3f8eb66041f774eab31959d06c3e9507a05caa0e9fed4f0c08823e5afcc1175ede85aab90f3c3d7c8ec78d885d717c59677cace1bca655714287cbc7edd6ca8cf564d14bcc47fd1cb50e1924ad4e197db515c3de42226bd0931c4def10d1003fcb226c41e8338dd124be28736e500fc510d2d70184ead50f122f4d3abece29ea3726de9ae50d5889d4f4f06cbc10dd4e30b38693528677ad16b185159c2c7b682490211136c1fd0b36671268e18caf2803e0f6f91a8155e96100b57feaa816b78d427b4815765441d0af7152227bf2348ded07f744a8921e1268343c790c49f31707f098a8416d5ec5bc8ac1fb0b742f1a3db0263757456879e23aedbf88d7bf50d41a3839a829af1b7c01c989bd898ba4b1bba05309f3e9e2c40df701712bd6ccbd4df9672f1d088b88f306b1777fd3344b22366e2c4023ae20fc5a351f925d4e988c9d0a35fc9f2000dacb064a6e917aabb8bc15a285eaba2279295059dbf7f518f1f6d59008a2c09eed1751eafcc8e67f11190b01b8b26e852e2287feef8fc5f826bae828b8a0696207e56410c78f7a7d981712296113edeb03d44226467d98f18277f4650963df60681b72b064e200bf99bc526da604b94bf86dedbce8a1a556e8622469a2d00950f17f2b2c652d872ed5aed2981eefcf2941147bdfd078feab8f70f8922a7d376a424ee3b5e7aa9efa94d74791cdf6d98f3a8d45aa3c6c2e3a88429358aa3ece1cdb3c5a113c7a5486308cdcd07258dafb00ae835a7ace6f902f7ba71637d2ca5d0be8c1d6b5f3bf928eccf9ea7ce0df4b27004033a1578a3a98146a55773a438ce7e35ff638ebe6fd55c986012b84d295043fe0f3cfc3a6f80db9a2dd9440109fe09e0e29e7a63461c2ffeec7ff4de6c8eae5a9b1336ddc1fd4495015966aa47e904a03e032778fbe13cd478a901d5b2267e480741c7453e5b37b2e9ac234ccc93c0d5f5c85c266747328e61e06d14250a0fdf9e1014031e8a22782d0581ed4a5d52c487366e6bddbd6d8004d040c9d66f52787b4894c3e804ef658949bfe9838203cbd137319703fc8f16ef74958a525a586c78f438fa36e5ecdb802d64ba186503b59dbdeffd5ca2b2430f4f87c1100488e5811fa0f86c31d7b40a5ae476235ca74a6c518532c0903a1f4a8840347dfef721c4bdb3f7307aee0df66b1c895796a0a533fca1abfe289dd500b7176af94b6ff826e46770de9ae967fed5b6a059936f2f52211c11e50bba834370e7f7105715357a86254b75d5a253a92ee55fede016c9f817d8d001e78d6594cac5f6cee303aa8c8cbbf2f4320f59318b6ee78b71603465a03d9dc9e95897940482496f63777c8e4c19a9c34bc416e41f8df00ffe374504545c15c2aa0df20c78d918d0e6feeb4cdcddc1e5d851dea0fd28ca9cc8b35fa16ef0ab36e2c100d5075b505602488bec048c9baaef2d0c79862a1fe8beff0586eb2ba9796825839a877667a12cc065a6512fe8764599b7816cf024228dfa82beaf07b21520eab1fe3aa3b7aed69bc728f972572a6af4aa42bfddcab243a24045f99a6468d5395d4415b85fb08731c1bc24111fd3a82c66ec0d36541a154e22bb69e87f72a5463dfe2d9975af030162520b0528acb0bd68047a20cd30f5f0a0ad6ba2b760755234c16b44fc9e1124fe029a69008a1c76243e20ec04fa70278dc50fcc6f19323462af2f9301f49cc57fe21ee48747983c73bc8608b2906ff9bd1ade4d7c340b572be512744939f0ac6ed71af2ba26e7e41a1cca2bb253816943dbca1eef436d6035454108d62fa41e2649f24bda9fa77cf939ea63de88ac44ed14b1935d8c4122cb12713ac53e1c22a48b5c86e60c526dad177067be6ba6a6251e7c36f39dc0b4be8fce1e6f6ce884eaeb1fd75b6a2a472164d0714e1d685aac03ad264db767856511728fd519543fd3bfce2e7345f489488a155b0609df03f2d6b6d279eb590423b4d6129897bcc3e7a69b925df95816cbcf2e309ffc73736d4a0500ef1355fdfe1f17cb20ffca8dc5614dd46a079ada661e087b9e7e057b6b7843daae14dc94cd029bd0e8f79f3819338bf78bb848324071e7f0c14aedb33a47d17ec905572474456a83de1c4ba8b08d4ee62a15a19e2704bc5fd1270235286f10881f1ac596e6340376e47998c481187860a9f1c2136cb62a4ee819dd538736ff63b7707d689d847080289f13cc94db86d9146247e40d8c2718c769097d0d1ea5c2597222c49d5b5d635ae872f5ecce559cb3a95fe350080e8b15ac73224114b327cfea6206d203d3cf1fce8b38afb81a966636de92e5dac4644f8f80152784b0196457be93c3695e371789d55fbef341918ce95b17c2c32cace05da6b5fae1d2b21278411e392253870c1612617b88f79086c7f29da4d55ad678fe8aacbf9cf3cc9ef68643d901be0339085a44ce808198415a8666f2ae9de242761ffc1bb08684cf0a7346ed74bb575fc309f2ef548bb822c2f92c0672515b80faeba8472c8b0ef2b213b6da1a13180caf34fa52b6552562e53cd2da016467f059bcc9012fb640a32f72c6affbef380fe78e51cc3a630ce5c6dd188886951b198862822653346795bbc22baa9e1f961765cf21879eed082ea85834bd91cdc0f114ff061a5f292e8e95ffe33b46f9f84bd92c2442e36807bad35d17cf40b18678faf867ff63319b7259efa8f35e16a313fcef963aff8f91aae8587394c63547cc433c51fa7334a0b359e170ce13071b2bce6e9aee4d7d657f73b458b0d14f349e4d2104cf20346883b614acdd80e7f203303c61b06f910405fe7b8d51401bb325c2f5dedabb31901e3c9f7f1cf3a866d11f55a10f76459177ae751b6feebe3e2dbba6158ce43d885e62eb85ab9cb2230c6b62d78b7ebeda5612c5b35099a307db7444f1629446210ed8c9bfee46bde04842f845b707799962fa4d4ccd024e56d3024ae2ec5cc43c256b4d695de3a5186eea953d8e9b2488f9f292cf21794831d7bb2e9c4542a7b70f1eb11dc16f3e1b27b5de74b0eb5a1d249df21f6c560a60e900b92884c47863cb0af07ee640d5b6fd85e69e23d0b64f2230686c3d03dabaaab2721eb39c300c2636bbeb0c7eee01ed1aa06394e358c410c6dd5a176165182c804e87f20c7393a8d653bddf7de529b66c85c16de74cab905a013d2282c2ff801edfe01d4dc64600af587ac32c92b38b8c07f6f6f65f3e0de1a1bf1abdf42841a0a07288ecf1a13a74b2da6e71585cb7388a337effb1d87f6b81cf310b7cba9aa85434096247db94a63128f6dcb35758079136c6fda1c44a8401a6cd35b4c821104126b504ea351d10e215ee7dc8df8a300cef9e0e401fef306a815148d8b61286407f48db7e89b53b3340b5f89974f392a446a5323df58c8305887e4b9ebfd19e026cd51a69a2eac6ab15913d19e71032c7d6dc2ead3e648b302f388a104bdde9ba22384c2794bacc534469a3191fc244c1306c87368d8dee453cbf798916b84d490207cd761073f447da5dacf9e22e24c98215b49e7a5a8e9932460be451ced725b8205ea662f1b690903c67f21d6c8faff97ea2e0180e113968e3b1216042512a271437dc4f2882de49643cf149be2bc759305899968862979d4b3336461c185f9bddffb765d3a9a82eb4aae07d4549d2383a3418d288757a587afdbb7c268aa914b91337553896c944ea0a2af3e6ed483ec66bd6d74a37868bbee605cd4a678412a40fb2487d04c452f95002c12c2a0d0563334655e4acba32e61d619538652cc92b7f91c46eddfc2911a3242b77d408af90407a94896b7de3d594b57b465c194f58ff49429a9309d5229cba6184ae95cdb28cc268d173222a64f2dcb3be88d42e241ebded9f885a89d066e6eb84b6f30007d0e312949a5ce24afb08810a1a687722c58e247c6d0789bc896941ae648be9f1f8f05d116f18d4a909036e0d90a448621e99ef2a527caf4b129cdccc883fae651a6f0a9a75c2c513426425215b191297a5e27f6b95367b5fb027c27be96fee784490c640b810e41219c80551ff93978e902dfd4d1be43236e4627c57fca38420bd8a4cb4138cb509b114641a8a81d085c1da6199a5ae4b88eb14649c9d402c2d12a3242b58404b400be1f5f5f59603fce1590dc53ff6535a10eca8509eddfcd04bd3cbb556d07cb143ad3afed916852db13b51c7c38d53929da7156331100f6f18a283c61b66d70945c995077d792d858eaf74d1f9c549676a64ba956799c83777dd5ea04d1be42edb4fc1891e33384fd1a7148cd159b0b9e369dce4c3aacf020bfd5e5fb5d4ea34541220bc5eda3d2a2112f69756e6f84cbbcb7678bfa55b5bc9e77d1b5a739375b3cf01a486f3d76e31fc143e605462dcf61345635406e7f21449cf4d38e0c2018803432181286dc34fe0f3e28380529a9f6b08a9532bbcdf61aee5b9a78e9908100a6981d2132d4927e90063d1e718537bd638ab864562c8c800b426df9f68104846df033e8dcc0c2380d70450065f7a3f2bcb8c9d2e489061ba34999dcbb44bcd993082519fef9d83ee3988fe53a8a2e489069195de37095d19abc7498ac379f561273c865cc773d81e9181d49318d07003fb4a4234ab807c1a11d6174b3588c0651216aa0d4e5ae69b405160b2260630b4958c55dbdd48bea813e79c24c4b1002a0820c58b674844e22f911ce7005bf586466dd70c3544b76620d528927552fd99d94b23ba3bc86c5c03d69c2ba902df9edd76f495304891a1d161cd2f001eecc4de919ce68683894552423cfab90f112873ea3d4590b708732c62bacb10468a54bb20fb43493a6dd229bdb2829cd1a17a1e146493104599c1367bdc301e58b0267922d474fd2c471f566b28c7c37e3191b17f6c6d46ba376cb48c4daab96aa2cffd552eb7435b78dc6a710e70afed632959f5c38f5f970b1612421bdc73f57e1457db186cbfaf36d060ca7b066ebcda5db06ea550b6affdef73edadf1eeca7e1706e8010815e3163c81880cc9d4d822962d67a295f539608c50e8ee900a2781596ac2a241d9bfced15c8803c0c01839360ca82854a78eef62f6b02c2d4d668ec25ced2558ac9e098a669d4f74b389eed8c51205ea13a83a947d77314d13e2d967acd710c489ad6518ad65ef286c797b6fb056b7e804116f1c1fb604f86f01132ac24846d304ba8a192a127c2f1685e288568ee3d89af90c51b176ca7a59be4605f245029b2173876c1fe03cfa260650d2d7f55bb8320d0df0697c778ecb66572e3e6a823b236f5050239f41e04369acc03f6f97eb1fb9b32f0e72814167c109bd95cc6fe5f6d3b3cd30a83fbc2bb16976ec526e5c56a9f7c2d148feac11d4d5d144abb1fe45c6db5249329809961618f4c030fd453593e0f9aaae8c9cf7e9824f39698891c2a78179aa8777c102ce7cad13d35ee2a2ae14bc066ddf5ca6c0db7ab02d69e4bda61ab9ca750a8232e3e8b6deb936d153587101251df99f3daf26a88c1a0b373b7355400c59761375b5224cd2fb983f38cf5805e6c732f85875c33be88c1e1a335762b4a1a066cc7c98b857a6b9a810b7849bb41834e1cd0644f1ea47558b066f8cf141e5bb7abd518941420d9d47ea821f7d960552586ab13ec64c0f2b4c760fdd6eaca17959049e8868b5af29d7b30001b039f2aa3309f60af28b2649cf78e04d6802756106783049b31b962f6129a9b81f4e66985401c93ac92a0e5a3a2035e532cebfa5beb057a563b821fc4e84041551bc9520ffa326af11e2385eeb8015020d3dd76384f426defed15084455795b822cee4733c7a88a217087cf42829dba38bb6d1b1dcf7947dd4d9dd2860362041d4a35ed7f53786094886dc7814b3c7a10d4770e2531c79986006490eb5299ba99aa90530a92d6fe7eeba4f7a129d3c7ef546a08260e1e7aba282d4fe0a7285efb7f54b965ce168cc62f398cef8f638e147eb1fe329fec986102d0eb32ce414c6f78b1c13f9435d7ec72eea79ca9854d0f47f5e5c199c69a9daeb1d1ba052556233732d486a050aa047a6e9d0454f424df48957f3719fea6a77c4277a5ec8fd9aa6b6dde678a34d7dd86d42e3e82994c37b298783abf8da15eca2350c80b63ec3614801389d1e17f8480f63906ff8a4ec091f92f715e24e54d1b2df793e29dd7d5609f794ef4f897d7e1eaec50b469d02bf50246c09c077a91f4b4c16fb9cc417a9cd8e4eeddffe40095c11b0b8b3a92f87d657bad5c9e8ddfbaf11490cf0eea2ef251629551abc752217dcd20fbd3c8b88d7682f9a2b0feef04fc9798ce23596542e39872819fe0f8277073c47db9b682625b5c3ecb2cd350f82b317ee756481e0191e107a7b155fd0fd767811547ee2482f3e27767a5f3237670e61c884111052a1ae74a460ea8e9f7406fa9b9194bbb3c8e261d3cb0d87ae1ec1e6bb025efaf4df6ec027a5b6da24bd35ba3e1541a0f7cd592601a4d109cb6d32423537e632008a73b08f2e9c25d6ad282976c15e896318ac59a0923d28daf1217588854ed86882c7835e2178d8423b8499b85be95f38bf5cfbbfdac3e345880d4c14b47e808680188d72d9933c4cf5a236f0b285d6f694c51ac6a0540158828280637b60259691f3028005e9dba410701fb9af08e222240b44e80a39813410316094f437802ae9ff9e41d418c1b8f86d8c0386b17668f8bbbac866565cae278eb10bbd07e61ff88a51f0464ca113af95123b3ce90fff8951cfb429578d3eb727d2c30a919d1b7acf27a98109d81264c9e00aedff9e275d009fba6ea4a756b7aba5d90ab4b2202c801e57f48c6403e007ed5bb269ca23741f16803d23980edd92c343773e47b6de2348e2b0fa79d23c2179862ff338ff57ebf109496134d12fce1d0260b2d129d52da40f55f21b96510a5fdfee264bae0190be6fd34ccfcccb357caf04ba9897ba5a20d2aa9a0eb1f0b0566d2d5601cf9f3ff79f1720583e2c8f8662124bf063e69916b5ce71d016b5202793ccd4a68b47e7cc85308540000749d758d36d00b6d1080e2d7a982046e5cf7d1e366d5d60da505bb2bb6db9b794322519bc0b5b0ba90b40dd923fda2b250840c4a42c09b164a349b102889a14287e76a6c8a43401ba4949e267678b996ce78a26294a86d8c942465b03881d2c966ecca0bb9d3485d1c48de9c2dbe1da2d6493153dd41d2937eb99e07e4527155c0a851b41930a3e2a9a84ac0b9a96749dc735cecb296a1481a684bd9289c6048d8c972af2469342054b7bf064baa562898a15dc1c40a060c9ac99be7b2a4f34a857f144eda5ed2bdff22eaaa2a2089b82cb3e4a5394e05bca143df876150c60e0b529648fc35eda840fb3252c1cad3184c403176f5f22f1900510252b50620225414a643f82df4a707876d087332ad759cf07a6298e363c0ab4e75c82cd9aa89dd9df897e6205ba5724e2561f5b8c9ef3ce8d5a6afdba4374529f74526a9d8e364fa97f4e9d06e9ef649fe3a290f2dc588184d4b80d1c9e039a2f954fb738e76e057ace7ae2119fe7dc863662f286f30e5b6c41dccec7165ba384e47820ee18b6d848582a21247aaec5136ef2861b0095dbf94843f49c8f25143de734445207e639a729923afd9cfb92d491e1688eefc251f51485ee0c21b459383893bd39cad5c059520bc8c9a1b3721874472b64c8a94f6f694a0817f1d9618721a1bc610fe58df5504384801635845d288f3ddfa186dcbb004fc58013f5a87f60832008822c6d0b450db1a2957c3ab554e744296ee07b2a733a38c9f97d3e33847b1dc7d99bd7716847699a456d58cda2a816f796d0678b3a2a54cdd6add1e1563f39f7853370a770c513b533071074a9ff927b61548ed3ae1c20d2f6940ba95b7943290585561c77fbc53c30a96c70a80389f2d4a5d1d3b1c75318d7cd5a7b0a0ad1aa51bbba163cf52a025a133f562adf11fd589586d420c4861076296ea5f665903755488ee7f8642341f5cf4e708254526e3a69d7926afa0a3a3be956f54a3f75e54df5b14e13dcd183f2d551ee41f18ada057a752f4abb3ecebde9abd3eaf40a17d121cfab53a27659af4ea1b4ab739c5bd152114e11abe6b4d453910e89455cea4c6514e82b0dfa8a866c55af59beeaf4f0d56f38872059d553e10c8264556fa9aee21ff3c629cc3150e14caa0e56ffc259a559d5695dd4518aa6cafaadcce4432cafba0db989b1348bc9a659b59b6335abba337d759755f740f688f07116b51c78ca51087c907c88bd4492317dbf449201415685529513744e14286f98a538723f03d883295d4adc769e05013d77cb9e3695cbce602c711ce7c5650e75801eefa9b82242fd472aae888c948a3380dff354521619cd1c002c3064dc3b3b0552a727ed44d099b2b3145741bac10099f96748e50d3768821294a20ed033d61f574474ac881c992292f933806f6708260a5edc9132d8f4a9b3d4a9fdab9590ae279250d291a758be1e3ef4f0c1d2396ba6b83c5d822e3bab6688cbd58334a57409b0668a39e7945d4c950bb5a1387b38404fe5953d421f09f7ab22d655f85929a59f9cd5f3449e24302bce2e6a15a96d166bb6a8733ed28f4efa53047db6a4f770025229ab78e4feb8a21ebe94f2e107e905c81be9349436737613e193f255e9a5dee24db1a0c5651c1d2c9b66499fde2ce949baa77b62a1e374e972ba54c01465900218018569170555dc3072a499dd50661075808109225d061a707e2c3203ce0a2f6538aaf0b2c74bc93544c2fd9c775c59162a6a67f653a7744e59a4f315be9ffaac4f9bfaf81c579d210b4fc3713aa5655cebdd89697c2979d3a9027c15e5b659d27b98e915ebd1130deb7b34b4f993f57e40c398b79e5865ab7ad5400cfd8f84f95f09fd9f09a0174a58cb84d92c59ac162a527953bd76cc226d82e5d3b9f4be095a13fe9b25fc4749789bf7420e05322e03e0bf4efccf86ff79a711fefb6afe0373fc87a2f9af2535f3dfc5f19f8beabf171b32ffc174a10e34d80ec4b08c8dff6ebcfca772f90fc7fd6f26f5df8a06f55f0ef0bf9aefbf1140fb7968ff13bbff00c0fd6753ff23a104d086126602d8ffb558ac962972b5c57ea2bc74d44ba49f273f27b84838c490624d2f916237e94a2f9162472f9d7b8914bbe24f2f91622fa8434688b845c4b5d391ac143cc106c5129f98d8e03abf9932ee78818ed01f6f4cfe49a84f4137d628215f1033ee780a623f059d8498d854b6a4f95ab9c0237e49432fa7e880c9f35f990de8ded4ad5d724a0e62df9eb2d2ae3953b724ee5d4269ca365fa7d96cb507a592886a41f8f6d451bb02f0ed21d3eddcfa780aa2af7b7f96b8ea0924aba9734d48579d35ab9d3a47945a82521f321f41f8007a095d95ba35ab845b54fbf114e5443bd59a053796baf1b3fbc82967cbf301f4239206bd513b608bd7706c098328ddea9f7be3079a9ea25ca268cfd370862a7bd489e84fee85230d7ffa79f6ef939d824e3329c794946f61fa14edbb4508b63f41d6134871bcf9f625be478ef9b878cabf5478639ce7793540443f29db89c9cce714f431579aa2d2ae8e09176fbfd75f78f19b7a118b9efd857b43caef4774830dff662b175efcfa8b5f9733e562435cb9e0e22977f1948fa7a0d3900d678084d9b0e14d6c881768b69a7ff0f37cc9beb1efe51b0a53b714530e22268aee29ca89369e8268a5b19bac5d63aa768388ee0502ef12267ebc42361cbfd9b3a76e29a6540de7afa73c15aab853d029a85f269c664eda254f4646a7a3ef53d0f7e9e809a51f4f51c613ed543bd9be9dab74fcd8a79d6572e425e367bbe2ca45bc21e9d9af084b89ab1752377cb6d9624f891fed12ad78d083d17c39e5f6d30393670b20f1f0040f27e8ee25120f4293879f9797483b1081da00a3b6247131e876a8c222ed1085b7031327ee25d20e4b7c3b240122ed008442f2c182e423860e2e172e545cb1364027605080e46304924f0f374035542721e0f06e33322f9174e862a5c314cf21920e2bc8a18350cdd11ab69897483af430022a0d4fbd44ca810c31a6060000b7b0c1f112298726542f91720841094839fc98605f22e5e0f3ec9d10394c8ec59534f8c1f29f5cd956549a15a671a78faa5ab3648e384f6a1846a100c5ad8eb3e3e64a3b6ecd6a195bcc4b47418a3b6b3a5b13b2703a108528ee748b7229ee17b33365dc2044a09e27f368dcd1937ce9dbe9e71f6aa7b24f54156d747c206a07c65708a881b3bc0df75d1c85c3c5651cf495834e6ff88c735ebf180fd2b3863031de282197551f96af8989d0062704c2d271c369eddae1aa44dc91feac72b6a452d75e171eb716794c1b343034df42f00096dc71c70d86479033cdd7d7245d3bc8903790ae1db766b5d7f9ca01c67690d1b4e3c689636de2a938d65a259237341750a8e5850a62fcf421849fed63bd818489711819991b39dcb881daa98e03b5e339825c99b4284abb5649cd725bb3a8ec70c7afc957b6fae50043236e4dcdc73b4430945d11b523532b6a5647a1d5788d8fe0352e6134a1d3388dc8b37a81c673780ef18655159bb8d3485828f6c0ea374208c6400fbfa60673842e44b3458463ab1638f6557429eaaf51e256e7719bade67173168bc7cd431e4ccd42fb083c9a7ac478dc5a67dc1d37149adc91845b0ea711c1188dd7885fd38e5b4d6dfa11e69bfee542d4ad76a1b9147912e85323ded86ef51a722cc56212d5028ea73ef6ecd45042a35aa8fd3d44c01f799e8a2b1752b01a3ffdc8dfa446e4f1006c07d36c354a015e0772a89d1a988c223c12eafc1caa85160b762805d41f6f78ce3f0fb42805f48f1d78ea5ecf5311f45043bcd3773a9d4e1fd73226798e08f76392df61a559206a88cb0a3b82b04a5ad976a0b1b2edc8b2b23511499dd395a9f1e8b10690cb0fe52cd08fde836381e31a9fa0974c6db6642e4b9e631b1678dc503b3cac34abdd85887dc68c9be367cab82e505ca2b818cd947147f0c7952d478d1f990b5050514e4e8e0f283e5043e8bb10c99bf61d396e163b7618c1e3b6b2edb89d7830b5eb84df71e37165655bb251af3247cdea55154ae323a3d4ac4a65a834ab65929a15448dda8ca74cedd3a132351e4d3c9878dca608c69ad51ec48ceb52e4f3faf99a98ee88f3399cc6c76fb6b2ad92bea69a99322ef51933ee077e90a62b7f0049dcd19364a8c8d496ea4da726e92cdda64f2c265bbafdf8f12387cff9354da09f0efefca414fc59f2354dda57237eb4d99a353e828f20f2c8d91abfa69f5e23f6c0a8387eb59f9e23046353e640503bb53ef1a466f992a32029004384e4b843f2260001f65e95ca9dc5c2c1e99c6f2579237de502093c49180b2f5e007be26e8293e03d309b70e5828db39c25f29420d2e0f28f766667583ebde5322e4ff0187fa1e0302edddae64b874bb74956a95f372edd5669d78b4bb7b7f9dae1d2c5a5db2bfd4ac1a55b2cedba2edd8bcd178e4bf764de4fbf5470e9de9276b5b8742f68be5670e9decc63d22f1e2edd73e211cd570f97ee157951fac5824bf78cbc9a67f3a8f4ebe5d23da576590f0120860000404813e38e012086d2bb8a0c4371d5027fe843f843e91e7a288e2eae88cc5126c67b1ec67bde86f7fc4bec47687542eb23cc09656c0471b435e278a55d89e39d1147150e717416cecb84154bb362424e16724b426ed62ce92f21e7a459d25d42ae28e48c42ce16724a21770bb92b61173b859d17764161c7a459d25f6127d42de9aeb0039a2de92c849d4fb7a4f708b9a6d992ce23e4ac744bfa0a21b7a442c851e996749c90abcd96f414422e4ab7a4ef0839a2d9927e13724cba255d47c805cd96741442eea75bd24f08b9b05ee9967456586fb325a78f76f6d25269d7d84b6f67fde241148bc57070d22f9f2a7be9164abb8afae593a20101ca4bb7346b24ddd6da75d42e79f403a6976e6d36a95f1326ddb373a967ed5ab1ac59524a6f57b7c44b6fa6765d6957f704cbe424226a96749aa03bda9e9f52ba9dd958d968835e3adb9909218f8d2031966cb02437d2a80246829710f28035180f0f15f664c52e9f04f1c98ac57aab569ad52dbdf4e6a10367b162205ee22c346326edce4eda05a55f122699a6c212069a61650aeb2dac569a259d870fd77fb4b397d22d91745b24ddcee6d08d259b6605f149f768c055ec154dc59c2f9194ec80d24ec2461435e093365e3800132cd9c428b77dfec75fd0b66072616e835e38002d884882d9f06b827d62948b1a3279cebab4d455be5d76cfca33f014e10269e58182623218c429ae18457cc165d490c9a114c048208089f0113f2611e339141146e239ef5008609f3570961a384b92af5e032794d060365c8500c6853270c7b158bfe40e6c5cb50862c2434cc45cd52193ba22a038f1a3a4f2b12420d74a45a3020a8ac9aab812c27df52aba0d8f243c2613572db08b37465c765b4b13df2a9c33e1d25de187a525f0eb51e5caa327464f8c4ede67a3c675273894b823d398496b882b8f9c14fd74db9170c5d010576fc6b8f2e8c9cf931f4ac6a52e8f9c30fd7494d3e9d2579f4bd84c010e500b8bc0608ba9208c0cee8c339398a2cb932409b60ac39533ca013c045bcdd74a5c5167d88cc8c3b0199f0955f3fe5c9610112ef59199f053f99f0c282353652a088220f8e1f4c091ec24c504bf937ecd783b177d0ce555322ad50d99be4d5dab6ec8342d7d83f1ed174bcbc8c8c88c48b805d0813ce8f2290e521098dc7e7a60010ef206409401032d7c482376052440b36c49b4dab3ed0b79a8594ea8cbead2002528d78b4f717cf1396d0b659acca7bc59ea5c87b161c36128c501c625bb4aa57215fbe4c9939d3ffef863ff18649041b07265675a930c93cc4d46e6c68d1bb48e795185a34bb9f4238f3cf26ce947a6c18833340e6f836dd8105fc20ef0342ba88c3bb2cfc8414640ccdeb5783b07499d21f2f98756bc0294e95f480392197e9e77c86eca53620c237be74e85985ae2c4e10c8dc39fc2b17178b6f6de3943e3f01fe8331cad4f2c89a622987eb8713a2ce540535223c24645908483fbc01a82b9fb6ae0f9d3e9e421a97ff2503e3b69d65019d79fc98e1e6e0c566e0d5768d2d3840438b0810850b04609964820044c5c590ac20c8638818c01102fb5cb0a12bc8444d183444b55fcc84943cd44273369d7500ced5a19a1802d8956b372d957a184cd8412a66a1594fcb237b79892e28e94b2f5da619123d4bd3a5b9b163d8ba422740214d8a0a90a170c414889357c92d8210536d0e2b3d96ec0d8041288fc3c36e7b6ab7f54f211ea421595e611faa3b4b1ec9622a3fd51da8ab80043bb58cc91556c9ac51d8e2ccf47b72ea7ca7a4d5939cd92dec3e78b36dba7f747a72b604121a0a48c2742a0240c2b4c4029c20a7eb81d3103202b174805ec9f6490ad348b995c76f93d3f4ad740cf374761669e4bf366639f494c1dc43f658d160588090b17fcc84253d4c0e1471e3ac222e84786c2453f696c549bd987f4f38fea2cebe3a7cfd1a2e0833b32104399aaa31ee2c8d2d1b0e946e6f4186808228fae70f2f2e88a297e3a015cdec64f2fc064a6729374d919887f54ef17fb3011fc82716bfae9f4f23233238a279c2069413885397dc642eda23e819e82764e16a5cd1212df11e9eda18dc55e86aba719dd24dd768ef10f9a51bf90c823f6d3e9e5656646144f3881711807878611046ad7a438cc62db17b4564ad33db83c71980892564ea4e92aca6e8d9686a600a27422f24705640aedd3e58f34536a3fd250a680bc6977a571e7d1335f7b8511480419ad1124248b1a8e35ba19317172707ae4684113a245ed1a515952a3194929424890901a13c8195d9a9753b0b0c086e36cbf5e4ec1b245930d0375c30546b3d016c10a2c576c3da44e1b0151bde42b5b278e1512b9278feb6c273b9690fe4edeb4b3e0c4651fbb97ac5aa7d34bc34f9f20929fb47680290f6511f41af7c80a2b3f761063e986b822b4867cf16d3216a9c3de8cc6cf0edffedde66c46e3db3f21d3a588e38c4bbdb2d84143b8541c9174f755491b13e2556fbda3cc313ccff06c257731587e4fc480ea5994a173e698c5917d9c41f59e739e385a6bad373a11d58f453c1103aa1f63782acac0eef918c37be20c2ad0db31026d1f559e739c2855b26fd660430d32cb4b97547e48f7229ff048daf9670bf5bb45fb4cc327bb99c526d24f4d272c39dc4ee5cdf495d2ad3ed299ffe25620b073fe1b5503bfe735fc3e47ead4e93ee4ab8a215bd359ac30c4e1e27190bc996e0308b77dac5b481d1beed7f847f5e9758ad439ea17e873ce4ae5a7abe60b146bad265eefbcd66a35d5f472e6abdeeaadde6e95e9a74b7913ae8a9c722609cfdc1f9d5d7b3b38cb19246682aef41134c027bf94e79d3c3f799f943afc7521ac0b6d4fd44e0d9ce5bb29694b9de069a5740489af8a4cef812581754ec386d9d006fb5dd88921c33ad1c2aad864e5c284519f302af224814db1a74bd23dadc8a46be4d2d8b4e04e8761beacbd37c9936412eb8bc028b9238d7d0983bc19e2b2772f25772d630f0cecb7ab7cd2667cb1bde7dfc46996c79a2dcf69e8b3e57d2ba5dbf9c73368be6e609ecf99ece9a47d9c50a2bce73345dc2ad42e947ba07b3e99b4eb73cf49bb4eeef924923af23d8771e28ed25664bea464cf6998afe99eb5f7769e37ddc56fa07efd86e92ecece0569cfa5f30c92375e8bdf709dfa0d2e3e9da9bb70fdc5a9b7882eb8d8f0c9b6667954dee379e2c28bdb10795ec43b5b9e7b4f5c78e17902fa8bf8e4b4d42ccf41efc2fa12d5022b35cbf313ea25ea34839ae535d37b1ef37cca3c6f26cfbbc9732e4485e017b2986790d2055fde50c25c42099b45b3e5f90d574af7e4fcb3f67dd0f4dcda7b552a77d60c7a8f8be6db00c2ad2e6d3c518617dbc908a5db399c0fd96a02b4c762b12730ce83b4abfa91a4c2398c1397f3ca39ce7c4df738ce47d67339f286a3e2aa7309ebc42673a574fb2508b7a698be4a27372b9db3e76cc9296be9a49c19dc934e4b6b4f59294739dac9abea2aa54b7cd3b2a4b49bb3ab9474ce39e7b474ce39e7eccead7c714ec520b3259db356ce39e714294dfaf8f45e27b99f21ad9ccefb78b9bea3dd7e7aafa3dc77684f56367b4450caf381dc92a2f44ae6b88a83d3230785c3f3a1bc3450ea469ce3ea1057873c1411fa1e191ff7a495f3c09377929fbdac0a820fec644b6d49d1d4ad41e6cbba6c97afcb72d93838383d725038382a481665a1859fa16c51ef401411aac25305dce7fc9e5c5c503bd55fc091a6734927e75d930b13aa28a59e16358cdbbd3caaa20aa46b5f1e5521c507c5055f1e55c1021754c1e45e6bc10b230225282d665a0ca56e1543f8006251d452050f3f7cb5194a0a16252759b7e45b0f768a5bdc597b044eafcda1d6fab55d510349e79cf40b07874be26c1d5027fbcec9b7774cae7c940ecab777b376d574419dcfb777b11260c9c12d714735317e8cbeddc9b4cd9a2cd6b4e89b367d5326a2a1afb7bac4cdb820ce6756a3fab344850a4da66f9f55661137c4011581fbf9a661aa4a494c3ed6a3ef995af4ed7506060e558d7d5bb98561821b3e52255bbb646adf3e522861b4d3a076c18c1408cbb7cf26267c9c56be7d2eb5ebc567d2a47db1868b8f138ad20fdf36394f0091b67f40956f1a5af07d45b684856661dcf8919d7c3ba91d35956f4e62c2553e1fb079a046aa9ba8a85da836b24dd15498fa4a63910d7dfb387f7e851fe79535d93483292668da41e90627e802f62384ada93603201df45027c971027d8f0a9238030c28b418a3960556e334a89d1a9ac357a89d1c545a4e8ac59ec667503b34145c5159395ddd72f8d5ea46c4afc270c1af1c076a67e51ed1cfb80ab53383a3e971f80dd40e0e95cba0765437a8f81b1e83dab951d36882c9c8380c6a47e68a1f0306101fe336503b313030187f41edc05c2cdec61750bc0d7741edd8b02f7e513b2f38dd72b1810b172e2e24bc8b8b5f1f9cf12eaeaa82f42eee5f08bd8b4b19bc8ba7503b2eac1d4bee28b1b89706f706e002f9b1c75f974afe3a6d978fbf77c98abf5e04fdf542087f8f7ac082bf3ec0e1afb7a0766e4eca51a89d548bcb167c8b83a89d16947fa81d9405611e1c691e74daae9b07c11dace04157f140870775508407fd84da019dfee7a753167fda39dd9a2a66ef7987daf128b53a58f256cadb5b513b9d52d053cf01197cc4cf49bb2bfa1aaea181e7e0a870708a7c98b9740926a2c4a04e72c78f344f9d52b74e3cf59b832970a0b443fd061183303f7ea4b1d1d123a9881c4944375072031c90e0dbbf9c2c35b51f75d020043938a2c1951a1071540320d860ca370e13321c0c148bc57ca09452974775f0230ccd833fdae8c081ac41007e944634198cf1edaa2eb2f8769fc1ecdb593370f2ed3954a828c940055dbb4209941a6c01c60e52469083e88927b448220d2564a8e405a3a8e9f610e28e2e039f123a5577510f74f2093fc23ce5f194fac581ad491a36e0020a8dad553268dc91ba0d4c0c90beb9e042e85b65801b1223b035894959e28812475c2102880ba618ac5994ad700289ee6ea9d3473180c1534b290b822ae59fe04a070a476a7cbbcaf6ed8e4486eddb250e4c199ffcc0656f95ac4c8e6adf055042a68410d7780bf812a89f1ae9ef10e6de7e9e1c63c078927031d8f5242ac09ea09c874e61410d6eb02430473b803d697724dcd7d8388e6327a1f5c47efa749e47f94c350a154a9844a18c748b7da9fe6783194fc162413b81548b73ff004243b3d8a768648618422c965a88d641940ab0a4a221800b682a20fc43023205f609c81be66eefa779760ab48b3d15caa316287d0ced72ff8fc1499baf6062662766283133731b69177b100a4cc19ad387cc9f2821fc3d9a85d32c66d903a40e09cfce321fd83bf9178487903f1ec00c45ea8c5cc4b784ec2806e21f19c7e40dbf78493f807f300eec44263113697b1de40dff27a4ca1ba681bd03ec4662105f706932694091f2c60647e56a77d7e6222662286c9b2d9ac553a649b642beacbff094a7e2a4cd1675eacddd9304a0a269ebc9362baa95052795698bf2e3ac629999278d326a487d8e226fa88b34b8cd3463b59acd96943459dce2b2e3a03e6df3b500d9a24e5b9c494ffdabab5adb8688526aa5a9e929a594ce504abdf69c3419d0a4b56b751f867d28c79ef2929b44ab519f73ce22f3e5943abb8a663281617c3c69ed2c75aea2fcba962cee031c5318538ec254aa2954f7ba4c8562cb09bf420250e10b38234640b6aa9f4e44ee1379f9596154e4e24ee77ae58fd09f35512e6a67825fedd0f824c78923128ee3388eab5cd36e66912709ac26e16e223a9de9d2b6fc90a2b5f7aa544e6752ae3caf63ea5738b33e16c80a11c18893592656f6bce439e899879eddab9393b56bf49a80da15d4aef1e4f33edccf13324ee899e98ad8c3aded9adf577d7c0ee83374819e9d135667b2b17bd1d86c55f983fe48396d36896f93c97ff8870e8eb5f8f38cd33af84777a28ee79367c38ea98f54918b3b764c74a85b4c4b204f206f78564104a00e4bbf28d06ca16186fc41853805a6765de99a96dab542397f3d859e9f1c155e3a9b2d8e8ab752e95757a444ab52b362bbf2dc25b17b430f86de9257a559ddd26c7167a58a9c387312472bebc2aea9bb226f3a2cddb2a2d75979066a21fec1f9700aecdc5c399f672a94fa19a6beb95addd66abdbbd231713e2d22162bfc638a9d193205761f34e40dfbc8f120764c5b5ccfc7934fd3b39f7cda253bfd784dedc2d2ae239d23b1a718d31c4172555812f3420e089902bb0d39a090fbe19670419c50b338213859b3788526aeb3db9895754c5dd3e9c6111ffb578015d092246576427465b674615e702990460c3e8c481d1b462420a518529490f1fc35536e170145f1526a944ab79416202bdda464eb66a0a96a6aa2b3900ed16894679a486794ce26ed59088e9f744667740929e9ac9d0e499d2e92375152229dd15913a944462d40a4820757e6f43175ab461c6ac8e7f3a5381ef93ec2cf40f3957220e940b439345f29d148f751ea471e62252c4052cc39a7d4e9170f4d289ec643f3454bb0042582e2d91b2504c7b74867f2865dac420da59f6217358b3de512f50285a53a8cf98e42722d5207e5ec7dd42f3ab32707dd480a355f1d4557514d254a44e5d93b514a299f28e58eb5d6aea37655a319561acc4b548b358a91f9eaa2ae89b46b4402ec6c44eaac7458b9239de1f8fbcd4db17b552a77d6d746c8a533a018b9de84e35b6ca29a2ceec8b416e794b3b352bffaa85bf39512bb688aa34a1c6f0f1d3a88ae55dd1651a4e28e4094465035fab1a32c1d9d51063731db19bb317879840653d14c1ea971f4dcdf519ebdbb66cae5b8a276a4caa5013f444d4c673ce3389e4c9a25b53083e965f8f2144544fa48a51667e4f032accf280448d690cdcba334869e51280548ef161fd02cf61a86f4b713a1dfedb24318e40d3ba594555087508536ad543450544444fd92621419b54bcaa3294bf8979e6fcf2e67cfda3532ed87dac52b960ecaa48be2479045ab111535cd574bc320755a5c09e1dc864712dec55db5f3113ff2113f7d9512795868066b11613d709a4544ab1109cd60ec41dac5473c6f01e5a5adda7808e1b3fda29667d8e36d288fa630f9ea759ded746a5eeac09158c0d0220a18e860c8033a4aa45d77332a4c428fb8c1500e86497298c104067a906631019ac50ee40342443f4cc1848a2647c098032418ea410553a668620918337b8d15770442009c2646fb643a183ee9fcb361ce27830148ce1066418058b1484d15362c1dedea2923826b5d2689eba9429a5311a68f4058456e9e73115dd18fe07b27ffc2cebd93b86a61bee743e67beed95015bbd3e57f4fbc3c3a22fafed17f0402839132849e9f1d880bcc323edce9591fd26f1130550790a8163ca2b722b30e34ae8cd175184a781b4a1a17b4b7e298e4adcf39e79c6ebb2566e28bef4456b3d88688570c16da4bc2d8e9f41b87a1c50a07d2acae11bae395f5b832a9c38ec330489dfa752584eb6fa78053b73a42989b8491183e697bf1132218e4cf6fe71142510f1f7a74f4236df226afc8a6d8947c34ea18af6ca5a269560e1b89a1080c0768d7ca6d8cc4500406a903a793c1d24b9731ba3712dcc6a57f9452fe611342acde40696b2fadeda54d7ae9947b1231c588dab5b2d58a84e247f02b163b3323a275912b4abb5ab44c8824936649918b7b032218dc6024780fec7a4d9a2de9d683f48fb0d650f2e4724279d0bfa176d12174c60677fa0ca687cbceb59670ac4b2f1d158ef5080d8fd01f12db89d84335585c96f7248e57e589edb2b24a1366c8beaf41464d917dc86835188d0f301bef819970040e110efde1b2ebab678e98a0b46727131b4f76d168eda241586242e5a5cbd1b2357ae9d966d2ae713a79e97205c303ba226452d36f1f42bf390b138cb846664bba0d1177d5fec37b60ab16570ed0711fee428eff10799eb4e7788b2ee8b80ff721f2e8780f6cc987fff0b163b37691f0d2adec588c65612cca04ddd96c49b7012cf3b28a27641006a770a04073c987443501aa8904a1a06812c98322098a2fb80a28cce8bc18cff8803a01b5445c5469f60aa48e0a97032fc6281282b44ae40b114ca893289c60298c5050a0381dbdd480edad638a020d49636c7da86cd992ce895554c5bc94c10c963c8be3fddbcb2aa430e247ff8e5508820090621004e3b1518c8660497c28018410409d1558b104d3220b1741302e8a74b8c1b0c4e08c2558873850609ddcc1113cb8c13aa4f121059f942e4a67ff6879849f4ae9b3a5944e45ca3c7bb096ebb84ae7b4e14cdb4958e79d8475a15fd6b7e7d65ff06ce793569f4ece16e75205f74a67c7b36b77f7cea50e4efde193364faa4bffbe1a3ee9bc864788d0efba9025ab82a0fe3c72f2ea1f47c4fbc9b2c579e51ab5b35a00e89fbfe02f9c3e8c5b836cf25cdebe07d6036bb7a7d0e7e437f4f95cced603e1d6209b1ec9942a74f30b25ec14da70a25ae0f1b6a59413d5e28936f4a92dc771734ecb71f3642dd755af539e4c7fc23ed932e57c56e7421f4e85f62961954e2adad033cb9c9653686f94b5764e3b7520ca233e395f4fe84743fe279cd3f0c8c78544ead3d005962d8f03deb7c3207b5243cecb8064fe74d6f7c0ac531491cec591abdbd0c73a0f4f6ac879245305aea74349c331c9886ac146d79629dad0dff9cc92a5a3b47b427b9a0e4169486560a73f82dd0c7d4e521b5a03f3d95be8ef5644e6773ebf73ce2702384e61649681bdabe2103fc24f19cb5319aab338d66f7188d409d168018bf4ebe9f38f58a9431b011ca7d0f4a3201fe11f394eead01ff29b2915abbc69afb55d934e2ab264d5dace36b44ca136536a4353dad350502a44459f22c29a2805f0c8fa3324422d8b473ac911a1dff927398a2ba9100dfdf41b26aa85ea53a4cca184f44cef50be9ded9c28a902aa4f47c0c81d4f1c6495a75fadb82a18fed1b19f16f54501267d40bf80746b3aab5b4c439c664d2041d806a72888055924e1822eaea896b8a3cd4ff9853c4de36c51851faa28510ce8207386297b18fec1ff5f7cd2e653b5cbb905e1b35f15123fb6162da039fa9635544f69c3a838ce30653f6b70e5d7265205202ebf2c6c2eb1a045c62465cfa21cef8bf3e0b0272e3ee27c4c4ce7323eaa3ec63f86f5313a3e06c6677cccf918496b8939fa989898182b8fe3468c4bfe91f218717459f94bd864756bb2729aa6679f59c1303d4b988d2acffe727b76172b77291544d1b3b7c49e1de5f3ec60d0b37f42cf7e9a3dbbc764e8d971c884b8e1356c526b72c355611049cf2ec39ded654209e36a4741d09ebd659fa4eb89692e069fe41ffc83e573884482d823616e011c4ad8a40e1b22ebaa487b0f2c090cf64db0869c68e50deca373d2d9c28956c2a8d864fa84cd9e49ba1b053c38725082192c092705f183046c7a873cdd0e60496056009b229308b034c1b62841900cc6c3570c61060c6049629ec064b33082ecc410c6a0c13a5c553182713a1bb290048c474a51c389125892ef0651c06cb3f06ebd1379748e502308968453c304b04e0a11866ab0245d0dce8075a26c167a602b172c0b49c0ac68c5d50b9d7bded9d50bb6734fb49ea46259c35efb206a87a3576e15693a950d67175a912767c91342b0249d14b0ce7b60cd6a16a67b9d22d8839b8e2b450ff35dbb82f1c92124256cede291f5c1a884516e211f8c0be56c75e0dbb977a60c48e6afa648a45d039f0c8d647e8b2b22dea20df36590cd923839b776b2a351a96c5bcf9eacb5765a18ef5e0fa4e049ea506fce3b799ee78122b537fd4f4fa75927451199222dc1c9632b032a69542aae61eef591ce7f9dbcbbd5e0b4943a379f7e953ad2ab92ce9652b2d7c3c82fdbf648fabd6ffbf46f7a336cf68f63b17fb66493171ac6a29cadf6e25b29f1ee6e969205194813a8eeb4b32574db3b1858df8939dd6acfc9c949e24497d09c3ddb324d27509245106c50de345869f8a53ccff321b2869d0c4723d6b9e93535f9258a6df0cd2ad39bdef4e6c9e769ce53cf13cac7fba7132af47a69fae9743a8d343fbd0045fa4503e87382e275024c7082d46bade2e7ec39ed3cb7968a2050bd22e8819eaa747047d5d34061980e8a2390a43bde977d7bd0de1bf652bf823aa791edc2abe5255bc44b0095f4500690cf89e07b3d3bd07bde32178e3e72de8527ff3c48f7fca96ddf7990693b09d4c52673489ef32f65802f253df7fc74623eb1683d4983e63c9d4e3e4486dc29b461e7941ec12950e7c2b1959e36aa793e2133fa1194e2adac05cf7e816fd29e7378cb56056121d0c9cb88d2284789a588ac49dae3348e9e69c931e268659e6d88a3eaf9451cfdd9451c59cf37258e393d6be19a7655cefa5c8a4b333667f3e5a2ad228d18fa4a1ced8c385ec7218aae0a672eaaa4f352cfa4df10472b8e37461c55d261c4d16d8823eb451c715caef494385bc4594dd834fe79e9a038e6f88c38585857dc8aa3aa6b5a4d75e5cc1172d36c49544f1a4d83b3a08ff3393b9fdcaa76d1cc4e1ce90ccdb5767d4a89007183643606ca745ba2485de55cb670584d0401c9624544433c4bb2d568f2559d631a2eacc9d9d3cd459f7cd938fcf41936c3be992b57baecbe507655cddd1305a203d4826c966a30f831e7698badca8fd2a8369354a452d3b02c70e551164a3f9d8a2312fa7532285a2bf3823bead061d3604c135a66edbd23d39666cc331396507fbbb345fed1849f53ca9453024d2a9fb481d1e2b6ab6fca7e608b901180b1f47dc3afa82153861863e9142269b0599ea7c2d15b2cdf68419a6f53769bcd21293e889283a774064e868a8882868664440c54d4358e0d2db58c16d404c4746b4a62baddf85603b205258d3da3599beac4b75bbbdaaf53e71b4a295750f9c254d8e21f056f88029da2860c6104607871274a8810037043d8a10a18dffe41662a1c99360486a30c4f2192f644292b118a3f293eb6c22806394c390a41d87405165c6451cb814970fbe5d11a3e9c452d070120c57e62b12c66bc952299dd91b403075618c54009e88ef46733c126f8388b5a0e3b6e00341365b22865a1f2f2288bd18ff4b3c0e0b99747598a5e8b2dba60fe2173f2124926241b42f6d34396670727f07113179481aa0633f0c9ea02360be63b8232460bd2cf0fd20f6820fde0031b4cf9810aa41fa020fdc004e90724907ef0415272e5680d19d2cfede5142f925efef4e0655e22fd1cc5b8b86c6b6a77c539fbc8ec3c7e82a6d3e4cc17ab5b2b3431e784992c9bf3e7688da0771962bc2f7b90bd44e2a1e9a5df78c8c173043e6953b9ce7aa70f44b5a4ae0b3b8cc388e38bb3b82202e3ec2c8e361cc6639c07f462c6884fda25b530a14b78433642b19f3cdb711cc5a5271adf8a572c828e12794011e529e7f944d05bbc07f6f9f51e9864b2b33583e5d2349a6012f664ecf1956b0969e0d8fc5afc890ba827ab057c0efa93aefbc41cd6e7a3ea1347d6d7451040a0c560125680d9a2ae23bb9daf3c97309e2772b64ee2ca138bf8d0305b54882c5960a0c8f3891c9b2d1d145c0993556012d6a3c407b5a51a173315962431e7035315ea2ca34e03f50e28c142d281322ecf382bbeafe605352f98f4c5d59bb2b325bd86d37954fd9c5f3384edeed6690780bc912c6f6c144b1cc74d8e72955bd55afb25cf49a728847fcef95f0d226fda69a5d5b39fe385416ccfeab35269d9aa58f3053a4e90db5f18e45a00481df6d5db7839654b1d2a049574f9e5b36f07710bebc4d172a2e46ea16290ae05fa53e4a48e1764896bd4093a5bab156557abcfc9d54a75d8d89871696c542450b528c005c4515bd44f2175e1d93329d8ac5b73c4ad36055ec775371a3f68d2831fccec123f08c2c1f98192205a5a6aad38e99684d22d6b254ab7e48f770c2b44b059dc96974756c8e83a8f03c28a0e829059e9e287242b4641dcac3c116465760491151f9010e2031b19690821048c2232c210e2c58d8c192c899131c5114464b04008213da8916144088454591a238d248ac6581281902f646324755d87746dbc3c12630d31d0f0acdc1c2f8fc4c04197c65dbd3c12838acf8b9b7a792406918e9753ac8cc1716af6491b9ca9f2a99ab2ade470323333b3b5ac21b822d53f0b82ffc56526aed5a60da90aa894add4954d2c15a21101000000009314002028140e878442a1502c1e0983a67b14000d849e487e56190b942488510a194300018000200400460006464c1300888517a3e66db21ec41b12d1b522b31ccc48973e666ae4411df104f1540d4a45ddd62aadaaad099a605449556d95a32af669d2512d70a04ac7de8ecd48275668daf4ea404931aab268587520bed8cbba162b292f95ad772c633d495951b4b54755ecc91cacb84f938e6a08a76a8aa76a532ecab610b5c140946bb75273d24b7c231d18e5647e94c281aae228798fa8642d187628a23e2ddfaa698f1436b6ca4d4ae9d88c7b2ab9011c9ab7c746d2842165a564eb0ecb784f88836a9a9252a9523bae514fe0b08c7e823e60a605cb0d723304880e2f1aecfb409402b8763d793349f5187ddbf390151054b17f57a647baf31003f89e9720bcc8a162fcc53ca44c0bb8b050fccc9dc0ef666fe11ed00f2a051200deb32994f73bbe9455380dad85af97d3e09f00fbd6aee9e3d0ea0848684c99ab71a7598513f395dfbe2f73b288d0362f4855579eb965e710b86cb744be0a1e88d631de9c78d92521907c2739bc3cc9b0d197707e2cdd6c68953579590a816825230ad587f7158243e14db61d4ff132cac32476e734b78621c6862dbf8b0c2262ab718766c4e23ec9f1293c520069d9576226bb92b24500c3e8ac6582b445caa26139df6998286d102c2a7264357dc5df9130c3d0d982780b2cb89de192be91c5df18c65bd39d0e6c8af160fb000eb2e7371289cf161f864ea8977037058063acbfa2f624f641ac7cd5e599203660a449a3d0358fc21526a768a31402bb384dc51090ccdfc77db5bac80902d68a7d8f05414c207a027d5b1ff0dcd4a57e4550c3617c9996b5639a3ab414ea0c0910054a6e6373a7b77afb9745921dcd784790401ff8c841be48a58b136bb2a41c6956b40a258b6628cd8c30bc701ed45baf74267e7e515ca5d67b28e7604d147da84b7dafe3976f06065f98b242cc6a29a53836b4e763753b6783269ffbe9dcbee847b36a009b02a676990dcf93876a4c99cfebba9f6c71598810f1a648cbc483c48c442dc4d6427b8c6d112a831a9ac1bb90f1d66f2a842d8f0996aa24798af4318fbe35857d39b1694bc65662d828a23f29e9b40e1e67d48b869f5082267542cb55b014c7786894cca042f9600b5d9d8fe5a7ddf9b89abd72d480aecef6fb9d19e9cbe2f7adffd261e9143cf600f137117bccefef1f8545f28d19130f01a056cbee1428b3bf86b82412a8e0a50d339fa302ad8c846df9a3910ae21e9ed46ddb20242f060e23257c355d860dfa926007d187da0647f65a7b446016344203c352b20848dd165711aeabc78470c8bc3874d56912b001cf6d166271237768ce49f59d5a1394069388cb191d2d1f6cead1d9e8e49c951aaa5e68eab198d19970ce5dde9036a80102dc7f1226735bba63cee01a1acd84099c87b58d19fc04d9e98de96af2b5f405b82f2b4e49fc9b05351e9c72fa95e6ff6d45d7bf0a3e582ff60aa4a25709c8ebca78b760a21c28ce72192bc3a26461a52d1f112de3ead163fca7a1b8eae4b8062456b40f32cb7fdbcbc9300fd80746a4ac30e39f3f57fa2d7318195e5bec37daf2f1cb8c9a3036fd5183766b231f4103c2b0efa20ed0b8f7e91687982ca4fffddadc2abc5a012897673f229a4d2fe3635df3b9930dc81791d79a6353481619f245e0c5d87fcc19d6b49b56ca65d9c3f793554bc7e3d39aaba8baf708fc7083cb74be4a1feaa74ed14fe604d3d975dd9b8528f892b3514798e54a0d15878c4a0a4f98840ca649131a77c415976232d0ed6939fd342dddb83ce940467d32d1bae117f9d032371adaaf5fe3136ad41de9a7ef69c4cf40839e961a9a1c20b7ec80bb7265bef11bbb4246d725c1ea27d4ab9e6cc2ccf8219d2a380bd7205808393f1ecde0b7b69e4531e91c3ac74871d236a45b658fb942ea6bcc2b144b46a62c8c04cf07fa16595695ef997c314ad8165539f00235930fd4eac972e8d9111f65d96654b649a4ea9d3a80cc8ccac07447339e85d0368b8239020939361b67dbaa8b8b8945a0d8300d8dec0848c5277593e09ba733638e16dd8e9fe1c648dd980a323788895b6358091929e45fa6b4a091b27dfe98639dd201308ded299ff83cacc45ca32c2f40fb0864df653867e730f6913901edb30d979228885eaa174fad6f6ae785993606acf7008d5e9840e2b63fdeed90b6bc6244f206c3bd5b8dc6a219616a23ba5ba86bfb96b5f92687c6404add9ed413885cedba61a1c2292e6397ba582ea393d88b42449c3092dacf7293180a8d8cdc35619e45f18741d8bd40d76e215417e24f532b6c7517ef2cb944d2c297836a4bedf5c7297254207dd560aafc07486a33d864941da2a228462b05efe0251da0439ba712a3cbdb91f217213dc19f461f04ed2843ea41f0ea7f6e41688eeb528343f1ace2db11d094dff3e08861b22ca8b88843d79af0f9870e6230727d92a451546fd97599166ca560b77a0e8c0c7d05a1de3004d8053770b9efc3904ab606005e07610f7d0c3f27343f4b71baa7a6b860592515ee85d7ea262960d0ec568890a0ca4094f54ced73ea73386475d2dfab8c60d37d257c54505ab3c89b0068283eae1b2248c401684b2fb931cec5ad90528754c1d51079d1538954b9128c56490a35ff7d3094ad88c0a0d1eed21f25e911740baefe18ee0f245a185aabff10d5a39ca49cf91bbad27dc4f054204f4ad8cb87de799fef1553f997456670172f2c2b1ec72092509b930b91c3b5097c75ef44851831f434a4ca6d0c10b48fc178282ee30faa5e765b13e073cf191f9542909433401365c6ec3ef996b2749fb7bac5a61a0828d15f020e22f266b860e015630ce0000c0448ec83b756135c305b81901fa9d64eb16ac927b3af19d3a554fe4e0ddbc862e40ff739b8a44ddcb6cd3b2744ad2572bbdd5e5d6987281ea64bbc0b1334500af3e6037880e7ceeccd6267d1206394314d224e4290b3eeafbf2fad7c578e827b72d9be48743c2ddb72b33ea2eb686ea369200b57d84ad53369098de484e3b5a6ca18d6d60ab7d8b97077c45728d816c211bdb1936ed19bb8b96bbfedb9670c9fc6902c026dc61790a280b7d145134f30ad90be2129a9e365f6636358d7793ca1f0105a3f136920adb9fbc6fd09a95795d19a7b083aabeacbd5812ea5a98baf110a90fc94425ecacbe4ffe18dcc2f044fb01bd02feb8036e52910e0fbfe5fc82bcbd72babd90284936b4687b2aca12dcb8a02bfbcc2a24b056c5ab8c65b4f3103dd85c2b7c89ba53e13d713e832099b5e8dc78dea6fdbd57508ef8d32874fb7b4848d6e83ad496159e33143bfd09df877b48cc8e97e389760f3d53e50b74b1004f18a190b691186351c1cdfcb40568e1f0ad05671e9fbb632761cff1a3df281d5b057fd822de56a80abf6c9b4ab2fc2d8600a9a5fc7f7e406581f13fe401e14eb4f80e6086dd703d62ad68bd3b41603acf3beaee98f2f7de55972a65d5be1dce18aa53b04b7d2a0a7c0e8bacc5d68be11955d12e6c1a4123706b370fa8ff659192ad7c817253034b99db8ac123129e17f5ff8af652b7e180ee53a532cab5d6547f84c928c2efc8c16afe9a10b3605de247603f81a06486e21e359fc29b8179f6243a237c42f1ba8d6c3ccbf1fbdd92c0db4a065e639b5fdeb19ae56ed0fe66ba7b4900b97336a767936a8d880f6366cd3645bd3e572bfeb2c861ec4b1c94fde4da41888be0e3e17b70c4c0ddf50298c4744bc9fb0f2de4091c060e1018501c4470afb7a027a6c96012d9c2da20a989fe9839e7b1e831711d00b4bdbd5fedac2239bba70d6027d66a1fc264a14228ef4e3646093434aa91e1b812f0e492b195d8c410d428bc81db328cc1d8f971e2838406dc33cf9aed5a03652cd66284728b66dfc5c0cf6c5e59d660d00228fc1fc5c6ecd4d0396540ca0f0cf4ec57f44554274b89873418485d01a1cbe605de1039d28d01caffc43c575a5d556ab5143fce22d1b526a272800daeed621df2fe76725b73eb8c5c3135b045526bf84cab024fc8bffccdd51193b5bf0dd0a1fdeb1f9df53e7204d7c72abfb44079fd0d8bda0b2d3fea91f41939fdf19f0ab15d3cd416c0c7d756a68ab01afeb5b0bb7840ea4aabaec99aabc444bab0a65750676229a19bba05188accbbce6923ce372d421909902a7542339354aa8fdd104a880b2a60963460aa6771e9f4931fb6aa128e9e295de8aecbf0f359d0d5dba0790e377cac700236299ee396bef6b280a95dc2378842b099c180834237b823ae50eed35eeffb52f206a50ce9ebd62478c72c7e904b7e1a6123991c1c4d9cc07b580924774e958768767bb131cc02827bca6ae60d1d578d6d4c9c5d27b7cc3c8aa0190de5939d145b82e6fdb65a013494d6b5da9ce3af4c15932a141623ab7cb1a6ce846d852730d8b307bb3d9116c22df16d3006345880d8d249d823dae98aae5c20fda7f19830510163c18a30ef56c5f5101fb9f097022004024e624f598b50e48b500dc09484918cc44dc21f84e367d96d0d87632edf7490c221680cbff0db74f1283fed42cca94a8375d940c227261085429aff708a04b59247095fe91ded7ad5b601ead6cf3c151e7b96bbeddeed96e1be4b114dd4a1b5324c35b940ca267992d1aa8b2fadefa714e4f5f2d5b28227d8bc10215e60d59dc8e5ade6f2b1ddfe5f5609c7684f979c6aaca2ed1cbf4f01ec29cd3600509c97ebf5269ba05c6404188cb3e07deb9cbe574ab782a9201acf306dd68463d2fcc6aa2758d72ba9c29d39845b9ddb4569c4b804b2a0881a7947b6a0adcf425ce244ab08e41d53a9ed47f68ff61e806c0391fd35d15872f0574fef71030f40c2b312c6161f451a1420a11e42d8433906a4da6a02356c75de7e6296095c519cf317b89b99bdaf99d734971e12e18725c9266cab5c86fd05be0954aa8a38d247d03161954e31f81d645b85a9e94f527d34c43b0665e7bbe9f5cf2173a81f2d0628e429f080a96c9210a6700ec548aa9f4547c31f59bec4aa30afa4decbb856ad1839a29440f67809fa2c1160f0a780b37ee17144ebfb2fc5fd5cfb5a0e64e90551f5a7036b8426872d34d089c521ff84c7284276ee01b1dc0d4f306c2c65fe020c11af1a67a372828c98d375cca15c2373480aa59288f11c099816a1c8b94738370982c6c47a6ef30a2f1179fe0369a48c35c227d97b12b61225e74396a4945c60cf9f55bf241d1c0d4ae965e0974bf68c0044634ec220cd79e0fc1a8052ee00a0361f3babcbfef0b420a15d408d9606a8bcd37adb6db1742ff0cdcbf09441b8aff167a9c0570211ad7a6001f12fe8aba55772bb89962c0403cea22ca928a0f3253a45ae78160854d59df5b4d35cad9ffe6ef1894040f6a1900b583a9e82afcc34738c70349bba2ac2372ac61e0f7574c947548c7c39cdc6818d03badf6cc7bc961766eaef1addba5b0f360892166c9787d3c453f0f22549e35d96a5572a0baf046fa31229f0acbae46f5b27bc60157fc889f5fecb13a6a36e258af987ff01651b5bc245b76bd3800dc7fc5af21dbd1e8034651edeee084d15158cff786f715153c0d04a5c3f2b291254c1d40254557742f06bc3ebe57edb90d1c34d5e238580c55521e7ef7775b7b90c15dcb741b30d40c519e10583cc7aab1415ab10b11842e0b0f5cea1dae18ec130a144198f1f333f652e5b7d1843f74d469ecea158f972dd7bea4265ff1eedb57b43cf42b166f6171293a2c350d8bd684ceee1d36540c441cb00fdf606086667460e00b00c01f7a5ab332f0e1d0fc0e2e48d509dafa3995b6f5f39d95ad9f05b06ffd5c89cd656cf7bcd2f2db65523aa8dced179f938d6fbee0c57b1c77936805032db863231ea62261e1b3280866ba8db3fe16632ce783a86788cb96eaaefcc35c5dee4b25886732f839876990700c279ce0384b7385bfa287187a8b572c90290a8083e12d741738b0baa42e0b05eea64d1a7fbb88f58497179bab9c2b034500a7bd2c03fdd0cb8a57141b3339fafee71a32c21c4d2b1c4e72fbcb9c0bf9fdcc6f4ffd55264b717f26c0206478a1e99f2be997c9e5058e6097d89152d4a0552725d941cbfc9b1d6804287de0069a2e603f624bf18ab24c332324754d0dc71e4ab0c36d8f5c884d060fb79b4050952525e8160347c43008da15812975ac4108f4a72c6f0bd109aadd5071541230e4515584e40fb0ada325106bdae71e97fbd1161badedc6c6251b720503ff8bd0469fdc00a2c1570336becb4e762205f40c040c77d894fa83ac9bcd7ab292cf75ab08ad7223baf2ee69069d06c00cd932d7a43d63eab42ccdb58517913de44991c5258a9ee6f6af360087d521d62f4fb7a2b2ed7081c04b538c86153a3a5e56b711fd7f223bd12c1b34f845828d6f83957706d61314765faf1e6bc891b22483cf74def2281ca4fdd442d04722e721d3ca3c967bbd5b351ec7c837c9ea29323dc208a127d5180db016623fca41801cd8a25363abe954b2ff9d3a9261f23a664acfcfb60ac1e57fd1f59702c0c0b797fa6ed6d4742b245cc2c52924432b42f6960caeb74da1b5494e6def334fbead4dcd2ea996bd0c3896fa39d4e29c7cb9431058c337cb6ea72cb63963edc14e05f275f61dad01e31d79175efb82e9f75e03814013adf85ea508b03b41663e41604f57890732a63f487fa26648a5015b97e6606628aa17467f4c487c75357ee39dc423bf5d1d373217c590832c900cd250f2f89e15390e391813ad124789acba20f938f29938cb061f9c1eaa665cdae754d4cb7d049d0367e62291b0635f41451d7564140fb550b5fdfdcac4ca576f6892984c61b7ef47d0b81c07f2c96ce02d574de790919834f332a981cf3efed305652c6fb37066b2fb24bef9d8393d4b7a5d87a9b1d15090c587319dfb5d736b5665c60e389c1c57da02c0682f599bf67734eb27cea41ec22c2a6a7f1ca9ee0a21d201688b3b8bfd4144393ca866ea5260a8d5f43f759a5b9e6063218b0bf287e1a6ddf92213fce3264e25e87913a18a0b302c5c9f98b26a8944b4578d24942592d60d56a784a70d29868bf98fd46c07c3020f8372128372fde49483af402c1ccdf1de3643ead44661915171ea340602a1206976a2402c70fd930467110815274899215ea54081d368b884ccfdcb7dc09f0241fa7206c5eed39f067789ddd88a9044bf0d8956268c2558bec64cd60544ac46016a8c337a1de4239f9b0dc322a4c7d16333dca6774efe96549b01844230908f7f2dda7b8eb2980fd5cc10f00ee1227442a6b39193d2ffa906459b8a7c31b8aa546e307b15261308ac7ee46b545b42f632507519d4216eaad7c76c9c2cb47b55a9266d12c184d6311128c7f9812ee3420f07d86f57d50fa2b50d918030afcd9a1092c0faa6d89f63e1341c2c60cd553806be9c9929ff436ecf00365a9e46e9546afc375b58bdd34130c4d8fd7bfea6b2ed17be4e9d9209c5bbb2451e80153551edfb118247477833c18b821195962d883a76a737a0a292514bd786af41a17f6c4a35b0008c81999fb9f19a7c934686fbab7a432fc5c54474d783f06b1235cd4e24a8f81b707807d117867dd638dbf816809afb9b02890b5bc202d0d1a900c4c2633b30caa7e2e673dce091e0819358b4e0194903187984bb379d7bc0083eb6673b1caa99470a1120c146579304e7d17822ac84aeda8a17f46bfb950a1e713c39c056f201113bd8ac3ef0ac0f04cb119f8206b0e18ee5ed7daf2bfffffc0375aca9d29dd781e3e314eafe3fe4af0324f3c1e9377204e83949eefe2dd790c8304b8617066a08b84bcb703611412e9e828e32034ed593471411e25eae904a70f0857a16a8ed8be04320354b11aed154fa96bf4178e9ba1bb00110dafa27a6820df1351a4110e001e6d624334447e00527461ee56d80260517d1ba67fdfb83345a0b3f83e343a69a0b4b459a9a89ae65fa73670a6d21b0c9240440b587794b9ee8f146f2ae299aa8a81b4cdb61e102e4dda834f18880eea3fd1958010a027a7367d99d5b8978da9f1f93d400be2453998e02d78bd11d284fe35e78fede45bf95263c59706bc12c1d8acdde9f5ae8e537b3e550e74c1986b0607437e33c58308adf98452f19936088241b2da1f414ace17f502eda427b63e526f76c95d8652948416c900cb637d14b8f0fa34216576bbda3a5914b7178c8db41cbbfc78f14e7fbc24466fffbeb1dd082706034ccd5a764722d3188fa390f21f9a036e8a33a18d70ff89df4ae92a1546633a41095706be76ecbb14a245542b9569fd311f6b28e28da10fe586d984769c2aa6241ae4d1e108c8d9e51d611b636704995e833ac14b0508af0ad0e04e3ba3b42e13aed6ce968a066d991b212cd43295620becb94849e425bf451fd0d042a72dd1b3999292c65d166f48c5246250e5253a9cf4d471d968e6c356b0e7a3a4986ecfd99cab3eb9702a37b8d4ebdcb98e96a48270987cffae022b2cbc15ce8e4806382d979288df70227399a4b75e3867bc065414575a801c04c53815a1c8de1aa5848ae3a11a35d2f1e59c0597a72ccf7426779b4b13a9c60a715e092420f12c0cf153a0dd38d059cc6782aee46010229cc75cbb42f39111498d56f55a343e425971de9f0be4151c935541f29238a6e45af38a2580e76e30d6a2af33191b1e6e0314dd78f1d64da036860e0f7b25871d041afa9442195bfa0118b374db946865814b46ea2805dc5585587e0008641a351ad5c2be528827ca242f07e70b4314d206f68b8cb22e5c9cdba8a6d945e9537d9ddbaad811608dcc4c079050a4a243402255e4a8cb93cedce066634211086d3f0891eb1e5c92cc0a3109b4b7881dc1178fd484b7611be78d71fb38dcfb60bb46fa8858e6501299c5af399d595dfa9b8f451b52797bb23dbfa01b5f89c3c2f594fa6a8333a8ef31303baf77e7cdfb147f3f35b371e8e31fcb9a944c793908e4aa428bb52f636d72ecb6cec3e308a829215d427ae9678529688042fb619411a86d9b9852d1abec15363b533f2f3f15e9e67a12a06dd1a3f779ddab6167064834edb20b14b152dd050494ac17349377c5fe96f6358752f24652673265b009be0dc059635195834bdf412e102fb5db7d87721082350a76ba2e648ce80e31213789eab5fa6eef9dd7117133e9cbeb7fb591560dc604d1cae8248e5b3ca4b0a4b23c080cb342233a7cf40bc7cd828fc3137c471fc8419d07d14a052acad07a3fc5dd9dd394843847680c461f26614a4749d50ecd3c715ebde4afe039b04241b02b5181d8844f647ee7e58b2a9aaaf775972012f295f619df3db7d6664454d099392b3692cab5bfc9c0064080836e6f33984080cf5df470dfc0defb62eceeb54e97117405d918aa8975390d24811254c19c467bea6b79b01e560a5be067b8a41ba2bc2c1e367ccae68c0e2cdd9751ac284258d3227e016ea2d37aee07a3dba031c473ac4375608b4843f88ca8c447b2330b5b4c277a8d5f7432468b447420951860f496b76b4834b3debaa44eb7ef15ec2a850b49d54771c13d465e3812d1b15c531e6a218eb6745c4f83d54a2fd51bd503a62a10b5a87883ab09ba240ba8617c13cc9cd6fa164c3dbc82b5c031fba4bdc8e10306504563dd438a233829a395c57a8ef185b4f90ff1cc9cf5d76c7e079a9457786f8fccc6c70c5cdecf19fc470369246e3906439a1a5568958be75774cbe05684bdb9663c4554cd1402788c6c499c05241e0ac53267c0f529c3ee879a8d038c9066fcfca39d79b8be2d1054b07dd20e2491213181890a8a978343a04a7179b840a73c438d03fc407b472e6aeaca2bbf117c210c6e69d986134d8661f91861f0b03bf6aa4bc42d4a3be7506fc592ce5449e189410b0cb8bbed792a123fee2ae564c9177cb43a31cb1e4d6b7efe00b1834acb934106c8bb8c726c324ac9d5b19e0fb2105d035054872c375bfee6416330e833e421625be409f2d2077846307d2ea6c341088f03dfa6d2cb9226ef2566d8bcfe8e86054ef801da316b5fc985ee2d419027a906eb6a707717522ba7ad19046c3e7ebbfadb94a1d9d7f442fe9d419023d085f27f7dffcb0ac78240e37aa0fb1a867107f6f9995e17e3774240363fd209851d5e1fb4e5709a8939baf08d915a71754777a00d51f03b58014141c7146830fdd4f453fcc44820c2660c7afe3fb2037f6778c237087611b297a7da48562bcda60fa26f8b4e73604ae4e5a62f023336679f390c2b24d82adade5592ba2c09ae9edd36070131de1e9d83302fc4cbd252a9a4a656d406ff7a0d0a410d3116bef93d96ec19cc10f6677fc6e6333555d755067b52ad88c9441e52989c7777ce3cae6ad476f3f874ab8c972d3fca5f04da2e3fd093ddab0d2416ca601452100b2fab147e7a8ca0504231310e906aa76b5faa15567fdd070ac89739d5035188bc31cccb99e40c36e7093596879dd2743d302cdd30ac6254dab8119d733291ad260d94e90cc584eb3c4e448eef0d1ba8308b1e0650b474bab78d82a35b569450da5b840c7649ab15ae46969d7f0b8fdc2b101270642548d12d14ba38a97eca4f6c626c94882ba535893382fc227894b9c3460959267c8c93d0f5380093f3f2682dbdf8fc78ae9d1f4a9e899c8d74251238a3aeba8a31422eb17cdf62bcbf15b4c1a97fb1a2fc1ce806908fdf2af665a06e92f3d03ca39d06dd7618f1c04eb9672cc66a82abf92f06652f5e4eadedfeb077eb2e01e602a847d14f6eb1089bb221d3e7e323beb308696e05b24f339087c1499bbb1b1325098e0e691328ad7e223c6af25f89048f98b1d037da05f8456b6151f002f22527b3bdd89777c914e92cb23a80b06f18586ebfc2546228625ab19757133c034b8ea4d38be00c40fc1a95bc861d373e8c5f582a1f42aff06c021e1f910c92015f735d35f4a0012e7a0586da9479a634e50bad026c9ccf3a55adc28ed1d6f4dbdc7ea038f5122cec152bffb921f0ed8498af31b60ae385bf9cd2ab615e2f9e65a5797a7f5593a0fcb31ffd9a315f5f0a9c6968213a189b2748fcb9893e663cad5e6db633bdc2db566ff1e47d6d9673a4cbd1145c3725a66561c8b0c24258af92422e62e96b51088258fe0afb46c9e8e3a1089028bec11e8997f7f1b5ddea01ee8d537b5b46f718110203494d42b38a6e4a226f013483a0b886b628f516dd43e307b1e156bf0dc9788c78226fec67b5c3a1684ee639908efeaaae5d4a8586ab3cabc7f84e6b3e261294dce739327a723a20e0fe4b97eef28a7d46f5b7e8c0e97e9b45b8d9b51611f2146e251b7e2c3bba652e7538724c048838670f6a88123cf4f0812982b36525d8630fccd62fdbc189eb4c405941b652f769c012daf38c8c917920db4f527b0d16069aee1232e3c486660fe6f2fc82a558d63830da08da6a0aa194848840e3a1ad99416f6a9108a1c6ab55e1c1aebe63b5d7d8acc9a65119fed6d17676650b46c8b85ee09d18c67440dd4a5db38405e861918fb4801fd140e313234c47ad0f94c0130f1f2083b0264ff4a692fa37cc78269a6c723692e3a8eb0890fc76e70efc230334d935fec8494cd1a3ef246f80abc0b242ea80c6aab0422102263337bf3867bbfc3f11584628096f4ae02fefc7fd93210e6d41db38700679a1d73744cf1302d719653bb38185fb397f95d4104d860ebd7175b4051a7c6ce30674e23040f22c4d8368734e053aa6692e1d2c482676a58447d6e7c305d3e9d6fc00fb8931450dd1a66541e082d5e8e69e85a65e02aef1b7c60119be4672b9b192cdc38ee0b6b94d59a6116017706ca236fe8fab8522741d0e993e816ba850b92735451d27fc7cc007bdd1a3f0440b87ab75314f248cfa754d37603e1ff4c408852696cfc7a6eb834f8c42e4deaad3f50e6cd6d796ac640df5cd64f341153b3c54ca0d7de309f895f15ef5f8f762b9f11802bdca2d2b4744bb6a480a0bb2cbc1e178a50c6e7978d83f85587daba99609946d5f8bf4b0a0c4c39cef70b699035c28ff390eecf89a3442dc9a35a83d91deef9193b8b10cd385694b18f31b4c0a261473d741d83c2b9341927facbfbc8c36503de0f0f79e00b77764ff497e498438b71521096ba2931bd1c3e559ff6c6ef809f0901446dc5223317f3f703134f2c43ee9e0feae99b020f17e9074bf2b7da823ec42696bad8ecf04df413456a48a02a8190dd0272e81e3583501279ed5f14192b543b3396c44fe8957bde111dc0b651e425d3e9b52b0789bc13ea02a50e4f2342de4079e1a019c27b3a12f0ce538dec61e303b4602bb8386e4cbb590060e55ed059c2e1d68ddc19c9d86d62d2c1d002f13444672177e95cecaa496cd617bbd87ca8ff46773d80ce4e8a2bfa8d252bba051c3eab99bb26e78ce88776282a6173fe3fa8a6d74df3350fc1ffc06430a2fbc900e4851027c1a248bcc09ebb61bcf6938e26b533a75a9abb32110b09f3e984c42d5c5e3cb67ef4b0aae60e670bb30270b039f6f22b6c714dd0e223910895a8713662f2a07e1e7f213fbd7f49100e33e0793d9e283568ed88a245cc3912c2e1318ab90d2daec3843d7f71593003bc96641f7f9b29ef122dfcc51659d3bdf267349b1e4e285ff604c26e250b56de5d5be481bbc04d35d5be3516711ae6139ed61b88c204cc90695590dd04cb8c4b806df3ce24bdd08ac345ae1d11490e60c234bc27e23349fb42123bc849260a279333c53b9ae6ed4b7f06249a4010edd1437028aa2794f36af787a48d969a9a9bacd7ac8d75e8130a81811c183504f14aca65a08717e9d516779a523cda9b34d99bd75c153c5cf1ca14a918fd699d55ec4fc2e566a4df8c2449f113f53ba1f55747bf1866732d375a903d82564230cb0aac0ca99d7da6ac3aa094f5969062a712393fa8d3ec51d1133992905aeacc447eca6cc8819c7c0939022cab076679cfc2db66efe0fc865a43350f61e9f8c2d28fec9e59eb9d1b00c9774b7e03608f45e5de9890e5749590144f482ff5af6871bc516a810033841c1b85f938e4cb70a9ceb66105fa2a247f250fce5d53f1652c60bebeae4e6b7c202d88764ad2d9dad4d072015e82b4ad3ea90d28b9b0e327f97fd1f133853a075ae2f93801b5d6e2431e81a7d524a2ed09c94bd31f51c8467070d268c2a090f3a067806d4bf2d0a9a5cca65b7a52da9d2c1005ad9cb857a2f3557a1d03467ce2c0adc0ab4d3145beb5fb302055724ac2e5ab5cee9e326624ad7383c127e1aef1bda4a2e70af8cb3b97bc6a3049b274e4989214169b115269c598dee13ca44c460faebf69b63adafb644cbf33ac42256af3cfe3f95f3a24950c770399ae411dac24f9d3b49a592b4b7e120df7e6e4c6ec434d36a2de53b92ab2df48af7c3396f3e987a8a933b4ccd846aa05024f3f1a5a101deef61d135e97a4895d88edea0cde5e19669a02c98cb33e2dcd33784638b5fc3e23de1bdda2c340fc149ec7aa906473e7ed729027673ee5eb03acae8f9be3f6c1cbd9bb5fd3289e33b2fed69f358421b7b90194234654a2d291e628c3664860908493d829c08c1694190bd25df66d4597989d776dad0a1d90b4bd4f771a2dc965b74a7981966306dab42a7a00a73bf0d23e20ada99fcedaa54502189056b72d9574206650295ad7ea22d3adf8217468c99dc54818a0b0f546d8185a2c1a45c561addfca143c4db91dab623623903d8688c68a9448cd13ebc236b72681332fd50e1a4b38ae3341fd06e72281e58a968fc71278f4d237f715049a1887198b6b308abd62879c170469426b4d8f76ca204114189e7a08e3fda4df8a501c017358c937a1c156dc22c56ad41ced06397818f3e84e1777b8f8a589154535c639617ab3672ee936ec46a1fcd5020df466c95654c46ee491a454384c37eb3db8167cb229223090b95ac726d24d722cbf37122fbc38f902c7592d1081cabc099a5aa8e283d3b7cc37f2cda7444af66bcf709d16c83981e62bc63105ae35275082b2002019980b8d50381d002c42ecad38dba01b812faa2ec31cf3ec4799502d0d163d0710e163da30342ad86a436063b1f306f35777e3210f65f55a829786668450b3488be945d79bc5d520b2432b710e21798b8a833d24c76bc4d20b96562ba5aff4c64a411202bb736ad760a04aeee7a32af02fdb9dfb77a2e365db308646070a3e6424ae8520f20a376e1e89a4712a882f8be27e0aee02cfd1b0f77a1054e5f2cb25f5cc4526a12c48c55bdaa85d35125ad74896ab9a33898e559c4fe6d74c6e796e9dcb91cc4595dcbc9ef99fec445aff59462210e9762f479aff3a75e69a59d9430a4c389cbd59d503cf05be9cecae19643ca0aeeff2d688a8c0865710196f3c78031ff49fa927e65ec4db4520dbf5ef35995c993f76e09cb27ca02527262de86eed76a0cdbced5a49e3ad0ab79913c74455602bc3aa120b664d21c9a6f1d3e8420edaaedb0ff5fe9887b580a0759d2102dd493baba07b00bc3b2a7e1020b96b8b56e607d8ecd7d3c7a1a1fe7277a4378e74d237e9947e6a3aad8a5b0ebf16cd654443e9b02402c2de539e8f02205723ebf935f9f39d3494cee7bbb562be7b27a1c0e8b2d9a48ee819a03ba307a98be93207cc262b0f99593606c058adb819b675fa6b32fb00948904703da94158bcc6ac3850bf45db51a77a7842949221dd83854ea07efb91afdb18ca5d74694cc7e32da6ce5498b8cba295a4e06d3350b0b1214d9bdc3aa244486782375855fbe6ea4c7bbf583003fcb7444f39ee95cfb6db7ae793daee383542074c720c6ae7b421edc076718b03b48811c1f5ae65640ac5a171fac34778472213462e7ca2a2873aa5d621a0d0c835bf69481d2fdc0ac72e898d78b607c19882fd4a7d91632c2c9c7e0d3586a9e26f9ea63d9fee2a8342f09562d9863793853d93eab0bf734aef65d98b2e67d004e530cacb5740a9daed3d098620fb4f00076af249f500e042e6c26c5b0be5ec7c52800b0994ac1171cc02092a57a66a27949c729300c33e08f70b384274bb5dee00718610ecef8b49adc871e469e491cf1da0494881bc5f02dfed1f97ed21ee460b2a73639bdfd9840b2a7cac693dc21645a4be4149db17b97f4ef2aea10965beb6f896925536c0e4a22b050aaaab1085ec502d3331eca72d5d37592480c20c369af86fcd2c79374fc48407028fdff8376dfa426d43336227e101d731582344e2e3d182d01b57eb215c94923223e23226b4644b2d4aa6daf632cfc045b01a72397766dee1d4f4a81d37486f87ee67c24b76735df0fc772c81a7f005ca2f766f8ca2d4f01d46f73f5da05323032f4391448bf4f666d2e6fcef96fe694c910fcd826ee7b8eed24c86b5b49df3fedc74f113a2870b80d9f66cd6edbe1a073777e030ca94fcbafb9b32562c851aee4d80c32bd1e46f5493430d8f5e45994a517c120e354b54c742e35e5b00a5a56b96458155250921551b5f21124cf84a35920c702288043a276cce5962d0c8f12f672ef6696cf6baafbdee75c57c104a5208ba36cda031a104e1f6e9c427da06d270bb3257c8f8523b2bcaa85e789d15b5bcdbd464cf2ae02773c2513f9c5025bb918e82e9cb70375841ef67821e3d0824d2f5639e6c155ab433d5f40359c8de59ca9be8f60ef68857418a2690411b654565520ef75a6813aa98222ad05335a6fa6f19c8e1510e3cde81a47e2846b92e01ebc81688007c519b98c15c9c40953ad3557cb8f64d0c173f06e20fea6e2a72fa9f84c25e5cacff66ad51713388e2c4624485a7b01b20c6f336ee4e7ad30604fc252a018a71720e7ad6dfd16a831a9941541301f1ed4414eb26272facc8b335a99b0a96742330281e5662c85620e0b0df719a3c3945ec96423170dc473727f7dffbd2ad005e5a54bc81718e5a7b909b6063c22f6dce54b25bb3893c58c29c4f9b05152274c0b42b426a4255d1f5b8b3e821b0c55796ba0ba50303d390c6eb3bf0c175560af43321e6fb767c764217507423a619fb4af33884c7a363460893c36b5c47b0c1ac6ffa99892158c198018640ae4dc960231dffd42888acba5ce7174d3fdda9e663bfd8b667f2798386a6b8af8bec937d29f6c85cce48b719c278ff48ee2b1dba232f307b53ea116b4620cd934d3e6807042f0b04ecc9396f5336fded6e7759c757ca84c8d360281723ebd15c64a79c8f656a56c85792d75213cad1f2bc9c13bccdc8e065bd2d762241f3252f8b56f126a94bf395a3a7c4226f756b6a4ecec291a3f08474ddfcb1385750be617b06d572c4c59052a96f5a117fb3f52470aca6edc7d1c8510fd0b022f1458c21c04a125bcf619c1e0b1daebe5d7295992741b5ec080e2b9add449d72684d5f411c558a96d92fd18c403f22878905c20677d1c41723da8df53a5c71a558964519937f1d053c903a4143d112dc7f5732da330d957d7bbcc2bd293c2a293ffbe5cac05cebef82fa6ac0597b0d36e16022fbb918bcd2ffed4607156d09ed04000ebf9460025bffd50a97db7da978a34783a3d8ae5fa2ed1490b190216eb1ed2498efb26295ae4cc83f6d63374c3358062a16ad1fc33c3ca3bd5a40ac7ba9ddd55a654b30f64583ca42c364af005be5ae3bd8b04e928aefa10709b62fa2076b7abb47c48094a2d8f7be6889f46a857c79b44a489aeb6ba7fb142e37b08637ac907b3280aee05d6c25c4e780dc5b40a9c4c1f2b944b21e58ec0cfff2090acb6c679d6684e1713a14463b366c23c9818c633d1fe51d196a8f4810f10884b9d653c77042ba5cf9c6f595eccaac5d33826b558f308bacd0851837b9f71ee0691f0e5677b26d833b5eba10a8f6bcf559a7fdcb2bfb6313bd00c8cfe8c2656eb7ccf7d5a0c4c6e9f1aa89ab3a33070a048dc90778a4b2521132b77a112d4f87971f7c40fce8126bc76b70382a1ef67221a4574f1ddad2b793bb5ffce2ddfade910c9dc47ed66f029c1253eb47aef2f113914da6b19fb901d431ce9fed465be3648991857e76cf090d4907302cd10749bda8486f0464dfd33f99ba35121d73c6e4408b57441fbe1b602b4a81a6fbefe2c057a609bf42e5d2ef2d43b64cef1dd21dcbedc0732c93ada3aef2e4af8e342c5bb4a6d4aaee59772c31c9388aa5963eed2170a53dbc2737d1ad0b38e178159488e82350801082424a2638a1e250920906363b4da4269a7ec4128cd237c58fd79c413b301f3fde8385da3589a82bdc488f7bdf2f0263fe8041df7ad1a03feee4779180282d8013a3225eefc26b377c4188d85e63420a7c4c4ace67ef6ec0445449325704fdcda06d20239371f6033a103a3c014bdcc49773d291411789adc58c4033ae258071f185f4e75b5daee81c0d125dc6ac2364eb77ccd17ea23bbb71c0338729d6a75d02b5e60d53db4063b0eca65e8957adc991612cc6756221e3cc42dd12bfa6872a6708b7ea90e30034bc5c89b209b40c83d3421a49607c49506ac4d544c5f86b02c628d082e66c694c6a59f8610b7b82c68e7efa2a1fea6a5edf84ce827ddfccafc092c4944b4b06759675b05c60661425e2ef429b155d1fcc0a5fb1429654436a225948e906ecff1c0d1355595ddb2d0d43aa134c04021bdd82e8a88efa2921cac91fe94672df20415e0914277024b40d066df069134f261ede1987eb0b5f1a83e9cd0b60da3c163ec00d1ed476519186df5814042b0a3a12e9e00ec67e816380b56966a8125989959c6e83c971534859eb825f2a8cb23d9b3b0e21f6f66c68e892557c39fa8257d64f2865ae8d06e8f93969fc452c014a1d83060e41013258b0b4c4c86a9c8225dc2dd38150bf99988545ed0d551cb1b695a5a5eaa36d8d9759ea5a47d178574d5e81f775a247c4b20df1be6801421a59059a89303631965a7ce33212faa904d8d5712a9efb2bbbf401a4ea6c32724df0c12684e66efecd6762aa430f5cb6ccd00d348f3119fe6ebf2c97f9b7d6ff697bb895499903cd20b1e428bc05f2ff363c98fc076f5b49e55e0a7d04f3e946b308092c1abf5ebc597b62e2058140b0496101cff2a2e69a185b24101f0f6a203b64af517bbab6ca0dadb72283758e696b3f0431780ad37d848e5ec427206e57b803953ee12d451f3e4c93f2b3cb4cecdd6a09b5023f972be84191d20940ca70a0053aca81de7019ded1fc8dad376ebb08a5f010320a9c898cd461f9a275b7f9a49e85ec800a192e2f74695e0428673115a65fa5d951167dc3e5800cf760c938b17f486dd4fe3a88bb055c8b57cfc51f384056d3d490ab284e39d3272b8f8637290d91455a3bebf6f4f3393535313b1c65c01f2f6ecde6e0b60c4f14459f2e1e4831df14027e30facccfb32ea769d7ebbb58b59d814df3809423bf302ca992a70ef63c591ee6c3f3a1776cc57e5f0faaf01b250f1cc76c38f2561ccd211a490c4ef4af2b0920a624454aedddebc5525e3ade80a02e2c20bc670ec93c7f15159ac3e620ed208f594be6b78d0679cdf55310e1a28b6d0be19684d2a4c2a86fe717abdfbf877fe231cb05f011f010f282a90f540edce257a803965c2b1bc9852bbe49999f4e127aa1eec7776ae9528285b0483d2c1a90606ac02dfdfe05efad27542fd432495078e5d2adc1275fdf74c53fd1ced6c8457f3bfff77af026d5136389c9d36c0ef5e4c0936b30bba4997bf1f0d489a2de9b8fd13672a1c36e2d042578fb8d37a888ff0cb5a143717851b632e41623d4afae28f7bc5f8d7adb1e6bb2f53ce596592ebcedf55981fc50811d28ab7c3fb9aed84983a103fa657b7d3bc6e3641649b8b55178350e603092b81b4da44a8c9421a89f8fcc2987a9a09ab312852e30af136749ab6fac2da7293a0be3fbdd4dc2b8b99290471526b6d5620d31fe3e4d0d3df4b8f71b18704cf2c849d573f1d1acfd1fc0ebdea8784f4b3e830d6e46d46f7bacb46ba51c9e93b0e6c1b789a05b9b8affd4ad96d907a5fd5481e31ae950d8b7e05e2504f3e5125e701a22dfc2f795bbac83fba7db93434f5c9508f6405cd4a250910d532cc5a3039173feae3c47ad8d87aebc186387aa096b4694a3ca337e57be1bee6d0a383096d50fb2501288fa454512c126866588ae341dcadb421af8c47cacf2b8cd1f09dcca94aab27615b586509f3ecc562949c163de07309d72423b58b4e85719039ca949947ef28db32e67e848dd6061d04abb86ed9a8f60bed69e2e9c209b8a386bcbdf1973b103aebf868b6318503dec4ef6b3b05d369a3ce94a0938fe3605e809f56f5ab37625821aa189e0125604d05247310db3d407afc36eff936fc6f440f54bea23f4625e2da5a127c98ff492e09c00131071d24be5e2e1d1bd9ded495bd8650126932055b33cf45e21888a74c3789a565f91664cbab6af344510c1875f816ad9f11f6414b8fecad6c534e1acafd7d40a249b686aff933fe9e6d7c7ba705f2638567c023825bdddf277f3b52c3cd2f2dd79a82faa504eb09d6640578078dea329725855bd49bac4873ac65be2dff8a865381a20959909ef158918225bc37933828cd11b75342aa058d3d193fbb0649ec3b80ef9a06c279cedcb09e323abab68eebfeeb484cbfd9714f96020c6839b9d7de028bd90aa2b6557b5cadfb250c54f9ab44a799286ec82cf371051ac2c6aaca0d9f82d4fa778532418827f895527be2ed3a271952b2bc3cda45c4253d1e5e987e0e989331579e15517c91a1d430d4a8084bf24a6fd0d7193cb48692f919893d51f74e27ca86bb1d148ddf80151a745a4d1df077d626671ff5a26c08433b910110098484df5b4ca36f23c81f5a762c35d9e726a848c8421252ae31c18cd4ddcbbff70920a79d594f4caf806aa8717c69403afad9ad3a40c395e086bc2d46c3a59ae2cc2830901ca75db62cfc5049fd48807e1c7ed8d18d920263941bf9971bbf1bc5b20948e1c55f175d38cdcf14c4f04d4eee8e093fc8f984ce00cf53ca1e596c7d8fe80dfbf1d38d105c0c1043c987d6ac4d46d44a4af0488278702023e72547c2b1625c448c5adc4ac395697715fdd1f5bfc145135afe8f1c17d2a319b2f8052d563e4100d169c5651083bb2e4439eabd3e5185149a85fabe370afcdbfcb38c289e84a8ea0e37c43bdf00a775ec10a77e3ea2a6e3a95e7c14b7e924ba2c1f6bd5b7d8c13c4543a2dd9e58168b9ef0f10669d778e3be2ed48e0933a3a0f9f0202b3361b3ef7dc5d10301bca670190ad3e16d09c78efefc884a42ea1d99b32656e271ed50122ede7ac1c00202da01a51544c7809966e32c6e147859c9be82080ca9d0a00277ca6ad78c7a31d84435f34623725fbbab9e3b95002c48e891dcae1a9f582714b23b46aa704078a7e6d1c3f94a03465bbd198f96c9a536ef6c8930cbb2c9bddc4da4027bd918d0c471367f615f9912513b5981a4a0617869091c2cfe635e76e18ad0c3e8f6f2546b2a26be637b9402a953786985f008d70e359fd977c2e0c88d950fba85e37a1926e458d40b6f7e4e4856aaf1ca4f4cd3fba2972dc7918197afbb9ef01db2446cc8e957bd8ca61bc63caa95056b542982e012987cabde8b6d7ad01304272946c2a768a96c440b39ac00d7a6f20d3958f3e6c9f91b03633b6f3489b2bef9751939af7367446017b0e7ab278ae6c94df5e763af4a3776f1fbdf3e52134d54606567fa054dbe5459ac84820f55f9703f64980daca11a1d697f09f69fff790d215d2e624a1d460f465a27fce65cd1c4319dc1a2a82ab1226a0cff3e61fff88415550fd3827f8d9338309d1783ec4cea0266d9be8b21736568289bf4f90be914d0502dcaf0214a403c4cfd159055120ceb8b37a2ab33c0e8abee4d4897518990d5637b1675c18c21ac9bb57c561e5eb32dbf16667a1036cba855308e3ae53ec4dafbc63aa93de44000708f728ce42e8e769e11ad1d28104f30939f97fe628c33fbc00ad626f5301403b0eadaa3be5ae8c2db0e500752d5fbdd80cd2c26dc983d7b92bb5681d3fdce474a3d48abb98e2fc6a7a07532f704905402b73e24643f68fbd95557fc127cf68f5f3d281736302a3f7a3579b41fe52eda066f05daa1d06420182cd7b64e454472e7df90b786060cb1e504e98f0f36d6e1a01b5f9a78b92ed2ce0610fcc0dbd8d0dda1a4b6bdd32594a18288d6a9f41ce7ad1e44de19d32636f38fc5fcf0320a0c15eb004e105ba8faa25a4735ea29ba23ca05cd8d856dcbc84153cee318c8b4800e9f9a6b39ccd3aa6e1ae6c08948c4af9a410910685c6f24889c3f18ab96a03b418f93a4fe4cab3087c27260a7ca779fdf33ca5583a017d4eb85eb8089e512dce1440eb38cbe5df2c8bc4546d98864fcf4ce3da92e65331723bfb036a08623f037ddb0e485ace2c46abe7eb4964091d2350c23a3a7a370f2bbfd8d67f8910c5175bcabeaf05103dd7d14b97bdfdbc863331e0ed5a9bca5d28ada8f62163cd3a4807613d89cc27c934b6708f9b6683f6454bb8954ef6459771c9638461dbc6746fc3dca5cce18d8e48e77ac1bcb164a9911cb649cd5fb19e101b5a8e09bbd6ac3f08fd97c3e513c4a36686abbff4fc8d81a7a084042067b88055fa00f85cf34003d5744563b96c9ec367744afffd57edd032da8eebd47b029610038408c078ec1a7f4047209b47584f8d68d99613f0ed6ea9ba455e804e83873560456b45b9709dbe1e1c9e1620e96c75845da3d622787f87fc3948ccbe224d937ddaad216c15d778d73c2f87c0a97c07e05089fc1f81941fe0d70664ce465cba8e705222a5b1dd41af0ce44bfabc793559e14ba47b638a21ede9585ad8269a003bf7d5496e040f36ea8165267a5cef36686e8bca9318a6d28f468edc45b4cb8f00be37a5749cac14758926a289f54bedbe12321e2017add6dca76e44f1805c0e5d7ba2284e53d6ac771126d3ac8cff4f79a63027200d88e6ac1c0d6ad3de2b1e287b91d667127bbefcb891aee97b0e0ae07b3d8e4f700fea72673f1029de7700d9815a57dc09795a38f85c840a2ec0848817406c66f143a88436d9455ab3baf296a0d2f1f7c66a0be153beda2000dfcfaa5801408f8573a6edf971faabda66bca9adc70441acc7d4331f51292cf9e124f52470ce3f90546e2090c119f5ab39350522679bd148a646019f9a1af6c74eec41e0ce45f5caf505612c5217360f7fe330fea411c39f79068b206da524c69c8c240bda24d79a4e812927c6db00b4777e0ff956f746ac816ada50420943ead5d1792c4ee4d0f56ced0dd80b025dd39296f6902d51f4258f0ea8f3dfdb82d7bd3a3f73caa536a0db2fd931bdbc4d42b2f4a16b3801efa3c6fb11b04ff2477633428ddd407b69097d931a6565468d32dc6ed6017f8511956330c748ee5af14469c6fb5ca298f4224e88b9f46470b696735b7ae90ead5ee3c2b968756faa9a9daf59d35fba14f6d4cbeed8a8934572d137e7dd90b13504a8a5d37373080b814b6e961adf0e88fb235af26335fd40b0f293480eeb87e86868f8dd28c7dc35038e3cfa3ebd2fc672c919781782272018465c70ea8501f82efe316a80961e088c81a5c786af218b31f34e53efdccfa3933c1a11f92c66d9f9ab4f56c29e8c4e287450f8b34bcfa9cbe00c218d58b8eac4fe5b69cac1d951e3a7e1a7b8f39e1f0dd37b9721969f11deadbb9db7e366af43aba223062ff6f4e0e4deafd3d023c565e621f81edfbe4fbe4afe32df17767ad0a73519748fedfb5e3d287fef5b640340838060e404dbfb8731bd3a813be976976fb97de4d6a8f406ef0373012d44e8079af112a1bbad98abc5e9ad276459e6cf63e631442acecccf7ce457eaa09f6116d02195d2ba271d11478cb7411ccedcdbd9917320c0375d49b9b2dd80c75c9a8c5b369e3b8dde6b536d109b2dd0a4afb980d567673c33be1d33db4b96e74496fd41b0c09c117bb428a53b363e45bfa0cf951e5b8a72eb18334a79b986b7105260dc56a6bde6e16d103980af9a2ce625a82ce9dc7455f0d5031a7a1cf75a281131748746be22892c444d504630e6012f4139c29f07a578fc367cb507a6a48e5c9fb9d221d83a8962690b137881dd01fe6fd3237cfca919df6bc256e46dad066e69885f9f6e50fa906d4fc10536cd89fdecb7a8d299cdf7294104d18603bf984b0b847201e2e077994b2cf0b02332276cd09746193efa1aa0bcbbed985b184866d8c09b11e558df43c6483c72ac0e046b3b1c4952f823e9dc3150ef0e3740e9c5127f4282a82c577d38029a282af680f89cc98119200119a11ac5317ebafcd82ef579f7a73974f42f92060dc4099ac8d862c3cfe45a8bdfa867ac49ab7c30645031d995007783ed9e05b41778ce5954395a01bec72a4039d018fef619725b7085d9ba3f2d7971eff2f9d79c8da6be5fb9fce1f258f71ffbb3fe88b7da546aff675ead04e50e227f3130a4cb79b039a4a4abeb65f0949e2cfc7ce44c28194c1e81504481f00b0be0ba11b8c1affe06716123d4fe547f448f749425e9df80a98d83d5a93f33c501dbcf7f5a57dde1afb9d3305e3f442ef33ecb5391c8eb075f1b5c229a951b119e62786f58ea828df7fc74d6444d6d14a733b2aba1b27cfc1999ae54b5d26776ae2010b39dac00fdd90ed2b0089fb3da687f3b43061bda79386e648dfb5ed4e9e19cafe3a6ac3b339e80a20004a38ad34a1d8856f6fa1c9e1a3c2aec1b64827630c949bbf3b58202e673cd76e7c6b73be345d42f4faa48046431e2bfb399d59dcfa2b11c131f951eda8846571cd622802b60c54ada49654e4cb098ed72f1903bfe04486e2616bbfe96bc6adb05dbec54e61489f748ee6509f0e500b0b9c100ce8ed3c1f6e0f9c08c387983aaddcd65b480f4dc8a61bfa7079dd09ceccd68dbdf80cfe74dc3f4c49533a120781d6f50700832e0f20289b5e536b564f991c78e04c6fba920b5402c4b782913975b945212e88f67265827a44fa34d5e4b1a31046fadda5161b2ae6d1166c81fc5c4f7305b4c54d42267e36bcf392f50a4866d631974899221e0d15f0f0da3bb4b67bf396b2c0d335773c34260dcd0582f60f25cdd8f612b2d4014191b2c46e871f0a2511fc7bb54e3ae236b07dba9bea249a6fa848f33adc147ebfaca03aa208162fad2f7445fe1bbcec61638107aef4b909b80cffea4f1fc2fed3df13f36cb285e5207daf93c18262df658aedc19b8a1541f7b06d0c02e67e1c935ee3c3b38fbb310d770b77387fb845fcdbc15999b99afcb6cced866322f90e1443158a90e2014312f1bc3d76b2ae6ca69d40e575a76e6a3b8a34d19ff6d0daf4220e38e251a9d1efa0c2ee9f98a6cf853d02e2cfd20988e0693d1fcae65aa162ac7ed3c8fd20ec9ec41df5b0a3f5d11f2963bd563f284eefd50fb6fb6ef77313eb03cc8ad4242e4ba805a83d6712c266fbb55b37a63a9b6e6042fb423659c6a1b2fca03cceed44867ac958ac013ce5156cf02e2f7b479548b0a2656a668d8d2e7b5639d722a0b9c918391123bf777dce8a3630218fd4852905e83c40e51d511f534ffe6877756096e506a7e58eef718b41b43ba8928ed3aca4531f7e19db8a5512fcadaa573e0a86c7b2587245b7bfbd684447d2425693656a8ec02ed3fa040a73d84d07fcdfef78334d62053c3bd4bf7c068df9fb4840d72b20e8875012f0c8d7e1aa8759bfdafbcef27a1ba9ee5e84e0926922eafe31e4465699f1dbc8ad3db34e026dc345aed708d99793a873d43c4c641f924c5e01510143efbc10448e3394e7b53b194a8d7ba10c3342f6aeca1566662e392e4deaadc760dd7ff7aa2f821354cbbec8887bbe5ea4f80178413f24aecfcae532dd851a0f5d18c5be586089eb851cd866797b9a950b156d403a92a7cebaa266f27a1cb83dc7a5ee9207b9a6bbc4cb0fa3f08299993c7e6b8210f49e9a9dadcffb2c6e798072bc7bcd431cef280faa25101b2ae7452aa8d5b321fc043d22a1c24e45ed55730cc61171941f0686e56686cb3048259bfb214d2b0065c497e555f4b70289192275334fb07f665020d72df0315187025103149f59fa3e693cf310a40575437a47a2b1be8e1807ff30fa6ec034ece84b37042838ec7e01702ac42a191ab45d6c8bae238ccb65cbeac0ff81073aed7eb65daebb60f31b90fc19e3ff7ab03aef8204835b3f89b2781b7a7e56e10c55e8f40b04071d7e825882f19827f1cec72e3fa145b1d55591d608ace3687d7f9a0ff14f03c210d1e23bd1e7b475c1a0da74baa6774c67a46ccd6576972e6638bd6df17508dfd5dee54fcff26d20c2ee402cc4edac2c00d61d5fe255a1444f398c2428908d386a0309207e788757b88a0cb1f9a967980f8d0a770743aaf99875e4136830292c454deba4bede22360b3e33088249a3a9214a0f00a513bcf3d92b42e367de85da578fea53026aef2da181b17abf4fd014805dd99a3598339994f974382c621f1efd3cc1052d4a29ae1677ca41de1fb7427718a9e1faa2734c9a128fca39730ded316b5919be13d30eef11e0ad1945716b2d12ebe240efe85a1d21284c3f268250ca8290a6f86d8d8258d9d49c0fe73985cf3533a49fdae2073cee9aaebe5524e5359a0a8b108ef06be12437a6e351f2f0adf953e26e308872c136de58337543cfadcfafed3ea27682b1e8d81d7e1bbcc240e3b303f1967eece32a097f2ef8be1fa25c81b9ab52368930f003809a0ff87d5d13748deac501937e5a3cfbf0023a43b0221ca4213a0fce302dde1dfbbec63554a2fb5f8c7c134effe875a6d2ef74d76831d2d5f3e06cedf9141fa6bda867c64bae24e7cda7642bbfbde96244e6068807c581395ba0d8b5173900f9bbe1541eb5769f1c005c73cf1bf5704e4595943b629662b52b138bceeb17ac2b680e9617eb427d0943d5dd739e7113f34e57ac0d8edfcc30fb08b982681239d64581b8bd3fec88ee0b1e8916de43a0091d0d8a263434b3f2f5a5d66163d144516db906de01f0b2f30b2e08d75971adcf85cf4f14cb4e8b2a6ba064b43acd1bd252e9e082ad45fde6ad3b52269945c370f76c9b41ca1ae862c030c54640a141857c3733c45bc71bc5d311535efbea29d0deb556b48e7c9ac3232ec7aee209269becbbd44906842319ea1c7a3cb5d077aa6b997aaf4648f1a7e2ab60d6f6497ba728b24cc2fe17ea2bfac8b1c256b09f95957b82301f4ddbffc10c903233edf5e3f1bdc7d97f1d8c834b4ce8fa1a5ebe96da5a5daa0320a0b8c8dad5a4a67701f12582f58373c42a87c24a430f7f1b6dce0420e5a059617495a11eea1178aa2b3061d392b1c3bd61461d0ed564271379a054789a01e7df97b794b159d5d77183363740b7e8884bfcac70cf0dab04c00111ebc04490b1560bbeb0769361008f566ea81ba03c7642d2700cc5fc63210eb1143e0b0c0b9cea37a25cfd7cd7aa35a61b9f76241d44e9f2a54c38ee7804d0d69014c3caeb123b0a53f1a12120bc34f674c82646703f08540fa3dc44017e319816de8bc242b03a3e433273ffbbcc9473542fbe793f789e9ccddb173e4d7e9f14adee199100b310014996d1f3dfb14915bc2a6e64a60b29be9d07b602d50d6807f02ffe8598aa216931f9fba2a685c92e8ff296558edb07ae48e1aa563c1a305815fd30014c3deeba825e44bb5bfc3ee8f4fe3ca7a70008461388f847f3d1fe4e7f18a5d3af9f94383c9bae07073698c2755e0acaa13f6b7ffb1b12b3fe59bf87848b1251f9e0e1f7bac863c615c9c2cef147c4972b1a658a4d4bb8bb1c843317928862b4576aea7de2f8dee9846dc16d08c19829c249e88810ca4a5fd8f1926008ff5fbfb609bd3f8358ec510976cea954d71d3ead794291632fce19f029761812e43c27ac8c99681d777d51e2874b9c5f428858d37155cd14aacc5875b475317a0f8c3d9dc3c5edccd26b48398587c1e292d191b18d193afd0912feab205597cdb553b58d1ce6e04620d74d62962869325c1a8f0bb35946dc692758b0f5fbeff84a10841e071bfe2f1aed3c5cc183404fdd78346496b97ae11502eae63c48dff6890688f2eec9f89c2b209296c8bf8ff282d6ba71a0290c58b427ff6f201ad90879b8055446366adb94384e4098fa12ec8ecdb795c509395ca701ac85a685600c1b6e8c7f2cc484afebb6efc0f354ed5126ff6db6f0954ee15e0b7c03188ea4313e07f5aeb8c9892ef3f1304512288872c0969a7c4bc5703240e472e8861cc1d2cd8e6399804dfc9ff7dc98f88e199e20b709771a803cd4338b1480c2a573f2092bcf65c8b993c2d98600d80f155616ea0e6be1a010572ad2e39a2c971d72fb326dbf7cfbdc60fe64fa3ff01f8da1e0270131be924363cf1cd1f22d8e26ce98f2300a6b440b74f5cd3edc5b5ab40eb52a5c9e1183a02cbd27dcbbd8436d6db18c4536144b7fefe45644f1837dcc6ac9ba5916117386d07be0f21c4fbb96afc99d8bc4419cad98811d9f916169ac39db16d635cc9866ded4d5c41d8df193251cc03f99e268c9f2adc354fb07002c4b76595e8a3c5586709331fa9eb5a1c5b910697f57741c0d255af2914c0e2430a47225071bc7c549bb4f536e0641f4e29d61b3c1e34c86929f7d7ac10b5973b8e00af1472288504e572effa8f6b9c415a7cecbf4695a1d6a416297c7043ae770ddeb3338fd5f13a25c538ca67f9c6e5aa34511b553ab9098a11474118ce7a6c984dec83b24ee98c62e38750f56879b0ece76fc0a9b75af982f492424a9bddee20e006a266257fe3629caccdd0d120e5222b2e9fe2da715f42a5edf0370e1d657087d4f8a127dccf32b867c124f208120563f0dd09514062b6f3d87f2188e74e9b670e4f158bcdace9c39e08edf9bb7aead1c55658ccdb1093fd3df4ad1da635af6b47caae356bdf6980ccfb0420f5b862ec4aecd91c530ed08b02bd6c7ff07f9e9eb91308ff357aceb9ddf56170e3fc196322dd326fd21ff41865678214a177288dc5c91dda6c083a7270f389aa7fe8d571d5d99c483146e5f4580015524aa9eb4f547fd414aabc077bbf6fead77fda191c5483ad2d3469612e713e3e175149c205384b3f5498b4f73a7c529aa061791514294a153cacf59ee3d1e8c0baba839eb080d556c7ba90d6e0dbebdfd65ca78eced8d65bd092055d44d1ba07ee1c59d512e9bb597293723bcf884ec2b703cffab5461231be0aa455f1f98b8523814827edd379437ae8049130e036ef6f80fbbf0ddb3320bb1428fd1c5949293e86286e2f8734d7f7a64ea4f91bce2d9d5191e29e3b26190c63e59541cddbd630552387d6bbe5c7daacb46136eb0c97c20023d5491a8fcb93ac198e326960c555c869895f03d5d2fd6b1d22d8cefdfc6a64bc1c52e5d9b970596979a47954436a580855dcf0f576489ca36bb90ebef30ee97d0c9240fafe8196741c2399c663e88d62135c8a5477e45ceea14837d3d77e68a9a124386bb0585242c692301cae40f01adc2c2a84068647178a3298536b93c8b38e4b3d47752e5a66b4c0d3dda75fe997a279c74eff449134b382b47a3f3bd0e709abc6121cb0f75369f938100187d36cc60f3385d7a70ddbec011a3533d9f2146fe2def40cb5ae675a88fd67dab40628871b36229d3356576b664666fa0892437d6450c988e99e70b1aacb5c7e92aa2945743e9f8e032d6a6c8fea8c2a823e0fcfa83c3b3fad3fc610a2b81cc6342002dd7aa6aa7c6e255caa37c065a55cef9009052650eb0d5649bd9b6b15b5bcfd5fe8115e09ac28580934a0c0570a0570b2f1082ce46af4ac0418c7ed74183ce2fb3a0cac9c0d3e8cf8cc74618c59a8a30596376d8771bf2ddcc0a093e29e973ef3b37a7568fdb355a44fd329eb12729888819f52e9a6af62cbb25a76e11de4379d1857e6ad6878df538b121220582361969f4c64485817bb583c524d5fa70a9487a2fe8db58dbcc9a1593ebd6ff99848759c79c343009d95dc69573b58635862e839492590a4c222df1f8cd22bc854cc1cb3b66598bf636c16e83b7547c19892881c140c05146af28eeee4e79d45511ff9c56dd509243944bcdb2cb3e7a83c14921d3a28a9fbb8c8acc0f500ad7ad35e4121afebf7939a0778169268de0ad3bbfe75335bc36b1d9d684e30dfd26b10f41589c18c3d0805c9ecf77e8a66520672d28ac62dc0cc2b2b8b6f09c690e62d0b91e2107137fbc8ffb8115d813c4ec337dd568ac9baccde9efa7ce3b6cc749fdd2f24a80daafcc2827bd04077bc2da04787c02e6e8e662d38217ef345e056269d8f17aba22166c61f5133431708c3728c79c9d898f874e03c5246926419cc0a5245f9c3203b041ab5dfc4381ca369e7d04fbe310081a3d280ba028f7301190b1f044cbc3eb83157aebd88d9b43f00f51cec55ab46a73482a8f14dce80ed39af80b38d8f06ff60ec6bca4f02f8521e759246c20048742a2ec6032f8a13286e5dc469c0e7360e1a133dc3272c79d8783e2356df2b8bbba0664a94b6d2fb5d501deefecb181d4251d9515041bf564657f857df4ca2714babf30917b223fca1dbcf3ce933f3858662777677147b1369970968e698d24243847110f6732a9002340244ea0b96cb7e11e8270478d8b8322f17082d6d3e92b7ebeafb20333fce77da822c67ad7f707fb0d0092c6090e7671df12089ab4cea7e57c735fbd170eb1390f45958e98da02e55d93f62edb00f2e19a1dd1c48ceef44f330330856099cdfd44a869d18fc1412768a7d2c79ecfefa02c0660f1f3c104e40e6df3bdccd7a830a09e11b1d7cc621a09874a6e9a12103e20c5af88467bd408c510c32b4a813de8dd2cb08c5f7205b9ec90fe0e37e212cc43eab7298d7f828170d300fd448df92e3c86d471221095612b0e8942be580c23889781fda641390d32ab7829f65f3107af6971b5a064a7adc58cf42be9266ee21ff009c85ef15ce07b1496542e2b49b0236a740b091082f21c29645e5bf2616d983b033b2b76114f54dd0aa920c9d68dadd0dac336900f95569a8b064069cc5f4b25c4204cc5afbd9b1fab7269d346e415170a69a5721216e5dfc8b0656c6bfae9d18047f4790b72de1b3f91e4b99353c08d9a90674457729d3c3c83bc6bdea64dbd8d023569fe30b7970af04e5613b9004b6b1592f5d7b6fdee7244d1648ad60e1cade6182cdcae3a7b2a0dfc5ae9d815a61e75f6cb69723061c0f519e8bc065288bd9aa27e065266cc9e98b930906a022e24b14fa35ae5ebf22254acb4faf4e795d02e39b51c0017bfab684abb33c719409112277d10f522e31174dfd5b06c97aea490212667c8f39407508988b0b78fe6accbe2a2f055eee893e182f40b3f7d525914652342948331f2e53a0bcbad8b77f89528ff8c1119a22df98699819ed1c7ddedd04ac2c2e95a7502625a0f31b8405b58ae690b8f2a752ae149e32f00c34ebac6a3df2c0f96409c39d6e47c641c8e942b288708f7ac4c516c69a96af2c5d4e650f8dcf1fdf060b2bb0ef1295128d5a6eb5494dbf78096058d147086386c6a81bc275d9f286032576e5c312d151af62fd8e69b1fb4bc76aa699b5e14142eff64c2fb3f9e3decd86eaf4eb9593bc651c37c7f678b2033dbe1efffbbe430cbfc21f089b946c66aa0e5cce9d1b4f2c4eaf94685418d8577ad37c2dbf9d85aa855d077de7f94fe573f82f0cc2651b2971e342cce9a178b3b4fdbed3c6e42ddda70908688115d4f9ea70253e03d1e239ba7fe49273fc3edeba73972327dc01705576b1a3d3b8c9edaef97146d9118d196e408a96f934965e4266cc2805b4f77557576567946ac12ec0ce5debff9889ac8f1d6d90bfb80a15f9fb1fbab9eb302cec9d96a2ac566b1a46ad57f9c465cc498898b6ebb259089e7ad1a14aaf422f388fa0e6d4a6db3c27b0aebfbffd87ee75291d768bb32b20708c9b5f019e4f8d27170027c7e48325a05110b312ca9274b664c84b1a343e7ff8c83003ac3f8437ed3f0b515958efdbf02e54b8ac3844d41dd44fae1bfcc186a84589271cf91c707dd8fadcec6531e0f5d75ee69d63c324ff0342117d5bb10d0595250412b175cc0618999dfa86ce31b401ea184c064c67c66832058e186cec39c253e3e686889fe9bf0a863e131fbf6529e08869cb7abdbd8999c9df98b0616b8afe3fd8e714afc8fcf2bd941f6e7a1b82afeae204f6364e68bb8ffb13299e218e2e8ad6b18c64ad0c9a9799c870006cf757a4240ca4568c71d1ae9ad5415e21deef6c3504e8e8aaa9dc68d744471a789d939a5eb8a3bc0d8d3dc3ca087b0d30309772caf87b29233a60f24e9bccea5b9eff34367f14514fc0b3f78fba98f3c8a3b13725cb8b05ef8074d9a7e557153d8885e3fbc26f402c71ceaa4dd42b54790ba983f4d8478f784628191bcb12ecf45c391065c53959e6da1159a2457065c101e3071e1df8453c63c639c4c0edcb116889f249c2156c9179091b9bc26a5dcb1c71cf3946f15f175048fd41d7a756c85122a912cc7594636c1fd7b9adeb0b94009f3520e9a6142ebeb1160825e85112c82e210d4a834826b7b4db25fa26cda3dcd79c5163bcbfc1efc044f1fc8b6b40a313fbcf45200bd25013e1a654cf764aeceba1d9a2c01a79a6de5af84c2e55370eb2e15a87a392a17e0ba983ebd0faff136a77d99b723ecb935b4efb787e66ac65fc0b2beaba2368df891e4c3a4b7c2fe8f7ec6a608ca638f089f95c26d6f60561e1a3b245453be3a58761e85114ed8e725c18d0c8ed535c6e5c1af26008892248d0ccb7b0c7806ad6b0478486ef8a996072650b9647fd466ccdd725a714a447874ffa57b338e72f49ff8be1a3a004d9fcea039cb6ac3130b0562f36bab64c7847a664319ff9ab6e89f70e31deebd887af11d40cd31553ccb3e1a4173137f9230e50ce873f6c9c2edf71c145814b71d6e60659ac0ff5da601015e5eb838d8893289d1b7516e559187b12d580d13ebe8066d047a21553cd95c73cc8e8df004ef43e0f6db1eaf2ca7cb0ad2d03d38fe7783f09874ce2beb5de7a425bc4a2c23cc334f5562fa8c009b0e2808051e43f76af0451458b199c2d43441023f9f8cd1a2d337c184719162e5a80ee1e469e14f06e2f86b242c76c64f199f61a4b407be136a436d4330fc13abf363d92f98fa86a4cb28b16fcde6ee35b5c38911b45565f8cfa0981dd3b2b3d7821b739f49a96e52c1daa4b63639b1eff5fd4a4b6ac70f0e8219e43fce7c005fe3254c77d509963f9f2886209135710f192595ff03445c95d1f4f634ff80536d286098e55ebdec72692337d8078ca536db91b9cc0f5761c17e2530b5a46b4b612fd89ce25400f0c6c509f72b09678193a879e8b9d8c58c3e7f3b83fb911562486c6753ad828eb740342a5fddcd92f49ace9874c800ea72bd7f66c9dfb826eb120bdba72c9fead5fa0adec9b33fd5298eff041d208b94c5ed40645f1546f02d594ec3a7ce4c6495f85f180fe5eb8cf6a023c8384d2a358aafd126e6fd84d14a89bda0d228177df42fcd0c2dd01e1edd2b280b2aa243d9dbc48d543a436d487e34a53e3790e7fac9882e7e15f77435485efa65f35807b8260cb5a8f733a233d2d70aedb4ed05c23a19e265a492ec2d06612be05209b761cb0d30bfef4b8c31e1cbada752039f9c361baf751cb817e51020288c198841ee4922f0c1e57802fd7fec2e0813b64ee5096e92e06f6f21a250c687020b4d9b215a6f337a23a29705d2e0e9787bf20ec44feec3527aa9f69de989b454b51069da8391ff4deff6c1fdf6634a57d1148a3a7a9778adeac3c4a5fb036b9a4dbf507f45ec7ff40ae0380e848dd7b11e07ddcdc0bdcd6cd9dd67336e78332b75f0067802bf03dc10889221b025cb33186b6feacf88ea9e6f4e732d4661499994909fd8b2a591edd6424c077d894dac721917c81c6683bef68929c09787622b9323073d2127217d5a47c22a6c6b02d45e12512af6c195defd6d440397f6e4ed3fbad7af57dee253d330039c2f2c7d124d2838a39f3a9e5d5265b4f77ca61c969a2b144df534d5512e15411b3e15eb8ef0b32ddea1dc4914ab2ea3ad8e9e299b9b700a8f3bd422da95fd130bf5d7cb3141c042ab601b8a448d22bf96265564a25443a996da06221a2af6bb20c3bce71615c9f1cd6373ca12a2249c7da59cba2e6bf453e6c0083f6231f41c06b9bcb0c3a08c9285b898b2801ae6b90854dfe9be302768f520153e75f881833a8c4fd5fd627d5a46308d37634da261fc639ed6d34825a039988d6ca3eb5028471e346b5cf1daea53dd0a235f8600f88f11dc5f73e406b7811ec23b2fdbe52b8197ea05831f73b7d6b2b3a26668e25084ced3603497c2dd835ceb88b4b30e84ee6d3e0bad096ec0587523b002f9e8f18fc9341fb4b32a7a40f81262b54ded7d0d52c25227928c4579ae2d92edb470ecaabe94cd0e4e76933ad8cd817392c646c9ab45edd24d96fadec1c883727746a9098ef420336131712f579536b5c6ba76d2ca0ae4d2c60a936e99705f2d1e90403f0f8a23c653e0cb3835c6460f036bc028bec530e6d8f2808e3e01a8f2ec0d4296b65bd9c98b5246dfe9a2d74b990e9a49fc47e3c31553e809512f2c3d5e1a9decbc377338c71494793eb6d4cecce6c54d162dd9a00f2edee6a02149965724b3a11c2b5ece31b1e91b10047ab03e1cf16ff005ecb2278a05ed7464d07234f22ab7baec21349188eadc92888816fc6ef1206c10819d192faace854c0a59dde79e7481d2723955c5909b2924038f24ed1b55bfd2d6ddb6e256ffad58ddff825949506f9935316108b221d6ebd457d8a91842055f30909396cfa1844f921e15d2aa7c8c1e0a658e1a667d6d3f23a6f2b74643e93b48ceb65160511703e9773e4fdc8751650bbfdb6aea7433dd89979aaed059ad78e0701612433d78eb2bfda370a5580f731f883a4a9a8994dd5b7cccb81ca6bd19f3e01ac851949c58a1b36bc4399892c7b9d8ce1b818f93f00840e05a11e02df15e8f7e0f6be6ba9eddb5c286a70d66773762dc65a32c1812a2e263e7282b3770105704022494973bd562b2594e8902edca5b424cdd79aeb1d49f447c057f3f2743d5a646493b1e5ba20a3255ef6016173e0e0c502519a562045b24ab535f6ba81f25496c45857f8c182b1e3714c718bb5f605ad24d21da803b09fa38d610c9d85d40470fb6d6dcd1601d190d830c6db9cbddc656aa221c66c1b4680a29c9eac8c23c98cc84211078c3e9a035c8a752681ae4534a87d3ce2c1139a1d514026950e9cf3f2c93212f463c5348afd51811c2098042c4cab49b8c039a8be850381692806ed7eeaa71f12efa0d0c743ac95ed43fc1ba21ba58538d1be5a69b55a33b90e2b0ef273eec0db0cb5523833c9ea3bde3ac495ea8dfefb842075048b65a4a27f815c3c7e61a984556e2c981d394724702f5210ce51e716c55d8dd5cb2c1e4838f4385cd1c62c1e7abe9f96cde42b562c7d13fa635575778a47e73784d1c98284695d5dcd908ee7256f7baeff26d8a1383f482afab04d46d7bbec479aac53b8c479a82cf617ce856653b4080dbe118fdc03da6e1eb6089943e8bc80b145b1e7f06fc56436266bd6e9802098b51e155138aacdba834b24d104c46dd1964f7b11b73ba51a3b7b6087c01dfc677ff3d2052f9cdaec41929347519a7db8d2590f800fd2354c0db458958e81521cceae5539d8c02d189e226e9718020c04eb25bead0b8fa4cb4bcc2b3b4852c3545a34bea388ad347159c3f38beccd4912313ebbeaecd8e27cbfeefaa3a012e4196161cc33e646d78bff0ee66147322f118719e888e234b0092bfb5e18c8a9e8f2d8f33eb44d08337b51c33ce9cceac0ed6664d0452be07cdecc846d38f5fb95c2106d5dbb41439959b1b0604e6c8b65f700ef2ec29ad8237a76b3004ce0bc064e40e71cf7bb62b4636099f556380e61051d9a7971e5b075a68d1b41f7b84721d78ae6ec462fe7896b3fe7d1caea38450fddc568d4b81a142e565fa409dce678fde3ceb13e4bf91654746e250d4c619cfd64e77b78c94c1a1bfebf29111cefb43056c991d7b3a62bca56b3a9cad42f48184f961b6b30c24cb50f5f821877687e09167e193b41262853c31419890ac53cab3cc43258ad8b8b624508efcec98b1a90f7b2edf53600b75d1741df381286c02ac66e71c37bcc75bd4c521b1e707a1232e1191ed4eacfb354b2dcba9bff6a67c7bfdb211715493819577b9fb34d77671dab4aba43290987a22951134ad9f0583ecd760498bc562110a5310ae83c977bdd0a50c8fe2e36c7be290fc3db2ed2700955b56574010248ee32bfea6b43209f6ec684f0b9cab24cde060bc70740ae610335dd29ff06aae0a9fd98b9eddc89f2482190d47c637906e6f7237414f7106f4be4476a6e707c0c1875963e71a087554deffb12357141904ee97c4f0886eb1f872012e5668bc11fd515a2ccaddf0b402c74a8d372b9cbadc1c6b220f14e80e7149e985773bab2824d6111e8e65873c8cbc961916b6004a574388557ef48b6604ac67d72ba9628acc5530a726d75d6293b913fe7fb0238da293dbfd241081cea28e937b04d237071307bf19ee33ec1bf5e91ad1c3dd68d5d5e83e1088f4199e296f69453325a2d88c3b023e11636346b627ab02fb3a014e6dee0a9c9401ec289f10170ed995930912b553e7ce99262578953a23383e174bde227f63ae9ec2973de5883a230a4886c89b2fd32b8327a5a9f764b442ab50951c9f48867a4d3bac6100a85096c80b080403e2df351a6c656dc88d9315522d10f5cb8f22ef865f6534b114172e9560e2f8888b8e6bb81295cd686f8fd55c41299873ea825a6ef7e491825b1e58a8f356e87dc10a6d4046a8d0d7f1a304950198d45109ac199201e9a5be78ac3651f132870304d52960c0b5c349cc1438d4e234c40bcf830956e731e8c5b3bbd3cee5456010949bb103e3030dffa55b5c8009fb8878f2b0d6803305fb899b7b644343e23026cbeefe63f440ad3640f3b9439dfc5141a3dbfc0913e917828421779bd9c58a59920c400de019725af3cc8bc91339e79bf376cfb04cc31a4bb5bd51476fc0c921caf6f35dc5115a4a31a4e047a921c730122e14cc85905948491f6673301897baaf52f36e21a9b6cb9b71f505a792db74930fa51226a465af3b708cd12482c9eb163721c63909fe97c0d2dd56a684a4a390f5282f52d630c6aed1723294ea45e30bc866beea4acce1a9f9277a45070106c43934cb4f5243e8051c89e4eed61353f0f9a0c04bc8caf4c78058b04d1f700d81ad8de1764167f608494c0c18978e4e0cd9c05ba2d8709d80a9ba3645a7e4720688cb7928063fb5e2c0d692a0e54d8850398262c4357b625fede9d63732dfdebe9867e4ba097de97af15f49544065177b1dfa682a71a387675baf505fb2fc1ce94275d2b14dfbdedbd849e065f9c02ca1832376a8ed2f42c06789f3d6f6ba868db29703b15a9db5534184b0484119fd390b6bf95af105dfe87f69f70a1e8bf072a6683bb755bb934bfd81f8cbbea1dab971f50224200388f8dc402e22eacb625cc05f5bd8e635022e0a092899d7844b4bb4b21a026932113001c6492d812470aef2c6d5d7a547b020538d2b69147e1319a527ba26ce8d80e40e71317ca5b830ee0b9202fb90ec8537bb5581561b3c9650ca347da253e793ac66e0c9b150f43a2f149201cf85a3bd681f43cee746db3df7da8dc2edbcb3f9327ff62d6f1bb6d3e1a90e5b8c6236b0a603961d8a2016292a0caf1fca81740f2b7f75452f30a0a81b8dca9cc0ae44add3ec14cd998ade906b16b77f38b63d3a67835744c919ddbe20f42cf605a9e817c9dca01391d4ab187c56e848f97b4939593038aa784863984bd2c777c33b173247dfe5467ee2f2a95fb87f5f44ccad546d065f020c89cbaca5d5e4b333f1571fc5633cd8f52bee1722422c7544253b818b6cc074551c900370fc19f43cf585327f6be536a641262eb75fec04a17b0c58047c313e5dc08d939cd83b4b6399c6eb8dad15b057079c7a06775906d949f91687c2b575b7d6f5f218abc1663ff1a51ccbab6de95c4187dd2938ec22cfe7d8225a15a7403990d66a269a6af507d472ce03e9e6b18a54431448de3d04cc71c14bd8cd9409fbf510ff78790cb03e9f533f50dbfe1dcabe4b4c483c8cf132b44778cf49f26b664158dca9c568aa7e2292256982fa69414fc420beacacc292a95591db1c9d5435dde4b7dc96ff7fcb5d7f22a50d8f46a378389734016461e61ece058534d2222e5b489b2c28ec80d7b7e18b3582990e82884258001a136b1d22e091a4f0ee7a9d15569c207fd51e6e20e3907a62b47efcf8e3b4cffbfb1832ec485fcf44a16e559163e1d23617cbbeb10a45e5edc48ae4f543d9090b1834c34abd5228fad07ab9fff2d116fd7c17d9046a1a60a0cd1bfde28c936990372f08212e781b49d9039f9174be1f973a32c4e120691e795f168b92e4b7e272cc602ea38327a5a304c61b53989c58f799d0c0e0faf22e45190a5b49dc6a1d625e0652686cb5c0c7d9c03b5d82330b2e32d4030be6a6cafa44d152c14180847054e84820065cda496c8d3230d60753513a37db5cb35d182d7dfa3df429b4899a40c96070f082e0766880f619a20b83b44081d82ec521bbf08538488a2f0ad4942ba2d094edbfaba451419f1095fc48fbff0e7496e44647433baf1a410e41dfe72e009c2fded10ff6311ada828c4873fbf5d28264f4a3d09ca932c192457ba2158f619766d2ce6362673c4b74fd16963f149d49da29438b5f117850041100443585b33c3aeda9be1cf6d22d3c66f9ae8c60fe24a59c7934e10ae2fcb93424fb28fe25bce958f638fdf9f1cca932678db3fe1237cbb608fc9c7753a3cf6b94992097978fc7789277df8228cf1d0e3d9e357806ba2ff128febd82c7b759473f836e6f213be8db69c26513b3505f96944ed9ce1718733d6cca876cecaa2da59d676daac9dbafcda59ce529c6f5fd3ec97a6b6d257ba3781a9d3e4f04deb75e3d7524cad6a0ea69e721bfe20534b7530b54e4399fac96df87f4ced24337593dbf00b99da83a999dc86ff832966b94ddcc247f8c52a3fc2e88c4bfc3d5de9341bbf9b8d7f668aab29528130452233dce336fc3433e4721bfe12a638858ff01f99f853e05bd8254af9a0de69d6c46437cdb41b84a9f79069f7ccb707d36e21bb3b98770799777330ef2e4ddf31d33750d626cd708f26d09119e8fe31ed0c3fb4d0fd322d99749730c71ccee270b9a7a727371b5b8cab7439863fb761dfa009fe19fe46aed1376e85e69835fac62d15cac72fa2f826569111230e96982d3438ac22091b1a8ac03065061a70f8c35fc8e5014a09224939c3b7f0e747f8b59e85bf1b54096e4b6648917d863f99275912a5c0476859c5b00273c52ac67ae604ac7dda954ad799137a57db68f420449b3b3cdea8a0048512c294b0e629ea4dca02f8d65a8b8ba094a7bdea00df4e24d064aa593fb29f575b3b4120da5e3b95ce99056b2278086ea32a5b74a0828507ac328983044af889d055f3c0c19a076ebb698bfb1ddc57719fc5fd1a95d27e05534afb368c806fe0a38052d2f011cd6b1848954342ca1a08ee0d1b8323e56310a41c8a535a54cb8034237a235a0bfd7673e028ee35fe8ce66b7c6dfe9821bc5e1f804db3b516afdace75eead91816cff01e850144d8750d2c8f64f4163d684a96cffdbd0d00d70ddfe493d14457164a7d7d5f617801351107285ed8f82545114a58104cff60f0094d7151ab63f062f1445d11c16cdb4fd2f88d1056cdafe48562f1cdbdf026dc6836efb57f09ba365fb9ff0a128aa036666fb9be8a128dae3452c6bfb0320cd5868d8fe2574288ada70c234b6ff518aa2288f1ea338046cb2fd49fc5014753a02d3b2fd29f0a128ea430a7966fb8fe8a128eab4c2e86c7fa31545511cbc91ea86ed5fa4a228fa84054bb77f0d47d62ab34c6d7f131cad6cffffa128daa344511e706259aeb6bf883c435f59e26cff1079455154aa041059f46cff09f28c084c4b8fed4f9467aa5eb2fd693e14456f0cedb4162cdb1f04eea128da34b4825ac46cffa11b435ed66cff998ea7b5fd3f0ca511b5e8d9fe1e7056217cb1fd857e288aa6705e33b6bfcc87a2e88efb82d863fb77f01e9ed792ed1fe42b8aa24fe516aaedcfc15514456fcc68e82d69b67ff92347d09638db3f964a6da961fb035dd584ed0fb3114504b2fdc91445d11c577e906cfff1a2b32a8d65fbffd810c56cff178eab1facedaff39aa0d585ed2fded8d230b67f68e327e6d8fe20d2ac069aaf0e45d11b434c1acbf6f71444d34bccf6bf6509c24c4e79774dbbed46e2fc659e34b4fd6d88429bed240566b89600eef726617c44bf264b19d66f6f4ee38ee83ff18b38bfccf0c50e88e03bebefb02d8c838ca2fa55782dff00438c2f2d3ff8e287262d83b55c0a47c2b6fc38f0459b9be1c01f33688622f8187c9cd338f0fd5a180776b598e906a54548ab33bb295da34e061a4b9fa830fe9ec040a5098b3e277252244ba8dc00a34eb842c5e995b4a2a9933e548290413add939dd1e703a582e4e521d501b16243840a94d72f0bdd32870a16ad75590b10181a5d40f287d26083ba67a562f5c2ab88b2598afdd85c31e3c10234fc758999033b01f6bea440eb972c54f6c0c254468e181a4646972a2f622156305d020a0343499514d603d11e9e3a799caa38e110652306e8c7a64f951ea3aaf3526508a851a63bbd3031821c014ac330515d6290428af8f9c884c91293638da960aaf4783981678035d461e191b2a30a160cd4812a0c3d4daa6895413d7506fa65489518c65bf5c34be2c0a670488113933d71c10efab260d2b5ce0b258088fd7abd5f183a3b22b00fbadfae6b6d72b5534bf487b5b6c0b4db6912650a63c390307cb0c2d8d074ebac59e784d97979a1546dc870f991e152c50bfa998172c5646a97a6c34ffd81e942060c971760baec762a843d1878903d3959705ededb89a99923315e3d334676bd3aebee0591c36ae60a941a6787e7f5e343bb4cf5ace8d8f5293fac5ab0d61f3d1a3aab6c563e3982449c5042af471a29fde3f106caca92133d2d2e5144d4ce0d98cfce932b3fa1ee0894962a71ede1325aeec07465806429f38425a54aeea57360f8e64059b9fa218166dd9a1c6ba4585913d4e325a93164caca16a8fa96a82c5cb1f21383502b335396cc287132e3a467650698cf55335050335e5e693b49ae63b2b8fc3746ebce3a264e94315a28939ea94e18b542d342cfaaf7646506aa297bce78286521b5afaf5c7844d6ec13c5be4496ecd3ae1ef669abb0cb66f7cbbb44b54ee9426f58272a419038144b05cb073eecc33eec3369341ad1041384082142c49bd934b15f33e8a6faa9d4cda65eddb6bbaeebbaaee99aa6699a5eabdec5f26dadebbaae6b9aa6698a732ae24db3562b2a321a91478cc07e4770f000df40dd96fd71e5df6fbda9cd36cbf7e94e5d755dd775cd6b51adc8c868c4080a282061cb361bf66b2b91748a729d597d2fff3cb0d9fe67b39fde2a7f33cb75739f7f6208e65fce3f9c7f4646d79f02290a966c7f125324c86bdac86b1ea925728912d86f090d44d3e0e562e31a18dbb60d8a1aafb807f6c6daa94bb007ea6cfb04c1de098e00da165b6c61af2b298091def324a197068e40c94159da20b6e53dd97a6266df10dbf29e4411b12def89136d5b9eca07948a6dcb535fd822b6e5a96372a862d944dbf25421e26c5b9e3ac3890b591719da96e7a4b72dcfc9bacfcc73126417008e7e916af610d54f93243bc4b6bc264d3c263c2677b69a4c32f942db96c74409886d794c7000c1c8f1270644d30068e307dab8769620850bdad1da27ea80ad956ec3f82db6165b5992f537d6262d21b36dbc1f3f285da2d07064007d602ce53022d5e6cc963a3aa440d9b1945b53aae0e68d53112d310c19b5eeff083d7c68fdb8a1c48ace004d49f6fdec379c91d48f2ccec893dbecf6d7a5079a40c98a22841783066e8332328ce1e211430e8b4cca2e75b9bd0c31339526c90e1a5e7025520b303860efb80fbc616a4e0a679ec849b284c8951b76e840b1a460858a0f900d6e6aecf4204923058b9b13b25ee843278f962724b9861ba844e9d284478e9d3e67c8e0e8aa91a686902b3edea5810e35bc3d2c1ce1d28252931974f6f4518247891e2e180d5461a0cc4026059e8e061a1e18363488e4bcf4e1f3eab3cb13030d4c685670f244043b17ec3411f2232523f2b9a5a00aa131a6851c5242392d36ec18b32463863c2417942a43ba84474756983725b0a0ba51edd8a0c347cf807d31745c6c6c39b9c1e65962ead36381c7025428833ef2940a89015da304e1012506a82d60b4cc8c31480088d49a1c8e1856cec4e498e0a3890d1e43f4cc10dba324830d9023768abcd0d5b4802168b46e5465edd070613d575db2b4682c6561010912f5898d3d4650d0a3fbc00b797649d85ce9a304e7d9412faec4a981c99e364d38fbd603229e385578c0ac2908794203777e0aa51c1553d7993a582618c1dd47ba7c2c990dd8c1eabe5954d0d3654b1b2653948a34ad3193828e1a5dcae0eecfac2c98771b8c2c210c43ca8f4b6c4832b325204c7240c048532e8981c5d07234c64081ba602921974c0012c375471767eb49d52f0344563729d488e3630d53950f5551258c784986790c8d557dfaccc6a52cb07149499078e7c58e25ad5a172d3bc4bb44063a9ba185c38baa9810a1d19ba431724688151bd8cc888acd5081f295185113ccd05304036d46ee45130fe29d18363a7479628278474618a318738648fc82f1ab41aba969852b15d8c127090b6564a063e6051ad997177382dc05183366a38c26b4ab3563ce496d4619a31a1f988608c978f2f005069f204ca62a0618302e6876d89249c145f3f2dc3096d896cc102c9bc3b6648624d9e7cc470014f4c2438ce825470d286a48de14144819d1876d7978aaf478219d947ac4b1618a173a63d4e0107f2a5a90f1650f9b3e3c2021d663df7240bcb34fdb46c0551e1b51b4a8f8ace0ecec2ba74a579e1e2dd0b0410b97012976d8a07af8b8f025012fbc98b1848f9116e47c09abc008d9f24d5941862e4c706729c2b04d6429c3030cd31c1b7170f6ed06c0f007b0558e17b6e2c84be92b94767f3ef252fab6bc24b91daec8be45b8fb8619add119bbe2873510b5197400e8efde5a25fe51b5277e1e016cca717c0b5b8180144ad8933013015825d0f823698e3f5ed8eb0d833d90693788da0c647b7c306733f03dfe6bac6dadd2f6c087991ef60802a9f604f817f4294f10dd3fe8388ed864cdda13632dfc1faeadfff51ae86dddf6faf031ad01fac3308cc1c1375c06b14170806ded090b7b80c55d742c350fc9d6ceb6766a18075a07d65a80293eca6f410ddf6cddb6e6842a4cb67047a6d695002f9cb0bc8821f3bb34e8aca0832125630ae7e6afc18da1a8496c7a972d79b85e24360b30038c16eefe6ea02137926e4ed003874d17564f0d56a6702494088223496cda352a6851716e165de14618894d17fe864f0a707024fc8841a1a9e80a4742072c1cae8930d851c31523b1f9fa71152609ce4dcba50d6e04140e9b2e2e9c150a8a23012351c281c46628f5dbe1c38d412436c315507831851b33f60bb31d3c842a0d45509c9bd60b131c097e71960bc2b8d0c3e5cf79c482c385cb4a2f255c4c09d7e1957042af84fb806b340ef087f89570fa95704ab8f2957041af8493bd12cec32be19470f63f98764e69ceca2d5907f3a1a4406a52c64c141db4c047fe25d694ef7fd50f40e4287fcc1142d895b95b8194f2d6aa004086f2bc4f4c3b250c6536af0e1f4d3129ef9320a4741dac61b44627896efc2fdd7e49ed44aa3abf8d715676e3b62eec42884e695fa84d695f05b6a63f688ae0b529a5ecca909c1265cab0967d19cb6d2088944ee519feb83c4936c33f757eb036fee9e199d5deb3f1e752944bcafbb21f5fce9344b81498cbe1dbd1e307d3b02abc0ad3846196dfdc9da96b8f8a90ca6fb7cecdba6ea4fc76d384507ebb577e84577c0b618fdf0060e2f183597e3bf1f841377eabe0f1835d218a6f163c7ef009df901e3bf9ed82c71f36f90d83c70faaf8168047f1f82d9843da27982b013e9529ac50982df011fe00981ee023fc189897ca8ff05f60de2abf3bd302f3aaf8087f05e66df223fc274c00c0bc527e84bf8429e2adca153fddddee3aed2e14baf167aeac991bcf585ffb1f58c093ec078000dbbbbccd003f03ec9e71b0274216af84bb9f9ed6fa364d8b612d9f22601aae41c07160cd621d762dc368afe374dbc74e595d51aeb015f9b10529bd76ca664430d8858140340dc2edefdb6b2705f68e6adbddb6b595244992ec6d24bd750fe73420a841321cc3525fadb50581f4b5800213caf363ba768290413795d4ed4a52b65f10942f52afc86e1bb53886e09847ec770cc10f0d11bd1a4a0f53e5198bf576ecb7af88ab7d5fc49527f9fbdc16cbaaa1b4e7dd9ab600bc633e7cbbb1ad55c676185429ef054eb15f8996b9d82fc625a2978994f8c8aeb877bf3db2af758994e50d12d2c66a810f9a3133c8a0d2c0d91e94122e19603c695205c93e0b6c1fc97e0a2eb41b25be37042b2eed46e93f922190019a946ca0df5b25b82d17291f9b167e7e70db17ef25c7b7e2b5f80133a258ac4614012520ea0b3d3cbe3051c302cefa51f9319343ed24776c8ba675b169fa479b1108e4c6f80510559e331c9e220099d9dac211b49ee11951074898b9b54af2c77f3df976bffc453ef9fa4752fc2b661c92b56b6d200edfc5d79f10dfc3c79a7cbd6a44e1e3d7abf0d9ebb0d681fbafad55deabc13547e09704e0b53617efe90245affbe3d349d8e2e7fb27f467d88ad75f2dbb1be420811a2452ecfed820be8b567ccf2fae00b75b0c14be0adf59b4f662a0b06641705b23fc63b4462af0b3904929ef9f4adbbacf6a4b1a3f0b1327520d9f642c4989c465e3478154c40763fc4829fc5ef0c568952eb616dbd8bdf7c6624018871cfc31ce3309d77d862b26e87838a979b3a3078e17aa00b9a2068f1a3d53422c613ee244cac53a25a6284d2b9ae7776587528c2c53388a3c95c9c2b2810268e30ba8d199bf915a612a47560a2500915a75dbff81ac329c92e099928294295a098ffc630c677431a1cf6882e64226460cb75104ec62230968b43d9cb1596802478bcc13115e0bb813694a1130c976725bde14de141b7540f0158afaf57abdb4183ab8ae29af2dc59081c245668aefba0840149e1f8e840f3edc385ae1481871638d4978b7d5faf5faf9f9f1e7e7e7e7e70441b65f9fb7ce4fc334fc79e35a1653fe3ecbf7b7b9bb97315f4b34bbb2f28ef75ebff6defc17ffbdf7cb59c6eac881df6c15282b94ddbe9f813abc2853971745b7efadb32fad85c54779c4663647f3f15108024f79e67d5b6ca4a5f2e98310cd7f963821aad2be85dda92025a57d1042374afbf649739c990cf04f7a51826f2ff9f7de8bdf92a1f92020ed35d42e6a2ec6276b2ec87fd54e25dd6eb1c3578141e062fb5bd21d04a41dd69099466b74ea1819e310d44126948584b05f21215208f47d00b366e0d610b867fb83007fb44ca361bf34d0973e39413da552ba300dadc2aaf02ab40ad7304dd8739b876bc815ee09bb42aef027328968f813a7442971893825ea4429a22aea442c318de846c4127b6296e8137b8e3348dec72f6cd2cbda7aa8cd208d1ba47bed3a82ea0e5cadc01e964ea7d3e97461aaa538e8f3f97c2995ae2aafb6a77103dbb9a696333083a1b8aeebbaea344dd3f405fa7ca00ff4891849180c0828162b39640e1cb05f0eb20da2600e4c9f401d38a5b14adf6ceb7f36ae704d41354dd334dd812b6805f6402c1206145bd7755dcb344dd3f4833ac86442421e3c7c98e5d90cfb9d75e8652cdfd68f4ba7d3e974baf0b782e8baaeeb0ae6c0147c0275e05407994ea7d3e9843cacebbaaefee66c0804081a8d88688210394408ec3744368376d64d657567cb563f2e54d485bfdcfbfd32d6d68f6b08844ea7d3e968e12ffc4d104284887fd3ac15e5a222ecb788c3fe61ae9ccb4f62afd7eb893d1d3e72dbcf74659eca6adee5355b8510a1d3e9743ab3565464643462040524320912d82f09525b95bd1996d8c33f9bed7f362b4b8db94a74ef59eed3fca4355ad3aa188a3d50ec6523239dd34cba49e734aa9d74aa51b7f9c7364e718a6f1a4db1d5c63d8c857d784ba3f8a6cb99aa51add56c026d15f886d3355dd3355d29c0a9104c42bf80607b029cda13fe384db5ef4472bda7343e91f2befdd8bd37ebc61fa2b77dfb620866fbd87f484f54adb5d65a6badb5d65a6badb5d65a6badb5d65a6badb5d65a6ba3a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2ac8d8a8a8a8ab2362a2a2acadaa8a8286ba3a2a2301e329a6e23b7b5a0ad9d2ef6bd42466b445e9cc150cca288fd8a98c46028ea577ebdb0df574886faf533929924b15ff287fc216140b1329725f65b92402587a00eb22c9361bfb21fd79e2eae1fc804a2bf0e289387dc87593a948786b0df217427856aa756ad2adec259b80edec27bf00ffbd22727a8a7544a979a21c8b7caafb63fb6ca39a7d9fe60ee85390cb1df30af455be5e81a28c4388ee38feb7cca555fddeab75af5b07c5845bd87a2288a3a966fcb7fcef552555555551445511415c18103070e23643f7db94a7496fb74b5ea61f9d6755dd7354dd3344db14f555555557d4af5ddea561afb54555555f5853c146d95233aacd7eaf62e966f6b5dd7754dd3344dd39f8fcb51cf79fa24a6699aa629f6611f0eaf5f0987ff03fffb1cf8d75c30b1350eeeeb9a8bd75f17f7dd5f0987bf45072a5858539b17f8cac7dfa203152c1c88665f84bb69e073a0efa6d92f0193fc25f0d75f0226618d03f1ef9740bfffcba4d91a0dac41c05f3f07febac6c17df14b20d690b0518e12098c1ac58b3fe79c7588712d877fe69c33066dedfc804490d25a9c33061d6b51e3238c31b6d662077d3c328ef6832d82ef0e5a533441986dfbe0db1a0e9f06eeec38fc138777abc0e40ef39f38e70f901bfcf1c424789e25185ed80a2b92d83cc18db17e91d83c1d481bc139875a7b2e8086adc09fdf5e117f075e04c31063ac01aea1a82121bd604e4a133631a5d1ff98452210c439bf2c2c35bedd1ce23084ad087f4212d4b157eefdd0b0550548f1396fe036ff0ca240ca6058a53461b38121884269f41f8a9948a6f508aef7558002aaf68f167764b739ae01e08492c7679f796b9b010d1b5b4055de325a8333f0f0fc542961dbf278592393f2675b1eaf0d8f5726eb04f4882a63dbf278eb0b8aa7f2a644f1155a5df2784cfb9cd1d1b3b2e46a0275e8448de4c20d1d5c6b74f0c85909e239d2e4709323ab9c09f9e194e554877795ded8b1dbb1fa91dda72e1d7095e38d9183020d63d4ec13e98718a41a25b92d6f8c96a63151e68c81a252ea6d79639cfa8c9191a60cb7e58d411d20864bb62d8f08179e1835cf78de7dfd4ffc77e6e669c9ec7a5b84fb72335b7c947f0caf9933de2376775cc65a6b6f17987736d31a63c7a05b6bed4df251de17d98461a85f76367474c100b67d33e39cc18c6f6a45f2c60bb54730eccd83d9db8e4a1ddbf5adb17d035cdb6003249b4d458a221bf895bdf22d00686f308a64381ba2dd9d6b17bdfaf151b88b8ae88ba2afaed1bd76e66d6fe6701dcc203b0e63f0b567a6bb2fc9190451d81321ae2181b593dc20e8a0e313049206bee79208348d4edbe70fc19d419d1466ed201886b59901bac85194e90fdf1fc4d63ac9b7b5d9ab70d1eab3745b58b30e82423bd794b6d661dbb7f49efddbe5b7991fdd77a6ed7eba6e5391beb3a7ab3ffe64647bd3c672742edf26f00b5028f2d07a867e6d11fd8cab3282acc0656948956ac59560b0c0864d0d17ee4ce9e36ecd9cc101e7e7c2963d5170e7552d60420d3eca700913478753b262260d8fce12a7a52ddc79b74e34318149d695b58522b8f3fef689ad9f1b28415680410ccebbb459b22225eac75b42669f469b7cfb65934f5afd361946cb26c5d0b011a08413f9cdab8c36cfea84fda3994acbc548ba4faf029366bffe46428e9a279c7e6b57e8f20b1e9df428f8854adba48ca2e88b1f8ae2b657f9d1fdeba50bc5c67f4d283d1dc7e8f2de5ed661a9512a3b802c0db6225f2f6d367e109a0993d95010f6628567e39fc1566099ccfd3ec1d225743fa0a93a61e3f720a24a4d1fae283c1d6694a4b4ac676a7052a78707a763a867dc662074d57409b3f1cb602bf06ce3244f55b45c69e3a34a8a2b6d159123544c9cb4783cd160c1b431c618638c3bc05660cf77441a3303b0575b9cb6f3b6acb0fdcbd9bab4fd7f5db3fd6d281cd9fe489687828fc785ca765e971256b84c5605cdcf4d2ab316391b7f0cb602739527791f0c8a7d121921609f28b6535929a9e06cffd9142f8b9bed5a8e6c4f8162a9a1002bdc430c58e0ac702b51e14d1a33172c423050860e93a7262a3876b8d27a890105831e1c3a750ec842631e6094c058e0db0cac152129cf99c5ea604694f36bd88a7c7b1be317a98878579250b0fd43bd77494a524696b2db6bb3f16799ec0784c79b3736943182e294d29c992954a913346170fe98053ebaaf616caf5264fbb8dddd3d694c79ce66332bbb8db14c76c54cc6a48c2c65b7828dadd0d06bca939c11f176bd0c9ec8686faeb4bcddba2d6fa7ee73bcb3ef9bd896b763f2cfe36fdfd956e9d3b292e8076bdfa7599126da6f616f63ce1e5dd2de7eb0b4146b91b4aa776ebbafd533e579811b365edab8460b7b3f5dfb7631fd98798f7674f27c57d5201925fea98140eefcdbf36a55b5fe60e19bb6e24361df0ff3db170bdf2cceb7b57f7e5ab5273028a2c729bfdd26eaa852a5f124cbab02a533dae738b5efd81bb148dc39fa9aa652d569e763fd6105a477b13ce97436fbfe3d41a67d825bf6fd7b8a7bb693ed44bfb8ba2b85cae80ac53eafce4dd65d3ab1cfdbb5cb2fffc5f5836a156bdf17b9342a72895c2297c8a5519dd3a9c8a5755777d5bbbbba3b056e41425281b4923f9ea1bac31db85a6d90c9934ef009cc813930772d2e7dd2812a9b23b087d55ad0292d0ef6167b607be304603fd6682d7016d60256a3f9cf6d176bdfb43c1d4befccd3755b876f7a372bd5b7e9f0cde2a6d4ddaa557c74417005ad808420c2ef87cde003bee29536820bcbe5e3033fda45996cd676d3666dd429d7941b3ad2464612de0e15a6ec9d2a223ea87435e9d9e169ead4e449b4fbe436a87b5f6badeff8fb37fab7d28b247266c48931c38b2c383b7543093e186cf4aec01870f7ed335e30564b7c42f01fc1df830f3cf0a45ba359b779f62fea2a3df8c06680b10e4d6aa2eabe28f998c0b3dd843d724f8005f6f63704d88cc5d8ddd4b4dd84d35da7f870e75181f2983bb6265e6cdf12c2081e0499a8a8946c76672d0c91b211000000002317002028100c0744921c85712892d6f814000a58923e64583695c8a3d15010c2280aa3200a611884100300320629a58c328901af7673563030c2f6b076330d324136a376ba9b9304684af80ce0f103a650f70f95e22564701e2664850f830cb688415634633fd57b2eee3515ec04789af8ccfdd3804ec1b0d4cf0d6ab81bb4d058930027f2c593c422857224cd21e9b7f9b3ea989b2ded11b102e6893169e9cc544da87b485ecaa1513937be55046e12ab36a1acca56ba782d4c4cb8e1655b630711a43308ff1c84fab41bb597163235b29eefca09c712028961555003151cf3ca4c90bc591b6ee9c40b4a3824f61d61c921fc85ec5b45a42c3547d36ad9de822bd57af288e2d62273da847b2bcfc455c4e7e4cd5e4b0c4dcca61ddd2c081e3bec9a328928f1119a0d339bf8000d960a58889eca166b360242c18532e263d0acddc801b433a0c6b238d9dcbf35850e16280e0bafa2d34bba69552560d10412e4d1dafa1049c80631c751615c21bd10d0cb08e6e8bc1095326abe0df23431c94f8a87e45faef0a33a7d9cd519975d3ffccaf666a8113f249e889dfd3c36bafd3ea16abac94bc79dd0576062206190edfa2a404a58cf3ca9a601bc0102b250076983d23dc4a34508ae39f6e38c63c3651ebe1f205c9c7581e8ffb142a39712a7d826a06120d25116be90fcdb22d69da1a4f6eb1d5c966b74f24350867059aa168d1d2cfb5d91b1872a926107a3fa258df44b17e71c035b8cfa05f837c774a1707a835c3ac7b1445866e8d4a594ffb83f341f611630171e50b2cc01dd686cba916514678c5e6560eab089590fda0903b96c8436c9a004c0856646650a935e3a477186803f155cbb052f2a827d9cd337d3ad58d2611736325d151b9fb188156c2ea49ddb027afb69c9ff283c4e6fd168607c385e36a5bb79b919e612573b6418b450f7540f90efb0b2aaddf444c562f00c2cfc0843f68c905603fdef5a8ec062f3cdb2457dc0fa6807dc06de588f986dc0573bf943c53c3e4686ad62fc8b06b857f05f2754df1d211d8384cf25e13a5c279343f583ed275946c8570feed57c789c2ca2484e306642c5749541e0edce16799d1a6b4c8581573dfa98d0a8961a9d57e6e6e1387fad4a81ed1848ac4a3c105e31f686f03adae7a3dac2ad2298aab7823fa073806be845bb93c9e4ec0257c0beb96dc5d54036922cd5bb9fafa0f70a40ee6b4bfb61f94a699ead97e783c8a4a62ee09a932c7410fc5ad880ca902949260bd9bd800855d04bb632499393b35d12b03f15d0418dd5326287abd2dd238c763dda5d714fe19984ca996284a5691065abee69940f504c4d119ba3433aad9ddd2cc887f54c3ed17525d3403c46b8b1e79d991dc38e80ad1586aaab48351102fec2bac620424638cd3ceb30bec919651a6f2d10c86cba92994f0ced44fa71d5c9a1130b642e8136733b604819614e7372f8b8a3ead549bfbee38f83ede79757e3d15805f08228117ad3953f18d71dd6bd68e4c0e14be6b483d1043a1bd49c31c07c33fb1f2f225f083fbf154bd8f4d7ba60452042ff6bf00a62c4944c341c122c4d4d4388b6619b4a5e1c3f04f30ec82a9dcb63194eca31255c563022988b42174109316d07a6e68f219caafd07e56b1ed11ddba1f234d3a29b31bae08f9c371e013cfd2dce73e41a7fc79b552703f17790ba1cfc8f3c67890ca4914fce5bee283c66e73ebe14e5bbe879470c0a0ccccf77e8ed0586ae41b97b487d009c4437ccb80da946f5cc879f1e80625233f39fe1724b5df828b606864df9c6334220bcac5bbf931df973409d026dc05ae24fac144cb5c342c114768603a4d85b566bc796f36927ccdd846f3544dd050142c098c1ab40b1d6eba265b9890458d9ef40975253870d6c0300f8b8355a05e448b0ff79bb1958b099e982b50a4ba1e5e910956fa9015e882497abf2e43eac1ec588efe2c6d64c915eb132899086cb0339619e8ad0e821bae267e79a284eefc3e70b7aff3b41f07d16bc8149f1340cd72da77ce93952e35f4665003e97c08682f87b42536e729e28b7af1d7b70c9e05d583dd82cd4b02a6407f8f4b0ca22e2dc18fc42799c189e7e52f912e12fa9d0aea620e8023c900a833186250a6fa82615252bf0e24cea1c7345b4da26f863c269fd174bf3f95c1185ab0182e87b26ef6d8d7cef79f043f1c9047aee35ec41208361db52b709e696ad768f90a7112286563121d007f01278d18b88502011373c66f4537aea02077576ebdab3f11039f099343c2f7ff764df96bced34937675e7a713f640464654464e077ed3d91b3bce01f0b309fea23bb04dad7d3c3297aba80c12c5f30329ab8d4d152122413a7ba70087a88d890fd286f298f8a00060cb27ae859448bce52aa0681435e2abd5329d508c11ed075537744d2b21d527f310e43e40cf8794701eeac7d94467eabb3e7ff7009ab418571852d60a54aac8460791c96d94d98126a9a44457751a883d305c00cffcfc44443e4f2a9b7b5e85c827be0b5cb69dc11e4535a1dd6242166c5f290b63e6846320951bca5a270e9bc9d7b2e6b918bcd3945b3651cfe6f7c802b78e8e74bcb984f11314d31d56b2a00395510b880df99fd51a7d986218ef16ccb8033d7ad6301582f822c74b92492e990ade9ee78209d619e2a140948464f3c82a1e1774004b1ce11a20f83fb14663c7ae70e66ba7749a02d8a424956f3a5d99094d770ec41801fc113690f21eb03ab6a04898b87c517d5c08fbb6fc9acc145274ff4ac530b2f4d3c2aace493c87ab860ae1a0458f8a2f3ec562ce83114970f6212c08da54976f018e62b28107410bb312f3e2b48b444e32bcd591246708fea89cb5fdfb4d6a76ee7fd58dd3047a4021da8e40d1a27d86ce5f8096a3d49033ccfcb627efb896106c2249879e6375bf051d0f264f9bd3f5239eea72641a928f2aea770bc6a574e7155c30510dfd9129b2ff174e330fdda1b193117bd5366dfbcb600b8c664e810bbd2e58cdac90d63389c5af93f3d6e452dde42af0167b19f82316e3a5a7bffeeb724de2cdd3ff2341ae45c7f57e35edd2e695fd5b735ae8a19ad9aee1c06567b2320f926b0b463e4cc953ba1e2c0f23592080e66a387254e499e750a32c0200a84f354c33dcf777b114ae8a35de93eed8e378aba20c535d5fe4507ea73339169074f84c4270c7eae51d3ac8f42371aeeb4ac66e4022514520d1937770b21fa63bb01306504793936ee50441d8afd0f572dfd1a6bf5c95fd8fad8c7b19304e37dda57f3e8c0716207f3ee548e0ab714cfe6dec63c35f013d15672f93b5d94aaaf389dd7605e958eb09c76dcd4fc0fee8679c4fe35eef478fcdeb0003cd5f03339fcf7b69daab971da7aaf3da894058077d4922a6f9246d4efea9879bcfee9084075e60bb59a761900043b65187cc9bc561f8120c00437d4afc882598895a2c0835ac29ae007c51a5b79bf2cbdcb316052db5fef39e179ece3f6533298f8ba41fa5981b5fa4e986c5419443181ad7c2c3362043210f29877c74efdf571b86c5a17c97cf6c62195bb6687cf0098a9b3d66333f7403c0ce3f71e8c3c7c537dc54f3280c586b1b4151c875261bea7a46db9bcd8eedcd5037ec140a327d79926afb8819125117f0fbd011745fb9a1d719b800bcff3bd52ed4d9155c668ec132a12f3613ec843a6d19de06c64d55570fc68764640df1323b4337186063f46c4d91aa8a4295f5b73af841e66ee5d585555400f78076e76cf3c0a3f57aecb93aef4a5f27c4b2522ddae410725e0dadbfb01f8c362b50a809816f5d7084f0f1e0363aeeaa0cbf423e9ec3a8d2a34bfd07a9ce289f9e948719a04e8131aca29f61e9bbe75852a1ffe8515cb569f06971af2942d4682dcfd90481a4ecb5d51ef55d4a8338364cf8a53b9820d848da0da9498b6888dd270e7f6dcd16c8a601d3110b198e82e1a08527241e2289bf706c21d6ff693b9d0542960c6a85a3ea2deda488c44ea0b2a0620acdceb3ee0529dbbfcd5ba8e74e6ae139e9ee27ca9ec99d317aef6330ab33fd3d2bb9cbd1b354bd41dd3f593d09534fb1be5ff9987fe37c78946f8520d00f5c0fe87fdcbb6d11c6a751c4f75a8f9ea824fbdd6b69d6024ab19dd889911fe4be2a7d8e361ca8655140b01cfddfcdedae423fcd6c843086b61b020f2f0f662127f40d1526c3b39c8cc17ae9002466e1e13766bb029f1560abddd7f92575d697d85ab91ecb34c64ed6a09d987017d66827484c52c619e2b62674f67a511d80c1ab9179faa0d9dcb1cbaebe3127c4aee7e1562a5915c1e8189855adfaed7ce4f93649cf0e4a7a2e92cb942289c4b4481ea04751ca9a21848b15267dcacec11a9bf960afd30c53d808e3039d7e114807b5803fb36c059562362f614fefc6a97ddd87522d87198c20cd3c0ab98df8b69291de94e8c7b8d8f164fa0d5ae5d27ed12e530fde7517f319b4ec7344496f4edac324f63cc4e5b88f689c038cbe3622938d6fc1c6875824fac87b51d961f1a0e2162b01e98c1671b4af027e4cf09b82d6c412087e681acc5e20c42279191e39a024126c1a32cfabf82d58b3dcc3726fca5864dbe2ce05b9c57f2b14ac192ae22ab47f240abb6297dd02c34486e4f1ae3f18ba6194359ed925b316684806e6f4a4c89c5d5bafe2618251650eaeaa74d3d9ba6d5dd95461691dea287b33ff75f2953150061281e514374823b40fdfbb9efb019915bc011f98ccd4b00b1ab34610bf07f8b67ae38b92671d0fe7705d3e1244e4030f5d97b379a5600f4d6d5966c53752cd51f83b0633cb508fe9595afa33070244dba4e656c1624bd57430b0c07ff281c484bf2f544d25583d40b0f065a78158228c8e5c63c8b89e91f3311e62b9e796abffa9a8c5aa0dd2485570ab4852941d3b301fa312ec400a20a3a0a1c6ca86be27afaec883e4c620f47c9a9b667e1d839776790ebef81b8226687f4b81d10c84bc44ba941e839c30c8752f65f948468c2263897c5f716ef60d31aea0694cb152b518f1f38d9e363eb4370c54cec1bfef3abdc29cf8f5dc1daa30a3e1783879cc4b9dd39c58e6a2a788868dfb829220a1e1699fd5bcb1fe10b43fbedcbdd2a2ef9adedf498300392bd354c6ef1b587aacd4501808e308dfd9b0e50487f92537aa1269f056d4370f4181c8cfa5f98bd0ff3b1bc56b3eaa0543201dd4d03d630a5aa02f7fa6121268f8296d326a34c330e841c65fea35a0f1d49c27950e78453c13cbb563afb8ac287d2dc5978c4a8b471143f9f2fc99eb60eb39f220542f1a2b4b3b0a807893d86ab35276efecfd96df727375239909272e1d352c15416ba8c1b4a143192fb57104d2bd4fb05b311971b9cbbf3cf9d50e1106628e5b007f3832b7ba300891d9de5ca1968b9c7f9db39bd4ff2b51d054436cf4b89e5d2b1f4aed7ce2f10998c4cab03c51b42a3d716521230f1100f0d914b42014ef796669b73c486a04d98247cca0817ac5dae5b64c93172f6c2b9c2ef6de962fab4873e2b641a714d4a7ee7bfa0558eee87718d5f27bf794559957304022c0992940d84a7aba99b898f023aae30ab0b1538a4d95d2a2dedf1ecc621ffd8ab90be424fc2d121da63cea8a74c0ac927a5df4d36a38e054381095a0f10bdeb95a4b36a267ccd2e06b184dbcfffd2b2611e085ab33167089175ddac06f37c1d871cd460ed6b9683869efdd1482a95cb2bb6668304052c64ff9bf7ba5d102cb6ff09ba82df828120bbd28221089d0137b582e3771f62e8b8cc978f7dfc54368c15d661475530ded50008d1456ea26317b93f0b49aa653a6e5d58c282bd9ce0dc16a596d02966c5856149f8a65de45f381a0172fc13c1959fcb532934c5625463e4e457f9ee4a9faa6f5046c3a802dac71b2fb550ab665547bd9549fce3a498d324f232d1a76564700c97deff80fc669b165c1a00526ef5b593b970ed661c0f687ceb93a9a683421ea1cff828d004cbffb457aab8583e71022a19256011298cce5323430024391c0e415465fbfb13110612880f895327b611c6bf6bc06997e88aefe730e8152086bc0ced2045ee9f78ddaafba496977e2837a1394f126ae162248c3580e6fdfa6ca24968f319df4c111cb5f0c3a01cff0ae8928e6b7dee4a500a1f66fdc8b2d196eda6e3e6f310bbcecd142ad019100ea14abda0cac0fb4acec566026d77beb77c61b20875974540cd112d87e1a034cc69f4a1f4ba8ba6f5ccebb53579daeaa6438968fe82418a15ca20d527516600d77eca800faa6aeeb72e09aeb44407a3f969297e7a9117c8bea70e75655cb49fb77b3295cefbb124c62184e1d2e109c0013d2112877d4c9a5c376a9344fa2a0f83562018830e1c2a3404eb3b4604afa8c6493898d0d96a812b198304072368e89378198ac4d3ef7d2f31a157b6a04039e34f8009cc19f2dc9ffc04493774a83e10b3c1ff8a26a86b02f419f4fb3e0003cced74475d6064db2904a196000b044e118f8a6c07b5a273e51918f375c54920498e5282598e3a7189cf4b4807c46e407110535d8a54398d62bca35cc1cc66930a1eaaa6883bcb27b0511f65d757bc73b50fe9344624ef1bd0e7419beee6f08951e6d82b52407d74a38cad30db912bfd7c5942f5cc697e04edec337b86def3ec42b22bac75e2c1e4557a1cac08b2001d40e40404daa3a7b30f153f7dd0bec58e01ae5a7851f2894bb4845280cff70c77cb52009cff5aba04375160e1811838267de297f934f819ac4442585fe1ee9a4e16f4a62d99ca2fda924048e662bb7023a67bcdefb03d038c64c5f918e2e3f9e2bed73224142d4a8623dbdd1f2c38ea9a8341e4a227702d3ffc818277c8a3aa91f12c1c5197d8204886fe557402303adc0c70460cb2a0178fc9e31230d54e8251cad2398529f683b999a5ca8bee1ccfc4a1ce2c10ae65ebc39cf1d913ef1011ac3222815da8a055dab5688467d1b9c50ccc57a8ebabe2f8d45b644e6befda3356a2a324dd68d052640a840a425d32c5981e143923cd03429faebdbcc399e1ffd7d329e81508715786ac21213364dfd4a44aff97cfc11dd69689609ac8d52a92ba13c143cfe7b51bcfad78a48efbeabf5f94316fb9df37a326ad38ee155a048bad30b880bc1519abdbccfcab72ea6cc6e4d1f0d75b4d8572abe7bb4da8cd8378530774bae6c6bb5c30c9158caf56feee6772e9ed5223aaed4a0372782a4353e5780c32ce5e29cbfff652a4402e0ce88060f0815b8628161c04303c3f2046e4d9f1d30079178dce7f46cbf710e12ed3f39cfd4cfb45143bb5121390d1483b5546edb5200248a0295d0c243750c68e9bd4dd52a86a833d30013ae1c20338c452d3a990228824c1f4d288bdb8f0fb403ee493a2502d2ac749e1997355e6c670bd89fc4f66a3c5b033687e3ff0511965d4e27c0695d4d710487b9e586af0a6ee35c6f689e4ac01457a1fb59dba8c293ad7d953d1456be27d5704dd73e84ddd2620c655cefffd2cab87d106952fe9362fae2788842fad2c9c7c9f31e4bec230635ebe355de17963306bbd7fd810a7c343f89972e00586912c8c4efb5175ffeb2a48c4e677e9b84d9a73efbab812a23d1c4ba7c7c036ffe48a4140f22554bb52cf8959669c1f0c6c1c01ff10c77c6028e2f0e0eac58865842ca6f89c12342d934b626067c39ed828f689dfa6d6e5b8723a66b312d695d35c4803ceafcd8dcf6100de6f61523085aaae9c325694aa26a431d2bbc6943beca5eb819df0746fc10d40e514352e020e0477b6811304a2fa6b530b8a7206f1896bed0bf6013528a4c684a9ae63064a2c0d6ea8c9f2d90fbe311fa738a05ee280417e826856a5d5a846372d90ad1deb2c408413d7016ff341fdc4f0bdfc07f3dff6cb5fe11d146aeefabab18a57f464f92120ee0625f0fb6d5008c7c413efd1ff30fcad20e42c8a191c2dfcfa77e82876bac4a973c2edccbaaa99a9da6feb97935b4fe7d8a37fad1d19ba1505bc73fefcf6940ebc97f17535ec4cd7811e6131010dcfd905b18795389856451dd46c02ef80ed0e603ac612c59a6103161c69b1af31165ef717358f280b9bfcba5953923230f466bfcf265a2f28728ec515d547bc0c0676d23423623e119a24ba561c20927320bd0c780913754e772af2c51f63b575bd4d92c3c935a930e195bedc4d2d182e7e178ad2a8fbf4698c71e0c593d8a6d97f7540439fb2ddb9374fddfd677a3abd47c2bfc3b9788c01ed046e9990cde562c2c2c320331858054ca04f9406c1083819783bba9dac78e1d9903b62abcb3bfcb79be2da018c0240ad5871dc3943877025bbc80b01ebb25c5eccb29c8bedc5b6e2966dd9c513f25c72ced22c4f7a5e5fa803a5a8a956782665c13882217cbf6f453012ce4c5bc74a81d4371716267dcb8c7741d421816794109f7ca45e7ff0f20e2a1246fe7f14dd1b62cf9c138afe5440e79da1e06023c87f4c090f17d436d9c4059722cb0be64969d820fdbe9ba9bc26af21f4da3cae9fa4adf00704f0a439d5985d83b33400eac2cd77a6b0726a13e34daa58180e127a76c5b315702408d76b4cb2c469be91d4fe83a705d627003163422810e205c213a40ae22cb9e7382d29153a74bd8bd5eeaf01f0d0b7a1aaef274f85b95b46e6e20fc85993b6d29e689fd34815253e9d9fcbfaf37c3880f12139fc408f68765703c595788ba2cc72a2c6a112dfbb819f2060dd2e419de3b681fbe6c78e622cd9e8f1581309b7e4bda2806ac10558ddf6e1966cd6e6c201ea0940ccd9781981030fabbc3c0db137f83b78aab2274827db274fbc26a944bd2e427bb88d476af9541e1bb0ad0c71dbd4b9af7057bce609df0bbae1b30d040674115f713aeb02fa01b286f075909dc3d0b1992e8b884fa0cf1814164ad593ee6dd03f58141f65e658fee0b973518440da9efc3f7a55d23128993b9fe081c3c9a8d6160270c66bc4df56876669e301953e253eb9f86d8e5c7974c2d60b7e2b0e2fdccda253d1858f942ce06c079225a828c11058751ff0a9d158b0a786c996264884e702b11ec56ff67bcfd4607af19684f3ce3cda6c69ebaf94f1403a5cb61b00dd508b9152bdf3d4f830efc2d02b6500106caee61eb580bef25a64420e5c82f52f42de075a4bd9d2d2cfd8065c4fc058199791ebd85323cb1b0d1a3fbd2fc7b902b1ab449c788063f25fa3dfa1dece2aadb517e61f00c3c444e675591456e992abef43593be8342d6f6166b6e84ba2b57af398c6fe3d5cbe353e5cbd7e4d1227a3c085d96832a4c9dc01159106553282aa3998a2aacaf425ecc4363fd56269850f1e55891e94caefc71582fe869fa5e78ad19266f1257a8368f6505296f52f9aa120d2ad51d41145778d0f880612988cca37f75f2014197104750ea8f352e1af45ea11b686b20d788fd55e1fb63332f00d8cf8dfe031eaff5e825aa94a5796d744e8d221ca8e62801340c7da12073bbcd0e94a1c4f3876799e73ee3e01e5c05374046a9e72f1e645f1dc6b93d03fb907ef83ee99307cfd96f5d336e5f57f5648cb2f361424808e80043ef26ac06323fb459f25001b0d96e1c4ebcb12171a0127ea4171a96b375e0d1e13a17f1a41cda2bf78197c59d1a2e8d951a7998a579db9221b1e88fa80d467a3a3fe0fc85fb90a3a784f5b53ce0e09fbb91e1693799ee8ce72d2707ee30c9ecd33e57951ee3d41cd9ca7e84d77ecee58e4b0372062ab7d99f3cfddb6ef196548e067c082bd408940201ff47a89d4438411f21aa1a2e8aef2b519a0c2a8bac3a66d02289399d62a7d2ca6090090be58a4f6cf4c32c29c25e63cd917b188cd5c720780c889def9fd2c1527eda0540b6393c75feb68929285248f10afbc16b62cd0ccf68a907e6e4eb18c089e5ccd91afa7224d4d4f15e63ca4baa20c2da07483b50d867a6116809a347201043ed76ba111beebd4311509131ceddc41dcbec5132d32b1a5deda77eea81182697efe7bc4cc5ae8bb9e23ace1cc750b5b31a4feda7265ba5ce6cb354f64d29cf05457de7ab3066cee831914838d27f59cb5382c10db495a1fbe3bd628e61ce5090efe5418d9208ff587feda431c68c76fc7c94518d172d60e182ff3a8008f472171695c405f081e9e89ee56d993ac6010f4d83bad0a0b18a13eb891040a29cee8007e0e147ce3082f96637f1b8bcca0a2845b92a805047bc7d6154f87ba16a067794dc0339773506c060f566ae79a3a21c867e320ddd109a8e6e88d2d82e24ed7e194c0741fcb568d13009e569b7fe0ace5d7600a14d936bb0c99fe09fdadab7b8a2046e58504ba728d50f7ad0e098255d95fa57881f84d3ed697de94b82014cbf603c4dfd1cf4ff00d74ebd9a17606639389f526b42a91551a0a80ab71f7f5d6392941900650a68c7f145dc05499efd9c9e269a40d3bb34998b03240040185ef1961224fe3e68e448cd41030ddc1e9372af9b1f79fb86161ed1cf5c7e8b1e59ee33a028a91f64d0e0f125850321dcb22472e4010c3586e554a4bc0a22b33cc11d8fc3bd18012dc95d3a10b4a2ec4818cf29c12f80347b3036605af69f692bd5e02ca3c5b73858850aa45b116731d199fed789bf61cc4f6cf3084f6e93d438cd36bbbb83ed56dfedcd46280dd297dfc9e68dd9430791d03d1e7e13052639d1527dd10a9ce0551c9125a0f39855546ac7ec38ec1e9835d2b8d99ddb3cf3baeeddc1467cc796241051002a314bbb5d6c436b56a13a521a9f9081a9b6e74aa5095c12599509d24b40a00486d21edf1cb6850ba6db8aa68a7a1c76010e5b54a77fbe7da47a54b48f394bea256ba18619d665d3805c1abd6dfba9e9cd574b506f47193b064727469970519c2ba947fd8a5e5725005e3917e9bf0ffc53282af5071830088f154503edae76122defffb4954ca7ed10302335a5aac1ab423aaf6d1d143f56c7987b50dae589c18246a012345ee9769ba7477c0c623588a96aeb3f85b239bbc8af6b7a2f5e9751a826a74b480b11337bf47107b3e0a4e6a87710ef21d0153064c954f3f09eb408cbc490fb158050cfd9ca08a3c1e28ec310fe399c67abf4e67a27dad57b38f2d48995d241e0060112313e8213126d6ecd36980568d59a6870c7bfcc43a3781e164ee6d8b0628401dfa942aca5601aa179c55a761665b9b728c2817827e114bd239136a4573d666cf3292821449be2598c1e352dc3bc1dedffc7d2deebf2291dfb24ce0c199fc97831d99acbc3105de8644045870fdd5c1ae88362b3213c646a701bf83a193d47e5a73ee3c9ccd76b4f3b25981c7f475049b1c1a388a7ddf3a8f32f1a48007baeaa0d8eab14a7db0ed75144dbecca7d4c154931bb9552758c79657f355507d70d9d46a30e57b5ba7e5a322547b137b159e0f555a329fb00caaf994fc860ddfda1ff3927ad62734ec19853fdaf54d1a67c274689f03c5d293172573a7578af717c7748dd1699879471b73470664e47f65970d1fc929de22c2a1a7fb81e284b5035d9346dd1ca9b611f6a816ca440dc052450d32cfc8194aa2b365767c0408ed765bcc97994147bca2fea7ffbb5097cd7b7b8de5fdfa4c328d680fd583482a76103b81b241b2ede57cf652ea4010ca34452fdac7cf39d66ed37b70c2f9174b191eca4b87c584e352086d21f012d4238c9ac51ab6a2c7695609e93054b603b388b18278bf01e7f827b8e9a77d3b3734796f86d052b587a43b919fa32cdd36806c40bd6589adad364401a4aab394d147c9e918bc69e684e13019933e26a82ea6505958b09baaf26a85c4fd0bd9ca07b558792cb0c2dd7097a2e3394b84e507add03f6547a534b74bcca1029572dd1d838e39da1a2fbab5634aeca8a94da1a9e6a5fa51189ad3322255f633476675e052dd2af9aa2712a53afc37b8fa5af6e45e2938c5ca771bf0221d2cb138b66eac6b21e5c37409a8305f5b3927a3727e3e7d0347713aac4e037eb24f4744c64cf49bf2b25561bbf939c291d316a1d75ddc42214b2db6dc70723948ecd1e24ad75fb7a56e3005888447d3734b355ab6c245e3a22453c744e9ef33404c4f580b9772b6dc955610810e901b8db355ce13f58840a811e20ebdd821d98fb2556851e152a04bac0ef77eba0692e9fe930e4e21c4241443fb8906e22a89fafb7edb76d7797e4fd2fa5da8929f6105be93afe9e72e92d3759a3c8858d5532072e577aeedcec684ff8c8992245e1fd147875df2c39b1038e3a91d1c09a2690b5b1d11542daadd141ad00aa30aa45c772db4f2926fcceb51926f57da9a96e442246780e94df8acc58c472418b81830497bc146e26aa4e238ff34f63b7a65087045d79ebb7ae51dd241d71688794fbdf7a5e29050c86c247a26407ac3455d05923d6b28392e2f6013df021f3f7c4539fb212818490c87f1abf586f8c17bae4856156ff8b7a331c50e379f91f9e91ad7e0203fe990ea008b1f7a880d5ae632424e4a0eef815c8fda7c34bde802f388da249ef85a93acd604a313e0c273b5efd812d4ea4a0052fb17c8a51a38c8c31feaee1de217e543ccd1bd29438f51430c797480bfd11fca5a69a2c485675422d3ce91428820a680176bafcc811478f948e9800a1048809bd0f96043e8d2f5b000d585b6875284f6d5947c0715d4116640ffb6d39a8aeb371bbe3d823e73702059f0cf7c345c89bfc41cc2aee52395fa9462191c92b55487ccbb9bafaa22ff3f35843043abacfc5e2c4468c32c2c6245782e55d5f134365227eb6f3966363569ae4f56abaf75ee43a486706788935676ca364ecbd19d2c4bca38eeab95f19222015b65c947217028412833169ed7e4e316c02aef6b2bbbc3c06d00461d1dd1eab5865be7f7eafcc555204e62b53f09ccdc8d6311c4b7fd8c78e20b4c4dbd2828c405e47ee1874a32676ef91a2762b0477079c6ed19e71f4fa657d39329273581a6ced37c29d623d696d6b22df092a0604dc06c740f1f94f44c664fea7c7a6d4bb102094644033ee4f5513af3dbfd5308f52104445ac480e54e807567111857eb903deb178d2d8334a7cd3088d235f95d1c401911e568ffacc42d6394fa368ddb8b11ee656ce69c8f1a4667c5efe8b32e4d334359c128d022eec02afa6a86b0eb84a0ae941da6735c03dff562daeae2cbf13f58e32a7bbcf7ea885d2581c25d32c2fe620c45d093c1a06d839303fc96b8cfecafb391cddf049518e9e72ade8b8dae4258295bdfcab04f7b6e4ef8bc5cdd51834d08c5121ae4135195aeb7bef916a8fa6114685001c6711b0b3517d3a8781879c3283d1aa7c2a63796d4290fc8fd597b11aef808ced42b1d5d32df872a64e1b6f236bed8f8f21980b932180d413bf83db6de4c888f8e2a27b12fd61994d5c9072799de8f94433293f4f39c30e73ddb00970cb0e81d26885c9d3218026ea42a1de2a199646936c801ac384e9d07c479a80264be6320f192d054e5ed40a24f93fbdc393609fba626b7d4415c62b8110dfc84bf48faae20f12743593cd54c85be78684d72fa307193491b06d356b22f839e2207089931f87edeb7eb8b8fcc7f9ae5ae001aa05ec84a166b62b662e04be89b9c52632ce593ae69f70c2109e0f84e77cab5f8302290db7a1ce809f0c3f12a323c27afb46ad158c74d26436034c8e829af52c378d4b5630f2b23062152a582f3e898c841d8e3b381d3dc7e4fda8f6fe60f154228c58734c033206130ba61bf18e70a1f61e7e96f0e62eb460528955d8764d8c5ab5f9dd1e8d1ac603b1d8f470caf88ac75fe24de98a37e538271cdd6ffdf131ef75bb8029b61795c94dd64334b7c0b08cf4dbd7158011e06cd91401e7be9b9d965a31dc618533ec13b064d13a254bb374ff9883f07a2e4b3300949d532bc4fb5a81149c70a5a557c2387d754e9f2c13ea088b4f8bf333c11011da1876681f55719f083eada573b8a4bd7dc739530e35d87fa764a2541b77a2cd847190a8981e258ce704249490088c19b3d02024c26e6f75c38f08dd2af2f8e00089a6e773386e77a34cac3c26fd117399fa23781b2585dfa3bcaa490807995c44e2710ce33dc89bf2b0fe52d070a2b23b3c92a81b91568da9b41bbd981b75ad8162d7f95c06070ca090da316204088550740b623d8f500d15bb251d7b50dfb3b96c71338199c1034a831a850d3f960c0cbbdf64b476d7354dda7b0313b22f91884d8783a08fd112c400bed11a3fb1cda4243ce15ac2b53a5e8e369766dbf01746dd2c6e71c0fe0e69b66b887775ac1673bb3799dbcbb2b3ad75d64b41bb12e916151c578398316ae62c83c61f950ea8af429b10eabbdda51f7701b63a9bda236a1a92a5f9024d703238fec44945c570d0a4c2256b69e7f56cd677de42c83ef80957087c14b2c1aa79ab6097493525312a36784f798d35cd952bd40368e00de1d638371a434e13dca8e7f7ecc07c74448d1278877114e20c9cb256ce4cd13bc6a51e7760dba88b383d01bcc3b80a71dae50175cf981304b7345f708a1d6f7538258385bb5985693979461411f854e02f47f3ad1025e00de3d638572bf6c82428555c4facc9698548632114d3b63f489bd10f6e4816de5375433ce9cf1a2b5006edd76b5719431e5a0db600a8e81f2f21cd1acf9ffda8e830c4be512de9808f07431fb311318a124b62b4df1e088e7356424235e1850b1d26d2f7309f78c487bb16ed8bca196fac3a5c8c348d4dbde31715aee0e14d2cbf9077dca22f1d219333bb2034b6a1b28861102134abbed21c907e806be77f3a81f57b0811f393665affb5e3477cb1f0a10e161a4bf5d209fb1768cfc4f6febcb81f848d4ac21666de8f6fc044d6982a7db008b7f984a94c9bf120175132e5f04d0048605ae58f4d4b587a4b8cd866638481217ca9153cdec5238dbc81e23d7891d7a7c886abed97798cbfbbbae9c83831a699447fa4c91a693180d7e93ed27afe47ef48152c1f1233a23ec8c39e654868b0d76e5e7519b9955a4a8e1493bd4d6da81211e67de8956024e8e00f7653a5a00add733b92990fc6b5d32749a8738bb574c079b406d12b7918d8747b06a1d83c4eec982b86f1cdfb4457a06bad03aa862fb412a8b79eb42fcf41236d10aa4ad192097b4d28d8e470621782f62c2115dffd1d6338f0235b1b308cc00a22c5d613a61772878f2bc1869286248ba8df22b0ba63a05de07a15c58e669c05327ddc9b9867bf285e566b892903cf2ad17a3bfe5e5406b70a29e0fd71ffd2e0634a199321a6430fab5cb75920145de877c844f98121d611888505b42429814062fde62fd38d78ed42a7dd1a94c0acefdaf1c61b36ba175d3a4719e4cff36a45b967c2948cf317c9986b07ff593e1c8627654407261ec1c0e513459af8bf472c5982397b6138a384bb48d35a6b79a5c9149423a9eaf295af9b9dcdae64a125cecf58613fabf4d87239a494cb062d5c6753b74e8d80aea527f4c67f2fe5f23f632a72cc1d8b2bc4002dd260c704454fa843539b90d01b635303e10753d8747b38a8c32a06a24313a1a9ac6c03f065ff5bc13ad2d1a6cf553dfe33c4351d1555f8ce65a933c50aeb881644d0e402e62f37345839afd1d3d4f97afa2d6f61ff7e490affe2581655e91db5195f8aefd3dfffe6612596ca9d9a11dfa383ca86351984759cda113744a0be47974e43943288f113df55a6c13ffc7549543373ecc54fa9e297685431f5bb608da3652ed86944fdbe8ddf43af646b87590335a535ff46aceb5460920ff197b572e91cb715b76103fcafa11961a79f562ca282050c9ec6ee3c801163308432bf1b1d8a5159ec3f341b8d3f41b582fa36d0d839201550f2219f2f6943e74486571051894e6454bf69938699d1da53500f59ea79f66eefe6162d99a1e8a7285eb36f44de423c959a2b717104a8238641dc0cfd06e55f5f8a6912129d40b0d774a63370f9a1827c1d146245b5a45d2b35d7a238c4a7636d492c71252102338b9508e3ad036aea28a61f9860a02eee51424567372eea4698da23a6c5b29c76688c6339cabf8843b4abe73ff7a1ad4d51880ef263d1bb5d5ac0c0fff78dd3961c5043d11163190aea13c68b98df2ca127707c374e3fef59d7ac36b74359146a68326f55d4017b9e82f9b105ea11479089450c8d94a99efb10733ff5ade1f62b3ca2c7336b4171db68e55cdf8115714df69ea6c6b9da505959734b51af822b2b2a8680d11480899280c4db13b290dc08fa9818c2a7df854096a0bb23acd0b7599ec9acfab0c5bf19b851d4b291c58776cd1aab3d2e4b652c71c47e30254c85b43e72f214307743c3b7337d9ad2c1ba6c17219c00d4d50e564c2c7b31c7eed6b58ede1f4b691ec27a2d63f998ac83f54aca1b9381a7e35a709a5c601213736e5ed4242664140d03d21252c066c862979751091f54be60563fb87c50261bb02b41ae5ca937f2b71904bac695e11ccf149231a66eeed7afd56bee1304c2c4c0868db8e08435aace174bd95d68ba6d6b961dd61a042d74fe604002dbd601eb874ea1ada0efc9a71f0bbdce6673f4d0d479325cf725f695d173cdb3175908821d46c95d69721241416219ea45f479c9a079a10ef7caaafce6b0e5550c367cc369b05084d27c40c585f85fcad256784aef4674a95f2ae65eeacc780ca88d5c59b93a1b9007c040a407e621e1f03326f54d87dd6c94e7936b93d6c83497a22b64921635917ff09b38d666a58db4b4fc0125de676a86c190992fd0472ba28a1c40c04c167ee33a723cc49d288b5a1e73a4c9accc11b7b49604e65b2b1ea7974899225134c5271662bc588f5041cca2e81605d4e3f68ba4d85822cd8b68468875d71c4c432ae674db8305cb3c448b487f7225f5c105ad8d41938852f09d45dae89fafe235c41af68d94440be6bd52baa3dad7baf4f5af48cd65dbd1091d03591a322adbe6534284107a01850c1b2290cb9b2c979a518e55bb9cbc0bb5815cc62db729e84244e8d23574dd85e8d245d1352e6bb142476054e8382a2e48c5341c6bc51799019cb8dc080094e6784bc53a4c05d1541ca31e4204890e6b30cf706c0bade5c96bfbd616082550a493f1f94598cf5545c68caa3652680782a716b4189782d66ec9a5287e35c76c8caa460cee9c82cbfb0865e34313c6d2f937220dd57e6312876842a3ad17187460b8390a2752853a92fe262414cf677a7324ce63d7b983d7e847eca33a720b8512edd6f20b5fdc196aa01ab049e7fa6673a8bdedd0732c2d754f1a9d2bcd4271068dff5f0c9497c25531bbf3b5e758f9db509bbdfd0874e376e1e8f60e21c9c6d4d4397d2e2001a2fb84d59915591cca9be99b7e7920ba5ff9fc9c3201c8f0a775cd91040452fbb8d92bf74ef469b9ab361e00197427b35ef8e6035641b8bea77f5abc77649469598e4deb3458537a28876c9c6dd369fb81878cae2436771f8dfdecc7f7e23ebeb2a360692f860dfbd17f1466c3d14fa99879537d334aaf622b6a7a82daf0c37aef36bdeca4ff0a5335d53883baa45f2be7d342a373eb61a0b3d84b9297a9cac643884c398bd0c7ea645ce097de589057a88c0be8c08f49bf5c1c7554a43f5189d60ed49c12030fb7e4a3563621d453c2791ed3137add191c6a72b091c1323ff3d8d899f09ec5d9fb15bc2964c7e8f76de93fcd7eabfe71fc9fb85f81ef25ed534faf06a78d609569ee0f026cfe5fc7208238b6e3cd197ba217c4da3ed2f5407af1923d172292c456c640b10819a3e3286e923cafbd2b8d1072bef183e4b8cc42781c1ae12ffe83f87f2d7ac636db6e51412136caae4563ea5eb47261f55b6b1c58cef7b1744718c699d1acc0be61ecda18e47298b988495b785ffefdcaacdaad207b6833ef67e18bc28c32b5b3767295e2827bc2ef713fd8bdced73e4ba29881770054ae909fb993db56b63af88ebf520b085b2507aa4dd4c87c5b9f26f0ee281317dba6ad4ffad83aa2b345b1a3057b16be3bdecacecff0c396358c4c96bd240c08bd77aec748bcf33decd8b3ff675f5ced2b7fda4996bb4079774781a4ca0cb75b3353786e2dec9fb4b2a10e2448d9f16263ff32be0acdb18a7dc0206ebbd0a7a2fbbca4d21dbe05acbdc9299436639faf57ad728b566159643df0e4b8886831e33833f1bca9437c2a2e82950a1fee0eb38040ee5c832a26af03b3da1433c02453688cfa0f977e3c599ae2c674258e4da33755bebf83d693188acd1b863798906ea159702166217000661ae0d336b1842a0522ba08ca7e8532c5b598b511b2b6ccba89a88cb405dd9e4f0e550e7e17aee3839643397861635a91a5cd22ee3584f041887921605fdeca9501cd513381603b2846d5114e93c3d550f85b50bb36e6161933c34b73f5c65aed297a7bc5208dcb016597961ce99a54fcfac136ae81644990eb764435bb5dfe8a76bbc831cf2d9863b5dd2eaa7d364cda888c22b20be3c90c17a3d08b2790f12802b7e0b7a25c3ce8450a4c254597d0061176728bb3822b39faeb0c4799116f7bce0c090ec195549a7777154aed2b4df3415158d9b54cb6bbfea441c9b900b0675385d177d2aae6e49e597189400a94a07ce6c4a9ef54bec2d0a4ade5b07db344e28f61937bd3eb44417f27532e24b0fdb41a519a7e1c5eb1681b99f065bd2dae9edbc8c7d71d6e6f11521b0ec3e10f9b35b1adfd70c5149ddd5fa37abc412f91225fe50c61ffcaa857cd105351962c14fae245b9942fc512f1c4c1cec3805dffea236f4e3c81d0e5bcfb4b5e848bc52450b5099a6478837fbe09a0ca8d274570b930fe44177404e9357b22804017dc7e1a60ef0cf3a418cb4fc04f3850d0fdf546e87454be49e46dcacd043147f0af891fb59813d3bab327f448967213ffc8191c37f826125fe890889c106772c88cc4b71b42676f64f83776e26509e5048bf99ee0438334e504bd3313134ce8d14d034422ea2ae5a6c18885481db6eef8f36308281284bf1a43276f9c1f16914fb249f4d2e51363a1f78b049b10f02ec1df4668ea0341f74c851b114cce8db46f392418c405e0913d7c05269e20e54bb1e381001293012f06fc6b04a0ccb2e9066909620edc3f719f32a8823ff45184ce14eadadb47222572c246e1a5203dd1bda51374cf00917a4f3a03ff8143445faef439a57c0dc25e82092d86f7dd827b90ad010c303aa4bb0428572c843807c7eb7f5b3084984328be651519135620cbaf1054587c3bde8539d82feb9f045707f17eaf062c23097ac437e4334237b43456ddf19268a8de0e9596ebe6e71f06e818c87fd5e6944caf8891ad4aefa1d6fc0fa8991c4c8471accbbce8fed271a4e3103a5bf355f694216708d55b5a4a1af0a2a605f34dbe1cc0a29f862f3c98223c7a5ea4db5d9358f2ebfb0327fd53a0d06693a7fcd3b1d1a78ff18f60dc4e26f2b0f8199ac6482039bbbe4f2c8598a4fea455fa94faf3689c72f8a634ec4c3e435e6a8d8b1f98d8eaf514b5c8cf0b159e4daf401a238812034d644786aa54199d770a0b7d4f355d318b516a0a7336b03a2f5e0d8f4b3b3d20a287da98bca3add289f9b0635c657d01a9866f6ae6414470e1a92bc247bfa6964d38d0bb5d60858e55347c67a76cfb7e3f5c02b3b87d3ba427592ac51c85b5240dbd0f92b2cf4273ab6c8ff1edf3cd0d23ceafb9ebc1307186977eef8b31b4649f284e0d51b53863d145c0d1d020abf49cef4f49b43ec8620c51da0c0452c00b31987861ef32f41c4e8d6287246fe2f5b4d2f57f3e51ea6724b6f89d7c7329792c0755b8a1980951219472ab4d8fcf12f140905f39250aba0ef101c6714054bf5510cceb9cae00fbdb5f24168eea8c2667e16739ceb0fd996aa88ac2f17aad8152e6b402d699b8162250fc4c0838bc612ce609daa01247629081c1326357f1713cd2d9e45b3c92a293d5d0ab740251fdad5a173f837bb7eb435e44ea7213ecacff8d14513d08f37aa8afd6009aaae0c85da92f6ace9f641b94294a4d0bc6b1aa46c0f373126474bd2d03d8e7b9b7fd601380c87e351d368fd4882146fd06489d2dd18cfa663d28886f7f49141dbd55f9ecef64a05488d7cfe1c899ce44d42fad4ccb2e12ebbf2f526d109d1e77f2fef74339ffb261d36729396df661b25cf44304a7bfc81e9892c224e189c069da45365c9966abe8b00228699aebe74446aeeff77e81105723887940de3990a23f383c58e2784d68f8871c90d43a2e03f77030083e9a6e0f0470c4186c103a31cd427be5b80a8316386c59d8001b88e40a69fd3b6bdd1e639481512ec1a10e3f2289fce648ca26e210689f1f48420887cd99fd0cdd022bfd0f9e4419dc1a8590357d80a444c832e099b3e2b3d10e20bba8d9324847b34c80d50478675354dabe433ba8b298c31ffe8059f25c6aac6acdea9e11f54371d73d21817f6c699afd3b4fa0f473476c30648434e39d8159b1518fc8ce9dc3572c2aa1651f786e4e8efe81eba7f44077fb113b9cf9bacb9c4dc0620f745b9c10069cfe00f9b7feba58fc806dae02c819243e58f9f165a4865248708318b6fb0103225c806b1088aada03eca72ec04d4a55ff8d08bc2360dbcc1f367860572d72ea3fc682a546acab578bffc0b031cbef15b7beea751062806a1b0007b078369dc95dfbb0d5632cfe0386c9588ae160fafc9200397f8801577d50e8f17d54087110dfbfce3522e5733fa53ef96f29821a7fb81f6ca0e8a8cdfe61fd1cd7071cea0af841d3a326526bc6399cce161111007a1c346c0eb006676300b00dff8e7fc004977038de93392aeb31ba25c2e132898fa5028d7a8bf183272a2dd670a69a7f05e987269077c0919b640b730c7f464485db111b1ad2a2c4f9f4834174b5ec61717f88ca2613ab6bd0c546d390a7c1657dc493c05816eac8abdea7d3b600fb0c44d5db23f652557673c706805744a7d6ec4f63161e279c3772bf24153f8f8e3b0e5b8674bc56bb9f1f1ca31c127c4695c5160245180fb810e4691b82a1e2452c7249d03c3ffca4740557730c10bf7af8d0811e9088c19531175c77fcf331b56ce0136ad9f2e93828711433b375bad54a1aa2d36aba2ece0c1942b50bf62133716b2557b88f8580f93ef6dbcac187906179df65a28be3964d175a5c6a038a0c5f975a309a514d8b016d064300769c1dd6eadad48fc022cc4eec8d78213a8913a35d076a8e55e231bb025954413456dd7f3bf55500240c7d4b1b1f6985a519b0f6a8567f2348ced5268e942c486970a89999dd84104288442eadecde01fd080609950937abeb665f9fa94bcb7c20d389828621ece18b165c418229e47441480ac21914808113831a2a5ac082245213f8118330b4d045133e80410a1e4278f8e2155199f6d73eedbab22b8c2d8fa8fa55cdf6da2e7efdcb09da90bbbe74e407721f5d0ea19dfb10a18f38fdd991feacb6a16bd742fadfdcb557bd7292dce5a95efbe823fad1ad56699a5ec5711c37bf5d24da718118615adc43d7a6847176cf5afe302c147a0cc73dc4697a4489e07070d76442d7f40af7c170a1430ec3b44a7b48cbcc6b3b0405969ae430113b2342b2c81a2a596ec56eb324626b58b6d7225781ee9a9e495500ffbbdc55da39efdaaf568564400f7d2615b91de4de81e30215463b17d2acf9cd6eec1aa6bf1ca36b8f195d0b9d2562690f1da6aead693be4a91ec705e4a9fe831189b48f42fa13953f2bcada478f099da459a2873ed2ac1c9548afe89789aa995d79c95de5aea2e7f469d76ffa7657ed2a7a4d755378a2bee2f29357449bb9645783784dbb3e5355b3aedb5ffd51ab3f96a6afdbc764d959f6fa933de41d13158fe5fa883d568d699878135590c056b372e659f6d7af66dd67d7aaab3f69afc2f4278fe97aec31f51876d6f6fa18ecdc39cdd28e65d7b46dab988d3d7695d5dfbcfd754cabaefd7595bd0e53f5577ff3baaeecfaa40e221569604abb88c427c8537cb4d189369225b4e3e30db4916d18e3b1cf6cf92426325bec4bb6240950c40627da44abe14449bd8a37d166a2e205b1192ab925685045a3924552ba65f9935bfea4fe72d0cfc768c7340bbbf6a95939ac797a98d2585ab8fece96ed75cb6a55410253483fc4f6c1503d4fe79c496521282495a88a9232de50efe352510166e55c4cbb7cc5aea2ffecb1d363bf5a35f5777d1e3bbd4afb7cad1a16b55a230e95880d3756d22e935dd378a22a961d729ab65a856959e9e7a1cfe505940a68fdc0a9f9966dfd5849c9d7e0d48944d156cd4a6afe074ec9d38f8ca01126f417a9e1f084a00d28eaf121e2e168df481e74fc6efac4225ce018215d66d3b95c725026f9964d8e73e9a19cc383e89ff7511689dedd13fdf344e700a4413b107f08b1e9352de2e0049182a78a9f27e0ec08e9f12162eb11223f5efcd45a2b91d9128144204422102211480452b3208ed87f372e1175608033834d230e4eed519f3de2206b76e4ec23f75d0de3895e334cabc57dbe057a2acb3c8448d907d375a39b324c59cd84bea475b4489d26d13a84b4cb489f4e5a26a75e2674a965e443d4feca9312b08c38dc1daa67cd77efae9aef5eb54a3ef4171939ec9b64f121fb753a7335ed03107467af5fc59d459b7db0877b6babb8edcbf4e17adc32b3e4499f9995a392fac348fabb971f9df561fab357a9beab3fab73cc931e233ffa3cc99e04479bc808a21c431994234ff49928daed10d978e64a90135483b025e7fa8f9b9aad1a97942ca5e42925634beb874b0abfe6a6beaf2e05d4dc14fe8adb107f05ba51e392c25f89a884b087135f84a1c1a1b1a174d6d3c79aedf431c86c29991e6d4c1e79aaa0e901cdcbf92e4b8e9b9cf4bec1140576540072016661d35873044e143e52d0dc34114467e72222595678c7e7093e12efcc961f248a9ede9d4d7f8034e8b53ab22b8220479b284444d1cbdcfaf1148c065875f100ab38824d69686e8f7b4d671a664e790dccec0b679856cbe4de5ba56fd7220db4d17197b93b96e3771df89ffeeebfc3940ed0b97f8fe1fe7567cd738fe9fefdd32c994b6eca2437c9a497b2e89a6749177df42d7b87a37bf683e1b8ee5b86292d9a324c5d386a8926d12e240d676b0427aa25d2a7892a751a94bfebde610ae7eef831dc3d8d7577783f1f0e883bf6c8133d8e28449ee853d8e35221286870912b3d2968970f791f40dc5d0f44695b784578c3759b27a4b16d780fbb1cba2d5554708f5dc73d3693d2813dd39fa557ddd3f922352c85ddeb2a410ee64ed4055590c0ac1c7b16bdb2dd90c371ab55f39ad5222344bb23477fafa2bffab3aaf9cfeaecf72cedd863eeb76f9a956959feaec35486294cc389baf2d7a1caa57d803ed7116c7655c03cac5f611589d2b1669e66ac59998f40ea6b6c429eead4b5d6479c18049f7bccbcd42cf9794eb37254f2933523876f34127d2291d9c2d2c2587f59dcdf5fa406e791ce9ebc3e56d26bc9eb65cd6c31798d45768d3fbbcaadca24e449de7c3025391e70eece65d363e4605a43cce30f21cffd84e4a46b23fee07104b1250221a26a68afe214a13845a69182c49802c35b2302d81299107d6a7c208deae3e37a0e3d2e7a411ff75fe603d36a954ef256c9498f3fb13e16992df2f59108b47177add527e5079e112736016d68af8f31802df10710555f4f845deb6bad4ff981657dfcaea3fba7e3915dafc3f4f83351f52128f00783b943eecbb466e56467cd63cd92e772cce3abe6f133ad92e7bee551e825d9bb468285ee65d049b93b04bdfb07833177528629b86f869b84c38e349c2891ded10a6938eb5b200d270aebfa96a775b43aadc344d5737a038166aac44f6857db3ea35d855dfb752dfba66564667efae356cf430b02fbf6988c95a3d29e6d6765c752d8cd3075e5ad1eab3dd4efa887a9d7512f7b15f6f95d67dd5ffab33ac73c76d53cf6ebac9c4babe6b15ffdc2c2f4ac31a57204969146caeb0acde4a5c36b3ce467e655dde7a596297dea2fca98bcbb7816d1a18f3df451873eeed06b7085e1102c7e36bc62c321589c606b736369c54e7ff79f0a665e83a68f9284d8893da3d34723b345741a7d480f414167cee101a65adf4d9719a634b975f9bb964d8f1c8e2fc74caa3b0f33a94ecbcca4647254a677ffaeaac0157c764090eab44c05aee0b34393325de698d262c9490eb9ef7ea6470ebbdfbd42240b4cc2155358416dc43ff4d80bc97235f1c363b6c424289549248135805e6483e3e3bf4b0a8263a809389ef3813d871ed87380f1293f30dd3e28f5f15d0df3995e8f6598568bf492b74627b9f665949bf2c94df27c294b9d4d1f7d429b3eeec85f22b1c8aad41de5aaee285a26e75e66befbd52aed275a467eb9bb296b37c93055ca30a5559822c93045ca3035ca3025fa606c49f64e92b79332fe2873cf72e8a20cbacd3cc054ab85efbdc57d7bcd8fa901a706460823a5c1b45a43689856cba3ef748bd32f1345dfdaf4ca278a86a030a9c800c7797910cd68a64a4f06f650fe3e26de6a16f6f8ab59392a162cfd830157f6c89ed922e3f5d24716992dfaf5f267b6a8bc7ed2cc16001ce52b4964258dec5a67cdaef30879aad306e5a6cbd84e4e4c47315d468ea9efb329329ef218fd4fb3bceba7e8b3f0656c875c4797d08181a4c10c340d07d2a8d247f64e7f5cccf20892883cd5cf2c911051f554366157d90369d4879a60add6fec58bb0e7c1b3546e80f1bdc7d74beeba66b798a3143db27f9c8641390f3085f2981e30ad1aaef24d7f39f0655c8777fd3b5bbedb707bcd725f0e1008140ad97038be1ca57f5795fe69991ced32f8a56b5a25ba0d5ac6bb08e732c9f900c87f0d39c655f2c9351919a65262fc24a75ce7eff0fb60504c00c83055438629950c5332324ce90c53598e1bbb595f4b9a181a4e542b45c3598fa2eb5b273afe7c3a1699a87a938e3eb67e2779abd502bd74d25badd0452f39c824479cd9227a15e5d344d5fa924c92759448a7513eed2aed419fc7d93bbd0aa43f7b91a73f2bc2077d166b49e4b3a2c7e08b342b7450484b9096462e3e79ba864c6630693204af4b75dd76d063bc779ad5ddf3406779df36d0268a911781360e04d29f060281fefd45721f7602da4a26d1c80473c7720e96f7790d7fa2832287237be4342b0706f434a4646652a09fe498fa3236cadc478fd91ed2aceedb479a956198adc7f4a78940f71f76eec3be5dbeea1e302d93979ee9ef5ec73c771df2dbb1fc5d9d83fb54618d0b715db77d3022502c21218d44a10e84618acbf35b96ef30137ca0afc78f22bdfac0161de615e4599d562b2b971d22799ee7d1733c88b20ff0d5835b48f415de21d157a51d0a1d8a34097a791577bd0633a53948159322a61883401844f1e1af5fbf9aa6359aeb218410c2cf4dcaa393e4f992bc45af99de835c8ed13d910733be97f143f82310a69ec484e4601feae9b50f6cf87b5aadec95cbbe5663d7b497d53ef000b30fd7a98ddbbd3ed4fb70d9bc8a0d8874be4c0cee4b8aa4606214fa459a357a8c8b468f7196e89f3005125d3f6674199a158395a38af1d159bfe831e6173d26c6473a87e87fcce831628c51089b2a048918c43ef2c17544bc39890a1cf202c3386769c3e86b73cec79b29e393e413e5b3e4337f9666ca344dd284134e2dc334525121b9ca4b2a24979172141d392cc6a8cd39e79c73460d9b734e0cc3b039e79c7062775e64a391c009678c3a07b8af0634fd22454f796b7494431e515ed12ea3910cad72191f9d54b40cfd6997815da43f6d0504dd7487b9b91831d15f2696b76da351affe6197f1d145595ff418191aced1b5168948f9e4397f7f363d462eb9969261ca848792946c72942c32b9e82f72d7fcc1944a24393bd19fd661a2e65b2d936e99e8926e956897899af324ba3451f32f920427bca8051856ac560d0d34387b8278a210a861f6574a0e07f6afd668235b486ca6988773ce3967d5b01ec932a7c0c49e3fc15560cf416e8cdbc1005bfebb6a8fd006be76096d80b6afe6d64ea18dd0b9afaeadd5ad7d6545a14c210deca02cb187bdc3b06fb3046960a37cb3a801f537cb470dc4b525bc9be678a8324333589acca05d2a39d83bc8fb256febbeba6b1b777ca857405cdb3be89a97b79521e0d0577487becdad37706d1f40f77e857e890eb5e61d5e5f9d6c0f6fef269085cad36c29ddf37e674bc9bd6b35e7303aad59ee92fcd5cb979c247f557f39e6491e235ff27992d1719e7b947bc430369ed464c31ca49732498ea5f922bd0c3acca08be0412765d87d77ce6ebf0eca387f5f8fb829dc5e865b24058eef329725a491b3bae131bbe1ef05319617156aad2cc0dfdd46f0e30f776de3324cf5609fecdc63b46f9a6371cff417214e109b1b2db3c10962730306fe2c366ff2187993666597379167699fa7263726719fd87bb79a8ecd8de93b3c3d263615e53423299de2f85861432446ded3ac2d661edfe61cf3589ec57d5ecb79ccf6ec383e4ccb26cf7470d7e251724c45eec3748bf491cd4d133a5314116213448a1d9e1e6ba4a708164566cf6c9101a3078c9e4d2f65c0b87587111f1fa6ad8d0dd6a3fe9a9c0798328169b5483eba297ff7a6c39449d66ef298ec26cdda9edd44b372549bfeee4d2e9f9dc5e9edf32a13fd61ff6e76f94d7f98a6f4dfd55ff6188dd33e3bd049b287334c55d0b68d3e182dee5286a97a897428b964bad4e5124c69f25bebb6a2cd44a128c80a8f7a9efe2e8c4b3ca251c76d9a9761f1070c9d2339602af41c1ef0475e06bdcbd8f3401efee8d2f82a9b9668e6674bc4f13cd975f9629e1e9d1d1bd10690063d8d3788a14cea48eeb3dd357a9d461b40143dc57468747462122df2d4de808e0fb9cf6a180f26a45bd9b97961cfdedace25117190355a26e7baccbc87b58c7cf717a9cdd05cc3be65e75632cc44f5305134af600e67e7d863ad831b7428e7419af57d7e2c944b5dc4880f11e953c4880f91b8bda6b391b2d332292797b288111f223fc9fbbc88119f4ffb268948fd6171c738287ff629ffdee5cf6a904e1f9bbfd3133139a59735206aa294a39452508c83a6fc4d37c1a68c71311f0cf32182c50f18201bd9f231e2c5114983d908aa01d9808e00d9c418639c628a1a3ac51437480c52ff61d2c7c77e3925b3bacba36456ca517e925927ffbee59879d0b59c631ef42cc7c877a792fb300d33e535bd557293a76494cc9a07fd24e7a8bacb7f9905f221026dcc4d2935792f65d14b323e974927c923d143aff98301812e12fd48ef10b57cb0d6a1830be702c219cd60126406dbc1d7cfc7d44ffd89b27f911603da046652f432c0e80177f080363af8058c50043ba6e2796438f04894c2888e91a8c92812318e943008c66922e2c0523c845f41985affc56079eee021875801bd88345408b26fa684251f6c29afdf4c07315171478e35f147023045b5119d3b33e50583fe7a4c3cd42cf8c8822ff8e637f597831e5e75a86572a656c547fd4d9978aabf39939a977799f29fd205945215235cf4743f48f5b7838fd8c4a61a088a8550610246c78b0e25253081b357a5bdb2e3e9e5293899b0d9f1271127b5823f7b477a47b0a308f66adb2dd719a0c303246a6ea95fe429dee50a8c37e462110f48b7230db7638b3f681b7210b8178880dc5403816dc839609eea68c5954158a80302914715855029361975e4099e07dabcaeab5e578d39ee79884d786dce3b3fe7fcea538bf19a578c33ce38e3cc74aed0a0ce8e9f74ce9803bcba70f68503bfba6ee484775e37b3e54ac5396178a4d261811e240b961d7ec70f3c240b7778208290912ca143d1e1e89074485272f81d3ede489693c347987218e3f0318864f9613ed4878f52481693437a883a0cc0a1000e1fe163159285c6e1000e6f385c397cb442b2d8704880c3ebf00018c952faa9060314e0abef03d470992d2d2c04c82af074ba0df92a1658c927efe1865c3ab9c000f2a8b48346c63fcc38d970e2b16bb84004e064c32908d4c986930d353c1e0099d6a0a2a10c93be509c4c261d4cf24a8d07e83c630526e7133ccd50b5e4124499ce924f3af0f5089e4ca61d9b3e7231348627d3e88794bc611e28f96e409c646a0ae2cb109e4c26872613bd92d9f9a414802470fc6a740178ba8ceceb8624f7004fd7435824912d004fd74145704659073c5dc756347180ac430d8fdb8112096280ec0251d70b90214475b0676647946b70dc0ed84587505ed96a3c009467682b30389fb2192a2fab60271d7b1e53b100974fee7bd872c99e5c60544b3bb28c2f6c458696b0d64a51852ea0903101df212930828604c6806087c075e706f8ea5c1ce01be4fe604c090d0b5c57a0832b0aaa15be00e40c5f686161c0160d591270688b6d092cb4600ad91070b6042e8ca00101df0d8778810acd0a6c371ce2851d2fe8542f6c5ea02902e38211cd0b20b727db8209ac163e18154850bb7073b918820a2e2347ac0e4a9045901364f1c3040ab4b8292205467686705144178e4c14bc5b1c49c32644109a2c30de7088133f603881856cc7092858c10921645738214555021e6d38c4099c5aaface172037e0b9f1990200c4d9b2351688224969eecb84d96b44c62d74af939b50e3e5ad64bd2295de68c134a49ea02f0850655a29c74442fd145e75543d582ecc517f3eccb44e11e2c832fd067432299c669dbb6711ad7659d8779f85e746290bde80485aaf480e088e9bc42a2eba25334a223d2bce8249148d8035b3ee14b97aefaa293845412afbdf6bae8bce82c2195e0b5d7e27fb6bcfc90075e23752f90467c2942630c5abcb6c41ffccc867a15773cbd284c8d13a695ce73801e44696864961b523df509cb1929af09ee95a718e5ac9f7a35e79c53df8982aff994ce4b860e8ebf6106d0fa402a2785d75e10b5d7bee6a6327d2bbcc7728d4bea3ecbad1a9714762dd3260685b66cb45dcb7138e6b96e4e128610c28b864a23ecce39e9a4934e92c92ca1d742223013057fd5a02748634e3a29a574d249a1d64a5b10fbb6fe66dbc3b499a6ade780ad56577d228934afaeebc22bbda7a95e96d4c4a5975e6aeb15845e5baf2794d0346dbbe8b5f57ae2463ae98df2ce39e913975e6aeb15845e5baf27ea652fad970d72d57ad927e8add713975e6aeb15845e5baf27c42027a5d5621896d9da838e0c07378a1ac096ec52f3883bd892c7f683553f9aa66d17de188f8d3dda6f5c3cc5b1d45a7ac3715c375f5c5c5cee553d09035f43b6449b169b1b425602d83f25bb2f8a4304126f90f53c62cde9bf805c561eb1e6d291e727d6781e87e3dee372907b1e6fdae1caa58d3617c48147bc411ecac0cab82351118798036f90efa901a421af3d758c02d290bf2148147883d0c6b5f7466cce2b455bb81b0830dc828a0ca312d5cab997ff8153d967f61f38857d1e4b96280a1dce6c66fa93d1e42f32fb9cf35a2c71205209ee4846318acee59049cec9b073397b29478ee38e71190e1ff59f3c4c652088d59c57bc2e79c928638c71ce39a7bdee9cf49fcce47c9cc7e6bc337297d4305867f395354992b95fa9fa2269a690c3e171c7dd41879c0ee1eca2839661c43f9c0f280f96371007a1c883ab842bb63428dc215be4205342e489316a71c5d64eb5671c0eedeeec188723c3b430c1c67e391c98e5705c3a846db308c2b6af1c0e7b69cb5e6dfb4ac0beb210c20811f6758a894441c65ecd8037f6dd82cf9e5c90c19e5c48c39e5d78c29eb30b65d802cd9e375b8b581898e796e167d3d3df2ba0b029bdbd4418a2852836a5af578b2d0b3918c0a643b2a005ec046d9934315399117fec558d1b14422c36a547c426aab057310a241cd9f4f417977e5a41c3a67779d101e60a23d8f43a7ae8c1a6dfc143c8a60fe20a26d02ca1e60a21b0f98173052e8214e1d16981648143b0b0854d630f8cc058075b5e62dc050faec0a92ea6130056d86c27c06fe5645a87b78bff03a7bad3d36e643a363936390bdf14510ea96853fc93c77447d12c93773f31797796e998461a69a4a6e3c798bcc3373da6bbc9480c380b1caf792f7925a0efa1d2c80a1b222739076594f141b94b49f19ef2508a7794929c8120705e756408c3a6d7b4b861dba66d1a26310cc32266354fcbd10848831e3b4167c3824d1f69a4596643210fbff456f7924c5b41f989cbb5a71c45c35a49cbf20a880d4b39b778c4339cbf0cafeec6220dce464e7e50b09fe86f7bca51dea5a0e86f3bcabb9f60c7fadbf497e3e4f83128dd4ff05f6606c6c65d04e6c6f42a6e4cf758007673455270a49b40d74a19a644201c0a792f49959090462210f6608aa39824e1d0eb7d037703a51db513ad1f5e1e49143d2e51c9d2c2f16ee2bed9b9c1e1787a7c4c37f1e4db4b27bde4418860715324e397f2e8337dcb9ce771f76ef2b89f944c3d687cc0346c0acdb06996591e3f2b08c2821b186cfa78739359537d96615a2d929bbc457ae9dadc628e43401a47fc6815b1e95b90c6a5a67fd761d2ac1cecac79ef9f8613a583d32cf9ed7167a2e86f963b04058ef46eee26577137e17eb56af49296911ffd457ae7f27693ccbd9447f3de55f3de31ad92df3eb7a685ae711dc7719eb77dc48d442110f6f4cb44ad6cfada7dace44c20e5a73cebfbbc82e8ecd0d868343435104339e950ae14ce2bd901451d9e2a687a24e904a650cee5ee11638cbba7e498f232cb74d2419995a3329d74d67792ef924eb26bb2d68a558c8b1d2e767ee022b358479365d7300d8382a281995d7bc0b44a2f39c975c893aea57c2685923facbb0abf3bf64ecbe4605ac53d45cb98cefde433294dc3342d33e9ec44205147cb30bc438fa7902c571318673fd1329ffeb0cf9370efb48c497f98feaece314f72953ce9f2a473afb65e23510854c25ec7d14c54ab8888cefa151e49543d9e2d5407314bb5255b5e2f235be8e7a314b2656a1b5f4f73ebc74a8abe06d36af3ddd7e69d1e3f66ded378c23044d9845877bd6402b471335bbc974680a7106608ed95ec8959d062d7fa8ca58541959326524a1819524594524252d2a4919452824026071d0564722d6e3a839e9243976172955246b9289b5ce5cb6c441b7420b6c41be8c0233af088b558a6a30ea4512fb2c1f241401bf7f51c802df208d8912b7dc07cc71ee201a664fccb2dfd94cb4b181414130d532a99e4883351f528d96a5ddf2a794abd8cdc4ab949343d25b74807dd24b74a1e9246648ff4813688d45a034370c20a32a4eca77dc81e54a279459eec71765999e1054ec14c94fd953faa754859d8631f77ec238e7d0c02533557bf7d88ebdca5d7bcdcc344d977358c601e6716d91a0a4e9482c73e566167cdb6d65a6bed9c35f66a62db4e479eec5f643c62db93bac0f341cc964e7ff4dd61ca9ec76cf1b6778fd9de7167d56f8fe1debdd3acebdc11b225e2d847ab57775b7bcdc405ceac5691277aef6e233ed8f173da5c5283c2a7833bd58ba43fcc820d7ec0e026270c653822d4853078010d477040e40b8ab91da64ade45fef2272f34eedffdb43494fe9e52ba7df7f0d65a5930640a57f448c13383548d3636d188fa0f0a6c836111ecfa036ddcc363950551f55206d2a83f1102ee997508ac02da98bbd62dec5aaf80c2aebf7250bfa8bf185e59236eac25ab63bca054bcf79b96c9b95ab5ddd332dcb7cb74f11ad7e5bd05f7ee2bc8e59954976752f0de7f52eac896183e71270aa94e08419023110b2af66ae39cd0a2c25ec59d5aabccaea5912c2b08463d2259a0135a6048967b825d2f97bf7b972e7f57fb5071ef7cf000539fa8fa1e3cc094f64ecbc8946652f32b977998d2beb980616a3b4c5119c9029d20441176ed3257df8a417010e004b6893bb385c7d2d89a7ac43b7e9195eb323d97bdfc4581b35ac190a7fa2c4b9c6311590369d4d723d006ac5fc096eed58260d7ac1ed9b5d31ad3abbb8a3d31c3590fb7d4b12ac520c01698aab7de4caf30a657a57aefb5bfd75a9c4b8a6ea0419528f0a783bb0f4695a5f616b0decab4764c944419c1ab4805153c910a385de00eb06a8a21a59452d0246d18ab30bb30efc518c693665202bc2a9524cb6afb499cf341cc9b6b66dec893bcae1eab6fa378a7fcbcd1202cf263c5968fd0c6b58dfcf4ecc8e1d8467e4ab023b441b7911f20ec086dcc6de42767c78be3018a41072df0c21842800521782105212a421b711bf9b19795d65a68e9b471eb62165f6c47a21045036881092360b085125841848a9e22499c000462c0f9a204dacd486621026708021a7630c4901c1021899d1f1c0143128828030e8e50911d81849ac184084bd0e2094610210934e820878b18bce00948804113864ec8111a6e1ee164c3215d80610b9f96991364f153861a1b248290020610f9c20812d00081e78713231fd8706d90b0090311459860051262d0050c74963085163610528622b432aca0bb26a0c2dd465b174a48c3cb90051c4f6ad470b9f1824b9864c3215d54015f44e8204fb5c6084738a20233f84021f3e20c341883144ac800c81448ba88718bd00b88c20a5fc8a2082668c10512941082186460c50c7c308531e888c630045309565fb8c119b6c00152869d511521a9051b9418e20a42dc5ce1838417359e172ab8740464a0c29409e17384204f20020d3b2a3facf8c11658104184119061089010322081ba403e800384128461070a5afc80573043088cc88289224ce1092facb079a185c925c11524631043954e10e2851226362226386e1303184a861083266217432200361cd285135d2441e2026b74cefb22471b0ee9a266afee6e02c38b361cf28531ecd5bd9bc462db34d21e854038c6df792d5efb15ddf2c6d8295b9b1b9651b646372c9fec6f6b75c3b2696b76c3b2c9d6ee86e5d2d6b00dcb255bcb362c936c4ddbb04cdadab66179b4356ec372686bdd8665d0d6bc0dcb786b78c3b2b735d086e56e6ba10dcbdcd6441b96b7ad8d362c6b5b236d58ceb646b26119db5ac986e5bbb5d28665bb35930dcb756ba60dcbd7d6be0dcb746b271b96e7d650362ccbada56c31505262fcfa686f79bfaa7be420daf497dee19b7a2052134c196f9a1197b6937a096f9853671b62d1ca11d553b443d8db67e2965ed775ab1f6315ae1b5c8bf72a07bc7bf0d8d7f7b5784f4a5f5536d53fa86c284f33b20630ea8ce58942781523e0d5b6e9489e288d7a244ff487f873422fba7fa0515401d2882ca0f252fa604f39e79c73ce39a7ea003e38fe00463840153038825774d3fb65d8e3ceabefae3efbb8b1bddadf75926d63bfc82cb2007e0179e44987ac29e9e015dd13428d336c9bf717b660bf7a456f75cd2b950db7bb577425936113b25c17a5f033218841b3e54ebcc7235bbc88061c39af4706f8e260f8d5f57a0eb0bd4b0a18deeba15e8f64815b4eaabd1e48c3ebd9f2d0eb8136600c1a1a650b54281658dea0248b70c365e29c489f15214ef20b2f3766e0526322b1dd2033547e521a9d8e8cb09ca2c68c93ca4f4678bb7402b92ff84969843715225081d2cb524aaf8b527b5da5aff858122cc184baddadd6aa4411945e96527a5d94daebc2a393252a17b28cd62ccb28cdb24ae94f2e45a4a818638cb1e7799ee779b5eb3a25b6c8325ab32ca334cb2aa5b874aa46b28cd62ccb28cdb24ae96985c716e1397969fbe874c2275c3af1d42d507a594ae975516aafeb86102a8accd82bdbe844c5c505bb6017979f5c6c50bf0a75b7ab5ded6ad7711cc7711c57b7ad564b2bdd6ab5b4564b6ba5d4da4a2ba5d6da4aa9666b96654af020cb68cdb28cd22cab94964e5494e0398247e5625c2a9dd2cb524aaf8b527b5d2a2a2ab874a2b2048f1155dbb8ce2b618c31c69ee7799ee7d9aeeb3c23945e96527a5d94daebbaca8c257a3063c68c3be3ce285d6586fd4196d19a6519a55956293dcda861b930da7075b3af32edab6dfbaae356a1aeebbaaee3388ee338ce6edbb60417371d6419ad5996519a659552979e2b0297192f3c3c3c3c3ca7151e7b4584424affe9b4b2e2c2002157c81572855c2157c88a10971b50c81502a597a5945e17a5f6ba566adc58e202f1d1630281adb5945a4bb39be95aaba5b5d65a2dadb4da4aa9b5b6526a6dadf88a820655e0def0c6defa81b3b77e3c158219c68f95544e8cb4d6bac57be966376bed76e9adb6daedd6de4b6fb576d3348dd2aabd564a2fb51aa555cbacbd97de6aadb5d9a5d766b53ed65a6bacb5566b312a638d1b4a194b5c8c042aa76d748267cbca0a5ec12b5f99b6881bb854fa4fa79515972ca335cb324ab3ac527ae3c68d7be3deb8374e2b7b7563a5c60d1394b68f4e272b2a3368d421a2e47b760f863d11f6ac6c17d843f3e3e4625cca325ab32ca334cb2aa52727f7045f57b5af7a757d758265b4522ca3b5625846abb5b6d26aadb595521b6b1671c6af6a5c8c4ba5c7c802e5e94e54bc945e9cbd8fafb15a38e5ad1c8e1a11257f2ffe5ed588a7d5699fb81c66ecaa571487fb95dcf630e280ddea55fdaac6bdd9a5f7b2d7cd7eefbdf45ed6de0c421af7d16e40ee206936d53d6618616c7af9817d3dfac01ca08511c65ec9507a2a33af28e1bc34ce17f922a1d5022c62059127c8934f153d4278e02f94c22548133849404a730068703c0582de06488d3cb5e4a9ae946864e0e705048f1f765ca0070bd0a9439ee0495800218410420821dc21c61b643c7184943622102c179d3ee40642ca7803c481521a81905b4a4a6984f106f8c905ed4a16083d88e52f4ae927d451473d2509a494524a29a594524a29a5bc4e3a5401c0e1039f16a8042b5bc98a542aa5660600000008006316003020100c074402b12ccbb33453dc0314801277944c6a549c4aa324495214648c01c61040080100000308102846201b0050b7b852d72d16177ccbcfa856c15a7ebe85802eb1b02341cf1e049cf7f3672e4be7c9b0bd6964c41612f4b2287008832d7b10a111cfd06f9ea0f52d3a4a881fd4141bbcbfacdd972747f6cb88a5b6c94312fe119987fac4954f087dc82213fe4f5ab7745c5cface1b1ca0b5859f8c8a006c5cbb0cee25c59a71c35f1e43ed0cadce7cadc3a5ccd398718b857cd21e717c73ea1a88ff4a8622bea4b4cb1ab99e5497d2467eb9f219b7c091b9610d788749fd63b9b8a2e717a9b1396e25612c80968fbed8dab93d3c333233dae7e65d223a888d30edc2e86ed380d319cc1e512e82221b70bdb08b343d380a3758d10ac63da7852b0c8c63828ee864416e96fe8b1cfd1e0d0029858f2795107b54f4574bbd70df3bd6e1ecf6865555495b3d3dc4694a04920b0da3443239046790a4c6d5f6fbbb256a5c2c9a8714dca363dbb343326116196daa5711eaab1adae2fe2f4e8baeb3d949ae14b520e58e1514cfa0c256b7a45144c6df748c099e54c8fd3f1b2c2d8be5e9d36dba4f39ec1af2ce261e38bccf6dfa71ad3145b4a1db464bb36a8a9ce2dae10f3da954adab68fac30478a2aab7eaec988edfb7717e901459f70fd64a331447fb6d5085f325b821ed7bd4dc9d2ddfec0b0f9752e9e5ed7d1f995e99639c6769f3513270d8df9275be234634a068736063fed4d514d86abed2715991cfbee53268ef6715c7ad7081ee33c652370becbbe7cb257ab21dbffd50a4900cc757839fb608f8db99d54eb9c62d8a4ebea53fc283489adc1ec857176d13cfd87a10618abac8797dccd5cce09124bf5459ccb3874840747139152298637adacac766de6b374a1b6ad6e31086ea7040254e84dbf8bc65b4f43c1ed17434c8f036bbe928e4be9450406ffa74d965841b56519296d3be92b0c300d6395170eadafb3038d3c834a29b787f46a7be16750ff002502642c09db0fb019710820056f3be0806dd70c76b0d5f69a8624e25a96097f5370e7dcb4a3b6f32e829c38737d3524d6cd374650f5523c0ca06a0f1a6465be77e65f8dd2513f1db100b7a2384e1db683f234d48948057533d2b70e1e43900c52660781d6cfa4ac2f730b030bbd35fc457ca312fe4d71b7a6df2083d4fad4e4b4e40e355f74b0fe8e6cf911d18446430a543202f1506f9d745585ce61b9dd8b0d3826dd4b8482d438353b2c51d700d49104d099f1c79c96c026cc71482d75e5694a5d55d6f8656f10c8f9523a1d75196617ef8e3fd3b36ceb3cbc88bbd3d7853db93e80d1d8e4273ceae154f6994a73dcab374aeb1e4083ee8094e64a252d95ab77183b9a07d1013c269abdbe1c559dc58febd61858e1797d1611d79e1aa5c2e3cce1f88936ae906ca5ee7ee219dcd3b81cee22ede8a56cca33c84aa3acdf25bebb049a4ae80c1e02ee7d108cc0ee125dcdd2338a4d2a6acdbc43fc460b2bfe5fe695452edc56b8d0abb9cf2fd61aa8029c5cbd36fd2612f663e45f742862f1034b7703a8e30c856f362d5332f0865d837a9b15054e61ccd4d83a4b5fc481b0167ecfdf5565e8ed3458b5038824a643d10c8136d2e9b04f019b7be0dad3904aa91df9a2771f36d79c2c80720df310fd8a3d644e4f149a5a040f882c782001de590cea0cdfbd966c24aa7e52494278fc8b474571ed2c612101ea3355e70ad3c1c8fe43f4498f69cd9d021f29c2abd1bb503f55b79c53f62704496b7b58e31b5bcdf15df302eec6ab2ce30a7ed5d39692200790cb068da0dce889855f168796e469662456d512dd326d3cf528fa850955828717904ee467ec8df6f8d5ac5b80bc8aa472bc9851740bc67ae7f1826fb8314a0cbe952b93eee394d095bf2b7e87f60d472a10880eacdc91655719b8f724e89b6149edc772e1d2624e040f8f6b5bbee5195a9911b2811d17d8b51fa21e6bf17b44190eaadf2a4a6033d8243e2669a0401ce2bc80ce6ea55de4dc0e07cd3e3e0823cd6d25b58b63ea1eefafc7945d335fb424ab283591d0cfe735604162bc9d211a7a39079af1296043ac1bdf9cc4c4752dc14203bc496a55b92114d00c7e39d2c5e440989667fb7205c3dfbf2963780d589947a7156983151973014ab66abd25569ce83f8206aa4f385626611fa4174470ae6a434a650cbd8c555c680be0fe160f0d7e1dfb64098c406bb130c9ede8c95c9e02ecbffc2715e56206d5c305046c2a43adaa5b258002c5906d3a97a380f61d2b631d0c59b4f70152e506e636daece96079386beb66a588b70daa24bb6952fc41e88e02315a198265d62040f392e6a1023a98cf396b2cbb09fe0bb51615cf4c5043a6a9827d3d6d10e347411a2810b44f8dd7fb4b372362216af60cca3d149d476d969015372f6822eb7cc4b260a59f392d95fe8a9a0c523cfac8cd5028dbc6bfc4d2c28d84b62f2e1c52f59e2936e9c503f497694dcbd04ffaf9d6850cc2b34ab286a5e691f233a24f6c4097eab88123d11ab904c101c9cda5372cad2d2587510dc30dec82f1045814780b70a2e3993cb9e9426c86ead45d740ec1e505188947a695054bc5227c8e9c88db6d40932617c906126f66c74b26152a8f414e0ba13df14af5122c5499964e88cbbc37e6478c10799e6d48f4d40f1ad9faebe170704bcdba79ec0e0268c83fc5b9cb86212eae97aa14005c808a11260c817358089cfdc63d7032a5b87cbfdc2325111ac31b5bc6fe41bfa478b3c2993c9c7e71f51a5a8c878422f85a58b4482a07811b2d7bfa0f26fd9949719e85313d23548e5a2806dd4b12aebc00be1bbdddfdf0f9eda963f97d0cd4035036c15816dec3e77fe8bd679af4e020eee550cae59325509205247ddecf70226ce1c146efecd700f354f996aeff0701f11005259a1ef83ec38a8ad069da0ccf4eb0209911f694977101c8d08bb883ccd5f4f44e1efc83eee81bbd53af1b718d0d450ffee29bbcbfb7a34be6d9c850e52be61e1ebf002e422fd85d840fb6163c8e1ec1e4ff0ce5c14a08e16363e0e0d9ccd5131ef3490a8f7587ba978824fb0fd0f7d9151f99b23496155bcd65860ce7dd7dcfe62283879b5cd585abf65d0849964e90874f02853ef295c7a30c7c2314a06aa591f49899da98b190b71474355d53c33fce1cd83e5f595ef928f4b8ff204f3ef6eba78b17e23024d984465ef2481980183f04ddaa73c105537a2f3ba39e5506532141b7d5bc025bee691cc45a9b87f469fba82543354c895dcbb372eb91b3a4d0f83a886b1605b61293621fa7d19291a255806b6ebbc24ba681f5ff9d28120411621791ef2350a36ccc8e013ebe6b9f31e872b605e8e4e03ba1e21fc76b8373764bd4829fe60071beff0282006116bfcf5daa6bc8d0106db4ff38944d924c9cf93b2100b21ceaf2023c7724397a36bc8a41affdbb802b94ece0668c412eef9c183daa15aa4c67657c19814c0e00c5bd622d2563a195188b09410421c95459488cc86430a2f46d451241ae6f69deac8b64ea811182d4900504b9cdea7c9f49cc601d396452274648b19433de94eb3bf04a52437b25458608930397b8fa6c94cea80dfb0941987ab4060cb2a9d5bc8505556943e2a51680bab128f0d8d2a2ad2be8a50aefe7b657f86c95566530abe8c37640decedb79c4263e53abb2fb9a614c3df6892148ff6ac84135a684b1b63184746894c1a1f215ea0474b187e4c296a61b706739733fc80ac093b2cca1f5aa4e9104791988a7cc6e993370eae80ba85af50b732434f55eedee8e4e0c0bc9fd4833238cc4cf01d92bea433aff78cf20e03379516cd1cca4472cd79b9ce0cd64a43231128cf69809ac06d3a85a10c5364d0df063909c5c056504f67b8edc23d45a44484cf08235363af02a201cdb66df592c5b248a5b3b391aa0c103f862c04671a434c230a36748d15e4ee333aab7ee8fd1dd4095fdc1a9fe698c3b548a788f5e7998e475afc90dab515ff6dc43a7ade910292d23cbeb931ba134fa90b64ecb4f7da6d5d969946f4be1cbfa79f2690cfdc4ecbad2a0e63753d9d0116511a9a36fe21eb04b7745e3e1a365d2afd7df4abda62012a3adce91ddd2454b51b32b233174f6b2fef3496e4fd60937ada2a6321951ed7a93fd1073e8d1b2f36f0c32ec6ea2de80807f2d23e1624160f612b2db7c823f3733ebe1f4d30dbd4e53d9fa9338f6d306eed71981556a5d31a41a3af9ba4edc25b1a52a00a8c63e3f58a4ad3c835decbd7c05b4bc13b012d13808f6f843d4df99a0150e82f6bd54c1761058d91a8697e37a61e70ea2e4d46e1e6282d04fe09dcaa94b1e7e5d65467e6a761a50374b8fa00f70714755e5082e132a906ef117b62389c1afaca726878b25a855d7af1effaaa7d0de5d1ea324b9cc7b0b97446735c43a5a94d534a406b90d534cfd71968e0d8bf7fbe0da013be04049df76e1ff61c330871b1d2452e83caafab43f1d04a4fca113a0b17ff1495ae2502e08950009e91a5e1089ca2a75f6e68987c569a811ed3144ca4639f177c74c38c618e570c8802208d4eae27cbdf4d4bd95207850e5b10ed579fb27214a6f62edf353b0e52e9b277f2fbb3c6b6d7bc1dfa78e127076e18269ec2002e6c52b637c662de88f79b73aafaa0984fd5314fd81a5b65f3a7b032f4775646ff6e2b830fe21d50c4fb81e32966664ab0d73512c940b5abaca0addd3edba0b4601c5304710bb881f63f69c741a83c464ca074713bae89218807952ee712ca9fdc6315b73a997829421c276b0a0d6628206c1aa0a12871b880e2a60aa7c9771c80301ac7cdbb377b46b6cebc39c1a378d27f39c702d18dfe317b2ea76ab033b60806f39367de12004aacba460ff7faed70dc96e7d0b03fa8020dbec7655639407c7460b661c6e92c482df2474f1f6f1074c11fbdfa1893d56aeaeae5b7af1a5eb20941910f9d026a30fff075ee6c429181697d40ac0a7cd1e3f0bdf561cf0606100354b2808b67fe72ed156d5b9917cf683686767220ee324b0ed305f81db51403e153d66fe6b484c3caaa87d7eb792f9c7bb0c8f8986b39f8386a677392abcd7525e103d3ebf121a0987c1c81311f4da4b85ee11c100d9415f47ad0fa9c3850cca2c4807cd889ee83b9abd8900b2c6c58a4d6e4681259834e93d5ff08674bf9291bf94a96a1ec6e7c7e43ae0139c918c4aa6a411989801b7198c0a0f3fef6c19e73061013f45213ca08123637455787dcf189fa91de7a0176317fd66e7bf4bbcdb0dfb736aecad21cd07814fde5624d81f7a79d6602ae8b2947138897ed048b04dfc108dc5919126ff72da714e5a1c4b4d3b05bf1fbd0635b57025ba7cdd9fdb0b2356218f43a60e7a4310be511237885f04e1de503f95ffc97573ae19ab1421348565c4da4cd9d63db1c689d8cc18a74fab59a0cc5a8ce0afa6262f771df288d294920fc74c1b6c5cceb5808040206bff9ab42d656c3945ef735e1880745dfc65ca3baf552b7730468005e37227c881a4b9f94b1c9ca709e536f58d654ecff336dc011cd89b5b94d07ad8f83edb9c6beeea9ba2410034374094925c67310812f0f2bc02370c1247b57e6dc2b7edd2b2b67b957729273861f487c7d001d164967f07eb93132abfe7ae6fe2ec16341c2adf3d27f0a045228962c5f4364192203b79b245c91da88b01a76c873d2bb43d10d1a7eeeabd86f4e28aacad56ae22419288870955c05025384c2585a99d10a5dcf24247a416ebd4d08e32abf19409113238563aac693f44b7b0d114430b31d1a495ac1b33d336ce60dc702045ed277c38d637089879886b7e2d10f5d5a564d2ff3f0c8d5105e3cdc23118a44d538fe32274a9c0586a0c82c81ea5e7ad76e766ed03ee1a53c56795f9aca30d43542462ed4620f951a165dfa11266ea93a3d96cd1818017ee69ef44ddb9e959c7b0705de269d5abfada1dd324effa2ab1b923d51ac9f75eae2a6a3d24b0b0bbffe3d012e82ed36e14cb2d12d0f92fad567038bf3e213189a4b6064322b21007eba61d632c76b06202cf823ba8d07c280345d0ed8b47b0444279c2c32e0ac40df5dad54e1fb0b546f9ac17d76637a73066b494e80b9eb89e3353a03cd8767b4bdcd1e370f3214d214ea8822aea093857dcb50e39c1b3f55807aee18820ba897d4696e0500519f7f4563a3b9e71e10eea54aaa23fab48faf22d5643ca1c9f58a3deaf31beb33af26acc45a1d3daae05abbaf8d1b289ec445fb27bc2371f123f7b6269441263c9b10003f1d106399e33403a66089faa79b4d43b1dce4fbbfdce34238db88c963be6707f71cd98b8ac373320770150fa91e6226863c00c972026650cf8310f4c526257cb7e0ce3f10a4dc7b6cdd6921c5ac5e0ba35d5aadbfef3c001346d8329658f9d086277afb18398846276069d1455a1a971a25634700da92b9f53cb99e0fafb84822e0fa2280fdc7c6d306febe80552a853d947e50ddd678306ea68e23ea754e235ef129b714a8ac8fd3451976085eac15a1ccd364286156be90ac86aa7623c56641404ce4b512d78dae2337b25dac83c9f7146957a7b5ea72f60e6ec8a13dbc7c57fc03dd94dbb901b38353339c33fe15d1e9d0be03e4988681eee433471797e3842cbd3c3c972392e90cccadf9b96e0d013a8227754ecef510f9ff77850e8826b5c4162c25f6b73f3e381914b185a63db7bc1314e53f27e7894e4e19c0f89936b0cd778b1ed5234c8e8827c6321bf35489c5fa7bf4c861e83f0d0b7f10e067d7ded8d922a5461fbb8f0eda43a8a1865a34a150924c478201d513d5b0588ba15f8f85539b3df889231f42c72bc24082669938080ad221fc51cc59a681881fe694f8c07be2dbbbf4f1d50c5eccfb1ef9ee4cd4f8abe862c07340ad49f3dab86c04e301426919ea8eccf78519355a183e46f8dff68a0b1d42d2533878877c4d3077643238617c8a6c836290ce36c4949b03fa4e5889d3d05373565afdf77b9394af52386e3d024546a7b14c85f48a14865e0462923ea509d183d6a06fe52b4d0e40e57ed33f07836862dbfe738eafbb625597e923d034c11a9395a0c8047163430ec44be8c87a77af9f7a42fcdb893d730a58ff6605ab1d449894d13762bfbd1c74bdb1f72feb34d3b477147010e0dda67a6ec75ffc5c20f76286e553addafd7d8c0f73994b9fcff0a16453f056e6c1ca5c659a626db5078420dbed190c92684985d0b174a80a553efe92a181273071cc06709c23dddfcddaac2721adaaa3fe221944470064c7ee6d37ca4abf19108b6ed3dcee7805226ba3cc7ed8b74abd6371ddd466d2843924d80d4364b575233c12731a4472afbe3b0675a32c13d7a97ab832fc5184db35c9597c3d9ad255215ff493dc0723692632bfbf78aba2c96b15c1859ba587a27e9c54409338a2436bba9f131594054f0963b88e98a28ea889320110c4d7398d44a6618dc93b1bda8b48ab35cdfe014d4eab9bd4559456575420bb97609eca4b88347848fab34a161a27bc3c031e7a0f75a05b381e1d7a2d8fe8ff67a0a3cf20c32bb307e26dd4881de0912ef24c39d05028dccfd09c3c0319909c415aebcf1bc64aa415fe6911cdaa409f5e1dfe9268e3f9e1a3c6db9db661d298ec3ff258fcda44bb751a90e5690723e83a8274888d424d7e9fe66b6e6ef7558f1553bbc4a2e1d25086465f6d2ce9a17b09d47342ce5c06b8f5b11b0d405adcba565ae5f8be0ddd0f25499e9c06fba34eebd3a7f40f72812011391814aefa023053a2fcb0c1b1545743b1ee85a61195da35429b949d72590b2b4a817e53a3408f667d966cfce1047785e61bed858788e2287cdc1ed8be1f934ac2af88c52bf4a332915fe4e87f62f456ce84c6620308283e22fda0c7a54db219c00b33128bc288cf8f476ab6acaafc2598321389ad6bd9345ad13209ea9c1ca60fc47eaa46d8bea5e773fd248008ce5e0e8023fea4555379515ea4441de46b970600a8a2053fa2e54fbe188e9e198e938ba359f9284a3c1892c514b078f886b72537fc6a08b066b412880dcb13271c80e8a99bcd334e3d912a737198394ab662e98e1c85ee6e725a0e80d5dbfb5a07c58c08fd2b2fb93251b824424295eb621d63a7517416b41739aaa0338718d7c348d3a7f444f226f121e0e510c48e8265c7516ae18be42518d0789d87251caa2b885e00bbc9235c719f778cbe806b20bf61be44353fe1b0c840d440d4deeda23966910e236ec0dd4b8ed5f9f559844a6bb0a0be492aac6901fa27a9d2b416a45f1154a61a16d467095ee92d1a1644d8339e8110f8c5087648c6ab8fb748fb1c2385c39b84fdeb144703a5ff984b71dafa3ad012b80f26893621b6384ce4368b9a101aa38b2e4e6c16878377eeea41e7fcc824b559340aaf238e0e2e03412319b93a66963a57242a9cee5d8fa8428ad89d657ee9353c01d79098dd7a84283c58105573498a85feb194a5121975f2357be6c88bbb2c9738d487008d67fc387b39b378cc058944e1d7503090e18349f027e60fe8b5b1b9997b018e6cc1f18a8f5602f1d4f4a9c02c8bff57fede1d2720dba9d1c3fd8d3b5c1cdaae47ffa7fbc707088a5e22a748aa05c64a82995080fe7d16d90f90719d880e7781f9fc57378cbb0eb74e75541caea003f78fdd7102d25e1fc8cfcf78bbc39672556eaff0a059cb12c86213a3d12f7ee8b937e0b2c328d8705fb3be73f5e0a690a29857b00c467630dafefd6f8b7bbb8d9472ef3e9911cd2bdca0c6fca3f33ec46b0da293623b06b43f2411708f1afbc8885eab26389d6807037a1363cfb154902b9d9503b758a36810599ad81e329592d9757292d1b09ce6140499ee208d070357fb8c8a1ded74d9796118681e490d288627065a8724039acd5303dd73c94e0e282c86186fd7239cf65e1ba34383861b255d8b4d5be0d5b2a27fa5407be942c9ac50a9fa2a2411ed749502da1f0c146e415e8d86f89795320ef24a350a3adf83e017259c35a260316ab8792218683e9774ba9fc2c688e9767af0de90c5dc63c11dc4060aa7eb050dd1b13c5a61b2280aec65cc941354c5565080bc71c75b1d3f5225573c76195e8778dd8485e7af210c612c18a8696d350d844fb81f0eed8978f4b04124b18d8596c4954e9dd994f490f2c86846cd2d6ef1b04d55bb17f9576401de5c1ac68ced9b197eacf88cc77a709cdc014a39064c370304199ae3c026f63aa2a5416f9a23b4517407c1850ad9a2242cec0ea8cdd4b32179cecc60526677689ac72be21d9095a1888d7359d2899a98029da5f25abed78d370dca24a1c32b2fa30b4dd37a5b25c28eb4386e26126b65e76a8c28b54363cae90e703878d2c8d134980cb8d8511f82020714a7ca4bb8c3f4680fbb2054f46b9302253f50848450b97fab682db48dc60571cc1978eab65b18a6c642d45f21252ea9c7f96d06c2db32cceb31621fd41d2a32ca0f5a33a48157c963501dba54eb331a67df940a15be7b4f283be5812a60a47e43c3211c4d91232343e125caea5136f80eacb30abbe899382b96a1c06a9a7988774b4b2af892c458f111310fef1a88a4c2ddddd583de6795f665826fbf77c20a74277d14ba90bdeb450742a76ffb04adf837a43b70ba376f4e167f63226b48538b68a9cb4d7ba799ca44ca33283e3d0a28f6cbd8ea691ba7d630d62d03657c0d286d47dbb8cb0241167af49d89762c78712d0668f96a51a43a46828c9bec1eb6faee4ec250e1136884ec85d3ddea12c25524290c94a222af68ef1d29dee19954147c62937b13911b67c5844c25e7dde4a81473ec9c424ca3ac24849d3c2a09001930a5e38838b54b363ae2e85f2175a73a618fec399104a81cb2ce43212808fcaa66c3352fa971a73d18bc458d02c784b48399c0c706b875285091369b7cb72b2dd34b29379ac7df70c069628e042fe5427ec4a69ce248e88d00537d17a22313bf8281b52b42d33d76fa5918da989367b06082169b1a0515e890cf7d95e5e6df1cdbce7e6810997218ea75ebd22e121c40b12e3314f5b8c9b2cf603099e5a7f4d2dd303b6228fe76b1f39cb866081b4c008829fb6464d314e49cc3f9e0dc82b7bb71e5982e7103f6797cc99457087941abe703fd597a8d28de0beb28d63fa5a39001800d0c1e0382df853734a658c2a48d02177e82f10f93c47f2aeb41338075d529f93d7eea5420d7b00215bed716a9cb242c90e7167fcd7ce0890ad46dc37d0ad8fdac14a2d5941d3fd9f5f49f194efb005d390f2d98f93095c42e71e1c6f78186c48a02e660b617b4de049f0bef68ec58de91f567b86c2749d07a438e776c46e07364ba2ef7b86d4568860900db054defc3e78a37d4f87b20ff8690144fd5f3e1d91d2aee2a1f5802dca4eaa067af74f7eeea8211be87d6d5e0f3542df45e961c21880347963322b4178bb0963dc7120a2a6985705ddfc473b248ca17e43c7d19c7308d77fcb4d07e41ce934fdf9058fa4809d908725f1c2f3487565a291acceabcedd91003d93d3e5f28a6047a0a11922dbfd0900a8a2fa1129209f571197e8e24570029df4a01fa764f8ba01b01f5f152a29025b90fae0295c2e736b5efa5fc6d680b979818ea948407ec26be939cfc8edd596ca2df7c5c8e5648bb9b8e606f21655fb95a5f73d4924fccd54fde6e9fc82a3a7892e5b613462247d27514a1b0adf2e9ae7903265d88659707a9c44a788af13afa90c8af8229214e5a846a1560d208739725cbe61975620e23e29dbcaaa8393ff4f5ed4a6fcbfe2c555b9d26a6e14e6b7f49058532a8212548237805f464a71227a7b246532b49b5cddc4b384b6081954f6ddbb3c4a6ce21a6d7b9b45696919104dc20cefa9ea303275aebe6fe4280916f177b34197499a06bea35c194e11b0d44e5b9a39b06a710fcd9b3ed9d8ce4ce8a7556cc29786f5a34e8c10f0ea9b0b645b0204916c5fe0214d3dbaf500e6dc3027e92a99d90775dd92d644551294f56d203eb720f79eb559e16aa152f228133506c4b117c8dd749018ff8c60b90e0017f33aa436401e88f37c327e99f18f23da94f4b5ff952eadaf9317fd109367b2b4a0839c18c78018b20091b6cda5a92749e8a95c457b7e7d2916b161c9fb1b1b615dda027a621e054137d34a967a4599bf0b0724cc4be1634e7d84c9e12a202336462db2b28ea3936d694d6263c63322add833e0c0af5493e33030d14f177f3606b5f9516a20d6ee81e514cb2fe167d26d41112a3c9c066ee24c941062abd3433dee00dea29df0fe7a1802ad618656c1bd620d846206b5c39fbb416a009ebfe5cc1c0827106bb8bd84bbf9361ece1be6646d5e6d611af53c5ead1c36ab39294b21e7c6fa997f90a61178540200cd6e8d90b8a0bc12bdf1b6a836d2f88310c90bc2f7020c952f9280d0823a6652791241b81b80d44b289b8732fd348ff8e7802f41d40a61fb54ccb0477a469905fb4a7b648fb7d34164e99e3a99a97758a68a6ffab18e2f035c6a8673c509e443c5a936cb69367503cbbee25a40440b6328fc3e59e6225a8573568b4d5c887c59b421e8490eabc94b296af4a57ae49255a113ab9c8a3862c8c1b8099d0494bead9243b6e68f73c01563a42053d8bd156b79b64b10c0c99803c224d5dd3dc44111312d2b0ce7d7b02d6536b4a2a754b13f85ea60092c49f77cf61dbf575c6d249207b16c40653b4c9356a82e5c83f280c25a6a94db17fd58a0ddeab41c3dd9d3acd0e6b0d12efea746f428548c363fc5c1350b377e0b3beb2356b71260dc09d510d67d7f3d8cb4780dddcaad5024a3813e3ba064d4db33ae9cc44e87d64d72cebe0595753f0afb50f95647fe89a6b1c188e2ffe55ed6752322482062735217f1a89a8f63775c14495225b6793078b689ca4c1eb8fdf774510fff6ae73b0b5d015477b2a3d3117b09d8a1065d34ba2f29a80c28a901e945e0e0200c4d2c1a8e77adc1b01fa30ad0511b0c9dcb9a8be73b7d6d48c29d92ffeb37861a33f21a0a918f30753cb4b345b1ed6973959dc221a62ef1351cdd614b341927b156123ee3592bd97307d210b43b3705819435656d50b05cb0775eae1811466d5969c45456a746d108906f6d284302d5f0545fdb4d2db695f9ec36869f460df2e5a16d71a3424539a1c0ad05c723bec9e79077876878fd7772cc71b39e4cfa88ed33aa1cd4fe4f4fc2aeebd61c0bc8a0ed08c7eeeeb3add9c29ab60cab2a082da1e03514d66c91fc552f8d3e3a6435f859dee669e05c493cb606b442b77d0789d7f017f6ccb4028a1a5399cf9b364075df598517db7c00aae86cce9ebea1b98c6e22785cc05cf3ba0a9f173d90be48aaab52ba39fb0c2e99c4875bb8e3de09a6e4de7750cbbcb4882f25b333cb30ce2eb77971f920c2dd5ce287cfb0d87ed24aeff2f939b21a391080a0b8bac2be0097a38f88f644c1e8c8336ea6856ee682c7e91cd0aa37b1d497834aa5f08fcb13ded80ba92aac9c2908b37c28e6854446b80201b7f2d345ba02cae439fc1299889fbbc36007ce4a5197da56e31b231dd83a018d17de98b376bad8c4fc11b03fd0b1d46042449d4c300f25a7025a1f16f57f8e8eabf9a2cfe45dadb4d01ea02922be7255e81aa43d841f2cf78a98c6640069fb277ba7356a7a0484826f8f06c203983f441c72f1b2266cdb23f0b8ae1bafc17822f6f8d8b49d6d3c79173a4666f81b6795cf08c0dcf5c2cbf86dc0c35418e1d89d28bab89570387015951c980f75e1dbc7ecd9bc3bcfd5d5a8b6829bd40d0c56662ede50176a1008f207aa6d5e635073193aa5e3f711807986c079769157ce4f9b414bc372d3a94f8ecdb905e1d7fc4d6cf0087f39870304157e500b45a10c2c558af2c1ac24db5b0c4a38aa6cf4687cafe8dc00c7ea27ee2f9b51bd04605612234cff7521d68a3b4aea721a6075ca3c527998218e04414ca1338d810498836054d712d542ca80e803887828de80da8871fa41ce4e88da259229a68a5916986b242d7f0d8a22822b3d744b42a8c19b68c1528f1054517b9552b42f5fd4fc0bee98144a7c2af66cde7979acd6339285cddcfa44ec52de3d60a39bedc2f983b0466f6f7df732b38943c9ac966a1e3f5eb332eca2a3a3e1725158826fb5f2bb1f10c7beec06b02aa2aa41eede949828535ab8feafed71b48342e9b8765564b41b96b7f2682df90cbe60fb7e572361102834892fb6ffd1d32308137c8361ae67a37d562c193942e1bc66dc6496940a62739c76138656a13344aab3ebc3b7725868f0bd2fa4f86d3bfb6cc08d47ed39f6af9b804454f79f72fb1960eceeb032767113b77ccc4400a2bd1acbfbedb7c9eced1c564a5ccc5ea24f649690f0656cb0a63a8f81ca2618335acd7cd8fa20ea11b49dcc5350fab6e201ffda2343e11e82a4bc085aa30f4df112b962963fef6cde1bf71c7cebd6d487c84f23d15854db0017ac4e4eedc43c50d8313e5b150021fd10df19d14c2bd1199a0486f7c8057499139438dd905d40cd73d85787c591db77159c45dac3175e21de763183de2016ac0aab4498596b0b06131f81b47a3613f0cd9488731df9f8c313a6a5e37fd76bc7d13e0bd0ac93df335432be0bc6e70e19781a082ff5be3c22a5a6625594cbcb9ac65fda84afbec1d8fde25968446b6ecf6b86010cda390d2919c053edf82e594477bbe79547911082e6b6f85821fd1421ad0986dc7738d8656fc0376860d1a9c42b4ddf7d232f2dbe96dbf515ba971f7d41a538fba46e24dda489e0fcea5338f73d61bb07ca8bbadae77ed2687e672852c6245f6ed771fe78dd8382eee84fa9717fb6444bd6a7852658e62a84d327976173c0c9f8782da56121ace03b6e3f5039bb0b56cb1759af688ac0c8aff1982abfe31ac403c1fefa0789c2991fd81d3de958936f2885652063c282791a1dd7cdc367a611de5dab895ed17736510c2d9da22b6d408bf1b57f12ee33c35da73ed341b3562aa9635a699438558e33d24aa3ae2138ad05252c5a434250f1f3a25f2bb93804e621202b0f443d38ba7edcd4ee523aad4300768bc44e81299802f0b9bf6eaad0d50a84900352e604b4f131178663ea7dc06873b9159d8708277c4b71feb9e9b7c4af1886a8beaf42191c799b2df4c155a16f259220369e56c79423816887c5b3cd070ccb4eef9e4f5a67a04c833436012195c830665f14cc626c3eaa5c6b9229e34e04cea8613c9dc8f075a97fa70d5c8f02f3bc333edca3fc10c7c5c6ea57c0961cce55868010c7ec03cdff29950af9243c47b6cc34a3a0ff2d295f4dd251d101f6dcb7497860e4404767e62e97cbb2426449ace2f0b2d33bd4a7fb7c0aaa615c7bb8561baed4ce10f8c382951db1ea75066c23a2c32b2e23c1b8cba0773eb029e0164f04dc306dfd605514879db322bbd1701156dfae9b10936ed01b59f236485fd932c4772db79de0e8ad10923bae9b704fcba9555d30a7812151a61adc8a9114cd26df665db09adcd4f7dc73edae10ff70015f6e27685fe60b6f13b5b2a6963757b83530140791c93b81b41f593633d2d608af5dc449f27692d3276192a9c652b252116b4fded9a2f4b79739aa96176a0069f22195066560a8d6d4cd55a93012373c8f7855c94f1acc057b952e03906960a876a3025b0154ae460de9c1bcd6c4e096cf86f6e32b0aaa146113fe10680bd7c070e2fa5031294a6b82a93c4db2fb53b7cd58bdb1b5d547115bc827d0647155ebd4ed4d1aa6916cb0121241f5b65122e36cd260b97f947a4a9a615bac3fc11ab88e122cebda67715d69cf3f8ba81b7ff3a800c96392692d310f91a322f908fa17f499e21ed23012ac0684c1b487b595a5d9e230daa49255cbdcc1da23e4cdd1e6df4bb57db00e99a24e28024a0c56c252d221010f2572d01ed9024b706c20544a9f58a0176a10a92a2fe179d3b5a6a0bb3f7e587ee420ec7c7c47b4df448aac1ec50ed7d54ecf341f1d52a4611312130a5da7d8c73ee028f2b0c9ffc2671877f7bd053f84201648c33b8ec85044fdcbeec08b47528072547065297a10c854176c4be04c70c6015ce82d55c9f66e880cdac5f50a4c2fcfb5666bf020c0c6ae59232c2562c05427465af3dc0927c05e0f107b9568a73db521accb012ae8e6d75be02763b361f42c5187eba614a70e364d8977267efd50a48642249021fe208b4df35dcf3a93a4550df09001a801f3f1dea62ce78083b9fc9f185f10ba6cfbdf2c9f9505680413eb5ef4ce63314b9c7a9735004a842603575920bf681303f2cc17b717cd766f7bd90726fda5d8752b50760f26b5b7530bdda43372f0d88eda9009af635800dddcf22b1578dc92b61ba8f80dac1b6edc337d125c0b813617dd856f30f31cd0840f299c490248bc0cf6b5bc0382d5881dec6928a41014b2d133b06c6638cc9a2d6eda4204ada02b63e0e5daddb70fe6ab4e5ac7d4a5cdb88e0b6f526e2c605aa7a09a784a992a90465c8fc8f2895b2b6e75840e2a1f1e19241cf4933442abc96f1ae6549c8a920d25682ced4a2f5f3f52f8614562a0485881203ea0fa428037dfcec2cc9ca5b861adf7853d8daa279d2329547f9d60c66bcd02aff3fa559705c6ee1daefa3582e5a0120151d3f75e4c0b4c5b9835c8a8031abc1a6de4e7975dc4c5903bc27297e739a64b25d4b5fe2eb126d18421dd8c4e301d18349f4ef6b8ff59806985079219176f185713c146ee0323af22ec506a0ac23880ea55c5519b495701e6481ae8c0ecd9ae7ad1a9b219cc61594556a406939a26e4a0cbce6df87d51b7d7df434d9cd6d023785705c7059c9cf84df60686a3e2b57f542b53c8349e382350b31f209b16cac9db278b1222d4b45b9f2ed9444483c90c461561783d9e480f95bf14b243e858572d02c13e9b8124832628a4e74350de0e1d88ea1da1e159358119e21aabab0ada80eecd4e6d850353267ab736caa8243551a580e5536550494a588c2d9e5e22215c148cab5f77bcef7f07ca23c3306d353c6784f094a6e28be1d4a495181d766347348c5052b92dc54c824095e1d89372c27ba1b185acc4d13973a9b0b37c81070ff7132598f40dadf6a80b679de6221a6f34a891bf395220c7d6b19e83a8927bc6f7cc51a28f02676b7b774d645384c4cf1d805000d9907cb1ceb02e843433707a86698f1d0430f8a1089ca82693b9b130d134f0cd778fb8b614ec634d281a66ad44b26e6d7b0f4af362828daa2daa43183a92070b49f18c48be047e53268ec851c7819904f30f2941340e59e67bf191a53c25cbdcdca56867d3c8d3acdebebd2940dcd6588b7273689019c696065c43567d90fc4fcb4c7172a8c50989074238e2ca7a6eb41610e29f0e0e49101cf39798dd89050315760b5e9b3872c1f48162f5bcf224f26eb978a5d23f9c07bc5a331308d1312b7fbc2434ac27cb3da76d1a3121626e7cd5a89fd4aaf6028cecb1aac29ea88c1e6fb00e1166551e3e537e160da039dea8d59bd4ec5847f5898176d28189811d289ae154fd655f1e1a2d3199bf9f2338cdafa8b9117abe48a3b7aa2fb9c2b4411ef334e2904085d30c67cb3d4a91b226d27566fb70761eeb67bcb3e9093a787ec9340d1ff88d0b48d1e8fa773923e623c2329ff4353d342d806a6779c722d933309b7af8f39f12c20ef0ca5c99edc7828777d031d511284eb63db00878a5b44f830a9fdbf377daa85fb369bed4e04de7455755d16a9eab2ab09e9ec8a85e6c214ea72359581b459103c16b77106e29febcf36317ea55ddc419572e62c4eddae1d537764adf8ecddbae0d72748614496e599f5022a71c12185014a461ca2ef0bf1613d4c8a484f9021e5d65a4bb1d2ad925c8e2b79adae5d30b6d810b51030d4dbaf1879e2bfe0e994ee2a4634eb7ba7cf8a917960863b9546ca2d292e8e3dc55afad1d1a8d6e9c644dd2149ba4f5f4ce772b28be474b23cd679312f99075f1175b4449bfed0fcd316bdd2a46ae7175357c422ecdfbbf28eb3fc24355e8251df72c725ae1574a3005c558dcb8d4aef1c84e9bcca9a2459122644e5951254adc68c63401563546ccf0d57e1b7bd17ade4f0a762b1484340055d48a2897b0d7241206d4e36aab645bbefdaa2c749b1076ba8b999a5600b86dad35ca209f33c5fa056058c40b1e3e2ef92a3a5b3286e845161452f45e9958a1282c4b86504fdaa08e5afa2b9126b9ae228995cc9b34f1f5ac5242e6a93f708931627531b3f3b99f63aec31a297d633660cbaaaa9d8c52746b25cb5a59009a96dd05d57811094d010fa78d72bc756735d189de8949bb7aa92902cd10427c03694838048aa6d95194a6488d85c05c0ffa01d0cf415956a6b91d6be4f341a4b81cf4dc31408c96f39e8bc3030f366096b61c0c092a4cc64026793c10a8ad33de854a2e08e0c49ec6d406a8441b69016d257a55dab12c951447e97db10dccdaf15c2ecc5e4b3a3ff058209822de356c91e287ea140fdca172419cbfe1a62bdb7d76c71ed00f6c5d46ef6e9775452752e847c1e74c697803d1c657cbb5a3ef9d61ce357707b91a4367eeca369dad96cba23370c4020a47c1b31837d117080aa1a7f7982d1e4ded0d2fac318dd9964b663c045bba76bfcd3d3a30436e1860193330a3689711ad8b118fd6b05d19162ce233fb307b5f0eb532ac480963e7046e2fdbeb721b0f59b3dfefb6ab4976bc06aa842f05762cd0994aac83438c98b2705ba4a437184a05935c0abb7a87de8dda06afcc7777fbc8f149c2f8a22f0e304a3bd73152c68f57de1af080757be4ec8a537d259879fb62d5145e65baafb0f1456c4880f5ac2812ed04164e09ead69b21f417e2be057ae91f1a1209ccfec2d0605a61db35131c580d9f8aa67f20b63b8531730d649934d65071bc58a1f682f1181c133c18cdffe758a17121e04da159f00603082a54249302930b8398cc693f06a067ef58adaba4334601d0d604e072586fc3313217bcb1bd32cf67fa07f622a135c5b1dc3b77506d10730001c2a7050bb28c38534173ccd310fbff1ecb963937fcca6ec5108cdc0e041ce76b4c0637d363eea7bd51ccf2449359598962bec8a422366aadeca0d9d0c15de42baff5e218de2de89a3ae3ab492f06a00b2b2b5e79fbe0c97ecf1d9ed7d05bd47669c82ccf8640327a82da323f596b48c7a02936c149a6b28140f95fa872d2bb7b847ba3c6eaea96ecc1f1b3afeefed9b67bd03379eaeef62338e032d55b00001b79b276fef90a5422bfe74d41915618d29a9f2e7ebc38c6aa79852a4d1e9e22b5ac1dbeb536b84cd0a7af9174714120bb7dcb4c51fe8b9893e3f50438eaf72043ec4da1e9fea120c15e5674206aad0d0668fe6dd5ff05473f06f4d1b36163bc2b56eed10429179903a7bdb81a5a7a3b5e80d6ed31a8fbce6b1bf778e2a0f9b98536a20990f4bbe9a4cb266de4c668a0f15e375431511f0b017cc151e440b039a77ae09c9c9c07741c78821b14404c06f12ec1016322b4b9b2b89f74297a614954608a3812032f95f179bf7ab0a08bbe1f4a23d885b6e7ca6471a8bd5bd381107a16650b4292c0c5d3a75f8db5f16da411843c2297f5b4318d0479baecf2d46fe9eeb6bfe7a35fd078fcc8c4550fe2e0e6487e9d5337bc5b8ed98c6b70ae596ea7d825e3fc3255bcbf26f7eeab742a66586b9c98c631d1be17e7599ba3d4557be9d1f1082f543632320c25ce93f4d6f0cf45da113488f1695416d9da844a64183bbc92827d88f45e5fb3d8f2b0070114be92278fb1464d6dc6e4112c0aca78c1e644115390415e717ef5826b5b6bed04e031753b98341d31d90113d2c8845309192208d34f61d98d883cd0be120f9e1617a611bf59b7440e0fdd628649469486c6d6dd92ea4f359e058413abe22ddb786632bb0ce6c64b2d8cb6dabf41c90831f820e90d173a000e6613b29b87573be08c1b7106b1e606558a308f3058c26d4604841f424c19b12f28031fe9b9572578e9951f5824ca5f209b13ccc425b537949e288cc556e7e0867009bca2d4fe41099d9b84f2f0fb72acbf934ba43965e48d11a6be396b313cd623802cb3c063062902e78188a88f1a826cf88458ebf2366f14fce55e29f6c65c33957e4b0b1d61df7af63f961ddcb6f3c03b06c428e2cb3bd3d0c07bd9314428edf3b9b00c91a64907dea7fd55028597ad1fc29d689a8f850d77e1471f0467e40bbdde529e9658f799147da6e7cb1d9e2e64263c57f4c1388d05068cea2a02316e776ecbbb02ece56f8b4539a45a0258bc9150e80d7e278b3bcb997ca2d8eff8f3852e2ab35462fe893ca4485dcb6e009d7edeca2ed0dd4655ebf496311f14be011988404e220f584b8cf88a493ea0e86a88c9b4dc636d67ef0f0df6e018d33fea8138c330f2ecf5a76a1a8daad65f654a04d62763071ad23766dac24ce70c46cb5d37f40a773045653b073b191b746f039555b2a91482a7d4bf44074cd051533a84a350921908fd61668f14e54d51838e6f8feee8ca560646c47e5c44fb408d0489aafaafbc06826ff1d37bc2f0d1a15f0cdbf2636b946c43f5d1a7826e756e46dd608f4b8714c223a94d0f305de34809bd3df540bf4eedc08720b97565ab2f4d41ca60cb19a1b21049db4578659f782802e0296995e609cf7fa347bf4118e368e9d85d9eb78acc5ec018b8057b1bc458544f5ecfb1adcd2432bcff35fad4e281cd6b4e5136b8a2178f88ee3a08389e3e07e7eda314dfcd1c1ec0016d332ecdf32eee6bce52efbe5078988441e40c0e148d00071e9f1fcb1f69ec1f185ec88e9158c38e49d67824b73834f820de70522901a2da668b9a51b3797a5c6a957eb78eccead487513f0581061923c2344af9eb78cd0930b898dcb6dfc2e6c22b19852f91678ee43bacda41daa0f72843bc3dfd448ae60185320055ab45511fb200373608ad970579689b34dc521f87ef664abe0242d8a9928c7a1dded451d110819ffb3d0a562bb14fbcfbf81f3df763a27caa87cbc4ab2aa007def6c023983219ef5169fdbd3fab9bcffdf0379b9ee4bb3029a9195454a18095d6049a071cea4fad3436209d59f524bc1cba881673535f00e55034fbf1a98eb27bd9916d0d5ff3d072993437de463c94a05b9f8d791a2df807210fd9e8f0c62a2a9528d4b6196c59052dd53cd89685a601caa5c5718e27741a0b63e2185ae93fb978ecfac0d70b5b27831c66269011f9d0889000810d5fffc30f90c219d0aee31e50c1d71706f7c801f7a1640903762299b6750cc00f44f53dcce7b55bcfae793ad18e758cb2c851a57b6b4d47bb433b935658de90d8ec4a5b4c88a4c9064e825356e64d82281d08045f6982448ba94d9c5be9d48a1a264642e0390da4c220605737f3ea9c71923a5c5eef13ef71baea0d742748267d40e95adc8f1ca65485713e59b2f12597a26e45591636ec7a32099f7c3687cd2844d5ede44f4e0a9809e16c6bc9c74f6fdb960655916491a900e7feb87716b4aa5c7a86723bc3f4f35a9fe8624cd9514b9ec3b63abb354e4068b368383c1febe80ea1c50d069aaabd3b7b935ef569542e14054db77baf3eff82da02af6041167fe3029b6f8a8ff22846d2b472a9c545e317304d65c2632ac66345b3dbfeff0a86ef8049ab4caced584a6010747904a6c09ce37cbef590187f5d941c9e0673ce4251fd58556109dc386cd528ceead6276acf025c148acfd69807cd991cd07f2b9b3dc28b6e6194a7b0bf00b2756d5445f8a9324fe31394334a2c8dbee834a7faca54c5c68e9df4668a97b326f4309ff79e9a646cf6405983cda08108d00c10056084ce11602bd4e45c7511a43a0a363b2af34f44e6b3199028a62bb1f061da705ce4c8ace6e302f2b58f02c7a1e5888b91dd4668af5a1bac79030980b3fd38f933ffbea14a5f48dfd48a28745a763295a0c8eb67dce8acd28791576522609ed80c1073340d4db19c862e0ea2433c484188dede6242cab41ac63d596d25150c9383c0198cf16e8050f7a6bfe4353bb8c6c1d48464cbfa3963aa9ec46686024ae661c03855bda041e14d1aeefa624da4c917d650a64a9c094a3ac18038efc2acb71a0c6f3ebddcaf66b16a64ab121e322e412185de21ec3b2bc94b73167d6912f02fbc5ccd1d6c0692a9ed119b1cb1640887d0e16c85a18daa7cf7ba197fd201ce738aea4ea07bce80d44542092d154c6e6b2a1b972fc81950a62653e4f978b03f48a41814e59955f13c05e523fc50a0a9f9aec5120f99d88f7e1152e9dfda32c0663d5db7602c0035e7500554904d76885c18d35094dd2e56d7fc8d218e8b4a533e87e6a0e5c3c0ccf7044862e263ef03fca0180da65a531052e0e6687c61b050f3c7ac60c3e423e48a836cdbcbf33122421f9ec3522801ee33c3db8ed81632c1589497ae2cc8826346489d0b616a67197cb8bc8e72911b815643939d983aab88263ea71add156f58a1bdc7b2cdae7583535f22fe9c1a32aefdf5c6bd4d13c66843d5e2657b54ab22ae83684f49ddccdb73730b194de1a792018d1110ea1463d6ff31e15f4be92f5dec9887e27df76964e26f4212b476409644ee42ee7b5ca1c816e64d2042963afe941d37d01f38ad32d793b40da07c2194d64f722e10232695cac3618c0ab93499aa70b9b806f89d7cf694a1b0e240c962804c7d2a43ada48c0fc32303a3d5027d465178fd883896f60721ea2aa53b85550ceec32596557ca5586098a68e6cceca82d2cc0025d5d3ae556dcf78bc7771898ff37484eace81fecade578bd3f97479ce9e247d855bd21cada939705258babaca90ec1ab6db44c818352826ba70a1d2a0a791456aa552cd0e0636c35e38251b8cdf27d1b2951b6aa14a500c5ab2def521283bdfa184a25024b2379248ee087ad96617da9cbcecccf46956670981589bfbe912e6d412625f30e51247410a25f50370a6e83a0859a21fbd555b2aed5fce5cb76dcbdafa7272152be07c927a6c20dfab9cad2e3b69cd4856285d2269ca4c58ae719801cda64a6ecf55c9d430de08f2481d72b079294cbc9f360c912be3cbcb41c2d1e18c857c3da10ecc5bc897575e421bfbdf1b26eb68e06f0696f1cc980446a4b48f2f9769e3223619822431abe91d69fa5d9dd4453598c64aaf9f7a1ab89f0dc3fc8dd915f25968dc7a1d9943ae81a48044ac91d65118b25d040e32d8ee3f36ba1a4ccb483a3d2e94d49451deed197e895dfeb57c6806ba309225601b2eb7cb7186ab9536bfe1c6fa21c4824fcf21165a90779681cb9fb9c35a33cc868c4c4dbd138017d2f01a75182440cd96d23b138b2df98358b2da14dda1166c16f6fb5256d6d67f58eb27cbae19782236fdabd2e17a05da4152b66f873345537c9a0853c0a3295c49e7bbb9ef482845a0e540e65322f01e22179823125ec9653d02c0566009466f8721137910ec8a30b65f1276eb88d724a14f7d9f2fdeede0e6ddf5bfc5f105046ba8129139ab6dc6d39f15bb7aecf5dca63e2451d2a9e43a804921f984d95057a98c0428888dce06b97db6a30db2ef2ab2378a46b92c33e0f383840318298182ad131ee607a375254451efcaaf6e62d78753ed608b17f0196ad6cc77c2b0277f6bec4736a61589be6bdd0ecddb30bb5e3a3343c0a51c27035bb4c7c76443960dad1e2bfbaa7b1a3b12455e2afebed921ae7eb98e84f8975a82eb9c71cda61b268757f1d0a97e98e4af67554ab7e1fb7c6e0485e965c0d2cb8557675a71b4dc8ec496486e223ee20404a0918a84f84f02af5e0aa9bc8e5d6b2826432361a455d3295dc94faaa01b224e5321d56db3dcb0a69934911a693426daf0aa0e110224592c6303d6c6ca6105d84a81bae16dad5e9f3f6efdf10501686f5dabea414ab2e6329901971374f785a370a85086433d0658d3a9be1b98ed7027b9354bf59a2fe4f0746023b4d8a5d8604a6c4576f64cc504519b59d8671ac9b0303e19b7f01fb955946b2a4f36ed0e19e6dcb07310a0e0127a93f3fa56f1967239efa2ebb5b29bb97fc38e29827f3ba9a2b43834868377f84a06261271349b441d8b226ac06fc5a34b809f66ee87a61c80a9a2030d2bfd21a8604b3b38e518cd1503b2e67b5581840be9f4d732a907291a069133d436e3e7d318444a4a858dc3306e5ef6737ec00eddf75e2b9ab4bc4b0409011f04a9bcbd78d81ee8a38bbc6447fe6be96cf8b83519e550f7309f0b11351fde20d89835a6e0ee4a8cf335cb9006a7a3409a2e419e66da1ba3b1fd2114429926682eef8f93bd9fc261b57f9f10311b067c6c227d7e4c34e96d57de0693dca3e3b9e9b5d8dc91c9f65c628794f32dd8a525f624fc87672d3690f76b5b67b601bc47e37e1bdb609e7c6f292383c613d0aa06160e4aab9415e01f00500680660cf0370e4e30e8222393938d37733f78a3af139eac64131bd14227218f6c0602018ef0946ca43d8cd940cd0040f53c7c3c1f585b15929ec7437c6d3540bb3abd98fc081d15fb1f3c953fa3f4da0cc422f8bc6a670c28f7da3a89241e9eab9fc6121f674e9a5509c7557239a556d77d1282580b8941fe13d5ee4dc031e19fca686d6b70a372303c6f52be0f34ad422b3baf680c499ab541a0be6efb9e58a3aa32a7411e23a1704ed660603baffdf23911658f3540efc86ef5626c2d96824acb403822da22b98ca25ecc945f338820c4c7a1d7782aeadb0542a6241c65ae4973905b9fa314cdd0e8b61ca9465d7c850c97bdd8b0d6f0b95bb125ccb6a9b18494ed928e394472f122f6840c68d999f5a3f9a91afdeac3912a5a9d0340f9d7b71e32b84fabe9ff061ba48c37b3eed9da06942636a93879dc4707b7a11cc2b01393565498db5b76c4be95dc766074112e321825b8887729d6c5079fd44cb98d641f559fc690659a106a04d6ae2330914023f7b1a964d85254597d94ef3dd8ed34a9a6e0e8c16667845eb676ea1ea1a48348d0c04dac6905048d9e78ff2c6d268a02751fcec5c044d193078d9ad8fa92008d59e94375a0096f7eac56768fac893d33f2e67e229addf7cd623f585f4dfce1fe3453e3c82e338c9519d09fafa7b0b5f6bd2b3a812f1796ae64c1fe3217668fed517806feb024fc236eff7be4e1fb5989709d48692ec9f4b87208dc281e42a259814cf4ac165ebbb0e5fc2502bfb2e7c5b1d1fc1d322f177cc7e35c03c64abe17c3fefe001cdb2d3ce6d3663816c1989e261fd80d7ec228a4f5d58e8500207804432af6ea5cef9b51865ec10a6a1c9450ed3c0695ce3b898f4dda269b045a648f70da7b5d131bea52ba56e9fdbcc1ca08aa597bb8be007a829dca37534e2ea8a6f05ffccc4aa5f085339cce19ca84c83044c31cf9b4f937c0affbbc43435fdf249255a0521f825b6e254518651853bdf7e533a2853fb8aac56446d2020ae53d74a0397e353e385b20b4b5b88f80f7559c978a9fdcd2fcffb20ed9ba2262a165598406448b4c3c9cae9b9dfa998ae39effd010c8a9b938e93d02ea060c9148def39178d6f4b5bb57c8a49d578199d7252d12b49f810b4cded8446d3a7e04feece6df158b85e235bd6701de546eecb0f977cc3235422aa323580772b726fd152e9821689acebe36d674f5eb9b3e3d4e55946b88a656bda7c3e9b00a1ff5136d2b7c58ce718e37774f6676b2aeadbe7435adfddb6ab245e2a354b72202df042f42dbc6062d4b485c8ffe442705bcba0fc4f356dcd9262bec35521e3f8a786c02a2d4b4d2ed080a6d544dc9c11a5ed624d0c5ad429cf7663b208103648be80a8d6cc57d6ac49a47da571e9659db3663251f553502edd8d3febbbc16ca136e9b522236af76480c69e825e0e478a508f8a4678f4a714c3db5ef659f5527dde35264d4672e1bd4980e83e00ba90fc4431029981a900f26fec3a858fa51c3c0845b41c75e898a7d93b807d32b33cd6c43afe8896aed9fcba580f369001c5fd18edb6996c24fc046fcaba41fee550ebe138b9714dfca582df4429a16f1823b610472aa0e3b9f1a6e267eaff4829415bc64a44a8851f4f94229370d91541e2459181438d282cae8bc05c673391da5f65383129373c3e0a740909e01ce06deb1ef60575ca5c56b1e65eb87d2224fbbc2bbb0fcef23db256e41349cbb76cec109319f3730f84979f0cf56640ede63318189f7bee37f86f5c8117d2c6770c2fe3e307a4e297028e61537b9c461a1e69d988999d4609d3d2c112969c4a080b51821f70693c4c2dae1efbba4ca75c2f262a2388a539d935f428c140271fcce8b91e3b65fdb95223a88fbc19f0d8ba132036355b84e8606151e6d6db8283cf660638d27c717c47d91a6e89853d7a64c034b4d9b7a105fa1d2b76dfb5f105b5d5d187f1c0108f535311b63234fc1773441fd2302de80e3d26897f32bfcdf475ef3721d9cb84bdaf69e3036c454f69a5039b5f60dff1509801eee1d79e7e65e902b51d4af929b1a8226a65268b2bed89d3f15d67b8077534c8bae525eef1b0603e7826c4d410d36e2dd1786535a011e39646301d225badc608b664849e4a0b90529d8b3e7d0649a2041a04404ba05eda44c4d65c5794e9a325ce1abe4976e252943b07222cabeed2e89b0d1d7ec61eb81d6742d8f27243d94ac68194678fbbf19596378f1bb20ad709615310c5f832920f18c5baed66005370eb9db5e78ef1a05ae0d63867b41e32785ed06eb70968c71edb502d67382fba37d0c94c65eae00defa5e058c18ffc09723ff8a0d820ed748633ba775cfacb2767343feb2667ab10af87352fc7adcf9cdfd8324b0bac725f378d09a76cad319bc796a7efd6b9d7609f95170c6c872934456f5b9754c5775d9996dd8d29d60705e33c089dd4e23d884ae4691ffc60fe02d10c1b064726434982ca0543926b53fbfe9aec864cb7e20c8b684dd01d01a44a03ca73fe805d30d2a14907796c6ca63bbc8cd8787e73623b39bb8a55e76cd01aec6d8a0df55b5e6defe2463fa2bd11730f1960047e37cf0004c00554310c5064f9f892bac47d9b50083e8c139a712c946b9c824e7e23846c49c8de7b6fb9a594494a19f1079a07bb07474fdcdd1d0c9a46bc1553352a8063c79c73ce59a9271d211db9bb1760ce2f0004340d3aceaf41795cc74ad814a0da00b286ab48a6652525d804a652a593f22065fa3c41327d9e1f3fe5943e27206752e693ce294b51e080a34d1e16326d36497d7f7fda70d97d8c73be9efde9512c3176dfa146257b24a9dab787533008d458fc6e8b7dbb7db7bf0f765d28312d53ed2b51284979ca72b77d7f729954743681aecbfb3909ca639348993d89c562518c75cc84d5e337c0eaf1e7a03d51c885da7f4c1172979dbf13693776fe1ff79e257e5fc595684529bee8a8331defc39c64daecb1efcf1e469ab4c44ff44429c5b9ff1e214da5fbb9a4492e367cd67377a8765c765d35c8dbcb9820d3de868ef7612e1b64f963aefa282885480c37c03e25701013e4895801629c1045051ca0aca006578228e1a143e988172931c032a44b1021ab2033f4e0a40d6c1912e5064868e02109246c82f0c85b3e2582c88087205dae131ac82e5b72a85ac205253d4e20ad1ce1430d3cbcd8b0c49624b8c9a64e58888f2b04bc547aa660ee450f0c9b233eb82adc75d9c2ec8089212fc05eb26f09c5440cfba3504cfcd871f382faedbce88131a39860c18b11e785f95eecf4c0f85e9f0e9070ca39e7dc0383f274424334e610322f47fa3b7404a7ce3153f8b265532a8a31fd31e71212c6249760d397935222314f9b605c4fa33ac2a751116c4a7df81129a31fa369f8a569d8a569b9a56939d434983ef2c595a48cfe126ecad48f1c813dad554a597d31235629b32f234a29936f2b90292823ef5add1f8f9b25ae3c2b47cb7160fbf701ebd9043817249074ec4e4f39f7e57cf4d9c4788e7b36f986b3ed0336d6538ef6a5fd80f51705b578b0a63c6b86b9ad13cc0eb6b06acb11dc5497904a10255ccf14fc13e3841a7042fc00999ed038890109292160f06283130f07555b74106181123e9c785244c0319c608b110f4a5f9408220739708152132f0801922088201d711e904ac0c2416ee0c2911ed4a6a850e5052924c10088244b4ac4900548121b10265454171420c609b01f97c0a6701121f0a065881f3f8069824101498e68a28b951198e0079620b88a820b84e181071e4e6a27c8c107238c40c245cad4122f39d8283318e9f3b17201d0602acb0d9270c10da8108009090ba4e880840492231d0d2006d23305ff1420c609ac2da174d003f703f93418423ebf6ffbf92fd8d6021e98051d40a91f4c074e28b725940e9636edc6aad0b402257def3b4fe697ddb37ec6f759b37411d310f8df17adbe7b099403082432423222a96a3d8e9294786878cca9f5de7b318e8d1b385c56e5538caf4fa38e366ee018777cd67dfd9e3a7add7fbfca9d88aba55689cf7e67b9b7cf81df6922efc127fa62f7fd0e71dffdfd4e13315d3dd4bd6b22fadd13b97dcf1377361299fbeebdffdef3c41c409f9803c83332dab3de5a8dfa12a872eaf3c4d8fd7759bd3a0343de7f19a8ab4f1311e51c40f469bff2aff7ce1a0fce27fec4705915725935a25fbddab8c17d27b463e5ef89f43b31c3a6d4ad12e2df7ec67dab8becdfdfee176d967e900484b6b7d6be7dacf15b31e662ccf1cfb08f39bce99dab7f28b54f0160ddff0325cf7c5781377176f6597eeec39fe17d7eeec3e762f5b9ab87f07b9a88fba1ef39d67f5ff550077e27bd9dd773baae9ed33b2e931e8c734d348f7c66c8fef4bd773dd3508bc9563dc4bd4b135909c47d7deead048a558efba297b62d4dc4445bb2fad5b7dea577ec6aafc41a085c5ff4e3d24cf55bbf7ada8e11ad9516b2402bcfcbcf7d9137a328ebcc7a3dc41181fa2736893e3df510d7e9d735720061f186cb2c4e90bcca41e9a6c45fc83939936a528d37377494374eb178f2e6a7cdfd1c40d67efd21fbf5af26aaf3c7730ee5f1df3beeee4495bced7136f6591113fe22faae97f35b2fdffb2a7db6d29b1e7abd83de0c73c270f5397426ad54bdf83981c6125472f6bd2f8ddc7b3f5c6d36f7fffe8dd2be7713a2814126e037d19b54d9bbdfd6390872dcfff80465fc97fffb1abe01ec879f63af445addab07455adee0cebf89a128a904b71f9ac51c7b1351a09ba5670da608df93fd3d28d26eecef7ffc13b9f7c44e4b7d4347faae1fa2efd2580fcd6fdddc8fde1fbc980c1ddbf4e938c28f9f740ec1b0cff3dfa9fd03ccd8b6d9122c2187fdfa06b03af61ae1470d7f1bfe4234fc7ecc044c81edb18ec16c360090a46ad810a2116bca28b67caf21b125d4125cf6dc34288f0c48dbbf004b48d9fe423db6bb749a73c230c104147b88f2b88e9940816ddf00f5adceb1251854a5acda7eb0a476854179e68ed51f336c45983cb6d8f561d2c7dbf56dfea6ce03f85b19fef67328cf68b36553ae49807f0e1d47d0047ffb06f0b73a9663ffc85febe7fab0ca92f2c18b35e5903a91276f62d3a757f43d278166e75337fc71f8d7f0b7119bef719eee34909c52d29a269f53d2398bbae7de01de63a621eff17f6211f53af9f3cba80343a635a4ce74ff26539c4d35772852c7959852a24ace60ee79d318701a9612cf39ebcf598f3aa3aefb191cf79d2e6292b1263906a54938e85fb9227da49d57e4e5c418f952fd24e79c73d6153c79930388137300c59ae418be7d0ce3184210b081c2c59b14e5994fd3cad3fd182eabe1b2fb3494e49d012c8921e433fbf7696ca9a0d00ea11df4a7fdfa463de8782f0ea5797f569133efef9544ecfb31ee3760dbb66d566d4c9ebca1f9d1dede93a1d9f2ab8325cc3d44c7f9fd0a20f761fd0a9640f72cf242d0903a730e2175e6f6585306b7b4bf7a07d85f79598c09d930fc986b8975acda9f9175ccad8ed519adcf3a07b34f4ea449027e2969c0d744c2400974d77b45b9b92a69545cb1a6c06baa15a56a7be6dea9e7df38fdc66e75eba9411b7e6efbb97d2bc2e47147fab0b6ff0bb7e04847d745444c45dbd3c69810feaa67fcd0aa3d16151ddd63254179ac7dbfd7be674509b2a82c8b95041d9dd565fbd3152adea1e3887d0018688eac2d05d23bfab41d310710b54ed6ceff893154a302b5ce4be544a954eaf439cc510e73ee948a26713f2a5225972d51284dd4e927861095eadeb3a0d00efcdc7b9ed889b126f947ead4cfc0acedb037be5c3d93a44ea54ed489b2a0d22abb4eeab4ab10bbfe8f02aabc57ee1b8a3f95568aa7287d92fdeb7f18851a95657dfcd51c3c79233f943349c3a7e24d19720aa86cf9513a50d952d33ee0e37a159dd7a8173a3ae569b1fd3d49faacb6d3f7977ee452aecf11f3fe9ee44a32dee4ee44f343f969fe3e4df8e113d5d03ceb67c8bcf734cff2275a4547aff9d8d35a56709a5a565a507236659032ff96152732d8de02627b8d8ee9d8acf9a1ef6b50fcf7530f8135138c2960e6697e68e669e6cc5f3d047b194d44f343aea7c9ef0a61dffdd0eabbd54fed4a2ef37ffdf49921c7bcccd3bccd330dc5be733d24f5c774f79d8ecdefdebb9f41f39deebe088526621ab2f99af79a9a9a8fbd8ddef19897f91ab106029b2fea6c3453ec6b9eb663444cd7682197f96f246834cdd7fc0c9aafd1aca799d1794fc3e9a18ea8d3314cf343ddd3b81eeba1ee699e461375ba3535234a97e104c9f43771d6fc47f891fd5dc997fcc8938c4ca397e82e0f45ffec4bdb5dc99ffca9e830481dff9695fa2d2b74a6d3d4ca32d54aa2f5c55db5ed2d2bdb5b5db6b7aa5a5e5a615c3bb6ffacd461a055d4cb0c36edabb5568741faf891eb06cf3e11736a8aa07b230c642461784fe5637b1018b42964fbd114fdc85d893ecd8fb6bfeb68a379064fded0ead4a6f948ac317d8fcba8cb153e91f6a8261a3511511e33cca3f588b1f9dc8cd573daa58bba5a8dce6a8c90949a504fb2e44d5096241035b2e99c45dcafba075d1fbe03b85fcd2f4c439ca6ab07c52297962e0bdf863f047ee8499b3eb8d2447ee432d7e7ef9e69c80b67a83b4d1443dbd0397b1f7e1111d3f79f2ef2bc9a7341024983e0fba2904aaa4d69d3e8d34c3119fedbc7be4ba259c7e6e7cfba88a9e8cb61f719b33ee7ec7dd64baffc2fcd6d1fb7c20992a1d01fe147764fa2ef353772895e73a426ea44a5445af5894b474b2e19b25ec2d1e904cbf3cb486915751a22d7a98dae9278f286866b5c90b997358ce73c3c326d9bda3be82c87ca6a393c21c8952a25d1d17bb63b9efa82c324d3a8528ff7542b349c653b978dbb6c7fdab8bd26b17d3bdafef54bd5ae606cfd52b535a2e317a9e3f868cb155e3c79c3c323d797952704d99fa7853ca76eea44d2b4ed7b9ea71428b9ca67b2c5b63fbfccd5db9f50c25ffdfcfc96ea90330964e7b3de67b11b7ed6e3b334d1eab37ed6d350d39acbaccf0cae0fff0bf3d067ffd3a1265a816068c11b8a39bb3c5ab383f2c8236ac45a6ab42d45da96266d4b95b6b5dbb53fb3d45853ee36adce952816b9be157e7e07ac9ef53fd425320dad74fe965814eafc141c5addcad244b426abaa56aecf9a88e9e66b3fb7b4cd4f934ef7e6fcaf7fe9a256eb5b1a04af2f9a3597bee1324b9353df7a5d0effbdef6ae98d44a8635dacd3454c45d2c31939873fb14e872151a787f2eba9e4323b8fb67d0a0aed583deb718264b7cf59fb23fcc8b4669f1ad99f55f6e717fb2e4e9628c59528fd864d1bcd603ccf16b14d6c13fb84675a2376ca36b154ac94cd62b9d82e3609e5a1d922d68811775b44fa7894c2b8d3be1106ba6f9fc6d9a781f669ac2d616c3aa9bcea4bcdc8a7f674dd90ad6cda0b864381225216a48e43a1339d2677b2b2c5bb20d9b44f861da873d9d4a79cca9df2d0280b9bbe4d8287d029cac213c5f85223e6aca34fa7e814f73fc0301e6c99e6e0b2d83418966ad360381497d126506c553725a6c605f96f8dbb35796b4bb7766b94a785d124a107e5994d746cf299d7ee5dda57e6ddc377194de4efd2b78613822c5ea3f088faf47b74771805e97bbfca23cf2de4b746c7fb384c32cd971c8acf60e1d3fc0cd7c33e7c9aa7b9536cb27ed343f95d9ae8f5e10fbd3e9cf9d74f3dd48ac9b1f9357f41999f2fb3fa1a4d24f32bed44361ffa54d8046aa27be4d767860cfeea5d1f7ba6a19a0f639a08df3084ed3b653efc221b4dc434147b99bf355fa38b646464bee663ba4702d1c6d5cb883510c4be28464c33c5646c3f7fd331efbb9fbae6659ed663448d962e93d1345ce6d2b1f9322f8142ed7a999fe17a195dc43404fbf08b687c46114c3b94ef8966bc2a363f3d14c668a70adff543e1bb5e3ad4614bfb962ce210a7d13dba7f93eedfda35ba8fefafc4e934a5a4cffcfbdaf3c8ef53c1aa7e4c5adad7c35c1d4e9bbe1787864c9f766bfbaef028068a362d874b4aa6ff43639c369aa3e6f31c651e21794ed1b1c59ef36f86645a569a3743f2ec52038304e689ca229c7af0e58bd3dc2169b86cbe0d97dd10c972c7eadf9740dcd5454c43f7b72fc2f72ad1717e4c08e37b5f4ed170598c6271fb6e7b4edb70d9fccd35100da9339588e041123d7842938c24a1e3c4e1b2599b4d52677e7eca4fb98a9c8d3eec08d143c49eef49ed200b0f92a6a453475f94dca967a5bc44792494172b7b7e6ea23c126a070135b02055430a45b24b89148e5862b2e5fe6032659b92ef96504ca43069ea51719010251c95bb2da19828e9b8e4ba251493126c1b779b14e1b4f9c0f33265ad28a59452f073cf3b4e6ff92f9ad0f0a61ba594527aa985e13c564a29a5947e86ed381d29754a69c594d270f57352aff6e6bbb136bcc21cf8551b18ac72dd07001ea1e7c9aa9c61a30d4a4727ae7ad9ca0fe4b86a2357812b9a9c02f3c90170b1e5eb1f624bf90490331bd286d49992a58c3ed6b42f810a604a9e3efbd1ef4edacbefda4637a58f5cb1b2b4f137c33a56be6e022775e84b5df31c7e362ae59161abd671276f69852ec73d5bcaf5a23039fbf9eaaf3066ee6c1b9e43f9e3326a838e756683ca0695a492f9e47be1cac6db903ef2288595fa6d8c65fbf7dc31a131d78d005247b41b476fd1e645fb32102b61ee3ac61430817eb8eef3be29660067f99a8b504fce0be300dddd5ff84829cdb4522d646fb84cfeea9b624cc6fc1cfb35bf29e2ede5af565bc36f8a31a11d6eaff54d9102b67e07ecc7e0dd02ef6ed9bc3d57abe572ea19113325add35b02b052c33967ad355fc99a7867ac2b2cc1ee0ba364ef5ba1a54e1825cfa751097cdde77d22a8e03f10f6ca9f96fa4347f940ec50f73cafddf7b9bbfb5c7d12b4b6d65aab05c120f912afa472f097cdfd138189151198dc8c6de82d10883cbf05922c678cbbbb0a2492d6ea3ccc49296dccddfc695b30d79d2075e4bf18f3adf327c745c8ddadb59616336bad55dc16b7aab5f6f3eca5f96745cff58aa9e162385bd271daa0a029c214e00224d0acb5d65c5f14f50a02481d281b05bab5d491df64a340f7943a52f46ee894beb27929d151226d14e88f6734d251caa7719bbc7bc69be9b6cb8032668d8d4dcc0b478affac48b3f7edb52f30665d60cc6a21ac6f586bed4b29e5cbdab9715ac4bcf066ad7d9adb6a6d753a41f84000a58b4f82d66200b6ed7b399fcca92fada640dd64b68fc13a323b365caaad76bbd8f592b11cb8ad06b66fdc9d23c70101ace055ebb53596e5bcf5d6ed5b1bed02dbda6dab77c9ba63ae6eada7f75e8fc0b6e2b6d5a7bbbbb86f0440192217545938c0ca804131785b711d68ad15e7b6d25e0a767373d75eaf75a5a99d522665e10576adb745af7e4f0556c67b297652e77a607b90e670b01fd82eae76e96edbc54bb66e7749c97671b5dbc54b77db2e5eb275bb4b4aaac55bb5d756bcdd25161fa63c568e96db960372b41fa8d5568bb7abc456bcdda5566b5b0b6ca73e95881004ae3fabbd1be636ee0359396cb95e3232311f95feb2b5562cf1588966ad152669a472863d7d1a0590c3eb9bb57e9667a18be16e85a294355f2ccf582c66c3b2190a9d2c6c5aebac3febbcb5566cbb34c9d8a09873a2909a00301246582167730977b905ab29809cd357aeef5c5a5a5abaf7deeb0fbb3418e31923a327a327fa846bccc0a69cfe56060cc2313e6b7df8c79f9d183e8ba1db7b5086eb9538f79c7352e9be5a69297556bf5aad366edbb66ddbb66db3735f6badb5d65a5ba51c2b51adda25d20914f37251a059f30d9f92ba0452f11e93cb54b19352674ad18793a2b3f9349fc61a6654a8008356af825b81714060888602e40f5bbe90f4e166535a11b67c1d49c2ace519ad41c462b1582b70c7b7d4e919cede59333292a9411423b465498c4f8341f6f576b3dd905f969696e4548d29027da31d783e71793a81cee67c923af62ed59824cc2a4b4baf2dcb8e49c2aca2b9ece859b2e332fa37373738f786d69f46528e1c37ab3c4d282d16b5b20083eab36851710df376ed52283e85e199a54a974d7f5be2b2e95f4d9b4d30703dc9f746d997734b9c53469e40b5569974b1a796a188a50b9919991184680195e796504c58d8928e43b2eba9db2164f292e5e3195c24919126c63d08d1a2e24493541608abc2e66cfb625bdbc2da97349965d324976db1d817866cfb420eb6b530b8b02d0c466c1b751465dbff41daf663d8281f51b67d1a944746fd7061aadbd5a35ca061bbe31c76da1d1ec36033cf3c4716961e47b400c4cea6d9b4c0346ba14b8f146cfa319ff37ec203af38e32f7bad2f5900b3ebbbc0a08a43c0420d5a78470f22c0e2021692f26c05fa191d09b3699ea940a38c5608a27866946978bf78b020f3f001869998706dfa314ec0197f99f60a010ebb7e0ec10f561862d7ff603ae020c67321b582931ddd13aa151702961d275081885d1f671b98c038e32f6f610ca254904a8107bbfecd394401ab6ab51a0f2b847ea143470ca27484d9512968d954884dbfeaf004a594524a5bec1a55bb61d71aa54b9e998b969b153fc8e1891f4f50fd00c8a62f696c784d6d0cfa9275da6793e0f7dc5a6b659032cc3de73248196e01bbd32481eaa0f85784b14a94a7c5c66f97b6ff34cd3ad9a78d9fa747de9e664f60956af611594a6db97944609d2c15ab6481ac1525c78ee3243be84a74c4f8719ab2d59e44c795689794ac121df1e3f0c8da2a491dfc38469936a12855cd2f3b680f07227da03c3d7242b1489fb9f17b12e5d91e67fc94093983399b492efb210693c73e7eaa65f2740f6bc155d8f8a5f4c14662e3977366c4c64f80d8f8a90ae40c87cb70903c29903cf5f1d31b260913698a801f3ff5217be061e327780886511a5a5cf274dd8f79225ff1c348987e4c0864b140cdca1208a66317fc192bd6832b6fa563f7257e8bdf8e74c49fc51d97e1678916bfc56f95f0db25fc57fc89e132fca08873bc649a55daf867d27d72ef4cc2ef4d5be988c3035f94a696b278a9d8da1b303589c740e48dfe0f9deab29d0682a42de356f9573babf6a6734c6e9a63030049a6430635203c5c098243b7430a96502902073fa87074f9410a3a38e2070a5498f4dd35cd5e77f729ca5d2b75da76566a05450a59be4743edc9a64654260fcdbdec1ef43dbaa46a29ccf479546b13e5a1b3c9c4a956abe9482265c9964d2995a1d569d34aa54ef74279becc1a5292582b58826fabe993f5293a52eb3de848add740aa6f267100dc858ed47ae1b6044d985fb573c1f4cb26b7d0915a9ac56e093a95ea5b82de14802559095682f7c820cf2f49f64caacd5a6dcf1db856db4432e89e5ee848e791bc61c2e402cb40ad474874c6fdac7beacdbe19385b3ded5b759959a6154ea42245ca93274d9a24b1498c3cd53074c6cdba99677758fa95be3da23cf72d129d65283e0b775e2098daf5e52d31a4329628a90cf430d4dfeb222995d1a497ed55d3f0acaa47b24705a8e692d24c7a7aeae58826d19ad7a88c3e1d22d3af4bf4eb514da26f7343ce40dd28543cf3f6ae87374ab729372641f245bc2537a5bb6f2b69b7577bb74d63ceb75a7d7a1cd7514fa4812b560e5baef015c6c8ccd0d4c46c50a450f152a4e915f50687458b51e602841c1d1bc28ed38b39020d8003a0ee58116eb8a8a150b7fceb13c2aeb8f2e8b8bbbb7b0e0742e7c26bf1e180372bcd12f387eeeeee9ec285e265131393a19981c16668646a62622f1b178a560a968ad5832f44a0bd15dc0dc6d958dc1676ac327741dddd3d47e680e0424707c8d4f11caf2054eba212d5bb8dd9bd489563adb256d97937deb7e20335b81257ac67651595a8e630450b4525aa2d974dbe91af9437dfc8af981a199a19d80c6c06462343531353137bc56c5c36285a28528429546415cf7a71e538380e37de0d4e87c38263d102b718b75176652eac0b102a08399ea34375429828a24c9d493dc72b08d5bab0f36e637881f0fed537d48511c982eb70e6f46ebc6fc5076a7025ae586f3f505959450e53842d14f603b5e5b291b17d69794a990d2f905f31353132343233b019d80c8c4686a626a626f68ad9b86c50b450a40853a8c82a9ef5e24a831fd62b3efc5501d4b0e2c6bbc1e97058702c5ae016e336caaecc857501420521c77374a84e0833049d10724070a1a3a375c4d7d1d1d1d111c00ab602a41c55c406df2b3f01c3f79560c4e97b7d2f9b9bba03244138b999128412132d4dd8a06506b74a0b0bb8232d357446b424f5a0a5e604105d361be49b2da18070da840061025c25b3d8120a08a39b822c534064714ba82c2bc060728b2da1b22449f901ccd6e3072e4c7e9872e4871ab6177ef8d1d5208f5b4261c1c15582e54a0eb0dc50856508a743ae79a24322db14d11d5db944e4145b42f9e064073e8ce03ae1430fef87ac43031ca0a648452992635b424929112165e445c928b684ba828409ae5cd97145074fc7952558aef8087245077e22aa6a47541047d9664ba8a825b28a2da1a28cec04604ba82d4b705d2a062b0a6090a9fe55fc4d9d5d5d0996199ad8ee79089117dcb0c4892d2500a2e52d6fc0820f2e406a3b38550172774cc4061f5655cbb74545121d49824852c40c5190d46053da23e3834cabf36d28cf44d214802d8522525c5653b26cf93026f233112b32aa482d5751d9f2c122643a4869428407134d43866849591a82c4854c9b4986e8900f3b22dc526522253d119259331c6df9f257d8407eac071a27a39022375dc26cf93430f8917513545bfe8d969915c430e19c5cc093b5cab014856ddb36154a90b4b32554103df44c4f055810e08b2359b428319141870c2fc840457ba234d53a5f3637392f6e2aa546b26c3a82116c4a47d0834d49f0c3a6479a8cf4b029b82b6ec8b4d7deef33fc7afbf3ef532be299e911191764daceb62f187476636fc87bc7be858d42e4faf6472132fdf9c2fbb3d65afb3d443c99bd39a50f9dd2c74ee973a7f4e1b69cd2a79b734a1f3da50fce9620ecea62d7975253fa8c5b4ee9a3624eb0be578b4cd9f33d19d9963f7f53d996514474d8f33d9a164cf67cfa15a9c56e6c58142192b78c2252b5a7b7a2ddd834c7566cf94ea408d0e69bd2e7b7149becf972b565141112d012644478ec09db322ac80af674265e60d0a68a01057b4a1f9b297d5040d920b5ab28f7107b4a9f9a297d629b6a48d49ee00e926202267bbe87438384c5101dafb78c0ad2c4cc117bbe8a39a54f8c4cb86554d2961d6efadeacb2278a155b4609b1818b6f4ed696514933ccb9616050d2933d7f0cc224a78562cba824a33dbf7a9595c6ac6818d854276ff92e213db0886d19154308ac2d7f3ad9730518b4a96280c19e3151428cf67cdff9a68c902221c86c19150469cff700f04de9f36df933e0a6caf465540c5df6fc9c9b2da38268d9d3b3d57a1733ef8b82d65a6b676856341436fd9b6f4a1f39df00e0a60fa6d31186884c530497428e89c23b64153660a50cdb320a49881726c76c19859402c725bf72f0bd90bd226e11416c5319ece1db91bf1d381e3287438725734d3c221927e1808c6048be5b4601110244deb68c027284002046f7626a84331e71167fb0030615478cde892580a468f2a4c2892e2ea0504ae184102dd898400985132d8821a684cac6892620354aa0c49cf841021a25463561c00c81d920e53438cc10249899c10916a605493248aa66c2341112c3f44586865961c9ebcb25588aa1e283309bb673839609b6bcb004099948b9f00e0b7c649cf197912cb57c708217584e8c42bc5383d10a67fc651248e51d9c8407b8d3b3f3a2c7090c419ab640f940851e3524f1c0054a2995810acb5085731338e81174640bc63b426c8cffa3330984f1c330c68f337e1afeb0ce34d4a84c1ae1a3241a947edcc14f3eb620a6250e053e6e90d216bc836978c1eef4ecbce849e2254998ed684865d283091295c94dc3b989da519093263039f81154822f60b8fc08b2a10646aa475053ad5291012dd4e8e8b453c54a93289bb6637f906b68a2898f2dca13dd0a79b5444724b768606d905f30e076e41c6505d9e6e00dc1a46baae1085e227f5b42d50064299ec5a874ac18ab8ad6292a0000001000b315002028140c0844029150108789aeba07148010719e3e705e99c9a34190a2288a6118638c2104100400318610470cdd46026df88771fd61ac7e604c7f18a31f8cbdfe09bbb12cb252aabc2150e1559cbeeabd05b0e33f7d2f4da79f8bc01796e461c5c52a51db29c0da3316f8732f43b7be04fb8d302868e8fa0d9397c1013e2277108e27d0945c3e0fa13f79dec76bd3bc672850015ec5e011016dbfda3725527b8a3ac97ee738a368def429800caded0d271bca861d5780a3860be1ffce07d2d525778274b95ca57b0eb5c0936ff06ad6446d5fd2e71564e2135d6fb2cf36cd000b84882f851c0043debcbf52b1afd3917eb937b43257f11d1684e9ca9544184a71e8e2d880f1014c1e905f4ca1c350aa02436249c88f116319257bbbab7baf949a97fddee402f4700c62ca2e38e7d847c2fb0d336246c1132fe0d4f340d80d8b892c6b92c5b6696e611a88bdfb4f718c0732ce528cf213995957c2a9b9219448ae8100767a821fc7f816e8517e5701ba80b87f60bc132f63aa389b0b0d47395e8cd0245a26a852f5d128270535a71cbd1c271b525d6c794d74a659274a56a8d85cf82d7b38d8a475b33dc95578c42072e8936475d75608839eeb71db6b4d1522a67ed5467682116746286723393815ab5470afc850e2b101bf9a16333a8aed6af3dde058656386afd44fc222c489ed330f1c24c46d868bc978f1b3dd4b6c03e327ca303d2f3b8933b88883bf9f639d97f04eba16eb9e1d982cdca4cb4a32ee11ab1be31eeeb9c6b43a1efd40c5a593726dc85157b91ac0a1ff7318eb25dbca0c0ae82677da3165a0d803e939a0ba9f06cda1c53aefd88e20e6afd03f2b686ff2cf5e83b6eea78bb7acf565b178feb3eba9817c1692397555caeccd3781b54a405a8e0308ad94635a79d14716372b54962d0958fa976833a4e426ef247f0ac97a5420d60919f9cee5ce3b98acae3b660868a0c386dcfc00c5ba3a5b1446dd287f4b0006a29746ae2aa591be2a694427771d31055be7326d22d4f8e20fd1d156b63b2b79aa31eb016834c10e021aa4f66c34c13873c12dc6e4f9f35af1333d1bc9281f41e2b0873740b62554652d90543a9dc98506896157e70a79b2ba39dc446041e5505115b140835d82a39e57b2e3d7ad886985bff3b29f114c80f3fda8d5b00f749111333a97be208aa4c7f63a4646e123daa3a6b071d0a0ca527fc0147d544d496e9da19b375f55b5a3ce060cf49d933b1ce3ed44c5fcfa7639fa18a3b33b2b387411edbc0a133c033d576521442f73c748ae035a420b66457ffaad8345ecaf5c1cb95914fee88e4ae5ef025d92eee970a1b26e8819e9b5ccdbedb0bf418dc3076d964ec19be258a7ce413c64bbd649c16b28bfcb3fcba3a6ed641033c971a461389a28d65386844ee7d0c487e489fad850342b5414a816d12009f3b7bc54d27d98cfac434b8c8d0fd65a624d9e8ed40a651fb5b7bc14de5905e3a48b81014b02f42e4a6aca4299dee96aa057a893ef2d1de7f8d2ac70abed835f1459a484ebfb8a35b41a655957cd367dd2126d5cee32a41a243bdb774f7beca9378f447f7cb952909a12c2df1458c97c001ec6dd174416f2bee6e58ea9c420ae0a78a2a2ff6fb6c6f15ea6c2ea88ed951f52babf2cb490816079a459be08df0f5a8c8933278d6f4c70e0585e4e7c37987248550a5cbb1cb8bba47057a970af520d47df688aaf04ccb284d7bf49ab2554871c5ed4f9073d24051b2925bc1c4e382c289558cf091c60a1107a0cc2070e5e832658d8a8a35e6dbf8294bd0e01253b7cfe990d234e106153999475c5594b82bb9482732905c7520ace52129ca5149c4b398fbba2c96a7a68a725073db10194131363966d5eb30dd9b3d744debdf380f99ae102deda26aef585f22a4b11742d17d7522acead1cdcad3c385b2938b772706fa5e06c25c1d94ac1b995837b5b194fe88ea9c7c903aa9434004842b62438176dd5a98ca08be30bbd2c7b66584b86b0978cb02e19615932c25a3284b5648475d9ccf60af434fb9af5d31e9c15b71c20010e28d0035b029effdb0dc24ac735e08fb3a54edc9ab04e7a4999df33dbfdc705090d04609f89f3187e07c65a6edfe65f4e9d21e1bff02558bb35f5f9035c104ae89d0d529364f2ffc37441950e6f8454eaed53363371d69536781f99e39364e6766bd7f2a95a129c6647701e0a2ad24ae7c4955f4eab7fe378e11fc84b3d9025309a231f25e449ed4ec492de8d0fb0e02886f6d295ff709cf6a330ed8f20691f87d37a0c6f9a0b0e2d848cef9b614cf1af2ce0b4e45d69b1a2651e83a702306c1149091a81f1ea5b4a8539454cca549bbac1c0c8f68d53314fde369a2ce702d95f01f09a614cb95f7c720697b6e7fb19ceff639cbcc7737e17e7fc1d26e7fb784eeff139dd89737e1fcbf97e0c3b19ec879f202122603a83bc8182c1d905b37329a7724dbaf8112cada310da8fa0691d09d17a044aeb6898f64750a3e54d0aa1d6db9ee2f8d41adbc912e58882bd6699c67159d34048c488f8fb847315c65ba6c1c989a4268c81c8d95f21672ec4fbb256844b6e7a5139d6c832f66c2b462f217ab806d6f0e979f6ddcd89dcc1b6452179b140e8859507d85a1e59fac7e760a62d012b2d30056c27e00c6e5ad65ed976cda83f685d6ee73e7a947a314bb9c571d7b002cdc8953247aaec6c136023a0e950e68becb849cea106c555dbc4ce61bfbfec0fb330de5168b0317e16be952e79d2d182215ab6f923b00151fa8bf6410d09e1484151d96da4f6ba6c580e097f1f3e68f2995475370c340fe2240c62b76836c71345abe7d19b1fb28d1ed26cc84abc784944f14248d105a8d29570a50b908a0ba16ad740151784942e81ab5d0829daa58557a044321d1e5cc442301672cf7c49a263bfa6bda2ebb10cc57f950c8797ac91fb2afc90ed40282e802a5c01515d0052b804a27201ace00244e90298c25ef1238aba543870811d0f051d5863edede2311388eec9418ac738d665f9fd2ad06fe9641c3f0e200947cb53b7ec5da82b15dc3a068b3b1a5ae115d599c3010d2de98759a19f21394a2c3106345093074a40282672232e7883c15dfc145bfbf1c56125134c620b91c2161c964ad4010d962103c012ac80d74d27c5738b8443952ec61578ff25619e38c7a8bc25a6ff9e2f1c958b8031bfbef08cc1b0081ef88d405bd316e719a475260153f8f4cbabf5bbf4166ebd5772523901dfb9c3f4e14ee5912ea5420f5c3c0c999647bd2039f9247685c202dec2424546085d3c94b7c22dbf4c712adbe7d498b9a7147b198f84d2b55402ff74489b94d08f6356582541c0b0d042e8f24f2b56a40eb2a025eab9b0829cff9cce40c242db26a1a51114646641454b3c88263cfc4d14a284a3dd7263321622f31e5edca1c0d14005cc6230b405dd8b06f9cef525bfb300012cbe7ce7477eb0dff5e4b51c8ce11a1395e4f03fb4044af91fe1b6871bdaae4c750db0151a5f451a2f035198c2b8ced243a5049b400fc9fe4d28667f126ba19326080936d1a8ed7cd777121a32457cc3d393c1beb2b9b1840e4ed208d6e561639054016974eddab1f0142f366a5887bea6e0c0aa4b125dc113abbc4fce9e11617b58fbf69cf8fac3d8f37df2c58ccf1589b410fab00d29df9948f228bd78e19e7ce205b47e73636d9178a4e949984c541b41d54e2a5a3d77ce648957091832654514027896c351d3575ba2b44dd77d88698625f8b3a5d5b6cdb812ec62a95e59c64dd64afad6bd63859b5ed5d0695863f9a52d559939ce6a942b4946ee9b940a093bb9f61aa683847cfdc859568f04ec6c013edb0c28e8dfccfb52da18deb9f4ba85d79849b607890c337f7dfecdfc60ece4637d6843631740bf6aa98d496ea6d291cc7cff8615743319cc59d3fd67886377dca2322c9dff8bfa8fc8b093bedf6740045a8eca13d2b4d8a0c8faae9262de56b311a2a65790c6e80d9de7a0a3e336cc32ed78c5ec8fa3c23f29f4064dce2180510c29e2113f364cfc322414716b3e80c8fc96f1cd5b9b18b2933bbf0d38c180c63f884b1037298ac107168acffa9dda73a56e39c06d0fd3c4af576592a5fa1eb8555b98b42baa739efd3c0638afadf08e3dd43b429afccd89794503b33089b037b2947122d966b30575b84fb481cf4290155d63540a9db5fd052a56d6c4aad41df0209e940dc949d91b2a81a43e2f6ef2f1614bbd578250ea2a566f1f9081bd6211c438a031c6a5c412ada0b166b013f37f6cb0afad3ea8f75fd8a040180ae1465cf1bb808c41284af3b83f6048bf6b3114d3c332369bd4736053b52500cfecb6b3bb035684409375bd842d2bdd140d1bc4269d384f7659cf522be606c3df5b9eeafb459e47dcdc24eb514771ffcc7aa21b1baf8df5c5489b0824bbaf1542482d11c8f2de3e22121f0121583e4a1643938995c17ded1d09667bbf09407d01345425a2c0b526d69247dc7527e6fa2ab84836af7639762cc8f769312f6b8187573d6e2749019312c3dcdc97f980b3a9a1ead348076d7050a07431a51880a65fcafb9025b64243db061d355b246a299c3cf5804b8e421370bb7f68efae0b0dea1353b695eab51cba0ad13c30a8af46ca68b462ebed2e5b57b6981404c103043b669badeabde968392411b20d431bf7107b7aeed99bb66235b48b02aa9312048826ccc57bd02233ade4b59e8863095e18a949839af0e26a99b5bbe7590dcb6372bd70013942ea73675720eba019e79f34a43d4017d2d75f6bf05fcbbefbad7c6227fe555865afbecafd3825746ead7e57803abfbc05d8d8233e2c6254bcaf3783c8f91e724e5e63c8699cfa46b1353e9552b9a19a8abad68451635c7429e36ae37fc0bab548bf042734db86274afe57b451e4e9fc7253066902f326b7b33bdd4fafea46dd521df14b14cd3926fa5f258eb552f57b61bec2dfca18084bb5ea7d893c50e3e95341358618177d4ef9809a96f101b02263e87146134cff2d6169d61cf623311fd84e39516de29dfab9f7b8c868f4c429d8cd7c920888cde890b1fcb633a959d131b39ef3841feeae88dcbd8b477d9a20be87393646a454ff037ce7355223cdf933ce5892f2241a8ac15f0e56b4f7ec472e03d8f0e104855d01bdc17bc775dc69ecc5dadb7ea4df8af7041d5343212a4010893034bc307864acaebdbb3ade2e34874fcf0e7b1a84c8f2e959ea4a5d012de92f88d978e96e14d5e7be78e1be7f9f5a92c48d7b4b8020105ef82a4e7742c31a250df8532b8943b30bfdfcb6f462e36a3247fc0feeddee1a25b38cdc41fb8cb98fdd8ea6f417d78c5b5112ed2265764b7469c4a260aae450a8da1758153815454d05a52a4785a86d8154c519116a5830551dd13e524557e33452e337e6db8ef322ac561c356e363a9bedc3754084da0b4255ce09512b8880ce6d1fd586af33490ef5a7e02030d030fbf2e93a651b762c8a5a83a98263217cad5b22f2a4cc85a3747c0f131745e210e66ccf01d1566b0d44fc491a84c929dc06242c8ac4fc155328df60c3325d87aaf916b399f26ae985b70445f74f0183952bd8cc87a6cff81fdbc154523421c2bd58b3f0ca991583614e0b308cc2cf983be05d4bfcf21be15327850e79504226847df2f40340ed44cead255616991f39857de1415fefe76bfd0d5d62154517646cffc5a24dafc1b7259e5bb3ff0b7d69189e02f331d8f2afd6bf9d93927a2d06878ee891320c9fd1f31d4e485c1e6253c0c9d797648aa98fb339accf0d921cb723ae9278495bb4227923adb062ce22dd69aea9121af03f7b722b1bdbeda912ceaa1251d14de2d1637d93f9872ec99300009e54422ede668a201bc72315be25317a56f7666bef150bdfba5a660b90970d305f9de40af0497f29b28d4ad3bf308c77cd4028a2730c49386180c1d4fa0b439b02403e2cfa0b4385b08a96dac080bcf4c32707e6e9d776841fa591777dcf0671e09a07b7656c0c7093d3d71123cb4bded2b86050764291cf10d08a2b5ad13c829099b039603ae7861c0df47d1ef36558a65631dd94e405ae14d79e709e216eca51d604fd5823475823739a4bf492b96c0d899da86670bf6b032372662c54fb1c64becf98281b500044c839bfe684a253f741a19d3f34cdf95febdc11d5608485217817c8e6ff49a3bf9f7da122ac797ec66d64b03ef0d1ae298941ddada80c9159b2f75972b28d6f0a78ebc2b23cdcb43ae9431a173ebb54d377d2cf61011d518763f5df8413574ac07b9b5c3e946bcd8f7dc20d841985063bd3497309d744a781367a0238b68cc3cfcd386a20c98aeacf0168066f5352851108310552de8936fe1458c49409d706f378253920c72d05ef48a4f08c1856852520ecb11733a01c90cb045258756ea449335d5184077ae11b3c457737b1c5146c631c8508d2c799d4b12bd011c3d565779dead622aee0abec64aafe786c79b4b8e1a973e455edc12b6201ac101be75655d7b86404a2c523e4b1844073e05d21266caa3fa413b4ad60926be891ad2828612154ca891117355ce130ffc83b475df58b5de0f0b460224301fde38a4b2ca5e2ac8addef0704c12fe0fe55fec272d042e95dac413cd28860dcb860b982d4b67e1372a01b65be33f814a6cb14ac3102ee0c6e7a510c4e059ca04867ed04d448f5e1c602ab127575ee246051295c2c69c502164235db02c8824da54cc2f15623091675d134a62a9a41a7fe7150941aa196892986caf4d1a37719ce3ad69532ec04f7a4337c81f77d1e60315a0b3f446e3fb4ef9941d508828bdd1ad053785c9655e08dc269ffce3eb09913e18b6d8048c66d02ed61611bdcd2a8be4654c6e6e8e5f45fa8e0a15d08ed8712feff7184068224ba5d32f723c2275ff072428eebcfeaf7fe9cd936ea1105bbbbe5d83e0f8f948cdc84a8a2282d6215dcb2720a5113404e024b94571a7cb4cce0485afdfc2ccdca000b36f2fd1ba29fb4407fe44b6365cf4c092f292ab9385a06add3fef9d86985851adff20a6da815f40098a1740b805f54305b9a482b4dc48966bd496e39de51198d0c37be5546ae2914ae33f6cf3c0e18e8b0f82051d4f1c979a259e82c49b3548d39bb1b29da993ec062a7082025a27bcf2150251872bd5ac3db38747b66ca6710d5134249fc795a68554e24aab4f2647782b27eb954b8cf8cef0618840817c09aa3a3010c2854ca9769a922d6eafa7df67fb8b64d26d98d4d2464aece2ffa5b6c9d138df5a1644c2114ccc8173b18c7959db44278a4d49cfbcec06a5e1ca991e83a5cf03874c5e9898574edd507f3aa5c28410186bf8a64749c740f46a1cf4df2486f316179267c1dcdbaa9b8dd3ac0aebde226f4740cd4e29e9b7705218ccc3ff8467db45403de8ce6d2339823c2909a2e849fb50ffa4802c96a5d4ae609961146e89d18641fc62327637c4853073a6745a6f566af9714623e5a699f799affc947ea3dc8558cbd72b678419c6a08e58390df6e1202616c4af12679d6f02cef39001434b6813e1153b6a39bb1005bae9ebcc95eb730b4fc9512255df9fd077bb155ae041662ad6261cea5cf2729b935ef45d209587f6d8eb2991159468293c3c76d494ef18a61e6a7805789b2525286f30b48499df75377bc609fa986b5cbce2a70d7f7e775e5c67fc16cbb480719120abb55e2442ec6f48ad0b31060902ce6e3784b96d1f7404293ee961c9a045be6ae3461c1136a16b5a192c797a7dc51b2ccb6c0a7f0912511099ae29943c6f4af77441c79d30612f680e9e7eb17f4b3b0d605943099015dde5f29765c22a8db5c04a0c4764e055cdbe3afde7fadb380e930677bfd9fffaf28701ed459e4fd3da2c78fb5b87786041167822eb0584952c3d37578d0d34896292b17982899f974cecfe469ba931b28f81962272ff05b2f54e932f7d65026ec3dc5ed4ddea8f8d9844fe91d8d85c0b1c025dda6802a6d345ebe3abd96a3e9b50ad9b3893ef603d9a86f41152b8c870addd544d85f84f5b464fce4050d385d1980371ee9f2e3ef63d46b12484a82b2e03e17d9fd2f2a8abf77904480a21e78141812f8bdf7bce2a6cdbf90251d77b60420809c4ad058d1258ad6fc1ea0083f69a25698320004dde378f8207f34524d1c61d65f61781f6069edb599c9830b45bf15a2d288d1b8c325af0c3d6b4abc8d13e95eeadb3478e1e318cd94b1a6a91629f6986cca2e3e77c6bc1ae722d51c28d23fc2b0635675f01f11c0960e6c3f4b10c85fd11a9d33d22c8e01cea8758319dc49813ab7d3e632fd2f10e168383295e13fe1a62e0da4e0ddbe3d0538488e1f148cf73a42eaf681c64e52c1b53024f93c080682ee26b8d4adf623bfc2568f9d7d5af2d2d4b9d84a9e566647832bd2d0e1cd16c96313680bc410c5c09f82a708ba55b1d5c7b34b9e37f212033faa2c6a8c5ffddb87256927bab1495c8433c234c7ce58a19dd5b44447222dd3e7190779ec217f24121f70ea60f4e4f1f5c6bc71cc2813c9f6c9debe9c94af0cc2dc8f153508f9bac1c9e8365a7902c5e1c72ee542de1354ad52f29b1b0134ac8e45a41e86c1d7e30c3a1f19abfc0f34b8f7ab5be311bcc3b55ffcb0586f1cdf4b3afbcfa7fd2bc56a5a99410380f919f421d7a86aff1bd1bcddcc312bda4e557f3dd4d7e97f710fc28b382848bd33e47007f16b1ac1b1d316ca866c43fdfc70a386b6f1d34f0733d5ce9ccb8eae7da26c7e6f4833c40d059c9c727db0bde4a3b3ba6ddd3e45c0aa75d983ea3b050aef3501bc90651b4fff32708b42e29eb5a70e842ac53e3350947f0d69d709cee0a6bd49c875de2f64ab6512126b9f7c764516394504d189566da312d6a6580d563816faf874f69616596954b7cd392355e33a5d6bdd3f12a423853953de1c68a3533af3ab154447b71de53e5801dc5ab4cbe4ffd9dbe19175f941dd5965fce6a77dfbb61619611bfa81df2a0d1e0272306f644668356c80b0c853493a6d2ffbed526a4395e328fc0b93afa7122a3377356688507600a4ebcd107023a01409747d342d70cb60d0609cacf9de288390bc913bd4cc183bbc02ef310cc12d26043c34e85bce529498fbd26452ada6b096f68900f921eae6c30837cd526b1450b9fce84ee4c1ff43051f742bea1e499be3d231129c87a8f67158f0e1fdbe7be401123cbffef94c7daee296099489f3ed21aabbf9f760b538bdcd48a795fe61924bfa5dd71a34f1d88fdca33b63e4af7ed7b5d9cd6095dded2b7e873133433333f8d8bc3ec13c10e1f361f56d88b52d7a0de6e9681b4d0a873daf85fb6875915215f24c5c3fbe84cd87ab6bea1d0fae7f5318c210eef4ff656d869a1d22185f7078b185465cd2c026add78de0e474c5432a0cbb4409aa0202c9bb03ffa03c7082927267eb5c71a38b71421b2dbf54d0cb956fa65df890e82d52bc4f41f43ad136f76e12ec85274915889d0da1138ee6f7eeecfa4c4295e5161431d9d6f82bae75c2715f23f195ddf79242ba46a0c50e889a913855cd5c9153e90246ce6e2fc1f5114f215261750f24543241899aa948657839e149e16e42d3d435e2137eee17225a2089a72a695b1ab709d4a4593e93cd278297e51940787dfc7fbcd580a6d746ce2eeeac4f8885925eae3fe03a6889dce585991300b1fe63b1e4f7f17db2ad97bd10d545a10cb70a5e22239ad6d4b818dc21c5d830cf7623502b1ef500bcaee606b256931af849c7a6ee4d40a38d0942ee72305c41ee61f01bbf24ac0cfb35ec3655d8d6c2be26bd0b703820c0eab42c11bd31f30c31bfe2f2ddf6d5785c7c0f94e39585f2f5752a4ba03b62229aff68b3ace0019be2bb4188ab8249fdd0be080efe10e4266a4ab5923f2e92ece497e02eca228c922f44d4661f363fca9104985045e3832251a3b21dfd2702b97223a3eae2ff55cb31f02f738d63828736fb23138923ef1675b2c488b8ba5914aa04dde4e1abae93d28f1f66170743170f88238ab11ebc0cc0448868e9a0ab391c2f97cc6d997ef4e83e99312e5e7ac5e43634384df8ac2bbae24b987207c1d4fff8083ed30c4a1adac46d40717a7c4e1704671b719a31bdeb6ea6a98c3f9c8f719d3668da11ae8b3eae88010bd2225cfb6360fd4725bd84d780cb678cd9f8b9cc0b361c1758a546bc3613de34617f500b0f93ddc75b59813b126ab1780558c2c443af116a54a651d8d0c157c10df318ec2485f6544dc1a1ee9ced48214fe293351e79e789274d4471b26b40c80cc69c2e1b2c09c33ed7ca6bc78db5ef391a76a547772c0f3e0ae8d575089e2559e24b17c34bdf08ed35092ac4b483b176c60cd64e7a3a92b8df9e00f0b76f0baeda0519f5e3ab6398d403befbb3d2e0129222d1d456c3ffecfcd54bef23b770e82c5b7639a3813dc2fcd6f800c51e7894cae39e5da87b62d16ad8bdb91873ed3eea0b0465f239906ab6abf7477324051272c611e666e7f669c7a689975010d5f431222c874b7bdc905930b4448cfbc40707cf33c83b912ff1cb4144a778b431c270c19f3dacb193ad71e960c26c20180441b3302fbacaa8a18725d23b28b42cb09506981a2aacd53c6d7d092004c1e12ebbf9ed96906494cd5f19f0a811394f7215ce9f7f1e2a7198c4d8ce3a20c3278f2fdf3a7158c0fef771bf601ec38c26196de6686999e0477a4cab49b87cd4ae1444febee2af3250369f177b22efb02724617315d81ce104f36a6206f3bb9c64e8714b04ea0061fd94c452c8a6c031c8453f93a09d4cc91b9202c12d0f88f04d276ef45a107aa6e8e5a6d880b1778ae69cfa2eca31179c1be84dc8f65171edfe2d5172e6ada67b76ca56f56a5a5a764bbb418455a6c266f151b13a52f38bf72b31102697814b7a3fe18dce388934930dd74861c73c210f25f890b40854b34dbde4b74675375af1c20c42918197144226d9c8e39b1348048cbd5822007b25f1b90b2af1421dd4264abfbe90ebbe58d6b77252446bd609b27a5d2c918ba5742a68320020f496f2b666ad49e384d04eecb6d92c220720d73d1e0fa8ca1a18be4cc221db4b0f38fe3b4c1dd100459a378ad5b23011ad94c19063184ff085e7547800d1c6a74b611e0aae8b3dcf0b2d80da503124f954e5fbc2bc27e4240002e1c42f760711c42094cb0083dfb05286960ede5fe071a72dcf71d64d1138bae6126c2858e7e449c4d13c6090a7e6ffb402747473630823798364788a2575682b660d942bff8e8613bd532a1fb0820b3399059eac423e40b847c18aeb0b858ebd07595a9149cc62a3249b97585b646175c603d906f40f1f424d167574aa6b6c2fffa84b35a4081711d8823bb1388b7c3c815f60d1455ce80d91307e88c8d69a9e1da55ff15a0a31979591ecd8225883f3eadcded9895d6123f899a55529abba553d5325caf0fbdeadb02982d29e219217e13d9dace60f1e65f0fa451866b16df3780c3e5159a2b095935cce1c9d18b25f21aea83638b7beee78a0eebf13a76b546c4dac83dd5276f7759b3089bf3b0ac37b8a9ede129e0e508b9612628a2483f4902e3aef27a4e8f21d586c1be009f0854e0100dbecd704ed9b9c2a447c1bbeedaf4a7c2ba84a4459d39f2228b0a022b688de7709dc1ea5c17f91b25a6d220442348198c5d779208efc0138695143f93589deea370e57790b06824ee954276ca676abfab2d547909de81149321becb213e3cd4e9dd8b4a0903e50c4e8ee1997af48c02789ef8b16e2b55525d6962f95b206a15e03c91f0d8c57aa9cc1426121eee97b69004098988174ba1af6dab07a903a41d22af3944fe55cd72f2028939f162c4546280725e559e91e003e362c3659b97d91dc72508b06146cd930f5d2328daaf3d616544d350350bc82ff574e00b7b667af248702e4a668dce413ca64a5dfd74b4d056f609609c73b5bee156641624316f0c923c0928bd027bb3f0a1b7ba101675b5f1cabaaa462037ef9f4a68a0cc06b70baad6afec034af021061862e0f0d920baffefed9ee60379f34128021e811460a7a5fe5f02ec744bfda93f21c613958c237ea387aebd9f52a52e0459c11cbad2d512ca8e2d58854a96cf22d76600d5775deb5aa550a16d79c6dbc1b25f96c5238869c0a09a444eb7833ec182d94730babf742da93dacbc34f638a38263c279e05bd9c65c0e87bf665ab47b3b3e852544db661fd3b0005e5fcb0869936d1cc7827c7ea8605f93100944c544baef0f14e6db637543208e292034bf34e4929799c44e3c443806c2b0ec1c73b506af764c9129fee94010102458f9300e3f1a157f0a6fc01658e1467fe407917b9d8938c162a653fdd8d6d4d170bf01551f363eeef7be1cde6f7374a2a40deda5bede6b50227a25e4dee27f0c206419b17a2aa26f3ca880185203dc652898707db2d57f5b33400133d1a691cac16d24f73999500072077e5e23cd9f7a20c308685b872b4f579205bb3e65b53b710c6ad7b32d4e587d40aca4bf7b99c4228c003eee6e0695be3a6f728e3f06c3cfcda10034be0573081d14076fe8ce22d5931f45792095effce4080a26753446fc7626e33617a053a8f9746b05d08a628677e7140357c1d67eb9ef25f26674a5c47e320130eb6b091c7f61f527d28cd36aae9f0e6dd559457a15d5bb9de86abaf770795c4b79af052c820e11880a00c44d40c4d29f1a9ac2b8af48ad9705d9f44c7ac03d72983573b327c4ada67f534e8dc7b9d652816294413d6597978823aae03fad16b23275e919817da92a4b5494b52557c41a78e47d1c716c8fae02c8f6b39d382667a563a5cf195f58a6964ca8407ce3e0634d70bb0c1a348d77f3fe178c8cb09c54eade6b3c2e71a9686e85557f8dfcc28706e802b8a32cafb39429ab5f7452aa9d4b3dec02dced931e00f2f453c71a27cfd88d2fda413cc32ddfee79a97fbea48e8de559b6baef3c47ae2ca6eea68ae5b4411e070c24f10c875f86c0fe0cdd36bc5933610de558953ca25365281b74f07a2bf321086b1cd0d45f1e9019be01b7671e34f3d40a820d70f4ad70216dd3cec6c1796262d00199c4ce449f71acfc8c52f950e1760c1ebc2f51e71211b004d31f77c7d76ced806c5b763cd3b7516603cfa7b60639c174cf2811316084a2ea7311bf3113d0c819741e8eed154a54a0d32c1485a1c98ea172147ac59d426c68e87f829327ec231ce1c3a11a12c080d34500f530764f33602f71d4b8ac734a4e1c0365207dfaa17f1a41cc5d7ce81b700f43e2afbe761d2439c99daf624e32770892b07c6503ab9c868b79c8e8e9ddd997c895005591d41a7c28aba2c493494d6866d4ee2041667febc9a4fbb532e4d957a14bc246d34e22ebfc354c6ddbd1e3e61e6114772cec872573c938c661caf49272fc96992a291e46c7a032c8f0d5600a8d8a798a531b466380b1ce7a9c4510d9d0bdfe40c73cac73cdf2cbe9cb65de87d569a7a82b971bef6ef031eb45d129f0018d1480641b4e91ddc5da99e30e420a4a018963600b8ae2f849e7e2247bafcb04a41aad1d23b627d8ffe29848446905f76c9f118757ba9a907f16c26088f3c7a41b5d3f6393ed37cbc43bee52bcb3717592e6ec4f4eb199c8ab1439e3654e49d240909f6ae5700fbc8c81d03e28a8c749e11c8a41e291fdec562549942d8d531c902a4cf1e116efa6c3ad6b86643046cd890c6679a05faf5517a934843a1f43d72c4a23815ae6cff4182a4247452fbd29b0e17da5009b6606086b593b084e60e1e07621c3d828d27a311f9202ebe69eeb06ea90da4d372a216cd60b041d8cd4ed438903c05042192ec809444fcc3d2d09ba411a18f35eee0b4f22fa985bd98f63a9e16d43318fd78c6bb7d88553696316f5a28226186a8b864d14e9e3c9a4198b2cfb11e80c241cc7a15835f13d2ae7e3d3dfd29ac887fe3945e57c3c8c2d46be4cf45bf6c41f6eef18f19963ce5661142bb0d982d0bc57c808bc61ac42f7892cc47a4504df4034277191381f8fd47824218bd97b49de4c44bc221ba900bf1f4b8f90b958b442b3b62c83bcbb77addcf84876f71025d989918d4242e37f5a6d0473fe7fed92bb62b28dc11a741e43f4413665da01d0cb4d9fc51bbe3223eab33dfe9254f9e7efa564ce6aca7eb44a5a9610ce8efbc82871c64982889434be3530dd6d84d5fd3bd37648f61f795c232cbc1ed0338abf4be12e17d878c555f1b3114783b2b0c148b1658dbb7ef2623cd8023f0544827f3e84be4d69621c0acdf87e06d27620dba0c7866a03233e0db6aa5a38860931e03a442246a98f4893bc0ce8c8a93bcea5d0e7994d1b9081dd695ffc4b4b4bbfefa324595cee0215d19480338c2bc02286a92eded390cd4df76b1caca405351525dbfcad4c8866fe7b9b9cc79ef585d74765acf4fa83bdc332adcd1d8db53f011ecf6e3a5863dccba6ec0c6d1032a49e3f65afc35fb867c15efad46397b309c0de591856f86e1f812c3bb9b61bce2ebe7f178ee9f83310e97bc84783b186e49e616447b6518874d2b6008c3109e84d20294572ffc92baf0fea87e17d5c45b1ba8d4bb44e1412c55a5daac2f23c4e60eb88aaf1d4881edbd4bd23dc36bef69b92d3706b8fffb1864b3a0eb01d4f826efbf7783a5974b2c80f3cf2c06667808bdfbd4382fe34d1d215728840c3fe843f19a9a10e4b59bd42ed0e6c86694403734e1ac8209856a2c7124c59f06909d659ee309fee37c1d64a1bc2404325df63fe507d872770a3482164a29c5941202b89d3e4eb15dd0c2e5f886909710903e7278aae89bbe39c988051420417439e6ef9d9b29cf721ac3abce4b005ca2a7cd3f129e9b17de5cc9191fcffb60165d6f1e81c82ac9d69044a3fe5f4ae2d15e0a74c3935f0f289de8d940bb9439b8350534f2d4b06382b2b01a1d118571eac4ceb883874db316141213f157973be466bfa0ad709d00ec9e0210a2bc01754e93434eca855f3b8b5ee661b33e256f837e8815016211423b0cd080b22f2f7a6c170c14ed47d85a58fa5bb365d0cab255abd8e2eae31881e0f0d6a9eae2409da22865e2357b957da8d0274cf59a35b984e821a9a3636b601cec1a43d267837644c5b97eb2b036a9df9036d2698b494c6cef6494fc30006337c30e61d8423fa40eacb01c10eafe872df6bc17fdc66244698c90598930d11d4a42017710865125e3e62fecb0f02929149f31a982ec6f4425656b6cff89a4eb0228505bec77c5a866bf100786dd8b6c0e4e3851771ef59d45b8990fbb5c0e5a80c1e9caf0aa1375aa3bcb648217ec36f01b2612f4fdcb06b74e8ccba2004217d582a997ad2749d367514085cc12e2f2a98fd14c49652a275c355b5db1ed77f6ec848c1270380ed0bd1e547793078841b408063bd1ddf450e32d4413d23bfad47eb1e0e3629603bb570f600ac60bc84a882709be053781f0f918b08f6925e0d3bc4d578c0daf619c3c4d2b19e46afddf088a808b4017aa7be2800fa8a5775334eeaccbf09440e0b7eef82e4b160cfe1add551d0d48b8f1186a11b11791cf0343ee67b79f0ca01514003ad3b1c9187c4a20afc8515978afce26e731fe3b7b646ffc92b987f30bfa19d3d80132b13a409b900e00c554d0891043768b20bab5095b07166010621a9f8ad088fc28e66e152ffadbc7f3b41448bd8d5ee6ddc6bbb1af7e0b38c4d570c23583792f96312d59631fa008a947a6296bdbb43f2364487cda71578aa420ab19ee3681208d5a9448f02d531f5d6548ec65cb08e08fc549d1dafc7badf96b66fe08fa3c08516b7a597fa4c21d35dbc5aa5ebae44293c5dc97c93cd51d4894818728872d3faf07b8b5028765506aed73965857de83703f3733779aac41af9d540b8a5ec399eedb370a3fada9ac21232915f60ec600ebf181177ed9ba0e9bb2f63785b29f894dd13022aa58fe6af2470ffe6d10afd80742936ba8ceb69025481eccbe25810cab301011da2ed095d104e3e8256bd3769c3f33daa04c1eae7e881fd049585223d2a04948aa896cd0fe9198b42d934ba2a33c6a677632a7b76dae85cde84d0904e85cfe293e7bc048e23657b6d10b2cc3e4c7e5e51f20835d081f1a280ae86e220ca9f48d42b297bba456c423981150f1d0bf12732b1968d2191a9cb2b81af03032e3cc50a6c8c055b27e4d8233293aef733a98d0bd7f15ab6bac6cc106f17ef9f8c0166f4392b484b76b590a8192e6870b28d975ca441bff050183219717015a547232825fd7723cef8b33f069955d28a92043ea8b22301a2429c81d91c442a01764b0306b92e43f546439fd4c2979cbdc2e5ac76afb0c75b18be57b321bc1c9c5ef763be258057784ef80f170eff9fdb84b70add0573633eb877b1999a052b4a377bc4a1b061eb6b1d4ae48fd8833c387a4994237c79b9124cf135fa85fad28c4429c201ff75ef2ddc5163c6d2bdde14552f2db0d08a8aecf7049f2ee3fdf04806e4ca6a1dc6f2dcd128f234c1c0194a7437fa640291498dc45a687d3ceb5206a9df39b91f9f1ad85cf29faeae669bcb0fe19623b3043229792f469d31b96798c467e32be76db2b60600f7e737a60c658a24455924db0a845f2aa448dda116bd2dbb3018e7632f3d9024dc51f126225ea9ed079e9bc0a74d51f1709052084d81608695b1bd401c43e7300c8d03e256336534749d5a08e981aab841a88ee39fc35ddbd8bcc8c2a4ca2e594de81dc168bd2a6db2eddd018808e5a37d8463b0b4047a1698e25cb558503ad2cf3e6f344c95ae19fa1d615709164453d7100c39fd3e64058940fe414816fa9a3389968ac16d244a67740bd32219993a2e4c0cd9221f43748ef5d6af3afcea8add791e382bf5834659e67f0d4ae89e3418ea270727b4df5fabc9d85b5c58bdc7fee0801c33caed5949dbdbc469e0b6d90a191bed22fd4a4f8c76eed69becf91ef53c828f58d5db22d69b82403ffd0130d097cd0e93ebc4c89668fc73f3c9d45bcb6968a66e1d400004588bf39e2b2b79b9613d67d89380a3773edc4ed1a5431ba7e4ff994d3b5f186ecbc73834749025a3c084f9a81291bc6ac89671e5ca374b09a8b2e987ba2c92b09bc8e32ccdd6d575df9471bfe18aef822ace9d57c1aa45b8603dc3a6b6a19963e8001faace675109f97ef29fab7e831396586098cd194b32fa56fa0de927a0ca8e2a51c8aa1e80bba3e391a0a516738c18d050cf9cc63e26f4b03ddc8e6165f903a3ba43fec22e3cb71b66e7ebdc75045c663133a3f4f0d85d05bbabd87d68dcbb62897121e6431faf747d2bbc341a98732f9fca8cf4abae1c8ad3863e27828b9daf4003a13d704d07a5c4803d34b48b078530de502f16e50c65a979fa5d1ae38bc2d2f7b07885409afd302aa185ef98202e9fab102a258ec1ebcf8a6db3dea579ca2ab5214e7803af7af64c7bf89332ef8041a2c9f973cdcdda215df3521a5d17e69b64661ea805fe2f12e3be5ca970c1a7cdc30f5b2f063601667c5c8ee343bc0e0ff683675881c6154bd0190ecc61f99c2ff23c5669b4bb2246f7a1372bd6f848b0aec2044180b9a57955ea3cc619f423544c80a32c3e3477e0712d9cc163c3296818ebe447da0280d65a706b327dec589031b396c58c312d9320b753054839ce6a375ba6e3fe31fc79f1e7c31583cc1fb32ad5c28f43de328af321131868861da1307f395d7ade9b9688e79a835f2e58c42525f42e1dd861f222e92189529bb946c575d888d369b1222d8674fe74242461e7ae36db492330e03e08610fd9d4129744842f7c4844ccc8773dbe414decb178fbe43b2bd7190931befddd3cb69d95edc889b2d593f501cc55bd97fe542727c1812461c873adb21b1c706eb9a7b5f2f0a69cb6eec50490d1d368edc8bb6ba2d7586fcca4f5a6a1eb3abb18775b9fe9d4de2e63db7aea2b63b86d95446f77be0b9934d7325d6f88e516bb48a9b8cd4250ea63f8c3af8d315453fdb7eefed59b4f1bde267fd216ca5ad18db6ffe5b0342b20aea568fe55ad098e822933817c52d5917a9876a1e600a4619503988ec47b5ce1abc575d4ebec3762a4a9c1b335cf24831935313a9b02cc1dcb3421e48360ce06c46c666c2f9c1a7d03744e4d24e4dcbba35bb9f9beeba61c5a9412da4e7699144c5f4200e35244cf70a2b1441cb2070b965b031bbc04572fe85524c38a5b723cd43e39a93b87fbdd57561a2f3591be6adefe1e11a4ce0a21517e646d51286ae128f5cb2fab8bbd2572a8a97dfba8fdee241fd889bde1e32a6bc9b887c57b41b0cae7f9e5303e0d1c25e36cd669b5cce6aae4d5001235d1b80dc631a5cdb0649573fb842950b42bc8e113677b94059ed169aa99bd82d86c6719af285d71dad110a4003697b0c876cb36b499228a12ea66abb5d7cdc506dc7eff1476a425c3c806a8dc5ba68532ea8038219747600eb2a816d0ee0f37ad9f4ecf27085e8250c0a5cfdbb8613b71215b1f9c36ca949d3526d398e57b20ded2e77bca9b58fa21897c5b9186378b9a7daf90275bed0028b17427c9e84bddb684091743094add181b7e1d37958b0efd40edbae350a66b23d78dbab1e8bba7b9048eb79999f9d7d03b332fd3811cedfbfe2b4af95a3f4b6e997fc403e65d5d524e403eeb7f422b15c5d2f9c9bbeef1153a076eafdf2800f6157fba54b4bbe568c9e1900cdb128d74e993fe2a65ae5e311426083815233d25b1eb4af21f3d40d16576bc2782ca545306b820dec7d6109c8e73f5867f4be31f38226250d5242de88ad54824299971341efb5790a083d56c04c23bd8738649f1abceaac563ef09e1ea64d780c9cd782abd4f95d2184dd2ff159735f96a27f26c15d089ec4f07f38611eeec5cc922c434dc888e6573942aa221382fd2080ca6e89afe1a2090e00c17dbf69c40673619db38cd20c6bc7c9b6f9d4e96f9f3fd8247fc74ceffb5b180867f667173f5e2859b3a830072fb3430fb06e1800dacb9d98790cb81abe8536ae3a10b3bdbfec1d5f8d7149095a9572f90f2fa7aedae02d9231ae0ee40a649192f190261016f386b8f4c878136bc6d5f6d631f4924c88cc3f1543c3c4ab9bc3f6b646fff4a803b4e2ba04265a12cf6745288fde4441a2c8f740d715efb775039d9ff5b7465708bf1d39a2b24d0bb0cf021ab78ef6f00eae1f635bbef5d4013074d1a8a1af632e7e24db923d8bfdcdcd579e6665b08ace019241c9c06cd6f4dc4466ed6d124a88eb440c923139953a4f9adc3ea4347bafe7c181f7df3d696d81e99ebc873c949c48a922aa4e359ee092b84d82a4b1848fe019c13ac630a79725027fa1f4eeaefedde826e3b6fedd9b7fbe8beed1f7e560fe4486d7c4bb19669e0dca7d31117a1b2a1f1b428c0daaccc84aa16b8f19754a7bac74dc0df9eaf7a9763ef6dea9d86093c627166f2b4fd2939fde81f51342b7b3990b5a1666d58dee542aadae4e5baf12874a4e4499f5475efae89164ab73775cd133560bb9718700a1973bad5704856ec3a1bfe41cd218e90345e68020fa2a561a1c23b7905a00c7dcc1d471da9a3cd360aad7b12f465dcdcef4ee8512873b3e7b68688487737b02c3368be84a6a8e2643dc0503051142f980273a19dad9c9f940a2734887db7d74384a182db8924c125e7fce19e6197d9803b724aed1e99154c7776b6cf95ba571d20fc5e670c2d7ce6c0cc4742ac8e25e6b2fa89664c72aafcfa6a2810b2dddbaa4d83d119cd9fd53f5e5851eccc78eed86dc52aca0072a615077d393d6c89f147758885f62de071f476872f3da343a5bfd5a772e4c29eed726285b00ffdf19a310f23016b6e0c5922fc7c4ceeaf579072946af901cdd41ea3d8df4af3689dae90f0660a224e5e46503dbe8d02c3953bc0456977d20e7769c656be321472090431d4a67cad40f0c2a1a17b68436cb407b5c58ca94c4c35f3de5a9037685be801c6e4b82aea79c12f2d401f94c3b4eb8ae9ec447315307b6aac08909aaf1d243a55117ac1ac8b6da80d5174a317bb272155177709c6460b086f5c9e3d5a5468b410c423aca339d4037481382d8518fd6ed50b7e4f44b11ddd9df716e7d1583a3c1781ba372cad7bce9f94994960af770836452d2b92dc7ebca87cd679f9f3a05f81a62fcce4d908bf01a95d0e0e5e7a397b72c70f4c904a37bae3ebc140e8c0666057a53e88e52e584c800f29e4cff349e3f2c2bd38baefccc788c4dc28b0f8179155d70f1a78bd268d979f120ed660102b42981e9d7832fe5b7039d13c7b7f1d43040135837249c4b7637918eb2e9154d0f6b7bc40483cfb90f99b14a3357d63994de7d8e223ff6386247d8738c6ff4e39ae760285867820016cf5faf778eaad2f6cb81d1f34769824c6b26fee2620bd3e4af145f1080f6d642ae201c7ab6d4cd3222aa48f61210594b0e4a42d759a9abab4f290708416bc62e2d40748e73bf40b48f2af8d15a6a7116c8b50c3b349abc94f76f71d6db5d1e43c912af8cba16f9957ab581b055adec250652454d9c5e710e53110964582958df19adff42b63250b354e80741ca0a85bbf15e648aa130aeebfafdbea76d3c431c7bbaf82bd4d341e76e9ea1fdb32664b7c017c5c14fdbf53d50f10f3a61527ec4f1bbcbfcd674e667bdf386c6f7c29ba436584c186187ca7f6c79ce1fa5fdce207123892fb99972b4c2cbe2020d501b6a1f4de73a542b87a25933d3d2a39d8216e63dbae2dc99311121c198456e8b8b904a4d38d072c73e631ab326e510ceaa3748e7f286380412d9be74978f822b35e5f38255543f0d620f82a1759f97c6a6927e4e43da9dd81417c1337dfbfb0a4b266cbe8c5ea0b43efd63b476d20abf141f5b604f6ef27d353b2cbc8e909a7df2f185bf993392cf785f93cb4d1662214dc7c668f952bdf1a1494be9540e2c767209936fdde5975f58d85606aca68950431a6f7d85f272ee7e508ea35cd2a474348fa0457e199cbc972b2e381d315e3ef7efd8b41a3055f9f46ce0abaf0b3c108b17b1a8fca50b9a131e6fcf5bffc9da113f1d5658d3eee0baa7013ee0be477c7ce9a51d124ba176541127fd8c27121c6dd357b8f0c61cdee1594d22dcae3d789e8c35298edcb615b4232169848cf9ce8c040d5fcd810c9df34cf1bbdfed497353840ef7ce43c128acf9a08b1fbd9bd4679b01eb16ae5bf931f4b9b9a53f37dbb96da1f2411f0dd4f13b4b370f3b650514b15850930de0c206329488c888879809709cbb67d3da86030ecca41a8fc3abeb6fdbc49bd37f8475e49885ad530eeb0c24b2404408696bccb11d05045c7b6ac36a08ae42f6a613c54837bf092fb8cbcbbeae85ec4abbbbddfd40021d5bbe99217bfa9770d2e93ba5e8996298cf6d843274dbf9428fd72feaffa3b20dded6ec92bd8e59f80adc1646cf5146033865f4eb85792d6a91c1b35d3e3e2b1f7ba96ff6c53884359b6236d566420f73a6e6f1f2c6e04c2f5c4916df95ed51d77479859d8809160a5016e43892933c4ba2545819d84a802d0aa220f498b496b600e83a9244663e3b382e9e1d8360240cba91b1dad464a04bfff04b1563f47a891aae3e5db1721358ba22b97d81e1482b3b423f1792b65b83440e472e9a246d48fdeb7b56705cb90f6a20a0cb5eccce4b872ab8452bba6a80ca514201deed30c10e9f4efed9a5bf735e9e6f771ec3ed220cc994d4e494a9347a8661ccc8900acf3f10cd6a1ca26b3304a544b7c7285379fe0d9b0077320a20bea8f21642eafa4fe5559ba62cea54c4a247734209aee7b8b41a6582a237cc30158df83c5486ca82fc881a644b110f0f04a4038b7184e951146efd3d0223fa306e526de35c9284236bf3231bbd229ac512c850ed995f7de7cc8241aff537b846d448e84941d0bd0c796a65a64bf20b4392b279ed74ce9af8bdef26c8194347732e470073f011a27f32e429fbe00ea237c41b85f89b2b839df12b3d575fd45c1501ce68452be791dfd481a40a976f8a05052c108e1e8ed2fc1489b993ca0e4b633304961c3b84d0f4a2223ecf68785d5f789eb8c532a0c52f6df0b651b96e3528c29b469a245bc4c0be280910a562487e63562afe344c5809dc3660b7d5e34767d185cfb16a53b9eb63f9d8229fe73bdcc6a3929161167aaf89e58fc2e5702b45bad99cd7e88a1d755bbac79cffb3f063520c577dc9a1fed3c201ca767d66a196cf31e4fe4fc33ce04d9a32224dff0c3f5afc732c5417e54c796b4126db25a4d5356d68a939d9ff9e37f446e98e638c147bf9c2fa3d859697ecbc29e1ee600355a3ef6dda8e809e8f94fd07717216a4063def1802192e6d36ffeb523ee155cede0932f5c833b5b82064a0eaeb828fb48c3ba6916f6d23e68b441819b8f4dbcd40df0e346cd0076c1b9a2ffdb930454759905babf1f751f6cf9575deb87e01e515754ffae70601ea631573fb0a468c5e93b94b7ff7669e326e65ab25e357f22c2962696d25731cf9ab7c594733d917fff69ebf921656062f936a38f8883061077732936e916c26423473df05cb0684c87ec86b3edb42b27cfd877c4a409f34949bb7b7cba110f8d02b9c16ba2e5e47fd2c88bca29f7a5757510496810f746df0fec32734ea13f33a170cea6254a51159b05381b46a46678d0bd0910d84a2242f72600122c5c24a9f6e7430a95bd20b060b2e62cc287d47bb4e7772808eacc084e069140fc5e83d2a837ee30755830cf2e8ed0f1cdfe212b17cf705df210f046d7e1e1a54b8e9b14e5e4e05266a1d4564916d6641a49c540cc275c98358f2e2e6ab41f41b66abce76188f91c62cbacb1584236d82642c6bc07a85409a8f16b006af7aa8e06534322b618e2ac364c671cc5b779e3292ae6ea33f045706c361b440914e0f57e7c52aa6fafcae330d27a4511e2b4656cc282b003f0e33af05aca2f97374361bc121bc702f2acc530bb8e8e67fd1f50ed595eb273c2606fc46613f930b6047d7250eab41f17a36b30f2c3e8c67af2ae731d4fe623b3215161203a3afb03dcb86111fcf56bb2d659d1be0b567ebd06f45837f2542537ccd6f4cf7c4a67cae921c4a98335b641e8ff9016e2edf18b57298a294ddeeda4f1bfd8802102c90c54374c9f0d264272e6073551a71b9cc00216199bf29785a812558a6e6c269884be63faef05c04fd03949053e361d6c4c2ff40d36c544f2402fe5497585c8edeef4906969d61dd18a350523ca6eb96fa9916fff58449c0e8c53e20d46279d7c01c16f04fc806d89c9a67c14cf7a7d45874daf751c985047dc59b9b1dd9e0e7c1dd8a6bcb9ca2eeb940f86c9b78334911075e88c979c9d813d0f692d73eed0df839271a4954de6b5cebd83c150979fb1adbe15320003be166bdd6a02adb12849bce088bd7da5c775bbf5a66c062a0271fe7de56dace701578542390b393667f45e904d6bb1eaf241aef406557b6cb8bfac573b8efeba817265b67a0dc8d284ecd0693c56dc683380243296fdc041b41949185a1426f2949e674e482098135a2cd508d3c722ee25c8193dde180c1b8a8d5af962a1c7cbb08862de930632f028fd02e3c0d20ddf204779d6d2574dd5d8d15e23760b1a89bf276137b8827b5728b51d72fa40c6ed81f2bc9640b916a5e6a85457d4829a95e1517bae6b856936260d77c4d53309fb0c75439d37aa4dcbef85440b5d16f922043a7d9b8227f8762acbbed62c0d8df79a313571bb5c900458b9adf39ea455aea26fcd704af5242a243e45e17578c0b455f168d53bd3ac47ba33b3adf08f6eee7a69166316596d999a6959cc2d7d00ed080916a6458c943947edc8d839e323d7f2ed49c2473147db8840fa0b806a26c8d00751361edb4579f9e5a0924b978b37276d1e16109d5ce5890758063fc3c557b69f695eb7d432af97383fa5238d8a28294a0dfdc48a52aa01a4a6c483562641ed4d4a0813ec9355ce2e86113afd9a0443548e9599ca9d82bfc44019ae9d0e9118990fc6ac9a3ff0a8a77856c867b00f2f5499cb60c1f79c4f6bb4cdf59a396490baf0838cac36ed4b657de97bc69363bc064a9458512c5a563446ef82100958a3f29243a7a183f3ef74b25e6831ed51d3ccda91d881e17cd6a11076554eb5271d98b0a4a211eb13ce67d3f0a7e82f148c1d68be812021608cecb1b21c1622c74fdf54dd9560cbacd4254f0842beacbccdcaa9ca5d4bf4944d0b0f829da84e438a06096f19d10bc985e4fd79e2f82afaf05b2850d902cedeb8587e94cabef3408eb816bc29330b810ad200d73419fbd34b890393ac34e8a5b8169d34c251ff9b176e09002757b847c061e35ee2bf3644cf3e235c0da0f20068c644c9cf218c76e563ef3da6eab0bc5b37b417f95b6611f877b21072dc9cb51d26c836287195095d659492c0b87a01013b3762ce768764191c7de3ba43e84695833566ee7c1ea4b2854cd9477c3eb0abdcd6f55f8ec6bb844d228672ecdc5f36476e00621a168fc6ffa6296368ec4a46e934d69ba19d8428f162d9cccf977d00baed34921c318e5e4f4f3fceccf879ae0bc026b8520ad12476569e60bdd4806dcc68f47b61e89dccdffc5f6c1c782f729fdaf08565f7618b3a3dc2123eaf8f07d011e14aa6fee3e91e9af56091319fd4a7785d9c1a345011a7545b0491cc8af3588b7fa16c4c4193fd1f14116aab208a395784655d9a522a58f622f9cc2aa89221672660428409593a6215b305d641d9118506f94e516b6b267ea13c6f4dee2fb2186b3c8586a2704e429a35a950097f2856074ac0ea46bf85b9effe982b976203433d74405787d541d8360209c9f205bd7d015f00537fd3413a7b4a4f50b012b4166a2c6491a03c04c4c660d49faa9218abd1ac2c56770c67c8c682f64ab4404f8cc1295f6ee2aff2374e69e3696458dbf99f96aa875c3dbe4955ff55a1db25c2f27f1bfc3a312bb5e286b941c32c22e7558d333dc914da107cdb074d84c1be861dcae173c37d18d668fcc46f70aaf7ad0438859893798f35a5553dd9098aa1b66577583475a75131723e3733d9617366e33659aad3c65990427234a9c542381f7c947168b0e8c455fc470cd37ee3f90caa3ad7b4597f7114780c369d2e3989bb0a8b582cf10af6b572d16df405637c91316c1064b8b35002f42bb8bf9363c3b7ddfc6ee64693b9bdaf24f89fb98a4e8321fd906e0c970771af922bdfc9958065da479d7c221f9bdbd3a66c4e9ce6be55d5ad9567c4eef2e12a6cc22d9162cc6409bbaa559c8e56a2b6ae3bc2165eb243b5a66e235db286e2af9c5ba4cafdece48d46c1b8a0c1612017c4c04ec9481a61a60a4e589918f14317d4d83def2c2903cd8e1491d7f091468970210872bdfa0927467f6970dd84537144363fb5922709cb95de0b613110e9573e4aa5b119d308e36720356c605b8abec27ccd87045f5540208489d95984b2104d7d84d28accc5a74bb0ce62d1a017f7eb77ef2f4efe3b8e51a66325fcef5c1a75baecc618761b11a32ad41c63714f23712258187a607efd529801a7014b97024d57a015f3a8501deb017b929411b419af2f8605196c1d48556db2f66f79ea6f455b7a24551f83660621d50feddab72653c4805c29b6881ba9186df1be52099d59914b3a2511d828afd53bf4b83f1f837574bbcbcbb236396460531c7dbfa80607dd6446e75c560db6838d97f33b8ec92c01c981faf6b109b38ee38e2977a70473ae3b85ff370d0b9bb19f388906725e8ccb4b96c8f8ba7cd42998d96c0173dac32fb5780cfc2cdd602c5d452d80d630afb57a6ede7121eef080a4d234321d2e3def2a8a83b9075b9802ed6392c443b923829517c8054d342744fff3532726f4ed349a111059021e081bb01079f4e74695592b7047b23035d6c86da5f093c7a8e615b1bfff089ee4b3b68ca1d39a6ee540f87f0f443dc4cd372dded616360bd6c4a091713a4fd1f3acda800f0475abe2c034a1191bdfee56e7639cf2e19edf252473fdf86bc5a597de0b081c125eeeaa11def2839452d8112811e3db2dd33154a6ad1f966e9d3755aa9d8d1cf2d225526f4ff708cb2f88b45747c618be60780c51980236db887f4ebe6af21f3672ef98f6c817c7a2688284ec79e76032212806e0f4f40721800edafee1bc63687ece56be3e4b9d647380124bc2d56c2b67580f96dd14a951900f44f019e3aaaf5fb58f16417945b316bfb5441ffb11b3c9493607f17d3561ea5ca665a1f471b5a6e23bea17e5e9f89e19d3b4a74fcffaf3d89f6b091e36a0b09998706601215009ee89da70dd486f785fd07d37340a4c997d072f0196793fe4bf85942ace5dbb5f06a47b7de18bd6a9304d1aeaa092bd0db722558d678f7141b75126a70ccc68afc0640f4fb922ffa59c5f761c42312552f334500b3855740a91e420fe22e22fa4ebbe9813e8a45be37246e099e62891de04f9286d274722c993ae899bb85fd2ba593dc0dba65420b3be21071f53742b9bd26126374b437511f655e05276bc03ddf07f0f5e67ba3bbce5b61bebaf22baa65f9d298386f3ad40b0093851456b8dc303ae9e17443056a7527389cb8bbfbf4e973cee93fe79cee5fddeb0da89e6e9072c3d10d3b54a0dc8082932e35a324376cb9e1614ea8dc70c3c98f4f315245796e48e2c9941d484d6e207292d4748070a890ba0391c60fcd1051751260c01890c3188421b86108108481087e84608720621002b61fbe60187baa276eaaf52b54c817e2a07e918a50188b8e321844858da70c7a83d9254052ba14a3e29379b03c93cee96f607c57e5eaf421c4a6af1322f54400e221f64402d7458f2d61bd5a1b31f01c6ae0de424369a5d69d6ab45dfa5f6655a7a6237ebf524731ac1792d5a5a9208c89bef1fd7a2aa223a81a5fa0a9e8630d0654c8854055700452911b9fabf90aa56216e7c156a8b071076b2a0663c3181833f9c6f8e5a9d8a353e157a3627bb18d91d21250bf928a138963e7eb46851ee760820a6b2f8eae98ecc7417c4985a0c278a98206ca15be948a60fceee257a508b31d5e007f24cdc50ec0d7a9008c35182b386c3007153696c19c8ac0d85fe22e1ddcba03daceea9656204a6a940e3d7545ea3345046f03ff95efa2b7a6a78d9cd363897591e115ea33a7a83e9e407958e0b870fc97dea2146d5b31aa5bc60c47faad9c23eedb924763dd01459cbc8a236942e19784ecbdf7967b4b29539201d608530b80086dbb0946d8b690e9ff6bdb51af3e9da255f56d1deda724c5a56f2b28a349d99d6dd1bead7db932c6d390e91f84c6c0fbfa129037baaf3f019984bfce7eb44a14d85ff1589c9266df13a9689f02d1fe4cb4df89f933edc6efbdee616fffdb380b000a7038c66f25a65dd77500fb0e17e9b7dfd47f394f7ceb5bdc2a268a9e0800d1df38ad3e05a2c7716bedb72776feac1414264ce8149d6292ebd3294fc2af34fbfaf48a27b9b0a257b48a6ea161289a5c1fd3295a855275b8c3f11804ec2f42b3fd21b06c718b7f8b8b74ee4bf40dd5514c46984af4691e5591cb034f6a3c7a5fd7243e91cef83d9cd9dc913ebd11451a85450ad581552a9df2a3fa32945cee8d1e4647a57aaa725f6b9dd5a87e66739bfaef37d128a7d527d2994239adcaaeb9be11ef67a25ff951adca2c7e743b2d55bf133bea49ac63e7093c3c82d3ea7f8c7ff1453f82114f924931be7e43d95082c7e12fd22a94ca6995863d427d7b670c4ca79c56dfe861fc48a790d81fc1935cd4b003d9dbdfc21eb21fc1935c7c7d23fd246ff490bdedbe48e70e8f43a2cc138832c3108d8a5e88d2692e6422751afd162296d94b208e771347caa27e4c1c41227194d55f218ac00d895724d2198639705a7d105e78b435ac607d1e536986a51fd1afd2a577bdeb7b4d3ecd8ae114fcf06d214ca5160f7e2dc49647f32510e7b310e9d0755afdfb444fb9dfb29c4bf45836f4c9a167eecb58b77193793d27f6bfc41ddcb78ef935e420d4416793f1a419fef68e64fbd86bdb9ec8ed7d75218766f3b6b12823a9994fe5edab9ddf526d25528c8888e8efcf0ec227c2453ac7f0c87dd3c771f48f54b6d6dbc4b45610c1361cfb421194348f0267d733c82c170de9cc7d119afb87c072ff1676107ee3229db99794d3362098fbedbfaed3e18eb470fbda54ea2b3fdafe65b2bb3519a76d2f83caad39edebd3d19fae905162f1db7b14134f82e2553c298e2771b236d7d16c3fda98da92b72a0fa80cc525499b4fc74ab6a18a53854371c969369c36bdece68ef48ba03079fb4683f5658b49defefbc0c9417914ae396d620ac8ae74baeca7b9f148c2f42779e38a27cd0f01847d30d8b7d8b8e6b4c61458218e6d416e68e82596973c996edbb68570652b7e7b1c338685c5c344113a8ffe94b77f89443a8758034e0b6103b7f1667981a9c40253a013a907f33d0be613dcf9fe935f83dff85906f12499bf1f6183ef7df86af9fbecf77250fe0871e0945be4b0bcc4c9f24f96585db4f2d7a1a54ea3d469cd8d36723f0d992cb631dbabacf669b6587effbde48662585dbeaf1978d2787178d26be049fedff390b2a944e5513f68639fd1e7b2fcbdcbfeb66fbd1fe51b1ef2c6ccdf73e049f3bfafa332eebfefe5ecc34dfd84c5054d7e91251617aa5c65ffd6c1e7be324cb8d469dd2d8f1c4b0d5da6a47089f34d302b9665943543b2832e252483faca24cba8ec4fff78d654eab83aaeacacacac8e9007c56342c783b2d311f29e8c6476e8c8b29cd6548ba2b9b4e39a47feded3bdb22ad5714d25aae547fefd4e3b2ea71d97d3aee3a27d28213a88fed9f179f6d98a8979884bb1f4fef926cfab3cbe8c2577fc3cb58ec8dc91765cd993bc4dd6d240de7079c3e50daf72256f78d496ac41f2864fc91b2e6f7896dae02857324ef399d36853b5bb943573daec0600240d51d6f0972fa3854be733f8f74a06a94a5529a32a15ab5255ca8f7ce64a5266f0d8bf863bbe842a59d62981491e3b2e245ae156678c87bcb9873b52293a5d767d51115509cafe5528cd93bdca8b6cc4ad50f268f3b4711af5a48dce3a736cb416679b7087cd14cf2ba7f9cb70e1da3eb67a9ef75be4395e79345fd2a6eca69f69d350d056e59b2f3b7b63e02fbf31f0fc0014fa740d3963c07865b9b91316217c3c40286f3f1639e3eededdeddeee2e80d7e854d5b5d121e3ccc9d28d20f9068b8b54b61fea904df8c9dbd350873c024dde9e082b7aa838e28cccb345de915865a49c39f2ce08f44cb18098193d0520a2004bb8d7b8810e3148395835b0684de4ed319f1834d09878a1046bc8851822601a227178429289788f58763c76800eb7711bb771b5d718c29aa11692f4e48d863bbe3f3a6c1079fb4f6e9bf71a3d90c515a1638bb2a34ed131c9e40d4ade1460ebe4ad863be6156b396b2d6739ce5a8ee3acb59c6dacd7981530c728007695b7b7e10637f2f64db353a9ca23ff3086a4216bc81a8e474eca1ad6bf36cdb2c5487aae63113e735f75589087c8ae2af2f6be63c49913a1c896ed13f12108a0519f730538650fc83211d9068e2928db3c25c933a62bb16aa093e9d7d9c83dfdfa2fb29fcb39c517fbcbdcd986753e2916f590f9ab60a55ca593fa9c734ab1a93f4ed1f673dbbebbbf226b41a425d996dba8addbb66dfef43ff0a71e3642dfbfc3462693af63b82f2d74b0b4c041a3c58b16aa2c57626991ca02857f1ba02c7d32105859e8c8e142e8fb24d6f149b720864ffa273bce9baa2b504f5a79d0909982324850569c2d5551507db4aed05499e21a4427ab86f4c7bf3b64ca8ab3a58a42f5d1ba4233ab700da29365b5c59978d4569f36574dd5550871d19191c2f59aa44193217f763339b67124c3c995f555b4010930299f94948a5621c465874e18ab293599fcd97ad3e68a53f913a13c76c88469282d2528888cc363f6c948e1caae673ea9544709549675a0aa2ac8b24e12429e345dcc9e4620d71583b29003a70e6bb28a6334261d4b2ac3277df4a143a84deeba6957599336af647f6448b979f2d85aaea524c5059de636bbc85d736bd5ae161dda1ad282b29434c6f6933be89e6a7912f7be256fc81eddd3b7df51b14867cb613b0595f96444ddae95ba981aa44e232448be8cbe912715d19f4eb7a66236e276c834dbb387f3377144ca5da7fee4fe427794511953ee48f352924b9ba9df1b3f1e9768f2c690ceb4269b19c9e742a66e3aabb7dce8d34cf148820addc9367325561734b9fbcf1fccfee8a2db721eb6edb211b77b1b32711dd740e40dcf96035269490a4abe62225b6bed8f8d6473b1450d38cd620ad021d069f6abfda5d18ed6b970c7e7aefb4ffa10e8342edb0fe249f3392ce0db8fb9b54ff31ab646d9e259b648d97e536d855c64f983145502ed8981caa097e1caab26dae4ab27b676d05c5ef808f7dd4fb148e2a21017c9cff1e10fecd33f427191c435a779bf348fbc59965bf43df771103832c75af6b8f770935c427e7d08484a6553371e5010bae5536c44d237d2fdf29d72f4055afe3cfc6b4b548a4351c8b2960e4296822c312164c972561422daef82885f57abb8d695ba1322660e37d12e5289d428ac2d52b92964969bc0c9bda5dfd5b82ef75fdf7650a473632a649637dc44bf6230856f04837857d95fba5883e20af1ae32c54d1337392e01479c29f3f92e93320d7c8238684cff7e8a63adbd5726fba7d16ab53ccaf2d2129305490770438386a4617f8a967adf874799ccc3b56239b936639829a64e03714f9047e6b9000b0bc329c80d8292467f96b78453c53ca95f0cbaddf24d9825ea5435c22c4d3a5999e60fe6a38dec7decfbeeeeeed9753b7f9fd8d9136d6419ea186532bfe085cae1d6e2f15e99ec7fd63a2b874c3488a4e15f834b06d5052544147a610d1e297eb404c240171af04891f3c211503ff4fc98f2834515c70d181fac004d61ed6025490b3b5c3d01998008ae8620f3860956abe9b1c40b5661a43841288c0b7aae7ed872441a3e7fc84c6d519102072a5f8014e0ce0d50a41043460f15253e1813f582941b1bacfcf131850d9f32649ee03a639320420a90150b770a5155a9a3449ead14903ccdb17e2aa045cc9c255c02714539616b4a1b1fa65a18a26a2b4a146eea84e91a225015201c9441a3c218282c2a6c4122b6040e9f3f48e24481460615424ff0305941891b7b44075896606305c9172778f081844b8e9f207a78810918ac1147599e206307871562c06206aa091efce031e289e610a5844a203d73921402b2ad3026cb843550e030031e1dfa386df141abcc1d364a06d10162066acf1327a04972854c1148fa30890283952692fc6843c49c21968062cd98273e4f9e7670c3041aae27c6b0405327cf160e53434cd9b334f524a84ba11d8c00e4a30f57151c2e3f044103212d164b04f1441515345f7cf8138750117c00ede08225424e0b5b2c389146cb0c0e40aa2042cc953957dc2cd1a3c78b172d37c839c3268b1240560ca2028a9a2f4c2ca96104554870c0c18b0c54dcf9b18547892a4e7208040550e3304412384ac8704159d90324a985386a9edce0820e29e471ead2044e116b9c9c60e5e40509da03c4923d46b0c1c3831049aab2689132e5cd943d2ce0d08298292e280cc1a70c0c4294f1b2041c1a2f6cb9ba93c3132af2dc9162cc15ac24453821052109a2ace2e83102100d4bec3c290305104c5460a2901c0000daa1891333fc7043109d46831eb0a8a92384151c02ddb983e50a950d43684d9955fec8c044ea0f15415c7400b227062dae30625ef0418819a63081a1d00d83d450d143cd0b280cd252c84f1b3b630476ea58c10288871f7c10926242171a2850a460a18e9d2d40d080a7093d44c00122076581e2091f700044678d07d1c2891b2c535c05d1054e92209e88400452505ca0e80e40b2a2283923454f145498002167073e7ff698e943e7481a2e4ad0407581d367db0148122552cee880670a2a0a081f777e70c1872b774a68f3ea61047874a022850f95fd4109354738b9926213c6078d1c4a7052051a289e18e383d6962e1eace080e40a9f0ba4a801cc1a2d506cfa64bdb1128513564a602551c6043349f460f1c305500e76ce076f0a29496347092b5e7e5459196444971050484cc18240932d490ca2420c201b7e6c4d00e9401329516c4913050629e4dcb062068e1070e068b1b1e1470f422c7992650910535871a4e628c1e70d1933492401e41aa1254f9a3a4d34f1c56d0f42b6207142541329292cf848428a4025cc0067061efcf49a21366ce2f82113c70c0cb3850ee84c61a7cb0c43ac00050f439e50014686334f30a9c2879e4048fc00c40a55bcf0050eb843154dc4f8c12225a7490f63da6831c20a0a9437960a8a0f431471821e263a2b3f74c69099a1ca9e1d02253922051d6840814b9516664013c889a0428508593745c41046100c6b4e789203a4cc1155d21402d3650a2f3ac0d8a2849d412c8871610bd5f2044316159b364ab46101072758b85089e903050a1c252be4d0458d09960d0382e81267890e697af0f2c3c91a3f82d0c08082191c68144f688591218624f2e09903e40a134ff6fc8064892d390052c3870b9541223882eac70b80a892dc50c54bd50a388cf98245cbcf191124e902f269217184931bb268b1e10a8322e6b079f264cb8d161f51459450e8496b054153d644000917b8d2ccd9b3e7ce0f0a5600c24e9c1e8478b262d578e0843e80888052e64f1d1f0e3813a689541518ca98a12b845a604c382206139ad840039a142143a127c0b059429dd0c04cd50c3518f18402950f1ac270818288264db26cb06924d7115dfc747121cf1428a7335855ccc961071bf6e84193c60f9e126a28a14fa142406aa012870a0d48f830a162cf18604d0d3524c9d2c29c273f68dc9902a6cd99398578307381416500b500c49a1bc0f8c8f3c3698998285200c2cf923c56fa4a0bd4551b3c264c8d800a2e13cecc41a38296327d6c19273356528298d2d503143976ae5069814fd50e56b42c19a63c764ae8634505191f477698e233821f96ecd065c7d8c822c41077a874f1f285859f1952981233a544d4f6c30f1ab034f1439504cf9d1b762cc18a228b55550a537cbc680250559799276e5010e3264e1829fc7839b325cc8fd89a2853534831a1cd9b30370a2d6ed858d990c64e04deb890248e134468e962c140c0c99715906811420a8f949baa4150f89026ca1e6b8304a8f0738508395fe6c0e045f8d032c5091263fc6c71a933bb80fc58820c0a35d4d9f342962f5ac63cf1b0c21a255b757e64c00426a25062c21159aab0da9202a50741583f3889f263e4a2439620608072c58b17a727aa29e4acd9720288259c6698e2ce141b84887a628dedd26304666488028d151425ace429b4f507082583f070696a33e50ed6184037f4f9c1c19695142290507206cd96a4a8ad13c6f499a2cb071f47523cb53015a609992c5b039e4154628c10c286207c98539c528062a50d9f13b0743863b5404049951e3e4d9e6c699343befc81e404892f3bac7026cd106eb35cd0b5060c1059c2d0b0c5876f71fa656ea8e8e2421362a202b1a1c2b7640f4de40153f5b4c3133d406c95d3131ffa305104d70b56ae36212678226a08404af8e86141f609428d9c3b5151a0a8e227853c2a10c1248a931228979312aa3c5370bdb0e5294b833a348c9181d09219465084152e7bcaa8d1e3678dc592a1a8e20915549c0064056ad0d31077e444c9c14f12a9278824415cd97235680559e8cc9592262290418a13c69ce9210c943242acc9d1364b382de47e695db6992d4c4b0355972b3d4be450c64a8ed62346047ce658b9d2849a6944e62587257290f0cac1a36ae0ca418200a4a8012207fd291a9173729020dde4a0984b51bf53eea9a40527545630d22cfc119483045a0c5b5410270a513f60d1ca61444ea1872b07095486b6d24a3c2f381194638a9f9c1c2e7626c19ddafde93671471b18dc515e81c083029e64b16c1894fd35a875d26d9a77ddd0f8ca0e9347fe9211e5f270da0b870634d4d0266fef7fc5026c5d19321de970631b0f77ac65cfc09324560d7464db8ff2a7e859bed12c6ff8869e7146df7fdbb60d8f14bf0ccd7d7943047995e50d118ad85c9fc8963d6f737ee7ad070272c543645757a698058ee3c4a128977baf2092ecd8f5d497b9fef6453a6f75f44cc2551374b20c37702aca76c2a359b9cebe9948c29dfd27c3c91d25d74ce4e23979df851c3865af65683f99e7dccf822378df775354dcd1df510ec7a453553e501f09a5547e549f92c9f5311e65b25ba95ccfe3b4fa6ee7b79fafa4d4f2087feda0f0e34e1cc188f81f905f7f842ad5df22b928e47a6b1545d840cc1ea6390d3f8bffa4d8795847dbc7df33a7e1ff2608b683f85bf4c4a7118c38adbe8c17eef7db8f6e0763698740a77ddb7f2cecd0751a935cc5173196d9b3103b53265276acbd5726fba7d166f893bd95bd7d1add6637d9b66d2eeb2b7baf0cc41fad86fb39ec4f32dc51728d30dfdad943de4dd1dd4703413c09c46367f061433f247ab50cfef7df276ac089db19fc51f631c2e583f0afb4b6f3bc877df88effbef07bf89d66556d632b50070ed700909f4aafd7ebf52f4cc2fd2338702d8479e4ff7d3e02f6e18ff20a73e98761398f42ecc13cca4a64317d2f311443a85eaba059f1386bfc1c062bfedc2ab99abdf0d8f9d5c25a5ad18f4bd9b2b0af812bb5d1e3f0a4ee6dec8b6077e85b88721ead780944398f88a4f0eb6bbda084dbf9f5e32c87cf0213e18b61586a8976d8793f7a955b7baf4cf6e1b49d9db848d2272d2dadd748a92c265ea7c9385bad7529d7d720897b1cf5ca936ad3ab2688973e3c2ed53c3cd6bc8a96477975559543fe17725829864b9d8b4b4acab9a4bca5de69be62ccdd7c8bac430f581265855744b9dc5bf1e98e5e953917bfb5f8f1661758666d0b2ce53b97ffc98e8d301609661260e94731874571a5f4bdf7d25dbae7d5b297818747ae467b5991ad73d7f2494fda6a8e7ecb7d34547afd18cb9fd1fd7136f42392d28a1f6de42f83fc7d78e47e5b213a4c0c45ee277d4e9419734e9e3b0edfacfed1f92e0e2161ecdcb27da0dddba1cd8238e610eddafde779d498db3df7f641df823df8a1383ae5f05e5cc443e6fb3b64beef943f11f69e385e207b7f45ef61a253f6442235bfb01fd13540eab45aa1b8dd8f1e15259365f728a7f9138d9a822697e8110d713b1c935a49a5ba15e6a43fbdef6fafe3da58ea3fe706b247d77425a7edaebd886f0ce28426d7a72edb6cb24da6956ea2cc467c3fe7f46f9a0990591baddfd71f96326b8eedec7fb3d60fc4d26916c7ecec0c31b7fe273ff949a9f5a2dfe1f75f7b0ffb1ddec3de29879b08cb135ba06b50ee3fb17b4fb493291e83f820e9b457531aac6c22e26067ad37fbf60dbfe58c85db5b0fbb5d5bfbb57d4917c716148a94d26fa23fa78ccaeedefb3bd554ea3744efed5155a34779149158bbda55eea859e0b9dedba9147b222ef644ff418cc3bdf55ab9ca1c3888e45c0ff7687b0e5dd92eee83f2f6e10c3177fbe9715bd8893f6788b9549499464119ee702a7663101f94e7dbfadf7b6253fdefbf2a8ede831e2edaa07bef7774ef61e9343cd62fd2d97b6efbba754c15834d937cd6939a5e6423ee18c4a92ad39fdc48390e8f41a49d3c5f8a4df367c576b287dc4fa810f2749a7b11df900b967bdb74d28dce6d36413729f1b83d7761d67250b54d4a9aacb9180cdcbb6bbcf5a48ddbbecae72cd78944680fa23fdaaf23ed05d05aab04fb096bb9e7383ccaaf1fa3d25c868fb31cf7dbe3704fb498c3544a79fd846f48caedb73df108e6cddd3d46c473f7ac3f7deb2d0898299eee4bc85a291ec14c93c0918a31799d366b4c56514e2b8edbd7ca49aea5c441c05cf13c615239a94884663ae79cd8029a01e683dda66ea574972e5dba9475932de54bd952ca96f26798913230dcacca38eda56c7987a46c39f4c427fd82317baf3af08233acee0c3030f290eea2595f1a779fd3a7cf9196b53edb0d360ddf27284bdfcae334a995256d466452fa37469b7e4f4ac14b9b522e5fcff8723998f145c6986294b39df7812153f80a776cd96d1efb8f7d8174522b61b02be78cc562b198b7bd4cb11d5cb69286bb5f29e58c1aee18d9bde1bafb0bcb6df5850712b57b4fca244a4a12d93e0422b10dcb68ed8e69b46634b56a36e810239fc9ee1962ae3f8ee96db3b2570a32ed9891ad04125c26990b17769632b021ed30151519196d3060c0a830e8f48621c1d768c46bf1c95cd0240df92e42a64f83fa2ed62eb7c8bb48d29a837b272174f12206337223a396f5c5bd4543e2782798604e30814fd0b66826338ad918f455b4019dd9c808068c092688c5b8ffa2286bb3d9f4ee60c098608225a618e18ece36fcfe6bc0c4c369f2c57087630c0b99624ef311b2f7e7d1b243064d9886d252820605c9e28134eb7697349a50c7422699d364c8983264c890e12d5f1fc07270efe5b133160e1bf9400e3b8fc25c163124f816226e21c347b215250dbca371d8a373110066a20c97d1322a0514c898e1337ac60cb9fd873a628831dac769f265844c33684737007646431a6715cc0a2aa8c02ba8a02b9043af1104b490e9e8280001a8a0021b4c483468582047a77c0406a02b90f3359230c3861b8000843a8eb60a645e2e8d96fe1a9db245a21132596081054d41705ee01774b52064aa218350998bf3ab388484ecedddb2be400003b041801a3566d87025375fa3532eda60667f9ac7ceded808466d8218b5da8bb55a0d17d56a2f6ab51a9dde4847722b408aeadedd534afa0a12cbd4b19b4f89195f261e6fb7cfd872251e29c83467b8c19625b692067d49652dd7bad1cd52902ad3e7406e86196b2d68ab64732ad39f616606183a030c9df1e54a496978c3d86695e5cf2873afec6780b9163683d1661916ee30cad269f70e0d4929a59492564a444444b45517af20db4f11af48f2f99cd35f86b47b8823e5c9a90589e05d6579572010c76a459569906ad55ea674aa75dbb80ff43e2969bea1bde19ceeeeee33884fca1b2da534c097b7e7f0e7e1a9b5d62af308d6bf75abb18a4167b3b9d7ae5db70737dfb6bf314fdaf0b87ddbb96d1b6d4a2f2ccfbf9dc3c6c44e7272939bdc52add8c869dd9c5740dbac55722ff1489b626cfb7944a7b518c49c384a0a802cd7a862ebb4d8fc2b42cd4168b93ec573cd000071db8f1cc771b4e380b5d6da740174e62ddb721c96b567edaedd74d6f02f74526ae7ec3ae70653fa56b7ca5469a594c6e04e48cefb9967485f0e5a5ae96cfa331441f1135dd29034ea775cfd8db3b3865aeb956fe973a2e5ba9bebc6d4ebd30e9ed68ac109e713c19fb2f4fe93a2cc9efd0fbab7cf6123f32df746ac94de739e671b49dca5a974a4fbf9ded7784ca5cee171f9a0fbf947b8b70fe222f9f5a7878ba4fd0feacf9776b2f79ff745df5b205389fbf910e8bac9bdccf1793fbd0bb4aee7799ef733f4807b39bd67f8afef6cbf3fd23df7470281c6a80984c13bb4e23524def0b65488fff5fe17d6ed75d716c360d8c8d8dfa3bbba7253102ce41b07e9c77204c7ebfe8b4bff7dbd1e067b7577e3ae013a17c553eda8ccc521bb669687915cf1388d02197d83604198b563998a4cfda3ec925b1c0702070292052946a2d1cadcf9a3eca2b9db3263c68c41da9aebf0e8ddcdd5b7d636c889e06675c1a7a3a55d966a366cd4963af728351a1252ad7347e24f5b85618b24fbf5f145fef3baf78f84e05ed84b1cbbec1d95c1efc1b1d9234872c5e60cdf7c328a6222ab946a2833da549d1fa36faae96f9f62aaacb65ada7c0bcab77ccbb7b67c6b4269280ee5491c877fd2be97f2538e5a9af3e9eceeeea53cf258ca8d9be8b71d97b2834b1b763b78eed856dbb416d3a6e7c99e27bbe75bde37a73dc97ee53aecc9c0db792d0a0173f77352da793d12c9b47a1d2d75ae644a339d42c04c71d7530d7dc29c53e6f078c1d3edbce9a03f369cce556c24998a1a4cc9c39c933e8d0dc782df95dfc0c9fec6cc9c33b3e812341b4b195011a99b76d259e5e1bd91d24a593f7737991ad4ace4300f8e7be2f1e6cd1b9f4feba45f6ba5df37d6613b9147fe2e582bd91f4bf6ef2692c6976be4a549f6b7de569e0e7bf640098ac5b051104792b9a756b12962b2179b27b955532cecc47db3656565490f43df78527d2b83ca8e846249da96623971c70dcbda7baf40bb657992bde3cd82b612b8b2cdb448cdf5a5e5b619ea902512922339924bae3877b4ff3dec250c8fd65e0a3e8ed93d288e5d9199ebc76c0adf864e0e75d03cd626ecf5c223cd0d1365f8f77bcb819df79fb755599f8432585aca9f67032983cdc973cfd29eb78228367495723f012406069035fcbb7b297b1f3e8b18d10a518622c80478717cb097372260eb6bc330fc9a27751fbe0d79c37ef853e97e18b61628d6e651dbad3bb971db36c58371b6e22d391b71e7963cc68e68b8e3f6dfab7aaf508c195d71b4d9e796ccf5903103135979a35dc57986595221b5dc44bfda5aaed5e616a2915824ca7954f495963b7bd1bdc057240e793f369104ef50ae3cef5bcb95e41b2ba90435ad547025a8f0494dd584e262911d2b8d569e4a33873f91f80015aa880f40218f96278d4d25b5b22c13565076bb0414ef77ccec1579dfe2650ef7701103642df09116dfe25dbcf8232e5e868bbc9739642f73782f645a2da8b97aab85f8a29c33ab6bf445ff493989621288a3f744efa10eef593c0b31482d7ba3d4d29a47ae75a575e55744af721a11762aa7798d1beed8542bdcdca1d7b1e287acd3bc1fc22d65f4fe9e7881a9f4e28bdeef0b8fb2915684632abdc072bac0e157cb1edebee977e275da53ccc2432821b5dc248e4bb97ef49b8577e8c7ae336c68e815fe0c757886d9cefb9738fe0c0f72f582ccf2d6030475b4d491ca5448ede57388eedef3de726fffb3816e67ee476abb18d7d65aeea837bcc4bd5547ff6c8364e5d5a0f0ca5c219b559a3b7a595e96bc61b4595de0add9ac1a172109baa38ca2ab2ce3c9287b5992869755748564d5b5d92c735f414f0ac11f3d69e8c71192ee8f46727b20371e3d7b9b82dceffdb0a5dcff9a91dbdf54f967c3ed794e50f2168a433a7b58c82c8f4e64f2e6a18eed5f864cf763fa682352fef018e6f1de0a32b5529643a21c7e32c9fbf03999d48fd435fcc3f00994480e233b9245c0ac3bafed4b5b67526cdc4864cbe15379956161f8afefee70488c225b86e111476e02c31f41f0e977e2d8e328af8e5cb8fe1f2c0cdd7dc2f0083ecd2fd1fb501c6d64975979fbdb63032325ce55ae3677a2cc5d64cb153bbd9a1a8134a3d1903c772454464652eae200bf8a46806e67faa31155dae6cf0e294f3103f9602cd759375c6ba502d249143714a791d99a525b524ef3a33537d66bc66e2e50ec7dc665a5bb7b924b510aebea7a5db18154b3519d3cf72816b8b1c04d4b650a86f6b39ead59db515b0b6b5fade907824fa53c8b47bad11e8da5751a47ab924f86e04aac3468f207b39e54c473d3fc6d6bb2d66e155baeababab6bc3dbf7c4e086edbcd845db4ee893b3914645a98bab6cf3f6f8fbba0ba06e67cf7b1c4e9b933abaecdf752ec621242fc85c21de556e3acae18edb95bc51cbee5ded80917bf392ed8f43486a35ca8d5b58894fee08a3855586a1a5a396b72b4963dcae44e83cb6b0cafe34aaaea8ec5a366c8c4e55b9e9fba6eeb7aa5cffcb60c58f76e85b29f6df18d821d94a17c0f9f5e17fa168a386848da50b785a9d966cfcf0d83d4cb420e85dd083bd67adb417f42a1ebfefec7f1d1ea51d1b9e14beff52cb0eff1b83efc397ad14865138baeffbbe8f1385483b6ec741f17b1a32d9eedc4f53a9a9ac1d32bbbaf287b10cbd0c8b2030bbba720ce19f477ee3caedbce2873ef6443fca8a18b00202434f8471cca3ba627675e5a69aff345aad46c569bd6468ab4cfb8ad2d7ebfb1c8f9dc3b7ddb5d735a41c3ef81f28d2246ee7d06b53c903afab5df928d8e10e91c34df5e1db98ea8ad3bcb7b8d7618278efdf523dd5fd9c084277673d68b13e8e19fadb59068d32083a083e7525d883a0d554f2e05eafbfeeafc5979e074eeb5e864c1feef0571d5588d4aa4af4ab61e3de124256cfc073c75a761b4b41a41dd954f287892f82f081d3ea8730edb493f3c0697d153a18686a55a96e3c725f6156065efba240b619260ee9fcc242c03c02c9163771df545f0f9b5f9f93b5ca727777e57e138774575757151b80792422372c04ec460e8fa015bd0b907c30f05f8413f67a187ee191935c3914472af55c7b5a79cb6343a9228fce82c5e1538a052a95dd6914ec875ba32a133f40d4e7b8987a6739710473a555eae5168a4f2e5d0b82b6f1c7d9ef3b710802babaaac8dd2c8f14e066b97153a8e37b6fab56ac6598b882e8c7ae5fca1b314c64ed0a7c63c4c8234d1c67f99347dffbe7638cec9ff7768737241a51e2940304437f2404436f42e718c246ec5bf05b0c431cf660a1a58e9610c4451bf477df58c82c377d58d664b175da9d9b0cb49fcd84d0a853e70dc81d04bb8e28c6428216b215405cb890892d44094416626c840eec80f4d50a7c85af5e922be4e2e292325c97eaec3d6c7b6de1066edfe66d019ff2a8e46d15353d0a15c34800008000b314002020100a8705239150349ae49046fb14000e898e407250198963498e032908a48c21841004082100008088682410085491f700f761f90214093768167e13d7818a9dce5728a1d0eea4d33d539e5af3f86fe2ab72ea3ea375bcc69718044e9cb57d12c6d6e9f74e5e5244c01cfdcbeafa4d056ee2042f659d394784a1b9eb1dfcc436901199a54d0bafe1d64c75e3c4d27e61ed97e44933596a8e2f68d7e304435c2c6ccad7c9895eb97c39f1d334ee21e86c89fb21058dc40e21673627c65201fcbc1a804dbb430e914ebd8ee3a057f78b78eda648f4037e988bfb933885e94511b1a1ed9f0e54835767bbfd7a9a8e66eba1f873d9aaa5c001d23eb2be19073e2a9ead1559020c939937f440dee58016153a9cb62e027552f645a2185cd1172ca1e2d6f77e1f5b3525211fee1ca97e10bf96df8494565a65c7e255367bbaec84623cd04c93d97a8d034d3e7267dbd89fb8dd96f1bedbe70334d50c560dce1077ca6291c647eb6c9f676577ed75420dc5efa1e68f51d3e951535add249b0406d2198d62bbda087e933ec7f0a8040f9c3fd62dbfe875e04792dad429505b4b0c66c1b1910f6275f58dbd520e1b34e7f93d0bcd6292b53a63312795a2c1b511deed9a6cdf91667d258fa661d3f75589d3681c0e568f89ac07f20afa2568835c4e0d20deab2eccad939953a08646eff54435c7360fd627de3cbe411fb889ad59e02cdf0841176a847f5b122f6f1b10cc8f800b049dcf5235c78614cc0c96515410fc10eaac550f7b5506d936720a308d018f76ef56a83b8b01f293f723ec5e8b28250c7a7cf4a680fd028136540f934ca25d817b36aaeef023386b5a8c06d1c2848068e6e4462e5294c41123e1f1bb94c92ff0eb208efa8e230dfb2fde398061907f4f9c3dbbdabedaaed0eeff8c2b4ee8b4e5f296a882528587eab9e262573ebb39932564bb0622385a96b7b8727bf9182bc70be69f2b95250e02be993bd26f21d5818d175b8fcc2d4c37b9cde1a9088f9437093766c7a7b0fd65a19410533b8cd637564870767d7fd210d6e67e4ee7042ef2fd27e069f2b0cbe4c35ce2e087c8807811c717fed1907ee3c9f5fdc73fa2368c3a8b7a12c4310abed7c7b5248eb7a3b1aa2a99d6815201ca2a9dc5d0f2d5ffb03fb152ab64469200c32bb292d3ef23603d42d005b0e97c24b6e214f622bee59839d21dd1ba216c33d7112d6eaa1fdf0e250457b89cf6d69825d452f76f90df22f00ebf353e9ba39b83cf4df4dccad8d0b9fb133512f00f306758c6f2e21d627b75ac7b79a484d088643794f9e19e70b796574b81de1d37c63578a2bb1cc5fd3de87a369e6c4b39c9dabce7132398d3f1d95a78b6d4b42abf33c46482971931eb27472d40312d7e182c991e30e79ef29eb5af6b7dc6a7a0588e2694ab3682aaa6f4d6eae1c5fc4901737313cc31e681d7980c6829b7d2068807ac1f759c7c4e06317afe21c83db0ed9b950975671236b4b19b0b279dc57da8a4d802d2de57a64c3f0e896d6a2bde56080a466c917546812097bd82c8e5fee073c010066790a50781d7fa511b503e2c483b91a5b17b084eac487450dc4a98eff57fd8079ac07c9a706dc1c6b85039fce975c632755c4915f66607b9a1cb8de64c937f3b0f920f3b80806aacc63c1affd5384e452a0024cc35fddc5aa6894767aaa192c9ec063466a8083fe8a0b2bd9abe2f8460d33b3b828205337f1bf32f0c14c7fddffb1a85ad0e01a514fcd7f660f1387826a86276dd8e82685ec7705c5414dee0d3ad18d8b0c0dd98cadea144c4810b5285566b156c9896eb5089317bee137fb480896dc325bd2c8438335a087d1d961e8bfd6822bba8ab53b33a70dc2e216346db75d27522c85017d92d55ec21575954f0249a98a9f60bbd347233a74976ae6ad7bb1d5123363e4a292558f4b3f4b0260318d2c1e49006af73dced302fe9443ec8704b6597cdddc8e622bbeed3c17fe7f5a41105e01c5c1caa018ea4c81ab2323ad58e56e50c576559800ee394f56cec5162461d519d9ffbc5304ed942b4aca55d624f98cfe9864ac3598ea8ffea72b9e3e40784dd09f1501c0ef86e17b9c222a3cf2b69805d6966dcbe7eddffdb321e2ff3f6272dfdf99076ee571c60f12f4eba0fc9776ffe1ef94f6ef43ba11755f89a8739f01e04ca7fc1873a5d4340f5ca448821a267f229b9801fe11a1896e4f05684371c31884fdc111768f03f1766f29b2560309f2bc6d03c05535de86e16a035017886f3094c493cc3b39446087cfd13515da6283021d1cf52e4a6d56c283d7b7a34ad90cf42f16aec102403a0bb4329179541a3431de3849cd505eef0ce4fd95d1fc037b5655bee76460d19add5567a050746906efb399c48d86e605db91c4d6b7ad90d3bef8a8af32e0ff9314074c705f9ecfe12e15c3101a63514dd694d4f393fad5e3774b1fe40f7b5c4b8410b2d706448df69448475afc979e7629573c62165f83761e1a28a70820d9a7a250ad91f7e7a6905280d3969a49f32358e5dacc8848073d4bd9cb96431d2d9e6ed9fa492525a17c6782558c8caafce5ea37242e75a56aa98ed3c64442742f269a67c7a233f70393cbce01678cd31cd4e1aa9ce12669a083073025e40d05b0f7f1bf08047d2581f877000cf70e6b51da920ab287f30ff836611bcf651a05ba1c9622c9775371c617347b4e18591fedadb1874e4fca5c0020780d595465767625ea4b3325c5c7066a6b63a802ce0e64dc3cb9692e0f0a380ed1ec76d05f407e074f55fff3b21dddcf3642ba0480feb6542a84a3f0cdef047705fe4ad4ba3c584bfe2afe358baa8bfaccfb3b5ee12c93990e7d17a703dbcdd7ea6f4327e58789aafccc7b866ecb560efff93d1a35398e44c70fdc19f0258f08fa953f34beaa3fd7800ed522a998dc5cad3e38925b24f8c4d5902a32bdf372634b2a0b4e884bd1b501decbd0602c0053243410224790fcfc68477cfd59b4149630bc5ca81544dd2580cf9f61a24a4bd929691acade8f06a59535760a8305238a22a4bbb61a5d8570cb6d1af46608c4c0a00b898aab8f4a0f633b538bb47a6576a99ee7fbc77f898f27b3c80e0aee6ac93e3f2e8335bdfb3cf0142a7c02f19d654d8043bb8718b6e1f6ad926ad8d893af93afb6856a33359dee20a7b65459fb2b6f1e12beb0dc76b437a09a23d0004944e8a00147bb14b3704606477e80a1fb50e80fc416e24a58023ef3ca0347741aee562bb22d268ed6fc01ad1bb61b0af07cc487d551bbf0d069006080e1f47881a379308978b7be4afe51dcdf5874ea15417fcb60a94f15c8ee0144f60041f42c77a34f91819bfa9505ad3f936785d7382a090aeda2154fe2b4197ff4f1384ce0f577d625032ee4c7f48d0016a86ba67af1be268e2e3864c36c7051abee1e225df0684afd3aa09e211a3ca05c7d5a755f4d43a226d80a5705fb565675657ee802ab524d3b7a476caa1f9183e1d0ca90c2722ae673e4d9d809055f21ab01017528e1fefe519a375abe522d25be294043b7ed2c6add163bf29c6261701fceef8f9ad5baa3ff13ce0aea3447422937c04c416ed68db7f6cc7811aa6f8560e070ac44a6fea506c612197db0e4f8f561d498e330665bfa23ec649ba810e494d38a6287e814cf9dcffd1575a440516c78528fd0d5fd28a6de3501db3b2daefac84d0147f1dd0f39166631bc3d177a682f06a35acc9aed7b0da55c72a0dd7700b9c8c1e96b3814a65f284812c3178937f4cbb781f93c4e2b9879ab1e2970be648f063cedb2961d2be34d4ff89d2e5a77049e00417123cde92f0cf26cde02857def5534e69f32cbd4f7428d44982bf2404740172d6bfc1cf997914569a1d9a3040ebe24ff2cac31b38e82be1e704151532ab15e913b0e8e5fa18724237f0b0f5762d7f62af081c2b189c0c073b9197e29448eb0b3d953e04fa456b8a5308369a6a833c3d83a72ef260d457bddae69a25275ed5c3070b01a5547a61f215028ed2981ac97c975e45dff23e8d9091380fa1bdae333949fe1b51dfcd909b6ac8730033646c32f05df8e8dd65a7243c5e689b0e9b7b02e6d206dda03921c6034c2f07d4155b996bfdb8355064738cb41607b69216e76bb4e5727c1af2c97f1b29297d1d104466678c5560c6ad0d523d2042a7450287e8fcabebe6cd10993600a545cd08f2a9ae3376f39113706ffbd4aaf510786415da0211d196f140333da3fe9a767e3ff4f04f6587a67908e6887a6fadc461eb82aded5174db3ea510418cb1876b28fbac36b497365a3723b1483bd9cd670d2c452d37553bb3cd90b5bdbe0a7b6a0d2e89de948829c15a1cb6838f9e0fd5a0517d4102d0b0baafa86aec5903b5fe6f94d68aa28a549cb48debfff13102a57379c90e84bc8b6697ebc81dcc762a9bf343839071900e9be8cc8358ffb6212b315a8f878d0e573064afd99b613ae8e2aa7b2d1e84abb72b92770504529fca68a903d664fc9f09d05b34d78374b1080df9e5d837f3d97c932d50edf759b1d8fdc331a444d4dc00d7e2c122079a604424ef8832a748663f113d5e3a3f10e2365956e11024c04d8efa89ab4709dbff258121b48cce784c3546f664611d62441acc8d287afb0047c7f189260b574ccf7c10c62a3dd564d111083feb094d47bf5433a09ae04dab51471a65846f59a18c590792f6dd7bd23efa20b5e5da47e872752f8770c851e215ce04db9713573d65a2af1335f4acd03e2548c2877c4ce371a1a7d9a1cb306212179c5b8f08a03d88585550d31f1355ebb1a688e6d33207a3b0de5e25224055cf27916aef30fe8b8e4227298e5ea91b90a42b0faef525656a4f9a04cb089678e413151a306d663297b6c72fc811fff594267fb22fd5558c0d53438f29c0ebd8e1e1c87d932deebab111b3fdc6f25d9629f4025dac5df29d3c6b195e0d94508256dc030059d110367ca1ae6fb306f5d17709eda5aacf31a7299ae5749f1baae8b8c26c8f9659d0ffab876ae685759451257ed64300d5c3ceb6519f3d66476d9e606483b0e32d5afe8ec35cbe68084d8c4509abeb7267441555797c7abe464a33b6f0114bd181e292e02d84df8b29c53a74a0baa12ce017c56b529bbd02dec998cca69d72fb69302395c5f56937dc109f0ea83243a2f110e661a9c4ff4890a9f215a8f34095ae8ccf38858b050587fe7aa152d9ccde1df032b0e22df410afe2b8698ccbf77c6f70190117b1e08abb7206667ef6ebc4a9c3d3d3618873ac098085d78cbb530f62645c0233a27d869abd5d51c2f189e5999c7615aa50acbf3d257526e9ddc59c16a4206cafe831e8aedc7abbc194966c9ada9b21b26e6360835e82dfa04f2ce444382fd22a51121c3fa73749a28488ed32229d8cf9c488578a3c63b24a108848c8da66899fb489d334d9ca52e48a5ff2a03837a59a600a21e4919b82e9d42244eb998d21ff952d47042e1817eb56527558f07eae6e6e29bf2afdc4caef9cf20995333f1775c8e544ef0080f640f4cc231b134a3828d0918d782ad714a3c94a388c242980a61a928f5c63a37d61b966fa9ade68b8252b9d15413b61adc35012f620e7cd7f01ea120809a1eac411bfbfeafea6cc95f373bc65bc67e8699906dd61fac5ee6663f6a39a73111326ade8dfea851fd1cee18ae0da7124687ad19a6864bacee40b0f2a407c646838ab4a7e13bcea756ff622e15971989120b0fa58a08cf1e22c3db7f2aa5ef531ad75ead1fb3030600a7ea44de0a986094b20b1d52e26943f9f6b9e3058efde50c6cdf21474025cdb0546a0d461f7438c23f93a81df08dd5a26ef67c73032218e6a62314bb8aa07e68497021ea00d471562ae3403e2a9b6ff14227e0b9f670a4cf5e7c5cef89b1c26c65686afbf97a81142343cdb688f880b748a516d4dfb214a1be9ae189d4b630cfa262d991b2a4b2a88aa5e36a2572711014ee66d0b511ea8f2f7602042fdf6c9244e89c9ea184dbc3ab6409d44af6ef338d65662cb5d5a85789f36f63d0c89708bddf035372dff0fed3c6b4af07815407b940a963005b7bf91e1dd2b94acdde3586407f2f5b37cf25da46fdd0ccb09adc516175cd1a788a7cd1ffe21a4837618cff70062d4ef2a6901c8a1bc0396c32543f4bacb7d840c8c863152573d8c2a81e9ffef116f2c4e7eac2159f6df32dfbec26df446a6423c321ed99e312c216f6734223a6173ba87306810d4b8bc4255cde6b4c9fcf79460fd439082f26243d4650b850504db98b88ecea56b6537b8a9c59eb4045d2587e594505c3ceb7cddf9f0ab2953b7b2123e1ef95f063b17c20c17258df2480b9d45ca9e11effc90328cb6060966a009e821544c6fca709ec799cf4a4fedaf1697ef0133bdb63ca9d2ef66abc1f2ca6f581ce2eb37e26632d0a7c68edef824b95527b87d7dd2513ba9ee7b8d93b0885ffa42620fe3d2888db85c59837b3861ca49c8173b03ba74a6064b5d70dda7b09bb8872ed11e0b9cb089bdece9c35bc5fa409fdcbe09c2bb029d652791b3b70eb45d1d354554f8afee7564f79f582b0084593682385a7cc423ec74a985a1bc9a9bd61be9f40eccc8d906de825288e374b64e79889432fbe4b50792939d9b4bc57114463483d6c983d80549ad38567263bfda8ebb83cfb310278bf762864c5b42c43e172c9f7227a6a07a60656be4a43aec7da5f56876a4d82c81a4e0cc3a3b74abae5f9b265288ab263fba603d3cc8cac23d198f58dd3ed162627c5b402d2e48a61602f23644f2ba62407ff02854008769e876efab4637fb0b5af4a64553b65c21cccafa32256b741e75a1c5045fda71c919299ef25d7c3d48ff5d69b9b76ad658b6e717907b8619bf8bd5bc881e71ea94216161730651fd4c4ffb842ffa18411b80952a2a1115541c372e1968028b94eb6e95b11269c6b03f9fc9df1e5423bde64769a0d45974fc08c373e59529e8ccf4c1c762def1cbd770623ede0e099e963709d563779254230895190a2a2639e00332090d8ab65e3a80d3618d159eb499e6ea0e07d88d13b01d9aca73054ab70975ebef54ef74eca5e918845bbe4be1dcca54d86a3aca2e748eb4c5eb9d5e6d93176f66f188308e41d94832c686604dd02c5e77cd295bb09567f132e486f62496ef2e9e299801a34ddaeaf9f159e800e6fcb707c3532f04c28cc99cdfa95578547ae5923086e8040b2cc103987256583f2b4c33eae8d1a166db842282e9f2f3b6514edb0a520bad9c1d6a9824a091e946d8ae4547b8c4d0f6e1a6eecff43acd47f8053349c396f1e8da336cb9df7e80649499d495729163f92760786816d064cc36bcbec36a3b80aeaed13312166e1a06c52335102cf26b17c114d1b15075da72b7b40cd87edbe62040e4ad16318c999f36584d363456989754aa8db5a09f2c2f0ff98c75f8c9f89789b662f000e00efc554569557fc0a354f0d97c9c1518ea4b51f718d40b177b3e28fc22969246297acbae5e52ec00780ad57343399ed9d30cac5ee9486010c93366e9625c18e5063a6c94ebd5e1e7ff3a8cc7c085f010505f6e1d31c184b26967c0a6ffdbfd634bd7b2301d7a089e26fa4049f0a6571c9174dade29a7e8a515c5ca06e2b96a61c5fc186c7b7218d907db8a37af7162e44808c06af56289c1c6d81ae8b4d7aa26644f0e59647ce709a8ab06b185354b1f477ec4bf6edafff109be2bbd29b3262b52e68cd03440c37a8fb3b89eee9344ed59d88013cac98ed45517ee42f75f911a4467c29285e5d70049efd5c9e831cae33dda29d9cbe508c5e559e16d156589523d3c23bf04aae72db7967541a42b921471fed7b55d6b97febfcf09a024885f771523f7e494e6a0ed677e8b976e92dda987b9f016c44b543e93f5ea9f57770a0f9badad6e2345e6ba89a68a3b14e6ecda5499a60d0c8ad95c92481b552c3a835177e99fc5f32c33174420be706453096333fe4f410148f5cf0f93471612f987240789a3804fdb89e19d072df2ca3e6673909dab79f46837aa2b9ef32d4fb5008f1a9f71738f4bfd0ca01cf11ed2984629c64d2b8400fb48e06c13c3814faf471988b85f5ad0679c35415527d5f9947374b413bd4ef8c1ecf89359e2f8f33a8f070ef06efd284b82423e185fd86cf41d34f2d1353fba6470dd437a129b6286d9fd6770e2ab96e81f17c2afac05d1334253a919b5c017cbce7ae2ff89584bd2d06c3c5ce497090fca027a540148e8ca3ba672c407455ebe69e4f87824b9d64b6b87086bf1dd120d0828d261ba8dfc3159550180c9bc3101dee34f6c4ebdd61647fc9fedcacde1c1d4087488470845fd5f2988407ee119e2e0f2a72d681c91e4671c0367c62bc250e8d756fe3c5d08eb591ac0f2cd0a199d8dbd278d136b18b6b9ec38a34c64a848c9ecfc7a89ab33bb51533d36b1672b5b1cbcdee282bd979b7f854800e94364e3957f6b26626490c9c78086ef827ef70efa71ed00ac779a9e909799d3a8d52e41c8c8151ec311265395dbc01c10f9095ca47b00f4788f9664911b1a0402f02866afc8aadd3f53c63108a6574e840d03e8b779865501b307f941aeec64834382f2256810e6b30ee27e6ab8d31e89420e0447f002fa3c38531e0e4fa3f3c37e4a20046d8d71ac7988fee083360e8369188193ffa2d84b521bb872f942d2052b2437e7fa2bae000b9c52a2b5b3a7d867ef0eb38b15b0afc4391adfbc11885604d12e768c687d3585ea0e82dcf5eb691536d1408250fcd9766b98b1ecef1808b4263d9e4034af70a7ea5197220020c87c7c283bf209572dc768e424b957ae78e3ecfe47b6f21129c0d15e440b3f9938ff9590705a8c5d0ee0a8278f63cd0c6e4650e88eddeeef984358df0d891a882b08cbc5c6fba1556b416d2b7aaa365ed59478bc815d7a3baf244291e2a6222e28fa98a5c7e2ad2c2b9cbced97170384750ae3376c9c2168dce6fe9f169f59da91e2bee3eb3ccc1d9c9a678572bef7461ea48f3ab404d44a3de90217490a7cbf645ef31da0205fd6d81ec11d9b9809bf009280d4a05ba4e6f761109a8396eb0af5e2118e581eecf22bd8d9bd9e828cd5e3cd309458478f6c01760e22176282a140b8de08dacb7f1fee6e15603cd58d64309441f6956ff0ac23b5802701427700d50336f5c26f020ab6028a80c081c7af9f67816162775cdcce6be27e939d452da3d2b08eff76a0e276c54c52d55a3c002ca8e9fa7cc0f8414880d763302b650848ea980296c759d26b72161e7376ed41e24c71be16dbe939781e32276e8a6e6ad4e38605986733bc06fd614bcdae384bcc8560861c2f65cebc746ad0ee289e87d6b097f4929f080dc8c2ec4fd9954c8fe6fd7a3e9715d04539b812629b762f1c6c30e734672671801d2c900e85a7b013bd30df6d47dbed424fd2a5942a12003e60d6d20c34ed5af7d34f6a7ed1488d14edff0e822a0ef48dd6638115cb2d18efe3e19857af7136cd50dca3763c1d5afd6dc283ecee67bf290f7580a64bbbda94afe5a59be9c8f847abb39a50963d2e3b128ac72b9edb90602ea0af22c579cc86b84ebbe19107932d8267b4c41f8c9a38a8ac59525e4ff406e31f55b86f791c0ffdb29817f695970d7d25cf749b190bcc0760479ac4b502aeac97649529bbfdd8d1843715080ed6158433fe94f9fea7e7cd7f50968d32e8eeaede9a42c53c63f55818446c7cc68899dd6e9db53b3c7118c39c493500a758decc3831b6a93ef72ad8cbd1183b79e4478c3349295fcfca42aef5ab4f606196790089325b605d2191b4b819a7641dde6b4ab483025c15f91c5f7436c3036dc30ecde2968f47b905a5f62f7f18115f4c795835510b6caf16eedd8eb672e2264f4bb5c31f15648fe31f8146b811488be9599090083bcd08d4d54b88b34e169cc82c8706078c62b42b166c556a9c6d90c89f316d22ad501fba7f97c7456aa3f7451b83790b2dbcc09bc7054b06aec00f720f96fcc87d61f51a3a65e04315d07471e0df43379412c291caf5aa42e50fc3b71e5e8ebc24cb00a009b29714621293383d54822ee9438186eb8024d56d54195dfe3a3daa81678f4bf9cbd71c523e2cb303c24c25aee6f7626a275ee1897b099ac9e35fd2626efbd493b00c23ff73ec7188acbca8dfbb96809a5ff182abe1e0dfdff91422091acbafaa7c9a164d28c3696741c0d67ea06176e66a35b920a7f001b5f984c8c893a44a22479e8d279bb40eb6e432b30d050425d8494eef3327499824cfee3d204c6ce6603cfc99bbdc2578d79bdc66a38c7f076c77e1bd9dee578077ad433d2a54d49d80784b3bc7293cb1303154a0a90de16b331930d866094ed1c9944cc14ca0d82a7ac9dd4bbab962d8f07c499bc75764a6a5c46f8319c2f5920e60dea7daf427614d5cf330bcfd0e3c235bcfaa537252646675c4f5087e7a722b58f8fbe12c8a8fe97083e83762fdadc9f4d72fb976aa5850f0151fec19e2cb0454ca83cd5cd51be218517478c39364301879aa1f8c811e4d5cddbf1d5ee5af1dafd24dac2fb11465d54c53e4bc524f0cff7e82368d154ff9d6f4a56a25794b5be543a1906732bf3f4b7aec544e1f203fa064ce626768ac71af7cda1da859530021cf81386d5532a871e84caea62dc222d93a39102f0f281018a3b3f8c1918884129d2f2c12ba747a4c98f96502bfa1c65a6d68f9afa61afb2aa7aebc9a2afcc6c5e2e5f563cb22748693044d5390c521a4cf25f7fa48f595e3c7b7a715d73c5a9ff9de56581c9ec3e5988a5680b8adb1b5a0d54c506c0a50c8a282ad3bc3d6f7ce2c11781030650a629ba8f631587f4d4845a0f59e6db227989d0dab4a210311e93e75223df5d2b898cb38b55800953f357a79912fb107b55f08051a38dfbcf52f04b7c4645d3ef76af2e9d06bc45127559354fc40b9b074c1be53bab35dc6f4df4e6b6641aab0f46cfc2cb747df329728c487c5c65027aa8ddc95bf3512059177030b941ffb4b1a211efcbc4de8ec10d04b5ef959fac8204e01c7b39dd559505b7967439e2d5fae2f8b31566809315a1db10b37b7a7e51abbfc524336d0b98330386425a8b8322933d8868e1a1526a50fb56ec67899cc8be0d5a19405d613199437ec3ea70287f592615b4e4b101c12afb4c99801fd3a0cd52f9e96f7d7f278c4b5c66d9c12bf6db33c1b270ccd93b650bf22d010a18b587d4419c28861348ef7ba825a369bd3157dd0e2dad35858cf16a735741f39b4fed40422d7d8add44c09b02d9c32eba184905bfa0ce646c24ce2515d933550b162f332d77a05033c5715934141fdf158f82195510252929ba421625faaa788c797c0fab1247bc732b8edbb2d7cc407629b81a11ba37f4bcbe34ccbf230fd614000b5d4f5203f8f1fedb214417f14b3ff83b5d9201caf8f3ace516b27e5762473b7ae0c1a9beb8c027bf217fa94fb118053ba840ca63950e69f4b1153410f636367f33a7f04bcde80ff075b1999f2c301d325eb4600a566540d4a4a8852a23605cd6a7972cb085cc35be069ec54bdced3b991231e988b23945b40c7d91c0da7f50110d8828a2d07669b3e63dcb256b508534dc1d5fab67fc0010215f820e8924f4e0f9e4ace6e5b75a8f21d6bd9dce41693900fcc0727e672718f5b024e5a136a4151bb272e2aea66010495690858ba9941806c99b8a216ebf1f5c81db9e240e4ca6284c4947fbe839ab0414f7dbdc8ede15b1cb45cc7015d812aac631e8676e4a018319c071f74453e2077c5c67ccd292d612f85254a2b639b5f6507210a335fb289575ecf57b6071b1d3f00d4bc60354be0d1983a8629a440577ad036752f1a53e10e7e6ccad4e6291c0138a59105b92ab8188e056c65b84870cee00e96a7ce005b11999181d7533536ccbce4b42526d9243dc49f1abc9c16b78ad45219e2a070088d3f0d219538dab5d448b2053e123ed29a676a2f5c3b9843e556782764a4c491766b57061e3e0dc05aed42c893582cda50e472463b9b519cf56e6bfb6ee9ffa8febb1a72c28840adea8bd100b902fe89bcc4608d25276eb836438013b2d485a181d2cbd1f6a11a3d46caecb6b6cbc9f59bc01f5931cf27807d6795cb360b72a7b4d50e9fcfe1374b48d2542b9d75da3c23f922412c3cc18993ef464c6a1672296f6e3adc54cbf8dc93d28d9c0873b6c252950d2989c54b2c02ee67b4de7c2a730dabde33a63ffbeba0813585ba65c7fac9346cae59e05c6ccf8b7cbdf3949434cf2d982fcce3c7546d464b2a79eeb3f0a2c76efbe67b7ba50d616aa19eafb1e25285a802f16f8162df1849ce78f8499437f29ebbfaa7d06a74d615d691fe5f0b888c22334715be2dfc8781ad934284c63ab1e472d94ac547bb397e0417c661cc0986cb63861313f8f4aa80bf8403548689aa07bee6c93b2e199d984380e3633b6a2d5d1b5c1a6ebcfecb567ae67c746c3a50d8c357ff7dc03bca9561c34a5aec0a4f16346f0f39beda949d1ff2a418b7b9ad8cc14078d44802c0e6f943c5834a6a981d34c231bc443b6e8a5141a299c576a15a3a9cce5819f2281aa3822c8d222029b7a0689be2212a9e526563df318d316a7deb884f7e6a5775262fa718045533091d087abea6120c13e149290e635b70fb972622bb5993514d7eded16f9ca3c578f6b445d55c5c82ebd2126ad8e525a7ce5e099c77a907089ac79ef9996e44366bb6802c7ac6fb556e2cb4724cefa0b91530fe08f24b6f038905a3e5fc4b4f265557bfbdfa600930f1ca00fbc1307671dc8dfb609f903b480ec969411d47dbc521bd701e421646fe85f8eec16d5893262cc87d3f66b0e61b0eb2884e58a7975934753f055c035e81c9a954f17f1b85e624c65f7130dbf894d7955adb39e35ce08888a71120436a9cfb1a7226c7df5c5f26048dd8d4eb324eb2efbb0dce30cad2da6bac9d28751552d919d3907c2bd47aa98356e938ce8310102a115f3e3ce37095a187afd09af84a332535e4202e64d69c0bee6a9a5577d508b2d1d467754dcbcbdfc6eeae2ae996931a211394afff6b2ec607a40d44ded114cc1f96e1b97c649493d6a7ddc29f4046193332733d0285bab0fd5a5439e170f0ee51730460685e452a147915474e64ef8fa069cd78b58d43f5c22d076a62f23e62ba0fa67c43d2c1f567f2207fcee48ec0a485feedbeeeedbdf0fe3624ef06cb7f148e89e400b48e526b1cb56b49e5c32e26af394c0692b4941d82dafda91de2bd19743c65beecf53d223c9d37a26ac61f03b79f9dc853fca55fc75d8080d1bce884b36c6143291147626973678f3a746f32fa7cfe6537180a842046af96f920acff2876f3b386e99405b5389f140c0429441e0085c771de2deb727f5730c764643beae9b1d7a6256089ec96c1cf2f915d68c9c5d624c6657315050c609497d17240e5b25280f5e85c06feeb25a9d665a5c0d33f69006337c9717fe9e5d875f0b96dac989b5d0a4274a28bbdad37c613b97565562faada5c32ee9cdc55a841d332369eccd096bc856095f537961cf65a998937b5285ca109ff624bcb6c19c700d7a4ef2fd6818f3d9350ac1d402a1d929084ebe6c122546f6358bfdad958bf07ae2dafaf57a4d291b148b6fcf5ffc112a0a86a3681e53a01d44fbd7702c98ebeaa646618bf02a6dd1979a3155962cb152c56970888b296d7f895319c65838afe8a3596b0f13c31f6823242e24ac58dfa65dab72a162c0c3223d6b9261bb35cdab4e5ef8db69fec8af91c44f17e36a98575f39692e18c19d0d2f50c8d53c78e43e27b4f802bdb0638f1fd500323e2c7193a7c939a506327839c8571bccf6b8fa495b68534e524e95d2273e323cdc2c373a7aa563b307b545dde933f109414708f518dc97d74e4585b788bdd925b22105efc44a671306f5babfc6c8d5a806b871f70c37b7e90ea91fd92ffd2dea308be57eeea689a417064e9b332c37b502da8b890e453a3c3abf533c4211cc4c7492c756d42082cb2f051808a7e3299b6b4907648e62bfed19b66c95733af37956be3b7c86238062c51c300b7691c144e45e00c1a20164483f9221191ce06c490da3a3aa329ce8d91293d591f34af02560391d7179d8857e936ebb479b7b80ab635754800a09545e739a20e47857e8d06deeb162fa9e64ad6748e14db8846730a6390af0ef0267e3001c1e8d1995efc85cafb011d37d363bdec1f404cca8d3a1cb9d5ffc7a702a0124ce4f4cd68af25dc31025cfa11d59c789f2a790c5712a9c7335a45d1ef3ac59ba0b2888c6dfedf6106b477b444d02c002658418e12b9883a500e898ba5b12b055e799c5cb07930c60350572e47231b5aed39c757c7ff7696ed7e42790b72663540aeed29a0e44428321b5691bc78c84a25adfa1f724d4625326d36135cbe7a97e4257b9ecf51ad3878060313900506e6b7a4a74e2fe9a0086082c32ce73089a7d15fcffbccadfd7608bfeef0f1a0d36a7bf6d777da13b90027fb6d267794318786b44b2648128d50bc802f40d9c1a20d372cf4169fb3ba0999abce971ff0006487a33d764365f203d7c1f1e16e4bbfdef6de58569237e2cd55369d0c65146057963f060c2b9dc98061550b635462baeec6ee049d8fa131cd3a41c3258750dc1ab90b4f7f98bf6ae3ea435a3bd90faf71caa33980402b1a6e3095160a8da776fa27c8f6751935fcaf65adfdad94b60cd550fdc4c64af2ef64f1458ee2cf843961101768215dd06e5bbf8bc68b5cf67b6b3c4bf315875e9ceb3bfaa327e73bf01801dc1a09e9ee29776d914e558d0167a8a24ac0e82d36dff92689b18b532c2fb7f647adea2eb071eb9cdab9dcf42ee1f8f4f113f2a77692c6ba104ae36508fec7776ee1b5d4e1d978c4113718f302c54b654274595f3a761cb942f616160d3ad4512958062168ef5da7dd2599ecec0f113479d1bdefec2daf72737214933037cca3d2b709727b4d9e82d10a5db066b152340dc367f94f188955976e243cf913792d46823ef43629152be0793446bba58eb29871a6c06710d6eabceec43eed628fdba0dacf2787382711847c1ff0358fbb220eb7af6bba75d88e1c926507a3435623968178867064a7e53e5a43012771d80913e89dcfe28367c294685b9184156f201b143de9f7ae76fdfe061d9cd33cb195535e5ed2a1c9ad7643256b92391cb8d3a9ab26d5d7024b1843917011be53bb0627feee642228b8c3e8b04906da7b5f5d8b040cd570dc9494a8401f10e469ab7914bb08ecd2f6e46c10116021fd2751e74d178c32f141c6d70c8278fd2ef1f97efb464ea219008eae4d9dd40b0d311d2c47e8c2a05ffc503c1fad9661f468ce826c94ecec9d17d9240c80b0582471e1ea020dd54757c025fe32a934b92651411e8d8af5d69c07aaace65b031655e06ff1ba57e7a0f4e58448e67051ebe298091adf1c3bd01da657649c407b6a91f692d05eaa00d5f3cac5b759b75303def943898c18c8dd1877928ab1a90cd9222bdb4310072bb08f27157e05bd19ada79dc41940755ac93af66239442680d275b0378dd8d410243d9d2274d618933ed2f973648850d53ba5d79c584072b62b6c27d382a6d855a0cc5d385ae0cacf387ae7ae682abe3fe49c0e05000853c866b7e716687ed0b0e48fc5d1ecbc1dd3547aa590418317ef079de6e68c03e4d70e4a069f068ad0ff585b31cc38913505519f0dfd4ee16a17e7dbdf0cf01b43cecfa8c883cb34bad37c29bcb4893619474600027822f4ff7d4ffe45039c059850bb7b72add58493a3be0fcb81002c83b28c9cdf9c03a54d9630ab534d443ec1108dd5e3543dad8f86db82837c4b7a5d2db331065468147ecfe8a0c5da88462d5ceaabd78a921f600d7a954e9c263274de8b157264eb5d383933bc1844045e86fc6bdb6ff6113eea6b43e04026546fab68f335ea60191baff11fa89bc7da90c490ce24ee9a4a9164f3a6af0b2705c0b19be6274f1d3e6ecd06fcdebdb09c8cd68e305dd21d89946ee88ac1c8e14a37c27ba9fb3ec03c2fdfef7938f3d2c3832e72adf8855a3ea42a33df4e9941d35eb5131af12bb81311f265eeff13ee02919dd10eb8110249da88f509b9373b77055dc06fccf17e2951126b773f78f3e26f4015ffc76970ff015078c265a56bb06aa775f0c9f0b755dad3d9218b0220b1894dfea970b1d2b828be79acf1263a3afd40e0b5a813b0cba1a8551161740d2161bacbe060023426c830215c5f2e6a8af60553b4d9c20050d7a64178ba7e50bf01dcb569615119ce7476eb44880f97947c92a4c9df9a32281f83398801fcec38413e366b30f28fa18a822845df53fb26bc94b1e737891032eab80be396e28aa3020e955920a346230a828eb998a269c724da8f01f5e8fede998294b79e40b7634cbb50ee8f2c5acca67942096ac1ed9a952282339832df40380b82b209a0365e9029a8d8aa19502eea67c0fe9f68bd49abd989cf68f827d32e97f6f6ca99e53d9727c3285a0aa91bc1e7f6b384afbd761131e88c45ac229c4507f06117f6c9f32f8122d1ac3d413356bb337e0e1e7f07e03acb26666601f7a4fad84acf80a61c94988052d83ea476dabb2aa9ba1c3605389d8a1c8a2a6c94694f6cc90a95d05a066a69e806566490a947666bd408205e75691135dc34fb5224c1ac62152483d9cc73881e3d8288c9c2cbe4549a6eda812926fb14cfca3302b6ef1e6a590bb62b76618aec3f1d464e1cfac3d874b839035cdbcebe295655d6d558b8506d30cc7c42868729524401ebf72e6c076a818f7996ec128bf49292c9ecec836da684355aa391579d52ee0319e25b52263807d29e4d4cb16e9f5a589c4a014128955af57861163531004b7db5f1cadc17023c5e18e2cec35287b338a5374767079124f01c62ae1e8b9c06e1efc8455269d698404292ebe3beee2b3cc4b3411fc15230c42775483118ec079635b511b180ffe2c40b352dbf3bc278ed4b28609960d7ad5b0e9769321a08545705e9dbec0fa1dfccb844beab512da1211a6bf2d1e8c650b2be80d47d3453abc1e27715fa89a94b146bfa0305040ebab0362c24d2dab13089b42913614b90e64126809bcfbe12841231cd99ecba8ded0c1fd530a066828c1e23db058e61d84c104890795116089ae61b325351fa722022076a82a0ee28aa2648c045bfae8ec90558102021c34e5330ef928c024868336bd33652da7f0ebb531a804bf31aca043c6e23e5b8487d2feade901e44f56f5b18e7a641f32e17372bc243e06e2f6d2fd6a2444853ecb6cdb9f5d72b7135219f12e1732580670a9626563c10b8194f49868b92f1256dab3221a251ccd28104c053ffabb4669eba230d687debabf39cd67b79a6b5a69c4706cc513b7d4bbfa6e4a0e1bfb8fb67aa56c2cfa62ba24d565c01097eaa3133cdec3cefa7706d0adb173d0eb9523c2b81d35ebabb6d7b2d71b92fe40c980a249fe26a427e512747da3f59a610d3e9181ab113b9d8e24751ed81b00ae2db8a2156030dda4835468f04ad16f635da57fb3687e9f1e9518e5ed5bcfea78daa1b46889f74d593c49c69b92284c4d09a939f8c88b62f556f457257cfdbde1cd78608d13f9a3cd1c59f5d9b62b41b6bff4fb3230184ac40a84f4901ddb78d3dd378ba6940b39bbbfba7013027dfa126ea0a6d28c124ce7cc268deb82557c38948469e19e4a1fb00cb41c35215e4d8907e0f54588f61bc6f01b208347d84ee1e54f0c77ba0ce2a32c12b25a5ba91f693a05edbd8b2de0e62b38d81fefa1d09ca590981eb2714489b035c05c5a6468e8d036b6410a74882ab75fb71cb337137968c58c396a90a51a8690b661e33d3088bfa4a49b120b2c55ef8c8d2386c0d241230ee250bdcce8446b04049de18e4eb47b3b88f7cda48733d9f19c92b2b0a07a5512a83430d0340a389298ce6ccb07b6d27ac413cc4cf0e412f311241db342896532ada2c9b6bf43c86c75e891b45bdb5bbcf1433382a73a82fd89f91e1824339ac3e7eb39e0dc053bdabd6cc1c56f46cae3bbb9d197feb88e10ace164dafbd736e73a4137069bf34e27e28dfcd9b0507975b7a76339a110f11365393611740eb879990b5823ca52576c70b459548a2ba21debb02f7e781bf70853983db0d8ae3f5f8ca050f61b08c0d335ecf807e09178ee5306d13f7f355bbdab4656aa8edfce0a232b0f1d8507ae27438e79f02d2d532fc318667257409e15101cc3141ee3409ac9795646bb7ca1ab62c30160344260cc9469664ad163aa8f8f0b0b1c3926c6d3a6caf482f9b2f46292ce56558c0d1dc1a7dd012c25e460df25edeb868a9fca193173441328613fca8667a579fa607f4622fa43f1cf5ba489992f3b0788ae01259098b1df06a97c8371079e0578f2c12b3ec1297ef63f6376a844074b3ec5b0520df743a85a8239d82f9a72ed6388a7b869c87f210478f4daca50939e2d463732fbc58d36dac4ba5e371f5c7941a6f925961f56a2b3c3a0c5d3c6d7d7964573435b5d3b15fb5805aac2f508e598ffdb33bc7d09cd8bf291dc52c217c82ea969036a517c723ed8182cea8c902cd7ffb8b3d7611c9ae500224c7e7cba10ceea11aed55e3641493c4598282eb96a0e00c3a4c9c90262b0a6e1b1f02250e04ea34a69bfcb65bdf49aa3fb4f58196f330a099731e30d01d32f62441651b019c0894a2157db531b86e2dc512eb3af1c4d97590e944326c9326722364a60e3ea9fd41724843782e2a861b06b927bd5f81257adfc576cd1b18c3ff05a26b35c85e83028cf92d0c38b30b23ce04e37c666a1cf9d93763b1649bedb8a7e5b1b3235536a19c51ffec5f7fbbe26d080334ee076a68f591664f108800cfde21ed3c76708ebbdb7f8c76300a2c3bb6bd7f3f94f36a1856c5ccd4fdb1d6ade76750a15b5246d2aaa8d5c20f828fa75c49db11c64fa90230909d640211c1d4a028e67b9bc12bb9be765114abcea1999f1348a50eded358df3866ec187d380ce8a395cee20300a12585d40c33126c5a1099414f2948b03557545002d4953144801b04d72f49e8186dd5af27e72b71d85014cb7400a28846f17f4dd7e1b516cc69b450342f8425b49b4b659d89762e637fdcd40352a36159886d28e920dff4bf9c84646afb1213fc7f7c78d7ce5ce9789157ef251d52b66958c90029f165abe30903106652bccfb8a3298a74fd81b567ec120469acbf6226eb0e3874891115302a0d946449cad8de9ec4714c97f23fc493586cd489a9780b7bc3637777ceedb5e83977bd7b32ee83028b4e96063b353f5e7690aa6843edfaa5221cd970b27cdca50cd535bbca7b367a1ab196ebd432804b058f83d4be357fb57f403023ff8d2dc7ca8766166b44bcec418d7a91e5134bf351de6110a43d4abbf0ccd9c59b84dc51532defef252b87c3b9e34c90b85f05ab34233123704aad1c442c40692e67e014fc41ec637813d2556c574a1b6d798af94d84511ce1630f6f680c31e3c37737f15cc1f2959097f169aa63ef04a110cf689b8746c6abce0aaefffaf83378ce6700931108d5c620cca16064cc81480641895e14d054a0076a855430f676affe0815453ed688b83a52744a1fd2e158f964f4cdc12e056a11d2aab52e0e5010a3d60b1924898f08bedd80121d2190494ff61008c44f7630c0a6acab3e1f23ba2eb14315c3b803d6fe02ecd609ab568b5e6bb9a887728dfe85e4a4f44ee32b4f8e74df3ee74f4e740ce41553f1be02c46d401d74603787a4c877ba460705ac98044f0b6bb1e46c9f6ff2c04d285867de31c3a86c0a3e80be12a228a0f5389b2396ae679b0154742f558f6c477505de9f4b4f52153c219942c076b8533b218c882f16c7b0e49c23e1700e6c2a5daea865ccd0b0e051642d49148831c1c2475257f8970db1f55776cfd9dc95cb0d925e327773dfb0ea0fdc61cd3e62304c8b4768814bb08ea63e52ae2d3ef97648dd224f01356b522a0296d8ec075bf7f6504cf2879c2d464af2a893843be09baa746db35982e60cf06dea25d30e6c7f2c2f645609899235e899a6029f87148232aba441fbadc1902beac337e88a659c4ca5c1d841f79221c5d8a2493b42a7c667876faf6bd4d551f2c06275d262db1ac9941c57ddda795932830eb6a58d8c54878bb16d4f35b07908c9944dff3593c310d01aa4261a054474f8ec75f33d504ada1d939bb6ae21c2476fc80c458dd2ea8743b7a72ecdf3a3214b12997431e17ef23096fd1a983e0175189c48f61eb335b104d80635352e5cae800af523c8250d4f846c26e04186c31dc1e052cda859a1c7137c3c3fbdd2ffc261ac526168fe373b1576fa7c0ceb5fe2a820f2d86a55c03671cd8ac9e1ce390c5612bff898e738f40456a850f93e5b9bbe0e9ec33cb0522a186a2468a6a23c4911659563c02ad6a8b59fb9ae618042920aa25a9f14166c02196b5fb8811b144b275b77683b2cf12b9d338a4f1c247f1b12f16496a9804ec182220a5a911e29257fb08894c4a65e12ee00db94f4be780208b64aa20416dd1d37f456651d3ce494a38e3e8e5e7f1e5bfd4874dc8e2705cb26cd20def0c13798013ac94056e604d781b2487a8786e13f1222100fed94a0506eabeea0ce080a484fcf370fb4b0a812db87e836ec0ec00ee36841630f10a81b8fb383d1a7588a5c93318335f9ada3057b66b035e11f36b4ffb3add14227db11e1458eb6b4d17955228c2df836a99c684644354754736a3b4bb2df092b95cc594687e7439ab5260a95f8aceb899c3441a1622a1e9eee609b5fc10a4932471b7ccb1b64c841c2324bb44c2bd802f6a8aacabd012f3fe91d0d32a02ded28c46a14c5a73a2118b828b25db5cbfe38d72d07c0653f33c54ab880ab26747bba3b8d98a02518542f2741785fb1a37327c33d1425054a295a86a4f93fd4c8b76180d0fc63668bfe8c34c52f3e4f232a25d0642be3cf62ad9edc12040fd0ffa904a7dccaccfef349e31ffc1f038383e3ffbe42b2175879907bed15ad76c8f662feb88a663b8894c3adc5cc2bf794e68ebfd0692eb5ee479f877d97cb0dd8f3520381170859a946f7535da5eaef45e286b17cd279bd23ff664f041da320c26100b25fa0eafdcfabdf38830884f29dfc41767f887bbcb4b14ad5a4165f29c06a28b810c650af2887d4c957dc766dab6ebb0890c68ad2686c666f691769d0c1d882baddadb14fa380c7c928f6d34084c3dc865954d1c8d134f40ba82c22160cb60bc37487e31ad9264dd00209844fc017ded4435e231024ef721acefa2353a69774ca5de6d8ba7e602342bf308f9c85ad97324423bae282c42a5f8286aa658a8cc1daf07ff63103cb11186e39c8e3392403b5022955d91e7b37f34bfe0a3f838253433760a13a2f38ac6d2a944d6f6fbd7c6f044dc4aef63a05138745cc712b07db79da40ce669067a9cdfedc47f1f8c09c29d6e5948445b25b0057eea8b01e8a6ad76b2991396fd0fac9c1ca5e904d883b361d0519286ba5f92009684f1c7e8a44fa98229609e02ee450f667a2f76489c25145237171d0f0bdaf78a1738385685f408a403fd37c8af086ddb08e1332490e2c06bb338c6d5516b4e13515cc787058ac70589dccd3cbfbcf57e761563c94f90dc7b8b1986995b8cf9ad07bf2457487dbbb55cc58cf5d72d3581e3277c860a7d27d3e61b1e7a3a5028d68ddbe951d062ccd8f5f57568b3d2f73b1dd903489e96aa7bdca1de6d9049a416bea60743f1fb12b7eb9125e6fdfd871f7e1f2ea85811dc523a8f5c6f50a13f8bea7481bda00734068f67a7375c5160e245600072b051a5b7cafd0e6a6b2462de1b1842bc890cd1f9bc8080ea0f8a6ed25c07b2808e3c71101c2cf57c8c903203c9b5ed03b572674793f61122a9872a250707d12954cbb0966438a7684ac789ba2e99ca4b58521574d90190815ec9f36e1901633b6992e175bd9505b1a98e513924a8e4cf2e5dd1ddbc89d5edc1673840f49e19f4053b440849c3e075c13c3cf608acb3cd3e3fc0efd5e66b274b6e0c55b9da1c998488906a4db2c8a1030e7af75ccaa557fb2de9c2453b43346621960fddfc11acdc5fd85835b8238db37eea2c0d6c7ce95df772e0c1d1a01caa4a26802fe2bbf91647f8830cc069a1d1483ea01e2f6f83540f168ca78bb1836fdc94d96269a0135dc748ea89f3c4a8232b2d498a0025e58d378bd2b8575cd7ca830a9d958d3991b4079a14ad93faaec8828c787a2fefbbdbb16c925e0bf17ac8152302af94bf711c34bf483fd88fe87873e9f5fb09ab25704807566c8ae80b187d8119ca42d02b0a946884534bbca8897b1d54358cdd301ebd1beae3c1a452d334e72086bef051e0433a0c85d6504c3dae0e031a918ee0ac10dffd6dab3f903ab7100cf70f41997c7b9ac03670f0d8c327f6172b7290b43569eff185090d35f926b1893d9b8b294f341e589c4d985af0884fc0782d4c82558d5dc3bfeeaba352f24eee7edda4a1717eccf396857672f154df328819b501c28faf33e342ee4859760fbf16c2c9b298b9f63c7e2b6b335310c38d974072f31a0504d372b9ffc1e672ceffeb49cdbde72eb455cad35383842d5e78190c6064eee1a7b22105b078a0431f64f2d1ae75724b32da7ae762f4c2fb172f86c3a511f85d427847f928c178e06f176dadeb3ec33bf25c3a498065249a70cd060f2e885e9ba1dc27d3ac1af197dad3ab279edbe2b46a39f4297a694cad66db4c6911baaf406ec3b3588dcf2ee2bbe8c2f84eea89b0a659c46a2594bdca58aabea1969e29882bb7c4b2b401de32f5e047b9c9bb0ddeb4e4ebc95b342569ca6790ed0f9a688a5471c46c7513b24a951ef6fe01ca8784d967a01acea5f79d4f2d56035cba70ba2656fe3c75cea1132569f3ccb04bac0e7ef48c195c6002914da7efe3a65db98b9b1941d9253b3263f234eb199d77415d2fc44f5007009b781fa1058cb882fa8294f423cab658a805b459023eae196acd49dcab43c1d96d68e45f224499ddc1daa2cb303eeb786da4cc6e804d0c1aa8aadd11da881b41da00fe9f750c2dc2a8c96c072394459d9afb9fe2db5b09cd1594ad6ae008abf13fd662927642be29771aa801c82ef654d62c00afbbd5de967e6ca9ee419c825a461270e5807a4c12b31b80af5bc9d7d4b9412c108c6a6fa18286d8ddbdf6b8a91c1fa662c8f5387452bade18b4bcd162915c295f8c0bba6af163066d9384bfa8c65025165d5cef60f51f5f7730e90f1a46407da5ea39fcf78ff67b6bc8386716445a69a15c7608070c7187f57e945622e636cecf6a4d1916f0eac7aed16e7caa1e6a98f08e90ad7bb4776a2ed25d1593f566a2190fc2658262a0b815453d7649aa7d8b34a0c884ed693bddd946148173ebcd66be6442671adbd456c2c1b68bbb0ee3d5d620be5d38ab3d2fac6928a930275ed1b60314d0420a526711bcb3848a846ca4d744bcbe7bad3dc5ae1a7df4539779058905e3158c3ac6906f4f62599b979932741851b1c68f387e096e541f99a8bf18aef7a85683cfc7b83acf5a798a2daa4b0c400e579c2bbcf569ac453f8ecca0ffc88c7c8bd3a723e4e98fc25fb8d7a5fe10be4c1224dede725d44ec13c993fa96b34a9605f6cbecc5653dc8143f7d3fcc03c1a83242ca71ccce5de83e463a7c51a2280402bf410a92389b0ec48332ab244ea38656648a6b1bd43424e1b820150299574166b8ae53ea58212362105d8e1528047909d4d9680d011048d0251040e759b87d7d5ec2f073afe2fc82037cadec538bd50efc127597d3f3ac43dfeade0256630c7bd612382eeb702306acff4ffa25cbb072062113414c2f4c9ef5626fb7068af1032d02afd007d1ee01d59d6fe1c4a7f4022ab466f5b84d172b30f94b3ff47ff2669efe5583573c1ab59afbfc1000d94337b9163e5d5908c8b14b943aaf7d8c505dfafdc1b93152f6059c012ecec83837b47bea694870f8ffad767f8ee3989222378be82f0218f3876bbe0ae836fe2cc4091dee109391acfaea46a61c05d96535935e5bc35beca27a5788a5f588b522ec952d4e072293273fe171e1d9150a5a8ea8ed5aa4504f08a75f265d90c8812d5b721ae9aa7a597902b496909ab3c9dc3cd27db55adc269717cab23e2bc610bba8011b59ca3ed8a99c94117dc8dbecd3d28953eee33a5efc06bbd419ccd53fe90d0ee09ab0051e7beae39096815dbc45d72c4fd216a2928b0a49158c461ce47278da81e011571d85db24fc25f155b45b384318982913ddcccd0218c39d54a1eef171183b50fb0c477962e72a0adeaeed186f4530fdb2fe22160db0079d802b4d835111463ac3957ff16a8943985876fe036058661227a9fad69440e5f11fd47bff44dc80a7f132201adee560bf923fb86f13736d144f3d2d3dd5e9915520a0dfd453da2c51ff0d13132624f03a743526554bd0bdedd48258f29d904a262b66275141a0ff03ca3c5674dd90477a5b291796e953e9448815b7b40f122b3323932db73e908b2ff0ef2679655b85fc43e5cd69c0551b8ae29f851a8450e86fa42b7ec4ec9783cc91f850d15cf18d5b5421899d12699dfa7be6156adf6b1769738ac3b6a8bd6b4f7100a6ec9280462290b48472cba3e6189136d7d62afc15e92f5a9ffdea41578f7724e80eb891863a4a45cb1a37b53aeb518c6017cda9b546bc585dad01d34dd0b931d90bfecdbf5001dd276ae1afbe6d1bf519e1195f28088e25c7d37dcbfef778050154ee2cd3c5d828e9803fc4d6bc0e7fae79231141796f43b25c86e0b027cec4952844faf0b009d77428c34bc40c683c443428421bff4fb0a349293e4b8375c418ec42daa850ff11e3c5b8fab05583c9edd53dfa2a7087651bfcf675f4a2dfc422b23870fba6c694509f3d6baef5b7e7d2ee1f18fb2417494da50fb34e5ce329e340b391588004488259ea5ae6f89c07b9279d281348ff8c4ca112c608165043aa1e18f0a7b932be77668f7ebb922634f242950221845a90e1d5f690046887b717b62ea43f5d1008052917888007e68739f4ab47e2671e2003e7d90f1587d7987a6f9c064475044fafbae7965119e7131767bc59988b709052b0f62fd4ad4ff76a7b5c2e1041b789afb9c116f7033cb36f9257ced4ce4e2181f9ac48eadaa694b5a5f6e8c2e3a05a7370bfc644a65d4c49138cd8c9492b0c0a067d516c79773410faa7354bc15d24acf1a18f4e59f07730ced5bfa8b1f58715e29fdac20b341af796a5f64d08ed527ccb640084af3e397d49011448cff960dd5be91910c12dee1f6493607827a69dbcc206d4c9d9297e633b813c6ba032349e99d84948b32fec41ccf20be0d5c0be56c7bdff859c252803027f4f18db81c52b60a0f1693fbe9e23efcf0dbdddcefb8cc405ce7b2880695e905302f726d8e91e94b711e2eddefad0605a9f146620e46a20d52285161f307829c5390146f04bd3572228b33a01b9f2b3879176eed2d9c58d5c470704e8e4864a3b08fc7a8f60e1348414140549123c3133e3467df0d558bcf5a5b884b16ee71e6f693bf60425e726d4819764deff9b628a63d05b0341e7fbc22a64d82ee98db6ecbd085302a8b1d63443a2c290246938eea2cd54dae5f219eb614901043f7db806e87eaf26c102e0c3d90ef73ab192edeef6b14dd0705bff5fa8ddc577321f816450c9a07aac3b2675b81af878e640bd4968817e8f82b25d8486c671feceeaced885322550de0dfa801fcc727cceac73d296dec602ddfab1ac15ff5a75687408fe710286e88ed27f82ebc90bb9fc0fd2b0b3e992f11b1a6665e4d05497a6e539e25b3ab670ac5ec317b0e2da203124120f960c434ffa87321fff19a2d24e76ea75a5ed2e4de819f450d5d3a481897be35d492b1f0549b55128a237814a29cf3c851c0630562d111e424b65f6a6982825665d147a91ce45531aa11e49b77c3a0c579b27da9fc7ff0ddd9620cbef56028eed380e5250a1864f89bbb07376590a2e0bd9e6453ce00b6d42b7ac2e66e115bafbb5cfbb0511374aa1a9a127ff23039ed60d89195cb05eaa44695e19de40378f97d5383bb9920cac9b1ce0f181ce5ef5d49d14024aeb8c56c54db593f3ba0b86751b56dab1784d83eea7bc660a2f0c939f6bd4733b1bb86b8c7f3cc836437e5424f01cd370416255c88cb2ed46f5de8f44747e04d94f2a077be2a321d0388d1a7da44c957f45d35862de7c48f1569e8358ff313b0b42b27fd7f62a9cd09d92603cc924f740c58518fb3f4f9aefc8ee1bd83019ebd4d46429dae9474b528c2c94aecd8943ada6fe5342a98eeab23a0d459c0a47c3181b905be8973a445c77c2b386028a42131d2002b2457999278ec182482a52b72b4e9658a31e7b82274872f4c238afa2a4c66c6528389c0077878dc396e10c9c5e61c835dbd7e739c0090e5c9274bff7d7f5260fe27c53b3986552d64868bfd96a5af039c5378186d0d4ae86553101225b9c38e630d53ba30ac6b5215d5ef8e459a0b53723c3cedc8d290719f4b1ae10b7c8b9dac72472cb1b129702a0d1418e31cb103241177e11438ab9e6d061078db1abcc045f4cd51c0d1040ad3533fb7899edf6ae20afc160e8254188221c937b6166ed94f1e796f3620801e6bde8abac57516efaaa0495c4440bfcc81b05e4040e5158ea95bcbeb90dacca9b4c9b2ca7899fb40d67f09750acb8b39c7ae2ecc0daa3a78e89fac4fff9d779ee538a3a6f03da04193153e904a41e838c03cd60299d3d9a297fe1baa03dccc4ea5d6c3a9f6c395be653056623183ede22e3755a1c3a706c9966e3b3ea596246c6c3fd4f35f0f343a2480697aa3f6f0b79ae605370754ae28a850dccb359c36970cea0d8ef2fccff5d29986c6f8095fc68d055c3e8fcc517a4d6c0a46962e8b0a9d47525ea951e4b10a4ad7d269a5b22c0af7fc037a1d968448b71c5b77671e32872317606618f380b3a7a3f8c2cfb3ee7848e354a09750adee11a23703c138567fce766a74879a716cc520302532c4e60882d04a02bc3336c03868c97dcccf6a9c915859894b6b5083b8d1465625b074a92d27a89c8c9a5e4cc0d4fdfd23f8c6a6b2be8fc08c6148711db919d7bd0d20294214f4f93f826e7f06bf5ec209ba134afa25e0a8fc5067bba35f31b3e31057a2dabf0c47d43b1157d6a13339d40059df9bbfba48c61be010674183918d6433f7a7389cef21984aef684a90724791b0c4d9a4f0d428fc3a753920971adc5188885113c689388be4d315fc4c55182407cecd3446264a5499efc17e542e18526091cc9e792497f932cb8f6f664ee3bf81ae2b0c6d44d58201d0d099db14ee2506207fe0c4900dce8a01323b29877cf862e92b408cbc1b3d91430fd28470c26c70e59309c1e9f90d5ce5aba7c061db49b208440e6a02b7b1edb523d573cf6175c039b85964db9ea2e0eebd74bbd9089c9d926a5b1538c31fb998c4ef318147d4b7c4ef482bfa97c1e46c5bd7e4a41d866719a7e10ddfd0defe6f14bbfa62cc69e0f001e008e952cb00aaef3a87f3ab2526a135dad3e8b583b606c800e4ee6b63c5e0c1e616cbf834a86331259dab09a589d23c7438f4762e4b2d2045d087443cfa8a84038a9afbd80550f2fcce72a8d446a4e77101854284ba997411675440c623daa1ce27e9f04fda0eaf0fcd28c724685bf7cda67ad8ededa7fb3ae6c5d610a1e7cd488f8d06f06786d2d5dbd44a48f95b75f9d8472035f0d94b00f5f2674720eaf1719f406ae0638f80eae1ef0e81d4e1d3be02938169ee0bc01f411d3b4d3e950388b97f3c40c23902f057b880659d4c625481d5cb07928cc7e3d1ac713b608f404046e405e805b5bbc0f5f0b18fc024c36681a30376083432d50c71318755bd2521678cf60f4d04c21bf4a90c78e4772c2bf469b4e7965f3b2278e3a5f1f2729ba5d6124e69ecd94b512bfd8428463774d4e21b8e19002283ce5db0e79abce1ba8c07204e4a3c8f04092f759f89897e2bdf8622d95ea993137d0c0fbae868761edcc4d546ab7b48b32104da4a50db0c6b5bbc7107a1b616d256c30065bca850d8b608b16de93507c2ee1e82a180d38fee36606cf68b93ea0ffee6cb542ab0de5d5608363bcbc6857ec7ac09a40ed2db34b1b4752cd33afa1535e80862266afdf26a2da00096f3fc2099d2bb570e80b3e79e05f7d9970c1836d8526a18b42ee62744dc9fa6f3af91c8400f156018302f669d851cc1ff5f6adae0178a2d60882c4fe1989e2052a640df69820ef6cf9c7be0f8eef67409d9f31c8e262b4defa187394ee99095681594e95b04e823d208f85cbe3d6ca5e887a3e14a4cb7ad7ca4a70a5c972e6e0f8bf7630a76c41fca7c7bd0f57a8fe8d08016b16a06538229bb8fd7b4d33911761e2a1624454297d5cf2b8f6ab617f06c12b98f67b8a045f338a9f419b08b0045a52ff426b2c4edf32a2359397d5e1a99e53b48f84272132d93ff30785c457a850a480b6bd0d32fc3cb085746533f27d9b2c49d8689a6e624ed7b7d115f3dfbb444da13ebad3770024d1e0816d2bd0d3d0b18b76676b940bd95a8e3aec1c8f752c59b53efc317cc41394e0ebbb3126d5ecadacb4eb6e308841669485d988ec8c5a357ad8eaaff722a0e5af468b911568f0dc982f0540b34464778472998a09c12a80b4318261a445f66e0ea23a16dceac3fac37efed2919f91aae0d5f07f664085f5f635a875e115140daa1a6191c7c8b35eb88ced2cc3e717d1865831dc93b3fe796d55686cc2cd1ade82f8281269cbc0d1254146fe2e14160de452d7c155de910a1c9d96026fe0060ef3b4dba77520ab59b0422eabfc3ed1fe740647e87e6e0417321c303fb1886d664a4405d1c260ff29255b26824a51003610d68e00ea96670982aa22e00ffc45b76f39d390f2a800802c21caa1b36c52202bed826b3e23c7be8c8ff042557140fb73d82a6bedf06f54531c08a38e804e88e45cf01237a45c3f10ae991318880ea458fc2cccae5fc669b0f3c3dfed5e79c8878a14efffce582afb2c488828db70c3c2729930a11e5f93b0e4d459b7f7bb07cf16cb93830e0df89776b803973253597ea3058f2a56443bfbb15dcd50807004acd4a1579a372e459f91efde0c4d1b482bed8f29874aab0289ff84590a295851c2a18adc25e3e0743d2b6ae59f640313f4b9e59f618fc59e30f50cf8f00dc20ecbf04a0eb929c1f88cd82005e440bd43d058174c501f100c9261b294016dc51c78b14fefd421663559b772b10db32762866b9a0143eec5e055197299e22310cb45269f68c360b22b368d2733ed1a173b4f17e8fd02d7b15565462219f90a4dba08a399631fb60bb60af58415122877ed199e8511803095f79f3a8433d33b917d2e981628530ef90e96ca2e0c893a6a07776a7a163bb6e652e8c6a42cdce43cdbb5c70b813b9891e8ae315c35d2895388af0fdfb222a3c6359eaa513faa2aac7d5b29f356bcef85288d5181db0a79addd81ba8f96da9d6af59f8c5b33fa2d9f3232f72ac7084f27b09919ddab3332cecfdebd5d662deb4a03d8aa8f4a60073b453365b597516d3bdc10319516bf27d32db215aa3024fa403e1169035fc447372ec1b57ba4687c096ea7954675c95d404d840802f371f2476f02f408373ed6374087c3b047afa36945930d81da5034547c684f9f8c9a995816ad70acc8e3535e10ce19418ca874817958fe5439a81c23941b0bac81edc3c41004378ace987a3c882ab29d84854f50f7cc10e8b21ff926be2d0e1ac91922f09d97bef2da59452a62403fd08bf083e0942f5796b4aa9a3a0aa619cdb6730817dcdd5e8cd04d819655f69b1cc50d3d12e999999995f9741e95146869e9a42faa6b3724ee965c846ce912adec78f240f1d48dfd087453f4c810ffd0253425884a4e8a19f8a8038f2b0050fbd7828a5941a0ff8c5cb47242525451c78c1b3c3238c686490007ba82c16d2c4e7b86eeef9a1f3cc7ec824b0d1a2b25818c58a3be83f41df057d0ff4ea19a53473be42acf4c1db0149cb298d157b7c0456282dac3adca8d77e53de6a7bcb4ba51b9d7fa9f4b260532517fa1296b85aad56ab8db48aee249fed872d4f94565e481fc373e1421763b55aad562bba4455926535bc86892712a9e42698cd0af952c6c5904c8b9d56cb2bd25243ddf1e18668f169e88e4269d1526bd09a36611b9dbfe590643592935657b029920b3d09d28cce6975e0e54f372c10ce3aebac33e6a1d74a9da7c79f37355de8833407fd358cbcf6f4702410840b8daec651103e98670326de23730a4a62d45149b132bb1d9df3b2badb7f6e44a2bcb656081f8e4fabda6b68553bcde9bdac7b44a8ee11559de65452a4172cb33cbe1b514bac75fa841b65e9cc506af17072ec484426554a58aeb93e410821bc9913327b5914831e8439e3789f37309438a27b6064b6566be7ed9c571e04e204b1aabd7dca66261be01a4a58e6a199042a44577490e5dd892327b07cd7400c8b9d11e958dd2c17fa09bd6640e817407d66272fba8c7998a3841a4f046abe3ce88dff3e6b9cb8c3be447dbfdcdab28ef17616152c3f8c31529e71a2feda7ae20dd067dde253598e6d96cf5bce7e693d4a5f2bd37917106fb4f103597c744c76b7a7a6437f0b98b72b111f7d0742df5070f9f7ef79a45e7331361120eaefd91499de1eb505f4023aa122f1dfb349554fd50b7fe8d71f7a43aa07f7313e1b762ec22e30ea554afa66f49fd24ba93d3365962d2bb367feac140f6f920252faf285741f54617e6d9957f80566bc617c7fb8b32d7ee5c16e6caeb7023cb1506a8c6dffca50d5d210a5946e693c11be94f5651871ea34d478a263de96f3d6454a2fcd2d8f9dcd1a1fe348f1805fbe5c995f9bb6fdd02f5fbe78817fb9757fe0e49fdad64f3dbb71ab0580627fe0972f3236fbe53af0a20ec4d5ba66166bd77f718dcbd975e0253de82394fd71da59840f1b45d8b071d448a03c196ffc2ae34d1173bca91fd11f144c856e7fdb11b69b237c45df7dab15b1ba65d552146c97653f4f9cbddb3ec51827f4d9ed32468ed10a4692e82c573a4b67814882f09d9a29b7131664c53fefad834fbebdd403eb039f30a31e73845d7c1ff8e4dfadcd3d8ecd59645d2041940489d8d11f12578c20e20829da0f47645220a1354142fb0012d916249080c40db6c876a05119ca62a0313982e3e4c1326a57c8a6d09ac8a2683e1cf194f090d0c11e4fb1ef0a9196a75e136f268f866d7d60a3f74ca7de4d7fb0a3b76ba75edf6aa75e2f4fe7d9dd2abf60422fc617e1f50163eeee6e5ec1ca0111a8077befbd07018c1b729378a8ba75701f9f0d8c35efd6486e12741db0b3c4a07fcfa66f4a47fd1795603f9a7b523e8a153cfd5bbc0ebb9d4fcd476fc8fdded6cecc5770ef31f30f00706e61f3f8298f2f6bcc3d799cd1d237345ca4bc1d1ec9fa0675234386c77077bfde420bbe05c06bdcdbb91258196f2dcdc978c959c64f2edc4ee85d70669f310306ef0c1083773370dea954de6d3278274300dec1bcf4ce7ae91dff0ca7719b8d9f8a9dc6f69e4a00db7b2a1936d5c6ce6dec31ccf0ec3018e01900ae035dd85298c6430380ebf3a0f85467291de9c0874fdd2c5e66e83b3954b3ad9a93f117361bcdc9f8dd5e0bdb824be7165af0a7f1b470659c06d59c8c6301d890c0e041f80e0c170afb0ce9db866d3436796b666c9dfd19b505efb294bb70bb191ec3e5d6d997a9540b72866fee33626c1728bebbbb8ceb340d8d4be9820b00f016dc85db4947f98c198e518da785ac851900d85e73333ce53a906693e11a0f2a757db297e1dbc523e3d6e6645ca7515bfc185b7c1927aa452fd3462fb3e4655cc6498df2327208e2e43c958c6fc931c1c8b8354215591997b1642c4bc62d193faa32323e232323e358142743d99297f14c46e6c9c8b8e63297fd24a19bb64e1a75b2e8dbedd675cd25a7a57373a95a8f3e7a0244ac475e689b04a753830da7676424436626064a062ac68c4cd12926276b0213292875ec226dc75f2bdd24fcda32a3dbfbf9b219f615f57a171191471f8016db5d445c89a8544964f99cd5512d90439767ded5e85209c4215de9644a4b27d809c7e475757a5ad0474679c844ff5e805ab087634f1e5fbb9dd06b4ea36f601c2563462ae6c6e4a692474f6d59abaccf38bd7519d651d63ae969799277f1491e838467cf8640a97876ec49412f67b76c9ebd3e95939c743be9321ee3c667c3aed327d781339bc9652779624ed7e7697993f5a8f5b0b868328337c5986e6dce3a8de6acbdd24b1bc9bb9ca78e6d1df7d4afad433dedfcc84c4b1f38dbd367cf167b5c37d796b3bf9bd7c23a0f6b3e843ee3d2f69ae3b62eabb177e3c2489abdb28ddf92f835ec2a61d7bb61bd1b98979ce45956d27cdc7f6c7bcfe67a36efd9c4674d07f509afcf496a3d0a90022b4d88b34ab527c8d90e2bb71f1a1c6763390dfca97936b239f8ae3871f472fbc1696ba3d9fcd9407fda47a6415198e9964ba7cede4deaf2889746fcd3a22ce225933a37b982972af8a7d149c47220f83cd6fda1df63b9757ba4d78faed3ed95d61def7fe84f2f027fde4ede1f5a047e6c82bbbbb9f987e415c25ed9c8e91bcde496c7daadbe544f3233ceb72b79e631b6994d663b6db0e424d78176d3bc94ad5e8b9a966382d9607da059faf2e54ba963153472cfbda4f9abe6af9babb3d985ddae66a3691553bfdcb228cd5e0b8b39f5ebc23094f4d82e7db86fce1a36e98e35c3312f1bb90650fc8e09f8f2e50b13ee1bd8d95f379e7db4a21579607703e1fc9039c63527395b1ebd6e1206c6544dd5544d25af1acc46728d47bb40f249ce91f86324bbccf9aef107ecd5607276cd01a9b4deb368d8c0b8c9352f79392eec866a95086c6cee543fb38f68c8b32ce368798c7d332fd9cd39abdff74fb0d3dfd3f8f159a33df8cb972ff302750ff8e5cb972fcfcd0ea37840c910d40794f8a08682704218713f561e88e2b3d279444740530315d83c40e4b3054521b6349010ffc011200cd8e0890fedc5c4352cd73082651c3c836bc0d40f8de21a46404d417483005abdb6016660a3773927ea1dd7a0d2a4fa93b789e53911858238f54604548fb709757a1f070c30039885d481935ccc497eeec06e6daed6e99c246b6d3a8661da8dccbb6a7186553ae5914a2754c2b5e5638c2d5cbe9f8d31468731cbf30a0b35834a1a4b63e9eeee2eea1b2b7d63d438995fde58fa86faf5ae6b4b27ad601b79c09f91a8b9588ae2e3163f8629f6cae2d27271d11797e6daa378e99db4a232517d5d52dba5588e617435e54227ad74cb4adbed12ab3f2efa65593ca365bd28aabb3fce728b5df459425cfe001e0d65590362f4ccfee8f272abe918391eead2de84cd9aeb25b161107238dc5e15ba44ef72ecd0379d8def14bc3afa618ec611400d7d0324160db5f0ed43da7da08c3672a2ef881f69340e8d74d286044af4207c8794016dfca48da6699036648cb78b3c7c65fa1a6f426a0f0f63760305b8c6c62e3709708de850e341011e846035cbfcd4374dac6b1ead6b9dd2d19f3966a9d7e68624ea762bd5a8dd505f3a16372112dbf8ad90846a18f6f8415275afe16ce4b48a63246daf6d5c1bcd71ffe56273bc0d2c7b737d03c4cf239dfdf22262d0217307d498e6c5c60f352d73ebaa1702750f186f84551ae53b7c04fad804f38e878f414de2ed284a0a281ace628c357fa1681090c45fdfd44600e6966571adea586fcd127bb2343621e396f117efe596e672905e6fb7c390197e805b8a077773c617f6f2a7a530a9c925720bf64586a5bebc7609167b798729b15867bf3b3b041fbb9d4d812cfacbda28133e2c318f9befc656885392291eb083ce4fbe5cb26428c9f717167a433b0455ed244a0a1ed796c9b74f991faf5df26cb058e81da6a4d6c01955b04c842921cadaaaa9234427666666ceb6e474998590e89fc6d3a1ee95d2fde5a539723e2ca58ed41d9a6b471dc9257c80e46bfe5d99228c6fe9c3bf16f6c15ee2d9408f81c2769d648987de496a65e9bdc9e0a1d3d9f27d213ae2e8231791514983514925cbcca45aabf5c62eeb9636d24629bd8f560a19661a51b6590821845c7b4a1a548f1cb7ea1bcbe2da391addd9b081f1f06ef40ff169ae25d09c909ad5e785394873ed4127eb9de5c17a598a9e9de32cab524a8f2ff49c03e55637941335a09afbc1421bd8cec6f79c2ef472c3a4dc80faad4b00ae31bd4a1b7d13bde1edb8671d44efba28bc3c879f1ccfa6739aeb326d6ace1e69645b0e3f369e4daf9e8d2635b9a53429a5a65dce51c6dbfd50abfa8bdcc52cc777e63a9dc373e817ec2e07e8977643fc1ff831db72b04723879ff76cbad55f573a7bc749785d324a282fbeaa3b945e044222115e69dd538c1003414683136cc77134563672fab2e617970eabee4e2f662754664fb5ae5eeab0fa1e78aa1008588cb7db210ef9c8458c11c63829d163357314c42979ada7a7b29cb4595ae6f3b45ab5af9642440b63a42fce5a835ea4300b139bd745ba48f572d29d53d2984d76926b7cb9d571ab9945d1780d95934e3a9fe4d3147c3adcb28661587ee622f6895407b2ffb846e75c699a9b7ef96535e328629f083b907dc6c1d6b906ece7bb6ac2428ff4665a5e673f70e2e8b108618c50b0fcb3a5e487e506fa03aa007b8e392677488d873a73c7eeb37a1d56dfc377c673617d564fbdf359753e2b4d87e5d5a7c643a3ebd093f90aae36193016e6312698cdedc6d7f61e3b7a391ddbaa55371d56f7915a7680e8eb4b4b6ba55ffc98ab269675638c3027ae886a0d1b581f70562259524622c1c06cf10ab17ac966505e1ba5902b8c85c9604830303a6d49b262985f8eb1b5d67748b72ef45989b475414ff24cf3a791849e4400ae8179b675f1a95f9be575eb3ca32d68a287b05a3c58165d3d8107585f16dab59487ee99a50ea471503fe66c2972c651eddb519a838e4a8165ef38890e6c1fb0d2ab610e8a5dd0f700f5cf1ba2cfdb6540e83d6a3c56fc193b20cafe9e2d8c728a87e51763f4b230aaf1483adff4d9d5140fa7737af5e9357ae481291e74def9d99cb2aaf9abdaa08fb7bbba60714ac09a2ebc352deeb3cca2b62a6994452de7e8c2d72b73102950432f62d574489f5a4d73d375203bb3ad692e42d85c3efa23428d291f6c67b35aad45a12037e31776d5c51a57cf393f3a6badb5f04a1963ca879a835ac2dba21f2bbd2eed3eafcb84475d6d2d93b7c4eaedf2c7852f5fbc3cec8480f8db75785dbe87bd99c05e0dd6d1896dd4314d5a3e2d9fcd1abcbaad63886d9977d4b11ff83d1cd92fbf2a46338a39bd1d86f9d3608feb7b4ccba7c7ad56fab3359ecac3833a9d92533d64cf7b8c66ac65f4098fdba9037a085752c86c0c29b0d43b145bb57a76c5eb29b02ba82443c9c076281d1416a7ead9d78ac262e660e66b838f1a749a6b14caddb2965b164a06965d566ef6a47848ff796b220d16b6a390c56ad4d9a30ae1500c22389252a2a1a9a1f1c2b22a952bb8e87611a1943a466f4ff5fa985b971781179bae557f5fb942cb67bddd35a9452dafd5b24818e64fab96e5438858d78665d1c8216d397a6658d1e0bc5a955e6e6d296a5d56b5e8e5f5a957cbbadd4569dcf2ecf2eaecd4a5771c766d29ac5e7cd58d48add5af7a5d8af9758bc0bf3cd60c0a4b3bcb7f28e74560e4a744b07b5d3e9d2757873e6fac570eecd76a6fc76feb5bd73a56ae103206b759d9eb57be3fb408dc615da7df6b1bc786710853852cc72684d077c820933f8d859e09c035aa471d685d9d2615f9a1cf45a4ffd0677fda02a417818f751a80d9ed32874e37223ff4996fc72387b0438716eca90f7d08913ef2f2fec05bd31ca4e17ab667d33ee4c7699a6be8ae79878a3225194e1821116676c9b7677a7d49dd23f422f0e1ede6fda14f5dde22d0c6275d4b31ca73bd4ec3dad28a168451b243787facb7a6eb34dc76bc2f12ef0ffd2943126c874211f9e1e17b80a006e0d7dbfdd08fceac82c2c270b6040a9d32d56175fc984fcdf3750cdb7aaa63ce5b4f75ed1549766deb01e2d7e13d633e25bf0e352f6f4ff41a312d11db3a9882febe487f0f8d57cdeacd63ac49c75c46b7960ad6cd914ac5606b3c50c6ac9f7f78b6cfd36fd2e1b3f979cf46e2bc1dced8e1f6b408c563855a58fe1adbcc9b21fab59db84674de6c735cddba19cf9b3517a1e0d8f524630486710c4f2c5fe6582a4d1aaa45c6596336743a1d597a3a1dd59a552734345a3219b0b09dd5faaa2858f6ec3ddb6d512e0316258e2d4c9b981942860c19be7eec3a6884209fba48e24a144faca755cde9d6fe4ad0b148b7ce8544b8c1941c6e422f61aefb2209487299571baa5dee9e5a547a0c94783896df9a459f37c557a7b9e8d0239016ec3302d23fba1a9ad38dd7baab8f37d6396b626c08022927a8b951e2db08aa623be11a918bef4e158993f8432bf13136e6c403b1f33fad0765243df0c6479e4df40144b1535ad15ede0d69d437d487b82ce142096791650a22fc1d1fe13e0271da49aba2d76a6d971e4e965def6278e78277317cacf111e76302a6f8a85deb4646ecd788eb6285a33f8e11883e5dc0bc4d8c641e04f320287cb3ec0e7976acfaa07e5eac5a61606fa7877c797b8816c1b3893e274e012ccd47b7e1e4638e5682e4bb2cbb4214dff947205c61ca2a674a16c192bee93a09117d53b97cfce2bb2cf24e9dbf23be14c1bb31ffc80094b0fcb41d306681ddd0a303fc540fe8d429e7f0f39e8df5e2d6e510270f6c1af434d2ed073e9d597339fcbc3ab7947c9b54c1a9b90729ece853ca22f0630a30fed9b996b90d82ed5e91aa06d6068853d32ae815c29aa21ae883005aec8f6b4373d04d4358e87d83c16bba35776077ce1b9dad6da30f422b9e7cb9334ca619f674727b5f73333144a03cc665646464c89021c385de64f299ad8b3fe328940c136a8b11e3a84de86d8c189f89711d28b3c5e64c7edaec6b6e46fc8e864c4b1860af26c6c75df1317a8fa78a0edd06888301208ea870faee6db18e8187935d56c2aae8288d54a9a0d987858ff7b10a888f9f3961fdb508d1816f0392cf2b7838ab167c9c45eaa3e0b112c681793cc147e712bc1bd2a30fe3c02ebf1ad3651c009ee28d3b4459e9ab8f9bfe6a3f479102f66afcd17808a5b4621882ec7c6ade3a8c4b0f027164b8742110e7edc0780c970ed437302e3dc6b6b221c3b4cdb8c9636262502894ef788f72a18fb175fe31fcb475f54f3eb375fc336eb74e480cb76636197f9a157abb01c997b9f009ae61f2d3d6359637b90e8cd96273f6bee6ecd56919dbdbb15ef2d738a4cc3accad34dedee94cdab4ad43bd3f76d5534b20b05713a4566b51287fafe39e049a73769415de3b95005caac02008597ad004086014edb4e7401ca10e1c018a2caa18b184125eb0d3ee5c4d3341cac69ca9a0d8e75837cce08b3188216c62a5c84912488e1c65a1326509115cb6185979e22409922c8e88a83059d2858b156f4583bbeb1b5979e22422c9e288880a5cd2858b1546519ef4105ab2888268c84b978745f5c4f2553d813658c2082324ad9ecd738ce7834d250907d8f4e773e36f4c05c54ec7981bc298e2218336cce7567bc29f30e218c235e6543db130559c2089b75f7dda308471d4700d681fc7d6308e1ab84687aaff1836a9ebe1edf5296d3b3407bb06c6f15e8dcba1a5dd78bbdaf50760898dfe44f87d523dec53b77fa9c01ee3b01e4ef5e79771487fa8ad4215df788da7e2b877a39f0d7be737f0318ee6faa6e34fbf2ffd710dea5c4347cf6a88150d1a1cb75ac9a39a2c3b9d6868dc6b6a7080bd392dbe18e38c352671892be7782f8ad98d04f66aba6af4d1bd183d01fe5df152c4b7f6c3a3b90e7ed2d37e78aaebe0bf5ca7a193beb1cef5cd29c65f6518933fbf00c5f2ac3764f3706aa5c11ec08914ffea141f291688538fb42a7aad16552996228853ab51c5528fa2d728760a4704a3d76a2d0ae5ce71ab15e7c42410c706a88a5e95402dd1eb96e8b00846471d25c1f29c043a81388cea121d2681385c0455d1ab12bba46e19d2d19f6345ada56ffaa37751e358446dc4c5ca4730a210c330e2bb3e02c38aef2d1fbb4441f45d7b39f2d1ea97bea35f46242c8c631e9d37a2d89b9c424552692e66692c6d853dfeb415cfa68d78fbd9da4a7346b4ad741185b1dcaf8efa84263649c93065c2e466391129a5cb48192aed2c738bc0afaed35b173981384d459d420b14129c7cec217ca4599a8b1abc140b018840b17c74194c626e5b793671c84ad3963d9b1943567a578fc8279b4ca23929abac9249cca25531c6245a153d72918b9c951863f42755ca472a1f9d93409c88c409c48159c0285a159d098a888f71082f282e960b2756aa1545593e72d15bd9daa8ad889e6d9da58f9a8b1049ab3a8b5645a7322465c993249c098a080b87d0f2ed0505a3c31bbb28c608dbc9291f637c37ea7b471d2dcbf21dd2ad2bf4fc1d14e4b9b72af4f052806bd098f7c56ae21957d0a8e1381a3466f3518ea7313bd1d4d0b091936323478ed99da469688a48203967cc4e994663b5aaa139d9b0218566333c32990b58f9638cb05d73692e9ad55d9a6b7fffbcbd34d7f53617194c6c577ba64b49855f97ec2dcbe22e976318b317e612c5bef72e759f2c760eb05743dda6188079e611b85c738c31ecc23c73202ed75c28c58092678e038c6b9e6240c9330702e39abf177aa8ede02f37956200c9330762720d0892670e84a9244b37c538986e4a9248971b29992eace418c92f17da79da0f24a51b040548c949de8067c49226e9bea6c172cd332d03e2cd3be940b1dba1b9e740d1da7ab85573cf6b4b2add5c8402a47a57ac6e1d05aa6275d25c8c31d6682533338cd397b783891e63ecd8b18da090c39d9333856433179aa727a9038d0f8d90645662ce9a1a771d381f2e0ac9662bd89c6c5d580e49cbb0ab557d3beaf31699dff39c1d687ef7408564b710446e04f3624ece0981aa76e729cd71ed766327f6fd3fc83c44801c58a672594a732614d88ea57cc79864eef57945884d037c36cfe60d400a22fc3f300b475e7a10be4343f5f7b67ae9111dfca91edfc39107aa4220a92d07e87b457d0262ed2a454f5b8a5e8f71ea3137080a8de1311e3483c16c296a32b98c0331b98c5397b94150e80502e3a81b14c3613c6806e3cc870c4551193486d34b46a373f35183146bc3db92a22eb433b3a5e8250264c6631069c0dbf9297903de8e8cc7b841414f68670758a9bf1dd47d3b311ccedcd48f189e2add06bc1dde99f1140ebc33e3bc3373573b32423b257fcdfd8037d6d037959a766ae89bfad06d80ee0336b1b72f23cc245bc74af8518b52f7a9378bdb12eaab91313ad6ddb7ebad5b75abd748248be29e0455a4db699e79cc666acd310dbbbaafcbaa4daf0e94f2631bbdc70ed47a650ffe534b1abad8eef4d1461aba58769d3e62c1a3a149fdc035dae376718d769411023530300c352714f3ed1ef702db57078421861862e048ea843ed290a1656049ea8462e0349ec88cca2c43b8951e13db570601d0b0190053ce33199890a25101a00595ca0557a954db0c954a860a156346a56a620bc78f31ca88a37144c95b68a68a82854f37aec90b494c8e9571c87fde44ec4209fce7278bc92b440a734bec1efa1907f36b028e10b600e34c9f976fd8bbb7c5f7ed1a9ab08ce341a38b05d873ac998b8c119eb032587a4a73dcc34fa2ce57b4bbbb6f0f907cc83dcf6146fdcd1bdb653fa87adf545a8a14db7114b62b884ad2423c1c16e2a9d895a084273c610a5388b2e224cf86ad7d37780630cf07cffeee0e9ebddb9e71c0bc847d4c3484b5bf1a1fa727d8e7f4dde09ecdc361176678ceeffd8c12214c89e1d9b0c75461bb181e7c0d638c8e9e61dbc0ee83fd07109c3c07a9918175e13d08c47126aea0e2045700a1e58b1df6defa87281818bb8fe6deeba8b6b0a729a72eac9ba0609f5779cecfddebd2bd29d827b043e0e1d4a76a97374ee1be2276c263f9eec524c176f5ebbb5161647c63d1a1b8e8d98485c7b3692560f1dd41b0a10afbde632b3e30c45bfee1988ef08084955c098214a3243a030215df71122044f96628a46fbad2bb62a4e5db815c11c291ef9a85ef5e16a526d65710c7e67811a4c2446fcbe39824d81f46b0df6bce798becc24a51152060520508963c7b169f5f10ecd574f0e8290c2fb0a59b9a5ebad64b8e83f5d235624473eb38c090ae4395a6f90aaa34d7dc86bee9c9fc72cdeb90cf1edfe95bcff4cb2fc7665f28ede775350b92dce438941c5e23d04b6eba46a01889912102fb9abbdc74991c8776ef8b83c9dbfb1a816e4a5ddea61b04e5ea1b044d759a4ca67bc11be34048de315ef2989bba4cd331b8913c662bb9a92174230e7f3ca326ac1c5e1d931b3102af1093778f68cb0eef080a7d4df76d6914c790097402a560130e01e79cf3baafb946d29ce6d956da529897fced903648721cba9dd46e24c6a1bf9d9ea26d1da53929cdd1f7efed5492e36072375d12e93acf982d35a7974e6eba41253f79500ce6abe827d28db9316ee26ba4745333c681408fb9a9e9262f797b8cc94b0e24c6491bf498ad9db4ad4c393728084a03de0e12235080c47869c68dc45c3e0255d44b1ec34f97a34015f5287ef218ef384a13625c5672040a33b7747908aa2895b9ed04aaa81b31b991d26522ef78a80931978da08ad29c151bfd203592e6a893b6ae152a699c47c55164f2d45f07a3e0a32a4c6816850a2db40a2bdfd54c79fa1d249ad42b363b7894440b932d48ba4b9423433049dfa4f8a839ead4ab172c34162fdf3517617cd75cc0f8aee6aff01d44f2d46720c23a7538049d40257447fc0995b48a3aa5d49b7a3bc148dbdb814afac622a23ac704da1d45df644eab536f2ba48d77da8ae72d5045bd359e1f0f522dcd51bf91847d4ff252c75a9e7adfd404d25ebaa9497220252791bc7481984c770555acedc06ec773c34a5bea72d3752f2fdd2028d7055272d30d7a410faa48294b731845df748de5a953cb824ae01226d46112d049e34491421d4ee91bfad4211548d437458dc33bd42ded6a2c3289ebbaae1e9857cf1c7bd8cc9e765da9f1f464fe7e6e5de635cb5cf339273631ec769957efb2b75cdb7a7e82befafb8c479c3fd0aa1a76bb218fe2cf7c504ff3d3aaec50c5cdc4a95378441b004c8c705605783835580f4786caec69652327c6082da4d002091158384204494a5083226c9162092d17135e78ed92440a09305b0a83060d9d2123c18327654778045389a9e8fd587d365d359e212b0326b480354a1624bd02db92194d2937a081155d5890840a2e44c0326484225cb10112531031f18212133580410eb164890d86380211484084f7c587151461480840107951c21639aa1598c062664e481a0c2173828923488d09d70f55ae1d500182c833c8d981fd2113c177ce0eae900a42b085102c400108888ae88007bc6c39c1921bd8e0053440010f6860844d16ae585902f6ef8a9522501b6cf16d79fd89478e94e081a8f347ad478c6875fc28f8dd0f3bc24c8317a6c8b213bd1b30cabe797d43ca62239d3246a24ae50dd2899452ca558c11461821841042b9411f51588e34c618e323f2e1c307f4e1c3c70f207d6379ce3f95b455ead46083456dc49793a3b9b6913dd1d5e58f87f6c97823d12aca7bf739e74f080cba0bb0594a1125acdfdd92e4ef867cb1f931b324b57ca1c83c832c4868232787e9df952a5b261845931e31c2d24246ce0e888034cb12bcd00162bd1b2baa3cc740047b0d8ac651342e84022bd4e08a111578f0e50920bc280a628a2278c0050ae60c8a1040ad021111306707308011c4142054590108a26084072b28c2962eaa1802141ecc2089a44e74cde774dcaaca15f5df952a4258a2e31ee8e30518342abe17a2aca2b8bb0041800579373a08f420417c04f115c4d1fc91fc51b7a8755f9554def89a90fc052448db9056b56746b0d0b9873fbc5973a8cc36b1ab261c0a052dac2d395083a269ae0a2411e5a89f54a852f41007e54f78a0668a1b00c1355334111341d44c11af545182f4ef4a1526553ef0ddcaa84b74b7cfe6bd9b39638c312a018b2f2cf1c2121542086137e423d80ec489d05647a17ae7419c3725a9468d1adc8c45014e4c7064850455bc0021c4c4045592108526d0c005514ca008242680f283228880821d2d8ea67084267ae0c5162c9064e1094ce072041f5061e7496185284d0851c40a64f0c3ce5352050a9c34a7e52d298a9e7b4cf3fabcf9aff0adedb8527c79ac7d780cfef058ccdef6aef40088c76626b76ebef4018a2db2fcf328df0dccdf9d2f3df66445e2678e6d5bfc4fe933c7668685c71e3361df1529b0c08657bcae4b5ed7bcae8bafebbaae3a83d40925f198bfed5d91228cbf36a1ef1ec93bcb9b44ea213def2c2f691d75cd4924cd061dac94b1a6c372eb06ed76cf2db7341eec09610930b0afd88c175d7aec919de53d96438f9a0f211dfc7b343a6d019643f8fc6aef60065a3e8fefbd87f144028f0f5982b8c10da06072831d54a5c2151848e1c3151e28c150173bcf1f8fe028c2e8532808de20283870007a5012de81d7480fd07be02e6af083233bd73d025dbad00e756b7be189659415db59b97150c56e5385edbc8ba08ad9a592ceb1b19ac962bb9609c376abe7c6e2d9990a2644cfcf9e03c933511f75c327300c63be9d94c2dddd5b47f3b14a3927a5d5b22ede302ccb348dc45b29898c376b3798cc741125c1638a394da122e53433c333b29f6ff70019999999878a81c4cef75d1ec0b0ba7543ea86c5a7d55aaf85ce1bec79cfa68379e8437ea06cda74f6969a2d7b76774ba7321a61afa66218a682c2529fee987cb0d66ad9886158ac447ee837f7eddccae88d37ae621058a43506e13b9933ea5a7e51778dc70c3d561fa55b1a8fac959f7f66adf5587dd578668c31de0cd1b1a629a8d46df6843dcb189a1101000000f313002020100a07c4218150402899ac99ee0314000d8ca844805617c95110a41442c620620c008001000010082401434069a07181ddaa605845e6819cea16a03192feedd8da33a2f85ec096ff4eb857c6335b853511c8881d44a9f6851cd81795e48cb89f421c878c4cafe034aaeef8f7de8c04e14b8a67e566390bd17bbd82d1dbf2aa7c8593c280c3e9a25e7539973103fd8e73b4259d19ac375be65b643b624a4dcdf3958a3291a2890e98f3184e864c76aedc107d9498f117f87c694b97527417f443403909acafebb6bf9870f95641fba05fa0aade626eddb4121ad3052bde5b6987bc7338f5364bac6674c1c3ef0cc05fcbba71e391ed99ef642d013f486bb04b732b1e1524b76efdb57f6699f22499076a13117db52c0da8e996962ef3eedd1043220579ff3249926c05d602eb836a389f0c56ced3fdfa25860f1423d1399d8f2777551ebd5c741e975bf080335b7661d8d34dba54b38e1716afbac2043c5d204c350093a1e9a33ab1b508bc36398e6688329d1a2d0834625b6ba9022295a5751b4ca0533bcc82600ae73989cefeb9a9c0c1a2fdb840853a45d385bacf9b9b03d4b74caac1b4a24a5a3ce71d338a11824fd9718c0a947ad323f5c6aa468683a2cf561da32adda36ba77bfccf4a7b9e83e3759c95eff81c8a79f50afdca2e3ffa9d9593cae85b4b467b5bd3d9ab6ebb393eb515aeb62a9fb0c0a9e85f0c77e8aabe740db5eba83c6fb28119d7a2153870565baa88207a7c40d1879bae6115e73053b9da083ee9b9fbb64d63523c0f816858e9f0edc9fcd16c7983b79b7219495eedc709404c0bb935026254a8c97e87612eb3af8e8e38b0e28171c65aefcd02d609bad27c9ef07ceacb715d078d1f6a549cd34c8fb7cfe2c8f886effab97f3115a4efa7301775e80b4911b95092b065e06b4f83be008e85bd0c9ba0fa4203d8c8c4f658f54b4f9443f2ce731bb8ed98a1326366067d61330dfea54719617f59eccf17be275207e0d50bfeb8967cdb0113375b10a282bd48c65ee252e8cf9710ec64b4f37ed96191598d513b06bd67feb991d7526ac46bd27891344d78b6fa162466e2c2da7f607bf8aca9d27bc7e1f9b38b751858928e56f323f38cdc5cd64ac9838d6619606f03557e9e25e7818387e422188fdd427f1710cf0e4f481c6b6a65efc94045b43f97e4e06c90c3312fd3f81e1afc5db3c42c360f8ea029705482bd4c05358b8511dff7cbae267dfc02c35fdb2b2e00aaa711a6940e83bfdf4f014d8cb5f9d2b76eb2f87f23ed98726ac126976853135cfaa52a9fa67562c7acb61b08821c0ec668ed49002d7e1bd1d941ad07fcd0f32485647d15bfde6b8422d7880c562691123ed1a711ccc571b13e3837cfbd61ef4c17d68188a599e0c474faea0c8cff9c4440538a0653b36e4fc3905130303e0290342318f11e44d39112efad0d936dc29da78c305e16403cf11d34ab9e182f101737b2c336abe1a25214b25bbf886cb8813e1f96066f341dd59e58cf5b4359729d49ff18acaf32ef14b1ff5b3b45150c9532a2e82a61c0aedaacd78a4c3ba9c393658aea6043af0350f4db50f560acc0e37b7cee01ae7a556965b72ea4cab58f0b003ff8810acef7f8403a0e3d0ac46e6a2fc376e523b684e63cc9020f59654562dc46144498d1297d974e6ae1336bcbdf7f92a4b31ee76e3db836e9212ba531df1af2efbb441872e7a25e0c486ad7ff0ef5a06ea0c9e35c19c1a88016c15a0c4943ba0fa06a65eecc179de5418e90e49ad5d80ca0a04929e460eb7a4454b2b75cc1cc6a21f4ba59afe5fc862645e8708dcde1f663901f0239527775be0f995754234852caa94b4504329cf932c67ae1bba032e0973782bac183a0dea6524ce31b6ed4819c6854bcefdb691e0d585bef9da158abb568d0ef0773f9b63d1c8267636fa018105fe51927b2c0b9defe48b2c20e94486b61bce54606924c4a2ab50fbd4f24f4d4dbed9c89c0319f857fb360af91379962c3fdb9e480f499cf031a5ee73a367b0362249bfb9869c496f2ef7d1fd84186bcf385c9ee1bbef43cc6f53843cca0023488ad320725b6110f5f07ed4e373a2a67c34a6b464dd80d06ae6487e040a3ef1950b77926386c1438239aa2154d9206056fe19828f5d3d4ba6ec8e2a838cc172587282f86b1ea407e8392c8cf952087c4df00d3bba500837273b7947d5e5db1f5feb0a738378de4e02a85a1e929d9d17d8b9f24a90c6b90d378ce0a7b2ad5479d9725f2ad76f26d059486c7f6414e7647b2f9cf4ab36f532b6efd69975bf6a203ee0fa388c2ec5b817838b5fc87e5b17cbfb93f41cf338876a9d3e9b4d61ed736aa41a7d1752886b11efb4e816dce009dae67c89cca46127171d8890586b8092873f2a49a280ba480e429633bb68041f3d7ed105e05287df723b7d03e14682bde148273e15e920d71a4c36c37db19094eea3501e8c29dcca9b6c256b0578a9a40bd3a9522330d6e02dce6d68a4ca152281831b140c9a0b2902d80318a52933cf925402a1251e56cb27e00458190ed324d01ec1868f89f8cae4ba9c59ec1b550b45bdb84df031ee2e65d1048c498401bf35e2f32fd0ae489e145ae1d8259400bc293df405e30bcfd713e447f4057c31c95e03c267d1274fd158e19f36a6d08aeb4ed6256aaf08a62c447489b9f4430705f3fb042254b219333338ee540087fc67d463dd0c7428c1c49b66285c2e815746040dac727eb246d978a0382bc1f7595cb015cb889a4c72bd94694ba86d87707b22c63018040c6c6b9a2912a4407e410ac263d2559b3fb375cddff5aa5ff805096ee46af0da1f9332921468a78543935bb2d9272b7fe0afc345de616f6a889d2a34d1c212df0c83e38df4f545990add338f876d9f7138dcc5372d9b7d12d58de0fc83c204928f1d0fbfdce7a694a573a0b369dd474dd2c9575e449b0768fa116551139333bd4e70c5c5af481884d69942a0a7765786fb5b20f4ab67da89576c2a0dae6f15ec976661754f00c8f007b59b533b5393f83b6ed68119f73ef88a38ff955b8bec61b898da2bfff5785d3b22eae4bb9dd77694be9d5cd8dd822675ef0485d53e356874451bbc687cfb41a19727445bd6a34d79f3c62490b399aa942ee176d400969e006b5f40b043d35157dbd3f015c37878b51bc067a0b019642f5460d4137c180afd7f11520363cd8864a338456be197881fdc05fdb91e7bd10aa40bcbb940734f974a482030c33a27b614811a0b0ed99ec3e9305d834f2bf3fdf3308d0f435b4c958ab67cd144c6e63f7cfed7e5bdb531268376bd72f24f932f86df28aecb0e11bc49a84e17702ae65fe89964edc4f9ffca3f56680ddf07c7bee34b36198c75cc91ae0602b8bb3f66ae68d3a6e248f5eafaff4becd12dc26e683426fb52008df86bd395e89aa673b27d2e08c7df8dd068a9126051dffe19eef7c9f135329a012fc69d13cdf57b04b3c1b0b44173b01f78f80ca4b8b502401e3be6dca0eb19b1428b22204feaae01efd2326d6c66c1ff3ff1e2c550eb81a17cb9f57388a819912cc56f592dc12c16d493286fe48006e7085a58a0256a517a9456a7402dd5eac6ee88cf94bc352f5830ae7f9e2ec54ae76587a47aa0c4683f74d51dd2114c484ea3bc349e1cab3eb10f237208a527912e90fa46696d32b6f7c99ed8fe83a71ce2559bf7e497cd21c74bd0a69cad30a00c453e7da529857f734cbe95f8807247383d8f79de41ca22b90872a3a138a6cd8d5d9d5351e47b6ecf114553757e798e9caba95a676a1c3f0e17d63ebeddf0616bdaf8b59cff7be3d30fd6c5a69e4d296de302f6e320717168d49ce7c24d3e0517d62856f6be0c6f03d945685604d97c1efc24ced30188f9c1c6a1ff5cb5372804a9758681c248080107cf02850c1406baa10df50baa401fd4317c0ddc012fc6d407cc639e003e2c49bcc98a79cf21e8a16ac3ba75352c79e246a0f231991c7fce15d516b6f0190e1021a47be18b9597ec1240643a909191d35bc29251bcb3412004bdb48f64464a1edd90bda20d4f8e49d6ded39f1002ff7d19557b1a985c0b255c5409101ec06b5eb171ded7b7eb32c445fcd5033bf9cd671f062eb77634ff2f273f71e9dd1b0eaa00fb15ce0c4e1a50c9216d510acde21f998fc5320047195f973d3fefcbb938e37b4ec137b346b9a17262965b4357fba9796c1ae18941f04baf7309d22fa408f7eaec37c0de569c093ae120d0da707265dc318efb2a21e773e88c4a0640932ea12f1210182cc8e1f892a5800781af1ccc47d025d8fef0c79683dfc517a42bd4dc5158c017e696b41cfea6a8cfb22807f8402eb4d2746a26fad9bcab37c4d22bacb94a55eab4f73e9dfe3a3d714acbc633ff7deb794b8ab087cda76bcd1994e72370d28b47e6fab8b1c09298f2aece6320895c2be8df0846fd5869812ba80a1fb5fa57b218561ac2d99024e5001623a2197a9245bfe0ab1d9225cec7f5a3f3fd99dcc828feda8ccc7d4cfbddd328983e85aeb9e2bb50049fbedd6748776fef3f97afe4cf567db6f495b1c2af5f32b551148dc1b8375a09487e363e955666aee3a24ee7c6fa4a8e79744a5bf5270c1ffb93dd8321c5effc1b1dd42830932293df7a62b78dde1323e33c2005ba4317a745c46ec8ed2b16329fda6fad6a9282fd05762bfba899b4bdf20d9e7eefd52eccecf338b04d0105e70c817f2b0bc19780176507b380ad50c957e40144469a9c3c677eb3299a47b32c15a5a7505c2327dff359de8120ac8a839ef503a2fa8d3aa2376335e9c864446bb0206354866294d8648d262b65d1e2a0349f0c5dbb94827ae55c1e4170174a3d68300ad070d11bdd6b97b2d68bacc92ac3acd4bff68aa579b633202f535a40b3e47015fa9cdd89fb073daa558045d6c863140184992abd8ee0075b8bd59c256b4fe987a74e8566d4bbc287a5fade9f016ae8e749ecc52ce328a5209b3985a31bbe7a5ad90dee945890a19197928e73f22c661416d6d7504ee452d834efd58392566e49afc654a4c9d90d5864e8d6b3ccaea8316b92779a8d9b2dd0a490347914a695e1c2ae6bca1b3cc040f136ab88435b9eb5c655d49bf5aee5e522e8adb078b5b73611d0904d5318845d5e7ca68eb1d041faf5cf32995f85c34b7afec63cd0f6e9667ff57c266df458edb797a65925f39ba04c90399e3cd7882c258e02e6e3cefe26660df0e871d83809f58f31e7316846a6ea290a26729a359bbc8471b8a28eb618a5e78c23fd5343e6ccb12fb2ed9f12edd37f2b3a41f8942e68db6d266a2bc47be0972fdad3025d688c9503fd731c238c301a4d568ec3564504a08bf3eba6ba144ec1832c906f05f1ecf3c50e95676edf58292048ac6b999dab5f57ca9485203c099cb3e306cd76e6e36ee68f269a0679f069f6f2b11e324e95baa97fb27d4219876ce4f91e8c78349ff10347b4df906fc54e8915385a83b94266464a49d355f49359f4236fbb839d7733243816e0d520c3ce98f6f869e2c48a070df2a9fd0c2bc1ee9e55f714629f841b2a5bd8f9154f1d0edf37ca240e3206bfcf13bfb21b0bdf421709379424ce28248a99440ab5113d07bc5d68f130c0bae1c28702b6b8cfb8a1db1be63b5060c915a00415370100f27853fe3b40759a2e3815bb1555c4f16f797f601954cdc9b5a23a6249e09436b8015278ea18844b3180356e3965364ac78c02ff1aef5a934225549bf9e480336018c65d2ebf11eba1c272e44d6c292d293f54c21ac26f4ac0694445bcea8dc82b66971bbdfb876fd17818c16aeb9108900661d92db56b1261b714f4e87135052dbe634500a9b081dea546f4b87459ee3192aae9d883358732c7bd1d7dce6a30ff75760a032f1ce19381833321fabd03b790150af646a63b58998bc977382ee785fcc37f54724ef35464725686e28fd6292ae03c16878d6dbe59970709893a87037a629e8d48d87521d2cdd05427568668b47963d0c81b61b16134ca97cd33c1af3094289f27ca165328cc52bd1b62f51b79489321251b749c80ae25f9ef2a37122030e80e615c5be49aef16d634148c70cd21b0af801999b5f730adf45de4d99e74790f780d4d573547a341573e1ecdf5034fa1bf42433dc579a1a2f4f96f9f9f2bcc85dd0f9e2bf8928ea1fad4cb28c2548ba8d6bc933673c8760c671528a0b4fc8631e316226a35884f90981739c9c3ad155665975e60f5bce89ba7f99a925fe174175969ab9ab405787e7a8c1a3a3ae4f8138ded8b59733f5f24c5097d5f65a0c583655e0053835d74e3f6d11bc9f5b076a1c917c8932617a82975776b00f12653b266e09ea4e33d1c3bc8fca9d98197a39d8f76a539d1a6690ec2a96332648ccaa4e087e8f83d398516bf1632c4a95e9f88a883d26a0146e87dbdb73986cc270b7cc095ab6f3a5970c1b1c9a768425d256bd986fdace1d1468d04bfa1f76584e8add83aae5706419c8d972bea479b5c048defeedb8beef8c4c509d5dd19d69c58a7a4feaaa367d81213faf4c6dd51ab56e3defa2b8a7b8c6653a1758d2eb75855f9449677e2dbf792146e28529ce71d971f86f182dc55aa8f3f0be101fb096e395f131e8c3433e39fb2afa0dadb76ac00ab69b52ca8f48dbe266f42ab810f0c912522606e950dcce720bd4474fb4a86fc67a51718b71b8bd013a3de30fcab54343dcda2c3ff654ed91b1d71786cdd134ea462847d1973e38cf1011525615f0e1188f6a29787ec72e4c53aa2bd4525ba65157d5b7ce502f31506bf87eebd76d1e0daeb18601c6fdf07503a89429e20392421fbe41b5ff4d5c0219297f19efc02735db80a33bb40acc809fc5a7e2c111c5c4f6f87ba9c9acdb37e19e9aeb4774b10e2a868e42f698904820e04b3faadf60d50475afa953074ddac83158012cdbc32d619e43abbd65bdcdb855817e0f6666847850eff53c1cf3002a1888a47dedfec62ae8449fe427fb82cf71ecb4c253eb7efe640c6f550728fc08dfe43cdeea2822d5443818f8052a928f1e9b32c89416305d46c555fa0cf9314934810992d107b92a3e838323fba778cc35c258c8b725643ace13684fd600d97815ac0528dadc2227e028c5d3044ee21867963a01d54a2b0be3bb79588c47f73a02a3036f20490cf69ee0dc070c9e48739b6466a29c7912819a3d525845755d11f452239eb286ca2dbbe34a60941f612161b9f4c14d4b1b8e999bf3be8246dd67b63bbd8236e42444bd0a755fb534eafe3bf294334591ddbc05f2a30bca7f176ee28710b4b50161837d8fb8fef56fc98ce0f40b447e3abf6a412b7b06e19f518472ab680bac55235048150dbd5b9a1d2f4285670fafd4b1cb10358d8c2cf7543e47c824bc38bce8ecf75e3f34ee71a7e98611cd857afd84e1e5fd7d50ab93e58e845dd6952c45ec22f08a81b32d983b0f77810cc97508b0f3d71e8b6516dab849050561f8bb17f8b0b38754b87f88731f9ec6cc7571cf0a8a226da242112dd6ecc3b73f90417274d3bce7733ee5c75d14f417823860ba541b73a2c9312d77c6bb8fa9c62d9f95ceb632b80fae69554d013d92c87b77415ec017418f96be4ce2630316c98d785682f110189cd8043212ebccde76f8ae15f2ec4fe50010a122204bbe5592b0173ce33d148374f652ef1685cb9169e38a8428acf1bec29a413a022dcadd3143506482ec711596891c3e121c2189101725e24b678c7c5ef590639b9728cc842c3313ca2059b281025b91e35be373ba5671d756e41ab6c1097edefd1c74d114cd0219642618ebfecfacedec080f24ad006a252a22c7e874a714cbfec831486026654bc2d2a90576bfb892b445e591ec2e012d9d2e607a56728c70b0039521540d97495f78b43452cf9ebb5c56116490354f2ed4ca6ccb91b353d6c7001c728c6d3cce1ebfac2b9fad34f159422bbe61ac502c5cc35d17dea923be059f4154ade5f6d232651c0fcbb875a8145aa3c9e4c7b916e93b91c8b535ae22fbe338ff2e79691e497e00152c62ab018ab1193b257ba55a344d7526cdc7e6a1ad15ecd44f534f18bc6e0b404a5f573b78458b7a3ad5a3bb8c043c4a40d4eb16ccf0fe6838f4849eedff30d36c85d3c3813c0edd3cbe780483f53bdd8c18ddfc76729aeb95a5f803b670dfdb4590d2b448197c78ba484e0983791b622eb5b43d439c13d0f9ef19972c684240f08b78c8c4969ec0f2b79eed5912d3272051090e3801b68ad3598e185a9fa077dfcb5f26a17809ef31708c23d40bdf1f8ffd6f8bd24c8b2d2fd420678b53c82c91513df4bbfe241fdccafee49c18b2fc84fd0716c4fe63e54a12dee29fe063cf6303bc3be6f4e057f0b577c1ba1e547a32a39390a43d3e05c9c63d3b68c983f145a0974c41f6a0bffcbd7fb2e44863a152c77c780624042d3fc1d0a336bf764c203e841ff442e52de2b70b9b16fd77f73719c8fd5884ba46912eefbaa113edfe61c41ca63b47e9fbe2249c689dd10a9f62fedf7d92692dcd8f738e498e001aa96a953d5baf3e6d1a8a5ec097ec3b299a2b7be4d3f3d478751fc106ea7c8db9490b76bb41625204846d88fc3edafe10b1c00b356c81c206a91a7344bf917f0e782f233afa808a3d2eb87660321b663efe500ae365fa0623c793ea2a0ea458405ceb58eb30334fcab5dee4701373295e54335c3b5611e3598b6492d0af2f362c37ddca4214fee8c71f6081e5538b7cdaffd3131e30a69a1937491584c95924289af962128447f1c7cb4540ef4df062c2f145209f70e42eed257e79eb23d481629fc2c75d2440072628bcc471e3bbf2f4c3e26d2eec492db6000c26ffe29d22c60ef8022a4c97254047738e850780f7c2d2059fe61195f4bf64b4a8325d4f87a9e9ba1d5731a2ed2d7e5fa67e93fa30342f063685e582c6f3ca04b0679db90b392b5491a98483de1a303458ece0a99f437ecf9f8de3bb9b52599e41b77e7612814ad918031ec417fe79007f9fd0c3a9fb32bc1a9fc0de61d50f89eb84b8393ee0b5319713b4961238fdc771b197c0eb0ddf71420375451f1a33a3164a846c869d3a91ff5b3f35a44f2428b6306e430de39896193f1b5ed77cf3d35a7d7bafac435d91f4400c6b9e9dae36424cb31a987391da5bc032986f14b241145db44adfe12f23ad4ddd58b7a7e4f5ee6135b66eb87d15b584fe560b4cb3e14ba756cf3c7e8482bb95bb6a199905211f153f9ec4778030d1cb5d98443a84e32455a7e6a9ec8b96c5c41120ec85434ec43237bab5e396565659799ab9d2c9d75d2506c5c42264c244258f63e663cc51418d1decfe7673c51957aa4dcb5062f0bbc9785109bb6e9689d6f70f6efe43d22b5da8a552b000043d7be2266cfd7b9d87b4adaeae6e914ec24d72b8606e1c0da2093b8bc691d4a199a1655108a35c74107ba5ae8eb635da1bbac7c7fbc73ce1dfe6b4224327e6e9d1babcd5645f93eaebe2409bf1cc24c9d93142443a9238672c7fdd983e0b99478b8309b1486834400c627ac8ab1b9e798264bbab6d35908dbc94ce3e9050e54d1fd34be9df3b90af803b8b63fc8481df7e52ecae23e57ba99e15e16297a76a53d16db29c14c828be8efad653486576b25d03a225d51944689514eb89e08ce850d1247e2a6341095608818eb07c85e854d67df01f8a3abb85189ca1a6c03d631339dadc4e77cfa7fee3025c129bc177b86c62862a7ecb0061f2390fdf6decb12a0ef5c9f88f885bffc311ffcd8a2ce736d32b103670ebd4d9b2458fc93907443259ab56f1151ab1b3c4bb8fa08613c261787aa350f76f4212fc5aa62a70735258758fce7281d99cac02ba274f8854bf4ee3374c564a72cb76adfc604014047d72a431f2eb8eb0ceef180e6023f7035e22077ceb4f17ce90615c2fda6e0b97c583016aeb496aa1324e5c22ca8d4c4a5d7e898b9fec50945239dd06c4ffa49576d5aa0fc05bd389b9cb052e67178234e81bb6cdc1e24b7f5090b93f59927fb21c2af8d3ece9a2c24757d3152568f2480b330014f3d9db562dd0cd6776bb17c673732583f5a296db2a6b02f37a6b9815c56da514086f8fe07375e666469ce58d8daf3573c0492552dd12169b96d11c0a59f633356e410e32b58c8d468897075082f3e1fb0c38d5d164b0927682bc3ea58c627a4e739d2d1c34388913fa7948a371e7661b1d5e043e2c79a2bb3eec0bdc284fc0df1380b039f6c974d0ab6863a0abd5b7197fc4d63126f26fb12b30c81ade249cc639120e85b41e0f90dbf59d94d1b52019986d010dd0e17a1ec7ce2f1602201463838887d0b2792c33a42b073d158a23418b205becf6aeba74a39eb59a49ef0181ad2800af3890c5a37d9a196ccbc13544e8a6be0b71212a1208338879a440c967d0deab59b60ca65686847da49f1bfdba5fd26cb79d368517f80a86a130750f3718c2a5e89dc321e05ad551ca1aae983e7ab69890bc6ea53eeaf701065bd856079e69deedd565a70ca517e210edd06ca0fe3ef8089f728d849d81791e29c6d134534751a5dacf39b3059b56537426b841907c6d0f5cd9c6de66ead80b90d10107dd8ac92ee758e0cfb955b8906af89ce145e44f13382a63d24093cc55a28c9b5df16530df551e7be8b1503c3f57e9c9a9677c0be683ed6782b100e89907e27804adf6e1581ce4565a48d58acafe300390a4e962d296f67a3e48a750430fe99b11af3ab13dab5f493e087b25d63a9b9bd97cf813c50e4ca590ce1af616f0a8917edaa8565021b12a23763de3ef88e8e8ededdef64aa4cb261b255c8341bb302dfc6740ea301cd50988c456ac6c42741663ed99364579ff0712966c7ac76e3f4d360a2013c757423f8e5bae00ecf67f32d2fa2f8a0e8e9e0b08501c8021d22c66acf2f4e7358163e937dbbe482c1cfb8f0efa68f41445ceb436c54522025900f4ad8f8885eac18a6c104802de686731053676595b1d030f1a42b93d097b5e74b598069c25a55cb1db2c1cac8bb9574182bf85d8454402a14a79dba2e3b7202a654057de04b46b5de30247ff10ab9ba3eb7f7f29d0f8c5e4405a07285ff55d5a05429cb7e76e0ceae49a851b0b2741644f0623a04ec8fcaec192bd8d393c67ead04ef4882af26aca111275c6ed0ca68147431fb5733ec01d940c0e240b13503c15a98550e65417880e9f69531100f999dd852d3845a61672316ee7cef8e734835b75b2e7a4a59f3d9e7f333d85b730563a5f39a1182f6ffaee1f4f5c20d912528023d65a03ff2273ff8308ddfa2dae32b41311f7f3df9109dbdfa9886c67f177dc5caa40815aff77bbdeea6c62da66432bcce4405e862b7ed393502aaa1e956f33acd4a9c509c6886378a94e248f2bf6076b360a25f11037c8d3fc133e151f2c916c408bff552a82c1876f6472e7007398895043eaf6375ad3f9e54240a3006482868375b2d4e8ad8f4c43b8c25b484ae3cc2d859dd542c11ed136d6c3bc41c57a61ee2dd81733564f1147203e013763bdaa5c3606ce110a0a459013f5242ca49cf92199a863904cab66c459647b531211e3e7eee6ff6393ee3dcc9477274de0cf2e7e1e616cf8ebb0650556dc5f8afb5b117f2bee2fc5fdad88bf15f7b7e2fe56dc5f8af85b717f2be2fe1aea0862099977355c2481da55608958fe1270570dcf4c20c5c92dda22986a2622a2c85f3409cde49c4f23d6afc4fa957969e6ceed9422fe56cc5f8af85be405b96682d225044edcaf68e836a98ccb6676cd654440594546539aa3fa7b40ea633d58e3a7f4489ece0ce2836fa615fc1bcf8412166441359a18e09bd910a0a1be1a96b7504a8f2e6cc3ca2d65b381e79b53d5aedaac6e337191438eb9949af361a39cd1077fd41680d5a9c5e31eb9f6cbd4d481c7edcd77ec44fec13861c3acc4d1d411abf63fa99a1dd5aed4fc624f5c7c95c8e80dbb3ad6a19a8a3bec45c7284d0d1eb8db20fb60e1882660c3967f9ecc75d15be044e379fb70dcd9cac5323f6da112e8f3e95b72d1fe3cf709fb9b4cfecbfc4e9bb9f153b08988fe99f452d7bd797ac1ff43b5178550fa9468befce9edf156d6c8ad273db04afe272a441ecce10f639dfe2cebec8553849d821d745d91d416d057d1733483bea0ccd9299006b9afe1a99ef99abcbef94b911dd7b3292b6814ce70ecdd09df7d5d4481fe55c8a330970abaf29140822628819a84cd28ea32b1c3a6fd042ffbb6ce090575f78ee2069977fe2cd097164487eb904ad0da1ce603f1d0806d7e2e6f2f0fa82f5290b3a47c989f696672ef1ae2b06b4f0d70959680691497263ba81c5e5052305cc5d4951f24a69e029ef15de80ce17cb0c928ca9359a17b65de31bb6ac54ac46cb937454ba5c0ac11ac0499d3b5cda97637e28c342872ab0eb56802c40bec20629ef9515559964463615d2901ad9b51dfc65b6fb6f406039fb52025217031199b7113330facb5e9556c4f1c71413bf71033faa5553981a10f04541aa48e027e69d019aec3b889b94675fe8bd27585dfddad2fad3766ff936f7710b6adf60319321a0bb73d344c039549a175a97df554fd9a949eb4316e8b94b10eefa53dbdd3a5010f2d0f88ac0591799390e41a5fc303aaacc81dfcdb687fffacc6e7318449d5b21c9d5a9e2a2864eed1d7dfab1b6a4d8e753284025a4c4a7575db4d4bd9781d00dadb3c00956c76eaa9eea42051dbfbb22c5c30fd710118020854ec07b9e7cb0b1379209973d444371f9599c61789992e83aa71daf5b46e0a3cfeb32103d043c235786385adc23d46514eb8c871ca05a65c125d142c58037cf6dc3f49be7919393b2032bdc4f6835572932543895f6d6b650915d70cf564d8114626a09590c1529398af190170ecac465b5f64368ccc9a304b35ffe72579ebe339824675acd89e5948625429c98e322dd66f920312c7af25f92f3bb7af78aeee55814cbfd066d8187082bd3ff2751357a78959a8460f2e54ac5d7ffc16db23ca0c4e3509511191e5e38474b45885e882cbc4019324e7855db185cd920c6e34558f29fb54b0f80aa81499fadd0ce92c330b949d8cdd601c590131f30d731c18df8fb3a3a18f0162f360f4c7991fbc3e7bd08f228bb037354ded3e8fedd4ea07df07e07d1a2c5390e0746d089a016c0477c2f31679b656c5cc2e236b15dc94ee15b4e3afb15d93f7b5125eb0545afc985745556283ea0d375ddc0d544f49387851a2bf2785bdc207094452a511ac6d6275c7f5f178c122a282487296ef62b51dbaf5b549e4c70c778bbcfd4442f7e12e96a0076787360defcd2f9cd7df92fde035c1007b1b5e82832bd045a009f29bdbd3bb244d7aaa4dee06e95f607e3fd9294e01122f44c987efdc80ab93af42c97992ebf70727ef0944424292177df336e72501545d81122280fafa2c07361a823d6dd19f30767f2dbd7b29444af7449cbf0172850a3a435b701102b68ce360d00aa93aa322fcbd807672ce993c76c9cb7af6cb537c2cec5af0456ac5f3294d3d1b74aa4d37efd01a537ae4a2cc140c2437caf33efc55db29e2ec17da8e937e9540b30ca94f19efc571bcc16394118ff5eef1b699198f9551aef55d040a3982ff78cf66a2b2e83ec57b03a38b8bac9c7887104e1cfb6b671ab9adaed7eb18f5a2aa38acaa462cf740508371cc03cbd2666edff59ec87643948d98e1787a79a2714db1f0377ed690be8ad76c47b3b93030c1177046af53d5ca9b0b9e964f5424b7b6209cc2b9acb9b1bdea117abe50798dd564f2e4747849a1c8a22fc6e55386c92737dd4f5151d93222d0e72ce16743e486424e5eb002e17df25344ee5a55c8ad153cbd131f4341a6ecada8156a9f85d01d6956dbbba76c14560c994f000bfd61297827d93a07ada88c05c5093bc582ec894c2af52fb772463c8a13a1d1cb60abcd604bbe89e00a2b57c275448cdf0d754e532e95ca13032f2667cb2b8489e5ab994a71670b5de3e16cf85f8ee62221f648fbf74e637a320dca9c32eb3b2f738a09d49c0c80c1e76c8ee17844d00d953d3c8d32b5a8a2b5500c847db50468c2c666cdcffee8ac621d3c81d1a1cceda7d003ef5e97815c4475af988452084413afea70fa634fdead5500c2b77b160491d928d871fdb334f5e75f61983a6c71a6c4e16b56c06c9dbc00e22373d0441f3322b05c6853348d8234bfb73781b262959a16172dfdc3682b1d0867882aca92834d6d74bc81040469249aecb634cb941b639c2e7ef4c32d971b14936482a2f0e3070201ab8990207b2eba5b00574420e874f45ab01636188d219ec7467d7b137b3d2b77af386e28039de2dbe54a4f0b076329c23f28bf8d3a6eafa2c53650cd628fb3c710b725034c4537f8d3c7798b18cad633f8018f5dbd664e7539629ffcfa456791816b36a4a89ab471d3258e89f93e4a02fd8a8afc3631db5da18ad17ff945d03c35d80827cf887a29c34200399382acc08a4b223d824a20a2b668c3ea63e02ea526608d4462a4c9195bcbfc8ac21c46959f0d64a8327b4cc56fe15b15bc8202968f98a8c950f79b7e7af6ad6bb789721affcb9d44e29b0d76766b9d5c94452e411ce8c4e56a480d482b0451e096ec0fd28102da1913d9bb6fb4b6ea1e5318e761d25f6b51dac39db1e1500f413d5819bbbf7788a8e6ce4bc8788472b4cc83f6906f4f786e511a345e6231be4bbdb303f5a84a3b719cf81d500ae2065cce97198da734337132dbf128196c9e35e10537eab3592094446b234f5d628ab4bd2ad2d20b04e9c2b93221b8fa83ef363509912396d45d21881ce993458d1f505949919e19465d2720d1cc3887a55a2968a74391e778c27be1956b144633a9c95313accdd19b51247cd307b856ae402235881d67e9f2a7d1a0d358a31be18b83452f85efa00d227d4c9d9490d1c7f5e72bb42af6c4af31dda32fdab35fd81914973c44aef79be587a232d825e4ac84c7b1e7ccfd9a69ff1dc59542cb56d140522d23aec67ac0c1a8d331ecf83a4c11c76fe89df5b52001f0e119173fa8a48aa6ebea40f0ef10585fce1782b1ae4bafeff09075a3893d17a69417b4b7be8de7ffca0208200fe899493f7fa066a6c19d968eb292e56130779313e2903fddeeee6e50de6ddb44c4059f190a6f6ea637d84becae73d5b2d7b769a0151cf429c66ba7163823b3e342ba613e048fbb25d3d575e3c8cbc0d19d41e3e4f42e44cb5c35bd20fd612ce310ccf6c3981a33a75ad870d2aa62246535f03c3ce7c9579432e997e99c25cf62774e9e25ec6163d9251a52726f04d9a0d9f3e59acba6d1d32b53d197a0c681d73971965df83ddc047c94002f9d7b1cb60e095eaa2d2a35aebdced370d993bd616af2999f0c659a4ec524f1ac4319c2c122665ecceeb00802d7d90555ed94aa14b3fb31f73410675032cb84d5156cf7ca08464c8fa81c9b19075ca49681961e12f760fc37c1ae1237ae0da9473c2af43672ca640e47ea4675f726a72177d4eb387bcd478eb6a0b35c7bc39ac20a8da32c579c7b149ceaffd0dc1c99c24a4468a5fdebed76b48481d1da16571cd81935d63a967ff0f5df366e83f85580e6e3af8f6af2c5fa162b012753a07260e66edcc249ff037cca1a45e90e890cf3ba91e23e8db5361375961b136e0c15b2de41005772b62beee0728c8d76eed5fc986ded5fd1a6b0aabbd55674813acbc9740056e9a77302ae3857e7b013d026bedb9651401f685407ac44373e79f041e7959e8a051f50811b1c074765671bf76a5354a62f4cb04f92d3cac180ecf32b938fed08b838284c242d524e45c550ac8276b1c9926d383ee122ee426234c5cdd3d988a0d2e268c0ea04d44139d9b5dafc8dc5787e6d8d0be60e0f272d14c9f49b579acaa26c647114412d0137c5d76048e27cce00e94e9177f5e711253af4175e4bc9fcda2819e571af9dfba370b940c1b547791468053391f8ae48d11f6d8dd6c3fafa56a05c5a5ba07676035e3e8ce09134d38a234b35f2309fb8c72f3b5203f1bcc5653b93ebd1695df260fc50d0c708b56d957f14daab4b501abcf93226962da1c37f999e8f4246bbab50d430ceb7880973164905a34e5cfdf9b97cbc9e8800ee905319d4e6aa9be3bf95e99711a917874eaaf5b8141a54ddb5f2d54f1422303b29590b20b8f2bc679c1fcc13cfd71d447356dc21956ffa555d5b20bf2d66fa3285c48c521193d3d3e342c06569c2e30c2abd080291d603a4919b58512122144230a32d059750893464d46d5db913be9a39789184a3857d7b3577ba60bce2d396eb599ec6c6188ad1e230b733e6b364ccb874249c7ff28e38b5f2b9bf78d17c41f389395068b1970a4faa0e457e18bf204639455ef5b723c29584f3ce1404d0ae79cbac6294005a15e7799a337f56ec91ced62c5a7ca8233675691b24f2d25bbebbb5a09f3d4a7f3ad0084c7e7a063db46c378a08615ca5a6bcb752bf801f177f51dbac2a9a8bf92c79228933dfe600a04747cc7790ddeb76191f4a74494fa9f599d97d47f2c78d96bab8f8d91d4176cee70bb63c3733ee01be93d9b0ffb07e65c604b8c1ae06a659a83957b46c8324b640750ac07b2287ff476adb0407bec6fec116b341164d2c6b5dc3a2a4c3d68e2ed98bab648d407e7a57550b7a8c6f7ded1f91a47e239d2a0ed0609816272e9a7708599918828b001fb06ad873135c5de9b1dd749046323b8ac3cbb5c03968445a07972fdcacc603dd43a4da3608e211374b10615b30f0bf8b8df63118dc69318ef005a34573c18f0841dc26b7d6b3e916f6ead42c6ab2bbf472a652f9c553d6cf9f72ead892340d43a8fd162f01627ebe9947613a9836a9ee7e71b232916240ff0ea3ef049000d2581af708a0fe64cd783ab7a8279e76273c0819608102c2ba8f99e1a677aacc8a29cd01f6e0e7ec11c61a2a63f9de6f80549f8b31171e6d44958777579f6b47cce09344cd0d05926ff1fde4eae6f7c86e9d9562c59177e056c7641404c473feec2e73f6770b8a483e51deb703f06bb267825c0799e71c0cf464a0648f12db8810350ce27ff2b07ae829f9c227dab0d2a72592966a9274a37ec5f74cbdb88fb448bee7cf8ad2a2b83b46bcd96f54131e8fd626da3177b5a12d8f714e65cae5340cd66f9151c7b657c75d98267554111746009b5c6853c050003f69a6f83bba63f9a399eede38499348631c92a5482525c331cda39471f55f593d310e07876b0bd369d39c19481284d0c86f6776a5be5e4123a9c1da709f73070a0365f2bde2db4b63c2420eb565d903f7640a8923abd9107c520e82d2997ef4b20157fadfc9e80003add0913ad738c5d36a4dae1d3de822cc46af8da451f8e9277440dd116d2b695b0ab20f2811f17a2e5d971790836beb8795e24bdb484e4dbfb408c1b1e19b0c4c744e5b64e6acf531466f6a25659c5b19c753b197ba69eeea6392038e052a2aad2a69a44715b5732b43364e192779d172b5d2040184288dd1d0afd254f638a484be3ff022496f6bd6d5eecb1331c8c17d43cbce265956f8776da21726a42d1f210d5f077f5562d5be969783272d5323506f48172cfd4d2390f551c5b9cafb7d50a49aa6a1707f5433adbb8cce5a4be66a1724e8312038dc8c3d01119197581b3fb768814028e895d102ddb382fcef18a12fbcab34689a88bdffab67da449eb6839757906867d7b881fff1fb59f262d18f2db9993b2dac916984513450a5dff02e712f05a810521445ce7abd242c46f58f3c6b60d6aa40cb467fe4a0f72c43523f853c5e90ed6b80833d735a163697d5aa57b7b8e9086c69a1fb9e356d56aeaec9f5acd98fe9406a94a704509b7fbe92ccda2f1457cf5abe120204f74904446b5edc52d86e43d34bc48a00ef340ee9d6042e27be0e9fb5bea00ce180af7888c7477e01c281bb9a2df2f3f5141d740d754f191a351a5a714aec2dc8015a2b841181535ba69c681549a96517778a51085900785348231c655a86eac2f26445b12ac7e584c63345aaa445785c7c9dfc2c1582a109965abd38a8a7a76dad2015c5c1d6a7708f1df96af59dc0034a4a5801613b9b117946b15d87da38c75973e0f5995fc90c88983223f857d7e95554b66495d13ca66beb3a9a120cb5f729207384abda08c059fcf62b9e110b3f3067a23ac720ec1e25041d9362060c6f85bba2c2dba7ddc3ced398a9cea48ae46e9441b76c7cbd3f50da0b8f5e8ad47295de128c370530e9fa4716bdf02a6fba741f0465615ca3f612c81657b30f56ddcb9d232887b6552d63406ab8a24f830314188b2e1182802e34cf10302b56167252822327243573b36c1ff714c254476ae51709bd2124dde64a6a2dfde9836e89e89eca2e365f94c671afb783f888e27ca0370a403f0ee33a6a713909d72047a39134eb381059f0f522d55e07aaa77f40f95ee598981c63da9d1679f2ab717442e3318554f2ae463244ec98dbfd7639bb04f9d9ad9ff8d85e7ffa20b1739b3b1ee5b3d1babe67ec616eac20edba1721058cd7f7c6b5f818e105bc3ae8f67397a3765095850722fa5f299fe324041a4ae842a4c9c0cd9e36e72bd69894e4ebb3e9f0e97c1f3116e93e36d6412cc7fe98c3750a19ed1e8f68a921df628792be91eb866ea1744990f6c90a22987e3e7d25611916638875f06d6f8bf29e43b799c298a2bae19d79975c8440cae8d56ddd52ab9a882043eb18de30017d9902e30faabfb93cd7b3392f3952ae32cc713a00f6ae0e214151c15003f5ceb7e41c7216f9bf77d3f66f18cdb69603061c8aa707dd8018ae438d7589c0819c958ae29f0e159490ba77315a3dc8f7c23e5833a7dcf24a9d27a9f5db8dfadbca814a527fc3a706c97ce745a3f052550b57e29ab57e2cbc6e5b0d81cc7af2dc47492605c7abdd4093ca44f6e0c80d1f6a18312893c41f318626356856690fb4bea2409ea811f3f1d77af16211847219461334155442d55d2fe0ab55d0514803af265728f18e1a1a22e9a790116d4f65b0290a77da953f058beaacccabd232cab919383e3ad4d31392fa0048b96d7575a9adb9b597759fb2148483c2efcca137ac6e19c0a6d4621316c82db7417b9d194118e00b856a88d5685628baac24eeedbecb6cbcc7be33dc8296c34f7d1d52cdef645b8cb54b949c04adf130d34416c02a0171a07065eeeb100f8bb697f6d735b0db5646e738c927b9e531a36fea6366d00043489b64c1f766b69ff1106e21f6b4266aed356670052bb379552ac9df692675012ec8caa94eaa2351b7b787ea4b9ab0954ea38696f2c2c3d94881e13764522f54422dc69e07a50b5a50ba8ba215dfd3c86ba1328eb3066519f2b8e822b3b5e083efd1888ab1c7f81f6ad2bcb0478857aa1fac5717b27887cc4c60ea525e0561dbab2885b36f7e78fd5e41511c69be2984bf3e4eb9222660d61bbee913297a7f4161f5949b144045482d18dbcb29d042e347e5b148c7a2ef8501bffb3fd31f83a4aa70a44c5640c31a3e6e7098ceb1aa06c453252ef9e6b6f7ace636503c4707eef13d200c2f24faf6735d1cc4f9090acfe46770e64af5fc7a3c3b628a2afb7f58de178f766e73046347aa765537ad5d23328ce2ec69651a8a7688cf85c80f51f2f623677a760a69e7f51b3d22f1def11eb20e157a8e165844576db6386001c5e568049f3d8aff8895c872344b043d2f6bd4093913ca5839b96350eb4c759250e2d002a20aa5b69db0227c8080611ff936bd05335ee80a2397c6c580b6f4f7e8c3c1cb744c2e8e13ce9a767f28c88bd3d24c502268243b17c750d99b9e8b5b8c12265ed8446460bca794cb94243db9d9b071e8a40ca481426b2d73b2c2380ce1e38202eed1cfc94e1000bcbcf5b12629438cad40bd647988fb29c5188ec5a052683064a9f0c8baf0db93278b9622778a57b9095a96b8aaa5480a3fda01ab28997fa4bb96b1a839f70ddbc91ee8a5ee7fb927318339e9265703beb05a30c8d161806f6f1d7ae854fa3fea92bd508e784ac378742503668a8ba348ae8e4864784eba21872abd3479329962ac928451b37c876170bd1ba73104ab4799e0a0ae692bbd4f5cb793ee522c0b23b4f1c27bfa7ab5c04f2402ca53a3226d38e4e9139f2067b0b96576d443a6c5ab3ed6721893f53ca40b09a6f5313c7b86c3ad494994289d800836e4e4684d85189271a63395a7154a16ce3266983c29a7a6310e4a669de184939ace1e68544499d384c206634f3ae0418b26307c4380e30cb907c536862c4eb911c1d7560890f7216c7af62825aa41928af1dda9248eec93f147f71f5970a92e44a56d6610ad02407ee09d52f7c46b8680b8abcd31b7b14f30eb89940ff5df211ac8aca75319ff286366cdeab4707c43b3edab2df8d0015930b54739d43f762678f96f450a344e05765acba2d2f8fcfc7ebdc548e3d9cd234dccc3be3b2ec6eb8f9281d4886b21161a67afee9826144b2204914b67b99d66a24927a86815fac22c42ba966904718867730cdab0a8467d2eb773a073b1ea14f24e0e502ccfb91922cdd2d246a8224739d015552e0b674de8bc5925116723150a2c79904e5ccc242b4ccdea5a5f707f93b0cca59d650ec6ea847c872e6b86319281b1ff6790b15140d87825cfd5f05e7bece02c90a895130e9acd6a42f141d35173a8c1d083fd04cf4098a4dd5275a9b8965939ce201341ce40b4c92576bace0a794e9ba1a2f2ac727cb12c6139f53ab722fa54f8a978c655eaf05d2ba65ac9a3a07928311811d7e043a293252b75ca6ecfa7c3b40fb9158ebbe85d5d42213a90ac9a108d786e3e6ca4f1353744835c582317a692d4d488351a7dfeaf784459d6f1f1d8eadb7235db1ce0e26c31ab6c753f0ac1959de8b773e6ed5e92c8fe56fdbb974f9cb293d6b8f538314e11a22cb73f4e05637f1ef6bfb870fb1e718721cdaded75c0f60e3e879bce79ac02081299315c51563f3688813cff3fadaed753af7f5623f3c28691aa73035abed7ae5b65bd78dd91eb799495167e73b986e0e308d01d5a101ebb26f354f594e6ad5be5c5935a8697c82a10d9ec397610932df99f1c36707c2f0e720d07a1b0986c50e3f2eac5307da0b25e41301f57b77d87d38f9096a3f11a5e565ca5416cc8352d1665c1dbd60f602d8e7cdff2211c0867271433fd2d81385d4bd26a7c36770f7f21dd8d7740bdf0b1d8a66fe5ab462776a38aee1bce8143f1fd1b833599b68041421868ddee8a7eafa9dc9873466ebff2ff4ff86a695668e85d38813a1526c022e0e30558ee37d2782490677e1f809013a9f08270ee7a967cef0f40fc6df73116daa4cfd5d0f98e883ccce202dc030a22fa8b6ffe03708bf9c5d4f93221a21c58e5946000abd3fe19be044024037002187d03403a57a845df7b11f5a7c631eb2345d00035b10ab8ec5dc7a25e761da7c206cdad4eb0751a264efc595418a2f231cd05f66c28c1ff8eb13de2355ee73cf84a2c245589b67de53417bd97d02ec23efdd3f3d9dfbff79def4d59ba0c1be89eaa52b8573a5d2248b2ee48f96d941fcf1b69ba2c7c410f5879ad92f53ae8a4b4ac0e840c9d3d7b7fc2647350873c929bfde7d3e0d416652d0cd290ec051537a487e71ec5381b8cb0e71d9ebee5f24c91942603311f3b083e3f6ac9e599b08e7235b17f9b202ceae8fd1991981920aeb60170230d0c82542c7aa851bd6d5f6e4de0f0c00f8ecbfc9fc033fd016cbf873bc713dcd41e726be6d988732a520f6c7e87fb2620e8c1b979a4f6a0ff908e5ac3d7ac2467aeac5d291cba0080e20336b8b3d6040f350c8dc7a0c2ed975cd828eb5f8d70266bf55b0ba68cfd361a11548f40bcc23a076e45d55a4d8257c582c9d9e2e68d953d1209c3efd34a13c792d29b076b9e1bbc8c382658831c7106476fea6e4b47f5cfb8086475c000c99b0a24dd118632742da840c6f09a90281d095bbd4c11ad17d0fba02dd9a6063c9264d8104ab3415ce164f3d129b56d8e9151c4a16877f97a80c0e12c474451d49c94e2c0d25cf2a1427229409b62955d3c6c2cfc6161bccab71c4cb3b004eadfb270e232a89fc1bd50509f80cad6a864dd461cde7d87375c57f9020efdfbca65d597fe3010db5eded724d223d5ccdb09d5f319d7407c2f1ad601aa847fff5656cb651b9450c0990fa7520ac24f6b9d6ff3c70e49bf8ddf43043d1c4d0f4836ef7a457d5359d71c1b29f6e73ad1094c6e156a2bb2329ffa7fc621033fefe857ff5f3a6d07c5ed60ec9825a2a3bcb0f97fb0242a97b357394374685e848286d98983c51ab4e2387c06f101745d06edec828b93b293f91deccd76770a95bd6f796ac81473d4d201d90e2ef1805e3dec993fa3c8b5efabf3e583b26a16f4ad3d0e0599b052fe561fe44ac65d76315db9555581ede8d85d4e3625056da1a726e6d170d727800dd8741cb3c7e846a1285724d6106c27e5567e16ca50afb09024fcc60a06e1f032b2ff830926cc36a02e16bef1bab3c80e21fff01d62c7d44961073a1d9c5b3e7ba0bf2b8f87ec2385578662441177e26b23237b209330a91ee09d3e36f4fa3cd370e4d006235c67ee7a5a5847949d720b33057e6bfcaea86687702dfb837992d6decbfbcb85a18ff4a6d5eaa9000d497ec89a2901e1973761cedd1ed731a503132fc4df696b6cc8d967227cdbc957cc2a8ca6698473d6eb036ca7c1c44458590eafe3e6d8a9e1bb417a0422079d43185c7eeff34a4575ea8800aaed5ac341eda7360fabec8eea63ba02a17128f057ae638e2a232fd08bf0687ab3fc7c18f5ede8d353334dcff48e54b2847fa94e2e4fb0ea72c03b62da4ad2c36fadc38c9ee422c7a1ef2c3d1f8f7a410fa5973b4f53098416f7c827342a469c61a232900315632695c6236ab25690f7895fb010644d1de9853328bab20133aa7e3656b745951b0f27e8bbf0aceb2609fd259eae66a137f39e4ee13c200a03a18d8f309fab0c96a530b2640659c87b7c62eb7ed6544c8c8971b128609713cfbecf37439971b0f51529335791b4a74a6d8ba706550a6d1b83ed9d20c0456f3befc31041c0ac8bedcf043f639f20f1a2af9ed6ba79c5afcf2454e09d41aaf102225e62265be3335ce5e122521033d97caee8d9c9be02fb1ebac1e27490d1868914acbef607fb318e5dd61ab18e4d9588772dd2c875ffa5542a3b1655bf891e674382a53c5fa1b912974e2481f51609914046b518c847a4fbf3e07df4e9d7af09908ea0edd29486fa910c160e2dee194f4afecd5822cccb8ac33879876ca20bf6972d19d691191577efcc4e83e2230257eb890b2d88a378a05386342aa192210517f81aa6141b2516a2d9b2722277244b95c6a5fef0a5365a4c5e71a1165a29a676fc9ed6e9f590d48ca9e622772be0117bb87bc3a7c9b46d60edbcbdde242abd321caa78d622172be4612d90f90690c30e29513c9f5cd3b8b1662a1a62fb2b721868887ad1ad0b7672143bb97890ef6052a0283f1939ee56680c919505d54d64794ed7b6acdd239df17b1dbbf075e53656bdf4e71a8ed04cead879adb1b110388b149013becab5ac919e0cbf84809e327dcb46e5142fbad4181732939232c4fe2d0920ab23204e3450b34d4febe5739940f069446349fcf6605d1016d006e89d1eb63c4bc060b26a0dee18f6b0c8dc2017731fb5766bbf6a5525def300412d182a965f3f136112389781eef335cbbe6536bd0a3f8017a82d7b352f668e9e15fa9d08ad44854e4d5c658e3bffa56ed922fcce83512206846ffe2e81aba0f0dad5ea7302666b69c622d4c0f2298ac03cc171726b2129d4da8b08c9a00d9149e4c398386043301c4d9a1327d8f066dd059ab21cc6885de68ba7661474473051b70002c83cc820420662eaa667a422e08f070afae8eee8ef244eff26a9b582f8d60b952b5ab50e3ebff6988c17a2ded6a10492f6dc0c381061b139ab09884f338878a1007ed01a19925502a259270bc33ee389e568507dd29f06348d471002443c25ecbc38481a3f13b8fc87db468c3209fb4166e753e9259c62c86fd8f4821e0c3ef8c9fbda9590757a01a1208e736a6715789a96c77a4b8caaa3cb6c0274a756e6c9da47154dea06a4171df4effa9f7d7108427658e3f47e310a6051dc1301e2a3ddd99f209310e954185dafed7a86474cb86b42d95cb16123dbc4cc81d151c1cb576962d6b0ed5c0f51c84d256dc22dd4950dec3b4057312a4c12cba40893419e20642163fbe4fce7e81ccf2410185eb8645bbf60204e199e4db7e3d023514056362ed7a155007e9c6d36dd678d16d7b3f063a403538ac1e8e51377d45e2acb4280c6f60b957f234e03c9c76d9b77442fb05dd56ce785a6082c4a061823ccfd75cc4cb433fc8928b6f4bd125ae3673958eb24f72950227080669d4d9f7d9886e1a61360e9344e438f60c9a879977d000c59b625341b817335fbabaf5f086b173f53f7195fe8b00fc4d929ec6da16d5d36db3a05ff7061e38396d32147a7a30c729511780e6d969d1fcd100f7b76c25a82c14a8d0cbf2829c80142ca585d121aee8117c8570970a515dfe368d62630fcb1ba816050ba06e3c00a2adef949865da7d77239bd193f3f548609d6d6aaa31402a1a437a2cdf4cbefc79dec828c9110d17791130454f5108d6e24abae5360285066f3261cedb3eb42a3a82e10541e80950ab4143936a311519008ace6f998ed38a409b18643c8c26591a7068f4499d450653055084dcdaaa6fe7fa696ed76229f699eafcd679f313b44b925d2183d337554e847960e702d3b2c805f581851e4beddf805d911fbd7d000e9673e9f4d1b8f3205e5aefd965dd03185d9ed41dfd6f0589036cf86ea29fd74e81c1f93b82add3a382eb00e4c42c40861546ef42d1a2444d2d39e0dbab93775362d3d264834be72f8590597cc8f1e9d099edbe78c7ec7beac0be2f136ea56773a17668169f42304469a9142494f54d48f9757c532e156a0946063beef78c6a8bc63d748620b6571729729fbb7e977887bf699931b0bb969f8b8a68867d3113c76fddd399203f9282380bb8bbbc56b16e3744e06449aa8d85a936dbbdad1d5bc052bd7e26f99604937e8e14667c3054b96407373c34dd72f88e7a657356ed8960d1a9a2d99083883fe9828a5409ff31734f8967f87b44b43d09aadf09252718d254baba039010894d5b132005e75e71015e911fe9327d47bfabfe437fb456182d6c4738e03125b71352a4b4dec662e16d73e31fba812bb32874d3de46a4978d796534379c427842da77162c00d4144952c56a5bb055405896352d1b2adf58c03c90e933696253efeef0017eeda9a1ce8b0ff90c4b7d3fa0650ebbbe6adc2d2f5397ab0307409f5e4b362268d05d8ce064e2a992e65dab88fa2f6af3ac155ca767f540e5e1c8bc09cd4c2ba0ca0fef1c5fc850c5b7c433571417cd23442fefce8189eb2b6edd922fde5987ec8b2ab2ab353a05d7560d1eb70d5254279f20b01d35fe24eac42d7b3d0cd6564a049dcb5f41b6edfe176b0373919a839369dd784c0cb39c4330071a437edf84ad1ccb28e54a8aa1ea2e5067cefc8368ba475178e21d0799bc5da1634652013aeb597d0ec91bb5c11e2585dc8ec4bdd158a12b80b831c745e7c203b7ee6df24d438ea9472f53e90a6aa6e652439f163116f60515c7cb3df698d4f55d8da9a3b9b4965dd4d611f2d03ced09046f5090c09b5e6d91840722ca85e81c43a73f00aa69d2ced5e077d306255013564cbea0151fc2591546db68e43c62e83206b249a4fdf0e1c9165c62d5c0f8ddd0264208e0fed6f874ffe6af83c4a121ae5f8a61eff0f761101805b6ee27c4efa8b062635d5a654ca73b51bf7da782c2fd918f3a70ddc52002155928ddb525ff152aa61263422e9c8018d9c0673922edf037aed683d2f345f8810ba07254235e713dcf946806e7cecd4e9e905e9f0235aafcb829b849870b2d22a11b336322296af43d431c707bc199bb256961864dc71f2dd84e42684f114e7edfba5d949cd44d44b5a85a1434d69343bb78078e138f2fc7bf545568ab03224671365c7e2c912f062190c7d5fcd0d678e7354eadda1a8072544b114d0ec1f0d866fa0b77cad2e7d700d4dded135d82358933b78a30d6d26c93790fcd43220c13e24a2162210071975b1c6ff7b08e1e3657b2f9f3de4e98a0cea398bfcd5c95d3edf63e9227e55036335fc94f80c6427025b4817486ba98ec4e7ae223446442db2aa2d009a56af5082ee63e223bc2f80b8489c9e8231e113118a6ed51e83b8d8bd8dadddb0fd48bfa516985120fa82603402644aab0c861c317d7d66ae926d394126c2cb0623a2d78f5eac70d25eae9608625567999949533b91ceec59ec6de03531a0a039244b4b521d642792160dad23c8ab4b0c26a806b8b5d3e63d4bf84ea8c06db0033819aecad90088f408a44e10f107821de8ebc3a5591d8b8759792baeced1f2da4a4be3a76a839530533001e657dc0202c40815308f8959b734d15ef5bcfffb3b31277f43fda6304b8257f6ae05e56b0901114397e2c70e5164441475288529865e74cb622b117608f262ef40e89c88e7060a13c35fd0c4806a8b0e217bf6bd7c73925ba697787e2a258c16c9ed5c4d1c98ef3fc8bcb2eb1f908e57b223bc0d0b893a4997de3ea65fc5ddbfbeeea29a3a05ca6f9797ca45118e9b196f080a5cf2f4d6e34a70e53b5c5150f9e0a6d3588c3a8d20d4000adf65b6214e7fd7b8c45aaad26d4462390dbe57ff584516568129758003c7893074f02d3e860314a3ebef3fd48607f5442d42534cdd0d2976699463985349d15eee99a30cbaefa80a7b33bcc241f9d0afb717ce895c0c3d85a66518214c97bb60c8618f366dbdd1e87f91314390d96c3ed9f192e27e59cd5511c1712fc5011b170c1a7cbca4cf3c73de0f1048d535ecd0900d8da2b1b3162d28a8950a5d60144ccc41f9784a89f17615edeb15ee3e86b8bca3a34186d982fa93e6a1351e61668f64ebb4dd3fa03ef89bc5888272782a4a6eccd55c1f55a014664cd4dd6080b3ccbf8f408efc0d38d7e5a9bbb9ca80c91ffb4adde1990e46504237e5e2855f46ecca656b75b369f5331e4f696b5fc3c307040151ba1956068ecea8b48c1b1fcc310aa77f63176b894446a67a3024ac98f2ac136939196d465b064b854bd417cd62e6b64c870cbc72ace961deff82ae2a5f4a9c87de526c1be1b8540df3215d596d4c4a699019fa9e4e08115168cbcf60a78bc6b6d9535458cc6ce83a52e0c44d7e4bdb1c18654bf3977734d8f10a998122a748705029c3b1c04e51b162085b74ca99ed34c70a8ca09c8dbb38cb57e53b830d916c03c81a7100fcd72f1476e912ff9a297b8f1eb90aeff4956bc20e6cd69a49d084c126c10b53bc2bbd1d007caa94e54fae13c0bca1f539268a7101b0a62ea4aec3369dc0f5d2d884390daace39c6eb902dd63cf9d4af0453396d07c9745a2b56825e815543e0bdc16bd6ccb15e262c75bfd28132fc55db18aca7a213456037234a6c2fe0bab181f79f7dcc59edbbf9a046a0836f046174e81ebe370d43419c5f4e5b5a75dca10a313628d0c4cf1b652433151960ad261bdbaf6123af55994001047a6ad2c57ea692e3121a8f2fb4dc5a3800224be6911c3fa47515bdab7ac56d52624147daf230b5aae07b1ce36dab8c42b279f5ce83cebb45ad02b7e549324efe0a3856e31a3c50df6e52f1229f70fb8e76f72379d752228c04d6f2b4ea56f3e6a250acb829029b7055adaf8a321f61c99767771e4bd3e28249665d975d323e5171d7f1f0fe0e11874c4d6484112c21a5403299e61cd50f2524834af9cf1d97eb349d3865b648bb6d0b00bb370dd1e3d7993afe4dfdac6cb87af9bf484db333bf38f21a2b89addb251d21fa5108bde52eb2dd55e9c0878e088cbb07cb41840a0ec46447bb2c439ada44b923cc5390f240d41a9cc087c5cc2654e2280a58eec074c725fc78615dbac3b0cab585d6126132ac71d06ab48a15f88fcd3471c8a23b73ef807f588303011c35a5e3572bcee60a0f2b6d28cd6f99a2164fc57e4c6e488936593718ecfaae7d1ca323aa2aed62762026ef4e2345faab9dbb0cc21018ccfaa776dbfab8e2024b07da9363d4b4a6ae76f05a1ffa1eee839126054579e335c7938ad1a32459ac24c9c269980bace727c3480d583ef25b49b5796a74230ef98744297c6ca23c9a7b77956405b9ab10e77caf4e40ba634ddfca6375584b47b5a6f23be5be7a52234a0cca5b55c243936c4615b9b12db1447d5c93730d497fbc0b73005e9f439073932a47b9a2037a2de8ef0c5a58953274e9c4701a6cb6394d758b41713c2cfbf249dba39d94ed39787934b4442d70a0585f646c6fc294a10d16f31309cfcd9bf9a5e0d5664fb7f36ed61f50538700063fb1f129141cdbf1d77d250b99945935bfff34c41a8c7a6d3e2b3e699c635f0521873ea65a90e4b4fd932f4f37f6d7c60d131f9bafde8ae2dbdc1bb82457fb685fd1a1932328e7be02de5460e72bc6f51f8c2c0b440cafd76211329b8ff637f0e9791f680bc5996544e127b94f2be100143b2997bd1a54665c0916959b15269c6b199a2d70356bf338e50489a6d6a29f3093e69273febb56c1b475e853c906246718348ddd9bd7c200a1faeb546277ab6094e6da350b446581ebb840fbde4b06439f9110c4facf3cac35cf0915fa838f3f6744baaee1198767b2b791b1440d55b50ee21446541dc8d8dc7a979f5950949e65ed3553abad3c4227fcd54100d5d55e19acfbad05e373db54ccccd08ac34c7e50245613789d21a5b7ef0d61740016c701bd361f04769e444b4e76347201f0aa15d3580f4d3fbaa632c81e23b84049276b2e2b7e9d9640f599cfd2a508615349f2f9b3afde360b44094136eddc3b6b853604251de5b79bb4ca4862c21ec9e7ae701ca93208b091344a2946157ffd5bf279ea289c017d8ed7797e12871d793ecf11506346266e082817e52244734f12be0e10ad887efc68038598c6c3c8e72e9ccc70118460f5109857cfc354e7de7b4c06a1d8bfaf229a026cc035725d6345f20a0994f15040b0b9eee6295f247cf63cb4bd723349f01badd063870eec38da176be8bc5d634b5426550ecbd24802f640a22990c622b153fa91339b32d53323b41d83c4a138cb2015d1b2b89690051ee1b75d18794d5642c6e19db73d7cd9005b909af5851c1d3d386bd62da5664067f4bd3cdeea1d5a7d74bcdb7a7829647935066ea950d9d61f54baec474725a35863e62cf5fd28ded7284e2d2f13cf20e64024920837817fbf6f4c6c42d9b8ff6a38eed8ef8c6f0cbdfe0cb725cf65610985008756b51c4be24931033b3c72399f36880d7a180e71f863f5cb0b1f79a4ca1a1afb64bd82a06fab42e74279959c556615a397214ec9d8eac66640cc83ebc977d5bd4d5eec903cd832ec4e41159c313eaed9924f3194ab6be50bca36150cc6ace527f3fa1bfe4a71c1c15bd6f672adc1500885422678b6c0ad2ed3131c54c1a750fbf2a98315529d6e419c43e3f726ef25a0b1f7294f4ac68692240a194160ebfc4e30ebd8bd8475226f5312d36b6745076403718efb0e5acdac21ea5c56fb00d66e2db36ecb6a51d52ac1dd9ae0f8b9899211c30201c6e39ffcedce860699efac4b847603959d03b0cf00929d8038aeae90b60c0ddd096417edf4452da88734be0dc63207f88a6d3eaabfb17d6c074baa55bc601bf344c6399c35f8c3227eb11dbc1211f88e724caed10282d0593138d344c8be9dc34254175c162f4efd57a02c17d2029d1663d0d595e70071f1fd3f64cffac46477e085b7875ae3eecc11092df572735b41c1d58d00abd93222f46c906cae4690e095bd07590b39e9ef38facbc30ba698ebcb6c21718c5f4415dbf951ec04876dfee80624906976f580b1ff8b55b924ca9807e0126a7b3a0692cfa3c9f38dabb847028e1a1b00b9232090ace239f336f76ae06885102965afb3e05e12c3c73ecc47dbdf07cadc782a263c7d00daf4dfa1b8dc07aad9d7972143257354c0575e8394fa12f59d0161e7b5b616cd4e58a800561c040f77ef55824104cb66455727850e989e7209c796aa9b428425d1b8881c49edfc2a454e592e7166d391e618c9b034f0d1ba689b5128fe97ca064336d3fed300fa8085a38cb651d79031565e361c1bcd2c4db56c50eb7768e070978ea06db971888c3d9e2d379bc0ae7d212161d490d66bb6a5f813494bfcd8c3330ef187721a70651e4fba80e965310ffd16c30e7ea637f1e0a279fc64499ef324bcfb793ab02091091662844e3b347c87893d0d51ed1cb7256d0c2761f8ea8cd4dc04472f72d6633f5f466e84b473bcdd1c549b39825c65745a0027ba189746adb02b9eaae1a295963b2133ce02cfd6275d128d5f6d44179bc14d793c5ee13592cfd474f4b023db431189e9e1e104b5f2dd458a5668932f9641edb03967f5e5812d9fe38db315e10a463426a0f7af12432dc9151d3bfd0e8cd2916a3aa0587cb8b08c45ae3ea89f844372b9b2b83821ef59d4323a6004264549ae507271a975ff4de5a5fd38e09d7186e772ff02a77eefb78e5782f386467d726b4a79ca811636c1bf9b428827f3468a42fdd2e1be18e7054e913283937e5ee6969e962fb8eaf16ce6461acc0c2ba168ea03fabc523c7c74cd5be2dadb73833efe454f1da2788c7565f3d144b7fcdf2992f05660daf65a83c630235af927c694872d2af699dcd0a12eddadadbe56607d9c5f0d5a04e44a46fc62f16772ec63d6b042c3a29223ccfe6a6591271744f9ba66e6f576fa858d1d54168b068469bcbe0dc95d64a866c633ea6ee326dac00eefc13a21050575835e1c5d9a2964c96f700048c49e5766370f8b2e278d47045822689e9c28615d5194e45f51162e4ea9c00d278eac5ff0c152e121459e13e7983e257af138230058c846bb25bef4efb02924e923bb2a63d1e2545dc663c30f840450bf564887530c7fed372d63bd3d8be9c50cf23a3bcd28b6b53491573f65562d91007006a608644794f106fe2a2d54eb3ec1eba7ad5c7e9cbe486a3e03c529093bbe075121544424ae9e49268bd98fd0db63cc2126070e7465d7104da4c3320587b66d0d85fdcde8695443ac4edae06069e3b84f3d50d9dcdb7305e19cf6eb66efbeb53b34db7aae7fc913bafc702b86be443286a86251754cadffe666d63e60e44cd06a24a2e43ecb214e4f64aca87ef9a547c7ab2533a9db8261b44520e5d7ca50f3c780e60918ef16d34fd255acb90ffb0c4df3e9bc4613857ff99f80e3d4df534ace8ba985350e6790c8b910deb6865aea1fee37c2fad45836223e204abaafc49c1537ab184ad7966f356ec603f3a1c56e23acaf34361bbde8da688ade465ef436a2a263a3accf46b9f585f48a07761a9b34361b5dd193c6a61b0fe9905b9f89ca9f7d246736d777c54462f0607dbe1e65d00162c2fb01010e81661c5c9766ca0025e9a5601007e44a78e99924f0c4cd2cf6b1d8c162870d84c033cfc287adfdf422dc12c59aa702c1fc8c7229a8fd7040b143a19fd3f3489b0dd5ae37c150e1327dc69c71e15b090c6be5870fb3efdeb2e366aa8ed487aee386e22c22568f928617809ef6962e33178331d362c84d70127fa1a67dbc706af2e86a325c9c7993bb1bd4c8bb724e7b1812a4347ef03ca9fda55a1af37b25052a55ea909a06e65c793404ba7461e0694d70532ad6c0b34bd12e2b37dcfbeebb1808643437bf1f5cc5de779edc6f90c03a60a0abc449fa0ed57b01debaaec35f3d1fd9c5547a52c9a93756383db200b6720b6b584a7d9bc98572d07cc28ef0f134b247429dc37a08928c7a0cb7440c56bf7fc18e6955791bd06d63d10e32e4d3a927164f80d42e835bc025a69db13fd639a58893bf31f10ffa50de49539ce71279950e40d9f0240c65e70bf9e218bce3f928ab839a995b633174930bb2bfb2448692d2d154b43ad628681e9164c49d3363b7bdecd6cf2c40f288c443a9073b957de9323bc81a0ad74d8c6f91d341b3d1326a92b3f80c17de671426a323f36516f96b977e4ceb24fb959a0669309c3e48ce1c15f9c14be1b2641f38e01268a34bb3d02e3c9efb1af10afd5a040596c9901e78cf71b3df29a318cf79bf17a8ee5d6b20898bdfdedf04b6e46a0c321816e56c409ba6e95e1e1e98973558fd8dd0fda9a826181662903c8f62895c72de69545389a83c22f4af29a13d5ee5263c9e78ded08897f8c6667fbba87810c726b165f3015ea696979f915d2af3fc7316de3d063a547ac6de935a40245de1c74793ba55efd508c589282aa241f5285b0477ca420f00d13b4a23e2371c4c56bbfd9a86249cb041607551224d6a5cfd6002829c649ba431c063630ec76ecf3b754022bc4a6793f3b34b50aec39310b9cff2a73c92e3a6899dd07af72cbf8e5fd4c62a8334e9a0ceaca8e20c8cda0b0379b90b34735a71bd1a85cc6c177cbdb8a9dde59209d2753f34998672b7ad0a7d03e5cbaf6e9002ab81211bc0d1555d187c5dfa5ba532bbf44e7301d5219473fa698aaeaf4e62f8611e51d4574b30fa3cbc7e9babde67ffa7c9c5e3a3b2d1da3f6e513ecba795e3e845c5bed4f6928b7000ad82879e89e9386bb182d84475fff1ed65140a5bf6798bb19684167cd1d431a7233cff02092429e964f28b9cd3a552c88d822595208e066e4b19e28d31ec173976806e9ee00888626840383ba224b459386842a498c52768516da67f351584df0974804daa3dbf53493f6cb94abe05ba3fa8462c21ee74c73feec4fcc4e8848363b149485a52df8434829082efa1c2600bd5eaea58db02d5329931555a7d61cd3cbfd9176f523f6a4caa748e20813409f749a679f12bc4e8262f9cf25a0b697e16d5a652e39c44b66bc99905e12f2f5dfe2a1223db2bdb92929a28bca8f4ddfa8d6e0af6f7591f0f4417e95c6dbbad13305a9f3ac76648552db3ec22c65b8950e6ad9add4b152523f347b910fb06079c98eff457823b0273a9c7eb41dd42a446e138ceafefa49c6993a011afd14dc4d838de178d360db38775b995cbf6e0985d84801a61d4368b3f7ce54d938bf8f4a03d056f5fc159fec0be370ca3f91b58a08862f1b43e4756977629ec299bba6a6c424a315204751878200d40d59aaedd3675c2a5d563971112a10507d5055808f8217a519fa985b8a389e3a6eb504495649d47442203b4042dcc8b597a3cadcc5c38b633f811614cfaf36c00a5e3b50e716375d076d0a226016d9c7f4bf4012a878b51aa63fda7ca6eef3fa65de9d11b24a090709876893a11edca16e369630c5d31669aaac6a75e3b07a9aae7d1a4ebc6817cdddcbdd07232297ec412017d69772718ee3b5d48dc984c27b59c0b45aeb6853257a6701266ea7d1e0f36d1d071383250eac584b1b8900ce50ab547350153d46e46e16e6fe4bb8dbd9e28a50e816513d097ef926402e5f4ee5ec25b474ba3c3710cc3a2a0cb8aa14bdf3ab4b8e0f7542ebe96f02cb83acd1416de14563ce51e0c6ed28aa7d010d89aae2f38fbec26ec1911df0bcb831b3b348bcdb22799c0e433c10721455ce9adf971086418e7b8cf545da25bb42bd029068c8e18382f37f4e02c77d6911f3106c1d2f4d4e7c97869a73989da34c1a65aed18e3b2dd9a302073971bf1f4fb5c4b91f5d84bfdc0b3ca6971319f482a7c7c7814473a0097ee27325bbfc8e4faac60b6a69d603e5f91b7683b107e1be1e7c7196f3fac07236527415e3bfb680fdb54f8a5be7e881f52548f0add84a9069e75c2b6d1e42b8897d3ce162188ada17fa884bb849504e76904101fb434254c110293f29502798f19b45f5a4591ff3fdf66bf29817bf22691dc9c8c73cc697d007a143935d096a110170b3e1916b11fe31ab99021cd4df5cd88cafcb127621bb8cfc08127d37c2b2668e31e53637a6ec517068f58016ecdcaa4c909838f0e86362c97ddcc01553c4fa8bfa9a4a1239ded5e4d483eb7f8107570be9f74702543cd2b79ac888e991555688b0dd93f07af3e2559bc59c3913955cb4ff5172cbf93cfa7c442410aa3818f8ea6fc4d7a7978466c310155995a58290735e572db6475eed3c24ccd2e9ad1f432020ec90f36cc5c3a729fd8844b492a40a43e4ee3f3fa583dce56a5424bda587112dec749aa069bfffa6a077d62972a42446dc034e808dd6481cabfe210862b71fc5de39e2c3de21123b9ddbc6307b51cf681e6cc230b82527653ad68dc5a5d09d55f8a17720766085dad6dff830285161f71140e3abd433d98980a29aa7617ee057f539be4593059b29d770a19ab07ba375b35fd3bddbfe90272cc52a69ab1b22e80bb899b06b11eab5ee56a45ecb9236abf6a7b0afefdb06cb882b33222c61604ac702c1c0e64df040b23d13d3c8ff4227e9abdbe92a9b07171982162b64d8c3983dfbb5221dd4b5766e424ed0da96baf28e494dc09cc5624d5e8518d2c413a83e2fca64b1fddf00011c407cc1bc2b950aa2f2fbe72dbe17b6726f1ccd903f090d04e20baa978dff5821c7a561cc0badccf6da66bb2d6c8e0b161d2f93d61736e4849e1818e57be3b3de124a8216d103076e238e180195a626d27c41839c87da86adc84670e5d0c3321c42bdd258f8002aa0f8e4298f16d009677c3584f7971d4ae1f28f40eaa7576f31508aeafd2c5afd74e686c9c1d241c99ee6b5d2b79de978407b7306140fb4f44522c5c328bae271fc31519f2efa2f8052892fbc6854e3e40154c092cbc9ee5fb2812e08876c00533b1c7b0e46f6997336de4b499947fb34af16c0270fed447b9a24ed03d438160f3cd58769afdd353177fe723f093992ec514f5e3a4d8cd9647894aa126c8f083dce19ec1420caefbcbce14527a498958b1f68f19f4e6fdf9a9c632c55e64c26cb88328a73fb4338bda042a00520c6f7aec4ff39bd5491960463a3a885024216702fa46cc895c3300b8061cc307fc37d8ed60fa048d9b94610211d8badf380d4cb3dcc259fefd306532627a2a42a2c8cea3cf22a3b6b535ca07a0ce639af211e65fe75f028d3e8b642628d1c79797e9566741900d71676077cb373edf92f08f0c863f2cfc8a6a3edc60baa9588e0eee0d0731fc6d9bd8c198b397a776a85e4b91993cbddda15972d0ab8b0350f438079a4ccfa76a5cf493e116daa6a9cba013749d3db109a7b65a2ce18a90bf1818df25a869ef893f40bbf1c0cf2d18be156b3e69df276a4eb4ae73213a87d9baa20baf19dba9b958c15da84a83f827df2a8a59a1effb9cee57c0ef4a0e1d0c516b4c75105569905d663596313aed57f63cf3220fc3316c9acf13f38e049e1eea07ed2f606a029a7047f9cd640b0f646c58a8b4a3b38b513539c6c8f6a2dd318f3f1e3ea64f0ea8c5347f93bd73877a611025c8fe65939c0459d5168a732e7dca2824e18a54febc419ce4afa5f26ae793107a10e62c3a5ff3308113c9c16cc63b3e3ceb5b1756eaa1407d5d228e4d26e33690cd295974b2568bdfa65877f2787e82e05c633df129b9e9ff2fbd27e0b04efbb63337e8487d7638fff6477761b3206c298fd0ca9b667e32efd3e946e5354f989921fdf3ce8272135da42b3aaad197a8310e9c9c466ea559574131a52fda2bbaa2893862d3b85d6288a786f60f61411efdfec4f9ddf54a11d27319225d27c4d842f48646b164b7040afac3c95930585d493a61c140804d3138be1beb16e846ac54baf978fc0a516b808c69bda81d1c8b445c2e39d8ec44402ce401c23cf401e2a3b32cc296ce64ce89a3df6db8f39f13eeedd9eb3abf24b2a136d1eed608218d1042f6de72ef3e0c740cab0c388f2eee759d4ae549248ce657c518bb35b3c9ee7ee6ca4c49b9992b2333f3644ade342eeb78eebb8b2fcf56e2ba8b1f3baf48a7a3ab79a92b5ddc75ff5e53f2be5f99f7ea5d1ddfbdebf43dc6debc38eb72f4c829eecc4b311edf186fee0d5bb237bdb737f3eeb1d311dfc9609dee6e98f11803565decbf34176544945948f96828b3cefa11904fb67928b377b484a46c739bcbbc75988b09d5a1b80d5562c9605d66168bc5756b75eef1765dd4e97ee978e4ef9db9774693f16e32ef8e6793ddcccccc67666632950a635d0eeff8aa2b55bb1cde6dde5dd575a6eacec03c64b6b9b4e1d1ba0dd769991bdeab61717ec02cb38f39f3e7fbbad8e9c8790dd7e92680f2d051522e3d3611d4844f2e3d76394ac78e2ff66339a4080000b03500000000000c2982b5bfb83d3964ae710068bf347ccfc371adf3e2adc7031b238c7fd724bb17bfab1cde6feee231dfcbdc388eebf426795ae417b90d1bd8078e673ce486e3f8109ddf78919dad391c7765e33b8f3b37eeca065e0de0c6f37bc0f11d1cc40dc7f18c8338c2c70dc7f120747ee37127762d6870e0ae5375f7f1660dcacc3ce4b28cf7e2f6f0d43800708e1a8e3f73c396fcab6ed892b3d3dc1e9971f6090353fcd2f1e3ff63f318cf16b747661b7058e335dcc595195f6d75961456eb8a701c57648619669081c362c9a041838dcd8cc78ec7e63a5d53a554eaba9aadbb1ef95fa783329d92638eb9eb72943e73efce2c41c2241bc9a5c733e149de2a1731c6b85eddb5e9dc1bbfe1e2780dd77b8d2bf3afcc5368fec8dcfbfb1bd7b90f37f07dc081e364a97ec3b7d8753de2ddfe5d5517e3f1caf0798455d01916c92befa57b973eb73b1ea6901d0fa547bcda9173ef31cfe03813b3066bfe1bb3ce2db273c32db293c3842a15b0318a12aae4cd857be9becbb83468d0f84bf7d1380d7cbb4ea552e16fdfe77933f7aeee714ec365eeea9e86e3a03a1ecf9bc1abfb1997815757a787e4996f9391b98ce73d7632325ed6a0c4df1702918374eefedd30cbf8b1935cb7be47cf53a91e3bcf535da58a99ea111fff3a8defea621e36675dc667e0d50e9bb36e73d6b71357e381a120e418a509a22cbb1296569e58f1b079eb2dfca3749baf78b07e94ce7acc72c6675c863264dc9a0fc9aaee864372f7ad737cf7dbe44ad7fb6e8c3759b766fefd5e99ef614b8edfcc37f33893e3ebfeab8ebb986b6e2873cf64d9fc371c9267bcbb413adb5c758374661ddf704896c1d2d123a7f86678a441e3dd0cff6e4ba6f1b025cf40e358c7c31434667836c3639783069ee13368b0e13ec39d477752c1b9136956c962570f6757f3cd72abaffe7dabebf46af58efb66b9effb3edbf1445c246b90bb69f5d54b2f973ee96964d463ce78a9f5aafe3263380e77472bfe8719beab1b7128b3f7cdbb211d9a47556c388fb29d3f4239cb429b43efc7da7fddbbc76883eafb3e1bf9fb8c98a3f3ef53f11bae0a15bfa1e2aa1be3cd0c1200327ff97b773c5f50eeee9c54701aa9916ccc69a468bb67e479d4ad903e99544e979f55bae572f9696566c6f358b0f0a9b93273aabb5cd54f1cf7991b16c9338f1dcf4cc7e3dd90662f66e55dee2b8efb514c4c4cccb79a1bbd19a4baf7d50d8be4d5b7c9d5acce9380fc4940c66ec5f7c51bced0e96fa5558880fc3d765dd7c99b801cdfddefa96fcda9aecc635724c7fbc3cd32780619c3fb77431ad9bbcef42ef7d59dc1b4a841499f3428df23da20b35c711c667905c6a1cd2b1ea3e971c51b29cc601eda9c7a8c39a19753dbb6b56c87d96e7e1df51b54ea8632afb8a18c99472155c1e2862d39c665b83fd8e43eddb6c78e07b58a97592853d961c186d2a7918e8ab66ddb3a100c71c21a45b3284b9f98d3442fb11ae5588f6ee0b8e1a19777021080bb7de7c6c8ca374696ce8d9175c3c5716fdc2ca80809009909cd5ca71b694a5924a1748be632e621183eb43d72e6d1449a2c30738fc121c8ddc3e15598fb27b134d284a26c73174d68926bfe3dd33c9309b1f8cc55dcb04856f1ad85e33a1dbfcca71c6d1b77f9af5b31ab7026548a98f2cc25c41b798e3331b1e15c4296f2f449b7662e4f8bbaa5e2dee5671384908eba15a3342128cb4f2a55b23cd7e9888f7951b9a84e2a79d565c7b322f5e190e6ef31971d0ffd3df5b1b84eebf4bd134a8392c77743ba02e788f87b4ceacea2209d59e069f40206eb20f87d9dcee34e4cc4ab01dcf80def01c77570103ac7f11b701047f8d0398e0771c36f3ceeb49846d3c8c52c9a46b3684299460dca9ab3b8e137dec30db8450f3a18077e8f1cf6c83fe0e41a16352c58b8f8cd63b7838bdb3cfb77db0508de17bfb161bd78ec7860dc17b799b05a9c050e6966f12dded0a68b2bf0761c2fb2133fbc1ac08de3b88f1bc781871cf1ddf071e3388e030f69a4c992bf818bec7c1f0e7be44f763ca9c72faef8e5e2b1dbe17bcdfbf1669f4711af7674fe706c90c5556771c1bbb8ed73fba741f916177cec7822ebb611b7858aba2569ff889ff9fbbeef47bcd09090114321912cb33871f23171c2a4890464fede4343310f830835d8430f5b28472981993fdc23b3387112db4983f2cd446661e244a873282806db47ba153652962c9320e9a06e8511292be925b1adcc9c223b12dfc55bdcd7b0481d67deb88c49b1a871815b605cc302dfc7893b7c84f31b2b1eb19cb2e2dbec78e4950663bec52e85c31e5962e9560c7e68f3f7d0cb371e82f9fb670e8e7fcf374ed60d5fcc577c8bb972c595494c6ccc439994e59506e563aed3386edc2e5b118af9fe25756bc5e5e595cee99d159d8ec6924a83926501292fadfc40d12d7959a55b973885439bfc3de686357c64ecf1d6efdf538f37c4b951c6efc61c5b682e8bcb4ec537169fcc5fea31379439e6db7775c4fc7d9b1c8b1bf3d80920e60f7befbeef3a62feb087c3f89987f3287ec553d78bf16e91bce206b9320b9c152163cc5c75c31a9467ae33b306676664643e8f66cefc992c19432fa6c3d1fbc54253663138b4d6939f3fff7e1ef18f87432f5b99ab7098651f0e6d96b138f43c999b40100747c66629333b1ed5e9575ce6aa8889f1baa5c2a1ccaacb7810c49935e6d16405b9b2eaab6faaeb5d8b0305ab7a6855d7e979e45d76de67f09177ce7b0a875e779d197365fe5d15f72ecc63c703ea2bf08af01966f55dde53753cab2b7f1daf109923fe0175191c16c9a8af767446a9705824abfeddf0f97bbc317edf75e6e71de6d1e3515da73d1cd2ec3de6df278425284926b12281909088ac147df17b188f70f2f77d0f71722caa9165d686def7ddd4e385b9d73324a38eba4e7b3766d5ed991975d9f1c04454eac6065b1e51e741e1acc196eb7413b5fc058759cb5d5aecaf9fc27337b4399c471995b5cc47bef00f36f409942f0c36a48d336a64a3e51048db5952c41e4159ca1043590957f216699db3ce06a794739e25852d92512d5952d84e87b6d11b0ec9d2c69b39bfdd962c270fd81453605a4651f4f2c02a9632a8066526969138b071daec0a5b8c36cc8794524a67cdb09a654a334c02d1c8a0380a66c7b22ca3f49396609b31c618e99c9d83c5cad32cb322bbe9176477db491d1001a4ee146ffa396038d5c8a2144f535884d239a5300528421305a51ca340b940672b509064f9688324400443124880a2841328f18421ecc4c892a61088dcaf4179be3ab135499d81edd7201adbaa03218da6dadddddd33c6ee4635d8ddbd0292a9132fb25f66d8d55863e67491d54fc9e4eecbd9d194b917bacaad619a66b5aa5934f164e2b81507acfcac2f19c7451b229542128c8e04a00945024842519424283902087288832921091a9832450c4c98c205a02954d050606b8e51a6204d39ca6884c9310a109810658a1046f37336bd62e9159be122f9862658c9c92cdf2c573b62c4f48aa577f62401f5426d49bd509160e5279ddd00a09f2d634439cfcd5f456c1b8c2c58f9ee4c061772f743292428ca413af75f3071634abb76c0ca7cd50e58f9964957a44f74e5b04cbbae16d41668a52ab3715401f126e99a39f5331b40dda9580158a85cad62580127936657ab1856604a9aad21b145d993d60bcb32cd6432994ca5d20b28a050dd9cf3a217bde69cf3a217bde6c49d694e596bad4d3f71283829ce8ca6b181ac5372a793b52d2e2f2f28542a0503a3ba542a5555a95a5c381bfb52eb8b28a45aa6ba1713ea04d3303027944db5b878def4bcf6525e0c0c8c4ae5793131dfb75a4d61c50a95caf36262be6fb59291513133f3cffff73e998ea75dd0c0769531df4a4666252323a34266858a994e47e7ec05142ceabf7de5bdf19ab13dd3e598f95674c88b693a9e14d8c6b3a6a6a66b6a640d66c18286a6a6a6450b172e40904517720556e62825043957ac141064c92d93bbb5e2117f451c64660e2877dff3c9fd8cc60e03134c28caddcf7d908926a0648e663bc9471a204282ac763c638f19c33fb0902cd32c2fb1531c0e0112e30dc541b2897b66beae5b233715d283dde4b6c960d35c73352595979452ca1916c9530a114e72d32bcc78e7e5dd700f964be71ea30dabedf2ab1e3945eec13d14902792fb40280e22b1cc7dfbdca5a1c41e730b99b94762c9252da4f8eac1f036459e3e3e447cf2fc0b27b6e7450dec8b1a5820ed937bb0e99335398b364984a20b808008fc40ff0d2ac92de50347729feb8cd21df294f2205f83cc3cdf749e8796d3025bf69ec8d15c26cb1e3b6b356b356b6ffab437951e3b1e6da2e6a433d3ac04c928827226857296655926a7e4ec54cb613faf5da958f11c32affe72f0326f9466f24a1214244e243d913bd9259d4892b40be4ba4d9bd257bc7eae601c759752a9b4852edea2d6efca4cc395400d66420d14b58084254b1be99f46d2495a49502fc9de4292caee2cfc211a81383db033cb9e4925272c32bf1e825289cc0a15cf6ae4189c1c7363700c8b189a989a98ec31df302882c0b0246734c8ac5940eac8b040040494334c763bb06e071a2e03d42d9967078f955e94ceb3e2e6dbeb0caf97312e7f7373195ed4c002093233ce65bc9ee2cc8043191887de7c7b0f9663e050869bedcf1b163227bd2b5e6fe9f2ca34985d022b9ebdc706f370d7e9174958eef52b5efa84e1cd0b7318577599f402e3a62e935e5e5e5c892593490d66331b9246c4a04c0ac51b4aa3ec0029d3db1335999d5eb924de648f9d94d9b116fa791707bfda28285d9cde95a42e28485bb878965bb0f08e2cafb84ecfeba2046625b004d20b71817bb0bce22d5ae643a924675f49a3a43995744ebcc25076b9442863d239339ed59c5d1265ab9cc52858ace4ec724ae7f44e764967c6e5ec598b679757341f1d35174088a02e470b2c64e6159fcf321a1c5a1638f4e6310e0f1e87387166c5a52a642e77bb1937e686366bd75bb57c359f82b9ab89736429ee2b1e3f5a9ee5f996a3f0aae51505799543e697f91617bc6ac13d58e65e4f90ab923c3b1eedf6763f8133f33c6bb3bf18b2f3a18c0e0e53949745a326b269d612b6b984986f3177554add95e603e6283c4475986bd7077d0a0ff14eef42091905232632878ddeb8d3ddcb0514dbd7a147b7eaba52152005fcd02d9aaf2f1c71f9baba9216897e699a761d346b3a38e4b095baeda79b7e92394caf3dcc7bf80483573e52471dc5bd763c6c3f61accb61525defa90bf398abc2be4dae5e2c3361d6b6609f7dca81dde5da75b11153ee3aeda2b9e8ccabcb81a9ae77ed9a324dd3b41ee81130261b326bda36396dc7f62ca439b06b12f730efa94e7f51ddb8839dbe9dece92db72da757da727b3823c7d09cdaaed3ef1cba731dc4ae61d8638751c9d88b1958ec3ab33bcd9a764b3037a5699aa6ddd26d685a942b5672f6aec484128cc8ddb51d25989b3abda8fbf0711d4a170707b6d4e9e8d143cc5178e5831e75141e62a3695ca73030366c742bd2ac7d4bd13458c25d8a763c64ef5e38edead023670af64703b43fc7ac611f0d5ed7c1e5e2d0e0f58de6d0d2a2c35e7bcb29cc8d3bf606e19d7ede20549fdf5a6e77b5a7ee90223ba9c76eb9bcd4727b971bb6a078e8aebd0085891c618fb0f5a9200d28bd845f903aa27bec7674ee30d8e0d56049fb751f3ca50e07e9ac3d769a06ac0dcef52de3ae6b0d43f32f1fde559f07ab604354be7ee82b3943f9409fc22b1f1e2a763dccc7e0950fd590d4552fb27344f7d3e949b61a6e79f71e4c7bcb4bda5d5eba0b0e32730b1632b3761d74e6a6dd86ddb5d3dc59c3749e2e77d376ee5b77bbad89f276d525a2a5a0085b28da3962eb2b3e503a348debf484d5609e7a911d1dba057387702f20820896d82102f301265cd9894d23ec2a59bb4ec35cf9020bec400aa11d9d89ba71a7843d75e34edc416538036271831825edce5100452f14d5212f3c91c3787442ea8295285e30ca61ccd2a74e4ae97574a602b88225b2a24ff61359318302f0025064c5ac43bcd921b2fa54c87d27f47350609f63942b587218a10019d9220d48051bdab0a1c30136abd3ad28edb36c593c43de88432fecf21e5e8e605dfef2ed2691f345b2bde1b37d774ff67293a636cadb752687d360966919ce7ab80ca0e78f34d260287d6cd7286c59b762c419d6d69b74ce392f4a29ed6efc991027b7ea254f19a534d6cac4267b66184ecc8951bbcfee7fc5ee3ffe2ddbf43fd9b6d8ad963debec5a6be51a9c75ce06637d1673329b6bed2c5e57fd55af5ab10b67995e27d8e29c73ceee8e15cc3544703efe316762178d08d6a0239bc726e5917bd249eba4ddb30bdba4349ebc1a22486f04204f1a11ac4187766b228d4c79e47979c5b0c600589d3cc030ac2485bd728cd2852308d185201cc95eb813e5388bf2ba90031e2304715d1002010f94240e05d2a02cc7a164688ec030ecfa801248701c5042051e5002c97565dd22c7284af4809a80522e38214a1750b04929b96085460e178aa0d3085bf581d73234336cdce430429912a954b99293c398e5892cb94fbba1f8416e2c94203716a690851d3cc98215723f071fe47e8f273e68018adc5740920392e47e04a26c410bb9698e5dff091b7da4719162439c7c8536dd0a6942ce66385cbf6eb303bcaeeb3ad773b88e73bdc6d5446cf2f2c63cb7b9c38ebe7cf46c8312ff8897a778c5a37f48bce28121109570c227d7671ad878d07a3ad872d05eba2b8cbb76eeaeb07398e4aea4dbb31b77b80de7907fa891af4b79571277560f4e567de905d94b3df44e86b3171ad84f23f9c413199f18ca4e4ca13ec1822c1f9f40929ff0b9b890e5312792206ba57546cc1402c962e858b0821831aa597d54868a42769128b63a2fbbefaab3cc3d728ace4472bf6f678d02536b79a234d6dc197655ac361d03152fb7137d39415b657bc3b696255a94b05db13cb33773c0c96a19a25e8d491b6d883457772c60bfc7705864932d866b42a1f5c26ac8828d4430c2951c8b48502587efb0794d542cbd4cf3a52ec795279e5d0b0f4ab49401278a28112c0a872e1c59b1dd0eb41fcbe518c5092472c8fdc009a18c8dc1663946712228879c1349ae905497907959c659941486a85ab08265384bf00015baa27060e2a08524956888c6c211ad81105940ca8a10223bd2ac88a459191694342be6d07a9d59ef5c0b4a32ebb672051564f9900687880e146951aee04344c4383c8125661856ba7a956394216ce022428c33c6f9f8897fc4497b62d7e5c939e79c3473ce396966ad95ce39a120d54a75885ab1469d00e02ce3c9b825d82ab10bbb2a16b5d8d2f32647554dccc932abd2d191afc7389d206cdd4884d862b768a457ad2d7f409afb190a17d0810e4e40033198a0bfcdcf994323099ca143db291bf81058f0241645a328c3ccea9032e38010054cdea65b33e3ac70d4449e566890e7dbe6d4042151e4b3d33b7dd9f1b42d326527d93821e4171a897e38146751d3089366ce390395431b2ca8d082242451aa80852856781225e702a0cd8c32ab5c20cf39ab2491270ad560144452e0c1142958c107619821075f4022620a2433c8c0cec4f1f1f1c1c073c8a6d801123a95b073ce6850822db02198e5147e70a6e064c357bd628c317e668a29c690e723bd902b772b467942508e1d5d1cf9e48adb49fddc845c2041660f96eb55e9b34cb7cc0206b40a5ba49142b2bea19039af76f91e2c632f9cd81735b04066909935bcda01247baebf9c5bcff57a7136be5d61585fda34ad1eab3d43f2f5a8d3b567e6eb52883092c3f8841e49968d6e9cf62dbea8828d52446085661cba15a584004aa6f43a748bbe47677846831a96b91e4e83407aea7b62bcc16990be470245c2ac620f4335486d1aa4b51fda54acde15566bad33622dd8b53f4465fa0dcb4ad85d95340ccb304dd3e4f50cc3640f962560bb75619c25450c24489c371432739c7fd1010b24e21e2cc7639fc77090992fbcca72c542668ea72c471aae76643e3e3e3962dae0125b73f2c26a95b4db5157d05960e20828c8ccf1094039468e519cf0842c7f75b783a4b807882cf10b7e54ec64585e180f92caeb959a80e3240e71b2a474ca7bdb95d2d7d739e79cde7561f26a27c8a31ccf3a8a4759c6232ad84a71a4619c93c69b496ba49961b84299ebf55ae34dc5932a60524ae99c3348ad18889683d44c29131327c71969a491abb3ce7adf609c6731f479d5ab567ce1648aeb29a55efc8f967a61af5776ea056cce593feb7f4c2a29957d1643f2726213af76fce0655ae4a22d95567abbd6f82183d2e4d8f990f3e21cbb15c53d349ce1dffc9ac416a30dd8452f3a29a53407cb326cb2e88c94ceda190822e06383d02c29a5320a9bfc1785bdc1a1cc37dfb6d8dfd732ee30ad56ab9b388efb3e190130705824c3f87543991f306f1fc3e290ce3bfbc2a17d8c1b18f7013d5f91cd8df9013d5f51bcf99ec4c0306c0d0c1b03c65dc5b8604c18f6d78df1ebba7ef3633ecb3730e66d8c0b9939060e61fc060b99190656f20535485fb2ec7858edd08ebf250dd24cbd60bf250dd6fc5312146df89ec49b998733af98f98a8fe84b819581510dda15d85066d665e0b81733b0e147943fa2a417512c51ccd2e930e5893fa278438f73657c850d2c9781ec90e132eee23a8d7365c0b1c19b8b74731b1b9b18df62e0150f188f711d301e03c70663bc48bee67c8c1bfa902f19ac0c180132c6cdcd75e6cd5ddde67e8771873448dfe28632b7f88b9a215ba3414a8f1aac39fdd6b2db7457df9306e9817c4fe20d7d0f119fccbac581ad798bcb8725a299e3c30cbdd0e6290389c7097146504a29a5945ef72f4cb0f33ebad5e2f4b3e63e803535c7b1e6f771d6fcd7992eaecc2d369a1be2b0b82198c3ef86debda1fd9db9615d71c39ac34f49a657f10d657a991bf6931c7e5fcc0d239177c388a4baa1f481b9a10c4a851f51289172f87d44a76fd121871e323670e816fea18d328fa9812349723dcd269ab94bf366a373e80e3d0ea5e3cc9c1251b3e8299d354a44333cc13e6601052cd80007449065c90ae8b71f2ea841fa1135484b4499be64445f3aa22f11d1978a32ec82bdc206b69443bac385339c7d4499fe33fa8e3ea2afe8850f8dc6e10af23c6d7bf783037cdca27c68102b61258c45e1838f1e3a481c1a04830d2793c9a45bcd7dbbb68b9e103969c24467163d2172329b34d893c9f653ef9ecc279406fbda9c73762daf23d2dbcd1b2a00e3e6f6ee16c993db5eba59d52e0e741ae58e2787b64103eae0c819d485e0f7884eb6e51b0e69de7862eec9dca264300c2b69736e316655e3b46bc808244982d05b14920695fc1c69b0e72c619396eef5c3228bd57ee6946ecdbf747779ac5184451de6d74f3fb376fe20987a38bbd269c00671e6cf9d327722b933c99d4131777a771a31871a049a4a1aecbf44d19eb7bd4f87b99ee47e777f6a84cfe1240ab3bc1d9d2814a3069be88926e744711c2ae4b245991e4dd774aafd684b1aec87d757490db606d460bf7435245a124d8916d4606b471a4cc28693e8277347ddd28ce4fe247ad29f54a20d31f79c134ab768ccd9e9c11226387842054e60c1ceace20211444185221021053bd30a4d7c604082241ca052829d0268e1064da284a0094b886267ce1d4f46ba082151edd22f2e477d661d4f0aa561d74a2d9737f438abbd05eb91b9054b83d7ccf279c0c6cbd276cc6259ba457dba558d748bfbc98e5ce7384e6251d8982d58cb228b85c10ef7d3afcf6062b93be9561864e6d3bbae0a7578498397d00957234025d8f0072eb78475491f2db1a7f711908d79d523ac49f2f53e6ab012d5a23a549bd4245549b7ba5faf41dd32a152ad253607b1150a991975975faf3c8836f460198543d485ccfcf28229936eb9e0f83a24ade43ad4e0757d125d9f45d7e7d0f5d9e47acbcd4e17c7746d401a4fcb38d4d54443358ab0f2d85037c1809264f99fa20632ea241d64a585927a084b1d4a9a39b1e5cc892d9f64a522211d1dd5a25889f205745464254936c1e4afa12617d0ac4946498a8088e4cf1016a1a4202b40473f46a8a4131579f9646924cbc70b28cbeb08965b54967caf64f9ad4291236e1a797a095bab542a413327b6063473e64fb37ce4717040f0f73c6baf20a02c359f2c97e47036994838a02c8fcc1f23b2a3b021972514f92f60b0f29c1624844d66734e2a7b0a94ee29e96d2872ce196b956d9424528c095ba409abec492bcd686696690dc5680a2683759e77695a495e286b6bfdc64169a39ed247218d8cf4daf04c4cd339b11c0d8b204b1b8a1314b65bd4444343136d887508cb0116020b93a3940cf0a0f40323b4246c4b8e5232700227ec29472919383203cf6699b55936b38513c86436e32c50b36292a0151e4e66240a402b9c1a38336a4031020a1315d6485109be220cc918b18108628e60b4328202af89a1cfc80f11aaa3a1180c5809829912e461208a0952484052618007a8258c603080c4102f46495218502202972849280c7800042d472f194e184060339b7136095894e0e36271322a10713ad2ac98b3236956cc56091f301935b14040d2259d2e9004101785c874011588609b52d44d11543a0210f704128d094d362424c996482ae9a0045813479a0552a0e492629449b1c010403998e0230508721861c80a1139a2fc08a10539980892e2a38222722c618a2c2dc87240c162696eb92ccbac274395dfc400bbfabab0e650323254a11102511765072aa12986b8c9aa188cc106b9bb1b8a4d9679fa10f3751a5b2b1e357b7d5cf1a031b6e28d88acc8243a894f2201b040893699de1fea7ce2f3a0f5b2eb34ebbe94bfae1a4640c958ef73268532cb0980e548644524fda324b22201b02c89ac9824868d524a29a594d258b596b7e07002d995b9bb1dfa19cd4188d6f216bcc25eb36f8aed6ff5b2b3e55b4bcb75f45b5e246b59a665d90dd2f984679031ba6bd24783f240b86f3d1c0ed283e5ed326f38ec1dfa4266865718de517124aa3c8809c10ff70b884090b880066d481c4cc547b3644e0eed23dad02381b0864dce01680eb080032c600a413372321b4eb0612cf241be63951e94436115c3ae08052024b9a3151391143fc861bc2285929a069248721fbb2a074e6143cf53004fadb556f00936a4a1e91c54b3644fe7f99ece14bfd881959f3702f1462a01ac11822157c3c6f6516d738344f28c51de186fe47764652492eb55eb95dd1e0a10c9170e27407798bf502d50028b11b980cea93159f4a62db43103c72602d186fa781a4aa573e89cac59f4110b367b89d3bebd70a617d33993c9f462baab1793e9e5c505e3c1b0969b830eddea1e6e386c39dc1e90467adda25ecf1bec745aa6b39d7dc761b7d793e9ec662faa41ba9ddb4c9dc9dace5e20d6da6316ffe89e65ccdeee3874eb74fa1c74a0a7ed6432e1b08b9da7031ba250ddda4eefc99ca65b1ba5b7e95669466c1067f7c590c5ae173bb0567230d8e26317f16a473c761d11d3d8dd550e31c7eb8839e2fa2259763a7668728a2cbb495d322e3668d360c46162cecf1973ce3967cff5fe85641d6d106267b44188ce94b1af902cf72b15b2daf18a7f64b92fe583f46039622159ee39255024774f908ac106e7cce48a4a4a299d4479d2ccfa64b5a374ee4068967feadb816479c3ab1d250ca473e925cc436208ccbce241b5d8f5f0cc98182c06c3b81486a5b0542ab55da9d495baaeabb73fa0473e3ea01472376d2fddd9a621a5ad67e68d26730fe8919ee63d763d3c2e3037c53cf552eaa77ba5de73faf61e0a702792b70339e1201c7799b7d24bdf52a7eb8adbeaf4d55337e62d9e1ebb2d65c270e93962cefd3acc0db197beba3d5886f9f60dbb42a69099630e7353e76e0fd683e5d333d536b90b03491de33090f8186cc27a80c8272029dc83e513bebefd450d2c573a67c29ccb9c2edf68fde9a2bc7832954e26d4556f51a1502ad45f5e50cff28b0bea9c45c94ed5a95287c142664ee110857bb0ecf2172c6466175b2a6d0f4bb2547a8f0d088652a65b320dca1e9a06b9edf66c3f99bac71b79baa1cd59ee30b7bdf4ea65dc76575c69bbd5041748a9542a699acc3a62ce1a5c4919234da31fe2ac7c6459731b765dd875d18b5ef49a76551c66329b4788a60e7b97cd1c8a573eb8d3391744b021a5382b1fa6eef55af76c296ddfd834764c257c8f98df2e3cb5d2e77b30f9d25be220339770b8e5faad4e297163bfe44eecb0cf89619f189e7d65e5838b4da39eab2b1f9de9dd8becc46e451377e34e87f545832dd268f598b63ddb7049d3b29776681afe91ddc5e55b76439cacb95cc35b368fbaf4db8c6e81e06f6d96956e53ba38546ce9a18d0e1c3c238c545a5eebb9aef1d8f9a078e5033564b2265e4d3c64fee54576b2c9aa9969935b8d398f28fdd25e63e670cdd2e29434a59b5ddae07c0933ae46ae49426d46b7360dcbee75d48d3b98cb0d7fc0c1b9cd8c97b4af4aa52d4a0124839a1455b924d72a99e45a9fe4fad2d60abd05d42ba05b1503b9d66d5a79a459f51ea069d4bbe8c101ae2b52c97e806e69da6d5193a37669977669b4e3d1367c7d3b926e95300470f28febdbebb54bbba10d8ef6a8653768379c91717258242873dcc31e39c3a51be26499b59ef787914ace019a550f6073602395bc71af59e6d262e591d25d6e68432f67b7377c08e64c1e89d9248ffc8093b1efc82312a85bdd2b86facbcb2b96479a467dbd8b97bb427544b0a573dbebc6ca608e2d4a3539e668a83b44e30015110c6187088c0b4c30851dd4bbe3d97e63d328e130cbaed71b993ab5c4162f650824eea8a50c51246508a22c31308104e9c1725fe6186fb267558a086628a05b61b492e7fc0f0ee8960c0114791e87393190432ef3b021647a4d6c36b3cc5a6fc8264d245240004596c9510a088cf2768abf12885e899443da23b39049e32fa744c2caf5db49e66d93d995d755b1796c9b3ce8fb3ae87bc88be498c9ab336b8cf47587d9780a6d52892598308a81141218c921953282244e72394ac97a04537248a58ce04996a7b808182960620c475c72fc01125c809123136350a2e39079840e78a068c84c939dd3e910d390d35b7488d0f0012492b0636fba44a215b61085a01dd35b2e9117a21d8b8fe87eba445244ec98300e4da3bf6d4db4fc25b1b32f6c66d78165b2746de0c0712fc99bb26c52ca1f092c165d8c2e966593f9ecfe909f3ab4e3158fecd875641a0ee5851c7b91dc3dbbdd65c4a530880d1a52d8bbaaa7b9bebb2b1f3eccd885a31c330e0de2a0434a20a40f4d12368823e68368b9bd0947eca3c5e21729b0a1fc09bd9923270e2f71086614176c182f7d6a6489c322f353fe34f8ad84430b044e3dc166df6892b071b2ba1e40b4bc4e0381617740831d46287e40c286b1c88a2644d66101d18698b3ccf3e617c0d08126b2f8e00b4d50d991f7624e4d165c1085941d0ca1842576525058c288139e7c20044eecf0d0440e68b0a404265802113b5202c91f3903917d0e659398a026b965c87d49347ffc303104e429ee98c0b0c51ca911528810924244122944203131408a0786a40801254729423889528448225f394a11c288cc0528534a8dfc9860ee907922337660aeba2b1faab70a06cb2b4d836ef5c626628e248a8d94a9340203021bb6510e108da5ca8421c2c6bc4d1f8b448e51ac58c932171d4922f9c488a8d65a91aee04c37cacdaedea75b61fd3220b860ebb1631f72faa9e5662a683748f35091573bea312c7d1a945d766b14845a3946810296dc46ddea6efa9565195604a429946658d0697c249577adb50675eb6ac91736b978c2862d44b96d481fe6e22338eea58a8f4e31a785228bfe25d5d2423459f42d8fb1856ad49566d1a3b46c0893a6a49094e9a74fb7e6dca1d732a1a1505ee99f2c8b7624530f64724e30d3f7118dd734d2ade94323e9c8ca154a3f7f3aa777e833ec1afaa16f239a09bdaeebfae9568c22052699ce649a8485b9eaa12492c1ac6050742b6c28999e5e2dd442d18698691bbd14d9b07f905238cc70683b09730cab2e8c8962a5a36e3873d842dd44479129f7925462c3270a579a4acb55d7aaba2a60c003a19d4791c2921ca34421490e658e51a460244ba24d0841487d654e23f2488314b4911dc8a19c02d6eb9247ba555b6e3abd34d2ad96d3cb9f6ed9d3b56fa69bdd140ec9406858bbf46990b65cbb2d3fb5f4514b9006690b6e237b7b0a141b4aa04c2550f71f44329a4d78fb11a473f62a33767fd41cb575323d763c4ea65f1a100dd2eb576759bdb14120563cba05e4ee51fa642b9c190de278a18d3a27120dd1aed2499de508a55060928d523587d3a7ee84f327d3635745924fe8aa860dcd474ec954e3400e25954cb51f49645403c98ad151056288f4a934f7257204f7abe3293dee6c573e9145128a34da326ebbecb8cf8e87cd1c9645a52b89e493243ba55bd745afb0ab64ba812b0a2d9cc003576ee0e4270c3b7509222758200831084306bcb0531f637d164bb4c59055d7c5912320d170824f61c336eac1019345bfea41f5be0a0f491dd921a2a2073baa37cd103b44a40ca6b0d327326347f5d8f5a080c9a21fb2aa573deeac7a88f97c0c1e12b790022b0ced106924a61051c48eea130f2152820210a610851d153e02bb87874c131479a1c9ce10227d22b109507081949dc6475cd769f9446a57429139ac76e8d02095443290c4221a4620897af868d0060c5615a45b15af7c68903ee60334127d5ba1ef233a5f862094b4d3d76917979e410a5bac618da0143d2172228da0143de19ca066602f269896d4adce39710848da11957aad8a66a573625eaf5da92eb95ecbd2ad2885033fb9bee45332525ffa69eca253e46e1b9b06ab4ca61ccce90f34a04d0c2258fa9006db3458b92946a69b4cd75f2c614fdc9406c32b49339a399c9366d50b5f4d5a5e4f8fdd9392066be9dcd5a459f515875966ade71dbcaea45c9b3458eb53536c7831c9f59452ad4abca91a5283f5e53495a28749a94eb1c3a8522ff7013d1a957853b376146fb429301826f5eba1069352c1dc950a86c2dc6a02d5cb0b4c2aa43030982362d22dcce51b8e95503392a7d350ae34444e661326b90e2d6910ca131b0dd68ad360a562bdc78e076649b79afb3215ac6634851aac9f46f45c82e792066bc839c1d9b6ebc270fdf52f8824991ebb5710487252c670180450a6475d67c6a06ed18aaf250dd65ff80a6af04ad25db84683b573cc45dd900ae57aef8617e5b06042b9bee5869ce98632f974c33994ebe7922b89926e69afbf82ae25dd2a3d7b3d0df8e3fac464e7eb9a4c97c974994ce74e4de73800944b4ffd0a22610e834321de7bb00c73154e83301cbd30b4e3a1f4d4378ceb4e0777d3e9351d15041ba2509eccbb75c2ae140ccc5b85dd0bc334f51ca8bfdca26e68ff1262426676394eb7b80629b546f4267ae1ac3e877a9cfa1af5a5ab1db536e56a460dd6b35660431c27b91ea75b339c742b3c21c111714f8cb429da51b72e4c4af9d3508c14b61c5ca633b01de3157ce63ba849b79e583902254f2a450340c8612fc9b387343094c376926736caf395c63e328128e5b2c49dc436b1b1c119914662c992932449526ff692f950a321996e282966d4c0e260c34683335e7ce0053bafd3b373dbe09c86cb6a60c3d3d8e0681ac8f3366a6402074484408a1e1c710128458a78c2101640220461400210a5494c1c3ac10669124626ed393f73981184dea26a34382f4aeb2f2cf3ae13c954dad0c418b2b3da99813c2f536badd56405300c31032d0055c1c80e2d020e9c24d18223357882ca0ea5f471027548d824b745066c91267ce193e9af5c1ba55ce7d888a759a956ee3afd31c18614090464f28f79ee1b55d2ad9658c32e291575ab5b92bef4844a0132ca510a10510e4b394a013a924b4f3ac7c81131324e5f9a19f71a54cf21f32b3684198109614a821a64810d4b3f51d8f0236a9229d6a45946305043cce95504758be6f42a96a810ead6fd0aabf21d750b9f7a9e858939d893c8a287f9d5ed90af15af78c8908183cc1c53639ec30eef2f3e3b9e1738ec9171efb4eb91483e3e3e5906fe96c45cb00936fc8cc8b8f7fa987f9311f342c65dbdf064c8b8d504de9501c4f3bc4b4faaea63645cc8cc3270a8ba0abfa086977e660e256a167d9659eb792ffd645ac2aa64fad3176c48899e647a1659eca9490e4b44ac1dfaee48b73050b72e926ea992744a54aa7b5ef530456a909e1e3548dffd74abcef01a455818b7301e66d9c27868b385f1d0cbb6e63162c488f18f68d6a8818303827f871fd10adfdcdcfcc6c6c6c6e6f562491aa4ac16ac16ac875966bd45e865196478b90c29542a43a58e3ad62463493025ddfa4e8f05614bbac5e2f49810660436d4ad99531a704e4f8b649cae4e4fe9e951b7644e4fa974ebc55d4e4fab742be6f4d44ab7569cbe868bef455def769506b76f1ad772b78de399f9e6e2c5757a8b8991b192616f5155c6558f9d4e579587735df61e0ccf7a55e64aafe46dfe98fbfc7617b7911adc2eb76bb7a16870fbcceda406b7eda806b76fc7b9b4c1ed322ed7e0b65de67a0d6e7f71651adcee72dfe0f6984bd3e0f615176c70bb6e5863c695c9e147147e59323d0db73659f9d4a34c2fc30d5741999e75c38a25af88323d78c32b49a6b7b9e10a29d32699fee686323e99bee686d751a68f714399a04c0f43862883392c11adb0d7cfdb6d930675ab052f11a24674ab3b3d1da24ca893d93f844166b63fc5e86c0fe3d79d57f7794fb744b2e9b1d3e918b7479e82cc6cba89e6d2d5c1d4e11c388e520a234610434130c9d3de1e22154986711be3f6c86c0fe3da4d07196b73f0d9b26ce1416fc088ee96bfb88c8bf39afbe22e6ecc47827af468b05b540619677dfa348bcae4f91c7afcc0ead0e3c2c1e88736caf33670a862e7431b3a387c466464be615cdc899f114aba157e4d3e27dd5271faaf49b764ee0c5cc933394ac90012f269de36ee5322d3875d8e9f51a6df0f228bfa5414e42845035632cde14784a45b619cf215752ba44872928fa85b518a0684724b7e5032fd76cd3927eb2175c921cd252ec619e33168f88c83378c3fc860d6ed30efe21f936eb938fd37d42d23ba35bf23ad8737683ca491e74d9e3579aac833d5e5f91a73668dcfd36843ce270e8d348833c5ce879f914c7ff077a4c68d0dc6c0618ce7dc186fc0631d0fdf924f23f0e05b38ac019e060e71c09f7008822fe1f0e04d20485fea72cc70f0dbc671b2d361732b3b1d37bf3eeff51837a439c661dc506618353d58b63536c60dd219c675e60c183766179786196ef843fc418671f0373787cd2d789b4a833587716b3eafcdb5b8a168b0a66b5ef3979a979a979ac7ae795026841a42fd23aa39575373164737f28a2c50aa7f52ed936bde354f3d76cd91b29aae99d7c8ab6955cd55355e8d57e3d5dc036340107ccc3f23dfcf916ec55894e7d7f1302969b2853caf797d53e20dbdf06764f319a828a844cc36b54dcd32856844000100008314003028140c874462b158309e69d2543e14800d91a248704a1989a32488610819438c210018002300200003341306051442324d2529f5a03d4141d6bfd085c24feb17205815f2f86d88b218d8a7f87d6eeaa810bb0b1cf62256b06f8e7534a14f9651345c80221daba6628bae4d2f4c7e177d161227903856dc0a6e8fb6c724ea61f9e45ed960380ee090734fd2761ba4cb08049ac8167c2fa9e85eebc52e0b8fdc1f42d6e666a4d578f6b045c259292ba4afd95a860ba4962c49a9386a11ab059fe0e1a386d8441bb20995dbb219c4c58444998caea7bf8ff5f4f1d6266ee152e68280b42d10085483e70b99cefc4863ba1fa04bb67e6faff2e9542feb242b9031d8040a0a0cac5771d37fa44641db6e35791d8ea1b750da77ee5a1fdb6ffb1071d45b4dc5e0c0a5ae390aad21be9f82bcefd726b298ce9bcacbec478b4630f63312ea68d0eeea914e0ae743b571a788cc6c4d329a2fbd955ef7ce26a1098d0903a95bcf0b78ae82998d0aefaeece040cdc5eeb1d0979db9f831bfb47cb0b82bec77101c5c117d4e1818a8611d640f44b1db59b09522da5b61d128f15417ca33a7a622f0a58cfebf8688d202550eee0e7c05325b7395bf2bababa87a5a755ddf51e5f43904e738e12252ec9236980fd4131afe635e6e2f8b0cb07c3ea5b409bb3d4cccf3cb4b50c09e9e40db524da6018f0fe36bec5c2c6e96cc23ae3f06d661fa1b581716f14d7db95d40092f90bae277759789cad0b7c61b5c4effff3c5fe8e6190fc606cdf4821e727145c41c727201a872bada08e42ae7df22786d3ff0117bbe0197068f1ed71009d02d85eae0cb75ce53e50a3f02b29e6a176e54a7dc82d89c40fa1bb66a01f481ade033847e70b2c7d6ec18b14a1fcec61d062a9e81ab4e9afcc16b695dbd7518acc0ffedffccd77b5ab466592761b8984749299fd38e1c5d57ea7086d846765f2b8cf785fbce061b9f212b879874b66ff11ccec484f019362a0cf0eb21eb8488cdff5af8cc8a2cc3c0cf1f9e59bfc8cbf5ebfea59bb37cc22a10519e142b269fe917d1a3a302cdbb353568866a29d73dcc46e42059b2dc99ab4b54dfa5ad483d4df98472baa2dc094956605801701ebfa6a87e8cd0f75b298ce4b0a6823104ab27da3b866573f41759444a10d073db9e3492443245b9710f9986f63623f9e4a43b1b29966de2160f848448004ab95bf7abc6261215bb6f63b4fcaca52887132b09ab4d7161751b38425d54a044b8c6e484d527b6f1bc48807c0737740b981ae48c974e780214c267e6c301440a1d0a54dbdb839c28ffdfa7d6965060450c4bccd1e16ecd4396143c5ccc8981b2ed78b3b059b4de3bbf6151f608f3e072378604fcf137db8c92134c880a4af91d17afef3b46654d1c5deebbf7f79c8058743a29f112101c5fd756c55c1f1198a8d1483579c9c118b59310b16d387f0f2b8f2715b0b1ba99d1f0374d44f9331e52cdf155dcfa7ec08064eb544b4ef65d8b03037230c1f1184e3a56c0c1909983bbfbe24619afd8e0d796bb521d80ac70aab170de6dc245b95e8135e2aa2d0f5c83e08c2104413cc844a5ce2a1112c9883251c1b24b4f692bdd88809519f194d74a15b7a88146b02c83a63e38e78fad02e26779a1973da7a2925001c6026229db7f793d14b13039e49500d9b0f2681bc22951444be28520c93bfa668d9d39b081e8cb5e3edf7d7d488331953d40f059158095581542c3ebc940f4fbe56c5183016e1eaedc83fcf0aa752e44179e3051827de2c5268f8319f430b85a5f495a87c797e52c87ef8936d14cbd259e41575cff905b9f2b1d1c336382ff0c701bd06cd309de0edd243187ad0c12759e327f8c92b1d840b5726caf13e24e174dc15f140d8893cca7dc3dc5977154bd128d25066b2ad5d12993047e195bb6fc34ae6125d9b878529c7a49e137641745d4c34a66f11309d9bed703e348c777619cc2716ba73eb43152c24d82b8f613e6ea450e6fcbaedf27ba3e9d6ab05ad6772786e5620b981aae3c8f20a0a091a78892da34f5a2868bea3a4139a74dc17846c048ed067968c470641c482be8313eda016fbbd92f273c21ac3a1c8fdbc1e2db5fcb0403d6bfed45f57a561ac687eb92d4be748ce4745572b2b775257f49691d840e0378091118f60bfb8ac398902fcf6129ab453dd725655559d55cb7c426e4f76eb41f41e718bdebc89664ba2a68e778ae9d280c7f12f375e1bdbfee0f8cbe5b2573cf98f6d886bf3b823d5741e52800f495b86f16b021ababf39e58b245e1a71ecd937e9fd5cc7ec59f3f6b33b38c31636c15a7ddbd27f40cc960a7a0954441616f52e2449d3c663e64080e560d54b2d6cc76c7c081363977e84fb977059573d661f4c01a8168f73e2793728b63d81c637941bdde0603aa1d1083039223d71cf3820c49e294712463feecf5233dc3c8433cb0a5b7dfa4b5e58dc7b753c267256e6260660383bae545f5bf77a470fa8ed589be5c1fe4a7cfc0c3c962925be1ba79e46a59989f15978e4bb04604096081e51f3c4caacd98f368adbb7e02cccc736d65d5b08abca2288d8b0901b98cfd400056f193d28c35068ccbfd17644137727453e4842015914b4132f6812d21b25108168928fe0c4e9c830ded22db6bf43ff9758ede9fff3f28928d658256d9bd864eced434bbd77a35fe76e6562b67836f9f16df6bbb881dc55eeb9f06d1129c1d98ae1d5054e9e436e6e4566b51f12d5e86fa051a6db7bf98ce859d042d39083c31afe807b8ec4c429887541f5ad329a9c29dac059d06e3e673986c47001da3574da40cb6ae618994eedff8217cea5b7313778b709c54d4281daed036fa04ec48a7914b3cdee0658e5f3809b28bf433c0e1584003df4e46143e21c21f1352d0119976755a026ff4b7ba1c1be2c9693a14a13063cee3b3f30979fa05082d12de61424242e5c94ae3acabd67c1c6708e40ccc0604e1cbe372584d3d56e469c26d27945d05eb3ee617e88b31c05d1b47b7c84caa8a687de0a54f9a6e5dc3000358f506ea2e9571cf0141ace6d44c627b03245aa3d68445520b3b99ebbc7666bce7bd6b48d4f34c6bf3c5483dbe76d4d16b5b64500ff809355a5720d2b189378b21e32fe9fe511d7b6e29ce57882786956d4292e8cd79d54a54a3f78b6b291ff68b1c617d6040244626220b60a54df3e9b74c70a734ea7fe8c5917ef34afbd0687dbd3dcc5c514d798c4d2e5e9e611b0ffe6d2cc621bc244fe5d2c0f240a153cb1a5cd12940b6a5dd5ff91e4329b4a18552645ae83a9782a815c5ca69c9ac2868e74c6534386e916b3135aaf1dd453b25fa0cf7a9c4fb0d2f067fee8c24186b9e5e34b157a3fd4f64cbfc44fc5a305c9c120a14f189e46c7098b68c54ab08e9aef7f3ae39c689628a4c4217bca2b400914845c116e4107f9c6cd008903b695b62f8a5e2351eddf92c7718bd95481b40688cb8d20be12ee6ff008431d52ef3b3d4e627aa2b44296412be98889c3d6ceae9be866c54d500ce3be628977a88b1b0b553a56bc521cb0dbba8b866aff2a954224f4270222e631ebc3535f440b0f8d48b61ab3cad14fd5f2f745e3514d9b8212b9187bfd239a4986878af75d33e22a87a2e45944f7d08814da294eb74c9e940660564cd987c3678f20fc5260a8c0784720c91425364ca5f8978b9e59be3a7c3a2f6b319a778580c97a330e4c7eb92987e9ceedc92c892611bd0984fb8074a8ad32ab7b1781d2c50698c9eeefbd505274ab2fa98de0ab7c77c92e56ca84ded12f88770bc3b485603a76ddf11a5585e55f5f6bbf1bd4749165ca9af03a8de4413e6121827aa9c02e14cdb245b8bb2d2c1a6792fdd5a6bd1815635b3e7b8c11df46ab230814e98f4486895b192a4ac4c67ed31901a11e34a0f1acd88022e04274bcd8039f711265e469bdf6920abc8641a83504aff20124709b1a9b91b9a71edb10648c433181159c808ccc8e3db81311b69ad5bc3bbb9d5fb766f56b4a3de663536bd32dd05264cb84947ac017df3764bd942c9a5980e5eeb4c19601b98f1a19d4e200442c2c43e09912316a326e2985c956314660e925263a874057828532ffecae2399a06c328b02529a9e3cd86dc70755adc8e5c0c94ff385f3d62d7496f1d7f6ee19350082d88f4ae64f69e15d1572d5038276430e5531e4ca274fb8d64164fdf0638ac2e3b2228e70624f1474dd5b1ea046a5f604892744e5b5c81c222be5abee25d206487f4b5c86d26f2401bee494189e7ea5ca5c1a69cda0401606db481e62829e6d7ea6fcb1810391bb3b64564fbb6b47cfe36bbf327da2d78309fff4ecaec67abb99516142c825b9672d93229bf8a42660f6b029631fdb23aaf0e688d00145822074424adb40a5802e5fa95f3daebaf609a656838a56686c66d2df317331b4dd2c2496d75a5a79ed49c12ccff0e50b95b9382a89c9cd8d791c74cc115a967f4a252294daefdfd8fbf22deb57ab1fc609bbe307e9731a338bf595dbb9ce00420798f30fb277c463adb968b69941c07ddafa179edec3dc3740ebe9576a46a2b9c6262e5cd8548292dc66b9ea1f92f3d82195ccef3ca78002c3bc878fc6724cd0011724a1cb9035bee7c878badfdf235b7a6b68db832b201c36082c78457d2c3d7c4804ee5bc50d1029bc9313c0149d85cb685849ab3513fa2d98c861fe9c1fb290053add6e44efa002b31e2602faa5aec44b53f916fd9fb6aeb2fa9f199368b681ce3874666ad2bf1ee5007c1aef4a4d7af34c7d246d3555b9937cdf4207eff95ffa9a537e1b1daf557f2cf354a0e487cbee9c651ec5080459f2a2908496ac6b2779b83d65c9d49cd814c2df54040c72cdc9398d1e981dc2fc6a1de6956bf3353637befa80f5a56f48d7add5bb54ab6343a691c5e52f9490ad78a42b4330303ce6492848b42a4418c6e4ac4a10bad2d61c5af11369b482d6d305a541e6df8deb82ff2b6fc95fc7cf86b73c87103eca27df1b145db7aeef917b13a0c1e9b3bcf9be4577613fda3a96992e74de45a415bd5aecdfc38f836bbf975fa1bc49a01482bfa4b7bf78fdc056b094d6575d3f6d608fc51af88be5dc24a123377d5a6ad71fb71cc055819581db2ab37702b8008de6711a13e13a37a843ff5e14bbbb213deeeae090191c2e179198e65b03075041474f14f73ff3b939185019a28de657f40f2a2df9d5f1d918dd077ef865117513f07c37a220c5d9441ba008b51237b868ec0351b49078219b2222d452eeaf1697b6ef46232667592ed5255441e137e719dfcf32cd0d107cadf49948ebec58473290d163db267fa6d8ae19ba334751edcfdf62a96c9447bbd371edb15f7df5567b6eb0ad3e6093408d30b7a42293aa9a8588e3b7f6841be5603e324f298177cb1d9872d5b4dd9abf38d5004ffab4a45d0004ab11502125a97065f7aabec7ca8d2686197770370d459297bf28b53d4ecfe4a7d0b049f3ab5553b9c0798d7c4d21476b166aefb22337fc75393391f009b1078f415f0d7d85acd9c1ac8a0042f8a0b4b79cab3313d6f95babf684173c5314422b4adfb17607b044373d9397c0e4f178f0389578f3c3b1782a840ca5de7d2e5f05b6a245c4c80766cf4a9eecf332cc3adb8e3560a1d33cad477edc60ef27a58c1eb6d02bb0c43dce7b700c2af48be4915e481b3ad61b42add8af9cf1c46fa8325829d112050d6dbb61e0804688a9938072db33c15014edbb9f14788d1c9277cc0811c28c90d0687b77fe90c65044e823d0406d0e72bbb6a8fe04d5a1be4779d443c1e7cc6df0cbeaaae75162c12a2ea7a1c53a192c83f8c5217c631f51d5d25afe05f3206d36fb139eac943a29554468ac6dce920b03d27e69a3f0c07f7fd68faf669c5c1abc522421e29946511ac7763571666ef2305732045658ad4fcca0337b3745890a8c66a3feacb399414776883e48f7024f3f98b04055666df5e25ab68f8799603f2f9d8448b70073ee942b1901da82a1cca2f203461aa40fe6227b2ed4463f885009e4ef90758fa70e8a2a430078630039e6185553b8c509ea8c13150e9a08e586c4c30b24c60a43db32378dd9915eead39034100c0d1b15e7986110ce3d96aaf2f1761e257f490a9d65073be79ee72b5f678a40f980435d557a8614846c2924d47268084452eef28e76984fe72572f36f46f118fce5d5affba092952c563206f1b921c9f0b93ee68cdc73943914d6c408c3d01791c02e4137c1a00e586d63f28c434e526525c21a175c1bcd295301429d3e7ab7571f83c37a86c792010a1050f6084f00e07c1f31eaf3de435a47cad19bf8f89210949b3d01f57e3bdf9370f03d47bc1057574168ad043e727e9cc9c36bd7672a8d931d4ec2c06f84f7a5d90fce59f3c641a3d28e351534afefb74b2b24b31619534677784ee9bab47cf31e28cc538c6ec434ebabf3718f9776346ddf50dbbb31c1801adc872111f9ad1c58cb20f4a03b5066a95cd132487a132f49086f1a7f61e2ed9099809e30b77a1d84d6295a9b5ebef13a5b6f67e651e5f006b14612c3760d82af3e4903c821d42e340d9e8b751869885c598a82e03b1edc0bbfdf027e9ae074fb5b53e560747c3d6221bed4e07b4ace374bf2643cd0c15b50ec7a1785d22d6a442137b8be17e2ec5969c210bd6b76fb2ebb490f3c4ba21789cd2a58ef6ded3d808826806e05bf44ef7167093f07ca361bcd090184cf01ea964bac1222ff956d2a071544692259d2200ba8c37d74be9825c061c2f40c0f7016d85a3cdf41ecc46df249708921388aa76dc4ad673486aabb5f98a3fa94648902650cfa0805b3cb56eace43464adc299e49f311704b3842680885710244b39188a467480c69d2ec85075d449128ac7b2a8470dffe13580689be15a81be067aeb140d77765f506458ea23980d79c4e1263ba59954bb42735965f223944b8ddb0d01933bd97e41ab6336ba012d75cbbab16d07497d4aeb2c1924d42880c906e74a3540ee5f4df74acf60011a3160f74799064eac6ea7d9e6b086ef96f33a50975904d2824ec90bf7115d4fda1d7b2186ccbf35103ef4b5156f796712f0b1eea9197d1c23aea7477839b24b4df434e04462ecd4701faf2e1162ece7b4e096715543f27e66c2d09293e465d3062cb0d703696e55ef240e68c5165be38c874bbef8777d7c7080961d9ff6eef19d23d1399c58aeb412761aa72a6b357d8aa915e2b68dff9ffe5b0c9a6edffecd3097f15d35632f2881970116415debb464c6aa4663d5bff3fcc42d89e5feb8ce1268911b46322198e1a92e946141c646141d882d0e7d01fa48b07087fac86c9725c3f37cfd3cf93beba502c432d6d2a48b3070cc79bf5e3385bc0d5c49e9d96764990e112f256ebc4ec41f83ddd919bc1e494b164ee600e371971418c1791d81e071dd84d60bf80f2b0d52c990ddb4e52218f408a3a551257efa6c80632674612b643d2d2ec3215901c06e38bbb0092215aa1f02f84704900b5714cc54982f4a4a5c58016e2429a5cbc47727460e25434aeb24872f43fbcf1804181fe4616fd5ba8c7c6cf006d11ad28e2f4f0d43930cd8c95629933000386a64ba78baab6d5e37bbe79e1e872c414e0ae62327447430dc9c69a2505474a5c4105833ae35cddf3f48bc9e9598974f1ea2a4a7d79f2b0a344739dffafb3dd055cc929dad6f77ed567c0bfe629177519414df031935990f68d8c114202d6fc4ddc089cbc293ea2e77f13224a300adb6d1a6a719a0af81e192edac2b5a7ae0d49d0082cfc7db4daf688d35ec4cfe82bdc2065267ec46ee6aa554e3d9479aeee4d7e14ee837143835186adec45b21c1dc67313b69cb593ce101ef8f4ee5844fc180187dc6d6e3804348f46cc05bdc010e91dc3996ef62a96f5ab29d14ab1faf66f7478446bddccfb7f8314aca3498e3f42455cd2a2548011554895dcc67c585d33d7e6abf6a5958e94324a2f51762567c8174feec5f086534754b8c8e052f217f0eafb91354e62280e9c8ee68709cfd5b4eab54642e18ad4ef3214668df318a717aba74f79ca6c124dcda35d1902e52aa06f75aacf6544a4bb025d2768ee6f13f0423565383f480769da6da34dc6e0d49f85224e48fe44bbaf12d2693e86d3836676521ae98bb82e1a390a375f9a0b67765a120ec2fa5104675950aa516b86355bb60fc2e2ca7024f1f761462790d0426d391c3eb54263e4ba2abac71cf881a16414636ee4cf065c8db2b74e41a12faea783063d8a6315635be7bcaef91dcb8ffb9ba1066f30b4b99e38e25c1e93ef2f0a31a012d70d845c1c476fd9a8e2cb2c0155d2252c7e8317490719086997218c318f2cbc93144ca6fe562e0a80c60fcc9542433ca92d0490c300f0aca5ae0123c2c5e54c912d8065d7a29b0575be79a88db48661bc21559014f8d4fb7afe5c36bb700b7ffed900099c05ef433b1d2bc59520ac227feb31a5b1b94ac68abd59c8ee6b3c396a4ae4dbdd1a8d505b0d81216d90832b1c9f06d490e8931bbce4aeadb0ee3dc55f35ac3258bd4873b4db3185ce94b1e6be166373f9f9609c111f9282d7bc34f2118c67087fef11a4c057db783ad70d8071d8b6a1400bcf84d92f78ea3686ce9b89a47f84452e19a92d24be2efaf70fffcb7f3ff98c96276acc6738f5452e1b2572214be7366722338117d8c7e4ebda5660e68c94f25d751b893dc11c128570db2fb0c2538773e7328b23258bf1bbea35c48acb2aea1892fad2d7f965c08bbd1bf5403996bfc45cac5700b1514d2a07616753f80ac751b018462e77604d2fbede8cd692ada860ff8046ef4660255a5b0ddfccab48d6056110a264aef6afb1b20c66cd8492f5c64d9a414dcce7212a67ed3932a45b07b0c0428bd718e5b12bdbecc2c58f42d8b8e80fcfb02ebd8ef01e14bd0353d1c724c04d1de49eaed2c30cd466529b427ee0d60ab4b9e9bfa83ff4176c1ec8bee55390dd23e9991a8607b159cc4eb3909f2bb6bcd4811d1cfd6413f91e2a714416b4544ffa28f2984ceba456e51c188342421d9b2918bc3d9b8236141c70922f6c8fd93bb7befe3e68f70a2d2e6fdddabbefffd434c553941333b9078ec1a46f4c0aec2fea547ff2016d66483fbdf0f280cc92e20d2c58ee8861e3acb674193f98af162aab28d7d64c91aa57286e07bcab666c449378957aa4be7ab351cf3aedfa527d2ff3afff7831696ef46a158933ab6a31208717129c9b428a7a8b991586bb399cfbbbcd30146fe9102e09aeaa85afad8e719bb7836c970513854028377216ef8fd3da54114457842d779d7007eb60fe2389e87811bbdf3a459c2be52e922123adff4aad6f6c183da2bc280c2dc020ae186414600b9c1721861aae1abe2dae14cd8b662cc6e38345c3d08ae5d26e0e182a79b556c6446fb451fc2aa3d018390a79606651f05c88015c027631119da87d25cd8a7501964ee4d8f822535f4718f8ee5ba224ca74c5073dd796b970df9e7a6419a1cd0ac8a4d0e5ff9ead7064775e2611174cd792eac626bfac01d04c9bf09c3cf32cf6578a4980f50675c244840fa192183018732785df09e51d5027e77dae6c5b8ce1d87a19e05e400ecb537fd2d99f16b3d8209d29aacc85342c6b87b49bc78f059d23d7cea8df64869fd56ff94483ca0bcb3690ab9f03dfba151cdd931f4d025f4cb4c75b69e153bc4a04964da3244eae6b55d061e360bfd325330d428a7fb7d42f48830c59426a2ee701f272e372acc59b37f612bbdf0efc76d642d2b6d9c38a8f4ae13fed5f4169bfdae1313955ee3b9ec67e4c94ecd27d50b97331fcf0b5ea965154ca727c946682a211711f26939f4759800da59a5fac6e8c83f1c44d4d2688983f857a0b1f10512a60e3476ee2e81ab3f7d0c7d9638af79f077fc00aba966c074634ee0ae48e596c1293b1c12d8c9b95594672a553e44c1448e0c21bff1faa90f33fb6f951da96913a39c54d292129664f3dc8cfbaa36ab013fc534466c3ad2ec581b01f7f62581a991ed2bf198c0cdcc67190a1d4dc2446ee272901541d8712c23f760a102762b19d19847f79b9a49abd3a1068eb1171c132d6c3d30eecb83c1e99cb8cf989e576161bafae44f89ee4b61dc8a1456248dc29c395118a045d5239dbb0d1a885f1259154fdc20e96a016305f697cee40103854035179b1a14fdc7c28d55a5630bc7a636d6e8beb1e3eee001cbe020691b1b8ed99875d51a53c056634de439e4622d2027acb3ff60db00e2cbe286258c78853547be5063011df575bd62a8218cfab92848bbf83a52f619caa18c299f468c6c078b474ff02a435591bc54c26fe8e9d91151c304ec69d2c2c0af270edd533fe507ccfa52d7ab385f1731dcb5b42668b861ab3accafc7499c6266b5cbb7f88219d83de0681628e26ba2ca4b9a03ce28efadf7973e5ac8d0ad4e96e2d1a81700e0e46279eb730274986db55d3bc4a4e76a6cdbbc69b0405567270c80047326e1ffd3ffa9f59c3de7e7e5de0f0f79dfdaeb622b727d82baa3299bdd861233ea113977336363808ebda5e39cf475049f6177c0e08f1efccfab85951e4e9283acccf1f1940991cf7e39b885a3957480a9bd01ce33695ae5ae381a4a8661e754b8c8a3e84e465b16f3a007e966193eb8981128f4267554dc7bb8ed17bffd8cb745f115e623d002985c007568af4562bbb5f52e27f47e9ce990600e0ef8026995fc01c54f533d7e3db317d4f9dec83aa20da6d2700298bdc5c5bc4d34d0b44809d143df053496dafce0101b964ac99feed07600dcab099d49e4fe345e73cc1f293bc456cf69e80ac804f22b2e3fe428bc9cf48aa651569722a50a8ee5821dc51418661378a29dc8cab95cdf8c44cdb5a41e0bed9fd9a396b37e0f4d20ffa820d72a04e2401ff642369d6303a009c966a2f9348e0b1a5fbbe5369843af82282556183a96f07c9ecbb81a6cc42f5aa79742dac030b0004fc75f1fe1ac2c48b2f14d839d57e174fd5f892faffe90b8b4e3d3d192dc8d86a8e2ae29100f6e53466dbb971fb21e084b69dd28c7aa4c6d23c79278ca0df80958800094c534cccd45817b95012b81a5216ad821c825dfd0b89bf1ff090a01a8f9b5c09a1daae620bfa858f3ef441dbb9fad2ea8c381fa9f68552110f491833063f69db4d7e7f7f24bb69e407b21a354edbe4ce0dbba939570f380f8515852552c9ebe959511c98ec6d97a6c664cda46052f505deba4039a55f03b53d23d4ce81338024d2cca916164c39f3d9cc52288eb9bba4f8c931b9832e9d37a8f6875368679c6a62d2d713f44af0dc2294b17e5d1254ea99e0800ed6771007daaeef169015366ffabb9bfb3197d19e2e4b2cf561a471207e81d1264c1517325be5435f390fbd22d4e9ac9519868c2c9347534a3ec433118d704746866014cb09f3bbaaba976afb8f7174bed405f5734d81d773ef1baabc1e6267c2802d7e92e3b3c016d6ba4bbddd9c48a4a23c5f54e2640570dea6ef22752e59ae2b69389d5158d74d79d4f802e35a839d96902511f9b70d95016df4b2ec6ceb91b4c0a81175ff524bd4dd1654e8805fc940371ddeea7b94d2fdb718b37a23c7d1e7b4bb5814edd35f2ce3b3b615534ba5c767802a2ad9176bff38995358dc6612713a61b0dbd738727a28b1a9d9b9d2642f43518d73b4eb4ee35a6baedccc449030d6f2dbf8b1c896f6271af001098708394f71288800b3709382f81084cb871037d30096e78fec95dbb390004a2d12219790108fe2b7a521d19c491212a1c4226e6059463ad4b0d96c5d9114d408702a2a1f087db8b250477a77a8291f824a001af6cffd2fa5719984ae2c4e7617c8ef7c74d39f24369c2fcc10c7005c8ab92e7716d15bf5471eb38fc0ddfeef777c35f2e59f399377677c71247a87586e009a566ad1a530bea8d462aae20c474f89282e01f3e9a59023276484495f983cf8f487dbd26010245b6fad0832eb6c299a222ca8efdc4211dd913d5aebd1f2caa2254c0a0dbb6581c506895833269756ed542d9b105666f4ac77a243d26f90a5b28c993cb15b702f048f35db95112a41b057782ad53bcc77f25e8bc699a4ef17ee6ae39e81825f8f5374a017a737546954c93604ca6b9674865f2136379e4321c1ca09ec080623b67f7219b77b1bddd31490031acd0c93c07d4bde86d4a5af3fd299d84c49e34db09d0902b30575fabacfb20e8cd142c511104e7969cc2201ae4f3b6c9ebcc549e23f4b5d00801bfb4d2a22c74141c13219a3bdb5246663c331b268ab6109579124aeab7dbf7ab8dad204517778e9082cb29a6d246fe951a4fb2090d3d2656f01bb5a21c64b6e74b75397b39b6124ad1bb2e1fe60700990c20665eeadef11f9fe18a8680183c8a4e4cb621f808d7f7bda68e8ee52601bc4445b8897a22baab32eb6c0200004b43f361863139f3f5a2c0460085f8220899ef4c19d82aa85dedf27c5653b5ab394000e6142cc406b3f2793b803f9dbb5dde00260c247252a5e18b7ea6b33c1340d6a33cce748a98130c1e10cc15af1b9a16ce664b2ab46c3bd745560d91a9233378acbc2e82b548e5e2f11fe103d382d4c2b568fe1cd20b9c8fffa06a6abf85d6ad98053c66bf9c3c956311087a1336407de85bce77e9bbc26e8643a4c65b72f4327ae438fa483045b22bdebacf3780b2ccf2d40763808b883a5817c1d625d90effc0383cc206d5331d3684df8c67708cfad403ae6f170195bb86e4509c2e336595aefe713c0a9391bbdbf3c6ebd670c70e3dcc2fbdc1a9e507bc083873d584efecbdd91bb3ee6a603e572255d9d657eb78f10848c1b2ca39c923c7f179c309a92e3e1fc8c3bdcc1e1ccb6bd9614a2f4014b48270008719aeb754b8ba8c4fd50c77751ddc2a80d8b7a8852132cc71339e87544fe4605e86b8912c13f7cb772298fef9815bf38f1596a3c50c9bf4da0cc6e06efa1735d165a3a14d1f10588f717ce9230cfe1161bdcaad9fe7668251800b3dd575e9380ee1c2cb1212090ceeccb51fd5ea9af1218918705a92e09cca6a47a6d89454492067e411607f5463402a7856a3df6af0d34695d681b9ef3f6a16961f6453270273997221e98f8e97d1c8a44942800b7e4108f76c6834246d19b0f2af7d4c0e0c4bd85b148c3f9b21f51dc5a19842bc5c79e38cf9283937616063a0bc5d925c12846ac4b2740ff762619c5388ed8a4b69b20998fdd83449531c7d95b0e4df5f34240d178c258909cd23fb2895e9f3013705aacc8014fa441086e197860705ea90a8ef6a587cc8f5828107480f766be0eed0d40a600fbbd02b8e041cf6b5858a4ac00c1cdee971383921d01308c762431556deec2ab437bc8cb10b95ce0e7a76967004f213d79f6cfa186cd277eda1cc3b961022ec82c15454c1bcc5d0d56b545da8492dc045f4f38ac620fcf0f79671974f49c2c9717fe4cc11f736f6229641fa2d0536d3014f82747e10d227a1c07ebb56b87ea1638d35150243333263bc2f74f19e127926f2b149f1c73808cf6fb62ae82b1511cd6e35c4f144f98cbd777b14eace01368048d5b36e83d245ee44270c8218bb143cb004031d9aadf6a0fc060c63aca5ad3477a8cad9da3580488af1634deeb8b137bf11a4c351432a37327e08ebd1b5719bd19539fbed201ea029b304418f4b1b71f0b2f779ee8cf5663c16361f98e7e92941d2dfc3b185eb74f12427ee8229ff427b6288f6049f76962289237ec8fe00ac55dd214b5c0ab353b9a484f743a298008492da90b008bcd2fddffd90c7f320ee9ac531273b2ee76438ecf349061404f98c353f837995887e12706c42e11dcc4596dbdf997249038527a4038cd230693cc700c215d39e847fc13d0530d10dc6e56b4b21ca3e920229c651f2b30347fdf9733c948fddacdefb268dd262dae275204dce7bae537a097b6b97e86fceaa0349b577cb3013d27697c692051ae09d9056401f5651003a77f0ee6e55de4e67dd2dce33df4e7858ed27ec08fd9963e7a06bb59b30a31866738bd7380371a5ef966eebad42e118c5311b8469dd97a20ce31a62dcbc2f85dd0bb3c065e19ac6b0f08fa13df7a0c3aaac64eaa5e721cb2951b3e20233e33b92ed0b9edb90caaf0b3eab43093c9976cfd9f17bcd0e0625124eee0b1fea577a610e8a5455d41be91c4cd52a7d52fb8f08e4003611522bc9ffec50e9214eaaff8fb0cb7e79a8bf8ac1e79d9e3edc8f480d57105ada8e50071fdbefc2b137270d1ce0d17f33e09338db73dca8839215365eeb7103f0139c3ae6688043de478de22e468020f96921f376c66dcc0ff53c35a627072853758761d274418384b438d8fd9e544fa9935172b40e6b22c4b0f1be05eb269dea79ac488be65ed9547b21d97b55c9dddd26dbcce7dbe4aa08863b74e6974b1802a954fddbd1f1f31f595140d233e952a4ca4db22f2fa255d17f6c41bf3a2851857bb1e3c3beec798026a5e24bec1454ca538f7adfcc0855738edf3a03e579840d8419df83bc4aa53961c604e453289e309dbea0952073beb191638fcf7a73b16c0130b002933e77c20c4d77f8e02e6bc656a36128ffc79a774723701b00fb4ba211f8678bec8ee495cf3f01926606163de01a02342f98ebdf3bef0a2663d3df3ff41af7fbf6f0229f5feea40c8957f9b0033b0a849fc8658c99c9264a14d43b81191cff2f81f6d0b38780438a6e2e3fa048a1009659b619ba2ba04ea23a647bf8a68aeb9c868807e1c3b68be58828c74bfb76d65c4df94727e465dcb75d844781969d7d804edc8a26e3b94cd7ff507f52ba3b155caff81e8a57462d5a6b35e9b1927ba1fec716d6281168e055ea19631d9ddabbee4e7ec9b350e1860882b3b2c75ccb74aa34883c2a255330553e65c3135496e0f305649b3b3ccded8907f95734bd6d1d19a28a02b3cb9f6162f1147ba3802623a2fcdbef11020eb2b33bc0e2529a2178f9ad1852f9999b457b9864a11cd2040893337092647536b926032599aaad978c18b407a14f8af2b8a2bfa09796bf92bfc84bd6998e230130139da2ce27d248bd65dec2520d7987f68f9cf12bbcd6b178a36fd712cee178247b2271216faabc932283234bf22fe7714fa96e807140df5280c3d2422812b63ce758c2c57fe014beac059d9a69bc59ea3f79f101d44eee9f7200f870dc9575aeb1994367d3b1a9cfefa46318cfae897e5a7f681b370e0b2752c47d5ac62fea96d31e49ed371414e59249c86baef0f0ab2bb6bf78b7aece22d26a55c869e22cc88ef966b0bdca418bcd262d22af5ea19fdd81bda200f6005a3c2d6192c6e6ec4e2b51843639ff5fcc66e5726228caaa6662b0a00360b121b8f3f9f6131e8b350e879d1bd88efea14f78dcf9f94992f9b42b7200e20427128f3e2e4c313214c62250a4588877ae2dd8ecc1a9f3e7970d02807fae7b48cb7325cfe6ce15b8a13651ce9246d823893de86d9f6fe8f3d66dbba876090e61df35052bdcb8165e5e01a23921affdb95f833ef76e1593585ff14d30168fa0ec26be48b1b8169cf74be2d0e638435fb75ab2a8fb9a01429c252cd29edaa9eff01a7bf92a85ee3b35cc45d8200cdc895c1d67d51abf197f9b629820deda5e3d6a85436639ff7c69b9a83d0e37b455e8afe95486efb456a3162e076eb575732369667e293ab8db37a59abe186a1ac0899c8a61ff7093ecbe15503b0f359bf99f0f06598521fb808b14a277a1e418235744148c8919a6f49b5ea815582958080d3a8be58dc4d73718a380586dfbe52a01bec9e303094aa90b1f42e4363de5d3037bdc2e374db2e3ae6672bae7606ba420687556263937cc250bc9e2350cfdef426d022a3d9fb8bbe431370852dd2a05e3152c6b23825c2db10ca2aa3e17e7eeb1cc965607fdbce9c0d5047392bd8fc430ccea47ea422d3e1824ade0d4408487544513e4a64c16a30a7d22ddf7602d99e830bc9c1df223d28cfdc3fe11e43e9d4d5043db58693b447be4bcb2fa86fd081029e4ac03cf433d29994148a34dbbbe30f5a9836bd945907686e466f41f416a8d60ae7b9b2c5549ee147045a27f1743a1ca770900a8624fbacbf69b8217c01eac04cc8e2a7ee250d874be5bb34cb99aa80e84dae046ab5db8311332b87a64f3f49aeffcf1db53d007772b29fd251c45206b700138d0f8abf7c1e784887a09374ac80d821a829efe5e6198b78ea3df1aac62fbf7918cf597b99e97a3dfb0555376b76806ee2ee8e59dc295957c05b72de3abe036ede9d9799e4d47833c6b9daeeb5e09e867b4fe6c8d4144d228a2673ab317263a8292e0479f02179152cf31f58854ca0ee1c4a9dab4744f07079217d5486e5b108c5cf40d340de47754bc646dcd1c762bbd84425d171d58e92483134f7649dd749c202595e3efc6e8b2574b34ff12a6f2a9204f6e7f4dd0c2781d74051f7b3badab8526858e344ba074f970b3dc1474e3c82d7f4a7eecfce0935b459307b59ed4860a575dedfd8906e07845ce43e49ab454b2d9d2cf52cdc3189f1e301aec90a841322f7b671dcc7d52a55d138033a5bc06796940df12fd316a8700676906e27dd28ab9d558211e9448ffe4a099cd97c44fd49ab176a0d170077c4fdb0091b2f1e7c5491b48ef4a731c0808825edf1cd46c74a86f48d5c428e48a7c82adeb37143f431d8c6d335ee3d71c2c88b9c52dd240e96f94b700f302847b4d2728e209f2366a4afb494bac16d2a64a8fb64ad44d390cdb9e380d3366217852c8849c931ef4de8e581b0577ff2e2c9d651d37b242f0d65937f6c03317a56b356a75fc681c618b0007fc624176d61a3c5845c272399d76d6d6b82c11990e78f3cfe2a66906465601e67f32e177f542b85ca2c8f80562467eab17b43f90ee1b87c0b977b0695680272c487ed272c548bcaed58caa5c1589db6dc08fa5cc96694d541af6dd91cf6f0235bc79eb7eb0e9912e4e2acabba8a54b9f1792940af21dfb636dd8b107bfd441b4f9cd2e6b9b50bb1467b5edc565d4f0c1200a40bbf4765301693c4a5a3e2c23fde6984be1336e3c2ebf9f91adb38520deb89998a00c851e2e6f82a28c8bb30d0558b940dffbae29159cfb3503fae021af0ef6f3007dee02dabcc229b6e080d24572325850488bb2db15126cbe8cebdd1c64e78be3dcbb7896915da5a2ce9e622561d33c810a5da0df9c541be9b5fc180f07efd2be91f0cf1d7a0334eb658ba92ce85b9a9a78d9e179121019ed66aa43ad14d49da3fe8a27714a9a1d65c84245272d275dab5cf9e66cace5d9e1c3bf568d120e0d876caa813a9c1f86cefcf2ecb2d30d930435040e1dcb525dd2b3faee1a838a1770eb13103c4bea1685a926a21bbe9efc1be640c7f8c3537fd87d312a9663e8be4fca1535d6895e7ef857f5923b48e0c52680c932f033f7c77e2f418cd61dd535392c3ff236734ca26c6d957d9e8a5129a1424eed061bef446c0858635b26a06d862a821489d78a972b628fe348aa38548b00d2794ce7fe69f3900439e1f80bbd45342ed23769d77c7685b56408e37f46b739a8610d746df9f40e1d09eb3501efd4548dbbd7a22dbff38beaf0091394c3c3f5de4c30c3c1b1863d219b055d1aa6459d94a05dfdbecfd33952d2ae3e5b3b3f2feb22e1d9aacd626c10c0c1278acd8a1a7abe7903414b2ce648a251352322e29cbd9c185ccaa90e422b57c46455efd8964db7ca0be000cd7f703dd2de37c00cfac9db3e72c33227b6f628d2595ba56c71704f07d1e5e7b2281b0c76a072723c2c933ac27fc700478231ac3454f4d8ae0f580e01c72165a9284daf0c907e40170443c45b2c518921e3c736cdf4800ec390967553abf9f105bdaf5f6ab48c298f63e77d06edf26e6d768af04473cb37f8d28a1aa7a511683bdb059867280bac063f288f011efdec39e453246dcca27590043484f87d161566f43ce9c1ec12521d46b63b027c14c4ef6dde139130cd1c2c6d08d228319c40235569e7c53525b086982626ba8fb50ce30e9b022f3ea4a133c1207cb397f4dfe660dc53ef4658e6467938eb02a6fa7ba65331cbf7668f0177d62510027d668e25b4154c078b99b565d6f21d94248c1177216d6fff8833529fda106b0f275041164eefe1a7f9d88125ca6506908f4832adde7382561548118f8304d0f510ff2a9b676653f540f49587b8b5a0b641bebf876a36124d247d30253c2598440013844f2582aa12c871b595d8004300d5e5cb3d461bd9408b8910d5c22815f4f5a12593f2fa2179fee57ae43f616ccff3e619754dfa32d734fce9cc301a083f9c0a81edc050a9bb5fbc9b59399275603b2f2aabe114b2a76feba2bd6f7b8cc89554fac89fcaf88e85e96f618fdd9c138833cf908e57cf90964325c761fd3fef8fa131195a9e27895585ab1e13e6906b2af28dc4bffe5160f883d3091fd8b924119ee0708a5b852f8586b19377a3296853079e7f84754bf03552fb9549363bdd055533f0383e635b113cf95a238813d82c1ec886fc422c973b5666c2b950acb3381dafd8af4f6f62649035314149b01be5b3694bdb2439fbe6c0845ed4b61b47873c7133253d1f447a9ebf1a762c18b0c16f7c7b2f4ba1caf653a49e9c181dda0c2804496df2784bb39020b2372cf0445b60ab7488d6c62880f34121b5e682330d7cf50dbd78244f8f3837706911ee7291225b00f875908a1fa43478e943f198354da73c1f477f69c264ba2860026a980c693fc617e424481acd443d1f935d57b15b7b78f7f70262f450ea75febb85b1e0343cac564cebe3c8245998da5a1f4751f5600dbbaf438ae8ef44c3a62dc71255c2bff0a9206301f9524e4a9037ce3ff6e3e9acbf4fe248bef13ded14a57417ae857101bcb7ceda00301312ed2a1c40b25deb25adaf9c982c1ca043ce2e669beb3e2c40fe91e01d75c3ab6e2aacf782b1935d71e7b5c3d54e7b93b477c50d7eeee1f58f4c2338b24fb894ce4faa653b3bb0aa68d3b34e78844f85df13cef7238b9317eb97a61fa1f617306109450d834a974ec640222f923cb01f3fc2ad00da6e7575ca04677756d32e6f5fc2969dabce614c76b6c0c6657e0b4d3ae2ebcfa33c17a0a0bc7ed7dd865e8c1e53d787006559f1d5b6db263fd9454fe2f05c10e34ab8ae7ddc6fc5fb6b7c4c333c31be7a6da80bb8827d119854daadfd068f6b452963e487935e6ecd58d040286225e8b0be93a7cf386bef4f80a743957354be1e748829ed8d60a677e36ee5e87334dca6a11c3fc79e0139613d53a74f9307be1bfc911fe8637bec4ca70721258df23a9c7f9e0995336360ed46fa90809e5b3541d67c22759eb2f108c5cc96b934fb8fa9c62421c4a2068673a22bead43f1c3b8055547d220e2c113f8ae997417418773e9468ce33d93a0cf1e18273e9e12fa0fec57ad1018d9b20fa91cba29f050990dfc73e2637e4b0dd566af37356dbf37368d0fcbfe931e3de0046656e0de3a057da7d0d4789444a2844437269f299788abcd803a028a71caf3f37b9c7b90572fbf8664e9b5a5569eaf946ecf37995099ac63107303adebe88f99753c07444d748870b5d62bf0d5986b878634d73297aff9b3fc58f11623c3899cfaef155f8ac37efbbd9fecb95687bb9bd9cf5ec99498291d5444594782a59c88804d3f6171b3589f7b6aed6faa999b4cfef651a086016a7f13039306cf835b97515a878702fcd709c2521e10cb2683be57545e9e96338eefd50f5604466bde092d88a0a9c40d712c10d05b42b7803e1b940a4623b15531e10c3a89804ce62bb058a42a4f52fa146f7fba890fc770772dedb20123dd57c506b40c3da31314808d0eed7ab286fb8a794dfe8eb27237b0006c711dd28231b5b2dc3d3e2e37814ca176e1daad93bdba6b8f56b3ac9837a3b999f141568dbbb7284855ec5a0767ac37cbbd8009cac93167a82e11c560a5ebb8ea7000924dcd1a3c12c1c4cd6e4b257303030525db66918c34ec60603ca07ace2938ec5d21c66e19b91ff158271096fcaeeda426f055d8e4c47c5e3a0b7a69dd1c81b7fa1af2dda0ca444415d96163312cda1cb2d9e30c912852937bab603166a28f000beceac39a5ec3776166979fce19cc20a2c323ad038856ff5293bba9297486a4f8ef619f78626074068b0ae92d83f050c620d9f134619088278d0beab6652f94b674480c23327c77378409aa083086f246ac69e87e1b26e393a1a5cc2d0e50db2eb79a9955c653ddea8cc5791318f4f719f724053b9360c59359ac4809ad174a2385f56fd8979cb11c4d3f9222d09e7b62fb84cedfdcb10b640adff2584543cbd9186db9925f583a0e3e4156eb482563dd6274cea553f3162a6a107c4c5ba77b4e0f8574e997e051bbc9499882d01ffd191ac4e8e00fa5cdc66e9881ce45ae85706aba25cedfbbd467caec7f6cd445c5d0243473f61ba33a759a57a9f8d44fb28a5412046c8d663c89f6e57455b6d51bb1a32b49a469898a3b0f6a64b19b9373372eeb5b9ba31e03f6e6dd0ea7c1c74bb0572f003773799d7aad470180595d9352d468cd1bacb54d8eec094532a84d7abffc4844b40f95e01de65f20ad6cde53072419dfa403c16d8038c4bfc40c8deb74c2b8c23be9801e2f59d373b5ed0c12167c8168694e7d7c8471388ca746710e485e213e7200417b74d30656c9d4715b9745ed29b5816543f4a3847b735e4c2adc1a0560a695f2bac1d1a75f42064597949221aad09b516e10ed1326cefb9a33e591ab5f618926f91c3cf03014be5250b81bee3425d57409ceb6d3f8787471383c5bfa375b78f0a964eeb94c6e1c01cce5945f6699b5f7298f015abe516e83ff7dd3f5817d5124095938520f6f6790704090e038832e5e78307622d6317afe1a588604b6a6f14f00bf37ebbc2f562852239672b06754c988bed2fe5f4d38fd9ffd9154cd590e554c77756035d94b6828de6081096c06040b120187461b90b0bcc9084e331b088a939ac93b518f73537b033eb9a238a0c74c0c621d9ff0e427661861e664cb060208d81777e0643a53a2d4a23924698cd473c53fc1c8124a0c32f99e0e852f59f33a184732cf93fab0e1926dbbcf4688552c56c58372c3ce9e01d68f4c0734c05f862b5212147de08964f1c58733fde2e1af78e529c6ddb94e7459b7813d16f93ebb2c41baee86d9ffda597995822f5f1ac338b4e814e391138ef9c9361a6d93f70d2e78ce22234a49a20e60a149ffe86d8bf07111595f8b300036cc28ff782f88218e373773d5c0a73f3b626cd1ca6513fcdaba4d6cd71633ba318266a2004e4ce8e6fa2557fa6530b51b7cd4c5d569e63262b8a4c7697593179883f78ea3afaff98c42c7d0c52dbc7e4a9091e6cd74b893a56f13606caacd644b6b5796d2ef91a170fb283e656838f2d18ff8ad5aeeecba709d5b6e5fc19abc6e32ab3870fe0a85a8ce0445ac6b3aa76287790765665e1c2b2bc4d6da7c0f6c74464f12a82a8256f2cb3487c80c78e999d139b26630991821c7f518c66ba0200248a7c72dc86c0861540ffb4e31f4a31b800779ec2d7f7e1ef035f7e808ad4b9401ba6cd540025fb4f9fa50bd337364771b40ae883ed739285d9e0cba86685d9075d4dfbb4b1509d9853b76012c472192cb6e63fe702efa3a12aaa9c00adfc7c2c054eaad50c5262b6b96ac5a979a30d7f74be29430f755525dceb25a6cf47b345ed1b89c6a414675263a59bc8ebe0878674c5cf720d72f5663381c365649b8910724203986fc7ef7027d92bb923580583b3fb9294c8778fe3ea7b6dfc7da576c2ff6f9efaf476c6b7ff3bec27ae0b0d182f8f4f53b3b3a857da0f293772179f1415f1edb5e24ef126695380a9c91fb6cb0ca12c988411390e0777bb6bc8668a75635c435c83414413c886d549d6494f9e2782f89d1373ee3a87a8c44dbcdb8639f987e7080fe2660fe0b3a560b26e4d9e75bf1856361889142201b568bceb788df81dd8dac8608055a4e0336b89b77cf2778e9da6aea985ea99d8065a7904e889d50789f50e0097aba0bc6a33eed76773179b9fbdcb6e711ea48c906741d0cc2df2745b780b927a86319f2c9a7282d35c2d828b82e0e5030c5bff7f4a00a5c06fbda0c63019d0c87100b1eb8258eab93c5272de9e19efae0aba610dd6e6c22a59cbe3f96a4917a02ff9ed0f4cc3fc2c5d5a9b3040efc9b5fb0eb956cbb196cda53f3546276f2451f01650f6b979f1a966fbfed5937efd15c1d5ef103243eb2f4ed929c0f9216c334e73daef536e83f80a977f0368aed3e01a51a9ed0de8bff9aa3d211158cd93613fda59ac148f30ecbd65bd42a085ee4356688adf8889a4bfa0b8e30f31e0dd7ccc11336dabdf6ef4b0cc1f0b7d975f594655a282e3ca098ec8a82584a8a6046d2a0880c54a300ee8c900e18343e6e95e8877800c8373cf44daf9c979342f70026984521a405001d52f7de61461857240ebecb5cc6e47715d45df200638d520c4951e0b36c88c91de5a96253475ee45b099b4b4584a22450c6c7161630cbee6f19bd4cd9afc38d1c423fdd556eb5634a26899fd991140a2bc893a44350bfc7011965ab02e71511e3d2896d14a779e84dd5d6829b3eab9d6f1c900bc234a88bd3c4069a12ee72ec66e749c9e2e6a60df76d0001e107bbece2c63b13aa138ef0d2506ef2021f39a68cb1af35bf4279bd3c8a9ffcb629fe6921f77fd07e5eafb8f1ee6392bcdc64b957a5cb4d0ca04491dc1b63f4f14e0dd8d63b1f46afca0646d2b818411463f8be991c3574ac048d3aa363b07767bfb230a3b380ac91c0878da489cea6f3a73a5da57358d1f64c5acc47863d0201cedacaaa298e3221360b6f9191b6dde3888733a0b07b35c57be1053b16529eef755512c18ad30b16351fda17432ebee6536d8933b21e2003a1e74a9cf067208e4da6b15901fb9429f17016a13b9d4f638a76dc8cd6c7cd6ac676786f880c210e4b67d9a063c2ebb0e0efe6a3217d1f3eab6492cc798286ba0f6c761785edc45bc6862e0f912def1beb18a6e0cd539759e784e8be20fee2607990aed3f546624af0a29e12aa4befe6887f1c1db0455d36e140a141c91213d3865a302e0952b97ffe342043cf01d52cd1ea230d16c409cc2bbdf1a5758822b8ee9a5b4c3215517008989349889568b54bffb54a0ee929563ac6b35f30823c73ef77860039de054d1d20e40f72894590e04b6733848b82365044f91dd0d923131f3f2b447e2af58dc308312ddcebfa9ab03ad26826d810138726e064e428fd87503262116d5d49db3209e0243b721473f9756df94502c7ed9c6363d3000b3f209459f31901da7538b8bcc4431963c193b636689fd8e9f4186303affbad642a6d8c58f9c8f41f2b772fb312966713b335e9e12f042fc951c2d7ec8c3781876e781251472ddef134a41c0e260bbe827f2b4d54f968872ee60b6c7b2c2673603791bf95c155b007871a205b83cb33936fbe54a313fb6776863bb66f78ea4bb2a518ca3c1c88a1cf8b0860dfca14d939d1982bc954d7d8a7e82000099184ce5d48a56be36bc3abc1f28f2face1fadd364fcfeb378da49c034f58e838ebfe7229075303ef9fcdbef890dacb9f3ee7371003e0f5cdbc3822f2b1b6a23f225236cb392494805f67ba79006a3c3680bda2a4c1d74ff6cf159e06429438e0702fe98242f041ec2e9c79b02bb3b6930f04a4da525db860fa26feac44e4f9a488b8e306a8643b1bb45d0a6295b5aa6ab85a809bd9d2c1dddea990b377e2226ab45477e8af830f4b368a1df356ef5a50ba0fa79c99e48c46df343b4c89d0d36c347808f79f017e0e0f87201b00b39aa060e85d778d8671607ab9ded3d0fe2601a9bd3076fdee2882934570bf2725d90993f13a7b7a4ced83c5c8909f8d9c43e2cc7bb7111654b4fbd12ea5d4c1b2296344f5a82c0481095c7fc0c6d15070c8d11ce76540243acafd524f4d47c91d0d6b8e5406777a4cc844350e51f01aaf7bd5e144d2520951fc99c7c6a5f87bbc03a7dd6f088c8ab7d2d9ae2334a709eb86c49e3ac1b9401f6ca434e13a0dc036721bde22b13f09dd050d6f0b2d74c4d043811e6390182ca090b8037ec3b0cc0ea313af5956e405f109dbcee3fbbb717bbdb87a569e07dc7cc9b65fd5a2a9ed37c18e65af5f0bce7d704f797e823cf1056eee162aa0f1f09da08aa227c996103bbec61c9a4d2043410a6a1e350766d58b4ddc8f086a464e936cb92eb40677f5055e6dfd56233c18efd16be52d5c5e00ad56358e8c09fa7c4ec54fd6351236655cadce96b2880b9e613d6e7a8f6af15aaaa23fdacb30d2a59fbabb642d4f81154350f9cf202b249dfcdf7226f39df72922a70a91db2089b691f10be00377b1938fe69b2e5adba632e573dea8af0600caa6929bc519806bb9b084036ec1741de742f3e6b90416d90e09af23941eecd6bba66c30ca93674b1496cb60a6b4d69aa2b9ff878c2c924f36340a0c119bf75c775ce4c703a0708dc4ed75ab60d9cfb37e1abab89cac4e129df590889829fd2f79466cafb26dcb6875cb0815a6a5a0df625a6b08b6b5085eb891a77e9a93d6c9b116f891ea40b3ff1fbb8b94e0cf95ebe259967fb5ef3092b37b012589ece19cee303411bbf5eedd35b1f46d081a28be77b9a5e9a536f3161931c1fa7bce744cbff34764c296e828959c065c7616cfd1854d2e2fd2ecd98f9ee6b38a5f78605cc2ab94f754cd8f356b49a9a814782750c2c2f7e3657cbf49af5f9c68cf70378c916ddce3b38ecadf144c8bdc7855a75fee791601f770df157530cf1861bc7ef3f13c247a4c28063e48a859df10b2c00aa0e2234b4003a26a772f3dc9faa001eca026cdaf51f30a7ed392ffdd35d5237a1704844bf731c3a0f0ba44406fc6eeb792df4649ca01884610a91ce2d6ac09b7abd65a025e88924ccad86d3b9c26ff37dc14fb7c8d4ef3222dc582a84a50743d2b3a6a3cfb8a77b253d8492e64199b93f732599848a14d48d341bc66678d4307ebc68fade0438dde9344e259850db8cf65b6cf554efeb5108e87e0b4b910fe8822c47be4039573d2e60f5c4a1e691f08c0d9b2a2f59f3b007df12bf6386eed65bc5c1391b076c5856e5e04292cd3374e06320beb19cb6147405edebdbb129db08c4a41969f34c807c9c40ce5b39f446b842d015fd1307429e1c9ba3d3f829cf60a1160fed866560c09cf33eea83764111290299f0c7a2f3a71a79fc335f421ddb8e1f7b8efb7e45abb6aee533190c6a69c69e81395481ae43c3978c8a1f14c14c1e67c8fef7105f3d0c7e4568933a76613dfaf6dafe0c04f5f11c8a212174766e7888f86e22d8564a2850faf99b781f18fd4da409ed4a2b428e1f5024f59c969ccda821f7bb03922b6ee5cda87d6b8143bf438fcdbd73a1f784cac27f07cc695bfd4a4e495b247117ca6a7c5425664a09afe5aa6d77566df5d991f4b2536bbeae9635d8c154aca0f4fb6231831fc203ecb5c60c96185ae694bfd0db30f077c7b29888cfb3facd451985c813b6550380d800bdc568fd9f2e5b5c4bb7b4e4bee831008665a42fac5d009f6952a85892990c1699f45a53569937792faa3e175c45dfb42cfb89a9e166f43d0bf4dc9f95c6d430592b6611abe6ca1e5db6538cf659cea6d94d39fc131bfd2bdc3d8ea93f08f17a34e0391b73893df6d991e52eaa2ee738d5d94760720d81087534d4b4930f24457bde192dbf048cc7df4babceeb14e826d83daf117ffb06583eefa1e11c0b90eeb583d89502b66ea06e110ff10a15920820ff2b2feaafbbe8b2b757b732c8734c27368cee3135fb10690cba96d4ee15dc718c108b06051fb218f860e81dbd50e2f00b10ac7a37becbccab92d6b63e74d85bdfba8b93dc8f301c8777c9e7122fd77a1c940bf2fd9e69f079a68b4518dd9ec452240e032f4d8e5536b7bad8bd92e83e86db268a983a3e67ddc202b11513753fe5a6fe2ded651faa5a4d943eef99aba91a75c5d34911b592ba9a8ba6fd338455770dc8a431178c186615786e0e825815750dcfb9767a499f0fcb8ac3899f90b7114b7bfec8325e5a130beba009388108daad020a56851849f2811adb35c26811b92ca019228edda996748865fca1273880029d449c4d7695f9b5a979dd55a26e96f5d1e1b93638003ab86f066e2b1b9992e0f7d611fe66fb08a30f6e9fe43d6410ae730a08c4471e0b44a4788aa1f31f0cb2a7eddd3bf9764a16854683c0ee8192b8100ad18155268089dca576474f403d1462b7a14bf750794c84b507b76670cc7d890cfd98d61edc8671147fb1239a8880c2a49e42ed8f970965a17db8d0d3d4477fab538444820870817b7220493d1cad0595122c886b4bf604ac4834639e71d4d2af5fa35288010efd620ef0606ac5900525094ea157e2d4e0ac7511fe41febc50fe68dce738b8614333863a035c71152b06707b7dfaa8478f32d8013e24bb875ed32e7d306865da8fabe4bee9f6552ab65a5a2b032cee5c6eb1300961ab5424b4ce7dcddd7ea6962b813490a5c867c3d056f642d06c0682244ced72fb53a4593190e0da6e4a8872cade285da70a8dff0c85b9288246b9ef60e76a834fdd4db27979a941ce898aeb601b8e1bb635c81d6df9c6a2110c581a5ecc3d5da2aa7fde9dcc9dd49cd2cda52865904720830d05eaf9621abdd0c0a8cd03bb723188b17fb92bc7e71f1a9711ff91472307cf65480fbf176f00c5b8b09c914a1b207b452ad191a1c3fe964a6674119982b0984c316eec9a9390418523a084958790a001cd9f8fc23c67c5db780efd78f0956a6d0b9631325ff4e1f495745e8ccb33f896544664f4e18da0895d9cc677beb821bee697b222e06d18314e08199f17fcbac44ea387d8aa4e759d6e9be4184d2ff4ecc41350d4a8e6c681f4640c52fdeb77e797b6718f0ca96709808449488ce8c421cb8990b24a433c090577fa68faa4afbb01e612e84768bfbaac5a20949d70720c9bd6f218f74755cca480c06b43bcb3c00efc2c5041d6079753da747eb601c8f1cd5be210c089e1d07f36b07f886a01700905aee7f70cf6de5387ed8ec06f9ddcc89b37a7c2eb0e611bdf7575822aa31faaa45c63d210017377d24c657fd330d0a8e8a4a3f19396bcc85b1f4126c3b03b63995a35e5c7cfe0fc46de53b88319557e729ce4d85d328b830473930f1281daf336e129bf843dccc54b0a2e5818ab4f096ff95a3c496f90a600f168153e06da41664b46f781dd4f4af6255fa5f6eea3b7d27cf15e2e214edec1ee61e791d7f936e8031fa10cad257f6b2916af619d8f53ac731ea70072a32a36e459c8bbc5d90173369233b7e0a6ab70180f08350fc3c78b93f03351b1fd5eac254d819545e3418139ecc7da9bc02205d08ba83453e0b3a9be081ddbeb7917a554f3ec80ccf7430f4949b16065e094d8f7edb4ed70e9f3273ec9b9f7ed90cf30c92410924690da4f5e500ea35238a1ad6c2eb67716986285533269c3f0dacba6858b3952da70715fc16f1e606139db28e5ab4c2ce8fb0fbe6b72a25a7395da8a9cc71c8dbeace952ac7fe3dc944ba9329fedec0366d0e2a6217a0f9e553220d7b878c50245c9a49d27bd5c52634b51dcc8dd45b4808d09ba0066f58ec779390a51a0040a250e786f5594e0c4ed9b1b256bd481e984bef6d06c330d142050e17ddf578de318511a7d1425e098187a2ed621758b052e8e176cdc40c46254a640490b52085832ba20e93f94e8024d508476bddf21a520f17dc1b01b98f020806b66015864cd858fa9372c6e2eb168313aaa52549cdf75fc8c151d3e5b5fba9426069e25856b45422d6fadd2a47acce4cb54f1319060b434c866d3e156a3e745218dbdd506508e6dea225eda0921319760132946a66e134227a87af88832f496ae53e5d30bb29c49e6be1f90a61040ef96c4b5067f3ccc8700847361e033c46c27104ffa87a87178bb265f29258c8d4d0e33979b7d82d607adb1f8c074623b7a9102ecc2e1f9253c3edf4eb4f0fc26dd0de5c9e05c6ae7aae8e1d74cda8d98535080c03a8313ca2acac438509c48a491564c0e1fb1ed896dec85ef7a39b8dcb3c0ac717c5a574255c02aa630dbdb3823afedb5fba03c7bb2f1301e46735de3d6741ad505035c5bae209bcfc6323099d57324705d7a8c34ee489e534640c35bc6a74b879ee5b0bb8dd754f171a7d8a44b37cd90d68bc41e2daf15f55ddb64a17566fd00ce697b4db33d86208976829b3e1f5a7416fd601a290010d323d3434954d93240b28073ffedc7f2b5f476f167bb233632f46a1a6d57a1424afdb0523cad12ff1ed84dfcff152bb6779b30a87661af3e9ad7fb2eede7911eba42d8ae0b3a4922f2c72586453a0903650a8519166838207c7e29c3969ff13a7510dcaf6e7fb6c2b548b49460e18012baef2640890c7d765f653850a98345aef7961d74364543d8aa69700cba09c95034319a7808a8cfe089e9c956d47cac62002c9eb1512e0d74bc8fc74bac22381a98142a690601f86a1a9d0f5c0937dfd851ce08c88be6e43d8fdc8bae35e07fb117fee7dfdd7947e29a0b55342762cdf8159d319e769ead88f9382b463cabf363df0670d7a57271494d8d2cebf1c6283f27485c05151e4b122244ffafd02c638fbb649bf153a866be4239af62f0c8fc4e77693d955ca92fbbb10924a373c3a78ee4c661e1ef97ea11b0d4f51817344d67ff2ac42ee6461c003432af9855a5f76d4daf015727d5087255605939bd34b12451b36ff1db5ad38dc1035047c221be5706886cac3d501648a329b2411e37be97a9a476fc8dd11013ba9a1ae93c02dfccbde868009346905d6b6880432c563f99dd22dfb132e4233c69e39163f8032cf66bd6e465a89be80e4a133c65b39b75d509fb05287e27da7d7285863e3f718c08bfd0a9e5c06890c033c7108b553e436f836a7f5613aa3d7fbe2aaea5d6f5e59fc6962a87c43f734072accebc95013a31e81a50c8f6f2d39832030f25eb07a3b04b8e0304d272f2dc9b47310febd8ced9ab4a655ea31a7691b6023ff12861d76baf6e918c29aaffb05b465624a89ecf744707e6e220e0ae232a1e8c551096cc798985b3194d07333e6bff5dd4829489e49c1209f7b6d2cb30f978bce64ea9b3a514eb020fb3bc6dd5cb65e8d14e833bf021be4561c39df4e9cc1790befaeec343dab7a63b6d4dc8c0a8cc3772b6f938b25e2a47f45d3a063adec573e04fa2b41aacc76bcafee0f2ab456f388583681dd8160ed31f5979e7dbf2c37affe648f6305afea669af1717ea1a819048f26ce28ccd529d3dfab373faa04591b04d031120367913dca965a4a0ab5c6c0832efd89e764974764b168f6c16b3d9b124cb9843f906f4f1a973ae137756158fceeca78b5e2fb43520a6aa41a07f0509c3dc1057b6b05db2016dac4ddd3d44aae9e11580058c0c45252fdc62fc7eeaa412cf92a3610f6d8b9c098aab0c4da270e8eed78ec81342f0696ea18a56125e3fa58bb6bf2e05fda17b92d7ff84a61b069885e3e2c8a17f3d4c93fba969632035108e96daf19c79eb521d4119d63aa2b6d9785009d4fb529dd4eba3484b45f2aca575dc62ab44877c0392f2636d703bd28822f8a1b6d747492be6e5318f225e454ad4115bc930ca147e2aea02782bdeb052789cdf0e2cc670459724114910d8f83112db217258d4bfe7b469c2fa200c6eb4b5aa9628aceb95502881d0f3ac8c1636157bc9481f0bd47f55987d50099c93b0254738d76692e00bbc5bb9ec0d53583fab86c6b1e87cc69889ce2166a2b523d900d449a4c5b5588ab53faa3746101609a94d39a0265f01b9768456ab700084f0b2942ba9891513ef35f793398e607f17e3ea46f356e429a06a03f91c1870fec3d1bad8ee1804755273326342522939752583b2fb3e0656668142f1879610530c4d576c15ac2739bdc6c43b51d00c1199b58442cde7dd02c4bae538d89c3a6d312e4c34404a4672aad4dc04f7b56fdcb6aef4353d554360b3a7ac18a71c39396fa62b743e3d0b008ce25c278fe925e3380090bcf660b042491d72eaff0847d5bc944a4f686dc8f38dc3aacdecfc5693e59bd66155894849f0f8261ea0ddeebda1d747489f70d193bbe8427eeab35a9562d1e052c379614341f867e707f4ca2ea893bd053a69c3b9c97d147b2c5ee2b4b3bcd1fce779d9b2a3ac52000a65443737f616f9a9e32e71f763e03dbe80880e552eb9f5fb72b8e9b17333daafeb47cbb7410588373140b4e77d0f3f93e248d80271aba536271445c214394e60b7ee14d3ac9c69aa2d673c088f097790dcf61d186b066f01dfdc8b206e6f97e8785738db5c38518c98321d31e490f18f82564691de082b51ea9fe89525d4b5623d24e57458edd1a479d23f278a43ec5b12610f3bf1c8a6cd6ddc66461e0d458adcf37616b4b1571bb7ffcc4ed3cf7b75d31cf4d58f96e1e0b1821e6037026069f56fd183c655e90aa20d07f8beaa23ced84129c32028e2d71a54470a21608e30f65c4ab1dcfc3a48bd88efd30c1d3dd112033ef59bdfba60ccfa263e6acee3be5e2ec7bcc14b63b47c2b07154e9f2188b670684890647fa2bc9696c915be52674a70b2c7075a7153024c9a8fa7050a63e63c24c3ed8918241da5fadfa5a1113ea0ef39c81dec1f71cf39b873bf893f22c10b37301dcb9d47d037f3035b31d1233f595d26be61d8941561e897251804cb52358f05a5526a25c8f2b8ebc75175ef74f271f95642730801e9f7f60ab143fa5e67ab97f21fa19f7de4384791109d7dbc79021cacad82ecacae773a034832cde04ffbd3058c46f8700686a47d0b8601121d031cd0defd98fc98b3b3ea7aa53ee629e5d986e79c31de7dc073917a198bcfa4fd213aef21923ee9681667df752800d91749f5180e776fbfb67e569fa4f80577c17dafd108476e9da0ffb33179227f4d0982ea98987b47d0a57350740ed0c7977a1964943c0e09ed5426f34a9510d84bc5a0436431734c68c8e8dd91d883539dcfdca55ca86040d78d83457d8084b4f1e35d218002f8fe22a4737df71b4715c4353e9256a42ed49808561b0214b5e2470589154dd215554b1969d883a0eb348f87e143eafa40df5322ea3351092e85710d90b3ed5d2ef0d627303885c01913c3d594f0b9178d7e0e717a8964887bd2af44c048c77337db1f1f4ba9d2fa096a202a89bbfa8b8bf1bc760d3b84335dc62437777d378c9649326031c3d7dc9384fbe4208f9f51e8dda1a48adef0491c16c3e0171480c36be122641f880d3b058c86199334e45dd49bcd30c6cc731de352a32f227288ed0c4aaa7b409c1c519a062644e12cd11f0a8d38feab8244ad032dd907bed4ffb07d2e6dd68003f1eb739cc03bce18c31238a918f17c889f27047d603672c2f4edb2ea224216ace1bfc863ec1090fa9c47c2fec402a01de34edb21a1e652b6865774b4193b826ba8d82d4b57c80ad1c4e049a174deb209be1b19ef756c6ddf69e9466ac05f857aa9e85a7b16ae8f0e97c98c5134066b472a9f1ea7ba83e9f32b84a9cf806ee0db79c38c31ce611a8d129ac928999ddbbea18ee87b08d653fae943e1950a8ada04a6118e43f98f310c28e29862cedd1fcd1703543290f5a4193ee2de0a2803944d7a0eab7151f2ca61dd325236147f3d525b9f654f802d17141efe2dc3e8ed1f2cbe06d76cce8370f00e95f71105ff7e6da7445f70cb6af7b3ccba7017b86410941438a7e620fb1c5b94ee5dbd6b35b6ea9670aa15137d462baed576c9a65217044ef94112b2dda9cbcd100d8aa518b904f5b0e002569f0fa19f87f47b78cf0ef9210d1a891317d703443911892e23e9125ae2c4636a0c262ce4e2304156aaf89b1c1625644d865da1228bd8cd37f44e4d900264e5a28f11ec33b6b3191077f5376df0200ade31d9e8c751b52fef6a9caf91023eb19423038a5e07d16068952599e51616ba175c74eeea2c6efe68942747f10d7b9fe402580280a34703973600f46cfe728ac7ff38dd22da778266fa5b2345ad57befbdd5693237bf5ae1b5cacd6126ce5b24494c6d7241d53b7d655088a8ebd5dd8989708e83f6b5ae48b393704acf937977a7a1cb4de08fa07c49bcafb10b01d943512a012719ae2615f423edc2d1fe611386339660cd297c28904504d1ae002c07cda01f8ded57d3cbfb4778d07462697b1c8bf7c9efaca93b5d2391b3ee2c09206e5b7e223e5760e41a6e76daa5e59a74e6e7e191ecbd4e6fed8d14966654fce19f251ee4c1f2df62023da152163dee32c199cf14b2cf9d41e362a2b77600ad9562731e6b5732a59033e00c9fd62dc2b329c47d783459504979dfafad2b0314a2ef94f77ecb791274648443d4e3e3238b1d3331812497dd087b9ab8cbe727080d3a2f7746e9fc44471ae48a19ebb8ce60457e19bcbabb745ef84436c3bb4b38a6337dbd1ecec3db2a8869a29f1dd49ad8c48914b4f19743891632a196b78bdabd0387bc8aad04cd7a1ed3a4970ed7d9e20302885b58f54ed3331ca784182d4e13911481ff931558002e7acea8abfc2df92b62daa0f61ba9db684e65a9a577eb6697e570590e5df385906e3c9b6d6b464631cc46ed81e80b723393ebdbe9951cc88ac74ffece1c82ce8e8a1a2542412666ff4e1e6f6697fb461143d20792a7c78330811106e87b71a052640ed28e7896995877e3ca97d791d6ee9c5a9a34f81cdf4c81c03b64b477d5066267a1bc838dff90719b7df7382d875ead54d30e98e68414cda9fa14ab826f93b9feb5bb90f21ed369ce50b4450a1dcc0409863cbe73ed3acd02d1f62b71528e1480cf03750ff4f6791271054aa0969d1eb289b68edb225063f4a12920a2d21f13a732e157610450d82ce8883910c28a23087dc097ee0805345adbe92e23935751b3a4d35a4e052ec0323de5e29d06b492040b900998589d9f9fb75a2a74b287b4ded08c23b0f77f6ac85cd2fbccc087ff5cf59c31e84201f567c32561707e35336487aee85699b2860f977669a2c9b7576b212e14ceed4080f4e33e59ee068c14a19772ecf9d16ed358d57495691bd6ea843f2a381dd2ab53164cc8df05010917e8e24a0a27f1ec658b039ec3febf54d4ef5a38b596165cd0f6ec71baeb9c9ee4c889055324bbe1c0d433c85129f4522bd6ea7befdc0133bba7cc767e30519251aec80f03e5fc6b3681e3b1856226273e329341e60fd59e3ca42c11a55816e6ea0b56a8cca5215ad6b11df3fc86c94ae10aa87ec2cc5d610e722ec912df82ca0e332340fdd80eff795f7c9bae61c233fbe9c9c5b87ce2f91a0616f602f8af2b8203c03b46b083f11afc97cc725ed368a7605c862443a8fef4f88bb37cd1aac76af22910be5a08f4ac4aba389cbb78936c1cf7f3a3c85084301299c08413ef92f8a842ff174981224f1dafaed98a3b450db176b50cb941a0def3fb52d1f2bb88881ab00ad87a9e14a7b8562585f903df48151894aa98159bb9d77e2f85b884c02c6f23cbec79c7c13de70e337815de75a1b3f60e0d7fc07e513a75f45d93b9b4e90109642f32c18d137d84dbd401be6e55dfab30714a360e26384dcca5715c5d9dfd571efa6a82afb9208092f5107a5f6db601e0733369b745805ad42d487dc5fa0f976b878c669af7455f24c80962650689461f027ea483403ca45542edd7ba11afb30b1e9a65576b424febcc88fa06a921573e3c8a1e37d593e62fc22047e9c6b5e69002ca54ed97d567827426c4cfb261ba446dac913138fb4d0ae8347a671995e5996f70e5d9f71ce0d01e5dc6f372809c8831cd18c94b91e54250322c9500adfa24c28f24e2662dae451d9051e7b6dac755c33099b56f8e60329d63534a5d89c12653bd95159a76daefb9e98848aa5195e56e5689b8e7cb21424c6aeb9c30e33afb337d0e7728e949a3b5f3bcc422bca96387b4ec038178c2ec42d38c32680989c02ab8b2a6d49b5e955b8253cb7433342f21a2dd35f1594c118a329d3fc914bb49c2408fe5471163e42eda207e6560a9aa10029b34c3bfa3812ac87e5b120b073483d78d079a0f132470996d689717874420441254e21a49f9387f04e1f4be77d0884e8dee1997f913248d4cc48fe00c922de8d79b4f455c1ebc106659ea9d22129c25b5b5ee9217c0b754553cc371eb9aece1090412e3929cb2b862acec8397f45daf0aeb5485b6875be2c500faf6185827495e0ca620b3e47639cab7cb253c629e03d087907a421efde377e8b109d1281c8e9d8852d13bd7e8ba0344c75b61c2cb528cd5fb6f53a137264fb45e89c8c302028fa9a6177ff5f939e1fbbbeb0cb30df1de5d62330b1395196046a47fe328413870b3390006338c1bc1e8534cdbd29421de49d6afa2aefa193fbe8951b688334805b6dcd9d9e4447516d3cc808b99bd0a75a789f0c8d21b5c7ec1082160a04b63f3c233834f96c6aae9936cbb4a814899e3d05f0f4511d83d85cb3fdf53348dec87d00d0fa2ab4dd0d74a0ab12bfcdf0ecfde43f421731484e3d5ad050a7512d98f7915563c4f17a5d4761e57514d43d1f2daf4b7f462c72f5c543af7e272ce1fb997e2ee353be693d03b37dbd2c4e376e92727525b71d878375b4741d592ed83594ca58af86d206e335337d41a6a2e3badb150415a4e95680e252ade9f249ba3c7be3ea394ffbc6242632ac746f970a538ef787749ca8713b4e446585f7137e2e56ab06bc75992c5f17c82dace8fff4f5243421d6d4172059fa87f9f4c8b5716f10ab2ff6af843f45ac5534599ed880653e87d9b6add9a6d2ed9434608721e2e9013b9e837e5d58c0e62da4df8d2fb06839e8bb982e44fe47c22d5b4b587d85afbe8b01102210dc728f703e6577a96f4264f0adc1800d4706e5aa511de0bc7bc12e63a1097f24a90cc79488c20b26ee2b4968fbaa12221dd7a209431f2742a941f2e0f94884377665e8c5724913d828dbdd9a6d09c97451be6df7cb962c14ce945771af84c4ae2b3fb12b5d25e14dcc645728b8d94875501f6f0827a07722a9d55386c819c0164ec449ab126696cece6709ca4030d879818700bd24c37273cccf185dd36cb647593436505029c4c6aa36d16a73b87df397615ec91dce7da8e3a78e67e4209b6693c35b734b3aff1f65a02845cec47d297a39cab3ca96775e8ab874272880975f391c56dd524003d2567f07a5ca8736b341aaeb4cefec2f67f8cc207aaec8f1fc26a9549d6736479878e66f2233b80dd68c111d087dd1f51a874512b8de38aa3bb96331bbeaf605c3420817be8b90f8c42e5c2361d3f1f53cf93308dd670c3c6d2d40ca0c322ec0c3ccd491619845ba9d84f7a92fe6d7c08502343727949f63f12c82a48e6b52437fbe7d0641f1a61cdf234b5ff309c6904a157bc4a187876e9c4fd3a5e38c84423ca0af24465e6ed0ec6f815c0e120d3235cdf07f6798428cfb85653330481378ea3454e403890482b628ccabf1b4bc34503c693d067f8b20c25000322ba35c2a56620b632376c6350f12aa5b91c024c1b10a20de0d664dc35fa1801f3985701c0fd0c0a3648b8732970646a630579b419e7919e88e96781b6a5ac343bb720b2582410142ef9d5dc609e1bffff12ed527f7701baf0033d15006e7df70341138e501e6fedb04cde03890e24d40fc4d6b8b7300e60597cc340e6c56afcc552f6fd52fb74839705790e50905726e553d450bc83d078ecbc2ad7159a64d4cc8e9a95a76a2a09c36ba4e6d31850bf5652d0ef0efd8c07604083ce33df963051837f70bc6ef43e4990537cdb8e49ed4c9460e709c21aec37785039f5a15e19c51a8637750ff66a00f7601ff8fc20680719f62894803cd5918491950af73fb22904c5b92f4927d3390f30c6c492f01b7fb6b04499895df0cf50c944540c29aeb8c120c4c6ad4a1799de5d55a000d8cafd7768130f41ae454518c683f033f53b2343fd438181f227d5724b012bfc07736535d7bbc3ed25b7f729aa142be9d8119c734393a8ae1840db523212c5ea181843534990d5aa5ffb5cca568e01603f83bfa622e5ffc82c5cd44629a478a0612be855830f86ba9b387eb9dfeb9e37304fbac707e43235d37d7f7e452d43962249bffa3d13f98fec1f81fac7fa93b84b67ca60b61eda0feb325b5b1a388a2ba7948bce1f2d9974d7fea08c07f68914ddd7f4bf1150882b1657959a159f1e3bc73b93f142146eb0ca434b1cedc339f93ff8772dc011ccc4edbea5680dd636cbd0ac65b71bf4fba8cf621482f7880c6fd5a2bc90fa973a4c3f1194815f52cae441cfb020451909bf52d6dba04ad82e9a73b7819e0a03991edc20d2f38fe6f4e6d01d9df772ac7054cd8326c4cdc72a0e9eac003bbb4ad67ba8f25505c9c1a6d60202af1898061076e37cade617d8112e9cd0275f2ee7aedff7537fd77caef09eb3aae3a7c92969b468b77d8b0e18c9f5c22d9feefc6ff68f54fa16d87f53fc1281467dea1240104c6026a3c0e755b3092324e07c9094408564903e0632b121cf75845d3e438bf29391b75cd28cf4755343a4a003b8ac9becc3b00443a86c1eac3fb7f37b3abe402808c78ea30ad4fd4db1241dae85308ee251ef8073686faa51bd97b6fb9b79449ca14120736073d07749a20fdc61317e830459c1fff2007b1cbe1f5d72a88d28391383f862208b1d391c35a1d33a65189d4820b1547e2fc783811934c49c7e8bafee40e4c62622753a00691d8cd32904469c30e49a254410c49ecb41dbcf8a155701912bbad065c7401123beb831831b1dbbcfe640aa480891db7044cecb833e990c58f778a9111542af5f4e723e8852476d79b1f0d16627f1209316410248168e0237637bcf9d10489fdb1b0100249ec5e6ee0212676379af0113b1c5e7f1207a024714a51c64bec60bcfe642b0c22b18b79c1608390d8c930a1612243c3344c8868880190d8cd2851a3c44c0dd728010510af98d8d138b1a18162c3362d2b593871343f1a09b258c344ecb8bb39c1075db46a4a3d1978c337b202f577820fba68899d8d37bf1a25c4fea413b02e80c4aec6eb4fca200c23b1b3f1fa9337bce02576375e7f548c247ec48e3b709a60052e787908dc2507245c3b457c2178f3a36122f6576ac20621b1e38ec7093020a4104410418b71ba1e9e64a1e9fc685898486a473f1acd5170fd24894ac4fad1689adbd78cbce6354c442522973c20db784d89eba512917e4a44b1c72af4b4d493818cd32304f0ebd1a3478f1e59a53b4a66123a619c748cb359e99fad15a5431062c82fac48a1b57b60246435ad7a9ab79500430c2fd1824ac43ae552bbf564ae691cf8ccab3c12f3ed5bbb12b1b31f381e89d97ab49d8f86056bb72f86865d89a8444ca1edc7a2fc686f9aad536e8da1f6a59764d0d55a6badb5d65a11303da3318053f944567aa1be549fe0073ca07d976cc96ea5acb9cd6a9996717da19e396756360f3ae629e504a7fc40c72f058b2d5c4efccc3c459a68c22afe91ae8a34f1c3957651a71262ccb22cebeeac332deb6e26e109ae75f3ced2cc3c74fe40eee0ab779d3dcc1ebefaacdd5d73602267d6923a13b2e034e1a172897977be2b33333333336b5f83ddddddddb4bbbbe9910a048bca75d6b955e95ea094e085ce12b7b2516bad9a6b55f39a39f74634a763966559d69d65dc9e65d676a0b96fee79bcd69ad5aa84b42e418d0d4dd3b46dd336d7506f6463cab4a39db44468527c5883d963a37da4716da76414b02b9ea3805d79f62c3c261cd6984941c17d1d373bd08763ea751fc7b99dab0de4616d0d4dd358d36c359d91e5b42e1634ab9a4f97a71fba99182e7521ecf314579a50afb57e33743c6cf051c16923c85b6f1f645cf63cec94f50ec78f04f18ce85ea2b830e82cf102c5a15cc0a1c890202649660697faed66b61cc771eddc1be96e66e6beacdb3aad6efb03d483b2639b998ef42d731cc71cc731534b43f711f1687f65724e9eb27f5ce03b73179eb3eeacdb82a392259ebb7f4c961411f09c7577b792a13fc2af51d2f0197da6a2cb0e4fbda6a0b8da33155d6e78d9c3aacc997e3bf7c80387555965fbc558af0645fd699031c809fe63bc9f65c926253271d1b5772d6b77edd6ba767777d7ee9d233bcd3c5fa06468c869c16ee62db899ef62ec3af6ce39d0083bf7463a8ebbe71cbbe79765d3f9cb7c76cba9c96c826377c6bd9dabaebb3b88e7a51fde67dd07199773eb3173c565e1388e39aebb53200078825717724f78ba73b71a5852a4555071f2d4bdfbbaa8b73eee3ce58f67e881b60cebaa7438436c50ba06a59429659e2ee8545ca877f4a3e00b944b9d524a29adb5ce1bbaef8766e6cf05695df823df7f2f5170cba0e32d6ccd57ef0a76169f2506af934b5dfe903a4b5cead3b3505ab32c3a118266be8b4c8789cc0875d41b6190f26c1f29cfee91c131c9738351b476f969deccd56957aa3538326ba8cf28a595d2aeb373d0b16fc1b566599665dd19675996f9dca2997da471bd535396187c8172ab4f2f0b777737b3ad37bb6287bba8ce2a70ac8499c70a8e49be3a73917d0878f65ac7249fb99ca091233c05d014402392b7cf53003d3bf7bccab818228c1efcc8ce9f0e131a48a77777777f5c7f3a7ec6e92a7bc7956ba53eb8dc76d373d1500c3c9a655996655996d5aa79966959562b9d5d7400c0e1054a084397ba3da2a37981cdb395143079ea3f9382e27acf566e60e3a95346ea64c4609ccc27133dde48e5e700f3bcb0f35138dff991c17025499058b71cb8814b6450899bffe010ad8f7654f29aeffc887afaa11ec76b9b5b9e91561f3503705fbd561fa902988baf6014e635deebf7001d2c4eb4214a234778cbf83272d10960ff01f91ad801def21ee836daf80c8c3282243c0590c8a08fbf742e4980a700122588843da653a8f78113245c80842b66b78f45fbf95029353c21810f311097c8a012a5ffe01079890c53b4fe83c20f0aa24512040bd291b480240816b60d94167cbd380d13588942060e60b0832a4225395c89010f3c386144041a621016dcc74794564bc7ef838c6bbbbbdb6af2d5f128621e66aecc332928ee74a7cc336be65d05ed0c2b6515954274d2ced5163df287fcec78817f8172d99bb3bc0e13b6e574429932a59486b4bb69b33103d009889820b15c72a9b7fd5a9d716a00ba9a14193c670d4140183b2bdcc87a751dddb80d14d215887938d77c23621ee99a7336f08a6bcd108879368e051c6a3ed6251588cabf207fac407f02c78213ae70adb93ac10a879a6b1bebc57ab14a05c46b3e7241af8d33ae3089559a045542acd27cc816374c7acdb78fe7c52acd790347216abce6e3f69a058524b14af39c185ce923ebf51c850f0e2e95b28d11c20a71571b9d95660ef35ccab8c43ec100fa4c6a37edc9cff45de6555a7b565935d3e6f23bbdcd59e25ea0851906695653cf322f40085d2ee7acce333f09318fce6761f7edcc54e62dcc1590cffc021be0c091c98a99a99ad1fb3143d40c337729776423ef336f8102d6ed6d56bb75eb14c63c366fbd0acd55bffdf19648bbc00c33d7c0166698b1d1053242f68d155ce9fd2365a1639c7126c8884b643ea5dcd14fe78e38249921e6e9f1d361a85cc9c12ef7e260339cde71af667142957bbd8eb89a8fdccb0b6ad606de98d17e0c17f41dd2c6c199e12cf5fc98592633f6f90c8e10a0b4bbbb6bf50674d425056d3f8e276682341854404fbd9bd743cdccbb8c049f20ece3adb020cdb21d648a8b2aa2ee69200e2a6e8c776dcc539bd896a7d6765dd77536b119d2d1e6e8a98d161280309d9d8631871c5debe3c9274a093cf974be59ef34e4caf5b1364645ee33aba47d4df21c3d7b4754e7d6fa4f2b38b481cdd0f3ea419a75c1930fb58159c1ab8e43eab4f3d1e6e4d3f9c9e7a997c0d1bab6655ba6cd520e2191ee6ead3ffe0ec69a760a3a3da13743a727374c9c82e6ea26091b30341f6f8826911e493243da573344419b230d94199a2f56f504915895420aee887211b9f99818ab3a2804ca1ebe422bbc4209cdb05152386c1fc32bdf23897934ef1b22949493936f6f4709cdd569073659a13dd4707d8f3744dfde3d9258d55c08af6fa75fa9c5aad640d38b55eda7a0ef916b7d7b47254f53954fe557905985e38910a649d19d3a3ee5b8ae1c7a067a26f290e2d4ccb007678635b5ca5adbe7373842c06b8ad43c4f530c39ae11aa18a18a1cd70f1f218b4e72f76c8fbb995249794091ee4827cd91e25a3b8d50bab18a66d9fc4eb27400254fc1b1f39e4b610aaedb4e4b4442ef5fa07fa4babecbb2cce767e00881afddf7a54e3a5b33bbae595e4d4c87df7e5131233cbb279b3a47dbb4819ee74dd5b3874077f45efef07c3ca5596bdb578f54d757d7aadb47d9b94a7d959c55a22e46f062042f46f062042f46f00285d85be7aecb716d476f3d85b9d3e30122363946dcadeb5a4a29b98ed68c5a2bad3de514716fb34e6e5d87a859d5adebbc9a95b9751d989116e0c4993c5a2d424e954bfdf4d1c828d5afbf7817c2cdd17783d4291d9defadd7efe6689a60fd0529e9ed8e585de2ee88354b8aae07647ef22e3da0fa0575843a65fdf4e9b83a65bd4eb9a38c110c953b7d24f5f8486295f51c22eeb8c335de1d443b8698a7e4d67724c13c9bef70ed80ed307ae699bf922e451b437584746039985c98ce94c992319a29ebf68aff9431d2119a32463a4253c64846cb64e12475cabaf52e6ac4a9f99c213c87ca2de2a3e563075eed70cdd0eea8e2c3c998b2f2d6532fe6e19c47ab04a11d554a98b2c33557250071c324f6324693036f7e74843e00087120094239ae8b23090558b36e629db27e83821109473e92748602f0ea3e9befb4aa0312c020e188796c7894a1c2d21f75b1aadbbbac9443e5561f56754ffb8d16bcba89cdd0726e9d7975c30587d6c71b2d6fdd47d25b1f6f98bcf59b1fe6e99cfb6460acb27ec385cc156fddfa4d6cae64a8601918381f79b448d0e2ad8f3e92668782e98075a08c0f078e3b28d80d8dbd75afe423e7add7a190b31ef76da51e8b9a5d273b083c57828f262fd01f758474a6f068bde5d19aabd6119aa175f9e9b86668fd0693dbdfa1b4dc51474847480a9930fce9e57aeba7d75bef3a1e2510e550b9d27d5825fd268549c4e66f7e58e5a38cd1cd0ff398dcfa8d11f350b745a38cd15ba7200946acb23e648b3bea08958858659d4b456cde84c42a9ba2e0c8e908bd75012431cf8eb73a436f5d4768ae80bc751d57b3a65b0f7c216495f5223f9e03a39cdc82d6e278e2868f426c26d631cea81267d09052ce09d699346ab5d93257b582748659b53102f2d47f08314f78e505fafa9189aa51b33c05ead3c78ae4638dc100ddd1c6a859ce29ea5682e3bdd349f881d3f10e69dd913e0e77b4316af2d46d8ce66a6a896d399aab0916e11fc306c9868b4d924d171ba3253f4f7dbc69f237404f7dbcc1e1a6f574de3879fabd90812aa0ec8ace366b7698c4838f7462055492c4f9d11c2176538d197e4842c2810e40e2fc1849cc0f5f68212629c168074fe8d0426cb05223a02a5eb082a40c8624a264528e7cb02421ce8fd55081166267bdf9d1273988fd21a13da821c68398a467b0028bbbd1e00617574d80c31a2610938444b4cee83c242926446d8849180685d85f4e152818ca31cad23279fd856b9c1113e7c73968d922e97afd310d88a6387ac922c88a23717e3b476277a37da4e4e00731490723e30c1c56764003212434a6a50826c424a16b680b929d235186293618d5e7e9d58588cbd018aeaff524f4d5c7a9e52bc8b5ba2d0933a8fc6899c0ec0faba6679ff6e23224d4e036c4aae94090346af3a7a066695a666afa16a1315c5c867e6a5d4e44f5a74504e633503302e38755d5eb0864c66d1a95bc6455c7798e0a428961c21473ce392533334f1a60378c5bd5b0565009e34726daae5cedb9880a1744d4c64cafb9099837e6c67351ab07df3d1751b9c18f214c8a986baf6f540e41021869622a413fbd54ea99568719421c0579ea5e0c424ce9969032060e3070a5c04a1555134008030b58194b601125dda0c480047f25ce0ca553a142c4f0f3a7cdc1456a414d09428b20640882074f7d8b8999417a4f8ba44c79ea944eb9312510e329b56d14c180ca536a6915219e9a9e52ea51ebc9e718103f3f2f0f38bc45143fd63c7dcd3c757bb73c2d1272c275dc00a70a8cb525a8c284676d380d51c39d3e2369b80cc3d2e447effbb9c809a137400d0bc6bd671850db3253ecd124f5e078a65d7b5dea3979f3d186f452937ed658a726f5767cb8a3774fa6eb230dd267259f12d3c093252273be36c66469ad4ec59aa5bd9c10e130d4c4b5e4a726f4538bb5b8bca54162158e1b431789792ad1cbebe5ca5ce1f0e92f309a1fe60140112fd077e2850666fcf4ef8c3b7aad24785567e070081c2b0d4cbc0d60fcf47bc43cd5e7d0e6c40b9a2b944f4a3d1d319e140e3da119b6fdbbb9d76a560ca8c574685eeba77b4273e5795278e565319757c547ebe580e91b59a77da8ad435194066b160d9206e3707c5b972d29d6accda853d363f628b6c5b6d7b75dd960db15b22534c3d96a9686a4c53c6c85413f9d06a959da96999a4d83f416d4b22594724450b29fcc678633f319359feece1b9a2cb9844774c5339a2bca452fe0f2d3bd3164500f54fce879b0284b7ef4b4fc3cfa99d1d85c8d5aeb8fe66acc5ada96b9cac0f8b969311b4cf0a337f4d43b8ee8db4903b49e0c72a85c2eea21f6d2e6e757f3327354d19a68f9dac6b3c2244e693e724e7ce56093bbe2ab730dd74895c00c18a09fb565adb552afdfe93b0b43e566d508c85cd1d551a7f904f2d353754a11d528a84b25aa4150aa50bd52afc0687a644c12778cb1304058748c33ee082262d5742aa59412a5e58ef5555f52887caa9d62a72318a00983c364599f7ee3629e9d9fa7d829763a9aabea5c26ab4299525b4b7efa1caaadeac4a5dc53ecb4c56fb3581c6beba7d3ac60dd8248a4a851204d62cd9219c2073d7ca185891e48204e3f25354bc90f59603880cd3003365e202a890284276670050a5e33e020530333acc0c245121a6d88d3b974da428f4eb1194ebf81823bde1b94613183d104bd0601d1cf1f585c396757ca11fd9ccd45c738230c6c655a83c30a03af4c49d587a57311667145cfa8a29f3eea3ca35e210cd14f1298c54398f5821abaf102d384fc60dec53c36cf9276d36eda9436a528a15310ab4e41a522a8a01ae5c5a39c4e413de3a98759a4fb053cb5c02855ee786a31e11bfee2d3e910f3589f5e7f98a74ee7b136791598b5c118cb4f17c2439885c3a7176116caa7fb18b27efac6dd519bc02d8672cd9005bc4255e170facb04d61e607eba48219e4f3751c12c98960b460929c4038f7e76a0d419ef0e18a6a5c573a0eb278c123fbd43b9e68af34155e1155702ee0735c419c1fc34cb44c5cf4f931696a569073f615a39de943457b53543d31abcaa2ca83d6cb0a1666db18669420ad9ba489de93aeedd5043bf75e94caf8e35cb94d42f98b57734258d5beca7941958959c60609856b32e08d3c41d4f36fc8469c294f4d3616ec0424c5ba4cef469daf213a6899f5e2a72faa6284b0d60df3ed41494d00c834a8082e23357a81e389c3e7150f183a3633f9e38a39f6e1a6ad6e90b4e4d2fc33474d201a7a6e3f84e58f8640587d35fbed38def24d4a9e9fd9da0bc9a751a326d91424e3db0cef4792ad281c9f4fa797af2d3479317ad669d7cfa298879a84f14fcb8bd3cb55e3e2b368e3fdd0f4912f154c51378aa49b46a9552848195668e1944e1f39ad3c87035d6dd41f4f661daa391e16615ca0c35e6202e2734438df5d29c488b796c5ea3ef50eec9af9ffcfa3803c47a358b0bca69e2f20c25183403c482754af313cb6805d6cb7fb8231704459b697dad30405f8b582f4e695e9d650366cd2c9923cc92af303f5f9d239242a694af2fd599ad786d07111a7ce525d2c9ca9f602f4f574820bce6a3498dd194f4b2b362e5a5d7a14af4523a47c43ca54e3e8e97d5a51cd2ba9a8749619794cf5c7942fc0bf34b5fa806ab346f304cc2e18e303eaf79ac5933ae4e5de115f784adf08a0b9aa1c63ca6665d1f5947afb18c5e2bf9c8427acdef674f1ff793daac984e55d79c0b9a2b6d66e84f35fc0a8e47aa7b2821e6b1ae398c0ff3a05e73981fe699afb98ce61b10e329e9b5173c20dbf82827ff80fd28d76964b876be07fe58f1e4bad367d7ddb454c4e6ad775b0f65aeb5d6ba39539a7df2bbcca391e172cfde6525e99de69dbeb0cb4c6961d2f49266187699a1e61af205cb68aec61917eb8ab91a8fb4eba3fcb878727965a2707ab160332ee6e1d79c439a68f08a6301174d29579b7677333383b43e8343b25cfbf485fad28fd0d0ebfaea729ae94a7e0e817933b4331ce58f476878869cb99e237a094a507e12a9a4a7d79a4058b064e153ca5abb76eddab56bd39eb4d65a2bfd9105b7776bb6bb4cb3dbb51c5732993c206a5cc9dc7276adddddddadd91723ec3770a06038981c3a62626e8c66a90c9da13494524aa9a6699aa4b5d65aa936e5466b5ab321f080c951734371e837664fbd4b792a6fc7f348e0b90aaa409d9a5f8207e48c6982b7fa7e0609008f67cd001262863ca1d4f3817e06004820000f0032581c117af4e8d1a38708e09742edda33abb5a6727efcf8f1e3470ef8691a9033ee3852effed98903f05c1280cef06b63002522e11380da5022448a1421619ab05aad562b137a88c0eae6201c848370100ec22ce68113c24580a700052c8052ba8066ee05782a78af202a910aa515ea50a7cc18f2a2288ae2cf01780c20404f8fd70022458a7805288001d43880c7020212e0a5f8b6a4033c20670051e34aa9008faab0c20a2bacb0820a9afb484d9f10f0809cd18217815aab04989941afebfa74367d8047bfb185084420021188400b12f02a30010aa8809c01e48c1054336ab7052ce0820b2eb8e082054650510c60200319e83400c48c2b9d6a806a40670495bb8005cbd9776b5ab3cc6e9652a64c993265cacd53b2e98d506f396ed9c9d3368ee3386ed3b2eb7557a2266aa2266aa2265a2a11d1b26a5f4a2bc4740aa419ed2ca355dec0819a2b6aad73be8916fc0932773aa46e3feefb2746b4dee5f0b68db30e639dfe58d1fa662dc5c211494a5b94528d524abf0a663a6817826a469513497bd1ae792d734e161cd14c47d3dda51ef6cacc943fb0c5b8d241da0d96c1cec9d94dbb67d8dd1dd34dad6dcdab9f51205caa0fab2868e90bd2954edbdac9f285cb957e3d2b39efa58c2bdd32b775a651c997acd45a6badb5d65a6b7796bb3a6074d0d4780822f4a03bc227db139b9a191a1990524a694aab94db3aee9362f764a336630ead4c4c8e940feb837934ee9c1f947e93c39a7d0d41f643552bf51c480e53eac9ba36737377edda2370dc93fbc574ea094c49470db7db874ea370bcdcb82a4a29a53b955270460757faa9baf452a9a79abc1d2036dceaa59eaa03882bf5349054c775315026a5946627fba2bde4a0f1fae7ed77373b3ad93a9c2b40a752e814510b2b68198c4c0e8799f166719e143dc9c9d2ce0e8b72a333d4321c352889e3bbf1f272abfc4a1b8707ad5466ded5db478e35c8c3b3f90cac40b3d6be51eaa1b49b230a82f66d56e74c3fcbdc177345b8e106d8a32fce4b8fcba3863f841e9dabcea4a9d453c1192e6e0f4a5dfe74a129f44aa51e1d385cea92eaa0e1b677fd4180a55deaebb8ad33d5584d968e71c6eaf3cc221daa3f4c5d6348d107b65d31e4ea82302464cfb831cf4543405a0b6e0e20d8c08b8ec9353d172161a459416206760748c040878b7a2e4242051c106d807161c2d8620b258e80b98e4862872380c8c0384287ccc9c5f15c74c4924e8c7bb95432ae7d2e32628cce05b7f45c64840e342af7c673911137c8811156b0184164c4901136643db0f7de1c28239ac480030b239822237c9ac4d29801898b148838786169226ad1bac10c444e34c91273d93054840f3a9c004b4cc472748ba061862d0ba1ae081f1aac518c438306cdb555e9a2864c8c21d92ab118aa988323adcaab45c52cb22a47dcd0e2164755889f69aff5aea88356536b9f6819430b975ba575029798c55e15aa00e1f8f5acbd3145447cf1a3fb0b381ddcfb5c4404161e8820b269dc1dcf4544f4e099e0fa731111307044dc1b2eb836ae8c14414324b163c310446871753c170dc182ad074334e9ceb8f4b968881f1586f0b19495986c8b5c47fc18e38396dd5b4f197de6849e3d68862f69f02422050214000819e4e08b2cd080e1480b9e365cd0440d39b842863462d8a6a8a184ed872b5903907c389ab28216b011849c2eac9802450d28d600c2a77e91a381f044f6c4142fca6510a00009f05cad1b92882f72c1e0678cc7cc3c175109c206836e1cf2baa3fdf9cc76d2c8ef97208d01e4d84a5ec97743b2dc21b03bbd93cdd3346ae01b92e54a1f02bbd2896e76338700c495d3c648f6660bcf3f70103ebba4dded99a0c595ce3304b06720687877775b1eba2e478a2b5d0577f29c73fa4b1a5752da26dce04a6ffb7c93c69573ce59ade8184747c64c293fa6593b3b26fca01b9cad622f88be41d4a51ed74a6be83b9d9a1ed312fc827065f873e5e379c80e778c89a999ac12666abaf48aee0e2a9b2b9dac66b0271de38ca8a09fb5bd93ddcc154afd82b652cfe438c9314fdbc93ffce33f404ceb4fc900520c7a5de923d77232c3597fb85ca9488d2ca9405f72ad4ecd66b110d70adaf1dc0aaeb492a7694c32e7e6d51a264fad419e5a41567ebae9c53cd54f66ecf0d3bd3126eb25a84b2de669fac281a8c9506989abcbcf17218fcb0bac9bb361681f56bdc61812aa15a4aee999cdbf04356b5e3153d3b5086d718d31bdcb4b46c109ab5a8eebda52119b37bd58557d4a219bb353aec595c36655e65b8fe0a964959669e0c8b588ecf86d8855d54d68a27aad2733bed6f6fad2307cf579c5649d82ba7d98877a98e2a8e44cb7353d0c19aa190120002000a315002028181209c52281280ba34cd56a0f1400116d86487654341947a21c866114c4400c820c21c0180280310620a454d1d80093af87d57008e107d0f382eae4915aff97e6c010ff19c4bca31e926f67c14a71aa581f0fdec3c384c0a429db9435c7e0eea58c0612b544439cac7356348e7d685eeb58813a6dc52eab77e3168d28f46b2a33a886b6d8c369c6d8cd12a41f546baefea52768f8167673d449d7143c3c8dd076354a33ef0ccf465dd5ad3d965f9f214e97c9e9dada26562ed6b237a60a33853167900c8a94e3a141d803c2c08b9528c6dcf56cb870432db74c442cdb9652d13de599880b539508fef38f34ed9bfacf37f5d27d2fbc81d59bd89784a8eaef3706cc1fc63fe90719ff582931f9f663bf21873710bd3a855cfbb93ad0bcd0e1cb5f4bcaeaff1d52ead31cba5e41d6709eb0865c05a848147e96e962c5e89bd67c2d3c07e416c9d7907396ecc37fcf9230f82112393b9a53363e4b608113ef2ef61f0551a7e167d4505da9edf1e5a684989ec797b2725ea3b54454e64911996dd8fddb78edbb2941fd2b9740d5b3374dee34f1c53c55b7575621bd9d9bc44138a4d7f695e11ce30c3cb073a169b9a4aa2da0d0ae844c81d281ad5982aaa508f815424e91c55b217a4d4fa8dbe5004bed959a3752efe50a5f41b38fbba57491fc2af4701f3a05d08914f3a8da5ea9cae9111f353ab850b0530f2c2f0c1b0354bddcac308cfb7d38178c5bbdb3c4a54b7271091620719333a1241d33170adbc45eca1058b6d1b7e9e89df4eee2cab85d4653a9b052f82a3caa2afd3f283a30ad6f651bc87f75b0ad2025f4a252dde964573d08629ed56bd4ffce29a0c7eb2a0e8c798184daa538ac1e4a020a19e3905091a00870132078f4f78e8d1396984968950ae4349e2ec0cad9e2623f58de8e705a84a04ec11ed69181b30ca0dfda17211cdf0480b176423f38b9bc5b71589c3294a89ea21b157a27ce450c8fd78366d95f6cc83fcc975dca8a99012b70becc1119a3d7186b7ade561604251dadf57aae54e633109dec715da3fc89afb81b4db292851c403a85cc85e59e68d41d5f4c13e13e5fefbc9d1f9139262bff219cf5df41c134b0bb7f8a25989bea18420e19e801cbdd483a747f9d5de180459c8988248c69d1b86a37611376dd2fd5a82766a5f3a2a2496892b6412ce7c9e437843c132ef3e7ba8d827c03bc54fe366448d37f8a9a6a3c178e5fb41e8bfad9841d76ca5213e128150c9fe7829c3f5d018b22f4eda8f19dcde6ba443c878b739fb9c636330594e765658efa24974a0bd812842e8cc387a2b84f98d5eea8e80565e8a2a848088bddfbb9e1ba7e248fcdef89f1d8f43ff913cb258ac247087244065c053125a4acd62c0f66511fb38c48a348d16f6fac7a4425bb5f57e05c9f9dcdd4c19890e0e45f88e09bea42046b705e27b1d3ed108ab697d6824452385cac3164b121638ac187566dd6d963e5775bc022bec77f442b376d6ba0d7ce5d447e439853320957734dfcd3e3b617fa12d759eff61675c562014e48a3ae0584f5ffbfffffa3800f03683455428c27ce68f6f74cb2a26a1e78d021b9eddff676442ad1bf58573567ce920248a863a9fbac1decd72cd0e19f96ee91ff63ee3e9fbb6a31dcbea6582fda9b0e74d608577d28162998567733c1e8f05abf1f7b4397f7f0dd78d8de3e251bb38ffb45c041b35f1c17042714e3e58d3e3f5057e475679eb9db52d312bb8517c661c349fbdbf875bed931ac4f3e13d45f1861a7f51c82acb4d790fb8b086417c95f08724c26e1f9c8c0900505ac1d6053d9483ec5266a5d08bf5b5e31abe97473ed65dc7f5e544d64caecbf324b328e004022cfae956db54c9d4cc9c4bb88e508d9fc08798667c2cf81173582465b85c9eecd3dd78d88694dab70191c243c688955a14559cc0bc0a98980150496796e5034984b4dbf27d70da916810652d2b4d5773308f1ffafd12ba2f702f0c08579aab66ae5fb9bbe2411484f5c889f542205d7034a442d10a80bdc45cd9827ecc90d2666b645c5522f7a5e6ffb1185bffd98c26f4fa47254e5b3f6e73c8791828db59edbafe948b62d96e047365eff035c38aceb228c44c03f08c14b289d3c4bf0f3870d744f2e0fe5929c94119143b2f00d91d96f7024bebbc4706fa8f776f4b0e4e0a3439211bcc0bf0f5ee0dba3784a02ad56e9b63b234bc95ef293ad38f0b4be0d5557ab92bfcda7584424cdfb3fb744ab5a32a68c3c8123d903fbf5ff1ea750bd147043741d1fcd8a47c821c6707650392b0fcd35a84df178cc7b20bbe906ea65f076748afa2bf181f8cf82c06dc4fa1f49050cd715d25f1a4892a222609fa81a44237f8a5f2b4a25dc33325452e39766b82e3ae49a8eace19608e1bac4a3cf33e996a277d553e2f6136549182aeb566a4b74a4d2fe85b87b54bc1ab07e9515b437696c63f30f0ce82e198eb91655a3f7277ddcf04ae9ab07926dca85097e4a7aa0fe1756f55ad8985681080a05e79d887c4c5bb609e58367968037b0a8cd9abb4cf118785c35a2b6221749ab1e5e4db9c173fbf86d457f1ea0a93071fac4245603e6d247ee45efe738e8681718d05c409f774d73cf4cb3cecb94b4d45c0cbc0561a2b9c8cb07852e6c0ca97617539d3e6a022ef0b5f26b50d0f1b0e4b7a7a257f25e035e8161b555ec837e9614b37a90d6f917de20d336dbada1941d6cfc77963970395e7eb58397afc2b17dddc72f806d46ea3a63f853f441294c9f51a2bab0f0fddafd486b2a7efd50c729ca254b72b9287a7cbedda89461754223ab9483d44aed23a55402cbacc6aeb72e47008c2a4af8f2a89b9eb2ba38b32d90d32ef2950aba337a90d59ed995316b732c0152d80c2e62fdeffc84213115b157b3cd2e477fc1e6f1e4ed1ad8a78f9c50e50ad00d334beb77d3634df39fc58153ba26d106a972e60b4c99cdeaa75ff5c15f69db2e2c6c4c248bec2906d9110c914d61ca3db0003e66c47693ab7ce01a2cd304200038695ef495ca0316ea2f7c6916944d961c7863c5b7c342ad5c8089b5a6b472039b0298e3ca3e181820ff43885a31b5636a93fb35ab62b91efb4deb14aad3229750e1c4c4cb1a106056fdafaabb9624b707e596cf82f2e79f50972757258a3c6f6c18793ef332b2195cf4a3a394fec721dd709782516283a25c29a1001e36349d99593205e557589ea1fab0cd896c078e3a55e46aaca94f5e5accab943fe0faed6fd5e0d29aff3cc6a2dafb23dad48e724ccb4ca404436733d3fcb4d3c2c8dbea786615eaa6937ab03e31345ff4355cb46061415196eb1c0b93035632baf9e0bf49fae8547636f6b3e14d71ef55992819b03de9478d5f872a0c91e37b1931fc4fe756a0558394e8f2a5ba3167e6aa0ee872bd97c6a720db711a1e302b136577778c20bdfed633ca331a97360d7da986b3df3242d44e077e72608e55c6a5b251310f8e99d5bf667eb285f9c10c496db2bc1cb81e5a818f6b8b31feefe30ab7effb78443b6a5b5709fe4e940b8eb4e7b3466e9b42b7b207d17302fb42fc754ca3be3e709b5ef5945ca1b3c5c5e9f5ed8a30e567003dd518b5bf3ea8bee48fd9995956e6f500eddbe61ed0442442d3bc11e14d8c4bbd0ac071afd93d7267b9b41ed8fbc4cd3fcb5a9fb178e1548f03b2c221930fff2bb6503eb05a38446e6b3c968d49ac8f056da7624be82c8a013ba0bbe0eed0aef462e5080705637b51b8abe91a7691bd960d718622401948b9a300728ae56c4fbd92b36bf025725afc0be098b5c20ea89b1cd810fe5d8ab96df77723b4b26c533c65b0cb227068a01806e6fde1e3ca4f75d99a3341809ee3a956f219a1c07da907cbbfdcfb22d56e253acd1d79641e0bd642c1910feab51016da748f9df89f75ab1d6245db7b24271860015b3381a10c26c896e1c4a4ede7157de275194bab03785216f177b7c1ee651545358a4d8199025eae1a65a9c0d9b0f25cd5ad5c2ff5d1479c7008a901770e17833ed58a8d929d5372ca73aab2de538a5c0eab97e71f9ab3536ee35f4b440da85cd85f44bd5690a16d2b930a11d0888f8ce5344f51cbac912696bee2e563e3ca5d15f1f49ce45ffeaeaccf6d0360bcadc0b8e7f68e4d48105f6d9042f97c4cd9cd18db009557e80795ac18da3804a01331aa408f560113e38c0bc7da84ff7459e0fe50764b4a949c698c1b19bbc9d4e43887d367eeb51922345663abebcdfcc16a697c9e1498bbe1f6d6bce3bbe7b9f4354114f3bdcbab827f413078bfad1b9eec1ef26e64d170e7212cdb53e6b51fd47a52558ece7d785c1625e07bd5aa23865f86d793e1bb5ed69d51a770c560c5c03f6860b485b587d2c4b6def9275c9b03f8d3f99241a5bf5e947db8d10bf1a87229f2f60f5b2fec79709b433912b52d41df36667e75d0916261de4ce0cb7f1bad8fc793c8ed7829990e0bb0aa0bcf82e2c4c482355aea434c8e50b124981c595a2baa803a81041731b7ca92f423d45e7eee63c70adc163d0bda203e8e4aa0f2bc0e0abab805bb5a4eadf4fed43434cb7656aa6a2244cd671d25fc0b690947b64b51262d0318f48b0fd7157d5b05d0ea575fae153ef8fea5702cc65cccf5e5e603cbc443121ce795201693c5ab7ac2fa7af989469b30034888970a6ed36d250dc4e7c60d6bd8c23961c679c808bfb6a28a97d06919ddcae5f2e52c675baedcf2661996556d2e2e719c652c2d572c3927657507d7cb0f2bc84bcf254b9683e5f7d29f7764157251f9cf68856cf0e1e315af9e816b3cd9d1ec93a85dcb89ab031051ff211c74173f147750d9a93c42536a8ac35ed0cfac68fc6bc957d0b27ec8acf2591e7025fe23bdea21b964ede69fa67a75cf7bcf74acfce48fe1fd5c9ddaaaa31e2f9473eefe3451df6c4427b4c47c44ddb1974639ccad26c54b5e44fc119fae1f04dd3ebb018a67a13d99ad03466ab5af82100de747da4de1ca8ed86e92d656f01118bcb3b64eab3fa5882786985c5312052348b0719c29a908cf50cb6bc084359eda5246733dc7ff34bcb80ccaf2ede8a3a501423301f85253d96ed290b514c32da8e95e763f6f8f4596e26ba08e133da19f468b934cd38bba0ecd178f9d57328b75fe6899d7478f4a1b1ef12dd639ee8da5970cdd3d5b9a3db26fcd0a618f964baac90f876ad838915d21dc4a8b7e2187f93b6f7ee756cbbba6e65c0a773b17a5d05a1a0eb0627e32254d29f6bcc2137bc8171f9aba6bf0c14c252552bbf169d52aa29b1452d801c2fbc2737ef7a0c6eea75c73edbbc76025b7c2e5b173d55cf8a4417d3a9485adb282a77bf9c8657f7f42c8e9f73d3f1fe20da6816feb48feb290b9df8b728d4a10d454c8ebf50d647a640ba3d614d2bdfb4fec046f6ec623a93ed849e635362d23514d184a7042b5ae45e9de1c39c5f50f2b5f7e25e8743f1892b2126e28afaac9f6d265c4db114c9c8d6c04aed9ff2709034fd2815f0ecb1abb84a41d19bc93fdf1950379242a7cd6b32ab257e905210dad65fa89fb9508e3a51345856a794faad129447f9e738915f4b3508876e08957c7a0c56c2c92d22b45b928ff5f341fb353d967ae34bc010f8771f2e897ae13d447a82139b05e16049d1a50387e47204f40864c469f5033b1c9b8f4f81f2968830f58baa951c75570e430796d53713a8932b554291a3a9ad64425e25ca1f8a3d59298a840481533b4f46154812ec033082cd6b2b4bd2d05db61829d22ed983eb1ed18739b25929be7f820cccab4288f7ac046bc41dacd5944a03be4a60c08e2b500dab500ac085dd440e37d92c67044c715947ed2144ce6844358a4578732bcceb83a89b4581848b5e584c6a7de3c6946595e5835b310cbf2d1147d1d622e8e37a479297c6822702f8964949bf103d1abc2b347c78aba0616a0731fbbd44d6343766a8ba9bd20ee53e07c9987a9069e37367c45d68f726a3aae0ff94d13ad89154eb43c63137062249b74e98ddb1587b8021e5d8b18083845ac80eb6afa7d3419055caecfedfd4f96cc2b9ffc23330dab1270546a58090044f4e63a1450d82d81688965654d6c296f0db1f3272bfadc75b36a055efe0469fc99d852602df8042c0b1816e8afd64c2c09e82612075f0b8e9c2ac39d391e1a099c548696650ca3e465208e45b38ac3aa79d166193780ea3ea9a90c7b256996d81d827c400ebf05cb56bdb1f7b7ea5ad4a2a61979ca407c76eb012493bf104157f5e6ce125583c66e4cca58caa7a9bc084aeaaf417d8775c7110509bf469a4891cc7177a3669c692c90ae716c77e6473a5b16a7fe8485db3cffc4f45f2031a03b7a723330f7d56fdf760a75d8f8507dd954254ebf14aaab364ab5caa1ba4a300294a58cfb48b6e488dec4b295f10e622669be43cdd89bfaec4a30424262f5de21e40d5c73d5d3d3755335e26078612253bc59f7d5e9d8738bcb23c349aeaf52d1efc5602968c26e4b181c0e15fb66203d7b966496c182794e76d181169b0fb740621c2bcc7b34b32d9d38c642938420891de4fa02314bc9f50e68ed05fc51992d2598df12cc0326cffea6f054192d9b923c03812758f54a258fbfd913580442d51979ecca682ff66cde115f6af5cccaafaad16e60140e4a5aba538962064a0806d4be62a2efa6fb5e78815374bfe131a98d81c0376bc67a52f58f37274672d6f03e858ed766af871e6a5ce3d6991d036aca7e2edc38ea8b2d84d807c8bddc048c0ada0b20802ffb3bd3f7d9da93d736e879b8e9b1ee34a065987d6736c76c1c5e63a4351857c337edac5d9861cda44222be6a1ee827baaa102293cbc24ed65bab420101f144949671b9cbfabc79c9a732cdf9f7238a3b8c413e292b01996e802f86bcf2a2fe870b4f5d59ed865f9fde89549196ca71f7ad1101340e9db7e7bab16ee97916f49d68024eaa5e0f43af918d8a744c6aead0154704482b458f12f7374eef7a2e822f12992a55217455ec502b11fb67c8738fba50a5bc8590b1bd12aa0062edaf8ae823a56ab95345450528e2fe8dcb147669c98ca29b663bb857827737f000f7bf5b4e516644627fbfba5a13a2c30c3a509a005ce46de317c9c92027f7be5e05eaa3e3671c2d9f21183828492223fe0c08215f571c1af54d33d4f1a51b424a8c5a96ba0c384687605736b2dcca7e8bd6b79fd1761c1e6e42f9a0bee9370eb44304266ddad72412e86916cd08a2aca8ce49f00b6523acd653e36fe482dcd325ce1fd5f8ea916d8a5ee8de2fe7328599eeeffc443c8c83f653c81c59561779cca6403c03f092dedf6e6805a44a0eb1715fea52097ef096f00897447a1e68382c0208ba429691e252a87c99754c4879f15834fc614b23a3d12847102f3e6429fc3ef642c923962d3441eb08c9d770e5811fdb0705e2e409fbbca37ae35ace3efbda3bcaa8761b5d31c06c8c24fcd49e177797d2442f06efd8e77fc521d2356bd545f49b2bc8a561ec7d2ccb6a161c2c21b5a5409a647c23327fbbe7124a4278f316df0a5907cd350a3b91066f4b0d11bfa585f973c26b94fa36739c40033381161bb5f475ec0cd64c43a45f57cefd478a46d7e44b558f12228ebd6a0623a48bb8fc61a5dbd4610c9f816277f2110a1a7d8dd0456dee588680cb024595e9fd0fd7da1879f15bae4ec48fa0f32da853998e5a6c88a2e09077709a3e71c6539e804c57a69391ed2de97b480c86f6234039711b3dbb269191aa312be1370b148758cb52473c69e586ec27fb1aff74fb539fceaee9e18ccde909075b6429aab126bf9839a4acf7b143f58372e90e744f1bf8b313f87b9c4d4944ff07174a30afa84145a7b5cf50014fd1a982dda77c4227f0b788ade3f9ff955f1e92d98d2dac36941347b335fb711bdbcefbe22f91d7a499ae5a7502d533c3d3af0c25cd73ac21abd21bcf6d216ba630c5705432b70724cc43c588faadfe5dec5d8e35d035181cac395dd4d286f2c365f4270724ac63578ee8ed50c8d4ffa3c9ac993958d2d14e115bef45570cca231e4ed2c5c6c044b7b32181d18847dba60486f5bb5c8f6051cb4701c3d0b04c5238bbf2f065ede9612c60900af14c2c8d1058d0ba40cf92accf1271295f964a0c9a9b88be24ab25f42bcc72cbfc6191c25e0cfef73e544ea21efa5b3819c5456409ca6b911101b30f5246a87e3a1a02cd4d6f50b9276503e756b1330709828c635da8662b38e1fa3bbab7a2b220b7fd116b6d45700b0ed704cd61b455246d4b855bf43fe4782620bc85a4581bc6bb2ce8c54112adc067b04519e3b4d0940ea99c532b216f0f7e33ba95dd6806cc1a9160c951b8de42d064172cb8563be3bd4e815a5809c508e2c01f3440594f74dc6fb99f1143691365ffae2b4e22b641c1253064abcb7191fc65ace105699db7a616bd101a986fd71e5c345064dbb83e1213f95c01c21d48dd21f39ce70215e3cb02f1040f5d47d9354ad84dddf665394b9ea478e20ed9051e428fe0aac5ada34b27a5114266267dae7f8595e7b234690998317919050037a42540b52bc3e057b24dc9eac6b5531915d536c85bd478d61606c9119e660a6a01e982231d8e70e6997939d33ee33fb26e1db1688aa7f6399dda43d72064f0dc368e0b0069186ab479fbb1727b7109a355decfdbc5f34dea8fab9f8cfd79431b20f05fde0672fb1d1a1a55ad0d5fa991e3ac145afc5d7717668424713b577fbc288e97e382769ab6ea0aa738b5f3ce971023c005d96d988e869e8733b0ab6014b419aeec4ea40484e32e4d9f95c94bdc9a53d38ddc4acb8aaf4cd9f25efc4f66444fc296d82649df3967b21692ee2b3f4dcfba6ac864348d8068d65bb8a1656f96e065fae246de75c536e76fd25ffa80e794b15a94905a54d63efd71372d5fb554d5f75130025c169c2475f24909a37206bb72b6ee9809a3561020783c894749e4602bf163fd98c5a8e1599dc2fed9c27117cf0ce7d5ea7cafd3167e93d3b90f3b2ed6a875c9e6e0c6abe7d42f4398fea3e808c3b7174033a238c83965a581557319767eb5ff6898d3c6da8090192cbbcb2b13783ea16422d64db54c18d75610b65d3b62fa32d81277d4cdfffced6303224e50422cc0613c6ad73e39c1e13890278897a9fc662488a9962ffebba368b2f6c3d46958bcb63a6c2d89e5d8ddb85a6c98666f9a092396f1ad16543cce5e90d0c69a8bd517c95adebf7a7119a3c0d468ca28e254baa104634cf2f9ff63c64078a740ad38ccb0ddce88cd530faa262b7727499eb1fa00a2b2d54f1840c8d13b31a0efcb302c12c426a1d63d151fbdf32fc81f577ded8f534bf8af537ebc2bbdc824c3ad0b54bfca6ea53edc1a41b08ac8a7ab3417d5ae64757d3198f065d7236006caf6b477f48dc18455abcaaf39bcb2a217ec0c0b322a178e09741a07bdf5e94a3cb0fed4c557cc3ae4c8d457d258182371d0528558d42ecd45bce68aadaf8636e38db64b2d4262995e12c1f91189301f94d7c02c5da82d0e3aee2199916bac3cec3920524ded2eacaf045511c74034ba5724f93f57d00ef78d384fc08cf8e60c9cbc78b4d6a781f5dcb51620420cbe220991257664b029181c003eb9d89a88eb24c458b5d53542ab180176c69a2cec81fc0b1aa3577e9b67d461113d7190c6ea8ba6d44799cd741eb46b43a8a21b38d8395ec154e9277ed1fb49c36f5b61cefd8365840866a21f30bbe8cd703c41ffa31418981dd4a9aab220703d8b5de65290ce091b8a492c6c1d29c68552b58a15df58b37fe7a27648146c45d10e276c9cad63f5d22d98cb352c470e8efcb858db881be27154be0e4dd033c638d1cc49541deb6b90e5d878de62c58fada187452029f7bf314b3cc7aa8997aee0a326e60cf05c4489d40475d154c403c2f3924b2a85fb9306fe0917b0cfdc1aae13763671197dbdaae78bf335aea8643549df88114b2e2a9c64c2f0e58c92b77eb52d399562977615c4823fe17c33dbe9d09f62bd2f3faae9ddad315e104c5e6312d07bcffe792d866e2b5cc9bd7773b849776fb5e79df2f102a48c4579a0b64420f42aa61024782873cd1087b5f927c301fb06cd9d844b44dfde456667534d2e7a9b1893eb9d020ea34ec99d2ae9c4253e02ed221ccc084159635011ff1e9549ed5662163e43a9e15ebadb0b38fa2161a7ec29fb12568e763a0ad11abc0a8c6c3f41761bf2523513114b0390f8c17a4379c26bc66cf1afdfade28c5e47ae53e36871a57998278771fe257f86643107b93090834ff516af5ec7b49c2b2ef391e0906ff0c8567f4c8eb082d741a3e9f4dade60c97e25c14d17e24ab234d046217af976dd85ae0c801db0c79ae2bd879ea91ba10bce8b456a6c15f38dbe2b4bcb500bd0b5360a4cae179a71fe6aac4b67410dae6b2d65240f4fb5aafdb43888162d5e99ad03e84344b11c4e6b3e4cc20c12810128bbfa01b1304a67e8fd97937f4b6a246c190c9e2ddfc036756b91c91ddb02ce3f04b4045281dad8c70474a220d41a6b30dbc5628564e7497d6dd6b1eb67be7582a3c494a5a26369a6fd1ef05fa0b4b0208567e0eab5203551bf26b4da7daaf62e64f41bed47ead3f59441698f23d23cb67f0deb3c2ee0498fc242adb4dfd3509f0cc4a31484c239c724ff416194a5372a1b0014a96443476c623f0acf8cf7a1d5d7cb8f4e39433d85000a4ea46e9125bc8fd8b01ef1dec581680c36c0e3e867503847626372e8f465febb14b92357b4f8a0e2c71ec372305464dc80318c7e91422e95923182c9aaf70a85db149dfa605184de1d14a1cd5ae171eabd8f3204c5c29e5645701b5683e5615186aabcfa838894c4688898cd2207a88888349ba2e5315fb679ec933461c60fede983cc09a877ede71ad5f54353257b9a1bece7b568be2b2d9adddc2ab2bd1645912c7b6d15e7acaa3d0e762f21abb72ad02c2f02c9141ec32fde3f0ab813e68ebc1424254860c3226d0b88e8c959b8d73202da45f5903981fa758a6e51f70aee60314ec5453ffa682042ee229c88196a3bce40f90fa43ef301c3d9334b319e84a95122d109647b273c6bd3e235e305c400e497b8cc7635a779a2109300e478d3aeef1b45aac2e8901458494728276c1de93b440fe65bfa7cdb3a28a0e2a6b8d7481b5ab3a1745a8db60cdb224395be565738d500660e74a3872f7f0f9b1dd3092339d581cd92118dc0a55b9ac117cedc0d2006c0c44aaacb7e684587df5797192b3598a0b36cc0142469a4f0f70564e3c75155fb885fcddb09202283bca17e72a019f9f2b1b1ac4a2ceab20901b3764afeeef4f1ac6c8ce0af7c97c01548a64ccf3aa1bb0c903ce8ebb44d9a8dd30cef6c79782a82c98478c730828cdb3fe92ad701948899b925cf83b4c4cb381ca30e3819a93bb492241c1384915572fa07e24eef8d65d5a8d5314d415523d219c664c52cdc31f6720f1c48515916e0b2c9239ad3b3c27bec5a3b6fdbffe3c8dc0da90705860854a3e2b59dc5ad3621217054e5d236c726a785e73cd9179d63fd0c47327772164f0cf80f60363c816898f23f281b279059e663aa152a16ab51a5a429a621205b0a7f90aa3c4e2dff1b054fcd93af4b8e249a609de1c5176a785b12d101370615af57a58d742b1d49efc6b09e1ee535252db619cc049ed2adbd9211f379bb06d52cfdc40f4764d139f53c5b65d6436d13d73b481569838e3bd1b44bcb8002864fbe7e1c11db33347afc142d3373bb741d31b6be36e82767afe8585459e618f49a31be56d119939b349020f47c747fc23821e651dfce5e7c9d2b0fba382f9b273a6474249d316b835cea4bd8084f6c2890f2346693326cd5aeffb02485c964d561b07df870c731f18a7f8cc53de964f334b2ebf2d8558a0114d0932c1b06d02f216fd2998dd154c2ac4654e26c0ac7116906ce3b5c5e53aeb3a56a465e500fa852b5ad7065084903fefcff76dec3b670e6df6c8fd273f8c3b8b33606fe52ab7ce0928f7b4d20297d2cde01a6463baff446ec22899386293809d16423231a78ab20dc5c34fd39eacea7c80f3bd66fcfc4f951914966fe3e787fcb2470d05a9b0d50dff8bb98c238f48efb417c47fdd33694429a92b721d2f9466975d14927c1f57f74431dd6ecb2de10db5c2db6756d731ecb4d53a710e095ad630f1106dc2aa109f6aa146bb4286ff1dd3df10aaae9103191a8616f39fc25e8bca8dc3a6060eeef8775c86342fc496e18be385e93a0dbabd9d6eea04f8704c682f204629c8eaf84bba02c6f845bd789c2ceb307c4cef93f18b52c053ccfe0f91a580d1862a9fd07ff5691a63220e8da4d8606bc6717ca9e9db46ec3e067fa342f5d6bea8d1fa70ee09af5e344ae82e743af0feb55060fb58c14175c2fb92ac3e5672d354c270da1a1c179c816bd1b9f1369308f5550419e1086f8e85251081a530153117cf094364e74d26321a9a35505c060b7ccadef3be13a10680c78945b97db88626b5039df99aeea0b19e9e73fb8970e2cf7dbf3d6516f18fe2e783c20f5390b9ae00683926c639c41be4d3a0ae23cb2bf026433639a400413ffbd128c2d2ae4881bbb83679dd935f09f95d2ca387f8369812dd100c839ea189fa6b0acc711cf57029ad7914cba159fa8d426d646cd86d6aebd8f63a4f9fbffb1291f73b55c3dbfeddcde8e669349d9fa884cd11cea5ba24122ea0efebf119fcd8e60fa5104cc03ba2204a73e3dfa0cdc1e75ae158f5a1a1f1222ae3f8d753b3c82c8902d7a31eea7d665cd300582237895836231d39c50681366aed62e1bf656662d715cf5ede9a9912ac1c70d6e048dc41bbc647736028d784e303c62d008ec8870ac588b865843a2ec83b430a2e13e16bedad4c8d7cfeef7f6111366d6c3b086223b782c8347adc1f5851a24b2346ba1e6e98cf8918d437f196d780d02fa26b4b9ae7ccaae7d607cce4733427f89b7a0adc271957924690293090595b9c0011b8270bfa65e14f6c386cb58f04f35f81c2098151dac6c384c65dab68e4a444306559e99d72756b236d7903378c8bd92b7e24046186ec47a336dd5abfe99207daac89827782530be56522034405a06ae06234be6be05bb4ffa7cc921b916d39f06703579af9e78b0a07a5e112572e075694abeb3fd330fa810ded3514f6f1f9f0d59132a0bd03b3750d14172434b3905e67415eacd2ffa6cff6db74a381f737066738a3884c8aaf0100a6d38272e7367c8335723d23a61bd9414ab2699fdfd495b72d90bfdabe8661971f1b1c2bf1633f5170a195ed97a8066e2505405d50e2385245a1aa2cd34ebe9516da4bf134dcaaa41e17886584e8768fc7e3125ed62324602ef989eec3454811c886802d2eb1948d406c6fb47235b9bf03418a48ad073d368302b87a2bb6929a795d9aaf400751f9d190d86acc35ab72e68bed12087d4f1d472f995299139061400924bfdb21142c059f76070764a7fe312c13d98dda8a32e5bf4148bdd4d9d2bbcfd731a6764b17b881ee87be5b7f6275eeaa1cdef5d01557416f6585b87522958b5c1c063b009cba5f0608382d2276262d735785d0d1831dc6f290311e30a6ccd8b921fd8a7001f4606610077030dd8c5f6aa23f89aad5c055e47df0077edca3847fbf5c6e79fc48956431481098dea626348e703da8c4cbb45b9cc41b6057ad3522b1ea43f74a7bf3ff47b9fb0a752b4690b046b7889728487ca631c930c4296e90412163d8540d92e3078db65f59195045d36527a553f3d7aa7b3e70945c0e5bada8036f50eb490ff6782cb3df6ca0b3410443a50bcc3a4e733daab956102fa0d7fdd2053ed44c16f0fcfd84228ea6bd5bd6b5765e00659f5f75211582779ad3498649a7af18b0a49a83386af756a764948451c0ddaee01a3af87535985290d90540f35fd6a4c261b437c48588ce0a12691fef668b4cd186a61ad4310bec962542446647e622bce9895a98c93388e51514fbd8d77dce51892a181e08172507703c356f075c70fe8cef8e0cd768a53acef6c5ceb0d7700cedb52be9ede9e6407ee0484a2dddbb7ff7955c763363f0cb63682f68e039d926d93d61cc4c3a142bb032445e3bed8045846ac4313c476663c90a92d2d7304732b8054c9d74d93f9b4fd31ea18a5b0f3c7ede5f999fd41d863b3beded17ac151d28e9b42e48acbc3f7fc36e2e595bce762bc69481bfa3c63240fc1ac8ae2a79e2bc0e6c1a6a8efe9a97c3986aff71f91bdc824a8dfec9e4acbacb00cc40136bd7f88a484f845d2d0c8173636a697b1011a95827dd57a10b0d4cdef2b85cbe80a3540ebccaf2b133c2660fbab6256b4d5d936e84bbce24e9808246866ba906394eb84151a8a183257747a9cb084a36a557c4e88fb8c70adff7dd24190f50f1235625d8b456ba8bd131a561bca53f22d22b494816ad59a26db4b7cd1228b6381317b3c7c596766887eb1c3c2c6e5b943dd1d6251916275b3a935514de466a2bb65d33b8f9994e025b58aebba8984be1b00a0fa9e2974ab241edb3e935c35c3adda2094577248f2d77ae330c50dd58301a3008b0fee658e4583ab48320cfc70e0061476abd18c8540fb448bd3642165b8980c0308101c4cc642f6f5e5f946cf214c32bd421901a5bb8482a12588ccf1b6e3d58022b666b355fec1192d51943e6bd843431f3f491665e54fd72acafcfbcb21bc721eb15a0ecfc792e0016990b98ec4ea114390b6d656131f15face5c24490a60ba2bf8be2e3c8af07c0e36693cc2f97a6f3982d3a12206c00c717470189cc3e0a9e4a011e52361f0ce3f03aed4a3398163e706bd645963eea34b6c91987b58b1d6a06ace56657c4ee5787b69d1afdf7a7aad610fcfa20462f96e30756c86f76473d42b458853b35fc85e3d34962df299d6518fe7f5cea110bc97e5835794594904253f4eab1924699937c86a210d8b7f0746aa378bd1ef096af5c7061beada14da9b1ebc9df7f3a11dffbae9724db84276ae3c1d1e6db258bed793667573e653bebb56b8a1ddd696adf40dcbc410c9890da4768fee44b6f2e16745a3f5f5e538959c3825f948135c26f488d6b54fd57ba29610b6d7ab2f0297a8e5118da34037ab7e6fe8472e5568428a4d02dba5ad4ec467602e39bdd3dd30d693b51b0da02584db6023870ecb3cc185f6dfa83b59c0182681ea799b27819e042a02ce32ca7637b61819e6bf7413bdea73b00afab62d3c1a02805b5a30a203bdb982544ffc2268befd24b2b1b8f824d3d596c5089111f474975b92497df396feea8836c9a819aafd68a0ef43a12086fba3f7e868e54d8d5552f29111d716bb21c233cf2e1a484ac5213ed57b3000ff7ac5a69a0d4a8f99d46e7cf11ba345d08d89867595c0da29ebfb0118f6f019945d7ac9d8df165442878ef9de099f0dea52f4cfc0e46fdda88b51d643b529700b9fe9960e6244742e11fe8dc7b1f0fad97273efde342c4c370672070e5c945673985dc98d62215ed378c481c94753fa81f23390ed15bc2c3d573071884ea329a6d18f76596826344e8158adcb23e27c27294c8a44e945614721a554325ca4cdecf32e272b0e881daacd94617c696144bf959826bfd57ae432e07ff7f701b81815f165ebcfd624b824346e8c5110d8d3ba2d2bff44309ce6e4630dd0490aa8c40460a5d19b40a1189e0ac50518b330fb72f8eb9fddfe04278fb674f7e25c3a1f5053f8d810c3e2696378e69ac62a4e89ebf71bec9cd092d5cf9a549e78d99b4b9055d0375e4d648493ec7b851d4d2f9ecd5c9a5c56ea6f9db47af58921541f2f05eb6c9b6a881368aafc60b8153334329bf2cbb4ff4ef5e3dec2f7d7ed192ee740f65e2567b118fbf24b1cb49fa7c5d490fc8335e7124595cbbc43a15b49842de84151c8c802d62963021573b44c1671ee8691dc22acb7ced1ad7599aef55360623bfa23682fd75cfa69124fa8c37b832a8bbd8e8c69d64c0d89dca1371947d0b9d637043c4d2a6ad36181a13321447d995e6007a224228e6d7da6eb9e2070739df1b0180a8c3399415c8afa06ee0098db8fb0c51d6f119a666c6a608d7b951f7f345f7c5400f71013500a0d0f1f88e7768e120085a04749b52817666fc3108f3ca01f139dd60ccf00ebb6271d67e5de2c8c8f7cb0dc9e0ab6fb0be913984034df4948553543ee325d5d39ff1298131512c5331fbcc0f50bb8d608f7d37acf27da3ff7f9ead18bd0320a9958a4001903f1630bcb1b753f315a25c3bfb9c5e269557ab4b6be74fa4b8e3c825db0b8e5af71463ea35e97d911fce31b7b27251afe6c44cb7a07e25aab4eaa298c79a021b542fadcf96499f981c98a60e81a4668cdef4684a8021324c6968e4fbfc67b6e454e0ff92f2d661f3ae0468037139696d2c3260214094cc4790a6611b58e5cfdf8f4fbf487033e1cfedf760567fe32d9f2d3d00722fd17971428c86477b389b4f3b4cc0faabfee32600419d965462241fbd5b4ec8bfa87fe678db8a450c92a7492e3eac5a78d9d851dae3e7186ec310d9315c7816b76f0fa55237aa5f983891e2051dc4464324d0c4ffbb38f03aff92b4095027c5dd9c7213fc44295c4a5f2c7b88bfd93a052c51e0bfb9afd1109099af560c6465c1e1f97eb5ce7607d916851e68f5833645b42bdfdced0f8feaf8a600068db51360910804f09cf4b6dbdfe8d198a336b0684e3a3903d22bac6affc04f3c8ad44b724e4ce63436e06a74e3fbbb562be033d25945f4bdccc417fb8a370c73a607c57fa44b7be637bbc111c8686753deb43d09f132b1dbadc9e7fb994c089709422f5ec0967c9631fd7d1fb660a554662bf4f65b107e91b862284ca34d3524daa9a752f8a24f8c3bdfb07c9902053c417f61b40cff4569d3bebcdd6000cd9c2f257d89f5873afc4a62383431fa98e3932bd164fc8f09aeae1219a49a960f5e7e028e6c6333d58351f46a34d8569996501b42d2a09a4512defef8996abf5199b625fe43254353a09b4bd8df0e0477b1e64daf53849b807fc41ece5dffee6f521ed601db64f52c1d2ec28bc4c09965ee4a80bf03fd45c4c5dc82f7653e2bd78744b7b7804aff023704a7338a5ac58ceb7d63bcb10dd0f6b421cc195b0e09001537a4b8921b40ee84c931197c5ae11974431bf8917d02ba743822226ce49f216898819c7da86dfc722f6eb9c6b9cdc2ad78785a0a1e83deda7467aac284b0bd02e9d8b3cb4cdb81b0583ff383e40e1b341351b1b1372c973b7be49b2a754f867536e4421c23a574064a32730643201821848c642f1dd28b870dbec0e706df6e692fb52feb559376e777d301e3a90f0f690e17ba79866f8ec3cfab86112bf63cb12051ee5981a4f8489544be0e7d413b5d2d89e2f751d2d271f3d9cd9b3dd3cbb8accc3beb9633b6dd39348a47f893795b9b4a87d10ccdab75f527d7c5cf6f93828b4f58ccaea34dda1362d549abaa6125969de3e50002c887aa0aae129ee8161182802d560fd190bf121203e5526fa35e2b300d864303233588c3083a0967bbaa611427df830e2eb3644635ee11a37ed24f26e81a88e9a31f021b64d57fa9d32023af223cd130a61d4c7f4518426c826697b75deb911297c8cd17827d491d4e465800f094365726674f198c8310774d8cb31a8e5fcfc66955760059b994166212691688a5d9c563b71e278621ebc145f99dc8543f2e2de0d07f8914490e157b877e538911707feee0dae1ff91d310e1691a079a2f26299f2ab0cfdb9ce34b0013600f6870d4d1c9b23811001f0166a27cb1c5d1883aa314861a78045ae05c7780377c47b359801c176b357224ad9e8a69abd94a362746a59a1e03a8ebfeb09db0f70128a6cf3f7956435d37b6b70222b7103f3758c48f59d5deefbb85f3993d0505b60be22fa816f7f3ea8e08361b5b72f10e47c1d73b682b9990a183b02cb0544628dec51d7f6adec81f2f3c0f59fd770028cbfa699ad7cb6f05a2792f850553396a9562a87c035e3d447c728a29fff2f467d9fc2960e389270f15d08d334610015e67c4ecece854ddbb03323220530a0302abfec30ea7b20d23b11575ad7ead54df87799a83e7223173ab60c2bd017e48168e2c732d479a18bd7a41fab8930e54826321f78b33913ef3549b1ff22d4192307a1a0e88415d815d13b71ccc500d7cecc8b0149db39a2539b4fabd7178380e3471b830b9cbad3118d911ba03d540025c4443031404cb3339068a2e1603b930599dad1041fb24e5a8b6644bca39c92020fea715045ede099fc5ff34f1315cb54c730a54f9a3875afe469e4e46e07880b4e7e832041036e075656081d950d1ce4e6dd81d22e1b4a664fffe1625a7949b1d7f535331be51dce44c5e94cdb530bb189e51013e17caf5382dc4377254f69a94ea5f9a335e77255243096bd6519ace89263cd680f0d3f81fddf44b1f47782b94eba96ba335faef18134ce08d3056d453d1ea03f42a635d385258d225e4c3a0a78291130eddb0dc1bb8ae2c2d9bd50c47f5dd1b218a626651dae9eabe42658a061153d2b7fc3350b72bfa740b3a81faf6bf62b695d0a06862fa36853809d8090baa4a2832c7a6cbf569ac7bb63587cec07e1b6520a0305a7ae668dbe5565e786b1a1c33e3dd1a5624d798058d66b06ee8fd6db8a95d09d37895163b1623cde2b68d7236ea0bd24c65848e39df74b27c54cdbd90f372d26d79b7b31a969bc6661989c37f1236293a5e3c6728694217e20db1dbf1864827cb13fccd6a15a2cd48354fe8005be9cf97c3dd6b6290bfb2061a356758b806958511f74c58155eea3a4338104a1e5e685c6a2a88ce1e7398b6e8f1af80f32d18d1a09eee8d8f55424cb0b611926bf9e9b174a8ecbcc5c34370e52d11b0e89f3eb09b89aecc7a486f70340ce342db047bae151dd56fe111e15f95ad14251f97ce7d7e5e9ea433cc31e0a003aab19748b8549254ddbc10bb6dea49867ec706eaaf00fd577932fd5bae29ddafdd756d92f7a8d2858641f567bfeb374c86c114ea41eda0b9cc89ebd46053acf577ce912af981f121625f505652e2f2ef9959d1a81f59da7abc08a839bfb8fd959f3d1b48c792f167fe57b4f32e5703974d9860e6f058982fa7f43ffdf072354f433b3e5d7091ee56e9fbfa78fd68eb4faf8ca544dc5e007cb4c9220ba71db2b743b69fa75a067b2ba1e61a0a5a000ef699248e16d49412fc0a7c56236688cb07ab79465f2de3110e6b2cce8a617678d1b5fc65edb08eaba03478138fb006384e7a414bebf6f3541ca012da3c3cafc6841382cf3e24a5413cad21cc2262864f68924760bce6b0fdac55bec867d378620647bb1580264a3c9ac1fa43a73ce0c55268a3bc51749877234f0b8d1c84e16aa11f427cac321ab64da8be7a46924d8ab82f0815e73aa6080a981a3e307d2a42a99681b25e28376ef01ca109c27d76fa06a0aaa7abf7ca29e82da2f4631c164872b294bd7a5a1378df40e2038d6a59b5cfa4825659482959fd64a90507a9aca996f8ea2b1b3aecdfcc7c8cf34dfd2fbdb2f80b6925807aac6f19a61268f3f8f9866bfa17c13d1f6062e31627730c9a60be93498bc6dd897584142a47d601e2799f373cb5c99281b248525d41e0bca6bb2edd92c31a74cfd12a223d328a0b3c63677c8dcfec880fa6338ab3b629563acbe7b365ace71394f44f7e553749bcef8953a21ae74684e555a0e01a90e3049454f3956a0cfb3859faf0b2a088036f0edb4f4116aeea0d14279319ee429d62278608076d178717fd334468d0bb4304b4a2d58f1e29650146a0ac2135a7b403488bf606c783dc63ee184bb0c22a32594fe908d68bc36aa4a20a6740b6c8b3a1003a3cf70b5a2ceff603b1d50ed2567c47bbd51d7bf589746d52548ea8fcb0c4e7ce02925a0d90a72e23dc921fd8cf76fe797db519c841790ce6f5b250ed7a468e82491e1c7730596aa98db4fbce61e117387ba427494357d9bf6340b120deeda6fd1637aec046e96233d6384f6234c26ddcc5be6ad9acbd7e8530bbfd98a1fc209abac28556ab0066b8bdc144d96f63d562d94999a8c4db1dba442e117e3a8da4977c529d2b4e8ed1cf668d7d9841cdfd9e770102bd3fbfacd70aed70bcc5d66a2af97bf933aab4d5b25150a3cb23d9872bec84fa15f6927b327d8b99c5994329260f8be080d34f1c08a31b7f57c0212a348d5456e9379d0646ba9fddc40ed217be3ef95c1be8cb201602c501658757cd1ac3774b9ec83e9b2f53793952e67d88198696f2be13e0481447b0e549868aa9d626e79dbf10eb7bd588ca6d83b8c84a1c7a826524cf875f6361d69e2ffa284b4fe5a59f746e041bc2a507dd35d109dfea09284c998ec9b8db4798d3f67497eff6547683e77636506baa80a64c38a7dcd1e04c6c85a59fbf2eef8867b68d56a63b3b97a05513b7856b479f8f9cc19b9df82b450df9a7ead1120d0489b8c4efec776873df53cee14fd346211c7faba70b1d916753dd539a39f28564c0f81db3df005e7d7f7aa75bdde2c5ef950320821decb7e559af1f3d493d455427b7a2663ea231db8496d882e4514e834f147bd0abf90f88c455326546b63ae53f46a70528231762afe0982437a03d55cfa7d7942b92bb065ca9596786dad59667e41c648bd11845db607ed34446af52d5b904c7648e3651efa44632643bed3cdabac261751086441bc1056d9beb7049265142fa67f1bfcd7f53a9a96402261de918abff4ecab4e1f892aaca60abff64602b9a36a5c3db1bbd56f7d19dacf413b7ba6d3a34f14b8794a2000f076a9d14e76b07dc4e935cb476b39ab1971b9551708d6e105594975075622a7f9e8419cad9e949d198529733409554f9a417a57dbc997f687c02875812927a63ac7ba20cb01ab62d5ff7a07a63f1865f351b1a96c04b879fba0e0e5b8dd0eb416720e22522c87dc24c5a81acc0f049bef6fc9042fb0879cfb18990dce6021f5f0c388c9f47e9ca2bc620f8733d79d9f22e78b3e10d8999b7dea091271c2173ba4127ee2cfe8a3d822201cded60fe80348d1da39bc3ace6e7a06fe3f4d59bf74305680fcd2a7ac996d0ad8db0c9f80c7daba3a30fd23f365b89630cae3859f9ebf456c5e6eec80d8a15dfdfafc2397f845452458542b29fc398531596022131c453a1a9d01e3ae648137221bcd58827488cde7c2aac286b9a6da4e1a0b76875218fbb1cb0ab7dd1ca0a39eccee6482da315e09d9ef62ba06f8a7211600e08c1e8f2b5e58e5ae05497aa3f94ef1cf2aa04236e3da08387f87b392fad20ce264e849ca9131ec36bf1bbc267fe257e8d221f9e0abc3664a44302c1cc1e8aaedd3d944f3c4cf71475b0556b1e2e2db163f6775820e67bb2ddae8a5e022aebee51aa881864a2d7e79a0bd993e6c391f8e6cbacc3d7754422e30f9c794f96cb5fc738578f64d52f5e5cadc0ea82babca310ceb2650450b0ecfafd68f44624568d5a832ff0b20e09b267a40743647510713869119a569bf42f48aba5befe6e7fa5d1d8ee8ede73d767be88945c1cf3d96853c8eb63c4885df9fba83dc2e66301ff28a340d81ec72dde02974ff5b7d2ee8a7d581c44ea1c1ce3ed1bdfaa3ffc876341e03da44b67a5f30103ae21c8973935fc0aab331d93c4574915b608d76da0168727b24bfb5d039f16254fad44fe99cfc8bad2bfcaaa0d407fb9eb9a2a04203c121d5678dd8e266041818155cfd33d52efae1fd632fffa0a5ed6ba15fd04f4b4b9b4829a594014a077c07e10732bb83be64f45d23b7f66bbf8cfd8f9e7270c0f880f0c13fc1f8e2eff0c1df4f8ee0870f7e7862f1b4f706169129a810ae1dc778e0dfd37b0bb2a74d14dcfe35bf8e42969569a83f4dbd5d6559bdf9ce94d5d390d57178cfd4243eaba724a829095f8fb91da1e4de7ba4db27b8285df720fc1a08c7ec93238a3abe444627d8b0c62b8f4eb0b9d5d38d2290579509631ecface6168e80cd11d835c837c3dccab2f0471b3bf735d0de4058061394b34f66c0a3e35413e998a40e71839e6adc10403dd54eb4aa753dd553f0b5d65a7bc3d38e4c08d3bc768cf58f6abc52b9b51fabd9966fe9ed75fc62f821aee35cc7e3c9ad2bab59a683807429feaa46753b5e0f28b730005c98d9242bf061891326924882c80e7e6ddb359ededbf5c1a875bde0e2dc6cb4f07bd36bb7353c8b0f3a6b627fd65a6bad15f7cfc036cbbe9df146e2c70f204076b2be3b353e176b80b3c0730bff6d81b4acf4cb5a0be1b85bbcf3b995f100523330f0d4f6be1a8ea556ad9165f8f55bb586036cce7d8cc7d1aabdd4aa25b02e4d02ebd229abeda7669d0ce726f80d6dac5c1c029510dcd3cf248d9a05320aa6cd2d6d7bb75f5bb72efcf8af12291a5823fe4d2bbbb6755f144b258cb30d64be9dbcdfacdb47472c64c73e6a736e7ad3edb76cac65d1cc4753862ceb930214d0a2023601a3149001d7275000a3f9532e46f0578c9dfc35b2cce24eb06a955ccf2fe355828fda9cab439a75fbd8e68cf84d3b962090c38651bb79171f7f69635f6cbff8a18de917dfdad80c6eaf4e38eb56e7577d7ffb77da3e8294195906c306179ef011850a86f0ece42f21cb2c153da22696cc5a40450f3b12e80187157a047124070e36781c31050f37808245490d0eb04f73c6d397eb09aef1ac083205fb21ceb5fad32f621cfe0786df8ba999c726aba3d665b303f1e627747a0c19b83fac09d0ef0b1e3ce53c05e2183164903083a71e846e9f0c51c4c80f3d45552058bbd8113c4de527a1e38fa159b6b553ac9ea6b449ebf1c4a7b5fbb476ef1dd3cfeaf9593b8d03b45b1bb26e64c0f1a7ac7ed39bf0d49432859f5f5846986526dcca1f5a1c9ac29e9ace6c5712df7bef88c51c66fda1d5187fdf067598453c5e1df690a8d6a166cd6054e79cb32682b4ba6e538b1be1bebd1fde4fdd7fe5a2c87b7f5576466a466c34291fae4240eefb330bff4d89d15796d91082480c423920424baaec1440870f328841880a831876f27f7e34ff49099e7ecfff58768ba8a136b67bfe05f8f4fc40327a84d8dcb7ef06c2b174464866e587c183a38fd1fc2f2f7cdf39a8d9ac7fabf2dbe8f903af39a3076eff9ea96ec71dd477bf272fcb6b869d1c91ca6b9262bf27016cc06da469d61b63cc736befbdf7c390f65fb3ec64572120bd5ddc18b557773297d77e1e1900bd1fe99e58b4c14b79cdeff6ecf7fc6e61ca6bce18c2ed93d664d226fca58ec78e826b43e33205244ccacd7671ac1501bbaccdf9465b9b1dc297a5d602b3d4d030cb8b51d4720384115c7041b27a4d4d9019d0e620a7d6e1fbb64eb5d63a6f334683173f38ee311a94ecc394680193b28279a131c1cca8ac8da9d141a6a7d65a6b513a954259cb42e6a47aab32594bb385722b4b0803a3d76255fa1636fed7ba347739cd52e79cf3b6914e1a8cdea8a6fcbe128616d285b5e20b6badb53a07d9597f9a73fefbd9d810523ce79cb78db5d66aad61526c8cc89614c1857144b82f1cfbca594b5a783efdaec5649386d941b77ff95c6ca3ad97405ac8adb5d696a4081f88dfdfb7dcd27bdc34abf588cc2204a336a6f306c2684996b550ebf04cc31cb46da3118d4cda910493c26f1882b56e5f873cb460e90b5be86f98520cadcb7ea86d18829f5b5926d270eaf21b5e7bcf348753b4160ad2fbd6edfd187454a9e733c5807d1196c0a538ca5129509e6528ca512950d4ba6ed023d032bc85fa535cf38cfef0fb298a61f8af46ad0ba33728daafec062d423f128af1d7637571d6fb03437124cb11c985975e604c3127544a86856a8666d5e201b0a2f96f844dc3b28f4643639a270c9a9999f3ac79cda8543535231a9b25046714c3510c37a862c18265bfbf2c462199f0ba00c1954a8150da047110460778711396a27891b339d9e67c5956dae498c8ac1fed7f502874cf6821f47b7e348cea8f8642b5cad68806f821e4efef6e0901df86af9a647461eac9330dbfd0fc6ab01c7c347d636242b0413b79cbb26b522f4f8807754c0275ac9ad42cfc9a5499994935a9fae6fb5dd377beb871816063625c63cd8538d4ed8bb8551f85ac0b061463328980c3fa000a6b0948d0c379d55cc0023b0e6c80f78251a6b28cbf1db99439f9ecf6b999e2e8bf8c17106c3aa0863a8113608c508a9f79ed480abf78040094ff61c8535fcd6689d417a3dc349bf37d8b6e52b550697eb4d048c7ffa546a18f96226394314634c0ef83955ab539379b138463fbef8f4446a155bf67d701d7eabda1a1747b55939a6532aa49d56599ddc1e12933e5336576231afb94d121e1e987a3063976fdc38163e9b742ff56408d0c40d3ad58d19e90d19d6474323a9b6361341feda3d9f40fc26fac24e56c0e89227db48f465bed46c0810901b6eed2ed93211cba88b58e2433d62e39df28c1efa357f0fb1bcbc6a6f2e621373588228a284643bc4c9c87ef2dc3b4e29573ce5878f487c42946090e6a759cb25919f61172f3c13e9687e1a752362041032860288e245814a2607fe6dd2147512884167aa549118c1ff0f0f0f0f0e00c8a63f8edd147f4097dbea2bd41739f56098f0f1ed3e5c1390a1f1f9f549326fb037d3e1f7d6586297c7c7c709438f84d110404431004c10f0bcf14599a4c11a4087c1a53cce0e3e35314040f0f0f0f0fcffeca253c9fcff6c12fe8fd65bdc1265f91a813a3682c3c4c680de6ffbe6f6b2c3c7868c44b2ea492248bca717c10144752db28f9701f17d24d9491cfb63da9e2a6cb94f4dffcfa6cee0c8e70d2c4081c4030c9edbd7711fbfbf60782dfe62187bd73a6b277ce5496eced43849224488670430811c411208a6490338f11a1223ff8b077ce54f6ce994ace79ef9ca9c0d0e014c3e463d91cdb77437ae0e1034371fcd66b5d19efcfa4e9fb0ccdbba34d2deee41e4268a150ccb0423143aa64b2b2519d513bb642681853804579c44a18d52caba1aabd06139efe33c184bad53d43f16305d8588d45f15bf4d6c8566d759d4aa0e76bc5ae4720f6fca16de9afc935b28cdbc7af5f9b39e39c73ced78ea4cfe7b3fa03bf1d6a9d4d62288661a8b7fe6f84007dce9cbae7dbfbdbfb64f5f4a0ba85516b508fa4b833f963fc21fe10d7dc01fddf5e808d4d424f6602efefefe79d73d618875aebdf5ae33c4280ce796433be367fee99861f3f7ea49ef41c29a208bdbf9def7fd81d285420c58f1f3fae2871297c40f0e31186df073ee991e20a13297cc4ef9322abe0c78f1fab504f4f4f4f4fcf2e439b43cb81f7dd6779eacff99503bdf5c744d489519ef42ca1f5b75713653de93952ba70d2881cc51d298ae05f91a65f1b1cfce1f28334ca953ff68e1d647e8bab5b2b53badf5bd37672bf3e1b1d721082430c647e852040a80cc8027f4019191999b7b23004653a46c5100422f33100593b90b5830108fe00e2f3e3053d379e1b6cf021f33735c8fc7ae3829e9b1e37b69b16dcd070c30290b50359bb9799b1321064edf60c26a896f56f30049c9da622be0c51e9f80547aa916a349d5403ef7749b51d528d5483a9651684d04261d42cbee0e21a6a975bb86a9cc6699cb86a27b48a63d7f1cd5cb42d9cb3a6dcaee5d09677d098cb85e3143b05c7d2d10636b039dd2b21e7544ee5544ee5d4d84b1861c677fa0689f38886f8fb1c41f19a9ccb2021460aa3f8598f8bc81736f316b5cee6807648893e5ad1a22816dcadadb88ddbb88ddb4a766ee36e3270390789532653a865294ce39e267d75cfdd645d2693cdb1575259e71a20ef42ea14d34df9f139937a243c254147c7e6587b71e0425996752ecbf62ed2d396ddd9260fcdbfa3546a6777763b9b63f76ee7c48ee32ebe57ec5bce0b4fd57aba8382c621b266c7215267aba5c4b5cb17861ba6dbadb3735c1c5ce3b16d181d7d461f1cfb5eb679e0d6ae7dff9ddafa086d3c725c9dad63870c35175c78ad95b9008d41c01f7bdcc7c76dd350430fabb379b80065d9b6d95c803ade36972340b800213219836cdbd8137336bb7df66dfbd83caeceeeb16bd8346c9b0b4ef78099e9ab8bf4f492542de4a3dbdf3c6c42ece8f6b70eab231eb938b836c282533b1ead381c0e273a11ca29397275c4a124d6853f1585e8f8ad888311050e6676c5cdd94026399ba3419bca2dfe566f9c83f82568533796de6f65314647f6d5379f3162d81c8b592949bd593d84459da8e2167e511595a462929e847403bf25cd54d5e6d82e46119574fc4ac41c968951445554b525a9f9c97e5d6a9c8632d45f7debba36c7b2308a9af2b3bee86f58077cb7d65ff999fba55ff83502ca32326f215c968d6f7fdfb46a73c0a7d2f1a730aeb80bda4136c7ee20eba2e941a35b9a296eeea07d04a704a3f84773e74606c0e9d966097e5f0cda2ccc5e373bf8cd22cc40a3c1b022bfec7fead157c72f9b9c7bb302b0bcd1c1efdfd4f8fd9b19f8fd1b1948175254abc6f48d1b810516a98654dec450dee4e0ff82dfc050b225b1859581e0b971b985fffbb4454f531de745188620e727aed5770ea330232f30ab1968b415108c89c61473a30254c8730b48aabc7981df47ddd0f8fd1b17666e5ae0f76f58e0f76f70f0fb372bf0fb3729e0f76f6ef0fb3733eea2fcb9dd469acd152e5e20b830b6c0add605e309106c7e805a1b2bf87d9b2dfcbe4d15fcbe8d0f5ca50d155c041c8cf3ea2d52aa719765dfb971351bb7eb1807cb01bfff7abd48a9d44ce3172a5421a26e55a128ae6e55219fce4daa111f29d5088f8e5d6243ba0176063afa7d128fca11a4f0ef8fe2e7f8534fe8171cbf37e4a91b781a83e7d6bd5fc2fdd77d1959960029aab06108072d4dfcb07331c6a619980a328572d6f35b56ced97ebb7beffd18b5eff7badc6bf1bd17638cf75ffd771481cd2d16ea37b5bb7eb975d930e34c84d52967ddfe0bcbc89b8c02d4a08013b5e79952d7f3ee6a7c83638fcd7d4f6e5d65ca537946fe12f2bf6460dc6ca691206f11b914a849cc8620bb55ab10e956ade2d3ed7fddaa556ae8bc5bb50a0cb85bd6791b9a3d8ea52995ed1aa35bfcd9bf81fd354ef854df5703cb4cdc0919c031bbfb7e13dcfa4ee1e87b7f78c3404df14f59f56739e6cfcac491030abce28a2b7672484105dec9cfac12af74a5b4beec605bf7ef0bd08bd00b1016bd7f656eeac6dcd11defbd2fb87eef29cac5b97fc57bea5c98a428580461df243077c549e7e1188c894531acd62bad5906d3f1b2038cf6029465b01b2f406c7911c2b11854e0707a5a5a4b6b4c691d95d6d2daa3b4a65e705db7233a45b93a2f1d58e9f8c553948eff9a3e5d4f61d0741845e20565f6eaad45bcdd14fc8a8251d4f952096043089a3da0d549b5eb1835aab1c2ea51a303e8fe7d36477d347f584f9a3f2e5e74814f4417e7ce5cb052508177fd200c493d992555b5537b0aa3f6a26271f0d79830683066b9d5d382d1d57cf15e44af9d75bd74af28553afe13d1d5794141e244f49d2fd5069e92d4924db5abf5342c4bb05c6e615da48b827e6e3a5ee0a916a66972d27c6ec26c268c665d26ac87ad75d80b1676c3e2e8b99f21231df340fb9ebe54ddca7cb5e01559d7cb098bf382620998970a33a2f163b26031a2f16366739be69774d1d511a75c9c15c7c45d161b13ab5834e6532cf272ab88958d3f76bce5d61884d19dc4c6c62138e8cbebde2824eaae0ec9c9d575fc3434c873c5c328143c7ddd7065c250264c090c7732614253ae0e6cc8e2885560477638063362510c4bd2f1c7885362ac660c919765b01b3fbd8e3f0616db8ad18445f16358104e10b4a77f8f948e8edfe54c39ec858eff8557eb69d8d397da5f2a46a338b93aaf1abca49c4e3ae6276c665d78c53379d64532cd1569ba33a54d104fd17093a6e7d37ca9e66b8af97af3c5cb2dfca69101707a78be743ff095d962c66c7196ab4ef66c7e23f39a3cb72eab66049e2b9e0b5527416861ead96c347f564faef88b72359a3f2d5e6c71ae5634df6ea13ab95ad1d0d068bd5a318a57bc1974f6dd983ae912452857a0a971ca15d8c1f1748ad9df067fdfdfe01713631ad150ed543bbdf5a7dad91c4b237d1b06e6e5e5a5b4e261745534a2412280159ebe545ec7ffdae1981ae5a57b4dc1b1d403aa8681df7ed11985af9d21c5662a5c811e99f69ca7f779fe9bcf0edc33a56b82943a75730e311a05c77f9f8ce1c0f1eb57e5e0f853cca3dfc78901c77f7164acebb41d4ceb33705682bc6f4384cf7ad6856f0902396e9ce069981fe75a6ee1b7ad37dc03ca41b434f37a1ae65a96e15e38e3b454cef986f9dcc057cb5594a85270aa9420558a90dbc4498f1078dc3e294249ef451cf972aa1cdaf8e1082974bb2655849c000222c5500fa6a06d79819b306a87883c01a20b4243112a86ece0062ff841071eb0603b55298c5e1c235c9fb51e09884c606dcaed132644dd6ae9f6496eed79c40031a8b3304a66408505a8ef706c24e2e1d84d55f8732c2d4e860060dda62e30c69d7c6b8e9fc52cbe1ed1184f0fb0baa87df872e083319610d96ec4ad7fea9dc9de87cdc9fd7e0670cc3e3182d6ef7f4e368063a29028fd7e53fac5a4d4465f00466f0debba3f83847fb62f87b70fdce6dc7e3f4d8567f89d319ee476b4198ed19b403ad3d00419b319111c4bbf5cbf332cb347e0c83b21a0b061198ed1ad8620faddfd3ec9f9e8f72f108ef17eed9322b6f42b94b1b5442a8ea531744e9cdcffa2e0d806a2dfffa6e0988843bfff11e19818833ea35d6bea5f408cfbe53c60770bc0a80541124b84a82571838524ac134a8ed8b0a336450a6298b560831a6e5576b060633171c10f237c7801908e2148660054050eb0e06007315c71e586a11e52fc0879d9247ec8a1dea0c3f2821319a002a4a74991a22d30183de0054f6cd13193c10724d60a229d1245acdca0cb61019e65a4bfa3bf390032c4071d761002fa5962272489238c40421ae119f8d6b22c01525e9061880c497c9802045400192227831c9ae0653303d66583f0476f6decc10f0b84c0010c4cacd8a00187102baa0cdde003111b4108294143922d3bb4200614c0a8fd2ff7e55c39887c96c0b0c4c78e0bf0d4e08829a2d8e1086f079b256621e57b7d9e40ff3e817df4f1836f63e7fecd65997e13be3f4d90033e4dd8faf7a9c2fbbf9def6decf07cd7fb28dc27c10c1610d7ff00bba34f9b5b19851a61ca04b7dbfb5418f1f1c44f4f103d5877ca9ef17785bcdfce7bef9c73ce4b78ec0c74943b1af406f3cd39df7befd55be7d74e0000081878c839e7167aeef776e7bdf5a986d5dc1414a7e68af0932088608c2ffead738963a9a9ef3a4780f99d8f67761a6718744d4426a8ce61ac6c86bd314bf6947fe20cdc050a144bc025475cfb063c2452b2809341441b1ff95897c850c592158288f08116229c109b108103229aec60157153111dbcc461af37181091e39381881b4078198538c4491e84347091ca9315a8625032c4b7e3badb274a8028c2471e7e54800252e2630525319c4a663198461a2fb5f0f8c8cae7c3b91471058ec2559164c86622c94ddc8197dd3e49c2636fe164b74f92bc80c4969e5a1cc7fc09122c234fe114c14d34fec24438030ee324fce13243f60e90e030b680a4053db5b8100912157c40f8c88aef063f590179433400553eeaf6c910115afcb6ce1637a300252c6048063d45558e031e1e1e1e1e1efce9707c6e22432b9a3fe4d7dcbeef9cc1e8cff835b7940cdceaa1c36b5938765febbdb3288a6118eafddf08015b01afbec1effbb4fead8057d73b6a82b0ba0da2331e92a2e9e853f1d3f153b2bce51d91483f22dddb4bb12c5f2ccf7134f10786e183e13923a3ddeabc031b3f5964b821c9ae071625ec9614a440c8ae8917dcc0126489110467f03da7b0e24a0f3ad478286200961b20b10148a887243040711281b8ed291fc11f74008a180a33b08bad869e6eca619241c7cab6f2b1aad99cf2c791066773f6f76478c8d8646e594687d571e10182abdacab6f281d1bcb5de5affcaf6633cd3158f8e1faf7458143f3e539aa131080dceba7078a632403237195b96e1c1e3eac8e8b038672ab3c38506999acdc932b48e3f93cc7047a6461a8d4e199a0c6db422710c1124b72168f941922a2b604114183420050b152b3f331c78e0b26ee1321eff7e968e54967d8f651400cbb04e72b6d765c541a4d65f96398fa4fd11ebbff78eaf31fa367575f089c23d53b0aefd038081a716b7de1e36f6286459b8ffe2c031f2f75f5ab97f0336e7fefe19cf019b65a433f569f8e94dcf9c73977393cebb89e076bd3c2e6d64dedacd7171987796652888677ab37b5874ffdefb67e0d80ff8299b7d7863d6f593b70c43fe7addf58c59c1530c946a5b8a7620fddf1af21490cd21757d7bb9a59f877cbd6b6e696ddb423c05ad0a24be7e0b6419896619060aca2d9b133e8afea774ea754884a7d676712bd11141d8c3303c6dd6f0eae40f3f1dbbfd8bbb3af9d4b68b83c4e684a776811894652884a656734bff686699b6e5967efd658881469c97a914f98fa617279e3a975b5b787efcfab54d3f0a28fa9fc333fd7e6f2d8f331257d34f3ccd6ad482ab5c4c30b71ee9a5647b72fcf25bf81d16e28c4aa552a9742ad54a8b4abfa032b9d97898bd98ab75d1565a74ebba7e69fefc6f13d6b3ae588e182d36cbad2d18c545bcdd4a9a3f38542daaa082c5ff687e0baf1d16dfa209222a576ad6858dd8762c5aa8ced72e684513a42b49f3c76c61e268c1aaf9f3082e49996bb9d09ad57664ee92035b36f3a5030b002b1606150b6b71be76b523681214571e69b5722ee7924373209ad3b996cd9c71c9654daea6498dca9a814563d95835a450a7189164dd6a9ad4e46a54d60c2c1aab06962d55a3a26ad4538d1a53a38a352a59a3b26e63b9db99782e65399e7aa72a5033d4102821540ed50407fd1447a93ad074aae2d443cd5043a084504d503919d42c859aa150b3136a16839aa16628b5f34c269752b7d3f174b6955785a6569eafddcec49b11599839e827cd9f55e9f22111ef8a0e0ade9aa5cc23ce572bd10ec6cb2da29d75c1a89cae4c39f1700ca644958e7fbcd5483a151425499749ba918eeb483a92ae8a755121c2e86ee7627231f14af3c77cd2fc397f347f54268e1c4ce5e76761ae597a458270494e3122d97bc9ada7499ab27be9b24ce918c7604a5814c36e305a2fcb603d456c415906d3910496038763b0177a31a5de50a9d7e3a117a4c75f727de6e584d5743b1d4f67db55a8d468b3d7961e46f1ca894ce76bb7eece196fe59954a5f9738e2cce75e5b3d3bc4149c7d3dd562c16c706a306830603078c167cb5ae17ef459465bd3a2f2a55d69d6ec7e3e9ca53173d519a59a9564f326140d665b3ae55905b0f1d16e5d17550980c19e161c75399afdd4ce984d576ab1569feac7e74996141c4bb22ae3b00090141fe886361aeb4e0165ead375499604422514482a8cf4ae2388e23298e6216c5555c5d566debe96b8783d5d6ddaa5bb5acba5545d3f368a5315fbd51f52c6678aa9919b345cd3902552e6648f347f5a58a85c9734b2573d2acb4a878bb75e5ed8878453c9d8a8666665d753b225e916e464b0ebd95a47bb1aeba1d11af48a7ba2955e4e82a552ad00ccb199569774ad2fc99f971265dad445e3bebd265d9086aafa7afddef667dd7f18b3366985bab16de6e5d793b225e114fb76ae1edd695b723e215f174ab16dd6e5d753b225e916ed5a2dbadab6e47c42bd295568caeb49074bb75d5ed887845ba10fc368b5a0a9f50e4c666ba4867b17ac528ae79a12c33c3f3ed6f1f1c7bc1517a8b3abdfddd6375f4a7fbc7fee95161c36275133d2a330dc5ca746f17b12dfb7ac8ca7650127da4dbd7466c8cbfe9ed6ba19d1bc5b7ba17a40bab23ea2ece082cedbd186bad75df241a3b8c39ad8a70eb67f56116d88d2d54e08cd852b41ea9ae032ba66f258e780486bce4650d4c27cd9f9adf268c675db02db01e6c851561144fd1a9e60f8ed5b710ee9c573a7e58131607d7a458dfc26b87e64f25a240b141c72c9a5307eeac68e0a9eb968572ebfe0775d7ed060afef2229e268ef35f7c0baf1d10de052a040d428788a8103a05bab666ad15c89befcb2db5682e1f9af7525f98af1a5800e007c17c49b130f0bb305f502c0c7f68bed6dcc2e7f9522d0cfc2b1e0915820e41834454082a844e81ae5916034b6b85a2184da0421915ea7954a8840a81a8508be6f2a15d3e7806e2b945fa805e5e4a3d8b4fd6e06a92d4e4582eb066ac1a6b878a854c2a66c4b2a1402388aa495283abc9b15c60cdb20c7683b5630bab866331a8c0e1184179f820a91e3eaac9b16c28d08802c1984c5924330c0c39be785a4f594e3d541154100a874a62d1fb339fe2a09fe2a89c6acac882a85396d37aeaa18aa082504950b899534f75eab138f5644ebdd499f21ea71e2ad7f1b3545346aa29600c48ded1014691d437d388868e69b17fe4d269cc1cf48fe68f499a29ec5721ec29a8c0fbcb974ebad39413132349555951ed4e44272b3828e72bdea9288c825bf8a562b405fceaa2a8d675d25d1d18148bc3c4690a0c898e7fd4755c9b9154959593951391485249929a49aa0b4925a9241509eb826271f0eba2b0689f2fd5ba30017cf094f7ab634634f6c78c0ea03b0afcd2d59ad449f387f5a3f9e3e2c59dd8a8542c996c7a1422a20100124316000020100a064462b15818a49924980f14800d68885068523c1788435110a42088a128c618420031c0108490518688681c001ba6d72f52f88b090a94543125810405fb52094e054d4357382d0538373683e841c56a94d50560d69300a3a709262ff8372dd49e6594ca567882766aa6c7f468b830df84b9e9380e931653e5c7eeed71169d92159dc254112b408904af70bb82893e9d8495780f751fbe45fb462c664c2c8f8e2864c460fb2c79f129da7bbcd45ae2103ccb695acfe2e46d975fb7d80f0c6ee065428a0c7472935d78f529b5a70946de0a4b91124695440bbdcc9171cb7e38052af586156b88037597af0733909ecc23cfb64ffce5e3e98ad5fdeac2a781a8951694fb8429aae072e878ed66ce7f9e76db9914943d67cf10a18ccefabe86a884829671a3f210046e715f77a9d803972b36b8b8364e3e4f639b910b7f2e1e276449a7bafaf3ce5d57ed81c3efe3b31bbf567fda4d30c7fe6f558ba15d95a410a5c45028895cd4783d988b99483275015a3007f5056a6fc4b54996b25b09a32d809927a8005fd5b2c4edfb04dac4e5994e0d7018d739808069a10294153842b8854ed93d11a8d52a0d1d90673110e33f7707f1885278cc25213a47306ca4b92452d0432cffa868d9fa99c492bf197c642ae529fbeba5c7cba4ae582ae4b68f4e2342e44a902d8dfc3615c3a075f3aef16d01dd1138567d43c558d2d2c41bc80b9f9c0d376621b36574158d444ad25c4bc2d2a6585389eecdbfee9296d5aa7b85f07bb60c6f71b7091ce8097914eaf2f6163ad60f62cf3ae436567e62f26ed1b028cc459dae074448580498d1245335bd17913ee2386a340b118efba2e82c66281ac8cbc2fec3e2170ab03ff5820ca2c5c2f48feb47e6068ace0eeffeb2172f57f36cec4338840fb4c547d9f45ab0d74ea94b67e83436fe5feb1a6758882005179407a274e72822a43385bf50f42312189ff56ea16a16473733496c3ee8829a3852e4f2934acb608a5db2d1f9cd97e9a798c980dda537e791a9c1c88fc26221b239c070e9dbb0429613d15db973ddb9842252b5e26939dd772c642b8744456a7de20eb511a7ea395cb20f465bd343d8d7589355bb457898afebfbc82df47906bc5622b28f29ac1831cf36e8776eb37c6511552f11729ac68579396d30c39f9e4da50fe75feb5fa0d942565f720219ad2876c4b7dd5db42d50342d78dc37accc10362626c275c6d110e1622399bd7e5b64426ad34fa8e6cffef4314df8bc9bdd75b64fbcd75be28167a6ae7f158151342dca87c54ae18a6c93d3c6f1623d67cae73f3a5fb608c920b9bee3e43562f20b62ab3212ad75e3f4b6f977e10cd6942c9889c55a0c5f94330a423e815a13778e235afd5971c15d2b63757efa7764e25c01e0c0b8be40c60764dfd45b5308902212e604999cb845b7aca449ae1efcd92c0d5d5d02ffaf827581f0567e334884038c65f9ef77a062961f9d0250756bf213f024a4b42cd0a4a5cc2acd7cd87538c74851d707e6458195bba501b6d798c0b447096d34ee420859c1593ab56c4b7b4e828ddee1de4a5f4ba6b6bf76d5b426752bcd0e4120b5ed2b3824d46a891525847e4c259ff870e19bb0c84af5201ec01a28a46e5ec4c610011ec5dc28aa5832a0dbf03af5e9a7855eb5fb9a2c4f14c38500ccd66a49791278a495988c3f4b2bfd017e41a328dede253360c7c65970e4c400d4ed45c39dd1dcc554b635fe140f8cbf5bb19b1fa4b191d96c9b3f543fcf7403f413b4e6b4ac084476c5fac65b56ec6cb60deb1a73e6bd6f551d64a59d942fd82185a64652ec1fdd43da542f6e55e2ca8ff2656ae107f08da591878a2d7b3f838fd400d19db70474032aa492d9c9cedba3841367e8e65d091de59a6ee81111a011154e3978998dcedb24db7856e234f9b9091c6ed16993bf6f848071e3578bbfc3b3c6e61a12224ee092a815763b62a88e511229456e8f48b06d742781633e34bae34265cba9d654122d089c3d08046eb392c799c02546cc056520b59512cb099cbbd1fa446c3c550406e260814d2ef08ddbfc326c95ad4cd407d53af922fd78c61a04f5681302a4ed154f8566d49eac957fbd3561adb65bc5a5b7e1c626f24006d1e1e5a713c931692af91a6c307bbb230244b6c23f74551c048d21bacb49f6209f0ab2749683a067782aead546c562955c8a15d2b17d60766b9ea0f9a46e84ab50f3ddcbb75431b91a1466f7df5b3d638b736b6371344309a66dc12e8f54236801299c738ae733d716f6ae5b518285d76e20de3f1e5d1b5a15edb0db91c66b11aef931ecaf409712728e007f03b744c1e6e9976b6bfd9ea9a286f542f4b5ebf521cb4b143ebe8d0a4d7f8fe573412fd14953bc76635b9b815f97509f28653b26e82440db791bbddb06c09c47eaa51df4ae2aee508d2f750e43db15598f8b7a07230648f99853f4afbf2cf069dd54b0f43507041a2fd2bb4165e326bd4b0c505964061dfdf1b696cb7939ac32a8dfe81d83bf30669f6e2d20f105345a9f3b7983fefb47c018b29cb3b5646d26a1c22088ef862fc6c9c9fb5f381da2376600159f2bbf5997854e8d912fb25a6eba88daf5698d91556c6f20857cee155b19258ab2b21f52cab5c3b283d949f452dba29723c42fb3d4f3ac1f67f40b4df49ab6547b55c21986d3f12473eb8285ba7bcd60af277958dfe48fbb97ce86cda3745fe548554a8f2d8a19321126675326c0c71433a54cffee6d2f81d1d617f34f67ac1d9be6eed90fc4afc63c42449a0e11727e04fade7657a0be7e4757a0280529dc09e73b85aa16f5b1c1be774dfc949cd9fa792b9b339e082c5e37e4eb1a4b56cefbdf680ce8b7a5762a6a011fa12e80fa5ecdb7607c789dce050692342d916ac066d1a230b0e9475bd8498032a7415a2e484c24bcf830d48edc89ef670b56c4b7f8754c9381ef7bc5dfbf5fa5fb491421677e95ef80d19cdb55c32b0677e10ce48fdd576177737be3afe036f74268803f092a329e1e4afc31b9d583a645683bbc01b2c5ead3f69c6efc418b333e14e47fafe26548652cbe282edb494dd28d462a4c9ef2e3cb9c8b7f18ac0fc99add0b73eaba12ea5d6865089a395f165c73f90de6603f2b7e5dae8c788c0af63a2a6454e0c5f724248ccf1e6cfa14535df0667f76fa2ab686577741700bd0ab1f05b618c5dae97d1736128b7ac3d0562d937e8b77c146346b70986676ce9e29cd6bb94238e1e62fcec109b3de93551c0011a061d14847482a88a484da2885c9251bffd24611df2249a71c943f2698114e78903424569ecfa622a013ebed5cb498389d98410b38274c69bc6d2059bd3a4745303fa8d3790140833584499c3273c2a00a4a110e55094df1410906052242aee1a89a304db611ad674e17c237857e9c9af85f3c93ff81292b74e952f508c21c2df922fd931d5a8c698d056de271a926f80590283d5bbdcdaf3aaad5566d095d5afa4b9457e51bb25dc0e08857601675756c8efa1b0f0304e44c44d160005a3c07d07ca9c2236d9698d3b90684636e7495bb282406f8a1b33a37a79f884f1d1302bcdba4ed868419cffa980086ecb08962ac7d3731834ef4ac63974ff604015b768880b03779ef47a83e6b29fb6e8a6b703de19a5ed6d7e68b81e28aa1fe21f3ca7b0b04195a665103ac2be723beeb355b3c7954b4e03ae8261c578661a3107281c1941952c994ec6052216949ea9596d5c2be2942b2263dc4af4887a91248cf6b4ada2e2560388f456b0d58f70534de7cb75b45c18ed7cce3b434cdbf575e06920206e8e0899ccb0f937f3e4fd3288100e294baae00118b15eb2623547433cce47ef5c09c02c6e3fd8c78cfc642cafea800e00dc607edd9422886a726d78454c06cafa5959c1f048e0b989b5de7f66da2223da2d394df0c5eef25dfbb526cffee7db38def6139484b68eb32021179ebd848305e180d4786e66ffc636e3ecc73df113f9ba698ce4e399dee10345b862411aa5a791d126a8f23538a6748235d38b8ee4442dfc6bfd9600766156f567c48b6cb6f30aa52bc3fb4c64069abc01f1039a2d3f98ab198afdf45a45c610c4ef5743a424510dbbfad05cc1687d057932f4adf2cd50cade351367af07b5b25d3ecaae432a16b464f04c90a7dd1e8c00e4d3f43eef9bdda2845e3ce94db571dd83b79ba5e12a6d641b9e7f3a0e2fe6f55ec87a08489b1daae41865a4d1c93fb238792d0aa53111a233c5f9305dcc10f74ec7a33a375d9d0294ab9cc20e0127caa4b19e586d35061c724f55f18e932e5c6a1b4a6cdc7fea1e568e9db56dd4b2446f45a755df968303984cd5ee2b8455cb5b0219f9a8dbff585d879eeac32a869123eb10c8436fdaae130b1ea7f367376e54cc104365d5d8d27de9552ddbb55f5ae845b7b4915b2b1dda5f1e445dd08e83a64e73a7e90f10726bb22f109bca4d09e25a2df470cc1100f342758ea906220823c04844bf7aac834d24415f3d52e1c6177615e3241119065c25207160df525ce040f10ee445a4a6872b507e04a48c220ce2aa426e4aaec34ee30e405b35c3d829bab5f0c48efb55845db938e7c95804c6064858e8b864d4d6079e26727205759b20927722376cc0dc280561ea315fcc5919efb00b15a0c28277ba19b997385507b2efc07566edc3ac6e3892bdfb585f241f02e1ebfa039fe196ebf00f30c763ce42ecd588a3df50246ea7c9f92d3e874a72bb7a4ddf85ff1fa33e918039f5ea7b7a090051098c3c036088207016e0058037efce04f30c000e7d79ac9f12637aac5a82555fb148cc0a4dd8041b1c66a83c742df3d8bf21f39ee991102f00b5ab376c78c837c7c1e6af50afa2ed9ab372bbc4e216ef9f46864a8e2a9e8ae86479c3f3d939269b24175e4a0fdf4107d2e5b253c8de6822f4a0e07cad4133ffef5530633f96f2657fa7374240e75c1f1042c0418c86a91f0173decc4e88232bbb2eaa8946c9ec23bb229d273ba6849a28178f72b6d3bf7ef4e6366a5aaa245322b7ae4f89f6fc236b7e57153d0b07994388fc7811eed96965237cd852bec77d6f55f5dfee111041695a62cf66045557fd918e38761933a7ce61cc47f40802e3fd8fa6014e7ffd1d40604b9fd0576e0d1c01b82c03412f1339148fd978d1a05ba2960be466d861fd31acd2ca5fbcd49b24a56e64665a91131589dc345219ef546b69c2ed2bdc820e12fa8a9807a16881d1197588fdbb836946146bcb93ab87b13810bda31ccc4f533a599fd57bff035b55273caac2b3e32d92b2cebcad148364f64d60d7c2cfcdd2368750bbbeed63d7896fc5f16894658d0556899034cf54592a8dfec70b57ba878b7b75f285be1f9d21c1e32f4524c03e8a05646808a90429fe533e9fc9e2584f1bd9ca6ec1f6edf8452af7aa32c63f8959562487c0a8be654e048ef957b23738abb5145af52fc2622e46fb79fc281a4c113b20c91c87c03be49768cc8d510aff2723893530d7ae8ba5b37dd4540c2b517af017348b6b9a98ebc24e3580b751ef4b983ee574dba8da748be2144ba5f5878aa000ff8c0e09bbafca89e2561a2e84320a399a62ea474b482452286e6ff168154f6c4cc0f09c00a09a56b7b7aed7d804960cd3e7c3815f853074271ae8a2acb5ac016d36046db5afe04f698713caa93952e680465d45444f78cef22fdc858e2d9ccb03752a31d22266246a01012059ec37cc0570f0ff0e047655ec61cbf797899ef254648de1461821146ee6e897fbb42685a1a0723fc3210fc779cc8625ba88d86890f70bfe2119817ac0897a16b1cb647d4604316edab552f0c06661779f5c158e34041e061f1dbd09965c8b684d229321375f106bd0907fa9ef3aa7ff0decee6465fb3d5984f920903ed4b6fca65f71e0fc70ba454e1871709d59f3aa805cec1d4767aa06f19d41aa3615428d9d3e7205ae0e22b8791d6f7c18853ada0d4f72d8e2725c1d05cdc71eb53ff16d2ebfc7965129f18e81dd5f1cfe3137a0e78a7ae3fa2186d7dce4faa3a55b31199c65192ba63dde093816334df6ef3cefac687ea71093636935cd073aee68fe4a28dc635a32227ab2b5d01c655bc0df937322feafd5eb449fda506d626f529d164eb60bf11f171f444f8c6fa84de56d44526d1f8d08fcbe38a472f4e356833bc8dc11ca3e609f4ecc98cefccb344ea266993654960401b603c2754622075e69e944ecb7343d4bd161481da1a3a8c27e9f57f7810782e1b164ae46715bedf3987c987923e2abe7ef6d58357a7ee0366118b3d6ace45a7c2ed13664f5e385cdcc62e55b9f9bda29ecd3c607b4a0df92d065a202ae0e7c3936c16cfd0d3599d12b43fa81aee918d2e6f8d9ec8ba53663ce80b9806626f7d01934446097df1b410a624670737e79f2fa5076d5d2a183ba9f5aa45a4bc63d12200580b4ec50c0b63d34d0de9448d1c81f831956706d6d3242c612732756ad5ec60613d0b5597812cc5e2af9f049317c46d665850cfe0b39ca34ea4108a8d1a3b42cb8f1768f030aa2676759b4de3d3e869cd644888045d13c3c927252fa904f4dc94be05de02b2a373361c3568193bae3546d44f19eabdf5dad149535adc22a24d1a1feccb838dc73f57bc628182d42a2838477f862870f5ca05f5f99aa8aa813acd2d767eb2c860dc1821e20059728b204fe0897e0efb2074d9eea861da313c7a2fce3412d60248f1211cc12d275ca2aff33880ed144074fb55ec5dd4c5bb8e045c849d43e41f19040f902777b47cd5bd66e96ced565252035a3f864eafa761f6abf1c15805eaf258d679e48061a0b8bd91b22ea4d97ca0c6992fde352f4e860061ce649fdc1e9f8ef210fdda3cd0f893fd6e9b8a2ecee0384c4dea2cc7e3b4803902d90a07a697d6c537d8088dcf6d15e75a872403d3b2e85fc1be02e823cd6cbc09531b9fe967389ca99734d4de7a98a705e3063efe49cbb10eb561ebb14607b625bede0626e2de85930a1c4c4d1f33d60a835183bc4c06f38c1ec8452c284e9fad7972566b65fd2cc91c419c42a00b0cfb6aaf5b6b7881b7aec6894b58dee19b42fa164d90e0590e7d52492e04df7b0ab11649595b8e7824b0303cab159be89380c3aea99aa9b8a3191d26727654013e5ca83e54a012901f2f0b6090f0f375a81212fe22cb56113dd26fc96a24165ac9381a238e97295457f4d291a959037b222f2453763ddd6e9695b1909e4c2294a06336e0b7a047b8b74832ea327e2dabd122bd49f1543ed0313c600ece2c465cd58a7fedc4ca92c8c910743363fc694465cd806020c77ccf13bd211fea15d9dafe27e90414cef3b328109b65409e361635e98b2053a09030fbc0a6a07ef25c334ce8a962ed2ccaf51b52fec1e9838714f97649e687e019f7abd08a811a6971d5d7449b8000a40f34c975584e466ccdb79571bb898229102bdbeffd636bb7e5e839650238a3c9ce716e0ce47c8b0082dd1a9eae5b03cd921a91d3fe5c4de468c5325cbc2de9f0fb140ea143a246424f14de1e46dcf24b59150ee1514434454da9952f83a2de7c366680aaef8f202747614e835e7a635180dcf51622719e5d1ef803a6b3e531149f73f4b860d388a00f8d45b12c78924064dd03a13920962b172524f53f09bd916d4996c073724d1e80967e9b7e6b21141f61bf2d6583d577ac5510008e9ae1c1d5befd0168a198da8f1bc25602a57c3b3c0ca3a7fd5cc7fd9606440bab9423909dd97e0ace2303a6198ed044056340efa3396260d08f96b2180040d61f4c9b6b343068d76823b168d0bae21e7a19cd82d36528cc4f8773d04d0052d1aca134e857c2f0a54de577347dd332c69eef581b3a2199b42715b24657b7cd83baf9c4dc1e6324bb202c1677a9b949721dc63ff17b18c1e2d891401b2363d1c8a6597d85376f9fdc2a149feb937fc9c689f53d52d96b0471bb15caa8fb9c470a15b0126dd32a52570f7c27741fe4a1b5b1c1cfe24b5c967390a95c193a85eaaa97012e56413afbde3ce9775fcfed4030e69ff1c4d66ec301e096b074738e7708204a204d988798d60d8d9552071c6022042831ad15e9e5e568ebc778fe27e46c2cbae9e75b775bb074f94812307f1c4e362af797a85ee4362cfb84c0d160058dfbed6eca1b604ccfa04244583cc5d13ef49cbd4795da20deac657db4ba32945d3aad93e2a9b20b53dc92f4a4887bfdec75fd6bbf75d054eb4024e4a8162d01c061d03dd28181a21bf9abeb3dd8208f0243a314e4a7f13c4ab436d887924c782824b2376c297ad7a54bb15375c7209745b1835f369c73243f778155866390aab42bb8dded6196536d7ff388845a51b89e4277e98041c814a3dd7867e60b4abd14f8853df8f9b5d95b64c86d4c89b4ebddf39bf70bdeba1e85d8740d39c1f2013343d19523b8d97d2e2517dc4a7ec4446c3d4a2ee0cc3ed4c12daf7bb2b084cb3c5e031787b3918990b069451c0469e95413befebd3193cdef04453952f866e503855378ff6ec9a88e7a026f46ea4a8c7a37bc951b84d6be3e3eb539d2eaba148096a9b3aa2d244ea69317f4d9881090b5c764302461c11647abd3b6d711b35352961c4b7c9fe86fecec4d1c744bc61ba24f26b4f2766104489ef5aca9d22b2d2e965e740acaaae47fc7e61d5ce4d68c9ba296746cf2209504a19e801c3f9812d143367c56c67e6423085d3c9f019c6c04280be1c6935b79623faea0271c06b655f4fe48a28fd28262d0ea94349db52790ff2f2802215f18aca55a057a220c80cea40869a53aad95eebd2879132417086738baca77bc736064cdb5075782f8b19d1e9e8aedc1540f2aaab1ad89662e8413611b669499f43c9669d599630cb78119cd0e84e64d1035141372d0c1ce3fc71c5321638127a150ef23ff31e7047f061983e8bf3806d54f5e434f97ef02f25c7f9cb2c0ded4b693113c220cdf66403e55aa82f0cc032110f41a6cfdcaf31a73e6198f4a9465c8ee3f774cc60aa54d68f81df04234995b0928a9067145102d4fc3325164716a4cb130d270d135a4baa08d002b5fdb3b8a39ea7902dfeaf3a3c8f9d517cb56679cb391b752c6b9cb76a9258db2b047ce40892db394766d2a5703fca0e1bade5b3eda5551a0e8eb42e6ea31186575c1fc3150690bb217e3c325d8d10ac93a9530544dc874489f3d128b7a36270b9861e1bb25829c7da5678ef6c02090cba32c9fc40a5e66027476d3f8dd0aacb8803610bdc118c674056c7ae8f32b45d519a533e1a7c182a4473ddb3fd56940009979883d6384405cca36a930fa99916b63dbf4fb18531ff9985184c5efa67c1b2a82fe33216fea0b65ef8efadd078c3ce8fc3ba4f327324b0e1b79146ea3f3f654562d68e7e5cd8408a08af01928f7ab3a205101ea324fdcd843f18131b31fd1f56b9d4fdcaabfbf371d926e3c7760166b417d662d3b9fcde33c26596ad216fb7c86d8c459bae562e5506d4e17d023b164cf4d6021387d73e59b5a7325c65c652d9debfd309ec6c19100e31756229a2bd6844d245c2e775d6a13806c07c54b8f0a38f0cb7747bd3cf940a5138b52823bfdaf6fc89dc640814767b9b83a95117e0c7497153610a0bfca4fedb3614f2390a76c2dde410f4531f467f2792f06e8fd37f4b5d72da79a598f6f28a10e7a6f9ba17788b75f9c00bd774b02bf9140efef108514a545010ebc3089e03888361b32e493498beb07ecc62fec5b488a809c330870ef201c1d9a9162e3218c475104aeeb60031bf5d82c8d588a4d8ea314bde4f93f9fe2fbc351c583ab39d9586c8d32d29fda8009688aeff56bc0d8f87780e48af0ba3df200a7b1464a9089305f37d2b0081b07155f6e12589ad672c00f5d99727a824d2b76024d4ab677c684ca85100e9003ee0239300295ba71917dee7229f3bf61e33a19125bc8f227d746c54c96d92e4af5ab66a46429d0d1a57719adbfabd33eb97272888ad7d70a50e250e45fe2f5bc4c342132e9a21e527a881f07aa8ded011bdd1e28f1d33d2f20774553c511ead3131a126be8d0b92d0a0ef49704b99ed70a8fb0434e41184b4642013094308631968df20a390109174f27dab2e9a7b7c4ebbfe6e1f01cc9a926625916ebd020ac0a0a5c01c177261472b460f0bbda4ba89384b3693fd86a165d36238e9b25c8f05da49ff06cea8516a47bf4261721eb943b784a174a72d69188b09b13b05caa5600306524043b695bde271d02d9cafec9885591754d411e5c7839220b4453a396164cd89e36cfc1340d9cf0b1b945d6bfe60308087cf1adb57ff2511773233f3201fafeddc023f8f3d636b808b41e10c16a1bb447d87b1989460910ff6865f530535ecdf312c02a0f96e8daff5d3c0e2f69f785b2c417bb9ac1178a18ea58fca750d41e977bf2f6327cc113bca6a846fb7dd1719082e52a452ad7796cf613acb02e4f7fd9e437dc2c456368474b81a53d1aa7c9f70f5ef99c2ae707eccd73522e499b5e75c026fd716b353d844a4a205cffbc0b2cdc269878fdf3d6dbe7b1f09a561b2e5bbcf6ad4deada631ccc5f34cda80145f3907212bbd9946aab973ecd8efe053e817500374b7736a40f7b6d66c9ea87556f15e21e6bc8b13c161422db56dad915a4eda49cc484d19a8c6bf3a4d76cfc231a2a1e1a89f5486c3da1196f2f1314933d48f33e4a451de2a98cdc3aa097fa6082ee6f6ce170e66e0e26d3e7ade8c7e83221acffecf61c1c575107742b0c4635c2a6bc743dc64ef058a9f3fd132736c0bdfff847f624b6962824b81e88a202103c2b25cab3f654f7954bfae17b2d8e60e1cc42c31252e2f9b7e951c07ce30816365e81cc707f2c2ba16818db6098ee42ec4de8461ecff34c95d36f65e81a94f80af75ade8935ec11bd57ee297433a21550e957221e7872a8e8117566152378ad627cbae64b76397f34c6b776e2011302dcdefb7b343b51afd034e2b22f1623d9053dcb4aa78c80fbdb967fec5967e35c6f9f299c854c80aef7e91351e6837625b9db29357e8507d2d48f196bb9eef4c5389afb00890c8a3e1ab836961a82845eb44409edd5fccb3eb678a7d4ed9ab31bb5139922e5bdf691bad4698841ebdf560c7cbb727298e9b2778ca4e20a9f4313023be974f907f14e8f7f483b49573247b41a70ad35524deeac5a9551cfc3efb37598e4440854b3f69a195479ebfd8d5454ee86c26d46691665349296ae13c836d7ece8660d1a5c5929c7af63f269e8148fa8553c6b27fe38da500311d808f54a3d04c3dc83f4018b4f70cb8a94b50dc62c88229e844c784fb2ba3ffb6ac0f022caca988207b62e3803898552543e1a20bd01510e1fc82bb4fcf1b6794cad94bbe77eb2751d239ca1dcbd7f0528d2cdeead735451a4e9f10a1f61466021b5cddd87f885eae0ca1bd0e89be616128750cf44511900743f4bdf6fa33b41aad228c797cde430810f69bcfff4d40e5572dace36fbeb6ee9d3313f468c7a8f2273daa29ff2939e373978d41befc544e63755ead1e8cd9b5ea6723a99f6d4f0bf468afadf02771aa39e216cfcbe05ad7b9d763b7ce8f0b1ca74babdd7f115fddefe03d64d39282b4d98d294d0e67a37b058389b51351a91d4c090772e62bf0d2765357a7bd2f3dddacddc2c638a204f20cb9c9f811e0db1c2bb4160ed7958c983909dab21c011e896f250d682d18c462435fc5b9bf94b1cd44853f0ac34d8ab01f67850884d4a2173ea3bc4772a8fcfafaae6635eef0d43b79a8baa06e2641500398aab8949629310c9c4ed4faba16a88d6ca95a471dd4d47874df31d5cc146344d970fec86901e63f8e10bc38eb4b454a4fd50b687e486ad3f9cd26642af019f3db3dc118570df58d67f1196f7263fa4b73cfacf528876e325e72737ef4f57fe2bb5c8dc9f7943ab736ec68460ede1ba290a4ea4b309b600794c6263f970ab8d947ad49efe5b17e3747c72905a705f58980a743e00c85ee42166fa3a37fae38d4afa3c7c5c47f5809d9009a69962f1e2c9fa75b8b6037f791e080caeb4d2adf91c251fff561b9342c357b6a2f8fbeb32c11d697778f354fce7f5af9f1590af78eeea3310c9bb7cad8b9abb5f6cf1f5145654cbcbe0581c3e651bade0074d4191428dba1a2713dfe3426a8c426714ef6723609a59471e96a8ef0fb5ae8a4f948314da6168db88a800fb7f23201e7c7a0f3fe4185a03a2e11ea198479c32b4ffe841dbe51b110e49a852d879aaf49786cb984ee8bc7820e8a3ef269f3079bfd4030a75d0c3826a3d202d7e7d42fd10d3c2b45e8580038910cb71cd73a7cec5bf2ff6891865f13149a24520a905bb70def5586b9649ba090de5dc0a6f66b77bf5911ab8b80edb89f34dafc004d321a98631f1329d722c2255cfa533a6daf926510568200be69b6f51a2f12e3208d72b61e4991e51ed0e79d328e710e4dd029bc881f1055cd449994ef7e227335b0c4c268cabf9d17a824e9c78b5719a4c273e48e38be4b43426b67cd2d87c80a248afdda7a41fa80e68d825b817ace3c08126d5bbcad080355eadc7e419fd6b275903c0ab2e34339205264b196eee440621042f2eed99c95406894b68bd58e214f5de541acb023d20dadedd8a0e83250737a2159a0a23b5021a8fe23ba99d80222c1e689940c46050fbbed8f0ad69c0b5b0548824ab97d81b5daaac31cd22097188debd97c3dbfb91cf33ba0ec6aa0101238b462699f3725ee7ea46c0d8b09e8630ad5be55a4fb4e1061ac4610519f942f14e5fbee506165e0b58f8e26ce03394f3f3460b867457dc0c3d3d470c6269dd08aea301ec07866df174c75cf9f97f0c30b813c777f4e0960acf43eae22064246b6ad387308067b67afe0f669cba5c6689d8ebfb5129584b77ef889564773b13295cf781ca5dfa4c5f2d114db2d64d021a13d7d5125a3351a68090128f423323aa66175e2ff8be72e417e9c1cd0f3b5329b12c47df458d0e10b594b0b88e7e4dbcc6b3316a8b9d3f41a06c3338c6bb8d4592cd4d0fb9921273c64860039dc16d7f5b4a6a163223b99302f4f4ad16c5bed6662efa412462d291ca4a8fd3046a24416da9f49fd5172c9270b283d0f7802138087d999505153fba2cc42fda9bce1509cdf96b168d145a447b83e2bd13c97125451639ae580d8d4299708642fdfe6c11864f63daae9d0cab717e08468b6cb6012f72a251293775138a8c3e3bdc70a2445058a75cc801b81fb15319847d3fed917750c6e97de9f825838f7a704d4c487eb3fca6bc46f715d504696675d74d44c3b85404f0bbbfc07bcb7f02c2e07290e12e11ea4979cc874cb4c14f429cd1894d754e483f6afd40e2bc314bc77ddd81152f1de04a94ee4bcdccca2892849ad2674fc988cae657fe90764d632ef3c6b8ce1f6f795a920601e41501f97b4849fbd9bb00a9a296038583f145e60b4dcf3b659e37338e38c7df2701326e4c490ce02be0fa7bfa618cb80d04af40ebbc3f5a9746721308d42b10e8999820377aa50e7c962e0ca1c06f591ec44b30733a3816949d440d2e9d28f1fe14794f7558249420924ea08a0810f6cbd5a26452858d6fa80d4c97c29926e30257be9168860e5ba62a93215c0262674a070d54e296c7c7f05e22101460515e933c89c4d99caca7521cb07929341e2a4832e31a0122e9efe8a04cc038ce0dc9de0fb345ea7978b685ff21efa8c6f0ac18f5c67f20639864d405547197b046399b1166e2d8f7dc78335f28e58a4e045d2128b00bce9041001c95897eb1b4ce70dbae2dd74479e071979258a834d2176b3859f3a14b954841bccc1c016acdb1a2785253b777a938ca725218024eb428d2b7d4cf18299561ecada4fc4f3957d377b606914b95197102fa94ea9b53fd6eea90940a92f25bf5887a33378e5e935eafcada1ab832dc14b30e8da01592d68caf864cf06e3c13f26afad5e731f789a13c5e1b566df84c9d3eefd7ac67c4f17267e30054b4bca011c2da5ea95c8bab2749a561cf64b88eccd85d3f21f68cfa9945eaa7e6d649231a48593bb28cb5e4bcde79db1df4c246d9a72641034354e926a650ab9b353a9a3b58c89f0a398722250c8224e3fe865a2889fae2f2a8c9082611b44078e3366451176cc999a241e11d48631fa13d00c762e8a4b5a8b5d0e0d2c6808137ce109d3abdae87815c60d8cd04d414f177efbbf46bc7b1df02d7af8e1b5e4e084cffac6c17acdafef39a9284b147c02494c00870a2892c6b4bfcce02297732ec6a98bf3d36208a30adda3930f529a6c7ff2c50596ce7336747206ce57b826f254d77b3cb6e2ab57827a17082feba258ba306033e80b409530cef3eb0f5c68c9c959beafb7440a8516ecae0c1b16c0354dfc618454666b55611e1eb2d63e9b8a535a919ca23787d4a7335d91cace77b4a2f4b23f79e470c75e053c955f56dac5c1cf3d2565cc21d396346cc72f4beceb28d4f43e72ac9c651f9b83b308d025a2180f7acc0579592ebc1de853e9769d235a6d26fcfdf07ef366bcca2e8f6a6ddcbaeb47f7db2c521f0b0e318f0e5659dffb172dc2f0e2c0f13fbbc06b7cbb3ec625ec933ef9d54860b8839c92949cf26369238880b51a2fd11786f82075acc93de1842721a841129fde503432f0217f9c7005b53a5818077135679e80133f936d88742e1e16987063b631a44dbb13e1845d72222ca59193ac38a622b2a59ee8250ea2ce83a7f21cc7f979407d5072c61ca93499f2170decab63edb5e7eb387fab79790d648809db3bef891856adcf120e3e3836a2678ce940414cb942dec3bb43926e696aecef3d53ddbc1836b93f5414623728c50b8bfa7ac7dc9d6a21c1543afaeae95acf49be8540d42937983e579188e1025b87a40af4ef4227f1402fa7143f08e757ca6a4070f7bbb1bc3ded971d9589a2e6a7f7df5dfc10ec91efe77a6dfe898b87974dff839b348d3f34c3905c30c9f095f1179a0998e11871d3d224e65ebda3452217c9a849251dc864acc237794241d23f35d70d83a5acfa9f71781cda5d4f900e07c977acee4069d739e0348b9f5d69fd461f30855078f8e03adb575578e5bce8855f87fc650eb56b7d5abdbe1eb93eaaf573359b75cda0e94e53c6629c7eb018e6239fb94a6b9133eba1902f431e95e2f6dd76304f09c418560b68012492dbcce88c50ada4c5101f8ecb38d7d3f94590940999bb569adbbdfd9374abdd35194a57cc905d9d760886be933b4c69170096fd6ded354bcd7acc3abeb4aeb1fd3c241d62810f3b21c05645de08102363dc40619d5bd54c3c56d6e9f51aec37d0d16952fb107b99dde3a118f17d73f48798924b9b80c93081379ba20835ca75ba0347751a1fc9ce807850384bf72330e85e4ca49e17e78c20d3122d6bd8325003234c4f99c3636564db1954a63e7654c709700fe5b29a948678641e9264ac4288ca7c6d84c2ce43637c6302986d8d141c94eae01741be8f6ae95d328464a1a7b09e589bf8b6edd86965e971ed4fb6b5517613df1420fcf9a7824bf05785fb3598495601ebc4f38786f0b957bdfc2caa44acbe64d30a825da55ac9c5f4dda5837568d39ce4999a924e9a00a50e5759a46598e8c586024116d4dfcaddfa1481f26b7a7024be93f87506bd6ed61a2fc10c2260a3caab0a5601f4a10180ba70b1baf43a497b7af4984ee40f169fa306cd4da8674ec94fb7d25bb91700ce9f291cb66a56b0d481414bdc9804216615cb011877de231722df443de35b0ef89c65fe0c69df4c92676b709920825d10bf361f551a9a0853270e084358ce884c74b7eacde5d4269122487963669678648d1f51f19160f6e686572b5a4e036ddda22f55f6087c0a8745e1e7bdd4d9b5ab61f775170ca2084705e6e4bbba312814c84a5496c4a70db3432be323a8d58130b6b02a2a4cba601b2146c1528c5eff2bb8c8ae56c945827e2c4057453d4f57f27cfc6fb7492f8e98a8fe5b6da88480137dd423a28a924b52415d5da0de5149d4bfed665827c53287e3db9adc085565abb007853a879685d91af2635880c03a854dd706f471a09986f114eb99f73639692d0ef979adbb47883fb4edfc12a1eb92e3c887c3aca481c7a9c1bc17ec6364ccd6d86bc159dfad9b9380c6b753d454413e5fbeb5fe375119ae4980f725c79d184578076287027efa6a72a6839547a6fd1e5ca3f11413bf121a2e2832b7002cdc84d1bf584e1a7b4297c58494faa6bd64f305063ab7b87bacbb7e1a66f9f712f68994695df2611fdb662ed6f439f7ffb8c83e13e7928f726cabae74c03a2e781884a288f9bad844cd5451e022b59699d33e9844bfaac92723712b0d6a12b46964e451aabc127fb91b52e13a725e9d004955f890cd101d55a6013e6d63460b8184219a89202e57a2b103ff88202661122b4d6ff81a3ce78326069f800c1240373daa8572309a46d00fb0de1ba9f1541eb5caaf5d61d0abfd4b2bdf5feaef8dcdf53767f5f66fda7856797c25449f23f27668f958aa7e782d0d1186e67c7dfeddd67219ec29a574dff67b6a83955537fc8051fda24c5eaf615031e7e414c3c5bc6c15a5dce2179e7258c16d382f3e38b9714d01240a8ab23c549833034fedbae18b20f3de2c989cf8c43808acc8ddc52171ef6feb11ef1d9e3de8cdb48ac2715075f32b827fa7da09bb7efb2fe82ad98149ea821c71c16bf66bbb8a36762417f0371b0e47fc006465f4507a96ee81d6658a1a5b394a5f10a301711584b9ca671341808bb44e6579412bf89d3f4740a64b18e30873d0508efe8d249d8320f29e9bce0bc70b48df5ee2acd4eb1fda4671896c93655326c021e9c48f70d9848207e1a43c870aa0e5d8cca0a3222c3f8ce69d1fe3c448da2c044da311f1bd6ac0db6d857baaaca16922924c76760b61dc26ce97faad813945669f77e134b05db2c28385e5afd8a693f82e4dc16e8d251f9c64a39d57f8154cd10056d7f669d90fd33a44b5e23f948a4cd17a980a1f679158eb17d68be7123c6e707deae747fb7df585f6ec6aaca780cebc2d012fd2f8b64ebabd6ca50c2dbf53c26231c0b72a9bf674d589b7a4ce703b6cfb65c5c925faa4ddaf4e83cdd1a31399f5efdff287da35a3c6bf501b0074b06797e5a026119c0f8066cc26fc6e37d67447199923a3b4bf9e3b1d8803b9b3f7c7419dcd93b39593703c1948140a974625dd2d48b1e707277cd89e721a313f1bfe70ec607cbdd6fbee846fe996b1bcd899b4d0cc5a64612c05de8801ca6eba7567888787b982c45249660f425afa807477905f855cbf4ada20aabfe32e515f7d42753515a20993523006c2e4cfe07978497082b406133376ee3136f17d2c51df809237bab6dcda43bf298e9caa2213f57755889ff366498f8d001d869f5ea5fe9b785a0b98ef5d2b99bb39f3c009030f294e67e2650f60d80c8b0d5edebb410f81269d71c00808c0138897f1b47197b64eb80a3afae0153f5784c1eed78d15dcec1481265c97c15a0a9979408a0c11a017ce2886156b7c85fce4a6885e52517a7ddbaa00c157058cb65dc54cd82c16b037a433bd15b6b9db58644637ab2384cb6a0bd560cd13c83aa8d7a652ed7444a3fbcbc0e3f82e0ba567aecc5761eeb7e6c36c80ea36f9442526eb9bfe4fc2a070c44c379df3135233a7349e55eb4a6a315aa4eb9257972b2f3ce327536a0862ced5ad64c42b90dc2b883f4346555764020c3ed3a4d82fd886e0eb1b84374d913d70e48b11ac5e492b9f272b36451d6a439a5bdf95c3bc6c68998a3be6772b7fae3b2e03005127b1738ade6d40b8df4f48059904bba92a00ea38674a04cd0fd00e81d5b00fde124bee0f8d92ba555a55a2b873491287ad45eae51ab166244e3ea991b3989f98f475e5cbd22fc045de39b98f77bda523155ddbc80228eb18c6a7e8583e968fd9e98cd8131bf84ad3a33f523070da76cfa2eb244c229ef79f85fae68b080b485fa012d84deced39b55e8a0c62757abca4a10ab68fb99f8132fe19d5f8be3403b79d6d4619e3509e759839eda842479c3d8a38806f4a55f10a03a89372b9578c49d7aba5612ca6333d3ea1e0d2f59490248ce7c5dcc5473384b6d66b647518564fdd26e4b07e7d88d6d43a0c4348ff2128c267bef7aa728fe83138064a005edc85ef40208b66b0a1932f371086855b59cc0913944f2c1019beb6ded8be0bb29ef17dcec85fe26398569982a36fabfc9b29083ef85e95f8a8f1fc3aba42cd7e983d841ded7d00770af4c3ad29decca04b355ab15c456d785fc80b56b621ade44368a3cafc989578c0c672cf90577e4d8e953af40fa46abebf130f69b9c8eb811d407b5a37668b78c4f54d0f405a0d31b370187c32dc22723cbd663c7ed90c6cd2d365d35356b4dc5c7e79013c9483ba2730e79e77653b39dd7e5db8f4042a270daf7410a1a7f8e15d30e1c3baadecfd655fbbde20f5af90ee94346e4657e6157e1166740acc6da7eacdac1aacdf8cb78d3429469087cbd036f863aa156b5ce4feb7ef0d25dd7f8779633a7ff803ab2d0f375f1720746062bb72802c9aab8c3615779e06c4cade60231e0fafd92712ed027f7d9fc07abb24b8912f6e41fb99c354eb2eeba293f8d14768cd6e10e784abf9341ee6afa89990861df54264fbfcc4e8383187062e88d0ea30dfb1add0a8a8e95118a5a9cda1014e912498e017d4fb6e57abaa500fa75a610aa9bb3405477e81f866db6e3c04b7c2a97a13fcd95a21b111685557e70c2fdc095dd7ed540036b6b5ef40e4175a154e95cf2cc14876aa071a681e8319920a7a05107524f28d9c7f56e01329d270607cf4fe1487c32d86c9d2b531c285a9cc08fe94000b20f2a01ad535688d81b1234a1e79d925724a0b702b0a812f667d8c87e08003188361ead9c1895a140562d602d4a05848c60526cf88d5a6fe1081ab8b5a0132a496b45cfdfecdf44628b4584748465fd151e0a8b9599f935f729dea0b32fec20a4a1aa8e256ccac580520fe7579421ada85f6f32493299c80a453507839ee7ce6e14248ce12398af6081d57d1867ac3105c5d03f08757e8ecbf5acf3a5564baeeb9a4893a23d03207a559fb15ef4f7535d1072a6c64298c2e0a6cc07aba935c72a29bf8fb71cb7e7aa0199bb8408ca1569b08eab1f9ed85f1e616e36a4943286b636795ad720933a38dab3942c54813af707881c67d0e7859526d55857230ca708773298e5b63b04af93302630fc199c7294e7bc15736a08a8636b2da13990dc6e36657a0f1027ce3175aea4c7f9cb819ae8a596a8de03e3941707396bf53f6ded2245c2718ce684c874e026bc807975a4c359aebf1f8fba6fa7b64bd12c17976b6e3f25095a63a1d7b2ba8327ec94421622cefb7cf035e90290689ab628812cb7442c32773c57686156062db141a3f3b88b4094e72384faf327f60460edf6b1c6c272225b0e1537cb4023c092d19a729d7b60bc1cbd8634b49a66c8939714480b2bb9b2f5ede70c75959914d0742b8a7f15ce517df306026d0329099d46bddca172f5059fefd4f005e4f36640840e148415712cf29a58d93cb3ad727298199e29628d2579fa2e4576176aef7da05393a27808106af4bdc6f10ebb5c95b9b4c549523bd89a4f47c3ea9fbc0b5bcec2ca0b40f8a3eea20eeb3476fc3106ee4ae8924ef4fcc11a24ef92d57624d6a6d88e64b8fc7205c9a3459168c6f2a73c27a238455809c5704ee35330b67b08f5723fc778ae06ec5fc5e739f34b23f88f47784330de6f0489648337f002e7b206446e27853a3f29b96bf603db206ab49a32cfc863dfa277c27c7239efb7f055ea2460f3ada5a2287e0e05123906960477049526e3f53bfdb536cad0186acfa8465d74d4d31f81aaa984cec1f69942c594bfb2265721b5d0e79fa8bba97a54486b514cf65af8213d329a1d8c491935a7912a07fe82ef14e1946ac253a2e537cf19aa0754b70348c4179dcb216f27fe9a4b3397b81171202747e760d9b68bfcea7495731283b8fb0ed0c2324fba509ff70234dfc351ea95044c36be6f32021638eb3b871f20d29053fc93764b69480626eff29f133147ac6842c889aa1f49992db5524d06588eb400517a57cc11f110c515ab3b561345c2583b03f4250fa38e304981ead19a42c9a0f7b89e242dd15202aee55c7aa4684cd17216f98b1ba410475808d784e83eac52454b0f082155be2a88431181fe058ad9be4edddf014705b9e29ee63179ef54702bc7263d1c357b13066a686815f768a2942e5c765402dfa821f6c0c001a3ab32c327e1e3f9cc0f1c15529fbea1db314efdbec583a92ff924955b27e17c80a30f2c13c40051dc19d2c922a78867a44606433c623b1a2f120619bdb1752b8f2884a04752a04be3bab1f55d0d2f82434c98fd76fa7bf5304aa0ba1f29abb9722ea7fc843e26e76988851913194e1ba81970a74a4c88248a31b14dc0b6be71ab799a3a38e9e5426531dc77698a94b1fef82fd60607c234801387df0678201a3ada2437c9f24eb228334f465ef2e394e90af4723f7973d552680fb29f7d8f6bb7a3526e3a3ef1125e7c88146570d99aafef3235ba452a8849dfb03898fd976e7ae18d4a056b810ec2e9f8061f1250e673def1ea198019464259c88451d07ad3e0b05cf4e606bd6db3499a9b62543591e2414c74adef5ee79ff0bcfd144fdf26f83022591b4681c28561ec243888578d291adac2f3b87141547837fadfc3e98eb50e2aff306c982eb240ed18a64c95e3376e8b7807fb26e9388861a962d16a7b532a36e3136a147d1250497137187ea6da7c26d1cd620a02260003c3e91f37b6e990862f7155fe74b8e3d1a393a03cd625e98ea124761e56a32a926dafef13ff8c64790a7e731af4bde73c51270b1a427c5cfadedcf34b3c90a325aa4dc20e72542ae754be8d44dd3cace8bf71acbb79d4632de81e4f896019190839d14cdf5b2dc901d4fd7f5069160e3b5cebec88a6008de6e8c8fcd00338749bc7b23d4edd106e4228f609e544dd2e1c603f51a100d44502c3eab449c350ab87e3b1b2109f9d7863b33a4e0ae52fc3a28dafbc4214588d367124401e3df880b72b94da04b1e64bc9dc15efd3f295f841cc09e0402f432ebca9f96cc78563c7709cf392167c8a4756d7e5bfb7f2f4c110f6f45b55d6efc09703e868a2df39960391b868e23b440b897c1944c7d98e4fcd48ad6e04e515160d3d02489d2205dd7ed068ce367d1b5aa4b30660210e3ae299483048937c7141dce48557f9167cc61a51c3700dc529e4829547f3b61194860ef1802b2c1b577ecad9003ce93fa936b80db0eede296545dbc594441484da0afd3bb8c962fb8ee9d293e435acecf5e250af419254ef81b30b76ee40927c4802320091708d8fd21420dfafb6a76f913d81caa00e42ea18ab3c9354818260d30ded891bf02de8fdd63947158604297d559e0aacc9885bceff45db6c836e603ae2488032bb4e6ad8df112f9b95540d385bb81eb747480c757ab6b397da25c2e0db341126b9dcd5b21890d3c7c17c8bdc10735bb6214a123f92ab67c2475df7f68f9b447e3b0ccf8bc30b4388628c47bfe07073f2d77e39d1d86920174796074a03fa59a194ccbae1baa6929b337b1bca2bcfaaa813418999e4b2fb768655a8000e32a66b00af5a2ae41a403414c3145e31a6e9c736f265031398929f80d2b88f04e6324002fa1662e7ec6a1cb2e1389830febf5db6a2cf75d52349f5f4c3df54178f830e42baa6b08b0af0b92a067859d0b2b472d6e6aee12dffa09d57ed185be52970220e239bb0520848962aca0a1b606bb1bdcc19c102748207af694542baa5c2a73495287aba0a5486961fb6a973e76ea1ca9c8718e3864f1228057868b09993966bba466865f6bd136880374fd7f2a849b3ef983d1dd359986234731b76367ba476b3c50d149451edac9c6c2744d25fb04159f0051981c1ec0a0d5c5f6d1d642e8e2bb67dc1522e8fa4949d4ca3dced1311cffec000839bbff62194051f7871962b74d20ede2cce1cb058418f98d0d9b88716843f7a7e7436f5df943e63e0847f39644a60878dc7eb2b9c62656e3118374021f9f2e18499ca9919d20e2817e0e3c17578d1a099dd749aba3271810020606b4f535d4cab69b1e3d85e3a8adf29f485974d5a51deac0b4fc79cc4c65e2688e4eb275861561ce549dd75980486f8fe78d25c44139fe2e79853c7c0f7ce7ec2154f67a3030a00b54f1b79a4aca673cc585868b3c83f062363a9b55430b5f63c2b5d2a9e0ed7b7abc2a35642db7ec4780542b181df494ccef8fbd479506d7e62f4ecea78133012f969104975eab8b6551bf01189ed2e4a5974cade921c095391f5d85607ec8879bfae071783c897ca6952c778ccceb1b8cfeb36c760a3b1ef24533885e0218fdc3df64041379d8af6a74db7d83965a7f2ac8cac759ba23400027b0a31917ee6d555b4621b9ee5b979786f7932b4f967570988c9de2dca7678987fa2db28be205884f6db26a9d9c4cc96ef9d326404f0862900f4705f52362196ff6e7cdf5a8d9d3bc07f498640a6c523d7732713d1e07da59f4e4d71356318223dc1ff3d4e2fab0d8dc0e8b57cfef703ed5cbb2bfcfbc5d2a626be4c188ea248b5b89cee19cf3420c7afdc6f446fa8be78f5e9ab69ccc8593e73c072d5d8865df11b4633732e04b930ce966698901387450e2d03ae880fadf3a809d11df3bbead6a74ff475181914487bf3b07c14694bbb08100ee7a7c5fa5d0a7925e692ae16e9d2a5d971c2a212804fe05d4b6d4320ec4cd2a7366586809e3d252d80a701f294b02b5b5ccf0af58cbdd8ed20d5d43e12b658b090032dbf4ef48ef6932d382a1594edf2539985d1c59febbefebe06871468b807d66523674bb6c282b32bb1dd4397202834593b63e7d81c5edb46a1fa8520138dc93496a649fa251844ca1a96ca529de9a3927ce03eb9857becf42b4a6af6748ac7df9af261373a1b1e12ab0e9c1f0024de6348696279930cc2c9aa4d06c5c5620bc9e43ed099b0d2ee88c352c849a1d3cec46e71c791f251991b12346c1d38b39fc6c318c4392ca3ac2f6be1f284c0fb0d63c0ba5f836868897b1d8b6c361de789648500a5bcee6f0de32a80b9a6dc0945739b72ee8209bcfdf08f4c40fcbe2c645e25ccf9951ce0951cdad7fa4ce4e8e8ad71fa59c83c13551092086b9b43ed2d2a89714b6f4b03ae90556f35548b5b9a683302c5298bba874dca7e5b1678ee9817e4ac6b9298a09a2b6e1eebea1948c576a38973675497650a82304c3985597ed11692ce2711653e1219dec6804a34878bd09ca2d0109923e00154af9eae1364b0a394a38535d11562dcd81bfb8199097e2afafc958f1cb17bff8ef6b63822e77c65d5b63070e035cd49d40a965456b77759b50e6a7bf1c398d3088b68b9723e2c86d5ba667485fb3f6e15f5d49e1057dc8304f8b0b9b25ac291259f890dbf568544de159b9bdfd52e6790283679f49646bfe4b6d8c1d7e9fad4ba699e3e207394c039aaa54930c2793e814c5185308c6a0b1614d1ffd8769a996a23783961e5cdd9bfcb435b226b2c494dabedd1e138aa69df5c059596477c5e4b6a54849dae5e49a9e5719fb7959896947d38cf41a5e5c41ebd14842abb50b271114c15242f6dd1285b8b768a1a58854c8b7178df693956f23967a8c1b8ab04a5bccb436194c4e45f11e995fb63f54f74088d08bcf3feabeeb9e851fe35b22f1384bc2cf7d6421c56fdb0eb8adc78dabf088fccb403cd3764e10b6c049aa23b99888a7e0b4068b41f2f72e89cb496fc60f6f6150117c3960ef5920c680bc1ab05243e6bcc2d58125c62d712c4767823e189e930109700ca4ea9fd0e8877d2b2f4b544d443a1a249cd5c4e895761c056dc1ce53508366f646522b4d870cdd7d46ee4e5505dd1fdc040b9b6cc3ef4f5fd62fd19f22e43bffb4ef9c82b62421cdf9dc848047fd4093313078cf1a5098831aadade0f6e0c64d9edd32285c8d945125cc24eb44e8529c74053ae81ae887cc1e7291ee3efd7a0f9a4a2df0942348887088f56d2248e42dcdec2807215128df8aa9fb731cce2798a465d0ea432590d34f066c83336180fb9abcc2526a30f41cecc60509a3a0e2ffc7d31109d8975bc7c08259f9a585231def61305e4209dd868fd7d5d25fe906970f8e80de85e6f0855a218344457270bd5ce412e31e6267def85a42a41887ca1514e032e3f50d266bc50275357966295d5945b0d0d5f541a4f65fede598d8b18f465dee2dd592673937e6b9cd09976cc9621076438e9bcf7724773cd181c5a52b348a1b0fa209fa8d577a1e5afcb7d3d48d149f99daf53f040f91b42a2047bc3e69d8f1183e2495b4d91666bfc5cb7ff14e7c778033ba027d61e35042f942d982099796c8ba28116168107748f988f54843f91a91387260d9ed844d870bc52f15c434d16114a6b0cf0837f376c55127904abc47e50aa9dfb936a69a94e325cebb5337a89e2a57fea8ec431f0841279153f50664e2c781e30ce88e05cb735f39f1604d2b112c3f03387002b682c30a064dd27dd48bb572a3156b5d953972e2231edba5cb623249bbb4735a61811b825bc2d8462ae841006cff8b2299d36d16427c89f5afbe8e09ef04b82b4f313b14e2e9a8ec7cc31ba68890a94cef2aed005550f07a48075b1fbcb3ef67c9a67af0b1b88fe49ddcc480a04f31f62b30a4ecf41d5a520059f6b805396b74a4f31baa25cb2f72e95936e46013286f9637c4a2adda682954146e8c5f52ab9552d28bd8f3eeb6c45f274c5593f002d1efc8130b72d484a3dafe870866f476fe89a3178c88c7e2960c16083546b9c3bcb0073b02fdaa565378d1b21d65a76d837e6bdddeec6cf9c0b3296eae82f0a0b18b04edf4dacec1ac79b5ca432dfa05b7e27a1a26b6638f5119cb394c34268cd27db5a9e7747b462a5fc293789a178a08d8960a8927db5ab7394928dba9ec6f290269ad161615629840cbacf005bcb606a56c5a2f7945b2c72e1abe5eefc487732c91908ec67a2fb68fe6d6381dba5ebd03aea9f5f83b070439038047f041aa7a7bd5b2052b2da1c96cf20bade6378cfae106d42cb94593a15ddf45fd34cd09cf7789d02fd35ae933457d24cb0f1495dd5d2bb0a06e801502148211ea6942ad760e514f2a8a6f83d025ee8d1c9c9188d58d5566d32ddddddddbd654a5206880b610bf60b3ffcfa8a180890558c0c8e4a916ad0aa3c593132d7899ef7615830304131356855aaca93c5656b47fdeb0aa87fe9f8b2e586a1b8f270e451d5a097ead92575bdf592f21ac5e9e5e57aa5710e9884943011dfa75396866035c6fe92bad7a976b5b0a380e406096df7de8b225fbc866cf5a8f119aff11917c2afd6759fbf65caf9fef586cdf875935f2bbf8e835f2a87f1eb94f21752e40932b8a91f250c6cb28e17ff527e5dae4bfd14d9d281f2ebb73c5b3b0e70c619673c8cb7745c4f79aa3c4d1894fbfc756a56797ae579cbbb44de1a7995d8e4cb04c5e541db27c67a312e8db778d0d4d88cb7225063335e6333a5e93468bce5214c8d4d5662932b151a64add184837bde5a8dead41e443f653e14fdbc1f8635e83a05e59871aedd2269c8181a3653bef0796b90ec767ed620ce2786a23f9267756276d02387d41ad2a74b228af29d4ba0d680eaf4771d9581124fdf4d8ebe775808bf28107ed1d88c734e9bb438ae4543eef0507bce6fdb56b674b4f360b30605a58264b866a9b3dc936e5d2f5104d5b195c2505e82a1d75a8001dc541327f5f5fb5abf52ce65a0ecd5b93c0ff075b473cbdc7ebecc6c44f46623da88daf3ee25026b5c112dda3dcd5fe2b25736d97c364d17bd61666f4aab5ccbc985552084a82e8fc1b74731f45d9b7ca53a1ca8e48b95dbcead215c4ee8052a2f50c0fbce999e81deb4b7571abebd5939b40fdfdd3ea443c8220a48a89bd42f755607b88de300e0848516cf71ed86a3755536383b3729a0dbe6ecba11e2d2a77e9382cbae83fbd68eea9b6f5da95dc16e6500aab0afa753ae007afbc4adf12ace0e0b38391c94f650c5c43d1908a8614782902861f2ed3dc2d8e0b676549b90fb3c64d8d32956043d9338707ecab82a21dcae9dd6f4edb4db9fcc9b1baef91d96455d57dbf3eeadfc799669cf32a02796393d3539310dd188908e966aadd5f34a7ebef57c27437f43b6ef2a536daa57da5e55a5ae24f7ac4dd4ca9a84de5e816a7b6d6abbb1f885124942d7cd0eb73e3b61b3cd157e388207673839a3092dd617b062840a7e40c40e643011eb6e0f85869cda133d926b035193c964330c293939ab51d77e6423cd064bfeac4267655267b69afc6a76f2eddd4dcc1ad45e85aaac0285cc1e7374ab6cd6715c2811bf241076c1606463c93dab118abc2e9ed128363122d246f58836ab6f7bdea8232c37af230c6c6e0e24478e6ea10523aa65a35a8e644344fc6217baaccac4097fdbb6b515775cecda99f316f8e593835f3e39d8a43fa44948cdb0a4cc532b2a890b03901f3e727658e0ca93d66c36ce87639028dc3ca4483eec33860f32c43e3b75df461edeb6a6b6395286fa9c37b9c382f78538be3a772187f31cc7b1f7772b3499011c8fe339e7cab3d6fa793d7bbc101cef79fe3948da53088e1e9cb3c02fca029b1fb9e383f37ac673258f1a441fbd0c224375fa21f59b84407451149d236d797ae4e923fb6a9d8eb56d6d22b20debc8655522bbb61ed93cef471e67733beb91cdeb11d1057f2b96945d95acdcc873840b7ffc882186115270cfaa7456a0edac4075a932e12849fcfabc6387722bd26fb687c92aab53f4f0f39dc7c02f9f18d8dcb6f007bf7c7e738e52f9c1e65681f895636b72ab127ef19092dfbce70586d1981086d55847654b0d9afeac32988d6dce420bdbc604b383905ac00855833431426bb1a2b33ee85ef7d764578ee4f7f94ef7475a6b81bcc02658fe6093d25e72bb3c99099b9593965cdfe4a3fca6be1d45ba90230980da3dab937360e94284b058e5e7f5eceb52356c7eee954ca5642536dbcf9e356c27cb10bbe8ef642162933e0f36dba9123dfbca4f33e5c82e1167a9f0cbd2dea341ba99915d82ea845ec3d03bf214cbb0b4a00bd67a48d20fb2e148fe1475a844c990d216a3efbcbb989db6d605125ac301966aa97c15fa76af5685c80a59246c56df8282c0d0a35ed72e65dc5ab34aecaa0e8029b72672fd36c8f6119b55885f1fd5a902ba08ce9aa9419fe95c9b8cde4abdc42faf6163399bcd6666dc2096099b7588cd66fa28f7b44a94a46270698d8ba6b7355bb335281e15a5eb198d3a5cdf54d8aced61931bb0b5affcb0597368b8a725faea413e1f52bf63a5af41da3baf9ea54275b800491950efa07be4c995676995b8d0797b48ebd1a54a5b987ce74ddf5a256cd6263d40340b9ba9d2f7c8b64cec907f931be03f9ba94a5ba9305b6b57f5ea6787e183af4e6b0ba10abda935cc16415dd56b4f2cd3d7daf4d5c5d112d19bea0040baedf44fab447ca2d32a2dd9a7666a9d3d6b75b9c3fcf63e62627ff8057af51ac65e50577531bc316e19acae81e9abb751cf9aca69f367cf584937cad950be2af16ba9be8df2d59b885f2733792795c626947ac466ad3d5057f5cfebd415e14f4eaa4efcaaff535cfb953bccff9c69df9e2387e7791e4d81cd1c5c5ccfadf78352da44a953d32eda019074db3df74617baddf3960ecec12f5be0d70ed31e7c0adf40f0e8195feb08be6a80baaa77a50f36bb1437aedbf675be8d3c31b02906d19b0af3d515e079df6e6f97e790ce6cff4aea2db410a4a5e3f3ce3fa7df9567477e6402d8a4ce12e29e94f6955d990403bf8474ef81feb3bebff003c8f79bd7339e370f83d8ac5fca864dd143ef19bf5aa09f35c86887f9a0836545c2e613aa539fe82391ec41f2609332937a4275ce6b5057af50a80ee89e772b57af7a4eed79f732a92ad42091997cf5cfcfebe23c5c44fe2b7b7c62238f3cd6690da3f7f8c4c69352f19fd329ff3998f45f79facc3e8807fa9b846074facd632c47ffc8cf4520ebd8bd1a7c64b4a120a01f1a6690c56cf089754f7cddc8175ed86422e3b821a4b53287e06604d4e6ec8696983c7e72a279debd2c96bb4984c35fd75aab8f91b541ff6db67e6ec9cf435204f2ac2f42255f368e0a9b3c2a4025827e83c3e56afd6c18866158b7da9f3eb3efadcc4090cfbb262c6cde005dae894d2a9efecd086eadb5d62ecf1ecb35bb58e7b823aa63b7926be268fce2d8c64f960d18d24ffe95538689f1d59517dcb343d229e990f0ebec823e885f4c63936b7e2b4ffb9bad7fc32dc9ba515236dddddd92324ebdec80d8b457a88ef59243c226dbd4ae334e96277f4c9df118afe30af66dc91d29ba27bdc2b42b47b8267e91cece61e19793340634507a27e98b2479491245922e24395acb529ead25c994bbb50be0a6e8210ca6b725a566599eb4e645ed37df61d27fa76d13bf9c5f9b8fe0cc62dd4b53e3341eabe5274bb144f4868788f82582b3f31097e5e9d170b23caf2d4f9675cfbb97c572374d9c1a39357c2313c002f378b9230249bf0679d2a8544e1bf696259a21375059e4694f9b982be2afc80dd43fb923fb27777474dafcc91dd9119cad8396c2527a04fe274b01c953fc48ce1b06219c44af40e1d710aa539180087ab63126830e81daf05c7778763a1465c6e4cf7a34a5064922a50287d99facee6ec886656ca8b214fa87ce7e107fe6340a3a057c9acf38cf5e6ce183a7225690258929621e2002081b2425391923089f1da0347194056d09299e62375bd0e0450d7810c41065c44eea54031e9e9fd97dc704536a90826796fd654171cda7536a5fd494b828c23086426213a48128e070cf0dbcac076c31cf27c69134b6913e313a823410044110044154cd6e514385c4665d7a982c278cd3338ab625714f70081ca20184a2a15047edaab6568ba235cc6bd751c3b618db7a595e55360baa061e358c4675a85747a1923c1085e480aef4fb731bf24023366fed3112dbbcca79c7384a6e442438dbca6d48e82948fb0ad2c023f008a48147e01178041ea16a2fd83ade8456a84c29a51d94e487e64890c8015b6c136a57f52797fab9b14865a8673033d39bba79d003b6d836446faa6f496a0ca1c64039a99a6638176b42936b4293bb09b1c9358466827a26e88a3582c411e54dc699a03bd343aace04d5ae3340ed7299e9817a57c5724bdb9a50d7767a295aa3872641de933f678090109a0102955415667a386780c014a882d8645509923cfbe7cdfca09cf8b50df118f4b5216167aa0aa0125009e9bd59bb59fb801a73295541aa12a892a89a9e7de667e6069410ea04a8252827d5912b93c9680820974f5e24b02d8edbbabb9bdb6c77b7b5d65a6fdbdddd5b3a8917d0dd6c49636666666666de6c3333777777495ab9373f785ebf006156ddc6966b529dfbd55d54a772486faa73a55c0c359d920593af4e2bad51ae35b522213a4e8e9bdd4c5718e9544b2e9d4265cb532a589e4eb981122e9e4ed9e2e85dc62d889e4ed94228cad32937507aa631d320880ba6cd6e6c14c42434139b206125ef19b1ac0d9bed9b7b54383515a56ea646b5ccd99fe2c948deec1fcf5e6d949fcb484cfbe1569b02bd691c276ef54aba3893433615d355f9aaab418fe46b189e5c6be521f53350871ef44a1a61fa0cd0da83e5e93373d14f9fd98ba7e82bb2555564abfaca7d62436c36934ab61ca0f295f750f5c4b8cab7a31268b80c855f78b8ddce4330dece44ec845fd7db99dad5cefa1559b4c91e76c53d59c69da919be967589cdae9155a95261b37d169695c9534c3d562e5365c81e195f7909605c7e01e2d619e875d6e50dbb9976e694ddea04c9b32a7d3b8f3bbed9a398c651d86c7721b9a7580aa1b5ee236b5d4d71abafb2b8d5575ddceaab226ee5380c9730ad2ccf5bfeb0ec65881715dc23fef32bfe2b2b906ac93debcf77653247cda93f9b8ed60e9bedf55b3bea730276180524345bc2911a6f48e710eeadb38cc678b4abbd5b5cc9426c090526242689f488f0e43eedf866dfecaa92c64d546ec91e86a9bc9d888aa4ec0a372319cc9c58c63206fa0103ff7c2d601993519d757b6bc96a0b0d4663ed5c63166d6cb94ce397eadb1989ea80df1e32cd5a189d8113925263e1179d828359338d97f84af7d3b75b7e750b48b7738d9798c6482d6b589dc956a8f1b58c32e445666211d625f74aad9603a3a7e510fe0eb0fe242293c97e080b8590da9cedfae252af074a19c8a4ae2601a84968122ed5d99e47c824b5f1e1b6330bcd3d58af8b788a380f818018764316c4affa748a2d646f9d9e0ce52d3b79cb333ef2ba8d870f7e9dcd82f516b82e2ca5526b13d5d9dc6e3c9c371093b727bcf58d748571b9a0bea1b3f7349086b1f5d17bda413f7388346c2c7bd8a688eb2c0c519d25145691a8cb7a116f2b126f2912756d6c9f9afc51bb9888818090745018e3405dd66b358af47da914456a261c300ef4268a256f8348f9f0d6cfcf02d11beb30532e1814563f8ea4d46e5ce9e64202bdb1fec53d4978eb8c03a53ab42b4fefbba9ad9ce9d92825a43627fdfa072034d73909e8eeeeeee65ea70cb5dd325dfd25746b758971ab6d39b9a96fb721157338f498e7ecd511973d87a3bd5ae25667176ad86c56f5b07a51bc50957471509ddab09e76b1ecca1a36ab75d17b50dece436e9d8748221e3f5df614f568b7ceead26bd7d65e4474ebdd0e76d0d9c112eca16591d1dbbbd2d9acd75dfcf44c562a75bd08ca5329bf39f7deebb734e2a35d658e79737e0797c6dafae61cd430b18e3c3c7e9a7e730b5463d66d59848858026997e84040ed12a3d57504da6d59a4a8878b5b2f82f2b61e015bc4c5adb5a5cc96468a54a2766dde3eba5856a1d859817e1b4b9307505d74eb6715fa422ceb513d6ad7b6f98b71c4e3c706d1addb307a8b6e3d02a33707356c2c2b52bb841a26963cd43097b22eb56bf3a0df1ce68acbf9e6b569eb6ad36f5dd7f57ce81df97ddef93ce7213984ffeb389e8146782a2a2efbea887b7a9c9bfce2dcc5a35424771a245b3b3a48e89eb7d3a7a30b4140df9c2b5d2c83781e7ab78774b441a887e48ecec1d68ecebb7e47da901b39844ffb38e80df51a720711521b92aabeba539df02b0a5f5d5f5f3f5cfa02844b3de46a83c91340937a26042b876dae535009faeaa20f1dd56127bbb8d477f825745fb65cea48869e43f1b8a8be7e185a1cae8e9affdc8774ce2d137ed570ce2d5137b34642ed6a9809ce99ceb14af0d3fc9c3f9be9f39605b9962d57e0ffbc9918566733994c360316ce5b4b3f716e65f687bbcfb9bd62cb736e83f8b53de75688615b8c033f3ee217c79d15cb73fe3a1be991a07c2c4852622a9c27a280c4e33ef0f3d1c1f2fc56f8dc9bf1afdb7e66b433dd4c49d9e4dcbb34425a54cf7937519d7ecf1359f4d004929ddac57909a48bec29ea31829b658f0d1fa1e49e119c76c358ac1a6403b1c9b90db283dac5f908244d79f2781a2fdb9bd5350d03dd1b66e3a0109cef9c2cfb874d2eecc83ec226e73846b7e3808e903dd4ae7635d3c72acfebe5c902bd74cec3ae24dddd4ffbee241904f4b2ebc052756d988286be1ab3b0670d6b2476712e829f1e8dd9ac61f5a99b81b3cfebd391b2913eef1cf46e6a1bef69b953cea6ec6979d9c4e53466e336ea13cbd8ec5ca40ff207d902fd86d31809640b2c5b0eb071123c0236fc4659e486db7012ca22453d6eb80d2fd253d4830497dd288d987ec349287b8a7ad8b88db2a7e8465924a75d9cdf709b92d52ece632830dd6e7ad9e17e1ee367338dc032ddc66df8697e6153726ea364418c1be557c4f28f2c491a5208ce7f8e33c6fd9cfed93f23bc93f4c920211b248d31147e45e1d78c73ce48fcf2dc9d73aeb112d50199d63f0cf3629cf7117e513e7a3ea23a0aa00fd2074936a2379cefb00e3ae72109d6380de9347e5ab2860c621df490244b5bba0f613306e7fc26886bc36ff84cc94c98899d9ef3d113a1ac519eded328af052dc833266293731b654f510f1b96c26edcb8e124b80d079dd2d7e7a0d7910754bd259ba9996e92dc1825ee599fea13d551397723747b030aa0bf63c641d21ea1379cb793536371ce5b4b6b08bffd569019ff3cb446b73e8daf9a7cc6bf7287c11a1fcb8fb43c32c073fb05f9661c245b35344e4706783e5353b6538b6c1ab2b16ce1d7d9432fe3d7d9b319b2b5b0c979335920fb638f501dfaab95878dd4b0fac42ece3da486f111bb38ff1ce9395751719d39ca475f795e18a4cb79cf8e869a88ebb88355b6787437b1c93114366b97692f39dc7619b7b141471e3f3614295200e5dc862245607936b151da701b364e6395a85ddc0d526664042f5281dac5b90d27c16ff85989482869737ea3ac4847a6238d50167d7ec36dfca44f5fdc286dca2ad4aee69c9d9e989a9c95f873ce43fc62c22fafac4e6c12b1ca8ae5c5396723aab36d621d75a43ca4a3b564fb0f947f248cb796215c7da765848e984ed59fcdb402c39043b66fb9bc902914d972f1fa2e013072e2d7e79c57272f4f2244be72487feb73fa4c2b5b9fdbd657f2114361937301f01043030d091fe0e0890461d01b60f144182c38030752a8542a6c72ee21d9da71c2f05f59b1d0b12e7d7ed6a5e7be9291d8e49c3b6a17e73b1c002d7c5499ea15a6e7bc9d38ef27ce9b89f36e82f97c68b00933842d1eed2c7bcf7a8b964d36afb1160f6b6bacdb6bac4b56bbaa77ceb55b4a8b5293c85a63b3b6ab76248d714b94b64375ea0c9f84e543aa5217f5ef4ba5e80db5248ecc0c1292315b26c25613b03462976245ec3e5fcbd68e209e531f9fa71f843fffca20adaefced3fffca0054f1381ee9362c1e5ceae213b7d54e5597c91a36ab3b4ef59cea6ed2ba8acc5b21a5abe30eea8129f7481c6ca6b075dbe6512daf7ea6536e0045e8d937af5b7a7ea5c0a68f1888fc00d2755d1713e59e39393f1ad6436d504315403123621037688ac1f4b498881981598ac194459dff00427550cf2e4487e82ece9129f7c8b39ed585143a679df7b91fedc2c1660a526ee7278ece51a5cb4b99c2cb967be68c3a52de2d1d5d47b674b447cf38e33def0ef09eef70d7f97cce76cb46952ee5c9fa416f38357ae8dc5949914dd0457208c9aa11e2e2e097e7ec383cde904d84dad2e1f9e69e6f658b73af6c39fd189a9d48b3ff00e20d855b043d3b4ed1ed5e60170f865a0b2daf28cf6cf47c5469b6eb534ac6af93369d140b0c31f0eb2775c46b588db3dfa786d198cf09b24801c58a124c641102d582c5097a800311586e880286283df5072994a400c57a8cb8a424012236e34604e0c48a306234ce3d2d319062465a3c88f5d094407800ec33a5101e003bbbe7f1dc4beaf07cf4ce1b5dd81c0636f9522c41b59b3d77a764d7e9092df7895f748a164e9efd6e614f054f68b05d791283aefb38daf8825b1bd52e4eadb5d68ed613bbb71a726047d6cf63791fab03adb52ccb514a291547b15d588ca21d67adb5a5adb7e3ba6d7777776b8bcca6b6eb82fd5afaa0375c370e65b9ce65c987677e29910bef136dfb58f2c1e4c37ee197aa94c9090cc5facd78ae5f22c0532729cc870fda5bdbadad387aa34b67b7b65bbba038bbb5dd7a4ba57ca4522f3935364f5dac4b3e2ce50da77170967c6c4bbdb4f4928261cf4f93e23c5dba386eb78649a958a0b5f6937c3af3a9afa4b0eb951080a73a4faf8f259c5f1a57d85c36f0e15df796522bea3181a48f762df9b09732f960d3fae0175da55ce8920faa4365344358ff90551ba8f4863da7edb66d9b8dfd21fc944d4faca4cd875f1886a228565288cd8b95448d3aaa4c86baf7de94981a5bb4e4615f5a2bf4d7ca952bc96f3b847949c1801f0c8cd771301b8ced17ce8cb067eac6e25aabb76d9b4c5bd6c6a94e7801db1c36c72bcccd6e9bca83e9b6176f0bd2f47a9dba60b96d1bca5a4ae9b6f150a7edd23d8e620dbbc1223cd715b776ab174e30c2c66937a537368ab03686cab0575d57d898d128a2be58ce82638b07e8f443bfed9cb5561c2deab625c317d192e14adc624819d656555798081d79cb9539b21fc2dfce664943d334b7e6c565bc4143a41cf85fc7d510e1067519d60b2dab0dd146a4fce2d708247881e587f0d35ac20be1eadcb8df9a3c6b73a5bcb970a4109be73c2c61e4e1bce438ce398ebc7143424dcb14e94829256500801896d0b40cd22d9aeb71268874e438196ec21b19babf4fc7dab23866bbe809332c191a991d8c170cb9cefbac88724959dea80dcb4a6fac8365f53cbbb1c76d22786e548aacd4b5a53490faf6e1e158cc65b496bb04991b6205937369c3dce33ad2f3cd7696b3bed9b256254ecdcd63d1adb78eab3720420ad3b830c336f350baae5623276aedba4a44134f8ebaaed6256a2d2bbdd9bcd625b52eb1a2eb6a35aab58b5abbae12516bd755225c407f1359d0b0d045e63bf7bcedc7390d1b61a85107971f37b5edf295dfe7dfe802cdc17bdc959439925273dbb62d44d5b73db64b9263216a246b0ce5d296698fcd20189294ba2edf6f0699f3f1b863b282f117954a9c42e5516adad96577b6bcb1fff00fe2154b48d9c4699a36759c37af95c8e3a4a1ca342ecc34a5d65a6bc59b256ee5626e8c543c905840ba51e256f126895b9dde2071eb883a6214459d7a53610276287d0173e4bc502fbe31caa881ac809217ab98302a402d40619bf356d61fe6c1b3b36984477564a83829b87020432dfddade2e166b46a45487368cda20a2116f66b7d2b8d42151086137154f9678caa6581b7a9222ba42f7696d080805f7696d68863b069309ee49af3cf5a51cae1053d0d5d39a104cd09a104465b40f5338859c1c55cbe7f46323c57a3939f83544b7a5268410429ca08a2ab1c67b4f6b4294e04f1b32dc3d5b8b42ac826932990c491697235412125427494a33380b31c3d7ea7cc450ead0c9485fdd3b798889be8a3f8ea3cd8f3852f831c78fe3383a5df2a3dbd1bd1358f9d12f931f47f7247e745389d38f8e33fbd1735090e547df51e2c71468f9d1c59167f4173d1c79c450290cc3d06f171fd68250e2c35a92251f86b26f067faafeb3dfe77704ff09495103428ab7ba33ba9ae76ccd6f4eafe0547fd6c4c08437c053a58ed22a74fd79fd598fd0a09b044c7cb77b351268f11d5482efa02bbeddece1876fc7e92106df9ed383956f67c187137c3b0f1fb4f8761f3f72f8ae95a08aef762238c8905401e4c3b75713207dd77ed8812abdf5192b6a0ca47b59de124e15f2cbf28c5cd0c9ac3c716409932c3f48fd1ce9800332baa0a20b338a965ca800469eae2a251e7ee001cb0e3278f6008c3cccba3f580031c6134e3440611f22662e289a010b8030fb418c2dacf2a7c413339899198591872d68ade0c2e54f1a050712dc0007306a388c51cb818a226a3a94513bb254dbc1e8ade38c3cf64913ab13469e56e900293182203c3b00461e66c93c01c00d5ba68c608ab77e7365ae68f1d63a8e11a86e98c18491c77aac1b54353620b121076fbd84ebfd245105e81a79ac559d10c58f12cfcefac9410d613cbb39f27091aa56c313128eb08019e1aaf0a768060d4f9efdc67dd204a6be6c2c010cf0ec1e0d32193cbb0d960f0f5e4c01d262c6165c24f149e2075282aca0a1a665885863812204af96234f579ea188873d2154a2ec08156ab22fdeba1fa9ce7081096fdd3bc3ca5b17e176a14232430666f4e0add760cd00c65b771a6619752693c974c00226a50039a2d024aa24842d4628638632b2d8c2c3962bde3a4ece107c78eb3b2cf0a81979ecd296124e1c4f62d408020e41a822041ddee2c868b139feac01820e4940c8e2a9056f9dc63d6005c82888329ea494e153021d6a2801132c9e90328498adf44bc205b32f0522ee793956fd54d590a1f47a76ef07393c3beb074ccf3e03650990eab0aaaa4646cb1664186989f2ec323ee321668ca767580e3c93c9642588d59ab7366fa9fc9983662d156bb56c01005b916059c205163390bc75df8195b76e16bd751c1ed4e0ade7f4c088b7be73c3db294e55de3a0f1f5996bcf51f5982f0d68128bdf518a6f8a00753c690e2ad57a01a2454059617aad3558c1d88b1e419864318b51412360c200860593750e9fc59d3d4821a802103838bb74e6d30c5104f3650d1420556387172c5e8e27faabc294d24b8e2d947561247bc885174d0c3b3873d8017e98b289efdebc19329d78ad613bd8bf4c50ccfde39ddd3aa52c8c10eb41c50c16359d656b3b518118d66c3ae8d2272586b8353e5c5132cae90e0d9ef152bcf6e594c78b1ea1a18ecc40ba65891c133ffce95140d9d8a5c1fbdbd3a05755f1fbd48e8a21309392074d123707d246f2889bd903d1589110d50c48c30162362455c4515494faba062e9cf7ae5db29154faba02287af57f8057ede6ddd5627afc7c813b260a98ead3508dfe7f6f2e2a997b2889d56a7135cf6d31b15d0e2e1c293d330145005eaa3f61678784e9e93c762dd7b549d9c4717b81932c07a5b0601dd7a18d6f2c431436b6d8be36ec8bd743a58cf796841bffcb20e5eb2150b49514c9545421ffd863e7a91ebe28ecd6d792f098220ebb9f204f25d298407f8912db0d93dd875d4dd971c1d45e6380155a7fa3492a628c4759bb7107d0afda4594a2130beb95a9daa579de80d5215aab6d26a53b3a7368c783e1e5f2c2e4f6b56908efe146b569cb015253f3ead5939f2d5bd960efe13041f025a8384b6506b6d535a9424252a5e91524a696530865c468ad33017ef8b83f3629a2977d4bda10b49632d27b7728f912a0514264c1073f19e4e81163123345e1073298b3c3f592498e0a6fc76946f47fde9270f9ce756e72fee134b91a3773edeeb3eb18d895faa176f90e338ae565a5fc6171f9db6eb73191ffd85bda8f355d83519798ce5e6d4aefea1edd259c1757194bf788c17f580f1b1e580d15fbcc7e82f654f51e73d234e8fd163ca9edbaef67163baa39f4e632f7ee2bc8b8f650450eee228d1bd933b22c1e0721082230eb1c9e49b6e2deba1e68ebe7d0383cba1d22cdf3408dfdc0cdf5c9e97c36188930be2db69e57ce85437a5481abb51727b8a7a8cfee23d30cef21897298bc8f88b8f65cfe829b7b1e5b2c814b9d3ae76197263da9aa88ef8ed1b167eb16f47db518d298b4e80c17541951dd4aef695abfca4b42f56a5aafc416b458ac08c3e8e63291b4b2345aaecc553650ced6aa697b2d67800ed29ea940a0a6a971875e6291fcb3a6474abd75265113bca475aa5b5abbdd2682c64b209cae938818b2a6545d68d14b1f3cc9f2ee3249e4e7901ed9b49b6d44b50987cfb76a537a65e626696f16b631d7143a7e77d8f472e694913c53db7a37353f22d54048771694e96bd3071cfed684b10f6cf2ddd619be4835b9376501bfce7211d77701076eb21775cd9dac1f9e60ae03c509f73cf37f7f91dfe9c23bfba85cdfeca209c77de1e1af1bc3248b99141d8bbb3721fe7ecde67d93b67ee9cd9634e62b359263b9271953d6b416116892a60d02cf4a997962c1214669f1c2c7be92b7be97ae549c1f8b39768953f7b89b7a3ef8d69cbe27ba9c69aa9bd9bda5b4e2ebf7cd11b93e7ddcb1dd19bb64ff689ea6c55821004960f52619cf66963ea247db29696584bdfee42d2f336a94b3053dcb36ef96e1f19c0eee3e4ad0e765b562d6cd61f10d5f024d629d022d67272c53fdd89cdf68d6973da9e36a6ad8957430110d041c626fddb37d49af6a9ea22450e324a80f1d63d277200459578559d7515d158a5258b13903183135940e1a307258868ca811858c8a8aced8813326c14d7dab08a7bdab06036564443135d84a24abc2a7b733881e299e99ea2e9a4c95b2f892ba3a812afca758419154422a4364d5b7c7a19a8f554e6639eae9ea6609ceabc38f5737ceaa7cb53d4533fefc394ce238f3b5992366ce80dfb48de188104d3550269020ef28604c009d7bdc5b0d4f2fb2481c48f0bca70e28c2fb4c0000d89891cb494c08825aed71f94e726cf516cf11cf3ccccbcb1056d786b398c6f29be9ddcd37ead7123849ead78662f503c5cd824dd9cf20bbc9f589e6149d904cbae9e53aeacbed396745208cd895b53aae1a00b4316f7c6883726b4f7eacca81c81620c1baee8205605892d78f0c5145758c9410c756d16f65e1ab7f67aed92611515d0eda798be9d7a4865401034f22b99faabd263939d45f237a9e13b0c82200882e00ccc0813c157dfce476d74b244289928e6c6c494675d1111b11a9401794027a01d529f27c74787f1d1673c04c9d3c2385d952ceb8957c53a6b1e7410c657247dd638cad0fde83df2c080650c99c258b2667c875b98d949400d5208bbda6748206c1a1d39999595888d98c8c908765aa04daa90438719dd7e0f7eb5ab6456342bd68a895631de420cd923c6513c62ca1e4cd4b0bac5a3a1445b9868c6db790bbf447f892c96c7c4c8ac6456327eb2623c6685181f6378665e6688b6b093b312b111c3e8184970c14316355061c595582b61573b0f8c6ec003133a20f14513b194cbb45c86b55aadca5346094d19c36a577bcc503b2be1578ce7c4d0a00cf311e30de41211ad2a5183de60790a81f11e796462627c1543d25fb1e8cbb0566510180fbdc715603c743ac6c4f80ec3c4b88f186f071213e334966a4ada6a8a719ab229c667ca1867d1a61897a14d31258cafca2695e72f50beb1d02430244f215e796b00dd93f57dd914995acc02c2b34849968e2a6badb5d68ea0caf6c9b2b79e0f9583aef2d1da18079d635cb49e78552c18b71e43d217552b95c334a1015a558c0a54f90ed3a8298dd4788d873535a5acc8c2c09442fa552fa85a761cc7d668ad0eec4be7759ef779ca4150f45e543031302b18186bad6f3666a58a09436f57a954d64787294feb312e866e63c41b136ab18db2de8c8b8be55832312b154c790a49a9ac751807411004c1158c6a05530649f9e7765c2165cb9d94b5768663c9c4ac54b64c39cc4be737dc72562843b60f4bef234f219df53ace6edb5963759083c62d0dd9e24186554fa036a7ec52b3f56c427e8be137a577f1d5eab7ae3740dcfa3fd8e495bbd8189972f48d3cdd7ae255b1ce9a576d64e8323210d1e1fdca77384645b62240c39bd4f09127e45f39499f8a21696bd0288dd0701a1ed220c33af6a051ca8a3695ab4a21fd2b1abaa8c41a3207e73cf5a05470ab8c089bb5a9cd1dd8f856c278e881fe327a7df1884d282ddaf0eb29f56a5359c3a68d94bbb9dbb0d9d4b08a445dedde8d29cfbb2a4fd6ab8890f116fd257a6fe44a4537777155796e2ee3755c618b2145df4899d1c7948cf834be9441c2d03d6bd36f4e550bc3689624aa98f283122690c24aacc16842c809136568610519b14b637a3d2272596ee23c8976b323cf6adb5c455f15a3f2558caa0cf2e2a0db718597addc61733bcd8625805d9bb7e7d098db4ccb94a7c362cad35ce56ce58bab72beff85f43c458a7e49289ee7a0e8593673b0b0d9ed350cab311b22018872ab536d62b35f84ae144700e17372f04b14bfe5dbb60520c9653f6d6a88c5aa2a613dc3011c1b3db42618ddea4475da366cf45ad24bbb65546a1de3a9d72c54858aa4b563f3eab50cb2c35ca33a9df306aaa555cfbb9586a4aac04ace8a8474e121ae551538a99ea0e4995d9aa07c23e2a18631126b3b7a1ea2f2a7e51a928d62694955056bbba467c7c121465bf0f90eb07e08eb63f48cefd29633af869a164d352b3f4f6b55b4d4aaece0c7a7b52a4c5f1b30bb42bb11529b7386f6ede116a3ae9a314cdc84986c4448b6289b8cc8055b101351173522267f6e46dfdbd146b3955144fc3a3b941327eea99aa96665c855d514442bfd5c4e236fcf0ebc2d5547aca66f20d58cea54d54c3563d88c4c75a48aa2aaa9a84021535d51cd54482a25d5928a49d584220a4125334824f9f6139cf22111a96643ed5535db92706de272de9533337ad3a48a2355462c267ae3a2833b93c2e4a203171d501df60e0a32ba28a086a188dad5ce62dd8b02fa0fe99b55258aef19110b45d4309726ea6a77faeea7a36f94ecdb754002e1a2836fa724d8027ad3bea188b60d45c4b06d083543414121a194f8456b52fc7ca3a87c5b26285044df2e3528921a8aa03f5149dfa81a6a09652b38e3d7a99a1df1eb045b001af1eb73e2bb0970f65d49ae600b3aaa33437ba98173259a60d92a0da09872058b01d4568f1e14a200a3c6de4255a17beaaaee79f764251955f1da05848b0a6a9264fbc9933f737cb52d6b85b4c0b094acc70f222bd8f2d56c2268121130f8935e2182883fa9d3d7994ab7d8ae51dd865fa8af8ea3aee0e82b114cc4efe873c19f348a93db0a5c8daa02970158726b5087d4011a48ab81b40fd4b050aa6181f4b486c511162c78ee690d0b228f0161e7b4c2282d5126eac4b1d09b550165a355d103d4d094135441058609d18c7604c912f7e49a984b4e89cdae327d07c65b36619e07bda1955d4e9f2b36b515085da9352155076cb14e688bd960e29e5c1387c46607abb1ce392dfcaa9f147275ef2b735170384da9194541aa5da9512a52526de90ac73511f9d0366c134bcea95d1dd7d4aece89c0b8c039932748034370c4e47981eaa8a3f93917fab95ae6bad56870f4d55989ab759d10c33ca6aeeb3a2647baaeebbaaeabcc3df1ebe4ae7c57030aeab8a72348be73ee0a09811d866adde484c431e1d7598538227e79e75c10f6d951c342efbeb22209c90ad4aece2dc991447470c90d953d6c769d900d17dc931baa4243dff9c93d7de7dc13bf780bbf6af73384480f9b1c735c5dc96a3410e22a532d15c910223d5556812a123af298c0c46dade0bd3763b3fbbce923392c6cba66b522d83fb26ee416f31a56c4c54797b293955e8fd0c51ac93db50bf440f0db86a648f1047e1e37e39ab827aee6919c87e4e6dc8c6b7aea645cad878f177e0089a1f38d64b5abf32645d773e47333cfa59eabd4f38df41cc7537ae395a710d0678771b0d9792569d879e75c8be36a3aaf434eb6efbc46e117ad3149face69e7674dfa6e057f8add1432e8a610fab342f9aeeb2a0bf1eb1487f8755e227e75278e4e49f731d1092df167e7e43ba33f3ba3ef70b01a66bd736fd8e65dd7754c365a6a965adbd96062b61da5b44675680f9b9cec398e13e221aac3cfb94763a4eebcd57d4356398eebb8e69af3b6dd13bf9c38af5a38fe79aeebba6e46753aaf3527cf11c015c6c56959079dc646073d02a383a21709bd2b232016015d2c693be83beca3fbc4b66ef41ea28f622982e4b531823a574b6f5795bb397b751ca08a0385d5d913ce73b424cfd5dac373d4f57d2cc424780e87b213bde17c36a33a9c84de208104cb88d410cff9f971f486f35aa33a35f8be548a52ee86a66a96452994524a3d6badb5d65a6b6570f9d5a0e739dd51cf38c32bbbcda3e6e622f588547b7f7ce02d09a1436287ae073515aca0633dada96087079fd6545083d1c7cc520c51061884db7a5a1b82e98821a0c872534f6b432c61c510446014432ca90d71c40460eda9cd18e206ef89fb0da10302196096cb3dad2de901d79654e161c3c9c14921670a120f7169a48c71c726b61f28c13d71bda7b525478024b8ddd3da12262ccf528f06f77a1eab65c5053ab08668ac340992799af1707e88f1ae27de29b624fdb0ae151b7a5811cd642e1941aa284131587080a142b6c2010f2f34151640a9284d30b41f2eede9e50813a0a2704a5541010f2e50c86e151d4621145396204404d0825c70bc2e7c0871727052c8691a3d1b1c01a310a1d8e18b0151c8d484270512c8644450370325eca24cd8e5cdc009b39892f470c4a4030f485d9c7104a80b1fec80001accbac8c10e084002ea820b200448699ad2456d07042411b58b7a24ccc0f33ada9fc7ac05ca0e7fe268b93463744d9c686272e20a6f06276a00323921e506276290c40925827022054ee480e44261e23c15dcf1e9942686108326b0d026bad8614440134e5e1356ec2042016a9797a489273e1634b1821e9af0a1891f1ebc256abd8327653cf9810d1cf5ac87002768de0faec7838e76bd2fc27872c50c2ef774ca9329df1301a6c4a8246c56964dcd3a552310000000d314002028100a87c482b150240c14495b7b14800d87a44a6a5298caa32889510a196380318000000400cc008cccd0360097f32720e36e7a6172fdfd6f24e2fe10e76aa9f7c1b6a5611c7cded1797201744c2cd6bed49592bb54bbe5bf706fea3d1a41281260ce527ac0109b5ed61822337625082c462907eed847cb30f308b2e3df8b92a0d129b4fc7b8005052fa4226dce556375ae6516cccd400e6f94691131cebd80dbbe814d54b3de953644e61e7a9d80598c26b904ebffea588500478978cae7f177c59f5ecef27b5772750672045fb7dd3f47d52bbffd1aa57ea080a0f64fd6837f26b61c83209d54436e960048664b6128a6d53a4f9d3619b2e62e35b298c520d978335dce1710077b49680cd11e614517dfad336ffa4cebc73e5aa0f58d6ed39fb13e272dd2c7c102048410cab19495f4843a81ffe6871386c61d4891fb185c850d89c05ec0f60223e2b0007003ca7e49ab443207e016aec621c31818076e8088f54a93d29e082f34541b1d0bda2bffb4d000733ee353ead73a5c6abcd6101504ab31ec81096dba2686ab7dc24ce6f44d46fd1435fccc4e8d48226153a309c5866d856b205a90c873cd6e9f25d18660c7098d211dcd3e7cef9749d0272f5e609554cee8bb21a264f4489d995c8b91d5739deabbfe16319d6d804da3e40fdc031efc63ed0826db742e6698828c58eb681e2d878e820c9e917280cacbe340e490a38bbd7a61fe24466c93783e11dafbed0d91323911ed57a719c32ac674dcf3c3800da83a40ac56c4331f7ba944a92ce70c16372b20c72c69a09d26e64c98ac01f844ce6430ce09c98d84d0fd034bc8958a50e19d1d0a41afd76f6a2a50d07fb48092163af35ae74b6852045f145c892c43d4d4fa760367c311691415050c4fa0f010cab5bee15ea74a489209a1f4b58c67ee90d54d2947c9ee42ff4fb4fe428642a65ad53da591181485b7a38357e86d6e336b03fbc0b114f1b002d3ba82c961cd26624d32c281511c6863d797fabfcbaa4dfbed5cb908321f07c0ce4aa20250638ef199b23d7f1d2c3e487b3bbea0e978f09bfedc1ed4418c9bc34cbe1981becce2f2f6ddf88f76d94869d79f1fae808ae801aa8cf3a48839264e21ad283f822a5eb32a2d96c4af00746ef3f719340b7a7659340bccfa9e85ab2fb9439ac830ea59c0123befa35edfb50fa09503bd2fe8cd0ef04667963512d66fa9d6e3a7477501c48dd945532f84dd4414d70cfa3b29974c05cec37a15cbe08ab48cdee7e80bb896dcaaf1da44ec2cf60337ca6cd540f1ca8481ff63aaedbad5d45d4519ca409e775e609b7d3a022e14c5e88cca8719b8743b29d4babd3e62e47faae9b86c33b424cc47c126681d929e1afa7198143e32c8dabc9504c38a3e9da3c51184ec80211de7b27b122cc28bb29701f266e335756c02ac32043b541b73a005e01cb4978e14e7b919d4804213a156239aae558ef4f1480c2ed8bf2af8444812c369777f660239274ce5bc2904bae95bec6e3f79ff806f6e26defca84d6a563490e4d370082f14a7ef75daff388d6626aa12ca9e937d1567b8d2012386c330702b05adf051a02ca2655a25beeb9d02279cb136f7ebfd3ac7d26a36b147f6a367ca5814d02b59820a87be55aa91a0989b9f241eeb31881215d645898930c6ae8200a5b57de27a99e309561169ea7d72be4a5002d5a74360610cb38826b711cc8aaa0bb0eff10ee75871f5dfe0ca57c0e9aef0da74b1c3e63de12af7f25b5c14de136969167b1a56395cbd22bc703f7cae71034344d6b69f4e567e92bafa08a4c308c570df80af584201819ca652bc3c8fd813bf94d4d5545ddb854a5ff94fc4978916131ee9ff44061a04ca923750fe52d53f9409f1df7bf44154aecefc8937049e736d95826f4d21f7ce92b8280e46d9e2eb1c7b8e7e62da55cbc00da4ffc99b438fffd03b21575972e0637ef8b6814669a1768f00356c54ca794f35144f0d00945a75a9b5f990d0b4011d08c6129c2ccb8da5e5d6bcc87139db86c979f4989f3bdf1a88db028065287404995e86646a187d4840972044047c084466ea09dcdf0ff0ed021bfc559caa1aa9a742b788cab643925b9d84bc0a1815e40362216fa26f98b80b725b83de442f45f55de27ab67e51bfe51eea806a014454e092c0634d253b06b8b5a4b8eab82bcb366671e107af79517cb0599a9d22cb3c116260801a3f77ba182f1d52a038675807b1dacda1b93698f21673d8519daa0fac0d7a2ad220dc4709911cdd884129838e8a72605a19e2641141b4ee780dd5c6d41bb4526a359003bd6a328e402ec2ec7bebec1036afd8233571a29fb024a2aa06a41309d64e0468641acfc7cf4f26238923c5a3c5bccdd1bc942aef0d771ed89c360021dde9bf9646b0bbae635713a79ae6aa2d2dcf004628c71de9cd29317b42d2a7062f369f2f78a110476c28a792213b4f52344d30efb6b811272cf1045ffd954d353f801f18bc69d74a313ead3bb4164a0b026e5ac24b90dbdeeffa3efd9c713ed7619354c75a92544287f2f17ec3f742fd9d21adcde9b2958256feba321ef284a55a8670daf76bb5f0e428de5dd86454f95d7906128c605944dcfdec3bf7df2689e39c5eb527705cbbdca88aaaa0c38902244c3d0f279a1d617a4e46071bee1c2db46dd355a2815617bfaa249907d0938c883832797b2b166b127792ff8558785c5b5dc2e11b7e5ef096cf53ca332ff41285112bb5542c5110f6e9cfafd058f3768eb49cd2adaa48af00ce94a6e60e83a825610469e7d32c700020819273be9e4bb67c1ff6f10fe74df895c5cac317b633b1fa7db34c89ca20dfb94d896b4b67c8c8c50c1409b6de95d461632c017b0883b628c2bf7060f5fe1db9585332be19ddda8e6e2bd982a6d8d3805bdb588ab7a8579f8160dc97550237ab5e6290d2ba669a2c8533500beac93473fd69f014b07850db3ba28f60a60d633e836a980f1e3e4620ed0744217c45955877591d74c7d01774b463ebd376185f428db325c6ab98e068a02a588d6c9dcdabf825c111e6c4e74bef201fa945c4e6121320f06edb2f9b89eaee32e2a84cfdb1adb2ae31ed174670863541c9abb3769d647b150673194a318ef9a98e1fb5ff3b722bc600aa9b0af1c9cd3ba11acfbe877e0e319828cc57c4df0c5e7a1244e6cf2a8abdf1b7403e1708d653f15c05aeabfdbc0054b150a3d8592fd28a71fd747dd54801a99865203b37def102a066fa054e6dfd7f27573ca5c69471e4e38d328a462c04adf9bc05eed4af96ee62831efb6d151f3131e1467228127229e53126b868edcdc1ac57b49be96cc15b89e38b6578087d5c6c8c2c683a5903b73c24ece7f7ff3c9eeb1bb42839ff61fc8c507e061fcaaf5d3e6733bb6fe1ccf1c617749b2566bb707466c4a0f193a62401cba6c53b955a9609cf849488ed7cceb97401b00d65e87ab5862f5af32079f458b256db9ca24d574c813948d5ee48a73e0cea24f26b848020d4c947944223acf797cd1cc88e864bc45fbb7c265e0a0e11435ac887bf7d37d77aeeb84a6507562cd89f8d8632f16318a380c6da6902ab903c662bc57259aef10294caf707e9d568d029fdc4beca267324f4790ef95744e005fb6efd62ff145df34dc5e0a78cd01a797a36f6e80398dd5be66481a6e49f0681cd43f526d183aa30690740355bc9356d2a17f0b2de0175090d8800957058a13cf027b8ff016bdc3df76ba19a64619e9c0388504d578f370f10afd8e8a2689db29f6525608d475c79982dcaffd96349bac8183c4d3ecb169023876e928594db08995ca6b5853729e3cbf7e13393852085d4a8ccf4b33f64ab51569b3184451316339dfcf60b1953bdb4cfc12c9ed8163e0a9da3d40751c07cf4ace5f3a19f6e60afb3127daa5b0dbfe64d24d2668756121f8191eed60a8c1b136f7f52e63aaea5edbcfab394126fce530cd87b5fa56fa42d35bffa3556bf91eaf041bbf38d7c5ad31153ba6ec2d92aca8bb781e9c94ff6d5b3b234aea5210d4d8225f4211741a0824adf574857c620d9c28a949d5e94cd79f92d72ddf455b2ae0630cccdf7630f7e9f4f350954323c3d2722d27487b807c0abbfb8ab6baee129b1585f9de68e88b9b808968f92b871d1e9237e3a8701ac7d8d5cdc695cf7352236763df4449cb9a39aa467559ffe1070269dde01d7252e771e821f7d8283e7d1ad332aa2f9abc29ae813a313c3c804ecf9ec0014a557194632148f4de2644458c3abd0e37c97c3b11ab2a2a3257ee30a71d0c0e555477aa08e78157acb2e9ef2ca309351e543fe06807db71abdcff0329c2245f749dce29901b582c7df6438f1c24fa66f524182ae96b8de7ef128fba55f1a71f41f3772dff136857254d07d0aa52385a8f84c3bb5655c47f79da1a0a3e1db208bafc3b97ca16d0fbf54d17e3d3555f96a5208191d83584a09f37c7a4a56bc15d1d5fa9305a50989d5d901c3d721e7f3cfcf24cb64102d31a318b1aadcc0436ffc98da10da32eb46474d8a2bb941f0adce0d7abde2ac8d138d422385352163621a49c9047d2299b1c69b3faa0bf61450e199a0d670741704041c9e2e8942746e2396135d0c2013865ca60aac6006839a9561ec12cea979a5a307811a51cd217e1f95f93729e1cb32cf2eabf1639cde6f58f8fe76ce372fb49fe62eb322faf5cf9e3fc8c84bff502d1faef9e228b9799671721d05e71e54d4db659455d5d58f24675631caedf8597a15a2e45bb559df6ec7a2e28b6d13738f4249883adbff6fafdc1c0e82c474f2b2347eac8e5bc13d85b0a46f18350fcdef6e96f1a66e30215b16c1b706073da62d4bcf6066f7982e3573f04ca0d76827a3cab2a874fa77ba0da88465b55e4dd9ddbb0e2c521ec60a18c7dbf4d8bc8d58c36807098fcc058dcf56f6439ccb70c26a5e33f1d84608e03239459753d9a5fd980c8dc6f6b47c4887dc50520509dc0acbaa603a3195be497a79b43a5e2a549e6c59ad26c9010e0e69f0ba5d9e6b0328cdc9b392850c28569ad8746f067c6f757a1baa038b08e2cdc2fa8c5ca4402677fc5c4a5c10d4e85175951a9bf7e94b5cbe9c5f446c12b6fa4066dec3ad340dba5b73d5db2f04e6312dd379b99277066be7262bc8f4d5889a09374d4d3c775d843ea8b3ae4012e620e72751737d10d72d46126c9a90becff6146a447d2cd3b72e46a289aaa81e9ed61ac3d60f4988ea157f97c8535102359daad76507051514c72e989a023d12c4f746d2881cf18485d7ef26e4243fa8d095a887f8e8c18522fc48256b6c2e0856526c8a03a63ebc6fae8f2e638c93aeae786755976b1348566e9273a4bad672c5d8d6b3230a2c244e0cb6864440fed3ab89f66d37187141bf4d9916816511f867728532199eefeb090a7f56a0604979da9eb6eb11f5eda00fd76919370caee86655d8752b1ee96f654d9449eb86f66ac50fa6a4b86721f35c86228c3d90a77ab4c619efcf011f053cebf757f28ea5eae1b7414eb17592ec018890d85ee2da6fd133b1dc4aa095b023673cbaf1ddf940d2df100272209a32c33b1cc21949a316da9e63154db7174533fdce79cb7aa141bfcdf016134161af240930ee5c1d98ad16995d38fd04aec670528be3179dc72a770074d794a8669fcecccf232b95576f7b9374581f8730c29f90698947f28686cb24c15c3619a8a9c1b30e4e9e9b2d31548841e8e5964afec7bffe05366290b2cd94bf1386bc06d85327eecfbe70754bc97e061e070e49a960355047f340f1ed090a29c137e520ce1642a5f1b94eea082deef5b491c8cc86f4b205500fc33a912f1ce873f82354274d8e69f37c560403cf0dcbbb3232995362fd418eaa25b1bc5915fcffe4a924939e182901418f52b0cee40165a1e97d7e64fa51329699ea5f75aeefb766425829cbb6f386b0a5978d26f5177474a949fb4be41c5c4e5b2776e220f5cc4d8b0ce23967aaf95d74bbc3e74abcc0b40bda78e7cf59c590532a0a38cacab2836c9362b9791679fbbb666549fe2c156687516eeef3c6c465316ec2eb76e206deac2c3c299d1568943d6ee9973cf234d93f6b4b5dc1743c869ea0c45dcad6657fd295864a773a1a8a09b9db61d2d04f9e7a09c5d579f1d1789bea4620d844c77f66f49c2536b89f247c204ad4fe4c90d4e49f436612d1c455538577e86b2743ec032ba5898aecc70bd8461e34c8caa6b43f2831879ee70fec55d674b1a4f58180cd73dc82db0a0fc16cdd85405515c0a1c0bcfb0c44eebed38b3fc8f1c657a6de16aa7258e58b670841494ed47a3b9c55e37964a0a6e02b41fe26ea38ae3877989a50ad83c44631c50fd3934272630da357aafc3c0775fa55e62c4f5652320ee9adb435881ce52b09dd1b7efc2311f73c3812c575070c26a6cb0dc8c93d806e90fa58d53d4274a408b19f3db6038b05c82683410eb0e8bf06c02050131e226c86fe89f93def15ebb4a3a4d6b27b968517560ab22a1915798d482bd485bf8dd0016dfb2cc0db54e45396ef81e7cc5fea341a83a609ce9cc36642220765b6bb34c111e8a153ce70e89b67576e029b1d8a1c422ad24031210f432505588a117cca017ca8aedd7ec7e596e557203369e2001489256c0f23a5702909fa3c1f0242203ffa8df1710ba426c857babc9d0b44def7aa64aa2b3ae8c8192c22c2ec8860e2367d3092b1d573c35dc9eff49dcbf81ba28edfff8e5753c342e76f054290b1285add577b9c31d9d1bac32b5153d26b85245bcb0ce39b2df9ea931c25240d3c45a1f740033291119d9d743fef667d0e364829503dea2a20be61164e2b5dc13332c480642d3cfebf2c6d4576cdf102fad3d194659874c6ba652297d038e6b56528150eb868d44a981adfc3bcdfc402e13eb623e1a8aab5c0f1c4a222cc25fcfa5beb2432f5d170aa7283f89c2ec26ab678cbac5a19a3e635506cdb89c176c5e242739ffa3adc30b04f2466b15e45457f812d789ec214557dad9ecb4c784bb879264e8c983308a53425c63c84b20e8411779fd37a717e38c925aeebf9139980b8fb25e9b03900945b00eb9ce8c484c732fe3fa8ba45df6c0a1e585c6af643c4f5ed2eb7c8fa87d102e30486476fb729cf7669b0c4840b70de13a74ef7a96ec26accc22d71fc37b26a5f0a8b38a902cd133a1a7dd2922077bc695897c387fc39f72a7477a75464f15a0e6ea264b8fcc14adbdb45d1d55b05459c55ebef11ce2692faa1c6bea487b474509d69bc61192e5743945e10247c40f5411b3c436d341d5f4a0399c721a9cc48c4eac8cb6d4301a1e6f554986b7d34d94045bbd01b8ee63049ca2e3867e079530179b68605a069f5399530f13160513b549f938d47c970a258f82aa5ec73678dfacfc2ca0ff2651229e2d2c4ba7e861d36d8cd45ee1d268902bf08ccdc8260c6d58022112a37caa6e8c3961404a077266fd4a09871e81407a2304c144c0dfd7634d90eb24856b644aebf2f5e2800f17cebfe3a5fbf5f6f36972319b409f59766b1ff9fddc7deca32e4b58652cd410f859c415b8686ac0caecb4fa0a1eccdab11dc92a3cb74669decf2591077a11487448a5f4a69c138329a430b9d85c03406257b7338849fd5623e0caf7bc4f3870ac3f4a80a7b20219fcba3ac3cf5809841ea4a8a617336d0739b99ab3a0c57dd07d8f5971bd722c69080cb39c2ae43c8ea2e00031e74e1d6a20a85fe941f2250bb13ae4b63eabfa9e5e6879ff96e2f99b44209715fd6d1293e88c4ddf7117aae4a0448e341761d8b810aef722f9b490571bf15347699efe2da466f8bde82d6bd7c20ca5f871e439847642145d5c275b91909fdd94f554ccb5d47d7887613c42e14871b8511f8c726ea9c3ee6cc88b1552535ff7fc0b6c068f33bb86ca15a185350f4269d178ed6796f0a330fd52f5922a35189df15407f828a99c05a7b2e47fadbf690d31ce8a97277050620884a52c8030b5300d1f507174bad5eb038e225f779834096ed0174f4dfe90786a1d57990069c8af54f8f22c240cdc8f8d7f06c89effd09db78861a91b13f78494272bd30bed0a809bd8177032102d0d8df69054e26e8fddb6902990974e673ea815041e8f6edf481922034f3e11481d219f4d6cf69074247d0ae1fc2266eab0074fadfa9033992410beec2feeab208a93c54aa95fdd707e4685cc87a9067e01d81241ba6138aacc0d73134d6479c98c84037a6d72e1080e1abb12a450be9123b624a6e0363faa6649bf10ef4dfac99248a4684f46d96cca50a47a15c5e449a44bc581c5b54e9c80aeed1cb2339b845fde8948c9289948c668482c2fecf04a5cd75279a2ee5fd2b0eebdd0385e16d23ff1ffb0b7a06c4b6b22a3c93cdce7db044eae9f716c1632cb9a322104ce625a38033422e4c7418051eb75b4c5c48d0e30ca7489d9088a1220a088f30191a50a12870a704e0982b4e893d82474f506c215f355840e913b2fea74260ac22ba4282a0be159b99fc3a3946c0ab8b230aec5c7a1c425890b3597e48b3055960fc645b7b85cff875cc175f663945852265e008cac12a8185dc845924b37928f0a7bb281d008107fb705bff21e32430c1cca91380fd74f76f437892bf045e1707a13657de12879d708f5cd4a9163ffb23a0d1e796107cc180a0d9120ce99c8531d50c246c00e379a32d453c8d3bf7df833e4613204193abb602b64bfdbde935049702d541d3dfae5924777b9818d8ce55229212ef57903e7db33ecc3c32b9566abb86b6504149428936bc7464c9ea87a79300f48d1efd0f74483d0609e65183a3072539156ec8dc483f426fe426873213fa60a9901b1d4826347d4b81dfe8403cf1020f45e428f9ec991d872da231c3210ee120e417e9c0a422a78336a168a3804aa6887cef5fbce1f4a07c0db294c2561ff6e00a2875593299414a8bcfbc08808de01ad2eb25985dc5d438ad1834a81549546a994c6cae82f1dcc5146064c8987dbdf4b31cd3a0472ed82a1d0eaff8f66f6316a5490d82ef69e5f7a0d11d049044ca0ba5a61d38fe36382b7e7393abf9448e3ede1a0fb66f26aab2f8d2844f8eda63cee7c2f173c0d98603c168e4b9fbfdd905c5189c0b1478c9a0916d82b348f2d87111e4030a28547e1976c7c95a349272f53c061c968bc7d051a58dccdd0f958b747852888d758158aef88cabec45f1fa316d7b91adcd0e01b68f20c0a7ecca04e420f2c56a8044b225b3ba464df7467f4113d50118f6425aeb993e911be8fe0caac35a872907104c1ab9a05326f43842bbf4e5603c92b2a9118e19f01e85da549d7f08a742e1a3d6ab61b8fcde5592af3802561fb36dfc40d0c02a777392318422f804028d604b75649359a35bfb6702000e2ca82839db31dd1a0a9043b6e6b76d1c8403d0be39af5ce5fe3e735a14b036aae20f43d4d53e5cd592f243af0686bf139df098c1532250a7ad260cd20ed0c851357e0ab99361980f8648f1a3707eff8f5b3a30f81c103f9011224e438c3e1fce7603fcd31eeda568959db6937f2766f2366ed40b2e3efa2087f043341e20cba458c8fec0c8703c442314aa81c576717413337e4675ae70d7a97648b5ea60dce81cde2aac32e3ee85550dfc46c97c36e328779566ffd55fd49c0e97692ef33a559f1d47fac5baf193f37aa72b4b84ea74cdd59fddb062a070a8bea0d5770e8d67c8c4a8aa765155ed4bbe55a496bede2e1d572e693312b725aa7e4716c0db71fb048de676e4db1f2986d3f0229e26eb744aa1f80c93312e6243a1921b70815087545ecfdb551ae98ff45f266fd81e47b746c67bfbf05c94dc5d1e63090885d48e3d77e2850c35f79bf0947e56da0945ce6292ad97271ff537a74da630e8e507f76fe2d43bf2a1485482ba2769d27f9f802b9ec4d94fc98f795fc06655857475a36ada9861b876b7924c469f5760abb5f802ffec96455c86c67f642d7f09042f2ef869d4096e07ab81d8b3f1a0fb2c17596eee0c10411f9a2018c86e6cb60ba31f4c7256680c86db8ad85be2773444910879fcacb9c4deb4f5d6b90d5644663c5781f8b76b52a466f93dbfcb3d4ad5a99ceb109578240fda013a17ef4547f12e28a51af9e8f06423e96c1e5c542b0ac3b3aff4bdb65b0f9e36d3c0edb4e585cc3cce838bb46f3711ae3f669b9dd01e0d102b443219d2e4f805477bbd7c9d3c911abfb4eeee002a3526a6a6c2f3c8e1996c91858cc553f3783c1274ba9f5c6c0b1f7e6efa1816db278cedc981932b2cc34aedda18656a3699e0dd8f06901fae1d52aad8e84524e8db022ef03486c7de043f88bbcaeca541dff2b9bdb6a4f5061740a5a2004724618f723fe6b7656850debc01b6867654344730a907e3dd7379f71db34c788be54f72b66a003be127c39585ddce695fe07e2c9606df97e0eac37be11a9b417e2b58d38df3ff0c9b6e30d4f7329554a3cf3ffcd9eaa6fce8ab2088d12d7ac8ee4360801d04897166f91c18230e58f2b87005d27a97d0a16c27681cfb3546ac7f0baad39af0255cbee32ebd18af13a61ade223339639c5efbadc02729818eed49bc4c2405a53f119f45c9c4467dd09111e7338051c1ada00a901da7f367d3ffda227ea6f690fbd554cb818c337c15cc4c786af9c96392da1127d2f624002b560840b1f9a32b04fef6d3e5874a7659532116700faf867479a5e277027171d496e791043c7fb07752d9f29fbd65b5de4ae75bec535b6bdc78e6e0d097fcdad81d86b5867e8e9f24bf2aa228ded4c713358d4c1a96337dcb60ea6d32f48dffd08e782c43725c7772413d8dde737096cfa3c2865993ca6bb1bfc811154f46fcac932cbfb70725402023da363d1bb4b9aaf60157a8df6d32e88e2c0a8b46c3db8b3b918388d5f1e7155e317ece219d4f224510a3b548fead2a7990bf4150280bedf8496d652224234b953b3c460869d6212c24f50b33512ebb679934ed9e0492efdea5f62e63113d28a14f4973662af998eb833c59d678c2b6e1c965dba920ab19cfcbf2d893c388d531bfb0c5206027b3e8551c698e317c188d61b8c019c824bba3b969c91203e51d8c4a3d30d6ec5a4eb336cad003fabb555d5cfa4bbad85fcd6e35d30705768e69b775d1d5e75bb34add73167178bfaf0b01c050b2998036c3caad4f060992da2d624fc7e68fbf4aa3a3dcba15d4353228b5538425da164bfb8a2b0db4a741b9826bf8f8b3a08665b8b44c74bc9355244f3067258bb325b0c7104e172c610f53d11f577d20f31499adafe2c0e19c2e0a073a51910045bfd7296307d45975ef922db3ede32d169ea271da7a97dc4fc602a65d44759e6babff0c70164f722c916c56a560cdce0fc22c966df51c2b22810bf095ca6e8e20fcd043cfe4111c3123686dbaeb630a7306a32bb237975bc0bfc973d821fd191686a50c10f29e4bb02f6acc0d1b0361beac24724e3361f476139c05a8859d695ba242efb993ede216871679bd44cfd703f5b0fe1fe0e1da6bb159b107e68c36d257dc2f7e7fe6e5544e7364bd3298fb01cb016eb9dcb82e4e1749c0bce0203be7a4509996f51c137a301cc2890c689e52046483413366788585bd4e80fdc1e451d529cf6ffaf4b20e531feb894bc5153f13a0b909d95aa149d3e5b9726307abc631b2fd3c542e89760b09777c4304816fda9fcba501a99def94bbfcd2f17869f6735f2a188477d4543cde582f36832f6468277843f56ecb265ddfa9979e716dca1a4974292c8ed0acf71211027c34589875ac227979e76b80b7567c88c81b0538b246dfa2eb5cc7d780aa55634dfdb212c2870efec504199d46fd566c3881887ec01bfc180831918e8fbbd00f2c7695e810dc32f2b1db46f8a6d5117461ec2a1e9386e6046b2cc2d3a988279b3444316a0d561582309cb0b5596e69814b1c4ad5f1d7b2ae8f6c65bb092dff0a1f480c4ec266c87326e50567c116cab44a9e3f1c3fc934222df8e10cc3e52e19772d3d9ff18513086db3ee49bbba6bd5cc01164c2d07ee91101d8d611d7ffa8bb3fadf9675953143127bda477d2e4ac3fde92c8b232fc77d457ed0ddf4496acaca5ca6e825227c9e18714dde6d5de40da5ed8d16066fba17a522c3e4cddb25e5002bc37e91d7221811b727381180fdec061f67377cd785bf75a49700e62b6678f1557f92496f08aec1bd11730e08aad041cd757756f496381c0b4fceaecdf0b6fe63d8f8bb8935a8ac86e82f7feed88d71ebd6013ba34090c6148cecb193417003cd07de1b84dbabd33e5f95568f0394cb2623e74744b7ed63befb5fd7550bb09f49827119928117d1c877912ebc04f90c0fe48fe5e67568a96455d4b301a8b87023b14ab681150bb6d94415a5b58847f912a87a10d05dcf42ffb5a4612651b50dfa881ca3d583f8c7014fc4bb4e265c18f602e691d01a3d824a1d882995daa32b52bf288416199eb36e447ea8cf1a8a6ea47454bcf0e8ebb53c3952ebddf1d11af42aa8abb4e0de45ce52d7bd79f9a3490661289abb69943c3098478564bb25bd7bba459f0edc0f704cf980d0d67456c391ebc1f3db4da540cb8bd6abe48e3a8e7d66663ca525c33acad09b6125eb55e78db515fdd36397792fe8f1520472c80513656a276f5122f2468535a0c00d39527981643281e4ad9fc649a6183c0ab69a8e5e976f3354dfc390587c36502fd72386b48c79d02120de69df2d1de294d421c67bb500bd588fc82b23a0e8923bab5b7216974045a450675ce9ab029fd3ca93cae6e59257cfbb1408b5105ab43ca772b3fb715e9a0b3b6bd887e4df391e2161d2eca470fb89637d0446ddfa8e477839a9605ad8d3ab6500be81dfe491b720289688011dc9b047f54a01115433acaea18dc0e3165b4c9eaaeb485702d79817215a8fd3079527819e8f8f3101ea996409e26fba70d87304024d698a20c129920351160355fb244266da46bf8f32a3889d33ed8f8e88ba3467ba27ae7129edf6b659a2c7a8d7d191ae564cf0c4f1012215aa9bc06f1b7a498a999d5cd85ad0586a4de20214fa3517826ecef0e23810b6d4d93a887d30fbb9402f6d120112e89fcaf05a4a233171ae30b42086de134d38a5522f8265c883904bbe7a3c38cc67cbfed88e8c07b6ed4d714a28fcdf3ef5249a4b1ce40fc4d05e8f04ce18106ad4b3aebd255c9ba1918aa5a6471bfb3dbeaa12110d29472a3a9880c3f7a433692ad7d93babf67c604d5a073d4907c85140a7058399d2393553d389b478198a70771d6dd220b7ecfb6d0f7cfcc9cf8d2b3f3e4453d064634c38dd2bd04c2fccc998c378e0b6fc067463d03d1980bb50e3b0e91ee9f7f7d632c027d2bc9505a5e134f02c86a523e82cdead2de2f400e38eb27e0c4346bf6e61ac1b47277a7543302b6974a640edb7668e09335263b626eae3838e6b7cfcf93c0b1bb93934731826f591c9da3cd66f3e12107601e9f84e1421ca6bbf1789a6bc5126544ff5111a19f0b671795b83012550df7a6e81e8cf0211a51790f2cadc0af8f6e17030cc413a2dfc88f4115b01513cfea5890992605e0b559bbfa01d3a00d72ec07bb2b6d7cd13993187081c002891ef086307f102e8001e812d84381bf8483cfdc0c31c11ba2a7b80494deea08081e5c73962ba3e6d2552eddddc230b65fea57789252fb03c8ebc4ef4f554b0fb1371f835b36268c18aa5eaf6325f7cb995bc40db67dad16d9217e8665ec1b154494ea0cfe27486311b58514ad6987696ccd4add07490c1047bfaa824c32ccb8f92246783c1ef82db1955685b6b91b1f431b19d84343d3b3f04406eb7687c3b5237f0851ea73d5ae1b23a34998484cb90958be7758b8cf820e354b28b2fd31f580501a9e56b909371f902aa3ece5bab348dd4b8d5db7126b80478c33b6e357281530508128c42c737c1744ab7b565834c252aefd58a7021e1131710e609408fd68805335541b7e62970e2bcbc1366c3f7cc843ad6b911d3003e3bec9b59cd7256cad1e6d9c4f6cbb976dd5823eaf4761d3ab40c1611f732392a60618e8929f040b3cec13ad2ca5d1f7f49c164c8c182d25728ebcebbda42bf368c82a2b5677054b7fff7abca1d5f474364bf223d29b846eba729db18b211a5e9abe12be0edb35bfb4c50d9e1b0b41a0ba9b1304b661f98e21c02ca5f617ccccd4ff089aea70f80e5adfa9e4267d0f55129cbf98ec9a36ede54a6a7cfb02690e6e7721d6535e6438ad300a3453419f34ca11bab4330d2cb1b5523c109c2ac7fb4cd701321a972d6d16e15a377ef2de2fa3506bdad1aa4e788c41a370e2631df91349b56685b1c00fb43e2f77a66871fe1260785acd394d5523e2101163b49d95ad546a7fde5ecad364448d323995c6d2f8d50381638426587fb675e4a5034181b143f98ac4ce81be6880b60417085d90981f0d336f26aedf8df4c76297803dbfd605aa825fe0e193b3d208ac05e92b9ec890c45216531445579e07db2d5b085b71cdba1f8835eb8e31990c5c2759fb04583c736d1e8fdff28fa2ae43bb486f96cebe5266db8269e95b68ed4d35564fa4dfc29521b1cd1f4803a13550aaee7f36652eb5169d2400cd23bc1bc577c275065aa0e1492302c4d677707b50c6cf977a992eab4e7d190c1e9b087fcebbf87f7bc0b225e20c5b54fb41bb6971a4a21bd6b80f756a9ffe0404be35422a70659956b48d10c2ddd2c9148845af7f7488d03300aadc4e5841c06698c7e35469b4862bebde8b7c6bc71d7e8cdfa4d32635e88f1e799dc820a033941e2fd3fc6138dbb217f57a023bfe328ff3469b8ad648e832d59199d3120e1da4b23e36c2685e16cb073e6dcc77e5088f3173ff790471f7da000fd8659f57e8112664df5ad1df1ff1c0480647313b889cc08929f76043ef97831574f5c46aa98861fb6bc24918ae4bc341d74ca66b63858a383992a9434a4ad48e53c8b1f8d4a67f78c5989c23105cd2636538128086d5b00b7bd8675c99812f7f899ff9128e36f76d7f29fb85f52e0b9e407d1ced0421c3593b2400361e61ffb8a80a53e4fb85a293eb911612c8b9e44a356eee9910c915c716544f2d41d9e97980cb52eca94a9ff0068797889cc89bd4d5a91b03293789697a0a4667324ef4c081cafe1ea8557189c799d538e0c0a93fc69f117d76d5dfa18f9906a0cea0a9f1bd35a5ae95801dd95f8abdec913132156f4e842d315f45aa23d4b636f558ab594ff43a8d38c7594174ba74ca8e4a1644b5ea9e687f2ce78ffb85539216d53b36e788126cf4fc74af42fc5aef6a9a33e47ac12d5a494f8b1d0b92a11ada6bfe2ec5c9c0eacb09b517ca46533f7902bc139c8b843ca485429f084348885ca486cf0b9db968f223cad6cdd6b3698cf3ede3c72bec068d9990771a28c936e9365cf788e0d6e2d629d469f257895aa9f23576e58643ce6f97179084cf44205e916221489cf57944f99e63500ea72c8e53f03177ad775583e862803e0701b62a5c56acb2ae34d28e947166be7233f450b5bc555b5867f594c8052db6e94d8d46c2da3c1bf7da6c9080830fa5d2cc6bd652dad7881183db4a76922243f90c13f3beb28e10ea7e9d5806c937113fe5d18fa9258f45c1a12a1a7bfb1109a3b0938a7f38fdd91388295b71408229b4725e07dec481dfc2c7d9aafcb7efb98a353d0e5bdf2cd8a53256efbe682492cdf92721858ebf42adfcc17617241db700793a4c783b70655e68d33b9b7a89f17823cfa30f03b2c48baa93fee2994a3ee85d098b20a35319a5d215ea7ecdb7408fbbedf0c37a0ed227a9181bb8b3cf78db355e988831d084ef7eecd9d0e6afb2935b20e42d1f5218f0e9a7ef76ebcad48ec09ad30bc9cae7034a15f59e78d8ca5c88f211c77edb39c6e9d6deb66dd164317a7c39fa76eea44c333cc91455c8fae3ddf83a0c5dacf30b14ba5150213655347deb05c290681d7a18efc9399ea47ed7506e52e6bbce3bdbc94a110e40091c51aa641598eb2a4c6eaeae9597d08860ed754adca74077ba0fb80170e6e07068aee1607b294a86178faa91ad32e3e1d7c7f97f36c8f7ef7dc0c1a31935cbbf0f518f05b5a8070cea244c64ed71803b3af4e30842191d3d66c74be4cf6af66565cb2a6946b23f82b2ada7b0a46bbb75f9fb294ace030cdc80a1865eab26650b101fddaa944802c75560b40d7d06377205a45098f34098fd4cc177106c29fa68ccbb4d9c65b258d4b02d37a5161aaaf3fed3b02ec3fd34edf59df480c5ad54690d0b85c61add9734f57a5bc02ce2888d333cc7cfc1b3cb180d9f31d295af135f4a22dfa826b8c03c541c9a541da7a7272404a06ba257cb425161a9cf10ac7ab887d070cc8177ab796552a9cd115ae4dfad52491189f5cfad25afd02e9045e68924d0c6919c7298f02131d54e6a1e747f4c77d1904f72d27e1e4c217275aa3a210542c918cac7663cd33a971cadb0ce13a943f47b8019a4081a9f70e6599eb3942b6abdf57feab84bf75782c22de1581969c42329b476dbcbc05fe95ea44ea15a9adf15d9baa2d1a82f9845c26b58f6402d4041f3c90d39ee8a8d7cde1a3ea38eab5907ab1542e8c20fd55540c15e00546244f58b14afcd995a225716154709da95db5060e8f344c4dcd4ea9e78bd271490d917dbeee9d52cc7cd48bd74a68e6ab6b83547d9e898ea1c0ea61b5882b491ca60495ffc5765a0fe0c16d296b3949383637e020b43f881ddab980f5daf346f59cc88508ed4c4d22c9f6b8537d91641ddbe36dccd7843022fc37b4a234f8be5f7b2da84e21424d40b91a815a429a538442402dbeffa5964323b7bb4debb3fcb528136a0c27dfa039e0d020e079bad1184e53f8e9092897b302e19469f87431bf775f8b0470b9ef55deb81b764cbada25dc0c51b0c78366fad9e0b72fb3f0186bbf12771b755c24c06d914d3b51f63b10643dc7390ec88a157fae7c101e434a58e1c78dee454e59b49d6c85bd667adaaeaa9d9960567803ffc8af515c36995bdb6f4d9ef9404212df076d67f939d0e7045ecfdcf953e02aa82b909d1a3789145ab96a68e12194c651073a191d981b55b106bac3294076221b780c197d03c1c71ae1cb92f4aa4a27127d4a7332f76516c403069ed0a8e91c202cea7728b39c5d7918f9606fc401fb8be7c6bcb8977273ea288ffc8a560d874f4c782a199da01a8debba4fdd2b7638b7cd2ef0f0d8bcccfeeafb8f9d42abeac75557cf21c7ca8b9267b296a00615aefd87592ec465154c3ee04cf649bb33582f3484670daeb2282f1c5064fcdfa89a7641cfce127bfeca48211200fbea2ce05fb762da48efe24e48f89789f328cbef3765f0c2bb9c67d7a48785f1d98cdbdfa94ce8229f2c8ae7fa24fb8c508cdbc167df2df618cf279fa3e883a8684f2f404e16131909bf1bc831568c22a965a320d637640d24d98cecbb4ed9b1d0931e8260220ecaee98c82b9bfc0b9c2f1b28e1d9ef8959787b10dbf4dbd640888a0708d854544afd7dbdafe328bddde23878c64dffb1c876765b45919c204e19c8b5bec3d87aa40a43ff2c1928b183655e2ecb4877feba0252ac3ef2b68a4f20a159303e27baf291d6d78e8750c004ba6fb95bdcb9e416455ae07424a377995488a7ac4054ef007e5b8288e726ede4189c643c6e4a19696fe4210212d742106cca9c3387d312869c2bf3bb2671be4a7ece8a61e14cbdad0d271b86cda649025b143aecaa0a0d5720104b884cf6efe5fa988a783a8b4d17025ec124a2877ddc6dfcfe0c9831b396aa9e77c1623f9958c11ec6b33db46e8f8825a60d839bc27ded4afa114073fc62833cf6a00501785017315b7bfbf47202754150f1ab4275783ec129d9430d45e6882d1e1d5e10e49bc0248208ccef36a6de5ec201fba78f3704c990f378ca03ef9159d444c872bac51681f955c9a45471c70c48388d2f1e8e6f2125a8c21e91e6b4382fabadbfb7fac89d1a3cb15450d4708bcd3f55795d52243ea37c0df189c3e12ca371aa430e3ec865d3c3c0b810ff331aa1d2ae555bb57d462c4c55d6abd6e3021420919673d03150ebe7ece55b97cf8eea1364c7c7e10e2f5014bf5fddf420cdceb77c1acf843e11d275368ac9101efbb2ae1f4097186f5b433b0872d3b1441dc8e29b538c461f32df766f4052afa47efd22c846e99e12a6365bc9371832eb5962128de997e9b822fe89180ade23c7ffa5847fdcd2f7d4449dd7dce7a4d79f7f7e1099f274de86186c47d4219d5fb7ca3dbfc784b36830e805843f61035ca0f86d7cc6d8ab214f239469c75654f93a5f912417f9a770dfdc8943da33c86278b20e52a2072ec4e4fb2e568ce2d86bc4c095bfa7a974b85bd2288437bc05d6e20a430b57f55af644737d33669adf8b6c3b075feb412dd7a30074b6ff6e9485f833bdfa4de3b6137e9cea1dcc6d1b3e40b53fd399fd4848e0aab34f442f2a117dd391409aad8d89aae2e4f3abbaa7c003ea3d2a9347c38386d32402f08bf92518910d92c179f9f92376f3ae60eb54e3930c9cd423c2c510d0de1da187df2b29ec6b998185dcc9aa88c6e95ef35741020b505a616e5c166003cd7017c2c4921389530f2eced242f9cabc1efc2394292ddef93fe106dee087af538c779bc209722027adad0dc6f66a0239df26ec3fbd56101844333af6919fde9710e7f83d50291768ff0b9949744f49c54d5ca92c82128eea0a618986da47015b0cd5a425c23909863ec9829336ef44e0941d918d1319c48fe6ebb5ee8f1370337485a6e8a6e4ed499a263223686cc0d9406d99d0ac5e46490a8dd2da1799ad32774d1b1a6f5bedbf1210d424b260fe8215116e25e364ad8079be564d14638a512a586f5eb91b61225b791051993a30081a30d014ba9d024a7a0aecb7b6cca4c10b026539c8d0c7960515dec52fd5d3c3ba9a0f8184141bd51fce13de2c85e945ad0df71ad49079f6708fc13c9c4116f98846f9289d8707e227455c7084c502f834c5050c0ffd704b366d409468bf2ee9f4818a25ffb5a6400aad4e96da016cd199a2efb145e1878f9aed01e53f79131c912d3a1a9bd81270c6b70acca62007c822c2d93373fbcdf4cf92cd7fc08f1c317e1d3ecf811410a2223e731af1a173121f0296f810dfa63d367f885630dd61521ee7154a907903cb329899980e924ca1284b0cd5ec1148c9d82c097c0be6cb5a621b19a294b88bfebef424a5400599b05c498e11ec40ed20a66055bf08c223ac1287f5a15cca138a37f62451d1444c40708040097620335057f62414c5090205da0e9e070aefa9e78b1f302aaeca279b7fad49472a93af251990333d58a6c1f071310e61837f0b75d438d2a77c1ee5ab6c217e50ef2fb8846a148dda441e1cde3d54faefb436585d2eb4585804b83a42f5830d78236f35ad3b493565f203dd2f977b228c26f3f1302d8769346181b31fc8898961d481fee259cbdc4148315319d383329934a64e579f5e12b8e50e95da333fe89cb12f48d08d558c78068dbc2762379539131e03488e1c8926ca4e86ac9948847584de883f84b2226ed2722925e71ea39867d16fcc5c7e6fd0da34ae9e496d146d20cb8fbca2e4fa5d69649aec827931cb281678f132d338ac0e1cc400f1bfea636066551a6ba334c9205f8acfd10f60a0e90298197d9adc8c8ecfb0d9bb4357fe529dd7b70572bf2dcd35c9487c18e38f426765775c71b59b85737d04c5993dbc763955f27013154483a5128aceb882b749f9e58d5f35203607fdd19aa0f616c0a6fea88c2731881ccbacdf976d862d26c69b132f24ffb5a2817a946f6a319e4c4b5f21418e255b55a38c6263dbb33b14431532ef3542f028c52ce039cad31e6e7e3a8f02b0b6ac1e098cbb01ce5765d45ce7a3ad9a8bd68e50eb8e4aa3b2e0f6add65e0dbbb74f4d25605bc358f807a5bf3a16dbd69d2b770764a013c88141f088ae3be9fb6f542c078fca6d17e44d0f084241f0ba9315fce847fd313d3a9bb1b1ff00c31683866a17893b423af691f5d9c2d7b6894e33c3ca372d18cfbdbf66ae3f68fed900cc5115248c827fd5a4bcf16edb95236a9b66659f6b9f989d148d584a6a45c85d5cd4cafc55c69da9349d83ea6111a33b1f0017277c0a7fad79dd112ba065225b1d128e60fcf78588e604f072af1b046fa184dd994874d3ce96a00dc4d03ea95411d2b8a6d12ac60be2988527ac10351165678e0fd644c25014ef43a4d2ef5cb5813006e92081b85c7aef0a824cd652907ca6b6575c4380409bb61cd363e86523405c354e114313685897e38063ab30d0d0d1ede82af028b718adc5ac08b948c787308052a9b21a77ed6bbb8694dfe2c42208ecc285751bfa643870ba4dd5a6e1a58ad516848d685d841d892484826a5e54d4515f70b539fe00e63bf9ac05dac05d8e10b3dcb29244c1be4a88d526c3b50496fad3ae7c29f85e64c19bc4426b63dbe37445e33c3cd404290b3b449cd51ee2313479a5d5a17700f44084278a8324b8b08e96a3124a42a820fc8afc06a2fb08f9d6003cb8cbe709b0408c81dd3fdb502d3aeb8245d46ace98eefa89e784053a505edae3ccc7607947bbb43523ce0156d1e30ed4dec329e8d8fb9d66ed77d15e8ae3a0906b60894d9d8d6bd8051c7fe838cd81c286f614eb191d5bde825d8428a6a5d929d6083170a86e56cc9d52aec7ea3e85ee504b2cabaad56fbbb4d686810f210efb646c0ad35a535cd6843f3c53a9644d6c8a3c8fa19e1c25d9d805393a7c34d4ec5592918bffc4cec332735dff9e92c7b329e7a4148eaf0768b86fe8731b159e370787790c8b6820f906450459ae58413b7263c6824b9325ad7b29564ce72c2a034341cfde284c44c987ef680827f95c46a6f1e1e4a4a8fec02c40ae81a032986051a411c8331c44d29d8f20e77ab0de5d2f6f244ff5b624f2568f01455f0c9120a53a699335951892a9c7e4a578be54c2c109f3218dcee37250ab55bbaf9932e2a1fceca2dcb2e48142cf65fe01ce281e2ae43b72da33d46edee8d903a78049fbf21a4f20808986e2ed83684e2063cf0838fa18a446ce93e118e4d818662a2db4e14a8eb071567ae607d2e3106932a4e2de96fe5e6af6088cf9b575d881eaf4b8c420419aeccf2ce3da7b0851427ad58cee20d0c89c271c309b72609d0f348d87ed494541bfea3d5313548525f3e322c796bf5765edd0a24e0711f74fb4e17c7b3a56d63162d5f34889086ba8e4d906c7a2b7a9b0fee6fb8bc4ea1c0217e4ece5fa15edb7e2ef4cd21316ed38cf1eaf67d47577b6dccf9d07a9e6b89522704da0f46c335ac17fc0ed2db35b5aa2069449323b194888d9c3b76dbaadc7440db31a3a5ee1fa6f1e329d2b8dfa6788503d1cc6111a0b94e47dc2df48ecb69fea62f19880f79b8b720d7152ca329cbc420321076977dc9c6573c2b0f977c6fad268702075be1b81fce4dadf5d0c9144cb4211a5429c5b81ea9a676a6c84a7d80d4b07e501b93848d61f7b61a591a86ed71cb9690c9b8045485da2a45e8e009d43155257083237bc9153a390809664cb9a37d7f24b410528e0a4c942149323f621060cef00fa36ed9170191236400cc03d4c598e52e1b0dce250c63d28af8c948555b678aad551ea320ad938318825787feaa542022892da5f867b58d7c5107f2f8567c3441435dde57ea73b67345c06b68b57d1f8d18dbf66130961101ed85f64948d2dac3459ff92c8378136d4943400d7a933f6985065dc0165eb643bd8e94aee6d43c46a9cac8909709fad89887f68496742e1ec97d166102849d8a04d749722103ad1e831f09f4332ed04a01da6ee6703402c81890842c74a842abfff615d5bfce003cca0f6091c4cb27deb7347aceb6ba5f3ccffba680565b1623b1eddb72db2ff2ae0a2a29cd7cab4f5580374d0a8d6b39c12a4f1c61fdb48936a05422a8b65eb4f03cad8f4340d13c98a0d9e86234513b4352abf167e270214c127717753e6f073b9e69bf8b2fd4e05b83d4e1000b839282c9db91266f2fd5c9a314e7fd4346d70569600070732522c58ee074c3a46eb66e032b2482ceb8906c7d45fec95b7a29f7816897d13fdd21be52227df222db0824c5b242e0fb47925c4edf86f3b7ebbea21e948d7a3bab696f698c4b90ffb8bcaa5ca6acafe1799f1e86a5a3d584268db7cfdbc9692d8a8d512643fc24dea5e2ff77405c98b91c6f5543517c3f4de47632e7bcc6e2ae4e36e66939e67d08039f77ae68d1ba7c3620e3680e97421ec0f95524b3d2b2556b2ee966778bcd3a5421208343d97fe38f7c954832a298ab623af884e05960724d192a862ddf0f851b0975fe117111c77328bf93962c9d2af05929fb8950b28ed22679796940c9220125ede1d846563e28e4b7e01d960d10583dcbb4ae6c4dc5af1b5f5d45edbca2efe38aa96df4aa164c6c70434e9e33d0c4a0e64bb16cf2bd7ebd0dd73ed6289a420f9e46b5145a9f63e8dffb9af89f862fff25f0f327c531f3513d9ca424a8690c411cde461e78b164680691bbafc4151324571ec7cf0e659547674162ed44921a56891a4629539517010fe2f1decaea9474b2706f856899afec3736655d77086b47b021d14c1675e0f370d44e2e638271346ffe0f251953d16dd1cd3c92480c1f62574782bdf3b19a7c13de8b38a800f6df44388983be32d6655bd6f08ebbe670b69a77b329ec0a249160a49b65522692199f07b4a50deaf34b747bacfdc7f45b15723cb7389c09dc442389730ef3b242cc7c795196ff50862561be4a5e42f3911b793fa49297edd11cc668eaf5d7cd2e3d8794544c883ab04c116e824b4ebae6c8e1e07021b98590cd1437f8b52912cddfd60ad7192e5bfcf4593166e71b93b3fab53dfcf028b3f8cd42c9daaf8114eb3a8e582e6c8d57cbc7eab1fd553129d2311dc83cf247e44a3ca5df62db4f25c6c497fa193b7355a4caf53308115f6a7f686b980ef60f79368570ae577d7a017d8d15ed005d95d9821d4409e45956c933a32f0254ab18d192bdd45bb68afa239590e0804ea30b3298b89c4a7d7dbea11bb83aa827589d0ab1303f210ed2cf876995968500a45fb34d86c8bd4230cadd345b88e5a171a0637a9058530fbb69b8e55ecbdaa2c15cdd380444005e7e633582847f94faefa49647114c0972e17f5dd7de7c08f1764e5f75eac3c5a8619e8b5c7dd43b78efd8a087051d3b846e853b266a0ce9dd61467d0c5753d16006c13735f58c0a9878e1a3d60be0a8154db1610332eb684e4917a40340d35683d0a9cfd37c62bbb1973d11611f2ad304cd5c031503c9d9f5187c0e6a6f3189b3a4cf190a52935cff9aa469001528e2910c10c21feb833335ea61ab5c4b4b1e9d9edd80644662e5d8826ef173a1b17be10f77444e2961b5024f7e0fce9e73a0631578b3c3d0115089d8220c200b147f97b492b2650943037e87afc1fdb51b5d3dd75f9c90a5fc79e6e3099da25d621242ba8f3b73831e84f48d644255d82b7bc58b713aac7f5d44e011bc4b2106792ddee70958697737bf95524c0a0ff407c1e6b0be0e25ce8e67094585a2b08ed35f28cc2ccb80978c8de63e16c50f20d9de140e01f7a070c0de6dab07f00fda3b960c2810dd25117aea9b7cdc0e76f711febe7c2dc52a5c650860caf8d4c4e06c7e950d8af29a6005ddf501e7fc3fd2576f1e1843d31883b67a9e0337d5ed5119fa8ea88127416ecd50da32cdeb9e228cd64f784e5d6505f4fa255b05a65c69b59bf178983905444d2facf856bbfbf7d1f937dcf8fe8f060ad20e042e501f9390c05030d439aa9dae4ace874076f2e9f038c9757a3bea1782834dd6d6c1d3e4ea955867fe802b75b758f3a93f8dc675fd92a63a1cfbf573ed763f9c9eec2ea4a9a624821cf9c7945cf0e465148235709ba03b1b9384ac6b5f7b2084e289477d2b2f22108103b4002a62ae538d4dde78a6e58aad2f04d5aac7269d05f7515dd95c72ab56710839c72473a308ed1fcfb9dcd217e075eb8465649ef74be13dcbbb06be57b4f50f85f3dc8bff37ce9076eb9b53fb12a7d149ded86f5cda69d2de30f90321600626fdd3f248a05c4ac479325824b20309a39a7319a1a8ef6c0060cf3ebabc54a9c6f28d51a890acfb449c383b388c35daa1ba42e3ff9589abaca85d76d105585f4715b3a073b4405a5235103041d2588a4cbdece0f8c243a1f00acce22eaf9f2b22c89ca119f19c96664733510a35981a492f49951236e55f3851a82afe4f07a896a9826b505e0d55c81383e875b5eb2c9b1888a547c79449bc6869538051bb6af12679e3b2a86813f24fb7d15019254962d6556de4b431b064051b355bf7d0bf77e5c28b9ef188ef7fe729a5d86fd040caf43c7909a6bfd5e22231d0dcf78c2eb876fb076dcfd5cca83efccdbd58e46aa014098a5566d54a1948f37e79c4f58f2058a8eb07da2d0b93859a17f2200eb6c41eb0edeeffa14d53868a961678a301634a5691613104fa9644d5b49217ba7b67a0e21ccc37e7b52ff0c6a3300ac508502789793c8fc68d1994f3a738403589ada8f4c738fc1e83380f1ad53852a74c94060982075f4f53a1eed52286170c7a7a000c719456efbe02ab8f3ca3de73665d854298e3d67df5e461ff38c0fd64e016b7f95ce1a5a612ec2f038f9fef91ea3d39311b8a4252e9b1bbd570003d238ac6b5c30bf368234d88fbb415b28a15ad4a3a2a001799b9554988dd81f8557357538e03b5f1654acf5072a9e11cc67846466343e08c70699d5a48569b0097d54d385e96f08f40d10aef800a135c3fe869c20eaf2e26a191f30d4a93529b324358ae2f7bca1bfa3938453f9558228e3ed8404bd4e2840a76bd70252b78c4006057a8e803d1f36c6602964584fe12f0df32be838e2929653ebfe06771351716243d6c673e911205ec3963d3604aa9e470ff36e0022abb987c63daca10d74275382b177f5b37df847ec7ff00bd314ba045f271a0d66dd6109ace768cc82dc74e51ef7917529cebf283f4f2268c5e827eba2f2462e0915bd168ea2b83049ede1ec16a01d2455d35f3841c952146e93864fdac4e13bd59d1fcb0a89f2dce414ce5fcd51797f93f0c4ef377e4fbbf7026053244fe6a4166c811c39a1abf7e83ca528d82e7786ff00b06ce7307c342fbb07259edf39ce2ddee03259e8edae98b2b51e6dff1f5eb5c4a6b1d37b940d1b9342c2f8e7a426661ae82949055b90a417914eeb95d8a2161c1f9b672b7b2bba7a0e8c4b20f270eed8a1bb056311c541857b70d0dc1d0c9aaeff785e939ec306a95ffbca6a066d70ff888585d7ad1236fc3973909c286106938f3dce9aeadc8b13dcafbbe48685c09424ef352db483e233fc391ad00f5ec820e4d9e0d1674551aafd6bdee59d25f7b9d393863b0f612aafab979754d9aabb5d1b009cdbfa6f8e7fe984e8e1fc695800d1d105765b253035f93eba6bee8f4f9fcfc6786168e607d6425eb751cde3c635d8c52dbd3a4cd8b9d54328e0d0ec1b309fc5c2b9e05fa6904b4faf9bac72189a7bf3e17a9815d63ce8e1425d70d3ccbea47b7d7961325e536488985d297ae4adf84552468e812b866252d58f455bb2b142a048ae7962cfd8a464742b036bbd040bb9d8b3d6c653d3182cc268d07470989f6d5e36fbf06d13686b83accf3222761959c36b1461564c18ff7859322fec2faf69923feafe973ee3dcca8d797896d1f872e734e9133b003025ca09f77ab16225f7630af111a24af7e20c2862580982b4f2e37a4ce387d71abc3a488e02864b18f047c11a46d8e30ee983323585807cb79795c8c16e6ca7c580fe4eca1ea73b684e4c3e18991d91a59f41073eb2622064344082e102a6de49e1fcb71c7f52961c16ac2f57d02157bc1801bb859c038ab3561992e8936978747c77a8569b1a626fa55ac084db28864881ad4c67b8232285e2368357d055342158ff45840a1cb3705be06fc266652b974ed401237d34883f6aa1f6489f6eae917bf5e22693094b80770aa58a786b2243cfba3ca1cfe20de0d7762338c88d1f2201a9c21b7ef1dcff607292ac9d2702ace966ba9db05da2614531b33a1520e831f00afc957d36b9600b816acb57b73d5f27eaadef3a11f515d89ebc27d6e33a3d744d0b73ea0d21f006e0931df70fec35eb6fa2a95957e27f1faee1f6bb26019a89870da7b52c974b0838817049f77b47d2aa88fdafa65362f74c2ade4cf4f7ac7e85389cb9654810be3d7eeeea765c2fd95ec75d3f0d2c43c93b970225f0fc7dd6fff5976282ffaff7e598f540d3257fde4e1c77288061d3cff68cd86b097913960bbf19943ff77bfeb83f19d0d93cc286b1798bc2703bfad55dd1827f301c7c211d750368f710f326c11fdbd36c413be0247f21715eaf85f0ccd8ab68c85c701229cb02d776ac768f7371aad0b8049b42841d3822add91b98a46673f41f43146fe01f996309871c528da3b3e6fc21b52f7bcd10fca3a26c8ceb917e04a19fbc76431a93ef4f916995f0d70c13af35784078386848aba3dc338c5d8f5dffd66960184687b8d1f995b15c256c88f09c4392181f02e072a10be4f43151d75fcd3318d6dd060583a26a8b2fb50c76708184642add16695894b8d321646c36168ab4965402b73bd794853d6817c76f5a1491b609b8a4f5efb8f75bcb8ea540a4b92aef6061db23f818d1e24bf866eb49eadaaa6dc7b41ea0f6038ace19e6817024d093456dfbb9a4bdb06edf62ebd7ff955a58838e53b7acfa7ba82000f2b2166cea6721a3b3c3d6884de63788712b3b50658acfefca8ebf444557cc15552de8e174693c71828140500987009403165a1cf970e52f7c42b8888506a9d36afb4b815e4a2ef784ccb7553e801bd7fc184102bb7937138ccac9e56baf9200192f72c2cc80bd4da10422de51fd56d4489a1c80dcc2e39c9e3a0acca627064c1638afd6b730ea1020c17a3f3b55e6a48f2c021d59caeb4fddb02cffed3119c8336a409a631bf6531870428ad55f99d131e3b872138c32bf9283516a8e705551526154df6384dd0f18e105be7c379b8a58441e0061513fd794b9bc0304d03d5a923ff7337f716e8aadfdcd3977f44eeb366d49cadbdafa0bd09637290019e0e37d50a021c4075c83f69309f29a9cf579ac555a7ba8c5e99d46715e5f81f7db1ff783cb234b595c22a873c0bb79375f3c1393be090e0ef11ba14d8a09d7f29ff32254e1c15ec77515cd06184f7444c543bc6cdb5b883749bafa2c8ab96e53ad119d41a53238f2025c736029636051f80918dd753508c6a9b18562d1f05352f6252b09ae979b512fa5e7c7ff76f2d468a6d89b973cc192ef6e261ecee8da3423160a341d6ab450940732e51250fd8a86bdf58914a880a59d0b28e0f145b043bc62aa5ee5c05fe8db5af64488ce1b024e110cd88fe820e4b54f9e0490f4a8af7d44d5a763b0ed2bb2d77eff363f786aecf55747590a8e82f8794495503203fa7d68ca90012861677652cb358f4ff6e9eb82afefe598354c8765a9f6eabec6fa9d0cda42258981fb67f20bbf9de5c0c9c7666904d3934f88a5283f0aa8db2e5a9c6df55ff6bfad8ba8017e1c0f4bae59f20156eff9096e9385fcd11a18e5caa1564e0ca7be1e183651cb2ea63567e433f53f0d688d4fa1208a82c6d625ed651bdd39361537ef3fc170634b71cecb657b0193d09bab1370dd53d1a5b32d606e8102f7cfc7347a223040609571fcffcc28243c37aa46ddee11c95137fd21084bddc41077dea0a5d17440a4ffe55912ec57dbf92773d8bd407d903c64c7a263592b70d1e0b5337d304c75f1e3dc98533ef78ba9d18be2a6709df42f9c229d15b57a9d47055995bfd68f7163a4d4562256bdb9947f89623e5f8ab430a502a54b7b0180afde9f11a45c1b143fbef0b178336dd1f16fbc2d53a92a5c4385f39174e6ef021eb866a729f4086f07a4a118f0af584f05474b3c07e3af3c9f6293c4a37657e4785d36d30b2e414defefe6838306b96484998686cb206fc610d7022a90753738b741e58b4775ee5cb62d11d8fa37d0b313e7c3938d757191098d7ff5a914283fef2032f64ef7867a24dd340a4dc1504a59b91ed37a241ca788247c3abb50d082e25c0920d7742dac2ccd51ad59dc5b4006ada0fb1d8cf80b9f4d53884006f828dc413a9316a3f0c56b85e81bee2dcfc4795454cb027dc4f02e652b28332a82dbafcfe3dd06f6bd31fb5094b0eaac602232aa44acfe8f78c74c9a34f1f3bea058bd39424da1529afe48b8a406b9497ffef2352b55cb6fef1cac29abe5aa5d0c2a34424e56ac608cd3d64499021413ea7bead593f1ae6356071fb510a3f36e383018f7255041d8456f941ebab96e6ad8515b15fd31a8863fd066ebaf2deac7a62d404a790c1f3fa552af24884f75912ecf00b83922eef7e9d6bcf6d3640907e2a3f5be42e6885768200e745d484f6380a7eca8004f5f4e1ca5f21d959ad53b7479dcb8b30fe4dc544f2cf679372b6145aa43afc43f745fc1fb51f06f76b6cfe1f387de1dfdba9833fb2fedf615f3f1c81a841b7853cf7c1f4dd8fd76cfbb6db2ab9c98e2f488c775a2e9a2a1f71454ada626af50107a588f9631a0f4b0fb4905b98b311d3c6aa68c96229a1b7d2bf178eaec6747a6474b402c23c4fa1bf6f4369e1a0cb3ddc7bcd359dd8c97858192f0c232c5101e2402284d84c9fb43172c00160e45140a5914586112baffd00c6041a0d8c0d965f15e22c2af9288fd3604dd75b31691ecc89af2728ffa758d568b43a34abeeea661971586d58b800daeb64de45c01deca1ad9dccbd80ff5beaccf646b3b287660eca50199ab978447e070f45afe401c091068c0f48cd00372584576ad3c7ac8dca81f84af545ad0e43a3ed8ad8f3a265cdcad06d2a8b41e13bb81d5b97b209f844975933c35d17f28fe78f4f9a57a01697a314bf797f07232fa0a1dd39a93ea3f37e8980d5415785c41dfaf525f066f9547e22a2ef77d82145d1d753df0df8c96cc5be124d5a1ceac0b46ccebb96f4586833f6da56cae5b95429e60f58ffb99d807a99baf29f8930de59d8823b0becbd570023c070ca1b87721fd8f0dec9696c610ffc95dfa016bbc8636fb024df06469b1261d4b0d736d59b7fb0261551dd648ea84a83173e531c3c01ce5652cc3cd3a3b5f9359eb5f441ed038edb8cc5da1728db42242a37d9bb3703a472f42c0134d201115376fff801e9eea1f0851ddb8513c04454f781b1b5cb9751ce03c97a7c7ec698788d2d093ee1994763fe5b876ceab8533d71ccf77a5bf6f022803d4e54719555e19e1ac2cd3f074564df363b7a19b99296ad8d68a37ba8709ec59679e516e24361535eb304f42c065f1c684cb6e3d598687532a17f687a8356bc7a935d637a97299c7088e1492f526763a16be3b934648fcd83057263048d734f4e734f8d70d6218a8d17d9c9bfa423303f50db7377d5585b3e4b0c3dca8e289d11167ed15ea6cc5341f498d09e66fae4b5cb9f51fa1064042405ddcae9055dc85761798b1ebd55cfb61602bf5073a58159de59f4bcee5d2d180d5b7d710b52d88938d95bfdcb0ce33d30266e18fb282cadc3ed3806e8560b8cc660d882a52449ec4c1f922b401a02bd2faeda7e435a2cf97d403994acbc945d77789d0fe507d97f5279938112cfca242f371196696119a3efe05c9d1ec473980b931472fc60f440612e2c834130c0109317d995ac5d32426d2028967ed1620b4b5cf72cae86e27e1ccfea8b951ae37c591ec2710fbed68180ee19cb183b8ea2e089c0b641d6eda598431fdb24f34258a78d48075ca32c9d2cc19b5662d73647ca6e8ac4edb20bfb29e1652eb03ca207566d688c36cf608468477a70df1cbd7210eb245d2c9ff2e0b3ee269b7fd91e125bc94e816e7ade02e845987d4b655588d691574d111ccae888f8c173eed6a9fe1961ec7a9917dc9378f93be2f28f5567f023e4c92f23a09b6872a0162c2de579a6f37272b72fcc6104ea62aa3d3b303b9e0418e0330cd3131a6d5fe51d45bd8b68fc6f4f9ca2c878798fb8be51ecf19929bb88a3b53e41ce3d8736450f9e9fe33e7a00024fe489408547500d7eabb6111c4f25cd37392de8a7b28607ea8997bcb9088fce3b9274de2e24c558abad82ddaaad6d5168c9b568ef16cf3931a55f8e8c13f50dcc505d6257e89f980e3d12b2b3ddc765a284bc5ba4993eb247e18c43bc8e3c6bc9258302b701bbbde3c70eaa2298cc4d4909626b24f847d393c843fbd435e52b1bdfd3e2a1a8bcbb4c8e097803d06644e5841464a88116fda5a345450dd67b295714df5a4ae0b74fe81374008098a4b8da50cc0a55b4bb6101f91e50ef2877598de71d38888f03699db410d26de4ce8ad481dc480ca5e36c3175e89386e9818ab5299a7c93d7c91360b03e21af938b031de8243e74484ab108bbadb132cc0cd4800dc8b6b3a169c9d14166ea2a6ca512436f27a0f4f3893e9ec24819c2058e7a8651b98f6c0800a0942fa08d8748446b4cd6956cd25100c1bbf89d89bedc66ae24591c6eec784257a20a92d22ede8a4c0f0cba6dd160b7471a7982c9631a2c64aa30c4c0b0b31fdfb3005c490d2a58752ce41aa119d8e1dac2027470f484b1ad9ed4b1406fa8180840e394267f4aa14c5eec152666b621c47fa2ab6f45fb527f7a654fd97a005a5c2e49f4aa22737c659dd2cda5aed7232f5b95f376b9d43d4404d274d4dc3dc2c221bc95c63498057c21cb9d9bfcccb3868d2fdb4bbfc7f764a2a747c6f599deab90e53acd82cd9eb7b3939cad2fac87969c5169b6d5d28531a00e8ef1d490e14b1b30bd0578243068a6b8875cffaf209f4b5f8e1c0fe507c802b4a322e24d47af489995993a0a5177bf41b84cf1babd516b749dba3d71a08e8984b8c25e1d06aa000d3b045e918f90c232a2b7752ec9c4c6f1bd76ba55f2f8df3c46e7d4a87d3c6d5ecf4c1998cdf51a8860068a2076a689d2828aadb4fc896d38f235812a4374cb2b60ddd10a0e1d3fc597747349923c305d006da300f2ed1c8bb5d18d9382768ece3de1a26cf1f261b89f605d9e04e61bcf44dc7c43165497c866d2d19b9d00d1a44ebea7322aaae6959ca8921e767d3bfc1b692ca5dfdcedd6de2ae4eab1ed75918c08ef84d6c45d6f850b5f48c65f1486b0391874c220175311130e7a41824bc7880318957969554e3ce14a39b0d65564430ac12027c1ccb96f22e705c6a588e32a43115ed02af079514aad8342f77b600a0c5b5d3b98ece0e677046d02529078d9e37e51a291174a4e86d2fb8f8f6da6b820aeffe3ec6879652d5b955f54ee5cbe284df84ff534a4f2d5cc10e679915d15a7ed8431339e10bfdd38349e90b0182184f0c89053dd57bce63ede097c0525f15a53a11b5c63f00df1c7226553bfdbb5c36d7f68f7c41b623558aa9aa91f6930feda8a0005198cf888a2b31be77f52004800177e0a3c30dbe8d29282e3768b8908a52979d0bcf4c51ebfa4de342f0d8e678f1ab20f3df585b897a9dba7385207e01ad5c2423de4bbccc796a9db719e87092f2cb2c18d4de456a0fbc6c3fce32961a8e7f217bcd6e9887e876d80cba1dfba923984a615d38095238ce1f384bd2ca10c6f34ad5a9b69df25cb89a63193be925027dd2775e6403178f5f152dae8e8fcb587e800f1611d9d1fbef67ef7c8709e119c1fbe2517a5afd2bb2a836036f3d81ef5970f6df62436c1e2fd4157b56166f3a4d0acc4e738467ec56afaf9b5b29aa151e5b7021d7460e86c700d0d248e76d0ef69f35e12e6e6e55338a4bd6b0290bb211712a7b1c1e74f7962fbbeddec2d6cc92cfb1f7f04616543d8f527016cb073fa717e732c0710d4547959e091e8c658a9f2c8aa48ed9c89c986874bfa0fc3ef87a3deebf669bc2f644b341e925b4f72d8d83817584fc7c736de12a68dd25a2261f179b0039bebf3b5c061d973b327f72531fd6e005d88d6c1e78a3a949918702efdea8fe0d459c94f73e758dd333593454ceeb980e754c23389b5e4e60bece41713af37f7f4044e07c7903a248f8b1d8cfb7066a474ddc52e074b1be9d46e1f569e4bdf9296039343142bed2cf3f4fec7bd6f59d6526b16504fed65b30f6431ed16e624d880de8d951f904021ba4891514463fdc557369e3bd00c67e2fc0ab7ce0569dce84e5a41e148963b925541d6964ff8954497997d28701e6260bd4dd99e10cce432b31ea34db9420f0713ddd7babc91b3a2c5614a0519da2270739fbf955724633d038d0b9b452c9387feecd72c4323f2ce16394df91e0d466874e261b928b64e3cf22959cdef7ac6c67e3634cc8f2944fba34c47db84d7dc2bd7648e80fda5d2f9e7f18d9212f5a528c8654295b2ae74edbf457d6942beec5e2049c30b65be1c470da965f9b326d1c6facbe59dcba2012310be5ad562c56834882f3b20dff8fd730166ba462d1d38705659624408bf24948d8e5c565e0c1037a92ed672b49084f4ff26cc4c40d1ec67181aa2785a6005afb3e2802fbe27277117968529fe31650c4228de1b1cf361d5d5d19eaa1a9fd9c27e142153458a575388e2c5970c2435c7b39019c0cf2dabf91aca5eea146eb69fb99adc144240ad1f4c299a4979170ad9f399e1d814fcf27dd1ee23a9484834227419640ee438e4eff9fa74a5bc14180a9c3ff17ae43e5b54f922e96f29ed4683b5edd7918701c4753b1eb5d59ccaf6009546d131da84099d6b1a80ebfa0a213c1524d5cb2fc8f90c96fb6a03c7293d5cfb6fdadf60c819c379fc23de0b1e2c79ed40c916ff5e5a1418562da68bb839c9e28372bae4c1cdfc6d4d40025b5d94fabbf12936a31f584253c6f217252e709b18014cda517ed7f3a660895ba53ae4ac50df543122c4bb2bb183f11b9ecc5ff41dd3d92d9845c70cdb8e80704d72be2cd1eb8c940afa537bcaf323b6b5b226379a80bbc1066b9a1532f0b6be26335c203358061598fff38e1f649f4e77aeef87f4911c6d9818f420229da2b06a3fa08f9b95d18062e6faea3edf2641d8d35f473d2873911d030554484889eb81f7c7a20ef3931c5df86f321348ecf296b33ea11a0d9cb84614e340348d2c04d1b16f875c3893326548d37f0bceba34c73ca9c94882574f82ff807532b5fdfb2dd31c97a0f0c8fe314b4453e1e4e773cf4439735072e037082b4bba80f4b26d1b70f4b468556bc873087c0bc9fe87ccda14d5191a59e687f100268813c76649b6bb0ad48583d25a88fb539fd8b9bb7848206c7c1a160f388446345d9c32b083192f2efeb37cdbfd5815ae30fafdfc2f60b253422460a907da1d7715f48cbebf8be56b5539e8bf7c2733826f28d8ddaaa72ae30150be1a6debb3b5333d1c291ae6fe135ef674b410240bde6cf54f3075348622e0d4e8059b9ac58238329719ac154fc3b000ced433dc01edc52b60aa467d58bd9b16ece3663c837c2be63389ef02eafa17586a12c74e50f779c6118256b899d1e95e70bfa0798fb11412f5bef40d0ce042e7457545411e5c6826ecce962797cf644c0836cab223528a3505486b349a4bf4aa66af21eb81c1c76561490a99b05ee96112dccda8888e217caf5b715c3f5ecf0910630c49377e8f94e713820d085f283017dbfc981b90ca9d0938cb3afaf07a06824f400b423f4fe4f049d43c3441c8b26e5e233842716450714cb168d0009e5faf015c213cbc61a12a553f1826c107adb56ddc22265407446349e12d2b43cc99b2f06ccb20160bd6506bfb396397d394f4b3a5452e06f21860bae7a31a2e777339997e696e586f12526119a6c654fb59df07d145f5a55186b76473ae92abf178d03733b2d52e2457bb36a071dad4632f413e4b3b4f8293b701b83c198a981846566b2a95c04ad885c80a93dd61c0250c548c2d19fcb094140e9e53b5ff89270d10a7ec9523e9549953fe698040a8f2db0989c8050ef47b2ad4755805ef71ad42eddf40fab733e36c0b8418d69a954d325ba78c4c172d97002a06045a829f8dcb76fc01b8929cb1dedd51d577fa49dfaba1870e52d95ab0ee360d15be370571ddca3891b0c2f2f799a52b0e2a7b78efeb470b013a2bd63e8379d5f902a62b35c1fb526490a1291cecda570a8219fe2c714e7435957d7963e3214a9f36395cf87a5c5d0894237c7a893819318abb43e71f7b3a877f425086e3744f093c3cbfd1016d3d5a462f0f612c851e806781bee0ddeceadd34381be8e7fe950b27a8f4a4f691c466df170a72e2da5518814ad1a42b54960f12c32e4915575639d802efd4c3bbc44135d7f2491e4852cc9266caa4581c520a55ff197cea635a9201554ebaca6ed1689690cc60c869bbd2403985d3b1f95e51f4aa209f7f399d2c8dc32b708bd5f8abe2c460f7f5eea64851ed4da4ca826988c09644f3640d2663dc3aeafb24f35dfaff7f1a4e2a5da347cd50f6d526ff0d717a9974b4cbfbc27528f753e7951a70deccb4ca54d4241b0a0f112288b328fa2da6d14a8bce4b28658638e96febdfa0e1275a31633b3dde218ec0820dc641c30a0221fc362a1f96966eacd8ffbbccaa44e2fdffc568d3c11e4c832dbbdf9860eaa5e781e80898f2520dfe9f870d724d38370272b1f0bf5b82e01980f551d3757a90fcc07472a62c3d913913e468e255a6e0ad3f9ea09440eadbc7507383dfa98caf57892638f50b0086be2c2cce2a38fcdb190a71c300273068296f4dd112bcfe5c121d6ac597e23f765e59855306781d9bec5738883d502059dbc2640efcf53d129596120e084980017c0ce202889909104845ecd645d6022c746889d5da2ac4c615121495b7d226ebbd6681bf9a0849f67548627011a1021eeab423677f0ff43edefedcec75739bb77745019c55d97efbbb7a13687c6dadce037daec19fc309100b18c856d9ebf7dc2830fc5df202f38409c61b6d7c56d538ea8efbe5fa42fec3f96ecc5b43e869da65fe09c1328d045b1ecba5b1d93346190839fbeb81b414ce0227fbdab1710d02b647d5c1c052e4f44ef0d571050c968d30108af3ba8e50c678d3d48cf5c89bc6dfd3577d3bc56267cb811a52e8aac83d57b7e6741cb07a69c4f169c34f06df8724a03d9043ef85f0531879d3fa91fbfd6b6c1341ee1df38063fbac9a88990bda5dc01040ec70da60d34cdd2b24c9472695dc2ab95f6a0a2525abb190c19196658abb46a1b0cd538957c78d267d2ac2657b325902a32942bcb6447e9c864a1ce91eeb687573bf38fb406e61b349756714b42bd2ba3693131d951c84587bf845e50ac73fbf5994851a8306c1fb26ddb3693c9047e9e49eb93ddb66dcbb20c44927d03b76799c8b027404c1f9e00d1e4ec2ccbeabd937dd263ff78222cc7b159a753923b65472873e15033699aa66dda2626c93e395bb7539f98e8ded7b2db3dc99268622786656ce13a544dd3aee338ee1509b76974d26b62177547baaeebba4929ea66d929ac0f6d17725df78eb5f29ab689b5d69ad55a6bad477855c239e79c3da137bf9092279a1e4faf076d08c6ec7e61f6cc204584930d174f01c31d9a55dfd7818766f18f5010862a6176a9d801566224552fe5d6b9a39c64c8e2223c1b3dc8cd5ac167d993cb81cfbc135f9e27ae9c49e7a107c303daece0ec3abbceae53d548efbacf3375e74e3fd27ca46350288e6366247c0d447262f17bf965af128ab555f5a76b07adf68925e7896568124b542796efd1b866814a8c6c1d8869b0071e67a3034bf8bd1196dc0cf284328cf9b523c4d0933b672c89937aed34d8fa2e47465c56df38a6e64f97d24acdd3997cf3504effc4285798c83ce651660e7e8a4c4299c75c4aebb35168fefd64a35c6142f3ef5172fc741d148439c414a511c39fce04c7bfe3f877b233ffaccc71d82354d5c55e2384b375657e464cf5c17f9711532da67288f9e9313ffdf47d3fbd6c57d82e7e38e7e4a6455110499590aaf8324e08c1c7bc0c3ff124c65846a22a3e683b885148af9a3dac6e73cc28a4624ac904eefcbc25235d3ecf9605a2476e4a7e9fffec12aa126fe8711e79b61c6fc9af928bbe5976953dcca33b9f89506ad74ae711526d8388d24a1b88459e925ac24cc4784a121a1184e55c0ae3838e1a841da414c59706f3a4593797ef43b3741885fc1ea6196a64b90c0e607ebe451d9af4c84fe5d02d7e5115f35d00c303c9404a588ab874e9f2ead241445b8c6247af6695cda91d24f0f31a22eaa016e2c1eb1c67fc60465117622c1d21082e984b49b820092da86ce9819176b5d3eba020acd7be9d63310ccfd7f9558eaaf8955fad0e2e666b8248964ce15eb9f36968106adfdee7a57398ed5ccf625d717682304a7d6a09942b4c4cd72ea5a58950a204b125b5c453153f3553535cd2e4dd5b408af160718411366f49add9da44d796d4d2c414103dbaa88a9fd9d96ae1c70527c2ca4434fcf0abe45ba572c8cc41414a4b94952865258696f8cd049818330775cf18d151b34a66e212719798ab5facc44b4cb08264687b48dbb641f1e509364c696ce1b2e58b238660b4a50a9810926a9ed0b9c2999a78c1185014b1a5899a273c7ba7381e0d5d8e0876b919558db2a03b3f6de079dd59ed1d306156b3da4d87e04d9d92863b6bd44718ed69a3519808a34694a42d130c06ab2af078cadc29a66c98539cf6728fe135575ae9a454bcd9b3670c60b7bb6adbd711d18ea86e5c57ca514a2badb423ea0e964d71a29df5f481bbcfddf493041de5a408bd3b635a96b4b85102e6e999a1c8a867a0052923ba01125f0c6909a3886f862f621fcda843137edffd686ebea2a16ddb52b004161d335a40842a8d30c6cc5c2715caab1d9a2297e634df0f683eda535457ab8391c2d32697db03c38a6704729dac4e1cdc5ac56d708ef55d066e77e0bb5b3da0d5ee13d862ed31c8a36fe6cab5f64f385fef8c69a9526b15e39c96155c7ee5686e905bde1411010630a4b8f428308a70520a97052785a52f5e20a1075f2c21c588257290841438f0c10c8ad0c0e04c5b0f0c47d80b23286e87a8d0c78db9333686d28d654e30b7c32f8b2157b10c7b6c9a27d9a5dd2d721d46c81d45811a417f5f28a1488bdbaf218a88fe428adbaf7dda030d8828010fce1003c6829e00193f0002147200840417ad46157561a57e345f4813c40d9e811b3c5da411533b1a1d1af40add73cbecc28516ae0b226e3fec2205b7bb58e37616a1db599070bbbd00baed85106ecfc08adbdb178f9fd082859e5a1ae69dd1222c5bbb1a9d49229ccfc437b5f33728114bf85bfef2390c57c475b2e665aa6597052c214d9a41b41aa32a8d8f10d61825bb059e71cb99544e235cedde96dab6690652bb7e803a0a57d82e2eaeb8335f6c055deef7c945d005637ab6ea0310ae1e9ad555f968beb8e54d98bafc85372c61d2a459d9b57376071d485e6a1514a68f1096b88804788876ed0e9824cdb5b227462cc7d578cbef7ee217851c2f7b8836a291b8dacb5ee26a6f2870bcc5725523f2207e87880a73e010cb20b7e4221ee8d7809275e022fc8439248858b695318aab3d462c0f8a6533715173a90c456ffb364bef0ca2dd003fb03ab9f94d1a765fb759be9e56dfe0b51325c3f11225796895c65903fc0c4d56bd124eac73dce61c372897e3441f7ad478e8f187a8c759ce241327b6ab1379a9de549826e990cbe55aa2a55999aa8965aae65db24596a99a97b5648b30e6386fb9e3064142c8efcb35ab66ae9316da693e959d6fd6a50a286e972a56707b6a32f7bcd6344dd334bed65d05a5699aa669da4c0e5a4124da719c3f7329b57cc269b67ce5be900655dee078d5001077bba594ab81ede260ca41d8a12e5cad9a7b3535a2eb0aa75d137ba0b7e46f40cad5c001304a642a8d01d3e53ecea5cb438f7346641897d9e58e5dc43c50d53cc741e9713ee9713ef43eefab9b58c69c3f588f934a8f5042194e7bd2e36a8cb0d2008408a5c7d9415335cf8573d24c41619402c53a681e218427c8600744e82d6bfc08018b2c6082d03a693acefd661855cd4feee3aac66aed6b9aa6699acc35ad65440cb4e8647b29656887a8699f548788c221c246988c58aeb4932dbbcb9def18f012e871feb31e0f946498e671ac55f34f9ae4d60c1373614bd8466217f53803343fc9b0b2021853999aa644d8aa29a6fa6fd22c6e8a31498ea9c1674cb28b5a353fd7b8f3a3126139f608244cb865faf09df333421c373345383f6f0a756fc28bfad1252c79eefcb67dbe675eee0243b33631a59daf26726c0617b05821c2cc728c8f7a9ca796bbb8a006c7e6fb68be8be6dbe83ad635e342758d169f3fd2b3ca18a008a21d66f6d1843d521afb24fb687aa43deb10680d6284f048f61a687acc326d45ea80f5ccd0378b19b101c3cdb22dcbb8332dc0b819106e769dacbbfb668c8559b94a696f2bb76c2b7723fb7586121733c808a38856f61a28b9c30a159431c50d17175c5ad957d97bb26ff673057953a73cd52ab2185b9a41413488aa681025e98b55f41c17244455942953716982750961495f3410a2435c44837da714e6f2e207062d9a0213d590c0e2d26b302ec26929983e5c1166107afa351aa58684c98b51d26484c915c1644ae221f4b4f48ee00d813245e1d27b311c97a39cc7844b0f0661921e0c3cc2a520132e05a57069cc082e8d3922268932a6894befc12819e3c136b1447d65a28f11a2bf492c7bc07731429ad06968aae8cb18a14b27c81561fa247191d3d01c424f7f2a62fab078c5a5a755c484094b135215979e863a91a3a7a2247a32ba287a1c5b84f39627a48a6442aaf44a979e2231490e33552f2ec26ecc21464c7a82c9ca4e994eb9fc12c72de9ebd22514c10296903fb908dff9378d692a34b89a6530a7989f2f5a6071cb151142700acf8cb0bae083220cef8c699102930bc2993b635ab838248427379c10825e3c20841b0f3c2e687c4284592cfb819149085980616a41165b78485958f1042e3c719ec993c2bb020666a184a98aa12f0b1318d161f1f2a600e3a8789956dc128cd8563d2b9e1e2a8a3a6e35841f8d0bb92fbcc288c3810a3221ba713340a25a11d3569c900ae8aa67c5d333b46586212e59c8ad807a862a8e6a4c063f3f542c71589498004018222e5c8225e9e1c7ed38a209c315793c68e20dcd4af82d41c3126a47e84a1066494b3af098d0441926686206d90e9aa8a2a34108de6946132ed034ae797a60e08b71bb771c3de165d73b81979b3dbbc6725c165336748b4777b669c89e725cef44e47a2799eb75dcb6715a5629a5cd9393d2dc409e3741fa7537f52acf4a659ad01dee80e950e7362dabb4bbbb51b4bb3babddcc62d9e1a976777777777777770e2770d39a691bd781b533795f8cc77da08985a1100469c0b9a8a31924a6fb84389e3442b7ffc51899804cb0cb13068db909283c859ba9aba18c263393cde0a8210e5a2bad343942d47c9b864c40e15773e8084d413a7600551350b3e68e98534c8c09c8046402aa193a25c106e66e54284a697ba935b24628d6eea6b56bad599669611d79d334a4c951ca5b4f8d87086e68074cc8cf6a46bbc70bea1018d4ed06ded4e1a655ab3932ed9e4635dbd7dbbee9996c395feb14b9bfb89627763f42bbe6c01899191cdfb465e699be0a52ca4d540b4a9843394e3232dc56afe940a13a2ef5181e789c75266e337d4c88c4a01bc20e6095261d911ae554dae252f10621ec88c02438b78a26a11d257c6076430d604ceda9b25ac59c808c4f8ca79075fec4439925d70be6830f424a218a9ba2f35c48785367c22e7733ade3b8af366bea342ba3df6ea84106365e42fe669b2c89356bc70dcee465de57571b58651c3f90bef60d2ae6f46d5f8109d33f640ffd8290df554e5f67ea1a3654511c2daa228bce8b212a389230f4041cdd0c1ae672b9506005159e1552a89d17578cc16937e8181643e82eadd4603a4c495d976358b6b84c7f989b43e8019015344c10668b19b4cab9e42596440dc4d8a2854aab64170f31d18c7d5145052ea02fd850a35572121522c8000d33ae60011659a48ce00654a89146d0154b6db4501f3512855d0a84c512aecc651e8248646caa70ddf0271049783ae3f47a3a6141e59eae30e39e1e032239a1bcdc98832092980a7e5e210467c51665c06a67c5cfedce81483a2ec78fab0e5529bbaba140cb16410872b534991c54a185ab754ba5e79470e927154d04260cac6ec7996c776efa6c17b9198451afb14d7aac47bdb3e592cb620fab9e8bba87b24c7aacb1d929e889dc0c8242bdb3618f28d477a0e44dab50af7fc245ba3904f57a1d742e6a8221004a64d2638d6151871e4737423e27e484cf99381b364e85973dac6a142d54299fe36cb9e4762a30efc8614bf1e2388d2d51178788447343fb039f6c49531f63cbefa03dd263fd6761e8b1be866671aff54bb88e4de20c3dd6d79b80d047f78de338eec74b4e8597e1a832ada01a55e025d72496debb528d7aeeacb2bfb8f53f8a1096406e5d5d20f51be7c364eb5d5dd38f1f3f7efc38abf0430553c789a20f3ba94a2713bbc876cf0dbc27dbcc122201a2137b5d993b636680b91ea73ec398644aa45d6e68cc060008672c076c5c4e8895b09c31ee92c392e9c39d521c4c1515db8c4bdf9c9029c22333d4f064bbdd761d9a1eb7772fc32394bc3955599d566d73f6b81a0ae71ddf9dfb669d74e7442038f0ed3e6ff684dcb998efb8b76d2012f0f559b27022f77aeef356a221cea29e084b3a24522ccd0ac0f98df89c73eb48cf4b29d1bc5e152988842996223a63ec15d5da65c68a6a172ef2c42e97debbf1ecedbdd46f0e36b949a56ebc7e52aff7ade63737160a8fa74ca292ec1b3072b94391d2ca79941c317bb7b8c5e351bac5e313cc01e71cf71a911235cb139da46cd89e7d1329961e29518f599ac59408757a8aa5c6f432bc1c6751af34ac7a501fc332bc28eec63b6751a7f4721ed500bf81aa377bcdbd6ebb0d1200e773aa3c9cf3cd80741167e2a13a67116a8587d06f3adbf5380b84a34cadb049646ac5d22e2b4adeb48ae6220de57273fa1a7434c3a3231da7347351b2e364c2234a66465c98191d6546a9531e2f399c97e195295157e699924ca624f3393325191e2187234eaa1233ee37dc2bc7cd7033dccc0c8783c3c1e1e07070c7c1551a9b3e7de9372555ac12e5e6387513696c06e9d223bd10188438e75ed2d801700ee50a7773c3c3e58e73a6a70984b38c2fbedceca594cb65379d7b0dbd26d4b76fe20493d41cc5dd2cec91eb00bdec4d908692cb5e5f72f7668de54c36ecd10b972e5b27f5db0e4ebe84890e3678622965820ad88ef32d7b8cb24191b8ec66962b81b8559c3b6cc95d4edcd17d311a8b2333da6e99b96a1497fe547ee27ba437a826b95602429b97a86ddb72c8c452fb137ab9df0071b76f1bdf520adf8d0c42e8a402f5bfb313024c62e472dbcdcdcdcdcd39b14a08a2a46e4428dc4a69df9e5db3e5137aeb33ae5586774e556633678cd376f44867d64b4a95bff4489bbdecd084bd6419b779453810d2b25ab9ad074ab3ca7934825bce255a6bad272e212b39c1a29776a73d454a0d84a2aa940db54a8a49e724b5e47b951413eff35691f64ba9b3a72a5a35256d4729a447283d6b294dcb3a244a63b1309752971350a09f52500aa8135ea80e4a29a5d73256892aff843e13c1a534b8e547b7dcd3e5cb40564d72113dcf220370c2893964de0138f1c40c326f39c97eadf7c5ad8e5228bcd444e8bb2720ecc428a6770e267104465aa6734d84deb32155d1aeebbaee554c6208a2f483684d70492742e156ff277c8f2a357011a106425c1102c70b0f7edc5842690a305af404c6891d1491618323845a3476822658e186120990d268f55d6012ea57812a8c424163707b92a6ae22314993c83fdd12b74f69104d9f06d12aa608cbb97481a06485358cd60ac4402c0406e16cf54b7e6d5d2f51b213695285552a348992340a6a856910134218d0eba75995a9d0a057f78f8998cc4693bd4455cdb1faeac46d14dc060a435fe197a641b74f29a534a99b26354d6a9a44936895499a6ea255dca65adca65fd031a819b7a91ab7e907f360a6daf1170eb6c1345806ab3f754a18305dd78993aa626010b69e60ee9c5e42264d86506a58d22cae7b39b7c0c00344bb09fae8eb455faf1e4ad6255ed50633298c89d4c5b1b81d831e286e3fabaffa3a5522a6aa8f0221256e3f71bbbe66909ead9e91e121263923f2125346f4ba642e3a7d38064cdc66a0a96a206617bdb443f2845e5e624e86e20d0e422f8b4094214fd2871e81c812d22722103db6e9a556b5ac3ecb7ec2b2be5e1998a429cd4e5fd3e719974f361f7aec03f1d59a9932cafcbe3e9032d78228292332100dbafdeab17f188892f5a755fd2a8af52585b0cc82b034abac42e5137ab72c8a1eb99f8050e62ffa027a8d715f976f16446586fa1c1786a849cebc5f5f949c11b9ac8adb9916332fb32f6e67639831d5b89db54113722f4ec688fef4ac46aeafdb5694a24862e23695dbd4eb0175b959b363aac8c86cb01c5bd1a5f71a465d2f7c5e8bc2245f10299556d1fb88f4e536c4a5f73cfe5eb0455eed576972badb2e1a381725b59ccce5ba34c7cb4ac5a4e3ad2d652285b511a67c3c95a42f8f9714e6e3f44c5578ff4c9f9dd323e7396de2d2ad8939847efb3bc84555ab71fc51a8304cb5514a05b1e47808fd8e973e2c91b70d67107a1e96c6a5449f33fef427c8cb55399647f1785f8577a6c4fd1851aa15ae01d10711cbd5ea43c4721c7221627921072202f9788b9950ac85d51021216989885a98accc6e47afc5a8e791cfb4a5175e6a4ba4cfa78f98015118c785210cfc5a587d1ff249857c52209f2c04b9c7b244c4251311cb8a5132136a153d0b2f39202f43212f51434e4dda92b6a42dc5f002cf919d98989898181c1c70c42a517cfec2fb5993170ee54afbf8bcf0eeebc385e3b8f0024db3789c52574d0eff4c9fcb60af02fd397dce22f4670ea13fada014aa94c25129fca1142a65402d88e56ab512cb711c2296bf10b144a180886518b220a23e9bcc84503ec42f3c84de268858f2b03d8e636b8f1910253324aaa25a8caa78000179c9b1f01594542faf2d6d59cad58f97e37dbc44e564424259f6e55220628c85d80a624c252e515203ca9028d9415b162ea27119c57235fe10cbf12a88e58150404b261e62b665b9f45e0fab730d88926da40169402854a86399ca1ce9dbf2a549dcc8cc9ccacc340c8797d0e73dacd81c1786461a5010172ed2b0d56a1c7f144ae625a771b954b40c83f5e951329f0dbbb48d28a901756b4046ad0119b50664a401519f933e2267e432fc12358eab9591908b0115fa88d6ce1e65b0b7e0a4574225d1d074ce678f38e48855a2c4d04d7c0ee54a16430ce2a42a1e62c9c3edfbfc08ed0175fbf2b0e593edf671c42a5160b80f1318441f114a9193e08a068cdcfa208af47cbee78dda1276531825b90d18b9fd235dc442e1d60b2390d2f239b7a09020ca077c6ea425a5e553e5033e6fb14a08a2bcf028ad092ef111a174eb85176ccf6f6c99dd9458d2d8d81fb8c696343bec0f3a280ce8d2f01456d0c2cacfa42dd1dc522b19564e29dc27dbcdc42f4b386f8fa5ffb622221d8405ded409f2e235f869c42441b1a36855bfc53e2772258da2eb57b6ca1266e72f577b495fa6bbdd13cbd32dfb75bb83c29ff0357db2ec35abe7b2773133ba5c7a67cc8cd8f566104f2c9f6c37bb499c3f30c7af1ff8961d4423a56fad30536742fca9b3e2a112681d6035e4b6581941fc656a99d7b19d2d02cc16bffb9848d398a8c90f56c485b95c3af485bab65c0ac6b87cb95cbaa092b2a14e8c4bef99b22ccb4024a925f30498ad291e80450e0219c8c70561c94445cdcabc8ef28f0c42284d9e4aa06f60d1a9b489f76b19e6d440241910f3331049166611962b9f1684e58f6455ccc41401666b4a7f0a77d3bb67a16522366a1bbb746a69430759585902136ad09a52d8c28a1b5eb888b95cad49b42a57ff5a06195e6f75d8a4092599e8f43e4b84f5d2da5c9352aa5ce172b99220822360d1aa356422e3831e4c3185292e177ffea4850d966e9ffb1a97d7d5ce278fbfaaa44170b34beb0c52c59269f31b0527ed61b352366499184e6ee338e678dbb66dcb4cd9b671db9d6c5cb79d13e746b7d3eb64eb998925376fb2b355a20dd9b39492ea7239b9d90f328eef4db332ba514a29a594524a29dd324a699665599d95bb76aa0dc912f6b37e1982dadf349bdd5a6b92e7a19a95b2a1b3b798b281d2be94dbe29cc0e42dc219b341d2dd5e7fc3f0fbe6afa6a49580a0ccf8de4f70fb91d6b46c8add4cc86896d511d6454030328e2ab53640628fbf9b267b260c357cb12e6e82ccf0220d2dab311f1cddfebcae953268437509a1443b15e71cebb6d56b96ed149d707c83d2accc1b54adb5d6ea856b4b174454314480029006818c32ce826a03308c224e407908234a701d1161841011620c8da145511194ca902209a450c9765bb6044521d3d21d512ddd1a9996fefc5265054a323082073840020c3008b797e8028d9f2354f0c2a2d51195a1041a4cc14204430c2184328478a1e24a9614bc206603d711aacb8d1fd50740f5e6c8162ec8c8b6177858626a90184230515747713a33d470034786954ac6d06dd4513477c6c800baf5ce1819546e8942f2be78939182b830bfeb2d84b63b2908745f5a2c48888a0329036f52c8df2801a60fb64081953496a8410f84d0e20dbc49e1c6514ecbb89e1cc7715c4f31e5076edf05b5d63a4190832aa2104619563c610d16d010428d2b50c0a203257a441078de38e3892e6c60861b520ce00446444105558af0d2258c2d5e43f8010a9ea0c6115fbc8855a0d182130c210d27e8400b077919cd6acdde53ac9496a0b99ba39476b58da8502ceaabeff76bdbcf499f037284908fd0ee81be6e770dc3ca7df445b3a8a156b57a352265845fbd755e6d66cd9aa6ddda5d4696bd72999024c25abf6665f4bb1ca5dfbd34ade2673857758f34b5375464b3d24a51fc8c99451a8db2117e2814a529337186b5e7f6602aa22205aa3a7e90cdca4760a106b5395ab50a223162d455bb26969a66cbbe9e966959adb566307a844cd3c4fea493ce1b5416d2d05b7e618f773ee40eeff32851d201eff32c51b201ef1371519201ef1379515287f789c028b980f78900515201ef1309a26402de272244c926ef1319a22402de274244c903bc4fa4889206789f88112599bc4f2446c902bc4fe4889204789f08122573789f48122597bc4f44899203789fc8122505f03ecb45491cde67bd2879c3fb2c182595bccf02a264002869c3fb2c214ad6f03e6b889234bccf22a26492f759459444f23ecb889233bccf8a511200efb38e28d97a9f8544c9fb3e2b899247de672951d2c8fbac254acaf03ee9a2640cef932f4ac2f03e09a36491f749204afabc4f0651f285f74921728892e4fb24112559ef93459424f23e6944499ef7cefbe411255d78b7f03e9944c9d5fba4122587bc4f2e5152082573c42943f01bad2be049c0b574deef795132c8fb3d304a0279bf0788922cbcdf1344c915deef11a2a4eafd9e214a8eeff71051f2c7fb3d459454e1fd1e234afa78bf274649fbbe8d159b217ae9b91ea7e229a5b453e04fcfc2106899d8fc2294179e2083a396cda965927a8e086526f1a095bac71bb03bb19da31da49da41da59d251e17cf8b07c603c413c423c433c443c453c463c413e339e241e249e251e25922e222f222022302442488881091212244448a881811891139228244248988129125968bf562c15840ac2096106b8845c42a6219b162ac2316122b89a5c45a225de48b849140641029440e914464116944c6c82312894c2295c8a59e570fac07a827a847a867a887a8a7a8c7a8275625e73af6c5b572c41e1755f571aed7df06ac0dd10fd6a64803d6c6c8076b13cb80b539c280b541ba80b549eac1da2839b1364ba54db92c60532f1e6c0a56019b02a2804d054dc0a6842460534311b0292208d854d1036cca68079b8a39c0a68e1a6053480cb0a9241d6c4a690136b5a4007be34a80bd7935b1373004d81ba003d89b2003d81b2126f666a800f6868800f6a628077b63b4c4dec406606f8e04606f9070b0374937d81b2525f666290016c76583c579d560716034581ca02416270889c5119ac1e20c01c0e210b52c4ed1b53846472c4ecc88c53992c1e220c560719260b038452c8e8fe5f182e5d16379909607cbf2206279f0581e3b96071155f55db03c8aa8aadf82e5614455fd95e511a3aafe10cbe388aafa422c8f20960710cb83059be35ac1e6a86c0e8caafaa3cdf9617382a8aaaf82cdf1617386a6e47c88205c2d7b1d3be78e7712ac5a73b6f09d0711261150e491b4138bcd161a87159b3ee0fb3daee98373fb46b484a5ce0bb43f5e33488f3640d646b43630aab209cae17adde6918492c71176bc942f4cb97dce962fc06e6b79a25ca15ce1e7f66b8688c25295a3da7955435aea5ace735236c524f59ce7a472725236e7399f200d649091654f80c14ba88b30f5f2b4745a3229f51c51954949b44f99623ba6582a464638554394dc41a1b81d364ad5d00e1b335b42da1f8bf6fd03eb517cc9d194689fe21f578f3da5c7061580f39c77a00278dc464c31b19942139688b56c2ea59563534c72a04c34a268e55c4acb9be122a49447d20c4246486f398b887a8e7adc89d9f4b886581196395c3b2e4afe392fb9540e570ed7bdb813cb1167efc47a2726ee7c99310ae7a5cfe1615da616912497a935a9aa24a2747b27766f2caa552d863dce968d0b30d889ed205152650591185680b0842ab8b4fa3b4994f4c145050ca4d872c50e9cd0eaefc4768ec280c140ca8e6e82048f6b40460e28fd8b83497983838cf0eabd18cb48c0f0479aefe926b1e4aec643b4eb2354fbe7c5d591bee1a1a9aae7b855d29d465a862e27de988ef3238df315256b666870bc136b2c942b486ade36a9c76ad4e3bc5f7a1ce94bfacae8abc91d481446a59e32d1ac206aa5eab8d50c27b810157119556a56d947b7be6622c8b6dc4a297dd117bd95b6926d30bdb4e395fe181196ade4453b8bc27aa42fad959ae4567d2f75c85154ca768b660b7d5172b50ab7ced263159b88be72bc6c221bcbe313cc81c79b5bde677958ef293b5b5f9594cd3dfe78589b56ea3bac0e4d5bcd5c070f553bc3564c55fd1628306a0dead00c52c90b507185172c9cb8c1088a68d5d750bfeaa9c7b13796652c17f11623e6c231e097f4e5d6d7224228fd2bd9fb8f12829a93805b3562aa859f7a36aae7a1aabd76a9ae1b6af214e472b984d872eb998da25b3f2b1bc58c6add34fad3ac6e8cdb6d1bc78561bd768f873a6eeb590dddbadab8edd218caa57931ff4c26935239c66204986c1cdd324b7a985b9f19018cc988308bf4fd6c3847d363ec3747d341cbcdd174cfd6399ade4b26d3cb3635534f08a87e26cb5f0571e0fb8961b74d563659df64795cc83ebc2fdb8838d3d2f461139b1e36eb27539925cd19a413cb275b786a6a7f60ce474cad1e05ed753e11080ceccbabd6cec8185c96443ba56c89d6ba44c9e6b83044a1b2244c92664ec8deb8552b8176825bb515dcaa3971ebe7ac722ba723fa106fa4eb30b556fa732b9df289e557a3892e315d1a7bac1cb3a597cb7adccbac8ffbf8045751669186cd21f59d77ca74c6930a1e53c9a8649ee9cbac567b9a2e6549354bca924ca24e57247b123ba9eae4c19023cbb21c346f1f76fab0d961b03c6506e127b14ba88a5fc436e991bbd3c783f1929a642f41993e309c5fc324939cbf64b28a9c67510b975597bd2822eb1255a900c67c45ddd9f4f7b8ca129a5e5e67ecb15aef9d1744455c84a9f0905a04837de145accf935824ef9652b52eb51746c41d70bccca1a1a1c1798e1c38383aa724735cc83d3db716f1d26a1c8baa495c026bf62553cac0b46b823e5e46cee757b34e343e5ed2ab23e487ea0ca6eb29613adbaf76b5202c394cbbc47ec970232294189ee21b39b7685ed6a56cc966607aac176233251d9b7d01c3e395c77d8865739624d346d84658d2a525ba347d3ad00e798c5dfdb32d1c8935721fdbf3172cc943b4c4b52e7db9270af928c4c76b76afb37c3b4e26acf9a7e9b77d3d4b2f0591047905337dbad7a556d5735c18d6fa5a44c923afaf46cdf22839c36b4fcf6a7573c6f1e6fce6e4bc0cef4beee67c527206919b2ad3730010722d714ed315e73479a61f3185b92613ca8432994c47cd499a5e8677079b4024a667a69bc024f47a15cc815d542544c8c74389c1c8a31809f2236de4743262c48811235162789456b762c84186c77030d3877c3d2da2a491d753a366f5b05ef6adf9e121f535445e9ee7256ac7059837e4f5744ab356af2d4c1f9d8bdbeff6e3652bf1907a9b1bb1355015bfc79216ca0cc28fc19e2cbfde3f5c240a935631eb878808e311613b30362edf857a1ddb820d3fcbd529cd12227aefc4767962a5e9560a225eb440c4f22c88256a05b10c5b2536510f0cbb9dd8534691c3fc68a5ec1f88c4c792ab599d0f91ba7a9ca2524148976898aeec81f98b52b338ccd2ecc41e18764d3fd22b20a092cd044c105dd3bded53c1eadc87cdde43491d5ac5af610e06d583a2d1b1df0e5456e35140988a0c404c224f8ff50421bf04b2d4994ea74e86eedeabf7fa0c4cb6d475412c5d4f861e3d7e84f6b0e1455baeac2dc7fadb1f98e3617fe07b634b9a942d399b259afa1a5b5226dc7a545dfad54197eaa54962c2ad9f09652caac7eb8cdd263ed96eb89b80308697345dd79dd8721cbf2ef72f88a5fb8965f71ef8754d0f62696bd8ed4e56037c8bc2a466955a123cf09f8fe960966412b919640339068f5f468c183162c4880c4664e0570c4f364de98546024617ddda3d83c03e7f91dca4307bedb169f896a88c4483ba2a318b70161e52ab0e0d3755cc379c25b37d1946c906e29810fd185629a51d7df71eebd86335d9668261d513c771bc29439ac94a01c143ea7bac291cf540a0c21307a1bcf0882ccb32304910d7e32617039a9464cadd27156bc47f6c96f75ae6dcb28180b2a07058936d1a71bba67b1cb7713dd62ee3328ebd9e26d3ec91d2a09d5bd22c167f142ae41aa8559dd840d3875fcf794a749d8c4c4dcd988290a6c9ced64083ba69963dbd3bf87a9dd99a4fb0c966ea616711ce3287d467282e6532994c99dd8eb2dd5357c7ee3081f9cd393e495d9bed59c67d99d5ee35e9318ab0bbcd996b6ca99344c7a27a449d7b29e5b278be1ef88120921e0741ef4b9a559b984c5f73f1fc90671146e221f55c438f75498f751addb0a4c76a7a8ded711d6bbf59beddc424273055f57507242ef28487d4d72a7e133d0a22e9c419f0062957bce8ed404920a8aaf20f0fe11f99c3a8701c67534aba9a7703e85ec3a58e3a679d706716534a6a4427dcf9ddcbee9ce824256e9bc8404c056519d689369eedcbd6f36cf7b01d245adb429e8e8fc11ab1684b162f49cd48cc04133a352fbddb79a9e39c897848e53eaf492c4d672098c93213a820a622321338b6856c47d163f528c84db0890aff21fed86c0735132f99d733d10c4aac11cbae9f0d3483644192410a4b66246f96e18c99517459b833664612d7d3be1e96c7459b736b7f207e98d6f32559388e157c14d9ae8305166c3755a621a5ea9aeec39abe82355d654d6f919b414c62d9c38a819a653ab79541dc1a9b7b1c8e6caab2e3f8bcece50b676f1042d3391049f61bbecf64e9d5a6f76f822653786f6eb22925a8eca8cf9b030e00f58c99b974d2c3ea96ddbddf9cb39c98529289a897a8b3e8c413734024a8f36dd0245670ce20d96d2c0826d19edd64e9f5b61e56d749ca864f28e3537c28525a3f1ee5c7b9f5c376ef165b25dd3760e4f28f1f3f7e44191fa5d5adf1600e2a7c3c1b713d67993ede2bce4b2ef5b26f1844677df81c4bc3c386a39d1e50b336d14977ae7e7210256f9ab1f02baae2882cf28dc8b01eeb538c054c82ba771b5b83baf78a7aad793d03799e656f9a02f4d3963d77da506fe95d1e71824926067aae93ef31f76a287bee3c17f6b8dd747aed4ba66ae2c0b9f3333eeebccc7c789a67f17bdbef386cc95dcff31eda932d7f5c4ffc816f8c4863513df45c2abe860c881eb3d99fd39ac452e7ced93bdcb912224658b22b0b09dea2795632161a3b9b48c95d8ecb9e95402e77af5686d22c76b52a3bc7856179d3e73b65a22fd9c56239da1a747ce0ac78c0492ea1aaec939bf334ab2fc2f9920625def498f11429b3a5619ececa73be4757b3a6347883943be9d94bf5a7c9946a51c978fbadb384923bb26c87a883e372cc6cc2c0c343b973afd59661a53cb5d6c432884bebbfacd6ee8686e3388ee332283dcecf581b45f74b329a1ee7bfb059f445325556d9b337c9ae43ac075f786e76eff4f698ed6fdbb26769ba3c73d9e63255652f790669910a310ab303d159352bcb7e43b3fad997641955c22b7db84e7808ed5bb706454a4bbbe7696f9b89fd5a338daf6513e501b9d9119055102d256b6a0577b73855384138efd139e79c993735ee180a26a197e79c2514ba036f3217e1348305a81a0669f8a5f554670df3d21aced92c5adf9beb361012d09d5aee8cb5d1e57a415e2127f5c8a9b0023eba652d398945f6d223f984d0b58577ea9d7aa7db3d26847cba7d9e76de52600a14958cf7fd6fdfb679db46edd863edb1b357d3b75f67e34a150ef45e8a3b7fda40ef89294e54325eee9c38721cd771dd970c9d6de3ca026f52e00b1bf7eb32052e4c086b8fdc953277d6dc3b46985dc812c2f2574bc59cdf3d15e3fd94e334147bd77e9db1331007fe97f2de9f36f03f31e5894ac6ebdd1347af037c3d11488f2d9aec122bce4b46985d47ab5e7853a764d75774092567bd1622cd24f0aa2a42fa1525e79c7345275ddd1b84dee45457051496fcc3494c9fc97cab6d20d796b579d6ecf566975f94a49452dadc10eae332cee5154f9059a40938c91eaa629feeb9fcc9db575f84fc6dfb2d236c6275e8b19fcd5aafb16e9072797636555f72cc71b5be56e69eb0e4ae766eed0d228181e76aa7da3dea65b369c699c6af97ff6b1496f5cbd5bc5ab9ceae9ad8650a56aecf9d5da4a0743dfe78787aecff305fa6b89e5954325e3e8bab1ed9e3415872a9f9724ccd8f577b4d4d51c9783571d5637fbcf596dc7d527fa8f7729517b764087ea3656211488fdca455fd9edc3cfa69046199da3e3fde793eba3dda717e461e87b1a58c950bfa63172c45b3fcb815102e349ec068285d66c097183698cb19453db40951a033f8053950ca6239f872f9256043075174f1e6d308c3697cb97cee8934bc5ce697384f809fb0ef09d100070d446990a50209d1004b65a308ef05191b534026b4ec8d18136cda1338ce8dec8b1850e892c235d858a3cb11bc35b67c62d800e4b4b8fcd81a587c6b0871376b7409ca96e0876b007589e2562882c233be54993380c4106286c351049a9a63e6f2d71081eb8b1d5cbdd38c2d5decd0c284262b6a4c556c6a8a8d2df574a7195b8eb8d9e2bad9c1971d2011ed20c6e582c1f9b42de017dc1078846ae4107d07423b086226760014da8a86c8ede005d3d101e74307496018cf0d15be2e8daf8d99367e7c5d1afc8f8c2fa6032eb833867480850d2c3a68c175e9b833a6831777e47d612e062bb0010612158dd3ac80850fc823c388a32d574b1140be232c47568e9848c1ed1b11ce581a5d382842500a42740c61c8eacbc1d26521be31c313e245f84de13a7add194b83e896e19d47ae3b636a28dd12a54610d4e872f95f04626820c5d038ba338686d12db3d79dcf72670c0d2b77a211050bae388128c219fb8117208ce007602eff33e2cd2aa1d6a5080d5809030ce13f1d201f1aae5bfea68bd277c6d02d7b38073477c6c4309a398c1105255a00852b5b7869e96022ac8192a92550aed07afa1639aaa224b7b88aae2da945c514ea54c52dfc14f55015936e4191d21aa98abfa4c9911ab8590a9dc586d8c842c199410bfc67a1b011c048b145ebbbf7f197d2ea148d898981124365ec89eba049c69db11860b9554e628f17a38344386f5f24ee09624ca375fa67a1788f79eda1dbffa18290e638ce48f3fb448612fe93c249b683261761d94141321d14ead0220ced6cc91c0ca22478997714f0df1b1453f5dfc37f8f2223a6aa98ca01bccc997c0f0f9607e0a125a825020c4c2fb74a2846d981aa7a0955f56719b05678999733260419d107a418a614b540d1888da6d26c4d90db98412c94efe0bd1b6031420b14afe88805c15398b1822fad4fbca2c30aa3366ebfdb983e93db2ae529a6687b629b449137511333b16c2cb7a90f397e5c9f9d2d2f8825d444df633e732950aed00f4a8c14d78baa38458fe333457f80f038c428e0c3cf88e16c71100321e92c119ec4548d11537404a098aa220fb598484c5131f5fd00e063c42857be833fc0f798c77c9fad232dc508227620948497a1376ad06a1c63bc8009274cd1041743b47ce86005615021c410a020a2d552b05842164b683c81684b125afdcfcec4202c5989955a296b2b596e63992daad35deb98325b86a3e0ee20223128afca33397091dd5a75469729a59467a55d2a63e79db132a72012993748c316e408e1e9f331e7afb8d5aa3f066908dfdd649d50f1267152ee9106df163cf5819235473d8758723b4e232a1d87b8849235228ae36677844e3049f86ec63493dd0b3b4ed1cf6bfac9a61ea39dfc222cf98bcb0745203ed187272d63809fa9c464890b6acc585867a6846588ba41f1e7d156ead6ee43932c20a6644a318e42a35c25bb063822e8db70d0ee030f4b134111dc7a293e4c1903fc7480ef01745c8718848eeb780c538aae57ad9218a614dd18a61451b18a2b862945ad20748857fa572abd0e7ba55f7f19b4413b02c4617e2ab9f83ef081e0e3b022c21bb745263d2e4125219cef640cf0d3ac79ced1313fded4296718b03b3f73b872e478f51846f89ba39f634ab3aad4bc9fa33ff0d452af0bc2cd728080c419413958f8222c7762497a7adaf4fa89354336441687e808ad56d412044ab7ecde4306bb608e6da10644889137086bde7d27d6acf2b4746bac4d9656f5391ba22ec2df9aa11b4cc1851056b690f1002028788006195698800a4f8714a1ce4be74707a643a5599e9d399c03766d4e07da2a37a7b64a0e98a51e7b24f5d83dbe782d822a9a009ac2e9039fa3e3ad6931aa21158e7ba045fdb33baec3b290e3a590580e175581df61bf9f4ea7d3ccede9ce3cc7dae8b0aaebba650ed74948172147a290588f39b1a39da4f75543a14cc8331f28048b102c4288c09c83e2417b100441f0ab54248296222d94cc39907bfdd9d8f986124c589a685401ee74d93902c59d980ac682b0cce1da89d1406f95dfc615c61cfb25bd262145ad7acdd0f401bf82ebb33d42c298544851f7696c88b80b6950dc111263c56690064518254531270c29ac4752f748da12762f77625df6baa5cd0a412bfc582184e584c4aa15b7cce1ca84b8650ed78e979da5dbd73cdb5755a41aeab1b1f4d8f4deabc87d5684f352d516559639390c2592306ad95c4aeb48f708130e89a295ba94d64e6ce7a859f42052b37088ac85bf602fb80bde82b5601930166c0557c1573806fc02aec2523014fc043bc14df012ac04af8093602418057c023e828d6022b8043c021e8285901225041ff000077a3ce9001020801204bb58043c8549c02f2e827fd8040ce3143015560103310b98096e0107b10b380a9e828518066c85a9e021be82b170164cc45cbcdf734449cef27e0f12257906eff72451928bdeef51a22483f17ecfd20bae56d0f491790b89ddfef60ec60929a2aa267b24ddc371bac71f0ff07ad94763633e634fd4c65c6fa35bf336b72d263c0e4b73d0ce9cb5d81fce60587bd16ee05c647d9cbfb01a38cfc0aa70f6c2fa70ce627f9cbbb019387361c7f31616036722ab3a6b612f70cec2ae709681ede18cc5b270c6c23a395f61819cadb0e579c8063957612d70a6c2e69caf581ece56ac90730c6c05ce30b043ce2fb014380bd9d5b98a9dc0790adbc2590a2b817314d685331436026717d89df3131602e720cb7376c23ee0dc024be4dc84dde1cc84659d97b00e38b3c09267256c03ce40b6e7bc02cb80b30aec0be724ac0e672ad6e78c845dc03905b6c819055601679885e17c029b80b3096c0ce7236c93f38f95e16c8445c0b9086be44c843dc0f9658f9c4b600d702681bde7115826e729b6751ec216e02c020b80b310960067979de1526c0e0fc2227914bbe4506c9287c00ee020b034fc03560007c2d6700f581cde016bc339606ff8131b80f7b04a2e6359b8d49ee8476df85b7bd662377006c3fa38175915ce5fd81fce33b03fce5e580d9cb3d8f1dc85f5e1cc85559db7b0193813d915ce5a580c9cb3b02c9c65602f70c662819cb1b03d9cafb041ce565827e7219b73aec296672aac90f3156b81b3153be41c03cbc3190676757e81adc059c8b670ae6229709ec2ba7096c24ee01c85dd39436125707681e5393f6123700eb244ce4e58089c5b6059e726ec03ce4c58f2bc84dde1cc02db7356c23ae00c645f38afc036e0ac02eb734ec232e04cc5163923617538a7c0c27046815dc0196663389fc02ae06c022bc3f9089b80f38f357236c2363917618f9c89b00838bfec3d97c01ee04c02db3a8fc01ae03cc502e03c84657216819de12c842dc0d965915c8a25c083b0491ec5e67028968687c02e39086c0dff801dc081b036dc035600ef800dc0396071f813abe43dec0d97b1aaaba2d245a8021255650fa3db9f41222c7762a50a76755e2b00b5aa2fa428a987f87e0fa41e4794fc4b2145b747d2eda01e7b05d70a535678d95871dd0dfc876be0efef28513203efef2c511203eff3b8287981f7795e94ece17d1e18259dbccf0344c9f27d9e204a5ae07d1e214af2f03ecf10252bf03e0f112529f03e4f112527f03e8f112525f03e4f8c9211789fe7889210789f0789920f789f278906ab21a8a40cb586594c95a9111100000008008314002028140c0784a2b1502820a9b2643b14800d8ab250705499085a9263ca186208000200000000000404a34103ad9cab2ab24c6020ea6d7a2f35c769b9ec2bc8072869d2ce1431415c92a27a98ad2ec8c34a73988b66580cae8f803ce74ab577e5ae22b344b802a0759a07f4806106592a83a393ebb617650da8cfca3705aa6c3dba4d93333430d94697d6d9177c728e8e3200ae391d38323e2305396ca4e24250a6a1431b6c3cd93e800020694cbe2b7d995ce1283ef79e29aee52a7aa41f4b6d2ba7110f7d5713a741fabe6c0996340bcee56dd760d6806d7d50a1695ba39458b9eee50e04e5c0cdc10058237c51d7f4738721c650f65c202eb2a1ddaf79d3930f8e2df964d290867748664ba6e61aabe6c1f5bb5bfa14899283fc198ed29717d35c4707a27d861efdc4360c5f7599b1906254323d7892c3b3bed4a0f5a220d4ab571060d4e322c815688c1d712cfe416023d5ee8769ec0bc1393b1749b913ab1c38fd897bdd859cc167a4ae56ce703e04b660f0162d60b7d862ec72d52d0b44b348d5b7507ef9d3c5869cfc7b2d07cbf19e67dde622777a5888074a2eca9b8282209a47af7f8d892c7e2f727906c58a7d8e842662d3a310b9acc06289516759dc406692c7afbb4d29b9018f1c2624952b5fd7b13664a5f424d1e01eca98e5eb6ff4743bf3f5c1128f61a256645d9a563469207ca5566531bce65fee7ba3468f8f8bbfbb65dfbba47255cda462cb6222f731dc69f2ba430a240c9b12f0d4d6b68a2b95839da36de1940c9bef3c786e1712fedf7360f8eab243d80851cb60609d932a552815bc6763049dea0ac3997f243e006cea759075a053ced5df299e2383620b67e488dd154c35108dd95de2f81d7b738a9be72e3c667caa369c09506de88d4fdbc719bc0033c4e52058cbaee1acafd2b614236e3ebb141741c14d0152200ab0ef770e736518f4b09bc30f301d859b947fb04f028f54634c0c79541e28ded132b8c6f18ab0ea5649f26ca7f1c886e48b8a8a051f3fb22398ace18e989e26e8eda86013d8331640c8acbfb2804c9ea7a438b8b55a4fbbbffae24a6632f56072a8976b4b6302b69b69f101f1ca7dcb7fc0acb04647b5d50c648398fc14e1e1c2887de739ec33ebe3c6a269e143b3a689615d669e35916641f33fdc9680c0613bc6991eb80cf841aa141a437388b0d51c6689204667c20df7720cb0657e4ca9e65015b4af5bc1e0150d5df7a444cc7a2b55b9bb378d345609fdb8ed831ecd83b9031c1c53f7a65dfe6a50ef392eea0a955fe74d6bfa94ddbc49a191301b13c02c7d7360620210c4ab034ccc395d788cc60b35a150beb8511056c91d8bb31166c177d3feb926bef567ce114a61dcbb02e392bdf0020c8f0cf3523c768c6722d965aebb8a6a6efad42a9820c43e19608a97e46ff38aa4a4c64447c4ea3e668d5e7d84194277173ed386650e670d81a8ca3df352bc469414a4a919362bc37d602904ba1580e5618ca159fc7ae53e951588daa10a1473836136feeed46c67eb50a1e09a25a1a6e0fb3be4b876790b8a838e6bd5eb48b422149f4621d539f3cdb57019ff65c5ef50bf23d37e17ccf9347bdf4b826b7e0dbebe09c3505a3bdbde70dba9a588dc7089e556614d81a3021bf159527036f1395ddcc539641b4541183304d52ede412e29d3029b8f17365e9bd401fa03f4042f994eb11089ef1d1d6f25e92b0389ddc59c9f91f0c97ace373cf572f2bf2d62473c3955fc80cf27b8a2fc0b4d79904321f50a364e609b0d1e33dc2e4fb3fa1416fc4c66c3b262c3c0697c80c5ab66b45849276add0ac6b3d4242fe3437a014d3048c25ca8ad61f8c8ae7bb2369f9f0a22f988749b4deb688596532a489253e16be23d88d77b915c5bc31c1f490ee98897a4704abbb78905a2e83926bf9a2053eee97de9dc4897b5b8b6001e44262830d8c9838bb008d55db85d0e3e35ad163c16a7d9f67da5cc7e4fc8793a6de0a8b6e8cf6325090a64b09074eec143e9d58212747c21030234e963ae1a62081c8d7bb239ad32fde8fbd5536f94ba9ebe74fa1cc958de137701387ad2a423afa47be0d30f5e7d66a856cfe8daee3de11c4a132179b777a53b7634bc2061a0ba92fd3d352b52487aea663473a491527fb15af13b47dc936ad552119fff1e30b9dc158870d1651292ece9849f3579da6b89f8f3b86e4d5fa1c51056ab1314310ec47ce04978da46a2e2e55fa767b3fd499b19afad6ae74d8dd0c0161f7972e4379c13a0d715206f407e5f94d995df0999c564510bad4f228a7f62f2892636085e9b96c9d277839a2eafcd2b8edafd13de22bff2696b2b210c74b0c43f4ab42e4bf68ed51a99782b688f1e08f8d698c85f2a9abd2a6700cb956953ff2316708cd730a80b4372d213bdbb45456ec92d8cf3c1639bf64dcc49a76512b3089f10baa456b22039676383a91386bddea8221d12d90bb8c64a050dacf7e29bd18731b5b45ce4c2a2d876b2a9bc4c218617061e956cbda015e8acc4d7626d021af2f7c3110d5c43f9863f390821e7a5a068ea5a7a757ab7de0e8ab9f4378b2c095f1eda3c1bafd3a0f46fa4961401bd50bf891395801d6e43c310cde64183a2388db67beafcbfc00fc4279fb3af8db56c12a3443ceb393f65621dae00b41f32c87fcfbc7c725479a56d3b8b37d231a9bbe85590be12951c1aaf55a9a00e2b345f7f94292dba16ee547602aef63a0e1fe800b40912a45ddc8891b751f637a4d4bb57d0354677127e32e8825b271dde90083c98eaa435667218f003ba889dccb5485cf08d6a7390c9a5ef0af5d27e5e73a0771f55201611ee3132649d8aa081a4fc0cc9a2351d641001e779159d129495806b133beddeb75b9b72f44788191c743449c5b2ee98d6bad088427940409f1e04a5fcad8697272fcd5bf4c0f5e09e51de80e159a953905dae7d4966faabc1e85f043bd55029166c20de0497247105ceb9f70864a6f0a425a4bdd32494b2083450f7be969ea6007bd4bfe543d0b7d7a2b03ab7b1def861c6c6ce1bfffc51d13f2402b230233b5635897c6989d1af86e09461fe7189607da75904ed5657b71afaee777a7f516727a029ca4249239cea847c883ea0191b2ee69141036f8d60ea16a88b69825b7fe48b64e82f63c623bfa7c92146093050b4e3fcd0b0fc74f2d5ab17849de54717921435482b38e72f5deb07a9d8fb03e3ad312082a2946db08cea02ce2b587274e91874fc22b0274b3fc62c20949e4417ea0dfffb3f1189763f732b3a5ddce8bb043ee76437dd088c5b63e43b84907599b4d764ee7a66ad4b4681eddd62f370a7c8cf08d30b338331c70bc4452dba8849072345ce466f61fb751e5a17518fe8a5ac4152be18e8136542954e5f3517ebba8a106b38924270f07dca77d77ef344b47145a7363b2456cf14e0e88e4aca036005d0dbc9284fc3ffa2cd5605597950a2710a602dc57428fda53feeebdf0bf75742f7228fdb269efcf8ee666b7bea6561571a2461f46fdfe5b421008d52031c7f87e4ded41a067a7c79b4a1d1d11128097658b7dcbd6a7964d02d01e409c4ae43281aac09809a44b0228dcfa2309e843e8d46d554478e9d901ffd134cbe47023a1b186f47f886ff975c8cd32a60b4062c84466a3af89faff4dc1ad1d03a77a089c1a3fb49e767700d028c4af719651cd83e4376baf50c0301cecadbd5aea660bdad6cee8c417d75b9c9f20c0d73ab6b0b2d58ababa426539885c0752dc7b08a01c8582ad80652e29a65004e7cdeac2c0d7fb3a3bce93f8edf12662ddd031dcf68ad4127245675a73b61b3d23117f4f37e3aa1f853f6f29d1f5f897b3408fa0e8f4c2832e64b81b95e8086850d2b8b2feb37133c49afa9fc6ca2a25133505bc01401639e7dfb134975e59df1acadc6142233387a6c6db3f3728a001e878b37299f64f07a55455e86a3eb77b772353bbf3877fe5d5a86c373aa0a3ec432d40819e7f4a6edb973c40cd6cdf42981540dafdc70fe80c0f64af76d2207d08a7b544962996d77fa5b65a0d6746bd93acfd1c8395376a73ea94fa64beb377e32c8ea3a23668b304f6de2067680323c2a0400310f29015c3dbef93d7e41dba67c5ad67eb254bebbbdd426965d47cb521921d65f819d69e304c47e556363c3263a774007d8ef31c1e508c73d970221c7393047b2374e130fb8b59e148dd171eb07972cdf34c1eb8df548cce9a28c51003ebd265aa6e8bf72f601987b9bb9c5ba7121917a4f269310f4c4002c85025066c2ea1ba58e35d203b03493c88bf8234b591d50187e4db4524c314c33ab689ab4060cc169d8891bc419f75f00a8b319e9998a3b812d24f353570a8c52c6b39ce2654b8612884b34b6fb4c5318bba707e2dd7a1ecf60893ba3028cf70b78a4ae07c7847e6c25a72f1808418ee569b5727fc62b03f595529a592556153a33809e2ceb8872c145ab15ea1df1b05c0cf1fd2cf1d55670bae450d1e8576c89a93bcba238a598923f876ca1ff781199c9b1804b165a64bf2221e1085cdcc48282f1f48fb9a87f58cdd0b92c5b1465b8163df3f9aad8ac5945c037968653ed0667913c9bfada04b5946c75b4fb1e52a99a90c044781c0b6fe900e46657e4be16f3e8e315d5912f4d2785481e082ee6c68563e787218aa291358183aa4d372a63af7f2a99b3c4e2c0dd4ec35528b951968347a30c58b60168008cad523ea8ed2fd324df4f1b0a9d2eda0b43ea4f8f2aa89c6ca90236f5990240c0e0434fb61550a7e2ce4dfc9c41b631d1819511b9e9fa380b285c2919da9cc9d4f1beddecbe3ca30ebec672b367a1a68b1dfa75a67d2af3a96246ca794651003a104c392f0f34ee12d69ce54731bd8c446c030965d2cfa3baaee371e7d6250233023aeffa702aad704c02dc93a94addf52cc517e3048dbd0b4fd91186782726b1505ceb436a227b1abf062844f7908723cdbe38a340036c7014fe04f8551fd864f7dbc85f9d5057059d181ea4052d69008e2ed829bd9b4aacb1bd96fa8d5a5e6fff2bfd257016a4f5e00879c9e692f8353a3524e220550e31bee1326c6e0addb17525b527fef8915ae83a75dc70da00a09e1422e93367a325f509cd4d81d555f8cf402c7cb35f39a1e2f8ac2000389227fb676945e020acfa90e5ee6aefd6aaafde309f630ab925768f1280bae8d0fcc06eaa4e995c3871095d43ce321fc3be25c24408937a2a28741a275a41070a34e8f76fccb74fd5464dd473ea393d3f68540ddc095bf438e7bebb4a91cc6de086cbfb043a263f505040248c624cea1dcaba5e809868da138b57b8485a82a48b24aa09798b50448a4aa9adde069d0721148c01dd469aa318fa221c316fa898669a56e3543d482da607b7a1b16718e737a031b4688beb1a26bb7156593cdd5d271632031404b29b8c6a45ebc5b032aee22a1e95f21eaf380159b206b42b12084091f7660951fb201810e06cf2164d044f002c20fc9a8e75d72c47743de4681af52582c1830698d10af56e0118110a54b8cb535c0ed0b545e419b4d00568412020a1aa770c302b5bc0e514f1d2baa7f9b3656beac7b20b3dfdc1ff4fa18cd47616262e6f063151a157550c7aa4efd2b3c1c63ec7aaeaf2e2098db416f0393c9668872dc73500a992b91801467799ba95f2bff78e47c011d88659b17d61da611c7082a4d08378c08b1ededcfc870b540d32ae30e0bd9289dd65020000c4e82afb54b1b4707749d9856b4638e17bf04d6c7e00bac080ea9d27ed9a35d8cc50e4e8169420acff7ddab3b7303c67342c745f66a8eecf6873aa3efc6fe92079864dd5ade19750223414308db7736fac61b9d6f50e574a08309c450db436b22d9c00e2b61878f77f655cb219c2a7fa7995af41c4fe44d7f12a8f7637780dc5e66d50febbd218bc18082982667dae442910ad020934a3ecbd6c8a61ac8cf2be07f2e1ca3ae0617a4f4c980c9caa13084c87bc3fe8120ffe938a0b0eecb66b9f65ad2e4d5684bc8016ce7ec4609fb37410f014ffd50eb59752fc9d0e0585cff396437d9641833730bb57070a8cb9f13fd471fb327360acce5a580843915a5f401ca44dbb9e9a499dc29a9f45329ffaf391a82c9569c00311411e85e94bc9c9109b3890dd0e0a0d36111f640dd6dd5deefc77df184541aa60b3784551b3c03d0b8d7c42e9988186763c467b910198f7fdcfc64dd373557ebca2d3258bb44a0bb2082f16967dd9af5435c2b2715035cc0cae863d58318a45766c7f34fb9066e4a1d3d62872c9431b033dd6ed262b4111d9afac7dce646cb7c8fab48ec0e3bf8de01deb55d19e13234b2e9bac38de84de2ecb957e6be386440f27654cd8d433f263304088e4c0c6d50bb85b6903ec528064db8a3cb637d40404aba81e32916a83429ac0f39c376330f1e6a48fdb98ecc23e570aed64317cbdb6282dcf2588cee2ce1db1623af306201ee98dbb1fed2019f73797bedd550200f0a819986376ace3a71f1a197237f1a34baef1a99bd8f53122bf01e475d44e0b469d2b7504372aa357fd7ac3335508214cc2e49f7aa9da0c606e54f42b711fadcff7b981303f9620b1e040fdac1b891af09dbfa38138a1dd9336c322525b7aa7735a0b6212dc5a5e112447402c43989bdea3ddda0e56e6751974413d3293fe1353cc73adb87d19621ad237cdd0b32d4c127c7b7a0561587b078fd96201c0adde6b26d6c4bb1240de95e113f3aafc9f58a639d7b8321f977be2f64ba4ca6c0e501e831b75c28380275239e843d5668cb980d1fbf9223886f1ec6dc3d14e8cffcc1f57a9051e7c66e59b495efa4887bc82cf79e9120ee18ca9ea6a54451fef68fd79c682a0babf029ccb40860a601c62251062bfb2fbc9b7d971821a34f0b9a213d9ee50f151c11e5f9af6337f482a4067f85fbf15ece96ab200b8ae88d4a786f89b867ce4be1d86604bce29baebde31482ee51a322ca3604f847a70a5c89c0ade2f8a649ead34d751c278384ababeac1980acffa32d688c2f499d40ffd8c52c09d096a2835cb12d61274ff331ef7ec82959c82819beed01dfb8bbae539ffe19de38e32da8e181591d46c061abe902a2f16e047801a03f093abfe8140672b10e33ca3dde731bb17e6008bbdcf79543ac5c7c49acdd176713a70690b70b3fa5963c165979cb2350216b4b2a00b31741efe3cd1cfb85f7c9280ceeb0142ebb8cd03f76574b36b4d6f2c86029c8dd12789c1cf6d32d6427f6928f58cfee5aaf3af55116feac5e6385a53c465f9147187fb8cb8a9b7a2121ba6e3b720d4906583fc50c3e33045234041a1e7dd283e458453733435d8eadd6184d231ca9999e5864ea8485aa1c0a351058ec24472bf99abd597b8741bf01b2de72c74f10315a1cc76ad2ac343303779945f198ed0c66ae7819c2bb4c955a462b96ddc3caa2b8ca76963257a00ce14fa64a26a355c9ee8164517c643b13992b4286f02053a58fd1ca63f7d0b128ceb19d6dcc151a43f88ca912c66875b17bb05814afd8ce286685a9506ee4077554bb7d15d37462db4bcca1470ce920a6c5c3e8dd6157a86171c4b02d16e6d015867409d30261f47eb02b64b0382ad8160473e803433a816911307a07d81562581c2d6c0b8539f484211dc2b43818bd1bec0a152c8e08b605b7813958f8b13cfa272b4b48efa1bbcb1087197701b23a548a7bcc563c69eb0956dc05a53e5be68fd317b2b8155f1da334920b47d73a9b65fb257a17aef6f7b7447b36723af833ca10e2371ef4ae1345fa4d9121565a2526baefd101183b78a5d1ecc3870972b7c1eed4c5bfd63d9ede14b9c5132622aca740f8da8b60be58d70b6045b6184bf154dae6c4ca767f45d387f359c71f4ecc48c629d44840ae9bf110c33b0d0d9fd8fa25034530c784311f917d9207fa03833e7ea34bfd8d142e35e52fad4d97a9c1d068295b568c64f6201de63419e6c64f6f97c3d2da099a70907a15cd50590d7ab25308576f4d56ab16ca1f1294fe3bab44bb3d1d3e5d9c8f5f7387075053cb542519fa5d71b3ee9d42a103dc807f6f0ef79c39746bcc03dfe632ff6d534047a2fc51df0ce396227dda0ac51fe6e5befde2c847c4f06f53167a8b1ff5da1400de20e77e7df3d05764e1c1fa531d434e6fb1bf82fb9141754d671701882dc30f8baf2b5434a27ddd3e587ca980a211e1fbf661fd75051585085fdb03eb2f2aac28a27ddf5e587d51812210edcbf6c3fa75851589285fb6078baf2ba068449d7d3bf63af830c06f1f072d54195b37e28b844fc7cbe4ada92107b174a304ee3ba08bf4a8b0bcc78d3fa693ceac7ed2f179d4b669697cc33dfe4f97e6596f154c32e88bd2572a28beea0c3ae81952b1e8ba057f0cd9470dff19a24fcb21bb40d3b3f7fe35cdfe874944fc5758cdec57af0519e7249e258c0e9d96c872f2e2cf978ae275fd0b399778b4a1883907e8c7de9665cba5ce020f29ee1cc1ec4aa5d35b4c5c7bc4d2a117f925dc2cac5d9649f5aa94361e073e9d05520e3dd010f7af308964fc50c9013f6d00a798104a3d791187a929833d9d83cded6e33e73089ff7b3cf7e8acaed1c046ef786e1dd910c888d93b942ffdee307f68e380042bba79d5008078e22e3ff6c052d74bbc929f9e71fa5250f404fcbe726ad51fbdcc2ecbb197824c866a7da9a0656cdf75b6965642995d575eb76212ff4eff71fbd5390447ef541af50c15d28e69501a620f403c31adf3099ad6d790fdb9fd711793baf6c7e0ffac6ce3c6e8b52327f5e77667d993196c914df5eafae234bd1afab0c0ccbf46c6fab8e7a46b609c47d92af10eb04988de901734b186177f9c0b598288612625e0d740bba8c32f9b1271e56d3c00402cbfab368682e5ce33a23bb1b1223eb03a53e7f0f7b893848b877fc7de4f1c2b59a789e3e3e71d42825d1519dadc35846e62af310233546870a0c695963ae7c28312526dbb9994a51126ccf7d24f06689b39f540f24028f390102b8fae12470210f2d1b9659eb18043bd49ad8d9bdee05513a208c1066dd7cb2b53b3af515568025dc5537f3d470c2101c2a64e773fac3bc17ec11f3df2e649f078c4063480e5e223970aeccf231a923a40e692c90f778b52316643d8fda2b502f86a6b9408b526d6a6a1327434e80e016ba99fa4d94f0565b8650f9f9ac75ec0a30f1eedd2bfaac3188066e54384b88eb0675939bb9da31beb502f852017a2c8e111dad0429bb252aca025f91a943111be97a2d45b66c3a5c61e2840a48dcd0be04041fc7b0f2f8aae0f93af9c2d70867c660d03bfbd64b7a4db54de1b1a755acca6c7141f6f1a62cd2a5509b642c79f764c6c1e3e2a203ae042c1dc3dc1e2765d5dcbc82f318d57800e0aba9c3c1ba60814b7cdc5fb271ced25bd6f6a71a13cada7cf8fb60096399e9150d61acae5e27d46784066d802982dbe372190706693a4af01c15210f253ffbeccc2c1a8e8228863c599cc486dd30576f83780f1c5d346f48518e9f4f9dcf2268399c8febf9f993c810e15aa9bdf0974df6e3b8264d036a93ee1a0cd541d678e617bbb9f5a839a86f2bd2411b571346b8512187a388c8b69d2a1791d3224c5031a6da12cfec7e620348930b0193d5f1874616ab99583b43ed99b48aeeb61ff4ca48d7322d8d82a1f106186b7301073eeb15f58f9b58fd0fbea06c4fe9b8f08613c0c334e3e869ff9e14f08dacda82455232b11f8b6a876500fe4f7f4ee76cf4c99d5d52474e4957c0f2a267ead9fb4ad2667f1cc7533a8b9c53acc212b7ea6ccc1819c95b120f836d7ef92e19b3f2659157929d9ce399ca00139e42335f855724b38f4054d2e36ae9055e4084bb548c4e959cbc5901f7535546fea88c61863c688be424f5e9e307e243c3a62a42a4b215952419c83f09a26cdcf80a88af1a11c31a7ad1a9e00704b314d2379c0dffb630d0fc54eadbeeb2835910cc7e473d9a3e8e99ceb572f46e02719cc6b363c8c1a6dfad397b574e4f00beab831d706341fc6c68185a01812249139adf1aa9515eda5a49a143f928970b7d7264327b2e8b2d4332369248080b3f922c145bff03971afdab66c82ab807664e8e4aaab9c9df97a7d9b8661a9b26d27186179743d074cdaf69d76f422845a744e9d7b15fd945a20a1c2cd01e5d0e88542bcace9802473d0421517bc6633e9f9d30ee8b18fbb88eff878f7dd669cf8d6793088f8102a05407115f8fc8261d1b10bfc778206059f29b3fa2605c1924ca4e6022a882e48a8cfcb5c4223838a1315359c8324ce92865c1c14e1e22193d3879d82bc47e44a0ca4f7855f31d83965a2d716fd05484178f48114c36149d62eaf296193bf8ef05ac5608df560f2c5f4af31881311b380e1582435a6140b083fd4d030b0651c93fe7d8fc659f33a54e14b68ce8703700538bfff6347096aab9456f903964d020eeea1ec6f9690f3092e0a192367cc9be1806432eea7641f415d6dfafceaeb06d15033688e20baa30c93af04b5a4956d8dc163a788130d94415eae6db083e4b0af50f06f02402655340e3a000127654f5f6fc55e6123da137f8b203114e11ccc928cd42d6a5403a60f3b20e29f381f298bfacd01c00fe67922dc896776b82b8c676200558d37ade26c50bfcfee23a80b8625c311dc00b0465c9e5863effa4f601f81b65bc5f666647a27612fcdb5eb9de4a9d101bf9314485b2c6def34efb5c52c57572ae3b586ee694c5b0207444ca70274fccb2ead251b1712ce63c72b977889dc9be222b8f10041ad0302790f75cb24856bc7d6d158167db142f8577ddea3ce677d06d8d1d109927a51ce741176bf6d14dc4d7017a7a66e0a8e5e6e9c5316c5d710522a44395e489570545b2c2e1edc21aaa755944868ee15061e363e71837c72149af44e3691b66c83312a247d0ace90a1b53812887550e37930692725814b0acd6cd6b4c6088f1fe0f281b9c443bcd14c769b23a03295e24d1fb7944c29dbe866a4c512e475a01c862220a5647c5e82e0e3787258d8620d5f61f0f34c48ca854865aef7378accb5b43a516455f0d52fcae8e1aebe56130442072ce63a04800498b1e6aa747a60964f8c7a39216709b6d86bfc759d42eca469f67a081cd2b7562c2cd17d423d8e1c93188a30b659e556dabffb93748de98f70a2dbb98e8141fc0fa238147ef0346c7d605288e126b215dd6804465fe2034648a097e017da85aaf88238c419cc2339c091c0e44a84e66eb63eac9b41054b0124adcd00fe74dc22dbca2d1ab32fb0d8d561a10288b93e2a58e5e7ee34ef15a99b83975a109c99da6075aed66cb84bc013348aca7e3a20b9c93682cf7a11f0046166b04032437f9433376ef415e5be98dce2a4fd0429ee371f9d5cccea3a631d9ae48403bb025c1ac2c32c844b5487992f2a7dd39d770a55d2ad5ee33b487be36cd9e32e858298e64c9ae2ee2e66326ab06e1faa55997970a7c1a6e2060fd3a0522bcddfa1bc3298e49a679ee75fbd8a6f0d8da9719fac76328f7834238384e9ad7019091c99bf777107ab796c7229328d06795e90b9cd53a123b003b95d24929edd93515751cddd12fdc7c6a30389bb86c90ee66b49115f8a7ed2478f55a988df864f1d04e991e85350426224ed945213b561b47bfdbdf7997e5e08dc01148d9fda81883f6d9b96a32cd8df3c014c206267005dd4f889613239963db2124b8620c2e6297c8fc8e5e1fef2048da52c70a8ad4b27d959734d21a7f3efb831932868fc28093ed67fcc0ce1c9a9797303f596794e3988c2a37c8f5049960fdc5cd98733f1ccc81c0a4af6c0e5f228993ed2e035be382a8e7e8e5ebc3b53809dfb22d702a68dbe490ec407201be949839e85fa0043601d9cd5336e44fef241747eae2fae301aaed33c17bdd233a5d9ab665ec3cd8640193f68e185d3ae922d268079051914458bfe2fe86e59a5a08053bf9182101cd5a4de37065cbb9ae5e58cc7721ff3b74d25016ec711d676f04513d2022a09f8383d62b130baf91ee0f99145546e40e9cf3d86fdec2ef98d7c3b7e4f20785a40e5f3970b220dce08d13066ce0d380b84e4ca841cf01176d86a9cae8b9a5f2f0748953685eb9e297707c6882cc282dce3a6789a247700e24009c0e4351743dd2a9849780b834c00683dcbcfb2bedd5c087c1b869009341d78120f5633a2a2097c34041fb78102862a18e5cd6f9068cfd1507f4a8983401322f1436249ffea01a6ccd542ef2e0357c1d9a935282a0d980851b64aaa8f649609dc5f01d193e29c0b29924118cf07423a7a1bdc181f595fd0dd5a6310aaf7a1af4fb70c5057529408a5a6457259a60a09592aa959d731fc1ca9662afc975584e01bc2b3f3b829834d00811678ac2c4c0ef0eb4078a443c09fae4bb7044c5405de41ee1c062ec1271e26673f1c6458ebf714c187c08d43f543fcde3299be0401c500caa1c71415e2c936745816264cedbedafe5b0a32290af7ace5d8a2f8bcda6b40c13629900d183cf75231b5a9281f7de9ad3d607457b9f817cb9d4900a66ff105a8705eb56a44394b1d1f2fccc45aa1ea429e58bb5d5d588ab561a05c5430f721582ef98428509f7b542cfa3bba6a7386daa99fa5118d5331d69a44ab46910d18036bf7e46c8865059e44adddb53a5ebac2292585a448c508ab28c3ef710c0bff592306a9519457bac8395cbc4e283fb49f3bc203854eb70f430b513d4adcf328679444be0f052723eae4b21d62227ff2b2b70637c3a1631bb5efe225389450e83615e80b30768fb2f7af69c9df8e4ff82619df4e0551874f1d831fff75d65b34849a45a8066f2c70e65e5fd686d0d1e0fb24f7e1f46e52afd6cf4fe5388796916d8596908bff708eea8d5b5cc38ad7b8b938849fa8cdf80c399b4e2e8a92fb9d37127d7c894ba7c1b8acfadbd3eebb3359ee770cad81860f8c80fe12dce2ffdcf6a74e19fa8814f6445b7d484cbf9fd6c99206cd73ab7847b32bb445e868fce6690d82d6faa67bb4248096095c606be2e97834bf81dded680c679087a09f2440bdd1b6871038c5d11cb1f576c8cca4cd8f1056d2c6a75d53663e831ad3f0fd56e19785a02c4b6c9c5a2c7e47f63f5dd8b9e27a2efd1577911e1eb593be7cd00cdf6f66b86c62f3b0af73e1626873f7a196555f8ffe7b579e28e102ab7a2b7a01f4ccc8fa17c2ae2c2032e9977707a82c3fa770202fa51cbb1cdd6a61bb460234eccc6564c97f8b9c99a297a0cb11c2e0cf992581cbc3ca367de1d989bd9b0581c24dccd8273c4ab4d17b98279158315c5b98c4dc46505c1b7636272e5b511cec700804cab5856970dd082d88505a96040b3b9e2b5604af08a24f396b346a4373b79534386adb6849918c849c93759c2f0baedc536c424bbb73fb0213b7aabdf0ef5daee664fb128f464cb1a3070407529c9ada5db600602da1f3e4463024e5d9f4dd8b230d17836f396f9d284e7fd7b62d6c4f15d120d0c432136975bfbb3d725ff73332b6c025232f91138263128c449b80bb93688b03000adc4cb7c49ef9c83887f935e7aad69a865be661bc8014c677668de22ddc11e118ea208087288506ea4cdb79ac81adad0dc5e90a9712702ee21b644921b993482290a18394d4a68b121c80d67c8265aaa207c405a84321903ce04c0185a461818cdf0d545c342e262f000e310db372cefc91ca81c544a6dfe97e6e330115404cc15c8c5a79d20fcb92082f54b41248b03dace430adaa5db4a63afd137e96fa36a708d3a25c4278108feb12149aae4e1d6d3b83c9bc8520a674e28e9466245e96a8e978c20e6b70ea131a2d9bc72cd0624167f6e327c07088e6f970600353942d04e5e900e68188e22c87826ca90a004cdd11cfe77aaade78f0437a2581e5ce06ada8f1f856cc641260da932297a897d227a45e2df197cbf36736069a123daf0ada390147ec3e05d0450e18f60a25135ecc0e0762229ada44783011f631c70a314954d649dfb43078935990353f46a7c4b1a292ca66091e472559d40900b400fcbba936103d45ed127e5a4b0e4a86e439ce946a322fd60039f53f112a2aa237d0dbce6f520303cdc2deece9af680cef6ae833d51e746431d4112a5862c70d2ecc6538585b4fdd5710482cf064eba2d851fb33524799c630ad65bc2a58fe34501a1cc0b1f3ce4acc1d2350b83cdd37fed7388e9856bc51eff38b184a63a7a86912f03c1f469ca6b3686d7c859a4711b26c53732178d4bd33c1b0af00b6cae44c512a379de78f9bedf5ccdf6f7de13bd4cd410a223b17fc60c2b493584bb60dc5256ec0db29f35a67cedf7a8b5dbdbc20ea8e1feb00343445cceeff1e3de74511d297e254c721d6db15ea9b559f073703716bedfac4c0ff0bd4b489503ead95f5fcb38f32bf3123c2eb8c1ca66c3a1d0273fce540c5aa55ccd56d3924b7507b6272c53c738a7cb8d07b2e5b416f438cf33dc52d28a28b7f4b4491597ef08f0a6452f633562ac3f2566ce1b3cb30cc7c30b49b51cb311874e3ec4d014810900e59f2505adf1a74845b12448d55ce244ad90dde23af8010de4d380f631c5c0a12ee6bdc040e541ebd3a7302e328443206a68e8ff890e9748d765d918150dc9b80720a3d5d5181c6c9813a32d729a94fe23da705476721c82bf6137d411239a1e45bac56b2913729fd11d889425f0e8fc0349e316d9af8e27c8063e56bd9355cab1a967e7d35ed164d20815e160f4e06737a9426c9c65180036179cb3bbf9dcbc0a5bd1551bf0e70489c17f75b836a5ce8185810432fc3d20018588e9c4152fd92fb52badd36731dc5e4421409a868fd1ba78b4652fa698d0178eb9620d808a1166bd163861a7bc21b3518ced71090ac78a66fe83a3fb1ea028b8873c8ac88324b0c0e7d014bbf1ffa76a07973f2b436d32e5c02fa68ca41bc5737205039a08a9b82a185534db2a7e0713e0ac391bc60fccd8037b0455e42b09f1c0cc24b81cd2851ebe1ffa2e9585580018536973bd0904939b84d8be4633ec55ea91d6c300f8e88d5c43a9b3406616ee5142a7ad6eeb6327d0bd0e990924691154cf4f41115e2b290285d1c2c87ea03067bcf85da40c43b361614e0bf658a77a2d6d6f76b3c35ab403de32625f7158a56fd2bd999e5a6d348afe0e708c2dff4853160989cbc2e2e6e71a7146627489c0bbd8ba5a49a04714d475c57dab4b75639fef47d3fb3793b31731b556d55631825a9676354d7229bf8b0956d4302be892981a3c49ea9cd2358c336ec1914cebe9d8aaf7b0a313278a0c119af29fb8c6b1b13e48c9247cf9f8e33a72af8937e4002dc1e0fc8bda1686c9ef0df4c98d48561a16fc594c0fe96a1632a83e3990353565cb493fe244b97733383578ec29c6140a5a29d90ea298d76465a35d665a0edf86575e1d4fbc7cd81b3eb8a3276de2c74cab79e77caa2a67ac96a1c657299c0ad474ed8bd97e2166fabea63da8d7216e0418facedc31b00d4e1c12f03f19fbb64a5a47d68e7c9a36793033e2d5658567621923cdeda8e82a96d338d80df12a21c044037835df3e89829eaa62b1e299963b7a8b32d5756c0fe81822248a98ee2b6ff00ee37c2049182923bc11ee8099c2f4084c369944f02761276017c4c8bfcbdc00e41cf29bb2d4314701778f11dc501a4174849008642ec828021f21064e20a060201542aa4d199b018cffb1162d0fd9d7df57664ac4ce993dc4a5a632f2c382b54d742d551fc523bdc4942eac3ee11d5cbeec4e62bc9ea19fa8b3deaffc6f45a0524b5804c0cef3572e6cdb3b6b272876f908254a91d807dfd6de402fe3652bdf05f167a56d239eddec4103e96cdb3f0ff58f410d98bd54994761b00a65366027dcbfa82354ca68d7b3155d84f03850b518d228281d809b3d0fdc888a9e01e542351812c87a1ddb3d3c30ceb4aea3fc68f16ae177f96e2355dd6a90e63bbf3c7cc4c71f928e79cbaece482c7b1a3dba088c6447136e6cd0094a486d0c7995f97798713731ff8e533a95c59f8dbf30e9511143acc24c321f102db62972812ebd0e3d4e169803d58ec928356949371264ba5cf930a1c0654fd434cdc3b08ccd32401dad42e8be3f2d25e29afe6db0a7b4758d0f8db04cc2d9d2902b53493d3f4420a9968020799d9c4f365ce068674be976a40cb5495d3491bff6b5d63cae048612730b647b1cda157b5b918bb386f7eee8e0147c9212994d3ff5fe0bbb27fc47f60d2dfb1806c5f7d848dd2de04f3aa258dad904adf14e7c5243f95d99e0e71fec037d3c3ce93e42e019df0d11fec36099024bb5e6e99a58bba78a2cb3875e67f9dfd5a584642427fb7f8bad3c6e04c60812d3c33370cda202d1f8387492c0364d9711dd7f9b48e35c11cecd566ab075e16977c61a59932f5dde659f0e936174f8f168b11a4c49c05266db760077742c48d2090053e3f62f66dbde4f4630306e2f3f7aaf1ff80e488c0cd59f4b765618f6f716386befa2fed59e544b051ff41ad051ce735ddc388d976d63c75262857c309c1ae7de5b38990acbac671797f9acf9dc5c0402ed152d0868ce6258e47ecdcf48613201a43239dbd7577a5a1c922e70733f19a0774ed660c2f240b308d49d5bf3130224b045f0b9b15b76f50de02b7f293710149413ef06842cba063e11b819fd98b8a2633b68a98929bc4b14042bbd7297d5b5b4f0dd91599fb7191ae34368d48dcdee8c5a0fd070e5b2fe62e503d6af982fccab204dd55303399ba18279033dd3b42ae94da9c652eb1ea2c02a08f5795ecd664720863673b9b2d826b3999b1a62bfeb7fb8dd887fecb80947b81eaf3dee7cc8fae18e52e435e7a4414ab37ea6d2224dfebc9e021f3474c1260ab5e5684882fb4579702ec3b6c21722093fc9d5fd25d5ab9b19f3afdca76bff22bdc5e10dba1d5baf0f5ffb3e5f6f933b79e6d7247a48d424f475c4741cbb4a2ffe6dc63d2ff621c4745bd7bedf582916b1926c1ad718d7abddfa6f430745c2e14b30c84e544624639fd895c089357c1207259bb29216767fd1c8159ba800e7804271e7ddd73d1820f9d2006743cd5d7004d9e134f02dd795aaaba8c644652adf8034e992e2492f21674c0bcbf42808ec39316f15d8192c329009aa5cb0fa714d7facb269ba14b48d6097ac090ba5a42b4edc8e98a8946f52d3efc383ed6f3f1f99444e17f3f0e9fc14f10b7c3e159612eef4e26e1c1ae43f604a3d8a56db7ee6d825df827736234b8f58bc1efda0c223fad4f2f4b6e7e17454f5ec29ea5c2f82360ae9a90b8a84ca52d2784f901402e39efdb16592cc5d3bc1210a67a766b9e90a35dd9ce4fdd9672c37311cb11ad93720bee52f8ed2ee0e75a5a4cb79415949db800af8cf12eacd93745e488d97ab7e73632f4ac496b6333037f2af5dcf4230048e9335352b3899af4e043c3cf7a6ce6fd42487c4b28542e52e3745cd889b4ee469e8fff742e4a95d095d32e1a2c3dec0842a2170ebecd3ee1857e939dfbf060aee844996614bbbe797e69724380fef4a88d7db33bce6313687b0a4afebdd99632cb272fbb8fa2f7dc4789dddc931feec52d3905acc327ee1ebd923ec42c9b993570a296d745fc57a2847e798122bf7571fa8f93e55feaaa2c2feaa03e1c0eb0f4638346cc4ba6d54586bcc1507432b1ae5b6ef2af465ae67a818a579b0696bf5587b68425e3fe2e2aa79571e13230f7aae22e5f9788cdec566238b8a1d34bd0eb944d19a5c27798db4323a205b95f7c5d4b30a88a80dae9c41faa73dc8ed00cab213a19714b357e46a5e1a8a68212c571c1f06c7b67abb408b1a27a218b222fa0394aec1dfea9a46ac9c1da620d9279e987a8034f016597feb33a488ea3740bf742a360362cf48e3a4a7099abff2f823fd5f47ac2ffa2beb4652a74d4474765fd54c250687ad8af27fb25c5802aa1a4a476b5dec1672f1fec2e848ce6fa4168a8ad6c7eb5dda0c660fb89a2aea3fe4eb2f96ef733b4462a4702725bea99aead2c12b5506abd2087ada8b8011d95338ef70e442aa591a2df0cdd8c9791ed967d9e11ced114a09881015c296a3687f105158268a4efbece2606531d94a8dbb570c5916fb843bc900760b9ac89358a5f880719b6c9ca0e173848e0160b478b3416e32101861b496347db1a0a83efe4cb82b18d43de044a2b754e855c08aa32ad4172d4a2fbb61eaf1139ffcf22927375929ff872501c29fdeba94ab19df9f6c724152d9ad827d5c5b7c31bc8cc8ffb637a31829931870bccf96b693a4f77a782355429ed794553ab6593fe7c90d6c3d374ad9529796d90688391002fbc2ebd0e3c71ddd9b46aa60a41031e62a0e0b0472841e720f2470913dafb47b2d3ea801eb9ce37b424916e76b66d310b9e3ebed5b3cd6829a8d8f2ba6b01130bb9380b0ad6cc24c69764f7a0236a5a29061363f7a0f80f6e735ab6e2cb808554575ec75a399c5a5af304ac9dcbd766d102aec67c0c91aa71886a6fec28fea584a85eaccfa74c5163bae12317e5c3917dab300388d317a62f19344a68271cff1eb9dea473522b242f57ad9801dac894487130a4e42e8d7ac71daee543b32128c2a3ab15d8a910d2206f212d243e046087fdecf4fad8464241209ade57324da84cd4736b4404f5f633e6d6f64f17ff08d571c41fdd2c5d507af7d14b4cfce35671f06a946e79391c8c657c323a4ba87f3526d86045c9104973d1f68bdad04c55d72eb145b5d6a2ca6331776231730edf789aba01dce00e1c7d9a0efe8d70df73d3ed1722fa084167fec9f2519ed984f9824f218282f4ab8f3a56bc644b838c4f8daad5b1dc9e9bddd2df38f0cf9ae323128b37726c9d756ecac7fb2202a9fa005ed3585214ce1e0f81c34a3c5d798e128cdcf18b5a855890003983b1a28b202cf1ea6085ef644f32014763ba785504e3934b206d89874f0241d2c7816609733f6a7d1fa3a3e31e603efc0e0d4d6042015b5b9b187c9c4c9f0088145f44391b4ebfb8938069ef7a941888a0eca8b7e88384fcce02285034c60482f19f1cb83cb0329d0d7878f46fa4e2e503bb8c8a068e827c30eb075519bb351c7efd82aced6445b7c2721e10129f6c5c9cfd08b49b3c079c3b3850d4f857acec3b2a36529e290fa430f83a81b81faf8098c7ad1994d9ad4148684eaad2e7f4c5ba4a797161aa00d8c6ec636602a523d22575bd889e14bbaa7ee054c1d24e5d120fd74c654dca2af2f0a7a0b7cff930cbebedd7ce15b73b2b04fa22a0aca05f99939cd6ac2692988f1ee6cb55c57248f25863c03c91aafe9c901fde1ac77fa04037132f50a4e6b5576575b60c3d79c0b1525925139e10ad2e765fca00b86cf60d7d18dac9a32eee07c0120a18d7cc11fc4303a35619c445f3e071569aaf19abbe72efd06d62679d9662075100986421c400f5ab07ba19cb84d2c6fa8c4390d4eeae966f92301fdf4796f3b92a367ae4f552c39eb3253908109f1a719d521cd7d86a36d3a17bbca9783314b7e9153d17f56a963037e4bc4df8134a174ca23b656927ec35365732cd224bef20d6be81210b670f01d64e4f4be861586132ce318c827c36a8352fbc2557290269c9b59ba8c775d210517d2b01bf4e000d5e34522434359e70437b0f4cbbcf245d1fcf8cdfbc483766e2f628d36c3f1b7a4eb5f0a9cf56e819da11b6d078f5ada3e521caf4008cd2f57b3ee5ed2fc67ba0bd7f4a8367e63541ff47fb787c91b2b7c4d3a170fa5a3e06a2c09fa5f7a8afe40e0d6faaf1ddffbed5a01c8cfa7fca63e9c87fc9762d888aaf14119849f8b50a83bc4329251e0bcfae5513e959e331c7f0859f8db9d19ab77ab5876bdc3df415e0d0e8ced5662c0b934d561f0028b8171c354bf080028e1dbb520c59088f5ca6692d4a772e7b11f6f734a5dcae3b849b88c3faf14b45d4dfea00ec0076760a54f62e08cf4501f861e1aaa5a3f3f51cd1d26bc649fa367b110d962de054ad075efa4596a005c3c73c81c8600ac45e2b2db01e94eae0ae009e8d34f0492b6ef76e6c69ae4543a880896956e16f7f8486ddb0773ab9f76c4a23a23749987367373d2aad8736c8b7f16a5a987d0704fd042c4c363b2783e7294af5df9ca4de4a194538a4f8869bfad94d75ca9585364faf46a4c7d5c8d57b6d62df1bac60c68bac31dad82842475a3fda53b92394df24f320b7897575cc644cab8374150a41e33389be97eb63a8f9f068a04195e00cc0e3569e29c4cc300784456017154f0018b4708118c375119d569b97bed293941190e3a7779520791861c1e76354fe917ed3da0756701274dccca6084d7b1cb992fc3804afa691e9c7575af3989e9670221b102ee01428fb7c56c3db1e0c5789e05292a76fa31211517a7cae275391224a7c1407a16a6c3fb7dd7160145059e077172f647bf9d638af80b0105e6861b339b49d67b390bf02f62a8e227f8fc43a252cc30ac653b8f06c4c8c30f377a82624d40646a035d8e0762706a974b52502e2453348b9b1e9b14c47e806eefc92eb1f17a449ca26c47536852a0ffe7802e6f4260d448b19f2042875d7b740430c8d18e13102f5742c94af460fe3e569ebaf61a796128ad10dc8be6771413574144ff375e61e100268e5b56a0451b2c2d0c6d97567463fead046f8f33f73a7a5a6e5a6e7c417f3a95ba714bf107b44394f7f2286cf2fee2108d03569750e8908bc1c2463dc93041aff845dafa15c6704415a957c09f144f4a42b9a92132ec1bbb1bd56c9af2309ddb88392aaa58676f1e82d7b1c6edf76d34f9f3baa885212e64630e684866205c4742f32080d67404c21e8db212613d0e105958201d26eaa1f39a636406fa3d7d576e21af2d911a7eadd30782828c02f96582c17f7673d327e15540c2d12fd7f8a343d6270d69ebf6e725048f3b3922f70fe04fff7bb5fd30ee557dba173c294a8c6660846dec786d09083d43dff4b03988a90394482ec14da2d3d5fd4dcc4ca5ee5e97c079894f0794c5fb6e71d03109dddad7ea9d3b011e019aee97927bc4df490d096451423c3cf0968138946a9746eaab93fe36fc59c1d7445271c1af017ceed24b3c751cab88f0cee7d6423861a41b5f42313e10635648a05738022d34962cd094237c67da2033a33117cafa7136a7c992e897302db14acd4b40246f444e1b2605f091288581fda4ee85648c5959b59fffe4bbb4bff3862b376cafd2c2671ebd6ae607581ac800c12f5b6b19991dc8d00aee5f06fc141c37273d7cca7e0855b6086c435072b7f785bcdf20ee494e34df7a5c89e32e4fe930844cadad37c22726774ca3d12dc6afa70659425f4969ce95681c1bc633bb7136b4af7ea4702b7c80dd021b6d2450bff45c141064baabd4057464bb67004a65ff6927615eab43218b4acee8b5333a3c85c79e67a3c22c21a028ffae7a3e0e836e10425fb72aca4693dbe6e5d70e71d48a89e341a4748c64d81e3fb1d6d3c22ce1e5fec452806fa3876294d9011e2e4b3801375914e715b1015d0aed6094d6cb945a8bde1d71df0e9823ea1b78539da3f068a68044540c2168badd325cb21a7ffd67985054ed39b0f5b9ba418656dcb5123f9eff744947f274040e951838e2d0a147bb90fb7f07059949e6f1a5ad18b4fd98243ab07d3cfb3f0a4c08a43ebaf4be1b90abb464b530b1158c9884e9e1033977812fc3f0e39bd71644d1f8cf3fea1001f688f3e051dfe6988ddc8561fca07d09e84ca4b8cf863c9147041554d31682d13df034cf97246a10efbf13960cc7935a902e7c6ddb377b8ee7bd0ce74ee50f19c169facf28271c710374051d4b88d194b57280967a820c4ff651d00e775838a3020f9b45f3b54a14727eb0e74c590617665c9371a60ebcd5f3ce98f35a2c9632e2d0ea29a49f76795520f9cdf25d70764c69ac966d9c2abf85beffc6a8368069f0b10c2c8fa417eecfd06a1fd87d98f74952da8010efdc84f47dceb714410d420185903d71d4bbc8d361d540419e1968e091266b01aa104d842355068cbac81c30aced3d19b63f29367377c1d696ca8f7a41c30479f943a42a7e62284764991518ec7552c8271b3c3d042b4e7736337c864453f90e1170d29ef3e64203fa0448f68b991729d106ee50058730a32d4630a8a8798d74dc09a04275c84092de27bd1b2c64115771f198f159d4e41fdd9b9382804e5ca9b2878313325197be9cd8a84c41fc15b0e708378a2ce9081e3c0b9ce5619340c9e4051b23b862706ac845e82d9f3b3da4810a1b33288d56e2aa29cb3ce1a231240d33cd9e320e6ec04dc73d8d8f954caafd0a92b322ec212ce1b2b5fd9fb2e023f22b18375ed320ea93bacc624ea093970a15cca40e45a4b8bd35cf6abb0302fb882816f0d3ce550e52c75d4b197e6e17b47ec41a1b180d79d35dd2de02ed4a13d4cc69659adb45c4f208eb580cb00d5d85119779020700212ca921e9648ce8178e3a63eb2e678a34012358a994fc93aa2cb22de36552294ce89a88caac6215baec4fa059105c812800288f32d5441012ceda786560c3180cf32e65ec5ec2534b09b71991523670b14fb889ed489593f7bb52972a51b7fac39224011f03ee9436a944cf959c6c53b13dea8d1d1dcce834005f95bde898f5f22da7e11b0537214f4ed634f5bf31f1d3ed4164d277f8793a0e05b463edd63f582ee1f1436986719424ee35ffba6e30e161058765cc6d7fd442bc7ca6fa8a8b2fc008e473e8984c7bc2bb219aca23ced85710b038aa26f3922d7f8988b707b513d811976cc2bfa2f0ee4149f6a36a16385820b33cabb5c1133a6813f3eccd75b533c6060532cf5a09c27117107f5627e53ac55e2daad72945acd15be5804fcf24676844b08e690226eb8000ca226540c78a2c40169962d3417d81c98e0fbc8225abdf67b2ec2a255c37688fed611d7fcaae580ce0ea58c7cb228144ae510b6da068603162584edaee754f7de143f38fbe6c9ab759b320f1bb8c41a270cd0338e55fe8d0df327398004a363584206628d476d5b836a751a097120419649dffc4ab5cb506d35757d96835950ad74ce5201cfb1c6e9cf74c4a41e914d94db015394c9cb98e4dcae721a7ae8e6505612bab0317c2436315ab4bceede57d9042e8daffc82f7125660c461fb4241a36434da5de35618b0176ae0d6f8ac7ad3728157eac9eedb7128a95ca7a7652e5dfa1740c9ef180c82417db3b0f783d0996103327fd2b977318606aea870dc54695d0538e51a825a65c04b68f10ccd82356d48688053caa8e55a2c0593b650e07736e30ef8ca2e749380b22e5160d10b5abac45f99fdb30e74b0322bf63d4cc4ddcc37e2aee84dccb236a4176d4c6039dfd00c0c10b55d49d786e7eb617865d82d89e1c058f73fe488e77e633c2cdc2abd4e5e1e1e70e02cc2017883455ff999491b1abc6360aa51ff154a6b5a943294fa413da37401aa695077296115454f32b03360ee3f2ee80ee2f641e6771b748cec8b13c023597b2651f0782b6854f3cfd181167bdc34e111d1b099dc18ed8ccc2f2bccb75da9e781bc2b802f88175fe518233de0c938f126481dc33906724f7820e66bf87f1d4812cdae07ae41c7257211fe235b74c140d1813fff1121827e349e4fdaece5f5289cc80a8db2f3e49ddea4c2052f95c387737d598879219a6b85a1af17a66a8656db018c081c863cff50d996391746ee929ed5a72b145932f70b2a99fce1caa07afaf57d691fa0333da1c751dc74549613a1585981603d93658a82707667e5f0518210c89a95e47a9e9d272615f4412f7e3d9d4c68e005cfc6ff7c5ba3d51b0d5cc15e51db1bcbd3cad370690aab91deb3572554fea9e336e65a8112872babeb9a3de62df0a69287cf9ffbe063d339893cc584aa84b7c839b6ca17456e47d5538f4364f0a731f9a1efb3690699bb00a9adb25a3e5eac4de6505561c106158545608ebd88a9f9186eaa2380b2950d4dd8c03617098033ef6fc3c8410b7f64ada09cb59edb448a0930c690ac081c24fc057214834121a35b0722264f7a2a1c5f4453b46f4838a37f5442cd9876d8182d69c3db2842cb83911641539348f50d943086a1304eb4858316b67ab6310660d660f06acd071b1fd6ddde3ec8c9f1da29fd8c9107748d5c0eb2f7301b12ad70b68f452982db7112a069977942512b47400005703cb807c02921ada532bbaa254c82d5a755c89b0d50fea94428b1e751bf820640871213d8addd33428add0c08c254a33a60db57ea6113b2af936f5b881e0ef721f45528207df2e443e3638931c1939843917870bc3a786e514b571343fadfcc0686ed211a245db849c4758cbab2a11e3a060e0e6860f203ffef2836a35f897c50a13e4a074c64111810cd02e097d79ac33115a25ba63b9868434c421abeaee37da5e96feef23e9e1950f47c1a8c15e6c6417bc80651b6ea0272867817fa27434485c1c02c5b476abb61fbc5b834cfd61fe9c8c55a3f430174be51f26ce448fc5ac53e54cf919722c4b83efc07766e906a319e8b44eba5ceb4d2f451bfdd28b25076d271ce066576853c0a9c06138d1cbdf6487ad9852ecb6ef665be9684bed157c64e70233b11f8136c449faf419c2d01a4b22dd94463d7ff7f6909d7cbaffca5ef27809b2cfd1c12358c807b908387d0ab7743e5663aaa83295f34fa0bde3b114c1dbdcdce1acafd0a5afb01cb2706f0672b259ca2b5ce731e8483c13f9d511c587264ebbbe95e716b2cf570a1af43f8df86a8ee041a4c3a94074a13244ab028b414b87a8d7d682cbfedfb2b62de4f74f2b979dde5cea17724e1408dd770bbddf8ee637a0861ba280414b705d34387f81c80d347034b0263b568aea0f1fc072421c49ae2c76667daa7f6765a57ff4b8216f61fae5b30628715b75249df9384a11dfac34fafe88451192969030e22c839e27b103c96039ab371e4060f18e544969dea55c100604fbc57c7b56865e1f5c694b1579ea0709656740b66e142af80348c1a826839636509ce7acf97747e54343279a1395301be24bc98eaa01af4a5c76e03d1eb04b470b09b884405780010d5773982655732989a86f32ba130199c60038df1600544b21553d3359a1374f486a30698f7992bb459f70dca0d1052582907452ebccebc827b93f7fa6a9abed8338ab3da843bc2a4a0f5a1b906af6446f387b2d8f6b3572d3aa52ffded5a41530608a37b40a029d355ca58e727d3831e25eed86dbabf998b8088e2daee7c704d7f9241516f3c52ac0ac960cbc92b9537d9395757bb6520beb8a14b84615127bea95d1d846171c02b8537e86ac42df6eeb49d2ee56a6428f16f7435ea864d855ba9efb15f5119686222095e24928e048335da478206972e57e3cfc717bb0814a7a80211f01f830e5fae1dc40364e91c50ebc3df8eb1a0dd4bdd521986f753f7c71cc00e03cfb03a4c13a617fd2dd3e1f9ca85ca6aac844977af506aa49c5c86c13f47036b752f428f1aed0db0a175ec09acc90df7b57c974e79042f81aeb884a42554b6e205bf568319546c6241f1349adbd85172214a5a52b8ed5e4a8ec6cbaeb42f5950768809ed2070c526bd50b9cce91f524ca700c70a9893679711b55eba3f25504ae8e2df6d6102d8e8059a69dee8a50df408a958070d3c60115009576b07510cfe7eaa8c3f2db6a308301854de8753433a63c4b6804aedb119ebba9ad40017eb63c3545eaa045301b0d96bd29600024931d20ecde301265860c83bfaf6ebd8fc94f9cc6eaa9d30f8a2aa455121788e13408280d815a30721e2a941cf40fdaf68a81f3811e4afd22012307f180359f1abcd2a137f088c597d4c36458ae6d56340b6ff8f4f1ec6ccd55a64e1098284e5b3cf96e0a1a941764b44290d580dde8f46717a5e12d30408aae804d8a7dd3d21fb5d56c7d869b03a3c66a881fb5f94649415749dd2066164ddafefc0487c69041e9af42af8db0dd48aa488ed642a7d8a3a18efe9e40b6195f2625df4897016ddab8c7d1810d53ea19f3ebc3ebdd1683e40c647e2244a4bf6c754c190af5787b1bd8f10e209837d4bfa70fb493d73d50f976b6d4e994e6908303dd128f763d3cd6b2f978c4c7588369400394e62d086d506921c978d6070da0aeefab82adfc56cb42020444ef792570555800adedf8034629f6d1cc0b292bac4d395fdd86ac7d18d672def11e64f90c61414ba3ffa0dd85f0f682216f51826ccef1d7a23b33b90d70494ca9171f63a671f91d06b053847d313be3acee57256ac1989ca28a9c24876dfb5d03dd89d61f50d19e760906be138c0244404dd2d0c743943a892057da56480522626d536e8e747e17d74b74239bd2ef06d7ec9ed9cf453120cc856add7fddbf526ba5b92ebcbbb518e3810c440c3cb4808114b202e751ee69e4a9d36111c740600060e9dbbd4101730795359c06eaf4104a2f14dedc80dbbbefe5e8ffc55fb6aaa2a10905a1a4a47318230fccc5776c98dc678611a3febfa70dbfa97542c8853212248ff9cd226a8cdd2f566efc0987787ce4f6332ba3993bebc28502a1929fd63d8e3043e75ad78ed6f87a6115390b73507a3db74f6e12233f449db09d36275e9f94161bebb4714ae2326604f2d306a571eed2716596ccb3cbb22a6977583eb3f840934595ffc28b043ea617ad75e507b41d63b49dfc86c3aeafe746463bf3c9d8d0daca3e3361face57a610f8db0338c5618d6bb318c4921012090752e75eb778e78bf2978d49b23bb5c1f3acdf66d6d8f0452f9cbf3ab5db735a016a1112c7e24c08c261215dc8f982e636eeb907d87eafc02762a4375e824a1551cc6750077669a7594865e407be6532f5704dc44078b2e1166fa1d938a7ce671ac47d84d62c76b40e81f27e4098e5cdb757f6c40b88d63fab52815bc0c36dfed807ac516731df84287be6994be860fd5857340c61687b2cf699effbbc5390b549dc61b02f89d3a149abf6e41275f5446884057e42dc9906d2b720bb4e29e15616c6f96a1734650db832ba7d32e2442e31c227a2b44cbd3c5b4584ec905328ba8131b94d434bdbce317b519b40c2adf2adb8505e4ee184654988b04af4f9d1f5c497a648918d1b116415eba165e644ac32861e351f3f83cecbf11e2089602ea5081ae6d2f08c12e523752785107c86d9833cd9fb36d54eb1eac4ebbe7b168b8fce595bce67c0b5f2cc6917766bd0029e7f00c6a3c70db05c0091cc32bba1efcf3c62112905cf8aa16e5d42be08900f2b25bb436bc3e8b50173ab95d25fdfa0a5f71cd0fa8b3f1108b27114b2dd07d08a6ff871f71f2c17046323ba82a03e5fb17282c735924cc872d2fb0e601a164be3278b7afb262edff903a76018ae2845648016cafeb86db051cfa695ea5b5800dfaeb44081f38cff86a746a9b1aa80160a638e1dcedb9b2de9f226da8c24586b81a080ed9607a513b87ae79a9654aea54803058e72632180d54583a0e2aa1b0d89f9b042bf8e955d94307dad7582df39382f6842e29949085d9ddf6a4f24bffdbf9880d1635024f0d563647c20edfd58f82c92564723fbad8b4c1722598f677ce27a8b0633d1e176ca890d822574700b1797130cb0c42396f1641124d88d176c45f7f0d0aa1b0d116814fc9627aed5a9b35bb15575b10c3b3891f7d964060f8290f822b28ffb8c06bc5429e1bdb4a65be95fb12169709120049fcd533deebb12056dec2c65cfc2c80118440412cd19b34e6977401bebdfb3bc383ee68875a0125998153d903d4df5239a16a2b587bf75cf5dc6a35fd01cb804059f684290f752c2dcd23b8328098393223aa24e9b7380d24a9a3f0a879539e2b03dd3d843b5fb89b84ace681ed8232c96b116ddbbf10a212c55058fc535d95a71d9a6288cb1fa36eb08f82f2e67aecdcd43b84d2edf2b0c21cc347476c07585f54b355f0ccc369084f0a8cfe9f7c4d8132dd4f074150834cb5ac8e10d8cba4834eac89e59faf5150d41127f7f3da37dc4bb7500ab0fd38170e28eec8e04bd362e0872118571e25d15dc50fc819caae8c07d924e2d97697d31bd88d982e36405966b556f28afbf35a634e34746270b49f9b42e2e2bf0239d794da4e2acaa9b3f5b6df923588cc693ad176d697faab650df59814318c22ea355d085c7d80d2996d0c7ac8c697e6a8fc0e0a6115a58992180f92b294795ba9463e91bb8aec050f95649800290b6715f45ee7bdd5219093ef7c70d1c2d1f3172e54478d690aca5fbe38379235ee0422e2875dff6b3508ac1e2861227a6656d79377d0b2e04d78adfeacb6db92a5055de27975495ec76d18cdc74629c1eb68c0f7d73e1a9f1d65366c32323d1107a058ec54674ebac2208387d49284a8c28df0dce5d9d02a2e68bdb54beac72bbe7d734b38181af23d9baf923def6fd221ae8c7bd90cc023535fd2826281b83818ca820ed207f59efaac027f69b89a23fc9e59ed8bfbac35cce63366c627aacdcf1d585a651cbff32702a1d7baed804d469de068884071536b4c8a226a447552f90892b5f5c0b0d02bedaf6981508d10b863ed2671de523d0d43f626c5099f22f99488b243b17596306ec5e176a994dec97035550567bacec5cad2e476ceaf61c875632883f96e84d54c141f784d4ea3bd92648b8d872d8ff0df4f30642bb1263c5799b2aa2b94edb9161c22dcb23218a78d4b9403408c90e2f826344a0bf4119c035ffb9620e225ca096f4bbf69913f8a020ae9097463d3ee490197ac9235eb36b37062860f9f1c6696c4585475bafefd2a361ed608651f8cb1a518b80ddedfb9fcf38e80067077986bac05c65a22c0c91c27c6665bddf2626e0f2262e939797a6c5f0ce16b44b87c5381a29d4d8299bdfc53a80eb8899d7fe566a02e28bd04c326a058d50812dd9be4502b2c38705ac63d5186899a1aa4a7da75f59b5666e99b979cf05c393b3b34bb231b9316cc543351bb03d7ef8fa967be9bdf2ec72459a59ccaede60347def1f368649abf50e31cdec0e201e3f585783e4d92154a260506dbbd13655ba6efefb2b04388306ba2a83450cd54386f9a3ebad69e1998aef9e9288622d6bfe5359349c84b56293072cd82d0cf13349d4bd026bf7310b48dc4eace20dec3526d75929ef345d47b02d3c100e255a283fe99114ab7fd548ea5cf29944b5235b2db49e66165f7339daff8435001a37b3a74a5a32c75157b3941f422ebc7ad5571613388811cc2fb73b0c73fff362f7af6694b3c6ab493452f6a6fc41ca75403d1e9ad0c868f9ff5df4d336ad5c022e516532641349574a5d901d1c1c579209a730433e34c7f30c6b20b49430ad0576aa54dd3c8f6d2f19aebe7313ca1e2980df0400ddb036b0bf56b0929d116cb784fb1dff610363086f5b3dc93516013fc0e4fe3ee008e88e2806620045f97d635e8097c15f3dcddfb3fb7a4373380b3dd01d426cce51e97d0aee0481bea5d44a3957cd7a056004f2435ffe35477287ec72788d519087cca9b27ab7fc1b2a0a2f75ea56ee1c93ede0390a4a3d2250ce97856b71e4c636e21ab03784065fbc70d342ae25ae38676cda860acf5f6772e6900e88159f365c4c4eb9fd04820c1ebe2c40b7068b6c784b32026958b29f7717112f93be5fa7ed5791e53c1820bc4228110e8c72d4e102115c2460a993eab2eec994e0c6b986f858cef0399130a2d0c2e960d3dc855ebf4a57e4e673fc351a86e4f95e24a021a57b74e3d6836fb55dceaf40e8509a593fdf7e84e828d51769cb294ae7895e3a86e982a1a6ac5f46804a9290dffdcd9081f7c7e71e6b9a4580544e1d07964c0e29ba110c2748a0dbc861ec8531748ea0399ae9689d96bf57e853effc0d798c3e037e160ca816bfc251b2394da3300d54083ed58b57269ef6c7ae6224c26dc0bf0c5c56902d8ef8eb066ef2eb603bd219ee97f5586c872922595fe77d2dcb9510b84131a3400044057444e51898053a1bd84a854f09c42e7701174dfb5612ff1967385b55cf9e0682781d12452fe075b04cd1413dced7c52b60e597bb53c9071d149f7f198b3fac95970a106a5933f8cbd6416f6afde1aaf09fdf37d2e1de30d7332b3283d7e7d5ef2010c611c463e78738699355a98792f0a66fe3f3033aa73b9428fd4b9c9d2207acb8c4f4f5ae04bf768b00e7cf65b4f1b29b9cc53f8839747db9cfdb48fa9526d38d57f10f4589e05f832076ba5e941c03bafa431e94a33d05281cc9626444723a1933ec87a3582a984499e1c01a79745d7adcf61cea84a45eedee0cac958300f361cfc83ffb939b92e63b7020f1babacf2e1399c4436c46fd1059e59aad7b458ba4f89f6b9213fd38db6cb81ee9b2ce5bcca898ddb9a5e2f20027fcc3bdfc073af86223bf641c9afbb3f85cf9bc5d7416df2e92c9f39481b8a62b35e0253bda1186836ff162b58621d934836ad1ee9deba36857e1a83f41ef010a109ab5c9851fb316e8d15fb795600b946e9bb4fe5cb0446e9dbac277f2292e883a446fb4b393a11b019c1ae1ac9fb4789f61b18b15ed27d8873364c4ee8553286261344da980d2295b7a8bbf4db7b89238e2631c333324ac37d5b2f1d831a96a7f141ae3bbba84bb32d337b31a6f98566492cb12e84cac3810651e80725a7a5484b46fbc074255f6110ec6e349a0222556761f6291d1913a175e80b76c8be6c55918ba6ba9f67b466c6e0ce98644fc645f6da538a6230cdfc1975778c46a1488adc089821e5f9bac427225663e33fbde91032607355976876375ca4a98f56d1d9ef977619b18e45aba296b9ad9d431eea856071a3874933aabb39baa53ecb6507c4a6d87e5ae4b05ad33d983b15ad95a2d38db1f5036c2c0c1a786fe15ea6dd02bcf69caf65b9385355f72f73823e710334f47db116665fee051937ad19b836b36b843f5e44e4c4350c0eb6618627f20da3c1066be231c18618147e32ec139ed04765fe14efd99f9d519a11fb61c83a1a5d4a2a105176201eb10a1dea7826837c42df0df059a973778b694ecef96ff10e4918f0428ecd81e109f0099230ba0671b25d8caa1dffad38115790d167e64c1849bbb2c6c5556230af1acfcd5d3ede0ca90d3d0ccf33ac5d65b2d59f137962c189cc7ebe511f50c938f536273cd40b816ec22f639bf02ed9f1bf419b2250875966463998f86bf8546f2e096fe50b744da19bbcf1a5ae371c4ce889f2650a740e53bbaf1fa9296804927b93c70f1d182a8ecd4f9665287ae87b5945ffa5e62e52ad7812feaa9c29046a856203c429b1e4eb51ed53fb03d82e311209426d194593b68c3adf0bc535ad59ec3991fa33b00d6d4fd7c151e68ef40aeccb78fd9fd122c39124bde40e94b2028e16eb2ed3e44ab17670741bc5541316ed264f847cf221103607b2f1678d6d0227f747e4e8668f8ba34500cecc66337571cedb40c1324ab4951fe15b71ce7356bd3911022741e2446ec3037ab0630e97288e1561e2f71705c8fda167cccb044f4eab61afe1c6acf700d657bccc7017543837f4516343e9e71a5e862bebdadda9a2edb13ac572c3894bd3d75ee565829f9baa76aa7891aaf1a40b7163a97e07bd302209f98f95b5628a2f45113c1dfb781b4769be61dc0582c8d09e4e446dce2bfce992404923bcda111c42e64c21a20f856fe8200f93782f6aff18183dcc1a0dc1cf16b7180ce1504e8b72cb68d90f0d4ee3b6b9bb99f0cf92b7f9ecda7e0e94c6845ba7f08e5c328f91ae7614076b8bd6d9da48ef16f9a29d5c34a0b4f2a82d2d92e8907dcc0ffc97a19456e2e2413e794a53a0100bcd11cca2087c32236746fb3716f0a9c62b33796416720064833a0cb62fe92d62ca463fd5ec128234b37e9e518a6a3c9fa3b96d0d88fd3015be877ae4168871932f558c52c932a610cc03b6683c95d49605d2ebf2d75d4289d0e88955133c34b505ef7294bf293a0c171f8cd5f5930c0051bfb62284557d06f04e4364f368d189b1bf6aeb04f00ea599791389e3332daf6a701a358d2422f9ea68468068b0476085094f98464bc305f0ae6f44f3d2adf0f4b4a8912ed59932b10ccc8cff76c7d11049a6fd1ccc0e28f76f5b861fae068041dc0fc8f16a14e7f02e63b5cfe61c622ad2a7092de1fb57295056ddd9e5c0991d0629c9894bdd30c1ab1a0e12b2e661d25ed5d981498cb37eb2768394f39a492c4ba41434ae1f660e9e20005dab853310707622b0c019ffd0a4e28201b8769117f95cb0acb209514d7ff9bdc2477fcfd1b8ee140b908982c6936b0bc49835d177b24e6f80aa40946cc69b85cb61c1fab107776a2825b8d3a2b47a91ecf32d51e2f2c247cbc852b681af9cebe6e3ddbacf4ae40fd80794a810f8361399b81a1d8be9b5a615196930ebbfaf09d16b91dac2baa8ad96564fb305cc434d966545a4bc6e8782253cddccfde64bec9b503320539905d555b30e09bed0576dec47bd8a54e0a9d63acd2556adbe217eb1d7efd03a615decac709bbc4bd5e4bccb6b3ed5e8a42d9d08844c3c647f95bdd75dc7370e7c4806dc4864588a7b446b456dfac8d92511b1082553e8f2c3457030aea4424429e5686ad1606f6e119884ddd684ccd05fa913602224155d2bd2642e51caf24bfe2c2254bab7bf56c324f835adf74ba4c7715e1b3e88a949db7b28e335961a76402fcddad420538d538415f50eed8251ab0a7f0a884b535605452be2cca302c6042a24950f7433f69553d2a860757aae2eb178865dbde4ddb1dd11e757cb2c39c81ac1d76b2c94c7004768786a8c5c94ec273e4d51ffd226c659a967c2a05da5d01214079feb612673062507ee4ca0a6577ad24c98252850d9c024ec17264601305ceae759132f9c7eaca1c172806379adcee3e8a3e3313126eded019564711c9e7c84f27f853d506964992f96a3e5a817831a8dae5e15f6d52b7747ab574376f2bb2e0acd8fe01fe2e1c2ffe7c08c1d677552a1fd96b2cdb111f3d0dce3465938d25079de769c39c642c0ee805eaea7306fe96423d02fa9566e3fd4090a6e5a4a054a1bf400bf7543cc5c001f5a7e6017c64d90d112afe7b26e5ef7625cbbfa5b8269da9f6ab20044cf771709e11d5c2603329380de4d5b5009af874573cb3dec4d00bb34264881e1404240190b17c84ad5d67c6e4081426270beadfc6a80ac8e0e25d49c5c7b11c14d4f8d8aeb1c4e9ec29a1d8f68591c716af9cb803bb5bffed4615bb1b306ad3fa31db16f7da7da8444a70409203c92168270fd23c018f1a40877ac1b44744c8370a116406a02571919b8faed40100d628c19c55661d5f4869c7a24ca0d87e2a7ac55cc52c4fc7c40ec9b1ba40137b9d71589479dac73dbac12a04d29fb1e1960a37937c2871502491079ee4ee98a375b6ec9740ff6f3ee9257060ccaf5ede7bb1fbadc6a34634caf92331bc895ea24b069074aeb8b94642fb9979db6ada8f76198668d43ea5828008cc59fa8f30eb37bba08b922556ab9c2c024359c2dc6ec19678b643a5a8c4ff4700562a18b15a1553b63a40c7014ebf125341100a453ea14685cfd218df9d4791de3fb8ece79fd78a362c529104088e8a5951ae1fba028ef7295696f20aca994c5514b90f3f94c9414dc42a36d1bfd028394d2545d80fcb540d99a1fef7fa349eb516fcb2d96dc25f21e1c16bc424beb1245d33d0229db7ee814939a6a4065ded5fa483e913ecfec27c14474b88813d1cf5b06a486a49dff2f41052f1f5903b2eb406c6615985cd659d2b3b3abfbe0442f7dd3c33c0b903f3cfe6839d9a9076886ce568cf089696d301baf18c17a65509e72758047fc4eeb7cc1e4db1f10538e362b4f5a25ad9ee2e25780a438ffebcc33d54186190a0d039135013f30c9a8e6a943f4842d7f0fe101103a68fb8906f6f9ee26504849ef3a60ab7bdc7efd3f9dbf63fa0a8043dc03603165bbf3a227136a48c8f4f7a978a6c05b5e6a890ac0564d43055e22d5eb132a00986a76f83e9928578f072f6bb3aba3a7905f2eb9cd5bfc725ec114e69e475d5127d22f73b619a3880906de89cb87451dd7272025e4250582bc079b97ef02989e06d973b6ac7b8eff4f3d8f765ea5e317260e6d5b12946ee326e1dbf6b2a2d0de9a4dde0f390a35f198302d5d963a7127b83d532233ee021aded82ae303fefd871b146ad45eb63945a80805b555154e7c4088eb545ba5aca314514eb9f3cf384fa85acc8cf27dd7bf87f337e6ec2d70d3a5d976586828e40de7f614db195d4a29dbd536f38d548121715f4c1d6b75e49b45b912d96606240b0922ca63e80ddb1d599718c46fd7e6df5d9a3c7382e722bc3b046a316b6d14a314818eb2288f32dc50e1a1179791afb50f2437d6d9a4bf932e2911d6f3ddb0a7e024b000968c44c8738f8eaf37ad7f9bff93886ff317b6828e2c1c81288f8f4ec0b986c34c8b63071403c7f72a2f56aebfb27a0c4492d6107e91185c3037812e72fa776b2d296fe619b06488e3eb880d2f574a7799c1aa7186a1398ce4c518f0c2a000b37eb3122e4c6d220d61adf2badbee3669359daefc311313a9c8925339db6b62335b80fcc53c01871159099e11578562548b38e1e4cf75cbf874f64af01e9f5e60c0b4fe5602701b289a5ef8a518fb71167c28de281fce9ebe7d200b8bca7a0dbcea9138380e550a7fd40132c329351c733c3c6f21066ed43d19dc3fc2ab8ee6e986cfdc2d5c6bb234d81cde22f1ca6f674c32cab2b72a232aa05ece2419f4c6009f04c533b6d74f7a3bf60e2d4ae802b935edabeca00b5c453c0054815470ea1f69a5b7b224aa40d27ef88dc575856d175f96e5306e6fb5ccf3eb953ac1fbbe994ff4ecce3ce7448fc29980749691f8006eadbf80c115e4f3524011f3e88deb867d1b33381980f8af90f551e21b8758addd274dbb4ce4c0724dde52fbb86460f927501b3ab11db79f5e7362ebb0d896ff9a1ca423c6ede30a61408cf93021c289363220c090716780f704b03778443cb2f69d55acdf17ef998b6f849693713cd2d66f51592e230bf246d06565745c46cc58802dd3583d3128487c25b3fdbd221a25d01438fa89648955106366bec4c254e7402cd9ccb19a19b1a70a3b5813c795c1abfd5efab3f759af6d2ea2cdc3255b0019376f99c1903a0d6c94ce6f652a31c061cbe638fcca6b1aaba07d1ebef760970fbadfb6504a30b62689fc5802747e3b7c677b455eb50901599c5592d584268358cb31e019f8e28ff6f247b1fdb4a18d5112f76401b3158022cab1494cb79fc3bc89147191dec29955785a68ada6026821507328e4e38ae85a1355141cd79e118d1713fd9686ac1e67ba3173176b4c70878bdd4d62883f48e0d4c7442dca3a3f4c5f453b8f8615df3b99ebe285892a4909242f25da0b1a968ea134df08ce5255b70db6ea1aea001140ea6e28a59d53a5a6122f539744d361456417dbd74b6686dd93f1546bca8e16f691d34506b802115bc3b22c4d71b4bdaae629aad25561e7746c3cd11d8938d9ccc29accccda95120338026598919ec4487eb6d5ee3521fa419478dea4ff62025f2389faed52c0b7bb46cc09a4e6cf480b6ac1fa7a10c46b744aab6508ba7cc8c1a60701125060252e8b5ee602b6b8e156d506321442ec2ae029b57f881a6388561a9ebc064f1fcb6b0acabab4e6df5572c7243bed6727c093d36442fd69c07fb9fc8348975e8eed7a48c29e56333ec05a7f86e067df175922ec4bb365971ef362233f981721fdcb1880f3dad821671bd5aba306d8d33378a77eede2fbf6015a01172430e16e3633acc9cf0decde5e430454d6161a24235f1cf42f0857aba0aba4f363a9af85c3dcdeb067d88716562b03ec4d77bb16872307fbfa12f37585492262a0188751dc6b8930373184a03f6a5e39602f8538c7bc0464f6928a47bd69608475ed8a802c62edc70ea50f6bda90543903c5f5ca389a5fe91451a010dd45e7d11c873f86c4b94fbe5af2414c95eff960c09d1ba3ce4c1edf1ada8ccd8d500ad91c617758d3f85474b3bdeb9ac2a780d0ccacf7099e84b26618760a7f122ddf5883b0e106c9a05f136833d9fc12e6dc3201d206107b09c254fa7a4f7b8d55a48b288ff8150034a3f63e2095f9465b939d803ec66a44f938d4b56abda57f5bab7f07fd653f56c1bf0cda4cdc2cf6bdaf12e508fc33d920c317ea860857a3a08f364f94fce0e007bac44942383d97ef219c92596013e7ea857f35674db1e6b124f5f1d5cd2a399217a4b37d3e93d4e56b318e10bd14a0d9435797d25331b180be34e5003ca666d1c892d119dc8b00c2394b8470ff79b04f1c36ce2db3b975fdc880c7d9095d810e9880260e58225e443ecdef7e11d93ff1f265de55717c82920cca981ab0e55fa2434b46031d7df7f2b5db934a7ee3d847074bdd6f59b111ccb8970e0de8ddd82859a29df511d12107feee38763bcc25931f669d91e16d02eb4a7e61f4222a85a21b8cbf3764be7a55e6dff78da96fe692489a3180191c5f27f54ece1f5c3f998fef1c5ef9cdf499755ad7d972f11518b421498a892d3d0f02a4fd645764f32caa501898dd26f09c90dff2217cbca54572b41e9f422dde1ef6a2eccacdaefb7decc4e2bd3f4697de3ccde2488299b250be9662c6d7c0baf8eecdc01453ef1ce916f5218b7abbfa400ad1e38b1b34ba54d8659f100d62ea368fc5f92cf5b4128c432b50504d406d760105ff483d7e1f7a06d01430e5b552a98f464e60d4d133edfbf5a981c52bf565163ff81b10207c3ee85cc6d3afcfcfb71878cc1c4c203843744a146cd937f882ff79d6fd9ddc8464a5605b03590fa51deab21749d9decce17cc20600d85b9d02a0e5b0004389b96905b3f2597a1bba506a91936d57b474168a8080fccfd24f145fec3f1ff221ebcda7d5fe38eaea33794f95b265cf7d26d365dd95a7b2dd272c1ea7ab3149a6a0f068f771f5ad845339fdd78ace24f6da42a60afa12865883a7918f93b5b695beef9900b83d03f2a0460f50ef397b3294706190770f8cd840c61d8a89742d58d1cd1879c96821cadc6a065e7ee5cc45e32c9de62181e4737bc99dabceed8e052994c66d9b08f974e6193e9d08d8babcfa040c74a4d58a817f86ea11f3f9288fa91be3c8cfd847b42f74d2e5cb2908b072682404812cd622ec6dc8c1dc5befdd404ede25d1eff0df141870e471401b56f06964da8bcb5c25ff00a8290fd64c9f3aa4250d6dc430b47770c673f6ddfc1b4ec52847b088870222947568bbe9fdf49c99214c1847a0840897df9853593da95a6e859195e743c251b83873d5fb860a7c5a9830b54010513b8a47c83d18755fa02d13883ab14b60b5c5576c2d9dc751b3bd3f4670fd2123983c624e2b97cb850c4b56c85c68379edc2776efdb682a3e50574765b45d5165e8a7090289afb772d48771a1d35a60df739ed4e4871b99ffe95e22bc3fb271ef831a8d183fed3f9398d8ab926798c48876308d878ff704f4b2daf08392bfd99a3938723cfe78f05e8ee3ed694992c539bd24f826766eaf15ae1f72f3545e7eea45767a64a506bde436f536337754389336d91f8003fceec451870824211631577fdfab7239f5221f4f959e95ca8db3bea0031bcfb2b9b69bb0acf89adb5ae3e85efa84f5caa7e84a5af22f49850582b621e8954042524623f61af2c20662dadae729398fe710487fc586d2a2ca1e3151b1a233df3841a90f69b133f7c1529957774fdf505ca804f202582613b1cb3341dfda9c3ea3eec5b067cf1329f4834592a217a779eb28a4a9c773c71716ecd8917a76fa0d760bd4a838fa62dd0b2876a2757f447622848c18871bd94d6b0eb7d0c4fef3b7a452f8b1b46516248be8ed619e67c87f1166ffd8ca8f40c179808b2a86fd628877b4a8e4f41cd05d9e0b0d35c4659b21cc7560dc12511c507ab4589900b07d7b5e3f6e27d428773bd44a21d400b1170391b552900dc4ef76ca0b21a470eca1188438cffb6794b638675b3021099dda521538030a4a4647315f82c1c901ef6ea60a897d6ecdd144fefe0c959a8e41f578305eaf2aae00211dfc4ea1e8700484c71f6a25cce80ab3a841a9ff4c5dfc334e1cce5cf35709107252a4990c2367b654fb89612989684c5902066819f49585a9148b052116c43e9ad76e268a98c8de63ee9a714d8f3a256a4d426e620abc4e03f86f934f7d82e59a1947754685bf18be0d43ccdfc6a5f5d28d82c6f65be024a66107d6054ff1bde0246a1562ba3c94eb9987c86c894c0c02a45361216f810e1a3b7c98cb163ed352c44c439b7950f53759bd33e492e609895ae025d214d141b3a2230a78623ec1b023ad7b77bc62bb86fb9dbbe02448710dd0f746515cb6be570be8f2996f64db26d6992da5796fe8894ace0b3410b8bfe80479269f7240bb9b788d6441c08628b7c7887ba9def329eb24a090784b89cf4b0b706e126a699bbea6fca52d0522e0f7814c886882783636fc8085372407700e3658d64c0412b7697688c2a0e73c8991847d9aa08c8e68644e4880137e8027dd3b8a1e1eff41cc77c1f3a813aba7f0277b639c6f5fd278b1f58c1615792db173c17c1428e6f132d8c34c59efa520235ca3f9788254ba977a0d19582a9d6535a4a8356d711e1c3ea004f68ca72adfee186d70daa8e6ca144753b52acce2f1f270010e99539f1523fea8793c7e83c4aeb1c187ed5cacaa0ef3139d975fce5c94b85dcd16e5ac641ff0d8ff28475db2c3253b47053eaf0c1d4d03cd96ec4496301dccbf99ec338da2fc81b17f40571c304df64510ea8de0644f04291420acba3250ce93a35ffc2c21c519c3c0ee0d4b01ae80d2d5ad3e39e509710775b26c2b41e5c248381fbb05a1573a0b2be999a52a5d5ad2e6f33f0e387fdd894172ce846deec97bf6ba2ed6eb8244f6229f7b96004effdb412fad5b91d6fd87fda4cb82444fe260d58f98d3357495ed8cdd090c7ccaf04f63dc73d38e38323efc5474d2213b7a0a44497da5800946d58d6da3e2803ba048aa73e93760c262c33a8b23a4224a9ec11288efb1b01e07dc32d7a0d73365e90141b86eaeaecb9be083eb45e648e003026c5ad3d54bae96b01851aaf565a370b6a0b69e5aaf7424d7d6206d36abbb22ee40430ae08a1c9e33e0ca599709b6a3b7cc1aa4898c3bca704f012c01046a3dc3a7582018564d07f173b09be9d6c02f57728dc798bc69fb187b6732d3649d861e3542dfc7bb257b4f67d770ff80015c20969817efd16fe5a43159eb9bb12cf5126f7252b3c16bcf5ec447f58a4f1d4d76db7bef2de59632252903360a650ad909a76b326191cadceefefea04eba747447a61acb8ca1dfe1bc728677be8b9a37a190e95759339fcc183a9f4e9bfbbf9b79badf7f45995b0b95f829e5f264d68432863e9530f4c7ce557c1f61601f676aa67cd2d4a4dfb9673afdc53777378b0947d67ec41a4ba6ad7df77744c9b7a43d89ac1744793aad9abd1bd779df08a44199e68e54c34649e5060ed34a0e1d2c2d3b7874a14769a84f991e27af430de04d4d562dd368b3746f5559e34333a63a6cc6780b366bbc1fd89d1e2b47852361ea733a43c818efc75341aeeffd589885d9278dea0183f703083d1fafc74bf54b4de120d65d02a34020001e046178b083c16030d0e5c16e36035f78b06bb55a20283ed80d0d81e183dd0a0441f01fec8080401e0f72b3d96c06ee78b0dbd9015b1ee46030180c6479902b2a02753cc8b55aad1698e3416e08e486c0950739d920089a1ee48080401c0f6eb3d96c06de7890dbd901551edc6030180c2c3db8151581361edc5aad560bacf1e0363463ea10487a705b812b109c0f821b1078613018ac08bc45207ef079e899edc1df41d274ad560b7c245d87c02f226beed00a5c812f7b05de15f83de80f0281337006ce40f0b90b048276068277070461f8868000f0523018b0804117d80c0683bd3012bbd650d7ea5a5d6b28d7fff0fb6ed50175ab6ed501e5fa3c78783b66ddce6c36eb7672fd1d2d1d0bac08068315e5fa2d3ab81c5c6b886bb1ac6c266ec501712b6ec5ad38a05c5f078e7b639b713be036e3b6d98cdbc9f573a8d812ac6883711b0c5694ebafd8d06a6cadadb5b5b6d63694eb9b4858c0358fb6c9b6da80b6d5b6da561b50067f9a40101447192404560483c18a727d1c76bfe1e8ba4e1c7ffc680db55aada1cedf0dd35d5da0bbbaabbbba40b9beab509bbd656133a67e90c7f27c3c9587e30539cacbb1309e57de715927e4fa3eb4c0e39dddd9944609e0a94fa32c8c2ea14001f89132c9a3d38f9e2e216b6c91cbe8298fa479e1474f538db22c1655b1a80e8baea6f4cc9b216baccb75461e894f1a655550a214c17a26e442d6581f9f260c491a1ead4669b15850cc3562f9d17b14b2c6e2b80ff2e8fd47d2ecf8d1fb4ea33497cb795ceeb3248f5a7ef4ce0259a34181e22ec8a3f71c49a343d6288dc59ab13cc57255949e315941d668424261c4244d8e268dd254434f462b57c81acdc7070b21498383d5a81a8bfdc45aa36f9f9e29fde8bb0959a3e1cc983afa1e7de334aaba5c9de3ea9d910a1ab2a6428192c614496383a85195c58ab164acd9939ea9d185aca942424f80491a12934655954aa8c908fcd1cf1fc89aea3363aa4f10f2e82790a4c13f8ac5664f8c35e26090473f8f903515c787465197bfd4774d8122258f1e04b28642993a92a6fbd1f3d033f347bf83a4f118261a3d92465196bfd417d2228fbe88aca14233a6be14c24154a3efd128aa3ad233de8f9e88a4b93ffa53cfd81f8d01c8a3c7389e619035d4c745d2d01ffd6d94c7fca5fe68843363ea8f7ef438be21a3a06c61b62800a2850140b43018440b73118b72fd177c8881c1b72c9765bd6559962bd7b7218e42abb23e56f5566555d627d7afc1e36389599c184b2c6671727dd20eafc505c5c5e27241c9f5b18ecea4b1843496496369acfa600e6e4553693e9acaa4a93495e693eb8f706ca59886132bc5be58fdefc655714119b94aaecf0525d7f76cd81a95558546228bc512caf53b920656954f15ab8ac395a3b18a23d2188dd1188ee74e0c4cf3689b50171497cb0525d79f9b38fec8f5074b88c562d5f71bfa7bd7fda4f2a12a9f5cff86f46dca5696007801f88abc70a1961b07b13469e512e613b18f28d8f327a9542a05a44fa3b014545fc60b7231c89f389143b1b3bb63677666677767c54ea19e71354a00b864f2c249d4a7fa3dc209a55fea77eed9f798a3eecc29ceace9a6cc986ac238966b3725d7c7c9f56948df862c1ececc519eaa5fa6cc1a2f081953bff6e43abb33efce721542c2d41fbb2ee4fa9c978a82e97b41f74ae9fdfce49aaf6dd23323b643f6e5212e35eae56bfd77e9acc785357b6b68d678413366e5282fe52ff5316ef95076cf57eef96a95eb8f5ebe7379d2be432b4fda634775f245fbfa5ed0ac2db96ada8f9d472f28d7e73e1b3e772873bfe67938d7495f7e53a433e0fe996b0f20fcd1327dc2383f018f4ebcfcfdeef67479ebc89f9b437daa2f8070c2faa57e0f592934f5cbbbc8649ae73765b2977254c974fa9acad545fff6885cba87223ad9012c877e5a597b1d46b4af341cef6f0bd07e1b671af9a6f1ddd4bf2198ade860a6620f609e528c6459238013ecdf239d2eeaea93f6429a004bc0a37d656d356be66bbfcd60b4af790409e31ab720fba2740b72d4d6b305699f235301cf9ecfe5dd208f5d0a88f2e79a50c0e3e7cada6f3dbe6d3d77ebd97af24846451794a7dcdee427ffcd337500e8497b11c0f63da976addb2cbd1d5d89b9755549b86403c70d1cd6237aa5ea743baa8aa56978807f533d5bdc415bf39b8707d694a37acb3bbe1ab4bc8957c2c8882f48397b64f91d0cde9434036800541d7f99bf5ab1f26cc1f07279410022f7f77ffbfa0db9dbc6fdb6f1d0b6991d5f6fdba1bda6f5f09ce6b37c7a7a011e2f4c0b0fd1070b8f1762643c3c3f47570093180003fcb81183abcc94502dd6134b24677a6249eb67c913ad1f5f5259354212ee8090b403601af0e768e6a3f17e8b570d118405bd7a068c6d2167c03040582c8c9718effccd3c22a534efb351d2445ce3d146d55455e51eb15649f09c90c0234d8287d5c39304ab876715e41beb113b2b55e89db79d23f2ec59d111a7ed646e3ecd1d02bc3bbd4e066f06211eed93477b86f6a9b3f12e8bd4fe7e27f30db9281c5e4f8027254db55f32bde7fde8e58e0bca1a1794c79a7afb3e6278d49efbb1a6aebfcc37c45e2ec44028ede873a1d7791488e7d1d06179ef6f9ba6699ae6afd5ab699aa6bda689e3f696da986f48a5dd677b80aeeb86f82b571c28eee3973f15284b39d6a0dc35617effcb4688fdc5891a8f432178a8f15d8db0b2c2569ecf8560585355f5023cd6968f2c3f2d84d1d1c21ef9ceb7e194ed779aa78502c81ed67a92011e2b509e9676aee228811c4a1b2d7cc9a4f0d6d03536cc2044bc1fbd6dfbc9daa74835c030c01806b5f707618eaa214a9278fbc158cf804161c819f024c120d00a0cd297f986387d04500f6fee640c00607079c1074c8f0188e1f3d8d1c22280975300aa92af9168d136b8e8030c1f60f8002377a09412664e70488ee17e1be86ce9f3d5cdc9836d98b023271374f28cc0f6e33a79fe9cb36e2a7f991f8bc96479ce394516a5de5377eaaaead419758de53d55dc52fe02b3051e7d8795fd7da767da79b61f2f42275d464f969dd2299330b4f31f57c1dc8b207294bf9ac834894c8fc83496a92cd3173b716bbd1cb579ea67b2cd6379d4883422c7af1165ff6ea84fb03ef9bf248cb7b2df7caea236b469446ee3c16c81476d28fb8f5baca936a4f9f464750a52d3acd5ac464b5d4740b328c7a0b4565a297d2728a52f3cc162a294564a29a5b9d64a2ba54a9ede80a788973195e0b1a38545478e15138e1b160b1b3548181c65f99f279fdb68183a78a4d96add2ee8640f00a8bb33f0e875b36708e827bf93a10d326f01edb5cd5880ff57eb7711ff4fd4514523d56b098988af44b54cbed0efefcf91ad807598e3fc29b64f27477fe2531c266182c023f5d1a1df871d07aa333a4cbac3437b24cdf77404fe68f45e38822391aa66e6be9b6dfb29b3aa4f74be90ee90ead01cff01ea17d5cf193cf251f829cc9ff48bf4b0737f363855e5f4cc266eed9e69741869aeb6efe9047edff155cf542cb6ac653ab0e88e539f964df166ceb383af57f41579c9ced3273a9ff489cee953fa44611286eae0efc3ccfdb4c5c4872069bcf07bcffb1a8e9fe889d4a74f1457569fe8bb48978c814767f964faf4a9cf48bb88d53372d634d5338e6a1dc817fa3eb842c06d85a9b5c8f451b26778329d53bce6e9991e097e43a637c9b4e44be8744da11994847cf9b96275d6575de43b6f92346781477f98a4b94fdfbb9034db53fffed189e6fd6efa67ff6f46fa7dd4e1a291535ed1a653d2ea3c3dc3893dfae42887f50bfd7b3136997efcbb7d7fdd46875d879daa58ea13b5b84fd444f34cfd302da07f7efbd73f42439fe69b98a0a59ef1a7d4ebef4127a5cb2ccd2642fb0e002ec023ce8f2969be7d53901589224280ac693fbec82019cb1fd8a14f9afc1ad297a10df5299dd53fb003119309e3232f29d794524aa9e72a8e40d06f0827eb3784137fd0e99ad4b8a79913257df92262e551c6b2f6f635bc83c9519a7b51d65ee3b80164c9451044f9fefcb64df4b49f01d39f79bc59a35226044a29a594babb53a71b2501f1cf071698524a29a5148949a518feddd04a3dfaf252d95ffc30fcff6f697916965f597993e95554be547a12e9f1f7bde7fdb6fdbd4fe9d7b7e149e9e25ebadb15fcd50565df5a6eb159c3e9e86cb1d98136e4cbd49127c5f11db9d2f4022b7568c7b5389d562b04a50d79c2215fe8e872031ef43ba224e7e941a1a8a7675ad99f63e2dfadfc3b9e9e999d8f3743cff4a3519690a8f993e4477a834ca1a03f68c08f94496886444d18921f69109916418f5880e542a23a75e447f7223b155c8c223f7a514b1412d52c223fba14d9a9f02c86fce8af47f58b861f3d06d997f01be41f7dc98a1524aa67427eec31729be1412080e50a89f29e203f36127273d15e1ce0c786a2827217901ffb89dc51b4143198d0902897f510b959d03120c08fcd4342d1717e91a715e61819a624e7d044c2bc620e21f7cf1f48140d82e1c7f9339f984de4990490cb8f3347fc710ef1c28f120db985dc0f821bff456ed9058f1fa51354ddbcc78180dc31e486c94d02619097bb173be0a7013f4860370c58c0841d31925240aa488a45846503ab06d610d68b8657025e36af97906d350b52d343d373801e171017ca35e38ac1f5c300052080cb6462563e5630ab20568fa001040920e825e85e8c4dac988b8ef8028f1c3a6ed4168f1a443688461714c78bb1a6e291c76ed56ac2cb15e4b29287096bd4278761e7ae85d3e1018bebe1563495639c0ab8d44c1686e2e84f3eecdc1276ee5682a2007bb95a2cdb6a0bc2f6b3b1b69e961671f49ddc7925ecdca9c836176caa2d359399ae0b0c22d86b65451cbb499e9d55c2ce1de9f614a1f5c36295661789ab735537a5a2228e8d936767d24b4a8c0846842dcb6261836ccbfe9048e23899e4d9f9b329cb845d591dab9aab0c2b431623fac4511675dec2ce5dfd51822ba8b5bd7c85dd4ae5a82e89aee544143d4fac9ac8fea326c3fd63b7ea21619afaf8063490817eda2393438bdf4f5312356118f891aa2ef023d5b1c08f74ca0f1cfa894475aa023f3a140afce85126d02ddf406ee81d2d896a96047ef4a008fce82e08740749d2fdbe2351fd7ac08fcee3801fdda701bdf22d0449e7904954cf6e7eec19037ef4d402ba6938d24d24ca7b8cfcd8430af8b19f1469956f22447e6c2c8424cd0d9644b9cb861ffba7861fbb35a44bdf47686894cb12f063e7d8fcd83bb949df4884740d2289a2ab197e9c31197e9c3204fc389f2409d24c248a06d5fc3885687e9c4d0ed0dff70d33c681f44f204933fafeb992281a43f564c5f0a371f041a22a017ee26403c8fc0802599303f8fd3cec2069b8981f654c12c13c12d9a3bf88ace1c04b901fb9bf874471ad233d73bf9fc8e9c700bc7b86a1df45d2685db3c38cf97ed337a47f36a0819f0cc8cc9ab9240799cce96060c22e306116104793ff8f59335938885bac02290aa42620029935d3e70620128840b32020069935b32749906df50071bc0e1047ecdf0021b366f22011c7f62bbb11c7cb00710134cc9ab93a225e97911e05f4141147933f9159337788b85c8eba3d36b86a700d993553870671b4b304b8ccc665d965d91fc9ac993942c4b1edcb5f6658c9b04280e89f64fa0719ca6e5933e6289b4acd18ff9a209aa0030401815d9438de1971c431883fc4d13598bfcc1a20668cbff6336b4a3063fc0da053001d02e8c88863c7882d1fe288fda78738b6a6fac0acf1a1db61d6f03063fc5bfe2fe2a967882a91e8224659326b6acb5b4bc2300cc330ecf0e58d18862e2fbe8b18861f86e14b0c670e5f43b5858428509e28610a1797269c0e8bd3e174381dd60bffffff1f8661f839be9bf0ff850fff85501c67feff2533ff929f275c412daa8330a4ac17c2ce62cc27168bf9ec68696969696969f9ffff6f59f96ebea525fcfff0c571e616b1a5a565e616aaa2397408ea4355f04f71b6a09ea0a0a01e1e2c2c2c2c2c2c2c2d2d2ddfd2c2f2f2a68585e5bfe5bf451c676661616181c2239c99054aec8b3c3f35934da1a5858847d879c78a8727c7cacacacacaca0a0b0bcbb3b0ace0f86e5856565a9ee55b58c471e695959595a099573cc8857c084f869a781158589c896c2593c9563a4c2693c96432adacacfcca8ae9c677b36232b1fccab3ac8826d3cc26e7f11e4fc25bfee32c57626545ec9ce3ba76aeebbaae6be7868a8a8a8a8a8a8ac9647a9349e5e58d494565e54dbf6212c799555454546637c299556653b6e0398e5386c954747b746ecfedb93d3a384aa552a9542aa9a8a8bc8a4aa9f4dda8944aa65779934aa9f4a55269a8340473228b116da1a2f2c21176be31cb99cd663935482412894422954aa52f95482f6f4a2492ca975ea5248e3393441289f453239c9914365043d1a4859a49f3a054ea252fd5eb655f536503638c31c6241289846b7c37248c4b4ffa12491c67c618631badd345346bd546904862e71a2c1c168b357146dff77ddff7618c1fe3efe50dfe3ed2e327e1effbeffb62337f33caa442e3cc29b3688281f1846253336553363553a0e7799ee779dff7fdf779f8bbf93c0ffff7f8f3bcf73c4f080c67f6a6906b5241047b4d2bbe6f068161e7110c08180c3685dbb66ddbb6cdf3bcf7bc0dfc6ebc6dfbdefbcf13c76d9b3d7389c96402cd259309cf9b3cda4f09b41fed47fb9975f7de7befddb6edb7ed8ebe9bed5eefb7f7b67ba7dc2966ccd5d4519d213b732a1f8a28a594527aeffd7be9f7dd5c4a29a534e4a2280a94265c2961881cd5adfc65ba49da5a6badb5523ad22c6f68ad5494b5fea83ffcd5f5643780949130b33b1d9e6c54b7f26ec9859b4206c8bbbc866b354a4e2fa690c76ed5df7d37b369ae2649d42991fd7d48c1fdddca51b26b9eeff293bd63657f69a7a099088fa7cce299dc6bbe9ebd40705096ddca9faefac56be4697e0d6790a7f95ccb5109902ff5fd7545d622cfafcfc39b5d33111ea97ba92c5f50928139674085ebe5052ce3dcb84f7e2f969e27615c7642bc6cc8e8410b5c361eea80f22d440f9e35924750be9e77bfefde3902c10f7b974442c30731100af8054804ea00e527794e4e0875b9171d7d43660d1b9e8da694eb1139569fba37284a98d95cb12a691b2ab1f91b60ae87f301e5ce98e3883c670e9e3c3f874e9eaf42459e2b41798e2a3af6a7cda882a392e332d89ff355529286c4e3862f447cf1a3b25d0cde7bad05ef1ddd7052a10b4b10d9d8b0a5089b860115b270d9742bde0da712b3590eef863d8a78f2b2b1a1b4e9747836d491e49a6065d3b178d7bbb6b3716f8d16cf864a6cbaee7380b411c22ab1e9386e2561fa418e27f77349c82d8b49474e4619a3e2e8e5c54ac2b872dc95a4a9332561547986765e81ebe1baee381f0e8081c7cab1dc65b81cf090de7ea17535430c6bef7408c578c7b6a39b4484e184958d0d75706103f6b810c99736ba5692caf59514c1e98f4048aeaf44874a5f864c9ffa8edf91fb77cc4047b97f047894fb473cb2929946ee704441109dcadf907e19f630d3a03ae8302243ee1f810cca52d4514486dc2f834c2377d4a3d35ea1d3a175b4be7fa7ddf00a78fefd6e738e078f7cc51e78642969be1a70ee61caf2e71e26912767cdec203aef3ef7dda7d551a50b08b7e7421b661a99db3e9f21cbcf48b561867cc51e66c8f73bec4dae9d8e48d0f9072d5f2bded4d74423b88b39674b8d7adac4384818ed863e69efa30c3c7a79d37e94441367aa66ce0650da732003b226c98cd15ed39e084877434981382a898c497bcd469e3f4a2664ede9b649a2bb7db76db4feac2f69bc4aa1932e3d276d97f72e07e90b2c67cd9d31fea71b1c75c589f3dabaefeee530de4c233804ae3f4e1c2b8e27faf55e531e3b4f2a678f8474157fa814f7ceddddddddddddddddddddbf47d249dab9201c9851ecb3b2fd66d19163c5f438666ebcca97dec6d7203d067f740449cf548a12df9bfedd4c27b2e35b7e8748436e1147d0f2fe2fec4e7ff2782fdc9e863b34edbff0fe28fc1e0c478f43f04921fe1a35be54fa1ba1cae3c0f12ba1a925ec0105a97bb18925e4f13a4296cf11eaf89530c777e1cc628803c58e27e26dc4cf41fa02ff6c1f054379f23f364ff8632f916d947eb1efe1cd189b4c1d653ce54e1ce7d85156c4f1945b42993df1bbef8187fadd7846bcf7f75a5ab2378fb08b665376842ee4ea17fb9203f2e52569a86cfb6a095b6eeeb0652c61eb087b16f64ae8a93ed937851eba2a7495d075fa6477fab4ea93f3380eddc747a12ff11f206f05f5c9be18ba50bf34991d652e69a09ef11f7fd09b439ffabb092025cc8f3c29a5007041eda6eddd9fe11ca2de4dedaefdd3adeea0ee281d45d2d4b7dfb22873480c59339dc8182992666e2161e64bc2d8f711061e7fbcdc7fdcf4c3fdf6f345d4deab656d9fdba4e06ebee66b164d2752ce2eacb5f62baddff5bbae90e4869a2f7fb13fbf50655a5f44b36cbf21b65ff66f1545dbb6d4278ba44ff3652599fa34bb1bd645aef5bb76bfba8a5da5c9fda5a35bcee8a4cba8016994c95fec5b6b6d9074a1f90197ac3f376bbc97fd72f4dde8a354d3b41c498b7aa63fecfefe40f3f73d80f9eb80745df7b7237a98ebe27bef03b9aebafdc5ed2f6e7f71fb8bfb55a2fa0bf962ffdedb7d37a3ae7bf0470f8ec46e76b7a148943d798ee34cb9b6a364fbdb8fa3dfb0389ebedfc41eea7ee4df4d27368c7beb11e934adeb36d70bb6e47e357426c3759c8907791ea5b3fee4b323eb12caf6ddfee9ffda6bbbbbbbbbbbbbbb35d7e8133791133b6e1bea53f7dcdbaf48ffbd186bdefbdff74423a7a98594e77a91cbbca16cdfc70c8f9a4ad3d18ec8f6b59caaa95ad24823dcfbf541856649d92fa2581640962f2226b92391784a5e54e2e993f5fe7a7fbdbf61fd2fa4afd9bc692f77d1a9cba5114fbc2fbf1f66f63495cb5c2661ac96a3d33395fa46df39ae5ff3ee3b00652873dfdc77f7f7bbeffa937adf7ddb7fadecfd3d0348c6a321f833a4dfc911977335cd83f449d6b2464d59cbfce8fe2b6be4d839cb77d3621077b9819b7fdbb778573e230e8a23f8da9bbe1bffad338001be222f99fa7082bb49bfba5b4ec3d68184b1df613f2163ecd7b081fa641f0cfb27ec1dcc182824cc926649185b69ed1c9f112a4ed514674e9f386ea5a34ac95cc6b1701ce73297712bdce8b99c29eb17fb404064764cb25c05e6feb3e18aee3fd0ecdf0398fd47df7d9fbcfe8ee861a617764d1dd4d40973cffe5e7b1ddf4d8b9af6deecd68c90a819e42ff65d307829019b44a3d168341a8d46a3d168341a99be21a389e3e254713f7382a6cee9df64c29815742fc653a73b6de2dcf88cb4278ea0f87da7813e66dfa51ee60f37d3f7c21ff013bb0dddf86eb8ef963446b8ef1f7520bd0f33d7787b310647de9742d78284b16f23f431648cfd1ae124853327bc8ec5f15e50f4fab91fb7e7bc59e333d2bf893fccfc7dd7853ea880592e9b35327b91cf7aa6be7dfb74d55df568a39ae52ff67fbc56c9a26cbfe4672a9c364e0fd13892866b9cc6691cfbcd7577c4f1dd78a2278edce3af48f79c0ed876a20e9f3873260e4ecfe8e81f01a54d8ab27d97bcd8f427ea72b9ba0278d38be84e9fac94a2cb0ae0321fc3b3e0453ea33a7487aefa648938caa7748ec5c9f6afbbffe644311851b6f6ddb3ff953532fb7b7286cef4903272a676e0f4795f73d7bceedd73239d26de18686ce65e6a3ce8f130985ab0caa7a9e48b7df99a1152ae7cf03a30d9002b316a30a0b2a987656440a2a6cc41d2dc5f592191e40f34f7f700fadfefa6fb7e1d5f0d57c45e9fa85792e1e179a8693a39aa9d7eb10f0464c98927dba794524a27a595d25c05bedf52595ab65f97344a767df54c0f336fdfc42484995420fb238f95656b94aeacb14ef1ba4f1cb51fef3bf187993771bcdf7df71e176a4cb49606f4136a3a12c6fe166a474818fb5ea8bd60c6d8a7a1b6d3a7559fac8b41441ca5f1f48b7dd77d61189116cbf6351ffb3bbe1a3a93a1923436dba733da44d2787694a6a2ae1963bf5db28e1f68f6be07307b7f8304f9207d9a9b2cdb8fbd4c2e2c8364ec370d7231b56095dc236d22db1fbfdc5f258a36215fec739246e3be9bed1bfdf72399bf2373f4ed63852c6739fbd4f5efda3eb0599f91ed3ff187495dd6a452b5d50114fb67137b890b911da6ce04ea1ea18ee5fc0cf9acf3bdf79b75e3fd157f98b97bf1aba1fbed3bd1f350cb5d38a4ffe6f4c9fea7d32ff6ff4d18bf6b3fd936eb3352c55e325fcb9130b60cacfdbd7d721b74e87efbfbe3c3cc9ed84b6ec8e2584b284fb6ef84cadbef9f96e1c65b98fe4f3c752aab5e2ede0b5f0d2deae089fda44ff67d98b9131bd627db43433da3e3fe268e807a91cbfac4eaf76e09b398decaf44bbf7dd941d8657a3dcc7ef7c3c39ab9d0e4284dd52ff6edc5a6f13953b6f3fb39ed3362dfc51f66be22ee93fd7cfbfd6dd664a3260114bef7effdeb0010ed5e691f4d708af60baa04fd42bd59e4c5088f96343ea58f171e5bd6efaf7befcf70a869e76c657a3abf452fa77ef909b9364a1bc76d2c264a2a37be26ba1b1efe86e0c8c138b66d7b628a0904ddb6ca0b3a53ffe81ccbbdf5e6d09e7bfa429aeb6176751b524a6bbda1274ff56ffdeedab90380d58166221ae242ee1f6bb27c1aea6b2fff0040240d779d56eb28151bf9dde6a8928dfcca715c67a3fb86d0efa4a36ad858ad0433a6fd47909ddc3cb97b34e1aa4844a4cd3c92cd94af0b359beef3bab0da7423af0ba94d077a5de8361df63a92d785d3c6db487913418daf0829dbef6cd4b0232961b6b7f970542598352790314ea344c2f48f4d431cee7783a3409b8e4660a661d38952bef84dd2a79b5da4485ea0a34636f27bf886499fcce974a94dcd353a1bf9262fc4d2519c8dfcaee4a8cd46e2e07e2f0d4c6fc8ff701881fdbd7b6e78d2515d78c3c6da4c9932050820625878bea36ed8c8efc0919430bf750908638cb9e0444a3983e5a1e103522a954ae9744105a334706063c937f6c541a39c651eaf34a4c8dfd3ef2f0b4a4068f7170b5d8801e6a8156808ddfbf61b72bbb0b68b6ca7b020db2955c8f60ca06c5ffb865853183830182365a369d58bdc533c6106291bfa57e218b8c093dd51350b5c70c105ace49bdd1232b64571a20732067b6c52420a4288c213b12410296193a41b7773a9dc3f42c85dc30665cc6cb004278a286c64a64d3d7959d91ffb9bcc5842f6975c64ff29e46b62c1e25206918f590b72bfe9fb04e49101042b232777e329c8e4b1b40526ae97942764e06421ad5dc1851661698d01c5e54615f0f4bf22c6a08d09c253f3a1b6a0a3d74a7771a45f35777f17a9d36009da84b775010aabf244892df030818c317e803822ccb0a53182d9cf124be4e06431844f7a5d98b9a2c8a7093297145334142772a010c18503278abcb882e7a4e6076a9b01db6b7f0452328218697c22ee13be4e5243981b1a374b2738f8a1b176779f4dbff60e40b2bfe722357cb280c10e40bc271388a4165de45cf1f3844eac2705292d0544e0f02b62984256851674c0851498b0620b65b895d256ac90b0557421cad64f3827daec86c678faf122630a4b9012032d9c6183c2b1051ac8aa30a50b4300b219e54bc81172ff252aea21ba4ce83a29693429a5942de594d26a95d2a64d74f5ab13485c14f2429fe606f8ed43914403020a1d0d982f3fc97c39c524f3ad0884145f9c3f62fff911e89732e868e8a49ce9a7528a774e1b3ae9327ef69f5f0d2548a55241648f07782ce552cfc899f9fe038f4c0225b7451d46da87d93f5f8b4ee691c630c1af0375a7b3e9ec71cea6b4d6eac42766355ac5716699041dc9659f9ed3323d039a4c57fee8a7a16defbb43e74ea54832c6df0753f69fd6dbb7b6fe976eefc3cd52c2d8c612c6df8623291c79c85489a3a0db8fd06189523245162f226a4046124ee0828d3c82194ba230848429528081fc2be5cbaca5642b0a2b26f4a415d4e405238222fb4983b50488f523616acb7aab32a9ad566d492d75a7c018632c63c2fe0283bd6081312e618c710fa71272633c73e5c3cc41cd14f00084ce4ecf766d0e3ce000913e0589957a5cccf227991f40847c60870fc43e2063456853cf34c6ddb3bbbbbbbbbbbbe76c1c9c4f7d52b50abb2c81310d3d33b68ae50736b99c6480041142c4aa724a7d6a156e55ab4aa612c6fd82c2a5675abac81f9e8bbc25d39f7ac800b17e030e37f40d12462f95f709138b0bc5f4524a2fa5940e75336ff98e2f7195eb388ff738cb7f1cc8835c093deb298e33deec39ae7295abfca54595dd5b59f5498555a026f5a7679854577dd5a16b7b7a66ac5272d3eaa393694bc2dc1ba4d4e362963fc9fcb04e592c0f7bf75e25e8206182c891249ee779dee801f13ccfc39e07f33c1c72c0017603ac47e874bae1c791934c1021449024c9414a31b1b8f4bdf79e4e38f4cc68fa71e4241344081124496ec8c1c462e24c26530f991ea7d349ca2e152e1863fc18e39ed9e475f52003635cc218e32ae8c8489ace445cdb05b26d2548097101902034504a29a53f240c25e2a24976208204871c3ec0830f2548d17b8488a32875517a04c9111711974e0e3a7943a7b9ddaedd369b82d7762db5d6da27f9fedf1e82e4fa8ba94f5307fbf747fbde154bddedd30d7dea7f2dcc54c0aed9eb9e22b2eeaeb9e804f742dadee03dc49da35c88837b0e386c5274b2935eb55ab5b6fe542da1c324f74f1dab3191a467b6a2596bad633491de2e810071e9d3d4a1bea98ab74a4a828011aa26511d393d334a17e50010a8a9440e3bf07023cfc8d7183ab967464d9b7eadd22a7429a5f42461e6d5e993dc9e7e89b2c8e06c4fc4db6c2214f573d0effc1b42bb7e9f4c9246e6df421c6a0e375812048c58cd17df94502ad998eed3dbdddfa794d47d66774da7b44369d676afb46b155dae0b13b47a2ba439a76bd59b4a413acdb2fed44125bb3badfe92869a289f3af5222e7ada905b351ad6dc39ed69651d51517a969f8b94ee000717acbc158137262c908c278ff8162143620cdc59be64313049eccd1ee0dca38c2cb5f5135911b9ff62133665f99212cb1e0ec2f7b17fcf9442208380cc97970c2c1c0c30f27c79041b4481440e589046105cd0c2e5c42a0a2a308295453f992fe7dff9a62944ba9068f7852382b6f681c6b2894faca07a4f11d4bec92251848bc5e2b50516aca02d16e2f7e9095b20228f32a8280d15b84c2bc660419bc337b27c15415144461e6536247cc18331ba2005eb052d702df9c014ba88c24e4a070b424638bd9014ea419e2fe7dff92697cdd2094e1a535c8e58b2450f9808ad863001109e2042166958a1e3c415f278ca634cf1811358e0d3841ee098920417e4c0065534a9e28af9f2ce37cd287c68c2881f2734e1029c554f61bebc623bc3c70c962c410b515c2d10832eb181143f5809d10420aecba30cda19ba2eb3ee8aa63e5951c9cf176130d103a122a6b0620b2f0a75e38247548534583190c22c0a94920cee0502a85571c5a80a1fed5e22b095b26d5b1539f0aad8a2e5f75e1cf8008c1f8891451652acc819825a2184b799b185ab0b2229448002194b4c97a381c8112d8f2eaf222bac94820419b9ff9ade84234b2748300109314c44a093190d443022093e2990220768b816f21c23e552c118682c91624a010734b88288a808520c010b6ebb5b149f1537f09149b0bf8932d312218bdc0d85dc7f72998ea902755b3cb994b0274d43c8c0c91048e41e8a829422a1269491852a7825ef25e549c6593a198288bc65e96488557e5d612ba3002940c2136c908430a4a0c2868c3c97e00206668c5145103f688931d184217041074d563baca2684203293d4b1c6104ad0547c6c829821742403182ac896ca4c862064100010a5430f1910333b290f3041386f0ba02b50415568802c6853070b06de1068c2c70c044e6050c8ce8c069be69de2c8d603385b8d2031d1d22cb4772801fe0796713b866e92415cbf3e56896b0002359fa472c119746e1345110180b7e70be1e31b03033676ec89718aeb6696a65147277d1cc5307faf647fa1eb5a522641eeedaa7c93244eb93f83d7a79f60a5658e857416cc7d54c102a6ad9742885a26063849d27f408610526301b34b45002cca6ab5e873240361e02d1413016156c50609760233b86116bd28e2419674451d9a0a0e7bc4127dd096b967df0aca34d905d24cc945d64c1e6009d74195d2777cfc6ea5e79f7ddf4262069eabc17e371cab253279a369dd8711e21f7cbeedf3bef8f3b9cd4600519f66ad87ff2c23a9d489ad67e1e6109390b49a3bd13962005275c410ab9a79ddfee44b356fcae7342fa8bca18f8fbb157267f6927b0bf34c9fb09481a1fe52c8b09489ace6d051519ee7eec559ec0cce25e8ce78eec3feec89d7492bdf7c44ece565b1e5f2e218fbd925d6427b84ed75b0fa808849ce580090f6c50f07961535f898d873aa0d415e0b02ec153a45747120a451258e8d8a0e0c3810d7d25364000d1a2850d556243461201a572a8b4abd8ec7a1c2aa20100000000e315000028100e870362b17814a7a1a2db0314800d749c4c625e389509a318077290310829040c3200000004466464c6093a8da9f6ad05b91ccb04988a9131ab67c2e0b991b1977d0988a9d0e7f7d5bc433d8b339da42fc8d552e7d31281609cb0b24750079c8130ed05250b2058a388eb2cce857d4e709ace3cdca279f7eb810ee218d9a121ef0270b5d3e00f9e07a11e74a5b97e716845e431833eadd0da4a3818981611a375120ead845548cb9863d0e98e76cbd16537085a4243fa02a40c2a705469f0f92ae35c71219e0c89ca1db60c4a68f1df754be56a819d942143ac2b64709eff954c71acb142c9bab1401b31169e05914cb42b35142f8f889d6651ed7f6c47129c2363ddf9791877078c38f068f55704f8de769fa04762bc925224c6b97f93d6c30a6d9a473b31fa34b6f779aa1d1eba2939c8caa98becb88dc071db3622ed9285e8ea764e4a2aa9cb371d791be6c35d83035d14f56b1dadf2bea59906a70708074d837a8552da3490be379bb71d14b90cf9b224e4a9b45b5bacb908a811d8f869e9bd423ba33a08285d3dbf95ed2fcbd7f1d0d485b9f6eb68aa7e09f20070c3d7cfb9f16e1d98adfcafcaec0eaffc58f209d0a902df81cab0d03cc9b0fd5e9fa341fb7a3180dbc75debcc2a71c38489d25177ccd06acd7beb702099d2c863e62229ead4a964d01854c3fc73accbd1dcd23f7bc16f274be2b25ba95852e280e08a1a617100c026c6db2af3a7f674230f50b9c102a2b8464ffb7635ecd49d2c8fa315d4bed746898cec9354274555bdf35a5ffaa0be8b1c04d358c395f678c7c2bd60eb3742445d8e06c41774981f748e3fecc89d9a869dc75cf1aaeb68003fea8260b5a0a41327d9791229b831f99dbd4b5f90357cda0e36ff5126acc106b341c1d9c0cde103ff38f579121ac6dae904b73ba26c15a45e757699ed806a97226a822461fcb7f94b3c8774389d5e90120f83708c9b02cbf9d9d24d180c344f7db58cef61adae56d1a21b44d35c6f4a9e9e8983fc54027a912c17ebbec5758be0c946e6b3c7bf79331eaad4029d72d51bf04e4751af87a5b7168cecde1f78e52a0f08fc5d0ab192fcd2fc02ba182c7c8eb1156e05be1811e4fbe943fdaa1e023ff96c9fdb57633aff762a5649d9227a9471b3f1fd77972e801a0274e6963ca41ffd71958530a09ad1773587cc8b998a909c99166ab88f4ff83e9a808cd055ac0951da458bb43c71693b59548d4028d49f65f62deb0a130880377ed4afe80175e1a075a62cff804f8fe899dd758b6f3ae158fb8fc9b94be8856532477a6f453d5c8e844827d4377fd0e9a5b6d842fe33fa24a7f8e7a2e2a89f8c6f2a75c6b0de2af344d352b1bd3257434ff58bad95ff85b7b4e9c537831b3824c637993c0b0a700edf1e279c7ab0125d236bfbf79b1d2ab55e5d7d28535fc3a49eefbf63460b87aef458a6fe9d6d392ffdd2d68ee6b96013e2b047cba1c1a77f289745e926faec7cb14488b8bb90b1310ddf2c8653ffdfa055619b2701eae7c8c75edbe68863bb0d316f30c90940a5a2d910d66ae19ce3fdd8b0e633a0120b45f14dcf2f09f852d139c2de4f7c2d4d4c38c25d673474e3299b34be43dbda0b96b0203e3f89f32aeda4da858a5dd244cde9862adb59d3e3599e5320f918d0dec7e76df6d6cb055a84967f4079fcc0f3e1dc05d79247834147d254c72debe58f5f3500c83f6e10d391d79de47d158b295af0ba12b2051cf0dcb6e1c08dfa8c27ba9c1e1ab3f376f33ff60ab4a6686acc9f122f6e22a40ec7246d94a90c711d8355413ec31fec89aea07ba272c10586368ce030fe1fe79207d097b365d58de66a6801c1a5f0858e5a614256b6848cbc7356433e5566d29f73be01662b5f8dd4a47c89aa08f1a68170ce3e777588d31505bc6c11317309dac01ed41bc73a99deea7f1705ec704da387c375d72f6c39509dd1b369ab634a5009c9c3b04dbd048cc2bdc8b540d12e448d903e29ca1b42a7fba2aae46532f742f7b23271af66b961d82083fd584172d9415e002a09709b55b36e12e582776f76c3a4b05590c6e8db3af0689b20ae2b884fefe1a61b3973e27fc6490ec8d5c6fe0f8b023a726fc83cbc5bb16e03ca1ba49d71602e22a36fc4af9f5ce7cc1a5550d408e8509c20a19fc4b968e058cead90b0279d38dfc6425ea126263d3d34b61c2db0e0b0288f8a6ee038ad40b4fc8060139c6e1ae394afe794ce999b6616104650390e135df06c616a91885d57fe566c44051661e42cc2db9e1533e5b4d2a572aaa68d3849196311886852c21e212a7e65b6cfead987fe3a3e5580f048dd389f661a4dbae51274d8d70b0e433a0440ad97576d4379ea50eec0be184e9ba56fa7dd5e26f8105b52de06bd416f3d3f7c85c6bd57ece78b634538bde54969dc4ef3300ae2023a49ac8d4b79208db332d939239bcda7af783b760d86d08387551a8702bd515bf5f778c233f379a8f1a06fd15ea8b446c8b6ee74986d748da9d59252474824f5e528b2b17ba5879120d462e605294328de5c98534bebf3478194065c1973beea4b30058bcbb19a618ebf39d3309206fb59bf2784ec265d1448dbcba98a4c5865d720e7b240e836aa50c4f042f89dcdf8f1073d1341cf67fda842fdbd1fac4b83ee70843fb64bf6fef4a6678457d36eac6b96fff73ec57c1637ac76f0ec6bb2a888efb379f89c69f6849fb0c1a8725adb12dd8d3a6e7f5af6d990f78e535d9fa8b901cbfba336404d2997f457a1fcbfc1bba11221b0ba07fa23da392ebccf6e2f4b18f67d9ebbc0df42b9a387a61f256a77b881abdf7b087b388a1f426ca176019c3fc6e036c117626250c1dcaa95a2677578ffc263cf475c9271a279ae9de2eedf481a85f702d38f4faad37a4851a0064a9fde4c1a02b4086117cdf455af1099b0e4200b980e357e001cd6999a017a1234ca6aa3f4aea7741ddd144171178e6f3ae27372ecbbc8094255f23bd477965df76543a47a1bea8a4fa1f5a6c322ce017f2fb5d3b583bc37530606addb181f9517bb99951a19989a1ee4c63595a95a4431a62de1f470321f027baa07b929146d973ac1c5b63da001b20ade3b14d526d83dda276d72fb12238b79faf83ed531609a6f543f2f67d52af6a43c66873b51c419294d3be94a4843c745fb9f7d56bdf25066103762d3082aa350dcfef1a076d35b9486395d666f925b1acbfe82381d4504cd97a43304886c5b9e0dd58033481548815bafe8e98de9c9cac6ae9db311a9f1dbe53ea8a9e9eb749e7d0982b3838aa6fb74bd9a20a9c688aeeecb87898bd3557b188fe895e6f1885ee53ff8a29747ca2676ecdbfdeb26c71d55003cb7eec750c7843ce0590abf6b37bc8034e00d048b7c667954bd7ca4900d4b45282d419ca2bec8597ccd90fd268a70afae2d45cf4ee3d12f37d6a9016efbd656b6c34769cafddd668edf622580af0ced03d4637b54b76b3820742675af35961968e87e53d8be6a05111c831c1b040363fb8afe75b14f5806ac54d40759b8e62c65b8bc0ca5ba474cf350750c3641eb4d0d88c695a05a82b7897f4c0ace25e48a6082d9f15beeac220df4ca9babfbc4d35b0bb06947e03f1ef062d61c5df47a2ef67fb13b40b7da8931c6719a567f4f74a9761cbf16ee5427f911e60a8ba0b0e4feb899754bd400c68d3b31aeff1176ce34f0785274f74c4550d2914d7ce4d81c74f050e43d892f07b25713af8514ff31e5d8b2e6e7c3284470a6b1c77ae370c3c2411ee7931d7c5589018246c8566c460e1d2e59931027ddf0bcafddfe3df131bc34c095482c8b61df8a9ef03bca54499a3a4e6e12fae68373f70a6d1a1efc5956130e4cf9e0396953a74ff4f8f9b2dcb86cb4a011e329a1ce4f4da65b99386be3819d306f48889e08049dda80bee42eaae079fe523cebdf139fc95ebfb0285dfaab7e788509bdb1dea5648375b5f4be08fa8190c39fc7ada8236ae5067b36da2fa61a530f0aeed36fe159ffbdbfa62a480de32b27bfca31179be180738658eaac37351e432c8a420d85aa562c87f8e48eacc425dadf72a04de3ba538e214c5b7cb07256646b53eafebc42a1e20a76bec600bae05d19a9be31822421cfb21e9224f5f6e761e984b54768971263894f892c0d023c67c699e9fb7e39d67a98fa9ab054b743512120ac832b606df39099fe1f64450c36d96049eb118065377a5f37112fe2f02562bdb2450596c2af13886655a27892cff1b5501df2a97cbbc812a699751b9f1035701d0a688ca7d77fefad7b91cc746be61847295399d6fdce389b804e3c0b9f0670cd1062456a64cf7136cd1dc94cb71750a19b96ca5844b9bd48e0464333fb30b674efa2c07f7fef3d1b80373b93ab4f9c0539c5d98fc5662ae3bd2ac558073ccffbd744def436235ebb57ed2a502162e91eaeeda65daf419b5c04c0b8bca4ddc8e47310a74e6e665e50730c98f0c0a5ceb466e3154a847869052eb27c78c890e61f0877f9a8f8a064d0ad60de59e04c1f0d3f78cf64f0f2b1a2fe6488db1c6ced04e07f320a9356db841b582e2fe94f13df4e5e65d0a0eb281f18531ab0ed37cce97daabfcef3939c481fe088b60c7d9103e57df1b5c61bc132ca48d4457cda01920c9b496415efda67d47a90a92f847e176f087f93d2223a2b8f145eeb1866a6817ebc554f0f85cc7f5ef153f52c6a1bf58500d32b2e59de8c2c014f74b61f88cdedd352acf4421bb3a769e3ccfe75f2221349f618fea2dc0ed6ad1cfb5c17dc473ec473ba4c3ef43877f64375171881ac0b4063be27513a0d63163176a7bd9dbf487f34d159bc9bc5fb15952f17ab4f4755bfc2cc8db2dd1b2c9260bc500c87dc6fc067097badd6e8eef82628e56db0c1d31911779a93c603806ed6806687c87b4450804c2f467c92d6994f44fed965964f8c5476534e3ad29afd7b966b5f76ad0dc95b5de83461ee814183bafb4d26e55880cb90a1fa70a44a91077ffc385392e919707ea145bee886c273389da6c5d9a66ca5dad2d45be0a1a55bbce40656a43bca474050eae6b11a2e425717fd18c4419f6bc688d6d73855aef0768cb1b1c9dc5c9cfe2e96500a3d62ae032c9cd4dc23130373e30fc74c3ed87f320d6f009113843dfa36537f672cca95ee6c9a6795431884f897a488e0807f1808210444935e8094697984da22c68057b4e9c3a32755c2fee8acc18aae8c160b4b48553abe9ee0ef0fee8e4d65120aaee022a8bfe253ae12b343911a238d12dc2d85fb86654948c68d4df1186aba98dd48f2d78854afc5fd97c7040162a9d08008e60eaf453059a769cd915877d4fe923943bccf748a88f4103890d4b963402fac82e8e4114ec0147b90a47a5318627231d17948779b620bb1d84b96caa8e0e01a4db3e5748415c208134a574689985eff8daf0719b5ead8e0df3c37d91c261587d1c4568436add23aa5b438519530bf379e3f2411f2b38a099f0839243101bb6248bbbecad4c136b3e9df10a80bf243b3aaa686f2f9484ba71e4a7eb9d6589a67449249a0b279e5430186e94613737ebf282e411e828400c5b8ead904aa1e2947f989ac782c858a6c046fc613709904a35af3c4e07d7900d45b9536a16dead1a3c7853027cefc6c2c34aa70f9ccaa364121184dba9dd220a164005521b0cc02fb354ab65d1029ec903bf60e9b5842712c02e08a55708ae4efc18ef5b920811a18d207db42c87e7b8e1304ffff351a149e9bc24c1344a23cbcf55309397e410b5bde5723c081653f3e0825956caae259c8548720743f666d92d0884b39244446f4ff049882fa8112cc8f1e00bf35ac4ce229329057099eaf3571734bb8b6d25c8373bf7e855c3f09b06a7f7e4bcda395ed8a0b249b1dacac9b42819a3690c400b3ab76dbc9f3d433b95ca9f05aae8c4b83319a81bedca062676407150121fb77a8902fc66e52814136a53130793a4e91daeae458fc2a024b8ebddbba1ea7e051a6f08de2c75d2378fee3ba7550d37bc1db8112a21ab9839865ec7a9b665dc221c6bf1834c6b08c006f40e6b4689b0909a69d0f1b7981f1097efb9e6b15a11695f644cbdb69f3a75d4fc1efb19e40b8db83d178344cfbb58d63121d1cc981bb82a2da982487ad53a050d0df684d584aef3a3816938651ac2ffd4cfc2a7e747098ed32c0117c27015a2e7bdd5ace95b1e9371678a965e1f1aaf89d0713f88d6f393ff989945e63adef2679e7e7898272f02a7460b87c8b2477d419f3ea526d71473bada923bc83274c6e9c67488d83ce28f86756c1738b3346cbababf17c9b4cbe5c7e1894868c0f4ec9ba049868d2f8a4338c129564bf5dded27a182f7fd78c55de27dc586b90d159755657619e3553750590db45af0c7375b5d17fa8c4496b94248735f6ec08b729ff411fabc2b3fa328afc9866e35da067e41def2bcd53318e0de70e86642e2154c4d9aa77ce6c6cfa28bca8096f30d1b00512318e5d07a18f2b87f6bc385d9999593e440c1545c149832cc71bdf976110d324553c89577a995fc12e4d6d44e26e43f28c3ff3b9db0dd74ce079ff787028e4e2a95d1b121b77e492cda06a0c89d9165097a58e77c0815029aacaa0cb0149a8095f1d42b5db2c19f58502c5a70672cd986857d1f642f8a16f16b33a04a01f233635e8fb310449922117c38054ff501a87496c2a9a588db5884f04089ebc0d7408749f4395b34882acd09de0342aa963d8602bb1ba0190ac3cfd6e40543a603db0572a2094892b425844d1ec059f0d9d847c9264a35bbd6fa170707d7454dbe0b7023b16670548ec2ff3811e24d57b0c7f114b9f603a7d0186e6aa64862e639b6e1b132fab15bb3259ae2c4027e5d9c41356695a222e9c46476713965c03fd4ad403c3c2f8dfeec97971086569af872e6b3ac31ea230d2124bbfc8f9a0801fe68d7f552ce9c7d1049e5975b70015c308c99050e810deb70d101abdaa26d227a157b340634427506f77083e80efedf04cbb33d84b402deaf2db10a4b7178c5cd06a786659e25216accc5a4e5a7e53dd6301fec212bdb6b522fed489b26fe2a03737b892382040ecae225cc62bc4944824393c19968e3112e2e7345cdc391187bcb16acedc9432621239a2e7a753a8488a732d747232f658a0b206059bb18f32c5f9f279bd256ffe590b402c1ae2e6decb119031eadc77fd2d4d202c3650ec59e9e496c3f16c4744b93fb681c80f9181ce4bff606c203eec83c9df76402151256ff620d071f0671470b606674178b01b66be135d92efa2110c3706f02f0a931b27683888399fcb9c8bd29f5fd9ba9323636de34f3674cb44142931ba9571e11476dc21e06bd1e5b194ce5e3d504704cda92bacc0636dd403c95980686ec63a7da12687032ef48b12c4720e6abedb5924782465952ee9851549e031fc1ce08c3f787e4e0fdea749fd5326a7dbe0cc7bcfc9e024cac0f24ab802b4ad4ba80ab63472036bba04b982b117710e1066012597e914214db93b0fa67d730496e0be7be2abf8ac055bd4f90bcc0610067b2735526b01f8322ae2136f20b5b1c0549b5a7aac280bfd12e4c809b1ce15fe37a510347ad53543b54bcc5a5415e368e428b75f810c07ed5c13f4c220725325387b06eaa1b07332df569150c4a3ed22be6f952b612b1c36a571874b6b6078072c055bf4155ff7039e6892621274d6e8e904de7fa89bd5045a72b146e0e7d6d75116aaedc4d207e079d7d57a0c3a63194b4745c05c160396af62d226791fb9842f9ce90887507cc0ad15641532b6df78ee291f5be1ed911af9dd80f683fb1abcfda6a96d4aa6294bc539778ae5f63031e4008adb38caedb343e2aa799e05f0bef535de39a1b21362fd4b7e594e98ee6892b354813ad4df666a4789dbd294c626f67a3355b6cf7e55fa8e844c7b2dc18f3748e68547bcfa6c8dd4d5fc23316df916e3f91cf6175e024bd103ca4c70eb11a41c072e5da6104ba8c3c19aade8d8d65983be644805e140baa198cb6ab0ccad2c8c19cd1320e8cd08e728fd4cde46bd108be8d217d865f18a9fb5651547fd805340487f5a363c94b87a432e65471fe3b4b82c79312945ea4bc2b8c95f997990aa07653b991ad82b600469a3899dd3273bee028e0c8be326f695570d79d7a67d4d2ca3c7725155c7fad08ccc8ac90f22b06453126b16cbb0e171774521ddb2329e0beca9cfbe8e8100b370a90557d8f5c5518864813bbcc37b8166d029ab3ac6ca2a8d288724d7dbf1833be94a90f960f2256be370abc4562e6235088f5995a9ba62c84b33b988b43ba22da25c96b116a250d9c094a75d84c74a07e54a623eda2e2876d206cf754e96123ae7d448418933bfe40cf14e200aca329cb31977e6179e247c7a9afc038a4de00beafb59f1c60fd935050b5aab00379a46eb390c0004a2db0205f6bb2a2106b7f5ff045046f04ff117c98993b4d922a5f0f333cd31c3f3110c2c21f7012ceb471cd73192cc6905b97244cec9cbfe3b61832c1207cec436a072a76fe1fd2e546d09c46890c4d17b174f21484d00a3f725e4bccf9ac707219cf43f23c5c4c8137061d790517d51d73989c5c81711b6cacdbd28fe623d5abf9318c72d52875b864e076baf01e990816c4c4230820204a88455177f57641458ba9c4aa4f6cf182ffa8c53ee3d4d4a1c686a983d83dad02066222cb266ad6d68ecca93d80a1a3b58687e7a6818dccead0310c13e418a2cbecab0dd52d57c0897adcf10ab711a34795cb05add6f8d391c265126d2dbb90cf4bdc80ad019d8b5445e71b939bce0b335628414eee849ad10345d24dd59a3964526492f924c6f4f182d8e19b8aa686f53282a2a8f28b81c3da7220ab93bbd43a441c00f492f64d2d26f009877087bbb1b93cc3f485f9a505188a0af3d993e7ae1ff0e9546a694195e310384a9bfc2c1d9f5e724c0aa984d3ef55af96086194490d5b62f99a227b8777f85981414cea5b2680038442363e89be6c6b6e87b7f1994ca23cf8822ae7ab3efcfbd0458dcf4c28412b50733e2e585dd638c4aa6076c76e9722426198690f6f98982e5bd26708a96ae53b9d6c70a1d994b4f3f307afef40767e62b612670903e49162cbbafd944d19b84692c8e7beb0b5e491824ddd55ac6076a1f8568bee3b505a838381b6bc06461085226788ad48291d877c968ae0ef14cf192cc21f4c2492ff8b301346d1475ee907a0d6efe072bdc085ddf90337eeaff039fed1740a6451b4a3af409915d24e8b2d8e5ef1112217a676edc07ebb8e19017317a12bdfb86ff4033b7d5a4ea454c7c6483870ac52ef0889f5074c4796f63f7824b28f10680ac3f4c3a335eb6f2410c567afeb1193f0cb2feadf3fc5afaf9a107754bacf1f2abf001bd7079b179a98b4eea5f8643d3c0659da5b88eaa6266d1061cdafcb5ae90deb084ccc4d1beadbe8cd30bb35b90414d80119dbeb80bcefc7991cb15c8f13afcc07f024eb8e2aeac80b0f712d1a21181e88deefdb1aac00b96f1ff86a2f36b1a1cdd1a21bf87f5526f7280ceea63d1e3c7a72aafd17805aed7e87f8b457543ed30cc0d31defb848bc96d3ec2a18eba42451605a3cae5356453fd2f18ea5e1deae756942ce135592c764b9f9bbb56f6dea4158cd7b107b8b688882e464d409a5eba53ebb4d2abc6822f0f090b50f99120998f58088df305a1d74d09f79609d243de29245ede611190bc3c6347481b05e42c230090bf35bb06a6fb9e897f81f81c313f260ce68ce84a1fa3d5a5a48485e45fab2daff8e4d399b701594d1f6c715d544f03c40e9beb38f5bc0b193a86dc9512b3253b042b8dfb75e907b7ab7741725dec67e1c133ab2b5d1c91894909e4400020a878900b2884d23267779ee78f5362dcbcb4d32e8d3a3a7d374672197455fdd1eb70cae61a8525d73d6c5368054e7cdfb03718b3e1146a85117afe9a7dd9f98be5dccf3cdc75ab52792bddd9257c9ecfc93b2808dae7c8fc158fae7aab5a0b3b75eb56e01897a5edfee8ffc5c1aa68f9976ea86892fa5f3caaa3420978e524fd3131bbe38c69cbf0f267f4590ead3894ece3114899f99ed506b7e62d12004b4fe9a9e4d31e85b211f26a9d5c734224bde658470b4d1a4115fbe59a7aaa83c54cab5712e1030bba7d36d0275250d49f675b9c08ae7ac8f59586212eed4f46f59075b777912a5979ae32967d7f220091c7c60853c218bc45e7f942814cb9dae5008040a84098b2d08d82b39174f6d2a69da87d757aa9ce90e11aaca16b6db5f2ad9547bbfc224dfafbcfcaac20994730de58da8cc155b18fa226d6e9e40ad8758c959bda3e425955802d8107e189169e4ee8ea694312eec0f87e2d4f5a2a2f0d2cb97777515df8ecfb9121f843b648a10e3139ea1ef02423ed366764ef7ecc19c54ea7c76a5d10fa2dd33775cdb98ede619fb1262f4133eaa795fb395d64207b665db3e7499640ec397a428a5d42612893f69e527aeba301e6ea437453baf29b74e8a548017626930815031ee6372b93e9266c251630ba6e4ab8f8ecda9fa29934263fbd0d13834fe7c71527010f64d33a43791c2f9af940ece21e43c1480c614cf26c92b6d21090e9aab49de99c7f46f5be67d88908fd4268ef15839311bca140ec8d62d354a9df11a567d291d8abd3de7a537950a317b049f05dbf2ad7be8807cd8e7a3f76d061215e3a02a34d62796c0e7aed05c07d7da91d22c814e7f3b7ab5ae612cba1efe3290172a953d7a5cc2655d0f84eb58a12d90eb615d88e06aa158380f7374e2c30b97a8f7257daed87fabf072fdf10d873edc64d2952aaea1503efcac48c8d1e7c5cd546b42e3e6931307d3d3a818666f3618b0c2dfd74037bc809f7af80cc0a10def3224cbc10a78bca77315be4b1204841bd379a7ccb7d47b0c02f91dad3f8eb51127b7f2cabd66a7dee00662987de2185e1fb721065eade08a78e9c112113e302773ba976ef7f244c3dbef45f7ee1c5a42198d21dccb0e5cb72f30923a346b8652619508c5babf5c297588323650cad16f3789d91302d22cab54f1a03dc449e74190570043f6543ea4c5bb12f20535c549ecec81b02c094298ab1d69d4fe1b4b0b71c45cb5e6f84d155ccd058e825fc087f761ef0c95df11be05bf58af00105e94cf2e3ab4ccc0ff5f73b4c4122a2559c15391c680822253e43932711d98df6ff1940ae564e386ab9b43cab741195a9d63d3be8bd80737e108d3a44047f288ecc69906a36068e8f6f795ec23a483dee6de464f7fdd85fd64ce1667a0b0937f831359062e206e5ebb6913128ff28c6acb3f3f1ca4b8a1eebf81c518ff25681914a4f0e1db7d29549e8a18cbfd70abfe857facc36206d3442ab0fd34ca788c01a0fadff3d28343600a4235521c5d28c3296dacd1c630bd017ac936a40048be280f37af8dbcef34c046807933cc7bc146f9c892533228e3238d30d2e027f1a8fb51f1288ec45c09affcdc53ff61a1e0c815af26e1ef1ac440600aa924308cc663056cb8a04259e8c7605736108b40dc93915d8ac2af4590b68352cb28cde3a16bfcd06940faa70f0c1a2a33a75e191385a5dfc8e05bf8af0bff677aba120ea3c07131c602005771f3f8500cbea4d8a619b130cfcc5fc9de280fa178a6b639ee2888fed84047492c17c992d9deeda5661e27c85aa879b41d3c7a557fa6062e7abd9f2272809719c6ccb336b8abdadf9987c88738cdf31fa504bf1cfefa442faa08c17c123052fe3c9536ca4d762274fefa47026999526fac55698d522e8862ced8734b4ad8bb23896de8e1167d880abab1f84d4b15bfc30963496bb2cfa277957ce33a6df31849809a70ae12b30be5f8946913246fccb0b31c0e73f9a0941ccdad943354c549c8d297ad57b38ead07bea701d3445a6be21e8e5eea95c5ba4d511549126f81e0f565c55142420753c68a9b913280a2bd272eac1d110f9a4f3861db3ee5e259e8143c325cc3436ada11d623865b4521bada6323a7ba75e705caecc7c2c278233a23f89dead1c84e08364427c008577fced0f22ddb818768f1efbfa7d14ae67ae26414056657bc9e9400d7212b86a30f72f28672eeedb438cf99342a0637829bf500837765bf53bb2fd64c87c47518a9fa14f24c6f9c93685ffc5e845a729c8db101277366ec9ef42434d67ed99049a6ca1ee056940be8dd984552b194dfba524163285e69ec729a5d973d03817387c1f15083ad01e00d7a5b392c618a8540ec8820ae22492499150b549aaee81f29810752b40885c66827b7998a12fa0d5fbf243deec9575678917cf9f3733a881ada58758c4a7548390dce034b95362968ca8e34642ca8f15d04cdf093c34b98a58ab53ee33e3312e8c1765246b01ed9961f4f814ceb79631651b9a59d92c28fce92e5325e6bdeb3491b0f953fca84e94a69b92f55646eec768688915192b3be1d5931369c7b4e753969bfac1472669ce39cf332a93de0768ed324549da11762c9272b2499ae267e39f36a02919a3472b9ab951bd1ea964a2d49866cab85369b15bafa469a838b6d193729b9c797abaaf4b5617e1de70a3b8bf2516ae467a25d0fc94dba37fc51f4a032aa9b64b36c01a12584580426d532859aaf14ddc304ef10507c93a0089b9a2e2cee7e7e0885d0ce2c9034133caf73366b3440d3986bd119f90fdd403243dcb702c401ea165640751652fa4c5c6f105e5913b3de3b30d0311b49e6ce71282e8a5fdb567a100ff63238b4bd068bd9195eec69b6583612b91b3bc1729784a011f78336955f823be5560c6771eb1b0003982ac16b2736b68afb020afad084175f7cb2d2ec6d1eff79f5e2af9a4f9e995ce4a65acfca8d0947ca155ab236511bad1defa27081dca29420b6440f803ae5fcf405d65c9e9ac132353eb27f47fa9d82685c140d1f2d534751594dedbc26b53f13b8eae0d85fe3f9764ca85130639ca9925b5d6486e77242229b4df7b2e484465f3263a3d8e8a5d302c4153fcfb8d1f566f4a8d312c807d4ee0b683b328cc33dd3c939bc3101fde61c6519926ff848c84c6d0e18bae13b5750a68ec55e562860433354527cef4de9e389e91b6b634a0f7e6d0ab637427a77c87f63e31ffd1c281b1782f9f8f3c1592883145d2523bb3b929a73c53f4d64048f29149622d085007bbabc9c7a0f32f7842c786ae58248d15413f7a7c86aa1bb74cc767d495b0945ece260e6189054db7a46e93a96e9fb2f255a9e7fbedaa09433ddb0aec85883acf3a6a9580fbdbb4d8b42e4618c00060668f690bbda51112e08d074d858c8374c74ee80d664974f1ae0955e174f918a60e54eb22c8034eab1968d166e8edac0eeccd337387f5a0b61ae71d6428858cbccbf0ac0d137f78453da341944328db27249cf5e9e745da681af297f40317582cdc2ea3b7d71199930230e00bdee87fa43e95bd033147928e22077129f3c5a7e0f26815c6cea73a094e7458852455212ec8de562a976808ec0f3695dbd70e0329e7d44c832c64a5867c2b6299861e5794a823538cdef737dcff7f8484ff7a7d31e93be9dcaa480d39a843559d878638223b74948b6aea805232d79ecb48c4e62eee074328ed0e68f79429e0dc026ac6454cd77208d9ff3469542bf86102b1a0b6caa83a0c7c93310182858ec390d395db865d98ea5603be6be665e80a938ed64597afb15db10a92e354c3fd718b40a8d588aa42018a6eccfd35fabbbbed52c2301812dc722a913df0eae6f0708fb76fd8b5e837a2c0f56f00cc6de60fd5e914a1ed9e3f10dc8708b12cbbaf10c9b1c7a55934add6265256a5373e54aed42dc0d81eacaaeef96d78bccf157e7460d399a653b2bd6901cdda503e2200ca9abaa0684f9ea428f8082de67de51bc1e8c844be0fc818b2053357e745196e4f2c71d16da3b579dc39330902eb17b026fff073757286cc54c223075802a492b10f563ba64dc17827c148bc07c790b869d2ff4284c4c428779570fe35a69792050097a8fe6154fe37db4977272a7c986964bac982159b9a30dd322f529838485c654d9e8c6fa2fa050f122d908a2abd2cdc4b29a674ce27d429583a153168946b6d0fae7213590df70b1c498ef31bfa88b04a7a7229817e695b8a9540515843b62eedaa2907a005f39521a58334dfc2dfe7a3942ae0a37bdadd63a4291378c0d770fd82bdcae0d0d8f611db5783569b263d6c023b49dbca901b1fadc9cf65201d05287de5d5c7788cb24b00f3f889ff734619c27485f7620454158950eafd3c9825cb383cda6f425e79ad7b973eabaf24275b962749b1525a2cacc0021069682d70a4372e2b56503a52f99096681f5c2245699c92e0376986e02c388a89d37884239b01490972f1381e93be27c813b4100fff910219558d5d06761d9621fd75f48861963d8a67d4422caf30366aeb86ef7efffab8d50dd6b3ce92f194169d3197f68727d4b66b07906e9b8bd30266540a6caaebd896369ceeef263acd1c0fb370a27d5462597fb989d7ee97e7f310511cde2f7182085e214d81a3ed718b6d4f53839d76b6f68f57cc9ecd3f5a48b08d9bec21c6feccb8daaa9846b94d345230285df8efbac0d24f017242709106cfa8ce2a4d90f8303f129ee6cf591262c805c94ca94aec594ca103d8949f1e07a3e11b7d622fb939e723c7f2491307f47f14179a1908244fde9ea32a3e9b8c189dcce5e61ae22261d5acd04cc636f763dc0be1ba1aae230872862a807dc15c9961ef8e020045c1d99145012e62f3309c6152ff7d488cd853eaa61566d5c1a3c5f0b4a16798555434b13343eb4c53dc93cdc5715a40587237dfdac8a35b225286ce3953886e6c639773aebd66e60b16df2867c2d8a7829ccf2002de5f3484d031bd47ed048424e6d1289b17dc1754fd9b16e700fb386970a4ba52ab768fc90dfb6118811cfeef5f63da7ac9d17bd996a1fcf3480373ec5804fd93a0fa8fc555aa4764d39d5c317d293d36b0bf00ba2b4e1c748f3186835bc5e026305b9cd581bf743d0e115559c82c6699e5c801df3bd3b5ed8e5642197ae6a18211e169ede542c2c87cbb5d684de7776da49e04e1c95e4add8aa9131ed83ce51b0e5839ad413f3c9efe81c3ba474357604cf708620b8ab695693edb70747c34c311e9e3b4eaa080be5559f5967563c582204d6f7a535c91982019476e397a372ec4eab8e7b81ae21147153c77b41a36101bd33fba3b33bb189d124184953a548cf70c2a23e3986c4aec300540662534cc176e01a5802f4193b0680ab0085d7fb8593e583821c61b3ec8f08df9442b276269dfbadde2d2fa8a3c6f4c73263ac44d10c9840343ebe2f846685ed81b5ddf8b4bde61a2c7d32c8f8844d3fd775b30f40a2c96c55270895fa937c6c2ef968c6c6f82b036348873fa94ecee16673384a955aa0d0fb52819b0b670c15dc872753f1fbfd2a0ef7dbd9aa06e53cc42776dc0d54982b2aab81b9b9a8fc72935c2e644feb0de707de186c4010bbb51017559640d083cc181148f42a9a6cb6671e6e60f48257f4fbf93ad5bab95007e2a4c762f9cf6fe03e88217b01ab695916bce3d09804080910840a669f76d8272e15f9cdfe16e996e5bc618af225d1fef25c4e3737ab942a61cef08574e2488c773ccbe026489000f87d0a5e33544db847009740a4a98414bf5aa5321331756169a85ac66f604b0c621de48e296fbf0db441377af1401a1f3797e06550f180d09368b769c27c4b2ab287dec2aba5cce942b3d5448399903944db1bc34ad23aba570c2a2850351290ce8e6caa6dabf380dec59da12244e2f4b8da3c6785da877b8e86e4a5e630a661de67040088a58e1aadb2d9644ca3d59826f48117b39ac0f528a94dab06c786eb1202539379adc469ad6654cb385f2d7ec04d11fc57e4cabdd7619042dda31abf38917cad4f7d448349ffa9ec9112f12d39d73cdd1d00c5e6889337e057334701200437607e2ccdbf8a4b794afea80d5e3c8132e895de711963fc7972cd8ab79afb3108ef5eeeece52c49d4581e2d71ebd882748bd8c1b546b1560c9645a1c509761db733f32956bbbfe9c9689599a05b6f8fb453a3f5bbc7a02f8fae5571357d62d02a1d1db1a6c6564d36e8ab0122916606fbe511d5890700d53ba3d6df72778ec5d3d547e5a5fb1aae6ab778e8267d4475f6aa98b86c1f72a5161d0ab636bbd83210478915fd2fcfeea902f1b1af6d17ef35ce2c6aa547b02868d1aee5a860a13c254102a003009386f998ed1436d10347102885836117530739188979c81fd77ca3274201fb724e0cf7dee307a7a7295e251a507979336216c93a9a162f0c8e38a54b8dc0eb0b6fd6064581475a3bdff177b08e369368ab6364108466ee0780c44fa8d244857cf611af68482f0437f5b025e0104a9751ace979c653285039625f2f265d9f39fed662d92efc5361a87785b23f0b362744a8b6949eeeb8b495e197a5f95906fe57da6d7844de2e37328840271e9d4d10541227a36735e4bdfe42af6ad23b3c8143b82fb12f1208ec50ce2e30df351527d081fa47564fcd7e96db375f4af98cc6722556107d9832fe7495e1ec8294d611e51a740c302bac4cbc0ae80a0dc46315b6a0af42385b5dc2086825b06b4ef50bcbe9daadc12579282512dfd616f9f43f5f780256ae027ad7afebb6109139d287e10776d906fdf7bf3eafba204f89120c2943e9785b6b82f2c0c5082e58a9f12382840b9f652eedc8382c51942b1267d019b7245183b489214243e41ab5acf4e65b405393562cac63f265f615a9ef97158e0aff1bbb4722ee7b15345c669b3c6a7d60e5539bea0afea71ce20fcc2ecfd1128a33dbdda9b5a5ec866d22a0f64f35b94464088e0683bea137d5ec4442a1676638a3b4c7482d646b65db326a9024757504ac97a96e6c98d1fe54be95fb8cd422e8794ccad972ac61ae66e93a45e625af9466c6cb1132d91034ae00d24d5bd345d3e2cab6c75ab01c52085751bcb8117666a982ba0f2cf3f9867367d44357874988d4a72e7cc1252436167c3991f474b4547f42d8675659a21cc997afdb55032a683880c0408b8b66c5439c99f9d3d578a29b2b0659cc3e8bb90d5e8814984c60f180890cbd8bb6b0cc5d71281a87441c06705165dd6253160ba381044700f0a616cf311890941c9d082cd1c234f7c71a5f97362417e22a218803bddc51efd41091d6915387780a43d278dbb800bb724f1a6ae8882877c1e4ca11551e2bd687b937bd638e352a1e2074d27aa8b8669d66da9bc614481302e9b4e570684a680716cc288c2d7b9466e8a15109a1fe7b2b2e30b378b71a6544449c843e68a39a8955d7946e6424cbd413a7c44dae255cd57bc4dd26332dc791dc1642939ba4594464fd6272f86271873b78d52d6f9d6fd6338e6a2aa8e29ce7303dfdd3f1ebfaed3472e7569af82d552108d0660cc23cfa3857b7906f515a1769e2836c958b0a87e3ba6bf14d97dfc8491109bdcaf6ae775ac32ead0d0ecab1eb03161d33ce922ba70c3f6f65f33d5c8d373c1503f0c90bdb150104a424305da5ba55fccf256850871f64937f34a42cbd92a5924a7d1496d8c30967f1557e57f3c4219444c8e57dd17916a37144d7796619a0db7f51025366f8fd794e27ea36cb2eaca3fef607cf4466941f6b333f0a909277d28b60829ae8dd52b05fd77c06af38be8ee12b2cc5173e706275f2026f9828e2268585e21d538483918a645d817a0d77951e473f8cc4e8498e19412ac42ee4cb6b7fcc5c000482d2d512f60d58e7fd0de413400f195a0a6c5ca922d3a42b9cc290c8ccb0542c611d028bf477e0999264cfc25456ab4884592baeecc7fc9014c80a73ee630903d247bedf1ff77a39e0b042c9dab7dcaa4fde049dd6768d49e54b3c00d1ab8425090ee3e805c0e7fec6c173612f0ed3452ace1078f3bf89f817426c1a754ca14a17edc6e94643f3aac513e057e88b4082f164c43508ca04cd15996153f2a71bc9abf95f49e71342da557c7e4e8b85313a6c229ea874cf02c3947819813bb89321ae6330b141e8de3ff3062c9892a268a10c371cb2df13b4a0d88f043a0aa8145b87fdd64020f7af87005c043bf8c16c3694ab703b1789256ea1704dfffb432a940f52436bfafca62586975b23720c392d1d39a663f10e7880668a5767316d62717a58ee1817605ee5896dd61a24aede3e12bf6bc00c7ac4d7d5d9ea2c4d563ff0c10c12f2cd0936439f1f3440a05958e7f87cbfd28eef54b634c317a48221fa7ca51a529e95ff3e6403986097142fc6520f9e42ee29f1d41cca3ca171959afb87a8d32d72ed640fb1ed9e98eb34eacc6e2ac3fdc240d7245d4200e572a7317d5b356ef98fc95efc5a2dbe32c980d53430bc5f2181c63031e91897d44d77a8a791975b742ff0a77c204ce0b11912fe386c10fa0a02e91c14288718b552ea7586209c303d4b6be37650f7a2b0197ba66dcbdf20ff9e7170b1e647d39f765046f67aece8771789efaff1d87e5927fd98a6722573b2f69a28b6e1178d555c8e2691120ba976d0ee435799ab23d0e3227ca020132ccde585dc1dcad9b6f0442c8e29c4139278ed1b1ce22fc605848b7972f718b664e3902550e5cfef85d5c3669a26dc90b94e030cdce647f8db5b8db1b132bb5fb4cfd5f50279895e6de3f3b2a7bc3a7eb147885aa98c5e93b99c1d27cb0d4ff336bc6c48bb9b77d6d5c0f4b417fd1bdc88327d2010d76a9837ca3501e1627c46e307950aabf28053db1f4d685c5f23115c24248181d3f9d017895b1df8685d4b3879e992e10f34886a61819b7536bff3642e8178fca4d8e68130132c31151371c7f6e1a2e08deccf816130ee61a349bd5081b552ca26dcead9afa709425c9122e585ce1874c412a6ba9551fb2b7522d05a7dfa447a70d6be39cb485a26ecd61e0b38fe989580ab919fa3a7c5a05b54f12f1893cd09ec83ae9a25bdb1df0619ffe50f6249408d4a61cfcc498634fbc3a5333a054f4e37f4f1733d25c4da273963d604b79039c13a89393421295c6aa6777406c5e4cacab0421eca4902c69c4000e31387f918c2a65969325a01b052577e5546c01e915719615a62979751fd83bb6753765b22a9b8a69a562ff39b6dc77978214b14e07224454056cc4b4b5b10b71514b010c6b3b11e2a6a154cd471b3d6b8f1ae00009013edca416f8393d605e7dadb1c975fd5431783094861833cd35ede77b941272256e3338f8953a1a207ef085cf9754dd9b8978260dcab672949eea2468c5c711cf514d0858027fb012d0c25d75da6cb887f4d64cd6a4e3d90d8768aa2ef018cf12d312f878b02cd19e12499bd5c3f93072cb16f5bcf422918df17efac710e6e2fb6182227bd75502eaa81fbf17ecbbecade7192149a830213f6cd2b561f942f0f96347120716621d7a366ee1ed980c5a3503e0af5becf35b95048c4e08d4c3869971364672c50901c1b2d82172d2b61b6b1ba6412366bf44acec6c0721d94de55fe3a233166f746a8ef8680f76c46f76d202a5571fd9530b128cfd75027d99ac06d6bd2e58e428cd21b5f0e06561618c792af21ce8bc84d8a0c66662a9224e513b1e744fbeea11ca5fda748ae56b8952f2b14b8b971deb4ea510a50089b4e60dafc09118ccdf695888648d220e6b2bb5c3422e4465bcc57aa3839605eaf8cd054331e3261878ae160ae0efcd5f94b2e106dd2d2916531f4fdcfda9a9158536702e44b22f6d4715d37c4395ddc574a55d8be97c837c478eee04804a3a7fa67fb7fb4caa9747204dbb77f188203f9b6a6d4736a9a0e0ff69a4af7b599871122e567c83764e3f6cc46a4ae532a64487c5f0cb38bcb1886ec73f4fe4923bfddf56deed4e2acac59da657655d5a742b0688c6493ebdfabe7cb27f305649f39b9f1e41f9743741491f2ca4dd5f0425ea60f14d664b6b1e714df2a1e639567679a893767da8f31d4430391e142c6854b1a4c5e853510e15bacd1c4a0a000526cd56f67dda0e7922e9bcf1768d970e8c369e90ee957550e3b90a5f6c5fcb019958726bf16849b1aa41e4fc2b90995440b5d617526be5c24931ed9b281fab80e8ad1a23c57df4a9342755fbb14066349423d787e2ea51bb09797339bb2d4ee7bcc2dde06839aaaad1a9b6a79480a963503b019596645daefa74ab6b8f4f7934bb15c34ab3ac99ec05d0d8427d7cfd97c2aba8f80f39dd61c7dfae1a284dc261064c4001f0b33af4faa5fce083255b03ac34433e201493fb7769062aafea6b0c2615b658b8cf416ba1716198bdb79f0d7aa3bb0f5c064086cc07f8d6a0c83fdbef10d031fa8d5fba34f0b1a19878b3180d30a56fbd09ad36896cdb4bf9c5dd79ee16f80c030d091be0f30c26d825cbb2851f118231bcfd0a2037d8f540613214c8e4c0ff3124e12c487fa9741f7018f440ed477483dab9b00952dba10e8465000737c7a56115407c2588eaa47af8eb677a60c189f46fec511d39fc2091705ef8df0912ed1da1da038d73b239638bc4a78480a437d7ebbc15c5d1405fd7e0ef4b68cad09463463222ec901e8c9106bb5a0d1a8de073b558ec7fc2576bd22965d68828ff4aa33922e9150c085004271403c7e52fa81fc58bddf93380a758f1a65b4ae33781a610e928fe1698376835d1714ec401035d55bba86183cf0e4e2df2ce91ab68d90ef07fa21c05e782da074d1424f2fec1f0295e90f08985725a7569601700ee672f0d4ceca053184189881b0647f8fde7132057e09b4813ec9a8456131df7f242ccac8a1d1e142be1cd29ac03d16a4268881dac9cb01732fd4698e80000e1a170fac5ea23fa82ceac6029e4106b8be432c32ef377647719dea2d7dc7e717e10ae72ab8cee3a9540b98a932a0dc33f5808f1ccef5293d66dee7db2704884038ca4417b827b3d8e2d4a9c98373cbdc7324aa072c1a7c6c5e41cfc0513b55c52bdd027e3abb746e8398ecf8108df69b854dd012fa0b72c7a9ea312578abc15d0073e11e3608cb16011363920aa2a64b62d9da90ec5dc3b1939ce9d5964180dfbb8514e0c8b51e4e5a73e32588ca4b320f363763a60d36ffb392141394c728371c67be3036f40d07d159d5ce42466902c931d3170a29285517277483d10e1c178823630fbdaa445aadb569c283c532d06825e618e593ede3ec594350ddce4314382ed89448365a89329668a24b5792bff3795a8c4f2a6cb88f43ce6f13f803cecafc58e0788054d35d8dd365cbfc8755ff07724d0926d8666004737c6dc1182a2367413a395d6013f2ba5e5e4c96cb43815fa3f31041a5300ae6ad566a3574dd055e943d940130e1ba3e048850cc5517039acf31a5acfd43f232765ea7f4dedf26e196cf43bee984140f8308d2b1d33dbe551208cb2a96ddb85a0d61bf0d224c4ba0a48edf1e47ac05d2261e1336edac6455fa84dda915afb66d63b9b5dda0d001e2775478bd18cc61028a6f1c24637dc83565c65f4aa632d340ada64856f093a09ca3c60f9e3b4f25b71e0d43f40f00c61be945adb9a6b7ca86fca1764f8be843d74529b93290dbc6ee71ad4392a54f7be2649071f1da4ad0b439dad9ad52fdbbabfb5f67ded7bd0d0859f29a670749e97289f0cae51a3bd49bf1326679ad5a1a6742998e8e224243a7cb508c57f662bed3460bac7fb2a894fc814075e3a537f8ccf33acd84c018ea3c7f82b28bdd0508f7bc5ea48d301c20212d961c35602a6ef1438b2c3b22281014581aae3a7a98cc02b07849c0abcbb380ff67994b48ef3f4a16a080416204441469b7b21437aa0bdc08741b1d5bc01699968533d4c398bc5c9c0751e2db1c00c45f5a6694f8a187ffeece67791f60608518a09b0267386c8a3c2fd1e250e4fc2a174b1681d860dbcadbd1e3752401fdff1eb7802c79d3df0226657130aef6ac45de02252e41336f39adfde8687d010d3c334d8751e0e8d515bfb316cd8d59c3aeaf933d629fd41a472ccf81d0c4a36d2a5f78aab617008184933beadea99c7b7793950cd626c98815522caae3fb15b36006af3b7ee7378884349afcf944759d49e3f13219927849a4724eaee7c2390b93bd40912f1bbb98681e1c17af53e81a20e6455f5a90da6602e100ca86802beee0b736b70986802d8257773ae2350d54203fa1038c017e88f961f40af5f9d50b586a7f070afd5cc6cd22e43e0353851d7773d0d8546aca57d1936ee66a61cf5fe39eaf484d07c16d94e73844a5f0e582eee138c092fe33015b9d8096512c22a830864fd072ae7e78d04d810df5158d418b57d61b8e3718300ee4a2118a2ff070f72df7c88540f316ebd25feef94d6d02907fab3c5d3aef1f14309748aff49c2f718d51dc8c241f16addbd8781382d913fdd7ffe93681e11e166559b309f9585cec9fc79519932a6b9010df30e69bc8b74184a214bcdf130b09bf38f0fc16723410e2fe791641f4864a18d8f411a287c10c6eb348d4abbc413e30ce825bf3deba43ed1215ca3636acb196959efafc3005e6fc63e1b32a083edd87534534e49c3a8015132ea5ece8968e5403afdcc34af1a5e0ff8c5e188498369d79135db0ea96a8d312d7366cec0838182027a5068f86057219077946c35f7c3e10ecf3fbfa93ec101f23c999dd2f64e8e98d91fb60202ea1863bee271d80b7fc196485c0cc195c848000182b7ec3321386bc151b4779cc625fac0e30d04dc922ac79f775e930a0e080134d3c496ab8b8bb58c1b1a0b58278e765c10aa873c4ce32ea7a15098b7b46fc347ddcfa4cfde3f039d8607613dd0d8ae6d0892cf2e5817af3d7f13b22e6d773aa085af133004a85867867fcdd5be822251e2d5f789f18a440c08387792cfbe478e4d1204eb122bd070cdbdb5d867a76f0f316491a2f7b1fbee69b7c25331b19e876b8a3185afd225723bbf29f6ea5e54041d7f40a7816b9a20bb7d1dcbda12a11e96615630e895863b1a3508e4ae5cbff2fef957a9edd1df149a925a4c4ce9c7fcb466ca25fb17992b85f550c2c72f602065cc1b43a02254bd57904c14696f0d6226b713da394601304569e72dc9c3412e562f2c3a37a0e88e4ba23e95c66b30c14f83dfb7b8703044781d507c4d6fe63a1d6f57ef19dc81e806e07617393232930e399a0debd7a4670d88fe95745a24b627c847d2d4362ff5a606f357f2452514c1608304d60712ab9617ac2dd2d9af68e1840491480a81df64f25439e6dd2a32fd29688507143af75a45d371105ad8e8b515e78b5de7b22a7825eede83a7868b97bc2cbc294b606883e1a3170e549bc78a9b48703e0140100b250c6e7dea4aee917c7cd64af9b8a7710da522c2a190e483fcdd216695c778683508c18856a8f215f82062535fed0a2ad4eaed5769fbe50f05cda5320cdcf2032b3be3183c65074612c8c7c30cbe29ada03d3eb7a07b73d48df4f6be6fbec2f7d82c3438a678764eb209cca0a3108ea0602e8672e82c8cca1301775be296a757e8b217eebedbac44403e8d319767073df2a27543f56a49f62bc20ac4922fef850f3ef92f58a40ab5ba4532d57b0563b805c30281ed1ec241b950ce52372e675afe7eb3450795e00bffe901d84b7f14a3cd5309a985b98994441d481982746cf0c6cdb6d817aaab0c41bfff7262e71535d5f19aae32387212c67a90ab6b83f8b1dfa0dc0c86a5c425b59df1c5d9723e372b9dc7be9f6d0872bdbae24d51eef0dafffda71c0e9f52babaeb5882b895d2ddd38cfb033ebb3d248b94e6513caf915d200d3e657c476a3e21e9efeb6984d68ba7ae59ccea4656d6455ea2912903b0cf126a6535108d5a616b189a35d7b0bf474ae910a4f31a907bb3b66af22aec037610077aef6de38f51d85e55585cafd5e0d5c430d3b8941f0b07fe4bac02bfca1f44eefd42bbac60997d257fbb377b119d0ab617361a4ec2073e62ad8840f61e942452d0d31d44fba5b41fe509e7406febffdc760bd26f341ed63706038917e5ea1ccc0eff802cdea838f4921bc3b9701f4cf1c57cc72ff135cc96c729f81030483c4a6c41fdc9798697db41c176a17e22414c4ef6d1616e906868cdfb700038342c883c9c19279efedf764d9cf19d0def1474475b363596d02e3830ffd105e2dbba68d22b8b8a866acdc89c43d395f4206a1ce0e7b7bafab4d5419c5359dc491d621927a15a87a6ca826a8e9dbf07d6e7ccc3cc27cc90ef1143999c272c55b3761e9c8fddcdf3e8b46bcdb1b8335aeeef5ce1d78d64828039a2f0b3ab16864821d8dae73009630f901992034766b62dd15aca856c4e8c16de796c28fe0d0cab82c923effc8df439c492c7b33bf33b150683bf80bcc994465ae9d24b23fd34694e93e6b4693f2d35cee77f1d79ba74a5492b9db4d34b3f7d9a69583aebf403e9bc4a50501d6f412960d03da481caa38cb5044d81ed8461734ee9f741e5082d1cd8aa39661aff463ca9d193362999a49777309895efe6ba8c933c78001c7bee52aa57a4c9bd6227730463a93f245e39140d2a61417304fbaf993e34060d97f0f97cf40a5705e478a9d31e15e712def92221fd77946d1c2db7445de1e161a07f188da563d158e9e2fecde6353aa59031fbcf6235e0a5aec69be5e29afd5834353af6fcab94eaacda8ff19f51fd85e673ff383946cb52067c5f4fb6e71476c36093172dc6d54c0760ce45e0347a7083666c1f0dd5b50daa51b0f2d866f553e4dfcccb4fbe860496ad3c2a188679f1b6127ed92595f8ea3f68b624b32f052a9b8a306a139cd609b0bbb11e995a89f2e40a5620e915111a896c5f20957858b9943b430c4194b10292db3beca2c6c883a950b75442463b2c5545155bfdf594fbe5f9fdb1db2b16d5ecff53c26e45755ffe25c0fe49254cfcd9dbb645751fff4174701fee660567d57e02888beafed6d79793975c517d9cffd5266c51adc36f60d6ff37cbff0fdaaca8eede875a4fad1d601515a7f9d32ef797e8fbc7b4472c2aadffa30bb715d5bcffc24e296a02fd9f31fadfec5577c2c0ba68517141e39042a4b4e86c7318ff2a8800b0d3a0a862f06fff5c5554f3f03f8dd5ffcdf2ff433758547719a1628fa3c2b07f51c534bf3ce5bf38bf7e74fbdaa29afd7f82dd6151ddd7bf06587f043cff9c2fa845b524b3021f207a28bcc7b1a27290f60b09c8835cb213647dfb1b32fca97476c1788a38e2c5dd98ee8c986c507d4428872b2a8edeb2bed0f6c880ad4d45f5994abef42a40d92e2a5ea7de68ab6ce30751bf2d3c4535bf75c1d8ed960586fda009afa8568ddaa4a2a2f9c99bfffe8dbfc5d8fa6d64b5e36c9f5b992aaea5a82e35b32308a7d453b3e5363f384dd26e57057a50cd4320ac562aeab92653c987b43dba9b8cd9c24ff10d98848739aaf23d43c70df3f8df75f794bd0e626aa4e0ef35f137fddedbd4eb3d901803078247b9bba47723235627cd0ee19d97783d6989a272244bc4491afbb8a8dfa602d0936e10c73751539e31758858d0a859b027ca38a4fe7b83ffaa3d30cc8fa3fbe5edeff4614ff3aa85176dec8a19c217143aaae1eb6575c5e7ca9cacd7c3a3d04689d98d4fed36714b20996d67331f49110234ff75831a0fd3629b8c0869a223b1a0e187a45e110228ffba641a37217d6021bd69ac80aa8426f4da8e8d183d644a8912d66fa86e4dc4c8b54420c2433e172c81b08fa4224442260715956d294c537a67592a0351545d3458251eb1cb1ec440a1b0f075d54fd57a49672783721e055bdb543a24ac2768447f8d24cc7b7cee55eb42b1149af1ab9a4cc0ab422f9bd49367d0f1972999e785ac1557d1cce87c5bfd802f81e470ac61614b6b129d2f6166ff89e60e3934eebd554a70016f431153226c916805407d91f9662247071c219aa770a72462f9bfbd00a5a80e83fc2b04e47408cc8cf264053901607bb20c084058d229e472246c81529f8c90c4c2f844b1cf121b4184672168485403dc3729d5543fea32a8a91b43919ed35632f0cad877ce36dae87f7b1442e1276ab076ce8d0b21ad0bf0d551d702b0c0f018ab7d2458700d3add9015d0599250fee2cfbb225d51abbf5fc8c32b63c7edc5681d401985cc78f2b3f2839ef4a7889d075f9fd48c53895947d640f62a8c3e862d5527f05291a3e59046ae4112463394a8de6bf192c80b84d7708ecd5a9c844e05ba581a8993fbe018e4c8bd710ab6da81b84fec4b2ea97542c0b6713c0d0da9344c8996137434ea9d9af14b87655a9c3777c3a574348809b38d58ad1c303f0d73081817f9e9bba40548bab8d25bcd4436d6d6dc9a046a2bf631fa2a2a25e3297b3928bbcb555d01c60bfc332b621562e254961d93b72434f6471b1942722f0e2796375bf699f0239cb3675a52c66fef6caf6f844901ec491ab4dde11a988e24457c88335a3f110958c6f9f7cdb2e135a7eec44ef2b3c0985909b29d88e21efc9d690c84bf951c264b7ef7d6dc4ce75562506c683ff82c3b9806799a7336a9e1e354e24ef0c8f35bf57dd815a2454f8868d55e90b09fd5a2cc8011f3a0b92ce274207e1e936082f233961332eeecb64a6a6a19aab53d826466d4e873a0174ad6aa266d013fb32171e29bb8b26e54be894d15148b897e80ce744df7a0cd4a62ff75290d49c969b9a6215b8a1d1f1377b062fbfbd7bd0681227a0a291c404bbf246a921d6176fe29549434fc3a1f46e5e1f1132a231a902b3fb51de61213a88ec876e935703b2025297db184ed2b49bd2e075f3fb4b4315e13fed5a9121ed18fe84d9d4802f17d17e0098274295091ce52cb6d5d4f5f2787b2790b7680e40a22494bafcfe40ccacfccf595735d1f977112d70de8327e6de1eca5c2eddace3d15ce83706c04c834b6d9172c32964f8247d3052e38de2ab59f90143ac46620bd53e8098fc5d8724526c26d18eb75c4d0c82cd5f74d93d41f81de3a20d580310ef8c18b1ee1e84b0e427951a4dc01364bdc46d68dc701820e965899f3e7c029922b763e40f29d09a16fb028210393555dbdd5e5f7ed7b3d5f26946e37964c631a0c6a54fde72bb2e1c7f8da2a42a5b50e54df6e0b559dd3bddeb39105ce2783c127f3cc3542078e4367694aa7221ec703998870260d4788ca671aea15cc26f8983fa44dd5433beb9df66c29ae083b6834487e32cf1b3fc7b4ecc2540906419397e8c069f51842cc5111a6fcd7cebe65ea800b000a094b2522eee1fe50318d0fa760cdee11640e99b8c8e9875382d71f2803333ea50d48e848b3d16077ac5d04222f989bfa7f47ea54714bfc85ced1b5056cf3f62571e63e8774c0bdabb499ecfef652be7b8185f88dd0e66643149b002955c137bb0f22679e88206faf369e7fc546dfa34063e6b957c888b16e3d761d794c79c46441627c8c1d831f43dfc17fc337ce242294e7af979be42a89a2c184bd741125163f8300f95a5904453d82ff2c8cff32580f7db840a02b148d01f2d3a6ae525a34392d444fcf2b14f765f630af9767d393d8219784ad9700f2d481a991d5dfa893bb0b8483d91cedfb1f3697ef21dfd87cb758b7e9f0b910f210819043a6df48ead066510205312cf5a95664b4a08e163c4d705cca994b9abd86172093fa400aa217a1fa73fb5e34f9336cf6cfa09f224421f41949d5756815831f44d3ab1f09dfc36c3af2b6aa459b0790117cbbe6b8be147c546791b25ac2609a4726300472eb6901f8e0a98c60049cc8e64f3273c68c075a69d33f45e2cfe2574d477cd369e81bcaeefedb034421e71c702ff97825cca817a239ee6545360dfaee78f257a8ff460f3f4c953bc2848c4277ba99fb12079c1a5da4349934c784a2ccffa6a8656b8e76cb9d5422525df4857fa32b073209ac26d443fb5b351c9b84c0b44b9fdb53231f0abbddc0034d18edcde2cf513d0ff1df51c03212feebea1560f388db90f544c11eb4f071184146b5e59880598ab35dcb976dcb87b6fda2131befa0556efd886d05d2b105d47b45b128a5bb826169879f2f9bb01e7676c7984a0eab686e509c57e4cf99c785e18f3bbaf30f2e6741e831a84e1ab17664056b025e6a83de3c374cc51686efe8938b582b1be175281b3d8414e4698459209a2379cd3508c8ce2efe48442b2012a38328363a57be62bfde636d7b321c7036ea5554df60df8d677dedac2c3509041bc46b5ce7b41395eb4a71a946c9d5a4483abee42e8855cdef50229fe11219806f48a027f57b476ac533bc516cb054b812e795127f71a32923f916d483628e867308e5842257a998379d86e49bb8ef2cb49c851f678e91b0c4cf422edf616e539bb4c6e2262059a554b0756fe17a82148784e256091093d590cbce88fc80087a2339657cf768c215d448c785c866f682291215f9c1df95872b780ff4570f9f4be8dc32c2e4e744373b7907048fd7c627b37a6bd4c30e8727a3f0181695628a4fecafed3fe6e5409122be10dd8ef9e6136bec14afd60838e1ce0b07fffb7ee83d8af4e29553321d0127220fd91a14335f19fd4cd81b9f78e1ebb1a37a1a80b38abdae97d1cfcacae820675a3567bd3973352485787bee03f6707e5c40f14713785d83731097493576b1e7c3be8f362f71584a0503f4e6b1ce6b3d3f41acc29843ae10c297ace0fd6531ea573aedaf9feae83a9eb101b64ba2d7fa0ce7ff528b2d17211902dc215e5e4e5175d57d1423a38adc494508581389d4a46f2bf297279913b633f272d0c3eccd460f3171985ebad1ccddef8f69cd41e81b75383e58aa39834a4a29c5d45863cf8f454c430e20c3bd8846054f0f471a66e37cee1d402f8f0cbc6d1c421bc37b13e6a4b01eaffd4912b27e02afaf2b489ad3d1f79672a50b62b404ac3d6673495785e9407f04f46cca600f457de60cd0ebed5d12851b7f238ce9176154fc83b941ab19f60f913823fbdf2e72728af98a50da58e5e09fc911765bd8395221e56e6e78103a950372812242cb545e1c69b6c110f4c17598bc1984ea80a8f76ed63e580dcdd1027984b38602b8e00f9ab481e4bb60f1645f8c8c253ba2205b64001c034a0841a24e1900973da2817947c52a9320282283904e084d946f7f3e433e08c8b3c70be42de3ea148415039017cdcf15bc897ae08da84c1e999058ccc685ea80399ecb1b972c90822f20dd7704f7d5ddc90676607e37ab1fb8651c06e1691ab00b493593fb1535ab65e4cd514b03c0bd5195326abfab7a7fd706f49dd98672cac4edd7604a9f0e661d7b5879cde1a08780c3f9d3f2b44bf31b4ee2535be8822627f540dfd8f4cfe0f12d083fdf091a235a8cdce1cd591d83c660f7a8f2ecaa73e723947f734b3b305e8b28636cc7b234d51086b14626af4ba1a2798b73d147c6b1b9c00634e011055841ceb586542adb300732fd528073831c53a6e74cf4e0d472d2bbf60f3593f5f50860f994ce7a0e457c85127ec9344afeb0c29cbf9a981db518f11dcc547803ef7c11ab9c4de5dc6581abd565f56fb463dc845ee6df3f01e248e50c8df0fe7c7db5020e3ded1ca8a94fab77ad2f684ca382e01c42f3e10cc3f56d238c78774cecc2ddb5ff2299c5a227d9a1ab251f091c1c73db6e952405fea0a92770dfabb07109e5938bd6a6c17318a2b078e6dbab8dab137df88267f8d527d5cdf992ab3664ea538ac1d8b09f983f708cc6299c8cadf602b5fdcd5006255ad6e2178ef1e494020c37e87d28ac208c52050d71a868ae31f7a144936fb1b330b617a93f21463dd4d907e1a8ddeecf2266e6bc187e0b8ffa009fcbf76ce3f5f6329682d7a5f6390bac3a32f43f7cace8e0089f3442dca0880f02cfc61f82a957bd1fa4e4c8725f8d1ae1497d06150d02786a56942a3e7f3b7c55f14b1a068ec75fb8d5c4937805b201b57ac2d03911f76dd4c10c5951f6eb7117f5fe10132d9a5e2673af7e564861726f468ec93dea1e7f0b755e166653f9e0dc24a9ec3516a57eb58f6017bf3005f5c6930cd2c2181777b001b7e726176f8d01bb821dbbb91dc3242b3721904ea591003b95119463ba9200179f877801982e9ac1eb5b4ba9730d90f579402503ad36f9bf0d90818645c999eed0eb43e9efb4ef4800623a5fcc0e189f0f6f0dcfb700c300a85de99f9e270f8b8999c544017a0be97bf7ee12452e3c9b298a19e107d6e143bf90f94a3ee460042dc8a83ee9112905f0962a967bbab4dcb73a0e30e2627377dc1191c1085b2c748e91d0d57fdad9ba1d4b8bd0d6b66fa49257b61ddfdc7bfc0277658d19c801821cc89e6fb50d997639e38b4525406a23a468c4b6f8b10520196c2d5a3021223c3a1db9d3bfbf5e6d2baa861b763372da666c9c9a480da4b25cc26269452c51a8f4ef3b31633d8ba495f7b62e98a9cbef94d4e3cc903a14534ef147a0ec0a89641bb68ff94b8e22f3e201d14b6219c38b1b9b8aebfc0bf3938f2e8c20042cdbab89e0e939ad5cc45021976c18447e19f067b4312c55722338403756f8eb99da62e91988961d722f7400a5d1977329ebce1599427e6fd0c42fe028f8c111507ed746ba2176bcb05410ba8084fa2c39780e1fb6a2a984bef187d6e6e7f5ff05b1f9221556cbe87cdbb5423910e53a386129e566f9f9cb5677831905395f39881a0299551896f7066ef6f93fd27335d7eb46634edd9b003734b307047d36b205edfabd1408c10d546d30f994325f20083cfe6225225ef500ee2401306d6f127a0c4561d4babed6c8d921b8f15cb29b1d602d8971b6e20a7d35dea18c000d3229c3ecc09a90d54a41f25e9e42570438e02b06dbc5c9fda16e45a000b852df830e3f6288bb3f629f9657ed539f453988bc42a9eba316128521f7cd5053513117b09c23848e381a304b3a56d229ef24108ce714cef21662078d27fb305159d698d804d0a0c8745588f8620c5de5ac369aae5936d301d21c36a4c01fc494035dc1f9a72fe518eb17b78ce3f330ca66216c98dcceedb30fa35e5c9958e3f02309be5804c6fe6a958282c88345a83977aea0f2ce8d12504016001305c7a51e5178c0195b86dfc22d5bab7ac4f3739be1dc41a98ba1df9853eb7b3ef61498aff704dea7bd3d1018583c21b25171af7630b6a2eec061e63b7cde3f90f6995afbde0fdfc2a3ab517638162cd01a7433b8419b9ec2ee510404016b3010907c2f71a2521aa97f696898994d52b5c1cdae5f80f6b4e8a75b47afefffe8cfdc509fd8da7ad1095fdaedfbfaf0feddedacb7394a019d85a153e40ff275b6d557b0dc0a008cf5e992df994d0ff59b4576bdaeac0d4dbb88cf5fc21db8a2f7dca84caa9db32efaf306840c03da2396725820ce61950e03c936e082c9d319154add78949efa902ef5ac0d26c2a152d00c2d693aaab055a12ef9ef297a551270400170c2e5ed33b4a43f39426adcbab7f85d242f968a4e8bf7f2b343b463edc8277bef2db7943225290301070007f8065745b64b8ae3385a68224f1b103bc023b63b424cdd01424955679aa44dee89bdb0ccf0cd99c4e18b4bbf3dd2304fccdddb13868c1c5487ed0aa55bf661cfb87723fcfdff3fe9d7c07c25a5948274b657eb4dedb43fd3adbdf3f35a7dacb4c37c9f099fb37fce39c1e66827f17d2ba884dddddddddd2114812baedcb5532ae6ae9d32658a67cd1ac775d16cc139917db0652958b070e1a208734438034a3455f47bbd4444454444444444444445ee6ebb6ce55aa713dd9294f198967c7129e3d5c39e316148d105337bee0c39f3e308b0cc960172599482858becd30c9b387a321d93018de267dcb3c6d0ef4e76aa273bedc3d44fd9bf9b44c9de560e7ad696b7992058fc8092fdf66388ecff3964ffd9ad894ff61b1033d9ff0595ec1f4386d310d97f04128864ff11bcc9fe356e040182f64443530f2821b7282a215e55574290c06aa4791bb2430d8a169134940bca4af6a75d5e5058d99f7e3dd18a60354141193113758215aaa5aa233c5c6129d18292fd86844ff6a75b196626a45ab914cab495be732146ebda769c2646d48c10e112220d591e4d6fe94b1cec011d8acc20049c292643c8b6d6da2a61f94217647f1c4ec9ee032abb2ce9477be971e5c9a4b165ff0fcf169efd8a921ecae60068952771eff7718dfa4fa7579441696ee4ffa245ae16f6fd33a0019a44eb5023ff356bdebca953a7a45126501368b64ee998a051611d12822a5c5f2d3459e35485479563849590163cc1bad26788ae3b733bcc790f61acb0f818d1c5cc991b2c99ebedb8e0ca8e2a314a5c38c1696a015101c321a2797ce10174cc71b4db438960c00d54766a6576e0c164da9034e56125f7ad070b3ab0903192258922649ef28079de7aa0c0f57595e763e15aa895e79c73cef9e5512e95321d6bd6dabf9cbd77ec19753f829bd028f489c260d8598f7255bab396ef02f28cfb9c576e9cf356579a46f3ada51867d05f621d3607edaec8373d89a45a8ee0266194925ab919cc269c7164f34ed7d127ac84396badb5d6da5ba9157895c396c3cc776dbddf5d5bedb5d5cef21d2157cb5d5beb48491d5d8eeebb8452ab3c6914dae408d592a74de9e98832cdfabc1ed99d382fdc2849464515b692d751d78cebb764b6508bd6bc7240512b2a7a95c31652ab1c663eaa4e49e9e86836fbbfb3469f720e3d628c39b394cafb65a1d7b464bf4f6bb556c3ca7eed08a04831e5029ba6cf29ba4fa59ecd9761afd5aa8c754e0ace1d83e603b9f65c30ed49a153c1931f27543dfd1082862346744b1a641e59446ec883c4e685c7173d03c157e8642f23e2b82038cc711c47454b4a0e51aa04914201c9958a24cb098f538127599878c9c982e3c475574ae3ba9e1d4d1b539bef5fcc1b539ddc8f652f8be57963b23169795440bc90cb236f89294a5518e679633a7263f2c1b4630ed72414caf3b624c4750a83f2bc2d717530843f79de96ca74566e4b60bc2ce197e76d098b024b57b8ce89c3a520b9941d11eabc6e8824402cbcf1c95662cb4928042ac8d6140b5203bac1c74f90ae70cb1098d355ac4a117008d7cf13211f102d188f22423c2790478fa7cec9f60d01859f9abc3943b8aa6e8bc805d28575b05c5c96531552bb3238b9902fdb42530781aa549a280843a2fcb623ca8893577f8b3ba06cd79017feaaf7948e9ca61f0c82e152cd3d5ae8b101137a65b8841c0e9d5308e372b3844056ac11a107c50e8124c34067c88d13fee469a343c359215010476d44bfcbcd9023a523164a20f8c03184384f5b979a5ce2a510ccd3d69543eee684b03c6d5db59c44011ad7871b87b63b6872cdf3468b21979fbdc62c7c5fe732ac945dc6f5b5b862f76bafadb5d6d1dd6977777777779b50f2d1f66a3b7bb1ad7e394e4986655e937d7dd1fe1cbe2f6a234ddcd9ceabb6daea9e87ef46e28b9ed5cf03dbdd56b715f460f4939294c27fef9779cdd660de0b37d2b2793f2f6ab3c5e44261c2d6a6f6daa697bb4db9210a50b23ecd40798e4a1cb8373491c54c53f4acda6967e759adc74a1a332bec2613998e26d44c636a65a63c47b10c634dc39f9fa6f3c7da8a6df866df7bff855f117f27362991f73d91c90726ef372991dddbcb35ee3e10f613fb3ef004b556a8ba588e16c37e622150d0cfec6e53a0b28dced94729a55869ae4a1c98330c4d008941f54bafb596a042a289143f41611038832efe3bc71976e4b80f276c68e2f738ec46553c016ef1af3bc269b39a9e98334fc82e00cbfad32706e0d098bd8e77ac6d82cb0fac1bc47347d8ff79dc58ebf469c7fb2b94bac9260963cce18fe3525c0daeaac36aa1065342fa0d82ded8ddc1155442faeeee1ec3efe592662978c491829f28d88a75dc72393a6b955dae5e1077de27644be06b391d2cbe1c9e02c2f0b59c0e165f0e4f81fdf4e9c44b7e3f60275af28b819d5849273f20b0139bfc82c04ea4a4277e6258a3042c84300b95c03fc9fa3f30187872778aeda66261d7513c15024df1a680826047b3d90c840ee57d3c0a85f74bf07ae2cdfe60235d136ab62eb21d6dd89a0afd1e9eddff79ed469d57bb11acd53d094aebfb083ca96dd1083c09bce149dfd3266dcaf3cba9359647992b8afd50980660ff8d39863040c9ef29f98d4d2009fba64a327def03937472d03d2852b26122541236fa588a91df37792f0c19df382707ddf592bbffc2257321cc2fb46328291d1dcd669fbba9a5e525e32e0e0b617af1c65b54d435e7c3fcb66e7f9c515b880f37d205321427aa09a112414061ec07067e5e87b96bab379dd6dd73501ddeb0a8157942fa2bf2b8d79dae38f56778fdc0bf295d617f9445f9eb59cdfd29c016fc79f19296ace4e720283af955f0c244ef67fe623796e97ba1e5862050e754811fec465cff8e10a8993e5773d3aff7bd762ad55e7bcbfb9dfd7bbbb1fe8745ce8ea58e6c692e812641455badb57786b59eaf5880b9c1d460cefab127ad9844f4839f2bfa33e8cf449d2bf7994e3804810cb8ff0f0fe0a7049a44b67fdf67d08a6967e7c38d8401f8617041966514d7829c9d463013e416ca257250febcef0341d0c558fe7e404e9ce44f0c7411cc5f08baf8e50f0874d1cb5f0990c399cbd7e60f05e862cd9f0c74d1f377014874c110063f3ed615581cb99bba0f76c20bf2bc2da1bd094fe47993aa4325c5c3124e2a4cc52188e37449613902474a2aea872b292722706c51449c10070b873894618fca4b851be469b35324974742c20bf2b4d5f9ca13a2c8d356c74d0c7576002289064342fa5ae1556a1aca1ebbbb4b1912a1c9fe267bc4c1829b83f66d431b83fc433882cb6c8e7118ca64ffb31b1a080947e8ffba31bfe697adb6ba25c939e7cf4979a843505c6badf55ace626bf1c85d5937f50ee8021ce4b34e21fd2a809f1dc9e605303c4db7d79f2abcda5ecc610e0871ceaa00ca0db4b5d676e5c07a31b6360e14e85fb5757c3b39fbaf74c5d0621c42adb5d6103e37a6b5a12e0e358e28bb09354fdbd1d16cf62f9351a8282577a740931e5a17422b7129a46fa285b0eca626da04e47b269125e4fc79e29b9e444e4fc2f48d98196a705ec8c2a25ce0a0e1a25fb07ae8f2b696ce6a2de922bdbac18a560ea794c8e7e549145513440c5c648b96c812f26b1e526ade022e5768d5ab8621660bb4a8f075a1587969a251a2ee50611bc45461755a32b840f36e73a03ed0c5c9a7ce538d6c91003f901fd8e48b0d06ba38f140e1c345b6d8386c21bf9ff0e795b8a240912d8e58c81c4d9b4badb55619f5b798c31d5aef1e2f05bd56af3de38854191e649b8764bc70a3696d19c6c1508fb72b7b4332fc39c834d31101998e3af2d7f64e9ea58e6cb9a68af99ee9cfa942c98deacf3ae2c841fab8c3f7615bbd3d3033adad3586e24748e75b9bfd5a8d982ae6cb8860e5f91eac09e97c0fccf8f7d7318cddab3c9fe338cedadb94adadae076371da313d9bd8da115bad9ecd178784f403fbb8d6faf78baea8b556112cd93f7bc491c3e6e8fef800d1f66ab93157cffda21ff8cfbf46cc16e0cfbf5557b55c86e18cebb7f2f4b2796979d5b03c29f4e2f2eaeaa4900be33094c9aeae6454611414549e2194ec32e59897ed63f5e4190b87c0c9f3ad9bf941f864e3d8ae46e29a2deccff9d6d69c67edf53ed07e1fe87520ac7aded761d88f779d87b99fd88dc733e895a6965fdf7aae175b42fa1e972785e0582919240e601ad92f21da0f4ba407841916823855d87fd13018f5ed0a2e47cefa6198035a0b280e358066f03bd35c024d6262aff0cbcbcbcb2bb74c089727795c6dd4fd1e8009af3cc9eb72a3fe10cbc297795cff41e5feab12a3075b82c4a269f43d508afc7d08e5495e184285503fff4520e3307bef71810fc6c632fc193f0e64fc74f6793f6bfe7064fcf43b11ac73084a9717c7cb93bc3b1d3ed10f3c371f53531f5af6f4c0099f72bfc73555f48b4e1e577b5c1e579e2b2e47f53d5088014918255d6d6a681206890db344f47ca040d3a6c70a4880a1c10a12fc2507219562c9b261c458e7a1490ac90f4e8ae4599226eb059cc525005e8f16b2c028a1e1d683114976e63cd9d266abc987100c110dfc4b094ec00245c6cc52162d1ac832670839533600e921ab2b28cb8821365490609119e2081582e0833b1c6686eeead04d6982e1cd983234a8253534753514116aa3c30a0c6762c05244eb871f6cb09beb04c651c9a262b3b2ae781e0fcb5e1635c744ad69a18725b0bd93ab439c8724bc79dea2dcd85113e41665fb7e68dd89aae11a6e513184b869308e4aaeb99c3ee4727e51261a1585875c522c4a63b9a475f264c1092ff050e4842a208a90e5cc023cf0f045c64627cb0eb29c5dd38b36e5a65026b8ea618d5498206c90204b5aa504e64c0e61725092041eb2a457d496fb27f58a2ae279a2a2fa298d4a85dc4f6b5154723fa685b2306a299733a6a32f970bc25928b9e0fa0431e951075eb5d73fb8a08c8ee7254f892c2f71ec4f9e37255a50b24230cf9b922db93ce2b4429ce74d89162b205558f3bc290977aa68343286704e0afe583b5e114f15d45a285805461c39c81eaf4c24f6107943bac8020c4997947025a921ca0f1b7850dda082b8044b114aac1047182173c12a7a5043d611f2e3c02a22255952457e18aca2076dae92905fc7e60a49140face2c423c6c9870face2afa121c1058255c4f16ec28c4142e6e8400a9337647d1771d02a7bc81c424ec83a5671b699227303e9e23cc387ecbaca6d93c366863fd6d24f1ac20409d245a12f9ec2378b4c784ae9acc0378b64619d481356717c30bcf2bbbbbb5bfc7ec2400b83d5469af393cdffa2598afe81894f2416cd8e58b878e11ffb212c414aa97ff8b63db7d7b8bbf79af995958291dc5f6b38ccf596bb7b9f71776793e97b7f95c9929bcd9adb3668a6b59baa7177ef347da6c8ddddf61aec3277f7dabde6a8d5f4dd127277afb567b3aa2685bb7bafa9ad66acdd5beeeeed6a6ceee349aa6d50dc902631406d8d1d420088fcc81ad1502eca55c51851e14cd75592a5aead7b77d8b103891db433b5d1d446238a192c7975d9410f97958fd6e3577d45cb097ee52fc69b5a872b4bde44bd6a0a4580502fad9f2658424c2d281be630416d592e5eba64fa5bf78a52d9a6dc2b17404d595068b840536bb5f6d6f432bdc4b8baf038d328501a8d8287c9327306fb96579b6ec0fcf06a3ad8afd486f0341a6d87d90563e468997179936b0b3b1afb362bf603cc9bac2da2223146542012ea406acc1ca1da686ca09c2c4b6c5b4e69341acd86a7e1308d46b3c1a1a1c1a2c4960e7068b000cf503953054c4323058a14f45ca191024d37ad891ac9469db59a66ebbbc91095e9d6168d231354ce54399211e00c15343464366e48a3d16c5c4ae909b037c579c2e8f3f89ec26034edea3e615dc708e8f0517105c19e799d6e6bad3ee703aab3c59216518f6d8f326ec6e4fedaa006627996716366aa825f6e51b6b2509e37286432fe69e48da58d9b61de738f394f9c81df01337f9c58ce5aee0adf13cb17991361ef8936ee0cf0699e30ef71f93d6c2c218324924822cfe0667ca38d9bb9b77173799ffb8f76e20cefbd710637ce180ac1bee7bde84e4747fd062cd8a7a4678c952d3b33b0214296321ac2dc1a68c0e184d7e4c1973759a4aa7e90f3dda0e050b10679dea054650cf2bc411942e79b4562e8d8c8696248481f02971e2141043d739cab38690dd55126a842da54473412ed17ed6e6d7094f67ddc57d6b35a024a581211856135f2cdf76c82294c1aead74176ef7fc393867a94c134dda8c674a34efcbeeb1e7c11ba07471c56baeb5184eebfce1bbbef460ae74a9d15962cd5a0d1c82337f2cf72482b27f072fd164f40738b267684e5f4aae149267a84e5e4ba4302976588d033b7d1a61a3720c03d09e687341a2dcf11808e08cb39a96c9587e18863322824c9fdb5311e5a14801629b207b964f1c48c93dc2ff392fb7faa4dee9f49e5a672a3f446f6848a05c6a187f99c429ce7ed49d47d2ae2f9f0c449c8931e2c58272d38d2446a4eb6a46040d59c80410283c8573f97430d6278844130805161900a638240f243103f383378be38356198a70d4f1700f2b47989f1e19b5e6b7577ff5ac770d6fecf80ced93da1edf572cee1ee67f9fb92b6e28e72453ebbeacd5a6bbd6dedd0eeee76f739e79cb367cf9e4a476ee4ee2ef3ae2fab5cc7e3526b6badb55a7707359812d23ae79c47d36badb5d65a5ff86691f7bc6f6bad0e54e79cd77ed9596be79c9f091026fb89812168ad6da439a7b576cee9c5c039a7d2911bcd5a6badb53ad80e8bddaf97bb2f7323ea312853535353754a9d9a9a9a9a9aaab656d529766aca4ad514a787b6577bb98e3b0205d5242aaaf32e65a2d126cf121a43642605dd42b7d4f0c2f1f58155045c344680a90c1b074680f9d14cd6b0f901c502c16f059a456b3d6bad36c2a21f501a6855ee2e14cb663bd22d20a01081185a93fecca25bda684603dd92fbc10f73b07fee5aaeeb2e08ecd5824ca9158a38746add9c38652b00aa2b5aa10db72654f01686024391a64eb6b53c867e56b6d9bec5d6d645c98e14a6ccf0d5c47e8c8aedbffd91ad182bd9da0f2d8c277ddef440a74a9e1a485b6bad56c2f2bf47f6be3199cafdd5719422fb73866cbf36528a6c97ccc9f61b06c3566b2d9633d93e088d1466fb31ec47a0adb5d6eb2f6102666886b0735965a0a010fd233ace82ae42daa7962d6dcab628dba750f4482345090d11d6a71f444358e2fc9884b75fd6ce223bce0899640ad6304e58d64a4713b08d9bc12c3a9618a45f3872fdd4d7d41372c212cc7e1fcf24fc378c6151e456d442a4b296762884fbdc73633914255f2a3b9a209465cea6bb6bb750cf6c9d301b9ddba5b27e16cd2ea83c8dfcfdd53cecc554e1bf35a7077481205d3d9b59b93efdc4dc61176bd4652dd47d7d163349368b665299028b9c78c531ec9950cfe6d79a95ddfbe2a918dbda359deedeffa2a56cb5f6defbd55a6bab15e2388ebb1978f7782679df8d0151fe58ca7361c5097bd2e8c06449149b0e26a0101182c4ca8e94145b0bd9412273ea64b913654c9025283e6dea7c41e1863e3308b1e4137380012039c245cfad6a4a4b14e72427851a6a538228f3e4858f06515ae043844a1d3c559e95075c886386ce55d50d743c480a676a75c0703112857be8e084291f6c52b093664d5d81050b34ac19b21404535554b74586ec8fa36e0f069059a2a40f973c607c4c07040a47682c5c69e2c5737292fdb1147744922f4b8931437a2011030f5a5ab54d100e44a4e0d4c34a1e1fa2ee157f2c051a996988c07326c994141a6e3d47470a39ac81a384cf0a397459d259b5487244952c5053a2a4c123812878d23819b161091fcb030664981421a4c89a1b93630972d282aa3e5235da90280f4f0786d0010995a53a5288a8674020074d9f21564a86ac89fa9efcb1d40e2b40e552d641a63bac402bcab4d68e5c64eec7dc0d8a08713bb076e4f18fc84e0365b29e296d60242c65d45fc78f3368b0981903430d07b20c61e893fd6b11d98508224b192f6a92c8f142c240000ee1cd7b32b54bc6b80993a429062c575e90220fe8700493275b98a2be6aa62f3c79f8a55f50f3421f186cc8fdfe5a987e423138c50b564e1cf182927ca2ca903f2b33ecd39f2dacb8c154d14f6bb93f057d23b21630c3df4729f7ed58933ab0c51081c651b7db0d94584071df60b6987c961290fb8e4398e4e0a92663841731aae83246e87fd11f03ca53c1feec5a7bce19a5b368b6a0426349c3bebbbbfb84bd7d9818f6accabe3a5bfcdc0a838d313e3055d4e8a40350dd606a526bad55b9c2bacd084450b970fe2e581bc9849fb78133a780264c96f8125f9a28815d94b8458d04f4f36729c21731f61a35054c04df45a06f31f60e830164c3661028a6e40d83011b87204033ec1d4033ec03313c29451bf96c5609cbe955a391beeebb231573c5cfbd3f2309464e3868975cbdffbe7e0d124cb051c2fe036163d919f63fdf6219863d74902a087a16ac20e87d5072ba51f7f7b01272340056020cc6e77d6fc373f7d89358b08212ef839225be8e4332823e68c441c9a0d09330598f54cc15f5b915b9a6982a6af5b21df154b115de68a412d7b0d1c2cb3548bce146f54b982a6a4c151c2009c5a15a6b2dbcc1a757afee7d7d6aea3ebffa9c1f9b3972ec69ec5ff48c7d1563e3f7ac9d163ac9f3668455aeb99b684de91214d9cb542c813a80cb3317738e1ed5b3d88cc56ccc4e2b2d51575697524a4570f7d8777737adbbbb5b29971db394d6148bc5622258b5c9ad94e7f42a9ee44dfe3455b437b1109694468b817798d026f48ea9a28946699dd4016d6aaba658564d5aa2aeac6a6d6a8f6a03e47eaf3255b45b59b7eaa4035069a935d21cb3d51e95bb3d2bb79bc9ed6c727b9cdc6f27f5a8462abd4aee261dc57995d9a2c9932853f7534a9b2ada00533628222ca7191270f7fd1c10818dc671efd723a5167a6a1f167b2a964d9b352a558402d991296d168a33ec3215124b8873ceefa9088b4d3cc5ef673a97dd7249e010038ddf3f2367ee0913c1ca101e75e4f0276c041c3ac8f03978eafea6f57bfd340679402ab45a664a57a6fff589329e956999295a7289cb4c999281f22c33252a9799e264ffc6ed7b2b6dbab5bf40cfa9bbfb8650834b328a4ed11d5ad1b3dfe1dafda52f44d065738f24f4cc5170fbde7a6bdf68a4721291b9707840720966a763f7df776729eafcdbddb34512a60affd93467520736282d55d995b6341413c85544562e295511585758f42a7195f30beb81a2542b09371a69de5cc092fd715014cc16d666123c49461bf98b305578368095d0bfa44a409a660b8a8b50a94c5100913e5064c10abef741c9efbffb13fbb1ecbc5abbbb69d75a6b77d7172e76b436fe86756ddbf6da0db6c2068952d0282a896acfe8ec19ee1242542b0e4d30516fb0c849a6880c55e4478fc0d1a257ba507991a16c4f5886637c18a165412b521580b8b922eb05adb8002275b8c82a8e58c88f03ed0a22c2be61d1ca65512e5ddcaa3ce5fed95137bd9fa110702e73647f4a99e4c1d244d617947648f122ef5cc143233b8d9a2d4d138c0b2dd4f6f488dad3a60e549257932bf2e3c0168980902ee2a05d6a4f4ec81c778bbb787674d808b9e2f261e07befbfd1fbf9569aac44755df73a32c61dc6dc1791589ce4bdd77a4d04b54adba12b9720cccb4c532ea76d87ad30a9c96babdbc95e279760ad2416e73492c2f50c8f325a9c6f080338689d2bd2fbee6dd0ac8121fa28b0481c28b0c8efbba71c3c859f272067cb072f5547ba4ce9980109255439c06083172672b6c04e9218fa3051f2c38b040188ed0ad51e3a3fd821fbadb6f22ccf9b150bf966f595e7cdaaeb66b52387b305ed6cb952c77f781c8a31337e1d798a252ec16ccb1bb92bbc5529225ff7e7441d998a363cdf91bea12ba657b1ba93cfabedee765c9c22b06b43d51a273007219f97270f0b486725087602c555399d70ab684e564fed7a721bd410e9baaeeba4d832c7711c77b99b94accc3d911cc771dcb5a15e2b1e55d18b62c87e86803c6f527ae49be74d0a975c1ed9c21df3840f5896e8d01a0a539e1b6a53cb4d13216c34d2b1dcaef4089cb5a864edf814b564664c0400000208f3150000200c0a8703e2803016a792aaba0714800d6e883a72543298c8825190e2208a611808629021c000409031c010e5d4dc0d706260ff91457b5f01353193402f72bab5eb96235f5f397a294e112b7ac4b82985396245f84e0c24aa7e109a93b73c63d6b489fee112f7931643ce8c30a31377d1d37cda4748603df18c3b6247653ab958487a9173ecffd586fea4b6d412a877390f3a96d40f7a847cede324f69557ece127f5f96d9301d9fba4a83a3749dc7338c596ee5f2ce49e5262a6c093b33f7dc3ce808f4efb0889bda4c53f792f12f83143de4b10a4ed154e9c88fdd7cad33f4e42f691a3ffb800206326a15f9500b2080274cfeec312a9f7ebcca958bd8fe7695eddc725f44667b1f4e882207f3f707622f65f234ffb3889dcbf9c3811eb4f945fffa084fd49c7058dd28c276ed6025530e5e9fbf4a7f2096798ba161bddf88fc4557ab614f294b2f2b2f3ef4c3c15eaefde607116ea5501357f2f7aae2846669c96c345c185a29a5e3961214689ff5c35e13631ff2fbb8514458965bdf1d8b2f3b8308c1f38276f0d7b8b05cf9722c0ea8b5102681fe1169a704abb0104bbad057c6483658634b5b6be47b280f48685a2282ca179c57d2cb6d215b34469264b6ba87b0de6a7ba830e33ee2ca624ce9886e5d27d553df0c415eb92304d9b5bc62f4c444f07967e752a884ff55013221a454f4eff02da4aa9ba7c84370a4f996112868f3eda4671c004dd4fb7f69f272d25c214ce3d254001611877a5d9eeea29191994f42805f3c1eaca5d991e392105d2555e6479ecafaf302535071130ce619a59049bf1b6e4f6aef6f6da6a5942468acfa81e30b37052d5955966906e46504ecc2de1a0b1a0749db70ee129a645203ede094b64ef7e5a2321b3496cddc657b5221ebb1e49808a15c43c0312bc214799920bbb27aa906231adae80686041dd6e85cb8c0a04d39872fa33e6f8e8e9a691acfca024e1f9a78223e0eb119870a8ac3b5d7566e6e42bf7286871696b852a230b4d3b7b5663951de0a2283f79bb875139b8fce6919189c02523a9de9235dd02a39269afc5a58a1eb46f02dbd55ae30ebb3367bf5c78dcc217c98b8781963a8b59895fa556b79bbb8e734f48ab2bf5e12fb6ebf34d3de28d3fa53ffbd4089253ad94eb20d25e350887cb8e08c2c7785cd5fada830a2de069bdfde38cffbc7fff618bff057ffc5fa46afa3a9ae6bf198295d5cb0c63683410168ac14287d894195e8106468ddf256181092206e6e017e951178ff5691e9191633e31e6a18161172af2423cdf315a1d4b7c6922d331332079c2c04cd0154cb14943f3ee18988b50604869a570f987d469e92e8be3afe175d6f241df5d37694037a8b9ca764199567cf50ba0fcb55c2f7041586c1b41c0c218a4c2f0a7d276111a6070358eded57b22f90a43c5749ae44d6c508b9be3b011262207a5b039e1de50ada9b8ed35d8c39790db7206e4920fe9214c2c04603efe1ec5c6ba3b54dc7c3ca4d5d87d4d7053515a701d16dec6abcef9556812bc73de79c349883b04e66b01e7a16080b41ae985598c39e3f053fbd6dd30283d77f54ccf9910246215a3631ccb97199a1bdab1be00e8493ff491f6711c633acb037693873ab10708911fe71135dd1472542d2590eb7257bc5dfaa1d4c9a1cc447d525912a06c08f24392d90d648ea8b0dea3f424303278d842d5a8d2e734e1a4610f2c267a0a4257080d297db59f4b9f2cfc44f70138df5f3dd57010498f86cfc9b92eb4f398cb161e11333047502329648e4441636173301411498c9d31633d87fbef2e095e0ccde53b9b91641861502688d790116f5e656c483a859bbb6e8fe5c0099540b4bdd1499b71cc5a82147be4c9379300aec1b336a988800cae1da75f411c226cebebd9b5ab400be7ec19112e22fd4b47c7e91e4f932bacfedb775eeeaea29cf80a8e74a7567adfb2ee552165eda125b5058cb59091ad4c324f6035c6de88c1de8fa94d72080a41629319739e334e6d2d6ebbcfa8d5058bf727c0b9da34c24c30f0230c0b0d8eaab344b3892606778977e5feb0ffd6b4c500e8578c3ddbbb0eb1b6d3c881087b93103a7bf6772a5a66e96a920deddb0ab5a5fa0aa15184dd09dc4b7632ea029cb928a765c737a9b9d3d4b22151a896bd15283c28161039e3720aaeec1308f06b602b390f98532a3c18675545e0f7a95681bd0d2eb3088f8f4420730e5dbc0534b14dce2db93bc648f4dae2cc34ded484d230ab1666ec813264995cb802c24ddda0e081651158e5c6ee28492286508dbddc4e7dd9b7b0f5efefcf113995be1ab8ed9f89ed3ca03775a2211190624b15e3b08ec7d407a54b8695d6c9f8940d4a1c90c0aee91248aa53b14d6c8fe5d7bfc781ab359b29693a40689c71f565f602d5cc60a472bf099559c458bdfe4f7d223641471aae71030e2047c3d00ecb139162fdb66c9abfe19d4bf28f974e6cb841908abdfb42d4a1fd110ad2364411ce60529037fc6c18771b25d4d2e6e354b8561a25f55450964b587232b2128db198119ea2095159ac520a4c14f7212b14b3a1ea1c2262fb18fa5880d9f9971585543d9e1688dac03e4eb66687ce09f397a049426c7f844682ebb3096021e6542541a47ec3999473c463c5a6f2d92cdfcd04c87171e692808504fa1a5fc1b0f89674318a97e13e5bddae94ba3ed93db1651da17b7cecc691c6c1a9128411533e6aaecf69f93a820fa29a7270103145c128a114809765c8ffeda6b2bef4c1453d0ef9b7c0d4548a621013a87797c5676426a0f71c9f0db3e2540d4c730b8abbd97dc03dd2a02930a52a199f40ffff8470048013b64245e629b50b80018878e6effe673ea745c68336e7e202157c7826075b0080bd3874a24c61bec107f218e630743960773a53d676cae0dd7aad12d574c592883492618466180a6afd54045759f386bfb1ac802f8fd2d943478bee47568cace032656645299227b482d91561364095a124f4a83cc0bfae7bd60655768ca744d09fe8f9a9604ea9aa266757e3351c5ba1a1b655559ce7e34aadec251a4ba2c0476b9d4410c986a0f44100ff5b5eca05245afcc5f74cc3dfb28309fe2f164ce35c8d2fea4b497f098f83cc6bec0b459581be27db0a297516a498f6a82d3ce52633beaf8a5f739c9489fc8f733529a8c90fcc042d7bb2c38aff73f6439b5299d4ddc07d9ff94dea18b100095447ce46cbc1ba6c0084f2f09eac00fc807a81bc133ebbb96ab42f79107cc77fbff474d0104fd8564704cc6deb311d351bfb6232564028b8737997fbfb56449d0e984207b58d9347fab5daeac6dd87dc0e9d00057afe654990dcd482646609139915492230dbe39d6de53096f2a6118347633d85d3f26d79daeaa5d78ad596997d5bde0a25e918316799914ff6796ce01fe6f0a275f004edd4a241dc80af1ed34fc4c2561bfe867ac8ab8f4654ca9171c97dbaad7ea293ac4be6893b3ff25eab397956ec1627c07f0266051c74402b6b8e77977d680db5c6d371c9414d3ca47692f002ab27533fd4f210f601a38c0334bd1a803b615767bda68b36523fb2dd1d322285202360b99f6ffc2ffbaa79f403cc06c34a8a8fe22b5b03dbaaef150237026a1abb2aa6e12fd619d76636d5a5c982a5b0d4846059b8bde93c63a399d91eaac6b142f7de254233a886d46d1942bec80142b3a74851a366e40d0afd1524e4f8d2e8d8b7f247f22bb34d771b1f548be48e5baf06d8233895cd3757298a8c19d15fcdfe11cf996fd31eaf325c4c0c539c0a4a595bc941439923fca75991ccd77c0f7f012247d36962c55f5145a53fac608dd88397d51176d92ad534467f4285a13c0ef927eca7b2cd63c1e1f83eb2dabb2308efbd6fc2021b2c2a326fa4bbf7b5ec6d7f1db6430162d7cff8d5d076572f9d5a5d19e53e257540657d985efab09535477f9979870d2a4c6a3b2238c5fc3975bea87ec92808f02eac3e97f3965b3675c50a80684e9421377b1f13d20e555c403900d9d23fa9f980b4e80a96386d21b3c4c8761eaac75913acce754afa2036e9b309a1822ba3e814219229fada09d2cddca00f8116c2abd3a4eb71d60df75c16bbe2ad0ce24ca1420da8020b3ef8bdaca7a6208944c0de4878fea36375cc8b3b091775778f6bb9552e41bc2d33950059bf7a6d3955684262af3b59ca482bcc373718c0b0ff4794b67071f58ea784c207749aa69969a92dfe67061ae67e70d41f193ea35036c6a819e7bac0b1d497de70ec538b4b951be18c2097b169a46e2f68646bd55af3020445321ad404297115bdc8687cd1b48312234ddee4644c43ceb5676cf218b7775ce820042eb6738cdc0092127c9573d12021c5b239ebf423a4369cb37ce538a26d8e97e30a1d57136736a2c1ca3c988e90305ab881baa9fa11e1a3310e1ef92b8a81f3fb3b9023ceafdeefcaa6076e9b0019589638d0c00b9ccb6c6f037f0788ff3808044f1aedea9dd52e5d36c1eed304e59308d2c92c9c0e71a24081f23fd49e452afd583f73f4252447f4cd4d270b5983f5347c4113a35e8e25935031780a05a04bbc897b92f99047aeaf846565bce821137e6e9843267f189704a2ebe197f74c13856b80babe4456e3eb0bfe32b789b80eec042ee18ad9af05c10d0a51d31dc5a825812465952c457bf4bfea39972162261836c588f773815d8649cd1a4ee61b8011c5f2a258a997a1637b1ffff10c8f97c15645b8fa3383999edd4aaa9762afeac55e2d7aca666794deb1f96da447089d3a22069dcc4d286239755b2e97773400934f887c04c54e062c2c030b21045ddab9ab5a836272a6d032952865eeb07a4e61e84ad88f93213d7aacd2841e2c548aa0bd453b5018bff23caf2ba531505dbc4389de4dacc0a2a503fc152d4c5decf8d4a3294fb6b074dce12585d14b4b4474646c48db0e571e5600a233e7977765aa7adc8c9380d3b491911f1cd4d2b88c417d34f02cdb9d7c2b7eb1068f91c56dc51e56e0bf13c5dda27db00207903f9f4a7035bf6c08eb150a9c9c7e419678efbdeef0c79e1e0c536600c5f7fc1c426cd011cff77d199ce9aee8e0fcb8cf22393c98811ff284e07ddf41c36ef582f8303314bdd3c1ea91f08e06a005b48a23498a68b01537cf2771d51459d15cfccc7edf08e3a4e6a31957ea51ba1717fd3dffe3a28b2c11529cf386bed7aa2581ccbb5f155900f9fab6dd4c83b3bca7d0c30e21ed08c2ecd1309194ff02a0afb872371aed068a9178ac0633fa0bcb82145677b56203d425208f250776404a6f1c7b0b13ebd14c3ea5427e8bd3d9a6138c7152a19bc21fe6deee087c84fb7b9d962d8d3e467cd8897aeaa85380f4dc9a274efb50ef97f2f6a6be56a25b4cbfb17e61bcd7bd5ed8bce7e172b0cd0373881041a1119d5c9774ec4ceb4f2783e494ee2b4c89ee29794bca175dd603a1410d811b0cdad5715264c87a0fab6fd15c5a404deb9560c5bfc16eaf7ff0aedc2489d4ce11da09bd98e080517ed66b5d61a741b621e539a0977706fae7ca22f46b5782043eec65b9e05f01114111721865721e817e303a4bc7ac942ac72f2e384e582f8dfb3100630b35f435b06fdb1f4ae58491a4c8f99c58f3f4d5f6b93ee538d93671b3c1befc824f943fbdf056b13465b39fc1f032d2880bd6bc9dc708018b181211732a9a5c62ad70fe1628db9c9d7a7a3962f831605d2311ef627a801ba54cbfb288a396f30abd0dcdbe313ae52d45d8db49450c0cc0b9081ae93a11608962dfb1a0f05525e9628937eb0ddee1701cbb49ea6d0b1ab08fd9a9822e835b34af400d504c9e928c86c68da3066fe5584732f0412055d1cf256a63f14ea3be339c621876f7c80b10be7a078d26b2d6ebe5ad83f7df04e1cc8e2921b02583c2767620b55c66c98b7163ecde3a8adb874f77ef101341b4e3117623de8166aeeb81a2551988b5a20e206bbbb253dc55ddaa1349aeafe38e4e12d305d7aa8ac8102e621b2acf717669091d04d95e2e2687b6f1f6724b4b175460bf608bc5e18efe5e2c1a46eabaa5993d69444b42f11ae0702b0d0cfb5cca75cff19feafa13d426bcc614392d2244691af5526a0572b173911403937a15adc1e802aff7231859947050e48ab06bcd8dc88370ce78f43bb1cc1a8bfd8d66ac220544ea29f50d935d2e2f13a523130ddbdd20c9cd2457d50411a594333ab6f171b6fd1a6da081b1a1022ca590107d3d71f02ec1f128f7c6c80e6e4219363ef0340c1c01f1781138eb342899aa4a0a7bc79bc4179524a19b5910fdfc0e97f82340fc1449290664247a63a41b877fe80b9ad748d15d2ee0d68969b69ee7cbcfb989e96473c2b38f33b92a497f8373600c729e0f46f00945fd2e89ba1531a4963db7f3629dcc7f3abfef5fd9a6d4ffd4fd4e06f8ab1740f8cfab4d390e3fccf8efea50fea9d5095e8097e2f066beebf13d6fe2eef3521ead22fc487605109ad594956e4f7ac29ea8649644a24b56a4594bb8958bd68b19e320fc1f2332f33c544bf30b791998b412547500c1322062a5b7b85755ee23996b9d1cb64df4690e2b27fcda198758d64a9691c3d41d88f4c4b29412a2c79eaaea92dbbb19b88aab40670e176cf15f4430611286f66e00a399f694a965d43297121009e46b951bbb8884334af756771b775702b1c6db2567eaba538ad84decac4e4021953b3771eb32ed6e1fb888b492af55b8aac480f44f94028aa2246d09b77af9dd25f7ba58722d8b71a02c92b9fcc845d1fb5096edc932416d4ce73fe38e5ab1df440bd291e7f8e1da84b627922eabe4b4aa8540a995bf202fd2577764338abc89f522548b0b3d55b0bd8675c62194896225e3160504f1def1701954f67fb2dcd7ba4defb9b1e706b7cfa5267f546a62cb3c3c02216d1d3e7a63b4c604bd85c8b285698f643eb3f312f7f7796e6d0b185bc336ddae5aa45d0a3d66b2b9840b7d34c840f0a32c7bf733da87f0304adbf78445c61d476699f4a8f4165a0b0acbb6ad3970622528de8364a4e5b7c48c41eb452470bf72aba91de15ffad2b8e444dcc07594e94d90d55ba4c95a8c9db74eef8e8a5b764da7ebb8a910cc5955b93bb29a7ec2c7b34bc0d951b8f2475f8a33c6406b54db773e32774c1d2b7d2d4271c1581ba57c74f6d9f4d14899f1267884ada9c662e5195b8051c9a3a00505d09981d4947b892da7d42a9351c3de283e64d455956ed8fec1de09737293e790f9ac85846fd674be46d0560bf069359336283ab31494b922e58030ad4d2aa0fc751fde9c1c5afb91c2477145d44595ae1503cec8f6e2130816ee626ca53a5827fe4c49ce089e07f2c2d26d7d254ed6748c377c70169506ae8e6030bd04060f6201f307619290c67c71056d84a4ab7b07f80942c5ca85c43beb94a7f51dd03a4d13d24772c00868bb3b90c75b4daa61112a182aecc2ae4f63150074baf3b7c9aafc3507d845111644f0700718220a1028f708d4d947ffda1af51dc12a0b497359d95fc33d5b213fd623049973be0d3dc02256eaefe5fc4c946597417a0403e5017e54294342f0ad210c711c4097e15aa59a99fd56e26dd130945340ebe397ade5f1171ed7f10e86e734f2c60cf9fdf7de45e1b0c65b3ea8bb2e53ce8508546f2c32538065a7dc68851ae68e2ea2b20668adc945a403ad1d6a21ab2aba6ba8980e76a86b250b531db5fb4b6a40dae8cd585ca9eb2b88fdd95296e2b02ff5fee79f1f558aee4050aed2830e5588a1628e5fabae61e9097e6de01a211e911ee6f01d8acb6e1f9d30c65bab127cc3609c25d7ca25474de1ce796d9734e221a564aed581a8c5f37e9b3608afc6608053a077ba96a59bb5d0021aabac3a2457a741a88d9e0e5ac9af6b297c3e90ad1031a17bf44eea3a040548359b230c4067364969e88e0c284d60d470810a422290279008237a2d337ef74d99d098fce2ef3c04c2e589c056fd6abfbeda44242399835e8cbf0b4d3742337c542f289ddf4f93c4e6b6b9f25fc59be0f9d2c5ac6ed7aca79ffa9f5f04d3fde83b72807b63700fa7f17bbe835078edec3724df0e3c2998b6a3ee8c9323529b4cfabc9b47c288bc1585933152cc3196273747b9ce6408f43ce3e91352ddaca186e7955d2ed0afa0c443e15a888c3d032d627e6b8078aac7777ccdd55248452b9c9f50b5b03bbccc3cd02cc2deacf20929b235e11c27e6562d4b9d8393140e837a06916caf876c464a44c6a43f3a506b5e18ded26995dc95483d60ac94a87c1196d7644e3079dfe3d927a3512ca3fd70a5b2d292a70552cc5b8d4111dada812e9c205fc13467e0e9961084e10bbb16328113e2e519c68dc9c3e5bd3c45d5e4da7a80f6ad432be1486ca5af16522e4876483b65b57a4cf7a93320d9fcc512015c5d89386018a4f66e6328c17918e09ade1be41b10b47eef91759db823609a6e92ccd37e7b95591215b4b17101546cb63cabdbff11e7786d3210c763c2efb80145b0765463f46807bc1612d8a99a8755b4fb54b26bc70323631570cbfc9aec314fed8f55f4263db481f3ab79349b8a94068b821e27f2c762a8e61a693f1b101b417726ea68bb218e66eb6c2c106d382e58c7e78f30167e96e5029388232956815d44797f19eb690bb07932721751a41ea49e9391561f0f2368742964d7d0d5144b3a6b3a7efce558865ec294b57e1f8009c4b0c9e27847bce12f763300c60ee428ebba9727921edd9958c2edfcb54c51d010b25779ec3226c352267ea47c460636ffcd8d62ce21b08eca8603d179b50c6d3b021f28934497f8cdc6a9734a2bb1771e99ffa270d499738f4794ae1b301d680f669eb4dc7b18d9db3987e7b6b2d24838aa84db0b0ef488f724249d2c1f2087c1eff68b69349909ae74a1f0ac010b0b002dfcd5550dca050873620c2faf1193a8983d4151bc08886a1b776f3bd4d18e451b6e8863847d95cce003f3ba8df3d933fb9743fe02a69e0f2d171d530c0404f0c9ca3d44646708255cbcad64e0ab3c1d822121735b2a87ffa17e29d18b37cc3a226af691bee67235d981802e536077c87c573f1db45e0509140e9d1f62dcadc364f01798e484f555f86abda2c29704072943e9c212f7d0929462bacfbd4b2cc2ee37508c0615490ef8f408e705f3de00d2206c7b7aa815edd6c58ac5c2e564063049c1f82fd9a9553a07c7be444c030f445fc701c33e5b594408b7ee3e7da152baac3d04f13a3f9026dbaac3576541b185998c67a7e8f594f7d39ae0e94bcd6dd0f7721f88f3ccfc5083409b058c92c3984b5be2b408801574322666288a34ae269e104e3f8cf555ec08271b1bd5b35a27019b13c4cf8d4f361063989c1934c07e5d9a70de5393c6e408e62a9e0b0225eaba0ad49149b3e9a50668b408f7156568e4446994cac90fbdcce2b0c35759709644eec8526f3f0d2d0351f4c640b319379a5dbca78ecda153ad7f2047b3ac1f3cd9d8985fc71e1433839462fd7fee7ba34f04c3ad35ef71207bfe3396c67bf28a876980441a7b906980a6cf29eb0ed23041d0b64ff51dc543d44ba34c5ee73c858792315c542d8a55887234c594d35e341a21c85e5d34d6a629528852c3e2e50b05008dbb44f39394898b161dc72a6dd5ef020817cb9ecf811d1e743ee521f9cdaab7c8ac822eeff5df003e19e302744b79fa3d7d4f3fc11a186c2b6e79c1de282249b28f259e0f8481457836d8e3770625fabfcf4cf394f8ead59d01d7042faf3c80a840fbabf65f7dc81350fa9d8fa3ddc517c5bf8c0caf98054a54a7b85da70a14e4c10f7103834a19d9694963d9427e004788b1b344f0142dc54b95ffc7dbd304eb0184386cd80d5a468bf27c8b2d846ae5e7eb2d9f5802b94586cba55dc40e00266430c55435b8ad150464c5e0878f059b5d7919bc1e94354b62d4c5acaf5f36cbbf49064846e19c1161aa2b88d10374db65dde4e0da061f14eac6b1a6eeb3aaee45cdf9404f21e29d84bc55ac26d86115f37173ecf0534a26bcd89b5862f4882fcd12b4e2f21b0cf59b1b8237645ef8684163f8971d5ea20402629cd2b55488619ae541b9ef401106e1146d9076af9e00baf4a503319acb542d660a49d99631e58486845bc66fa585e5046f81713130b63dfadce514364abc255a71e9362402ff8b73ea0af2b2af4591d245fd77583939b2e094957108108a1e47c8d314043c0d68aff62e50d578141942d6a089b566eccbff7a36083651c792bf7d6b5e10533b9dd64e83aef1e24021944c2a4b4379dd6960695c3f2fa0025564d243b611024615a2069d68d3bb6239650debe0773597002508f7e3e69358832f4784b99ad67699768ff32c3461216f8c11e13c28104903791967cd7c41cd36a4b307388135f19ecd68630b7ae5fc1a048897ca885fe1a313fe4de14f3a67050a6b6c213dd236ea401b67279f2edbb509a106a018e4d610a0015c8ce9b10a7b87bd88fb0fd8c9ce1b6edcdbf7779c13b6332758f7f62c0e8b8645ca84e0e4779cf11b47c90ecd8c1864669e35a8b4951a87f8088c14d46d0a8a61a736b676bc7d9ff39691168fbf4bdb2d76ed900d66b6f085583a9db7eaffa83f9a858ef53897a4e98fb0274f107a1151a3c36910002dd324ea9c0929542f1af2f16779c9d1b957164db25e0163ce2c6008cd3ffb1c39a60eac7812caeccd2262f5a01af84674eb246c05356587c51e0c917b6fda2378c57a38366fe34acd711c9484090e3dc4e62b02d2c506a86c1ea371e5059431684849245a634663d7e2916d5cb18c196be35620fef886ce8aba3a8c5bc68136668216d4236dbe9d357cea77e1412e1bdc069003127afb2436908c96cad7f64b02a435b32b9c5092666942b3a190f4ed623599f30646169d219b1c0ba3303311a99ec740991b359c29bbe4ced9da9611d6be4335418e597c0f460d0ebb688e1cd80eaca8e19d05485308b5403b4f01f2e14894e444c558842deac5d014cf2f363e28d18fd82b1fd19081634e7ce84332ad0a650624812ab776968d3f2eafa0c74ba55a82cdc105294b994ea55029604f9d6a7c7835ecb650a9be61cd184bf97a051c894295aaf0e96074f7733ae4bca8b11b6a3f95beb5f8f4aa40a3c356acb66fe38f8f9d50e411656f1dd8ca9bd8da8043ef486cf31ae1ce6fd092c0f5161e2446b84773a07902575ddcb2f58b0e509cc7ecdef102d52bc3d1cf0035c626ec9bfd17d50f653e22509aa0edb5ccb7382140f624d0b98481cffab2bdd8b38c37bed88c54d91fcd63607944d9762e303df4ccab23765ade1930abbbdb911c1c6fed43cb22a541a7e2bb7c27f30ef96e440548880278398c9fd11c2a24ad2301309fc4d15e2c699b67f9ae75a834c371ad7abc88adea2e2b3929326e34f46a72f8bc34a72eef20db44b0a37ad8f4f41396be483cfb7c91d80a1feec66d11b878a4e98b90e8846f30d43f384e1df10190947d3cf57c66c00f613cd303f20c6968a4ce8ad4edd159b8b544477da2117ccc0ce2c16686404491a1c0ce065e00e27c0e43424b32c3e4c2e128ab69b53b309f4e72cc4616bbd76da5a3f78ea99e0811e0447b4b228dcbfbea3ee47e78be9fa2d958845c8da27cba46b67f94d6e2763759ea54ac94c06ba27b16ab6d24be11583a8a9efa0a4a0343a2d3b307a713460791db00827c6874107153271c42f5e05938636b4814ac0c7d008a304ca11a7fb6108f4f37e3863fb69b3a90e39e2679fe6f009a49ffe19617ec4457675b27d11a2f1bc071cb0ad81a14bd3130164a89a063fb818f2fcf218a66f2a1390f7ed5d05f275391213076274bf8b273ae67f1b47f72675c4fc57ac04cde9b6fe06ba5b5651bbccd5628eda10f262dac0e8345fe143bbfc557c4c7c03e6ef4a8875481bc6587b4d99943b0b65ebc9c222a18e809e17ca7785f67122b2b28774057308bd1eaa8052acdc4a954a9d389d488dec20f29fc5459901087a507b015d3ba534aa69551a96ca675cccfe2f95e4714dcdd864b676e41939beaa826c5338dfd55999184a52f7b3d48d10f546b72657c61b660448077e92ee72646f3a33f2aaa5b07ca8b80ef8ee6f6cc630f58cd420c38aa721f83973d19130a01d65d796ea8844ee45482e96804b10ab2049a83065fa8545e9f60a0a120c494b6d0d9829595ab1b0d5b6355c8a534f3333a40a81c48c33439279a830684dc2ccebdd80381d57d35907515735d13c4025b9d807eadec8170fdcc12407a58a14102e6babb6da44527a4f83d6a2c60a2dcced62254b80fec2200b48e6b136edca9102bcb75782b72f750d100179facc9d89ff869bb4616876c5d02c12c0798050c821665d23a6094266a1310411072b90ed2a9c74dfad18d44db88fec2b81859c2698e6d8ff0ae08a2703494ee48a672862b2af3e2c5a9a478c8978aa5746fffee24e3b495edd86f49fbee27e190e32eaebfb9fa20914d5963448dfb0ed75e5954039cdfda3f2d777f14face466d2a52bda32238862e830e00726e46f9a922e09c47ed18c9ac42db1ac1917ce5000886f53da6a09b9b49212f050543da6e73814213f53207b3a8a2f827e67b9d841fe64f7878f2d4b84cde1a7aae5b83612605bec0b9a9a5d7b4c258a560337a7e2b6c66b64b3b8fd997cff4b7c585c3dd114554479171838b87ebc2a0c2abdb5fb99b9ec720c27198a26dffcee1cb3212b63763332ed2d8bd485333138a36e27570c7a0d4c247e1ea8ffe0f72696d00bff2c9a9799781a9c060c22753c1ced45d4970bbfcf93fb36771e5f67bc557c0aed8151015b64904189d5132361f84387f6b9fe3f11b8758e4cd19f0182fe352f91af0ecc955cf727d71e3d5c1233c742634be5a756b0db1361735a815640a8d34872914511d28660514a19fd226aa727dae1ccc36a4e632a337d123455d2242ddfc9ce4272c9aa5b26a16652558855558685665912c8445586b5665d5ac9555b0082b3959c9f6f3a0e891083a50fd3058cf94756b55b9eeb858fd8088183b337a020620fc80b6bf1617fb59462bfcae40120d66f48ffbd7db68794af9005306874c041f556de61a31133cd4a2edd5a2e369f2e70b283d92780b523cbb476ac28301c31e4dad30a706452369c70ca455bcee55cd9cab3709d969c8e4d4947f2a7d4f9c37918afdd3ee9abd2dea98268ba0a2d164a1432a4f1b1523937cedbd6ca26a414db7e857da819cab69d849d349676227350b9730d51bce649e55add7e7531e08f087fa59a39415f32e8a680e7e05aea4bbf55969d0dfb5d80e2b95e28668cc84a522c523ac81632a1680898168ef664a1150c7e3e3a07a5d1310e0a62a4d95fd781a67079794facc8377fab8a1057f5ed7e8033255388a595df426ac8f0d20ec1960340b98a3fe1fe4e9bdf999194f0320d82a82f93e52a689cddceac55b0464526d47c199cf1290802177eeff399323fe3660a507b8c110818635a162115bdb3f0750f1b04b74877b57b25b76902f05d6b44b13790b718b3e02839709b014341b14faa859c1e2a68073cf0ac772e24c385c2c846468d4e9ea9e78cd74028f3c5470c415004d1614069d8546eb56db0c549b5d1b8cd8e2bd3137c6cc82c8e748b4e942aa5f4dea2d93fb507601e7ba29605040da08a4bd2c7f7f1d99d230d18e375aa1bc8dc014029826f01f11f8971eab3d2b43c468ee67fbbe4634601348e813357ded76c3edd87da05c8400d63424d83dd190e0a085300cb9fd856812d2e33ba30f9d8ad06c40115ab22259cec048904f0b125988e574a0c6de06cda6595e864bc0c68836a3aa81bc4220c3c9d2bce17b64a9da6e3231b81e9e069f4741e304e6010bf4210c00d74adffdb43dc0c5e3a04d49a8000dc8a1d12db83a25423c27cdaf74920b57946ba092e931d1683ca2609fb5ffb641ec17a6a353dceaa78549a1d8058fc56e383b8068dddd4d20a6a351b3fe072288bf12566bcc86976e1e3519a9496e29a526a3bfeecf3c84821244600ec8d76f04f06329d62489948f20722494dec29a1bd4aeeeb34550d91717fc2014fb1804222e95f7892d7e3b36c1da9c3c95841460d0e0319bf9f8d8dc737724e8e241d848dcca03fda06f84135539f33928490aa7efcd4ba2a3d456c314c039a759c38c019c739cfdf17b31f4f3f901712a871cda2229ef2406d7ee6569bdabc1a7edf4f80e88c138e6b9f34f08afda467bd780ab8f00a95cb42dcb54c6993b08cfdc956d0dcc0f46e426773042c45fbc0f222a89aaeb9f729f360b2d8f5a7f00a15b31d2ecc6167c3bf2710032e2c486bd516bd6fdf66d8e175f8255dc29ebceef1e2f0b4f6f5d63b3ebcda02596be5260e31ded6a6ec2c1d288a74250b12fb90fd3fb137c779484eb7268af1afe045bc6a7f0c529eb505182786a2e44a7c608099513b5418364e9418bc87ddd4d7cf4c225c119b14210d9baa5bae677848136941be63a9c7021478a0a0d7b427745717262a922c60124a6ae045262b0d9570c96e46c62a04b9736c865621a1773ed5b43101a3c1ff00974630268524d185116e52248702969dfe20579c4a5f6300c6e4f74e247b7cd9e241815585a05653c10fda5465ab362c59ab9e26fd5e2a00b3a20abce27f41b2994894e69cf0931bc8cf5cb35f55bd189b211d6d5bcd9c7c1e57c0ed6968e36ee1b36ca4179abeac3d2a30c2407302592e472bdda290bb6074b39ac6ec0253e460ce9e3e939041ba1572c71a7487b699720efb0bae8b945a86327dea1dc8ce912735b71ea6aed1f18d5c50711e464fd17ac92ec738c969d87ae6a8a2ec46ca7961e000c855b34584e81e5463af3f4ecb6328e9617b08502839d8b92c080d87b6ce602b0994aacb5f5b11691dfaab00226dcba927132ae824429fd95c34ed013da54f4c6b42642db3e446ec946f8d1b12d2e6c00ea460a650f8e5a124fddbe54a415af7b77d66b01720f15d332546cd58bca89999359e95f31b28e14633cdd4305f5a565dd513363695726aeb59fb6d8c1b65dd94958df032db9f52f1a93fdc0bb28dae400298d27b398885ad9a51b5d629b4344508e05ae24a0b84ceeef2c90ad5550e59b00d3ddb9372dd2b8bce06cb056f62d283b3f9867faa0ccd56b1dc93bfa13f68d630201b9e2f7c740a2985b8b4fbc85caf6f99b00cef2f51b43685c5b4f5f7981b809f627f84b2cd5292de93a40be40f077505e0036c13d353e1dbb42bd042bf9985db89552f6644e724c6ee692c37375f4a24168d46ae71432a9eacd5f09a2d3b873af465e316c2341adf5a862a5da4a31133010971ab1efd5520fa7e1a0017e7cbcbb41a206436fcd3f789e3628d96c72dcb0246fffb65e3d8c8817538d403f84fee7871a6bc2f9b0f0d164f60e97d3da993654e2882ed35b76d7b1da6384d36b1f0a685ca9e69bb7d32e287aa6df96a7058fa846a1ad293c8a5db204bd76566ea358260a9d9627203e0c625701b75ff4f15422e2254c7da2fc6e94247a3bc7b05660f41dfe23a39468cb513bd83d4b31ef9da9d6c51f4d25d9a67b5f4cdb82f7493feb6bd10c540df3eb119304bdc5b16ddf6fd49d165cd2f945557ee93f4bd4231407a71d7c94f41d1bcf02dc371478b5ffa0b878a43834cf1d7fe148b783b4b0b06baac24b873af98d9747921fe0e944900f3e5060cb8b1ffd0d126aad74bd19601995f73012b0a8fd6c095190d21eb99f22e05cf396a6169af5faf5f503613a1191a90cde5a1d5eb31d74938b3cadb2c598d9d62098d9037af00319f3aaa5d724c8494c980def30a1b03b34030f13a818b87c3080f9366e98eeae094c475fb58cfdc7b5b05d3998e69ad369f9a3be1f9948431299d590d9802e50e52ea3f39074da5cabf27c87a473e7fc41cfc0a0658c059dc033b4f7c5147518325b1160b6013b710cd0195c0cb7024e082b882d812d409f538d9a826d24c5123c36528afbe35b5a4b7291caaf97886d60d7309bab5060bce3b18211c1414a2fc5343f4b24024ba545b1c05b15b72df389d98fc6e3b311002546ca9ff49bd534dc74ba3b07dc73187beeb8f34a49ef0a86c984e67ad53a0805bb89f9355c6cf0633ac7e44e4504dbf2a2be1a715eadbbf5db2511a28cb34d347095e23f85302c36f1ffa3dfa17e428ff49f6c6b9a9d2fe5eef7ce23697930e21939f58613128efce3fff14775c78d14e599901365df12e866e580d5966933d9042d4023870c66aa6439a71364f870889d1cedfa0fb435787d40a0b42c59ce70dc487de167feda34ebf795d6e28099f1caa5a4d46ac735a46f2a40e720386cdc64dde45c508fb06075867f3f443cb0a34e05a97b92805bd5d216e4cfbe9f877437d6c3cc83fbaa0f39a4b42776da9f2c1197c323a30d56e9efb0f4a651a90dc773a6e0b68a87b31ad347ce64e1adda2d54564de07955b8dac56bdbec7d2c00e69e01808699eb37e20bdff9374a433f72c6310bc906628a7f55a15281c79e92858610547bae175b4edfa5bec9e0e9496fd639dfa55a8bcdd3b31edb734e17b46b2b1019308cf11f7210c0d6a057ad2502c4bbf84979ecc3676a8796006e5e2226792613ad16c4198f8e490e7db63cd715775f470f32f4c3fdcee4d7e1483916048a489af240802fca246197076069886c3007e86ea18a684d60078939631148a483b29ff60bee085cdf1f837dd7607f54b3a7b6bcfd945b27231831f078f55167b83c05dc50532a0518c598d8c074f5407086a7a5296f292291555eae7f944fe816d4180db56f3c640cf901890735e81be51f6af43e1ea725089b1953049fc4860d970197b4a5968120aa5ede49b432e9e782e9220972fb13caba22a0efa66e4e2fb92a537fe4c1d20b5067b868377cc4a3ffb1a739e67aa4c5c7e5846e4610f4de5cc703b425813cb706ca16789115473b2b3f418a116f5b3e089accd8ed7bb80609378dff2866983f887d9662c8aed5cc359b4d53d5e0cdbd475453d02a1430bc71dce10926368498b136b7d3eed49ff1a9307ba1b34a552c17faca45fd6ce3e8245e023cd4d9e44c789be7895ee88ac38a196c0deb35b24f16e75ea46785f4137d3a49a69f83ece72f0458b1a322e86342bd6ec13328ad9854ed11d1189c6d3537c638db48047bdc6b49e3915b41d9e4b0f417c35bd6061acb3191cb07b96d9a3a4175ac2d367463b755cb69588194a45f10110e8a28d1dc1acb4590daa651df53ee7fd94c5f744684800e29160c8a15c712897d473fdf3868aea719c4334387d60da3624cb2b0000be220cc9b921af1a398d8087fe89c500ea4310d94dab04132dd11044e91180042aa98c8ef666c58bb8e30612301ef14424b00d0243a4a1b3af5755eb51c77731f0e0eeea3a29962777f4e14535f7a1a7db917883773b769d12a67dc7f5a082968d6ec8c3ccabf3e1e5e6c72d6d6de95383c643f3b03fe3f3d1b3fdff1e507f24fc53928f73984d3c64176a6fed794534cda6a2477a4953daad7a03b0bd388fccedd554708716091e22b625cfd358511f79c734047ffb3c5d85409301536617427d2c9fe284de94525a8e214ff0e09c9c42853ff38eebce5ca6d660c7f59e4282cfe507084b7f165a8ee96937fe139c13896c1f207bdd8e981d6b10ac191ee37fe26bccf5b9601894a24f1fcfdf851ab670bbf690540c3c483710897bfa16f1974de8c624bb650dbc443164de8e333d62afd001550a2edca75dc50c1095f7109dfac5612618b06422d39b5b37f71e8bf67af784f6154221b4b389857292214ce13c68888c42427a06559328018d7ba726ccb6a1ea3e8692bf164559d77423e78e12a311e5f6c2e2542fa9e45bf04c9670125964681b741791e881aeb16c2d4644d2c65c105ed2e4c5128d455841de464fd072134c7bdcc91beb0a9c9f1e48133712117d6b3ab02a63340c01fb14a47401a8a15a8aa0a286527a34eb9d52880296385114da50c5116994021a80176b023686943fa827325d177ab001383fe8d99801f278acd5f022ca48157fb6e4c2376c0bf7a7c91282cbcf62247029dd9d742cf3937193ab474e65d13fac34bd6fee7dd5322840f00e6b0f18e7f889807668aa78e68bfc2e776cd2e6ded48510d88128a9502fe2020f677164058214d30908634db3b07adeed1b0004c3d9ddeea1e05c98dae9a272f8450960ac2cd6600cd226d63744d2032aee2c8fed717ba313be245405d5b1bffce4bfb8d2998a0c3529c368933f0af1bc9a8abf6a9e350c3994621591e34383ceae760502151e5c4a6eed8e04f5c3a67d7ac7d2c1d703db137867a7ce908f795ae810ae7e55b79f289db12cfe5119853a5427e2156a07163c582505cfa024879ea0866e388cda5a0b2ed22229dc419cf0675bd3c8716b761f57c45c90665d6e5163a3da771ea99a0464337e649caf0a89b060dd866033f0e84370ce1ce307b0ffe811a7263b0da653264a6d87a8de247a1782e8dad6eafe8261beb112257dac393970d0a2a97c5dfab939e2c43f0776bdf6e43bad90ff7cd188f42571ce4f54e04321def431c1631bd77ec3e31061083179d750321ef0221468a6df6ad20e2587bfdf8c7ea2f13e82065c30e2131cd32a1f98773f0cd06f6d28e1f27e3b37b924115e86696066425402d2383dfbdf110274360cebcd6bd804e107dd54ba9dbdfce209637eba6c0ff0b47f68c48906baaaf1cea9efa819b0a5f4caa1eb2e4ab3fdfb6a5e945fb9b5bd852de0d305495c8a2eacfee5981d1a589891cab2865a3961811ed9331165c579e26c1ac2edf1464b63ee34fca824fc44659423482f2eb454293bfeb270dd5bd0054eb27e8fb6257879421174947ebae70426d9d4d7f16906216bff4ed5d69045f40c0ac059d35714c57a6847c4505c020499d7e99b2af48b60b4bbbbb7f68518fa631b01632392e079964ff95c59f2b52eff8478c073e9fd8ff542344172fb9c4a7338b2c4bf0a4543f6c0683f6e71a3bd1751c51069eb301f8a7be5f8c4c498344b9683e3f04b9145f285a180287fd1e9a7717b671cebb2dcd547f3c4e5c47151a6b2f9c540cdbbba991c0890027aa96270c82fcf901a66a33b76e131fdd9c37cbe35d8cd8a97f16a059f8cffd68851edc82661673d951f26150970d71f6bafc6dbf5134bddc4974d5055432435d494ce93f9783be480e7fcef2ed455eb2daf491489a54da84ed55227cf43c512062fa6b8d94bd41557f053c6b5c2c2cbc77c8850ed691f103019793d97ae2374c4230af2d19b80412c3cdbc19f3c1de91f254cce6fd881580d715352824949a91cc6264410a5145da6b738e0863b6d04838668b425b72e11382a207281acc75d0130ca7c04158e5df41bd42cc42f318a87033a9ce491f40926fba1c98b3ffebb564a10acb14ac6cf8ed0502b627fd4e5f3204a0f1678543dad9d70378ef98591dccb0a420b6d798c99d1acca4d7f77101533c5052858aee07c77d33582cd193401b15cc8aead73f90cf9863b2715fc292a134372f38906deb69bea2d588af36c13e2bd5594d18ed78c87fbb4f94f1af3e832d5342bb4eb584308dbbe412eef14921deb821acda3d9d7a03324118583b0b0dab45a0b1d214473c1684a9e5fcb2ce57701f4af09cce560b6499c94af4c614f8541ff50309081f575c4404a2444bd4b1881ff46a09b805f2b145821a227c10fe75dbd9db94112d70cb3e14d6c854d261499e18908477d99b7af1a55da726ef8951f9090cc5947c989c80a31a231840226cc0827f2996ab29aa22f59fc73ceea11eed2cf1101f8782b56c4d013b408c41eebcdd7ec81601a8d951d63fe2bbf59cda994004144cc23a984d28b8cef7cfed3c7751ce32d6ca48b95ce9f1196feaeacc19b915ab5f8b960c45ecf6dd0e58837b80263d78a6ab2aa00bef5cbc809e1fb4278a13894764d4a2dc8ac8459d259baff7e8403d01355b9d4f616afc9ce3813fe3ea9391a288e9752b8dfe92215118cae223dbfa6e935cd4ca6e836628eecd5ea9c24706fb082399becb88409d7c172ede8e5074e5cfa78ab9fa7c6707f7db6c69d8e7815573805ac21bd0a8743dd0f007bde6e7fab7f8a4685a7caba5f603dab0db13b4035344aa340e914091c185f500779c22efed705cb93202fe5cca5605e68d16ee750bfe8777c7ff098f9b778270ce008467fb7058d520c7a433afac95f739d1e307c110a7fdf19d1a0ba8ac9420edbebc9fdf4060e5d18125f57158d912f9a0d6e914642f044bb8299868be9de3df04d14430416d307041bf24b5072252f08fc8d0f45dd7010a7ae09f8f23f3e2affe39f3c44332914dbf1e8bea7d4a4d6dbcc792e3b220a17fdf39aedd750b71383aae5856c52a9018432cd15559a880d93e12903436b69cd1af00a7ed57e0f3f19522cb6f5636775fee4a1680a32632e1a750bfe9543275dbbfdbbae0568e42f448e030375c740af046ea408f7bcb82852ee77c21ad914edd38e729bd013ce1c3a4773f4b8af016ec37753ec253f9936d59eb28a900739e9a639425c8b011bb0ce0c9a0199a6845e014ebfdef6dcac4852c920f3a7f3b6a20aea23fa1d29aa53bcf9a69d475f79f08a115898badd78a224efc19183f792f60e75ac0ff7961ea7f6aba874719b555c6054ec381279be809147cef8839da7684fbc065a9f61607b20cad8ce14587608fec75d5e0b82b6fa131f4c861bf896ba900dc55c8a137985cc229d8f199a9be3a725197de1bcd1158f8b0fc4ec03b551ac902cf8ae3e4e25063abedc2a9cf863922e45586d9c3d6658d1b296e186b74e76eaf3a85dab982e870f266c23f7a3f22c2aabc49e3f3bf1fd33c2bebf10db76f3ecca3552d4b3e77a9720bffdeeed4928fe3e7cf8f9f7f9f90a46f17c2b391ce3e34b11fa1ceec4e781a62f1c3b093bf96b18e911ae083c2715d915c16d329375ab44f4d3778e6c24d0edf87daa1f20ca1becd01fceb7ac91fc09af4cbfc076f8e0ce7b42898c515031716e8a5d35670408b740dc29654f3446ee0bf197dde4a9303d6a78ba3b783eb8a0e87d10487a8ac379baaeaeb194f26636c4ea70ea37686aa376c1b0918b581682382b39b26082a329020c0c6635e1d2c0d7c80c057b400fa9b6dc86ad127b5277f26da39651a25096427f572ffa5bb1ff3f52d3016378d916ef935ea52a98453b53d9972d2051d5c04988cb08b42c3e649c1cd7d1c10f7f5e79efcb4f6b69ec02cf8a21fc7f8bfdc3c9910f96ea41442091056f5c5ac1f4951bc0b2ad2fc80565f14d262916a1c58d79087d55abf61b9ac9b0435965695f20995efbf450317d042859bf21b840e9e522a20035dca400b5abbc90c59064a8e688b54469affa062899d7ab67c68154ff8f406b38622c33312a1ffe0d77d99009db6240469d5164b7e65956dc22564e89fb88cf4cb1cd282a05f13f3523fa35b06ee879b6b898c4284f9144e862ce238eb9162ac26124c133dbf1a8fb22b97566d758f3e214299c6e2d7dd4a38d3c311f06bf2333d31b61be386dbcb3c03f3e524ad76e7bfb22be1bf56f19d77cb0e5a0d79f37bb460329ad4e66fcaf8bec80b973eb28c3d569cc518594c6bf7c2d272801bc72bf1d1208b02145313c64970a019cd27d999fca967c7aa7711e1c71f6530642cacaa06085982e919a06fb1af2bbc335b25262db643c595384a87c4ee2cef5e5b8d04fde0dd3262b347f63eec0ba4c00ffe75558a01bd1eafb40eaa8fb5e76f1bbb682bdcde41f581df5079b073aed5be5cec3166503ca682c4b29174111aab6c0b7e4a7ade59315cbce7a83881466f7adb76a1b2e8dc3755442287b9082e555b2e267595e56830990e4bf41a657d074b5918faa805ddbdb7108424eda1631d2dddf337f041fd65261170c3aea291e72c0c9583f4775ac233e2342ba893f5ba4315e03876a0b360f35da77545ddfc0eaf5ba9ddfb08b2f71b16aa6dd8f4185b73e8bb82946ccb7512e0202d4fc8380c065fea9da78907ba4abf92beef83987735d3a6b9b4f38f19c831c1a134c054aa57d350ec2e6a799d8e82144e386c898db017cb2caf7bbdbdf6015ed00ad80b8e665180cd50efa5b1932c8334d76284c63079a4082179bb40053628ef211be8a28ba003bb5955a0942c9eaabe127b1bcdb2b014aa313cc4a8d11ccba1025157789af29f744bd96b209265ca034df9aa6e1abf7fba4024413a9d8c0b4ab2a4d2c8b820254dca1a19094ef0a4ae9921c1049dd4fa191688404813ed0c0589540b70fd5981649e54741910a44c49572723c19924757d06085210d2d788a0a31aa1ebcf0520f3a4a3c9d0094cca7e438a4c82806633a5f50de215029823d82f71576712901f16e0f46c662ce85fb06cbf3f50f45a7d6957c58af170410102746f9fcc0df0d981dca0bbd75ac8c5f15ccdd578408d248729dc8540a6da6aff5d7d069b41c6dad7749e0f4ee013f5357021985782bab1374b46c692643ea77516b4debe46a7b4261f66534e663800d4d07a1d8be001733b2c00d6d7e33d619a8814aafd26c7a8155e5b668dcc1b9abcda37fac0007e43be17a7798b28ffeecd78f81fd4574fa153e633a97b2be3384f8d44402f3cc8d4784ceef1eb7b8ff771dc6818a088444e10ca150a00d779101abec79602c4f378241f7c544c6549121975afa583140340b87e2b5dab2049b9caa8c5a6416e73bc4fe519ce4a9788b685a39fcb124745cfbdf74cabc41f776c63a4b7ca2fc81ab7a1adc6e6d199792b8413ca339f4043fc9f1accb597b90d485440472a3ce035af456f0dd8e25514e48fb78f738486aaca74251147d6193b834fa46fcc48da746e5fcb50ae9bebb848b71243547094d694ad94b6de293e37488ccb1647a899ce6eec15fda3ad152d38a3ac7e137b80d8ca748580addd78d7d17b0f9849103e3fda63192e7b3f8b2c07bcd34c4f860a0418993ba1af811940750a94554b9840937a39adbb742ebe036618cf873439eee490f383b838279a6a9c3be0ec6d853916e3141e0256f414c5984e844ea9ae23eb1f05bef84de1adde0a3c0aa4388c2c10a0837436afd56201b497c9661e344110d019e5fe96d19f4163d78e36b532335f82197b3b14df347e0427013223c8164205551d9696a2e6d105b372f250235285a4227d9cc0136b1b30801ed4e0a94b4166de14ff59c5df4f5d13544496705566105a48477ab1a931962ebbd69fd2c1fda14cb523a817ee8d9002b447158f834de0caa7218ca841ba1f0d27891d431964e090e96f7cd195577bc571f3ca4c3b2996ec30e33fa707a6768115f41af0cb8106c2d899d75db120be8579e514199a1b40e57d67f58093cdfe070cc14cb6cb28703fd2492918b454e308b1637980307175e527160cc9c92752e1e3d712ec7218df11723b2646931f7c313e13c305d1caeec7bb86172071bcb55f3e805bc5987a9fd0edeea1029ac4f40d851de0c80f1cd8191d141980110fa1aa130a14ceb8d9c0754190a1de6536c6968e4f7a32833af9342cd0ea99180ebeceb01505d8facf61d69b005518a1f2fe771aa72b8b747d0d80d0088119707d43bc0fa33b6263c83f636e46580ffd1be6627b00f7ebca80aa4652fd1f5409005c6e913a52d7647307378fd74a4cbd51ddf7fff6106dc743765d01788bec067da8169b1d3136c45212380f8e1136e30093266899631331aed50c05517fe7104d03302fb24ad272ff2c769cc13cf6e800be182787d446c7768341d3ce03a77665c6ce87552eb7ea581b2c638fc66b4a22091e4aa384dd690f0d074e0431cec99ef74ac531f6e4b0052ce6e0ce05c13fcd6a91c7c96e2e0d803455814bebf234945f0220587b1053a0017a9406cb593a81a886befce4a8b4d26c79120420a26744e98e0c9c8ef7d63d158488177cff5e43d30abe5d1bc95cf21e9f8a4cbc1d634e93c58584055e429d7104de26f5c4b55265dd0b1f12bcbf8423c343026135aabb78814a96b0e0a4950ddefc9119124b74e05a89e3505ab612b4b8c02f100be90b41139c38333c7b4b213ab7e2e65853069dd9c7009231be949db8b69a462123a76a21294a7936118f8d3a735769f39e3bb7b159f787806d65b528c433be3ceb31c9a275e97363e21b96d3ac0d9d4d9f6483850f6712c5b43e994b9ea4276e7b4dcee822047f910075dd950d64af902d4716b621cfe82b6dffdde22453f3d4c075016c2c5916d0c43aa5d18cdf04284a7e2aa75da4cfbdedc09f61ab9d1dfe62429c2fe74e950d0b9038a9f7c39226c2f612c88fcb753bf43d33ec64011553e634e4e37d8ae7fb81165b069a608ce01a8ed5bc68d0798d5a24c38190492bf12759983b617e7b011e69f0164f1b1882e24ff2a28bfe34cf638452d56acdd4cb9461c9ed11e0ea400963c8157ba608be653b52499067def0b3d5d305546767258497463d5386f2632ab6b343a36c5f982cf9a2f561a67b759ec4662a7079ff6968f8755cb1fb7bcb09c437bdaa17a33c516e686e8e637f7143684fc1763facb72007876365d1107063141558c918f5481283a747e5e734b1a6271c09a6a139a703a0a982f3854981750caf3b428d2d0c45b240d79cd44162bb3addcb97ecce1c7c6af2c3c3ac8dc1f020970c84e54bd19f86a4dc3a63fd742795c11b47d7c61758c2f79fbf3734b54f408e32692b563c1156a832b310ee40f965d81b262272f12ac9b97914b706905f448499c041fb5c00131915088475f00fa42f3c1694ab52b996d6273a0d7e19cd8d97219cc579f04a9e0a2a5ac7968256228b21b4385f9e628104bec6accf83bbc87fbf1b30ba970fb815fe1eef2e3ccb11af72d54799d26926310e7765bc39419d30a7042fe04731e26d4667d2b95571a5e212cf12833a71b6c813ddba707a334965c31677004edf5c9c75a7f41bfc8469a0f806b2b8c5f359352c16960663a080550633405f81849351a14948c86ed62032bc370189aa0db417282c9426fff71801bce088297e387b163f949095fa9f818d07d8b4659e215246070514ed023a26e2705a300e524e07d8ca3b0870767acff7f7a8833a2d0804ee9bfc33be7cebdd75bed5e8d21817223ce77a20fcec8ca2f3b206ba49000a40a463aa30ca2375e6c1d104b41ee13b0a6d5462a6bbb80166d788b884c8de7bcb2da54c49a6ae07b8069d06afcae28124ee93bee7d80f157d0c750ffa00c52232d6bdf746623eb8fffaa75b0280566b95b7be94b374ebf3165f5a7a7347f0562ba62a576b4bcad4afd1956efdca4e566ca1e250f8e0ef6857ea17974112e2d6772cfdda80be8c7132f0ad11f077fe53b164e173cf2a1fa1f8f383fbf039d18fb89731eec727d66e099e853e08be159d260119b32f63f6a951f8f912f8dfce4b207c503c01fcf077c413b2fc003fdcf913c2ff62df738c846ed5df6181e0b3012593323a9215d50759b27adfad5ee7fb7fa40ef8f253b1409654c95781e28ffcfe07f87daf128bb0d7ff2a08d629ee70d07c4f143999d76483507c436497be649960af106ece15b2dbfd6a71e98b000287794fbbb760c84383d2faad865930e4a171698b355a08c1573df7f6c7c51ff72ff2e3933207a2927ff8756e3ffc3afcfd0fefbfe7ffbed7118b7822fd7838107d3461087c87f870903f57d6cf0ff0bf0745162debe787154721ff08748c0b65f508f75fc75a666d18f6bb9e5fe8b3a10f0d2721df1f1f43fdf277aebcdd8b3ff4ff138bec7020eebb3712f358423f54fcf9e18945b2d04e2ce28946621e8b631d8b63ccc14013861c447f8783be3edb647bd45763fca18fb394ad2b155aeea76d73b57ef56aadf5b9fe8e6eb126eceafeae21f24bb0d73584bb2558ee7f9e9dbaa0b9eca403951bc24f7df9c3955f2e2756516c512564045800dc39c6b8f3c702dc397f14c09d1c34bfc59ac9412cae7cc305898b932e4eee18ca2e4aae94978b19015c76e28285c70c61bdde7fafe588312d501913c4143e2f84fdefdecb77bdbc4f841cfbf1e1893f9cbc15b06216f187137f20f0bdf712f8de134fc8f2a37bef4fb0ffbd04bceebde71855fd40c0fef72374effd54f918fa443186b0ad8b8e6110219761b7641870994241114dac1c2dc5e4941ee03c6d6993e4268598f4c0d052182590302344125e78403a82e80a146a90f836d9acfc795c08f976de277d6f4511e15ff9ac14c2d1872515c2be97efe33019c3d1405e594158b7c5ce8543a8460ac220acfb1a004202eb3a334f71f4e75e3a54d106c914619a6652aeb018292aa8991295c4890566620a2422396a6e28686244871886646083256a082a2f1d5c38e812daedc7e1ea96122870082b3636538694c44083234b9c6141d41a3929c4e4032141d6a8e080e6b2130e62ee68802bffc565271cb6fc57c9affa41157f7a9ca4a008293ea049fa01ce1b282b44ac59628632b19e2492b0a1055a134545b10a38cd20e6298a0a569089c967958d33e168af946ecaf0f054a687220ef2b9ed63b6f25eaa7af4b5bf26ec97de7defe309d4615c32bb8e7d17759c0839a8bbe5ec96eba0e9ff7efe94dc85ab3e7ccccfdd3240171607b0269c9f839d79329ff1979dcd03a9b0551f00f920e64a3001a8e2089353181796b439c18b0b46dca02043449698971a8800b9582fc6e532485baecf6527a62d476c70b94c92a4cbe2b213530b688caada943525c27136391172d3e5f9f4484ecda67136155d2ab3618cab262c9a4d2e2b721827e540133cf26e77ec9ac023079a522e76bbbb8b63c718652d8970943589261c5d56f3de9b82e293c1f98ae278b7cf48ca619fc80e54a9544b7152e1d835dd39bfb3798c13423ed51867a68126948c714730d06cfa7e7e27e5b099cf89158131efe7734d0efb44906bbaf31d49c835a23bce231bfafc046b176c026d777e5377b9cc14a4ebaa5a97c4edce6fba521ce9957c59fe9436240ee3588ba3756993e2285da8979d985470e7fb91f0ce77222625f28634c31ad04a1458a2406116450b51b000c5134456a61c6162894d0a285f1718dec44009273f70c1e1852b96056fb8289620c1643bc2a88d1b229a00a146cb5214238ef8e00414cb248513982a6aa0ac143104118c241bb47c992384910d28f0152b484991a60729da509141044aa0492a220a8b0a6dbc5b1419241b908ce9a2849c5944451a3303261a720843a5635ae17a0b5c549aa3ca449f711ab484798aea418632489870374c9eb4f8c0a6065b9222281f1304d4707822c5c311433039a20a143031050f508e9ca9e289b7c4df1e1dc172fd499c14702102881f9882986ae28b8c3669567881490533332e8913c0ac80051eb8244d716596860830444ca89052c3157505217890e18d1134bc898383db82e488812229ce104c8879e2e560850986208e70811447d31685654a92336590a8a9012492c0d40c3098c1172664cacc27cab429d384144c7a788ae2099804156506b22f71aec0a0246ff8ae60a1a6464a0b5156f0e42be2c611344069f2c30d0931334d08e44049c185284e71c01c713508c006333c48f14414342d734889cb0c51ca1c19211953a3a0708517255b91154ea6f0222aa0054c941a96f8e1caec0997c5a3748001ca0b4a4889f2022d4a2697d1cb13922676f072a4548f9620b3c495219c90419b2727c2480e2eb08149152d8012050468d4c4133640a94972e6065913c14f2a00620ed1152f284144e702232c6072244c1423a331637ace0252f0a202941992102df1c4891f61e0b8d1e28219393a28b11138a809330312253c9ce95af0b7506c1b3e02063bd480488192992b576480a28217185c9166081da0c400c4d410513944e126081b50e0d1e40564a82c99c2091b0fcc0e4f69e2a4204aaa369d607001d410493001020e1328f64c2b8d1b1848b5293ad364be80820c599c88c10ba6a8c0c421f12a08a066082c5566e0431c18aa97de94db1a5c7aa3b7799b81013ae5466f9db8a2cd229c5f3a3d38f476a3701ae6c1f16ede6d75f37208697416d124fc6200b7fa99c728b94e9226a74bd5072e57ada207424277470f1e1cd4cf4d2c0e5a2d8fabb833ef0742e40de71565a16c27cfe936eda369702bcd611fadfe47fb681f6de5449d6e7f342aae6c1cd4ef6304eb4559285b329d3a2e7e34a7fc24acb45aa5615f958f96837e1f8d161e7d37908cdddd8d84ab747aaf6e20911c17d93e997efd0de49c36e084f27dce392755bab3abe1bb712494fcfcfcfc378e84f2651743e77d9deae3aacabffa137765369bcd66b3d96c369bcd66b3d96c369bcd66b3d96c369bcd66b3d96c369bcdbc67889bd503c1f7b8073fd0fbc0eebba3fed22ba294baa594ce6b411004ad70a2ecc4b12fad17fcbc592bf55b6db7dd01414444444444444444444444444444444444444444444444444444444444444444444444d4f1bca1d3b9ae7b8e7e673bce764d3889dbd583f2a4bc270fbd2787716c5acfd6add9755d9744c57a3bcbc9e9c99f5078360eea6fcfc639d8b3d96c6197836c9fb472b6f33e50a5b30a7758b4e0e971f1c207468c1f191a40d1647349c64f0c183e2f5c006003196e44a33628173d3c2d58d00dfea76b3437da09573aaa67c530ea9a0afc3c9608c388abddbcaedf8a337ce48b46b7bf25cd1acd78712dd4ed966ef7732a107a6e77636889868b7bd5843c9738478fd7e9f424f18ece3397bd9ac7e43575abdf0bc3e4b095cd6bead70aca0bc3af559afebefb568550bf5fd91cb6925a41f56b35b54ac3af559c9648e44aca61aed554bfe42a0ebfe48c5b52d2895c41075e1332904da4ccb379365bcba49439ece3a695b27e59ce727482dff7b209c3beef9748beca799deb86cad2e04a994c265ba1e092bd62e3d96e3fe550e639cdc9f2220ee2ff269db18629fd7771fde9533ae7db6822943fe70ce1c575faa4bebbbbbbbbbbbbbbd7ea2e29cd42c56f6a0614ece23ac7b9fb0d52b88a8f698ce092cd8bda4ca38962d370a4f8d686a18fcfbf1447cae6a86da409473f728e63d3b04a5382b35499ea50ad5525b5a93aa9b68a74549f1cd62935507fa7a444f32125254b4e9890aa8058aaed9b62d32935077d9267eb480ea22eee6c5bbf5e54340d549fbad59f001ac2b15352ea179686395203b51f815e42d08f6cfdf2b94cc1255b44fddf8086e16abab59c83b65f925bfc94e59c732e31333315f99b734e6fad09e54fa5ebadcb9e8d85b5b685b5d55a3bdd2dd881737a9e4e052dc7feb6b26c7deb51afd6ae2f39ebe274cd78a267ca2ad1b8462bc735a8279e2692ca9a4d9e1ce64d53f604bfe6ace96922f186bc216f68c91be29c187507ec4d4de6dc262fbb5c5191c3ea140deb94ac5a59bfeaad5b93fbd984614818d6e25c9ff45572ac221baba24d0ae58fd6fda1b0486db975f1a92f3d77ca1c566fb729ab3755975087104da8498c1928a95b0767aa4e6f536ff5566f1ecd23ea6e73769ead916112d3794c62c830552aeaadbe6158350365a6c6319383198b8481fa398e6b128662062e7d59a7dc3d70696d0672132e6d6e3967adb556a628393959dcb55ed75bfc5661f62d6b7620c6acb5abe398f2458c1934516ce4d45b9d3527ea2d883695dcb4bb7d4ebe8f9fcca0798a82b2c9f6492b67a7b5ded256ce766c3beff33e50a5337574bca50e832a5eb94096cea783e5f2af942eb3c270cbe5df59623159b0f0962c9ad62dfe293872a6e0f450cb6e4d5fc4347d3163abc923e94422c923e9445691461dd56c380ace0d48e3b83a70f01757b7f865835652d9ee73525a27ad95e3acedbce979ded2e36cd779def781aaa952794b95fc4009aaa4ce2a9c61e82d43955cad4019eeec8092458bd9a285b76cc1d3e3e285cff4f1f1963e3b56de110c41b27a5421c8dbf2862fe68b17def285d5f9e9d16375c6105cf93d578a6deb167f01a47c4c63fc6ca40947a1eba2ed1fb1b14ec8fb559398975f154db7389653c13e876df4d726af35097eb953c12161a019c36a5403fdedd62814dc6e6589eae401c639747b9c476eff947507cdb520a576fb7d8e4fdd641efe957e93a1df1cd6592255d5c3de4456f598778a9dcf61a7a2e5d319992eba928679cd9938877f93131b92436171a92d7eebb93299949ac33a330dd48fa629cac6e676706ee7522327bb81d073a7d8d9bad53fa38950fec8c9e66cd5072eb975f88be10b39870942b83973a6aebcfc3dd8a4ae144bf0cbdd92391660bbae4397538605682e8ccb4e57d06eedd61f1f20cf6e95326ed5ff99af9a73fecc6f7d5f44f5dd4780635fc4c781eaabea0b4d714804381676e2e8a3f3a3108d716cf5a3fda13f8203552a0e8900c77c88457838507d23b107df48fdf9a1faef55e28f8ff07f7ed857bd0d2ec4e7c871809c7385784f90523a4a1c466ebff74b8a2d26711f7e684123147c4c63ec9e2c6191133cc5bc67d50fa9c40343e8fd58bea00d2736f4095b1ae816f57e2bda282c42ded85cfaac1442c9862515f24d626998f7453af63d7da9e4350940e8bb88211ca5924b9f5669a32b2a1842e15230f45f649c708ea3af7269b79452f657dbb5ea8320accbfdeca603ab38f08b340c24d22f96ecd2405432d12eb266e4a45f478dc443dcd12dfa543239cc138bc8d827fe74b3de8692873d11fe6d1afd56a2df46f4251309401ce6638439670737a9c9b611e6fff4a84b96d07638cce540f4297d188ea53eaa72293b81d9c2f4e5525903f3e58e20058d60c072c756ba74cbd5a15dbb947e95afd155eb17ad4b68d75372a964ba544a291d200ab5ca84ae86dac9f2310d66daab6100b8b5d2967e8981e32adcb1b1a8683e54b963337d9173c7fed24d6d1bdb4c3f5dffd9dddde57adfc02def692d8b2ad11cc652523162bae5b54aadd241c01675e110ce1fe997eb4d54cce8b3b2d52ad7bf69b7db8cabf5b7451a48a322034db13e65a235dae4d49dbe2cd9b991241ced6c2c4cb89ed3dd29f5c07252ba74e9d2a5db77ee5df248e9d25b4dc207f4fdbaf43d31a45f76e57fccb2324a2955526597af511157aebbbbdb4f70796ef5596d6658c4094709256bd078f40b94cffd9adfa0bfe431d33039d440f2c54816242c2681e47b1e0b16316288e2000670e38690dc210d20593584f2613ecdfc2307a0517f55f4df4812d2e4371696df6212362d46cbee481b278d527983079425299364125a7229b56854fea4cd2d1e78c0e4301f212197abf5df6a128e96766557da10dd6cb7d34abe35a884ddad4125b4b7069590bb35a884f5d6a012d25b834a386f0d2a2137f2d4a012f655f530ee742107f1db39997dce39a79439589579823c3c2d845cfa0c19be1b73ce39d9f62834a7651442764a67c0b07262006a421ef342d1e5315598ee687d643c8d2a2bc7c22b57b9dfe11cc7713ee9f428a5a0ffa49482205be66e9d7eebfd5a72bb0e3de15231e42022b12a4405ce5a2d5775782aebc7bfbe15418855b148a85dde9a5f59f672914facfeb702395b5fa7fe647da7b22a2107e2ff6ea46039889f5308e5f30e337b57889c33c55104aa291204c1972a9d5518ae7454e00d99dbcad1e9f3729256a1fc722c117834e958c00e5aadb270b8682ecb011244d974da4d425151425109e55fa92c22c2412d41950a4c5ae520c2419273708f8e108fd7d10976202bb4b2db81c122f2442c57e9bc21eb24139144bc769144b64fea6a013dcb0746b843848d30ccf34417a5942b5b904d24121d514ad1e713e515219d6eb94a9faf955248b02da5dbba141e529a740849119a2c226d027eb95842b7dcdd722285b1333968b6fe959ea5cfc91384a7b35ca57442f98496ab74fa9c73b6583076e6cb25a825a825a825a825a82587918081fa51b89da4b642d3139a11b7df2372c5d4d7e9f4ac5ccaaac7fb5e2091edb367ca7593925a5e2c22529504022a505050500390403310f54ce8b4c0761868a93320ce13cc9eca396c0f23a0ca2954ce9e429ba543887a0d07a51ccb8434fc72310809ddea6f6ed15a82ebf33fae25b7a7633916b6a7637e16e7a8cf9283c4ebdf795ff89e8f8ff7f1d7035a17100b46c713840704baaedb59cbd5e9aed26972b558977bc96152d6b55c922dd5b8a394d5b84a3050bf13456e8c1a852e4abafd9d0a04ef4e5142cd8162e9ddb63a20f7ac5cc4a07680dfbf27adb5d64aa7ca556e3bef932010ebe70c233333db1932d449e96466fedf209cd2ddddddddddddb99b33c255eb0bfe1fbefdbc5072ecc3309c2b701c154a29e5b88ea0bbce52789df52667794e96b5f29b0245c8f2c0cd9d1aa11a48ff252a1bf2ff3eafab3d7b5e4a91e334f07274d9a907241b979d7890bade13e7f8dee573cfbd0fced13d77e31cfddc77cd8d3847cf73ef509cc33ef743a45b568fd2f5a71f15d75f0582b9fe3a2ab8feaba8eb1feeb0f84fb2ecab7efc9464e8fcf851b1fa11041323fc51a502183b3faaa27c58fca8a3e5fabf68f1e32a85ebcf8192e5e2ae9cb84a27f8f682e07b5eb3ea4f567f0f6bfe0edfd13cac21f2b660c11ad9e972bfc31ae594cbb9b9dcaf5863f370b9d7618dbec2e594b81c287a451ce49f8021c2917a453748d23888fbca92b71a07713f596ec441dc5b9643711047c375ee8effd3a3031c274a2a4ed6530bf951f16eeed6cbdce038238a125037b45ffa0b3360f03927cf39e79cf3a34f29a54577cee95f02fa86ce7997f8b45c75771b526aa5f874f9734ac94d5fd1ea644adddddd0d7f5326e7753686062cbe4d0f434add6381768a9d53a67b9f540991736e77b7a4ff49eed6e9be53e67062d0ae49e99c734e6bc3b09563826063ce6983836cdc763d03c906c1ed962ecee1d7e8b9d55fe44a3b655696d861d25a29a594721c154b68ae47759f735a3b6b926db6ecd2b28b24736bb24b77f70814607f259470c209376e78aa452ee220a031e128b74c91861c8173b46daea9f96034531c47a4615e935591c232258d249254e2ea949a73ced97d458874cb7f64a859eb039973d6073239ae3e107f0dcc7620406658b1ada49f612504f243033b6ab6dfa1a386c4062d1cd574ce2938311c27c20f204188e890323151373872381d0be8d7d8daa163ce39715ca6ff57f4d112c1871007eb78ee3f2e00dc029ac00326c771e2102e006c0059e3ca6f8d2080b1027cbd399146002c70593c7c81db9381e45b56109e96509117b296b9314ce7a494520ac26021e4310209fd9abfe38ad02fbe95bed71715750871930e9808476efac14384269c8341ce8aa4c1f25bbb56596573d0eaee96dc9a2f550d30c11d4d2027bb8e149983e607d4ef1ceaa5466aa4ee6ea47047b702c082706c27eda49764ad95561a3208e11502822b439e3216e89c94524ae9534ae911aeb4d65927a59452d7fc5aaa74086903782efd8fb24ce81e26b8aa1e54d500bff404cee018e943a3d572e9e0f183d1b46a626c4f5045fa25a5e496b7ae8fad968b35610944ac8f9d456108001ea48474525a699d3a84e69c13d63d77f3c651f5bfcaea31653213ba5b5c9e20b2c70eb7fa5df27dce1d0eea77c977be7307c707ae7c6e105cf9de922b194a27f3e0204dc82868b55c3a78fc702434ad9a18a71369f4199ce648a10b5ad7a528e388f3252b6edf6f05d210ce9f2f61b586424d8645a6428c3e28615e2d859aac8b8c498c3e8f8485b521994c8e2c4a8cbe0c8900f1d267f9a200b893d239bb5d563632fad55dd7d9ce72d0b2b4724288dce9b18656dc81fc231febe10e3600e34a9e0eb4e020f95205020f082d6ebf0e07c951487722c8412118559727b74051489116933ce9c9e8575fa65073b4b7d2dace6d3427a573ce39ddef27851c2682991b318453643941a33694522ababa95c4e1a0605348e9b3ec76d0e84a9d754e3a69adb5d686d5afcf77d65a9f16b9b5db0457deaea2e456f7a075ec135cf9ae72809c33a47e09f6d6d1c895d6c74e99924f7e7777777777777737fff04b293d89fb1dede3d3f7656074dde5125a808f0bace4845ee95cc9e9d76887fa35864d42d94a0e96705cc1b9be82b39a32720e5a73ce3976dddc4c6076523ae79c3389fb16a1817c1e09a709b31f2036b76a09ea03e690d9fd3ea72843a74f4e093f03347fa13f948ed030af010942a45f43cc4ca71c9f9f5f045ec3524ad900d92c1ddde2177258ab81f8b9f2df111888dfda6e7ebafc92c50e48da992f64981114cc4881c5091d90d4bc4026898a1a1610918233320879043558a1018946850a1756b374749b01891daa40c2cf3bbe9061b01dde08714354151764d081244f92d2bcc18285a8670d192068b0c2484d10311642ce0bb7355164718ec4f83901dc041827b429bc202561c6c89417d85aa8a28508222e120a8824815f8a27882764f921ff04fe399f278d15427e1b0cd4ef813710532e161461ab8ab763013c5c2cbeebc2db755d278ef543960e8b9b415c77aa589e3c4167c4b607f17ddddddd3df52a22e46e6f2d5ff5a177360fbdb3e9fc6ffc38ced2670f80778a6309d78a41c0db0fa7df4c41857477974147712bbfb955bafd16e99ce3fcc9713f3971fadde1963596607facdf71b7766f59b3f3cb737cf4db3eabea03fa75a460658df576b3dae3966ee5ce124b667777972ea940c2dddda54b6677777777e9920a24a0b84fdaecee4c5ddaeab482a005634085d23bf2f95b015e762a23c51ded1dc00cc2cb4e65d67454b5160c798a70e247656a2b984959a523a980a15b19a3a34e54c0eca84c9167431f27a83b7eed09d7822b5dc884322e3b5da17160c216979dae2c717a621bcec0841393316b84c832e524040e45977b1f32662ef71fe572b6275c30a914ab4f551f543b668ada39c686be4ab72af1b1dd79adabc9651e4fa18627d0ddbd4a18c09cc42c8d51e1f6739819dc7e0af238dd51c6c8018e1e67313fc8b9fed39b6cd79bd600c18549104884c972fd77b053981ed85666c50302c2eb6ec37577d7e0872a468c7618723374c58997322e44cb0b76a801081a192262eeeeeeee31b96e039cebdf7577f757103f14c900793e309f9412f6e53251a44220af3492539c184967a37e8d2ee576bfbc25b7a795f9ed32556eb775fc6bbffc21f8e597460de53c9da300346ecbf01dedb4197c4c0347b78492b8e7587d1cd49faf8c59e5b774e0100abf15faa879f9d5261e3e2e4042094272b8098acd6d4a46ad6c429f5823028fa590aae67f93357f8a43e80f71f5bb28b9454d70fb039ba6a8f4ec98252d75866c00008080022316000020140a87830191509a848134ca0714000d7292466a4e3c154823398cc3200862180842880062002104408248a1013a036aa556f216c4c9e53075ba782eb0d1d5d130ebb8a96f9de584576a48171f5536d9d1137a0ea5c3bad00986dab1d100646bcd9d751f7275324b90c9712ec4404b833799f33342dd33bec056ebdeb9fb4f0a4ef4b5b4d2dd82c6942cf346c9df98f750fdcde0d78992cf65e40ddfad351ba7928e23eab141abd2aaf21874a421f6e6047167334a9d56cc544dcc23b2f8f154ae7ff9bab2563c1f532fad781ffa5d9286dd43cb248e05981c627f411034fb6d959edfc742c0c6dd7a33f630859bb746485049349f5530ef4f91fc3daaa4bde1f8307a872099541e2177bc70f25c40cbf75da827d905eadd5bd817bb389246a74ce8f63c8664b1afb32f12c547bac8eca8eff51e3dbcbfa394af3ee98b7d0d925d524191a83bb1afa32cb0b07538ab08f4fe7a042186019401b8d91d4fbcac1ef43eeadc19c0320b9f90fbd09656e684b3cb1226c5692b671839a38a982cd01a51c4cdd34d50d2516df2a6c8964d67f88fe3500c7c5420ba0cea263da8579f96e2206320d5983db0c76264827d552182bc4284b462ea63d7321df62ee9658d49040f37537d3ed9716c6fec42192634e0eed962204a6197c8ae3ff88ae6d6e22ce4133127f016eb8338ac734cdd07770bde600b9ddf6d88f6e23127e57e9d838e643a83e9044048d76a403c2b5c214afd44ab15018e708309696b9b01ea309424d6b1a68979311f9bc265589b2fd631d2e06c0287c9d2456cd684f986aa7db8a98065e56e56b8318f1a586f4c5afe156eef89a62d7e8ef55664805aff02396c45ac1a189f8373e685f8c11d8095b43a5e37fe296e43a31eb4606251bfc2f2c81b7f559684baac937c11289d9b7a197ba85ad27d3b3784e0ea7a4b14f6e7e4ae3323273a66e1716cd53a1b7c4f105642770102d206d6a156fcbcb42ca82a8bce4eef09e7d2f841f2a570bb52fb1489bc40907acd74ef019642567c413fee446da9ac25804b782d16171116b2c20d568460b69284e080c9d8407355b540ba36e26fd767ab7f22a51594f27cb9e3736a4342b54f86adf201b23f6e1b52d1facf95d025d8d99e3af4f4d1270862d65153766619377d4683a246b3f844a8da89cc41095a3f1aa82a7374e8c9c7ecef8ff16c30326fb118309ddf2be4aaf09d0aa8bc98709d8e0237a3fa5ec9da45aa706e8bbda9daaf75a9ca798322e9c2fee628247801df20078fad8dd7ff2cc8324ad1bc8cd80acefe78684649f6ae8ed3fd50ef51e36804e2e57fbe6e926596226b623360d99d2a70faf36af2ff2f790b4a8149d9df2702945049ba81ca1d6df6af2aefeacb0c541a3bc6e11c4dd9c2fda2ed258a4112d7587b0fd36df0e260bd196b28443359b1c3dc294d29dffb4042cdbc04203b3b09e3132603982ea146d04e9451ddba2dc9658d3aae3790dccdb7544e91aa881eb1b44652ac128efeb135fb4ba59504c5b9429e2590528af58e972f3ee276b1d7cfc0a3edf9d01af4e42b8049048149838544425c99b6b0a75bd675cd22e84d496999b30d40f707c97ada4ccd59b369762e40889e9c897df57bef717f0ce94cbf2676e3ae5b0208359cfc51634b5d5c2cc9e91cd91d1fa05f1ac1b5d5700236eefc9b90c2f585be632a519174528a35f0b0c21a82f9b34286a3adb842e51444188336798e1eb748be75033ea3f0d096c32813b39eb67930122e5648d2f637b59e868ddbf8f9975a2c05aeef3191b568b2018feef6880e80045b3c5cad4a249dfd3b3a0d98c6587835f060408ddac0cd75fc81b321939a13effda04813d894ad25b660e2dc2528fb8d16fb0264fe83f6e308293a254459be18a737efc015b7aa1689cf824f53cf32199f2d4f358e3980ea6021c22d446fcf5f1d7ed538ea3155069235e9c5d9ab2f716cdac44b0ec6522fc0641f444c0596a6219bc553db1993b142d9ec076beac72e9175e993f239e8d69387b07627df4d905d40169444bc749328153225391f11dceb5946542a4953b01f1854ba9fa384fa56f121f2eafe71715e8f536e405a3ebd6f0b9c4fcef8c7570025849a41b8c1f9ce6320ac57f740a68d6c381f9af595f40812f3d39fce70a4d369a0221d586de6a2cc058b06b28579bf30610704b06a978ddbb76d5dfe27f88712aef86d820e68feb7643be98f03cbda4903a3b8b03061e14ae72f870310b174107803dc4388650f574d8304f7e2726834fc48dae4bac9c5b95b51c2e9f16e26f2ae5318c33dc328ea0f1af2534cde4885f11fbec4c330f374eece28b77f4c4c0f048d672919258fd8065a00af53940104455fabff732673ec878d3b114503948c9666add5b01113594a8f463b8c2787e47410054e0972778058650eda2f2219c20ced9db6dd452a90775d3c1e7e1d3c18146bb0e42606f49900ec9091a6274e4ff7f30efe8aa3acf210f0d88237814cfd8732956c952d9880d0a3676c88b2151234811993a66db99279a42043c52ff3a71d8aa04369c8f6611066350274315d64d8a9a89da45f7de58381e432056830441e7963947b9b93e8b7d71cd29aef303bcbf4f07519844d57ac45b184152718cba676f898b69a258428a8e61181dce6eda9bf6094c93e503d0d8927eccd0f789bab435d96f4b121ae0d7a33df84460b064108eb891e1512e530bc06da251548e241173878fdf39668c0c5fe85f088073f5c14fd0a8b9de2065bd9f1f4ddb1fe589aa64fdd441870e665209ebc5248922bd2d1e2650ce2f31dbe1e2121c7c7c2fc3ac27b63c06592dfee9d986771148de38b77841db863d89a15ad1a149b17031f8268fc04ac68258ac67736712c8c5a05fff0aefd137f69b48b13c5c059321f3c3d9b221262c0c43e21f392d1ec657f6c4bad8341cec76e9cfd22a2dfca3064449900c9925dee022c604aa9aec9060c78eb802d56140c6be131960ed2c9813ac83df08cf8f34dfc867900e149e838abc80d983d96309e87d07988a4bfee88ef6300e65a91d299e1827b85ebb44d24f958b03b7d7e4816c389109122df113f7a5efd93c13b798e7e2cb08e1f46e929ff25d55d248796b0a0d88f50195f979a8be08f0b87aba7e1c1c93c207050fed61ead15480803686376cb69bd81bf2d50707feb628cc432772688f23941e062ff953d72d5e6249813c6b63b85b6da58bda26f04190c77f7f54c7083f87bebb902ff10ca71439837cb7346524b1639dd0823781c413908a0df79fe41c0786886a65674c827bb7a215a5a5a62cf06662ccde91747c626df98656c89cbb6b6a76fb568fb6617c1aacf1ee48eb4827ef0580e92124b63cf666c28936e94ef94da913b39eb8dc4d5475c9e1f449d352717652043b95bd99e64eef79c80a0d78365a94935f9e280929bb1784fe19dd2e7b51dc8f237ea539958c3722be3f2716c8e82c3ba417401dc8d01086b0100dba81356c272523447b520e06db0efbb9c06c4bd0d3ee0590e0dcdaf7b439a77519c42c3257e289eb93cf15b950ef0b687d7129e8316917b64a895d0fdf908e17db611f1a793f31dc9c284b56f96fe13641135c734c7999b3337f70044eef404ecb4da9b3db7c3187c9d0091aec382c33ce7d426cdf57f9a0ab67826d311186fb6a90e969a4da7bc7205c4e2ca91aeffbc12d749698a353ff3c8fc68a86e271263ccf66f35c39b18e9170225e3c6ec21806893704950096f5ef01468cc993f144d57c0527bbcd62900d996614dcdb75a93209bf5cd9156d874418305e30bd2572b087c927fc49cbb6128a3419b10083c88712519542ed31946d609de71fd04aeb0d8e5916f7a2f20898b708b8170544461d811a306c162205558a11b4cb92f10c4858b422b065821c0935f2bc1394e8195ae813d3dd600854481d6d90138d72f2f815887919698f99ada7e1a818531c904b188d8bf4889fc183900c9189b45f8632088b013fcbeed75988e9f079f451458e441301ea5b5ece99733917e46702ae5be5ccf24380f48b9bf89bb0e62123dec8bd04a418139aafc2dc705701981c055fab1870dacf4ba5d23dc1601d3ff168e950acb961a1558a927c2d22b82ff797cc8f8458f5c437d3e43b43eef344f9f611a1042332146260712dddd7ba56e27175851906fb734759778da3633f100770b413440b8bc4a7311b03ec77b48d64fa4bb16b65eb866b77c3b1c85b9e7e465e4e89dc185c4fab5af6eb96b79c21d7617c94d93e543c1ca69725b1bd1f915fb2a917bfd2c11e88532ae24f87685f17e741310638ef48999fff6ffe2d0dd021f9e3b8b287ca17ca22f610379c11da88a221128169761c10268497674e28ac5a2f631e5b9d67d2582b99544c2c9c2d48963e84edc318fbba3d682fca2a1e5319a495d3dd7cdd5dd24a5185f9012a26b1b284b8c60b63584db33b493a456a04418050f1019fde1332367ff508f483985cea2bea4b14143460d144186edaf667c1ac45f247a2e91bc14dca476fdcc6ade5d1354fccc95d6d5520ac3558c02f283a9e4793be280f03d12062119cbd0969aac77eb03e21ca9f100a18b2a2a309fae4c04a412c6e301f9e5d663a334e24eb448915920e4f300a2b22e5b06d543a6f139375597d8d84595dcc9fbda415db6bf028e69f89f437dc4c39a3be9a046e016485299bf6a2c57c8c9f54013f75135af124403643e844c28547873926b3b375918e10445dda37d2d286f2bcce3252df6bfc0430275fbad46754aef68791a0d3e7f2343faa23ee845f6b65d2ddd02f425e37470b2f678221e9d9799fcfafc3d321456c002b80eecf40d357067f8ee446a79b335f246a5f053843fecf3922d9ed18696ab45345ea1b089a30a8958d9efb315960a2f9a932c5e60fd3defd6caf578d116f874de0e433a0f7652c1203e29d7eb2eed60269247c864b2f2487b7fe51c463b1bac682822276d3ffd94084d036f8f33038f009b5f6b44a4dd7a74b1b71fe13a0795b777935c8123ad086232220b4bf3727628f3891a4b9c2f33dfd983cf7942bd08a25197e05a9e0bef01855a78ed49ceecf87110f59f0bb602104a4430690237edc0479e482f21ea2d2c85124a2c347c8db4587d19c63dc9d83a1d43025e6b5d45d9668cc9f43e17b0706c56563f367ad2af59d1f4a28c22b96a34765d7aa1ce5d97be0700dc84c62e16cdd8722fabf491aec4fe9c5529f051981756b756e2c08366bb00a59205fa7f28a483a304dac4aa582058224c06c7ca96dcbf898ce2cab643c83902bc127d22b76ade95cb4f425a371b7f051e0245656391acf873d08a471c2627dbf6e55e89f85cd663d4ac71f8ab693aa00825bc06ecaf9e3a9b107f909cc4fb258229a28862fddb556829005ea0df3cc6f95f2646abd960a9dcce0651bfcb5fe6d16393ceb6012c7142eb58a823f2dfcb06f5bc48074fb81f840847394fcfd6057122f0b61662e50b0303615b0f8c88a425f5027c8b62abbc90d7e833868f94cc1fefa5280849e3a648599546ba049c4a2d6656cea69c79d2ff91e29bc7901104e5c501dfce287097fdbc4908560262776261ba7f418b397c7009a37da578dac676d10114fd138ff6ed07b5820a1fdcc807d10da9595ef8e73500d165afa6a0d6cce335f6d40a22a964e5ad12508dd501fe78a76532eaf10e1fa4dd493b73fb0f29763b7adb2dccb74d5a7d4cd20daa62399b29063e59c7a0679ef2c454b21c40a00efb09076419fc6ec2d949b049c74d243c18a6f53479362472f47d19652dce2904fac146b81f7c53251797b6b20f616fb678e0a2fe2de25e059c7034f1be9d1239b678b2d4f827b828b319b549c37e467b33fb260ea7299d2f969bdd2137614297eb86126bb8f001f162ae4602c8046ed9b03e27a282a0b5bd2bf42093867d96c03c88902763ee2ff8903100c294d1043a983c3d308f27fc201c55b1d46a203cf8432c56894bda802b322eeb22ace54fbd72514295821d2eb8703d410488d6093ac0dfe64ad802bf391be33eeae26747dad35313c6e9616103ac00fc809f5085458f7c2c819719052c477418ac57d91cbe015cd24a4f97f2e001e61acefdcfe0910a8cc553c062cf77df057627554c87d683cdf949af06afc91a1cd93ff4ead84c37c04a70637facc0e080be22b4363799404305a9338b71f07f1f2ae55b9e1382db9d64871d8afd80798888edf3995778393642c51bf8816cc47ea4014da3623bbf32c8c2f9e2879580e79cbd8359d3736d0a93e57dfe2428646031f6dbc1739e713e828ed4a2582fa14b495f445ad0c31d78261d88f6a0cdfb82c2de0d94dcefd2af9579aa997bb18d5bf2eebe3adb373dca05c4f842b346d1e085400dd20d2ae1c4010085052109c1a75abb40befbe800ca8e2f05dcece4c41a5df386722154aed44e1c77a4df5b8b0e8ebfa7dad47c1b7316a08fcc9cb7421a59e7a960f708dc347c39990e77ef8a9296f6cf6469ec2f11852bbf1d28e11cc6f9b85dea18319e35c712a80dd2152307f79baf41e5dfd2934544a059880a228b00ac27a8c896249fd523ab7f056b20be270aa5935fa1c75e5cc6b68a741965607e631559573c056bde25e37f48b00e79d7691ab29a46f84d5873a7871a3fdebc2af4ec31fe7f72642591cf82330724f03875ffec741e39a8ca110d4adace4cfb929730cb4cd2bfc15d96b7f560af62dde0565175a7db7124ecfe39e3bf5cd39ee14ffe281f257f06afa1495c0be71e1a2a768fe2a6a4e08830ccadc965460b44e0f3487761072b71faed4266762bd9134211cb529810467995c3a8d7b38500d541b1a987a7730920f1920e2363abbc1a85c47035b5ce963dc379a5ef74c46d1b7bf259b673a46b876b90daff7b594eb80bc52848cf7c12fd3608b7427b7b7153898a48614475940944b900495837a3a6851a4c28209a8529a223410355bab766cb70249524ba88e5645ebbe070d8d55168bccb0cb29ba1ee89d15b8733549a455303d24224ba2c1c63d3d7c30231e57c7a16d386c1bd5e36f7b6e9f5ddc000bdaa962768ea5112264ea2331c2763dbb331fbc1f58d71910a5ed7e036e74ec0da2452846f370dea1f60323cb2b02cb3e00e205b0cea04d77fb8f2c0f7f4891e2f412820427257535386fa3b9bef4a8ae49aeceaaf69592447e8d4d9b13ddaa1205c32dda2ebed8c57c439e94e45c97bd0b0eaac37e25993584cba2f37804c3ea26cdff23b1fb27d7b80e13863a05a92edcfa4ad34957d6a35952e11c788bb7817c059ee526ce5dfc2877cbde26ad7f87a2b0c88c204698d52020e95fbac0ce5be65937c38f63f7aa57a889edb1b4f87aae5abf7beba73d7ef1b561abc0c7f398269ff0c5fc6877dd4d9d49419248e94913ede5d3ac2baed901263e9226c19128c395ce75c2323be581f5aa555fd8da4a143ce68c73489aa99d46a6426f212211fb3f7eebbe29d1500cd1e6fed370c79b6caf93efc7804410f3bc75ef3d9d908d756ed3a656784930e59ed7c1e033f48c8224917c2a0c12ef33eadac2027a73c2af78b211072aed4abf6bfaf194e7cfb0bebc2b9854d51f0f2c4e065ccf35619b6bb8b04088a5ab7a0f26a6c1e36c3bc9737d22209e5e17261727e7e738fd9366dc76084696a245464f63b9676f2342f42f067a7c1a39a8cb12ec16ec4018e5c36ff87b63510927d0a22ebf25b59e01c9afc4694fb47e712ee33d348cf9944329599ad985ca072b85db0ca1d4ec2ff582937b52f6e507faa79c640a5372fa035c455c5db18af4de3ac8f0bfdc89e0adf6673e1c0922b9e53be64ae61d6c86719c41ec156fa8da4483805a331a3cf1870adea90f44bf1dd90ed17a84be3284ca32fb3197d09c32d04cabb2f9db64fb404430efc5d39faf35b9ac975a22fb74f135efad9af6954ff2f83e85c32b9c2f6b29330976116c8876ca5cb306968d48c389a2e2224d985b450bfe3cb508640a1256215aad8e9962186b9160838c1706cf91143b5a6682ba595f133820501e19581886991b55936d06f0b4afe11072d03cd7127a1ab92a75d38ee607352b8d6e30d888d4cc94f79a355521f866f059f4ff51791b785a5b4b0e0742c808113213b79a8e4a2b560c36d35f28ef7f70bfed2a8b1463209ada2c36db004489e88214e685fd18edd3c58dda9db1a24887b8cd38409bfe73be89da7fc0cb7e5b87de1d95ac5f362bd644fb8101f46d2a6d05505d9f50caa3aeb58fba675ba167488a9b8d8ecafdd7819d62c0d34edef4c939c0b0328a1f2f2aa11222abf9f5f85b11cae4e64a557b98e1f252e9cfbd1b8dadf2ac4831aea87b8de707c08f69f4eca6c262ba2d45e05e1bfc1615391ad1b1d1f34d2c2398d0033b12124b39ba96a40b653d9c4c7774994af8cb46786b935122df494b75f4b194a45bb1bbcad6e1d8544016336e274abdbcc9c9b4926334fb1fd8ec9df13ca8a7fde3909197e5d21145ef504f5c9a29469604190206f00d77c539c2dbac6c26d0b429ab16b5ebe41bc3ea6a56c0d4a8ff9c1742c1f3b505be7b61a86b7ce4def2ac939e589a42d7de47f17f226a72249ba0998ef75eb64dd0cd74f19767e3305b5a7d5c3e1d353731a08e045c061a64014dd1b5b5fab414cd8c5906e978c8667af8ee2595b927abf7055f831c5008445122e3d56df6d1a1cf0a8ef8d35d7a7526f891f32aa5b4b9a620662634e76dab338b7cfd0b8ec72d179a2537df1b119357f21d6d2cb4b0748837c17cc6009d9d01cb11d50cfc5a60cc702f588ccf8d6df667f6fd979511c879993c4a75420b6840d628caf9ca372d563690a94646579e0c5b8e9118edc680666259f5eaa0a13f5d00255be324281faa76c54e73edfe17d1bfefb40e5e18784f1a9cafc758f004da379a0c3b1747ce2d3b0e90e33494612f30f6159be257b158f86c68391c01d27b12eb19402d3bbea839f089a4dc7baadc08073bba5a11fa77c7e4f428bcbdd410f9dd331e783c7ac21643f6def65cf289844423887b0378450fdd5dedfa793f8daa9239729520219fd545cc03eee18219813dacf7e6ac8c0e1b6db0ef4c3013169e789f6f81cdb463b26e266931e225811b2de1d8bc4dd5558a926b3c937528bcf60854191503768647dccdceb0fc108e09335ea7a2781f984153417052bfc8f1ebf1498f59a828b96b03602584886d17747b253392a179c40d5f9ebb94f0e307c3bf2ebcd555c8e687dbd16fd44e51ecfe518d299cc8752e39a7e35742071d84ca44ef3978da9987a58e54facfe12214db7d62ae7c8598df8da86dde2fc934b6df311b30b03f97dad3f796ec3e4411ec9f7878182463d2791cb8d11bb95e63a5f8961731b7bedb7c429f2ebbb2b9f130f0eea007dcc170011529cb23ef7666aaeb8d52cbd5f8d50233b9782b3d6e8f9ebe0d698ae4625336d2219d13b836570d8bdd9eb17dfeb2e6e04f59c063164b3cd08ffe449bd489162f0aedef4c32bd754a5e02c804719f503c517ac736e20d80d46973ae175c43bfa8be5d4273c3f220177ebc4c42d361d1ce14c03af8db99b04c82d2aaafc48939d2b4853abc9964b4e739122d7ae11f6524de0a5a1091edd71b9d0511b54efd84e810402aeee4507ba99d736a7526549bc4ce7bfcd18efea4ee2f0c0eae650070dada7ce2dcd0548433d0f8ddc409fca79d7046458504cc770261d1b5dc5ed31fa2002ac0a47a4f1d240a318649e310d1be2d85aa87d8a162b25ed8372c08a382c641d3d73ab65b055af578d1862a173af2f89fc72b35ed2de9500ff10f242e7c4869935582b1f28a3a1393d6c9542c44b66191e5691e668d050303b8ec1a6fb02eec751fac163ee8920873cf2a50239dbaab679345f98e1a57a7c4121d2858fa634a64b01b417d4db7bb2923dcc6fc04ad1a4a7c7394b844240daae6e99407ee2dccf72e47fcfe9b0b4376b9c1f2f32b7f928a34aebbdc2be197e24974146fc86f148a482487c7ce31d7e5cf1c6f38ebc6a6c849df9b7fb7306d82db680b79fdbfd82e352deac044175ee246724b85876a3d7c68fffb342b2e265a443d9f345edfd593d36508110303c0f4d15c352cc13e26f288233fb057d87aa837419cedcb5c2f17cab754acbeacc326587b1946d3c30fb1c39bce08177dbeb7b83e0e9eb8d85893f2a10d4501ece892ba34b96ca41bfc0635c7585cf28ee2d47a503eefbccc8354c1ef84c1d2a62d7ca79be7d8771590df686de7b485ae355d4f75144905a12be611567f56cd34bb34dc3b1d3a28ba6995804e1171acf83d494f9af3c15c73d20ba0ccdc4c6faad2ae1c0822605577c82c1de41384ac581fad3b828f5ac322785bd5f7959e199ec31f5a8b27a8c30de18eb006f77e361857f3d7b1afd16b263347a4c9f4bb6633c0a2dae831f638627dbb94ae76c9b7479ec6da3a4a9fe283f4a2a7876ce4b2a78913055260c67ccc8ceab15522b896b3a3ad0ce3690e678ab3ca995df37e67957defb4e6c5f5f40bd63e3bf330018a6ee6693aa0df099b238c6526729e3c70a0bddf299e80ed19ba733e730c23c771448e4fc1354ba1c223926df9d6a06bedc7368a5e6d3b6e593b634a8182b9470ef54e934b93149c4f85277ea56584d8be090a004baf0490271ee465f9266e5abae7d1c94694cd6da2ded1ae1b42ec569267d6017efef78917698d289b06d9bbf1a74952c517bcc680068e9637b4960b30207d38e987d1756bbb10ecee1aa8f02718217c7780b0c8dc9e1eb3d0f0035507dde1368efe356320e562bb2a1961c37fecab16dd53479d0e48d6bd5d569fde6c4386d45ef73918811817e228125b647a80928e9529702f536bcb2c8739a91c5bede15c8d62e8a5f4a9bcc201bb34409fbca09efc9a736b51add8ae8d19dc623c448734bec3ea5bca99192dfcda9569464004dae50f4fd7bb7ddca984645f7b64b3e6b3a5c6b8d27ccd994a350ea92bbced803dd9bc0043bd1d1d12abf3e256bcd27ef63060a268777fa9b3bca24087ea11f40a29e93f738124a44831f480081c21a2b53d0388a8d096548d8a198a9d5d95c62b964893087bb21c6cf3449572fd186ab2bc941dfb4b0092cf32a27f43babaf618712d78511b98618023f251aa604d0112c3dcc8a510a4e9340368742370823cd78213976a2ad4d8e1a9d84b3d0dd342c31cb28ce76ce7f5d33e1c38f8b2261bce6a74106d7483d63c3f88fc0d80624f8b3942ac5ec72ba9428950c7482744057446eb45f1e1cd1b3e7a436d6ab68a080e8096820d8fd9cfe0ae6c871cbd57c144893fe2e892013ad957884a454cf1d9655036f38a5bb512431e8ed7c34c61c784f86577450b557cff6691508cd9794558b898823fe3737d56e517154ef2fc5ed95be58d10a6e745faef16022436aee6233fb7d60b68239459baf748009ecaac530ad5410f85577bad3227dfd502bb1ce008e961c8060c3cbc518349e0bc50fbed814c8c5e4b0b1c68bed0c31ea5966b00c7c9f38b0de022afc01568eb612d6b6a6a51fa7fc6512d312c5ab968b6f66b9dc09ea9026221e3d8612405e8471eaf3bd033c457725f541b29870386860031077221cbf5c13b48f7374ff4ef83be322ea49841630ed1cb1b055d68c44536d46706ce570167d09725683e209304ff1efe09414a5a5f5260c3e8f2d7db009906e3e727a9306a8d7d7a7e5660c20ce2fcd01a39d3bc8b0925c2146ff35e1cc6c233f38a53270fa91ac6624065c343919e058f387adf81caccc9552d030b0396d650e193a1f6e803e917c171defd6984aa4a8094f14093729f697a6a793492b0ea485ec70acc570d94276f78a7b2903572d3e9178c7347da900934aaea4e41774f4eddf6a9acec799f923c1bf5bd9b3a57bc1d64b63b62af9524c7f37f224163a881119a0e908f414ee36f90425f22e2d0e78560763b5b822b2d47da38e2bc163fcb40274e833019ba4ba7c7305b2c085f4b7d5609e15d7fbdefc7aef9a8f0a02b7699d603c3414a8bc11f9e8a4b28dc0a14005f389294d003ed9c2a3180077c08a8e06d281322b162a5ec1d79bd3f957a9112d54c6117f849ac49be8ed55f6590160e7437417cc27d94e198eb9b7ba807106fb195618929a03a11c2dfbd9d6ce27e19bf363c885b0d4ad473e382145a7ba3159072c9703d6d5498ea34fa14eda0d50a79fed5062d5acdeac0a2420ac44464e0ed9410af515cf46b924fe2368fe1ac53883502376de37e1e8acd4947f1d18a15f9b83a726cdc58c2f5873480b384d14d3c84aaad74341babe1dace7c2662c60dbd6e4e27b3e41484a346750805dc564fa4bdc35d269e5e05103901887111ac6e122ead54721299ac23ab2ea3ef654510e8489fc1eeb5767375641c1914992d21a94176d60b732f31827356c832d403b29b9206920d78face0638e4c3fbea721d45a59e86332069d447d8f1489bc15f55918ee837d837c16c9e65ee1cd6b5d4d794dc0697bff94ea3dc2791b1647886c9030392297c498954865c6cefbdd0788ea7555730ae826ec52564981ff0222b04a6d5f91a32fa01462e80a1e37d1a1bc237b64db9c4bbdcd2264fc61d67475023731e2f4aecb4e4d31527070c83b12f1355a7ab60eb35bad37879982994e211406035eed7cddf7fb3fa18625a94e6d9f066141e7a7589920cee1a4ea96a4685d5fc05707d03b6d6e96d799742ee10c75fb97cd48e2bd14879406656ad5322dfd993ee154cc289a653ccd4b80c25eb66c3252257c80b15e20ab651ae4d55cedf41af565a07b402b6cd825ae065765c9344f5878055a22210fcbe548918fb3bf6c8b7d99f61db9d3219aa8fbc949fbbd0f6ad2d2566e2002a5977c04ba49a62eb9542d9c1e615418275bbffd856f37b549223b6016fd82edb86a0db4d69bd461d289f16237b11a3f2415c8b5a4a8555b4b01990b352b0205411b65ef2058bbd498e864a8cf03a57aa45c15323f301db16adcbf70498438d9e1dbfb31d26500656585f8246957b7e1f2707bec7b28994aa4393f81c4d10e412bd8b69efc7f1369a1cbadc6297437c2ce4d70ef25c4ef6da26b2d6eb55e9bb3dda11b7152a038c0b1b4e12579e9247f83c8a8528d20b4e5322ae1d99bd5ad847081089bf97bdf46fc4d41b7e7f20232f48272b3de5809809fdbe7eca7098675552c5eff02f4aba9acba941c2f0092cacedd2e6725ec4808222621a70d2d86eca0e3244e1532572464dc61f91856be389b124c3e3fdeb3c4f85d27bd143e56be51ba988b9b109f1d06f13fdd28260550009bb170487ab053fa31c8e61a3db54c015f6dddbb43f529106b4ffbd454ba69632c0e73c217650983b31e3cdb50ff1737ad192cf526c521505a331e91dc550a05a79edbe16cbe347455e7ebdda65a6f14a6f6f6eb905c7aa21688ff6fd47681b78aad246f12d2834867ebba6805d2ebcf5813d82e555a565a704962f226b5c866652708738ac267cbe10c8c4df881419c815b28630c0951528e29fe608615170f854a33d41567257b114f89522907f6329da7755897378f04faaca548296abe7c7d509d0bd7c14137e62155dbcf8f260459c02d74ba98b8c908907e920e5135caef74b1ee93ca54df87756a68be4c8a8725a769ff8126f44934b24b6ebf3062e7549021716893fe6e535d6b67eec3083cc142cceaf01bea4e09ad7fa0b0056b5475ac2d4e7fd3193b2ad55174a1c6cee18407572890f93429ba23936795c0883db8709be653d28f0da03ba2ac9d343a99e43227d245ea49ddaeed787c33b30b1973751862f7aeb44ac75b6404725f21a2ee8e9b13f5176cdf9494527347e18354a98c83f8271db1c83ab03eaed965e6770815a9912b59ba20b3e4ed1c64baa28205859602761a2ddfe53857c35bb46a881c6baa18936e2c31145c44281b7c705ff417ea94bfe8ca448627257fed3207429a54de9be0eae64e864ade2c28738d12dfb8ee8ee4091cc9abeb7088c409e5aa932c299a010c67cd61c521a607fb6dc170750ed0683567c51894d10157b5e17390a34de85ddb9464dc831c7c8bbefb07a49bf8e4d55442a3a9e135463f5a66e41d659442c2bd2d369c0adf14649d90d27ee504dda10fa404372c6a07158fc1e60c1b0eae4da4640fb1a515a3bc3b024bff4e0e0df4b604ef5fcfd7e3f33590c202f90df1bccb690dc4d00335e525ee901292f07cd99af027f09486bf1d508e560bc373212d816098a8b691dabaddb86ecb2d0f380f5520fcbf1d97b2331f83befbc19454581a84d898808be30bdc7f654084900d1f9adfccf28f97073ac641d70760d5d9dc9cbe8fcbfdbc091c30301b0a06edf42c80a82c202f1b3d3b59ea3d3d1c20af6d52caa66deb8e0a5700275787eac313e346cf63df4eb91156bcad3ec4ed048a9fb3665a5cbd8441cd8573ad114c1b9c2d72b23e5550f0e2afab6c5ed9e330dda498082a0baaf6cceec1bd75520863c64f5b0e50a4e04757450f09621c958aad3b75ae767a2007849f99483344dbb63f3231e1b93939f7dc0dda6612e824095c87e263512a7dd4f7a4229b3dd493f75a72170d7587afa257364c25e1c27f3029ee6929728baca368e16e581b6c0b320a9c2b2dcd660fc99c16f6bd9ebcbf243a58562864fa5d0c9211101256c7afc6c036da2b1f26b897f3d3a7d96e5dd440b07fefb483cceceee3a5762debcee8e95ecb7467631f689bd2f1a8e9ae33ba3752faab98cc394d777d5313b7f4af0bf8361de743752c44db761a94b83e133236cffb4aa594d85ff2d27299e831d446fcab59a313adf57d11d30caa7ca96926fa91653c2a334f40683df55681dc32a3bd5d65f577668fd9aab861373ce75aafefd5157fc65ea35d10afcff77306373ddad5d768fb82ac9f8ee741a3dd5d4dce3aea870bac68d99800fb28ba5cce1179d3a19756584b154fef5e086edac9a7a9493c275da0f60eac58e6f2f72c1cda9635917c0a6307efbf178fda23d793ab70dac3ca025f42db233db457f00c18b1e0d7d111e05a3fbdce3caebba17e8a862c611348fd6f757d547ad736ddb1b10cdaa6e93c6e7ad79b3f95a71924e6773ace80b6695d8d4f9bb17cdc74d79ad68d9556e48ba944dfcdb7f5799786bd38e90487d69043fb3e0168af4899af8839eec01d4a8bfec7c0b6951c1e1f683adb94631c8db9420ff8963d6a7637d7c90b71187d9107914a42dc55affb84e92e20c3fec67a459d6c276abdc3549325b985a0e7f747c34522e5cb5cc169575e8ab1d2f6aceb5efe2addc269a97dff02c102efdc057744e3ec89ff5638cd10a69ccdfa9b0ab19c0d0015b7b6ff36b22b1b30cf9e13923f63a86a72c6ea736a06267395f93781c1f7e66ebd3ef8ece3ead7a94dde93a7a9866413235c808f28ad1be6c18a461434c0fe7c5f8d54a4036fa7ab426b92a1d7d9572115a9c0f1d81f68a81ac9cedcb325cd06245223f6d7db385eaa2e93e5a05d9940364d671cc736edcc6348b6b77a13e85ccefff4785518452836eeea8f4e995ee564e2ce64b7250da878897f9e696ececb440ea6969ff664834c4d82e922c3c8b7f655cd25be29ffb92b3ddd6bf394f72c7805ed958520493411a51068efe29dc4bd323ed7e44a9b1bdc791bcd44376b3e400ab5affc235c3151f49f4e09e691e1a0a0c7975b750a3f41ce0e2370ae3686ab520fbf6a50a3655b58d2ed3e35b7aec02a02d841c90263e08d0036a5ac419d9325310a6b53cdc00de1da6ae52873e6db704033168e94b81631e41a50166c1ee95e71d925fb33d500237b1006e3d3685e18bbc6e6ec485812590b4eb9725c1c690f853e81c352a5505aeddbe3bcb41d67129be061cd9d9036839f8c1c111b3bb15693ba448af104d669031e61483d8b6bb1eaea46245bb11babb936dcd721d64f1cd0cca0562634cf7e4dccdda217ce4c95a2f915145bc29b1c83a0115428c945bd1d087f4e08a1081a39766a60a9f860b093117d2a654c2cc5182880931ad5f136423342bc69db47ec04a15c4102b76678aea5a8a889ac4775596e68f7b1e906147183f15db84e984d95ebba136ff45340a45ebc3118c80c5ddca396c91b0112a41c3dbcae110b52850e9ca603dac4ca981adf496d035ab2023826dc88d2ae2069261803ff34da3478d4439ad6fc53cef98c77718198b4ce237e68d14d6e18ac42a1416ecf9d40d9698a1cb48ddb57a0fca2cff475d3841ade192fb9f27a507da9d90988af1c1f32341e32c0e2c05e7da06519bc160fd0a20b94693d889b00b3040741010ad39d0f74e074c48e1cccc3664547e34ff39caabdf79bf3c5277216e3d4ef07a8313510df07661e72334165af5cc26956aea36a76b0b15d380ba68d0daa9b8aa95ea218a64f0dfadf9e62a3710c8f8cf520475644e868c5afc99d5f533e8a7162bdff50afa1f56c5a978ee9bf4a0da4369ffe737efb4037fcb53324002b9b7073468f9c9352a7364d168a5afd6bf0194d097b4561fd2ff81574cc8676643f6c7e91f702c85f4a029dc304afdc62a4ec68e3dc2a12bc2f0593fa5d7db44b216b45877a4a2d0d7b11c48c6235f363c2ce0f21a11886c4344dedb6561415ed08eb4395c24d56ea68534f59c018552c069c706a1203a647504815b3c0ee945729b78f3d678868eeb77c4490ead99a3722455b7576e65961dcd23043c252ceee5e0169625ac5808053b112e20b0e2d15cf6b55213d8ab903a0d504e722ee5d3a1a7bc4d491bf1499cd5f5eb171a8146462898432b63c17fa648c8bae26bd13e8481c01b84d3032ec567573da398dfd491420f8ad89c476ea0b0e04bbe050f32078d8c06cae99b0d65e9c93ec2b7ea1fb8b767f5d312de7dd3d6bf3a8458d4fb380e3d4558f8a2d5b9948d529632863ff3e7dcc8ea28c1939b9f4509e471ee1a0a85a07e496a9ad43e4ded6785dc43d36471eaa085dd9feb2ff5194176d502af96e054d46e564702731b2a82f387a1f51553b0a64492ad26aef1fd07b22252877740331f026cb67c503b7edc53cb5b319b160328394cb53217de0c9ec378b70b7392fa5f48084384fbe415911a49a463cd17d0bc9c7e3f0fcb832e7a65cca4f8cf2c1cbbba7d2eadf0deaa157518127c1957a97a3f54d7cba1439945b81a403da2232763a3e6f44a10311bb2afca59c3ba3c6f8145271da22a0d84025f8777eeafc5f98e36fd0c1a62f8fdbe2b1ec3839af7470be84ead429c1aad7be9b3aa40a454727e1d8f36d098409bd2212d9b7b70ae258edbc9da595bd91f57e4a4f73211c574a81a79980d68ab354b7506c37c70515ccc647d0275d917a2c99ad264273e780868605563ac2520de5bbb7e83f998bdc82642f0fd0c81e8f6f8354fc30a526c77c9bc033f648c9f51b4ee8572b4c2a6059d3bea96c6ec8fbbef943e33a8b8393596a48dc2f3574f2b84fbc735d51cee8c7380fe0235b2fd9bcf18225096e7f391b43a705a61f1cd23cf8dc30c08119b5102c14a525fe835539e4c91c1694fb13f85532fcc4c26ba70f3681f2b0047c378aa29906bea029e33700b4f75d0c2d57dd0308131aed3958b3f1b04566685822947e31a1c0c521f20ff473f6b4b41acd5ce3e2ced0e4388e7c3a3fca49b227d24315034f851a23b19c2702d95ba574b7bfa6b6f7e2a387e43ab4b4b735b03d7061a0083047c9ccb51d4974c37b17568123343e9cb3f78038476a32ff1d2929e8ca57bf0679d57e359cf43bd4ebf22541bf8474e904465204a4af6723ab53df393ff0626ee240dedead2fc64f2346b7cbc8511de14e2dc7e9339944b98f82b710b9585133688588e63e88921d6825f04a00e07e931c4c610de5dc42a68c87e15c46847ae4e832dd4f487fe3eb0bba9d203ec6d70ee8c09a49d15b5b09b74481d924a09c55552e605d591fd530afc70ad80098b1f73be4e2c1ec2ac84378e6ae29fb011c686fbb683e669bf3313b375d74f4d9c334b2931ea89b79e69c1bcb1e59a3243ac99b6ce0e9f3bc7f51574b0a2336c0e1bd5b7c38133b641b2faea0a17972c613e308f60c60f1ebf037db9a3f87ae0349b43f463312d59442bc5b15832f457292a72a0095cda79dd13590c60b9747fe400beb1cb1422c12d1bc2c1ec30e9388ad220948074708568b47996c4a3f6fe18c168f35e1877bda4caf9f9ebb1ad6f39a93e8af9cc652202d35cdcc7f4d738252901661639ec3cc07c31b1cd417c03c6a9f1df933dbb68cb34da6e10cdc68480b7a23ef02bf4d1c60dfe14a5ec9a18c124c07723b7ccf1aa698d52e4dfd625a29310156dc5cc2c76e55a9973e6c029f5963294c858aec6fb8f7c1249a9b5fdcf3ff2b68a8b008491b5e2baefaec2c048eb339f733aa4c9aa8b0e9a229ff163699d4f2a5315f2f04d9cfa090190f6088201927f4b3283899d40e02889e829f3e0c4c25bf27b8b985d59d333da67a7b710bcb92bcdc08c43e228943bfb54a5d04244e0aaeb98fa126fa1eb8db2356e5050d40166bf558fc5a5dd7bad7a757cd56f88b821a0b6f2878031c032182f2b9d558398fca602a41e200c626071d70bffc45b9e6cca51010004304a0aa504edee7b1ba2af055c38b0f0ddf12b0f99748267a9aea415d6296af4c16d61bbe9f881583dd328fe9a3253c67f65d084bc41738010c6df26815464722a9518084daad44115ead00c7c7090ea552248678e015a06a748e560a2e3fb2ab8814a15b3c1cb680f322bbca546382183bad519e46045ba41a9b2a510f0c4d0a8099fe3908565c80f4a4327841cb084b6fa2f3892282ee7b5ba44f2475f486215b4d9aaaa172ecb026b630978c13139e90649175cce4bd01798aa80d591e4e2e39150e52f4dff2daa941a78f075a0ce5623ed3f79605a6ce5454f0033b334b117dfabdf554871061f59514ebee049abad06ecfd4e08aa715f29a83b44062349c7048abe1bffedae15c974f408b94b6ba7879e4e713fdfa182f13d0237ee2465ea7077ed903002d38d0763a50b3bbe3e1738f2551e619675b59d9be2df2590a96f71e6e30ab547fbc496fb8d41b1bf7f82249d436431240d9ea48e76e24de09f804e35bf7bd1e5a94cc4ad35c5c2c6ca074552671e69c1cdedb278b770047b3959dc29ca091699ecfa61594340fdef3690588a2a5c1ea5b81d982ef24cd1ce317adccd859914f2f935002e82325721b223c4a60ee04680f45b9de2391930e24ecdc21054f7363fdf43e7cf5d3fce74be188b9b656238015755dc7f46a522659e2e4a385981fcdef9d971cf197399e8e4c89f26c8ac364478e5c606a4cee478d8e6097654986acd1dc8ccc50b43fa7c1855de47e6a1c697e4e8beb5d17cb4a066f3e116b489df8d7c442a0b2b818727121fa7517d1509567737f3e5a486b7210c8c239d30be00fe17a09efb66297b1dc6eb620f6965096794cf0854a14f5797a56c08c6130fddfba155ff0fdfbced8ea119d66b9a6acbd3ece6415334daf99280998af37e74e21d4f92e5d84b9f98d2903880055f5fea2b285a6e915ac8c5dc7e52f0b249e5d6195fa8d029382b3dfba3f81ca7ed08ea9a7cae3282abbbb30901bbe26de459d51146316f763290652a8a5681b4199ffc1de357caef374d535ca3d3c7fdaa4ff149afc4deabdebcab051cc9edd56eeedfe975e8cf28c397648fb4bd5f1d6142888764fee33693fb8061a5c26bac75d72d4ee1c0d700dba6d13c9946e2be873bc9ca0976edf8b3576a90eb43b1ccf6483aadcfe3f33aaf5abcfed50cbf62402bdae47ae2fb6e83f070c89d0117bc9964a53badf25ce9e531a53e03ba09062584c50f8e74f4b9f3afd26838a0bafcb13cfcccc8cc0b6bad8fd90a12d6194c94c49836ee13b0953d28c43d581b6e546de9760c02363a0f191e257fc106e934a937f57acb0c87e7a78f55efcde2263f9ff41f9a0aa871f2d781eb396924c4b2e2923c4a779382c9316eac7cca31817f1e801ff423e6ea97654289732447c52202f2a646129cf9c436d8da74cc3ba3ff4dadcc5a466fe71d36736091e943be5c025c8444ee496b9d015186184960b2da4529001b2290b86b3a039fb18dfbefff9e8472709aceeb1130c09baf48be881c984c1c1435f0ed9e63085804947fb07768b8ef55a66bac4df6d28940f037cf63f5248582268ed164c0976bfc12295cf13e2ad10f186279551308fea900c8760e7f90877a0a170fea09402e3f66aa37abe8522f54038da520499ad0f59128504bffe5030d4049973cdcd07a127ae5523d6ff0400a220a5f4712b75234c2f5ad40a7f3598e61f19453bbb8f795a2636869b2d7e4c03254b8260879e4431299970f73d9069fd0f86b541809c78382a9d462fd237e57d175631caed1b4b479b4409a74dc5148ad57efad8f052b867ffb347a96bd694bb8ebc03933a5aefa8f1758b65c24c4822de363776e268a6eb38bb2bf40a1edd459760669c26a231886b8df9dca3c11cc2f1c16830da04c16c00eaad2b24f33adda369fb911ad352d597285da1a5e5aa20695d9fdb6d3a2b72852e1e823210e28ad60d6aa313aeb9ed5531d20491868820b3395aba57ad3d676311a1787fa6f5c1681229bf4c881e85f213274bf8633146df8a734abbec719215f36f48a800f7776ba10577ddb0a8b7931d89124de071f6bb51e541a5ee8101bf2bcf8b3efac10ca2a18c5f2458dcf0bafd43d1406e488ccac7b3d44a0bc7c771b45892b408536b881c8e85db5ab2b1377dcbc9a1a87beb8ceee2df332c2f299c1cd15d84481cde222ed80ec0ac19e938cc178ed6e2b6a31b11e832900e7b378f6ae5308a92d9bd4e4ba44ff5759d3b66edf4af3836bacc4f7f40ed7a4a1c6eaa365e8c855af0b50112e7b84e22964f94bbe48955899ae2f076dde57ab5f24364fd44b003ea661909756d4e6e4f5bae9f4ff50e3e54f198a11e57b50039f9913b16e65132f69cd87731eb897a5df46d3c0e99ba431c7374f1888bbf723e4242471d9890cf7bf8b8af051ee9243949f9cdd70c07651513c4d5109c87019a226e3b71a5f039aeb27633195b3f7ceffbb6a0e9a08f9105d9ce32728fe9c3cb440b6e275bad11ef5e653eacf376774a576affeea98e7f320bdfb149d1b7c0d56f436f3c0ef280c53e1e9e803a1d9939956397d5cea3f73f716075bea52fe50780dfc237baba01d050b2e6eb0e9d896b4e90e06d2317bbe08a7cafc4a39daaaa421b1df71ed9a74db41aae9c6af0c6c1ee12ea63887aa60defa82c591e991c61cdc8753d47dd09287de0d1df24b9e3960bd70bc3c36155229c9494a2fa338d489d32a34e02a9a2d679b72097678f9d0c9c6ae53abf87657eedd0fe9a956d27594e0c8fec1fda4b77bd701db54bcce94db13b7b2bd77fbc516e06d305fc73c2bc5b691676bb64ee757043593d06e9ad8a907f88cc96bd858ec0a8d49faec91277afafbaca2e35e6067052e93dabc5bf2f36f74748970bba5cc63de808cf04d7360dc382f79742ae5ad81cab9970394f9ce7525dc3dbd54a603f47821459215b1331d4e7227d775287f9baeb6ee79d6b1da4663705fd0eb156ea6d9b15596899a8f19d5c8047d15368b7bc674de40a6193b3daeef44d0821c9e2330e961d046b9121a1b040de22d8aae2ffa247028858f9022dc9614e419845e961c880d632ff5a02cae336014503012da8bead62e574809cda7001c9cde1e69e31403f80b2d7be052a2983d87724dfcc3e477e83259e275c4ba1f07d498c6b0601bf36559df1bd7188543fd8c1917afad596c1f20c9a0c7bf4b5c64234d90cf223f9d08602012c3c1c64399a42498bd5c91c58e48fd760051ce14ee9f5fd2252600fbce4f3e0803c00303a0fca21ac74d1fd46de1ad442a3883cbffb2d272b5e5fb1e6073788f1f9b1bcb93655a2a05b1da50ab9a26f1904a0d0c84e85c5ae9dd66ad741ff4d183cdb5eb8fabd686f2db866c1b404a85ddd50444ac33dbb944418a29564da730558a1769be7b8d2f967b55c42b08ba02eed8249ee5743b7f41f49cead0d8c94ea15d8b2d7ec994933f602e254db65927ef6e8d63a3eaffcd603db8ad3c7b32a8d7128094f750a07a222ae1d3398b9f6021385dafeae8033af5dd20cb0ded8bc16d16068546291cc01dbec1a4125f2d9f0baf6b22341d039dc5d83455985f25489b2b4d7176e85a1bce6fd195e10981294b5066cb39c2944955e8fb49ca003b6cc47946e77e6f60e959f9dc34802313e5b6b0bbddc4158e43a81764300d30f047aa9d5dfeaf8111e6e30e896870f854a486be804e4b420807c44962ac480a7e83add53b1c2b940a47ab3c6fd88481fabc580d68d52c056bf1daf20419dc066b5a0706fafc0c99e0adede24ad0b9b587781428bd34b43b648e7a9bda3c7143af77103478e447004e139147d724b09e6316c3fed4e847a4e3b2ecd5d768f9aceeeb54708900fcbc9493dcc9936a5dc053fd044478376737a08acbacf141177320c10340f67b42eab2e6185b4bb04935c970be2d5a41d308e3fbb4028a78703327307447073be2d237e6c42e79dbd3611d00a288d23606034db9b76986459ca179f079d55b7467fd56e0896d6edeb6dfa4d49f13cc97cd34b63350b395e085b44e9f534f6d882695fbcdec75917c21dc5ee616255ca1b89d58954338c8de937781e0c7d5448e6f5a311b564f323825b3257f0567cfbb2acb98aa85812041aff47fe7bd4910e6f9b688ffc3676fe5614e1c1e08dbe091a4f83703706f14e8bf9786b71a521a16811b33aa78f20dbf8079ef71eae7b57396e25d80b0fd1ff09b6da83ed69dae704aa9855475497e2b40709452c50a2580ec27797f35f7d947812f551925418f6186812047bf0ef012dc505c4c56336c4e44db1c4a9a34e14eca06ecb131951fd700820f838e3adcb9456ec426f15c07a074f32ca56e39ee3d3591d76301fb6c6b29822fd6f3c01f60f55a5ec7c8becf66d2e7947d73cc167275f744ae055df1409aa33f79a3346c67559ad131dae6dcecff332f5fa1808682c22a4a635de0dc1516e256011e678f48f8fd460ef2713428f52a7fb145fd111eacb0ce0c0da3348df8f4f862e765e46d7702711ef4a4f7459c4612dccb9ae93e890330673a1e87ce789b8ba933d42b5577b90b9ef3cb32931c54aba3b4ae7aac45bfabcd4deea89e9c8bdb573b14881839e13643dfdfcd931a904647de520d2231b27dc54b6b341b2e1c79621094b4b964d44ad6993fdace4a7363eea1948a0f44a4f8166938d3db81bf4d1165900916e4ab7b8f918ba70f52d6c0c340890c194c870539e6f5a32b4872ac34ab354624cead4dda695f40fea2d931831ca4eee969d2e1b9e580379a6274fe517a3714da01ba642bf40d23563d0f4ccdfebcccb9a65c262bfe778d8fd88b5d3f221dd40a725feb36ec8b57f3ca92f4647d35ee74e22de8dc5d06a97a7c7c62228df1d1f41ea9e76e6b4d89a09226d261248fb9fae2cbaef719bc65509e7963a3b2ddd1b9893411aeb258c18e3f4d41d1e8270e23b243df059cc768f9c6ed3b82ae186d45219d013004610079ac99b6562acfad44d18b4f52a0b793f3d8bc505d736a418f1ec5e30b5d290f6044e62bd46c4497b0df7c4fbe354faad4d1b32f6980d45f12993246d7aa44b2632f1a4675e22bac209fd62814ea2345c27ccfd3eeb4e29fd30a7a701a98f64216343d369863212eb4363a98498d4c97d01c867c8fd4a2a1eae15a1054265216f9f89d3491b48b925140764e7028a18e26a5c4090b24a07adf8df33112e31a78274c0f56c902e491953524573f29b067e58011ae4a369d0a80f0497eb645fd80e747c0d73c5d6ff2c6a0ff8822920e6a8208599e02f666c9c3fa124ca2563e000d58edf24217befbda59452ca946495065c06e506f657b0d65a0c65c55030ec457360b5e25f9bba9ff29ee5b558ad489dd27e090d3179d20e6574773742838bfbb514a6891700044929ba2007e407028e280e2fe7e25c3e2fc3bb389729378cb89f6bd1c204c63674034829a53e5a524ab98d90da21c618638c9d9b368d4bd45a8d86780e6cd204071e9e34597aa5b0dcaf972c6132c4c885fbac0d7a36e5b54618e22e3fd0f21c5865adb34ee9a325a5942d1faea365f02ea53a1f2d10a057800354295f051dbd937d20c04180383d42b02d1044a81148f654ca763c8ca42e86b56c954d8726525dc81fa2703eb4773353a7b469bbbb3bf4a8378d9bc786535a9aa51494d2999259b97cddc049c13962db72514e38f17ed24f9aa8a5f45157c1d24f7a4a5369a44ea2d39d7421ea7ed274bf66125dcda4993449a2ae44a92bb94e3c5ae2d21495442157f22e3e467cc5a038e45370f0dc045e94210c727c9764c0223b6390418e41f9abc99f2bb912539463ec70bfd924c79f4d8c5c0a0eb087e7f9643219813dac9108c09ca6017af1b930e16602717498b05646600f7b2473a8b2565aa9bcf1b8a0935249e5f4d19a924a4a29b5967eb4cf8292e12e37cb7c1b62e2724ed9ad7ea1c0021326433d14d4d4f4b5a0ed970951a79f401b7f4c44d453fa9553f8917b29cba32c51c8ed55beaa9427b007a594ce18638c3176d090934fd97c1f641861077514006d22c526409cf83aaadc8ff553ba377d52055704abc85fe78fc5823893096bb509c17e397d49ae1ce2a57d07d4f3583e80f464c9e21d5549525acae2395f7b91636769283407cafd1a0b1625da5d5eb854524aa59452ba7764a2944e3a870089363923c896625625abe23958b2a4ac4a16024f0030b85f4625a39221c56c698b774b10059c52ce1b8fce3a67f5583b84ceb3569e39dd638c5718a55644600f974c521a49e213b404a909d34b6888099d9f3702d29c736a2c2225400bc5b502c2d752480c9153a90f2cb491f62190a863244626a4d4e70023dd7c4ba711262626a01764ffd96f8489493ec46907741f0a596744600f9746968c2860a0935249e59c73cecd5aec356cbe95944a39df4a2a27b5f2b169316abbafeb9cb56659b5c18d17db9b0b8249f9a273524a297dbd86b8e06a6031d56dc88bd9ddd3a77c49306e28a5934e29a5cc52199030ee855eb76f496eed6cf48fac2cdb865649397efdefc67b45d4be225a1979ceb792c14a871591bb3b248a2c182277652f4df98331ca3a18a2682302cc2b4bfcc1a3f61551b4f7a63618a21c5d58d7410f84ac88a2cef6764594631320d3d7226cb7dd07142b5e4d0ce566f7ef5d25d12c986ee69c74521f2de8d528e27eada3ae690775788eecab05e4c60df8ce015977b1d4a3d05568ab0fa137a59c73ce99794081e2ce778e84e830ba409bd0c6b12c2b741a7cc01e934a4a279dd247cb8701f207910c106d84104224165201e04ebf007548dc4a20ce8d231fb0c7dc86e60e4d16b6c750eb6b4e31438dc310582c88e359bee417f6a6de83fed0e6c777ab7c492d3548ada0e7b17c00e9c9e21d5549525ad2925590f9f3bc55119e33e146d0432ea76713bdce0ee0f6804464f801803a40667d2f5a1b530ec85d9448d45a0b7bf85075e2db565393815c715dba6043424a79838d8a76d8304c29e79c736e2d8872ced930787737a538d88a0670e3710f4d883a27b874539915b178ea86401b87ad2316f42c0b26653924b7c42924794db34e8190c10e4d4ae99c73ce2dab107a18b598c56d60cea969b469523ae79cd35f99ca6e9f4f70313ce1017bb8e7b17c00e911cae21d5549525a125ae26448484a29251625f2e72991a111466458008f00508701d026beb70088838beed74a3c25413c600fcff2c995a1591f565aabac92fa68514a69aa88522b21004770afd65abf521eeea574c0b00df6702eb474ad9556eab8b3581cdddcf0f83182093a2cdd5049c292458bd4c173a4bcc0480729a5bcc93728a5fbdd3411770316595049e9a453de78524a691fd6409bf9a99c020b3239059f2c25a494b6ffc43f33d0904a4a279d128b49b9155b2d5d76993d279db46fbcee6ed8ee274ce97f2d1f9e1367f794b3fb3c723cfd5a9431ce1ab496a528abc82a58a848aad2425905c9724f67e87e4da5a934522f49211243f849f9ea00a4944e3a7db466ad78042028f0b621a9c4ec39e594eddedddd5028a4325af1a0e7bf7d2be4f6b1f22555703b2c4bfcf292ddfbc21e313fa949b5065183a8543ce7ab32a8473508da44a4eae872bf5a6b559a73ea404a29a59419b2503a686702f6942fc039679db5e668bfc9879fdaba865ef6acccbe8621c4c99e35047b37555c96f360719ccf27bcbdf3ecdd1e51c71f8a70ca157b10c77f470ff7abf1b8aee65de76687d195b2bee72d17cb24561d63e9d0e1698e45a1d59861b4e91104dac81d3cdc772f2249f92b115cc823c229530c04e2c80f5293e58b18f7b33ba0cee60900ea8039dedee7792e63a0ce667ba75f8339f4e5a360ce7c9a944c4c4739dd8610976788920cc337aa86580c738d192e05bdc04ed9c04e8bf55bc8599611b1d85e6bf19115e6d72560dd11faf36bf77516b3986547ea63f85b2185ce47e86b7812793bf1fd1829177a51e7468e7f59b115dda2280d1a5c69338ab8322cb89f7c18c44676c9024b67f81267e25e7c9752caf92a49f3a92f414564f5335f047f0dfc53e3f1cfe0d44f0afb580c5d33762695e3f1cf55f7f37fe53931aff992232efdaec330da00893634af1a42438355b35d3333dfae99136a7c0aff14f5d4f8d4cf60d57cd5abf04f0d5c2483554264beaa84c0bc7c98979f9a799a2f92fa1a9ffa1a0f5d2bac9a5ff3402e8c555ff33daaafc13e45dafba8b257a1be468555f555f3551aeec9f1ab5f611f558655e8e91ec797005d3fa24dfcd5d77c91d5d7e0ffc1817d3aac54047ff71dfea9c126e01c5855b10a3d359fe34b80ffaa2ff2afc23f453daabff13f39b08f57e4c6d77c0dfe516123d0055d40ae0f22e5f8af55f3d0a5ea1eba70fce7e587ae0e17c1bc7ca8f916d3bdbc4c07f3393a1cdf75367ed5fde3eec637a71a32f3453cf8d44f3c84e64df00017c9af01800772cdcccc78f000c03e33ef012e9249a57e66e6f1ffc068b3fa9f19cc02fed47bf0190b0f308c36a91c5ff3abc7ff75d0ea73fc09f86bb06a488e1cdfaeaefb7675ffc36b74aaf91e3c908ba6534dac1a4243837d8a26eea9790fb00fcdd7e02298af21b51a1d0da6f91bfff3ff4383fbc6d7f89acf585c1caf226a2226385ef5ff37e23f8e3fe1c6abb06a080e1cdf2e1b36be5d36fe8777bb66d7414c712f7e4fc9711cb1a4a324a4a4a3d94b30f7520e9918dcd597ff1d8eee57eecdbfd1d9e82e122f4bc0cb47b0cf7e7bc79f07d4cde8805c34ba1e1a3ff3a89fc13e4528dc33e369b08f0af5340f5d33de4785c22a22a99ff922359e06ffd47c8d9fc13f453d355fe37f549f7ae8a2f1402e1b755259f62bcf397d96fd8d3a342a22aa4fbd0935b86b3ce454e8a97915f669a66813bf0697005d3d33f3d0a5faaf9b7214a2fdfd8b8fa05e9bf9caa1ba77cf3d98ea663a18b30e7b9f9dc452e541ee09b9171f7b1a1d74cda0ffc3dd688a3fb176d2496d482e087d0c0304e3335ad4d76a77d58610d74ff63110a04ddd2cc7a365d8a92720acbfdae1b672fd96e7dcc8f5fdedd265aa35beb7ea8b70ca16b7204efd1fbea387fbddb4807430dadcb05cc747cbe87e9feb7ffd540da58f61998d3663f67f78b56fed5bfc2171efba579f75c4b5ffd9ed85a8b27d1b755a6e53bfbaea5fcf69b957b5bad910e2ce0c7f56d9940c9ba9ec6b7ffaad5359ac22b27df63f3ec330397c9e0a7b0dc32a2259f6a7c7b0f7d94e9d0a7b14767a14fe41fde939fc53d483c227fc83fa0cc3a8420ff728ec634b80ae9b4157c6e242976a48967dbb4ea76fd709bab82295100a3374d91fd17aeef9bb37b988792071ad4b22a4b7dcfcab7d6a1fb318ee5bb3c9d0c75288ddbd79769d23ee67ad05cab6d6c6b0748fc752acb9d76c77a4fea7bd7dac5309a947b423da57ccf56f9df158cb53f187f15889615d2bfeb4e7f0c4a8049c84f8f575accc23dc671bfe80f26623d67d2bf886c45fb3f893d96258c6fedb62eabb9fcd54da6d762701ff0c1fb14fb12a48fda75825a47efc2a83d4b7f883eed9af365307ca5a6342d2feface257b37a7edcf3eec29a534fbc6aafdd9a500339d15dccf5a1f20d7a6f900b9b4ffac06b9211b90aac8fdfa147b6deb7eb4f7e17efbd845fcc33191e5877bed9bebe1b0fab33b01f5a7ce461bfb154b1354b8211bf601726d4334ecd32e1b6d2a093e647baaf906b98a3fa09cc4ffeb1eb7c2c418d99f3621250320432b4d08e5e64eb8af611fee2fb6d1666212fc29ea4f4f5fa813e26baf43e5fa5bd4d6fd6c7f7a8d4e99bb6f8598eb37d602eab9d7b48a3ff97d3e4ab560ac5f67f5c9fe01654f2166bb82ccfeb95f285ce47fc23f1c110eab7ab48fafbdbfcd569ad092e16b5ab77ded7c2cfd862ebf14a8bab674525d1ab8b3b58ef872eb1d0a401dd1c22a720141770866792991eddeb7c95c8957b84eee07b1503c21c7f26e9ea4406ad2a56cd97ee3b9bb639d7dfaf3a5acd6ce5f2195bb4e3b2db5f66b27a9c52a041d84d12615574617b7e0b78d8eaf1175898376ba11e54aa79f7d115a24bb7883146612c35675fd22d9d7fa3f12abf85db221ec1d0bd3e43e8b156fbc51de88726386b0b920ae0ae22fff4a114679be3f50fe60c97b37553b9f800830f334c4910e71e43b179d7260a61042e7293b08c6a01833b071c9f1e7c604714e33c0884f431027fe29e8b481de39bd4e429ef37136680713f73b0de5d350ef788e7f5ae239fd724f42ef386517f2e74357cbf9f57fe8630d1bfbfa45b0aff8a7e807eb223f1643f74884361fae6692e78470caf3e14f2c9ea3147bb89fb7943f882576305cd8e3e69863b7c53dd118ddf928c84e294b8673628133c93d38bbe04083ab6f860c96fb9dbed3508e5f63c795abda4e43a72727a2d3d08909a48d5544e6d3ef994fe94f9ff91503b938a41cdf421591faf67bea5b0ef7d4b76fb14fc5b0f1c731714a393eed5ef9bb75a88422d235b14f0baef93f7ce2cb748724907b748175228ba0d592fb82032517c5648bee098acc887baa92b900871eb6b85c8656b0c021072c3c808485126bc5961bcc22ece5b66811433606d3b685892518194dda962a560747d99617c450c52012c308bb5b52b001aa8325bb258ad02423a86ea9410649061165d92d1c188aac168b476b074fa20d2c43e800622c8131c69016278e628a50fa4106afbb1551c30aa0fc90c3e6e48711e47e8c8c1f62a03bf8b0032fba4c2e7cb0424b1333195a99328696412c5a58299cee32fa94b16543ed840aa33dca496b36abc52c662996d54ca3da363f2fe51877ba297b42394abbf745d3324c3b41c7be70ef6e778f52ca392795f15a6bdb6f6f6fa736d0628cb6abd318638c114208619c91ca18638c32768c115a13d02d468cd2182385106adb0cee4465507d638c14c29376b988594a658c11f5b2d19739310b632b9d18c7a5c8498c4e627412c5498c4e62744214c5498c4e8a88b02615b3488c30556b218082c51ad2252dd4422dd44242b12665da1c01089244c08f0dfb4dcb56aee524d1c6adf7df4b7ac83dff2451a799b88df74ec7d042b0a903b3856cab5157c813422863282c042979edcbc7a6a1d7eba50129c878f1620a2d292a42007325554510563879b1a28a0a60bc8853b4141193bf48450926e6bfc82576e929cdd45dfc8913b95264923b22e59894636472cc1548392626e6ef155be49887e1786252fd7a65987fe17860a4527e9942871344bc5cf75ab1c2c89ede428ee339dd2b997b588512dbb6bdc6f16c2f57b6c8bea14e0f11244174f472652f4b1c91318c0a2f32b62484152aa2fc0d229e64fb95e3b1aa5c1f4e318695410caf4c651353c85095bca428a229c7f465ea7ef9fd4724be329b4ebb68d7d8ba0dac9546fd035296524a29979052044d0b461246585ef061c9881a6c6ec8c19206a818820c205c122e21ab30620618236416a69fc24be24696ef3232b20524c8524a29a5dc64b62bc3ca22029bc32b4f4d05043de5c8b30a11d7d64692f9e2da4721057b402dbe656a229aa994e7a8b03e8238f3573fdc0cfb14f964f8ea7082083feaa4a803e4420e865042031a5e00e30ad73c72c592104c6440890e96b8e6f751d489465c5e10050c23ca28816b3ee00436bc80b46414c6906b7a18454491f472c5ffe12a20e837a702e2c60c391e17a05c4d7ce4e535a10c5df835432b5960c092b837432b51dc207fac24ee29432b5130b1a258a2d43ab4378a1408ddfa0404f2004b48d44a14414ce201a6409a6568c0ab602259168a2d40d0ac168b478b8a2e6e03b3a5a2c96d60feec856269035520118142e9680acfa96da9bb6b5784c884ee8c0cadec40b48d60071abab859865676e840fe5816efc00125f0005204415b6b46696468c5872a4730d06a0771e2928cf33d56eed4c73ba352d67ae5cec33df755eeee9693caaf052a342cf78ce6e14929e5b7fa683484f062a721e77f11c60c319d4adc3d4a1d28883937dc767747e940c185702a812d63b451a2c8d81f65ac324a1425a436310be4085f4a3a6192211b0a5107f54cf079b8ce471beca1a7b504e0352b1bb8d36a1dfef5219535a8ee421b4dcbb4cc6a5aa665d64eacd52eaba4b0062a59fcc1a49a5a3911dcbd66f840ec5bf97dbaeedc85566e1d84b5e123e0877b40760a00754437c0cc115b8c0aac02b164f1e1239b9eb97683ec02c592172fac40618225b8d4c81e4f4091e3ed9265471be08d6d42ce0d3722f1f256d33f33122f773b097a0a962a8302a51a86a6b862c50ad777b3c481162da83c610510485764432b60416f32db958955dc9f904129b54409a6e072650751b030c275e5962b7290821976b081861db8a494d246d98123a2c8f211e03975870a7862b6a2c4022634b8d2a00db4f1b721c46d1deeb9eec66dfcbbf3d760eb6294e3c93e809d1d043804f46f3ba7dce426b70dbeb5f7ceaf256098b5dbc3a8b369f5b1fa18911a23e5b67723fbb35adc9fbc1125e74dddb77fe2362d6611b3b15238531d68b9cb18a3bbadb6a672ecbc75b8bbbba34edc764fb075c0af71447b9493568b65dac69d50f705f5027be7346944c1c4703346669399a1cda091a168cc60a899944dd16cb0776aa6a9416bf4ce94aa4dc5f1cc57d548fa591ccb0f1f3f76b2943725c38fa823833944d26068cdb561e386dfc031b9edc8c6ebf6be7dc1f1de3bd25a88d371e0c56def407b61efdc93b5b6c6031acd1a6a660d15b386f2775510eff7efce531542679bbbac41c75058dddd64f85b8803f18c73763178f6a0bc823b8c36315641691e25f5186374e9dddb6873a48c75c7bd5b079d324287944aa751ca4e06967bb6b3e3de7cd0e0ea9b31cb5e90582c8c05809f78421cf934cb0b480cd4ccdaf8532396d14c9bda26372e4a8ee378b0e750d9cdcaafc56eb2b62df7dcc74def7cc0f2e80e8d153f9b7144a64bc32c0c051427191a5c754f99cd8c6234479e4add2b3b62191fcb62acb67a0bd52d46b16c669ad4b69849b9713cd96fac1b8b653babd62121ebc6665505b08a597642b20b6d28c334c0a5ee65c282df63b8bb3b0d9e64f72db0242e648761d425f6bf6ee25f80203be78dd4555ae90b285acb0ceeeeeebe832db6f020a509134f1021d1c516618c200cd7d75d746edcbeb8216b2f3da795b5d7381e6dd51cfe808232f75af7b160b8fdda731d12d8a47d37b9bf9bfb8ce3396115a4f6cf8d0094b51c355c27b2879f4ccebcf040ce322fb4c8d9df2e47397bcbf164298e079320e46fcb96896cbb40caf6210dc0c8f629c763ef06e5c55341c8d40a0d7ac8f425c743ed945c6690a58cd799e4536b2f4cf902d3a2372c6fb6301a628b2fb2fccb4511597eeab9d892e57b5c88c8f227cb06292dcaf820cb2a240e296bb26441964e64a9c550965af0f03ba4988470eee5410bca5ebbdd2a591cd94b91d0e0ea9b464ed3c395f15e661a4d4083ab8fd2f4703fd825ab584802818e17e27412d8e356f89fb5afa0fe24fd2cd05712462fd84385f9d963db6338eeb87231ac67922ac8cba3fe83f2822a9af62756cdc79e621df7b33e9d8f59cfa63c2d2274ae2ec01e73ba6687ca8e52489fe46198bb7342fab5d7660724134453d4e9246f8a34b9b3562d0bf5d53b355cc8f02b8d0ff7835d0c90bfa69265134d2929a9b16ce07e6dd4585c87c6f5d3be7da04c3b6ab7fcc3a7b80ecc810a9828d1440e4a6051854b7e6711822cbfa5780e96e5f751ed5a3edceb5e62eaa456722f56994bf1bfa62899b019a4a94cca94e964713b1f999f1965140d0f37665c72e4a14c73db3a2d675d670a515d74cdee9421fc319462f24f3c22230f5265f9feea1d2ccb779bba9ff2763c716953ebe82488236d937c9b6526d96deb66ce01c3b37892b7ad53f90be2c8afd9e6d9a9bac93df940b9773871e9b74c0ef7eb6c764079eb62ae31e3865bdf5f5147fa5331301ce3825ba708e99f581504fbf9534a10d803e56dd3c9e27e1300cad9678d23613ef69513321fc31a17c20c329ffbada3f9b1eceb37470277fac84d6b55445e1ef54560fe7e09d0a5e485178cfa176052b7e35e047ffb5ac661f83392b139bbfa590a58872495b9ce19875b29c93df9314bb7fed749744aa7a1b66ccb937b5590f9d99f18286b954b0045f950f6a06e8a79987f79992f2a42e11ed4cb601f144621dac8bf494d591ea1ee0f51128355f55f1ec805835515c7af18857de8946813eb4b1b6ef61c0d296e96d96fa128c32a217d8476712f4a39ca165e91f2a2536667e7788664540c88135febbe0dca2b639886e15e7ccae4de07affcb0942d46029b4840e5f942e691f9d86b939641332c42ebf8e0951f943212d8942bd099621d2adb2e85584619b9c6a71d2acf0ebe18698e61c08e80724fa03347b934855f0910e65ffe8302835f2d141d4152241f09862520312c9d5cec33d94927777b6d83f2f282fafb309f7af917ec53040383e19e974f611f8bbd546a02b92e56612f188665a70a121f024079e6def140efd825da6f49583ce7f413e6e73751d4b93f533fbf9590803bada475cc9fdf04e784210679bea6759e372dd8d738fdb6c5ce5ad7f9a475306f5a723fc6d46fa44b56f2cd2a723f7dcd79050c79ce258803637f4cd73027807b69c3e5a0c4c47450b499329ffa992feaa1f1311f13f3a9ef89f9d4fc180ef7c4fcccfc184c03b75e7e0656711ff3402e19ace230f73ea87f790ef7c07cccc7609ffb300fe4c27e83e9e894fe8b4493a40d57c32afa3067f87b1a525c8b6953ebe829b99f7628b82733a0cc371018a97a27e66e7550d4a9dfacdcdf2ffaab192ef6d99bd0ad29e9252db4059b4da8148db92439e910cd4800001000c315002020100a05c30171402ca0e8a1367714800e72923874543494889218c8611443310c04116000308020428841062a1a3a0324039395ae1164b40b9cdf92d84fd776aedef2cf8ac5364ffe8616c29a01ca4fd4d81fda65e852b6768406f6315546c0375096021121a6f18918b083d224b8a295fc3476b22700c84af806d66f573e0a1409e316a2f6eabc588ca254e6936cbca9d16df08e9bacdb48aacf175cda3d05a0293c26dcb4dfa84e526425f2178b07ca9e99f962ecf52b1d0e654a21216ca31a475de7c8194a1cdb5bfb96ca59b03491739d8754503ab60cb83ec6c1528cc4432747ca6e552d2f538d8bcd6f4c73902543877ee0927abbdb0e97093d82ad624ce32855a0be24c2b2e6c98e6e786e431e36593263fbb7f9a924846428faca268906b7891d4f8c732d1afed53646e2273d4f0296da96157466b34395b954d4d9bc97b087c2fcc73e73411c5043906a1dff2f872420d9c412485caca0c131d32c52a1198e23ccdf2c815078eaf508c570aa2f29230eaac0e02d7ff95611532732518ce49287084343731aa0779dbea5ca433705bdac2db4775c84f5f379c082a3d3911b02152f499549a07aaa9373f0f8dc80900cfad49fcfd26c780743ae37e75abea52b352c4c9e33236135d3635551cc63c8aaecf17c4cb7f206ffa257f482d1cf938f6e0ff8823eb72e4839c94f9ac26aa2cfbaaf9c4682b04f208e5ed387599e072d2f96b09fc5b08b907a62851f96ea5225ca92633f9e5980af0989fb6be3ae8758c71375442deb0739e3d8003692089bec00f5c7e0133ccd44bfa48a889334f6cca893c65871042d8e7e586a8bdeb94bbf9980daa80ab8b399e5948c453795b0c0f9e433c8712802f681fc2fd440f5cf32ef6dd73796bc0220702a7574a42d79bed87d42654541c87422146dd07292e864f9f0460c7cc6c3611f717af8645857423d6faba1b7c52fc15debc6528546b2ec868762cd94f6aaf91cf4ba54c6a21a0978ccb8648b348751a96c0ab483a268091c0beb3ba430d2ce83bf3e905c34869065fa6753e2d514a20919874ebad156c15927303aed5a59404217dc3e47d78fc4fc75357177c6e337751a7913b3637703371992ad3b6ec88083fecaaa2130bd2af795e1da2988336f2af1f3ad8130ddd1c5b4390361af02e59f1f5629c40f2adc742bbe38382bc728d50fd65970f00c0b9d697b13c97cfd74ec2276183042132ad2f323304af0154544ec4bd19a0754c1615d3bf9cc8ed2c4cf50f6a89aa4426a9e300f9a2209b9a276ac48900400db195fd286a5a11982e9cc1e56330897d5cde5b619f709b49833ff50d157854f06c1d96913d2a22617d029d578404bde1713c05149a8b742e9e18d83542a8cbea23a16a5d3101725769123931b5731be32f104a989d6ff64622f64e3a9346c7938f9ad5b0c7d0d9f9f7b948e2f7a1c3bc882c301650d0a4953902dbe4ce367328508ac7e9d457b17ac8a7a19a25547c48520a84795d7c82544a084fec6c397d7d33d09b958f4aa3ebaad335612f997ca526d3d1023f56056e11f10f208bc25c76b2dc79937b0f90de9a71684605d164472218ce6d208f821736e6307a097759b15513656c47d84cef3b540edb53ba61d95603a4f80d907f42e3c2c0df09a3a4371ddfcd5443cb4d1d9efae445eb2c31bf6b8ae10a65380ba5ccd1983f5e4f51fa09fb098ab88e704a3830911b9e8a5e35753c537295b37ecca9b7ed90b8db1a05d4d26cacb2cb87607c4a5d8c6424d1fc927646592e92fca2a8b30f504b25ac924c504bd51d13920fa8ad5908c9713222b66886131ae645c2720906f379d80ca521d3d44f68cbb6982d1a9542ae3cfd3cc743e763d6c85dbfc743362771ea4dbcec853235b6e4bfe9d032861b4f6fde5dbfb3a28d8bfb902915dfcfe3fba44dce473a55f7da2c359eb482c09a7a13484def53d524a241c5ce9a483369de0c05e279d83a62ab750c6061705f1b09e4fe78403b5e4380d43edb16969d0dd74c3352a62b4a462b268b14dd0d9dedee94a611e870bc268d7e5f28317a98b478bf8eb1f46bf024c8fdf66c620100979539cf3f746e32d4362128840fc429448eb14ed4a1cc6209c05ac60ada7076bb0a2a966ba0a660e519fc298d53275ac8472dc509f48fb1bf22505505e40cd956639ee12066518601ed6becbb3e9d022244138f45a310143cfb0b8abbd33c991d4b56ac19d974b878edd72cea908d13aed787789b362a799eaddf61029ce599d159ada719a7b3c6bb44cfac4221aa0d65d33538338cff546da4ef59a5c4b40e1c72832d069a45799043d9152af09bfe5d801956d07544a867bc0bb934f83c922560f9d6573d582ff7ac0203a82c789b1ce38080a8f79ece6c91fd13a6d6477f0312c8b30f28568ab29071d47ada3237ccf8c2403daa58ce953be71bad30c18e6e5f403cd2d8563a0460f00ca460945ab796e5ff267a0c12778648f7894228ec114ae149a1625bd94dda7521fdd5b9676fff7109f9698c240e5af5538d9ab342ecc03bf676287fe1ca0427f7d9f27f450bbe018a4d3fefeb9f32f7321371bdf082a92a8848f88c55851ab4d63061750547b5990c229f98d88c6225740b5863d72e4edd1c69be141a75b734039d2573ebc2b140410ccc3dd3b745c576adf3191d1a52afb86fe232b569838275a35aea2547ffd395eb71cb91c4b1802f91f8569204bb14a34515a2f89ee9a8da91a50ecaf0eca43207bac8b89e905fce9c8fdc1d0108d4255f41e33d90af6387dea087d070d824759bee695a7b2f79c9ea2d3c43f14b970bc9a9832f1d2aef8050949cbd05e4a39d455cb98a863d04e092ee5af66dec3c13cdf22d98792523b677abba7456d74837e3bb1290f183f1eefef8cdf11dd7b9346284669f85c3bb6a07dc6c59dc9457ba6840cd0ed355625fa58b26a143300550b569269763056d01b360a8507cec4be789ccbd70a0ba8446bd4e968b21e38611371476f28c40aa946f243cf9af053fba8493ce81511254f02e11373690b1372b382c7f021d00450f8cd0ec20be8b45a4d7ec73f65a1b0a0ac4aed028ef8525903a2230802574111180c095c0d19059f04442fb56ceb4b94481c29981e8ed66e950ddff73e3cc98cfcc9ea995489d818ccb1809c8889e2104d9a2caa274f786cbccc87a4f935090c0423bdc027ec101df4e65c0603365ef87131d21bac0555d08a5c4896b6a2f4146ef5f994e3555c3ae1a27772c18813a39a2ca317ad4607cdb0d13b39c1a043e0f59a5a019ff81f875da0c4ee2206b607f73af12598111fdb32c81f019ae1beb4ecb4cb9440acc4ebf83855919c0a6c273e5e152375d65d3f0b6eafafdd6c85c27f98b61675cab783c10d8e24b91b4dc4b995126d2b3ebd7dd7fddbc6c5669ddfe27c81cf84d374274c90626d2a44ed9a7c62863d38904913d562aaa8bddd1153a360253af6c479875580dc4319240d09795b0f57e48856f332981301d40f86db49602856543ced1044c209e5d0ae06f3675bb396682e58423b5e717a29255a20194a06118926401f23e85e880a5ce453fac4930db925e1afcb73b79f5f5f5d00483c60e22fc9f1593a0065920e70add1017cd71f1a84c83c7611617e4a5b7666bcda85b889ae18cc6270e1182053d0223bab18bac7a78abc9ffbca0b8382fb4f8bb13c09fddb4d485656bb3d6e678029912671f43f447cf9c2ebb5c14f876594b87698458c20566e9167546d646495466b3ae08d44387b99cba80aecb2350a831008591cd0410d0902dfaff8843fe0c8d9ac1f0650e4fcfcc827a0671c39e15e4e5f4eb399bd9f28f67513a95aeb5e7448667540703290bece59e9c6ac3346a4969769c5f6d2265a4692b76964d1faa6c162ae3df10ea13fcf5fbae7a0eb239327db1f2de357084afedf8f65fa8ce7eb80965afb4de533bc7b662c8f2df9b88d3d9d76c683716779c8443d74c61c534162a7c8d4ea8a90c35349b3bdd725255467f168c447525b6dca6ed99921238c8136f7aa8adcf4972c85389bfaf928a59a81f26f85cc8674080fe89e19a0faff35cceb78af9d265e978df4cc75ac06249f12a9838fe3f4b59427ffc7f87b790e0eec5e03ad41c009891c254afcd95e0cc727ee13189cc458a073f11f7dc51e4388ef4be00469b5b51feaed70becc70bb245df3e52943ae6279c967670e0568617e3f13000512f19de5b5f138b251c56af9483edd41f9538504de82f8937b1b44e4afcf2a77cf8cf66fff30cadd1ee862d89111fb69c5546116a9a16603ea57c2a40a72913bc1e51accba6c147160f256fef859bdb42f794f55e5529374ad2cb909e1df2410edd57b023786cd9a1c3e24719d9116bec17881de531845733a0ac779e8c1c66c6ffbbfc59b716c5ebd8ef7b537068f91f263a3ba9a7072c95e658d8442d0d304c2349094e45a823b4a82de61164814fd4d15dcc54c664673a7fe956be4167f82740b7a45dc46a0e76cb4bb091f56d748b14433e97256027c9dc205975e975cde78971b72821baea71d6ebde0e523a44c945e32be7a07ab764057bb13d1e77cc91555560027bd136ebc9cf0e0699ae74f19b2fc475ed9866ca758ac350f66b02764cb47e4b8118ac97ebce7e9cb774bb57b7ad6defec1f393e6f9ac5eb8725d6db82c133bf418a697aa95e8d5e910f9603ccb28491171a4c9223fa3d878c73850432a5dcf783e7e6ed9790c81ca9c8318b2a9e18acda2ef9f9755c0facc0741a1d4388dea422770886ed13d70f2845c58bc97672ef68e0be6a2a09e228e92ba157b4d7625356705c637b4b69d0e2f229268481bc8b5439003c05f7a85e129abf8ec524a75510278b9d2251012e6692845164f85b36bd0851bfad7f5c2f241e60d92c4ad11c857edd772dca8b5b637f5d2bb0e12a079cfd1a81c369a548450b60d0d44566cf9022101a35e9af9caa0183927b907d77daa631e4ff7ad08277bc4a2efee05c049ab6e64b2ee57ce82ae01ce71df8d303fdc7c6440398e2c7b5d11e026abcf645d04f6824349fd020dd80df1e256a92890a169cd56a5a85186b0b3bed2d0aa0211df01f44c401f0aa7cc54b06b5280259320bab0d7dd68e2871db7f290871539c0dd91ef1faf3b4d49857d3d7ab42e20a569ded80ccfea5d53ba8a3a0ad9e496894daebb4fdd6d14129bc644ef55b6444733df160d22acf63fd427cf73088396df6cbe01d16fc30051cf131d265fb6e7d9c108033a0ed2d2683b416ef671712460a5d4ce3898e00c58b962bfb74919d06f019b4f0867b442677c924afac4201dc10010a2285dc2462be84f7832ab31042233c0b90b1b2446d529516240b5fda677ef3a9bbed75d5a4d810b1c16cf0f1a1a87d900383840d587c0813bd1705e62c47f050e5d156536216f9df43c6b62044a0ee04f9e3e11c9c572f8aae358d06cfd638d9871d1bbf1c749cf05d6a64214af337a12caea3a8649070efe59501c29b0dda634278b6dcab3fe83186c5fca89138d54196aab2d36e2297ea8b47f67f53ce577873aa391585321e4769aef57276479f1404cec9d4e297486e7478744a9ab6489ac54d1ef23ca482ed45799098bd03684e6e39be035e9acd296a368d66908d6bb10e569e66bb620a1d414b3438212ab15c520d8d64511c2c801871142be625ef70c0638d2a10c9c5310887744d27b009d8e60ca6622053afc6cca07ca7825cc20587649e61cdc087f2fe4592c078507e4590d0685f84bdaa0f68e2cfbcffac4e9b19fcfb3c9bcf63a6e5f76518d7dd7ba1801899772ab900523b4869d07af5450310dea5525bcea76d0782a87245254e0b91030b9f08f531e8ac882fb1f4770ed4c027807a9f60667c0562878ce56aec85d1a03d45a2a16747cb49a6f7623aa139903b024f4305e6015a29008196844204148b8c1ea8fb7d56b79e5282bee986eeffb91c9f3250bbedb9d57be4e42bbb44359f4fde64939abfc16573223321f9ef6d9d5b7be3ce80c465c0cb842b5739ad8240dccf104ef8e7f6793f27d5d1921da879730c27d472237edd4497e74dfc39d171e34103957a6c8f5815108f9c2fbe64b28282b9843dcc794580d3206f60bd07c9a6df9d5db9e1082817ef29eb9df5aecf649c38986989fb3820c30648892e7f4543718bfc7cf939bcabb2965f9210734f14dc7b251d1c27095a9b806b460c6da44457d4d7783c4cf0065c4e8a2a5c03bbaef663b7c1918359ec7d1efc4234f764ac61f24031c012887f4318093725fc23e96d8aac44f80f4279e720c7ff3bfc1b92e127497f50fae6722eb0a9354e1d7486d81b0ac0fc3d018394627ac49eb9955ce6983153c00626668d5ec09b7d423f314d306eec73d054fa930aa4be78a9d31bd07bab0df6d351e37093a8fb41b01ca0abb4809e94bc42289d4457d7a983d902ca6340334d4074c58b1afd5fdfbf1c5f305a7c61ad5d491ed09b80269b26c625b8dccd9036872a24b93fe9be5dc8eaa171f4471e591eecf747d2f713abfdff3055015ab3cb3e2b9447cf498cad075c01607af482640b68e4258143712ef422d49eb04600c1b65633e7abbd2115df1c04cfade84b881f8099747b42a6f07873592fad8614298c1d6586c503472de19c08f12a51c4b0fbe08ef61c00c97350cdc7a5a62c84331ccf45e40f21790197d8f575582b40ed4a05da4b13939e2094624a61001b79fe7a810f37a0fb07924c2a4b207745e8acdd46c20bc8bb955dfcc2d0588995f2f9027ec38f16b4e8c8b2638ef94a6498d5cf9e9aee62eaf6c053e2c39258504c05dd4807cd07e0f155e3d7119114dba0b03175053e6f601ba08c5a0be42ec239647c88c95954237f630a841733c230d3f18395648a8fb399e828e400f9b4276ff076c726526fa85f40c746ce1b5f017011c9e562d826c07e0021a4e1db789af0896987c586cfc76b1bbd9eb8730d29cb6dcde2a6d23e0243cff3ebf19bb63b52762d171c5586eb698606862cfd22b9917cb44101e634a8e2ceb81bcdf08cf0dbab94a1eec9db843262c2c8ae200e68312c3a4214d623862af842675c1b2637a81a71563986fb8903c52e73abb71ac7b9a21cf7f8148006af02deacc82b591caf503342b882731fff7aae833b6b17aa0f81c98575a61937e91a56408540b2330da83e13c650c7a194d6020b452b9f094dfcf84a4c5a81decf9c4d5e0cc6419fc6901207d18aaf9860b04cbdba03838a159e6a03531633a2d40ac6296640a6b8f8efd94fd6596b91ddd7a08d63f4fc5f0eaf8066fcc31d7407247d27e2e814e0ce441e2c48a97b69c8955ccb86d1c6a6fb23c8cc4fe8dd56b005486750e4a187a443ddb21dd03fa7320f8c03f5da3c3f135768b2d55b66399eb49881fcf95b6928461c4a67f9ddba2652adfad4b47f6f64b8cf2ca4f82252974ba2ba88f977b6599da48fbe8a40fe92989e1500a43b75e46ac56637e24fc5349805e4b8cbcf3489f39d4de3a8784f5ac992627b9eb1e01561a2c543414c818ef396244ed38541144271780d2e4448d84410ff7baddbc100077033ce4562d6a6fddb15ea05f0852b3c0c398e6a0295bfa2d9c90c14ecdd29c937a21274c7daec6c84b96cf3140b3d673fa640766f079528cfe4002188b808d9113d49f124675dcdeb48b9b56b99f62c27753f2998762f8bbc3cfaab06265c2c9b0449418633456d761f4996230fd485db3ccfd3150915e68ca62e8f0340a025e549ce67b78f23caaf0cf6eb4d662e8966c96812d701ed394e5b3348bdd6e4a88b0fe1ad3e06591c6f547176388a764d30c16215310c3e86220787be2ea31a16b37a3e35b0bbd36c8eff5c88a7f64b1f9ec61df1c402e399915176306113c9f96bac1411d41c3c57492941628fcad6f163f0cefc4a02f75312d7cdf805f65107f5312f166c531988b69baa14d774aa5df42c6412c26196166c716d4378657d94152fa278b49029156d73673797fbc9a542c0487286310c99111ffbf5c6985de20975323815007410262b0e0d0e3bf32f6a265e5bc073ab9474921675eda294eb39caf4f94212b33fdd6b206117da192bd5ab999c20e7e18122ad551d0d48f1f7e160291da91440a473a3e79ee7bbb5ae65742a745843266d804199fa79f1d1927fbe277e598925f3326a8502aecaa92ea5d3215d2cb95898f3f13a85f793715a54f489e7e40c1693e85ec143c87a9caa041a135815d504651414691e87941c15ecad6c7f87adb76624c91ff9501f40f2a7aa59e2947a13b8f9110aa3c23d37b14b21a3a3e975097186e454522fbf407bbe02c91c1c9ece72dc141f1e99962926ac636ededff9db2187e208d9b04df44f9c34316d217d9e1bccce77f2ac23a139b5582f1c18fe2fae14fd92bbca23302a44406d8c6f5db67126f94c858c549a1bed0e30b61d2d1526fcde447db6bd03d1e45c5a7a5531ab6596ff15babc2e3bd5bbb18524d002daf030b5673630c149c60ce10b9674a0f3af231caa2dda0619121f5b5ba6e96648da212b4e5fade50d29428a4b7233279bc464e910118658ec606dd313f5cb0b5b640970734c767bb62ac5b50ab25bb21c5fe8814f2cc1ce403b1b4aca4677de904a473088a4ec1457a8a4428c45c3a22c046d64d38ad032d923047957c0a689079a5d645137e90b3263d5cc321d2f2af01e98c4b020b1f0f1ffc450bb6e31f650c9560c9cbafc5eb71f16ab4a2d0d23502781734a1450b39d4af4440ab2ea165797f1305a0f365930a685406187bff7ee6dc52b586d566ad416f3cc7a47f1e95d301c12092cd25b280a00dfa36c47d0f7e72fd1b41cbd2655fe6cade36d0723e7ac32f7dfad522b498fb94a5e026530c1e0a38521294df79735f4cc85b4111e9d0c8b8d4dbe16abd5458eeab230a628c16e7df65f0724d9b5d5afa565ff539bbd43358d88bf36a35c8eb8bc069d50e9ebf13bda73ddff91e961fce57d910544289f182b779e747dbf10565c4e778e7eb8028ea9a980433c4b4fbd694eed95f41f50c1fbd24a9d9da3c5d590eea74ed9eea3dd8899168a027f96008522f138310c6f3fee5e4136904336c90080a2e88fe2439744ea98b4965c19e44d6e64ea9583870da71953be00a118b7a2888cc4d192817d13708858fcbcde4a2f2aebacb4dca5009e99ba6c23a381d6a9ab4bf68509c9b3c6b050df92053142affb6d20d25a11555becfa24712ed947ce00071c7f7dc3f2ff0474353e92d515259ec8826833851d6475bc2cd9c2efee0a16a13674502268347dea2be41d3b11a64b0d0633c8b8de9489f7fbd99b380978dcf4248ae5520cf3f905e8e22348e6d79746fc196f3103f5f1c852e19225dbc77fe93172891f2aed11fefdbab2272eaff910a94fe082862faae5282d8383579b5d8f15399627b988e62994b257ec365f2512a0551cd1527c4b8e0e5003c493cf9ce38dc59b1213acb908b7d47a2dd2e72fce53b82eb6fa2e04218537086a8e1d54d99715f2616996f19d57a7688310fd0c5092a7ce1a5758cf788fb5d0971b662e7262edc0c81871ef5d0b65f0a8efab07c0dadbce309b162ed544377ed3f59108ff96f8971f88b444f09de7611c023b2f528c945d8f52e05b6b42a40d852b7119c44ce3f5c8cb624c8b8402a35602e60685b71001d20c8235bb5cae0d1b0ed596433ce91448d46e05f465204a3025ac365f5d8051753633db7704d82dc5ea852c722277e24740318e770fd95162df90e9ca9c81eb0390b00a3f37f51fa494e9ca6d7859d0676e4d9512d6e4f49e22bd3e061e8964f83888e88c99536ca31e2bc0d15979007a5eb4a6248b845a039ada456e9541066e9ac46fb817114227288e692670577ceefe54814f4c3aa7208ed60c14e71c1e331ad180e6a6dce1d523b5a70a2a7940aab8d5954f030ba7ccc7a82079920e593aa9d37b6fbac9b76ae17ba5f7243b763a796be087c43fba20aa8a7384034228e9156105fcea086e476f6a0f5a53f346cbdf49060bcc445dea28082660a14968d79417da7bdd819c79abe125db981624bc0558ea74f906081a85bc5a6a5e67526ab62a814c0819e64d7404d2e14de13d35ccaaa1b8251376b8781c643314a5cc0600f8edb5122fc77a0ccf8c1a81b1e7bb3d54945503aa2a0829770d88cee1a39a5f079886a747f176d0aca3c234af29d4559b3cc579ee94193dd6bb1c2025234d65a75615b802f1da32e31e8d5fb1b70952a921a2ac996637e473e7526aa048259ff0c20f7712ac99cc6d6f63a5077980797e232cd030c5d6ca9a82fc6090f7b13575e3686c760fc2bde582aa44d10bdd96160831df199cc1daea2d957ef97b5843f6d7782191380b6b362f0a939da3fc68f784f1b45f59d89661caac69342222b3056b3af21a630d4c6a6133301c4b3c5632abdb56f88458282f191d6125f2a24426678b7f963ad5a13ea184e903822eb0434d80bcbb61372846385677b33cf6b0116c2e04c4c2b178c8e8fa344fe0637f2e9c5c4cfb576b8eecc3648c5cc98404a868f82812356d4ac055e06a6f4f9a07238a251fb974911e9c33b8c8279f40d716cceaae330d608ba66a4fb89cc6a29a7b922a8853a68e32b3464e2b182e353995a1c7d6cb04c79db743767bcf659b052729baf783a45145855cf2860b063fba20f55a8e0120e0cff13b92ce4a27f4299222bb3268866a7bd513a0dbd7f9e97cdd13c414f223470bf0ebcf6085c201ac6ac2d03d31e584b9f27d5b72aeeae5e979d6ccb48cbaac101e7fe66d95d851b376a8030d47080d039876e7a51d47da79e8e0bb972e4bf1780163ff6a6f83935496e32fc8acb039124b5199e9175cd313300131f59c3797ad80ac58ba17579ad73efc98f31ec93810cbdf65de2a53002c0590db69edeaa170e69020cf4a20002b4bb7903928fcac1e549c2915eccf48f60aad08370aa9017f52558a298d6c099d0285ee71d29f19dd6c08452eb1ad8a0733385ee2ff33010fa2531389426b5b4e54ede7b747705a24a7bb2fb0955c68c4165ae45170bfcb7cef375772d72f0f6c3f0edf870737595c2e1a4eaac0335c5957db05b112a04ef236e0b5c07e03c7073c20e0e794e5482d3889ba0316cc108f82f0e5651a657e3e8f4c88e071bda860c2a441660a04d8abf9f4edb97e8b7333ad28cf8e3471d1b1672859ba313a785436f50fec4f6070b7564de8d4837549e757bc980b8370cd88341e33047cf7f7bfd91161b4c3e5819028119fc55cc6f63ff7a94498a4f2146da03786ab4990b8b56033e3634a7ad98671ba24d7676cf0064cc193c72fc4c967152666a860fc867bfd47cb60ef0b28ca29a22a1b6bb1cd86d40cd5786f797c8a2ab113a7abbde8fd08b80ee8ec78c5a69426d06c1c8a9a69b55a9d76d697ab6e780ea15aa29e6629a530379ce0d27f6b12252a1b3fc18bcbb88ebf3b55ceacbfaa0828ab185567d37777bd2d0e38806a0b395915d018b8e120cd9b82f3f95fc5b95c5d29ab041829209e0926a8f2306f4aff07b1250b5a935250afd33830ac6665f13b7692a6034529446bce7137a0aed25f4b3330b62fc75cf6482c0c59e96ca2aa847ad46392f79d96ab9250d13463ffa932f2eceb94f51bf76f9c19cb1d1a85fa72dd253c984b3e712ecec5d531ca03a2738f495d918bc55570c21035624358e40a68114ef338a403ba41618eabc1032f8805e1ec92354bf93ab7135f4a484f35b094929874d460099ab4da504bc22a2904a35cdceaa702bff7afc1a0fe52217c48a62cdfe6bca8ca16081086dd39288d616171acd4da2e24923a7c6332ace2e2d516a8d3f69f4521de6c177e56dab2ab195c1c3ed99d21ebbd3d0b32f84f060ec0ff7f223bace58770b8a0484648eca97604f6fab5e295644ee2f6de1d13e4e2c48e68f3f439a84666f4a83d74a151709983ff08586476f52837c17c79c77800c44a776d5dae895807266d6186713fb07320c9b894b040aea8cc16258555da897c19f8bb629381a3807dc0826112b21c232ff6f339619845c80a2682573441665cf211d059c435009aee5078b326b908407a472d3a4b575b64214a1aec036d6fb4b00ba91023ccc97f73910d3296645653007f8a0ae20dfb26c3102b53fc482472aea7de76137bdf1adf1ce0c03f832d37e1dd9123a9ece3daa140cde4b5ac97dca833f5711e3fb58c57dba799f3628f2ec756e2537b5116a956fa915d294e3daba8b1c7f6ef1d3982394cbc127775308ca32b4df9583d470f8e568d776b28ed7f45bd41436086801eb1f192ca6fd03452d1241e9494660b1d9b81128faa5a5c6498ceffefc83b92344464089b207b0363b4fb714b11530393b2e3f001fcc2c5eab7522bfd2cb9bfed5872c1d5c9c35cbe886eacb90f02e2fbcfb779784a94265f8ed526e495b3b6c128032e4fb7408a266fbe1e2ea65b1c12a113964b75ccfc64c02de1bbc86aa7c20e87467c9427b8c8a305c84fb398570b35027ee5e9d48fa40335e850c7fa244265d67f87cead8a02ace84e14b77db9d1bab7c4f504aac790ed7312b7534d352276737302c3e48ac9e11477683b993a27cc3eebe418ac0615edff517e338454b84a5f3e6342ee73af366c03bb40ea27b17afdb8ed4f71d00722cbb2f0097465831099518dde2c00b7b9409d805a4c625e7979ec8f39e8cc7d29e97f7b76450d0ee718333e2ebb86fef77eb587e5ed5e9583ef9f8856e5cb8fc3350961fe8fd32800555ef84fe7cfa355f7639152f669eefb79fd56c70da67a91592e89acf2dbc2eb868c0189a5de7abf16a8a474defd3bacbfa213c50b095210a6c07ba1a8df6b0c204bdfd39c666bd154d662a19601b653e17b371eedd01edab607ca808a40d9130dc07eeb095041ee232ec8af7fec875046a85239b71a50c4f482424f2665d62e27cd4e325d84bbc57265f86e7e81fe6f256c7fa7a92dc3edc34fa101994225ce50218e4e2ed741fde17f6ee99a21d8eefe22b86086428fc3dedd8167e14c92cc4f82b2544ed0583bd3169881ff6143b366a647af41de23d0f8a8526cea7301295b48fbf28fedd7690b23cf294731dea89086d7f035987f804d606ac69572486d1e2f56925103082c416165c1e557b029044b2504f3b0fca8ed1de85b0e7a0dd1ba08df520b69c0deb32f043c2a621c64b538f5ec98f9294b25c7c5b8febd4242f791b3d033439cd3e620efaba7a9989919e511b08472813094ac3b011e4cb13404c8367e2086ca1c217994dac6da74d0331ad72d2e7575c6c41c1a7683a6b8f38101e8270490c5c59cc2113a8b9821b8d33b1c9473831efff0f40af77b702edea010c2a4626e9df10b4effe873856db52455448d7d61a94fd20e4749b0959c7e63b8b4340d3801d6f91c149a6443cf89f0eedff5faff49e618910f1f887e4e8c77decc324bea02225ad41da9b42f1fc405762175974907c36ceb95746d2ea666790d3af3ea4f74e889880cc8fd3e60fdbe15028ef6847aa13eb32a4f15480a86118136c7160d571805bc248dc099e703f748e2eee883a442c043c3ad231d86a96addcbb8259995733b4f5907a1ca936d82b6433511944a07a87757256c46f0019184f0198867fc45623db219d5414d7978dbd088d5669039d43abacdaa0cc86671b46a5766cd88144d442517b57fd657102f4a2453d6c14e5c457ea214cc388c332329ea3b466ae318c9b1195ba812f3d1522e6db70423980f8f9d52c03b650759d8b25c596e87773237890a4cadae79c5dd6646dcf21c794d13ed8e9728d8f591bd68be01609d61228618a3e05049e454a38ad5c3310431856288557cad19df6c13ebc876eefe25330ea276d3a34f37d23def7ced8139d026ed98f65fde722034ffa0c05f1a5f26cc0d53eac8d31dc92c88672c5d8684556f9dd9093c51e3516fd47830c45c3f059f634b51f982c51bf2bae0c2eb892e518565a9519457cf97fe27afcba555b0491f1bac354de849baa349b0c10eeec72632472af614d449f524d22b1bb0236b521639fca5c0c19f0bac4d98e5b20c8019c1e58cf8b724fbd27da766364e4ae7a3731075e9614a518ff8528e31e442c98469159a34c322e1ad1aa59e5e3d3d7d2709f6cda1b4e4ccbde02cc350e64ef3bdf553fbc6db0f06a4dd5b733a4569bbb59d06d9f636c5751ebfdc329477d9d7c0a4e94e00bec1609fb8a821b552626eafab9efda71f94daa14542cbe00f5c727cfdd6bb1f3f453b9f899def1609b7264da844e47986dcb0ed47ad958fb3e4030766121d4054da643005e73497ffc36a4301799b51391bfee5191d89740d48adf3f7e0c2ab26d088a41453ee73d7c540a07727c5efb1687985c4f7acc28e0d90f9d9739d3517b3c983f49c2cded6d7f590e2d86c28a728960bee7faf701515bbc8ac572913ddae2283ba29679b9bbddbc02870e9c1d7ed2ee452ca33f3f19b5a92eeb2648bb5b102324cc0ae8df6dc76ef2f5320c544eb0a0aba4603ff40adefd1bf479bd7dcab8c1733bb082f233d4704ce532a3b07c8890a4b4fd1a574aacfd3b4a90eafe01c58601423a6309c8998de210695b14d40221b66a8b83163e820ba0aab59d5aa993188c08a857c5a60939ea83fda448065329c7418ef09a2022cd9c2e734d81dece84d7ab3da3f2b17e63d435c117efe54847363d624bcd2ce9ef5be39ab8511b68b555c1126697aa4816fdd2513e6226111304cd89849fa8c21cdeec1baa0e85bc5e0b91004c6e1974c9026da792db7f79d98c83dc53e7f2725961dac8aa243a6f854e68d95bfaac628a49889d9c521634ace21bef42a4f6ccc7c3bb76210ba047287760292ea5846bb657607afa94d2f9b40bf154a271d892664e9bb4fbec61dad1d11b351918ead6738fcf3cde70386d6abb527242a39174e29e73b881d4b36d27ec4c955fa4fcbc215030e67e033a68b6b5808e0992169ed1fbd4bd137f0257035e14a6d653e9a9fb925f6576a193dc6282f7c29a6f82e02dde9a1107875e38ec0b275f6239f4327ac841f09053fbd4b958c894cd6aeb15bc914ae631a220cccd3b0d35fba357ed034b00de1cb3560dc41da13f2e782672a169801bc46f49d86ee03dd7fe55dae79c775610f09660989575e853992693df3458d0f0a2c0f5b974e5c0ab7122e6c7e97188f44d2b80ebc2965caf5b11dda1bf705ffa4e8fc1200166a72f8ba6ba77b54601e8bf70a652fb335615e7ad60d6c0df411968aed0168e448eda5198f780886c0814323c616d42b42d84eed03fb7aa9ce1584437c7d10fd2ffabfbbc603c810e89bac01f29275feec499c643eb77c121912c354f8d1777a4cb1dccec39c2328ee2eecc8ba6ae8c725aae18f21d81585ad2890fbe5c8bcd1a6b9f6ea72566090f20baf3984178f41c9251a82222b1e70343b500c55c70098b9ab5d0dfe08d4b43cef23630261606a14662e304873ee9a8d5f8d9014b2dd8f7af83b8a8dfa57a64eaaa6b9b125817852ddb70c216548afe0dc7092b26d1cb2dca29326ff28e81162ae03bbf112bc0750f740c68d323352ca95f92d5cd2c7b872965b2b4c7fc295d62f11407b61ba03783f920e408d5fd0dadcbab286b55b061b855d12d841f5e8caa60ee03362db1b6d2c1ff1cfa02d6e82c35c57d5beb2b0866595d7440c72e058f98a9418f86abdde71b352d1531fba52035b42dbda41b5b2de98f3cb76346a35ab3f2006c2875c9f977d531ceabf5b28adde219f8908431717f33dcfea93b02526b0edbf7bb3b36f0218389a74e29e8bf5d783d3ab83065a38ef63ad4889832151b6bde9bab6e4b008d2ce03996d35795e99d0bf4a3f03484564fe26badcf091650def45e40ea75cc430e498c9c70ec1839274bc20417f90d776a1a52e370df9d17314b8e5b205b182503251f1c245f26175342169db628df3535cadfb11cfa9204063b44b853addba3add57c1552fe91cd7fdab98dd81faa1fed9b8e2a32d65fda3b0b6cd7890ddfe1e54f3b7a7ed3c48e2979113f2eca4e5b3075c7404f717212d1c4ffe1d8d0a442845bf355bbe7fe180ec8b33ace3f708a883f866c0c2373ba8ee8bfaf423a113b227e1f88045023515412652b318cbf0517cb6b3e4a588e5a73859d26c117c0ac3f77a59a4554955485821c01df0a078a8b6543231e4455ab9456244bc39192470420489e7982ffc90ff3e8a203b23e2862654a47af8bfd307e6368e3a9a69b27c84d134c1e0371b66c6078aa009d1e53d9773ade5d64b2534697f7946b2999f76862a5aff297845ba2c847652068e43830927ce58656f035dd13757a9bc55a92fad47e7dc5ca8bc42dfa60856cb82473d6dce270d0b65171449255c04d206465570f79780ebd2907a216f6112aa96856adb666e4afd02cd943a249c0ce948d2e91192fd18e298f18a7862c9472f290e9d9254210e823545f605310e19acbba0c9c235e6105c86ac70a0c204b945d33bf9cf45df376b02bebc790b18cb3d422d12a9918dc01c611edd7db0d5dcd9db8ddcf761e2f6aec5ca7151677b9ccfe9cd25c53e588e4e95de8389adf0f020cc5fdd08da836c33cc4503790105054517c2b61e290b1818c6be015bbbde6b6dc2d9273e54e1488ad659b220673f01489d8787264733a37a53295a8ed7e881a11259f976b0f79d51bb965e4e38c6ce0e729bad5dd9f898ae5ec812d2e8e5622aad87a1222afb9543d30da37628d099e0899c459f131e8112cc3287084e7cd2ec269db488d404a34440be0ef505a290d6e4c5941695148c3839b443f5d48a96c63eb01ed46bbd60e9b57e414c2860e05eb62041290f9e7e794f371faf842ad2c79d32789c70ebe1197851816cde405f772f117b3c0f9fc17930a3ce8c328c1d31b4e48cde913d6431d8a5b87b1e4e9fecfd1c4b3d4fc62191ad4c2e049331e5d75a652f2420cb53040acf70cbde66d51e719f7a3b809cdef7c9d7c8f3b10b48c9db2cde1d0827b5aee59415081fe44741be81c2421ab4c04d89f56f76de64a5ef0359421300ec013edd52db215cf5f0b1ccbbf0c4c47075f3916d47f90970d15cddb0fbb65e91167ab478effe40d20fa8cec587a77f588fbd8eb4c18bd13086172391927d0a06e9d36238e2003f92acfefd64f09d1c59b18b706be370455fe66d6f5ab9ddb85f48d64b4aa0f8ef478982dada015d086b7e6f5083c2df88fb53a64057dea6a9c570a5e42a707497653036756e95b5d84f8a8e0baba9ccca6e01f5976f7c5a7925bf06553a0262ac52c3b8b2031cda6e8464921f6603a30e454be13c47ac5b114332fc6fee7c7a98b33853eb03f288dad95996dfcaaee55a8d37190b470a24c9071640266b96e66561590692dbe9c2466fc72fad780a9eb816457b3eb03befc8e65fb083a595b5ed67f88047af5fc8d04f9091776a10b5e428b4e54a2e5ae27ee870bd5535eee39bc255c745e9c2cd3f9b850847d7e706dba8ac5a351b30c4b53e598e97e5c88620a6bae1ec3be9323c7ccca40ab85b37447d11beae646886d8fa2b46735a81eaa7b4df7ee08f02ecc35f9289b44dad66bc94c617a8f0c49ef31d0347ed706a006699f1ffe21c1523d7d4061d2955da07d58bf9936a73927bc249d5dfef46b43d037332aca67b4f4a1ad398c220f89e5d25749607dda57c108a7843c63eb46b48f60899b7930f6b0160ddd9b61c38f7ae412a0a050189ba3fe000fb479b2b34f6e15abf2f168dd589db7afb0ec51b1a745d85686c0946cf4242d3783e81d6366c35dbc0f6e12d06e09bc7003272bbec95dc6826c9d8636c94743ac98b47d4d7c432cf6a92cba316bba740799f1db652031ca4cb2b302e5ca0311c844c4cc76e0b6614e854641693b94bbd1962c1335eeab76dc5121fe7544ed875f4c1b6ae827e5f307d769be673d9b5e36d5c2c93d73a7a370b3c56d91c2bc7173360aaec79c5a46ca9b6e227909faf6cfc5632a58c7c3af4764e24172c22198a2aca608cf3e7d972ea8af9c18b8c149b9f3191bbe19a43b6edb472ed02dc1f3d0bc2287bdd0b9afd13a0d2e4d247dc6ddec8e53b6a768fc124a4437044a58ba986b47186939b09cc8e4bd09a62940c6c8df8de40470031594105670904a41977d9f20c532027809f10606a15e13ab03b2273a9888941e88f0dc15754e7cd05afccd49ce46c209598785d1659b46e111bb2c77d2af4a4353a7b45622d040b18e1cdc2a968a96754ef1d148775dd65d93922eb60336c59971ae4733db2c334814ac757594ac82993a48c49e1a5292c01bea3770ecdc55603312825a7284f0e63e49d253a253b567d148e2143a82023e1f079b3ff014e9ce60085a443cf7ba9ce723bb3fcbcb408747edd6b73f5cb87e706246bce7bf2761cdec151832b324afcab3fe8ff15504a23408f712ff54b0593ae70af2359b11f0216d2d20594b15eaf38f618ee813c6e9f09d3e33716f3e3e8e9564e510522097d81d567ca2516cdd206bc27e71237607c9de71f5f50228211a139240fe43b029d20f9c4ffa2e0ea803cb1bea7387c193d09918969f839465423250f31d148be02bdf3b87f935b934c653d3005afc167acc632587123c26611915213613ce4bf64a2460fb9d264356fb233cc76043bb4316e98eed8ffe0cd1daba0f7608097c6e5f0a88f4df216d4aa6c3c9ed6d3fb056ee6d885a07175cffe5fd8ec728552b2cc617451597aae0da2374cec5eb5978b8953993dfca38de2bfb439a218c846f00294f2aac1d7f7d4be860e1c53e952bb0b37b72a9f68ec7625ed21fa6838fd491d30e0efc82b60f31e52eb3140f888ba0d747f90dbc0caf7256f89a117f269a10c4f82a177af75e4bd57a81aaa8e75c630ad3f37946594e829ebe5d53621f9059258a898ee600180e8041167151d7ba65e95b629a0f0be2c094d7a752853f0b4d5394d920252b096e993c7390951ee49264049b4acf320574d402894fc86ea03a27ec2b337b938e7b2fd9af8abf04192d2e9549e084f5833b839960b57e0a28fe83ac6887f2165c4105cf59003e60fc74d4126cc62b184d67b1448bdab78fa6901efcca2a97b789a5a7986da95a68765bee96298122b9ca50d03e07e76faac3dc6488146520a175197511a2602c295034c60025990c80481dbbc757659e3f4473ee1aef59e9d14e20e3ce072cd5ed770ee673e3289ad49bd23cec1777c4af60978e6ab25d555ce5c2e3a70757e696a0a2c43fb1b3d6dc89162d83914918019c08cad0c93baa46b64dbdb81eda630bb0a1901a8d7dc158e53a02b1fcc0286cfbc4bb65daab1fe95b9f2ee029ef1f6ccc8505dc7265c1988816403dc33a5e8bb4305d2a6e7f792ebc55e14c44a45467c91c1bc379ee2dfa5373ba505384768c9237c5f5dc7f18148be09b6a02122a1743f2da301081adc1344b748157c36ef04bdfbc8d17670d410009a36f4e8712c8459755cf187b941608e51f892a758a51abba5689a669c80eb7caa9c7255839107aae2234be9cb6fa1924559d92822a959e0501e156b94c1bd3b2950cd3a461e4d29dbaed062808a85edcabd133560158a9ec0fdbfa36b50fbcdd95c2dc22ec92a486d05ff5a94a3731eb586dfb09ed1c1c384aa104444bbf551406f5f8bdc10a49c09611334b83440c56a20d9c6e0ea42c9b4485b08d2fb3d2489674d20ec0b6af0e50cffa548b0f892d535756824c7bba8160094d478bc5b6e10e152705a5a9d9d329c58be80a912670b7d4ff758a1967b6b480fb521bb18a48b2e802abfac95caee15b221d6b9dd72768595584c5d7b0e24a8d6d6dcf498a9f262b7934380ebde5907da4dcb280691f5fbb672651bf18c3b93690e5d188aa147fc92cef1abc3791bde43df2105904527f987f176559e295ff9850790dc71bdcc60a1d716843e8535f2dca2707041a9592b0c2d287d5824bf74fa68368dc07a2c6d541e0b4117c4186abd814aef8cf00467628bbe967273c36c5f126e905b3fa7b65575f6e636bafff7d7c9d0fe371fdfa942398e63c94404ecd2320e7f892bdec5c959c6720a64dd0090630865fd1541b3e063c6ff082ef50ba212aa5eb0628bd135a56da81c83544949df002a012394738cbd39dfba21aa7784ab98bcb8145ed5902e4218613ba62d0637073437236e3a02a7f0a563cca9b3a9fca031cb180551fbc06d8316a86f1284f3ffe84021317beed54cffe815526cea9b8a162b01bae96c114a5ce55147d500a20d5201611652b534c274e1d4a26220c08a146de942b1454b7cf377560b4dd24aa4c114b24850f40521b56d4d19e60a9fa634406fa0fe7a25d46e14d8eb0d30aa56997d3b1fa4eb55a740d9e107dd1ab9707ad4868e8b5a89d16605911846c8e74ed420ba5f86a6c545b0142ce366f877e939f336fce276e4313a02409f906bb024e0f8ac7d5a1737437b2473234ec151b6f412a89ad1533a569e94d2d44f84976a038479410ba8e61fa04d39c626d6a042059d2c6b917a375cf6c97db1a7fdc873a5204795ce9293986ffc2d4dbfa0e494daf1d63dafa2a26f0ee97cb1a961d78d49bc0d99e493b2e566d43b34531ae761d8b9a0df17b18d5da8e6a433aa5fb231a92c246671b1c5836063df4583882a64edc7202f6d3dbc96df487254770585871d0d3eaf47e08f431b44d27b73be881e480f62f1d469080b89ca4c2a5f1d4930a172ec3089792a570ad338456ad57a3e500f1fb924af9bdf2d89de4dc5015e8ee764caa34816fa3861b77b3cb050cf29058bf643944211592831d6ee9b7ade0289c058026ee947d2d4db1424c774bacf5426868fc94c6c9cd12f5bc9469e207a85df49172acc92e03118df9c8fc6e5fad69adc342bb4eadf143a387a6cab1d1da0a1400e4222d4c945ed5afbc2f3a342680e09908cbab2f674f79d9cf27c0ecd7d57bee0be9345223403e10533e3f60dc0e665e8dcdd03f6afae734beb77a56ba02e1e46ddf28dbbeaad342b7f1fa5cf582f3114712eb278231aa91913c6bd2706a0da6a18851bf1fcb1a1b3d89ee50f4ee650b2fab209730de2559875d97c61a0a4efeea0b6a86e9a72dab2d2df54d0bff2c584e7df9462a8864ac41704ffac85733e7f1f667c628a177224b6698dc94203a8db7faef7e7d7b05687b15831f4b14f30eaf737ade0ac8e310a39cf76e340dc65e036611029cc51e2971660dbbc98fbe1885a4587cb58e6d2aece7b8c76daf205ea0edf9821dd9f2de3b3b5b634bdd4f42134f2cdf9b9d8c52dcd911dbeb2cd82d6e2961a6d7620e87013a84c6a0f7d0a7118205e24da5a598a11d242ee2378c8bb0b81e69385283863037eed40550fab0305875f059c04245a42efeefd62a67709a6896a11d50d7da084d75ed6d0005a03568c3119d15d5264c9f98ee0b5f9accc813d8309c5c8bcc1c75d0ddd01a669061987042f057a8a0e0071a7833448e0a1940d437877232d001e2c9b5e8ad8321ee1dd02a67e4b3287b203707456c7366530d18991198c25ce8034e4b36df61cbd4a873c8f56bcdc1afbf3623c016765dac1116d58ea98c610498548c45280342486471aae59829761fbbb6a202358e200d3ff0d11dd196c51764a9e4efe12a967c4f07e04fd593b20e406c023303e2c6f4d94d9e014ac8b4aaa1f90d25788eb5d22d74cbc270564891909d2f635927644253aeb6fa2ee0a0a7f818bbaf40e00c8974c478ba45b9f1082aa24a14b0a95be5b858c2ead63ccd033ee3b1eae140ef4a55c3e69bf67b4771b57e4efe92454f7b1d9a2ffb18e0dd284226e79dab7896899ba1790c8e0da6320f6eec4740884076211dc035e1f25c5d667f772be8e37890a87e1c4cf70a00e660e33bc5b9203a08dd2a7cd8748192ef443644c71010812946106232ffe7b59fc70a5da065e46cbb922e25493b17858806e026e9003ded4621c6ea31d37d5cab5741311a936d740780d90f12787d885233396271db389d3f07d175193018e44aaed5b0cb31a8cef981a1bc5a159ef25321dce765f2811b7a1966768a504f2ccb20dc405d913fe11e4fb2c5f323656b8ae6956da2085860246b30e6e5e0c135ad40703afc2daaef0128221b8ec984d130ca0d7cac76a0e836f080a4a4da1e9c1c795848262ba92387cb4e0b8a1d4f29055d749fb6934346e61cf1c2b95f8b86b478bad7bfcae81dff6ff4c4e1fad98e33454babec921126dd17a8a72f887a32c21f5e73b84ac6379c706d6b78d2ad0cb4850638d5053103b0ff42762d3cc41f9721d9cc3cd73fe456e58c2ab9cce588af394a14bcf3683bf611c51ef2cd49ab8aaf4e67a5bd0c3de4059e891a643b68c74623c9168322f22d7818170add4cfd20ea94bf68f3a03f7cabc4e9a256d6f9d8c5c875384ef80e1ee588ea40f9635a94316d712d28a09c20bf3b6364fe01efddb04fbb372ab864b20068fc2fdca68fa8e66cb521216e8b4d0791ba23e63bb62b67376c84cd0c364f5e90aa8e472f02a5831c4c8f1edcc1a849a44529542f0b6de1f335a78e39c2a30ca2810aabe9271ac3d31ecb5fb470a693676a68a368219f61d4474bc2ece8f977caa040cf7a0e2f99e7116e13060763f1bb645de99779d4f275f1c50f60b13c677d41a3c86481226dd51600891388d8b158d191bcaa89c9a9a98738eba3986949508841166b2b4a60a36f2a5dc28e72e88dc320d2f8c97e3e7ed2d259e4c5a528974dda497948191bbec2e642dac4409ef4158a0eb409ceede90e318137bfa48768a2bff4acbea99f221d44bed931a6144b6f188085e4ec991e41537d588c51bd6d2c635442fc3c9e60195c4666af05724e3494cd5d0af26a61bf38ccc98d2ff80e22825ddde8d777f44e7ca78206c7747ea0e968282105488f64e2a168cea86ff523223622488819c5f0a9a6b9a7fd80759817f33ad9ea0ccac59d4b8646414e5bf84552f110bc8e83c4d8026ddc1b19bfc5002697f5bc03a9f54cbf21d9f4b40d65ed14e7753074ff50123e2d9e28092f0a6757aede6b3d73b8928cfc6b96b2934c2aa48eb88cc5336269ffe37cdd8440d9481576e0a8d634f34a2b0155f48a7e98665efb088d9957fb394b4d1512f371b2e7f0103105961e5d24a6478aaaf4cd4413de3336b08996db0526797fc153892bf53af6cc0d2dd7c5dac41a75d92d6c438b76eac325b2abc01f8194d0b916be682bce8658c6bf5243ab436e84eb5340e82ee206de118406fdbed6cd17cbaacc693572a83349a045d913ccb02e1a5db2510b9aa2696b1406140323f228e7bd8d971054cabde0db581f678ff14a07a58c12b0d44617118b1b468c2409ebc3f5c54affefca9f09135c042f11abe6b0a06c8a6697e0c46e37dfc7568c4c9319825f328c15e8934571b383a0de356e547085405120b8d31c6556ca66694dc78c9ae76fd4209b78e0ae96f229633724a0dcdc53499f1472a41282512e99256760d4c0b550cff7c41585e30c9ea4654d1a092d99e22a97c898a4af29de0d88e100361e11625877999c6b32860e3494c7513ae95545af5d6507faff50116e9bb46858c451739d4b1ec161bbd9b1fd0c4828949a80b5a4ae461a6be41462cd882a75357c4419a1efe763d6de05c64857c461a4e266f227c80d10b6798af4e077efa5c70c426355c28f5846cf193d4b0b87f7dab9b7a8713fc9a46864ac656e10724572c78613c159a31300f42ca50f9bc4cd7de006ef0c983f700f4aedd792b31472fd8f2c4df4b7692f9816d4353584ba81aeb00321c5b321a57512f669ea56951c6eb1a8274463bfde7e926775400727fc330e87fa45bec1cf7de337dceca0e0968ac43afb0ac59e9879db764c2fea3d1ccf1b03db3f241b80782a980820d8aba2657621952ca190888f10d99071c59454fe3265fff141a2d264d051190ba3af48ecdd2e76198a98dab86562a040af6f6345cd2d57f584dbb50e6b5962726a3b4f8e6442835f0180bd89eacc3c4e503b508d70ade50e1380f7221fbda018e2b452fc92fcbc68c2023a7ed80c7f5da7b7ed8fed0d8f0a7154ed79b13ada2d1473bd7454232fdd474bf2b367dcc2c80ce4035acdaa935920ce424e074d0b92bb3c0228dc10b203c6ef98e173df70d33396dc690fd53d2b55714ec47df9b43305af9d2f1386cb7950001ca172d26eaaec16f601985f92ba529b4fa61a21c1fb4eeab4b20679c14676b72df796322529032b09040907099cfb10c077b2761310d08114d7b66a8ddb3e89807eb20e8af2e4e049b49eb86a203d3ed8950076160a1405fb9edbf7c4164610bce7f23d9185826905ea2651e5892b76f5085d0844ee68074313388476aebd009247fbe81e1ea4a2dc0cb6b8f375a0b8384994c9275b1d4871a75010bbbe29ca0f7090e3cf771f5059827522abf31fd7cfcf20339de77563cc3cdb81c08761d54a9269adb5f36d0f61177b8e042225c764185a98887d1685e131475c2781b015699b7d7976131856ab48c909093204b4f2832fe407425ce99c0bb1f65efedcdc2964c519c4ae5494eb89e30f1004b00b08d85f5bcfe713863d01a2eae2b2907eb1dbd1d6646de5892310164ca215ad759722489865815d720c659f42cc429dc4154bc8945d1d282e5745908257ccc7fde439a544d383803743d2ccf71a6dfc089e6846a4d17d6d4a6e2b6d1c556966779630e9ccbd0cc15309d2a9004870fd47e7e9d88f0e686400428c284a5c61236bf7d1b19f2d47552c39a3022a88e822fbc992431ada1251dc944124eb31a22881860b2654ce3881ac7d6787cbbe33c3e5a4305e84915aa061f2ed9c11c3a4165e40f9766e0cc32667e6db3f9c1c9be3ec4340663f893e3e3f1b105224a9e7266b4370fc741dc7a938c467c755492c0a86286794c8a2ec4758f43a4fbf1a077572949ffc8a3ed755228ee8e33e12ec2b4389387e7222383baef223d7719c88ca4f7e128fecb8caa5ec0401949f421655853a8e13a6e61cc2315b893e33883614349bb41b3aa9a99a8d93862368e518f88fec029f43d32f8eab70fc86e8336f57dc117d66ad5d85a3738b6e6d67e24c1607862c4e64a5f0393b911cdb39ebd68516a5338252be65488e7ffe7d0efa90cf41f1f394e8c39ff8f9c8b38f1674c37b9693a3734bdd107d6e38088a3e3744ce99ddc41aa62cc549185cb00a71dcaec8e2fc47767de4a41d97b29d9c948f3d5b39fb8efb6c1982c33ff7013a80ec8683e24af459f996213b0e8a3e2b9177441f1e126b98b21b6291caa54ce5230fa9441687e3528623b23851481223ee88717cc7b70c516de1dc676808e83ba24fd3c41e92fd1a39a354c85d11f4b169a07864cb101c07838ee088ac21a813ca4f2c21a02f40ca40915beaa10c2080309acd645dd4af761f2096e1780c22cac71efaaed58a1acc0d489021a306473c120328ce4416154fe85bb358421c0b8e4867fd6a07fdf3b16b5476c9486326c836c4197552df5022eb7394c8a2de2c225306fa94814ea3b36f500867d4af76ae261b29eddb0760c3f51f3b5a7b07a59b754060378b8a94885d4d833ea85f4376f5e3ca9532938c06bdea87f2aa0acc4c68bdf060c3a38dec5700aa40c0cfb3fac76eca468d31bc1501b8e24e20709a7822bbf8ac5dad7c0396816ab9239dde430bab59d4e7872fb963ba953ba65200b03009fdf4cef9a61a7c8b9e51470103c33a61869f32bc4cf3dc6340eee81668f003ec8d7061d81867bb7e4d9ba558ee481f845d16521df55c0a7c63cdeae76c5577572a522bea9c73560084b91cd775950b5279be451596d621c5a5ea910473777b0737706f7a12b88b06535876493074f4e9a0ca2fbb54466af5d6a18a136a7d41f56ce59aa0799c7901888f2f33746b413b57d56df82a4a9bcd665464ecdddde1d7307cea72c77434f4022edd4d69534a45d60954649d30cecf792a763d4017b71ea056fb690afa59f4507ebab80236ddcdcecc4a6ce03b9819a15dee486bc5b91c275e9cd9fa1685b0c08c17e88f2cf0b0c035275e64585819b5117e4a294fbf40a02d2ad25741ee0042044838802a940ae5ca4fa6b3ce4ef4167bca40a9ed39a7af90a89547ee5968bd651728774ca1ad25cf76a3f723abfa7c1c2fc2fbe0e6a77761a882dc319d8ba4a41c64b95cd925f5fa34c815acd26264f960d714523df65d87b018a69b1d24b877e88c57d609236dd108bf65170ba08fdb457c10c4ea523a914ceee0061a64dc5ebf917c963616dd4309008aee485734b494a7484756fbfcfa02786fabb9565800bd380882f714c51dc136427fce203c034e94913eb8853f6042e98d1c1c213c86beaeb06d7a2395ef4c41f3ec6e6e6ee6c9719e42f2f37b588b1ba4923ba478b999628c74010df602a8ac36ce7f9327a3b0704e64ca2a99d516f567b78f1cf9aceafd9af3a924d919fa524a2d0e195d9bca35cffab1be114a9f05f02dbb7e827412ca5d74ad4150ba2395b5ceeadec3204f5156e978802e6efbec3072949a52565f9c8f86d6379873006e58f0a17a813e0b3e7ed2347625e58e743a084a2048a9486d334bb28b167d327653330e0ce24ecacd96343593354dcdd8085457faf35f6ee8a58e7a794aa1659ccf137c1304250982d27520a0ef9e1dc5642b2e056b2b1e80d25589b30a8e47e41179441e11f5e91e910968ce5991cc0cbed63ab65add2b6bedb9a33e6bd775d4274729ea8867c760861a32cd66507c3a454f87e40fe9ed75e6119980e40fea6d7af6b122f9a6b117458b19bc89d6b1d54a4ae9995832c7712936a8a25492f41155a453f4c54ae9ae9100c7563e2608518161ed5c3cfb20c0eb0c1ffd2a52b9cec8e4f1453a268d4c11549307fbd8271f1d0301bfd857ab7b977e640c04f9aaeee313adf8eae306afc333016c48216c8074558741aa60e5aafe00f9aa9d38d6af6354df2175c857f50eab02be6380eb4718bef3611703a9a608211061503d08345812d4a9f9a48fb155319ab62a44fcd256c54b063cc7144d84a85a78140bfb8ad198c2f0e60c56bc6298018611430d94c989649737d90d0fcf4ebf5879cecb326e922cb5b1ba756964b5e2785f76a29439c66a6b15c515eab58dd49ed86ab17141b620f060cc55dd295eecd1ed97658e386a391232f412ad95f669ca5eb05b4a902f4ff24465cd1f98b2cdff9c40d676e4c119497070c61934b4a0c1c6b7bb964ac08383c8f6e4346eef12688c971eb1049047416ac12d18d6025a0bc030c1b33348e9172b9a524aad52170a5627dc9252951f796c12f77b5946090a18f7823638282ee7c62be27a491e1287e5da1b38bbf6c81e71bd2c2c0e17150567f3025e6181153558d0c3186ddae8a10d196fdaa4e17eb016a70c0d0c421929f9c61c9da05062bae2067a61e28959fab22cb164924c42d8d0d5fa25db8ce086116a426d96e0300216416d664b8cd8bc4932021921364a405904b12163c90863a0b0b92d19218b24be5165872f6754375fbcf8927cb9e2e3e14b13dc08be28e1c39723a6b8385e96f9e2c3165f9270435ed858bd2cc384142a28042f7dce6fd93d7934ed168179f2e4d14cb9daed9a3f44a03e76c3b6506efcf1b270d57ad78980abb672421cd759963caad3c931d0ae95a395a34d2827542b07d3428563627253ceb9cea5e7f8e2d9c7ef7b2a2781c9839d4747bdca1f52ba354d11382e06eef758726d8f3906369d82706e7279a164e7d5ed9100b53127b74a008d953c289fc00faedcc5137b4225a5e010324441238a282ba05bae0d03e853a3e8d4c50da634c0313a786f88be3040f68d49091cba204b50bc21383568360a0ed5cd907543746d51809a045943c88d0e41d0406212e4cd1214364041d2305a12448d5b193057b494c0149d000c13d604d7f4b20c9821286084bc20c058712136ee2350f27342b9e5909148f54c1d4193afadaf7504487c859283ef50d49de3bbbb8724df3d9ce1c1c8a9989bc6bdb2eae27b0264822728e0c1895fad92803b247976ca3ba4b197bde0f03c8f6fef198107c67122abfb79da968ab5dd84f6040459b520ad2063f639d8b53af90080aef7b49bd0ced3ee2305df945e7422e1919ab6d0dcf5efda5ce56a3757575ce5aaeb9b273333e32031b96b8e72575d3c3e2fadb42bed8e725d3bce769de5f161f2dc6de8a2bbfb5db9bb7be7ce2eea0c935ee70ed6c6e9cc715c9d7704bbbbb590524aa69372949b2796acf5d65adbceaf5cc739915266e9eeaeb6bbbbd9084d993265ca9429455faf40ae564a8552319a5275bb9b40c2c90e5aeef7d2e60488499333ca68b2268c6b5fda9aa8f958704f2f6d4db8f8c2b8a897b626567ce12d419b6d395a6a526509174d9c34390a6a82a4091745b4a4265c00d14ed024c851cd2f68eda98932539420872d6a694ca1c59b6c98c2e8471054010155395e2fcb4ca1a655548da074de9000bb804ffc44cdc93d9162c5461b33b54ca339669af939e79c734e4b5bcf71b4aabe02f95afdae61d3218a155d01ed52743362ba524149344127929a9a2d892f4e0891e60c255c60b154460e63eee5c1092e64e098acf1ec9471d8e239072ccf5e576650904995a74e9998712d3319cf5cc23cfb08947b9631c38501966059b274c318256380a0134e509382d482b049395052452a48cb275b63acf6b69546be26506b0dc39861d4adb79418569da3b56e2b1599db1f13ea97f5945ba04bfb5107942e5747bcab7e592cb7863ba66e6f7566a95bea96baa56e3d6c778c8d79ebad961a86598f8d61588e5b8f09752c06d42febd60a0901752ce5d6a5c4f1934be9deb527715cc580bc18d05b77318cddf39cd0c52ecf3dcfd3416bdd18c6e3adb79018c63b6e5dc7ac632ab7507404bd75d93a84deae7ed401f4d6555d6eca553ec24a40bd496cdde40eeb2d2f57473cb225c78fe878ca77a6eb78ca87e888ac934b594acc1187ec88ac93e892a944964924d2a59cf3233a3dac737461b78e498fcdacc511c77b5122ecf6d653614fbfaceb841d0471a7332b85ce530e81ce53a26c08702e5b88ec97774acd5e3ecb52b77ed9d42c45c31d7ffee35390af75eb97a5e17e3eb63410ba9c0642b77ea7f1823ff93c29a07f84e1c71b259cfcebc05338a6fef4e3913f85e3e94f4e4f0ae07e8c013c8563f727af270574ff811a08ddee4fa1f89f05c193c94f21076f0a49e8fee49f374f8c32f9290cdf148e22f8937fa6293d8b5ac1e4d4bdd99fc2154c27989c7af5ee9480daa106ef85d2a644c9cb5307536e0d5b50bdd7a5e83d718506c514124bfe6c2f1cc22eeb35eba630a52648eac62e9bba394b057659972f017659efe1511ebdf556525b6f2db5f5d6adadb790acd0ed97d20c27bad0c11bf17cbef75eaa76c7d6ed5b3786b15b8fd5524d56604125b6a0fae95814fdec52f4535ca17d3a1d00d0f5677735fb6df6557341e32acdb935a9b78e9968d6d29a54ced25051e4d0e40d5544a39968261a8dc25a714d2f6d4064fcc853b3011d99d25cefa50d280bae897b5fda80a0c8315b799135017db9a113e2971c225a4981c259d08ab78635fc924afc9235bce197b421c92a083bd012275509ad034a52030de294681dc4865a2d430907a1e1885a306a98419220358f096ef81204080cbfe48ff6e264d1c4cb1a8bc6f55e96f192821c2fcb3031337dc0e3f2284fea3c2f4f0178791a325f2f4fd6f57d5a4003e061601380b6bbbb270fbbda031703913ba4f3f04bcc9d5e29ad3e68ad22b52b4a296d2a59435a665dc2706262cea494a64fde385953ea596baded3ea42baf8ba76340e48f59a45f7c3aba5c178035773ac7d9dbcd5a6b2de88361ed2b9e9e7e719d58a4bb5b917ebdac28c22e5a6416a9b4e9ed76b33239bf313e90032eb6d6d9dddd6375aed6ae768b5c0db5b3b68c76516f8efa844ce79c9373c9892086ca7155544356e6da3fe9aa382e849d7455efaf035cd873ced97d1da05d08be7d1e913baa53ce8bcbfa8a0abd5dc924334ba6db582ce4931f6705d8f8c18b353b28516289cc4b510d4a5280c6133cc8c639c3a0eb727ce7328def9c766ec57ce7b70635dfd950e53b578fd9e3a75b91032e77ecf1d36d904e1cad77ee516bea4c26ef3a21ab2ac43dc08faae75c023de794b32539c173347859d9af250843a90e3619c0b0cd00e669d153d7ecbb59a2c0d69200024ce3ba3cb0210942f452e59393c7cc8c67674f0634556431869929d4fcf870830d6850b1e40c275c6683b1831368801f34b9a3cbe5e3a76b821980fcf279496f3999f589349318c6abb627153af738e7e997f50986633efcb26ec1ab5ae5f096cb83373de617a5b728077d044d3ee6e07c6c7930f6f851be79eb3d1d439d563cdd7549eba0b59f68ad7c592ba5ac282ca073f0e64e24f0b344389915c0db2ab3d2ab5b6baf3d7a5b431eb9c33a0782a2ab5fd6d15c2bddfa24923f3e5368fb555b565ce12675417cb2f5fdc009328754a74e85f48b1b72afa8c278bd03292e5de38ef6392f6440c1cd19c642c173eb567476712ea568334309886435a43f3421e3380f0abb38294f66c778f8c5b9b5975b01b9d3ab78abcf8fac8ab65fdc0755aef59107749cb07ba628d609fd9ef77ba0d84389fb533379bb38ee8bc8b81ef2c787e35f487f9e70c417146002bb38b75e02bbe7f4ab27ae244802cee9049a405a827c4991f029c80ad371dc0b2deb84e99e7b3f7d3a618a52ba3cc739f907cee9394e38c230d6f7e4a348a03fbfbdb00b797ac81f464290b10ee4c8b1b373faf1f423cf733dcc4d5108bb38a7cf71415e11196c7179ce0cb608123623663f824b2f6d43bcb17161f3a797362e6ad8258998b171a9fdb47129b271217afa52ee90a264570b5ad0a046eaa51923ba4c2a6ab041fbe9524ae93279396b5d95e33ab7473ae73877715e27d74964dd73229c57f14875ce3df1c816161f6197853d3e2652ed68725e7d9691afe9f3cccf99e6e71ce3674dee98b3a6420ba9cef957f35a4dae75cf87e694768d1a66de0006b8862c76764ef4d9c2e290cf39f7f1becff3562cfb26f8797dc43ae7353cb265881559d43de79cf32326914545560ad6ab0f9941fd9aee4a23a94c0bd25429430a19e756b4ee3109b8a041072e4b824023ab528dcc137d6650f59a4cca38efb8b0565f49590d53b6454875e93934caa8253ed91a75043de308a5cca7e3083b2ad2e420f3f9baf8b046cb4d764302203c9145543efefaca594747474788dcc1def2723b08bad4db41ff26fdfceb36f9c7759676e8f967fac0130aecd0fa877373523a2ab0c31dff76ec7f37baff70ac2e003bacce02abe7f897137639604e0e9813f67f15ccc9116be874030d32e81c2c0c2ee0158e1b3baa294f1c742d548ef78b3d45ef2ac4d1fa1cb187dc31bd754b5171ba4e38caa4e77a271c47550b0dbbb8a50a5b0058c11d75cccc3cbb0e1ac3c6548d09c3c6e9ed73a60368e80bd3f8499252cdccd017da133ae71499885d3cc4899fff74bfd7a9df9b721ca12a54f9ce0eede80e5585f2144447f62be5a3fdeb392e39a6e37acebddec33a661d6bdd3825ea4876e978ebc62e769ea39bf2b1754b39bb8e787b306eca755ca54ad9942a25b28b95c205be72221788b2dd87080ed16725de7eb1e41046699bc2e83b70e3c71eea294f794a7472f4d2e6c4e85d2f6d4e825ec78c61ec3a9230cc7b76f149e838f8af2765d42882f03f0ad6d309fd384e43947f15e44e24d03f390d41ff38b03b9d50ff731a9afceb407b3a817bcf6968fdb33edebf38a870bce0393f852e746db4d1c69b1bcff9178e47c6540ccf75cfe1f071b59aa16f19e7e3f095cb538738c2c9f90b516103b4a1da4ca2f150c7a64ccae41214a2a3b904858956b55a905091d16d22cd808284d8e8d9d724b56e2d3542badc51c74c88907e69b963ebd66ad6b4925a4b0ce3d43c7beb8dfc31ad3d411750246df1e2044c58219bbe9231a9823266524c19634c2d09d97429a75b39a7a76a1dc3e1ec3265edbd3a66dea364c975cc5235f9626f71b436a563d6fd14c78b34a652475296b384439ccec19b3ba66a0ce3f1eca9238671cf9e42c330167599ba316c8a2da87e034f8c6698aab12b95149372c1973627483fa66a2d35ec62efd2427a6edd5ab750042d6c00c95454dc31e5291db59a8e19bb526eeea823d4a9422849a663c6b016ba40f1fd4df0863c0949d552b71452aa963ad211a4620e8cd0095d21c7a720b50329ae901309ed39cee5845db54ead1744ada54868d6a3415684da80a2a5034f56d67a78b9ed1b70310beeb160845d0c8104785e849374e5190d494768d42025292dbd61a04abb688629c3869a5a6516a90007e12418a855c400bbb8c6ae8f86df3f5f335367506dc68449c872a1e76c54edf6ea1f04ddea2a1cd982e32951051691d48f2c250a91b751de8fba620f25aeca77704494cf277ef20fa6dc1e157c40008414542192a54457d7efe95388000e9a0505cda03673346b3368ce39e90f4dc86ec89721d440c34ca623ba12e08945523a447af84424e57c1a72c375441f290605b21b224f0fd1c982c8089a4c4774f5abbbbd9d258cf670110c0851619c4a73cd0c120009ee0da976a4e33788dc707922e2e386e8c32a92a5449e7ea55c47f439c0ccc9d297f239b2e40b1e8a642957853e2260a38a4cc7d52ff63944a32d24e979a7bbfb44a4224123d3690115328a6429efe194b3bb64914a87a52c154a990cba7ca3049f6ccd196860d06431888045972299e7d22573dccad9854192144e22bb871b8875b3059124e8882ebea4235430276d21d43b4ba9d71aba1043d7c3d43b351269ded8d5222779218b88c93d37893098dcf36e6bef6da076d38d22ae1a210ccbe28eb3c631949f49f30dd43194386ba71a58bb35a05a5b3bce1ad798b08bd640ecc219baa33c02328526f4ab811aa8694c80fa99933ac637be8945dc5ac77c084941fea8ce2f94913bd86d903bd81ba881382680a02f0da6813aa8b5f4501355da363cfbc83756e224eeeeb6c14c0d69d63e10ba23cf6d312680a02335b39664d626d2549a4b33a6cd492a0c614ee2611763b9f28f78220c9ed730659eb3178a71bd89d4ecb3368f6a18a0a0c9b5012951c17d70bbce3edd26c58a4d8a14db0f6b0ef0d3ef4bdb0f5d3cfb27bb5b7a95f414a4abcf1e9e50d8a08d1e000dd35dd3eff455101e664e759e9e345ca6d460022219c6fc7841c20443b53358c83469b5789a7673332d2389524a3da0de39d8558b604048c74268d38228a6e4f0459720592d2243873545d4b420514356f955bd4a9672dea0f1cb9a119aaf124dcdc2892fb5cee4641318266d3ec8f0758caf3e42656656bd6cb8ec758ca2a76f9ed6aeab0c0ea18a5046a8211411bf79ea7c9a3d755e923b6803215fb4459494d40f7744ed3c31a2a43c75d410c3465511c3c69d27be306c3cd59e3a7514110accce135304146df2a04e5750e494dcfd5c4047bd53c1aac0aad687706e51449c0faa4844fdc83c944bf4f991b1aa73fe23ebc2aee3441feb9efb70def98f4cc53b45dc1a28da73dfcba03be2b812bbb8257625c91d9cd3b0039a3c389fa71478bcac2bee4c81089575a24f0cb2ce3bb1a3b5e3c81fd5696a34c872bb97de7a00b407fcd231011993b2001283ef1c88fc21572d50c1776050d1b9945bb8d8d5b55253eee8c34707eb1c480a9c571fc2791d521d04a938047413fad53928fae857e73fb254111a64b9200ad4d9bd7005fa7d9ec83ac1e49e976072cf08750fccf7dce2bc09e7e58cd5222441b32476c6ba2224b7d997191399f53b63384533dc6666664f64d657133693cc82deda2cd77bd95304f6ce716ec7aa3b4e524d01ed442939cb59ce7296939c5c413a95d65a2b3b713422dd2b95cd49137a8cb8ac19934a4a788145186ae0d02649c626d1eef0703d58f9e827aef4dac457ebace133f3ec259576a5ede580e0ee923695e1fbb89f73cefadd7fcc3a3fe7bc737461b2f931e78dd0e92d03774354b16847969d3ca4f3d3557f5c77cef7ea99e5e5b135f6b5f246b8d2963c299beeeeeeeee6c96334054720c35a58fd0ad3fb9a5111d19050d0a4f10401c336d0de320d2754ec2045098c131a3b0d5e9327581029f190c615322a16e9d71ce54dbe098a1f5d4ffc288b9cf8511e81f9512635f1e30462e2c719b4c413fd386b396c947441f3e2062a92908d8e011cc2d092054b126b9ec8461f29f420460d31679410a28bacc551d66688e28b9624cc7c098209198b3f382ca105094992a21e8e64e82288376668d105e9896c9c502cc0a508206e6803041915c8a498334038d952060e54cec894f82650a2a8628da3268c6413cb17639a5033059a36b259ab3549c117628e001384ac0a2db47c21852dcb1244c87e9828e3d686872baa1822e9740619b530698868b20217c638438ca51ebab091219bb53068501a6a728234a8904d9f421ddbc00a1a56aa78c1856d8c6cfe6061020d2882b6d860858d6c1e756db89d028ba12cb02862088b2a3f5e6ae7db48c004b3062f6d58d030268d1f5d3532348925444c812508871fda28fa198117b623bef8210d2c537ea418b16143942664b6582201597e3883450b9e902193841543b5c40a14ac4132060d3053a41926243e3457b471628c27a6a0954903690731ce10f14045042b905893c5cd1a2a4ec8c6d5144f8839b3c51a2c3c98be58a2da1493971fa11290208a19324e50c60e3f4d88ae28138615316a70d14a3e80f4f0b45d61c3b3dbbbb251b1f4fed226460c315e50367e463004501343dcd086062d64a3db0db268a3444909953072005b2af0ae622d098027770457ed9c87b7de6e53976f77758ccaa48fab5a5151c4826ffb236598b45141f476f699fcebdc32ac9b230f8fc5f1cf714294fcc08fc8490447fb56ec425557913d86fae3314dd343c5ae28775479d02b7709608a20bfc78790c66d676b5d67dc66661fbe30372a806cd7751ca594524a29a59452efb84addd66ab14c97d58c3ee9b215cb2068369b2199ded1662c6b82d8b84aa58a72471b5ba95454a6104b4c39c011776cb55c1ccbb1a23c33ca17de365784eb816904cfdee2f9c9c495b6a1db73ae7adbd053afa7205d279f4a505531878a5d54bceca2ddd57881cc903c7b4e0f17c84bdb9095e7f8670c4fa178961ecc9934f452f2f0805d2e39c6d483cd085a0841362d526c5ab4740f25d6855a4a9b98eff3fe933ca75ce1a5f7b0141985efcc77777bcfa215b7e79473167d50a4536b67a3f13177cb1d23bfac4c2965cacccca4e9a5b2bb8a10aea8ced5ea5ce717945b755f6634aaabd26903457ee0930ceb58921a5cc679174237d7ca3dd53c21a1308c7656ca7ea712cda4dc4884de042941594353f39381a6b3198ef1ac5fb3ea9387fe88679f46fc6891d85927b4060a5012974167865fec6880d4d0d6744a1cd4bd61a13ae3a1aec67da465a3c69fd760830d381bba7cb263b25aeb0b0405b83a16ca17e5ba679a1c4e87eafcf4aa527de7aaef9c272be4970ca320c843b048e0fe4f4a296773f37015c68939b88abd5a61b921d0d58a79bab185a9d997e2941e50ff703c29a5284d1c572b1a9f64d84a5631cd44f24986810cf34e1ca8b476d7398d843e8e5eb07a1cf606275f8d7ae17482fd1aaafee3c02ee73f0fa4e17d9cff40d49f1efc0f05d2f0fb0f07a4a1e9bf1c1a7affe580295005aac01df00688035c7d2c0c5054ac7247bb089e43c080e53cd4da6bd43e297ffcce0a3b407cb2633217c342aefaf4d50534a4c0579f2fce3be4380d7ccd794ef6d33134cf362d44bb4d55f249867195d4e7f649f98327ff0f9d738b0673d22324bba419f090fca1c1ac4246318513728a298514cf3d21a550e2abdeac736ef95e74cce10ad9b8d3c5af669eccf38acea5f47ee56a0e9e9b0007537c5a39ca5336e7957b0e690e2d295f72ec45e682a36a3e086c5b906c5ab47861b7f8e9431790555659abacb236edf64b16ed328b762794efa06ec9a17c4a250d57ec6a3377a4406f18467d4ea64dca946972473b05a2348671480ce3359d1935246ac58d46714497a8d1238c6896222a4714cd37bd11d12825b011d7fa68615cdcf17617f292dcd1ec46be7ac98c2c3c545c51be89ba492b4142c4aeb1938c929a67492d7619b5f7188eb919179a6feff1aeb196c6341ad39867340967874fba15335160b843a2ed16fa0951a3fcb442a3d656b9bd57058d0e56be01f7a54d88273f8550c26f7e523183ca8d4aed572f6d5494f8c95ca85cb13d3fa9b8eccc9629b311ee67cfdb273d842dee0c73b8533a187287f4108cc24c157cdfe753fb094218979be7dce19b5f72ac1893d7f8ea3d6cd1acc8e0aa48b971d2538b3946773aad274a29d87d953b5068ee489f762014773a25a1ab0fdfe4ab022f8692e40a3e06278e1ee626cfd46dce394720f3ce3979fa6466669ea9da9c734e19f3b3c83645cd2cb205cda66d8a9979e79c939b99bd847ee639e79c73823f39073377501a340337b77b4f5a666badcdc0cde5327073b90cdcdccabf838b3b3691f5b7d68a2f4c9e2e5772477b9fa81423f9c3321a7496e40689cd6d8ca334b5336528936f2b5c4880e79ccf130aa08a75c85c9f1f19083493f4142da1c126690ca4337cd456be8518d6795be79270cc72cf66bb64261a5cb944463d18e8d8495e71f455cb96ede10aeeb8fa9e4b3ceb382623cf33358571a5b3cf5e8652862c29e5bd52cacb3e7dd638ec993ce69c8543d7d5afa57e49778e59cb021ad488f193e7a7ebf2acee40658a0f44d89c28bd9cc224f5d21604193f994829a5742aa5149a5688b191c04886314553ca1d2da889c0074213f04b8a89999385af587969bbf2e447faf24a93b72f6d579458e95edaacac61b3b2f4d3b18471c0975984954e0a07f1a6879f0e22d98aa05559b2b5081b2ae5669f0bdf27dd02fd741364983174687635fcf41e1f2d0f7a0091616e5c2e9725c9abd857ceb01cad1e36a1354deb2d492f65e022aa25cb2ca916c10647842c238594976f7efaed84d6088df1d3afb50981f1464a1018e24a9297362e423fce97bcc4c5073ab9d07ebae532fb91dafad2b6458dee97b62d4b3ffd9394cd373f3153088a9fe1b4a2c41bd1592857a5765238eea54da8879f938a500e3fa7509297362c4a3fdab76109e3b997362cb79fe1ccc2c5339380c816268ccb8a0d8bd1c442f4e5a50d8b152c51b0341626dc4bdb10670cb166d221d090f9a95434b9a1d602beb40d11d40d41ab2f6d43008d16f5d276250d21befc083e4bdb15a42bb7ff5edaae6cf1d3b332b35d19f3b303f4cad7c3cda47259d2ed7fcf92a2943ba48d08a29736228a7ebae4e0328088a52a495c6fd9050121ca1021990c01228488b0f2d246c4932b4b6f7a692362898d08a4ff5eda8840e3e3ca9501a2d1a8c4cdb555392915a2190100000000f314002020100a86842281502898ca8a2e7d14000d7794407a52194c846910a3300a32c418628801c0006008218648114d1500999781fff6363125a6cf805e0e05eb46da04f7082f61ea02130906dd1f342e4d324f63692564c2a0f49824f08f1ce2f529e28d78cf2d677aa9cd473b50c2026c33facf9d626b830623a289ed9c275aa174112f9245af42e4766f6386da9c63507bd6935951f5e2765185431ce021eee31f777fbc9e675256325b2093d75ed5b497f55dff9c9e51909653cf96418989acffeb9ec73233f9b5959c2c6f120f65e247efbf9a4aff5631d19f9ad2e92bd861d2ed1443d0516918f43eafc9c06f0f66dd2cad77afd954992fa2eb1d6582a1997548f63b54c747077829246202fc94f22859faff35f3a30fa27cb94a83e4ec61c9d7c7443aa217c0069490cd9fed335128f6fdcc3fb4a2e7c893e22748531702a9dcd310fb6ae5e88d2a2bb4f495b13d44111bdbd1366c2c5b33d0185c5bbfbb2fbaecfaea6782130bc3835079ead2e4f1155f0d74cdb7669b7d75d4fa82195d7dc4c49e9fd58914fd7086feb8eb72e4a7dcfa5170d75d647b2ba9457ba35ff444a80c9c58ecf473f91e6e74ebfee7b814d4c240fe8663c3212e66b128d782bf925ae9c84c3d6fdabf5eb9809f5e45ad587848cfefa379c422d7fc68515e388c25971eb8329b2cca8db5dce286bdbbd4635daec806b84865c3a95083282bd59a02d13e11ed4b4a1a1f902de8214abbd70c8a1a03f1d0959c222259e3af76afb9d2d03b06980e66ecaf62d6cc19ac602399065fb2ef490808bb2b0133737b845d93210d7def844da1d066454c91f4d6031d5f53840b4339100dc7c3e5a012f98a56b0f097ee8350404b98d0537761b33a43b4f44c6b524fddc1a5e3e107abcd53041a9619933916012735360630cb8552a5251230b3ad8882246effc9d634c33242fdc529493289a9e82605a18831923559d766e9cbc481b08ee559ce1200a38aea62c9d95483c24d82422587804ab9e45669a1d89056f5efb18936731317e2df753aa6d486b92972abdc770f65d37906d3605b8e545fe61e2a02672823bd06d0192dad65e1bf2a4ca240bdaf86435490e020c720a3393600f16b92d97ee2180b945570dad2befd1a9c354a293fc412d057edd63d1da33d195aabba2ca253f36d05d6b802b203048b9129fd8a4a4fd2df4285cbcca087378533fd0e6aa1a4a5d9aad8b3b23f10d5e3c06cb98c13007abac2a73c8375ae5ba7135302ef6f7e223576af1b48ff6685f4279861f7e3a93c260b1e9213944024574359c104c5029690c7ef6a74bfd804eb7a33be11e86335390a7474db65ac72452d1b95ecf9c02fbe4c2bbf84c537e9fb1071f118b2560085de4a307075b8aca598b6ab057a8aa6e26aeaa1d969a304b0b056eea120384d0595b7844881520dc7332c49165c20d6609fd246b0c512f81361cf2d167a4c83b5d38db1f5164856e470fff35271e29d1fb7c5ab6fd56b7418d8bc9b80f27b7d37c3ff46b67bf56e87eb1755a2d0000aaebad269dd58cc4b9493b030e3266449a1bc7b533ebcba9626f44048379622ddc4a7bb58367ede7183d5d8cc281ec334c65a6529b5fd253f7f79a9d8575128ea232b8b93d6b0227f73474aa3d4f8732266bee7bf27e8722be90c19fcd40987d4d01feac7ae450889d6d45e0e38951e46a6100c4dc24ef18e1730a7e7966b9b1b69867b362aa21104fb005d94202219eba3ddf95a0c21b6393adafaa2d6e1a41f2299691a6cfc501f84eb20c45dbb3566dd89242538e5bbfbae044a879ac05057b236f263a94633cdf9508acd0417589d0c357139a67a9a51e51b1aae51dd223e86b9b3558796366ca7ba87df979e0dc9fa9aa7c1b112f888825e4659a814b6a1352c433fa8663729f2704bc3ec549c483ea079950f08669c5baddf35f6a06f2845140aea958c67eb3a8b1562f28cb7a64747a65777739f28c14a4f5685d6b1bfebfad69e78c3aa6b0ece8d7ae35dd6e9c4c92b16964b2ee36966d5d4e3bd7e88f88596dea313f7b9d2aaa3b538ed2f5aeef5ef9cf603c6dbe546c78f41a0bd7a68048cec6e579e9101e4bd37a8c7a5afb1028f130f1e2df0088a55290cf302c367771a2bb58fa9ab09740462438c524f187a5506ebfc55358d5789a0d3889aeda79bcbf959e9eb8fa10a6f30ce2721f0d2a941e55e5f336bba7821dc725983e2486ebbc4ce8d6caa2ec7d29261aa1ce6d5b43eac36251058229afe4aff14ccfc17545e6f6b49436daa1a5180a0abfcb321baea9eff2400b5847944b0f0592864218e512e8818370eecd4ee6d4124472397ef9fe9eee25634c2329d48921188e2aa8b43cf645f450638678d77954f48f479773bf0caa6840d86e180756c37f21d4a7a8b991de923b8a61580c255f145cdefef7548efd748b803eda5506d569ee80e0157f86c58532ca53f60423856509974270b45b04b31e8844cf8b63d54ddbc7628b6796bc97358886d44e572bae4398ce8d6ffd194c00fd2a2e5639d16847e51202ce6e99e1f2ada9967e6063face75b742cf5fd25698652db811a0ac661226722b48722f50c7612062894e632a22a50548e2a7c975b55f1ad723d24a1d64422798349175005495ce5aa9b921241f7edf287e8e23138cd8d828c03ef8323d4255dd55e022600de2962d8ef38017041818450d5cbd739bdd0c4563f4351ee7540a3e729ab0eb8387d0c9ce74e24fdf947519d23ac0e2c08b3ee1c6680dd5de930c4171dfcd23870ba0a4aca702ed4c5940230ae720f736530cf775195b81d36ed1f7e6021a9aaba772308b71c19a352e57f701ae31425eb7d76990df4482b3a445d76b93a4c143774b961a85b13c2019194a96ec9c8abe5a6756092faf14e9298c4449fb4201b8780f7e3af9128a87559a543f9a0f564998bd043a2dd746f1e564a6d86ef46405972f99f7c1d840172718b0ccd00a534c5cc1562d7bf03bf5b076d17ad9af8c5d2ea596f87f28febe059957fd02cbf677beb08006c35c27a18c7508d03bde4ff1dd70ec920bcb41eb58cfa6388ab184d24e0e9e679ced0bbb826c65af0b4594936fc9cc50f21c2aecf2ef3bac3d4941e73eac5fa724bfc5bc22607b57ccbf362a853320afc4c89b550cda5746192eadae91820b901402c4f680d594408dfe65d84eec9c095242748b1cee17bd07c1931d763e70106695bd9d13cd044d06ff051d52f7133eb5165771c588063c60fd041024f1add45693a23d915088bb69f01069deacfd8c20f05c3b4736f9af716040ad16ca39aacc1741847da22cfa3cc0de04b6e4490ff5c140f0141037678e8634feaee2945877e5263bf408003059672c87a151bf7e8cf81b38c5d28a84304dfccada89f38aa5ed9aeb4882f1a100711e1e22ec9c822474b962c4e834fa21ef2bd85b613b927ca15da266d29a84054729c3b43c58a984c43e6366a0e17aeec7af0d96e460ebd76a53175aa1812542f343183fc5812e701d9acf59f1dc44417cb9cdbe0d9e8dcae7032a52dcc549977b60ae082c30ba20cfeed6f7e020b360cc12748bbd1a2abf23d5c31be61acb142f33193bb93a0afcca25bf061f50037740a06e0d0504d6cc84aa78c8e89bac29f90628684ea51ef2ccd20026ffefea14a133e444c39b2a98761e8785b2e068483dfbd0a1e72e0d4abc010cdc85e29e94d404e437dc4cdd2e0702b0f6f8f0306897324c8d921d49e6eff040c1ed73ecc6b47260ac902681a18b2b6c338f951fb7599ba9d3ebeae9ba6414da5328a558fb3f67a883fe991f7a7b0cf7ccb8dac09b5d67ddf0d3755950efeb33d288f09b480ea90d0878cfdbd0c87ba7b848341b7cd658e244fc743440d13e6a8e06593e698e884b84a89e176f1f512fa82985260d9a26080ab0000c468b596c43a2f28a98ddc31b3fd4266f8dfda766988627ea80eaab925b3ecaba6d3525b88cf790278d570f4706de42bcb10ecfae944e0404795071e0b747cbffc13788df8746b23b2238ae5de88e5a5ce119ffdbd854c2a44f014435c2d42e8704103e140f67809edee09226a844aba11e5b22c94de778e4c85842e413c0d9d10848d1679e3f5504b60b87ba8bedbe832920b42e9250df83dcfc1e74dd4fa1950ffacf3f3621315cef02de0521e0ef77a188d6839f18304d680ab135d855ba3f13f3908033dc824d8a5368c37700868ba0e4a4dede7d43e1f7d980c2cef7e1f23a672b1628b51be83ea355adc8a29ae8ac39273dcd582c7121b4d2d48511cca7ad78237f1db7781f3b0097125e4d14d6020eb0cd1c7549292577cd2dc3e2140c453ea1399231d0cacccf6db1e849224d47becd5b4f7957068be40d8d4bb6436a43efc40a8b950b7c85c84d99cd271144816ce35e79c3397b60f08c3e45b3fca67900b15ca98616966b910a211f228812c4186d659803f97609dbb0177c40ef49f29cecd091e83aab9985513dbb2258670c6578a76b0993dfa6daaae3fbaee58e60ab1dac8d23ed12d327d27280b1c006772db9c4c5fb4b20567c2385546f07e28ffc31ec7b93385a958a101edfc4c6b8cda0841ea54191923924ece4819837d2ec2b81f6a3eedaed4ab6d4489b1891b7bd0a0e8a64d34db0cc555dcc703ba783421fcd78ea278963aabc176d1d13238e8a032362a7a305e190157a1eafd31ca078328cff87454f9244540a8d9864211271523fa351104defb4c253087df0c5f8a5f16e9213c67966f958657d9874ff50f91cc3770f2e16813d438bf19448076a1a7c996e89757b642f1fcbcf878023db2598518161e85569c3ee68c46a0e00173be66bce115a6aa2ec2c0c36379617f67a3b1958d214dd573058f9057760a60b34f6f9538c5229098da0374b8a22036d86b7bcb71ff014ec27801f16ce29dc43a110f6c00218f43068579b33509502d164bcac4d5d9547cae3b898b01bf4fbc0b4f24e10fe7990abbbd9d05203814d353796dc51301fd1b66b02fce6fc46b4305685b7ea91901e472fca76ad607d5cdb76a8d2287f2fd25e3d93e400a8f31dccbffc9be7d7294afe1c66e0669ff2933db99f40bd3499ed4d9752e8be57f893b9e353cb79abcd897066cb55c9470c88ea12b6746e762b316363f5f594c298d41d441dc3b98037dabf6932564dec306d9750d00c743758b7c85836b5f8b02a07b8fc8e5774327190bcbc23f4a6a070ac5b1c884382852c10d5f0b156d8be34c49def92da2600ee63d053f6842fb4470252e21f7b971342a6f7c25ad41dc1b521783143e63fdc872ed087c156b0d5a0a1cb46e8fdb056256f9f6c3a9a406b02fce18cbf572527875e57dda93c39efe6b490d74c6c2ab836b2d2bc41fc1e352c923fe091422793d784b19d27a5acc8f1d01c8dd549c2e1e44021dd2b32591b0d75e720a0ec9b7c8631a045fe65a33fbe2b2fd3846063554f47aab51d71aba5f350d96a1aaedaa7f9f0b16c47b26a41c22546283edd8700685250314044cf62e1174b30bc2b269ed0f1a64c7c931f1d61ab1fc1960520cdecd93ffad9323212c3811adac07646313afb2e6da3ef687c5fb919b7ec2dca190dda055e6ae1558190463bdb028ad98b250ac80f930475de29b8632da8e642b330c0c41bccd0d629f35686e7a333fc0e6b862936c964bf4e0db5918b06e9cea86d9b63b22fc26bf8e415088bdd57671b4c58b6c91ba71a9751c6bd1c16a01827319326e17f886c23b2fec70b650035c3a98af57f22c24ffd0125381fc46559248212bf6cbd2eecd21518950737ef46983ce248d58807bb8519a19d066b656e9fb3a9047f770c7207ce52c7dff33a96f0e6ce0c45698e71af11a5fa842a7f6b5be6ae5059697a15338c2d869f43c011543ace6042e5f295e79946946e62597991c5c4150d67b62ba4c792526330f7b32162129f3e34af06056c48081fcb92c437aa89dafd930887ef732dfa5fac344920ce0d13ece18fb04a2dfa1c61b9b48fc0399716808854196b6a4d14065d58cb670a51b4e3c323884339d47364b2f708b81dd640fc3d9245c5ba3528eb01f5e81f5803b7819bd05d0fd54b0af3fa1e1eb356905bed5427b85b524f235273714d540bc36f4fbaf264f8f2e8a664992c496a9e680a01c5c4e1401a4f72ad29c65932d148119fddd1550f9da517ce38c44ca8e186f9d7f2094c5c1abcf6fea7621680f01e730d481bcc1e97c8196ccee756233b7a99157292b4c361eea50c4855bc298734069d58da4f140b6cf885369c9c0779cc24725062ef4712b45381f933c2641669568351f298364883ba4dea871426359f5440b72802a3367b96347758ea7494d1f9db3741572c28090bc258994b4a0bf64f1f0edaa060bd1b5d6388713011b52085581e77e7dc4fae80686165a7b7e88bbcba284583e5d1f05718e4c0960104c1478fd1f4ccab0ce0bfc765b5c6631e2e95cded4d50f8f570e6911600e8f61976b4c9d3e877079c905a6a3d7870f74072ed2946a404ffaf2c86148590e9c00ad4c303c4232751c8da3acbdaf53449ac9308221d2108a4c3bf8433494f27dbdff5e048b3640f40fd6c78fbc8edb3d97086faa0ac13b7d08c6782ffcbbccb1f1ac93f13396cfb87ff79f9efaea2ffdc3f69bda8bc07c8f59e3f8c06cb764768f0e73f9e69bbaf545b0bf7805fc7f16a3db5d802dfeae443a256b1fb0aa50fa7a60a023a2170166f14a6d266f77b495076bd47c5efc73820e3cdf2033037b64f7ad382f7f3dc93b4d8dcda2e8ce0c2b37e3a684b0759cd5e55b15ce950c106dfc753e715cd8c6e6c27a28dac0ca99e8b0ab872326ac358f2b4bfe15e854afcc04239b50c84f0cc37d419ab7564328696733d49f7727eb5f2ce30c870c0db998f76e3c12835346e452596599afb527bb3de9e6c01a776cdab88230cb2eed0c02b66826b77f32c188e578059e852944f0b7b07c1233302985662d3c382906226d1036685ba361fee474054c9370090bc5cfd133112516727192704317978005e8eff7bd2945ef6c107d91804fea1bb94aabb6265b6f9b602b83834639fdba1f1a66ff00ab58e415de65a9b70971aa6da7811c1fdd60c8385da0703e800914b43902edd866af543fce1f71d02ddc36cec590c3fa30adc80837a670946b930654c6990776c230432f10fea54e314bfcac5782335fc326abcc4027dd528694a94c6fce75a22a1ed1c4cd43bfeb5b17f6bf0b66253b36b7a91415750c187eea6bc8449ec923788b5eb3ddbd1cecc8cad6050b9e4a76d894c009c9609256a29e49fa460a62b8127b6bab33b3008f12f66cf4c21446dbe427d75333c80778b8b9ce954da32b0333644a958350babafdbabf7a2200c22f530d3dc891795c523a9c95bd48cf934ebcee89508d2f9d0eb26ba2087847f1d9b220feef04d29a1bdfad65261dbdcc38cdef44d85390e5e1d7adf260e6f8c5c63b07cf0eb3b6532d18c2a608bbdf33173b114eb609e0e8502d464a29d8cc01098f19aaa33d43ce10fc53df8d0239d225d433703efc258007bbb9450bf49dfafe22edfc479d28993a1df6ed29a545ccde108a632da823e016133b557dcc84e6a726687514e9b017b58bb0f8490084b94f43995125dd21c45b54a6f4286b275ba41dfeaaac150a728108c5690aea622807a21ae7932268a71552b35b5b563d72b0248580afc823a3810bf8eb2d268ae1536085db0c409822c257092027f200a72f61cf655b89385da30f5c8cb109e68983e452a84db013a606f736584bae2322427cb9eb33fb3829396ac4cc6f6f31a204eb2c9b68f15a2a07f34a228c80332b0906d675e88354c2919aef8c5f107ef83c40b4bed843eeea9d4349f9a9cbf4b6b699633c046dc9c3183f4abc447add74c5922fd2f8354ff5385792c687ce366b1740b6536640d2b84c4176e72232658033b1638c0bfca1f3a67f6c0a393c44fd93ddd4ae80553f12b25f3fbb126994776243016da910b4bdbd6f5ce5197031e287324585599b642103af14cdb0c1d66ad2c14ad17b138a8afc9a8492743f6a49a611a7100079bc06cb7642cfe2c8e24f572c172ce410f1261ad151e9523ee367290d5714b5c6618a1cab6c09ced64a0a7981a26b0ea181f0d2703046031c4c4029524af659d462a7ae4dfc1388b0d8248a24c3532a8a1486d416cb9949ea6f5e043b7f66703f2aeb9d85dda03fdc48329232f05bdc710392de64e82e0370480004b89a07fe523756f5d1ea180773123c92250ea2548b1c9c8f3e9bc01aea7575bed02a8d1990630f0fd5688876f6fc4231120ab9064ad0c263a1b366238e9a27989389ed087a653ececdda4e70e4d0878f12e280c11e29a4acb691b82bffe14df19fef18bb702f7abdddb237bf42ab670071bbf39d313bdf39c101e955079ef603f6654fe2043de76fb4c5023cd4388c41c45ba41162ba9a45e23550d29a2ff8809d98fdbfcb6bc23b8b4bfe0d944c13c51735756ae3a933164709348be8714c712c6d807b028ed4b48312ae91b98e386a7fa0dd8b5795a216cdc6e98f95c8d113c8cfc71ad4d653ae278177c39910187eb8139d9153c1cd56c38dc913715caa21ecf6dffb26504df10745299b6a5ab46a55d8c0cd5554eb4ee3a0e4bb494a68b407dbb23ae7a23c681f2fa71b002cae0251eb7549f7f84dd7903507abe77cae8351dfffb5a7092db274ae573c8b8092fca9eebb48935ec0a1a152fcc716afb23483a7af1e4fec1131bf420ac693e341d236e001a4c19342b10e3a0a2812e75d575dd6d92f4163940c953ecd6b8b9a918e7485e17366ab015ca65eceb4bcb5612b7682be44c620801c894db5b333cb12658ca75c721919fded5b9c1de2fb758e901956cb29201c901f7241551d87d53a6a6004c94966899f3f028d170fda5b4c001990ba26c814207972481b50d9144612dfa4f2ddae8b1d4db950e80caecd06373ad75d9ce0b9733d7cf81e6f8f2c4dad2f5adea9b98d30c99ddb8977b5a05ba9c9a71c13a17c088189473edc9011e73c6f130b14267f617e458a71c7a02d214bee65a173e5dacf700bde0d7456ececc79c6be847114b076286243b37afb283dde53a6ce9897158229f8047f6627a2bec2d0a2277bdb87c7272e731e9ab12a9aaaf2219a7546d1ba9811b2aefed336dd34de274070f5951898a4f0dd769b96ef177848703a8695359da0830cd8fc19381a880fb1fdb135fd4101ea0e1296c38c52db427f96405c9b1818e4a59cb217b247bed9cc40578f281262238e40b37930d1663dd51c7ac86eefc9e12ad6277b8512d952fea7ee450d92ae339eec48081e743a184c638b6601878212a07942c0ce0895344af91f36b5dd4c8a8d36967d0a09df6ef3602014e7f301fbe84396243227bf7188aa2a9c26306d75d8b641ada1a39d070735f6c8732b53a6dced0a4794f1c808df1554b786196ce792bc60e8b6fc2544c5237551adc60e0056da5c356fac62684d8ea3158dcf78e26b82fb425498bfda6b509abea485994050664e7059dcd04ce5976d0db28839e82896d99419e60926ec730aebcd1222f27407ceb49bcf692be4ae25e711d5459bd22729440a301d70450d7d80b2aa92a2a922d50c2911532a8ad85167073bbf3ee7d887b0f809433e876483436972fc32e0c91ed5e775811a67c733c0d95e288f9d2fad0b4425961a642fd42354b5df11436182a4636a47fa52c42c838155b26bf78240f43c43e128682ecbd4dcb42259a5a2b0a322ee0666602d34c246d8f900dcd9cbe880fa7c2781f769b1ba76e8de16b3fd2a69cfa704582e03aca8f7104b918ef29bd5b0d52de34ca83d2b18c9cc95cbafedda48024c41e1c9c432b89d14bee451711d516a9892a7343478764ed64a281ad5718330b5f31bfdf015e11ce84fc70c04cca0611a078bc2aeae3e62455835735c886539ca1f51bde2bb1b0c0746be8b5b9beea72b57df228a2fa52b8a381936968c040e5f1370c9c712f52020525b49b3f0ff8b62e5f19a1dc1f11a32d3d2221ad5eb490387dae7825a3f90dbd701d6a347b34dc3d85eb02204b5bc27f88387dfd4f79e86e7d8208115dd3de9b94727be2a619b1cd248296561d82f8a5463bafc1c9a4a366004b985b2d1cac1ec09e7345d93b0808203c18948473e54065c6b56d2b41278f801c3f1e176e942654986be4d29c9502305e847a15c7218d1ea7416833088b5c5dcfb91ef237f610a254e3eb576809ec515cfd7cd40cbfe04b21e43e523e096d4daa4cac6673591c11188152ce82405184e0a4ab26d89cd88b1f9c16ef207fe2cb8037185b5747d1c61b2893bc9fd9af746247a8450e3c3e57e1977329f4c648d0c8dcc988d3e978424d804423d298f591e5e11cb3688c96edcf07f79700e3d4f2b9ba1f2a3e714a09eb38af5a69e18e31de20c5c8579b5c33d1d7207c2957e9cc0d9eac8028898a4c0a7cd5318a1687b6633751943f7be648b41b7e9755ff2adb4e1b06035c78128fba018d5ae94f1294f1f2ac364886b4aad77a7001153f68359953cf9b78d58220e20a76648f6da1455f71aa53178ab97aae4eb3e8df24180553dad93ccee3bc4a7541fb1dc57f23424f2e804d59ba6fd8c2724e85d21d9a87b0974115f5192b7ec0d905de6bd50c83e2476fc8cfebb43d0e5d4402b9070ff2237ffc3f86a038fbf9c242f46cb61fd8050d3fcaec622afeac2c38e66cdcb39f80563ab51f67c380b6e355c86aaebac0172160c4f00f31d1e0f01add7017477ac78d5eba9075cbe6a98b4a19f03aae0955be6f0aeb21339584346d17b4f98c04ce6003cce100bdd6eb1336c1aaba7ea25b9f048e4fe5ef0fe13ef0f4443143eb1c6f873cb32c5429572b4f5e5b4f24756a4eeae51f82a2b2c0195896ecee68d54d0005e62f0869c24b3751a2fac18e4eac5f7ae69eff207c04f30793012184536070c9acbf498bb4617035f68abb7153a99170af5aeab7184d14b461f807407d9d8d93e36c80d866437ff4ac723669c41cbff9c9f2ffd63c4ea036167509b79f50d316dd62f0c08920175e3df1c86009eae810156d4577f24475eb730cbf43e68282c856cf89000d084d9c14217a46f114e9e36f4ad4ee48e1bbdaa0c04343450a830083a636ddcffe30c91831f05a9198fa5d8582401ac1f46f8489ecd1c64ac06f54b5cf7ec19121f0682fd7f09380f071294fd12af06d8b187d864949332afbcec609f103498cf5c505de0fcd6342bc5121063359d1236b5f5a7857bb228e21131199f02a303453e7f438e0e7408168403c34340816077d713cc608b00ddc908707e2b0d74c2883dc694b8a8a3dc8739f5e532b211970b8f19b85e740f0034142b03a5a80652290362f6ee91719230e6f812847acd3291f03dfc309e609931df0baf754546ffc4826fced50f22ba8c49f6a2a411fb36f01e10d3d097627c12c4a355eaf598da6cdbcacc71442e111c8e91d07c64c506af11078a576ac808f2b28ef21db216fee52dbb0f75cffa3f08d53fb347cb809c37699813b6f395b555bc19c0f99ea0c50a653672c98e30a0f5f28b3ac27de04121b6b8ce2183d4454f4d0631a95f1f0484c1baeddc6320f400f95410aa12d36c302010b75129516b96b8473533e8d2b157e0d28d1c04a13e2e984d22be5406921dcbab782ed286f18f4118fe8ffb5d186b1c5afbf99f05ff75811ea7e6f2592e882dbab6024eb182e143fe406d7cc0c78818872806aeeb40ff6cd97636eb1d421f4785f5642b33c1e32c86024f556c3bbde9c8648a7fcc77a55c3b440c10db2f929bc1342c5457e0ab7408302292f0ef60e85d541ad3f9c18e4de440200df44069610e8fc04436deb94c8277d2164135721223020f278a3e383700053d8d1b788d917c2663fab57848370fd95460dbaa626bd393185dcc7fbbd84a2a239d8b90891d5977b825ba0c21ef9978219c6bf67a4c7279090262a27ec9f7338c66578369db009959947d69e6316c0fe2bfd107c79379762ba3bdfca653f64b52c4fc5c2fa3efdf9bce9c090cfd02f24af3f5641626adf6341f51678197d4afd578d339eb41f04dfb20915fd62258757ca367e957caeec23863b960609c0499a67fe76f651e8c990a8179c7b4ec30e86e6d7b5c40882c3fab28fc6a480518d17797de4bd1be050aa63e115fc404a9425960ffc74c82dcfb38de69271778d8463b471ea68d6551de791354d9c703014cc9eac0f7c84596ad856c380f4dc53ba58b6680c2d001fb2f6b7be2d9fd30edf8c1d1720b02b062de9896c3295e082d7348f050d51bedc14b96401c258ae235370efdd520a29c4dcb3a4ba4a408419e3d5d0239f6be64b0c2fbea09cec02af9b87665d3eb3e5a11b09b7e2b731608a88ba510eac3b4553ccc1eb85de6d2bbcfcc444f00428178d6ec8aecc39cbfa22caf43320d8d8a2864a13ada09c38c1fe627e00bd3a1e80b02b04691946cd05fdb4d07815f46e6008113c00383aeca5fe5358bd2b10b950b6f2c14e26b22c9d780f7c58a3b035651c23c10eae0849210ab72495910799d900d9e78e7efc31287ef04d3007a4bb53a0840bdde2279d4ca961a064086f251d3fefb747677db81343de0bef0e465899a22aa68d1a5e648a2d43d8a5bb95a38f0b6a5ae99c80bb91dacb96237955ca0255c8e075314af2c2eb38e9dba6fe644ec819c14c7a9d373942e3cd7234fef6eb62ac7110d22e1c2a57f14f5c377821e859d2a6c8323b38a87a8ba5dd166777ef9d192fbc950c749b1d1a5be263a05ee8fb0b0caecfd4a3856108dfdd0d788074006f244e8a2ea2e19c51405fca6b7b3daf00c6bcb904ba589e39d0d5ca2a7a40926f0d5eadad7c289b012ca0977ee07d6b51ae603dbb047b6534a193c349b3d2a497143a685e45affe201e16977f91a2fa62dce471653dc1894966cb6245ac32dd171217d9918f72a9282c097e0e545c452e387501c1ce77614c9f0f63855ba8d7206658d5a0968b6dd312e5d80ee09b4fd5f673e792b566e6b98da939a56244d76d4cf98b028f3db3ce1210e4af1f4688afab4407651e19ef75fdd4bd2e8eefc4d5635fa1dd3f8aee6d608502db1e63b7499d9dd14b9730fdea08b565f4d9781bc7ab8c1b50d08fd6088d705a5d8261d72eff540fe6a675751cc9272055171186003c629a9921ccaa7dd0de7e092a2da4bc741b84412833c90ff149bdd44338d9172e1a5d6e1853622bc6fc5072936d66140343dff850f54391885c98cfe464122d3b20dff3aa130ee12265f5360a1aaaa9704de1d276074153a643a9f03161c062d9af66c64f8d2696429e5e14fad23fdf8c116a7dc183cba400626c1b9e089b980fc02208351e60b95981b677bb203c9be0fa2128b5b260b5e7905bfba1221990904d7432d6913a22bfc861899a515dacb8b3e6327c9f89eea2ba2efff70aa47e9e62644b4247484955c05369b3ed395248bae8aca13555efa148b24e35af0058542386bb2d76eada065970e01c49f932f1ec4e2ac61459e8f2f8a4f715380dff02658e807a647ce1875b2b5e0b6d8453b3e7fc828b3d2f9cc9582e2ba288eb5f7e6a72d225c30a46bc72461cc440f33ba4afe69c130141087389a4d8c263461e4b2a5995f5b5993d6362e431f09d7e3b315ad6951098b0c8454f8aca82120497ad786605208a68c86fc1c40b89aea6b54d98168686ebbddae8ea27fc00c099f22b0c44748d6ac7ccb58f43811621e6a0a85b0aa2374226607961453687952c88d8b70a9163515a0bc2e213b72def7a94cd152b6170db16dc5b6b5948d151763af4ba4acb4dbe84da5cbe71b37cdf7bdcf371048e42ef4b07a72083e06e3924d0835c16cd717632f13f92db485b6443892fe598c9b8dbe1ddde4cd82364d9f35ed9dade2b99407677a42fd8231a6fa35e1e447a31c04aae501e3ca37415ba441541168859b9ace0c5811571eb439443186ab684341e0bcf8ad4333ab9900a43c972b20f4da6de1f3af86de17075f676e65ac0528ae9dfff4bbf8e10e50b2d6e1276508cdaad49cdb8d1281f0c0c1f4f396fb714d3f5f547649e516fe6ab86853781ce2e7ae05d2a4100f76054dc1c22f814063e786ccd7d910ce3bf203458ead67bb99e2c4ee7ae14c8ec2b9bc45865f8a08c3de253ebf02e709cf852be00c7a4074346de7063b7dc60ed09c0082fa7eb6c0e2884addaacde7b9582340f1cf815e2646f8f6745bfb4070a82973bedbc4834f37c51fa2b8381a3b401057433bdf4019840962a96a1d77b3721b02c900dbe572f0e83ef60ba5dd5ee461b3256ad719b0b9790ac8fdb64253d47c11bb893f7698386baf440674c060fc11f870c048c5c16c7c2f28624f6f27e2b3d4c00507d536f079c9d6572726f3064378fe89100d51fa779cc28db7b3ee8c6cfc0192fe0716c888b46637992920be8ba9ffa259866d27de3fb9f8f237866a6f03545474ace6fae82ce727ace2bbd219ffa5cbbdcd44d9380675a26e8a9ff1ef993dcc3bf5e19e0c5c53e64514caa7f396a2efa84b3710a9febf611b14cdd41bf63eb79ea3121b2bc6c3633a8eff82c4f7da1b4d6a020c5af387a9d2f00541afd11e652ac432b59409f45b8c2b38e466e0a33f644111b64235b661d109941d8fc9017d565c0f3bd80ba722969441b9bb218dbf6ba37364605ae5b8438f11e49de68a2cfae6c83c1364ce12b8ffe1e47f4453eb1d4533938ba72a9e8e0183bf0785efbf748eb2aaefb343119cbf6fb5c27f32fbf592a31ae67dd2205e6d926e30911bfa1bba6cb22c44aff642d9ed1d636959b87f8ab6bf10e12b2f6eb45b015775aba84eec7c56e3d7deb2eb689f51cfce2f6c8ee77c4a1298ef8eb653f4dfa778c6cf7f50d51fbc92aa84658b97e7218f4977508a100fcfaee4834d46bc03b61f1e08df544418df31ed10fd5cbd621af76fef119d7a8887a1640b0825de028c295c24ce57a890cfb1f233d0ff9afef1958bf7253c830e9378921d911b76ee0f34bc6b7eae6c437a228a4c95fc513d83fc8b343c607f79d75ec73fdf30fb091c2baee1bebce0a6efc6354d2f4436a7c7492fd5504350fba0e3a52a0ae529f0fde1710786ba5730b565f5fa302dc35c578add5291c3b9ac91789731f26b0525aa3a752b845babcbcafc98cb9da6139009e572aaa06720e0728530be8996fa1880eec58b3c405f3aa97e8d54640e37dd036c999d42d7d4d5e76888b195b431086379f9763138e02501557722edb0501327805ed71c2c4df2cf229ccc12d9aba860d79cbf14210c18063967443257d3badfcaae2ce5aaf2f944b822fb28e5a949d66e1cede5d99bb461875c847c928b8bb488f74b2d517f2283a595017b10eaf1272460c27af9e7f4d4d05ae057d84028a7f22115df635ed374fff6d56f5bd08ebb7df676fd920511721258e657dc366e76887141cd0c974674d97a85866de529c12dd7daf8a5b9773c4f7003f98ca88e8810cc2b55155062c0342b7e7afdeb3faa968df8b98a130e82b30b647251ce5af79a05acef2d46f807a2da070d06372e535c329172f1d4d90cee2f825e97bde04852247938488bfb3d6726b58072b76efea2ed8aac45bf617f520b7a3086f947a9771ea910fdecc92b8874a6539227e0a2a3df1317b919b02880815cf4663b47d5c5840a84ee92c7cfde56d3524529a8dbe392bbc5e855f31e107a117918f9412ab8de8d337af180bd6a4bfa82c38f58d8eb46553b202c035fa841dc94c4e7762f9bfb011f7fe2003cb2cc7bfbcce14182b1cfb3ac393f9fba5d5ac27e6d5f80e96f4bfd73899fe17045dfcba447c04de369969462bb4a56acaef3bfe3ff7d4e1f7feb223d6a940912b84f010c08000282dcf20b5f5a99c3c00e938d4146c1da8c35120488db8201ce5ab949437fb46e4049ec774f9a5c08b8b76bc87c087ee04374cb6ff76a1b00fb3e3468b41c4a3e3792a7e5d3133e0fc599fb6030e465f54e7098c371cef82b1a9529394412988b0fc96826f614a1e95e7967e26982c310523d4f2f122a027c24715db5423659d67f692710866f6a4953e2dd90a63925e075f79ef10c277961695b0db64c2098ac397d7c45f83840268e98d00af2c3971b5e98662ad3c525e5d784bfd9ddccfdbb3c2faae25e77a727089fe37f2d5380f3df0cdded4f8b6f182dc8855b39bd20da32737f0fd4085ca6d7c6ff8428eb9cba943cbe801b32953832993ea19ccd97b34a6da33181ca69b2edb606febd118dd914c6f858e69138a37781a17188aaf52631d6c567d77484a9aa8cc284006a7e32ad1694ba9d8902742682da80e97b78262b2a0940e77f7bdd2d5582c95c5b1a8b6d540b11029e071669319eb7e377a8badd8a93e29f032d4a1450a8f8331d97770975c589617141bb00b64ae36f50aed6574d7efcd9f6ea18c0eb22d4101510c962a7406f3a743cf9dc3b28a8a409b2394658a6a8ce087aaa6d2135a711f1f5f906f99f8a59b9491dd3ebf41ada652e9eda9dc8ae0b7a790f473cd92ccfa1bc0a2593bca6f5e9d82cb77aa026b8bd0e7fdecfe6e7a8362a9bcc6481e7c7c06dd2b1b979fb2e688edfa2d669adaf2694b345d1c0420f63efe39a14f760bad0835f7628c36677ba6973e4a3d8ec4b6d113995e9a51c62d1e80a15cb451cdcc39b19da32cd86090b45fda6164280d7d8fb2c0af89f21e654789c5e78e53fab7ae8c53b30f6a7dcd602b9161c1a12dd45b613978ed600b5dd792338962d8cd88e450c0e87c0330473da7cd227436fa3f9143a7f6d8dae3949daa004aa34ab6788ad11e05beb5566cf4167e4c094c380998861a7d664bc448022c6120e30d600950bf328e8d717ffe885410932d0c73b537baea0969699d27a88c412c7a0565fbc2dbe56b21d1e9988a044cb631375646bfeb1a29a60a6dd3f3c0d4a5970aed62bea6efc993e26ed854398e75d7e7e44d6518f556258fd1ac76a44481162245dbe53c759392edc86dccd4445e68b122aa487e316cec0ac23dcbb85fc12986d49368fe67385ab00958088ae122df96591d7ca6eeda8defb262bc446a08167d552c430b1a007c7cee3632dfe7e6c6d223379b03aca3a4eda4630635e13ebf85576200a6cc0778a6cbb4b17921ff8a88209d3ec4a106268715f463dedb313ee0c04d078a807a07478559b7778e35b57ad1af35db95f87b1f45b61eb5e0ef3d16b9b8a815ad42fc652fe0de463cb7a4a5cc43c6d2c0784550c138d5e3970fda12c966dff9c7f3bc9469d7b9e102ad52db75b2664f376ffe2e9da7127befc91ce78e31d0553e81fe5bc4aff6ea82d83e173b3c8c92e41b4ecf468098a50c8aac7bbef8a1f50c728e82d96a03edae0c1cfc77e9df7986a3494c7297b352d415955548c4f214afe114bdd931758318a3478291276102688c6582244d531cb06126239d20c137b2d90ab1a440241fab6a690400a8a6ea80113b2489e68dd0f547b324a05bdcbf8a192dcd57722b71da40867ce4f8834579f0ce8a870f6a6b4a74fe5c227e1ca42b3ae220577098344321a59ff0b1c6bb80f9992d6555c9480be681dd0bfee3e942932bc71f1de77ef65917de1da89b84299c53a2f07c40cb61527cbc1f42d34565d08dca3a75d50a9ee215e0502ed2dc20c7c54fac1821ae3a8d6f959cd74f260266d05f43b77da84d41b6ba5841810ea97829386e8011825130aa6075a5c97910ed9bc9c11cdc46d821a51ee0bfea86d8317d9df110553a0b822e2d78f056e293ee63ae779d9bd4b0d6c210073a473fb7d1800feeceb3553c8f24bfa9fd96562dfc34f7f9bb27644ffdb51cd2ae8d92a5408ecbf0eb6af4661b351d0a764bf11da75886e49c2f21958da5143b1df7fa13077434ae545a0fc8822fc07f75d403a21083b84bdf2817b5582f8f13cc7d14f853878cdada202487c6bc5869e722cb5e37591a3201e96fa4337d28e0cd0289c2409b387e1ed92347d09085cd9bbab97ab650cd9c0270a1b6b3efcf306d41089d853b8aea0003111cf72e9a7a7e9d95d7a8138517d6730e740d9644d5f7c7ec25488d71709f99d3305a316cfa69c831704af9e81fd1330588f53fff3dd32e566e47abab17b0a86bffaf6f4ce3a6e2a953efa89dc6c02d5850637aa9ae8225f3723b8bbdcec05b2966d4ff5c5162951b4da24454663489d253f9682254926581703139c84845225172672abe99f8e654f91118eea1065a5ebd86c1eeaa777948dfb387a99af16d789501d4c9f4f0b3857d4ef75f8e5b78c485500a01f73bc9e88f4b96bb25a108fb8424a49ad2e810f2eecef8683ab1f0a8873abdf2d242afac87598931daa75d3d7fe709ac056110a053d057af375714322c5dfd8099a0e9e79f20deb5c00a1fc22f7048089929563cb1d4ff555507249da7e9c303bd312d0e121cdab4db63a5359b2586649ff13196b3b23257b7a6411f58fcb562688c698391ed25649b43963d0863108a2cbab54f57a1f79b88616df9ea35aadf0bdaaad50dbe66383595e9999b20c898ea9aaab5127309bf1e7e96c7a97cd05d35285a49132ce66e8280407381b47141064c69c4fd1b083ae18381d361275533a103446dde681717b5ebbd5c150c833321ee8b2199a926cdc4209ab945ac0b922ffd8de3bfaddda5f2969af2d3f90354a5720664319d32e7b6a35ad6926bde4ae1528528e9f0f599160b0e4ca89f96e6a840beec7dcb11e57b3fd5d906659e7370ff860aad6ba1c4a6d690b6ba836cc744d0ade3bdd7059a12576f6b8ace74c0407104a353a9be98a8b8a48e9836b19de4a07c75758a0c73b03046921b55ad532a6df5b8f3041c16ed7f4a5f70fad5aab558d8f3f7af43617873703cf9d9854ff297259a9836a846be54b40d5f8c187d1074d0a7855c347d18b0655b27949330284c9c6ef984041b029cdd0eb91ed1855276272d953672f9cb8f17424c401377c622a4cace652ceba36d2ee81a6414e3927456fa84151ffd5f026f7137b92f886c458d79d4f3f72b7ccff155c15347e795859117c22cd44e705d20b128d85ce83648c38098433c45be2de2e4eaf644d4b5b067838fe57ff69dfce51dbf4360c19e90e5ceec6c044e38db0c0dc8e9b01ce4f0bfc5c9a3addf5f1047d2fd0b4495f1126c6990b865e759937643a35b5161216ef9d45f5533a4565c3212548948692fae0c827d175d7a488042a9921865f1f494224eaea5fa69e949a9ac23ddb743e230e93d61768d6ef062f5a6158ed9775336ac3ad2c6333aa21073f6446ed38b0599685200fb0db663666753402adbf057c570daad8c8550f9673eaae104b0306625d2782409cad601f7b74e0a8f9cb964829022c781a1bee49317483c8e2acb6fff67bf21d0b32612707c2cf4898035a94e8a14fba5c52fae18ea91386058ef7ad20513ec7061feebc49f9f2387cc45d9afbe320ab896fac66bf63b06d09e087ce6c59a2bb8bec9458f13405dd8c936d36bd7c774470e93441b1771e459c0d1a9eecfebe320f82c7c1bd65744ba9143c0c5a47c29e0cd9eca2ebe19372a323303a23c8b3b79305a34e4c1a0b5a40f3f8009eb16ba734a70131d1c5f6f4a06946d4a22c81b93799dea41a21afa47db29f30d7c430894b63cb3f8da20d2ad5f31287fdbc88cec245f7325796f520a09bd249277e5e276638c9eaaa1611876a7c30656618077a728a8b8a52c959bb5c363184078072bc1d17a8f592cc4046ea1a3fb2eba9564cd3928f76122d5b9534ef26e82f4e549f5560093daea4eb89b9d04f668f038563500ced419b3957d3ca5b24aacda8a0e7c57abbf11be2b22b5f39845824715b014e388ce9f6f2cd3eb75fa73fc5d4d3649f28122d6565ea21a1ccb272e1d72345c3a0f155697df4bc310e9c43c60d1742f13d6fbc1af0f0d6e438efd1b3b12a196068de9f27f849a395c75d838d75a26ff5eb4f1e09871da8164d3ec3dbe05f77843e8a1c03be4409e0e0b7af31b2a88576a3f16851c5ad18ffa381563249c18ee0a800a2d90ab15e1b9ba02d071f2cdeee6b4d67f3e877705f4057ac983dd3a40eb21040475e721295eb4021fe755617e1b2be9cd18898dc6f64cda94a0f75481e8d2792434a0fd10d1ea5c35341a4dd5d7a0dbb0a71bbbad7aceb2ff42778ca616f6c112f5ba83f4714e75393c2862233ee5a0ca4c2f8f06a5a429108db35a8230a952e451e358a238ce1aae9af258c4f50e2c1f1cf48a98472cd241d29ef248c16653372f1347104d7ea4c46ebc191a4e53606fbdce714275b76d890efd978b0b5ccc03de7fb7acd6fe1e11fa60a6060c936fa1ceb54ecfda0a975782807cc199c8a99b7985e5e50c165a61738cd7dcb8ccff3085ceff16a84ac4e41fd3c89fd1c58e65d078cb9b32f8aa8e48cda0d77068b9ebd150b7b657ff3297c06d8a7a2dddbd17e420cd82282da3386e9b6adc9018de5d7c68cb5696b1275d440986904a30a4928ccc0dfa11d88725cee739a127019e81f98cc81e76f602c551a0d6e8cf63918948a878659f8ede22ca38ce8c393011f558533df3412cf575cd7cf07bb8acc0d07160c21ed9df6926ced0ee0d334ce3dc29c130bf676f5205a08f970262d3804a8da5374301d53aa53b9a328208e5ddaf7e4c73a588a73e796783bb3ac618e4523d1821288ae2a28b4482d87dfeb1d7f0735424930763c3cf8f7276d80978209f39e9d6f3a649695ccad95a309d466ac5d13ed801e9ee12ff85ce570885928a29bfff2ea47633b933c16ed7aec3edcaae34af8916b18c2b38381647e06a74872d526bcc5bc85b5333beac7522c20de7dd8d666cdcb53bca2bde7d151a8a13dc2ea6cbf75b9ba7b1ae2235875a84717da79d90e35d485e3815762bfa93d1a996a10e4bead328551b41cf5daf7691a2fa6030e9beddff877d2613c09a095b003847555bd6b62bf7ddaea07b64444013e272befdd730ee9cf2183a9f99e060ee551cc71cb3b578b2f38e2d0169dd8ebacb3a4bbeb4ca40275bc23ae8e86423fae3999d37f08ad16581858e6c6e2ba6be850d7202cb25731cdb19fd370a5b087e5d800e7e43d07878ffc7fad8627ce3680bbdb49aca6b6974703d39cda41883fc5e2da08667563a9f1fbf3e9264257dbdfc80edab56037c1d0eab9b4b4955f3b8a53b4dce991e0ad6ed4e00e744b871aa25db60b6bb0a5079cb335a2ad810164996a9f94ea8728c1c01082d479dacf541a5f1af70672ddd157a6cb870ceb34b3e43748145bef3a48e4180c0659b3d73d81194ab751309dc3580e94027dd9e6a875632781d24a5e083c8335c0ec479e18401bf817caa9fbc22348aa4cbfa35fa3b03eebf23a5db02d4e2db1f9859c7e500a12f7d3eb0ec301577e52f03882ab153320610b3edd0bbf05908a10ca47d388aee06f4f3d0abaa723a13b989e3310ab12ec40710d2e80045412338665d881e055c66067a8b4cf4ae9ad0998a5e830b9e6cb212713fef5ffb340d3c39dce240f3c4c9bd33fa6b0e2d8e90ff3ed12db9d1c27143be8a9598b33f15426df27ec99f09a5bafdaac3c961aa16281e3571869e052e08d805b304f59aad9f07db75c93e6cbc6b697f332b604c22df4385267cfa49ba2a4c610e35a598e60c2dc9b905c89f528d0e83166d7cd03108c914232ab810a54d5adf2b39c41f922c7a2635baa613e424efd0bacd21227e0d47201d1b8b7a24c0a38d42f5f63be1ad9651674e6adb9d140932906e9667ada46b2931a6f3edafa7b92b25b598db046f131c3ada426bc474989d9eab98b9a00252add8aa8adbd841d27f1c716ccf71120bcc687b14b50f1b279517e31675d4648389ea1896775d870b62c10ef3a41bfd1176c2838d046fb82a72027cf59f1c364a043fa13a79a1256910052682828923cab1013a447363fd7a1a47e4540210f9712ed49b51057da3372aa12173648b23321b35e4ae8f06b1f0570dda9a1365407c46ca73e40cadd33dcc900d79ae3969a769c11f0abbd334a527833c02a29007bc92624ac2a6afa440d24cb22697273cf681915c5e1e1301e6654532ddc6ac00c8f8c5aae063388b07c78a4b2c8d7a386095066f361fa5a027bc10111cce752495c6076d7787987b2908d722e1c9f1ceb5c36eced18fc31e2ce65630acb8aca84d0aa759e79113431b850312a58f1cdf480aa75151381fddbf8c24d11accec1e06e1a7fd463b216d8d861146c658011f61018e06665a704a06529592742288e37b645a4266d50755359ab4ff9b9ee40675e9c7aaefc84d4454904d7462ca29889e685aeefcbd2d91b5927cc9811a8548f1c28eaa1fd52fec07028273540073a987a47b65e2342fd936bb7c012e26cbe49246e953c92fa91c2931895c5713b9e5a293ff93452c062e6960bf93319f49c71edfef334d115078e66b38b772d49f8b7338598c69db99fd7f620cf1057d2d2dbae8a92a167312d8f84f6353ff8629631d5b00ab98274342458bb3f06e3bbc52a76f59710e437f301868276c23136c1faf8d185a19368e22f084ebca23a40f3850165e8623724e2c7068522aae95fed3a8c4f652cb3c043d98e2aa8ea0d564d4457d4b532f9118a8c26fe02ec8316984955050332cfc7474df770671210e2b4a641efab66b5182142b49eeb594274139022537d0d093a24fcf5c550810daea6c78f3cea0d7c578f9f4f6753e4968325ddac3be3009a268605571153b727571d54303c9c1acb4d6a8b339d670ecd81b4961c7e10f05a207bf97f27a6a35e7179adc88ed40879bb4ab618fdab7b9d691313b81857438fb6dbe228aaca12e000f46ef0e3a9e909b347b1e51d4bf984620cec3fb425b2cce371651068bf59a2ee67075db271ba371dd374988e82ae8bac3b6c3ed5fb5f68e760d70442b6a2804fc7104953ae694a677ed580f8a2c81894b7c5a64def312bee92e6c20981401fdd6052dd487b70a3dab2186e576428d3de5396eecea1e95145e45ce6d2f9cd06e0000f6ef351383ffd480d3c73a38a9589ed7cf64b2f79c462f47f0cf88aacd877c5a91039e4ab0bd9ef335006a0a45f5c74ce3b8a370911baf5b2c5793e7cc9237ca4f4694da4c5715fa3e01ea7169fd69dec76e68b8e8c6e26eda2934d6bda30981bdaea30699d491a09454fffd5fdb366695846f350bc974300c5732fdd4170888b90bac847c5d581932935368964493a5e13f749a3566094d33ecc0e920cb730c0c0fcf3910e0c6bc84e9f28d712b2b586d4150795ebdceaecb17e435a87c3df2a98f93dcd56d351fcc1c18c19711d103f001e70c99ba81d2e82ab16b1dcbb3a76c02713b5cc52843c3d98d5e6a0939f5a414a7932caa97718db08285a9b0c449b2e7cacd77ac3163a6eecd9ecc8be1e9a6c2a8a6e8d6590ecd65d5723dd95b9292ed0b7e5da86d787a9a6f115cedb269f95c35abc2d9e3d3f5da209548cdd04ce4f5d4308ef1be33f78c7301793f88f45d250b188cd3ce1e06f607a6f4c728952db48b13e0c0dbd7962ab4c95d83ab0e99fd6aad327aeccaae2adf8928fbdaede78ac51230e1dbf8cd4dee8d72380cec273d36d0dd4b7cda225e72b6d9e098975afdf20c2eb7ce4077f55b8e4299af6f9112828f372d558674a60f3618926f09be24581081908bf8d7e02878922d4836bd2794148660d3428209522b86383bec4cae035c38f164ecbc83c0dd267c3341cc8966dca7301890f38158c92c197b6cab1096b745426e92e45dd7814b096c4743e794bff3b48acc912a568dc1efd6e6534e3ef76fc07625ddb6d623217b8a3bc29df8c968126164ba27fb9f89efed6b5932889b907ca5e003e8a612dc811fe2206803ed461c7fbb81b0dea4709f0f2963238a59052565e60dce8ca0c20e3f020b575476cd9cb033083e07239cf1276be988330ab9693cbb08b13545c6ea7bcd6cc31f3a18e71339a5ff266a4437fcab53a713e9e67b55a7dc06c59911f1d3a8f6559f8ed2e033fabaf4fca00c41464caa32aa7e8fc2ae347beb41d1f52b3e811e7787e7330766384d49755c8af9e3042a546dc8524776a5e67c82edd02ae5b0a00f97a089bf612df56b8ff5eb5c5d1ced596ce95100367e037b2c3c9a91220317f6f30a8d09e2dfb43ca7aabd2b1118d000afed11505968ada62bb895a350d14aff94b90f028e378c3b875c9d55b7e16643e7861b910c4dce27e1ea3836242f0609206791f6a61c40d719ef25c96988840c5afbef9c0f465ca4fb9bd98100f9204b08001e84dc0006051acf1620176748100596ee0601ef70420ef38fd032edb1d078e98a36d8becf0aaac4c56129296ded04f9ee5a362b2781fecdcac299912ba9fc310be03f51fcd4ca6c4417bbdf2e71efd56fa9303e559e7c59d5d1ee8604650dfaf0b944246141af9d673dec6a19ec4168638ab8fcf29396f12393a2a3ad1bc66dabc5bb927e98e7d8923e8eef128a0786b41acfadac4a0b829591dffa6e84d496f6ce71ee7d86b4f8608e5434f6f6cbe6e45916ac50b4346b912ffb8918a80c7a14965c3f580228004d75b3306ee2ff4af1821a835f06df922742af8219f2079703b48c871499182ca5789f3b1321c79f809b17db3c420ab46c260ce9df542a3e64348f84e0824e621e158489646c67d560035ed3f9ab8edf4fe0853f2064e4eefa0266e2575945db387783074c22a0d4bf6c2a537d8c3215ec23549937773b4cdfe784ff4f3250fa5cc81a6a9c725a8bbdabc253778e7149ce005975ba233315c5fa52001d10ab7bd3f08519d5b8a4091330615c96e285203c5104cb0494ddc96faf649217158e71c1f579ad1a2acd7ed3819bc7d6294b150f9fc0bab9ac653e8fd856e9749bc6e316c12d682a1ee73a7e16b2fb181b5108858b209b9e092cd3fc6d2edcec7ef0ca145f2239f882096aa7394d9435c05fb1df8f8f39ad4e45e7c15bd33b116d14bb29d652bf4f28ddf19cd8dac881d452ee16b225179591cad0a78c847d2a472c666cee1bec59509c5279b353c8e98968b8919af60d941a0c11c03d4d6b76fba1347c85cb4fbb90bc4f4497b7e2d494e2d30c05a8e5fd135b37556a3e372f1c41d9fbf055670747d13b0a592be968f0b492a287aece4c23da6e0ea6eb6aedfef4545017e3e46ee1c93b841edf9dc38088127941809a0484669a558d6310f529ea18023ccb4fe8f976c764b23ba50cba85b8781754ba52aad9a3844a2ab7895e258c776c97128ec5074c029f9ace1a820d6b0af5f2ea74cb06b8107c949e578ea9f07fea17d192e938d4a7a2f3adc56a5f5eb4030a8f444c5e76ca378a18fdf8d0befe35f65ca206d72c65c948a1a73f21867abe0f2df8bfdea4094b39bc61dc7571bea21031b88997b09a0c36cdc0214814ce17ce5be8e8112136c74e1c15bfdc85ab2df94bd4c214b07538cf21791e1a00b7b57be9f41a118c4aa348b86cc8be9b793b8103aa30e46e4c7ad533339b761b80df657e51d0fbe54c379a3acb973af1a2ed47bf71c63be6cc12db6200bff75ab440a2c6f7c1915777f937d3104f2e5beda8d37baac62b96b84fcca6906cde63b42bd71c8d2c3e8bda925bc8553d878362ddb1298f1348f86eaff21bc98f744685b548718b150703207112559c60618cd9d6270b692926e90a207310447a35fa828572de92a88f14ffce723aef9e7efee03332a52a2419581d5d42b15a3f41b548020b2296ec9687b7e19117ad9f835c8d111a495de68888945fa2a77a6ff7d4e47256ee3448c1e335879253efb7a62eb167d913b95dbf3480753df5173003ab6b2c7f51644945d0cbc6eb2a023617f36b57d00bcfc607c1f6fc7cd29b8644d12053f80b48bd427411248812314b9b2c8b18004d4cd2f719d61440604441707840fbe97f4aa4ba4a61d06c1c88a6c5fdd808c3e22f62fef30b5870b5eb9bf781525de773dbbde60ed24f1195a6e92b5e7a5dcf4f73964ebf034624e5199e8012867b675243a3779ea041eb9a9c0fcaf265f71d003c80ff782f058c8f77df5ba05dd30b0affee295930ffa6059bd3d72751e068927457f43e5f1a6b08b296950dc8088c370dae3f31aa48b91f906097ce3b01c2f14a164102fa6483c5130b8c04d60a4fccfcf73a798e6205dbdde4f8ba89e054167f5903525195063ff64e6f351e5a020f038bb856031226150331fddf1f9cc9a6cd862077244bf38a01f343d0022ba7fbd94920486303c91ae2a51de3788201b9111a3723ab77e17f3f9cdc18b28ad7ba1629ede814efe0a8121fce02c1c0485c3c3f1db5d0533515427c87ac023a6e526b564800f01026d986e7ba3a3e2a29d55580be2ef86fe79d7cdf09a6699423d4366333c407e623a45dc70ca9271683788909248f2c1494518da0a74dacb98d93b65551396facdc6b16be2c07dace04d014934f1018243dbf68ce830a0c0b42b3f5442654312bd462c2206aae97a989ac74d7d12dc86ce6760c352bbc43edbb63b66007dcd7a89e3f7090fe6ddb011b0bb748f070bf544567d4fa138a9bdf7a731892c251170497763c1c00b4721d093d3914ca4f25a53d7238b5a103e747903eda6a7b7d00979259dc28fa5188aee7749c79c220cf7c360fbb1d3902e36db40c33efdb39b067c9093862f3644d7d7f1a5d4ff55c3aeff4c132e0a921d9464c205a799f04785581afb6c51f016b7d557e2b00f83f98efebe56ba61b201e409175922fd430bb475d65ff8a800a597909194d1bf94b89254f9da9572b294fcb65ed527e390d86e105200317b5a38fc78fbe09503d1655c8d9d39c95cceaa3718fb2931508e9d41a52e4b1a42f13adafee5da3eb5c373dc290398f823e1826bb0ab6c3443f42411ffbd2a29cf4587e005a49422914ab57f8ba92d2a4f0ffca5ae1ba131c888fe0671abe03944a672cff7d70f76d409c9dc4bb67873d93a5e4c25c75d0a27f12689141a28c4589d015340c540a7934bf243e91048a0f19df95819485b838a9f3ce11cc7926c98ae6c131362cf26440b8f3572a138e5eab45884334e9ab4074d24d1f545f8ec05a620152f5abaa9dc7bf71ca3da2d074ccc78b43df0a75a4c15a9d80f066ac055b26d4d8ea430560ac402c15c9f745e62a8ee9bb862f564099fa0eeaf9e9eeb14a533a60312960e117ea5386578005e48a002c56496500b4c2bb36f36a667b84a3b191603442893d3a9983e01b41bde60897cdc6ff73e844a6f18af02fbeb398bf9426f765803bc053702793840d00b9bf1003cf24659383f9c3d6e1deac23a1a958442af39438606589139bd926b653e17d736a6496bebce95ac8bfbaaa9c7d26efb091e102dbdd7f78e97d2111af0eb9a4a6e4e8194498129034e8b526e49c4c3c8465255616757621b47ed4c98948633a9d5324c9f6ff3a0b9cf1ad28d42b460ab63c00624bec26987da2012f6dd2e1b16805cf45f6ed4e13e309c0ad44e88947acc3541df1205757501507f11f66a0d732ed0366f192fd5542996dee2bc95079db3a035252672e686cccb7b28c64afacab0d458bc3246c9fde8cf48ad491f08411ba408b6add5ab4b2f80f3969898064d8c37b460c694a2b727881fe5ac515a06c54c682fd9d18ab16384c77ebd61c68311c9a50413d6b5051d54e159a61d3a60a5036c535b9fa6b4429b73900ec084fdaba8b468c316e005aa5f29a059d0372e059288f9ca17f38c250123b56a3c91032bdfb481e64cfb639ff7fb8fd345435572e2add48ce2e180bddc4b8dcf430b0ee85f74f5d8cb991eb88bba12ea6d79c8ee4ffc501816ebd96c86e659aea483cea45be6edd0210d790e24f8650b965e1e39a1136138fb0ca045370d67326ab1d7be65f0f2b6fe7814807ea17fe0198f1127c1a0a9ff8cfab3c35815624fecc63938feda3254d318bd0a2cc277466974d6d3748560b994eab18de90618e453b35507c6343e1f378109f0e26edfa1337b2caa38727feea2cb014084187668d0c44256c0b67579d17be37c2d0053f5ccbfa6c1efc6af8d985680dc636e0b4d5dc524a473d6a5a499e5687ff91866382a9c04aaa524bb0fb48ed21c83575efc0f8a8a80b953cf4c2dc49ec3581e18e55a6f8024b88bd5426905eab6ef96d940d0fd2618af49c00095a57a7007a7900ad2ddf87118716bd2f6e0242d7cc4e08383a5554cb5adf52269713dc91cc44078e7d82daed1a09fd644800a5720467cec40ba99d7a0c7a479b528b440d64ba0357934d12e55d14c67003a2a5af585f5769552023920b06f345541a8df92f295a37e61b92574f6e36ec21d411f4dc98021df950e09735f420cbd5472a9e88183b3bb353b2d79df1a2b402fae67457e404ca2af61b3e00a3647d4f42e1acdf2d6da3f94e657075cec4d8d9055894bf321073f8296ae89eb5c782881d69e44c670f027ea1964679d0f0b8099dbc176a86f663fdd51e7579444b4d498355560b23b2c9aafd6615f852c78ab64ad4c810312c691cc631c4d3bad1c4e02576cb03c862c14b3e8f3d5b445f88af4a1fd2fe97443853e1f904c0d3747b058168e80f12edc383cdba76330fcf3e8f5c05a8acd11ceb24fcf804e86dfdb80f03fcaa7ef8ffec20f0411fd7da2b38eae7cc2bcf91612ec11f8c65bafbfcfba142bad03e45ef96aba001618eb0a426343ff8bb4c290f71d43da02ca28dbdf4a28a65196f0c5eb54301f409dcf58d770c4ec1ee2d6997c5b5a66a53e32a68dffc4fb89721568d70bed68416e29c92732ffd5da4c8541b27a0c51d4e373ca90fc726db4daa099b53ae5e618c99a16362ea98cc600977c78a9787402eb05b97b9196f0aa9da5aaa3bc91841b42e1ea8cfe8c4e283260cb6afc283bce209d6c81dde8d9cab05615cd7acea9a7ec880bcb0d0e7b74b97dd94b0c91007da703b07c38caa63adc7f9d57e67ff20a6904e08e9c119d9683387fe4015c0242aba057a911e9e70c6e5ed9afe73dd2b3dfb5ae29d4b06976ba005064fa379ca8a1a11eb3de1342bbd7d5aa32419e885b4d244748117b42bce39f83092dfecdbe2b755df8c09976ec5d25b98c2ac053682d7e41f0b85981eda679699e1fb588b4e49107132aeaf538fe9e7e5231d12471107e8839d7d8f170c67ee63c69e8d33d46edefdaa93b1f8f1b4c4a6463c0bc428a235e7a822ecf471e2172c2c04e570801e38a5152a1839c8e50f2201302b01527a64f523feb1ef901243765fea6a5ad639bf8d27738956e8480e61e0c607abddc01ef320bc0148e053c405535f38b9619b9a2ff05e5e061308cb1da54d585bd244c9c95af894b714a14e7c58ce9d5340df0108e4d888f6df3fb1b58fc0fd67e734b40e1dcb770521b5103a96a23108c8cbbdcf308730e7044ffa3efa2010f5010205870a5f9b4ca3655aeb2dce46bd4b922f352b6c934489a40ad9567a022fea884c963a7716e660eda171ba5d6c8bed49aa37ac353a26da0d48b385f1b71c68b1b5d84b1f93fd22941f8c1b6be92a30017a286d4f0e5c566959de19b8c37883822db147d7a881efca2c596b6315a2407eb938d82d2c4558e93156dbfc8bd432b8703f37a47b6036151627a42d5d75b072551696aa85a1d202c245da9640f9a19616c429e338177b23a4e00868db1ba8627aab4d52b80ff37f4c6fbe0593bf66f4e2d8af4fa1bcbd87365a546e6cd7cd3b44cd61b173f09eb419eccbea79fa5914caad46288325085b267597374be920af940dcd06105f2681ee5f90b53e6416e3551cf39d803a8fe4eded6a325941bd1db425b114386aab4ef782a491b94735e15302ffc5f98e148b9e6e3583828ccbafa0b4ffc380852fc879554674e6caf8c75f79e260a41961408e1951ee083cbc1487ec298f69db8a15bbaddee517ebccfc42fe8375d4af9ee07e3a1e8639113d20dd2de8e8fecedee5a5dcb54e345c797b5f86d1aff1875cd076b1e8f0e45f19581aa86d9a40e4180fa97e2ace6eac9a0449949b54fd198e1411b62487210cb80c58ac50852fac410a53f61103206559b968c9afaf60350d55add5e3f61aa5ed2b048eb1bca44eb2ed44b8bed1e8d5c8ae6b67f52505261ccc1ffc2c68dc06397fb15670eda9556095f4d5e2dad7e93be3f4c6cabd75856cdc7b45ed5eea832dbe47bed9e384a5a94bfaf14ddd834fdd8018f872005a7f2e20c2d64b747bd7d8d5be6b891d0ccb30ed73d867929447a3e3f81c727eb5098a38c081e8cb6dc36864e7af47a762615ab8428195d348ca7dfb505be0c402e0e1300bdf41d48e78c6e12f096e794915fe5dc0109a27dcafd29b11a46b42fac0b02de72675d2783f535cd16d28d8027ba9bc85b6f6ac2152e13545ef1d03210204601ca70596139c35fd2c80f7709f48d85ac42e4c70da65ed030d3012d3089db2a9a6b407b3b4c58a45db66c0c50f4a5b4e1cde16abe0b8e0858109513d54edbee7b9d9c30d27021bd7361099909e66a5ee21732f4d61d7ab4dead5353453ac3f0db10f9d0d4007c14ef31bb042361a8f05ccf3836aff34d00ac532b95981a6ffc88109fabe19664511dce40237e475a0f9bc41f59e7e227c17fc1321af1c1c361531160142527f22ac4005862820d3da037ddd8cc5506b1b0d8f3752ea5c700432407b01aad334a9dab534048136b0af16304d0b2613042fed603c42c9c1a6d03cda570135905932fb6eaf334bb66c0b7d22a260f1471c763ce718bb25a212fa6f19822dd6419fe09bb2bfd12538531bd2d5f9e3100784496b37675c750ed9ec4a7d671f978b624859b97706cbf90ecedae6334c08742eb8471c03478d2151394cad0e1e4e28e18622f5e17b3cb01cad31a42ca5cc09a1dc2dd4d519b0a924db51a06605c9c5165d8bcf1baad636198cf629d757add24caa53c897a70bb3ced23a19926ca4df8addc1bc983f319b56971714cf5555b4a93a32cc8c72df886d14f2286663594f5fac8831081612176e56237f1fe7aa41ee7f9dc25104ae9059caafdc625c7f96b332b2265c0535b538525fada061816349c0fbcd2d47db1fe6b6679235f7dd948ca3a4be46da24fd27f6d3e8e741aa791068d19de9e6468d44701dd8ce91dc25da7520ca655c4300599abe96c52e7c08eeeb7e215fcecdf405637f93258a74c2c221d29d1ebed13a493924967c64723f88272b7c844d37a59af6b3cf7e1d729a51a640a9fc3a61308e51ffcbaa59f153daf2a598afcd8f67ae37a3c6999ebeab230fe99a2a0e5edb183230f6015c1c344b72e295539e5e6392d1a28aabb684ce5efc6b29b47fbb4b54c09619e5cf3c248c7ea6da52bc357e30785445f8c840bfc529cddf9ac8ceb5c1519aab5bff40bded48c8d6ec61ae42e4ebcd85cb863f3a14f838cf815c4d02324a726693512cb8ad68697a7f0d08d6134d3525882290003442fbf17e2d2b1d83f7803fac7aa6af35002ba3cc524d23ceda762f4401591184dd30f1865fcc4607fa0d555ed03c6a1e8a7c5c75af28315b2810d7e55dc8812b5df9e0bc7572d4fed371631ede503fd44a50b06ff655095bdefa96eb0d455761039d8d789bb38e46db7e26720b7d61bf64a1d164847781ce3501ca5ceff69489f11492e68407eb0d2ce333bc074e64e235983119e32037ecd9f1b59b6b67556822b98358d39ec724db1c3eab9226ea38a8357b70e3ba2d5b3cae4d42d1422c299989b66369644e346adf6d510af172fea164444e34ac8c57ca47ffe7212ca98562f6b84cec1bbb8e61825a8975ca2a15e93576f2924e151160786954acb27d1168924a7eec93c7f2c2fbc3f96392087444603e6c8aec9f78281e3338058d9d04db2cf26b7ef6d54b8af0ebac77adca7e02bea1b179020060894c218927704724437f1145f800d80e149a03cae94e975930ce3a6ac68acf33641a797a4bd2307c8325f089262e0604aef1090e60e713dbb06140c791e2bf78e4f629d733367c52c72a0882c86e4cc501a2ee8b76ab5f6b8e2edd178b5c2ed4a3fdd6f65beb46424b5676776f29a594329e08280a740973ae91c7ae9b698cc8f4b35629d6bffe559f596e54356b98a147e0949a4c5fab94df1acc5bffaacff52c5451a5d2748032c62c91031b574441638f41634c1c4fbc8c21060e1dd6a801e5431729c08cf1050a1120192e763822a9082a5ac6ac818394524a39ed992cdf43a7a4a17f9571c30ad9c51026e4c0040834d878e114061a65c091a608316d9cd6a4c132679436640d5cf27357b9c197266b6cc1e24b0d485cf0c413356820997104860f35830c9211409ce1e20a377c040085923069aef090c51aa824f96b6099731fe0f26012ed79b9ada40752e95f99d6aa0ecd2814544aa1cce9f2992f52795cb29eea12d057faaa5db2de6ae923b26e593b3f3b40b4ac3a4c28c073cbca7325c63651dbe8f576ec1a762a6a5507c3bc4d8825e79e1e776bb5f10379ed526ff75ebeaf9af7fbee754f2ff5c8e230fa2a76c7c4f1c81eed85587bdbd8b953d17b27d66fe258021750ae7a146281730bb1b64c888577d0e4b9b34b997d7a22781b5051569d6ddbb677a25675b64cda2f76f61eea81fc02c3300e1339aede3b11faaede5342df7d84b9b5dbec5ad62529c398bbb6baea86d5fa49fb772dbc27829af616f85dd3ee799e87d20e2002afdd7b4a1cf3e56d8ed244cde63d54fbeebd86a391ad8159cb5ad6723e883af80f95c18f46f6f7efda987f359b7fe2f83dd49b4cfeb4cd351d6473940e6a5d1bba9f1ebadb467badcb9f585aeb66757b4d8f98c502c1d56a05ae6ea77d57fb5657fbb2c7711ce7799ae7d97bdf344fdbae2581ba3bd5ae7910ccb2cf6759e665d9b950a3c4f11bf52c8e4676f63c3deed89e0e1d3972e0e0b85c3737ad168bb55ad9d8a854a9140a753a8561ce20f87d9ed7751873dcb6d95cca20a954b6bddf5cca20a98f7783377ac4b677d65ba2943e582a70a5479bf22ee58fd43d3d9e447cd4b3787f12c7a11b8a23ccfddd6699f6bcfc0a3eebf11ba41b14477cecddc76f0eeba1bb399d5d3ecb1b69cd1413d386ec567a827c9f516aa9a516d3466b456aa9a5464c4c484d496694e86bc7524ac5ec1803ee15a1eeeb0109d6ac59a3b4ade8819d6da5521753206d026cb93485119612c3e43fbfaf951a77f5a871f5627a34b287eed8b347f9a14bff9168d3571d68530d29260ac6cc40ee268b7f14650f26dede55d7eade5b374771cf98134f07c5596fa61e45f81ee1669f86e473dc4171fc0641104c690710ed13f7097257896378fbd5539cc8adde433307fe9e9ecf899827040cc38f7973a176398068879fa9cf671010ed940ec18e1dead1c8cecfe7de5339710c9fad9e4f7ae8ded5391db47a4a07dd84e2d0dddce7ddae8337b747b5ea8d8b75cc6bb5e6b1c962b1260bcbc06c3e1f6461cf66a8476c825d778c76e7c46e7618c3303ef71f45d9e5c1ce9f3aa8fbf6efd303eabe696e77415d9e9e90dae12c562cf1eda477d223d13e3d258edfa987e268648720a8c71d1bfcbc6aea71870e1d3972e0e0b85c3737ad168bb55ad9d8a854a9140a753a8561ce20f87d9ed7751873dcb6ad567ad43678d56d44cde663b6c1bb2e6510d5c7bb5767b9f4886df0addf8852fa68d9882c6d63a355e0a5fca13a08ea11a5d2a3f7947d28664789e3d03d8923cc9d6f3d20baf3a7e741fdf64d8fddf3b3084ecf01443987afde8fdca11ebf27dd531cbd6ba7f947eedd94bf3f500775a3a787eeeef4769bf7f8d1c8b697690fd95da3b899362da8b5d65a9f437f60afaf4aa948353a767bdbb88f76d31a868d4037f580eaa079faaa54edddb6e3d5b951dbadb7bab38ebac9e7701655ff4490e39eaab5d65a6bad5575303cc83de77f5fa881f0f79e9a457c95387a97ef1e661173e2988ff3bf5bd5b967712461e763e1393dba8678c7dc413dba420d84c17bc7b8abf42693390d0ee98e7550f75007a5ce81e298f510dd9dfe5297bf4171a71e504a5bfa6ae95f140afc054fb739dde66403da70a24dfe876bddf9dfc9e6d7e61cf88cf5786db883dcca46af7e577a9c9b03410e3cc8fd1ebcc6811c075e779fdfe73f3d721b07e16fe036e283def7fc79efc06d3b4efdfb9eb3ea3636dfc3ab424fd21fe1f34351d257eeb238624f9d4ea81308be0337f09b1ef14150f47a28087affc4f0591cedceaf1ed0f750cb9ac5eca077f0eb3c1d843f3f6e9772e79d61d7d6267064fa1f30d040839cccc2b9061800d1acd5ba29b2983025f02891e79e42e69e4b6a30ed1e5b2e8599b2c39809f302b69df43c9873df6c32f250dd230888466db3cefaeaa7b782c06f07a9eced28284b4b4cf6a8654993c5cca6298c75d2034afdd3df316fc876103cf74e4bfa02bf7bdc53e2d85dde01f8b90345eed283c0dcf8e039bdc964f0de2be609497d3b28629e10efae3ca43bb7fdd3a32b6ba0ee3ba73709fb7bf7cbfd7a3f736f4fe94d266ffac3e774107ed641a86f9f38827a886eac3dd4e55be268f7e9d5f36002a1b4a52f961e57dad2d7e913f269d5a52724bceaa1389a60ab8ea7873d5175ac759ba8faf4848ce03d239bab754f4fc8f81dbca7eb0ef55882adbabde609a15bf54dc87750ebd17ea86ed568e96bfb67a347a2add236d503a2dbe69b68f3efdff67d93c943f57b260e7d43766fe75122bb3c98fbfbdcdf3d1dc45d03e2ae6917d0bcf7794f8fdcd6b8fd5d7a43e6350e7f6207beeb88bc83a2a4d4db4004babf63c9012c6712592e2d2dd9dab90e3a3dd2dd1de51d1447241b4c5da5d2a3dddef35323086af8d33df059f4448c1245c8c2538f83b9c377414374877a84b93f20babf7fd7f4c8fdfbc46e7a43e8a7c7b9bf77f746bbc1570fc87bd63d153c463f91d217bea72d7d61ba3b1dc47d725abb7c4fcd1b13e5d00452edc99a9e964cabb55604b891b3d7e39b4d46c6ec087407d56fbfb11b0b0dd6667dd346a072a7f680a5e71ddb69e9d741a6a5b701a7594ae4abe5a6475b6fc59168639f19772c3d0ee6e6b87770cf9d6893b06ba611ed6a9f59961259729366d1640a2b69957bee794b37a05572fdd5f51edca06b96d5476be4953824c9d662f77e16156d2a7448a10a29ac58010a57a290a10a16695c71e20a208c50e10c4d4a06802c61aeb860cb252d362c65b13203344029f2a2054d18294924e0c61193161c5d81858b294e6abcf14213439c51c10f5a4833a024b16245881cdeb0e268a806278430b302124e18016685344360d182136414855123c316484b51c0a8d20519444ea83069a2a10d2b340cd1a47ba30d292d1081c310653610d325852c94e0724398a532638cca90e28215701cd57064420f48308c11c31665ae203501854a0f428c6142146c0cdbc29a37ce6839010c5d6a98400f5f9069e184259e50816512c3d146260916294e00c517250748a38d24379c24c9a10429704812430949525881441247a3174a8aa080f2c2165a94b42a69c008428c2064c8820525ac6086268688b2c6cc1133c4e0c40c4fa0c1841b47f01005104dcaf810c61b5a8e66a0c20b15518c9244a942c31218279a50e00823cadc00e585294451a22851810a343a4c41e10b1638e43086cc9a1b56f0054a0e4c1ba881c4850b4634090207ce8bcd12295eb62053c60e2ad0c410ad208935c2a4a0c21938be5c51834c0e493b1c6186970cf410470a3f146146891928507801072c5da4004c9625341f8e06a0051a2a6b804063698b11f440460d4e8e5288e28486b9410254c2e8c1092f98d820730128253405f1031531dee832e50608a459c3c60a297841628168052f6a683912430b242d1c97189c3061060b66e080438d962635062c472dc052c60f59a08172a6cc067c48420412461c39414492c605102645668280630b993272b40851c507348868e249064a589e2c41e2a805516c112283265820c4971478d06187151955349949028949135ab66842e945a0c7d72ab5554a29e54c62ebbaee1dd1e6c40d2a007cec89803da702bc9c6ed4c6177d4ded45297d278e09107b6cdd83bee65fde953ce6f0e821ffe4bc7a50aa5d401fb05b0fd9ad7943b4739c1e4fb138e68d3fbdddb4f12d7d51dd7d7a1dc87901be9c1774d9b1889dd334aca8eac85f9dda4d59dc56d76da6a35b09723299452f6c2bbb7e22eda03a26606b5afec56aadb5ca7b57f2c472a002d340cc1a475268e9a1c915306596784183154e967cee113a0bfdc40088065daaeb6244a7642593b5ce7be909f90eba348926b4d8c46861e3ae502b3d940885163051210a9931c244a15b5888038837aed0c082182c7872e2b0d06965e3aeec518a195f9b6e7126862a927ed042298c0e9ca09482162fbe6c11c267944a5d9e6060baf8d0250a539719ca9875043c3b07c8a0637539b58301102fc2a03b40763028da32c41055a2e092041192cb19388861060635c0d0d0c406274692fc44f7ca49e54e764d588c51030b4f98f142195d56985636ed521d17355cccec249a9cc84d517cdd18442dacd0041352709022862a3470822a698290e28928599ab4c8b0347d917156b87cd181619dc5450b172698b6b855bbdf31f79c41aacdf6976a5ab661d8bdf7de8b8942e24c7519bba3b8ab66e570ef9d94d232a6bdb5a6ecb679dad75b5f5b05565a6b338c8809f004955e6bafad934ec1929e52ede3f6f17ec4ae69af6ddb5e75eec5302c579db96fad785a6cb196568a7bce39e714122dbdd65eeb85a495ce5a29b5d2c7a4e38d0a75dab505acd11f52ea11c31e839dd36a6d36597befbd76d27b6dad5a504a2bbd92a7b5bfb752ec5e5b27a5c1ccea0423a3246baf9df75e2d63429ee0a6b690c4b2add6a814365f2b25cb886b8572b616cf6e76313d626063f729714b2b6da6c3c8e2961fbb2029337985c46db54d81dd007d19a12f5b29a554fe524a8bd017b556530a84526dad0b853c6fed116be9776857eeb5768ad226eda4e8bdb3d65a3b0c7b7dc6302cab7383b79a56cc8af96e18ff00225f6c6343d8aebf40e88f6cdb8cddab5d1c64dbea23d2c7bc04637f20017b08db551b15f991c3eb55add50103905aeb2ce35a3b0226e39dc1d65a6fd3e71979a5fc78efbd265c8f8bb4f75a6badb537b379639732556b927b654a4a25f2c87a8ed51dc8dd630703fae3de256bd5c06217bb17bbd584df31db6b7ac4aad4a94dbb7a2c02a22063538f294ba98058cb3c82c8db47ee23f631fb78b76d7b711cf7aa23e7de304ccb32ccdadbddeeaef161d8077eb8f3363336e6c278cec70440d16ac786b6fdc4be8b61187631ecbbda7e3a34e92886e5cacf39e79c76d62be5e67836edb5a37d04623f26c08ad5b4ad592d39f15a6d3b56ef66a5e6c9a0e14073464a8fb64799d890f1baed7273da7be87d507dde72cbbcb5e7ade9d1ead0e7a55cb51ca4d02d184bc9a36519942f6b595547526a2fa59a35a5add65a4b3f3094ed0ee49ed287b451b0ce4e018688746b8918d05a2206ac269fd96a2ba5e0b696ca11b22d83b880b25d9fed7a45906b36466b25bad4f2c0430aab870f0cd9cd4391ab02d3e77efa5cbda4f3b9cf55471e08dcf5e0e6610457d75a6bcd6a9a50f2552ec02a66fe040b8725e6064fcc0f1d982a6d58c1609282d89b0e9b127cefbdf7526b2bd19d94068cb30ca395565a6fcd320ccb30ec5a5befbdf65ead5dcb627d47add44e7aefad9c4ce86da6738911bd9452249352acdebb894728a6bf036781b51f415279ba8f49e5c9973f924753ca62a4c6445f3bacd36cc6a61febab52a126f275fffac9304c072c669331bb7e26b9923776fdb47403f275446866408b98eabda73bc9be6b76ad15fb346d44fab8c7618b1f489d7b90e9e8137ba4cebd275e299db8832552cfa5cefdf602ba41d28c4694d10d0dd30f7d112df1e48c166390b16445cb91325d80484118356851c50decca1a45391c52cdc23281d919353b6388382e9a33b42d076f3d4cacb370e8c66c19d694e4c21e25521743520a7bcc181b198e8c0d1368666dc9a97cc69299b32587b1448f42393bdbdce3c54ae5cccae0964b5bc46cf1b2c797521b67b2cac9b893e2911349d5993dd2e49d790d3e1b724f037e1ef0810c8284844929053267117d4d17fddc54232181bee60d30e583223d3f395316fd2021a167be0193524ae9ce3c06f407067b1e15461e73d63a4d278916452bc812050c46704d24c103162fcab8d0e433df53798896285591823248a88082227ce67f8ca6b0cee4f13ae4548fdd1191d0173d5275d4e891268f3b94e708d5a13d6cc8638f4d5f65107a4488cafa8b10027d5197fc7449a1293df43ff43bf4405845995eee89c6964b43a4d97387209b8e08edd0262aa59460aa6c0c363d2a8c4c2f17cd56393509e64a7fb3bd5424b226a094a260c3a28a0f7fb1e52b5828e16c8b15d659385b2e6db961cb0a3693a6039e52da2ba594f2269846db520a3a91e7a97ee95791472ba9dcac8efea0daa553069892bf056065861eb8dcf046124bea94344a9c1146d31266f8cc7ffe352fab0b584a09d65a99a4d0b9c4cc0e02a4c8f392fe0c2c93dfa94eb4d7abce779cecfcf0d053758a7ca034e94443a99541ea07f405db9bfa021944de0ba40fea7301939cdfb177a6585d6a0b0b299ae1b0e5842d4ae8921635b44b75db964b5ad2d863ce455366db02e72769604fc430809643295d6db9a4258b9db75cd2e2c50a3943e9c3daac1de1c59c2737d47421c5b081850b54a280728518128a8c60d2a2e98c14ac10871b5be69c73fe354f65d468991395a4cc1c93a6ca5ce3461573ce34d29431e70c430d5691913bfa9a735279a202bc306754c7d025cbaf2f59b01151907630064034e852dd1726c8c81eec02cab29d01aeb5d65a6bad1c0897dfc00bbc265fd909ac9924b7b1e5992daf75431d3822836856beb20c09bee601d9bd9180f1ac90678ed4c99e7bec2cc32e5fd9af0794fd136dcd2ad68935ef2c849daa693bb8d65af17fa50a8f698b48314f34b1314d8b1731603f8b38ca355de1be6c60cce03155745d60304e644813851118428c592d91060c4ec2e8410dd2166a844a72705a94512b065305ab544761a50c154b5841c5081756aa20b38310268cc941cb32c607945dc166bf48d364c6889733bc84714202e369ed15ebd57246597117cbec8629e1858b3d666c94b72d97bc88d9bc8451a271196756d65b2e7919c24b933dbe9c6c444ed68c81610a1156d678c228090d432cd9f0461651b0133a2e8b0c862c8b951ab29f0720655e58902981c43aebb5e5121468405146ca1071e4608112518e825023b5040faa3042bc81ea1284092726464451f510c40fad26d05a4b05866d55db5a2b6fadb5d65a4ba594326751fa41cc910b2fece043c4fe070b2d2d6c5aa060210b52d11b453ed65a0c8cf298e9b5495292d9f20da03fc02dfff300c993a5bc804b96b7526b76005038b122a2931ae1574a299da7cfb5869c3db7ddd76863c795898aa15724c975c9cc606a8b342f50810c42b57d42fac02cd3c6fe4516f4854d61c55825fac2b4ac72217d60cfc4dac5bc003bb65dd1c66e4b50435f98556363f64efb996663338321ed760b40218fd6881ebb35b2495031d6c81a59236b44c5689666d1a34ac9de1d7bb542feb062c81776acd3f62cacc71e3df658a56c4cfb32e661afda36491fd80b30060a15b3b15328540aa542916852e5913eb30334d93e13b13dbdca247d601f801af9dea649b384fed85230a22f5026153b3ddab65ffe188936f636c872386f834dfb764b792c525151d1131fee973fb4675996651b70dda66f26d67dafd592a6529218a626339d48c2f7129ca0fba75d15903e2474ffb4f741a7b5aa03844b562633354d65aa4d4c26132229549064d3911090541e2b8100e9f9f9a0889105a080b4b16b99f517962ada48499587c8077b2712f958a5ca637db05b3195472231d92619645e231b14e4b66ddbb66d18639cc3898a86a5a03285954476045602cb61b8252611f417898f096b035765d3ef68f4af3d7c4d505c45b16af9b5a50915e877e8bf0105a25f3863dd697b26cf2db7a64756766dd5e3cb8aedf0b4b1465b69db4fe185beec311629f5288451795fb1a46d8f445f560a912ecd0b98986a533553d3142d9141662daa45754935aa4cea5185428fe8118522850a52920c32003499be8ad8961e55aa3763260d2da24ba81165a28494a42486a9691a4d2326f36842914cdbc8911090541e8954349750a51d203d3f1f1459000ad97eac52acb5d65a1f4be4635f912a8ff5b1af4995472255a52a460699d608097f4084b966db63216448b673af80f64c9720bbe69225d0be6997943e52d472d5b90560dab90772fffbd77d26caaa4def83ecb3005b7c5079a8cfc5303d8033f9526a51c08ee7d4d3685e801dfb4906a17aba30050d53d08034461e659a0f365abb02609143a8489066120f774c4f23d6983f4df372ee582cfc4d4fa4aa83bd005a6499c1089aa6076026df3fc94a7b16d11fe3c4553bd6b4d35df7f438c8aecd14e80bfb5c72fa21d34b1fadeacc6934a14c238c0ba9643a2bc59cc897963fb4db2d87beea35ed47fac8aca669ade6caaab2566ab5add7a67d827f6410fa9c1f1964cbdd77b6c4a23639d86acd913e00804949a5adf5950c6cefcd979c894c76764a3dcff348d8f81ea65d873b916863b1ba4094cdb966c889a22ed4ac91a1053b5825512c01070d60b098e20a0c0bd110362831650d18274a459061faac9002052bc400260a1042a081c10517d860610d2c658cf8382b34e8619a62a0a832a16822b37200b65c82420628967c415fdaddc192ef954ab0567950c7581bdbc180fef08edde6d85f79402cc79f9de5cc62617c4ceca99708782957a5b25172d26e733f3d6a4a4e5a12196dede189f6cfd6f498891b6c7ac71331a02ffab2f7db6ed946945507e3ab442192be26c6c7383f7525e04ff9a913c94f6922e04f5a7af8f4d489d85c755262a3d2b9ea58ac5d444e0f531aa565d5d9b0877f6d2cbfea583d0a0901318146d4d1ac851f68e6aeb7377b565bd7543fa57e739bd55dff8e3d31fc27caba9a73ce39e79c33bcd4c7bc21ddbd0e3cedd33eedd33eedfbb42b83dabba6ede81dfa924472681cfdaae35d13e71a162b6bd74a721cc713b587e2089e7aa9672f75cffb77dbfd7c979a36e6ad799ae7791f775ce03b3dba3ae82ef5e802350773cdf6f4fed99e775707a0bca7bbcb4df45f498ee37c7ae09f4f248706e79a2bc95164cbe3e822bbf3721c47490efdb325a8c79fdd81c752efc4d1f374ea9a0e4a3deba0d53521209e1602b253dfeaf42e1b6da5fabda6c71b2de9cbe696be6cf43854b71422f538b7eaa74b4f88eaa78f26d827f993269ebc7fdde99abcf74f75fa3d5d93f73a3dded377f9b54ebaf5dbba26b6beeffbbeef071aef737b97557a97b5ab2390fd5d8ae3cf9697abdba42e2bcfe9b2f264d7b5caf3dfb06c522e3dee6c79a35b7aa5c76ca3557a6469941eafc7d7fe1eeaf195f5b833ee7cbf28abce872fc5510848e779d57ba647ce133b21dff1a779e05c9f488ef3d8218afa57a26387d681c343cc712de254cfd3e3c411f573883c7e51bc0e7187f53cd8401fe74a783cc7ade78a803ece89f0788eebf84f0400cfd1a1af65d55192a38bb6f769972b02bf78223abee3bfa8659557a2e33b340f2d7a407577f73c0f76e80b1f73408473f14a727c07cec513c1b9a8f189e4f80efdaa83bfe3e289f0b8dea1651535be121e3a571d7cadb1f89fc88eeb10b5acc757b243ebd040aa0ece818f23ca8a5f8580d0f7d49f4d5f8580ec11a6962eda728265e501c78cf5387778aff388f614b153713b7d28565dbbaeebf0b3e3530f886ece041fe063c713eb6eb3acdd43f1d5753afc15f36936697d28da67b1041b6862b7181fe35f5113626d74344138b13989b24fd4aa4ea6b3797aec19360ab1d0e4b931cc520c338125d2688603be3e920d79069ec7f71ecb9d251827eca53b6de4196ec986ccc2822ac6e862830b4aaed8c0135e7421238c2154908598093c39b3022e96929c11e589329ae802081ad4d0018ca32359460f4d25a40003952c4848e00d16604041195eb8a0b156bee0e0040b4b907200838a214a88418625a614f1644a0bb01c0961a50c1b5f8c943843456ec1a2868c384ec0658d9a2aec1629b46861c5145058b1660a294db08023891933a02843c51425a8028412264a0882cb1701a823c2305ce212656389b730bcea74f2c2a39ef2bc5085ba867a28ca9d42e10c1b92611587e26877f8ce03cafff4e9f7f60454c1673d412dbd21197d7d5a236135330bd822d919ea18f7542a8ed9e9e73c0888363da63614a39ec963f1c39835be36c677db36ef5c786939ee2008de8ddb384e3b287affc431d4423db6b7c18deb193e2a75ca2d3d6a298dd236aa6dfbf52ce0a238dbb12beb50ddb30c9e0efefb5c5f2aa55d3f72a7de81dca913ed9398654fa1ce9d32f027916867e033783023b2b773e2d8ed4d8f423da4dd55deae68a7644ac6c9f1d4ff1dd771497f881fedd6813128d2af4455d71d14555fbd87a2502814ca6501fc951e5d546e227b75941e896cd4b1065715fc3ed0c8c63fb3a3f4221426b5d6ba1255c7787a40a8af5a5f8116e8a12a71eca152a954dad5d244785cab8ef546bd0df2c32ddc36cc23fbc2f09ec7c3ebc22edcee8979753c3b1e1b15a54f4fcdbc07b87e7350a4cfbc1f7ad56df70c8b63eb9dde64724bafa80e72fd460789287114eab112c79616eab15d5ad2d7afd2a3508f2d5e0289dad2d7f577e8d041698e1c4f3d47ebb895e3e62d16fdcd5b396e58add3160e0e0e0e7dabd56a712d6e4aceeef26087a794869803eb11a95d6aae567a05825d0a5c9202ca6e618e258e3d36eb37e24864dfb45aa73f513dbe72725a3838bb8542e9d34fabd6e94aab8e52b57e6a5d521e7dd525e569e931ffe6a76bb1a7b244f91b117b16bbdb84dfc25feb0185dfc3e959409fc7310f8c87ebdeb1beab955e81e06a14eab1c37b77f5d4f07b0f0dbbccf380883e8ff750cc83f2f8491cbbed1d6bf155677a435a5aa32fd4a94a7c61ab1e8ab8763abc39d16e89e377eb3654bc69fd445554a5ba4acc0fc594468940b6773c3bfa3dcc5ad257d683488f1d549ff02cc5619c737610f0cd345607c2be39206c39112d8ff59b77a9efc79fa83a2886299b87aa87df10d44fff0e822008822a0d84d227f03df51bbfcbb37efac42d6f600ebfeffb50cf27105c280df481b0f3e5066187dfb18da5627dd341ac9f7450ea5b98b359ae2ee5e19bae5be1aff00aaf56ab70f52dc4abd5b75578306cad74abd5021f8661188644a0f448b451a77fe20842a8411004433004c383c701c130c409f598fa77d571403d763fbda79e44f94fc49e1247a19c9ddf1d750ac3d34371ccd9e1290c73e84b26b5e817c7abd65a8becfbaab5c84bca4b8acd53aa7b5fb1c0d33b16ea955f5d98f39637d5435557646f5fce397fe12bcc458a64d54ba57aa8835859147abdb6eab559ab8d65736fb5ea3a1b1b9bce267707ffd9e40e638c3b295df7f9ae03354dd3b2fec4f15564775deb2c1bd6eeba9f342d6716eb147e77791904c1fcda75af5791d71e61ba5171a687dcfaccd6aa734488754488e52488cd736d2dad4b81a88379c8e9e173d7a134d029c4db7644d3f276646f478e1c4109b13621d6de8458db25c4da36cff33ccff33ccfebba94a753a95410ac231bbcac3c398e3ae931e7c8bbd3423d6a422c168b455fac9d23ac3dc2bc6744cedb6a96e26cdbee901076f66f3a847d3f644318b299f6b01305f52de5faea36adeef9db7116f13711ecbab76aadb582b8b39b7872610db4792ed77b68b7e177216c073fed3abdeb4208c175dce921eb7275767776bb6cd7a552a9542a95fa964a7d4b811b2aa5512854144dd3344dd3342d049e1c3c38a75027d4a0a43a9aa6816298c18799beecc65acbf22198d943b5453b366a09da4db88f45b2eda80da9c7a8b608b0cf4420a4f4614318aa657cd852e7b0f7d56d5a1dea5d0b757048f8eff9d3dd779438869ff7d3e77d1d0a4977d075da484e1a2894d20792f0f350de3f1de4fda4835ab56bad3056e1eeb853617c7c3b4ec4ddf78b3b15c61fe65258a7525dd7751d8f0fa0778af1fcf6897116bf4f8f44fb7bd79d8e42853f89767720f86ea87e394f6fc8f7bd13470d28ec1e8a22cc351becb2f401eaa1bab1de644e21b936cd1ea2b523b393b3eda8610d847d2f76b18b3d47e3badb69cad2d9274a0a82500e1115a19c9d9a46b5170ac6d8fb865abd75dc850771289e9ebb6f841dfb043eccd979cb39e72dfcf7afa786e2261f8adb087e039f6f314f48fea7693987e197ba500e08fbfb08c2060f7e7b4fddb00d3c69a11cbb09e508e5ec55d6a350ceeef0d6a1ee373db630cebf395f9b5f1bd6ddf2c1f0f3bc5fcffbb68ddbbe6d83927510a65afe7c0ec2d7404dd3349c03c20e553a5f9571706cbecaf4f58da99d59396795f85d521ed7a7ba4b945427ebb1930f45ec287114ca398956d3beef7bce393bbfa78222dd591cbb679ff731677b5fa7857236d6da2527e63de680b0e56dce1ea1b2e8a7064b8a6dadb5ca3a270aa8941f299364924cd292b4242d494b82425f55288421fa4ad292b4244dd358fb47a23c497a3179b22469c98bd2177dbda418e19e9e06fc3ce008d6a494af63edc5e51dcdfa8015670ad368be405f1aab6a1bc8922a797a9958e8abfe24431e279609a5ead41e69f24fa7a5723d552a2391c8a0c00ad98a148a54c872690b35f33956ec58a1d4a9d41aa17a070806776a0c300052e915e5ae4f80156f670a26112c39e20c105bc07186924fcdd28592121c70bcd084059f7a23475a70bd88186ed0018b3698b0410c9f8f853558dae0a14c1c4f7cea334b534af57b2a4f284a9fa42c7dd4ba268a302d80c20b2f6a7c3868e28912121a323b3ce153df5379aec516483bb001868c1ad694004493262ab40087167cea2f60227f53db050ba60017144a3043852c767803c9d1529927258c4901cd1a50dc283c09c515139ec0ce300090bd030609d4964b609ef0c02491724055c9d618a135a0e7e701acb3c0306131798166531ada6052d3821b4e468072040f3b58f9c18738b2c49126cb1a2539382e4436365746113b4764100db39f395207ab59b6e5e50b3b6284fec0ee7b3ed8a202b282b12d0bb2e4c912902f2160153ef8481d7b2c76b14bdb06b1ab01b620db5aecea02481fd600db4260d78c0dd9f5d69a1d57cf033007846db3d4c1ce894634ed3e6755cdae3c9a587b69f6c49176b1cc666832e746cea2c8f7087f916696d064a68aa3ccca5fc2d8e34b498a00bac0c2461059a42891c17921862e3a1c51a1430f2fdc197838a62dcdcbca972abe8cc9b65cfa12c509195851caa2091ac29cf0041c417811461138a4f1c28c2af7891ddc981e59ae28ca218a174a3e4835ac58a30217b2483ae3040d2e70163452dc1699a68694316648434b5218274dbcf0418829493829218d222e4b1a2ae02a1c29808105a0e3a8840c596873d22106491000002316002020100c87c3e1a0501245c222e70e140010759c44624e980904c22847411cc420639041c618430000919119a2a103d53cd2f32a64f9ddcd9eb4e7ac9e6430a891382849f415451df91b8fe4cf8538c3bd2bdfb4b6778df5ba72fcce6f119e5f16e1899001c9c598f3330fecf7adf39e9632896afc12c6ae5ba8888fe40aa9a7deaa7b64cec9fdf4906cb419365543d84c44b12e35f27b4b4eaf44dca39037071bd9f6d4bf60f8b7c92c0a749fcbc28bf8f6c03e154b1278ab3ac05ba1037aeca2e67bc8894a8e913c1ec93a2e89ed97f4652b61150cd48235ad01424f866932b947fa7ff42e994a5781a96103337d338766f5d8ad85f4742989570086a426b0091b8be5652acb88ee4b38f70dfa080c22bda06e446e3816a7d216f199837b2f504f4f3c883338bcd0eac0512389d3a745befe564c845e2153eed5b4cceee00e0fdae29a5dc89c5bf342bb5b5c6d20ce2bdfc961e44685afb5236588fd6c75b9cdfbf9470cb00f07c3cb031c7c415de8e2751589266a4736b61c12dc47006ce9b06e8a1044fcf5e0f0cc4044231df29081890ce20f7fb83f350b4a1ac4fb8f07b78ebb47414fa34af5a7cc622046901dd3edb1736ea24baca6a43a4d11916b7788e9e3dd8e8ffc6ae91207f6892e8b858693f8123b6f197a9452ede015db810a69c6f5ddb588c3011d3a378b38dc45274afdc7d37ce6d7dc4691f04abc657031fe1ad95b226c98b4facb36995c96493f67549b1d51fa8188d1ab584dc453647e313c6ca93ee4a55bf657acc40acff8f08d8f94529f31ae88bca547a4b7897082d542e83cec4878122aab06b92fcc44e22ab4aee62eaec7ccd2c2515a2d24dd620b8c4fd533ff91c33f2f9997fd9a85591861005fed15e18c089a51cae810ae19d4de54319def3c6fefc6bcf321a04a17197fcbca8480980991d150816d05143a210a392508e39616068a6ef2c55c29bfaf50c880183ccb23813b8b37471511dc4eeb731c4fad0822768cab50131d5930e90587ec8b5d10d11e7e4ab853851063a418564f6eb031994deb900bcc5541b4e03fef6c8c9585abe3213c5a970fdd12b313dbef2ed98462ff39aad3de099318f3c1977eebceb93e49c7e967d358c84fb649e38addba7948e4557cb3321678f9a5a3f1faa2ee557f5e5589100982fd4c400990628852ab9940192b0e23196edc12a0805a5dfd6edb03cf32066619a43710199f56e52114b7e17c4008df5a6caf13d8b74264e414f825c64e056cd0d04e44a3125eee9cccc7c04e8c187190922dfb7f4aa20aa2b0d3f8de069d0dff78b429d879ab648b68438c6292674ab43de38046ac916ef1105742bec5961597a7a31d04f8e77da303dba9a3caf272bed54e094becaf1021957b52d7368f2ea066cfae6a7846dd83d009e5f94473d47296e8d31f54e152fc42d60d9817959f75a7ba71ea1cc0d2d730aa2c034745a3a512eefc31255a9bd7928e45ff99a3131c182df8ceb2cb061398ed3d6be1338ec28d23ec504de8432453f9b8e4201302ed4fbacece54017c5675ea6d01feb4ac457ed31cac39e997a74078ad3d2988c3d105434e3f3f3ffbf29dfdbfc45f73a63eaa122ffc50858addc59964c564776144773308fe740721bd9ff2e8279cd7fc5d887853d78644d7bac8fcde2a0b5e30d69ad7d20af6d18629dbc0dbb3fe474496217c234edeba3a02e84f5bae7510ac1b6ff26c958dc3629dec2697d5ed85a041573aa31a68ea2d2cb4c7f143bb69a0acfbc3841e50a1e46b0131d47799ec71ba999f26bd21620472db62e8ec1530f9b9a9e44a055717eb412288beef5f50613613edb38392615d2e2821b88d1b8aacac5a176e8b43b70acbcccf4e6df6d9e3d703979b29422153a1059a14355055ac0d26ac652e84015e01c65c4834e3bcc790b438882484ea82aa55678fee87ba388c9caed566a2c296f5fbe692cc4df103d8269c09acda9c82926a253d72931fdbfb0b42f416a39eba5a1a83a8c851c8dda4959cd64d8a19b554b4148e1143ee1188274b2dfc5143390aa2088505382df54743c7c305c9c7f5c4fdf12cee2b834f6f45b1b07904d4593f9c86206427702a56f7deee69ef0d5f3f3cd6c0a64b8e80f618a2928234a3169ddc5f4c891d1f8142f942fcf608481dc0e46ac43e42f81128037baf5476f1f456ac2545e57f040a447c611c9a927da1c36323bc62b328b053e9e40810417c0621e56faed65bd7c9de42b825e151cb30b243414740f259dc6038d3ad1fb4d95c9302c4b7935edcbe2370d8e27dae84a54079f2b37a6b98281aeebebef5ce5a5c04c237d9a07a0cabd5578aa7205b415a01d6c3e90a40d2447358a16fffc14a4156aea8dabf7295305095ab025a1329ff43eecc0c7641df5957b5c05f318db0a545e6474d024ea0c058665e706603299a140aa6220ea52410010f10e7dd913ee81a78d915bfcf07d3278122f5e0c9ae3659f41f7df3967e005279c3bc8b06f2dc73458ed045dfb57e0a7c295a013df4bfa782a0d1f40fa3461d91643070ef7f6f06e584dffc5cf58b15f8441dc54ce7e7b7b8844a6465c51ffd37460a2e8a578c952ee4163484e3d060d3167ac657e98117d3132268aaddc0c8982b3f214d265e1870fcaa11b0af0113903bedd7f8848171275c7d32aeef5cfe631b3f0ceeeca8f19e83e1839109a96a5fedb307d5be1497d7a62b92e14b1ffbd8875015b3102fb83abbae86de9f647b08812e8a1e2b1e2cebc91b1318d574a39b101ea17d3deac48dd5fd0b5c022b9f13ece802795d74769a6da88fe7f174473f99e8bb0ec269470a88a69007559f529994cade9505c2631e351a99341dd9f1d1575871e43da545ecc767da0f272f359ca59222c5ba4945ce2bf1c57897cf67d649c14df0181feba6ed45cee117811812ffcac37231723abe6fc4d71e082886afdee3f06bad35efe73fb5cbf6be631f210416b45ae7163a03e4574c1dc368035c1380cb84f3a0adec401c6b5411e73af4c5465f05464fae05bf3ddf4fb1cdfe1d918ca053788648d30628dd071a6996080fce364c1fc53074c7d77b15ee0aaf50340a85c048a3b57c5ba07471c389db58ddde4858baa69ce229f31de121608e5e2b19af9f0059001c4b290d6c0be9cde7966882598cc5615d4b1974ca9d77f3dba3ccec9481d962c9522678a527e430ba7b850f6a399d3711a561e16f756e24f502af47d537a7aab56b2929e2588fcdc68cff9e740400593c9cabbbcee707ccd5b673821d410758e24b2c8fead9f213f3f66647547d230d4b0d46b00f1826b57c14dae220a0b0383cb09702e6f0421b44b800ce4cb99d52bf08abaf1d2b90feea8be01cb8d57d6143627b0122db4e4453810dfb0768605a35927d01cbd269cec09450cd54382374519f60131862aae38161b480afa4098941fe06352059eb2fad7d7f92472f5209407f29967762f8a7398b662f2a07308362448ac6ecccf7fed231670038ec9e1caa29f78fa60a37fda56d05fca97b02c782572b651b9d945cb9fed2bbcdbd6a6b27db5f8a0e4e5e246d10d405d04e76c28af32ba53beea7307e9d799fb35ffaea224b11c9bacec44f6cd676a62ca96e5b62aa947f4f84bcfbd7e29d35821da6e92aab73d4dbff8591c9d5987ec7906dc0be0ee7984a56f9b1cea86a3561ea307d49700bc76bb9feea0cf0ed24d54e2dbed5994ebed0aacbd43573c674bea0654ebbf4ec4cbcd8811620d6cc23025be89f965c48fa794cea5d6b4017ac718c821b5f77ef88c623bc90cd788115529a2aea3915257ad6e9f61bb69a1e272460aab6ba432664889e06a079c69df0fb7682082c329405534e088bd9003a4325d41df2f469dadddf54236ecf2446697901394823861322ae3c22fa838957a468d150303510a0d920fb5a756b904de073992942a6169a787a71d6079e761ed1c0207d42e8af2291ed38192159faab763662337225eff40bead88629f25de7f122917b660562776ab8188235446d40ede6c2591c55fa62cdd9bc5a5f8c42e501388948ef342e999a948824f7eca96c9bfa62761a4844be8f44c21de0676dd451f16c4e1d167926b6212a0d23685d6509442ebb1d45dcf177074ad32010293c91670ac894247da7af957c432072b4eb4db1995627b068d299e974dce8ce2f57100291dd39d4726202915a55c199e80ca443205221d79b4a3887049995a151e9f9dab3a98535e9ac9f602038bcb93d6fba2e433d51fbf8132cf8b158acc91619142f92ce33b3df431486a45359d7592e09198b6060294a5474a6b8e3f428b024887c1205ecbc60a9f0cc0a17aa7cb96bcaeb04d85c23b7e03c19b3b870c83ae7a2f1c15c0033f8346531423ba378592785bd5940ec93d75d4e712b0950e7fcfe7ece14efb90781e07c9244b2269188c527691de70452731204786ece486f4edc5b0346185914f8d1229cb31615a0233ed940c9191ed61052f7e29cb4aa54facf1b5ee264524d612925cde0cdf41bbb4fac69cad4424f100baf5127178c2dee431d01d1417602cf28804e7ad30edb3ba6046a18cf60058d12f2bda9a3dc1dee61734d7528669506f9cc68527652c75425ad17c7824e9ad6d39949e9de2590bd5fac725f42dda7888ad81fa81b5b554ba807b773f6f5a2b46cb311b01797b742d39942dfabdfad5d0540a1d31cc032e768b46276d27e955621704ba87c2a63660c9c6a566a1696fb7cd5cd00b3b3450f038bd45832981001013c2de49309ed6902346d7638f6881f5cdea954a092210ef5e519839b0b52dbc3b019d4dcb8ba08afa65b909dff738c991170544eff093a51a3c7c165207a1c5ba0f22ad922082857d54c282eab8b2240a4d982de1705d7e21d983ea8932021ce540f3bb84392dfd83180f60a9fce347f8380c27c501b64552a42ec8364dc85259954a048d02da6ef7a830cc2d76d870282e5bee2d09754732e0daa1ab44230bb390f68a486a0e079f72c13c099a8614602a04ae8d022d4d9a252fc732767cacf42bd835f73305e74c6e52e4171775c03d83dc37cde9ed537c331d816f81f4bba25dbe44c102640d6db1c554787187c76e55efb98ef3f75525955eba8eae2e1fcb456133e0be5b9cdce0e9721d6052f2c9bc715b7b216501708f3d9359ff2892bdf5b90a2b827363d19808c8a162b0509c0c860e5e37b739ddf2c8483bc1d3b057071bfe7f083db4595d8ef0175727e236173a21af9629874e020122b4a50ea3c656eeba9c7925e04c295decc43f2e1dec46933df1e33d2a71345906f8874c35aefbc58ef2b1c511598b9fcaede30f43284ec5f3a9749dee5ff483ade21b0d28ad91f20a6ed543b2cf394978a4206f48a7413438a16333fbc55d3287831c14e1091bd5558529c093eb49f2cce1c18e273d412095e8f3684bcef29ed8a3c6153c7ce0c2c8eab5708caa4dfed30b7fe0d323d0d8203f38753af28f8672972ac1b3038f7402a46af22c038aa0f9887d10ee60cb33b8bd445c442f1c52a50672a6d1d6737747962881fe3296684744ff1790143ea4452e54514c231194222a476741018342d603d4b6a9f72370e984d951c7e98d53ff515f633402da4fbb41b084241840657775a650154b5a11c0c08cfad58d2c690770402c9f3d90fe1a30c80d48658017def77c43d27a2961313e9a6447402ff8bace77af2ca43596f1218b75a5b86c63bee1b1f29fe4936097dc5a4de16e29253c612858a3e8a7eee2ceb9f5ae0013ba9988f14e5cac068950c6a22bae9963687b707ad0d4e6776acd7c67a9be9c9994e85ccfdb4460f7866b0663919125ce2e59c5da57555b4bff04374f4ca0c2b30f4b08a89ce8ba88b8ba63e85eb113746e2ca46fe0747208dd20a74a07831a1ad94924c13f3d070929beb2b41f3991cb19fd2a728855010055399322b5a403aa3b0c0ac1174a96ae89aed96cb41ffc31b9ef5c8a0915bb17e2dad03951155ec9e557935c8ea043db8c5c9931ab7eb656c9583041994d071025efc9db9cf327b3219ac07f51b4098a13c8dfae340fc52c6a0a7d02adcf848b46004df48b3566c99ca8637f01d9dea726d1d1440e73adf38890ac62e71984e4559ce4b475b0eb509cfc172059ed5d41e0466e3946b0d61d38a582ca36fa150192ba27ebf014cdd2eac6005ab0f294a683206080104a90938b3e427da6d6b4c5dd83248e1289734631e3d2606393c1a450957175b86c4186eee4a2e74bebb4f4d4d8124eb18e8b3bfd8d288ca34239fdcfcde1a45daf8054db866c8546a0ebeb598c076d881dcff194559a8485eed59946046765b8ca2374fa69acf6143e3746544627c4fa9ca60b6a9e1e03428bd1892c4e156df3e2de64031be57926e890147412978550ab54216b12aed0fce3f8284978ee0da8295cfefb133accf91e1061d9887775da6c0e2fc9770a418a93ad2bcb92b19787b76d9bce806c61bb3364087e3c493fae3647ba74e9c29c163ab7a41f4a6f0e69d6e84feeb60c577b01fd462252860fad9855131b6566baac3ce118bbb98add7f7840bb3094187cdb15170187b47ae5f1e2bf6f533923dde62bd852f707b513c60452bcb060c854a0fe7877e7a583a875521a1282e4df448b241a5c511cb6a4cc5137e1789f95a88d4fd46151fa8d0c6a35d29cad1721019e5d490f7389891722de6c4c725e0935f2b007048da88a5778caf0a60f393b77db243af30a53a0409dff9213489b7d340b8daef868d8c7b6540ca3674abdfa706cd82a0c55547280be6de0ba21fd5eea1510e054fec626e2097e4f08e00891d4d1b69c57f5d47c8adbdc97ef24712a2e5c38e958f6453006f3967e724e307062107f6b96ad0766e9d4e2d9c626d0a4138ca26e9b05902b5f66aad737d96e1178763b4c149d29c28e91d43801244f1ea6de48d764c4644ca8ad80ff0ad5a36f5bf3cbd04e3df981a43953bac60fb7302c8754acb34c4d24d24a39718c8835a0b92d23f4eb207eff06f4457c9005d1f6985c1bc4b23f1ad43af0b0921d9a2996770da3e966fe65d8815521e27a70b7b38acdc58676e23f220cb538ff2cd04e8412931609d7bb085a2a08f9dbdaefa87c1e314dc220a8e3affc9e3892384882a0c5b77439f87496b4ef222015f905bd8077612a7d8c83bec933801cbbd35a9816bceaaa522d5fb553735255b3a2f5faf542aeb8a184c38a143bc5de9957de4f92a5ab9c097061bd3ae3cada2692915478866e90831597821fdafca7e314a162abab7db911cc8c659afc547f2813ecf448880b91dc1f56ebc5b2a26a46c5e15037df484118582f9d0df163857e26d30417e6f67eb965eba5528d6154eafe3f355a2a849f89c3d70cefd3140573cc686a65f6a79576642b10b21746f929a60ab6062ca15818f5248557b91d3b24e6c7ad97890c7f031b19307e4ef64135e85b19c308e1566e01d098831f222401590ce088bedb83ad2a72eaa7d463451f616c08a5a45265984c8f44e84bcc330b71bf0b66e7dad0d7c1e6807056bd0d555ff8b148535ed0549dcac0b413c13738a6eaefa3610cd4b7c6f788395a4e079badbf2dd24444c06336927da4218c3cdde85bf51628f12de1e6f3ef8296562521d33e2061c59e187a31fdb450114b9c0f80e420e060c4dbf20601f0cd8a2b34f41c6831dfce5aa690f0eb068554ae4b4408f4d851b1b9213fdf026bd9002da984b9d8753d911e41b7819c0dd1ece2730d7565333c8a4dbce18ab77e590f101e8d3aee9cb871d1c54f8e810b8d947d02dabc59c5eb0616d7163f711047ee5f9f8db53865ad96e82cf5dc4b4fd4a3e2c6ca42393c1feca0c7869aa6a19f1a195fb6247a17829dd70a03f066c869582c0015cc53622e3ed53ef104516ec6b8bbe2c63afdb19fab149a7c5beadd8601adc865b38f96143771ef56d385ee1f062ecdb9cf8d7756c126ec491ee38d33024a80473c439e1bca9be47ad5cdc7294568f77071ac7686129724de9e847024bcce9edda35baec8eb97b97ea3935091f036944fe8988d6979f5eefd849d646572df8139b1bc71c8ddc748201b9fe403c4899ce3f95df8aee872e6e219cd62bb096183fce4abd3aa4292c70c371a3b2f44431a16cbc29940dc7b31660aff478e27d79d43b75b0bca74bddddb87a6b4f87e07ab22a27716bc40172f1d1041bb5474bcdbf7f985c6c7ee93413cae1d52fc893f4263cb93dd1757bf083307d3960202e74e604553aebe3887ab2abeda776537b18e6cf9e1da0ee90c9c119b08ad888571dd0518cc04a5fdbe3f13070013f09949b9cd8b503b3e9d4425465a1c0394bf5014abea625e80d8e7ff51c284f6e91d8a09191eaf8afe265ee3cd26ca4001b749902f882873ebe726c973d8691fe43cd52560ecf1381b62e1f946d689dac2f7d55a5273a4e168da8f107163ab5b49e1eeeccec46ed812acb70d1c37ce224896078a7a1fb3f7a831ea503dcd6915462c11588241bc62047441a0234200b0a5f8a87c1e09c2f21829f13ee6c8183cf164418cecbc2e7aee6715b6995645bf9bf920ebd567ec1f0b57eefb4d0ef95d0a1a2211a5484ed278ebc19b6f511e1859b645e0cf1b3fd0810f6fb8f3ebdcb925ea3fbf7eebdb02ce48f2cb80a8659f550f0cb7b5ce422ae650e274dba1dac3fced9854a957cc51f8cfe152da58048b99091d9f5539bd81b68e82de29aad8bd85260ce7b76586c573adedc77c4dc9c639f9a6a81e520f8c33772857d13cd1fbb0f782708a76b5ae7ea3a02d1c607836640cb8457545ceb4a9fac745057a4ee12556329816b3fc97c9c8176caedfb01be52eebcff14b4ea6aeb36a5c665b064d1c5302e2b76657f32ae0f31008e45ccbc09c4931e060de24c6ce30651e45598660e405dd9760fd9b5c9d1cd8f2b09e8f4f26bc2078ce27a46a4f278ad9a94c5e76290369f07f843130b19ec2b32011d8302b90c6a6588b3b60cf8ff694381a0b472d19e57130641191f0047d3dfd0d00c9a4dddcb9532d76d22d59a18d74d65fd21820f1c883c06d6654f3dac198a9875a5d42fddc2a4072bfc98181a00bba5d9574fa6a37618191d5884c14d5ff1e999e54f6759b8d1b01c0fb23239da356fb587448449fc90ed0284220f4b58900b6ee2a7c1b4caeaff980ccb334871ad0e9110b4de23233aa24a0f071215985105af4a431563fbce53817fa6a4dd39b1749a97de50550529e30cc713a52e84834604c217f00f23b4973ab9206deb16469974435183c3026b8ec9861bb5d0c9ac304a97f4f4d96e84192d30d4c01409d1f81e6013134fc45f077348e32e5fa792e64123b63b4f4932408f415d743b12c4bfd1b1ef61f97fa10c310a7595c9f30afaf1aae2480b4e83cfd57762c0222ec878f935490d6d797d1e3549068f5f78abce74fcab81b8f6378976e2815adebed20a07c4e6e97551f81f891dc8f4a3681beea06d3807ae92677370547314bdf9b1a27960ef07063ed101f5e6ec8b6e1edf49bf79f57860ed1fd1244a097158c9f735fe33511c3708479f89246f7307023a8f221fca5d70ce41fdb934e5ac6240e82940a63429d6c674b4ba48ac57449f9391f80ea6a1e646bb86526dcdf007c7c739e9a9641b610b3d8077e124112ec2abbd76b2df4e4af820bfa70899ce1cd62331afc629727eb4457826173982a2666cb756600265034140fa3240ccbc6b90fe6e92db9f8c3e26644d0269fab16507521a3e9e5491319cbe7df68c1c1c1f65585c4181306a3cbdceb582f7ae6c9643124bff93e225187386a33081456994197358093bf4725d68e8657b4c64d3d1f42b4aaf4dc02ab19a8b79506ba96094ec4e5edf03324f1c43d9a6a69f32c9e94074afcec8964c2c8c3dd89184d15d627075bc29c703f68967536267bb9285275b9d5906798545091b5a1946363685c3e5470fb788ba1c1afc852d1080ed3d0dff93aeb38b4da4e40c990b10643d921fda60e40173a631388c591e9e3eaf7e11d109278b1da36496609c44c75d1fe5b51073b984e17c252cb6aef322a2500e0c588110827772baf26d2a42b0e6ff6a477d3bcbee330ef0e0fe16f8fdaeaf35ec81a8072eb3e12cac3c9805bd651fabed757c74c5feb0bb894998fa00b1562555c957ecbee4dac4bfd8d044f4ac9071c51f8befae34d1ef66eb8e268c206a406e3e73416d98c6df4d885f3b96ec827b96a3198608647f6dac0bc4a50654375b5d9033920109587a565024174110c63dfd70e6b5323ab8560e38cc1d34d588dd74868101067e578cbb61c09687172d314cebb8b8646dedf2c94fcfb51e7cec72cc08f9b98c5cbefdcb2719b27f8a2bf088e0c787f685a418fd7e9c8bd180458be39ee23af45f93e18aa65f674af0ab8509f18aba9a8737df32595501bff3534c3215ded5980347ea005d9970a9bd3f74025fdcd59692ec92a9b722e5bd920bb24eae813cc29ec73d0a85757a35a143b2625163a5321b6772f985e590cc0dfe14d5e779b80f0021497cc0e5e3603487f488b9bc82bca719aba94763b51933ec9a63803b9d78d1f48b43bee1572e0119de927056cf61a9dc4b79569d356152839ccd70b6a07d347dc856820a4f3ac13a16401ca1005b3c10b860e73ee15efdafd062f2bca07286e33ee26d04ba7594b55316d78bbb21dfbfdf2b5ab630c96040fbdfc337a41c94d7e63e7cd23b68bc536abf38cdc404908f58a14197083352160943ccd9dd92e79c0df9ec909fc83fb2e410f61fdfcd5663807328f19680c600a559a9484be8a43f8cfeee5c00cc045d38615c0d33ffdd52c862fa517ad8527af79bc99b64e8e27a9c0b87facf608537ee683286f10ba21a7d3c95762ca0203ef50b0bac7408f15d4988787ed498afef79f8d9231700922c1d541ec4e908b32bddc65a13cb8d9c6871a5a7e601a2037330814bf83bddfb2b02b0433596cb1888307d479ffd3999dba558ecb400acecc4ccd169715b984701811ba53a5ce6b4f102db471ff0633df561f3b2072ca028c2ad0e19d6e35dc25b54b433aad418909a8d3c2e166830454105e50097dadb75735d36228b32aba7ba2b1026cbcf074c5d2d993a533f4a3a6e15704e6cd7cec5c5403e88a64ed0d5a828aa61abca2cc4b1d81ad6613fb199f1ba22c8de744244383865a429ad418701b976646c527b6e17b539765608382597f003abcaca35c00b646220314c48ec6d6e4afa5f9a1e295eb456eba3a6d42483d5528b3df802eb07d540a8a2c085d85e74c61eaecec3831a5d2cbe84800713d8107141bf49548e82ca99683f10ea77889e1dd34eff027097ac7469d825c8e773e0025897ab49c6eba8cb1e3b82c8c2d48e70bc45a91b89eece59289692511fb39af80c4207caa64d39b5cb78b700e0026d79a0ee295123e76b42c15d2009f7d9cf7297caa557bf4cd36d3479ae64cbce879e97d8159ecb5fb3d954e4654595f0a5b889c035a8ec7ec514cdc91121b7322e9776bb6e522a40ae74e8acaa85d36a48363c77bb66360808559a226fb103553b44cc8a188aa45ec51d3e8ea3ca9808f9ded722f336826db0c5eaca9275f73787daac109dcbd80238f19000d26d0fd617381d5f5815af2877fcbdfd3212bb33a08be94f4ac59911143ca621454fbc98da9189caf506971c86fb5c9defc5e1c1f1297a08a85d14526685c19bf879e320a874f36f8430bac7cea69b777a08f97b19ba33697d9583b7900a35f5a9a5a2edc678bc2802d24591383531de2395e73d8e2771a17892f2be908467a171be2905d96e21a0963a53c34f02449b19d6a8957f2b7d842327c0b1700b6c81acee7cd3b8c297904f9913a2f5b3b77fcace3508101dabfccaebef5bd5616b1fbbb84180bd97a3fba3a867921cf67e3dcc3a05ffe1fe244159c0ae43d02478d905389c7f580a1e434ae7bb8bc69997b107bd9ca51a7f6931d25c5ba4eef84563ef3e0a1cdd9b2b3893a69fb31bab83df498fab119db758e77945d40dc9e48c187b994f222aeeafcbd4fde7c2738eebcb0bbe4e24bbe2f18decc53f773d0f0cba015175e5773270e2cf1ec6f001199168fab0224dc9e1d9cdda67ff9828e1ff0be21d7820bf01c4df023709fafb06849d32b1382eac47c6a4f64bcdda56c07ac257d2066d535489a4c7fc2f38c7fb2216b672472474b7ab63b2c16eb58623ebf44e03edf105fdd877a09df7ff0b329521903807fee5bf300d2c09e8b39b3c42104ca5ead0b752cd3c5573871a9abf844f4d704441fe1d9147bf3a29d3e9f4260e3bc43c9e0d48122ca80d13c6c5eec40e4a4b56b11bd8fe1f1ac717911f1941496fe8a631a45a39dab2b83451967a96e59ada704835dd91091a51a446ac6aaaf6c7d2cdac2fa8254f7d1aba331fe5b40f2cd948bc1f0f1bb2345e9f13ec80187bef04b01ce6db68b0fd06f2f9259645d40686fc98237b1f8ead2c0dc2f38a9d22424eb61c5fe43d6790f96b0bc3ecd07f93e11a203d90b3c81e0eba7fc90e2792740cf750402d16a3a2b5c098184113efd0a870653d461e993060181f88f8ef60d93c04f01f66150b90d5df368db187a2c8182cc63d1fda6744e30ae6011a6b569969262367d43d4b8f19ecfabfceba0d93ddce0924f978f8fd45abe26d0b64e1d5af97527ae7f13e30c81eee8e868f134cd76f1f66806cd67cea61bc30cac2d3ba1bc33ba224f5f1a82df1460cf92877795015503c7f9a5f313404cc7e8912b3bfd9b98307eb14566eed05a3a38b9cf4853f8177a736ff72cfd22ece5e54b9174dec4a0b056c6e56213d5ce8f1e7eb8b44228eb1a8626458140711b0f5f9575dae22b21968b4e27693855818735cbe91cc9a4c215f98d22dbc6b0986eab9d61a4569a1df5d1ee8bd303e9df43d297b3937dfd6a55f3f7a545c111f209c1e06db2efab9b9ceb7b764a845bf72ef31e06d5a4a774362bc43eee6071ec9c879483ee867b996943203f555eb284052ba94d979d2d01ca7821ea6f29b6187db752ad66b19815c380dceab1827b74e3bed401384fe6799129537fc5193dfcee405b6453ed64c4b21a84864e8ec1a95596ef21ad25f772c4b5a9efcb9fd64a91f924737e2203e721e966933968b73337a99c91ef43908a123ba2964abffb66b18d9dd489010faac0251abbb5477c3862b07f87c8b9b792dede837388bd20e11cfdf1c9ea74e2c5016411f9e5721a0fa6cb11e208a79500d40b2dd269fa45264671d4030e0c0ff536cdcc7ac7db60145213538ec10aa3740f17deb392acae8e37030add0150c5a08464e69c244144561cf9811996e8cde52c4f38de6432f7a2641996998b8627487065d80d286e8c072808bd7dbbc6eeaee6b64ff3235fa7c2056e0df1fa11f797fff3c66b40c49f7c14d104572731f4c7046840f8a6237cf62af6c2f1b72a27639e0cc24c749c85035876e7db01e6f3dd1b1ba341a77e531ffb75c37c6ad51a71da626704869d5a51da6e5ac24ba3baef4eb0ba7e34ce95b350fd38e76880b37b3e396111d2d5d2f1b97ea91dab01cb4f0a7501b7a9134632ede9ea664e34e9d86352c175066fac335671627cd2b4b9572a6575ea96f501e5c3bb5b4e6a6965e937aa5ecdaab47c7034ab74a6b5e4a5daf9b8da3f45a5748be1483ae8b68dc8a6a168a9beff7ad66dce922ed1a1cc73a8a9e3ebb0e0f85bf4377f9b56bbd9d69f4cd8c23e57a5007268e94d2529fc7e03e7a989372bd2c1501169c7af2a7970d7ea0a4061f6c306417baa25be74c8d30168ed1b19961b9214bc75174e1c52cf428188eecd370eae5c4865f0e5c535a4562c3b439b8cae98d722e7dda741c297d49fcc25e4277d4a518fcc25a2e58dde648bd752e360dce94be8098302d1407d261c2ecbb50763bffe9b5c8f24fe74ae6bab8f477651f37913dd7b2a089e1468fe9d1bf52233873e2e92d9708968f99a9b4e68fa85272daeb95df8d5c3fe72e18bee02a1973fa5df7cd38db15a260b4d7066b1b4577e4e02c175dcc4f471b05e167e348b9da1d2bdc29704a69758d15a6edacf8b95f917b6b8c33e5c29728852806ec9684d93b52e63ebfeb7d046602fa905c092ce635e1a0ef161600bba63db52fdfc415ded605e5845e54fdae635971a3b476458375022014fc3812c595919a5752b2745c29f75e74c2da03ca94860b9d30d87f8168550a201eee03040d03ac7ca2bdadb32efb1df74dd5c1360d8eb99b60f04b7229a52df50806ef058794862e7941415e2eee969a02c310ede0f7b98301934928b832674d490ee5d52a2eb1734cc2a9f8e5a81685e19e2a442f58066699eac3dda7f3938b4035ab2e38d3ae67fa6d3cda4dc767029970867dc6276865c8149947da1369a1fdce17497a951269dccb53ce501c67c765deb67830f06a249235c6dd1f73c612fba7eb35d02c8d9f90ac655e86eac26ca48df56243a53fb580526e273de4892ec431f298413af3f64a8405c0c357842f10bcae621472a932602b2f83941e27683d53eefc1492d98136b11ec16cd5ee46a96bc83bee5128da27744ad3c5c87d78a21150ec48074be1b1fe45c9435405058f1212344a9ce257a3cefab7c10a5a95b35e0ecb13cdc2dabeba7ccef4e57b4a28e35b9b1c59fb884fd4b7344b8c207553d2c823c8b8581212ff239c274dc82cbd5342009ac7729e1411df8ea7381f3d9b56c6d137c94fd229b2b89904ad37dd70d6a2cb4f61476c1e1f20663bf946ddd870e74c6c7185222d9a8878f06ff5ac824f8df1920b86bf1acd1ca1645dabaf1ca564e4ac382bd01ce59a97b376c1ab32ab6005a0b53dfbff26850e1d356065ec0d25e1b9ed39206edd76e06f6f0ef24b3a0271ae478a323573416a08a9ba9786417b182afd5fd32eacc5e5e5f55656814166fab1eb5ea9776bc446aa4c5ad950f78d59f9e72fbc961e8cf9e833c0c1e946712943fb8d6332d4bba9f08ce60ad8674ea3e2f7a8c5b232d4a3f0da5746a93cf82ba5c1867a5ca4f30599adc02c4b0e75c0602aed6cb5963cc57e794eb57d3b7c02afcba56190854eea8912c1ea55f14f70d8f6d956593634c6bc77978183252e4c8995e5bb36f0c37102db6455cd5801c79fee8fe02c0d427bcb42977dfd05727e19f480c30f27fc338c0efa07c7b4687229ed14b5dfe192e3b127bfadf3a7e6b31fcde2e606cc4437b6be1ff9a7491e6121c91f6079d2e5a276e13f507e8db0d292bc16d84758527ea81eec8016f8da288aa2e9d7b81af03a7401195c9d4a84288e23342e468ae27e00f1f233e83c17f94aa3b50ab0b82110742ecb3f94f7d1a6a89dd6aac217ae584831e373ff9b97cf010a4a1c48cdf41c2b2c389b8260c73d3a7635561b0767b1e31f5f0846b463c57a494aee9573816af2de6b00990d10625d5387e3f11a3a064e7e68b871c17871d57a5d037d4b6d18afd1209afd426c83cac9367383d6b149eebed5ac474ba079670ffa8a4e55cad8d4ed1823d0cc4cc6d99cddf5a7659a17fdb2505dc6096fa8c9e2d9fd910e705e2c06bf73e21cc9ff658ed6b00ffdf32b8bf25d7098761017aa8ba828434ca9c60e375bc7526744d84b8f014d1b9cd0de762527828106d9a343d2bafd38724da34421e3e197a9a079375eef1b175be45c7cda14b7cff6fe81a72eb603e3735681cacd76f16ac457e42db550617b6213a5a3494573f850dacf02581f847dbc6a719e8bbfba18716b1b1d772d645c68afd88974a25422277a897b143e420ca6c80b051ab2adc5d47bba5047d56b9942bc050952239a18151f874a024143ad536dd108f350225f6406376e61bfd465c50f0ac2c8d78e8afca6f480993e38521b5cdb7875c0eb72ffaf1dd9028d8382722a9cd1b2689891af624681ab76d66e754334c60971b948af008af7c08f1bd948264cfc2fd9677c444e37e18938bdf0e4a64be92c17a5ee8d4811bfc25d58af867388670d9d6b9e029c0a7a84d0efc7843e4fbf212906477bfecf2338d359cc307bdb87ae0908414b345b8ca543a66f2bc4acad3f93d92728b05d0a04f9da48f231c82d23297fe6b14c1f80e36f8c0bbd224192f9e3e0d1708c6008599c17427219a7a79f3ffe14ab5c008cd60ffa390313e0c8a3bdf5beb32ae8116076dd4f5821b3484010394eb9840438d0e0f43be9d54d6250f234beb94def3c40570ad28f321e0c3d661e0bef41f1fd072a09ddd4e9240e3bb4cc4ef64f32cc291800b849ff47c7e014aaa74a964ed1576045aa6efea77087c1a6556ef1cfd5e209e44878864926a727a9357b564cf263ec8679a9dc9364450d6c975b314474095e320cb65cc6e50b0618086d3c21b670f3747ab72b03c721806ab0058fe4e1c17a1f6da57ef3c9a4736a016e814f70c1a24b9dde97a342b4d11d7b25e238ccff7bed65cc6bab42f575364463e776c6cdf87538818ae9d1868849dbb1d603072e435233ba66bb8b434a92e3f8e1150cdfa3ae7f0bc29e36d15ada20eec357c32c5cd048e25055d748d6fd10157c3658f41e23d4d771a66cc50313eb1ff82abcdc1282c645a7eb2894f4c9797f9868395fe56e485f85fe4d228cf82114677252701f398a720070c48b9edc37ff8fbda1c178bd67f5464bcf9801dc40cc305ad1b6b37d747b2c5c18d1c87ded2f9750043e3e1bfba796595c1e9bd4e342bb3b0a79794d8c07820b629d68c58bba85a7c98f4e3ab08d52ae016f8703fe924a8e668404f0007ed8996bcd601f27380b7a3d4d4988dadaebdc136eee3bc68dc6db5c39f950456fc6f508b62e9a36197447ecfd707a97bed86a4efcacfcbe54c4cba09ed9157c77fbb2e6993c6533f83f3d2104e85c786b6f75b63404625c84996ee301c1194d5145c1a0f1ca8e00a17582c315d89ff6b4b227005f441360059cd8bb62517e7a2851e7c15131448d808e0867ec60613ea738e5927e51e4901edb05f7d57acbe1a2c44bac297b1cee91077ae1db5b84cf1e125392d6ede32ebbf6fb6fd7aca761ee79d97e65762d5a224901b3441759004b873d9547270efff35e218318e7426b4f7802941365e43d5ca68d0b053aab3c2450b96a86cb3cacae0baf9de2dd7b97324e69848cf648b772c2e772be6359816ae55058b5f1818d48967f704505928c1c58c2949b9a3ab020a84b78dcfe05432e1b75ef5fa93242047ddd376fcd8d6247d5845e66a72a3fa284e6d972efa573123263ea70c091c8541603d11e22bb46f6596f898ee3e4fa94e135e3ae226e0324861ede129e6f40e047c852b1ec609021ee6bbfcb9a843c772b6894d24613d550907fb36f93dceec5a58444e49024c428cae37494774cfbec49b937191d025c16e7d1d85c2f88677e6a64c993522b1591df46631eac8278d9aa31ef170db4ef970883eed55f0ae50bea40362e6dfb8179eebbbe2fcc2ca2443e33f32038fde735454defb168342029f03e6d0c285f799a7dc5c610c471e784ed40763858dd6922a879bfdc48761aa7562e5ff07449435e4d9b234cf20bbd57c4742a96cd44de29b124ed1d4ee1f4c38d94177bd95476ea7286057b7fbde36958c0c3f89a3d6cf46202acd21a6bad1c9f123674bbf3ab8e857dc692461f4e5532691244f4dc1d2fe7a3f1b184d634c5bc409377413ed4397d27dd73efb6a42e9a821ab802900d1e7988d3533b2ba563ad3e4a5f9cecb5d8f8f8f273cbc9bc122a8036b3a61f2daf6ff48a8ff3d9cc59ec6ff171c34e81d4cc3c0ae3d4f137c1df007a79f32baa2322857d682d67134e0897fcb5b6dd98076c285c1be5c069ad831a994b9803c614e42ebe06cdbdc0fd55fd47f668e5eea90007b08721af47f9a5099cc261534e0fb9736879c027b96c7f04caf720fb603e6a043cd5270d5cce123fc419db24242545c5c1be416a5c304767405fe36df84440a3a4bfb28548a6b60fd6a46740ed5e497939b421e67fd0c63e204dace01a74368c55cb370d2d426b129b60ff134b77257104acdceb7edf8376d753b9c1b0964f0cd41a7cf28bd297e9d386f779d9548d81856c2201fbd07d1a45c5e2be42c9a640c046c765f754fc31bb2a38ddc9a590105f754dfd98ca1ee76fbc64c7a32398930b54fa5f7dca1a0944366a81932972b2f7fee7b7cba6759a9ba7ea050d32c8102fe83909ae496aa38dd54002b743981c3eabd05261c6673c80e1fe53c14b8cb448f3d8eabc789f2adbc869ed5b84ae870bf16b0ba491b145b5c391a6c98d2463d7278b3d12f93fb9422fd185006e66b213f535083f79c4fe187af011a20b0dbf7cc1be94a0213ab71be70c15e9e86343928002ca332aef4ee6974ccbb8092d75f770f4796d7f5b712c24a6292a24635e6530c2d35e764f0370b2c23d1b88763d9f2a3584cd869240be08999b02cf4f039a34148961e37c1f56e853964fc3cbcd34d94fec6c8d094e15444ef524c45eb449a3ae20c7fc6f71b0192b9f50bce122df6fd03d2a764903a93f203c7a94389829cf09e1d842cdd49f4fd44003e841375dbdd4d9b74f69bfc85207fbbe29a8d1457ae34ab75b33e786b381d9f80c482de0a4bc642dad4a6709f67ac99245d5fc1759d787491d9bcee2c0558e5c7666266764565492e165f07cfd6a80b829ba381ae4263e101ddf798433510123951ed27df3f6581a61303f3d9eaf13c15def610d73408e36d0666d6aee9500dc2d88a949c82ae5874b76d03e923c6263ea8e4773cc62d0299f81e429f04ddbc179f4f6d575ace2bc5d3bc3d99b0cc8e58691dc5af3e0cab0525a4bd420fef85d73387be448ee3fbb8739ba98517fe8caa84a84116744c0987b4ef9c972440f8cb4f05cba995b38402d9afb93325e0ef7f235918be618418daebbfe6372bfddde723440b84b4508e9802636e62d3172076b6b5deab5419ea6b38c0958879ed3f39774f31cd5c92e47b1f8c6dcb93e8ae66a8b40bad12a3a2d5638f99d3b5d18ed240a284d19d020d0950e33795263d43ebaa93d8dc33a1f6acfc9fd2ef6b306a8699f55c1155493eaa17c06d7bfd272f4966eea01b2f2b60efd8780129a40453395ecc8d92eef2d82a96d77b96bcb524f87c888c75b11f319073ded2637dd6581a6e7bc81f441872085ab29f96d61390eb789c00c948f70c97285f615e2ccdb481ba39a13ea74d1bd6bd336bf1aab18557f77209dde1303cb023f128a648259e59d39cc5e897734b8f4571844cd72507b4e3b269a14d122464677bbed591443800b7460ffc9ae9bedc9153fa596f73398bd6178b3529b658b942d3f5c780b115a502fdd330f2c16fa83b74a87f214fb1e1fe13a8cadbd592af88cae66f303a732366945cdceac29698481250be7dec1f8c4dd94cd9e6703f2a04fca6a5c891a6e2329b8eb870d5d52b982db191556921341fd304313816343fe194b38360d7a53d5670a7701fd9d52c54292f2b2361cab5eaa36ebe824aa488550522f1890b01367c4ad00d8cbea49e0a29362ebb030f5569fd1437c263a4d89feadc6323fcd452c298b14cf74fcc681e1e0ee852c63e286805ce27803d30629143dcc5c572101f7417a7f4a4e23dc0804230bce293fe01f1a4af65611f468c1206432196382e4cb65df6c14f6c7e9ccec81a8138ae52f7103e77fff7844c84cf7fce6947effd913e06ac89defe00cb08e2b015cfe0a9b9594dd9e15afce6aa27e370099a26f8421979df63c64cc2c07dcfd41a3554a66d8be7a909767403d4abe3f35a164d3b1770c80139653c16859bd38f673c5a66a97590c6e1ed83625eca66d46f16d10eb2521b9e8cfa138043237d632b32f13f93d2258da4cd928bb8b495d84097e646948ea95086659f4547273ac6276e5ee3760f53ff09a2903618de900aafd6138e4d12d2a09a72856e145459314a7bdcf9ff1217dc2c1d31f7b4cbf5d3e5253b9fbab9c791c9235567ac58255556fe10a95959ffa6c8b80c1d1b70c7040c5d00471fd1a002a50849b2864d8b2442dc75a899054ba28aeb3fec0d95f6be6292add779c422407d660b67bbf2d55b9c3524e1d63e53df41d03efb12507d0846ab99598e52fdc7697dd435bc3049bb2b91665749358ea1ec1a8ab6e69259cde24ef0e52f27e312b245a528edd8085366ce6a5cf9d7012c1a996b42e35f7701048354da10d194533cbd4e897234041aedf6865583aa7bac5eac4c687cc3c223528a942a40d78a93f98747fd784036b86c8a28e4a3f6e866201d8ca5e2cd59fd2e943527d8557f33ec1c201d3582a2cd51135ee0bb3e6819364942ccaa4e2403950d990382eb46d43003ed524a6881e2939e703a810021fc32631de6fd21ea0025514b1a8a25f30ba0684290104c0c881a28a193de873cb7a3a416d03de14ea9dcf951040fb5f8cd55ca18bb197a70996236cc2fe2700193e24ad0a232c700dfcc46fa4498263d023a6b45c1c10bba1d0b0cb54b82a53a14c98d79c9f8a4ab7e738e9908208e1c6b130bed6044631fa508f31d6f74d2d42b21183b568a91464511942531d200459323074b200e327f1a5b0e61fbebf35dff8ece0a88fb5d1d299b49f30ad8755fee9834999d92dbc36fbe62b9529460f440a4fab4364d77992e8b4e97fb0c486e78c53e59aa3d226aa53d1263e33e0918e3cc3ff730292740a6c7078ac81bd8a8574d4c169d029b16a418d6ca8a3bb04d6d8e27beb4d3aef092a53541511e74e30f9ff37208f982dd1026849095afb6ff09680768750e8357bc5dfd7b237c5328ceb6b10ccd3371751bab30ffbf1d33893f992e138fc5c0986e29001a4ffe0dfb1f2c7d784b37a6a081ec03a9b26eb7f6bb131d90b3ab65b82d913fe1c3fa34a3d99cd5a59320d922ab8fe32e41893d2896feac8114076b83384cb83c90a2e5fe67ccfd80177a0b6e8befc1026e90c028813e8378f863b29953a3f9c88d11611d2b93d350b029180127673136c89c17a1c5d0606d43309d46d4f0107a247346bd90d20fa8431ea8935309d0f63f5be4a4ec50534468575474acbc79cb4c80e6211fbbd3587f5ac6e66b402012432bc7c7cff7cd18b7c7678cafdf64fd36a9fc0735e4c599f9cd49e18a05432c5c9c4e302465f11db7946d259d9d4015f7b675bb566ff37e2c916e9d35f50a12c90d88cd3e9596c235653ff509e53dffe2936a30b3a15c53901ad4d18d8c607a2792c54c19ed3439aa44f3292e5ffa4473061d3d578e6079ab4b08f1ea82ec5ff17f378325b01839cfd644611afe8fb7eecc3e78edf985101a17317a198b45d21481ee029365c1daf416f776b71630207053d582abab22a154b83454beb1ed8219598364c787db6923ab99af0637b8d60b7501b67eedc16c0301392980e67711e6df3c160ebdffcb69e53753ae12bc97f74451b5836a1ee12b5a326b9bd3ffcbc22025988769510bd26355c3266eb8e57a3aeb7de252427679031f26416432006b249a96940fa2380cc598321dd32da9cae6dff543d6ce41f96ced671c68dfb3e2101631c9825857687b1e5a71c8c6fccd3b6852ad3023be705049085366d002fc1d8b0cf379dd27486e36f88b42d19d4f6029e4c9294885a04fe9b7106853504999c85444be18f6b2eaf03fd06166f9feb67a1db8c8fc594bd822fff579871f58af5cc0c168d48ac51ee6fa9ad7f44081d7638642ed1d2ce6cfe8dbecc3c739ba001d0d2bf6d330ce6a6938e14a7b644e8335a3cbdf80240026465754aa30c2d3bc63c9a85a8dfe6a0848542412c1ef2193e3baf1ec925d1855cc63e11a4a8606e184f70a4021cf01ba920be54df98652e9c15a7b40816d37f98739e91b4021f8a64ce8ff72d319764a04bf2814466a9644f563fac00942caadf46e251e6352c7bf2dfb09bac59306d0409f52428555b203d5361b9891130095c02c0ec527ea2330f8b0f51524843c463a0277b80ba882611d03500f4d485c3b482d04b06ddb0c878ebc39777e39eb9309f5fe666058d5143c554e58af5ec717e96cea4752f33055bbd981afecf09757903aff86b60e777ebcb473e3ef404452dab8e4778569df1f988f7e6fe9fd554d27a0b146cc0aead03f8461a38ffc634542ba2e7815f1a377f88b836682090a8aeb60d4acf2211bfc3e74ad67aa8ccdbe2b7a7c28f8513ac263d53b9b231385392040f257884135d61361d9d8bd6b6c19a5208c7b234d031565019178c268db3c02a27f1b14d660049d21a2418f4cd3715b014564ae63da4ccc96a5561ba35b217068c1ca03641d555640fb339f2ddb39a2b711a1130b4a87eb19bd3638a10b7edb9c8a0d76bc822a63bb086ee98df7de442b283cecde175801479dcff714689932b9bf2f553e664476a406c020eff85f72c6675f2931748a56a8634babd1778c8039f290ebdaa735bc340dcd22590787926d96f8a9df3d0ce7dd03b8833deb85ba13f52ca0d6cdc806b881de51207fb82ff5200df20c1219d02b89f22ec76bdf6594a2221f7118a464ccbf8971bceb739e54accb31bd0f73b529fbbee248eab0788eaa60af5c3b31f40ff42a16e275a44280bcbc605c279fb122236d6f6e8e94e6d2918f22c7b898d6f609a5f4ff3f9131b7273ab5fa8e1032836fadb61c325f36d7b1ead5088bc398d6ac4cde1eff0fffb49b85f8a13830489c7781ed4790741f7fef6c8264f2172161b456a9657c5a732a0a34bf2e8669b34286db6d8f042ae7086dada33e467badc8dd45d009784f888f1fe2d7b8b3839909d4e1921617bd72b74d22a52d00fd21ebcf1ca25c59f13edb2dcbd4ba90d8f9b5c203172167e0b3f94c4cc7c132c3080d2ec4909219e3711d97988d531f1007b73cd92eb8f1f7d1648417624404a88f4fe1564daebac7f1eac852ef89dd2f6456ab1cc81e2f0fee7015b3081df09a9de2432cb18280ead7f1e460b13fcbd92209407b69183f7fe41ead005e4c371db84bfcb0fb276248e7f3eb6df90ad32c536ddd0ab25e3516f153c882a405fab79f8e0b5576a96cc910f7c619654f249f60d44f97e52b2ddb1874c1d6a02916303c4e9aff8a14cfb62a71ce6f4a56ce18a127241c8eb377133b2b35a6e459a0ebbdc2e5f177fde76b586c3624cff57b54eb4625f686cce16249d58133d5b55743ce63b4c775975eaeef95c635124141b64255ff8c60fe23245a51364d918239438cbd7dc346b9dcb0bfc51388c221430a42dbe4c84f3d277f7b2bf83f0a20634bad0c1b8f5a45eb1db4009a5ee4c1f712cb84e39c052d5bd4541a412edb1816d11b314dcf4e332f7c72ac0c4d007b5cd243f06ab66c677098d0c2af87267e372718b8b3e1775a54e53d6fe626eecd6cf0fb77282096090cfac5e77df6f4b885c7d99ad5b81f838f116e0bde05c18b1a9d6933f74402e4cbcff9125630dafc958af3c9133ddb4524cac935fd3a42cd2574a37226d917cbdd7e079ffb43f08935bb869b4a180fe30587d1cc395fc1d56006ec454b3d27990ec28812a2da5236fe9c142ddbba7fa9c7c48bb468dd9b36a6610bb5c9133f90dc46cc40915678f12915b93fed8dcaedcd4dc9a916fd3982c569a4db08d433c32739ee5e58612d828c51de3bf83c995a3a3b3dca4eeed18937b17d01cec5e08aa45134cad1bc545f7ec0edef70d862041e8fbdfdd4f93e7961851a7302257b2000a55204d7c8a936d5d2fdc4c85eb2cd8146fe7d95d304e2db41cf6e96e6a6aded7a174c00ea5cc1f9466392745d13cc36104bcc042752c2f958df8073849ff16eb1315716288f99fd375c8dc6d8b82b56c1a5980a7fb54e99f24ad19e569714c0d89b9f994d2adbe0ef8fdf5acd1130e606f8bb618b9cce12fdc86cadc1d1aab4479278e5f07d8592ab8054e37329c3623516d228492ba9f914cdef6e484792ef31a2b7747c883329086a4bb36bf522d2d9346caffd6bf9919cc91e89564654f0da7846c57337a258c7479efe4894765ca8f1480a29586dc5c95b18688a9ce38fb9be0cca2d714f27255710fa184e6c28cda21b1b4a98354d8dc42404b6dcf50248cca03994cf0451ec4f2aec82c68193b971826805f4521e1481d84b0b90ae0619bf2258102b7888c9a32e4981ddc9e712457db9d942895c7d2f296f0ab602be9edf8f2e8abda2275e6f0d750f923981cee8a6a4fccc3f03fcc3d5e10c5e431f0f7ffb9208610a639a98f47ff3feab3c90d1e65c425f5898ca6d0bdf7c322f33610724ac803f9f85c372e4479e2302e0baf75739e295e02cdcd5ce905d08f69f0ebd10ad609bd2d182b98c6e0eb6f2ac7ce03a1584ebbc43578fc83c08a889f5355ce730d0e2e41aa65412050ac2b4ca450d3a979afb2705faf90971e3d0c7e577f41974c0baacf635ef5fee5606083827bf0ef7539bfd5b883f7def07c645728fdeabd9498c5c41c4563ab839d21e3afee2ec388a7c45177e40225c8c24e8e7605c5d34d8e59da157aa72bc597ecc98158057dbb52aae38dcdf04899d72393e4e4938edd8f8d134687a36565005d5993229b90078f2ca6f6ff74c5fda0f0e2fc4059d12fcfa2624914de0beefe320d895ecf8fb8f439cabbd73b6dbb9250aa0d55411336eb09a46d50179a60bb9640d22655816936eb04a46da9149a62b34a50d2867a81291beb9486f252ff6d78a2c01d49dd9d24599ede74f9b3a4912ed52324dddd0f29fc0302ec18461ec373445c390b7f282b9404c5cde320e6eeef3b6632daef2a4106064e62c926ac0f2596169ecd132d6ca0027f34a684bb1604670357b56e4fed21ce6a20e8a75a7fccf4ab1035abed887269a6e4ffe0fda6279440643cb9663eac53fe032d19fdfd2f8e4495597e09512e0172a7a53ae537bf5be4f8bd4720231d366ef2561879f61e4a57944550efa25b50fa8bd0cfa857e77ca134f5959b16100ef5d8472cef2f3229422a89bcc483d2108fa028f569f52256c026e7e9f002d64095022b19cd5c957175c9fca41b36b44b050c8a3904b1c912afb74f102923de654f14c314486c78126d23f6ea140ec1532397e0a192814cb7992e53f47155fb409d24aab50d6fe5a48c7d768a1b539801c75fb18f305399eed6e1bb816afb55ef23dce16ab1dbd30e0cbdff95737042ffdf04ee33c32d262600a9b57070207d5bad2f7d3fe96b313e4077f17bfc2053336945d5e43f796d7e51fd1bfad0c8cfe41711318ce01a49824d62517e64a24dd9d1c8b2e7587463430b4e6785ea7c2464883de7063fb571b584a20fc47e234bcf2bda07f9d84d28af1dab43ad37585ec08b9ea87229d7ef6de3ac7efb18c74405a1b8615214fb6860c4c1662b6f440a2a52644386e8a6ed167bd71d5de3fab3bdba8d3744a871901294da7a7e6deec1273e715f4e1fbf06ac1725233943d83783aa62f2e9107bdde40eab60dc35ea57ecaeeb3b8b5c6278e7635969190f8f22aa4940b6643290b7c8603ac1e801ba1369c3a4abe14b7468769d242db21effc2b2147828a612bd1552e71b1cff82745ec5794ff1aab721ab28b4577c6faf1379259b9a9af5f6e785e71530291cee01d7ca2db743dddd8bdfb6f8b8b02570fba2ab707515499665d9b45eea137a45c5d204155fb09036588b54185784d1f2224e28b5b4e5fbe3a2583ead82d16fc79dc5136e517bcc22f8e28c203145b47c9349653c70469c981f9f5e7674c22d3f6dd3e5dffb15d0b168346d20fdcc9f50617f3b204170ee8dabb13ebe795390646590a15813cf12fb1d7480285cccf1e44cb992b6d40b4db1592520694badc094ad7502c936d40b4dd95a25946a435dc894cd6a02e9b6d4854cd8ae25909656912e13a4107b201677b91bfbe6d29369ad3f875ba077bfdffddc5b465f26a61979277c01139eeecae103a79dbaf8f3b61afef4946cfa03962e344114d6cb8529a6fe22a4a1f80f58e9ff8a2ab299cce714c8f7e49fd552db664f891372d0170ae19368480c923b874c85ea40b6709bc3650726d19b275dad1f279f9a45591bad46c0c515b43c4fb35eb53a291dcf1bae51d3b6a1f4fc61dda4a457e425199392b0ff839a1e9518b6a1c1b329e888aa9027992ba203346b4d8adc1e93ab181d8fcaca24441c965d4da6129c3e096034bb0b45c6652df72ca391fd8bcc37d20e049e74d91e271865e71bf48a52365b7ee21f07f5e016829b0cb9897e8b04b398231441d5a8b2741db0c86a2c1061b1e6603d2cd26eb2bd6b7295c26858ae0ffdfd02ed2a59cbdea490aa2847022534f9e8d361dd4d898734b55f1a6ebe366531964e5dd0856ebd03be0bec65d279715577d8baa694dd35a75ed7781d911432d5ac22249375e9541a553610b4fbec72306cfa6b8cf8aedd463eac513abb7546f6900ef918a9bc57986882849c208d4d00237d4776fc2fe71d7506ac3eb43d8f5beccd01349f076da25ed2b1e10c67503a81afd1416cd19b57ac4215150f4348a71ad40e63c34f9a1787744a388a9eca6dde327bd38d400d8169aa2a0ce97807f818b65048b2051db2421ba41d9221150871edb49adcd1340990a44b3a4117cbcc66793a08c44a87a4f763f6dda4235d17578a087d13996871ec80d1dbb2432d297152908ea8f046366cedc9d329239693068e839c0eb670e96c1f3e198aa83a24b456919ddd87844e0d992578cd433af2342cdba8a462a1026c94a8c648c3758494d279f83e7024a6b6ad81eb4e0f1971d7444098806ae93c3d233d5b3698e26b3cc8dd7f9b36ccffb240afc03ea5b34b79001dc26e52991c2817d57e9b44f34d9cd366c3bd582c984b5720ff488b5de0daa4152e4ae316cd54903168aa44e750b7271f35ae80f87e96468ceea93f4d43943e523f23c49b9176c9d4e819d7ef5a13eaaebc42e363f6fadeb93ae030fe77e1d6f4358d04905ae293cd57d6df7c0a9da0d08bf634cabeff0979b0252ef532a7ab3d3886efc312f0d0a90cd2be06cd083aed5dc46508811885d9fbd98e00cdd800c4aec7c4db8a226e4c81cc70dbff8db9fa7fc8c61fe3d2d298fd6a00deb0774d21f21077f862f65da8b574faa835a8140f1515dab481647ae09ee1b204cc14e896e3f4ad1970f4458baad4dc8b200b74ddbb9a88130678f0c9d7b9242eed0fc1116a234b9281c3934846855b6d80001851f9ffcb1e3ef663aa77aa09751350cf3a0c4589fb455779d726fd40fad630ef143e742dcbf3fb39503d94a2212039334ea8968a409b4c6981926dcad33505ed4bb85b2cfb31de8f31df7e18efa6c084c2a0d56577be420d17f984bbf3ed3e1786def8fbad20b1cc840b401b0aedabe8590965dec3da307a3011ecf52218707f1b073035d4f2a191db63ae31bf8f691214e047d414410b41210d39489023e6a6169b402bd197b6d8eb2451badfcb0da9126b1bc46bd9ed792925564928b289c4432b5baad8e7ab88cbaf356e205476f45365a4edfe4a7b9e1e77d129e9d9eb7e8dc55d7d0fd3bcc850b1b2cfa82a666091f0b9111077efdb46323009018aad4f8afe9e086133321b5646d4e93a4dd04258491f584570a133f6c9e29b6f622bed41819c04b5e889ff0e26a19f067720500541e5f743d0b2a0f9b0d603912cc8fa54eb0e7967e08071de92b11bc3a7c400722c48ddeaf6c81b6202d33d87904fbad6878e888bfcf3a3a2bacc61f558d09f048e29e700ccba1641ade38fe78ca4359aa7bfa3c1d266b965440859883880660ffad0243cdb6545d344526fa6097a3ad20ed7fc1775e6698af76fd1453738c8596a7657938c65a6cb74192c248e0aa2d3b1009dae2dca5aa8b4216156b53591769c2c22691f52f624950377ef96c6df43fcf6c90450c03b6aad7a52887ce87fba5db75f35056ec0fc24c05dc30fe90ca1b6bcf5b6e77db27f12a06c8e4e0ff52ba0dc6dcfdd0cb801abf8ed99be7fcbc3623a21629fa9b9aee28b30ea8275456cbec2318938f9a6d4ad1bff03b06504ca78bb3999401121120423b0d501dee16f3a13d52d804280ed966e9c37e738c290913d1d1f9dc41dab882505c065bbe57c858ec337121889ae559f5beba40847b8e6bd9be7d0175cdcb3022a01921294be079e8964f968fbed0a1c422b68992eec3dd9e6c885e0962c5dcef2e26117e4f87a4039c93dd88ada817adabd373b2e12b12c81046f95ace565ec680787d12ac94ca2c40abfe5103f078fd4cc159518a3f21bc90b6c88033abf768c592012b3491b5eb22dbd7135b7399dc8c4a54485ece46d86a00021e6fd7ee399dff7238727d9f7ce7823fc383b44bc00a89000001057e41f377500ce2a005aa39a52a905c30c9644c36c37eb6f1b694d2421929288d0caeeee1d6c0820080a09369e43357b402e4454aaad07aeb22ccb5a225fad2fe546dcf23e95e57c5a2c7bf55a37e65cbb116eeb6dc4553f50542f6910579c504e83f575419a47ae6d286e733799b4be77b4511c05766c1dfb72d268d39a482ae56e326d1487dadc888de770233b5c87760db5ed08d8780ea7804d0e0aecd8475e731d4788bcc6699549a55261d4e9743a5da122f239a34ca7195337d38d329c3d7854d188111bdf91c3d3e136de0e152a02395c87532087eba0808de78c8a800ecfe114d0916367363b021151d548cd85247a7a554b7221e54d766b3bc6d2b157f28861250fd2b49207b1635cc81e98532f8fb995659c469aa4699a0bd95cf39f1f91489af719f951c9616691bc9fb74aa3ccb7cdf12491366a4876920bc94efaf915dec86bf9dcbe8008bf39cec4d8beaa1cc55b4315fabab01cdf0eb771947ff4519a74cc33995c733c6136049f503a24971f7c143879ccf3fe50e0e433a6b5a63d930e2072b0186325c75c6f1d924bfc5fb40cf325a7a1a1e93add759dc94483d5cc013bbce4da935eb314a45b597b26af1904e2ef70cdfb486edaff459336b6c3e5ded9e1a5bda3c3a5cb8fb4796498dfb1a14ce570bc75e8c871b241a1a43c9d4e24c7a453c949dba9b4915c926a6a6a6a4824128944aa425b8e1af29dcb2c3bdc7919cd68e433331ee6e5feb27b6993dc3d287b9036e9334ef2cd933e729c39f2f20c4dd7759ec54ca7f36ed2d0d0984c341a789307711ccdc837d3ee3ccb971d8ecca1f3be9fefe468b45143667ce442667cb47fbee46ddbc8fb8c7c8966a3d917883e38e7b8192f0f6509fa99874353a4f1238f0bc7718ee78ce3998d1ab2f98c0bd97ce6e749de47a5f7adf01979525792dfed0b441f2327799f083fd29ccb19054e64981c12358355ad156218439929e3305d61857b87343d4275b3bff511797cafd62693bb75650df89159b6513999772e24dbf4846d6642b29ccc473eb3cd6156b2bc8fc85f994f92c3b9edef6788bfdcf2cc017fed5207857048fbbbd4479e0933d906a7dedfddb6b63f6d1ddbd6efb63dacfd11791e55f5a8c7a322499b45961a1d9ee7709b1dee9d96935de3743ad73d5175afd626d3e75f4a736ee7704ed3a5005f49c94d2eb7518c1fb3cd31e566dce47df9cbaf3f5de2469e0832a57dc633d17836a60c7b689ce69b0832a539a73dc7da731ca933bfbc4d6bdfe13c4448390f117e0ed9eabd5a9b4cee5f8a73ac336d47db3df193fcecf4c4d73b477b76f89aa779e769c7334b7d42c931cdd3b5d725f979ed9d6f7a8f60c78c93848c1cfbcc7246258799c9e1c867f6a499196dfb23f29a9bbc3bda81264d3db34578bd3f22df39cee4acf5bcab998ee77aef788ef7ce0e1ed56bd754efe950bd8d7699e5ecd89ec3c6e601283fa14ea8d3e974429d4ea79ad3aea9a9c9a222228208a9140f9a92cf94f6de5b25649baad79a0047e8cc3f954a454425b44396d208aa4ee48de575cf4ce7ab4faefd9980e86b75225335a8baad23e0f21f749efa04872930df360dc4f40b69d6d8f5b655bd711bdeb66d43610c6b1310bde6b453a6b9c67bc784b9ae4f78ea13adf596f568a4b5d67a8aebbaaeebbaae6bcbd9677da2d1089f58397c7db2016102a2faa43e198a72dd3abe2e6b09c15ef7111c695df86ecbabcfc461d28ac5864b1ad5609d65d6e1ee635e762e07ca94d69cc669ae3d6ee330a7dbe6262072c03c63e7bc6deff8cc4f121feff4e464474173ceb38eb6b96ce793737bc794b16dcb7934721cd98d72371a8db0ad1be9d146229148144baeb9663938e79c7d7354e69983726299e940a9478e67960333219b73dfcdd93c472d44fb96a3371af00050e08c54431a719605051551aa37f120169509583297cc2c4d904e9929e3b0874fce9d320ee35376726def9c4e2513cd4ca9442275a48e4422913a1289446a62435dd7bdf7661d5c54853b1d8558a10af4d20c50324c74344e33e3a51ace2f2f9b462a5cdccdd7c8a1733ad3dc91acb56b9ae7fde5253fd2f4b567bd77b291e7435ff34cff3239f49a124d37532a651289446222e713e727cdb57bf52995bd70975ca76e7974c95c3223174b8c48333ef3d578c9bb0dc3e69c73ce39e7dcf6d7735f89cd636d37e0e7f1e61ad73857c335e0e7352cc9cfe33d821dafed6dc9638ee11aaea6c6b9bd43836bf2fedcd4d1cc904a5d47229148a4d16834b2ac254e270fca1ed775afbe326579fa69640e02b6ae58ad5f7eadaa020b62befac58298180414df5082cb4a9d935c739c3decda4ccebbc8696be8387bda945d67d7b09c3d945601e52787bf15419d5810c38298dffcabd126ac7dd37bc7e478efccd4789bb6671c3acd4ca9239146a3d148d39836c234cd711cb76ddbb66d4a5cd7755dd7755d396b41afc5a0bfae4b859387f2ec7d31a8c8c9511bce1e396fa718249fb0202606bd92189f0cf90d50be7cf3ebd227adafcb354dd3b4cbb56bbfae8b46d3d775e98efb32c0d1f8d4bfaeebd2a0936a4ea85c536332994c264dc318634dd35c6bad694d6b5ad39ad6b4a635ad694d6b5ad39ad6b4a635ad694d6b5ad39ad6b4a635ad69ad354dd3b4ebcca7da4aa75f2d79bedeabf5edeebd5ac3af6ec48990b832cefca4e1cd1bf9e5694df34c6f1bc76dae392f795fc78d38bc39b7f1fca675e7ddc7f3da3bb71c1e69a7dcdec13eda3b996b8e233b8fa7fb369c39f41349cbb4fd9948a49c73ced7454343438384ee9ce3f4fe74c9d3af75b7bbddedba8ea7cb7ea0f1bd2ecdc3c3d3f1f0744fb895ab739ca1aecbdb38ce4f5bc937aed397369af1be517612c7f1709c6f9b6b3ccf397c9e91c6791fc76d9eee356def6427ed9d93733cdd73be759fbb3f655c756e7fa62cebbaaec3dd755d34343434563a9ed74afbd325aeebba4ea63a9eee95c46c094a9744612b9df8de2347aa8c444ee5e68e8a473af345ddce6bea587e2df4912b48d94311a492e66d8e8d304ef38b47dec7611986650f18611997ed1c8e738c2dce5ed728e348a512c9671c660f20f98c930240d7177baf0af6987eaf8c3b526e94bf955e556ff78a04d59d3e5d84f95957ad646a5aeb24ace48dddf3b3fcaa5424a85696a7923f62102837bdb3d680218f1f30c31be994fa74826774a2fd1467d059047d743dc5fc0785c27c741c08a4c7fab9a91767d070688b977f38b4a58b4f41de548f3488fea5620f3a5ed52a05c5577780bc217df5610b105feb1627be561f6af5e13f13bee6e751c9c0b1072940201711f9435341ad8a3f6827685135dda4f3fef4364dcc2df58bed14201079edbcb9080064a0231014ed729172c75709618c32ba8c50a6c9346574195dc6785f002499c81f4c346fe241b41d25064527f1090c7342b4d06210c33019cb98fec1305874ecd9b37c2d8bda6b518a61f1f46368afd909d9013f39ee1db9c8d49cdfbc22b7f8ddaeeaf44a29a594515e6bd3b83f7ae50a1592a9e99a47a5cc1e5664ea2607fa8b5cb8442f514a6e0186de83feaefe542b5510e92938000289580c51c6101653e4b5c9e1f2e6f27bd9a9d90a1f3b741282e01cf3f5e2579faf594ebdec3357e99a471d664394d0b7f6bd7f616e3d73cb4756f791da86d90999e3ea61bcc2ce8e71adfe935dcb1501d187e596952fb73c1264caf2ea7d33bbe5e11eeb73c61b6ef09a73851de7e59d60fd7a28bb11107d58b7d6bb3f24c8d44f0fcdf152b1b2fc8d41329592365ee8cf86e888dcdf7da29f9e5ba239452cc1097903ad2c0f5d36f1dff55fbc3e07ee18544a43df09bb2c5306d18b53998219181dfd337da954943fb434c91e533c4a8960c412e2432f2f7f988e235dfe8041e6dc500a492987d2801642cb72086b85a65b6bad96ad134238e70a20adb0c231b56a3a06da0a1dd25aab8f84f3068c558710fae538c24dcb6ee7b5be6bbbbce87dd3a35fd7370d470f6762d2332f7b77ef40873c1e781ed3cb4bce2c52ca29a594d567ce225dbc28798779a9e4dde61973e959fff105c3304fc9acd999717b1d6f9bc95a3779181631e831c6c8420ee69a29678f39b3f098dd9b9bb08d691ac963e6344dd360842360cdc3de671dcb91d43e73b43fd73cfa87e408d06396c6eb8916839e790647d0dc5ac7ecded13c2fd93230af2cb261f65a6b478e799f9ba696980a359e731c719c674fdbd42da7711ab795d0b78e7123c7dc3a67b19192f976e7e8a087339d47e734e80dc1bce4321b52f2ce94f767f9e733b387cac14cdb292b52e33bcf9cf32d6282d9837f4d6ee1ecd1d54c851a87b387bdde79f06b3ccc5361ce1e5d60a39a9cf591c7b46dfb92c4a2a2a2386abcc683b347867a3435cdb33967d9b669286d17a9e9dc7ad671e791fce499308fe49d87918a9c6adca43dd4e61a3bc91bf9c933913c3c2a7272937fdb2e5273f24c359ec9adb7b9f6ac9fbc1a8759919acde433b9088376b2262862c881275f9d027df559abdd3e1e9d96dd994e753aaddd9f8c143a8d39d43a9c5f0e94294aa5c3b97de24b2536ce2f3075fce30b48e3252ba47c761aa1b7a80e8d97bc7a3ad9b563cc7f74d1f35effd125522513956377a25b1eef577225f2774c8eb9751de30ba146370d6628ec6c0e1f633943c7300f6edfcd2ce4688f58f62d3bc45878bd64273bfc243f1ff10afff3d9617698f5e488617642e7307b74884261dbb91cfe8c7f3e12471c231ca106931ce4f6873976ede68baff787215902f43e12eb899f25f979bd35cf7c0695b37776a2e715b66d85ccf1e64d2ab79cedd22ecd370f5fbeed2f023d759c516c7ff4b1ece5792592088160d4b19e159e44829ebdb8a9631efccceb994fca9b3acc48d931d7a8cc511cc92f0f95f90fd06b24395b4ef6a844763be732796cef40d7dcb4a193bc08947f8b40afd138741a97d9101a2fe958d7188db739cc7268f647e359fef9c8cd43e5642f79f6921550de8a54341caa82cb47b78eb19563a653fab8772cfee2ebccc39b5b4fc3b46318e6d6fb68cee63e50a67e3e6a1dc22c1f3d734c73c9cb25aa631dca1456f2e067effbc1ac37331dcb33bf1e0675e20937fbc14547eb9777824df2f3996b87f286c32c8c7a7ff2f55df2d846b73cca1eceb4f0310fe2486d23e6360763282e3b1e79d6356fcb3ceb232f734dfba77976cc43e99d33e328cdb5738ed2768e8698671e4af30c45f2915bc7345ec967bcce73c6309fd9dfcf43cfdea7ed9c92a3f2975df3cc43e59da367509b8f3c3be63cec33dd6bdef98c87bdb4bf9fce91c4c73b8773d4e6dbced19ee5919739e76dae79f137b75ee623cf3ae7e96dc3cfd990037c749fc8137f7efa8f2d7474587f78d1d1a175b7bce8383302cdc49a26f4e1bd3959a622d5991b6eda04a5d7ab9c965a4b2d4a3f6ae54c30bed0d4faa4544a14a8c7a716d5b1fed19c9973c98031a45e75e8d1ad639c2eb74948741955985bc6276cadf387a582b56db5f69228c5ac02e8a3eb6cd69fd21873b6282d9f994ef4cc424b4e896ba65bd2aa63bd9ce8b26628c8fbf337be10b474e83fbcd0d3a5943a3ad1a7941185e9d57f7efaa10a2844effb41217a74ead7bb7c7ad42b72fddad0cb50989f2e72f7953a08b8668070ceeb734a33a8161ff006a3d3482392f8724eb7ee93459fbd83ca895ebdc7da4a3af0f37627a9ee53bfee24d595705f7792e83ed947ba7b2c49862ac5c3a67bebe66c5996913cb19b1949a5a61a2a2df089e49b97af6bce39e79c73ce4cf29c4afdc6eddccd38374332a28d7cd98891cf33a49919e7f64e4dea2fcfa99fa9c134259a52a9944b99a6542ae59c9576966539e79cb316f7de7befbd77db369b6ddb463425d2e449a5b89c53329582598ca4c8a85297fd5256a7dca4f565d54d4544259f6cb9481ccd88dbb43699dc5329aee3eed5da3d95da54c8e1364572d810195d9abb5cbbf64e37ea4ca8191a53e93433532a954aa4524d4d4dcd161b1b958de7b0f172a80218cc978b1581c981094c1324ac0c3682c4454aa9e3c0cac0339890428403185c6e28e38449171714717145882e5b4c2b3a0e035280433d8082840c9c10e205276fecd004881fc63c6186126082c0c8bc94524ba188848a888a13551122c2c1961cf42582077d1f0e11d980de1668d19de9870730425cd83083184dae884b6881c50c845cc0c486214c0c2e4a18a34d5674a7a3f0f2465e59d1354c04610855b080091dca58454429a3063c54710319a02f30685f5a90cd2752d0262702d26a04a11e0ea1f1050d2b9eccbd92a91b747e3884c613bfc2010d237efec868101154f370088d175420eaa5c9a6ac3bdd99542b12da8821aa562a125469c0602b9d52eb42cb60685534d994756759161731641e9dce265fe5cee60c28fee32134e1c05970e4ad17004c3c6c2c1ed636b90502136972cbb24804f138c27487ce2822c874994c9e3a03ca7faa38ea25e594d55eeba5a0458a2955a200820cdac08204414d86c2047104110e5670db186170e0a460fdd09665390c7acb0a23cc5b965d59b9b6d229b3165481c9703d1c3a03888b981590418417559a0019a9b2c30d40b812041161c2b06207f6c6a7bb3266e03dbe46dae33f2a29cd0180379ee369e9bdc21f97d3bdb15d73ed08bd071014944f8da872c30f9ef6781c8923f524a3d22d2a998ab5d69a85fef2ca88af6e61fe59966555ea5654ab56b776cd4ff7dc57ac585c4e25ae3fe74faf2fbdd63cedb5f3cd55864bd249aba59fa67e23d4a69482716c149665ad6280460d2b1dd05001bd6794f92f95c5e72f578f89792983276880410a315e0044100f00f5a0458c2e5a48828820d24d2a29630bf06782fe68a33dbaa94b156070f91516fd412107e030c0b22ccbb22c4b5f6c05853603086650f91d6444424b87d2af7493ec1231371e3a9115d4c10c2b550445e9a2052782a06045105a507141961b74594111c3181f3420c443c6c789225e1c6be3e7101c40fc845eee8dd0fbae7b3738c2f42b7a487c668ff5d6a79164e734c723bfde03e10897922b2110257a42204a4c7ff905ff6e8ef97529b97fe3b6619812548e7fdcb9aece03d6f3f196c8d4edb99b078e30dd676fd6a3e61ff4826473ecd9f3999f1d5b6c643dd4c85e16cbde4ef6ad73bb772ebf18265dbbc71a793b56c73f057923e52712253dd6633d970f2ac79fe4f0497ba747c9fd6b1ff9cb731dc7fdadf083c4e7fe759c89238e2439d6b3c447498ff520e0f100b635205313f3e8f7835e50d6fd472452c42ea6468eff682b991e9218f3f5fbf913029fd3fbbb7973ff6d2b997fb3e821b18e1df75c6e824cf1902938bff8c59bb37bb1df8d33ef44e55c8f7eb7089d1950fe835e86ccc881e8f21e12eeb56dae49a6b0e399a3f74c57c111a6f724f9f9b84dbbb3b8cbaf5b8f8eb1f1589887197679286cdf3530a2879955e36116adeb77ef58bf8f8a8ea9f12814ee63693c46f4d5e1c7bdd9dd63fdd3ad647ef40d02813f575668392116204d431c7d91d662c00b1988d4b8428b1d6810824b0e788822054b932862e05083a171839f1d8010e20561644902076c5cc08b1b63e06042081aac882105859d317f88641451c1c40fde00a383a124b4208206656ce1820e785069908174c0172c80610639d0c00b193f33c8e2c50d4353f0408b1e80c161f4254a2f570011751737b4fc415b6badb6b1d65a7ba9b5366b09848da3852b3de80086052ec0f123a5063f209185162a9c6871c50c20e07863276d78ac8ed837d75abde4e06bf52b53da8a71850c443b80011a446704f94c8f8215384059011c64b67811a43a1cf242c4d75ac6d7ea2abb5756340c423b2656c063d92aa5e3482caefdf1ac542b12a853aaa7432a7e4ec9856e4b8271c50525de5a99041460f8601404183108c1eae11756b83c01860d164646dd3cab7ff20596eff170e80b32fe3e1cfaa24b14580141e86b1583944db084d60dc2e5891074f8212e4cbcb5eef2467af1d653d62d4fdbfdf1acbeee6e15d4c3f470884b94cf1e0e718192554ea8628c51084e1e000514757aad95ee54a792ce4969e751d9bd431e74c6d10412d4a5748c8bf7b75ef787391c42f795a92128c0910792eb13dfb27c4ebb3349f80f96f1d5ab8ef7d671e6bd5ac36f07cdcfcdbfeda74f78637d6aedd3ad0d7a62d4cba7ce5098d50de004095fbd66afee0108247ef50f4020d4eba88ef690d48f7cb44590a9cc39af6e82bca9ce7999fd76bcdd78e6792714ca396f2a5358522977249594521f5634dd57a66af50f0ad54aa5bc91d2536dd198576c5f99aa96656508643eacd7b2e0fc81937a424737c0189d6309f1eb55af65d94d944981e106ae4f2c5344b1f2a787534481622d0482fdca21d7a7c7e96139e398fbe381a4fac497ee40be1d1fb78ff02633c12df8c3347bd87bafbf7513dc6a3b5b45bbbff9d363f4eba7ff72e9f5a28123f3c7e87278dd8458c20afab06ead9be68fd1c6993dac733b3369d81ed1b2bd61de1ad0f18f9b47a6ac1fb1961540133dad47ea5adedc7bafcecef57cfa2fb57a3eac68e9b56e2d53f6be3d226f6ee48e1e9d114eed4a7923f7a7daa2b1c55bcb94f54b712090f9b0ca16e211d9c37a0a0a1ddd0063344e2c21be7506c81be9d68ff8c89bebf6baf495c4979a105e58a194d22ec8fc473f9b0ff350fa10b18b20c905981985a84cd1ec96132e6c9091ca2db6bc94130a9e8ee97f165a7afc71f97424d531e6d353f226fbccbc1f36bf367f5aad0bf1cfbcfa4765b6e9b40295b83685fea710962d5e26d1241364039421a85cc9c285bc91ff73f39844c9ea06a467ee850e9f397e80f5babffdd8a9cdae4ccd3b915c2e24caafd0c787613604058f339f9eed4f0eb1407f2bce3cec391b32a9c8542753d3b33dad681ea61579837dbacc86d43da9c89492f85fa45efc2122f4c2c94bbf598e8e2efd3ab67be2bcbca9041c613a9e114638ab56ef878279650ac111a61b000efdcd29532615f840b706f14d339552a956abcbafe3eb5e97d3a98273b552b99b4c73ca6bc7ea5dcbda57a662ddd029ce8cf507f29aa0033002e451422afa90fe790400804aa656b38704e613893ea41b51027a160f739029558402bf08657b0920f1d2a595e82345005da74b8f4234ff45a1b8041c61c61ce44ddc02a6a4cb784528fa9051083a68c9c1cb88e5077004e95f44e28574f49ee82fa451f0f8710b1d85a2df1b97cc1f4edc994557ff68bc054011aa4f0f0350840ab9fc40a915caee10484c0115cb45883983945a6badb5ce90af961884be56d7b5d65add30c909a440ccec01ffbaacd51224c55bcb456ea1801d14a0030f3f2ec0e28b1e9068a207576af8e9610a358aa8c24416451405d1a0e9a005530b563bada773a7819e52153ca5b40d6b7ba8a5890a2415364e2aeb74e329a59452a7944eaa0506a2a79452ea06b52ff8f03b1e6a81818acf1e6a81e1ca7f3c66955a73b0af8e44f575f76cbfa7b52b36b445e57c108ba78e44f5742ba133479f28a97843cc5442046178dc79c52a0c192d2d1069012253c6b2ac1591960fb5bc30037ac9e878a8e585175c28e3081ca74422a61b419429025383a11ab058008b98184c79020a1b64c041111a3b69a33a7cf2558b0b39ccc42a6d6ca1174d55196084570b59f46f8a2053d133ad93526ad93a551044a662f637c27b6badd6bad4b275472804e1cd1b4b8c6c70ad11c5c233d0489941bd82c043145b94f9810e52e87c2173441718080141086130a161040500a740ebc10a013cd402248516a026ea65467e034724b6f0a18b21aa2ce1831a43245001032fb230c38d2aa87ca942bf1c41c2327060c8072b5f2c61460c6e30821139885963882d6d30f105caf525088d83f2432d40375c286fe44aa7d40fb50035c1a2080e27454429a874ca55ee6cac1405e1490f878aac0ce0e150510d454ea2148ca54b9fb00d1b967cac8ee14f8f45298c3ab188e8037a9c22a5c8548c9e742a32f5d363410f3af52035638341b2e7bdaaa2bffba6ec356f7993737623f307cdb57a900d66f90f474cc62ccb5c08fc6ca334dfc97c7ab6a76bd9fbee7dac79d9bdace39fbf6c154343e6d1656de20179e4ac3b13166d0209ab6bfd0031861551ae58411b29a0f2b3831a889e18834a1138c08063b022e79c73cea214fc9cb368869f452e14b930c6972c7c3066074474d1c4ca082c9a5083075a407181172d46b8c9c552d0268f238c50b6d65a1604b156eebefcba6b81d6e2a8a10c910d1a067a07bdad5ca0b55799f22a773663a69471a28c0f9ce0c764b8d8f8ccab2e1a351d0e9501fae93892cc1314181b4aada539e79cb3db7cce64b8cc596baed633efe7b1e9e14c4a664ba482318d2a9091f2d971a496d06fad28d4574791794226c8c6e6abdb809164828a34b182cc1ea8ec70680c97cf18e6d8c3b02b4b965d598673e699e30c3b8ed77565d975b18b79e659c79eb597c8941c1ae3c4679f3241988e99b23dae37744f2db71bafc0d03108f75cb03242702fb3d0e899dbeee150991b5414c0292a2a8a23c80a3f491415151505d9b09b5760e8cdb5ff6098ead1cfbce9dd8f9ef6d8f61f0cb3248638fe234151d1df15183aca75ede1509920f9df098a8afebaa671dc57e784c8b22ca3de860c95874364b83ca6f2d871ce39e78dc27c277b742c7bf49cf9cf4fef5ba239cceafcf9aa61c79937bacda33ef3507147388275383406ccc321324f1ee3aefbea5d991bb03b7b6058962b01d7b56d5f7d1b33e55e1e9429ccbb373b01d78d4a017e752199ef54d73edb0f46a372b4afae650e87ca04fdcfc7e97d4b7e7a963d7c79f67e1e5f8e33311f8f423882f5cf8746384466cbfb64d2e60621289272861b53ccb8e2839429b240624a0f72d8011b4b8c6c70c5e1658791171ab64aa7d4f170e80d1e6881a3935dbc9066a5538a69e34757586cd269ef755d1cdc48a2862db2604283252f0083862741b8618a1a8258561853dedade8a3578cbb22e26c6cb1b59bca18507537653dc614201c044dd5751ac5e302446085bcc392d6b255324c894c9c67988d1a2d2f0d3af982a6c151f8fb0d838a1052e9a54a9a2840e55827c291d60086f289db2040991c48f3ef2463a8d3ee1fe60065dee19c3556badd7c216b6b085e78578ef78979aae6eca4bdeeb4e39a5636a37f5697918f66f7e955f1fef8ffae53893524ff2f3138b96869fffa2cbcba43a9328d19ba482bc108b7c0751162310f85ed8437b77a653192b80af0e4ce50f18048a71f2d0f5096bf98349944f7a74264d54d49b78901762519028944a00c3287504321dba06815c9f1eeba727f9799f1ef83f316e6055855ec99bec32bab4309f38af92d0d7e15fffbadfc93c3b99ec77e6bbbf8cb397f9f572b267fbcb3b9663d9837f2d87d9f572f676e2b53cf32c8f274ccfbc09339a4db6ba21db106a834a3dc156cbebb5baeeaf3ab6722cb7fbdbb15e77ac67cbdba95eadc3ace69de939da35562ba17b576ff70e0d010f1e1e2b24280d010f25f5727cbd7c7974a5047d2af38d15ce20240413a12b5b34c9a18b3156b061051358bcf0430c300c3f4e8ac0ecb0450c9330c8c0ca782022c1819804b7c41258c6a082c5081e803e2844001eb6bcb065891db06012e4d30f31131f60885e70c118685cd1220874c8019fba8a62e5031e3ee0e183f959af5e3d5eea365ea7318ec1e4fde1901a4eac11e6550f87d658e2d5a09286105c7cfe925b60feb2e1c327e0e15098327e288c9530367c182c8f3f7aa442ad37729cb1e7ef8b54682cb7f6e783f717b54c277a9609d1dc8af0b1859dca14ae518a9c734a6f2783dc9cd8a5c43df3776e11b184e938723a9973fb938f638cfb9b59c9bfe8252caf67fecded33bf98e18dcaacfdc57f80e5717f399647b73c4ef9f1f3d17226a4e4115bd3ade5df8c97fc835bac6f46ceb9bf394bfb835b8458be2375f25bbebf24174cfdcc836f3f2b4194f18b5bffcf0a16de5fbcf23b9ab3f0d1fbe65b2f31fd38259660f9dcf1f3d93df3bfa865b7a48f741f392595b718bbc49a7ff2c373eb681e3d468f994efde8993625fab0dcca8468d13b2f3bf5689c6479167e9432425d878f39ffa293fccb9c34e2a28ffcbb2e1f6dd475ceadc7226209965bcdb34fdbd6a332a5f7b7b9751ab84548f41d4d277f8cfb4bf2f396679e3d4af158442c017ea672d5fb95e02fc733c72262095f7ccbad7f7067ffb05fffa2dffdc12d65e89dcb2dfff0f6995fdc3e33ee3ba5f69de0f299e5d4bff6f5e85ffcd68e45441f9693a31ba4d143501a3188210d19888888c004115df125cbf645081a5dc34b1959268307326a30925dc8b0c19201031a75c03101033298b8910d418c209878701a020e66111b51a460862ed628e385034ca1c50c8088630b2c57aca187f042015eb03588e942c61562bca0050d64418318c634594306431843cb0606e78213555401c2105f4451458d21d8a0650b2cb6cc80658c318618c3881adc821817ca983266075288a10524830c942d5f829822ca0ac08cc1c680610018c8823143cb60b408a0c7a894ec58697b54a22992008000b315000028100c0704e2a048345104618d0f14000d86ac465c4496c8434992a3280e8220838c318610000030c68011a29aaa00039f1823b94d2ac8e3268fb87b5704f3a4a81cbe53726bf858d72aea26473eb1ac9cc035a4a344a3fcaddcce27437683475e62053f2c189b16336d4f9e4c8a7e447a15aa3e5f8c3905fb8d1a45fbc2a12e3e1a5c03f4861b5928650aa20d2ea9d1dc7d4646ce8f1931fe1cd2be5387d46e3be50f33ccc229fa8d33d5710f3850110e5e9130d003a55185ca9ab1395564a381110c0d934808078c409ac9a509de6940ac06ff877bd58966e2f602187c15774ec2234ac9da36fd9a53ce34b481352bfdcab857770de765402b2d1d2346da004edf7138dea768d9da0dbb2da005a1b2d1a74e87f83c64dba90e819e9094f5313d90443818ed25a4cfe492fd72ed02f7fc263bfa71e07157e53cefe0ced3afc2e82ddb3bd7529be7be3e7f7336d37b9d8a70c06ce5b1c4cd2e569945407473e7d1fb37f09625b94c085856478f9626929da91383b912483cdb85b46862977a987422d9947cf46f7d670e033479b6b6a1d2472a61842c052ace20246338a47ada4cae22b804fe95aa89876f93ca6d29d546377b4fb72fad513738f95c92de277ab5afbb453e923c73e8ed287592e3cd046b18d9ab950d7dec7ed8b31f8789d0e60d09dd6b1167b734c9d938dcf66664b189c82f06c0b726a5e79e6168d9a4a15cca1449ceaf98694dbd97895d1bb2b82896b674a3c0ff23ff94e7b800f7b0f586f545f83f53c002941133b604a104fd82804e7a31ffe9721fc7647fa38912aae06ad6df3cee9dce004469918c70d2c5c6548afffdbc755def2d11d07d0e9c3dab29536b13e70785c8df501b56c3fc4ebd193ed9733d9cf5c63a7407f1b0c04b193ff9417817b4f5b0e2071b8a99ae7e1ae244b9dedecad8bdd6465064399b70320190f26c3024b4333e539b1be799c68b285b97394ef6bcce8a62c8bf08e3e40443f174448d44aca8e1c209d4509f5736f043385689fbb11a5dec624e1856f113d4f5a435e54438eb6d0884e4c84c341a18cc6cb0db72a1da719dcb9a187a4024a841aeab3153d1b449197c0cbcbcb7694ea62eaadb2be94cb43692b4989f5e3020ae7200ce451124fd4877877155c5447aad2bbb229224728c184e6515e846a1b7ad33657ce549a50efdd0f8d237f5dbf3818d055c8c51f9f66f7e2585a9206cc71145f662c9c998fae43ac8471b901518b31fdade91da2e45c7117c67d525ea4320bfbdf830a2dda29f18331364c782b216fba7f1400ed49d77ba9151aa23429f4a863c02b174dcb380a1740be81c8e2ae4b98cfb7dcd48dc8513203a19e416a887185e89b60cdc2b9c748bc1fe719e195bf9236d04dc83b6fb5da12b709d3a505e45f8acc43561e83a9e764b6ef44216eb5d8edfc479f6adbce59015b7588cba5a5fc18545385ecdb33375a56c921a56084e06fa147ab255c4e5f0d13adb54f02dcdc3336c356f6e976f11ad87ed693cbc405437b718137394332778ac56447d5aa6fc70de531b5d6813a8720b69e68f9636518bdc5a08b40fd52abd8ba3ca6409a94b477f83f750cf4f2ac519eaffb84146c07ab812728352ec4acc34d58c7436e73c787a70c7a5467bbec17067bf9d0ef9db0fe33e146e6870145b2451fa820a0cb5467fe5fb3e337093856f82965792a4f5396b9b437e3801780a665826717f1a11d3ffe7b03f3cf107efe1011c4177e3bf3eeec122d9fba653e2679307fbbc4e7e86385c0a2a65c5534ea0fefd010c9f6a89346509bceb365e7aa0fe79191c61bc3246c6fdc2bf7ee247fcb0bba5c9f0a3c2db71485e6cad63c7ac97ae7f839002b11979bc99e0348d1c27e10ce499e76b709a478d2e0e31f9ba91954eae28946c67b9b4d255f818d0690119c54c01031ebd003b722a5e1e693c058bf0dfe7850c532d929de91bae65c27a265eea9eb39e9de98075f740e73017444794beeca0fcdb485bd25f6c2661265907d1b4a9727932ef457232cba6ce00d8a5fb17bf28ae4dc143959d2a8a1f8261ff40f3c044e490e33fd0c4410863ee52039900f99a14da88e49bbebb57ad6006bcbf59c5403f3eed29c0bf28c12bdeb00a401c7e96d630c952abf2873892bed1f6160b818c47f6952b2c5351a118ec10ea45f6de4b9ebe787449c238d86418fe86a123a3166c9e93331d56a4347602280866dcfae88eda446cd41f880b3ef525e9c2046c681d4d0eae7685efd808ef29553b4dc2c06077827b5f9f8e2727d178bf77e05aa71d663241db0017ac03357ac52f8ad9e0a2bc53d28f9638a5bc2dc031c0b4acee8e20e6d13e06363931d9e4c034b44522d90f59042e126161f306bf3063fb3bdffba539c78bad5f3e6fa53c44a86e88e1cf00386b3342b6204fadcb0103271e61bcc32ee3c38314830afe5e9b40d521afd279e8aa4f45624282be107fb515526898e06d38f78a6e2174dec5d8bde1375b0aa9e93473de9e0d922fe10c2a610167e94c3491642718575a54a3f93a8b1296cbfcd0e87db0fbabf47073e1f2b3055bc514c1546305c04077e13ee421ab01b8ac005ac8b2b7d3d8ba5c3979490f9cc91b73933f27403a7857d4ec315caeaf418e9d22db18f9b4016099a9555c56839bdcebd0210ad45988c2717db3541cde2751697840ae7e0006492cf11c85cc3a4551aaff5d2974c503ca7636f21cb18853f1bef98a4bfec681136eb82273cb902a7ec7b923beb96b9ea03afa1fc1351347e89d3b7dd58d635e50202b7e07ebea7494ab2b8e4d89d893311b079d856e694cb8ec0203ca7214ad44e4aa7453653ced2314f611ba930825f973b147f2310675270f7018eaa2c0a2e0289c88efb305defcfd9a544219858f17897e68528d516f21c623e36ffbc6dbc228c99d51ea0ae4b55726a792f60a85a0348f51cf438d861c98338bc11c28ec8166f1f7a0661b54166ebc45eff49ccbe98994ec50b2806dd119eda149490456eb4224f20c18b3ebad9d9ce7ba0df72b2e060e66b9e9ec699792ef190d79d9e0f96c1456bc5255bf9c9ec81eec4bc950c156f19bbe3d4fd446a1e2cadad6e972e9ac7ca005e762ecd673f15e89cb376ba09a5f6a7f501cfb31d8ccdb8789a97bd674e7063c0a1b72baac6ad5f1e0bd54afa2e6f304b63295e1252f0008a61a804471eaeeb928b72fde07a1ae7c2983085de0946cd5c21d2f45b7868a6bb9baa4f0c53ab68dfb65ab807d37dc9b1cba02564677c5db85ceab9e8c1d88c83ee417079918b624b91f8462a90b78b4c56e1344fa7e67ec4cedc72497988d071ab572187bcbdbd0fa021f7874ac1d145d9aec3be5696c3c393e56859d4987c22028f88822996dcba3db134586fd6e5223b5fe697944ca6d88f99f2f788076aa4b4da52f622ea0ff83cb5293239ed283996b04efb73026d7843f245a7ba5f3b627987cb16b446ce6855712b7a42e631268a31e68f526e2872ad274469cf99a749dc0e7cf165e0941b8eba1151e7f37979621999cbda0e0b2a742809bf0d725528e2d14c82a3931ac2f2b2c2223ad53f33e83b65d16319d2636357b3310f2429c84654967aa70ff8e4a5ed200840af76b3bf2915ee11fe3c97d1083d529dc10792bf9c5a97e2887a99bd1e1c40af9515cf7abc2e0d915155a87a2bd99366216c1066191d86c809160a3facbc4f7822a98bc7d58b918c2b80308e13592fe825121cc641b44884c18963e905d63b2d730a81ce1afa93dde99bb35e6d30c93ffb1b910569e0bd7f0661602232491836202130a909142265b534b967d68514d8a37a95606f82a89acd01d416aaeca47cd62f5a6ac1ffb9d615b950b36823a6d1138d837dcf21414fd2f1e3410a8d848a0748f9b1de5f5203b11b47c4a1049bbed1ba7a6c11db24da4fdc0a7b0f758f71da20cd82da50ca01ab8d27dac46a937dba07b00f1f42a2c8c4acba53f82f6e94b0220ef780131f0c1451627037a0783171cadb8b213f2ff31a2572c75324504df087237aab7938c87a39d94b2c86d482474c0d3f19ea6ddfbd15cead65d4a048ca69b2f63518a04398a8426825edb61211fed8ae39b6f18bf0c59370211e4f61fde23401b2fbf47b69ee94e8b871c6b3b3af4db3a91fb37ce23b1848292c8dd7000cca8ca00c994957ed230e52fbce54d1ff64545105824354e5b6681765fd11dc5ec23c1fc85f29bb85a722a05b0a6e2fe7a561f7196ed10a5e1847572f41450fa6a514dfb129f4ea036d3208e3bf9f40fa484b4c195de4795979a82a9b4c67a8b2c7ac82061ee2fbe68ffcf76f4211cfc579c7b7dda817384094b52186ce5ca42285d9f3647e51be712ea36b5b110fa11adddfaa43b4782d61818212c3e41c27e006128f80cf563bcea0d6b854035890d223746086434211ca147b03ca7fc09625cbd675fc63b5721bcc084fd703d1282df77408e1b65755957c7f9b83c2565615ab89ec422211e90b315ee468dc2aa176cb60e9603a7e805f6048c83f2c4a667c114307350bdc35da112f3eef64d6e0c9b574688a0e431c17c872a453d798ef3ccf34103ebb8894d8cd80bf84ddaf9d906ba85cad68edd501f894c41f3c075738db4936df7f692a71b2fe6b960dba4437f2ac1b3835fb96fdee833b882379cdc3f9f2cc119d052129771feb57a3699ed97e9069e06187206c39825fa7ca874d582523d0e382bd59f842736840e53936de1e9a3ad7543d0b7e540695834faba561319a9895d5f1c7c15aef1777c945132d0c2a7a58f06d75892f4a2a9f4801459367559b8b1ea99c2b174968f897c63a9f2ddf6af978894ceee69105b43d04628ff2764c1e68e7a08082b5fcde876acd93ed90113bdfb7f5a566012de31d56036d438f6ea49778ae8a41fa48d913c3ff3fa0006c5a93eabac45c9473c7bb9be5a3853ed69330e5444ebc2e1a4d1ad2aac5d9cc9aa58513e84f6512fbb2a1fb718a559b9ce7637714d550855a13b03277d279395d1fb080ee6eead4158ec8a8d92ae07aa944d043d4f8d5c1333c877dd4a8435e6700319fbda60489b87ae7f2c2cd033325c90e52109313553e0618ceab8201e000ea25a3f98294fd73a48790337ab1dfa05544da19781eb9cca02734e5ba693a5b39a26e6f2ff2dac1e6ea710ab659793c134f0acfc814becdd13297a9bc22476cb6ff839838e32d72907b0ea7ab0b1d6f5a6d9c3398916e8b4b2083e6ca60a3fb83b0f95c96da977c723ee6d7b4281952bcd0a0e6826bea356c055af4b2ebd10354142a33021a566ba6aa746a3fa628b798287cc21879179e362e0b2680d2fc36cf901c1756c2565277891d548ec358e6c53631b9cb4f182dd7f41e3d14c42299c50b8895414c7642a05c0bef0e381cc7794246023ccd833447fb1fd53207f806ea244e19e244918c8a459635b0a83f4621996e47c4249f1ccd1a62f0126d0dcb82597f5fd4a5632391d8a4a911af5243fa78e3f579bb608553466b353837a25ecfd88fc00f4ae6a167c1f41362f86a6a70f39ce55f656fd8bcd017f3024e2ffd9ed5d729684bbdf99e8027a9a8bb92931d6118a8d1556ca44a7a0605d8fe22925741e225916f338861e3afe718d334a7a45541c0537768f284672c4359cd7846d166fb1c7315e1b73c6223c90689bedb1896c0f974b5f05a5b40209bfef47630454d670b6691c666b623ae22079fc6a4ecf5cac71e7806c83d4211ea373b0ecab653bdfb5bdb80c6b7bec12d4481dd40b006a908e766c4310dc6edbc2d01a8370af3c354e16a8efb44d710937fbd17e7ab96818340cd9e7d9664382bca187a864b7c74b7744e0d4c5422d26278c86ca893bdca530292b758207ccd688b839a0d1d54754acfa498a93e541fae72220640beba3a8db0b4cc12721164477b644c86aa925bd5c79a0eb329bcd981f49e9ee692b499ff19cd7e541de2b34934f0c358260a9b178adec37566c85164c57d91b3af6c00f60f7e060420448338d38c61e4b58aef30224f930391fecb7d01393418217eff003e66c3bb5ced0ede21f42201f7f49adaced743adf156abc5cb7c465adceb10c2e87d50c644860e5cdf8c9e67a2b330e32ef0e41f047928ebc76acbeef17f7800651fc22a49c22b72885b105951b7e3d7cd79e375c01890817c30450ee5ea420fde9e5d7d14152c423fa63e3d9bdfecef3f02015a06a1f0f5edb978bdf72b365222fadbc4c4681c66d2230f910ccc370965543a75e51448eb7955372bba3d8c94e1f176efa7597db98f4122bff76fcb13c2e7f6eefcb1a8611074ad15da4599ebaf496e226b58a9be7f688312bba5045c30411ed3918b6bf064df64ed379b753f0b3f4900c189e9cb2101a0478eaa0605d84cd75c61754a9c9868923e5884c3611437b605c0d01d04bc4ae18c4005d97b0ea5cce17cc7048ee22aeea0f8ea3f69229caa84930fc0d36aa3d9d172f6df2818a68032b1632a31bfdf3c5f3c0a157dc7f23eaac98ff36ae340960b79bc65509fc6396421b8e0be0e67c057c2b5f76642260b5958b3736866f6fdee9baa1957b088a74545be7c35122131aaf9c474c380758a176592198424c17a2c0b7d7b14d77132eb10104da8e876cfe646ca195d4a406a9d89659f345733c4ed215c4f5e493f2ae99e119e96b0f78831669fe98111f26fcd25cb48b4e4d2420162db1c963bf62a6a27c6cf469f39fdc596cfa8a78287efc14533bd03c5d3ee246773f44053867f4540b9fee347c2272ce8df9b89571c2af07c7e11363f80c03bd4eaf96398cf3659df65b12532b4b2c0ee30c56da1c807bf85290eabb7a2879de636deee178c9b402640d1eae576f2b2f5dbe68a7783050e4880d6572c0a755d55fb75aa1ff9a35a23f2c007d9df33e3752f196c4d4fb6f37a7b1e05b2408d5fce6abd37affa99f23ec0bd8f80a129f5a21acd23bda9c025352441eef41dee22464765bb23e9fec3c7b1fed0a9cb29ee8414e69f51bfdf09f4283d8e84b8020c0ffcae4549319a6609d0e2aa8fd14004c74ac2d304bcd131cf7accbd8310213292041106a26bcc17cc2c8040127e07cd01f73da0441cb4449184c2fc166b027db817d9d685c34326da02cd96725b3c84bc7088c475f4c3920729cf04d4f52b2ff8d176ae262e5fcf761c30f8a534ab1fbcbb35ee86f59d47e03a9e31e8a2c0cdc42283c89d20494e6debd65f0f27ba8edf30b974fea8e3824113491c02dacd467592aeab635e2d8ef468c9489221b0f2071d6aa72abb8bd7ae30cb26075d696ddd90b6b6613151221da8ea4e743dc19c3022b3999a016a1d2bc2b272756e50dc5bd2404f6644eeb9b2acfc12acb76090ba18e51d4f609878261e0539eb4f83b71f03f07ac6e3c5ac0234c5fdede76c757e24f8f9b83918416bcef3a34485c869036290d1e4fb9361dac39bf2ecc2d62549cfff66ab974183b7437a6001a181dc6abbf85000d4d5d3050fb645b6c3028f4969664b060d88649eada547d47af2b4aa9cf108b672bece53a0b3916e9db10b464f815c16af87aebf10614868855b02de5ceaa972a6827c92ae8d24346ac02bb60716eef7b9cbfad0a14d44f659b1cde26592c61244109361a9087a8e56d8d235b59e0a6fa2215e3cc31434223f545706aa4d33e5715b089bfec261a74c174c6126acd404eb0f120ad440f19801a244620de22b9157de6770799e2d14d7d6689b350cda2d2e68dc18abd55cda50ac1083032f63d4c6bde2a739d78b76f154b77b408ca11438bf530768e8634800da7c1cf4af1092315c830d9b927aaff7e8af2909a9f3c878a4feb301af84a7b3636e1d66b1cee486af54167e4e28fd4232d40367e5b5dec1deb6875c3b8c4036fb30389a550522d19ad1f7f39f2ab9323a3c5a9014e4946d000e30c001a88d51804dfc0ea1080fca7a294cf1b211ce5580b03ed6dcb495d13ace3762aaa624e4562ee9870a0cae20fea4eff320fe4a1ec31a10f1e1fd1e5efa767bf04f09edbf8876a819a5bd959021c7bcb32cb50951175107585e3aa8da01f4f5a1f13d4c1bb001789dd0904ed8db84e342fc96e928a6f7b68d2eb8698bed248183c4b7343f4e75c62161478ce76d00ed448fc2173480e9868234e25ee0f550ff56eef54b9b88723e096b540b140deee623f7478468ccbbb6e2d6708256c2e86b87537728ebfea361dec0fae36785e1985aec39aa15ea606e8b529200bd11a3ff82b45d27bdcab7e8681d128c31393160bcb6e05ef29886313d8bb4cec42598c61ac94e7772c9cfef41952ace35db1b595f8ac97cead2f35f55046bec90714284de484a7d61e6bf2d219556f0d6f4a9c9baf76ac535333c9945415ae2b99cd62d54d8367d5541ddb8e19b8dc988a18d4fbd08b71048333bbf05e3837b89ffd788afe89d5b56e9aa3902bce89daa8b52ab9692e47d51c3e6aa328c2b6ca110e5d6905f01d8cdb8685c30677a33502a3863ecefaa028f9b5926529bd77c75463598023b404ae79f0db08f53a7552d1227f2611653cf7b8c1dc0a9414aedd100b9b52b7a709b00e6f9b3230ce399c1b7128e15de49aceaa16aa1b11ee5fe11116418c91a786993b05e1de9ace5177cb029dba0a51014e045cf98ceebe242b57d116cb28d9bba35e541f8429c15975b317ab6a2be68e4a53dbf86cdd369862fdc73de35f5bfb1b82c4f41f5f3196ef1024c41acd27fc111866cf2fd0876ea3ce9f6e7c8e7cf05b9acbf6133bb9c3f11ecaec6e0181b22e634177cb0b9db9c049fd4f98fe0ed52ee4356e1659cf54daf5d9424cd7590b153f073436104932cd44c35fc2f8a35343e7441e6f7427a2273dd0c174493c22540f60414d730403c242b00c7b22f7d951a7faf161d8ce8cc7de9ba529b30233ab94c83e94d7c3cd207051fc40d815be964b42447d15614e9b9cb1a6939e7640de8589c543c2a341075ab170baf7ec84f0703e85248649c10d9a3412f26119b67eaa750d4af7bf0ab59808ec6e5a814d6dfdbe84d621993d81838231ed53998ac150c3deee04e25bbba7560c570013bc73742869b8ca9b3c6cda654f1aa415ba3fd95dfa98bb88a4bae07d27312a44874835d4861f0c7c8cd94df4af0c30037fc8215dde890a4480ec5153b7278b5a33efef47690e3c0d6c1417a0b96e4a22bea87f86be2860c8f8fe60d0b19f31fa2b88ed8909b81879f75ba7953e11d4c740d7199ae2f5bf9321b858a1a412fbf35bdca0d061b92b91eaf7f87442b2bfb89f49746f373d239d1407a3cfd2efc730be6efde274ec6c1a56f04666a196496393e1c45fc8e4d0101aa1d3944b55630e5a06cf1c0d87e41ad9a654af63aeac63b24e514ad6071e4ae70150ff82ad96fb9d94172736a84c1c9652501e789a16546439dc8daa8b6bb328f63318523ed4ef0cc9e9d22f1d809321c92eef9b1768c894e7a2ac47336b3c7b5e91755cf149ad095f888998de30b089f94e23e8057036ede34a5826a22d631458bbfed52da1211876850c9bdcc15a9fcb31c4f54a8e3624861708c4c2654495af97c8ed6cd42e2bb4d8b8eca261bfc8e3ed9373bf24507b54d37b9cc2c50e697d6e96434d5f998375a577038a52f6e65cdf1da17c057918190ec38530bd320c0cf24b52608ad6ba6ded30adec8a7f29fe73e5fb3be9460b6158b119c3af2cc8e4b8a77b1749f715ea7b9752f57bf8c768d96239283e7ecfb232c6b65a8502ba5687e581fb2079a25b812c197667e5f5dfe55a1d93645ae978f7a3543cee8a1b49723827115692d46e6c326a482bf436f13dd362a19824dc02a5c3edd58d42ce09a25638cb3cc82c0b52c02a3e9915f0f6f93138d6826ce6e82fc33ef5d774b5de121eb40b0c9c8b50def79bc9aa22571eecb1c3c9b7f17e8de82817929acc48cdeb1594f463068018e6271f6fdf29da154b7b06e6f32790dc26e9bf956567d1085fab6cb94b04fe29479ab8706fba8cc3526a64214bbf6a45049d7e4f14734709ee4f646606abcf264799c51a18f9606371228692bd96e775c1d75a044006b1002a82f996a0d59d9e124c838f3178e5d64247056736b685ef655c6d05a9a490e596a8a2f07c31d1ff7bfe42acc004bdb838ebbe80e782f2b814932d3dc55370a2a7754b50f45455a261b4e27236d27971347a395a1eb73c568e240964085704ece9fa0817763860df65903144b098220d9673b09677589cc5d9040b6d0d61e23d89b046a10e4905858713a34ff5c38802ba2de40593f56fa7c94c94b061eb84261aa67b2b5e1120e78d2046edef9575d32c520556f66f5e63f7a27b722ac384d77055e302e472804f03deb4b2f523d4c7ef352cdb3a0322c11fa2b1a1ef2819753f69aca06ecc3d3d3b4fb47a50fa8cff79fa194107ff1a5dcd15d15b6d41eef5748892a6d7393428bb3a0b1f9df8d06e096eb93adf14bdd64c44cb09236aae021ce6ab97014d16f80d5b1038f56cc30dfea65cdcb622ec9996dbd00aa994b7f0f66dccc41bf920769860a0fb9676e9de9c1ad0d77ea86ff7fb20ea03850f79cf61a7f1d9fb8da4bdaf2089026ba8c1a86c628a3afed53a224f8e6631016a2511d6e69f03bfd6ae2a6881bb8c4f8b0dc47edd464bdf3316990b809d875172bdab65f1e5047131709299d0c20c7fb1ebdc310c7006af14ec07f1e3147eebfb01c6618945bb4d89896b4d01ec1e6599b83f49fc6da1e2b64bdd1c0cd8cb3fc50280f1c91c7e22fddaa01f709aa36c809e993399063396b8a7de4a179bd847154bcedfeab1443a3eb0302622a7ff334170dd917e45c8c17063962909efce3342083aad680436a602d678128724f5b3902eca383843ff15b7bd270a1c97d7639f50ade783fdfa40ffddc2ff759e29c38c214cfdc7cab8147ea132355ef9547c816d33e3c6df4c4edb871b0a42cbed5f1ea911e3663cd150698fae3feca591d5e04e69dd62ba1393b47a622721b2ad61f6d86031d5d2c90782f4b75fc1517d2e0469368fd480b0e49499b83f4d5ba6d4c8bd2c65ebabfd8ea4c6356fccee4bb45fc9769fd3b4383382e00c82842e273f01f38a199d715922d4ef2c463228450b09a713380ad469fcb51817f4c217143ff348e687d4a4ef7e5cc25e20dd20fac68bccfb21af5151edd72fc4a5e78a11090e67cd72428740d2dd94749e18a5041dfa3db8a14ccf3971082826b2998c1ed19320cfbea8e6ad29ed830d1885ed51eca376e37e47dec735439430f879e107bae814f5547bfaf38ea58bba57bb5c96e027adc0e5dde5167858f0a9759431783f80668f38f42126ee580fa4b197746e93dee3b64e22c4a025b5fcf07507ef25c53b68da96207b543d9ad93c7041ebc5f3e71f3394c2172eba6d9e481ed3a07e4cdc65a3c6a804174e7cb1d309f7b7125707ed83048aa49670a396ae3d16c346a20d534f8e5d573f48b67b957c8aa101fe26d3ad70ce17c71d6d4bc44c9bfecff88000db5bb3cc71798965dfd899dd3974ceb469b894c9667b2b16eec7bce93282bdb5f3fde85a55f14164fdd7f57e1cf265b10481c10cbe7c6058fe42a754a3b024f7be58a41c39a25e54b6ade466e6724c7f50309518cbb14477d79d6a34dc6bc655af6565acf296aa4f52b02dc792c81d537f6ca056ed77d7134b1c57688e9f0c42e1e56f286b40c1728f1995fb1f7601d90e8af785c4ffb389d118c5e34e7b66882782d7557cbb53a01eea8b73e62f33bbd7009f8d7203ef964de3186130d0b78158e6e284a8e074fd4f9748c4c689406e7416f8f5a9107552ee1c2321aae286e7dcd26562bb5357cf2432501075af989dead5a520a10e4a12d19eb6ae84b02076eec3bbf14a67e494e88bd1970e8bfa64486c61a4c7ac3330b0321a2948bd088850cb0a74963060f048119f171efc0e5aa5dd4cce94e651702de9e82b49da578cfc3c0339f31840dc538d7c7d6ce254cceda2f07e71cba71debe72dea0c412cabc7fb2e748e0113ca52b4bceddee84cabc021d789961deb9b292ce53b178fcecebf0bb960f2e423ee3d9c4375cc955bf3d6290a0b9d1b8359c2e5e807e6a894e090ba8a4aad017e5a0a67926e39b41ccb246ee1d59dd25645ec4c1b12318c00a4b5dbee30b76b7f54fc80fce5c3c88599096fe2ef6a50fa49fd96dda76bc068f119dcee54987e75002a21e987ae2ea8b4eb06e213d237537ea429a87b4a2c58f92c9038dc5f65da661d0cc0ca5555a784c8aad7e365f9f97e79563434843a6543444840e31fb3cd34e7017c910440661bc81ad0ef10b9d8c1e1701f891dc11d3146c188525680e990f7c902e36508d3c7491bf476bdc1480fb0fa984e0b5a31c6c861c82e01feb40c8ddc1cb54a0d2c6b35241b5410dbdea79b2b9cb103ebd9135dc9cd93619291bae9350038f2deba387c42995fad10bcd1510b3c0544187635e95a10bd75caab5c3e351ecb31a51a69a1afeba62ea5abd5575f6a05f9490e53f2db65e53108771ff5d9accba1634d84dd9ff34821c11b7d8d93a4fc744e854043280a9223b6dae6088ae33b5dde70373d8010653e71962a70ddee07c74bf948c3d33a5a17061869a6c77dbcd698a7a842dab3149c477f409da42bab03aa9897b0f4f0624c9419d506f7dd0e7ced0426c92e97b3e0b02d032a39d5a870f2ed7ad735979b7108578d262462fb0911cbc8854c26296ee524d6f85e00da929541e782f947dc4131994ac306cd0911cddedcdcdedb117e0bcaa06cbaa4a736ae0555bbbb3e28df8f60f7be47775eb14e994be878a441ff892a3bcbb01dc258f6b6e7b86b153a12e4ba616f3ec16353597277c04a40db87e87e4330a975cbf932b97639e4d51b7da1bb5c50d45f9f0f0aa701258598af19a07287faaa7c7989382c6f6726cd67c526e74a0c72558e82af227634e103718d7a42cb17b38595301fdd967eb9429968f98bdad12760e66304cc2858562f32d56e587bcf88d26bd591c742d6a56a313816e90b42f1dc5747f58cd54912004f6ac59741af86a959532698e812112c49024e9fe6434a0455306352a3b5b8d81262e5fb869e0caa08d63061100fb1318921c6a56c4ff61281d86565cc5ac63edecd11803aad4abbd72cf2839938315ea38bd8ad52066880a8a5a08717162a260ba7596ffad46d82839a24c802e21b19e54bc745410963ef69bb2bcdf4a0003ae3c4094de23027da195efe49295430551e41d5688657e00c0a8bb9c18d86e04c675729a208ece20e2a5b87a189b0d5b5a19e93cb3d62de6dc6ba5b1246fd01bb4353a629759439d54ce1b2342049526f144dbfdbbc36bd00078335cd760c94546845485eb26e22fb100b7980b5813d505813d5128cc9ba18609db23dd639680447e98d773e5be0e0c13e9a589319702886bb2a50751cd0daf5028dd76dd14d02975c53b002f4c636187b0d470df5b23d1d5c057cd189b076842fd2c1a564effc64a964ae575f39a4a609e210c8be4e92f8ae2348810fd1a04dabc0236e3543501a83afff2d6919b5ce4067b330142294e329ca41236212dd2ff32e3808a998c057ef4210ce5114606b6cae62b9ceaeb2e00cd144ad62a46698e9352af64c0d4b83412bd49124928fb4b10bdb6e47852eab0cb23874bd12b75bf249a3f4e56605d1ef864cde00d30cac4e77c181e774ff252055d093bfe9ba713b13a26a201bdc4301de32a7a6436f77e577c22f51d28aff816f55e01f9de51421e79a19dd4c720e20d0ace259df63a4d96334c44522648f6e2b849f779bae0a7d320583a0935d498e68c249d589538d10915522a18e34550f77b6c3d65735a8b5ae86417d244e8193ae674562f6e0553278a0d0f472da5967b5ba50fbfae0ae8cda87c985b6667b5f2e77816996120975752dfbc6c2e24cc19f6f42dc6ad0551fe1c8d08068349c9d2af3931312baadcfaaa3c1d6c9e47201579654f62534e89b3f180d1f220a5ae2a16fa652359b71bc7831e4397506c37605c4426ebe5174992129080225468d863937912146808b613865702027697ad00bb0ba3519a3812790412bc8e36a0386f060dc4d76838015dc25c5fe0c080bed2ac646cddf0e952e261c4ddc269153b72b1728b52d82a75e81882e0545e2a52110d7b729595a888d9454569a4b5998b4b90f4b943d583ce73d6372c1bc109943c4fe05b7e3851acea9873f66d523e64365685cebdece42b39241ff0209e87121342282f300d4b6cdc8e8c3792642ca5e7bdd2616d8ffd4849eee9942bf916dd1d2fbabf3a8882443d7e87b2ac9d1f339daeb22831381d7ed942ea4b96e154ebeb1e2dfbe6d19b0d409196d13d7b894202cc539de8fc04835e946be4c4ddb9151e6bc295d4a10ac31afb4b9b2d1568821d79ad67383447b748b22840f5a9b2e111ff3d0ace8c9c374df49597a91966eecc5277caf3e0bb6774cd9f8da94951e871658d005316f22267c2481a2f343bd9209643c9688358bf749bdd3bffd6a3278a6469b28123568819d7c532852aa9e56bae2e7e32e1c5342561b1ccfaf6db1c797c346ba4e1cd53d29257e607f7400654d7f6e3c3358c05e0d6883f8f8d00b17cf120c36cd04cc27a1962c40485e365051b1d01cf21a5d46754888c57a52227547b1f326a2df4652712af31945c55473b5f19187a70ce2b6adc1be7cd2c0d0f5fa4c140aa505703f953c627b48ccde9840a46b2e8745646d426a7dfa20224e20068390b3abe4ee39acb6a6ab3886f86a6a064fdbe099dc7d0fd8c4de747617e480bad5865d720c81a3c9f31927bf8d1903c0c0c8cfb7f18db19b255ce4a5a328e1cf9a480d8255e42931d6c7da4825c8852750851493ce541d8cf518bea08a679d2b0a6edb38c51500c880b4118744983e3d96b02b8bb3012d372d557d43b7f7f3a135c0171c750f1116c0f62d988d79ace63b489b654eafa2b459b2898d89b4a535723182265ea2f23cedc1de0ab6bd3b5abca379a1e48da48cf232a50b4e16cdfaacee9fd8d47a5cac0e043f5c8738f0b4d9c10bd556222be15b9a8707ebd1c0fe5806015c9e2d103532fb71cfb8038b3a1aef3304d297ce36aa6c9d46525da6a37e95b64cbaceb57b95cfdceefe4a8877fc761d907152b68cd2c916510040d5cea0278642355a00bd0f27da4fe105610ddb72a408565db5261d2e50e76aad6d95fa7baae2038a43305a2bb54250144678a34a38aed40a2663c17e0d9ddab0f50487e51ace7d9a1fc215daf67a52c5554dedbda7c6fc4318e79b163fc3d1e409206115f67d69dd0251980ef373512621077ee73a3850a5ef58c828e249fdd93ff043c0424c0bf7e898a46382b9856aa89c8e44b10542d659ad030b0021087a5afeeba5e1de85ed536f2b54ba8ece3da03c0b2c655c9e65821aae91b58f0351ca9b0655d623714e692f5f745d6394cd460f6d0a1e0046d60c1b5a8fee02df72c2454327ea0e0b2084e0c17ed6db9642868735739dbc928d0768f9b14af09712b191dea92190ff61fe3c07129ffb175207b758c6b91178b1ac35bd41ac1dd585d2c6a9d2e202ceb2275e40edb6c553a1f68d7b645d8393e3ab347c786a084dd22f78871130d7f33b9fda671b79de6bf51fcf22fcdf6d7971e6da1e00bce1c821246fb92b930ebe7a6e849bda0768f06d8a0a882097f2f6348fe82e2b9ad27a0ca0090a2e51021ee4027b0c5e2928a379d8a36cd714f7290021b2fcd61cc54f1c926c609419a9d204cb66dc88e30653a207ca8b74595cc82f2f7d8eb68d74c6c158702ed1a6c24624cb3f897da21bb0fd482940c6bc560829282ff6977a891b62d346e6400a8b543b282ff6925534456f4850016199247914de8d54ca1ce890fa76232d96ce25d1f4b197a2f4c5e3ea56a3e153090906bb14df533165fffcedd97e5bb7939a59676cc4cce831e90b0c7bbb55f928f85da162e67bb587de32f0d6a429acb5a3fdd9cacacc9f7171399c10b321e8f8a60927f23e67608ada6cf725ff674c710e44e709fc1bc530ef7d0569fb12cfdd87d7f1334cfacf83497635ae0dd3781d92a51a849af6b47d85666c0072d9241d0c24833e3ad18806f0c6e2712e0cb06c00dca151ce9792493ed453760629790066245f17df01203158a60dda52ab8da1e21bce43263d7b9d25ce2c288b3a8224d93396e6aa77a9b4ca2d9aab28d838b45a63cb74ef7e0e8e9e4a0e645ec30998091c06183f24d132262f03a4aba7092669816089a5796368153748264b4374db1b410381bebde8376c723b39abd0a14779082f9ec5df5466aec92a14a61a9928487959399cb2409d6027425fa6fedc10898ae935794ec4d44681f1c730e4077f2afe59232cb0b28eefb4d9c861a105c9560b8b7182ac417acff345fcc76c3d50e5e5ebb25dd2c2ca625ba03fc33ee6790ee9bebe35f7306d23abe12439e24a6795104530db7ea958b389c1928be48f4b03d4c8532f604929f188dbe22afe853e75a7903b426346682b068946fda9a58d4adb2d1cd0909ba234bdc15d9020cb9f88102debfbb2596e2773e797d55404f00ac75d9ede4ef675a375cc8bc33a9702d65871417fd43dcfd561ab01d693579b6f3f208a549d19c49e44d5dab2df0fc45931e77ce8dc6e126636cc232c1ccaddf7a845545bf8ed59ace5f3089a942a9e89a9dd030c65243307552869e1a48ba76ca839beab4c22d93bb6c05f86e924678080e12619244e0ed92ae67fb14ace537a3165911655d5424279e241567da10bb6ca592a6c0a69fdf526672db1f2c5c282f070c88e756a52fec1919d870e9c815c8ef408f53f32bf7aa57510f10e6726bb3caa3afaa182456b27bf8de5180819f1b85e78a779e0ab21e5f5f71a01ed4a4f06e26d3f34c8506087b3d440bbec263bb4f53838b3c248c4eacc8a580c13aafae462372c3803cc876411c36f0a7c5d3f267ae0d40ea9730a5b229d7f19338360a860bf2aa0a10d1dc339b7926ad0ebd417ed18778f86a4b87b5c508a965e27031c34bf1308ce8c5da7ec95c1271a04671e614804b98c06a894e6276a2104c7b2bb9284c9e1fceac0f46f87ae3e8119d5aec66c488538875ad46174ce321feb30b535b784fb56eb544ac0b98687dcd2e2bf6ea176ea739ace974b33e094df00c3d3e1cc3ff362126587372e465c84b306035438cbe4477ca1a3f64c136771582b0f9cf1036a8d74ec05d13c0116ac6ac812ce62d1000566c29b5cc27604c06beb627b5b3863907fb3837a05d369015270c6d77f267703908031c381f3488fd5c1536b9700f12b5b38337615a14ecf12062f7b3db6cef65d7c3843baafd34843b33c88a81d911bf3ce5af0703602c2e3e81c0e7992938b0bf32292e05c375e9a94b27cf911f1c3c2f609e02a825cd90ecee3072960236e725b8c578d18f4187d3823c2f20b52b706a002012a3ffa659c7016dc7d3722239c5fd42f68bcdb6e76882a03ce723e51b9e6f9a20b8d80b23e81c4fb3bb414443240df343f810a926587f30bfc339e6c4162cdc0d18556090a980109ce2c161bb6a1ccf100ad2b7cc80c863398f29bf35ec6a076d2566f7db5b5220c12488cbae92c1a111d5a827064946c9802cee4b5dadd52b22330381bbeecd1bf1e7b9d9607ea6097b0e2186b3f31f002e77a4be87b4b106c39a3f5f5b5d409a743fcb31d49c1d7b2006708da91f7ae2cc5b540850297292fe9384e02e7d78633284c01ce7e1ea1856d2da70e86dbc7a8b594c179a4934600e04209ceac2b2841b812d579de4b7d94be42c955952ec775383f9c6b8a00c7a647eabd706736c20a1acea96f3819d2dc17819d0d6781ee392db817d170757c918171c164c0f9813fa22d04e709d5984d6362052238fb3d6938773964da66109317d88aa6380a2b7fd63d321213e16c1d3fb611c22454429a758075aed1bd0062712ec6b36c0313ba1b360fbd4708441e94347b0ee01c611b9cd7847270677e6320bbe08801b098724ec267119403abf579bc05cf19e99f6ac737354fe7eef3883c9b5cae130eff0a351ec5f85190f2d6f5dd079eeb411539ff22e7cb1092c63d4b4844076273a1921464d8c66084a62a3d7a60d8b76e2593bc485196b8e0c7507d0a3449b9ca92b8dc321110294ddc82a47e296e2c432c4cade6192affcd41219dd6af25d33c9f400e25cd8da7da941b23e4484dc02fa07aa9c642c139f81dec81b72a346b5d6e594805426adb5f54d77d2ed7bf7806240ca92b6fc0f7db05ec22cec12fc107be7aa00b0b72a202d772b49e6d8682ea5827189476e37de8e050ba9a8215f53fb0fe9d4b51c024738606d1c6c196be9a8ddfa2cfd8ba6b1a199515ec0321e24859830faadbae219376d4bc5ffa26f2e1abb01a31fc20a2d56a14e4849aa5b5087639a6f2c99894b0ead992750f0f0818ff5443ffe864fd53cac4c99cc6697283e6ba4d6dd005954c60973f218c8a0b9bc5f6e8d24b29d8c39491884c61815416cade9076cf74b43918e46bb5aab5780280feb1c0efb2dfdc636421324b5ca841464eaf0061fb17908a70e0adda28e76ab4b7000202a49bb55ae335161e8359797204c7a7e2967413bd2fe017ec01bc4670df1de238678a7fde2b67018102962a7c0e8cf3fb0e924b3ded000537e7ff56f7e4502025703603752301381e3ccf9e7b5cf66eb8d71c9956f5df0292a2a689527ff51d67ebacb54d00540d35d56e3e5ebfc73cd6daf8a55b79a771bbbdf9037b4c3dfc16bc5c8c33ff548b3d019c0bb7e9a31d07160453d2fd5dfcde47072eb4be0cebd0036c14439f28547aee38c61cadec777499eebeeb481e0596a0fc54d39b7b069f7dc132002b458d3ccdac05243590a90b94fadee65580ea3ce900239d1e7ca3b316734d395017225542998f783449b9eba167a60044588e8ffff7eb7048d7c97ac701917f7ea156356d1e8a62172b40e9d23af9cbc14e4d066701bd8d166f3f3090a4fdd568c5941097ffdda1a7346000498d85447c5914578d6a35d8c1cf0b4414907a798d608db14c5c9790b23c7de588472990de1504972b2e7504352aaa9cc95809519a3274947f9250d5f483d9fbe4270998949d70845822bff187da1c2ef06bf58ed8cd464d1b61a4d2c6d2a21dad53b8299d22456db46301a0f31d3a6d25c815e76ae708f50edc615f1a8cdf7cabb65bdd11d4ffb035afbaeab5e846c9b29903bec53cc491d3c34c20bca34f02910df894180b1fe88b2829b6fc77b842b5e18a521834858b36917e892c80ea622078e71cbc88fd2f4a9f3e2a9c616b1da6791cea20a119785c79c24519af6d349966426c493f0535538689fd4c96008006fe581007fd04063ad3209410e538bc4afd804a6a322cd6217fb1876ecb37e28964f01f15bbe300cc25b085130a3c14da6c8778d07ab8fe0673d0d934d82316dc492b50a21a28600e490e4951e8352ad795e5a115e5e50a0cd0757e69796707558226971101bdb6d1fac961fabe8dbe68d77d1127017a9a6c31b61c2e2ca165087d65882ed3c851186841c012c69bfea93f2006cd82d4e77246224ddf2828fa496284d2bae5b844bd6f517220668bf5219102d32c7b7912ec7d41c4fadf1280219122ac7210a4b44d89f2605463554242f18265599adeb2665c14792c43fed804dbdd34caaa1214752ce8acd0e96aa53ad523151a76d07036aa61a0e86b7c7546067c6e3cf565ee7332acb1c7b0cf677133ad795008fea3d8ad0151cc782140d1cf43614d7e09ab287271f31f13267dd65f38543475e5b20b467463068ca2eb0e7073d8d7da450e2bc401f7e376743f23e2bfdb089415e111457738bf0c06c5deea9a26ad6f53ccf3acbb208a715fb76a0df68467248ee2856d90f846bad3dda49fe0a7ea05359a4b025e6f825f1ec1e4ef18a626cb299c28cf3e0a6e3a907752d3c29a1b1fe1ccc6206292b13699d56d14a0063715e86cd4de5560fe03d9cec888e3f281c3556e8bcff5bdaa4d1d0fd7dca742c5e0f00017a45cd6cd8d6c3ac337372a6841215639a791d5003945aebe9d42d0ad8a96f934097dfd0bf1c7ffe2894a4ab81c4b3c963273c67f3dfab76ad437f483f333b04f28c99b2f3f2766e11bcd3a63f4e64091f16672a0a9c0b0035a50f578640753e4455ec323a19b6790c7a4556fe3db29f45e53ffb6d017216a28f79d2f94a03616038b53a875605a15298016a2e403103eaace529108d2bdf392c3a9858dca6b93cdc62b13e5d2f3c3620ed530963a9d80caeb12a99ac2ca0c97100aa2376d16434412064d32217e409a58e52b2dc0dd8c25a993f4056bfefb3f1dc6be520f0d1bd70330d0a58cbbe38b51e80849c01b90c0008c1dda0cee27c5ae1f83d39af9e1275048032cf30c946164c4993f2453ba09c35f3fa5d8b35501b9968732d80d71edb0e18b2eddfae4544cd27c583868ac1fae11f7e9b9281b402e556f379f2868ca731d461113a23f44b00f82d5e16f192775c5aab0ba43056e1c7bbf0abd588435b3465429d627b11be2551f38aeacf3e7ef9b847b524356e27f26d72c44c54832e6c9dc606892e19f1e72a2b7c7f3c3ceff691fccda7b643d7fc5bc9b5c99aa094eb3ad5f310db88c17ce6db2d9e997b4dccea1d77cb8d04121da4b3ac551d5309608fc4cf0f8f08f6578031f02e3af1d4c7610d6bf455ae274c4c390872625c80737bbd088da042c5597fb7b607ba69eaf95f69861451e266bf50ae1b01f104f10746e41de989b848e3c4c7b57f33547c81f959f9110bd220fadeeccd81fe3086399a29c7975999f8e7cf8cc8391731f6bac0019f23026e7fc6883753d8fcd8c89a4e9b5997845201e82e359220779b8e3d9852663812ccc74aff5c951a9351c8e10faddc4b0a8724aeedfafe1a26383c35808c169d408d59a4de4a1f77bfed094c288c00d0a9698fce3d71882188c558d83198023c013622f90a0873a4d7b58f6f7ecac156f75bc691c9dd813e792da9cc0d8aec7fefaf7ab0a6f4db8dc5003c828aa5638ed2ca274d79715853b7eca4311fd8a7c0b208d7721d5969d7cb86029ced34a42664bc8f602934a93faa19fa51f4eae180fcb0899bf558c867150472d474f56bb777b294eedfc0e0b4a65967961c142630d3ea6c534f78ca6f5f01467af8b50166f48d29c485ce83e98114ad67fa6aa96d06472418e09ddd69c26b42c7bce7d600cab8eb299eda2343e66ac5ee73ce337c778a2cd178d062e60aa739ea87fa3c362fe468dbcedbfb6650923e4b6a24d49e9ef9706b3be8df2683409a5af2181b2db0683e690ce46c6ee8887878ed778ed56e16a4e71bbaeddf42dd2839f37702020412982030340f363083844442a01bd21059e872071938e78f5d522ddd96e73ecc68ea6c1238aed0809aa7daa19021966c44568a14f326a12b4f7df1ed33285b6160aa1fe9f8b093e169622a3ab8fad0bcba02cb31f8dfcc53b1cd168d5d480a6c22a8f52b61843390860d7ddb36f25aa8e89618f5e19ac7cac8d637c9168543e2b7378d0e2b141cec8b5e5c90b575c5c82abdc4420dd5996809f30ef87bb4c5498fa9fb5a8ce1db703a67d8196a6ba9ae9bc78d3761ff0913241d2037ab38f3efb482da658ac3ec26b6604091ddf8e160859a0cbe805ea34079b56203977d5a967c9b9b60eeac148a8617c05f69c5bac12d182e51b85a589c128afcb13f4cdb46b07b4240c129fc7bccd898c820a0aa75a5957aa2d5ca910621f8a902fefeb80783d923e7c9f4662eb3a995be13023ea696343cf5ff8e7d300c15b6cd3f499d1b5f77377c1b1c0ed4c3fc0b43c3127732712158792696b650927b8385f90cd1bb4f2dc78c0bf3932969921a544cdc4ca551e19f22b94ac8872ca9101833c9b94a8899d7221191dbb566d1871d24d5e976cc0cc93287ac98081a95702263bbc3cbd7298cc4007dd95c664b53c327aa14a361881c5f9a0e484ccbd53be965c87b1e25491479f5cfd9be177fbb93956aed825c5ce19ec12ca115513f82a57679f71701c3e4db4a283ab73dc5e7cd9e8375f46bf874fa2ff512cd198047ac7b4158805d71ca8219e71f5e5c7361178075457775296134489fadfcd9163166a772a44f21cc2679d0dfc2156897199fc42a18363588f3d62c1560747cc49b7c854d73f68c1c0d43669d447fc714aa9d470a0cbc8d1d6e58e37004a84a7f442b51f85345ff04c76ba007988d2e92c00e97695a7b46c7ea15a6422654c76048169a8263587a8e72d356c3290247383c343e1217687d054273d4492d687488cfb10112044c4304f31dbbf33d2a27ee0ef2710694b67d57b5d006b176ead0719301e3584e648220b9e432406cfc02323adc71d70d321b712b500be0c4ddf535e94f4bac8f83c990b25d2fa1a487a138ec75915e2f4c81f1976aec5e1160e6847caaa66d8af7657214fe1b006b01b2a35351c51c9bb23babd4edb5ad32b53f480144d003025d5445daea67300e277f90e7808cb23b2c31c7e7eb419f8db18a5150d21001172a8c9010e2b427d54afc25600a0f6d45c9fa338c95c82244a294d0bf06964cf24d4003b92047a1abc5b121254584695ddc77c9ce4328c2664aefa30e8fab3da99582791dcab10d89cc5a5548a769d4410f900f19e3e3e0cd5659d04ebf36bac490f224ca87caaf460627512611aa9e64b08f15247050d70fb232c760ab158f11f30759db2d6e4b759d552031850379c910c887c84ddf87c0f398ccf4ac976fb3672fbd164d08339680cc25886a4f33d7e3ad914749a7f5caf1d68fdcbfc781836ad026aca9a685428cc0dccca4ac8adfd2360514922df078021601758f768bf43ba112abc9b92abe7151262762bba94375593d49e0430fc9a375fe1463601e92b71557f8b4aaa6d5afd0f2d6ef33bce09d024f102132516da8a24b1e55d807c0d7851acfa3e86e1592965ff008ead66e9abc4daf2d8bf716eead26cd9c702ddef9f029fea69050927c2f8bd1c858c129d55a3445d3211f5ea109b471701eca9eed414ccc24646093ed4c79c14eeaf92d379580792f8bec10cfd6cb7399af3c8c1b70547b2d8f683ce22dbd12ee7b341f6617f57b5a27137636c5ddf87b2cdaef8def6c5e5a43f1c1800640092dcb7f596c38ad0cfe6e8b05b2de85fbd44b78194918f02a8948d4157e3f1ee2db2fb16758ede76ca21b389b52827e083566338a044a482396af9fb246b5cec366ef1a7ab79418ea5003b4b29ac855035dc62827238a93e6b7088bf164f340673e2e58580123821c03e222c07bd48698994b6f1a9fd895b002848824100c96378d38d2f2bfcd12dde0eeac52b92594e7448f1652ef060a98e38222aaf8c8fa3d9f642b5afea67eb909a5399d8596bb20cd6f90662ba1b4a45e851503e5029d34945355b64448835818b70927b0016265c98699a13fdcc37c896ad1b480b8c9d3b3014d55c71d24b4669eb1a5c94736e6c25df42963641c86e0c0a93bacf2aaede10beb878025773512e83c46a12eceb5c6f223b32cf258af6006d427b8ddf94670f4d63ecb472912fcc138db5bc09449fb63b17f8c1a31bdb5a61f5dfcade59b6640b98b795b267c1a8caa5cf2259ae2d5cd315adf1062f62afc82d00f02868527409aa6379b42bc5f0065e13946481e9a4584b7fb66a48e8fdc94f27de0db7440229300ae09498c042082ef00e18bb76fc231f0c222e42d48c651b5d3ff1885812a2ad91bfbd5529cbd142d3b88299d9cd0ffff937345fa09ae72aa05bf2fb886c222cc208d8cc40577ea0e2c0bab1a2a61a95320207409fbb861ab6b496272b215f91f37fdda6fefd239e832eaabb62cb159435f8d6a828cb897798a4daa83aa6671ca829435ea44fd97183121e4d320895c915dfb0a7522ca9e51bfd33b7da46b38265d4cada0ac099256ed274683bfc77e8b7dddb6a3623a5520c48722f428c25b280f2bf95e751788cc543400c23ffb57b9c8427cfde2a6fd74f103f85632ec423784900a98071e8058f352bae0bdd1303aa10fd2ae380a2525c45d630cb3ed0cd8bbf5effdc15ce82c9c41154483a272b4f92af26c50831717b0918eafb780a6bee1018d265e71b6f7f54f537db82af09c411d4ba81208a314718a80ad6bbe317fb0c137d3984075250076245449275cca1cc85aa5452668194ce6ed7476951d7e44bfc85c34d4e3ee621320b1a3262cf6d538f3b960722186b08f5c863aaa5f1735a2900a0cdfd4afb63c89a8784cb0313e1e450eafe46c4b15ae41af28ca3ecf31edf5cea9912bf58caac2f75a6358cc78ea3849cf2a645e8c2e4a138c5ebf7cb7aa3bbb345b0adbc9542da440f7d1b8a8b73d22976b52266526ddd4d88d05bdb2b1d96d4f27ad073b83d34e022fd6f432ffef38fc2f4bf87b7cb44557c28ac6a215c8933116fce96b74c16621d6c32cd3028adce70ae3d65448f4a9d76273630be06b77fe17f2be84794a3ae239d51636124b47c01d2004a06ac1cb4bf9b43a2be93bafaddbe6803ae577f84685f5f72b0f7cb26ecb8f92bb1f00986fffc379dbee5445bca05428209449f42a8ee963f07e5181da1de67de91ccc054ab19c1fc19841598f8e717000209e22ad61971ff4638f143097072f7a613cadf014f48a69364dd157f8af52be745443daa6464b26740a7cd06bb0935249ec2e56d2458f685bc4d57e78e9d0b5860889e139256b8de77d9e5052a42c495dd2d6699839bfed9904b15b2679cbcadf52563d8bdb3c8dd861905b996e01f05d03f871468fdb8a821e6f33060e1068e42cbff00e954f7f4e5dce616859a0ac42847a0813c077036f33f68978b3333d9c4372109e541bf35b2234c13666868d4dee38d9c38cd1879ff0b4721aa0c6a532e3889a4424666f0b21d0d904d3043e00be6a9f47318969c685fb018ed650c131a1a02d52cacba130e11dd44ca14ba74502e35d57b0a3cf536058be82c0c5aa33217041c51ffd0da0c112278418da1542b4405d7c203add0f38af48f2001abda7edcf9d69da6b1c00f97c511027695f9715d8777a0595ee03dd1f51291125712998730bc70c79826ece3c6292a0853506a014a8a479cc6edf94fd8ca177dc2e72e81eabd3fa98dc6a979842d829e66fe2483e6ff83ccefec70809b5ef6fa65b4ee1fca10d0a2564a34ee13ac7bf0c6e806a2def00f8141351d4d16d0d20b617608bdf482eb03e311de80d7daa5641eac5734eb4d380410d4df118d723c2f1709b3fb40029897c01b9aa84bc2f1dc624658dfee2b943f3fd11985ada6e0c928ab133f96370d93fbe32422ef7a9833b2d7679bb77a3c1939c618050f42efae4469b84b2b640282b7e6102668ea8f45962e838eca65bae2d1424beaa1a3f7d25504e44d26a8eeb2727a8a3f2446eba5e959a6fe239e247c2fc1a483cf887b10e8f4111914e9ffa870aeaec6b365bda9ec1a940172597e06d76fe90d569598fa91a62f838c655d2b127df93ae5f608927e40ea2ba27b811c12793f913ff1d4e3e6315d89929e422471b85cb8104fa1ffd841a05fda8c22f5a3d939ba38ceaaaf8f928891c656872a9c368af98e54078a98a566afeb6797846094175aba4e94d4d25c125e170947b6a00e6a7cd3b19befb5b37f44c24ce1eba1a752d081cb7a075c1c209f67b0bd128b2acd01eab3405d9a4f521ef73054c223e78434a983b15667826072d8b5066e100ff97e3b3049d4200f7d441f5f46d7163b265d12b07454a6e0d355a56a2e1d0d955fe836b8880412faf0c67c8466149a6a96379063391d3bca243bba20e454edae457c4765fd48b8a69f4beab27775ce7d20ee41952ae30e5b50a298d9ee97008c29b4cd05ce8c80b612b308fcb61a906d9770c79c4d872bafbc232eb80768797a0ecb030640423335f9053280f80b28009aca90468bc9a8b307b094abff2a7af19afe78335088e4520a034a9a0e889ba977ba66b0ce19a3104df54e5b6fc450e8a15f3360006fac25dcdb355255e6b71c2a0b91bed1757827f2d590997a6d38a4e0fd87468fe0e3d6c4e063014f72585918f5a5db9a3c6869b3485d13da4067a1713b40d4786d109b112886ba469c2fe8685a660b52229ec38128b4e65ec273fc8bc2ea16d494753d82a3bebb75401dbd0e5e5ddc2ab342e791708e8fd1360bfe3bd395423db6f66dbc1850ea372a30e2662a2831b30b92cfc600023aa337e605318ad40da3d47b887ed00afeeae0782d8e7b07fbadeab6d4af43a57e59cf91bd4140ed01391b17e43caca98438028c7a64e0ac48fda0651322921a5d4c9269041743421e1414a1ae50b6d384e3f1fea7ae4f6d8ed0f353342b5217f31735f7b65567750ff481fa69fe1133ac284ff886ac6c2eceaab3c869ca31c79ce9835e035f863fd10ed0797b9a68546a563d113b8df3d4b6340fc0f395529c1b37a5c197796d8b2271e3bbf416206d775491d815eb136048c059871664961ce6a06a8f1ec35e59772eb29b793728cd89cfaa80c1261de61e8187a1fe1c6de0eb4a770f1cbcb47f04110d8b3247fbd9d12cf35629c3e2e83213503dca790e208df97bc4493c9a53430420c1f98193323462a254f1d9e88fbb27fb01174a852abe2e01076d0184ef39b622a9fbb91a65383b98f3ab87c24529cad098ad2d7e639112d0276244d6ed53059e8ee7145006381f6c6a8e268ae6476dad419944954f066a0e6c8aabca916f23e763f3f44dec4e865b215535d0282af4845ec6d60a46cd020b1d8d43dab4f22df5a672a960dae07041b3b9f032b3dffc82429041b02af5667275b1692d149e148308a5734e953663a538063f727b3626e1c8d9f4729a136398b0c5466e5e45cde21ba4797646fe21c9a193fd0a6aa99be6dbd70c4db72a87e221f2e39a371c6ba2867d49a4ecc378ecb5d0f97786aaccf7bc19005d4d2dac005af4b8a4efcdc082a13a1a3c304e6ea037033a1480d5c5b084c6c16ab027e69b0102a07b881cd59d581d0bfdd5747cf0f0f7cd80a3727b914aef76c5a295371660a9364075cc9b81a8c9612eef9b8134eb43135cddf49f64300785455f09b84bbdead443fb36031407995c7a63b3e5c8c1d9a4452a15ac0b2aa8601865430b8934582ea9518769cc360d5252605da2460db3315bda48a48171490d354ce36c69919602cb81af1c4c13b03c13d324a09b27ce804dd64c94942f6162680c33493384485a9229c565c741f2979f3f5bf6e8bfdb4bfeeae780658d9bf44fe1358f00648d710cbe57e90a797bbef8e54f20ea129732bf56fa6a70ddd2675a61ad7c0366030ca0b6cac8c5294db440a7889b0460e2926f767420928d66ab91c79e1180961a0200d054ebcf7a0db149a24b5e02553cebcb9e981f3ac36a8c27e42144227d5aff51732bacbffee934d4e7e6147d7981a7265bbd0afeccbff55f09ecef54e9441a42cc71ccaf75bccc603e4ba4933789944a0c0b6881a8402d9b4dc09a7845725050e4948275d44b4e0db11bc1d32d801467b2950d245cbf205b6705eab896bf46f73088239daacf1af522545a8ee8c74c9465eb40cbf911f7552dd5fe9c8c02024e7c19a6f2d43fdd2d80f10046e1048f44cf8489d35ea43da39ee14159b9f2299c646a71fb1b74647a12f70a70315879773ea862129cfff0e1ce8dc3be5940600aa8c002f615a428a9014bd78ff80f887f39feebe0ea3b26feed69867f772efe396f1321774f1ccedd4c3ac5c0f6cd9a5acdf71922574ae3fd9fba59934d8581f705ea8fe25c34c0c0220a929f66f9d4b526cc4a827b5385cfca23f088b88c230519de11656fdc63b22c391034a296c6c06c2e9391d12114cb0528de0c6df8e2a0044ff035c24ae27cea02fb2f0904713bdcefc0998c069919f3ac1869661e54b3b35b418d91a4db21ce31d2e6e8cab63b642b2252464f4ba9a3979ed651833e8c052e25efcb0d722e3bf8c30268d21ff604f440672136a8214fb7d5c9db4ca2f69b6dd8e3e79e700517d56bac75cea716f08742b180865364a5f953d8b10d86e865f545a200fa2c42e143b2a6bf4eaef1314bb373130a5284f8dd6119570299bd035f92ece5e097041d9701065e995fde364e1c134c212553d795853bfeeeaa5c9ee0b9eca1a4ca7469dc497e39ba3a41c1650b93cba04842ff95041aad826db330387bce64691b0807ed0ebaf1367004986ded71d0fd4193725142b2a9806363713f6b5e52a04f55e3dc4676b83f08fedaeecb32d3a8c214b549ed2c03c36c0b81f7c8183f7f9bdbd768841b7efe02e929f71c7f94e8d47abe6f37800cc36cb3fb6acf8d5bc37b9ee579ed18e3c041f647a77b370e994909a40d046a361fa65920923a4a8b01a9f14edf7f4ee0356cbc57aef3163142b01a7ec74563d1785d2c9ddd6905be5ffedc1f52f5ea7d43b550850250042082a87c98010e72501f4fc185ef7e6fb0fddf3e7451fde8bfe8db6e84882422894476f70e450ad909cd09a7fb79bfb1b06927c2760bdb89b0222b6cfb1f79ed37ad87d60159fa06fcd063538bd04128c2e7edf81d113aaa83c80d4334aa91ddcb6607734fbf1c678a6072e8f8f6059fd2ed0bddb68c7f6fa6f1366ac110b353a22f92d91f91846167f99b7bf336baeda3970864bb9d198a7a7ac8b3d17bf7ccd2e84f6eef11cc8e47e9539a3d8b5946f590f7eed9b32e7ed3aaeef4d8e966adcd317abc596ce9e397cf0645334b6944e92f56b1f40bd5f1cb17cff3e8b6452f1b99216cb7cd0b0db365f498f76dc3ce6d56cb9dc558053f520febf8c50b8eafc99ccc393eb30e9ce186fbb475f11463a74f5fe84724b76f745b3df44844fb49ab6cfcd2fd8b5536d69b0cfc11511d3947a6a61cab6cec19f6e5cb970a66a3dcb67d760f3811c5b42c7ec1b2460830fb1bbe8298f2a4cbded9f0f504ca0ec209104b9436b7e39f6cda02a45dc2862f21b66c219e3c29b385a0b2eff6be546bb2fb0cfbe8e973ce392709544cec3a21a84f0cce25ae03c23aa0a8e94d3e1dcbde6f46f1cc1ff026a5c201e110fae071d905b9fa4b45fd7dea6fb531fd8da0dd7bef90843beed5feb8430f69622290fba85dfec342f88e10e8120ffd8de00504fdadb6c0d1dfb3c078300cd3181631ed2919ff5d6bd58e6767c11e773c6e3a9c367f8e0f99c78e61d9c5309c7bd951f1d87cccaebf1142d0df8a87fe0e825655a9b17b515ef5e168a2a93fba497dba16670e1b538755da46ec272fcbea13ad627b47865bc3300cd31f356a618f337e451b7bd4d4ccfebc13c921d461d858a6747bcf4ec34420f31925b33f2f7e72a33e3fbab43f2fbbf77bfdd1a5ed5dfb8e4ebe39c5dfc7693591dc570f614769c8835d638d354ad1b363fd76b07bf1d8519f39e64fd3976e2d63d877a0bc87e984a07eefe5f99f79934f4f659aebc8d95123ec2f4659ed2f46e97294093f9be2f97876c5ff46d81f0fb7d53c7642eca9be6684d5ea4f79fa4b613cf56777e576c6a8899e1eda3eba63d488648d56d96731cad4a9238cb05afda954947aed981112b6f7cf0809dfcece3ea2477dca108a105f3b21de87b0ee4ebb22dcf61ea3ccbaa3c5ae316a1815138178faeb34151347c04ec5d025b8356ddba8181eac949a7246fd1921c10809247c4648d0befbb83722896d9b46c5449cf8352ef401c2f503977d632724eb410267af1fb2740e308a6243d8e3db6eb767871d91edd97f24cc302c9bdf32067d5a20a25b3b1c72efe550d027ee785786cd7967add9b51d90ed88c84ab1990df98c8cd8f6f266595c31e0985dcc4ed811c12284f671ffc86df537826d37fd056dfb19c4c6f69178667f46516cab2114613e434111a4dde2475e582a654b2756b68cd4b5a78635b8901e814b2ed726a2d9d82725e236f6bab4690b474ed8128a204f846dd90206c6a60fe1c8093b42111c0085500d7570a30c40d0f3829dcc87303d94f1c18cbd4c7aa6ac7258b0a4872636ddf0d503191cdcf9103e1e3b0c072de6e0ac477cd34a040ba6919191110b17d50bb15a18a65b55cb2e745fb1d30be163df94b6773a2e6dba456d76a1eef4b57ebb10cdeb2f159bdf6b3a7a993a530875ec583bfe09eb1666752bd3add6764a7f2f949dbe7b727a774fc72dde69740b3bcd6d74a4b2535fa35b34bae5e956b7a5fb76ab57682509d9df67ba95ddfb49c7272d7a936e799b6eb5b6a05692903da75b57b77e34d62c7c4697a6e39225a525a91d2f54a20bdb2d597c52abb6d8ea94974ce32d872c4c5ba5aa5994c6284a2b83d1b6b849ca7a811f8ff4327566cc474988a61749646eba6fb20c27b06007745fe66609ccfc818414c2552a1d97e2d28d5eeae8ee4eb946db5d4b86c84a92a7b932a3a46e41e8c7b9d0007e7388731e03d06f511db71c833b7ab7b987f29ee3de7348d510efa87b47fd9356a04e1d76403abe9a7f310fd5e70fdfe424cae342ff4d520b42aadffc9a87a6bae846b76eaec2a9591e3a72c299333fd8aa2136df6ef3edfb4648dc717b8e6fcfa1bfd3f16df29158b3da3f5276993fbc6c59410b0b53670add1ce75269fec0d1adb8242e993af3d04bce3fb8f445174b00ffe2923de36f32ce6316ba398e6ee5df7c476e19b1765c76aa14707e731570f42d109fa8f4cf54e5a5a24865eacce32829452af937c7d9517f3074a06ea31dbb21d502996647366241fd79d7749cdd4f58bf30f7b7da437208b6bb0b20c72d53673e0039e66400e47c9d3f2c7f43514b4d34979a34692297787ce27ceef8bc44924be68f9bcf7b1742564bf524211c4e9d88935b384f12c2f377e4d68e2709e1bfc94837d7dfdc15e9664746bab92a23dde824aa8f9cb0e9af3f49f5d03d54daf3d662dce5217bf92bc3092c9cf338fc8e674838ba088443d6cd55dfb09b0d5f3db8f68d9cdc327f2409e1389fbf93838710f6a0652b4dd9f3128bccc27dfe2882383c0e79363cc4d178eacc7feacc0ff3d03b3f38ff76ca80f346074d9d1d2f8261c7af5d3b7ef39bf35065f8d9a500593bba21341f3961df879065388105c2a56e41eefa24207c87def4c73d0908bfd190d32f60fb6a2820e812dc5c5ab153d3df0bd8de52a1a89476ec824029019c3a124a0976bc46259ce3e8d4d471296d552e812a9760c76fec827668db4100b276683c759436ec80826e9e6f744abaf63419e590374274f8aedbb9e557b2cb8efbeef00977b6842f162cd9f2d583971db702b6a41b67cef06281ebd564cb183d43707935a1f26a72f46aa2f45a0199d70aa2bc56d06405482f159469f252c1929e215e2a0083553a3187a2f4f0862d9b9e526a002c66d005958207276ac073c3170f5578b8814919fa23c5809e1830ddf0c5648d1d0f9988d9b5d65a691a2f263c802f263cd8338e1c9e9e1ea44bda2c6253c21e248cb55082310d68c0262b47989b8204731bbe983c9101a3367c3151d233830f768f0d3b80c9d9c1cb9c29026cf8da81c9ae1bbe76c0617fa98984933ad2984e894b03a348af0de90b7c7558f160dbe0a026212971b2c2e322536348a909d214314082019627e060c29584431134280184452a82bb392031d9906cd0c2c053e615717877c3970e34b86430e0a70171783c4e660fb829f38a30f094c9e3845ae171b1298558363da574062466b0b229cd1bbe742862e7d8f0a5c3922d9a938c041e05f424c1da86af2558f4581560c3570e5f72f0627f2b1fe4c0450c396821c3b6e12b871b5058719e84f684bd4b789c3031b9c09381c789d403080209183134f9628b0a525862cc0f57c470041b41b0e8a16b531a94d01a789cd81ca2ec2df5882dd83e85930313ec0c0f150d26b4cb0ef3a701130b1a64ea5f32831a7e1a40975ca921954a91b063f586af252c58a2647f3b5b6c9425486658e2eac6cce02489141cd248820318243774d901d8f085830c70a8527b98c0c0ad33f284c13a48f1448a5d8f8a51723c50f0b713d441abe1d3cebc66f1ce4401099b470cfe764a38057a2002c9b52bbcc1aeb87e0bd875cbc636266365034208eb0f862f1c86d8f119a6b55be90382d9da3f23104cec1e9061bf9f5193fd6dda0804b3636b6b1aa6c9ad05c93418b63d1277a68bf4b8007fa63d29bd01968230292003692803030f47e4d0431563ba2803bb403a628d28beb8614c1032d82e0e2fa84a969494c1b5d65aeb0d4a52fe88c00d5aa40edc9fc52970d18841936001fbeaac662677cef9a855438c6c9448591cedf97ff5726655ddf1fb304d07d9545607d9b62ad341b6adc274906dcfbd7f663d32a324323535b251ead0d3464f1bb8470c9697b587663b0bd08a46711a610173c58b0d4f44381ebeae64b9b09e38b942ddd5a50f58a1bc9e707d5c98797c83808117a80da90daa2cc98ed1731ace0eb7a528d590b8e5e9c572dc477bde66886d23abec9aebf8bcb4b2b3d3289b3b86b4b9e3259aecec2a22fa33bd3e7b82ccaee25ae2061b7585c99cb9de8a3b22f319eadf69dbc75f8e3bc52e48087484606fef88d45cc74d5d8c02d37fddbbc8799d90ae8b5d903984eb88d8bcbb4962d9d0e9f3f1c342f06b0d50cddceee5a17ab851a710eca1fc9d2070277c384207624041c513d6ed86d89ddd6bea82cc9bf24fda26dfa86152db9ff6f9d90919c1906d047ba3c79dfeb45d4fe750fd08f6cd5fbda4dbbb5f9b9c3acd39dee5a11cdae958c6ba20f4f8b50b426fab8a88e93a6c478152a743d8874cef6ef3477f6f57243bbdfcea103d3c0da65529ad1a6273d36d6ee2bafc61e73c791dd986fee635637a887b7dcd4df5524e470a90b5c348869b2781f0005ffd7d64fdcc9b1c36b9260f71bf9a46e3ac22c2dd74ee26ad7111060718196daf43c1280a585bbb6843ed34c3b0b3d1deb67b228c3b11b68f64dbdec4156d7b2484ad1d5e18b6ddb408529b28b5b57aafc36285cb9edaea943cd9009f7bd2c09b0c3c25100ce14b092b5bd21d281165c3571256ec1f1bbe9260b2af097ef58281932d81f8913af23d66e00f5ab182f421f42d6f04fa4c2a66f607c7d8f1890be5ef0ffb65054caac796ef3183b3820567c39795275652e0c4999c0d5f4e74d163c397134890b0e1ab09389ae081091bbe9a30a2091c6acc88f1bc705ca8f0ac1051a30313496ed2d8f1526df8aa62e555e5c98e1e3238fea330a523870daa86e6c69b4e5cc8a136ddb083281f17ee6d21b765191c3f87a6965b69bf80753e6e2ced23d97e81a633ddd9bd806de8d342f4b25fe03ce8d34274ed2327ec78972bc62f6e5402c7dbd7125aea8f404a72b2afe434952d3fee3ad994257f40d6115e7c1645af0f4734a147d1ee882d3b27cee94dbd4375b851087cdab13189893433c7a056542bd894ec899db2442bb38d71392953b670b7072db1ab52a8782c7801931e3b0b60ba4d708d81ccc93af192d205d268483756c91104e77b98c0df8e14242398e4f45081bb0d5f529c4869b2bf1c586bd502633aa34b1886d51a065231b5d2a59a651c605a50060c982f5ebe8001732557370b35d4f0fbad95d4cbaa8bc4be836171d39c4d51d45622f2dc85c873da68dbdffbaafd66a38d11c9adb576c5ea95bbea61b167d9b45693b64a39b3634455e93910e7b01edda8c4916f79046fa971209028648c388272c6bea64af7b7b33f23246cfa09b32cdbb6d6ccce7b739838829c9a8a8923dc9a21092a5d922b496b95dc670487521eb7590c4906a074a9c78e006db7473470249e39fc8276fdcc99fe22a5ff901d3be66d1008860b469b522dbb5e4564d6287bfbb4c943db6d4e03c5caaeb71957736ab46fa0081c97bff9d122759e1a4d94d1b4d9afcdd9613724a397c676413852fe489c2c83ea49224beb84d8947dea36dfd0ed37c37d9f09e98ad0edf636fb7df633e18eabb48e3bc4ae12624f5379c8e67073b985d473dce4cf3b7d2a17a9b7fac3eff4b715c1a7bafbcf1cb2bde639b210b8b7abb24d1eea5ea33b9efc190d79b2d3926655bc9452ce5ecafdd2ffc86b2fcd2d5c8ebbb6877521daab711b1421bba68f120a981daf33b9fa995f2b08fcfe91b53b4282a31850e0da10ae20acf99ba7a7540fc14f7da48585764af74682f481998e3baf5e6b338ed3e4b79fb63c5fe79472a3fb9457f79a7286edae6e9c2314616eefae7540dd33dd9b26924462fddea637e5ee32952b538e562c67f22c0cf026334d769a6ca58ed6719799fcd6b8d38ec809797bec80b48d6eba51bab10c313486c0f055849657114a452051c4930b5cf8e39a20953e22bd7c5cade68fa7567bd61d2d1721bdf66a24d8447367df3290a66d9e9b4a13b8c343bb2da79f9259f03f408115b2dd3d4de4643d4ee00d506085254ccc96d4ce523859965dc15f2a85b342b6810f44207167678188045974255d1891307c11a1b4e16b082b3602367c0dd1c3ae96daaea70a8c7d6251733d587090f42144810824eefa1536f001e943be3e6219a2c9a69f7772a1bcf630876ec9adb05d0b23bc29c37de4cedb016d50aeea36bd9333cf394ddd3dd39198a5cb0a902b4aa35010bba7e6e9823ffaa57e44a4253d5a30fcc7f36fb54d9de99aa2c9f4abf564c15fd42e71b65267a6e4ead69b32f72d5722bae9f5916be39cb05ced9e18e07938b5d01298a749942d1f9b48a8a589953eece7d4b21f0634008520e9c303e3c90e68bb5aa54a01bfe62a9c4ef31a8de4741a6db4af67e2de19751a95ad699ae6e40ac2a93fabd42d7161ce15f2e5ec6b71a40fcfd6d7bcc709fcf5d8f5da7b481f34a7d3bc1ae1a957004d8622d46428754c5ee66cfeeee72da723dc35d35cf5a45403031a23d3e6128f02e23de4d99fd1923daf41c0b3bf06eca987b80f65b7f4e3f4c763f7e9f8ff50a7dc651eb9f20e734f167cbf7d47fae8608f0daf694f7f764f08a1fe38ce6af9eb11c4ea0c66da491a060f955bf440d1030511854a9462557a40fdcd8865945c7d3bd80b85152756d90207a70ab6d7926a1c25ac8aae782457979288ae7a7056833962c96799e460dd6030fdfcacc76615fcd9207272a44ee4d9f43d628c31c62a050e9aff9993677719255790cbb7b3b3b3b3b3336f2dc69afe5229ab75ddd914903a3576f4105efea0b6c70618e7cbe992eae19202836118771a77ad899ab24729e65029b992af5b46292f4d71ea60a9e974d33dede5f0e35338873ea947fd19c9c1357f39315bceda63961e3b14a1d66f4c6d8dcd0dd5df337dd601a52cd12402ed4d863b95e9d69173649b9cca359926c79bbc63a0ce74d34d9aa86eef98f71fa965fb9f698de44c3a33ddb4238263a507626c69948a558d6aea99a2878c153b73e68c965d4fb74e0601cfae7a886a2b5d20c8d943f4d8e1edb52db5fd47ae76d45c771fb3b8efb96ce56adbf4672407ee0c043990cb9c9501e6e46abaa0278a2cfbfc4f967fe839e8e3c28e212bec39753687e8650e92ab287d649ccc43f341a6fe61805cd51fb9aa158a5087401f0ffac45d663f433dfbd5b89c2e88d136511c303bfb7db9a0cbd64ebd7bab695e6d0764bd6ff17613614365eff6de965107f28a04c910599693ba08cd5e900c91b50dd14ebd6b47e59afc799fd103bc6bbf262eeb808ec43334fb7ccee937cefc759ff698ed8a64b7fa9b45b47745e8aff72be4a3dfce7545b2a36e334aab88dc7b50fb90ecdfd43471bee636595724fbc7fdd33e77848204e1013e7bec36379b5e933f1afd196da238e43d6e9c87ba6b8f365ede38ad71dc10487b9e72d0c7857871e700a3283a2173c36e08766dfb2ccb20f601268d8d367722792484edfde6a1ee70a78070e48afe87cde15119db7c31b3e186fb6ebaa37cec509a16df497c7b934d0774baebe83fd2c9136abd0f779f49bbf01b6da42694a76445aee86384cfa13e4ef0179d58d9f49ba67544628ce264d3c728914a9c12ab401fb829cc72a0d85cbb943972456b5724bed35f77d3bf4ebb60746317ff12c3c9fe12e58bd28edd6d277d74efba22f8567ff2f85c57c4f4abbf1c79930b465b62db154169dd909a1c95d0d3e4c8e407fc45177d0d67d95c1eb359a48f4e4bb4a2eb7e63361deb803a9389c644137197e9f66182e96d58f8a85c5122e943ea9cb7a04ff733757876f8088151a01f4f8ada15e88f2218725cc76d4e7568d75192b36c9ee3f4ab1c19ca126c88e43649bd92b23375fa3b3d6a2a7d9c7476ca61fc4efae84e8ff38bd3e54d0636fd6e1d1036619309c7cef4aeeb5272457f3b7fa020579c90f4f1753b64366514e48ade0707dc59b1298e198520d3efed804c8f510f759758aee817956c72496472b90ec8747d80c01fb4028520ae03925d9646e44dbfb0c3eff20b717797d98824327777533662baea48dcdda7c9f3b407a05c6171dfeb7540dce5ee95d2d4016d546af6715b3d542f619437754072cb49ee4063be625f2e82c15e9ab06997bda68fa02c413ec959dab3af56964c52111922927b62b5aa88442b89b816a33f61b31ef3bc8c712753907a6e484584dec33f5de621ac6b1ef20e379134416902cd3f2249bf797cec3419e92c1ad9328146b7a02ca1be457318a02ce174284bf05ea529cfd364c8bab003b2e7301ca43bd6dcabf79f69ca435eeeb28a083d777aee3f13ca95dc32cd6635abf5a3265977b81af6cce61a2569b7b9cdefe4501ba5e1136475993b96f4deae7b87fd4eac0886716b6b45b0b83b7cc21a56843a649d4e5966833d43e5c8ba9065938b50d771d809a1ae4317e568e1a21c6fd9bc26474ebab7c949daefbd272d6eed9e32779cb76730cbb20cc3eab525617676cc64b398b558d8dd5b45f6b75efdb900c396cfbad3d3696edbe974aa9a76a2dccddc49522835fa8b5b229d5563b46f77284da8d1ad24fc56d2e935efb05f4cf34b93e3c62649c3bd8bfbca6fdc6fde5e93214b9e48b6bed6feec89a4cc708316a3188cbb62698f5e622831d159f3472425848f463bca0eca15755d08a90415c1308fcdcf2e6563d8589876cdd7cb18843616fdccae8da58b603885b183227e70c41303d4ae79250abd972c5b9e040584d164cb1e32029f71f0d7833b0bdbc63408e06b1cb28160db33f26c193232391e30b258fa25c9b5a1865376388c9a4186c393bb658a3068e080d8a224611630b27859dad9862f2f66705fbcd8411730aa7c51e68b25139731fdb9a03f236be1b3ae48bca6bf4ddbffcc2cbb60f4000c8503d60ef7c76d99eda965b303c224d0503ddd34cb126b5fa83e37f8a4a076915bf0f8d490c3e353434e86e50b2edc95deefe37d0be9041677a95b4942f29e6e799742f152b73c8d75a7934416a7e5e335624597cab230756866fa0a5387feada4eedc3d6df2ae694fb782a60eed38dddad9e092b6a31db2b643566441d60bd827646d39cb5f1cf2c0fc9fd03576a60e2ec5d1e9a3c38ed538b93aa2892562d8d0e5072a8ec82d00030e36962811062b7b950103237696653e4a50ab1c14e652e73814cecb0b257bc786af2fa26cbbe1eb8b271cfd0f7f5937e6a22e059961744102909569cf640701c84232c309ac0cb2b42331ca461230627541479a6e250565d79ee9566465bfb10b3a8adf5441f12aa852481212c2744b86c8c27e35526461dfa8a45efdd4a1f45ac690851dc2ecf4b58b0064d95700b2e8ad0064d95f3a25964558a9f52a9258941d49a667388155841d09a6673881251f244fa5a42a7891a1e435060b7c7288e30636c2d0e06383cf0e5d80d1c5161e9c6d3270f6786b2db4b2a5ccdc2f0b3865b3ac1d835e76baf0c095e936bbc7a096ed311f991b04a96df5f7816d24b56536a74f0cf71e619c8b92824ec726134d515290e934ba65c4f2345481de5365d79eddfe9e72d144bdc8f45692d0e928ddaaf9e92d9ae3ebc8aa781d872c2faba256a560ba7715e675680d5951b67c565453a4e3de63a74a81e6a60bd1dca42327452d54f3a96d2ea2b9496bc7b204ca76ea6cdfe4932e966c49bba023ac8b92ec299b74cb8875bacd4127cf3379a6a0234fb792824c67c5a023fcd36f96599029d09b6e011d9fa679abb9d0b2e5b32e5c5c74d9b10352a5e07934f7302d64fad4ad9a9bb435229fa9826c0eb7508ea3ae23d3bc371af41348752f446fbad0bc771f17fe78b613762d3a1d759c8b741cff52fd6d3a7212779c8bf06db42c8bd9b3bc619ad0e9a82dfb96ed29a7a64ecdb491d426400ea4e4604b1abdd190b7d1454942f8285d847f0a3a4252a3559646ab322458abac56dd0b099db42ad3aaab53309d5e056fbe0b2a1baab46fb737e12d0b997eba965330fda45b49560b79c7bae5bd959d9541169689e8964ad748931807326099e223c36b8b2aaf2d8eaeddac766f013875b22d9571bfb700a7371d6424358d3229b934f14101521732db7689f2d2c20b8d8bd7acd8da6fb06831450756bc749085a339a73a69d8c31ed68478683841d05cf753f7014ea5c2b7008f83603a87750aaae35c4885a38578700741b3b04d1cd6346c24b5bbd48d8e7befbdf7de7b511a854271f73ccff33c1f14586bedabcb18af2e56acb5f1f6a585936d394ec5fd74958793b200ce41b080ea3c5499474a08e72008a9ce03e74220681c954ef17c20e575e1b227a5b1d639eb9c531e995bcecb493919f7e46c1c211ec639e5d428945055a9a4945209b1b8e53c47cfd139299c94424a2985b0d67c64ee2a2b9119446f79e9436aa9b53cd545e20522c618634764ce30d0460921841042082184328b0b254723a591c623ad39e5189b5e4620f08b27a2fbc3fec1cb38b5df89d529b726ede186bd5afdc98cd95b3db461adb3d29d1d5369f52a5bafc22a9db25eca4d215ca8c8674db260b2b70dc3b20ccbb22cc33221f5f4928b5896654374845ec811a6a55cddb0eedb3e4435cd0dac5d7ee8da2a3f14a5946e944df6791d594e79d764da448cb0e070667f46585caeedc2a4e2da5b0b5a5c9b9e68dbe2c2a83dcbb83ea8e4da54e788234c541c611eb2b1331b28c23cec503d3f9828e8b37d1ed3a068074464eb89037fa88d4128024ab341e5d8b2dc281becdadb5114cbaab861d9a75d7575904da56d57d50dc322c568b63d7bc6e5c98bcc8e5d11232c4b5cdb05a328a8b8824c2bae4da9b836d5476619d7deb4174798efb838c23483e310341ccd704f94064f9c56657318cbb0c5186b78c3185fdc610e7b42de9781fd597963a2946e1ba5df367ab7ac03425dc1dba15ccd0dd3300cc3aad60161da6691258551bae5b8eb770f6fb665f0f67b39746976b8b367c7bedde62faab0f833b37c6462fb46d55569aa6aaf8a966e475a9b7247e6a69cded78b7dbf9de66c3b7c654126f1b0039a5613001f2549084f25c698d2c128dc150481524a29a594529ce7ac7a481f33c6380029c30d12373c96058061cfb24502cf7f340537005848dc39186637cb6af780f9ec586623942bb85029db908bebc98e1bc813985e315c5c4da20bf131ce09af09088e875c5c4d763492315e0180cec74749548780546badb5d65a719eb3ea51b12979e01da40b02a5f413d64b2d177200fb3cfd2811ecf3b51b426b0794d10c03a1018e73e34f6ac6851cc83850e53122f304bb3ecb5f1daa9f32d64f2146588c5c9ce3383ca58f29511cae34e2a8727618e0c65a9812b252eb30c0cd8121bd36f82849cea72e9426c847a95138bee7d660482f86514eaeb063b9c24e33102af8e3388c6194520d25fb8f9c74669a06d73f86fb7118e772052409fce1ec89f39c558fd38ffcc1055203c63848dc267c94043d0c695639144e65205850291c2c43a51990a04c4cea0e1f25d96fd816e883dee2a95513ab675c0e7bf82829ca12e48f92a08fadd65aeb85e4aa1e881218852021e96352995b8891463ab5e845a20048126cf1c77103c8acc5dff7b7edb9419d1e5b0fb99adf01b203fe7a6c7bbec70e093c0ac09494f0b2e777e785224c14e46a1e880ef8bb7b1e85a05a730b71cbcb98a1d20c4c62ee28a6ab97346e90b8299e36a989e5d05a28f15112274b989f874090c0f29f154432a0f30d739e527aa3cdd373009dd386317eeea82b912046320895228b932d3f891845b1e96796dd10a8542fb114371ee69c1962c3d70f86d89f69c393b0e12b8e34368c3a62f87321a63f4a8af233e2e2d201e620b0dc908b6b0917976bc3d799a5fd9d7046695f138e5c499ae186af3355b69d3f762435037fa91e15ab874a33206da834031355d52dc43dafa1c4cb571c60e48539df8f92e6939c95140f29c4590887cd03a9418c7174d9f065c68bfd85b0e50db0e1cbcc946dad0c78fe43e517a89c2f425d2ed4bc9cd8d42d4428c227531388ce8a923ea0c4cb0805e9acf81f3969007254eb67e58020c1d93f6af14c7d574ab10c8bb2ea17eaa67ace2980a0604bc46695b6be0738903061e58921b810038c124a948c81a30833708c81c17186d4628b4bb3c8018d4958334db20a47131f0ca1848b1254d040c5982d57e4a8e249920d57c278c30c8bc211655338a604a006282e732931e3f2c2ae7a6014ce8f7aaa13c33ce1620b24315ea0b8010b882a4e4891411667b8ae964d290512c30e1c3f98ff7cc1d18685a38d1d93a001151328a3c9105f24f172030b48460c6ab0821a7041030d64c08a4fb1608c9923c26461a64c18770659b4a08d2d4be4f00414707ca00d9e367cdaf0010f6f94f101928d09816d6fe890450bf3c442e1460e0a73a98fe1301b1beb224436260419bc1126880c2461c10c6810d3a40a1a5078a2054080a1a10c1348bc3e45971dbcd185a34193e695d4996fe0607f3956dee82193c28d3259dea8e20d28a814cf4a724a323b5f1655f46006597050061915307385103850e2e5022ea85426ec557283936f08f106142d0aabb921c50d2038322de8a10b1a50b992258d1ffc7003209cd0011957980c6145160337786801b6ed7063ca5471230a3265b25828dc1843c68d246dc0c129e130c6c61a775c2e974b89151fb7cc1ff4098ffe56557fc734d526ed69b8eab07f9f5ee60fc9c3b3b3239750993a4f616cc492d30c3c0463973d5b49516f8993bab674c55674b12651b631ea22ca36a68780a43e02cf6cf917b22df56734c36600862cc8aaf34774b1e61b3b7ed996f08d06481f1168830c5c411f1168c30db882fb8355ecf9452ddb0c0cdfd8707f108b3dcf387ac38a333cb8a18316d6bcb2041a5bba1421e58a2bace90416314890792dbd806544049438a01051864c1a3d60653103132c7ca0460f48b2604d1f62e0228729b678a34b10acf99df9230429da60220a2e92f8000dd6ec62690917e4e0439929de60cdffd42736894f1e529f31e69c5e5caa34ab6c430b1b5c5e6d88a95c1738eab4e1451b5df64777940b73a0e422c6281fe39ca20b1b646e906121a382ade30c0ea017587040230757e07086873194e8c10f505c3a10c28c2b3457c6b4c18613325274d428238e1d70c1e40a33a00d96680192325c3c89620936a6989ed802b5ca19a365cc1763b458838dcc099a0d5f63981803c4162936036616b7601c4a35ea0352a4f172b951a586309edca0032d908eca04c1450fccf0b830a822d56335468635cc44913c3c5658cb634319505001041a4dc29061e50a296090d4304612343ee0c4fe56fbf136b113a0032741f8b0461664d260ed60f224cb146492084385159fa2c2063c3620c0185f584982092faec0810c7c9930411623a494e104184d8658c30b1bbc7a10e6b5e4030d4a113bb821840f3f2cf15a038bee5631aad2450639240d71c6120f3e55cc1e98590389358cf08162a90cb5a8319492f0c1b2d4657fd827064b36d83e51e06cc3d7920ca85d7ae20c9f2b5f9688c0c6d82cdd80598b8dc0648c154489620824de48415218417481e2d2e14b1a56ba3466c0dd25d2a042d35062f2c166c7862f35c8a831461bf2908c684403174cccc0060c76d8c207020053c5152b5a4011c6952cb012320440c88084cb11165850813531e60a34c4785283307424116badb5d65a6badf5938bf9f3822c6304f102e3c889510e5364d1024b1431989941199b4bc5470a16ebc46a8cb1d2491f6bac31d6a901d8a3ea13608ffa08b5d02106941ebe78598249131da6208388306630230a247648a20615981a56e4c06a30458d18d8334a90c4c00a2ea650c1c115451736f84026ca15336a54d9d2a842e70d6a1871eb86af303198d1820c09bba18106c6387534ac2481860d3ebce00c313fbce075c617253e2fe0367c9da183aac9299588c2891a6c4083154060d1c403dab8020e2096b828c344938e08ee884c8d1b36359a2479717930803be50c0e7c6882c9173d80e1a58b1a40e921075b6c60034b0ae20ddb7dc1164e8a5277839d65383338a30a06f30a63e61566061f255e6292c8321f29a91eab140ae3e42c8171ea3c307306106734c178fa2cf1adb68c58b64c03892352c0440e515ce08505c5f070851466dcd0e20665244d39e24ac1801426b0a821494c191e8c30c2881c23a0f0d08c075e9461c68b076136a53e51541bbecab862631bbecad092d1df38ef968b725192d076ef4532b79284ee762abf5dd342dda76e45a9319e3ad93d99e33a8edf4a12b2798c512895d241ba952494e351b776a64ef61cd7a173e8d68fce8e752bcb6ea3e1d4d93e73772e5ffaed42f49b6e25696fddd36b5a68becba2bebac5c2d4c936a95bd1b52446dd5a61ea64bfe7244d763a64c58c46663559cd212b6614b24c99de6b2505d5e85664e5a2fbeda75c942474757cf2a25d06a64265ea64d9371a182b6a254100b2eab143d6a68bea21eb8b5476f62d435697218bcb9075cb5052c6937da184d283a20ac2ae4264d5ff4896d294d912d71ede28752b2948b7228b625a85ae1e29b26afda68f929cc0c28e1459f5da678eac2b23ac927a2c9a83f20af631dbfff810b14dfa79facd7eead8473d75ab65ff4125294fed216bb2b057ab87e0529413cc9d87396130c6ddef9178e75e3b550addef853aad853cad27c60161b9923c7225646a68b40f4feb10f66fc810bd861deb86c463df7eb71ccfececdbd4b402648c18165175b5ba5d770f4f632a7a1c373d4efa0081bfd56ac5791e778853f3070952479efaf8803f12a036c16482c904a4b37036e533fb5ce769249cc61a4f1d78a9492d8b3b7f6c77cbb07504e366b6560c33bbc2b02709702b49fba63f75e45bdb5bf8aed8b7185cf5113af3914dfbb0dbc3eec8a49bfd892a2592f617b3af74283bddb31b929d66b5d3e80eb0ec6ac5865eec0b4b80e14b8c29fb9a606bfbdcb0ae08942bac65c4da1ea56e418523284b983a73bb0aa64d5b093f2857a88a2b942ba9a518a6cf68c7f86bba9ac6d5173ccbe9a1225da7b1cc2d10d9bf80dda4ed6d574416311d07a2fba864edb495450d32c666240000006314002028140a888442a150309c6a9b281f14000b9ab24464481408a32086511064103104194308010000630c88d0d4900375cca1d5a4d723ce37062ed9346c430fdaa20302e9c162470da16d8d4df4049342b18300ee09a0694e91046d6c61790453b8e0d7c5ecf0aaf9a74af07cc8a3684dc86052d0dca3d2572421fa9b826feefbf1a6c5cec608898130d811f8e7d9452d7351c83fceda5653ddbfc07476a6bf62e95fa82bf19321990a78af02f7e7cb5a320cfd459d22ebac62ab5ce8768f79c71864a10548404b77bb6f0527e5573d0dd40f2335db85011e851eab4f493631016d5d41149817d69dc1b6069b57f359a719608154b751badd8d2d86d0191324e2a053ade5b3b7eb85a05eefcc5aee10c6b0c2e51a2d5f0fc3317756e0858d8cb28e72c2321cab02636cdcecb946e4d5e046d74053ef53efbb979e20cbfda4d23b2ab782f7112a4e285097ddd8c0d7dcf28cd9f916c7c2e2c5568329ed7a1209eda95d1f6f4180ccf5fc270fadbaa11ad4600e7be6f3973f1991c41a18ffc525a91f86f9c508ed7d007a425db014063ccaad2699455cfe3d698dbb4976f82ad92fbac844a027f44092903d6ad03f4ee382a79071730171d6940392aa4d684dbb999247f10f7bc874d64b883b37ec6a9c06abc364b4c2370a6e9a49353fc50371954adba91b1aef2031e14b77d1053e9d2003750f9a4c697af3d830e342d74a1c784d7359481e3788445dc5ac73e5a15cce14ac5b49f44de4838159fd87fcb5254f0720a26dce18351cc9739fea569490f379e2cf108493a87c34911d36ec1cc0026c1fed950ed963870ad3c241632d36f2f400ea34dc0389fb6f425a45bcdfe9d350aaba40d7f5ad6b6ec1ff52a9a73f9feae33017da9d03898a0d90dbdd038501f4c072cfe9985ff38e4822f696e85c24a69d986956da0d78c59eb83693148f571581f8763498503b0325027439d1254b96c6a099cb200c6b927d80359cb036ee47692d2a18b51e22478dd3b30c825b7e5e97e01c3b34458ae1e4828807af34d7e46c32fa8eefaf74082910845d557fff5c0a5f2b8328ff031326f1c1019f65acce05428e67ddaf484bf853e32fc61e509c74329b20cd65ded6ca0dd02ff154e8566411e6d2affe00216bede025ff8379190e0c75616725e6ea48a0b28157ea97716fa471425de1ac1694c106bc0798073078ce01c607fabfc7438e94735cc07610e831d15b6d902520b6180a982b7187ead6351210a7b84cf9be18dea677020cb0df4338d642d7a3178c347a67ef83f69d2a4ccc89b1db9712a3f25d004def3ab4b73a38ded25008e5870613a223204e2a8fa9a7a968ba81f1af8420de6920b8152d9402ae1a325ddea1e987b841e8fa0a2d3e742d5040601c18eeb9c954aab181d56a1420a134593b6f0f0f3700a970a7c0900b97486fd012c7f312ec4ee589a2f104c84f3fcb3f1ad5c55441cae65d24460a102afe71a102e783b74080c20c1a649cb04e2814cf463357328b07b97b7278d556e240620f7e8f5f14199124485192cdc693fd839e9982e7cec52fb7a96f564b05cc858c4cb4f3d8c6451c016c829b5d508f22f57c6b27020e17b43cb2a39d9f59b7b44aac601ff970c9735a541da42fa5f492282a197fc19b677b990186e7d99d0075724f3d177ef2fc5886a0c0292b6ba29a55b62b63efba2f8b37964e8d059db649a4a017bd995a1b7ff8e8b2cd9948bca23a1ac53d449f350533cf4528b1c22f44e78488f4ad77f9e41c82cee21234ef3913c1962a0c5184f1b918b18295f5703890774ccfae07603a5cdd647538810be93f6a938c6b7307c54a138be373d86c6c87257e82862132f7d33ad69bb600738aaf74954a384432239b0c1bcceb68d3307915cdce8b7bd2330ed59b49312baaf85897d20022284157cfd16605d03572d2f085711248464a965f01038a5148769b22f1434c18a9daa6f21d646b35d833804547acaac9ae0b3c8d9d782cc092e5af51f836aaab8686de4e793b671bfecd3447a20730f3da0ecadd60729ebd0f90cddb5c683bc877afe8875b4bf9c1cd2026f2292639fce437264842489c388db189f7149bf2f3430409fea07e4fd6d2e750aeebf5c0dc9d25e0c0ae70fcd52a070ad3509b0e9a320253f0a82ea2f40454e52ec05e85e8b5c4b05031dd6576b24b290fbfe1ba443b3af4c469eae307b13730366359226454465f4fc30e6c95da383b4d2c6858d36f9a1ded6b28f3257be1ed3d297d6f50e3c4d4b1ba8981a05778552261b547628bd7c05191a7d6a1277a00288faf7ceb106a97fe6ebaf2c24aaeb6549dd823b8379bf2110da970f4ecbb72463106e358617f2c892064d711efd333871081e7828a6299bedb4c72c4b2377365af4fc971b9f25aa5874ea4a6934ad1f76d6eca5f3d586d23f9ea506a04ddc13fb216479f5d30737227132693896daea0a42d00aab4932f06610af722180686492481047001f1b5b91481e84a02c19fdcb853fc4bfff0d60c2747686797340fb31157d2e3d757c0f3295ecc416ae54a8d9c11188f366f0d3cea941a66e87b868448ed6f382f444a0bda0da5647129e3f7bb938c31cbcb832c31eb28e958f4afc95e8957cd04dd24669151e25749840882ec18d220b75285132e6ee8804cea6203fb7b322aa122ece02a278ff7022f09e7d6acbead7ce1e2b8262e08a7a4638c361951b370e10a3feba1c9ffa3ff4fcd744e3e74631b8cfffa33701f635be1317469395c265013ac76219fc797b7d626d395a0ec2484444d78eaaaf92bc82c29478ea4e9f13316aebb3a4bed6a5a542b3841862e09abdc4b71d82b632e9a9f171945ccd2b27850ea290ee4778c2e5bd4d2738e8f6893c92e2b255a6f328baa8ed9b639d09d953613cd078744f755081f568eccc26e795fec6f2f18a87405312b6cd64a866dccc0959c2d4e7d0ab13668706df6b095971ca0fc83729b863d701c5c3ef575c2482f4f0debee90b3cfa62e309724d13fcebab7d9aff519d9eec474c156058a23d675de58c1d5b0b72b238e5c464c08a229c85626d09fcb4ec466db18310536be245a13be0c7c5728158e7bb57c0d511132f879187f56fc3208165193f2c85ed5abc06f105ec8e780f4110a6d997c0d3e15079fd4a3c6988718002cf3d8a3268dd61333c9cb33b898a693e22f90341682f127820b0891d9c9b8e60c154f43035d502f29eba1dda473c64d2165571774f3c681d24a9faa498df999af5ca31d806678b0a4f8d63898530e54bb8feebbb8a3a9b6c4649a71bce208cef368798f3d9e29a9696401a5e5ed8e322af089a5e115087a58eee94a06bbe10e45bff371f7f66391a3069ef4cfbf6a627596621691c97230e2426ccc3ebf393391295046668a343ae56abd17507643d11b10fbb35e3b0c040d9bc5f6a5d53e0c93a3c642914677c3f4229a3037880724a07408eaa1c8cfa4642828ac084268063d48cea700955be4bcb5a15426307a1e4898c92206ff9462f2b6aca1f61cfd67951575dd088bbcfac1b4e0fb37a75092d821339b5f0ca3dfddd06649d9f8f5dbc283227699cd253a65510c84046b5c71e8824d2448eaea6642ada3846ac6374449e57de714675ba50277fe50928725fd963739a2e63585682742ac2366cc4fa0ec6cc1ada4c9f9fccd6bd828276284b74ad4fc54f7fb8ba4ca6033028493062da2ff825b35925c67cb75f3718dff2265c43a7b2b45fd1633135ce61dc994c58d7a6595c930d542d3bb1ff73d62f70fb88e43d9a2e47d888daa3b5fa6c3f6a9f1ad31b13f40c67bf52e5807b2652758896a69619b5759de0c099da76909c5e9bc0319cb6fc0465402d44054c3f3032d8bf517cec179a1bdb4627e621804b6a444d7d050cbf9e8ccda074dec88fd87c57f38256340c00b1a5f1e01c19ab76d3109e53af0cf272f766235c37e01bdf3487f53316f01a9736c6b9e4a5e5991f4e22bee6d6b24e72184911d4e9c7955e9ee17c0cde353ef226e6cb589570efb3e01c40db2ca5998c1e247d5e2b8c0a90ef80274ccc0f28c129bc2f7f54ae0d37a02966c3a84fe56358c4a232c981639961bd92400a9a8cd6c879c2531c4476dcd7ae8cfa67a1cd5d5e640248715f894e4059113831d21026058d92027f452863997071c54d99df8d26a0d260c0db532d87281858d2fc317245528085604b246a885f64e466ca69fcce9bb158446b954e681c493b4b2b8873539894eb70786487f375dd5f5dd96fdf9e443b8796a92a28a819caba11f6b75eb6b862b7fcfe3c1e6c473a488eb5fd3c9d5a6d6e0034744608866d8add11d0675c665b6ac20ea55fb661816c006500c48bff14b6bd4e050b0015b1724616030d4624599ae6326e6fd90022021e166d4a84e685194c9d52c4137485c47eb5724bc7072b1e90efaae45d05866caea9537fccde205eaa69f3e88e1900ad3430e156ff8ff30e717222a56baddeceb188135790734b99a181cf2d369e2617098797d424e7522dd0cb96ef3d6278f9f189182f8294b3158cf587f032d5122779a0904ce024e5a1f8a6d6e06e7162dcab3c5f55f01028f0a7e13812857dc87141b2ead0a66ea829f9839248640a273daf00dcf807e711682d90981a8511df71502906c33fbe04f2498735b6cad9b04bac891f3b1324f5e9bcd0731fc78481bbe86839bdf7c5c5dd7ce2b5301101aea334105c4180648b74b454571daed62a93c2f0caeec1531012d9fdc2e20c94540d654f278fb59c1b8bd125a815cec5e5ae85f2e27b9f7f2df15727b37ee4d381ac3ea886b60496300b65c30bc5c5dd0851342d43a85b50802ffbeea7f74f04bfa6f66becb9099769d15f35de04563ef841efc4a2a2815d246dffd377a5c9e1a5466d5c271567eebd2f305a2b5322e78acffae9410411988bdb8a4b040779005be80fc4d9d785853c4a6fd71536d3849936caf90f7ee90494029be1a4c258eddcd2ba8bdab5d46f0be9273055c1325bd47c446c0054a1873798cece702767d625b81afb48cfbd07f40e07cc96796e46b956a2850bdfb8a0f58f0dc82afb1db289a8d094d88e0f79eb899ee8a440703b04c449e604294e5c6688f1ea5384a604aadbd9f6406f537307eb4fb82f48530fac954ee217939bd675b749e6a1d1aaa16d2a1e3170a7400d141473d2de62496941f0777bea68f3b1b1ffb293d224a26f6b924a856677713046299ecaa2f41e93a5002214bc8dcec7175176b6cb6362850e403766101f0dd15bdf573d688610c162e60aa0e79438ea58616524cc5aaa4d060ab21f40b4d2a0837183e4a212bab5fb3120d37d58bdcfc113ff0d3c24d98eecaafa8a7bfbc8b821dc33f79ca6cf063e6e1ae8d27833e0c6d5184ceae55e6938d9a7ddbf7d81abbece6f1b62a5045b44e2d73f4add0ee7de36bfb9405f669c4c1bc1b2c6a0cb83f9f85079484033a5d61934a5cd8aaca2571a386a2270683cf5240682a4df7a7b172691e1c3a00dc0426cfb5399921e2f5ee9c0814ed6bdfb58f6100c9ddecce8770f0bb2eeec4801f66e179d11960e884b981b1854e8c05ebf5eb85930cac10b50222c2e1d4c783aad6ac904948f832ff3ff13dd26ddfb73601643319c995630c05effa8b561d847259099c88a7000bb9c8c8fd18a8a306f49062b93cc5454037e013d6a5b82b2ffa12325b0287d33f6614def781d56887007a04f4e4f7a09bb9c831cbc1558a0ca56487f12669871da0bac13be4fa25e25024a7adba77be103900e5e6161c0acdb62171b20a695967e2d0d0e3d2cab135e83481bb3e1741773dad9345e7e5643468ad3bc6e222ac7ad32f4027f58e462d308fd283c71db63a54c84adcf87471020ff5a1000bcd17c6db68256ab24f2a2b6e81a6e50bc9b2e051b76df4b38a4b2c65661b9f83b0adb1e1a2c85b2a50b1af683bd57f36146eb0b22d49db107a40219950ac06d935143e7b1baf31a229cc7cff218557e6e18d73005e0d1100c7f323a5d78939bc35dc5680b4cf41a596e7c04705e10b03c1613a31ee107371a81661af5e454118726259e928475b357b3dc9b8fdff6e3255f44109496d940942869069766a1de5d21bb89f96b529702f473ae830ec74fd01fa52d2bd7cfa5411957f199e7f2ca702efa6ca53ae25bb661cbdfb8d92715869378b2fc6a5bdf1085a701720b2a52055da3c509a3105bbfcd165aa44a638b6cc51ff0525cb1cc13a7a13d3649e677a126cb41055c6442b1cec2100db75706ffb75228f67f8d5fa09841f79cd5ecea8229d0cf8787ae6898f2ce08662c35cfb732950f6b2c0d95c9459122dd6e8d6d9d5a3da598ec47e3fbab14b8f988a3a55eae6e09fd6d87764e1861e31f166ac09ea49387ade84f0c33008371ed7ad3c6191a30269c66c751d99e2920374d50c5b5ee44cec0a9d9169f90433136859e69e09e18d524a5f4ce6d58025b8154398948c1be4783db935f2ac5a248ce29f7bdc425102f4308f19746e550e910cd8cba6aa11785f93e8fda6cba32268dcc6e68aff85850481c6bf11d2afc0d8b812b2c1380c42a8b01a03ce8806b66491eb159a64a2b01d5712c909a6230743e00f86bb380dc7b332b06bf410b434aa111096f749c6195659ad1c1e738d5fac658dd05094af228deaefa87f03e623e3e88d593cf9cfa8c04383d472a61797c4718a524662c4934daf37072663a1c17fa040353830fdacb1dae4974326e20893cf6468dc1fc0d977daab0c318917b221d35d0c01bbd4228483efc804c82c020c2ae54aab227e6d882a91b420783ccb1954a0dce21f2b00e947414ac2eba79fda86aa939e58780c8253cd8168760b224663c07a90dcd67177223ee8dd6f30609115e8f164591b314178729747e56340328b50a00bc900980c7bba9439811889a86a953e48473c9c47e3bebe9e9372f251d9bbbaecc8d80c0169f8c392e6e91b429186b2d6eae30b9985abc97e093d4b11f322f548927de6a32f1c03ad1dfe273c4e56042cc96c395041110046bacc813f195ad87a9cd90ae11206f56271c93c97fafbd001642d1b18f516ccb916b2ab601f46f12702dcac13d817efd79f3cebf5d2c7ce4a67bf7966ed6c3b7c4bb6d5795254099a230c926bde7803c506837526822debfb541422025d5c1c02a5810a3bd23495752897383b92c02e24549d7b2210b0c0ef5fb4f4b7009afaaa82def092675fc0f6332eb41e77f410a4e5be715b3d823b8f55b29aefbedef43152bbb185b024886029f9861b900b9b9083cdd364241c4c1151c2a99205182b095518356fbc64f4bef8872ebb9e7d0c00ce476cb3570f0ea0342035dada8af2024aa96564260b7762f293d28b16e186750b009d3a4cb1004ad45b8d9fe697a05ae8a24452a1260c2024ad23d31d48af58bb65f172861604e5bd24232cf74cf3a8ec4e17b6c0f59f791ddd62120d94a70dccc6314138a4fede758b1a622c785ffe61f1995fc0ff348b6f4cc2011f29980d6dfd6c9511b84c960271d80a754993e9b0739535300e0f3d995cf1aed410105a294d48dd54db35fbc6c87768134f5890addd6f7abd01dbc476432bd023d7220614f277fd0654335d9fcc376240d690bd18a754c20e598fe99a41b5fa628aab025edc7095e3ae41c622abbd09e61f56e04f6f441e62af6b81f6aff82c4756b4587191006665a3d83c103a67e8a2c28d253ed59602770a6908fe96d0d9ab50e43bb0ac32039de831515f097f5e4b9a717bb40ccde2dfe702abe46f97ba333c1887436157ddbd3120377599afd200b749d60d82028b38fb121fa53c2cd122412a5075fe3503817e2969f2576721c8932970b41b6762d000f647d142a9fb508d2ceb213cc98634b5e987d114b2cbc306f153c735f35f121e64f3d9a513576651971329ad5a8107ca5daed6f5cef0777c656ce5e76efcaf03d3eb8a07da2079ea798678fa19c284c2df23c759dbd3416e336bdafe4d31c22010ca41345705fc5120b5d5783e543577cf91eeea98b6fdca501c3b3811f582974db336558fc0c8d0b30d83cabf22bf45f55daddfebfbc421bb429f8986db1ecbc20130ba27e801d1f1003f8d2324ffac2d70ce19952b4a22bc9c5b23cdb0231b959ade517f8e16598a63416b620857bc9fd1190116c529c0e16bf63fb0890c562995e4753652ebd926073df1003d39081562aa19e41a7e02f1a4e78fb0747c8eac26a64288ff32e03a8aa5338b02cfa945a6b3bff7cd886323daeb47616542ef850729548d8270fa1b25740405b0d46c2003f87c04990f66c382c4ff6dfe77d07116aa9332720e3456270acc3450c29e1f4b2f80ff9b70552919321d45e890fa1d06a2d5ce105d85095c7e67c789a1e3047d10a6ddcd33c716c078414fc444b1e8891434f5f9096d0ce7c6efc63e1bbfcc2ae1c4750ad5ac217c3904af7c55d8747de1d70be7aa1e7291311feef4db04fdce0d40c43d7a1cd7927e11ba6bae1ed8f1b86726d06c84cc4ae77ece3325898a78780020c8806bbd8ec690d0ff4db84497a24416a8b619d62e53c7d26d6d31b4e0a485159869126bde4adefd4bf836ff553e411bac580fa246e342531fee8b57260c6cfb50d2b0049cf0227b25fcae7915df6d9626c86c370a533e5335f08ca17eae088e5a3c1c9512f72772329a8897e1815b303581e3a5d6bc10d3e34a240c606f5a20533e47d9853db244a0c641d810b9d346db675537c7f5b4c812d8f890fc0ed15431d80bf23909f29025578c0c97790c849a668a2a2c81192cfabcb7259514175d3b43f2fcaa04fa1c3d00ba57543823604d4b22a68116aca40fd7f2f59ed2772e224a311061810150aa7af9b89e50fe3d49d40cfa87577c09712c670cfee67bf0c5508f4b589b90c7087c1cf8cbab99259f5d5ebe4a25fe2e0431c4b6b99cca78f1a432061f5e10ce8a58094fc442af5e91b69a473ed69b9c6ffacb092e8cbae453ebc53630d40d57509b5171af2e593e367da0f2f02c521fcfcdc0d088511a9ccca8ff46fc3e7f6e2ea4ce021e63133d2ec45f1b9d708d198f65b2d24c5646c649ee5a2e2719dd029a8848c003f7d6e11bc6720946a29f584fdf75fe62d60eae5942d4008e0fb8523a8131b14ec9955e7485ad9df0b354db3c1749980f3974c4784a0eeba8eb9701717f89c872a645c4b1f6e2a8c752617aa4d220306174724bb3786de6872b75d782d5dac18bddc184adef52e4d3937102fc55d970821e6744f7f1eb6e4a0953b07f7102f8fb9ad35c9259b5efc7fcfb9235870c6a631479278aaa788cc75198e14fb02caae2c3029cc451bd15bd6d9794d8d79e323be17b0da039dae9d00ce462e0b71653254b006a2a416e95cebdfa45958cf3f36ba300b8235de6dcdebb768223ad39f7921420c87cdaa99779e10d25fbe58f99f018a7385ed724f889fdc852acf6c3fd2b5339a094965adbc4bb619cb5684a2b81728f41452e8e85a9a32c533f0cd1094a791af6e91c584b71beeed55099066592cbade189b72ba7fb68e662d7d9b8da7a927b1c2bbd3d8090f6d7de7308eeefdb92f649bc4cf6ea96b839b30506cb7105183b2c3a0f5183a71efe89772b58a6f37280853fc9d5a847ef73ad6c04f79ac46eefa4e1ded511da3c68e84b13954d8b2061ed1d70b156de7bd6b5616de911e689cc276cb05cc34887daad156b2bbfbd6bd689325180fddb99cab17e29589da0fdf3ba587d5cf4ed201f8711107e39accc80db9e8d0c0c2d1cfdd362070182c778316229f0b8b39092ec4ebc2c64afa58bab0d367e364f9966adc4fd9a0b7b00d0d9bde643b717213c8b055f4690ad7c2bed69377052bd223c157042604ac51a1e4c70ba4ff2d33aec089d498f112b4b41ba04511628016ff342b7ea4d8b9bd0243e546f026740d8f895cf39f618ee5e6c7007c15dc4db073f7b56f79bd31b39deea881f5264a36458266dc201c1c56bccf5b72d26d769d75dc62131e68e6cc9d6196e9f2e314e32cc22aeab1fcb62ded1e819dd1e9cbc5ec1376137484b83a552f01faec0e07d7b84cd79a0c7d27dfd6560b3126bc626266d3dde686510410696875a193e7f5833f8fe6774f604edaef39ce9c8e2fee29dc868828ae6f344d45c805b7bc3017cb11d9a3a7398b97ffe94ea1eed630502bc24470fdd02186e847dcfb946d0969484c1cf77213cdaaa8ecfdfa98b1195f5ee0870b3e164991436c1c4f05f89f6584721107863791bd6b918c799f3ad8225413db5b909798cc56d21b9285a66693318ed3861071ee7710403ec0ff7efee9a144049ba7d14a230c14102fa1de8d56240a08bd549b301f532ec24d48fcc10807635106a17e53a918011eb695bd848fda0ff490c804da7db58fff19e51e39dfdf47214625d64fea1c973ddb3007d5c33fd01664d9bc9b04123e826671a2a7e25e83e28055b61ad73794a85de04356e60cfe307e14086755bc84ce6ac73384ef0d9bf7d1ecaa66deadd57d36c10d1f74538d1af710c084557948c187ee883f6329c99b40292b866bf79155f598064f89e61d2ccac48ac613827c97e128ce18766e7114a6570e7d3db8799227549ba5b34078d74efe910cd394924f27755d2713a07b1c19349e336151291372df3f6fe56a1d57218102f822e9cd7a3387d82c8188bb931774636da73bdfd4a8582e5143a65c1e9f7becc5ef619dcd5556b4995a09000b8844c1e221c3d8f64c2f6ae34c20733c975fb00db5cd3d3563ccbcf191da754621d100c7a915b7d3b1e078ef2d7cecc07bb536b28c9c865eea8a552b96217caf5a92e7288acb180451e67ef1059465ef67b7622dd2ebd3daeb89d4062399b02183b8e2116d005b6e866563e1b1de58139381cac69fa574b3ca12839f1eb46891110c649323592e231f155d900548b658ee51a9af10b6f2d7860108740823eba52783c551b6e06947df791261d372e799ce4eebcac667f38572e61a42070d5421645202ffb9348d59fe2999333b3fac6e8f2700502581fd31f46477e45840dba4bb46e2395f95b7790ba8e69831cd9756d15b4e36cefa507f08464cb0ccf5bbfc9ac7aabf7e284610b164bb8d5b92b11d9743908825c53b3fe178002f0d68079c4f88f4c35cbbb90db1e26a7fabcb458952b8b4f9523d16d00fc37796472dba68fa007fb9918c67f8a98ba815f86daada277eff315a139930ead8bdc16042c913f7d905454398384c4a5da115fb0217ac67fb3c6c0392b52261899e8ac5e373f235af9454e0741137f300b6209cf3f54c60aedb94842f7065caa919cb1a7d19f7492d3c1118968678f39a130679426a8a2935b5e5be30a7e2a6a88fa6c4aec976c0e0df82b54de8fe4a7a2e5ea39c7eec1a69c6985c95aafa2f25ba8bb310d1926551bc582875d9b5d8dcc2508c00f71e0130f896de1c49857c948d7483a92b4f1012254e47083be50832812aaadb9fe2c2a47f1f856d5f44882999a97ddba037dc40a88b6a434d50dbb4b9c139aa7d07a1ed013aff079467d9e7384b910f25528266cd8c2afddce7fe4cb3ddfbbfc816d5e6296cc424c6c3b07317b1aea13bf9d00729377a749070fa8995e08e8b9b3a12a1db6913e5449fe8c8dc5aeca277443357075e0f590821207c780369446ea701ede0efa2b769918e5e66514ae6ac1fb4ae7c69ed0ad7053703bab8b863e3a936a14cdca2ca2169b50d05f7cbdef977853731df999b4442f83f3a8661c948296cc3f5014b5d1e1a973a920ed3aeffd5ab702ed519ef20002a398e72788ad2a0567fbf80aac395f28a8f3b993123310cf897e5476ce92a7a17504cec30fc21ecdd677ad287319a21df3e5b804fce3527262978974214f530d1d4dd240a678ffe3f94277573d4ab6df4a25db68271cae801a0d220799f7d64aae020930ef51e2c75a8b92552aba3ade5fb73e72408ea87284576e9b44c6c4ed4ee19fcade7987b39fbd5b9e9cb0f575084176068246901660587b611ec9b5c6db454a9f89628a35ae8041fa6ab5a4f4356b2c7b98ec5fcdce43dc61127859537dc88a50b3b3a17ababe213cea8230855a924485d933b1bae292b835ea7aa96951a32dbe4a6168ae38886c5bd199ce85a37030c90aa44e2272e24fc70351eda802c2c0c79439a45c15a31b3b351459f0342e562d9611d3ae9ecb34bf9ae0c5d0f81e067e4a972abf1aa2f822058eab122bc687f29343a74c32d5c96c590da92987d1ecd5882df743cbff9fe9a515a1f3efd595880b50102d6ce1555747bb196b9be029e4ad788a22d8ef74367af2aa3076cbc2bacf46676bc5f76dc6c25d035ee6d121ecd2c320dfaca27d28befaf1c35e05b14f64e4ebec53bcbacfcc5251da32553ca5cca3d9360f62a7108fec90e80642d261853262cb6aba91feef50dc3e920e169cbdb7ff773f8e8de046ca755c2af1dd6c14006ed84088c01f15c1ebadbb5906bec9e4559196af6ebfc4c12c4a7ce76b2171588c00f53eb4283e717db5f5675d108ac56e6915f1834ad390b3b03dd351717ea6b17b5024bcd03af387690ed57f575017efb129992144f1772d1311d8f087433b1f3bfef8fb26d93f97fad8d0dcdc45fa67aab64504a1814fbc09353ac456cbebda00b5698b8ea13dc15b039867bac64469a5dad31b3254a3b20442e0413481ddabdff3b47e8b65a342297d68b46ed65e3f4008b5553a3a22d2ba247f9571842d65f64cb1e5cd1378b656dc391cd96ac65e901e2c0bbff37347af4998f519667df1ec5b41c77c3590d977b8c4594f43713b3687cc93cfc4767a2cb65417fca2aee4dbb88d2475df71f7f920e267765e5f225ddc74fc1109dd63e2c27d0694cc5c53d2a04f74ed324817b19ff38b5144cc77531df0cbb745aee55808aeccd9de9e8ca2d89d271d1bc61b5433e02625debe08acc917fb7ca1383ada5eb967458e016799ae4018fc813206091e11c32ad2789e9b60f53d9452e26f1b1f7a81b1a989b1556439f613bdae70f94c884746f0d11c39bcbe1eb17c6656a861a2b7afb6cc1af563e7e1688848ab30ef00046665aeb2d61506f1c738c086304f54e5f3013ce3185f7cd8cc298e213500279653ff118ae7573e9153729a6e714e7ea8a853604afb34bc3eb07d2a63643566bf10762619b4d2f514026388d23d8b534b1ab94948f15bfe0ae1e5e83decd52e23a18422fa2576ce84c7b987f15c8fde0e1aa14fbfd3a2e5a983d448f658a58cd065f04c11fccc0960e4b646de68c10952b09df051a730aae420e792acf8e8bef3a979cf5fac658644281d45bc9a51ec3ed58fbdc056e96c0642173133078bd1c49a4ab97da68f7ec06bf601504cae8c7701df7ff7c47ac7c1788218311010e9ab4436c4b531bd7b9629c4f401e8a685b292e1af6fafc954892930cc4e3daa0c968012eeff5b4a1986202d5d78585265e363a8bff5aea69be86778237afdb6240c0be82ecc6326ca2d5502005f42a0ed67b4957699fd1b84292ae33e78e109c20d3de9b219b9c4a23eeee1fdbefb801ff21f0eae0be8499cb0ff2af3805f1e6649db684ff13eb4cc626558c8af52fc8f99564448571cf04b9377694e81950d6f9989a5756d014798f3d0fbb1bba786a011525bc6fba7e2c52a4c17363628a4c3e1848b980db121ed94e580ce0c939956c12157bb6f5b8523f0654939c0232e0450a7516824c4c978852834b43e32a8d25306bf8c20f5a0024b2fc617ac1554faefd02dd4b6334f4fe41c70263775a68f59e354ee52f4d931d6b00c2f4a7afdf3ecc864fa41a98821126f54c0b820e73e6756e115f7623ff380380477a82ea69b489674d213c1535009176532e496fd83a192d93c33b7937bb4fdcebca835f0d138128f0cf2f94493209eb7b5f76034a30f8f97b9a3b13cb6ad9b2e6b734b53019042600848c46fc9f4636d256cf72ac74493d1aa722a61b0d6769cc1b4bc50f8000755fb4f119986af3f7f9153ee67da77a0cb0fc5215dc81b1e74d75ea9e73bc1a053c225ac96f612d1610e7959109931b6372b37cd6b932337810141a37672e6020a0f3f0a69fddddf9c0e042b2af207c93f7e5524b384ba23c714d42148775b7ce23a227f43ff0730dff821ee140a0b5cff6981ed33711d2e0a8616c831f98cc8b6ca804d7f5e07eba49d38e22cea98d299b9e88087ff08691861a951e79457db24054e483b2eadb9d3f746ebd5efd2531586ecb0bcc8e2847fc6e0c9535471b3b5eaaa0a3d9b1a1d925a405c76acd5216ebf9e6766f32aecd060280d846f182a8195a904fef37a0605b1e86ce83e9e6da11ec25f13e389571759166d09059c7c95c505d2e9ba676ec2203cc2277204019d518a4c08757c4b0bbf8000e3be1e971500e1bd32511d8bac287b5104d192fcc76a21dce528cd8370dd012c13e32902435431750dc9f5ffdb9bb0618e4f5346821353321c65833b0ba695017997852db47c718480c30e97007b98d518fb3d4d27be1efc14979affed6f8098224ae84c9d6b481f945852827442aeefee7c8dfd0ccdc1b005cb835d064c58d335ad8e474bc8a9ac656e59c5af7184ba514347ba143dec8df241b9aa7bbc0b9839ecdcb16c0a52203c372d9ce80ed47147bd47ddf4ad69e6d6d72536fa63da27bcff39c50fec180dfc612370dfafba3be709a008ae4346003e28f992cfbfe936b3f79a394e14c1d09beb3c32e0a0cdbd67ac85b6863cfdcc9f13a062977fa768c3bb905467f4b8b5d15a888316cdc9702268282ea2671333d7c8693ed41bf080fed4c4db39606493e16de827b6d94ff6db6756aba5a9e19d1b3929945fc131efb31b21a20ee5b84f0feabd4f14ec03e26e9b075b2c8977e37404c15d66c93a08bf217da316b3c0548bfdf884794f334f330020d5fc3545f62eba20e95c4c761401ac87f0824326a4d413931ec664eca3199befd3a6f7dda6f866537cdf34bee726e7491e894a87b8758e749365cb0ebaa30c9293385bb414acd212dcd2e57a0a8a5ad3095881f65ffd13b7880182cf16ab085c4ff8bf8bf0ec4bb12545dd97449da01cd2e1737bdc7fdcc4004972ecb55494aae2f0d608943cc327a25559f653e77327a94f3fdb8c2afdaa6e36e252e1f05cbcf6ca9608e6e249a41c429593c5acba6df2be2f8c6891d594fea051a9506bffb913ee0e0b89a517a5a09024a70a78df66becbeb2ac8695a2b4580162360c11e9ab986110b528e3cf7d56338c70ba7427a25db33518b08121daf1a8d9ef4fc9e4e0ce9dd5d6498b0d38ac458c9df96c1a42ffa44ddae1a5f3cf0dc2d06eeb941f23b826af7f4b237fa2411ddbd61c5296930abcfe6ffd91101eeae075859e94d16d7748aa1595b471c08bbba3b0278b66f6e5e9ae248f6e61e16273f5bc0c01e4bb5637029a20902c90b68e46eb7add754f6f90f751f473c0decb9589778a85e60d2b303999c3a2f03bc0ed72d31567045622be0fa391f989b1e82677b750a085f8304c2aecbc73e14832541e669eab294a828ad6b911f6f05d9ad48111fafc228988282e7097940204458d9ad624528ddeb42fa793385eeb5c90417c067fe3d408db38fac67a9610c4b07a38cb6ff294b2944178ee026c1d806dab3cdce6b4dd40fe52e355c4e50f8d77215bb54ddabc9c7cc20f09bc253fde1bcccdbf03511cf7d4092f3822338e45b2a78602db0e8d7151f3a4db14dac4e042d4b72613af4911baef8e4632a509dc3bf4223416d76fa6d54faf9ad9150da7d2d7679ec093cc02ab0772ddc8bcc4632203a3f9e7d098a7010ebb494c2dc1ee2c13c3b46e8262d27b4c28a25dd9270b1bd6dd7b449bd61c2d28f38f8acbf878be81af420f83124a0d4447ac1befa127bbf112f6d8b7e5dcb86e51d8c82b7c959921371835184aa26d535626332557291d377279c8193d0e06c2255371f6b028acddffcb5ed6a39b7c3756aec449d91ff560124c78c657c6cac26238cc8c27143d8be3f6bfad0cb16373bb653c56e27128478a8fa171cac4d9c347560b98c133a97272d282c5fdd37a3098d2bf2c6333b96809f46089265b95b96b0a05cd3ffaace3ae0fd59eccb2843c5d6868be717797864b352dca0381a66e0a364f6754bef6f4bc6a9358c8c14db743e37a8540e90993ad590ee447dee0af45d51208b70a52799bad355e92d4e6c7ca8d9cf2fd65d5158839228a165c963a4574bd6afddf10de527cb170965d122813980fe7717d5275d2caa7ea137ba008c5578bc84fd6fd30849df64fbda79704dacbeb610a55a9d0140ac9b24f49e15328e51dc27641edbd2a87c167b667071c5d3750a62042d0a50af263a8cf6f3c19894b040d22219b6c74c654d0145239c174cf0983decef273884adfd1f50b4b4d23e2e99ee534399af07e825e6636df8274bb43b6748cc4215045a20d9d29f91496aba3321ed9cd6abb2997c455a6a32b90622afd5d42ec2b55e174fd37540cd15d19c881ccae574ea1c6326ffd5adbd46d8e228541fdde8c6f8e131428f0c785d6e05e5b494d61077c1e37ceb2a1f629325360624486b71e162cc125c2cc09d98797706046ba921a553d7e700029cdfc39e5bf3c2bb3cd308e36e059a928e7043a3e4102214e03534e59044712b2ff40c2d9e3317f5ccfcd85fdc3302fa87017d8378eb58a7b7f01516cbc007fcb0ceb698170817bc1c71bdd79e463063bf09914e4a6015b5f1d3794659e0db611694bebd405a7c37114687e97ffcf12a31c28ea60078552504051052a3aebd6815edbc52a4c2752332bc6eced9a9c602598b33f00a1c089dddb14f593911d4811485fe90e50b03d304be82bb063ef9f0b1caaef472120440948a0b0e5e17780fe829bee4612fb6ba1fa874e45661e285f11f2f95e00ba9e074fe897b24ffa56fae96a761d009cdcdaa95f4c01acf50b8eb4570e3fbeeba20f24ee103aabb3a4099bc9fe348840c91c322510c11323d2e988525b0c7223bd3144d873960cf6300f25738faa8ad27e663cd6cb776cfbf764a591846693e80db0044bb4f17e299a1843f2ca242d7cf76a200cf38270d4604522da029fba014d3a277361803167203bfb3e4d44c207e611222181e1efe1a4224060e4962d30ff986a72e02c8342d839c0b6717fa8585a34868639c333a0c711d51c7e86553156af978dad204979772ac01b4d7a3e7c05d1ee5f8dcc89bb54eb0cac272dee0a765787400360a8c39e5d2df0366c35108291064b5444a3c74717c650ecbb5d7f729c3811d79027fae00e24b560f9392c473d639c48ee0fde68b4c2a3904989d512299f21564ac1e4b4a929bc4ba47f646412a2cb1adeebe19e91175da4e7bb1108d0e8406d266a050a739cf5d9f09f3504309aba699f721033f986ab49e9cec7b843f73acdb4d36995889eabb565e86c651a3500aad5bcf9113f45710cb5600d5c69952de46c1f7d42c114d128a033395ab6aeea3d834473dc5f5e6ba19bf322544e9f71b7c63b82e6e87db764cefb916385480c200dffac7bbd27c4d4301f0c1c2ec5a450361ce580d9cf19e8b2f3487b857ea13e78adbbff87eebcc48953d8e89e61fa60976e0b1c3f3ee87966c1ffb9d7cd80b1e292411967375a2055c4ec6d29e4c450c3240f4baa209bb3b1f0fc663306e6115ad3d6b2afdce796f9e9dc53827836fb19f35ef8ee04c4fe4cd8eb9d00a7249ce1a03b39ae7ac22085990d9c36f7e1ba3c72eff776315c556eef67f297da44f94176d65340a7711e2dcdf411db34846670109d9a65e185fcc4433dca42658e1d852308b4a867e2a5e00bed36feaab7fa4ca8356b343f034cf8dc4f03193a47e61740b477d893cc4f5162433f7008a7bbb6c3b06b3190dfac3117ba3d471a8a5b91d7d36f9880a2570acbcfe3b047316749cdcd26185e77aa9f85ca70f7ab1b29016ef4c85155a5f14508827ed15c6f6da4579a26abaa72c087f3cb49d14b83f1649cf5a45d81d89833321e95239b5ea5438d708b529d4136226f25e2a1cb3ed8386a86328a0f3bff19e6dc52d472bad98f632bd2b982d56a8dcf4e6cdcba2f5778ab5e3054a94ea1310406d811cf8bff765e67801ff105bdc2cae7d2fe74d14ecf0f4d2d92abd996ea316a315e316a98094d0379a16baa25be64d3d9da804f9219037c6454627d3c5c14ec4862c9b99e326c9305f433e56aa316b5109fb30eb9daad680516242a0a5311fa5059f49031fa785cfa71d9fa4051f63a24049339ff3b45ee72f7d49b774af4e3e12883ea7c8660c4e8cc22eb8dddb2d2bcd585e27698a2def63bf06cfd45ed84e5b3fcc1b9ad75d8e5bab1893121c1e1fe4eb524d3b7c5e0e3cd982b7bd83adc705ba996dac54a74b8fac2682cf3d31e71a7b096b4a614e47e71defbc243c94e4ad856a1d5ddc058e80628de75fa5bb026d36f2b0d1a81424ef94357c02c3335232954149809a346c7ce9b3f65a076c52880256d9ba2ba54d7ff1ce867d1bf9375bd7225ba61ec260181408d8f06c9d2af17b1031a3df020b5cdffeb5fc55a5aa70c4a1668c4240d4d8e80328904f265d1556b0d666a27d3098b5f6a6a445eaa0ba3e5d0859eb22f6aa3584f9c989a4464c2635f70d144f3684aa241873b4afec239f7d57639592de37ffe00386959f764029e6e871bfb77274d7688d18ec993dda6de7a49ee3f999287a218c78d5ddb4af6af45383b3744623f7cefbcc25ebe3de1d5c0db6eae20906ee812330fed9f673e99f0bcf79145eb8ad15173acfd715335dd63bc95ade462f8c399bf3666ec594a2d712f6794d4ffdbd8d5ad1185a6ee26064a2243f428862879b5a5def6e1a3b52963d91670da864b4f4d8ab2b402c3ce2d4979ef371fbc9ddafa3655eb55e0c44cfb38ff00e57e474f8887dc2cd0e523adefa35d1f671392781d54f4416cca02c8a2fcea9f74b5d412c8ab205b871a9ad8209403ce07e017cd0ddcf1bb2b39415f1504161d351f981fafbef8dc9943f584625da43923a05b0d5f9cf5988b59a883134770f71e9fa33aa2af07241740c7a65c163cb0e8039df50a8faa2eaba8fae018334b94ead87a294a2c9b216616ce2aae249f5d3cd38430b2d901025b20e8512efb9c6844a02c21ca76263c3500751cb8181b97e260c59670c9b0fc874485d8e0538ad0f802986662cf25d1e980675c366bb601e8c72d5a6b5814cbce4300d44624b539eb87169686032b59fe8c95acbcc26d93ff0257ff8c4c06a598dc47daa6a3201044a9eb1446e96cb9f27c9548bb5ae9150eb4db8f436e316ee5ab206879216099992940cb2a442414d57e2a95ef1f4e3a0f9075f52e138cce977752e4b5f3b71d471d66a896060c77a29fe792c95c243b8821b2c82c1286abee51052cf019f15c9e6149b3bb73d1728a4cbf3bcfa2f07c37dba23fe9cc8e5418fe88d459455c29806ed4c2996c2543a349d54d84f7fa414c913aaec4b6060f3a1bdce3e585d5b2d9652f6526ba9db9506b10bbd698e546e1a69f209412c84c6ea76f2cda2439bd5c69b25a336515b2bba2c0c54e5467ad2aa51d223ea91b5652d0c4002fb7169d5571e77faba43672ba0c7cd112b4754707f16628dac3fd20eb019c58e99d0238ce5fd155a3c853fca50dbec164fdbda9c29f73a63f3ff75169769bb0d8f519ab28e86b65d0d49335aacf50625af2df198512961969b6347a5c6d677e7f57dcc374c08329508ad8b664988e76b9e515a39cc4a10e98dba3f21ddc2ee494b077818704dbd1dbcd7bb06d1d1daf2d27f7b124afc74d6147d74864d6115c453c693bd1d3760a922306e37391777ee80335335f0d18d74dfb6d727267c02067194ab3372d2eab3c89cc45377ca6357d5ede6775e7285de0340c5272abe7e413b4c4a1074f1a6e086eb2eaa94d4b293a8886197105d8b7893b27ef33922a8f229503a9c5bf0c62147756e194ca5395db271cd0453ee59088d3b1faf822cb49d9b8e7f42c2776b7b1517d348336c6e17d6e87f21ee98a676935b684963a2a93f590dc0a93db97e0f175464040e04ca9c3533beb26a5389577419c7a74b8408ede494cedff0d38ddce98ecc9cda070b9e3ce14a1c40ff8d659a8081f87404cd0362673add444f949cddae44f2f5b784ee746a8b75b9b1c290c6dde1f7604c7cbe7a6a5cfb963eb32d34bab6b10a74249c0955ba120498271f2d5099ba6074bb5dfd90f8a8ff07cd5c679f9ddf928932d8bc532217bae830c575b1959b75c652e3802e4695022be5fa02541f9a58ebeb61598d1fbe068b4731f44a6d74e552eb7d84e3e37b6870cf7dbcb848feed28cc4411f9a4ecd75fdcaa6cf30540c7c0c8da6e403b342b06f157c762c1755e2f580db540b2932a9430601da490f79cd42c00f4780cbc69c7600a1462011a6782843a03925cd33ca9c72672318ea9bc791742befa29e458a90ccb6cd36031b35a2302090ab735cccb9591f5573c420961f70c38dd4d000064800fd60a1eecd40529ecb9dfb6b7d12d16f53d7dca858642c679d4513c5054afe0675cc45046623e02e999be6b84a28a82682af957c2e412be575e8df8a7020c92e10e62010c4f8c398b7694f3e9b725d8d8780a5883b3f3ca700aee1ea544b04e79be44b51f6b3c4e758245864c624e073fd1d3577e2eee1941aafc01f199e3d3cf3e1125155616d915afe497465e2c652cf4554024e9a0346823a2500670a8f4d4dc911a4391655fffb0d17928e99c15a69ae4837dd19f7b2be03157770c0f74627cccfcd296f08ce0bc77351abe5b9e21760a69b2433e59d992fce56a49b19a99a75039b078388f6d5d909468496b09bce286817dfaeb6c2c421778bb8bce7c22f526727ccaaa753c71f16038c3f1d8fd32bc7f375730ac5f17ef7887984cfe2d320ccc197f8e52565e291ad789e6c38321f8246671c66c2989988c77567da27dd85e911eb322f6e5ff8bcc328cb0ed80c1c866a7be31a43c7c64739e0606ec9cb3809d12f245b3aa52b8c2d9bdc7449983120e8af7f38d3e891e030b499d37adcc08f5f05a6cd6157dd41d95e5bad95e116ab448b2e2a37ac835ef5903152393ed4ae96b02c3e3f4f56defc775a38bc57679421e90b9f2b4a31e2ec9ecd0152c1f0a0713422c4e7aa276b59cc92900ae3b5602dc853d384b6667a45a92b083351506b95b483a7416a30f503b7cd11d704c00c91f74b822680fed52814e65ece3806ef3141328115f6f2aab0ee96ce12c566f11377e4281d0a33272cf9fcf9cb7f6b242c1210624cdd7e4552a2954bad03d8069e820c4df0499bdc07d5d08fb4a4e098404dc414b602b098d01e3c09dae967875d13314dbbd885d993ce8b8e043d315e943df62b1710ea80cfdc04b74b1eaff80bc8ebd2f93c2adeb734fe873b52861d7e9361686ea30aa7ac4618000feb3623e1b000662239739589fe65b8970a14a862bf12b9bd4aa7aa168aad02c48746507537070aa5d70490c02280589fa6943c14990de0725661488f640846ead27bd09b18138210276dfd985a6c84db69e28ecdf362ab8603df3ab452db4bdfa07d423adda16273fbc7019d45d26e76c1c0cea6992d826cdadb59d1162d361bd5f9f6b30c825b38364bcf8fe3aaeb6a0239753b2556f121d98f562f6cbd42380c8db7b947d545e2aaf43e1e0164dd8ff7a7996a8aa468f42598e70d5872bf533e747af5b8f27c89ea8550eeb16d95ae20928f902c5c7b1ca59b8ca20caf562de0fb5302a7c62e8dc446e9482ac100d40b74ccc94e7746f27f2cd8f3bf26376e68c12a6d7a634b6f42c2d5fd6ae51d9f71b228a490f1062fd49a54d048b408c2b111db1ba01f3900e82950c862ca8c009d846fccd99dc36aca2e5a8c596d6feb1ad3927baace933373dd6dfec8fd67d38ea921bcb4bf3adf97131c339498bdac87f33a1820868fd262cd25511008517650fef9a4ccae9adcd7e9aad44bc98c27b596f6154a0d8cbf1f98095dffee337c4847dd3718d4209d91295c7174e86b5a0027c19742bdc556e681f0313034b36e9cea6606dce0ea3c47fdc5b86f2663e9f6176ea1988f064afa6c064811c569aed4ab988fd6decf104f8b07a564bb88f56559bbd05e5e8860c2c502e769a3b9b70b1d6864a79b3ae47e05d3c18acc16153862352b4cd7180aae51b98318c6de8a22957005603305de95e439759b2a4fb493f008d22b0b5ef8298a15f5bd3fb5d81b94f79628c3e6e963d9abdd41c71f01ba51bb5200f548d5dab8ae15520fc3018bc026a8258d766c4db456be73faa1e487a6c4754fb20ba13aaf74befd8791690180a032081f8ab91075b8e1569ce84906161e0262a2b12e82bfc92a500b7b46d4661a94698dd4b66895f90aa165fced05ca1759825166b7ecf05e7b6320a4325149df1e1519f480773f46f3d66cd54c73a46e797ae608e684a2fa94f5df47a6fe0cd99b2a528d7f8b261abeb96e0e251b9706b24f4aa9f20eeacef240a88e95ef7b543b89e19a999a8ded281dcaa7e38ec540b523dabd869c576a1fd0e1cbaa326734662fcdedecc855fd6e08fd14bbca2760e540d0f8353a721599d88b5c965d375202f5cf49a309039b976e5ee37961134587102d7a47ae3ce3eb4e3ef684c1a1a659f083b6319f29489ea9ca087674ed23aa7e7677b08657c48bc44f4a40f63ff42d476733a8a060e905936be916c679cd5206a9982d7814b8b80a7af8b7f2a4f0b334e2e347c04dd22b928771973f1173f5592cb05e1f322f1a152c7cb07af8640da0fe0be43b39398b6e0d13052520cab054930841b08eb600d401d623074f0af4d6718ba3848a7f8df3ee6a3611e7c8a0497f7de07462f0615ccdec66fbde29e3b5fa96ba31f077165adf3a97ce979e912838f5191f979d6a5526c01445e22601a26b30c4e16b5e3283374c292856d27f46454e2b80a924b12252c699e2f70a216fb9f1650481dd2c7b1b04ff3e9f05ad02ec7c46025794502210c730c3129425dc646a221353de04bc4ee28901f5e60ab7151ed30797e59696412486cd6fe6637277176ea65c47f16c46db7fe6283683811a34e3a0b1dcafa91e99286aa0a1ebc2c423cbbc8108e62e03c28ec95e442de0275de932ddee8134ddc6bca195544d2ece401737c6e357e677f2c6daa82267a13c90d29fd43338e4c5481d0a9153aa6064e99976392131e6a2bbd186d15da1b935897e3118a2a139fa660fe1ed7b42716d4f6c3aec2e49a5ea9fe1d13a42a9cfa9afa24cc2dbb9907dace8914280f501d7819044d6085e8823042943ac97519dd1ceb7637828daaaee34309520f5922c72d2e822d01c199be9699cf70365e9aeb556f8dc9c7544e957d7a6866e6cf497b9e64b2bf0d5a77885b5a1c6eb24d8ea0cfc94f8cc12254d82645bd44fe095071ef83976c7035f4496c06c463141afaec39df1cc848495b0c18b75471a072a46b375a49bf9251cd6bc3c3843943f68427bdd33057f794a7b835d7971db5b1499d2a51a577b08b6704223fda4b82752ad7f4fedc4d81921ef17ac64b50ea1078a42ebe24427a911376815b84bd0e1fcd960f3f98a0e64e5e597b005b1bd6bcc92b46e52e1f55940f12bcba317d2fbeb2109e10e85a539c71109c5fa4d75aeb469c909a209bd1362fb5ce8c38eb9c854afc2791ac6e35466044b1241cdab8b7567bd1bc962a9c055aff33828f4f7484e109132d41cd49a59ccc1108871a2db6855714094e679cb73c56aff6f709110e0e98f7f2731ab8b8a8b6104c4efe1481d926bbd59c39b2579e20a0e9b6cd4d26af93393ccc97060a236d8cd3474de061aefaf8791755cda8046de5a79487a08e308b553ed26718dbf3a87aed1920e7ef8a24b017223a69935ddb783c62e6c9a0b5f95c5a87e88615694589518da2833f18ccfb2ac8e333c7deee42e1c27601579bb91a2c0f5794635b375432cddc3c830b1293a46797f0844a970b4db9cacef04f2d3027acecfc0cf62d18dade32c903f6570e4aeb0b8d858f036b32525fd6b3370dde336559684f3b93e0962113472946e041694fcca04d5275c4abb6c1931b23e705417f839a9c0d3a6db8b7715ff73446ea23daaed913d11886fd74133e6fa88a56753410ef3f0f780aa1d8863a3bcde15935b82df4a90f5bd1cfd2ffaa7bee84732c7137d1ec168b55a8bb00a1522eeab70d7f6c0a2d6c345097d53a26e2093d8da31de1c8e8c68269a93d646db6d6b536c05aeb276fb9bbbfc56243edb3ed3d853593b8d8d423008ee306d637dd55f829b3567c6c36ca3e6dabe2c56876639163ea03d9494002d3870ac8530999703a7a4a09400de5343eb3da240a90f4f532a1cfd2158d4d92033e284ce33387272c3dc9cc0b431f83a44dbc00897555cf31a329ec022ae649d2a4ad79e47b5ac65ea4fe58867359ac00d63707de44e35bc4f8e7c33481ab64047a3e3c694bc8ce97aff20cf101c6bfa2c6809ec3d33dce29788ece5a68e1564dbc109039cbab296581a57944d055a5956d512fc8d60fb536745c55391ff8dce3860b6f0b0f58d3b16ce6d53a8cbfa1e3e53327abe355d4a602bc3929f18ae1503106e0937e0fbdaeeeae1d65c023e552953bf46088c54b6690cc9ee7d12eb22f2540ffdb018d7b47776aefe9fdcdcdfd55b1c4dfae7762999784b69d75585b8cac2468e9341e9b1d7b0883b95de483d2af4898676adadd788a6cfe7b8268cf0316db551b28d7174fbeb2df8de4d91cdb4a0948b9554b1e92f225b7a06cb899fbc30f92d66b44b7ec8bd7c3b31bf37ad096c7aa726e1f598a04cc13db04adc153caca042591eecd067454ff7cc3c74092d83450be09a3de07913602815977d46e0553591d3cd9092999d7118114da2f4882656613c99b048525929580b08795990d3d01061590f8dc29c2fdc48a96757a61dd3b793e276bf524161363b6b717a58e9e4c1904107ca73d31051bbe28e4fbcf89663a7b63db638d5e8b945956d46816ccc9679b2cbd228ae5948d40856a0685b3aa7430b04d33131eea6336cd0f092e39b6457fdbe76fcdd0e0feb50cad5ea8d41e5aaea4f72df87f1c92410d9fbc13ddff8e71eecc756c9248bcccdfc1c3e6971ab7eab31a782f3bf17db4a9650865de61dcd74e85611ca6d7fcc2c1c23d6fb6ee7fa04f800f6e48d15070b1567d3404df10c2040996489055cd1a5cc0df517458ae71b6cfeef8fabbae6f44f1c2ba48b796d31ae2eaf15cb2edf34691887062864786db213bc110da5f82b2f2a9a2bb31320461ac21525aeada9b6337a8a8a3911155373df94cb8f942857eb471d358b8dff34d9c188a0744245a2d275118102c7c6e4dad370c0b0b83f167de09c0d1e38ccee5acb367f52646459d85718a2c80ec36583290cc7a9799b27f90c0d634ab84422b61e725227d70f64ed01334ceea9e8ff2d49a50190f77e47df84a645db80575bdb5243393178ff28e824dc1e3feabd7a2e384104d62bf832855cca4476a151905584d0326887b48ea403f07c40cc44079b3c994954c3b152287653634605e03ea791aa7e818f1eeec49827abefaa9fad025767404fb26227bba4b19f69c95c311fea170d2b4ba3bbafa65f98f5d1f23d6221aff3b406da2e55031a3c59fa75aa2daf73b005a2e5357151aac1f95412406cbe90bf8e2f88f64d7054139f65eb76ec1974556d127c9d9ec1758bd9c5e13dcb7bd44ce564c5431b2cc894524184f860f257d69f1e93ddc0c40698ff385240c973dcf15ae3b27a2fd876b54a4789690b633a87fad9539682f696a3f75c9d3ce3e99efdbd8f879302a13acc6816cddbc6a9665973b38b52bddc9ff0d15c605be245b07925ac499275106d46c38598a85d122ccd8365572f6682efda1872ee6b1231bdb2fcd5474c3508d6d158cc733cae1c4ce9f3de4d9e0775ad742de2ebb8cd12cc74cab976326a1f62b237af621bcfc04d638967fb63c189a63a6432fb2a86155d49d3a5ac479498adee1913711eec8b1814b985efe17dd7f0d146c2fb233bd4ed724bc55f5efd4bf4b23248ff9027e2d3f4c33aa11aeab8835a3813eaf3711491f9ce4411c33caf3699f85212559c1aac469206440eb3b3d0562c311cd6f018abb2f0edc03050cc3e8628c1e161abb22f2bcf10757d001dd03279411af44a3ebea96fcad71319758166458af597a224c1a3e2350b63bb570dd2bec8c413885d8e3dc95775f9e66142f7442ca7a4dc95c217325cad61faecb37098c9b89640bd3c9d13e81d0e4a684e2abb0120d930c9a673491a097e34481745dc1561b203b1c1162e93a1bd372c2ee2786e42e83f50149cd4eec12c605f772c9b2c7735fac722287dc0b71f948bb655db28b1cf4f6b58e5536b8b5c1f0d8e0e266cd21111f8a0c0d9f334b6914c13b27e065de19b88d7c592c766b6d21871a4cbf2e262be9c2944bef24407b6624e1112bce3e1f96e46a5dd2cf11d48575f942c6d7fe1b9fbd02125e21c407cf6b1b695ee50ddde20dd99227aaf51d37b8e56906b56f1656b3de60c8b1a0edd57a94a51f90df58391cb46d45f86378056dfd954df73eb798f5f6a4ef11c37787c726da9a49daa6dec933aa75a0179de0bab5f259d3e54a2ca4ffbcb95e3bb50387168457de4f236b97fa93539f465b56cba9238e53648cc51fc2361c2e8577200fd53f68ec9850e00c5122e26714ff43e3c564cad9e2abb389721a9522a2443e4bc59900915910a9c6179acef2c229abf69d7adb6daeaafbd0b7c299e4a8c3c124530feda8cb78762bb4e216ef815906ad7a364215395b78ca8392cb059586ef191c29dfe1ae8a01e0946a49dfac8d6317e6b47a2c16f0c9a25bf3cf4f4704a47e9d0e4f694f229439027897f5f2e0e43fe1654ad44f0c462a539ac627e42008a9425a26899fc982258a91b2da13b64240a922a58ad820a4498554ec3da20261196c38612fe4d4bc6a518aea5fb6fd3d3534878a94b1919636f51a8ca903aa7e8681354d2d7d5841664f14935e5849859212bbad9d883b50d6734ed3f004e480bcca5ab7c4959e6562b7d340188f6c7ceb8b3bad596d8667f86c5868a0bc8a88f58f2f990b6266ab555d0860a8b73caedef9cc71bbcd53c99e677cdaeebb1e2634b73e07fb43fe1265b1739dc6e1b36f341e5df2bf03eb4e9b75932a558bdbe35f4c0a8b9ef989cb697c0e88c6d66a1402210a3cd63a1802a08fd007fc1e4f16f73d2f4fe8b4ace7ebf6402d9a24f50b5443238c2360cd59baf9abb2d046a859deb54bd883c9c8db9680dd7524e79b0bad1ade5001e1cc9435a14285108199c05047935b3582973333e98d5ef71982ec4819a0981b24359d82048a593cce761ad64869ff420b4fd4c658cce944c4776f8eb96be5e973d4a00455fb0de93a10bfca339b982356fa415ab9f17cbfb58aa866359ff763e6e9f7bcea6d99ecfa3ccf81aa0c766d75569fde1c4a6fdd16c43c026cf543dc31ae19850e4013e86c22a445026ec14c50d41d0d7d67f94b3f67d4abfbddecc019f6ee97e7d018bfb4a0a8def6f980b16e711261bc8a4392cbbec30e7f47e8f5a27dfa0c1177c33caedc9b953b7b040f9704817b49b2c24077e759cb73ab9aa7f88ea7302d3a40d8b7e55ea55a4d46c6d152291446289f866eeb6669bf8c13a8cf91f9c03d4fbc1b9dc8407876d940209b860c809bb1128a4dc6033aa8ce3f30c7d9d43a18961e24291d098aa3ca5b85ea594dc885bf915f5bb212fdd650300ce038766347947f1cc69d44caa12962bb28b3f95b30f21c99fd64cf9064e0497752915a84b481a8a089cd47ecc312183e4869c1a441c6c21675ad66c21eefc0d8890456f6b3a6e6299ae792b56f034100cd532822a4ea9a92c263af5260f94b63394663d92b7a7472cdc80a7056b2ed27e173b10eaa9fb8a302278773800a549485b5c6da6394275db5b984fc475b3f0594f8edd1c71341820837493c51c231a9a1b7b39718ae6196ee79e3ca55bcdaf59c837d3e420b0032407035484046dfbc251e1711410627060e8c16b25ca529240fbe2dc8a9fca2654ec9b012faf315d98a876780f9300694bef6cfe484aa626e117abfebdb59f9fe3befc0b3175e1116cd4a73402f11314045af5ed61f102e681204c5372d47295f4c4841725a090593bb27990032b1744d4db0306b777b51ba30a2f811042b815ffc35497f601ad2c3b5b8753b805eb4d47c8430d56b9436f348aa61fa10fa934c99e6af083357012d6636d858bcb1d0676ac1e7b8e89a085a88d521640b8150350f34f1bc53388bb4256beda77f718b8432f0044ca8b0420d2f47b8f32d94ff0c2019ba96015f97f30764fcd3f0ef04154365d1e6dbb21261cc71ff78c347c62f13b92b5d46a14c8df63bf8adfe93516e3274d73887a0befda964e4225f9dbd1a927c3f7ae22a882a4c0a60ca25e2842edd528ef4a1c3a25f43ad0faeb11c9e30470c23f030746cb4bce175defcb8f0e480c96f475e02af8aeffa6ac2df9548a30e55f8b488fb586dddb7040a63149b6f6dcc51a8da83338ca191856e707cdc810127a67a2c0127510509c2ba4b0759738bb224223c54ebc04db9372126155303f2fad620d2d7a0f3af9492ab58c393c028a757150089183c5c9cb8068dab86b700bd8faf01192f281cf3ddcbcc7f0bcc8a8709dbe538f9f15c9b7683d262e8987573aec0b33e26b4b5ce7d10ebb0f65a1b21af805508d018c875be4b2dfe97619743920b2f27256c180bc2d848d1fbf0ce434e5dfd38e56de281e56111e74b8b863daf7c4ba44e5ce3c0051d34cc61cb00722e89c472e9aa2710c1606e6dd34a23667fc2e20f2a026c367e329d4fdf0f3b53bd9941eeb0f04d9fdc7b2ae1e37a161c0eb07d1081ce4a6e9c8e12a2395a14176fd62d37aa671e05e74abf86d339d59fde4a1ed3e38ebb1a471d6142962f2351d771e85dc8438af1072382ec06ae39313d356446f2a91f2f82c52df4aab805c1ece0520724c9a08d8d4d31863d98aa233a6abc53c863110fc967f233daa8d793828422aebc2318dfb623db287a7aac05a5adc21f934077ef69bc58f64e2ad8190522b282220c8e23cbe8e32bacb268b12bcafb2dce4d6e945a400867046c9c3c5ad29395288bbfa7beafbfdb3785877ba056113727806c8c41b54adced024ccc45a5fc535d39deac049ea332866d0f22e9ca011bf454f5405db78682d09145bf2db15fe473494a451dfd06b7a2e07e21d5159442a7e300631c8051a731a373ca984c1ea7680463ea18487d68f8dc2b81659eddf9362ac3203d0852d31c45459abb88584a279c6728b842e7fc4dfa6bcee4c6861a92759b6f869f092ea4e2b1042302a509b0d48820ffef1c8e068379e3d8184b1b04ee407bc10fe2af4b5a21706174d80f9ab6d2512cf836c50689fb1037badb4966f62be8cd05046e1e6ed8e39e3704ad39ac1afaf52a37888c4256725dffd31c99d035adfed75ac0ffd2638be471c8ac91a884b64d00cad35f595669f8b757049ef80c7f1719c512cc940922aa10804eac33023a781bbc6c4d7b44fde4ff05dfabc0e5dbdd8f41414ddd0c1645bd36497beb7d6a9328be2d7cc4ae2a527c2fa43cd6b5b687ffe9c1ba46816c2dbb6c7d8553ea086d97803dd5d63cdee4bc706e699b8b7a30b1718bed7e1b1c27469f996058c7a45f6e1575e9a9773b81ba0192e4a2fb3d96b992f7796856679a4e58bc85e371862abed4045894aac869b8abdcd731518af0342757f8d9b19c09b3e5d7262d2a1a25affdac99540771c3681aee7b7b5875b5d426ada3857293a07eba429d68886b1cf0a35b748b44f9e931742d4a855907b1c20f4758e014e6e4e5da391b78955c1c0935b3db41f45ab0a586fabceeb0bce9bbda725909dbf96a27410d93fa9147b682589f24258597dead650599a2ac2145d7e18dea5d6d46d944692fc2e9a148074d3efb3553a02240ae0b09a34b13e26b1d92a6f0e17431d60266f3f626741c80deca0076bf14909d0b63e4ad025ba18c987ccde493efd24b09e1860b5ace34e16a2583a710e1ffe4803b138c5a649d988c4f52895a28750f3e099119c674053a648940974a3fd615ced2ab27f35795e584deda150f642053b86157d436ab3b8376b45baceaee94706c0f04bc1cc7399e6ee7531cc864224375878dc86b25a1f2d996b533b6fedc703b867ea3f1180e53ffa5f301ebbd84631c4badbbcf240aa53f22210509e60bbdf5bf85d0b5d87d8f8fa65233cdae68ff93b1966814143478f384fd5f7f78c092b1ebde8e0b58431be67a5d43a0e82fa22c116f485b3584b12a02437c2d5d6cb4d5125e492665a944e9b64d00984aadf292d566a700c9c0cbf19754b1344d89386964b344a994d81feda592e3ad4c574b0daf9c906d287ac015996d523f3ccfa053edf3361822b5321794a89353ae98215733158460d77a982904680f4e577167461ca1d0ceac90a9f2643ff9d748645da43f035d5b267901a49d79d81e1beb9ec0fcc05913f846417a618ed7cdd227951653246f6619b4022880ead95c7ed32f1078963a6d930d3b43278988b61fa78f396d67ced519769945f6f5c42793db6bdeb68de0eb36e9430d98a0e53ac7e284d1a6298768a676b18d7d8fa42937cf674259f0a9f6888ebd95f5dfc32ffb22e491098b994ab511e75817ec348f64d1c5cd163a4a9e7b96da4dcb54f67ae3bfd090a234529eeeb0739d7ae200bea2040a554c4fec3838d4931e29eaa36529a377d724eba325e0e2987923845c9b57442f4083997036ad4f099dd9a30417e671904b8b155204794030447e325776f5d5af9d21c2f6a0f0f1857da2382581a05ce217d26abc505829c311416c46e46ac6b7a66b0bfbe8a8e99f8dbc9a442e51fb796ab1efc3913c280e8f8a5481decd3c117a2debb84c10265088214aaa87d48238380f03ee8799e8d5ddeb23aa5ead64806541ba31aecd3075a4ce75a11a615069612dca921cfa2885ef372d8428914833f6aac51f115da95199086f50e3922acc601720e38f5cddfdc60d9447a1c135811d280accfcb8de9dd1aa6cf5e6c05d0613664d9ce238e6b0d0840ba1678b9d7216fb613dc49810f8ac9c647a42a43bebe46c56a6c2ba439532d459417e7b04eb7fc2493a24f13103afe39927c553c8e37117e0ad9abda0f216ed9d5649516ec002bf2d6565eb8f9a0aa9ffd6d161cb7b10b0591552050ca7321d95e0b00cab4da702044ee9cdb3d083d60eda1cd21edc568bc65145c89e71ed6722394140760286c639f1a3f2a573e32c429042b7c47523930b3237f3b9975f0b1a43da94b723c782cdcb7702722ee03cca58551f0543adb28e3755563639c3c43cd0cf83a39e45b5469bef0a13bd39051e3681feff09fabf9f55f986685e83e2b0ff9c8a9d47fb13170da29fcaaa420abf94bd21c2de6d191654236f172953bdcf4253dee3e46c0494b06072829cf7c29ea0df881857a9846ef3ac42a551870e0650131a45f9be959304160a2c0e313c036fa41e8871558865b29ebab6029c153aa6682712cf9f02b6d21e825d1b5a53630d889f906422cde9875336bca4fc6f0e10f0713c97b178dc03ed50fefb2555a4060e94deda8ff262252b0b138d7b9ca46b7d2c91ebf86d50ad8a2143464a7a9c608c3d7d43c0aa65a472d114ccd02655e1e2347e783b8adb8bdde862c6b5460666ed168316f70c22cc18c8a18b156dfd7463410c4e773162191b76b573dcb6fc307d023cf7b82143af76b8455257889e326e4fed50f6f524c81229a02474bfa83f786fc3a74b5b04f5b965c06fa016b8661a394d4f4052e2aa9ad80fa69273a653d27513f5e395ac36a1a90a06aaa00f680ef40b47747a277254e06bfef07914497e07cf3ead005a52d107aad592b2a30beb14c457412ca03076bdbe332024b9f02123b2324ba030c47af19528d6a9b17035a1cf586157889ddfa27bc6eae194cfd84a188208036ac13d02f8e3f36daa2f0b6e0075a1d5e1cd694a7db37bf2e285283b9569a164d94b1b513a442eb5ba530a7fa11f9eb3553c99981b75f1018465010a09d13b5a400a21d60654698c0e02254511095bb742ce4a46881e453687d225ef6503a24698402928dd97807b073afa09f4ccc23b867acf01b525dd05ee951be539424b36d4565476647e7e0d4c98fa294497c95771242511c9953ba594026403a703bd0303f0aec6d25e436d0df9e74f21c502cffd967389aeff2deb0c95e9e77dbe131f67116ea4bca182e75e63711615cfbd26e32c44cf31b8a047cc5aee1ef2def52deeaee91fb4a03dfd3242ff1eba082058cfd49aad6102cf3d3a81f0e59fded45acdd45263699199eb73fd2233c1d0358722f47f0e7b1ab420e46001107a40e107fd5221020a427d427f6da2f613847acd77f2531112852b5c457b0c84170833308014a105423dd45e0001a80085e96baccf4f3ef77b686b306fca6410f9bc6badb5263709b5e729f028dedd5a2cfe85ad21f5dcefb6bcc1d7fdf61b6d6be89eef1c9ffb0ebb7b2d74cfdefd4a4375f5105084feb59c76fb09359c7e0181fa41cbe40cdaf784fa47d7e92415085184ba4697de347bdfbbefbdf7debbf761ded73aef6b0db792a95b87f037574158d81350b4b57dc81be02eb055b4ef800df4e42c3226bae973e4f83953a00367e9c055b4ff4d285b3864e044ff54480a55ae829e08895c45fb2e34d396a5136f0a87bf9243067206edb7f621e020d0bdcfd0b5af2f1f0879c3879cc125b65c207bcf592ef8ecd19ff0f45d353d7437a341a07bb7c33f39b1e0f30efa934205093c0082c1a18bf24f0b4337e59f01105620cc5c458208f226a6e4c9304d871e6ce205a10f5220cc5c257394adb257b1be89db77ed4ded3b60619b37509ed73259ce39bb2bdf834d24c932e79c73ce390fc92cf749be7989731fbbb9de50d1722d535d7dd4c7ada197f75d52ff1e508640fab6f0839c240220e02ac1f3f2cbf36bdf087d1f779907922449923c4f21f7686fc1b059287832e85388a6b9554e0cfff43f2119dcc4d3a3c2944d3c4f8f92284afa3cea899b78fa867e13cf9ecf61d987a7900f53be6384d2e7eba1272a745b3eea3fa028ea37b1d71bbabe114a19ff5195ab6c5fefad63aacfaf9cf8bd89a83f87e78930dd44d4ff50d4a33e3d3d079ef2d36417ea63b4b22c490f64b7efe1cc6e42b72c7d4eb2d6507dfe6cfb2ef951dff37ae896fef4e63e87e91ae72949b21b40ddfe02393c8741be1a7ba0baa8a613b827f5af839fbd4a41f9eba083ed3d94431504d77b84e94d10fb347d2f4bd397a6ef807c7959bf54f2bbe99640aa0fb04ba1feeb97babf9ba67acd3f6fc81b4eeff64e3283e939bf42336050b3cf265a0035939a83fc4b9f537e10d8bf2c85fb9bead6e049e066c91a941fd04dbed63e48fa10864b6739761ffd39ce81fb2e3104dad3db73903f1165b3640af4fce94f101a649f92d25152525050be5683a6ff20fde92fbd1a4ca2ee106c10e5e63b68e639f20c61fd1d1fdbb6d71e84d621a079a33925850211d4b8c64dfb7db3b6b7cf295b5ba1fa6712cd5b1bc916afbd6b95a43459895c4dd508351eabac340406726f594d5d763e582e2272a4b4751fa4c094b68e0027efef0583ab281481b7b26000bc719de9c28b8492d3925668c0da18053720e369124b39e06186b7468e75b40e1d22bfc8734b7834ad80957410397815beaf268148d6012b8193089961d254e56b9aa67992a6699ae6533613c08b02d66836c660682648716242b474d4cd48b5e8b12256b3e185a522b569f2af9757e6d102c6a06dca3238016f06ef0bbfc1c1972c06fc06df20be1948db7b059fc1c17aa788ce7b595e5d938d3009ca6bd94dc32b046b11697001de24305a0a78b30dfdd5d32f7217acd9de9e991a181a132fbab49868004789d0510c369545b394d63c693cad020ece38f2101fb0161cd7f29e80654cc014bc46f4500e9b82b58c0ab9ee8257b3106206f9a6f924c17b046e5f1a40ba4d2cabc53130d90dd844f24d9389460d6e92997485b9b1c1ec0b84c74c0fd1527946005ebdb503fe01eb1c9717073c8020f084177db3dd0c38059cf37a9853d4161cd5dd99d4d70c90a21391a7301a9d6fa6c626f53dc2e66b04a5ed32dd0f3403bcda45e6c25ac399d33f62194ccea4faa60955c1db84ec01e71ca68e9ed294652946219df13cc69d8f23f0beb17453ac834b58c1c00830205f181a892ec107ce3d90c0333003b860df04af05ef0254887a208e665541648ee28c762e7829faf1d62404c3586395caa4af699ab1b1eb9b5a8969c41258c7789201cfe47d936943caabe4cc6455765f3248a01be104028c1f1c466e633e479a9f6fa6314cdac9c2ab8ff21d91175df455b60301674c0778730d4d97c760de22c1000b3b1e24657734d63ec8600a418303049515d3c4a0294c7bc49b9d973b2686f1714541059ae59047f5f8ba2623e293b10c4c92eb1a50a6f87f3fc73175df55bd5c4c1b8f9652931d369831a2d7e27842f1f4229ca09c1c234d0cf3624ccb9349833bae692b67f9735ca4faee0a8a1417b1d2b83814bf2cc545a89e1657b51e17e3a2daaff0735cfc6a59719c69adb5d65a77adb5d65a6badfbf04c790c1445c9b22cb52e75699a5a9bda2c4b7284fe3d6cbf85a730dd423790334972ce39e79c73d2d47524d4bc893ebf498ffaddeb0df50bd71f6484d91794fbda73bf8764164f5310368eea6aa8cf7d053e6cd5d2cd8ab70453773726b7ba0551db2166a365136b816cad732b581253ac15d35a046e8b245a26a51c164649862d82d7eaccb52284acadb14c37d89cb11c5d2b8b2e2a264e6d8e113be387bd4ada698392685a1b4bb8ea58a73716c887190e1364ed08af76ad841b5621a0d8b923b5a0d60689e707a9668d6bc2964012135997b4b12bd45a1d356080ad46b4da17572da26e92848658213d2c8aa3106547451292c888130284880eaeb8150a3b82c1265171e2b8a4f5168de8c2814bc490e1b176742cce5bcbc376422d8659bb15c6c25b3ab2da362af6ee893d7154426815d2436374d39e19c5b459782b10ba15eead4d626b7ba8ad6d666061ecd216912c2554acd2d34ae4684aa845ea8129ba614d14c5c0e159d1d5786b6bd8da1d6a5b66ac8f3096c6560b96b526a1626d9ed8baa39684d04e0f2b03df34c131ad11cf896ec85beb836d0da2c64a99a185456db537597454314fadd1910821d6ade7c57bb3dabd31ec0c1e0ebaafb7968aad5da1c67e99b14761ed8fad3648162b47c5d23c291dad7442ed909e36a21b128862d821783d746d9137168b8d75a1d6ce99b546c25eb6d812d4338b35aa27552b03d5c648629bbc297c5a1c599e211b9f2198ef66b217efb75e42755b45fb5308ee734f72ceb95fcb10856a6d32656d096ea25ed93c88ea6f200df6de7befbd77cb422da35a2895fc390e72fa466aefe738c8e8b36f90cf4f2135002ffc1c03e501cd7d37c8e9d03393e72e39a9b5d64057035d3ddc2c5a830ef566ecedc839c78e7debc66c4153024de1904049381c08080728e767c93118f444baefae90a5453874d8c40d36f187ce8f4387ded36e52b21068d0cba6f7ded9a2fafb39fe59b11e517d3fc73f27be1b6455fc3c9d424733e84ff3e778d37befbd37f9bdf7de7befbdaf6c3e77a78fdcef6d383c663a043d9104dc77577e5e2f3e68c6d8470ca72505a2f8ac605223e2770b7eef765267ad0b16ed870f1211b3f7ce06f9c06b931f1629f6e171818979b4beefe7d8c7f84f7e8e49dc91310f930b53cebff464c24ff386adf59317070764960cc28abc54925281aad1a6671401e4c6a21a0452a4428a73442569c24e1ab34f922d474ef5e7f898f44fae2351cdf167e6c8633cbe7c7745860c08b49059363879c92500cea2780e2d6dd5dd6797a8fde77867ee0351309cc19fe39db4ef06bf0bf4912f90e47ac7c14bddc9c2513110f34ed3778951db7479213949f2221bdf4e4e4f6fa78873fad64d357f8e75f0be9bb5823a43787470f0e894d5e888cde8c4a0d17161d4c992f13fc73a423a36df5db9f9e2e40c8b2f97a21a2485188811fc1c077a89482f71008f874d13ba9d266e45c0c094f47821b232922d3c399602484f959a748a9e334d62324f7285d592699ae6499a2609df348bd44dc54d92e4fe34eea1921795584065e9b95ad672519471c2520b2222a2c91312115d1a99119822356d175255563c463c9c4ee850d99da1d1c518218365044c8f9a544cddc854f590bac9f17089972e256f0da92b3294cfe047bf4ca174a625e49a84de56dc186303f2a064044a46d09b8e9606658ae22fb1941871346d44c58b381b5c36e6def062e24a94f5a8c0da29c9a1b2c4b23113e0f9165392ae33b01c533e8e60726cc3c248b5a4882cee2ae6c7c7a0b669c5a4a8a99b26d6dc37cd1445df4ce12934a7f4de7bef0d90537b07aa4192244d4faa64b6cb215602450c1edd8fb21b24688c4c436024c558c5f4fdbdf706cca95925cb5c52689d39831561cb266aaa384ed442929ca72b44929a97da90b589095dd51109230baa364e6456157d097e8eab767c134dcb88ba5aeb93ab70eeb7560c9abd90a855c27cc02c37558c620da8e45ead1af1b927a9e03ee79c7397ab949892a9f2aa68522d262699c9a74ea028fba1d8b1b9ca0d86f9ab840a3ebc21722f3e323b710b24437c2cd911f9805191573d1d5a4a85523ec65514460a287ef81813922ca7dc7e3965e497cfce3eb5638a2c889650067f2a040cba4421c9605d8981295969e0aa53348458e2194642b4c8845cf09fe329311e4f897117132d1ec86369d0928b1a417668b852a09bb4bcb999a9253596b82c45319948a1648294cd49549b2faa489afeb8244595f528b474cc2529caeb4ff8398ec22ae282e4e3529c11d6c346c887169c873bb6172432e2aa9d36d26d424ae2f4993fc7264ea84b28706b20d3a0d65a6bad49cf94872e44aaabaa1b78ba28fc03b7061e2cf3e624d9f7f9e3a0e4c2fee38093bd729ba8eff780efa6727f6ee226f6dca350819b13393611f4f90f023a13b5d79998bdefc73d8a729fa5d6c83c984066d980f3a18be16735320f2cc07e3d6cc9643c68810ba0003308fe1c9b80f9fce718aac97783df0612600f9196acadfd51cbabb1220123d26a435c5145ed24b16c433e3deb0fa8104d50c5b8246c521c7b04480ba463958b9584b54b30c254b0404e942db561efd80876ea0987c7534cfba264c8085be4c63ef1a071b6becd6863aeb4ac3314384d308ab07c581c4e3aed90d34c7b95c7e6a063c586b4377ab44f686c1a8d1e31da142d5854ed78626b9460df80e49a8eed4c93b145c164cd3b620657c3c67aa51dcbda982f242ed8a8143a26a490d82042ed9b887606930d8bc7f40265d7121561b37eb02372c499b525c86855bc80c362e9a46428b53c88582324048dbda8144bdbd34986666c0080022318000018088301499223318ee492ec0e1400074fd46080603c483c1444e26030100883612806a01880011000a118868118042321b2e801f0fa88d9c4266ef25b3125ceb6f377b9624ae864b5607252a5fba5bac39c02852af3722b8b2ae1aa1209d184514d6f540391c6a953e4cca42f79ef94cba5aa34f97d827eba08e1019936051d5809416dfe80b90099a29ae5ff55772bc1632108f6043fa6da858003c0d1c9e84ed90f2f3c7d9ce1b4772bea188f4556742a1e122c8932f8ba25502497de4beaecc1e190d2de1c10fc715f08f76623052e0331a17611df5c69d7f2a8bc12f843144ca773017c472710ae1fab222dfa47b1a6e58775ecb7a27f6778d4158ef78231820058d5af95acd97c6492ded38b2e7bdc8d3906c9f4ea16fa1cc25bb6473756fe8f40a90dcc11e7a4b6d0dcefaddb02c70c1889083408aca6bb366de698709e82f4374ba21996db058f39a7a74faa4e60b88d6ec8e9d3c683f47afc777ef8a31691ccf5219242b4c08f0c31b8e204f489253d203eda0aba4147912fbae21e83868022e7d244e37d5d5f22606bdafe154750591aeb8fe90dc6e9f5f8712155e822887061163093a42ed359452d3a2cb14f21607b6c64e7b85c5b082bccdc10357c68678999f201b880f4c2219b16b0332de8885905c458f726529155fb06bc1e13b4172d3b2e79b3ea6f8bd2e12e7029ebc154efa1a7e3474abdbd7afd59481b854b0b873c18a47fb39a24dceca73a05f8cd34abea649f1cd167825503e935bf13cceab597d1124f1c020415c4a50b4c1282b03a698280cd866ff1ee6cf782cdb8dc434c1d606d2e53c5b7c0d6e1b4cc11a1a5c4ae3c91ace35009a57b9f3514a87fcf95eff129dd55d1eeaf5820c9d936714cca80e35c3ef868be166be6f4c3927d975bee1259787a7c39fb450e55b75fcb0676377d3450e901eef571de19e2467376227a9208788231b7d4c8a2581a453ee48aa56d5c2f577569e0ac2057a57db3c214791cfb687fce4dabde9008db3dc55ac73a86115a04d56cdcf684517112395e315fa2a1278606fd710904c11b8e53154895eea440bc3c3c579c7ac0a921e191a9e520cb31ebc4c2a39be88b3b7078d165f70dc7ef4bef11133723882e53380fafdcb8bd4b34b1503cf72d560a14c022b56c7290d470eac17b1034b65816a571d43eaf77f59404d4a9bce7b1f03f000caed32988fa97b35ccc1505cd90a5c242471b825e79dea381066259e004fc996a6a6e3e2e2d5e985699a6a9ccae457cc41cd3f7089528fed33dacbe5829f6623e1e1ffd2041d3c6691107f119e9231f8bec9eda74d0de4d6d0b4c2e39530b1d72340f2cd6b642960ece433be3c53cf129ed450fabe4d245869c6839a7b71273a425b83cad0e9be2461b280eba84e2541bd0d1fab702e96497394b4496228db914d11ce792c51d4e8fa1642fe0bf392ad4b3e6bbd50fc907690462fe3661f95a6803c90a74926534ce7afe661612485435918ec4763e367247f23188f0e3a6b3da7a4fb6e4f90e8397fecad14bd124d49f91d0a41946dbed32d9665dbe8afaf3b354b1df41c59027a8fa08a9930256c0db0e29a28fc3b438e625e002c748482f7f19d4350b8d653cf8e6db3e184465cec367f325461917d01253556a802739c7502ffc52a7c8c756c114d57542cc5f91fe4709cc5e365d0b80c1debb4709ae3e5e21366143ee0cc7130a02a0b42cc4947cd86afe59ac96d3e48b07518cd1aa21262636d41703399c906a0d3179418340e676e25724aa92b0f1095105d80221663ee77a2cb41404c98251b987e76fb2888442a804ae05df0d46ca3e997af14869fc1ccab1cceed6d9b45835ee4f84d1732e8e704320023e4871e19af3f6385dbc787b2b755d79b78a285bc24e3edbf4bfd0c14b41bdd677447bdef9b4bcf04e60ff808b13de5e509965450e83c91f8cbe636a0ea5a32e4b7597d480ac627bba3b1dc0e4895c52aa3c124564568ac7f8c7838cdb9ad823f7fff6e5a2124613a3b1e42a21c8387528a1a33566e97456f59f49c925fc683b5bf74d1afc7c1f49765b64ee2a91975ae7a8218ca81d1ca1e31a5795b4320c8c014dcfdfb6fb62101553bd9c50fd4dc696e4e494cc00d07404dd474b1d72d15131cd04ba29480a8db3e17e77da1aec072e12ab63c515e18b2030e9828d397a35854fcc592c4a80dcf98375fa548a0c83c295d5da1b5239ac60b5731be5e17de846b8f04736c25c47399b0f9b74aa46184da7de35eab7d966544bcacb6ea78fe2ba191531c13690e4b8a1062b12531d470d1bb83ba7092a05dcb591cf01858d3f6e11bbd5e02b95531311a8ce06c685cd651bdafc0726689813206bf112ae379c815d0a82a624177411d706916e98acaf7c71cd4d26c8cc06da488a751055b4608f541d39b66044cb22977a4c53640843d03c445d1d5dd740718329d3c63060b64b9c230ad0f378c3867788197734aa4ca072e6d24936c7fa5c2924a91179b7caf5d1a6446946e572088ae6155589e67b698f39514be85844e1d914e9540c518e175c9b076678430fc828ff0c19e212b8609f11b10ea35100f7b98603d0b5f6e957f8a784b78a5c501a861ddbf72d4d1ced170338da5c8c9d942ab4d05d0e07447fd533d2d5b599fbd4071f2d98e1182d4ed72b4a4de642e6d253d61145dcc3b7b0c1aca01fc97ae4032d6913d40afd5db9e69aed66e4039e1ea6a14d08c226a62fe41a989e0d58d7b4ac76b284abfed231b287bdae97d690ddc3ef4b64ca75a543a7dad8063e4d1ac3c62581f7815ae3115341ad533a7cb4f26835681cda84302a05f84935e28c50d9d231d686f574eb79b6b46021b1c151eed1d860e6d01703c6d3c3ac3ed6ee14f434eb13e71f6d9cc7b214a004785823cf501e0761abe3861049907205cc39ec00ddfd2a2590f83e3d6963e3146d045c833314d1ec56bc94562b55dc3d8fc1227f152cc12ade6380f8cbeb5ca069f02ae2cc179bba82ecfadb598c9b1f5a089e0ee2b3229f6cafc35d89a2a184d796ed1d41a8232a957574e5eeb588d7cc62ed2aa360ad8680460d3949daf09f5fc1a3e18ec3bd57f02a34ce9d50693ede928c3d4b53b94d95ced1650158489605e162d792daa9642af2b997168c534a413d4d94274694ef2545d1ab995b9364f438686e4f8dc5dc28af82565ffeca8c522b1b03c81f58636083e23921f6c0718fc058bea333fc7e933e422662e989c3dcb4d12b07c135329c1b548ca85dfec146359b503b6cebb9b1a5eee7c4cdf0cd3fb65b04522454fdc6298b1f8e4f43a2eec1ff283abd454e5f4e184f5f180b23107f784c530629f1b229cc08cb2b00efdcc8c372f0614fcf6c1e287ab915e37f836ea23ce0170736f94bc8a2d6ea3e134289901b4dcc0afeace20a512c23d675a3a408e116f665aef220ceee4f950fa2ff9938c10ac390a09a0f18556033c0582704ae35ebf306c712cf6b69ad7c80c202acb889aa9816326e272104f9b0ba4744c230a4ec2ee8d05dfc317b057bff65b8d3e1c8ad1ae3cd4b49a56de3478a9f3e1cf61921228fd28c6eafb46d5e6935fea1f61ec16f32f8e442ead2ce70749baff2fe056c4d33a2b9d7042b34949dd5bc3b274c30c1148e0cfaea5f8e81c02e6e829e8138b3e6022d06bc96a320fea810bc866471597657c3b35da96984ed7a7f18c38c71f20dd8916e6568b7a2de3d63dc899e77191d142466a61d1186cc03cac48f94e9883e768253e303948ed639e23ba1376002609956fed56c1c18d8ff4667d36d406946fc0574b3c181030f37e369ad9e7405dfae499227083cf76e60d40d02d9ea9d7854e3c5e4d4b88f057f285519cedff96cf58c150eaa1ddb6a3d15d447713da77b66ef839ed936ee57db1298935b5df4df6b18f890402e66466bd25dccd64a63e77a994924a9aa3d5d7a1cc88de48dc34c17cbc848af60c6bf49d55bda413a064459548ccc140c141b58c98c29eafa6d7bbf8b9df28aced0e870e2c241c78c5e6410e3299eded3a84e92ae4c76f0a8d1a8feeef24acb1e56be7365f223712bd95dd9a6eca3e99a7a1715a53a8fd9bc22c2a600122643f46a278b02e497a868e283355af3a8a07bf893ebd5265d2e51c9a0a25f954a54bf0ff38962095642b372c4e6994443ae163722566ead12f08ccdc7e4f65244b8c236e3770322f5436dbf2fda073cd2b81d7af6430fcce4d54e2d268de57eac5565624729b256831176cef09ac3b80cde1ad6ab45f3b6c09b69004ae5aca169cc9efd40f744fdb34046a36f5370db0b73c804dfe094a27918cda7b877762317b532a6ce8660b2333800fbdaf61b3bba73d9e1e2bddfadf5033fb56137f81f98fde42e87c965fd5f694d6f15e5da33cea95f9c0436d860bafd5f4495d3fe52b268bcfe455d31cb8b69874b920d2b1fe6aa094d104263915737924a0dd4b00fd659070bd4cf54a8521769d22ece09bea62d9c5fd8075bd7d64b6baf2064ef6ba22079b918399136c537ad7f2b541ae36e88042aeb63eda74b22bc53ecc55dfc424fa23d02c371936f11ec4f1ecf99d6f89d82f36dff29e5e8bcaf7dfca65cf737d99d1c3ffd7f79534868cbae0fb6c024ca4eea87032e422b3e90bdbd899add83f28322902171447b2a75563979de5ba2a3805c0b17dabb5f54de48f14642201e445ba16605b7a73def458561b0b5545f6dddd33d7afdfa0a6d81de10fbe3bcf86fcce92d706dbfe9d07086f80c4e88e2fb137441c51ce2cd6027b343e48261539e397e466ad9708b8ee0250dcf590817dc766d8f006b5980e3602d261be5935bc7cbd97e62376e29b4da3b7c79d0313894cb39034fe518c05b09916e732675d1e987ea7616aa83abfd6cb7aacbab57655b6589a5355d2813b27a681804a59b4d8b2ae1f81bc84a72d25a127cf52f997d4f223acea6b0400d5539ce223e5bece1a591d96346b6eb5e4fe6272af5aee777a243206bd7e463579264f1256ebd276b0fb406935df592b15bca41de8009bea53b88b33122950a980478f1f5461cb27432c675a5b1594f24fb6d8a31551c21dc3808a1c13447086010a091ab425845c7065f45536270ffdf0f013b1e6e5ab9948153097bd59ae8bc0e7468d3542e901e93c5bc71eb62570e742c3281c8bcce54ab3b35d15d6dc93baf1fd499023a79c43f0c8b1c07a2848c9911c88f912fa0ed61bb0b14db601149a04421a12290df3a1fb912c7489cb64042244f1ba59c16481b9795a3ae0e1945d13c855f1d73acd34c8a8c60695b1972ec870c10a4eb231969d3bccbcd51af4923988e8b23221d86286978043d1d65db691b19c0f1e140769ca8e3580e4d2508cc31e2a635a59623d4a1c75180838f038923dab176083bb8d951e44cab97158e453bcc17d10008ce01948e21afb46e4a8dbb423b21fc8e36c714b959c39cb78aff731a79d13b3ae62160e0c280b64b95e3324af4b2b1ae6227d37539683204481c7161b40d2ae803a979cd777d1fe3a500bd3dab325188eb1c6573b4b80a899f0680e03baa1d4e47ca01d0e45a2e1aba60a1c081fcebbb98515d32924f5b0ad8e1c49174a46837f8dd0c49bc73301c6fde15db01b7903dd3064746be348d90b248daae852498a6e3a2b4250d68646480562ea17790e0687d29657fb440c98c834895369a2c3bd6eea8b34468e751ccde6969c95007fa7c1a33a176c03966d721cc24d2604aca62d0b44428c7b70359bbca4f0e1e8ebd7018f2a721bf909c68b964bf1de8b769a89391415aa96c6b8d42770c88e3d82d0d9180e7e8ab31a486032c87de5194a3fa8e8e07453b14ea858cecc688785cb8c63b5933939c59879878e478b6e39013ad3659e178b46369621a014b593cda522ec841c44ddb462942a51de5fa1d6535689b9291304d5ab239ae3810d241b2a0e1900f4733079a721071d2fac8d951f310bc84053643937c7d6be4cc27e91fba0991192dca8b211a9a3464844a33175ec70607a1a38303e9d068471151bad1ff1c4e71bce36d252d8a41e6a5a806ede4629d330fa4fae62e32dfd1463f8d2f861cb28ea6c3b4e3dc8ef4f534c6c888172d52928eab1ab96c72e072c0734497e3b40bad1c89ad8324475bab98e64b032488e12884426351315641d312147690fdd1862323c1e0b2b3f33487488b43531104ec2071d18629905469e7a4c7511bc3fa3832e9af919ce5f638a74d8ac8f5f49f1051d0402f860869989c8c6c696d511d203936388a6a928277cccd513692f645ee396a1ddc8ea423d2a1ca31ec60e280d31a09bda0bab665b8691110380b529eb622f023cacff2a20d9a562223765a5a421cd1eb6a8092b22d16ed1bb1aba5045c93253cbb7a2ffd9c682dd159701933830f388bf4cd31fd7133980f4e73a12758051f982f9a6da2e904bd967e07ec1df650489310ccb0066cb62fa16fa23cdbf985be4542b315b328960ea67714e9d1dad27447b1e034373139081cc0e11841d3ccc29b638783d8d17c67b6602292a675703f4733bb10297f875878631199e978918fc61330390699a145c925c7ce263d42d45624ec1c6ac7908355ccbdf54e5bddb100af9a3469dd94b7452d2addd45636730e64db3abcbac3e114c03a3c5b4d13258a0eab43a31173f49eed4b46129045e36bfa528ee42729a337234e728c409ce32bfcb90bcf399ca00f3b13960e961ed9709c9347d750e6995e3f02a4db1c6597b44cf285a3e93077bc716c1df2b568413a2c38be0eb443c71c6539682b1294a35e384802dd11b698f5655e41a86f96474918846fc062149350cf301a593d1dc5f24ae56b03d31989fdcc0742df68b1d8b5f98e9e426c462962625a1fcfe8932da2f7f144de8357ca65d2c8a30c306069917525325e202362337b159e42cc5d838141323b1a53521b44843582a660a747865a5243251dffb1c67e36b07b549a30b9c1e8a8eaba6afb0683c063b8b7ec4a479a4776c0ad401fb33b5490d702d89c6b8381c3f8422518f0da00a191a15620cc9f6545133b80e48588b3111760587259dcc1f4dd691b3914b3e4f21e49bbb5f94802c789a97e286e2a226bff3d884ef4023639d13e5a0bcda23e98162f11af665cdc0f1f282614a79991ae925d8b7579a4da2de9ca2d8a2b64c34b65ed02333ec1cdc43a4c821e80858c8419940aedc46ee8488b0a4570fd7e987c70e96b0453baba909907e31da86ce6f03829b20ccf1f07e96157c7daa25ed4f82dc00f9c18584c99bad6585a6d37c2565a1ea4f2c0d0820ae41f537dec3547d04d3bee90ac6d1d9d6df03610a044ca4a0fc4981169bd44cd1e72ea576c9ef0c72ae5b2a27a50f37b9468dbf3aba5e08991f59dcf907f86b46930f9e7a904ffe60c15801f3ca77574ba740b7a99834f73bd8c671b7231d7db35fd2d6e09f2b35fd7559ee3c05a593691b4a5d0d4138e03e3874cad46da2b26cce149d5d70ea3f522f6bdf686f70ae0715290bf16872850f6448d12778d8ea21957a8fedff0fecb96df21c771a6f86d6358d4a89236ca83ed368cada272d0d66d94bee420516ccd6327173b65e5de00b1e4f926a0a8854f7b47cb08859662333fa9b51257c4a4a5ddec6bb4c763760c46943f8d9eb6037ad39ff0b933101f90a926a0a6f871fff3f62ef35e62b31f290f9589caa36e9a7ffe2df8f6ccb334cde89a3517fc160942e65668ce57b5e14c744fc699b6878d25c24d69ad0297a6cdce8419162d2c7b90822bacd2b78f6a2a610445ec0f183b7ff054ee3429d43916091a6645529cfad4531810ea9e48eaae559b2de832eeec2520caf276cbcc6c07d9a359112f79c574929d5872928d9db298bbaec8c8a6c017c6ef9409d7ea94a73902e1e56ff167eed2a38fe32aca9c31ea4676d39b44220e59d62a589d3230a2931c37e4ce23c125bb72422f28a2602804755bedede7519aef4c222ccd255c7765a5b5fe8e599d70a565ac55000d5e6eaff9b05dc8b53adf9580291b04a27bb81cce7658148bda2cc7fb33bc194e043157fe07308a5b7ea413d5c3622620c7994e5464357a98db8a1a1a2838858a198c33af95026e1bdbdb3dcc6c9daa24f7ac629b568347956dc3962d40581bcdab175930078ce8242b8f52a6de942cc7fd093728d65c117728dc18e031b979dcde7718367c34107880132b6f350b4f01c247a63a2fd68f64c73959f3ecd65416a1a58e2058ff6ac5e174b5e5046b6171dc41cf0577d4072c5ae0376d99cf99ae8826f271cfb1d8c4c12242090311a0848472756dcd09ba16ed45953726059c2c4ea1325823911f68f9294f9f0b36b16f422ef1be8ea62280bef6cdd2ec8812a3eeb3c04773c56902e253b07e011a308c87cc42a49e4cd6c011d4f95bbeac1e80c282eae4380f08a552525958958d655c5512694b4a596907dd159fb26809809b5e1f1e2a0489abf84203f0981e1a1ea7a6021fae92096914dc487d9c42555c0d4eb180dac842258586bee2251dbf4fdede971e444f581781b10b3585a9e2445f1c16e6cffcdcbf4226db6f50a6ec9c96c1eda2ab5674887336b4e881b7fe249f65c43895e1fe4e2ff823e8091b405db30bc958c0b3aa0e7c561a2c975daa660672294e96b9120470eb85afd288897af039444cd38177c807422868de667ce602fce60374f412d9c8b0ef2f3ab341a96d8c7175c128918185c785b0b70fb51ea462ca3126fa1d1de0c169abad7814d1ea41d0de1a2534e9d0180540215fb1fc3227caebffc977732aefc7654725422d1548ea10e8b7efa09973ffd3fe75494e791441f3648b6a3ae093dcb9a282bb1f7a35dbdccb321c3700f41c500a406814e6f6ecf806d6eac948a85e4b0c33435c279f5731a8d148c168cd482fbfbd16df1b89a899646121b61312843c08dadd0aff701c4c23edf367c9d70352041abc23c00e449910df1cb903381c8342a4c4ed21d60ce1466ecafe686ca2c1f0cfbcf89e7871e1954fbf67e6baaab3826afe835f19ce03546ed4e32be4ab7e819823deb3f3910332057d5963d8e8ff768dc03969cf036ba1801b5dcc017bfb9aa9de70d5fa490ced695e29900ec339673488917ae9223d6617fa48bd92d2f6955f14aae00029311a628cddfda993676735ee22f8ec430d5f2cf39b3596b984fc5c399388dae81fed3d7c384214baf8e6e53178d2c8c86e2060bbc23372cc0033900a446150ef2bab12b606c6ca281393d3312436aeb26189a171a8c0997161b3d57786899d16b9141cbd140218c152e0099faec92fa7eebe9073a8c0df8c18d240ce3375472190f9379800faef5e0224b6fa41c0dd126f8c46639cedaa94903ea03af43a15b31ddc090f221293bea3593abd58d4662ad339a9b3b783bebc4eef3edf0863f541d41b6fe47b5e5a354a86a61773c2d091905dd84397a91e2fd11c9a91045ed31a3ae98bd8eb0639e59974f7fde0b169fc17da925fdd0507eda23ae56ce20a8dc7169387a13c3de87bd13b96ca6f37f7d3ba36efd8e9bdee06532943f7f17f3359b4b539046231b2a492fc6a2b66423b55792b986400e5ab4b83496da4eacd7c8bfff2ec2c164f8df5b871c035273ab61a3617a4a8cee46661c1b339387f1f0a7436b23bf14f00f273bcbe0f81dac72507e90fe94ffb0f66e75bf37f304182b63ebfac405686a0983abb03fd431db371ffbad540d293550202dd0fc4254aa2aaa023f9b708fcae47cc470d9a9b0ebe2b82c9a75050d7513a5b3ec2498f6f25b6e412dba596a369d87a302de615692d34f104d36efc075b8a15ac7f771a39307843a4b1426a1e5b2f45b6d0a00a5014eaa1df925df2382dd839762c6e2c19453f99be3f00621296f2095a1a0445d2402d01be483049ef0d48cc7b2b8d5265830381b7efb8f83a7cd432332b290e77a8011f8428d50c42090531334043de05380282639ce9f41228f8f1106de23be5e0424dda708add13229cfeaac24badc282593114b61f8614e5c73672c9a43bef94694b82770c9393ea09fb41691aca079a9377dff2422a063fad508fe8b1fc1db164fea72cc1d9d4c716e4949b169af68608999494b2851796aa73cc665a21a394516a957548204c7905c507467c9cab076a3aa4e2cca65e2c2bba6647fd859479e7687199815a0bdeb90337cedbeed15b13f76be5cb63eb6625e70674058c29c91e321107b1c0a12ff76ac71fe542d3a30e0a9e36de4e833a5f74f7d287a0e225d9edca2ba4824594575f543cc1260a1ed440af351b19799183db8de351cc1675b49c855ef5abe4ae8b6a76f1d83d231ebcd576e97fce39b04f67ccc3b9a435b336b458dcbe7d88a0b2a211082de9abfc903e63f129a201a89cf9de123356ce1a9bd8b078d61d0ab4f908880672862c854916916d64bbaf48172d28d8cbe272d7706477f569447058c81580e20a8d2ef693ee6704402cb7523965c44690ca9959bd33d9cbfaf1780a26a754c2905b8fd94fbe3d5e21e4756dcbbe3e893d47c3e757df270cb41f9d720789ce9b345c88b1431c25e7389249e7b49fe4361e1f7145ee33f620c63673f065b049886e9006df39f4ae374846e31b52e1425f594145c9f83abd2823576c9b277ce6ab5a9a0f51041f083177992d4ae45622e57a5a76ea55943af2cd936f742caaf6955a6fabe2b7a761da890be11cbd77d94f66a8c0ff894c46385cf0e52338b3d33969c2435a771c123d6ff51545b85687ffc6c8f450bac9a4415ccc827e4d55dd3420742dbbe4e6b2379498a43510d484028aefd9655f40503a4e0755203e33911545b74d2323f8a564ced74e659d4d3cf31537309cc312a730786e85e75c15045f91c44db1651ca8b8e2585ccc07dc93114bfd38c10aa05823c815c8e806d0b886d88bbd9827242222b4a4edbdf7965b4a99929401a406fe0522063ecbf62b0e6dd243b632199662a51f259d124fb7ba8b2146ec5a9834fda51fd3a65b61967862e860e85ee878743bba15742e743a5d0b251def58e874743926ce0a9d0a5d0a130736716c49c707d9cd90fbbb58d7587dbf17c67c29e64da79857dd4f89289104ac7cc72231a3c532693c4f62b61acb6cf5ca72c96da3c8fd96a841e8b7b05125daa159d39f12ad12b3a61f25da25664dff49b44c88368b6da2245a2748a2d552add0275a1988f6caace9bfa2c5326b2c6dd6f477a23dc22221da24eedd4831a2c53269fa57a2d532697a1ba7d532c3214bf31b3a2d8c56c518d9d2fca6eb6c673bbbfd7db2dbb6af395b9e62dec6168c34a34fbf244bb5f7c42bd9a8b33ab34129a510d872c9899ca86d34f8da3c16b351abb95f5babd56a79fea5322ab3b66e979c349a0dec92711d8923f7fbabc79785cd1afa76825e673931728f757697d459160186f015c35f8417ec3b5991b8eb703fb3a6be4b28b43ab976311fafdf2b4dff66b11a6fcd71fe8d67cdac99ef955c388464cdded4469b727c0c67cdac015fa8eeafef0ddea8a32836f832e1df5e47f71cfeed4bc05b37626ec40ebec217bd41473a762995c9105e24127009780ca149fc02b7afc51778838e1bf8f266dec09c54eea64183035d3184b4452efb4871b75d5b7d7647aa20a0616e8c760c93555071d8dea0f0eabf6cf69f33cc24a5af9afde7c47356af60055fd4bdf43a480f3e05c75208be08fd7addec3937fb4feabd66be77cc455d6f6fbfbbbbbb5519bfe755a7eae4f9eeeeee157c6dd57ffc27cfafb5d6fabab628536bad7dd94be7df7b5f75a341f3b7ede5d97bd74e48cea32310d030b98eae9d107c75d7624c22efc5ef8d3338df9bf3bd77e3ebc9b372a25742212746c69f1323d75184be31b63a94e77b604eaba0e2f0fa5b0106ab4fc72ac6c813f01b0b9b735a18cdff459e223cc1ff336d02a6ca4deb16fdee22cfcc563f5955ac6eadc49b49d3af125d93a61f378d99698380d9f2f7ea8336bc8a37dfb8d9df5563e290be9f0113a7f4fd0b9838e1f72b60e298be1f67e29cbe3f011307f5fd214c9cd4f7dfd880f0c1c4f9be1f01079838f7fb0d3071b6ef7f1a1307ff7cca009d075a800e8d11544f4e21b2ea73492ca2436384d593c4223a218cb00a4dab4f718f124f220958991b8bac46ec34a609027d8fdaac225599c680409a1a675497e99fbcb02492c0d0b3ade9389ca948670dfd4db4f5da8de4bf1255e2749a0dd5980aafbe574512eedb9f5b1852908412ee8847ec346132055f349748da60635269a2f0eab2ffabcb5da261f2045f5deeb203b9f75e5c6f1023456c5f2f1b11ef4e077a8022d65afbe12fb31b686103173e3f302180142d44a9291105134c96a84ee026385ce0a30658ac0852e54a14363b4cf1f282225e869eb4d0fd98502862300401d921080b42b628aad2450b9638a10312a46f89113a82265d62455820841519904a2d36042111cb410913a49fb089fcb032c7c124a4de1ef04890878122528468a155d1b2138609213c3c1105480f318c604b4ab880e1a103b642173c545041c4972840b32b868a18c15abb05b104f6ef7698551f17f8b66ddbb6f5b06ddbb66d61ade2de7b71bdb7c80b3f4636285122872f2d58c10f3bb11e2f465d980021555875b2c327cb0d52aa748165470f1d6278c2880c31406284bb448b000061a4c2e8e10a0e5c6e60c2420e270893a48995245b5828024c72b7e766a03f45dd4f96cf86778b98db4304b7e026f99e9ecdb91bb87b97f4d8d161c98e1b040fb40898ed873a9d0042872d46e030c40b1419190fa513584c5982431046d8871e97f9e4ecb0010b1c8274f019428a142b80445136914393262e94827af0067270820635f0a146a5070986604228880a5b808a2c519d40820a33459229acd012248be944902542558e9882851e3d3a08a13bbb3b321092a4052f4796b811c2c4cfcf112c5c808192214aa494be1e5ac90d384890d4f5c729d01e216018a26746c591142d1a7882fcd082213c7238950414a1658523454811051648d08c0021030f4a867ef878f0cb640a135d62adb5b64a0a66a0820e46b4cc404393273e3b4d68c1c38e244962e0b7438fded1c124e45d090f064c864cf60631ab9f4f91273c6badb5d67eb847ef601d86fa8795390e24d8212684a4882341c050c03264040b57f00064b405a1c31d79c7e2566c2ee80e8c14b1ac2a397069b2d3c54a0f076a447686e8896283229624d1c167a48847200b248ed0a2944aae98618608b9520ac1e30a254cac7cae448f0da4f0d1430d4396b8228a00cc00564397253160f992e47b8020dd7bab77689b60d245a907ace2c9151668d8f28317205ee082082aa4d430250993f2f3a30e3a2e6e3726f3ee7b25171021592f8e4ceff5f0f5cdb83797ed7badb366fec5d93ea5a909fadf0658ebd5ab65b1eebdd45e4ba9b781beb9df97fd7b4b12b0ce518e54bf46e08e3334f7905767ea9f30e6a2f073da5ead47af8e1248e0e76ddbb66ddbdb39e79c33e319fb27e0bf6fc75c14cedc68756b7650077577bb8fbb7b2da245b556fb437facbd5487eadc8d9c433e61fdfb5e876fbd173f8742bedf3dd7a932fe1c55beaaacba621f6ddbe4facbc1d65679feecd9f35ba86fa63b6ce2d03cc8aa7c7f3cc1ff7d246dd4afb4bddabb61aef33e90540a4d27544ab58a61c9bc206dd87166d6d07f1767ec0863d6d0181ccc1a1916a869faad60a1300b97ee92fbc916503fe941d7ba6524f6518e2ad3d1964684f46d6dbb327f866ddb5c3a9ee8e04ae1c90d4f5ec0188309bf3c859ea4c024dc020a275e9c60b182932732d9baf2c1ed9cc0e0e3871552c0818b1d9eec54b1c3151d5694f8f0045f095d5c54f01243163428b1640a2c02e0a506a12a5b5850e3a188f739b95ef0e56cf5766205cbcc10217ee2520188ad8a93d80e273a3a217c29184e886cdbe64418b381131d2f4f21273faed019208a92d0c035038c710da125999c658d299af870c527d7086a422493618d2a9a08e170139e8c31c6b8736d0943d6d33c859ad0f24c9e424dac684294c9965dc115c415c415a4fe9c14e32f35c6ddaf1bb5ce1e326790ab4b375ab58e2b17fe552ec0a01b2363d10406f98de9045653adfe67d254e36add32ea56a5771b72a14c1f57a2ae769d37ed68b7bbe3cad9ee7ab6bbdef66170fb30c891ba1247ea4a5ef899bcf0338127122a5553296f9afac4d3109f4c1fd5f34dfaa9f09bf455b5d23f32027364d4391a560b02b2120424442b298f0f2099bef3501f74088dd149e9a4745213269dd43fc8b44ea04cf3ac230dda5e6db5d69bdaf66aafbdd79bdeafdabb7d77c31ce6386fca7d1be6b8cefbbceff3a69ff775def781a412a954f2a625d2078239a452f895c09cd074329d4edef41403be502c19f0a57a31b39a99f1a6339f09cc711105be689ea90f05e6d06c55e08be670a55aadbce90a93666e70769c329844a290eb93f55eea24f2845cc7a6750bb40206752ba85ba09520137832d58c4ca61ae4f6b35ece76c30545e8f37d82af188e33ba21e63a7247abcf0406996a4eb38d2b1957ab7db559d3f5cb0fa86f5aa869e8e7f01c60c0181975e9c2854b67c99249ae46abf5583db6aa81100354cdd69f89737f4e4b1be2b8e8826c8cdc05e94c5b5142b8e8c924e98854739afe8a92cd9a7e52cd5d67d6d055eeac344d7f17d42d5305567014d4916a41b9bf046b1bd2d272d78c4847243016d7dac51392358b198ad07fe6b34c7a3337e6db7fcd1bfef65f4e69b77f9fdba60ee6d4e94d6bb5cf72e738fb9e6d6badb5746252637ce365492023dbf797875ec1577d5bed28ce9a69c1d79da1c0f6f7757023bee0cbe2c81bf8aa7362aeeb3a8fe3ba12b6bf4fc236861082d3709df5582caf84edda8fe3ac7ddb8137faad676badb6473c6be89c5e07f6bbe86df40bc30f2461fbfb81256c23769a06c106cc6cdf6bad954e4caa2f42bf4040c3f80dfb15cce9723a14ba5cbb6cc7fa9d8b3337e8cf7f65effb3098c3657062d08e23c8b5c7dae10ecf2b7977035f348c8b05e1369276e6356066fcdc774fd6a1231a3431f75329a5947a91ff147557cc53e4ee750baab5daa3dc6fed256fcf88c1576fa2cb86103f47bf0d7cc096bff75edf7beffd6eb7ef74723f37947b24af9d43b98e9334012d77c0ce408f720088e5de70f6fcfba83d42a9eda1945e7b848eaa1db3d52a9d95c8fa1851e64b62b6689545ab2b8bb0be6aa9a6d3365d50ab76bc4741d6af5e87ccc77c09fcbe0492204389494303be6428315bfd2f8ccc1689239f4e3fef8c7d968d79d68802998f7914b07ef5384678c1c91076af7a7a7aef650cbd0c22bf91393de9f9fbf9bde89938f63be61be799d3f4933c977e96c8173da86e28f7cb8878d2ccec5d12a791acb96d9a945194fb6b9849552c04947cd1d3cae48b9e2c4389dcef89a48c5a6e5807ec2c8ba49de5fbce934956eeef5e4067eb7e7f8c8827cdfd9578afab4b48022086dc8f29b6b307502852a00020966aef67d67649114d739ad8f77ddff74d1293616651af33cf149648a07b9caa042acbb24cc57cc462b118ca894edd6c369bc160391ce6308739ec7af0891c9850c6beeffbbe8f068d54a6418386e7445c89047a8a730f5502955e7a65798ab5cd7dd03d0e9bbed9cc93cc66b3d9ac2600334454a6b1582c162b3dcff33ccf0412939e0c892611e7315c22819f9b30179640655972a517f3118bc5623127722e4ee4444ee444041800cd29d3b22ccb92e3388ee362b1fe582c86bbdcc0cf4b5bad61ae042acbb22c633e62b1582c56801a53a6b516c618635c6badb5d2d2bf2743f7ca72abdd0747f2fb52291830668ca407997471ed4aa0b22ccb92c65780cf158350867118f6586badb5d25a986b462425e9a5b27e3bc4caaccccaaccc82b5568dbc5ae36a0dd7da566bb7d6ac01541f150f30e4003eb91f013d1f7c08f03ef8a848da24b91f84d9b401c1c6c69bdad04ab969adff6e1919fecb72c0dc8d9616822a0210df974ac180316386071ecc26e5a6f98dcd325403739403663b5a1a10b48d238179cee8905ea0e6b54f9aa24d290e52c0408a0d6d436fee17ce1a6765774ae32f4295f06bdc6ed539bfbbdbdab66d45f016eb9c4da34a21626295a790941ca9396d3c9bc2b4b9a6ec9348a777cc96bfa7306dbc27bb2c7bcc69bc761923db1f96c716d9225b648b6c918d75cb6dec0e0f39774c9b6d67b6bc6db658b77ce3711a7f8cc390c57a72e3c9fe4162c9ee94626d53221101ca409eaf88277b4f264f3db6e824134db56de73424c7dae62464b678b6d2c7f6b3cd7af22643d1668dbfab896b47907e453f4020d91fac617e5d7cc4401e608e0fcc6754e43726a3a6f13781a9e5b0473c60d94f5727fb0948690bcafe3d9a6addf2771911925d4996fdab58e29935def1b8a084f42df8f294ec03aa8144d845ac0c954f4c2129b32c82b67956926611662189b3c3702a86c056eab356d2cc8dec23a981dc31d41042284a91283f518c4409a2e2aad2eeb59bd66ab5da6e6befad52a50ad6010404d45eddd65a96d65a7befbdb70cc9eeb2562bcb320421b061d2cb26f168b454cb64a85369a2b11c4e22a2922b4ad8b4b6019b0a49a1157f79d2bad5a6e977551192a97bc7b05b5e67297dfb369cd2896f525d71882bf96556ad5caab2fe5b21b5deb5e1dddf1caf1573241c84852839d48812e547941d61a2b0f0419415a07cf181d204ca0f50a2c0a1c4c99427a4dc40861d7c3049b2440d5480c187280a1426840881628a215c7c6ca161e39144132d38590114503628472cb10594263f4011820a28436a348102048a0fc6b88616473c29227c42e5c993274a9ef8f0c4c8132e5052786244c3a43940483056cea13371aefde0a88f8ec8a6e11f1cf90d2804cba2c325d68527834632104c4f6e2f470706b95c40da5aee1a9337b103735425246dad036373d43674acddaa24989037d3007ffb2f774fa57a7a771d433a437ffa9d359bfb66c310638ec5721a7cedd7efc01bd662f730b46fc5d7ccfef6fdab7df5d7f7c01bfd39d4ff357d037330686b77c49b33eedd36cfdbbc6d768b6cbdcf3c076d78ae1dc2553e127a23e9b3bcfd06ce70de73dee391286fef6d9ef75ef7df515051d1cf51deb6a794524a3b286fdb7777b75b9ebcbdbb7b2daad5fee46d7b6befe68d2e1f5c3e9070064712850c921e67d248a2f02a3de91dbc511a87f2f6a471f3c091eca3bc7d4fde7ce8a280963be0335a45c741a25eec6f30ad129261aea3076ef9d31f0ccee13cdc077620d37d68ad7be4f2dc1ec7c1699834fdf7c8b4f19dd9ea9eb6f158b770f0207ec3c421f90fb7c16b701ea761e2f0f8cd9df90c2e83fbf01d6781f7f0d8c4397d5f1e1fe24472bfcbbac6ca149654a8cbe1adf348e0b7bab33bcb6d0a4b5995425d0e6f9d4702bf93292ca952a87b3275e7b0443309ec38bcad2ea9fe9663aae5d234fd5d8c2c98cf7179b46e081ecbabeca32572b920245b7dcb4e0aafdfcb21c3d0fbfbbc440116ab7e9fa7523865fb555fb59672ea0472e8f04a36c6afe44ac281b928ac5f5f93f6c64d8eb6577b378e64391474ab3ab946427a42ae3cbae5321292ae93ab1dead67db269354a2985c01664a356547677374f1795eeeea08d5a2b8d594b7588f2bde41c72175d3c84f8e97b98cb9941216fcf8d240ad9e29fe08b8e38c727e8b88f7254d9bece2adbb169ddaa638622f4ae2f3366b8b4a875868b0656091645508666f8520be23048a2a33385063d9c7c6006430061d245861eb4a82a38608a18aca0072e41642cb860c5ac7683293208c1a2bf52005c78a122054c901f2332b4dc1ff56adddeadac137ca9f2cf7a37ccd93be9db0d739d573dcf9b7a1715db6a459513e47ee33aef9b614ae9a434d35929bd97e3603ab9dfcbc123f77f3a301fb99f14eb56d76ef693c4c9cf0ca89cbd54d96e5bd1894b9753113d11cd93d1a97622a2311e1f407862436431ee6d7065109095a0b2a28450b46e35aa441da18c50605047a85a0e18aa0656daed5eabc7d5906e9c17f381b9fdfd893cbd9f4f8ff4c8b3fbf9b40b2979724d441679621e21793e9549318189737f06c14212b325666705a4faa22292c2f22498fb37af4fcac0e8c84292fb6fcc96dc6fbb9ac7ecd08c579dea8bab88e4fec6292c34538cc390c5aab4d96c369bcd6030180c060b4da7130a95dade4ba936185f9ddd8fa3194646923bdc12ee9480485f4844faadd7321392704bb893fb6f09a8495f48445ad633fb2983cab22ccb3236fb39cd4eb3d3ec343bcd4e33d43755ab1903be62bec992a93232de54e67ae2cc190ba8f32df1a8f07e7435104bee775027f7f7b78466eb51e1fda81d35ac75623ce5ece74474223a119d884e44b9df5b792f381b703c602db48bdccfd1b2b392fb43ce06b9bfc4f190fb29d65206d186888a663fb1582c168be5fe18df8d6d52ae972602d318699392fb65b6eb25d318e5a1b29ed94fad2ccbb22cf30c8c183138e040868c17ab287a5391956f0eb985e836896e0ed70a99e034f48b6a47b0948ceaa06a7e430393a81aaa46a26aa8181e073db95fc6109fdcffa99eff684af6a25424534972ff989a75503be8c09b7630c7544cd6e1525c92461ead8e94cc6f68b8ac9c05fd94b98372bf27e35b85806652065683b0a30c6cd6c8c072abb20ccd02445c2e5091e10b959d1950e9e1e241258618507981082a3bb45071a18611545aa0b202959efc224f212a52a8fcd419256a8f7997b566a9ecfa84e4a4f9f86cb1c4124b648fe220f25897352a2b793166793e0cf001a918332f9a4496808317322c27912690c18a59a92a893cc15b128902d1149648e07749640ac68d44aa207b1d8c9844bf3ef1e60cb2ce72bf07a3cee84cbf7099cab231798e198ab0aef21ce7d7d9cd02cbfede7d96a8ca30643a66a54aa19e5ef15b64a932e63aef033d18ef5df1c55b51e6618833a5272d4db4df228b48768a0abfc0c8a40928fb77ca0434e33d79dac9feaeda79f17d5d9db6c8806f7f46245148585986374c8af138c7b00f4324ed2acf88a4278bc9b04c7f861d6dd6983ad8ac716109494f56a24d9ced5fb06256aa9413911589bf2914c9ee88ec5f22819fe73df0fd1102b7a66033943b52e5e91e510dc9c499595845424454ab599b020963ceb4f8a245192abb5f8bac49f38ff95a5ce58aa4496a619d911a6ce23cc6789c4f25501f04340c9eb9f5b72269366b9c5682b964109229982a45cb4e9b38a7ec2a992b89903ea992654fc168d9555b89d6c1545675a9b3c09b33c2a7a5a7a4a74f6b13077cfa5d4e9cefa9f7f49d68e2744f4d469c7e4e2cb9df89e4fe4abfe47edb7f77f04944bd4984d1bd499cc1de9bc417f87b9328834f22f82691854f22e94d624cc627b1f4267195b19094887d927eb94f36d08e6fc9ddf824865cea714ea14651954da22a8762499cc0aca14f12a96cd6d007455a9b35f43fb14b8fcd1a279a4790544816994ac9b447f6272c0c0b8131bec194a32bb4a06244032f4ad47eaee0d2c505c3142aa6449183cb53684a17502c3743c2151f8ec851db82ca8f1bccaae841e28a10cf941a3ee2aa10255334d0949fcc419e425382a6002169b46b5e561ab39368e6068eecdd4f0425218e2c829270d2b18b07a35dbdda6a6db7d76a6dbd16d72323b282a94758246d0e0babd5d6bbd98a2bc789640d02b212c4896415a26d1bae5c67abe779ef79225979aa0f2095c713c93aa4ca3cefab20c9d65211972e4546b55859cb61759ddc6fcac1e34551e08b92ee23f7a73ca6aa2a953755799f98c449eeef9f6e750ecd5d2dbbd5dd3b51d7cb7960e9945ac9cc8829536d75162e5d86f40d0d1aed93243ba10144c34a9edf326ad43726108121ea1ccda37d34905adb70407d4363312b31a1589618972e793e2da98fc640c2212c9f3c9de4f919e81b8abb84462c3039328d99d036f7b3bc10cb8a073f8305e3e683be6999771f9907a884cdd6f6b074a84e000028282317000028140e0a44a224caf128c6357714000c687e48625a341249c3b12c4a911c83310c23040063080004006080614ea14101bfe371b10e8dd0ffa59458055686ed94acc295e451385fefefea8058a5be4e56e0f31ff98eb44e957310b845e5fc57c1a40e4f6b069322dcc4e8027b2f1c88815a765d509458c94d9d07e8d452888f601620a56ce63f9beae0a640453de94ae0516eb369fbfd9b71bd54fe85b2324227af68fcab1e004fd117fcfcca84b46ce8e7aa1d02de9393d1565648e45613605f011686f02f4379838b1f5b474ec926e628a4f89da8ae633ab9e87c96ca7a753855a0a0c8490e54dbb5c3c32dd8ce447784676a512f67c48032a09b474ac9a6e69841a40b88b59544823d6929fe9c00e95e8b6343809b3b141479c882b4f93506df623bf7a8adb448dd93b47f2af5a3c2321faa1a116d6bbab13e30750f51ea84d350fc574b1c7ee377a8051aa5f3799b6fde56437a71a19e7ae296420ed05f3c286089a3b4924a30e2962e1a12fc43fda2b6220a5ece7057040f13d018a3d33f76e98737d816b29932b83432a330abf5f84003395e3703d835d0a3bd1f8bb34a645d46e37a8db3c18fc8ae71e4b433ae306b03d45dd4844e7d742e87aa9b73ee2315194094191cc4174a1437429cd3ecb590b3ce8fbd5909be2e713ec748344659a8ea3211a3fe41e8f4cf0031d3dd50ff8c55c422ff1f4abfbdf4c01dfff934f50aa8e9cf04a71a0a7e629cc85dfa1de1a3019024f4b26986d3564a831c92209a66b3a9f2caf4434c5481d6f6b5d28eee68df1258de5100bdb25c451f3e2d0f303d4f6cf63d26048a659a5a2a74c803824a862c39cbd0cb678e60fb3408f6caa8afcbc10f5ad921bfe8d6902794bc06b3cd4daaa6c4b506787fa979553a9fcb50ad9f5bd519687a2a52de51c16788895bb086acbfb6a73334466bc0a52a54a9848368c368d028c9e12ddfaaf44a06f11014e97ab330450ef845687752a9f2f62dde0f9c29b21135cc63099c7652e20b8fd2670c4390f8eb15c5b9c86349c096ba6fc8c2589bbe65df869f53df51faed4a01d7dbe346d18e6266cf2324048ad99186bd2e3876906bea73f216b6d28e53de462c6cc628da49c26b57dc402106aede0849e7a6c4ca4ec2b7d02883090a6d0a26a828d9c05b6000da0a27c90732f6416a496423f3eb5ac997b6c5822f9dbded3bb26dace7fdf2e22a342ae60c87203f0f2113e926571f2035a6d2dc4b9eafd49e3bf9270c13a469a2bf6f6a22a78e9301d54121590976fc0bf9dc0814d90f3f5e4b43c4051c50a45121cd28d389365f0dcf8dc37c5c69c6131c93329a210d834eb8de6c592c734d54c2a336fda0031ec27eb994bad3bc030c7728338cc2189debec1131ed898d72b20e1f4593892c8af19fc316362765b56dc3bece02530da724f8fce030f4689f2606ba22629f8bd0c5db3243ad9f3427353dfec5968d4f110e048493950be3f9f874cd8dd322dcbc06d1a7ed6f7be56944dc6dada76870f5d3369fc142ee37033eed6fa6e34a0aba1ff40a72351d6076b4855a6e1b53b585b4a3a3b4e873b86770e69a896b952439bd703d3b41071e86fd72d3dd736ee335aaf5ea85e996e9d71cc81976bb142da43f56cd9a8d26b1a74310a5f5bef3a88735c64646910e48f1684efc27ee5f3b9e6eb2846d554b32eecc39e774c332839c471f0cd39cb3f05694707a89097fb9801e0b25aeb4522efae9ff149c32a869a018865671b803227864993b2cbc097726dc8e2487f931fadd4aef54c679f81e19177d0a26a8548082f7e2007fe1fd5977ef69a23d4c8cafe7f1b698e8345ef43abd67af9df8836102aca0645289fa35e43546a4513fe04f7e25ff61172e112ade72cba20d7543201ce60cbb8a52cfeec318c2a6403b705b661f18da9cc26aa252a09945057fe14071df0d7e64a961dff908293667c880e70088f937d4cc168f29c720b6dabf5a54f79272f5ed10b7de00f797977bf4f80195195f8525a27595819f9cc7dd04feb72a608b723185ea9b22e19593529d72d7d035dd991efa61cf6f272039bcc3b962be736e56b88bf78dc51e9a311b58e066a673941468a1262ecf24fe4659a8837a8b18ef4f448345ea45b6c384007722d56d801ddc27af1cf0deb74c6b910940ad419fab64e5a43984aedb945e8ff5386840972b365da0fa3a1c6c1609ae3e46373abce969c8465bfa064544e6543bd5f83ad1d1cf4aa446875ec15bc3ee6ba5cf862e3329d7e1448bbcd93ccbe43771d065c42abfbf529433f41b604f7d8a0dc1bfca40b1b81022f7a197ea2d66da5064e28f8ee2670cfb9b3709b42e0656b855a705ebbd515b3f57189f792a47009e388316fa10072b117f5f1105182183b59358c69d9f1fe13ff0f5bc6e0ef266c416ebf9dc5dc153efb3a800603957da5600a9aa64306e27a580fe02e33d31ea0309c00664d3984ae4d3b9f5a6bf99213a0d77e7b4118d4eab0cc37a1edb721123baae0920402a4479303e85334b1dd066e4627bc3e95ebf2a10133f9fb74120602281b6b3303355a5bda3cd6555bd35cb6b799d8c367a00cdfbc1c4a48a9a299d93a4b38ceddf3481bfe7a2717451fe6aeebba930f4a99493a9cb3aa69771f268bc55f8ce150e283125950e50555babba2c5599a9a3bb0c62b15547b0bfa4b545ea4acaea1f249b499a1fe5377a121bac9fed9a1b5e76b94e5c91ce718cf359550cfca3272fa11b835a26be4512cbc74569088ba978584c426b098a284ea23de9c6f35ad865b86b49a3a7c5b8e40cfcbcf17e34f4d38f0785ab5712839491cb620c767b1e5e52830c96b3876fefd90a8b7c6f773d5ca6ff84b1a0dc11aab4630f352d23ce00aa6513528fc31fa5e63e6d84bdddb56543b798f6ec46cd51e1d48b695fd1fce5721239f1c4be3192b65e9b5f2df18017050e37d8af54169d4279d83b188811ba060318f5d025ac99ef525f7abfc038bd60f19212d8c46c4b51ad006d88d68a74b8b09d8f4b3e1f85581d4a2e3105b66c628c91e4a820f0cf4da10f92046b8934d15f34d7e96c72983599451106c616b4ea6fab9533418383ad9ab7b9109068f180f7b0d8ae280f80fdf50d0b7717ec8d0858f430f6061eb183226900a58a4ec36c2283094911aa055383914ca3fc960378916086616265cfde7d4b3209c73d6228c243cfbf0a4becbf74ec0a99350c2f3ff40cfee9ad1c74a394142c1cea99de19fa9d28fa3eaa65d9a19ea617a603561c16abd1551dd872076c5e0f77a344b5ad8b0a970202725609462104a5d9c817d1714af2954457eb4226f3d6223d0ee26ab6f2e3394b3b2a9f89cb9fdabe7458c78685dbe06b2ded27d71ef5b549a85308d5eab30addecfdd96123013b66a6439f45f459063b60b897b58e792b40808e836d3db03e22af4c099a50119b4d931071e12c334b03f8895f1eecbcc9e54d2821027eb951f3c68a74180562879620a9ac27beb5fb80024bec066c886392f19a766ec88fbf106bc80f03e3090a8b76803a0e38dd4d26f98f403b1ffebd4360c5774f81077217879e128dc6f4a06db1bdee6c102058ac32675e3428fc10bca2485b4143e79fd7783fbda1299a8c598233d8f03107c5592936c09a8a6f8d2d41f2524fb41c0b2aa2706cec2c5e14ff01197068b763bb53f32314c3671f6023f376943ac3cc73ede0d9980d699efa91a3063ac061601eb2f160d83ee43e2c0777abe855324934cec3954f17d1e52bc01290f27ee7aaa231ea053e9cf00da6147dec57fd2d0e2892d68f25bc20c2913b26d0acd132bc130ab586dfe217112a0b29bed2361a9a57e01fefbf3f045ace954769a4b80d5f72bd48c1e584fd4ba2debdc44f7b2442a182afe675c3229bf00713d5262480d6a0a124094212bfb3e2eec98bf2213a2a44cf9af761688daae04b19c43d9fc56c2956a582392cfb280b0ad62d28adf7beeac7b5ce5415909044ff480cdbb96fc5dfc3090fbfd91f8839a7c7d767507ae41373fdc98318aea746b389131b598f2a44c6d439356dcb6596a3272343dd93b6d238d6d20241e91b49609b6964a98463afb1dff51c04a9d100aff0de507d29b3d9d19b0ab9d0017d869b7867b9852607358c9217cd69c0d13d52f4ee5f537b423112e93eb97e0ff9f9f0c4bc72af2eafc44585f8531505af2ccaad910c3e997c42a0b8c880b4d66c9a51ec26d0a20ea3a5102ad5d4ce08e031cd55d800291b48e0b7a5d30d12b79802c3eba42296c610f80fa7f69d48c53b8edecaae8a89d9229d81c03e933a01f0655688edea465e41d997930ed53728bf323f317a979c0506aacb557103585720afe8483103328b18a19827475b4295cdb331748f1331db8046e2fa251bcb5767dd6b4206032ee63454bdcdf5ed2734a9c024fda3fce8a118a1755defad0a40e37bc7e259e821439518d6a0bad751cd48e8a6376210c6fad5e1d2e5dbbfe1589176670f34ad113ba77b791f280e4580ad121f1e3dda37501863df06c6f5e836f3a3432aabc7faaf012a2301d879895b3dc5b19cf4f212f3d7784c7a98b43ed610dab852d1249eadb9fb822b322de24f1e0925c2d9c7dc84142e6f431d3613e8c6337e9bd70dc750cd1b1cad136e5b1d49fee2a50be9eaa979518ff38d1f110197c9c9548a213e14a3bd7eb1349f479062b5bc8358eb7c837f448fa7122d54cb3cc75aad0203e0a4e88359681d76bf121113a17345debc3de68505741cf0378ce4a642576aa3a460d1cdd5769991c4cfd8d1d2c5dc8e88040c76b3f172d5a76be7b2be026825f606f3117ad814099b130a0e38dfc6e219069cbfc3f426fa25bfa0dd10896ca833c7374861031b1c4d070f75355827696517cb87062126ac91be562403ed5934a8255ed34943d980b17c1f53c16a03c9b4e8013cba0c5232d2d1a0a5b3cfe53300b84f2769c5e55f90c69514f3eb66fe7c1467cce06586584953fccd4972c3453f839018e5e8752c22bfe4aeee9d051ee359303e8f838f4346d1852f425e7dd1f951b6e3af02f07cf5fec6be94800922cf26a73e4bdf57871cc5136391af4169ba5983c07f7f0d7086a221fc0c61074b1e1be678841edbcac9d8982c9499bd68b49ccdc91c169e763faa82a4e7ac12a815ca61fab12327a440ca60e369617e13a2233a17b994f30acf02514d6bce9294388dda850600202003d860293a6a78909468f3ad6a205467ec1ce53f8dc81e8cc31cc60124c6b07c8625d8b0f765618c03b32eff85871db6df5c98a607bac9c9916f04cead6855087a500a65adf740137f12637b2b352ce34fe6df043f778db99eef74d3556ff8a3737c06ebd4d4733d2417f69bcab2d784d44ee5ef76a1449a782f9bd38adff597407cbf8afe5411f748271a0b5a5bf795873749bfd54a131eaed25c2ea0acad5bff556bdaea3960ca9da3ac8c084dc39fab7e9013aa50f233b8c67065a04ca2f155c3c2f767418a6b14f261bfb41d6ba88c315223613612479262779b584fca74f925ab3b85dc2935ab57aa9b0d3f41f2ec94c32ffc4a918fbaf982b366766721c91e7c051b097ee359bbb2eb84b40f49f6a1fb406a8e50ad5bd7d548acae52390701550ced231f6518450e5cf2bcadcd770ca8c66860283e6175bfaef80132b13996ecc1311ef61c7de706f100f845618335fb05c8b12f281e5d7e0ac0ebbfe2878d2cb961ed1b16cb8315dd499319d23453e1631309259bee30bd12ba23c169c8ab57d4c46d4c4c84abd712196dddcaca9d20f9277b598d7f443103f49f644dd589e8f9653ac733703ddd1392949c41226171ce058d71c9ca470455f95755e68269de6eff433c30879575e0d5cf6fb5a62f9bf2945b2170779da5012b094a6c29ddc47259b9831e44c75f05e2fb5fd8d6c47899faeb8ee5787aa702a131a2c152c23ac92107b0fd34b66aba71e4b5ecdd40f362b8c70d2000800752d6cf01d0e16f343400143a173b91f50a7dcb9f7dc64ac1699d9b8e9d2f03417510d44f3b68bd840c527ed2178bf86c94f7b89dee9c4ce991afb171faab155c3d765b54d14ad7f7f339807f947ddc16e52176aac9a2d65a4cd506c1d241fb8cb598e6f1519790110a5cdaa732555f15aa13ef15aa4b9a77f5d85004a20c10040349e999653f9e7e038a007c7fb4d0de784e0b0f68459e070439e29ad791d672a2b9e2d324b4a07bd9fb9e24c535569749b2b8deff80850efc730ac614268880dbe82d9bab433821b85e211ce978dd209cdb792c10ce4251cf2803506babe20a8401a143454752d414c280514c234ca2f1f3512626dfac322add205cbc1cd38c0d5c2cac384f7a073da3c1969a076143d22807bb8e5e5118219996dfb958af87d5b9136121fb8d36cc85dc0f3837dd96bf5978f2014b1ed79c9b1a5db41b9d294a6f04a98dd82d7165472dec968a13f0066faacd5940d6eff531a9371f3bb01fa6acdab8dca698f740e5410cec7e2a57940d73e27730ff9f4b05d9a66908176e56bc92bf1b7174580d9baf1b9f6e53c59d83fc096b2593dd1c83f097885d6cbfcb5cb89c77c1a4c8d96d4ea0e2ba80a6d2a666227798b26f2bb344d79441f6215cca51126447dc2c60da4cdcd238178b65af6abf7bdb25b4f5c5c0bd826c8fd9ff555b97c8cf7589162ffd4f2968d7a8d44088dff55536c0f73e52e07d0535af6dd3b2605edddfca469e7b5f06637ceb40567cd58341c0a2074cc369e54d048f40464bf29c9b924658217837cfad2eeb46a8d35ebac8dbd0c7383afccddf4cde78273f59d161a19481c9a6f12685c4136e575b0ebdc13d7875d3003320c9dbc9f3fdb912d5788fe194b5cc68129472e7c9f7c4881cbe7f3f273f93f02685b407d75dfc4aee8296cf02af5256689f4b4a122d7632f883b2acd328823a7e94321a72461955183d0430233a592acccee52522813d8b76f54b49d146d4b4537e5259f8ea19d83c3738af2b9d2a0a2418768d9e0ee774148e9f4c70e23de57275e1462a8d60368db4952590b81552ea9ace36687ede6deb1ea42755b464b699b2d172ae8505dc11a68be34790f5e4d4fc50c5e05ae0dd7760bd98a585e1ec5c995f4601058ae328506768bd0a89add253d621a42c5646ef8bea8a445ee3e355f69d6a5e572bdc27c2f733dcbf9bfc537e663e4019cf559e36c2df432a9b2e0aa1175a4e21611ad16fb9693226b27ca5fe25cf41db8be1a131dfb45b5bf7e3116b1b82ac952aa543efb1a42fc79fbdb091919fb1b45d38518e5d970a8c9bd1d889be668755c2ad83bd87c295cdce6e43d55f193826e72c116503516094192bacf7494d85df8673daf14c073f261449404ee652dee2a08100ba443b694dacfa02b2bfc4a97da90e3286e4e80134761531b5ecf665570760719fef6e84c179069282693f57c3ea6b1328d45b0c703c1867a21551ef355fccaf190fd97148bfbb49855f7fa08460ccaa44c94e7b1b0b0e0a92c7a105c772dd4d758e94aa2f073c6a83b73c9fdf85ce258e4d0f33e007e0545b2fd9ec789280d0ab412af6200b665f43d4672b2df296040393a8bc55069c61e95499df1efa45f1cd94d273f97ef8c48c664e0df88cc495ae059b4a0ad2b3e7858dd136877735fe09d705d133322c83d6727a6eaa95d209cbdded01765757cffb9555d69c6cac9aa8a3e005b17f9c338a80287a7808c034c5545d63dd0520404159220200387f514f14d065dc153417dbf220853ef2354aa989d395001a11cff242746d66f00ae96e9dd174b2e5438676236ef488fb8ca22e914c5fb22a9f97684265f9841793590dcfa21ecadab7b4bb7528d02435a14d8efff8fb2a722981b64341a3f5acfb579670b65644976dbf74b02917f422d4855437ea225f4814f3c6200587821303621d6db41f7e196606c822c68568aa068dc93b01018e115b90259693eccf357eb560dc0523c9c9950ceb95489eec5a1b85582f6bea8e6947a094a0799931a1eec734e0935e306549305837c6dcb4eac72b87f519cc2ffb33ba65bc328e7d5339c22e78bb67f86b49928fa925f2efc6504ccddeecc7dcef46de233f6d9081057f10c97f1c4e5534e35b58454f4b324f253e30abbfeed55a0409cf791299acadc112e90d02d1b8c3ccdefc05e2cf4ce1fe982d621993e141a9e1864ec417196135ffd4f76167cde7f81149a947da4bf6bc0497e46bb95365d073c8fc4a99401bbf52920163d7536140ceb6e4b1d18e0392b2f0fc2a744e0449b50fb9c555535f1606221ec980c7ef6feee0d8f2931ca9251b29678c4900068d8d7d0d80061964c35fe424c7f3bd2c59b5414002a223b49332696447d54a987fb3b793308d7ad3e495d2a615aa7d4f77c21cc214b39a9efcc2b2ee615065f6c4556dbf8f1f39a958be6e7a86802b9140be296e453e4b2ed7e1b8bd877a13ac5893b3397cbca4a70b2ade4bbe541dfe1bbf9bf1c6477c5a49e72cdb707a50fd12daeb0d3e67659a0e88c137f99e46dced418b86189371437ad9b12acc41cb7b3d080d3b322f7abe2f9416e9d2e913bc192886072d98cb451f3f47dadef34c792e3c68fb5c7dfafc25de99e03432a863a9fb5eda5ddbd443ee3e0703d7211a9b93a40b3c8080827da66fadbdc725ad6e12210b1f2acd511cb8be50f8742918769b06c9176994c705ee2f95a0bd5aabd6d37dc56463fd3ff24e848b670a138bd236c31b345b00a288cc293b8ff6efb9e03989b1ed1b1d82f6f095c1fc0f2679dd64b5fa7809193ea0601362696c3e247ba97810a1021805882e681c43ddf526621a6f3c99319d8f5e3e5bbe68cd1d4828abb97b7db15e668117e3fb7022a70d18f1ccda008380918c6fdab687abdb85c8db810d8407d85df2a92499a8b4147c483a4d996f2e46f119c0aa0e877ea73593aa468f50d60c4fa64767aa60689bc1e6bad80820d8ca1f4a09fb3d38de040d37aaafa5077b7830d9cf42f90b30c5ba9fd407c5f4d106d5233a95ba0d6703176f90d76ac27be38c28b86048b6b2918e087d749c973806ade8800f9b6180bec44302138a5eba1edc8f007ae1bb84e890d7530dd0de9c8232003e46eca18f97bd451f986b30f562c75cc87e559e3e1e58e057ec8cbd85d44632eb80a0a0f7d43362272ba4a0ca821acc2a3f6c75a45b6f1910d374aaeea7d7458c0cd90da7e2712882d24e4af4d79c46688d2523157edc97c9c4f861086bd7b03ccaa1411ba159ac9f6f88bd9f69895a4fc95615944b23e3dc80d61b0a3482037de49466ccea17f429a6954180fdd5bc50e50eb6215e44d5b94103975ac5164ba685fdde00c2acc8559f3af840aa8908e7e1bd0fb4bca0434b88db4979d7ce70d66ee04eb0d64d21131a035497268cc54b28b203bf6e4e78cf6f792e456cba5079feec008c04e650a7bde060034acc0c1c553b529efed106e6285f4c68654ef08e668fc215c15fe09aff5433350302fcdcd630489aaad0d520715150cd0a6d4da47ad5e67742fa7275e49d1554f33296235fd7dad2bd9161771c4a63a59a2950c492d581e44665f0c423d58c8ef904d57b2325129e760baa79176413e7b110b0e5cb8f554d7384d18864aab9d7bfa545048247fc0a8d359be8ff9ff37a1a0f0848cdfae97aea466c251152f919cceb83da88a3597361ecfb798e333aad37f1d2664f9d10e749dba9d90c442e0ec11cc6ca7ecde322fc63834bfc211f7bfe6dda1379f11f95c29a830e6672ee4152b35f0cc38a71c8cbd46be2ee3788b5a5be2cdc63d37272546adcb765441b157105b665e0bf9c3a79c109c53b7efdaacd87390ec2e463f54a211361a199da804ba36235dafe0ab08f48397e07adc87de8d38e4d0d8411781c615ee2e1abbac2bf767cbd7f760590941bb21b8eef5fa9679b92eb40c851835d8ec1c64ac907291b677cc1262657b704e3b377bf48220e70895b49c90a4c88edb8e109a692505eb11500587f223592dc087019c7b3104247edef0e3a4e14d2392aa06de0b142a4a5545c09b22b0fdb2169d11abaafeed5f1f196e8d1557c0166d0318e54a4c372ffb0817738f91df3e536a24486c8045ab6244572dbb6e5312c0103fb163608cd87fc375a812c4ce430a87e80f286ef793cc2515c97e72df9d3cb80a89230c19f8294ed5f048dcf4f80c2188d5349c0ffe4e0407bf195e52a8ac46b5e49e818559c362fc4ecb0d30396d3fc52a834c93bfd117348a2255c3f9342f92b2ba31ecb18e9aae85d5c6fa04479a3fec5504e27d42e66638cbd8338c3cbdfd77be5c3fe7b80d1a654c194c4c58ad547779370c48a85078ce7d20c60dbd16f6042d4a3be8b8cdc2eae5b21d0d0a7200561f467b3bad6b06abbe6c60ea451b8aa18dd1446bc54a7e72e7a1b2cbdb9995b58cebca9bc72232773e97734ea385b85f62948ed5f45562348c5a3d637bd75e8ab4ff3316da2956134da5c4c69476372e1eefa45f073b56f847ac8993416453bdfbaae9ae173d7d834a9d57b14e156254377166c31449b0200df523cd5486e72cfde7870a9893de1670b81c8829413b329b0fdd28c27906fb31c59b70c2a30b297a1cf2d4c875e08a27950655744905e68b6330ef8042b6ba77559e61e61e6004fa4efdf124e95f85c5a039de3154539aa62156e7c716f98cfc4e31186ec3716a9939e28c05de0b19167ec7fa6ce79307a8d9d22ab4e5faa56da0941c0d87662354781216deab3879b608deb1504f3254070c26addda39d29501e14c1be92bba7346133ec6fbf4599f6aab0641362dd2790a57b41777db1581454805e476172c26502361b8102b08edf1541d5deb29987e295ff6535f7e0cf03ffc8cd2b4018599eb3f61cbcf4d03f2c5c2d17947bd6f6f7137ba0da2a1d8994262a60e69cadad117bf224e10b13ef171599b0e223b64db469bb15e08dd81e25d149d04fb6593c2f491bcb308b33b2c4e6ade2379c5013dce8c36ca07a0598d24354d9b89ef694c9f63ba69279be304cd7c804865856d78d49b93178dfddc523ad1a4fb1719ba86f5893bf22b561bd13c3a2749c07917696c776dfc07fc6b7c7289f5b89b6f0f6f9edd0208023e14b2c3f467e32416e9749ea8b04a6c8ed68326a729f2ee8019808e2401ac669f37b3287641f7d9512c0aed799d0f4f1a16676cb0c9dab4e0fd5aa15a78c3cab1edecc03d6d4eac719d780bd45dd1da401ded6a2554b62d5015af959b8303af2d64846d75f56046a5a59d64d3694978d874fd027dd0a60f15be84e5902efd179c2dec2ef15409a4e801c165eb6b69c98c5c2568334f00b42316daa0153a2fc17a0e9be00f76a86e4d9e12d05e31f177ec6bc74e8486eae2441a04d9794792ed739c2893f31ad9ef7e10b02b75a1211b1ad415380cddea1c07f40d5ca27ec9087e81d5030e38e60985ed6ebc76cd4e84e45e8419b9fe088c5f4f09967c0f01d41af42c6cb73b86809a4e750d8ddddfaa7d3565e9db185aca2eac7bdac0d9f879b27702bb1b8c0e6e14fd3c8791d63fd06496d0663e00c8bc8bdbc92e5cf6a66f7f7facf4906831dafcb4edf20cd466f367de756a034db15a86430629a68bf2f98c47cab3e954d5ced0c81f3f6cadf2f4753444f26e714587b837c3e91e7f66c7997739019f1519c1cba83c7322dc2c59d2091b6fdd2c71a6f40ef3127aa18b499cee749084edb0f8e032c50ac345ceedcbc4185b5213232f3b8b3ad8ba604813a9bbd60e2458d85faa9337698c797639fe69f09e0a361f970c9bf7141b5f8125d85ea56ff8072e63fb966ae333800cab7e554a6f78f90cf8e91d5c52d513bd25a6a19ab91d1a0bb147f642cc79a10b034aa5ec1bd6cb969d164fa3e31ec0121f37128a1b19e4960fc494f12b1541d860702e4b612fb6d564ac69a9209151f40d0b22fc79310fec909d6e9b37f2d286c19f38f6357e233bf5b6e2de4cb8c17d7e77e486148b3a07a9b7ad662524a9cbaad877ea0304dc940744645ba6dac6349f107dead02df37b143bf3817c5f32023e779f1a895c48c7b7d7e8b4ad9fd04f1170ea4b911106abbf8ae44866f21ecaa4eaae0794d0144930a1f709ed152a7e764f93dd0ba227c6d9bcfaac35fd27787830483d1c8273d45fe3c744bb39aa63e6b1d0e98f25161d566aeaafbfc618d1abad01df1e61c77708b4a11b525d9157ec5c20a3961bf661f8fd3dc25a9703230a95af40cc5ab8908ec1db334a02b0986ece14dd16c2c41ab666455ae0c2c29529b99f412dc21ba4964c1255a840249098fada8e6d8f1d1bb25d8428e45993b028f31b9bb5c2b9eda174dbcbbd28a31a5380a6499bd580be90dfb1404da0916dd47bba9b682c351104c48ca85681488f45228849134c0b812beb0e912d222aa9c35ef557f0e01cf5ea3d1858a3dac58c0858d334840cc8057e692004669a3eeb8530b2472e29eaaedb683feba82775e951c8df505452a6e4c43d2a4341cf4c246d2c18a148c0fa161aaaa54772b4eb4c4aafc114abc2436f5002be7f5d6993afe117651c31034824743e8a3b9516e52956876044860d52a4ff297771596017255bba30d5310db65e61d0eed375d805018592d6b6a57d3cbb44e617c89398767a0c1a8c8671cc90619c0bb45583180b98f44bab102d51d107f04e42b03331263cf8c1bbf5c4ab99a5fb0a7c8e7b47c6212530d8742bd47c2552960408de6e0574392c0ce3eb8c700ca782729c82098915d72a691850ead19d92daf5c273ff87d76c740746236faf9cb01d2b166d6a26fe45e4805216617b7460300a7471fb360c48fa3b68c2b51f34babb1203f7f6fe98027ee407c82b5bba54f501f64e26fe3927c1e736fcf9527b54ff809ae172d13f31cf61ee39b52328e49d9249dbe932fddd7d0d0b9f004af22100180efd40b8f2a30bfaf804a3a5253e3809045ad4d6ca1eb641d300698c283e98105e3b3c35d7bac3c5c16bb707e19387804d73f59280eee3005b95971cf8531da0ede34a00a07c2166ae2871e14c050dec297f7dd7017dabbb042b8aac878c9c36c1c962bca5caeac5daf5c215100813b62cdd689829f975ccd2b70903259d31ec35de076cac66644ed8e2cdba42e24a297bb34cf853455684522f8a1684bee856f112f678284a19a98c72844dd70bab43f54d1148bd2330053be603c394b497e4d75baab7b6c0299cdfa2d5052a1d2c28fa2e87697978b0d0621364b4b2a13919c7f9007d8578c66e7a281b24f9e127de5528e0685bdedf5faf1bf12d22dabb7bf46ec60e619496dfe6bc1540048d3ef67bb3386ccca5be622d53ab9dcfeac68abd7fc459871b426c799945839eb1ce85ffd9d7ccf6d3b7a515072d94c2091671b996175e2278921f62c036e2c8eaf8590830bf6b022a92c4bb20690b94dc7e4e52b0906a778e2942c06c1175d4050ae6c93fd288e93c8c1d397c463b6fa048cb30058660112cad015102f140d32d005056442e1b6ea797e05d56666e053e1a713771654197ea402c459a8a4f2ec5863b1fd66b72d310a2e29abe1e7d0f65bcddf62a165db1a28e74035aa9b733e0a4e8949e8973ca80e426435909a57d738e44b926525ea60697900138f62934f9b4731c5eed49e2853609f01f6ac1e9c81af875588132db215ff8289a690c5400fa3d442f27eda1fe452d971b711fa3adb2525e86f90f95e835c6b80ab23351a21ff3be96d8840fca942ddd48eeb322a99ddbb26a7f276f6947824a24c05b479b68c2a6ee091a5c239be1fb59986195522e574fe205deb12bd6b668edcd546ae368ecc9fab7d532569917d45a0f369a8a10000aceecb6749d4d00e899ba9e97450f9994b2005163fa2e60d980798a8da54716e406bd8d1c4e7a3666a368884193b14938dcc067fa04c420bf954d58a1dbc155b599c916d37474854bf9b2bc333d14aa276d6a107145815676552440cae7899cd3b863a9c49f676c0f34027d4f703e1c2b60e4beab5b800087819ccc62385afa10c7c55a6d656df4ae78014383299fce61c681949c313a3b5e902a15a0d48f2c2534cd2573108e75dff36a98ac267d65d0e9d22ae1c3eb9e823231ae34c03fea6ff5e56e6d163937bec1dd06a6e260d515e2734f68d172f874cdfe2090515c4767e1f9fa734e594a2ae7291398e8cedca35411fcd6a6b1e8adcb0ab59d1eadb6913b73c7b596330bf6845b4bb1b0921da549ec9b79e3cb63d9977ca033e4892ff3bec020547874f71a1d1c53a20962d303251b7bee6ab9deb86719b1aa0b86864b6bb98e71eb39f9b257594d5b1361375adce55d6c36454eb1d13c5b1f64a6a8e1decff0596b178a18d8c849de31acf680646a0adf1b796f6774d850793c5f6dd03f597861efda0c0d4ede9822d232d13671c6399c70dc93c502be57ac63d79920755770692d8b3478e7ffcabb00934e9781c132a1446ac9f605a2bc9425f1d139d5868f2d572e51cab7e349c3a0b0db45fd630351d8116ff84a9a68410486063c43ee029619a38d141bfbf3b94990439109eb6a47021c7946c374c58282847ae326c534d6fda1360e419fe0930100ff0ab95909f9c4a69b41752eee525a96c4dff1740497a7e3d865fba2fd69e807b2493d286934c23c935f5c59b768a0941d372d5c88ef8cf5f20a2bfd67ce937e679f57d58bc8930c4cc5d712065e79e9f3234609fcb27866a6ed8021deab42d7b41027e4aea6462058e729c5f02a44149443daf27eb1ac4dc36529851141da9df05b0b64d6c39345eab9770c2d52fb8e1666342260b76759c66472f86fb3207b7ebcc0cad99adf5178ca08a7e7e8a0bee970b88b08aabf4c1d496f184c98819fcb56ae4127904fd93dd5a5eca23a070be4120d85b18640fc8465778570d04bf19bbd9d438ebcfd002752e7bc23998645b74c1191b702e040b410bacb0340f40824b1d6f81fd68ef6559b79f0efe6691363d6b19c6563f231597902730c08c7fa2b1ce61df402d3d7e8ac08c1e97535fc47f521abf0f531f722f95496f6dcba877b6307d81ac27a4488fdad563cedc2dd30628f674d2c8e482f20fc6396554d723334cb012b380884f58c9378f5bbf1eb2a116905f1424e168f5eb9a12f330578a154329b5549f9c83d698ce3ba0d6860fc0a169e3b701972d144b483277eae00aacdcf47691b8b405217a5aef7b31da52a0b877c383144004242720112c26025dd49cc0b0935de9ca1ced952d682a91bae8f1174a6608c41cbe2e69cde4cfebc01b6652d57d918e610e854cb7555b000b94acdf59d587cd46fbb9aaa508fde2757548b7ce681945c72d2df2a1d4d9323b74ca638145bf5bd1968733fb189eff0b8f6175b59127eb5b6327d123c1376faeae62bc83d2c5a400d2cdcad06c2657ded64d2be8051c526c0d84d219bfb74ec7c2708d4dbde40a8c91e11fc5ddbe6d24fb39de9ab6136c5a0100168082ee581bdf95700b34d7dc4bfd28888ea874019b8703a5a10e2e92942d1a2c1b4d1a9801d8accfbcb16508e0497cc72e7314d358989bfb81bc78b7b32aed9bf4d071b0dd516c958d2256437dfc650b142bee2eb397a755c4e788b73e3362836e5fadf03d2cc036b0906531532ad04b17277a8ca8f70a03c8160f183638b180af1f53eb47a31d4b05c46df4d1dc02b0e60526a727baa34d13d029fb836f7ba406644c296a7fcdde1dbed8c1605d9647f2fa4b2162cf75bc79a43f4365200b02100897b87a0a4a154b9c216b555922946f3fb97a3be95cdd0cb4e7f45646b15c58208025f2a3c7e2780085cbe3b89ce3031446c2c50c3d8e994f37a06c2c98b4bb7aeeb138736cfcbe3c909fa97e308fa0ef03f6b6cbbef5e7deef8409cabefc29df23c8ef7112651cc6606e523d1a3dba1e9bccf041df907990d9bfc594ef2cbe8ae130434c2d4e3da265005efa7d4e1531bd853ade429efed141c3a85f7747f83ba54850a99bb7872a5a04aa5b0cc321537501d26fd04355fe7a50b4a91f978948612a1b074520d9682cae70933e92c52f98464a93641a35c13785655bbb9330123a63928a469689dc7ee9a8b1c78a6594879bb0d69450a0876b037285727586442a6a512a746a76269141b0477113fc4353592bec6afc464656857966604c8908349ee1f7d08db14f37c673e3bded0489900ad62263ee46c56f4c2c028a8b493157e596c02cb1e36bd96501c150f6eae08e4cf6cfe81274c23f7e04c7c560083635df0c6c4c4081802f2b24fa9732531c4db6a48c633c141e487644e55044723a45aef4ecf74018d04adeb5f58f33b720460421bd362b81d142e51b63faf70ca339a6e2be0711b2e5d2dae1d78c8d61cc4ff8358b995f86d7b181cd7813d01e0bce2a3a86c6c52973ac5bc31513e7bdae622c890bc78e24a1ab11b3a3c94d946795c223d7116cdd795a4ef38ec8b8b70e218f45df337168531f49a29fee83e474a52e7dd0ffb704d5c314402116191a5e32f6a0128fcfc15b384676bbadb7fcf1ad7ebfe7323e1d1eff0c88a1364b483755b26db8683f0fcf782de4e88752436c240431c6fd3f5cb93864f224e80da3203a56829c9dfbafe83243e501040b91ea321ec5ad1fc7288d3e5b1e97a7ba21f12b87018635f1e8d7ffd49ee7557a08f5c8068cc201b5f0fa65b285fb08a1b202af5c2941abbfa60039d0738fbfa6476a21649547551e6e50d2be0a0cb8b16b0963e0280f4af12c1954db2b6f536cb762cf4f559df4feb89508c648bb42efd0ed11e041e684ea407e876e6cb15615592589d739dfad5cdc79585611180ff71972d3db723c05c69180353bc6b4ffb5218f803717ece0ce67437e1b2783965072d3872e92fd001c36ba739c0cd3a05911eda30422424b7485956a396a0a2182f608583fea91c63da3f74c60c6931a62e4b670718172f990bcc7c1729e355be8420e86b80f9fe1dfc0f44a56ce079837047a3f57ba6139c8ac44b6dfeeac81481c8a5e0478c619cf948394c9712c3f0d5ec3de17cb6e6449aa2dbf491a920289a21e43c3901f9372cf89cceb9e871525fff02e643ca55873eaa7a8463b0e7d5b6c90839b9c9f4db9385ce3bb9474d85e72e591d527ec5220ad8dbd1212a33a8f3f533c29104a13a180dbdda185ea29fd46f4130832354798956123ffa816ee74d5cc10d3240e0e0fe68366c0b99bd0cde17d7d40d55b80b855d63e5f50b085cd7f5f7f5f79ebe1e6b2e73c04a9f24c058328df4588103d9d931ae287aa8a024b46a39fa838e4a208827222b73d58316d7acbe0061d7ad318a9d215fc3dc082f5547dedb90543f215729dc75ab2228496049780d45f5a40d020c4c82e7c85321aa96500e0d65f25f5e608a96745ffeb8ec54006d4aecc6ed2d2a88a1398b975c70b6d17e51ed8eb5a6b2df10342bdd033208431bda8a60e100e39aeff2f7bfd0bbb6a537474dd27805455c89666afb345cdd49790a2481ceab38f1d2d175c208d6393b64b850868701516ddf7a9382908c120f4e2c6794a7d4e67df699be8629002f28cd53fe632625e5427538bbacf02010bef2d30f8d0cabcdc5af54aca4a2e35689b39d71fb48251d161764281461c8ae018e3c2dd577788b0f2577fde3358c723c94ba1656232492cf3953bc6fbb178e5ab991027b5ad5ecb104640dd9d5967e5c851b54a33a6fe1fc3c7f22ee9ae5aed9b08706f84a8b0423ff3fdaf4356c605b1728fd2bf5fe6686c1b4a48adf5a8808244fe3714ac0d59c002047b24533f124c6becc0175da9ea40660562a428147db840e3d962bc10a980d4e9fc99731c9d9280743225c271cb7df5af167bb78a762ba53eaf1eb3579f0d0a26dfbc97f304a1dd7b18046a2331f52a5d83dd8ed87c5d209fac31d77b547326a9c45085d605823f4d11ecc2f987783431b3d874decf705cad333f85f38172d8fec90b7e05d6125b45c22bbf0284aa5baa91fa1522d901db46287561d55c42659b9df28ff538f9fa4ba45495869a987b771b9441c95b5cdb8cd94ec7200f71393b78a120f039737e1c09fc65fb1b4aebf9b9e5ee7fdd4f7a8c498949cf485e657de75bcd4f1dbbdadc31989d63af007f05aba858f2fcd2dea0f1aad903a9cdfc1e5bda1c2a9a0bcdf33f347c0684ecf2234f65a0ee8997bc07801a66fecd2d43fcea17ea39b3aca48db3ba6465840102d54423c927d640377a34a6cd2b596360f6aa20b71c6e6b5d664cd1178d904898a29a402d2f6154266021a005b4028d24d07494a3ef36a232fcab801802d4805c90116c863b3767b2c9865a819a111a42bf3384e7a450f243418b1526962d514550832b18d0a6fe472e75e4017a39b816e98f465fb62a4227cc1c2350a9a0061c24ba0af1d857b109373c54fd24f2b3670f731fc809f585784c9adaddf459cd6d4a1845b9dc09a1a60292b89e8532efb86f8937327c3112a263e20845898ce10e2b80a8b60a6aa1fe9e658d6441ebeab1a8246197138cb39e33da7fd7f8d7afb982ab186829aaca63b01f719aa595d3dbe4e12d54c1a1c89e48675a3f6c58aade858419d018390fc554ac021bb0a9c660f52cdfc4ab39834d194e8aff1416ea1349a6303af58b683e4d9a682283a341f65a4a1eda4b7a83e102ffb514690bc3f4562d8c004e3f3a1a5c74eecaff2132330b9cfd7b215d0a08cf771e18665a10fd0f52b9e4d90959c804d7a8793628fc434bf6934568e22cfbd057663e2c9f70f9611c88c3b20293fbc567e5644acc0bc876cfc90705444955fe8a6b6dd712ece12288599526a11dc64ca861d44e257e887a615e1614f464d142ffd5afc231692b9b8556327e0b307e2f373e2ffe58de9f5f1528b9d5408f69d04893b798686cd768d431678f4d4ea48169931b51d869252fc503e2375df3dd4ddf4d01c1f99f8452e1b09e03ee55c79d16386f6ebd32f3aa70721f195e50c29f71d69d09da6de316e9be08015a063a0842b94b10704bab99d8e55b1937d374c6ca01a85205d559d9d0e882b31f56b952632b6b7daaefa4ebb498ec1a33ba60741bcb8548dfbcb7341337ad124fe16e128d6034ac2d0df1a32ed43f823ed0fe992d9b26ecc844ee23bb07b505f084f55f968a4ca718b5f5e1922eb71508963a5366fcac67296f421c9fd7ea0e85fe490be48331a4871fb2ae558ff44d485e1b49549ae847759fa8c1162c5d47008f926d06b2b83b80fbdf56902e115e4129c12cd52a41b56a5248655eac1c63b3869862a4676b2792febd25fc31ac4f5582f87cc8d278088cf154f2e2388dde9ec0a920b4c326b7749c63c9c5a12122b40ccdb1334a79dde61fc901000c33dded256a8605ac5c00e6241628ee60c99b04cc2a199e0c65cda87995f8406452cf47e3481d98055ad9b77fb996ed1de1458110ee7601e261216222724d8fdddac7cf1ecded3d1adfb7ece4048fc9393bf814c8c7f38910cbf0386e51b0f0904f8dfa44e39b5e7f48fcbfb181e62c08a801ffa2ca1a5af7bac5e87f3da06ef521630cb0cfdf7334b91e76c113eb95c400d66de5bc49fa842468212b051417a4d1f42d35c8d5228a3e683bed30614f1e1596f34b6c10a02ced489de54fe5032d1db18a32e3e19eb2267479dc7192aeb58b86cfa77cb6987db879f843013037ff0a656ba3f6f083ccf3b12bb509cee18a625e022ff7558ce8b7a3d024c46fd7e7ac095a17da2027e40920bc27fe301816aa7eb519026f83fe6377a3fabf6527e56bf4c17c5e32dcef7fd0dbf4c2b7e3b8ccd0afaee953da32077b4a16ef9a7c9dcac5a2d696e3d041756fa1f0dc84ff726021bb39df0fa1d1b0248a6ada6ed4e0e5dc487c945beb80283e4865799737ceca4d0e181b536579086ac38ef9e2390e02f3c1fdc662d8236183a2eab97d12095cb628bbaf1578e509b4a73495de6ee8d7811edfc7e88439c2096b634808950a101e4bd510818b425994c0c50201a1d5e400e0bf110fcdd7897f654b21ee72de8b5dcd11519820cc76aeeafa0b34948c007d39ff7ad4f338f8964364dc7cec63143b4a671f06e037c90031aa9ce885d40d4554d1b9dfd3270dfa5fc0e217b0171daddc2f3ef0d7d37045beaeced93832f4e0cd7d82686ab8f6be6c1df2249e8de237c7b763e603b06f3014d841cb0521f557efa2ee9f85bf735a84714c565ebefebdfd6ec924d24b2bbbb7b07ec0869082f08b5c66ac413bcd65a6bb5422f800add5b6eb47c4a6684bbf0279331910df1ae4210feae67dc155aa4f6f971f0d77069707a78e1851d7a470b97ffc28ecbb5e7f08634776bdbeef862d0979c461ab9df8bc16d9c1a9e66e519609bb8ddbf5f0af1eb3ee1a5e2e70de3cdc4e752e031fe7dfafdef5db9f3c580786b3497c6d2e0cbe15d69b0c6e14d69f0c6e13d6930e6f0963498b3dc467a35efbb35c7f7e62d69f0c6e51d6930862fe2499a24953813b38c2f4f52de1b0d877326e112d6f0453df186792d6d5643e1375e170441a408208048203b4206b22378901db1c39fec089c234680e48a8be485c40a19922964488a6e2093f5c864b012c86436c8642358821156144166c413322386f89319614466c40f6446f8c88ce89119b1020e7fda17812062448f031891030f23486083206d8d70801f5d221ad27509247094a0e4defba4889f21dac49fac881afca061308422788a50010d973f591145cc29e07b0fa59412764ff62862079756040d3af748136cb04790e0920207dabad1048fd9f24a78b46ebc9f06dce081ec4810ce8d964f1d21c2bb0a2dd08ef4a0067980233770454e85d32a478ed0807747663083b602a7f2722408bcbff8b9e148cf0cf2080b781c29c1eb088f1a82665c094147f6464e1cb9496da69c928b292dad7df15e782989b6225743d7e02a47730d176013969005df311ff2bb1db0c267ae61ffe61a1462344d6a93445fcb3528702b2b0cb72db8cc36b8bb6f9c892a977613f530888171f1826ae1d2c2725ab140a4a09874899439bc69b6d229c512f9b709290421349c5840115990104148295b6813300848fe9505fd200bfa81d71eb88810ce1ba8442d61062f57901f34a1c374028a263e84600426e0304133e79c530ee173ce39e79c72ce39e79c73de54d08f2014e8a02159908b882756f02723828877cd9f1219114132228cf0272342888c881cc88800e24346c44b46c4cd11ac43cc64121c11b648104aa45fd91042644300910dd1c39f6c08986c081dd9103328a10a9910444ac8844022138248106442f8f4c884e09109f19209e1920981f3a2a36ef8fcb76d48f3685a3a3a3e4cf9c941f74b5d6f86f653db33a675aa038f9b0e293f2fc69c2aaf1763ba7497199f2eb3d922f6624cf9bd458ccfd7c1e5f566d49ff3bbca8caf5c95199f6f4b2f3e2b45dd0405f1482389267d7e51ce59ba93d6a46e846fce523763cac67b29d34bbd7f9583b9e6c554ea7de94bfac598cfe51afbc598bf5f8c99238043030db9065faee61a73c358d3368db359022bc899f978cbf3b77fb9f41873304ba0f498e3f204b852c9f4a5df72cdc64d1d3695ee8b71f3bfac25a01f672ee6cf790257ceccbf8f257cf19274e9f5e35cb3f152b7a1e8d772cd76ed46323d4af7bad2435eea7a07b8ee5ee92f2f913a1a423a478ebda56bbbafe002cca2db4c70c381cc8815fcc98a3ce15dc7644586701d5bb212b3b1c2e7ef1212ddb7574c65f666cc97f1a98ef1aedfebc590dfe9ebc5e56b21ba00b388b3bbcd1ecf8277ea7a31e4e7a03dc7ece8cde3b179030d213dff29d1f5697d4f370d212d1fda78b00759911f3c1c3e0765457c70f82f0a61c81043860002880430082245b4602d14c8d80296403f59921fde391ebf06da05181631c20300f893010184084736aed9101a6e980cd1841b05f8a08aa3285c468c80c80fad06dc78000d221c3cb9018f31deadd5801b0f0042063300e206206e6ef09cd467038635102162079717472d4036b454a151721089bc6087d30284e8c99f8c080b88ec90a34284869423bc50a0d0312591a38fdc5002e241b2418f1cc40a4ec005818309301625d8a0388106840450911200fdc003a827054028d0018826f000c413302094e47004c411179123cec29fac080d456e7857a185116834c10581650a1f84702428073a43f1df8d4d8e7083273841a630a28426aaa002919432222184048d221c11638442348a4084191f007f3222c4b06d41bf2569ac761d86204e3fc64363570c29d19822888c083cb221c8644370b594e06f4ff8f62c459c6c8810977f9f086172dc93bac62e6fc22ed80443104adb8059705cd36108e2a5ef3004c110a4b18b097fc9e57197c3456f1d34c6b72fb99c682c25a7e49c493893527226e19c4ba552a944630a4dd33419115eb22110699a065f930d01e21a6973269af4a6cd9968a9691acc36b8d735f93b8dc5682c28c61d01a50b34e6caa417509e8dc3f4457b7a5ed487bee0a9680fb8dd437d680f9eeabdba75efc5d05e3e9d97fe6871ced0555a5e34ab75b5bb9c13fdb8eca8b5f787951ac4a34ad76db84accf45d02d91103d48bdc81f92e7362be4b1cc8d2e2bb0038ec18d03aed5741ca38a1933e72a6f3018a0c782a59e4c674fdc2745dbbe87a0b7fe9faa3ba9eda5bfe964cf8c4a89241459e4a4a9f5db934e2a94e1f5f2679aa24dee9f42814b41075a2fcc9d39e5c0649284f5b721974da91cba078da90cb248f899780f708d0f52c2e20e5df4b00cae34a42fdb67c3f0ab7d82befb25756dee559583e3fc086afb0ac74187237eed52d0f480bda52b6a590cbae3c51e8d36fafc2694481df65a74498cb462972d92697ad398d2874e95d7689d38842eb77d9244e238a2096bf9ca5eb1ce02c9f79cb3e753d3ee12bbb4b959db2bb24924ff0f8a6dd5f1282666cee4e5ff48727e8870e19cb352697d901b106414c706b104c2c1961a5c5ec452987680dc818cf61bfbed51efb88291e08bb0df662dc5dffdea7db46fdfb24d2735145bb0da721e8e1340430e0b4c39b151af2522bd21f79afd6b2a5c57e8fa126ae0686ebcef4e4c5889ff5c7870fe0f7610c41fc7edf603527ae6f94361e3c6f9b8128147596776aeaa36c3f85de0cf8dbbf2878fc37e3d6d8567e7812dee9cf8b6245c92906859491837833f18ffc28e1312fe1f18b98e0f17619e8a5fb06335da184c77c8af1083bd3131d7447094af1bec1f22baaee472ce20c7d9c9ba3775a7c40f98353209c7edea1dfb7dbc527312563f45fb6d162867bc04f86ce3ffcf25210ca96b26ddbb66d5b1234e43a775d735d6fc15dff1414f903b96eebf4861c4208650e2962116568199f74ef47ca90377772939dfc180bd75efec81ff9237fe48ffce9f2e709ef1c8f7dad2bc162aa06bad7231e1ebf1ebd195a0d7887f0c9bb5f80bcd7a352edb8a0ed2806924a6edf5eb956393bb37341e69af3bfdcc29be87af3f6b5e7b01d35cd296594aca9eb96d4e58ec3d6767deb764cae75dd66a5a3c25d12c4b97a4108e193f049f8247c123e3e770efe765ff98077f5da56af7beffddbdd375d94fdb28b974a3d77efea9dbbba717d6d93f2573a2b9d95ce4ae7458ad5f5c40f2658c4f71e7e9b49130e833f1993214c827003f0276372c35f67dfd3f7543e7dd6ce7bcaedcee1420cdcfee3d4761d72da77c4d7278f9d05e3f26bae616bd87ff9d99734c6ebd67126da763a6cd82e87d649296f7dcbfd949d4a6c3aa99505949f05c3f5b186eb531f089fba288a52fa2cfa38d7a0d53ecc2e6d1bf52e767c1a9332debbb0aca448d35621ed7a4c2a6fdbb6e5e05eccb6e5bcc57439f2733195c23c8561c152bed31e4e690b5828a574cbcf7d870ee06a878af9f8366f33d2eb47f9171afbc699e8ceea2c188f8fda39dba84f6b6cd1727a7915fab6ebb038dba89f83dbeaebd70b8a2645ab01511e5379cc7e3c539a37a5d42606d68bb543bfb27ef06e512f03a71b64b176583e78b775eb72d047e587df77c47e7be4a8afbbb360dc12d103d4025ee90f0fb1fa94c793412bccd70e451f45dfb680a2947e0cca3e6b07a64051bfbd85d9a577b1f3a3f6e32f5b6fd68bc6a48c6dc6d2d1d8a95be9684ca54ba131fab7bee4ccfcde12835d7cbe49db28fb8f6f34c6513a93a943d9cfff9232a8909c997f35157a09f518def5ab6357e54cb40e1ae3f9bb0e4a5df97390ba9e9f0a491994c79b813d4968c1110f1c7ea7457c521d38fcaeeba05dfbf099b9c7cf7ab17a401666c1f8b596d503b222d641ebd5eeedeee4b676ac1e3005baf2d3a20543664f9a08c255e04fd6040e9f1531a144cf0fbf471c01fcc9887cb88cc8257362262382ad5efc721e5e1fe7fc99e5f4902ee1317e8baeeba05d8799cb364a7f1fbfff56ae95ceea155537ee996b5ca85f659bde6efd7897229428b074f484eec5bfcad911b5fb6fa5ddd76c4a0b2a2b9d94ab3de9aea8743d72d2afac5edcce0ee3be634208490f21046e87224100beed3a0bf0eddb87d15aabe39772b6b1f2965b89f6f547bd1223be5b2ff1706fb7a2a35efd9048d63e7e58729adbc42003bc5d042b1fbcebdf117394225cb9563990053fae7678d7b7851e7969f5e27d477c8dbbbe7a71fd1743dce5b05ffa8bf555f9db5dfbfddac7fa71e4acb54f2ae9550e4cc17ed51b9a5eee935eb9361d78f05a2dcac36c03869778d87440e1368a84527a1448825f22a1fcf624940ea5bd7edb4b3cf0dab7225e77ee3af2b3ecd37e52937eeafa26adbbfba5fa2b9dfba4cfbf72ad7420ebf1fc32d7c8ab17ad5c5be94056875cca90126bdf77ccbe63eaa02eae69570775d93bb976bb950e4cc1762a3c3ab6fc906f42195b44d0315e1863d4e08d56563aab6c1141c78f7dc629e18daa3e5f76bdbe8d72cac97b4b069a76574aca29c532dc02d27d76cd4d253ca6c09b1703de4008e19c70c299922a4ff880a30c42b80c3f73faf0770383e0401f2ce08fb5d6eeb0d45a6b6d9cb4da99c3cd6aaf5685ccab6df86e98cb1b97e7e4707824e19064d06584cfd7f3c9a26cbe148a3e22103e9fbed90b7a71f462be4cc126f3e10f9f1f77c80f4021d0c8061ac0636cc00d984323d0823b3cbe84f138f49ad8f0749b178f0fa394735218a59c93d23a69add6deabd9ab69db8631b77135575229d75289ab5a73d564e22aca9cbbab3057e6ee02387193859ab8babb0c44bcee14a203f0f92a45757701f0f92b2b5cdd3d017cfe4986231ead8d32cc5ed7618cc757e187f95a45e7d27031116302064cf828c25aeb2384eb53c4b2c0f2400619ee80091c82a850c211ae58c268092782a065bceb1b5d872082c3c40cbca76a9053d67b2f124d03239688c1122eb0610921f36708c9b342153a08c9d3528556d13b182279768075cb9382091f3da8a2a7871e57001142921b244a9a5042637770026e77c0c3c760852a745c628725784c815f8caf25ca486bad4f2801042572e04409204af028618223256a584092a1274243530c112921a4c49112454a502cc815400927849d7e534ab9d275172e3b095f42d882aa416d8e62a153d97500706b6f0c130628f0f85535359c19e863bb67d800aedc8daa14321480b5d64a4a274591e4dffd68e04e71fb2202e0cfcdc91909858ecfa9600c70d95d15e40f3ca3ea85969732b0b43c3faeb507f918728f06cf2d65e0b57e7daac2fb999be3dcc6d930c4e9a1e6dd43edc16affc28ecbdf4b61470b0b8793430ef394f04949b2df8ab35e6eee8d73fbd164ce444b140b3fe18b2dfbc5985be3735f2ef186350d76737b43ae66ab46ea32aca0b9b9a78caa6c512ed420b75def00af1de66f7368d52be594d55abb04ad7d3084040d1c868ab85ab7fc5011234d2e2088ee578bff2d7246caf9f244b1202940a4372ab54704bf88638c24cd668ee18b29d28d292ac4d00c3ac048e268079924a2b0c15a6badb5347248220997325a43763821073a1d901b364fcea380474c1239dc0093840d35b8b842e7a50838a090d86901c40e2e12891ee4b420d1830e0b122b7821c103123928c9428913254b9420515244c90f4a80284181121a849020b44448263404212142303881900a72844890c428891249900cfd180a92242845a4a77874a2456d9491d65aa748d26343121624e9c16badb5d62649729048723343153f38e2091a3847082971841045470c9936890e9cc08d43ca218c33f7c59081866fc3319450ca4e6f3a1f04f44d7cce7f3cf29951af8b00ed38e4400caf2d786de195e5b4008e356d53717af74a871a7f91bf15e40ce6b07238399428702c63844f6ea4f85d843000fccaf0fb82df8ce3fdd0cc6e9fd03d221c6329238410c2873752fcf703b7b966bbd70598059721dac86867405274841024482031826408487c80c4064862808407090fde5b6ed02490350149132d2fffa275a3013125bb010e9aac0787bb032d1b410d7509d40a5e6badb5d65a6badb5d6bf3d0eed371cda6fbf7531689d0d0dad42cf97ff125391df687ea37baa023aa26a7e9c1f810b3c9e8aaa490f300510558fd77fff96bc787c491f05e571a7674168ee63febf9b5c2b3e269729c7f432ed6c3d52c6c35bcfc73c6c5179f8304854ad3c647908218750cfa28a28aa5c7493a882f9e88376bd192d5f5d3c3ee9b1101e8aaa958f8f6711134515cbc7ad87fa6072b93ee66d68523a9404fe631ec77f4c17430f291f43cc7f97d2e1d8ffff5d0cffbbb3a1815ddf3171ca3ebdcb5679d8826f7a78c7422e2ca4676f469194f1df2f2f95dec577c9b58bae438ef21a0b995c760a961ccc4ef9975b3ccc82bb78eca21bd21dc6b88b37c1ed6277f82ea87f7968c35fb60eeae228976fc9167bc6948bfd8e6f78fc963d8578f8fd8e850e1053f14f5b0501c4547c95aeb77094ff7ddf0ccac76c14f9a616bd443fd1592812f1d84d2e938bc7a884bbf7e4226e308cb2115fc67f8f826fc35fc781d8d5b8e86a5c442a4ab319a5e2e8a852717464a9a0828a4b85d5a8d8a8d0f05f8c102aa1e5a4e5a4e5a4e5a4e5a475d43a6a1da9fc70d882dba0fbe69a97bea48cd70b06e3e1910f4b2945251f0e493e2f067c1a322dbff7cdc5217571951f290577e9528fbcf5238d3a70e32105bd19b3d4d3c3a54c119269f89df2947a26d08b3163ea51bab98cc5214451545454a3b5448a181428386fdb3671bf710072fddb93bad612bd3dc9c46ddceb6ddbfad6b596c010c4b97ffa2bf7a66eeb72e48c31c6186b8cb1c6188a1aad25b1d692d6120e06531899c2070fccda22d87c5b9f16c182607104464646464646464646464646464646464646464646464646464646464646464646464646319e16139e29729afc48618509a5047f23e2dbb3c864520c3122e2f2afd11097cfa964182ce75c042bea30141515655886c16028282693c9d462d2048b26415204211549ee493018ac450483c18a603c4b5888afe7951e88e130bec7f1e4cccf5c432b7d9fc5b4115fbebce122c6186394524a29e79c734e4a29a5b5d66aadbdb789561351ca5c53b3d9d062a2b504fc526b7674045b5899cd62942f29a5ac734e7a7444e9acb2bfa0a0d6ac35d3f09fc642944fbb4859a83246d9cd58b44978511549dccef12594dac69cb7b46d3c5e7a9a6f3c5ea23c78b6114bfb4d4f43caa37ccd2809a8bce971a874f94d8f23a5b3b986ad5fd22e9e4b5d6b48e7ae730fb77ff9730dad919cbedd3510e5c583cb9761dae42895009b716adfe9cbb57aad5ef7eea07395b3d2f1d94268cc0524b4d211825b1013f07bd1318d45159c7176ef032c584c59166cd639699ddf62f68f4ff764f58074c3af13c216685047655c7e2b898edf5564c4b0811a9e86d5031a00be7c958ec29f73569a44ef8b7b82609dfaa02e2983f4b0e50a01f18e562942771ad346748efb145bcd47c8cf10a0558eb672fda03d407ef444d506e44d2ac4a4ab9da0d80f2051758dc462417c84fc6c2b9d988f915810212b9d55ceb6726d2b1ded4979dabfb7ebd0d5b2d2a1415bd47ec0ef058d05e1d087c38e33d1587bdcbd298780d8c2eeb68ee84e835eab88cea13dc576e330855cd76d5ec61d6b07a60037d6cb01936b5d4bd28e0ea1401bd3214051458d44557c930ef1f8a4d40787df2242d787748891a892df2aa2217cfb7428aab419258aaaa2a8ba2f7987bcb37ac014ba6ee3840f4e85a2aad326322776b87c2aa3435c3eccac1e30858eb56323a7b073a0059df4c88a5a394a394efeca9573a692d25a29ac1052aab37a51c94108394829a590e3385af29133f649f93b8d01b7f65566dcd2a7dcd26ea51355af1255b0b3d5662e44d3ef5bac0686cf9f374342c17b2988ed31144170fb925248df722f370c7fd906f774f66654de443f28b8fc1bdb6235302fb7b6cd98fd4b611c3ef731fccd88e176c27db998b2a51f6e7f9b41e0d6f6a8cc8200e743d8d3d2026beb8d9ca16ff1db0e42f8479c9e7c44d5d33fc1a2ea4f3f20fd134f54f544d56987b27a0c71fa3c07dd29c6315ba1c442f546cad03339439f96ea0da7a6dac3e9ebee81f4ec96f48ca46759cf669c76938bd3c71b057b31e8e3d8f634668b71dab110a7cf79d0f4513c70fa5a3fbdf807c169bdf92ca494524e1289d4829ef5eb4a67e55ae5c82757392bd74a67f55ae948b972c9954e4c8c43232b3951b5e28aaa5fd9892adbddacbca20a1655bf8203573a93eb68ae03ffe58d0a0c94b7bd220aaeeb4f0c0f77050c50500b979c8178fbbe51e1127b31e00a06e2f0390a6e38ec313d2d5e2e3eb480c104c161d1eab5d289897111fb70c4e5e356119da33ee5f27da2f0c171e4606681724bbbb4012184b385c9d1396b58db8305cb3568ad33aae09c733ecc7ae59aca3720ee032dbfd31f2ebb1f3c77c7ea0153986f6be782dc8e86f22a2753fab9723967ee92eedd9ee372cedc73f439ee7b87dc46ff5e99f175ad74563a2b1d9ea35d01b7454aa9fc9da3db9f96d2483fdaaa6dbfe518b7c8fa9103ff23ddfbac9dcd0549c2f86fcc376f5572f13e77b78f9b76bb0e9f571f26a731c66fc398dafb18ae5eab57b6a5c7586bac35d61a6b89ed638c4bf84b566bacfb8ec97794fe4a19295feafa0e8d65c915e35a7d4c75f5e1b8eb3a6ee6f04a67a5b3d2a12f52b44ea2c8e128f0272b9a150571a8c39f0c8a9f927c54fc3773ce99f6edebcbb0e54ce17d58f3ed936badc8eaf1f931d673e699f57ba639f3eb67ede45634ed2e03cf015b20bdfd567cdbe9ac95dea6d352777fdaa74fca9cd6a948560f98824aedb86967d062b42c58fcf7aa7c55be2a593bd6b27e441ba3b5d1da686db4ac1f31c6c87a45960ffba2b5b6e2afdf75c4ae43dc6996d54385ab4650c4ac7d29abb48fa58482e789274f14f102f0277b228894f2b3fc2c3fcb5c7f6616a40b92e7aec31a1b7ee77cfb3ecb1c1a106412aad829c1cab572ad5eac979cf265395f525abfd62925ab47544939a59c3b5a0e1f15e221fd4a87447afdb4a298b45c353bb30dfbf8b1dd603b7bf321297595e093f6cdf0396da523ff692b9ca3b7d56ba563ada6759d56fa28dbb45bc0f6e14fb8d2e1a9525801b92556701d7f9ea48f1bab07e438db60bd583d6adc8a36a29892bf35f9b71171d9698c838f7767f960e51a51c57a450d077dbb1755b405cc63dc70ba20b3c882c7a72d3939131d29fda31c1b95bbc082bd17f36244daa344f79859cc9bf1a40c1d23ed62e544b887ed31c6db9e3ea54d49184688379a2d4a578cd37f90db6e628a7e2b08ddb79e970f4ee96f2f49b7ae6f389cbe387d1a08efb641be6ddbcd86b3b966cf9bb13d9d4f38fd497f62416f284e54697bdb3e6f758bbf09f17971de353c4d0fb8d6522c07f7df8bae372122ba1759b115c96d2be2f1c1ddc37ab17a6c3ebc4d681bda66f083d041d8810ab63e9ddfd53c75bddd1827a62276e11c7c13534a68f812de0883c7273c72b1caf342a2e73f1f213f43808c04c984866644454d8eac788205abc70bd692e9d90324aa62373e3a04f5f1a991a8d282843a1b8fcf8a6893379fa669f0d6f91e765b776fa40a9c08e29b3f991340b66ef58aa909730dfb62489b1612badb20b6da37e3711cf771dbdede7f5cdb3aa86bd29fc8e4bea8c4544beb08dd5f74ccde8c18f8e29cd09212c1e3c7cbc94ec7143f81eeffffff4f83a409708cd583b5c37ab15e2cd80830754529a59434cba3a21e995998724e2925a471d35fb92895f265c7c5f86a8f91cf911010ba0e4ae5cbcd7abd94314ad96d248cff5305474fa870ed98ab9c950be3d5cb891027334080131f2f2eb43051309aadcf5d5a08c67e2818cd76d15aa86933d780792c730d6b6d6b48ef7b511c6a1ff7dc7d035c9b35b40c6b15384e8c5c3b2fcf6107d13b82455105e3e330c2d8c987a61997cf71d05c9461129226219ea35d52abad2c74af375a0b8ff163bd89aa8ae3ca79ed4415acfaa83c5185821da7bdfcf82f1ad0c2b96720a6e4ef8829f9dca5df13f91253b2a5097a6846d4c47464b2c2f424aa50b57bf60508dcef51c5021d8c97f95e6fb6d89b11f3f5a6e244d5092fbfba6a0ebc312c7f827cf13286e54fe05ca69b7ac30261c078199997e96290897bffdd1ff33acd624a96585c2a8ff26171b1e4b0bc5876744fd73d16b88084d005dc30e6e13fec1ec27b9a45557fb3135154dd5393a802c04b1f4eae37c3c59bde241455312fdf341455fff24db3a8da2fdf441455dd4bdd837d6071b9e2cbc41863ccc7bd5ddcf47029c4e2b200b01206e6022db80d9afe69762a923260b49c5c585c9ec5247461601e5beec58eff32ccad355617f35bd1864f17f70231256f6701998d829ffa9987b15130054309d73e465b816bbf5331a5fd095bfbbdb5efb6f633fbca19ed531bc696d9f77616882969bae1f25dec2df662c8dcc9dfbbfeae3831253f66d79b98920f3b0c636399ad65935012bad79b16afe51a2d505d73140a651292324c320a3d0cccbbd8dd86bb789c6bb89873da5a63fe6568c3610ccc4798bfbb6f80c3a4bc8b8df2766fb9468af62fbb5398ab85cbee94470bcbc924a4555850b49010974fdafd44c4e5e7dd35b7d56edadbc9b74006e4cbb43921bec8e2e177b92f3d0df9492f821ee28b80fbd2dbfc241cf9495de41c803cfe8c9bdfa0391adb2fa6e8d77aeffd6ddbe2b6d2a134462438c9e14f56841737007fb229867849453f7921e10cf8bde8bb7337e28ce9b90e07e051f87e9aad3cea75fad3ec44742a3a3581280420be00709a4118320fe371c83c8c00bc8c0c0a2f5377f7767fe400204d3198b23253310931f99882986211c009c0a3f098f3a84f01999f790ac0f894087ac081c2a75e0401e850f2675ee6673ea2d0a16487aa9d04665ee671ccc83c8ecf4f8ab906a9eebeedd690ae7677189ee8b7e151e7afdbce988add8605a15b5ee6617c37c556662a6f8a998274fa86e527cbdfdc78c094f9a8bbef3006839cf031c60ddb3ea2caee1f51f5c2e5ffe7cdd03fffe7efef4ef879c383e31997791b9a08e3651e078c979179181d8ed4c378185d0c303ed5d9d0c4ffba3bad85f40dcfe641bdfc8b8cb52fb294f52d29461bbeb564b6b6bb115373e5bb1642bd5e8c793a3539ed7d228aa9f9bf4f331e3b54d18b311fc6461dc999f9321be61afc068df2a8a23723fe7cd491940143e663bec54d69092f351fe6df7cfcefa9e893989aef82c7e7e6c390d94f42ba84220ebe14f793fb92f631fd34eb92bbe83ae5c1fb6936795e76a73c50bb531ede5f5e5dbbec3e7d6861d97dfbe0f34f27959d12e3ba0eca73882f1588a9f9e223aa62ec248e987a79bda2aaf2c4a24afecb0eccc7cb8f979e17205155bb07dc889433c5f20b76fb93cf8bd1398ee354b60a3538fa051b5b9421f330beeb0b6373714666bf38c373d01dcf287c796dd89b51b74cfaf764e87f4f8629668ac5d75da9eb5777cd39536cebac29c6039f8f6bb76124d01dcff87c4b54d4041f4595ed6c3c6e057e125558703751858aff54a029c65d7ac3e40c8a05f9bd02a7199f9b87cfffe123d0ddf4f28a4555fd098aaa6d7353101f21a621516502321989aadacdfa0204e4f7d8c17ee90bacb13c762faf24e83efb8bbc11461927a93eb6f33d0827a9cef83768e6d0fea9365d7c11c566515e85fb9eda17cbffb9403ae86d425c7e4dc6db8c789bb1ce6d7a3c390de6a727bd5ccc36f25f9bf23854baed71a0fc93331bc65ddc9dba5a433a3eb775189e70f8a67f1942536c035c9736e9391a7b136f3342bccd08237ed8722fc7486349680825677913daf27ce69acae3cc1ab7b759297243780e3d74d73cc67f9be328d7d1cf67d05d739596dad9789c3eaec2013a673bb9b94aa774e167c4729d07544007053210011c16b800af41db8ed3a0e17dba1a41cf97f5b7b7a1b9b54349400ba1d9a8c42d75a639ea14910c000014a315000030140c89c322a1501405829aeb1d14800b839a4a6450988a034a90842888318c184214020000400c109999a9a1420008040026604c40cc00cc81980098033001300163026206600ec404c01c800900d39ad962ddcf6fa366e7cb9f4600de1cd0148c29802980790073105330e600a6604c014c01cc03985f103023f54977fbde90d80cb223a95a02654065804a804a80940195002f012a012a0754065c02bc0ca8047809502281c00c3c6128526296ef8925346130334013e026802680e614003447c7072ff1a53b4f0270a3890011961fb0e845485018f031abfad970e13309a609304d904f5829e059e8540efda3351ddd04dfb5efa40dc5252e2b60dede6f502acfa2a2b36da04494c87d6e7cfa9bc37ff32d1f63c4d10d9f167bd8d9ed59944a53fa58eefcf7c1d72bf9000ecd48e6ef3969a7ccfdcb89537d79f21a937fbbd66738dfaa07bf0a90d5a35e5b6f991268b56b5273e5937f43eb6d4025755674a066d11503bec58c1396c9f793fe73de6d107e047fb3769be0ecfb6149411304d602ab1ff36ee968cbd37cee25046b5562dc3482c025c4329abe901d211f03afa0a41aa796245a32a991aa269ac1d3c6d58c0361fa6602df8d6281ab6b863992e05e840ae5497996ea6e698c1b145c9d21a87171adcfffcfc9272dc537168a770303d7f1086d86a7a4719718db0caefc97a9f7244a632d575c07f94d1db9b415d9a6a9e2ac4ff472519ca9f4ea63eb157e20c6082e42d1354c5d4075cda21f246aa92204506568332de3ee640a0122aaeb690c52d97ba6cc5fe5e67be1df59b21e56018c03394022f3eb9ecd82280a40fcbcf456a615cef2c026f59038283348df8b70b47ad3a403bf85aedfa13a6b6f6ab9a08e59f7a9d1f100ce269e14db53dcf82cbe1ede51b0ea4da78616cae098c1f827a6e09d583c6454806f427c670ae8c0240b463cacf20bd4d059b78e10df3b6160676ef873e967ff0f57208778628e760cad931c5b6d45ba83129a9061137e8500c730a8b1dd51e1ccd8daf1e0a0cd2239e4ccd8b9512f0db63d96c6a93c5d257b52a075e85df3b56a734abdc0e43b29a367d1e29eb6819df8f3d48795031a0befe460afe8be1d05a089f4f6920931e41e3b9e75eaabb555badb85e1858387cf97f99c1bc2e48fad76b3f42674557980a738028ed571dcbb0d4b9df8975ea0eeb3410953027b940e391131fcf4b209c7813ac248aa628d6f6d9bac2c26881056e7a119ae7defee9a59976e78974d654c5424ba2889660abd289b24362feaa99f407da23711820e0514360877a28df52fd337d6707580d6196ffdf02273bd034bc369a2774bcb2b3b9c5f0187a525ba121b71bf4eaf2992e2ecda86a12eb33079837354a5eb56b6ad7432d8bdd83ced3756d301c5f59b052bd7b3afd23e35ef9266a2c380ac560cf20971638692379c19a4765e50fb570545a47594d9ff2919eaa7d4cf1d13a8ec1be05fe254a3fff9529f563d16e10f20a9f674f876563d732d47aba7f5a9313f1d690352552b8ed7d1f3b47be7c23c51abf3f2edc0e2f4c0a1ecbb8080276bc5f10523da4864c2f1867f80d88acfc63969f3f83caf8048864953dc1061206fc0e3419ed67914de79c6decd98719e2518c0eb5dc55c4957b975a39ed8d035137e965c2e856c1c0e03678a9ec7c95b898e33ba6365dc2379f76c98a9038af09d74cf82ad548f677e8d98946afb6a6b2e451c5a3ddb187ea5dfc9c21ee1c5d4313e135253f58a309eb08d9c71cd9ddb358d3f21180ef0f1001e1424576c7fb4e780c5b35740d7d143078ab79a143574a022de93b6cd9c56b0e3407621061df2a05fa1696cd91bf72849b4911cb982218cba0acb2d8db512daf567329f4b747395303a4de209dea14170214f9613c7c9942d23a4963d358c9b0f99ba347602a1d061d22773516f73e45a79cfb4455552240727422b8e9e19dc99e16d634b9157c85ce9e3c581cc72765671586c6cce0fee7f0eee7601a5dad43f12831b8dadc4ce301bbc540b5e67450850d9d749ef34e7a8c22fced215c41b38668156f16ccabfcf6a386a1d8c606fb458581775a1b1627d5a7c8912cef368b1c21acde68cac0a159ddd9076f12c2ff95155e7e4861e370521e984b7f90d0c0c48ae27129d8ebbb5acf315eb18cb2a63f56bddd2edfbe3f68a27afb53c57b04ead9806949f0403ad5266eccfc401ae95a8adc8839f8eccdfe54b58a5376e8d3457cdc4005e1d0fdca48d3a57eb719c90aab4e6397044309137299d4423649058484796ab0e3248eca1b8a61a06196e2d45dbf9760224e2a9fa7817342f9bf813a8585d78247a532eb237da8d0ab3e850373207069f409431ec3c64ec23b072d369e1c36728208e43e9ce9ecc43a212a49b1a6aa8a8e3684267b8ba0a8cc0af48c88f80a609121fc3fca8bcf84c81099ede1d563bd21feeaabda70f0347aacab59df5c9b9b93c7d4558d641d8d1c885c9331683327191f5160b0f3330889082d73927e4ee8b0b3feb04cc4b09f43cc51b6e1106eebfc16affe0d7936d1dad8b34883816eb49fea43e88f36aae6b11a9b4f5578c8f05b0b5b59334ecdd25fdf4cac2c09d52fb114b2440459a42f552498729a02007cfe48419f125102ea50eaa4d21833b39b1532f334dc7d635bf4d0b9323bd500b0a382de9702f911d3b6c16e7486a94be4097d2e6293f194fc442e68748f931137d7ecc39f5e5325e14b0d3cb023638a9e54d40a27cce419b82e9b7fd927630c0de85a4c600e853df12c53ad273911ee56526608557ca05e396a8d81dc8f2071ad71a47b4d48194667acf361e5c72bd3dcc97c98dbf95225f86e178ebfc6c6e4514cbd110bd95a9a7262fe256c625bef211b0f744ec6f7fe03192091cae7c386bc846b40512383d94790d3be59de0acd070d69b57b8e5d1676544878a5d390d93c4699fc1a47c94cecad56a4b3b7d9252ecd2497eaaa7696cf0bbd3bc39fe1f3a1460b01faf6922a18cb54951122495d75fc2e701c88d56dd4607bd5ebd79b66c382feaf990994898fdcaab91621062189dc7f84179abb33d7f7683886215bb3b68fb9460d4c2495345f7249189a3fee0386051111431d33a88647a3241b388a16dc35cc5733f3c4199cb6e490fe9c9119680e332400cfab9b733e8566d63622182deb3d8c4d0a0c58f188aaa843ae2012a9e2811a468169c4d2fe734baa4f90ce33489078a6269cb12ee4ccbaf9a32f0a8ac0899bc2383e70c0b1493b1d37f9a22cb5518ada9daf799dba0906b053cfe8925050e1fd9ac5a0140cc4cbfa2eb8ceb6cbf40001a603f8da0b172eb24aa5d7c6486134982350d1fd9f07949908c8807b01b60b4011a570d9bf09181daa5e279b717f021c8fba206ba3c361500eeb1ded9f57b3ea11169f76458f92f486613880f5a26fe84c04ba54841d02aca921408640ff000fc2548492a66ea6579ab06f91387aac7f2aebb135a4859477ac7fa30df5435de3a7dac71da5f5c2c443f1d682b8670ee0ea70b80f2c7663b3e5b748bbcc898e7715a9b1e3eb734da4d8500a35e0d2152dc6a7eaaa9d69742fae122dd4b7f9688d4a990dc2bc14827431a6b1856c876380a39a7d1c61f95fd1b61b75b86aa64db9cb058eb50ed1185e62265b414816043e17226721164510b4dbb30cbec7f9e2f625ee0e108f94a60c7de881caa2e508617918f1841e09adf7e452cd89406921c09f10e5861a2d3c1a9118f695276e370d1f6508e88bab5633266b5bab85215fb6a352f2702e0b1869bc732e05ec706cc702383a8e0501d58626bea93eb9e66486f66dce60c06bdaff2718e427f27aa1ce10c066a0fb5e30eeb24c51ee4f687fdf9264b77a211f3834d7facbeed0f238211ef8ad5ca68da6636e811f105d2df1a423d06256a99f3845d760ff4a6d326b79c6baeba489615039e1e42f0bcf18fd09e379e8f6d78b3880888a9377559b5b3e5d06c102dd1a72359b20927be899376e8330aefd93485ec0025384566744106ca088186b398c8e086cfecff9fb43e54e52b1423cdd9d434dd73b31523bb123c17780373d48ab2333697944a06de6cb3141927ba3c42feeb72ff1de2be7954f6504c9b67adb9ce773d7e6baad0be14ba6c6c9954660bc3bd16feca9d734c765ab2023ddb67fc6648f495116353ce0bfa5663ae708d831518a7ccfddf67549a1314bc0d39412b89226ae7fd632778b249d293d89c42dc61d0995db5e64af701a9f88854b4c7ff7d20e82c6988efc595d8dbe368bb510d34e00f62edd724a66572941486985edc010d6cfe9fa845c5de2372bac9b1520260b2b02059f4df5bde705b99a83fedef25b73935e9b3fc8f6fe55f6fad5a304b16717088c5c751e1c9ac801d21ef5fa5484423e1bf424e44945ee82bca24a22543e13e6a137b80fbea8cc187b9b78f8af305e6612682a8ca5add0290a786e0abc33881acec66435f3a5eb50c118f61da96ea3e40fef88ad6f3af7be8a491b228458c69850011f322ea1d4c21e2a71c1781f93369c645de493d97f933371f38886736af5b830ed8077447c3b471148bb241c1e689fa6bad3497475bc7764ab2848c73d9310084e3788d5ef37c565052550c7b3c87c73938b1600c1cefb84c6e46ad50cea6fe0cad6b6ccd0c2ab53e848c21ee311bb45e320ec5c6246332d54de9f6b6540c3bbeba894bab1ad1f7da68da3ab3c8c421fff8e1801e066c0333586aa07597c9549f98d1316e89d99e6b711da51c096912d86466982c5ffcf192d855638e7de790b346bbd1766eab3ee9bcef0b27bab4fc00bf358b048387d161c4065cd1d11777a582ce6414dc5de5feb1c758a0b4743df69a51f28924385c64047bffcedf9b063ee423d9e8a8fb389937400a97a54eb708b956d6e0bd33e283fd15c2d46c008f7c3fdb1e2f2e130389d47a7d3780460fccf2d30e0dafec74401cf0a9d192b812fade4ab4eb31e6b2c9b86f64c131b02a3c8006624baf7b34204e71295227acdb12a6ee876a3812de6ad6b1d5a4d10e40f4c71c71e6d8482f49d7e1b084e405c612fa1459bbc30f9ea1e406d6d0fdced59103b63b3f5f216d81a5d8932a4809afaf380236a599caeacc01b8eaf9e913db3709b67513795df0963672ac65cbdd9be18b9c92afc913ebdff58372f4f5d41418f731496cfdb0720756a811ac81eacfd38406afa0df633bfc58033092d0c8001578b798093bad91c9022c29698fc17a9c2a47d78d03260e2592b0026b418ca0e8ddee57b93ee55319b8447446b3c5413d16a89d80637e83d651af25df5c7287dd50dd45c05b088b59c929664dd40a11964cd3c511b9a851addc97463328cca31464124108c5988f9b70044a215e6462d8192da84f9d9d298a63a5c21b7313a8feea100c438afaea79e3f7e955c97f99877e44581dd5c73f38d6b58008f8b99eebf75e72e3d6ffab3373cf10a60a1fa01bfb95398a876b33cf3ca264f3e85b6ef4d2ea562f2e0028ffade636dc50b13953f54fb7a7349735fd987464d187d8803f1dd973ea8455c96dd629daccba5c7dc204069cbe227ed7834808b45de3075e7ca1d50840a23df32551a0ba1250455b7af6e90281748e9d21747606110e71a121a235c359d7270834aad631698202c797115b3adc61b126bf835a6292674069ab12a19d1eab01ef2603895bd302d6aab60767439a298e9bc61f32b1289d89a943e793beb47c4a25fc6889eca9526ca125668170269336817c4489c0d57f484c92a879d8e495b9aa99c290c3b6e5f51d79f251ade66a34e73911763e5a1b09aeaddae99f626fd802ae8f4bf280216a67fe8ae68e28d016121b61182396145a23b44ba0406357c68480660a4307f7a417bf4bbfcba025de863731a7ec01979dc5de4e22c012c3c15e58e8e060316d5db194bcc4f9c50dd254af1dd4e7a796da319725067b8f5c07305e3c468295f4476e9f4d9ca2db4d6c2611ae4b5da1391d6a4ed2dad96eb368d95d3246ffdf4fc82edcdca576fb6b461a7975fcf1983a5e7d1b642dfb4dc6ed6750e2a50f3d2295b6d3a80e9fc7617c2e5117d522b1dc2864485564588124653188909458b5efa884e877c28e6956a20efb773097383e74fa17cbfa09ffa46afc94f93fd224b393a7fa7da98a653c4f00dec7b7ad2f62376e6b1153d7beacaa25ee20eff3979555a33a337e20e2a0bdeed0508744fea85d52644a0caa104a90a1cb9c64b477abf7a495de037c78340105571f42cf420a06dcfd520abd7d3c4d66313805fb3542b7cbe5e635c43cccb47cc2c66a6f6bd92a45c2cf3ae03ef79b0c5472ae6e2ee62caec759de577a6d5b8234c3af46ffb93d433dbeefc413587cd09ac5bc810d29efdde83c030949ecaf4fd17f5a3c7899937734e1003255f6f56eea1f1ab8d645f868170fe05dd29f67e7e9f6795b3cfb1a678e95c1c12d92e74788454645a55714a7fe235c1c1d43e3014eff563a4560d14aef19a433f96a9bfb9c04e5135c0a4fb8611b1db98f47d263aedc3682cc34e9121170450b04ab755813303f7d1bb9d819f0306de80a6e40556f2e1f647ac39b58c0240ab11f470817b057cb55a544df396e6e1da39503f025ca043016b96063ba12379c1898a0fc4dd7648357b6577f592a594adf4658d6cd363199d2ba160ff456c75d12721905b98a504f2839721c5388b5245accfe534cf1f66b4a8295ae2fcf434ec79e013460a86cdfa7c68933c85cac36bdbf2f7fd9a81a39943034892b0098d603250961b21e294a4dbab0cc94314250765a6856fdb070ca28e938316b67e7cce63f4e1f24df2ae18f990eb534fcb1ca9d807eb061dac62a276389dad87b1116b1959adb00b8297b25b22b9268a0d534e2667bf9bffd1e861d4f46b68efbc325a3e3e3bad4ad713d86bf570c4e42fcd1aaa0c85e012150485150b4bd627c5b8ca746122f7413b779dc2d62cd73dadd6d7e28132f91fb9a4db2c93a53b06f18657f7fb921995badf567e147c9a73099c5373249252ef4277e66edf43ffeb5a0d58fd7543d84eff636e5c829ef423c2b3527a35230a286812a92124567e7c2a9df870e0fbae11e7ef2fdc174eb9db8963131aceaa7dae357e4d68c4171a307f185faed9bb02f6ee8fdfca5c7d87726428e89c9473e32f301d7f2c9ef39bfcac7c7d227069c1bd063e9fec6c26ede5ae56917e7626cb39d5210c5ea719510df3cb4b576dca3e4595bf19f25de889dd400a42d9592d16ee6a521c21b7f8bca5a5cf71de6eab7ae4d635254f22961c3ad99cdeec956a2af1a305e8883f2ff63ced7b9fb43088f859e17f83129269575a4c41a2e21168233f0b5501c23c4b0384c1c5e472f5cb77ce62bf7f9cac6fda53c390be5825c82647e496c341b0c06a020495c0c5cad61563fa699c761362e7e4e131c8a5e49f9f76128f342f6076f73a5ebeb5cf4a3b5c198ad4dc21ee764d282c3491c4fdc60c5664a8810b85ff79ac8c2350ffc9a17d59369a3875664386ff38c27f98cc11fa28e16cc75c71b23fac0f8b4040b229e16672926d04f8fae079c8b0280110ac1f1b7cd6f8184741b1927a93438c4586515abbfa1dcea14757ff2b7b61115f62a2502ceef8331fb8e91d6f207c5633bf83c9a74d0b2711293f2bc8dbc72a6fa547a29ef69e4a62053219192528ce2607828f38270b2648ec1cbac345aad48cf1ba576b6d72f5cd955fbd3c19c218f6ff987c12d99753d97b31104ad4e1758ecf4ce6467b770e8f1e5183e3b0aefc77e35f08e0f14cbfb58453b3d94ba1bdb3b0213fec5222b3f08cfa662a1f5b987c75005d2d05866d3bef1407a880a004a8bba13e698366f32811aa8f2ef696fd4f28dbe06053fc42d446a9cf3c8bb3b5883e742f419e8f6b30760cc98a7e1841f1221a17d7d4dacf560760f6cc8b993ff611b4ee9586b46464af04fd17781688a57502f964e222e3529a637e1226c264f943e1cc699f0efdaaee8e4b16bfb39847fe242b464a40d1d65756cf8b9058b0fa1fc1a1f6f53339f1122e8fe3ecb384350732351a3a1a14d56b0ad2959cd7674c8358e60a75b51d520899a6da412a24cfb5c4a56921708485facae9231f0a5d8614252886d80982a926bf32238f3d51d4b9f003d623dd605ddf08f3f883526d7768e6597a5fceb14bf28c4831b1cb1d2d8c82c327fed9d0b6514e4227cf95b2bf31a3c69c7af7208a522ed16b343bf1767482c52b57b84d96583d5816d69f7ad63932880561df413f357b37f687a32278362b38ff9d4b9d676c873404ad7a967c98805495b7809a73f177fa585c968b4344b6992ea8f8439e7cd3e226bf78a59ba179bae58c952584a674838cab3544efa6cd52a102e68f41e66b6a7f965c5912e546488888a0767220b114993401db38878f3944ba4b8275696f5e10377c54931601b21016bf5cf8b07321dea3c97d78636a7bfc6f378122fa015849092b68bcb655940dfe87a508fb65216210849181911ceb28c6824ebf70c1e0131a2fb85a4bfcff2d7e77bf95ec441922814874de36e717980c3a6047e382e174450a4327878a934a4bd7974bd1128dcb71aa7ec11e0986495c660b535b877e3125612191c0ac1629fbfc79d033197bd40e136764b792b1b02fd871a13f561b40455236e65c8184a46fb44486df70dd1bdf91ec2f39f5c29baf000bc49fdb51a53f0d39f915ff25d4aa953782ff129bbe081020c5e612e5264206ab2044e23fbf6df546318da6d7f3e010a5e814a4c74bdbec8ec6b2a70aa68dad5cbd205aff91c7cabf43536305a1bd68491ebfba7564cbba07582fb5b0976779a244cb38747f56f482a982c8589306554e69222e862d084ad62d3ac1252bb9b893a48d87965044735f2397fdcfa3d655c6889abcb65a8b5ab18c4895b6da5e9b7bee8aec36c606a6641621bf3ae91063296ff4e6dc2b1dddeafcb84c7f913ba1aa15e30120c8f5e0ad83e7bff98975e4f08f0942902f41de5e10040d5a3bef8e9c5c0cf7f7f62522e2a537829471698417519d6829e8908b2cab837c982677adc9248ae5c9833f0dd6d6f6664888b3f6777a379f9c15ce964acc0c05bb7f331c18477991a5303c9ce0ed6b006a1d185df1fefa78075713ac7bd6b2c60cc613cb789f612f206a684c7365b5cacc7d3b16a775a53fc7098e6cd8a889f66e89e1112fbebcabfd4b8e0e66f4786be126f41aa5d978f03a7706306819682408c90dfc421d6f55ea7fb7554d81ec3882fa8a0a0660f51ec391f47247dd3b84cce819ba27833fbc637c93bd4cd3e567e8cac0d22c10f4ff1151b173460c61bbad0bb9f5ae3d847302200c047b6eb4d39bf3629a0f4aecb2d173fe3a6f11d2b3dd45a715bc84a435d92d5cc0b34df9699274dda1f0f50469247595b3ab069d0be3245d64bb22faa30c90a50081565aed5f32867534b456c758269114d39528bbbf6a31ca9d5e1fc79f913ff081d2a2bcdbc55b1ac573f6216ae8359f9f2a625ed35d1af24fe8536346190153b4671025a4595629b2060b77714df023a43fd28db88f4727356baa0b4ca301ad1cb1166a509628dd4b01182b3223d059e15abd1836810a8c079f0822932a234b1e40947cbe0bce8520d91a7445b64a57e4a635e7682b5818a786728c88be3cb1f5c368d3ba8f131aa400c28ddf1f4fe2f2d1766484be953c0258aff46e0320ae351f417c19729f8035a84085c42e11fe82320f0128ae352fc03c12e08b8e4fe45742fe6fc08cf121406542fa3437818319e5eb51f529225acdcb5a7071c37377378689bcd01f938a1192bb8c6d9dbbeceb1c752f7a5ba7ae9a0ecaa0a912185ce4130a90ecbe26e660ba7b0b67c8227ce5c886b76fc862172c691384a085728a225dbd107b7f80fc5af913afce3b1f41634b90729ee7c946d7101df3dc26ad987b1b574429b91f0028e94e4eb41d294a9d241216ffe806e5c604ac95832862f00fed8fc1d232cb382f44228b1e2a8a265095c223d628d8914d5b4a71b6564036bc71bff852686c61a995f28922502fae7a93466358f3bdbb9f54b37971a804c43840b12bef1304bbf9c853d4bb99503b4db5a4db8d4adde56858ba545c4930549d07ef296a47213378d01f4822cb1e18a20cb2efce544903f77ea6aa71613b4062f1b15cb8bf85552e33f109e840fa82454962af42add5fcfb7bc76e98b6b41ece4f8931fbd859e6f11b7685a3f684e82b4896e42517e0d0f340947d7f7553740378e79f6f5942364135f2c40f0d0a8cc0e160593130092bd16e30111ba418d00f31668855b0d9f7f4be84f20c61f4edb0d8c35255c5a0010b30400ba27e96bd0eb4848109eff46a6b89cbf3e7ed21b602711fbd936407f037617f0997426b94648ee684369257f10a2469990804cab66934ae28903900bdea986a34a92e3acf1ec08b4482f0ca51549fa8d19f7bfd0b870947a692fe6488f2001fb3be37f27efbb2bacb8397b0110954b1665b57f7dc4444895bd008baa0536ee5f4ac00e72b56eefa90188be86fea7294a4ba6b09769faff69e00188ffbd6c8d4d5c5d716422fbb7114fffc865426ee49522252f00931afcf1be8ffcfe8f65a864b34b5b07ed51545a26aa8693fc88a9c6aa368230e23f159a85df6332274b88ee07ef76e5481a8586597ec1d1d97f2ba9aecefb119dd0a6eae87e579d5c3426159757e753889eb2d17ea334e8742da8cbd9548b7d0b12829bd1292c25f022de31f5f5cb9c2dec96897ddd6bc4b90e39d33b43aac5b8e366553548e1b4ef1fb020970a6840771530f3a6ca5ce304ad2c272fa86cc3d8f5df2ad70c8fecd6c7e4c2199010f1f70ec204f889cafda721f05a17196c7135a2479002759bb841d62a9e77ad390825dadf97b204ae725bb556334942629279f9fbb4afd170208754bc5babc1096716c95aba3429f6a2364357066b95d58a9311eed15bfff5ad77f60d39a821c2a85ff1932a1428edef0117bfd3aa824a8ba697da58cd35ee6884818b661ea91819118c7f77dc84da57540c1fdb5857ac3a34a2f42c8e5a5e72a76939854e90c18655f170a705681bf46d9e423f1b4032676838f5a1a141059253235983b4a779dff2522e787b4c86ee9f131f09de0a48d13af15364f7bb36ba3b4204fab080a038a8249d928c50c20221a4a59e03b5e9187e141111740c29d6981c06bd07020d0c779eaad808c6807bccf2d69049a056b723124cc624e9ad95ebc1a8510d36faedcb0c591bb50a4ddd407a4bd92dabc10124437cc7453b5fe2e4f4b4658c71c122b3c4242d9044b25488a77a711b6922b533e05e3814a76d7322bbe39e909e82a0060627880ee97fcc2001460bd82a905bfed606086c2068f1da79126e5079d0979f256c8e371192cbaa89618b85a1dbb264cda258e2daf2607c0a1675397585b9c04134b0eb1b5b2ec325332a112863e904a8db6080c13755624984885392fc9485b081d5b110607351d43be063175ec05818028c18fa32a788beba3dcbcfa765375952e85f7d03a77c127a7189f7fcba66302591cc09e2615ada7904bccc74838427f0452bc11b1319fe5418885c6a9ecb3efc9db4acb2479a680d77bf53ab6be6d4ad48aa916e7b8e47ddd0d21e552c375697a17199638e6842146532d4a561352b4d239380fc5ba8dc86ae603ae4085520ab461d7a14b5b941b1c568b80036a9d7548a824d0f3ca40f81a28c8a3f87e927202485b047c1e2c65a76a53fdd0cf7155e08d5c07cba4f7b18c1924ce1903b4e80ffd4b75f30ec2bb16099bdd095cd0084dec6a918120e4dea26e45348061ef76b2def870e710f35ac3610abd73ddfc5a6b288f95c62e8c1be6d0ac1a90a6731a77c221f675d381bd1265c3856a6637a45b1052f89e350f0f4a57188b94aca4c2a39b40e2bd8014ac338cc1e00ebdab05e7b968db62f85ed2fbc33b7543b92cf944e7acac6781bae49fd19e7ac0315770715481735c7b0ab2a8cfa2d5a7c110988ee3a68e4b0019fda316462b367e315008a9a6592b883dfd0d1910ba64e610b44ff27c80e390466a07d2de6abbc18771b5a7cc7840183368eea050f819c661c46358f151914e8843549f7cbcb32b61970b509868ca9b69c9126313b52603edfc66d28537a02d3949a544ba63636be49563eb55d059c9de0a88a45aece58c7b5eabd77db2a353f12ee615c4901c6a2bef0ab51bc70b6b35e8053bfead2024a0c7749a8163c89dcc3a538ade2371d674dda4469ce205d875f3d132923f253d02620915413b0320043e8680823c723ac89bd5c51f952697d1fa4592343450070de10685f1227a9482b649a1f4c5973112c19eda3cbb104422f78c9d902314fc7e43218f86f8f4cc594ce888e806f43e3416a676390aecdc801944b43fac853c00dc5f363fc03ae0c3f16a40bb8f249e9958732236b94eebbafc0171216799a7db432611fc1b988a2f63fbcdf6f16ea480a28624f47d1143428d8d9500403fe50025330b10271c619b6cc365d47ccdab97e051efac3c5a7d8962fd62c575240b477b49afe575b2b1f49654340fa442f5bcfac0b94aadd9915cc4d9a485795661707fe2a9287754ba59ef328363b84403e8e08d58bdf24551972a45fb774db83213563ff4990245d125bb62cf6ae42e78b6fcf2e92120ec4b7a7154e633e74758dae37020da7375949615c6bc15184f26aa3cfc4206a5940136421b23df386833c8fe2ed8108e304ab7bf4c91c69b88c9aff341f2dd16949b149c77f71e68290ee90849f4a6808c14eb9aefeea8582c942cef3b5cc7f450e5e03d3db01c5c6fe7a0a9d95a4cd4cda26b0c542f904b5c025aa210c5e14f3c05c3f49344b6168e774a768dcfbdf14865380ef6e00422cd48bc9eff701a2a4f32b8ab671492491924b30b9266abb15d2e5138194f8e8773d1229973467a6d1a3c44bf3ab3b3e72917b3b29cee93f0645f811e4a038040ae5322cad15061bb979d70d95ac69a1e2c3eb6671670dac875f1bc5e490980b44e40052d6358839e08a229efcf0a15d3ee36c0eb51469a3488e90f47c9d1b8c257082b9bde7df37af533e371f89b43a4a5034a16e64149af8ebd52682c54078648a5f2878fdce3310e18d3e205e893ab0e78a5409bd1d619e9bdb550a84075722613954ad4d0cc7eae4d4ea8042ea76edd0d8aa7a3ad1bee8f390c292a9b470c2372c827c08942160314fb18f2abfcfc931de14c9431de1ced81f8a9c15ae1c08520a381ec34a966bd0ce68ba273d130992725486b1ba64c109b70235de50af0e75ba1154d0b916b5c9dbdd5dae19cd56966b4d6aa0c2b24930619742c7a5d3d81b9606157df5968ae8ba2594619270317347764b87924955da98411346674726a8bbfd93deb65994343e260b8b50cbb062a4714422da50a34dd2da2106b8d059853fba26cba7c2a6ee23985cd14ec6683e16b7f37324e5f290c80564ea7d117db318f3551c90ae14e13412e6e3db02f82a5b8aded061bc1a93e7a2e6258b911852f35f69e9c7bee8de409946a11976b7b972a4c08d425c48fa522e1582113130600ab03b9d0039e4aeac71283b9145502ad59c06d6fe00c197fe6dcdd50e4fc803752cd12351a4bc6005adcf8db3d8b38e910c6dfc9eae24138331ceda2d44bfa81e53f905bed90b10fc37a72c097085686af13d146118991408d8d4735aead758340e97542c8183e39b7fb9f7d8def70f98622b61b28b0edc0a00c758d625c97ef3fb8bb6ad471d8b8ed6af045d00d5d6c4a891888412e984b47fbc35c4f95b05f8bd20d57257ebe0c2c81b15d0d81074116181eeb1e4b0297fb3df07978f2cfe77bac02fcad002d470725e4148ce3d99c71ae29e2c6b9c4df99510022142a275bec4451c3c701d9a77ef9dea4fc9fe80b084442279cee246b320aef439bad59fb0c1a56a1925059a9613dead9cebb079182328c687477e4fff81d31f395f67ac2d908cbee0c8865957d92b6fb99d6535ee8a08e62d870921cafe304f3397dd2e57afe19a9f66d1b63bf35845299bc12364e3a7cdf8345bc259a4f669b9b7e8034f3f5a6e70bc899ad803d35731c7f369cb8a1c2dd0680e510b3264b6c2d3d766b9ea2f2f6a3964b0dd1a60411f7f6812e735444eaea8d1c5abd46aa4fe52e339796c4020e85f91657ec5563c98b8315340242986e7748ca4f966409fde6dc4a01f2b2c74c95abc0f16e5796bb80e126162107e147c92c0058a886055b58f916ae90fa1a058944d5f4ec3c4f8baf0efa3bf5f1c093eb828368215918ad83a911222257f1bd5ee935bf643273d2d43272db2e3bf8c7e939a7603a67cee368f5f6e975b5ca71a40a4188daf2a9ca4dc203040b3d435245fe53159954e3723c519014ef15cd0bace0804c8c9c910faed3bc58b059a270e6f52873ebd3b6fbd4b791e28e13eaa19c4b46bbced34d56dc759834c54d647fac526c48b798a7c1e2003cd2480fdd2919caa62e852032c2baa6ef1e2c68c1b10365f37c41f500d3621af8ff61b1975c18ffe647b9d2e30247de90e285efc8331e73ae519de25b63fd40fb062dd7886ca5bbc47ffc6e4fbe5bc24ad04cee9e72fb8a0d5112e261b94cf3aee98f0ad9f0451d53b0b107367ab4b8068137a7958b30a6f8391f25e32edc8440ba6788e7206c623e4796fe04b64bd5dbbd2a59f3412517592b433034a8509e3c42248208fc63a75fddc3c3b3d58f1732d3732d790355889601501a069193f68c25e1c610a843e2116125a5f129178a89df4564dc7adc81c627ea290d5e6bf294058036123733db35d308fa16f7916e2f3d170a6c71377e49313dcc4813c9de988731be92f649f5bb35dd11e8f2e477525c4dbfb5c20d907c3b50cc790addbeb2f0948f9f60a356a22f7fe384045b869fc918cef88a8d57b8a97bb25122112809453265dac8c853f1f901dc98342c20246d4a576d95504c1f81da525cf25c5c6ef670390168579360cc75f92eb17028ab5374abcb65c3f96686f0649f5c0ef1c5d75ee01bdc8568cffdc77d77049ca85ec52cc1ad8c1ccb5aeeb12a7c2ec8a4d078cc6cc9ae1b395691b832bdcfb9f95d42d325de0873319412ae426deb8116013ce42919d95d4482b43489ec69f571a1c756c293c501b15057da69abebc42832b0b18ffd88956c83cb65bf8f60c630d789ff761312877ae9a1555c7f05741cef580fa1a17c24b73d702740b9230227d156cd813815c73a777cf790f5381054d45d58e68ecdeb3d9a12c74299602ac8e58c25c764c6989f74a838a84243d4da9a719977079bbb10d5c5b93b6448c1fe0b85f5e36476a060142c340f6b15115b469189e0084ac075436ca663b35b419723f63719cd4a87a119e0725faf78e61c1c518170a82d6ec4ec72db2aea146116a183fde20eab21f200f6188997e77e5c24b221fe0000be70f44790f70e94030268fcec5d91ecef4d1aa98914f7394df33d5336fa1f4ee7f68b2038e1a0b21980bd52a24f99a379ccc7ee8e42f2245b98789444405f0e8b9f1086966ce0e69b1565ff8a0ec990ad71e6417b02e8dc2f71eca999dfd830d9488dc08d8a39906337442e3ad01b6ff27f005c268d1b99e129420158ef27d6039e9897ca65cc9095e019f45e244e0ee3ce6e3b5a872be8be0a8c8599b5505486be967280acdaa66a85a904a06d71eab8dc5db9ef22f589004f871278b48bc6ca869e170d3c64c9c9246645c150dd2a2ee582a4b68b4c6f58c5cb0a13fedb49dcc7ea98bcda6fc993ad0f68458a561caa4f3e28b504123bf79d491c8ee240ee3707e4407d5403169a89419a8ac213848efba02b97be6ad501c73e2e1f505802935265bb5fec0511aaa4d0a09b5dc39ecf4ea3dcd5b452403771f66497bc6ebe41b42c2302e8b92a5fc14aa202f663f81b0ccd15493ca45877816d40f6bb709a988df0a1a1ef02b868920908946d1466aaa2454c4dbd064be9ca5a0da9a685232b5e67c7495c0316f696280609a3f0ef85ca1be3cef4bc837e7b0cb99376798f275eb2788f9f0378d5bf878c089400de60aba9b91801ff842ece22d2d5f02cecd883b68a08543aec4e7be1747817488a3d54b5842f9839239abc6593914f80f8a345be66acc65f34a01d40ad20148396eeea4fa1080745db7c52c43f4d2447cdaf8ad87849953de7f8e0b39d3cb7529ae22d81b0cb54254358a01d30f402d8b81e90bdfa27d1dfecfd475145c6071d13fa6110e47d5e0311e8a7a58cc228c01a2c6f47099e56b609bcc6eac542d95dd66d95fddf24c75e24a053b92ee4df897e1e528cabf10f3a273327b12eeb6d5d223430765f842861d4fc28839075961c632a913a27586cc1be7e36cc64677138caf9fcf185b43c600ca180633584e1c86a3e4d0b9873e2c672c098d4be68f5360271980956d334a4eb295a41ce3b94cef07ce9da4209e2caddc6270bdfcdd78018ab692be5d3d017415e66fc3e5ae0c046c25f1b3346052a484aae89f4e5b2be934f64061dea3364ae806840934cc342cf51da854d9c627c363b5b97be018c887cbe194a6a5236952a79c56e74feec6ccea157acae694cd3fcf288696a0b19e6867c07e61bf06dedba39bc867dacc15dd04ecb404548ed166aa347be6d0252cf2dbfb66ee0241f37fb5287e7f366b380d1c28b89c09755b682a89d80a5264d7878e7686febf3accfda31c75e05c97ef46b4317aee4e57181e77b799c966072091fdf5d476aeb1f2cf02a013a50a6eed347396843bb53fa27e06b418a9e3771e827679edb12026d6506793cbf5df5d80ff2bd9e7ce5ec0d3de1e0a7c8be1ccf9bf98f50a91b93ca32c99fa8b847893e48b04417d0d647b03077b06e93764fdedc397f1d021df4f9e8ac93f63075c1d388a5958798627034e025b441e35443903d133f2a8b28c6ebaf14454a6157d2caad4b9bda874326a6e74e8990f7a1c72ba937c812f40ce51b0bd45dd7050fc3fff5e4b91783c7f9c0a7bef7e397b644b00aca9145b6468e4051ec9c3c547dfa1bcb4422f0a5d4c465de61504e8f616b04742052cf2f56d7b01e9917ad3e34c32d80ebe7f1e50e7b13d7d2ce98edcf24f9a7be1cf083238fb00f4a4c37b3e5f17ad18464b7e6a843044f3ffb6128e7c0752c08204c51c1ef8f9d5d2ee10b33b0703f25656fbafd1b5200f14a51bb68003028e4961ec2a8ec336baf68f5eceae67aaeaa2348aab71002700394fb851348ea1bfe91b6dfa2131f28fae5e9705ef72fcba37773f21811e6ccd8be4f9f8e270dd21f7bb2bdda55bceae2bdd9a43c8e71afc17ddc93757ba35208941c941822eee179609e8756f8623e572cfe85eff33ccde329748e9923220b5ecb788ded083911666d2e98b1f388cbbf3923ea97a5c024a7114896cfe5566897aff674e8468871e2e2afd08befc7b4a35b3e2b6c9a76068219aa99fad9107cee479aaec76414b3f913d3abeaaed70822e3adb65a8ab989bd0223c99126ab62e0f3ed79d79424fe94adfefce35996123547648860a89382d197b5e71518703aa4054d47612d5b29a26fc4348c37cc46d692015d223749c77e8214d7feb2225924ee9ecd08dfb6f6958d22b7b0978190ad10db05a5729e40fcce2db750b8d9e1ee7e4e8087b4be4bd9f3bb27ff86fdc3b761e330cfff8f294a871c37cd12d54414cefe5064066a0763e1550a482abdb38555b37ffba85d27f0040da4271631523e739adbc5be88c571e5f612d030ccde4fcdace948d3cb5a8e64876e0fd0b459eb3f982c1277dc1fc3d0d4d959675bd8be0516b9fa10f7c803d527bb1843086001d8827f81970230c907ef756dbd5c399241560bbd9b4b3e03673eb5fa4d961b4f2447c8b02e9a433ef7c825b5df3b25b66185b2bc77e6301fefc541fd74d05585deecf9fdc8315a2a544827ccf4b33a5adae099d44a8f41f86b42c766a88e157ca6d98c6c06971d359e654ea3052673bc60c8a2eddd7c2ca3822494a83347a0a2134fc31515551d74cea3e9d119d5a8244f44062e8a0ebd84841ad356374c60ea8953364776f27b2056d6ff1c18fd183f4fde04f713d48235e82c317e12320b654ca8c475fc2866f6800ee30fa657bfbf63092d689ffcdf3572316fd306a086e21814b48b879c0b9f8cbbf74ce0a705a07d62ddbb5da87c50495141de87bdb739a5f5db341ed026bb9a81c4cff2638224aa9d48b462c4cdb5798fef00c8f235a618ad4a36c665daca437f67ab5be47460824fcd0e23528ddb77f74df099691a1cb5d3e2e090efa4675c07543bf1c421ff063334308812d041d545e83b1f88a93a0163382f1aa27760bf0f06ac277d44b37b624e95717cb3e4074b477ea037cb853b6ec960dfb355bd449a05665c5724429795d70bed49e64cbd75a357d51da67e10ece86118a3ecb670fd4e646e6098da99e4a7847f246b1540c48379ac25b448737b986fc2b180f2e133d3be8c790263b84886875b00fa0492c711573750a3e67398537ab7dba9b770df07652f7cbaf3f56308cfa6b0317bc7551d85ff286fd2b7096dcdc0e03e10de17f5d1d85216c568b1710e34a29db4109b7210482ddec0b760960c467715d171e0fa9791e4ab8756885e2c309d967540d47807e089404df7402dd23afc1b4e6733bed9c7a73dc68f6bd9e9d13a589466d968a8af7d4a33c992486ff11d87c347e0346678a7f1a567d85e928d29a292068ce253e374802759c86546629ac55947b4f1e992c9afcaa551ca39d21284286de63b67ad8d7c5413fe1d226afa20a84126b7165a30f8fe88ba02842986fd0f2cca11d1453e0991e10323a0341b5caba6d958543dce09b91d3c1622b7940be90ad2e6e910ebe57ac7515f47ed5ad3539e3b5c580a9e66c538a7e81dc90d71a3c8ab3fe8f9b4d7ca038237b99522b03d12a6221b43537d38858b28ee14378cb7ae767dc97eaae1c32d4f9ee5fb811704a60e2e78a53e2761bb4910d1807d812463da90a87a273c2f27f70131648c605dd1c029d045cd3d061972d1a8060c389402c511bee1617a89941552b12693c8205bd0a0d3bc0fb3d650fc15730bcc25f563d162fb729483dee5198030ad1f5f66015c96b381414944ee0e678304840d36e75c89efdd9c09c4431011f640cc02cac61c457810312c3275891c88366259b0f9e63d2cca2314f30600d8d676f01a311a9070cfe334099e6ab4b11654931652e79c759d5eb5e0d97a26724884e591f74f865dc0f4984bac4190636144391ab161b283a7e05c6d1b7d37354b17d2b58112c978d416172c00286536602c8e021d4fb2eaf0156f0b489532d0456fa2a60d9ef0c27463733fbb612add0b3f1c7028d4666e26485b32b968534bc4f75513b1082cbcb53c38de5cbf0ed2d677d4d27d3628e5a9155261463a34cc96c26020548c3d1c8f1689a09704e56a93b90c33d2ff5c23076f455c12b0600cebdb3782c4ebd188cc6c25208307a60f9a5f066b402c4cd478590be85fec0c65d4beccff8bfb589bd447c8a01831ebbf3e0fed6c977b5c031edfa17c72512c6f319c0a2314b51c00588617ae043269198bf440b21b687558329eb4b27589b5d93f887aa0cc14d0251fac40ae8e55a68c0c0a61cc7232b0d46a47cf19a4764508f21306946241c5b15fa516140246840e5c6732144c28e59c7288560be925ea0e70e5488630006ed4738571b3104ea6005678dffdfeff1638eaedb0293e578c111e9d6cb07daa61047e2757351e12e83cc8744f697b2cb1bc3180c8d8cf40c7b30720f4e700b3ed404251d26cc43d18ef8eefeca22649dd01b60ae1d5ee2147568ba1a75594d0c00a42e729f0c9a3956c7d9c4541d91eba5e53c7c8e1413f59f350c4511c18321b1235f57f7ccced036f2cb8d8ffecb3688add92348c4492a1e71f8b0734457dc09e016fafc74310038079ad9edda607f0a3b7271e069633ee99960c310b4c855b23baa8ca204b5b27ff626586aa5a5404886407d31dfb3ea33a2f6ac3a36680f7a356b606b38fd01e0990c1b083abc65004bfc74718e86af92ee8a7a7a3711885d4094072e3526c352a32c14d4197f385e4e5f10e3f0d59ec6d176dc548d1b100e92f852c461fe529d4f73426c1f6bec768f3e68a64beb99412daf207df3e8b01c5bfe911b3af07079da5ca82b0298a27b9b28b07940b5e3dcbc25039d86428ac0c0f03987bc497ee5927793007de0b470ac0a37aa315f346d4dd1cfc4933804bd84d14df20f5cc71cda368a3847a151306b6917a81ac4e3f805e1d8e6c2d4406944e3e1cb40ca60bdb6792269db556821ce868ea99225b47ea8dc31ca3a561deecddf847ab52dce2cdc443e954b462ed7c653f13dc7802d9a54934570bf0aa3e2cb3f1e5c217b5a6c4a5c12d426150e62869e3664c4e4a0c443d86f5576bf61ce3a4b54fa3b48d51a6481214284a22b8485a7f14a9a195471061d446685991771af2a7fc250641ffb649cf056c0c2f6bec2f88847ad7a5db01264f7f5a54542fcaff9f4af66e6af9098754185baadf59dca0e892296c4a321246a94c70a4f3b029350a027dc44530ccbe7d043f8401a2f3f28fe0297a097db53ee8906a76c569113f81d151dac61fb678d2779592b8ea5aa04c85a9a40b747ca104d2220c185290a245efb1fd31eb9e3730896233434d4e6b1e82702086bc27ba764060c7d33c55060e6b666c722ad71bcd31de49d6836cf8bbca348b37cd2e10d226c79d5b46b3ab7fab3b7a4555efc1a1384aa099eda5d2e18ad7b33d9dd0d953ee8aa066f6f89e5df337e5ce8a21fb2aa67e5dbcc6e01c28b6f901ebadbc55583b34e9742ea1d0cb7c87510f210e1bd3825a24ca22b47fbf7dc706388df5b7868fcc942ec48f8cf55ecd6893422924c1903df21811bdaaebb77728d59aea9d7aaa48c89734c3dc3e31aa4315672c65a4b34c0f50c8d5f96420731b445479736992162a6f062bfceb9db6ab758062423c6f260c066dfd626cb111f0c968a2cfb0a90958dd0010ad13a5dcc8b02144bd18897ff794dc735601ddb11a2372c5ce1b5ac7f67353e0f9fd90ff7c2dfe539a68b9fa6dd6dcfd18a76ed5783996cf27686a9d43f61282b21ee0a1ede9cd85f00ae2e62bebeb4387ad0874caada7b99c2b823863499e16e920b05ea9c439b46933a551ba82252a6aec184162dc69a08ddc9d52d8d5eca0025bab8dd8975fa4a9c9d4a14df7419347c5bc6fdc470a055c618a344f6f2e8dbbc7283ff6a89915b5033992d95aea92c64881a30a5649567abeb6d4b13452d2b2d99f3ec768c4d713e8f072ee4d256cc335f5aba781f3209c400e86a0aa991c71e6c4c834989f302259ec93425022d5333db48752b7f645ad83d82d1206c69294d199ffbed406b695fd09534e03f4ae332db21ec4c32917affbb992af1a726a2254ada9b0b28d3668f77213d4c5f94860948dd61c37929f6948fd8c50e1e03445015198d85947b422a6cd18ec5d28aa2776c1997f09263321550c1247955314e2aa2c2f4c8539df1a302aa4c259f6ac64f052a994ebe6a8c4b25543129b9fd7d828049876c1ca02083b790599c2ac984fcabb98eaafe3a1b24429741dbcbbd805b5eab0ba0f3154b809ebddc0ab8e5b5aa00fa5eb104e8d1cbbd805b5e0b18d7620c3c727bc08daf1506e8462d19853af153259b1fdccea4831026e4bc7b492d2ee276492e6c4bd6285108ecd1dc248009c6a536c4e666c6ef9f1bc1c1b96105736cd348d252b759d77165437c617f83731a8b91d93c8d11d2e972b75ca78cbb8e0f5ae38ab8f00bede927dc9d9dd5ec41cf365d46f19039ed82772c306ebf0b13286d94ffd1741c76c8fffa25d6a9b13ef3007a63b88ffe6db33ea41f11747290b06ef1f26c0ca6e671f4eb13d0b6069a80da6a20f81ce55c29dd5748df388a109d7123c8405cd83a32088f8a03a7466a85c23eb8a02aeb00aaaf0028d424aa95134ee6dbb88ccb41280b94244d01bad1534a0c155a3eb5d5387d40c4d1884ab7058a88703314233c8636f905530bc512c205293fe10ac229c974654b37e5f737a972c0e1669993792e98c21771ca68c10f15f6f5a907216c42a1d1c3e0065719ba1cb777761c4496c8078853835e4006663d9e9f3a41675e918a7d300af214040913785ffdf63826eda62fc5c34f54ee2dd49295b35f30c55c32ef2378a63b839524bcf1197ddbc3129f9d5baf9505d0f78a2540ef5e75e34ea953b80d2513a07d8d934cc41c5545c21c94fa1d7ef1048fdbc5ce67cc3316894a4c30a2132a0913af25aa930986b41b174f868496fde3ad6c053a411fb0dfbe3a37b7efe0da41a8d8c223edce1496e7466a82af120baf4d533e30f2f52dce2d405c01ecc3250b1fb5a62d2a77c92713bbbc86043baab4e5b7d96c231f4e80284b83d9623778df946e3618cee7576f6b556e641d66e385eaae70a5b19277ec845226db0dadb560bafae16505c95ba93771642740553c0d0dd4bb3fbfad73f1b7bab74534ff86e5d0e05ea18945a58b3f5bf6d44f69f4db7c8889ada95e66e2c56ff51e03eca0dd793738bc89198eb5f9354eab190b53f489700e65e6b045a70d72249207fc92b1324db1797a6b242dffcd30f4df7b2ddb14b810a42c1875655d6625cce97d54b17ce43ebe825e3a92e43c6939418b01ddc5172c39ac0a02a69d3d72b643d141d566b95c470693780be0230d2dde8f8c1cfd4a28b739f2e88f032f719b178c80765ee23bd73a011ab0559e17397388b7213a9335e9f667a671297ff19a86b636035df7e022faf934d5b55a96e98a5b0337f1212a692472cde1ce1f8a444a0652e43c1d1f6795889c7058f6bad0719365cba847b9c0eee1679c930643f44603ab179966d22b7d71ee38d4f31df642e2904d0484339ddd704bf363d08d39f0f2ab5086a232986d8e0acec8fe2a58eafcee861c6a3f1d8f033979a75d3be3f93657a3caee627718c80050109e3430aeb6aece869b78418241ea42dc7d979c9d29505ed2c0b8484f630327b9fbb27dfb0560ba2456745f30668fc5df90018020ac523528f67e9cb0936673e54b50bbb5232909024c71d687253296e5d9ccbb20b7548a4b08a8041ed1e8b1ed15c1402960215eb062b2bdbce0dbc780be85c7340560adbde448d14859983dccdc4a3fa57400550d917ce26f3273a1983d05e972be7385514193fd7d681aea39bd9fcfd97f13762fe847c41e2f1b0a458545981812fd1a08a8471bc2076325ab15adc5607151a10a49a79dfbc589aead50ab5c8b36bb1004a8f35a72d343c1675a036ddff8cf37b34f51d800bb38ff55dcd8e2fc4533d85b05a0a51f25aa3572bd84da2a4f075eda043a2761d96485101577470129d66e4e3c1df916daa81a6d82ff9502445da7ef39a5c9f0ad61bd13a914855b913a6352cb8ae21f405e98857f207518d7a6c2bd4953f1908a9f47ba96102dc7996c3445753dd1ae90a4218ec36755632949771534bf3b5ca14ae64b30d5ae6f0a257f0bd595e734b8cfcbe8965e3d06c46f809472d14aa38ac2a79a2d75f30df1e6e808986f1b8df7834df969631e8e5925a363bb6f8fb61d19a7878748b4c724a018a73747b7cd09d3600d9551c1ec4e3b2602bf6932394114cd5cdaf7034fe5473c017e7603d5ff443968a00e001a4dfb706cf24093e299030eb4621a164946074ebaea15995da9d4336e92b42a2db1d82d12224a027eaa0a8c53efd753e2c78aea5bdad3bef03d555f1bd62fa25f4104510c94cf4ea5e197c6f2ba92846e0b8948df35f61ae86562c282bb76d195438e721fd44dc3f36ad7fa45089c23a71215b46b5f78019cfd3412b53546585abcd027e859365811979fc4be7bd911e321cc3d13ee4244f91bc154b05395d0caf2b41813fb5eacde9ff53bb2f84e96df3956982bff4b389f0f2b70162f7ef7eeeb63fd1eacdf87e577b0fe0e96c97b775a02738c8d6bb3a2f7959a7996af19260ed1ca3916e0338cfc8a393f4a9a251fd6cf5f2fc1f2a1bf8c0fa9d3daf9d1604edfa6c3d7527bb07fe2308e817103fa7ff2b439e2299d54fbf497b74565add06c6d7d0216b9c403257497b6820f7b317f2893c726521281309c151ff3b0645e36aa42091462212c18961280f59e58ab7749652dabd773e44b24dd6a6055c55714d8af53078e859c94ad6778f5aae222d8d01b97a2b777a9ff8ae165aac8066fb25f971a7029d6b276d6f6e8b1446559b7eed82da1ffc448a8bdf19281d6d63de2a7f888839402baa7961ebaa64953ab283dea5f6dd3b0f89029ec5a77e6ea9f55b1937075d0045b1729d5460606cd709a683e1fc1b80a64ecb07920202e8dee9370d1140e55cc1530d4392f0b2bb180e43a9d34b0e69c3aa08f1ccf05c7f192d849b84631ab1597bcee8120f8eaea248513d333023771096f2749e99d7f5ed1dbf7bc45a89a85c422b029578cc5e2e029c246aa2cb00fc3a7910f067c4b2168aad6be95fb725a0db2dd47127cef30e1e1c52bdd922078f516cfc24b12bc14bc062316717285588047d382f04479c5e23452aaa119240928b49bac19e202907170ee9c7cb1905e33a84cc27945dfb8090fda8b3876d52127ec396f783ec6f1472f7bf82efb7e5467b30ecb516d7ce1946eda4559888572cf2fcc4b6f229f8c61076ac60a455d13023b834b34935d56e38350ca9850c57fd578b5a4ced6e229a72a705dbb4cce5a650dcdb207a5bd18a0e6624e0b20de6f7a597d49dd40c7a421a9f151bd52b0f5fd6b52057f60df4c9ca6962a0a1b227b58909cc61083dd4d955778d1a7586a8192d3f192446789b820d2843cad5ba1c959e54a57fd58728c4fc0cc208c9a4dc8fca2f196bacf5eac0ddc1a273eead25b4716f351790dca9f837705ce57ead0c3a0920c31c8bbcf9592fd79d390ccfb166b6b10a3d6672b01fbcdf23189fa52e8a0c3275196c03e8d3e63eac28eb116824add7af3add894ca209c2245352a6ccfc4deb12fe398e95f88d17d7045689a4051cd131c8cc89df1e4081a08eec72f4879ad87c14fe55b546e992de2ff19b1183e14da5381304c5b0987aba0ddd605179dd2a607cae25bd90ab6120db43fb4e8d8e46162156d7bc6969ca4c90d85e09fd27baafd9554c46c421f1ae920f9cfc9f2a641487df717c219091f5ed1184a313ca461ca72c8794b8e83b1269b8488e7ce8ca28629fa95f03ed29ddfa6ddcf35f42a9035cca1ab676cf5f7720e41dda1101d58c3292a8f7cb33cf8a08b530d4d03ef14b2888654f48b9f4c3b272a152364077670f77078b89959d5abbfead3504be9bc9c54be28148105f834de6a9f69187862a4f2554d63543e44d3e7a723917790ea7e55b1ae8fc98b0acd272166a626f4fcad751742050029b3c4040c896a99c686e981b3be97f9faf08423ad1ebc74cc914d54d96551ff0dd35979825c4271a5f04919ab9bc7a448ace189d2db3f6ec6f70bb3bb1e8f97b4688d262daa2a21e6e8177cc1208716390c35ea28aba7427062ddc11899e92d62912c25ac43d89b3acedfe15742df27f6008d05cf26913a0e79fad755568171397c03059ce32cdcc8e7f98d5922e356132865b8cc55d686cd65631f62515bc277e224c3d2cfa392db83b498c1fa7b5ccce0af499db649f81f0ed34cd40c63e82d7155c3fee5c3756e9337e2a504c9bc730b6d04ad67e3a3a275209c241212b311475a832387143f370a64742e14156ee27c28ffcd322bd46c0d54c329badbce586109c2e827340dd9761a953aab5b40afdadf1577b0e1b2b50cc722df367ee08fc0f7696f8b34eb6c925b38e3d9d6bee52d1a14307d6761c0790c5ab4b8e0b67e9c920bbd157f358518bf386b4dfcf812aefc6c5085d43526d33b221c28a2eff85b1cf72d8843ffc3b2c460dcaafefb54f2bcd95206d9982ce99c4d4011b66c894cdeeeed591f10db689288093e51fae675e69e7873ada5e5396d1bd7e156fbaa622a4c604ff5c65745aa98609f6a8d57e55499c01e558d7b2a53cde4eb51d578aa4c05d3d853adb1c5b16cb52fcaecae07d6512c702549ab284c118c77451d043d795f144f0d3679df176d20f8fc9aee51f447cf25a36698158eefaa483ecbb8625cc9b4cc164f3d9a1eae6e41ec41c08585378cd364e64c1f419cb215714a8f464d64744d2a34e7fde0ea98dfe06e9f87effd5cdd3a9ec9f0e7c6fc774194e897b04b3f72d4a32c79a9db0580183c62add58f7d9f896edceeee2e3f5cb7d6affaecdb4ef0e3b502f59302180b71a35bfcdc682b7e1469addd5faaf12d7d7a1fe81a80206513fc3dad45f5b106bad4a7d8bd37c41b0b50a90c2ae8fc04b32990a4c5d32b1444a5256ac4590ad27c060b3789f14d0fd0963e05c302620d555c40514e9584cebb3f78b63c9e814dcae858fe1ac18f88a2d45168cf97b565e62794da6328e1efde6c89ed4bfb08ef39b40d03d8d4f371413542ecdd1f6f3c9ac8f988cf1bff8cf5135d2ebf89124beae5c691ec426bbd9edf9f0798df7d9359a02d068f90a1bd14ca16fc4346f51e2ca88b127e915f77f2dd5f2e5bcd4b70ae2db583ef7e2dd72261a86dd88ebdfb7864bb3582bf9bf6427dcfe158f6f3b561b69e9896a4549a353dff6c2b06c0df6a445d8ae7d8faf4af653c2df7f65c5f9a17d5181ed0b6d55b6a85b98cba18dd7a8464df4909c65cd2b1128c99855d1e10674d4709134fc521e08f2ea0c8c9073eeb9e6f1f54fbae948075fa4d6405082ea16d2ec103560bae773f640b53160218e2cbfebf02dc5b045fc4d24c291a5aa9c39b63ad86e0d4854108419f15cfc8aa00aa03e5a30915c205a21d182f0152b95670b5e00a5c049fd6b9eca769b0acdc4b7045583b72be3f8c25d60cf89e39f98777ef9ef9c6d802ca0498b96160460866140603653f17bff7e3ff2123704904ea0602d549137126be59bf6b608198ecbc493f1f31f32b13c4eb7ea5328e0c9019a01c6931ed99a3f0e8cf948885ff1c14d8bc0269ce74e8f13ac9a1dec06f0ce3a8d92f4b451c6ecc8e8987280f234418af63e657e1a9a52f6d39f1836e31739682579483285775ecbc0626ac3e49cd6cbede756ec920e0a9386fafceb5744d781dfbdaccae9cb87ef3bf8db00fab9dee72b2c8409ee91142d9465fb33e78d3cd857be7522941d7def8d1cf198edfa5b11620a01011615380454d99004031973054cf62741e26a3bf4d57227b35d6ed64f178118f0cc9707aa432b9d0375a5383b94627cc6b07effd227a9fe25ad97bd5dacf61c08ec0247c2007b237c472a2046016454b670b72fbd8eb0cd9e98c4b34c47987637386b706e86b57ce14b59d83885deca5c385517ed7572f216359633b8b63e595d9b7182efb8981ef10b092986c8e1da7cf9cfee7f154321b2e49501d2521e50ffce2eb211a62615a28e45101e5200542c8229de7c58b48564f512eb4151e97e986a29cf02a45dd65ea879ca9f19e3ca341321842db39c26cf0f570d42c060298070715e7a38aecfcf0cc9cafd4a1fa44ff3472230c24a6137a5ebe0ab63dc1ea2043604a3dd870d47b52c5891020091938257bc823ae25e9981d1e87e94081eae4e8478ef126f60500bab49738bd845ff315f39b5aa7f78f64882f2686838556a3ac7572d3fde760cf8c63cce725693f4c3144ee6028639b00e29c1e5710c5017f208628b536e07b22e3e185f6386eb2c38dee6b155dbd6327f1274a4f5100ac448f5fa1969255b40270ae546c92ce2e7070c6b7f76d804f4b9fed61b4b15416641694b4ec714d300914a65280c94e7c1454db072de5cf7ab534b0447e3c35d1368005ca1574a499ff4c6f2a339fb8cba645ef66f71cff89534aea3f5f9516974618f74bba81f79469571bc00924f3140f1e49d1286ec6745c330d8d5ec0411a5f896ce41941d37939a81a720c58b6b5b856474cc5e896d573b90c98e53b471b46b17dc8ceded1616738cc886b721a21b3e97baedb9a01de5bbfb65903675c93221ab0ddb27ba2ed6847738c549976f69274b37bfed4f53d8df921b72b0015a5e2d3e2401cbcb0257e87715c26def70e3dfc8f482d115d074384651dc50d8f5c344e1c83e6c901f7118a4276e829e2e9b25d9855527bd117192616318d55afc0c3fb25a628ad0150c96d99a383045c999cc9827623f1c674abd0f806b0c7979c53a4df2c93b5e4137380999ca8098d354abf9c11f456d782de4f138a193fe274234b5291e5600434813de91b143d5af1050ece1650c3dd924847a2f281b49772a1ffecc4a348089c1d66b47653fb08534d7c0aa01a9a8b922c69194a2a72ef0492cac0ffcc8aca9c4e1b428f85cc315a27ef99b39aa0ae92185ea898c319d748e462ac71cd9132d47bb0e7e7271b0949a6b731cc5834228ec0e6d77c00c2741e0aa2958e096a732fcb6075a5c4d6724a77cff5bb1a95ea887ff4ddd050041d56ea418969038edc8e924a93b12a9f685cef66057fa88fd68d98b543bbbbe218b36d794e3f035131891df0501bb641fd59dc757fd5b6e225b692937e90a28a2699420e7db7268e075b744c7f65fe636dbf00dc173d448bda8d2f70f007329141615c094ac3dfb2e0b6fb9c82563627644bc667bdf3e5ff707afba5bc2c984a9c123e28a8308b39cbbbd31a0189d2fa5afb1ebcc4cd8de8f1270c03909db2f8eb004009c7e219fbbf6173584c175d48f49e47aabde34c764b99aea7191023c3dda97f219488ea8c634b47c85d0a799b7609275ffa3bb860f683579319e9cd9e40aad03a84ce125c385858ee86acd413eca3b0bc466ce3c81afd2e0d2c423d4a7e25984a3e285ceef8a9c3f374ba51f5b16a18d86c0627cd449993c07b5c4271e8f8629077485dfc0b9b29476ad3020daf621d2e58e99ff321bf3160dce1141be326f090e38fe377c0456166677ad58a63f276ea1ae2f61c51c41031b06cfb4f941616a1aee9c8622cf8b2d5507619a5e297411d1435069e4e468815561038ec6a3a3f9f2ee772a735f9240351126683f9dc21a227293e5a3b5c1c07a0f3693c2abaf81348dc52726c915d7ce946d2ee96c6072f178e6f0af70d473f285bdedd40d47e4b012d36fcb440847bdfbe9b8890bd5355177515c614af2aa488c2892d491c918022b418a0894e1021600108201575668d326a2c88110615229e01e183b515995003dbf20316233422d842892d43478276e4b0a989c138f811010848799289530a4c4a4943447e763298ddc0691da0071c6ec8604c110a3cb180256478e2c448108f1cad0e8021c349d1094134b017036c88a201460c20081d5c40c0010ee00313a7221382dc786ab062f0996995a1617c645a2bf84ce01ae371f185e003018d989b305f073e2d3e293e06b09ef8a85a535e08de07b10e5c1ce0f4f8767c3abc1c330d5c197c334fd6baf1d9b86a3e9a58ec83c15c5fcb6379decb6bdc87cc4713ee65adee6bb329e4493cda7b7a343eae7c3c694b653e80c87cf490f52043d6838cd3a80dd31daa43e993565f4bb5a5db521376b9e68a1b69b574ef6a3dace81101590f07c87a288046a3b76b1fa7a33bf40422aa7302d1141004a3e06eaf233aee5292f5f0719dc19b7fef6a0ac95b7b8bf5b927dbf1821d5b5cbbf593946e7ca97e4cd21d9d1ff389f58e28761ce1e4fd5da9de6185bc2fdb01b503092da90dd31f6da969c6b65cb7a67fbb35d3803445feccfb75596dee0e24086c8cbb7fe0ee1a23039a4f0b8efcd0229af3399270e488d0112347828e143942e4c8902340477e8ef81c3922242464442848a8881011a1214240423f423e42478c0819316224c8481123448c0c310264e4c7888f9123414241468282828a0411091a120414f413e41374a48850112345828a142942a4c8902240457e8af8143942448888112241448a10214264081120223f447c881c192234c4c890a02145861019326408d0909f213e438e00090119010a022a02440468081010d00f900fd0911fa11f233f413f457e88fc0cf901faf9f9f1f939e223e463c427c8a7880f119f213e403e3f3e3e3e351febee3f5ca62306cf9dd7ca270c1d44dccb6a2bc56dabc3697b6d961c60b8ef9e8aea6de9676cfb1aad94b52487143a833a3f59dab32664e76c4a2ecb51baffc5549fd8567d36e9e3be347378a4fbc4b86d757497f77d6ad61cd5fda5955e7bfb1ac59b923fc5851a9e1a1d1d18280c353c352e50ca435da09452ea5e82bb931024870e1d5a030c773a24d3e00a0d1c20d320014e876ae8d0b67d49690d6de36e3653ba6d5fd21e37ee9a3b01c80927b8fb8e4e100da4641a1071a7dad27dd628d5f6719b0e69f29eb8466d98ee1353ab274710c1bd6688ee4ac9a71aedada69928431960e165adee339701039c0e915fa33bb27e2e6b53c63927e970ced8c8f6e458ab47848c0415213204e8c74796810bee0e823b67cb20892c0324afa59d4f06bf5f5ad59c8fed5aa7ea54420fe8034ee144f4ced5a440109f20355a44a7f844b19d3529dc1d0497cd48d71924710e8b14dc3f313e147ce517f40d31810057b8cb0c13b86719c095e33042e29e0d5adc83c8dc5964dc9df44a4002af8bbfd889462fb6db64b2a3b3db66ee456d41db5903d28413483c1c9cbf0addd5e893b6ca92146fbacddcef5dbd9a27767e82281111fdd1a1449496b0002696500206190ed9a96dbe2d69e170c100a8b85178a1130112cb8c03f418011050a0e08712442c2ec20cd961002276e812126179e9e14684901690cef8c0c352001540be40c26a82043d21b074b84252d2429524b4a8810396d9840e1541cd84327672b09aac405600358a20e2c600372c130a203b22052cf8e167c76bb128980fc49021f1c40acf1aac970e4cf42006049010e1a38ccf0513a85ab22489239064607c60d428c00b2238220924a22f3e086c114107a2a4a0c00103e8e22bc009b43ca00b213ef0190af3cd90650316c87001489417587c362c681605f880142b0554f12db9b206193bc6c8094f20c5f713812ea8889262c1145940f16d704606089013900501529af0d65040012c406404477610e108cf04255042000586d022a28008cf0a01900085941808a1c50101f09af852240a035f0630e5841d3c206c88620310510a80010b58f17450487d51c48e043c742f7852c6a0b172010a18a86ad89e9111b9040c4100317429945e102ebc30481f260f2d203d1c209a2c0f123f5600458a8f51c5940ed230a2d20101a47c0b005811ebc107133f02770a7029c10bedf0c5892d486ec40b46237ec254a14610f72b08601264841d04c84922e239311e103a8209165ce1783cca871880b270a105524c77212f4264e18206603a1ce0eec10c281cb13213001a2bee2c27ac5c8081266a3767c89009a300d9992c8840b2c619077420023ba09ca0c7f3947166881da4c082063f5dc1028c33314891821809c4cc870bbe3833b271c303c600805f71a38b334c4b8410c2105603f1813067c02fa4c8aa20a104135e589cc931040a27c80018176468a28a36d2e00017119afccf0f04a468c38b1c6265cc5081430715146d5421012433081fb614408b26da50c28c12a21657360c0138a20d1f90f0820208e892822e3e10d1c6f6220d5d08e64e0c1408401b2c0cc0a9861d7e886284263bb4818206a438432352019f282b6d8870434d74952fa4a0c30b6dd43ce0014e6c59e2cc5597cd8618649cc04c1025b8000c4628d9109300266c5070442ece20d98862044d9421c050538015296c6809820a01594c40040d0c408a8d1a304002a4203e3ec0812896b04165e54b182f3c9001144c4062e3a9014237354828d2801e88d8282206919a2c3b4868220544d8f8a1c5062d382004154294c1c3868760d7b001116818b2228435548065002dc0424b599870b0c6062c200b4050931a4e8ce4588301341065b09b02812c9edcac31800560c1f40312aba8dc99d61a2eb480881c1d0861e8b08135d6a806a0d2840f4e20a1810794b186d2075490a2f3d384000000630d1e1ec07ce0041619d620fa628dd9144e7e1023a402c14d176a9c7146c78035a690a20b2661d4e88209b38d1d5610200357b8bbb781851a1550810f2d5827f848f202c7bb91e3ee29f11e004fdcbdaa10dc3d2a37365e8d950e49d6dd8ecee7b016b50577746aa716c9a71a1f3782fbd62077cf8b4105aa444931256142129330458950c2267a4211ddd1b95f82b6b3a62bcd2ad7e7b57eca605bdc8716d17d6b0e2475062fbed54c0ad9dd7ed7bcb590f149a05dda5c5168885d88914519f7055d5c7561051a4da4d019e3d3106307164db497f18cd40d22a30fb0d0818ea0109cc8808dcb080da072c508600b1c5aa4704daa123c6520031d426ed8420408c8537ce0862859c0173cff9c58f0c1082c2486c8d0430a0e70e1a28a5617b10f6861061820ec2f84e0d021c406cb8b216840011479ce83098b0528a45106174908f1822bf402928aa90f3c6f85d1930ba3d4d08418338060c318b802eeba2201701b1758c0bd9f1e770fac5c390b0789bb1375878171f72f9fd3127707e2b2d7ef8a4b9bb8b3a490dc793fe3d1879e5044eb2e9f7c3aa4ab6f8c74bbb6b4354be93187b8db896fd2c64eb87dbbbf64b7cd5c92bbfb28ebb9c74afe1edfb44adaf6669184807e5e57a39b35c2586acca1bbf7688db992b6ac559769cc6115ee0eca5a562e255c59dc7774f25b9bddf749a63dfe548dc916779fe232978ebbe778c4dcc9cf656c2b6b8e223131217221ee2db8ac6535e61a041e017d7a488b7bb6be7874edee2bb8ac8553b3e5ceb856dd75b833b9b7662d16eb0377d720037799bbe370f71b7ee335ee4ef3d3a37fef3cd3ddc63d8acbbe2cae33f8241e9ff4018b803e3d4245744d88edc7c7a7c84fadd5808048233fb6a01e6c41fdbbe611dce5adededb3107ccb75048564bcc7c709d1f97513211fceb72d4d4d69bbd23270d947e45ed61d2efb6edc3d87cb3c337e427e7dadbb7b2ef3bac880bb6fe0328f8bbbdf2f2911fd1a25cb13e334dda1daea50ab27afa55f85739f45b3eab4bb03b97bd8dd7bb8ccb3e2ee3a83e3dde9d89f65ada2b49c9368f4567a31a5ede89835ebee3934b4cb533f148d925f96757477eafe91eecec3651ed519dc391bccfde519e7fcf4564afecde7febcefe7be3473966e5bf3a6b76bf7aeb98c6db46a71cf0877f7e13237dd1dc7658e0077d7e132cf81fcd2561bd5bf77354a6d985e6c77a5bb8c739fd319fc80b83b072e731d779fb9cc91dc5d874b5bfe2a4c77db8ed5aca3cee0f855a2ae662163d642465c9655c82ed75cb3a5bbbb58eede72f71b77fff689777549c63927e9c0c18b8d7bb9ba0a9da583072f9e0d9e0d2d2b573c6a432b87872c3c41d802994764137337b2b901f2dddc7c379fdfbc727e28c1e88b0a9693c4eea3af9c24762c8a42d8a2ad9a16adf9be1b2034f4c379a2a12d205660b0a11ecd8d1b7d406c80d88082118bd600b172c53362511b50306a51cf33fa3e572ce78a45bd1b2b38f40a35aaa13120566ca80dd4a8867a36395756608881456b72ae58566ca04637f4c361e106080c31b0284ece158b7e2ab0e8475938522c7ac533aaa13440ae784634d40688151b5030aaa1573c231bdabab9c981c1c64a2cca8d6e72607042ca867a14861afa513772bda867148621a34a62f7d124762dd9d3473d9c1f2ab4e847a59e58348b4d8882f08b18cbc8f75df9ae00b172a595e30415146c70820a0a1f0e15f7f2e485183ecaa23178b4455f70420a466be80b56ae502397d48bba680c2fd8408d5c392fc4409373851a7931bc682ce70a356251584e0c2f8fba7258d4690c2fefda8426a072d11675e5b8f7b06460794a6cfc034285e52a63566898c1bf96fb90f7001b970108954761395458214dabd56ad10f46d382516fb1682c463dd614cb6bb158ad298fbe98bcaa6fb3688cc658b11760b19ccd5af2609445f5a2c9a17ac55a39acd847a95e3954582e20545e083fea9f8b8b8d7b1eb5b159f2c298d7aafae8ab05840a8f90ea453dacc9f98050e111be72366ba945bd1c2a2f8436fea2b49543c565e1472d60f3f2c2168fab35d50a3f1a1a63f1b43c9d100ad34e080b127a3953bb15b6bcec85ad1faf0ff6234659ad50e7d3f13ceadac1c6c5dca045cc0d59c258e8626ec022e686ab156cfc1383c395bbf77d1fadbac9107e4a3c02e85cc12274313774114ec56ee012c670e012d2d0c5e08025b461dd509d2fe845c314c85e2c1bd6abf55118fd5ad45d406230186dd11b9793879fd24761d405c4719876629ea713b276f06ebc1cd88bd250d7eb870bc80f176db95c9ed2473d203098f7c15a3f5a2c17cb45dd45ab6e328431263f5ed4457542578e4e063eeff5c211b26809a18b99614ce872d947bd250f3f0f091b0f612a168bb1aaf88260316a138bc5621487c973c56e5c39add78b7a30188d81f1c2781e8e126f8c8bc9abf13caf2627067bbdbc7079168595096134067b167589b1014ce8a2af5906b3190d81030d70943c2f212c67eac6867ace940d102b4e4cb9e8476da0464e50c97094782f1c384c2efaca41933305fb4224ac1b1e21f8102d49d14a2b2b5888d8e2416193e346c78773c3e58626b6c18d8b662a46bf187dd18f06478927c686319ec714a330ea38321a202e1c252ceaca69c5be16cbf3cf0b4e1a357cb1e20b0d3e13534317313570095d4c0d5ac2d0c5d44080f015ba981a02400418a177117a13a1531716214b0c00a40859744a86d087aa5a3f58493f583940dc71dc8128f1426fb764089d3a2b86d3d4f4ca71ea1e2bc75fd4f34212c8762b7ce134b9a8e7fc50a2c3d3daad90f582e134794d5332fc78b5743ceaa23fbc97c7137af4a32e04d888a1a10930369e4d4eeb53924149cc0c5d4231575f844e39f8826ecc842e66060fc173a8a8938d7f343a1f4d924dce0f2fe7bbb1a11eb5a10102b3f9be1f361ecdf7ed5648437f50f1c2170d4d8c26a7ca0b5b542f23ce12c11a5084308fb63cd60bf6e3f57d30fa03465f300a63bda86034d4806caad5f2a1186d51970fd1d0168d51bd680da5014205070df5804cd5e4d0e478f8c1e82bf6a2b0166d8991227c515713a187ae18a42185982b65c259e862ae74117a218bd2b8e8d4eb454303a32f58eb86ee160d8501a179b96e62af168db16c5855ad10a7c9455f3f94e878ac1775fd70fd70d1dcbcc22e642fea1427e9c5f4852f5a75932164518ffe88519d1dcb51a213bee82b4787e70b7ad1cfcb71b97ebca8ff7851efe57af1788fe38829c0c686e70b9afa280f1161ceecb04648435b3ec572d5d05016cd6ee1d01bcac249b2c954708455ad1046772b6cb1583f582c5ac362b1680b674a8632de7393f34389ce548bfe50a213c6a63ecaa2353494a6a99553e5fd88e5e8c810d2d8140df5bc900432a71e75fac3a32ffac3a33a1eebc5fac162f1b83ad08614a1dbf0fc68d1a956e83f5a394a74429db0153a8bfef0688bb280fcf0280f0c4605a31e8de5b0a8a63c8f7a0e152f74e55079947e393cac1c6870b0945e34bcc0c6c1518ab9dfd01f3834b406070815af898685c3a4c5ca51f2a29e84e7eb800d8b8d31a10d8db5a82b8517885118fd581fbdd1f1947ed0d45098bbd31b2a4db19c2aea3955ac1c25cf7fd0d018a5c951a213c672743e1d8fbe603954ae9cd68781d6174475e3439f8bbaeb9533e539931665d123dc5b32b83caf015642166d0520fca84d19218bb6c2a8f145f8511bb7c95ccc95172a18659285fa9361ca45b717e6fc60e550e550d9d00fc8940d7db570986ce8476d5c5470849aba987cd4c60504489557e5c568121b1aa755add0a35470849e476b5839555e489343d5a2db0b5f392daa8f6e2f74e550f1c2580b896f515818ff168da9514518a32f8a83e52c6739cb75dc73a67e28d10979c258c8ea808c8a177e94c5a236ad1665b5e8cb6bbd7098e030bd28ac458575c362e97c39555e52cb63da093dfa01997ab5688cbe70583854aabc10e6a254aeed9109a306143ead8f8310c2cf693802d994cbe3093fea29a9f22a6083c37ba8a723a422a422a4c2c6c35172d7d1b9a12ab891951a6a7069c1c2da8925b16e5c382ab870f09d9b16cb75e306c5c9a1e29d09a590e1a0373e9c22f9582c168bde8001c17173837303c70d1c36de0d20afd07192bc288c5ef12117bdf9207613bbc9b9a12e2eac1a16a5b981b97080511b188cd6c0288debe626278b0fc1428f4ec5804cf108a73e88c9a65c43842f336cb4178653248553789e37c5f77db02f9ca24c19162bc98b95144ed172b55a38495a2ed62b9c42e6d1245f3805ec4b8a019105030d20234b2801d767c38d03b008a762b15bac05de8d2e3e9818568c032d1b0bb824107ad4e645068c8cabd0a3319a3542cf8731b68c71c4171a2e504516686841430068f080460d679c39238d33c638038c33be38838bd0c38cd1c519599cf1e50c2aba8431d344183347781bc062083301308325f43066aec2291d34ca80b2097fd0c0151e188383107888940981870851181c84c0b3451834aa00a3d584b7a08c8b09329e96d712686c117a9830685411060d2ac2a03101cf8a2f3484584220ca8040190a28434be861cac052860e6500808c36c840838c31c668e20c2e6768398388d0c39cb1c319339861c68c32c298510233c29801810098b1c58c2c0230030718186658998a9571461965841ea68c2fcae8a28c0e90a1a58c2fa111634891c615cf4c99cfcc9810b0c29071258c990e782d33aa20234be8d11b335f72fc2a4c1a4d84492301a18731e38b30691011260d1f2e504516a10f610142027cf4bbf2837b9e47433deac2e2c3e8d5fa6eb0a8d7927dae580b16a3af98eb86d660436b28ec864ae1e4b8b848d9e4d0c4983ca3308bccc5a5a68bf7b8ae70e9c2a58bd0a35d6868c68c202422242224824be85d3c16b571cfe805248bc7fac22cb2cf03570ecd17ef69b162748618e572856b0c920fc8a672782dcff321980b890a64532e2fc28f8641f0e0c183078f315f19366e4496634c180bb9b84c00a32d586b02322f6cade06573e541e8e5e4f852b346161797355c61b870e1c2850b17562bc798a91ee19725ec4186838b07612b27c71717c8a66caebe6409736820fc707099c1e6ea8b0e2e1cf0127e948cb05566ca861e6db572a6cc295ccbfb72a6a47c3e9d9007590df51f521f4e92242c1c2cae63433fea22e3867e30dfe2aba14464df940c07c8944c0b2bb4c999920de1fa12d6009922e232c3e5cbebe6a5c1cbf3a0178d852ef73c845768469645cb27d302644bf851282c23322eac9d8fca86700d88083ffac9ba841fc5d2ca91656185217c3a5ed883ccc3e165069947a76cb078a159c106210f396c6ee8946b8b67c6f36c68c228645e6823739961c560af1b33496c9a88c95a2ed7179b26bea09a9cef8beb8beb4bf8d11b59cb55c4102d1eb495a3c30b8f180f322fa441e651306453365cb4841f957589c55a74ea83d035868b0d17598e0e32def3d1503646861b2fbb8e178f5014a409d9f649a3957e8dfcbfeea07ebb6d596ffe6df5d55651f23536ad9e7ec67b6b90fcd7bbb2ac58ef9eca862bfd4dc97f0dc3f8243ef29c905528c84f84ba547faaccdde90944940ed16874eb6ad21f6fad226f1d97d85d9e4d45454227d1f84e886833e4d0824cbc72f7135c269aa1424dd0387f157abb76575e4cc9fa25c59bea6d6bd4da6ca7cde2f478040c0287f4f4ecb6cdfa62533f546e845232216fb8d3d8e9a33e375addea8ebad92627eede25021070f71f273e4e6e552df438ab15637d2cd8f782d9e890fcdc6fa6dc6f26bded9323f27f5f262962ec33e7242a264952590a165d75b42ceb88e43229486451ca545ceeb7a55fdeaed53474f71e9745e9e2eea03e6bb22855dc1d5f1268c819e504776fe23216c8385896afd395f2dcaedd3a5b1bb5614ac15d599e364a5a92eaa7364c71e3ae462c540139d9f7ed78c31f27fb7e6e574df175fdf2a156c840d04fcfb5f5f45c9b98c5155a4ed221f712e31af9393c1611093a898a88c67792b1cda688f357b9f8eeac6b594d5d735235a3a0e8c86f6d74df6a73add2bbaa2bc3bf58f74e3f66ac74bb76cc5849db3e3f65bc9d60db65aa7b0cf5ad6654d4ed5aaabab5f824e6240a07b7fedbedd474e36e3647dfdced4a2f7ddce679dcce9db75c719b3ed5bd5394931b9a98712feb88b369c78722a36ed7eafa797ca45cffda2595bc9fdff6b92a9f47ee3bd18a481013f9565629e33d561b896d7ed3fcadc9fba5fd31635cdacad2d6f23fa9c09ffe5673f6b349967849ca848dcba8934a359990d72a21afa58a1ae3ee4d2e8b0a421685828353a46c5c6a1ef25aaa285240fd385d4b4d49f29fdcf7ab9e6a8b93a2e0c6a5a69fb39bee8cd666c737750f792d950e792ba589af696f9a154769e4b554347abfcadee893bf33363f537a2bd5967e7e9c141359147d73b7a97e9b0d4305b12b739f9fc82f4bab04a7eb8e229fbcd84897183fd5ce283257dd4361fc445e5cbb4d2ed38fd58caab2fabeed91ae6d2a317efa2aff59490527b76b77386ffd48f74d26bfeb2ecb50573389dbf689d65f9a397ca4f597e4eb126353cce19bff29676b79f494005bd519ccb91c91a1a19ccbe5724fee4e87444d55df74772598ac706f364a34cd3a3474e4a74811a0ac8786fedaf262315777450a2a02f49f71524a828a00555c54501120ac937aaa5a1a010dd155a89f21ba0ae5334457a18e00e92a941090ae421901d255a820205d852a02a4ab50448074156a0890ae420101e92a940f90ae421df9d15528a11f5d8532f2a3ab50413fba0a55e44757a188fce82ad4901f5d8502fad155a89f1f5d853aa2ab5042ba0a654457a1827415aa88ae4211d155a821ba0a05a4ab503fba0ae5a3ab507fb153d39726284d459e7f6fab93fa5bcd31e5bf5dab64de9e4a5b73491b5ba8da3f29ebed97ec6a696a8ba4878676db8a64f95669b7976c877ad26f75efb4e487db30cd9df7298d461f273534544df2d67cdbf7ab92644ac038487eeed49f95180192afcf6aeefb399f475bdb25e17e2d2a8102926f4bd3acf4fed7a8ae38ba5fd3ddb619e3f659a9ee9d524801d3062e63a271d9521a2e5b0ac3654b645cb6d485cb96c0b86ca90a972d7571d9d2167787c95e371b68c8997f57976027f271637da86d737609f93a5c96e1c64e1b63a88b6dc55925b9bb0c52ee1ec368f7e770dbc2504585a5b4c64e50f973a7f617aebdd9cc84ac46e64985f11277cff9719b89bbbbe0ee555abbf2247113f95fd62a79b11359e2a5fb557056daaf7578b4f1bdf52877e6ecb54d3a5cbed1d3aebc4c34794f2577d7552d89e0eeb2a4292e4b6ae2b2a4251ebbf8887cf29ed848efbfe52a457eb6fa9176b736612ca5c34b3096faadcfbc6f13f29e182ae331ea3776526f937d4f7c94ff5efbe476717ef2556c5466b21befdff2e792a8c65a2bcbaad484fc7bb351d756dcd165228af9495b85b3299e660e1fb9e7af2a7194ce19376127a9b2ac476789a3c8cf78476127aa112f3977db96b666757da5edaea9c6c77dbeb8764695183f7d59aba5ad55e16db2314e9bf546b9bb4ed2d8741a1aca7f6dd3f7dcb3e775c5993d7697674ec86edb5c4d9c9f859dd1c556db2a8bd4c4dd3315a40b580515213204c8ea877caa112f3972ff8dab86866ed76e5c65ab2e1ec5dfd8c95fec8484e65caea727e772e2cef6bfb3fdd7644752ee0e44ebcf2459e9925412c59bee5ec968cbdaf94457504a4a32a23b7f95bb0b01fd9cfa564ba59ab755525986a3b64dff4afacddd1e1ad2fa625d1fca8809f29e586963a727b1d3ad1a7dae465da68d9df2dbaafa4b1b3b695b0e0d6d6d4b51df6a4d34b55d1276e1e6eb9e1c26af843c84db29de54937fbb15379a98fe79edbe78b479d313aff0832cecc0835cfd98d416b7296eb4381de5b9d5d246a5c8d7273df10afe024e6c0149e940a00ff8539564c4044a2a8ae6b9b7c5d319fc1ace5bff803e2050cfb565fedccdcd506081eb0c5ab38abf6b95cda62802dd7099cf5ddf4669fa9e6215154d9f94fcb256efd3afd1adcf1c256fa5a5cd3dbba772772a779f72778b734111180722e5d484c99188e4d4840994a8242a098f8e9294d05b719be617c97be24c4322e00fe8d34355c7f1a9ae62ded5d50c573557ee5757fe5d39ebca71b8721d7470af711a77bfe29ec395d35c5dcd7075a5c395fbd5550e573478b7b7fde770d4934f46af3da934f1490b4fa63c91f224ca13169eacf004ca13d91014bb9a73a51953bdb3f1a51953f27bac7c286ee39a8ed7201bf261c88aee4a79e850fe3d56abc70d49b95dabb5cd59db67935af91c11f222223f3cdc5dc8ce1127ee0e4449a025d01f5af5f93511d0a7e7c9fcbaa73473d6ca8705991018772070c80fe8d3737538d770bae2849aa014a7eb924c08018e6d97e9c99a6f6693adeb12bbed65aa62cb7aad52d2ae34cd5057dc139468eacfd5bbc76ae6f0d1d0d0f8241eab80869c45627ed3aae6a8465cd6725937dea255cd59d5dc68f5b5795bbdf8bad68a80869c44563587af542ea805f99ff4d010d5884b230f0a591129f6f839e3916e7c35a5364ba9b6f47152d4049a98b14823df4867506f9bb365eeb7de494579fe279b2859111e6e02912dbef55f11679b38bea9858c5f45a407b27cbb42fe2a26e4df263af7b7aaf53769fd23ce4f4a643522bf2abf7ea8ffac346a9b1b1ad2f7a9f01e1ad2e7ae3beac75bcb6ab4357ec2b6cbb4cb7857f2d6a6b2e63799943597b113a977f5a9887cd3b479eba19cae3a22eca47f050f0040de8f77c373b97b76199097fcdb8ab9fa79ebf2353d818892365756d9cf01dc41100cb2bfe4d9f5f38d6eec44414dcb5acb732ceb78bb96bc27fd5ce93f192abfea4bb1ea5bf31ec2e98afb49e2ee3b639ca6186f9cae383af43a7fd567aa3388d315c7e4ee4b2dbc45f314856cbbc9c556e77772bb96c4e34ddad7e227bccd5d3e72f724493f5787ee2e020b2e130286bb2bb97bcb3dc9dd6f7553ab33b8afc5e610d008e8d3f333be769d41216011a09e1e9caeb87b0e0dfdad66bcf5d0d0e7ecbe6716e2230414e2c3dd6974884677a5bfebd694fc6d9e39e32392697f59d6a79db1699e5afc5ccd367727ee8e44c8b69bdcaebdb6e63e9375d7dfbb1a0aeeee15b9df26b72a95bf963b9d6e55ea49dc74ab52f9c9fa50f9ab9830b95d9b9fcc4cf647fdaea32dcd13697f94bb9fd0b2f8eaf0a5ba4d48cba489b44cca3ada8b6f1d2f767277a25bddbfedb53613dc7de84bf1ff32297dce4afdae48ee7ec4dd5de862bbadc6a6bb1be17127afa5ca38e724770f2ae29fc3517fb1935408c49b22444d103aa31411897a579ffe6da2de5553eb5a1ee1c65d4d6d91b4aee5f864e36ef675ee0d70f7eab212d8204b7bfafc80403dd8766dcf9775d4e4df9bd51ab7eb5301461881fad01380d0fdda66c3ae2257cf0823d0138a2879df897bcb022d2890b8b77a68a5d0817b8bc95b4bde324146c2ce580b919100c599be1d5684c0c7fd5bc1dd4597ed98b0ebcd56d5775db1ef89477a4211bd5f8adbf6a5489618c6c1d6243de184316b2d3a2ff72be43fef9a107db1dde397251e8500fdfc0c39528bd4b715111a420ef923458a000d013a1254a448cde783aa8d14f209fa79202121e3d66716b28214d351f8141e51226a455a907cf27fb47a9d7fe32afaf9d43729081241b4d0212b1f9d5b957ac1dda3d024a9d00913d4539027f728f4884989e928e929aa470a4a92941393a3204582f090bfc7337f95dd3667b33982902cc88d209ebbebd02951a8131326a9f08869c9d353f8d46464b575f2392b457e155bd6fcf7937cce4a1d4935291232e127ad13abdf5fbed4d368f3e74e27a9a4a8a423a7a4262a2445ddaecd3b4a4849aa095292540895d4d4c429694998040595c4a4c424e59484c444a58e92523062b2644913a724a92326499c98a0a4a2a814931154529224292726a73069091326463b23f838ab2a881f637421e22d27b003c44066715808929c314595907b00c035423ce101879da185c905f0c719879d3973e6cc1930dc35001d8c3c61b3807b14896b8550c2bf9c094fa4b0d371d70058171832421177b1b004d20b9aa8fb0e8c041d4a2872a7c2e28a266178e1de0564c0d280971587f560220345acc1c45b3415088058812a87d9f0058b94189cf1970a36f5842f67dc61f5db5240f1cf054be0930f1c71676389ab29485ae0a241599c0002671c762403a316a209b86b0546d03c2f3bee6dd13141c7a580b39aaed06005ab04f8872467000ce4cef84bef6005929dce595a2079615d4139ebe9a98a041254f157010230420360b0827f5d80965a6b74e0b01a0480c4d59203384c8c1688a0c00dcd5d8c02d6f0818701fcf523480a37b470712f734573580ee62d6f9de0394c8b47ba661ecc7178ae0dbc1b5e0ca865c45901687900fb6231578be579bee303fd734f85160a9ec34c70398e97e79ee7b95c443c8ff52d791eccfb3c8ff5aaf2799f07fb3680f2bc9707f3cfc30159dfeba55343bdd6f7b5b0782dcffb6a3c333e8fc65d5eeb63bde74d7d9ef7c59a7c3f3eef7bb53ecf059fe7bd3e4f056f87e7b1bed8055c2cd80d6f03cfd311637906f03eeff579dec712bdaf554343e4bbf18a629e2b04d6091eecfb5a3fac9aeff3767004792eb47e6c94584f9fb7fc5380d762e9b45c9fc7729700bc1378feb94c2673cfbd96f7796178b18f04cffb5cdfc7f2bc219e102fe6dd7cdff7bd8ebc20dfd7fa3c1f1668d32336828793818f4f08cff5f5f05a1ecbf3efe9a3355ecb3ffb724af3786039900b788e24031fcb7b792d9887e3b1b27c5f6c88e509b1bcef6bd1ef8646c773791ecca7f5f3818ff7d5bc621fccf386bcef1b01ebe5d17c2d569597f39d9ec7eaf1686c3e2f06f33e249f079f075f072c67b987c37b7d9f87d392b15a5f8feffbbc97d7b27934217836aecf7379378cfcf8986036349f578bddc03e4f052fe679accf6b794b5e07df918f83cfe6837d2e8fe57dde67f3c15a1ecbc5f23c231ecbd3f168bc1bcff34cf03cf86a58302fd6f23ecf1bf2bcd7065f0eaff579ae9677e4b3f1589f071e8bf57dadafe51df93ecfc757e3d178b1d6e779de90d7c157036379ad58cbf33c23d4e341428c885582cb6379345e8b874743336413e587071e082deffb5e1fec3d990e1f9b25cffbbccff3bc1e87b9e92cc8e09559210ca72b144106cc0a40be00e3493dc1029a98608c4b01e1c2a38ae8c047552d1caa08290c0005043351a188a9324f95089225457840c652e5c0e748113c841ca937983062029c108c00a9f1824ce0b111443b738020da868334353ce8a16df978c6208179a80f092568e111e3031abdf980eec8c0b56830c569ae1f9cb600e0ceca8fdb980825a27adb9b25f175af0977f7c06594cccdd684e4ceeb5ea35ddcdd85538acee09b75d42fc5fd49464d9dc1ba2b29e2e060fd604d71d5e2e1aab5e44502f56066cc2043e2cae5ba818dc0c50cad227e5a3b6e8e60e295c3556b09cd06351cf000c015cd0a2d16581ed8ecd74d4c2926f4aa6199c0a3c6b581ab5897ab1c5266a031c232c018375e5cb9ce5cb96e7c80e0ea66e74c7145c3e3c60733c125c415802b3a6c7a0841436b872b1c40700061f5cc84c478ccced0e02a2126042362e16011c58eb86235fd0879d5bc9ab862d9bc7cb4786c7e585eeba6c553a3e42a01b6c2cbc7abe6357593e326070d0f9a0d602bb0d8a0e1e583c58506d7972b11a65a392a8ad0416be806c76bd6f2583daca3d6d3cd8ed7077b02fb017372e9b8e1bd6c58aed60d8bc5fa5830568c4553c3418b056b02cb00c753cd0cf682792c588b484b48cb8bf560fd9881e603171357379a9861f66afd8821d1d0f282861c91fa99365620822d3a0046035fce5bd40f58928c5038c108be62842124880c470c168505264e67b208e3810f7cf0c9220412027811022daca022024f2421041c6100e7f64167336050a60b316130f000196268410a0b5098382551fac0831d1b483101199e58400c30881d7080ef0737bc280195dcd59936d038434a941d1bcc426045062a40450420c0001f7ac0416c6185274c9c98b4c822031ca04096a51170a1851518a0620a248ed0a10600c0a04c08c4503185140db072f52453d20ca74c0abef04203189840145028f1030f4f8a2d4889f28429c984a19d198e165968c00005f8c1ca932da4c0a4946482a7e00b2db2b822031388020a062801440f56a6a4c0748209434688fcec64306bf999147c51822b3490010c4c200a062801c40f3df060e504e21429280801d7506389121c3748c001961d7480f2c4c7081e74d85939417386d5c6c7864b8d2f0631265a4b7c4a7c497840df0fcbc7036d7a5825b0e8061f7c1c783f603e583d3c1ead1dde06341a6490014bd6c271734386e3e3a6870d0735331a58ec05fb5e2f978be5f9cb4a8d081bb882d1c0685a376241301a560737523338e5c4745e3531a1d60d0eaf75f3125b3a160e6bd6da020004b87addf860342d1e9c0e84167055e3e4866cf1dc98e123f2c3d5a4e5bd882c7075c212a41900be564d6bc90e1a572aa08104303378aea1d9074866f85a3e583da607a4c8558298abd7eb83272b3a7018d5c04a32c30d573d689edce4b8c95145498719d335675c116d9a24342064301a168e8baa85c30e33c45a375e1d783886ccb0022368480081959819216e7c362e2433d89196928fc285060d5c3a354a3523bca4b448801da141024524a161091f3690f958c11997e450c595cd692b0000708070784e38609900eb1134430decc8ab26768365842909ab831aa533ae6a604c3851b1a51f494a35344b3751249104ae76b478826a5e431ae0bc6a6c92725a40e2aa26b6e4414d872b174be6f25e2abc6a5c26bc482832b2396982c4965e35b01e38483421b49c6876e4e060041f1b90102b4109d40833d4c440d8109c2146989e60372d980fd7102b88e6a615842281d1c06a5a425c4a5a42483cd70f1610d7063e34b1917524c9041eb19a0d688ccc70e4644324a6d30aa115c26b892b126eb4905c25b83ca009a1c5018e1f5607345c81423c968dd5d362b95cc869218829f07d620160bc7079628923729001062b4d65fb91d6821416a0386912f5b42485a521a1213a238800026d65000367c400630528148990e3a3074c0b07b048020915925018ea40c78d4d78f3d4100c141de4cb9add607c36be144cac865a8cd959e14c1e6981c56f5fda2a9bcddfb5aca3fe232d90807a88cbb4a0f9afae9a1aa7eb5259d623ab2f0afa39b3b8ca028a67e193858c0364c02934d20b072c074c92ac1c409213f7f8539f39e0239fe6ef7afbf2c9b27ec615f114f1149966a86b0d110fc9b4b3fd1b0d0d49511e6d452c7e747fc5fd1aa7ebd2d09014b65d2630eeb427f13844dbc0167a996ce08a5975e10668baeac20d2071df4028bbe28b839fc3a3aeb827ed68cfa82b76ae5efa38a92b9eaef07fddfe1a7d5d3f6b60cb2d9f660e679cbf4acfd54009927fdfc8651a90c9be8871079d644c69651d9340dd6fabdfbd12bd7baadaa98b764f55b47b25b9dff6493c7e31fd0b922f32700a4def13efd764dc0a2fbe5f5b91c5c12934fdb76a8a667d9cb85f77e0322b4cb12c2d95154aa872cd7d2e9232f14eaabb22d55d496d7b285d73d2d09054d10ee5011af2243eaaed6a13c9e494426e84a2ab59dc768abc96ea56ddcef85af1da5c59339eaa3911db2ed3e7ead53827ee2aeaafb237f25a256feeb6f854a3dd5fc56ad1aae6c8ffb27662a4dc68a5ad6a4e29634b24e8bcd832118def644815516e843234045455c5ce1dccaf4fb2e676796a59152394baea6c962c8b8686a430796a912cf105c660f2d434bc40974a9a27262f60e554f89ca23b3a53748d720125e4195523ef47e9fe5a61a3b2ac639114918d89795261bc84c4381d19700a4d57d1025dee2962f2d416c8024ea1ed9e4adcaf2d6085c9535b80861528632bf95b56012dee0e9eb50a24f11c66bc4d9b47fd48dbea9df25f1d93dd2b191a922a2a2a9222ca58892889c80a1bb97b082ef3b2c5bd98322f480e4ea1fdedd6d224f39345f9a132d2d67fb3e43e4d9cae4b4544e33bd1f9c9fa4bd87699b6c6e6141fa0294043ac9ebc53a461f52493a1a1ad7fd752ffdb84cedbb5bb6a6e8dc7229289b4626e849271ce8fd375293742216d5011a0259cae380a3899f15da5f0f252d820850fa92b8e4e408d092431812777f062f3a4e4efb152f2d61ade3c3cf9772de904645e3f4345d16587961ba190f7a368bf6d5827bf8eea7fa5285a8822b6b5cdd910dc96929ff1c5b81327812fdcefeb50025048000012e0c197263e55dd344ad62e6174c9e260d311947c628ab7cde14d29597134ece2a44bcc1dcc915211c0c2ac79d3fdb208ec22e0e3eee0cedf8c6b3a745b0ade100263408008082c3948dba13c24138f0e8d5655dc499a00011d5e1cc46dabab9f1fa0c30382a018e3e0e7ecce98f2d4fc557f6fd7d65dcd41f1e4ee4c5ce680329cbcef00313207ece0a0d6a736f1d6f4a4f2f99fc81c20d4801334004b79eafd37f2b4aada5a5aa5edad2a34008a7bd311147a2bb5e1a406f09031c0020cc00cf880011fc8b860c1c5caefd728c6b71ace26d5f67ed58d96f5bcb58982e49b26cee44e9f38ffed567287d6cfb74bab0ea8afad393bd6d224bf8a0b757730d7727c1237dedaf3f9e80932e48ff471524f68b927b6d1afd55d37ce7da6e113a683f977696d4f2c81f4b35e4019f0628a498a7574b7539655875e1d5e40976b73f9f7933a88d4025e7077506a01424e9071076db6b33656936aac25ad549b1597ff09bc96ee60f2d4da525d754e78019d4842e6c493a578dfaedd27ced486e9aeea28be25e5f9b2567163fd7c4faaabae093337fbf9abb0be55d68416f7fd9fcb7893b69aff38a92670e0eed61cc578e7bf3add041277908932fac46d4bdab23e4e8a892f3226acc09da62328d48649ad3fd7b6d5d9f88e54c6848fbba55fa3d1a4644b8c01c9df9fcd2f6b9526b5c40c5b677dd6f16b947c7a4ffa3829f2c9a2a2b2ac474554572a4544941ba1d89c5d221615ede810e54628a255cded72b5a3b5fdfd5a91d64043cedc6f2bfedbacb0d1d64fe64628454456d848a6840e0f97291103a7d0645bc06cd9b20577cf2d3e0e4ea17dcde651d7b6c8c8fb7a4c7e5b125c3c375ac992b802a7d074f95b243f09289f42bbd8eafba63eb5f863c6b6a1215a14fa1f959f6ac4a510d0cfb9ef8973b5485bd526cab32304f473521e1da2f19d8c45f96dfe938a58b42374521ea15387e88a5fdbd51cf9fa4b8c6ba2b6fbc49fb39b7c2754232e8d7665c162309a22e16c0642083a20384d11978baa34a95c22009901f971ff51c1dd7fdc4510c1e5342e1a9c1916387777970f2aa044e9254439d0dc63b0978b86f579beef5791163bc95f96f5a82ceb91161504b183115218d1c50807dc8cc88c38c200089841004600c0852096ec9c116f440b412c1901c5ddadcc5cc6591b7ec88216c1c5292de39c5fdca749837259114dfc2fded49e9447a9080d645a5ae0645977b5d18b2f0ffd1c8ec2e4a96ba6c5e91cdefad4e56c2d472b9ccd9bd535912c2d4ea4dabadab0cea499cb386c13f5eb2cea3a8a358bfbb5aee419f5b56a64e6ead69fb3524c3ad44b4c724cbb7ceafa59ca0994deda96bf2dee8976d2e466b57ebbef898dc8d2e28ea8ead6b7c9d655e988fc5c71514c660ec9cce5256cabb93e69245d737d0a6bae4fb942e98dcb287d2b2e491dce47b911caef0ab55feb30e79a6cf59760f28c7ae209776f015e134cb87b4b784a6c71f79240c2dd538077c45058fe78ebd18d3c53b85d4b75f357e124f96d173bed6ef8e64e6a6785f3d3107e5d9fa49820d15d7d3a732605698066146007e75908e1c5871388b1854b600020f0f2c3147524ba04d1850803332e000c9015041bbab80d3a4431f2624217b722c101ba486203342f83f802041398808f571cd4b03a6ba83f41807863012ca0b81304b8e080002620c2952020c4160207c0380a356011440e2746f023322b57f850012d3ee4080aaa87cc8a83381ed4a005b5f94e0b3ed00083fab9083b5c94a10282e4406a06a0112922c73b60e3011d48010957ee030621b4400d99e73c86886145491649b88e295a45bcb8c1876b7005842096c830c5673a5ce181209c94c0715c801e8000b52e57377450d0c50688b4f84d17294334f002832b9bdc120a4526c16b8ebeb822c304059c464802500738411157b1a5081c416409dc158c0a0735d8e064057f3d51a60009297af0977791982ac0e4aea740a2788103496b0b08eca042f383b75800c28726640802098b05e1991b7ab0171600aa8c305778e28aa5d33282012098f1f289290112471be470f5ed90c1034c2a332f1f9315b9032531d0f2dd3822840d4b977a5b4860021b8461858fb765892412c8321be3c10083130b50a38b27cf09141518401121a83784044922d0008a325e0e2c04e8a1e5c0e266320f4ad6e0c0957be1d3346e0294f12f32ec114050228b43d141090ac01ee878111cb0bb870ce0fc07164ed0e2a668c96908824814379a00e3e7122b96c86081256ec511ec94e080166f4189a72f9880e2ca9bd00c61ad9800852f21a5904086e98ea4254783528a1dfc04246a3eb013c47523158718722f04f98f171d170d57ca380f039ec2e4548185eb8cd0811910b270e021cc7a50b8a2e28a539b1516352419c13bf8318409333488c27d88b0446b054398c077c0108215041c6980ebe891450384e410c4332803012588aa40037c0653a2b2a10726c7b144c78fd404ca380e05c6a88247931bbf819202ee220ad06d3668238a1e1890c069ce987294030531f018191a986007213e8fd58c30822953ece03021323fb02c6186bf5e10a329881dc07057980c30104601d65d4435e70520d4e02d287e0460881c2e78eb0897081411840a676d200268fce0a53a0bf702dc112cb0c259321007890ea8e09f971d03177af4cf4a0c19cf04a27f4232482de0e7c6bd361c6064822e0770ef0a2b7609a404b947448e1a0ea80206f732d1fe028318f796643985e8c4c03d12be78f0c10674dcbbb981c05665873b0c3c10c1f5c200dcb72080124b5c4000ee16108090323b27ee0bc0828b27988c7137008c2cd3c1903b0fb2aa145a1eb8c7208198030e00833b151094c06b2dc0dd86c4aaea82e31ea504b50f062b7087ba6185303e9eb8a700022e84045871371a02044042bce06e42187393f0722f424512100ab870f759b2586820c8bd04110361e436dc4738e30b129460b983e0568c22c8c2fd032a55e0d0460eee1ca040231a0a807b0f9a10326a74e0bec106a6982141e39ea30a15da081fb867f0554865b47097d9b0c4088440c3fdc6163b70e1840bdc719cecac6085e96ea3c68d13c08ce05e73811368051ee04ec3c4073d94b0847bec8917a8a48001ee300edc2136700177d82705e4a105ee2f2562d49c38dc5d5b7042b0c3e7eeca2166cc0a8cdc5b580460458c16f7560f2b8c18000b77d61338b10d90706731e1c9a28222dcbf346c68e8a1c7fd63a2090d040085fb6723e19b3670ff8248400a006471f7c4300294e173f728500480d001ee9e0f3170fa02e6eedd9e886e43b87b465facacd1c5dd0382860f458edcbdd60b0dd04101776f81c743dce1ee1e08f272c50fee2e4508b22849b9bb124730d143cbddb37c8e0a15dcfdca0a665f6aee5e458d323060e5eed7851d02a071f7110524369872f7157472784289bb3ff1b8d9c207774f42c62e08ebee488c0853c50bdc7d480604169cbb13d97932868abb8323a8c04801772781874f130db8bb08608878e1cadd819899fa401477f7c0cad25490bbff98a2a999c1dd7968c101490feebec10741981370770dbcb042092e6a209385bbcb68b828c00adcfd062e972374f71b18600d68e1ee365a80282273f71a2a65f4e0e2ee34351f3fc8b87b2c878218da70771810576140c0dd5f1c28857070f71707b42e94dcdd0543931684dcbd15c699e487bbb7ee0f2f4631c8428a20868808e2eeac20902900eefe9d4008066c71f74f88ab0390e1ee9f94cd171ef4b3c78a4d27f16bb5d603081e1c4a24b8bb03e181bb3b103d40204692104840870135dc9db58209c584981c67c870f7d616239478d260025f8cb8bb870210519860c1c10052b8bba7830b3ed8c92e2226dcddb3004b860fa410a60aceddbf1b40c88100148870c506dc9d65c60b5a6840131818e205eeeed10e70a48912102d90e0ee1f142d3cc0858717627e707716979b1ca47e3cd1022677779d902b3242888fe70977ff9624a190021d82e88086bbb374f800260c21b248e10177f7cc245c804002a088c1c3dd3d072ca0e6385220b1c3dd5f041080192fcc501b48dcfdfbc28c1f5e584308141871f7560168b021701b98f2c2f7dfad7ff7884284e0d7d514d2d404d268bb9253687a68c8567e142d0a7ddd84823ce45b4aa3d5fd39fab89df111583ba39eee8aa37dc647d63e0593c0b2ac47e03ecd6be9e730ed5f094bd1fe6d655947905696f588f6361eaa8235c3a77f9b88b728fedbb0ed5af17eb9ad4e6b864ea0ae22dea24dd4fd15f11669d486cb5a654f2aa4154b8c4d11ccd8f6398cd35933fcf16227106f11a4914c21ede23b566b8651229871a51b9f54a8b66688b40b33ad4708cd9a7597bf0a8fda926fad76556f73127057da6c98bc15772d99311e4b3ce28db3b9e9aeac39bccf4a2f8fa61aa90dd721bd5fd39b0dd3f2499cd327f8ba676737befdb5b9e66c36a9b6a4d5b5bf91f54677fbf7b54c4f2125ed27d9813f3dda525bf97a5b6a048220e5012ac188f2fc9460a4b36f25ef8ffa494af1b6795bca63741ff78482e46b8d234ff271a336adce864f484e215412d0967fdbfefc5305f26fb72a45133f3f9931d5d8a4bbafe92f4d5a626cd6e8aee69c74d556d3685affdd23def4a96a4e97b6ee27e9cdbbda5bedadf1d213a877f94f2a4c4f61c6a02ecb0aeefbb5fc4cf5892fceb8f1ee74d541c09aab69c3a22802d12789b34931120572bbf656b7a6956a6bc3398cd381bba72aa9f2e76825ada8ff9e6091dadfadb7c6651533d6e35bfdc5b42ceb675314b5adca04f7eb8c773525274fd486a97e51b4559925c626a5f7766dcf67932a3979a27ae7b6c636204ab7c6385ab3d554936fb39407db44f16250935f5562fdbf71d5586b94e7f7f966cd63d4ae26ea6d453397712288755973f81e5150977f6fc58d36acf715a9e44890e6aabb3a4cd26bb735edf8598b23d6f9f5b6e12a8ae06baba3d13e87a3686fd2df95b4e4ad23ada6fdf1b378b1a5859ff111131ad5aeb65f49ccd82682b4a3dbb5f766a368b4527ceb58da2a569b7fdb3cea6aea7d62b0ac27950fb27bdcdefdc5b7f2d45c4d5cab36cc444551a491ff598946b5adb9da6ca5bae64abe3ee9adb8ac944632d55c9f68175bf2b7b63a7feed4ba9256acb99a2298d33557f3d6f13f2b51907c6b9ee3883fdbecd3cf47f4d6aa2f3f535d478ac5c7ed8cb5fe713c69d87699a0cc13e724349a0e5f1add950a57d1df1ae374d48629254b8b1bf7e336367738fae4eb5aa3e457b1d8762dcee689f38dd2c76d50ef4f0292aff1a53c9a2cdf56baf599bbf489825aff487efe7dcfc7e5fd5c0e8f9f9928a82da596664cc9276d15d33e4d4ade5a96a7ed49bdbb955eaca744f141fdd9fc4ca3d1ba99f0be7a8f67dedaee5b6bb8ac5127265129d04a75a5db1e25a1d15d9ed5f624b566485aba5fefd7a415f7ebfd5aacd256fffd1bf942ae3ef57d7df1a8a3e01e6bfe7d2dc55beb2f45f22dd5b6877ed59428f42f1e455b15a5d16b29fd5cd5f42b8eea1f2d792db5d52f2979ebc5a6aea7d6f46b3cbfb1137d7d6a5bdbfada7aab3b9bcdef84eaafaa5fbe2e932848bb34a8a6261edaced5f91c8ea227d0a88d89829ada72c636a8a62651dcfa6b5ab4d52fc59ccb691b16732e07e230ce14aaa9897ead1ae1b6d589a2086eabdf178fd75e2614dcb9f9dc64ae38aaad8ea5b76b6d968237f0298f2e6db5edcfa3a6ca58b7ffd2c76d5d47b2e25ca35fc357a7ac232ecd1fc74abf46defab51d1aeddaba6b5887569af1a69b8abba7cab84dfeeb537f3ef7a944c18be957d9926afbbb52babb95820f5acab371377bbbf66b94c4b8fd394cf5dbf23325eb6f5d6dc6f766a9fe5ccdd5a4ba52dac6a5a651d54d999ec2db89719b0e25493171a2a0aeb22795b7b9daa969c65afff8977eaeda86717ea2603e494a37d596ee9eaae25dd6d166bcb5c595e68947aa2dcdfdadea937e69e6aad5d31b52d3e274feabc3364c2bd576e352ef903fde13df5be9aea4baea74a8d55f32d7db677ab1bd56047123369fee5a824946a1d179b3b68bc74a6fd7eeb62debcdf6a4f2995ab3529aa841bc29cde16ca3bb5cab68595a1dadbb92fa71d7be0d54a2bbd2342b782d259f3ccbd152fd9fc3e33ef5598ed7d25ba935c39c6bdad9fe8d40bdefdb722ccbd3f6faa44c4fa1b8adfe927ffe4945c8b6fa2beed72268c3389b95eecad19ae11326a0352bcd4f95b14eb4d93048a974ddf4da8a1b7b6c364c1fb7a3687eb23e4eef5e0968cd1a45c1dd53d112a8ae666d4bbd7baa27f1f8487af754e2ef1b6852f269d292f0288a92bfebfd3477e66cc50580065106671dd536882e0e0681450741037da8b641d03a03e2cbe3b6898118c23de7ce9b3b2fc964f50f66c029b4fb26fee1cbad5f8e3f64a1c2e60fb81f7cccb83b2eb5fe11cb17700a0d8b88d3f6b1d0ecb55874dc872ddc072dae6d3ed4e0830fb86b0f65f29bb4872f610f3bd45d91740f4b7ebf8798ee2f0f5e78b8e23c40e181c70e6476d8e2be83b97f07243bc45c07303a5cd1018a0e348732e0145a0e39e0dc73f0c1c18ce3d0059c42c3e10a8725700a0d07d9953157b8b85f311d9c42bb2274dfc457620e4ea181b921cb0db41b7c6e701bbeecc6fb5b5badabb9abd990c5069adb5083b85fcf6af0b25fd780c57def1a68af6bd0995929034ea159e962e5cacc8a0a3a87452c5ad5dcd561b2c478b4aa39ab8ac57d925627e236ce5f456b118bb65c25ee6af9f9331e45ab9ad3bfb17edcf8b9dc5bb455995a87715ac4b7dc5b6bb23eae52615c8ab76b75aee6fa6434de9d0ec59a78f1950de72b2019bac0381d8dee6a3cff364a33eda6d930e5a1fddb68a1d6b57c9bf86f13ff6d62d12bbd4d34ed46bae9dcaee2beaf8b848686c8ad4553c760c6a748e1c1385d142914cc36062eee0e5e1c430c48dc63e0010319aa9afb8b290c5ff0130c59dc4fad6b09c3938364c6365bad5230f02837ae7ac1cbaeb4babe70be401d3c699487d48fdb7b575d712e94016fd7851e74f89ee4dd6311365d90552173cf2a5faa6871f72aa67b95255ca577f5eadfd5b26e6bd6b188f2d4a322fd1b3bf98d9df094f849a708495f5c4435e225bfabd7d6ad6b7557efc655562eb0d2f2396c45734b7ec5e5688544c98a475935ad3a32475deaadb8a46519eaae3898b1ee7550f0d66d5c46d95a1518b8aaeaaaee4afc4441b256d1bc4ac7dda9129413a7d38cbb9f5c78ce2b77da6b5ba174ef44a3d7da66a78ed7a80e72ee2fe0eb9d65d3665b666fd96eabb5d5e690dc4cd7253ae60ee62ffae62bb32c74d2e8102a63dc3d5f9efdbb90cad5df9bad66ae8e54a03888739fa3325484739fa3b285c9e5cd2b8e7b2a6c9a38f739913429f9580db38ea712f9dad65c94df161d6d5d97d42cf67107cb32a4b3cbc5bde220f9a57966b29e54e8e34d3569abc24bc49d36250a8de6bf5d5c5292b4353abb1ee4bee4684f68e66b8c1b733bb8833ad2e66cb91cee2005495ba33aa5524c79e5e0b5942c1f47b5a556b7672514f75247db32e6545fdcc119d516772a2c0ed24b65c3a59e32e3eebabf535bd4a6b8383885264e594931418a9afa291e6ecb580fd82bf7d2ccd9247457cd209f67f629b43edc2f125354d5e498247ed1ce6793bc5649ee4cc23db9e37c70b12ade4e706d4e146f55371166b62ddcc1283048cdd534f1a617d39a6f5502353dafadbad0b6e54e11a3d0a8eeafcdeada943cbfaebfe4df8bbb8b6559c5cf024ea191b9e2dac562fedbcde66dc53741fa4bee5e1ff73aee471f73f0ab584d7271275f20f1a666d5e95c356e63d0ac3a4dbf1c77e3db6c4985d08d4b5d473223168af7eb3ae266e3e3a4467777128fb406c6419269d7b238b893d3c1ed9aeb13ad363eabc1502b01dcd5529fe569da5b73b87c22f1a8fb5bbfb85975ba6631dd9d246b45e25e7938ad8ce3527c1a185a02f2dfeaadb9a212e3da5f8ba7689ff884c88208a40518b4a0a585215a409a4d39630a18076bd8ccfda999c07bbbb6fea96b0fb843a3e950f27b6653b04cc94de1e10e96f8946246ca172958aa265f0a1477293aee1ec54c388b428128b7281fb060c6c11f8bedaef975adf234a1d5d2e66c940d536d495ab62c6871a7d5fcb4190b341a0b321ac59b66c32b2025d1d13c57d8b2c295575c955a21079430c01dba53965587ee72ddf72c7155594328d7e2291343c1e2b55343a139883194988354a3a5daa94fb6202dddd17952cb7c6aa727b4273ab4fb4bac6ad3d0102d0ad54f5c9ff45a275c1c0c5262ece4e95eece424468d9a80d1440ba8b3adb90914776fc2c149e5c92aa586d496bf18975fdbd51c296593c211154594095e8b53d0e15237d1db1dc98b6b184fe1fdb92824da294a06e28d2fd41710ca0a541215cc501ebc77b75615b858555baa70e53e53c107b4375cea3a32d127330e92afa34f4f11983ded4aadbfccd84633c69b4ea10d0dd1a2d06be993cc73b6cca78d3219e3a710d2d212e3272658c012639b2913288e315252ce52ecc444875ad51cd596eafe6e8cf3a8fb4b5e6c54f3b6fa22dddf6bf194786daec4d814cb5ac3e5adc98bfbace90a94261dab9a139b968071f7d9122e164f2db9222e59a2335362c6ddc59912304ab628b9721795a8a04592a9c4f8a928ffd09094b82bd4d1ae59b4aab92ff7c619b78b76748a8aa4889a509e9abf488a48bc36572bc238eb2f315489f193fe12e72229a2ac97c6804b5bdc974cf7a52577f770c97b747f937cf16b294da2b3aa4d344d5a91b462121d2533ee2459bf2809f11b5715d5f03c511e92897c7d8a4bee0eda241dbf5513e9cbae397dea505ac634a42c7eed0c0969b455f9f5c6778644c2ec882c31a5bae2cc7ab4038dcf8e68b3a39a31ee9fcfaf2a5fe71eb7f1ef5b733d6f74e38b1bcfa89bb199fb4db535dae246a6b6746684c4dd6ff5291c330b15e0e0eef94c7735ba2bb82d79ab8d1a1a92fa5b35ff56cd10099e851e805368b9a88848e713d77037fb5724efdfea93ae6511e5f92a36caacbf440434a409de9789f2089d667d9c51936d6b4550484b444644e33ba11a6b0d0a29e3a38c6dbb8a78dc186771a9acfbe22a36635c91eeaf1645ddc43cc9fab8a29a9da21dcab33f2a8ab4f9d4353fd35885cd8c772d4b7cb41baf4dc4bb8afbc4e2e7ec364f9c937c59b3e689f34d143fe3a3f262d13c8b9688b649fe2ef2a9e92543434343e3576d5ba33c42a735d27fb1dd3bdc6d4b34be93ddb64b44196b8dd3754953e5aa138b9c28cf1251f8744434be932227a223bdafad79eb8bc7a21dcae3a4b3b34f26948764d2a9c2e6f84ec82228d1cc9d5fc53a112d3173798909a7ebd293f8e8622b8ae715cddc295ad55cdd1589acbf248ad7e674cd7f44872f25e911211e5df3ffae1422e30eead2e274b467eb6aa3b76b85beb883a45029b4c34819bfd83c29881b7725efe79aa33c9a164523695a87cb12dba8de555d5943235ab4b53323381abe467cdc7d1634a6fe12bdf69e4147f82c284a508f83f573357f9083536845c01461e2c92a366a671f59d526f28b9c501e251b97511b97e2d0d047511e9289f2602745444745524f64c5e5ae9a24d3fe28d21625e1aa225bfd2544e33b79123b118def842cf110b3e7331def90a45308e8a7c9ef9a87f000f28063db65da1a3fe1b67d026452dccde280908026931eec444d9801555cfe6c81efec8709a75627de2fc59fa71f9d990f191f289cfca121291dbe3e393c95ae5254ba6e1f21f7a39990310e92f76fbabf9fe94c88172156b78e33215048211aa72b0ef4a2ebc63d17eb13cce220696d20cddd4c320379e4ec7ea8cf55272a5da57ab0f4d07a847a64ee3c2af85cb5bb6d8b8a9e8686663c347710c72304ce786218a72b810cb8672560d9d9d54a803234245502757712cc5430e08c842b900412623b60e88e961d7347a8ee50e98099e96471f075c59934d4a1e9f83818c40cc6370818f78b836cd141ac9e6a949a05f101edcf46d8427fbee16cd26b69b5e13ac216f029761a81e656b311e84c04323488085bdcc99a13e14a8424be4f1b4e575c4e2ccb1ac215a79a850025041d31bfee6de25f0c42997bda3e83b00504118425f16fe4794110c1fd73566a969345eeb4614aa576655977d14e2ed7b2eab2ac4745455463cd5bbcb68827ace1d9956595a23c479487f2508d354be5ceade96877dd3ac808fb7e6e8ff5be786deedadce76a7e36493b3e793f879bc4f1c9a2dbb5b95c542445f4a5794a9133fa644b9b0de38ba92c876f38fb600b904632d13ee8025eecf48100284949a6a50f3470af5fdbb93eee7e296adc3e4351f777e64116c739dcc483eab75aa37f719307b48ed5166a4be2f27740e6566b9f3bf0024ea1cd3ae0c186c57d71b689d78afb34ab3e9b9ff1a8b7d5dfcf788c1a1a92ca6f9aa778abb5d2d64dd6c7ed44511e273a5b676b1349317f152e4b9c49a6a1a1a25d7da2bad2fc5bd7dc8eb422f9bb7e9e7160e6cdc1925b5c157220fbd1a5b4fb9e347f15a6ba2c713641575cd4ecc795fb8f27077ff8fc70cf67cd86b7f08145876fa53e9e707ce663e643e6e0e7700f14cc7a607130e3cd44c11e4f396d6fc58d9f9bf5e031e3b1c58e927fe9e5c165c6430aac178f968ace78cc768c0177ed715b874b3cdbd105bc12b263c933e6d9212b6bf666cba7fb77748312b83b58c4447988acb05159492b5a3d7999c8fb66d40642b30d78cc749439673abee8c8e23a4cd2e2aa998e2707a7d074e8805368628e3576153f5b534911c94434cb719503cacde1e30e6a30e6739d6990c5c16d671ad0dcdd7bf0c5cd34e0e1387f15a959065dc68be9ae94a664491323310929844af2d4445c8a0a97442861138dde8a9b32b072cf656ccb6f56f90c96c05bae33319ceabaf53e31c5b708a7eb126ec6e59eb32be2cf6650dc67331dbfa7ac8d8d6fd18ed4538d4043ee97b76b6fd7ca74ce9bee2f0e330ee2f882e32ffe1cd6210e1f4ab5bd31a64677904b6f6c719fddc039589b66377860a719ce98190e1707e9ce679cd3a1bb5b8f663850dc431c1f0733a64052331c0767375daa4edb9bd5f8d2fd3bca43c31babaa939add20f152f7b699cd18b59d7e9bf116f7cce6c946675663e6479cd568c05d57a2cf59a9fb385dc645a1556ddad8e64d79eaae484536d1bc99b5d79165bd7d59da9afb6b6b6e46d3c57de7198de995e62987331aea1e2bb367b105cc62385b7336ef6a7e9ec574c8cff5cb7106dba2a776ea196c8b83ba8633186e06a3eebb5ba96e82cd5ebb6de65e5fdc1d3bcd5e5c1c24ff9566af2ce0ec05c5b7cd9274f692cd5c65be685716f7abc3b533ca6535734171b047d74e3d7309f9cc256b9599f9ac0586eea846bb5b4e80b468a7ee8a4479489ddaa96ba72ee2a92962a2ba52225d74fb5c7745fab70d0d49cd585b5cb3ae5850583eb97ec992815368649d7d6448b27e5eeee70f0bce8afbf5ec43e2e0149a38fba84ddcaf675e19f18bbbd7ce99a7c57ddb93cacc83019c42ab9d5ad4459447670adbae2d22998894b6987917dd3bcdfc8afbae46b59d396de642ee33e7519e29e3e0192ef975264c9db97277906a7b66c91dccd5f16be4191dd7f68c836d70a1641b58a0da30dddb40e20e92656d8387bb0ef2c406995a568d4d2736beb8bf8dcad8c0d1abc3e4be2716f2568a0da19badd18b755d83056b64e160c6bb9e7847792896b2bb1d1631511e29221b136c49d28a6b58adf15485b369d63568b6a6d58bf7b7d5ab51e68b7b396a712773d559393885266ef3c7b1aaf1a44608bba2ddbe2736fab7e5d7d8c4d9144f52cc78d77c8ebb8a39ac4fbcffb32d0634f718c8a80e4d030cb893c6965d8deed76958ed6b7369e8287199193096fc3c9a69c2cc684686371a5ea08145e392ee13f32025511d2ebf46f75943c304c9d755dc4643c71d6f1d2a3b630cb893b1adaab8af699b3b834bed8c2b7e06eecf5802cd28e3b527290f8d56d68da5cc0003565d0e9b9165ebcf3233a0b8833b66504a7eaede32ccb80e97466570b95fc655595a2a1d15520692b08cb2529db7fe4c77db92f6a4624b32c03878b3388af126430b59e225b2c43832cc9ecfa61119443425a7ff2c35869931beb8975534ffa9c6c8e2e239064e8f21e4beeb93a238460dc94435e225a4d5f93fdbf4ad96361848c1c0c9d7b9e77e9c94a565c03838454a1429f496d12255e6292ce35527c610623cb93b782db5569f3f478f28f81793364cd356b5894675c58921a3551762db65fa010a03cbd65f1586a9bf2a0c24ee61f0a87ac10b6ed7922f58c2bd6868488ac80a1bd5b2ace30b90b8e3b6d5bd80475956b14c05e38bbb8b6068a9b24f8aba823183835368e4ef138ba4ada6986db76b499cb37af2ab585df3d7fca2bb1fb9cc055d5c5bdc1577509ba10ba0b88337fab906d12e005bb085d36814b733d6d11650b5e0c9cb1d1d9a5be0a036ed68b76641095890c541f2b725731d6bfeca02d359d043660b77077327a92d252f1e5ff75813f66b5a33193257f9ab584d66c9ada5f9d889d2c749911961056068cdcff3f64d9e8cc3156871d7f9aec08ac4b915e05081142ab8e2e0e34d773cbbb2563776a2d556fd14293c51a45050053e0e565da8821b590a309002d33d054fee2099abaee64f41c639fa8519f04f2af69e94bc35f79be90b2fb86d3e49775f94a5fd020948bbb6e94bba6b130575b8a4181f7d21cb282803a2000c4e6fec84822e200a5c40810e68ab1ab7a9f94f45560a4aa120963b41175bf3536da14e8025db7a7402f3043cdc411dc67d0eebaf95f59a000a9ddfa4f7477dd2d726686282d7182eeea0105da90ef217d36876c736d12e36bab68946ffb5ceae667b927e8933cd78cc15a8a9ee891be9ad47b2314b94690c0fea45184eb4edb359b4ef8ff99f4a8cd39f715bb4aa39247daba9c5dc79c98b6ba2786daea8ac24598b8086e0742d4d262510aa620964eebeab64dcf38b98045f3e93600b09acdc5d24c1d38bbabf24d8afbb30239af5731760bad0d28555fe2e96bae0e1fe65ade6bfe55975cb8c008cfb08b4e4fcb627c57104563e02280e4ea19d23a05c98a917d7b8d862b4545c70294b9cf7e5e24a73b1742d171db88b65697163d1bed6ac4dff59cac8d6fc385db72ec26df39176e417e92656b58988ea9eb8a326b76bcd5317e97dada88b767488c6775234be13b3a888f2107d3e3536ad92ca7a5e261dde028a83fb9e1889893a6d2104d22d5c5bd229045b3c155408acf8ef6a47ac75a578e72cd541b6a558539eafb2e52bd121780a818e0641190777eea9431f045fdc1d04c11512d357c1d9168260090431777721e47fb6edfbb7e6f29b545b315b4889e1e2ee2ee674b0aca3bed5eac92b46480c8f30661c9c42b38501e3e0145a182e9fc36c5dcb8bb1a658873922fb8019777087fc2a5bca3e00c507761f28f2b953bf4e481615511e0f78d95afc8defae2259e4443a15116d6d97904f4a95f5af2d2fd3d2fd72684849fc7c9a9f71074220eb801607ad9e3c6fb696abda92dbeafee6d3a46107ae48b27680d6010ada2ade370443c6419e5d597521982de5be38ac76a834d0c936ba20059942cc8c80000000000063110030382c188e884452c96ce53c2a0f14800378b8648a5a1d4aa3284721841c22600c00000000000000300400a242a4947caf40a86d2d8a2043f4b6a65378d87ae6a6ab230be45da167914bc20d90f0fec128a4574c60adf3063630b74488254ef812e75ecd5d5912a184e0648dbd6c3a38acf26b630308eb6bd7a1b8759bb6511b2594fd8a19c0b0000519e059de9ac31adf358cecc69c2ca94390fedc361ae99846f4121ce68c205e49502cc3391f58f1866b308eb459f613e311ddc805947da5aba496b6ebf0a33843510343f446049aa4326a37e516b78a1e10e1b8d56f126b02e0f6f4502bde60d6db12fac33a28bb704ee5c358c1c79eb3122a76b7c3ac0a80f35006247bbf75d9d4d9ae60cf90a1b4e92da41532db3e92ec2e17e59c8793fd12b814dc5f8a4feb9cc241d3138a2d6b1d98a6751c58e8d83b211683f54b50a83abdd03487dab59ca6832611fe9253075d680fc6e530f061ae390ee16ed95e5c56b71c6679a68199ef410a3c22eff800bd26f830494dd13e1fb318e84a597c1b6294b06dedb353990559984e9193d908970d06274a08dff4b3464ff42814dd06f2e95a850daa3b049bb9f7cab7ed688643db4b160c5fb7c2aa475804f0dceebf899b725ca23c97c835c4ec81fc80a617131e0359ff1ec43518e74e4abfa25a798d169c63b71bea6a0876f326f9594ff3460bf10deb64836bb63b129802c076e7ba8e20dc3ec319378ef2e82fab4ab6a65f629b495bf8f5b25e37cfa1b639076c8f09dff532b8e291b1e173eca8fb1e39dab46ccd9c321f1a5771164460179178c07e4cfc10e26c471bab3b007186501b202e8305fcccc20c68da954a976833cd217396075c089c848db8ccd07f53bc1e67e884cdf247d3d8376877c427e14baaecd9b47b570099bef7a97a8b71f345d6ff6dedfd69608bac7a8e2e39a75c728ec1ac7a7b5efc062acc8db73a68901674e3b1c2303144902400b5ddae592808188c4b9385dc0e9797ed9e89cc7337c8e7149b71fd5caf1a93b1deace9cbebd8df990ec661348e112ce0dbfa729e605060520b4cfe2ac85043b846e8bf5f689bb61bcba1a6138773228c4269ad81d8021dd7e0c2a08b4cd02ec0e2616ccc1b135ccdd3e57f53455a5baa2de4132e39380223eb18fdb65e909703dfc183a6a49e9d9d17d0c8a3f7924b6d09db6e7630e4103bc24585a948edac13c5b658aefe7def5b4b30cacceee55be5d96d763a4f2ca8fc11c7b2fa04b0d8036d77af9742c5271643eaed4ba91c03b3f0ff203956c2c0465a52da89445dc7c5cf39524b200768bbade85da51570a4da5e690d1156f16eff5323b2821b40489d8796938ad50dd605b1b1c581101e228b80bf78aa31fb0903e1960bbd57fd23ae16558def81a29dd2a3f97988823fd9d93d8e05c0ea3c3766f895c62c05784c91dc311fd4c53d5887e521502c6a5257c3793f0aa6a0d0771afeb24396cc5976f2b0099b52dc96ea8fcb818efea56f1c79d3cae5460ba2ef5085613c2116857d801d376db11764f84c98af92aa703011998ef3e7d0e009d5c0a348a2cbba4c89f4d1fad04f9a916045dae11a1fd29dd72094e0134e4a8be219c8bb6fde59f12758f78cb5e5692595101858adf0b29f5b7206778829db3257231a5d5e6cc4becb375c5cd6fee1cb40d98f205830aeb4c90208cf9cd3d41296dfe3269a7ed43d9b47782c2d031e92e5711d4cd5fc05e1ad14bd89bd43c0540555f855e0ed25e486a8a13893485030163ca7033f2578413b7f4194dca3173e90073acb74d78c47a50a60bcb16a02c4820a57ee3455b62a77378bf4df520be0468ced6d5b26be746edbb78918095016c046dc3f54e77fd82da3269abee40bb2a9afce3831b2ba014604c479f35cc441aaff21a35f3a7a2150c2b2c2007cc1a69910bef48be35cc274f3a59168280125d3437ac4ec80d185d8629d809d330c900a9c0f6e4596ac0d679a9adeb286623429188955f92033952c5df7746cee6d628bc82a612f27937147092c34bd1c0d48aa52758e8eeebd70e4bab2964cf61dd364ad4c38b38817ad349b64bc2af5279c71dd3d1b8e8ffbe65eb6ca39c993c7ba4ae14d8a4dcb1126b26859ec199d9119bf2112890f40d19ec71aaa58251a71b934d590ed45259536a8ceaaf8b4bf1a4fedaa785bd60c635a6b1a6c2c3cb8db5c10eb98e5d8785ca2e84455b7b7e9eea30a9f7296be652b83a765f95b390d86124a8c9142fcdb0c3c12f07fcc2043bab2101317b31fe0e91348d0b770b41cd71cb5c5d9188fa588e9a58f38d1ddfa851a9077756ab35253721e84df476e823d661c2132f25ebafd9629be55ddfdb1e7f8be611865660fe2e7df10d065dd7618c1c5c930a783cee06adf3fa7d7f1baf84146f08548906291fb79e4266d61c78811dc5ade2fa391ce8699d45021ae73718489538dac4004aa9fec4dd61a323fdb1fd206539adeac18d501629c7e892bd82575f2a3c11f8703f0f08e63fa4c6c2e116b11e7dd3c56741022753ada8a238e3c54ac8cf1cf522107fc17c1b51fcddf69f0836fb89fdc09b948c152ffc88dabf6e876e2497655e9c4ebbcaba3d50a49cba5039dbb113eca4c5569501fd4f68b77157c65cef1949e3b9d6e1fb3c359024819fdf5975525d37963bff51d4e410386ec092f129a71c65929372d94f1a6ec5c61eff688db14718766861564693771c893cc7806c963914652c75265bb90cc146b0b63a37fa91b627a17bf5b14f93459ee97ff4f7bab8826ff5d3edc58ece21718bb3be5f5f608a60abd0b8e2019731c17422e6e0022f052c9487d9540e3ca6c37d560bee41a03887a871e40dad42a752b4eaebbb91367be22c87380f22b28f32a229d7e103d39c97a811d144ba498074752e13688fd97b1ca330f1e5d7b06f84362c1fc061a306b711008a1d081c5b786ff24192c106b857ab43c529df37559f7955acd45cf2fb50f54bdf6ebdfa4dac735e98957a5ada8b2bdbce8fd8a43595068f393a1f30486bf9156deb148575bcf944788b9aaaef8ae3a2cab9efba10e6c7d0ef63e15c0ec7d0cf72a7c91dc38bdee0b4f08641aed518815c0485f27fd12b920b7e8ac7658c52c84e32bcc9e6e6669458b63dd922588c0c0429805348d512a87112433df46891ffeef80cd400752384490554874fb10204f9e9b4c7d81b6ee5b1c3837047a3010da714faf243f281d1af4f3cd0a3f8ee0eca5842b4e7a2be32329b77a2db0e5db2da37e0fa71ca73f95987f3318ac78dd945b1e6a605ef2a71fb72bad2ea8491a4c0030b0342209cb98a6b1d32987752785fdaf9160d10eaf620f97cae3a7473f813cdf03255a9fae097840f7681973540fd70f951540b073d055282b06d4acf880c9106af8aec4b237ad23da49b8571ce976ad74f22303576cebbea854c77967f862cffc6a9e425b9d246652b0211d61c00ad1e7ee04a2656291f7f66669d1b66575703153459574cbbaff7393d7039e0f0f93d40234dfc850a84d597c1852271fb56a3e185dabd41971ebdab0d1a5d3006faa02545a3fc37ba23b5359cc672103a05bfe4adb3127747d2ba6dbb33269086b4a5e050024aa7b5bdfbc904eb13019e5ce306a8428701846e95ebe7dc17628953881340b5568b1cb43b6f89a6ad15c5afed95104643d886147181fed4dabcd61e1c7740c1ba0df2b435c78133a0c80f3ca024864cc57e03ec7404da9b63242eab11998c4aed9e061e48668539ad4d3dee42fc8e7444df14cc0365ae61983d48369e078a9cec5f8f7943959e37233584eacee5cb0612f41a7b36ab6dff11a5c061532a51c9dffd358addab4b8e482b19df67eae8f6c6c8d2b0dbf0330966a124fa037b000dcf857c0b169c9a6184be227ab0bc75601f66e6908ea428f4d6c30047074a031b7775eca8a30bf4bb8b33211ae16ed10afa6602435f94bc10105711f455d1e9c39ed9abd7ab2ff86d629566f38c1a9c4cae5ab1ddd6b041b7bee8dc75c53ac0e3bdd6cd5d68ac00f6ec0a561ba8888eedb9104f4bb7cd74e4293d9c2ecc8b9315f683e7bc1a26b8bcccd0d03554317677d41fe03ca55fe46006773f83f9aca88586beaa61197767873dbd7177f53b99fdfb957961bf7fa5da0aa61d18082791bf8e3d275b8e91f8d713bf7377d0905605cfecdffd9de5298f0e9fdf63af6c11a8430345f983e41df7ef66c22fdd39f7928ad88a1dc4f3d9390889835457781ccca3e0ca4790fa88cdc06b981686831e0b11d3f2ed1f6b1496be4de62b0398ae49c4944ef23072933b600461acaaabfa661a2638cb0692687a3ed1929758fc5e194c46224d742788c53d3025c8c1c987132e4614e8e841abad5cae229bcc6e83c0c3011d5d617ac89d63387b1ee49ff10853f1861389c51d8267d7b7835fe182a8697b2ba3203dd8daae61def1ab272dd3e5e083eb80c4c948132c03c87981af1cd2bb333fdc7c7e3eeb8758cc377458d2bafee040e6e9f72243571e4df6ae67ac3808bb458826bab29a030f9c08db6b220c5334729b7d3fa19595077af673fbf22da884789db79912f9be1771aed99666e34b0bb7203973093ba55ff2a76109cc623041f32b8bce392ebeec21f78231d93a6e8ececa2beb88c37fc33b9326559da768108b3c7d4463d404458cb8b179c1f1cd6cad1269bf6b1b78302a0035c2746ec9c2b84f1c0bcdda1b7a90f33c957db52d18a8881947e810f7733c16ea5dfa666ecf35f514eb71655a53561da5535dbcd786f13d81129ee297e7e13f9b57d818ccc2609b706f300efbd65e7b8d7cbdfaacb5f4ff0e25e64962ffc12e8ad326bbbabd8ad2440de7bc007b9d6846731ce81c74576f093ad6757b98b7fbcd0928270b6b46c9f06b073f8102c52853f4b665536e789bafe9f0b254e0cdc4b431eec6fe74e8f8766c635a775b0e55eeeccff9b77274e1c29070b43a2d1bf5cb1ca596b77772d0aa432bcbc6388e1bf43bbca732cd87b9d9d552e1a63c1f744b5da9a8002a705dec7b70e33d4dcdd8f45bbda411cc5dac33cb47d351f99830b3fbe39c01237652f69e9d0fb08f51a8a01128a0f4a0e4198d644147f4a409e0abb3a0db11550503d6a1a5ce7d034e89bcbbe8139f5ba4f32a7562bcfb4f3e7c9905c91f20fcf09bad8e7e0818e220c03ea3bc7d42b3ddec5caa3c8195aa034e466f2bd6b21e89c37949ad37e4c53f5c8e8060839dbb832a15ad2451bd88c9e3d5d669f0c9db6af0c5d27c002cba277174f82c914f9cadc28c33b03d47b04992f64c8a10b0e5c60c124eb171b00d2c4732c7519fdd920fac3e8d8c2b6f4000a9aed34add05a177be3f8c3e6944187178f29544741693a8ce49f3521e41b21d8e983d89046f60e0824651f4748e2649d701c1d7e736aa3b1a758bf6dd52e39c736c568895c92b18a602b2bd16c595de76a732372757d1be5904b8bf0b076067f30b3c1b7ce7d5dbaf272bde986229f34f57be5e1b441cf445b629adf841150e3c76418e2119321c0467506763dbe65d4f4f769f47593552050e74541aff423c1186959532ed21684eab88b69ba02a4bcc0e8f71df1dd1220675dfcb1758953b576e0deef09448359776d1a438745480f541290a86cc6456648ef86def693ae25c5ef9f28fcd1585b4d15530d86ba46b21f6e2db6f1f9241bad1ca091776364b80cd3c3d136e53c3d125112b7d0a227819ec31771f2f46ff874703d48329fbcbbf59142846ca62a808df258f56f08f3d449d4d4aedb12519f13ecf86ed2a6b2c3b8b9eb2223e0922d0d9933b53c2c4966eec2a3f3d3ce556fb95adcadb8b6d4e6e625bc33ffc195fb3f6be70bb3f7987cf2cea58d388ae4bc86eac3ce6321f06b47589364a996e240379e5e39481ff65aae11af122f17e7ac0dbe92c3156d1d52161ae418e7f2a64acf04a36449bb7b7003b3bd9ffbec2274cc14f5b466cf4833e4b19f43710601a118ce014c69edcad134a065077ae871340c61d6a7d47cd2f6f5aefc9a2c0d0b98a1bb5b257b11915fb0fdd9396279269c11867a848e97a6e9de433ed42110bd2974fbce69d7a55581109f2a1f9f4abcd300a53d59a726c8c7bab233ca6cae15bd4e268745437dd7cc8f1c2d1c868c50f20da96f1c5e47aa5991093fc29e409b57944f9fd391905f156e708a754305bc733ab84c6dcdd1e66d602b3107c07a40e4959ccf0407fc8cb919a63d3084f4c1e2a1e5cb733635f665ce434f20da115039d6c300add5cca807edb4b41dba7b877badde1c9b9c32d571e8dd8f875e7a14cfdf59a6d6ac3868d78cb63a9ffec218b23f3a87afec8d2821dedef07c93b0338a8c8d474741b7785baf0b496419b71e012f78fd822de46bbaa05d8efed91fc8fed3f90195413ec38f5121657486f57a86d636152d4720ba5a73f01adeea57f121c30d408529982182daa57b3a514c027c17f25af6dcd3cd6f0185370d72526f689b6f80f809d5da38a0de6471f6136753db13d63a4f9c7d1cb4aa9c99b3862c5c025cd12f3b409c60978f9f48d4c3079bdcfca93dd2568c3c381f8bf0c19d7aeb4dd943cc1c636ff0afbd3e6476c3f8ef026ef2f8a13f7a7fa54892bcfba608702c13a1bf4a0d9013f7a27e86d9adac116b4a59961d9935d9ebbad15d548e18f453dff263e4e27e3669d8d27e6fa980f5852161874f74d9ba83959a56112fc5f3df51cce1a90c0b211e10b5d65c860e130959c066089eccef095cf6167d39b4dfbf90b7bdc5bbfec34c0ada482cfdde98cd8d885114cdfdf1fac9488c781beaf892bbc8b1f50c9e66fb6c85b78c17a9aad0948d4ec112e1e72d920db1cc08640e10c9c9d7c8e1a276906a511cae32395f938fdc37038a2b9ba94e883f2f65a561fc24e080aacfb93594334cabcb3c5b2701ff148dcc017807f5822a5902eb68a53e19fe7095f5c79146e2d2d59d416a0e69a6e29c329e3da3e893b8c851352206d2c97c92388b93cd76e761ae9af4f83628544221c439e386baa3d4636c73064f501bf7733ab507265dc3038f40c2585c1e7de58d865bc35ce3c2ca7d79bcc3b7ed21a4204fef324bdd53061c47f908c527db3281ccefb06f1aaca3d0e0680096e05ae573d98cb0677e0bfb5ddb97fd09c66bd4a27b3cc2acd51f070480f228b79e8b9bb33fa55d0103f7543301dee3f0e9da248a7c544bdaebc253f435d7db3a2a468724e063714f7094cf9395d0bbb38163e7449b6f4110f2447f4f3650bb652327150a2f744c4a26cc48fb3f5512045bdc93d47482dd0a8bd0dce7a1a6d301ddbc98165881e068e059bb0402e80dc8ffbb264f36d700018011602214ef9099ee221c5cb15614a23904e33e58c2e71af7e7d8ba5589de18b8dd3318e244ed3e5c3ddf9384c341fbb0494f0b6f1dc91d39928ca0188bf8f570d4f3302bfa3c12d0e0738717689505cb4f116630be4f3df61b0fbfdd0ffb23f3b089a246c5c54a5317fea31e76edcc1ad7d4acc6046f2577b37d8ca36c78057d5ae76005f85317d41810d2fc2472ed8b0be076a17b2c8bbbb85e840cb108407fe464cf376d3a6ff154f6d09bb487026f4c64e896fa80a33685caae3c173b8acc32df56ac0dde4a92828fb2a297e1aad6d060e89f7a919b0e6e35843f6b334f760b0547649e06a1e7d66ea0cc25b429cd74d7789aa1f7dabdd2fe73c76e5883af0a43ce030d35711d89501a67f330c547fac623cbdf874df7396aa2832595ccb0e828639cbf006b8cedbe6d72dea9a83ee7499b41b73936b03040e117e601daadcb23909c0f9c594d8ad848ee7e9e12e0d6a0472584f645207ac025778e212d31e7ea41ef20e53526de45cdffe5344f494272811dea996e1fa15d711587a95d4c01f268527d51565b62985526682188db3064aac5fb520001ffbfcaf43123bdd1eb3fa1877ea3a4b57e0015e61d940dbc14427ad6947d331e2cc84cccd839b272eba7c8f2e5849afd1395190c634fd5ce501e52af7d2762f8eda94841ec9e644de3c17245438f212f46de4878d6a47c4b1707a140253a99de3ae24e7142fa825b4542ee9bbe07944055cd39800fbd73f98c39611fccc2c89a9975ca328858d57ea4da7dfac70f90bbe85852927ea01c991696012854d5817db5949a721e40603bfa642089c3a27ac885edb592b29d04cce8d4531bc108ed86036f166005896be32bf30721d1708010d637e86c6e18401d4515bf3d72009118fbd3a8d6f1b34875f87d39885b43317b46906ecdc5d82cd376ff18e79d23bf8c0480528d559b1ff825acad3fa56338be42ea7ef957ef5d50979aa42180976c018a85ebd14cb98c25f129a147518580ab1f67ce95edbd3a487933a539024526d54b35080dc851b0ec2da21110bbb66db5b9695b48baad9225f0c6fb40623cd8a4fc8bb2fe0d4ae854ebda765c1009bb0ced6ad4a4af517467144081a18cb01c1b24dda0c95be9e074182ff10517732e2bdc9be1552e2a509f02644d1e7033047aabb27fe79711c4ed05c01809cd931bf223c0d5e75c32e31464cdb312d00a40777f1ce170302e507b278eceb9f710f45b450a450dbcc6e283d552fea1c771aff5e06c532600a56e5c033990e752e48e4baf863b796591116bbed0def1e681c4e922bf3890fbce60df408df46626415d5bb3df03019c52b434726e31ade970cad7df969b360c21a987575a15b5e651ad366072a81b8be6b308c086a8d3c6d9e9bb707c8b201fa1bc5f117c2c0f8f82bb872d93c6d30eb7c1d6bcc209a5dda1de6f25323aac4baa2dbe13162319811d1705e3d7729f3e2f3e50ac6e1e44ef00ebdc9c953afc331a51ceb62027e89f82bc31c3fab9a0d6e9606463181e741844a940ddd0eeff499c43b83a5554b978349f790780c1651b33894ac840b96109afb7448a9612e6a16d6e5d521c8df41a063621ccedf6ca4a64485f858db658f074bee25a4d6f3e29a8434e5d8382da74427b05307b4ed882090466bb06cd5c2ff92167159b21beb201bea790465a267eec2c9cfa426629c7997ae8c0aff2b80064a519c7afa7d92c43ecf5197ee145a887571600db7691c5f56189232bc2269480802a6b3b1a48ed9aa17a3b8a9457738639e5c9e8dc34f4380f253803b9beb9a121a00c7dcaede2e876b22bca907107bc36ee30b867cf2517ab9e109bffaac8bee2bb2843032b01a0a6d3b5123f7c19cdf742fb7d3136a7e975771b522bd8a2ebf8b11a68eb023530b6fd5873e3a348be2b2f896ad0e370539579cf1578bac83ce79c50b59fa56364b3c7eaccbfd3010467254f526d8155a86057d6a13f0400f7b8ce5428b0affccd01107c514f9d0588423cc6c8d22aa64f04cf27a27bdcfa3ed2fe1eace28ce3216df3f4e650434553db643170df77e5392cd48ce4fdc94a21eb3b321358bf685bed0cd7b81d74a8da70ff699617767d7979ec5e36865682c73a5b683b7d0e827898033ef077df037a8bf4e4e824bfe90e4a147bd7ec4bc6926dd63e498fa46745a90e769b25dd7f66a466055046d127c08ec1566fcea300cff48e704ee09a466303ae4f2af9047b51cbda7516f6c0ac23bc5e289caaa3d649e8a4670632bcff035603b8ae04fc8741b62ee8361fec684e19c2fa8a240b283fe197358432648da5d3373ccc55f8c6e73b9177ac1c04470c65aad5ff96f2dc8335f1f8f9aeb9299b4e4a4ce64f276625947f3d18c24159b35b9955a5ed7e1ec62472bf1cb6854a46ab03cd57399162c5ec92c6da4bcd7e695432a7134f9b682dd8c78988a7019506121333fa12b6609100f476cd58d30a9c5f4f0eff726d2338c30aa08cfd3554deff7d3ecef41f470629101fa0ae97f54ecd8790cb9a1c125ab877da0c89c7b6082f1066ab46c464b1de83da9bd1c8a29fd582119d7b7d400a67165a607ac985b96471816518c44df2467f7961614316c38a54ea8e170f88d1ee2714ff3bf0247d6a03668e5669358f0f337edbfdabf52c06c624df51be78aff0dc46c06fe90bff90f32c1d7a569835c2ac33ed9ed3d7f382fe9087589f270f575c3ff0a2ee527dad7c21e08274d40ed3b77bba23909abf131929669321984cf33702e76b8375f68ad92314508aa7a595aed7dba1eb8a24fc8363ecd8b1286d422d19f7cd38c7938e5a693e421667163847cd32700c8f041c7997b247d45b35548791484a6bd7086ce7b6eeeb7a2e868a0700afefbd2f03fe2688f77505190ebf17a71f12a0969a82f3050ecfb6c9b20e116cdb65d199953d3d597aa66e76cab7ad4cb2873f5754d71bdb02ebbc44e97d2cc41829c5ad3d66dcc992671122fff43c905152448a7434b68e3e8d0c2a32a3f0e1a25dae6cbebf4f17e2318f788ddcc901be8c6cc31dc2c61ae7f1c22b79b2eb5fd7a191b7a63e5ae42fc328dac11e065ac87424ab73e0ae6cde0436bb82e8f6428ae809c2f97411f2595e3ee8dfe6605383c354c6d2e790f97701eab8cfd45faa4136a7ae37abdb04e4ac467fce8dad7284458de002e4fb324fabb8b114d9e6eb01b9b0a2dd07c622bd4035a8cce0ffec55a2a581d2917faacd81b15de5fb0e023738c26e539bfcc648884543fbf12bc81690c45cb0ca6255493297a1d922952ee5bbdd5b5087771e2bd87a13bbb8588efe1f586d97a10e1ac48ef5b4fe451a34c937e70b516dc4ddc43d537c4a653f8747eacc75f64f84dc7f9a64e6875234643119e182dbbf30468d9a24e37324084af9f5763b95039649e4081d3d43c90c95a2c36a0eb9669ca8b06c4720a7345be1140fb03ac95cea190ac984975dec607138d091c1f92bbce8b2d226c69e61b043c5a0a17eec7615922bef7dc068abf9dba04067dd9ad839d9505694adceceae320ef3cc92f6726cca5d250502f1c0ffd901adddb4eab0a965a253d4c99c695a0a5def568d49cfd1a3685bb80bb835577530a56894d0f30db48bc4beca12657833435783c6b4d0484f2b26f8c69bc9955830b8facfde87ca3771a03652500227f57d9333bf4fece04a1659c3e832c35e24b07059f20d7928e5e95013b67870c8f7ea94671c69e3c0cdda93c6fd28fa964890d130113c4f771e115ae0263d8a7dd3cd59ab82f9965a36c7480d74312d7fbcdc3a1772a8a72f0c1254cc9ba00d7bd0ded67e2e2e3c41fe5b9248992ce3f52d69a86f05218182d3f90184cab7f313ba984114db776136cf369e090501044c9daf8c131a9f79413e41c0b4a32e1251d94638ba54389035cc4ac2c4ea4363fc212bd797038139576c395525f7c1a9b878680eed45c687c8aaaea3b5c89f94e972f79198c4eca065c00aa2e6e51f5639317853d5d67fffce91edb6265a1efd9649c3e11ca76ecfc37f117cc43922d129a29d10e988eea9de6e40fc5c922d6524170ac23c5ccb687b5f0c0f9012028bc6dc0d6585c73d0be3906fd2eca7797b60c3ad3f96b2a2affe680e4a9ac8c25457062c11f3fa9e448fc1e69bea68c62951b922296f238077165aa99f50f424292069356eba6aa2b5f725c6130e8d3d040a4e9d51f7f535441cdbd195c8e8379c602291c50c86d4bc4c1f6b6b88696c534f9e9005da6da789c7528f5dd0f2984aa05d8a0d73bd6abe224d080c41e8d6fa150c2eb3322fad9a60fc38a928dd2d91c2fd7d38232628acae57ef00af9644a3e5f2ad37ecd5d0e8227f9afde36da36dcff574d3a662d464c76e4ce08d6f149fa21c4ce38463ed6f5d2510cada4f13bb847e0ece7de41c46a0e419c01275fa6c3bffa4559a3f8ae5a9a51a1d929c467c2c2f98bd1accbcce4899f3cb893471c299c95ef35b4d84b7b9c4d995880824df49977c711ec01fe7eec9cce08987ab829b428779bc54939ab9cfc931218dc8d8479cba05e4aae9feb0a2d43be5979a45f2dd46c0b5a841be90c74c7108802294f1d104489cfbe06856d4af3488eb80e33b48a6c096189abb6328fd0de0933bc3bc0a1c627fc15113081382790b2f1c59db9169195b4e184907b08016390c011bc4be5f45ae496dab5210e30a5b53667f496d9b9f595f803cd37bab23cb20a9c76c8173f67a1ef12fbe7b479959eeece5c7378dc4d5eaf3db731bb135e9783b1982f5a7c676a71f23064805eb09ed1ab79ad9e8fafa9ba5fc2e8b4ac1c25044b4f5b639ebb54a2152237c0cb5b156748f6d358869214ef9da89d2980776018c318527fd0566c1f205712fd0bbe1d75214bf867528079c5b603dac8f6aa00d2b4ed5bd9194b9d213cd4141c8427b7cb4fa55a48dacba6d580cd6622a5d0af88a1837efbfcdbc62e4d0385b6576dac1b6a0566262d0691dd2af6c71cf91cc60057a27fd2b9d420495dd55180b45c6d837aac4a4b4a33e230dbeac78e746795e187ba3384772bb979e63bd98ba0b9e854446ff6b8a60cf78a2650af325dfc19aac5d96a6f8df0fc475027c5baab491cbc6952172c4ac426e3bd4a46e7055d7c6d08ec22ea7a008ee2ebb05178188100d9f7754990745bb40a1deadd69595f6eb210087e423fdf104b2e486df6737d805fbf08a2b9862ef8753de4cdcf71b14e37464edf88e61f25d911d69d3c2c92065f9a3f641904ceb6ee2821484cbad6178f3a8678271fe6cad4afc18106c4cf1c609d116091131a2fd83076511e91faab225cae47e35af0f62b4c9f5a42e09da06cbe7daecff10da2d01e812ea8cdee8726213b3d2b67e2d956d7b37cc8a027047a2f18849379777987e02b18964b85565896c8c30da08d366feaadd48ffef809e492f090c5c3a0e44c030b91736ec19c4b5a217eab6854e709c84589dd995d770a359897ae1c47fe8f96df739cf7c275f16c9d643d7b0e1a5983f034fe1c550680b3a8598610cd89584b6882e21d28a389c7741741d66792d34d4b3b5bc7ec50b1bb762784b28f94ee7341cecf42c9d6f33e9813038598088a956f14d5ed10e43ef7e327a2968a9b629103952a45300117a261e1cffc2734382a0bcceef5092e767b13a1c935ddb236f191fe52547fc867d04b258f87a27a8eb2bfe3cfa91d19b208bcc5300364472f95b9c835b21ed891f3aeb827c55dd7829e64e0bee43ac06106a824e861e64943ba7b3c3c4636921811e5ce6ff44f74a8ed4844bb48a882e7abe0dc3ab7efd833c0496cd17178a91031030d778766df72af88ca75ab851d099c8deac514d87c3bbf2329a8bfb8e70e9b3be7eeedcc3b9c99737f344243beddad2ea823f69c577db5e7c74bfe922ed431870ad63a5b7739096d1b89d3c6e8e7f8c14cac4221f785162992e74ffead22b75498c2e406a2bf5b94461cd252f0285034622fbe7b80c44fe51e66015ebb263eb5e854990315095f9f6ccb2a980e43bf8a63b6e33a3c3c6654bf7abb9113bfb7f684c3e0f9066bd87c936c22d64e45e88e3f93d955d0193af801e7a5d156e3cf61e8ecfffd1a004553267e96d0cda0d4369a0e886f335979a755db742cb7dc01c0cee55adc85b9a773a915364889adf5ca82ba23984b34ddcb278218b90b1ceeae397c1297305ce932ad9ceaba2ad0401ed72958b64eb1053dd6eb04d836e10b82487940fd75194b491b6f16c74a570966cda157354347a39ee92d5b9a79995276389674903fc709c8f865115e5fe9516978d53eff389632e4bf49aaec5097423db3882381543da126a35acaed80f2d9dd51f36d5974e29734f29b34181c0166bd0e43c95d45cbebb743ddacf9d28be38e9a7ec2830bb613cd9e34d56569293aa183972a6bcd3f021261df9151103c869f90ca875caba1336783901cb2560159b0016c6552b934da25897afe619efd2656982933808106b07018174e3f3c1ef361db773e4c6694679831e29ca3dbb301834ce6d4d1f42a4af463ce245a0af0227d7c1c95ac60611ae0894963484e7b4b57c9d5680ff30d1424904922b6ddfd0fd4ea8fd9abba60b208ba44a3b1288be51600162f66396dc8938fe58053dfd130972d174d0eae726d252cb38a41b9424f99547363d00d548f1cc8a60033384ccdcdf74baddac3bef59f188c7b3a29a296319692d16d62a7f873faf974a903886505154c41e1bf8a2d0b9f21efab68ead8c1af60e8a3fa642cf25757cf1cf2ee1a32db8071788ee97714dc55b42adcd0f301fb3303e7dd8a2c99ecb480d004fe006cbd91059c124d55865760d0aa7226b1dfaf37f1b275b6455a17adb433ae2b22aecc9d6b403816dc58e1fb0563616b8f5acab03c3202c93ad2c20ffec73ee24cdd802ff3921ca8ebf47e457ac471576416e3b6791a11c62f659f61711bce0941502d32ff0d741211fd1ca45e472417a30b848f341332fba21cc02edbe467ce92ebb142c0182290fe5aebb030eee4ac3cf1c759148df6afa8a147bd79be701ca45c9339b7460c06cd3ea136f97403c12e2801512e90a020252e1518aa73b708c9190294a181d40d805854e1e9eb83735daf62cf915788c5313fd849094a02d4532d3a36c800a9ee504bd1ba4c36bc651386ac3109e3eb85e7cf4ce58c2951ade425647db4115c88cceab18b2dfff6e4a11c3cc358fbca4db9624fb3855e0037e736764da3cc183b1092f880d22030300b6d35afb6619393df9f8be098e1adbdb5480963234771918ac70ee52925570404e5306324044b28a713560a37ec7c0ecb32628ecdc809b3c2cf279e63aee920c8b73a60ed72161239d8dc6526bd9aeb4e1b0342e9d9df84d4bfbba94f68d4a326147c926005522cb1b34c2210730d58490de128d9b6057d27309a58ff01f308f47b927e81f10564d2d41b2cb02a8105f0d59dbae86e33811aa3dc5994ed06d838e9d94ad86224b7e810be2948c4f75eda32ca72d319217135d0f965aa8cca688a48c28ff5cd83c2a93507be2b7cf9f49f8940fba268e6b102a6050ec1e40e923c7e07a8e86d0ca54864af59af82e41d0469b84412517ef30f865f82cede49b95c2556dbf10f707e80cc42946aefe1a1826bc0fea3803e80ea318eb9d4ba567812963a11c3acf437b6aa4402e339136503059f9da027e26dd3268c8a941e130b7a009f36274a0747089cc7b3837748346a563c49e88ae4b0b363916d2b457e8f66e9e201b27cf8f2614c2ee88989a9c5c0cf264f7a6f663ee23d10af694ef40688b4526ddeb01674569a6830c60574a826e18b318accf052226b55bccaaf97f4713454efe5cf335e96e348cf05016c1cdf151f2ede23a2b9373c252ea1d94dad157f27e3a960a95144f11ee985bdc38e81e863ef15655b462d79c41e8d6406e4c31ced791e225c2f6b828bd61cfb4108e7a2c3838846284ed6aec879221c8c1de2f01c7334e229321c9119c54f90f0eaedcc6aabcaacb71d99e42f583b325f214f4f335a56150528a4cdb63e3f86494ae8c0ecbe3823ab4ea6e61a849e2fc22ce7abdc727d7423e56ea37982e82d03fa482993afd7d4e84fea21572654f4a04bdf44b83685486fe4438192527c49575243c8e4a271724868fc6e78a907be3ced294299323a8e85b00e5d9b3cc34fb60131cde12913b76814d278bc790cfd2d7af9d129ce9c71d285556781b01dc869afc7662fece00fd1aaf6887e5401546acc6c2e7cdd1eeca5543187c80475b950541f4566b9203d3e70e8f65cebc6de05b9fad8c679e355e65b24c978b1e415aaa50e74017056bde602ae463405ef017c98927bc0ea9963926bec0ebeb5740056275f820e9f039ea3e0ab8d93c510f20c919d5795ee7e040a3da355f179e277f01d8206f78f0ba2b01ff61114b6a8eaa4bfb78288479de3d60ce1acfaf06d9ca30ff99a02da5919175d42c4b00e1277a7da043aafdf231076bf88f56e0f8523c61370fc752848c514822dbe46397847e3bc889d5ca0725ec6336070bd396d2558ee88c48fb85deab6c31767ef76b5b2b96c6dc17bc7f7e87fd2916144957da36e1c7b79c142af2bd07b53ebb3931e66ed4372911c6dd10e87b8a3514bcb04920df5d69db9a262f4f3be6ef06c010902ddc24e922e6f16e3175fe7c2c11bb32b38fe8f8e2a66e6a311e593b1a1013a6af94757fc2daf6e2534c3eb4114685107e11f7510f5986a5095a605e908cb319733f2323585ae3743fda7583b692379a275b9223ad0b8a2246d72e31c337d621256761ea68283a198d2fde9d58746bda697b3d7ce8c09dbf11ca83f77f2ba66f7a3eb1740d28777dad1330a279c805b4df5187b953e1180856930a760e5b026731272950c1f3628250f459fc295a69a664dfdbb699865218c0fc817dd2373debe6730f539d4e3b045ea907774b71e15d062129aca8d6011b12ffbf4ca3ecfed836037cf7bd0b55a9cb1bea5421d497be5a7222d992cbc4372b0b701b9c9750ac4f2ca4d5517722340a74337117afda1241ba760ea0c97f547fc07a29b235fc62d11e2727aede2fdd7b5121c4a2d43f13bfcae8ad2e3ca718e6c89c9807eba3013d1f94444eed820a52f530b75a71871dea862413a874e153c48fc1e99c0ff2aa1d463acfc9c2f19d70fd60d0f964f732cdf16a2917bec27d67a195bff9039f825834f4663f87427059bba2a81f656cfa692549e30330af31896b31d752e387958dc5f0c6befc665c94f69211eb33e5e878de96d5950f30981212e84cccf0df376bb9e5959ab332ecd8a549f019b51dc946a6c692db92c1ed4f6f59dfa0a95a1c3eee808258c9a370b940d1509b8fb490c8717f3abf3e2327c10bec8b33da0bed31458c8a8919db0be2b7628380272388a3e4961d52dd6daeeceb50e5ab49f79d401129fcd51735ace8ef3712a30f3a19a602ee00c53bf558488e0dfc84ca3d67437c516ca60dd5f64fc957cf4120efa6320c09e669cdcde41ada747e33e5cb00eb3bb602cdee9cdd735d64b61f1a16ffd49533e80093aa169e64b9733213906d70dc97cb0f435fc78cf5dd71413125e9f05c85312ac2ff33361b65675e3c5f5da1112dccbdc682880a43b2eb1ea5d8730ac208dc74f1745b1fe72944a88554617c123ddd8e25aa123f8e65e0bc16f53fc330edc1dd5a01f7793fc5601873bcb6a92b7e01c832ac4fafc3255b36a02a664679b90eddcddb9918586fb70b17314324dbe23ad371e754d8d935c3bbad892da3101e5a62c51ca5bd493861ad6da8f13956f4bbf424cc0ed0b1b3e7581d58a358e8281c4f1e28502fe5c1af35ce6525fbed66002e77dd342f30ea7b2343b75b117f9d6d4c0cbc110b7cceafa3cb90edc12105b8e023605938feb2813bdcb7c736c8bc3127ebc0de5ebe2bdf30f779736a5a4742bf411c9a1db1e0941969b86ee9b7d2491ab3692721052cfb16644bd81214e6b465d60253867594717509a5eb4a5bbcb8a2898ee3258dd7ba33d52121bf43e59a0d35d22936196cc87b80d1377e8c4d02b2e25b008b75a16ad1cc1bdd24d06cdeae2b3efc76b99e521bbf35398b2e21293ced4e8e969246fd20eaf330b0a8ce2988ef38ef80ef4bb6b7e6adc66754e1b285500999db0b0b64d1897ab707c9fb89900204e8c7e226059cd4b99cbbbc020770c658a2aeb3a44d22bc8b9ca37fe146602969c920f0b78e868b2c94dda81a1cf51c2dfae09cb67f4f59aceeaaa0959ac4be298a1c30453414effdf7c4895fab5caa1fc3b50481bba2156e3c4642dcc3a1056f778a20c998cd591ab57122b479ae389be45773e751278921b0c7a03847c0caedb9cba9a9b6297b45d510a3eec3699c6408e01bc262b26064006117e49c0f58def19f1e188c7873c53794e8d7cba6777961623dcab408f867913a8922cb26eaf57164a331146c3ce0bac416147a7513eed2eae34a4b1b89cace63d80fda90d5b3f284bd815f413cd25e28dee664af2d4a5cac71b7a7da49bfb04c253e8513faab650a1a58b1da293a9e897fd17a47bcbeb27db8c47ea902a183aae8369b54f03e9fdf256beccc0b6cba865ee98a0492254372aea82ab2221eea99315126cf4a7ccde232f082138acd0904eede0da47744098aef5087f58a5425d282da84aa3d90ed42545d11e04deb04418e1d4ceb933a34391fd670ef0c4ac8e192474b8a1874065f2b69ac49e8a4e51bbee100a3de1042dc68e1d6f7acffab1f6230c00ae7b255aab618880d1723361dd06598192d3dcfc46159b534847bc26a24688d30be649f786194a4bc8e425645a391ed6ea89d6e30469d984d62d85e29d2e8d5a4e3ef868f19db23eeb1c678dc1d7899d5d3669c7654c773348629d3817c3dade0e83b45aad581b092bbd62d1af6823738671a88446fec433fd51cf27c5dc89d2b063a4d399675e44856d76ee420c449b8587eb36364c02883a41176805bbc39c4e519e001f59a03f922df212a7550e2dd89a3b6d726679230f47d71b14f5b8b381d8cd36eddf3cda3418bf63985de4bbd896a6cfe27865a2002961353c74884d9c4be605e615759252879e3ba4583dbc00f643314fd3c07263373aa5c5429a1da3d3c5e0e779bd53dae9fa0de2002b1665a45d025035858ff6ea8218db969b6f560a833b42c36ec262397da4874919b4f4e395430aa28eedadf89659ed3e9761d0ee88010d7f626755a9d4e20cda396c6e1561663866b149415466514dd2a745824f6d8cab0b93869becc77cdeeb4ed8e51cf9d381edd83ac9ec7799f97f795acd7fc22a75ea6cc05ee46bc1cc6a39107be14725f65d172ebd6ab6963322117014e1edd882f5dce6f712c1e19dad33d791301148b90b91eaa0974c2a33ebe81ea38edbb259cefc228e8984fbfaadaef2368e7de99e35203fd36bf0ad0f75459d36cfe567b689d445bf4f152c75f1cf05b08b1c366b5b6e4e2297d88fd0f733dd030e2e0e31a30e821ca757d931528ffea8b389bff0f4a2f08d895422432099b71a61c42da13b5fcfb4fbceb3f940d907c835118b098ec265650db5f72965172672572da07254ed35983b01406deb4eb085231dcdfc90532b337e27f8ad4533e897177163fa341754b14925fd85370e10f009109eea04c1be8a4b23dda5f3e04121eb01dfd084285a569f8ea1222adee759bb0b02b09bffd8cec14436ea6400651d268f3ddc0ae7a8da36812900d8c9a16cc38c74faecc00ea4d04bcca9585099cbd663aee4f43bf37bdee31be7425517142b55a02b6fdca888e8b744d2c986bbdb426df3e33a42bcb3d73a056ed6e22cae8beb1b44153c0d4024038a57f97fbcd30c97ac01460f1e62f06e0803ad2a9e2ddd5646846697f252dc3ea73443b7a29ad0fd9c5814d30d9093827e8d9cc77563501f92631860157a197dc10d1e882067480a2eabd7c0eb79d5dad9cd8b2e281e2d55b929c8bcecbd16a78bcaacb0c2427de57469dbafea49ee20d4b529bc233ece2212efb76e5fc8b390cb487c46ef0204becc0bfd137b921a8619e9e2708dbd1b639f25b3da5b459356e8163ef550185d04c85f56a484977e39ed6ebd5de52a1dd2568acdbf2f9622915bb58cfe554c8500cc899b67dc916145acddebbf0dbb0b28d2eed199b9dea1ae89a7f2d1ec2a22b5f3facc8fb5eb81b6edfcb4c56e006ac743a31aacdfa9226005486188f45cffc5f9ba0d8fcb2716f51d130bc7d58109b7532d1f29afa0eb121d3f66fb713b901a59bcbc9ce7d0ccc520757613afa0ad043fdab712d09de8890edc0b43ca877b74400f08f0bdbf46521b84cfa52c644540a8a456484551e57422eda13c20e8847ab16da37bf52d49a71dcbe98c9bf6de9c085ac9b0e757a7c0510c4a956a6857b27237fdb7b68b96a26ca7ba9f8ae4197f0dabf41b6d4a3bcbd2178fd375ba250e216d703bef9b2225a7de448a87d6733bb2544c2b13ac4f64b0657ac69877c1e99ae01506aabfb90e830a02856e0145d94e55942110507e66faec8b8e77d5d7fcef048c87170f1d0267b889c7e085069214cffbf162c368c3651160b7e2298ace8cd6125f863a1bd28483136916e7cd36df4f22b1c952fef94317d6203acb6b055921b4cad80a04b4b39aab73de349f2e343ff0fe3ce6ea7d5d34bd5f87abcb45f15788cfbf5f957c38fd5e9d53d07cc48d0050f68c87c7ad62be9dccc4a7217370e32f1cb011d8dc7e7e0708fa1d80bc1b8bed3c4258e6d7629f1f707c16602ebf490da0bafd276b4d4d293fe3da73a247da58eb765c06bea946c7f3062835af06fab6e3cb853a1a724862bbc1b3e3e8385c413a71ea79d565e57cf85c43960fd7b5e80ab787fcf90b87372e5d62b44289b16e9ddc3981ead2b504b0eede61d888ad63b474273ae84b435557ffb7bd8e8291ef8b5674e719795c2c165f7d5e0c8e0f448a3eec77d2b4e1af0d281477fb4b7ea40faa1abda0fc9d4ff2033956ace05ff23dbfdcbd2839459fdabfa65b813ccadf80d04cd41f02fdec3ad058d2e0b3a303edcdf09c06f5510d4fe4ab615768ce84593fe0c9bb50efd45079bd9f0f148eb407ed208fdb96c5d7efa83928200cc8d0186515475af7cac5f2432dc9e42586eb34c29a61f8be6f4e957247e7d5d066f7c9019df3fd1386b300f54684f04f398431dbf532cb2cf7572c46161af3ff749880c047b207dc637ad2f8ecfdde8655adb922d0ff6362ad9598885d6bf9383a146b7b0659a12e1fc2789077015bd9e6b06dee2b64d4e3de5241ef990d23d45113602cdee3dcd247aa12e707c3ccf2377618317e54793546dac4938d56d40d57040b6e9b97d033860d010a1e6e26888fc6ddde77ab90ea14592b5fe7bce8bc00333a2427416d1981294b448185b19fd6c25355b5da16ebb4d02c3137b642c06f4ac2cbf473f2e0cc01448ab54477378e8955097f922ad30e019ac68dce94b292653ed98c78d9b4f1cf4b8431807c383f618555ca30e6782c84792354b584d188a269f0f993072b3e28a85e99a94335cc3a22540c85737be5a64e4e37f6ea09512027026a6a0aecb7b7c8a8a60df33ccc8dedec59e37d0b0beda473399431ce44179f1f2c1a3a04c4b7647f319499997b7bd3ffe3dd7dc7d9aa8241fc0a5b9dc48aa17ad7636e3647e2cb1b0e88831af7628b8f801bc8542bb4f1d7d55bd2efc6311ba22f2d4ed698272f6e480d510de988af7d41cc9cc2638926c4493eb97ad00909f68019b4ca84accfbfe3da88e6e497752ca73f884e788929d2aa8eeb84f564e14b82840ae9aa31634426fbe0272993523d87def0e84ce78bfddb93c10b0fa3c711999c7e4554489081840a2c62d9ac6303a7042d19c789de08ecc177d3e7cfcb72383a6dde326f3ea0c0c630689ee92ae330290d804497476f247a1d814958189e0e64be4a24d39731edd5526f4152bf824645b346193d13b93326096031a1d4b017b748a84c4fd9a69e1a112e2bfc0fb8096e95b4683b4ab170aeae100da16c1771685cef83aab16e146314d0336789a4360a5b48caafa334c03d7d8f7aa87c2997f05bbc89fdecc15ddc72a234cceef4907afa47d8778e7eceea02f5391b0406d0da1e1e01c4f3734e7e2fc9460aca5d74f80231d085617c5532da837739edc466179e83e5d0c002809de60445b0baee519f5c24a9b432fc2cc3e0b973937cdd212201d7a183bfc18f1bc67d6d5d17df556cbb0fb6861aeca3aee47008787690b49ea0dbe8002794f3b1094bb3ef49770ed30bccff559b203f8004d6c0c17b0463e6cec3993308dbba86b3a0d3f372f9d64a82ec43d80a64c9d4ca62cd45cfa993078a8ce4377045b230efe08dc56e4d0cbb368d1cc949830ea4588cc70a515177f971e0651e3c9122721c8b45c3523689cefd596ede9ef96a9fa2c2587eef3f5736183dd54c9af715ed9670a5ae52648d9ff6fe3f967048deaf9ae753cf833505bf75a801b1295196497af7f0fb8279bf24bf2c7dd7384ec07c046e92cfc36ea977fab76e0e31af4e94fd0857539119d803c972539a9ff31f50d612ab05f53ee3f906a11acb6e60d317deae612c093dcf25a3f02a422e2c290d19151a23cfde1e4b81f641e862c6ed4b15f3e43311d5cfe06f602938e2f46ad6b777bba3c779faea3d3e6e848775447f705776505459caa375ce1bfaa8cb18bc3fbde60ed201ef1a3bcfd5f3a43389f6dbe4d21201cd36565687b58fc34b32dae63937a74eecdd992280e64121740fff2af329c0c2e1f3b6fe0e1ca57f702693cd648a97156de10cada7503f357b61c968885901bd28eb86b081b77fa06db3a4889f60cc5a70c999fbf65b8b83b6601c0bbe3396d066f64486a73940a80c6866b18fee7f1df150404e844feb81d97e049232a5924fda17dddc80bfc8419e013709d000d6d7e883d274e183b5bb387ad8d3c35b95f1c92ab88981721b293c1378cecdb66b9d48748a406536f3079d5cb18e8f235cfac76a24e343f887dbe86c822807ace21248a18249b3fef24f18f512e8305f0c1a3bbc99fa8fc700b3b8fe9506ffc297c5ac1895bc16f223792a65ac2f967c33442043be3e45b90d3554c9d1c869ad9b1803999cb4c5e8909e2c95bd470bf44386e30563b3a717d8479da5d58978ca69ab6b2e1a3b571cbc742e56a7537a362903f0c84084cccf21520c3ec2c0d9c0753cfea016949590c1b9d5905636bb8de491165a4a6513a9a8d46901e8891ab0cb4768112ff3924533ad668da529db82c6e8b9b9edc9680ea0a0a4e0aaacb061f6032a65271ec0c8809c2a3f079cf28591676b7fc0cd356d288506694e4bf23af36b3f7af56235760aa0c472cf29c7fcee13d8625f863abbcc19f5d62a380bb1ca5c1e4bb60cff0851ec70ae7489fd2aba2a7bf35e75a51e22431506b1435935d9d2ec66a501905a55fed91f565a57ea493a67248a18a42a82a863c13c073be2648021cf6320ba5372acd7a2b1ad3c50c066071771f567b4941b2c5a083b898d16cf14a30cab65c44cfed3109c39fd631645c12c7b0b910e429ca208c6d0ad62db2f154fe5c305dca40ed10b86fa4a027f79260836d5ff40865ece59a47a1b271b3d31653a507f994c22b98776923c7f7b3cfcfd0c1bce62a8426c5a5947e7045e03377882b46fa1900003ea83623a1977e967a620cde641a44d8599946b9b7295684f2eaeb999dd86f768b197e7259e5fec96b0537c33f76918afee021f745c7e40fdf8c00bbf327c818aec16635e7bdc74c940a18ddf5eba21e2432f1b2053aca67f7270d3253dbd3154d36a695acf01cfcc4ccbf8e20e4480656fad058d3acef84893da18304a06843d0cf67407fa26e3e7b0497ea9d13dad8c39e00e97f2a6b08830309645b2e1514a37e3cb1456219b92283731d90cafcc76f38d0dc0bb8a20285a36634a398bee59f7ee0f24d0b7bb59d7e45c501d5d8d087ce062c9d53415023230141d2e50fbe5b15429bb671028dc5e44b04110e32b513bf6d21fe709e156861644d6b690b50cb3b9cc0c9cea2d952ae83bb8bfa5e25a564a925cd9370f982b81a95ea1faa664724ddf5b2a10b12baae6a9e607db94ef14d8dabf09bd25dda02d8f70f9695d5a9d425ba86e0c07302ac1a898a33482720f469a361d0d53f94b38126046de1ffa0468c5f75785fd5d2205fbe44fd03d676269bf45c60950466008b7b5509d2128b6326ab59822c6fcb14dc0eeed561fbd874105e3a15d99c19c60b6483f3e17bfc5f49c76df76f44312a6667f97336a274b94ba5413439641ad4a51d03ffff8b9d2e6e5f6a87eab334ac39ff2f93d5aec0438d738fd2494910dea42ac86d8108a1d9a4c17c09cb38e9a43b7f2d81a5550d6497d98f30085c34d6da797a27715e2bf1376ec88b75d77d4505cdf63bdc778769c3cabb1241f0d14e1d2ad03e47c9ac58a29680d5cf18bb1cb39e6e84f54d53c534a91e6710104e83c8e32aec7a36e1dc315fc1d6a211ec7bc05b102f00f1e09093e0f867279ac681d942a7328c8777f78da8087ff8c554ee7ab2cad3a9e4723c2a7980393c56763654e6cc2f16f3a4ee9316da8f89a3d3be684d5932bd2aca276c1e75bbcbf45495e0b2b804e2f401ce208e04ffb9e8c02977ea7c8891d39328a911fe7fe275488583409f3cf3dc7d61f3ce71c27ecb0c2391a6eada10b586ef62fdc2904a3104ca31c44e001242986753270bc272998a8b202240ba66d6191cf1f6728100e69f614e2368fff58a77d1a809814b7bb395d929b0c0e79d699c84d050c9d64645d4d17f8aba0ecc14b70e4f5138fa90a5c886ba6a480a09e27d1d4e5bf5a7017dabb55d3c866b1241ebb140acc2fa34bad6741e5f2d56547b50652f82a00353133ca212a226646bb101e19fe13034c8c9c49ea8e6f69382d1b189b2e4f44573101775c87d8162a83f469e2f89c775c9d453ecee8462d217340e52b8d91eb26506be5c4cc33427e9a171c1fce97a81a05354b624eba5ddf1dd82e63df02a47113a95406f255058648796bcf8545852ba3bd2b8c2223c14ab5577f3db246df63520c9c7a5965db840bac925f4a1cc0c4e26b36691c1151c23cc336bf6ef6befe89b6cc4588e3615016070ba1eb623ec36d86186c15bbab76745933d5fa518309273aa6f91ea085ccca37b30e3540d4a8d59551cb4994d168ab4b4ff39f45cf6f186c8f0037961629039ba116e4a0a670f116f63d935d9892e62024ca8c176d5516b19840a6f1427aa2199ed02ce5514a50546caf52c3a17e0815d733aa865ca639d504160151e2319b0c089fd90225256e9896db769a38fda1e70e5d03518515a0ea62d2e3dab44990326e97c932308b558cb346bfaf11a1fa4fbd1427e2a0b80c1bb55df25a64dfa14fb35f8bc619c05bc8d4bc26ae001d2c7a979d29a22cab54b4fa45601e0dffb2abd33db10e11b0563e45c1738cc476cf919b0e71237b208a4f5fbb470d2c4efc46e8d6d835c825f98f9fb8b4a52979be2e6d4a8222a63191ec2fdaf2bc82e1c40a7a2ed45409710fb1cff0e105369cc45ec8da3cc560a43929817d2318677601c1df1f357996d84cb2bf86e1e2aafffd8af0f6d6782004df50ac7816b622eba8aabeb4fe84c5c20ed224e714ccf16a3eb66a4751c86b0a47afb1d21a8da7b2ee99c9c164844f864615f544473ef6e447e00dc02074cae6f1fb85e917bc1550b1d6923a863159c4481b11dcde8b7e8b46049f8ba06585d2f1d3e359e23e423628d436b724a219ac6b7740cf68c8bcc68486bb6600a17ada64b40b77400747c72731b21b507e541d4a5ba1f3b568ccb83bf22c08b574f44e3c5c8b5511747484c6e9c78ac8333f40bc8b8d9cc5e6e6f7b6d321ff6dd8df1fe260512d2317f4c60f7e53dda03ea34e853d35d11fa790685c43579e5cfcf3d5fffec32944528304a57a7fbb5cb41f4acb45008c820e4810f8e42c8cde08546864ff70dc28525c0132bf0e5e90802d52d1c6f3650970a2dc8ab215d9b21b4dfcf365eefef1860d49311ab79a32c594523da38bc4bcf74ec3dc84c2b0ec64b99c844a8bf3e74905058fe3bce47662324f6554beb7fd972339579e9e486d41bda46e9f8795dde061c33f27629cedf19453e93c3f0d47103159ee3265c97009c2d352774b7d64b08b4222c75cd98c23c1f0375dbc8abadb85db45e90b44170d9b9013788e24da7f5679781dff25580dcc270f3f626396f4a9189ac0c44228518bf7ea5163ee94d64f19fd3c0079dcf1b4a9cf8937bf9bfa045ec58bb19e797223b2b0ebcd0de8a13db8baf85c7ac381a3f4601788091cc02d3efbdc368703bd4699e8321d9afc856cb726cfb0eb772bdce207c670ee33e042a47495e0ac5d50a756a4c4f08a129d3b5c8a3436434282f56cd709d538f5476400fbfaff7aa3dafb88a701adbb8035a1ea708a20fb91ce50bcd3eec491f525a208fc3ae228bea8101d6692acc59fae5a5b8107b280f5e478d9b3513a20917fa55cf98eded6f87ba318f9bf85a1c79b876e4853f137d558df1cd1c22b49d74c1b2f2f914ebee663b6fd81b99cff5f75fb1edfb3e4d13f22ed908eb05a452ef843d4ed1e3d5a21fdb03834180a7012d5562675d0969f6443c89a82fdb0a3f04790590a64f80e2f1d3346c0e61a2c2e5ed18405ca9b47fe97873a3b711a7f3df9f353200c360473efc44f0cedbc39e33e355c17f0a251db80f1d2b1c8e33bb6c82bf77fe08cdcb1319c61613d6207cad9ef33c5a86d1c49bc457b23a7cb99504de500aafc96c5ec763975cbbf71f22d70aa91ad9a380a7adb09af91c130431caca822e61b378327127ae608342aebf332ddf46dd7924e8120de5549302a88b28ba5c7018435ae2301fa26a337c2be264bcb4c8e1b52a13f6781d1af4a1a7479f72735051a9f4ef6bf4dcc15eef415f54ae51c7b90ac407e41246c2f397f2bbe145a5bbcc583ea7ede083133c58bb3aff714f9bf87f61a8e12cdda3fc332842152bb27989a861d2cf2521b4fde1cd99ab8ccad8d174d820af65d891ed20d7be929426954b34822375bd3fba301df18c20de448b941c905ce3f82455912aa9e1bf22d312c8042ef4b70a6e838a39563c7be9100a9f0d4e2d1b36743fe095958a8797a8fd7cc16c3c70e495cdbdf7148855606a6093f4cc2ff9eb01d794a4fa18be3b2e89c8abbc03b6155240df7da90e1c07241677b93cf99fd6555158d0a141e55eeb069f10e5d59df958e068c900b578b7c1548d006dfd7fd41338d552953fef4251d16315dbb263d94543238866a7d40914f4c3f1f6042ca873a12311bf085af687f3aed3e7d424dfc326c7de03eb4c0a1d6b940af7b6d16f98ff20c519f153566fd6c861bddc2e6f1623c4388a8a44540e5c8a1d967ebddc48b2043b05bd0e36febb3d11d5888788c309e0342a0819074f5334a173900643d981f88f94e398aba5baed4a04f40aad0f9868586101f029f877c0579dee1ae3144736adc8a6f234367927a0d204bebe635d6a1f9e9d52fe22186ad3b76e630bc25c20f3b77c9751c15f0c3814d89ab4bccf251aacb9139f593012adc33051001627850343cd59faf8f1fbf9e85493819ab00cac570ad0c2f96ebbc2c2f4425f8cfe557e5b79ff7d009e3f1ab33c85ff339df81000a069a6d8577400cff24e9a9e1bb5b16f766c35dd29b696170e6275009c5b5aa909854eb0b4710b6143a042e97739489e85a8b12e095099f8de4b8d4d313bd9446c9de7395c061667ee38db84893c42bd069ff0daf9fa60d0a3354470f134690de3c4ed6716560ccb1a54bfc5dbc22704382a71cc780931f003b3ff0f831ab90cae3df53aab74bcdc34a81e096cc77b999f26a89c9bcfae34bec3bcf82f106b3800816d71a505dddf4fcd292ce1f1930cc4628782126d1d978f021e8938c272eac58bc14bec433599b08f31b822c1e861c9164f55a542eb3f72dec663804d8b72d319d996d1dbc60d5adf1fa17c3b94d66e5c7e785d333dc50b67f140d80b03f09e3b2ae5510d886d921095d452303c10dde3ced1acf1caf4ffd1abdbf73988c9ef02f763668be456bf264c4baa31f71b3e90af68ef48f011d0c837b8a76a8d530b7fe7e8d976bd0e792c0f4c8aa4ddb9416f784ebbcdac29032d7abe53f518dc3d91ee5f7902b34279e024ba217d2bc50a221b80d688e9ba46f687baa3af81014982febf10c8d74125c1fe9f08e69ba092c0ffba7ff15b8632747b2be242adb5564922241399773c582e4d0a4b6b6e45ac9e1a6eef35ec242e6eeb61c21cdb5afd57db25b4fedc284cc4b7cbdba672edaec3385233c5562531f1d0603b9ee6f3cc41c63258cf82b66530852b091d7c0db9a87cc9aba6566216a25d86cffda409959403c3847a46d8a362edd027791e638dcb029cd7a8c215fe37947096aef7c4ce2027d6b38c18a46d1d35bb6ba7bc5e44139ea3ebacf8fe165751acd56a2e9eefa6cf91801175009326a425ef5f1926a74f5f21d0aec18da731af88468688b44c53940ef4002489942b3f749188202aa001134d29d036c12a73c4b55f1e510a11338231006af54c30e7e8b25bc6a79a10f440fd33653bbc088731341793cbf5e37613898ebef9954720a64bffaf80d4345459973fa17465ffdac8242735076e4d32f54df4bd8ff5a5185b2bfe816005d0128e7d56df331472a28b57b7d7a4ea34e8c7bcd1f8c6c0bc10e8cf55daf18f6057bf72a526f8b0b7ea44a379ab1f73d84c0d77c89f1f204bc522bc8d270e33564989d10b328548ac300134417592b43f7316dabf67095dc58cd04ee0b130c5a77fc883e9e61f589607041dba73b95f12258aaef57f2214f4f24b10cbc7b4014685039fdf0e9981f0c55a9be17fe0f38600b6dc10c43f1aabbcef496371d26c4cfee742f691c64f623d52b6ccff4c1624269ce90217ced070910fd622b99f6dc10c8f3a97bf48f7ba644fb75fd776fe35a6b443b92f38c54092333e97024574d2117b328db0081ea86edf7728665e7a99eafb8ac3b9207e6a5f3eeffbc0324e11e7dabec72c562f5591063759933adf605ec38e0423a29a0ecb3385fd16254784698c592f97dbb8c4149204a7ac2fe01cb2dcd4a9861ce26e08abc687b3198131340a5e5ced197b3fdf00435be8340761348755d163e3681ef677ce3a9294079a5741243b97d36589fc68ab0f8aa9d003d48f5f2004c3978bac354d0cd0d54128c9d5c058f27bc42b061f5f524876bce06560b1278b2637ec19074f7862fbcb7d1e36ba69a64c72468581a25828d147e1d3b462181a8e4f1bbed503a25776f75ffe3be1956d71d33e8fb6c4f35874fbf1fca64217e291b175feade3d73c7bd514b07ca01d7d6142247ac50e0ac2a5967eae5106fc41bd928b5ea5ce204cdf35048966796229aaa27c14f24ce734c240ebb57fb52abb78d7ab41a22078c00004ca3f08b780cce231cf247edd0d5697e4146207d435c618531c709f507558370e1601c551fec6db80babfecf4c05c4e2c80cf69dab7b2fbc74a3f6ae0eb04eaff9f1f91de33e597c0be454b3684b3ef7dbdac4d2eda8b27f024fc768bbf398f7093a39ff2db919ef43bff0bf53f8d8e4c421e702f3a00a37869b3fb3f4dff397c7900a47edcafad53432f3415176eb7a0befc1cec5bea220ad87ee866e0390a1b64cb6cdd63829c88bf5eed58ff130332b37aadc9158ebf166e5cd80c2c3e2ab79060a7fa2db7eb10b3defafafaab70047014952a48ef508fd47ef779ee0a5f915644bc8ac667f640cd276e5e7a6598b662c86d2d620b78f0d5e28b0992c930a443121c7a2ce086308d2c2191a0cafd2148b11e47bfac034bc0551e1c5bff1611cb7e2b8fd6d91f8c17012e3af4065a5f99b7411ef10557cbfb0a2d1878820ed1c41b1f15498f760444ca51fb07477033e543f33893501f50c2c7ed36cd0f510b9732fa40748a9cef09671db96ee70f7af720db35501581518d98e967aed2e03c3b207928d1e78f09e794f45b3ce62dcc8a1386226f39d7da845f4cfc9114825c5f8d84c056f55d21a1db5f13fe1395dac2c3e85bc9e2f1e3c284a2ac61879705d8d65b5cddf712bff13f4720bc02c08539571ae3872615c2f5915fe241238e1022a3f8ee03c9b120f11649915edc36a371fe872e01e89c31ec3bd8325527153ddf5352a9a774dc22dfb5591fbcb83aa4386e1eff844e915c5d7419aec98575142ebc280fe3d1526a1a7cd25d8571727d17872e888e823d79c21504ad0ee41da990d50a49f1d46df83e8af07d064b6a133242d0f77e02b849a60f437accea3667c6d85d53cf402779045487ae2ba585d11be5bf77cab34dd42294af6f2eb15a459601e650bbb6e830fde95d6b322c53c0c6d56062b34454ff93bca5a8998696d94a85cd6c779eb9d16d028f59c29fcd5d643afbd5698a0c671f658386e50005fc93acd44febc1baac481e5b0082da64d3aa933ca4612acce1be89fe5df192be1f67a85fa31b0275c6ea945c51e82105ff1f1c0c4317d53b9f659dd8435f3b7de677fdebcb044e19fcb058872761026428cac7f94139e8e373e881a3ced8290d7afd023398e77ffdc3232c6c56ded4b29108be2a0b90c3372ae3e39d7826daab3fb4e71bdb732d2e8cb62f927d440a8a229c84f7941f1d67f75d693cdf167d1a2df402cd0c940667d024d297c5e69118d037a1aeb17a5cbe138bbaa48f61f49fda55cf4d2052bc22cfce7e50b03a61d1bd57e30abce3ff70f609cbe5c43226fe9f4afdeb9833e95eedc18e9e7c421a30fa7ce6d8a8e8069da343fa03b6b1ac3f1eb852b2c3e9689e9154d3b2195ea0d3f83b8ffb17e212e367b599471ed79258c70b0f5ac3cd3ffb29f78fbe8fbec7b297e34dc6e583a8b098427f88c255d6d6eb015250ef37cd313bb95fc7cad3f8f36b551b26ff5c7ba49295e3c1e8691e714270a47d6cd1f17b547a1296ef490026be36f42be766ec7393bb8732f0bbd53a36b2d0d085718fa0698c2b1e114872dea3aedffdd61bbf8a7a2149ee7263a6b8bdb5d2bb73fdb450f284c030ff8d47ca862343027d4205af147070d41d8fae4b535c5b056f75750d342f50125ce05b12fcebf0fdfef56b68901cf107f6f9eb33ec4df5b10afb3e532ba1cb5f2baf9f50f9bf41e4afeb02d487c1807e87b0bfa4a2f64b9bbd34b288664ab76a29fd1ff40e53068d5265e6838925dcecda1466eb33bef3b5cdcb30b31c84137d044877669be7fe092aff7111f4efca7befd4f4e3ca85d4e876a185f09b826fc8965bdfcabe486e4f8d9a1aaf4231600a8c8e1720286ad5368d41dda4eee00b7939bf1456e3f4c40261e01d2318ef7a3802da9644fec7368d5b274f60f59218e3024c6446d103c2f173b23a70cec4406d957b6778c451cbfe98d43d395fd391bd7dd56651d075d687ab65be50ddf1733ed1c771b25e870dd84b23d29e0fc7839791daf0d3d300598e630ef03b8ec2aec6e320587193dc634dfcdc1e42caa5b7ccffa0371e9e7b6a5f4af500f2de8324b2f60cb6a28c2351bf7cd7bcf4f842561da72f385e2db85f097d6c4996908d0b5c9b133940ed41941f60f06af4f54ee44585b17cce9bbf78878e9f47e43e7161bed0246f593053f2597bef71c271dfe365c839df95d855d067085e289bc864eb2cbde759654d68ce3ae98b7757246b0aae623cdc6aa2f227a4919e8d2fee9517aaf33f2b4c5f8428d9f4e351b9834c9d484a2a993bec6fff3d1ebaeff03fe4530adb891f1f191352eb59af1b079a563321a5cf7508ea6692b62ccc8d60a640e8b9ccd07b45375ef221b8392ad6ee8237b6b3de1bcc2bd8d08c55809d27bdcc0bb6c030312453dfb17f2ee4dd391d0093095f8b2b654f1ad554a39f654a4cfd7387b8419bb68f43c409e35d1d6d023875420ae5eb9613e769b30cc6bcbbd0e1b581db153cc62be18f11a712f901b154f23e48c4f858589125fc4962af043f5e9c4bc40f8a8592fb0131578a1f214625e9f3c4b0c4e863a25b9fe0c6a96efdfb0dccc7787748569cc4a18c4f912c2e1833b3f0bfac0f129325f4c962af043f5e9c4ae487c542c9f940315b0a1f290625e973c5a0c47d494c95e027127b25fc71e25c22f403bb32da598125f60b6227b5090099e954ec4ec05d7c1ed3df0aa3e8ee34bac119057bbb1c44990cbd0e71e1c9d4de5756124b5a7fbe993d53b8a9b183ff891a46227f673912df0892cdac36a6aad1f8c1d45c1ee3b8f802bd4a5ed0c8387e5974d1d8bfdff303c83effcadbb3418fb0e378a5132330aa6a7100b97dad054353f804ffaf304448db127a4ed06f71bc9cecaa1ffecd0a11379266521cecf039d73c3bb96df21fc4a1205f7edcaf2612fac906173fdf5bedcd3c37c4a5b4c111ae6b4d891fd372edb9faba2d9563a88fb78ed741014e362b66416342a1bac44a3e0fe5d98a7ce1fe7b42776ff806d1856f33d76776cad7b2e6255cc8141f773c86527cb7c99c3acda39b89dc04e9d9ce1f3438e1d4f6ee6b47827db47f4a592a8e3406712f1495e63e3196aaedf79d5e56d326d89042b803fb1e86d88341c58392f75deb04f09fc0b14067361591e881ace8298242132c4215bcbd9d5dd0e5c473ecea456b77b63ca07b3afa019469a5ecd2f21f78a95f20572e1f96c6de9ded86b30ce6d0034494903c6be81089e1f4bf6d7e0956af442dba5ea6e785f92752e51ed19232691484b809e1af88a9e84cc5ca7c0d7eb52bc273c8acb3b4a10601982cf75a7206f317cd6f8e85b9a0de3957d80041fec4ce573259e3c64793e4e72ec04a843b074604a4d31963911517ecc8d775e12c43f1e53330393a2e6e49846f4ccff3bc01c446ef6c5732edf0e5f2ffefe5a5c1371092c3e82b3449ec383ac6f33204bdb50e65d1b6bfa51551a0796fe8f47685ca22d7a9b00eac0e720e9ae9c12632a2a03a31dc571419b433f1dbb8ed1001ebc73debfcb3d256747a259ae4aefd3b886e85efef4f453be964a45afb75463155541fea1930e90c2c3c9b9501b4692c11946cfec6fedb753556d8653d82aea955bfb9d6108000211e059e99c6f55923ca4a8cc29c27bf4ce55ec386fc8aa32e9410340be858cb36aad530e424531932561db70ad6d0b87183b08e6f0fdac4eec2f3000eed756e945970ce45ccd10214058301668670211c70085bda0f1ca8e595d73e185a189cdb0e768a0f642c33c7c44e8613519323bb7777948600b207258d0bd5f01a346f24990634b720525048f3892e653e6dedf9256a653f0bec3a01d68c561517e368fa4b14542be20c0fb2e34f5e20ed5b9aeb776a4834c6e8b21935812863ec4ebf429661d38a49595d0aa06a030def16444cb9dbc4ba5cb7954dd8b0a3ebdfaa258397264f64c285a589f9270e54973fb079d558b004f337c6a5e8da05f620559ecc4db2ff28a88a29a3554b90a8da88e5275eedd2f849a824d64717bff8662f0b875f002d3acd0a35d655649d06806f5ca7a38ec32f6e54c04eb12144e4a8bb55dfd9125601e8da151ef89bb16204aef4f906c4ca3017ef0759b8fabe81fa0730d8a5eb764c2d4dbb252ecef9832c353225fc361f640f8d83d4c7c0916f5423d29e754dde63e81b17dc176a2a4843a375fdc2490b207fbcb82b3cc4b8e9ec54ed38d5760c0db8ea8a8692f63b6a24286ef45c30fcb287c2fed4942da80a7a8c95db0a0b3cdc5b937cd6d8f23426d2712c2d3d67bce591735e2e47980634872844a1cd594c62e13641dd17cf529ffb854e8dc6ccbaa7f955e4d8e4ea21bd990018209e8168b4552d5357bb06fc6a5fe5186a6823bccc5c4b34fba9301a6c64425886441247e0daa9f04d73c3e477a24529e6faa6f23206d89064e55793c650ad14ee3a101dd04ffc9f69743ca80430acf66c1b2dac996bad6b4b88b0441ec9202e758aec263a6c1265d4dc45eb28123859f1ed103ec880d971cb1561eeb8cbe5f48e2e00921d4f9e9bd5cce91c5e66b970b034404f36ff0529ead63301274388791b9c866e663991f8550c0d43120a2b62e5b343fd8c0df24bc6acaada66cb4b541cc0d92f7f31d120c8a00522f3e657f5e598338a4c5857055a18ec366a3ecdc658d4939c113e8c51725a035342dbb67e32635b015bc99de47f944f7ff2c2aef9423a2fcfd81cfd7aac7feaa7814df402f127f84931073593297d247fe20340e701337b8050f66fd24aacb62977b5cca415e8cd17c74dd46965a535e532d06e4829d9d6469e783aa1fc6789ee4052848927ed2270a0e8045cbd214972a2a5936744e1db9538a1fe189141bf4815b12170ff11a8af103b81fa94e92634074bae14b7087012839f16cfe41b6584ee19343aaa84a38484d2b7304b0f94e46b2a5f4445d8b3a2a6ed128ca1938e5cba1e58a5b71ca6d019bcdef760776f183662ae4923c418c476146faddc46c1436219987a79c9f02ea72d3cd49e86e1c9ab6a49a79944c867e4d5bf67eebfca2f33a10e9e080572312f7948f615bdb49ac58ea534c1951f9b7217cbd06bdd2a14e57bab8a26739869318f25720d78c4e31fd94e26813e4e4f4021271ceb8e76d5c59aa9a6af909c6342dc19a58348c917b9e6d71452e983925683408310738044f2433f2651e613d5cac7955c579da2dba92ca37880c8a9af709c057fa6fe387341eb96a1d19764d0e6d5b4dacb5edac17dac2ff750403da464b288e148e81983474452e9ebe0588d4322f7119600e4fc868820ca7be9451869c54d0c20fe8bd7b842ba150e7d799a40057064e460023d794738598eb3003399e79f91f600ba8d502fddf306ad2c74b7a8e6ce995cf9d96fd0f927b29f6981b6410fb8fe112ec7b1037aea67aea09a9f068bf163c3165bbfde371203c9a064da24752231365ce951cf2cd364931a0445190afa111cfad8a7e07fb0c1d432e4266c0f48cd0ad003a51461d86f764cb3b0864ee98ce1776a6388da639e5d19067cb453f2eeb2985a6f3a5e2890a0ce7d019f50f6021b0f069da97e618b478476201c3b272da360fd527e1a8d9ee96094fa9241f7592f8d389bf5a89aaf132709ff394a938c562f915877dffc21ce04eb9cb908f173baabff5eb57ad2dc9ec017f77012af4d411da88c2d813988fc565c6a40def27897753504800ba658f632b3f9f95573350495838816b4b5f4a6a2b3a51b427b5975462c32cb0700f3bf160509082fa178dcac57101773933b34576b0fe44a7afd85095e7d9b5c438febd081c302ce1bb12b130d4cf792d35c4c090ed7f590168de284abfc0ed9fd5dbbeac14e3e803c9e58163207478fc330e796c7f0cfebfe75e96c3c0782390cff0efdeb77e5bbde1ec5e16d46726061db102e57bd321134648a48b79befc7b0e0e4db9458ba76c93a17c37ce7d1e3bf5f9215bf687f43722a1870a521d1db8c55ba09186560487670d0269efa2d19239439f7056cc2c0011f2bf36480a41060bd0f2a8493b45fb72561d36dcec836b31ad8dd8117e9987662c7d38a0e58f94d5d59effd74beb3292d27608d39a457b44260d2a01c9e0b472421736e9d2de4cb786bd392741f43eed1926ac3a6d3d715f4ac4485046d67a015d131b5123d231f196849876669b0b9547cf0d3cc9d24a31f4d6b8093831ac9532c4f2e540e2de5863f76f2f6e27b0ad7d955fe87b02a87bd673196a34563d7ba44fd9a1a45463728177b357eddea5131aaf841e71c0d4badf439a014912e3dbb597c464aaa8100d20140bfa3e940c9edd9f41f726fc1393fb0d5d505f0995676eeed106b51c9acc30e0bda048531549590eadbd810cdc7116c6cca672b82f42dce9f78e1abe7dffc7eac15ac68db20ef9716cf9caf082a427115271db2afb7bfaa8b82d89035a7830843cad883d0628ad3981a1e60d200c27de3a081cf7d9f29ce9596058bf096ff33896a9cc71bc6cc6719c81a6f7a18a198960697ad4309eef93ef2c6f0db9bbd4bf6445f4c428fe1cf695834860d3712425c508a171379fbca2a0029aa9bb90e639efae7cf13f02caf9f0f81274a7082ba0613d57dd6ed80a728fe601f1a7bd16df138807356090e2f5a38cfc13391f21a7bc071c99216f861d6a06a4c9d4f333bc907df5b9da2466e8ee83a5c89134a60558e66cef6c28d08d8784d03439a498d5bda832d4c11628f8fc12e52ca304c3e7c5b045b1fa9d050bcfadadb096a2e6e56e3579d855b20c67c95be7826f9bbf45bf11a34add265d4091d9c77e43069e9aaa802f9851f693b62cd689197e6f8a495fcdd8dbe782576f08df47a661242ba341176db9eca8479f0ff6f55e865d90520e1a51413e868c8d05847c84e2b2488bd0819b7d3d915442d2d0025f58be7bbbe41ecf533e801c061fe4398272a9850e26c1facff99bbe7ad4c1dc740287434ab2c04f7db7cee5f8453ba33ee2921b4a32226502270718475dda922a26a22b666627c22905a61a29bbbedf3d6ae29f6bd8307a9c4c631378b56aa8b185f659dc9aeb2ace038618af4428cd9586e9f4fb8b3f414c31841e4d223c924291b0c65605cd63477b4f1a96eadeb7f41ab9ae96d4db9b9d014ed0a9715c533c02743730c25e4ae4eb9f5b290d10a1ed5c921f2654dcf3d44b03bbf9db16d97413033459e5305c284b416c51482ce5f604c18ecc886e8549b81d86dbfe8ef8ee0b270a8aceb08e5ad8b8ccbbc522469b5f37d6542d898d69b91c81e42f835524f3c3332ac28d9d5aef981a9517490cbe1dbc650c91c32785b4efeebd25cf6cefc640355af00dac234a01553e7f0f2e70746683800e300d9d174d84e3b5ca3f765c99fd24970bbfb357614e2b9d60b0c0f29dd83933912c2717622e592d1b9f040c5ef35b54eec7707baa56023141b462726554bdb3d2a664445eb9d8a00402097005a8acbaef5dd85400bef8e2e95ce5c8d4fea0118235adb54550ccb9b810bdcea37c1144225c04f7c5918a1478aa00dac572e629a38a82f25f55a9bf3bc63723031c80ea9adb41c582928750b7ae45cecc61d90299c99fa39ffe2db4b770b84f5d9312a00b8247eeb8de444713c5a4c00b4ff889de03dc0c3c1b4005a9b51c4de14abcce7eb8e5a3dd451c78c8802a03d71dcc0cf8b8a8ed63520bdbad4821a083256f5379e9901e2476caf1da23ee37a1689e075424fbed874cd57e03a308ab130b2f0e8e6b3cbb9cd230e4229dc76fd02d7ebb34262bf26bba44498a3ff47e6a8316f6a14e38f3c9a02036d6e96b90b816eee3924769508524c5e9262e635221c9a9c8b43c597c78502f9933379bfc9f8bef3370ada0e0a829a8975a5c9c0c1b48adcc5fe38fedac1c95c84425d5ecc9ffbb7e8fb4cf35673f0e20877aa43d65217b5fbe7a4ab7b112e3acf456e94b65c8128cabd2eb85568f29815400e461e0bdb3c70c14ba72cf2011b62b21aea36c39ae05550954162a390b91642c4400b9c4726a3be8083871baddb6441097979340c4c429e14054f6118720d94143b4ca2c3ecac0f4390802ee3e66d440a19c8d601f39d6b39c4e68fea6a8da56292da20a398891a15193b8e30c07d9c0d1286fc836203886fa383dc50ee96f145bbb53cb467f3c628de97d10f230629ae34005aa386ff8762c0267439135d12f7f95903f1e5c06b718cf0dbc5ab6158dfb97012f9c6ad49f6d685b5a8debfcd47dac7a544b250690dc8aabc17ba6080900c3b59acd2e5e8e6a9ce3b460401ec46f43fdd2f5df0d00dd568cb42bd4427eccfdab58db4229cada8e6ce12e6a86d7305eec5b72b5781010beace34a5a64a2f9a0180cd5ec9ee1d777613802185f872013890c6bd898d369b70f371cf96ea7304346b2f2e0e23786ee1815699f7a32e3cffc7b1c0ae5bd69ddd937a99aabda3a89874598fdc3045519717793748b1871273e204f8cd6dad674b16d90f2e928b0d7a275d5fc4cfdd74668634934ef3e0764281b6b624bfabad181bffdadff29a492e36d079e7d78185bc33b69ad164ef8225cf1c03d8439767d93940fe021554a0b2c66a6ca919dc51b0ebefcc6e767d0d4aa355c260c1c53cd522d0b5827bdf2da543bd9848058669a6d8d711bfa8e7334352d5f65b179a22baeb1f2af9168c14a506e6a1cb51dd5146e4b2d46fa1a2bafd9f163f40f44ce68560f0d42d3693eb0a7e28902753a236e0b59f45c1596c34ceb3e78f180b1aa5ccb93091ef436bb174a6963de10389e74fedb3a1c538b3d0b19922dbbea786ab2b3cc70b469d48628cc3d6e30e5ac49df462d4efecdb7a6856bbe11f35f37177f855ee97e760e5803b19b22bd455b7bbea7559c22c034a5e9d25dccb32e4b87a1a3388ffba37f25c16f43cbd4c6fa763088b5a67b2e24787aed83c9902907bcfd3c2a00812bdbd57ec110b8a416b71ba7e52b262c4982b0cca8375f62934c2a1f4161d5fc1383384a1837e0d3cc3bf164f0b0b7924db7b9d186975c2ed6a105c21e929fd8473ca45cee439d10ee44c564398301b7b8a1e97d5d93a1d10883385aa4424ddccb926d81419e6c5721d68893bb22e9f2cafa10154a71346176e3373f9e7a76664523ad252c301f67779262ee04c2e094f9d7557080ebc5ce7289e471bb9d3f899ac17038548c26fdd83ac374996c0fe560504c094170780e83e7db321cadf19220bec88e99dd92cb602afb5c745d9c3d16ea3e6e881e25273f320a148118183c61361b7ae807079ee1cc2b27176720846c2bd1992e5092d040c1a968ab568d4b13249c97803c0c9c64ec075a8d8634baeb6c47ae245599553b5b468bd568dee97c1af0a1af4d8c4a1fbc7965a8f4367759a02305837a983079a11885766c82d20d74417d7112a0e32881f0a09721a9dc0000b75c2989c18986a758e2083b56c79166f4041861da0cac783006c434e52174bed038783911501c0208021663d4889291cc700b5bc85d3286f4c010b81435e082d830fdcc72490b504306f7be0c21561aff2a23176531e564a12af868639106a791456118496b2e7c86302c0b1ff95dff89e9e046aae8a26b9af52cfddd33d8207615e1fc5074d49e500190d53cadb1d4833b2ffd0fd9efe2bb1b05749156c10833fe32f3b323d16d1fc2218ee0792b19530b1970a8460b263ab52e4340dc38fb10629a6c65ea5ca167360d709beedbb6093708883e06d3446133692806aa4e6a231248c98da65968489adf15080afbb9147f9ab315d50221855ea010193d72f438b09a98c5646717eb0c6b8e134728241cc74ba787c91e04340a85f1ecf580020a49404b0dced415b764853e9104060d87f8190b9fae5d9fec03e312ba653265b6e32d1396cd12348e9880055e64c2dca2815fb484101e5d6159ba79206412cbf84cbd66c3ee6c8f5d0516b2ff88d91660e239b30c1b95f2a6386aac4ca6b7300164bd39c758548cbec31da22ead9fa43e03300803d76609bf41a4ee48f32fdb79576c64aa2807e0b7654f190209def41620d889f1532f8cf677df21e841ca856d68e903038cc8d14c7b0d55724ecdc51429608c8e23164a7f5f18c3657b05db79ec8edcb1676ae0f88075ec542487408081fb4fa4490e42104ca3ee06cf9703104541afd5d3d61aec83d52d7c1110b911a925ec53e3dc1da3562cda552cc269284c4ef7061519926f258794d1067cc2202f77f967c89b478ebf3736bb243578834ed65c0e042be3989e1cb55df2293734ed7d1dc10a9cefa1c1b291cc1bb16b9da908e914a386e83ebaad470d461712942d47eb739f0b32f42aa5ae87c1b32e0047edb12009d116a5a796e4633319b0260397883c02b91bcd385593527911ee1b12945446c091de3581b6ef99412c91d2ea64c482292e706fac5c148f54d9a08581238c2318d6d91290d49cc5d609e0901d857d7c2604bf8562b3dff06313127c88c119441983d96c07db8e6fa19fdaed09d9444a2a7248b6f686b8ebed0516725dd5dde2c62fa8a898b27a6c014ee9386c5f92908e98f7b6783418af5f4ac1ca47755a03d33a275491570f06e25c0afe8b701d765564270580870de08b3455c225273498cc29e2d43fa71a24a98a7f62c7651afd00983f8843a3822afaeaaa690d857bec819ec15a1323892ca00d3de06c3d521cdebef95ef0aa4b08fd74e3ae0c8181d12aa09d5f03424a4e7c11dda0f818aefbe02f319fc162dacbd0796f9ba7727928955f142ce981e2eb6d815d2a992eb773cb4729bf90ca62e21097ba518ba5fe9d898a9e18172800f59b43b8c8b403a4f9380953772fa240e203dc7dce136969db04858676bab10450047cc3c545d8145a1eb4ac1414c34324567115d0a1d1e559e4a862f3430141f8a564fb31a721dd7de22faaf51d9d08d5a43073dce5a024d666d878a7d70eb674d697903c6269fe2051f2fb634244868eb1d7a022ea3ad197be98b5c1b3c5a312bcd5b2e5d0c619d2b570272acfc853634029183d0184ed16550b86bbe431d937ac2777998a126536e09bf8cce20ed105018e9e1c99c200f49356fad5970e16e93eb9279dfdc6279826a4dc9c771625159eca1fe28bda940b04f809d7905072fff1705d0d1d193adfdbfbd501abb060f2e742562057d4bf0c7a3d479c703b83b84840820b6fc19f7905c4c342efa433107844a0c7496487cef297d2cb9ae62140d30af385aa5442a1d0be13e40a95ccd58eedbe7d4c4bc99e0a0687c6dd617422043bcc2c2fd9c4f228f8c77bb91eb43c9690827db99bd58389eaf2130f870e3cdf50c53d4f8c99bea67e90f2fef841cd0f657194d69d7c128e0c5e49c2acd06599e813815af88f8bae00b56b6a53e9125ebfe2c3a0c1f90b7f0e7fbd18de959aaabf98a1216588acc49409456f5f93978d8161db52b507e76106efc3810911832aa07d83ae438880bb3eda62111ae517cf0f6a40676f97373e08080f10e3cf6022c3c0c1ef87da25675377190f653ed79b8bab0ab9b55dfd0e1dbbdd237be593c2d81edda209002b0e28e2e9d10bdacf5130bc9ab34cae5f6892e23b34497ecc1ed13e7df8588638e79069d1c75a05188108a771f7c554c54f989bbcdcc213f3caf249a0006f0d56000db92e0bf380048e90f890638a8fac81db68be6ed20eb078ded4a967becbbe5d2d600192b6a37fc6794cd2aa2317d9722ba581c342ae4baaf01038ba97365d2b79cff51506d50a088875e1887990a2b77b009e38b30ac098159feb1bb07e351037a0c693eae06ae932c83764b3ef16569ccd52303595c91870373cababae122afc25727c5005e6609205e662fc30b826c62efdc1e62ef4081ce7ddb8ad9109d2326642754370cb8397167be10c1e7f7b3f4af5c35f39a53c1b07b69ab542958e394a3c6e8b945d13bd34c87c54d7ae8597510c9e328d5d1bc738b8e09097620057e240fdec7f14553ba3c745149977280502016ffad4be4304b0fdef9aa644a49e1054d974405ab70f330160b05cd6dca41d2ca4566473331b45c30ecdbe628200080fc23bf2509ba58ffd6a10d3be808974274624782090a16b27d8d85ae24f087eef01d90388b0efad4126cb9043a315fa95510382b391da0006b82d39ca834e3e741522f4cce7284671af491ac3f5ea87f4adfc37f92275559fbb7549a2de58e56a891b4bbc98acb1ed69e1b5c171f489a5445acdba3bfb604169e9155d235076f657612443605990af209180b756bb266d93d22c76ca461a25889c2c778488396c4327dcba28dc75f2a8149cd2efd56ccd5a5dfea9a5d1b8b4b9830fdae48e137811829ffae0955239dfb29babe516bdf12eba35a4d29e9282916dad683d7c6c2dfb87f3d9206adbe76283cdaae2a4443f7492572cc4649b99f82c5d8c6fd4be77e4a186e5d91b445d244afb1f8845ff7b5e05c141eed8f1de977aa8f5453bae96a54abfa32e9dc4f19ca1f0beb1b7d2c3682569a402cea9a5d5b5ba49a13ec9bea8e11e9dc4f0943fd16f7affc5624ffffb31e314832c56cd7de32c3ee8fb68f696d9192c652278918c336ee5fa16ee95c157f09d7621917e5574137c544d1de88f2c3b04cd7ec7a91b45986652193d67f471cdeba54cb546eba6edcbfb4a67509ad615a45a5a5f0995e2447abad98415a53c8f4dc379175f43ccf9bcd206fdcd69a98f1ae3b62662a0bd6886336dbc2678ac2cf4d972bcc94ac7e980ae2ce9ab38abb9761493d242654965019412b73f64c22ee23881b41dc8c5669acfda248abb409048709e44e20573aea721f456ecce05e26090d69d23469851972850dccdd1d001bd03961258214c761a9e70f13fc09d0d32a6dfa9873024f1720e0628b2e3ee0810e80c1810e70d1812fb6f0a20b0e70800b2eb6a8b3012d3490812cb0b8820e062e60812aaca8a28a2aaab041260a25eb05847c67c9ddb338102fc270e7a9c08e0cf8d3dfb9230af730bfa6e1b5536aae30df59b9961ceec9a9dc3abb40e23b36b5606fb6da8720ad5e61c14a152a4cb2d8920060af24a4292b18a950e46a110d0929e958ab354848e2a3ea19410424211c31b2062d024200887ce04107433800c01a6bfc58638769ea90b9ce1dde642e832c527b1672668e36ae84473673b4dc9d8aacb1c61a33c70f676d4be3810254dc76858da5e69940911313742cac434e4c785d87c23ae4ce338598b30bc4a22844e4ce23011e29469c8b7822c003019e07f0cc19e2f3c609ba70773d6fbc71f71b3ff8bcb1e59b37622d77d7f8aee60d2637907c1fb5dd7923c7ccc0052bea8d318c6543af994117175e9bd039e97e58e1ad598e03a288c3038709283c50ec40a0013b56ec5ce13b74a68d273a7738bf16eb64439ea389eae1b66dae4a34895d0713779fe213e5c475ee781a90135bb4baf3bc71e761803bcf133c4e60e1ee3038100fb460f2e4e061fddbe481b943b92fd2954d8fd476b1d0dca1a395682537f0f788c18e56deb6b5ed4a5214c2cf6548ab175bdc3de7736784e94a7327c874164c07c17434fecd664b3bbfd32f25e5a4df6568632fdaae8dd59476a9a4f7c7ba1c8d8ae0b5ab55ed6c4986bfa2ddc03a443b2dd6fc4eafb5280a7d1fd595d63fa2ddb53991ee7ce00214b0581b5351aafb933ec4445bc35c8044bddf35245bda054bd2506345bdad312c0d2a3c8d329e0698c60a481a3f80a4d1038d2e9c46a1d4a3140d22fc335da1d1058dcfdda9f75aac4623887a5b33a141dda987ab4963b8ec8c29ce5073c60feed423816ad1d6b4d8d819e219023843e5ee947a59eaaee10c8b1966b0cc30803bf57e6e56ba4c7adf1f95881ed6515d296829ed9ee8aaea2398508f2b4968a988d630d57adb6d2bcd895fab7d141f5590be55a146e0e35c65d87019f91956738279de8b64b95940c74bc046e2deafc56afd19833a3c1a7e07ee3edd795070f7eb403cb0e3ce534310771e26de09d32a5d69fc0a1f0536dcdd456563d868ab48845fba1ac5c818ddbd23c30377ef74bd51bb2fad44a2588970b6f619d6e1bd627d86d12e77ab7dc237da655ca3f749fc994480bbdf702060bcc077897342e113851f86422678c18bb35cde33139cf126b89a24620ccb0fc3d51157c7f0e2a16bc7d104495c038db83a8ea3ceb0a29a5d404a0073d74cb42d0bcdc2fa37b1fe92e72db58ceaaead5d2a853f5a59f89f8b3226aabbb6603a346ae2e4797a8949e7bee9430cca907cdfb7f7916040c458220609eeb96f1a411aeeae97bc7e1b1ee5719c917a7f6c044bee0ef4b5aadd79dcb871e3a6091e2644e000d7e2d325371093aea7d5210a2ea08d93457ab9bb8ed28184e0c749f16fb3fc3c6c7896f02e7c1728de6164c0a97771ed5b391cc6ed51a63d2f779ee779b3990780700394f980ce1debe271c4208bb56b556b690259782da9d002beb520b471e553f92b279c608ba85cb1569a5a586222d3025bc1e856bbd5a42697151f71dcb72e57b1b47d56d26d1cd62611939d12259e26f7be510f69894945bbdcab498d094d286ce26add642e1548185315a61b68af64a625fb4c4bc85795274c624d642eb06005081c0540b56d62c2129690516ccc6fab3447fbfc377a74d3d5c8f3409bffbe6d679c849335817f039f8cf1ace151c3a384dbc8c16d90f9c2eadc7de8e407a8fbe9805817eb16661fe60702ea8058e03b89621d750f102fb6e8dc95230681b4e49e808074a1c6ebe96f064170d1b15a41890285fae042abdab547f296b2d2ae3d12a594ea7881e2423b7b5bf8b3f1c6931c377078066950004a1009b350c4282f6c74e136cad0866c5183bb7f88af173ef5882803445950a0d0ee6de1e700a48e1524903a413a774ac83aba0640b8fb1507b2010c907504f77d271c965a9363be013d784457faa9d22a2d871653f13c1d517058c688b291cd6a5d6975284a2c28e32251ac446225f23c1d9ef7e1fd30b4b79925eb8cd4daf39a000101010101fd003d71724213134a60b2042828a80605053dad0e053dadd2b00c09d59506fdd7a2cc9c3e939ef744cbdd3beb84099ca8e3dd0db4b7a7d056bdf1eb0a395143e70492133c6ed8b8a9b901d244144d84e9fee211e3fc7d99f727624cfb3ecf937d4af9af1d7ff5f97c5f1352dc3b204dfc70af42a4c40418ae9998c34498fb3a7f0ddb2ece5598b8e5fa4c38717767ad9aea3f3191abe402ea5459005d00e9de2d0006a44d0a2eceddbaf7d344b1acb579e30e9623c56349dbe46ea55f9428513c4f1654530a7aaa4b41383c347baa398a9ee1d810c1e636fbd97ecde6c76fc9c64697e5abcdeaaead281a5793744cfbdc21ba1231a6a9a2bc8272795f97aeb96a716fd91a347ccd9c3538f76e8d14ffb2d0d547bb35384a206ac0e8b49a376a6e6556e3e45a25c4704aff6221259450024767c3fba0ae4fd44559b9daa380281480f33e6390820a80919448014988e1ded124d2c8928021095812aa8a5795ea3475701f5e5095e607f734a025d3a0a9e3ee1db89fae5695a64283735ac6399a7e914463e4c3baf8aae83d42f3c3e8cc1b9ccf7471a76782dc3badcf6c60e68d7b670647cd587137b3840a86d16bb3fa330675d6d7ee3a0382c41b249030727724e81174fc8830eef4080260bcc323702019c1c6882d5f9601ac428b65005fcd080f8ae0a288314558a925ad8552d32270f8006e580640bbf08998e33522ba942411469789081c9dc6af21c0f0ee623a449b2148f78be9104e5a43e0f02ebf05ad58475a85f0c02d7d6eba1ad1d54d572355d0972e7c0b7c2a429078a45f44052684945a0d0b1126808a0474716ab475c6b504fca874eb5b193ab54c1877ef5c0ea48c941c8de65de673198415e51eb70e0287fb7d1f8f41cc7e0731048c591856202ace5d8a2e6f0904192da2e8b212d59c60336dab7668d75958ff268455d81f9b615b9ded3adb751625ca2b48fff84b41e05309ff963947fb214dae648e06fe50c30fdf0f2a8c9768b54e409e541a43a7674c18fc2434e6e69db663707897a311f940850fd407293e0c11238677a118fcb4e96b311fde558cbbfbddb68734b0a425237a2bedc18a77342c527f616dfcd247a25845b15ea6cfb03008372b0842bc9856061065ec0984103a4ad012322470c7afcb845fb88565afb00e896551a8ab91d2c6af1c60e0423fdc5c5b2420634eb0b51559dae664f53ddaf805cb89b9ba42d7c6afdcad493b63be707f6dfccac1871e678dd6c3763f61248cab49f8758f624f5f84b1ec855fe147d103113b4aa06070f71d1417a795da794ad0cab88856c6367eedb7e557f8b62f22c78d5fb432b6c50e67e86ab44b9cfba22fc58afb50bb0b74086309ab7ecb76ad4640180bf81346da42b66bf16ba747181b5e26071abcd3e56dd3d5db9c4113b50e318559d794b0ace622fc22fa8c93f02bbc7808b6f16be317155fa6b8bf74eea7e057eea784a1107ed530ce3c46bc8cd9f8b5f12bfc8d5f6ec60bdcf5e318c632004c1cb29ce0e47937c070c3df103aad618a4445a6690e6f502003990f7ce9f2811b72182205340b16215918864261f89f4b58f83648c0dd6d10e336103969f27d1f5dd5cea70910cde5b68a8695163eeb47bb7135a9867d541d25812e61f235d5fdad58dfb7355dc224cc4fbeae435dee9b3e550dbf16abbf9a036b58d7dc37a9680e87f3ea73256b12ee9635fc0a2f137ebd48ab9769e3170f922d753c77d4961766b3d94c498e14433cfa0366a0e264fd9b278a15e7bf72f18ba875f1cb85657f84653afc7ffd585fe093311e2a836de7a704eebe440cb4768f34d33d6a0231d2fea48d5ffabf28b6f1eb0923d162f815d6a13af44badcb14fee7f27e8cc99d470a9416d762f54e98023419411c0b86317cc2d0020c4a1306239d3b50db5109a82d172a261737938b1bfd560bce8708de63f37c008b212568711f2a2a23e820410f527074900407002840a87077146e412c7991254de4085864516788170bf89962e82b72c743900972c0800b0869bcf083113b61bc90c347d535655cebc2d76283bbd3d913be340b16fd52f2b93c8209d96c37d5f869258a57146b7993d1ce6783f56d756baa0a6fdd5ff725a1947a1ab3ea670cf63c8de6eaa2dd0dacdff4034477a5d4a3fbd66b471cfefcfc00b17e7e80288ed463a93dda599d318c453ffd19837f9568a7a9b6e24ebd9a13a983b891ad2d1278737ae63afea2bd3d9125cd3db83b4d887663cda2ebdae7998b9c665c9bb987d3e9c2197aabadaefd10971b5311eb6e11e5b665ea3e2c593e2c7495e5bbe96ab4bb2cb9fa54e9912d57aa35ed76a5d956d2453b5ddafa54a97ea23eaafb4ff49f7405c52a44bb6debd3cd63b64e54bb644aaf72657b2ec69a6a21daddc06d9f34bd15d421d53bac2c6ca395de72dc75f65128515a4735573257da51274b69f8f99decbe4ff1ce8995aec2271b66d2e6b7d93e4d6b18ed76895742b4cbf27d589c886e3e2a5658ffd63a12c5dad9aecdd56c88475ac334cbf737b012dd36bd4a6156a29dfebe5cad6871a550ed445188a2ca08df85b7f46fbbe75610c582496be33e69640fe9534889493361d254eee4986fb38ee13d9ed7a35be4988d94c2d7825f17db5c7dba4c44fbeac72dfd5a6c0ce7bfb254133f86654af749dcd15cd536ff2ef1171efd58bb28e111f8543e9affde5cab50adeb4d2759caba1eedba6b6db7864f73d115ccd57d3e30ba3a527d945e4b8f3e3afeb61f8c453d4d7d682adae96ba94f55d1eebb23323f61f195dc8ec254da7ade4773356d77d5f5837d942582f673155a7d9937c5fbfb3e1f2b7435537d9f95eff399d19515d5a7bf26b06692aca0757a8d2f6551ef1ed16d6f25474ddfe65ab4fba074dd47df666f7dc2e1b54f3877f6bfd5a69538a4d7eab7b9d29ebf9895a3b16a35dc737126edae4ef60826444ba57b54b444e5697568c7ce25152c75d1695a85fd17751a6f4d5a2b9263fda78f1c4b1ab5ad708c76fbbed6fff47d1f45c187048a8258935012e87f6da6a2502869f76cbf88820f69b70a142b38834245254ae86aeb327fdf473bd26e1fd26e15d5ac9c787116eb98f5c5b68aa5c5a4dd34eb4abfefd3181f21eda6622d77b64e473eb17edb8ae52844b12cc4e327b996423bf46278ab51288a424bb0f0f10b768f7255fc562d53b947426fcb150963191e3fa98565b9b0fed2c62f8d5fe187d7551665a5d00e6dfc7252729195e8e8627b5dd735748f722dc258a6733f65e9c9eefb6cddf941ba351ec5ea7324bc650d5492238fd092a84092765f7844bb5c6b146b9aed3b595ac661bde1da3da2077077d1e70a5b7eba254b585ac49864b15059dc1d076a00abfd9a565a4ad631039f2b1071775d73cae7510cdc7d1e9d39b2818bbb172d51b9b68ab058788572b09c08036d78e441f8637de1d7d615768fb00c57933ad647f7c768579b721d6fe07d1aedd1fb7e8b92d0e97aeb4a70a27f5b423f97e044a3b02813a7265d57744ed510a1235dde2793d8e0e131c67421e1ee94ee84e122adebc75b2eb4caa0e1d9728333adee1efa6c4971622df1d9b2e1de85a8a2b91a3289e0b85b9dbbdab59e973d8f1cf32dac7ffb1083a258674d98dc36fc0f3d4f8a14294072dff417b7b4100ecb5898fb29a10dcbd84c810e0ecb58073e53f8c1759de1b0c461a93b135248a244da9b9e51cecc6694944c146b7729ae26753e34fd819445813e15fdc04f57eb64f306edd656b4fa69ae21a1a177aaadae09b4998635c5a190255ad570c5db86377dbbeb13ad347c96fef901da42b4f3795dc1efa3789738a75ad162b4fbd0ea5d628b29595f04ed1336a29db6a25e69daf9e84cc314676b3912e77d9fd636beb7caf7fa3e20d6ebfb5bcbd537bbf8f3a9bbe7e23014499acb1593f469e2675c63e52769cd529f9a8ae664b4cbd5266cfbfd7d2c2b4a5564b9fcf351bc69958dd30f5e25da7d4632155e2ea499ece54a52c1159bbd948e64444c4bb2d84b8968b6e46abd98be92f5b51a667d58f3a6957e15da5d6ce98bd24ed7b02d7cf109df26d6b5186455fd1a93b92473b9eafc4e610dbf88763ee27f9315559f75cdeff44ff846571ab437b266dbb52c08258df9372dc5dab57465bb56a48dd54633aec9945e5416634a2ac18fd11068972449fea1da62b17bc1fcc119719e18a0a860791a8f01ec2d6fbb96d084004b2868a7122f1d88afede801cec385a5ff4451a0d7521e2a50c8edaf559dc1129a94b466290a7f31786d094d4aaa6da7cb16c22a443bead52a08e8f1c9c2c1fdfb74ee3c6fae12c0ba56895841ccda11c05449c05fbec44cf261cf6b3d48650a0e4bcda24d15175fc2629989c1dd734c404edc879471e7f172bfd1e38e4a75f11d1be69c002585470dcf1a540a11e8d9f1206abf74e1c319f84edd5ffca2d752d75ffca2b8860bed6c36c28f3b8bd5ca29e99a5df7e87111958b8944229dbfe96d15a675ed97741572cc46757f524da9eedacab848df4ac6322eaa29695db3cb458ed948c33452cd1596df163e52eea784f58df47fd1fdac8bfe8b72f99dacf82dfd36e734599f62b6fac2b2df7589487f885fe02f6d8d9334ee6b4a9a56c66e25637a5fab6b768935bc6fd3fb9635a5fc6419d3e17d3237f42126facf55185993b4de37e3225cbb4763f94c5817e9261023e9b79aac4962624a0719fd5629950306a91c6b7035a9c3f9b56ceaa3daf5f3472fc5d524da89386f5d86e2e77fd2db2649d23a12a29da6354c8fecd7477cf45bab2f06ed882f065fcc1f629a2ad7baa7ce67b5ab8a7ab918e5f1810222291b488472974211b15d2bd26c2c77291e139c7ab8768f7297da2193dac1b92ba1bbd2b7795f9bda2172a75e0eacb64732d2df5a2a12aae56e16c5c912a03268e33c6f0d32d6b0c28d587a9f300a020f3012826aae81c475ee72df34132b88cf2801668718c4e00ec4122bced6e9be1a6dd440a3060e6a3c51cf47ac1babe87b1f11599f74084b6a51fc0227dcdd459bb840042e88e3023819d75a2e6abb76a671c6933852687f2cffc7742992b98ce5ca21239cab95eb8b44b66b3516899efe458ed9e8c59785ff5a2f71f2bc11b482461134823c71c61037333430230377dfafbfa41cedb513054a0707683106d00e06525006116ee407bb6aff341b96f5da74adb99217df9a6d3b1f94e163b60210062ab0310725c7dd797080ffb56258bf7585fe736d9261858fbf8f46bc6fbdc16633323c328a9031e4043f9c60cb09b6cc2964f03945e9738af739c5159f53c87c4e61e4738a209f53fcf89c0289cf2982f098737ee61c99c3c3a79c16f89423029f72b2f029478e4f3949f89403844f3931f89453f32907a907073e3e88b3c5671cd1679c98cf38527cc651f98c93f20987053ee16ce1130e153ee140e1130e1a9f707cf009c7003ee1903ee1549f7092e0783ee178e013ce0d9f50900105163ea180804f2816e0138a323ea1c8f98422e6138a9f1f423c00e2e307ed20040f21d580303e1b80f3d900d06703947c3620e88df6f9e6f3f946003edfa4e0f30deb4d109f0c80814f0680e1e307074f58c0e7130cf0f984199f4f7cf1f984e8f309269f4fa4e0334d9127807c3e8104c83402800ddc883edd7c3edd08f974d3e3d3cd0d9f4d8cc0671356f86ca28dcf2676f0d9840b3e9b60f2d9c4139f4d78e0938918f864a28e4f26a0f0c9c4189f4c6cf1c944169f4c143142a4c8082114f1d9460d9f6d36e0b38d047cb651e3b30d199f6dbaf86403e493cd083ed970e0938d0f9f6c787c2ea1029f4b84e173892c7c2e21c512717c92d93e36c0b1c4129f4b509f4bf8f0b904cae71a16f85ce3019f6bb0f0b9660a9f6b9ef0b946099f68cc5823c6e79a1b7caee1e2738df5b9a6fa5c03f3b946c8e71a1f9f6b7af854d3029f6ac2983c7cecd88163887730d5bc7caa19f2a9c6894f353d3ed500c0a79a0c7c2a51c68f1f4964c0671252f84ce28dcf24d2f84ce2079f4974f19986059f69603ed3b87ca641c1679ace679a223ed3f8f09986c7271a337ca211814f345ca0a1804f347172f0008286fa44b3814f34eef34c0b7c9ee980cf3356f83cb384cf33627c9e79f27966e6f38c91cf33467c9e19e2f30ccaa719327c9af1c2a7190cf83433019f66e6f834a3844f3343f834b3834f3307f069a6f46926f46926e6d38ccba799954f33447c9ad1e11309347c2231c68e0e86f408e1d1c1e4d10112577c2221e41389950bd1d1840bd151c685e8a08103213a70b8901c5eb8901c685c488e2e2e2447cd85e428722139582e0487192e0487065c088e39ee6ea48907de81911d3f8a90c167112df82cc28acf22967c1631e4b388273e8b60e2b308558f39c4103e87e8c1e71038f81c828bcf21489f5fa8e0d909e2a38c169f656a3ecbbc7c9649c16799d5c40104199f4020c0271024109f4f325bf82443c72799099089c22799277c9251c22719217c92e9c12799303ec9d4e0930c0c3ec9ec1c3b74cc311ef03946033ec754c0e718287c8e61e373cc113ec77cf139468bcf31a1cf31b2d40f0d70f85067fa60854f1f22e0d307383e7d58c2a70f46f8f4a18c4f3115f029068e4f31697c8a01c2a7981c7c7a7941cc169f626c3ec530f914d3f22986894f31487c8a09b263fae8a1c7670f3a7cf6c0e39307357830814f1ebef0c9c3153c3cc0270f4df8e401099f3c00e19387303e7938804f1e60e001478f0d7ce8d8a1043e77d0c2e70e16f0b9c31c9f3b3ce1730705f8dca18ccf1dbcf8dca18bcf1db6cf1dac04d9e0870e5af8d4a1023e7580e35387363e7520e353072f3e75d0e253079b4f1d967cead072f71e3b7c83d4102161def80c4384cf30637c8691c167189ccf1c94f8cca188cf1c7af80403039f604ee0134c183ec168e113cc057c8279e313cc113ec188f10966069f60ac4f30557c8299e2134c149f6096f80473c42718203ec1a07c7e39c3e79712f8fce285cf2f1af0f9858a1f00981bf0c07183832f433ebf04f9fca2c4e797213ebf6430bd80f1e965062f2ff8f4420ed160e250864f1c46e013070ef8c4818ea792a8f05412cc5348753c85f4796a8a1853484fad80c60a5d3cb5020e4f1d85f1d4d1104f1911e129239593940a6d3ca582131e3b6858c1270d29f8a481894f1a92f8a4a1884f1a38f049830f9f34e070000c09e3ce23e51ecc19a4f89c01c8e70c20f89c61c7a70c23f029431d9f3168e13386393e6348e33386303ebb94e1b38b183ebb7ce1b34b153ebbc8f1d9c5099f5d92f0d9e5079f5d6ef0d9a5003ebb943ebbdc7c76c1e2b34b92cf2e463ebbfcf8ec0282cf2e00f0d96587cf2e3adc79f0e8b181f718e2387674204c07e8176138f5be68433d1cf5be9042bd2f70b8536f7a51c7a9e70512eed4f342a49e173fb96fea828a2e3e7747830335b8738072e1c6b968f91674b6f8b640e2d4ab93823a719c7a7560ee1b18630369e60664eed41b430b1ab46861510b1ed4d300111a08720db8bbd30c84c900cca9974518ee59a4a15e16a1532f8b1f2ccaa0dec4624e0d0b19163f9c7ab32bbaa0deec8adbbc4235e98c413d3a6adca94727c87d86013a597c62e0e6ee1828817ab30ba031c79d7a35b853ef023077ea5d8008f5b418d4d31668433d6d8196bb5be007f5ac40425b2152cf0a1c55d0f159451977ea69d0a30a24f70a88e1be4b12df921c9a14b0625220cea400035cbba36afe8d9d848adc516156e00ec5dd59400512274bba1f162d64bdcd3b4ef8b9962ee8d9586a77d4ed87fb4caca81c5060505c505f505c505e503848600aea49e0059dbb8b7d54530a3a6005a570e3d4cb34f01449412445cf942200ee4e6dd7e20dde326fbad2a2584125112040047ee60386e8dc4120055a0c77dfe21302a1cedd0dee8ec3513694b7ce0710e128226a40d180520285001e3e878b3975dce96d5bdac498215240b38480250d1a4721e15db699fcb06697ede2fc042addc03209635985896259d454dfc60e0e88008bc58af144e1074019004543ada67487a290e21e278b3855cc38108833c647b5f251e1de47b55aaa6f547385ddb44dbae96a54b56d3dfdeb7351cd1576992e5356d2a2d06bb131fda0dd613500cd0ddc75d436293cda69c2ddb9f87cc3466725a128da1a4a800103d0b97be20b77e7d1e2441927c2ae13ed2e592cbb4b3735f86bb1fa7513c6b29d131640858e02f85c800e3267a47377829312911cedcc9255067787c1271b14b83ffd4bc764f3c45de73aa47fe3d77d16f26f4c85cd5c220596076a08502a852efc4a801239ce4cb386bbdbae7d551cdcdd059f6940b23ec53051eb434c24c444a3a46c2114c22ffc92857f1f095793f43b5523dcdaf8752bd17d52292be56f02ed948d5f196ffc6ad276697fd2ce5d21dbb522c6302cd3431a202171ddbe720ec4116ddc8ff0e2eef388a623c0235a78d315f556d43b8288bb1f61c3881438f5f0ed89ae8cb880fe90ee128f20ce880318e1823bf556d4fb0162914580e14e875e46224db4f8f5b60ac3af251e938835ee64098b05f49bac619d79de1cc28a8c6dded5863f8ef69bdd0ad637daf8258a65d1c6af35dcfde6530834667047c9e08e8ac11dd5c5dd6d14c08f88218c3b143e013f3385f8e13a77f7475bcd37f2869d2f3b3284471a937746f200394f13e7019a091081c91296d698bc01ee46dc3dc8533c98e14ebdcc0318b75d1bfe8338c36827e2fb4d38d3a8b64fff3fe6c09cfec2cfd34bb0168568b792227545880e36e8f0aec3b3d58874500f1b75fa6b95525d622c7ee053f9c6df568876b68bc58c65b4d3a5d6175b5dd66e78ebb8dff685f5c5cf47f5f9bc166b4db55f7ffacb7f2d76b49bcc45366f7debf831daa5be84c0f5a8f58338574bc438296cdd5d2a85b6c26c687277c9f4be56849f27d8e67a1fd4b4d21b58c66807e4d530adae663f40fb078876b68e56c3b4aebe4fe777c29f7112edf2ebba332647fbb1f06675a1a53da3ad22896d68a9de560be577728df5465735f753a8588e2508562a62dcb98a8462dac9ee11afbe8f46b1651a2862acadae4fb44abb77aa2f524d8ffc586dd736e923d9d25d921bd32ac549b4d33d9f8831ec637ddf97e5d31f162a8af5cbffa47106eb96327ee4a92d46eeeea3dae2f44551acf485389e033d4f967a61e76eea05cfc3f9afa86619cfba98e7c9baf841e62e624d535a7eb8ff502850a8cf082acf8b220bf2bc1c069cbe131e498c5fa4d2bd479f8b70653859f797a2a764407052a460651ce765bfc519e1a2e05838117043701bb8d1cbf39a38799eec2da87fe96829cce550d21253a831d2d6652bfc271c5e971398f20a77f7a3528e7735a9b35b3fcd89d4c85f6c4bec546b14b7281df1de788876374b73b9df96aba32e712e865b34e316c8d26bd236d3fb84692e718eee5ae29c11ed7e76ed47e90ae7d79224278af57312234a4bae2bf4256424a34b2e99906b4905ea1aeaee93b856c008ddb285864fa144a15bb6501f95b6dd7fae751ad317edeae755cd5d21dad59c78f1f7e9efd32b5dabe10f6bfe719743f4fb58e042295d8574150b1aed2d46d624289452fa0211a52f5a72c420bedff7b9680835dce9f105ee3ec553634f0ff5423b5bb93bf6d4f8a4fb5ad5252de707cb10e77dadf8464837811889d2d96c564b23fca5a77f95b154cd0677ef526f029a71ceae0fbf042726c4621d6eaae313be4db4824f6a9a3b52e4c404ad8f38312116a336daf55c5b6fb456f74dd809bce96a14fe2d3f14b1aaebf4b6a3a747a0ddedd397d62cf55151da7d4b9894df577edfd658bcf4fb7262f9f9aca2c882322efab67e5ac335aadf6696c6a02585827c5494d624da6d6d45fa4591058d7fdbf9da1a66ed12536cc3e121caba9652c1b0dab547b4d4146bb1d215edbaefa3399a4f4f1d55146fb226ad7649fa5c4bbbd651066fdcbd7a4a005ab8db306283de74bd953f6091a1d4583e2c312c485888b07458565848702731f511414595501f11285d89403d12d395085445a977db369a054b0a8b06574ee04e3d1f559ded6b3d17aedddcb1583c37522cc0dcbdbb75074909808521eeee368aec239cff0aae268de51dcb57f8b89aa48fdc6deccc2ad2c5d6095793dc515e6c8090ab51a83716634ff816c32f9cff8a10ce7fa508e7bff221063d5c1d67a2686fe0be16b7c005f7e36ec6dd8334794ac645e72eff0ddc75bc21003688a494caa496a4a404e0c5dd53302229180ed88e1f71234ebd8883e0423c88f3701fdec337f01daea3470ef70be0a822c49c3048806bc3e587194222dcdd35f012a3c2532e264fb9923ce57279ca9582a75c4edc3d478a88059e221a81a788bcf0145106dc9d071a25784aca124f4939e229294472dc40e140915d50472cf52045851162f057b85025642977da04091db9228915a8ab3024c918baa3802be470a002f93163078b112234c7e7ee4b5c8c0c98f9a1c20eca63c5776c98c381919318aec2ce034a0801171f4c4841c916d9b1610e15452d18010b4d4049498640918690231d8e40b8d1e353c85902a578511842766c988312a3884e9008f87802062b34751934f91cc15386112cf4283ab34151103c720c7965227278aa68871d1ae0d0c1cad500857a91016cb879f1137462e070161e243f4414b8d1e35758f0438b142fd239da932222d082672a7932c4415095177e8830668c1d7722c56ff4b8bb8d36eebe83fa0203125374f122ec01b0c03b0a405440e6ee9efa826883281b08e36eb3b4b1b4e18ff96d96969f24ed9ee53c1b4b91b4b7afe5bf760ceb2cbf286e8cb33b6a0c0c15668c5a4de9bfe86db9de88dc51267047952063eb8e22014a0c8d1ac12d6bee281184164485608342bf3f831713a18218321b411c2a8c0380c0016ce47c8893f47f511358778c1cdd511f083ffccb24d66fe117ce75f4637d69b116bd13ce85b14cff17d9ae7d7d88c16fe17c9976c6642862a317695514cba2f02f933bca033377549ada677714181db00e407d015a126f7794175db88776c60177c78192e3236825bf2edd515cb8a3b6b8362b5677d4123c51781dd40678e2a0bcb88f2a8aacb36314da5d6b9fa08401c5003e1654515a4853415d7439a80141628260accf64102b08472d854246a1a57397f2caa8294f4dcabbd194f7937a52c6fe9c7ad2060aed42b0d227b8d7c2fa4c3e09d24f504e54907252270aa59e130638619372f2038d3971c1492b8555ea8414ac4e68536b2246aac91b2ffc307c5951cc841ff4dafcb0dbb6759f8fcaf3649ff77d54db9d63e58751fd355a7ade87855e1fbdabc6d524da65bceb6ceb729cd112e74a9cfba2c882569f4b1d5aec54b5a63859fe6b939674cfdfb6ae6415df849509b43e997fef1f8a1d3942751d2dad61da7db4eafa351a3e6def9eb2672c6f75834fea6bf3eb9285f7e327592ee3f1c78bcbfa9f8c769a8e611dbfe79f7edbd2854f5ffb7d9f3f9f996a2544bbcf7f7b226b92a69fcb5d35cd6d5dc94a75cfaeab9f9512ed40bb51a8d4bae8b5b42cdf8725cbf76111af12de9476391aed2e26cb55c6abad9ff651b2ac9f7f04edd6f8daaa0dc35bc91aeb436a860f23f0300326421defbaba302542162baec2cfb409c422923290bcb94f62243720d1924212ae52218ce120a659b080a910429fcd5247e87c1fcd189632b285c54a1939725a0b9f24eb532cfcdfb9a1fcb06ee76aaeb0c76048f1f6e9b05ea968177ecfad59da69b23ee914083505420922c6e42c00b701ac34112b0020048047009c7a17eb3acef47fcdab7d9e51efbf468980e1d45b525a5a725123468c0041a48bfb2cff4a496a080c435a48113172d7e3ec56900812771fe229223cdc8ef6c5d9ec7505675b67fcf48118140a14281fd0f9c0531fa8f1502c719512fc00e883221ffcd0b3940775dc3de5c111290f6070a71ef5b26cf65fd3ffb554076b3ad852d2e82afc8cbfee568a43fcfa3a40a25e0746521da43ac0911a2202779ffc24cea48a76d433f236e73ab4c4863f1b41dc909e21448604a1de6c45531cd4a1f888140739a438b839f55a1c3ce14088536f45e9aaa4799e66724769a1810c6481c515743070010b585105aa02ee280ab8a3a870474de0c7faeabed9278ab56bd1206a94910af20137a25fd3fd217e1dd9ea502a480d30a482e454905b2ac8476d9546c3cf828596d10135853b4a02ee2829dc51114039209552c3dd6d7588a260abb40ff16b878c542a4967ab347adf058a02de21be5a4c4d3a2edaba6f977a44b95b93f0be96123dfd8b6e7bcb254c7c54aa1a26819660771533d6f7495c69a54ef540e33af74da91e425dee9b48a05f78f4644e96fb29dfece2ef06e6fa9ae672bd9676edaee437bd530df7e86b6d4fa3556e4fbfccb24fedf0e2eea91d5adcfdbe16fcb928b50328a8dba804f447d5510a15a2110000000000b31000203824180d06c3e190583ea4d7011480015fa05ea85c48168949948314528618430002000006000000060c05f108e2a2c0fa27e23275c813160f8790eaae5683035ac3f1ed0a5520b38cd1166dd7a4b61edd93012995edb2959fed232dc876b7e49c82be6346161d5018ed6f17dd281dd657835718650693cba7b933284500ab1539dfb965a99e23433dc0970e292bb4b9483a6ceddcc954c0fae876e61e5118334f80083f464fec9364bf3a59ca49a8ccbd231822e84012690a361712798c1a5dce3a0265932a2ee0f608b22e390e99a18288baae0bcd826a09dd5d734bfad65acc3d07bf9862eb968410dbbff638f6dec3397dbd0b39a6845be2a1ab67fb26fdc4a89c6a26736d86a9bf95cbb420abce292799a34e214c5b74e40b2439e2e891a1be9da53523d321eabefbd1806c97aee584cb3ae84a273da6869447fffce0f06a0cf383b01a767d78a7b09f9729f85f904ccd4e4e6d1fdc62fce6b6c50fc2683a4e9d24f94136995347b7cb2e8a6c0a4dbb80cc8cd33444bc6f0eca02a1589ecd23a9b2662643f8ff66cd645d65fdb36eb58179ea71e3b3c2e874673c7850099223811c2d064ce5b1f7936470ade688481cba513e7ad2589b6753a585260c72237d019ae0d9e985575d2690098914311d4bd726c322560410ec4435cf26929536652669707f76322d892972fb32419f44823a641a34e21491cd3a2c81d4cb9955d4beea47fdf8294e34a51afb1aad50030f011a211c4d82b02d209b85a5398993fd0b74151a21ddd2284dfdb657a8372a5fa9d314aca439502e5973388d03c21286db1bce8e78137961471cdb80885842eb3129ae018801de6bda021d41dec2a05074a6057d403ffb27031c7c47c1933dc20180d158157c9ec605c176ef4bfe6df1d93a91d325cafc1d8a6431ae6a3f88dceb70a092d58b59000c437e6af8ff5775b18332b38b262e80619881783948263c234f6b1052d09d7032dbee6d482119135b6559c770be6182a52414f541b8350b331246f61ab4a752562b1579a8afb8c4788f0ce69f1c60a5c14658286e89142b64fe7a97a09602a175ea3a296d1277cfd23c1cdb698879be58ee263d704f0624a37e2f80d5237f42606ad4af1e747b53a99ee2978e14d04773d342b050f7229e22cdd40fee8e219cc9c143ea77fd4eaf26fffaaa5650f28ccf7fa3b53668c31345e9dcba9ce140c96187398c9c8c9ea61f3fad8e85d0214bd09590e57e20611bfdc0fdb09aa974c8c2c39839d7c9fb19a033a6bab3fab5087241c2725ce3ff3709f2746954a71b6a58fa3d78e12d354cc520f0a75740095861af0e1f167573365efdcf3577376e2273508035a4c11d162bc265131c89e23b13ec4a3bdccf99c2b43f5b560fe34840bb1b70d2e21e134a98f3440a72c7a6e0cc9e25f98992454364397f420c1783e19382eb24496328aadc98cf437d5e678a2f28ebd1ca5296ceee181d6e191ecb3c34b54259cd2576b62b04ba031f7ab277b572f2daf5c89e4e3932003777d227748c1abb43edda9bd7367fa4c885a210db124138552e000b8d8e748ced43eede885849c7de21e23ff0d65856ada89f3ec1407ed72c5107331b8a505c8e4694b302dbff7ed0e5870354033159264866fee9c4f0eb75a2d6e96736f88c4d6e2a925b67f70495a02e9c0f8dea12d6860d9fefd203f6e12825a0ba8bbfabd5569e7bb71ba6e627d8e3eabd041dd733da2014b68fc9f09dc7c0ca1ad366db80e0c42c60d56135659f3b175784c6c8b6ec711d013747030c548fd0dc6489aa9059fd065853352d69a101c11de88527b469b7b4a9b7c2b5517f3432da0051ca5e1f2cf59703833c651624d6cd888b8b4b953427292b0bfda063a13c6f9db9df596b7ec440bc640b5b1f4d1aae20ac7dc7625264ee433410d3bc24200b277263f0fd94a9d9e1c51c7c0eafb2ca2eb6b73c6d053a1710856230089656cb10b6033760c2acf7feeed160c6ac0ad2dcf01b00e757e751b972a814da1ca3d42c5d2a0e5f0ff8be16e92cc79315615f28e5e864a53ae87099f18f9b6732a42a50b35ecb270d18fffceeed261c34648c45eb7734cc0e82589a3861f8403ad251527ce89cb00558f8b9a9ba39f94ae2e9e711491f51d1abd404a7468ead47a8f47985b51fe5cc44355ac9ef74e1126b6aae28f4d5e421af62dbb8a093e37e37ce1e2858d35809490c4e09c257ccd51ebd56f8a6bdcb116c7cc7c1e4b037a74ceb2a64244674c0fb74b9f794dffdd0da42f2713e01678e78a0056088d25247bcd4e7fe4f0ca95f3b0c84546f1031072cdd354a6947103e04460dd78d371e2bd355f0eaf1d86199520fe98dd97fa4eec0aa40a739407fef4a0b4dd46a4f64b44f004cdb4e98984c907c1c344a0e039f0bc2fa07a90d93e87381cf2e8f77bd70fdcb9838a5d72843fc49ed5b5cc640f380088c796bf3e876cb434902e21d31fb5fef6dc5e6865af4430df0f16ec043424817510d258b44b0b33e57a9fb4f69155d8a8734002e53516a24f0654f94391f6702dac5d5a4e3d8e7fd0d70d06a717200982d37266d555fbf68e6fca3306d61e975ad7b6c55a8c6c3e69f56b2e3f5974c55dbeb6ac9d9a1c0037daaae69f6bbdecc1b3b894c9657528f9b04972822d0401473cdd07290f0bf4054653481f19f4a159c8c7fe463ff88f8c3821860d5c0ec440a2542d160e903089e176399f58a5d724d6c0ee8affedf4446578868a90b57b40d4e330444f3e9a4246ac208e5fc1b81a03e0929030701d9bc7b66e020711d67a4345fc427613ed676c87ec6208723f525ad30aee001844b29643f4c210b4d401a8d08655adb1439b4e0713a2414228b936d000ab14290041bfcf44d80a427442e86299533039bc85463dd7284e07936dad702959a1ef8f947d0e130e9f1edf98863c9ff92717f2ec3673255ac224062d8dab88350fcef16f6ceba41b755d2940a8a142950ee48c46482094600730cb5fe6dc8875de64a3c5b71dab8056c05cf849475c54783b0e85e72917a8e6900f3f8d0a8143de95cba56d347541714799fc87f8b72fcbe3eb78119337fb10a4455f21d8a799e984bfd2f14f755c6ad73e4438e2ef12d0ddda699d72586af11bd9618fef575edc24f31dfeb8ac6659e30900fb209330b38ce1df81936c59d4dd911c3a025d1af3b1ba827ce1104b0e42563652ba0eba2a0ef8546029b00ec1dc9a99b687ff034e858dacccb484eb59fd23780fe35830e8112596b53ff4a648cbaaef992c08a2f3efd4f063745f80c163ab5af697dc54fe37d440d6a85a6c0643ab2352cad8067ce0eb59bd315ce151a66a29438202deb6bc954637c104f51ac074cea2e54005773be881329ee89f7e89761ebedafcc2ec990fc1a4b6cc418640fa4fc8668f7a50962b77dd35bdb62977048baef33a460eec8f595485e0f0d00582d1791a04950e807d1b30a85f67e3eaf2513f8a2ecd47dbaf97e67b885265756108f60dbac7f4e884589a5acf61bec81a564d70814a588bb2eccf4dfed4d7fd864754e79edf85695f24615a0cee3d173fe88f106a79b0102c61f64f12235af9208f28d70c33164c125b06da0dcc518b321158baa54248e7145545ea242e3a91428bc1b986eca7be150cc5aaaaccdad116d8478190d60078807b12ddcdeddc3eab1db015fb92039cf98e97d0acf3c30aaeb7834f66ebe946749bc0708900245fd7e9d942beeefddcb0747b4abab0b4a0ce2eabeaac9bb8ac74bab2391c8a68777d9b03a445fc5c5c53f0a8fc2973f36da5989991ab77b00021cfd1388cfdfd6cddf7ee9381e0671c0dca0c589676033210bbd8b226ef87ecba77ced76fec30829251f1219dd48033ffd24723cf8008dbf55defcc40110da51b49f268af47fceb74aa710b72684605b345ec419d67d170a1d4138e0b774fdb433364b0f73be8611ab24d043e01b6fbdfc53ec748939b009e4fd55e8af645b16006e6027d17a7ec32ff278279be74c9c47e0c27a3bee42f5c810e6db9fede02f0677e6fa9f69221d6246d25171c1557740bdce34f82663d472d405382078faa5536ad1eaf45b42f509b407e639ad7c103a57c39c17c06cfea7e423c44270fab6cc40052fb94b1dbcd82826b96e97840f9c7f6409006bfa61051a1f9c877f1490a17bdf2832a418253189bf8e6b84447141079b6254c272bbc6ddc7371a134099654676de08627bcd9dea5aa6773c02cfbca8940ea8ac86506ba2d51b884dcb7f846633058870f0bfdfe855d60ceba0bd79f92e7722ba377a05029e37cb551e3b8c1fba4b677802f882511bf13d1d05dba732f55e9bef53781e564b3714cded0dcf821ead4578d66ebc8dadf74d195fc84eb0b10fdea6be4057b0cd5e2aa7573190b417f74b354d116690c5fb68c732c6a6a8dec755bcee6f36674a619660aba1d4505f5229711dd20ed12041a7373b035bdcb4d2c5cf68fd4f341bc2757d33822ae73a0418c1d6a1285fc45570e83fd7bcfcc0c320fde5c83507074e31fdf2e5e638b54163f1067024910530466b87edd33fcf7042bc7b8a941a09b641891f042844a2ae526d04f85f3edfd1df48563b093a9c62b561a7af2e8c7144b540cd86717d363909d4e1562fcfd0cdbc97f9d34c84bf9e34f32afd9c1a89d789e0bb45114aebf2f3c30d79a472e930a26b183e295b1fffeb6a770e72f1cbe324e385603a0b378b0dc929375bde0a182675b1e94edffb4dc996d9e474283cbeb7a6d306e47723b990f002ae4d2e18b82018bfdc2ae841538c7e80d3a3459da2f824aa7b4506c4bd0f7d4c4ce1198297ec722e9fc9714463c0036a3801961a29e2614145bd010b60a8e2cae395161430872a7f552f7e2e931f4ce11ae6ee7de44f746c2e0ec5c2c49456cf1899c7decd7fe76635188d902209bc294924b1d62601095b46bb91a12cdaa1a9f927ea35994ba956e266caba92988c7c3e909a05e5d0cafe295782f96394ce4cfee5270e0887ec6e8987856228cbd1bedec55ea4131e021aaa5ecfd2958e99dad067335b40b47159607aba2f4fe8f75426fc1ea0b953cbf44b707e96c72f88b6c945fa34afcc66d4a6dc695b985eec0dd083bfd13b224baf1a11478c25d5e805001662ffb7c0fba330fec56e5a3fb88e2e2bba51353ab215367160c0ec6c76bb9c4eabe1e1566d5791de6f526bd7c69abdbc3646bf169c38e1e9e175d81196cda8bfbf195d46c20c3e756043b9d5dfbf5548c03aa494a102c3ba50e4105147b86c100573846248fe81b09ea7c23fa4aafe6a6f684a807a9c3c9f9089d2bc97069929868354834f2c06e9983ec01d0bd763b3ad084e6bb496229bf15efa85ba33eeb8f74835c9b5bb993c4e08ffca2219e82492aa400d0c7c7d2f707e4df9b78d348c5034c1d1ad7729dbf6d8af854f6fb823f19ae563e4a4f5fb496ad02e01a41192bfc1e918c0835b3a93f0b8112e266bb25a732a11ec1119cb2be38f20f06e16064226cbad63527387d140c210fc5d4f7a84d4c5b8cce4c8f0309f6d2fc31b0672864ddad848c9831183252013720289aefb5080528d0d81fdc52bd24956164d980992d7e6b75018ca17098ab12758ec61b386b68764e5304fa7b0259046a8c820dc1f59f6699ea0a2d5ab5a9aa04f6c1d108d62f6e787f48363672e96fd6618e2f5a51231d47f0970b180d7a6b9c5a4243f89ca3877ec40d118e6f6f8ae294caa33f0e099506c3138c1945bf0248e5abbc28403c79fa82d1460f48b2603a55befff5d867d1dbb24af65833123f734bf614d5b0a372df72182fff2cd2acbb77d5e40b62f8fb5b21c833f7d2525d516f23abec2f98067fbab67d3eb954986411c2d69f6da3843aa6ea2eb8627b9505746bfe8cc800712bd9677caf1c87d5f014b25292fe1cc29ef4fdf89b6dfa36bf044ed3743eaea6024fb3ccbf1ed188a6668c2d0b19bddeb0199d9502abb7a250ee42f9a6d5a246cfe3a88d42ec80ee176b5822a5b22a8aeb1e8fe6087c32926b4d59bd7c77034cc0f1dd9af431e6698ee06d8793a96be0771b96e745418a191813f34340c2881f62bcb20047b0fd1d17d04e3ff34aa0c0799a54ca71dc5ac4cf0bf809c5ff51fda1fe3703eff909043bc0e035d839affb59833258ddc7d84e3d7666e938edc3909c7af4d67ef95795cca6968d78430df1b7b74cc8f36bcd2f9e4d49be72029469ade82d9638c5beffadcb0b7e3cf0eb6ac05f76fca29ba39a174793acfa68a97f8bc359dec3812caf6432087501d1a3876978707280dc2bff96090972b0501676b97fc5b3f1f7a98a794a9242cfe3c439e82fdd74178b1c2561ed5a0dea3d134bc19f2380a1bc84575a7bb12dcce17907108490e52d06bd97bea11965adb6bedc03a88f2c41e78aa788ce77a992f7ef2f3e998eb0367f88896bfa5c51f1d4f573683d7e4531ecd7d8ec395c31fbfdef6916206921fa8b892b45a35e9c4be5db2b72c7c7a5940c318c91586179f0df70c43197c0efbc86483e73f71358b3f1d42fc84152f86147c606f1b2aaeb581eae1446be3df8b115975d442303038d7c710ba4d21b480cabf5f102027b6fca72958587bc3e0933b2d35971a5ef33168e36ec887a43e23d941be69768eb2f14abfd2bef11b135baa5bad7c64e81668bd44f6e43a2d7600250f5b161675f0e2539684ea994bdc84d924c3829c8c0ff90d7c613abb7756e8f91644bd25784c91d6747cd9cd06ef5d2c9181ca07d188e4cb4c8dbcb473bee5f1052a0d6a3788fd72b56167cd0cb9ce8310803434b281050ef6570f80d0afafe5979804392ff7da79307f7c20b25855a064fd5bc84a097e872283542eee33242da0eb9f3f83d049d6b188e5eba810f3629a611c03afdba705777d756d36f3aa6ba8dfbc801d1f8071f8432fa0b6a07ebb923d64b68cb5f3b04ed3c3459edfcc3e7eb0eabbe8b0109ff2e46606e621b531fd781de588436f6fcabb81fd56bdc8bf887d7e1b7dbfb1643f481a683070b611e38558d6577ed38c25719d3c077c24ae7cd93e680c08cd947455cdd763d34706f7383209c884e2bde6103d6f76e0df72e8913bf88f34caaaa1c470d88be6e7119fd8c44889e19f70bfc943be8f7868bebf63fe3ef9b62f1d5e0c1d468a4a75a7df57cede7ad85d1afaf44f49284846d50709f6615e504460b48d720c419709a7a3951b422a2a20072d6459eceb07b489c3b8a5c8a414a87d6bce0e5db95d0f0db7c945db5f94305cdb7e7ac22044718daaf8a1cfada48ccdadd6746061cd9e4892d3e3a43544911f0addafbb0f0d904338bcc2f34236d8d27ab32bea5fda8b84522c502bb4d89b1e59f8563bada56ff3ee6b17ebf3fffdb1779e90767b408d20a9fca41e1c9dedb0b9c569f67b66159df538a7dc5245dd00bddf78cd7bf83e1d1d524a6fe95b14c947e1ffc2d64fafc1cad76f3a23cafe0c763ae8c4bdbe2b0ee694e7e85027d187477f8edf0ba68544cd65c303077dc1e23d64d0385060b08443dd1fd0e2303ee6fe9a0f0e2599cedb750592923419809c41149168599365fe164fbe1e8fea7c746a5636d7234def88f710afa4b9122d22b677ce590836f67ed7f399810ebf794c0ff7a40636ffc3807f0bf2296cfa1506f65a989d2e6827d1b7bfeacacd3bb2d4f67190171518e8065e6811de2c990d9c20440060b945bb1404c3d1e7606c4b26a77dd0222be965352d1c84bcb0078bd78a5e5b454178da413f7e7079d3d9da25b8e7348f5dd286c9bd5051b04c95633e2bfc7e7a61292854d7d17031377821ee2b501a6afd35b299232484d9e2b45028ebc314612fc60d40385fb8020f2c11f1e64d3e430c300537954a4d52f7e072633b5dbe0436aadc6f074013f0969a96834b54c3e65647694d433051bc1cc3d3c5f1570a21e180c1ebbe5ab926cdfb68cde6720cb6e6fa59746b4739570021e7e8b513ba3289599da75bffd44654ab87ece2315fce28a5482460a3ee7e2039d0a82f622e669adfd2599300a7938036e129c94be08d6670e6c619e820d646fec001956b39301edb85f286484c92e2b8c3d30260a873ae0b6bf266976c3db25d010050f40563a305fe3396c19e9364a9d890f4d3b0f2c88482be8a405b5b95519fc76976c45be1d945bd821f9b8e1121b71d68f8f7a6e338934e69296d2d82a086e7032f59ecafe67774e91810f65d073f021ac240d36272812bdcc0438384a6c7e7d304b0b8f6b1e8a0f4a39385564edd7055d4704c6e64d26d9d6b6057c59d4195452f9badad82654ed49718eef8de4be81e54865ed62e6e61464f0acf8d6f3f6533c9bf03543ef072434b847bf97a529565eb290815273b6f86fa0cdb30cd10821601ff3987840bbe3ee7c0fc21ef78fbfb1d2ad2b97707018e637cccf1050e33641fc78ebbf90d7945c36ff5864f8f2b82df28673c76e8a49fcd4fee4f85eb1064dcca7e0f26f4d9d91af1fad3cbf37132b5c549ba1510178e1c059efb6619cb45598847b77278c0bbfba45f5ad9d71c9ec3f06007ef279d5eb7bb832fc174a97aa14cccb89b0f0b512459ac82b761c57f2586d1f8198b19c5f518e40bdb9c9244d4881bde83cc26041c138d11992b3e3b275fb14fc767d6860093c37d8a9d6597d9dbe9d019622f52ac08e99390414a4098c26c5fbcceca250799e14ea0e4be621d2ec828f5b54ba54058a1ef1b7f44af3e955a1397d061eccb53348e9ebcb167cc2e06a6c115a2da0b0f55f14e8bca5a1656a34d8c452c15515caece90bd8c4d764bab380aa535ae93c3304f0e2f13d7302022650bae99a23199081a828deb5955738667c3bbdae78606dbf9d96dc2752589112dbe8c594665b900969fd08c158b70a83a08d0dc9f490d62bc0e5b5101e2f32bbd23313556e0e5d7f9fbbc275d043b9a837d3fdb7215a2793aaf465cd57aecdda38c3154e30ce6ec10d700e8dcbe815574f08a79d85ec78bb5e8a0269b12c2a4055c09dfeb1ebc1172d320141021cd8b14d5aee843169d43834c823be65e8d74b98a2feaaebfb0f55b5b35e284f4a93a6e1900f3d234ce1c71f66a38e0bd22d0d35fcacdc61171d714c72d91b44cae9030001c6b06beb0192aa22a44c58bd4b2c9fb308bf934ec8b84221ea075965c05cda31d151aa2e209106bde6eca4ab4cf6c787532500fcfce9ae6be96f59732a591cd4c8ac06c40b996633a68ef3da75e65bb36a93cee1e4a782c5cd06d7fa9c5cfe0516773dbbd3dac82f992e1c86ef0fe93883ca29c7c19e1c0f754859e388019acde6b3d722a9103714d16dc62a61d76bb583c44e88f57e762c9bc7537dacb0a6ee92bfc1a41952d839b0f45ce8ed0575bcaaffadbc17fa8ba6aeb35c5c8b8dc8c21d00464bffdfafc6952e64f4322fb26a860dab46838be5086b5776c55190affe7569f0f6c0513ffce22fc465c5b1ef854c729af3d73ebab37fd8afcee052e23a3c392b5e5c86c58398e6cd22673bd998fb7808613c15c76e474cb305dfbc10bd37e8314e9bf5fbcab1e589e7cb2aa58a978eff824ebdfacaaf05cc7ae5b663d6fdd89d465509b57f6147b9349fa78ab19dd0f89d8e185c39163e6146c1f3a3306dfbe80a7cc397a46ca9824748e00211de1883a691dd73cb106001b543ae4cc5125b9e2e0e538c728dd8443fab97d2bfa8f0ea938186f3c1510a7c36b252efb185cddd7aa4f726a7cc32eb439f22a0ab5adb910e385f5663447f3d7df06a6ab5222072c69adb29068ebad421b77ca5deb907fba9dfc6295c29880675e1d822da0446d36f1c1cb8edc7dba7f0b4e7bedc9869f70ff8f8ce05455d9393e4a2420dfa805ef799b40f69d752afa17df2204b418a09796ccf8805926acdf182765291b99d58f762e8b67aa04d84760cb3f9bee751047ab497161dc3dea34fc8cf134874095d742b5bbc5234bc58a55d239c33cf3c71d1c13b2fd2c08cd52ace8ddb94cc076b46a76afcae7582228383dcfb49ef8133bbe010d528149346ab7aed2894f74bf06cd6f63b173d055c6651086b33a67163c675f44fd0839fc7cd6a12cb835d3a7706cc7c3cdb6c7c44e394cdaade6b84d17ed918deb4dd5fcc374126dcfb2b03795bdf6508264d56ff454ae42dbe79147b5726a6e7d61555741dc29f6b32dad814bffd01c5ab6c4e1ece03c8b9c6d28c3503db3e1ba4c521c5e87c7469911682530e2b7db0b39bfd82bb71a667aa4ce31b1e3abcd7fff1c72b37b9e47b45d11beb8bc4303887f06fcc1a76c98910e34787b5bd21720bedc44f76bad2de2b17b73456e108cee146e1fa9edb777c6527bb0c0ebb91ea94e6e386fd1240338fb2eb734e78122bae58e1ced1bfe9438c71dfe635c4b48e69d04584e70b0f921b392e7166d1408cb4a556c6a7588bec890ad5eb3b88e4f5e87f6015b717ec6dd815a369ce863e0b3ab65f4861f5206f75ddfc8fe48382d1abed6e8831d919227372c8c3788998b44da61b66cbeb6b568070c6aa09b34b1a2582898be304869431982fd42b1caf60fdae4e6c12e1ff2031499d076f5fc4ad9df48c9293ccec5356dd92ccc03cbf9794c6cc7239b810a46082477bee5a83a962c0301ae7061512f73d52d77f2c238763ab4698752a51e179a9648e038aaae70562098d31df9cc868ba6aa11bbdb9e9984a571666002691433214053fec7bcb755a214d5f4b696a5fb7adfa47778c01aebdedf252197af2d5da38fd09f27b6861a3620951d7601a24a11081284dd9aad9caa85c5b971bf62dd100556a3e932473d3cf059fcefdd34d437a3b5aa194d5f18b40855b83a25a35473b38c24b1eb6acf897eef5872bad2f0f5bd8bb58f0d500c6f8ef76f11f17b93254144fb269fd43e772834bb8c6ccf019b08ed47f43b9427e1ca0fb19d27bb61b84203ba5326dd260f5864864fa9e4ca4800ce2c054e0404f6865eda585161a61e613e9531c740fb0351a21c6b5208c7db2f4bdbbf9622e394bf9e13384f318dfa8a9a9f8975d52d58f89a72020fa17d7d8fa4f85ec2c3d4c8fd207986c93ecdd3ac8b388d729d30babccde8dd02d5860e3af18a134edee12f100d4709d51b6a1ec9b4cfa324f849fc3e526c74452bf0ebd4a7efe91e3221ec0127d22302ca9d37f18df55fe928686b2918fc43c9d6a4d452e93d3dca588cf68a45a398b3b2e31c05de3cc55018d32822112822c195e63acb99f956f86ab00db82d149e119b836243080cdc7e40817cc9f3df4a5a0d540a7d8e2796075dff1a820a13f05b41c1fb8b7705bbbdee6be35720b276b65e53a51497272f1e9cd5b98339704ea0544819f8ca558b121bc16b42e2b8864d25a7013767f6b5d9ebfc609d33628290202240e982768cdc9f734ec702b90a5b5187bccbb1de0d1905ef282806205e90a67a01f5eacf3ef302b285773cdaa0d08f5dd7873d85666562e99128f294d9cf159bc55c9c8a28ed57e2261ab13a5023234b411babc1ae500820f1084cd12317b7df80101b547873caaf06cbee836d10ed8e44aec3598fe126d1b7e65c70c121741ec35075d48f2d80ff84ea1753725385864af4ba969fad521ebf30335a3e38cb82710e42655470ad2710ad1ad280cddf5b40f26f01c4c7f49d1b64a5933e8fe880dc3710fd613035a3290196cbe3b8bf8ea5add0b42b10c13ba45a5fcb2f700ac6ecb2c50d97e6af9f4d76f16eb1e50fc6511dd700d1c972c35b8e62904a0d0d8f64d31ea2b91e4bac29c7c6735069aaa58a388062748f016a79a8de0fbb035d75cb9de73a6b6ed58c5c947df8836d05e5c0d511a82872c046fd4761d1d1e83bc0381be0e18d00936d29369f9b5938a92201604a92be1079f8e91e7fcf7cc0b4565222e161fd3c93defc85fa7816d5851258dda5592da5283eccfe96fce10d318f520cf7731f43930531437d3719424a96c95a620f994280896b61106cfc3e7e3baab02df2c7cfc483a84da47e73e15c39d0e004d755ecc4c71cd50b169ae37f3bdf0a6982498260983f5a301136bfe63dc4874acac3cb626cb3a83abfd07897e5062b1b1828d00377d086185eec624f3cf2819079a31186062b125274ed89a9ba6be6e8537cfb51cad84c3161a08b38a5f5d7e700c1a103ea2f4f46f2e1958bf554a9ddfd811bf375ba1da29350184d433776c12ed2fe43ca160f46b87aa02f4978d89fb58342d0eaf82b5c452baad8de6a2f70e84daee54b27e1ab6aa19144c4079c5c2f971221bc087ddd8fdd2f7abc589fec97c63916a1b7ec6ce359bd10b7ddda10d52e1941a2d314f3fc21fbb6cb358bd6b527a23a10349b697e7ea5840e4ad22e75249d0829ee8249e375b53f611320cee8ab3be62723f6f666462405f61635fa088bc299fbbfdb67af0a941a1ba0879ddd5f24e0832dd27f4d37a2f3565b0f744ab9ec6923f0a35783636a43bc0a7a5b3aceb60b279982e67b2b43fce5c3794a88749fcb8001c0d9c068f683355569aad090b477bb08d242bd219b07b8f301f7f328d3dafd750a9ec178a10ed50a234f203551934f96d9d82203b887a1a531dfd5021ed8aa264696683c2442dc06e640f411e99aeb25dfce6883e4b20e66a12848533f9e4c179e6c667b1be8cb7a68ea137e9622c56c666f08a0e78f32045c7d239feb2ae61858333402d2600b2846e4ab26b42940cf9a3b815c12f56cca8b41f172db2c0128ff80d9d5772315768bcff19af2c3ada97776a68d70b21c6b972006f8ded1e71b6dc17c2598a786b53dabc99ed86f271dfb80ef630d8697c0c37179145f2dd851a398cefea9703e68146662d8844cd9d1540a4fb9acd052cf16c56994ac9e9c3cb4097759579fd3e056a9f03c8d7655363896aa38bfe72598aee468bfd1c9f5b4c10ea189f2dbc33f7c80fd45e545e1b9736c8a047f2700552e0eff2314c766cb61972041178643f4e23d5c96fd9231205d38e3480f56d13c19c1e2f743e0cbac20d3f2576f8d3793040aeb255de3662047805975363c6918ba5f8e3c80757bb282b123dfa51efd8d7b43c5e5dc7258c9bba0f7749b2ad5af67448a23615b0dcd43c559ea7e74b367f23dd719f7bbe3fa9ec5b2a4a82af9b36608f8e9122e362b612abfc6a5793652aebf021c118145c12a7029649743ba3f2a21a80df5a52a9215f584d194fc777bf9d389f579bb0e06a3ee8b99a78b36a5f15c385ceaa92189261e177c8eca89489edffac2281bca61bb285fb7c867c75a7458a331c9af4465541be1873ebaac4197b89655e0f669f6018c421dd2e5c6cadc2b0a7d6e657b3c5e65a95ffc87d330cafc42f01ef82663b234e08e5c541ce1cca0e17b861bd7a743f4e68330b88444512744385d6870e6d2c0311dc257dee346ff47e7560ce98643ca316f5deb3af37d85f930bbb0ac671cfdafa36ed79da4edaf522e0464e7fc9b5547ab22b1423453a55406c02326c3ae636db885b40ecf4ca736d4b09984d75077e1f1345c48dc710eb40f842c8c260f318ead01c588e62cc310acd1088aa687716fc163773cb298f124133aaa4023463f0cd52d2eb7f323541877ce48cc03f075fa2591790da009d9975f94af8a3ae6f123fe09acf17892fea827c4bf06eee9cfcd1a76c446bad204bd3a66f8f26f9430ffbea5bfdfe0bbadcd676e98dd58b65576fbd57b4efe91efc20fbf773197bcd6a68f2f9edc33001ee6bacbe7ea6fecbbd36f3faffe35607d212a5fa8d6903962b5c3456c1f95f4bb285affc71a3739acfdf56293349b782752e69b2a6f0914c8835ef6bf7da85b4467e2e712ae674d5b021e0d2157bf7c6f2f29ebe957994f41ea2f12d3eafad46e31f72fa7f0a53994e96b2da8f49bc144e1e602cf07defbdef28211aeb6a16bc2bdcec07c5a3c06ee39a07dcac45d231e0c7406e1c3d5c94f55fe2947ffe0ff80049d03b24f147df9db9f6e871b027e139339efbfec12e960af07e90f257e142a33dd419776835c79a3f6bf188f20c79e303bf6074ffc1b5721d8814fd35d291e103b4bd2d1274e9a5fb8e34afc837a889985b76c1db0f63a3cf30eaad9df2f0fee218ab28175e53df0edf16b4310749dec874e288f5dcd8c47d81b2b7c7f7dd3b236deee72dbe50ff6ce4d6f7e05ae3eb9fcb4f0bbfa74fd8187385fee7cb829f883badfafdf0a27fb2af89afd045efa6eb072c4f8a8fc90560176a934dfe989b520b37f8fd5eb05e386da7f31a8ad256cfb0bef06f9fcc31943fff7b6418936c4301ab38a3f3df88e3febe3985659fa7793e992c1ba53dc53c7764c98a97fedb6b2c7bc8e4c28b679544f455bd99aa6d8867a1cf3baf876ec20eedf4b51bd848d9fdce0228fa3eec80d3ec7b8b20745c408ddefafec8f60d59eb0e8c6db91e75b80502714c93d5da526ea22c010339e3f9f75e7830e3f99d775b08c79da87fdbc3ccc9a72d7c13cbff011a8c942f504671f85ca5631ef43879af78afe1f48235db9ad71e3c6c343f07c3bfbca35f452a904b8516d344c433b9854e6de32fc2161cdee6fc3611e07e5462b14b6a1d75c9907c53ac2b7d8ff42299377f5dca0500c345d7a65fe41c90e9f4dfef90fb3a09832bd2099558e52ba3cb67077e741a0ffb8f96f3706a191e4ee0ed93afab2eb85f407682d0324fba4998baa08a3c30db9adf96d5366fac439dafac65488a173bda2396e0899eb46ccb9a8689f19dcefbe48e50544f3927366dc2dc327fe471ebb031ede7cc1788ae5a8b394cef2cbfbdd3ac608f1741895c6cccd2bfb64f6c94153ea45881a4ec60ec70234bc7be0032f783bb3e05e88977d4371bb8d8f9b1a5a01c8ed7d20357663f2a2fc3f8b05755fb3fc7f28dd840154385883cc606a8cc6c4321ec8bff5643be57d4c24309d55bbb7e3f36d943194dd430874266be3b33bd2f463fac2ca496aac392ab011fe6371ebc37c46a8d072ba49e6a6489e05813f5c90703a2a6bb7867feef1668dbddaeac7582ab7ff09bcf1382e2c4ec5fec1a89dc99156fcaa7258e8866958450bcfb3e95e7db658450c3aacb1c3cc30e68c7f1bc1abdc8e5f10ce50d8ed7ec1a8d6e734c9dee3b1950d74c832191d3dd1dc3a0cc01e006616d6741405b0aa9f6243af1a99c2980fd7ed6e64b7c582d338118115cb9523d0b6bc4b6ddce86a262bfce063ef9ba418e6ac387130cacd1e17a298948699c05e675a783c62dba8b321880bd34f80baf5787956f95d1578d100cddfc0ae14fcdff406e4de216bfaef55e72a21b7bb42408e44b06277493843fc4c9403c476c90717c41cb6b8ef53791f19e4e664d750bfb84c4a229bdfd60c227a8ab2c147c26e600222885df06ac46cb27b039dd5ed162e727e65f785be873cb35aaf867ff6eda1a8fd5c01bcdc8d100b174ae08ed6e21c7cf8a8549a64ead3a0195bc0fbda4547da2c6fe66af80bf113aad814b1cf6dfae1e8c7ab59cd2b3047cf7a9ced69d061dd56f34affbb39207e5ccd53d62da621ad723f4e2f528059111d40dac226b10c9a78818501c2e6d11b069fd01b54d95d1fd5c617e366e4ef5a9e5a446888f454b6b39ee005f27a25ef61cc2f333c47ac5b2c27be4e766390518f4aec1f1e267e3c913c341cd6d1c92b70d3b6f3d9cfa9f056c484f74cbfe109d2f0cb7411e85a52fbdebc10550ebdb6faa05ce227179e87d4c6e4e37594233836bd39f6bbfdc96cb955bb66ecc03500f1e1ad8f857fcecc2ebf23a2dbaa06341176e014937d11523793d038349301c173f4c93d01a03880a0bbc5762b9572fffb0c38414d85879d7f8d3f7089e5c3f03899deead317c57464ef35ccc2c2830ac2156623cc79a7ba348c8b4cf67b78db3ea1f353302f50c40f3263c3d7a6f786787d4132fc5d73f94864f463e0dfa4f817fe0126ac4f47d0136f38b1c34ffc57813f37c8e1a5f4090bde285af4f2ab1bc2c0380525bfdd0839547b92be07905b267d1b142fbbd64b02dd636b725c1798bf96da30dccabbe69bede0788232bf537411496a8df78e21e17be7be3f04642932296fe5bd4dbef218c6f548e624ee603e8a5f2bd586f851b522e426726efc0be1f709eb15b684a5a1f7c106cd078681c98332f3836f742b7dafb2ce01cf2be4de60e2b2a5dc05bf01d8b80cbfb9702478236c44eb81a92d0f8f0f61e100d2a9b75e7ef3564159e30b3ff15eaca17af5f208f403e57a641b73be1c40e5cf0d4e176e7c56d720cf41e7298eb9256911e1db860dd74657cd0c3c8e757bf4a9bb7a7832e52946e03eb29292852cfd9a11e1808770cdf84845835947b42a4fa8d10fee113c98acc01dd4832a99ae76dd492bcccadcf15664ec233cf400b3c6d4f1d5860f9dc137ee68993167efac27f18e5ed44b3b5e019f763aa8adfd8bfd408d33f244f734eaf127b73867ca5c4f94cb5f56069a78b05196f17903f69e5addfc27710edd439a3f79bee5799bd8e25ac17001e4b0f836d108d74d5810ffee07264924e3ae98277e672242108235c902651ea5c08c25ccaea9befab934a1951081b1f7699dc70c6d278dc775c614bfd880d337f4404f44f1ee825c8eb4fc3411011d109edfda2578422a478de3967d010ea2c9d405608da6525bd2171423fa7d7d6f1ce8a4767866184947c06582d7846e93e46d2321bc73acb9354ae3a9d14cf7249b36d4c349690a2863da1f3ae3a41c7ba87655bc299f047edf7313cdfefa7b509c2c4c32cda273e4a1cc793479cdb4cff2016ea9044dbe4fe1a0f25ec2cfdcad8db31a970bd0f99041cee8bd4c0042764a1eae5ee51881b42189b8c5dd70d87c27f3cddc3029fa07871b6386d9e1e9953f420fffcc27781efa4145533cc18b623bc5702d0c0e133bb92af4f0aba1b09d16089be399159efb0980f7adfc2fd71cf2adcdb01a3c83bbe12c885662d0d27ea299973bfc0c0b85014cd1219a540173e02b8d88c0ad8b96a96e9aa8f072bbd20d026f4524c1fd746d6cc1e503e397a37b4b5ad57d3fba4ac2236b46645847519deb301edd0080d4096c60117cef6cd8b9145226a7865fea8a4d52286886383783742fdb15a2f57b7899667421f5612b8db7a91e0d68c4e8b7cb00c227a0f700e35e32948be40f62f6bbcfb9ac244635b3526e272614616f95f03cc7bd4e4a459b0317fdca0d2d3715ecc47944b0ae874c90cf0d03df27c8f60d9c5ce52768eb3bf820518ca32959f248761bbf21d3e6b4e9996f9f605247ed0822381c04a0c05d93b2f5343775eba913cd523e39a4e279043812f11fa0f71076a8d7474f99f79b4db62ad675495f3902cce7f802908f101f7edbcfdca38110033fc97709d7b2edca2aeec54d599cc2a5db86f8e58bd04bec040b8470daf854eeba2fb930571409c9dd7b9fce829f926ebbd7547620819a0f617e3bf3d34aeac88b13fcd4be8182b61e772edec7fd9549aa58bcfe23221cb1428b749f3e05a3edc7807f2493e47bc34d011e2a5f2c37ae624b182db9d67eef0b26cc87d55d926a17fba17b0f9dd14f77caea0ab82af84286a352c324a20b49779aceeb45ed24d8c2e380fc894235b16bf39f6fa321005f37d01f95a4dae8e7ce2132aa1ed7bdd45177c3b412fca272a867793a51f2b736bc6c6927c103727e3eb2081254083d74539d0cb4792e16e16a0f5a7b0533964a31e851c5dd6762f6649419e6fb958d920515c0ea395cf538ec04d42d7e4801f3ebcd3084cf6c89aaa3dbc696cad2561f5647c3ffbfe610d6e0fbce6ddfe6ff99078fb9c77f15afbdb10a6d4f1123b5904151b3e6819364c360555c38442aa7c1c8bc3cc5b8d4853b964dff0e61aac91c20750d557b812b72e6effe347f0c3df8fb4946b53453ddd83b351422d15a938aa6f186b4e0dd3d72deda3254fd3702fa9e68eae4d8db5b460882d45afd5c6fbc74ae44f2dfa05bafa07c35018dd4677593c3c63874e97ddcc716a1bb7c6b0a8d15214ca9ebac63335c97618e398e43f4bf6ce7c1233a550d4d0749eb7a2c7a105eaed15f852317924f147fd41972fee698207bf0383bc322a589ac1313b9a78b4a6193076f7290ea3e36c7132e41597bb555006ce90804e47d264601c8a4014e24e72dd6ae353a51a97d8e19382cf58f42b15ffa637f0e07880fe914027acc4d01ce5b8f24ddf3746ee7d3c4cb07bbcb2f29da8da1f31dfa4f5493604a07557d8bb997ab63e86d51724f72db36df521329d5ae169e36deed193fc0f46d32f535ec57ce0430e8e0742db6c52452cefb3ebc2233001d49d66cb9865b116df77d7c463dc6b094ab979eecbd796adae9c49fd887b8c30d0b4fba428f22a68dcf3ebebce88e08bae18bfd8b6fdf180a10295d590f145c9270e4809ca85dd7f5f089251ec57544cae907765827f904737a92664a285fdfdcfd32dacf0604def890a1bd7ce521ad91453b6b3e8c8658a3618d95503e1846ea38c1fe98a484e26d28716cfd0368af2c9efafb060e44c01a474a7fb969215bdc6ec1cb46f730e21d6c1c5043e51242b439bb89e2398ca2e3acc677c2fd0c04ccec57baefeaa99baed66a78515ade04ebe16865cd89b3b2d21866e3dc2f5f1519f9921914b565021caa1de8a2badf45198b8052b6e99124dd65af8b447dc6c60f29b514244ef69d8af6a3a388e2fa74eb4b789fc178d3057059638217acbed94639b6e20cb68d158b90712a02a2fd1431b13aa2e91bd91811539e636aa9a30b6bc91b60fd472ae6a6480fbeb37bcc6bca1c7c0339b2301f7542f58c7eb1a018f600fc6b4a8c1d9b5de11fb0aa54ec02ed91e1ae055050b5bd0db673255d0df283b4f9a9fce270f4e156de1f8ac78a30c6c8443f67508efff4f3b725e423dfece93d4486d19f9733c2f267e5dae814370bc0cbd0f15fc369c5c8aeb85d7797cd781736d47701ab5399e5308646fc2a0b2a345634ca6b4794fb496e1b9423fab684fd4d49ae41d655a067482f262d81d877b650a9e837a3fdbe3f2ed6479d258a940584ce6ad687a6c258e2c2c0ed8700a67a395600674b469d5b379211e7a8fee7897226ddeb0cb8b0a46ea59534a9a6a8e1756b1be48d81376009d26082c6d884a4d50b8ea8522b1a8ff70691ac704436e53c2114b12e48d51badb0a6cec07a8fb0b79aff247fb450646b08741382fdabe7f9f501d995f0d653a59cd9036bee1816d9d97e8f502d92216ca4a8ee6122422fb841c2b36dd57ee4d7ad40b0828771f0ba00e4780c3a0a05be8b34af7c98d214bdbddd903204773883ab8ad50e3755a68ce4a1ec480e22c4bb24981e2a0a492202f822a70fc7035f1ab51867a40547081a8e0c8a5ccd6e75c32be2b43ff354ff41b222d7a602538374c80dda7add9e8cbf29bdab4d642b9432d1d8213e086c67dabc40b3f5bfdb6c48b16a9478cbaa32cb5c057fa82e5b694eabf140c75a6d22d51aeba918535e5decb7b4d7ee190cf005376f0647ecc41b00c5a30cb20801aeaf2cb06e0249fed8125157c8cb94acf7c9a60c5ac8e475d76b79a7457671631c79c1875622f35c2f2984d583655b90ca8debd2c7359aecd26577598a7727d67e1cbebe3b9f0a5b12d297832d430e58797072f3307f85f564a3e8a621ff03b9d12d3a5752d27dbcd222c09dafc86997677e07d915e8ca6677b73b1fdd318907e780e5fa8ee0363bd8bb28d0a30b4c85693fc905f8c93fe61518495e69d7466e664145c1a5483fa689b0e27ca524a66e96ff8f72007d0b92f4cd7f5cd1a0af56a980a92d93020713323d4e92aa1b32844a5fd7a4515b7f438ace888f24a5528f05cc5cb41a2879e46c5bc05452f43161387dbdd74fdf58c7374475d39b63b6431744099d8969912416cf6fd1530ec76ace5236d28037976f63d49f041eb196673ac2347f31c5528082db84854d4512d94a27788e55522122f1d69bb4bf0252d9a6d5f83ea441b651559419256aad7d21968f39e4c57e9bc609c5a2d34e77724323f46acb0e8cfd67b1656c550c9da21d41b8cacc9ec74023e078b49bcf9440a45a09eb0a46d56cc84306ade04b38909ab3cf6f25cd2da57f14661867a95483ed22021293162d3e4c28696d7b91f2406aa7fe3d07aa64b5095407a1468c3347852d4cbe680370c25583fc7e328a662855cb397c63cb7cb67bc12da0ba97097bc94ab55952244424a665126ecfbdcd85408ab69fdd4191190ab5145f51e550fce49b4c634ad654185030c2845aa4be74700295a5524a02ce356ff169567f3872247c90df47a88be531b98d4ca97006b7e6241a90c3ce15e0a99150349bbff626bc823dea6d2d51bb7457c2ed3b7c00e8fa14acce5c9e7cb41623ff9a8ff96101bb2f31ec9da9237789cedef431d4f9dae4af76c8a98ab5f06b09884d2c60df6fa70f91bc763170c6a6b4ca4443f7148a3278dd43d0f2b123c96ebdafdb494ae2c4807a11bdd614abac40a3ec5a8fe51d8ecf64bc3dc623a29c01c654950efbfd61dbc8bab131cc1a75cc84f0466fa6fbc3d337a536e582e4488f85db87e9d9914dbb60f485c523f2c0278f0bccb6d7fa1fc4d4069825a5fd4698d85061ce223e398b73a71ee858a8c2942109e0ea0b292a6c20548e1328a1ca2cc5fab9ddc5d6fdfdb3ea82f698862fecabde45b030c0994d094d1bb8ce84be6e9007d676df8df455187e8542118a900ad17dc97546d734801c3de11b10a36fae0baa36bfd676e6084a683380eb0ff02540ae0014b347a18116bf982176dc65cc7bcf221d5f806b0ea85b53cc2b79c23caa2ba7e82d4d0af9a844d732240b1d73c29928b555886ab0ee6e06c3bb1968de056a62995c1bac9493d00a877b1c4c21d9f9213e95cb59e50885e3a973520d71e66c543e3cc1af4eacf5d25a2dafd9d1e3b4e389404651abe3d7b01bc1e35f02a069c5f7f9fd907438ef1fd0542bd3be89d16a40765b9a0da9aa4b1d966b2661d69cceb160cc86e9a26398ef270308306d10b58367d0c596b4ff8d4e1c644a6dd133a7034877545f4b4276c392b1a7d1044ddb4f6cfcfe948fa1ffea588647d2ac8163706e47f7593f37711b549c7c0aa118dd563d4d42fa7f7f249b6118b08d0c2d5c6bbf71a4e9f99240d6057a160b27dacb0c445f05f84401c37003c47b3c9a58411b2624372b4a830ff527ba24d7736379a594536d5a888257ea8daabddbe32c337e5bd7182408635715002fdc5a5deb05c39038fde72c03701c387209228841dd3d3e8e89ff09284f65a45d45a83d7b331f38f87990c9933bd8834d27d35e45125ec6aa076a01101e7f7f1c8920d80138984e3f3a2b264e9edee2d554e64d4d2c3e127d084976d8e88e81c93a2171301fdeeee3ca405f94d88958b941655cccc9bc8d559405a0750e658a8adbfc0747f5794884f18a29deb1460efb050878fd4af2b022b76cdcb7ad2a8136f1eae8bdd0f34da2dbdb723c2ca824b8bd29b13612b4e08d158bd4933be323a8ea5fea33f8e4a92012d76916613081697b63d02b1d1c0810d66aa6304197da6e3abdb24212c7f46cc67af481ac07472f8f1b0078c2b260384ab711c1f95dd634d02922301afc77e96ec73d639d675ae8b03f813a3c23501f606d91d0ae30f024cd94b9897087916662b7c45fc02c34d2080172709f33ce1f4f6fd53a03e24a7c8837f58a16f72de100e21fe6466dcda8dbb2d9b5237e20dd630abafbafa4b0ad8bfb5a146f35a10cfce9f02593557d4876b9c64fc91e1e5a4c904489aefd1f5a1e49681c96be6c2997abc0f935e25619f2448e172e73c145d88c8d3f8f79ab46e5c23053a954dccad83544a8d025cebec8467f296d061424ecb64424eddcb15e82e3bbaff240f835a6a699ef35e56d6f3665ba300b68b6e1940631cd44e7f21d433e6436e3cfe0dba5017f1a9b68573f40faa704b37c22987ddf8764f11f01bc4e624d3268aef1f98045e00213e70e4b629b97bb3c20cd1c27526da21a277c1a68d2022444eb3ef3fecbe89cded59c746cb80cc1ccee08f59d8700a96f7fe467076957f0b00dbdbc8cb5653ce8e8da705639280e969a58d67429c873d369f5991f44838e64bd66607e96e7964788377b8c2b16e85de5d5a23edc84ec1a6d3af8ed985c659bd9b63ade5646ade730d56fc0ee72be25697d7f89e5bfe776c585c598f8b66dc2cf3bb55b5e7c5ad290c87a17fb8f5ea924788cb17e29e0079c3da55272dcc3567d6188fd53c3774a2d5e4d34a7cbdc5add21c64e36801903581596845badc59b44c1b2e090aaf86cf81a1d13dc6701b76763104d575f1fe146277c107a7c403921e25c342bee76a7b3a4b1e0c8dc7beb18a9ab8b8b34c2332976646cc1daef04760ab015725380c235df5609eee5f7f16aba1cb3cd6e02ffec70f3d59a0fe502f3c46048685fda042c79fc952241ba4d37faab97a4771bc4ace8ce4dd230093f62753734583b4cd3e702f08268d048e6a164880d7b1ad2b614bd4fba6205fca499e711052ddf8d4ee111b4afcdfe631ea332b07b36196c4dcac1f8638a0e62869185905212c933b2543cebd8c177f0bc1d6f12ff170799b9e8341043bd5ef14aa3b662b98a3f6c3635c241dfbc983c9f1201af203b46a82878303e1a2523b2d510733a400b577b7a13e84afd19893a06e63a57a38141414f510bc2d4d7ef4a36cb4f9d9b4a1cf97e680b082b4df67bdeda8106493a56efa0b79fe50266cf6c3d4a2748a8aa8d3a0fb3728164c23dd4aade807b29dbc3ddc07e14f4579b3183a3fbb719a09ded581aa15bd2cb105a6f1e6a1c8ae2be6808c36d46307be0804048be9ccefe6fa78fbae3e474055f166566e3c9f5e9a629e9205b5bba8befbf278a06dcc9fc573c61875f5bdea043e61cbdd27720a7fb89ec3b9988e64d37d9bf2f24d330835b1991698b229accb38983ddbf9de938a7535358c66bba0cd01ad35c42f052b2c0a963a5a1e0b8ff47cbf0b39c1b4de63877437a8f7ff12760d1b0461c5f9474e1a13a9d355009a4b42279389afbe80f9ecdc199bdf0c63693dec9ff283e3530d46d5de0b83b45f1b007438baec00249327504b398df7aa1f3c8d9388ba32d0f6b3bab00ebd1a44bbd2f45591f1aa2d5ad6971ea307f3a5b3f3c7cfea527318f56b48e0c281076ad2b85e8b1b4adb9febc842ae9963219c7db99bd3f004c7acb2eb154f18358e8f3dbc88b916df16f5300a8f6410a5a7fa134bded2a63b0145a9b20aec17676eac969ede3a95ab82376b4f804736119c5dd03e9cba718bd20bf40a9f4218301ad4458803f09d2bbf88bda875bdeacccb180997fd98558efa51e3d9c652b9ca7da9df4fa79327b1ff4dc41ada4b224983805211334ce906af613348512cc193a853d8fe5cfaba251833e4210afe5a830702fd0f01b4a23ce6db39738d545ffd19df74d1d5d21f678d43f9b979b5e20faafc735ea27e494e0916256cad15939066cbd484b729242596ef4ff526e1411e0067f774542d4a22242d29f10f8b6a5d03498085448fb01a056c80b9bf16b3705a020793046206dba9e0aca456a22a72dba9721181c76ab9b8cc1664def5b3979f0c059a2c3a693ea33f244971e209bd0f1475c61994a536b05d65c5213a70f04bbc9fc7ebef36017466f5c985e3bf06e2d32dcf69335b5903ba1858423bc5bb78c6c8491b4a423acc2dff5969347849b6cee0e4da1526f3be4dd951482a455814dcf18b6b1d2108f51f016241c9071fda6ec6961cbdb6276e372591bc022574cadf9d3d0b9a783dec0903acf275da463dea626f1ce9870396a8b90883e10773e79a3f4d5eaf24c488f7250ef7a5faa6b130cbfe5b6ad2b25c00ffe61a4280eba5903e93b27b12aabf010cd57091fe86b9ecdad6b7032942d5c8d1131b97db2f0b1c1a1258a902fef20611cc753f0a12452661ab014441f5b3420db3f51d6d9286d1dafe100490ec1e977817cf8df45ffe8a53bd35fd844d1f7a98fb3c873c387a4fbcbb964292fe425e211c9b15baf6bc4891f6cf60a64fcdbbe0d5a483fa8c0507e442777a0f974e14cf2fe3d78965d335dcaa0b079662737d36ea510cfc2bceb092185199ec5e6deecb1c0d57e2ca6e959580192ff45b3c222a0119b6d4003e3a0ae8707f2936cf3672bebabd09f204d99c6c4d3bfc22d0df4dfebc496de0f5575af7662b8c041652c14589ce4a4ab15ec096e4098735fe06fa9bbbd1768ce64b2975d72d3680a8662efa5d3daf8f630610bd4c045adfe0f14c2f91d38c855c5b31d37ae8e60b05a24defac39a2e22c084cfafd82a197c289d4dd74b4aa119c4358ecaa0a5943d60892459e94bd1cd653849fc03648e77128e6e94b0bc2f929f764520dcf78428cabb65beafb31225437025d0d96bdd9766d221189760daa87ceaeaa5165a9e4ace484667f79c9639dd22b9bc6798940c7b3b88707d3156606b04a8b104a650a9b55fd42e37980ac3694e5c63736b0354c1af1c2cc76fee2b502d06a45ce0f311c248f821ab209fafbb8e5f2efe58b64203084dfd848aad7c65f8edd2bced25de939082a4345f95c82f3f24ac30794daf1a1b732b9d3332efe69f64a0eaae947a8e460c3f9ad8a49e7b595a2a23bb7ae97f53fc7408a2fa4db5962fafc0913b9aca2f9a7b77223131f9ed2c6718603bec29427a6c975d9e8895f23e80e495fd8d4bcf030427af4b4338ac66204e3ad875adc11114d76d47f258c09a49df9a1b0c537ffd8e80c822faddb111cddca3a0ba210c02b49f5616ba0922837208bcfe23aedeba813e36b32ffb62538ffa7bb6cc7845d10b87aa935b611f71d775512969b348d1768e79c6b127c02200e63b4aeceb7150ac25cda9eb0e9e0619516b79753ee48a71cfe8b1008909e43d1940bd1e38665f4bd9938de9778e97c63fa256670c993d61f95b0916c674e830bce781487f009133aa977fcd3c2a68410c04f2ae948e977e9acf74867b888c93a31290acdfd13b1f70915cd68f0d1cbad18227e1917c7c8411d76885c2e4777cb5cf59cf73402f0951662daa6129191aad5836e1877d4366b07dfc24a225d6e053d7bc4dc1e26413b7773f02f544ead1298ca88bc167ed385bbecc21ff3793f5ee23074353949a4beb95e8ccb803ca62f9414c326df41e2eb2cdd8f0cd7975385df4878b7075562c6aef31a3bca0d050affdc889c14a618be76699302dfdff940fb58d810b80af013e84ddd9892c45a393d6b8eeddee1ae442a5e3a4c9e3ae4d4bae24d3a30ae1837e525bf09ddf612ca692904ca1e35c044f5fa02c52a28b4c8e74d24383527c396b5cedec50b60098c4fc2f0774d5606e83ffc55631f81a949567db3e14f646b6de95db67c1f61fb372e40e641b14d35672274267139bfbd2cf54ec15b8c03381cd091c5ed5140623154c08b6882ec6c4a4f599f538984ff18e6714bd459e75b52f5dacdff5b374b0baa627de0735c18d2a5be8892e2e8b7380fcd8e81a84d18dfab081fdc56d4a778ccae60e076f2234645ec930f5de341e515d419b22755fc62dee142b77306ff984c655010646d2725ae96676ff003860553421de567315458034e3ebef00722d4a66b4b8409081be245b102ee0fefab34ae436dd35ccda34f03678a27d7d70f012ed7fd467cdc7988d80f2bcf95677d748cd234f11b69ac01b8a9bf372191f76226ba74e23bb0f0a0eca3a4951a8806439eca11a6913ccf6a5d537325522b468c720260873127069e61e2e9fb16955b4045525698706f0ab73742493aa4e838e4edbc0f9dcb98a4fc9ec26e81ed7b7e948aab348654430daf3b664e98b1f3c7caba90a0142fc8fcba278ea89eb278502c2b29f85771c34a371cca63ece5c2ac193502bb8b183fb4f1776031bf66787adbd99049ad39f987f96ea0fb4ff8df9a5c628240f393729b5e62fffca4ad94375056d6204665590a9c4b9d275cafcc2509d26cbcf0df20f81e019103b3e89cc47330d3199be8d5c6d3dcc7495f0aa1ff29e57e33b3a0fbd9807bd2edb7e49ce00fcd37b0f7cea2b5973f057f38fa6bc7a1fc5c8f8afbf9f7eed8fc1b0db9b54a52a5f95ebf447aaea9346d98bb280b77768bec716ccf500d708602a040b4203e300e8ff834748be2d862124fae459fa9e69474a1ae38a1920797ac2885d1deb004ee1a9bd4375d08c255db11314a3dff62e6e75de855fed3932c1585fd3ec091850196b77a4ca6415710c3ee2f04d5acb42dc8201fff44c880117c78fb59f7869b84adb37a758939b9a90628a3d32313468e52c698a32e526862c3201655f5c49e945cefb0c418fdee39b8a64ee588694919c795339ed004ebd9e3ab0f1350fc3a6c5a60167aa31dea2fddad06ac3bcc5c933e4f133419df5e6f7253e5518332f7d738516242bcb37ecd91ba17ba5bf027c681dcfdd176da574152788e01f6f9b351bee74cef4997b8fbc3ecb4e1d8e0ba657acb81d0874e181b207f2ab6f3caa750bb4b5efb6fbcdcd2cfccfb8b72f43e89230a101d9512a42bd81881543bbbbb63802f110abc7f97aa787cd2d2359023acaf74970787ed751ae2c320f0ac96c6e688d5171552315af8aaad3b828678b2d4fbea5469efe0b68b4cefb7af29e12d99a26440d1008d63920ab089eca8dd2c1d3d467f46f947747aefd859057bddfb16cf1c0fef1dc971567ca6db258badee44ae4b2851661a5842a9d0508869cb6a114dfb3ac68fc42167b4c097e6e27129a12e48c7a7c8dd303c98739f59f007ba661a764e797ff5f4d6ee06dcbb005ca757f2aa8e6c136e245d8e9c28ddde2d70f1884255e0ca0d664eb22ad454956094911a1242b2b78c8617683b992878c0bf1146e6cd412fa2d1a33dedfef5a4356ffdfce6b4962072b84b7067a676f68e6d3a07acb57b7399908b573da68d19820333b6d216290b36c5d5f88680107cc48b97d7171b2f762ef73c8cc4f40106220f42d8e161ccb1eb842826adb91456bf02bf164f7df3e58671b3320540f6aec011f80c03d63ad02c295cf3d60be00079075e8481f7d512ce5019895d4e0ad00887da68e1cf9ee18f5d09ccc11b68172b84e79246c3b24c444cde58ef39bb61418a3bdd00da4d6449ab3e77a33fe94f287adf6d4625ad33848c77c11393e6275d9d6089ac1ae30663a7bc247886945c7b0a422e310bb3eb86996a2255d2a0f09e30d0b92ab4b15fac9de31a8d27b095e5e70a6c33cc9390a00773d7a983b01b771db1000e1725def7628690a30db19a1db2f97b2b449b0958d13c127d32b87c3dc155d971689e831fd861273fd8b7c882c968199e3297df81f7dad292c57b1a8921c76601ea77d791326688e03e01855daaa108b10571763030cc1cca946c4edb826fbdead307b005fa149dbb78908803137825e09fd3a116702c4b7ae229405aecedf04813ab33c47ef196a0cd8b8237931d7ce1a5e4aa35779b5aebf5db0dc9b6d7bc76965b4d90c5c750be7e1bafd0e5df07102103f06aff148019f48db411e0e17338b0f80c1a0c29a52810cc07b68911e29f69910befb82dd138611485e580c4f03a735aee5d207d0610df3a04bf98a89e4b033eefb3354d3de1fbac64e893e460a73fd5099635ac32a226268a5a672f10723f42d2b9817056eec4840659c97800642492e9283f7507c565c018cb3dd2403790f69989434c1f27428bb3df1e653e8bf58cc59e85ec40e754f1f6799301f15fd96076ec0fabdb3e0a11dbf8b0cc7318513e9fa621488c5f06ccd530693f9d565945ac74d00556c3bb36d59d407a9e278f98811800be7ce2666f947ceb13f7177a042145b180db75bfd1186f5dfee54409a337ffde42212d5f08e8151d1f5e4d1e34a730136bc63f6f27fe231c60d52316c6936d5b9e1f8e12f5d30b060953686c1048b6aac961a605fdbaa78de5e1ffece43cf8fd60105793064a909e47668fe133579abdf3248b8eade57861acd1efac032420225f6b5b0a3f372c173c39f79db7b060122f755a67e3fe6d715a12d9404f5cbf82ee0899b4941eb62c4e3248b266539bb5547d3d5847783086ff837356e6605c857a668afdb442c3d7746510ad0543e7d35b7c8b26e159f4066f889fe3a0521172c4caaf9038e585b252502a54eff79f047ed2d044b0121a31ef87c8e6c8424c826ddc98e99b5459047dac23c8cf59fa4016586cbed3734f1e4b83c3c16fc14ec5c4f019e0f0b6463b2eafd6cc0182f7346e0814d6c1b00136432d295336d871f0d1b4724dfd6363df5cd1305ced1e6108daaa401c060a4b37240ce316804cbde0398cd4abdc4c39ad8968bfd06a65e166a3781f7c8cbbf9db1b354e1ee7a3b17e1acc4816690465daaffe9d6f37a0f37bfa77542711bd4590b6aaf24247c2c1c0e824e3d285ca52dc5657867506d34ce1a6b524ac94255aee8d388a12483ce4c736c562df1b9b9674277257061915a31016c1be32b2700fee36ae388e3cb0e3f8780407b6ece46b0b30a657e73fe054266d953d539cf70c43f98a1fde972ad1903716e807f73231f969d2bbfd5fc99b139c05cdfde7bbd0e8666ab9d7cbcd7e9f3e68692193f091250ff13c7b94cb046760de3ddd6517bbe307de4896c1a60185a901d402e797c760a37f601364b9cb2708c06f73c762021d4bf8b0936144dbbdf0930d859fa2806862279b615db82c2b7a6035a0f7ea76078343dd26290bc2e4ea1b80af691512799f07d563d546b806c7924d00b2fb848c2f4e021c88faf95060a1f9535f51de841dabc667942a5667809e5add0d9e0bb739b3802a6c1ec0ae8d75de76ab1a2aa2e7e1845f2f95fd7ccde9cc5a10defaec486b5f802a6bd0b110f63d74ddd33dcd25da4d6a734e143f21aaca60208e6971502a0951721aa11ea4f03dcff520a5d458650db682bf83b4508fd5f92a151378d69d6725ff308962a4d98dba523c3165a8b6237f6d6e2f08ca4429536309836ce946aaab2bf3b7667ceef45347fceea65fdba03403935c7d0da05c4d4c37239e3a58ee8942af27c466a48f36cdf4a70815ff6b67b6ed33a522b62855a4f62fa1d7618004eafa4b71852b2dd50e730bfed254de97cee2d8fdcffe21e691d18381bf9c58951c2f469b3744292c66be1127cedaa0c4baf971c30d3b5e8806d8385b0be0837d7b69d37b3a559b95c26ff7c05d746953a9fce696368e37dba1aa10cb5ce357c7b1a7ee64b4b1e139516ed3a014290cec1c50bdf02280788e132b9fe45f0a5fefb50859653239649b94b05e7e2db4135bd417d9ecdf397bf5259fb8b65243d36ebaaf08403a56a6b7ab0a443ab079c0fb73feed0ae1f12ce9dd76973304bc8d63f2e83a37b15456d9bc40001c9d092c8836f1e69fb9140b4b55271624d4cdf0af66f8e9dc1e9bbc9874dcb6100cc30b7ac078c47f7599e82fbc19f9443ade2451dc8fc8d44e8747e7b7f5beb48ac5fd8b688e02d381b2b84a6477ab53c94d055866a25fd74b0a5a5f63c296d02611cd39fc291bc7d6c1413a20c902cf3865ab0c19476c67f7580ea8764961f9dbd2002f1001834c0ebb151fb410b3a1350429a6b57ec0e2cf0950d9b581c670f3b8fc1e34d4a03f58a7aa404605c45b334998caa472d2804f5ed846edf37cd35b375b794dd3b8b113bdc3444159835e449c70a009712b6639b113df69a61cb431b6a9039fb7b3f6198242ad0226f295f5c6a289f06087efec390fc817a41ac9733ccc568b1d9764b11c6a510d8f78aceaf20347cb2b47f126dbf87d314759e1afc9a1c6a6bec1647b74ec05fea7717f80d624bc1473b913a645ab140de9ef9b0692701bb1c7ccae5d4a24fe673b91717e3b93d85ed98a4c70766536afb5e802f38f450362ca1ba6ab53effe0adba03575f0b262e992b7032a35c4c0e9dc291b4c97c2f5537619c83f32ce32d2830675b3474c89f4c54c4760b309c5e14c675e3c1d99803b14be4e49257c06516811582dda7991b1178addfe1ab76aaad447bfa62d1fae21257aea3498611d52aa3595f4be2e82757099495cfee802c33db5bf1c9c1b371c6fc1dbd57f4e3db9babc19d60b60d9d8349a583b60f5c13b2de1788868ca5fe42c4301b9cbf0084ccea1436402b542a1a720f63c1aaa5c8740878505629da46835de3306adfd7696e321c2d05df7ce657fb15dde4ec891393410057684a28387bced7e61f5ebf8cad630b7502f9b3c65b186cc252aa0dd986c389dd27cd8d02c9eef56e000860d10e95ea6519235717a472b4108cef31a7d84b2fde8da16f721f8b45fdbfda6e934b410defd5a7676702b95400a230e665611aa9694ad4aad2da42ea8901f3e00bbb50718b8e48a511d3e58805a764cb1c11251aa304f265bc9fe35c9b90e63855fc349ff7e359cbf30bf05bd665e6474a2d9f491475faefe97efb358b37bf4df600d28d97f28b82dcf9436349ce52d5a31b31cb5cbcd90834883b0f92dda6829a9192856fc57d5209465e4423c9e69ff1a820907b677b91b6dc58031303d5fd9bb857a11400577a02e2af12e2952587b3fe9a0c86e66160d0f7ec60232915f418fd9c388e94c3f01c6b2697cf020f9c3eda8df3e7e8f92ddc63730732026313d5b946fd448eb99ee03af4d8f39e38e3bd2dbae64756713e9c306f89c3e54137f0895afeeb9f54bef4bb87be4b6963313d8b614b90b847cbc3f488282ec26e6db5dcc4edb3b77147c3f61ad3363ab801804160a8de649966829bf4df3fc553c0fdff614270b30d6811e23201de657e2938068ec06643da9ff2814ec2d022fd4efbefa65cc4fcb0efd7ec2864f8a8391993029bfbe4640bd6bd086fab349b80dc6834de05fb061ca30a3619644c137818708c7ad832c89b66f030601b15b0799037ade079c0376a619339e4932d7e3950791526aadd6d7f2588b1677f1c7ece7e918267b2a7f86d88e22d5cd4507c38359d54cb0b289ac3fbd8615ad827b27e45401cadbeb43a60052ec33b7dab978ac117eedc40f213171688d4c953c52075070a8b3fbd5f08fceec6f8d7a420f0d9d394995ce46efcea696972b61a8a9042f7125630984071091c76b57f59f70478bfc2b9c5abbe71f220bc9445b653e06a77d176e1a99afc5b5bbde9cc337638347d01474fd0b19bfd76f0b4efeb98473fdca5c678430fe666d2f79850f0615f06a4b5ba4559e9362635efb889fb283604a4418034a9bfb67b7679983db114f42df6c2765641d77e45e8baef1e43f1764df8b65ade4b3fedb5d4682d4e7bf37d5a7fda9befd891eeb437890b7a41edad8ba54a1355e990f2bf440e329d7073fc67e373ffd3cbbb541815bc84b5486048ece65ffe1fe926dbc54a00f6b72829ac5bb90774e5099c20633e47a55b008e77baf4389af7ea6f2b0561043379c4628af3e8d8bc52eacb549c29076520bea8c431c9670ae4fa3487917fada78b13604e9fc93cb1af7fcb3f0718869a9f0792969ec3019c42b93f49386d04e03ec4b924b6bdad5fc0d42f69807c1a60911dd08ca6120f88f762f705fa57d29e46e8b7defde3c5be0e713e9c1f7f12eb279c7edef7c7b5908a4c47e35f19aa13669c40a0fe3e6bf3a4286cbd5be134be859705e010335d91db15f71ba99fe5542b5a1277c1b4304192adda772f5e77959513020938c754c8a6587a39c885618eee822639ea200794700bf15346837974f13b297e2a574a1c5256832369e95ffc7ad8799d6221e2ee526ee6f0bb21100ed925527e8c8e7b7ba6ec67b1d62f7d0ba75296ad374c4952804ab7c9849243da86b1f50ad483170e135d8c9d820f5559fffb682e514096aa6c23a8958801a930772d7f976aeb0e508fd1f4f7ba8fc6dd7081fb7da1ad5d2a5ac26243199b0518841d72a248c0c11cdc50883dcf3c621f32931f570c499dfc42ca1f6939b2043e3018187ed370cee8d4242b1b6651d70ab662799514b1dea98cfe412d8dc18ce5127187a55834d7a71422a22a037a6d936275096650680d6eb1436f9685ae2925ca91bd8ba66838bd23f8fc9133ca5df315f284d3ac5a1bea85f5914d1927e42505c64ce068f7067514494a97bdd5a2e206b27a81378293f636c0e0cb875d41200675ee2d0a827f2d808543a2c8c1a3cac1bf4fc4e60754abdccec2a4bc40bf248258a97b139b953639fa0ff8bf9010d52b287a8bab22fda5eaf4dc4b7013f02478a28c9d1af5438937e8154c3cadf8eeb0a3a9280ab9b52f91513d07ea414336d8f717c30ee98ad38d72537eced2f81a1e17fdf78225830b2d7f07ee561888a23b4894fff2f1d2dd20f1c76a121b27d9a401c630239075a20af2cb1fc5d8208299862a7660d27ee1bf85a647a0ec47658cd0bae52c10aec2a4c5b1cfc2815701389c8d72098493c027e7c2f0f08903ce9c0a93ff9d9a084e1d70f8af189e6a0342e8034ae9c8e391294f7de4b62f40d5e19673e4dfa48dc07d85e489b695f69d09abd52dd36e8389687f19b2ced7938d0373ebe1362ab069a3a6efa4a6686a1c2d083407267d98babd9b02a5e78a690434bd598760b0f93a9517db9f36ddaf849102d73c13b2fed034583ed3c1b6bc23dc286ace28b35e362f3d1f6c7fe110b520324c44649a17589f9d1811cd412e670e76dd73653178fabf81d0cf38446e3e2b3b43f243da53e2fe4d1ba1147f7344f25afb2e4887f72ff196e551de0feb6edcaef1206dbd1b25c381a3b1204c08f2d920945bfdb8b38cf6813291e8301fdbdf16f9e2eed4cfb388a7b7d6d280789fa4e9fad83102dca538b92dca21d540625d614121987cad8dc15c41d08ad83b9bc7ea9812181dd6cac55400d939770a781c999823859ca54f9909ab6177d5bf514d8de8dc2d331d80ec8dac8ffaac8a451648a4fefca73afca857af9a0a1cb2f97dbc2999565531e343cc564c160ce023e8096477456cbc9560f16d6a9213f3de507843833c1f161d2b7e1460d37c5039040021e9e1a3edcf38ef91a61a9da403b55c5dd34b964f681f43717fe0b0f016412a1e3809d7a662cae02a03bd0a6fbf2b86c985e8a77039ba8a70f266a257d34b9d02233bc26504662226a6132ccf5372335d0451db3f0b4bfe3cdedd4af0d25064bbadba4f5b6993b36b4e70e478f98dd5352e5f567b85af5492b887310a49690cba13f982ccaaca47acdd12018192b572d67261eed6ed1eced4ebe182c04be813fe12667decdece75161f9042d0f83a9ce7d38ee91982ad4d8fd7b68b48b36c95d6fb359c69ebf13eb6f1353955af7f2d32f4f2b14ecf5b84b85e8449dcf9c9655cee104462c29a8c134728695d57cf260dd7fe600db3f0fc2cc26017ec96ec56fb0f003615b7092aac234db925047ed6d52cac57f92ae434c0f3580fbd426bd30c9b3da6e7e961bdf780c1381f561ec700c4d4d80a7109393b0e21e0253e32ed2d48968aa911471b18fe88fa7d4c61c733545ac16aac7e795f258ab5ba5ff3a8b9c28925c5fbc3ddcb6f3824173b130fe7d1edb07114b65ac5eea1d15b800d0a45b8af9af0305291f1d00fb503c64c94720b1dfed29d3b7d373a75aac48ed5c4c6d9e63ec8de93a2395867c66a91f52d271772a988e3e593d7d64f53ddad795bd8571ccf37014c9a3ba2ec81e75cc1775fff39366338f6069347c18f3fc0a234e09c364ef92a4a333828f055028506ba79811fc44e9f6d0a5e8a0d239a1e29b8840048ae5f9c34c5938b1eeb6672fdcb964039055338887be1ab3922fb7ac0fe0cffff9198e395c7f81552c135971ed0db30099c0b46b78070243b0a77429026f088a33ca22406df9166f28484b0376147c7b0923b82fec804433fe003caf41ea99a0721e002929841efee3f17210039270515c9dda3cd89bc42061a155471134e5cb8c578f35dc2fe12cd516c826d995bfbcd3a7bc99c11cdea54c6b5182e4468f1df462a02ff8d4421bb7d1c63fb341f0dbb56298e6a15c91dc2abae98ec89acde881c92c6de254210bd23aba9885916209608c7e14d296d1aa81a541a2ceb04d9c328a75f92e1619f06f027d1baf077d77fc1a78804e0b0e7e27659e056c522b4602342e3dd8ac9ccae9b85cef9365c170e9154fb8602fbcd97db075003ab8e80521aaa5bae9e6fe6234f2863b1bb95f21e258bb20bc3ca780798bab9d5c1cacb31f5e6c16b4d78983b481f2f0d31a1643b46be90de1ce54d675f2132698d5a79d8c30db07de3f4748c9d31bcb2f2bca8f44315ae99c8c53a6088660a9ca24a4a1453956755b534b8a8ec6d9cf2534449fa04dd232eddb09385840f88e0c04c30549ab56ffcf2b45e78a8d402026a6f5d014579730ffa06bc5f9724ffc67c6253cdcd8db9d2506ebfc2ef6c057374038953acf06e17316dd12cab6e76e21310abe0b0411dd8a007319181b107bfa28e03bfd04d34203826f20421f695c11b7126da3bc80a0062a283aa63914c204adf5b26aa234a4d094898b96798bc3b24ee2791853b515d87efc0c60cd62b6206ca33c5b134ad3e56f035f20f514dbe9e72fd6bf9cf610eeed1c71d6fa821f3c1f69bbad43a6c52b198838e2299c54825faa794fbf532a8f5feae05bf67e920932a6e02226bfdf7351e013e3bf9679bfc2c254b71ad82b9071c9619f94bad22016d5d9c92481ed459e1219deff276e773ba705df14a1547ee8fe3e223d30751c85682ed519409a4e17c051f0233056420bc9b29e28f849e0216a50805abd1a163dcf32d0a2762e6da38d1b936c4b14b614e66c90e060fcf56279e4539310c8e8aeffd3eab1224fbf3547bce3fbffbc6e77c74e8b6ab5740176759e95986ff00acfe7b21c3807ef10bd25dcde3d104757057086673f775b8cadd1a934dd94ccbfe7ace6ce5b6b4af46b10806eed9d5efdb3ec9eab586f64276d67112b9ecabadf5c7204b5fc3d7203a3a6a89ccf3ecc842cb4dc93ca29aa759f57dcd909be071bb3c4663d347be359777100b92d3ec1bd7f0efc2431bcdb8b193cd2f35ed0831feff86c55ed15216feb390b5a34c8c1ab4cbffb88493bc3198e08e61579f773a7f9261414fdfcfcb3ae26cd38198d91c5874f193d109e4d513b4101e58ef7eebbc3906fd101989426c85ef4764c6a28e3ade3884516e5c638ce10115854ecea91859c6c85c7ed0712f2896069b3ea2e664907033bdd570ccd10e719467f02f6205e891a4198ea6408790648c7cf098b8a5c2ba8a16008f19e01684758c3264c88c06f243aab15ba58e061f8c913746a5d65e547eae5c724023be228719b3007a38b3024272b31a8d2147cc8c52a9d826ac8cb582549e6c5264dd9da3a455f35f25c18787a23f5668d84d0a9f1a5ce25406067dff3bcf0dd848dbcfdaaf5b9bdd774933ebf1d1a3990f6179de1924b9f56df49ac872f21a9f10d621266252ae80174b78dbc9e487366ee52876289d2e74efc6c64e5d1350f37664ae63a8216fe9b0036daab4111cae5fe872281a1cffc26be237893d2f554a223f5644002737441b4971fafd3ec92f5cfb6d573cd08d1f3bdb2997400413ca5f9aa4ec054c683494eb14b7c3bc33b2240bdb54911856996da2b4b0e05841b0c90156290e211b1aee77539ba067db7d16e1205e69b142c81779cbea478940fc48a1ca2341042f761b321eff8c7161891a57e7628d521d775f66e3fbf885b80ce689e7570b149d96c07740f782e38f18e3ce86a4687bdfa9fe22b6bf617054d0696530e55590d65f0654c4dcb192cd1230e8efb2c3a2f51f25e417717aad98d142426c992aa7be4b68f9b28922a3be9881dabe508d01fcd6d0fe6f3b00549b5abb6a67e6aea102a076302eeaddce94042466298814ac127786abcb5dadfd26e2f6080a440b4175f3242d96cc71f39e525329eed653909526335c02a6c1b5f98b36f18d4b4bc02e82d22aa24526695df15a6533493ac2d576e2f90bf7dbc84425624bf2d254047ecd89dcc68a13287afb90ce0ad870a33724c64f7a0e31cee8c8eff1ee1831c941c092de071e8ab733f8280e2206457a2cc8066b6e049c4b39242b62d35cc60c69ba0c1518e12e22525a7fae0c86d010cd3879b2cfa51bd1958337c746a0138480ea59d8356a24505c584432d4e933e6544c41dc3d8c2edc3518b9166c10d32119dcd810c66d24e22346ac3d1d4a7f3de7366ae555d17745716272a99aa40439c6e09a230d490e0c9f418f4c3e57c311288c84482b0051ae31602181272cc2e49d7a23e9a67e45760c2411402666b1f9e12f9f51c654acf0034a55bdf5217570223244f9aee80b2523d37a0e6ce655bdb9c9171f982962c38db229a29d0a3a4f6154cea5dfaafe22df48d36342d6c3d70e93ab25532d27a652325c73a8b908e9726c2ebf9fd5d5822ad66879c414cda578d8c619a3394fda1d6fe21f7569c437b6b4927e5a5d1a66d8ad1e0906f8cec17cabc646f3f281b71c42fa9f4c277fc76f8e48a1e131e6d513892666e14000b6418005e1548e1896ec3cfd672e2c9d47ea04a5a3b09457f1ac4b730389a6c6e459dfa0c7a110f5e7c2062f082e4a013fa687cf189f8d45030033fcf0d0ffbcc23755d5762cfaae5be5e79fedd6aea0b9bc01b8649bfd501fd610858e603eee2e7b4d28ae7adf0583c06c3c087389273a60ba671d33fcaf178f6aa0f83cd80a4bb08bc20b94fc55814c85b29f4195f0c979b8fa41edd934d34feef7dde76fb3a93848341c8cbebe6b62edb88761bee006b8e77ccd76be0ad7e41feca4362d5553b1d5bd63d97d9b0831a5c873f1892e873deb03b3379fbe19d99782771b1c99e0fc32ad797aae17e1828002cec6f87b6d1bde7e24389d8fd6bc5ef254eb19dc759c7dce2089f46d170c11b2132836fa657e004ba9ebcba86cccdc8cf9fae696777fec357f078a7e64fef36497609d08cae124496910d9612f64d08bae9050fe98381952b54cc3e2744b10f52fbad469456afda654568dafacacde8a8601b9c4d9945727b5f49d6624bc6a4493937074705e35c3347264c64f54c07aa1db272b6b7d37478b06a1c9d3a72854857c0f72862ec2b81a5afe76a745f633114c269aff290da56acb84edf5aa1347fbbc288a7706104b43f5f4c9f3b5fe53477962d02a291103f64ccc8227420a99807c0caccbfc8cfc14be88dc24fb3db69f17ed472a45e7daff71091f7696a3999811e263f13960ca0f346edbec7c6a672f99bb361aeb26efb5d8dcbe88b498020c39e740c3441a61b14e6893fcdb8c4b1c2991ad4e01560cdabf94eb47185d9966262e4525d36dc17265fd77130f4045bef1a781339a65242c189796f06d08fe46de9e55d2438bfef6d808f962f6fbfe108e7b559c6945915b3986a993475e9c18d7973077bd6cd90a03e5c95ccd78b3a91e29fed207cc6c4b732a371227847750c4ffdcefa114f9e4a3283c31697827a5bf224e1c2e42fa9bb120fc87cf956800116dd31a70bd975a336b18693a527e9c73de4fbf37e57ff72a791df703b4e1ab30d0e461b4ee5b38103400a5e72c593d23c7688bbcc9b3af64227ffa5509b4f0de0ba6d522f3863ad4e04a359b477c5e237bb15fe20dbcf52bd4ed6dc38a528bc67afebc2a2606d1413ca1144312fce4de17799baf882fe8e28d3ed2000609900cf6e8958cefc1a40b9007811141ce122b4d88f4d15484ec0028f3e65f1a56257f686adb7d54e32791d9a767be74e5a8882d70ed4212575d6a3f70842c2e40b68d791e7146a6444347314570498fda9cb68558a069e9b82df13b42619889cfbb7237be59138a11bbea94a6182019f52ad28c496f6800740f32f8ed209136086406802d2a4778eb302082bd69b0ff3af68ea87c2538408e7d97eb393a1ef053e0e52b9692d778ba1ad2b5b960f40d1605fc9ae179418fb88997d506b9b322242e616c18d14420b4b8344b52a0b7abb3dda42aedb87b3fe45e93f3e1523ca82be6f184361e19d49024db371b117f85fdc123cf6b383b4a55cd10182078cdbb16fde54e4748d7df468c66fc2d3d5c93b470a4cff1bda2dcb96b3ec7739e46dbdd30b70c742d51a89359043d8760babd76381a0092c71f05fa3cea4c64cfd37106c2cbff0dadc39e1536924aa394cb97148933794684fb1bffbfae2833e2c333545d02eb6cbdbcf65b8bd4d6161c12dee5cc13023c6bd886cd413417cb46edf1cb4ffa611c50e0ef9bb53a0b5201044f1f1d7a84d83a86e515dbcbc0aae328c4b894b0f7384f0d40ced95d7359dcdfb90502f2674a229c3ea219312c333313371ff1cbc33c4273cd4f3c416454415204c72fd9c6dc81319adab931c11374da0284259a8a19cf9752bc1bd2c17030c9899d4f87beb3c7ed17cb8ccf247a8f7b5d49c79cf91caf83069ed849f026c78ef0819b90f24c066025679e24c4b467dcd19c2b5ac219806e20c35b3302d4c96f1a879f8960d5dc859575058d5652278ef341ac20568358b52e5b1a65b0994064e7b0576e184cb2e82722cbf8297e0de639b0949de196651c64dbfcd891a194eb2d3e323c1a124d580353f407f018e4821d612154514b06e972a3d53748c096ecd4f38a02aae4966cce190a7d704141119265c368503c0fb7c538527ec06d3fed47aad30ea6920ee45eda35d799b8af8a867a8a94c0edb44079f27fa7d0f7e2ce56cd7d2ecc5a3b998d3a6538b4d508cf3002dc366d6d4be070d91cfe36b246d01a0fa9ae2b1c2b10a14f521cea1d7ae9e0e2c064f4024676f849d36d2fa57e44ef416b12883c505fa9b1cada820d2c91a5e63821d0e11cec138f5680da63d700bbdd7b8c1e6091a07ff37fefb4887021d9251f792482b97d2748e5f4e211880ff809488763731968eb1e66a824003b2ad46797ec36cafb2b238e4a8b2dc0b66e6a8a32b767136e28380752f4c46655a17cdf13ea1ac8720399f18df2314db099d67e3f5b2a2fccfb3882b65baa8cdba2afc50deadc4e6e5dbbf8847de74098c33acff98d805c7fddabe6bfb6c1a3b53491135873768072c0a053dd3a4fb4ee4fe0028612d52b4519ce1f2d84ab7fe5c858ef643184b26e5f0461fdfd8d1e4a676ae05e0a5b47827800c39a818365c7ca74fcbab407b1855e9a5a3aa774df8f6d152b0ae30173c251836af4e4db0b64fac467f8a0f02975b8e99ebe67b59c45fecd5e9d389fd974c373a898d6f0de73304c0159e38938de38f4c0d0afe4c94cebcf538c05203df2995b1bc8f2f9ea1e1e4b231ee547c232dafa369ee678a1d0c1b807291a0f9a12a643910b6ef63298ee70ebe5b0560d1b4fe6034fdf7028863ec182c62cf74b633ba88484f5a69a13e5c1d70619bfbed270aebc9ae3780f3cf685677da2ea0d2bdbd3e9e78b3a7270445605b83544a8228af89ea36e51718a531dc25396ea4e1bb02c34e691a6252408ff325ecf33d0bd593e48631db727ea43a657f5913484ffc0033befc8a086c1006484160b0727ca3699c56454ed04d9c21d6534c8dc37852f88b294304c2eb36c78aad72e18149a7460f598cec914c28bb6af64de100d2a0dd8a730864dd29ce92da12cb0b329648241e6f83a7a77b867566809a48f6899965b6d5e64861c98bc6548e012ef1c335712448f31a8e5392c246b005b7602df7888dc76135f3eafff4b61666afcf9961c7c2c3d562d330e88fee497bd2ccc13b3fcb4045e18c4260e511020ee4a7549b768e229019a1c4e1e66094542309c8c3014346292e7a35aa0a0d87fb0f41b6960844e3d0d112992880cea0f9cd5e3f90e2a1c58eab92dd9ee2de28a7cf2883fa17ad0769894fd7c7c9b02200e980f400e4a3f3e3df63a292971aeacbf69cb6e3ab6712994aaa6543597941de5887ff3757b5590968f0e05ffcf12c2fa714181a19be9d795a52f94279c9703147982829aa99448a97d9a4a89a0dad6086a4d65bce5dc3725fa0afedb777d90c6ff0705f1deea18c704635354a5a15b57699c5d5376ad9d5bef68aa76fe6efda3e47304db8236575b11c1b6a08deb6bfb82c1b6a01f259fa30d886803e2bac77c60db4b46b5a66ad1074adbbb719a0b92d58a36eedcbcabaa2e424257a42e63955874453abbd3eba649ae27b0ff47e260dd4d9360dbaba36c1cef2a3b63f7a6b46db071fbed1b10ce401dde5a76ebb6745ba5bc0d286f40b80a6c73c72f7358965e755dcebd8a3d37d8176e53faa4cd54754a13056d6e8ac485b57da6c2a860b01fbc0de04acbb81ff3c826e5b32951b249e16d001b551518d04edbb7cbd83eb5e9a26d838daba9acd50be4d6562d6548e9f5ea2dbbf9fab2ed4cf7d9f6d27a9b6e2f33289575d7dc80789fb946f8eb4ef1745b87783ba5571a477237b7aba97edd297d4ee9736bd3be6aaa3555b7ed294aa93b713e54f4f6a7a1165c4b64ae2542ff0f84b25bed4daf64b5f7ededec654282b4b46ab4a76d9f71fd6482b49d34979bedd4d5443a85c1ce7765d397956d6aba571abbd37e4ea527fb6e6e0ae4a643ab6be4d540ee9b6e444e9a4b44d5dbdaf6192d062f686c4f986a6f8d5d913697c6f6956ddbb2f6a6aaa67d60c526f5573341995e1a1367d9269d45572427579aab3d35e2482dc7b9049fc366a4e1ff7f806a9dca6744affa9a76397b56da89235d75beea5acba2ae308e708aff17f2aeb088edb5bdbad6a9a6f4e90a89986ecb9dee49737955fc07b93c21ffdf9243fc961c46be25c704df9243e75b6fecf8d69b36df7a53c6b7dea0f9d69b27bef566886fbdb9e15b6f50f8d61b2cdf7a637eebcdd3b7de187debcdeb5b6f8e7ceb0d05df7ac3c0b7dc54e05b6ee6f8961b36df7243c6b7dc70a10688771d09f2ae2338effaa1000bedfd54f57fce12ff9f43078e13ff3f5a7073e6c851e3766370561c1de4470639750cc991e33fe70d900740136773dcfce7c491039211fa9aaa514cb8902cf9777178709fe49fd5c510cb8a8b8392018e1f6c7ebcf19fd3e63fe78dff1c37aeb8bda32cbaa6e6ff8f3054fdaedaaa57a553ff396db0f1c38d967ddb9eb386aaeafd9fa346ce0effba9dbbff396c7abae63f870cba228511464e1a3968f00ef59ff3ffe38c29ca4083f7154a8e9a1c3372ca78165d9172c8c8f981fc901ce939b2fdbfcebb8e58f02fd36b4e9aff1c09b0e88af423859c0838e58c91e3aa2a6d09c8ccf513814f192e1f33dbabb704c0f040403eac0ff781faed8abfb6b74ff98cbfbd5c59577b0e2c1c1e8ccd8d4d4de9f3ff7cfd3376c63afa7fd9bb8cf8b432590e5a531d1474526d170763fcbf5b04a328abaa1a455d1c08f9ffedf5b2b03c71159152048a5fd9f49dd166bac7b657cf923e35b97ad4e834eac96d3932c8d573e4eae971d9ed6e6bfab47b9549a5bbd5eb65f24ea57b140ddeb50114a68b489a7787b277059b288868e92fed4da3c07eb6234a36d8c64d71e5c6ad28cad465ec1367d926aa3ac4871879b7d6a9f8faba431be7c284a0927024180c6567bd03e9add35c377d61477bebf3855df52518bb699653394f3755d5a8d510ebba408f0bdc5cb0c50554fce6b36d2fa74d6a7b55094202c605efff0fe13d4bfa044deb0a30fe73c4f8ffa6948d42e26b9f39bd6b4b23721a725560f48fc46936e5389a6e6e4f59174a5b3141725fa09646c4cddc26cee55569934cf39525e2a8b63e8d3cbdbdb6b1ef06357359b4abaf913588aae6729df977572b767de2722de06ac5a1e36a9971b580d8d877735b0e00ae205fb88274e10a32852b0813bfbdba03a1a06ddb6aa8218737bff3f3ae20eaffbfe94ed5d955e90a0284e40e197997046c9ad45ed593662cd4aa674f516f7f7ad232e12a13ef3cd54dba2d4957043e425c11007145c0a2c305811a170462b820b8c205c1025c1000f16faee9d976aa52c3603d6d473b136ea5b140ddc6be40b573e35a16a575dd966d6f7275cb59bd335a7b6ad3ec7a6bfbec4cf7d49ac26030180b0bda843618cce53620d80b26a5dbbe056d5560efacb6a6dbac77aa1fd8912bad04f3d960475ad608e6b32179d70edbd07463d7d6477335769382bd5eb02a1bfbaea9abcf97c6ae7ae66adeb2fb897367b31526b575604ead6937abc0b6976e7bd0f6e3ca68bb4df7566b750b73dd94a3a8528754dbb6d7c8daabca2716c90f5f69b0d58a5df2994acf0dd6f6a69685826d1a9782c1aab8dbdb5d1d4342dabadaf946a5d2ce8d7d37bd6d1c4c4ab725d016b4e9b67cabc0b635fde9b023a8a6928939c58909ea09e90826057bbd90aae8f64d37a0963dd3a718906ebb9bd6aa6c3aadaab93a69e3dad70bb6f5d9dad25e1feec7a7ed6ffa7ac1b6d7aaaf402fbbb6e9cfebd63a9509abea69dba66e7775cba560fa65691fc0aa6cae9175a6651d28e5eceaceac7efaa9d7555bf9b47c8555d96ae7c6c6de2edbdad811a827284a47b63ea5d957bf3a91edc7479602c13a18ab5f2244dcb7afafdb5f74ddac7c3655a73157f7dda390366eaba967ba5dde5dbeb2fb5d3b4fdda8e0c6cb9a7624df72b3c44d5d3740c6bc108719715811879938bcfc6c6e0ae4b3f5878a238c83678cabddce3b90db6d68438730665ad6ade000facf4173a60d1b6dbe680381364ab8402e3b5bb78db739fab762d7cddde2c12b84ed05839551484f4ba551c9a4f5461b8eeb363735d2f697add27d36d36f8419817bfb1b4f7dcc0b9b1b75b8a1861b62b8e100f6dd7eb635dd7c8a6c28abdb971bfcd59b1b49dc70e0a7d674cc0bee4c96b601c2b68de182b61c30fe73bef8ff1c2fbae869fb72f19fb3c57f8e16ff3959fce760f19f73c57f8e15ff9f9353c50fbd5e3be57d85c206cff63272dd964362ae71c1ff6b735dad461d1ce77a53d5c0e2d500a383daaec6153536359ea8c1b5dc39c5660a1b2436ddff6f40459d4a4359695953c7f6b24d36eec7f4a1622ae1f512eaae26da5cbdbd5e5049b66ddb02a024c9e6ae017a8eafec99c61d699c49038cff4d48c9b6bdc6ac90851369a0ff1c10e7a99ead5074aa0eed74c6f6a7fed4d553f7b765550da5d55d2deaaadad288bc961a04b4d498a0467d33c83083016600f18fc40c155a65a0699541a6558612657c6568f0c59a9a4ab553aad66dcd4ea55fb365f9ca9e54bbc78ab6a4819ae956a751f2bca7bac9eddde883541b75b75369a8ee3af19ed6b8ee4fbcb72220c3186acd74f9dadd96181db43de562efb671afee561ba7df8d635f2b261b87b29bac5b6d6e4b63dd24176537ee4755356edf94f60373790742d96dcb9d4aabe713d9be32f9dadd2fd02f60ff4fe3a2d6da428aff77e05b5b30608b30ffbfc55cbd6d2e3bdb4edeca647ced33b5bbb1a9161665b82df7d2645890100cf10f25fc2f218229743033b4000f343495396207206ee7a9fbd298fe719c9045800d2b20c035abfee784f9910615534d846f5581c73fcb7b556c56c389dac1ff6fe55b5568715bae0a2a55405541c1bfebaa6ed09b9e3376e778d93daa650666068e14b0161560a828a14545fa0fe5aafccfd1e189fceb40d09a028daaf69d032627871c1cba8c7dfac769e2c71938647242c071c00d3624a0869c2f577ea440c30c32c49003c30f28390878e1711c6895c1e33d70bb0c68af35778100bcdc32669451a255c64bab0c51ab4c5726e7b7a8a6c791a387204f403b4d81de967300ec99982d2770d0af979bab5eaf74a6835a4d88d13601812680f84722a355b1e7501357efbee9696e4a8698fcd5040a916e2269883e9bd8feb757130c9051f39b12a16d7b9169e29f0c1832379089fdffcf9664f319b2bd5e57ab6498fcf672c91c2133011334fcffbbfb9593e606b941bc773708278a06b021a4b5c3019e5bf5a5eea22853eddcdeee72eeeb6a75eb556aaa5bada6af06aaa9412bbb35baf5ce5b761674aee991b7d78e6cbcb71add5cbdfdf0eefebc6eaaaedac75d3b0d8b668d366e43551debe7c66e346ee3fda7e6e32e7144181896f0d22eb19780f2ff542a8de8bd2a65ae8ed2afb492aa773ac5d65a5666a4841dffff3b0000882356dab6f6f64d81d0ed0856450ac6fbeb05abb24dad299014acab3c3557f6e59c14ec4a2bf553055ada60eeacf727ae967529985ed38d48a77522486c249e5e401ba7b1e63862ccbb697ad537293b10f9cf71e1755a7544929223b8cefb4aeb20f64eaddd75bbca8511556c2faadd8da019416544132344a04d0990db81288b78ffff559524a16dae36dff4c4e0a7881083b5f39f07072d22deffe77e76cbfa6ced79b21c00052b0a5614507053b47363a754bdc160db9a96494443474543a5d312143e581520718e5400d60447c31e87ea0847c5a11a6284f7a24e992d21d208a1c3ffbf3655559b4248f0ff6f9a9cabaa4198c00691f4ff5b42d836b7e55eaf1610b31fdefc9026cc92ffedf5c3093f6cf981f683fa83953078fc6f4ab617906efb98177278b349b1ecf0818d9c16587877f72af75d53dd96503e60e083cb87067cc04182d257fe7a99e6193c6830c4ad75aa0d6f41565a2bab15d4ca69c58a152256aa3c902140b81d065a6162eeb774f8e25b3af49012b01cb020fd1698ab1f6a8169e075e000c26ae5d042100e6970c802072cb6dab96d40bc20a5854353eb0635ad1ba4f856979c6f7191e35b5cd67c8bcb18dfe252e65b5c8ef8169717bec5a5f62d2e55bec5a5e85b5c80bec545e75b5b28f0ad2d6b7c6b8b17dfda02c5b7b624f1ad2d437c6b0b0fdfdac2c2b7b614e05b5baabeb5e5cab7b64cf9d696a36f6d11bfb5e5e75b5b22f8d696ff969638bea525cdb7b4703164674747021c1cce7d529a9cb091938710342cc01de008091c4f00e1206401242da4d6977ff53cd315870b1a9af82ff3ad19de7c6dd59a7d5756e5f47f4e91ff9c1e578dd3785fad983a8ff29fb3c17f0e919c0c8c6448f36ecb95b0d49a32e67f4d5b31f09c055a308cf0ffba7aa6ce663024f941220f40ae7461b31d4dd971af208d40c11759a858b8e24a8b203213d540aa060a8518182668522136331cc8e22547faae21248c304e2ae992316ac4885932220d0014535988708244eccc14097b3871864a4c070d7038fb607214a3ea56887cbc1c88816f0001b2028630622c13be8802c4aa3585c50319c8f143cf1b53326051009536189c30a5eb58c1880d9c803105c4c416363a4c0c80deb1c70c6e5cb96144a338cd8883cc1179a02a5ca9c01a93002ca0514cc062010ad0a20194c81768f0608101253d0e0d1c4085cb95ee6328e83c380f367a019a8c10411d54b4e94b627cb104e5baba1022686214b150c4d37062026ac206426e840c53d026d444f15ae972ea92b8e24cc4a2978e28a6e011008113f889e5b0c75013258568491f9b8724ae8c123095f78c05045019410214fbd5c5a96413668bad938110dd60a387930b3b9e4c37db08670288645001360fc6d99560f365840fe2c4522364e1e24bd07b98f96202497c0de8295e45402c5841a35d30033ae1c1962b6dc53d81bb628f3a340751805184a54019d81c60d5085366c081394124cacb478e1b60252c89e14a308204cca98728147270aa0386c19928e5150c80c35c830c33a81630e5309310001b37af248c985c52d84188d41bad793413a1b6a6892a664b05906b92c10810cc388232c11a51ba8010c48e10570d08820508af0e94209804d080b02487498f9296214058008c6c070d1d440a0c2f51c6252aa0498141c50449152185d415256a8e62582393fafa50da29a3298ad45f31f3e2895bb362851915b811c4a98a9518ba1c91199280162b3a8389410ba4ceca0046f888a4018452953b7e586163019b922a50d8e0e4490a3566a892425051033a08400a55a20e60030c483ad8a10a11205b8aa45040042a6d2270ea5409c2810a03782c10b5f470a12282d5511e1d06998a120a3fd8418119262a0208d3460a17180fa6a0c18613a910146031a58821241054b140c494abaf480f78b4724c29b2e2c61b413e504c79600f09ae8e864029629889c01460be235276f8028dd1cb0f19296c03d23a9e080252483da48507a9a4e42829e17a526ea27021f463471448a410e50b1f10b8b9810d3551b8152e070280c34b944e073bc6b47ad0283d6c6862ca989792280838e99a4c01431f512e00e120072f22b822aaca1225581460294854112cfa50028af10014396657f001b43c8042668d21beb8cac00a28067072930626240c940f2440c7044918b101e5020464708031585c2835d20859f3a8c30a94029088280243992d505b888a0853420e1c5493180a4b904945a08230b1801415b30c9ec8b883768a91c47efa010f293688b0c2f4e40609008e285b1a78122a228522e6d0443c0141618707f82cf5387d11a68dde00313070ca810a82057ea650e1941269654c14413a7d16ace0004e0e2a9c7e0206ae900285fa41154d9831041460960f60988182a8ef88990f6057674850068aec832355580bd0811242931d3c35e091c3e46c7aa20c1e04843758d074000ab8f9e0cd1e661394198a48c008922e4d434a06a041c203be30bd11e6015c9ca94015a6055880c50f127c9980890046a069f3804b02a6a424145a480d588269821dc2d0c080c18525342e20c004c828fa61498c1e690a31900d2c59714ca021830a254b44289819624d0e7cc90131afd18b861c94c270e2a70b335928500ac3079907c83d9a28ada71469b08047ab3432fd68c3833cec50fad1a625a0da85a42d30a0f530b3c182241ad68080011d47f024ed36d6ac89820e264948d2e8b0e68c913dc9638b921c37c0a23c91820b5159a3d47ad2421346a34949104fa850d0c6150a2830f4a4e78c124c7055a18593374aa82a19ab9013269868e28a614be78404ed4515197c3ce1e4030b1e8000175e83130b40e002c48a170b486cd860303a9871919018c148124a80b182a465a7873650de144846540c78536405072409dc4c31658b2d4947691480e60e21666a473ed87125851a30faa895d243ac8082358e94ec1f39ca58e9e10800229450870d4e3068e285165f1c994007249ae02080314551520b9ac482e4b1456d4ba38947a45b2a944430ea838b04b82186961f46667c488388511536182160cc124be8ac0230325570630290237a8c7e84a690605270a3ac03abd1438d3086944f18590389064108509e300696357d8c80534211510703f20fb0dc503802e483e3021337ae8a6a63dca00493258270a838c3c91d4cbcbcd96247e9cc0b4c9e54b0060d1a6e9a98f01881c1d512292c293a43ca1a980b4abe68082864534b66bea8ea8b42821860be68a84c4d54e3e58b1aa0b28383ef9f084d135264d0c23f5198ce06364bfe896415c010463caa62e3ff8970c0985b1659f419c2186107e162881bc10b1e57ca98c0c29229bfa4e7df042923c76d393605e25fe7071fee98a30d161aac32c888e0d9b6ed69e648b3264d13ffafaab4757bf559ed4d43439a150c90c6cb0bc8278d549a6d95d154766fdbab37daeeadabd729b66d696e5f59f5075dd3202403d85a765bd24bdbcb4ef96c9bdbd754d73ad58f11ee3a9a95a0aeeb3a9a159fadcff4763b8cc8162920d8f682b1dbaa5b3d33622a5978ff7f561fb3d5b16dba29cece03638c2e31d2e8f4a0c383ce0eff3a61fe7574006385d6a2b4f53d695f48cb1e2d0c29ff1b501847ef0ac307081b3442744e62aee3701fe1d1a8ffef42038566099a4f465b3b1a9f9f69191a2168feff4c1b31fecf0c9d79e2b7333c3ceccc08b0ed5d5336f6ffb03350679efc3f0cb64dad7ad55d65d973d36fda9d6e12183d80c1b341fb85149d196278b7052fd47821e45b2a2e2face81992da2b430cae4b738abd7ab6a9ead0ebd5c110437418f0ff4cefeac2842e846c81c5161dbc077dfcbfd4bbb4e08fb91c74d563415a1c3df02e2d8c68e1fa7f2346b62c4ef80fc17c9445ec7df08246161f162d7080450bff6f5e7559509031d705055d21c40a3e56b61d9ac9a0b4535343ffb6fc6597b8ee47567d89eb7ee4aac2016dcf92aa33591bfb7f76c9ed53f4669374144085140ab8a64033c50bdb1450fe1fcabba680c55c1d836d1c9b6a1704c6bc0b025e5e76e52e082c1982c0ffbba488e2ff613c6dda7c4da9b610779190663228bac7cc8d4536e55e75dea7b4a9b2ecb9b3472bd3810b8a312e287880e2bd28cdbedbe6486f77dd219e9aaf9757250586525d7e4285ff9fcd74d493cd95b97d4a736a00c0850e97256ebc5e11fcbf13474e5ce004044e3ce004007e36d366d19b2f210dcc1a0a10e60105181a84a1d744e9420f0414017a60e68aa033009b345bfce8b2d9e12273848bcc12323d2e269470352036e6ccffb72c1af54486f4f6a7feaeddedbd35e261d5ebb504035c0b68bddb722acb9eab90d055e72b47328538ef52d9e3bdbba690d08f4f92dda3d6f4094f85381292104fe2d63a15475ad3277daf29d5cbaaee164ab27bd49a3ee16bfae40b696b57cdecd190c0f21c297b34ced9a2d7eb082c8ea0721473f591cb08220e8023c5957f9d542796c3c0991b3e0b96344448f97f25ef2a4289ffe7f6c62e15d14211b3ff229a8ae08ae8d988d0c345849a7f2e0a11649edb9c5d8366380f8869e3b69c1828c428918418312b9b4e9d419bdefe75a680e8a0ee9b9eff3a9d73dd63ff3afbfcff96733dd23810d3e312b38198ed8536a0246f4ae41a624c183cb26b0897105c3c0e08385138610f0b02d6f603841f54d6c0e9c205c4983c80f0097a29c0f543091f54eb542b8d5d5d2a165d91bad1cb46e9a2a13755674fbcd57cd5ef537fd92a165d91f84a33ea6d53dbabfa9269b2e83ad3b2a827332d337b6fdf138923d5a25e2f105c3c08fda36bcab24edc4a3bb97b65d73064b81beaed4f36084048861934004194122247936c8c174e48283ae2ff03f00387f5ef72a18777b970c3bb5c8081a5f32f4196ff8ffa508ed90a62fecffc3f95ee009c273698231673c04a29c6ff5bcd61011c357c931a1a28c0961e130c20e4ffbf02221ebc444d10c4ff0761800e0ef8e0ffffeb59c2042a5c5f1a20c6f5258ceb8b0cae2f24b8be60e1515c5f9ab8be24717df15c5f38707d71b9be4440c30a34b878a82a0d851f23579d91fc6d1bca6e9a4804d70c3ccc40c3ff55f7c30dccd534ca7fce18dd3fefbcab485026551d52d521570c643e7bff3a5c88c7afa6db7688af5074825676490748c782a9b62badbd49e75d6700bd65dfa795e96559a7b73719a588524229a0944f8a27254bf9cf6983a5f4b61ff5962d5a5376bf29114fcd28ec6637ebc4d7feba3d8a966997f624e6ead8bfce11204fd5b24635a22635229756f4aff3f3eaf80069696a93ba32e957f37f1d233a426afdc93f4e133a1cd43a55976bfdc98f33be30fdd729f2ff40742cc8deaa6350bd65958664ecdaf9bf4e8f8c5dddbe5336ea0527aec6a6a9aad39d729a13379dea49b1dda17ad58f14ae7436e854e9ca2abd29119d214fc5a4b3e5dcf023d5d100c70936ff3fdea09a05c9d620b4ad72b5a0febb5810f3ffff3a19e860e0fef878318077b1d0f32e161a88b934d70a6d9c9494fedfc83f0e1b2bc854a080ea82d5a07026519c9aea77ed9bebae48dcf65ad974aa756beaaa7b958e751c3774ab673823fcffec5de61aff383be860c03b16bc0d20dd926c57605b07b0a7a6a6a42dc996c2784ae416a94f6d6f72fb948bb2db064a3618920d06db38cdb66f6f37bc056db0cd4d3be836377d7adafa19d46d3df6ba4666ab4cbb1d4ecff627e8a4b93e9ca744f8da3722ec4e5d1a4b9b4adf9575b93e4778dd5aa772ea53ba89af25575361eeebe5d2d8da9b4e759577daa6ea97f75ed537a094f683b22e27054399d69e04abb2d5ce9aaaeacd4d5d969dda86fa949eb1b31f577b0152d4454dba5239b9ba80f97f98ab8b5ae3bad37a4d8db9bd35ea42fe4fed978bcb13ff1cebe2b2a48a162e147009f2ff2faa9f9cb85626eb2e2d52681941cb989fc9645a6ad0f245aa4accd547ad4cc6b92b4b1b52cfd4a56a59abada6aa6a4b63a76c9c4b7bf576e4889b76a21915cbc66a27fbbae9db9f38efec39246b9b983cb99cabea2a59abd5218ef795b6a6acdbf6ad6551242ed7bd1ddab8b6772a6df5ae9af6c1eaba7a563bd3297ea595b81f9f0d4683c96828bbf5297db67a6ad36a8a3e1935216d2dbbcd6434de044b6b2aecf582c13634e57dab9d1b106dd5547a0392d17458394a508890ba9aa29b7b6e4044b3f45dd32bcdc1d6542b1559b93ad6d1d7dd9a38fdf6da4edf73ddf97f1913b211b601b59b555fdab8960b0a7abd605030348f3bda709be54d6db02c78c075c5eaff7350d0cc75a50f489d70a541bc4c738909e9c9a98c32cb26434e4c504fa6f94a69e995ff77c5d8b8622ffc3fd75ba01fd88f0ff7a9116d1c517779fa76f75935ec26eeda1aec077aeab69cebccc0e4e9b9ba3490db725e95ce05af63c1d3121427a694212576dd4caacdaa2badbf6c551c526bb891375dd33c383ba2807049a9ffaeac091794987f1d077ef72a738acb4a9395a47f7565537728086dabd634086dab8c9ca262ae3e32728ae288986cea0f95ee4e4a01674cc47daf2cd9f7cab41a85a33b639f74893f4fe4dcdb1bfd4634879ce3a6c0ca4fe7ad459cf7ce1de73cc644dcbea3bbdba1cfddadfec8252ae66796bd9fe0d98d604635399e6137d27a8c9c7ac4ac04841287bc935dccf904d18f14398ea7acf9ba6b684a9161e78da3d88da4f87560f6bc6f24fbb83b4ef6513cd1738bdfb65276cfc367eef4d78161d7275aa5c419dcbdfbd02f9f5de6e308d563e4d493bf252a66132a65389ea0d8690f0ccf9888cdb74f91a1699a27d506f31215b368ca2766d0f3b03782a1d87578f4bcfc8d27d9c93d8af9d4224aa2524a0dee1115c7cd35d98ddb8b52ea4c7a1ffa658f87e3e99d2d7bea0da2f4dea4a8cf3083baf7ec612750b817821ccd3b9f18f5b487c644ece124a8fe6911ef9173504451f1ec193f792a4fbe35f8693e92df89710e493c3a95e8078a79e3dca1b9e38f3c6322e6eceb835244c1b1f3c01ce67ca2641f39679b4a4de6bd47ef3c43347b1aa35d26994a11c5e2de39ef4e76ba9f39266275264bcd515c2a4794ec7aeca2388e9844d19e73074a65d761117f18f4d08e876788ba6298548a23dee197bd7d765dec4e4fc6b6339c5f4fce908bddc3796fad77cf5d4cc433b6e5d889931287b87314ebec75e1879e614cc4bb5799eceb65241c7a62279223e879e1e7815d18667067be39b871c7990c3136330697a8984f8ece2665474150871c8764c7a7e87d1e18c5a8fc3aefe4fbeb279ac5f1dc684cc4ecbba626c6e108bae7b744c5ecca12f34ff4ba4776e7d99dd92363221e7bcb16b53aea24fa70b844c5149994dd1bc7b1ebd0f3f4b0776e1465cd3755672e9954548a9a3cbf7c82e389fbd9654e547af814c12ea320d7ddeec42f441a2abf50cc1fe965cf1337d93b1d13b1e9618c43bc7b15d392523cf70631efa1d65fcf9c8c89d8dcadcede5e6beec7c4832d8a9dc8b93ebb107b61171371ab63bbc33521ed81e1477e9ff6b60776241a1371fbba23b844c5b452529eb9e7139f18fd72c875df3111833d504d7afacaaa451cd75756dd5db844c5ac92a41c4f94f34febfc9ddd163d1c13b19971f8ca502fec40c6b2a6ca5bd35ce05592609847929f60b775ff481c1371cca5cdcc9645439c44963b8f19ec1fd98d2238628ec6446c8ae35866ceb1479268d86db177988c8978c4a25872107330e439835b7778d431115bb1ed94897358929aa3986fb1eb780441ac632236f9aa598eb3d803d5a467a8a7a807aa072aa967f728115ca2624e01bbb087231e7588f7a94790e438325ca2626af9f077628dd1be3b527ffa3bbd29dad999b8baa7cb34d30397a898aab7fb377ebd4343ef1bfb378e4f1cc771f94333397e1925413e76a7a7370f6322ee816ad2c3bd3294eb814aea31d7d49cb12d17bdf69d693c6611f4c40c8a22ce3814f19731e66455aaca95a3d7755afcc88eecdd177a3b26e257869afd4d5b2bb2bf691b057c65a8d75b767f4b544c279de9d25ad3ac0009ef6608e6239c2c08f716355bf6d517006d03307f8e10f9717d7c7c8cf0559b1f07478ab81bf460221ba02f8d08367bcc34b79bca2e18626403d2c048063f185cf085185870c55abd1954404108e64d081e3336cdd826002313b814f064966d2b70b1ed9196ee6d05413290e0ed53144480dd0b20c0a94cc6fa3c908938d0eaae6e0b1ac01730903708c03a95ba4316c03e40da2200e05dc66e7127f7165385609eedee02e96c9053e487696e8073a5651ab0b0c9aa26ab9aef55a7e087dc780085185697e935c70328d06880813fa3020d436f25a5027df041813df4c8038f09dc61471d74cc21c71b3770b479c38d36d858430d366bd240e30c35669441461a0944600c31c24073068c2fbce8c2032d1f81073014fd1083813f73c21343cf53d4e65f042f04d8f112071cac0838c16a82e88b9d2e5cb6fcf72ca92b8668dcd1120293129a70f9ef62c29008001076b2ecd40240c692a69d233c4b549e254dbb1de2f120cde780830d251c3d09476f4bd441de8a6c6b57bb4dc9906ded2ac823f42ab9a30e228cc05f5a6021aac9032547bf13074f9208fc4e55f66821de79dd9d7607cbffceac294bf9df61572999944a75258d9d53a85497dae1fbfcdfd1b0ff1d730704299e519cc0ff8e952affdf028fb851f97f203b537e6a4d559a0b72f088e733c383a1783a1a783a2035ce1275b9d69f40b56cdb7a2cfa8519264e03ced5b23b4a517e27ea08d21121d9be2a77a0ec40fdef3c79fa4f5728b5752857bd5e7c4d9ff858f1f9e065fbca69e7839da29da61da6a51da59da49d273cfddf71d2ed20ed1cf1700064a7c98ed1ff4ef9bfc364a7a888acc829db5733dd42a92acde8096af7aa7f9e2178f00c91c05f0933c3bb43be213f3810b80df06c38ff394a03253408c28b7273066a3238f3b27d75b22a1157d32846321e0caee0c1e089ecb9d9ab7abd7295108b0aad3d4968ed495da6afb45297e955bf9a0b71242419bbba2e57d3284249768fa2a17c28c4e3dbeaa61a6789de1a67898484b297247b505e77658bc68c6923add6a9be30a5094125d93daa82113e57993c1578c05301e6a960fbd95e3efd4d5b2bae4f77e6fe17d228c0f2b4dda3dc7436e4a6333db5ce64a90b65c5160999f2df44884700523c93d9d3f67d3267ee0454e8b6ebb60441100441f0fbbeeffbbeeffb3ccff33ccff33c2fe79c73ce39678c31c618638cbbdce52e77b9cb5dee7297bbdc65922449922449921cc7711cc7711c47511445511445510cc3300cc3300c4310044110044110fcbeeffbbeeffb3ecff33ccff33ccfcb39e79c73ce19638c31c6b8ebbaaeebbaaeeb30499224499224498ee3388ee3388ea3288aa2288aa2288661188661188621088220088220087edff77ddff77d9fe7799ee7799ee7e59c73ce39e78c31c618638c3b4c8e62087e5ec64a32a4293c0e24fdbf6e3b1255f7a7b649d54eed53d95fde572b3d73db5ed3eaa66a26432d6d6fd68a55d175684913a96c6c5bd96ded59da941bf10cf1ec64f13c3b293ccfce93ff1740077f44039267e77b1e9d389e472789e7d181e17974ae3c8f0e93e7d129f23c3a0f3c4fce1acf9353c4f3e4acf0ff25d213bbd4764dc4355191935bc6de3625d2445da5bd3455d545e68c46c5b2aacbf10eb8556f9babfba9d5cdd53df6b6e9a9b735fdb1ea684dcf90544dc3b2e3fadf69fdef04d991802707f6bf13c1ff0e04ff3b0fec38f0aa66c254b4549a4e4c4e4ea559264161c2a4644a195252d9293d63db595295d094866aea542cd4481392f517698a5585461a525fd3a9b5c499f2cf72add8f5c9eb7654f7a4984b6b9a31edb4ed329aee496bf93c3f0af91f1fd6eb7081c5bfce163a5a005181efffcc028b5ff59acad276bb29ff2dfa501fe7a0f40a2bfe65aeb6dad82377e6463d61e29a54ac5012fd6ace07d85b9eb2514a681bc584b6515f583a41811a5a6a82f45452417a32999454909286909cca27734af9c42c424a2282d2f4edc1c5a36dd5ebd5dbec954e4d23f8f4f4ff5f4863f3cfbb1e1dbc9e7d67b5769bdae5bb0bfd088d348e84070a38cac829ca7dbdfea752a19f0d88fba4e617d25e5675dd9755dd9f2fa46d405f48f3d9464e51afdba7d0360a6dabee10f2bfd959c97b3f3591c9a2d5e163959299eb4aa221a2a723cb4ccfdcecd1424c1b6963c6b42f4c99e6b0e1d373ccd89ce3c89831ed4dd137f2cf2a23655d69dd107ef852c257fd93374ffcd3a6d2b389123762fcab6a88a1b4bdc9f566e8bf88db72aed9f699cb0d162e3752b889c581471c640001134703ffaf571c55ff1f7b532bb7e54c73e6b691e28da437baafc0023f7c10c2e1e0ccb3b6605df1ac29583ab0b1bdee6d9733b0a0838437cc80e92226040d928879bd2e5566d858b1410b3f5d885e1fac228cc14417078e58b026878516b8840195c6055cb411e012460826274baaa0c14546c613211e013fb8886b9298f0341bb8fcb8800ff2cb048ed8a2050c66acfca490b48506ab9d23862809c096fd02d51315ccd0c116244d62d016e4c0434b1e0e448d71eba0428b140118628a3247462d2d0039816a0b283db44cf981c84848097768e921410b1cb2ec9821bca16200893dc6a410986062460106a082510824fc5003e704255e84d0b4c51be06b06098450811ae590094c01210b1b12722c006ad2250b1262a86503b56709018503c04622d82c460b74e025284a0a5924004301f4006266b5341f1501b0caa254f3a1851c3a78c18c925aeb40121220c0e05a12345a5d5e4f841a002c20c2c2ca1dac2b2fb4803327204c5ddd8000139210a2ebe16a2a88d70f141d63ae321c66864410451e567d202df9d6c0c18a9599d797326db81c618580d365831399032bf30754d01e059859f96c518502121ba854d131c600c2a4b085a7ea01509871258b265375c2149b38cc2c21a9827aca400a18a114aa36222e4424f58186e6c60f3ed0705921074d892dfa58b202f204cd8b0f9d8117645334273b80614693110cd07898c8e8e23e20c97b460348e4282ab0df219a10c08d2e68c0e1a579a10594378b90778886858c3bccb85e06dc5c2043141f0ce0a29192c61035a71c5707350b2042c5cb85abd6e0444e0b45003744a3e3a24a55162ece920aae169381360b2721bca1071ea29d61ade20418ea38a13d1f00001d8aee00a30deaa34d400e723c6199401f514c40810a69b094c95f1959c24803cb0a0b60820f17a6506191f202123ce48ac2b2011045a078322498b971d9047c30b4316bc00f073c6584809a8db0bdc1c406138a664d1540e1620bb9c58c82324d783163a50bbbc60619b2904d80057bc496124b4f10256c9613c8123b0580812d2d781da1b2a18a8d000d18e268620bd02a819c215bf4d066ac3dd8b0c60c7b10a0cb8ac58993191498fab2762044065e50cbc2ba330489280e104503b22e945801ec408b99cc06a809c8bc90861a32348821aa20627a43968744bd12e06ea0f281b3410b788c11552abe36964c91c714ea0b2d3051c3484517aa9412526556684004d548192e21034a402a3a70ae0081e547a81c70a50c3ebaec08416502942e385391a17ab2a2a10e9fa88e4a83225018c087374957d878833592a04200ae24e1e60b6e18064784b2dbde387a6127338879fec4590d8ae36a2fc799b8f6665602700850ee1e76f9433fafeb74e61cedaaf9a269cc35df96754d30e37829fb4986a0179e631eb5d875dde1b765ddaf0265c737173b11cc7ad46407e63eca1014d131672ee6b1839a63f65dd3918f120ccfbebb477ebd13d13cced89609c7cdd8969324054aed79681776bd4331fcc48e7b9a9c9a927a7aa092f620412c7e2299711762307bf8fb46d1ebc00d72af8f3914bda935adf10eb3ef8a04e69996792f4b8f121d45bdb9debbf79888cd99968978acb56387f328398945d0033f32c424b83bb2e4388e834aea115960e1519227f98d7b730fed3abac73e8192875af7af7732443bf1f3ce3b4a8fd4df78ea0d861df86dd28e52e41e7aa23d8f2117fb178a7594ddb7c58dc98ee68f1c3b95453f1689e38c7a8a7a907aa0927a665a89e3665ac6716eee301d251a7ea3d7852307f7c745f2a4526927d932a1ba2715f544f514f53ce929eae17db562e2b8b653b55a8676a7ced9258ee3384ec42188f11dac39ca8ef7ae8b24b83f54f753d43111cbd816fd7aa09af4f0ce713d50493df8c341b0e42875f6f6e981212649deb94792c07a53eadd9de3b8bff33b439204b99b12243fac71487678f44074ec719462f74e14dd1e1f73e76171c3519218f4d00d863c771d18ea31266212a9a7a86d8d769f3d711cb77bd5d8619618569bb2effdf52d669044f5b7bf5a13c775f524c1f69d49b1de28c751445151fcf4f99d61ef27cb0d8cc191fcc20f04c390ecb2378a188f5def20984f4d7e797bac364a8f243daeb1ce1b6f10f5381ba597f3296ef11bf7a94f71edaac9ae268977e7ec06b739e2354a1d9263f7a1d80bbd0ed52057a3ec783f79c7b7c8c3512449b063b129f5e7ed7c92a038628cb3f869a8252ae607ac3525e8811a3dc34e83a03ec7b0a75176d01b39d7dde39dec21ee388ee3a6f4cb716de72c344aefe479cc1d1543b07727076322c6d2cd174ba939aeabef4973396e5ca262d25867781deebe0ff4c64f0c470f779ee879a09741fd7531a31d7be08e89b865abb48a9a53a9aaf630d7586a4a3d8264377a1deeb8478a21ff92586694e7d8f1d0eb5b9fe00876e8d879e7544462f67d7bfbba694b42b1ca28c58df9de79ef8c398a6a50ede952af62db268e0b45ecaa19f3c122a30c39dee7263bfe32b9f7e69af3a1946d2a398e771f5869ca73047777ea737f60c7f947d2786fc350882581926f4fece0f6c4afe3243fc30e8f1128fbd8791fe98560eec8bc4f322662aaad671fd86a55ef278e13db9000ac314a7d7e5ed6e8d99d24de5ca5c93ca8262a4d89e3bad10b961865878e5ec7fa13f3f9799d1c6322a6ca56ec0c0ca30449b0771bdc9d16f73ec33126e2d46cb1b899e338ee0b691cc7711c27b25660a129c73d8aa8b84f511cd12fc45d4cc4ec3b62f0fb429a17f255a4eaaae6bdaaa5ed102f5131abb0ce94b9f378973729629c35064130cabe47516b10e4e8ee1d14bd2f4af21cc1ee13bbecf5eeec204af3a2e4a2d7b527927d6f8e7a1eeea2f4b2f7e15387b86f10f43ccc4529762fe3108bbcd35c77e3b845796ef00c49116bdcbfece50eb3b4d821ea7524cf5f0e3316774cc45f28ce64a987c4caa2243b71937cefcf133badbb138b72d4e2e789bcc327fa718fecdf1565d7fceb229af9a9498f0c452b4a313cf3e771b493e0d745de55517ae0cee4d889dd798e9e287e66cafc7de4f7657c76b88738f4a828519004bf3d8ee787c52f87798af21cb7263bef9c731da2980c31044a3d9260d779077a2709e22cce6650a4283bdccf6ff74f8bded981dd78d58fda6ec52681c02a53724c76b1f34e7d821d6b0f4d89acb0a22849fea17d771d04516fdce0f7852814e5d6e4994774873bc431d61365f8a1baf7bd75d619ec5b8f4f32b635e2388e6b5f3794d1d607949decc89cb528e291f4f0d7410794a3b7f589c7b0eb1e8a4734344996132507b91e75973f0e6af244794cc4567df5dafed4be4f188bedeb36517ea4ce19a359e7500cc51ec6442c635b9474dfb17d5d326538826197353972b0eb3239caccb5ab22aecdd80df67090d603d57382b41e3277161325b8b9ce9dc77b3e3f8e379997b01a507adfd975d6a3c6d8fbd0bd4326ac31251fb9d6a326c7af0bbbee9daf0c35db2e628fc580f2cca3f8f54e04c9affbf2282ea0dca7de9d878e9df7e1fe75a78e2d518ae83e3149ee8ec50e7b60672951f253e37014478f93e3497a6288dbd7f59228470fec3e94c45ed78562ffc4d75540b9f9798e9d1647d4eba838862acb9e489459ecc08e3c3f1493bc8b1e1813f14ccb8e28c92e0c419044bd3d92e8c7c554edb011e519e6eefb3ebc41ee851924dd224a340c45b1db249a43318fe40812516ebd37888258dcbc1343cd3f3165ee488ea262b879c747ef0bbd214a3077dc134332d4591cc98f67214a510445be31f7cedc47b1eb6010e53982e7873f11dcbb13492cc6448cb1c802a20c7b3f73c71dee611fd18e747f283dafef50c42229660f1c41d4f3a1e4dcc3b98362e8e9b07b7ae71e4a54e47a04750ff90e31ba41d30c330f65e765141c31b8499d418cee9888772879b77b276a1005370fcf110c538e21e89160377ae0486a0ff53e960e25ef401ea260c7bbc6798805a61cc5b07b7b2433d6f91bb39e791c2b87f21473b749fee9dcc36ff72f26e28c43497621eea8b7bd917ba7f658fe61b07ddd1bcace4345d41bb1d7a123e6dec9b2a1ccdf899e1e397661174fd03b6322567302bace64eec48c86dd23511d13f19831cd7c65e8c8aaa1dc601fc78eb9de5e48a2181c3336595f4614837cfcce133cc11e7e5f4833bbdbead98765b4d55362d1508adaebdf476a527b5b1c3b99bd23d60ca5f7e5ef233d3c7aa70ef53e632236797f4dae67246efb6b447ac092a1d4a74633b8f5877a9fce6168aa5a9692192c59319421f98da3179e1dd8f12e92e84c2b8d2c184a91f4c8feeddd33f748908f31118333ad8480d2d37c7f5fb841b08fa2e7893111d73a9517b25e28d1cd33099ef90337297a9ccfb4920ba53e33e879e0a9f7e891587faf9b26912d94e2798e27f98d67df593c45302662f0ede3c862a1d4df38a224e9817a6fefecce6e8592dc587f7b7bdb03c3efec5ea742397e282a927b24c70eeb1db2522877c67c0c43efd32288d14f8c89187cc2787c65a8c742a114f9398e20d9bd4f8fa8ee3a651da0d4dfd99d19a322a877de7c88eb266e8a7542f975540cc7b18bb8eb9993a087c3cc32a10cfb17eacc3bece19dbbe8b9efda65b4a976880497a8985258256c3ce60fe3f0cc689775076319c0db63d785587f64e76d708c89d85b62915092a1d879a4d79de0f971afeb48cc1aa124bb8fa33df78e35086e0ef235b55a69ecca2a40297e3b77dcf376163bb8c1992cf564b4d513a1cc7ad49bf432efda3bf388b2e88ab4d35537711c8baea9292e513151160150fda19db83bdabbc7bbf164792943f0fc506ff4c86f7394f7cec361ee526a706f8e921a3dc5be37de31d174d38c672497d2cbe7d835cf1a25c3f1eb674cc42137bbacc766ba9d0271c6e29632e467cede26c1ac41de7557dd9ca29d9d9b61ce62ab63fb7bd252763b8b5a3c3b0f87e73e35564ffdd2649d371442396e1e765c24b3c6f82345de6529fbfebe8e76233f5134877b8c899877d3cc5955fbfe6aa5386611eca1b849117723dee11215d3ca552962bd4f94dc9ddede279e23c771bdb52a49ee65143cf7898e6088512f26629e9a7d567bc57588e36aabf696a89865558976e226fb187e19e53a83bd07aa49cf15479a5ab513c7719c3b63b1b844c5e4b47263ec7de09747f0eb449dbf9888fb9bb656e02b433978514f871d1ecf10edbcdec99e2575a1701cc7c9686b08ae18ee1115c3ceebe4276611cd1e8d457bba4c5367b21494d156ef95a1b4b60c51dd8dba87e749e6bcc9218ee3da7736864b544c8da504c57de6f3eb34b8f9d69fde9d9bec6b8ab88359b949dcc3f343cffe8124e63b2662f39bc296dec73dd2434ff123d1aeeb5fb896e887e630c41be459cc200e4159a977fe50d4eb421e9e3d0c794cc4ef8c35490c26a965d831de58ec67f7895aefadafba1155398e9b04f348ea8e8f5cf4784cc420d09552dc9cdc5e973fb477e19747322d4154f4341739d891f93cc72e26e2d7053152ac24456f04b9ee78888e1d45bb98884d9526eb70f75d656f2a251a43196df5924c95bcf3ae7f58f76edc1e39ee9888dd114fad2915f942cb9014bbb01bcf8ec7eedc201a13f1da5573ede69741b0971dc724d88558dca8063949c644dc612b7666aa3419b9b253bae5e128ca682b112f33f75010a3a117a23c83986cb2f5c93dde773f73efbaf3d43130b7ef0cea0cc571cc62388a1d1992b813bd90ec7ae49ec8bfad4f8ff3a380a8d47209c645e91432460000c468020424c31100304024188a8562e17050301cd90f148002548c5ebe5440178ad32846619031c818630c3000000000220333b80aa92aacca547144c509b08644b2ba816a2a29136f4bee651fbde01ce9f36bc3f346d25a1805597becc63af2b65259667229655124b5fa84e0895df5c73c00a7e547841ef5a4b5425fd7d4d43f69da8bb9cdb0e4d71a35bec0d1b892f8f40b23ca473804a02cb4851433904b9e622650194f0277f1d0ffb2ac078aa9fb24c6027877484e116cb16533e8cb558843e04bc2caf509f9d77ac89e787b204d8939d823707fc3d8b39475ce4386e4c8f9f1bd1919647522cb8061de5f98daea6aa6507d2049a55a0e9c236484ea6f17b51e7d5a3d5755fa0f2803c563166680495439919a04cd13b966edc09d4f9ca7579ecf4ec297234c3efd2833e6b2834bc3f759f35a3ac457484901eeab1cfcb83b50d27cbad55c0feb0f14771039050bef3894c30224bd033f1ee39b3e9d267cfc0ece65e3bbaacc86555252765d90792ef3006e15772dd032bf0503a710f26033fcd33eaf506d09d969a29eb214343514b3915e2b1be955ba99dd4ea4ac5014e25abe507419c0a0a6d0290310f3323dff539576cabd81f7da014f270f721d226996d18eaa8a7c079068d675f58bca5594501980fd270c4f6d81a0591b1ac0d4a51b13be5b3758d65e8c5b27c1417b8bcdf0fd804cc7e510c8a331460c435cf38396f95997df690f008569b69fd7b5512784c95f9a77c6649bd12d75870a5494b218f2cfeb4651f455d11c712030293789bbedeb6c2eb4eaf6db4a3d4d7446ad859ab532aeaf58e05281ce5af1d41e0873953515b5def75237bdebd45207ee8af041fa8bf625ebaf047df8abb4e15ef6d607f537a9bb4bf91bd88ba0bac37a33e59d21ec241c3105064132c8cef5e0695c28b6ac365e1e4695410c11d9e013e6af73a54962e19cf04ca384cf905b48e3c2ab40da0011980b7d40c08f2d22c1bb80e576dea2b5723c2b53936d4b864d480d4150e0dc975e03a807bc87ddf9fd1c8564c3422f20e3ba086907a04d23daa46ade08c9e3bca38de0f4d4224eb3822f7bcf82175eccefbc1a60a0096f665af42019ed390040a0a2898453402049fbc979b2930644da4372b493bd4ae7f6110138f5fb072b546891c340566e59e4b8d7864a7b208fc4642a7a084204fd625484881994ecc1805e08aab2667d8f19418366e1f9ff84879dbabce9bb22b9fa5cd812dbbb2450bbc10b94a041a0a9e4a36bf3e328a7a5f1347dce250701383a9143116e1494484a685ec071d19bf8e58f8c5a78c299352e2594a5bd9fecf3225d8f146289a1ed9f08c4e864661db27ef3cf1e63df66d67f9af0aa59532e80f1b7a313f65993184eed2d80c2ac245867bb005792842e5b89162e92489d617a60650340fe03ff63dbc05d353320630c79dc3f0c6e5c1c65926d5d423be33e2c4af5245add0fa041bde670a59fff53315d37559b45ea97da0a7b355e46719905809d00513a8dc379647a6270394323775f446741bc049b92a13259852fe754a866546b39325bb84b5b50fa31be9767a72a061f92399fc06b9c02d1e2e38c0987af8512cfab742100249f615293ba9203cb62e1ae1419aef5e4de38620a12203071cf0345f590a7ae906a2aa05aeef50a4be17d41084ad2b6e08758aa1dce0f3d21638ddfce08a137cda001f76584b0d843b04de9983a31a4fea7b8e2cc3f709118913196447df72f9f5cc65a0c7f15c42224a7e2b1d6a85a87208f34ac6c2b5927327d45e74b6f8fc820bf8cb7fcd50ae28ad45fb27d92b88b282ab6a90c4f4f1e0252c1a1a2e9aff35aeb712ed643c5abd6c865d18578734bef679ffae60e5ce4fc3163178d44495893fdd2a0ef674b55f0d8087380d6672e523930c53e5e9aa802abe931feade71f3f8710e04262751a44be16bfb7342b5a911eb56a3e10db1c6a04094d3f205fc3866111f4f648229849eef6f3bebb08c92e761930c014e9dd7d232a9b2c7227b1ec2af301eea8ab7ffe795b7e885f8c6fdb017402b687b702ac19b82e8784720805d79fd236328cb3084859158e39ea6e50e5ce65ea94da27e6db68dc681fdc16b27f07ad25745196357a2a88f9984b41a63a3d25a8189ef355cfe01b7beceb105a03c3b1e45370878207a6cdcf5b9867171f3951a9f3e1267cea86049ac0caaf8a0636e7e037db334be795644e70602f9e4c1de1c3d2f41b910cc9172c9088271a9ea392644148520dd1b4989da2a84572fb979f253f73aa5a72cca79ba94397406d79d0021d4367ded3e1813f755bdf069ed373ae16b9a41dea5047e223c34473727305a90c0860747181ce0db078cbd24b2af1e1fcc2cddd95f56f89ba313d44c3e359f64228e57d8dfc01619cf902c25684b977a06ad56b91e203c9b83b87dad02ec0b9bbfed486669b5c92895c9a3df42e6286aa9373bb617aaa36803d60bd6c28d185826cf4d2c800f74b400810f1bcf5cdf950c6e8103a94537c58c401ef01c969466009a49e298f9962debf44bf01061f4bb6c29aa49d6db54d1b4c5434c2d46bb2e47251c304526a9c13b18253fd16874d6e80dc88c2c5671c1310b15c8390fdb456f5711bc7c8cefaa337f8298acab2d08a7feb439b8973d3c9450f098c355049d40bf8e29e23d511a3b6629c9c489a8eed845a05789c0a94dce8e3a91bffca53f7da4f34db2b1439c09798986343e0ee80de22099482fc8620df3f79d9f7a469f910624e0d37450f5e440f267543f6bfc16ce2d8e31376f20d25f68df5e45c6fa6cf3807d42bdbd3326813d3ac56218be02959f017bf50e9b9f1584485ffceaade51640d1e0cd568f3c56c887abc3053d50b9797da6ecaf7b85ce1d5edb1f5ef928c466694aefad46a5481c6cca943693200ff45a8998b29352285cc80fd293b5aaca1432994bcc4c287bc81e10a2b6f971c0e8c3c288d67e7a4e723ae5b07f862101c1321acf840e1e1cc98b62a4c37a033aa73df986ae14c71b29b2a1e2fa1829e7f6cfb311d2fa01c8190412700d8fd6dd8b6c4e1e52d8c4cade52f176e675110b2a1ff4c78a358dda0d3c12ab6e607611b13205ecccf629be7b139fcefcea0db1040c928c8df9f34b19472f160bd6ea72f4e28625d50fb2892c4be176da8a03126a872959b887cacefb396c5681594dd3be86c6a6415054a55528acf4436430e45a5c3db24794ad255291e973c55eff6ac0d4af0e5a413cda1b0a6cfbf13ff44f2064d406484012f7c40df76673939d0ba571a8b04e154b5098529548dab13f0913ce26d8cc67090d42f6105a658d287bf4c43d496b1c7f843c2fa41dac44485f13d05d0aedb154f7585155b64ed74322f451ccb09481ff09ea2cd6a82b1f2ea1028472061e94627294999e37ff6014a9e10df05aba80fa23aac5c1c949ab56ab0417ba2609ea998b6f7719b8b664bd7fec1c430132ce7007d8f7fe761833e8c3ab5648f803e42eb41745d8dfeba4ac13464dad10749d476b0a8cb59e3d50ee51299232577f28e2780224f59d409c43401210c83c7365af00d5dd8806d28cae8c206c472b125badd1758b089ff6435164326a6f00685df7ae1ebc530bf989fbc11e4c5a5266120f711b0dbd056b0b37289933f65aa4b5c4b3e26aa63483f6619aede09f321ef10dd1e42844a3071dda33545c525e7abe4adb4f6842c9a86fb282d62e333bc2d02dbb3d07b9c6e7d05ccdd50e9360ebb900d0535410cc6ddbc5ae82443a4bddd7ad0ce0d26e956ac2220f77f3c75d6c7e50d011265c41b03f84b2e7a1f50e506349f3ba6b560cec2e742aa98f94170809376d6493b8c894312d0020730903b592c0d3b183f85059a0424a3264ae9bfc4b68e3d291e1f4ae0e49d96f1dbb34928409fbb9f9f1f22842b090b5423d2dd1b41d1828e7fe585e1d35b869496c823e1aa88bae5f78cdc66bc6c0fd9374fc007abeb575d45e988278a79a15a10f8eb6cafaaf07ce9bb9c5e98fd36dd405b405f77aca741f84fec54a73616b796d5d439c039fe3ad603e433378b6b81e4e82d61e822364a83089d49ee46554e30bcb9c61e0d647c0c0d98c2e9f7554c6fd133e57f7f85bbd32eeb7c786d7768278eed6907e4e69cddd826ee5148d69feb49a5a58e8c01f4028fdb4f80bffc8b099f4c5fc0b78024acc07d1f3d5ba3cde2de67e618a0f0c18b71cd1ec47bbb824628f7dd7a30319b1653187c417550ad526324bb1b3e75f23aef3cb01a5fff775a5ce470d6da758d23b994893575dac18d9f08cacf80e62708085c73699c167bbe4d879e38e4a59748f3769fd2a50bbaecee23d1226c8f6d4abb3582a1112e257a85ae3c68d5599f93dbd3d9cf7a1a4849bb16c43ef1f20c3e6c2cea60c33e3a67a0e3876b90ff4e10f78bf99a8f083e5a4decfa0089ddfd64db7976055e65f08d3341e22757a82e1ffe14d0a494ca93799128cda3b1fc3c5e113b7ab0fd1d64fade81de10637ed844d39dcb7bf95ed78c8c12f94044bdb6617f7f95d8f246c016e8c81ef9ddabdbe15fd3eb3e97406c0af80c326f911f5eaaecc0f8841dded30b857793a925cdc69ea64fa91e17fd096460e8ce3aa52cadc4aaf73b4c46abd250b6187f6f4f8623d9cf95b9e4689ae6a66bcef5423b13c8a216f64c8257b5f7f1d3a85193d0ced745e5e1fa9c355bc3fbafcc53ee57dc887db11cf32f3ef94515244673ab830b07616f41838f64086111e9f7402f1e836c360c872359e5a391ccffa21af1ff061f278dc17967b74e1982947c5c42605d242898f6884f45244e01f91b6144b7a146a033b0b3d6725796fa5f46a20e6fba196229f0acc4011d3a35ebf7af16b91a49677ff85aced510d50f93a55974f336dc0ddca42803bda6288a1e0b10e71f6e4e47adab7232d8c0f6b3823b122b3b68d0fbad58fa1f1d2b380b3474263f4d9ab5ff77f26ec54ab6e5b6db028ef23e987c4913d3f0fef92a8586fd066e10f682bebd83668e4534ca4064b0c3d5eb0e20b0cf412b61691a93e2a3b520de32dff3230225601ac1a4634336b6cd9be60e9956b845d262a229d2fa989bbb2f48258ce4a18f18b08070d2f9dcc802b4f433c6b8a36f7701e453b2ed01ad2ea7a4f8fbc97075d0abb77f7a53ab97b5147b770e606541c3bd7f3b02aac1e832133084231835cd9fbf00576a80ce0fd694264aed8df8e7302dbcf99fc36081c6b561e2677dcbd6bd7ab0edafb053244b2d3ce1184fde137ebc24f60a1d48c02cc56b53ca22b62b86681631b9922f50ff25a3b9a41627a65da80061f489ffcbba6f48906871865a8c4d2d52e849901565455e5b0d5151544a0982dbcd9070e84e2f56df050e9bb67984211abdbbf6b7eb74944154b0c8df3e90c8f882da014ce91cfb21ca8c29f8f5972714765c84688682f6ab970ca57b1145d61f9497f6c38db2916c0c25c5e2f2e3eaf567ac52ac5dccae5278f8ae59a51000fb7141f749906f22536a8e6a1fca8f2d9d3f101c37185db429d11e5d2969aabc889f1502241efc92e3e24bc4a847ac369adae2dedc6488c6540cb4f8b9eefda596670be6ecfb6e17b832bca750a399fb031c3d18898a8eeafcd3325325d668873fcb3355a09fc57ca19253f26ad1adabd5d529affba8ad04184c6056abdd9504e9000ff93233cfe01134545160d74a8e23a6dcb2f0c12674e3ce86d7cbfdfbd5e382513dceb56e9dd3d00c620ad676efc5bf43dcf104e7b65e779fed8b25a50081d2a3e1cbdb80a15a7f458c8001269e745154436f567a8ef10d17e64f5dfd23859d7651bf5c17a09022463ba4e007a0a5d6bbdaa1a17790834464d20870aed02c1a68eb2d1ae72cd04d235e64840119f9ec009c9b060cf814df9f7a767af0d7a99fb23e9181781639a640e42c8330760d24e5cb4f9cc9fb7001e2d3e43ea8ba7fa38b1477d5c9ac284ccd370c251127ea4a1355be6844f71c22a6fc1f0b6e96ec71f7e7260ea7ec4913f6c6edb30f62e319026c1ee25013dcab07973382bfa08d7616003c5415c4ee25664c5246c7372db0902a5615aaf7083f74d37b497496db0824f8eb2ec3459fa7fb33c36948a5105cca89328df572774cf024a0767c82feadfb46fd84023eba1b3945d338c1a1c59aeab3a8a8304910bbe00bf6a56861a9bfe0529edbeecea6d0dc0e67e6131738658335d348316ce06eaaacbafba05cce09eb425f14b2b98cec1edd06bb16950e0b88826556fe30a7c97b3aea58a83e84d3df19e31a44cb5d3f87b1e0b40adc6ab4e199c9bc991ce84608971bf25596e2db2c479eb324916b05e7bea98a337b92ef4138171039b6a367edd9e112b8ace31fbb07f4ae0d45d10a93e42b51ee6e77825b802d7dd198e0b895b00d7d094bcd370ad18ba3f360b4506c704299abd12040626050c9cbca3b74ee1145eedb875330c5fb061fe1945f58edc994ff31f1265ac0d59fa5e48a1f6fc67228ef19fa0b5179d79ae5c5d4fc2073fc92916ea7dd0ca596fe31332c5ceac7d4bbb8b05bbf5689543e3d9be452bb6df6104af5bdd59e4cf91f136fa2055cfd594aaef8f1662c87f29ea1bf109577d63664e57d9a7b881176edc32a99e2bf87897cca378c7e42aabfd8d8932de36be651ba53e8d28796107253e03642b5599ded16b6c0aecdd55ab36a0ea0064aa60366f5d531ce690edb5688ca33db8dab43e6aef5f5ba837ba96d478a80f9db532fa5217e6fa0254de13fb4d7a4fa50ee78575b05b09f192c5f0f26ff4c6ea02db0179dd76804ded336aaaa87e57d0b757406f80cdfcef404fdc19d62aa3c8940221be51844e693f30e99266b18f2963c0f04bf59f62054dca571471035097df1535a7e129c1bdd04e26047553431732b8720c74b35eb71db704eb25b3534e739d884328dae90b28d2510f9e5494305ce2419c4033641f0956c4696a285144f8e20222620b91119e4248cb2ecc4cf5ad95d9d924111f35f1061588d8923fb15e1b0d965a89c0d911e698f213a487d23ffd919e5ec96888ce64e7363cc154711e140f1ad1c0bcb68e75626b7a1eee33cd19aa8ac3439bf88a6b5c3c858dceac3e5dbab819c94aa767616ab926dbc5cfc2a95ebf92bf21fb7c9ac63d7737ed3b5a61f1967aad9944f224a66f8efa179571e8764ee59b402b30258159b2a3f6d716d348a170c812ec4c2dc26bac46e1dfb92ffd88964404fda6264cb0c4031c26a6d2eda5613a1fa5e1571a19253070fac1b8d58d1b436ea03098cec05c59519d6b49fb9405404a8178a33aa1fb00e0105d7a6c4b75eae2f8270b3d17c578f9c76200c4164d5bf3f1443acf6385bfd549f70059ba573675c1a375dc6416cb9fa16ec4fc3c31f9d98403a0334ce75291a8d3991e24b9c5dffd5cfeade9bb65260b5e6436f643de28b613db13f23d0981438db69f4f2c8b199d256bc979d8e5bf94195632b3070b963a99c6ba66be5a2fcc9ff60065e41e846a1f4e8000b2e74c35365970fd20e21dee61df0ec4a9879268794f2171027457220f4863fbf1140b5e7a7eba760195c4089cc918fe04a04d5f536f0e5cc5dc2ff7aa78228278d6005a6ceae75fbb0d98633c261390ed4affcbc3e79d5508d488cf4638229d74b216e29d546fdabc0d22e9dc88bb029b4d77bc3512ddbbe85c8acae4270cd986b05349efc559c8f30b1902560c8ef66b8c44e600e61277ee7af4a06aec250d08450fe92404574f6b1fe80cd9aa3a9a624595f2ff39d53634c024ff22dd627990c137daaf8e8e4c9cf956cb2b82db4f4a2a54e1a97cba5021ad93e10dbcbe8bd07ba09fc4b65df52247351990830c8a944c630cb621e65da8bc40f49e9596f84b15446bca6946a7a2e5aeca82e2d6d8a27fdf849139aa81c45c07bdf5aa3ec9716e7e8c809696174d8e03c11b443333d3a4a18448684d377175f30e9cefe7e3eb5ae2cb03c2d8bd048cd13d5bf9080d203f755711ff0bc60484ec110c6c644d7896347e6b15fb8b6a7418b207001f5f827c467da1aa98cb948130a728d91b5419a8a58f95b0a6efd90f48fce27cd25ce9535b4530979a8af2736e9250340ee8bf7b60cd4b934a9049c382b21563c98bdd10000d17d4448fa33a9e745a39a29164b1269290d5ccb40389123d18a859e2c78f02fb50cca80a03a2f0817f2eb0d69ea0af544c11960d0c7201e6e70e14f636966c4827d6013d62f176f69444677e131f0022d4e2e485b3cae76c644209ad1410de5b56bee1b31eef47c858a9c26cf0fff4702ff72fa17ac867a97073594f7fe3ef6a3f01a52f470db25c46623c786558c052fb91dfabea812dd510b71ed84c7cd1b5dbb302581b3f15415c02831815935957ce588171d6cada2df4a959eb15f128dac373b08c710249931cc370b3288876248af7a75dba47e360dcd49727c4e70663eb7f28a4b8ec38819ede943231a630aa4f0808472fac3d5bbc3fabde58ff9b6cf51537b76c81ba5b9a1ab69c2e725bbe29b839b18cc3effac0c2b8b786751a5bdf0d3a00ff969a7f8857c72cd81e311647c9e699f0b2d05a9e92ee54ea403cd52b35d4ba6dd07528f03dd4b657a7891aa0b4a8f2e21853d19075fd56454abc25ef060a9150f37e755f2369e1b06873c97a876aecbb21dd6efa0804fdbd7a837670c2e36b66f95c6c4c3e1b2778814ae322d88be4a749f5c7e5719dbc53f458980a2b01400a6fc7983b6ded3f02f583fed730d785f4c95850b805f48c6eaa3077d4175b2eb2cd98b1127d2146d6addfe780111f599ae79b4edff72e1adc2fe850e4d0b1d3f78f5701750c0a6eae963682cbf91bde4938760ee82f194704ac23e2dbd5ff3e7c7cacae737ba1a25f79510b147e1a5fe212012a7a78a5ae2bcfc38cc007f5a869218ff7194487788b2cffa1cc7dcd7a7e877ebcfddedbfcb98aaeff37d350e8c0e936bedf6b74f4d9b107c2881e446954fbaeb0ee2f07b1958f68a32340cdabd13b9e63b211944583ec33e482ea873e02d9a33b78dddb9c7bd51cad4e66e21f6d6b1dfca0a4a62cba4edc8e4e04e2e44146a6b322f101c9066d6884b36caec46ac2deefaa10ca05d81e7c6dc222928de4fca603f4af2caeb89f693805f4109740fe321e1ba33dde0bf96b99a45d307f85b9e8ba9e830460b4f14e606d0dd06140bf2bede83f1033a966976fbc6d267af516fad7cada39f758206f3e1d937de7d1bed0352cab5ea164373f60fee0d862f409fabe5f36cb07533e6b948b5d0631399411fdfd49bf5feca38b176928b0299442ad9b7e18b23c9efd8a625f905e06579003e52487cfbf29ce191508e9410f2fc37d5eafa62653eed56b8965afc58cb66e28c2a97e5d80e1a712c46dbdfde3a23fb5488c6b6ab3add999d4059cc8bdab3bf6b4b269a142595356322395ded8c6f51f0ede52cf13ec8a77a8205c365e2da65a22d636f4cdfa88c35dfe214b7ae7d395a5a41968d26bfe480c78f98f3b2d7cca2cb32f439e2babbc81a0536504251ff9f31cf5801bc07bd22d1c428372e7e7e0c14878d99e42da84cfe0eed1d7e9fdbee6be9660cbcad22edb930f00c504fe0c082429395c9d20c638ff28ad4e52e599754d60896aa402f24d0340824f89a1d2301e23208650af1a6c278616908a7df954139a5a8f5ed97fe4817194b3a663b46f78c2e4b510b3456070b905a85ff25cdf35627d52f776efb2f04cf32c3011bed2812c400003876dfb230b738fb23d3099b1d6074b805777b91f75e7e5a0dd40612c22bb9c1e807e4b84e9cbb11e3c67f3869b9d2afe56f8b4dfb47d1cdc6eaf8894b9f527434c7366d6f6d157476dc08b129174b75722c48c2154f0a25c743f0212ef9f8e78ad1d4adc9251c0d2a53f02eeea6815e3bf706c79bc390f022f6ec4e746f7a2faaf65f9445be726fa701e2d2efe95d9518596cfdc91394a36805b17e787d469a168ff5d98c351c349bb8139ea181f8c712226c26c16ed33912835a334daae18e8ffdba3313a11a214172891f331367f78fc5c3b1bc4296cda06ecabf02498964144c1d5ba955386bff137e1a6b7ecd5dd8bcae0abe408639f05c26f89d8bf583e45732b2ab71cd8d74577a3f177587869d63da9cc28d5f39770d77269e173385966926ae888324901627df087cd7f38261aed3d2778bb00e9cd74f82f089327b11977b738a31853205335de44b007401bd9b98fdbe8ca49bc57bd77b3bb3ebb500519f9a108d3f1f7f15d36278cacf731aab6b8bb4a8dd345c7bfdc1ef188b43177fe70e5afb5a5a683d440f89206f4e723826325661efd2c24a3513a69d12fbe617a52874142a8e6076383eaf89dbc818a95193ef2d7cbd995e68fae7e89ff106b07701c90f82ec6c2e18e69d40c06d1a66b0f143e2fa3dd4a981c6bfc39912c93a1fcd1a3a1bdce83bd8404ecb97305b74d163a28eeb70d55ba511840a88915f86b68844764c4fbe939b291372fdeca1529870ecf86a61a920a43ee747411388daed031aec217af5e46ea00f4639d7c1882ed04ebf2c2df157166bd0f7cc94f46512885c9815dd9b7d5ce581d866b14a0e9893520cd0d21d4439875a118366acd863a16006f8b42264f6727b6ade8042e5cd34440489a13eaf248c685278c15dc1def7c107b161ad215ab67d74604a02ee52b60919a3a83f60db0e14ee6b18b2c167ddeb75541254e37666ebf97999647353ad4ef704090e6df0d5ba535d48309498a9d3da15f87159fce7cf6cf80b169482e0bb82e13ee37b5ef6967d32a65d007f0599bc41a5dc6bc5a05fbfe75e902f30caeab8447920f7dc39ef56aa6cc1ff2bad077a6f00b78d3e93e63ad2e42e5c7021a07eebc412f3526a7c90a21797f22c9ce31bf78ac58ed5f4c156b663c95a2ddd7bcb2c220b8d89e166b8723c5d2b6d3a3ca90a0c3521e8431e16b9673e56c87ee1c91cf4d20a422aac232dfacb547e1db904594225ec9bf8e52c3deb9cb9d2162e0551796e4b58a3c3d430be15414cec044835ad296fc19257dceeb3409fa06585b6f94b74f19b10234740e5f2c791d9d00d2d6c4ee208991a83cc2d87107db14e4d687531b7216f9558e55b0d2742c855324655ace039528137b6c3bdd787e365bf61caedf1e6001625fa4988032fdf96c27ba60f31464939beb0281e0d1a8254cb72cb19693bd00ba3a721148b26799208f218dc5a30fcee78a37912b3e054fc783dbccded56a3f7ad4f2990e20b36f80ea080969ebc20736c1e582de7749e1e58bb93cb1629589a5ca0c8b7d5198397f53ef671a19a903075e6ef58e6a5699964b30201d392c3f3f9c72ef2fbdba85a7ef9da61a7a43adc8ff02323e19d77a80009c17ce622aa2558f4c48ea20d8f928990a687cc7435b86b55f78ac7e4b93f84105c19668572340d43004914c5a742509641c17f65a5d0be40dbf082641a8e5eb36806a69a99bae544f9f9a432c701c048526837d244d7f86cd5a80c5accc2c0c215fc3e04c2b89897d1ce46c2b5a3b93326b9b16988f6ff8782e34c801baf2ab517c90bce5790d27c8873d917caef67154f1768efcf00b8a2a4acc223b11ec155abbe8594d63788607ba803f804b74d3fcb0a3767e30646c4c71cb4792f921f8e79ccaa62d707346e7e62f29520c0e8c409e4724a37f34e316fe119fa310ea2da8cf2bb9487e659e0e7db90f8fde7ede96bcd02b2f0b8b6f5edffd9556d498ab54f2bc99686ccd2800f041fcdefbb591d99ff568aa61d9447ccc3655755f32f71baab84d8a74bcb1fa90cae45ae7cef3ec1813a98df9e4ee1832de2ad1cc7a07be379b0939b2e364745b5ed7006b8ff481810fb98f1204bcb74239330892633bde21ad3c7db838936fd1411a09ada95a3cbcf3a50582897631c5ed206ec8229e54b1b4043063d9dee944001fb808a4ff3c3ba3d08c6f9282e228c884e20c344753c36207837cdeebb6a943364e1dab4d7f8fcbd5becdeaf72b284a03b0f7eb25edd403ebcd00b5abdb67ab08c8fd501578c7f36273f7ca2a56dddfa8e28527bafe6d370250bdba540d69bfbb53168c8354667391875f3e531e912fd826c44a2dc710897809307e532de26326e99b519fb9018492f6430d5c81753b73b4bbbdca2718b2aa943ed63c969cbbae5085ea84bf91713cab7ae40c39fa4cddd19ec87c66be47c20686c2ba773f9de185fa8514d48e8a68347230af7fcbe7702b7fb0b6eaab0264b261c932b7ca476741f47f0072bda370ebef67046fab697cb763070e993109903c68766305fb69963eebc5bf87c0f057a24534c174c099f2c09e8012cdd0ab001528f5bc64780d4c91884b431e669065aeb504044e01be46e7e64cb7aee5ab8fdb3309b6303488b850cb68065a57b37f0e9614516208d848443c575ccceecf6fdfe8a9450b4919591506e9558bb2529d4c4126c00793f0ae89c210cb8c800dfecd85ebb21304863a0af570b9fd2566c219d428655f839ecee9e2d071f5a08d78d1ec971821b709f4334cf71ce17baffea460a7fd9508c0391fb6097f97d598f8d19bcb02b4d1501e8730ae959df6e7e40f8a4261f506239f13099f30405434f2027ac9dce736a730b3c9c33ce1d986672fa8233e2215f04fe4a0fbde95f4e95e26960ea80e94035da399c5f739b5343af84a15233f3fc5430e963397969724c0377f3cc8ff3fba07c274eab6a33beff72942b3f0e64854991bf3fb806e0d5778c47e9339e40a7b553992de495233f6e96ef6979d8fcbafa5f71d4aae993ea6218529b005619dbe0b5945369654d8f6987468e4d73bd47dbb723da768dd05bbc2e679d0f98be4e7fad692643d988001aa3e1df5622ec4b0867ca432a47a5cdc6fcd04453286c333236b86c6acc18c7749195049351c85a314dcb81903474bf57ef6b495bd83221fc200be0c49e6696fb2802ce5528b65f9ea4983fad05989f36230e35acfbd39075aadac19775cc5de59bbaeb6a07d5746e1085f687c8316a56a79bd497da4fbeb7a27916b84d6c01f74fb1bbb2a04f93a18b26b2b37ebd5533b8fe5320566ebdfe42f2c1b54147995b0c2e5919d0e107a6e5bc179d5312fc34bb61f5e26d079da4f8bf21175970e05e1541271e06c584bbd70aab1a6a7787247f1d1a9f51cb280bebc8d218fc7532b9dc591611c3c1ec8bff378f731482ccbb8fbabb2522bb0c4c1cdb5a777415186c0a45ae413e6bc73057fa057693083886b29a43c9f593ce707bf238124c6b47d5c08cf981f20ec655301ed39def9770911631fef18f01940388e10513f8b17ccd58c12fd5339116883f5ad0f9f827451ca8b8b7e8dfa32922aab129e9e98b02cef37437cbb8f4bff7207fec50aa1fae1e854ca50763ae9cda32dcafb9302d406894cc3b6923b2d18ef85b4f636ab489c41b32b0998e743708e9b38822c9e8d993b65c4cf2372b7d63e9db48b99758197beeb53f98f1dd592ee6a4c6482226f231948e39d9d851a97339eacd4ba79fcebf492af5c20b78cd9aadeeb696769d684005885904cf50a985c85e8fb4b647423791054a8bc0163460537a9bf609adf7537752a8ee0defa00b79fbc224b073c9d78ddb63998f276fb4430fcdf01634d070000c4456a571e775d1fbeb816d4b2db857edc34cfd787c198f9f2d12c62d00ea555bc4ec8f3e1ee6802737a6afbac9b7e12cdb110d83c0780d2c4309bc71974c90eee5dc86dbc029540d4e525a7ba033d4d8f17aec80e4e88412ce6d3c0ec07c934d9861957f49514b5e8a78016555fdb98f07affa497f3f31b609d455d35de08e2915892194d4e25e21a20708eb13b63fe9c1dfaaa41152ba941761f2adabf0def7bd3ddfb19d62d1ab3ce690b179efce710f97d96dc750698ff2324efb1792f7e92ceac16266c9e93ef9fd73753c898301e49914a080fb63e0a16c626ba713de0e890a9e1aef1b7c22262676eca573db5bff217c6c11749f64a1e35211dce70514204deaf85901189e881ba2d71841c6ff8ba848b270f197155719bcf60536e77ce488d7bc45945b62a2bb5b485c68cdbff81807e48b8b1adea3bdc2f96188f76173d2bc08539585bff0c5486927524add28bb2a1bdaab2aef3b5982ee2bd5840ec9fda6d376598e169c0d4f32da38591b263997c078b369ec9eed3cbe26710f1e261fd3f8fc7865c4d1dadb9c7f2c12e675753658a944aeec2477e3c5334619b6f53077ea19d7010189d29aa3e28175151248abda09b8d204fdc677b52ec6ccda15bb8e404a8c426cb5988e7ffee424f06ccad2df9d4004e492ad4b147743d96dfeeb1ad2b8ddff66b1427db6d1ff69089f65f5ac09c701cddfa1cbdf3497202b62e14b440575a402587e4c4bad247b2eb249e9e82dc95410f207cf566d212b4c0b7a70cffdb48971653e64b42ec70b0eeab84f797115ed60196a55e8a5baa663853cb0827594b0a86b9500d5b25370e861511adf694de1000911aac3af253bb95fc89a31f0b66be2c68e1a3da1a551cf93d3390d36312a0d316e2ef9ac37a750cd510b55faf3c679f1478047623c1506507c4b20dbc1dea1d0c67179858acbf89df1d101257f763c0640b1b4fb5c62e81d6b322f9deedc14ae328518ed89cf9c11d69d909a701550d242af51119cfe2ba0bcc2123a7974cb06eebcbf67835e3689418abd67f28f1a02feeac2bada8ca6d7d741a2e20e0c169129e3f55b2ad68d5bbe33af9ba32d9f70afced44ff4f179a3bb6833244a0074d130e64a7a729dc246269bff6d4ae5a980de8efed3c24ed84a47bf6f604016ebea9e6133943c4741d50068b2e4e41f9293e94ba223c9e7b4bd76980d122600b5c469ee5771a6bc699449829f4a3cf0f12b6a35d7238190a85da603eeee0575d7e568410a8119292009e0e7620cd5fee8eb4f8c15d499817f646cc4a38f2870b2d97c004b0961a9408363303289e160eb155263a2e20aa6b757a29d6a341465b878d0df9b2d0f3d92a6de3a19aa2622a9a458b0201b2e1a8383aa02fe609bbd94f871f470cedbfb52aa6ffa7ba9ea6826498f9c1fab174c4b3d579c8f5ffd4bb0e5ead72b70e05d8babbfda3cb8928ec6825631f575da20013963a1089cbf535e73e7672157fd61a9ba26fa18330f7b1b4dd6d78a63d302e5caca40d5f260cafce16125c21c7a006fa991a9d694559450ff14c05f6386fb374a3c5008aeb7be585d54e6387cb8b42fc59b5dfc94e30f163f6aa630c5cf5a0eb90fc8655ac1d93f4336e7189288fde928433cf972dc2059ffcaf0658efdcc4495fe9240a691f85d61c564ac509638429a6cdcfe8930b1d30932bb84457391c7e0c5c076d5a725274295d0694c7bd35c43b400694e296950a9e38262e7f8dbc163c52c19a1be4d303454a59f2499c4e9528abf3922d1894bf0bd5c6278aae15c20a63927290539ac1385dc22283be4b636bfc199abf25707009a8e5838438dbdf59ec2a088700c07f1c242d9e51cc4c0a84944dc9814e2de885ef6144581599d557f4de9831338d74cc387bacf28365d1b0bd9728e407523664535deb70d0d2e43a71d948d10f0c79f55d9687bef5be387751de2536c4e44202000caeb9bf7aab2eca6d14a9fc4c2133ab6300166cce8dac5ab493fc1faedca99bcc74a4c5285add0455d41b31f49007ff102df50d12c8119faab49252052cf1c9f25e221ac008c6b4496e6a772a3d4cec9d09aaeab9035cc914bbc4c01c7011b9e80315a58146d391b44ff28e1d8f606b43be41a430d1d8e3df5ee05d6e24b9f44d461b4a4b9e8bd181541be8f73ed4c1255d688f835f230d6933efbdded80cee0e86855f47bbec173eb0118e2c86d122685b862ff7e5b228fd7e0f9072635cca88d4b891cde29b7f5b4e8512765c0cd0520e80dfe8ee402e2a92f0d8b3def34819af74cbfdd6e06d660fbae4a96486743206005af60888e2aeac5fcab5765ee7b24c388fb9aa0761f8ad88f64f860213be2283ea54365382888e452f01ef5de8aeb83ac7245b49639fccab1133b133f6221dfb1ae4ed680f1fac930c8cfab4f396dc54eb5b439e35cfb04be015032c510abe37bc4f60226723b02dd8afe7bab56ead5331259227c6656f5cd5ccc502c266986bd1c8cca1dc345dce4b8f478c14121565375417d170dc9b6cd764f39af0d51bf006441f340b480e4dbd1184be574aa187cc4d8470893da74906a1531c988f6bea9d1d93480f2f66de4fdc6f286034e46ff136c7523b1f1d2547a8f6f4b16825941ccc4727fe614bf6c9f99adeacbd403b5b8ff7693ebe823c1c108b887a18609a8c53384186580b20858d5c18048d8d9a93ccfcff160e544be67129d3881c120cdb23b4be922e84e21017a66831096d54fd1f6859f40c5acfe0a4643aebfe4a0f839457c0c17125a04a55e604140a991974bf0c8c795250e3d6cd8f292fbdc43dd2256c50e64a9e22e7f39959b0e579e9d0cfefe7713857df4bac0b9fd1274fa2d85d2fe5ed41ce5288d1da9881535b1ab3a640cce9fb91b2aebaa96026e5cda951d8846660645e01cc909710c27271700617c58599a43da6d1f4e3c5aa9a53c138fee66a3e4333a0b6ac193ca91b2cbb3037f367d23882a39f6eea1dffe7965e23daf02234c65fbbcc0b832b877c0569eca487eb49371683e528a9520c582f73bc86aca57ef56d9e041a079eaf68670a16dd931f91d00be81cbfdd5853ca9b8df9a1d195848bd909e32ff515bb63447151d1e40eb85626ec496b3a797fd8e66a353515e30b3fa6a3e0c953a6349b425c1a513b93178dbd62419a983544f2821edc6396c69a238e43772fcad253f59227b6f781053c8721047482735fd7a43b266c0bb8a4d8c009c2fcbca4aa202e0a847fdb294ec15be4ef301be9037483c82563b883a5c59cf21abf1025281f7b35f20094af6dd10114ac141efc164b4e36ffa0dda1dc6b14e51c0e483ec75ee74c2cdea64b7ce672956a214aaa7cb4f4f5107579a43f7a9826b902af3f78c442ab7a4cd085b1b1202cb5766b1ec0ef7e816d45f430a60c4e068caf4d8cf44ec181714701e6d808680674c23d698038d8be88d29337ad2c3d797a01e4720ebac2ac7e2962dcf59c0368cc4ef83000c100e842a550d0f89885738caa5121523d1d86317c015e4bb2bf16960dcc14c51f7d2eb8d499dba80769c6cd0e55c4c7d74f4e90b034c1e75cbfdc8d7a95eda4276202e3dbbf9d14f7fdd7d0a30a8f09b91f209b22b1db6b64f1307e07bba701a5eea0a8166d11823b2de41a71986f67c585a98f1659d1b97c79025bd145adf542f398b94db3ecb7eb8f8593840a434ec627c765958b64e278a7922e4679ea4948e303dd7ebc4c3f5dab1b6ffc573ff6db662639e10f6a1766bec2e4444bed8dbd0b6b536953e6b22eae7efdbcb038c57e4b05f3b8f5c0fc2cf0118156153ce7df394166892af6c570d4de800297cdf1b1bb94f02ec59ed7721dff40f65121b6b4ded6f36b4db3dd307b95b7ca39e5a7847343ec67c1cf3fd1406b1b9176a7a0d5917dec567860099dcf45187d2fbcfa63ece59a71dc466a6291a92d44196c334689e0702bebff99421046a60a82b3db25280c5dc007b69421fc82a4e72dd6b078e8eee75ed1e513d9dc1fa0d36302b723260fc882b1a4cf5c8a457b1691cbe1362c14dc96143b34daa2b81d0b220e678e19548e129fd195ea53f479e807873f05a158c07ee1478ddc6a13510075ee457ff8988029e55529388703a81e78c72fee269c5ac3af3a4b7badbc26151387cfa81010d62fe6fd0ff43ee17e7a36c89f92316f560f152b03b66c6f81a953a19feb0696fe1eeb92d0e9ede899deab7dd6fa76be0ab5cbd7ba0931d7c7905c21a2e8dfab91fddeb77870c882fc5b634a577251cfc4269adc21a3835c5f6d2b52767f038ccd0aee015dd612f64228303bade510d9ad95fa9b86c7f6adbcc5a2038bd2ce275a51d2a5cbdb4bf4d99276f049ddad5b32d560eba0c48908a5ba042166eb172225c8e8f47bb76e871f5b37d1cf7a051d365a7f331e681ec7d65a58916943283f51066529586975d309ee4963cbc80e7c6e553c1faefadd873e755df422851327bd78b63d2edc8d20efa06babc87557bb6b6f5e51e74e15a4d54f5b07798c7878964745abfef50a806ae5c6fbe39c151321a75228c7ad13b30a03ea45dd7161af317d89878d4b5e5f23e2e8e50d01308fdc51d56f262e5222db53ffd5b120b07aeeaeb347ec6c489f8d289ce0e0a2924306540105680f422ab9e9bfa7d580690e075a62d2926f6953dac66dc3866c325367bff7bfd50f8243a834e95a969af568ba4f7b7306e392f0c2be162cbe4d051d2142244a1319730ae9697465712b96cd25ac44473ebe96cc6e9eb76805eb05af66a7302b515b3d9fdef4304c3267319dd660e6dc998db9aeb0ab409290eb78662dc082accba18174ada35087c57f811bd3a03f04a2b4350d17e28f663425eada2726d6e0f0f6be392f107124b03b4083c58a4cbd8de72e57c0c86018cadb5b68c4d734f8f9538d42d4c43c9878b5d7482ab3e8b904c86e58b0c85a2bb2609cab63b49549436c7612f27e21419ed60d3a105d753639fde3f91ac2361f67f980d81df794417ed3e2344d0caaf7513101165669a61379d7e50d708e1958d4d1b537751eb7cb2fde91951566d233c05480c1d59c658da027e65e39b15fd2e992ceb933b320bff6f4b8f966ae018f658030be8e0d9657e6381309c06d0eff6394d94f1601a92779cf0278f8aa673bc60d3f96c4646d31c9af7f4f093b1a8b3baf2d9347816d4b043206f24e5985c439e99f61ad0f68ee7a32b3d3ab1a8b314308e04e2fba109603187fb036d6dc74dc61ab9419221bda146cd628aa79a00aa015fd5ca24bb75c590bc050b83b696c3dbcc20211d8aef61c2af93b24eb95568c4b079580a98cd154132edaab95e238d0e66c61b5d3d34dc9c88f211bb644d57c6aa49d6bcafe40f3dae34272b2ce417752b4d3d940a285110d7b3459909ac20c436b30857f4e5839bbde29cc2ada0c3106d6b9791041a99a721e275253b7463184e415e37aaeda6229fca6f10d19272419e3bf46e4fa199725092faf198c829e53aea04cf70b97e0f8577313cc642723705b9fa8a956cf883f0190be4b6264151fee80910cfbba667f4442aee653b07e5d96e884bfc629ee5e904a73555c7fdd94d06c31d3ba9d201e577ebc474d9a22fd506df340d06eee39c0987d8372522539997b580750ae08e8d68685354b08da7de4097cbe78ef7be390d34630d8dc403cd103d6656b735b6cebc9be46b5648ff8e389580e07d200baed0bc853d01b198e05a50e097a9a82097b4194e967da15989d101c2ceaf67d440738295931c5c4c2a7d2615a57a28c6d2d1e119889e36442c96c56c20cbc626bc3381779ad214a25e9d4b36a74c566628d4128e6c4e631fe327f06b5fc34e7782f729d5b4c687da8ac7fe7a274c0a5403f2b56881bd85edfdedcdbb68711709f4707e307da4119602af6edf30308e9ed63491a7446d5d0037b58fb1d16d9ca62fe93c69a38549a7b33704e54d420d811b2f0b4e870d9c98e235ba836c3cd1f7b4a335dc4f96eb86139a70c942b683f4b41a2ed5325d4b2772fb545dfbb9d139201d9b1fe27a13a026f22d5f4b2b15135b760ff86e9e37536c34854f246d2539143d753e1e9603964d20e84a035d1bb5e0dd171102f0a33cf5c021dd12bccdcf73f6915e8d30ef1f2c373e5c8d3033b558ca2eab3266a1672a4cebcd0b148942ef49b310818ea418f66a72ba3c9b0223625103b6d59047669b007a83688615417f23c62d7d2c12f52c9739b7c349378626e13be731f2b1b7bbc9b463b8e991ec74b9b4b9218c2e8a55dbdf2ac5fddd1ccd3c74d2499c97654ba0025a9a3ba0be0291cb2debf23b48536e787ac5b7265f9120c1f56c51607b5a1568d0676f7071af28193b4b20aa0d017a19c97a38bbb7c7b3416691b1ded56c74ced11b094b0ece7de3def490d3011f488c61623d40064b5461475585338508095bc3bc5f39ce4948827bec6bdde570203e68c8237a86fe101cea12e3a314c4ba19ca434968a75144155d38ae833cc185007ef4f3bc7898117867c8a8435f211b9ec614e51c92de7a39ba93a0c0ceb45089502ca88d59411af04b6c954de0d1263c207c196568fd3df64c0a04fcfa573e7e55ebc23cbfa7996c1754c67c00e3f42f1a504f43ff84c9ee58d1fb10d0006b15babfc84b5fe11a6f27c2c14124dcf78f3e1ddf789626929b8122c2f578f899cc162e5f055b3d87dc4d094c610270e8d819f926c01fc63a6f3e5703ecf282501f239942563d8e93da687285419fbaf3844fc434f8b6caf7814cae8c86d0d75da03a7e1cb4e8b5e46ccefc38191c2535e8f03928039d9b220c3a9d0dc3d910992aaa6dab188d248c26eab21c84e279f3abfbe81120125544d2de39bc6c5a9ae56576db867c2d3931459c71a84cdfb7e47413e6facde27354ab20aab2883ad4ca6c60d64eefa695fbc97daf779db55c8911094e2a39bb9e43883471b7ff9cb377dd8a015aba7371c227f2b6e70a198dd16cbab039e2e0dc208d86d19fd37afba327bd1d4e450e822584c2450cb8e64be5869765439f9e56afc0899e0bbf47a556e992ce289ec5aacc98a5a5f22c9b1befcccda501411c35c4d498fe16f22448d00c5cd42df6f737d820e7539c1ec46c7a26143e528dde70c361b89214194794cbaac76d94ac88119dee248905c33e119c3a7a06d1ebfd7e082d165f44de70f66bbbbabd10908517b96b7bb7c88307ad135958597cef6933fe7a4c489ae3f81f03319363e480ebedd8de89102c014cd46797d36a4dbc4c0e46e69b1e94a41da73f0e84fa2e2723d5c58658b6458f827d3355d6fbda28e1acaefd030222a600ecf58acefeeb638fbe932a7b1ac9188ca6891d73e20e20a4bf08aa98403db3cce837d36a067a9735d4e6c779344cde2c38b009ab4575296ce879b445ce101859060dd090d74edc8ad05ef93287cb8ef6dec6d39bf4ae97a80f9b914a24370ab584ad5170bd778b79d143447c86ce12413d1272b55f7671fb43f2646ed9d3412a5748cbb92e28bc4a4b0c163a5871f76815ba3d0312236e190ab8ac8d175fb4e75b4ca1f0cea0cc05c573cd079fafdcd11bd524c0e91e09afb73d53ebd6a9097ef877a7fe886c1c64f0ca77edfe5142b67be8b5d680c21aa5de06dc9df97d4e3d1e88a8f65564d3de2fc4cb52e22ad038f7097ebf6c288c537ca49415558d04a2953408a4a446aea458447a0c943b2a16a38794b36e4f9fe1520a9f1bd9b362ff15e5b8a4aeab998f1c5e6707e2f10e9cf26654dcf965a6c38d124ad96840cbe03dd50a03aabd8d58ff2e82a65ccb0e3541ce7b3ac37ded10d9381e2b273a1b501ec204d312977ba8e02114c77b8af113c2399082e8bd6c3d953e7b7a4a17241bff35f37b128cb27916f1468d28d2dc8b204a70f25a8c7f54a23a0e019a4371ecccf450cda43f9089838d79e29998bcc18133748b41cbe11811999631994cd5c8c44caa7cb6081da549cc762ae68126cce94d3111eedf9f9bedfdf9e19f5705529e5ba58cd2a7fda91e5cb39de4881b490e752119d98e03fd02d5eefa28b43f3a36c66645c2bc5779fe6206f7fb7826c7fcee9c9fdfb182e576ea4e2f69be6f668e359aa3f959ee724fed8ee2f9afeca0154ca9fc73f70ceeef9503757ebb76d89a032da22f6c5e7e51e47042aefd5acc5c07a6279c934d21f2d3483d471585c68c3642bd2612dd67cbe16acc3c03f69213610c205cd6304c0a3961f4cfcba17277a899f1add9354e3aa7bb8739ec34301c33704cc2ea7837f669c8e11ae260dea386d7a1e88ffda72976df3ff0109e52de0697fe4bce9be7443f55b956b3f8a592e14b0c33b83042b804f883503d6f4f032b38162e918a73249f84ebc5f0f510beaaa05c5e081e33d5d34bfe307e40c5057c2a66bafef9aa71a0e7ff31f385c8eae987bb5ad70d556d13d5be37bece02087c672dfc03b444b415f13e4b8687880dc8dca4452e5b8c30420c9422a7436e1031adf0b7c4f41a94c783b2ce1c8682c123599b6a6d2cc239bd50ccf172d7ed6bd6a77ffe25445b148a44c387ae2b4fa38d0e76fee6e7fd77cfb657c11a772270dbe91142148a6902be217807ca65239c6806cc1bf142c12ca5b34fd6f85c89f8bd05b16ac5fc91ac6860dd38a8c6e88387133cfd4756330966b461a8cb744c0d991453336f4a60cefaba873b04c02269537db6f3fe08dcd1fed27a2c862dc86b788d6d3c9331643ccd77e389c5d16a2753fe0e2ef53bcf5df2ed827b86fca49ed059879e093be9d91f1c5922d7c1c4d2bdd6076c8f785de6aed30797943cf38c985796177186caf6f672921f51bcf4cbbb7fc29fdf25c6659945d4ff583b4c137db78bdc3f87df86686318d04389fbc4b518d30bf18b717cb1f776915897c56cbdbc2f725003bb9ec5d79939770926636e7bc3097edbe9c93f91c6fa9134d50934cae224573e523045e60ab65df0825f613c77b7622e9f3d3629cfae530211fd4f9aa33a73c8433a4ddbbeeda59529681f19e67c869d81935d92d1abeb7a3e3b967fa98e1ae393e7f62b93f73c15a983c294696fcb46cb5d583c555742c8aafc07defeb4c811c41dc7446400cb5572279c7b9c75956818177480cae5c8ad083cfe015786e0b0d8bdab5ef3ce5a3e85688b0bfa861150b43fe56754b508f540df5647bd8be4f0c7fc3fec0df4b43aefc6fc308c810fd066a6e4b862cb27c26f811ba407d60c9576d6ccf0665cc9112ac10b79cbf5ca978bb7e5dd6addde66ab9db6d71288c24fd877f6aaadde4f097c7da2ba7db43d1e5a13d2c21f973219abe2040e066262621ae67685997d59c10c95c2e357d20bd23d55e2132e3594f7712a799dcc56008dd6fc518bf2306486aee8d2b987eb7f340008d33565953ec4d53c46294aead303c4c3c04053d1495a622bdea1de7148c1f93bcb957ade422fefbab23fd529481c69913f51bf24807c57e1199f83f625cfaf09bb4cda90c0bc5beab4c62ec19d16775d2bcaf3022165ebebe7f35ac9cf79861bca2136125d2943ddede538cc076ec30e00f2027821b786927cb61541bce803ac61a80fb32f6a8b0a658b0b77f643c8c83be7a6932c7af29764d085327548711a983744310030b7be2421c69536e41e1a38439e3904114da32e0281ce7ee8b443ac41a22c5449de9c4f9b8052e6e5a1bb8a54c8a7b2884ae56fa2ccb780026d690fd336fda4156f528bcf75b8579e7c50d31565938335d0d6794a313920805fba890bcf3e633c1c3b708688507c77e9234c107de03e1e55be280cad7e71f265a6c93bb649273e0b75447801a74bf66e248a91920c2a11d4294bb5557d31671b8390daba19566535bb30d99e195e996643dd1a75883c8cfe2ae8ab2ac5c2d59d69b5581c4279d73d109af34196dd6424ce81dd3e68d98a4ab07a706c5d0d08d8507dc1a9181e7e9f867bfc56ee6d1cb7e32e4b9a74de40ceb675e98876596747cb25402ee1d7b957130428bf70e02fa4adbc25e455c9b7cb0c0a4ac4cb751018408025f61ab87828ef100104c9d4d523e2d6c369e3d0bd25d2f1f3c18cba35b482f9e32f6c5f5b8d11fe5b59bb40263a1aac6c45c9a0f07dbfe221409a386b03711fb317edfc3a6702c307ff035eb485c7ad29a2e7df0f0e129fb3d1a59154c164896eb741c627daa4c958897ab860b969456796e9c3185e5d1d55019bcce21f609b58e4950635837bacf76c02e7a427ef2eb3952ca563978001258e420ab603601d3f4bdcde27454325d9de1602fad21c4df95b30ec827f9f15c461251f82362d7231a4c0903937e1efb8063680a2de64b77b6e4dc0be880b091eb437b962078f144e2f2e84efb602fbfa8146cb819c5c34c1cc35584992c56586b3c146d27de89a1cecf66082b8b1a9e52738b3042915144e614832faa69b5a549749f2a60dcde95ab851019f504037a9362e6bc522c7ae72d7808723f8d5fa7d453d4930d38fd5c42a0f63d17ab908b3115a617cb057fed69af6edc9dbabe12da98c379fe75b8bb12e1d292ed22708f10110b8583f53759014c8468681dee8882ba8355fc8d2519b61defaa065a031bba01f695c72588467f3ccb32a089f1b9e2ef50ef92a9aea27ba028058c7e389b4b6dd3d109c827d7771e64000267304d9075fb552c61a527d4608fc91ec87602caa7731f2ca8036b6e8c27504270ecd309b639fec63860fd4a913461eed05c700cbacf648b7bde403f6611ca3adcceae53ed055b434ab7af83f22fe625ff6fd5bb56be0188ea97bce96a82e379bc646946349a92c2f42e9084d465a887f4b216fb576509d133844cb9a929c8e972c3dd0fcf0c0d7eceb762bd9e8c7174cfc05a7d83f5c311c6fae3c3cc54edf5084cc8fe12b34b196bed581179d8ddf6e24753b1de6137592e9b4aa34f4d19e104523f88b66a6f67375bc3c9d25fba5f7c2cb03c17c29f98e043dbb4794dc5d4352d9bc12ac1baf90ae4f3dc2f2503182200e68a5c5f6593898cae49aa80ef35b87150d922e665583869562dd61aec16d579c689cc02f1b0b511bd507e869b2902f5c8260bd783aad5bf659907992b9b3d4b1c9a79027969112b35bb30583a539942ae70ea1cbfc6a1ddbc1042c888634277fe2d260019b7b2d2303c55569e6310b3547b98a6e535fce26c344767b53c1e12dc022023fd5a5236d30ebefe8c7b25760fad60c325384010c8a188a7fe48d3af43ad9737df237e3e970e0982c391f458058f354ea9dad4e089f83ad1722b28f0cb1a465a443ca2a9350172d38c919a975c3b174cae8c5f2f43852a9589892578f122eeb02acf112ceb5aa63e058e1cf6b9ba9840a9bd9118bd04178ca06e688b4307da14d76d1a67679365beb35d800fd02f73ead9357c2446bafec606d4e7b57f334e2f12ddf6af322fa1676d25dc6a04aa0da50d1de12def527fe73fbd42bdd17a12c850003f236c4ae3a1e5a4efeaa384b142d8d06e7085483af9343b256754b4b5d442c6dde70c74c606e772b6f25aff7fdaf155256f34be054deb4a48740af710000bbc6b79c628443cbbcf2035f6ad1e9db946011b0b9f8752b0d2ad1e5cab288ed79827ec3193e8847a17686460a0dfbad5cbb868f586b0b2a3b25453677766d32dcfe886a1a64908ebaea4bda1832f01aad657349f59a66cd23c9c8315f4ef008eef9f81c658dfc7e416fd2af0e5583684367c5c08e194f1b87b3a66a9a30af84453bf64f2ee5d9acb596f7f956dd44fd2bd9c93bb28d5a1a4baf42ad59ac473172aa83b0a0d881d12a029f5dc1389ddf50126ec0d6e7a29e71a497660e889ac8c0a193678d1b5b41d973c75ef6014652ec481ba50e0997055f9db557ff5d48b74fc62e10b1269b221fa21174e617c6f317e044c8c7c8fd115504831e579d348174aaed6730ec38024e753a4c8ced2aa222bac40886fc7c30818d3b92b56c5055805ab79c05be53fa4ee116a4059bacab0af8ac8de5c30ea0b519e7a0c732966ec0a7859f49e6986ca35f82555b057e77aac3bfa9d8be60fc59409b642fbc6fedb94a9ab2945fd4c87b12503c6b396d65074e34c29903d7905ad472199109a3a0d148e3ce2889f1dc5e40cad0aebfa1d56470a403ad1af23bb471fbcb3c2d208cc21bd6130260c38a4870ae1114bfa4b89e8ca79160da31824e1f2b603d248b26ba74135c07daa40c1826a87a3f462f845d70cfd406e2e7ceee0d4a5a7c7942ae6d4ca997b2a8bc91c00ea5e56c5d46b8ab06f44cb2c9088221c5dc3e2447ba55cb824387121c2f013f756ff08e8a4d6ee785cc5e8d902355adc26eab1b3573bf3ffbe4aebb7e4960f48b6019b0808b6224ae70ae2b843fc787ac2bd8dd297b35c4ab055f8399fb1f1dca36d6e23e4e622e8e558fc2e4ab23c8e5ff06867ac72bc6a9944866c9f934d277d3e3746c1b28ae49649ecb9e80ae7f32b399658ceb3179f25154fb8e413e1354aafa43d83ac3221317e1e05e5a4ba3c3ff8a2f06183e2da45a2fcfb668d2624c63ab15166deee1fcf052cfabead1a059937ac665871aaa65a28f07d91c0ae4c032c803e563eae9436a3bedfbc9fccc13a491c2e5629b1cab195a7062103220dad0fd45a33269842d65e4d68a8e04186a58eab3e19721e4349dd74e1a5bc264bce2adffdbbaef135214e9815117014889dfda36750cdcdeb295e31a53a4d0af83b9d8c45e718859e4333eb63326a2de15fb38317638e18731859e04b4410585dbc9edcf22e685c76e96bb522fabc87537b8c3a0e1b14e3b682e2d40c681ae22c84606a929e7cbd015e8ca74fd66b93186dff915adef2e774bd99f6266532d7596c944d5b78347151802006b049afc698ea7394b04b79bc61fc5b31917d8f8542157274ac69556fd24d7fa940787e41140408e50e1a26df4b9d2290fe9f7d8d2c69488ba50b788e2026381523417e41f316e15291b62110627029b1d588911b9f32d7360fa32e1fe0ae0354898b20250d185ac42cf7749e924ddc70c230b8a949e0f6efe2c0fa2208dd25c9f29d57d111b623121aeac48b38344be5121ba97c7ecaa29483615151a6693a102845e0b9e55b11ae3587c8b15a3bacceac7fd910cc5949c55b3bed876fc50a9ad4fa45d114cb730b012ca490b9cb62e640394a3f925279d759b2b81315dd7847e3c1b09a54af8c189308e6e2d2c00a3261641300c648ab033579dafdf9b66fc7f5e34b6011524c0fbd040275932b3f067ce322f1d285bb8fe26ea0515f94d11c73dd94036567a7afd0f5b47391c53a1ef47f21920ce6d680e0935f37080412f425a370a9c71c631e5ee0a98af6fbf519a00977ff2211d77db1e04fcbbdc5af721bcb435817dfecbd861ef7c50158d82acb7a42853940d8115aa234c041e4785596247b27b549b2e4c79d17da87d3182d16d428f17806d63a5f4a87534e02ad3a4d8d7c15ba9425880a37ec987513b2c216eece8febacf554c972b66bdff1880bc3ae3262e4530dc9cb2df4690a9280c9454900900feee4ea19612f52d3f66781f72a3534aefc1bbad320e2054b10c03aecae7d68cc767a032f1acfdf76320a796b2842db7675bdecbf7b37e4eb8bb3778b29a2a0f0238437bd6c0b82875c3261dbdd45114ff9bd01562503bd9832ca38e0f3fdc53c8f629071d21941d921250cb2d2388109aabaeac04ae0a893fcb2b840b5a3e55460e08b40200cafe2d00cd3892025a15d7914fb243de80e44acb8c1c4dd1c7a7de825381ff3b2393c44f03ba96168e1f061c72e404e463f7db98c085ddf347a9ca9831b3082e06ed9ef5aba4e62fe6d9900b290836acae265b5945b7084240e5e4dfbdfab7828794fb53a3ae1eae7b4c383d6d465ccf50fb8405e2cafa1ee1ee5572ed83ad77e8c32fb81f083e459454b3e6afc9acf75d35983fba17e5a3893e037fc3bb93a8020a240412794862ead78462142650a2899121aaa343037708381d685c5da6eed9681027bbec56cbb9b75defee364d4f4f9c889569e601d634c1b2befe62b10531b5b7ec6956044ddd69d7ce7c2b8019b4e0adf5db36e05b7a9920fc00c3470d6c4ad6947f52662d1488df3e404563cc054d85f76d9a65c8f259d4c73576c150d38ecc85c70a0e252b595843bc5663bc241fe504fc8cb4e078a5337071f3df1b6070a3f012c8ccb52375c96760124aac0900ae7aaf3254de8412da8461c838838b91397c814dd0281e4a6f1f1dd4de3d707a39edb5f297f69d0bd1646d7b078df5ec9ebcecb178daf0a862b78a1ace6b11555f7bed6321b19ce58a4667aae4be894e5eba30d469db7f64e162f814d7d80ed00d73fdb3949fe42a6d0d69e70c18f7db67c097a23c735821d4c9b0e9ca0520678b47282a70d548888906b8f01f3cb8069f07fdff8cf21b24e5e42df82ef9cfef3f9c69832c786c87f52a36954a8533f41b3a7c62fafa661f8360c8aa7d07fa3c43383c30a20bb1b366c978afec8d6e791b34c568b37e4e0c566ff9390952e281b23f2063689f8ff06195bc3c3d3aa7f57023aebc47e621230e0003e7dcac69e261271550261eb07f7d756c47b79a5da7d703e85c630280b71e733bc8bedf8127cedcc5bd7c31d358fdb860fa3870df8c31e2e0df5d2511356029f792fb065b48bf7ee7828cae1234ebac626887fb6f82bdc02aac226f25b88a3616fd22683b0d5ffa1cb95d6085faff98716147f35786c952db88efdaff0bf1015595ababd050a5342ce400b03fb9c12c7bb23d1ad1fb6cd74360216c6d15375dbd3a3351007ab2400db25f834ba6752ce1479e212443f3d9ba989d15e489960f83b987fd80d3cc89750fd90ca7b3cfc27471f7e38734fb82d1638a8415716c6987ed6941494939cb3e2ec0e88617c26fb1e21d7c87bee813751ae6ef765a7fcc301f23cd3f3ad8a87e736ea47db70a1f631438c8fab066768cfee2b69ba3c5c477eca90ca55ff8f5a21a36c3c6813d284811ec0f082806147e5ef62414491848c25fe43fe9fb771fa42396bf624a85f7a4bc9de2320adaa6a41cede35f36d399f950687fda0ef80624d7a915ca3aa4f9b07c31efc0c1a2cf9f4aabb375a890b858c5fea67e7e01e9cbc3bcca0af0ae42f9137ecc010d49a2b0a0c014afb76e8b78edbc650e04e50ee78beefd9934e0733abd9c2df7d8ee43130b45ad4385a3def1a84fe04ee125c264f11cf421ff7b0e34309623e46bdd8e6708e10791791ff3d870799e3231c22d1044f6acd57a82e8b157c4d141ff1045fa8ed4a4ab0b3d2c7989ed0e6e2fa16778efd5653d8bcc409d674c9539d082d68ec3b2468310d66653df64e9999bda139d9385211bdbd0267d8e6545850d2df607f47a8726aa2f9491b12684ec24aebec843e49d2f7edc1adabad99c0aa1f6af141c3836b1eec524f08f30d1bcf5f8f75e225371e7153f8e3a4bbbbe9dbc6b5571f4759e24bd4084c41b987a177a1b756457065b8c38c0e48606e8ca9b91051e28b7541a788f1820a3437d888b2250b2bf773ea0789d21fe7175ff603c29604e04007dfffad7549200b98bde0809a34ebadd5b61a85df34d12b80eee0f1c3aa0de0e3feb8631001e9e6673461b0e0e8484f90ef50d0bf3f97d42da04d58edf88ad918fdd6bbe4b94fcf7d95f34dfe4a76fe073af76d2f1f3c358a7e7c2b70571094d4a56a352a3a53829ba5dcb4401f0489c4be5104c2f94ef686e857cd84afc1f8defd79672f8df4434f55af9d1813b6e9e510a8a0d46665794a6dff67e8aade3880cfe36e99a3387428e4dc5c8037cf483dc6bf9a56e298a104a51ba0cb0827f9116f868dfccc262d9ad10ce8e26aeeccdc1cf8560814630491caf460c0edc6c36961d6381ac906a5cea972fdd9eb9ac7144b38af39455131864e208f9309b89e7f69d84e2c3a47340ccdc56ef9e9f5c156919b6f56429c41d652e2f17f039a12d11ebfb5e0719bc906a1f4530e99250e8c2d9f490df4f91ccdb2ca1ed0f2a0ee547deebecb2bc5031dc8d78f315f5f579870fc44b9e4ccb3b8055468009434d700d952138f01320205f8c370757bcb338b27e6a6b4d07dbf459fa29013f67ecd0e75450cd52493d5799691c6503d2046a2ea24ec061eea37d54bcb82245c881f96d527c9a64fd7cac0ef6e87d10f34f1c39bbceb7c9be3c8a5d862c6a548012fc4ced81ee0b17651fd29d25d4f0491cc4e1649ea5f63089703cd86602a4b75894fe5285cc59e54edfd6403d0fa10ec727fb38fc57a28104c6365b05a5beae220b47e3a1c6518812bac76488786b2d2af641c5fc5297a5963daadb628f46e4982de2b5a769ad28cccb3df845ea573622ffd8cdbb656fbe439e6c94ad60bfd2c472b20e91b133e8a26c222e65de226556932c195fb61926add60ed33cc9a5336970d506960cbec88893b624bf20204d3bdf224cf6e1327a98155245dfd6d405336a01c17d654733d5ab3f1bb7e4342e8923cb909d5df21ce630e1603aadebb2082d9afdd70795d9301dc07f0f991455e36752657f25302fca4ff547257092f109b4a207ad32653d5c273f3b740b347b1cbf2c302e30612ecef8b8f2a94f1188379a5f514e921804f6d2378a7a5bbad8b3e12263f030961ce6a9785db1fe2ff960fef796bad70101416cb3d9202eb57365ee3a1bfa3f5024bf3d62b7feff5e82cbe0e0bfd0808f4d4dcfbab8237e541f8da59cf99e324bc3eaebf236132830c80324f64fbc655f0dbff86cad40323cd1c3439b1df014baef56807e0e24b242112715b2e27ff5a54ef79fe169f7e2f2e616ad138b2e06e4681080697f76668d3b71639d4bf11b21ffcecc509f8a6a195dc3cbe5b0a5e6ceb4580f4a4259c47b5f13da7239250edd68c35f982f5b5af2c463b8892f0c8d499896e7f8307b75b27b7d87a7875d16640ffde727d34e580815f351ebf16e99568729878e74ae83de92ea50b5fc31a18440b3be822b7bfeff0310fec5cb570f8875313c4604eb28d7026a0e97459aaef060086d98a6ee2fdf34ae8f533f0e98e950284cbd7d9b1604c7a6f2d5ff44bf46f41d6d3c6f71ba2220830abd642e9a74d2d831c1775e881cde01d62a96c06e9fddf14a3fd749a0dc9801365acb02f0a799aec61428225ec20a9e73997c839d8cdc363a69bf25bbf14fa68f3ade945a48375348315484797b1275ce3bcf1cf92ad993361234c45dbd2260f4fde12db4b33db7de8595d6285d87189eefcd08de10dd5bc850fa6f7b88cc85cd386e1c4d9e562ab5c630c6d86f01a1e2f2d091a0a7e07f8970f24abdbb8acb0fa71512901ceeb1ecde83b6ce527baa24388e1dc380b02cc0c93dc22fa03d655c262a4b09bd402f46399171fc2558a3aefef3792e9076c1b0342c0801616b1f641f9fd9ce9d56264027f2301438639b0e74313357be2739560f048e2ac5d4888976e9b7edf9c07e167ab4e7957c3b39492b9ee10653db38409987ae120c29e3e2ce52c3d2c7ea58fa68d11a03db298e46c353489b0ceb9fc5074046690cc7f34b553a42060fa12e19960aa09b8ce3da030b652b136930d0c0e93c26521643ce93e4c3af878c7c40cdfec6d309acdf49ffe196be469731ab8dcd702e62ed6fed29eab8f66130d5bf630b80b7249dec690dbb0c51f7434bd75c11aa903c58b09d11c44467753302709af0dceecc8c701aebb653fc327f66eb564888f81fd139320a27523420beb1c60cc541d995fe052ffdf14f11667027ffb5fe0c46ad4f30f8893e8a32636b6313ec98fd2f19f262f13ad839647e3f49ecaf65ce10c69e80752d18a7fdc751d4d3eacc56c73eb078b80e98c1f3c215db8c10ef0e2b81db7b6326a2b7fd356a9e0eb0a6b5fd868648e08976de8c43f37f614043f64d81acf907c19f6035964d8a1f77c337c3723d88d0c631853d3a86f05df7f55665c3330d84dd0828d88129e17d8aa40bb494b8d5a0f3c17c4d19c11c6566cb5d0a87337a657662796526661da396bbef7abb225f11eca6236cc3f18c47162ba5005d8451367372567a4c16df34613d03b891fae62d64021bdc6b15bab309c6c984b8be4e83e49a07439b2cfbc1108c63653b8578e986cd9108d26d845619993e0e2c24dc292ac20e53a9123b0d1bd180559300c8cc0d2355a3d17545cf5fe1e56c15c01d1fc44d067a89b6a59a1cfcf0ef2567241bd2d00c71bcb38138a4b45545bd36f0c997609fc85877c5d84d65dc3d4bac24e581ca9f613f56255f7b0639085308a5695b88e144886bc7e7c503c69d1f977863ce2557097d28be36650d25af4c4005d1bd3365f3ba9cf8103e65be4e86a624aca68624b4dce5b312f291de5df77511f6babc36631c76f19bd09faa179ca9e7da2f2f68d981792150f027bbe01733ae05a61597bc570db52bcd149966d690428517c6add8fa8e68841bce3945f2c07f3503d083723ee36ecd73a1c729e7cba84290701352147ebbe1b82bf5f34c4d6057615d73547890e7cf51f96dae7a9ac8bf0a40f8480488a2e946d9f2130d8f805b4b29299020029f79d9ac324275709f4046526be8fb379fbe9e948106eedba19a86d692f9b46ab10c8b90b6dcd3563d132a10c8c1912a26b402f374d3e35cb12d0a0dbd2f7fe2e08edcf0237ac530806b4399a50200c5f0706e09a1ea7b0885acf54caeeae3ca5cc23ded78a8316910add2401f24e4b3be625bad3cbd145214b1399678b8ea3117028023e0a53c6cdaca72b2a22ea4ead5a87b7fa8e1c6b7bec0d2bb1544df143172925768a806c56778fbdf4e93b833cf3307332cdc9eb2e194c91d93d9f9c97f5488d160e4edfb36fc6dca2be6e799553045f28cccdc139a8a11a995fff7715310c70d5b7e58bb46829838ddf7ac1b6bccfd392f220c4cfd0d90237fd68da4c36561cae2d0dde1e0618225dc7ccb2833eae7b937857277d11f2cf05d78bc29ee2c8e314cf313718b4eea092b437f0568d6180e7169e11cfad5217131c1c7cbc37da447c8dcf08a06082aca5251ab9f33a0ff62d28337bef4fc3c012690f0d6b05db065892fb24c224393673af83a30ac630bce4aef3df4546548aef67d09d2ff4d4f839b111e6c1184fa587d6411dda9ac3d731405f0acdaf6fa0e9f74f381e2b81e8527600fbe783cafaf9c79a4cfa647c3f7c983e2e06f155bd78819ddbfb30c4b5a194d655e8d4a41cf426a7aea59f8e3487cde2eebb2965ef8439199bcad3a681497c75769cfea464b19bb4c3b182e6721e5d375ce4165fda92fac5615bf610bd8870eb3002f7a356f28ff361d6fc4dbb7d2f430b195e0960d93eeafdc1e74a9f4cfea3748e07d70c90cffe5d6df5da9e5827bc7477ecfdb1a91b20d9bf187907646bdaab59e442bd7455cf2ca4cb79722a5abe344a2740612c2b285b74325b6a1ad8593ad19d266c8a36a236e04813c6cea3a135bf8fd3399c66b82530e149b470d91f0a93bbf8bf815e86c3950aed0c2bef52aff9ac16fc4174be595c767489c2dba7400ee1e81875aec76e94ab0c2221d4528824219ebac7c4ce15fe3a09d8f7ba8cf55edeb8b08bc99a9497b4f38797edc5a397cea3ba19e3baaf317e61d80ee3ce2e53bca09253ff6a3ad2d60e4c312d4cb1a5483664033b376c8b7f1f7f83bef921687f92e969126e1755444ed37e359be5ac79ea0d88b8f7ebc384490c9e47a06e3c83b68c5d00a17bf4894fca0edbcc177a818386e357e6de8748ed30755d83f789edf7155a0df5646d44ab3324009c2fe8284fcc24e32a4411c720294fe7cf872c598dc7b0bfb5e0fb0d8438bc6c5ba097b218ed1ab6b611d9b971e8b99b3eef3d9924e89e1878ca97d40caf4617569e08a230357ffa68c67154c62c201ba42e33b896884e88636c11d3851d93bcf280c90ab52b8cf4b3674fdadbf6bff0d49b331587ad43efe13d59f0ab20f101ffc36676c3fdefcb500b1ed02464be3303a6a8bd88ab588bb139469e53d0298bdc436c82cc86cfdee884c8686ab2d01283d8f7f529136ba145a61f78eaeea67ae1e419696f52682c04c385f6bd9015eea6447c59deea94d86ef8f60e20a3ce7e811f357ab6a6885ce565ef8cfbdb1a1cc5f2c9f0175f568e8c2b09c14a4c411002245860036df25e0e2fadd8576a2143b694fef465e0501c033adfb62cdad5b343fe36d1811675a969de9d3782436581d6cd8a89da2e9a59efd53ee8df57a62d581ce403e5a63f7e36806e1f2f0506675737653b6d4e96795811cc51c0778a277193dc4f67a06486ba6f8336ae0f7eff51cb6bc78a84ee440ce8e9ce04f6c7b72f8643296bfa408e753f96a64042889d78ebffbce226f31fdda9890a0cfdc0daf67b7e57df05876db1071c8fadd115078d1a1066451067f36033236142b292ea068c9d4d1842905e597f37c17b33fd9c4fa29b8214fdc243aad59dd210fbc22346c83124546088b3ca08d7b574f4cb0e608a272043bc54172e8e4c5d1f9d77d29f705159c74f0037b7ca6588431e9ac856eee8dd7f3a4171e8811127365d61eefa970d7b8de8945df83d496b81afaefa4ef18817cde13749357ebf4dce359c7a75382cd1a103e6ee189eaa17da8fe07e9c07505e4da023e4c46b40f3360b0a4900330333333333333333333332bf59ff17bdab9911e0f43a4289092e4ae8864253e9d77daf01769c35f44e2f9b663094b103110010ff7c49471373f051a68e073fcf62905e94852a8740834cec048dee49ea0de9185a41938ed499ddd83cedc792b03933f46dd959964a946063e88f038eb476bd2cec6c049fe3842b98e4585101a62e0739caa31440f3d1791461838cda1759483b5456e0b1850f5d6d2b4f412add71c4a73e687b92fb016247fe5ff69eaa0452f70561531f4a45a2649c5c82a0aa0d105269ebd07153f7a73c88891b5870663cc2002a51d40830bfc4bdd4fe69c24c6fa6c81f36842ba14dff7526a686881cf156b42e3e5786d521a59e072bc8ee9513f648e2d88055ea472a2d6875d81df9e8eea2e243d5acb0a5c4edbe558df6bb5bd2a30923a3f3c4d21d7688a061538a9287def1ee84bf0694c81cb1f670e2f76f78a78a534a4c0efb746c7962fc7e83e8d28309592e4871cd875c78e0614f8207914415b72482a590d98a0860c683c81f58cbe501ec51c529a6819683881cbe951a40effce6c730c349ac045def2fea4717214e21a051a4c60731839f658a5de6fb6b151e3055ba3ce682c81cb1b19b572a43a91221a4a302d259b98856cb15424557ad6a8ebb757132149602553b465e59fac7a0c1894f182198c11831a3028a306b1315ce0821bc30516a08104b6cd55e3e4282639f328a071043e878c1eb48557be6a0da06104cebdb6e26793ae102f348ac0af07b59f5a21b1f2f5061a446053be56c63b4b9f39dad8d8d8d81a55956ba03104a62be710d1ad3253ec6908e16c91ac60a2ae5621555489663174e091afe5894610d894b13377b6edc7f588410308dc88c77a6fc9b2a5af88918512500d98a0c618347e50847229cb90d4ea2a1629426dcc9c9cc643d9051a3e60dcd423875a485fe4f8a217ec58da58b4714b1fffbc604353aeeb980355b5f18b5df0d144ff3bb9ab0bf62ecd7ab7f7d3889a0bba4bb3526464b308352fc9711c6e1b792d7a830b7e343f4d5c229855cac6c6d9d080096a8cf1c52df8683fc69ecaf669390e5bf095d382eb47deb298530bae72c8a1c4e491379f87165ce53789c894d9fd9d59b0298ee669cde9515e47165c4eb00fa9fbc43ef463c17405f5bd9ea899290f0bd63ff0eb2868ea8dd0bf8231df90577a7557f0696f297d103947bde956b0adfdb1b33efcf778b3822b4f5fef9efc432b7b159c788c11f2751c424c695530622b5175e94d05973448a5f638e6c86317156cc87d6b2175e468b73d05579971d3a2e6a0ef5153706b97ff7a43b4146c85944315cd1852ea4852f09e96b4033d7d8f2b390aa6c646ea2d3ff61c92a26023eadd6b8530147c9d76eea79cf7af5340c1597adae7bc1ba2c47c8253f11062a19248dc3dc1b7f54de95a8eb3aaa413dca9d55aafe7cd390727d8f4b431fd73de867f9b602aaf2559ce619ae037858869eff64c309ad9525cf16b350f26d8609adff7c9e3f0f512fc24dff030dbfd678878f08525b80ef3eb55dae4b1924725b8906ce5221e9460b2c4d72fc91e4bb56312fc07e192344eec9cae43125c8a39e50ec93c3cc74f24f8dcf8db1943a68df7810417c733a6ae18c5ce721ec187df3984e0631d72ee3882d5581f7d7ca37e39f61bc1a57c413cc42469a9c3308215ab8f8ab71ec729c72c82f7e8ca6ab921e3e68d22f80badf2c92caa1f6b12c147e8d3cc49b2fa8d0611fc678994b223837b901f8297eec951f63849481f6d08d6cc2b5855fa8ddf5d083eee47fb1d76d01cec26049b3c9d5574e4f697d283607264dd518be6403ad782e0f26e45c7a6413dc63a10dcefab448e1dbe6bba8060ccde839c39f6f8d2dc3fb06a5131ba59e55171fdc0bd25f31c6e78a0fe917de063fb97ad84d0f6b8e403a39176bc562c761c967b6077facef323e299877a605b733f47217daee82979606b4259580c1eb8f3fb8e0c0fe93a2f776052e7287e93d71d8e67073e69f66a7548759f3af0e1be8d644e3cf30f1d780f41f26f799787ff1c58ed8e3f453c7b743539b066eabb77da41928ee2c0558e4777520e3c7a0f6d6c6c6c10257c010726871eb6c4cad14296fec51b981c497bc85cba1ddd74c325592d22859248123dcd3adfbba7048b4955a236f081f9e60fdea6a9548740181108e3016170000361109cc1176ce036ffe247d59df4c1176be0a28b75ac106953cafc0b35f01b993c27f3abcc184f03eb1634b4647af471284143165582e50ef5aa2439dc57527f48d0aac8589fc10a1d8487d6b3187321f8c20c6ceecc163785bef04ad91865c460bf2803bf1aa34a47d559c3eb2564e0a31cdf3c5987db7b8e311c69923c92ab467473c95faf7eae6f8d2fc4c08654b01c79148f4cc1303099abff6139ca786601031f4142a7f2dcacaf912ff093af11275ada8d5a79813f3bcb9abaad8207d9d8a8aa5179f8a20b7c34e5d145a77b4c2117811a25872fb8c08717bdff22855437211b1b1b1b0a003b7cb105d63ae8d882848888a7f1063dc6185dce1830302ef8420b5b7fbed46521659031010f846177822fb2c0679d349bf4aea8f46381dffd0fb615b76d42ca15ece989d7a1af4545c50a9646a860d96d6d59252942ccba57297ffad0ba2faac087ff194adac6c5dc2fa8c0460fd39a283921e6fcc6c6d6282a626cf8620a6c47d2ca5ba1e3e9582a030622d8d83865c080061b1b991a30418d187c210536492ecffef690982f5f4481ebaecd1a2939884aa12fa040ee88edaa16c2d272a490a22a9447cf1eed27f58b27f01d44cd31068d14fd2131b2363636366000820d417ce1042e74921c6b1adb4f8f37810fbdbbd7ef30455099c0a48f1e3df958ae067b09ec8418bab692a33ce10b25b05e92111e068d3412b3b1b1b1a135aa905198f04512b80ef2e5f29c9af73f1b1b6590a182166c6c10277c81047e37e9c5686522f5d21747e023b4494f8a8e9e59fac2084c8ad1736feee8ad939c14bce0b4a0052d86295504d66264cf1a2af765778891456a025f10818fbdcf93c49c254e4e20a0a24ac01743e02f273acc93b89573b286aad50716510326a8a15f0881cf1c6686b82eae173431b2ee8b20f0e9ecaac377e96c33e00b20b0af152d2787a718effbe2078c4721d6e4b969bc102246aa20065de33460821a1b5ff860fdd82a8d485eaa600b8ed28b3df0d0551d913d2980410bae67f082dc662975c65fafc5c84a010c307066ec226d8d4ce9b2a826261d2229de84aeff1c7ae5a4200530c0400c60a0818d8d14c0a00537461931d04591c4924a881e11521a1eaa3efe48437d18528e185931a8a1980b2e846f1e4bb1ef2d3b189481300041162e18e9c9517f21ee792131b2de05301863026398710b763db859a4750d315a1f90c0c6c6c6466d61862df8d3103b267f5dfd6bb4a0b55ae0fd811bb4e0011b1be7052a388eded8d8d8c0622c00001166d482cb3fffca9039dde45206649009d80366d06216aa4529e948a219d1cc4d8386897e9cb7c39c912cd88cb593fa1e7d5aed58d486c2a2365ec185108ff24b7ecdf974056f154dca3ff77fd8be1859686394118319ada80d63051732b2271bc9275a1eabe045dbea7e4248e11d5570c1e38bb935f4c4cf9e54709f22e7c61c58486b2d2ad8287ebd1fe4088d6d9e82c9714abe26921baa29f8db4ebbf992eb81574ac107d963db8d1f5eeeed48c1b54b784ddd48b858a360db2dbe75e7c0fd4f2246168a825db5c9eb67b707668482c931dbcfce2e55f68818593028a306195a3e03146cc7dcc13394e4a91c072a78c17e823dfd8e08f78e2f45e6093e4c29e728d13b0fab61596836a0aa514585c558403ac1f8af5db579791ce4d0143083134ccc71b4971b296aa7498cac1af418302883eaecf9310e193b63135cbd6d7e092ac9a6dcd41a8584199ae0ddf2760a39b674dce021a3c5e040d6a81bccc804132dfc3fa4d7a36307134c0aabb42d8f3f52a497e0f3dda8d98666cafc2dc15da8764a0f3bc4c9b195d0245959081524755594bca0251a223b4b09b6f3c64aa1991afbc3a24d983109b6a5c30a0b69121e93046f3a1d7858da7134df921a30410d31664482ade415630831a3a4cca1356640826949e61ed53c9a452e0604f611dc5ad6a5b3cdb16a536264a999230a5142a5a45995452ccab3527c3ad4b427da8a9135060cc618831bc1844694bc5d9617b2b1b1b1810685198c60b27696de98bff2c576117c904c577dcaa397788661862238bb9c91952d76e07de32682af948e65f9b7624e16447059296e04edf0bf626ac62158ed48a3354ec68a9c1982d7f3a4df1e92445bab105cda49e4bf0e9eb12642f0914493488effd7e1c70e82f7a8738a741f955488a82038f11191cecfc8c1b31b1b1b5435ca90a1021710c435cc0804e3ea5adf195f2c26dbf60a3300c14e477feb633164774da730e30f6c7a4909bb96a8f739c8e8164460a930c30f7c85d08eb6eeb0a47f326ed01cd8d8a851da0726d685b00c397b602af1814b1f9e859ff9e4a883670c12060828607b503524b5235aa40896b2527f69e407a9735aba8891950215f855193388c10b2c605535c60c3db05db9b3b5b667b3dcf3c0e64afa38c61e4ddd0a1ed8de9cb19255456fed0e5c87377aa1d6beae2163f40c28b0b1e183197668daa3901193e7ce61d180096abc60461d6ee94a2982848a65470cabf4398e7c9122e6a6ccb931ca8881994107562a8b755d6574cee40c0c0533e6c07b9c99ded2e1468f837260829667b4751c7ed05171603d8f4551bf1c3d7e6bc02fe1c0079a6298d6e68d493b31b26a20061e00810d608002883581196f60526aaaca29ea07f1324e0a482919e9067268a56c1e39a272a66468c80e3df66e9790ee196d603fd6b69c3da70faa270bd4a82b0d98a0060f66b0818fb443c44b8f611ee74030630d9c8f7e94e25658cc08ff052ab8c00866a8818d132a1e985d85caeec606160d98a0460866a4818ffe77c94ae37176518c2c1ca38c18cc40839aed65dd16b9324a5d4cebd26688186ac522821967e0a3a8d38de699627e6e065e4b353ffaffd0a153065662c893236e774a122103d7b1461f0f2db6448fcd18031b623186da5821adba6264c1e078c18601020a6819c20c31701fb4456e8d5e795aca1c324a04c2000106c2d0a2aa615450460c54d082161c12cc0803eb714e93bc4c3ac5f6c1c09b468aa0659a391cf70b7c14ead1670eea83c89d17f8dccfa97218daed535582195de02a8739e344b888c63c17f8bd1c55713a78a764cdd8825129457496584694abb855875977ddadc5bcc00c2df061a6d89a2c48fe60e92c3029cd4d2dfee57c1e2946820003619091f52d50c10cbc48600616f8da2bcf49b24f060f22e40afcc6945692bdd42e3d428815b88e1e3978102a495448aac05b8bde8bb7f65469845081891551528eb3650f3b3305f652b2b19f3839f7076da8064c50830633a4c0e4c815d348ecdd8fdc0dc628e305fc01a2861951e06e7dcf3f65debff60956d528c2861950e0e32cf5ee89faef172df08118cce08f04fec460067f3ecf0c339ec0874193e594f2e592546e6c94613a062e2025cc7002f7a9d32177497bab765f98d104b6554b72f7e487955902c20c26f04144cb93464eef77395ac28c25f0f1c75b675f71f34e574a041a81194a6033c7b0bc8cef69838f1a30418d9f91045662aaaaeef6ff52f3612086ba610612382ff50d953cb9a36a2a88c103acd030e308bce5b768e9ddd7e9716c94a2418d2a4583330213d1af32ae75aeed78810ac4a87170a00232b6861466148109fdddf9517e9024a23a600611b8e013f6817dea9d6ec8036144200cea40181cc0401808002ecc18021f87a429c71edc4ed316831b80606ba81666088171d50f5a72e4d861f245b0b151a86a54926146109894304b1e6b3bf3ba3002fa67d1ce66d28291c8398c413b67abe42c780bf95672fe4e264959b0395e9ae01de6a0ae8c059b3983e86553dd2861c156c695e88e57b01e265d0fb4cef67705fb1962be0e66e3716c05db793e69db753b4456b0659a27e5f4c934c72ad8b2d897b552f37b54c1a79872d8e41cf3f754f096f1bcd2acd5f3820a3ea6ff0871cbb17ee5148c44fbab9ca9d5a34dc1856e0d0f5c2c7a9a94828f396306d58eba13420a3e6ae52e0fdd519951f081075ec1c4bf3e79a26027dbe3b7a8a93779a16042fee9db8a288b83828f1ed9233c573bff0413db42dc0bbad3ae2718939083c5d4b459ed0497d5f1c7891a27b84d11730e2c99eb669b6033fe76e05d6982df0f235ba8786c51592638cffb74d921c3047739561717f5c83eb24bb829a2f54ece5196c8bd2d4dccc1a312fc75f8ab390e456c725082cfaabf6ef963cbce99041f7d54fb71e6448a47127c5c51a67bdf61073991e07ca543f238079bea4082c9dde1d15d8e1fe4ff083e2587e9c47adca277049772ec318847b1b3c41bc17ebcb9e3f7daf49d3382d5f620215be838ec7b11ac5d4adf574821a4ad08d673cc514ce9463aa513c19bf8fae41cf273d588603d33f405b1548fef2118cb2bb34c2166f51a820d9596bca31ce9782178ffb4395fe767af84e03c6d4eb0ef8b3675107ca499299d831ca4101504a7b9b93b4787664a03c1c6cc51ac4754f75240b07e973e5f8ade1bca3f702b15733be8c8f0f003ffa179e820c4e8eef481cd711c22636e47c9463ef019ebe30a379536710fdc6a250f82e4c03d827ae02bb6a48f37329787796082e730d886984334050f5c0879f247cdf13a57eec0471ef4a4096e953f881d984e39b4cb0a9efc2775e0ba6248883cb394217460537b253a732a343207fe7db36bda49fa614e0efc655734ffac51ba8b03a7ed1a69e3b9e4e9e0c075ee86b0cd923eff062eee74103c8867c13537b0131d62a6715292581b180f63cacd2ce6a93336b0e5318e7ea09a83cad6c0c791c31c761d21f96ae0ff5f7298d2b98374a5818fc8cb9e3352a52c347057111deb66e59fd419989ca392aabd374eca0c6ccca9cccd99e3dc2903bf1e3d3f0711457232b0a9bf6bc74fbd5aaa31f01f327fd746ca714a2506ee723fe4204b523aa9c2c0588eeba23fd97ba402031b1eaf7e7cfa29aec717b8b4f9b3e97845881c5e607376ad69741c963abac047be7992f56bea3b5ce0c3d51072c8514ffabf057e7208d21f99bd685e0b6c4bfcd30e6274cc7e16d8c80d313bf6f813792c701e07aa1e7594e2a15760472c04ab94d1dbb40217b2a53275e6d02fa60a6ca69ceb4d3db6dd0c15782f1391909f6e333305f6fe6e42b97ff0ca4881bffed6cc21b3f2e351e0a4e3fb8fd284fe280e05f6edb35f738cd2883f814f3974c494f726759cc0871635739a5f7ddd0476d36be6a61859b34ce0e368e355c8f1275397c098ef8d9f8ffb445a09eca51043475a96c3af93c0c4ade49ad34907b9460297355bca51d588497d04b623afedf8bbe35cae11583d0dd7eb8d1253b6087cbcd9e3eda7e5ad96084c7f925aab0d79a21d02ffbfaf371a3fec0f21389691e32006818fe3c5b79437baf740e0248877ec16ba9ff2033e48770a661a526b01f0019bfdeff2b669fe487bc1e7e8e3ee0da2d9392fb890a04957fac31cbd0bfeb38434d6139ad705d77194d9cac3ea2b73c168bee051e575e052e282f7f20fc54ab3aae316fc8450399d75a81fb6e035a6348f9b6c42bc167ca7b09ea8d5d96d5ab039d0cd792224573b0b36996b78c594faa92cb89a1ceb85a44697c482edd0dfec3205891ac282cbb29d6c9a3e1ee7157cf8e87598fc73e4bb828bfbb924674ecf602b38db28d50cd92e66ace02bcd744b4724466515ec5e66eeade8e86354c1c7e579a2a2c95234157cdfe65023dc7c4a820ad6edbe3f48f7959f537053494b4f638672cf145cae1ce4c9bc68ed948289b512b572f4e96f52f0b1a34d9e92e3d8e62838ff2c9d7da73aa488828b109d39a46fe464a160c4c3df1ce9e7180705ebfa57a59f1db5f30926d56dcc75ad5d1a4f30b62b91bd11a9f14eb09139cc19b3c7ab2327d809669e39799c63496d82afc98d209afd7f4d705a9a3f77d4cd6c2698cae5edf12be5fa98e04c53a460d771b24d04c625d8e9f68e23f2e62d89c0b004db22f97fb5a963864e09605482c931d3525c2fcd0d3e25d89ad4f0d4f5d21ac749f039f98ae7b0e320d54b24c145951e0d51ed2711a92680110976f2b647e93fa7b6ac4382ef38478f4de6ab05f7118cae85966075fb1eef8ee003c9528f3f1c1bc1be6bbfe5cbd48bfe61041fc71d27f148937b85e82218eb8e24f7520875ff15c1751e3dabcc7b89d871063012c1a57a0f327aea44b38e47808108563b4aa9af94e491791c82cf9fb3c6defc8b18f1620876237e592c2bd3ff142d041bfef1e8b9476f4ad706d228000621d8d7982475a7778daf11232b07c1796976a474a5cf981623eb8c1103ab304040813068008620d8bee9cf1af1f6ef6831b26a9c61d98037369e004620d8d8716a58fb9547538701020a6c6c90c10218c0400c238001083e6bb6fa4a5a39544cf9031f7654c91fefa6f08ff981f117eb683d58c88debf581efe852c71da5d3a43b1f580d4d1afa515bd490438cac1a662f08c1c6c6ef81bb9cce2baf8f6eb01c62a4046400861ed86dbde41ed47ab8394e4300230fdc27bb1ca694cdbcdc27238d0b60e081f7bff48f5b2468f9bbb141d400c61df8a8397d0cdee6f799aa25c0b003962f5bcc1db68798f43d805107c663b26c298344741c4260d0819bac48fa795f3921a400630edc759c43bfc9b1e418626264e10ec090031f07df0bb61e73960806301883e4008c38f0ad922669598d5fe96264dd608c32e0c0795beab8c35be37e6c2902186f683f8a943753d607ba81d18997a3dd88a74162dac047e9618c9c94839c29c806c6eddac389115352770d4c921062ad44ea1d330559651c0aa8064c5003004100430ddcbfdd65bd1ccc93bf06e0021869e053dc8e2d55c7b1c76d6c78fbf1f602f0020c34f0b69a6ea93fc791f32d46d6d612c038036fb1c7b377d8d1dea78891655700c30c7c941b3ad0d4ba1b2515060828108130b0580536364c042a88c103c6704106c670810b2e0b609481b3f678ea1abd22a7bc1859859c08541083071045804106d6f244d3cd1cc7ed612e469616119441060c2a40060cc4a8a1821834195100630c8cf6df67f28888361531b24a6d6c6c6c1cf3820cdca00c1594b1b1b1b1414604c20883037f64e00121d8d88840187633f83e15d8d8d8d8d8d84011b4c09cdfd8880119698023802186bb3eb69caafa3e2646d6182aa851952000230cacc761da28f952948ea5e8000c30f0492c567d9ef43dcfbec0f5fd4f88214acee4e311c0f002ef7194e24787b1a30b561820a04018e6011108e305c7055e667083314040c30d60748149f6d1c42c1d87fc8e22461619c40a6070818d59967a1f8ea4d83b185be062908af46c5ba2b9d40217aa5ab7f34cb78320185960bd63a7c6aefd07606081abfaf032658977e039c0b8021b72e284e6bffd5002c30a7cbef6d190a35899994255e0274b5b65a8800c15d060c3000105ca5001192a10418d1a1b1bbfb121811a680830a8c05bbce8d1f143faa04b31920c2080310526ab47fccc5b51a23962649151a3063d069905c09002b76e9a3cf5a2e6b4d602c08802fb1e7a44eefe5072889f0bb4e0a0c06ed408bd29cfed2e0bd4a0c0c6c66ac004356e00c613f88f52113b5e11fffba4e09cc0c51c66bc5af1e8e3d81423abc7383380c10d6a004613f84866b9a36e95cca589915523062e3057317041043870690083097ca7c9c9aef7d437826264556df4008c25f0ef29645a757674a1a2023094c05477f4ede7a2dd625a0b5a05658cd11cd8d888810b108c24b07add3e1ede3eea123090c0862c390aabffe83498476063fa38b0607e9f2949140c23b0395393957694058c2270199631db9587c5046010819fa4a5ad95437e4ab1010c20b0b1f1c7063070cb2134414d3b553c9d9ec4c8222b004308f994d7f6c7ba5152bfb1519d002308e777ef74e754b66830f88d8d8d8d0d5a9bc1093080607938a6f14b4cf28d8d8d30404081304a8d51460c008009307ef026af5cfa8167768c82e103f2e6e497b336fc72f4c2ca69592f3d2ccff0c2cbedd67ed9533be22e7a89b993597a6841cc1a6a478dffa652418f0182bb030d5d94c673564f4d8cac303e6710860b542006191b3408c373066110c9c5da99112b248d16d1f5380795a1aa3266e0821a2d68411b2d63061978c1044a0768e082c98efce259166babc92dd8d2bfed905aa2d95d1b1be7373668d8820992f15bf76ed32e550ba652c4547d919f26850c18c440035635ea3460821a1fa0410b3662dba50e633d0bdee3681e27fb8b1272109205677b77b59552a8e82a16bcdad7848cd7f73978e080062cf8702473b68b9d5473381956afe02e9877b42a5a1fe7942bd8360b5eb1323a4be62d6841531268b4828f10a3e5e620da81c524c03458c1b4b5dbbb6dc7973f5e8c0c03041408e348e056c1df6f4e264143e5b07f1aaae03afcd0f16fa2471d98a9e0a463f33bcbbb13df50c1c64bfbe97f221ef277be461a1963cc2002649c326e00011aa760428e1bd9b73f95cb9fc10b6898c29c831c5688ceb1792019344a514c492925cb22493417eb4aafe016f3c71f88a4301aa3609365670cebbc71cb210aeeb39b2791989a13fc50f0ee4188216eb953da028a2c6874ba254929da91cd3352c75e71fdd255f4092ee4284f7f2f7298e3d83b4fb07f315b4c965a2547e95d186874828bae1ed629794e1e62c609a6fa473fe58d128bfe26b814f69eb1c32b73746a82ff6cda9b163fbacd5f2678dfca488fcaf2826698e024e62093e55beaf04e59028d4b709df343f3e7cf4a316b092e57881ff65fc84a41a75109265d82e4f59e976b9894e034279564eaca5339dc88c624f8203564f1979ced3a87185948c629a33150041a9260728584b859736e841d09c6b3a654e7597a27b83420c1e4203784c5d81f4fca79049bed530e53688cd09c3b824b4bef9b358f9a77aa115cfa8f6db7f3438c2c31c898410cb68c19c4a08c196c0019c1e4b8c314db55b3aae33416c1e6e0512be6fe8598dbc6c651d5a8ab83030d4570a9421cc91e77f6d0311b1bfa051a896043c71f871e63270fd2bfb16134d8d8301a5835810622b84dfaff61742c8bec21b8e0717c52f76511238721b89059f3935804fb3c6b542158d1d89fe38cfd71a987105c7dd25cbb79663f9a41f09ba7d3c7f96204c1796666091ec4dc5af336107cd0fcd0426693c388800736368e4003106f8b6b7e6021fd47e61ff83f8967b13a7b5caafb813da96421577efad8dd075ed532ef5d508fc3900f7c5c4f1e7b4988529dee018d98a2d1124285b985d4e8bcbe6eaf29c40e0d3d70db1dcc42aefc1b6de781891c7fd3144d2b22e18153931ca61b8dbe94531b1b687760328a44ced8a1fd68c60e9ce5889891a3cae469ac039ff4562abb6efa1a37f01a3450c19782000d3a30d19fbeeac792c75605631c326a8c018316dca0cba8516c0eac460aa5f6d9eb71d434e4c0e616adb857371e7b4e1cf8c852fd8667ae9bd4c2a12049ca5342a8ac6cc92fc78ed2b6d4f6063e62bfbfe6d1cb36961bf8c914d5c8d4c80f510f68b4815151d5fa502b8638f909d06003ef6e9aa3f44d1f3f47171168ac81af9c52745e8ddd715f1b6ae0e39c31887b9985f2fcc6c6c6c6d628b5028d34f01373ca09d805f001bfc1726465273b4d6902f482fbf83e97e5304d31a509c00b6eb37969a965176ceee4e6894aeb82eb209da40c1e7dd090ce056b952c76da74146bd2b8e0a3e5b2983937ae47fa167ca07f1bad5e532fd2b6e0c3bc8865d782959026679b2ca9c5a3053b594ffc22d47467164c88145137595eff65c17fa59e889f9ee31b0bbec3d871d66aab060b4ecfcf363d144f9157b09d238fd4a1246f64ae6042b6a05174b388df0a362cf3473bd13e0a59c1c77b6b9deed73454abe0bc2ba262a889f4a10abe3f96587e143c2e53c1ebe438674963661a352ab88b79792af24698a7e0c65282757c5193789882f598f2c77a31d9454bc1e94964fde0e178c821051bd29b4a62f2e9f85170bf2956caf2ec18140593a4dc52acce1f5342c1e4e48e24e441c174d29822f9092ec472b3541a4ff02791398c9c77828b397e20f903ab09694eb01b82bd9a787d8eeb4db019b277a45c6b82899b3d07ed172c7b6c2698a831063b91641fbb98e0b5ef5cf237f2be7b09b63ec5b57a8b7bc9b5049fa129f32a8be76c2bc14ebcce5a1ad3071aa5041b9da33fe9daa65627c1f4e6641524ac36a49260fccdadd7ede3d06624783dcbd9a2c6943a4a428237ddcef125f908eed4b4b2794e993fd0115c0ee191a257aaa3b111ec86a5c90ef7a8153282cb13a1bfa7963e5216c1affd76ac6aa1bd238a60b753aa84c825820db7cba903adf8924304ab318594af7607217708d673760f358b4ececd104c852cdd1a53e48a6c0bc1e8787c298db584606a2ac6d6edfc51a676107c0eb2554eb163c765ad2078ffe8c3cfd91ec5606d20d81077c5a3d41575aa0504f7d99356488e249bb47f60a344bb2c2ad9bf39fcc0844bb6e4fdd10736c7b9b9fe41a7f5e0032bbe7f2e493a1ecd1ed897d8e351f3efaf0736fda34fac8914953c706beb572d794f277860a37be8316367c8b17307be2fa7c81d1df5453b70b12623db7398b97d1d989c77b2a392fa1c74602db3a6667747fa9803231124e56b530d8d910353371d954f8f03a7395868640e07fe3c3d4f7589a61cfd06be423d768896fcbe7603d7ba5629f9dd0646625b45b3698d58b381cf96a333e9eb1ca25e03635652be297ee40f3530f5a59fb9f91d7aa4810fdd359dc31c3a7a2c1ab89f98d4c3de3330de29c903a96d0f5d33f0713fa7ecae1a1da70c9cef7b8829ad64605aaa62c7f531b4a963e0d53cc689292a06a6a7e207cded774fc3c079da983754bc354d3070a779a1839c32e62dbfc0a59c52b17b244f2abdc04dd65011a2e5741f5de02a56dea40fe4027b9aed6fb7f7e31cdc02ffa15cb3e6905a7cd402bb1dc1420ec42cb0e9437d07be5d35412cf09ab9a6a390b3bf04afc0f874bc3b92f51b422bb09e3cf78fa73469c22ab0a71d332c6aa6140b153897c8cf981a517d3205364296c6ddf58e1a22053e7a3bda787fd371a25160a2e3e8dbefdbc142140a9c6d4aa932e4a8ca73fa04364dee0be239818ff224ebbce671bc6b021b424d2c84799433c604b63d881fa7dd2c8fb525b031a5d879b22ec7a02981c995a6e395e86ef1d224f06799f36712adea4a91c0f4c608a9b3c3b718d22330b9827b548d314735a911180fb2c7a123d6b79216810f3af2b1ee682a7d1c44e063f0ed389fe4fcfa310426c779edfb2c781c3a0410023bb126f6afc4e8ce1320086c8c79d99176a0a53d0180c06ee826d188f8d96108f0037eed3a5e079ef17243001fb0b12ae80729a7d534bde07e3d2fbba6aaeb79c15ec550e3b93f7aeebb606def4a7c4c3cb7ae0bb6222ff4b54d75a0e782ab4f9d199d263de8b860533a4e3152505fcf6fc184985cca73181562db82d5541fa46bfed03eb6165cbd8b5eec585a706513aabaf7d33f66c16565c9e551aee49c2c58ffd0927b1cf5b162c1e43cd1bcf23d8d14165c9e1423a494e5005ec1591c89953aef6e923900577057d767619ab2a33207d08af5bf831c578eace034a57acbbe1e438babe0a2550c12cfa20aa6726dea64d7d24b4905db164357bc90b95e4105a3e68188d96775ac9c82b5cbcda6f98147513105175a123274ac1f764829b89e4c898ca9271d210597af3f34d7894e1319059317f3d652fe30f31305d367d9a1e69cacc60b053be167f9e378e3a1060abe3ff26825477610b24ff0618eb586ee38b4a73cc15404b518ecea04d391786d97eaad599c603a5f688ee38b1423b509f67b24660e5de25aa509b6a3145531fa48852a33c1eb56fce8703b9b871213bc7ff2903da939e39497e06212df0b9aa3b821a525f0d01e6525d8c9499be92379f6a00437eddefe9e8358fb24b83b6bad9ffa8d5a125c7f1027ea7dd7a891e0a398dd49d30312fcd69e87ba8aec96e3116c4e5759fffda2b4c311bc87312bcae33482899d63bdbc0b12721c46b0923d8ea3c7e11afa5904db71f4122cf557ba1c45f0217960412b4f72ea2482a9b89ba3c9ebb4d520824ffd91a6f41de44bcc21f86c89636d9f9b1a37045755d69e72fce06b1782ab142923354a9c5c1382c98bd6f1b4467ad683603b2a6257748af96a41b09a9f8334963de8d581602c25ff0ca176f6b180e063f7a41473f01c7ef60f4c8867292b7358e4ac1f98dcee761d0d66d2f681a9ff14152a7a455a3eb01eda58aae57045d53db0651eb4d4a317ed540f4c2aade974691e789b0e2c639ee01e291ef8949bcec53fee5af20e4cd48769f735b7426907d634fad57992b41c75e0fef533073979b63c1d98fc9b24738e93973e072ee8e5fdcd98f71eca818ff78278c5300e7c3c9efefe7110fb2e70e03bcee0f1063648f4286367c8b30aba817789296df288314305dbc0c796d399655709f5900d9c66ebf03c4ce33979b806563b27dd8e31598ec3500dac96986a9ebc9453c334b06569a7171a1a986ce6414f861c796667e037640fa22ba1679919f8307718ecdf635ec9cac0c71d897ee5b2d77c9181b74a9fd9e3f4e66e8d81cf712421ba5ea5db120393b394fd7594ca422a0cac68e61ed11c7fcc0a0cbc47eb61499876e87f81fb8fb207e1f9f2e65ee03b2b3bb4cc3a7c09bbc0a5b869474dc2f225e40217d3c4eed8c3ec4a116e818f3f1933b776bc8a500b7cc5da1e0fa121548459e0c3ceae8cebd729736081091551752b163aca7105de538e43c892de9d0e2b30f1e3eeb856f2eb4f15388f3fca11f69226e65081cd996f1f9b87f6963305466b4ab3fe635ded4881ddb65825a2c1eff351e03fbb876ce392cbf250e0234279278f9eb28779021f6f244dba9e9caf7102d35752ede17efe8e3781898ca93c0e19253b9a099c56cef7d5facba897c0a4c80ec1fecc3247096cab871c43ed56ba37097cab851c6e1a9aea45023f6eeea1835412913d02176a9d1e7d397bb746e043d7182d879a3c445b042e69c8714647bd6a2a11f89c6ff71739d4e773088c448999d43e4889c9010881fd50543b7b76c9901c4010d8535ffd9083b6c5710040e02db679a448d8a471003fe063520ba976d3ecc301f8800bba1751246ffa0fd20bde32779c58d1b253c20b463a0593a0162a7976c1a758519355d0ea485df05194a6cddf5e1abc5cb09e273d4c19d563f170c18e073ad691b9b7bb5bb051d5a11172f453670b36b7c53fbcaed482cb2a92b3786aca88155af0bf933992977ec75165168ce79e74f8595be25464c15ac8cbdf51b68c199558b0ad12257c73c082330f11c53d737d1ce7157cbc7ecdd08fcbf2e30aee436e0fc2727aa54f2b988e1fe75c751b2d1e56f0e1640dc9ccc3298f5f051f7adbab0797a839af0aee73dc9cfe0911fb4f051f56fe74d495266b1e156ca49945eab632d79c820f75696d732c62a531057f5695620c1afd717829d874f5d8a34d09a9765290e3382afd888e824b55b7ccd6fc3814059bf45527424c964342c1f4a40fa286dcdbcf41c1f49a7f8f8fb54efe092ef9da567bf9a66c7b824f3ee11ef27eb4b53bc1e6e8f414dbc562bf9c603f47cc5a8b314e7037c1e55ee6a6a996bcd1046f5122e7ee9a185fcd049fed5f2f4467ca9a6282aface8dcda91871d790976377a3db28f3b86a425b8fd8b39db637bff6025d88ef6bfae2edb5d9012dcbdd9c6ecaddc3993606232f7cfd197d25f24c1b4e4c8d771bc1aa712093e886892e3feef5012487092efc3d7be28e13f82f3bebc932bf22fe30846f3dee338aecdee36824b3988d0bb1e23f8dfe875d16a2d67b708367b495e799822380ff9ddee1e65ce27824d93fa5c6a29e61044b09bbbd351ea1869d52158fb8f4edb10314469d571488a112904e369952a85383d2e21d89c961e4224a64e8e41b0a213e3994df7871d82e0e3fb9d07d1a1c38e409c9b22f226092098f0f833f55d72f3ce1fd81c5d8650cdfb816fcda1a78e7e1f98ca1b62eeb154937c3e30f6b716b273fca063f6c0a798b22dc7589fc38d1ef88d57d277413b6b260f6ceee6b8e3b8e381bf8d123dc73be948bf033f29c48b139253a7dc0e9cc490561e86ed7e741dd889f71fe57a50f6371df8ca6114d31ca4adda73603aa5f68ea8d7115f39f025992e6667a470370e5cd254d135ffa411170ebcc6742f313c0cb1ec1bb8ba5c29fd2ea163d50d4cc6f81ee465de10a26d6092076952a6c829c6940d9cde7a983fa3a3cd916be023cf92a37d875a39a906de52ec28b26b9a1c9e69e026e448fb4e851ccf43032b95b2c3a0d217a37967e02c539aae081d87963c33b066e39aa31873442caf0c9cea86564fba6f493c32f041e652c9b159c814bc31701712cf73ae5fcd514e0cdc89ff75eed66b47b930f0e9cc227c3af2fc210706466dd383bc8a9232e4bec04fc8aef7a4917248ce0b9cc7a1e29f92cd62eebac04af6fdf724294a7dc70576f57f72aceafd21775b60f2762c71a4ee226ba70526daf7fbac2cf09a53a63a893f6e1916384dadb7e5315dc8b9029f3bfcefb45de68156e0730c16b67665495205bef63bae602975ea8a0aacfdbd789047fbf25360624ae530859ce3b65260cb73f8b97ac5758c02eb6d9583ce99a98602b71ddd458f26216b744fe0efbcd2836887d63881d7889903dbe9c9e5d1047e537d7eec543ded6102179d82a498c5c35f025fee23163757fa56094cceb288a8f66c258149561b224dd48e0a12d8b28fbe081d68747f04b622e78776d69b3946e0d3ae8715fdb3c37c11b8749f97d69b3dd6108189f02c518267ff7608dc5ddcc8a21d744e11027b97671337a79a9009027b6df635395baed081c0e7c9fe30e6b4007ec0a520f5d99b2e8ad502f0019762151aad9aafdf5e7095d69f5256c8109717bc47ff4842eeb415dc5d30519d921e52f08eb2ba60aa6f24be89d77e682e788d8eaab2a62c652b2e98ecc98385d4b9e3aab7e037c33cdbf22cc4d4167c4fa7ecd1e6b87fcf5a30f1241e4670dc2a5d043e8cead291460fa96a22301131b5a5eb4a1dd443603daa4ae3515d21f09319e1398c7d9eea06811df5fadd6ec953e72200084cce9d126e9336b48f801f30d137f6adf868ca1b04f880af919c2cbb4deeacf782c9619e14a21fa9a69a178c6edeebb24a962ddd057fa97bff76515db0f9a3c9949a2b574534175c7bfb478d22ea394c71c1bb985aa69ce92dd8094f9ebf25bfa7a4b660247b3dc70e7d4c23ad059fa6cf7f7214a37b50d382bf8e4ad344c71e5aa4b3e0a38d2a9ea1729cc34fca82f58ea9adc3201a3a3a63c15de6ef92aed8a776c28277bf493994e9ab27f3155c8e728839767748f939ae60520e77f42ac7a92399ad60cbde237de4ee7a29c90a56ba3f8448a1377d2a57c1e71ca5be28a15405e3b61e576d08d216ca54b01e6da8a9ce1f74e4810abe3dd3d9e6cf29ae7f0aceb743349d5e8a9237057f3bfa671d259ab4a5e052d358ce2a3df15652b0ba397b1835e646a8a3606b42d04c57e2c12b280a56cb93aedb9945b230145c8e43caea6b498358080af66ee2c7940e2125859f603bfccedde15f3cc16bf7f476868af1624a27984852f69633e4a465e10457d92ee6f4eef0b42c9be0837d9c1beb5234c1ebb8fec4f4507db592092e87e379c13bc8d03930c164b878548ff5277e5c8233c9f1bb4951ff7a4bf09b3b3dbba5b95d5f09b662a688799e59fc3e94e02da4d552329360e3448447c99a2ff996049b3f394cc12e877e6d24d89174e51d5f2a4b5148b02b5dbf63b7e9b3f908b62e8d7f18c2f2c5cf116cb4f13c4f398ec262a411dcdda40823f8380e3234a68cc871e616c1a4a66d268d2b82558d2942befb6c5513c1e62ccd71f4feb1e4484470f939a5504dab54f3109c68883192e7ab8f4443b096f386e4fc923ad51582ef38cc1c67cbd72ad511820b7edd295dc714e90c82c994cd3cde780ae91604e797432c104cda2d5d891ed584c400c1e71427348de70ffc258bec28720eab347ee02368e6cf24edeef13eb0995572c71f2f5fd4381fb88e19f524343f28b7f6c0fb5488a19f436f5a4b0f9ca5ed4de60b261d5979e0f623c79f2a2a7a280b0f5c284bea133bc68a48dd81711b8f728c943ddcadecc0a6aca11f67fb1ebbaa0e7cc8d16f90a89034e7890e5c4e4d48d7f47587cf81a9503166eabb87db7260624eaf9e249a4c3571e05a5244f030d65b04e1c04a886611a3a50f397c039b7c444b2d85dcc0b6f485fa2eb3ec618e36701a39886ac4f44a123670e117d1327a8e11ae81b5907218199375484e0d4cce71b67fa591300d7ceaca71e534b942060dec6768fe8590b3ba2231b25e705a600e0d6a6c4de000676034a5bd4d8d9272c70c6cb8f7beb82431bf0c7c4fec8a9f34d5c69081e91cd67e14d1a9fb31063ea8d3cad7996a7b31b01972583ac9b9969f3070d2f9732cd1fe7b30307133a4569407e1f9021f6ffa76b2ac20792fb031ef685e7e0edaee02fb51865f9e4829840bfcc698f951f55b602b748c581d460b7c849c59f2ddf2654c16b8d718638e8e3a46d660818bc8f4133a6adedeafc06ed65881a96d09a94752c56815f8a834c9b4b5ba3ba702e376f7ff365e914e81d7dc21e7a60f8f925260df739caed2e51c865160ef3edb448d7ab1d250e0e376cd10838b9afe04cea35b0e742db88b4ee0f58386f9c6da94b6098c644aaf9f72bff34ce0bf2a2d7fce1d25cd12d83ca9f28f5dfaa054029b36a5afbd47d524815bdf7fff9cde425091c0479bf1dd23f1e8398ec069b0f68c19ebed4c23f041d00bc9be99e216816f0bc9722574e51422b09f3f4c672d9d2e84436053d61c722015fb7245084cce98723ca9e3d0db20b0975ae2af871c00085c882e751e77982f2507f801d39b3c5afb2b4f8f3b800fb8d1faefa0bfc300bd602fb6c7cc29378f78870178c1d5e4c8318e5b8cb13b0cb00b765483a6bc1e4287ee30802eb8d469297858396f8e1d06c80563f1e350dd443a3ced30002ef810faebbf62b7e0534aab495bdf2962b6d03b78c56099d5828d1a9239e5a022e5450b26556d0cf57f1db6350bce63caa371333b4aea90059b3a4c317fb1e0e3e8f3ff26cff5a982052baeffe9e9e398fd0a36a528cdb917db5c57f0b5ad9d9347ab35690597d643f4841c73d258c1741053b6acaec92d3a56c1dda64ee7d4dfee51051f3c680e42fe380648052ff15b43ff570edfe3180015fcee27df00a760e27d10766191b939c700a6e026e97aaa14995b738e014ac1ad276bd3d2645d9f6300521c075e4933e547c1759c1e3d33e958fe45c144f5bcfdfc97a27e28b8bb4e912e3df5a60f0afec3570b0f43d48bfe13dce4150be6613cc1e41ca3e4f477183ca6136c77bcd19037e7dc184ef0a19a92eee468426e36c18490f21dcb35c1ef87bfdbe7af8e3299606d2f730571959c6382a90c397718c9efd37e0936b32e7a1ce3f66f6e09b6edffe3984c62f65482f73c2904cbebcf9e12dc0756512c87b4cd4c82c90f59cf9206cfae24b8601fef7ded48301ebe69fcd37f4f1b129cc5348f03ad1fc165288f3d8839d4aada11dc847d7bd8a1deed6d04979b9e37a464294d96115c87b5be1d4af5fab908ee2279d8a12615c1e6907247b929a55cc944f0615fbdd122a584242218bf8bb6313dfc737908eebd634ba6e0f71134046357ef393dff03b314828f3786342d413d300921f820b47322998468de20b8feda24a9a2a9bb1304d717dc7ba2831c5a7702c1e6bb4f1fc95977ba03086e62e5d97ff4af713b7fe072d884e72babd0d9f103dfff92c9d53efeb74e1f588f63a84f661d3eb01fdde5fefdb749a9b3077ea4a205c98cce161d3df0bb1539f0d4bf0ea29307d6a26d472d2dbdcd8107fef2e31c9ec7f7921c77e0cffe24e4f250cb1c3bf0122dc48e1a2b52fa75e0c53b735a2f3fb09e0eec997aca10fd1cd8cfb1e74a1de75897031fe66b85e5c83d67e2c0779cca18ec6b7c87036fb5c9c30c212dbb6fe053c769912ae63832ddc05e8a9b6ab503bdcab48149e9cf23d3fe96071bf88e58766639887e0daca61d4b5f69bd4a570313e377ce61ae5dd6d2c04928b7b10df553a1818992aa0e519f818db4ed388eae19d83eabf50e51fd915b06bec34c69e7692c5d4b063e637be69493db73e8189830abad14ea9a3b540cdcc5f18cefd69e1f0d037fb7e2818aa98ea46060d376983aae0e83f9f90526f74308f5d0728ad20bbcc40eaa92b506efc02ef095af3507aeb997825ce032ef682a8fca97c32db03951312d654a15422df0d1b575cc8d9d31c22cf081d487973d050b8c558847a9995a39e50a4c7a64d6fd673f59b1023be5665d113587a85481fb1cc4bc3197881c4205be7c920651cd2529640a4c9d485859c60f39f752e0a335c7a4d645813b3ff5f0b4cd4e1b14d8cc9bd25f70f18d790267e7df717565ed502770dad97c2fd66ea709bca5767e7654f7554ce0e3f175e9389964ca1298ac9c31fb790e3b47af042ebd6df6c7e8817524812b1bf10e32340012784921751c6b25edcb618023f0d641df69af664d87018cc09947b9639fd6f1388e018ac0755e8e834899b7c7630022f039d2f45b0fa777720c30043e7d7772c8193fbd630021f07937dd15e59edd314010d8ca314eb7b887371d0300810d9e15e2719ce378f306f8017f912362ce903107be017cc0c50f4b1ebb6596f7bde0e35451d772fc2149cf0b2e337b1ce7afde90c3ec8237cf81e4f851e8a835bae053464a69a53daed3e482abdd888ec31bdf89c10517377ac8903a78cc995bf07e399c8e93755fcad882cb93b45f531d5bf45af09ff3c73c7a9d52745af01edf390b5eba3e4821a72c915c16acd9f969eaf85173742cf84d3147d1c3538ea761c1649eb28bce3cdaf72bd8be7cd19cdeb19876059f4933630eb6d16ab782bfcca16e7994759666051733bd6d3f65588e5d051b394a8ec8618ef9b3aae02d456b0c412a527c53c1a4368dfc6c79425251c148e86cdf93f8514e4fc1a754464f71d74c4953709a6f92c7b79a3a92a560a5f2e69cf18394bf24051b4a57af1f051faa876ff9e314630c8a82cdddadfb31ec3f130ac6b737f5470e6697020a567d53d77ef6e708f9041b9ea5729424d9fd9e60f34e0e15aff246ad13fc7ee5ac3d2e1da538c1f4b7db4b5ee84db709b6637bad8bdb93a309d6b44f4255e4dc31135ce520badb44458a0c134c8cd93e7dcae8f1b8049fd5e2b58a947558823193bcfabab1e3bc128cc49883c4afe0775382ff3cc12b7ff2b88293e0e390c395ecb8352b25093e6affcd0c21b5f948b0af493c5d4b2546c84082dbff78c17df4023ce2fcebb18e60c4367fbb63f30f3c8d60625acacc99e2153c8c60dd37dff7c713c5f38be062ca5e1dead64ff38a603d8a12a37b9477433e116cd4b20f434cd929f78860334eb4b5b2cf349a43f09fe3fe2cba7e51620cc16765cd0fbba394670a81c71b3cda0c213815b3cde952ca96cc20383597ee28eff50f417039bbee6b8d772a03c1eae6e82f67b4e42120f88e5243ac6cdf61e57fe0b7326fdb93f76bda0f6cadc7491f84c50b6e1ff8089f1811b4736cf9c07a500db103750f7cf8a61b52a67ae06debe3bbd70ccdc93c70399a8d4749f2839778e06f235d9be6d8299677e0e394dbf6d2e2d79476e04edbe35c1da7690ed681afc8c156fb52472948072664ea541bf5724a700efc74ccdb39aba6ac500ebc7fbc29e520a5958471e044c33258a4c081e9b70b153943f45879037bf1ac2268d68d49e20646aa62baf4e4071e6903eb9ebf2c04b18e52c4d9c04d74f3489b4dda73be06be345e67667b089a733570bf1e47938715193f4f037b41da83998d77f01c0d5c5f660f3a4abd1acfcfc0667fd7b5ca4a229e9b818949dd2346284d1de665603353b060394aaf3727031fe4b28adf71f2d8e563e0dc524e96a3493e75b91898b4f6ac9bd2d45e7918f86c1d7710b9962f073918b81cda3cc614e2e59ffc0bfca5b81df787ad1758572ba9102abf4ac8bbc0db646d568664fb0f2eb01279d39991c5ca630b7c6848ef4a1139ba1c2df0398819d2d55b0c969305a6a37a85f86e97f4c7021f3bf4f412e268b57f054e74453bb22599f756603a7d14ddd2a3c5ecabc05f86cc1f8fbc2d7a2af0a17d9ca38d8e4a35660a9c764485862cbd9791023f2ea69744b26adea3c0e771ed10620e728c7128f0b9a37ceb90374a8c3fa169b70ee1b61398387137b847d28e6c02ff96b3a5dbe4182f6702db917ba61b8d36f95e02173ff2d89d13f2344ae0f3b7a6ee6fbc4d93c0f8a47493d7a663b848e0d6fec32af856ec8fc08e65fdb823fd286d23705adf922b7dfc6c11b875fd97901c54599408acc6d49a1c43ba8c0f81b50d59ad69760184c0c4fefc90e3df90c7ec0204810f3cc7faeb95bfe2d805000293d42a7ff7d7378d5d801f303177282126bb10a2018bd8a8e46ae42242e1e0c05030180a0381c06037be3593160000000c180d85d2340d34c176071400033b322c3e2420121c120c1810160e0c0c0c0c0608068482402018000604c240301818c493d1ba06de9514db58cd16dcfabd95d3eaddd28c5d84376ef3d1e3b9bcb6ac5e0f606e1fd8a2c511771fc97706f0c30c1d4a7cd1468d0b6a28d1c484c9b7712ddd33b6e90bebaf5ab25d45a468636ae64976f9c918e45043a3a2007a92372148d92eaeda4ce51305f8d8ae815e59ca75ebb6525958c1ef3d03b17ffc0cf14752b2d48e9078cdfa85dbe8c42065cddf8a2bbfd283a97105b1bb939b186c0f779bd66a81088618b1898a2a6ef49216dbb4b435a202bae2ee765c89d435591fc7ca987177cd038e50269cf55a4d3c0c2816fc1c0d9294b5ca28a8091379954c1eaf1cd07d64297ebceebb705facc3e881a20743fd8738538dc3c79dc13cb45ce6d0a05da635f6c96c224a70df5421956b07e60cf1847d456fe6eb9133ba61a38d1b7b638efb1a5f49f7b1a689fdd4a3870c87d28e0935b59e746b9011c280982aa54275246a4e532ace09d86ddf387874d2d98703eb2eeadc935737befbc08a435040372e1f6e3a41bef989d04913694e2c87840d719911ba192af553bd994d007abdf6f4f1c34350573e6c5092b7970f8fbabe72e5dc31bbe4214016a533090a441d499328134c5ed7d9530797b6bb1a2a208270d954440e1fb64c46026dc774845d2a7d5426bdba2b1fe5258a78edccd18147174edf3d7770e7cc0127a3e7a401215e7779e0d17d860b099ae2e038ed8e6dccc4b7c778647a7e5289e6834549244a34c184d023484f92c4299f7878eefae99bf36e1d1237c74a428502688abbf0e88443e76e4edd3d7b76fddcd36397cc3d5610bc217ecb62ce6326b042cb13467aa49bbb3c35c8d1b2358a358a1472cba756c41174152db13bbf7c7cf3c6a36737a71e3813d4e725fea23dac51d1e7387fca5e122a817e0930be64843670834f1d7077efe0bed393f78416903fee0d777cef712b09d2919c6cfa642745069504e924a7a17dcdc1324899122b3afceed9b3dba7cf9cbbece8dac98dbdabe0aef5b8c09972c708b67cd69025f14653422ab727126a4d9ce6f8c8938fbfa9aa1d94c1cf6cda5002192ad4d0491023eb324d8f633bcdf0e0ad540af9cda14cb3063a56b2798d255b4081f0844a5f182eeee529d920460339959c4d43339ec3ba305d7affc831d720064cf6ac72f7c491b7f7ae9f3eb877eab0d6578942b0be38be79e7f0facc8c09b9949d3b758e810ed1af77949969d1442ba10495c4ed6a68219498c53cae555165319b6da6f5274e9ce2559d24330c1b08218ff4fc12bfb5be35b5cbdd93c6f013b90c4bab836879a6051b23784e718107946bc5ff83c3dd7efff29a0d94582d2ecd6d37177d0751e71e47f1f1eb8b07dcbdbdaa4932e971f2ac5cfaacd1dd75c7ce5b4b341d0268153dbc940c92085049c63acd9dd387ee9c3e906366cc125dea3662a14e8c7f8a9e464774ce84829bfdb571b86c9ecd523d596f3bbc7becf6f535e78e5d9d7620673b7a059c81dfbd75de3cfa08c9dc329be859582584ac930066b488e5c4a2018b84f4f8fdd91e0bc2778b3a77e8e0f447876e4e9d3dbdecf8c5c3fbce4fdf9c7add8ee39bf7cdc51b4f5a61419a7fb008f0b56783d70a8c7ed249907f017e14d2489a32f9347e45ad0e4f1ef7d095a383f74e38be350f217ad491a44a76ad534777ce9d3cbbc6f9e5b93b470e2ca774e6fcca933b0737234c843632c91c5b8392fdd40d87ae9999016ed7410a59a448d4c933fc1957f3f7ce6f1cb9efeeaaa3937b270fee9199a359f73812b45437ce3abc76c264faf5a76e9cdf6b9274ef8cf14898681811adf62d7ea6b68f25ceeb9f01f4cc9b53141e36d721b351e369362223fd7943851141c889e369a6a7686d1a37ce6d66f35d48f2dcb55307b97102dc838594c7270edc7675d9d9c9b5b3e70e5c7f7a8d499a09134f9d442448a490247dc2f4274f964639470843f0898c60c34c680b7d54e5a08e5cb28b6ca02929f5a633860f1d12b40c4f48a7b8995da43f15fac74edd3b7ff3d0c1c519e7675d38f91a52fb67e20e419877c50006ec6c9d98ce3dc720c16546b8d070cc61449db3d3eab5b44516b350eb8d77615d1526ab9874b1315dd4617a3ab60895965b5ddcbebde7e8d4cdf9cfce2e39bb7b681ffaa4b7271d1fb78058dea95b27e72ecf3b71fae2b98b1336d29fba71de6cca8533f78ce1829028dde44a9dbbeee8c2d1cd9366f8a73c7b76f9f98563b62121c249ebf0ec1ac777cfee30c4fcb037497b9f067acc865ae1dc6c6ad26d5d3a35e898d0e225611b21129e3426d0b36590d910070a94fc6a522d1ae6d032cdf07755245480a199edb52a15c7582e4475e6396541fc6ad691165d377f13db231f847e3c0207ee8926e27d24b684f4315f3a5d40d3ac37d2312b0104e32d3048d731b75c9ed484da8179234c3a61901e616072f36f530b1a09fa97dc50940928afe39f14c728cd943eb19c77e70866e198c6a6e8f8e7048eddcbc22d038fc433a00e004c87884488627d3dc98f195e28bc96819c850a5560e5f605b53feb0f0e91ff9a1ac354e1f0453899253e1d9c085bf8e4aa8588c7bc0b98880d46d5d062097ff8d2e35e9dfdb53108545281bfac16e14ff86a1992ff4e17b5c574a798bd1ebce18611c7b452ed0c9a4a711026fcd1205e94067b1510907d0b7ee7a845fae81fcb7110b948db36c94c638205de06625225f4a8033b048aff6ec689590168f522513b8a4aa05984e91cf209013270abb2357ee3b79acb49304a6236acaff154e7cb8e39d9ccd6baa8f4b41744550373c14e8e932cc63cc42885f2398c12c0d870be215debd4a9ca16e6d74cb101360551ec482dee3481d412f033fc17ec8515e59117b4aac04bf8d33a7c4d6f007839def0d289145742f128013566654cdede54a23389289aa58667515da82854e195facda491db4fda1dbea95bc4113c15ae4c5136f86343dc1d7df81cba9c6d61e0a34ab68c0a376f485e988bc521b442cf4cfdba458a6cceba78abcccdccde708785375a6db61dc2e48773f08a1fe315ce6744a2ee1400b793b122e474970eb11d7e0098a37218a4f4312a6c12339f07891e10872e1779d0de3fd7fbcfe4145bcac9620c04bcf3295ceed13fa42de23231a18e732450148903a5ac0ebff0c08053fbea353893946e6b3cc4b8c33475120afa14b6f64241b8c90b65c84b44fe90e916204e2d979b3bafaa59a7c5df5d08309a7eaf86b02a2cfbf41f588d65139f8be5dbc3230d50831837d65b1dd49c91798eb2353c80aeb8e71087113589db0714215f1d1e67ee54c4dc8f6447a4d1f0d9ee8185e6a99e30b5e49397e7337c708a4d2c50945da25593ca99ab4758385608b67bddc087b47fa4c421a83606779ce39ed0e94ae91ccaca959063300f1fa4a7cba8a224803d915cdecbcc00b84515147029bfe6b7f5b023d8c20db56aa90678662cebed044083e9ba5f16d50c09e12ba91aac8d68b157a98a292e99d77432ed2302fa138e03dabdf5d00d4d465db9bfdc424b27cdffa014b80999137ee4770d4900ee4fdd0673b57f147f6f552ad4b87730780714812a0a1648edde55d2c1b7cfb9a29c7a70c66a141ea681eeaaedc7292d00a7f67137bf3e3d87ed06300ffc770652c9435eb72cb00b4380bd5c0eaec62da08df1f303278bb9a66c5cdc6476229f135f3cf337cb08041a6f3a8da2690603cfb49bfda52a4c4a60479ad9e258b81d034a5ee177c1983c819e78cc5e345749de13d79243ebe271c14a01be909d7d5bf75784c31205ece6c966a4dc0076a44070b31bcc72f1816e4857150615d7de68a3f420cb3e58a29840102e1671937e11da73885b89f6c5192f0473f75641da416d3e1b1a289c028a1b550d18cb391f30685c0622dc1671f6995205a861cec29afd6d49f02ec8c00688f4a178dbeb9b9568e4beeca50a946ead82dc59c3c52f8f6b59c9fd08ec991d6ab500bc2382aaa47272267fcd55266cd5a77accf28f220d9ef287003df79bd3cc32f0aae9d9f31bc35e69350a83ece6941669ea4346b07006ad90111d371ae9d2fa3fd204019987181c4bb89b020006668033f0b7777b58d01007c05f0420a48c2141c5183ab142b5f51c47a7873617c9df14901052872e5b19b6775b2b06f05fa7100e3e3c31e9f4a48be41acae6a451984f8c2c5100d0c1c372da0b4021007d923833585e6a8c1e9be263de024aa478320b002e978283d073dc58253602bf1252517b813e4da907e59e549dad232f3a1a4d395ef6bf975a0e83672c01f9b4615bb610b4752a9c441136a2f7d642140e69314ff6498e3a6bc77688e3f30e0d4ee5710fa61f61f6cf19388040ff91bda50666800c578f785fe4fd69087dfb1d50c44a8303529dee83a144cc668aa0ae5ab401407d94cafae342c013d32216c6b48882f70c5aa9a3713d132da8881ad539d5ff66d079d58c3d6381c1b0695aed9ee22b42350eb7f8e47ec501deff1cc0eda83b0c1e20291367e2a54effbbdb69df585a37d1df8590e32c3a6ce7e42286a940385c0ff0faf6d1e940eae5e53912eb9ee7c3584b44cc60f1930c9da0ee94e8333df7c7d105fa2b14a1f13d4822d69e9fc2b1440a1d2f21a3c01ee476a407de062e35ac139fdc76f682d9b7c265f7d4ea3785cf46d32e7aa3c5f0e20577ca0968a59914dbdbaa90ef29dcf6a82100abe8e7d17cc8799a0d6535a6d38844be2abb852900817bd451d0c2530a11de0e87d07b0ea35546aae4d269484f0d2bbbdbe73876c070a8a6cf7f89817b38876c9a95e054f5b0f4376e9611b7cc3d289ccd4660016c3b1466b567d1ca3393507b1deb075cba4588445942d676d283aefbe3c26bae958c08450f2496160f97b01fddfb8630fb333bc2fdba2e89d9d0c1e2d3f52f51c5f1f07ec550703d696594c6ef8065d8a516a645ea42da8e9d26b18efc41be48e19664cfac553b35ac1d22e8af9c0b37209ce73587b8f430da485c7a00d1a8e83a8a98189c342372cf6ed8c2cd542171e8aca047c606e4a63c4edefdc31105a50b52ce2d696007be80b60d0b87c39fcd57c0db799b52e536ddaeab45e20c7bd8c9c525bff5cb4b2d6699af31e538eac01adbc88420f892e7d24cb25cfbe65512331ec2ebd02f925981ba25a54ef72638c132425fa2aef98568de8c34ce362323b6b7dadbd123a26328f42a67ff3b34005962038c44a11602be0947cf0481c4d0f862a564fcd41fc6786a1c2f46aecd135a034c11539e5d8b5494c166ed4924bae9f025c3776a3709c55f094a2b753d01663dca1fd54384f02dcd2a687de216c828b4240a671e5ad2d154abfead23bd211cdb160d7c5b959b2e5bc549f355a96cc5b01b45c4ca204d0eeccb1b8fd95201b8bc4e0f10bada9e0ac25d6a2331fb31c7dbfd2d391ece50a05e397285d5b2b0d12646bee054c5d7b592181afd64cd5317987dcc110a0bca066f8b689c7b72e8ed9ecdbb56cb208dae4c4d43fe6c50045f13360f41f042de0cab7bc64df9158b8152b11560e2608ac216d9da582a30a31d48ec61e65be169053c8fb72a2f92a4cce0e2cbedae73ef35a9cf732893abbe5dddc6341b09a794e7660a2199a5ad5649e8c80d072972614865fde8c02eba4c2377b21e68161806c17333d41aec9ba4606fc2e2f4932d9a60e58c5265b674f12c1ddee63d3402e313215b370e58cc0044e4be9a1feb805e6f72742642803905accc01b8766116668073263cb82a21355e8908c06a798711d9ffc961b2d08f18c77699ed3363c474fecd9a81999af865745f896bddd8d1b0a2e9404113a84d04759739616118b420e841450496485907ebc9552896fb3a2ae1c9fa1b52b66813f39a37bf82d22e0bdd1561b2502238c7e69a6bb4fc482d021197fbf5a259a0d41b29c1c82b0b4e9e9185b84f65a50081bf436b541454b9de23e5736d6961d1ea008b6e71fd7ad4ed8476a481f038b275a3288eac375cde5026dd9309725a6f342bfc2fba982038a4ff8139ee0580f9ed0c3448a1ebde4b0f0fc2ea94ecd758faa4cef4e25468f1f9560181be89bc79fffb4bdca91242362eeb229e64d806da634909ca842bba29fe2b60e7318c97dcd058c36734dce8687094e060a5cdedb667b38d505521f45498eb7393055901276169b0382dd7e5a2c32a64e9bb6354c96c651466d8d714c22477b8ae057b1eb02f73ecf343acef7668e79638cdbe9afda34820116378c0842a6d378bf8c60c33fa5e13536abc895684ce9ebc1e775d8d41b8157c6261acab0725846d2e6d6c71b301f2a3bf213bf885b358074633a442b51516436a5ed64e4957437548e8f29f7e2e185395b84ab67ed1d93b99e38e6d10a11b99e752b7eb9c76ff799e6cffc121785e7271704b3006a112c15067694c193520295b7e926dd738ad353bc5f3396620b3b868e3024152114ec19d2a6bd99f2f620fb3fb91676ba448a0a48c7d4f45b9967a425e6d54fd571de3e71ac6581cf30e3e01c82c3c769fdaa122aa82477b6bf55ae10187504ebd262124152f1bedf84c4a8de2c9fe3c7c0a25c13bd1707a664f53b1ef8119199d275e8e132a06adb928119960150a245567a69ef11891400fd001a396296ce8c8bcf00ba09e7874dd4337904a99cb74ef2429ecce7120777584c36caf020b594929906f6615189b9b0ea7f1bc1d102870566049faeade8d901a27c1e81309809499b336c9cb91ada67bf9649117db321683af1608fced281c4ac0a39a887d4a426b82a008a374f7cd92a8f8fc9040ccda4eec63cd080f0e0c0f675c741ac8f29deec08fc9a7068296e5683cbad9c8cd48ae62fa0f88806d2a497871bf2d304aa3e8d586bb99cb468b37219868f4cdab06e40669930dfda328c5ba93e652a292be7043746772501d8011c7178a5f91005c57cdd71a20d7163162f768b13ce18a0ca97b5fc8edb7f4d48c9bf8492c3fa9d691b3e9edd24187491ad00b898857927b75f417489523997e3758dd3e329fdd581c851ef7dd4119af25126347184d704f31322d103e5f8c6ad316ff07e10639912417b365110f7d6b0ce6d8c136bc6700adda71893566c4a0c2ca84118b598bc581298f5517ce10f5d5b5cec7980f4c2c0c11d85b991d682e27154960b860ca61cc65d981bbb8a87e8ef98389815931c814cf868e480c239ab566c3a9299de5a6c92f3302862d34451cc20c3fe4748e65e36c26ae116ea582f7e40508d093838e2788486e499028d504d3428f9a2449a4273779e2d4224125411a12934d9feca4c8a09040aa18d13338c281ccd34b9ef7848d4e0a741a46877566ec49858597e9fccb0925afe82778940ef93cbb0304460ffa605fe7289512f5d509c0b6c291407c22689817b27e1bc2d4c61b427e0acd70e4a974445d9d4aad06dd05c414692fc8fad1ca1533e76cea8ff8fa4b84a669377d9db321fee05d310647e484cd4bd754098ff55ed8fcd8215c6ccd0fdcf94bf628a154da105ea710ea9ee2a3f34842df2d236a9ae0ee7eb7ab62382f852a2b765f34e33cb94e7ad00b5ca312abd7e0dedf35ed497f32469949167f22bb5aa1dd1e8ccb3660cb2b48d0d667d49bf309cf66d026b71c1ce1c635c840959a6a682338ba5b230db024637d7b5f74dee6d3f5101fd98caf0c256d5c5623804a0835c149624b5b589600cff67e4d561167ba5e3afb06ed46066501096e63e8d7b16e940f00618c51b2bfe61b566550ece5dd330ea8ee529ab85aa8a69f27cfbf31013c586e0b6dbea680a90003b7939b47f4761d36f67cbe922be9ba5481727ce0d5807b2776972ec71fd123f26db02a29aec1a15ddde7b4db0abb125d5eb8705e91cab02a6312a2c4806802a2324ac5bb693275a015d1862db9b7b623173c6760b34c38f8c5ca725532820710576525ff11a73b71008556082cb7bdccb59844155bb980a821c1e511bd3277de14108780eed5695861352dbd5deb0d45e4c40b445adff00120705d801d901301d88a28697bbb4f82bf158a02de10f0e8e3e9735c6c94df592f4613785eac5becd98b05fa0cf5e5b515b592949db22d7fa5014cf65a7fddc37f910672fe694efe4f5f6f341f9e3c0fa1fa793645ade3cf6c5deb5cedcbcae11470adc4c2363d2302c2eebfa5f7d343056b5a45f26547b93dd9e23682b575b55453f86c957f8efbdb0a187c50c26a4e62516557099805249c2609b662fb68512b3cf831dc212573904a14e238daa06c02a0a43a30136f6a6dcad205b8d40305b0b683127fa23f41aacf30643a763f9cba541990b6661bde4903870260ad6816f3f6211fdc761f26205a7045ce02ee9ef93a2ac0b56f4523fe15f9a41111b86fb0e9156cba4cd33005dea7f379bab0ef2083cdbda90925db4d43dd86db1fc5b4682405762066291a061948b36c2e7b806d8c6024058770999ad0379f2dec52a143b5ff144f1b37fb287943c48f4e8c5a94625ae48355649a803e7cb49536ebe8af5fc3f7725127dd25d5db38ec80d3b3712105d6a926337cd3c625dfdd706d7304f9946a6d815540671e55230a01c39d7ca853f4caa8825393a89876cdbfbccfe63a93f3ecce4a4bec1515b765b7aee8988e8774785cc18df362d9aab9ec596e825e9d269efa8389858f142ed4b01f862422b316f385e5205c47a2a19d77a569fc63d95e40dd870c8fd87758c03f2156776bb0bd7c076080e2ca187375da4f1c5d7986f231b1723d07f8c31561e76495d2d7e0d3276ed0ecaf5f1038e6b4ac4d05031e1ac05b1a0c2889dba70b07b499d1366d5696eb084115d17002839631235ad5536365666dc76061b49462e6724411513da426d706ac2d94c925c7390026f0aa52bbab023d3f854f923754343c44b102fd230847c6c7e33c1cafcb80b61b5303060df49096dd224ec0917c821c8218f3c9689d2dce4d359338e4061c9ad05f09487e145fee02e372d1c8d6441484a8466cba454c60b45693eb36493e14882f0075ec392b40f8fcd2ef7eacb7208d1543dff8c61e806ee04208f596d647df1c92f0d91151eacc2c3c63834934d09b73ea6d2ec9e97a8d696105c71031a4c8e934d399ebebb2576240e673d6c9ed36fbc604bcd2c123162096051a1345b992535d9bf015af4f6085aa662854dd28efcba599ba94459303c2e421de6b93edae2a2ff5bc5bf66b03c4719b3df82d4f6f3ec16a9df894e836953882c8ca2e8949e31ad17584255a1145d4f6f7d68bee4e3c2588022bc070618474128b7e29c6047610b1994d7dabeb713a07d868d047f471862c2c46e4ea7aee32bb41ca8ee72501f42a1ff82862237511671fb2a006deabda92925fba09e25829883a1ba19f2e7a38acbaaac4886da548ccac63f57a15323a454b0d6c15d1a42bc7975033b87236d53e7f404a869a78eb89a4443e176bdaf7c7ce501953043603d8ad17892d609636f889515d5465372041c9977634cdc3d3fde6e013163c05f5401f096a2a80403fa55b6427800329f1d72896445d80b218c191079a76859d2245ac4d4a1e8dfce89162c1590aab01e84ba3ecc961902d7f69e7c68e881958df474a410fc00b86f95b4ef4367ca50d018e9a6740ff19ec09929624c2b0ae195ef94f9fcb258143ca1c533c502d33693a3505e2e84d3369df647e1a871ecf7d61bdbd646e570b03710421a43a1b727bd47da66476b208fc5d494a9f569319f5a56b8817e7d53e16a2635e48c9edcf8dc65f828c2d92bbcc87fc5a2384874e5e12b69c5389b7d503abbbed981321c8b7328593a9cc1f20bc5fb5a2b92f4e365c73f57921a3263a0109851944ef996fc2e2f79e57a3a786f35a7cec2583be413b8931da98970703b2f539597940f0ca016a74c48753d53bae942f37cbf614bb8834eb09ad37c7311f449f3ef331ee6e9eff931a1db26ef98aed026ff4c8011e25a5960f8ebae9b45202ae2c0241222aff11fc04518563943edfa68d76171c648450c313d0542daec89daaad0ba62d3615dec018259d46bc5aca668288577ae4aa0ef9944f962fd04bb1d7624e0a85434937fa16526d2b8ccf4bac20425a33cec72dcc6278c99adab1682af7cb0e41a24d905dbff7eb01b32b986f932aee7c323da02115893fc758bdca7fa5203f7a376c4840b8369bdd2df9c220cc541f146629ad23025cfa26b984e330cd798295fe90744c06710498a3ef2ef3265fed393cce2b7615d050309feda65ec3a35a1250dcc7c4ad210695b2d4360047abd7140a5a0a7dd812b196a1bd6775152c45029e2ec4a60a3960b46439330f0f0f0f0f0f0f0fafa18d90da483b8424c8946412af76dceaa5197557a694a44c2909ce4c7cd91dbc8377206b6467c4a7934509620a2f0bae0a5d7e5612c6274e5153dbf75f7c99ac270eba2246549377299b979d38485121457b98fa87cc685891030c4e9c949c58150de7a6e3927480b189e395a9a559887532e66634ec03c806189a38ca8a8d980d977d3fb3a0616ba5071899385f040d3959ae4745048f031347ff0f95d4f9d550f382b9a0e15dbc1e1897388ce44a2d6ab63203862556ef5049c9468c8d2d6c201a364200a31296685132cf48b26994408b74564a066050e2145537cba5b1c352bc5cdb9916729cbe861a0d05018c491cf3d594f0eb1c592ff130004312a7494253df09bf60012312c7ebb3935a71439e3941e224d17dd734a8304a591fe8c2c6164b01188f38977ab9141bcd1a6a8e38570c32cfebaebb0bc068c4294951c24ca420b62dd6502bc133e29c737bc9da33b9db4c329108c058c4b1532e62aebad450db82b9d002bde315301471ba8d1199c9235c84bf869a3d0046224ee611d6efb4ad2815d650a311827f2faa0276efe7001888389d8eab4d51b5a4ff431ce732e5b4a410ca5490214e3232d585388dc65512d9bc2caef850020c429cc7fbd5a25ff6a6880ce26c4a95ce74997f477e8238e91eb30c9d6c6a9436e363c69a0046208e7bb2499a0a237e210910a7f0962b7cbdf504187f386a285331c1477e38e6899d2482b4eab7511f7a4d21649c58623e9c7e938ca92184d290e73d1c946ab694b35b627bd6c371d56f73fb8dd5ee9c8753ae1e4bf99f9d96331e4e4a4c7adde8fb1d0e26cf23e6fbbd9453b5c321e5dfdf87cc3721cf3a9c3425c85a1e8d913b4287b3e4891584a65c26229cc3514d5facd80be570c863b2f15a412be671389d929b3c83d01be4342c3e667c34e0238b2b262043468e40868c1cc1192dc080c329cfc45506cdb5f90d0799eb340b6de3a2bae1d89a215ab8943c93eada705229236224c9d870ca9d3196898fb469b6351cc534c5966c25415fa98653e65049684a0d49229386a34fbe0849de050dc78d9727d4522b5406912f609ce1a4a2654d5a3c821e13491c30cc70cc62faf462927b3ac31a38b8011f33ca68d88d77fe1aa9850518653858fe51f54ada94a9b5e0d8c20b2eb4e00206198ee329a72a5c87f69071f00df602c6180e7f62aaa1f67f23070db32386030081802186939688997b5bf14f4f6138650491a476392f520e86f39799a5ca5c3891375fc0f7626cbc709c9c6717f53798b0b50b8768f147438dc98593e8bbee8bb316df2d5b387ce5da57bf65fc9668e1e027f24bdbc6d6f62c9cf5ecc664ee35d98e20049b87808185638989b9d12ec913697485c386b9d18d642148535be16426c2a2ebec894bb80a07512526869b9d974d8563c917b1ab396137de291ccc23a920f39f94e0a714ceb3a243f66d46cd3289c2a9ed2bf67b8974aa7450387f5cf68d24d913ce9a4e5c879297c1f3aaa1368210d048fcc43000817201c8030c279c456ebab05d89fa736ac2416c92a0fde2c484a3c8b352a64e5d25f92fe1d4f9a54509afe81764251caa5dea92fa2609c749238259cea96d6f9170d098c9a13d312feae50887b8d6657e6aee7b538c70b62cdd8a672292e94a114ed935a5b89908a7fc9f5fd2f327e84a86703689e633daae57260ae17c29e5bf8a77eea7bd201cf2cf7dcfc87658de8070da5cb67719edc7de82f18363a5d04ce7235f77be0fce1b438ae297ed1e9cb252388d5ff72563cc8363b01a11379ba129da1d9c33e84a9baf411d1c57a4e60aab961c1c44be942ca892903d3d1c9ccdae94e685b234767900c60dce93fbf6349e12fb7fb2c1393628bb58a6279b08d5e02c26262692086d23453438e8502327cd058b1e9b191c4c48bc50fbb1517d95c12957b8f8ab92a6e1a23138a4175d1e322c3038e9c875994bd246d2ef05e753718236cffc1d4a5643ed3fe04fa39c0d182e384c90fdbba067bd645a708a184a4bac0a0c169c5636baa9b1f82acedb13fdadc4d37e47aa38056da6749b48d779e1541c2fcaa5f83b5fbb29898a7305f5216da2ef87aa9ce2a0fd4385983dc37655a6385b88ef97e2945c5e677c7d529c3e6f444831eae58d3e8a4310daa4968590b07d8ae2d473a272855852362ea138697c6658d0cf9431041407d9c917e26ec9698a9f38b6ada776c5ca1307d917f355c62a624c278e1e692b65ca262c9d8913e79131987c7b869f7e13c7b653ed12322f4df29a3828dbcc99bffefcf24c9c228e06adb334264e42b7a4a8fbf3258eeaa384c7697c4d3f5be218a2a9c6fa7d2b71d211bc4fc64a54b19712c7cc3e4bd72c67e9ce491c36485b0b0f91b4dc298953f76cdbeae4d2783312c7fe7feb519599549b90386493d72c299adc51e6238c71bdd61435c4116799a8a6f9da24a450234e715b6335dc6710f731e2acf5f2932af6a6642ee27c2a6b9226466b508b220e96367c75c66dec0f7441e33fe0e7b7f02eb80165481040224e6ad3b5e948a2174f0120e278eded1fe726b346c386af0704708883be3bb56fe32e7bb12df873e0a011822dbee862e6de6d744104608893c9092e12d444c9badae01268910c737c1181126891300034104021ce3722a620be4d1c1000218ea3b2355f3e6d947635d4f60b0d086010071d93d8a32c28791909e26476596fd35f6b6b62122080401cde4f6b4e9a98dd1702c431bd6bda7f478c1163fe70086ae36662b44831b37ec04d8f188d23210610401fcedfba26735c491dcbf3e1581d2ac96fd3b29efd1ecebea1a331d4480f47f58cab3659ed5d64f270d09c20ee93eb4d36888773ea46481627b488ebee703e4bc9648a9031400076386cd6e01f62d6e170fe9237f8a620b582e8702aad48e21374d94b7a0ea73c3a8345d68c31822c87d30615ae614a5ad4d7c4e17c21bd7e88d312f15b381cc4e4db7d6e1a794af28653b6a0f2a6fef90b3a74c329fba91877662405ef04d08663521f191776574c576c38dfa92ced21396428ade1985a1a5f456d2bef6a38c89455d1083a4cc8d370f22a7161d2e44d66a3e1b8c9f54cdbae2ed26738498e244c5614bda349663845331d7df9082aa4a90c272547f95f881e190ee2e96e1674dfe998c67032b913af6c92761b93188e3fc2e7c26e27ac98c270dc9798134524cded12180ec93c46fe6a9aec2b7de190cc36c52a8b1bcb7be198f6ce72a6b01db1efc2e9f287d6ddce85635a7ebfdcb61223dfc231f4e289bdaf2469d7c2b1769209d32ec15ccfc2512f95509bf6f6478485f388307243d63d5bbec2210565ca54257527e3b7c251ec5764d4f4ab704a3e9752cc57316b792a9c54843b9942c5464a7e0ac77fd1155dfd99d92485631212b4a4a047e1745b32560aebb17443e16c65bf296d2bcbc44f380611997d6eeabb66271c62ca96922aa937e128baefdfe3cf2d93ce84f3a5acaec154be84a36625b9a9527a4d952be1dc16a92d6782c8dc51128e495d1e19564aff8810120e4a49772bd1267e54d0114ef14f9b983416b48dc808e717597f76a992e91015e1a0f233fc6c564f9321221cc44faeaed62071ff1ec2b1d449185b11429fbc8570cc1511bd2d97874a76100e49e48c280d2daa5a03e198fe62ca67f95664fe07a7b2115142aeb5b4b00f0e31f65ac85992ced41e9c3de304ff92a4e62ccc83d35eccaf31e8f65215dec12924aa5a74938d90631de0e69dd9926c9c8353fede4ad413cfbc180767d3d02e226688088b6f701e716a84d8c7feff3638c98914fb746d4a3daac1416bfe081a432fa30805ceee88ace15c69a7bb2aab6380871a4e32c8903645a9f8999d86b356ecfd17ab4965ab071a0e9752241567458ee6ca190edf9b3526192fd89c40e161867368d5dc9b6cec3bcec16e6e20161ca011804c7894e170192e24b75a501f298107190e2a628839c278394af039bab031a390041e6338693c33a12ecc89597e080f319c427875c9f50ecd75ea834718cefbe11b638f96a825bb8307188e32774248485a499cec0ba7d899921eed227c4798070f2f9c7c6edf4f6daa281a77e12442bebd72176ddbe171e1a816a772b8445d93bb1b3cb6709e64316752764cc8a40f786881517726e45610ad520db5c32ff6230b067ca08b0ac890f1376c54a08e6bcce01a3364c8e01a886b201ade05dff0c8c2f1c2dba46c3fd6d02e6cd0489d8207168ebb9da9e773a4068f2b1ccfa2d987fd4912daf9dfe01a38f23dac70de517a825b280b7de11a6a9fc3c60868e0e01a6bc3a30a278b166a55256d64996aa871f1c50d1b5f88208f70e1410563c50d172cc409d6dfd0c20b4614784ce194f13766c8d3dbb2be865a073ca470f6f6fc92383ab9281c53c85d5b4f99fc1a34080f281c74ab558af9b58c372b203c9e70d26ba27d4a69dfd5fcece0e184b4a67cd59a1b6ec2a9feb4474e5ac634ca82060f261c7deb92cde45259c2d1e6eeeee2a8f48dbf124e69f9336ed0162fc4cb47c0cae0918473d8eba83799e812c25cf04042d9165696d99210c2820334bef038c2d1a22865ea2f55fcd53eb2608006687818e1e4ae775a64299965b72458708046043c8a70cca6e9de5e7d4484b986da0d1b39b4e872430239b448800c1939b4682c3840030b0f229ccc4559fb87b2865a0e2d1a6d011e43386484ab79d6c7f6a4861a8eefc2068d3209202db6b0400e2d1260c71e42d0fc4a7a88dd90e5e0f7e26fa404cc8f2087161af008c2c9455c0669ba94ae940081cdb8a523c2e307e7b858a6444c90114d7d70ea4865631543479d55a885f0e8c1317885cdb4298dd6bfca070f1e1c458548298968e789a03d78ece05c297aef621a5563af76e1a18363ca095d1792da13a99483535808b69947c490f7ff076e7ce0c647a040c00307a7f417b19bedf2d285183078dce058215cf4124b93c93362f0b0c121977a1ba5e25a265fbce05183939d67d22ef1afb839390f1a9cf2e7f4569c7c661bafa1863ef098c149b2564ada6acad662060e1e323824b1303b3289a7ab9a85b13678c4e0b8a3a44aaafc1be242dee00183f3da48ab7bff8ce0fe0b8ec9c243b3286d5d705cd3792d21befb7e6cf068c149988aa8070b8e96dfa352f3cc551ce75b540a4267658c93183a5471d8152192253fa93a261c07828e549c92baaca3dd465c4eab861a1769853b5071da3b15b4ac925788f31447dd202208ad2979a638681df9fa23161bfe183a4a71b64a67d71aee7e7559411b1da438785aadb9a9fa31e3c3d9c61626e0097c6471c5c7651c3a46714ac234e809a5f7249a5c8310d44087284edf554aa43d150ffb1ad0118a93d01052eb689712b382e220428a9133053159177fe298a4d68e4c2f71df27c6130793d1441aa5d23b434727cea3eba5cc57333e6d4e1c52457bbfd3e9173a36715c9fa0a26eae53e7996a02e1ae72298292944c9ce2c98adea544fec919828973f986f09a2e9e5c142f71ccb420b6b4feac65d01227a9418624966e256b0e2b71f6b1db1853282971f0bc987bcc3456d224d4b07c15492411644c1267d90d32450a264afcde489c246f87b975cdc8e822244eb1542825d72765b25f858e471c27c860fb95c29a94dc5b204717cfc55aa1c31127f5932d6b9730a9d0d18843981817b12fe95ff97114469c4b9518755731bf4dbd88f38a30314d3572225f6ca42e1c708a3889d1df52e9eddfb031a32311e7f7b1a0273376f13d441c421e6fcbcc7e9f3b15163a0e71feaa9535b9ab4a491be2984d988ab11e5a5a4b4ee828c4d144cce8a34f2f745236d2123a0871fe92c9f466bcc811d3a60b1d8338ee05d9aa624a759cd008e2fc69bad56f696b260ec47944ddb2bc895ee800c47936c5e7c858b5ec2b0a1d7f38cee54cea299b846e976fe428c1f998f191c3868d0afc1621b8f11148fc57dce022024af4d0e18793bb6f0a61a1324a56169021e306175ca009d27f77f4e1a077c44aca52a3454c7c38e5eaaa3c2aaadb947c0fe73c151725a63e514d8ee074e8e1a454acda18d5b4e593c9c3c957349366381b35193c9c2cc55b49bee81d0ea35637779ad468c60e47135a2d454cc973dfacc3b1728890820a173a1cacd298ba1435ef2599c371f625eba6b92829dadfb06159e890c349347acfeda91a11b538681b4995b5e90a0ee7bef7caa332416732bde11813c3669dd8a6abbc1b4e9b2f840e9544ca8a95c5151f34acb4e1a0445c1c13ba345a92b3e1bca7e74d677e0da7645a1b624a133fb71a8ea3446398c592b0164ac341c6c9a4d46caafc7ba3e1a8b5f9efdc64af8658061a0db3eb38c3215fa5d6241ab5ebc21d66385fcbc4149694f41172194e69c25ebf566234cc28a2830c47d98ed39ab7ddba3763386e88314ad26ec4702cefed48aa52674a360c873d8f6093cf7f33ad6038a972bf0caad42f1c278bcc90cf37355ad40be750936d215e94a851bbf0c5bbe9cdff92960d7470e1683ba6f59362082d972d9c3e4bac8a522a36c7440ba7140b136df375cf255938a94c1b84668d60e1209216e1e67e622c835738d68f0ccf542366295ae1ac312bdbac99f8e6b00aadf59ba4af8bab630dfdc8e20a2f70987650e1a041c6c6929762a59ec24934259ac8d923437b5238bfb589c94ba579f451385e6fcf5a5c9c95170a07bfb093dd5f31a0e30995bc0ca7a76571e38f191f3264e0c861630b1c5b870e279cb4c94b9bb4f5f2437c3a9a70b4131b359923d4cd4c388750692bae4974886509073fa54dac970a426e5009a7f0aa15dde49ea64ec2a926799bb0b5cc52de133a9070b40a2a4919113ec2d144662f17e1d6b1970930a1c308c730951d1a4246091d4538bfc66d536d9d6ff2255ce82082a2eff296502a47a476e818c241d89f9a51cb5359f7113a84702a51d33241565d7077c6474de063c64749e063c64761f131e3a322f031e3a3aef898f15110f898f1510ff898c0151f6ee808c2f154239dc58d191d403897a891652b412925b316f8985103073760cf0be6020d161ca0e1808e1f9c2fea294d2762941dbf865ae6a1c307e70849a208a01102c4bdc5169c6430eae8c151c279af5c467bdf041f021a38de6d74a1f7850464c8a881831b500307d7b8e28ad7e2461657c89071e365c868d74774f0007926b3e7b58c080e3a7670de903535368514db3f2db8d0e28a8f191f58d498f1376ce4b040123a74700c37a633ae26639e59430d87163264e0c0f137f2068d2d3870a4a02307075da5a9777295265836860e1c1c766c7d53c9480d35bb0b74dce0f81b36c38990a2e9d372a0c30687d45f15825c10bae1770570f1b1800a7cd8a0a306a7ab79b11629136dff1a6a67775774d0e014e76cd2bac6cd7eda7761c3ee011d33386b0cf18da7b5c64cc6043772acda62c1011a05e890c1e15bde42bc2077ee26171f5930e00301bec516cc850564c8409342470c4e4ac577f3957c04db0fa1d00183a35c9ee02ad9572ea88968e878c12158058d5177c1d0e18293340b218feecab030de163a5a707a11f194fe45cb2aedc70c1ad6c182a39c1c25f267f22f1f59306089e961c1011a00f8028c551c54e90d1af77fa523a98002ae00431567977c714b49f8df2ca9a15664c830978af3bb66d9d3a8da692d0dd6e3dfc507b4b0c01460a0e2706f2959b890358ba41463028c539c4ae8d3b9fc9772c85843ad468ed7c483618a8358962057a11cc113d6820b1b5d98600b1b13f85fc01e0e122c004629ce6f695a16b63552fc3880418a83dee58929a55c21867514a7b0cc25e36ce4964b860c18a238869cd877abc965e32b0618a1f0b7bb5e94bd4d8cd601800f304071f64ce51ae96e6d9ee826fc34e58815ceada5ee728cc7d90a062baa7098a0823e21226aa34e54384c904164a63f8563502337559221242197c2b966df4f5585f44a3272c18a289c548c94444b432a7d3e140eff2f1b54fa3671a57cc259c447c8b1d558fba1134efa679b2e29d56dc18a261c2f4553d2164bc4fa13138e998297ccb6ef124ed6ebebd737a3c4460907514b5d8ba6e2f7c30482154938f9a83497dda02a79e31c36b2f898f1b1c5169c45de07bad022878d11d0e080154838e64852d226c65757c88d1c6507818f191f96052b8e80bc4d61923c5beb3e19a19558df6649ab4a3615218db027aac1b4f29a88f0a9c81cfffb10b014639824b5617121741669e28f8290c30a20a0b343c6483d7957463f682c93d0923399423e20f9c93c57cb92e11e5821744e489c7097632b7890c64ca916e31d98214ce5e7629f90191d9865f36a5836d3a4cdc197ebfd4bce5f650907e88a2e9b221e129237289245d1fcddf669411b64ca6a2c5b9cdca15403448a4c7154478364d613aace5f53b5e70547206d8bfec28697e9c08a191c83e6bf785142a77721e01ce4bff898f1f131c30437fe0b0a7cccf8f898f1618287c0c78c8f1b6feb0573813cb04206479f24ab59b1ac54750678c15ca0e981153138e5dba6a99353e9fa0483b3241133e69674d22afc8253d4d37b199171c129939a4ada33a4056795e09af6da324c6756b0e05c95dafa2fb6600c5c0362ace2e0162b857c21aa388fe6f0dd48c137bc948a83e5d0dd8b7f1911a2a8387758f6b828d974c4f114e7bcdc90bf2bdece2586298eb6224348a737fe09efbd6c01314a71144d1935645d4c95f518a438583c4d5f27770d352f6cdc701a26b891634d70230b1932100e2db84029c418c529c689ea1bdf92ee21238a9354c97fdba74ef67f1fc408c5f96408bde312725c3441714a273625c8abb00a8b7ee2f026aec637a98c295c3c71d4786eebea75e2a445488b91edf5ca7e4e1cb45a8590f5bc4b6acc12626ce2f8397ace267c5cb818690009313471baff1131057595a26a35d4d6beb92d1347cd9c9adae12237885ae0b031014c9ca4a518df228d984a290e70c0071e0b193270c890610224e307312e71941417c9eab45eb610201b5b74d1420c4b9c5e53f6896c4159e8bc1287a4f26bf4ff579a184484189438bc858a2761ec7655d7102fcdee122f44964dd9db5da4b983189238ea8c0ec96f298798192312c749729bda967d279864c880c4c125e88a215974495a7cc429dcf574369bda6ff46f10bb2286238efa36226ca765dc383f2046234efb12b4bad268488d33e29054d7cf4e6e10255e193264c8b8e26306161ca0b182188b38c574ded9e75a3971451c459a49bf6497428e2811c92c1b53d64dea45c459f7729b88f425b2ca87385784bbb4d61ae2907db646e8370b71cc663f4ae556aab610421ca36b8fcefdcd6ca70de220ff82b03d75d9622909e26892d62456967511fa409c47ad2ccbdaa9f4a705c449ac2c25e50cdbadf20f0719b7fb46e8ceac4cf1c361a4e9510fb16261efc34154a40b3973c1e7267c3879a89d5851db12c37b38c4f63719412ef86ff470aa2c2a365c7526c42c0f07192c5f52722f3c1c4ec8d55032bc7e43bec3f9fd5cacc3e254cc163b9ca49d963e13ab21ed8828885187f3c92442a4905b0e2dbaf8020327884187a35a4811ba4a755fc498c3295b9814ad2968d3a395833331e28fc9ac89c36135f4c550a752de6882c3f9d2649c1426415ca76f38e8dc2842e978982c951b8e6159e5f52ae7662578ef420b19327060c1011a3662b481547fb59f25dbb3e13a39d714ee23e2a8d780ce1b512fd5809b927759624b8ca14b037ba2aebb64558c1442c339e389d8956d1a12c2831867386fd2faf6b33166388d58b2b44c7941db329cbd7a4ef7b48b418693c509b3fb4ceb91ff319c326ccae7edc9d3530c07292a3a9bc454743731c270c91d19fffd82c0f0755fd0a2440e7de1705daa4e466d6d1979e12483c964526643f75d3858760996b6612e9c4b56d0a095925851c9b185c36fbc9c1d3967656d2d1c34c657659066e1243be4868493c1c2219b4c7ff15ada4368ae701c931445bb4a2b9c53c2240daf334d2756e1e09e9b23a60952e11ceadb8450425febbd291c2d531022c97092c2612e5bcc33be21fdf63868c890f1ae5138255169a6bde1567d2c3840438b1850e075279ec60c91715f10f013987fddd029e9420b2e9cb06ea4788e269872ebad64aebc5b0d35e7af71966230a136537ea991d2ae1a6aec058e8db10445b25cd84dfab4a86aa8992087175c7c89c04716577c28002f957012b5385ddb2a42732909c790c91d235fada1a697430b2eb4d882468d1c5ebc27128e1ae6e4040bd1f6bb9d11e3088cca1075ad952086114e49aaa51da1496613a5229c4bfbb2e6d4d0203a12e194f46fec68fd8fb55c16c5630ce15426832ef5674ae64912c2796c4536cea659ca3d46104e624c9dde70eb225312100eb925a56d4a963295fe07071513e23f4146cb57f9e0f8223792a94bdb0aeac129a80b353b99761f2f0f4e4205953dc1de812a2ac4a09405d9a0cc1ec4d0c121aa08a11b536e9dd4e7e0a0369a5f62353838c88f535142ba32d10d4e13641257f56dbfabcb0c62d8e098c2ed051339474fd663d4e03896d2abef5757d2eaff16b0183438869aa03317f2dd583e83f37f7a8599d930aa443238f7c4519df2a3189c6265b598a59c21d5078363bafd8c4187fc82b3a49c7f12f33c56171c7305bd0dca92dbbf18a305879467d258b0a83b293158704cd617f4428fab385f5a50a32396103231aa38994bb4794915e2f24ec549e84e102b7751711425ba6d3dd7531c92eabdad8b144648d21407152f987b04ddfa3296e2d421329c503d8d8da22f48710ed3e2f59142f56946719e1421a5944b76a31d8ae2d8be3e7b21188a83525aedcba4a4a83683e22cf2a33a8229adf43e7152a546a45bb798ac7bc0c313c7922b32da27892d912443864727ce73c9de4e2d7325536ec1818386a1771b33b6e0b080c9bfa1587080c6013c38711217597d3345ddb0f526ce21642a1322ef85cc4e13e70c97a99d1f7ea5f732038f4c9c73b643fb2893e4b261e274327d9a9a578b9fb14b1c8498d3741e9aa747b3c4c1629e8d10a3335656e2e027bfb3976a76bb428943ae8ae152cda5332771debcbc41a9fcd520a287240eeb23aaffe2898a9d08de02eb118993122aab48d09b279ebc0c078e4708015e70040c24ce27216e3293652535a8863ee22442a83d11edb327a478510f479c32c4525518690d35921e8d382459618410f71edee6178c38c637136abccee543a7c1c5223a194a735393dfa988c365f4892198897b7ef87ec523111e88f03844d225ba991296459521630b8e36c4c9beb54d89101f29a385385e85cc5952b110e24888639824bcfc358338243913122fe404e111886390674282d99aec9e64f131e3e3021f13b8e2c3031007a1920c1593429031d713b8e2c3e30f7bdd5c4d1c597aaf871f0c42344e6ee632a5217d386528b770fa848548c0830f8d5051cde343c5bcd2630fb5c5a66fd7b518f5f0f7c99341847b9ba0ba3ca86615453777c6743df0708773a6747131da7ec898d750b304dc35c0c30e87eb133da24397a60d9a79d4e1945962da925bdf6d7e036c6421434609be068d0f2f5f7cec171f5dbe3014f0a0c37934a9d89325c489f8e7707851a144c4fcad92457238ce56f28b5113a75e138783ba4ade251a389c9418cb15f632c92df30d6713f23fd7117465d60d4791a15e6445ecbfd886f3a548bb0c3961ae2b6c388f684cba1d0a402040160e415e99a639b99a82b0700cd771d715bac2b9f572c83c42d2c58d158e26729e17db646ab50aa7b0ed12a236d829930a27911dba3189f3b6e44de1a0c4f7ede6eea4706acfb01941478418bb289c35b3e35fddf3f20405c3bd65fab553aa80004f38069df6db97bb36424e385d50beaaf15fc1454d385f703f3713a6d2cc4c3858252fbfd494216596706e3b0b2a5b259c82da7e8a3cbbcc3409a7eaac4d966e4b7d24a82641e9d095239cf2f547a6a0b32d4233c231ae9588cc6317f4b2221834668f20e26ac95c0d9df171e80e4873040188702e65f2bc4f96943d0de1341733a6a4bd422a5f08af768c5b8a93fa17c681800facddc8e105003e4180201c5c82d0d29c03e1242385c6ae491235f483936aff9514969b2eea8383a59862a788580f0e26d42f2d24a931e5a9061008c083d3e40b937d839b66f67770d24ca52bf2d4c129fae4d199effcd4f939385e586568e91399e3e3e05c314c6676c4a99e6e7032e996c93d34e9736d708829a5d998b306c7e0ef63c2d2ca29d16970de90296d082f99c171aef24de58564700ce2cc542add8ce4770c4e33c15e4d3dd4a86cc3e014847cdea697186212bfe019cb681155171cd3c9184959d80a13710b4e21a99ee50b255ae44b00169c3cf4bfa664372f395dc551eb6c738b4aad13a48af328a5952b4890396fa6e26076797276acc7c9a0e2ac3549659fe40b1a2da738f8a9d5202aa864fa35c531e4b90ddfaf77df95e2f4e223c9b25f525e8414c714b3289594b8b875ba519c2f8e4db83ca7c25213c531838f8c1cdf97b22514279710e3a8b2d92fab7c3000501c53fcb9ddbad9a429f989c3cc89c8eabfe0f0c4412911da3aecc47964636269881387499b33ab6bd2268e3116dd6c8297c865d2c43944367d260ed252c8a1b4d4d3d7c7c4295bf5fe7a84a462f99738467ad5baf491f42d6f89e397cbfad76f48d2f295388574ddf4912a74da4e89d36a6668ff2ac99bf4499c75476e5b3049e29c67f2b52f7d479e237112ffaebefc69c15b481ca45e67987871b2d4479c524cbe7f964bb78638e268da726ea5a1469cece47a8c568811e74b2e2792d266a46911871141fc3745844c157152639ba75e464f851271b4145126376bfbdf883804a16d95bece62ca218e1e4a29b56d9762c418e264329e5ac9de18922bc4795344e267d68468b3f2b7e48df020ce2229bb4bd68d200e26834fdeefd21c6913889334bbdcca7db27b630071526a7f6232b4655ecd1f4e2b1629ac23dccec4f8e19c973ee22d8dcadf993e1caf47c9598d193e1c920a773a520ced73dac3e9e2cba58c889239e9e17c152cee324c65caf370d26ed75a4153cc20e3e13c399455d2a941c8f70e87fc954296e9d72ceedae1a4a96eb4869716ab6c1d0e5f363f2b527fe2b77438c87c5149c8a614e4b673384d5ab5bc5e4185d5e57092225267d8e3704a09a32496b0701b048783c5b49c60296648e1371ce4a89ecaa152248dbae17cb3d1e2ccd4361c368892bdc8291b4eb729fca436f96791359c4289ac985d8494b654c3419205e16e266641290dc7389564aa90454fdad170d0204744b6cb1bfe198e1a93069933c80ca748226f440d97321ced5bd5c42493a021850ca79b5197936d545aaa8ce12443aa09975511c3a96e75b229f195d387e1b0de953ed297901243c07010137db38e26d538c9170e9b4d9fca9ab4a0712f1c564f34a4959c97f22e9cb27c5e5e621c59e2c2a944e5d37095a2e9164e5669639f58c654222d1c4cb575690b65e120367be44dcd9a62838573678998d0e9150e7bfa2c8ce8c90ac7b4aba65c92a5881856e16476a5e57ba7c2b94e538a20eb6ac6bc291c2f69dfa0662eea962785d38b56ac13b9454cc845e11893aae8fed17faf43e1d4611631abeb89193de1f01abc9234d79c70526f1617f97337566bc221c811f55a1582e88931e1781a6b6aa4664b38dacde8987c9b21f94a3879cac9b4add134879270d2376d5947e9503946c2a9ae45ee7fe9bbdaea08a74c9b67dd2229a9a76484d3a9dd0ab2952fc2513769d8b86fb1c974221cc2c60c2afbe843388f7b5e9cc916a42809e19482124994d21873ce0ec22989346a379899be080807eb114189b7fc83c3a5a0525710611f9cd4de98fbc6104facdb8343da1d4d69920c994cc283e3fe8b1255896695d31d9c2fbb05e556afdd1ad1c149b3e9db789a8c859883735eec1273a15e41e97070109ff9332a96f7896f70b25ac91b577923656483836a3999746e08ea25050803a8c131ca84582ddaf49f667a30001a9caa2da56ce608a536333805e9116287a4cddc1a13062083535a4b2204a59268cd1f8393081f95545c8d1b71048383c85b6d4abd864818c00b0e2944e508a7368d3ea501b8e018d297efc5ac2e3ffa01b4e0245a46680b25739ff807c08283accad817b2056deeafe260dd9f5695aee5d657c5612d8638499e9e8a734bf6cd27c442ec1242c5d994882849524abc1d9de2a472e694cda4442e1999e2a02fc6596f9858dda0521c75efce4b868b902722c5694c3cc382d6a3389ff6bfa64ebafb0d8be258bb69577ef396f04c284e722932ed7f5d88a605c5c17bd29a94249276de4f9c3647ac58c5522966eb89a35766171311edc4a94aebee5bb48e9c1327ad4a9be426b334a74d9c6293aa8ca01ac5d4c4f9ea4e85b03a13e79ea44a88de0d268eb1c9b37fc3bcc4c9747556e957ca362a9638843121d66a1b73a4a512a7d8582584aef85fb050e2742a448c91567754582671fe535632c8587e32552471d80c32a61c3e89c471efcae2ce4e927b219038a890252fb2f65b04e1234e99f735ea255a36253ae274f325e35509f11bb11107f5d297cf0e19719898912ac435d7b42ee2b4692e481d2b8dd9a288c3e6492a89dd505edd25e26c1da9cbc3bd235881885312baed7f54e910c7cc193f21a5185eb5210ea3db5204b529c4b9f2f859725115527b429c5236df19d56c7ab23d8884faae6c29fe268873462da5ad0cc449fa5fec05b990646e0171ba517f3f937e3df2fdc3796382fc16137b2ac90fa72e8b5f2797a52a53fa708c90d344d67d496b1a1f4e31294c8934f98bfd1e4e32da9908229e157a30f8846427538a4fbaf3d05c690916c6c594783095bcd1bd133695ee70d438579bbcb42aea6f07d484cc2eab212eaac3e14fd296ccc576a90c1dcc942b2e748e733849ebbb9231c44e14570e9ed8eb3d91b1445ec88a381c937785d0a52386a42afb2d9a6f7c0e071831580187c377b756924fd3ccf00d27b1759af46a379cdde6a46ff08c3b596bc3f9f26a99904165c34149ee95604ab3dd660da7245d8266d1b170991a4ea1213c84b62babd2a4e19032882bddb04f8d2d1a8e7ea78450e7259489cf705095d23fb2ddd8298f0a5698e1147a2d7268e6489d4ac18a321c279fde88c41039494c8683256951824b8a79cf8ce1dcdf33326917b14c59311c47f9a8287b1b5632250ce7de8f1d93ba11f3236038c88b3b721e4ad5462e0a567ce1142cb8c698345e38a6ccb10c415e10aa7117ce7726df72da890bc70b15dfcf50a3216fe1a441997a8bae9c31532d1c25baa81865c45cc4250b674b9aea279c25cbea62e1b47d4246d35a5de1048a7da8c4ed0503c248241487030251201406a071a600631408001828248d0663f1681c46c21f1400035532263a322c161a1c12121410108a03c14010100c8bc26040281408050220a158708c23d1f007847dba4834dd96206082be846a04161d2c8fef3dbd4d033507082790a38c201019fef948e867f8499c3f26e558eea95539d24fc7d646c27e09d412983661790432923c2dc12a024e850d2673165f2884998441ca06190047fd3e798a239f72f9f7e44734056563b43db2cd2ca1d65799e832ee56eefb4901ece6af072484753162ea4e3147c2ef08c246980ff51b5d6d9d6c4590822ce9d9192dfd596f70c2c4b8de089751e7d76d1725858f9e53bd4a87e8e83c74d7b637f35fdc01368c6eca77aa4907de187491437042e909ff36c2e6c98d989d7ed5506ff6dddbefb6ab3902f11a283cea273011187940a3e012085e70f6910592088817810c4a5ded280e6c817959e158a0594045c08081e2d5fbf683dd2027201d9060004a90c5c03e41e4018405e009e002670164030725c84c4980ebe1caf780c0d73f9d0eaa78506320764f6b1217609220379f890db420d715a61ea08c011640b93d0d29854d2f80820016007a80770013007d1ec00e3b39b9611bf8310061a06080e005305221f98228035619ccc5686cc0d202bc0a2a0d1c0b102af867203903984e208ddd2100e6539e178b4080c0b0df682e178017400168073801c8af006a8e1d7676e200eb03b6075a0d9034c027400370012005f82920290357b6bc3794e1027a03ec0720cf0086dbfa08c7151018b08379770e40168012107fe0b940aa0b3005b2cb573503c2081fd88f011400f6660050adc690843920bf401d00da00b203a008ac1240293809032d9153420536000a0318e39cac6f36065a3c826ada004d1b10188052407501e000f9007003d00d204c40d8dd59ea15809f00af47c015d5fd2f8b06681db032908a00a69c00a4af118f25373790a37818cdc7a4db03f320f97107c2e22349434eb044873acc1fef47da7dddcb83e041711e84920360e1ecb1ec81301fa7aa41d83069b01181deead7cc0fef3cd6e7d0092f6090d3f27e375b01cb2c4ce6c5486bdb8d91757d1f98253014b6360135714da0521cc08adec6a3b6d9a0c0a480a758a310a4687314bd918ebfac90a24f214d814c318cc2cc2bfe94be27535a14fa32ae59583686081e60a56ef64284fe4b3e7114bd6124f36623052385491180628722bb293c4ed94c9d9bc241814e114241ab28fe24190b9dc28ae40b458b83a6108dd7ccdfd428fac206bcf81b714f9f7c013914316d133d243feb214d4249089089081c060c4b09904f68e5d0089ab9fab945254087809862ad68e06f84ea8b5e75db2aed8310609b36c965b5a3b8beaeafa9e46024863d7bd88517329ff0534a80ae81a8616900e3fcc10990ac16e42003167837d3b2b21f2c4f42d9b5510477682942e3d5b0e5068d0973d70b38bb82c0924408fffae4c0c5b064ef78174bf2013a9528783fed9b110033d7193e6d1b6584eb72f7892b7111f551c1155aebd8c478c0b7d3bfbca8bb6e7e05f38a2f8cb1178ead0878891d7911f212a11db3d2c433270e6a976b2f5e615e30818ff4acc2646a3f0d7f9b16e75078502a2857140a5058e2f5e306e162ceb5d3d9a491e58c10fc8b2196b607601d8fe4a5d1eeaa113a1bce2501a49fc43ab0900a02405c708c76dc9e5e0a01aff92e56f46224899fb5408942609a9fae403708428311b6efe48b31c573c6e3e41e1b1c474f19774b18bfe2d4a462106a0e0d7c20c4d9cfa1fd5327d52bf1a52459253c71ec75db710cd31103884cb7080b13bbe5a5914d73a3d3768b7b489607bc47008b377c918c2496b778e9357516d720ada64e11f3f15b1c9ce923cbca1a0c4a83a60111113f72a55c9ae98aaec73137a5975c15c6fec86b0354371f3074a5e73b8c5968b8304bb14d841abd6b933b5c545d5e9b4d67083836d94cf932f8acdd72b9ee77dce37c27d980eb040c3bb3c3565ad2a20e207e49fccc9fb862b26385750d82e857461f06e4043f039cd1424c8fcba17408132a369ced90c25eae8b1c95730b7e6348b2b100da71dfaca0d19593cca72380eadf381bfce80e76eba1378c8594cb0a4714de6d5a5e6cc464e3c4fe0375844508a5b2e1cc91d395b4c2ed2c9a911f939fe5498827932983fd9c3ed86a90805def7426caa232b4b4a5d1f7e9ccc63b33bbe15377cb047a3b74fde2a7df74e6b36f9a069803ae439cb65b5af50b3c62d8a557e33a9c0772fbccd4b2f80135e4ddca2cba8c256c431451e6ccb1f8bcc56deb6fab1bdcd6dfed006907bad0d26cd0f799bc0b27b6746d31d7b422accd7f288ca13897f15aa628e9e430832d16b4c4472d9101b6975de840b35cc7ad8c22ec43862b061bbbccc4c34de4062b431e9f223d9de6f80c7a244a5d0a1a9a58197c1bb401302417bb46a30b267c71e76388ec274be8d5a316a420384c34eb5a881197e004d44704b27af5f6d2700da618a4701b63eac61594ce4a4ff3020771cacf0602522e5a5cd5bf7b18efc4e4fd42135d8383b62835aef13320d121c82f1630f0da01c84588caf3090e1171a70e02637324be16e1457bb8c88a81f7825c71fec462c0f1b900385a3219c4af3722c9f8efa2b55edab2b29688ccc0ebcda887229a3a7ce0592e760c4f0c9360621a0a8b6f7131835db947f4004095f86b87c326d054e10a54f608ed3993eef43e169baf188b2fe4f3ac02cb10ce350ae06e8ea2e4169ae5b506ab3a21a298f2058467a9601c206951fc9b035513cb51d33e96e24f2af51e8e250e4061ad00f2dcc858f7a3b838e6d01cc16c21b80ba6f3db58c1baf9967796d0582bf83b3d930b70286c9e063aeb8362ca57c01c196dcdc2cda5f347f83c8cb8e527c81196c95cc69d8dcc9a6675635b6e21b8d1b64bbeddb84c8e75388e24a801b20eccd97c3b4bb7042c14a43a7e6200606c73dc2809571c0021ab0a14a8b9817a9dea734ea58bda00939224537589acccd48630f73c7cfc28ed1ad8b82aeebe01c76c7269907f22173bcb3af6a4fae7c46ac5049ad8a7fd2a5659443b9a6bcf6fc2cd202c28cefa0cb615e15720e36bd7068f31d95b5251dde77cd29ec5626e9e68332d9b087c2e2d19aeccd6a2a2590cef301802e2361b6392f8304400614da68014ec4de0f4050e7d93c630bf4803e3a10dc6743d83e539b92c32f3c2a2b078a37afbae9568b0f4ce6380a8e732b822b98ea928778ecfe1d57a69dd985e69f508c67bca385f979a1ac215f2ffa2f437a04a7f74180de147b3f0dc82316091e7c40e967b241f8c0c28a857b9d7b118c99742802a3d497b3f342e4b3f6df239509e454b20efc898a4a614b54b085d2ad23518a203495a03c32092973ea1a037c2917400cd783c8ef879bb6c9d8577d2035002ce311039c6639e4e511387ec51470327021d0e4f772299b1da8383e7f6f2cf5f7b8459311449b210a311f0dc261c1c895b86c45bec40dd3bacb812537d4b31dfda5bef7fd427e760fcc86c5a3bc8c65f43d885b733cabc220f25e754e3977201858ee70caf024d4145b320fa82d6bfd8193f64aa0d112de4883e13c247fd7171f1046a37ef28d23d699511b636dc624e6e65730025598ea825bf3afae4bc0f8ac502da330ba139abbf1349dbb1b42a49eb590ebc07906401af02cbc8cca9f7ec2a24fce99880549003480a060a1098d04e2cc9a5e423428fe4abab24d319115ec3ffdf5b75e35455865655ed6ec4b734f463f3360d36bfff312715e8926bfc05d89099103bfc2c838ce483a1f179a95671106bf4c0e53331c5d0683ecb7e04879399c0ecedae27636a9130817f930f12dff03256cc3e750cc4e519143fd7e5050d611756e74dd0a4a7754ee03100abe2f71b5a9c7bd697609eba2362ca194cae3fa9781ca1254bfcd0897bca290045fe77e0d359d6289f61fc7d9d020e0065697c86701e6eab925d9c5821e3bb8d98e90ac9217df0f155aa3069cb91b17264d481b55e2f774330716bdc3f9b0c4497e7a5b3640667dc80cb349dac06636116ec1945d09a2bcb83fea8ad042a168ca7432fa6d0ec72299e382d0911113d9e3956046e7f79f232929e8a7393da1d5de568e845893cf51b3a3813eccd2276d491fb57b8aa909bd5e60f2dcdf34582331c43080b6affabe0beb78466d199e64159524a54448ef5d966c67cff52b47d0508d1c6e15f18b21da0ad1a505197ebd119e255ae9795b8e535156ef8670d1b177f9145dd3d457a0f833ae130f1c8fab9d3962b463d2fcecf29d8a390caeb6883b995275215dda32e7b748600b997aee62c8000bad3267ee0084f16b4e11278f447d6def22098153df517143d192d12cab0697e72a0f5b6f5a4a46db399c6424681fb080a92c27e2c870eb2f00d5b605e125aa3d41da28940042d6c783742f04a80ef7dd2eaeefa88422f6ff968a757d28480805ed0f6ca7a0a8f4cf12c4b083dfda03e46b96a5fa1b511ff5fe6a00265a6306f762a66490f38f5bc819977b8e387bd33dffe48aec2fdbb869275e9ce25f32965e6d07a68bb654d088e60de38e1f4f760c45524adf2eb2ffe279b1be2c0ab614fce0995ddb4f1e66f4be2127778df03640332d92fb2599712bd960ec04eb1014264e10f1a3b4d6611a2a3a6b238848f872491e40533d8a5c01b5bb8b99580fab7c6aaccf989f43356ee4bb82ad5cb4454dd466a74adae9010ad994f187cee4ab15660e027cfedfef1dfe7fdf034d4953c61aee9ff7c5a36739034fd7f6991864aef9c2d2ca16074b7e989c29e7046c04757444d3f86f4ea42954814d690f45b06deb962b6e1f8b5b26ba819350e3a4b36588910ca01541061295303769a195d7a0d4ba4379ccc61f31199b82909cf516a62e2f0f6ed7b48f9d232b1fd70bddc36520eaed8116b509920666a0d72b917c74b5fece793c949f3a8628e117bfc40fee3ce4114259870cd6436f049cc8e44c2963897f92f01839c98f7029d0ae5b9a908f00de3ebe885f23bb341cd1e118a0881d664a67439a8be538a269cd0e9ee0db247db7a330107a58cf2bacac673a0c1923cdb4e9efc06d5e216d7e8bc95a29414155ee49ff1b8b33f4b4bfca16cc3d4914082c9506af6a28bc373ccb2b37bc4cd0d231a7453288556a8aff5efcfa173b289c2d6b48a7e7b879430147401704491126222029f938e30b142b249eb40588ef4b8c2e558869b2b96d7f3d103b4bd547d6f151ffd37cd47a7d945c8484bf150ccb32d300f69d9c8105e362e0125bf1267a00adcf5fcf954c6e106e5c8125f63a7f6170f812b4c8de7e3fd9135ab6aa2703eae49e00c28471f0c54212ad72ca98a71f16ec4e03e269049021a07b202faaa7f78776407e0c13db436266c3591787329c01cd8fe59b3f319021e28be96e5db126e1127c7407dc47250b2f4661fd723d46d6b0b7864d889c3965f6bc8b3b0ed65a59515c6b7e0364c4e117bbfde2c7ca977dc9163643c9d66cc836d1ffbacc5eb398b1df47223b1164e89c9e33ab33a14d58becdd4d7bd6252190b8bfbd6ab7b66322028b2cc56c18f7646bb77266edfeb2d3629842cde9dc980ddc0fd55512dc5acaea0e9b4be0e8610f3f1d789f0b770872e7f2e0b12d1817aebc7fe3bba51dbd7c7cb489e598aabb13716e36fceb055796a42c88d9e00809861b6540dfd236f20a98d89c46a46abe711efb11177e7b75eb5cd24647ef85799b8b4814e583b85436f2e037f4b565054e2b6cb5b29b1ba8627e8ee5963b02a4b9425b0d94be6c15548125aabb8613ffe533f12ceca01301bf89bb1adec531bc610bad9a8e9c8b546a1949faaf29926302b59804343c4bde249aecdbb029f09ac7167c7472c02116d33f43036aab075937bb742412192b8fde2200920f8e91a859c6cffd4a510b2c4b4971e59d049ed492496bcc0b72dec80593c7a2d40cd4644a04c54f77cc484a32a864e436262cc189ac4466f77252016332af23cc2bf3fc32623612cc52e1502ee3f96f28b77be49ec0cda786874503d87f0911c478d33cb67c02a3841b1fe0bce80cde7454a4b5d0e1126060079f27a2fb05d55ef5b183d45bb2ed015f4083dc4457cb4c698fc2625aadf46db28c21cc6261b33182ba99ceea5189c6c576855bc7ae015164b50c1b1da74e15d05bb2c32248202bc1290b79cf033d713110f46ca252818cc91e09295cffc5251bb94659143e981b0677761e64d25463189249b9c150397412832de2d70a5cb9b294681c54a1380395fcc9be04790a741ea01a12f87a3b5a1afa9f307a94a08fa04a2563bce9dc540a406ab760e0029138659c76278248408ea6f656260e09639e103895ebb2152b1cf929b67addc50fc22b56002a65ec74eb9c4e5578ed1444570f4e0826473683380cb80258edd9cccc07cbe9e3693003f308bdce46a1da3cef4239d068bc26eeb3cd5d1a6107cb30e10ecca731116e0918d8b6aac15c25c2b96fc394d98ec16ca3cf48a15d5a88a437ec14b5aa76d57b0ef02a47ac8ec40d1d0be1d5d130510122257e4cec22119f009348ac679e3943034902b7965cf70d56d9ee7080aeab50d03fc04156d248b548daaa26049b94ede1f53c06bd4a235071eebc4751ef46e757b424d3732cfb087322936bc1fd5db9fc13769e8d2baece84cbae55505db0f410bcf8fea91b4ce0e094060280ad7abae2746330850d544c2f46f4c9a045bdc444103aa41102ba31acc6704fd6546ac0b707c5abdb82155f8cbc479b59aeb53b47a92a6a518399be85f8eb518c94b76ebf4756ca342a03ed9502e60227c02720ddf715d3f27d849c8fa510740cb32ec2a767d57cc7b21bd7f9e9ca78212acf2eaa9e31b3b808f043f6f42b47309fb21dbd87955122ed90b310e62c946a9632a53fb1f9bc2f7e4c10bac40e31f87f1ee1d1ccb39555092e1ff82ae164c60baf30533f77d13066f0ad4439ec5ade2d5e990109add165a455d365251be84b72a9c214a2aa90f7eb09883988c5143decd144498089abfba8d9a15c2fb0d6c1693294d902b99d08b3529fb0723c727fd89e36c47705514b486ee7ab68c4d0945951d2e10b198ccde3f6a276ed8f1dad814f1b1d6a8e3c0f7a0b19bb744de09eb9406d48d319a1c6e70fe6e0df1e041834617dcd49f80fc2ce23835b4f06956e25ea99ae2518c6fbaa80514451968447ec4a6a1e9cc93ea9c22391aa5ea3a2d16537313303adee96fa0f573851ebde45c1aea8bb285e4657e8e1297afd80912feac10eabac22a3c3291c80f6478a08a1a2892258af75ea3ba8c50b70a98f3d9c64adf6a2632471176e99e7e68e5a6aafb7bd354097b7e942a86df34a3ac4fbd28d1625b1844991a6dd3ccda080ce04090ebea9911851987cc5bef050bbace747ec36c661cd29e1a11df12aadeaf8a397b1baaa480122cd202c6252713345996e646ec354837a98d462b53076433aca6c3fe5a6753b365e8cc85de0f22d0459271ea7734a6fea0af6b898e39587c6a2acacecc0c8231e978407a728f95bfe6c3c29e7049570d05d6cba1aa295b471b59361233ce86ed08fbc9bebcc852173931cce92c81cab80a1c0fbb67c654d39be57f2eef1d6f6fd2eba2f7f5cdc72800db38451d02c835675cb2ae7440518d28b8a32594822945c66a21afc47a1443299b7500c9ecea5bf4b971ea7ef17c000cda4bb316e6697e11ac58c69b032c673cbc7044111769a04db4dbad48e2cd145de2bd3a8dd0ce316c3b8d4554586f7210557862acfb745aa2e8c1029b28973d19742e40cc66293430f44d8cb026c4b0b8192af1eb08d256365922320521296b82239e8966969921e1b1268dcb8726d0d4b92ddd3ec79fa97081b705ca6b7117d533a2c87955f43df43551854cd8b7b69b40506070758d5a06471d1f2291c8af9f36de2580c5e7bee539130cd586b36c8338e85c44057e5607a9dc1f906188002124c0a19fbd4c98ab47b8d88efe4814dbae56812352fe145d3e2811c0c3aad7014309eb8cde3bb1ef7267f65152ae1903ba7d1a5144b550437692ed2232dd48dde0964d8d452fdc6f8e34889b7738712f094d8d1dc00180524ed83c1d7c10a8451e24863fba259a16b1c0b3db04992053df73f2a9a97eeadb0d076f7dd6d9da08367420de842d0b48691a0640799898ff42ad53aa187f974468e73513c33e7a34e267bbcfebe7fbd2fe632eee660b1f716724a792b1b0416ae17f3ff7ed3bd6f5d19b280a646ddcf313ade2732ed59a1e4ab8b059cd955da2331ca8d57802c973761b1c79f9bceec5fc67750a9c93025f4a0906a534c09a3bd9154f2855cf677d2601bf82ec9c8a16340bcd8f7b9419daec67a58a9a04957283d62ed69a686e13ad78b1b032484e19251d53473178ed42bb8a88af1677efaef4416da218070af16d9e56cb7e2dd282c15593d813808bb39e42aa96ccc482f7a27b6fab1553c861bbdb12bd47aec90e0ae70c511e642dc48952c568603f9aae414f95d3f2d9fdfedd7ce651a38b45baf5e880d8db75867f6da2f3185d7ce39af99e2fbac6470ff1227f3720042f116f6733dc87a6f0a6e5b65703d72e997f87dd8126d1469f6eb344de11edfb7c25f35645c0acf0c1bf52fd4e09a3b1725cf44a79a9092031357983e514649e22e092aa252dc52be91098e4fc5742310be83650a4a81f108d9c2b2853a4f6787019ae68c47f9f046c453034efb04d2e527c41febe11c3fc16113d4a7ee87a6ded5c850e3e2154c6e528a3684c6a7c067fb6e237a53901a51c1dc89c4ecabe61279acc4bdf803a6206c3995710787c72462520e092312ca11978e213441b0b63e4e085631102cddfe368a85073e702181f4185df956db3dd8cbf1ed165ea727b48af87b017d12a2d35c8a73909a85f0ef89bbf56300b4bab2c43915fe38c1be2f476da46ee2b3e5e38ca76fdacc452d73e6bbafa9acd2fc3fc582c602356309ed6e2cff8f5547d83585cb352c751320959ad30c9e68a5c136a14ca79d59203480a93d6d0fd3ac9ef08cfad2eb6a9fbea599f33e1cec7494630ecc65094a96e46c69912f82d3f5db53c593a307f9ef2fc3c54ae2c7e344b86d2e6774d1fe974f97b6953a0da23c0c5adafcae24ba5b464711d88b8045d1af283c6c24aea6480bb0801e354d6b726d86a1588f48c7f1d6bdf08a5d489dd7b3a219b4978cd3bc654a0effaf58093438e1941965d30a6058268e414754df51ec90600c7313dae79f71627f4c44e10a6e69a053c27635258e72a93785b1a2a7a082b0a0d430e81f878081c1403e90b12035d53feb7c1a7f5f2a4e4f28a5508932d3ab5ca9659c0e8bdb7f0f511a4ba8ac40aafbd01f955e6b7e157e10eb643ccd9f1adda37232f10d2183d8f985e8a0326f034e4bdbe9443c0279670772a6d0ae4afa75ee0a852def06a68ceb40c42896749d813a7fe85334321f1c866b7bd8af0fcdea68401de51efdc67c4e24449733285b6b3e15ceffd40d2adacd187e3731966f6c412985d2408cd506de469a41933fb6a42bb7bb0ded8c6763a0e17e8c39c8cb711cf8d87aa4831cf15f796105ef37252957fccc44294d51b9c55ff2ac418707b7007bb75b64e91879ac8ffda2c75409ce485b65e02720d511c7342eb8820a71660b14c176850ef1e7495b52847814a8c3d1ce08e2d371553c739bd9cdf37d8f5b9b90c64215aade6ae35bc356b1e90a88af86224cfa911d01021915bde3b32209a31be6c19267287265a99202307331f32bda84cd934dc0ac0e0e607dc601ce31fecba873f2d66ee0fcc266f64b6982da82d35b466ec1231cba558e0525ee530a774ac15e3272a5515d0bd4a4e4f449e9af09c5b8a39292eb29a97f258bb925b1713cc179681e1f7df34db90d4e609fb39843c73282a0f0ec0a4fbde6818e1ed6f1a01fcf98f0d03be5a142693f62a52d9d87aa5e179aa36ccfccfc1e09e88b0bcd12e682713a12478d59185a8e779f86491f6574e58c2b9733638a3bd1942f94ad945dca9d65b99cdf3d47458179451988f24a9988725f4172b51184d37624d5f1afab60d16ccd05bfa32f3df26fbd433ffe5bfe64f7283b12602f189f8e448f5f8b4b8ba7c3ab85637d8650300911e92433a96b65f5c96605e81ad7c83b5aec227ab118b4b8eb889dd8d384e26e644d442d5a03d13a88dd7a23a6857251f11e3b4393e233474f8d5ccb8c660d264c730693e698ceace447cd8b571e6a341d86e9b8c04a0ce97121621e86113340be8627168660f092af8a05bb7e0be3afc49f91d02d4cdf82eb2da8cf42315a706ba1bab8305a546f638ec185dc60b09f0bd292a1d7c030e202a87af485d2c425cc32703a5a422044544b832fac7b452333e4a10790501a622997b71d7ffa929a987e403e034c1ab57b6a247d5dd27b129553b80a8ae433f0dc5777043b9712290367690e953914b35b4cd54f33878a24bf34bff0a3b39bbe463fcfa0412e025d4f295bbfb40fc0af7d284ddd81e94a2585426e1f8618018530a036e40190a25e1cbd57a1017dfa938c2ee2b2462c865217092ef761408a4d27f88ad8e55aaf295b565105b2e4ddb224706f7e56f35557a2a641b19436a9243df26b43fe2b9623c2b2275b7e0f89d9cd0bd49cadd7b3f882b4f03d2c45ce083bc8dcbc27ae3be8f7655ce5b6b3d5b6edea19cc9373c9f4b2c268fc87b351258ac77c13bfad6254407e41a0235780dd6027bfe4f6b39ea6781263f278002803aa9186774f8699b30f683fd93496046845e08faf69dc4459d23d49808328109b08012ec16e488f6c22797c439af8f62c65395d5a651b67905e988bddf3b9c7210f8c49a2b8e02d1e66214043e4db017a784f8c3b80b0a4900330f0fcc0f303cf0f3c3ff0fc009d37f1db165bdf851b8a48410aded15eab1172b9bb52ee8a283fa1d4f9398a2bb6d90128d57f72220852087b08e308e42e057a7d0ce1b323f7b0b228d047b626ce62a4d6ca4ef07c6f55c592a7308112a4be2a7fe07f3945042885be97538c17429614bab9e7cb614cf2c3a021c028d4930d923ea51c4cc649124014ca6cea9bd9345be953040284e2d85257b6c5982a03c531b9519773dafbfd4431ebcc278f8dcfb33df1860e374dd071dff23b81642cbf9917bb0927fced0f1e778ee3678537f19588888795262c8fd385943ac4904c2469abf294c7937248004ce8527a63d9a74be881997c8e9a8e2e87b825b47f9992d71829c7bc7640804a28d962e374982f22e54f09dd64c6a3d8cce9fbfa49e8e7c169ac205f1e462f09ad37cf6fe48fc3d0af4742bdbf701792e698bfe290d06388581a3b64479df923744b132c3cc8f0b03eda118a784964eca5f0f1e64668761e6c4472e8119b19a175249ac34c591ef2e54568ad215e3a8fc2a6d4b122d4ec91ed04cba61df92311fa7bdc48928cee583f10a1f9e5cf5b7b1c42abc94147cafd61b777184289de101f67f140234721749f6dcb3928cd732521948f1d4a6be642d8e00e428bec16ee71201f245710ea874f6d1ee94b749440e841238dcfe6c97ce400428f73fcf114cbc2c7fd1ff438bcc8f172dcf2713fa8615b2ede2b8773721fd4088f4ddcfb7fefe583d661436ee2e498fd1e1493b0cbd159f0fc307a503f24c9610e32824d300f6a5cc7d8f77eefcee141b7fc2083db77c79a3207cf299d54e6b083962b928cb975d03e74c2cdf774d0dae34d737acf41e9986b67c2b3859095833aed63c6416bedeaceca120e9ace5575dc298dc5fc1b947c8931793c8faf73833a9721e11f498e63db062549de10a32a987e1836681d75ac7bb1f6624e59831e2b7418a77a54c37eff6ddf9d2d69d0357e1883062597777c36e21625953368bb1d427df0e82888c40c6af230d5c6f86b4e1d298362c1e68265cc296b44c8a0febd650c5512fee36f0cca475797993e62502ae2858860f93cae5c1814b3ce8a7ba12fde3a30283985ca94dfb9dde15f5037c5d4445586e4c70b4a58e41897e93a73982e28939f3e4e7e883b122ea8b5614ae38e580e21b605a52fcc37a7c8fbf8332d68d1f144d69cc4e3b46741b7b05da31327e9c5b1a0c7978376ebafa067fe584c3ffb16b35650f3648f92eea70a6ad7e5eeac1c77bcc9a282b27d16dd79642a2635053de838ffa39c4b41f9d75021ef32de76444193caf83c613c2ccf88005050dc3cc7c977a32657f40435a6f841db84f9a033ef042d6ff4c7933c9c14c16f82126ef29f7bfdc6993c13b48b1d570a1b2c654ff712f4b0638e6cb7c30ef7d14ad03c27f7437c303a6f2741cb293f44fc2b56e73412f48ccffe1ef51114bbf459825988d79a8da048867b7c6998751c5c0425878eef74af34c23f4450339c0711e6cb27da33043507312c9e5484a04eeab03cff658e1cc60441ebd1fc8d1cf9332706088a58107f8f1ce5f82ef303cd2a7d0a1fcf91fb9f3ed0e3ff7d5897c3cb3fd9035d2f3cba147310eec7e481e29e65b2e538c16ecb1da85bef9283bf0fa77bd481321f6eb80fd976e30673a066674d9f3598c61c421c6816938755f92c3750a643ae904b426f8cc4069abf8b97c649b2572135503cacb98fc1937e3cd3408be0b9e307ede0367c33d0ae63bbb3fc09d5efc940e9d82749e5cac540dd9171cb419b7e9c33186833b95bcaecc267cc5ea066ca614498cb5ca0e7c79c3ecf9b660a590b348d94b5dcc345c84fb1408fd35d7fb1422f44b5025df204b7f01c22cc47055a443ad77133057a143ffc9c72d8b1d204054a3a4b9df45b3a817259fe121f97560a014ca048f628f7cc7c29f4f84dcbf3760a9dcc9342ed10c353c814f3a4f247a164cc0be1adf3c409be28f4f81cf5e638ea9c3bca87427bcb21119252dcf31e149aec5f5ca838313dfb27143f0f5305f9db938f7ba2eb4fe69e49f34e28fd22525693a33fc939a1a5907b6c2648c56b37a1586ffeb8ab3c8ea7d39a507298b97fcc3246329d09dd62a6ea38c95bcab331a1d969fd5c4a22b9cbbe841e79dae3e794b6845a93ea23b2b7c448e94a68231fb85f7f74e8784ae85af216bd3908fdf324d46a19f31453ed1d47126acef371a7cbf0b09b4828319e5e7fac2c966218128a47475dfe0829d5c88f50538a1191e3287684fe1d74e6bc9177b23149184023d4f0f142e48eb3e7790e46e89fa3bdaaf94cd59b6311daa40f5184ee1e3e88f25c35251d89d0a3c3cb7e9d909b7b44687a11d2b9450e1dee875053feac2ecd8fdc36841ea3e3380cbbecac6c2174ff8be92a570841b20e4673c2759cda18792418c020b44811a4e6b3c35cdf0a420f1ae275fe1c3bc7b10d84ee17234b5e0c104acc2392baec7b63b67f502fc78cf191586f0aad1fb4dc61868b74b9d2fb7dd07fd3659bdfecd29b0f6af21399349aeed379f6a0e58c1c1159f72fcba307fdbf52ef1de02b28608515be81f5c0154e634615069007fd33eb6c0e6e63681f0f6a8a3539538c5d13fa1dd4f938ee92143b14f72aa2bccc3aa89fc6c30f31c8e74e07c5a54d3e86938e08e7a05874eaf6dcafe315392871c9827e6e09edc5412f8dbf4f2962e0a094eed9fd7fe60d8a9d7d1c72241d9d9d71839e637c701ed4ef843cdba08c7ece90ddd9a0b5f9051d0d1a2376ac41c9091e63e5ec24dfa8410bb7cbf350962387641ab4ca7e1d9b64b8ec52a2418f29db30d9986c8f33a8adb9643cbda6e90e33287555d333f162a6b70c7a902badd89a227c2c9241d3f1b91c48fa3898188e418d937ea272da641f2e06657a6e436bacec110f831a27a9a39bafdeb2c1a006ad5012f9a37c418f19f5e1aaa47275142fe8619274937260e9822e35e3dd953243f0e082221de4ef460726716e419b0f9aef03330f9942b4a04b78c8e778b9247b240b9a7f78bbc8cedb88112ce839d6c7d56196f0b85f41afb7915cee3ebf492ba8d51dfede834408c9ab8276afe17118a7a3821e79ec335365b1b27400087b46cc09396cf1a0d885bbef587b26d6e70ecae40a9fb9976387b3071e772c733975d0c390c47d934c740a1b3aa8992f49bbf226546ce6a0799033eb5f7f96ec18396832a3993f0eaf7ca6898336edf91d7f7edc183470d0f287b1fb2ce68d7ee60d7ac7f156dca499b3c68c1bb41c3aff7ce4b78b946983e6b14ee7dcd6cdc7271b34fd491b9f63cbb9f15c83f22192b9af063d68aeef509ae3fd9306ad76fee2e38986cda041cfc86163ce4e4ee133a83bbbf17ae6c13d2ccda04739baca9037587c1c65d022777e73f0931d4b06f53555e49f8e9b9033062d430c1a530ede6f226250b672de3096f62a2c0c831ee587ab583d18f4ce49a2c6e52fe8712c2307752ef93cbca0cb57aa1f778f62ee827e96ce7d3254ee18c385ff23475d0e62d98292cd4ab77b2d282397453e9a2a692d0b6a7e961cf78c7f5863418de41a591f84e80c952ba81d467d7b9a98a9e3b0821e7df67bedbfcddd902a28769eb3dbce5450d368866ecf1474114fa571a6f1d12805fdafb296a410bc668b82e27af399a3da628482fe13442ba6cd1e5f754fd0f29df869db4ed0aaa733d7b84dd03f967ed68d35594163821a2f45e87db6042526cd61a86fd9d25f097ac60d19ebb257ef4950b365a48fa3d1a63112f4b090e9720c8bce1d47d03aca77c182e6b0dc184193cbe14bc2c383c78aa05458d2b81f39bb554504dd629bd4e8875d1f3c04cdb7267bd8a937bf87109438d97218723899f31b04ad3f48c71c83f4a40c10348fde2d798a0beeff404d97826fb28d3925892841850fd49c7c92c751ca17808a1e281d3b2b62c6bcf1639a0a1ee8a29de7c2766ec95d1440c50ef428428958786db18feb40c99e420a299c470ed4daecb15308c173ac1f1c68f29303cf4c1b4a77bc811e6cb2f2890add71b2d840dd0e4278f990b3327f35d0e3f7ce7e921f0f3ba381a9b28be494f29a815e1582e5780e19e839471b43ce21933d4954c4404979c282edf9a4ae910a18e891d959788ff30bb4fd0f3b22696bcafd7081ae2f9d36d85dc70c1a11a86881eed661aa8ee1ae997311c82050c10225c33d5bfee920d2843860c67a208b4650d18647be0a94fe1c69f8e7891cc44f813a9be793d2e9285077729c21538ae092f509b48f392e33420e2a4ca065ac1c9232c5afcd4f29b49ebc7176b72e63e89042c9f9c07c735f8c51e328f4f9ce8b99781185dae1c297ff68eef886428f37a67693289f9825a0d042f674cf7f4e5d26f9849a7a7f5b37e27e4bcc135a4a7b497eda3afcb813cad855c4e4164ee8711ce8e77d894b4cd526f4dc9d3d85ceb429e4506371c51607a92a28a080edc3149ad025dcc7fac14765e3716442b164d79b6e66628612134af828ecd684e023235e42fd8d78d55fb7655ab184b9e3cbf0521d570925d38664f9ef93b92c4ae88197d7e7e578337610bb05126b8a49689a64420ac9c364610a4930415c643a0abe158cb2c21491d023cfee91cc166cb22d85292081b8040fdbb1e765adb0c20c533c62b3ce20e952e8949918a6708412fca2f2495c74e4762394b0f96827dd5f8c876c610a46287de12c76841db91cc1c2148bd042f2fd481e7936870b3a610a45a81d836b6c37c9369292401917a64884362923270d9b909803a74084ee5315f6a310de634e1f421dd9ae8d55f13184b0017a01a784290ca1d7ff867e9b6fce4c075846030aa1bf95dddc79ae08da22610a42e8398e1bd3eeb139c5384696d79061812a4c310825f48465bbed18d2dc832904a1be077117e73ab2d4db1481d026e43013ba3baad23c20f43059ac0fb276d8b1fc3f68f31b92e4dde72095f7c36e9bdfe3f6141f5d1fb44bf793df47bc3decf9a0a58be05a7aa797ec3de8f1c6f2384b7319173da8e3b12f71ef764bf33c28d9a763918f82db68f0a0f9ffe56c9a0facbc8362e1357764231321d57650a68375e8ce1336e75c073dcc93b556ba4df2d3410fcaf773d0cf41b7105a23ce7dc841c9914c3a6cf2888356dd91e48d9b462b0f073de43cb6b88f52d6b66fd0e38c8777a4d210b11b14a9daca410c164bbad306edc7afe330da7eee830d7ad2d97c1539e472cb1ab4cbe9e3348ce791941ad42099dce3b839fc964c1af43890589315ae49643468164268b967495ce70c8a77746962647eb74c9a4193b19cff3963192a97fc3c53fa162964d06adc237b596f759a8c412b998ecf83fcb0ab11cc90c130662c8d1018a08a03949d0a4c2106dd4367491894c8a9dc3f8610c3851030a87716326ce43c61f25fd0ee52ee93ae8fc5c3bda09d4ff0ba710f66c3d70535acc6c3e01fef7e94e382ba31684587d53ef1b2052d82c69c1fa674511ed1829e5376bec9b0ed1a5916342d97ec8ee72d751616b41293b3f073791ed515f4d85a327496ca57af15b498105f3ec6ba90db29aaa06674c4f0b2d0de310515d4dbadb3943ba4f898827e169f24871c2928152e678ec542ae1c4741bdcaf2e17cc2ddc51c0a8458d5fd6f162e6a2bac3810101a3566dc144fd0724cd98255ecb9c9ec144e50ece378078d0a911f374513d4dc51ce81f7cd0435e7af3012638cd4f64bd0fe3d4c915c32e69f5e097aacc12c2ceb7d601d4f829234beb3b674cc573990a09d8699f3943c47d0c3e90afdd7d5b12766043dea482ec7129a27f8550435ee8ee59cd3a789e927829e66376d0e9a0f410fb635cbc22746c7b910d48a3936351b2cfcde20286133ef548ae7d39203042dc2277898c1723cd6fc40b9fc1c3fbee303c52be7f37d799c5d323dd043f8be0a9515c22bc803e5a7fb2342f877a0c64d6119924407fac576201f41fb6ab61ca8c1d2c454a96338d062a8b3cd331fdf4175033f4d7bf06c711b28b962c347fd576796b6985103fdc3a0394ee7c647e9a781e29174e6388e5f8578cc4071db8e4b7af771ca1d32507c3c8e426bfa0c6b37068abc747fb88a57995b18a85d239d7f52e7cafbbc4029bbc93cf99126d2c7055ad89cc3d0ff713375d8022d6c9e34b1310bf4cff3d69014243b5b56a0dc87fcdc1f6e0e3e8ea840bd9842c81f6c8c4b2437bb107a1ddb3cce02c6d2d819a70b1b3750ec2cb8e48e5c9f1dd2840d1b28356137c791bb5b75aa140b6cd440778bf4e1443bc5e44e03a52dcf42f3ec32934502aa38c02fa0062f8d1a22d019281f7d0af3f02ff9cfde81ad616586810d19a893d2e68a97f925586b8515a49eb011032df7bb555b0c1ac7ba23840d18682e1fc7bdd7adcd92737eb0f1023da549c9d3c6da05ba2673cbd14b4f32dd375aa0e64f8a7b5a17e3741c1b2c506fb2bc34f4327ba7ac203754a05ba6d84bdf6da440f138d8503937967c4ef1c1060ab4cfda4147d6b2192727503cf0e8f4bc4c6257b861023ddc194b3796a23f8ec9e82db42885963284f70d5691d15b68410a3d7de6a0c62b88a6df46a1cc548cd80d1dc58c31a250a77c82c57b9020b8088592f4da43dad8cbea4181071e4c3393a4cc27d48ae329e6d6d1ce1b3e3e70e109a5cf22e73b784e1d84b1135a7930a39d6386062e38a14476cd619fe12246fa022e36a19827e9d017733f638e035c6842f9388248e5109d6de12213ea848a7d396797e61c1723eb7cc005263489393ac9e1227f9c182c63865f075c5c420ff2d2d127860b4be81d749862547490e0f118593268cc380198c0452594eae02b5cbe860c1a309ccef502300a179428748c9f2117236b125a248fdfe5f48d91d559982cb4b1d842468c09586185b100e4c18524d418bec285093da92c1e60851559c8b8020406132e22c15b852c1e3234064f8cac04800b5c404209d963ccd1c590496d3d429dca57926d1adc4e7384966e3e2cb9251ba1bee44f931d6c8ee3f124b86084f2a195e3ebc9c7615e333c402306125c2c423d9dd38f7b2f7edb5302178ad03b48ea8a103fce92424770910825e730eafdc3903ad68f0825a74a23547bb974fc105a6faad2fa1cc4c896c3105a78c7e1e5e52869cb5b085d3cec28aaa2bfa3ec1042cbf795c1e384e7704206a1e6c8987638d1b12f8250e46aea7c2c24f4e402a15bc5bdfb6dbd1cdd00a1c7113a4fc749fd41f338e4d6b80ab9f0835d3105495261c44d18745550400165072efaa0e60df5b193874e9cebc71e562ef8a08b7b9cf0399cd2398d175cec41ffd8f5f5ebf42db8d083b2f9e38f2276737ea49a868c196e85155658e19c85ffcbc80d64714507b6861651709107c5b3b844108de11f3bf0604edd21894564b250562176bcf9ac24597234292ab8b883b527c17393e65d02a54c035cd841fff0f41d74ec75d03efac81e72f0f427d3418f390779b3a6944f2e3c07bdbfa2e3a426e496e5a064cf77992a5778a71c71d092b4c7317dacf7f072e0a05d9ab3cf0c1d6ef56fd02b4d8e21dfe4b0501b3728c9a3a8cb97d1147a6c83121d59b8e810a17bb341bdbefff899943568952e4dbaf14f0d7a5c0eda2eb44b839e9bf947633a4cc70b0d7af8f68fa53d2e668f50e0e20cba4488c57790262ff366d0638f935f6ef22883661dba9134c7fce4c9a0644b92fd2d26899ccb31a8614288c60d1f42ca88082ec4a0496859e630464dcf260c7ae530a7f2b94da58f8041bd90354d848a1ff4f3052df64be5728db0a84a8b113803bca07f2c4152ce7b0e229e5d503a44d01cfe8470414d193331f967cfde395bd0f368c7cf39885a507232a6fabe8f83f0962ca81fe52876b618c3829ac962eadb6c93e962727105357c1cf34fcbaa810b2be829795021c6182a5ea6aaa0b5a68d8f7278d91d3315d49aeec8cfa3dfb0f04e41b1898eb7a17db6f1430aca07a691837cc9814b15054dab4a4fdfd307e51514b409314c9d841ca783a08b27a493ecac3747942403174ed0ba43e463ee8e4c327603174dd02e86089b1d739894364c5073ca9d5899f662db25860146408302c5c512d4d78e72f85fa139060426a346160b38800b25e8e16f3c0ff2459090641749d03afc6053a810211d752e9040e8e0976fa7c443fc1ce133cf0d29e2fbc731c21f59daa0b5313b2f528443eae039e9d8748c032e88a0079176f38554c12a3443d0fba522b27558c747c1800b21a8399e88201fdf88e5254626400255181a3566b80882f72974180be54132461604ac68d498010617405073270d97d8ec29f527015658f102173f50477345b02b8b79fefb40c9c164ee68b64567d23dd023a78bfdd32e3b8fc203bd2c5bf83889f8e796ec408be1eff52f64e37cd381fe7d1def6ce898a34be5408f314f0e1347ccd24f2e70a0042b999ccca1227b72710335dd67c95196dfeb8c5cd840cbf92e480e399fb9af33b8a8819a2ed7475772d1b4330d74f933af7029730c7321838b19e895a93a43f853066ad544e87c799c65bf1659c8701103f52d69c6904f18e851ce7d7b6eb9edb17f81d6e935a7f6c6bb7217e89793c7e1e3c06252b805ca853fabefd11cffe72cd083dd98d7ce1f36db5e81dab1e57479d2c879b40af4dc91cc1f6264b8f9488196339783cde1a4ebb845817616e2f79d6e04c9cd0994f3fdb83c0c29e40e441726d0c4837ce8b842e4799452e8521d3df1f3c5ae9f9042afc9b755216ce89473a3d033e5ac113ff09034178526396da4fbb18aae2b14ca84c971d68b07963b99d508dcd0800a50a87bd65982666eb27e679c28a8f88416d95298799a98379823d819ef129041812a0e50451507a8a2c61632dc035750e00a095471802a1640c341f080112c04acb062043bc31c800118016801159e505c333c3a0eff9ae33ba1a6c957625ba125cb09f53c8ca49de3f9307d13ca96c741900ae7671d9ad0c3d0b124cde513f44c28269a3b8e733c64b498d0e3c955a5b97284652ea1b46b87a12ff7c5182da147b289fd1072a62a95d0db4c4224e4889794d0fd5af42f773f092de56d8753d54b4273d1918deb10337724d478f183f05a43420f3a104b12e3accde3115a6e9bffb0dfbce774843a379ae2e328c4d9c41ba1c6da4f211273c8719c33420de221c7981c8bd0c4c33ac73d92cdb28aa87d62878f4ad389d073945354d2d051efd988d034d24d7786fa10da74b09cdbde3463ce86d0e32cd6d53dd956321742ed1c861cc7ca39303b99106a46fb5732b7f214f220348f214d77acada12a2c08b53da7f871be7ddf8e03a1fec7f1f886e994cb3f00a1841852b887f9077dc7836c19394b58c8e10725242387dc2e1f65bf0fda957bbcf8b75da1f34191e938a40e0939c7f21ed40d99c1620a8f6ad6833ab6399b3fcce641036c50e3ad620e36749063cdb106edf23fd984c8a841cb6539436a2999918e3468b1a3bcd339b7d170d1a04e8e983777d835b13e67d02e879f634bffb1a61ecda0c7311d379285cba3974133c9b127276bc954173228fb2d27192cb70721640cda9ffe944b8e03eb1431683f9511cc3e8e15338b91056304346a54991761d03cc7abe2e4b8a2068d9d718ca1e135ae20087801062b4cdd95a40f5bbbe383175f28b74d55a418fdbc50bc840f162bac3010240b5e74e114d2c179ac1bd5f78c175c282bb078b105a5cb728e3672723fb6a802020da8e2dc025e684149b3b1b4efb3a394c22fb2a0c5c47def4cd2f81e3105bcc08296ba224c7e4c9e67f315f4f87dc2e51c5faca00751fd7576e122a7e94515348dd7f039de4d9e568efcf0820a6abc6d499983e5cf106721e316c0861753d052c87a793c5674b5468e03300083042fa4a0f48ddb565b7647efc7c8926180f0220a5afb07215b75a59c81a18507bcc615300829c30b28e83732da71e016d993f2044d3c38bd8f5ce9bb6a2728369dee3ace79d104adc39cf5cb42c4ed6d63a4d39041b00d2f98a0c8dcb487dd162ba5548c2c2cb05882de39112c66b6a4c7e32bda69cc805103c6d25de1851234bf54b9cf423cba0a99c28b24e861ee91b2af7c5f3928bc4082ae1542b22fb3d2cf5d8c2c193560b4db11d48f7119d9b7f3df3e62649911f4f8dbe96cbd90972ea7085a078b0ff1df8c2d64d0d80012418f25527820bd4172e55c1f5e0c41ff8c1f6e2ec4974b9b1c5e08418fe925c2479e7214a382c38b20687921058d0f7285d8738c1740d06296ce1c22ccb3a79418590e83ee092f7ea09f7847b3236217b28a91d530cc0b1f68915fef2534cd876c01a3d769c44826bce8412985d2defc93a9f2173c50629945a488ff61b9037dfbb72793574eefbe84173ad0d398472958fa0f3b87bcc881f2e12e4688a1d5190c1a768417385037898cc88f17236bc61637d03d9c5c235fadc92a33c20b1b1c62f6d81a72f72f034607f88a0e70e1450dd4d87f159ffff4d3c531b268a05e6859301e043360d4e0cdc2cd8b192831bbfbf9c52aed281223eb9d060cf7ce1732d0637f4fc5c83a1fbc88811a3c937ef8b72aef28465a0f5ec0406bcf54312b77746fef0bf4e8a2426cd37c9573bce1850bb4cec13e7cd83acb1cde02753c9e8e1f2652b858b240cfbe5149c772c386172bd07398cdd1a754ee529f33bc50819a2b6d8a2186e41e39f6450afaf0308c664a39670c2f50a0f6792b861727503b4c6e2529598e37e8a55f9840ab8e3f5bba484123e6520afd3a9acf31f8f869b731b2e83648a1849d4fe8927c597251d818853a3dc17e24dda5f05144a167cafc7a971de55c8d2d64c0a0e1357e8b8542eb90aeb0677559221bc20628f4703264d987e162cffd84123464e4c0224dfc6b6c21c3135ada4996a1cc62703ba14ce54ee7e870e2f8727798d984feb675d765d18626f48edfdb49026123137a1cc7b1d961e75964b13118866b21030b3e1e6c604297e0fe1acbcc363ec303346250e560e3127a69e7984ddb13f3c672c386253469110b7692fd49ef5ac3462574fba06c424c4a681ddbb90726993dcd3f093d54082316cb2209ad83058d182d9272a64442cf71546f5775920a1324b4309da31cf9f8f38a31f908edb7f6f2d3dc44a4080c1b8e50ec7d7259cacef0008d1884371aa1c7c82c69262b7b87b0163618a14bfb4ffa30f79c6256586c2c8214a126d9130f53b66264553dc06400c6b091083da2e2e4f9d05107bf09c30622b4f20fbbcc3fd08e99372f6c1c420f2c67df449e0dfa1a2a6c1842a973bb89fc7bfa11f21b85502ccd8657bd46ccb86b6083109a04bbf0be5caef72931b288051b83383afe8f9a3146560896060cf72f26083dc78efb7378399e63baaf0884f651dd9e47c390d1570908ed8330c94fcaa3bbf730386cfc41cb1d75ee2197b561c30f9a664b71f2644bbb6f7d503bcba760c1272bae830fda68c7cfb817db534ddeb0b1072564cc6f3162c7b11f3de8b9bbef83858dc7b66cd8c8836ee1c30e997f3baac278d03c850e6c63f06a8ff433868d3be851d8db87d09a1836ecb047a1b3e9818d3a289eb43a864e1132a4f7f4061db4cc31ee76d25ba6dde7a089471d5eb622a4d851725047b4d35d661b9790e2a0a58fb3a2e3f71c744a9d0d3868697298b27de7be3cff0d4a0739a44e31173243bbe1063d4899f37e94cafe2a67a30dea46de68ab8fad4def0d3668fb12f244922a461e1b6bd0624a1d527e25fbce220236d4a0e7c8c6364f9ee9cbca0e36d2a085a4f92ebbfe25458e18595589063dbe8ee3871839ecdde60e1b6750225c08e7518fa40ac90ccb88fd070c2c83962c927cd899d35c4d06359cf9758e236f099f31a821c227a49c52440c9aa7fa8a9c8441bfb7147396fc82414d9ac29ca6ccad243261e30b5a4dceb8193ce668aff782dee6162c7fa0e9829a722c1562cac8b39d33b0c105e57348c983fe84d4db5b50729c23fe5b2eefc77616be818531638b2cd6b16002820d2d282e2e9badee80165b0386f3623183686c6441eb38700f724bbebfc6039b058c2c2ca8d1a1a9efc7e7ab3431b2647495161b5750672b87b85397e1fd8221a3cf8c0d2b681d77211f87b3c9623e461616ce592c63160638820258c44615b4b3cf8cb6cc410e9702b1410543978792381e75141bc3116c4c410f8348a7ae1ce4cd392f3f6c48410b1f272abe6be2525f636bd860230a7a59a52ca29993bf075571002b4ac1283a6c4041cbded4e52e2968a7b49031630434b6d0629d460d226c3c41cd1da57517233c923846169913144979af3a0af31c6f3246160def000d192180d104bdf3ce6d82ec7c842ca9246c30414f9bf3847b98e9ceaa185923582c1a0b19bc812caee8800c19078c1835ae08010c2df022b1b184ef2288c771fa38691d23ab03326460d15798a96143098a7b124dd133731d45091b49d0c3858fe27ef889910563091b48d0376648861c58caf9b278c00162d4b8e2025a60818501aa38401516a8e200551ca00a25545e368ea005e9f062e3ec56e6da086a876579938bcf39b54550642e7af272bc134e4304ddff3ed9c67948f00c417dbf37ef16afd8b208418fde0edf8e47bfab725ec0043682a07b5c221d62aa81a06f7c4dffe1f74f628e1f28c972360d7ee75f2dfa408f3c11b3737f3479c41ee84166bc8e15471ee895bde7395968db1c3bd02572969c3e88e840cfb5115e95ae45e38d1c289bfdfab4039b1c73e4093670108886a874ae6402d2581c0e8783e170180c0629b32e00e31408104080b0341409c5b2280ce4ed0314000447281e382422161c22160e18101218080804c260604014088502815028180a8445e1714024287e2e4410114be70b347121a8d17b55692ca54a395206effcd8a78f56bf4da49d383846a0abc2c2da1662054a2cf91ec8df5bd4ff716d4663b2093c52680fc080dd621f5814c117a61c2c5edcaf263bfd844be25fbc988009570d0c36dcddb95a0c99375ed6262c153edd349c045ef7c1d692108d73bd7bb4cc5980a4d22131e704bc77e60701280ade49750c0f94017de7afe251012196e83d42ab2fc9ce18888db86e57c53040739e3a02c6cc590488c9a8a3ee86c02193dd87b5b2ec7f1191ca702089a79d2acb09b8551095ffb70439823a05f30e64cf08be9b384766eceb2173252013c3283112e2aaf8fd014b7ce29d77067e419304885a0a15bfad18a6b55a1d02ad0becb05592f62ef15a20c2a721841dd905d2bae195ab6e6116960e84c0df3e68e484ef7100bd117cafecb368e8ffa64c742a197d217150821457419352f49132eb5d80e1be28942b010af719419820ed841b958538bdea243f6484631b3e6ecf9562a9283fd22b2dc9fe7eaab4e90294019027ac577edaa1f8484ad9d1ac08b4d7c4fb5d630e8dea580ef3f5a56307b5516513ff5e58d717972063ee348a7440f2595c68aba30164e9380d7929e48a3ae0ab4aee0332f2185d20609c35dcd9340693ed5e3153866303e0b0f4f2c0f5770ed2892ab6b6c6f5b77fc7cd47a46a4a45d56b5197c906089ca8d58e959d017b1a95caa69fd3279dc1bf89752deeb0e1beba3950a63622b0971237c917ec4dd439c78db414cece333a1ce1424eed2f7b79320ce3a71da30b295c20e623b11d109c45e0086aaa4fb0b62fb648b4cc4c801085378406c96f8a067d9e3397210ada4ba6e8389785188440581a4f5506d37a8d18782f86db1f542f98bbcfbf1ecc48f4404f7ed469030848c7290fb10b704af54e42fd640f3a20962386fcf359f6bb3698941ed6923853cd8da29b21d269fb4a4a777875be02a4a723d9ac08b5e76d7d0ca85cfc8bcce8b9e19953daef3c1ac9cb8defcfb2647a6a22e34121c799231fdc37ba1c3b34db9ecf0858f3451f18d1301ebd0f33df5e6e02959938e2a0a9b98c671bd3a4b8c834b5261d5c0ee7e1747c64b6f30324f2acb8fc8266bfc0a481e118f3e421e51f3c5a24b53a721451222650d3963c3f38579162ff9e86830005870191e492626078f455f3119d4e9beece502824cb4b0c40c55b35fc89d1b69888096ba695f7ffdecec363ebb3a8c5a6ae9a02c44830d695dc191181c19ae384d4710c90f7e2f40a68aaadeb6a97350388251dbb04250276f9104b757f59ad58511c91aafeff4fb014008a6f07e0f6a6aa6596e449a793efd8c7a5ea7e20aa5794156afae5b808692dc42d704b56fb384137c64977379a76e269431089307cbb437d7675f4b66c076ab371129a2e7b8ec28e36386c4d58cf831c8475b4e0c4751551d166691806d277dea189d21921a110ce8e901167bf747762ad79d3324acd1889c0a19b3d73da1ddacc917a6ec082c9c730a34c370ad5a29ea431acf08c9fe531c47cb284df29118878a8172703d270921dc4095e6196784296638dc8f6c5a5e7a08d9ce38625320204fa23e0b50e801ec0132006033318e602c94a5dbe271a17522c6b8d16851edebef086a813f3100909fe479441ea8f84ba9125bd565367cb449b5499d347c01d5e6583061013d04b83182caa49feeb1390c2d29d23db8ac746df45636003c56f295e107338308080217438621092c375b0e0662a7dad3c1c19acb42ba8d886b8a39a224f51ad020d7179e9982d6187a4daa0628b9f67cd1973bd5b513bbf18401abf7abf1c9a16615676178ef515f77bb01c5635409ac02915e492e397b039778caf3f9464d45de5e2a0954dbff1c75b0eab86be97bedb5a3f44a0cbce8a04b0ef736af092c1bfef425a55f0f68e05d87fc084bc813c3b988c38993627d7ef0a31e585ff6cf4af8547622ed87f2b27e0cfd81bbd33a640514c65f73f6cb5be8b00f9b7dd286ff10486d541e26891acf2f165197d569d3bb41e561e9b86453ce5d5cccb5859c2088c3e9991856c3cc33469777e95dd57bf18b4e1693a5a824049149a6488bf867624f7d351d4b159270eb2e4d835c8e1071f4ad237b627a5c15c0f045d9e06fb776eb3cece63174b06a3298cf4f1deffc7d4ca4929fdc791376f036cc23e8a251e0e7ab9c39cc4673eb9be09c1d6ccec7a3e322993926cce72985df8ea3e00ef67449e1831ca41dc6068607294db503c578ff3ab369d884f7b667b3cc0d38f213608d7f2ac2be73cfaf6680f4a4ea881152523eb9def5fb66034b505b892d2d0dfa7e18dbc60c1f1aab420154d60011021ff7fc0cd30e36d48ba9be0448e98dbc47a837fcbf7d94cde68c987f07fabb5480afd23c9ad1a15ee8e0d2d68d358eeb4ccdfc2f5cac8963c15e76e77190988484991339d221c978d587c856136d1260e9a26829d9473056b7e6bdf8d52e391202f495d7dcbffaa495ad0898ed23155a1e21309c4bbf46e0658f840e0ab898336be263a92ec82d681931598f4850130305b84f5d7023994cf6d8004be35194a817e69e62b80ff9a51b2b61ab79ffa5ca092cc14c88ff401fd228179cb5fa1e1c218d5c09af1953b16bc17a14a7eb84d55ed59bdb680b847422111aa21859db7fff960e9539a3a6d48a3568ad313ee3726d10af65680e1575a1fca2efb9c26e58b000122512572cbfc211efb65a4bd35d9526866d74a9131bab92ef6b2c50d39f7219999dfb72f6dbc8bafb51d28d65f7129990d4f00777e405658e1d7685709bfad5b07edb3e5b68aad89d4ae370ca0a3a9dab8c7fcd86d39cf907f076b56fd9886a37039265e2da0d71895a9f17e43cd1dc017b32a56078d98d6640d7487a5c19800b812300959861fed99e858e531c23e229115d1d3a99e0803399026872ad5d28a3b1eed4b8613bd17b40b6d412a8e3889359e60a9acdb396252a7a2a7959170a31c5cb44be179de9b9deab9de64e3034a3f06fd178364060ec66c125b4ebcddeb630bdeb5e8bba4c4510809ea07b461aedf5ab5971fda46a0ba8b2099aef401e8fff0b9df91b9c15b4d983b5cc7ca61e45698c4b64f5c391a55ae4586d49ad579314a622c46d09022c29661d9fc37e592f242f2d69764e1040e22c9340af1c5897a0ad053c22d127bfed7aecbfcaf518d4bac4e4d66991523b5f0bd1ad7ea581ef02c6ca327c9b288bc04cd55a7a0711b060b35cbc21af5552caa3b1c5b3cc8d0daf02cb082e2156eb296b40b4ac1994f619205031914e96bab41005279a6d0190e56b800b5d75d8422f878d63ad98a321b9eba8d1ccfb410d06281b0edf42f5d35903304ed1a4d2014116516433c5891c3a5c8a0baf803319089e63742698865f997e49cfb548cc0701cfc908ecfb48ddd466473dedc8c85cbf4c76ff4c89999accc70376e66df37e296611e664287f9b55656a5194377874219dee61cbf757476716737239a99a1a79d7b9121a2cabe72636ca558cde1101af4c6b629d54110a1b0294714e12b1681975ed96e401fa8d25e7a311e00971d3eebb20e5c27debbec469a6b7cd53ba110c3be0a744e5d7bfc1c6624fb871cd3c7cf49aca0cfd84bdb58c466a6dd6f241dc766308fb41d96b289aab689fd2be3b8188717acfbfb511bf4a7be53eff9e3e9c230c38d27d22c4a52e8ecc483823e897ac1e33dbec016a136152aca44a15c8a9aebb233fd81e137fc5dcf8374124177646b5b325feb0f91f8fe881e23c08f6ea543762e7eeb7e6155a589eeed3771d0969769078025cca6e4594705e11ce0b24fb4821fac5257204dfe297e1b84fd82eb910f9ec5152253d266af110b4ec44924547a6181f8a8e3af8be3b61eda8b8ebd5a4dbc344f3e3eab283eac3faa349ff925a61479dcfa9b8aca2dfa4059ddc2a05529a503a7ca47240981bc784697e9380ce317890d2afc771f54bd4119c8495c5e0bc4eb8d03403f5a9e50a5b2225aa579fcde9c75c5dcde1b824d042d7d703078eb6638195abe801a2c765b099eea38a3fe636e018d28052cb75b314ee2a0a7cf584040c3dff72f17dd0e09dd59185342fe86f0fcfd60f50f0781b9f522c1b37bd52dd968e809e6e6a9103ef7ff140df37666d450d5ad5adc0e297756042c0144a4c890af52fd81e2737083f33430c99adb5e500abe9e671812c4c7e393eba9ba21e5c7c82a39b3350482fd9ca646d285750305a8cbffbc1310059e8d628f50f3874ae2aa4ed286218cf7242ce18d3b0736d485d895ba257537571de20e6780fb41f081f10132f5b4c7fedca37e561c1f5309df9753ef90869ff3f23edcaad7d6fd11bae6a94aba051b39a6dbf8c9b74b6830aa89d441fc629257aa84ca78be4c941e52715bcd20398d0219468cf724bcc0bc1b4ca85ac7cf8266a85152bb433f046a415076637fe57838d05da5691ac8d53b80b831382d4af6ce3d320be65eaf38095882930084c04200161c0d4804f01668e40ad6720f11687206dd5fe4f6cd929ff0dbb5b180eb87ede37fb4057c46ab5b566280027dc954d5e846b7eefc8e409ef4c4cbfa58d4691c0ff933c2dd2b5c87dacdde2acbd6341946bb50d509dbea442b3598dec0814098ded493bec25f0ddfe155fb9a72a2652e4d2cfe8ee012d2f7dff6dc83d7017071d83d1858a6ca2af5f2dbc480534a2ca7e379982ce3b68646acc0a1c4e3258bea243f02f3204b1e1114aff857281effeec2610da2f47d8200b10c4df68ec81e18f1726587f003912f354ae05af870b1c9261d9b4d71ebdb02b362cc98047744472611f7328a236bc4c98ee9639978f0053d06464c5c66801266223ea4b3f4751a45018a09a66ceb0a5c4df0600646610a8f13fbf5e3c8a63b86a02e2dea4023ddad1e8e34dde07368344aa6f66e5bdbd55ea7205a12da921a900c282df81ab50d49e10cdf545a822f6b18653cda1b4ae05398a11be479f9bf9cb738fedff9a0f812319c11d514943106774415f415b852011486d474687531961ab76d574c24e001989b2041aab8054fed36d78d312b4af8c33606d29e8d917b5ff75519a40a010eef5e276e0dcaedfeab9c07521cc895c19b03971f0d24fe5e800bedb0ed9d299e0c9c9a18e01ce8084366ffb6800e2ff2b500c958b7a2d426ff2bd45771d4ac357f7560cefac6c385e4700050a08759d511b4f97992de2519a545aedc938e96e97a20c73b27f37077fa4bfcf2bfa0ec93539532b259a65d506f4872ebde5d798835d88e6f1b2042c9b0f2718f631f2f926106ea3e82a0b26eb97197142765a836f3dae5c05bed1b68ea0f9e4011a6b026f60776492f18bafb6acb52f0d50dff6e771a0148f02aa1214744bf2e267cec8e107c81e1caf5d49a72419ca69905897c6108fcf09291912aedcd5ef436cca2e788610ebb36fa2322f0417a39a1eff21a6386c315277ac34d711aa4110f00199cafcac3e800a79c5409472d1fe681bfdbf7a055746bd9ed4be42608983f39f793b41bca0fd8c528d465125bba24a500bb1d91b72d338077ce98b229628f6a5c8a65217752998b8701756866b72d938c0fc3c23b7e22f151f26bf77dfaeffca2fe6cffca9fa36ff417faa07c587fac3fb7efe1dfd0aff00997256b4000a1fae43ce56ae7febc9273999b6df4dce67eb124839db21d4107893d24f3b874e6e80e7407c8a2cc02f03a5853061a9e0b8d5f6a52f0c48c77c9ef40c5af24104d5a5134562a7319c901283f163103e5f87f15a13c5e159029d46b2c1054f22737d89cbc8bc59b06029680b170aff01d86152022cdfb39e1c5e619febca85f875e1a2ff56fb177ab57ab37c03ba86fbd8ab79b83b4bbe7e86cfc4075375befed25f8eb0c0cf4f2f75abcb5ee0cd53d4f8fb24e1dbd73f49e73070b329d6e36eb4e4e62bf163a75715d8f2e882ea11be89e747db3fb9a3451d5e97891773dbdcabd01de59fdd60bd2a30404d63d070cdad54dddd7bebbb596b3b7e3b60b05ac8ba6abd785e83edd715d9b6ed2bdeb567439ba6fdebdcb3d0d90600c66eb35f046bef7771378b9dfe95e062f3276eb126e7f1afcbccbe941546279ef37efddef95b71ee14ece56e1ddd7e62033c06f09efce97b83be0f59d6e1d21451a9a19de5e929b875e43ef5caf8a37e92ba4ddbaee7611190befb997d019a2ae97ef3631a818c816d9d5f0f2fea2f50a7a21bd6b5eacbbbcde76ef63af8a77af6f9dbd71fc4b7f9c2bedbb91fc6e5cc34be62ace0e0365a0d74820c25bc6b573aa2c85241bf3d70ad666219b3a527d3b857165cc06857d0db70cb11e168cdc6fe1efe37bdde3b2e772a4d1ca8974c5ec6eb1b81a371aa5e18f99524a429a318fa8ac19f0cc6e85cf70e5d334aace1eeade860bae60bbbcd014f7b4427a65cefcbd104ff0898cde623bb0f7988a7dc8d118f81e8b4256ce248989497ef88c6d853117ba0bf6908ccec1e80d8dfb01bc3818f78cd9106349a9e78af2a871393618198c641a8b3de6defe96025fc72fa37702758e7e0ccec669af705169331b6bdd85f50eee6713ea499f6b167f8e3aeb119273de9eb05ff70368cf4109ec12a36344d359d0b1e8b0d185364d440298ae4d2755b1f1a82ed725e05968a39b90ee9f5802adaa9703f586be82f714a87f74094e6e29bd99aad083063d739ace72d668294fe8160f5f0a2b6ce9db3be76495744e6c7245f906e624fc78529cb0783310f02d94d196204d5d2efe4636a7e22eea2e6839c0c7b1cf3127aaa183c13ad4512b878915cd6c5dc001c586c6a2c08e46c060359ecb4410c7d895251391b887129455212fbc4ef2af8652c128120fd7ba145b71834b0a00e4965516bcc8c50f2245dff2a651bc656b88f1ca7823dd550e8f85d1b37fc98596468c26be69a07f37e2d95b2872e7c08997d8be28c09fe411221c1222b758331844082b1adc781a453a2178a9434259d609d11a28e5f4dc5c6a96ea7632931c5746f8e2a0cc50204e73f8d4079fd29f82be9a9462af4e8de2c512e8c4a4c6f0651bba286902c157a04e33849976f4e27c284d0287e272c3747c295d09510133566e0e7637f066651f83aece5ba06fad102dfe8d2f30399cdb268faa9f0f4e6bb8f25bcfacc309d3c034d818c8825e198675db81fe040c217e3086a028340d5e0e528cb0f9adfd7e140a9b79ca5169d80d46ee0b7ba4db831d02c78301017c609d204cd822f01f202444840331d8201fcf949c0e10c21574825d007dcc8c6ac7b989b93f2143ae89f8a2350806c76002823a64867414db238178d936dd87fcb127388fe4e7dd40f1e021e14410186c0e2e840c03c36067003e804e18e857b2c396f913678357ac20d033d4ef8fcbc8396396d62e1136de0c105a9a8997b1246a8c1f843a288cab1e9dd4e8985e2b40f95ede8c734a5b471f115bb3abffe63354d73b59000ea0005801a076408b020eb018c04b1857a45b9ad484ed468b29805d7dbfdae70045001b000d70080284b37bea0913a001e6ac004cfb20d7cf01b48844968d7a80510068b99ed3574b80379831acabf314a78acc60aaa757e0349a02a0067800360029c003700990250081257b1a800ad0000200a600a0407b00863ca8a9ef94628e5932624b4fc4dcdccfb279e228437815403cd93279fd367850b566476cb31688146af05551e8f775edc2e5e0136a0b7f6dd979342cb421a1249c3d030363bc9e47e411647073542e726aa003fb5f6daab89910fc0016db731a12c3df4adc0d7bf34446450c735c850e783b487e23b6257652bfd3e1a5d94c692c0452a03ef0c55de2d20a20089c470f5585185a83772f061903da806970198c19d806b9c1c9a036601bfc0da0c36043e2a10eac0880070e0931c2c541408244383cc08fc0596825cc234816a612e6133a0419bcf09961f32b6c3612d369ed0a1b1f0259d3df12665439e5cf264437c226f0bb2e41b6d9bdb60793f596eb89f2012504e10227612a613e840d2b33c66a36d8980f9f2060184ca6ebe4cb9104b918f40d7e06a7816070d40d167dbeb4d119026da07c204938271c4808110c839b034a02ba22ccb41d80c6258141252c838ced100682c080a283990bb25f4a3a6184b0b129885e6315852e19dc0cde068cc164e035d8a6c13e7215bb08b8c1d56065103290548345274017011a98061f83b00169f019e00df80c9ec1dec0131a4cd6eded37be816330e5a043600c1ecb60196ea0b7f80c3e83c671b0cfed666e0883968130c83af03cc20c6b2d76664ea0778338d433eeeefe6a650ad06d7442081b0a2bf7b26b6019cc0d60069f81de203198c76005c3762806d400763042d01b9c068b413e7c305947b975cec077409c504fb8247887304332b0d403399a7903a035b81bf6f65ebd26300e17a67b38b8e5057ea133209083c95abeb4a80543c882b03bb04ee84380165e3a61e3a2b2307e25c4ea819612cb6a50b5de278a114aa791ed99d066f8ba1324834e30d807e574fd35c2c1603dd849701f61063530ec81f9304802fdbd78cc28d839507b0a64d7b76dead53e7c93d33402660e591c6697dd3073be96c0c4840dc710dd6b21ec7bf42218c5081816b8846b04182b6cfe7c6abfbe1e2c93dfc28fd3a01a486307bbfb05f672128013ec08c560fea07b029370432019700f7e12a6125c803043cb430e6e066d72b01524dabd403de89cd040380656038a034c420fe1881a2c079e44c268100c9848c6206ccc029e7744b70b3440b0a6d0013c0c3c0c3c0c3c0cac4dfcd6d7adcdbc05996492d3d03e5508ebba24d39629a5e44de39f441a5167ca13b7ef90a20b3e0b620b2d0c962cc168ea5042e36e890eaa04a7aaa593888ac95644096e93a47b1da249b02f1e9398b3c916fd4882b11cf53befe2dec9468293cecdb593e5a43406128c9d6758fe08de84ac50e23133491a4730b2bff67b4735c66823b80e96a4549f3ce89d11ac2621fa26f97d3c4916c1c85c79d36715a1639228020b3412c146d58c2d523bb9668b091a88e0845276a3a5520aba840cc149328fdafc4107d3642138f194e89e5249085ef7db2a4cea5c264c06c1c7cdd7355a4170a952bcb4e992283a0b041fcbd3880e566db295008293398b49ca740cbaf407be45d3c9d3d9a4e1072e7484be6a2bd349a8d0e80327cdf3aa72cbbf4585061f52a204d11e78b5936212da04b7def5c027bd5e591ae3eb79f2c0b9c93a2a25cb0a428b073ec73f93df62eec099a4dc846c91164bb4d881ad9ce4bf53293b9aa5d481b394cf045d5da1035b72eeec41e5e53db1320736793e5125b33edf2a7260d53f74964a2194928f03634ac558caec24994170602beb85d226e80d6cd612af5cc93d9bee06fea2978d09253a9da70d6c55fa3ff71cd52d1bb8ceb1e289a9e1ed1a788bf9645633f92566d4c09b9d0c5aba53a8a434703aa58c5ebac43249140d7c2e1399b1fc5a058d33f0d71fb35745cd5065d028039bd45c4d59493fbaa14106ce4f4c82b6335db1928c8193dd524ebef99a938a18189d529434794278520903376e826ec8a47bb1020646e8bff760514db3f20576a345cf5fb526c5bdb0c924664cd7a982a834bac05aa7ed9d9bc905b6c3ec735f474f4a32b790b058d94665ec58f3911c1468688135e982c864f23f7efcb97103ef7bec7014a0e9096864416960814d2d9a84436d40e30a5cae2a254cb6b05c41293b41c30adc8a0ca1429355e0a44aeeae1e4fb60c15f82c393b2679e9e49429b06351439a1254e511a5c0a718e29615ba89058d28f06149f449b1a4072507853328f58ba6d913381f25a7fd3cb3d22b9dc07e284f269324a4d104ce6de4c8ac1233a98f3498c0bb5a8aa9a950ea8290c612f8a0354b0c1f1d6928812d31689de4f9bfe41ca4910446b4944a761eb3de83349060e58b9a96fe92a0a1048d23f041a8eeeb99badf46e0d4e5527277c84b825b04766b3449276e6810816b93b32839b35892541a436033a8b74e2767be6c823484c0092583ca6af6b1dec460b0e9979359bb8a27210283ed2b1364c98ef71de22fd890222bcc8367141dfa8237df2bf590a5733fec052b723385282595480d79c189799fb4c9c25d70d993a4b7478b09c2a40beeb7d35b29cbae752ef87cb257caec6d0f175c6a2db16bafa4995b7082494d495473ebcadb82dd944f5fcde3a6a45af027c9f1f2d4346dd382cdc92e09fab45970a2c49cb26d9e8d5e65b260544c4c9a4c932679c782cd5ea2b299c792731616fc5f9f3ceaaaa49cde5770f2c7f3fcd3189e5d57f0efb629c6dc69dd6d2bb83ca61f73b97e3e1956704295d0a7eff45b8959057b3ac850f7f14d8919557019a47890f977e6692a18e5317a55aecaa74c50c1e9283165916ad9c4cb29385139dfed56fcd836de1c6698a21ab74c25774ac1bfc53a3d3284126c52f0194b4dcc1b26ad2aa3e04ecce4891fa46d2e0a2e7fcc5a3b43c1fe77b2cda3f2c70f0f14f96776cd7fd61f1a9654ccf804d73b4a3f5b48b3b3be5829667882cf3e667292c245e5ad139c6993947c0f4baa63c7093ee978176c2c5797ea36c1c74b2568935212baadd3045f2908cda27e1ed7ba4cf0de991f4dffa44b4a9860f427a1bbd16d34275d82cf24c99f6926b304f71a969dec64afafd13c07d231a3128ceaf50d4a4c929c5344093e8eba8c26e7754a8226c1c88f67490a133eb64b82af24c9a2936e8bbdf148303a9b78565996d9198343518e1c7cc283478b51823052d08112842146182708438c32cc8004dfc9e47437717b04a32f0893692b5f996e8ee0e4f26c92bdbaa735c146307aca2e7b5da8ce1d46b09e97359d9caabed1457092e82cf182cecda32a821375e4c9b2745bea2411fc65f1a444ab99a42622f8cf49b6fcfb9d9f3e04e7c12f588ee3bf1a34041b324ff4e5fdcf275808c6dc3b644992a426a58c109c868ad18427a9412b1b049bfc4af7e5310982df18e36ba9a4626e522038f133e3552725dff980e0a2668ff1cdff037bc2734776cc6d52ee074e8a29da6ba6a566b0933e70c2a2c6d1d896da1932767f98c1073eeba25a4ab2cbafde031fc5b48a77a7b09cd1036f9ed5a3e612b4df9a074666502553795a0dfab9c30c3c70d9fc45c9655228612e72ac4cecc0757ebf3f9d2ae536333131a30e9c92aa7ed3473d4154e8c07930f76d171b799739f09ae42e214d6a911bad1972e04b9d2a617789c30c38f09ea4b8c94f75d09f7c03a374c926ed348de8b86e0262861bf84b7dd59777a23ad886196cb8e42b49ce11266a41d4812366ac81f3f04cfbd22625d1a9810f4a4a6e31b865ed581ab8f4974a4bbbc69224e9f230030d7c75fcb55862859faa70a8253646e3193831b59ff44ae357e29a81f3244f4f652769fbb932709973a38ac6d3a5a52123470af430830ced57dc8b5b23f21f65f0d091e387ff188fa76387f6983106c67ce3da07999a536862e0eaf429c1537ac3c06bcc7623c5dc5b93e817668081d39a3fafc392dceecd17784baaf3dbcbe2c20c2f70726bf00a42755abdde05764cf60e3a5656a730830bfc7ff6944e10da63f23e29ccd8026b9a4dd2dadc5962120bc30c2d70e6257e3491ba176664811f73f75329699bb51d988105f6d4e5d49583c7d28db760c61558cb65a95c533251db92608615d8927d2a788cfbd6f72883c78d31a30a7c3c73511ffda702bbbb194cfe98e050433a72a462831953e0dfe4f65c2e2e0fd2bf1418b96aa2544d5dcad1db30230a7cb25fdd4cf96453a33dda3052d0013d28f8c172aa3cb1242d42cc78022727e9d3a2b6a6248e57c68f6ec20c2770620cba9bcda44a98d104d6729a96d82787093398c098ccff1f732651d641e6862561c61238997276cb234d9e28cb8e8485194ae0ea358a097e3fba1a9b9104de2435a26bb44bc30c242c5adf5e6742bea80c338e60caa51d2645cd124c439b602769ed1c05c30c23b0d7f76be1fe6e9efc22b0b6299e2df849dfbc89c088f0fce9639b9ad664087ce7934491d79f59af324308dc99da92fc244f30182f292993c9eac4cb3b301851974ef4a5a73cb9f30bde7352ba93abc6177c99e4375ec9e2e68fe905278752925c25575ef0f93944e9135a6de4ba0b4e68d2a3b3094a74c1f787e79283fe93e44bc905772f6a479f2c5d192db8e03caf5349eae52dd89393d063c24b7d8ecc169c9824359922a3e8cdc95ab0dba5b6b172df9b9a169c261551aa2bc876cd2c58f724f707e15ff275ad031f3774ece0d13a40810e12981861d48fc1a38c06c882fbbe8d232d9b30d9772c181f8bb9531a008bc4b29b2497a42727a5bfc224be6582d0ef49da159e7c63622a59cd5664f2077da2e9ac398eac3899b6246d7ad5ad0c1f377057c197144b52b92296f4d3d28406a882931a524f0ce9c9a42fa582cb5e1dcb6ce38dd98f0a763d4591ba1e2abaf753f09baec24c16edb6256e0ad6838b3c3998f5e7f69482f3bb54cb4a4d273587149c88558799e0a32cec51b015f54b4ebb39dda64614ec987496a56a28b8d4494e6232f9ddc80b28d8ecd027b54575f03c7890821ecf8347f76081111af009fe4dcbd5629027384b4227758237b54a5983e70de0047f9725a65841b34f256d8291163a86e8ce35c1297dd5e0f17fc73fcb046b4a450fa5d2f6631e138c108f79b3aae8e827e9126cee7fca0aaffbca794bf0ea174a8a3b9e4af0a572ca11327593983594e0f2c63b39eae67fea49706eea452d8a9262ad24d811919e7fcd62f84623c178d4d7101b51728a20c1979249ffc494fa43e71ec17eeea44decb48e60df4451a2fe08a14a5d0d6804632926ef8b41c4083628d9c4cf6ab2b4a22868c02218abbc92f4d7679e8e14c1a994c44d72ca5c17539408be74c92ee527c898b70a235d34a54c8d2cc1ef6530b9cb729a68f24a704266beba730f253811619622664af5497160129ce5fda714111e4f46129c0a9e8470b1ce1db144821725df4dec5d4ba80f0412fcb76ec7f44b52df57208f60bd3ee92ddde9691c3e72e828838741418f1d1c30012c02c4115c2e49cea74193ea74231df80e6d04a374ca70bf7ce8c841869e0f1046f09d37476f074f693d090eb51e3dfe068f26431764115c86a693d5493f8a8970a8dd50d3914304990344115ced7dc98ca22f076d72e373d03ed08c0a4012c1a6bbff52d21be87ffcd091a37b203b1d8020824b4a988ab13f49728f6a0b9043304aff88b76e6188c10a1043b09a54a576665b082e49c1e4ec133355b5150a1042704198f6961c3a259db1417059bbbe7b4a86132082603ff9a7206c3b9d091a1d65eca0044820184fcd59baa485fab050122080e0a4f509ffb63e53a74104c81f7ad74d27e3c80fac8e2e557b29ee49361904481f78535a2a5ebfa160f700c20776773c59fa0a9e53529903c81e58cbcd3926a9a0ed4a5a87067c348e12d801440fc9936b437cd5b28203903c249a1853df01081ed85319ab36454bb2575f40eec0e51cb373ccc14daded4c4f80d881edd0496436258543edc7fb3865f8b8d18663e4f85146d681379196a34a929553376e58b209103ab07963462bd14aa7b18e473990397016d59224b8c83751397840e4c0ba65101384bc6c2708e5b8c1831f3a3a073fc6f7b86b9038f023c4c45249ee9cba9101081cf89cfa4c49afa6e29edc486000f206b6a44e49d0315da154d60d6cca6f5fa34ef24d17d31c5cf2029036b0f99e1d4ad7ea081036b09a9d73a865d1c9b2ee9808903570298666932bc858524c1b4b80a8813b75725f729335d9ba8b0b9034b019c2d35452b2a6e97d472f40d0708eb77b42c9ac39433a733a77fd1e6f8098810fd966a34b2c65606ff3e6b6b1cb3565ca01840cece65cb7eec1635079f3fd02c818b87c6fa59fe4741db59476ece851823a31f029a54a297ff02eeda91cf9c3478e10a0ffd163070a7cbc0f159402240cbca8d378a743fbb49f80815182d6f50e356a4afd021b6410bfcc9233880e03205ee0a49427a8cb495da9a959f009902e70c9c642e8d22ed964c805decbafcf3573d01f3b1ab061432d12205be05492ea4efad169729203d102bb514d56ced6affc570740b2c09ed4de963ea655651c040b8caadfb14cb9de9f2f03c81538a11b6ef2999845e8e6060ede879ae1008815b864b1aeb5d54d5a1dfd8e1f8a3eb40aec49ee6ed2bef8bba6763b5670e702102ab09f94bcf1f7205fede4861640a6c0a6ac7f92dce51eccb3366cec0d2c804881b5169344cb6c13f2b1e387824481ed1e252f6c93fc2a323700814295a5f299ec9b82fe06fd030548049027b0eb49ca166ee238d46ef0a0c78f1218fa30ab018813d8bb0c1d409ac0868abb214ddcaf8a291b35d091a3063a729838803081f3edd594246142f529c11e75005902a35a53a614b7246d9267c7184902c3118028c14c777629345bdef4469a6d8f5f9024f0a13b9f8ed1fa242979923b8020813ddbffb3cb5162ced311d87442ababe60f16cc64044e446f2c8effef054dfa02a408eca7b374c2a398203a2270655f7552546915eb4186c05a2a131332e6da8f8d437b7c42cb0211026762c94b9deb1f7b8482c18b522738d4d006fa30c408438c303c033c701b366e945d2f1c000cfe43a5b5b20e8ff9f52f38ad4abad2fee45391f1059bf62453f064740f0ed8b031465b2fb854523cd1d6964fb88517ecc7f64c2926bb0bf6dc6e2d944c7173864c060ed005af795a83cc7bd1b1c3e80a76a42059c16b0e6cd8b0e1805c7059f5fa3b9f20754db8602bb38bf230dd820bfd61bfa93cbb09d982bf6ca13ef7e824ca530bceb6e4e86e9baa849a167c10999efcb684f27716c9cb1a73a69895059b4952e529e717f54c2c1821577bc36df75f58b05a6a2f6e4c32a78cbe82d5fda4444b962bf80fa9d94c4ad20a3e68eaae7553e399c20a4ed05df29992bf56e52ab83777cffbb9af27a80a36a47fec6892782ec1940ab6abb582da7472474ca8480755b2bf662c9d824f6da3593d499b4fa66094e8fa29b4e49125540aee4e29318b8814fc2795a4e07ea26d39a3e0a48da7366a2d0a4ee8ca98a575d99336147ccc9d4bb54cfa681a5070a9c4e49b2c66c7019f60e4d726d5ee95ad4a3cc1a567da942d669a7782fb6c6665ab27d4979ce0f47b12d362aa4e1137c19db463194c50326df69a6034a85025cdfa4c702698eb47ab8e31acc704bfb142d5a5d8da31e7b41c7009c6456505fbcfd9b46f09ee6e74fab4a24af0490a2a968eb9a2a6204a7055e9217cd44cd43e09764c7e4cd1e48a345949f031ad5a6e93a4dc7223c17b5a6edfca7184d04082f10cfbccb83e824d5a9e49c8b89a36ea082e9a581e75268de0f37e0e0d39a6e1298ce03efdc99654052d82ef20ae1df2838f522245f0a54c728da574899e4489605bf55d3c88e074693593e1a5748d87e0ce3a8f0629d252c5107c8a9e6f264d3a31af106c8dfeeaa90c328b0a1182b7782abdc8fabd3e0d82937c7412efdefadf17041fa47a285dd1d43b0f04172bac83ad05217340b027f8757709fa1f3e3e070ef80327e35bd0a692e4dfb61f18dfd357bf0f9ca035babef8dd5ecb07c67e3fb58ecc1ef84ed32c71a407ceae629dd0ea6cca03976a694ce82579658207c63ce8933a560775953bf079326f4e1e3bf075415bc537ebc07ace13c264d01d4007ee4c85bc24733e3bd11d30074edcbcfb99ba7389cc1d2007c6a44d933deaa978ee71401c3821f367d3397338f031d47b8d5062fc36bd81516b4a7e4ca36d16e406fe46e9d63c1363babd0dfc655139aa7336b09b5f25ba41b532be064e4cd00c9d6412847dd4c0ed9858b0368d3189a6e1aad1a059538a0646f7abe468a69d7d39031b2d55faf599c59262063ee53be9a9c93270f92e5959289341956460ff524e791dafe278670c6c6ebd492645ed3cd9110327e231492663270cdc49a75ffd4785d6ea8081ff4d26655a12ca46a9bfc0c82064073511769fd45e60a38ec8a0493a59b9d45de047e5d51a9961b1ffe6029bf44c4de50fa14e8b0cfa4824e1802d701b7a416e4a62d4d16b810dd7d2d5a0d4a3fa59e0b74ec68cd56381cd329d43e465f6a02bf07f23d4da655341075981b70df66e59af02eff6c1e44beaa602e7398f9fcaa5baa1ed2970252fc91774ce13f2d252e0939befae49d923941d057ed3a7784aa91a0a7cd01b16ade468e6543f81f798a4a5e80a9affe40436a81cc3ed04396a4f4d604b9026fd5dc610556202970411d56beda1dd5f426f4992570257aa437ece124fba93c07fa7263b4b6fd24448e07cdf9457d6cafc089c89d9635f68bfef8dc099f4e3ada66392c4bd085cd44b9d729299543880085c7eb38cb17a3d95d60143e024991ac3dcf5da5c070881af13f116d9ddb1da0d069b3b4d544b122a99bac0e0f3424793d3aac83ed95f301a4b6dd46865298aeb0bf662daecabdff682cfe725779b92b2c46d79c198dc21ffaae42427fd2eb8de7a8d9bc41cf27e5d70dfa5b3b67663879f0bb6fb52286d4d2b13c2452687ab7774d12d385da73df34b83d0215b704135a8e059ad5f3ab56094fe7862c7cad5e1a105d79b3a4c8c496eb1ec2cb812ad19c392dc599705279a297b7d54f3a089059ba4c9a99d4c56bb0c2cf8249a9c83da5c7d5dbe820b558d1b9a5f455f9596a0e10a2e26e9275aeb3a5334ad602d6e0e4246f51cb36658c1fa08e55b23c355b07eb209161aac4c7d55b055e9154d253996284a05179a4acc24392ab853def5224597fc4fc10795d37743c70f8d29f8349eb3ae5b9e474bc19a9a955a97b2dc0e29f84e3ab37f7f346f47c1f8a6fcb24b2b0d51709ed18312d326213a46698482eb9875d35510e129a33440c19ada91e6714cb8892a8d4fb0a3f5e45dbcdf3551a5e1094e0a326e7a8edea9c4687482d1267f4c69514e706757efa219f3ada99be0d38269ee9910fd996a82bfa42ab782da9333a599e0cead7cb74d7b4a29c5047765194ad0a64b7051f4653c93c6dc9b50e0b256a950593aed3ce70791277015d3b9dfaec8098cba922989e64c2b95d38492de4b6207b36b0f224c6084454b973ea618367c882cc104224ae0d3c6dd98bf61f1b22e1e2249e0eaa2e7e69c2ac68f3b0eb52282044675d4742a3c3d3b96e050d381c8111825563439784e278949fe79249a8f05818811f84fd5226d4c501b998243edc60e64c5072245e03ce46797e41b3ce989c09d7b2c57f5bb8e3169088c3c1d3ba407e19559171182296d4a6a9d3cc160e36bcea31f3bd5540d0c3e878efae9f81a1adb5f30a226e6d2a3e4e5a04f7cc1e86df224e66f1d2593bd388e07a1f3551c515083178ca66e496971dd00076cd8f8319281448d5df0a2af64f44cd205174f7ab2a4e4ea859f0bd64fa93031b93532967091d037e9d641ff5b30322695c1cd04d9824d266d072bd3649de46bc18d59884a3a87097942b460e408af4bd5b13f799f05f72596a81d43e347d165c19e8e49a93758e8744f2cb8ca360dd629ad85be61c1c594ebd2e9e78f19ed577063fa22538caf2bf8b498eefa62eefa7a5bc15bdf8ea796969cc76505379e4992641b2585f29855309692ac96bf39aae02e3da3e6b849f48752c1f9080f6e7ad544e6a082d3b4dbfd62d253f89d69632c7526a6c0d2d65d36192aa5e0533ecbfa18e3a9b714527099df2ca50b4d8d3ad61805234fbbfef92745c1e8a7fcdca2cf24992443c1554cbe95735efd354950f09f5344736c0d329bf0135ce8d0fcce1ff4045b395e657fb5d4de6227d80dad5c163da6cf0d72822f49e53c2698123d4f7013fc055552faa43de87e4e137c0c91ee55e3f7a5bd4cf02725298e994962af394cf06939fa62ce5c823539abfb9bc9a6df9d2538592a3aaffb54da5d094e4caf59cc4e98a42625383b319e2c3de1968493e0c41c2fea7626094e50b2c935421409fed2e73249294bcb3524f8283672a389d193245a38d47494d123ed118c56b98d1a9daf7f47477027982a193c8b8dce4f2318dd62aa26985785a83082b70e6a774dbbff7f76118cd071d426bdba22584d927439f2ff922ed144705fd97b92fabb458b228213e36f7bccde92772687e0ce544a1ea326a5f74f43702d7e621453df154db04621b8acf427878810bcc953f953532a932c85438d070f8231da7784c0778cb163f4e320f8f85dd194ea917ea31a82e0b2c432319b7725133502c18919eb3ed7aeaf0b084eeaecb294e63a3a6abc448d3ff0a1b2494ac7ca1d744cfdc0558956dad4ea21abb5448d3e5cab9693505e92207a53830f9c784149f28999e3503339ba043e74e4e81f3ec8b81a7be0a44b7d2757ec14256ae881f34ba2bd72f5c9f410d70c35f2c0a8379deef17227f9cdbd49d4c0438d3b70ae3178fa9e6aaf5cfb7bfc40418fff31dac550c30e9c98b7e4a649413de524c90a76a4e04560c346f2861a756037b9e5f1d0bc46a2061df892731aed3625a6fa926ba831074e2ed1823e935392a7a46bc8814fd57a1135e2c05ad26954104f99be92706063ae58d2985935dec05ec778994bdff8c9478f1ce9c68f1c63f0f061e6637dac076ab881d50e4b3d4b511c6a64f80e6e201defc3688d367069576dda6e5f49df5ea8c1062e28f10cb6fb5595693276f88f3248906ca1c61a38d10c99741cff98afe7420d35f0e6f153e70f7da6c54b83963f98c95da28487434dc9f016dca2061ad8f5f73c4998c8933052d0010d88408c305810460a421046d638039fa6c1f394ae92623a1c6a7664780bbed00435ccc09b9cfbff464b12735296815152965de5b714d2c431d420032b4aa7249a244d63e0469352a293a8ba77480c6c98862c952b7b1a1907438d3024e75b8c0103174268cafcbf5143a9260b35bec056efa930b5bc17d81a9326ef49522955638d2e703e5e82974cf209fa9a26d4e0022f9a4c4cb27aca16d8b09444587b92dbf6d402dfbad72b4293184d7a5960c4b3a69493e5cf582650a881853fc9622532c7ce50e30a9ca4a4646e52f95ea69215d850a3eb4e92b26609aa029796c2bc4653f4efa4022f2a8959f9bffd4e48a7c0e54bb9fcbbcf043d1929f0ffdafbbde246811152fcf6ce63ab09322870224b92afe2fb2731b927b021849f20476f4e6053ead89525d9bd046113b8ffbe24a50da1b3dac604b6bd2441c7a44674ca9425307a349bec2564a7125325f019b5945827a6f6932a097c901e363af675d62e41025fd5a92a566a643699237096513fc95fea1a46e0a493a4969c775af5536a1481cd59deeff7a62da72422f07e26ad49efe3501b03d5180297af4daa53a9a9210456efcbc4de4c06834d5236d1434781c19a549bfab972cc5bf3177c3e256faa989e84f2135f70d2552519d3bc54e8d60b4da7355d7a53c40bf69385d0e6a1fe2af8bbe09424692551ab4ed4ed75c1c7743a7ea8a04c565273c1c5ecf2ee8a49d76b0c178ca57d92d49a8eba93bd05f77973326171640bde3cf52993c4249b68ca5af0dd5782b4e0f4b9491bb36ed221fc5930a25373559294820891056f365631061df3794eb91c1c194262c157d0ea776a3308f9292cf8b4a5c96292db4484bc82919f469924ba497a3b5dc1c5de6cababa3712f492b6c0621ac60945e658ec9f362d2dc87ac82ed91565243e7c6dd2144158c5a4b6551ad82d636157cf64e7143a80dab78082a582d2956e7924b424ec17af274310926640a4e9f24b8b929a1b42c1d21a52843e7a0b3b796d2e1c1df20ad64134248c15892547d7da7d44b49aa10320a5eb54f673cb929448828d8dc55cf49304197322d0b21a1e0b37e92d726090f214fa0606c44b76bd569bf2df904fb9de40bbae2f59e4ef1045f923ee9446fd9092e9d8e1e64658db17ce404b7aaf74147fb0c316d82abeece599b2d0e144d70419499942c893542da99e0e434951a2aa568ca144c30e241c52f593de5f3521222e4126ca518633e559324a5d496e0a4a0f23796076d3a2d95e0648fa37247b1e4d53525d8f11c93db93d0bf10854c827d4fa5f6829b982c953052d0011d8f822f03073974a800c78f1c2cf851c68e1e366c502144125c67adfa553c1d8f9748683a752621541248707a8209b5a44f89a15b0b44c82338f983f2ffa09395961447304258671e21930011d2084669e7dd710de2504b3b14878ff6406a0823b8e829ed7470cf95565a04ab5e67d79b92f59bab08468e59a76029329b894904d723a679744f29b95410c1c5ace9c430a143f0258690259fdca2653104277e3206bb52eb5116828b31a6ca9c2284d22924049764514147d7b1d3a80d82efb02b99daad5652b28c10417092ec6f4ac9b182456f4302c1dd88bb496dffd974c90d238400823795597143de7f60cb634a924aaae2871f217de0febfa397e42e21840fbc058fa12c8910ded00d7821640fc9a949348d5e22aac135e89b5c319909bd64f941881ed8f4efe1d726a5acebe40742f2c06d2a7157ed452fbd28040f3342ee1046881d2aa40e638cd162d0610e140891830442e27023078f0c94a046081cde75ecd07123070f0784bc2124c40d3e78f037100969838fcf91019110369490358411a2860384a4010d3342ce7023012166904048194c08196efc6040c8187c7c0e901031841112869010303820e40b0808f142dab1a3078f2edc48fd632420840b3f76ece85180902d4020440b4948167ebc8f1b58b8918347067890fe35a080902b58e1c60d1efc0d4442aa702324840a0a0899020e1f8d6324440a0f0889c20442a04023e4093c38379cd00426f82063093b52034294e0e3878ecfc18724c10221487040c8118c1081902240208408120819428810404082e1c3c70e0f2c0004183772f0c8000b44407e5101105fe4e0910114d000e9052fc200d9850fd4a375f03d72f0c8808f3176ec28c108882e725103041733406e718306882d7c3400a41634406821020380cc220120b23800482c0800020b4e6c8f3926138458f7e504905730766f7fe9772daf63aee0635aea4b0fb6c11f5f0313460a3aa0810d9001d20a1056b01e4dc93ebda3ac360ab20a3e7f7b499fd52dde5e094210c6085e70030520aae0cee2580eb7926f64387ce418e39401920a2e7a3653f6b7b5261f03082ada37c9ec9498478d0e6401c8294cd67f95f2e7c6bb8ece01ea3253585ae117ad2b746671688fff91c3478f1d1ce8c00d1b3678201e2ae8f13f7494b1438c313a073bc8f813e820810d1bef237d8f1224037003482940487120a3380665824cd79b4445c1aa26bbd126fc6e8416871a48281895fa2da3c92c0eb5ebf183070828180bed1a2fed67413ec1f899244553997b8233d56da3e2c8403a6136403801b20946ef07fd298f65f5276982d75ca272840611baa64c60825192cedc3ccabf046ba937ac0f4842f1c5e44e23203c00096ce698efa6b4c97c27fb8023b0177a23babebb2a77d0038cc0793ca12698d81781cb799d7da287d0a099071081134c12efac62daf85732044e599da0194b891da4e50142e03726e9977694c611058393cc73e88d6f25e705189c585265d73dd35fe52fd8cc9dc4bdcbf94fee0bb6b5c4a04cc772a4176cc9cf959bf25c64a54678c1e811992663a72e533138b414c7c82e70441766c3e0482e8a315ea97fd5ef366cf878ef51c60e1f62e8c8d138c4b06143478ec6e185115c3496c7df4cc6334138f43dc7183ec4b061037d0e1e3b3c077f021b3672f03dd07afce07188915b7095da841079d68ecd00099a30620b6e2fb7ea6ee894ced75af0dbf6a3d6c71ca1c58dcc829317541e19843e220bae4dec526e7f2cf8f32c6a3f29999643040bbeb45992e935a764f20a469989b1e3e55dc145d5dffc24de0ab63d2f95b9e6ac60ab63dae09736756567156ab032bb8ad75105db15cd2dfb6a77de9d0a46b42f2d73f46c26d7a8e0dd3a0537559258987b0ac6db43bf6b8c9a8233eb9cb5a4bf905ad152b049e52ae52226a4e072d2294a6a32abab925170f23ac949b997a4352aa2602d357a079129a1e0458a3ca1a3df54731214ac0769829b4c59f519fc043726556cb711ad4ef1045b310942889dd6d4dc7582ddd54e27c59337fe6e9c607b4dd268d2a64636c126b73729b3da3ef465441366a307239960834a21325e05a1a007096cd808c20826d831594a0c59a5e492e518462e6136d08825d88e2769e8efb859c34825d851e739896f3aed37995182d3ac7925b3ec488c4c823d19e36df6b7fe92948e1891041c4622c15b5fb2ff8c6ee29f8104e3754973534992ee7c3e82d349594ccd973989274d8811477022636feb07bd65291b6984d918638411ace6e67c72060f32e53db208c6da2f5989162a824b926c9db693fd5dc96a3092084ec9244f2cc97bea4a58b4308208364cf8e709f3ec594587e0f6c646f52539e639c5105cb0249b56108e14829374759027b5f5c352cfe1a3cf11824d3244533e9994fd9f1a3132082e6a27d5f9d48a5fa97168598f1f3c94302208fe649f6072103d1b4602c1c91b25f2bee41c94d094e41323806075af62c8d4232cc95a1846fec065cd5ce5553298162d31318cf881f352f6a64f12d33878dc50378cf481eb8ba724d9f4bb499beb60840f8cc5d4ac39553eb207764337de8526154e8ce881933f53d2697742438ce481d329bbf6b54226008218c1032773e852da8234d9bb0388913b302a4a87c9ce26aaa2e70e2376e0f54cf6f426f489a1e78ed4818b57c16d57e4a792d27448924acf2bf46f1a8a9139b031bce412d3f9ed43732372e0f2aea7fdcee88d4b8cc4813d3d99d13f9a3c46e0c0a52c8b7d9a72cecee1c81b58f72a5994acbea0c42438f4863137f09e34c4f265cb1a5a0e32c8d8e1628441c68fc161a4200461e0f01fad8113884004e67a9041c6f6481bd8a4ac7793d2cbcb8af7f81c683dd8c09e5af656763d29e7a00e1decb8d163c78deed13ccacd61640d7eaea4d735c9a91c3776a03c398ca88151f904f318ba5dd3db869134b02b1afd4673b0f8a68443edc60e8423686084e8571f19639a888c9561e40cece79433c97eb9c55246861133f02955cc4ba93db5b3c96462a40c9c3e0f66da04fd217b632c31420646271996838e08256b3406364b4ea73b0932e3e51313236260446a4c8fb1b763f51f063ebae8c7beb4f9aec42b3102062ee564594afa2425dffa0b6ca6cf98ace437594c4e61c48817d853722cadc9566a84cc2246bac0e9ab1c5ef229a995c47f8c7081b18ca9d225a5c42475e806235be02e692da166315ae06a64ca12f2a4c8bd71240b7fe5ab984feecf47ff0946b0c0be595576693e93638843ad879660e40a66c3062356e0cb3cf877501a138c5481d131e4c94fe9781f2982112aa08d1b9982d9b01129b06d4a9fe55c524d5c53321205cece4eb2304b82022b7a4274099eed76474f40b3ce82562eb91338a5b1832e61f126707ab98385aea669d23281cf1342f4799a27f9a34b6037a5eb5ea69ce378ca8812d8b437395d5d5012d84a72527a2cfac9ed20815dcfa76485ee9c61ffc811f83856b91aaa937812f120a3078e1c310227b6ea58ce5f5257770d8c1481cb95849e67af1b0bba1122b09e25e546bdae52e522244686c0e7cbb6186d93a8b27ef0e0ec8f3278e8f840c9c08810d8bf1293499e1aa3ff2d120cceab52d0627db9a47c038337693c6db64ae4178c98baadd5b7df03115fb0b9b62fab92072df19422bd60c7b209e141692d10e105a319fab4374d9f527fe92e38a153922767934ea828a92eb813659a4a503a9ede5acbe582d3b16a3c9518c581a6c70f1e22b8e084c6abb2284ae78b9d5bf0d91b3bf589c616dcfde8e793ff594cda5289e09f03366cfca71e9f031f9f831ccd8230c420c35b10460a4210460a7cfc73800c6f818d058029446ac1263bff134f7a12e43efed38daf418fc6e166092d78170f6d2d55a9b46997831b22b3e0c3c53cd5653d52a043053a48803ef0cf811d291091051b33d6a7f292b72a44291089056799b1c4b22406d34188432de19103870f85059b24dd92824eb2939c0c249c107905a332e7d239c554e5903e42c415ecc95499620a9a27a36dd82884482bb8cb4963d6132a4a3f8a39b8b1e3c70dbb80082b38ed5f39e992b4b2499655a4b1df62860653db2e5105b7b9f12495c4ce4a376dea0f412ad8245ee98fc61e2544a6051154f0afdb5563c12bccaae41466830622a6e074ee1af55972be49726220520ab67ad376d29a6ce3f7a4d8b5b67cdb5a1f397c07ff68c70846c10932f79baeec25b41e3bd28d5d8188283831d5ba9f4a9a074442c1a5ea2a1db5e3aa49b11c21d004147cfbe572d1d723221d37ec3e5083d640623f7ce418235920f2092e08abf6bc29fe6ea38591820ef810230c31c220c35b4086ef2011f1045b1e1a636bba5c915d27f8ac19efb7e49276f2c509ae4dfeba8d16dd045b7b62e22951d404a76308abf1f466821f35d3da27bd98e0934cf9c4ac3697e0d4e5f8769f5aa3a8de129cfa6675b76c578231c9fbede46d77cb9d13885082172d5a2dc898d7a0753419377aecb83109ee725413753f25cd8ced4044129c0e2d966e9477d6ca8904dbeb6a996a72b39896051148f056e2bee79c7e049fd3576f64107a53437806114770b1d4bf27cf26d7db46914670779fbfb5a40b8db184117c8e126a648e3a4158bb0846c3432715a2135104a34a2f5b35a713c157b4cff869d9a4fab38c4104117c66a5248f6852c14f120c440ec19a8dd9096dc183bf3a440cc1c54da904a5aa1b3ce8d13a729c52083e899a73d27d6e8fe7b143c710210423ac62129ef1ce20880c82378f7ea5f7714130a641c9ef55d287854920d87c26973a6f9346ed06109c8992617ea1fcd7b23f301ebb43059d52ce10323fb0c952a536d1174cda7de03254962cdd181fcc2798d22066b27be0b4b947139a6338d46eec408803113df0572663925a59eb047507b23cf0a5a4cbd16972c614223cb031d96591d5eb1dd81883129e6b64ecc05645abda1c54dab4291c6a85162275603d5e123359b68e4a111d92faf72c5a96340740108618617880073d761c7483073d7690f1642439109903ef1e83f664d993ce6c0361881186b1b25d88c8814b22b46b0c75e3c09f778a41ba499941fe70e07f3cd3b7c43aff45dfc09d5ece5f274d67f1de0dbc8a302ded9ed5e4752ecb20d206de54da9aa4fcfda2989c1844d89076fa25bfa0ed35f0a27674b224a90646879a6cee22afb3e7d3c0a6df93745d96a081f54c2986d4763fe93e060c2267e0b6c562e9fc61fa352562062e43ee9b92c2c7824819f83826f735f858fcbf5c41840c9c3a416bb6103ad8a78ab182c81838eb0b192afdc6ce211503974e2d57d212cc5385641009039f5f74a9e5f926d31e0c8cde161594ee85a554e2500b83c817b830a947875bf01df705225ea853675e78d0b92e70d2affd45875a04112e304a0ef6bfa9194aede6cf9f1b25b1cc2844b660366e20a20546a3e964927de87d93e3504b4260d2042192054e92d5839a7492e94b6ae22258484a2072056e94b4959f17c44f883844acc049b771ac76fb245549912ab0654263d0ecb5cae6d0011ee20e112af027678cf741bf28b52422536045ddb54eea9bfadbca0644a4c09a9292d427a8a0848969c42312055effad3f69de1c5e8ecea8d430455269281008c3e17018043170305f007313000018141892c642a158389e6b8af403140004502e2456302e1a201a181c1c8a04c37030180a0582a1402810000502a14028280c4bcb15e5012b410b5ceb89042187f93993d85d140fdc05ab49609df91f12296db48bd59eda01b1e28d204fee5335cf61a073de20c10c282e25ccfb262a5bcb656404a527db7e23519dee78ee6b0d65ab3e55e79e4afecc0fcfef5569c172e7af9f338937b00740f9090e959b616007e45a8838a00d700320341a08fabafc451e0a1cfff95108c11dd45e57cef35f12f99236c4e07e23aae7c50fea5e6946110c8f94123bc17b04407bf50d7868c33274b0e57f200ac0ad56f94d9889a6e94049e269cd9e101fb313405600072c9b282ec13365663ab9e517a2860b3d3be7b7159f623d7bed65e04bce1ee79901838ffd334767d19bb4608f6facead0eb0d2cd94fed4adac97caa15c9460c39792636d4fb3e6ea3470fb872c9839ddaa204d0a2ef98c9fdd429d61bee9b5f56b0decd4daa4f3020d44b357bec191a3fba42aab23e575281eac4aa45ede540eb19a35cea860b63ebcb04b4227dd4fbdb03bf1a35a3a7d42daf37bc9ee2ceb731e84d1d26364feb2e7d04f742a8aaa8a07107e12c3e28cb8af61d6a42a10aada10ac12e9b7197946e5f68c201e8408e351d5e9041f909494f6ed7f78fcc71b18083172986c60490da6335046e199dde4ee047a666c95e6b04b2dc9079219213c94e7afbf6481209c4e0efad215414a49461f34d5843afbdcf94e3eb8830f93f7d2846af9f6c2a0088a40ba7534140f909203749ce89b1b450911759d347be57032614630d893be67e42689acf2f8dc6319d170011b7f5e643d0a7a67c7dc9659c48817270ec425e2dfdad8b310ee32bdc40ce7d1b023ea24f93efcf30b41004ebf0fb06bb30cba3ad0e3bf90de6e61e3f522f42deae4edb2f504475d72c1f580fe2ad1910fa2be8c7aef9ec130f7b2fb0df73d58fe31679d0dad2dfed116fe5a0861cbb4bcf30447427a712239cd726147f36211e0c2c98dc1d9ed433d8ea88296d9e36d7147060ada48d28401bf4d94c983eb665637de103b1d41024a7190aebf7bd8c40093aa7d1cd6e86cfc92646973fbe3ead7267412c8f59ba9533963f2c33c77d4843f177ebaa14da3645b5f8de6de6299ee285e3f9bd8a3759e27b40c3e32afad090a97809f2c9a822b8fcb345c13988392b04fd333592c5cefa3853e5a5535e33918ffe8d1cdf398a8534a37b662c4deb3de811f988e9742cb8457fbd0586e46defe885f7f2e06aba6e0a6a0397b92e3563d5664e4358fb6cfb531ddbc12e3e6679bd6029bb781bd0db0ac450e23cda64fd40863a5927dc292c1cadfe0bcd2e6d479b8a6729dfd522124137903d4795317896a9766d5d8d5bdd19e80a090c4f121903b96bacf6ab4966490c7aaca4d37cce3d97ebc330f819ee1037c587b6a4aa37b0ae494e9c5e1ac9c76e212b78c07d3d39151b916e6491d3cc155dfb5f0a85ad8d66982eae830306cb2a1a1cdb9dd16e0cc45fbf2c66b3bb49b06bcd18c660474a2440a30072fb5735ef6a9dd75c705405c6e34495c4db0dcdd95e8b9098012527f60bd0c6fc462d8472a7d127f06b8d8d2c83e41eee2243c47f788dbbbaf24e8954ebe161920b840b21624e94591cb9ad145799c510778b90bb8ea88ad31661e76a1540869149760b53c5cb8d0194aa5fb961586fca6ec8dcfa506bd0785482e50cc7aeef91355e9b655de81c7737a9f9566b18aca1b8e2fc3f0b810558fe8e5bad26ecb2edcfed1af70d20e177fbaa3ce2efc98a1f31bb93538c6c293bcae311df40c56efd4a7bcc31bf36771f880a84dab7edf7c8cf334490fd52f759d6da6825f5d1e8bc1819f36313c58d1306e55c5f41fba318ebdd6185904b99348beb82db2276c88c4b11014631fda20e3d8ef4197c54fb4c621dadc1863e502f45e126bf840230ef22d5e230ddc8d834e733a6996312cf85f6b6225262218ff138e12a4328921e2aee5eecb41175a7c8dae8b5e884bddcea219e67cbb1a6d2a943408d509d6a67a7d233614f576a84d6684207c6c10be23335e553682ae60bdf6af9ce1586947a7f67e55122d97cc167538b84a08be56e3de910a947a191edb50e6668b6f314ba04770551a4e6f79e9834735680fdc0a7b6e79774bc413e1d5cb7ad05938ac9fb28e87f5f94fe54de9345e8718338b938a53fe98b43b8841d2960911ab25938d0cd3687111dbf4fc86cff245b65199f71faaf6b5d1559015e38b42d5f8d53744311308ec26eee79f86a10623d8409417dd4024169ff0fe2582323bddcf441217a57a108f936e168eec2c1383d558e16cc8941b73c113910816788ba3fbb8ef98c56d9afad909232064b8ba20d3339d2389ca05fe0da9f8c4583934c301bc6eca2b50e3c3c960fe941deac60f0bb6a2931322f205934b12b11eedce7103615bd628e8351c38fc03d7ca3575d58e1fff1665a452eda103053653cbf35f501cbb51d3edbbb4748f36a57314c44876a6fc31882aa27cc2be47006918a01c3af95a790a5f33b306cb51007f1a86d07a8b4148c071b6bc640fabedc8f470be4a6cb0064023c38f5c60908eb0808c48169f4b853577a7e6b91727d477dd7deb8fa5d8878f0511762ae3c8bd0634b8e8a5a91c3f4a07416b67c07165085b2078c28d00502a99646dc78918ef9757e45135d46839f481ae61fc188fd77a5e503bca7fd8e86badfd245872dd0aefe4a1112e5198bc016bb7e0752fefa4e65d858a40e352239cca58925b16f28dd5a8aa1e109aabf40787ed27db30ef0afdb5eec62a1f89427cb0d2d95190f9d1be9e913632467918328cf1a9c952b7ca256fcc79687bf49c97e05e18d2e1c93cde32fa57ea0c73306ed22a6b651c44f18221ee87cd8f737dc1709c79441e64306f03869d6d0d13ce03c976dc9a889052ebd94293cd86e3018c99c0796c85700565917165b557d61f0397b9df336f6564e40e0eb8d6892cccce3771d2dc5b0ddf8010f0b26ea59d00f5f88953eab86cb77f67abcfc365485884e1d3f2a0de4769ec6168ceaed12027636cd6b349c16f325be3fb195a0cb8466dd0f7895ac27b47851ac7693a52fbc3a61b890788fec113fa99485240ce5824f78d08a9b411546b072628f74ad1d860c0d9dc12c6957c939fdc1e022698b4a580e037a54913f9a008228c21d609207eb49764af300f20cdf3bb3a4d2205e615dbc4a3ccfad3a4e423c86ce891b1b9df6b51c2a06f74b00070ae45a29ebbae188b1744b5e7a9b79eb868e4725dcb5761998735b77e122aa6c2d114f3f7f711877c3a229a630ff2f8fe61dcefd3efdf44a77b203549772e66db295ba709b862774312807a22cffc8c9c49a576de7202332d78a5e69c352a6e6d8295e6ae5192d5d896fd8da7bd1a7a3a41a0473e017461a4eb8f528d7c3c9ca6ab419547e86adfa3a5f6958080582f2b155d914aa4170845d6302b16067a7998fef993a10c08200d3763077940cf2d40dc283071132359d6b183dca58073748dd0218334536b1fd2d1029fe6fd2cac30407f6f2c988401eb5a791951776d247ffa333def6b19d8616dc1802667398725197a548f97f1285d6d4070ac533c9f37ad8dac47418de44b559d124afa67d38a4fdb8d9bab86cde6e7770919bac6acad02edc3bb522a1db29949a5aed1409e99d03d1610301829a687342073d4263125c8317fb335f11dfc8db34a0d1b29d9288a6745f9ac5d1dcd9c4691a0d845ec6461af88fd90297acb0ee334cec4ebf900807848d7b59128be4d28cb1f26b0de77cc88e358f7050d39c9798347b69d07b4066c04932f0d9a825ec1dc382c205eacc4438b489a840ae5a30b05140f161aaf815950e23e18d54a7b1099fd852a450857e1cdee158564d114ea66265fc756dc48d5aaa75013ed5dceeb3c80be74ae7a7870964dd8b139860381913a50e1b792e8dfd1a60f8e33d47e627ae3c2b52e2f43559d7466e0dae13dc1e0e76e0879706cb46c77ca85be1fc9af4091987f3137e34b17c1ece9f7af60f370d2b80bda2f31423c526c739de0f409ace1b227add63311bacfb91cdab7f1c6dd32013900d0641069b3cea81c1958bcc3c62ca078db3d6a69bff3084cd11e2f6a6d60ccd33447a57a804b45f628ef62de9dc84120cb590b28e24937c7864e38ce1fce84e38442313e92b1904186170deb7d96ead9c4c1b9396e707f687e334a606f74c4236d566be88143d881151adbd3eeaaa4aefee53418c48cd2b983897e80616ab0b4739680fcf4aa5046d678efd9154791a282869c5208e0bf82c9f242787e97f60c258bcfa6ed790fd6680ee067e24e3dc8dff11b637785432e8994a545beb5290ac159be4a34b69dbc1b54d8d48140210070c8765c4d90f53d5df14afae41fa8539316265e7ff97da65aa37a6e7030b45b194b916dc41f0243bc6d2fcf5dc1a5f24253e9f18ab3d9e52a799d6779872151a24259026b700240369d54ccee63eae3dc21df4196291a6720dc5d7b373032156475f510ce53941fc14ed197f19dec70a70299764f4d267bb8040882e9c61026d64adb487168a18f083066c96a6b898a55436a4be71f6ef2c771930a0d6c8888f10005a8b50d162fc7d2a901b0d45c726b65d61db0d60e82ccceb09e9762ae8d325d440b56d7b4760f2ca1452051a3c39776872ddeb30a7152e586b35a4d754e29d368846c3f7201483d09eade2b00e96f59f291f63e7040a614bde8ca343eb1a248f6c455aff6bce4b0bff9806b2b07740d739a3c517846547596dfc6170fb63cb4c55c0f9ef8783d8f483000b495d1e04751fca0568a4120cfe3f9ece905aa2210237427b2876f2ed078b3b1776144ac9ee30240bce096dd432f1a16b1b9b02c02e2372b4990469d26ab805fab27b4ca597dec5efd3423bded6815a5614305577b7511076367d085764c8d599c6f99e3106d96c8a4875334e85226082c94a8b9a651f84398838c54493fd30c56830784da99f86a72bb28234245c5a1e151a415f12ee5563ca96cd3b73d3813d0a34fc8d824bc33a97e89161710e3abd4228b7cb85794e30b426f18ea3414c90a448c2957756f50ba7dbe898675db31f7d3d14099a1ea5a25fffae36f00b7f5e17c3fc21c4cb45b9c3c89c09a21332a9a765dac9489ae25f04a5820f898cd0ecdf08ced45a393b01ee0b3f4ce351b512158fa6c9a96d161ffa01e78e6f06ff02d2d323b7dcb12bda98ccba0e3ac26ac5c84926103d1f89096e18aa8fef93a5390830f9e03915b5c3a5fc9313f37acb8e3fd393f844de1e77c96bf29d0c0aa6d3fa0546fd58fb9ddfe75db22a90c9ef3a9c46fa321f257847a137b231ce8eabed7e119633fd12904ee673243304b6291222906c75647745efb5cd4f634bbf22a521ca5135dcbc34c3c714e086608913065a9d03c8cb98024c546e92dfd1d6eb1c45a421fd777bb22f973f80de3959cd76994b3853a9bb7744faf3e81d104dc6de3b6577060b5fbacf0d6b31511abcc8cb30006b36af1d5bce6e6c909d1ce302736db03cd92c465999f24e98fe5049a21b83087505620b5cd1e36cbd5fab6dc8304905c329eb4cbc164403038a0dfcb591e3b7a351dfee759ebfbdecf4c5502bf101594740817adf5f3974dfa9f03ad4066efdb6d664704557972e8276e953abe026d749930edde307c22c536ce537d31648694fddd81648a118b77cc65a807e4c9fcf2ba7560524dc308b64cd1ca531ca4b4ad9e909feb6e9a26e62b99aa81ad28babf4b7daf439ede0cdacf178c713615965e5b9b9cb9b3fa2a1d4a3194aa15753c997372619614b3b25a9897eee74ffab9df7cf5fa8a4c2c977a1efdd98ca489c08b9a5ba74183b0546319a016bb82c53c8a73daae72ef42b531f5fa1bd9d20c62aa144c6ae2883797aa4011fee2ff788c6fd977fa4d14f996f3c93ab36c1696f02cb569ce9f637d9c13a132ec8c8e7815286f592dcbec23a5c337281a4245c45e903855c983b36080aa94b25c0b47d4eb8a6d240b5f15fb897a680314b30a3526693ef0b5daa931dfc1631bc550385ad7bec4dcfa392a8b98f456cc6917fd4c92caea2eee253047f13285bf23129c702fbca032dc3c2ab9fde364ad0c9d200bb9bf446ba4ce6dd36866fc0cff9c04d319415319000becdbb5a180109261289823da53671b50510af7c9cdfd7d78ff6dfa8879621a00a32892e0a64ce8af9e010080a6d891cd8200adc4fba1faf607df584a0bc4ec3ef4efacd5f96a7f7624505584b8e78702f2797ce13b447e34c02bb8973867d517245766a0d9a14b86ed395936e8c61a180fdbdff8a150294d6e9a29363c1ee0cc9068f37630ee8813bb182fd8b5d17550c3a0df415ba9608fbecbf49d8088e7512b5c57e01077ae1822a45ff416c07a71cc9543315aed39702f42c6f0e486d12e702e298fae6aa55a80095ed3426340041c19beea0db49b59b0bee2830a2331cb2c6f76a94aa994b8bce3934a7c1d664d4f9b7328d085bb666173d6d6e7470febf8bf347068fd331c61d09b704246969ce2e1631bb4973febc65952c65ac5afe376a617649bc59b5775e3b06589a51edcbd0e20269ab985530692c950e651c51586f11c5c7ae4a43ceacc4c455a1bc7d88542dd09eb114d58bd308820b722382f863bf9e2b92746ee7d5052ff0ddeb09a0b75c875b2fd17a69cfbd469c46ef3003bd46f33abed79a5e2cf022b5173dbda055afe3853e244877a5d85d3eab9e1108ac13ead1d11ed5433a0a3a812ce763567bd4c3a6bb4523929e39ef930f92ce161d52274daf898e1925b49c57edbd76f4c2f65e9be472e472abbc16eac5b2d7545eeaeda56df65ab4d4c48b34af88edb5687537dca4ad5c158d975dfe75ac3d759c65f37fe3ee94eea4dfb748613db41888bee0c34f74529ae80f884a0a970689a96921858ee58c84df2d729ec4761b389cf817b96e18fc63c726211fe6917500d7f0cc741e5bb1c6bbde9be9fdf146127b111ffdc48e841984a9fb1fef368e61f16c9038a352056af21fdf4107dda6c132f4fb0fa3a3ab671446408836bd3432652136de6ecf0fabdc1990e828ede313dd225bb47c3cb102ea1842df1fb81c70c33cce090ecfe837e7c942189994c4a212ad49366b5f8aa8fdc713d865152417f089a68b865a5cb174099a8e4de0ecf88e10232e8ca10ec5202968b2ba300f302113e2280796bf4cb9aecd66c5d4220db784878c962fb6fc6ddc802e0fc1ef84bb21913c9dd6502c318af1d4a3ecf2aa3b36895512dfe30d919a4884522b9545d8a48088201609630b8c2c0166d3f6bc5f712517589900357ba0d8c51c39941038eec0ea4390995dd11ef0aab39f23888de7c000260328d38207e7108ae0d8a4ff8a15255e6c0896bf022065bd47b24a910c772bb1b6c634af203dbfaddcc414c956bbe9d4f414878025034f48f1a0d2721370a1017370691e23284d40f94a4c55e7e80ea4d8ee5d94a141a3c59e4897595791b037626ed701855f744e8b69ce40150a328edf77733cf58c837f2e63452c6841f4eaac652831b296408c567304623d3616b98be5d3255cace5f58314c166ee2b96d4908971079e1f9cb530d89cd2efcfc13791350bd49e3f0576275c1d303f2dbe7181d49660355fcbbc83b206852197f97a86f35efa3339d4b00307b23ed6e6491145393012e5c25aad3869724932519e583bc363e7ba20a9973bd601dc2563ff72d4ee482e67b10e5644b1cbc2369e368d2ad98092bbad33573d1789fa46524319e954dee88b88212e0e9baa27f840fb4fc1dc8d718738b4f91c58e18d40843e12b98e8c16027fc14f72b89c915b43b6c0794647bb2ac0554026e5d4dc6d25bb36e3dabc4520e2789f26c67c3a97c0e879768ccfd48a465d1e25176bd9e7dca8ffc8569489ef345acd7e853028fdf40163320b17b3b631bfa4c2a7b1ee3920fd4043b418ab78b8d08023bee8f62ef6222d439b3dc22a07fde2d09e80cb040f85e304d463b421f6dc6c740133f848a5c7b85df8a0e8cc9ba9d7703d05f026ce4f4c2da88c08a98b6776dcf4a5a78281af14a5f9757f74af544821ef13be73209b46f60225ede10b9eddc2088b5a8eabcbde7bd8165e19b733d39f389c598c2deeebfc3a255be17b1548f57c2ec2e13629c445e8c67364c5b29bc5db054223a59788d0e25e4cdbe00a64ac37c29d11c7afb6a1f72c8b93699b4bcab6c8a4dfbbb592826eeb97b4055001be6eac48f0de06698d370f44db0d2bfbe272615901b1505ea591cce256ff0b1732ce79ac0ef1f6cf765de34a0c6a6d3322ea000b9a86a37ea36536356d693d2be6a67be402c0d5c47b85884ff6dc2c9a2d34aa80199c00bdb9b5b356e4826a9662d18d078da4a83ab956636e1657f9a64f335db474dee55ccf5bdd78f47721c933f09d2acc7ff661335ba1963d0421bba8ee311a9c9a70ef00394f16626ca5461d6df59951467434403aa9f223723893edf8a0bed0e4a2455557b0ef7b07e05baa2b0a075db59629824d07adb468208e99c70474441c6fbcb03270f62f30dbbeefdf8dbe5e859e8a6f93370bb54708605871a31de84842a53a1f79c29858f22b8bcc1ae712824fd65635300267586459498721ef2c17ad952dd054d91b1d854f39ee846ca2883fc593ac5afb26fb2e8a07cf0a124821d328f0de02dbbcd1ad200feb480e495e6e20fe5d3e609de552748666e1dc8546b5dd7b096471856591044e39df0a9d6068753c7e9a49fd125890ea45cb422ff864d945dd272fd04d5ce50f848986a6d5dbed8bb38e2ccf2f8d9e2ab1d24f57b3eca4e8643ef751e55b7f785c10bdb9db7fa12b7d5e2c87f79e3c37fc60ace07b5b3b74ec8c4665d31f9c32efb80a6f9dac05ff166c1ce475bae1ab01d8b3c9d81045e18b1931739fbee4f1a930ca477a2177949383944a82462a2265fb15fdf4bd6c802d25525dda27cfa34a2f0945d18dfc8a3460b8647f0080020d36cbb5e04940db199f3bdc3afb2b69bf916b14b4ae4abe29b6d4c96ab35c346dbc01d85333d0493e7543cf9d8f8379116728807b8473bf4bd85281595bddffde3328cdf2e58cdf7b6b5930d9d84a73ea7e639f38bb5bc0a7e8b4d02ac3412d12bd6825441f937397a6d0da4df366c80ba629c570438c4f17f9096decfc1d6d1c3b71f5568f27355f5143ab3992121bfce92f867cfd03d4a8f63dd3ac4334547edeb97dcfa5122f79c0338f2450b7f54b00b6757af6c7c8e5558060458f92ddefa38f9eaa7ba56de8c009ba7da844793f3acdf909000b8dcefcfb461996c95a48ebe7c18ec5a53688a698607f9a7e0ec9b1c4ded553d34452d7da1f9b529c7518ba849ec9a63ab8f08bdfdd629f5a133dc37fcfe938f694fed28271a7953a92dd677d4d4d5e21de4747923d01673f36bb1f057eab26644d132081e04ec3ba1e3a5b233c7336a75e40903b079b5c256625d1799cf247b2e428e7320c4c8d43802ffbf11a5e8a701a86b3e009e0ab3708529cf052447021d5b011b1170ba2c660a05360a7c410f4f749fedee45484441929119728fc010bc4bfdc14d7fb7ded793f8943e151c8e64e3422f11728f149374b09075a631356cea10b09d4e5e586c0a85b6fd51a1be5f693f335c119ddcd72499f53019c667b39215431bd067947c5337eaf88cd1732eb11bf085383069f0499714bdb127f95d5793dbdcd86e100a6d33c680c590eb9b0545deb62411378042ab16244bdc43bf805f27ab910578ecd5225a9d749fd4e31f56b0cd90d874bd99ed4d0569462d6f2492a80e9470b0791354d0b08648569d4687c8dbe0bd4718c59cec479256b796eb5c86d11ec0dbd2abc758d01513b3cb7875efbe617202e868672bf5150b618de59c57e8d1b1c7adfa66f380d8984446c244932fd8c346ed5615e3fa460d2dc3348300f945e3f7622dfede037e2d8f61121622e12776f4f4a81b0b9f248879875097261c08c3fcad13ec4dbb06bb6eb08dbdacd032c7f6c24cbaefdf78eeca6900b31241594147513ea5290ab607412298393fad525c88bfd0dd4c9b50dad13ea50facdba9d7a36850bc4b26eb557f81be003d573b11c3db6fb5fb2aebea2b608f6c86d080cf748db66e39387633656683b0cea33bb23c3176eee48870742b97b1726d565a9a8a6876ef300c2786a4e8c51f6989ad9a7be3026114ad8ad7bcd65ec19fa7fac566b8fc93bd91d43f04d822fa288c681aeff8bcc2d7575dd933b9f9bf744315abed0cb08bf94d9d410641c3e85fd3f1f4abede34877c51901322e5324039694472ce5b48fb080aa6224bea56f1cf5c312358a5394da3d2f3c4682d7982b4c461556cdbeca09418c95a42ed6939643119b0233acb72540fabfbfae748257d814b0568b2e4fb8808c4ad9b3e50dd0c514a6c4a0c6bc1ac22f06dc8aa3d4bec16cca4dd297d66ca6eed2d4107fc9f97500dc9f86ca7b1cfedb3b896d4b1d0ca803e8f036b234892083b52208d94642ab06c97133bd3cfa0049c93285c1b1572d0022ca2fe0ca4a10db8b4f10a8358b954e28a8a491c0d2849d70e260c723201494ab4730b62036f5274801351e1581c501487c075eff27c9ca86b1524284d88b76793168521022b0408f13b81634c0d331c5ae66a46d1e8aaac04bd716888195fe9246993145d701010bce7a8c2ed670dc21214c490559f8fb28cefb3b5621a641f0d11758ce592b89dc7ee71af0f1652ca16048deae07aff30e0174cfd6ba48f1fe496c4d2973af939b152f8895d15da431482637419e3757df5fb4d059224f718d3a83c5b206aeffe9a9727ce3747c147beb129850cbad377b128dec1777d590a8f13c4c309e052062780aa72190ee4b78e052e4a64af465d69d29c56efa191698f7638689de9e7ecdc556d7db1cd186413f06145b3acc085b2f7771851b342149af737a9a334c680ec8d45ac2d476062a234e073992dadf7a8be86869b1f25d680d1e2b18618f20a6713e92162704b36fa066e3ae5292aadc21f28783863057c07d0b4ddba29926e8929304acd0fd976536733741d3c0c87a235eeb2f6c6b1cb0b69c175be3a6b1f70448860a53f5a24bc0629f4554cc2faa459a19cc18e3bceb0f3e08e379609d973d2c73d3a3ed6b692dd911d400b9998cdc5abcf50e25bd6ea8d3674fab28128ca6caded58f1506df62abebe037e0426d36dc02a9467f715890797224514215d368009ea04f1c660aaa150fd1428b05edbe0d9b4f432188156c28362ca1cb9b55038033a61c5c0f285ec18eb03f7b2ffc92a404c1c0a5e6a276e4f2aaa4b0e4e086a6a6a85d07538d01cc14523ef79d6a0c82afb0a03476ff3c17caff8d864af4e1d5a643e8f5e3cda8fe2d8240d0658e42b851795b614df42cb3c4995fd969e8412904495c255425a9f3817d8f94747a896c17a394b7641231dfc77617af56310a8f565f8f8ce50fae038f12f9710afbbe237a13b3edc42e98bc578eda9826f81951bf0182378e89fbbedf155bbc64f6b62df85ac9b0b32c9944d22cec2e6948603317121878925bf96c7f6c8e7d340188fb466c8933ca257953442787baa6a42099ed3ccafdbff5da7f8e65efc76f81ef6af11e31e4bd07d08e0b873eace86049f62fa4ed77b6934cd3dbc94e119952fe8e119d61f37baa2ad39429adf9109b08d3ffb93dea239675405cfe63b1c5482242ae403914fbb8377c52ce93cd9f9cb8b3ea3b60fd393c4b000d9803fe53af806708c1c2f7f6142cf47e1f99b1d97cb07fdb84d1aae946f71037b3828fa1543e5fb82e06a8de643a406648d638f1dcdb3e5ed817e57103d881ed1f7f432ba5e9fa59f934fce77248eb116ff7c8ad4dc5326da0f84f3e630d444d625f54b9db449401bd68b1f851ffe5ecc6679d8c837387105623d02e0cf246a58f7c0ad6b25d6bbea8a9f14de3e2da9e715ea9f4557f4b40793a4f79275a50e06bffd0961635a495c09cc61c7e8e5abf6ea2c8b8c7025d4a99666a4849c35ddf754f03ad28435761cbdf353e3cbf2c2cda07dd7b7d14b6bd899b3aa5fe912fb59ce3b39bf4366f63ebd11f824b07c528d3a697cd2516561cff241721770ada7e314be12a90df4f9727c39e9ead61257bb333f70ffa59718f8afd650615bd9ce1332f3101c788b5f3aba9a5e1198608d97f6b8daae4095e89a1a29e8bb17d49d74d4b73b876eaebfe997ba735ca16a9b5fcabe708ee12b3fdf7780cb5f19c806f2829f5f85baa0bd34d7d69f4f3688a81f252d6c2cc6d56e582bdf50db6d093aab672a1cdd771c4d2ce95cefb74b6e2a4d4603ba832002127199bd4f1fd1f31a2d4cce13a24fd93542f19f2102ac114cbef03021e26df2dd697497207db69d1525d6430d306efe7f62059375d3d881df4387f033577c567fe3bf3e43a6eebfe2d5cb8228e401b936c3cc491cc3d083a4a118ef66b497ac904db606c343759302aec0dd257ad99844ee2d5da3d39c0a2f2540bcfb3f7aa366dba3332fa5b6347db2f04e43e5a1f815d17983a0dd5d7b12eac6f41e3c3ae00831ac28de5464359544f41b8399a8f2f500cc9651fb4fc5276197fdbf4712e13efc8df3290f157e3067e8d725870c3b9882d7233bd7f3f5abdb4a0e57f2c05c0b03aef6e6eadf7aa81eaeb7d284c9f9c45ff6378d97d6efdccea6451a69a866d4274bdbe6e20ef29a34dc0c4337ecdff323383e04da30057da5bb1a10c2123ccabd334c6d37860c13df3290bf84af2e902656fc00317380530aef8f15c517f97b38d4c4553a4d901dfe2f90ebe14e3c2b789abcf58818686b769df325b8f3793681bd58bbb774b8d42b9467a55df806ae7625ba01f63a1ea623faac65c60413973835feec995b468c2eecae957fa128a2f022fa4f6e5d82f3d287a46577a1f2490e3a78856163fc185fdccd86c25fdb4ccb98fef61de0ebc5c26975021ae3104d1fc74b7dffd3341119bddbaa294847c845464200fc73d02602685bef279d0c7d8bbf03c198cb83d80bd22e5014ae8ab77aadaed46fe230f442adf635b8aac9b0a11574372063278e2dbeb2f41bc9a54099bd8dcf2c2419e7ec66c53c4d59052d712f5bf5ab9b68293cb32e6b4b193dd032f1c9cdcd70dc388db61a2b1d46509d97b914a0f4fe4f70c93d867fbecd46929e0edde64c0b6fd11b7cdf8dfcebc97334fae24f44b91a05a572583ddde7fca4a8953e2550e11428ec24a4208839ef95cb98e8b901a0e61931b03e987dc5934d453932b343802a46275f8a8148d519bc9a0190c1eaefb25ad765f05ddb989eda2b36f44da0a66d2f09d9f07bc79a3606c00e3b88a08682d88b48cca9f27acd0a7e592cc809dff3a76772f64a01783b8861b86319adb44565aad94a07b3d5520869cabf792bace920f5ae572f8235b00519fdd49f75f90fec1f5c73b398c3c4b0c815752275098286be4d9a3bca50be701029428d38f80283f47800d289cbeb4a07ed1bdf628d32933e5a8fdba1827b65eefad5b87fdcd16fbe732227559a8bdd14618a42383151522ca1fb1903c87336ae0dc8bfc9d50c4ec9e02d7857a2c122ff5ffd7ee5b81a1cfa69e59483469f1fcb59988c71f0bcd23e3aa8a73fc3e808651f992b655037b13051b469c96c15af80dd488c9fb75c5139d4c9cac1493070b54c919f23026ee11496cbb6af7e90eeb0f9da6c1a577ef83adf8abc4b317e3d11bdb25dccf7f0bba2ab3d47f6f6d6937413635e9a7328b8bee0d245cc9717e5f5003227e0a65335be2e39ae2712b84e108cec709771bf5b368c6ec7c049f61cb8e8c12bc8ab6b6cfcbb59debcf593a77f8186bdf6808d0306551dacac1bf89a1b50fb8d505ba5a2e5bc801864ed80da3c703ad2345273f6567cf5b77993709c765a27849b8a2e0a14e31cb1599a6f132213e0db39dc7c13955332373cdfd42eba37e2bfac33be68c09d31e65759e78b5e2178b9e576a62e170f19c5ced8f489a1b6a407e073957a42598319c98a268632fa3d1cd140be9d2240eff48ec3c99d922f86e3ae1483212233a1c0dcc07b50acb50c91a3c08228358f45d782d744a810f7c92433280059afd778129a13d4e2f7bc54d67124b98e538a2539b2477ac17c64afc71b29cb173f3c5f281d748a5fe1f3d1f8b71ddd7a9eb9808104bf321fda754b4c2c34c605436ea01f3f76119c917712cd34e951e6f74efca8880363f1e93865c7f57bf9024052e2af95d9190cd2599e41b7519f7b6d0ac5442894a88ed740819e3ac7c7b77602e62d6edcf4f108ac61d0f40bcc058c1c238f6e145dfa0f2ce45eb85ea8e054c0e2f74ad9c55bb39c7912e462ab90bce8a4930a3d0d2b96256964286f4d3634b45548e6a3165f61ebb896d3e3da091ce4c1706b383dc6ad3e3957e1c9d376990e9b8a9f75f77c41f05a596f789746ec2f20a08bc38ff3f63d110ba1208126c6c73c39fdf0a6cf0c338b67cc16add107599c6849dd1433908c6cf7e913216666bbcc9bb46473bd32b51ead62555ad87e2ab16490dfb4dad823d6b89c63309d8dbd46e99f33f15e82f71dca6e5663877cb986ecb932d1de56f18a687add963561c17c40871bf274e40396cae2b42f863453cb901dfaaf01a489a1fc15841e494df904c81f494defaf090af7139ba1a30f318a24467b1fde36350656daaae3c835386c9e9b04a2b3bd646420c8dc00b7834d0e96d5613cc41bba09205585e669b94b70c6e17a10d1f3ad0f3fdb121f198276a5753369856f790042ee2a336ac846f4910074640f4b2693f402305b498cf144a4d2f8b4fda9b54b9e355e744116111b1ac79e544e86d6544d1dc702c801787f7e1513c3c058642cc3c814a84456e0206a10e205950738fd2ee2225055bb532f260dc78e278927ca4382ef05af1184530fb109a9580c7c24838cebcf05fe42f10c6c702a61a3539f905b8c189ab0c18600f00da32b9f3c1776915212fc28266e04dd0384f548a290b2c108208a5b3502df4eb3850236fc4c5b4054eed48c888cc7c838a923f19d27a961beb115d4f735a62dcf5a6d13e14b4ead17024f837162a600cc428fa252bbb6022a0049fb800953598f9aeb1f488c20a413b036683db29ef29c61d02e9dbae454d8fbbd76d4275e02e8ee2a8e6d24841b925743b95e6c40fb526a3b6f47a9d5b424cff569758e0ae1b1d216b8219e5bfc0b4cdb78b93e2e2cf0c0c48158ba293e73d94c8899acd1eccc3c00f3e56e4e0cf910c589dafcc03b17a6a86fcc7ae17af6e0052daf8af4a2ea2fdbdd7c53dd292796eab60184f9a48f548eba4641843d963e749b5abf3996ea49b452a18bce8634fa7e204390bd9d6a5e868ec46024078e61e7b009d5ae213b50144e43729871eb88189174131a167f57154e8f500f3a88fbd2882d6d1037051b1f5857271852998d4cc6ad25f480e48b39225f00e588e2d35814543602dacbc3993760b46439330f0f0f0f0f0f0f8f4408b7b60642da169220934c12709a62d0c82499924c2945c2153b10b2371bfe226df88bb4e111120004a809b60954097e2e9b9894d64bef6622f8f89fbeaab288e0440973919512748ee42118d5f14b9e56baa934046bf23fd7c8bcf57d29046bead3065d1a4270a7df6b3a7e6510dc9f79ced17eaf3c5604c168ebe451f5c440b0651a4229394aec27080826e6f4a11bddf794d21fb8dc7e79645091b39ffcc0c7cd6ff99fd2072eabc4f28b1bbe993b3e304a7ed2ce31b53d702332e99832c60d3aa62e20850e3d247a54b209b1abdf151d79e033e76e9f3ceaa74c78e0aedd76c42c7d07eedd44478a7442a1c30e6cd24df71eb3eef6c460243aeac0e8a41954d2f8aa2f163ab09ea4e7a76c6ab2480e9bd03107f66f6352bb79b6194f28fd24bd35f552ba858e3830c24b5ada0b716bf5140b1d70e0920c6d2a395edec0a605e9a96336154bc4ddc076e477bdaea30dfc2699d484984636b05a952309a1295407915c031fa228b3ac4d5ea1430d7ce99590db22d8479a7c816698a046165c183b1d69e04430fda2a5732b59850636e5ff52dabe22784ee940c7194c2e4aa3fec7e0191a5a093bccc0da298fae9f2287ae0040091d65e0b74e86ac7531ad628d2f96091d64e0be7af3f84d9041ccb278858e31705ee14993ae6006500a1d62602c69d276a546c7af182ffe863942471838538d1194de2030b8eaa9f53b47911e1a5a37b4701b5b58c7173839b636f13a99a660d3d09a800c19bfc5692ddcc6164be8f002973528cb9afa2ee652e90213cd544a5a636d71a3c8a0830b8c656df98ffc696899a0461643e8d802db9637a6e99cbb337566bc16cd0531217468818b9a1f723c8e97c814d40e80207464c17c72434f475f2c7039263da6d2ba4c075d175760f285b28e49d345c9f52302001c74588157dbd1765481bf9464b092639b35561d54e07263aa51b24fd7990a3ba6c09f893c955939c6a44926e8420134bcc8c2031b820e2930ee934392e6fcca5eb14581dd7ef10832a93a6d1d2830a92de99fd09427b0e19931b6a6886de23981976016df57c5c494d6d1044e9eaf7972c99fe960022bfabc3372d6184b550a828e2530c9447c517a216372130dad2e14031d4ae0540af2d276356cccb8b1680b1b3448123a92c08dda16791683b64b161a5aef45165dace064c8906146e8400213dc72c62da12a5fad34b4bc682fbea040a22d6cd0c00a741c81cf3e52b724a6061d46e064a89f529db3f4655b78e1c5df480a741481bd8c599e73482764bda8ae00e0830e22b031588cd99284d0d09af12ad8c2c68def22cbdc1018b3344aa387ddf6c408810f539a829f655fd0c8133a82c08646fd18fb7389681010981c299808d2528a12b1fd017b155f744e61f132d34ce8f0011729a5587e0e7949653de0456e322969723a840e1eb0a1156ab3b492ea2b848e1df061229795ef46fb5f75c05e30fd26297516858e1cf8d515aa112d2774e020539f3721ad4517cdc577910de8b8017f693fec53d561035e82e7c7b46fd6a6fe0f74d4800b2a82d27749fd43582cd041032e4347d698d3fac68d093a66c00575b2e27a0e49716441870c8c2316ac656526653978e70d16e42c7642e634b40c72bc424d93f2e8d15cc1e5c632215483686879f137be8b56307a938eeb26522c8bc9b72d3858c1c78e393d2b54e98edc2ad82d993d49f34bbeea34b44ec0a10a26694fcb885e961d8023155c081aad5f4354b0f9ec533ad1d77b0d1ba760dc74e759164bbae427430613384cc168ae9462f48a3a5182560a6e73f05c1da93c7fd0719082d1fb0fa1b59641e48a718c82dfb4d737ba765ad20019324c148cde34939b1afb6a2ba16043cede97d4a6855c1714bc59d250e215a2c8f13ec1295753ca47ab7e7ac98681c3136c109d22c9f3b213dc858a81818313bca87893d488663391db049bf37ed03b99e1d0045b1b62e792a124f5c7ac58173832c1f5f9bfe8eb16536d16810313dcc49c543debc8d71cc271092ea5499b3cf9580a32ad21705882f5bf0a4ae4986efad29560824e253285f429247d29e1b7490b765a5426c1a694f5ce257ed0693949b0f6e6a696af4d4d7d91e04f2f62ddc71224b849f69533a8b3cd177f04232c4fe868428e602c9d6fb808e9ddbe3682731119733368d74d9f116c10aa699b7f4cc58e2f824bd52127ab5ad4c92b8249e94ca51ca39b49cc268271cba147969d56d6112238214db38a568b55e21f82cb1075ba25568f25b9214c6a3aa29e489242b041e4942da7ac9f7b6942706a915375064b27c71d049343c65c2f2243da4a05c1997c8b582a8d49896a2050ad512540a44a9b4889932b7fe0c4ef42cab9347ee0b73af77bf2f1f217fbc08b88192c99ce072666f55411fed903a7f28ba68bef114b89f4c06627f5131e6279607325b36e0dbaabedc6037f7e514b345ed2d3d51db808fa6ba37bb56b291a030e3bf0e719218dca98775bc251074e4d889de9ccf72c533ab041582953ca53e988983930d13ebf861c52c9905e0e3930724b8b03a3e2c99437a44cf79b84031f548a6363da1bd83c39998eaa615bad1f81c30d6c88419a92a939bb841c6de0bfdf36dcf7eb2d651c6c60f37f47b13bf5f821e158039b1b5457a8cc0d42ed345439d4c0a4fcd3bd74a3c433a3ec091c69e07254b7b3131f0d7ccc794b6e48798d2c4ac990c1451238cec0e6123a57764b31d794190adb284a4791e00d82a30cab57a6242dab68b9d4aaaafd74be105bb33cb5eac041064ec7dc91904e9f255d4901fc81630c5cf27ecf331d5137e60f38c4c088aeb3d2133f258ddb488888887877777777676666666656555555556545006fe00803e3b944d58bbdae05170c5d08d3aa9efdfa02dbbbe982889f953624993c707881f174d61137a56069121a5a356c6829a594520a22222222e2dddddddd9d999999995955555555add14401a881a30b6cdd0779a6313749be891138b8c07765a6535f2d217c1f706c81b1cd924763ad05fe5cd355a64f22b59959e0e4a65aa78d6982d48a030bfc87121ecf2f7f053edf3ca70e9ef386885b814b2a49f64e2a3a9234abc00913b92742ca39e6272a30f6395a293ff7586e4f819f904452217b8a14b894354fba489e1dd216054ea59560498550275f82030e28702b22afeb3f664ea9d1d07a021b27f9b928ad132c6d018713d85431e435ed3a2d93c990718109740040101c4d60a4c52c1d64bee49a837b430b6f02071378dfd3b9743c75043b97c0a69ca89d54489284bb1b040e25b0153c527b97ea2f9d01024712caa732f7c5a1c081844448b09c271aec25701c21edfc31159612388c80c43c6f091262b4a5c05104469767c564621281cda6d3e5f9ae8f128b0c193b04f6fe6bdcd3edc520d70d7c063884c0e9bcbb9d20e4416052d84737b9ed92b473010710d2a684ce1cf53e3f607564af859aab6451ab0f18bf7819f288509e37ca028e1eb07b29ee4955c9c103ce5bb495e6f0b20817af2be0d801632266c5f7fc0af97b0e1df0612542c5bef08a046dce3719f85c1d3d35da6360d472f88f8e5e29d26260dd2bbabe47bd4b6d187851b7ca165330f055e1498ae7d98847bec05fe7a4fa2364558f395ee0df32d32dcbd3e82975810b4a25e752d7d10f6a2ef0fa41946be64aa9edde0293b3d6326676b5c0f7af258d3ecacfdb9205d65fd26be54abab4e5b0c0a691253188bc6d27b52bb07e7afba332c4ff245a811fb9b1720ce9825105ced4d3754fd2c2a0029f53cc4bebae5919c09802a33153c90a5d39c5523252609295e5a4de4a2ec802461438bb48e7e11ec3430c80010556a2df88a463a5274a0c17309ec0097fd79228292b8d4a0b184e60bc728fd0f53cf931a86d6c914501184d602b55e97c91241a5a3366dc680301cb000c26b015f92b628abf04ce5208517b2d4909ec767d4a16e92544d1a1a1578f6c54000d8c243066a39be19693d226b2e14529a2001848307810a9f65e4d787d04d6f6339bce4976e93a69689d2f6e1881cb9cfc2ea938ea193766a0065a00a3082f80410416c01802d7aaad41e6a4934aaf3084c0e77417a9a73345c8de1637b60b0564210046105200030805e307250361f88051a62b278da634b4740b183de03d33dd8dd066d5588105c81560f080fb20ec63ec182f6c6476c08f2ce5412711354795349486a3e08b195ad8b0b1851a063a1830812d147ca1850d1b5ba40a60e8808d9aaf52bf763072c05f1e1115dbf2c97c32f5c8460d3ca8022198d1001838e0c254eef5a42b86b859ace1002b1837e0d534a713f97f3b378a11806103465878fc1c64e4d03bd680939c96694c253bbdd38089a73178a949d2533d03d6239bf6d12682fa88c190019b6cd3d64242cc2926c5827fb50c225d32c182db5499e259753cf3ff0aeeb5d54a8b974c3d7a57f0bf35316d79752ef9b782cb194a5ec6e897d53e2b38574fd2625756d2e0af8213c9fc821411a982d1591777630eff18940ab693259d3b28dda5324705ff964327a5b68a9df25370133f461dbded0832a660646534b10a31a4a839a5e0fd3e76efd8c689e721051fb2489e147293e84c8f22213778b6585e8b828bdc665f1b27c511da50f0fffaa79d5b50b0254f86529a317f5b3ec148bdced1354dac24349e603d2429493188f4e9339d60256a36b7d6d02f9b139cc4e45d9eecb4c78b6e827f4f8f9643ed5f5faa093e799bf9a810f3f529137c7e1759ea841213ec69f0589f31e4cfd9bc049f431ed312dca5ab67aea045675e2ac1a7b4fb0b1a546ee99460920afe66428293e0a4e86d176591045f4a4dc34b55f64f4682895e6a2dc71c735011129c7a9498cbbc47b0216b5efd98352b5be7086e6d35c7e0a335829d203763041793dc98f72eaa3a69114c3a6b11e999f32247119c4c9fd46a6e2a118c755232d52521829469fdd9ff121a5a66e6106ceb8dd2af219488ed1a82b710a38d67d03c22a41482ebfa98a161840721f8d488aa5d29c91c7a1d04d799e9544e5af4a5ac20b84b4252b02fb1cab23d02c179f00c49b8fb0a080f40b06982169d5e3f7ff0f8031f648b85d09af5f0036f1f82bab01f11e1d107ae4a9ac4c949def59beac1077e4d35489aecf5ffa94278ec81d159d1844e2562c7cfedc1430fdce90941956bd6ce4d0b8f3cf0a6d354edea453c190088c1030fbce853b56926f284ac310078c1e30e859c44f2b012ca62460d1bfa5ba008d4b0809a871d784fb94453ec242dbd08004df0a80363f9b4d74fa2e8790c1d584d52624a692f6e993c0b1e73e0f3dd542e1d245534150b1e7260a4a5182fe7d69c8304eb0c1e716063ad774a23e4dea60e1cd8eebbd4316d87f6856f603fa4c57c1dde99dd74039fee25d5695687142766f068037b1db442bc14237b3ab181dd7a49793ce9785bd6c0eec91fa52d281d4d683cd4c08ae5082ac64bbf1b5d1af84b7252b21c3c6faa4e083cd0c0669151d4bb257b699186560c3ccec07feeae534aef28d10c1bc8cc071e6660b3738f6f68e5609d7f1918f33442d9253931dd6460e47bc6133153caf19486d68c31703a8baebff1fba082e4c5c05ef5491e112d7afccc230c5c14cd9b3a0d067663f68a21f6d60e3cbec0e53a952b871ad38d280dad193650b981871718e9f993d05a39a7a0f91728e8021f936648aa793c85e75117bd822c1c787081dbff117af12628eb81c716b8effc119da2b9fddd85172c781b5a60334a905bc2dd327555038f459f9f58468ed98c1a36fc5170a346046a580003f0070f2cf0a9496eda30d331d5bc02173bc99327575249d25b81ad5cd3759319fe7e55810fea924e6f2d15d88f94f29ee8af51ba330546fb538e933f2749504a813777c9b611c745732cd0048f28309652a55777a690c1030afcdf7da7f1d45b4a795ff078427a4ddfdfbea75df07002bbe9a7c73e53d362cc3c9ac086ae12ebff8b9be2e8091e4c606367d055e3a639c7f412f89cfd638ac493a42eeaa104c6ebec3655a3789da6021e4960cbeed5ff5c73acdc17376e645124e08184548ca22cc918b38805051e476043791042f5e7a02e6cf877910123b03184d43b19a44b8aaa166e630b2d0227515378c698f5a6073c88c0a54db0d4956a77534a430b031e4360ccd45bfb7a8ea75a4a010f21304ad4724b6d0c083c82c0e7be9afc9c6ed2c882e602089cb27611caaff2c63d7ec0e5bcb6b93374bdbd4a436b468dc0c3076c7fb9c5696222f0e8819264e9e4dd21a9e8d3d0eac28307dcc94c4ddabbe59a275fe8073c76c06871315192b4e96c86d7c842075c0a3ae8ce41c31a5fa419a8868d33a3055d78811cf0c8011b414b24cb7fd7a44728b031e3cf0c1b5eccd0c2c6ed063c70c0a994520c11b2666a33feb4a0b9d0d20e78dc80d7a4929a982c6afcb752e161033dde05ff06e1510346a9edcaca1854e9ba2b30070f1a30a24288bbda66b7d9cb83c70c3895948974a363d28f6079c8804b4a899f759069f3361932ae23169c6b90db171673042d2c38db944596499658d17e05f7ed923b66eca4db4d577029c8b210bd26debdde0aee52a7bca7eebe6296ace0d294508b1a828bea7115bce61cba4b989e7a509121860e5570ffb515ccd6e48a1da9e047c57deb2c3a968674a0824b1e4f26353298acdd3a4ec1b6c71862dc3599824bb6fbfef929057756aa74756c3dd59e14fcde77a62b9decf1f551f0e3a9a47a1c656a37a2e045976e5ebd5c3aad1d0af684461129da939e3428d8eead78a557d1d7329f607bf46e79283dc1987d129a41e73ac197d0d1fa39ca09bed282d2954dc69221b609ee3f59f5e4d5ff136982d3a4428a91bfca049762343921e9a99027d28109465f758c6595bf0493521219d46b869c5b82532aa8eb521332ab852aa108d366d52ea2043f394f8ee9333e09c6cbb2cffc96049ff1f2730a514f39ec48f0aef96a4dc8b3d424487029c55394468822fd47706d99ad4143a4577a1dc1a476ff2e13318bd8db08ae63de74a5258611bcc8183989b06c8bac2e82730f42597d5415c1018a8e1d2ad735ae54602375554e499a53e0ab72a37ff5c4189502a74ab495be90fc92a94481bf9c257ac3ea74560f0a6cc68f9ac652824ecf13d8a044830c2ae60446df7890c164d2009ac0299d24ab44697c8f1d26309a83ab08e5fd123825e2a5654a21746b45099ca79a70cdcae125c424f0a34442fc4e4202abfea23e0217f285e688904c757d4628c1008ac008899fbabdcedf4c44e02b7ddbe91821768e0f81bd6ca1b93327a54647088cce29920e4241e0a27f48429dcabc881510b8ea9427c5cf2126d34407f0035633d48e8ac498e3ee007cc087143b6e797c8b105403e801a76bd7f7537678c056b42a91f7be72657b077c28b3ecf36c75c0c9f3dc544d9e84e99a0336e9cdd18409d3219289032e7f8af9dd4e4fa4eb6ec02821a4dd8e0e3169ab6cc0ad6f083a4ba7067c0679cad2521a30a662ab6d6be5d42419c00cf87051dfdb5b2123650032e0ecca3f47a62f59568a0537aa52bd75768f758105ebe9d9e26ff0155cba27e54127ef0a7e257fc7cb296a052341cf445df55552102b387dfad974e2ab607356c931955537c88f2af8a4632ea9559d543021879224d77c458f50c1e9d4162aa5a4bb4b7b0a4ed37dd2f92e798fc614ec050f962d5f5d0aced36ffeab9c149cea38da64fda80d77149c92af17224657146ce7abecb9a550b096c33ca84eb9bf42a0603f5e86c631cd272c8627b8d14968b59c329d6054aa5215d45789a40c27f8dba0d2c5eff46a2837c1784eea473497bc10494d70932ce608fdff2892cc0413b3872426784b95f7b5339fc89272094692ebc4e0fa31ffc9127ca43f759b7494ee7c2518912628d1d0d6d2714ab0b146855a10d1b36a3809c64f4f7f85a4e9238292608398e428d1bd48f093ba762d7dd0966220c1063fa9b9d4698fe0729b7c5d4bcb619f39822dab5a4d31e41bc19ab24e99397777598c60df749c9094b69876528b6045b5781c91bb3c8ae0f53c78acde3a8d27824dfd889fa1fafc438860eb9495109e94a5c70fc188984829a51412c3105c490cda25a9f6b491c428049b43c7f6901074ff2284e0a3e68f5ebb97e207558d2fbaf0c21c20c62058bfa0829ac8ac20f8b254b735519b636620187d5b41a45229e54e16200620b8129664befbd15769d25007c4f8036fea296d858897ce263fb025b3064dd155927a4e1f386d799193a95b92a1e5039fd59227d12951b72b7be024855e6b4ffa828b1935b2682fbe0b527ae0f3aab2b4e5185492280f5c2e2de9447d48d6b7e38133c99f4a53fef22bfd0e6ce4bff4bb14836ba8edc05f0ed282e748cd7b771db8f1a819bf364307765584c6cbf5217e660e4c4e95216489dad44be5c0e58df5397554a8d2548c38f097b4f2440a318d52a9187060734a9e9c4e4571f53d10e30d6ca6d320593d7eb4deb8814b1a4bbdd66b7c4515a30d2523530c3660f1255fceba3eb135a881b5bcf471c921758e791a5aab31d2c0c61853c8d7579df5a91a349c3b6ee9b6a6b36bd5821867e072debd29eda14ef54968c430830b62940165580c32a81631c65019882106ce44e7b8ada12cc73ad120168a1861e0ec64b9da69cb231e43436380210831bec0a735ef4ad125777304c5f002d71e512fffa95cf8070af1418c2e580c2e9c0c12c4d80293b5749241db739c2cd2025bc182cc74ae6781bfbfdc5d971b2cb0212125bb9390185780410c2bb06361c95f2c53aebb1610a30a8c8410ef4d086dd39753017d35b6fd273931a6c0785ccbc14c3d2930e95d82487f7282ea244614184b4a9b8aa6eadfa650606375c5cad6ae76227b029b72c88b219bc71d9140218613584feb12dcae734cbb3781118f92f527a7d17a394c60f344eecd1de51258ad111ad3378ba1044e5d9749bb6a93617954a3679c756ce0011d352cc0010b7430a043868c1849e047051594a9f691c0e50f31f9962788946268a8d517336ad8b8da13c438026bae913b7278a4d0bd11cc97c12d827b2996eee019c620023b2955ca3ca232c44c8c21f039a76adb1ea1591154d5b181076c208610f62cf3149558b142f08e202726cf62b142c960f1428c2070d72552c8feaf2afa03815313a3c994b2c5f823af007a2f6e7c8d195584183f60d52c8936ed4cff4af201371a5f2b5a05d1b6a51ef09eb74c5707dd41e879c08d92d93772324f39da019b469f103a754e698374c05a1a95354d3352c673c0f95d4ab79b83037e5c42fa902235a4f40df87859a322a3478ea10d18b5db2c9df4bb4e35e0def327915e826c9506fcded5578a60dbe6fd0c384929c94ef1c49001ff29461112d36616752c3817cf946458ac4f5258b0218890cc35e43091be02156a94aee0c7423c959d72a790d20ac6e37e32b993f4eface0d2ffaac79369f256c178a8e9a82f524486aae0cdd5f53b2f89578752c18fda547e13775470b9ef2fff6f3f055f6eca7f73ade9bcdd149c9bcc67275d948ea59782edac7f1d8fbd26472705a7f39de698b25bcaa28f82b32472907b49720c2a17051b2d681ef17861e93fa160bc333743a96592fb01055fa3834e29e83df5cdf90463daee25db554ce58e2718b5a126dbd4e93ed5e9049f3c9ea568e526f19b13ac88c8961c73125542bd092ea4515242cce37fa3d604a754f094ee2fb5e3d9996092b0a0a654bed1383626f82454333b477555ec4bf0d95a841ee55982fb12a9468de5d4a6aa041b53b473d5cf6d0f694ab0a11ada6fa1448ea64930d937795e1a15a9aa24d8504148f3eb4d7e478289eff5ed99bfd2860b095ee308113ac4903e8fe0276beab2acc935083982aff5a4d147dd083ec6f5ec511546b0169eabcd33b30836985f66fd15c1e90bd713e9a389e0f2ce72cc1b447bd02822d8b72bcd9292758c513d0497d36795f0f4a64c450dc124ad94e3ba8eeeacb4106c86a8bf951f42b0af7d25c23e575acd20f82064a84fb79e269a20b88935d9e464ffab54068275cf7ba7418858b980e0369bd24a124f7abcfc81b7bb98aa5979d476c50fa94b97739023c53eb01f42bf7f05f9c0b675f4b168a99df43db039e752263fc9167deb81d5f5b496b3bde5f3c049959cad43e814c4c4035f4af443f6afb6e8dd1d18a17e9544e5d221c70e7c7f59e6f3182b5b07d692bda6de5856f6d381ffaacea739c6649a9e031fd7b6d6d52f932b077ef33c66e64c11931a07c63462f5a7dfb0bd0c0ebc4d504f4ff91e43fa0d5ca8ed7463fa7e2feb064e83c4a452ffe93adbc0a5082a779299620377d23fbfb95a6be0532b9426dd15e9cf52037fd2aa3b9de97419ab34703f7e49a96822d328a18153319666b98954317f06467a8ca1cad754dc1c33b0d716b4ffe7acf69d32b061417b254b0a88878a515cf75c271020077ca911ca2ad89e0002e080117aa571e448f2f49e1bf0a324aafe062bb19cb10113d577573c526ac0893e0db943bde6f4200168b097b60aa926be240d0808300336d3e5a5af0e5252b75c74177d812e6c143c1040068c5c4d79bcfffa88055713ff2659b0a4f98085114b06cd75a65fa2a1f50cf8d4376a7040868c2db678cfaa57f0aa9daab7f482e7ccc12b067cb882fdf7907c726fce9f4c1bc3472b1897a0353187fe64e729317cb082d3244564bf9fe86d57c198ec241e33d737a6d40dadc2872ad8111627a5ca4a295847860c3c7ca482b39cbbf72c2da76a0b0d2d1aee45a3a0630313b0000d2fb2f0801d3e50c15db68ba46c7f62221fa7e0533419849efe4e62fa3085b93da852faddff28052fb94e6fd494113e48c1a878ae273add5ace75146c4eb591275db43f49110517d2f8c91cf742b2988582d37f5aeb49d64e0a2550948c4fb0ab2de2af92b286e47e788297981e41da4eba738b2cb4e804177a623ab4f9c1095ebd46cf44e807b9f8d8049772ff8d0e9db2c58726ce1f5c4d69f55589660b3e32c17906ef3121646a8b7cc10726eee312f8610947941ecbe23d41e9faa3125cb2cf561262f283126cb4bb6f4b9646a5fdcdf86312eca4ef0b2982e71d49d7c8a2bbe00f49f02942564be5a548f0a5dfa72cc95189ba4382c91752eed5f54d1a9ef45d5c601fc1dfe6da0b31d446929f1a5fd060000796081f8ee0d24deed01d3b430e79207c3482cb4a9b84d29cd3c5d41a1f7c3082cdf628f6ebd913a2c6061f8be0f26bb46dea4deaf50fc387221871afb869fbccae2b89e062fa66ab389e9a7db3850f44f0695de36f96a02989aa858f43705a72e84abbba11f23704a7a9fca3bf67de695a08bede5cf5edf253690daff04108de64dcacfc397a2e8f61e16310eced4f1a95b46f6d4c3254f810041bed47c93da14ae836104c8c21a95c9353e7f693133e00c1483f31b517d157436b02f413b08f3ff09d822c992688a949af014df8f00323f34995b4d90d267cf481edfcf96e4ca2c7e8f61a3ef8c05f8e79ed9eaafbc8e6c71e18f563d933069d0f3d703a676e917a31755ea81f7960f3e432a1feb992aae4071ed888ee9382fc1c3d0ada6f98eae26f9c013eeec0ff9ea6d0497bc81c94c65f0533bcc8e208e1c30e9ce95112f2250f091f75b07459ac2dede8c0a435ff5093318a90d6b0310305378c9c1b5b20d6c71cc87fd13565882439f01352564e4af47130b72a56e776d11a97f0010723a95fbfb20bbfca0b1f6fe05ac53c567255ed72ddc0d8969e9223d936709e5e3b87fedd47d1b08133af095e3bd235b0de56bdd5a174688aaa81d39fae2b588d6895681af8d3123a2ce7a9117941039bcd5574b09442436bc68c1b4da3d8c719d8d321b5952c8bf91e3370278445da6429c224a50cfce9b411af4939e51dc9c0954c5abba23f06ee2245b09a64b2d23c31309efa1b270911db932a59a05c054230230035f80803a79571530c9e22e6a081a16af0f1051c7c7881ff209397d2f9f9a1aa2eb01722a4cdf38a633ab2830f2e309e2ba4cf132ca4557f0bac9b0c22a59e5d588db4c0859883ecece4675a9e2c905de4b548d0fdb1b447f8c0029baad74166c8a7a5dc2b7042a83b9dcd532726d70a5c1c2fd939a90a8c4842e4bcf52483245181116da15d123724efcd1458df49e9358ee8558991025f955ff2c41c8f9d8f0227725869fa1dfbb82a14188b20b6e933e9ce127d02979744ead121e904be4695e851dffaaf96263022a28bef7585097cd6ea6584ac96a7bd25b0e9e6d99a9a5242d1c255d484dc5e8d38c21bdfc51733b4509005e9f09104c6d2ebf5865216621324b0f143d27ca6348ee7e908fc7fa594da825241dec9088c6de5b23b8bc058d29a2bd9ae5d2c44e03f664e761f9596636908ac8905659d759b3e2d04b6cd22c44add36d90d029bf774d09b2110b888653ae9f67ec07e9c9883854c318690f7019f5b3aa98ca61e70a5b42c6948e201bba2cdc72495ef05ed8049ff593b5bad034ee84f1b95de31883607ec95eb284d3138e0e45fc6f536b967e60df80f1db5a516b701b7a195da832e99a404d58017af3d3bed0e0d18fb700d6d25a3a567065c275d912382103ad21f3260ff4352f34ca1f4b8b160e2a6f1dc51f4b26560c144bbeb88b7196d92af60824cd9c47a62489e3aae60f36204d99f9364b15bc148bc1d333d2bd8ff49124cb555b05a26244fbc5a15ec9ee9b67f5d2f39e95470b232248e0c6954307133894a4c9237fd5370a63f597fbc3791846b0a4e62e7ce3ababc57dc52303a6de6d58c99e93d29d88ca294474b2a6a8a8f82097aaad54b6944c1a7592edd0f6da231130a6e3492341533030ace94b595ed464fd2ff041b3c8665aebdb75c7b82d169b2c25fef4dd34e3096673aafc909c64e33c4fa897983a99b58c58457525f13bcae4ac821266526b8ca08c192da60821fb51cb4c8d8a7ca7209ce3d8b6d289dd2774c4b70a142c3fa476290a04af05ef2cac5dfd3590e25f84df5936369ca24d81077fdd7b22a77a4488209417e16d5b613dc8391603d68eca83a2224d80dc1fff3d4d73ffe083e3b27d1d9a3c7fbac23f8e029e3244da3926d04a3f26a9a2795392dca083ea6bcfc91acff335d04e79f940c6ea722b8ce2942ee9a07d12997085e3d6a3479d623825393bed7299e10c1ba437032f95db06c396bc50dc1a86c21c44ae942b02958e5bd20b4b62404e39af5a2d89a67b88360e3a6d4cd0fb611a282e047086531ad66816054e598124f0d08364af2abd320f289fb07f6b2c7107488d85dfc801239ef4f62a5cc0d06d007f66aa4e5cb27731049cb072687faccb9ae928301ec818b5bf9b6b2e5f5c0beee5966a5868dfa5ca00232645cc08b01e481bd743aad650fc2039fcb34e987caefc0e8584ef2ad62c4341a3bf0aaa72425653a9487681df8243a56c918547460b209a92a7952b41cc98c1a690617377a0533de8beec20b1b5edc7d170b18c01cd8d611f23abf993c213930d2f4327e7be7912971e0d2c8c8232c75cceac1812b4b679a5755f3c4d21b38d55f5f4963c80d8c0cedbfb20db5812f53e29dbb3f6ce035be558a8dce1af81aaf68f92d65b5243570a2a3a564224a0317735e771e65a38137394affa7bdcfc0e468da1df33503a3fe22a83432277a956560e3e42b8b9184add964e02b9ad25da32963e0329dd6524fa318f87113e1d90c035fe9473db86b08fa2118d8f6d1252b646e8ba32fb0a292bd2b2466858c17387d8b6a75f9ceedb32ef09d51b36554d3f2b0b8c0b778a8e49fc452e6b6c0efe918ea26335ae0bc73a49379d22facc600b2c04a0c3a74e678a1af3b16780bd15a3af54516a573052e746ad3bb7ca19e3c56e0242799942c3d19afdf2ab0950a8b11a8d4eea6026924160804e270381403b1e9ed010314000000001413c742a14820908455f40114800452281c3828241a1e1e1818361807c6816030100a86028150200c0a8402615030201a4403aaf905cdc8200a1182db1ce778c61a327abe50ceb843e2acb7b0b269b45ae9c6b711fc689a11af0dbfc9393a5cbb8360edea843fc6be24a486b549cde159628eed8992fc07fcba280c4308828853c9f222e958fd16698d5b7692d44e3deffdeced41112a38f470d64fcaf6116f16d197283e98de2921d840f61fd0ddd59b462cffc96d7997500f40d2031cfc5c7c594dd57ce904df27c1477ac67a7aaa61b7df6f927cad393bd824f39b938cc3d9bf0583bdc9a85cd532eed4e2cf4b73e15aabb7aea75ac32b488c0eb8267ce32cd698f425318372b2f78ab72a47ad9504911f7fc21cfa404369497844e4913bfb2ff05eb812d722c7c0e351ed6e52a8f1a73ed228b3964f52f8998ebe06550384046311721dd29c30a46a6795d409198f7fca1235601a123bdf58f83aefe14b70f21476740c4156ed53830415a7e31591b395b3763fb1ee065b33d42830eaf5c53b5a6598988673c2eaf54543a5e503a2c652050988a494446df3856fbf01f67cc600cb50bd1cfc908b459fb8df33497229945cc586333a9f15ddb218348993f4b26d96462a8f2824ddeca0ae903b77bf031964ff28bc90ede3f1b7fa7211771a72632a3fd16eb6fe1c851f23c1022ca9a4dfd77858ddb9beadf1136082cbc7421a8e2c16ee067f865f145555be73a52838146eaef16b1ea7c657bc032dcae8c9f8854a8300d0b07c0ea3e5875e4cb97382fbe4b27ff72241256e1eccc63b7f55e58055b0e90dc748d3a459710be42bab91496d4fe4b2d9e79c427e0ffe450842420a87a0bfe9d37c677bf7cee0f7c4a7cf4d6687f28c978abcacdb1ab7820f54e82d038fae65a237e5e88101924e3d335ac257b5a17034d674a621b30da68fb0858054bd0794633b633a3b684203c505ae0d4513e2f37c004b1d33b2c7c65ecf8eb4e44f845eb7768af33fcf43a4ea1e86409178fc943af49af5aab08d55dcf3404a93af36628eb4a7fd304adf5058fc4c97d973df0183f989c91a0cd6b26f634f0b26f1a5007f4bbc3f758422c698bfa1f794a3aeddff6a82835ae7d8e2846c8f91ac5c465f07b95b46caea83a356e8a69a40b5036f711467e0c868f6690792512840e6b9e558de401c9a5f042981b7789308e48315a3aece28e90c94fb7a08a18671078ce4fdc0d485c4d3ac701fb40d7229fc817b9de8cec93e846254b33687f617102c6b455aa08a592f3f0b31af5d0f4fcb7c9e30066c079265c78366838dd58c56d4dd876998b4f4315cd3045bd3f45b6bdc6e781daa8d51a699107e010dc2a9c468b3eb13031a3a13de3de43b8a47d8c355032b9a7141a53e92a1359cb0bc3059e6c45067bc157e80871c920308e4ba025823a4b966b8b508760b01c594f7c1d2a8a053e5cba73a81eda523d08391e89d1be3515ec6ef27a91aae98a215c00e0e7eb797ac463d5920c79453d08d194f2f1c58558eb565bc8c7c3307b6e6ea0bdb28780a17b006754a771b53f6648ef5c9548803819ad8c23b56a09f6b125613886a5bc173d8d298f52eab85b90d46557626edf6df67392b3c7c131a1f5514d522b56b73e6302c275ac1aa180e480206105b66d0ca0c1a9b07ee78b0ffc95570e7c51051aa094700abaac002e04a042e7000450b271b08f0615c4158fbf33a69750764177863c1906d0678cf5b869c0fbe50279fc91ced55f0b4d4e290e642a75fc4cd07140982294c39b3d83d350740a01ce75d7a154df546a886077dc566234f0a3568f10e3ec988af19883a4eb9d33ee5c093bfe8535db65879c69d9b27ce80e071e80b814f190759399be01b40bc01847aa019a1ccace809280661481159d3099a81289e9a47595160148e40271a10f887df4e59ecf32332fb025200c5ac5478a6cb69d0ddfaae0242234ce3d440b456472b801b03e1a28385566422f5de2ee8aea60c8e959beca450290256c788dece5acd1534325af841a5609f7bad35135cac6627d7cbd9909027677bc58d1d3a74960fa51a789a8df7738c40289500157218ac756027002226b328d74a610168bf154c5d39a971d3086bc35706efcee869ba568c65dbac59aa9d9132fafb467ba8ae15dff5c472de8a246ac51309e65cb4d68e5ae1e8989b37b7a290b5e2dd0ae6355affa59eded24ecf4de3ae326898b5f26b9c9a28cda7ca906a5e6a67906534b44af3b6542b6c6e9ee540a1af34679dd5d0723a755757d0cfa573d767aa158c10ca5a2ba847414fc83f1469f852eed756d6ae512b125a981882d83fa38cc31766ecba9631ae694fd3bc282cd9c2c07ebcf652efa607d67bbf325ab981e3275a0795593467c56edb279f9e5bf1aac66d63ae8157ade8465e19432dfb514f8d38ab823e4b8b623d01b0de18215ce57c1b776dca95c1f9908d576aea6971fb93022b09b5dc96a1987bb1e6b62a274b582e06d1a4f1a7c2445f9d12a2e103ebf05392a69733732934e31786b3b4e4326473f116eb8b39399a9272c2e778a5601808bd14cdb6b6ae3c8232f6af6907b4163aeceb08c96ad4c873e76699856646d3ac85cf20f53abc6a780a48407d692032bde7a0fd00e94d5df2635b555f2d98931809f0c07b466d3beea8ea388c4c5ba05d0da185e91ce3e8db67a6bb1bfb6ee8af5cee056d9d44c833214d0b0a86c902d44d3763946adb0aa6c57994d9375b05057cfcd0a3719d4b8f4d0fad1b180a3d4c9b8b9b56744fb04601410ac39626fd1ca6dd93ce085733076b360d2b5cbef0fad7b7f69b8528171c784cc3a4534fa45f46b45e3042479fbdc405516d591bad77634074e614d0ca23c03221698c24454a20817162a09e5bf1299a088e7e211b574edda336d3a6bd402f45d46ac027ebff80c874ed20632668582f6060001f03d4deac9cff9ba259a08b5fc26da10090235009641871b030894ad91646dd41cd8c018e7d4e349765936ef84c201640fd2a02e8a41ea66b517b6d991725539259503eaef2908d2feb8c4ef63f2812b02d31aa38245cf9cca488757f262aa8c9da6da3811535a9f0cb9ed9c12fd1436c6e547773bc39b32e890d9204c199f1174a6907959b312284bb1d6ea3279b318de908ac409b35e96698d8556dc5ea862b39c5e4b4449c19279b8ccc693336acf76a55cea993335be65ebf0d683366db2d03b6960363e6cc90310da8b08d75fa506308837637acb736e56d54d8c46d136536d3b0f02d481dc42779d94cffe6a69c4d72367046d95cc29b3192e85083d7cdf7c51933f9ced22ada404536d32c6d7eb2f81b7e1c2f6a53244f823b51c9498f9c19e4f644845443bea6280975b3f8de88909b6a4f5387da73f8f76c844af760303700fc3109bb6025739ca9d27dc74bff7a579732af8bbbc29d10bd55b41c08b7d0fd98d5f8a1d282500c9ac6099f6fa84dc822040e62215043955e8f57153111e9fe20c8ac9719eea700db98f838e1641ee952e68763da9387752dd475b2b22883802ca7847ac5404dbf309829a107179251b4e6be74ea3f856b0caa8647a407ac8b253f996456fa690b19f7686a2a1af76f57c14776c5611970bc3ffbaa6dd1e87c43f10809d5a3adf8977e836cb8d739d6d6d486be8f54618d6184f7c227c13aa919fca89e158487a9926fc84b6ee15efbc94a1cf71383841fbe1bf9695462b1f8cc8e0d28ae5d9ad848146a32b1977aab44a90c55a1399b8800fab5261061af0687bb9a346849cbedbb880acf0a67f31722d0da7efb23f4a90224808c7bf6f2cdd8a1d3cf87c54e94077a2d9f467cd6a5ba2c13c6c004af8251bafc8de92d6a5bdc7a05106fb73bcfe840d68258d803e32516e48241704cd0b2efe9c391f3ec8b36328bd4d11af88f08931f26e14d7b2c2d9f2cbe5c6f854dad67b8366e4df66408579b61bf76b6b9781bb31280fce5e018b6c4461b3d32c34f7c7d122909080ce4cf2f585182cb98845c62a234c699c64a696dca733695143508d428c16072ab40e9fd361621490a39528860a296b6374321aa5d1a2b924df82cb66d1f884aa20d20f1671ba4cea6c25a542e22ce4782f2e2a09194c9a8550be9fe41ebad3baa60228487a07f6e240474b27af9c2344c55c5730661c90bb85a3290408504728053ff53c129b91bdb55b74e0eede061b26f14fbc72c39b4d6c3e79d1b1b1417dc8f10bb8fc129c1d5c66083ec8c9480c1030a0a801857a7005789db26fde1396c7944827d900d67ac5841716cafb1b06254eb235b35850dde3787576fe2078b6f041a9e367404b9f6c9abe87a2387149e1f9599d4d6a25036758d20bd8f91dc3fbce98235525adef5be39e18af0bf70b5861b5df6a2b961e1342158b01231420cc97740279a13a607e0506e980cdcd8f8228159cf7b14994346601131c33116cc8c77803ca82480b8ef1887ab0a97df1bf32879315e82d7c3abed257b01bd582fce2bf37a79355eb9d7c38b2ebf5376e6d6647af80292fd321746029bc442f4322f7b3b3c30dc099353c283957df31c0b0f571081f21adfa1a4f0d8a62782974851d217d953f3be7953de61e27d160266538443b0612630cad73e0c086cf61d98f3b1d525ef0d61630a3c22ed5b1802853066190116f17af658b32c18f605cc33b68061bfcc8591c09a1c0f8a1fb2a59de38d2030f88ec43c2fde04dfa4f048f863784bb832e0e3af09d709147a355cdce1c2f9bfa8e4a0eede61a5bd39980d490fd78d3bca6fc93f3714e6dd69cad88531fe25518c4779bdef17a20722628c016ee063fc526ee20308c600b2f3d7b1e421d504433d6383b0172447617855f9787095ef200f76f8dd6b10f4854b050d481e598b594c179845e9e371d0faeb82000ca6c28e551e160921c6974e1d84168afad061e31180b7c9883f62d958f10e53472fc5165986aa3cea706ed3f64f30609c94fafe237baaf4d45f21a2c923c259cc17e6bcd8ed9d23cf4251f804d1fa7c8457ba091f76413cafcc4a1b7601c10eb56c189b16580e77b30700376bd54e11e34353b22609fd4a8c0101352edc67a223a219b00ebf2604cb43e53ee571674746ce43c2fee137d86f289a837e5292ee7eb2fa234346065e4f576852fa1f1bfed9d6bb93335e25b105524292a98375f4729edc9a13cb1220d3eca399b2fbef2da0e478504f1f7f39545dc90a00b29d7d00dd365b2bb5c2fda9fa13f2fb4fd05a487e48f17de2c0e905424610eabd0fb2e3a4cc9414a527bce9eea29f19f68084fff7ff61bdc6fa333661a9b0fad149f98e55bbffe5c1640ef53166292ac6a57dcd1a828f30b5714caeaa3808c8f2e53a9f75e05dd8773b673232608dc12c85ec5b64eae067e00a3430602ef25870002efa5cbba7e8c594e88065fe028aa90953a4cfe7f667a7f02639dd06342410c2717d97b597a2cf85640aee211ab116b33e74144f0b32d487d0244002deea0af34176e12893d52e2921a52c74c41e0995d642cc84e4095512ca23940742b3cd9c0534141b82465453a8aaa11c445d4205844a62e82d5a05950421c45d0acdf64f16ef17174921ba2774e9d05ea26f42870d5d46a23752d1cdc1167ae7a112641864a87ef16a9a17c26828064539408d0c87fb0a951005d0448422be45fda4e82d991306be11555f43b91670f121930d9540368c08331a5420191a4bd1e728ca5db88464704d28a7c169ed65a29caab4d2e40d7a3c3504734abbf27c694e606e802afb33d28006d9aef3247283daa311aea72e9261dfaa1c1b7c7380625c5b05d084385d46afb2f4f58f2bd355631fef9583c2d1ad6f90b7919628a23a65fdde0384eb59babcd03ab987ba9c25cf436b83b51d0021d42265d5cbd56f8d6bcf1c07a690819bf1362fddf9a6032a30ec259b2f5dc8c3d75adc754ae565999ed26dfecabccd0fca755fc50c74a11ce04df0c3174eb4404813025e278996649206a99a49e10d73b82b17b7274009f549744b79390bd225d5502d6eb167a1d81601d689b670242e3c2457b25749d9479dde3d4147e87163a499ba121b4441a1a622749b9b9d890ff1640e2af72bbec3ae62c153a191f83853e03cc0c7cc0db0499d701ea837064f441d744a77096058f6ab00088e2ce5d83f1591a3e2eadc91f6e0075a30ef7ca0aba9a71780c2087010fe28b2178628c1ace8e234dcdd81726295b5c6d930eedb0062c270e42017349ae9b19478a82fc8cfab5368b952f29dec97f12cc7b228d865175e6da0cc869230d7553f2140b987f80e2239b0f1c28c61f87e255034306080108adb7c4e0d0907839cb4228565158594d2716542948b0e2ac19b94401ee15646b8b865b45bb4a2b0c6f5487cc40d4f4d104e5e1d7908666db687550c1203ad97f0e2dee18a29774805c710a8a211e72df61703d01613d5f5da3b73174d4db4bb1f52ddf9d8e42b81d2b540ea204e7231c7cbf54a59507731209e90c7aecd650e0e5af24f7f0f8a82dabf78992f76ae87d91754b808c95a8bab247a25a341f161aa85610e24108346922226455585c93f6ee28a831427526976ce871fbd33acec1174f89fcc72501711b5b89c5989b821a49b466edfc8b06408881d4da7f13b1b470438ae3bd03722a5d7ed0becfe087a8be060e2e3a780ebb36fc82f97e4504f6ebd651ae12edbff1f2ac61d5bce1590743d7ae1b0913786c256d5523e3b2af8b09984306c60029b4c04315207a220b39faf69320530c9ca230e01f8ae59637f89b9a926dbc683c1dc43b58856da4a10f42432d7f5ea2c0a88d13176f9bfcdb7a9a64ab48c8abb6e55ae88271adbd71be52eccd483f22b105d1d908bb9fe97054b4dae73cdf837b7532cf227a2a121d2b06c32895b909f06603964880981c7a1a5dfd82c605094830ad1be712512053c278eea78df25e86b63e173a4c027dbb98ad81a30b6c55eddde559bb902d79a6a9a79a3910b4302964cc5938c47f0608afd2803a68b0bae471430ec84cf0505a81352c14da711b20048a20a405606c8291c32b898e5431164f938fb8f318462224e1fdaff6293621b9fb6044d352d76cfcaf5545606d3fd93717ab4005b3b6eb662604486c7301c4bf0d1e093e80dffe6e4c1f4984d12f4ef3d743f1668c32d44209becc59b0166d764d2b4e076b7107b556e2d244150f3334df42a90db4e2a40504353d9b5035f79f28253efae57b43dad552c31da0c0cfc0a064b3c02c5269b7a7ea0c02a01d72cb6bfa423ad33e22d19c104528ec2875611ba56f9a83f0523700632fda6ad994347e501529a262e66cce08aff5a68073e20f01b7308010d6e78a00693d3dd93d9f3cf28dfb8f2b878a13406d6d96de798d1d8de3ae07d99ac3d171097ee0b51a3b9345ee2e5d5973209329e67c82e4b5870bb24255b27ae5ddc668dc7897a656defb5eb5c2cc349381fe35da8833dfb608bacda8ac0ebafd6b9e68c7fe3db532422a137ed34f364b6b000b717c3b0daee7d7d5629952de86073d23947b5291ed2f69a1b2b8b967598749585bd9e9cc4e931dc5b2bac20a3769413d185afd4e915ddc1c2f5285790b2c4a150a427abae82e10a16bbc173e1b21a2e273bb01a00f043b81df8db6d6004cb6aacf1c276acf782682f7142740227613e115a2a637eaebda0bde85536b9b3202d3d15a597f619227419d0a66569c03f84b56bafc09d1cf24ab0192a721e9b71373b9b06ddac8595e4f5b85ec580d116c6602daa5cf2dfac335d17655c0925927eb7e8cb643f09074afa4c0a2a296152aa4954cacde496768044f50d627aeb5e821f5b45de9433d9ac841c27aa855a5d6e5b4854672e026deda2e968c27b701149ec71129d031b984c20a7d6f8641b621fdb3bd9f62de3319f0f7c43ba80f47944681e4b1d619cb3cdc34a7c2c912049eb858716f23129f4897eb320bb7d80125219404eaac14559bf204b1c12b890ccc32bfc98a489025422f5c0f623bb908e04b294b8ac6ff300e1da8f13ab3e875e158fd30382639f6c299140fc6eb63fbf787ca54fff1effa9bf634530a3692d74cca210323a4a954e7e36216e94a21897704c132b6ffc657a7fc9df58238359839c806a7aac2434abf1e5ba16fe0cc0304a166a88081114d4af11b1aca7541012967edb09e922cafad3a56f258367dc2c61b3fa523f110a82bde03e59cdb7b54bc54a1c4f0aa9496b737011d69924394020645d6de5dcf9d5a38790020b45f4f26a66be5fb302d28d7c4589eee5ad824c8690b398a91371d7ddd963ec28acb6e8b9105f3fe934b3382c5a0699cff9396312b27011800b6a0215a03b6a359a3135033f5b1b7343659c39ad54786febb404c50fb75cd143eb49b57f3e1c4aa21d98cc22a060adafc9f2174d2bb1bf471263491b1f5bd5839851e66aadba49ae528f34f19731e33116e67525edb84b8b42feb056257adeb11f0ac592923c31cced48e7e5e97dc5929ee7ffd9a67342178f871008c461b120c7165e9c9bb0e0bc020ec9cfcef7c97107156a5a2e652c2f440e6a6f0791379d91d253ae1371f3fa47b67ee5c7c224afc28f121941e9d7994bc36c2a719556b824ada85383fa5012f56854138fab55eab15161ec81cc017066f5fde63cdccdf7a5899e8ca1b5e2e890fcb61ef4917186a1c9cee50bdfe8535f3d746ca33e8fb447b6207ee6541af91c71c9f34612e81be8b992a51b5a732aa08e84af5d5c30d78c02c4af90a7bef8a8da822f915d6033816ee8b4dbc960604b2d40c1622c7bc63b90eba3d6ae783d668fdac4f22d592f90bdaf79d4840907ec12f1a5dcc0aa8dcb9555e1a8641741959713888e6fb341e0ffb89991631567cfb7bac6146147f1257fe4c74aab616ffd60278b5763c508734e209ac89edfc0313c05af26439df61ac9ef05f879ba4f8b50a6cf82ce2c2c2deded88e32d205a210df32e010d2dbeae771d12fc02e3707e7afda2b4f5db4a19bdff161898720d0ede78a1dfd376637548032877318fac9310129cd262d995401252b0686dae6297fb0d6c2df8d833c82d27abbfd330b8a2efb580966e8d63d18198afd4a1481efb72260a8a18bbe53de1e35cbc8229d63529ba14a629823e617eb42aa96c160820cc5053da0fff77f56b04798b1b1b60424521da0464cb36da313d6470f53b57372cdcd2d7e08a5a98d50199919ed36f3b5d3b7c2008e3f409619042f18d175808384031f29108d9ae46ac1f9b5f6b2209cf363e4fce67a15d68a98c21ae315e9fcac42059d0421df9269bfcb2856a02b3f4a989de4a5b34a75234dd19178b2ef0e2b371f4f3a5d43de8f6997440b4a923855bdad261aae37fca4704a6b2449ca9e8e25ee03dce4d268d0272881153951e4536f2af1d4d61df23179bd0393bd4bfc7c336841acd7cb3d10b94e749e918776721fa06382e29d534d01a14db7de5dea5f19176c45c1101767f5f42e767e57ec9d1e135b44eb920bfb7b07be5778bc654e23b857fc76450967eab65ca5a0430489ece93cd4afa1a62ae58207965ad791d70f405f1707cd1286e29ae0a6b68d6c1aab5a7c03eb92407b57c1697e876263c9326d130136bbc1b02bc6854d6386ee51446c9490034595a58a8e38bacf3e2e3588be55d827a56c49347a82747071212667b09d4cb110fc259af9f2dbe80495a1f5b80bdcce7428e2b50ec2e113683f4b2f1361721b8aeeed659c17fbef995aa0c5781d0aa29255d5813548a5544b904aae0ad008a07b2e31dc4dcd7772d9188ea3d5432c52741e35977d4daafdb55dfea430dca168ce95c3cc431ebc771e48a267486a85a91e5880e1ced0ce48962df5c3e2e52fe45ee386c8e748de232954cbd75acec94d34e00d76ec2da181b639c1044ad6930614d5b97b0ca944437855053c6eb78b9ef97e75b1cd715293f09b40d9e295a85bc05cf15a4ef71bdfe209e19f0d890b33a6addc8e076880470631dab86b1832a32ecd43818cc30f90e37de84f38148b94fd44d0597e57d9a0700b9dae6370c631b6941bd5b594453daf44eff87cd9f026e128874521634367ff71d98f1ba9f17ca03a80c2e60a61bd07654f41545db55e6270f3767099f510af7b8847575ec69a4e8bfa393d2b2de42acd4ce0a06c305e1c2089c0e1f8dac0181634b08ee1e27188049715099132532b5114e7d45dd100856c189294b837a62b54e1a16b003d0c0b4e0bcc2ccecf0313a84d8db0e40f0686bac9a7d90f5df7b122f16c203f03f8a7f9ed8043ffaae6e060a35ba019821dc9ee3c00dacbf07638b98e05862273a0004ae35487130ff89edc5a28535b6bf4c934aa1a4211874daa0528bb0038e8cb846b7482cdf46d9ab0d6be8393812af7cd6c8a81f20533fecabb326468a8693c8d96375fa92e21763f6b46141fcccd2549d53aab1d85f9fdbbd7baf1708b302476b2002fd95d346fdc9d553e340fef37550e88eb5825e06e1c16d933b00dd87b9013849bd616d83736c7f68073da0f3a255290d9ed15656d872f7c523fd52a61747851eac1420f8aae7441aa727239a5ebdea84b6af6391809f670142214adffcb7be057fdae8af08fe39551b7634fcbc2354bc48a5c100f16fbf11482f1c4757889d603b8898bcda65f77c9b77b59293b963edb2b5d841fd3ed8110b13e7aa0acafe0e6fcb012d8d003efbf94f94f569bf859479e2011f0f81eacce56a8c528fd2e4f1303ade1619fc5af08aa050d5e83eacaee645e7d7ae48e7a216eb247a611d4529d0f188c53a88aa6067118aee2c5a91ce452dd649f4c23a8ad20340ee1910400904c4d0801daade368ec33dd9c18ba92d514735821f970d540175b3e106a81fec0f4c1aa6c35b232fab386c45897f78e1e351e07ead474f36467316a978a7a315eb24baa29d4529deb148453a88bc6067118aea305a814e472bd64974453b8b52bc63912ad2d203d692af3aa8f2590a086e168d3acda1a968e7a522382f3a0032a73a12a30cae9b5cd1d704696c5ada53c4cdcc836580c11f6ca9801264b225525fe9f034aab0021a2629a7d7c6e47dedb8db8c2c04ac037fc31f3bec88ae688a52c7c0a67fe870bdb4038a5105811b1c635bb8a9d9e08ac730d5c3d78be8936282a74a4eb5b173b781d1ebbb5bec9e1f234e81354d63f2a17d7e3980370afc7acfc71a67514a32ff3b36ae28055879510df6d88255dcbe77f3c335740a956604519cc1b411d69df65297b8e319514e69cba294aa3a2f657dd859229090d9606d0d907490ecce627d308a162ec17efd0f1af683db08f54c925b89c1b92f9925f2400614143d01ccb6a33dfe52bdab814e3e1aaf1822b3736ecccd87d682305140292297d8562dfebf3ae5dbaab348c786e86eb7b058b855079bd03dce5110bd2feecf04a6793f5ba8ead8ac52e16de01b291450d0d6129acdfe72ad299f197d2f7a37f6a2025bbc401ea503be9c8a0bb7483a0562a8b20f71fdca74ef38f69965552b9a12faa4737a766fa091af9bd5f2c98e35b828704ac721202cda0451d87d1169760c230b61793a35a8dcefa63f8fbde6dab0fc98cbfd8a076342a0c0ed86096fb3673100ecf7a9ac3ebf9fef5f9cca287def788e217cfe137d1daa260444d2978184c485cd5ae143d11e001f9207d2c314e94a43e3733084751a96857aee32c58e629af77fad13cd02f5ed05ed3c8763b76a028c9902ae0b04660a3860b46439330f0f0f0f0f0f0f0fafa18d90da083904429a4c494ac0c9624aa14549a694a44c2991bd1ba30de8e9ccc4a733139f2e12872e019d0a420a700a33d470d8f08234014628d2bd2ffa3666fc4bdd0b608082db0c56212f4ace3ec188fc174253b6ede51024c0f004773a82c8d8592d72df09ae525faa0cca93caa9e404bf7e9b54d29a7387082e8e22c0d80477bea13bd1460555060e1a9a60254bf2889f5d77234f1899e092d2a5933215d1bae2828b2fd2596a010313a7fc98ffbbf42d5e022f502738c0b8045ba3548c37e9c534441c396858829d54425d27eb743a56da03605482ddcef531525f1f1fd706189460b307df94ab3e46dad22418ddac5f32b3335b64788d3e4b00b911c09004a373f41c56ea9e1c604482d33d39e9fd6d3e3e549083868c06801a604082b78b9eae34d2569f07c623d84c151d9e725ef40d0e3882d3b9ce7f2d898d602fa8204cdfe3a94b32827d4ba6a29b5f4a80b1087e54aae410f447f6978ae02e68932d6efae39d7e13c16437d19b848710ba11443049736288f40fc1e79862a5194fc61a0d39c19921b8d6c956f991b5ecdb42f0314f2e2531efc9285a1260108249429efaabca20a6f241702745fb266afe885aae11600882b11ce39aea53b764d2fd018c4030f246a753690704bf13b4ee759e52d16bec018c3f70d1732447ac0c0f60f881bf8d172ffadb26130d1030fac076be37a5848aed972729680974f1058e1a36b4f0cf61a38bbf40cd01061f5853e9a172081ab564bb07c654a8e94b7f7e49281102430f7c5f9034396b88ca70b700230f9ce4984468cc931dc0c003e3b9f9f427a1c7028c3b3051925750b9d33930200194020c3b30228745f2d8554173ee041875e02ad47910c9934e214774602f8ae48e1b74c7882e8c39b0a69bb72ac7f7582109c19003933d5b08de2263daf1c8c813c08803a334671271f7941c30e0c068f091a0d29768e4b051e3ee068c37302945e6cdddaa1b92d164b261b4814f8f6a715d73a8cb1f2e3e870c1b6eb0060c36702ac9287aa39deec9da1a5813a2e4c9ee0cd5c08aa71cf2664b73e0285d809106d67c445b84887901061a78558dd8af124b4eb0cc50eb824673818e0b30cec0a5ec5dfeba4174bc6e8b1a3472a0f722056fc200c30c044619c84003c61878f5db6dcff4618881afce97b23d8f64c008835e1252ca9023677b87a909030c380809607c819f9093d69b269d9f5466a8c9a861c30bdc758ed9c73f731025047861e386023e3e70e4781c385a0b30bac05b57d42d29eaa1c423c0e0022fca226598d71cc8f10cb81cc0d8029f3108979cb154a87881a105fe368755ed0429cad61a3464e4b8f13870744a004616d8681db2bafa0717bdcc50b39183c691e1050e848105764f698b97edb1eded0b7c7ca01b07c615b8f6a4619d83367bdf0a9ca90d2674f348cf7c15b8dfac4928b71315583bd56313a3fda8264d81bb1425c8db520a9cb29c47275fb390cf1405f62d63984437156497a0c0e9fe0c16c283656b9fc0e6da24d3c2ee3448df096c6551a3f2e3041db46f0267e9cdf4c499c0c4cb66715744b6f64be094cc78a5e95402a71a25a76bc693c0978b6fd22283a7dc50f0356e612081edb7d6fc5395637d8ec0a63ad5cb15947d903102278448a37e841c11691118897925eb42f46e0822029733bd333ce6929e33043678304df9ed4f83f40881f588363176d6a4cfef20b01547f7e90d25b30f0436570ad192ccd348fe0f18b51b636a467dc0e9341e96cfdc1e70da9982cccb2d0fb8b8bfa224fa7da5b4d901b7222ac742905a2dd201173f6f25d6aa39602fa20413c94d1cf06b5a22e85a35e963de8073bb354fbe693c4ed2068cbb24539633852044b2066c523a89068ca5947db462deacd20c3895f2b8c91c52be2492017b398455fd27ada5833062c04fca1ba345d5899d441830e046fbc2d5ed3a48ce2b982472a81c695f3b645dc18559f6fa4f9656b09db3e8d2dc113c968515c5ed3bad82f7cb7a1a6bf446f255c165d2129d605d7a44a9e02249d14f3f2a1825f1dd93f47efb9ce25531ddf0099e24c5048f01aff1850d2f6e3c8e0e5370dad43393d4482918b55b299e2e85146cd227a405d96b9f9246c18510a9eb540e16c316057b5b21e951d3bbb509051f4b294d6992fe3fef40c1e690ff7a7ad927d8de6457edb7e149c9135b47eb13dd8bf419006ad0d109fe8450416ba87082f16c9f6f9fa67ead9281e6454be00ed0b109fec374caeca5df4e760303a509ae83d2496aaa6c8d39efc8049b3908cd99378e09fe829a8a31e279094e08eff40d41e5e89158820d1d293ff42feca844991a3167867650023b26c1ded968c58ea3aae3da2109fb00434724344d5b9b33436d0117c0e220f1082e930e964b24b5232694830e47d84747233869af9add5e31dbc969540723d8d0ef6b49c4e86239ea58041fb7468e9ea0a4084e4694ac26af4bf4d789e0b564c98d9a2b2238537dbe1abda35885741c827f6f3dd567aa4f6594101d86201d8560544d8b9fa4bbce2a7510c23e72108ce610d931d36ce81004afa1bb621afcb57fe3397e0b2d1d81e04ba61d8ff8254ce56b861a0d2fbaca1a3a00c1d89dae0f1d9d9feafee16a2f37f5f90c352c32c0803474f88151a5a3e4105bd3d1074e744addd724562af9196a9e1d7c60d367ce135352ce50432974eca173738be87a42a866a861871ed8ecbe5321c4a0aef1321eddb091cce4814bfa2777b0d0fb91d32a880e3c70166e2a9dfc5c1bcafb43c71db8e4eb2932a6d869bfb40323377acc1d3526d55a12ad43471d18797b1ef4f6eba62e3be8c076bae7a78d6d08ba9ad1310756dd64fe72ad90bd3e5bc8a86123fdbff82f2c5083021f1fdb21073e67b333edd2229468c481cf298a062d31c6f453e98003b72731df8fc6dfd486d7f8a274bc81c9312c9bc7535929bf2e1cf0393a070614b084041d6ee023476a2fc9d6c9daa2060d2fc7818e36707f91acafd1c1064e86e957478fb8759f321c5b34170b500b41c71a98a4be27bae49b24c9c3d105121374a881114129b5f7f165e8e1504d037b564a6bccd8d2e88206177a1d68488396ee0b96de82fab7a8d1373acec0e6d08b22fadaa2a49c083accc08d489efe66517bd7520626e4d86ae55a0719b8cd2445a89cd3757e50171d63e052545efe9e2a2195e1353a078d43cc8c02586881c5d540000e2f6c1031948e3074808133d91525c690cd50fb15d0c841a346e3f8428717f832916376b7bc943a9ca166aca30b6cb4521a33a7d48d1c355e031d5ce0237ed0186b2538b8682542c716d8dab390a259cec8a1430b8c1e8da4de3b687578cc1b3ab2c078ea04757e771742270e1d5860cfc623e47c5d9a257b05de9492546b95b4022735f9560832749808abc005dd922d5e2519b386b0830aec6545d19c9a24a3630aacc9b413ef75a5d1210526c98f496f43d2083aa2c004d7b088d9de0094a2030a4c12fd1b37f88aa85e56d1f1045693c6ec563a66bef99f7138fa238001484587139898f7fc3de71b061d4d6084122b9db6d184959409eca5bca62229751a417574e858021f49e9d225af8466dd4a60ef6d47ae7ec7ca61cda123096c72ddd51c27ae8767ddd0810446e692d9229be408bca8a89164cc27aedfe93002a7ab94ceca54f1be4a277414a12444777e9269d42e741081cd3599b54bcc835e5cb5d031046e945a55ca8fe91002ff2926d51bb314042ea987f6783a760081cf1bcb7692c6cc50cbc145cf280ee8f841bd315fca98ef93d1e1033ec40bf6b9ccb30719dd8e1e706d61fbb1d2c94a1fcd5015dcc800fa13986d1f3a78c0c40f9a3a4e48aa92a677c0e6fee6fddbbaab8f1b0a74e8809da4facc47689fd0910356cb4b2da7ef38e07a271d248d1b55b5c504276bff4ca4dfcd30cf25f8e89f7f82ca31f1532ac1c312ec86a462d6e89f2dadaf04a7bd322d683135d1130f4ab01fa369ec4e3998e6dc63129cdab9c5acae784a0425c1e80f5983f25f772d4f24b824d2a89c2369cc4d8b0724d84aa2d33a7ad48e27f3083e5975bb4b30ed1ee3e108c6b63a6f49c849768b1e8de0bd640771031e8c6064d2cc25d46f8e581b2ec16311bc054f7af2ae76e8c420c143115cce90ac3377da23118c8da87927514ded8d0c1c34520d1e88e02d674c2ffa53624afa21503184257da9744330c27267f4109ac733a8106c4c7522a6e5eb1fbaa2051687030d1e84e08249887b0cc23e4e109ce6681bb5bbfa41571f1fe71108de32247954bb50008b0c4480143a780082111234bfe5d0586aa63f309eead249bea8fbd94cfbc2c30fdc590e513ba8cbba5ef2e803abc1f3757eff502572b0d0020b2db4c04206161988001638f00e1e7c60548850497bb567919ac71ece430f9c648b9d37640b722b96818f3878e48149afd97edb924b2aa50d37eb8107d6555b83bcff7a0d252b78dc814ded17ef3426ffce423cecc0c9905822e69ae9118b471dfc14f3281db8d1c14c254b316b935ba8e031073e479f0a296e96db4353f09003a336b1934ae9b794ecc4e0110746961a9136c848d9173ce0c085b67526cfa49fd5be81511ada5b540af934c7ddc0e5607e96368fc2e0d10636bfc71c53c22ef3ea6c6027bb564c96e51af8ec2649c83c42ef22ab0626c41c3da5a73b0daca84b228be8100d8c1c95beea274c35299d81df58d2c4e4bf66a86b0656849e18428d5d064637a554efd720522764e08375a8d1513e39235990e6497a7e8888811b2d328994933ce35a6160b2be85203f4efc48193e7880812b3795f46d66bfc0296d37bfda4d7a810b42a9348d6dd993a7bbc07bb2dc9f3a5525752617d88fa0df444ac12d709123071121e6a1053e24bf28b1d4b64716d85342928ecc7c9bedd2010f2c705a62c81a32dc73ceeb7ae07105f4b0827de0f0a8029b3d317267cf1732a95081519274fcbceb4353e052e56814930d571d7848811dbda72bf306652a6467a84581cb25fbf4998ece50bb61c333071e50e02b8886ac09b94bba44468ec7416ce0f1043e6528f57d9541c1d790a1821b39d6c3098c7e37ffb24a1fed5a2fbcf0680297a2448d22d4c804937550714c434e09ca6309dc68ff98fc3cb8d808b51738f6ca29811b8f26bdbfd45b8f2470a762be7162a8a890c089b45f2945d00cad00175c7cb100228035781c81b15c1325d4c8e47fb211030f237011cdf27e2559394278148114f6294fec7bed8307118ac710180b39449f1ad51fa2cf50b33d7808815151a33e9e2c48cdd7305af0080297822ee91f96f2aea76620bc820710d8dcd1e2eaaf9a213278fc809f5c6bada2d4ff69e5cdbce0e1032e05393aa8bdd2dba9341a78f4a0a4a9f26eaa10d7b2e1c51c60c3c6051af0396c4cc0480b3c78c06d7e289ded3ee8910a6efc1726d8019ffde44b010f1db0975c336bdacf0cad0de4f84202095040113c7270fe2416bfa7712303a50c1e38f0b8019fd75c2505fdd9d3b891812d6ad471c0c3068c4e9a949f858a6b5a8ec1a3065c3e15738d2ed18013f2d57c5329d3b14e3360c42c89e9c9b80cf8ae5c71ef1403b64388dcef9fe301032ee8dfbb778d1944f30a3ec8d115cdcdaabeb42bf833a52b77d09be8752b588f413368cc2a757559c1454cda4f97a7362dcd2a18a5c1ae7b4d8614fb54c1df687c370b9223a4cca4824b3923e635a147056b6aa2272ba5d036f2533039fba78b505a75948829784dd394e954599482499bcd82fafb574a5716a4e04c88322f1962598c82edbfbebaad4cdf13e94216a2e03ba48c5a9597d2a7e80c352c32c0001570e1851708d0228b503031e26687f2b614d40b8acbe213ece97351697592852758911cfbe39b8d597482d3dabfd2a1ab196ac6b86864230239687471bec08021260b4ed8c767b189928526d83c3542e5f38b1799e0ccd56285a0732b6414095960821325a3249d648914c4bf047f29a6e9fd384154095982abb49d56b364703d5125b853df7ae7d143092e255ad2ce6954ad69127c923812a40789f99346126c342552ec6c151e3a18096e94ea2b214ba8df0a063e3e929005241879d5766d133596527a041f3c66fadfa83b82adbecf9b2b6ab4ba682378addfecd943c8083678bae6c94155f7733dc862119ce95e488c557aeda3b640c842119caba6b8659aa9de671689e062059142c8374204173a2d8efc2041da0907591c828f31a81f2d0b9e39655918828f2cee63a22b276451083ea6fb3db5b6e2f59d1d6441084ec791a3be17f4887e06c17f783ead1dec2ae7b420f8133d4ae40e03c1b665d71cf504083eb2a4ef8d21e40f7c6a8d9bfdaa2961fb814f214acebf51d3074ea8da3619eae403bb39418268d1d018d53db0ebd135699e187244d50337da35a87fa7f2c0afc59c92744d15fc4a3c70223953e6ccea1d38bf8979b1d52d8687d8818b68e98214617a745f7560d2989b0e62fa54ec181dd8cd911cd3dee84a159f03a345258b869047e41191039f4b97d60f9df62e46e3c0b9bd4409b936660e221c3877b1db31fb94f4856fe0ab25a9f2ce24a309ddc09b12952b63b6b4814d5dd3da3c11797db2817fdf0ccfa742966c296b606cfcefccfd44ed666ae0336bfc3b66acd377a5810b1a7c4f660591fa296860b255a764253c67e0c2d28d0e4a86181e333398bdb2e5cd29a7cac0fb95069535e7d5acc9c048fab4b2da8f2948d1185851a5aa52db79d4498981edbc6e4ac4f5a85e7e1818a1d2ed8e5e1218184f995975b6b1e2565f604349caf8d79d17388b5ba1abaca26675bbc05fa4a8212f8438d9e6029b64cea4a386bc31f9640bece954972c3b2bfdc5b4c0a989ed172f8ab2c08feeb4d5633258b0d47b97e81ccb2b7069ffd4760ca65d5964053e8559f43b0fdd16275560526e2c11a26a52c1332a70d1d4c812cd77156e4d81cbeffda63ec4e4214129f09e7724e5540ffa641b054ec490175963060536756bb0f4a03d42dc9ec07f9b16f3981944ee8a1318112c757d1affbc2b9bc027a5b5a73675d097264c6054b4b8c1829744c862098c4e5d77427dc5981f2a810b3277f8951615721293c0295379436789042e636a9290829649de8ed0a7797fd0258446e0fedc6f7784570476f2a7f1dfce664104f6644d0c212236044eeb2ee94eeb29c8241502df7fa24f9d8b41e076b46809aa9a3f4a08087c081e44e9b5bc9f46e5079c5dd66c1174c5075c6eff88d1ce2b68ee7ac0499d74def6271e146da49d8a1be90d42163be0a38b2ce1adf5415da403d6dcd442a4bbeca0cf01a72b688da1732931ff70c0a451a5c24567734bea1b7031ac2a36604765e7d1a4a5db12520336a827979c93d6a0ae440326e8fcbcbad90cacf3d55306ecb678e494b26a8a746370a65789640183f228695a43902e1160bc82491bcf6ddb5a57302adb77d09474becd7a2bf8b81b22478998b29789155c085e5ac9eaf6620757c1962a399a46e3b6f64515ac27cdb8b529950618e7da9862781aab2c01062a3e8d96a6e4baade70b0dc629182d9e419d902963020c53a067659372670318a5783dbe4ed28d1b19c020c5173046615e1de9363a248ba3230a466fe658ede7059ad20fbced26bd2562f46cb5f68171dbcb9236c94a793a3762f081f1e0d13cfd5731f6c0c874b959fd6b23683b861e1871ff3f1b751e182dd5982aa21d030fbc5866ed33cb1d55217760fd3f7b4a263ae5cdc9f2871876e0c736c5544f32778851075eb35dd20ff51322871874e023a848132165cc1b392ac811831873e0cf437d881e2647f215430e6c89c6f51c82c76c17ba03b0d0020b57438c38741e295792fa396f04074e47daa41dd29dbe5bd4a031230337be02e60131dec085d0e013d43e62f0387203a736dfe9aabc19a6325288d106f6fb32d4bbf28927bd9d0762b08115a529f77eaecbf7118df3f15146d660d6939836e60dcf7c0c35b0213737b64b34461af814747ad99d090d4711a17d6f153a03d776aa7b9a3603af92a2ea5fb0711176195853923e5eb995b6cc92818f6ea5796d9245cd8e814939c493d54bb25219313051339d0433d3ac4cc3c069d0fc135576ba2624a99a4e5d582e7d818f565aa76df5b4c70b7ccc1caae4bad705fe826fe594abd4940a165a181738cf987b6409a5a7712303ce058d195a6c81cff590a46ece1484ccec10430beceb552c2dd1f2a6aa64814df36cfb1d3f5cab9a430c2c30713f77d29439076dcf6b5c1a625c81533d55b20223b2ac4cc67c568111398d1252e3d9ed5ea8c08925532e2276aacf488c2970498988a6b4ab75fe1e430a6c3ecdf9a3dc14053ea6cffe74490f054e0409a92d64718feb13d84cadfa1da926a60a72029f2505734fb5d9c2bf78c013623481ffdfaadc986f26f029632affac7a09dcc8b3ca66572e9a2b814f9b3269245d31d9a649e072d9668f562281ddadbfce51c34dad6ee304318ec09b16a129f6a7dee6d1089ccaa0eba77c2c021b4964a5f04ea9ed2644603fc5d1cb36c9cbed2130d23d7d345a88221702af315ae7a867a33925088c1ead6934440e086cf88d98bc4f776143025868515b88f1033e48127a82d0cc07bc58dedb8f145b375226f0372af0f1914288d183f4c9b397b895e2011f2c95aa60254a5de5ec80357713f6f11443074cce98f7925fe65ab95fc4c801a772a8b8a758282b79e2888103b6eadad66bec1bb0752a447d1c49f921b2019f9ff2667f91196356ba8851831834e04314d7d851bc553cad8287c0f220c60c3891556e9e27e5516d8921037e448a98378ba608316250aa684c99346968ac982d9ed29d36f1ce093160c0af78b068f133ef525005e1e315dc886c42f44d743f5cc188106a74793a55de7b01400c3e5ac17d86b0e89e342f7f7c86da711938ba0c070226f001192df860059342d6dffdbeb3d575869a8d1c3256051fabe0f2b388ccb1b7ae4a7ea882cfc9b2e4cad2c9083c8d1b19c8f1910a6e2348ec3fbddfe7251736643c6a2ebcf81b6a15f840c5974325d50b2529d53b828f5370a74fbcd63d86469a22993ff65fc8d87e2958cd8841097d13ef5472c607290e4a464cc26a1b05935d2d28efcc19354351f02af1cfc52a49edef43c18e4e51d368f1d44de003149ce8788c5aad2239e5355060033fc157e63feb20b38968d4134cc89e92d648bf152deb1f9d60ddedd63f7ec78d14bb61434669c00727d894b41bc32c4436c1a6cf2239ed4fdedb574003c78df7fe19664fe3468efdd004a7a96fda3666b7f493b274e304047d6482531f8f24427275a6bec60726eee312f76109ceb6836eaa78df47ca161f95e0425d54e710733e28611f1f9360f25dbe25c18564d92da4b07c44821141c40eb5f0aa9c7c483039a8cc7831a6caef9a47b0ffa1f4a53121e4e8c88723f8acedef4e4b295e9f1f8d6094dea64b5ea54262ce08aed453d729a14570294212fd1666213fad085e3b75b609a272326d268291f984fada8eaea7ae2e3e10f1e8e834eddf4f2d67a8f1e0e310f96108fbf828c47d90027c1082138b987473ed6efc67e0e80668a1a9878f41dc8720d8c993c36d93e746f70b4302c1754c79dc3a4bc5dcfd0cd4a800c108ed587944e211287f607d54ca19eb5e645ecc0de1c30f7cde8c61dfdb9a472db0305f08e1a30f7c78b4f51cdcde02c2071fb84a1b2db25799f6f7b1072eb7a5113bbbae4cd203232fd9e42d553ff2d0a94d6b9d94c3942cf8c043e6a2635ab5ec5d39173466201939ce8cad0c3eeec05f7aac8bdea66bb7f9b003174a7fd00fcfeca8918f3a900f3ab0e96d358b6db238e0630efc451c6d1692c849ab490e4cccd44b5df9f2e4fb7160f7357f509e32ae780e072e079dd7827abb12b1f3063e44b44aa3ce76036341432346104a3f881f6dd8eb47d297c89a0dfc5a59ecbdcdda4fd7c06e0e59e21d94ce2162d4c09889ca7d9d21c6a453d2c0e5d3d3c152eaed6c221f68e04d44a7f1d59062eeefe30cac9578c531e96ba9ee871998643157b2f4dfbf95b278f8280377fe7ecaba554306cefd5b44a8d14abb6e1e3ec6c04634d116bf2409c9ee8718ee230c9caaa77b9f76570faf0c1f60e0d6db2db544f32b8b99a196650c1f5fe0bf82482269fa68eddf0b8cca953a889919281cf8e8021f5488a6db3ca4b1b5b9c0ebb59dcec9cd45a7b7c66fb15be0728896a8d7e4d458da628b1a346e74d1c50c1cdd801b14e81cad800b4840021f1f0ed042cdf0a105de4663fa8de469649eb2c0c9107a4aa9a46a9b7d0d7c60814b96c4b643c4ab0cf12fbc2816f8b802e7191683596e52e275bf173270ccb821638b3e12b88004245077a38b2e08083eacc05a8d47f6097a0d6c4123011f1f55e0b26d5d6b0ae9196a6a0af8a0021745e737492928b724f442468e96e17ffd3105266596887834f5e11f117c48810f9d981fea2f2283771df8880297b6c62707f32084d75ed028010e2870bfa68305311de266446f031f4fe083d094924ba8baf0e104fe449d44b7dffd949c42858f26b03d2684d2547577daf2f1714ce07d84f707e176697661a1c5165d01287c2c814d49aa7b1c9dfd42dbba527c28816b3b377d37ad9cd9fbc34712181952ec2c4b3b12788f394809c9424d33e508aca6bc6d97fdb72ee83e8cc0e4e039849cd3fef111868f223036e963e5242302a3fef69b23cfea2a3504fe62e6e44983f6a67a84c06877644ff9930892a206f808026fd61793709328d16a20b0192b4a767111fe1efe80bbecbc69cf7248ce8b0ff858f957e97475f61cf9e801579f5310bb3f3f78c0ebc66c1dafedd2d466076cccf422bb47e53acdb9f184001f3ae0f2b42625f3f76be8d4ecff460ef391033e5b9ab2945b775bf2880f1cf0218e4e232c88d0bad7f88f8f198df8b801632a12a396cab944e86cc067eb7ad296314bf8a801977489dc2193a7840f1a70d2b2b7a46cc1779238034647f18b1d2b5f2c35a166e14306fce7cd412dbd660bdaa3153e62c05eed450a514d9486e403067c502551e3e71399eaea2bd85abdd25dd7d178a62bf8edbb9c837a116999d40a3679901f42ff4859c18a5fa54dae238f557011ebf3c673f31b1df75005a33ce845fe2474b3728f54f03925499d924490a9f44005a7e377ea177d4966ed789ce2d7ca2b1d3c75537095e22f724f8594829b542234837f1ea4e064a888d51b9a3478e9310afef2557d8e4a4a2404a51c3c44c1f649dc102704dd9da4013c42c1da59a6b4918182af6cd9bf43dacf7ea62e920f3c3ec1ada6ca1c4fe566280e1aebe10956c3555376cbcf5093f15c6c5183060e3bcc4e7012927a50abfd195addb091fe5c7a7082979083d98f593c36c188d64692d9a3f79a796882ad4d42eb6fab1e99e00a6de02fb54549b24dd944367067d965c13a9b8ea4d7c0eb28937ffd5103274544919d73d2c0fbe67e4caf9793caa281bb929bd28472cf6077eaaf8f9c3403e725b25e4cedd9524a193893125448882275bd25031b4c9baf08d5a4447e0c9c26bdca1e1e42c42031f01e3dbdbe25ab6e320c5c5a25a12c9d704d2a6060b3e5cb4df22c5e90982fb066a1a26ffe158fbc17b8ffdc39b4e25de093d2b14b3aa95ce0458f12692dbb057675bcd592d4f6204b2df07d622aa4ff0e4296b2c0b64889a13f72988f05ce7545055b8b7832bf029ff22819bca268057e4d6d5805ce3b5fcc937f24d353810b5a4aa34af44e1e4e81cfc9432d058d4881cfba5b25c213056e437de648f1640a6928b05622a9cfd39757629ec0d77fac1c437950a17402a3dca2c8bf8871f3ba26b04169eeca9373ad746302a3925049f28dc5d2a725b0c134c98aa5be415b94c06b95cc244a4f50515249606da3664f1d75bd26a98c21814d5164c86a4ae3023b02a3929297458fe837a1590b981118dd164466341d56b932432d052fc3460e19e450604560eb6a42bcacbad1412442e54127f14cf22b36047e52fcec907933c8b00b13025ba222e513a1d74b75160456f376d09245e6d8498de34fd0cf858cb51b5d74610c087cb2cc5cc1feb27e8af6032e454a2993e9c8ff79643ee04a64fda63508d6032e4a52117c7d7d720cf29f81a367d4f8c214c078c0c5bcc1eb548d4db2640008b6034e8d7ee7cbead94c9e706819311d70f147a4ff5ea82fe97f8cc172c0fad5464f614a7ba3f803c30177e2aa1641d6a6c9abb9011bc9effb3a8ece1738f4b46881d980cbe8ee41890e762542ac066c90f194a854a63289241a703a5a864ea33a88f47d067cb95a8da58f4c06aca6ed1cbff3551411b2187023eab3ede73da56390c1800f9542aee01d744b087a059f26c5bb64ea96a26d57b0c9dbd279a78f92476d05a72668d34a23f1344559c1c59446927e4d57c1a98c4984eb6bf01b53156c27992cab68c4ea3015fc660ab2b4e7f0182da8e0d4e82f997b84679a9453305e793c4fe68a2918ad2a167f83f5c57829d80c8b77c2d3a4e03bed22d9c4dc28f8507293df474e147cfacc9ec15348b9da8582db546ec17dffd4f8060a76c783daa02b745f8e7d82d1acea929444a7f2cc136cceb95b3db34eb0d193166159276dba8c138cd98498c1838e96a34d70ea7ad36f0c1d71d4046b72344347ff18b393092e33b7f6065dff2a263851da36b3b897e06292273ce369094efc82f03eb9ef5aa9aa04577eeadae289128c3c59d9828f3f09c6d46531732b61597949b09ed5f6f4867c2458ad9c2f49cc6022760e2478b55117a2d4a3a8d123d84bbd6572e3b66ded08fe728510240769ab6937829568a2e27e2a89d0352378d19c2396c8f5223849ebd529563a21f38ae02ee42444ce8e3f4a2611bc557a45d66f11c167c88b549d630ec1aff7a8e58d3104ff41734a4246bcb68829049362acd6542683d94e08d64b071f112f340836a75349c84a9973982a087e2cf9291f990c0427d3d4ba9bce2f6e4940b06b1e4dc9ed9cb327e11ff8502273a618f5031febfb5db47d6512f6814b13da84ecf841c60bf2814bd5392cde7d6889ee81b51ffd99fbdbd7cda20746d276ca499ace08ca0393728e133da64aaa170f6c32fde423c5e44dcc1db8ab8dd8a1985925a97fac0e9c103a84eea9081df89c2832ccfc9c0317e615122d24f7b44f0eec47db8b5945895d7d71e06405215553e45788393870fff9ce552bac3b726f6044d2881cd1cb972073039f2d2f2ce96056d5b136f09594f24af3d0a65e63031f34677f901735736a6be0cc3ee7de6cff2f2aa6064ee5cffb66973430669dfb476a16919da181bb78a29a4967dd339d81dbf5bcb142277a7ecdc0a78da64c79f805a12c039b9288a7f32559ca181918ada13dc772cda41e039f4b83d010ac8a408981f53aefad98dd61411206564ffb586d9a860c333060d93ab7721057eb0b7ce7bf983faa7deeec9417ec6a5329e9bb3429e6868d2f70fc16349c7c810516e7bea8a102cfd15c2ce0e3a3c6e7c8d15ca401e4a0bac085e705cd2d3e17d88f549774c9d316b8e4a93e9a52500b9cbc4c72372fe8aaf72a0bec66cd20c5f2080becc79049e97a6ea6b194e1b8ba0213ff449bd4dd98f309dda0f18509509f1dbea0acc0aee6a49fc1b7d2e972068e96615505de46aadb57b0edc8a6196a26e8c2f7074505467b94fc18ea428d8360a1a6c06ac618836a8d90c43bfff8f0a20b274d2829307a54123a2789b95f1927a7a2c0a7a89e2334ae95861414b8689ec9830c494ad07c3e8153a133a994d652ae4ed190423981bbb16e3725721b866a02df1faae9a344103dea7aa198c00815217bddb2876fba0436e77b87f0ec2b81f75c9d3b8a3651229b60a824b09a4ee7e0393a3fdb47978aa64c17ea08fcc8ef4ffdd1ebfaff4e52bda8af3b5045e0345ea7564b9f82a520192ac851e30b1ba7ce0645042e2b4c2deccca4b95b831a02a3259a11026b6b7a83901e83d4cf82c0de08edfd10433d5d12088cec3b6da2bb82a89ffc802dc97fa1cddbf201e7f613c392b69c2ee6aa07fc5b9a3461728347ce140f58d39f2d28cd5bed80b153a52383e6be789d29940ed824d4d59526297ea3ad00142a077ccaf72041cf53881ee1808961d6e92e4fccbb3937e0929ea6c7a4531bf076a153b4e4f89fdc523560cf2e6d70f7fca1538606bc6b55e9b7cc50392c35034673947eb588556b6c092503d68277b57e4c79e15dc580bf78ff1153a9c70f220503467b90173f7743428c57b0a7c722f5f9565cc1c6896fc5680577625ba742ba6c5e3b2b182dee41e69034b9dac40a3156c1d7298d41afa555c1061db93b87e8c64805eb5669bcac8448f1c2196a35fab940c656100315aca49d5c417cbb0dc4380523f5bcd5b34677b77e3310c314ac04f9c1b4887c3632a5314ac1ab558f4a4d69f37db6f02f6ac8c004109b816af48d931588418a749a9b3ca19121c628781d212c5bcf62c8498982db58e9f2f8fdae6f2a003488110ab63e930e39e4d441e731063140c15b4b88fbd7b7a622c62738b14e9b513f674dd28385165a6091a788e10936875876907fa226d73968e0b0e14572214627385552f407b527d535b2450d1a4e03bd0238c1e6d851b209567363ed6bf4383aed4d88a109f6849cf4e5ed255aa24c88910936e61092334f98e78b09b64bcf2269042fc155d0df14b4ff6f75c812fca7894907954da413a54a7021735ab41083127c5516bbf1ec0ea6e49360ebc2124312acad5884b41ab4238811892bf4bd7bd0ff6240826f11b55a3313a9427dfe860c1b19e3116c7bb074227e899c42770427d3eb24e5a153428c46f0954c475e8e1416623082fbda24bfc23f8bb84c6fd26b31b50145f07fed9233de5a52a5c1438c44b0318629d1bf3b1a2597818f0f44f069325488db9ffbba5e438c437035f135a57acfd93215c3108cd0bb71f5b62aefe8310ac19e86887e3a4d57be530c42f09e29d967fb28d1ec1883609279444d22699c148f21082e558a559eb6744a9581606fb42555ab2240b0e9d4574712a910e30fbcedae5a0a295d2a8e02a82411a52269281609045220083108cebc07e312000000081a140663a16830220ef54d0f140003582a22523a341a20261a108dc681913010088481e14018140885028150208e84711ce9440f0fa10a8ea20c32aec88a0b5d2ba0a6bff5d4f98a86ab8caa9e0fee014a4d2a8afbd1cb5951a85a684a41eb4ab956e6aa12d5e2a65eb8cad082940eb4d9cae8f4806f163f0a0b75cf6cafba74a5a6a932e596e9ab0c101c9d6122534f85bf6e9bfc683e74366dc11556b33268fbe9abe24fa92189403415b122ca3531d789a80947257aaac8abc5ab208a324c78d6f6b63b18b1cbf571a932357ff991cbe2ea19f8de99ac95f068d7870ff96ec2687d75c15558bcc2df274eaefadf9f99a46046638ce89c13294cf618c94de26a0cc78cc19c1d627216c69a27b1b3cd8069f9f81df640ec70f3d353cf74630bbab474ce5dc965522dc2883a6bea8cdd6bf0146e6f76b00f0ff5ab02980bdc33af510919f809e221f8d6ad32158169a98bf94a43a7b9c5fbb5c7042830abda4478dd076243cfa908de9f6e5bdc41af203c346f6fa5c18c2080b01de1a58042c9b7d63a78dc890bec16729404f9e6b41ac4d97d3ca4080bff2027e52211d4590f542eec0728170dfc4cffed1e28085f60dc6c5904230dc642c25bb8d891b396d66c33114ffefe925c3dd6cfa672c533bda43734b46f8ef37033fb90501a802eb4a47d83d1eb2b060ef753f91d7b67bd2186245956c7a4806bb9d979058cb26e6984f50319cee2277c2b2b42e5dd99268974d7ecdaf0877703ad28f0f87b328a23384ed34052a0ed8f64e309adeb6bd88f05fa4156075bbd6fdf8e876f6e3c35b0b785ba5238293b93db3da70ea16030e9f2fce9c0e86be878bd9d067093e1c5874c841fe217a2bf18fc869a09fd3bf69e8f1e094baf38e070863ad2dc52e0adb0dc249846c0bb7e9806eeccd9cb50e22fbf098e5ecc0bfc06ecfd5855187e0288055e0a6cc4c8db6d8538e58c38a89482aa7befc630151b1d6bd1522745a330f1db8283c75b11bb2edc7c927e93c61bb4be0a1f49b2d1f8c6b05ff0667b085e5e20f2bbb4080b614c930d30940208de0b82b93a662292a495688f437ad1f7dfbd8435ed22cf766f8a5ba9c5cfa29a847ec0d19db7eb392127a15127fe6797494b468a8a3b8b32ae458c203bea0bc18db6464591ac26e9c82289af5438138bdb4132c1b99de295e0c7a76e1c5dab341927a571cdc34585a016688540b6d6863ea4a44325e0bf19c11308b807df059a4b31d266ab314aec2ec0d7c471bf1c3b533278c0442bfe1eb3706f7a498d5e830655c115bb34f2bfb2636c4f7ab6cd793c5ac391d03082f4d282d03c6af13640045afbee18aaa3a54153df4e821aa093a1e9a5ad21260024a29e202436819d2179a25abdaf0d324e161ddaae1c794d0ce615f87c155b0732e01577f04cf1dc227776609399d3355db75a4fb1f4827b3f405380b7f108a4697dd290c406f8860f54b66c9ee74ef878ae283ab65b5649aec84129ffb7015016122a7702be0f222e30f70ddb900b31564bf4cf459bb563c1804b1b39a42a92ac3683134eed5cd208e33418d2e4e72d78f09122e7845378dbe663b82aca645b21733f60ac1b3a5c579b66da55e81234992f3805ae7db88dc141c3767544342cc96c21a032cca4a1dc4ba5a3088c685e023ca0d679041292c63e3b56b9eec183bcb7dd5ff6b2588e81367db76597e1f843c54f245ad5499fc0f148250835cc71c2aef3ba33d499b200a45b28d17dc2c7f889aa236b33ad65b3147aa24cdf691d592351e9491e2da32a1a7df0251eff862de354a5f6229590206eda64006a576dc09a49e73c48ae8e46bcc81b813462d45e81cb8e4c2b0c456194f189dcf92e3e1055e915cbc82a856b72b3324e54f9f8dc1e3d61e5b0b31f513f4ddb754ff7cca18da762263862e2491a6393ba7b0969e0c5d2f63d514ce470f96ad9669a0c0945830b66d5427b3aad663efee4b4f6b7182b397f71080db6d22c5d19bef9dcf33e52410c51aaad0b330fe5a0a42049c15b9e3de8580d663087455a6b6f3037c7a88a82a728961560ecc335c094999f294c221b1a86372d69aafb9b1a06067f5d8c8bce0d6370f676584ed388810f21abd67cd22c3153039669940cc0a48b201a25a932cccb747414176ff587089c296c910d035753e62a5b762689a7cf23dd7c5946eb69cba7a091f7722a853c5bfd58a51a1229174f0ff5f6f064ec446f53fe631ce9323b1f038003d0f52aaefdff4725294d6ba870c4f1b827edc8dc8e1c3604aa45dc78d10d545a664346866b004f6644d56c6a7e381391a8aa95a2a519960d01ef110a6401b6df484d62843c4a7f7a29e3a07a37befa16a529b3b059f7569d71b134f01b135f18ebe220b65f2bd964e42af70f56de0dd792b43fd79b03b3a6dbd863503ad392e3e5deea6e8e820ee4a3cdb4842140c8b54cc0927073aa513614d83d95d759f3739c176e4a9a015896994078bcee486388d3f051fab043803d8cc3b54f689f37c1f714b95fe81e4ee4410e59a22480ef5f68f148012ef979c92b171ef8db54768bc11e82325673cd14c4933681f44dd29a8ca0e89f398599acc8306fa6bee5b461933293332a5883d3a3b417b263107b98b7f28f8e2d8bf85338eb53e8b1a588063be447ad2da264506b30337ec6ab123446ae0f87ba9ed40c7e70e33a59180d7558815a424af1557401c022899fbe46993c18587526feba74e6fee652b157cc968e9290b460424dd6e0c3b5026a2cb6848f2a84e0c742e81ae167e8282a44a3049289d523cb03ef0b60d08ee8b8640feec235c8e25237c2ea6cde6e46eae1508bb622532a1fa0d9be91b6f20ed4254af002d3663dc597b23e6f8c3c14afc78e51335edc62daf7ba6ab129996e5ea6447e43ade9849118644eb0419a3d4ad824f9193a05eba2b9485bca778bb2e92c4868460fa359daa3b327420d95a00a633a14220d570a53db2b025014527125d6c3a08b6873048b607866ac3c85c56bb2fb3f5e7901f9e3ad2490b78c272d63943793384d57f5fb3be41ea6260ba57e9722296972ae36ae620186ea4bfd93ce4382531e42aab3b67f56fc54412cdfc270812487ccaf6c4fc3c9914866abe65e110d6e0b33c3597e6d3879024685a5acca745edb9486571acf07f230a8bda9d2e9f2923060bd9672ef6c4dcce0f26e255853cfa681e3dd9237262c970689576367cd6ff7956b9df1f2b0521c6e563affc96aa4ee44c706432bead59332c0591da0114807d7e32f5633fbb12b54943c782c603f43a24b3bd1aa538644745d98ad4e2c467dfbcf57093791dba9f75047a353c26bdecc429ee568e720d66d61e874c3eb569b2c10ce2526dd9ed89f1a63344edd259f602855d79e2721436021653111dbde067e8c39dfaa37f3a2b4e71e547de5cc4b81fa105ba79a7cc97cf8d230f753799762df14f65b34de75b2d56addfec6a2eaebbb7960a478fc619417e2f2dea3fccada923b74b06dfdbc4b4465b60800af43dded429244e26d4a4f50aefd34681b5603d8eaefd02a339326c2215eec8091366be77583de18f9875afb68481cd82f74ff674939095b344ca2d4084fa91bd82ca5e0b2142f4a9bb62694753c3adef93ff27b2389b79bcd9ddc36264466f6bfa636c76dfb6a3864ea103d6094377dc08224d6081ae609a9875890cd5c9de45d6684f30b39d9dd2fefdc2d4f7ee29a8adae69a658a6884314a1881d38f2d49d76461f359506f43e068483c358433820c7993b8e6bb148c45e8a904cb14b8440007a1435829ac8724190a68c2c0293ab2e0abfe04ceb9043b10f2561bd6831c074f16c90684c96a0e92ed7f68a0cd3245150921a632eb4b8bdb06842d0ca0d62ede1d0293053b94462353c66cbf26b17b016d9c0fc8e2fba5d22b3cf0c258e4f9fb14b0f355168b4604fc68035f3cd1fe4e875ef48ebd5f712a9baa179908e440c7a77f80b604775670e85947d8b0fe8e11047a81c56c109a500383331cf99bc7dce9c7a389fc875e4476f19de171e4936df0e54c8eeaec26ff38b2c72ebdba214875b9efb95cb0800ab702fa072bb4186be9aa88199ce1480f91621ffb88fb3aa9c68c8775c159b1a27b883c6c7410c2733b98a3c7166b17cefb3506651c1484ac944b9649766c350a5fee61a85cf4901ff160c367989363405388da425cf7996f6f8182204ca89fa34b119aff20427e525c33511911c72e4e4d162b03d6f8e7653426855dc06c1870c94823d80d2278c62e4b1f715a5e4a3f60089409a47c78883af64218056f6539a12c7bd615e8ab19b4a4564c25b459e5c3ce920f49d4d368ce7573e48aeb44087ae690db4420a12976802859eba813b88ad0234759b8e3c8564bb2036f21b5cc120ece61ecdb80589b8da150df63d23aaaa90e25d9df002e61dd87cf13b004dc3fbf740978eb6efb349037d4ecdb2694c410da386cc7bad5937a067232da02230a9a885824e4109405e92ff51e81a055b56b90e9083d11f97f6dda63013f90a664f2b3ab0e47c480e388c0e925d8ff92cc378ed08bc208bd800dd05dbc30bf7304db282c8cf3e6d5c610766693af0ad2471d20dc31457bcdeb23507c9b6d1d9d86f902d7101768a913db9d07cdbf9e44ea9ff00e5b771a9d78b469eb5d165c76e60fbe4649831529f4b82b8e95aa92522d00cf740405eec623a244ca2d5bb82af2dd5f515f349eaa4a58cd21484643869f86515052936b4bb9665b731205766427b137031bce3cdf32ac9a78b7d87981143fe01a1870f3fd1da6b2056877763e5bae6609fb1dc4282bc0478f2244b5ade95bbc0cdde018cf25df80725155358bc5d0488bd5c1066cf2c0589b3242556bddde9dd091ea44405f55c7e1722a42ba669e4aa740c49fceb6a67560a28ed2d71f7f147144bc41da845d1aa2f35f97215980175502ced6f760059a8c00cac02e8a877f72524629b8a3548338eab82a806e0d688da288faa3200c10ccb06f91b2ea53c5a14555abb8e882b33586420ece9152952ab8c8f50081a01b18ff41ff6f041e2f93d465d5b3a5cb1d9fb32f6230012547253bc51ccf7f6bc3b568d95c3b175cdc37eccd929b77f7b68624dd567e9ec8d5c7ef5ba30ca88c01bce8f8a46341e9381636091e51eeb64e86d6e38d98b9a47630c5bac748a4abff61297970e9eda38b0f9f9926bf9c0e8780e7efd6eb0b4449fa05a6dd689ce662a9f0182239a66b04ef146fb1eefeae080348f6fdf82069596688642e3787af907f544749cd22f09806d13df7ada56129668512921de147b053f731d1f7125afd0d6032a4562dd06bc98fb3971127693167936533082ffa3478c85fd8182dc23a8270ec18bbaa336ae500d5477ad23efb0a204dd3e96f3ad6351d91f79d8a23d4fed33113d1354dd0c466d84de9549bb8cea9f622c25281a77910b9414cbb34d6d600590235779e6d675fa2c3e8bf1516fa95dfdc99cc44a778f5cb0de8abc8d38310d8baea7489094b7f9151694c93d305b536da6f1432edae98f0eb55b9743a5c3a60606fb12e07aca1310db5c86803b4ec66b7dcf052353f37426b36c65bb31ebf191ec67938931a23c854228d882025dc4289f8606553d14e5b141f1ad9a903a42b183e3d2f3218ca0ca81d2fded7dac0692fa937a306ed4222afa4f31b5e85f5b5baf11e3c0516b7218e77e17eb9e3ee2479deec2980aa88c90ee2ec57319db4bd05657f876b7060f9ee6875ab854ef95d630021a1c575b51374404f0a0d505637c9863ce1d44944edb9872a03c197cb9583bf2c0e916fc047a04bbcb6dafc35c692781fc500507a7bb5dffd04265c732b60c3f45ed3745cb1238a976995fa9e2814bb7800d17f182bdddf70c440cc735ddcbdc467874fa89e1566c9fd2d70d93362c27eb65d78e68c95d9806e94df87a42679f461edaf65cd8aa1c929f01b668332964f87428ce07a216a29595353c359fa19bbe9163828a2274a9d7cbb646e5d160af0613c6253e34bf67c5baea255a1b1d7823acf730c95692bd280a50c2747394460546e75422ca961a01b270a73445855e43d7bc9c824ccf7b5fb82f698e1cdaa8771ea3013918563aca63b279a32ff82102e088abdc63967728e946f27d0b1748011976c4298012acfeb63a5a152d8a0f8f471520122b6bc853928d7be748b90b86cbe741a7a023e5968b403bf2e268c260eb1bf129aafafac0693e942e799baed33e184acd9339b44caa0662de0bccc90962ce6d2e22402f22cc2180926856d83ade7bd4fe615c93746bb36db5dfb8f52f054934e0cdfc4926d39ec70c0ae30faa84b1c07536c41f6ab338a406b9a6d72fef2c021988c0acfd9340d84ee83e5fa3d4d912500b7658057d103f490b73af20d82283c6a63ad99823c6d2cacb940d3a8ec0add23378a5619ecd1732adaf9b0d892a427377f8e344bdb94a04f3d63f3fcb2c79b175fc9153e333be81f4dab8d7ca6a4d31acc844d8f71b7c190c7f63457a7bedafeed917f146b7fdb922141423d50d5bb83a452aa217d2886d4859bde54df7e1e9b4aed8ae6c144e6263b923bc11b79bb2bad2514175cd854e2c44384fc5af72f8836eafa93dc5f38e7f0172c079a030356cec0d0b5562a49ae405b7a04d6e903199a5efcac17c061fc63f42ccc5551ee557401c6d3e2365bb536b579587e326a595a8bbc752bbab9ea5cd9a4da6d41684c0a2b17a6b32f113ec2c09ce0f471e07890dc3a13b0f982308cdc412808db829ef1d7846161d6bf2bc74803d8bb2acd9cad890d7aaf6599c604936c80bcdd2498cb9bbf81e6a53cae73de2d408382e07e25aa059811eb1ff999ed42276d0d080720053022156af525122fa65f422c589ed53dfb792c510a703c77ce2b84d54e5782ab5869c70d7598da6434aeae21e8560ecc2301d7424129360883193ace0dbf18e353d8424ce5b80d8ca4fc3ff16ef75256d7a0570d93b9ef396e72ffa5cf541b722935b5abaeb7357d60068013245cc2cc81a7571fab7f9155291f2aa00befda8b8981a544079ca0c9e9ba6c98645071884936b9c7ba6dbd22f55090657be6124b761ec12920283e053b99aa2a3cab3d3294c16ec956d421ce3afb8f1225397b8db4488586ee2e97229e32648aeabbb62545100c4c75eda431e89be1074218df67cb2d863437143c342f41b782a68b70e49eb32e48c94381b80a139ba93a9005ab004fedf653c7bd640ef70c0dc66c7b003e0c58a0c6d4a03026cb868399aa21e785b023bf3da9fea9678185dfbbbcb8e4a5ad3d6c0a1f1c94745c52585e3201be8843cdc4c0943e87d690d610f8d32cf3849482190d724c269d12e06b6f678f7c70e9f7499287a4143154ecc0a002390e261feb5e714786711fd73a26c9ce0b51cf972274236bc9aa9494f9ad2650acac3b144ea33c0abed8c5b5a9d0a5481b543d59f350011eb34de0ff7cb2074f11aae5767082ffa3939ffb7a4d20f82aa0d35c532b90c625daf5f3e9f06f70b78dcc6f5353836acd98e49d86a0a796b87019832e313428a139f5cfad74f8f19606590b5189eb2890b025e63230f66c0a4af94bc7e679ec54a71bb09fb0658eb00c0c2c076c251b857005ea36aa5fc3a5d12b621be8df4e279b286c7b4d8bedd940aa2fcd9866af709fe5d744a1ba7672ed6a731f277f5e166468801324d942d3dd9472dd4b8b62160adbfbea45d8a2ff858295766f61a7f6a2014224639b64093b64811ba1fc06bd99699f001ae3c5b6f7dfee929a3168d62ad55acf6fff1373b2ae6dee4adc74e30c8919c045075e0045297dbbd9d48b82058e3908efd20bfad8c482097d361a4b5ee2c90650ae35815f3510956cc13bf07506099036fbcc765e8e58d90b1b2d2bdcb4aab5a7f044731444a67c5892a00fa0c3b11f2655ae799441ec4a60b484d6b7992d73e09d526cb94f2c5e02ccea6df03201b4efc73ad09451e2d3539e56790b3000b870f190666aa9dd786d445f340dabaeac4440411e98435815b82b8c2d0400dcc30089c7a86980a694879032f3e8951fdf680d77bb60800dfcdb40f807883a910289f461d41f2355c05baedc114914f60108a7ae4d68228400831f03e302acfdd86e1406ce50ff677770db4d4b74397db5bb2b86084f97f16387a09dbcd8a9ccad68e390b0e3c14e7567d4f6e78c629706bb29ca90cde81a98da74825d87338aeadd87690a3282d07ce29ef011c1106b41367a6dd32df31b9921af3b4fedd248549c4715d2e3830613b89c2a7139afcbab491ab441e8e5256adae8933928684c1251fe731935b8ce4851283e931f1ca2369d1d2e809aacbd891a6eeb9240ad278c104356622a60d491abe47640e006321e7ab23774f2b8e10ee4924fef83b3abd3ba637ff4bc09c4db3b7bf6b1d12e4067b64721de97623aaef17b486d1293764d46e661fabc2a20a5fce8a14306e93d7db5a541ec2593873001a2d150e656e380cd08c73a962f25607465f27da3992b2f34a63be435bc71eedbde1d4d006a2cbee9cca2430d1bed4e9d6724d19418a6b023cbe57fc21fec9237bbb3ad8b4731f0a13e6232a10556588711a6272cf87088093b670a39e3b00677f0cfb0083912a16ed8cc34eefd4035903225a932a14b8f3299e890adeb4b0a4494eefec562217b4a991a2a6d60633067ea87c925966b2cf2a631a4bef3eb25ed63c128cdd8a22b8fa326adcec00ab91b06c4d55f7671685254a186542338207c980f17d2621035bfc3d5c6bb0b81a5f9364d965349286c3670d252c9041bdea76432a4cda5fe2d5ca6e2db6f899d6e90069368719ec62df63890a233bd6df53a0087fc16ff88b5d7a1ed1a4fed88ef5549a23e66e26f02535a649e8661da032fd59835a67f511a87f64b38560dc47deda9a2a0d5fe3c5baec4b1bda9c053a21d5c29ce1c1fb4ead03fe1cd580ee1d67a2eb4451bc4836ae35b1660a52aa2f217e9febce24041834c0ebf004a01af5b6c9deb4fa2207029409e365d57bf6e593b380fc92ca562e1f6be2b5dfa4c133f66ffa0a4283baa2a3e979585adbe1f80c5199b4b98301affd00605e856bba6bd13e065880489e6838404a0c658e11b3f005f13c8c5caf06e6f12fd492bacbaaacc05678b29185882a1677519ddd088a91980fcc389097e9a753c5d23c92398dc7e51561d81516b18c06e2c02ab32e9d10248739ee4ad6ea66b97e13780e72ce268090e94fc29aacc6bb780591dd0e985c715f2b2c2d166013b561d43aecfc8da7b392de1cc91b136776d4c8f645603c048b4032512ea36d8228d141b143924321c44bca156388bcc54e0416d9886101d286cb4c8303ab28fed0ae20dfaada1d2ae3313196de5a7e7aa68bb78ef9bce8e1857cf7389756e68b25554abb302e774fb072b0aa50652bbd0a4fee015a801636e4320ab733af2aab96271771fc576d4be73e96b3875b5ac581d282b7f2bc1be8528f0fa72f513b9153976bc94a31f37c5b006ee43edabddc04848741c7ed39742f0551af58aa690f180a790f14d2f53b37c0bf7bb2848c52d5fdc71928c57f5615092f53de736cc26c415ab9c785e41752797218bf88f4b794956cc13d9fda10ac8297c2f11b18695445ebe17154c0b04f45e6d33729629f540780ec7ed4930c09ef1a562460ac14d24be450052f0a4d94a1b2e1c74bc9880a00ab1488db863f9b8e87f25a2f312c442d4ad081029d5817dc7e5614d3b3b9059230b40a952316328e7da98e9e2e67b62e32b45b52543e5c3bf442285b6dd6e4b54480dfd9b43e1921c21dfa5a65b9534ae38a5a8ed84638053fcd731c46c3e21e6c0f912d3867481d0c8129a966a1912fcad0c3ec7ece6d7f8f405f704a969d8fbf0b1b2f3364dd2ec09d15f57c195dce08d9f83ff79b404cbaf8906276b0de004a31762e32f542a4501b1188fd7641b140793347d6be05d10d106c7399a9428349802163d985ed008a58344d2bd2d0d951f541688ea0b5d60220343fdf2461994b361919301681c2850a8418106351354d4505207a5439450b31a6548493111793f8a5d0f2527541135d0388f50768022f6517dac500c4ffb4011112a5ba7ab96f052149fb3c87634949da080a410a8af4fc2f44c190a2202c450b4a1f5fd5a3a50f08a9280946750ee031450d9d9135a1b056cb3a126871bcaa05ed796aa1d0022320294cf50d4a05a841a26545e42e9d03c5ffe4102a50514a342f5ad836a0844550087d628685e448434883714280dd57773abc12c93424214b0b4fa295b3551c0236bb268531407d7000d9fcb0922ea2b25bca00f95f18ed2a197866af00a2524147389ea7b2dc5ef9043a15d286059aa7a026d146375bc4b29d25bdc2cb22e0ab32e20d1a485259ae265e18b5116a5bc84021ca1746ca6ce4adefa0602052314880205e400e5c4bba4fa60f0637378dc8e3c0628f145015df74748c2e14f109a13d6e8b46043fec756601ce22a16e148034f153610ed38e30cae056a44289a40498562652820e18064fadfe4aebc46b41bdc0808273f97af182eedb95f5bec2bd444a0c9edb2c11bcdc33cd89511e726871b73c6cb2195b19516d3cfc81ee5cf89dd4b9e31edb98e1032f1cecd225b27b8f88bb66203040e8919ab40cf374fe12486a217f515044019ceda9b04d96a705c049a8fb9836882ee598b5c7d57dcc6466bc2d6d1016560dc65c40c2dbcaff6fe154868c814008c17c0dca226e68d08b1425966d301a3b4e8f9bd780948852f9e4b8d716b7a49208452662816ea935028662e67b94617d696fb62d010d5dd97fb61bab6d0ad22c9b6f1a9bb17dec7acf85e4a29b96bea7bc3c35ab2cd3b5eddf83d8f8106ac952fb9d186d3fd37595380120287683092a5e1df946b0a95d39925e3370fa53be1130089405100849b619f9a3a55bc2c800dfcff04bd4d88a2678c290c0b9a5b610e0363aa28a2ac27bda18978217e280f89f4357afb98d2635ba135f71d863b01b0ff814e0e288528fa9f91a6b1753a6878ddb724883cf521f3061845d32820ef66bd1bb55c0de30ce8e48b0a7862d133a5653a8d2eeb59a57872e4d605ddeca4534f1c7beb93d00381d7c3cfaa635f2a031e403275e307a54d2be02e53bdc13e0ccf2304563e37077534af28e917a9f8b68b2c955cdb217171b82c8a923297f0152da3edbac650c5d1b908414ff6130a2760004815ba97009354f33942d99fa1ef81071caef31dcac440fd7f93fdd26077ad414621acf4bf52f6ccb4ee1bb0b0a4f55114bbbe8636476ef158f24327fda0fdd2a56bb27009bf0f592b0e85c3635485d249e07933201e9d162107f196669a1649fae0a31cdc6eb98680e715a3a065a0a7e3e42c6fbe06abe02871c1760ebeee958634fa8e18bc712c8ba1a9a720b21662a91e02149a7a3d4a504f10b3d8884207af36fd5205dc2d81ca6371aeb825992717c50f523d327afa6d44f8ae328b4549e16901456f0e7a66069c126641b43c40a19354048959d703ab5a729fad650584498b73122998815001612557a1ae444ed7f06c6a9c64e0b7722cb272c8a9881fcff093bd1db8aca722bae375076d934cb8ad5c61f16aa002ce12bd9b76607e2f80e8a58ccd4124bdc3b9ad94a723bbb1d36a1410796f567cf2158570bd1266856b88e215d3799585739928207604e7b6a8527cd24c45b006035052080b2f699152eb2935908d305a68327f26bbb56dd17b4ad649ee88435f252f0fcb4a8c95898652fee24bf371859b1ede0e5f3e304ebf203c45cdc3d42123fb2e277ab3ff122a68652ca91083e19c6e78a1b1c9c483ab4ce318c9fa922e57b199f8e8390c51aec391f0f2c8a6d18c2841811ff614f6070e246860284cc4cf220a5729c61720b61c942dc042f2ce2d7c1a7e7eaee634e47683ab069cdf5b22fc761e902fe59597d87614c1178f5d16351c01da0b72b3c29cae8c6981616de4f3cabc817e320702f5aa69b95072adecde27c487a47961d5406b933692837aa7e356e26f0b2e6231e7c99f79e9a5223408f2e8599ea5dbc2fe4e9c8e60074ee7d2696c1f01baff768dd1aab19adf881dfc7909843388e58ef3a7a34d7b81c0c58dd417c23790e4d9a9add26848faac8f3614e360d4230afa9124bfd69ebce2cb04728838e5fab1644b03f588d1242dfa2409b8507240be1b9f2b7cac26360459e725c1f593111c2f0ad8d526bc81433511032af84ce47818f21a9b25a76c372aef5865c38058c38b5bfa3d5ada2f2844e8a206d5fd794ebdbc5cace469a326113a7a958af43672e560ccf3fba4d23afd530da9ec2904e1f54758ec10bc6749457eca59467cd7fa1dfe3d7c61f5180384295afed6b342ac28cbf608409b5aab1dcc48045867e30151462b339d1fb84a9fdcc5418d21c7870ddba6bffdd5864324e7a7b2605b6abf762f203fe1272359f4c55fac95023e86aea8bdc20ea35e33c7c8eb3201eb5bc08a9820f66c6c33bb337a6d373ef67132ada9f5209d149a589a24b7424be61106d98f8a45c03cd4a70069944f430cca07a12bb4f66788739d374cbb648da417a58708088e0d186f5a47f6c30d1e7358b19f65d27eca04f927165e01391bbba01a47fb3f1f60719c34ff7c8d0491ba481f2652098aaaa844ee631cf7a219dcae50a35d2ef144ecbd2b3279e64899f2e7170c1c92329ef8f43c38d98609abb98bbd8251428c81026f440c5dc699f46869a60db1bbd7cc368a14b7817aaa29a9381897c3998d8972905e4a3f5a4388c353ca931dcef75bbb9a0bce7bc5003a0d989cac46f66f0daefe89602406f46de47ad5a2689c1f413ad0d038dbe63f2dc39a6892f54375c8de8c6403c6ef64caac8752b43e81e06b499d8c2c499b25ebcfb3cf9fc7f4e4e68a2144a9e65633167860ce477e66e1e686c72b9224b9cf2f88068a502840105089429939cd16abf23ee5131cbc731417d4daec546445a9aebc7e9920242dde50ec8f9fccd165db97b3bbc2758ac1d3a5be2a0c99afe1c801c4eabe0e5a64dbe1e08a02008ab4e0c44fc9bb06a4fd0615fd079052f0479502acceb7f5ee7ff5feba06d19993e4151599a1065acf01e0019d67467f55b8a5e333158b6c5ad61da265856eba6470d201950f6f42f8cc58b3c9e72a3b70ec9c0cc7d9c8de55914915379be3ef181e9ab3dded33dcf191765883b4078566309edca81723baed52b4131caff1ce28ae7530eec4535efb719b27acc3c7333644e19d237dd8aaa841c6a9c1e0838ea28c44c2620c323c10673f65e3708018af78342c7d5a7199d6d88838dbdc9dfe42abaad9b65525dfa0659f34895b1aed3168331db369a650b402b88b41c6d299a0c98c1e71ee1786e735c4dc60981c95b8cd7960084b50fa6417f8c38cd005d3a1930d651c9602fb126c7a50e8afaba2597264234a57d038a4d268d3ac554736a295a68d0e6495294c4f3ae7f03278d958b3373b1bd1e298187e987d4b6d7d22525c2f8759e1b9df5922463b94ae671dd24c34acb02ce7ecfbe68c6ba85df4f5ba91353f43ac6986e6b014f0486158f2a7f2d9e05613730186d3d19194dec98d524ac54c922ec7ba59982ef36e98897776a92dead567b11eaba10d48348fbd6acf71740544ef088d1242ff2d54df03591b37846dbc21773b71aa93332456a74ecb6fe791e6a252b60a2ae3aebd05a99f3a0108fa5886c6c9c2bdae2738a6015d6a8185b3c11a752c9313f9626599fb84f4484d454166b64099e4e8383bc5f027e724340c09589a92b2d6660af422aaa1a7ddd2f1abb5bcf51f922e63320a11485053e921a161cd9b822c7c54e960fcf895a3b8ab7dcf555a1917cf8e8c34d64e1e7647b34364bad78debc216df8d694952bca2e43a5d1dc4d36e58e96bf30b61adf2adc5cd115edd8478e56856acfe64c1ea14ace8142e3351b313b0562596f9540866307387962a4424d1a808d406e0ee80da312a1dffedfb487c1872fa102f9acaa3d9405ee73fe4b19e478ab69ffecb4b1006319eb42aa0d0ba49837b5a18df19ac635ea03b308e010084a2fb59fb020d44d483599bcbe1fa25072e6863cd144d0ecc864f34958f05bcf38034fc6837325cb83c53664e8622af5e862f23037d42c67e1597017b0e86a6b91be51639948160e34ecd33276e3b189683367e65a751d68c7235bab777001735b9d7c44cf41c711b1490b810d8b79ef2657fc27b4f966a41949e3a701b207a1f6ab4b563c7d53cf620903f1e03f0a50095162db8394e54721de4a484271fc74bd61650cbf6b29464e7e13fb791acf2d8c926722756a97a309ade68028b2c23c360909a602553e41aa8291361c68486b0b76eaf1d9f45d5fc56b134097cb5d271d35e8729a11e3a21271f22404518314dabe25831f092981f3e0b69da8163e3fcee32410ad644e1b8e04ef80c22229b36c5e7c1d4a092b8470e6641f9998301f98e6b8276b4ce6611f96dfa6e72907ac131e6fb5657f56bed1d21e07a31db74d24d796a6e9c7fff57e791218cf3ae845a139200bc5901da4f6be04ed458a85a37eebd9ab1c0e678e6d8f5da008cfd6fa7c24d1a41d6219772a8f2a0e608464cff4886c45f1fcace89be33654b88370059c05291ac08f815f44378d888fd78d26c49cddfe04884f09e9d5c4b172753d62c41aa7bf988e9cfaa9c651f6b88896a43783d91677765a0b17f84ea48941432f7665d4895693882a6a5a417ca035043a8c2338a145af4050668f47c529fcc6312065e11e3e8c696363aaa6f613133fd4c8c37b1446ea625cc8fd1967d08edf87c0b6ec0dc8c0bf63d21c09c539beac70c1a92505723c4dd3417e756441e18d8896dba019a0fa3d82d64545b389f59a365b6830c516c8285e7a472342e5277243d51597664aca5be1374b08b4b271c305e565f50098e1b6984c630f6e43c8840ee0248c3d545c0e8d094d7b55587d76d3d4f3964e5ec18ec67997b96220b4ef2e8320aa09f95bf6dd2df9a55c46eda7c3f194ceae7c0d7843ee452a207919f3e894c8b73e4dab887788e7ecdf66d24fb0d8fa3d2325679e55e8c0e483e0b6cad020e96c45e0b2b70b61a0730c30c33cc30c30c33ac9ca72df7fe8317a9bb39252525259709cd80c6c584c6c584c6b50de701140b4c0b780b7f08894421a5d118628686055f8c158ccac141c249314f86f697257f0c5df002128c2a13b400052b58810b2e50b6b847b849b35d7b4639473871269639549c856b849362cac631c13e5ebbc4c231c20793b43192b8fb9c369b67b8457852e1248ab7df9d38960ca708ef463b468c6c541ee544f8281d653a8ced21c2d7e8e181ffc55ec9dd1dc20b398b74467510b21d6708cf82a7574c8fb9cfa11cc315c28bce91ad345bcbb54c121c215c6b982ae5b289e1b335084f3cb45d5a88df26ef04e1bd4b466a3454cf8ed5e002e137f60c2dfb66b439860f10aec7742a8e442e69eafcc1ff2c764ee1fce025bf747119d41bc52c85eb839b1c887dca281aa53c0cc3707c70aad33d0e29ec4a1a695eb83db89212425378e6be4d0fde27edcf24a6e6c1b1e4153d3c78e1d343738bccddc1496f0c3d835ce9824ace0efea4838ab3be94e1375707a7a663e5fc6943c0d1c1e91862c858a293c34cde1cdc105ff3e910ed31454fb0b5293839f852628f2f35ef02c334b838b8f9f1b656ce920b56400707274778adbe7ce271db09f6dee05ba88fa88621df021794b7c1970bce0d3e8e17cd2a733131fa27d832255c1b7c341aaf31323ac192206b001a708001a008c706a7e423e69ad11851fa35b8e92d99b466e9e86be9d4e04bf2c9a0a18617f94a1a7ce9194d6bdb7a106b3478fd37a1a99534567268803b83bf3d6a6972f6fa89314371d2b5f69252067ffa2385da0ce9d84106ff2c83a694db31f857d1434369c5e0d46ae69864a799ba307853123acea70306371e6d7ef1ff0b4ec6a833c8c675bf7ac1df4c0db545424e16e982977a4c72ca33170867fe783c83b7e0fa4a55ae4fbf9d472d785d114ae6c52c38975298e8c8191e7b58f0e5d782a4d0fd151c77891a7923c60a9e5b8c18c6ec1b6ace54c193a894dd96192af8a04185c9488ae77f0abe64c73f39266965560a5ec66ad964b9fe2d1a05e7c16a68913fb9dfa0e0464a6b6af6ca139ccdb9fbe62a27789e2743cb1eb6dba5d2043f23244465ea14fb99e08620da5ab295736996e0dafcfc796b72a9b412dcf28e998f71127c0dbb8b41fc4282d7491ad544c8c33ec9113ccd3086c81a2ee273c408aae3b8641bb122b89a1ac5cdd69a544588e084e81411d619e6e80cc10d19927b0c1db1715e089e4d68d4a12b9dc64c105cbb680dcec2cb630b10dcd09da2edc2f7036f62229a64399fbc9e0fdce0d8d16904cf20a3bd7063844ca7868e330379e1add86be58a51b3c5c62efca011da3795535a6ae8c2cffa71cd9a6f947372e184479325f8cb3d88c1851fcdcdb3b745d3d8dcc20b595679aef1cad5b6702e74546e4d311ee15a781aa4a5cf238fac490b3759ab584a74bc7fb3f02346ed6e8bb52cbcd8e629e653040bad63e1a458fda64c0d0b1f86895219ab83bc9d5738ebbeedb9c2c7ec1857b83d3973fa36cfc12aadf0b6bf6385354e9f6256781e659a233e3f8e7715ce47c9d02f4759157e8a315da3a0e9392439154ef89cab26c6149d4546852f9172881839a7707a563bf27b7cf68e29fcf4205386d408277f297c183fb3f19f21f785144e4d57869e1a937965147e88f0e917da4b43220a4fe3c4da3233078b84c24f6b29b9a77641e1a6c494831871b2d1fd84db187834ffcbc0b1ba9e3036e830e339dc4e389f53aa36364d336f39e1e694193eb7dbca49bb09274b689cec31ca16bf26dc8a6c953617e53f9970a3d1c9bd8497ff07269c568dcc612e657b8c4b781a12a9659b39a786251c3b1bfb7ce3db5a57c2197f492b352b25bcec1e7e3cd45a63ac93702d6da7e39390b2b14ac2edb9476a3d6a24fcb4cfd2c03778b507125e9691c79f24cea3f3081f2493f6982b5afa7784936b2ac7f0b071b7a5119ec7b56493b3b45061847fe10d728cd822bc741c177f961ade5084efe9572d54f892b413e1bbbdcd6c4ea92dbd8908c773b0cbf8ce43785dbe59b423a3cba521dc587db1159eac3b5708bf26446545760c1e47087f22499294f1d5566c108e7f7d8b85f9e7d552105ebb59105971d43895817063e5f9d031d4937d00416cece338ae817ff0672b5dda98cbad1ae8072f747aec935cec839b791a4ab4c62934453e386162d228971d4f8cb8072f39ead5cc9dcb7f433db85916eeb637433be4f2e0635c15171ec9c3320e0f3e18ab9cc9caeac7be3b78a2619363b4f49cd4b3838fef616450da8da37475f073a7caa58ba152dad0c1b594c3c4acc91baa3207efa39fa5904198f5b41c1c798b5932223d0e721cbca4fe8eed633838dd20e4303926e951dfe06afab746fa49fad20d9e4f454d9ad2b3fd6d701e238fc7ff0dc63d36b811c3b5e47bbf34da1a3cef3af7cf91a9c1fb709724a7096360692053abe70a231afc9445a6c2b64f3257677036b4dd77c619c48a31839f9281e498256570c2245169ac92c10deb763ea11a83371563450adba4492231382d2985a83f94e48f738085c1c0e09d4accf88d19581c01fb82772b593d4776378f792ff8e3682b97e4cd979ee9823f97d263bc25d3d043b870ceea924f258e2df81f23527a48bfbc59d682935db3b95b3a2d0bae770eae9952c7b0e08b78cc4982dd69069f0c76052f1a4b7b78b558c195fb9ca2c2af4dafb805ab829b630cc96e1efa55ea50c187e21731bbc3b9953d057fee91879e7415b21c26051f66cc1a6ed36951f0fe46a32bdf7b8c313228b8961e5cf60d19f3803dc169f1088df9cb72e6a605cc09d604dfec35a68b19461d454990674cf02cb7f4dff5c4e64d1e0b6c09684c5d49e471b800a6041fd9ab7806153c1c35b8646149f0d342f75c6b7ee0957382dd1e181268c9d6f431fa7bca0b5e900017c8e00537f8e20531b8c1f957806d05404002015cc18ee0855f36b7d4a1720d62850333829f26a23374c629826f8dba3de4f4b03685be6044f0e7eaaa44f267508919825f8e734ee5317fb69a85e0e54721fafb3c25cb2d172c084e65d1c86a11dc345380e04ce714a984c17ee05d0c7d65256216b2623ef034b37bc6b081bdf06c935fa5188d7b45f342f1c26d94c5719a7d76e1d8a72c928dc2baf0b2ee62b498954f9277b970fb7eb23f0c142e7c104b452323af4f0dbe851773b9cb75b06ce15df86e1826c5ac4d9b5a787df162e1b91a4a86d1c2dbce94ed1dab789669164eb8b2e8161dc4571465e1a399f1541b7362e1440d6f3f36fe9b53a460e1847093debdc2b36d9825e3f0b8c2ab102bfb36b6cd658f563849335f869c452ce4c20a37fa1a6f86d95c851f414c72f0987ff74e156e085e1b35354dad5f77a970ad5274d89d354b95d8864285a3311323f6a468b319a7f0e2336504fb0ef628dc6a2853b815b6c19878570a7f1dd54f239b3cded3198a149e24af98e327ec233a0ad7bc2a948cac872c8f287c47ad6a86a042c1a5a4d690621e544603234381c24bad1e132cc2833d100cf50927a5f5c8b28b217779c2eb8c71d924a323c76485ea8493613566a3c5486dbc5c284eb891af4f4afa1f746cbb09afa3f85f5abb54a134e1f5984684d8f249c36b5aa84c385ac126483bb630c155acaaad746476b98c6b5feacd32394d41a84bf87241a53346a7b4ba2ce14fe71c5e24c83f885855c2793b4742a128e18ce3adac068eb1e40baa49789673c87b8ad992843f61b64172aa5958ae22e1038d512c87cd552cb50c19c8606c3500031c680614249c6cf95d35493ef737f97c41835bc1abe08b2f5cd0821318a01ee177474b86dd7184336b292bc2d62c661ae1864621f7639c6151c2087fee521d83e0297a7411fe854916edca83a7d82bc2314dc9dba56312e18770cbb1213588f04396b58791d2a5670ee185d8953cdf764ad910ce46f6ca30b914c207f7eadb195a08e1b45768ce78c728fc41380f366535e4b79042045187e7941eeb4078d5d3a629db3df41910deb9a4a3f0ffc11579e49d34763416fde0e377c9f361227da0b5b3850f4ed6d4108928116a9fa070420eb73927f7137e0aaaa1ee3594679fce138e45c9923cd147fb613ae1e7b79432aa59adcba040062b9801058c07c90947bad287cfb4f8c739f583dc84b3317d847acd96b4660f5213dea749b98245544edb5ec039c84c78a921d3c77e7439c61c4c38e9dd2e224b94b6c6b98497a24743ce915237f058c249513208e9eca1ace52be1ac4dc84836172e434f0983f57dcc24dc4839ed720852ea939184f3af9251393b049f48249c87a11e47d7dfe6fc8084d3d330bd671456a5ef4778e7a85d2bd886b18c7584976ded337c8594b7b6119eb7f86aa6f48e31aa8cf02d5bdea41a53f85575117eda1812625295d9a02ac2f193e449846fa1a18d86a4d8701311ae54e8c70d2cc798633b84ef5b9652eee428e4184378793c48c85e2144c4aa105ed6601969a699985a2284dfa9bcac2fed527906e1869a761845b22c4f47109e667ca934dba6acd0098497ae3bb4add778d03c20fc6c90d6213d5ffae30ffe9cc55423269ebbe1077f1d8614e233fae8b7e983134436dfe4ccd158357cf056257bf0e3fd3a62db3d5259f4e0a7f990a96d953c7837edd5ea51ab2d4af0e0dcc685c9dec1f3958e311ca590413bece026cd65e94ddc4a93a30e3eb6185ab1432d3d0c1ddccab098ea33f73b90e7e065c90c42f9c772f0c3cf7d288decaf4f1cbcbeba2812c270f0ffc61cf5e65791e4bec1cf20a7b6e67937381fd3e5d77eb6c1c7290387522525f94d36b8ad751943953a8a5eaec1f5a97fac1ae61a22a7067f5b528a4aacacda5d1a7c0c22f6c59482063f878c635a4ab660d933382239dd64f8a5d8c8cce0e4afe83845668b7d193cb796e065f926635c91c1779873acc5305fed18830f3ae4d47ea15296550c7eb8a3ab737c235e5286c14dffae1583e147a9d9a2437b6be082051080003570c1175fb880c020bfa09cdb44cff66833fa03e98522c009b20baeb6c64551cfd9336480905c70326477c687ea06c6050ac82db8591362c335faac2ab55083cc820fe5aeee4382a7c7512c389931ccf08c357905374f466f9d41b2e90aa5150a292d3c5345cae717590537f6353e87e66eb6122ab816a91e597414d3249d82ffd60d5622c6de5811520a5ed79c550e498d822729cd69b88f515c24149c08bffd2627a39d2ad7802df20927891d1b3f5a904ef052f97cc7a434c10d1315aae5e9aea94a269c72ccf24972c89c608b309730ca9b1ab4b483dfe681548265125cff6831844ae4ef9e344d05a39497807d218317c822917047c83402a208b2086ef00d55f564a5d21922b89a6d1e877a087ecd5f886f97d8a91621b81639cf658e36bf4910fc8c8c5cad16b53b0d042765c931760859e15ff2032f8618c1fa72237de0d8e7ef740f8f21c4bd7042a61c19bab8c30c2f7c9c3dc4827f6417bedc54c819a5b02ebc97f31bfb60fea1712e3c2db5b81cfe6287ece2c2cb9a7144c914e32d7cb4d2a0e61bc4b411b585b3665177eed7c943ad859b8287ec20e5248defa485e358b4424ed779a39bb3f0a1afb8cd947b467cb270455d621a839b6d8fc5c29f0c9a16fd86855392c394a389471bb357789d2368d6f099dd29e50a27ad23d2d9a4d70ab7c291ee984556f82054bc556e7f153e0cee39ac8fc64c8d51857fd1eb2462264c456629ccb26fc30168c001182000010840000cfc37e0043240410756309e010420c0a1c24b1e352ea8877495c053382ab22659b1d7ae61884053789f2c6323d6841cc2054be1631cee28bbc32829bccd97367cfd5d388eea285ccf1453822787c13534120c1485f313eb43667708a99141c05038161d24e78cb5fe490282c2491355d9c1f959840437f842066604fc841f9fa167e968933ee509ff51e798314507f128a89d702cb64cfebbd0d9eb523b20277c98398688d91d8bc7cc26bccbe141869d3d9af0522d79b0fe960b3196093f35b5e39b5c95278309a7cb3ea30e7809ffff3465b9a83d29394bf835e1151f29e7aab10f2be136aa160fe14addc3352025fecbe0ba52b28e9d0027e15caeb8e0a0a65b638c0428092fa26543cb23dfe1fa136c550123e1d4b54c24c9f5f2af2d0021e145cd5d0f3d4965087c84174e42fabd32de2eab41a023fc961cd4da1b5f4e0f35c233c97f8d728530c2b506a32eefb9638cba10b808373aa6c5f556dda744115e700f71ac61c942469b2030117e6cc72c296ef6512d44f8695d52f02c39c45417ce031ec20b61c356fa9a9475493ca0219ccd9d95633cd67cea0ab010bee5486ddbe1d305b52021fc697c6134d4c62ced4fb0655040a28083f0bfacad2ae547df890109f01350178021a020fc9ebe09cfc6e82be7dc0103e1a35895dad01c867c0808c72452ff96879b7535bf807ff0a3c6f4307b5e0fde0e2fa01fdc148f32c68f4286d9f83ef8e9fa2a58d44e1b900f4eaa71a41a630cab01f7e05b4ef3615d3ca6871036a01e7c3019784c99a13ee79c3c38a92754ecb29a4879d38078f06347787a88d8bccb25c03b381d3663340dd301b48323514ed2c29727d832c3052bb8c1784111b00e8e276fb9b7ea0eb68d136c0d01e9e0c318be619f7dc3dce609b6be20810b8ce900e7e0860c22d954b67f327a82ad18bcfe0c7e063068811b00328172c0fd552c3240410b54d0821990e00666fc178b058c83b32621d584ec0840000210c0030358c00028908104fc37c03cbd02e1e0a5f412793ca43fa56f70b3fde5ec93aebdbce306b7330709414ae6be6f83d3696e272b0d7c629e0d3e0c591d530eb5d99135dcb1311b934ad4e0a42b7b98d271c65c9a34389d2334389d83bce46ef994927206a7353c9a4fb9ddce2b66f0fd71248ff29e327856b361254506672b877c912b4608d918fcec2987e059c63ba4c4e067ca90e5f1b73d530983631943c91ec3669062c0e09987ead09b6a21ea2f789abdaa1e62e20527f4a650ab1cd205b71f4dc8f0e83ba490c1053fed318c1ccdde8227f218ac05278966181997b3e08d3490b568f93f628b05e7563de36493225da257f0254334b064a25511b582db2863ce1ed266e3a155f0f38fcd6453a9e05b5f5606c9814a6d3a05c73ffd1e5ac55ca15229f82af5c8c5420c13ea8c82172bc7181236a3a830a1e0a96a9b76c48414b67c82a35e39df5fcce2afa513fcfc7d6aeb40a39b954df035e4c71a4cfaf2fac804ef2393a954e85e79e0127c1c53688b1e1bc28751093e944849f2e528934a4c82db3977cede2cb92d8848f0debbaae453ad63acf1086e56ec0659f1753d3182e3ef3397ca52b8f7ae08ae6df94b248d61293b2238679929da9a4858c6109c0c2b66b056d127b82604ef6263b4216b8ab0c982e0a75411b2efc32bd5050457e44b4e73593ff024564697962603cba00f7cfce999963da6a7a517bec563748f3e656f8c175edfe5eccbee2952a25df86942e53bbf2465e1a30b273cb6708fe6910b2735c6e1c33bd86f4ee3c275e423e9417eb0daf3ddc2cb199944fb6a5b78f6c953d2a429fe63b616be7b5c588b9d917c98b4f033dfc74ef779ed2a9b85f749352daac34c479e9385efa1b5717bfeca2e3ae062e1ba45690ce9374f46be57f00216a0e00e070b7f3367488eabb25535ee156e8cecb852944d15dd7e802bf84e2d9b22caace35ae1a67b14339217b92063138e157edae80d1a568787d0afc2af699c71ce95d2cc7a2c9c2a7c891a22678ad54c9d63854b851b437e1c9e197bad8f8a325c4adf29fc1cf3e518292a6d4ff64ce1788e9650edcf95c2cf932e774fca48e1448ded9a31dd1b85237e9171a6b16ae144e183d8d45d123d62b844d370a170d4b7f3844ac58c9466058597353ae6f2e47dc299dce87358c9776c7f9ef07fc2c6980d1155aab94e78f9277c67d022393b4ef8995190702dc14336f336e17466b2cad1efd384f711d66fc173e332e1484b7bceaf7d3156d032384c7851be194f26e9b5754fb0751684bb849b59b9ee1a86344bda09b6583003e6c159c28f91fc40f3ab9f6ace09b60c095a8002133c411c5c259cf37614a7a511a9bbc151c24d29f44a4717ed26e1894beed0b5fea56a3949b829cc939896dc01abf073a39b3c394223738f2a7c9b7099518af4f8ec543857e944925ccca6c8a0c2cf9ed72323d23d85f3bfda8d362ac3fcdf9ac2372b6d60dfb3b19e3ec192e00b19bc805cf085e696c29f9461370e6fe12a34a440be2b2ce4cc5ff951f8a61552a489398fd52e88c10bc69f806945d1842029f7a61e0b7e3183f25fec0336146e9094b4ed06a7aa0d50782173cc0e11320ec9d34f386bc95187b4293478d2137e58ca8d3ca22283838213c480046adb09365d739d64989cf0cfbdccbe3504ec26bc13c930f3bd59c6999a70727cc68c19e3c32f2df8e2652083f10212a860fc1704371394aca7918a86c18417c2afe6bc39cdc9e65cc28b359137c50ca5fe2a96f0cd3c5786c9a06e9253093f4ccc23ff9ea4845f3ebf769161842927e148a7142cd362347f2509c73324874fc9f3197d24fcf7536bbb7021e18a7a5b45fa9f53cf23bc1497c9f2478e702d63b6b0d5d40d1c8df07270f70d973384a8c9081fcd5a4a90d011a12d8bf05ac66f8364aa08ef32e3d0a9368970423cb628218dca7f10e14f4d5bf21865c241c6211c4bb2197a46de105ea9b66cda14b5885d21bcf5a03d298609e1784a475af39d41f833d15182552d08ff62a3adbb6903e1f8386cd1d4f4b9220684232ac9b1fcd857cafa0f894cf77ef03f4850b954f954b1f6c151c9971635271f1cf5cf1c43d4e41ebc14c3c9a4eec96c51d383133dd59a65b5960cc53c78796a835b8ec143882a1ebcf990c5b2b2e243bb8367dde173e7901d5a991d7cbce2338dfcf346eaeae05874091d3cff9442ee7e6dc7aecdc1bb68b3a5f931e4e0a564a22173acff60571c7c1492a61c63f8f4535938786ac143a6b52af99c37f833133ecadb9fa9e7b8c18d5cd7e0dc34ac41dae0ada5aaca6a9b3684880d5e54b3fca1ae6294acc1ff5c6e7196b305b94c0d4ed218b59861747f3b0d6e87b98cac298306bfa6c33a7b4db0349ec14b91be1e4ce8d60cde68fa24ee3065f545b765582b8a7bbabace6c60206083372d40c117a3052850800c58d0001cdca006485832b8112606f90ec11bc38a418b61cc643c6c50c906360c4eeecfea073369ee6f30f81e7286eb589b5d1e7684fd82d560bde08c7a8890be55179c34762a5e165a2ef80d335a4677bf2a55f218760b4edc6b5c5a4b71b9cc09b674001a70800b4c9080131417bcc0bf051660810bbe680006084000bd0a8080040158c26ac16fd0b0b562f26818fc012ce0109b05cf5289d6f5e7349db662c18b78943699bb2b40c190c133e0bf0175d82b78da1923ad183953ac15bccd696203c970010738b155f0b32fd671e7cc171a0358c00230124b0527db81a5162d4dd08244ec141cbf071163225a54b14c0f2b05377b7a370d2af3198ac5878d821b551ac5a19a464b2928f81bb4e543e76c186388ea0efb043f95b8c5c49ea855e129d609cea79a982979ca4e6c137cd190da63aae076d72d6299e0ab660bdb61dde53b2583188c09ec127c9f98b29da69a11ab042f53e5b81abb069e7192e03dcaca525b23c19918a2d895a763709923b88dab6108991ddbc3085ebeb4ac718ea6d22745704e32df24073311ba8ce21d43f02ea5e020ec2a32305108dec420275f194b2c4f101c7f640d33c3dc294db58b05828fc424a4cf6e318728d81f78934cfefed53bc1d6fac0490f36a5139595caf109d615da0b672dd465e4b06942fcb8505e78af912a6ac63c2d7417cba41821d9cf545df819c4321ec61c124ea583e662bfe4e939a3ce98fd93c10c5869608ad025e5b8cc241359bb6581dec2394b375e3321a38b0e5b38a19549a543f95d4e65e005830524d85af819030723a6854069e155aa10f375eb889967e1bf9ba64669c89cdd809040065fb820060b0295859f4c267c86f138c17e418217fcab8004672ad058781b192e2236eeb631b0f07b32c5e3e0d8afe37136027d855be929858ccde30ab71e3bcc41bc6f85afc9cb65c426871433ac70430ccdf090bb188f55f8ffa9227f259b51165578f7ee8e31ccf8c427a9f042e8cfb0b0b8e96aa0c2ada90c52a2a54fe145d330c92a368593432b58ec724be168d87649e17f4c7f9c1a4ae6ec76149e8d65cf4bb7d8ca2a0a673397b84c87cbf26a289cb3dc39c25bf8dfa8a0f0453355061fea279c3495535bb265cb1c4f78511baae7106dcfd0ec84f325fe9e1b573fba70c2cb6ef5affede26dcd290982743a70927f643c7573949c660cb849341aa08963ce63ce1c2841b9742394e9d4b38b32e651316a925dc0619a718bf8bd93868ae95f0d2264bc5462bd6b6f24129e1265b9fa4152265ec9d9e842fda49ccdca1c30ce29284675d26a59e34d2a7250d1a093fbd1f07f3903b66ef760c0a097f2aa5479651ec118ec34a4bbfabe09223161c39c279edfb724b13b43ea7116e6d6bb4c79f3b37d630c2edd77490126691d3b208675385484fe9bcd22c8a70a52cdd573a23115e56a7d50e0f5545634438d519458aeeec219c07e19a7932caf86c13420de177c80c07392675f557082f2afc6ab86984f051862e1e3e3a0c91d520bcefcde358a4fa1e8304e16948139e2a1b26bf27105e568f901d6600e1468cb24f7e3985dbfe0f5e8887bee94d23bbec071f5408b908e9434cb60f5e4773f9103eb87953c5ce5fb3073f3a4c0e600104204091a054a17a70365b47f3280b31843b0fcee4889dc3a39bddc3281e5c9bf5e86f5adfc1ebbeb56df49ae1e5b583efa81e848fc3749d5307bfebd743c80c33a52a1d7cf039f8c534ff0956cec1b11799b28a3969cecbc1f9346d52b1222233c6c17f18993394b47c9e378583e7d1f7d2198c58cc287d0331b2bcb793eb06229644f6cedbb6911b9c7f6684ae92433aab6c70c372e6f033a90fba06d7c4b378f0183da81abcf1142a40681abc9c1bfd68feb19c26a26870fbfc62dd7d0420809ec1094f5a0dcdb1755033f87d113c5ca7e5a065f06366c76555f1e29d4c342819bcb7f03bb7b7f590ea0632d031f8314fcda518919184eb102a06277bb32d9c879cdef209b6d006a001070ce002e30bff62d440062d40810bb2340cae865023d7c842442818bc4dd529432aafafef82d3021458ed41bfe06568e1410c96b11dac136cb940062490c1c7400631e833ea052f3bb55f1dc378f5f50dda05473e63a4d277da91473728171c5f73104524c7863eae41b7e0a72c4d23924a6e6519c4c00517482df8969d1ef9852899396d2706cd82eff197a3db5c757834161cf1cc9b53e3c9f678c361d02b78252215eb1a5c84c85bc1690c2af5e4be54c1cd20d66d2c9f938c6a2af8e0256d632f0963f99d825f6229b52e7aab67530a5e650eef2ff1176f6314fca025f9257d4bb3040a4e46121da6b43ec10d16a646fb5cb227cd097edd5df40ca4ce2ae434c15f8d4c66d7284c701caf668859962578762984f86910330e132578ee9ab339fe8e922c2309cea76b2437418267aa591e47cab619ea113cad49a6dd993282271b2be4f88c2278216d1ba6168bd020028312c1bff8d0672953c21c6698abd20b3a04cf325eb5c6216c8105fe051618c0021470061582eaeb579331ca4eb075835701096e40484026832f3e062d40356810ec8ff93f3de42cf95620f8a142453568f0d92e2de80f1ccf31fb038796c35414a03e704de32ee3cd91e9d3ee857f8ecbeed185178eb5a4986cb298bbe0532cc58c65ac0b2f324619639c71850e3717c6bbbd4c99bba9a68fe20412178eb94fcc75a9691b856ee17f08590ec237e8f4c4e08b97410b2090b6f06175e4a496f3b5f0caa38f048d6971dad2c2ef8ec8da369741276f169ead4cd67e90a13cb232e0849485dbf3a0a1240f21bc5b4ae12163e1e491096911aa324a242cfc939c4348d50e041630000730e009f90ae79138cea6b2211cd2153ed47e14958346a4cab4c24b935103edad1c7119ac705423434dd963e11965158e54d8ccf113ae35e755e178f615759ce554783979a669fb07010820874485ff21a2f78791d0f2344fe145ba4ae7471f61214de1cb25cb17fccbffd5a42c858f6a82ca787bf99a0119fc173220a6852485f3e062509354113173cc841c8523fd1f52e70be92a4414cea34b31b45456cfd1134286c2c9ba881ad382da8be5020d0a2f39cc7479c462ada52df02db08006fa13ae6b9a3419315b45115d069ef07ec2c3fb854ab3aa7c0b36d0093f2d4ab6c98d32456539e1a645aeac49bd4295d49b30f23d8cf4d8644d388f67da53249f98ff41240613200001be78f3850b6883d099f0c543457a2715135e54659cf517ed66cabe849325cab33f2b7537b42db15597aadb6747c9e5c7b12476587827d8fac2050df8159021832f5c7001021080055fb8e020a18b90233b65f69c94f0cd66d4c17a27c711ea49781763b42c6722ff634ac2752cde3836763a127e0acf517c520e0a209169469d4736e347381fd2c7fba9e454ae3ac2edfae8fe7259231cadf9d35c1a41153423bc9cc1f6e5708dd232caa5a017e1a750bbec8fa13347ef02179015b422dc8c3ea58c695ba3e43ac1d6178f821383197c418218a0802b062b40810c669008ff529a8d1029c58e616b44902a2551d1bcd130dc8770da1ed87d76076d393ecf807fc10d3440833684ffa55922a667f43ee209b648700219a0a00624a8c1b740ab10aee5f2c813a983977f02198c0be00964305e803790816113a2cbeaa8bb2d4bb1ad748db64f294ca6d3bce50964302e4000029c400632200001ec053d08e743a61bf96594db6341389a610629889d47e840b8256f139534a4bf4903c2f791d4ff301e7f70ec32ae0931ca7cfadb0f4eae94d0ca4e761f9c343d9beb525d57a5f98099b9ca4446d6da7564c43e770f7ecd868d1939cc92ebe8c1b1efe9cb15ca26a48c3c789b793248455d0eb1361e7cd478a2590e973b38153edaa64eddb6832f31112634964a1b235d07279f65cf1945d6ba8daaa1e9e0457bf5cf5b1936fbdd73602dbb4cbe4cad356fcf35b69031c81c185a0e6e9e1a5bf5749f2778e2e0cc688e29a7e31b0e7e0a198f7bda8a6b34cb00022ee83778e71ee2603e6f837f000b5cf04503dce0953bca46e7bd520d7382adac18547d2183185cb7c17928a1c73a54fb952502cd06643e44a342a64d53eb35bc2d558c555446abd06b702b470669538ad4e08c55f8cba9b34e8357eabe9a62b34b82e241a3c1778952d79872d8469f3e835b0fb2c845c6b211d38136839f516a30f1df29e542ac037419fcf38c2a47830fd3b9800524a0010acc6ada06309b0c9c9659499686b8de1493064a8fc197cd413e494619645c693178951e65328bc6647776183c3b0f4d69424c8e301380005ffca1c1e0c3e86f194af7e66c321cfa0bfe798c31a5360c8fd1e4437bc1c9719b4522860c1da62174175ce9bf509b341d45c39a0b8e89c474aa6be8141a5bf02fc6d460a1b3ad053f2e6dc80dfa6e6db29d85bebd55d32d4ea4bea6c63e9ac490ebca63754d96ed7cd1ae265fc1f70696c27430dfd41b40b415bc34f2117f1e7615bc4992afeb6f3c2e639b0aae46ffd60cab26dd834cebd053f092250bd7a8f23a9a54069f8196821f7129fc2201d6868e821b4635460ab9464553d6d05070bbc26cb56b347325af9fe074189fedb4102d5ab973682778ee32f1133329a21fe38b71011b7413fc937e4992b5dc6682f7e26213dfd9226a3bc1165906b87a09be858f6a1a294709cedb0633cb7726219d2478921661a2ac6d6da691e06c1af11c36ac32b8fa084ec8ded3387ad808aef57fd61c35b37d0617c1d50e5759a29444f0bca53f926d0815f586e0a5477f3c12c25afa08c1ef764dbbac06a9371604cfc51b5d14bf09f75503c1cb5c1353bbd867ca1497a17fe04f0cf996f694551ba4cdd03ef0ce1a9ba4e49414824d06ee856f315bb29ddc5a280b0a5050cc99176e374ec9e3d15845f6ecc20729b4523ea5c8e0a2ba70f2c530da49836d8f24173e74b18c5170e0c295d3b2983ac99d6ff016ae7796cf6a058d5d9b2d7c0d9edf431eb9bcffb530653e4768e1e75eb74d99c2b36025e262cbb2a6332aba676d2da6f3ef64e1672c1e15dd92fc232f16ce65e03866e49ad3be8585971936b2d33ce56e617e859fb9619ba50769ec1e5738d7c025bf46a4ef07722b9cd83ffe1ad9d0ff1cacf0cdb4d32449b95578a1baab518c1c33fca60aaf53b2b5481f5306c77903a762f0c9b2e7caa89603a3c2bbabfc613c03e9143e96986206cd0e627fea052f18a6f05a2e3d3c94b7a8309a814be1bf439b4a313d76259f49e1468e97b0942454a3703525896e93c72a840fb2289c8c1af972d68c4371ca64cf79ae9f41e198d979494fda49dffc09cf3d976d7c8791b8c09e7022d6658fc8491a4a783be16cb97cc6b8c29cf067b68204eb18336c2b068537e185499a1caaa6dc51df6c604d3879a2564bbcd2c764a1800528980067c2cb281623524a5ee9a7c30363c2b5b210ef9a315508365fc28922d96eed1a51ceb534b025bcebad0a7d16c28aaf5c09b727c60e19d6730253c207b3295ddd864a9a734ae04978c122a4343331bad88325f1662cf9824d58e84747428d1e1ba5b5e4136b010a580089c4b7c363f173f0234aa952be317804ec88e733fc7f2c8f071ee64654de5d22ebb2eda91eee7da5629a433a66849faa1a23b9fcf92b3343e045b8b6e23835657a9cedb3225c999467aa7beb61aa7022fce49acbd187f81c838311e15a6730a129e30fe1c9c7dba784c5107e68bc25294838ac3c29841f3b330c0d3badcbdb84f01cc8794d37f84e9f0771c7a5f6b02cae201cf5de8acec1a7ac0f849f1a35aa464ba4081120dc4c2aff1fefa919cf7f70264da6a670cd311beb073f64ee18b16dec839b2b030dd3e893e6431f603e38528ec3cd843c6529630f4e477bb3930be92193b3f0f0ea9a4fbbd0fa8676d5ed99474209701efc8c3437bead1bc078f022675f74712800b4c07770ad4190feaf9eec1bb4839773f2f8872a19a48cd5c1f10793db436620293b58603a78a7397b76ba0c29f01cf8f1b0de2986871c3c15910acbd12045c6380ede5f7c6a7bf965108397810c120007cf3dc48450a932acaa33a0057e837fb153696e98a5410b2070636037f8d91da4680fdb16a0400261e036f81b3365309f53e34f90001738800d6e54a6be89f2c802afc14b179e634ad9b8330c13d0055683b76296f2a44bcafcc02f5cb000d354e034786915226362ff8219b8e00b077014180d4e63ecd9e4f30a053e83eb399c6c6b49f9d5ba053683ab1633ca5eb53952ccb5c004288841961606b80cdee5b48ece6bdee49118038b0093c1514bbf6116c2928683c7e0dca6863d59421383e313b3256365340fbd0187c1cb171b4832879a39a32f5ca034a80283c19190f933ec1ce92b2d7fc14bd9f92643c6602ff8f7f93eaa1f4489dd110377c12f4bf5217d50c911395cf09283cd309a5ccb5d7e0b4ee4f46bc1abd4e96a22a6742137b2e04486b9a35f9694ee0616dcec17c26914b9496b5cc1ffb0a5a5d9b7822b5f2187b10f31d17115dc185cbcd3d74a048da9e065d4e51aec29f816f15f41a37c8ca14ac1aff586a1ea68834fc951704336481952c38cb68fa1e0af87104b1ff0131c8979e31ed4c4e430eb04533a44546e5455accb3c84e99e076982e778726c5af850a6a11e9809fe49ba60556ae2a71a37f012fc96a9b4feb51a2bc1bb3f9ba8871191e5e73d7012bc4bffab7922cd362a7560247832339dda2d1fc17bc7b1b161d509b011fc1422a548991ce322b8594a265a0ae1d6dfbc021381aa6b9558d3c610dcf458f216c472566859085e649cc7189f0e82972ea949b444033bf18c5f41ef8081e0dd652e15cd97ea1de4074eb4981e457606fbc08deb8fef160d72312468236c2fdc14e4c43afac67cd6bcf01d54980cd1617d4f8541d85df819d604bb8fb9612c892e5409e70e26a63bc1d6e6c2c931fb52c8e359edc92f3c1717bec7949375564e154e2e6f5cb080372ea8405319606fe1a714826b7d6768616de166b11cb4b26abe183c0420c0f98206e70b1adc5e616be175c567f9f05241738716be75ae8918f3eb48e99d85ffd192f6a58478982f74bc200332408102d05a305e1003fc42062f900555570f3e3748afbae002b1703e539e28517360e1f57f78b97fbf4fceec2b5a9f3009796ab386d615fe78f0902c8302ab32197c0cb6157eca69a6474b1945cb7fe10224cb0a27d286501a528a5913a9cc6ef0850c5af039820d8dc4a884b084025924140804e280388a61b0e8f800a31308001038280d4542a168341145550f148003522020422c2a1c262618101a18128d44a17030180a85c1e04018140a8702a1a089b0c431570725dfd8a894a05b8acd0826b4f06fefb46bf4071403f0bbcb34e8309ba499b5787c0ceeb8086e43b1c12a4848be5fcd8011ca94345e40e68f1be4f5c8a7b71b7c572d262daf3b536139d27fd6edd19ac45b5bb00c8870f163671b76cb6b8c41fca09b49be1dc9d6a6bc0bedc1e0ef38b4819c0b507a7f9523936b3bf164b536f62105dcdc9dc438b5c9fae2c4e40a7053c4de4b5b3e197fb05389446aed2ad1c52923085a26c7372e053fa25c79b7bc6f28536c9b0acce84686099290bfb740a252448e34d3122bb778f40758b4ba9d490b52c462dd8167438c858074aff6e0a27cab773c1ecdfad3c057d999ec65e247893254d14b9ca48bcbb036373fb1f183d4f8e103fb9f09cde0a75235430df23ae3f757353bd38e7c2072466e39fa9b6fcfea9b4c9dbdf4b9258e786ff770b2c6f32edaed785fb4f46a9f93a919d3fbf05cf899fd87a3893dc9cbd343bb51c2da64829d379d6082d5ce31dc83c709fd545d80d9f08da41289652ff07b91924e440366d2795927a4800b2260c20080aaab2a7f2f4f93d844e180d54333911c4be3bec10c5b33329b7d8058a1f9dc97ba30a189a5d9ad80039b77c00ef50bcaa881cdf4ea1681a5103f1d50f31c0b91dc3126209b20f7296e846edc3e4dfad56491a096049d595ae41e9a6313524d385867f64f87a42f2e6cb6bcf0b511c31746faeca26d39b90a201afe48bd1294a123ad46e0271f34c37e82ed9ff2a2a9b1692473ba5d16772319ec102d6385583cbca578d62dc6a5ce7a65be29be8161eddcde56468ccae2cf82da33712cb09973a2c234f15392d408fe383e7eb0e09ae48c9c5a043134f9e54353e534721766734767d796037cb5dee1cface38d8fd7cdb891c0f955ccc625b75f6e49230a7358fab3f744bf7db0f464e8a1dddf1876de0aacff5447ea373b6f0d32321f6c6f4d4160bc7ff30ef39494fd498922cf358cb413aa35f995c3463bbd500e39c4fdb2a41eada8076eff05590da7bd0f42d1dfc2dce68eade6cb14bb26feb7f8fb92ef22f9b7d0ea8b427960e2860b628ac9f3ec30053d968901b9bf9edc80a8ce5df9fa27a98b1113e630f73ef5443476f2324f851aa75b0e9f856ae2cdc93e013439c4b7d32a5a1c9b94047170c7557e83311dfe39465708c586a8345e428171c125beac92d55475e15c1125ed3ae0b4218630427e560f114dd387980424f29371fbd9cb609456f002348e3c58f3a010f80b7a6cf0275d785b5609ae8a5746b9ffab41205cb607c8cf0c92591ea66d484c068dd1cbf31329dfd4bb254d2bc827685dc97b8833eda34de0686ded6adea96ff821df2a9125a44bb9e65786d1e609beec8563deb97fe2f3e5100a02ef38d6491078ff743b31519f0c312ba5f5d23a0d9b308186d38b517d098a0786bf38066e6241cda78d2a977f61b3fbffe2e5f0ae9afa4799497c8cc143c4a75c41aac7636da418f9f14e027f8b704a0272de9680f02b4c7ad257f022662e71ac75693519adb424a689c7945d1559dcd9778ed3bb8a3eb257436014298d959fc58c94783435b4b759359cc0d4ae6f39675d14ab6d9e076ea5493c76efda5a811696b0c70812e5dc1136d156f12716e41e630025ab64d9b96bf98ee3fd5dc6e332dc1e5417e2d0420b4e0fa23d8cd04973d18c6682256e46b7d85c2fd72a2411aa1e45f6d91dba5fb2246f3b94892cea2320d9bc5281086b0a120e82c8a091cb348e8e2ea4277f7abdbc693272f65c139c197c960e56683979158596584074b821e44d45fed8588db855dc17859dfdc22e2b74ec211cb36f7061bb6b09f5a359901ed52ff623451f709c6cad3cce12951f20e2e4e9053e54232858bceada6b782bd05315714f558c3d2f542d33df80b9db30d0b5f34fcfee7914946eb6a6a1cac56931de682be808d2dd9a127324f7af4568027fa9c97004d133c72ebf6923a364018d75320b48cc3f2dd84b8ef7e8f9ae5efcd746583abd2e5a93d2b31a79308b0a1405735eae4529ffc9af8eba1e91b1f8a7bf6bd1fc2e1aaf956c7867fe9fd6c529867ee4e6ebc5701a3e3fa221b10735a406e4cd07160d431d874b4d0cb0a91d2f9f1c3f0f1add6a45d4f26839c050994f0a2f85efe6412318fd26bed8e7040aadbf0d7308ad96b634c4922b39f6370b6fe013183e6a0d8b622c58efd6297482accbc6c0e6975d3228b6db3cfc38729cd1598e36e8744fd3a40b286ef566bedddc2875212bb97c3018bfdb79d58a66e66d149c4e681220d77366e9c5e7d91e579944b43f26d6bc2b09bb687e663295115438602eb73c8044e5b283e4ac2ff9a91ad640ac0d1401cf9057dc9623bf5e3c4d0b9339e953307db2f5b7246dc2194cb88bc4eac9b8917ec5f63b56df0095e458b9481ad300068dc7960e1ba05a0e2297d594679f7ad9876993fe3f849e32e07e86fb4e99fda6be9bb86c238f47ad1b46f97d7e13aea9b05c443d963d6ede1ef216e0b6cb71ff7cf081072ce7991a5ece4fed3e6392c41d20759fb192644804134748a25709999da173ca4467cd19f44f739ebdd643094fe117b16f8d900275c73000dfbe3967eb819d66b9a8a8209bef9821459422a1318c124dcd844c1c46e8b97496fc9a3a0a1d7803d1b05aae07d1b401216f1126769c028f2d3fcb8ea7122918e509ca8c1b9e813c4ef687a4c40edbb8ec23a59c71ee8cfcb8441f9a5ba6bb91e29484073a0640c5d119e1568306e840e7695356375ae6a478469a589d7791310577e32fd5a193aaa282529de025135140aab93e674fe1da7442bbf3244a7718e587451598c74567e14700e65bb4682ff314f9c8f8e3882342e1b7d0e9469abe006791ee3684666bdb281cddc52303c1d85beacdde13af5a926d2657275e92bb47e05d05ad53736fe9fb03333bc791b559d071e932e0082fd7fc4bda2b936712042efc3b255cc3402ba656c2058401a20f462f009fbd5b8495986d436da541638f38f367e11a38dfc34a0103fcfc3e79eb0e1d01873f2ec13e7f2e35813c92154b6918cb253334e9394531742aaf9ca304213e0513a66c3dcdfed80b4f4b1ad0a3acf8b7030839003818ba9f9f1e582d503ac72dac4a7c07db3dfe4ce4190922a7bd1f0937b387b6d712bc8b1fc7644b55e822bb84a1190cc4cff1e8dbad8fd1f3d32d7504ad298d05014fcba5b0952783e9847d44b99a2205f7a3bcdeda6f48117e885bfeb164ccdbe25292f700dbd4c1ae89121495ba21931bc16b9293712999be8c279ed24eefc24da38fe43ce79204e6dec823b6c234fd1ae96648890778cb0a9f4e503abf09bc0535d9b06be490bbe5327f5fcbf85f9a18cb2c7bc38b535f136bca3fb675d1046c972a6c01ed9b67f8b8167c1341ce8b97bd27e075bc9107e6b02fdebd390d8c9d25a58a548bb552a0d004026892f061135b7058078290f29761e27697cba9d74259c86f5749d5026d22f70b2aca8d5788c698d8d8411de55e68d7f8d0ed545afd6511629c5a740f7ee568f0457a218539c5426039a7702dee9002ca64a7f6c70d7ad43b3104338322201274828391375a6b20187355570b6ba4fc7d44048d824444fba87b51478a1c3bfe5c9a816479e7918ae91cd27a6db11673f2df01c3961d6cd7c7a1c9c15d166409e7ecb671d8961a0c83cb595b82fd57b84ba1d6d4d260e4848ca413ac67af54cf01ab5bb75f5972019d4723b743397da61950ec447736a59569b41a14652a0ff5b87c35a98f18b49ee911f21cc24e6d346fca2fe4a13832400e8769eb961d18561c7a825e33b9dd1a8873c5af6a92dd13f31252739802e6e4667edb4cd8b81597255704a6d2dddccc64d0d737e718907cf3c5d60e8219df6b94dd547ac8d14be7228ef2f4c4caa66cd6bfa319f378c8ec245817a6caa4ed350293fc0386f0098cb1a09e3128b53de0d95d5028d023b33d38a9ceecb8ae0526e4cdd49a847ee9d1fc37eda02a60144e1ca0b79b7886d6a5d860241b6946fb648e5d1ba9ffbb06f35039a197376d15cb0032b3ff3d5f05b2dac6001051ff120e563b0f184a0e10aa19f41153df418536eb8e4cf0c5bf0f2aae8b46e832d31e6cf110133730ad5707d9ba855b979a6223cf5cdc9748afac3305928870159e3d7698a608144f1460c47b9eb74f32a47450160a020789be4b4dd0fd882704f21561d63c5df34e940312a37d8bc2710efc04794290ada8dacb9747780f0fcbcc00cb2a400084e1177164706c673ed1fc4b2dd8e08f370ae6c24ce6517da9fa5ee043986506ad8a4a36a66d61bd8d93bc99e53b5bb032451582a907b0a99818d20270713ba17240043478fa434844bcc99502824b87d5c093c9195685213698e868e22fdc01f2c371a95f419685cf3238a3d81dc7d9f91204b137e97fa97e27b336858f861a16c010bc867bc2f50dae7a157043a2b5f501904470261d28024e4e40d1f434fd624cceabc457b3aefac45d85cfabc57aecd5f5e3941c5503a742abb19fccc6e4f74b6cb6c4abfa41751bcca3c6281c371086dc8180a0264befebc25d8d000d104bad14bc36d784750fd03eafcd0279f56514b14dbe6d3bf573f6acd866553f4643520e249e0feea3c47ef088f230dee7403a596fd32b2135601a4995f268df40ae6d51442b62cd794da251a15ca8efcb9f35a096dd438756fe6fe845aaace485d2d8e009a28ef023e14ace7e09bdd3881074125289832f63a7a4407da4c2c6aa53a207037fa5148571a07c7f21689d21a38f508d919c9acba9b2300c51db8c0285432d77d155bbb2afebb7b2ee7263b381d9b67173720ecfa5a808d5623a6d5ecfc766c11865f1547acfc85e87e56059d65a4857a8f9c269de37ad06204a9b507550562581bc2ddf3e9ccbb3674303b92c4bc15cc5e601c1fe83624045fc9bc066752e2bdc6b175509e2cd8567dc419284f62f03f46ae1b0c2d02276fe28a37f4f6b116b5a7c64997063df52d3dc46d2081f09f74b1d5d40ad014e30b3d22590bb47488cca815377f5edfa296b5e3c3c92f6293e206bfaf5ad7c56488a04c1b057662c98186f631e289567d904bb2d508bac0d7a1e9aed43beee201a43dec9130d9c6aa2f4807c1ba7f1e68d85c82d6fc096402b7432e4e47ce7e5927abcce79be0d6a527b5944c568adcba0cde32c2db225a91d58c49f3b803f6b92a4078cc0821040a8c7d17957ef026398d97ce71688f168f601aaedb79fbc36306227c69d73651370c158e1d13cb64104ff7c9dcec9ea73ecdcca26346d82d70fcc44cd4e20c0da68a9b0931782be29ea391f4ceb19e29ba065b1dda8f00b78baf1e071d18941ec3b54c777229732c0a3e4a062cc9cde6d713c46d8a487383460074a2f95d43e9b3181b8e756645393ef464b12274e20718a14ecc47d6b5d785d1cdfee90ca9d44711ab06850244683ba8034a8ad1c5111f437541882ea2313646614687c9460aede690614b96c748da692bd21660f0b63691bb7b65eb8f355b2d92f4cc739e536744cae28e3d3146c5639fb242afe28af70ef664c22c472d7af7d1cc241330470aeba8214e7326e8a6c9df3832a10fed90d9567b364a4f744408542f431db45782155ae2b5ba897aac94a0e22940b72107ccb26b826b57f59d5f04319b9cf8f3d42a99bb565af8f49c532e8a16c58c388bb0f0d44b1725c12f3f6ac3a9a42157db72dc308d847892335dd913d48ecc2d1ce3603e7fade8c7632298c6a71c3d1aee483c82bb91c6da6a3fd1b0b0f07a218e16ec495d188464a0fa37134bc1efbf18e3e421aeaa3e82369b74b9b225ff4462bf0ce709bbb8c986694dd1ced204d1084ee483b56e3a8fba5e83fbb4fa8e23454c4450538a4948870e8f95391da679cd649c93076da9325b69a0eb3b13e952991f2c5dc68d5900b655b4e22cf402d5b6f220a1eebdb4e37632c2b3ef77b95aaf4ef660ba236d1431fe597aa7b00dafc4edfac76bb3c95fe80ce8ed707fad5927d42a25c2998d0804969487c90234b0184b96889c332740279c5eeb467e568624b99be4c2d2d3b56fa5ec6a633450127a2b82c5516de01ed37ea9a53053a553082678753f400864777efdd3c1233cc7c2c129faed1684802b91ab9d96c5c398e94e0245929f3d0fb7d1d0e045eb6084a5a2aa8960aaba65df98bf5b572632cd836b4fce506b6fc7a5d2cffe640404c1312b4077c81c4885da955dc2fcc0ed0af655613e2d9bf6af1b721c44e9a7a753634d988847a8f2dd53bf6ae35e15380155d22db8e57068f6770f750ef6cd01cbf166923b3e46b436172109695d23492e43907004955c2ddb91c1143f82f80a7bb91fe13c4df44f06199e01876a8b01fd564b9eb0722bd4cc1eb65802627241d03079bb1b281a5db81dca780993d0bc9e256743fbc830fb34191717e2b3edd2ec61ff1e8eed902261262d4db67c5d04461873288d1121897546cc2ae2c3bdbe8feadb3f2287480e08911f8b86dcc7bf28bc0387148f94436a47a173b1b410b6e6616a083b061d42c7eaf3e12ca4bb464cceed2528a17d433646c89e158933ad01dadbc2321a471e316e34e671e183e48368e6f894e2a62ec8ba5084f0bd9baeda5c05cc9a9ff9a9e37a8b6ce3a68ff7a74027d344036e9e350b4398b72232de379c33b459784d19e762cce7c89ddacffda67a508fcf71e599e2905e528becd86e17a9b0b122ca4b650656644a98c53b4688258cb27ced9fd133f6eabea54ec96c6d01867984e54b02fcaaad62a3f1e44538ad5e5e7c768c0cc8f93071b2f5198d730a60053d17438b26e6113f2c2d31e8be54e494426cc2775b0d9ad728877533a1dc25e86c55419a3623a64c08ba5deb8cb5cc668beafc5cde5704dfe9b648a39e8560fbf1b2966e1d7c6f535a92a7035d1088a0318b5d8cdc058f653c3f3163a5dcf43939651fbdb333fc8090d3e51bffd15b7567c274d31a777cfe67628fb5504d0262a092074e2181511846d6b55d8741c1188a2240f661155fffa99f28bfd1da14e457adba8de37a2baffcf0a3b157ff234c0072b72de09aa12912fc247841891d58988d608cb2b49ad6d6e4baaa59c0fe2c97ad28bbe415c844752501ab253f45ea4febccf8370bb084a2249c7c81397ae182a8b7c3b4552660cb9ac26222911902b993e24a9b53eb610aa1344305b0c8783631df7883fd1f76942b844a2cb25de4beb6e2e23b84f657d998b59acbe488ee998e27ce1cc9334716f1c90331cead8a0fdc729734353ad7fe7e824f0a92f7f853b774fefe1657b31a855aa22ac07706a797229e250203df4b12415fabb250b6246db6c3bd54bc3933bd166a1b77a6b9e29edcf54507cd326d8fd503e2e8461dc62946b139bf62c23bb53af7fb1d1e9506df64519aa6431b2e30bf9512be8b4a58823e9e41af13eeccb51edd0501e06fe9f5817a0732ea9b7dece49c388ededaaeef6fbe5db716c6a86ba60021a8f4c6655ae35866ffaf820f849ee5f10679ebdbfd5561498fbcc585f3212f309cbbad063c2f48573b9cc83032832402e5e1475695ae60a060b9e8d74dd9c5b0807804492799efdf8bd662f2f0826c51134c942988892764c3e5c241126a4180078b5d844da995b7a6b3cbcee505a2fde17e007c76e8f25107265c4de665c1da7b9d9e04a058afc78ca9ff14952eed2d2d6f375487d4ceb8227814ff234d05df9fdca4bea62b0d190112563de7434732dc0cd94178f197fc4215061e6384f104d7170c599a337f772d5a0bd88b44cd071a3e5ddf8af7c4c60bad44a10475a2aad1552539f96b079e2cbbb94bbf6417a3eb222f196f420d47588684a93d913034200468b4c853d8366a83288906b17b52163874069747c84b31c4170c4012f50f73c8156bf3c278a8c272c0489d42b17d1f2f76335eb43bdc19d4e4c0074bd8f1b49e3000354826f0d65511f395ce8027d93fe64f0f3f2fdf3afb16b1e125c8ed221b62c9308c8a50c5fe9444746182c0a8bc4bd19c1de2532531afa34760395788f65a827eefb2e67ba088f0e494e11375b79ccad06f97658e6f91641d91a8c2eb8be5b0df4ca22647f470dd76fddf8982871fd636c5c7daa838294ca2b198908e9843880306fd28bed6f1690a8e91b732153103010b9102e91c9105d104610fd90388a8091909feb5e55540b808001812bd9bd42c4109e9d27f9f638b15f6894a0d3c070c52e4263021d0def1d8d7ef26185c72f61880cef22684d945e78230b51e4eca0562410c409b51e4a24b298f0066ee01bc4fd9073e2bd4b586f18437c1c84dc65b9f20d42149196e9dc5a6043c85b6854484e859e994b32d6380ae2885a851219550fa2533089c81d2fe03514b45d1efe4e6a3153510ba0db55f5d8a7615662cf3f0b33a4b57fa3d490c3d0be2dd6bbe0a5462cfdb4d51e6573961c0000849cf4a63a03eb184430d8794305b14bd64be2e2a3c4cdb7546aaaa16b6a22cc6a6e1b70b1091d6bd6b1006c6980d9ade93d65b4105ae44c95bd17cff87a9696693c3b141eb27d0c828ec86183fe41054520e3151bd8eadba11f40e005e5862f64199610d7264b5be29c6d12c736aa9e85c4ace3e5f082881c9794b1264634f525e5602ab5e7a492671e6d9b8ed9143c9ecac72b2a892b81c46f27788a8f50caef547ddea6fc712fb25003291ea31a4d39e948b1503ba82262100528e51704e7996b6054de0666d264698d4195d1687032ff4a83d08c1603b205cde63ddfc9dc947f20173c2abd5200fe79a8e57f73d6284fc8e1e331a699e3d37f7dd8f1d231c09d075d497f0ce70021667d87487d30d51460b64455e6a34894d4c9a92d8272fd423d9d9aef5037cf7edffbbe9d42bfda77afc3f83e1558ce50e699b4a3ff69a855ce1700c05c47c188067bbe24c898a1375ec320f39cc0d1a720c1becb9b25186bc97b7458f1abcd52fa8e0b8f01568df7a0c14239c20bd58d7111e060054c6c9df25722c9c1605be8f4524c6569c321604c028a40ccc9f2379260d6324fc33e7c9a062e2a3ba5cd7a62df0523242871c6b0fe0708d085e5738d3206a0acd2b0026097f9474423575cab5acd5373d4aef08b57f24fbc357d6dd53f6ef864f26bf127b0f2be1410a8e60678fb22d04006d27d904638cd72d07a92f8eb15cbd9dc445ac0a726a1e6670b30314339b6d0733247d807d1920c0449e78e4788a22e1d0f89a0a3c563e8e35cdf64407b2a9d86fc2f292423e5bb09898ba0bb46df4f8cced86f5b24ae58fbf875121ece5219d85c0d5ee65714e2bcb5602458d0d84631fb97502dc5ff709d38b5aa2f79af7475e097208b455cb4e8e073be1cbbd8601a2f926cc2ec72e0ea2f33e7ef75d19a3bc52452985db4454ea603aa0d54d192175f20645d93e78032dd87b0ec83d648ca560f1d42586489e83b02dd2057638a8c018b558b937d4c4d0b0a3e28120f58e1daba65673d6480c25f373f774e4bbf4e6a56ca087b5326ef2af02d14b5f8a073105b058c781cec450614cf071d6586297736f4815b0e8a03f7cad9397049ec3b68c110ef47f0825ddfc9fede954ff8d5bdceba33b569135e0ebe8d81211537102daaf1b9485d08297927a8b4e62c30a9606ef5a39e400154dde9f5fe5c83275fe4bbafb5209e7184a6acae12073ed621abe8025a824a1c29e4b66bae2d69554ee0bdd1aa97c15d2ce46614b32f923b44330c69b1beb5687031253d2abc90fb417163669c4bdc71998e205ee23bb1e21f85f520d443d1b44d7777414639241b871498b39463f46b40ff8c62ba2416735fd712a39316b3591f379eba7655ec210f45a72acad05bf355cee0abc55604b339eb6bd7446c3f5cfc22ac40b3e5eaf86b28130f311e250b7d306b4a1796e2fb7b0c61fdb82e939c97829e49a0b794c54d8669a682c7f115002256c74196a0e3a3ecb392a3662a8dba6b09ffff68d23165f8a3cb43d21ef8d5b95d6632be8c5df0e5c8b3c0c5c3cfe9991071442dc8ab34eb2a39183c571e732d49c41dd5475ddebdc62ebfd9dfbee38746cea27b9342080877ed1e0f3823925462dc2b87e26c8b73663cf523ae50cabc7aa89b44fdd5f7021ff1284075e92759452058dfe0519387bf04063553a6c68ac4f6074a276c661e5a64592ecab3f00a29e61e9debc1498c1e715c5cc84c1a41498c527b05c361c4a69121158df6dd911a3cf4d9ea889ee84e5ea481705bbe339b717500080d3db17344d0b144d4637ae60c0de36fbebf509ea4881e67fd93c9b0cfc7b5a727549dba72149026fe397b5d1d2d3afcff6eac4918d32489f07e309f2954fe8eda8032a9c1da5685c9aa576746f6552c03ca03d5a107e52b1db517793bc44562e195e25c63776eceb7d2f2bce912b4c63ce2084342c2e35148ebcb1c14f556f0f0388fc47ae1f9b41175b880cc72e9e694a2e53473601d128816ede60c9d4d9a8b8a8bb5a96dcd9bb3ddbcccf0d3eb8be3a7b953dd04a0946d35bc864ab42943760e99262d19b36e5affb766f0901dd865c06143160008aa85ce447685a0d4d7d8e6a3d97385b0255ab21ebce9bce4cb6ec35394290f8164a77c3c6d4decb7bd0e6b0277a42f329c544b4e531e16e3723bee82b80330aa0866a7d45d15bcd52c5f89b88274cded89a828ee5a454df0f4b325a385a492911262b2dc63645c474b6d11a9a2548c8a268956b4e264948a52112ab68c158b94921332e4188775d38aad72565c952a4b7740effa503b32d015b20d141611456c9f08f7f22efeb3801725a26a7d1ec6b31f7b23b186750abd06a43691a70d193f1f08a2f1de4f14ae902ab4a5d5a1532644446025035908b29e4d1d83d22198286146b3cbdf670e2b90132fee30fb0a5f299bf0d57af9f1c34833cea641b89b4a4925098b4cd3b6940b7445ec5fae42988f9a58cad6f84095f50a5191c2f01191852e6f37459a04c18ec349ec4497cb4043f720fcb6a3637e2343b249f9a626cba9429598afe5ca5040ce085a4fb469495bb228f0874d5436400d9e4222b116ceb7b180e06a849654758b7ad1c6c4285f3fe22a0be4d5cd6e0572f34391fb996fa1fcd91e986e27690b7bbc8a44839c72461c8cd5e6676baa9b6b995de66e7ca09f224b96b013e80f4ca35de71a97cc5b1b47faf607e1dff51b9884492f23575adc5b8783cb315975aa5c839d41b9311eb2570d8570dd9926cf387e7fd36055b39d63b7d5a690b564ef91d57e9b2feb647d5b307bd864580f6b0a99b0e3a696b43e272f30c87c23cfa08ce35a07996090930b2991ddb36e8c8ba2207351ce619035f37dc7580b88ee0e6a790a9f84fd0d65fb23a800ad6abf9be81111396a54862562238f9700ccf55b6d4f04fd10b05c566d2e070ee659ec914682d2dc3a0000b79ed1b37c58e7ac0b6ab658eb488417e35c250f5a3e98763285a7ad9284789026879fb38fec8739b38079aaf74ada2e602bcbb9efdcc4a8f676c26048b70b293ca34a63a9d15e07ba60c82e499f2282900dfe2a9aef5154d299e45a1fa818cf21529f82d559d3fcbd6716a2938e50958ce053fb87523f178667ea891b84f7d1f7b1584c827828883f245299bcdf2e3e81a6ba96dcf1850e1d0a819cefb68d65e2e624758c012aa1641f44e1a2fca3aab05a28647c93b8f756344b2d0aa0b11a4492751b51320871a07c1aa28588ce98eef944e210e3bf78c550a10d868e6946ac16dba580366bc2585b75a97cd85e53b0deea2f93695fcd9c5ebe28d694b41c71270d73f6344d6b43af2243b544f71cbfdd0b3dc29b61ffd45b509ac96ab9e29268f9a0821f0b73284183bc79173f2ded6cecc0ca79edeaa283bdade49895912bee329cc94bfa73bd65a84424e760cb9bd2f5b1f570abaf110a197c520146a66c18822324e4fe04b445131d4f473c089f49ea8dcd65192e9db97584556302f0805b360f86d1750c85541a83cc74bd8da45a215cc2f316ebcdd9207a3fd531d50356c251a86a2e2e7c53fb36b97f7d4254ec42076a1557991b95d638d01c078ba60c654458f6e6d96c20bf0cc91178c018e7e1de5bb1cb0ffc624056bc855d26538216daedc5582b328e0c485ff04cc97228b8bd6fb351a030b947bd0600cca5364386cb984abf197845ee8c14659ad5b870e79b6fa8914aec68ae4b205b15de4ac26544c46b41811dda3b6261b6a975e4bf6c95d5175ecc8cf6cc7f53440b3af2151b3863b523cb3561b74a7edf311b80a05da52576a981115f9f829d3ac6691dd8f2d5ec3ef1316c11e375c923863c0580547157b18ea2bfb3b1690d4b1af01a7039ef1382d47fca7a422c52a36906e025a5e0e457cfb2665d353792f5f981814cc348dfa77f2e2fab1da47688ec6f805cf99054f978835210f6f8c17ed32cc2295469c3e5787561722c32405aaf55421916032784962c3b5b0ef8f665f6237cadd8e6b7a277030069e81bb96faf7800b5f3054cd9a13b5690c20aa65ccdf4a09169711a2e1b847a91c91c2a8180db59a894f838b7b4accd862a5be076b655e9fce90918c00099e7ee58a4f8831e3d0417988e9d96d27ccd1e2eb641f4a5a7694151adb7571b1c68af54f4d6df425c0fa97ab537c28ecbc88192884116e3184ab5bf932655d1c33dd771012b1d5799061cf6ce6d7a5497424e14b5bbb72cb9178c6d6f932de03a936ad6dccff70c0d7c735374b841350f1d940b21d052a329ab8f0b198f49ae479afecc25ee1d7204619652657eb90c54aa554af552242a4cba859e063d752a722b6c8339ded156a920c72541fd61fbdc94b2ad19b8a06e34d9d4664017748cc6580e65b2864884b726d8a3e855a2ab8e57448c29f133a2030353b48102b36450d6b319c9a70151ff0cecf2190c908015bd8113ba5a3b6dbe1d6e83b835be598cad6e3b7d2a5205c6968a7628d95b22ef0513c6cbb289755e1931728e8ce1a157307370ae33e09d1f340acf9b4d0a125121fe56686c1825fd87964faf16e39641c9251ef5cf568d4112b59184a2cee08d579808795cf134b876d816464bb16264a5d0ded24a8ef960bc91a059575f94b8588960182f454dc1fa619474fccd0348ce659d748bebb9454bf57167fc2b48b908344d38f06fc72aaec8df82b205fc9d24eb5816a4b9990263367afb528e158a155dd7c18083e843555bb393722c642ac420e233f5f2a3ac5795a6dd9c7d74accb69e5dc26200c076d877eb9dd43cfa0664a1a8e15e22e14a544ba7ee16b062de90c0e485f1baa77e4803422ab3312b516f2af1c1438b516e006b1a76040c9258e24a45d3bca809eb0fb8fdaff0df156293f7662a1f5d13e3de8388825c290e0fea6101d025116e1a2464e52e94e57d05e26958520573c2d5ba4dd7b66aef1c3578c6de1795dd64bfae0d0a0b246f290ff6edaa2aa5e283007213ae08c03a31f18c72d080aad9a53326f73c13ad53552a851c2ae5fa11bd2be28e3193593c564b2a14854986b289fe16fe34a0c064e08e0c8cfb144858457a381c709f3065bce039db8ca6fd22409f445eb237484338c62c3a0b4a223d0630b21b7a0ac3e8f4dc106a10cc890a7e89c8350885ad4160b16359ad7e2ef099ef4aeb3e64e5582a78b2ddd1defe72e48bec7661a6cf0856b65dd0b69606271c5c6cb6d66ba6d14461b060b0240e150b29450625f44384c16784945e473a382b2ed47e19cb9710214556d280891d1723792229eb55b05bfcf2ab230953dcdc8146a345b724e65caa16d0bf536cb25da840ef3c12190456b261386701ce3fb49cc45d1e097c3905e78af94da0960333b1ef5db5b0d225d807e6208b6b967d86a9ba6f77e30b02f2c3b33c6a306567d6d1a4b0b9da92cfc464ac3fa4eaa036a3b46ff1404fdab21f679fc0eefd22e7114826a7753385b05bb6c88d8065ec6fbc75ec681bde38acf274d1491edef0d2e3f415bffe7e0456ffdc13693a7719fb42588db2327f280f8c55a3a3d0412784e5648e3120c3630cbc6821f208552be7267cad74c45663c90bc5a72bb24404791278247971b9c731d8642a2486f4e38932c4f72618c02755dca5748f6d44a3f85f60a939ee8412eefb632efaa92886e53ee900ca3a56beb6c1be4ed4415811e6fefdee423005f14e28cbc42208be8a56cb6148a4602827118628b479a9a8ea3b9860674c30d60268bb2051ffb0db0c1a8dcad2054c300d2ef1034b6b3a73e3da0ef127f15b7219950adc3c5acf7a346d9447d9d454248fe51e9e621b9e7c0c44cb246275347d46d9504c31409bc228cdce17fe29aba8e9e4b92cad612089b06a91b7f6ad3d9b261c3ef60cd94a7e5247e4dc077edf18e9b793b68ee9c2a31c24e4f82e3f5674128dfa567370f3a34f8960e1852345d31b04e4f8d2dca5859d1888d18f54ce0a96e77a947d519a065909d5af39f53cf73aa0edaaba690ac89ab5630431a7367ca15ddac15b105cfb3b0b618c7ca20a11f941be889e0cff2185fdc11745aeb5d6b5006cc5573022e4b04040b3340b2a4d001ffffffffffffffffff51dbdab7cdda07edcb94361913500c45c8fc84a494524a3225f3f43338ed03ff151cc287100f0b6c0acc0a9c0a4a3c39e520913005b1975fb3cc322c830308244c313eba69a8dccfcbbd8d1c3bf011e6d2be8138421fcd0a48234cfab48d560a35dd184118614a2d25afcf9a4a005984f13e95685ac642375411c62f335ddacabb94249f236127c26cfae652e724bd5423c2a04fe816f93d0f953c8449af6b9d7e3fbb3de11a6b6608534a2bb18e4218644f4a2928112a4ad6354298c5d664cb31ffaf837c076410863325433b5dc97111b7204ca7443b09baa31aa2a1c3c659208c1672f1b1b4691d95c510c306093c3c4000e163d8e0c118653000e40f56ba1b1bcb15d6b3933c32727455633900e207731284aefaa42ad907a37512bd7637ef1b678d354e3bca28e38339bb47dffe391b6d273a6cdcc03d184b963072edf43af4600ea192126d9ec44ea29e07a3794e425a78ec4dabf1600a131fe127b37b01c81dcc694cc3afa46d0763c979616445f4b8b97530cea6ea8de97e3c9581d0e1f5d0cf5eff49903998c457ebf23149fea58126079356a8fe53e154630d75e36054cf16173d0c07a35ace11933ebad2e31c9c24f91cbcc1a4ed4e9afcecd458d33c37984a94877e0eaa4c94688d353ea381ca6a9800a40da6dd33b59f4ef8874e52636dad05206c30de2533ff931a77f7ea5883a9d3785e4b52b2c6da0e1c38d46012f48b891e9583b6d4c100240d465136221696e754856a2c1a4c65626f27a14c0cb5748d353e83e12bb89aec5945c5e866387f6e85c9aabf0ca6f4222b2749b2a5bd548d35268341c7c9e1533e99a177a200640c46f99c1dcba348eb0a0840c46092aec3e4ae5ec6581b02903098ccf2e3cf9a60305a0e5afaa41925b8c67702902f986543081d4a3679269ada05205e30e55c363d25eee79dba60d2398710d54949275a88061607e142524992249f166da9b1564e06205b3028f5a1c4ae534dd18c86164ca2a75392f44ea22b00c98239f5ef4df2144ae49bd052008205f39f1484ec7ce92b1884c8b7bd93a3493a9605b142aa24bd566b6b8db5260148158c164fcf7df0b7a01d1c62141a89c60e1d386ad0d0c3c118367080031c622c0e1b34c83020549802881444001205d5dc2c2d2e68c650007982c9d69289fda4ecc491937143043ee0800e1d27051e1e1e06e2049026f0f5b2d9ea59ad7de5a9a49caca28e594098605e4b39f1e2b64936421c3bc610c1128c7a7225ed4949b224a5b59192083ef0811b3a0e0f3c3c9293d000a204c37aac279debc2824a27c1fc72929e58236d4f1222c1ec49b40e173a7d5ecf811cc160726996525610239837fdaddf336f56669022185bd3737dae83502d99004204833efd241ff43f0c934a5236b13bf51fc230c91384ba1065929069f90886797432cb59a205184693da2fe845f74e3afa8b362e59b8d3b2e02ea79569a1ba7b94245f18f76227e9e7a504f929bd30858a551a2127d5a8145e1867c3cf73ca92f373ca2e38ab28e375156bcb2aecc7dae5445329f87e125d18ce5cbbac44b53993fbc8854994d8a13d8f1017e6ee720f3a9c9494d0f716a69157d1644b96dd45b585d94abab575d0b072b7166619359324954db4307812d54faed678162635a22bc927e34b4dede1f139fc6561ca3ff34ea243dcfad5217cc4c268728553dfeb32081fb0309b55884a2594685d6b03c70bf4c6c72bccda26c68937d1043cf870c516541cd3a7726cbb15f9874e95e7da5167561c941c9ecda28af26e15cea5301d46ffe9b54d15a588dc76aa6859d20f13aa4a3015c60c5d7a266eaabfde072acc56264d54b8925318ae4aac1353a2867dca16e1c314c6396984ae13b73f4b45c34a61bc3b553a4d1e5142ac1c7c90c25c794fb783fc5f1ea9181fa3302555fb1dad2b4de5134e1d3a5833f0210a639e94662c66e95c521fa130e5258d9354feb9fd948707280c9773dcda3dd9270c4a56ca75675b269afe3e3c61129f8451fa5acadf549dc8be4beba2ddd55b7795c897ca27459c308cf5e7ec9b245ff8d884b9d242e627cdb64e0b1f9a3025b9b1193732f7b3c52b7c64c26079593d688a8962745cec122653b75dc1e4e5e1b13e48ff6c0983d8b8d87ae2bb9f302b615eb5bbd1159b1226a9aa537849529e24a727616e75b5539df4ee644f12a6941dff4818bb2fa5e52d25244cd9c3d37e28a5728aa347943b2b68597585d3d2b4a81764e57fc711e611f6e5a3a146cee4f8d10853126bf4e8f4764985cdc3e3ccf0c108d309b5fe12be63624517619e37bd22da411f8a30795a2a31cf4e5c35b59de1231126b95f9232199d0face00569f8408429e5131d174eb6868f43184fb549b765db5542e4831ce7868d317c18c27057b9c2082587fd8b3e0a618aa154ceadebc53f930f4258f284910fc2706f82295d268e891a0bc22073bad74559febf1a0853fa649ae35ea1acad0f4098dbca53e737753ae8fce30fa6bc999db42c49a2d33dc2871f8cefb97fa4c5ef9c242d7d30c99e7225a66fdf7eb4f9601c5da16e4d5dec942e34ecd159277cecc15ce174f578aa1ea99687c7871ecc63d9737e0927472ba93d3a280a1f7930bf86be7dfe3ff06034419b7caa2374b4943b9852ee6b2b436c4c6eed601c8d3dcf595475307c7bff9c7b9f5813a5834149275cb4b13ee6604e4f3988bfbfaa37793918de7c4e5bd5cda76012076399d63ad3351ccc2147bdf6760755a27c834996f586851edd5070b93677f98a9975bf261fbf3698f2c8508230b1e4935a7eb0c132abe8eded16cbd2ac429d7acfae269558ca640d66ab8fa5fd4ff3f02864e8b8fb50834938e94cc67deb81e6b317039581c3fb041f693098b55df4de133dd2f001a281056d061f6830e5ac8b122fa91a6b64dc484a0e14887156e0e1710693eecf9f36fdf81c33182c087595a44863f0510693e8e059e7549758aec8507e96d8db95c43268ecc08673c8c7184c4abac505955de2592f06f3996e379d4c4949e7160693872c97bf1c7dabf5533e3ec0603cf95b2c4be835d6c4d0dd31868d32706003ed063ebe600a71c13e65eedde7bb630c1b65e8206b7c78c1249a49f6c954384bd6415d3077a55ba7f315b3fcfd830b861be1a19b969ddffb8d2d9866ee533afd785549d00588850f2d983e3cfa96e0414f9827b3f09105549714dfee52fec082f92e5dcaa93ae90aa69c277d8e118b3df15bc1687eb7bed716c382f75105a3dce778b1fc2413d753c17c296a28e9659f82f9632de7b8ac5526280553278f6619da55b9e947148cefe597b2e9030a0661a27bf9b59609daf3f184d2725c4eb9d0b69469e1a255e4fa047d38c16cc92f9b0c11237ab90bb80b1f4d3089273549bf2583058d840f2698e4c7cae6e9120f0f2e7c2cc1a442c7b10fa13ca77760c369948123070d7fb6157c28c11c7663a276ba54eacf111a49f84882e1a4efcab5d55c3b291f48308befb6c83e29438bd0118cf717475edcc3dc9818c1685f274bdd4b95a0f647118cf932a69e2d2dc7b67c10c1a4e2e7fe938354bf5c0e1c63e0c046d9304c1fa2efe4b1b41b69aab196703c8d1c38cc84a1fd67939229cf493f9f033d3a18e612a57c7be354cef7e06bd0d81c0d0ce3c8a9dbbff53442b5af23c721a36df42f0c6a9d6566df22d4ff3472f04f46b131da1746d74f3749dcf54c9e400b40707e059fd81083051e1e7e3e878747752f4c42ab879ea8d331fbe585f9249d72a5b45cef42b78e51f1144b2e72e326cc83c996433c6c565d98459c4a5258c9615684395e478e9382b3f7cb052a68a9d3233e19376c7878e0b0d1b8308f5b98c7695b98472dcc9f44fdbe0c352d8c95837bbcb4df2c0cea54efe7bcb485919e79cbc21c6d6d776ca45d4e158dcfc1b951168b45c3e26653d52b5997c78c68dd176161d2aa9676667b8449a219f42b4c622669d3f8b25d61f636b9a52ae9db50e20e742bcc2ea2935f92ff4e6c6d5c192b6ad0aba0d1aa30aa9859ec5a4ad2ec9b8a15342a160f258ffa14868fab6c262f8ebc726f0409294cc193789cfb2496671426ffa815df3c278d4561d6be14cd721d0ab3fb86b79d30280cbb1a3aff423dff9f308927ce76cd5d67513d81d85a2a497ed90993de3925ca09396138a14a97286a3d266ec230b2dde52a78eda768c2a039dea25dc98451ad24b14d0e13d673983049aa593ada9524e95dc25426b9698dbf7852f7963025937b74c931ea93ec2b615c913fe9b2f69430c8adae97312df2a7491864c8d36162f9e82849c2a0f30925679c226178bd14aa5ae4ece99030d7fa96fe3919df9247184f4ac1d2091fd32bc81106f9a943fefd4698729fffa829ffa03a8c305f8559524927b5672fc22c5ba37a4de94f232bc27049c79d1225ca25d1449892ae1acf96378b1311668b25c5e7d31a26070f617c1344e81acd10c6f730f9de2ff7655808638ebbc54e3a69890a214c3bd77d927b83309b6da5c91ffaa73741983e97ba19f19e82c80261fc5075f29a00619273e4b4ced208d11fcceef5726fa28b6ecbfd60d4b1f39b37257d30eba9922f5be283d1a37a6a7153a1b1efc1e8b167f23d1f264df4601a157c5fc74fb414e5c1d8b19398167db9d2c18369b7cdfe04f16addb983492a41a9962d413ede7630c53425c6bfc9aeb7eb60f4360b1b3a9cc7ce743049522dd9e87251da9d83c9c7cb6d3cc8d0a59483f9a48f8d6725a54f308983f9acf42529e7ba9d96c0c11c274c586deb08cf923798e2a7b648ebd0ab2b7183c1deebb2b5dee4d1b7c178727f121edbe48fcf0663aa7e1215a4589a246b3087aed3ad38174bfca8c15cad5a925ca72e79380d2679276b0861a73b321a4c6a26c896f4d4ebd933189424992cefd3bbf79ac124fbe74a124fea11b70cc6b558a3d39d49926cc9605069733be874694c3a06f3c5d0255552c560d0be6a33b94bfea40c8329c931a98399b42523180c172ac7afcae215c62f184dd6091aeae20573a938f92e899f59972e18c74ddb9392e682b16333b7b65f2dbc2d98639bce754a8fc99e212d28aac4ea9c9414ca82e984f5dbdbf8981f1618f149ddae770593b0ed93b5d5f52b59c17ca32bada25f0593202ea782c173c4a86c9772673405a3b7578d2993b39f470ae6159513a7e72898edb2ea6e7b0eea562898a414ebe27a3b74e709463349f8befc49ca5e3ac1a0224dc44ce8dd49698269be644fcceb30c1d8fee59e4d6e0906b7b5dc2657824105f350b9a3fac95fd2a5c4f0d5d691601a1343958ff224fa2318d7a49ed27be249b311cc225a642d664eaf49110cdbf1b2441b2082a965946c987ccd7d8661521fd9fb310bc314ba9f82d06e300c4ae73be70e36304ceae941ed75fa17065d5ec29bec51eaaaf685f9353dbc4f3e31e1d40b83d09eef463d47fd122f4c6ede229f4abb30e7281152dfe35bea7561148f2de2d299bc26b9309c38a3623eef58d2716190bd94740e2a26e7b73089271f27f76c9e1c5b984289deab9494a0e3a4168538215a74f9af21dc74666152fad1439778eaffc3b2309d5c4a4f28d14ac99a6361924fede734f13dc4ccb0306988e89244db3d09f91506997982a50e3acc8bec0af32979abeea378740bb7c27432161bdbf1e23f668559949da07e4fedc98d5761f0d85f61b6b12a8c66b7fd9ed4793a8b5361124df94a173ac44ea830e9bc2174cebda6bf3f85b1f5d2b6ab73fce2a63049e17379bcfc452d2985c1d3925612457b3e8714c6fb24a2a662e8d8e951984afba6e9a896e26151984dcc6c8f8796953714e6fe93163f545098e38890a74ac5954c3f61bed15352b985d2997ac2e815a6541ae9a1f7ec8441ccd3d8e7ef2539e484313fa86b988af893b209b37934b972ce7dad451326fffc1e2dc9b75b2513c693544cea6e3161101df76e2cc66f6b7b09c307a157d55ae6165b4b18c5342b6e575b09f3c9f5cf494277f4244a1854d33c45578df2934998c4dd083f3d494c9648c224e79294147ff6a1a248986f54ba7612a9322248984d959a7ffce8234c79fdac93fd59298f3ac214462bed98db089387fe8ef4bf7bbd19614e79cab29f1026e9781126196276e76e4395561146cfe19d93a096a6dc44983b8efef4d34b49a528224c79566d4fdeae123d3d84c9a47029a7673a7f4a0d616c352fb162e1494f8530ec499f922949cc8612214cf395aa4e272955f34198444f5352b092bcca4410a65c975573e440989429d1d9c4c6e70a02c2e0167aa673f433cffdc1743aa7e7b8f7fbc1e871c2a81cfc3e984a9fbb5ea9124b9ff0c1a442cdf8c79cc9c1640fa624ede8fde59c28213d18b5f5b7848abfadf3609252bc8b9573923d45f1600c0b9e3394242a32bd83393fad4b8ea71d0cf65fbad4899bce631d4cdbf61566844807a3c9cba2ba2784bc0bcec16039d485aee594e5827230452d3d1197611c8c21d74a8558c93cc1c1fc995de1498963e26f30a7d2bcb653b7322637982fdc961c3daa93ba0da693a4a062e3b3c1e46aa944bdbe06838ea272c84f651f4ad4603a9d4a5a5c57bf1aa5c1d8b75e42754b3446683086297964bceae84f9fc178b37fb72787934cd80ce658419f779bf8f56d19ea959155eb26190c27ad6c2521945b07c760ce26492943e59294876230898bb65ddab5245bc260f0942264e32b603099fc9e27a712d47a2b5f306d8a92b564cd0be631938b5de2739a5d30accd78a5e8f9e552850ba6a463bb5ce5c773d2164cd17faf6543e54ebe161c13e24a84e85930b52561b904132c1855f57412f4be82f136f4dd7bb682c994fa24792cabdcb80aa6a444cdd968a960922cbdc8bdab1cf64ec1f8497cd3a14499c9492998e5ccd24f0a2f0ae69274d0974d2c39e8efa0600e2ab3e4ffbd53b47b8229ddcfe70473fa0d93562f4e1c53134c722fcd4305dd9d9298603ae531d7b4f6472d2dc164312a5f36c92cde578239098b9d3be59360d05195db4912fb794782b9e436314d253549cc8f60ae921e23984dbc8e2d2d39e92298e7bc926ebb35400493ea9c9b25499ea4131e865176fc5a6f45f8bec23096f814de540ed7ef06c3a4c4f8e5b91418e68ad721f6dae92afec21c4c5011ea74e60bf3dcecf75e28e969b35e982c9892e4cf1a2f0c9e6f2f469e1445671746713361d2e4b9a095e9c29c73f4b4123b77dc5c98c4f6cf5450aa9368c285c94ddd5daeb5e0b3dfc278325f9432496c618c193f497ea716a62bd9430b9394e409aa634791a69e85792d534f5c0c6d6acbc2246527e59eafc4da3a16c53d112ccc39bd63970ad1d22b4ce1db04ff5322d6e20a83da5daa133ae9cfb81526b5f5f46ce9c4cf9215e63013e7250517f9acc2242f594a19f27bb4aa30857f7193b62a76f052613aabbcaff7b658428579c37e4e2e3bf1ec2a9053985408a56a7e4a7c535ac282278098c218a3439b259d7545dfa530aa9d2a2528499614e6718bf96dc2c74f9c466198b9d8271e2d0771368828b074234ede791e2414a6a4e4aded3e0f3dcaf262a05305105018a4880ea7af832a9df11326292991dbc9e48bda314fac16aeabc28a5c0e75cbbdefa93eb21a6261274ccd6a4b163ddde66e2e5677e91fed9d6eba7b018413261f6d1eea79e46aa53b4036619204511993921c73d0a0b1e371900347ba62d79a306ca5f9e9106a8d35342e904c18363b64286d2befc191209830850f99eaa626d6a7cdbc8441c5533c71d23f081d8258c230d7da6d9bba086ee0c8f101b41d941c366890a103f700520953ce9ea07277892cb15f4a98c24dda9a947f12a6ca503a4b5e93244c579b8a7d2514020b93204eca5df112e49fd22b0c63bdd5bfa9224dc97185791cb6420db1b895bd9d0d6185495c45286d411cb20a83ab473b191796d524435491b9c6cba57bad6617920a539d94546fec8bece4a3c21cb236db834af191f914c62c8f7721a30b318529cb7df5ef8d4a61eee429a824550e290cdac43e6182ca25e5da46618ea5325ff254c4bc22428828cc55fa63ce4913cd2c2914a66a8fd62aaaed3bda164240616c0bf2629faaa421e413e9894e1846899e3dfe623d25c91a6b3bcecd08e1040ad98439e3c404e110030734c6b05163870d1e68e2ae59757b7b17adca2c8d4dcd3ecb67e7f3185f43471964ac65c2ec597bf7d9b36775b0c69a8d622308c184f9043361dab9e48841e3737076749b904b184c7f955c63828a250c9f3c334d3e75250caed9b762b3274b398450c224acba4af01c9a8439fdd7c97353265d724324611cf92d8f26a5b9c51123615ecf5d9ec4cab549d2658440c2145465bf99ca0e7bf2904798938e63331b2a58678707218e308ff2ba8f2587ce277a84904618bbfb3d09b28475fe890a218c305ac5dbef5e894b3a5b44882230118888cbd5f2e9d2f9935cc8215071abfaf7002c21c410e67183904298c711c2e899df265c86ec8ccc46c820aa3399f54a91ef0ba7b684755c0f4204611893ec6dd3f37277bd0b84f1c45fcbebda3b407c616408ad5fe5dd1f4ca14b647e30fea95c7292cdbceb83b1d594f49177f2f192dcf1c1e41eb5776486eef660caa7fb52bca44bed8e777a30a7b314f772d0eb336e481ecca34caca4c604dde9a329383c989358752525712785ddcaddc1d42b4a50972127cb566707f3497d174e9c0815c5bc3a18f64b5e5a9354e5e860eed49bf326c7b424e9949b83c1aa837c52bab46bfc0b918326a3dc455a546bace9b09197829038186fc4a934daa40f0ea6b5be509efd69f7a37b83f14db678d95343bc99e5dc602cedbc921e4625b3dc43da604ccfa962b28d3ced710d6183419bd986daf4c610b206531cbb52a1822a253ba506838c35e9fb96f71742d26092be737e34157fe6e25c08418349d05b4a49d79d2443c8194c395f3459ee67fd2d66216630552541ea7d09eb2db98494a18490c1383a429497df55563a86e291831031982b7b8a5715461d48418484c124c949faa0157f08184c29d5be6708f982a92cc712c43ada56aa663a42bc60fa5252647de56bacf9fb0d1c39129f0eb3414817ccf104ef4bd29987102e98e2bb987cb1be6209a58e2d98b6d479e92c3f440b9b453bef2c4bb26b921ea1521b92059314b6b3a9d8cae6af3970d448c6389fa3ac48108205932c1f53bdd2bbf5c3902b983dd977ccd236ee7d9f60063470106205b3575fba684a123f992e86902a9844b930f5df2a71fb0fa1823955adc55a25099982393c55fabe90140ce3614c1a59898241d9f5afe9a1600ebe97af214b4f3005515e416ee4844a8ad539bc859b6092e307f9a5cd6782410795a12d993c640926419a509517528239b5dcecbead6e7892604e56f66bf27ef04a22c1149bdbd6c14e5cb31cc1701d64a629214a2ee64630cd251f934a8a7a9914c1d4f76ef183988d168510c1a04bc71813ef30cc713e8b3a1d4a5f528561befc2154d007c398e9f183881026426018ac840a7a964b7e619091a7d7215f187f2cc583b43659fd5e98e24a45d73bcd9bbc30eb5c72cb1eda8529943835ad756130c1939b9a3ab991736190a332adfa45b830e8b6869b9436445de816a6f5e829af6f0b939c9fd5222aba797b6a61d836b32a25589acb0e2d0c7b22e45b4811aed6998549864e37499f8a3d4ab24850614b8832752c8c6582ee9e64e3a24b5818bcf4d77f986c4b955720c7f2ae3096d80bd159eb56187e7f2f457e49b2b266854949e1e492bb64152653d124514dae33c9c3aa306865c96151bc63979c0ac3fee5a8a44654984e5c59322ddf2d1e9fc224f3d624497df707159bc22426e6ceaf782c41a9140659a3044be984c95393c26022cfe4d3df8ec230dab45b25917752b6a23009f774b1846f43613215cff944bdf594406112f9bb2b96ca5452fa84294486bb8ceca8be3d61101a5b2e6a3d4929d44e98d4a69da493977668ca0973105fa2c88d36612c179d673e7874cfd184513b5a6fe83b13e6b294a4fc7e1384943161fab951979dbd84399dcbe82d614ccdd2f1f2323fa795308f9fdc62a29430cc9d5a2d53cb8c4998c43c31badf4a499835eef3c793c748983e898eab13724d9b20248c72f721c4b5f8088386baf1354177db828e30a79b8b8c88558ba146984ccb96502578da5133c21c2bdcff9cf692e35c84e9c33ac9498a75e75714610a17b467d3ae53e74a22cce1aa3f095171f4fb8830de5a4ab1f52af3f24398e4770ef5a09d4f7c0c61d8b8102a7bbb42187d6eb67366593cb1238431d4865a5907616c134f96a70a55724910e69254092ae951ffe1b540982ffff565bf29ed016112c5940eea2e5495e80fe63422eb722d9f20fbc1e84912bc64cf2528d1d307737ad5a91c2c0fcce083e14fb6ca28298d050befc1e0213d4b96d856ea473d983db9c88e973d992721cfc883594f868e1fc69e810773fca53d593ce7ccb883a9543f2849d81f4d0bd261872a4ebeba92b99cdaa68852b9c429b994c74b52077350c24ae45a34bcb374309e52e331a48866ccc1ac9d9f6e974a3960e9d5dd9629a62629eb51b1b784b766c4c19c34c7a41aff0a1c3e1346a94fcfd68c37983c774e759e4afde79de10673ccf582196d4087e5ca6f67e849b2a1b46dbb4ab92c5aacf911f24eb86b307a3a0b9de42ce2abb621cc5043eea74fd08c34984bd9675b366d21c734030d067dd2884add396730a93df30f9f6798c194b6f2db3e7974b530a30cc6f8e0157af1f3ee8ccad0c19f3274608a0c0611fa835059392787f1f038397ec6188c7de69b9fe25fce1dd631430c5c975e8d4fc15f4187c13c66d9463e3d34bc2f3f980106d3693f4b1327fbb8858530e30be6b42d9a5e9d448c6384195e3065d3ada44ae77b13951865388e2e98f472c71093a48f4098c1057392fae40fe7962d98f2cb7e50923a9562e533b4601e39230be6dd10359f727606164c52e59e585ef5a83cba195730a55fb999170b0a33ac60ce13e4d689d413473e560583f0131595928965273f39cca082f1b4f4db799831852a091df35cab9682397fd2740e33a260f6ce2baa849e9815ed0c2898f2c784c6b0815406339ed088d1a7da3c5f0788194ef0f3093aee826e0f8b91b209a62046e8c9d9c4bbcf3899c1044b4aa26928396ec9e58c256c767529432c76a7cac9faef9736b916c3c3e36628c1a07b37f34f94fc1f4c7c0677a7c4d0bfffd30c249853d49b7cf7e28c23983bfcd34c76898bee8d60925d9492ea6415790f17c1b0a26428499ec9a33e398308a6afdfddcb7a320ca397b6b82e370bc324b645b9786f6d20182693a794163db54ae2b20160184df6d241b9a95cbeff0b835afef872c28c9e92fbc218ae3a424d1e373928d9402fcc6f4975d0a2d793cebb015e984dad09d749691726dfae941ff94ef2d2ba30c8d930418d3a37900bc452b9b9bc5cd8ce388d39b962947cf9bd47be015c182ccc4f52bd57d2be85417db4d88bf15372b6308599137a746fdf956a61169d334e289f16a6d0ab5b15f92ccc26c5678d08fb349285b9b742b34b74ff8d62611ecf7913afe4b39561918e9e8258a96c7a85c13a8c56b2d615c6f5dc5fa2bc28d9d35618dcfafaec6207999315062545d997e5925236d32a0c335796f2cdf28530a9c27025051d37f9bec49652616a0d21c46b899656255498c2e5d4a293f0a2e2e91446f75831d174e52749a630959e5bd0132f85e9a493f36fe9b229053b7af018180307367420c0023a30f062a0b3a38c1b0bb08000747c8e32769c4f341670010054c00e03671828572781f4c714904079e47a58040a10001f200c2800003b7494b1020204e07170cac0c118470c040840478e4fca701c39c848800974d820e3282000b5000000000000004060c78fb143c7efc000e2781d870c072c4001a04307f2208000ce8ee31e0508c0d9711c470e8f030060000f48408ecf417276e8a0416301000840030e506cec10a3868e438346024664516cec701c376271801158141b3b7660c3cba041230123af308997b19cac4d6a2c9f957176e373d0d8810da7e1dfb6630c1b2a1871c58ed7d10a326eb0a2d8d891a3860e3168d048c0c82a0a0d1a0818518501465261aafe9404a5525b5041541874cb47ee53d029a7ce298c5552d0b14387d27fddf81bab23a630f6579a18e6a6e4c6dfd01b7fa3e818c3c68e1c2f860d326ee04876a414267b2b4168e95c6107525082097c600513c0b4c408297630328a2a9e347d9b593a29f588280c3f6ba3bba17bf2ec91501465eb33ed6eab4366fe53b6ae31afcb279f6006345a30020aa3c89d3422de914f98f4a7142766661f58c10476f88003628c78c27855662a9ecb9cca6a8d318e182928239d08c20827ca9da61ef216c6debd3e2ba983914d983d9aba7f474734a1239930d7fc968c60c2542deaec44852e610eb1a1e26437fdded812865fb3244fc85c1939691d64e0a051239518a144625d9d7ecff12f274732868dcdc17918ec24cca7935c9a312289a4383a8850da628f045aa62d972aca24198184e1fe4cec77ff8e65a547184b0e2b1fc654ff898f71c438578830e208c3dced6768132d97be6bac8d31d208539cd359eebf540e96c30893a4f38fd2d14a4b32f911c392df412f22f38f1db34eec5f30a20893785151ef36cbb2ce35d692df818e44987279282588f498f2f91a6b85630411c6d17b625c304f62091934c6c071e3068ea4588e914318bbd4c9e16ada8e114318f459fb9f160f395b71ec388187879916c2ca1baba0741ed558eb010e442307c91103f58bb10395a1434f30031a141821c48e0c42470461b4b025a5b5cb072293adce0a6336daa22a1e3f48d33c51d515afb1f6635c937123f9c008208c59f2e82f5349237f3066872c31cf84f2b8c960c40fbba789659ac96aaa452dd1e4bd52d92526df69a40f0613e27ced83b769ab4046f8703546f6701e7a30a9d52a29d4739aca96913c24ea34de6db4c83f713c98abba54f4bc0e1bafe3c7c81dcc49e486507a4eacb4fb881db20e5b3618a1838eccc1a42b3684475f0ec93df567ca3f290e066182121c8c2596e91c6e724a42fd6f3069ef50f217773798d4e8b96c32649d9ce36d309a945298ac39618349ca8b9ae07943c92d598329b88f7f882f2b4174d46078cb1e2b6bab73c99d34984cd8ebffebfbf0d14683714c54536577e964eb33dc88190cc273cae9fc16af4cb60c261f75299fcce40735194c51d394d8b6854a151c4331677767df2e73312c05252ad7411e11835145f4a44ec235128632028632f2851bf18249f79654763add85d26da5e4e908174c693f4dfc3211e4f81d22781ce4781394cbf13b6cd060640b7b6ab3b4fe338261440b86134d0e954ebe9dea932c98e72ca8dabf207ebd62c1ec95842c31d146aed0a75d34111d762b182ffb7eff08bb0ae63dd3714a4b72840a26f910eddcf1bfa1323205d3c9572e77eebbd6272998d473e62d892fd9aaed228c44c10c25ea7b12e4fa0a05bbba4ad6aaac5db347fbc8e9850d234f308c52a53f2b7a18f39213cc9fdd3fcd8d29b74ed204f3284950399e526aee3d4c3076a7f512712657b67009461f135521ef5182491097d386de175d79adf182912498a229a9ba62877eed7d368204f37deac81565795e7381c3c8114c49e5af133dc95b67a211cc1d33faf31e4fc7915d61a408e6fab7f4f5e291c208110cbe774ad67f7d18c64eb1a4e90abae6a426228cf455126b44f6a41c54826190bf664a78b8458061b292b3437f1b37ca2f4c254fb624c99a2c0422be3095d67653ffa79467d78be4a4f465956c114a8a8618e74478614cbb4cd379ca1288ecc2141f43eae97e35afb8c61a7b40a4fe8f53be7aa1a992402417c6b470c19274299cfc15eb20820b93c679f796f8262fc9ed10b9850d115b5c2d54841629320b7369e734694f1caba0d31c3bc810914535f3157761c1da2de6a28d4ee93d9938a2f1d658cbc1694189a4acbc46c49f4a81857135dd6396506a59ba2688bce25c711ead300f11569854ec1c4d4b2ce5e5db2a4c823c9d2cd5afaa30eca99deca1543fd625920a115498c44d999c6a07955b899cc23c4c6192e2f8a8f47ff2521c8994c23c48611ea330fbe7f73529b497a093444461927949edddeacc2733147a885730eb9275f9ed70b97f4d6c2e020ad35ab61c1d4a1d804c887cc2647625d77a520a15f4229e305dea4ee25d4ff68abd7e42a413e62d69237f945b9c688b70c2d8bb96a4db988aeae8092012229b305908176f3975f259521326159e92fc1d9bcfa7cb84c9e434492c347e5c344c986c7b74ccce2988e5942e442e6150a29efe2816114b183f653dc4dea6758e8954c224077d524a822539c93a11a184f1a472511f4a65adf6e01099843975bc74aea39684794ecf426aeaa9309526914898ef76f32c5c229030cfc935a52f3f970c51e41126252bdfa2c77684c136d64f9576451a612c2947fd421461449d24a1affd6974c6b07123c7b7c0078e83038f6ce44874bc07506411c60f192589bc8c4f4f22a20863a9fbad0fb58b24224dcb32266e15ddc275980a2ac69569ed8b082288306cbec941a8cf97bd43987349d966534f9785dc10fe8cf8f826dfa4102649a7f49f7c564218e7efcd4ef6141984495b69358b1f15dfff2208e385f8cb4edf25e56ce204914098e412c24bfcc9950208736fde88a648cb1244fe60ce275a52bc5c4925bbc50fe60d2d5a3dd5a95ed12929d207d3b765653d93b39ea8dcf1c19cc39a18dbca692e28ddedc11cd277cbf4cbffe975450f267525c449f7db4bfa532e0f86710f537a3a3a05113c184e569ab7f8bac81d4c5a224aca88a99ad444ec70b625ab5597f30a9be5c240a40ec65ecf397a10659e318b41840ee63a759dc49372ba5451292273308d1057a664b7e79b89881c4cf1f2838e38917b4b6986834988dc1033a954d02929f206837f86fa6c4a4ec40da6ef58b9cbe28a5610698359cb94a84e556ddbd12c88b0c1e826c8d2313efbe7cc4e640d06a584d89a245d4cbd2435984bcd08e939e55fd489481a50040d2a72066377ca61ba4e8e19cc29084f7a52d2595cb63298e49c4ad27fd16c248890c168a32f885d16392a976330579f99b47f520a27e445101183a94337f45f2f27059130984cea6cf392b3db9e1087200206d3953c7aa753f8af245f912f18aeaeafeadcbc238878c154aa4fde5b5c184b97638248174c7de26ef7f58b70c1b49dedcce494cfe1df10d98229a83939a6c7490ba6cf355917a79205639a6b28cf9a08160cb3a3b488e65a0221720563b9b5574a234f9424a714112b98070e44aa601e2f420593b65827c5cb39e9ac1415884cc1203f7f1ae59504e56a12838c1b3674f00944a470ae7a66a9d27f0e328e05225130d55f5813c363c4ab480c326a243bce8d7c8108140c3662257aa7d26953167982418ef00d5bd1151127985b44259593242729497d600513d80d8834c16097a4648b30216b20b2047352d663a37b6139f94a30c992c2a9c8e734de27c1384a1056b284aa8d3a418239b5727dce614b1e751fc1245faba5ab24664d6e0463072b115d725b04a3e8cb9eaa388a10c198e1e9baa4d9cec15b43840cc3a85b2a3caef6981027c2b0c45c95784247c34348304c9653a82badbdd793041886d55c933be83a3565fec2606ff36549bf5d5a2e0b21be308593c3782715bb905e987b9497ece085f0c2b0a27582d0bf3c3da65d18bb042bc982858dd35d1706a1f565ba9e5c984f3095e41bdd679260e3c254b363929a249d720f86dcc2244449c1afcf6d3d46b630b6e596a07feae1e3b53029213f5d57a74a10420b93508b25f9e9ab9e3c08426651d97bcba5fabd9a6c9fad9e105998bcc6f4622407426261028bbca8844d86c202712c14094522812814c549de02a31308001040288bc562c1589c4792a80714800261301c30301e22261a1810161c140844a27018100a05c36030200c0a868361704038d72bce01d27eef3b00b85f514892e958453c11e6f509852fd6ada4feb37c69993829a97f39fff8442ca5d66769eedf13552078fa948f347755964205c2adeec70de4a7bd56f01fedc60a52b8fe4e865a2707a21a7b1b39cdd7739a0f21b1d04218dfcbe703be4b8fbbe8cdd5a0edba8dfe5c5052de871837ac68b65c1f84516301e64f33055d564e4841430c57abbf30a7111465d1855cf229ae23dab1f9d98093a221048ed6d73c2b5e2ebb173b4225444b156c07728f5cd09f9795bd4d32b89a3f3b4ab83a1eb80ba8c5b2a2e6cf5c80a53a9caf80c1c9c0420f93547c67c43496e2e0b159cf66549cbc5d49d67983af744d3a9cdffda91a3839816ad87a60072c2690b22688df258f08ae08801288d08dca75a5112e5967a1d9c9d6ecaf2ee9163245504f4ae297d8d0c3b23ab354be07a25a1b7dab9f1546ea510b691178ff3ee3dc69a6feca02bbb77ebe8922a89001681f48392cca6e919a45ac28f4064c9315efe2e506ed11eacf4fd913d21176239fd38b5c454f1c2feadcc24b5c09a1fca23267941e115c686c366b51438ee787ec7c218f2f3334549a06a5b3d5297ab3cc66069ae4fc3b9c2856904361e69f3f9192269c106284cbfac206694dd6cc7582c8902e8b7b4587b6dea3fdc8690b623476e0d197611ed745fb30fa1a02b2d5557aad99f7e96790b8a43b1d4de056bb4cd140064e4576c393363480a54b0a490963eacc1e86f0beeca0866a9a3f9e9092ae474381d56ba45a8b5b470585820a3175b3866719e4585255411d33da9d9320e083f3a2fc01d9d0fd3058b1216ca0f5c15466994ee37c9de8827f6684b292d5f2eed7a2f479eefb96df17177a269cbb261c6b1d99ccad084f715837f8503afb878097b7499e7bdefd6b8730ed378efc1d2046144a94077ca6b359a33a9a269fd18f1deae2513462894373c94810ad9c2c4ef39126295a5b3bb99471c106a55a96a996a420d9485ec6a3f893bc554d13c3b31a8a2e74f3b374a7edf7dcbd92f2c571414c91b724edb8b56d7cccc9dfab9da7175e40b5c3a22b8e584c64625297cc92a5d12f59d91c426cdfca70cea6106b4bfc77a09ac31750d0a815ec275b6e42ee997396bd68c608608629f38e7acebdd0ee29da536d6a57acf58626520db54e03d74b36154003c85072a6dcdf2ab8e9bdc2728a4c21e7ff35af8f56384f969192ff6501702c45b38542f1dc6c0882c04bfd34c300a1a7282cda3c5084a84adb665eafe29b4619c726062681da7b04edde8599eb04c913b24181b00c63eb24d0d89a321270d0576a699e82f91eff82abca9d752db3659ee7772e58cc5cffd2e7db2df8ec1f44bc5420613316f34758110ef78e11f4870587f55768330f4157bf239b242cb36a33b0d8ff0d6046df21626fb402afc73812cce104abf16a4b6530f639884be0132a5b791cd423262a94c4e1c47ec56cd416eee1fe8087f1310d3bafe70d5db643291c875994f17631c1c2c6635a0e35c5f31a513bb19d26a29c40f3ae5ee0c28d5d63df7e932d3cd0642b3e863e90fff9f3369930dfce206f6079e51b8ab8a787d7238cd77ba757050cbf2053b644689cefdce821a4096d58734c50789273b0b5ca466a83a411d353d9ec2a4209b743371ab4491abfe2e64ba060f0b9710b929dbf00f28736fd5ae23514ac11b73e0c94f863477ed0ba0a83f37827b51359469559e8841f6f32d1398fd897358baa67f858de7f406eecf2deff960266edaf14a828cb3d3cc829b26b45e008ded1282fd53bfb94810de98cdd7578add51b674a7580df293d368841e71d9603f06c9b58ebf861829e73949ae2f1cd63050defd4589cf707aff9dddb41796b22ffe0a82f5445cd59e5c1c637364790f863c091483c61de7dbc347e1995182c7d27826b54ad434161a85876c558422a8721f6f16c2b916f941c337c725554cd5d298a28d5ea7eea5398c6af90ce2edd9a3df4fe778163699c87c2037cd9c4445b6d2d37dfeff0ddafba6d7eaa8d91f17c6b2751c761dbc7774f54f32bede8981420d69dcf716543192848fe20e80508512d052599e96bf00680aee4bd3805a81159eb5c92643480e6eaaabab34b43885cd099e6a5449984c1a6364fbf728478630dc8f177a6f382f7587166162f829b2601c9939b37049dc47f10a79fe074ec8e70c877f68f0c7cd07ee37a01bfc0e6f36807b9da112ae79e72f453ee9f9680ca7aac9caadac15c2b80a7ef8711ff954d289462c4544ec4a4252c594faffa49d4346404e2bee859b065bd82d1064d107bf863ff7ae119bd765a901542e702974869d4611580e09f6c61649eb00e1e54a9c267989f713aa6511c27c40aef6beca967cc3bdaaf4a54a327cee306b7697400b62d2cc25172da176b3281740c0531022a6236ba6860d074a4207132659dd70f97588c7c142585268b6611c86d5e74ed83538a11e5faa0ffc71d444630bf645dea15234430844d183182ef69b5d5222f15448dbf63174b00001d38167758450611487cf9ef9e8378d0af1c7d52ed9a8a40d6de75022cbb1c9e90fb72072e490f18050753655e36073f7e8c80452d2e87110da03808800f4ea369a594a0c08b90435dcb4f97136d7f2defa2ab168103a33f723e3b762d77396b3ebe92e88faa2491a3c222819b1f41143f3f9083b353e991e563952a3bfbea4f33ccef436edc917ea9d26ec2f4615c64cb43a3c089f013e0e52b727f6d4c3109eca2a26c4e5a40242aa93f1345bf8d4d0a483b3b2158f91a110abd60d1c705d21c7b98dcbc55a326330a2605aa31995295aaf9781797b22b15ba412dcfe5c22722f732032b8a5daa5e7a4e5c8cdbe046e3e43a6580fcc8a6900726b7f609474efc7d0eae89e0c768dd28920ec504fe5ee0055b0bccb2ef17ae5cfd1c0de09be413aebbd6f7a5f122702d359b85dcdf84a70e5eb3ea5df2a9f9733d73bad765dc202ebef2c7433562166b1d42bc4c20ace8bd951990ca5f450f1106fc28891f9bf3491284dfc54afddd2bbf0ca04071f5293cc6a2c57bbda040442ca19497fc5e35a6b057cc1af3eec5c5623c008ca1c5407505c0927087987b5669c6bf50b66ab40809d0ab4b7abe1a0ab7d1f5f524cb52cd8826a68f23f5e221f65894c00782f598327ca4efefdb49192bd5874c3e3f6aea8499b475b85ae3ef7ab44edb7962b8dce476d86895b2f77f37e46e5f2b422698f93d131e1ad861462ebee61e34b5a1db93ad762c1143325b79a8af4e1152a4c522711f5c1852dd34b23b650d1eca3a66b99e84600ea141634eea15004d982935a73693493fad6543ac344a38007884e204353070f84a4addb531c8933f8b5d7623c08b993c18fb4be5a24d5510d5cac3d2a654f44288ee7c9217ccd7fee0a1a9a0568f8174d9aa901b3bc69270a4363c822c778532d025d3caeb03ee49f03cda6dce01029bbd5a89bf6e6b4ecdd6e122ec0d089c71e78aeec49defbd8542c953663be180f13176e54e2df4f56b621b499d9c8374895ab2dd66a892eddca1bcd823b8ccbd06b7f3dc4f382be151ba4f063635f411ab1637a9dcc8343d7581224794963cad6d7bea7ca9459dc185943364048bb12638d642a78e22049456c84ad5f819aa74fa8b8a26e2cc2b7ee68c08e0b03d8b9011a084d3603d5c66051e56440f95f377a101a5e9f956184c3266bcdf81e11dfe30a4454ddc8b8692271e8f7f6b1ee9a9642d79f5e29ab2cc77e2a06e1c9a1318d1e4e0dc26aab378590d9ae82dcc131ab7aabd14cf3bcc01b7f0991b0db060b4d4daa0118df6212d8a029c91b79cdd130f99dd87a845c220e5402fda990c3915080cd15e62ad9c971b4b1f85f24eb5d18b7f03a129db6d890af048c062db80cf8aaaa3e3569d1295a5cac7b48c0140453ee7a0883a3ee1e559377c97f4be200a569f6535bab0765180877c6870480a2b27574916919c0f42579d9d87be55b2c69941902f75bb0522c68c244ccb7fa469520ecc49dbf2c5f21e57572c8d53953f3a4dd77ba40f20caf009820c831ef7240055d8e23f6df7b1d217bfcbffcc781d09af4d8a3042b2b2d4495dd4f663a839944471a5cb6e22168651bc0bc57da031ccd2624af209394358fae0258712066c4d417503a1c7d467eb4a55706a3628bbc9c199c8fe8454d11bb9300b585d23ea02ed701a820d0f72c3a5c0e984ee9e5e86318cf6bcf1180170a484a576750a36d3a3ec24b81b16a0fc75adb90990c77ae8ce6a239533a0732b45b3341343364c1b0a0bf8e5fc342c8892270c932971ff7cf19dd4b73844185915a6e5b22a0b779ed805194c9593ed456419dcd1b67447dfcb09b342ced21449b9e1542a95d8fd7998e00077edf8ae3eec342bc72b7787e5929b4652d0fa462f211aaf31b584e85cb604be2ab6f9f0d4b663b8e3671b3602d18c231fb1419fbb0d5c448a25fce60e5252e5a5dc790e000c5048b76988f32475faa4815598a8672a39cec134be4283533d93c86a86917e56567512464d55509d387b2a229ca90159a5c7fc0999bd1fc01db1081d66c95472674f41c6d6ac45ada8fa14112c3fd03d96fcb43657e87648cf92cb467c4bc626e2f33a02597c39aaea18882b6911a87de7e4f75c71acda31fdd3894122c87490bdc7c955a9dba4e670d257e91c40608992c17ae3e5ef8a78b1b71c6d2964ded9e81d82ecf8cfe3979fd550803ac33665b7b7c0421482905c2a640914f81defa09b2fd1c8dbfc538e9ec473685462968ee2a76733a4650450806b943690dc056a3e928102e62a95194cbec13c1c0817050c40518e12b9939f2012c43c43ce8242808934c4be4e050366ac0f97f630c2f977762f439e3c8c2658e5093748c4d9d041a637a0a85708a5f69b53c6a96e69f55d6c7d17cfa951147077527eeceda06695c58b21b82b67c8ed511ccd040c9a6177aa912ae7f752a64548e822818aa540d1f82062a970e4b3ab557420ec31f9382bb4d8895e4aa08d747ac8da75dcb6e4755984c4255ef08568816f774b0258b3f79bc738a0caa082609a398a139f2673abefca59ccd5ac600a0428baed34bd84d9b784c4bcb803d96a86337f9ecb3de64e0d5a6f9d5b2e2379f2a3ea82bcc1cc9a4b37cf97ffe25db81efccac93dd706317d245ceb77aaf433b2404d8eb51bf09e09c78adc2248695d1a461d40eefa4878a03300b5e5a683e11f50d6d15e9717cd34d8770089e9b5a3eaecf56de5e8f164291eb3fac13e26cf130c0c62082b3ee1455af50ad212737974435e78972f11cd587c07cc7ea24a6f3aa382375152a83191fb40780a56d43fed559e88fd9e15eb781db1a2b85e748d6659bf0971b2745e531e53d9a34c82d5ad9261f04e00292a2c15dd0423454624d34f427dc7480f5814e86ac82f7c101e014238ca1cdd84d918c6a1d9deaabfe5b2881f8e39536aeff8af171a06da130b8807f69ae243cb0ad29429f98c8fe6cfa9c076f72af35a8a18c8d7c953f20dc83c7f98029e8dd83473a4c8f77e9af0cc02ed643a173776d9acb7025f72a40c51ec25301d122c021b9428d4a8be54cc7081fb932c6cc9ffd69e69a105924ab708e1f32254a658b9280f918b80a439257449726566064630389b456aa4be15d0b0ef86aee0f72579e4a6748f78c5b72e14a61969d5ee344b098c0bfb674ae4170b8008adcc08ac8197af012570cd7679b6c872cca65ad24f40ad8fde0036d6d2953e405b4b81aec8fe5f26baef852f521d94ddded9d1291fab3e2f1f2fd275ef4bf21ace4e61cd8cbacc392a6c06e29d28e3bc5d6d65458e247420242ba964be407f16926cd51daf5b67aac4a5bc2ef1a5c722305bc744422a41f4fddcbc8a4c7ee3a5e5a980c1a6964c21d4400a70650a3a6c576a5c924bb300fe47b282d584e452c07339e073ffcf6811f8ceb7b7c1441f50e2e6336b9d9a4b1a478113db3e21b588b8f13580d91cee9f6d2585ae1e86d8c8e59edfd2983cae5f97ca80c3faaad7091a6b9c8814ed9e5ae34331b9f0d47ae6f6e0ccf74325d3226ba3d68c4e5739043d15c410148897e03a4c8d47cc070120a58c963de934184fd4f9bd503d579916ac173dde7d18476bb4bd07d4ac8e96dfc7437fb1e3dc1e4533f0b6692eff866b685f1852f7ffbf2ae2019ee923d797a32669682031ab53e3c57110acbdb088aef9f82d8a3b908c25a9bda7da060cd0be8569b442bef9f02cf1a41c97d100fd088c87660d3a0de2f840b795aed760c83ebce161606f1a2091982ae49940a36e4884f0dd990e0324b5cd204332b846e2dea877074f7b4b4a6c4a6098219c467baa7778876fcd52ab1ca743183c52609cca21fc8b55bbe1dd9565c69a3f576459c14d3015f39788f4ea8a1d0612275b366467fdefd608e6ba0748e3a4313f12782f695fd09f3bd3f2e1b1faef10a82d064730e429da5a24ff5c37b6b6e0986f01fc10e85340f6b04947f60ae6ecc6fa1d79bb361e05723854bb0d01ac26534739c06fea3848628c351881688fd82a8fd009ca37ffc5cdefc6707c3e10dcc25276a50f8ce16e6277d5943d506cb689675e7aeb0e9775428f60e417d1c4542e9829beb29b22dbe240ec5cb015c412ae3c74e3a7dfec142e2c0c7b4473f0bee1b1dc1e9565c3800c71857c2b1cd6ebc41e33a976e85d9057681ad4c5e50add5d6cbdf0435fbe593ae660c2427b9ee6b909daeba520a2b8e1cc6ebf4fa4ee83e746670efbb76e745522fc4014331064e28f717bd1ce930e72031a927089a8ebf8dbd6627b835ef7774d13d58fdd3fd4494a6e46cffbc193c679a2b527b9b00c3ceb16aba988fe067c0242467cd93df9fb862262181a223b7f2c73b48693995e6f532cbb42545a68eeab263b7050674958684ba326700a63c51ac307846b79536ce33d7229a4bd02180eae702c98a5b3a7959f6acbe716220f5a86b8c46297343fa183d0cb3a1a3e3e24e66de6b3d68da27b78576b85159c09fce7289bfbce34cfd6404081a67e5c6f28fa4420b2b33328ba39372ab5a8aa5fb27606bc758384ed701ff83c0fb2e4879be8d015206e3a7189a9841dbde58abe96762e39cc0a713c9638b4bacd66a4235620229e43efe040890febaf7790f19f179af80ee24e8d023fdedf3148f7e1b069a7ede31ec29560becdf24a2abab0cc5368582493b23f1587c372c8538e92e535ebbe8fa73ac20a6a0c93e5969b827f6737564682bcd4abb84d0efe2c8c032d9252e22e6f17caf6a15e520c9a2f9a51a1fea042731830b9c3ca53bb129d1b53f27b0a12f8b130de612bbd514bcce13f1279660f440aca7f28aecc44c47d856dd80b0deae205c47da81fc983964bf0989cba8c9edba8a363073adab7e325b9dac56bc37e5317c63bbe8b98c3fe668773e5a1baf818f66373068b901da3a414f653ecbb24cab9a85fd770f1a11cdd0d75e84ee3f22edba93f96bb337984829cd4b6829cd931bbcd5375804fdd655cdee93aa6631f9ff2b1f4eb1e5dff05c545ee705983abfec33242a10cdebf6d5c911a894a579f5063c43be06bbb2b67624ae902973fe6b07b2edaf5b7a2daf4a378c462666fefd3b1b9ffb649c62e6da6d0c3a35aef4a09632b7dc316e929129a4c265baee137b66163c42a295e53a27ecb33e21f4cd1235f18b8cb29655b246dfe143ba26ab59ff5d1ac9f227b114cd93d0632fa5bbd8caeebd6ac54c2d90d1496b49ad248b84441e21d828b0992d7c57930a68dc0932935a134d91100da224a76c2cf687b69b5ae4fffeb72699776394feb98d8edc02d2d848e7b757d07e3fe4eb3833f590e9b0f1ec8240c5d93cc52ab25e524eda99fb774922fdfc56191549a12061c1af075f53c613adb111deb9b785516805229a3b41cde2d3b3d1b767ac9909a3bc4238ba69c55228aa0457fe7b38208bbdf753b947694828f3d16598c3a9706f745872d9ce7b4c8898b440c99e185ac8db6680dbbb29d25022a93fd5d8bb98d7efcb81ebc7c70c7edb63f90d3bbb8ed4319787b5738c20b7501bec8d97964d5e82fcb2c6ca61f904c165296a00bfd14767a4f779cf29622d8d1bf29a91544f8d3ca8b286b4a9ffc786bd85cce2a0ade7d3f491896af57c1b22144623f32bb59eca872a960336bf0d25fe2a5e7b070bfd893fc715efc5be49eefb98e539aaab059aed227db8f719a72434fc01761e6ad067e0f202c72d0921385929aabb5070f75146d4c88411753d891ca9456eee3203ea69090f76887fb403bb8cfa202fe9267bbbd8e7e13d42e2d3f3b7825644232539e39ec4a591ff6c83493182a41c7ddb89d844abcdd8468010fbbccbede504e31942fe2511ae804d7b8fdf0b85ff4ed07de98fad90b94c2e37944737d1dbc41e3990bb3bb8b537be79b51a06ef3ceb7bb59480ea51912a8dac763d0e24fa6a4ce70d4e24733242f476842225711736f564913a9691960d5f0ad512b80adeb44681b503461f0139f369489da0427132ccb947afc99a2a5b006be98bf1bf9ee1aef88e3fe06e4b9e18e35d283df391ef98ee88ab84457fa74f06d442f146fdd5a4403fac43be0e4550b5b43c84efbf7a2748584af707351f1ef51222c5d09523ce2ccf2fee4db20e5fec98167eba2b80855717965c76dc19cb33edec85fa39951d2a7146ca8c7cdab9abe74acb20c1b13334337a90699ae8646283c9e96fa59859a55228bf9a8870c36a0910722ce1dee6616772d991bd8decc6c415dcd4d37e75a519def85b94682ddeef8539f910b919ce4c16d46bb60659fdb4f0e11f53de68a76b009d2ed7d8538cdf07231896e622e1a8b00f54904cc6f20c1ec4839866b88dc28c7388c755b0a58e23651b3d1ce085d88646b0710fbaffdb5959a8e5388ca360fb0fdda5e0238d756f5f5cb91af69e5e9afa899404de547a9b7c2590bcb3c05018c4c80499126916e2d0f6d1c4f207276337e32f5362f0ef99eebcf740544d9c00ee80ea99dd9aae37e40975010854c829cc979f2cfc9d5a253a5674a56690e3066c9fa6fbf9416c29c28b8052fddc84d9d69bc72aa258edf0505a99e93fcd55069bbaabdb8e120c1d34b0ca7218e73a022a9c26f687122739036048384de7fd89733c6f1415ccf7009498b5a4de553b483d3436dcfcd250968e3c80bc5a11506f7d03782afe0e48661c84357d8c2dd1fc759525f7a1a80dd346b93ee33b526567c41da09f94f02ccce18451d5426944c88eaccd8474a4b11bbf21b526dc8ecb30903323316a07631128b680afec1a9f2400671ff745a903fcb8c7407c1894894fc0cae758abf57a5cb89872186e42845b5f69b4f573019054746080d12938d399a64c7cc16e1bf7adaa72d646a1d4f785228161462a08e71fab62c84dd9c99e5fc45d18567647a9c89b5fd9a0929945bf5d49d50a63f61971263a45255ca99ab447f5e348b515a25289a953ec813e89c1b69d1329d78b6f6e702c45221e3713066ad22ba70fde00cbc46521106baee69258f3df20d8936e3b4de2cb7e70c3c824c8119ed0b63fac29774b24a9e319cbe1ec922c7e18a0a3cc58b8b2b223a9e3f20a6b577826940abce6dad8f467fc9187b300823b57a9234b968d804dcea80d26391720fd45582dc1be011b390a757a8c8a4c83696fc41859a46efbbf8a30adee59481d3c31782a6888fc13a0476010604cec3c70f20d955b0e8cae6f8d0b678181447d11798e9b5dabc1c7ab88545d345e6f1f182c8308532a333933a8d21f4e640628ff32195aeaf8adff31560fc7e68cb6b183627311cbedd03258aef3a30c712b92f0266b233de40a517f2b13fc5a0e6aea12bc435eede24c8caaf7e4ec971cd951181f36857e1c4c78ed8d43e5380ce88dcf5eb9221eef013dd0d3e2af7b66aa650d1b0e2746ce96e04ae6b3186c51b22c240b3be458ca4538bb1cc890fb6cbf02ce20b9a0f478072db03a079026a467478b1125c7169c97eee394a2688719ad9e293dfbd1bd7a0e96a5d18bc554ef602b483310408c764367ccf323f48cd7f9ab6e8f725333b19a66a1431a9881f36c359059cc1125cd31d1953bbc64572177a725b07c78a89c67f11d019fdd387cf4ec30ee8318dcd76a99cade0d0c45a9cbd10fd93688f34a17f5b8999a2a6c5e6198f74e0b4d0013ecf84c8e28b3eb7775058eeaab7c32160aa0f18b8c33eaeef60f3697dc62434e60d99faa3628b3a94d0f0d85715c383fef38216bb06ef34300408bd73279aa27a0c9aa1549a63388e32d89d61afaa0901c126bc8ef786bdf082c238ab1fd84d0cc9b485b0b796cdc17e1b7d16300060a481f6c5b99551092fda0786eaa9702f1e7bcffe03a5a36422341535f148ac007a3ab8c891eb363d54cd9dd39178da932f25816a0a474e96b7c77ef18b88604c55992a2c99c2f5f09004fa9fbf53bd45085c45be40c8872cf3399df238e21bb8b304c03208409eea94bbdde75f4b969af38d7216532a7035b1b47800b732e9fb40b4fcae45101f9432e965414e9f74ec1e122f2b0616d69383831420a0239d2acc4efb4e07f387a257d21118d9e52131f46fc4a9dcb965e46d112772dd5418be938aaf6c0ec67c9ac27137af60a38177c42a85a4a6135e4534647aa28fd55bc3bba0a613d88a72455ce08dff531b031f0d5c9ff8e069d19217678e817edca92e9b726047665b40cc021801c4eb719d1f51659b3292d2f724e4d1fa99bb481295472c2057f3cc1b2ecfedf59338a2f7fede8128f53d5f87953090b2c7823b47c9f53e93ce0a0eca7c4d0227cba983f5a20ae210321b20c2f4b9a97dda5238268322c5d18ad608c088e51a6cb14fc3be9dab5d80a55af0181b4e95c9394acdac928cbe79f304ca0037ce4b8c0a1e43ff8e54ad8b4e6b97c13accd31640e5d44b8d3302f364bb14d7637986c56a7893d67a3f96f8ae3d2d05b6c5b965a04661c5119080c4c507f0b07d9de283bebc378650c367c24d2658652012515eb75038740ba97954f29cde1978d30297aafa06f2d20ab72d485b96ef2b135b324a64e28f147c9866e6153e84529c4a220d4c90e2fccef893e39b12788625eb01dbacec409bcc038b320c0e80053489ac76a04ec39191500607c1b01049a3561c1f9652906bb28b6bd0ab6cb10436e21dfe546388e6c79c89b2587696736b4a4c591bb6b5567a916cc297fce14235c27ba0d4b9fb7168e6fea995fc71ced97a7a07be3109d429745d3b2167ef7bdf98e50dcc0e70d8eb5449fa1bf4fc4da340abcb189732127b4dcc2a73290a7656eb91cb0893cef64eec483e6639e0e416b3f5fd0708404353698e4531e4746a9726cfed18ac1bc7819bb16d6308dba9eb7716d0661172eea4f44942b266c0c50de7ba1df2d3757685d82b3fe605a27bda547b187f5af0ae0d678fb27089748c7b2d4646c8b1a629fee0c9df95e212c3b053b2383cbd6c85d4b065b6995735566420a8ee17db532a60c34c072d14c111a8e36c741081e2ccd3b2ad18faac5400e9d5c3411740e3268b4449c0a84a0b24310da871dd315ad3beac036e0b6e74c51361131f58ba7cd186d5b437d0c55a07abe61b01553a92c2d3eb01d5587f61d3f2ef9482f61e4d1efede76d4340d87b0fcc9d7421267f14a22cca6ff5bbb889c99df49f24dcc0a8d4c1f72607337949f75a74e81b35b38b4e5da4de598cebf9dab3c7129bdef825fd1c4b4f8468b8ac0810f14d4c07e9e965c0c6317000b1f5f1bbf5ca3c9771b33278dae93483ce9243794e62036dd1f5bd3102a889afc922e6e512bd235a70eb2809ded3005a07478aaecc17002dba479371de6bdd8332c2ccc073aab89e83af8b8c8e0c0b6cab14e1a33b9f69c85e3e9c22b1ac0de924570309273fa30e242f35d131d8e1f8c51d11d7b5e6b0baefffaaff96020620556faf460954223720d04fea71bd015cfb8bd144970791c9b82fdab2263513f03d4c26ad3e5dbb004bf5b63163e3204a9d0dd0a5d0284e4566be9258b96a5a0164e39bfdcc2b58f76d4112dc52d7812c58c9a47e73fef65a45bb898fba8d7fcb8ac1d266593e9b0c2052f46d2d3e2dfd6dc2fe1d656d28a3f04c01d003ad9656c5100b603f819f9ba32eda9dc1643c6cd983283534208d3a4447850abe58d22f971298dc0a5f8fcaf71e534ff4c7d70a783ee30c57032b86a4b9205f3000c61ffebe0c2cdcedd5b02ca80c3b1f5d301c482fce2f83a5cbe317b9ae0466105aa993188faaea171db0c5410e0b468d82b6d4d183b860f1787ab6cca3f567f2f29c179c1e538c4757f825369b411196ce827a6c0b094a29243ae57017ad2db6204609d5f2b4092296f55e27d55801d2c965003a50af84619f93e957365c3fb6518c9b18e070f8186316404", "0x3a65787472696e7369635f696e646578": "0x00000000", - "0x3a6772616e6470615f617574686f726974696573": "0x0110c8caee6f6eddc41c6cc55e554343392cbc13d2a8a57b97f6f85fc965bdd20ce801000000000000008270a62b61639ee56113834aecec01de6cda91413a5111b89f74d6585da34f5001000000000000004c669b04865e9acaf7b72bdfcb0099d70d9ec63c8c2d6b8cb0552815d7b50a0a0100000000000000c9a68a26e9aa37ba6334f1a20275e3be7d3a9d4aa988627eadac8ea0d0a2dfbf0100000000000000", + "0x3a6772616e6470615f617574686f726974696573": "0x0138c8caee6f6eddc41c6cc55e554343392cbc13d2a8a57b97f6f85fc965bdd20ce8010000000000000083f43ee3e4521b55de0fe830847fda88a6b017b87979af1a41b180c39da1e4b001000000000000005fafb6219eb8d463bec0370b2aab69f45fc780959fc2eddbc7703760aa34202201000000000000008270a62b61639ee56113834aecec01de6cda91413a5111b89f74d6585da34f500100000000000000622c382187c0b2c61ecfb17443294d11a9d2ab770ae6f1fb49184a43906d59fe01000000000000006e309dfa4c8de814cad140b8612a9e41bfba244f9ab1468e1b5d9b3cc1f5e56501000000000000000509f9caf32fda5584343c473b386c433acb99fd9400724b8cf3c618d840133f01000000000000004c669b04865e9acaf7b72bdfcb0099d70d9ec63c8c2d6b8cb0552815d7b50a0a0100000000000000e41426f7465c13c48335771c5450bf61c50a9cf28b9274f170c7421eea7974f10100000000000000ace46e899b90e75199549d8fa2ae7097e896ab3c845217e3155f99b6ffb888030100000000000000c9a68a26e9aa37ba6334f1a20275e3be7d3a9d4aa988627eadac8ea0d0a2dfbf01000000000000006e60f1e253735fb113c183fa603f591e4456435171f387c0849001b428b5ccb10100000000000000c8de3a01502422b59dfa601c9c3a04a98d2bfbd79dd0810d1d1250feab4241ee010000000000000064adb43a7628139f6c02100f6a5465dbd33422418426c572b12547c5a665008c0100000000000000", "0x3d9cad2baf702e20b136f4c8900cd8024e7b9012096b41c4eb3aaf947f6ea429": "0x0200", "0x3db7a24cfdc9de785974746c14a99df94e7b9012096b41c4eb3aaf947f6ea429": "0x0400", "0x3f1467a096bcd71a5b6a0c8155e208104e7b9012096b41c4eb3aaf947f6ea429": "0x0000", "0x3fba98689ebed1138735e0e7a5a790ab4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", "0x42b50b77ef717947e7043bb52127d6654e7b9012096b41c4eb3aaf947f6ea429": "0x0000", "0x47c9410b11325752265d54845357656f4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x4da2c41eaffa8e1a791c5d65beeefd1f028685274e698e781f7f2766cba0cc8300000000": "0x1003000000010000000000000002000000abc3f086f5ac20eaab792c75933b2e196307835a61a955be82aa63bc0ff9617a0600000010ea9400f05e7fb75a3f7a92febbf58e5a3060dd06132ed6d5d68a3d75ec452826ad90a2c3fa2c756f974628dd279adb87935f7ea509856276e3b86f759b22451c161d0af40e6efc165c17d0189bd2d770bdfa0a9b8393cb89113f473a2e948c682253ee3c02d89582602ca5b0570cfc01dc82cc8d1b9d2071eb5db6318749124b000000000000000000000000000000000000000100000000000000", + "0x4da2c41eaffa8e1a791c5d65beeefd1f028685274e698e781f7f2766cba0cc8300000000": "0x380a000000030000000400000002000000070000000b000000050000000c0000000000000009000000060000000d0000000100000008000000abc3f086f5ac20eaab792c75933b2e196307835a61a955be82aa63bc0ff9617a0600000038ea9400f05e7fb75a3f7a92febbf58e5a3060dd06132ed6d5d68a3d75ec452826ad90a2c3fa2c756f974628dd279adb87935f7ea509856276e3b86f759b22451c303094c583e253794c9db14803585baaa74472f4ecba846defefc8aecfb6214ac45a6d0878f808b1baaa85dcfb4e930ae06e3205bb38855527aee6f259e3327b2253ee3c02d89582602ca5b0570cfc01dc82cc8d1b9d2071eb5db6318749124b02683131f96baec9121383995904c49a02ce2c2451f8038291e5db2dce66663e0a988fb965b156a07debf072fd9d34a9c7c0fc0e0ff5bd63ef766afb76e2b32890032c39c968f486f77f8764301a8479206f063d49eeb9f6d499333e2a1be045161d0af40e6efc165c17d0189bd2d770bdfa0a9b8393cb89113f473a2e948c680ce84accce1ced0de223aa72f760f1b3d13ddfd267938cd63e25308378d320084e1a59090261a7e6bd82544df1eebd96dc87b4eb1211346645fa44d6b932960b441629077e228528f91ca7dc17051bb437408a5ae272d0950e58961846a8fc2ed0d052eca7d732d9f560ba970ca48f67387b899e76958ea6ed342a3a553ef0229e065eea4143325fbbd26967c26a228d51a3a8384062f7434973f15d1da2c010000000000000000000000000000000000000000100000000000000", "0x4da2c41eaffa8e1a791c5d65beeefd1f4e5747352ae927817a9171156fb3da7f00000000": "0x00", "0x4da2c41eaffa8e1a791c5d65beeefd1f4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", "0x4da2c41eaffa8e1a791c5d65beeefd1f5762b52ec4f696c1235b20491a567f8500000000": "0x00", @@ -92,43 +109,113 @@ "0x5f27b51b5ec208ee9cb25b55d8728243308ce9615de0775a82f8a94dc3d285a1": "0x01", "0x5f27b51b5ec208ee9cb25b55d87282434e7b9012096b41c4eb3aaf947f6ea429": "0x0000", "0x5f3e4907f716ac89b6347d15ececedca0b6a45321efae92aea15e0740ec7afe7": "0x00000000", - "0x5f3e4907f716ac89b6347d15ececedca138e71612491192d68deab7e6f563fe1": "0x04000000", + "0x5f3e4907f716ac89b6347d15ececedca138e71612491192d68deab7e6f563fe1": "0x0e000000", "0x5f3e4907f716ac89b6347d15ececedca28dccb559b95c40168a1b2696581b5a7": "0x00000000000000000000000000000000", + "0x5f3e4907f716ac89b6347d15ececedca3ed14b45ed20d054f05e37e2542cfe700afd9ad680e7563894c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b10": "0x94c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b10", "0x5f3e4907f716ac89b6347d15ececedca3ed14b45ed20d054f05e37e2542cfe700e8cb253c2fa33f382c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c": "0x82c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c", + "0x5f3e4907f716ac89b6347d15ececedca3ed14b45ed20d054f05e37e2542cfe701887a9d70c3dff6e6ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a2259627": "0x6ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a2259627", + "0x5f3e4907f716ac89b6347d15ececedca3ed14b45ed20d054f05e37e2542cfe70198703ff0791c2de1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c413": "0x1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c413", + "0x5f3e4907f716ac89b6347d15ececedca3ed14b45ed20d054f05e37e2542cfe70260868bcb77241070efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f76108": "0x0efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f76108", "0x5f3e4907f716ac89b6347d15ececedca3ed14b45ed20d054f05e37e2542cfe70572aae990801cce1043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d": "0x043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d", + "0x5f3e4907f716ac89b6347d15ececedca3ed14b45ed20d054f05e37e2542cfe7065903e26e594bcd6d41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d": "0xd41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d", + "0x5f3e4907f716ac89b6347d15ececedca3ed14b45ed20d054f05e37e2542cfe70a8a26ecf38bdcfc668728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c69": "0x68728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c69", + "0x5f3e4907f716ac89b6347d15ececedca3ed14b45ed20d054f05e37e2542cfe70ab8d3e1fa99ea7e2d0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327c": "0xd0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327c", "0x5f3e4907f716ac89b6347d15ececedca3ed14b45ed20d054f05e37e2542cfe70d12736684524574c32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e1152": "0x32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e1152", + "0x5f3e4907f716ac89b6347d15ececedca3ed14b45ed20d054f05e37e2542cfe70d30ebbc69dfd05038eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964": "0x8eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964", "0x5f3e4907f716ac89b6347d15ececedca3ed14b45ed20d054f05e37e2542cfe70deca1f47c95ad9e99492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f": "0x9492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f", + "0x5f3e4907f716ac89b6347d15ececedca3ed14b45ed20d054f05e37e2542cfe70e7e316712ac574569037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af74": "0x9037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af74", + "0x5f3e4907f716ac89b6347d15ececedca3ed14b45ed20d054f05e37e2542cfe70eec11b5fca7cddef5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c": "0x5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c", + "0x5f3e4907f716ac89b6347d15ececedca422adb579f1dbf4f3886c5cfa3bb8cc402d496d20c019d22397accfc42b7635d94c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b10": "0x94c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b100f0080c6a47e8d030f0080c6a47e8d030000", "0x5f3e4907f716ac89b6347d15ececedca422adb579f1dbf4f3886c5cfa3bb8cc40ffdb9747f7a8bfa200ea2291eea6bdf9492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f": "0x9492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f0f0080c6a47e8d030f0080c6a47e8d030000", + "0x5f3e4907f716ac89b6347d15ececedca422adb579f1dbf4f3886c5cfa3bb8cc411fcf3e922de10898cb04273301735e65270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c": "0x5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c0f0080c6a47e8d030f0080c6a47e8d030000", + "0x5f3e4907f716ac89b6347d15ececedca422adb579f1dbf4f3886c5cfa3bb8cc415fbc5d9b44885a2dce0fbaa3834ba211e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c413": "0x1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c4130f0080c6a47e8d030f0080c6a47e8d030000", + "0x5f3e4907f716ac89b6347d15ececedca422adb579f1dbf4f3886c5cfa3bb8cc4279effc2672354478fb5e3f7e65726b668728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c69": "0x68728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c690f0080c6a47e8d030f0080c6a47e8d030000", + "0x5f3e4907f716ac89b6347d15ececedca422adb579f1dbf4f3886c5cfa3bb8cc42ffe7c0dd7d3d8d8485c403a33fb7adb6ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a2259627": "0x6ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a22596270f0080c6a47e8d030f0080c6a47e8d030000", + "0x5f3e4907f716ac89b6347d15ececedca422adb579f1dbf4f3886c5cfa3bb8cc4350ea875b4c0459b3527d475e9825c99d41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d": "0xd41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d0f0080c6a47e8d030f0080c6a47e8d030000", "0x5f3e4907f716ac89b6347d15ececedca422adb579f1dbf4f3886c5cfa3bb8cc44d176c4abc6d2410c43423c2714b909c32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e1152": "0x32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e11520f0080c6a47e8d030f0080c6a47e8d030000", + "0x5f3e4907f716ac89b6347d15ececedca422adb579f1dbf4f3886c5cfa3bb8cc4585bd5ccc1af6cf60c19d791bb091b750efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f76108": "0x0efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f761080f0080c6a47e8d030f0080c6a47e8d030000", "0x5f3e4907f716ac89b6347d15ececedca422adb579f1dbf4f3886c5cfa3bb8cc465bb58c29c9825c1f6727fe8c41650ac82c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c": "0x82c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c0f0080c6a47e8d030f0080c6a47e8d030000", + "0x5f3e4907f716ac89b6347d15ececedca422adb579f1dbf4f3886c5cfa3bb8cc46deaa967a94fa09152be01a253511479d0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327c": "0xd0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327c0f0080c6a47e8d030f0080c6a47e8d030000", "0x5f3e4907f716ac89b6347d15ececedca422adb579f1dbf4f3886c5cfa3bb8cc4829f3f4d6d7c991993e0c044ae97410b043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d": "0x043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d0f0080c6a47e8d030f0080c6a47e8d030000", + "0x5f3e4907f716ac89b6347d15ececedca422adb579f1dbf4f3886c5cfa3bb8cc4ba2db252d1b8c64ec51b04d0f50d7d2b9037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af74": "0x9037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af740f0080c6a47e8d030f0080c6a47e8d030000", + "0x5f3e4907f716ac89b6347d15ececedca422adb579f1dbf4f3886c5cfa3bb8cc4dfc40f350cc4563ad9ddff5ad92944278eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964": "0x8eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b8689640f0080c6a47e8d030f0080c6a47e8d030000", + "0x5f3e4907f716ac89b6347d15ececedca42982b9d6c7acc99faa9094c912372c2b4def25cfda6ef3a000000000afd9ad680e7563894c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b10": "0x0f0080c6a47e8d030f0080c6a47e8d0300", "0x5f3e4907f716ac89b6347d15ececedca42982b9d6c7acc99faa9094c912372c2b4def25cfda6ef3a000000000e8cb253c2fa33f382c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c": "0x0f0080c6a47e8d030f0080c6a47e8d0300", + "0x5f3e4907f716ac89b6347d15ececedca42982b9d6c7acc99faa9094c912372c2b4def25cfda6ef3a000000001887a9d70c3dff6e6ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a2259627": "0x0f0080c6a47e8d030f0080c6a47e8d0300", + "0x5f3e4907f716ac89b6347d15ececedca42982b9d6c7acc99faa9094c912372c2b4def25cfda6ef3a00000000198703ff0791c2de1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c413": "0x0f0080c6a47e8d030f0080c6a47e8d0300", + "0x5f3e4907f716ac89b6347d15ececedca42982b9d6c7acc99faa9094c912372c2b4def25cfda6ef3a00000000260868bcb77241070efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f76108": "0x0f0080c6a47e8d030f0080c6a47e8d0300", "0x5f3e4907f716ac89b6347d15ececedca42982b9d6c7acc99faa9094c912372c2b4def25cfda6ef3a00000000572aae990801cce1043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d": "0x0f0080c6a47e8d030f0080c6a47e8d0300", + "0x5f3e4907f716ac89b6347d15ececedca42982b9d6c7acc99faa9094c912372c2b4def25cfda6ef3a0000000065903e26e594bcd6d41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d": "0x0f0080c6a47e8d030f0080c6a47e8d0300", + "0x5f3e4907f716ac89b6347d15ececedca42982b9d6c7acc99faa9094c912372c2b4def25cfda6ef3a00000000a8a26ecf38bdcfc668728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c69": "0x0f0080c6a47e8d030f0080c6a47e8d0300", + "0x5f3e4907f716ac89b6347d15ececedca42982b9d6c7acc99faa9094c912372c2b4def25cfda6ef3a00000000ab8d3e1fa99ea7e2d0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327c": "0x0f0080c6a47e8d030f0080c6a47e8d0300", "0x5f3e4907f716ac89b6347d15ececedca42982b9d6c7acc99faa9094c912372c2b4def25cfda6ef3a00000000d12736684524574c32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e1152": "0x0f0080c6a47e8d030f0080c6a47e8d0300", + "0x5f3e4907f716ac89b6347d15ececedca42982b9d6c7acc99faa9094c912372c2b4def25cfda6ef3a00000000d30ebbc69dfd05038eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964": "0x0f0080c6a47e8d030f0080c6a47e8d0300", "0x5f3e4907f716ac89b6347d15ececedca42982b9d6c7acc99faa9094c912372c2b4def25cfda6ef3a00000000deca1f47c95ad9e99492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f": "0x0f0080c6a47e8d030f0080c6a47e8d0300", + "0x5f3e4907f716ac89b6347d15ececedca42982b9d6c7acc99faa9094c912372c2b4def25cfda6ef3a00000000e7e316712ac574569037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af74": "0x0f0080c6a47e8d030f0080c6a47e8d0300", + "0x5f3e4907f716ac89b6347d15ececedca42982b9d6c7acc99faa9094c912372c2b4def25cfda6ef3a00000000eec11b5fca7cddef5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c": "0x0f0080c6a47e8d030f0080c6a47e8d0300", "0x5f3e4907f716ac89b6347d15ececedca487df464e44a534ba6b0cbb32407b587": "0x0000000000", "0x5f3e4907f716ac89b6347d15ececedca4e7b9012096b41c4eb3aaf947f6ea429": "0x0d00", - "0x5f3e4907f716ac89b6347d15ececedca5579297f4dfb9609e7e4c2ebab9ce40a": "0x10043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d82c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e11529492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f", + "0x5f3e4907f716ac89b6347d15ececedca5579297f4dfb9609e7e4c2ebab9ce40a": "0x3894c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b1082c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c6ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a22596271e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c4130efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f76108043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170dd41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d68728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c69d0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327c32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e11528eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b8689649492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f9037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af745270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c", "0x5f3e4907f716ac89b6347d15ececedca666fdcbb473985b3ac933d13f4acff8d": "0x0080c6a47e8d03000000000000000000", + "0x5f3e4907f716ac89b6347d15ececedca682db92dde20a10d96d00ff0e9e221c0b4def25cfda6ef3a000000000afd9ad680e7563894c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b10": "0x0000", "0x5f3e4907f716ac89b6347d15ececedca682db92dde20a10d96d00ff0e9e221c0b4def25cfda6ef3a000000000e8cb253c2fa33f382c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c": "0x0000", + "0x5f3e4907f716ac89b6347d15ececedca682db92dde20a10d96d00ff0e9e221c0b4def25cfda6ef3a000000001887a9d70c3dff6e6ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a2259627": "0x0000", + "0x5f3e4907f716ac89b6347d15ececedca682db92dde20a10d96d00ff0e9e221c0b4def25cfda6ef3a00000000198703ff0791c2de1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c413": "0x0000", + "0x5f3e4907f716ac89b6347d15ececedca682db92dde20a10d96d00ff0e9e221c0b4def25cfda6ef3a00000000260868bcb77241070efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f76108": "0x0000", "0x5f3e4907f716ac89b6347d15ececedca682db92dde20a10d96d00ff0e9e221c0b4def25cfda6ef3a00000000572aae990801cce1043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d": "0x0000", + "0x5f3e4907f716ac89b6347d15ececedca682db92dde20a10d96d00ff0e9e221c0b4def25cfda6ef3a0000000065903e26e594bcd6d41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d": "0x0000", + "0x5f3e4907f716ac89b6347d15ececedca682db92dde20a10d96d00ff0e9e221c0b4def25cfda6ef3a00000000a8a26ecf38bdcfc668728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c69": "0x0000", + "0x5f3e4907f716ac89b6347d15ececedca682db92dde20a10d96d00ff0e9e221c0b4def25cfda6ef3a00000000ab8d3e1fa99ea7e2d0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327c": "0x0000", "0x5f3e4907f716ac89b6347d15ececedca682db92dde20a10d96d00ff0e9e221c0b4def25cfda6ef3a00000000d12736684524574c32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e1152": "0x0000", + "0x5f3e4907f716ac89b6347d15ececedca682db92dde20a10d96d00ff0e9e221c0b4def25cfda6ef3a00000000d30ebbc69dfd05038eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964": "0x0000", "0x5f3e4907f716ac89b6347d15ececedca682db92dde20a10d96d00ff0e9e221c0b4def25cfda6ef3a00000000deca1f47c95ad9e99492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f": "0x0000", - "0x5f3e4907f716ac89b6347d15ececedca6ddc7809c6da9bb6093ee22e0fda4ba8": "0x04000000", + "0x5f3e4907f716ac89b6347d15ececedca682db92dde20a10d96d00ff0e9e221c0b4def25cfda6ef3a00000000e7e316712ac574569037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af74": "0x0000", + "0x5f3e4907f716ac89b6347d15ececedca682db92dde20a10d96d00ff0e9e221c0b4def25cfda6ef3a00000000eec11b5fca7cddef5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c": "0x0000", + "0x5f3e4907f716ac89b6347d15ececedca6ddc7809c6da9bb6093ee22e0fda4ba8": "0x0e000000", + "0x5f3e4907f716ac89b6347d15ececedca88dcde934c658227ee1dfafcd6e169030afd9ad680e7563894c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b10": "0x0000", "0x5f3e4907f716ac89b6347d15ececedca88dcde934c658227ee1dfafcd6e169030e8cb253c2fa33f382c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c": "0x0000", + "0x5f3e4907f716ac89b6347d15ececedca88dcde934c658227ee1dfafcd6e169031887a9d70c3dff6e6ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a2259627": "0x0000", + "0x5f3e4907f716ac89b6347d15ececedca88dcde934c658227ee1dfafcd6e16903198703ff0791c2de1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c413": "0x0000", + "0x5f3e4907f716ac89b6347d15ececedca88dcde934c658227ee1dfafcd6e16903260868bcb77241070efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f76108": "0x0000", "0x5f3e4907f716ac89b6347d15ececedca88dcde934c658227ee1dfafcd6e16903572aae990801cce1043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d": "0x0000", + "0x5f3e4907f716ac89b6347d15ececedca88dcde934c658227ee1dfafcd6e1690365903e26e594bcd6d41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d": "0x0000", + "0x5f3e4907f716ac89b6347d15ececedca88dcde934c658227ee1dfafcd6e16903a8a26ecf38bdcfc668728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c69": "0x0000", + "0x5f3e4907f716ac89b6347d15ececedca88dcde934c658227ee1dfafcd6e16903ab8d3e1fa99ea7e2d0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327c": "0x0000", "0x5f3e4907f716ac89b6347d15ececedca88dcde934c658227ee1dfafcd6e16903d12736684524574c32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e1152": "0x0000", + "0x5f3e4907f716ac89b6347d15ececedca88dcde934c658227ee1dfafcd6e16903d30ebbc69dfd05038eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964": "0x0000", "0x5f3e4907f716ac89b6347d15ececedca88dcde934c658227ee1dfafcd6e16903deca1f47c95ad9e99492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f": "0x0000", + "0x5f3e4907f716ac89b6347d15ececedca88dcde934c658227ee1dfafcd6e16903e7e316712ac574569037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af74": "0x0000", + "0x5f3e4907f716ac89b6347d15ececedca88dcde934c658227ee1dfafcd6e16903eec11b5fca7cddef5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c": "0x0000", + "0x5f3e4907f716ac89b6347d15ececedca8bde0a0ea8864605e3b68ed9cb2da01bb4def25cfda6ef3a000000000afd9ad680e7563894c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b10": "0x0f0080c6a47e8d030f0080c6a47e8d0300", "0x5f3e4907f716ac89b6347d15ececedca8bde0a0ea8864605e3b68ed9cb2da01bb4def25cfda6ef3a000000000e8cb253c2fa33f382c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c": "0x0f0080c6a47e8d030f0080c6a47e8d0300", + "0x5f3e4907f716ac89b6347d15ececedca8bde0a0ea8864605e3b68ed9cb2da01bb4def25cfda6ef3a000000001887a9d70c3dff6e6ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a2259627": "0x0f0080c6a47e8d030f0080c6a47e8d0300", + "0x5f3e4907f716ac89b6347d15ececedca8bde0a0ea8864605e3b68ed9cb2da01bb4def25cfda6ef3a00000000198703ff0791c2de1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c413": "0x0f0080c6a47e8d030f0080c6a47e8d0300", + "0x5f3e4907f716ac89b6347d15ececedca8bde0a0ea8864605e3b68ed9cb2da01bb4def25cfda6ef3a00000000260868bcb77241070efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f76108": "0x0f0080c6a47e8d030f0080c6a47e8d0300", "0x5f3e4907f716ac89b6347d15ececedca8bde0a0ea8864605e3b68ed9cb2da01bb4def25cfda6ef3a00000000572aae990801cce1043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d": "0x0f0080c6a47e8d030f0080c6a47e8d0300", + "0x5f3e4907f716ac89b6347d15ececedca8bde0a0ea8864605e3b68ed9cb2da01bb4def25cfda6ef3a0000000065903e26e594bcd6d41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d": "0x0f0080c6a47e8d030f0080c6a47e8d0300", + "0x5f3e4907f716ac89b6347d15ececedca8bde0a0ea8864605e3b68ed9cb2da01bb4def25cfda6ef3a00000000a8a26ecf38bdcfc668728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c69": "0x0f0080c6a47e8d030f0080c6a47e8d0300", + "0x5f3e4907f716ac89b6347d15ececedca8bde0a0ea8864605e3b68ed9cb2da01bb4def25cfda6ef3a00000000ab8d3e1fa99ea7e2d0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327c": "0x0f0080c6a47e8d030f0080c6a47e8d0300", "0x5f3e4907f716ac89b6347d15ececedca8bde0a0ea8864605e3b68ed9cb2da01bb4def25cfda6ef3a00000000d12736684524574c32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e1152": "0x0f0080c6a47e8d030f0080c6a47e8d0300", + "0x5f3e4907f716ac89b6347d15ececedca8bde0a0ea8864605e3b68ed9cb2da01bb4def25cfda6ef3a00000000d30ebbc69dfd05038eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964": "0x0f0080c6a47e8d030f0080c6a47e8d0300", "0x5f3e4907f716ac89b6347d15ececedca8bde0a0ea8864605e3b68ed9cb2da01bb4def25cfda6ef3a00000000deca1f47c95ad9e99492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f": "0x0f0080c6a47e8d030f0080c6a47e8d0300", + "0x5f3e4907f716ac89b6347d15ececedca8bde0a0ea8864605e3b68ed9cb2da01bb4def25cfda6ef3a00000000e7e316712ac574569037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af74": "0x0f0080c6a47e8d030f0080c6a47e8d0300", + "0x5f3e4907f716ac89b6347d15ececedca8bde0a0ea8864605e3b68ed9cb2da01bb4def25cfda6ef3a00000000eec11b5fca7cddef5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c": "0x0f0080c6a47e8d030f0080c6a47e8d0300", + "0x5f3e4907f716ac89b6347d15ececedca9220e172bed316605f73f1ff7b4ade980afd9ad680e7563894c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b10": "0x00", "0x5f3e4907f716ac89b6347d15ececedca9220e172bed316605f73f1ff7b4ade980e8cb253c2fa33f382c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c": "0x00", + "0x5f3e4907f716ac89b6347d15ececedca9220e172bed316605f73f1ff7b4ade981887a9d70c3dff6e6ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a2259627": "0x00", + "0x5f3e4907f716ac89b6347d15ececedca9220e172bed316605f73f1ff7b4ade98198703ff0791c2de1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c413": "0x00", + "0x5f3e4907f716ac89b6347d15ececedca9220e172bed316605f73f1ff7b4ade98260868bcb77241070efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f76108": "0x00", "0x5f3e4907f716ac89b6347d15ececedca9220e172bed316605f73f1ff7b4ade98572aae990801cce1043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d": "0x00", + "0x5f3e4907f716ac89b6347d15ececedca9220e172bed316605f73f1ff7b4ade9865903e26e594bcd6d41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d": "0x00", + "0x5f3e4907f716ac89b6347d15ececedca9220e172bed316605f73f1ff7b4ade98a8a26ecf38bdcfc668728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c69": "0x00", + "0x5f3e4907f716ac89b6347d15ececedca9220e172bed316605f73f1ff7b4ade98ab8d3e1fa99ea7e2d0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327c": "0x00", "0x5f3e4907f716ac89b6347d15ececedca9220e172bed316605f73f1ff7b4ade98d12736684524574c32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e1152": "0x00", + "0x5f3e4907f716ac89b6347d15ececedca9220e172bed316605f73f1ff7b4ade98d30ebbc69dfd05038eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964": "0x00", "0x5f3e4907f716ac89b6347d15ececedca9220e172bed316605f73f1ff7b4ade98deca1f47c95ad9e99492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f": "0x00", + "0x5f3e4907f716ac89b6347d15ececedca9220e172bed316605f73f1ff7b4ade98e7e316712ac574569037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af74": "0x00", + "0x5f3e4907f716ac89b6347d15ececedca9220e172bed316605f73f1ff7b4ade98eec11b5fca7cddef5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c": "0x00", "0x5f3e4907f716ac89b6347d15ececedca98c2640cda6c0d801194a8a61c699224": "0xc8000000", - "0x5f3e4907f716ac89b6347d15ececedcaa141c4fe67c2d11f4a10c6aca7a79a04b4def25cfda6ef3a00000000": "0x00001a93fa350e000000000000000000", + "0x5f3e4907f716ac89b6347d15ececedcaa141c4fe67c2d11f4a10c6aca7a79a04b4def25cfda6ef3a00000000": "0x0000db02edbc31000000000000000000", "0x5f3e4907f716ac89b6347d15ececedcaad811cd65a470ddc5f1d628ff0550982b4def25cfda6ef3a00000000": "0x00000000", "0x5f3e4907f716ac89b6347d15ececedcab49a2738eeb30896aacb8b3fb46471bd": "0x02000000", "0x5f3e4907f716ac89b6347d15ececedcac0d39ff577af2cc6b67ac3641fa9c4e7": "0x01000000", @@ -147,18 +234,29 @@ "0x6ac983d82528bf1595ab26438ae5b2cf4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", "0x7474449cca95dc5d0c00e71735a6d17d4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", "0x74dd702da46f77d7acf77f5a48d4af7d4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x74dd702da46f77d7acf77f5a48d4af7d62556a85fcb7c61b2c6c750924846b150e8cb253c2fa33f382c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c": "0x82c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c01043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d0132eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e115261c091f7b7cb03000080c6a47e8d0300", - "0x74dd702da46f77d7acf77f5a48d4af7d62556a85fcb7c61b2c6c750924846b15572aae990801cce1043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d": "0x043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d000182c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c61c091f7b7cb03000080c6a47e8d0300", - "0x74dd702da46f77d7acf77f5a48d4af7d62556a85fcb7c61b2c6c750924846b15d12736684524574c32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e1152": "0x32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e11520182c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c019492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f61c091f7b7cb03000080c6a47e8d0300", - "0x74dd702da46f77d7acf77f5a48d4af7d62556a85fcb7c61b2c6c750924846b15deca1f47c95ad9e99492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f": "0x9492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f0132eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e11520061c091f7b7cb03000080c6a47e8d0300", - "0x74dd702da46f77d7acf77f5a48d4af7d7a6dc62e324093ba1331bf49fdb2f24a": "0x04000000", - "0x74dd702da46f77d7acf77f5a48d4af7de5c03730c8f59f00941607850b6633d80863c87cd8a129fa61c091f7b7cb0300": "0x01043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d019492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f", + "0x74dd702da46f77d7acf77f5a48d4af7d62556a85fcb7c61b2c6c750924846b150afd9ad680e7563894c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b10": "0x94c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b10000182c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c61c091f7b7cb03000080c6a47e8d0300", + "0x74dd702da46f77d7acf77f5a48d4af7d62556a85fcb7c61b2c6c750924846b150e8cb253c2fa33f382c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c": "0x82c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c0194c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b10016ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a225962761c091f7b7cb03000080c6a47e8d0300", + "0x74dd702da46f77d7acf77f5a48d4af7d62556a85fcb7c61b2c6c750924846b151887a9d70c3dff6e6ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a2259627": "0x6ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a22596270182c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c011e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c41361c091f7b7cb03000080c6a47e8d0300", + "0x74dd702da46f77d7acf77f5a48d4af7d62556a85fcb7c61b2c6c750924846b15198703ff0791c2de1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c413": "0x1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c413016ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a2259627010efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f7610861c091f7b7cb03000080c6a47e8d0300", + "0x74dd702da46f77d7acf77f5a48d4af7d62556a85fcb7c61b2c6c750924846b15260868bcb77241070efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f76108": "0x0efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f76108011e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c41301043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d61c091f7b7cb03000080c6a47e8d0300", + "0x74dd702da46f77d7acf77f5a48d4af7d62556a85fcb7c61b2c6c750924846b15572aae990801cce1043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d": "0x043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d010efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f7610801d41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d61c091f7b7cb03000080c6a47e8d0300", + "0x74dd702da46f77d7acf77f5a48d4af7d62556a85fcb7c61b2c6c750924846b1565903e26e594bcd6d41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d": "0xd41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d01043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d0168728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c6961c091f7b7cb03000080c6a47e8d0300", + "0x74dd702da46f77d7acf77f5a48d4af7d62556a85fcb7c61b2c6c750924846b15a8a26ecf38bdcfc668728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c69": "0x68728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c6901d41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d01d0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327c61c091f7b7cb03000080c6a47e8d0300", + "0x74dd702da46f77d7acf77f5a48d4af7d62556a85fcb7c61b2c6c750924846b15ab8d3e1fa99ea7e2d0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327c": "0xd0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327c0168728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c690132eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e115261c091f7b7cb03000080c6a47e8d0300", + "0x74dd702da46f77d7acf77f5a48d4af7d62556a85fcb7c61b2c6c750924846b15d12736684524574c32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e1152": "0x32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e115201d0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327c018eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b86896461c091f7b7cb03000080c6a47e8d0300", + "0x74dd702da46f77d7acf77f5a48d4af7d62556a85fcb7c61b2c6c750924846b15d30ebbc69dfd05038eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964": "0x8eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b8689640132eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e1152019492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f61c091f7b7cb03000080c6a47e8d0300", + "0x74dd702da46f77d7acf77f5a48d4af7d62556a85fcb7c61b2c6c750924846b15deca1f47c95ad9e99492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f": "0x9492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f018eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964019037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af7461c091f7b7cb03000080c6a47e8d0300", + "0x74dd702da46f77d7acf77f5a48d4af7d62556a85fcb7c61b2c6c750924846b15e7e316712ac574569037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af74": "0x9037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af74019492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f015270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c61c091f7b7cb03000080c6a47e8d0300", + "0x74dd702da46f77d7acf77f5a48d4af7d62556a85fcb7c61b2c6c750924846b15eec11b5fca7cddef5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c": "0x5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c019037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af740061c091f7b7cb03000080c6a47e8d0300", + "0x74dd702da46f77d7acf77f5a48d4af7d7a6dc62e324093ba1331bf49fdb2f24a": "0x0e000000", + "0x74dd702da46f77d7acf77f5a48d4af7de5c03730c8f59f00941607850b6633d80863c87cd8a129fa61c091f7b7cb0300": "0x0194c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b10015270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c", "0x7a6d38deaa01cb6e76ee69889f1696272be9a4e88368a2188d2b9100a9f3cd43": "0x00000000000000000000000000000000", "0x7a6d38deaa01cb6e76ee69889f16962730256ea2c545a3e5e3744665ffb2ed28": "0x00020000", "0x7a6d38deaa01cb6e76ee69889f1696273f0d64e1907361c689834a9c1cb0fbe0": "0x20000000", "0x7a6d38deaa01cb6e76ee69889f16962749d67997de33812a1cc37310f765b82e": "0x00000000000000000000000000000000", - "0x7a6d38deaa01cb6e76ee69889f1696274e7b9012096b41c4eb3aaf947f6ea429": "0x0500", + "0x7a6d38deaa01cb6e76ee69889f1696274e7b9012096b41c4eb3aaf947f6ea429": "0x0700", "0x7a6d38deaa01cb6e76ee69889f169627ba93302f3b868c50785e6ade45c6a1d8": "0x10000000", + "0x8671567f6bbc0021f6f23105f33002a84e7b9012096b41c4eb3aaf947f6ea429": "0x0000", "0x89d139e01a5eb2256f222e5fc5dbe6b34e7b9012096b41c4eb3aaf947f6ea429": "0x0000", "0x94eadf0156a8ad5156507773d0471e4a16973e1142f5bd30d9464076794007db": "0x00", "0x94eadf0156a8ad5156507773d0471e4a4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", @@ -168,52 +266,147 @@ "0x9c5d795d0297be56027a4b2464e33397f43d6436dec51f09c3b71287a8fc9d48": "0x00000000000000000000000000000000", "0xa0eb495036d368196a2b6c51d9d788814e7b9012096b41c4eb3aaf947f6ea429": "0x0000", "0xa37f719efab16103103a0c8c2c784ce14e7b9012096b41c4eb3aaf947f6ea429": "0x0400", - "0xb341e3a63e58a188839b242d17f8c9f82586833f834350b4d435d5fd269ecc8b": "0x1003000000010000000000000002000000", + "0xa8c65209d47ee80f56b0011e8fd91f504e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xb341e3a63e58a188839b242d17f8c9f82586833f834350b4d435d5fd269ecc8b": "0x380a000000030000000400000002000000070000000b000000050000000c0000000000000009000000060000000d0000000100000008000000", "0xb341e3a63e58a188839b242d17f8c9f84e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0xb341e3a63e58a188839b242d17f8c9f87a50c904b368210021127f9238883a6e": "0x10ea9400f05e7fb75a3f7a92febbf58e5a3060dd06132ed6d5d68a3d75ec452826ad90a2c3fa2c756f974628dd279adb87935f7ea509856276e3b86f759b22451c161d0af40e6efc165c17d0189bd2d770bdfa0a9b8393cb89113f473a2e948c682253ee3c02d89582602ca5b0570cfc01dc82cc8d1b9d2071eb5db6318749124b", + "0xb341e3a63e58a188839b242d17f8c9f87a50c904b368210021127f9238883a6e": "0x38ea9400f05e7fb75a3f7a92febbf58e5a3060dd06132ed6d5d68a3d75ec452826ad90a2c3fa2c756f974628dd279adb87935f7ea509856276e3b86f759b22451c303094c583e253794c9db14803585baaa74472f4ecba846defefc8aecfb6214ac45a6d0878f808b1baaa85dcfb4e930ae06e3205bb38855527aee6f259e3327b2253ee3c02d89582602ca5b0570cfc01dc82cc8d1b9d2071eb5db6318749124b02683131f96baec9121383995904c49a02ce2c2451f8038291e5db2dce66663e0a988fb965b156a07debf072fd9d34a9c7c0fc0e0ff5bd63ef766afb76e2b32890032c39c968f486f77f8764301a8479206f063d49eeb9f6d499333e2a1be045161d0af40e6efc165c17d0189bd2d770bdfa0a9b8393cb89113f473a2e948c680ce84accce1ced0de223aa72f760f1b3d13ddfd267938cd63e25308378d320084e1a59090261a7e6bd82544df1eebd96dc87b4eb1211346645fa44d6b932960b441629077e228528f91ca7dc17051bb437408a5ae272d0950e58961846a8fc2ed0d052eca7d732d9f560ba970ca48f67387b899e76958ea6ed342a3a553ef0229e065eea4143325fbbd26967c26a228d51a3a8384062f7434973f15d1da2c010", "0xb341e3a63e58a188839b242d17f8c9f89d1fb17def62216d598940d64654f69e": "0x0000000000", "0xb341e3a63e58a188839b242d17f8c9f8b5cab3380174032968897a4c3ce57c0a": "0x00000000", "0xb8753e9383841da95f7b8871e5de32694e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xc2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc602d496d20c019d22397accfc42b7635d94c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b10": "0x047374616b696e67200080c6a47e8d0300000000000000000002", "0xc2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc60ffdb9747f7a8bfa200ea2291eea6bdf9492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f": "0x047374616b696e67200080c6a47e8d0300000000000000000002", + "0xc2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc611fcf3e922de10898cb04273301735e65270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c": "0x047374616b696e67200080c6a47e8d0300000000000000000002", + "0xc2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc615fbc5d9b44885a2dce0fbaa3834ba211e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c413": "0x047374616b696e67200080c6a47e8d0300000000000000000002", + "0xc2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc6279effc2672354478fb5e3f7e65726b668728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c69": "0x047374616b696e67200080c6a47e8d0300000000000000000002", + "0xc2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc62ffe7c0dd7d3d8d8485c403a33fb7adb6ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a2259627": "0x047374616b696e67200080c6a47e8d0300000000000000000002", + "0xc2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc6350ea875b4c0459b3527d475e9825c99d41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d": "0x047374616b696e67200080c6a47e8d0300000000000000000002", "0xc2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc64d176c4abc6d2410c43423c2714b909c32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e1152": "0x047374616b696e67200080c6a47e8d0300000000000000000002", + "0xc2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc6585bd5ccc1af6cf60c19d791bb091b750efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f76108": "0x047374616b696e67200080c6a47e8d0300000000000000000002", "0xc2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc665bb58c29c9825c1f6727fe8c41650ac82c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c": "0x047374616b696e67200080c6a47e8d0300000000000000000002", + "0xc2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc66deaa967a94fa09152be01a253511479d0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327c": "0x047374616b696e67200080c6a47e8d0300000000000000000002", "0xc2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc6829f3f4d6d7c991993e0c044ae97410b043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d": "0x047374616b696e67200080c6a47e8d0300000000000000000002", + "0xc2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc6ba2db252d1b8c64ec51b04d0f50d7d2b9037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af74": "0x047374616b696e67200080c6a47e8d0300000000000000000002", + "0xc2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc6dfc40f350cc4563ad9ddff5ad92944278eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964": "0x047374616b696e67200080c6a47e8d0300000000000000000002", "0xc2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", - "0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80": "0x00e473ba7fd26e0e0000000000000000", + "0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80": "0x00e4be87ea9ef50f0000000000000000", "0xca32a41f4b3ed515863dc0a38697f84e4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", "0xcd710b30bd2eab0352ddcc26417aa1944e7b9012096b41c4eb3aaf947f6ea429": "0x0000", "0xcd710b30bd2eab0352ddcc26417aa1949f4993f016e2d2f8e5f43be7bb259486": "0x00", - "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb30e8cb253c2fa33f382c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c": "0x4c669b04865e9acaf7b72bdfcb0099d70d9ec63c8c2d6b8cb0552815d7b50a0afacb2f987caac6c1290a9784b1efdba78343d39aed805addb12945efbe444000ca3c2703db1633a27eff681d979967988c3a6752c669fd41f1abde10f3b054462253ee3c02d89582602ca5b0570cfc01dc82cc8d1b9d2071eb5db6318749124bf0e6c42698fffc28f9fc769fddcdf165af54c171cde43690cc8f73c853de1f0426e2fc857945d01520797a75388c58e710c9fefedd28387af70880f1682be41e", - "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3572aae990801cce1043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d": "0xc8caee6f6eddc41c6cc55e554343392cbc13d2a8a57b97f6f85fc965bdd20ce8b07d600e3487e2712dcc3879c7b17c9b29cd2243b45f0d9343c591b89cf82a650edf2a41cb81178704560b02c35f5e01a5a97a568ebc10c025ade18b6ab2fa1d161d0af40e6efc165c17d0189bd2d770bdfa0a9b8393cb89113f473a2e948c68def964eed9a73f8a6610f1a0373378dca6f277eb7787869ed5841893105ad930f89c97bf5b2c07c05c84eebce4ffc7b28766946c03741fd1a71fdae0942e8768", - "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3d12736684524574c32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e1152": "0x8270a62b61639ee56113834aecec01de6cda91413a5111b89f74d6585da34f5058108e1651614afc6a535c426fc013945e93533faa33819fe4e69423fe32330274bd654c470ed9b94972c1f997593fab7bdd4d6b85e3cf49401265668142584ead90a2c3fa2c756f974628dd279adb87935f7ea509856276e3b86f759b22451cc083b0d0bd7d6ffd14562b4c9e28738b087ccc32262170c633c18359ff84877992cb05c48fc643f057626c669604675c5ad5a836266f260ae7030c6fdc17a543", - "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3deca1f47c95ad9e99492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f": "0xc9a68a26e9aa37ba6334f1a20275e3be7d3a9d4aa988627eadac8ea0d0a2dfbfae240842b74e5dd778972e451558134f434c7a1d8a52bc70519f38054e24553306bd8fd81e50cda2bd67bf6893d921d1aae5cb08409ae43e0bff4d54e1830e58ea9400f05e7fb75a3f7a92febbf58e5a3060dd06132ed6d5d68a3d75ec452826bed3b452f869d187be58a4ba98588611084283810728fa75981e792beaec4151763d070989ead31f265b40cc7a0cd29d47799b766d6a7f084e44c82baedfc01e", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb30afd9ad680e7563894c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b10": "0x6e60f1e253735fb113c183fa603f591e4456435171f387c0849001b428b5ccb118bd0f67d77f04f1a92400421813d8927fad109b40a8689254a5f0c8b346857cd28145a7cde195a4c834276730d30f074b212a150e770931ee9470e853e7d22402683131f96baec9121383995904c49a02ce2c2451f8038291e5db2dce66663e92ac14f8ad1811cc83861afadf12f3191cca1391f1f3af705977faa2fa2bf46a629f9fd0dd7279c7af7470472d1208a13e33239b484974d47cffce4ad47856440333022898140662dfea847e3cbfe5e989845ac6766e83472f8b0c650d85e77bae", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb30e8cb253c2fa33f382c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c": "0x4c669b04865e9acaf7b72bdfcb0099d70d9ec63c8c2d6b8cb0552815d7b50a0afacb2f987caac6c1290a9784b1efdba78343d39aed805addb12945efbe444000ca3c2703db1633a27eff681d979967988c3a6752c669fd41f1abde10f3b054462253ee3c02d89582602ca5b0570cfc01dc82cc8d1b9d2071eb5db6318749124bf0e6c42698fffc28f9fc769fddcdf165af54c171cde43690cc8f73c853de1f0426e2fc857945d01520797a75388c58e710c9fefedd28387af70880f1682be41e02182879ec92e811e2a8cc117f3cde1f61d3cba0093134cfb1ed17a4ef74915d4a", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb31887a9d70c3dff6e6ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a2259627": "0x0509f9caf32fda5584343c473b386c433acb99fd9400724b8cf3c618d840133fb2efe7e70daf44b3466c63ccbf4487f42c6a9f6fbb7050b849691e36ce92e347bef47a9e4b47ed57461e1d28cac7da327a52ebcd64d74080d31deb3ac7a7645e4e1a59090261a7e6bd82544df1eebd96dc87b4eb1211346645fa44d6b932960be4ca45c68b0248885d190d22068c6628ee2f00d9fa0706d5a5c1c8456369f03eaa3955187f755708cd6a8104314b962ff5043e36efa3ec5d84df40c58b44222102f4f4d0eccb899bf2d611b56e0afec7c740efba404f8d0e82a545f988c45316c4", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3198703ff0791c2de1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c413": "0x5fafb6219eb8d463bec0370b2aab69f45fc780959fc2eddbc7703760aa34202274dacbca0cdb5099afef67e622c147614198e669931cebc605629da332632473b414aa148096a92a1831309f758f944725653363ccbaeb21817b7df5784b8d46c45a6d0878f808b1baaa85dcfb4e930ae06e3205bb38855527aee6f259e3327b2e2f75472708a497d1743f52b04edf26c250d9e6d220f3bae3d176f02f8e586c2ada042fb4bbfd9b6d8c48293ffc4a7722632c843a67e608554c41d06aabc41303a0af06322d100056125fac1df39d161089b07ae279505aae8731c4d110a54ad7", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3260868bcb77241070efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f76108": "0x83f43ee3e4521b55de0fe830847fda88a6b017b87979af1a41b180c39da1e4b05440add43e5388a81aef665c9086d386c0be0ce75e4f8a4a3d8168e976ea821f98aab6f52520022d011a6eba2dca1c6327edbbcd753c170dcf0e9118b5f0f25bd0d052eca7d732d9f560ba970ca48f67387b899e76958ea6ed342a3a553ef0223e547f5cc3455a61d0404d7296ceec7375cbe20322109d118c5e725b1a5cbf04cce3ec06252cf7cdad47fe1265047a9bbddb9059ee4bdc6dec83b67249b4a93403f045328f504c13dac9ddd9b1186098aee7c46cb8d55289dbbf2433bab7a26239", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3572aae990801cce1043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d": "0xc8caee6f6eddc41c6cc55e554343392cbc13d2a8a57b97f6f85fc965bdd20ce8b07d600e3487e2712dcc3879c7b17c9b29cd2243b45f0d9343c591b89cf82a650edf2a41cb81178704560b02c35f5e01a5a97a568ebc10c025ade18b6ab2fa1d161d0af40e6efc165c17d0189bd2d770bdfa0a9b8393cb89113f473a2e948c68def964eed9a73f8a6610f1a0373378dca6f277eb7787869ed5841893105ad930f89c97bf5b2c07c05c84eebce4ffc7b28766946c03741fd1a71fdae0942e87680325fc2095902f5fe394f244bce38b0dc3d631cbc05f0b64d5620a71bbf2514f0f", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb365903e26e594bcd6d41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d": "0x64adb43a7628139f6c02100f6a5465dbd33422418426c572b12547c5a665008c1ab03b1b3277edfedd24ef3d3359b449b64bd95ed82a04e7f9fbaab7b71dc0152cd12c731d91441f0114b08d314cd3f9a9f7fd0240d467fe54adefbee4d90762441629077e228528f91ca7dc17051bb437408a5ae272d0950e58961846a8fc2ec22ce14ba0e59aa974d4a05c9208ba5ae18674c6a23c9998d91e7d1ebea7e06b9a86227e204a2d003399c2a3b50c2c869c4380c195a014a02f6d2e7048941237029a1eb2e31dcaf468dbb516f9b620fdd7c3f090d58a88e02b51b25255b2182dd1", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3a8a26ecf38bdcfc668728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c69": "0x6e309dfa4c8de814cad140b8612a9e41bfba244f9ab1468e1b5d9b3cc1f5e565c44b3e8efe854419ccd5801a82ada22d39cfccdbcece382304cdfeac81ebe402a8a03d86e6c0dbe180cadfc7994121f462b28f7a8cb1be7e0e354147624be7340a988fb965b156a07debf072fd9d34a9c7c0fc0e0ff5bd63ef766afb76e2b3289ef622d2467ed115fa0c6c86303e1ef6a08a0609c97e616aa69b026a6d3f2663729053f28155071474b4686323db5f7a318cb3f088b76660cc8ff5e3e11ec32e030e901c390fa37d101ff25d70594acd2df67b4493ee77a73684f25d39313536d7", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3ab8d3e1fa99ea7e2d0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327c": "0xc8de3a01502422b59dfa601c9c3a04a98d2bfbd79dd0810d1d1250feab4241ee6248d87bd2a640ffe26d6b831735887c24e2076a3a0f3a74f7ae7568c27604087c03ca47a3201455f8f89defda4aa909cb1d25dd9ddb7fd62a940606f79b566390032c39c968f486f77f8764301a8479206f063d49eeb9f6d499333e2a1be045165f3b255dc17054e6d4447c4005f689eb5ed2f99fe201f4ff799bf088495850047277f22b9ef92a8b99618f4c86c2412f0e3b08a4f965f842775672043d1e2503586dafcdab3d4647d4dc68732a9cab8aa34c00c5edd04e65d9dd44c2a1fd21e2", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3d12736684524574c32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e1152": "0x8270a62b61639ee56113834aecec01de6cda91413a5111b89f74d6585da34f5058108e1651614afc6a535c426fc013945e93533faa33819fe4e69423fe32330274bd654c470ed9b94972c1f997593fab7bdd4d6b85e3cf49401265668142584ead90a2c3fa2c756f974628dd279adb87935f7ea509856276e3b86f759b22451cc083b0d0bd7d6ffd14562b4c9e28738b087ccc32262170c633c18359ff84877992cb05c48fc643f057626c669604675c5ad5a836266f260ae7030c6fdc17a54303aec8e80ea0375f8669d6e55d7abb6a3117678d7bb851a1bd100a01e52a4fed90", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3d30ebbc69dfd05038eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964": "0xe41426f7465c13c48335771c5450bf61c50a9cf28b9274f170c7421eea7974f168a9ec74fa35b3425eaf503dd36294ba8e758e7b8084c4d6bfd547f8c6b5827460fcc9d094d21fe17cfb7426501f50cb3d75c4c9395a3140e0f255443f660d3b9e065eea4143325fbbd26967c26a228d51a3a8384062f7434973f15d1da2c01068f7a83678a377701b46a5e6a4637e99868186ff4835fc0e3914cc56a76a360164ffc83f4f86cc595e607a00b977eeb6641e02a4e6e556c24ab163aecd7d146c03e843f200e30bc5b951c73a96d968db1c0cd05e357d910fce159fc59c40e9d6e2", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3deca1f47c95ad9e99492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f": "0xc9a68a26e9aa37ba6334f1a20275e3be7d3a9d4aa988627eadac8ea0d0a2dfbfae240842b74e5dd778972e451558134f434c7a1d8a52bc70519f38054e24553306bd8fd81e50cda2bd67bf6893d921d1aae5cb08409ae43e0bff4d54e1830e58ea9400f05e7fb75a3f7a92febbf58e5a3060dd06132ed6d5d68a3d75ec452826bed3b452f869d187be58a4ba98588611084283810728fa75981e792beaec4151763d070989ead31f265b40cc7a0cd29d47799b766d6a7f084e44c82baedfc01e029338ece1c6bc6439dc4d16bfe33f28c9f0af31626bb8142849742b7a624f6807", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3e7e316712ac574569037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af74": "0xace46e899b90e75199549d8fa2ae7097e896ab3c845217e3155f99b6ffb888037c8348ec95a0faad6a638ef74864761028c53221bde07e9ff7c81a3f427abf3f30c40adee5476157ef3c2a26e10cab95ec7d54b62dd220738f5a474d5f86874e0ce84accce1ced0de223aa72f760f1b3d13ddfd267938cd63e25308378d32008eed33645cda7812cd343bbaef9131b2794812f2fd37701ccb6cddf9c1e293d387aeb767131602e6612e607a9eb8e26b4ce4fa4765593d032bc923ce8acadda420203d51bba2124f480e3507eb1764fc3019ac7abae8ee215683a285078bda7f51d", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3eec11b5fca7cddef5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c": "0x622c382187c0b2c61ecfb17443294d11a9d2ab770ae6f1fb49184a43906d59fe50412bd7d3f1075e8f8e3b682d05ea20b391c287d8c849a0e49a78f568553e6994848b8cf2cbc9e6fd72db8d80676591b5be4d1ec68972ada48cf6fd01228712303094c583e253794c9db14803585baaa74472f4ecba846defefc8aecfb6214ab400c4164d016282b202c1d42d9dc8ede28cbe4b751d463bab5f23fef42b295a8c15606f4c121376097ff0e96c2a33ea7b024d812b42fe2c741c8b8cee17e63d03d46c454f9b620603feef8c3a2a5d7098205b8566500fda0fa0b456d6ded54538", "0xcec5070d609dd3497f72bde07fc96ba04e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19500ad445de53dc0cfe6175646980729053f28155071474b4686323db5f7a318cb3f088b76660cc8ff5e3e11ec32e": "0x68728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c69", "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19501153f927dde4f0796173676e80f0e6c42698fffc28f9fc769fddcdf165af54c171cde43690cc8f73c853de1f04": "0x82c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195012ba4e8c9e90550f6173676e80b400c4164d016282b202c1d42d9dc8ede28cbe4b751d463bab5f23fef42b295a": "0x5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195016108068be661c046772616e806e309dfa4c8de814cad140b8612a9e41bfba244f9ab1468e1b5d9b3cc1f5e565": "0x68728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c69", "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195016d5d491326e20327061726180ea9400f05e7fb75a3f7a92febbf58e5a3060dd06132ed6d5d68a3d75ec452826": "0x9492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950172bf7b1d4fd362d62616265806248d87bd2a640ffe26d6b831735887c24e2076a3a0f3a74f7ae7568c2760408": "0xd0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327c", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19501aeb8a0909a0259a696d6f6e8098aab6f52520022d011a6eba2dca1c6327edbbcd753c170dcf0e9118b5f0f25b": "0x0efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f76108", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950206946fcbcbb55c06772616e800509f9caf32fda5584343c473b386c433acb99fd9400724b8cf3c618d840133f": "0x6ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a2259627", "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195022df7698c94798dc6261626580facb2f987caac6c1290a9784b1efdba78343d39aed805addb12945efbe444000": "0x82c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19502bf84b6fe354ffa4696d6f6e80bef47a9e4b47ed57461e1d28cac7da327a52ebcd64d74080d31deb3ac7a7645e": "0x6ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a2259627", "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19502d8e55cbf27bd5fa6175646980763d070989ead31f265b40cc7a0cd29d47799b766d6a7f084e44c82baedfc01e": "0x9492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195033918a92ec5a0337626162658068a9ec74fa35b3425eaf503dd36294ba8e758e7b8084c4d6bfd547f8c6b58274": "0x8eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950365a4d707a6ade5270617261800a988fb965b156a07debf072fd9d34a9c7c0fc0e0ff5bd63ef766afb76e2b328": "0x68728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c69", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195036942a186c91d1fb6772616e80e41426f7465c13c48335771c5450bf61c50a9cf28b9274f170c7421eea7974f1": "0x8eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950377ac9e1db771a9a696d6f6e8060fcc9d094d21fe17cfb7426501f50cb3d75c4c9395a3140e0f255443f660d3b": "0x8eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19503a73714b16fa1b3b62616265805440add43e5388a81aef665c9086d386c0be0ce75e4f8a4a3d8168e976ea821f": "0x0efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f76108", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195042faced8513a5a6162656566840325fc2095902f5fe394f244bce38b0dc3d631cbc05f0b64d5620a71bbf2514f0f": "0x043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d", "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195047d6f38d0fa588e4617564698026e2fc857945d01520797a75388c58e710c9fefedd28387af70880f1682be41e": "0x82c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950486e2fc6fe1baf7d62656566840333022898140662dfea847e3cbfe5e989845ac6766e83472f8b0c650d85e77bae": "0x94c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b10", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195048ac54571b914843626565668403e843f200e30bc5b951c73a96d968db1c0cd05e357d910fce159fc59c40e9d6e2": "0x8eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964", "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19504d5070934a9a468e6261626580b07d600e3487e2712dcc3879c7b17c9b29cd2243b45f0d9343c591b89cf82a65": "0x043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19504f6e7e79cc9e4f1c6772616e8064adb43a7628139f6c02100f6a5465dbd33422418426c572b12547c5a665008c": "0xd41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19504fbe8be23f344f7a6173676e809ef622d2467ed115fa0c6c86303e1ef6a08a0609c97e616aa69b026a6d3f2663": "0x68728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c69", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19505214a412d15781646173676e8068f7a83678a377701b46a5e6a4637e99868186ff4835fc0e3914cc56a76a3601": "0x8eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950523f922d3cd709c261756469809a86227e204a2d003399c2a3b50c2c869c4380c195a014a02f6d2e7048941237": "0xd41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195053557db7980560f461756469802ada042fb4bbfd9b6d8c48293ffc4a7722632c843a67e608554c41d06aabc413": "0x1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c413", "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19505bb3161fb65601ff626162658058108e1651614afc6a535c426fc013945e93533faa33819fe4e69423fe323302": "0x32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e1152", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19505d3dc734864e36256265656684029338ece1c6bc6439dc4d16bfe33f28c9f0af31626bb8142849742b7a624f6807": "0x9492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19505d9ac86ecdf920c170617261804e1a59090261a7e6bd82544df1eebd96dc87b4eb1211346645fa44d6b932960b": "0x6ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a2259627", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195062a6c483038fd12d6265656684030e901c390fa37d101ff25d70594acd2df67b4493ee77a73684f25d39313536d7": "0x68728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c69", "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195064cc468ab603f8926772616e80c9a68a26e9aa37ba6334f1a20275e3be7d3a9d4aa988627eadac8ea0d0a2dfbf": "0x9492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195065ccc9ce9f581b2c61756469807aeb767131602e6612e607a9eb8e26b4ce4fa4765593d032bc923ce8acadda42": "0x9037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af74", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950678c21325827e7c66173676e802e2f75472708a497d1743f52b04edf26c250d9e6d220f3bae3d176f02f8e586c": "0x1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c413", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19506792a176f707220962616265801ab03b1b3277edfedd24ef3d3359b449b64bd95ed82a04e7f9fbaab7b71dc015": "0xd41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195067f9bb125e8b25cf696d6f6e802cd12c731d91441f0114b08d314cd3f9a9f7fd0240d467fe54adefbee4d90762": "0xd41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195068d2c0f060d8e93b6772616e806e60f1e253735fb113c183fa603f591e4456435171f387c0849001b428b5ccb1": "0x94c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b10", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195069561cd534084d42696d6f6e80b414aa148096a92a1831309f758f944725653363ccbaeb21817b7df5784b8d46": "0x1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c413", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950717bb541f3dc932d6772616e80c8de3a01502422b59dfa601c9c3a04a98d2bfbd79dd0810d1d1250feab4241ee": "0xd0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327c", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19507180ab4d5ffe8c79706172618090032c39c968f486f77f8764301a8479206f063d49eeb9f6d499333e2a1be045": "0xd0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327c", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195073b0d3d9242f219d70617261800ce84accce1ced0de223aa72f760f1b3d13ddfd267938cd63e25308378d32008": "0x9037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af74", "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19507466b8cede2256a27061726180ad90a2c3fa2c756f974628dd279adb87935f7ea509856276e3b86f759b22451c": "0x32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e1152", "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950749c8bce91e643ae6772616e808270a62b61639ee56113834aecec01de6cda91413a5111b89f74d6585da34f50": "0x32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e1152", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950795802224826305461756469808c15606f4c121376097ff0e96c2a33ea7b024d812b42fe2c741c8b8cee17e63d": "0x5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19507e5838eaecbd9fe66175646980629f9fd0dd7279c7af7470472d1208a13e33239b484974d47cffce4ad4785644": "0x94c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b10", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195085436b71cc38efc86173676e80e4ca45c68b0248885d190d22068c6628ee2f00d9fa0706d5a5c1c8456369f03e": "0x6ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a2259627", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195087f680d5c3a7dcbf617564698064ffc83f4f86cc595e607a00b977eeb6641e02a4e6e556c24ab163aecd7d146c": "0x8eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950892d429df08b8e486772616e805fafb6219eb8d463bec0370b2aab69f45fc780959fc2eddbc7703760aa342022": "0x1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c413", "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19508cec3cc48ae13ec86173676e80def964eed9a73f8a6610f1a0373378dca6f277eb7787869ed5841893105ad930": "0x043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195090ddc04de598f6716772616e8083f43ee3e4521b55de0fe830847fda88a6b017b87979af1a41b180c39da1e4b0": "0x0efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f76108", "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950961fc927b0be61a66175646980f89c97bf5b2c07c05c84eebce4ffc7b28766946c03741fd1a71fdae0942e8768": "0x043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195097b423b109a1a3e7626565668403a0af06322d100056125fac1df39d161089b07ae279505aae8731c4d110a54ad7": "0x1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c413", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19509990e89dc7508f8f626565668403d46c454f9b620603feef8c3a2a5d7098205b8566500fda0fa0b456d6ded54538": "0x5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c", "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19509c34aadd3112cff46772616e80c8caee6f6eddc41c6cc55e554343392cbc13d2a8a57b97f6f85fc965bdd20ce8": "0x043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19509cc6d5a70d4342de706172618002683131f96baec9121383995904c49a02ce2c2451f8038291e5db2dce66663e": "0x94c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b10", "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19509d726f19fb7e918f6173676e80c083b0d0bd7d6ffd14562b4c9e28738b087ccc32262170c633c18359ff848779": "0x32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e1152", "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19509f08b41b3412bdf7696d6f6e8074bd654c470ed9b94972c1f997593fab7bdd4d6b85e3cf49401265668142584e": "0x32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e1152", "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19509f796bfaa6092095696d6f6e800edf2a41cb81178704560b02c35f5e01a5a97a568ebc10c025ade18b6ab2fa1d": "0x043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950a0aff76314285afe6173676e803e547f5cc3455a61d0404d7296ceec7375cbe20322109d118c5e725b1a5cbf04": "0x0efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f76108", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950a39a50629306361270617261809e065eea4143325fbbd26967c26a228d51a3a8384062f7434973f15d1da2c010": "0x8eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964", "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950a69397f216a7497a6261626580ae240842b74e5dd778972e451558134f434c7a1d8a52bc70519f38054e245533": "0x9492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950a8670a2360fb4f7d626565668402f4f4d0eccb899bf2d611b56e0afec7c740efba404f8d0e82a545f988c45316c4": "0x6ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a2259627", "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950ab8402a39318e10f70617261802253ee3c02d89582602ca5b0570cfc01dc82cc8d1b9d2071eb5db6318749124b": "0x82c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950aba2e02edcf42d916175646980cce3ec06252cf7cdad47fe1265047a9bbddb9059ee4bdc6dec83b67249b4a934": "0x0efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f76108", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950ac3745478a256f54696d6f6e8094848b8cf2cbc9e6fd72db8d80676591b5be4d1ec68972ada48cf6fd01228712": "0x5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c", "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950ae71ab667a6367956173676e80bed3b452f869d187be58a4ba98588611084283810728fa75981e792beaec4151": "0x9492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f", "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950aee25d4290ea4d846772616e804c669b04865e9acaf7b72bdfcb0099d70d9ec63c8c2d6b8cb0552815d7b50a0a": "0x82c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950b090c0a6a6d34dc97061726180441629077e228528f91ca7dc17051bb437408a5ae272d0950e58961846a8fc2e": "0xd41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950b40a2e291d3757e66265656684029a1eb2e31dcaf468dbb516f9b620fdd7c3f090d58a88e02b51b25255b2182dd1": "0xd41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950b469b5316f2df49e626162658018bd0f67d77f04f1a92400421813d8927fad109b40a8689254a5f0c8b346857c": "0x94c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b10", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950b6da07aad040c4596772616e80ace46e899b90e75199549d8fa2ae7097e896ab3c845217e3155f99b6ffb88803": "0x9037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af74", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950b9847e90f2a93d58626565668403aec8e80ea0375f8669d6e55d7abb6a3117678d7bb851a1bd100a01e52a4fed90": "0x32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e1152", "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950bad6b6ae80666780696d6f6e8006bd8fd81e50cda2bd67bf6893d921d1aae5cb08409ae43e0bff4d54e1830e58": "0x9492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950bd1ab2cd6f1dc5a6696d6f6e80d28145a7cde195a4c834276730d30f074b212a150e770931ee9470e853e7d224": "0x94c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b10", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950bdd996f23001764e62656566840203d51bba2124f480e3507eb1764fc3019ac7abae8ee215683a285078bda7f51d": "0x9037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af74", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950be81b84f18801f516173676e80165f3b255dc17054e6d4447c4005f689eb5ed2f99fe201f4ff799bf088495850": "0xd0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327c", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950bef85ee78e59fe8a6173676e80eed33645cda7812cd343bbaef9131b2794812f2fd37701ccb6cddf9c1e293d38": "0x9037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af74", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950bfb5b848b461277c7061726180c45a6d0878f808b1baaa85dcfb4e930ae06e3205bb38855527aee6f259e3327b": "0x1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c413", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950c1cabf91e699980a6261626580b2efe7e70daf44b3466c63ccbf4487f42c6a9f6fbb7050b849691e36ce92e347": "0x6ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a2259627", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950c2bef1fa94927270626565668403f045328f504c13dac9ddd9b1186098aee7c46cb8d55289dbbf2433bab7a26239": "0x0efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f76108", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950c3b366be127c04d76772616e80622c382187c0b2c61ecfb17443294d11a9d2ab770ae6f1fb49184a43906d59fe": "0x5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950c61ff1db24ad5e86626565668402182879ec92e811e2a8cc117f3cde1f61d3cba0093134cfb1ed17a4ef74915d4a": "0x82c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950cb18236e84f2bcc8626565668403586dafcdab3d4647d4dc68732a9cab8aa34c00c5edd04e65d9dd44c2a1fd21e2": "0xd0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327c", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950d1c1264edac2bfeb7061726180303094c583e253794c9db14803585baaa74472f4ecba846defefc8aecfb6214a": "0x5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950d4b8d8139a9d2a3862616265807c8348ec95a0faad6a638ef74864761028c53221bde07e9ff7c81a3f427abf3f": "0x9037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af74", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950d5b902094e722e906261626580c44b3e8efe854419ccd5801a82ada22d39cfccdbcece382304cdfeac81ebe402": "0x68728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c69", "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950d74338095b2b3a5f7061726180161d0af40e6efc165c17d0189bd2d770bdfa0a9b8393cb89113f473a2e948c68": "0x043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950d84b213ff11dcdc96175646980047277f22b9ef92a8b99618f4c86c2412f0e3b08a4f965f842775672043d1e25": "0xd0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327c", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950d912f1fd94200c50696d6f6e8030c40adee5476157ef3c2a26e10cab95ec7d54b62dd220738f5a474d5f86874e": "0x9037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af74", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950db189b9054ee003e6175646980aa3955187f755708cd6a8104314b962ff5043e36efa3ec5d84df40c58b442221": "0x6ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a2259627", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950dd45ac2fed4ab0db6173676e8092ac14f8ad1811cc83861afadf12f3191cca1391f1f3af705977faa2fa2bf46a": "0x94c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b10", "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950dfe86daa30500684696d6f6e80ca3c2703db1633a27eff681d979967988c3a6752c669fd41f1abde10f3b05446": "0x82c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c", "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950e326352daf693946617564698092cb05c48fc643f057626c669604675c5ad5a836266f260ae7030c6fdc17a543": "0x32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e1152", - "0xcec5070d609dd3497f72bde07fc96ba088dcde934c658227ee1dfafcd6e16903": "0x10043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d32eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e115282c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c9492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f", - "0xcec5070d609dd3497f72bde07fc96ba0e0cdd062e6eaf24295ad4ccfc41d4609": "0x10043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170dc8caee6f6eddc41c6cc55e554343392cbc13d2a8a57b97f6f85fc965bdd20ce8b07d600e3487e2712dcc3879c7b17c9b29cd2243b45f0d9343c591b89cf82a650edf2a41cb81178704560b02c35f5e01a5a97a568ebc10c025ade18b6ab2fa1d161d0af40e6efc165c17d0189bd2d770bdfa0a9b8393cb89113f473a2e948c68def964eed9a73f8a6610f1a0373378dca6f277eb7787869ed5841893105ad930f89c97bf5b2c07c05c84eebce4ffc7b28766946c03741fd1a71fdae0942e876832eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e11528270a62b61639ee56113834aecec01de6cda91413a5111b89f74d6585da34f5058108e1651614afc6a535c426fc013945e93533faa33819fe4e69423fe32330274bd654c470ed9b94972c1f997593fab7bdd4d6b85e3cf49401265668142584ead90a2c3fa2c756f974628dd279adb87935f7ea509856276e3b86f759b22451cc083b0d0bd7d6ffd14562b4c9e28738b087ccc32262170c633c18359ff84877992cb05c48fc643f057626c669604675c5ad5a836266f260ae7030c6fdc17a54382c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c4c669b04865e9acaf7b72bdfcb0099d70d9ec63c8c2d6b8cb0552815d7b50a0afacb2f987caac6c1290a9784b1efdba78343d39aed805addb12945efbe444000ca3c2703db1633a27eff681d979967988c3a6752c669fd41f1abde10f3b054462253ee3c02d89582602ca5b0570cfc01dc82cc8d1b9d2071eb5db6318749124bf0e6c42698fffc28f9fc769fddcdf165af54c171cde43690cc8f73c853de1f0426e2fc857945d01520797a75388c58e710c9fefedd28387af70880f1682be41e9492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20fc9a68a26e9aa37ba6334f1a20275e3be7d3a9d4aa988627eadac8ea0d0a2dfbfae240842b74e5dd778972e451558134f434c7a1d8a52bc70519f38054e24553306bd8fd81e50cda2bd67bf6893d921d1aae5cb08409ae43e0bff4d54e1830e58ea9400f05e7fb75a3f7a92febbf58e5a3060dd06132ed6d5d68a3d75ec452826bed3b452f869d187be58a4ba98588611084283810728fa75981e792beaec4151763d070989ead31f265b40cc7a0cd29d47799b766d6a7f084e44c82baedfc01e", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950ec74f4b6dbe6f07e626162658074dacbca0cdb5099afef67e622c147614198e669931cebc605629da332632473": "0x1e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c413", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950f10dac37e2a0f812696d6f6e80a8a03d86e6c0dbe180cadfc7994121f462b28f7a8cb1be7e0e354147624be734": "0x68728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c69", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950f39a56e067ee2ba9696d6f6e807c03ca47a3201455f8f89defda4aa909cb1d25dd9ddb7fd62a940606f79b5663": "0xd0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327c", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950f87aebc04f6a52ae6173676e80c22ce14ba0e59aa974d4a05c9208ba5ae18674c6a23c9998d91e7d1ebea7e06b": "0xd41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950fc36b10abae8cf4f626162658050412bd7d3f1075e8f8e3b682d05ea20b391c287d8c849a0e49a78f568553e69": "0x5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950fcf43201be771ed27061726180d0d052eca7d732d9f560ba970ca48f67387b899e76958ea6ed342a3a553ef022": "0x0efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f76108", + "0xcec5070d609dd3497f72bde07fc96ba088dcde934c658227ee1dfafcd6e16903": "0x38043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170d0efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f761081e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c41332eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e11525270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c68728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c696ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a225962782c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c8eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b8689649037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af749492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20f94c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b10d0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327cd41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d", + "0xcec5070d609dd3497f72bde07fc96ba0e0cdd062e6eaf24295ad4ccfc41d4609": "0x38043393e76c137dfdc403a6fd9a2d6129d470d51c5a67bd40517378030c87170dc8caee6f6eddc41c6cc55e554343392cbc13d2a8a57b97f6f85fc965bdd20ce8b07d600e3487e2712dcc3879c7b17c9b29cd2243b45f0d9343c591b89cf82a650edf2a41cb81178704560b02c35f5e01a5a97a568ebc10c025ade18b6ab2fa1d161d0af40e6efc165c17d0189bd2d770bdfa0a9b8393cb89113f473a2e948c68def964eed9a73f8a6610f1a0373378dca6f277eb7787869ed5841893105ad930f89c97bf5b2c07c05c84eebce4ffc7b28766946c03741fd1a71fdae0942e87680325fc2095902f5fe394f244bce38b0dc3d631cbc05f0b64d5620a71bbf2514f0f0efe248e3ddcfcb4f29675b70fc0a8e2db66b65381c45d299427b60d05f7610883f43ee3e4521b55de0fe830847fda88a6b017b87979af1a41b180c39da1e4b05440add43e5388a81aef665c9086d386c0be0ce75e4f8a4a3d8168e976ea821f98aab6f52520022d011a6eba2dca1c6327edbbcd753c170dcf0e9118b5f0f25bd0d052eca7d732d9f560ba970ca48f67387b899e76958ea6ed342a3a553ef0223e547f5cc3455a61d0404d7296ceec7375cbe20322109d118c5e725b1a5cbf04cce3ec06252cf7cdad47fe1265047a9bbddb9059ee4bdc6dec83b67249b4a93403f045328f504c13dac9ddd9b1186098aee7c46cb8d55289dbbf2433bab7a262391e30aa51ad68b8918d2c46e914986818c111bee03582610cbc9fb73fe0e4c4135fafb6219eb8d463bec0370b2aab69f45fc780959fc2eddbc7703760aa34202274dacbca0cdb5099afef67e622c147614198e669931cebc605629da332632473b414aa148096a92a1831309f758f944725653363ccbaeb21817b7df5784b8d46c45a6d0878f808b1baaa85dcfb4e930ae06e3205bb38855527aee6f259e3327b2e2f75472708a497d1743f52b04edf26c250d9e6d220f3bae3d176f02f8e586c2ada042fb4bbfd9b6d8c48293ffc4a7722632c843a67e608554c41d06aabc41303a0af06322d100056125fac1df39d161089b07ae279505aae8731c4d110a54ad732eebacd223f4aef33d98a667a68f9e371f40384257c6d31030952b9d94e11528270a62b61639ee56113834aecec01de6cda91413a5111b89f74d6585da34f5058108e1651614afc6a535c426fc013945e93533faa33819fe4e69423fe32330274bd654c470ed9b94972c1f997593fab7bdd4d6b85e3cf49401265668142584ead90a2c3fa2c756f974628dd279adb87935f7ea509856276e3b86f759b22451cc083b0d0bd7d6ffd14562b4c9e28738b087ccc32262170c633c18359ff84877992cb05c48fc643f057626c669604675c5ad5a836266f260ae7030c6fdc17a54303aec8e80ea0375f8669d6e55d7abb6a3117678d7bb851a1bd100a01e52a4fed905270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c622c382187c0b2c61ecfb17443294d11a9d2ab770ae6f1fb49184a43906d59fe50412bd7d3f1075e8f8e3b682d05ea20b391c287d8c849a0e49a78f568553e6994848b8cf2cbc9e6fd72db8d80676591b5be4d1ec68972ada48cf6fd01228712303094c583e253794c9db14803585baaa74472f4ecba846defefc8aecfb6214ab400c4164d016282b202c1d42d9dc8ede28cbe4b751d463bab5f23fef42b295a8c15606f4c121376097ff0e96c2a33ea7b024d812b42fe2c741c8b8cee17e63d03d46c454f9b620603feef8c3a2a5d7098205b8566500fda0fa0b456d6ded5453868728d12a90fb1a9f5b0f0b2814d730401d314964113554e66ff19e7067d7c696e309dfa4c8de814cad140b8612a9e41bfba244f9ab1468e1b5d9b3cc1f5e565c44b3e8efe854419ccd5801a82ada22d39cfccdbcece382304cdfeac81ebe402a8a03d86e6c0dbe180cadfc7994121f462b28f7a8cb1be7e0e354147624be7340a988fb965b156a07debf072fd9d34a9c7c0fc0e0ff5bd63ef766afb76e2b3289ef622d2467ed115fa0c6c86303e1ef6a08a0609c97e616aa69b026a6d3f2663729053f28155071474b4686323db5f7a318cb3f088b76660cc8ff5e3e11ec32e030e901c390fa37d101ff25d70594acd2df67b4493ee77a73684f25d39313536d76ed774481ff68097867271bc8ecaeee3500817ccefdfda74ceeafd32a22596270509f9caf32fda5584343c473b386c433acb99fd9400724b8cf3c618d840133fb2efe7e70daf44b3466c63ccbf4487f42c6a9f6fbb7050b849691e36ce92e347bef47a9e4b47ed57461e1d28cac7da327a52ebcd64d74080d31deb3ac7a7645e4e1a59090261a7e6bd82544df1eebd96dc87b4eb1211346645fa44d6b932960be4ca45c68b0248885d190d22068c6628ee2f00d9fa0706d5a5c1c8456369f03eaa3955187f755708cd6a8104314b962ff5043e36efa3ec5d84df40c58b44222102f4f4d0eccb899bf2d611b56e0afec7c740efba404f8d0e82a545f988c45316c482c3105dbd4bb206428d8a8b7ea1f19965a0668dd583b06c3b75daa181fe654c4c669b04865e9acaf7b72bdfcb0099d70d9ec63c8c2d6b8cb0552815d7b50a0afacb2f987caac6c1290a9784b1efdba78343d39aed805addb12945efbe444000ca3c2703db1633a27eff681d979967988c3a6752c669fd41f1abde10f3b054462253ee3c02d89582602ca5b0570cfc01dc82cc8d1b9d2071eb5db6318749124bf0e6c42698fffc28f9fc769fddcdf165af54c171cde43690cc8f73c853de1f0426e2fc857945d01520797a75388c58e710c9fefedd28387af70880f1682be41e02182879ec92e811e2a8cc117f3cde1f61d3cba0093134cfb1ed17a4ef74915d4a8eef6710734f5d1e7d2eb303fa8f04e9bef65fb680647b24624723f95b868964e41426f7465c13c48335771c5450bf61c50a9cf28b9274f170c7421eea7974f168a9ec74fa35b3425eaf503dd36294ba8e758e7b8084c4d6bfd547f8c6b5827460fcc9d094d21fe17cfb7426501f50cb3d75c4c9395a3140e0f255443f660d3b9e065eea4143325fbbd26967c26a228d51a3a8384062f7434973f15d1da2c01068f7a83678a377701b46a5e6a4637e99868186ff4835fc0e3914cc56a76a360164ffc83f4f86cc595e607a00b977eeb6641e02a4e6e556c24ab163aecd7d146c03e843f200e30bc5b951c73a96d968db1c0cd05e357d910fce159fc59c40e9d6e29037d1020ed699c2f538d3ffcf0eb98087ee11ca4bd07bfddb0d68633806af74ace46e899b90e75199549d8fa2ae7097e896ab3c845217e3155f99b6ffb888037c8348ec95a0faad6a638ef74864761028c53221bde07e9ff7c81a3f427abf3f30c40adee5476157ef3c2a26e10cab95ec7d54b62dd220738f5a474d5f86874e0ce84accce1ced0de223aa72f760f1b3d13ddfd267938cd63e25308378d32008eed33645cda7812cd343bbaef9131b2794812f2fd37701ccb6cddf9c1e293d387aeb767131602e6612e607a9eb8e26b4ce4fa4765593d032bc923ce8acadda420203d51bba2124f480e3507eb1764fc3019ac7abae8ee215683a285078bda7f51d9492b8c38442c79061bdbb8d38dcd28138938a7fd476edf89ecdec06a5a9d20fc9a68a26e9aa37ba6334f1a20275e3be7d3a9d4aa988627eadac8ea0d0a2dfbfae240842b74e5dd778972e451558134f434c7a1d8a52bc70519f38054e24553306bd8fd81e50cda2bd67bf6893d921d1aae5cb08409ae43e0bff4d54e1830e58ea9400f05e7fb75a3f7a92febbf58e5a3060dd06132ed6d5d68a3d75ec452826bed3b452f869d187be58a4ba98588611084283810728fa75981e792beaec4151763d070989ead31f265b40cc7a0cd29d47799b766d6a7f084e44c82baedfc01e029338ece1c6bc6439dc4d16bfe33f28c9f0af31626bb8142849742b7a624f680794c4156ed6a101ae478a3de3ba70a05fce8a3d67be6fb85f33bfcf2777ab6b106e60f1e253735fb113c183fa603f591e4456435171f387c0849001b428b5ccb118bd0f67d77f04f1a92400421813d8927fad109b40a8689254a5f0c8b346857cd28145a7cde195a4c834276730d30f074b212a150e770931ee9470e853e7d22402683131f96baec9121383995904c49a02ce2c2451f8038291e5db2dce66663e92ac14f8ad1811cc83861afadf12f3191cca1391f1f3af705977faa2fa2bf46a629f9fd0dd7279c7af7470472d1208a13e33239b484974d47cffce4ad47856440333022898140662dfea847e3cbfe5e989845ac6766e83472f8b0c650d85e77baed0b4896a63b672a7a74f5234bf9ec8567ff3c5bb8f93795e15e2c498b48d327cc8de3a01502422b59dfa601c9c3a04a98d2bfbd79dd0810d1d1250feab4241ee6248d87bd2a640ffe26d6b831735887c24e2076a3a0f3a74f7ae7568c27604087c03ca47a3201455f8f89defda4aa909cb1d25dd9ddb7fd62a940606f79b566390032c39c968f486f77f8764301a8479206f063d49eeb9f6d499333e2a1be045165f3b255dc17054e6d4447c4005f689eb5ed2f99fe201f4ff799bf088495850047277f22b9ef92a8b99618f4c86c2412f0e3b08a4f965f842775672043d1e2503586dafcdab3d4647d4dc68732a9cab8aa34c00c5edd04e65d9dd44c2a1fd21e2d41a8a9678862ebe9d1a1d59cac1c8430ef31e282f9cb391cf6f2b4d9ce2fd3d64adb43a7628139f6c02100f6a5465dbd33422418426c572b12547c5a665008c1ab03b1b3277edfedd24ef3d3359b449b64bd95ed82a04e7f9fbaab7b71dc0152cd12c731d91441f0114b08d314cd3f9a9f7fd0240d467fe54adefbee4d90762441629077e228528f91ca7dc17051bb437408a5ae272d0950e58961846a8fc2ec22ce14ba0e59aa974d4a05c9208ba5ae18674c6a23c9998d91e7d1ebea7e06b9a86227e204a2d003399c2a3b50c2c869c4380c195a014a02f6d2e7048941237029a1eb2e31dcaf468dbb516f9b620fdd7c3f090d58a88e02b51b25255b2182dd1", "0xd57bce545fb382c34570e5dfbf338f5e4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", "0xd5c41b52a371aa36c9254ce34324f2a54e7b9012096b41c4eb3aaf947f6ea429": "0x0100", "0xd5e1a2fa16732ce6906189438c0a82c64e7b9012096b41c4eb3aaf947f6ea429": "0x0000", @@ -226,4 +419,4 @@ "childrenDefault": {} } } -} +} \ No newline at end of file -- GitLab From 7099f6e1b1fa3c8cd894693902263d9ed0e38978 Mon Sep 17 00:00:00 2001 From: gupnik Date: Fri, 15 Mar 2024 13:16:09 +0530 Subject: [PATCH 042/187] Removes `as [disambiguation_path]` from `derive_impl` usage (#3652) Step in https://github.com/paritytech/polkadot-sdk/issues/171 This PR removes `as [disambiguation_path]` syntax from `derive_impl` usage across the polkadot-sdk as introduced in https://github.com/paritytech/polkadot-sdk/pull/3505 --- bridges/bin/runtime-common/src/mock.rs | 5 +++-- bridges/modules/grandpa/src/mock.rs | 2 +- bridges/modules/messages/src/mock.rs | 4 ++-- bridges/modules/parachains/src/mock.rs | 2 +- bridges/modules/relayers/src/mock.rs | 4 ++-- bridges/modules/xcm-bridge-hub-router/src/mock.rs | 2 +- bridges/modules/xcm-bridge-hub/src/mock.rs | 4 ++-- bridges/snowbridge/pallets/ethereum-client/src/mock.rs | 2 +- bridges/snowbridge/pallets/inbound-queue/src/mock.rs | 2 +- bridges/snowbridge/pallets/outbound-queue/src/mock.rs | 2 +- bridges/snowbridge/pallets/system/src/mock.rs | 2 +- .../pallets/ethereum-beacon-client/src/mock.rs | 4 ++-- cumulus/pallets/collator-selection/src/mock.rs | 2 +- cumulus/pallets/dmp-queue/src/mock.rs | 2 +- cumulus/pallets/parachain-system/src/mock.rs | 2 +- cumulus/pallets/xcmp-queue/src/mock.rs | 2 +- cumulus/parachains/common/src/impls.rs | 2 +- .../parachains/pallets/collective-content/src/mock.rs | 2 +- .../runtimes/assets/asset-hub-rococo/src/lib.rs | 2 +- .../runtimes/assets/asset-hub-westend/src/lib.rs | 2 +- .../runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs | 2 +- .../runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs | 2 +- .../collectives/collectives-westend/src/lib.rs | 2 +- .../runtimes/contracts/contracts-rococo/src/lib.rs | 2 +- .../runtimes/coretime/coretime-rococo/src/lib.rs | 2 +- .../runtimes/coretime/coretime-westend/src/lib.rs | 2 +- .../runtimes/glutton/glutton-westend/src/lib.rs | 2 +- .../runtimes/people/people-rococo/src/lib.rs | 2 +- .../runtimes/people/people-westend/src/lib.rs | 2 +- .../parachains/runtimes/starters/seedling/src/lib.rs | 2 +- cumulus/parachains/runtimes/starters/shell/src/lib.rs | 2 +- cumulus/parachains/runtimes/testing/penpal/src/lib.rs | 2 +- .../runtimes/testing/rococo-parachain/src/lib.rs | 2 +- cumulus/test/runtime/src/lib.rs | 2 +- docs/sdk/src/guides/your_first_pallet/mod.rs | 4 ++-- docs/sdk/src/polkadot_sdk/cumulus.rs | 4 ++-- docs/sdk/src/polkadot_sdk/frame_runtime.rs | 2 +- docs/sdk/src/reference_docs/frame_origin.rs | 4 ++-- docs/sdk/src/reference_docs/frame_pallet_coupling.rs | 2 +- docs/sdk/src/reference_docs/frame_runtime_types.rs | 4 ++-- polkadot/runtime/common/src/assigned_slots/mod.rs | 2 +- polkadot/runtime/common/src/auctions.rs | 2 +- polkadot/runtime/common/src/claims.rs | 2 +- polkadot/runtime/common/src/crowdloan/mod.rs | 2 +- polkadot/runtime/common/src/impls.rs | 2 +- polkadot/runtime/common/src/integration_tests.rs | 2 +- polkadot/runtime/common/src/paras_registrar/mod.rs | 2 +- polkadot/runtime/common/src/purchase.rs | 2 +- polkadot/runtime/common/src/slots/mod.rs | 2 +- polkadot/runtime/parachains/src/mock.rs | 2 +- polkadot/runtime/rococo/src/lib.rs | 2 +- polkadot/runtime/test-runtime/src/lib.rs | 2 +- polkadot/runtime/westend/src/lib.rs | 2 +- .../xcm/pallet-xcm-benchmarks/src/fungible/mock.rs | 4 ++-- polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs | 4 ++-- polkadot/xcm/pallet-xcm/src/mock.rs | 2 +- polkadot/xcm/xcm-builder/src/tests/pay/mock.rs | 2 +- polkadot/xcm/xcm-builder/tests/mock/mod.rs | 2 +- polkadot/xcm/xcm-simulator/example/src/parachain.rs | 2 +- polkadot/xcm/xcm-simulator/example/src/relay_chain.rs | 2 +- polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs | 2 +- polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs | 2 +- prdoc/pr_3505.prdoc | 2 +- substrate/bin/node/runtime/src/lib.rs | 2 +- substrate/frame/alliance/src/mock.rs | 2 +- substrate/frame/asset-conversion/src/mock.rs | 2 +- substrate/frame/asset-rate/src/mock.rs | 2 +- substrate/frame/assets/src/lib.rs | 2 +- substrate/frame/assets/src/mock.rs | 2 +- substrate/frame/atomic-swap/src/tests.rs | 2 +- substrate/frame/aura/src/mock.rs | 2 +- substrate/frame/authority-discovery/src/lib.rs | 2 +- substrate/frame/authorship/src/lib.rs | 2 +- substrate/frame/babe/src/mock.rs | 2 +- substrate/frame/bags-list/src/mock.rs | 2 +- substrate/frame/balances/src/lib.rs | 2 +- substrate/frame/balances/src/tests/mod.rs | 3 ++- substrate/frame/beefy-mmr/src/mock.rs | 2 +- substrate/frame/beefy/src/mock.rs | 2 +- substrate/frame/benchmarking/pov/src/benchmarking.rs | 2 +- substrate/frame/benchmarking/pov/src/tests.rs | 2 +- substrate/frame/benchmarking/src/baseline.rs | 2 +- substrate/frame/benchmarking/src/tests.rs | 2 +- substrate/frame/benchmarking/src/tests_instance.rs | 2 +- substrate/frame/bounties/src/tests.rs | 2 +- substrate/frame/broker/src/mock.rs | 2 +- substrate/frame/child-bounties/src/tests.rs | 2 +- substrate/frame/collective/src/tests.rs | 2 +- .../frame/contracts/mock-network/src/parachain.rs | 2 +- .../frame/contracts/mock-network/src/relay_chain.rs | 2 +- substrate/frame/contracts/src/tests.rs | 2 +- substrate/frame/conviction-voting/src/tests.rs | 2 +- .../frame/core-fellowship/src/tests/integration.rs | 2 +- substrate/frame/core-fellowship/src/tests/unit.rs | 2 +- substrate/frame/democracy/src/tests.rs | 2 +- .../frame/election-provider-multi-phase/src/mock.rs | 2 +- .../test-staking-e2e/src/mock.rs | 2 +- .../frame/election-provider-support/src/onchain.rs | 2 +- substrate/frame/elections-phragmen/src/lib.rs | 2 +- substrate/frame/examples/basic/src/tests.rs | 2 +- substrate/frame/examples/default-config/src/lib.rs | 5 ++--- substrate/frame/examples/dev-mode/src/tests.rs | 2 +- substrate/frame/examples/frame-crate/src/lib.rs | 2 +- substrate/frame/examples/kitchensink/src/tests.rs | 2 +- substrate/frame/examples/offchain-worker/src/tests.rs | 2 +- .../frame/examples/single-block-migrations/src/mock.rs | 2 +- substrate/frame/examples/split/src/mock.rs | 2 +- substrate/frame/examples/tasks/src/mock.rs | 2 +- substrate/frame/executive/src/tests.rs | 4 ++-- substrate/frame/fast-unstake/src/mock.rs | 2 +- substrate/frame/glutton/src/mock.rs | 2 +- substrate/frame/grandpa/src/mock.rs | 2 +- substrate/frame/identity/src/tests.rs | 2 +- substrate/frame/im-online/src/mock.rs | 2 +- substrate/frame/indices/src/mock.rs | 2 +- .../insecure-randomness-collective-flip/src/lib.rs | 2 +- substrate/frame/lottery/src/mock.rs | 2 +- substrate/frame/membership/src/lib.rs | 2 +- substrate/frame/merkle-mountain-range/src/mock.rs | 2 +- substrate/frame/message-queue/src/integration_test.rs | 2 +- substrate/frame/message-queue/src/mock.rs | 2 +- substrate/frame/migrations/src/mock.rs | 2 +- substrate/frame/multisig/src/tests.rs | 4 ++-- substrate/frame/nft-fractionalization/src/mock.rs | 2 +- substrate/frame/nfts/src/mock.rs | 2 +- substrate/frame/nis/src/mock.rs | 2 +- substrate/frame/node-authorization/src/mock.rs | 2 +- .../frame/nomination-pools/benchmarking/src/mock.rs | 2 +- substrate/frame/nomination-pools/src/mock.rs | 2 +- .../frame/nomination-pools/test-staking/src/mock.rs | 2 +- substrate/frame/offences/benchmarking/src/mock.rs | 2 +- substrate/frame/offences/src/mock.rs | 2 +- substrate/frame/paged-list/src/mock.rs | 2 +- substrate/frame/parameters/src/lib.rs | 2 +- substrate/frame/parameters/src/tests/mock.rs | 6 +++--- substrate/frame/parameters/src/tests/test_renamed.rs | 6 +++--- substrate/frame/preimage/src/mock.rs | 2 +- substrate/frame/proxy/src/tests.rs | 4 ++-- substrate/frame/ranked-collective/src/tests.rs | 2 +- substrate/frame/recovery/src/mock.rs | 2 +- substrate/frame/referenda/src/mock.rs | 2 +- substrate/frame/remark/src/mock.rs | 2 +- substrate/frame/root-offences/src/mock.rs | 2 +- substrate/frame/safe-mode/src/mock.rs | 2 +- substrate/frame/salary/src/tests/integration.rs | 2 +- substrate/frame/salary/src/tests/unit.rs | 2 +- substrate/frame/sassafras/src/mock.rs | 2 +- substrate/frame/scheduler/src/mock.rs | 2 +- substrate/frame/scored-pool/src/mock.rs | 2 +- substrate/frame/session/benchmarking/src/mock.rs | 2 +- substrate/frame/session/src/mock.rs | 2 +- substrate/frame/society/src/mock.rs | 4 ++-- substrate/frame/staking/src/mock.rs | 2 +- substrate/frame/state-trie-migration/src/lib.rs | 8 ++++---- substrate/frame/statement/src/mock.rs | 2 +- substrate/frame/sudo/src/lib.rs | 2 +- substrate/frame/sudo/src/mock.rs | 2 +- substrate/frame/support/src/lib.rs | 2 +- substrate/frame/support/src/tests/mod.rs | 2 +- substrate/frame/support/test/compile_pass/src/lib.rs | 2 +- .../frame/support/test/stg_frame_crate/src/lib.rs | 2 +- substrate/frame/support/test/tests/composite_enum.rs | 2 +- .../number_of_pallets_exceeds_tuple_size.rs | 2 +- .../construct_runtime_ui/pallet_error_too_large.rs | 2 +- .../pass/composite_enum_instance.rs | 2 +- .../tests/construct_runtime_ui/undefined_call_part.rs | 2 +- .../tests/construct_runtime_ui/undefined_event_part.rs | 2 +- .../undefined_genesis_config_part.rs | 2 +- .../construct_runtime_ui/undefined_inherent_part.rs | 2 +- .../construct_runtime_ui/undefined_origin_part.rs | 2 +- .../undefined_validate_unsigned_part.rs | 2 +- substrate/frame/support/test/tests/final_keys.rs | 2 +- substrate/frame/support/test/tests/genesisconfig.rs | 2 +- substrate/frame/support/test/tests/instance.rs | 2 +- substrate/frame/support/test/tests/issue2219.rs | 2 +- substrate/frame/support/test/tests/origin.rs | 2 +- substrate/frame/support/test/tests/pallet.rs | 2 +- substrate/frame/support/test/tests/pallet_instance.rs | 2 +- .../support/test/tests/pallet_outer_enums_explicit.rs | 2 +- .../support/test/tests/pallet_outer_enums_implicit.rs | 2 +- .../test/tests/pallet_ui/pass/dev_mode_valid.rs | 2 +- .../test/tests/pallet_ui/pass/no_std_genesis_config.rs | 2 +- substrate/frame/support/test/tests/runtime.rs | 2 +- substrate/frame/support/test/tests/runtime_metadata.rs | 2 +- substrate/frame/support/test/tests/storage_layers.rs | 2 +- .../frame/support/test/tests/storage_transaction.rs | 2 +- .../frame/support/test/tests/versioned_migration.rs | 2 +- substrate/frame/system/benches/bench.rs | 2 +- substrate/frame/system/benchmarking/src/mock.rs | 2 +- substrate/frame/system/src/mock.rs | 2 +- substrate/frame/timestamp/src/lib.rs | 2 +- substrate/frame/timestamp/src/mock.rs | 2 +- substrate/frame/tips/src/tests.rs | 2 +- .../asset-conversion-tx-payment/src/mock.rs | 3 ++- .../transaction-payment/asset-tx-payment/src/mock.rs | 3 ++- .../skip-feeless-payment/src/mock.rs | 2 +- substrate/frame/transaction-payment/src/lib.rs | 2 +- substrate/frame/transaction-payment/src/mock.rs | 2 +- substrate/frame/transaction-storage/src/mock.rs | 4 ++-- substrate/frame/treasury/src/tests.rs | 2 +- substrate/frame/tx-pause/src/mock.rs | 2 +- substrate/frame/uniques/src/mock.rs | 2 +- substrate/frame/utility/src/tests.rs | 2 +- substrate/frame/vesting/src/mock.rs | 2 +- substrate/frame/whitelist/src/mock.rs | 2 +- substrate/test-utils/runtime/src/lib.rs | 2 +- substrate/utils/frame/rpc/support/src/lib.rs | 2 +- templates/minimal/runtime/src/lib.rs | 10 +++++----- templates/parachain/pallets/template/src/mock.rs | 2 +- templates/parachain/runtime/src/lib.rs | 2 +- templates/solochain/pallets/template/src/mock.rs | 2 +- templates/solochain/runtime/src/lib.rs | 2 +- 212 files changed, 244 insertions(+), 241 deletions(-) diff --git a/bridges/bin/runtime-common/src/mock.rs b/bridges/bin/runtime-common/src/mock.rs index 8877a4fd95c..deee4524e85 100644 --- a/bridges/bin/runtime-common/src/mock.rs +++ b/bridges/bin/runtime-common/src/mock.rs @@ -141,7 +141,7 @@ parameter_types! { pub const ReserveId: [u8; 8] = *b"brdgrlrs"; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Hash = ThisChainHash; type Hashing = ThisChainHasher; @@ -158,12 +158,13 @@ impl pallet_utility::Config for TestRuntime { type WeightInfo = (); } -#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for TestRuntime { type ReserveIdentifier = [u8; 8]; type AccountStore = System; } +#[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig)] impl pallet_transaction_payment::Config for TestRuntime { type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; type OperationalFeeMultiplier = ConstU8<5>; diff --git a/bridges/modules/grandpa/src/mock.rs b/bridges/modules/grandpa/src/mock.rs index e41e89341b3..4318d663a2e 100644 --- a/bridges/modules/grandpa/src/mock.rs +++ b/bridges/modules/grandpa/src/mock.rs @@ -42,7 +42,7 @@ construct_runtime! { } } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; } diff --git a/bridges/modules/messages/src/mock.rs b/bridges/modules/messages/src/mock.rs index af921205398..ec63f15b94b 100644 --- a/bridges/modules/messages/src/mock.rs +++ b/bridges/modules/messages/src/mock.rs @@ -77,14 +77,14 @@ frame_support::construct_runtime! { pub type DbWeight = RocksDbWeight; -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; type AccountData = pallet_balances::AccountData; type DbWeight = DbWeight; } -#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for TestRuntime { type ReserveIdentifier = [u8; 8]; type AccountStore = System; diff --git a/bridges/modules/parachains/src/mock.rs b/bridges/modules/parachains/src/mock.rs index 143f11d9863..3af3fd3e763 100644 --- a/bridges/modules/parachains/src/mock.rs +++ b/bridges/modules/parachains/src/mock.rs @@ -161,7 +161,7 @@ construct_runtime! { } } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; } diff --git a/bridges/modules/relayers/src/mock.rs b/bridges/modules/relayers/src/mock.rs index 667b10e5c12..3124787896c 100644 --- a/bridges/modules/relayers/src/mock.rs +++ b/bridges/modules/relayers/src/mock.rs @@ -59,14 +59,14 @@ parameter_types! { pub const Lease: BlockNumber = 8; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; type AccountData = pallet_balances::AccountData; type DbWeight = DbWeight; } -#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for TestRuntime { type ReserveIdentifier = [u8; 8]; type AccountStore = System; diff --git a/bridges/modules/xcm-bridge-hub-router/src/mock.rs b/bridges/modules/xcm-bridge-hub-router/src/mock.rs index 6dbfba5f6fd..54e10966d51 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/mock.rs @@ -64,7 +64,7 @@ parameter_types! { pub UnknownXcmVersionLocation: Location = Location::new(2, [GlobalConsensus(BridgedNetworkId::get()), Parachain(9999)]); } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; } diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index e40e1f9fb65..4c09bce56d7 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -64,7 +64,7 @@ parameter_types! { pub const ExistentialDeposit: Balance = 1; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type AccountId = AccountId; type AccountData = pallet_balances::AccountData; @@ -72,7 +72,7 @@ impl frame_system::Config for TestRuntime { type Lookup = IdentityLookup; } -#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for TestRuntime { type AccountStore = System; } diff --git a/bridges/snowbridge/pallets/ethereum-client/src/mock.rs b/bridges/snowbridge/pallets/ethereum-client/src/mock.rs index 3ce34eee191..799b14f4773 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/mock.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/mock.rs @@ -95,7 +95,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; } diff --git a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs index 749fb0367f3..086b27cb828 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs @@ -47,7 +47,7 @@ parameter_types! { type Balance = u128; -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = Everything; type RuntimeOrigin = RuntimeOrigin; diff --git a/bridges/snowbridge/pallets/outbound-queue/src/mock.rs b/bridges/snowbridge/pallets/outbound-queue/src/mock.rs index 6e78fb44672..850b13dcf31 100644 --- a/bridges/snowbridge/pallets/outbound-queue/src/mock.rs +++ b/bridges/snowbridge/pallets/outbound-queue/src/mock.rs @@ -37,7 +37,7 @@ parameter_types! { pub const BlockHashCount: u64 = 250; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = Everything; type RuntimeOrigin = RuntimeOrigin; diff --git a/bridges/snowbridge/pallets/system/src/mock.rs b/bridges/snowbridge/pallets/system/src/mock.rs index de2970dd550..a711eab5d3d 100644 --- a/bridges/snowbridge/pallets/system/src/mock.rs +++ b/bridges/snowbridge/pallets/system/src/mock.rs @@ -95,7 +95,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type RuntimeOrigin = RuntimeOrigin; diff --git a/bridges/snowbridge/parachain/pallets/ethereum-beacon-client/src/mock.rs b/bridges/snowbridge/parachain/pallets/ethereum-beacon-client/src/mock.rs index 77b5c1aa631..d2cca373e92 100644 --- a/bridges/snowbridge/parachain/pallets/ethereum-beacon-client/src/mock.rs +++ b/bridges/snowbridge/parachain/pallets/ethereum-beacon-client/src/mock.rs @@ -34,7 +34,7 @@ pub mod minimal { pub const SS58Prefix: u8 = 42; } - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type RuntimeOrigin = RuntimeOrigin; @@ -195,7 +195,7 @@ pub mod mainnet { pub const SS58Prefix: u8 = 42; } - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type RuntimeOrigin = RuntimeOrigin; diff --git a/cumulus/pallets/collator-selection/src/mock.rs b/cumulus/pallets/collator-selection/src/mock.rs index fe41e7318bc..061d8b1cb31 100644 --- a/cumulus/pallets/collator-selection/src/mock.rs +++ b/cumulus/pallets/collator-selection/src/mock.rs @@ -50,7 +50,7 @@ parameter_types! { pub const SS58Prefix: u8 = 42; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/cumulus/pallets/dmp-queue/src/mock.rs b/cumulus/pallets/dmp-queue/src/mock.rs index 6bd74a047eb..ed72ce678e3 100644 --- a/cumulus/pallets/dmp-queue/src/mock.rs +++ b/cumulus/pallets/dmp-queue/src/mock.rs @@ -35,7 +35,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type Block = Block; type RuntimeOrigin = RuntimeOrigin; diff --git a/cumulus/pallets/parachain-system/src/mock.rs b/cumulus/pallets/parachain-system/src/mock.rs index b76553a5384..0b1d536ba7c 100644 --- a/cumulus/pallets/parachain-system/src/mock.rs +++ b/cumulus/pallets/parachain-system/src/mock.rs @@ -71,7 +71,7 @@ parameter_types! { pub const ReservedDmpWeight: Weight = Weight::zero(); } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type BlockHashCount = BlockHashCount; diff --git a/cumulus/pallets/xcmp-queue/src/mock.rs b/cumulus/pallets/xcmp-queue/src/mock.rs index 1fb88cafd93..294f978f6ad 100644 --- a/cumulus/pallets/xcmp-queue/src/mock.rs +++ b/cumulus/pallets/xcmp-queue/src/mock.rs @@ -58,7 +58,7 @@ parameter_types! { type AccountId = u64; -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = Everything; type BlockWeights = (); diff --git a/cumulus/parachains/common/src/impls.rs b/cumulus/parachains/common/src/impls.rs index 957538b7cda..6a990740f0f 100644 --- a/cumulus/parachains/common/src/impls.rs +++ b/cumulus/parachains/common/src/impls.rs @@ -217,7 +217,7 @@ mod tests { pub const MaxReserves: u32 = 50; } - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type RuntimeOrigin = RuntimeOrigin; diff --git a/cumulus/parachains/pallets/collective-content/src/mock.rs b/cumulus/parachains/pallets/collective-content/src/mock.rs index 7a752da71fc..5cb0126425e 100644 --- a/cumulus/parachains/pallets/collective-content/src/mock.rs +++ b/cumulus/parachains/pallets/collective-content/src/mock.rs @@ -55,7 +55,7 @@ impl pallet_collective_content::Config for Test { type WeightInfo = CCWeightInfo; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = (); type BlockWeights = (); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 17a12dd2f6f..7da9869dd2c 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -165,7 +165,7 @@ parameter_types! { } // Configure FRAME pallets to include in runtime. -#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig)] impl frame_system::Config for Runtime { type BlockWeights = RuntimeBlockWeights; type BlockLength = RuntimeBlockLength; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 1ead2897855..3d69e104bd5 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -149,7 +149,7 @@ parameter_types! { } // Configure FRAME pallets to include in runtime. -#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig)] impl frame_system::Config for Runtime { type BlockWeights = RuntimeBlockWeights; type BlockLength = RuntimeBlockLength; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 0b48d1717fa..843acffe03e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -242,7 +242,7 @@ parameter_types! { // Configure FRAME pallets to include in runtime. -#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig)] impl frame_system::Config for Runtime { /// The identifier used to distinguish between accounts. type AccountId = AccountId; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index e1344fce63d..d70d880c50c 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -216,7 +216,7 @@ parameter_types! { // Configure FRAME pallets to include in runtime. -#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig)] impl frame_system::Config for Runtime { /// The identifier used to distinguish between accounts. type AccountId = AccountId; diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index 6bcf98c428f..15a2391fa5b 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -161,7 +161,7 @@ parameter_types! { } // Configure FRAME pallets to include in runtime. -#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig)] impl frame_system::Config for Runtime { type BlockWeights = RuntimeBlockWeights; type BlockLength = RuntimeBlockLength; diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 0668b9a4c7d..928c3ecc532 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -171,7 +171,7 @@ parameter_types! { } // Configure FRAME pallets to include in runtime. -#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig)] impl frame_system::Config for Runtime { type BlockWeights = RuntimeBlockWeights; type BlockLength = RuntimeBlockLength; diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs index cdff371c505..41b9ffa0af8 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs @@ -172,7 +172,7 @@ parameter_types! { } // Configure FRAME pallets to include in runtime. -#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig)] impl frame_system::Config for Runtime { /// The identifier used to distinguish between accounts. type AccountId = AccountId; diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs index 7fa70647992..d93c2a61ff4 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs @@ -172,7 +172,7 @@ parameter_types! { } // Configure FRAME pallets to include in runtime. -#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig)] impl frame_system::Config for Runtime { /// The identifier used to distinguish between accounts. type AccountId = AccountId; diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs index 232a82115a8..6967ac58e3b 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs @@ -146,7 +146,7 @@ parameter_types! { pub const SS58Prefix: u8 = 42; } -#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig)] impl frame_system::Config for Runtime { type AccountId = AccountId; type Nonce = Nonce; diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs index 2b8cc32f67c..05da00ac555 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs @@ -164,7 +164,7 @@ parameter_types! { pub const SS58Prefix: u8 = 42; } -#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = Everything; type BlockWeights = RuntimeBlockWeights; diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs index 2dc2d06a66b..e921df1e5da 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs @@ -164,7 +164,7 @@ parameter_types! { pub const SS58Prefix: u8 = 42; } -#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = Everything; type BlockWeights = RuntimeBlockWeights; diff --git a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs index 4cc0a81ef49..179bda356ae 100644 --- a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs @@ -135,7 +135,7 @@ parameter_types! { pub const SS58Prefix: u8 = 42; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { /// The identifier used to distinguish between accounts. type AccountId = AccountId; diff --git a/cumulus/parachains/runtimes/starters/shell/src/lib.rs b/cumulus/parachains/runtimes/starters/shell/src/lib.rs index 829754731a4..c0904f0faef 100644 --- a/cumulus/parachains/runtimes/starters/shell/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/shell/src/lib.rs @@ -143,7 +143,7 @@ parameter_types! { pub const SS58Prefix: u8 = 42; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { /// The identifier used to distinguish between accounts. type AccountId = AccountId; diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index bea78e14520..24a325c6f5b 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -326,7 +326,7 @@ parameter_types! { // Configure FRAME pallets to include in runtime. -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { /// The identifier used to distinguish between accounts. type AccountId = AccountId; diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index 2b21a12c3ca..aea139fb66e 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -185,7 +185,7 @@ parameter_types! { pub const SS58Prefix: u8 = 42; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { /// The identifier used to distinguish between accounts. type AccountId = AccountId; diff --git a/cumulus/test/runtime/src/lib.rs b/cumulus/test/runtime/src/lib.rs index 5ccec8983e9..8e3569b02a1 100644 --- a/cumulus/test/runtime/src/lib.rs +++ b/cumulus/test/runtime/src/lib.rs @@ -177,7 +177,7 @@ parameter_types! { pub const SS58Prefix: u8 = 42; } -#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig)] impl frame_system::Config for Runtime { /// The identifier used to distinguish between accounts. type AccountId = AccountId; diff --git a/docs/sdk/src/guides/your_first_pallet/mod.rs b/docs/sdk/src/guides/your_first_pallet/mod.rs index 6a262924824..c633c0a69ed 100644 --- a/docs/sdk/src/guides/your_first_pallet/mod.rs +++ b/docs/sdk/src/guides/your_first_pallet/mod.rs @@ -438,7 +438,7 @@ pub mod pallet { } ); - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type Block = MockBlock; // within pallet we just said `::AccountId`, now we @@ -717,7 +717,7 @@ pub mod pallet_v2 { } ); - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type Block = MockBlock; type AccountId = u64; diff --git a/docs/sdk/src/polkadot_sdk/cumulus.rs b/docs/sdk/src/polkadot_sdk/cumulus.rs index 60c4839f9e2..7d9daf9067c 100644 --- a/docs/sdk/src/polkadot_sdk/cumulus.rs +++ b/docs/sdk/src/polkadot_sdk/cumulus.rs @@ -72,7 +72,7 @@ mod tests { mod system_pallets { use super::*; - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type Block = MockBlock; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; @@ -115,7 +115,7 @@ mod tests { } #[docify::export(timestamp)] - #[derive_impl(pallet_timestamp::config_preludes::TestDefaultConfig as pallet_timestamp::DefaultConfig)] + #[derive_impl(pallet_timestamp::config_preludes::TestDefaultConfig)] impl pallet_timestamp::Config for Runtime {} impl cumulus_pallet_aura_ext::Config for Runtime {} diff --git a/docs/sdk/src/polkadot_sdk/frame_runtime.rs b/docs/sdk/src/polkadot_sdk/frame_runtime.rs index f178fc82bf4..f9b8a381365 100644 --- a/docs/sdk/src/polkadot_sdk/frame_runtime.rs +++ b/docs/sdk/src/polkadot_sdk/frame_runtime.rs @@ -162,7 +162,7 @@ pub mod runtime { ); // These `impl` blocks specify the parameters of each pallet's `trait Config`. - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type Block = MockBlock; } diff --git a/docs/sdk/src/reference_docs/frame_origin.rs b/docs/sdk/src/reference_docs/frame_origin.rs index 49533157b01..a2aac7dd355 100644 --- a/docs/sdk/src/reference_docs/frame_origin.rs +++ b/docs/sdk/src/reference_docs/frame_origin.rs @@ -205,7 +205,7 @@ pub mod runtime_for_origin { } ); - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type Block = MockBlock; } @@ -248,7 +248,7 @@ pub mod runtime_for_external_origin { } ); - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type Block = MockBlock; } diff --git a/docs/sdk/src/reference_docs/frame_pallet_coupling.rs b/docs/sdk/src/reference_docs/frame_pallet_coupling.rs index 942717ecfb2..cca7f9feb3f 100644 --- a/docs/sdk/src/reference_docs/frame_pallet_coupling.rs +++ b/docs/sdk/src/reference_docs/frame_pallet_coupling.rs @@ -280,7 +280,7 @@ pub mod runtime { } ); - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type Block = MockBlock; } diff --git a/docs/sdk/src/reference_docs/frame_runtime_types.rs b/docs/sdk/src/reference_docs/frame_runtime_types.rs index b5838b79e51..32cda5bc534 100644 --- a/docs/sdk/src/reference_docs/frame_runtime_types.rs +++ b/docs/sdk/src/reference_docs/frame_runtime_types.rs @@ -228,7 +228,7 @@ pub mod runtime { } ); - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type Block = MockBlock; } @@ -293,7 +293,7 @@ pub mod runtime_with_specific_runtime_call { } ); - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type Block = MockBlock; } diff --git a/polkadot/runtime/common/src/assigned_slots/mod.rs b/polkadot/runtime/common/src/assigned_slots/mod.rs index 4f032f4dfa3..5f1bc73db96 100644 --- a/polkadot/runtime/common/src/assigned_slots/mod.rs +++ b/polkadot/runtime/common/src/assigned_slots/mod.rs @@ -680,7 +680,7 @@ mod tests { pub const BlockHashCount: u32 = 250; } - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/polkadot/runtime/common/src/auctions.rs b/polkadot/runtime/common/src/auctions.rs index 46ab673a7a0..6914fef99d5 100644 --- a/polkadot/runtime/common/src/auctions.rs +++ b/polkadot/runtime/common/src/auctions.rs @@ -707,7 +707,7 @@ mod tests { pub const BlockHashCount: u32 = 250; } - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/polkadot/runtime/common/src/claims.rs b/polkadot/runtime/common/src/claims.rs index 68f42914e44..49ac4eb8941 100644 --- a/polkadot/runtime/common/src/claims.rs +++ b/polkadot/runtime/common/src/claims.rs @@ -730,7 +730,7 @@ mod tests { } ); - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; diff --git a/polkadot/runtime/common/src/crowdloan/mod.rs b/polkadot/runtime/common/src/crowdloan/mod.rs index 35d075f2ff6..6543bf305c4 100644 --- a/polkadot/runtime/common/src/crowdloan/mod.rs +++ b/polkadot/runtime/common/src/crowdloan/mod.rs @@ -900,7 +900,7 @@ mod tests { type BlockNumber = u64; - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/polkadot/runtime/common/src/impls.rs b/polkadot/runtime/common/src/impls.rs index 4ba85a3c835..acf5a701a62 100644 --- a/polkadot/runtime/common/src/impls.rs +++ b/polkadot/runtime/common/src/impls.rs @@ -264,7 +264,7 @@ mod tests { pub const AvailableBlockRatio: Perbill = Perbill::one(); } - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type RuntimeOrigin = RuntimeOrigin; diff --git a/polkadot/runtime/common/src/integration_tests.rs b/polkadot/runtime/common/src/integration_tests.rs index 3aa291f0f1f..dfd0d356638 100644 --- a/polkadot/runtime/common/src/integration_tests.rs +++ b/polkadot/runtime/common/src/integration_tests.rs @@ -115,7 +115,7 @@ parameter_types! { ); } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = BlockWeights; diff --git a/polkadot/runtime/common/src/paras_registrar/mod.rs b/polkadot/runtime/common/src/paras_registrar/mod.rs index 4541b88ec6f..5b2098388d8 100644 --- a/polkadot/runtime/common/src/paras_registrar/mod.rs +++ b/polkadot/runtime/common/src/paras_registrar/mod.rs @@ -757,7 +757,7 @@ mod tests { limits::BlockLength::max_with_normal_ratio(4 * 1024 * 1024, NORMAL_RATIO); } - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type RuntimeOrigin = RuntimeOrigin; diff --git a/polkadot/runtime/common/src/purchase.rs b/polkadot/runtime/common/src/purchase.rs index 301f1f21fbc..8de93bd68b0 100644 --- a/polkadot/runtime/common/src/purchase.rs +++ b/polkadot/runtime/common/src/purchase.rs @@ -512,7 +512,7 @@ mod tests { pub const BlockHashCount: u32 = 250; } - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/polkadot/runtime/common/src/slots/mod.rs b/polkadot/runtime/common/src/slots/mod.rs index 51bd0ba4deb..a54aaa53f8c 100644 --- a/polkadot/runtime/common/src/slots/mod.rs +++ b/polkadot/runtime/common/src/slots/mod.rs @@ -530,7 +530,7 @@ mod tests { pub const BlockHashCount: u32 = 250; } - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/polkadot/runtime/parachains/src/mock.rs b/polkadot/runtime/parachains/src/mock.rs index e18be03bdeb..7ed62a392e4 100644 --- a/polkadot/runtime/parachains/src/mock.rs +++ b/polkadot/runtime/parachains/src/mock.rs @@ -103,7 +103,7 @@ parameter_types! { pub type AccountId = u64; -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = BlockWeights; diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 96e8c4e0979..1f51258df08 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -185,7 +185,7 @@ parameter_types! { pub const SS58Prefix: u8 = 42; } -#[derive_impl(frame_system::config_preludes::RelayChainDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::RelayChainDefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = EverythingBut; type BlockWeights = BlockWeights; diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 6c899c52701..8a3cd9309db 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -139,7 +139,7 @@ parameter_types! { pub const SS58Prefix: u8 = 42; } -#[derive_impl(frame_system::config_preludes::RelayChainDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::RelayChainDefaultConfig)] impl frame_system::Config for Runtime { type BlockWeights = BlockWeights; type BlockLength = BlockLength; diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index b55d68ee0f6..15d78706d3a 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -186,7 +186,7 @@ parameter_types! { pub const SS58Prefix: u8 = 42; } -#[derive_impl(frame_system::config_preludes::RelayChainDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::RelayChainDefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = EverythingBut; type BlockWeights = BlockWeights; diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs index 637446832fd..c75ecbceb08 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs @@ -46,7 +46,7 @@ parameter_types! { frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1024, u64::MAX)); } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = Everything; type BlockWeights = (); @@ -77,7 +77,7 @@ parameter_types! { pub const ExistentialDeposit: u64 = 7; } -#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type AccountStore = System; diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs index c84f062a8d1..b037d3dd8b2 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs @@ -51,7 +51,7 @@ parameter_types! { frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1024, u64::MAX)); } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = Everything; type BlockWeights = (); @@ -141,7 +141,7 @@ parameter_types! { pub const ExistentialDeposit: u64 = 7; } -#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type AccountStore = System; diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index d5ba7312a3a..77b30b1eaa1 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -241,7 +241,7 @@ parameter_types! { pub const BlockHashCount: u64 = 250; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; diff --git a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs index 9892c500f2e..9feda8fb90b 100644 --- a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs @@ -49,7 +49,7 @@ construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type AccountData = pallet_balances::AccountData; diff --git a/polkadot/xcm/xcm-builder/tests/mock/mod.rs b/polkadot/xcm/xcm-builder/tests/mock/mod.rs index 06cedb9c357..536f8851bb4 100644 --- a/polkadot/xcm/xcm-builder/tests/mock/mod.rs +++ b/polkadot/xcm/xcm-builder/tests/mock/mod.rs @@ -76,7 +76,7 @@ parameter_types! { pub const BlockHashCount: u64 = 250; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain.rs b/polkadot/xcm/xcm-simulator/example/src/parachain.rs index 64333b4d581..50a12a3a698 100644 --- a/polkadot/xcm/xcm-simulator/example/src/parachain.rs +++ b/polkadot/xcm/xcm-simulator/example/src/parachain.rs @@ -63,7 +63,7 @@ parameter_types! { pub const BlockHashCount: u64 = 250; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs index 54c5657c00d..f41e273839b 100644 --- a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs @@ -49,7 +49,7 @@ parameter_types! { pub const BlockHashCount: u64 = 250; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs index a20390b64f9..1130701a344 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs @@ -63,7 +63,7 @@ parameter_types! { pub const BlockHashCount: u32 = 250; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type AccountId = AccountId; type Lookup = AccountIdLookup; diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs index 5bf65fa9f9a..42dd8237cbf 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs @@ -62,7 +62,7 @@ parameter_types! { pub const BlockHashCount: u32 = 250; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type AccountId = AccountId; type Lookup = sp_runtime::traits::AccountIdLookup; diff --git a/prdoc/pr_3505.prdoc b/prdoc/pr_3505.prdoc index 08ad909739c..b55972927c3 100644 --- a/prdoc/pr_3505.prdoc +++ b/prdoc/pr_3505.prdoc @@ -11,7 +11,7 @@ doc: For example, in the following macro invocation ```rust - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { ... } diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 437f76c9d5f..0852264ef68 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -293,7 +293,7 @@ impl pallet_safe_mode::Config for Runtime { type WeightInfo = pallet_safe_mode::weights::SubstrateWeight; } -#[derive_impl(frame_system::config_preludes::SolochainDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::SolochainDefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = InsideBoth; type BlockWeights = RuntimeBlockWeights; diff --git a/substrate/frame/alliance/src/mock.rs b/substrate/frame/alliance/src/mock.rs index fd44d33ef93..b183e412bed 100644 --- a/substrate/frame/alliance/src/mock.rs +++ b/substrate/frame/alliance/src/mock.rs @@ -48,7 +48,7 @@ parameter_types! { frame_system::limits::BlockWeights::simple_max(Weight::MAX); } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type AccountData = pallet_balances::AccountData; diff --git a/substrate/frame/asset-conversion/src/mock.rs b/substrate/frame/asset-conversion/src/mock.rs index 870538a68cc..4591b87c186 100644 --- a/substrate/frame/asset-conversion/src/mock.rs +++ b/substrate/frame/asset-conversion/src/mock.rs @@ -53,7 +53,7 @@ construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type AccountId = u128; type Lookup = IdentityLookup; diff --git a/substrate/frame/asset-rate/src/mock.rs b/substrate/frame/asset-rate/src/mock.rs index 5981b056764..d01996dab19 100644 --- a/substrate/frame/asset-rate/src/mock.rs +++ b/substrate/frame/asset-rate/src/mock.rs @@ -32,7 +32,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type AccountData = pallet_balances::AccountData; diff --git a/substrate/frame/assets/src/lib.rs b/substrate/frame/assets/src/lib.rs index 09d59ae1b8b..583c75b3827 100644 --- a/substrate/frame/assets/src/lib.rs +++ b/substrate/frame/assets/src/lib.rs @@ -232,7 +232,7 @@ pub mod pallet { use frame_support::{derive_impl, traits::ConstU64}; pub struct TestDefaultConfig; - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig, no_aggregated_types)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)] impl frame_system::DefaultConfig for TestDefaultConfig {} #[frame_support::register_default_impl(TestDefaultConfig)] diff --git a/substrate/frame/assets/src/mock.rs b/substrate/frame/assets/src/mock.rs index 906febb0214..f6173a451ff 100644 --- a/substrate/frame/assets/src/mock.rs +++ b/substrate/frame/assets/src/mock.rs @@ -42,7 +42,7 @@ construct_runtime!( type AccountId = u64; type AssetId = u32; -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type AccountData = pallet_balances::AccountData; diff --git a/substrate/frame/atomic-swap/src/tests.rs b/substrate/frame/atomic-swap/src/tests.rs index 4b444d888ed..9f51f04208a 100644 --- a/substrate/frame/atomic-swap/src/tests.rs +++ b/substrate/frame/atomic-swap/src/tests.rs @@ -37,7 +37,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type AccountData = pallet_balances::AccountData; diff --git a/substrate/frame/aura/src/mock.rs b/substrate/frame/aura/src/mock.rs index 8bc3e407158..535e27fa35e 100644 --- a/substrate/frame/aura/src/mock.rs +++ b/substrate/frame/aura/src/mock.rs @@ -40,7 +40,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; } diff --git a/substrate/frame/authority-discovery/src/lib.rs b/substrate/frame/authority-discovery/src/lib.rs index 2b4dfaf1aea..aa57378934a 100644 --- a/substrate/frame/authority-discovery/src/lib.rs +++ b/substrate/frame/authority-discovery/src/lib.rs @@ -222,7 +222,7 @@ mod tests { pub const Offset: BlockNumber = 0; } - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type AccountId = AuthorityId; type Lookup = IdentityLookup; diff --git a/substrate/frame/authorship/src/lib.rs b/substrate/frame/authorship/src/lib.rs index 8b38a58d8e7..d8f1baab23c 100644 --- a/substrate/frame/authorship/src/lib.rs +++ b/substrate/frame/authorship/src/lib.rs @@ -113,7 +113,7 @@ mod tests { } ); - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; } diff --git a/substrate/frame/babe/src/mock.rs b/substrate/frame/babe/src/mock.rs index b693f4fce9b..ec54275278e 100644 --- a/substrate/frame/babe/src/mock.rs +++ b/substrate/frame/babe/src/mock.rs @@ -63,7 +63,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type AccountData = pallet_balances::AccountData; diff --git a/substrate/frame/bags-list/src/mock.rs b/substrate/frame/bags-list/src/mock.rs index 4282120983b..ea677cb9e73 100644 --- a/substrate/frame/bags-list/src/mock.rs +++ b/substrate/frame/bags-list/src/mock.rs @@ -48,7 +48,7 @@ impl frame_election_provider_support::ScoreProvider for StakingMock { } } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type Block = Block; type AccountData = pallet_balances::AccountData; diff --git a/substrate/frame/balances/src/lib.rs b/substrate/frame/balances/src/lib.rs index e87aa6f9311..3fd3102cd35 100644 --- a/substrate/frame/balances/src/lib.rs +++ b/substrate/frame/balances/src/lib.rs @@ -219,7 +219,7 @@ pub mod pallet { pub struct TestDefaultConfig; - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig, no_aggregated_types)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)] impl frame_system::DefaultConfig for TestDefaultConfig {} #[frame_support::register_default_impl(TestDefaultConfig)] diff --git a/substrate/frame/balances/src/tests/mod.rs b/substrate/frame/balances/src/tests/mod.rs index 599909fa943..f2f107d8bd6 100644 --- a/substrate/frame/balances/src/tests/mod.rs +++ b/substrate/frame/balances/src/tests/mod.rs @@ -90,12 +90,13 @@ parameter_types! { pub static ExistentialDeposit: u64 = 1; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type AccountData = super::AccountData; } +#[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig)] impl pallet_transaction_payment::Config for Test { type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = CurrencyAdapter, ()>; diff --git a/substrate/frame/beefy-mmr/src/mock.rs b/substrate/frame/beefy-mmr/src/mock.rs index 94149ac6776..9d1ece7a1d8 100644 --- a/substrate/frame/beefy-mmr/src/mock.rs +++ b/substrate/frame/beefy-mmr/src/mock.rs @@ -57,7 +57,7 @@ construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; } diff --git a/substrate/frame/beefy/src/mock.rs b/substrate/frame/beefy/src/mock.rs index 9cce479890a..fccc63bd1b4 100644 --- a/substrate/frame/beefy/src/mock.rs +++ b/substrate/frame/beefy/src/mock.rs @@ -62,7 +62,7 @@ construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type AccountData = pallet_balances::AccountData; diff --git a/substrate/frame/benchmarking/pov/src/benchmarking.rs b/substrate/frame/benchmarking/pov/src/benchmarking.rs index 84d81890b17..d78cb553318 100644 --- a/substrate/frame/benchmarking/pov/src/benchmarking.rs +++ b/substrate/frame/benchmarking/pov/src/benchmarking.rs @@ -355,7 +355,7 @@ mod mock { } ); - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/benchmarking/pov/src/tests.rs b/substrate/frame/benchmarking/pov/src/tests.rs index 7fa2fb97dea..cec42057454 100644 --- a/substrate/frame/benchmarking/pov/src/tests.rs +++ b/substrate/frame/benchmarking/pov/src/tests.rs @@ -175,7 +175,7 @@ mod mock { } ); - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/benchmarking/src/baseline.rs b/substrate/frame/benchmarking/src/baseline.rs index 2fd3b634ae7..e76d5aed7b8 100644 --- a/substrate/frame/benchmarking/src/baseline.rs +++ b/substrate/frame/benchmarking/src/baseline.rs @@ -125,7 +125,7 @@ pub mod mock { } ); - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/benchmarking/src/tests.rs b/substrate/frame/benchmarking/src/tests.rs index f47a3d9f96a..206ae515aac 100644 --- a/substrate/frame/benchmarking/src/tests.rs +++ b/substrate/frame/benchmarking/src/tests.rs @@ -75,7 +75,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/benchmarking/src/tests_instance.rs b/substrate/frame/benchmarking/src/tests_instance.rs index c28aa694a13..d6e1cf99ef7 100644 --- a/substrate/frame/benchmarking/src/tests_instance.rs +++ b/substrate/frame/benchmarking/src/tests_instance.rs @@ -85,7 +85,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/bounties/src/tests.rs b/substrate/frame/bounties/src/tests.rs index da6596617da..de747db5374 100644 --- a/substrate/frame/bounties/src/tests.rs +++ b/substrate/frame/bounties/src/tests.rs @@ -58,7 +58,7 @@ parameter_types! { type Balance = u64; -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type AccountId = u128; // u64 is not enough to hold bytes used to generate bounty account type Lookup = IdentityLookup; diff --git a/substrate/frame/broker/src/mock.rs b/substrate/frame/broker/src/mock.rs index ac327c4143e..c7205058c97 100644 --- a/substrate/frame/broker/src/mock.rs +++ b/substrate/frame/broker/src/mock.rs @@ -47,7 +47,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; } diff --git a/substrate/frame/child-bounties/src/tests.rs b/substrate/frame/child-bounties/src/tests.rs index 276a90a3e29..30601f821e4 100644 --- a/substrate/frame/child-bounties/src/tests.rs +++ b/substrate/frame/child-bounties/src/tests.rs @@ -61,7 +61,7 @@ parameter_types! { type Balance = u64; -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type AccountId = u128; type Lookup = IdentityLookup; diff --git a/substrate/frame/collective/src/tests.rs b/substrate/frame/collective/src/tests.rs index 02c3377515c..8a80dd167e3 100644 --- a/substrate/frame/collective/src/tests.rs +++ b/substrate/frame/collective/src/tests.rs @@ -87,7 +87,7 @@ parameter_types! { pub static MaxProposalWeight: Weight = default_max_proposal_weight(); } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; } diff --git a/substrate/frame/contracts/mock-network/src/parachain.rs b/substrate/frame/contracts/mock-network/src/parachain.rs index 7a60a66b314..0848f97b09c 100644 --- a/substrate/frame/contracts/mock-network/src/parachain.rs +++ b/substrate/frame/contracts/mock-network/src/parachain.rs @@ -53,7 +53,7 @@ parameter_types! { pub const BlockHashCount: u64 = 250; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; diff --git a/substrate/frame/contracts/mock-network/src/relay_chain.rs b/substrate/frame/contracts/mock-network/src/relay_chain.rs index 6eb9b4e5385..8c79255728e 100644 --- a/substrate/frame/contracts/mock-network/src/relay_chain.rs +++ b/substrate/frame/contracts/mock-network/src/relay_chain.rs @@ -47,7 +47,7 @@ parameter_types! { pub const BlockHashCount: u64 = 250; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; diff --git a/substrate/frame/contracts/src/tests.rs b/substrate/frame/contracts/src/tests.rs index 4c1f65e28d5..db6b2e80d07 100644 --- a/substrate/frame/contracts/src/tests.rs +++ b/substrate/frame/contracts/src/tests.rs @@ -331,7 +331,7 @@ parameter_types! { pub static ExistentialDeposit: u64 = 1; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type AccountId = AccountId32; type Lookup = IdentityLookup; diff --git a/substrate/frame/conviction-voting/src/tests.rs b/substrate/frame/conviction-voting/src/tests.rs index dbcd643b60f..5c582a35362 100644 --- a/substrate/frame/conviction-voting/src/tests.rs +++ b/substrate/frame/conviction-voting/src/tests.rs @@ -47,7 +47,7 @@ impl Contains for BaseFilter { } } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type AccountData = pallet_balances::AccountData; diff --git a/substrate/frame/core-fellowship/src/tests/integration.rs b/substrate/frame/core-fellowship/src/tests/integration.rs index 6f177ba66db..3c2dc1de595 100644 --- a/substrate/frame/core-fellowship/src/tests/integration.rs +++ b/substrate/frame/core-fellowship/src/tests/integration.rs @@ -51,7 +51,7 @@ parameter_types! { frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1_000_000, u64::max_value())); } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; } diff --git a/substrate/frame/core-fellowship/src/tests/unit.rs b/substrate/frame/core-fellowship/src/tests/unit.rs index de8cd858bdf..669517d61a4 100644 --- a/substrate/frame/core-fellowship/src/tests/unit.rs +++ b/substrate/frame/core-fellowship/src/tests/unit.rs @@ -47,7 +47,7 @@ parameter_types! { frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1_000_000, u64::max_value())); } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; } diff --git a/substrate/frame/democracy/src/tests.rs b/substrate/frame/democracy/src/tests.rs index 973e0c28eb2..dd69f48dbc1 100644 --- a/substrate/frame/democracy/src/tests.rs +++ b/substrate/frame/democracy/src/tests.rs @@ -77,7 +77,7 @@ parameter_types! { ); } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = BaseFilter; type Block = Block; diff --git a/substrate/frame/election-provider-multi-phase/src/mock.rs b/substrate/frame/election-provider-multi-phase/src/mock.rs index 18dcd7061c1..92b87d92e99 100644 --- a/substrate/frame/election-provider-multi-phase/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/src/mock.rs @@ -208,7 +208,7 @@ pub fn witness() -> SolutionOrSnapshotSize { .unwrap_or_default() } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type SS58Prefix = (); type BaseCallFilter = frame_support::traits::Everything; diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs index 882b894bb22..d7d2006d219 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs @@ -86,7 +86,7 @@ pub(crate) type VoterIndex = u16; pub(crate) type TargetIndex = u16; pub(crate) type Moment = u32; -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type Block = Block; type AccountData = pallet_balances::AccountData; diff --git a/substrate/frame/election-provider-support/src/onchain.rs b/substrate/frame/election-provider-support/src/onchain.rs index d937f42cb40..ee4f6992a08 100644 --- a/substrate/frame/election-provider-support/src/onchain.rs +++ b/substrate/frame/election-provider-support/src/onchain.rs @@ -199,7 +199,7 @@ mod tests { } ); - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type SS58Prefix = (); type BaseCallFilter = frame_support::traits::Everything; diff --git a/substrate/frame/elections-phragmen/src/lib.rs b/substrate/frame/elections-phragmen/src/lib.rs index 308f2cdc1aa..b4be07030ef 100644 --- a/substrate/frame/elections-phragmen/src/lib.rs +++ b/substrate/frame/elections-phragmen/src/lib.rs @@ -1316,7 +1316,7 @@ mod tests { use sp_runtime::{testing::Header, BuildStorage}; use substrate_test_utils::assert_eq_uvec; - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type AccountData = pallet_balances::AccountData; diff --git a/substrate/frame/examples/basic/src/tests.rs b/substrate/frame/examples/basic/src/tests.rs index 207e46e428d..de37bcf7556 100644 --- a/substrate/frame/examples/basic/src/tests.rs +++ b/substrate/frame/examples/basic/src/tests.rs @@ -45,7 +45,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/examples/default-config/src/lib.rs b/substrate/frame/examples/default-config/src/lib.rs index 224faf9dfd4..5b66c78e062 100644 --- a/substrate/frame/examples/default-config/src/lib.rs +++ b/substrate/frame/examples/default-config/src/lib.rs @@ -87,12 +87,11 @@ pub mod pallet { // This will help use not need to disambiguate anything when using `derive_impl`. use super::*; use frame_support::derive_impl; - use frame_system::config_preludes::TestDefaultConfig as SystemTestDefaultConfig; /// A type providing default configurations for this pallet in testing environment. pub struct TestDefaultConfig; - #[derive_impl(SystemTestDefaultConfig as frame_system::DefaultConfig, no_aggregated_types)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)] impl frame_system::DefaultConfig for TestDefaultConfig {} #[frame_support::register_default_impl(TestDefaultConfig)] @@ -114,7 +113,7 @@ pub mod pallet { /// example, we simple derive `frame_system::config_preludes::TestDefaultConfig` again. pub struct OtherDefaultConfig; - #[derive_impl(SystemTestDefaultConfig as frame_system::DefaultConfig, no_aggregated_types)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)] impl frame_system::DefaultConfig for OtherDefaultConfig {} #[frame_support::register_default_impl(OtherDefaultConfig)] diff --git a/substrate/frame/examples/dev-mode/src/tests.rs b/substrate/frame/examples/dev-mode/src/tests.rs index c13152533fd..1c79b5f5fa6 100644 --- a/substrate/frame/examples/dev-mode/src/tests.rs +++ b/substrate/frame/examples/dev-mode/src/tests.rs @@ -39,7 +39,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/examples/frame-crate/src/lib.rs b/substrate/frame/examples/frame-crate/src/lib.rs index 7e286df1e32..781cba5658d 100644 --- a/substrate/frame/examples/frame-crate/src/lib.rs +++ b/substrate/frame/examples/frame-crate/src/lib.rs @@ -55,7 +55,7 @@ mod tests { } ); - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type Block = MockBlock; } diff --git a/substrate/frame/examples/kitchensink/src/tests.rs b/substrate/frame/examples/kitchensink/src/tests.rs index 7f626718930..1205fefc422 100644 --- a/substrate/frame/examples/kitchensink/src/tests.rs +++ b/substrate/frame/examples/kitchensink/src/tests.rs @@ -37,7 +37,7 @@ frame_support::construct_runtime!( /// Using a default config for [`frame_system`] in tests. See `default-config` example for more /// details. -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type AccountData = pallet_balances::AccountData; diff --git a/substrate/frame/examples/offchain-worker/src/tests.rs b/substrate/frame/examples/offchain-worker/src/tests.rs index ea37a2da493..3525b3b67ed 100644 --- a/substrate/frame/examples/offchain-worker/src/tests.rs +++ b/substrate/frame/examples/offchain-worker/src/tests.rs @@ -46,7 +46,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/examples/single-block-migrations/src/mock.rs b/substrate/frame/examples/single-block-migrations/src/mock.rs index 02f72e01836..68594cc4ad7 100644 --- a/substrate/frame/examples/single-block-migrations/src/mock.rs +++ b/substrate/frame/examples/single-block-migrations/src/mock.rs @@ -34,7 +34,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for MockRuntime { type Block = Block; type AccountData = pallet_balances::AccountData; diff --git a/substrate/frame/examples/split/src/mock.rs b/substrate/frame/examples/split/src/mock.rs index caab4f1ae90..5bf414ee241 100644 --- a/substrate/frame/examples/split/src/mock.rs +++ b/substrate/frame/examples/split/src/mock.rs @@ -31,7 +31,7 @@ frame_support::construct_runtime!( /// Using a default config for [`frame_system`] in tests. See `default-config` example for more /// details. -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; } diff --git a/substrate/frame/examples/tasks/src/mock.rs b/substrate/frame/examples/tasks/src/mock.rs index 5ad104b0dfa..76ac9e76bff 100644 --- a/substrate/frame/examples/tasks/src/mock.rs +++ b/substrate/frame/examples/tasks/src/mock.rs @@ -32,7 +32,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type Block = Block; } diff --git a/substrate/frame/executive/src/tests.rs b/substrate/frame/executive/src/tests.rs index 70b55f6e855..204889a292f 100644 --- a/substrate/frame/executive/src/tests.rs +++ b/substrate/frame/executive/src/tests.rs @@ -309,7 +309,7 @@ parameter_types! { }; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type BlockWeights = BlockWeights; type RuntimeOrigin = RuntimeOrigin; @@ -327,7 +327,7 @@ impl frame_system::Config for Runtime { type Balance = u64; -#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for Runtime { type Balance = Balance; type AccountStore = System; diff --git a/substrate/frame/fast-unstake/src/mock.rs b/substrate/frame/fast-unstake/src/mock.rs index 78d881965a5..b731cb822f3 100644 --- a/substrate/frame/fast-unstake/src/mock.rs +++ b/substrate/frame/fast-unstake/src/mock.rs @@ -43,7 +43,7 @@ parameter_types! { ); } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type Block = Block; type AccountData = pallet_balances::AccountData; diff --git a/substrate/frame/glutton/src/mock.rs b/substrate/frame/glutton/src/mock.rs index 0049800d952..132ef5cfbcb 100644 --- a/substrate/frame/glutton/src/mock.rs +++ b/substrate/frame/glutton/src/mock.rs @@ -31,7 +31,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; } diff --git a/substrate/frame/grandpa/src/mock.rs b/substrate/frame/grandpa/src/mock.rs index 5d48f974c31..4a21da655e5 100644 --- a/substrate/frame/grandpa/src/mock.rs +++ b/substrate/frame/grandpa/src/mock.rs @@ -66,7 +66,7 @@ impl_opaque_keys! { } } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type AccountData = pallet_balances::AccountData; diff --git a/substrate/frame/identity/src/tests.rs b/substrate/frame/identity/src/tests.rs index 60866f12baa..0a9464256ce 100644 --- a/substrate/frame/identity/src/tests.rs +++ b/substrate/frame/identity/src/tests.rs @@ -53,7 +53,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type AccountId = AccountId; type Lookup = IdentityLookup; diff --git a/substrate/frame/im-online/src/mock.rs b/substrate/frame/im-online/src/mock.rs index 9dad148b10f..cc448dc1ae1 100644 --- a/substrate/frame/im-online/src/mock.rs +++ b/substrate/frame/im-online/src/mock.rs @@ -112,7 +112,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { result } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/indices/src/mock.rs b/substrate/frame/indices/src/mock.rs index 5cf82305178..9f8bf8c3758 100644 --- a/substrate/frame/indices/src/mock.rs +++ b/substrate/frame/indices/src/mock.rs @@ -38,7 +38,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/insecure-randomness-collective-flip/src/lib.rs b/substrate/frame/insecure-randomness-collective-flip/src/lib.rs index 04f8cda6541..bdb089a1420 100644 --- a/substrate/frame/insecure-randomness-collective-flip/src/lib.rs +++ b/substrate/frame/insecure-randomness-collective-flip/src/lib.rs @@ -186,7 +186,7 @@ mod tests { ::max(2 * 1024); } - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; } diff --git a/substrate/frame/lottery/src/mock.rs b/substrate/frame/lottery/src/mock.rs index 563ce7202ec..596e1a9d837 100644 --- a/substrate/frame/lottery/src/mock.rs +++ b/substrate/frame/lottery/src/mock.rs @@ -43,7 +43,7 @@ parameter_types! { pub const AvailableBlockRatio: Perbill = Perbill::one(); } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type AccountData = pallet_balances::AccountData; diff --git a/substrate/frame/membership/src/lib.rs b/substrate/frame/membership/src/lib.rs index f4ac697130d..426fc985a52 100644 --- a/substrate/frame/membership/src/lib.rs +++ b/substrate/frame/membership/src/lib.rs @@ -564,7 +564,7 @@ mod tests { pub static Prime: Option = None; } - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; } diff --git a/substrate/frame/merkle-mountain-range/src/mock.rs b/substrate/frame/merkle-mountain-range/src/mock.rs index b3b5127db02..212012a052a 100644 --- a/substrate/frame/merkle-mountain-range/src/mock.rs +++ b/substrate/frame/merkle-mountain-range/src/mock.rs @@ -33,7 +33,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; } diff --git a/substrate/frame/message-queue/src/integration_test.rs b/substrate/frame/message-queue/src/integration_test.rs index ce8eb80805a..26a330cc88e 100644 --- a/substrate/frame/message-queue/src/integration_test.rs +++ b/substrate/frame/message-queue/src/integration_test.rs @@ -52,7 +52,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; } diff --git a/substrate/frame/message-queue/src/mock.rs b/substrate/frame/message-queue/src/mock.rs index d176a981ca8..f22f318b8ef 100644 --- a/substrate/frame/message-queue/src/mock.rs +++ b/substrate/frame/message-queue/src/mock.rs @@ -37,7 +37,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; } diff --git a/substrate/frame/migrations/src/mock.rs b/substrate/frame/migrations/src/mock.rs index 37292647554..bcd6a189c5b 100644 --- a/substrate/frame/migrations/src/mock.rs +++ b/substrate/frame/migrations/src/mock.rs @@ -40,7 +40,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type PalletInfo = PalletInfo; diff --git a/substrate/frame/multisig/src/tests.rs b/substrate/frame/multisig/src/tests.rs index 887c7f8bebc..0d73e3db661 100644 --- a/substrate/frame/multisig/src/tests.rs +++ b/substrate/frame/multisig/src/tests.rs @@ -38,7 +38,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type BlockHashCount = ConstU32<250>; @@ -47,7 +47,7 @@ impl frame_system::Config for Test { type BaseCallFilter = TestBaseCallFilter; } -#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type AccountStore = System; diff --git a/substrate/frame/nft-fractionalization/src/mock.rs b/substrate/frame/nft-fractionalization/src/mock.rs index a4138615009..82a60881626 100644 --- a/substrate/frame/nft-fractionalization/src/mock.rs +++ b/substrate/frame/nft-fractionalization/src/mock.rs @@ -49,7 +49,7 @@ construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type AccountId = AccountId; type Lookup = IdentityLookup; diff --git a/substrate/frame/nfts/src/mock.rs b/substrate/frame/nfts/src/mock.rs index e86fafd07e9..51cfd5f244b 100644 --- a/substrate/frame/nfts/src/mock.rs +++ b/substrate/frame/nfts/src/mock.rs @@ -45,7 +45,7 @@ pub type Signature = MultiSignature; pub type AccountPublic = ::Signer; pub type AccountId = ::AccountId; -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type AccountId = AccountId; type Lookup = IdentityLookup; diff --git a/substrate/frame/nis/src/mock.rs b/substrate/frame/nis/src/mock.rs index 03976bc66c4..33464db34c3 100644 --- a/substrate/frame/nis/src/mock.rs +++ b/substrate/frame/nis/src/mock.rs @@ -44,7 +44,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type AccountData = pallet_balances::AccountData; diff --git a/substrate/frame/node-authorization/src/mock.rs b/substrate/frame/node-authorization/src/mock.rs index 84ca4d7eff7..656d2bfa39a 100644 --- a/substrate/frame/node-authorization/src/mock.rs +++ b/substrate/frame/node-authorization/src/mock.rs @@ -34,7 +34,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; } diff --git a/substrate/frame/nomination-pools/benchmarking/src/mock.rs b/substrate/frame/nomination-pools/benchmarking/src/mock.rs index 4e57c00849f..1c513a1007c 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/mock.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/mock.rs @@ -28,7 +28,7 @@ type Nonce = u32; type BlockNumber = u64; type Balance = u128; -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs index f982b72c635..686759604c2 100644 --- a/substrate/frame/nomination-pools/src/mock.rs +++ b/substrate/frame/nomination-pools/src/mock.rs @@ -222,7 +222,7 @@ impl sp_staking::StakingInterface for StakingMock { } } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type SS58Prefix = (); type BaseCallFilter = frame_support::traits::Everything; diff --git a/substrate/frame/nomination-pools/test-staking/src/mock.rs b/substrate/frame/nomination-pools/test-staking/src/mock.rs index ce97e13d640..22939ff5e23 100644 --- a/substrate/frame/nomination-pools/test-staking/src/mock.rs +++ b/substrate/frame/nomination-pools/test-staking/src/mock.rs @@ -38,7 +38,7 @@ pub(crate) type T = Runtime; pub(crate) const POOL1_BONDED: AccountId = 20318131474730217858575332831085u128; pub(crate) const POOL1_REWARD: AccountId = 20397359637244482196168876781421u128; -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/offences/benchmarking/src/mock.rs b/substrate/frame/offences/benchmarking/src/mock.rs index 01ad8d64f10..ea2e9e93ed6 100644 --- a/substrate/frame/offences/benchmarking/src/mock.rs +++ b/substrate/frame/offences/benchmarking/src/mock.rs @@ -40,7 +40,7 @@ type AccountId = u64; type Nonce = u32; type Balance = u64; -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/offences/src/mock.rs b/substrate/frame/offences/src/mock.rs index d97be99def1..31d5f805f3e 100644 --- a/substrate/frame/offences/src/mock.rs +++ b/substrate/frame/offences/src/mock.rs @@ -74,7 +74,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/paged-list/src/mock.rs b/substrate/frame/paged-list/src/mock.rs index 37bdc4f157c..5d06170aae7 100644 --- a/substrate/frame/paged-list/src/mock.rs +++ b/substrate/frame/paged-list/src/mock.rs @@ -41,7 +41,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/parameters/src/lib.rs b/substrate/frame/parameters/src/lib.rs index 91cf10ba93f..3e54eb6d67f 100644 --- a/substrate/frame/parameters/src/lib.rs +++ b/substrate/frame/parameters/src/lib.rs @@ -225,7 +225,7 @@ pub mod pallet { /// A configuration for testing. pub struct TestDefaultConfig; - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig, no_aggregated_types)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)] impl frame_system::DefaultConfig for TestDefaultConfig {} #[frame_support::register_default_impl(TestDefaultConfig)] diff --git a/substrate/frame/parameters/src/tests/mock.rs b/substrate/frame/parameters/src/tests/mock.rs index 98612dc6a6d..4c7dda639a9 100644 --- a/substrate/frame/parameters/src/tests/mock.rs +++ b/substrate/frame/parameters/src/tests/mock.rs @@ -28,13 +28,13 @@ use frame_support::{ use crate as pallet_parameters; use crate::*; -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type Block = frame_system::mocking::MockBlock; type AccountData = pallet_balances::AccountData<::Balance>; } -#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for Runtime { type ReserveIdentifier = [u8; 8]; type AccountStore = System; @@ -112,7 +112,7 @@ mod custom_origin { } #[docify::export(impl_config)] -#[derive_impl(pallet_parameters::config_preludes::TestDefaultConfig as pallet_parameters::DefaultConfig)] +#[derive_impl(pallet_parameters::config_preludes::TestDefaultConfig)] impl Config for Runtime { type AdminOrigin = custom_origin::ParamsManager; // RuntimeParameters is injected by the `derive_impl` macro. diff --git a/substrate/frame/parameters/src/tests/test_renamed.rs b/substrate/frame/parameters/src/tests/test_renamed.rs index b2e0c1fd966..cfc870fbe10 100644 --- a/substrate/frame/parameters/src/tests/test_renamed.rs +++ b/substrate/frame/parameters/src/tests/test_renamed.rs @@ -31,13 +31,13 @@ use crate::*; use dynamic_params::*; use RuntimeParametersRenamed::*; -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type Block = frame_system::mocking::MockBlock; type AccountData = pallet_balances::AccountData<::Balance>; } -#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for Runtime { type ReserveIdentifier = [u8; 8]; type AccountStore = System; @@ -80,7 +80,7 @@ impl Default for RuntimeParametersRenamed { } } -#[derive_impl(pallet_parameters::config_preludes::TestDefaultConfig as pallet_parameters::DefaultConfig)] +#[derive_impl(pallet_parameters::config_preludes::TestDefaultConfig)] impl Config for Runtime { type AdminOrigin = AsEnsureOriginWithArg>; type RuntimeParameters = RuntimeParametersRenamed; diff --git a/substrate/frame/preimage/src/mock.rs b/substrate/frame/preimage/src/mock.rs index a43e8347d76..903c34596ae 100644 --- a/substrate/frame/preimage/src/mock.rs +++ b/substrate/frame/preimage/src/mock.rs @@ -42,7 +42,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type AccountData = pallet_balances::AccountData; diff --git a/substrate/frame/proxy/src/tests.rs b/substrate/frame/proxy/src/tests.rs index 67a662e01b2..3ed61fbedaa 100644 --- a/substrate/frame/proxy/src/tests.rs +++ b/substrate/frame/proxy/src/tests.rs @@ -42,14 +42,14 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type BaseCallFilter = BaseFilter; type AccountData = pallet_balances::AccountData; } -#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type AccountStore = System; diff --git a/substrate/frame/ranked-collective/src/tests.rs b/substrate/frame/ranked-collective/src/tests.rs index 31add52d90a..ad8b7d2a801 100644 --- a/substrate/frame/ranked-collective/src/tests.rs +++ b/substrate/frame/ranked-collective/src/tests.rs @@ -45,7 +45,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; } diff --git a/substrate/frame/recovery/src/mock.rs b/substrate/frame/recovery/src/mock.rs index 89374527e06..bec7e02c128 100644 --- a/substrate/frame/recovery/src/mock.rs +++ b/substrate/frame/recovery/src/mock.rs @@ -37,7 +37,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type AccountData = pallet_balances::AccountData; diff --git a/substrate/frame/referenda/src/mock.rs b/substrate/frame/referenda/src/mock.rs index bfafc107c28..135476d7cb1 100644 --- a/substrate/frame/referenda/src/mock.rs +++ b/substrate/frame/referenda/src/mock.rs @@ -58,7 +58,7 @@ impl Contains for BaseFilter { parameter_types! { pub MaxWeight: Weight = Weight::from_parts(2_000_000_000_000, u64::MAX); } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = BaseFilter; type Block = Block; diff --git a/substrate/frame/remark/src/mock.rs b/substrate/frame/remark/src/mock.rs index d89583513b6..3eaac4ab439 100644 --- a/substrate/frame/remark/src/mock.rs +++ b/substrate/frame/remark/src/mock.rs @@ -32,7 +32,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; } diff --git a/substrate/frame/root-offences/src/mock.rs b/substrate/frame/root-offences/src/mock.rs index 1f7cce27769..626db138c2b 100644 --- a/substrate/frame/root-offences/src/mock.rs +++ b/substrate/frame/root-offences/src/mock.rs @@ -78,7 +78,7 @@ impl sp_runtime::BoundToRuntimeAppPublic for OtherSessionHandler { type Public = UintAuthorityId; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type AccountData = pallet_balances::AccountData; diff --git a/substrate/frame/safe-mode/src/mock.rs b/substrate/frame/safe-mode/src/mock.rs index b4d7a624ea2..fbfc16f4aa2 100644 --- a/substrate/frame/safe-mode/src/mock.rs +++ b/substrate/frame/safe-mode/src/mock.rs @@ -33,7 +33,7 @@ use sp_runtime::{ BuildStorage, }; -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = InsideBoth; type BlockWeights = (); diff --git a/substrate/frame/salary/src/tests/integration.rs b/substrate/frame/salary/src/tests/integration.rs index a49b5637b8a..26afb2d8aba 100644 --- a/substrate/frame/salary/src/tests/integration.rs +++ b/substrate/frame/salary/src/tests/integration.rs @@ -50,7 +50,7 @@ parameter_types! { frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1_000_000, 0)); } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; } diff --git a/substrate/frame/salary/src/tests/unit.rs b/substrate/frame/salary/src/tests/unit.rs index b3fd00ec76b..5e308354116 100644 --- a/substrate/frame/salary/src/tests/unit.rs +++ b/substrate/frame/salary/src/tests/unit.rs @@ -46,7 +46,7 @@ parameter_types! { frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1_000_000, 0)); } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; } diff --git a/substrate/frame/sassafras/src/mock.rs b/substrate/frame/sassafras/src/mock.rs index 5e5909fcb0d..f145bffa3a0 100644 --- a/substrate/frame/sassafras/src/mock.rs +++ b/substrate/frame/sassafras/src/mock.rs @@ -43,7 +43,7 @@ const LOG_TARGET: &str = "sassafras::tests"; const EPOCH_LENGTH: u32 = 10; const MAX_AUTHORITIES: u32 = 100; -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = frame_system::mocking::MockBlock; } diff --git a/substrate/frame/scheduler/src/mock.rs b/substrate/frame/scheduler/src/mock.rs index bf7dac0d53a..8d36ca1c42e 100644 --- a/substrate/frame/scheduler/src/mock.rs +++ b/substrate/frame/scheduler/src/mock.rs @@ -137,7 +137,7 @@ parameter_types! { ); } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl system::Config for Test { type BaseCallFilter = BaseFilter; type Block = Block; diff --git a/substrate/frame/scored-pool/src/mock.rs b/substrate/frame/scored-pool/src/mock.rs index 6fba1bb3d53..9d2f5eb1099 100644 --- a/substrate/frame/scored-pool/src/mock.rs +++ b/substrate/frame/scored-pool/src/mock.rs @@ -46,7 +46,7 @@ ord_parameter_types! { pub const ScoreOrigin: u64 = 3; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type AccountData = pallet_balances::AccountData; diff --git a/substrate/frame/session/benchmarking/src/mock.rs b/substrate/frame/session/benchmarking/src/mock.rs index 2ef8989f4b0..81052141fd8 100644 --- a/substrate/frame/session/benchmarking/src/mock.rs +++ b/substrate/frame/session/benchmarking/src/mock.rs @@ -45,7 +45,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/session/src/mock.rs b/substrate/frame/session/src/mock.rs index 89804f72cd6..25b81668cc0 100644 --- a/substrate/frame/session/src/mock.rs +++ b/substrate/frame/session/src/mock.rs @@ -224,7 +224,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { sp_io::TestExternalities::new(t) } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; } diff --git a/substrate/frame/society/src/mock.rs b/substrate/frame/society/src/mock.rs index 04f3e85f539..3c27c08a106 100644 --- a/substrate/frame/society/src/mock.rs +++ b/substrate/frame/society/src/mock.rs @@ -54,7 +54,7 @@ ord_parameter_types! { pub const MaxBids: u32 = 10; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type AccountId = u128; type Block = Block; @@ -62,7 +62,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; } -#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type AccountStore = System; diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 65e660f248d..6c2ea225ff1 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -118,7 +118,7 @@ parameter_types! { pub static MaxControllersInDeprecationBatch: u32 = 5900; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type DbWeight = RocksDbWeight; type Block = Block; diff --git a/substrate/frame/state-trie-migration/src/lib.rs b/substrate/frame/state-trie-migration/src/lib.rs index 6b3aa9934e0..6e1de865ab4 100644 --- a/substrate/frame/state-trie-migration/src/lib.rs +++ b/substrate/frame/state-trie-migration/src/lib.rs @@ -452,7 +452,7 @@ pub mod pallet { pub struct TestDefaultConfig; - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig, no_aggregated_types)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)] impl frame_system::DefaultConfig for TestDefaultConfig {} #[frame_support::register_default_impl(TestDefaultConfig)] @@ -1131,7 +1131,7 @@ mod mock { pub const SS58Prefix: u8 = 42; } - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type BlockHashCount = ConstU32<250>; @@ -1144,7 +1144,7 @@ mod mock { pub const MigrationMaxKeyLen: u32 = 512; } - #[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] + #[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type AccountStore = System; @@ -1177,7 +1177,7 @@ mod mock { } } - #[derive_impl(super::config_preludes::TestDefaultConfig as pallet_state_trie_migration::DefaultConfig)] + #[derive_impl(super::config_preludes::TestDefaultConfig)] impl pallet_state_trie_migration::Config for Test { type ControlOrigin = EnsureRoot; type Currency = Balances; diff --git a/substrate/frame/statement/src/mock.rs b/substrate/frame/statement/src/mock.rs index 4ab9cf9e0f9..35d51e7a27b 100644 --- a/substrate/frame/statement/src/mock.rs +++ b/substrate/frame/statement/src/mock.rs @@ -43,7 +43,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type AccountId = AccountId32; type Lookup = IdentityLookup; diff --git a/substrate/frame/sudo/src/lib.rs b/substrate/frame/sudo/src/lib.rs index 2ebe4cb0157..d8b734e6bbe 100644 --- a/substrate/frame/sudo/src/lib.rs +++ b/substrate/frame/sudo/src/lib.rs @@ -156,7 +156,7 @@ pub mod pallet { /// Default prelude sensible to be used in a testing environment. pub struct TestDefaultConfig; - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig, no_aggregated_types)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)] impl frame_system::DefaultConfig for TestDefaultConfig {} #[frame_support::register_default_impl(TestDefaultConfig)] diff --git a/substrate/frame/sudo/src/mock.rs b/substrate/frame/sudo/src/mock.rs index 3b907a27168..a3a786c4af3 100644 --- a/substrate/frame/sudo/src/mock.rs +++ b/substrate/frame/sudo/src/mock.rs @@ -104,7 +104,7 @@ impl Contains for BlockEverything { } } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; } diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 4eadd85a9e0..c524f8953a4 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -1933,7 +1933,7 @@ pub mod pallet_macros { /// # use frame_support::__private::TestExternalities; /// # use frame_support::traits::UnfilteredDispatchable; /// # impl custom_pallet::Config for Runtime {} - /// # #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + /// # #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] /// # impl frame_system::Config for Runtime { /// # type Block = frame_system::mocking::MockBlock; /// # } diff --git a/substrate/frame/support/src/tests/mod.rs b/substrate/frame/support/src/tests/mod.rs index c63bfb181c3..88afa243f09 100644 --- a/substrate/frame/support/src/tests/mod.rs +++ b/substrate/frame/support/src/tests/mod.rs @@ -227,7 +227,7 @@ crate::construct_runtime!( } ); -#[crate::derive_impl(self::frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[crate::derive_impl(self::frame_system::config_preludes::TestDefaultConfig as self::frame_system::DefaultConfig)] impl Config for Runtime { type Block = Block; type AccountId = AccountId; diff --git a/substrate/frame/support/test/compile_pass/src/lib.rs b/substrate/frame/support/test/compile_pass/src/lib.rs index 575322df760..07d2f7d9ecd 100644 --- a/substrate/frame/support/test/compile_pass/src/lib.rs +++ b/substrate/frame/support/test/compile_pass/src/lib.rs @@ -51,7 +51,7 @@ parameter_types! { pub const Version: RuntimeVersion = VERSION; } -#[derive_impl(renamed_frame_system::config_preludes::TestDefaultConfig as renamed_frame_system::DefaultConfig)] +#[derive_impl(renamed_frame_system::config_preludes::TestDefaultConfig)] impl renamed_frame_system::Config for Runtime { type BaseCallFilter = Everything; type BlockWeights = (); diff --git a/substrate/frame/support/test/stg_frame_crate/src/lib.rs b/substrate/frame/support/test/stg_frame_crate/src/lib.rs index 59a66851f23..dc5fff65510 100644 --- a/substrate/frame/support/test/stg_frame_crate/src/lib.rs +++ b/substrate/frame/support/test/stg_frame_crate/src/lib.rs @@ -60,7 +60,7 @@ mod tests { impl crate::pallet::Config for Runtime {} - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type Block = Block; } diff --git a/substrate/frame/support/test/tests/composite_enum.rs b/substrate/frame/support/test/tests/composite_enum.rs index b9e9c23c4bc..1f937705823 100644 --- a/substrate/frame/support/test/tests/composite_enum.rs +++ b/substrate/frame/support/test/tests/composite_enum.rs @@ -114,7 +114,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type Block = Block; } diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs b/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs index 78ae6f57f08..26110810250 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs +++ b/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs @@ -36,7 +36,7 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; pub type Block = generic::Block; -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type Block = Block; diff --git a/substrate/frame/support/test/tests/origin.rs b/substrate/frame/support/test/tests/origin.rs index 5682bb500c7..a25c575cc51 100644 --- a/substrate/frame/support/test/tests/origin.rs +++ b/substrate/frame/support/test/tests/origin.rs @@ -170,7 +170,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for RuntimeOriginTest { type BaseCallFilter = BaseCallFilter; type Block = Block; diff --git a/substrate/frame/support/test/tests/pallet.rs b/substrate/frame/support/test/tests/pallet.rs index 607f54ccc13..f41e606ad7c 100644 --- a/substrate/frame/support/test/tests/pallet.rs +++ b/substrate/frame/support/test/tests/pallet.rs @@ -693,7 +693,7 @@ frame_support::parameter_types!( pub const MyGetParam3: u32 = 12; ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type RuntimeOrigin = RuntimeOrigin; diff --git a/substrate/frame/support/test/tests/pallet_instance.rs b/substrate/frame/support/test/tests/pallet_instance.rs index f8cc97623b8..c79cdf93e97 100644 --- a/substrate/frame/support/test/tests/pallet_instance.rs +++ b/substrate/frame/support/test/tests/pallet_instance.rs @@ -296,7 +296,7 @@ pub mod pallet2 { } } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type RuntimeOrigin = RuntimeOrigin; diff --git a/substrate/frame/support/test/tests/pallet_outer_enums_explicit.rs b/substrate/frame/support/test/tests/pallet_outer_enums_explicit.rs index 33b96dea948..8e8079b183c 100644 --- a/substrate/frame/support/test/tests/pallet_outer_enums_explicit.rs +++ b/substrate/frame/support/test/tests/pallet_outer_enums_explicit.rs @@ -25,7 +25,7 @@ pub type Header = sp_runtime::generic::Header; pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type Block = Block; diff --git a/substrate/frame/support/test/tests/pallet_outer_enums_implicit.rs b/substrate/frame/support/test/tests/pallet_outer_enums_implicit.rs index db006fe7935..08b0b919e21 100644 --- a/substrate/frame/support/test/tests/pallet_outer_enums_implicit.rs +++ b/substrate/frame/support/test/tests/pallet_outer_enums_implicit.rs @@ -25,7 +25,7 @@ pub type Header = sp_runtime::generic::Header; pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type Block = Block; diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/dev_mode_valid.rs b/substrate/frame/support/test/tests/pallet_ui/pass/dev_mode_valid.rs index 4dc33991b12..e4ea094d069 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pass/dev_mode_valid.rs +++ b/substrate/frame/support/test/tests/pallet_ui/pass/dev_mode_valid.rs @@ -70,7 +70,7 @@ pub mod pallet { impl Pallet {} } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type RuntimeOrigin = RuntimeOrigin; diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/no_std_genesis_config.rs b/substrate/frame/support/test/tests/pallet_ui/pass/no_std_genesis_config.rs index 7e67193cc76..23e411e1a09 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pass/no_std_genesis_config.rs +++ b/substrate/frame/support/test/tests/pallet_ui/pass/no_std_genesis_config.rs @@ -27,7 +27,7 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type AccountId = AccountId; type Lookup = sp_runtime::traits::IdentityLookup; diff --git a/substrate/frame/support/test/tests/runtime_metadata.rs b/substrate/frame/support/test/tests/runtime_metadata.rs index 40e70b219ba..819ec176d2b 100644 --- a/substrate/frame/support/test/tests/runtime_metadata.rs +++ b/substrate/frame/support/test/tests/runtime_metadata.rs @@ -27,7 +27,7 @@ pub type Header = sp_runtime::generic::Header; pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type BlockWeights = (); type BlockLength = (); diff --git a/substrate/frame/support/test/tests/storage_layers.rs b/substrate/frame/support/test/tests/storage_layers.rs index 88edd7de6ca..caa125153e9 100644 --- a/substrate/frame/support/test/tests/storage_layers.rs +++ b/substrate/frame/support/test/tests/storage_layers.rs @@ -64,7 +64,7 @@ pub type Header = sp_runtime::generic::Header; pub type Block = sp_runtime::generic::Block; -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/support/test/tests/storage_transaction.rs b/substrate/frame/support/test/tests/storage_transaction.rs index f1489a8b0a6..a5bbfd24ab0 100644 --- a/substrate/frame/support/test/tests/storage_transaction.rs +++ b/substrate/frame/support/test/tests/storage_transaction.rs @@ -87,7 +87,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type Block = Block; diff --git a/substrate/frame/support/test/tests/versioned_migration.rs b/substrate/frame/support/test/tests/versioned_migration.rs index dab5e06dc85..3fdfb902129 100644 --- a/substrate/frame/support/test/tests/versioned_migration.rs +++ b/substrate/frame/support/test/tests/versioned_migration.rs @@ -71,7 +71,7 @@ construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type Block = Block; diff --git a/substrate/frame/system/benches/bench.rs b/substrate/frame/system/benches/bench.rs index a0c567bf852..87c5581b2a3 100644 --- a/substrate/frame/system/benches/bench.rs +++ b/substrate/frame/system/benches/bench.rs @@ -60,7 +60,7 @@ frame_support::parameter_types! { ); } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/system/benchmarking/src/mock.rs b/substrate/frame/system/benchmarking/src/mock.rs index edbf74a9a51..39a64ff6177 100644 --- a/substrate/frame/system/benchmarking/src/mock.rs +++ b/substrate/frame/system/benchmarking/src/mock.rs @@ -35,7 +35,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/substrate/frame/system/src/mock.rs b/substrate/frame/system/src/mock.rs index 7059845a7df..e1959e572e9 100644 --- a/substrate/frame/system/src/mock.rs +++ b/substrate/frame/system/src/mock.rs @@ -78,7 +78,7 @@ impl OnKilledAccount for RecordKilled { } } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl Config for Test { type BlockWeights = RuntimeBlockWeights; type BlockLength = RuntimeBlockLength; diff --git a/substrate/frame/timestamp/src/lib.rs b/substrate/frame/timestamp/src/lib.rs index a62ac6d633d..5269f17eca6 100644 --- a/substrate/frame/timestamp/src/lib.rs +++ b/substrate/frame/timestamp/src/lib.rs @@ -154,7 +154,7 @@ pub mod pallet { /// Default prelude sensible to be used in a testing environment. pub struct TestDefaultConfig; - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig, no_aggregated_types)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)] impl frame_system::DefaultConfig for TestDefaultConfig {} #[frame_support::register_default_impl(TestDefaultConfig)] diff --git a/substrate/frame/timestamp/src/mock.rs b/substrate/frame/timestamp/src/mock.rs index 244b66a4bb2..eb4fdbe71fa 100644 --- a/substrate/frame/timestamp/src/mock.rs +++ b/substrate/frame/timestamp/src/mock.rs @@ -35,7 +35,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; } diff --git a/substrate/frame/tips/src/tests.rs b/substrate/frame/tips/src/tests.rs index 0e7ea1f4781..78df3736815 100644 --- a/substrate/frame/tips/src/tests.rs +++ b/substrate/frame/tips/src/tests.rs @@ -57,7 +57,7 @@ parameter_types! { pub const AvailableBlockRatio: Perbill = Perbill::one(); } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type AccountId = u128; // u64 is not enough to hold bytes used to generate bounty account type Lookup = IdentityLookup; diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs index c8bf2eb8f44..bd9565fe188 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs @@ -84,7 +84,7 @@ parameter_types! { pub static TransactionByteFee: u64 = 1; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = BlockWeights; @@ -168,6 +168,7 @@ impl OnUnbalanced> for DealWithFees } } +#[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig)] impl pallet_transaction_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = CurrencyAdapter; diff --git a/substrate/frame/transaction-payment/asset-tx-payment/src/mock.rs b/substrate/frame/transaction-payment/asset-tx-payment/src/mock.rs index 1f335b4f6c4..4387f319c3b 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/src/mock.rs +++ b/substrate/frame/transaction-payment/asset-tx-payment/src/mock.rs @@ -71,7 +71,7 @@ parameter_types! { pub static TransactionByteFee: u64 = 1; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = BlockWeights; @@ -136,6 +136,7 @@ impl WeightToFeeT for TransactionByteFee { } } +#[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig)] impl pallet_transaction_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = CurrencyAdapter; diff --git a/substrate/frame/transaction-payment/skip-feeless-payment/src/mock.rs b/substrate/frame/transaction-payment/skip-feeless-payment/src/mock.rs index 17c4c773997..5f26680af37 100644 --- a/substrate/frame/transaction-payment/skip-feeless-payment/src/mock.rs +++ b/substrate/frame/transaction-payment/skip-feeless-payment/src/mock.rs @@ -22,7 +22,7 @@ use frame_system as system; type Block = frame_system::mocking::MockBlock; type AccountId = u64; -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type Block = Block; } diff --git a/substrate/frame/transaction-payment/src/lib.rs b/substrate/frame/transaction-payment/src/lib.rs index efadfd60bdd..0e440ee4e9f 100644 --- a/substrate/frame/transaction-payment/src/lib.rs +++ b/substrate/frame/transaction-payment/src/lib.rs @@ -326,7 +326,7 @@ pub mod pallet { /// Default prelude sensible to be used in a testing environment. pub struct TestDefaultConfig; - #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig, no_aggregated_types)] + #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)] impl frame_system::DefaultConfig for TestDefaultConfig {} #[frame_support::register_default_impl(TestDefaultConfig)] diff --git a/substrate/frame/transaction-payment/src/mock.rs b/substrate/frame/transaction-payment/src/mock.rs index 1ca2e3d7347..67ad1caa02f 100644 --- a/substrate/frame/transaction-payment/src/mock.rs +++ b/substrate/frame/transaction-payment/src/mock.rs @@ -70,7 +70,7 @@ parameter_types! { pub static OperationalFeeMultiplier: u8 = 5; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = BlockWeights; diff --git a/substrate/frame/transaction-storage/src/mock.rs b/substrate/frame/transaction-storage/src/mock.rs index 31f539327cd..f1e9e0591f6 100644 --- a/substrate/frame/transaction-storage/src/mock.rs +++ b/substrate/frame/transaction-storage/src/mock.rs @@ -39,7 +39,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type AccountData = pallet_balances::AccountData; @@ -48,7 +48,7 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; } -#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for Test { type AccountStore = System; } diff --git a/substrate/frame/treasury/src/tests.rs b/substrate/frame/treasury/src/tests.rs index b488300de99..67d81cb5c30 100644 --- a/substrate/frame/treasury/src/tests.rs +++ b/substrate/frame/treasury/src/tests.rs @@ -53,7 +53,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type AccountId = u128; // u64 is not enough to hold bytes used to generate bounty account type Lookup = IdentityLookup; diff --git a/substrate/frame/tx-pause/src/mock.rs b/substrate/frame/tx-pause/src/mock.rs index 8ccdc43a46c..5206023838b 100644 --- a/substrate/frame/tx-pause/src/mock.rs +++ b/substrate/frame/tx-pause/src/mock.rs @@ -36,7 +36,7 @@ use sp_runtime::{ parameter_types! { pub const BlockHashCount: u64 = 250; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = InsideBoth; type BlockWeights = (); diff --git a/substrate/frame/uniques/src/mock.rs b/substrate/frame/uniques/src/mock.rs index eae12597163..9fd7f87e159 100644 --- a/substrate/frame/uniques/src/mock.rs +++ b/substrate/frame/uniques/src/mock.rs @@ -37,7 +37,7 @@ construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type AccountData = pallet_balances::AccountData; diff --git a/substrate/frame/utility/src/tests.rs b/substrate/frame/utility/src/tests.rs index 8742513be95..9bcbec99f3b 100644 --- a/substrate/frame/utility/src/tests.rs +++ b/substrate/frame/utility/src/tests.rs @@ -143,7 +143,7 @@ parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(Weight::MAX); } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = TestBaseCallFilter; type BlockWeights = BlockWeights; diff --git a/substrate/frame/vesting/src/mock.rs b/substrate/frame/vesting/src/mock.rs index 8a0cd135125..674a6f6e2a8 100644 --- a/substrate/frame/vesting/src/mock.rs +++ b/substrate/frame/vesting/src/mock.rs @@ -35,7 +35,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type AccountData = pallet_balances::AccountData; type Block = Block; diff --git a/substrate/frame/whitelist/src/mock.rs b/substrate/frame/whitelist/src/mock.rs index e323e806b81..6fb8711057e 100644 --- a/substrate/frame/whitelist/src/mock.rs +++ b/substrate/frame/whitelist/src/mock.rs @@ -37,7 +37,7 @@ construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type AccountData = pallet_balances::AccountData; diff --git a/substrate/test-utils/runtime/src/lib.rs b/substrate/test-utils/runtime/src/lib.rs index 63e0aa6e137..9270978cd12 100644 --- a/substrate/test-utils/runtime/src/lib.rs +++ b/substrate/test-utils/runtime/src/lib.rs @@ -342,7 +342,7 @@ parameter_types! { .build_or_panic(); } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::pallet::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = RuntimeBlockWeights; diff --git a/substrate/utils/frame/rpc/support/src/lib.rs b/substrate/utils/frame/rpc/support/src/lib.rs index 8280c46aadf..a839bbc3402 100644 --- a/substrate/utils/frame/rpc/support/src/lib.rs +++ b/substrate/utils/frame/rpc/support/src/lib.rs @@ -49,7 +49,7 @@ use sp_storage::{StorageData, StorageKey}; /// # /// # type Hash = sp_core::H256; /// # -/// # #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +/// # #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] /// # impl frame_system::Config for TestRuntime { /// # type BaseCallFilter = (); /// # type BlockWeights = (); diff --git a/templates/minimal/runtime/src/lib.rs b/templates/minimal/runtime/src/lib.rs index 91859cf4a2f..00fcaf1cec7 100644 --- a/templates/minimal/runtime/src/lib.rs +++ b/templates/minimal/runtime/src/lib.rs @@ -83,7 +83,7 @@ parameter_types! { pub const Version: RuntimeVersion = VERSION; } -#[derive_impl(frame_system::config_preludes::SolochainDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::SolochainDefaultConfig)] impl frame_system::Config for Runtime { type Block = Block; type Version = Version; @@ -91,18 +91,18 @@ impl frame_system::Config for Runtime { type AccountData = pallet_balances::AccountData<::Balance>; } -#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for Runtime { type AccountStore = System; } -#[derive_impl(pallet_sudo::config_preludes::TestDefaultConfig as pallet_sudo::DefaultConfig)] +#[derive_impl(pallet_sudo::config_preludes::TestDefaultConfig)] impl pallet_sudo::Config for Runtime {} -#[derive_impl(pallet_timestamp::config_preludes::TestDefaultConfig as pallet_timestamp::DefaultConfig)] +#[derive_impl(pallet_timestamp::config_preludes::TestDefaultConfig)] impl pallet_timestamp::Config for Runtime {} -#[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig as pallet_transaction_payment::DefaultConfig)] +#[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig)] impl pallet_transaction_payment::Config for Runtime { type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; type WeightToFee = NoFee<::Balance>; diff --git a/templates/parachain/pallets/template/src/mock.rs b/templates/parachain/pallets/template/src/mock.rs index f510a8b773a..8a88be3e3e9 100644 --- a/templates/parachain/pallets/template/src/mock.rs +++ b/templates/parachain/pallets/template/src/mock.rs @@ -22,7 +22,7 @@ parameter_types! { pub const SS58Prefix: u8 = 42; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl system::Config for Test { type BaseCallFilter = Everything; type BlockWeights = (); diff --git a/templates/parachain/runtime/src/lib.rs b/templates/parachain/runtime/src/lib.rs index 89899d286bb..dcfab59eb81 100644 --- a/templates/parachain/runtime/src/lib.rs +++ b/templates/parachain/runtime/src/lib.rs @@ -277,7 +277,7 @@ parameter_types! { /// The default types are being injected by [`derive_impl`](`frame_support::derive_impl`) from /// [`ParaChainDefaultConfig`](`struct@frame_system::config_preludes::ParaChainDefaultConfig`), /// but overridden as needed. -#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig)] impl frame_system::Config for Runtime { /// The identifier used to distinguish between accounts. type AccountId = AccountId; diff --git a/templates/solochain/pallets/template/src/mock.rs b/templates/solochain/pallets/template/src/mock.rs index 8346461e6ed..3f1fd2dd6d4 100644 --- a/templates/solochain/pallets/template/src/mock.rs +++ b/templates/solochain/pallets/template/src/mock.rs @@ -20,7 +20,7 @@ frame_support::construct_runtime!( } ); -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/templates/solochain/runtime/src/lib.rs b/templates/solochain/runtime/src/lib.rs index a8a5b7857e1..358db0849a0 100644 --- a/templates/solochain/runtime/src/lib.rs +++ b/templates/solochain/runtime/src/lib.rs @@ -148,7 +148,7 @@ parameter_types! { /// The default types are being injected by [`derive_impl`](`frame_support::derive_impl`) from /// [`SoloChainDefaultConfig`](`struct@frame_system::config_preludes::SolochainDefaultConfig`), /// but overridden as needed. -#[derive_impl(frame_system::config_preludes::SolochainDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::SolochainDefaultConfig)] impl frame_system::Config for Runtime { /// The block type for the runtime. type Block = Block; -- GitLab From 4987d7982461e2e5ffe219cdf71ec697284cea7c Mon Sep 17 00:00:00 2001 From: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Date: Fri, 15 Mar 2024 13:42:58 +0200 Subject: [PATCH 043/187] Add elastic scaling support in ParaInherent BenchBuilder (#3690) Extracted Benchbuilder enhancements used in https://github.com/paritytech/polkadot-sdk/pull/3644 . Might still require some work to fully support all scenarios when disputing elastic scaling parachains, but it should be useful in writing elastic scaling runtime tests. --------- Signed-off-by: Andrei Sandu --- polkadot/runtime/parachains/src/builder.rs | 448 +++++++++++------- .../src/paras_inherent/benchmarking.rs | 6 +- .../parachains/src/paras_inherent/tests.rs | 2 +- 3 files changed, 280 insertions(+), 176 deletions(-) diff --git a/polkadot/runtime/parachains/src/builder.rs b/polkadot/runtime/parachains/src/builder.rs index 5b218addb1a..23ec80e66fc 100644 --- a/polkadot/runtime/parachains/src/builder.rs +++ b/polkadot/runtime/parachains/src/builder.rs @@ -39,7 +39,11 @@ use sp_runtime::{ traits::{Header as HeaderT, One, TrailingZeroInput, Zero}, RuntimeAppPublic, }; -use sp_std::{collections::btree_map::BTreeMap, prelude::Vec, vec}; +use sp_std::{ + collections::{btree_map::BTreeMap, vec_deque::VecDeque}, + prelude::Vec, + vec, +}; fn mock_validation_code() -> ValidationCode { ValidationCode(vec![1, 2, 3]) @@ -83,13 +87,18 @@ pub(crate) struct BenchBuilder { /// Optionally set the number of dispute statements for each candidate. dispute_statements: BTreeMap, /// Session index of for each dispute. Index of slice corresponds to a core, - /// which is offset by the number of entries for `backed_and_concluding_cores`. I.E. if - /// `backed_and_concluding_cores` has 3 entries, the first index of `dispute_sessions` + /// which is offset by the number of entries for `backed_and_concluding_paras`. I.E. if + /// `backed_and_concluding_paras` has 3 entries, the first index of `dispute_sessions` /// will correspond to core index 3. There must be one entry for each core with a dispute /// statement set. dispute_sessions: Vec, - /// Map from core seed to number of validity votes. - backed_and_concluding_cores: BTreeMap, + /// Map from para id to number of validity votes. Core indices are generated based on + /// `elastic_paras` configuration. Each para id in `elastic_paras` gets the + /// specified amount of consecutive cores assigned to it. If a para id is not present + /// in `elastic_paras` it get assigned to a single core. + backed_and_concluding_paras: BTreeMap, + /// Map from para id (seed) to number of chained candidates. + elastic_paras: BTreeMap, /// Make every candidate include a code upgrade by setting this to `Some` where the interior /// value is the byte length of the new code. code_upgrade: Option, @@ -106,6 +115,7 @@ pub(crate) struct Bench { pub(crate) _block_number: BlockNumberFor, } +#[allow(dead_code)] impl BenchBuilder { /// Create a new `BenchBuilder` with some opinionated values that should work with the rest /// of the functions in this implementation. @@ -119,7 +129,8 @@ impl BenchBuilder { max_validators: None, dispute_statements: BTreeMap::new(), dispute_sessions: Default::default(), - backed_and_concluding_cores: Default::default(), + backed_and_concluding_paras: Default::default(), + elastic_paras: Default::default(), code_upgrade: None, fill_claimqueue: true, _phantom: sp_std::marker::PhantomData::, @@ -129,7 +140,7 @@ impl BenchBuilder { /// Set the session index for each dispute statement set (in other words, set the session the /// the dispute statement set's relay chain block is from). Indexes of `dispute_sessions` /// correspond to a core, which is offset by the number of entries for - /// `backed_and_concluding_cores`. I.E. if `backed_and_concluding_cores` cores has 3 entries, + /// `backed_and_concluding_paras`. I.E. if `backed_and_concluding_paras` cores has 3 entries, /// the first index of `dispute_sessions` will correspond to core index 3. /// /// Note that there must be an entry for each core with a dispute statement set. @@ -138,12 +149,19 @@ impl BenchBuilder { self } - /// Set a map from core/para id seed to number of validity votes. - pub(crate) fn set_backed_and_concluding_cores( + /// Set a map from para id seed to number of validity votes. + pub(crate) fn set_backed_and_concluding_paras( mut self, - backed_and_concluding_cores: BTreeMap, + backed_and_concluding_paras: BTreeMap, ) -> Self { - self.backed_and_concluding_cores = backed_and_concluding_cores; + self.backed_and_concluding_paras = backed_and_concluding_paras; + self + } + + /// Set a map from para id seed to number of cores assigned to it. + #[cfg(feature = "runtime-benchmarks")] + pub(crate) fn set_elastic_paras(mut self, elastic_paras: BTreeMap) -> Self { + self.elastic_paras = elastic_paras; self } @@ -241,16 +259,6 @@ impl BenchBuilder { (Self::fallback_max_validators() / 2) + 1 } - /// Create para id, core index, and grab the associated group index from the scheduler pallet. - fn create_indexes(&self, seed: u32) -> (ParaId, CoreIndex, GroupIndex) { - let para_id = ParaId::from(seed); - let core_idx = CoreIndex(seed); - let group_idx = - scheduler::Pallet::::group_assigned_to_core(core_idx, self.block_number).unwrap(); - - (para_id, core_idx, group_idx) - } - fn mock_head_data() -> HeadData { let max_head_size = configuration::Pallet::::config().max_head_data_size; HeadData(vec![0xFF; max_head_size as usize]) @@ -321,7 +329,7 @@ impl BenchBuilder { /// Create an `AvailabilityBitfield` where `concluding` is a map where each key is a core index /// that is concluding and `cores` is the total number of cores in the system. - fn availability_bitvec(concluding: &BTreeMap, cores: u32) -> AvailabilityBitfield { + fn availability_bitvec(concluding: &BTreeMap, cores: usize) -> AvailabilityBitfield { let mut bitfields = bitvec::bitvec![u8, bitvec::order::Lsb0; 0; 0]; for i in 0..cores { if concluding.get(&(i as u32)).is_some() { @@ -352,7 +360,7 @@ impl BenchBuilder { /// /// Note that this must be called at least 2 sessions before the target session as there is a /// n+2 session delay for the scheduled actions to take effect. - fn setup_para_ids(cores: u32) { + fn setup_para_ids(cores: usize) { // make sure parachains exist prior to session change. for i in 0..cores { let para_id = ParaId::from(i as u32); @@ -407,7 +415,10 @@ impl BenchBuilder { mut self, target_session: SessionIndex, validators: Vec<(T::AccountId, ValidatorId)>, - total_cores: u32, + // Total cores used in the scenario + total_cores: usize, + // Additional cores for elastic parachains + extra_cores: usize, ) -> Self { let mut block = 1; for session in 0..=target_session { @@ -442,7 +453,8 @@ impl BenchBuilder { self.validators = Some(validators_shuffled); self.block_number = block_number; self.session = target_session; - assert_eq!(paras::Pallet::::parachains().len(), total_cores as usize); + + assert_eq!(paras::Pallet::::parachains().len(), total_cores - extra_cores); self } @@ -453,13 +465,14 @@ impl BenchBuilder { /// to the cores successfully being freed from the candidates being marked as available. fn create_availability_bitfields( &self, - concluding_cores: &BTreeMap, - total_cores: u32, + concluding_paras: &BTreeMap, + elastic_paras: &BTreeMap, + total_cores: usize, ) -> Vec> { let validators = self.validators.as_ref().expect("must have some validators prior to calling"); - let availability_bitvec = Self::availability_bitvec(concluding_cores, total_cores); + let availability_bitvec = Self::availability_bitvec(concluding_paras, total_cores); let bitfields: Vec> = validators .iter() @@ -476,16 +489,27 @@ impl BenchBuilder { }) .collect(); - for (seed, _) in concluding_cores.iter() { + let mut current_core_idx = 0u32; + + for (seed, _) in concluding_paras.iter() { // make sure the candidates that will be concluding are marked as pending availability. - let (para_id, core_idx, group_idx) = self.create_indexes(*seed); - Self::add_availability( - para_id, - core_idx, - group_idx, - Self::validator_availability_votes_yes(validators.len()), - CandidateHash(H256::from(byte32_slice_from(*seed))), - ); + let para_id = ParaId::from(*seed); + + for _chain_idx in 0..elastic_paras.get(&seed).cloned().unwrap_or(1) { + let core_idx = CoreIndex::from(current_core_idx); + let group_idx = + scheduler::Pallet::::group_assigned_to_core(core_idx, self.block_number) + .unwrap(); + + Self::add_availability( + para_id, + core_idx, + group_idx, + Self::validator_availability_votes_yes(validators.len()), + CandidateHash(H256::from(byte32_slice_from(current_core_idx))), + ); + current_core_idx += 1; + } } bitfields @@ -494,112 +518,143 @@ impl BenchBuilder { /// Create backed candidates for `cores_with_backed_candidates`. You need these cores to be /// scheduled _within_ paras inherent, which requires marking the available bitfields as fully /// available. - /// - `cores_with_backed_candidates` Mapping of `para_id`/`core_idx`/`group_idx` seed to number - /// of + /// - `cores_with_backed_candidates` Mapping of `para_id` seed to number of /// validity votes. fn create_backed_candidates( &self, cores_with_backed_candidates: &BTreeMap, + elastic_paras: &BTreeMap, includes_code_upgrade: Option, ) -> Vec> { let validators = self.validators.as_ref().expect("must have some validators prior to calling"); let config = configuration::Pallet::::config(); + let mut current_core_idx = 0u32; cores_with_backed_candidates .iter() - .map(|(seed, num_votes)| { + .flat_map(|(seed, num_votes)| { assert!(*num_votes <= validators.len() as u32); - let (para_id, core_idx, group_idx) = self.create_indexes(*seed); - - // This generates a pair and adds it to the keystore, returning just the public. - let collator_public = CollatorId::generate_pair(None); - let header = Self::header(self.block_number); - let relay_parent = header.hash(); - let head_data = Self::mock_head_data(); - let persisted_validation_data_hash = PersistedValidationData:: { - parent_head: head_data.clone(), - relay_parent_number: self.relay_parent_number(), - relay_parent_storage_root: Default::default(), - max_pov_size: config.max_pov_size, - } - .hash(); - - let pov_hash = Default::default(); - let validation_code_hash = mock_validation_code().hash(); - let payload = collator_signature_payload( - &relay_parent, - ¶_id, - &persisted_validation_data_hash, - &pov_hash, - &validation_code_hash, - ); - let signature = collator_public.sign(&payload).unwrap(); - - // Set the head data so it can be used while validating the signatures on the - // candidate receipt. - paras::Pallet::::heads_insert(¶_id, head_data.clone()); - - let mut past_code_meta = paras::ParaPastCodeMeta::>::default(); - past_code_meta.note_replacement(0u32.into(), 0u32.into()); - - let group_validators = scheduler::Pallet::::group_validators(group_idx).unwrap(); - - let candidate = CommittedCandidateReceipt:: { - descriptor: CandidateDescriptor:: { - para_id, - relay_parent, - collator: collator_public, - persisted_validation_data_hash, - pov_hash, - erasure_root: Default::default(), - signature, - para_head: head_data.hash(), - validation_code_hash, - }, - commitments: CandidateCommitments:: { - upward_messages: Default::default(), - horizontal_messages: Default::default(), - new_validation_code: includes_code_upgrade - .map(|v| ValidationCode(vec![42u8; v as usize])), - head_data, - processed_downward_messages: 0, - hrmp_watermark: self.relay_parent_number(), - }, - }; - - let candidate_hash = candidate.hash(); - - let validity_votes: Vec<_> = group_validators - .iter() - .take(*num_votes as usize) - .map(|val_idx| { - let public = validators.get(*val_idx).unwrap(); - let sig = UncheckedSigned::::benchmark_sign( - public, - CompactStatement::Valid(candidate_hash), - &self.signing_context(), - *val_idx, + + let para_id = ParaId::from(*seed); + let mut prev_head = None; + // How many chained candidates we want to build ? + (0..elastic_paras.get(&seed).cloned().unwrap_or(1)) + .map(|chain_idx| { + let core_idx = CoreIndex::from(current_core_idx); + // Advance core index. + current_core_idx += 1; + let group_idx = scheduler::Pallet::::group_assigned_to_core( + core_idx, + self.block_number, ) - .benchmark_signature(); + .unwrap(); - ValidityAttestation::Explicit(sig.clone()) - }) - .collect(); + // This generates a pair and adds it to the keystore, returning just the + // public. + let collator_public = CollatorId::generate_pair(None); + let header = Self::header(self.block_number); + let relay_parent = header.hash(); - // Check if the elastic scaling bit is set, if so we need to supply the core index - // in the generated candidate. - let core_idx = configuration::Pallet::::config() - .node_features - .get(FeatureIndex::ElasticScalingMVP as usize) - .map(|_the_bit| core_idx); - - BackedCandidate::::new( - candidate, - validity_votes, - bitvec::bitvec![u8, bitvec::order::Lsb0; 1; group_validators.len()], - core_idx, - ) + // Set the head data so it can be used while validating the signatures on + // the candidate receipt. + let mut head_data = Self::mock_head_data(); + + if chain_idx == 0 { + // Only first parahead of the chain needs to be set in storage. + paras::Pallet::::heads_insert(¶_id, head_data.clone()); + } else { + // Make each candidate head data unique to avoid cycles. + head_data.0[0] = chain_idx; + } + + let persisted_validation_data_hash = PersistedValidationData:: { + // To form a chain we set parent head to previous block if any, or + // default to what is in storage already setup. + parent_head: prev_head.take().unwrap_or(head_data.clone()), + relay_parent_number: self.relay_parent_number(), + relay_parent_storage_root: Default::default(), + max_pov_size: config.max_pov_size, + } + .hash(); + + prev_head = Some(head_data.clone()); + + let pov_hash = Default::default(); + let validation_code_hash = mock_validation_code().hash(); + let payload = collator_signature_payload( + &relay_parent, + ¶_id, + &persisted_validation_data_hash, + &pov_hash, + &validation_code_hash, + ); + let signature = collator_public.sign(&payload).unwrap(); + + let mut past_code_meta = + paras::ParaPastCodeMeta::>::default(); + past_code_meta.note_replacement(0u32.into(), 0u32.into()); + + let group_validators = + scheduler::Pallet::::group_validators(group_idx).unwrap(); + + let candidate = CommittedCandidateReceipt:: { + descriptor: CandidateDescriptor:: { + para_id, + relay_parent, + collator: collator_public, + persisted_validation_data_hash, + pov_hash, + erasure_root: Default::default(), + signature, + para_head: head_data.hash(), + validation_code_hash, + }, + commitments: CandidateCommitments:: { + upward_messages: Default::default(), + horizontal_messages: Default::default(), + new_validation_code: includes_code_upgrade + .map(|v| ValidationCode(vec![42u8; v as usize])), + head_data, + processed_downward_messages: 0, + hrmp_watermark: self.relay_parent_number(), + }, + }; + + let candidate_hash = candidate.hash(); + + let validity_votes: Vec<_> = group_validators + .iter() + .take(*num_votes as usize) + .map(|val_idx| { + let public = validators.get(*val_idx).unwrap(); + let sig = UncheckedSigned::::benchmark_sign( + public, + CompactStatement::Valid(candidate_hash), + &self.signing_context(), + *val_idx, + ) + .benchmark_signature(); + + ValidityAttestation::Explicit(sig.clone()) + }) + .collect(); + + // Check if the elastic scaling bit is set, if so we need to supply the core + // index in the generated candidate. + let core_idx = configuration::Pallet::::config() + .node_features + .get(FeatureIndex::ElasticScalingMVP as usize) + .map(|_the_bit| core_idx); + + BackedCandidate::::new( + candidate, + validity_votes, + bitvec::bitvec![u8, bitvec::order::Lsb0; 1; group_validators.len()], + core_idx, + ) + }) + .collect::>() }) .collect() } @@ -616,6 +671,8 @@ impl BenchBuilder { self.validators.as_ref().expect("must have some validators prior to calling"); let dispute_sessions = dispute_sessions.as_ref(); + let mut current_core_idx = start; + (start..last) .map(|seed| { let dispute_session_idx = (seed - start) as usize; @@ -624,7 +681,14 @@ impl BenchBuilder { .cloned() .unwrap_or(self.target_session); - let (para_id, core_idx, group_idx) = self.create_indexes(seed); + let para_id = ParaId::from(seed); + let core_idx = CoreIndex::from(current_core_idx); + current_core_idx +=1; + + let group_idx = + scheduler::Pallet::::group_assigned_to_core(core_idx, self.block_number) + .unwrap(); + let candidate_hash = CandidateHash(H256::from(byte32_slice_from(seed))); let relay_parent = H256::from(byte32_slice_from(seed)); @@ -668,22 +732,29 @@ impl BenchBuilder { /// Build a scenario for testing or benchmarks. /// - /// Note that this API only allows building scenarios where the `backed_and_concluding_cores` + /// Note that this API only allows building scenarios where the `backed_and_concluding_paras` /// are mutually exclusive with the cores for disputes. So - /// `backed_and_concluding_cores.len() + dispute_sessions.len()` must be less than the max + /// `backed_and_concluding_paras.len() + dispute_sessions.len()` must be less than the max /// number of cores. pub(crate) fn build(self) -> Bench { // Make sure relevant storage is cleared. This is just to get the asserts to work when // running tests because it seems the storage is not cleared in between. #[allow(deprecated)] - inclusion::PendingAvailabilityCommitments::::remove_all(None); - #[allow(deprecated)] inclusion::PendingAvailability::::remove_all(None); // We don't allow a core to have both disputes and be marked fully available at this block. - let max_cores = self.max_cores(); + let max_cores = self.max_cores() as usize; + + let extra_cores = self + .elastic_paras + .values() + .map(|count| *count as usize) + .sum::() + .saturating_sub(self.elastic_paras.len() as usize); + let used_cores = - (self.dispute_sessions.len() + self.backed_and_concluding_cores.len()) as u32; + self.dispute_sessions.len() + self.backed_and_concluding_paras.len() + extra_cores; + assert!(used_cores <= max_cores); let fill_claimqueue = self.fill_claimqueue; @@ -691,62 +762,95 @@ impl BenchBuilder { // We are currently in Session 0, so these changes will take effect in Session 2. Self::setup_para_ids(used_cores); configuration::ActiveConfig::::mutate(|c| { - c.scheduler_params.num_cores = used_cores; + c.scheduler_params.num_cores = used_cores as u32; }); let validator_ids = Self::generate_validator_pairs(self.max_validators()); let target_session = SessionIndex::from(self.target_session); - let builder = self.setup_session(target_session, validator_ids, used_cores); + let builder = self.setup_session(target_session, validator_ids, used_cores, extra_cores); - let bitfields = - builder.create_availability_bitfields(&builder.backed_and_concluding_cores, used_cores); - let backed_candidates = builder - .create_backed_candidates(&builder.backed_and_concluding_cores, builder.code_upgrade); + let bitfields = builder.create_availability_bitfields( + &builder.backed_and_concluding_paras, + &builder.elastic_paras, + used_cores, + ); + let backed_candidates = builder.create_backed_candidates( + &builder.backed_and_concluding_paras, + &builder.elastic_paras, + builder.code_upgrade, + ); let disputes = builder.create_disputes( - builder.backed_and_concluding_cores.len() as u32, - used_cores, + builder.backed_and_concluding_paras.len() as u32, + used_cores as u32, builder.dispute_sessions.as_slice(), ); + let mut disputed_cores = (builder.backed_and_concluding_paras.len() as u32.. + used_cores as u32) + .into_iter() + .map(|idx| (idx, 0)) + .collect::>(); + + let mut all_cores = builder.backed_and_concluding_paras.clone(); + all_cores.append(&mut disputed_cores); - assert_eq!( - inclusion::PendingAvailabilityCommitments::::iter().count(), - used_cores as usize, - ); assert_eq!(inclusion::PendingAvailability::::iter().count(), used_cores as usize,); // Mark all the used cores as occupied. We expect that there are - // `backed_and_concluding_cores` that are pending availability and that there are - // `used_cores - backed_and_concluding_cores ` which are about to be disputed. + // `backed_and_concluding_paras` that are pending availability and that there are + // `used_cores - backed_and_concluding_paras ` which are about to be disputed. let now = >::block_number() + One::one(); - let cores = (0..used_cores) - .into_iter() - .map(|i| { - let ttl = configuration::Pallet::::config().scheduler_params.ttl; - // Load an assignment into provider so that one is present to pop - let assignment = ::AssignmentProvider::get_mock_assignment( - CoreIndex(i), - ParaId::from(i), - ); - CoreOccupied::Paras(ParasEntry::new(assignment, now + ttl)) + + let mut core_idx = 0u32; + let elastic_paras = &builder.elastic_paras; + // Assign potentially multiple cores to same parachains, + let cores = all_cores + .iter() + .flat_map(|(para_id, _)| { + (0..elastic_paras.get(¶_id).cloned().unwrap_or(1)) + .map(|_para_local_core_idx| { + let ttl = configuration::Pallet::::config().scheduler_params.ttl; + // Load an assignment into provider so that one is present to pop + let assignment = + ::AssignmentProvider::get_mock_assignment( + CoreIndex(core_idx), + ParaId::from(*para_id), + ); + core_idx += 1; + CoreOccupied::Paras(ParasEntry::new(assignment, now + ttl)) + }) + .collect::>>() }) - .collect(); + .collect::>>(); + scheduler::AvailabilityCores::::set(cores); + + core_idx = 0u32; if fill_claimqueue { - // Add items to claim queue as well: - let cores = (0..used_cores) - .into_iter() - .map(|i| { - let ttl = configuration::Pallet::::config().scheduler_params.ttl; - // Load an assignment into provider so that one is present to pop - let assignment = - ::AssignmentProvider::get_mock_assignment( - CoreIndex(i), - ParaId::from(i), - ); - (CoreIndex(i), [ParasEntry::new(assignment, now + ttl)].into()) + let cores = all_cores + .keys() + .flat_map(|para_id| { + (0..elastic_paras.get(¶_id).cloned().unwrap_or(1)) + .map(|_para_local_core_idx| { + let ttl = configuration::Pallet::::config().scheduler_params.ttl; + // Load an assignment into provider so that one is present to pop + let assignment = + ::AssignmentProvider::get_mock_assignment( + CoreIndex(core_idx), + ParaId::from(*para_id), + ); + + let entry = ( + CoreIndex(core_idx), + [ParasEntry::new(assignment, now + ttl)].into(), + ); + core_idx += 1; + entry + }) + .collect::>)>>() }) - .collect(); + .collect::>>>(); + scheduler::ClaimQueue::::set(cores); } diff --git a/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs b/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs index ad3fa8e0dc7..f3365945758 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs @@ -65,7 +65,7 @@ benchmarks! { .collect(); let scenario = BenchBuilder::::new() - .set_backed_and_concluding_cores(cores_with_backed) + .set_backed_and_concluding_paras(cores_with_backed) .build(); let mut benchmark = scenario.data.clone(); @@ -110,7 +110,7 @@ benchmarks! { .collect(); let scenario = BenchBuilder::::new() - .set_backed_and_concluding_cores(cores_with_backed.clone()) + .set_backed_and_concluding_paras(cores_with_backed.clone()) .build(); let mut benchmark = scenario.data.clone(); @@ -165,7 +165,7 @@ benchmarks! { .collect(); let scenario = BenchBuilder::::new() - .set_backed_and_concluding_cores(cores_with_backed.clone()) + .set_backed_and_concluding_paras(cores_with_backed.clone()) .set_code_upgrade(v) .build(); diff --git a/polkadot/runtime/parachains/src/paras_inherent/tests.rs b/polkadot/runtime/parachains/src/paras_inherent/tests.rs index fb4d1bd2226..41a84175e9a 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/tests.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/tests.rs @@ -64,7 +64,7 @@ mod enter { ) .set_max_validators_per_core(num_validators_per_core) .set_dispute_statements(dispute_statements) - .set_backed_and_concluding_cores(backed_and_concluding) + .set_backed_and_concluding_paras(backed_and_concluding) .set_dispute_sessions(&dispute_sessions[..]) .set_fill_claimqueue(fill_claimqueue); -- GitLab From e8b51f60cce43277301a68d2a69c1bb914853290 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Fri, 15 Mar 2024 18:24:38 +0100 Subject: [PATCH 044/187] Contracts use polkavm workspace deps (#3715) --- Cargo.lock | 61 +++---------------- substrate/frame/contracts/fixtures/Cargo.toml | 2 +- substrate/frame/contracts/fixtures/build.rs | 7 ++- .../frame/contracts/fixtures/build/Cargo.toml | 4 +- substrate/frame/contracts/uapi/Cargo.toml | 2 +- 5 files changed, 19 insertions(+), 57 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e1bd596a7a9..699fd35a824 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9573,7 +9573,7 @@ dependencies = [ "anyhow", "frame-system", "parity-wasm", - "polkavm-linker 0.5.0", + "polkavm-linker", "sp-runtime", "tempfile", "toml 0.8.8", @@ -9634,7 +9634,7 @@ dependencies = [ "bitflags 1.3.2", "parity-scale-codec", "paste", - "polkavm-derive 0.5.0", + "polkavm-derive", "scale-info", ] @@ -13845,7 +13845,7 @@ dependencies = [ "libc", "log", "polkavm-assembler", - "polkavm-common 0.9.0", + "polkavm-common", "polkavm-linux-raw", ] @@ -13858,12 +13858,6 @@ dependencies = [ "log", ] -[[package]] -name = "polkavm-common" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b4e215c80fe876147f3d58158d5dfeae7dabdd6047e175af77095b78d0035c" - [[package]] name = "polkavm-common" version = "0.9.0" @@ -13873,16 +13867,6 @@ dependencies = [ "log", ] -[[package]] -name = "polkavm-derive" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6380dbe1fb03ecc74ad55d841cfc75480222d153ba69ddcb00977866cbdabdb8" -dependencies = [ - "polkavm-derive-impl 0.5.0", - "syn 2.0.50", -] - [[package]] name = "polkavm-derive" version = "0.9.1" @@ -13892,25 +13876,13 @@ dependencies = [ "polkavm-derive-impl-macro", ] -[[package]] -name = "polkavm-derive-impl" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc8211b3365bbafb2fb32057d68b0e1ca55d079f5cf6f9da9b98079b94b3987d" -dependencies = [ - "polkavm-common 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.50", -] - [[package]] name = "polkavm-derive-impl" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c4fdfc49717fb9a196e74a5d28e0bc764eb394a2c803eb11133a31ac996c60c" dependencies = [ - "polkavm-common 0.9.0", + "polkavm-common", "proc-macro2", "quote", "syn 2.0.50", @@ -13922,25 +13894,10 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429" dependencies = [ - "polkavm-derive-impl 0.9.0", + "polkavm-derive-impl", "syn 2.0.50", ] -[[package]] -name = "polkavm-linker" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5a668bb33c7f0b5f4ca91adb1e1e71cf4930fef5e6909f46c2180d65cce37d0" -dependencies = [ - "gimli 0.28.0", - "hashbrown 0.14.3", - "log", - "object 0.32.2", - "polkavm-common 0.5.0", - "regalloc2 0.9.3", - "rustc-demangle", -] - [[package]] name = "polkavm-linker" version = "0.9.2" @@ -13951,7 +13908,7 @@ dependencies = [ "hashbrown 0.14.3", "log", "object 0.32.2", - "polkavm-common 0.9.0", + "polkavm-common", "regalloc2 0.9.3", "rustc-demangle", ] @@ -18855,7 +18812,7 @@ dependencies = [ "libsecp256k1", "log", "parity-scale-codec", - "polkavm-derive 0.9.1", + "polkavm-derive", "rustversion", "secp256k1", "sp-core", @@ -19047,7 +19004,7 @@ dependencies = [ "bytes", "impl-trait-for-tuples", "parity-scale-codec", - "polkavm-derive 0.9.1", + "polkavm-derive", "primitive-types", "rustversion", "sp-core", @@ -20069,7 +20026,7 @@ dependencies = [ "console", "filetime", "parity-wasm", - "polkavm-linker 0.9.2", + "polkavm-linker", "sp-maybe-compressed-blob", "strum 0.24.1", "tempfile", diff --git a/substrate/frame/contracts/fixtures/Cargo.toml b/substrate/frame/contracts/fixtures/Cargo.toml index 9ca9e404c31..5ac140cd91b 100644 --- a/substrate/frame/contracts/fixtures/Cargo.toml +++ b/substrate/frame/contracts/fixtures/Cargo.toml @@ -20,7 +20,7 @@ parity-wasm = "0.45.0" tempfile = "3.8.1" toml = "0.8.2" twox-hash = "1.6.3" -polkavm-linker = { version = "0.5.0", optional = true } +polkavm-linker = { workspace = true, optional = true } anyhow = "1.0.0" [features] diff --git a/substrate/frame/contracts/fixtures/build.rs b/substrate/frame/contracts/fixtures/build.rs index 12a7805294b..19aff37c160 100644 --- a/substrate/frame/contracts/fixtures/build.rs +++ b/substrate/frame/contracts/fixtures/build.rs @@ -121,9 +121,11 @@ fn collect_entries(contracts_dir: &Path, out_dir: &Path) -> Vec { /// Create a `Cargo.toml` to compile the given contract entries. fn create_cargo_toml<'a>( fixtures_dir: &Path, + root_cargo_toml: &Path, entries: impl Iterator, output_dir: &Path, ) -> Result<()> { + let root_toml: toml::Value = toml::from_str(&fs::read_to_string(root_cargo_toml)?)?; let mut cargo_toml: toml::Value = toml::from_str(include_str!("./build/Cargo.toml"))?; let mut set_dep = |name, path| -> Result<()> { cargo_toml["dependencies"][name]["path"] = toml::Value::String( @@ -133,6 +135,8 @@ fn create_cargo_toml<'a>( }; set_dep("uapi", "../uapi")?; set_dep("common", "./contracts/common")?; + cargo_toml["dependencies"]["polkavm-derive"]["version"] = + root_toml["workspace"]["dependencies"]["polkavm-derive"].clone(); cargo_toml["bin"] = toml::Value::Array( entries @@ -324,6 +328,7 @@ fn main() -> Result<()> { let contracts_dir = fixtures_dir.join("contracts"); let out_dir: PathBuf = env::var("OUT_DIR")?.into(); let workspace_root = find_workspace_root(&fixtures_dir).expect("workspace root exists; qed"); + let root_cargo_toml = workspace_root.join("Cargo.toml"); let entries = collect_entries(&contracts_dir, &out_dir); if entries.is_empty() { @@ -333,7 +338,7 @@ fn main() -> Result<()> { let tmp_dir = tempfile::tempdir()?; let tmp_dir_path = tmp_dir.path(); - create_cargo_toml(&fixtures_dir, entries.iter(), tmp_dir.path())?; + create_cargo_toml(&fixtures_dir, &root_cargo_toml, entries.iter(), tmp_dir.path())?; invoke_cargo_fmt( &workspace_root.join(".rustfmt.toml"), entries.iter().map(|entry| &entry.path as _), diff --git a/substrate/frame/contracts/fixtures/build/Cargo.toml b/substrate/frame/contracts/fixtures/build/Cargo.toml index d524dbff1ce..ba487a2bb5c 100644 --- a/substrate/frame/contracts/fixtures/build/Cargo.toml +++ b/substrate/frame/contracts/fixtures/build/Cargo.toml @@ -6,11 +6,11 @@ edition = "2021" # Binary targets are injected dynamically by the build script. [[bin]] -# local path are injected dynamically by the build script. +# All paths or versions are injected dynamically by the build script. [dependencies] uapi = { package = 'pallet-contracts-uapi', path = "", default-features = false } common = { package = 'pallet-contracts-fixtures-common', path = "" } -polkavm-derive = '0.5.0' +polkavm-derive = { version = "" } [profile.release] opt-level = 3 diff --git a/substrate/frame/contracts/uapi/Cargo.toml b/substrate/frame/contracts/uapi/Cargo.toml index a5081af2a2d..12bb6b8fc2c 100644 --- a/substrate/frame/contracts/uapi/Cargo.toml +++ b/substrate/frame/contracts/uapi/Cargo.toml @@ -21,7 +21,7 @@ scale = { package = "parity-scale-codec", version = "3.6.1", default-features = ], optional = true } [target.'cfg(target_arch = "riscv32")'.dependencies] -polkavm-derive = '0.5.0' +polkavm-derive = { workspace = true } [package.metadata.docs.rs] default-target = ["wasm32-unknown-unknown"] -- GitLab From 02e1a7f476d7d7c67153e975ab9a1bdc02ffea12 Mon Sep 17 00:00:00 2001 From: ordian Date: Fri, 15 Mar 2024 20:43:28 +0100 Subject: [PATCH 045/187] collator protocol changes for elastic scaling (validator side) (#3302) Fixes #3128. This introduces a new variant for the collation response from the collator that includes the parent head data. For now, collators won't send this new variant. We'll need to change the collator side of the collator protocol to detect all the cores assigned to a para and send the parent head data in the case when it's more than 1 core. - [x] validate approach - [x] check head data hash --- polkadot/node/collation-generation/src/lib.rs | 8 +- .../node/collation-generation/src/tests.rs | 33 ++--- .../core/prospective-parachains/src/lib.rs | 17 ++- .../core/prospective-parachains/src/tests.rs | 4 +- .../src/collator_side/collation.rs | 4 +- .../src/collator_side/mod.rs | 65 +++++++--- .../src/collator_side/tests/mod.rs | 62 +++++---- .../tests/prospective_parachains.rs | 32 ++--- .../network/collator-protocol/src/error.rs | 10 +- .../src/validator_side/collation.rs | 13 +- .../src/validator_side/mod.rs | 86 ++++++++++--- .../tests/prospective_parachains.rs | 120 ++++++++++++++++++ .../protocol/src/request_response/mod.rs | 2 +- .../protocol/src/request_response/v1.rs | 15 ++- polkadot/node/subsystem-types/src/messages.rs | 53 +++++--- prdoc/pr_3302.prdoc | 15 +++ 16 files changed, 406 insertions(+), 133 deletions(-) create mode 100644 prdoc/pr_3302.prdoc diff --git a/polkadot/node/collation-generation/src/lib.rs b/polkadot/node/collation-generation/src/lib.rs index cfa75d7b441..a89351628a0 100644 --- a/polkadot/node/collation-generation/src/lib.rs +++ b/polkadot/node/collation-generation/src/lib.rs @@ -466,6 +466,7 @@ async fn construct_and_distribute_receipt( } = collation; let persisted_validation_data_hash = validation_data.hash(); + let parent_head_data = validation_data.parent_head.clone(); let parent_head_data_hash = validation_data.parent_head.hash(); // Apply compression to the block data. @@ -551,12 +552,13 @@ async fn construct_and_distribute_receipt( metrics.on_collation_generated(); sender - .send_message(CollatorProtocolMessage::DistributeCollation( - ccr, + .send_message(CollatorProtocolMessage::DistributeCollation { + candidate_receipt: ccr, parent_head_data_hash, pov, + parent_head_data, result_sender, - )) + }) .await; } diff --git a/polkadot/node/collation-generation/src/tests.rs b/polkadot/node/collation-generation/src/tests.rs index 9094f40cca8..eb0ede6ef6b 100644 --- a/polkadot/node/collation-generation/src/tests.rs +++ b/polkadot/node/collation-generation/src/tests.rs @@ -390,11 +390,11 @@ fn sends_distribute_collation_message() { assert_eq!(to_collator_protocol.len(), 1); match AllMessages::from(to_collator_protocol.pop().unwrap()) { - AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation( - CandidateReceipt { descriptor, .. }, - _pov, - .., - )) => { + AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation { + candidate_receipt, + .. + }) => { + let CandidateReceipt { descriptor, .. } = candidate_receipt; // signature generation is non-deterministic, so we can't just assert that the // expected descriptor is correct. What we can do is validate that the produced // descriptor has a valid signature, then just copy in the generated signature @@ -529,11 +529,11 @@ fn fallback_when_no_validation_code_hash_api() { assert_eq!(to_collator_protocol.len(), 1); match &to_collator_protocol[0] { - AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation( - CandidateReceipt { descriptor, .. }, - _pov, - .., - )) => { + AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation { + candidate_receipt, + .. + }) => { + let CandidateReceipt { descriptor, .. } = candidate_receipt; assert_eq!(expect_validation_code_hash, descriptor.validation_code_hash); }, _ => panic!("received wrong message type"), @@ -619,15 +619,16 @@ fn submit_collation_leads_to_distribution() { assert_matches!( overseer_recv(&mut virtual_overseer).await, - AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation( - ccr, + AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation { + candidate_receipt, parent_head_data_hash, .. - )) => { + }) => { + let CandidateReceipt { descriptor, .. } = candidate_receipt; assert_eq!(parent_head_data_hash, parent_head.hash()); - assert_eq!(ccr.descriptor().persisted_validation_data_hash, expected_pvd.hash()); - assert_eq!(ccr.descriptor().para_head, dummy_head_data().hash()); - assert_eq!(ccr.descriptor().validation_code_hash, validation_code_hash); + assert_eq!(descriptor.persisted_validation_data_hash, expected_pvd.hash()); + assert_eq!(descriptor.para_head, dummy_head_data().hash()); + assert_eq!(descriptor.validation_code_hash, validation_code_hash); } ); diff --git a/polkadot/node/core/prospective-parachains/src/lib.rs b/polkadot/node/core/prospective-parachains/src/lib.rs index 2b14e09b4fb..f5d50fb74fa 100644 --- a/polkadot/node/core/prospective-parachains/src/lib.rs +++ b/polkadot/node/core/prospective-parachains/src/lib.rs @@ -36,8 +36,9 @@ use futures::{channel::oneshot, prelude::*}; use polkadot_node_subsystem::{ messages::{ Ancestors, ChainApiMessage, FragmentTreeMembership, HypotheticalCandidate, - HypotheticalFrontierRequest, IntroduceCandidateRequest, ProspectiveParachainsMessage, - ProspectiveValidationDataRequest, RuntimeApiMessage, RuntimeApiRequest, + HypotheticalFrontierRequest, IntroduceCandidateRequest, ParentHeadData, + ProspectiveParachainsMessage, ProspectiveValidationDataRequest, RuntimeApiMessage, + RuntimeApiRequest, }, overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemError, }; @@ -764,8 +765,14 @@ fn answer_prospective_validation_data_request( Some(s) => s, }; - let mut head_data = - storage.head_data_by_hash(&request.parent_head_data_hash).map(|x| x.clone()); + let (mut head_data, parent_head_data_hash) = match request.parent_head_data { + ParentHeadData::OnlyHash(parent_head_data_hash) => ( + storage.head_data_by_hash(&parent_head_data_hash).map(|x| x.clone()), + parent_head_data_hash, + ), + ParentHeadData::WithData { head_data, hash } => (Some(head_data), hash), + }; + let mut relay_parent_info = None; let mut max_pov_size = None; @@ -783,7 +790,7 @@ fn answer_prospective_validation_data_request( } if head_data.is_none() { let required_parent = &fragment_tree.scope().base_constraints().required_parent; - if required_parent.hash() == request.parent_head_data_hash { + if required_parent.hash() == parent_head_data_hash { head_data = Some(required_parent.clone()); } } diff --git a/polkadot/node/core/prospective-parachains/src/tests.rs b/polkadot/node/core/prospective-parachains/src/tests.rs index 0beddbf1416..0e0079c02bb 100644 --- a/polkadot/node/core/prospective-parachains/src/tests.rs +++ b/polkadot/node/core/prospective-parachains/src/tests.rs @@ -19,7 +19,7 @@ use assert_matches::assert_matches; use polkadot_node_subsystem::{ errors::RuntimeApiError, messages::{ - AllMessages, HypotheticalFrontierRequest, ProspectiveParachainsMessage, + AllMessages, HypotheticalFrontierRequest, ParentHeadData, ProspectiveParachainsMessage, ProspectiveValidationDataRequest, }, }; @@ -468,7 +468,7 @@ async fn get_pvd( let request = ProspectiveValidationDataRequest { para_id, candidate_relay_parent, - parent_head_data_hash: parent_head_data.hash(), + parent_head_data: ParentHeadData::OnlyHash(parent_head_data.hash()), }; let (tx, rx) = oneshot::channel(); virtual_overseer diff --git a/polkadot/node/network/collator-protocol/src/collator_side/collation.rs b/polkadot/node/network/collator-protocol/src/collator_side/collation.rs index 53f947142d1..dc1ee725462 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/collation.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/collation.rs @@ -27,7 +27,7 @@ use polkadot_node_network_protocol::{ PeerId, }; use polkadot_node_primitives::PoV; -use polkadot_primitives::{CandidateHash, CandidateReceipt, Hash, Id as ParaId}; +use polkadot_primitives::{CandidateHash, CandidateReceipt, Hash, HeadData, Id as ParaId}; /// The status of a collation as seen from the collator. pub enum CollationStatus { @@ -63,6 +63,8 @@ pub struct Collation { pub parent_head_data_hash: Hash, /// Proof to verify the state transition of the parachain. pub pov: PoV, + /// Parent head-data needed for elastic scaling. + pub parent_head_data: HeadData, /// Collation status. pub status: CollationStatus, } diff --git a/polkadot/node/network/collator-protocol/src/collator_side/mod.rs b/polkadot/node/network/collator-protocol/src/collator_side/mod.rs index 8fb0bb21544..19cc1eb1a57 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/mod.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/mod.rs @@ -55,7 +55,7 @@ use polkadot_node_subsystem_util::{ }; use polkadot_primitives::{ AuthorityDiscoveryId, CandidateHash, CandidateReceipt, CollatorPair, CoreIndex, CoreState, - GroupIndex, Hash, Id as ParaId, SessionIndex, + GroupIndex, Hash, HeadData, Id as ParaId, SessionIndex, }; use super::LOG_TARGET; @@ -347,6 +347,7 @@ async fn distribute_collation( receipt: CandidateReceipt, parent_head_data_hash: Hash, pov: PoV, + parent_head_data: HeadData, result_sender: Option>, ) -> Result<()> { let candidate_relay_parent = receipt.descriptor.relay_parent; @@ -465,7 +466,13 @@ async fn distribute_collation( per_relay_parent.collations.insert( candidate_hash, - Collation { receipt, parent_head_data_hash, pov, status: CollationStatus::Created }, + Collation { + receipt, + parent_head_data_hash, + pov, + parent_head_data, + status: CollationStatus::Created, + }, ); // If prospective parachains are disabled, a leaf should be known to peer. @@ -763,20 +770,26 @@ async fn process_msg( CollateOn(id) => { state.collating_on = Some(id); }, - DistributeCollation(receipt, parent_head_data_hash, pov, result_sender) => { + DistributeCollation { + candidate_receipt, + parent_head_data_hash, + pov, + parent_head_data, + result_sender, + } => { let _span1 = state .span_per_relay_parent - .get(&receipt.descriptor.relay_parent) + .get(&candidate_receipt.descriptor.relay_parent) .map(|s| s.child("distributing-collation")); let _span2 = jaeger::Span::new(&pov, "distributing-collation"); match state.collating_on { - Some(id) if receipt.descriptor.para_id != id => { + Some(id) if candidate_receipt.descriptor.para_id != id => { // If the ParaId of a collation requested to be distributed does not match // the one we expect, we ignore the message. gum::warn!( target: LOG_TARGET, - para_id = %receipt.descriptor.para_id, + para_id = %candidate_receipt.descriptor.para_id, collating_on = %id, "DistributeCollation for unexpected para_id", ); @@ -788,9 +801,10 @@ async fn process_msg( runtime, state, id, - receipt, + candidate_receipt, parent_head_data_hash, pov, + parent_head_data, result_sender, ) .await?; @@ -798,7 +812,7 @@ async fn process_msg( None => { gum::warn!( target: LOG_TARGET, - para_id = %receipt.descriptor.para_id, + para_id = %candidate_receipt.descriptor.para_id, "DistributeCollation message while not collating on any", ); }, @@ -835,6 +849,7 @@ async fn send_collation( request: VersionedCollationRequest, receipt: CandidateReceipt, pov: PoV, + _parent_head_data: HeadData, ) { let (tx, rx) = oneshot::channel(); @@ -842,13 +857,22 @@ async fn send_collation( let peer_id = request.peer_id(); let candidate_hash = receipt.hash(); - // The response payload is the same for both versions of protocol + // The response payload is the same for v1 and v2 versions of protocol // and doesn't have v2 alias for simplicity. - let response = OutgoingResponse { - result: Ok(request_v1::CollationFetchingResponse::Collation(receipt, pov)), - reputation_changes: Vec::new(), - sent_feedback: Some(tx), - }; + // For now, we don't send parent head data to the collation requester. + let result = + // if assigned_multiple_cores { + // Ok(request_v1::CollationFetchingResponse::CollationWithParentHeadData { + // receipt, + // pov, + // parent_head_data, + // }) + // } else { + Ok(request_v1::CollationFetchingResponse::Collation(receipt, pov)) + // } + ; + let response = + OutgoingResponse { result, reputation_changes: Vec::new(), sent_feedback: Some(tx) }; if let Err(_) = request.send_outgoing_response(response) { gum::warn!(target: LOG_TARGET, "Sending collation response failed"); @@ -1027,9 +1051,13 @@ async fn handle_incoming_request( return Ok(()) }, }; - let (receipt, pov) = if let Some(collation) = collation { + let (receipt, pov, parent_head_data) = if let Some(collation) = collation { collation.status.advance_to_requested(); - (collation.receipt.clone(), collation.pov.clone()) + ( + collation.receipt.clone(), + collation.pov.clone(), + collation.parent_head_data.clone(), + ) } else { gum::warn!( target: LOG_TARGET, @@ -1068,7 +1096,7 @@ async fn handle_incoming_request( waiting.collation_fetch_active = true; // Obtain a timer for sending collation let _ = state.metrics.time_collation_distribution("send"); - send_collation(state, req, receipt, pov).await; + send_collation(state, req, receipt, pov, parent_head_data).await; } }, Some(our_para_id) => { @@ -1453,8 +1481,9 @@ async fn run_inner( if let Some(collation) = next_collation { let receipt = collation.receipt.clone(); let pov = collation.pov.clone(); + let parent_head_data = collation.parent_head_data.clone(); - send_collation(&mut state, next, receipt, pov).await; + send_collation(&mut state, next, receipt, pov, parent_head_data).await; } }, (candidate_hash, peer_id) = state.advertisement_timeouts.select_next_some() => { diff --git a/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs b/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs index 1b1194c7270..beda941d37a 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs @@ -356,12 +356,13 @@ async fn distribute_collation_with_receipt( ) -> DistributeCollation { overseer_send( virtual_overseer, - CollatorProtocolMessage::DistributeCollation( - candidate.clone(), + CollatorProtocolMessage::DistributeCollation { + candidate_receipt: candidate.clone(), parent_head_data_hash, - pov.clone(), - None, - ), + pov: pov.clone(), + parent_head_data: HeadData(vec![1, 2, 3]), + result_sender: None, + }, ) .await; @@ -627,6 +628,18 @@ async fn send_peer_view_change( .await; } +fn decode_collation_response(bytes: &[u8]) -> (CandidateReceipt, PoV) { + let response: request_v1::CollationFetchingResponse = + request_v1::CollationFetchingResponse::decode(&mut &bytes[..]) + .expect("Decoding should work"); + match response { + request_v1::CollationFetchingResponse::Collation(receipt, pov) => (receipt, pov), + request_v1::CollationFetchingResponse::CollationWithParentHeadData { + receipt, pov, .. + } => (receipt, pov), + } +} + #[test] fn advertise_and_send_collation() { let mut test_state = TestState::default(); @@ -736,12 +749,10 @@ fn advertise_and_send_collation() { assert_matches!( rx.await, Ok(full_response) => { - let request_v1::CollationFetchingResponse::Collation(receipt, pov): request_v1::CollationFetchingResponse - = request_v1::CollationFetchingResponse::decode( - &mut full_response.result - .expect("We should have a proper answer").as_ref() - ) - .expect("Decoding should work"); + let (receipt, pov) = decode_collation_response( + full_response.result + .expect("We should have a proper answer").as_ref() + ); assert_eq!(receipt, candidate); assert_eq!(pov, pov_block); } @@ -1338,12 +1349,10 @@ where let feedback_tx = assert_matches!( rx.await, Ok(full_response) => { - let request_v1::CollationFetchingResponse::Collation(receipt, pov): request_v1::CollationFetchingResponse - = request_v1::CollationFetchingResponse::decode( - &mut full_response.result - .expect("We should have a proper answer").as_ref() - ) - .expect("Decoding should work"); + let (receipt, pov) = decode_collation_response( + full_response.result + .expect("We should have a proper answer").as_ref() + ); assert_eq!(receipt, candidate); assert_eq!(pov, pov_block); @@ -1375,12 +1384,10 @@ where assert_matches!( rx.await, Ok(full_response) => { - let request_v1::CollationFetchingResponse::Collation(receipt, pov): request_v1::CollationFetchingResponse - = request_v1::CollationFetchingResponse::decode( - &mut full_response.result - .expect("We should have a proper answer").as_ref() - ) - .expect("Decoding should work"); + let (receipt, pov) = decode_collation_response( + full_response.result + .expect("We should have a proper answer").as_ref() + ); assert_eq!(receipt, candidate); assert_eq!(pov, pov_block); @@ -1469,11 +1476,10 @@ fn connect_to_buffered_groups() { assert_matches!( rx.await, Ok(full_response) => { - let request_v1::CollationFetchingResponse::Collation(..) = - request_v1::CollationFetchingResponse::decode( - &mut full_response.result.expect("We should have a proper answer").as_ref(), - ) - .expect("Decoding should work"); + let _ = decode_collation_response( + full_response.result + .expect("We should have a proper answer").as_ref() + ); } ); diff --git a/polkadot/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs b/polkadot/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs index fd9d7a746eb..2bb7002a4f4 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs @@ -271,12 +271,13 @@ fn distribute_collation_from_implicit_view() { .build(); overseer_send( virtual_overseer, - CollatorProtocolMessage::DistributeCollation( - candidate.clone(), + CollatorProtocolMessage::DistributeCollation { + candidate_receipt: candidate.clone(), parent_head_data_hash, - pov.clone(), - None, - ), + pov: pov.clone(), + parent_head_data: HeadData(vec![1, 2, 3]), + result_sender: None, + }, ) .await; @@ -351,12 +352,13 @@ fn distribute_collation_up_to_limit() { .build(); overseer_send( virtual_overseer, - CollatorProtocolMessage::DistributeCollation( - candidate.clone(), + CollatorProtocolMessage::DistributeCollation { + candidate_receipt: candidate.clone(), parent_head_data_hash, - pov.clone(), - None, - ), + pov: pov.clone(), + parent_head_data: HeadData(vec![1, 2, 3]), + result_sender: None, + }, ) .await; @@ -469,12 +471,10 @@ fn advertise_and_send_collation_by_hash() { rx.await, Ok(full_response) => { // Response is the same for v2. - let request_v1::CollationFetchingResponse::Collation(receipt, pov): request_v1::CollationFetchingResponse - = request_v1::CollationFetchingResponse::decode( - &mut full_response.result - .expect("We should have a proper answer").as_ref() - ) - .expect("Decoding should work"); + let (receipt, pov) = decode_collation_response( + full_response.result + .expect("We should have a proper answer").as_ref() + ); assert_eq!(receipt, candidate); assert_eq!(pov, pov_block); } diff --git a/polkadot/node/network/collator-protocol/src/error.rs b/polkadot/node/network/collator-protocol/src/error.rs index 9348198e708..0f5e0699d85 100644 --- a/polkadot/node/network/collator-protocol/src/error.rs +++ b/polkadot/node/network/collator-protocol/src/error.rs @@ -89,13 +89,21 @@ pub enum SecondingError { #[error("Received duplicate collation from the peer")] Duplicate, + + #[error("The provided parent head data does not match the hash")] + ParentHeadDataMismatch, } impl SecondingError { /// Returns true if an error indicates that a peer is malicious. pub fn is_malicious(&self) -> bool { use SecondingError::*; - matches!(self, PersistedValidationDataMismatch | CandidateHashMismatch | Duplicate) + matches!( + self, + PersistedValidationDataMismatch | + CandidateHashMismatch | + Duplicate | ParentHeadDataMismatch + ) } } diff --git a/polkadot/node/network/collator-protocol/src/validator_side/collation.rs b/polkadot/node/network/collator-protocol/src/validator_side/collation.rs index d6f34fc81b8..8c3889a3554 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/collation.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/collation.rs @@ -41,7 +41,8 @@ use polkadot_node_subsystem_util::{ metrics::prometheus::prometheus::HistogramTimer, runtime::ProspectiveParachainsMode, }; use polkadot_primitives::{ - CandidateHash, CandidateReceipt, CollatorId, Hash, Id as ParaId, PersistedValidationData, + CandidateHash, CandidateReceipt, CollatorId, Hash, HeadData, Id as ParaId, + PersistedValidationData, }; use tokio_util::sync::CancellationToken; @@ -120,7 +121,7 @@ impl PendingCollation { } } -/// v2 advertisement that was rejected by the backing +/// v2 or v3 advertisement that was rejected by the backing /// subsystem. Validator may fetch it later if its fragment /// membership gets recognized before relay parent goes out of view. #[derive(Debug, Clone)] @@ -143,6 +144,7 @@ pub fn fetched_collation_sanity_check( advertised: &PendingCollation, fetched: &CandidateReceipt, persisted_validation_data: &PersistedValidationData, + maybe_parent_head_and_hash: Option<(HeadData, Hash)>, ) -> Result<(), SecondingError> { if persisted_validation_data.hash() != fetched.descriptor().persisted_validation_data_hash { Err(SecondingError::PersistedValidationDataMismatch) @@ -151,6 +153,8 @@ pub fn fetched_collation_sanity_check( .map_or(false, |pc| pc.candidate_hash() != fetched.hash()) { Err(SecondingError::CandidateHashMismatch) + } else if maybe_parent_head_and_hash.map_or(false, |(head, hash)| head.hash() != hash) { + Err(SecondingError::ParentHeadDataMismatch) } else { Ok(()) } @@ -176,6 +180,9 @@ pub struct PendingCollationFetch { pub candidate_receipt: CandidateReceipt, /// Proof of validity. pub pov: PoV, + /// Optional parachain parent head data. + /// Only needed for elastic scaling. + pub maybe_parent_head_data: Option, } /// The status of the collations in [`CollationsPerRelayParent`]. @@ -359,7 +366,7 @@ impl Future for CollationFetchRequest { }); match &res { - Poll::Ready((_, Ok(request_v1::CollationFetchingResponse::Collation(..)))) => { + Poll::Ready((_, Ok(_))) => { self.span.as_mut().map(|s| s.add_string_tag("success", "true")); }, Poll::Ready((_, Err(_))) => { diff --git a/polkadot/node/network/collator-protocol/src/validator_side/mod.rs b/polkadot/node/network/collator-protocol/src/validator_side/mod.rs index a1b93fff348..d23279e8754 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/mod.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/mod.rs @@ -44,7 +44,7 @@ use polkadot_node_subsystem::{ jaeger, messages::{ CanSecondRequest, CandidateBackingMessage, CollatorProtocolMessage, IfDisconnected, - NetworkBridgeEvent, NetworkBridgeTxMessage, ProspectiveParachainsMessage, + NetworkBridgeEvent, NetworkBridgeTxMessage, ParentHeadData, ProspectiveParachainsMessage, ProspectiveValidationDataRequest, }, overseer, CollatorProtocolSenderTrait, FromOrchestra, OverseerSignal, PerLeafSpan, @@ -55,7 +55,7 @@ use polkadot_node_subsystem_util::{ runtime::{prospective_parachains_mode, ProspectiveParachainsMode}, }; use polkadot_primitives::{ - CandidateHash, CollatorId, CoreState, Hash, Id as ParaId, OccupiedCoreAssumption, + CandidateHash, CollatorId, CoreState, Hash, HeadData, Id as ParaId, OccupiedCoreAssumption, PersistedValidationData, }; @@ -723,7 +723,7 @@ async fn request_collation( pending_collation, collator_id: collator_id.clone(), collator_protocol_version: peer_protocol_version, - from_collator: response_recv.boxed(), + from_collator: response_recv, cancellation_token: cancellation_token.clone(), span: state .span_per_relay_parent @@ -889,16 +889,16 @@ async fn process_incoming_peer_message( modify_reputation(&mut state.reputation, ctx.sender(), origin, rep).await; } }, - Versioned::V2(V2::AdvertiseCollation { + Versioned::V3(V2::AdvertiseCollation { relay_parent, candidate_hash, parent_head_data_hash, }) | - Versioned::V3(V2::AdvertiseCollation { + Versioned::V2(V2::AdvertiseCollation { relay_parent, candidate_hash, parent_head_data_hash, - }) => + }) => { if let Err(err) = handle_advertisement( ctx.sender(), state, @@ -920,7 +920,8 @@ async fn process_incoming_peer_message( if let Some(rep) = err.reputation_changes() { modify_reputation(&mut state.reputation, ctx.sender(), origin, rep).await; } - }, + } + }, Versioned::V1(V1::CollationSeconded(..)) | Versioned::V2(V2::CollationSeconded(..)) | Versioned::V3(V2::CollationSeconded(..)) => { @@ -1477,7 +1478,7 @@ async fn process_msg( "CollateOn message is not expected on the validator side of the protocol", ); }, - DistributeCollation(..) => { + DistributeCollation { .. } => { gum::warn!( target: LOG_TARGET, "DistributeCollation message is not expected on the validator side of the protocol", @@ -1776,14 +1777,21 @@ async fn request_prospective_validation_data( candidate_relay_parent: Hash, parent_head_data_hash: Hash, para_id: ParaId, + maybe_parent_head_data: Option, ) -> std::result::Result, SecondingError> where Sender: CollatorProtocolSenderTrait, { let (tx, rx) = oneshot::channel(); + let parent_head_data = if let Some(head_data) = maybe_parent_head_data { + ParentHeadData::WithData { head_data, hash: parent_head_data_hash } + } else { + ParentHeadData::OnlyHash(parent_head_data_hash) + }; + let request = - ProspectiveValidationDataRequest { para_id, candidate_relay_parent, parent_head_data_hash }; + ProspectiveValidationDataRequest { para_id, candidate_relay_parent, parent_head_data }; sender .send_message(ProspectiveParachainsMessage::GetProspectiveValidationData(request, tx)) @@ -1797,7 +1805,7 @@ where async fn kick_off_seconding( ctx: &mut Context, state: &mut State, - PendingCollationFetch { mut collation_event, candidate_receipt, pov }: PendingCollationFetch, + PendingCollationFetch { mut collation_event, candidate_receipt, pov, maybe_parent_head_data }: PendingCollationFetch, ) -> std::result::Result<(), SecondingError> { let pending_collation = collation_event.pending_collation; let relay_parent = pending_collation.relay_parent; @@ -1821,38 +1829,46 @@ async fn kick_off_seconding( collation_event.pending_collation.commitments_hash = Some(candidate_receipt.commitments_hash); - let pvd = match ( + let (maybe_pvd, maybe_parent_head_and_hash) = match ( collation_event.collator_protocol_version, collation_event.pending_collation.prospective_candidate, ) { (CollationVersion::V2, Some(ProspectiveCandidate { parent_head_data_hash, .. })) if per_relay_parent.prospective_parachains_mode.is_enabled() => - request_prospective_validation_data( + { + let pvd = request_prospective_validation_data( ctx.sender(), relay_parent, parent_head_data_hash, pending_collation.para_id, + maybe_parent_head_data.clone(), ) - .await?, + .await?; + + (pvd, maybe_parent_head_data.map(|head_data| (head_data, parent_head_data_hash))) + }, // Support V2 collators without async backing enabled. - (CollationVersion::V2, Some(_)) | (CollationVersion::V1, _) => - request_persisted_validation_data( + (CollationVersion::V2, Some(_)) | (CollationVersion::V1, _) => { + let pvd = request_persisted_validation_data( ctx.sender(), candidate_receipt.descriptor().relay_parent, candidate_receipt.descriptor().para_id, ) - .await?, + .await?; + (pvd, None) + }, _ => { // `handle_advertisement` checks for protocol mismatch. return Ok(()) }, - } - .ok_or(SecondingError::PersistedValidationDataNotFound)?; + }; + let pvd = maybe_pvd.ok_or(SecondingError::PersistedValidationDataNotFound)?; fetched_collation_sanity_check( &collation_event.pending_collation, &candidate_receipt, &pvd, + maybe_parent_head_and_hash, )?; ctx.send_message(CandidateBackingMessage::Second( @@ -1978,9 +1994,10 @@ async fn handle_collation_fetch_response( ); Err(None) }, - Ok(request_v1::CollationFetchingResponse::Collation(receipt, _)) - if receipt.descriptor().para_id != pending_collation.para_id => - { + Ok( + request_v1::CollationFetchingResponse::Collation(receipt, _) | + request_v1::CollationFetchingResponse::CollationWithParentHeadData { receipt, .. }, + ) if receipt.descriptor().para_id != pending_collation.para_id => { gum::debug!( target: LOG_TARGET, expected_para_id = ?pending_collation.para_id, @@ -2010,6 +2027,33 @@ async fn handle_collation_fetch_response( }, candidate_receipt, pov, + maybe_parent_head_data: None, + }) + }, + Ok(request_v2::CollationFetchingResponse::CollationWithParentHeadData { + receipt, + pov, + parent_head_data, + }) => { + gum::debug!( + target: LOG_TARGET, + para_id = %pending_collation.para_id, + hash = ?pending_collation.relay_parent, + candidate_hash = ?receipt.hash(), + "Received collation (v3)", + ); + let _span = jaeger::Span::new(&pov, "received-collation"); + + metrics_result = Ok(()); + Ok(PendingCollationFetch { + collation_event: CollationEvent { + collator_id, + pending_collation, + collator_protocol_version, + }, + candidate_receipt: receipt, + pov, + maybe_parent_head_data: Some(parent_head_data), }) }, }; diff --git a/polkadot/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs b/polkadot/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs index 23963e65554..eaa725f2642 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs @@ -754,6 +754,126 @@ fn fetched_collation_sanity_check() { }); } +#[test] +fn sanity_check_invalid_parent_head_data() { + let test_state = TestState::default(); + + test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { + let TestHarness { mut virtual_overseer, .. } = test_harness; + + let pair = CollatorPair::generate().0; + + let head_c = Hash::from_low_u64_be(130); + let head_c_num = 3; + + update_view(&mut virtual_overseer, &test_state, vec![(head_c, head_c_num)], 1).await; + + let peer_a = PeerId::random(); + + connect_and_declare_collator( + &mut virtual_overseer, + peer_a, + pair.clone(), + test_state.chain_ids[0], + CollationVersion::V2, + ) + .await; + + let mut candidate = dummy_candidate_receipt_bad_sig(head_c, Some(Default::default())); + candidate.descriptor.para_id = test_state.chain_ids[0]; + + let commitments = CandidateCommitments { + head_data: HeadData(vec![1, 2, 3]), + horizontal_messages: Default::default(), + upward_messages: Default::default(), + new_validation_code: None, + processed_downward_messages: 0, + hrmp_watermark: 0, + }; + candidate.commitments_hash = commitments.hash(); + + let parent_head_data = HeadData(vec![4, 2, 0]); + let parent_head_data_hash = parent_head_data.hash(); + let wrong_parent_head_data = HeadData(vec![4, 2]); + + let mut pvd = dummy_pvd(); + pvd.parent_head = parent_head_data; + + candidate.descriptor.persisted_validation_data_hash = pvd.hash(); + + let candidate_hash = candidate.hash(); + + advertise_collation( + &mut virtual_overseer, + peer_a, + head_c, + Some((candidate_hash, parent_head_data_hash)), + ) + .await; + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::CandidateBacking( + CandidateBackingMessage::CanSecond(request, tx), + ) => { + assert_eq!(request.candidate_hash, candidate_hash); + assert_eq!(request.candidate_para_id, test_state.chain_ids[0]); + assert_eq!(request.parent_head_data_hash, parent_head_data_hash); + tx.send(true).expect("receiving side should be alive"); + } + ); + + let response_channel = assert_fetch_collation_request( + &mut virtual_overseer, + head_c, + test_state.chain_ids[0], + Some(candidate_hash), + ) + .await; + + let pov = PoV { block_data: BlockData(vec![1]) }; + + response_channel + .send(Ok(( + request_v2::CollationFetchingResponse::CollationWithParentHeadData { + receipt: candidate.clone(), + pov: pov.clone(), + parent_head_data: wrong_parent_head_data, + } + .encode(), + ProtocolName::from(""), + ))) + .expect("Sending response should succeed"); + + // PVD request. + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::GetProspectiveValidationData(request, tx), + ) => { + assert_eq!(head_c, request.candidate_relay_parent); + assert_eq!(test_state.chain_ids[0], request.para_id); + tx.send(Some(pvd)).unwrap(); + } + ); + + // Reported malicious. + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::NetworkBridgeTx( + NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(peer_id, rep)), + ) => { + assert_eq!(peer_a, peer_id); + assert_eq!(rep.value, COST_REPORT_BAD.cost_or_benefit()); + } + ); + + test_helpers::Yield::new().await; + assert_matches!(virtual_overseer.recv().now_or_never(), None); + + virtual_overseer + }); +} + #[test] fn advertisement_spam_protection() { let test_state = TestState::default(); diff --git a/polkadot/node/network/protocol/src/request_response/mod.rs b/polkadot/node/network/protocol/src/request_response/mod.rs index a67d83aff0c..2fb62f56d10 100644 --- a/polkadot/node/network/protocol/src/request_response/mod.rs +++ b/polkadot/node/network/protocol/src/request_response/mod.rs @@ -31,7 +31,7 @@ //! data, like what is the corresponding response type. //! //! ## Versioning -//! +//! //! Versioning for request-response protocols can be done in multiple ways. //! //! If you're just changing the protocol name but the binary payloads are the same, just add a new diff --git a/polkadot/node/network/protocol/src/request_response/v1.rs b/polkadot/node/network/protocol/src/request_response/v1.rs index 0832593a6a3..ba29b32c4ce 100644 --- a/polkadot/node/network/protocol/src/request_response/v1.rs +++ b/polkadot/node/network/protocol/src/request_response/v1.rs @@ -22,7 +22,8 @@ use polkadot_node_primitives::{ AvailableData, DisputeMessage, ErasureChunk, PoV, Proof, UncheckedDisputeMessage, }; use polkadot_primitives::{ - CandidateHash, CandidateReceipt, CommittedCandidateReceipt, Hash, Id as ParaId, ValidatorIndex, + CandidateHash, CandidateReceipt, CommittedCandidateReceipt, Hash, HeadData, Id as ParaId, + ValidatorIndex, }; use super::{IsRequest, Protocol}; @@ -103,6 +104,18 @@ pub enum CollationFetchingResponse { /// Deliver requested collation. #[codec(index = 0)] Collation(CandidateReceipt, PoV), + + /// Deliver requested collation along with parent head data. + #[codec(index = 1)] + CollationWithParentHeadData { + /// The receipt of the candidate. + receipt: CandidateReceipt, + /// Candidate's proof of validity. + pov: PoV, + /// The head data of the candidate's parent. + /// This is needed for elastic scaling to work. + parent_head_data: HeadData, + }, } impl IsRequest for CollationFetchingRequest { diff --git a/polkadot/node/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index f11291fd0ea..eeb684149c8 100644 --- a/polkadot/node/subsystem-types/src/messages.rs +++ b/polkadot/node/subsystem-types/src/messages.rs @@ -46,11 +46,12 @@ use polkadot_primitives::{ vstaging::{ApprovalVotingParams, NodeFeatures}, AuthorityDiscoveryId, BackedCandidate, BlockNumber, CandidateEvent, CandidateHash, CandidateIndex, CandidateReceipt, CollatorId, CommittedCandidateReceipt, CoreState, - DisputeState, ExecutorParams, GroupIndex, GroupRotationInfo, Hash, Header as BlockHeader, - Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, MultiDisputeStatementSet, - OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, PvfExecKind, SessionIndex, - SessionInfo, SignedAvailabilityBitfield, SignedAvailabilityBitfields, ValidationCode, - ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, + DisputeState, ExecutorParams, GroupIndex, GroupRotationInfo, Hash, HeadData, + Header as BlockHeader, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, + MultiDisputeStatementSet, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, + PvfExecKind, SessionIndex, SessionInfo, SignedAvailabilityBitfield, + SignedAvailabilityBitfields, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, + ValidatorSignature, }; use polkadot_statement_table::v2::Misbehavior; use std::{ @@ -207,16 +208,20 @@ pub enum CollatorProtocolMessage { /// This should be sent before any `DistributeCollation` message. CollateOn(ParaId), /// Provide a collation to distribute to validators with an optional result sender. - /// The second argument is the parent head-data hash. - /// - /// The result sender should be informed when at least one parachain validator seconded the - /// collation. It is also completely okay to just drop the sender. - DistributeCollation( - CandidateReceipt, - Hash, - PoV, - Option>, - ), + DistributeCollation { + /// The receipt of the candidate. + candidate_receipt: CandidateReceipt, + /// The hash of the parent head-data. + /// Here to avoid computing the hash of the parent head data twice. + parent_head_data_hash: Hash, + /// Proof of validity. + pov: PoV, + /// This parent head-data is needed for elastic scaling. + parent_head_data: HeadData, + /// The result sender should be informed when at least one parachain validator seconded the + /// collation. It is also completely okay to just drop the sender. + result_sender: Option>, + }, /// Report a collator as having provided an invalid collation. This should lead to disconnect /// and blacklist of the collator. ReportCollator(CollatorId), @@ -1104,8 +1109,22 @@ pub struct ProspectiveValidationDataRequest { pub para_id: ParaId, /// The relay-parent of the candidate. pub candidate_relay_parent: Hash, - /// The parent head-data hash. - pub parent_head_data_hash: Hash, + /// The parent head-data. + pub parent_head_data: ParentHeadData, +} + +/// The parent head-data hash with optional data itself. +#[derive(Debug)] +pub enum ParentHeadData { + /// Parent head-data hash. + OnlyHash(Hash), + /// Parent head-data along with its hash. + WithData { + /// This will be provided for collations with elastic scaling enabled. + head_data: HeadData, + /// Parent head-data hash. + hash: Hash, + }, } /// Indicates the relay-parents whose fragment tree a candidate diff --git a/prdoc/pr_3302.prdoc b/prdoc/pr_3302.prdoc new file mode 100644 index 00000000000..a2d93fc6073 --- /dev/null +++ b/prdoc/pr_3302.prdoc @@ -0,0 +1,15 @@ +title: Collator protocol changes for elastic scaling + +doc: + - audience: Node Dev + description: | + This PR introduces changes to the collator protocol to support elastic scaling. + Namely, a new variant added to the collation response to include parent head-data + along with the collation. Currently, the new variant is not being used. + - audience: Node Operator + description: | + Validators are required to upgrade to this version before collators in order to + support the elastic scaling of parachains. + +crates: + - name: polkadot-collator-protocol -- GitLab From d2a7100e3b9832e5288d6d035be6d32bf8961f84 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Sun, 17 Mar 2024 15:21:29 +0200 Subject: [PATCH 046/187] Crowdload burn remaining funds (#3707) Crowdloan account should burn all funds after a crowd loan got dissolved to ensure that the account is reaped correctly. --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Francisco Aguirre --- polkadot/runtime/common/src/crowdloan/mod.rs | 49 ++++++++++++++++++-- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/polkadot/runtime/common/src/crowdloan/mod.rs b/polkadot/runtime/common/src/crowdloan/mod.rs index 6543bf305c4..d405278411b 100644 --- a/polkadot/runtime/common/src/crowdloan/mod.rs +++ b/polkadot/runtime/common/src/crowdloan/mod.rs @@ -60,7 +60,7 @@ use frame_support::{ pallet_prelude::{DispatchResult, Weight}, storage::{child, ChildTriePrefixIterator}, traits::{ - Currency, + Currency, Defensive, ExistenceRequirement::{self, AllowDeath, KeepAlive}, Get, ReservableCurrency, }, @@ -563,6 +563,7 @@ pub mod pallet { let who = ensure_signed(origin)?; let fund = Self::funds(index).ok_or(Error::::InvalidParaId)?; + let pot = Self::fund_account_id(fund.fund_index); let now = frame_system::Pallet::::block_number(); // Only allow dissolution when the raised funds goes to zero, @@ -576,7 +577,10 @@ pub mod pallet { // can take care of that. debug_assert!(Self::contribution_iterator(fund.fund_index).count().is_zero()); - frame_system::Pallet::::dec_providers(&Self::fund_account_id(fund.fund_index))?; + // Crowdloan over, burn all funds. + let _imba = CurrencyOf::::make_free_balance_be(&pot, Zero::zero()); + let _ = frame_system::Pallet::::dec_providers(&pot).defensive(); + CurrencyOf::::unreserve(&fund.depositor, fund.deposit); Funds::::remove(index); Self::deposit_event(Event::::Dissolved { para_id: index }); @@ -1609,6 +1613,7 @@ mod tests { new_test_ext().execute_with(|| { let para = new_para(); let index = NextFundIndex::::get(); + let issuance = Balances::total_issuance(); // Set up a crowdloan assert_ok!(Crowdloan::create(RuntimeOrigin::signed(1), para, 1000, 1, 1, 9, None)); @@ -1629,9 +1634,10 @@ mod tests { // Some funds are left over assert_eq!(Balances::free_balance(&account_id), 10); - // They wil be left in the account at the end + // Remaining funds will be burned assert_ok!(Crowdloan::dissolve(RuntimeOrigin::signed(1), para)); - assert_eq!(Balances::free_balance(&account_id), 10); + assert_eq!(Balances::free_balance(&account_id), 0); + assert_eq!(Balances::total_issuance(), issuance - 10); }); } @@ -1740,6 +1746,41 @@ mod tests { }); } + // Regression test to check that a pot account with just one provider can be dissolved. + #[test] + fn dissolve_provider_refs_total_issuance_works() { + new_test_ext().execute_with(|| { + let para = new_para(); + let issuance = Balances::total_issuance(); + + // Set up a crowdloan + assert_ok!(Crowdloan::create(RuntimeOrigin::signed(1), para, 1000, 1, 1, 9, None)); + assert_ok!(Crowdloan::contribute(RuntimeOrigin::signed(2), para, 100, None)); + assert_ok!(Crowdloan::contribute(RuntimeOrigin::signed(3), para, 50, None)); + + run_to_block(10); + + // We test the historic case where crowdloan accounts only have one provider: + { + let fund = Crowdloan::funds(para).unwrap(); + let pot = Crowdloan::fund_account_id(fund.fund_index); + System::dec_providers(&pot).unwrap(); + assert_eq!(System::providers(&pot), 1); + } + + // All funds are refunded + assert_ok!(Crowdloan::refund(RuntimeOrigin::signed(2), para)); + + // Now that `fund.raised` is zero, it can be dissolved. + assert_ok!(Crowdloan::dissolve(RuntimeOrigin::signed(1), para)); + + assert_eq!(Balances::free_balance(1), 1000); + assert_eq!(Balances::free_balance(2), 2000); + assert_eq!(Balances::free_balance(3), 3000); + assert_eq!(Balances::total_issuance(), issuance); + }); + } + #[test] fn dissolve_works() { new_test_ext().execute_with(|| { -- GitLab From 1f9505c0d358c20a7f95839ff1f8aa65ad843a0a Mon Sep 17 00:00:00 2001 From: s0me0ne-unkn0wn <48632512+s0me0ne-unkn0wn@users.noreply.github.com> Date: Sun, 17 Mar 2024 21:02:11 +0100 Subject: [PATCH 047/187] Eliminate `experimental` feature (#3654) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Totally removes the `experimental` feature. Closes #3648. --------- Co-authored-by: Bastian Köcher --- cumulus/pallets/collator-selection/Cargo.toml | 2 -- .../pallets/collator-selection/src/mock.rs | 1 - .../assets/asset-hub-rococo/Cargo.toml | 2 -- .../assets/asset-hub-rococo/src/lib.rs | 4 ---- .../assets/asset-hub-westend/Cargo.toml | 2 -- .../assets/asset-hub-westend/src/lib.rs | 4 ---- .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 1 - .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 4 ---- .../bridge-hubs/bridge-hub-westend/Cargo.toml | 2 -- .../bridge-hubs/bridge-hub-westend/src/lib.rs | 4 ---- .../collectives-westend/Cargo.toml | 2 -- .../collectives-westend/src/lib.rs | 4 ---- .../contracts/contracts-rococo/Cargo.toml | 2 -- .../contracts/contracts-rococo/src/lib.rs | 4 ---- .../coretime/coretime-rococo/Cargo.toml | 2 -- .../coretime/coretime-rococo/src/lib.rs | 4 ---- .../coretime/coretime-westend/Cargo.toml | 2 -- .../coretime/coretime-westend/src/lib.rs | 4 ---- .../glutton/glutton-westend/Cargo.toml | 2 -- .../glutton/glutton-westend/src/lib.rs | 4 ---- .../runtimes/people/people-rococo/Cargo.toml | 2 -- .../runtimes/people/people-rococo/src/lib.rs | 4 ---- .../runtimes/people/people-westend/Cargo.toml | 2 -- .../runtimes/people/people-westend/src/lib.rs | 4 ---- .../runtimes/starters/seedling/Cargo.toml | 2 -- .../runtimes/starters/seedling/src/lib.rs | 4 ---- .../runtimes/starters/shell/Cargo.toml | 2 -- .../runtimes/starters/shell/src/lib.rs | 4 ---- .../runtimes/testing/penpal/Cargo.toml | 2 -- .../runtimes/testing/penpal/src/lib.rs | 1 - .../testing/rococo-parachain/Cargo.toml | 2 -- .../testing/rococo-parachain/src/lib.rs | 4 ---- docs/sdk/Cargo.toml | 3 --- docs/sdk/src/polkadot_sdk/cumulus.rs | 1 - prdoc/pr_3654.prdoc | 14 ++++++++++++++ substrate/frame/aura/src/lib.rs | 19 +------------------ substrate/frame/aura/src/mock.rs | 2 -- templates/parachain/runtime/Cargo.toml | 2 -- templates/parachain/runtime/src/lib.rs | 1 - templates/solochain/runtime/Cargo.toml | 2 -- templates/solochain/runtime/src/lib.rs | 2 -- 41 files changed, 15 insertions(+), 120 deletions(-) create mode 100644 prdoc/pr_3654.prdoc diff --git a/cumulus/pallets/collator-selection/Cargo.toml b/cumulus/pallets/collator-selection/Cargo.toml index 20f048b97d5..241a78466d6 100644 --- a/cumulus/pallets/collator-selection/Cargo.toml +++ b/cumulus/pallets/collator-selection/Cargo.toml @@ -77,5 +77,3 @@ try-runtime = [ "pallet-timestamp/try-runtime", "sp-runtime/try-runtime", ] - -experimental = ["pallet-aura/experimental"] diff --git a/cumulus/pallets/collator-selection/src/mock.rs b/cumulus/pallets/collator-selection/src/mock.rs index 061d8b1cb31..4a440dfe1e9 100644 --- a/cumulus/pallets/collator-selection/src/mock.rs +++ b/cumulus/pallets/collator-selection/src/mock.rs @@ -125,7 +125,6 @@ impl pallet_aura::Config for Test { type MaxAuthorities = ConstU32<100_000>; type DisabledValidators = (); type AllowMultipleBlocksPerSlot = ConstBool; - #[cfg(feature = "experimental")] type SlotDuration = pallet_aura::MinimumPeriodTimesTwo; } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index 05936e93993..95691a045b7 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -251,8 +251,6 @@ std = [ "xcm/std", ] -experimental = ["pallet-aura/experimental"] - # A feature that should be enabled when the runtime should be built for on-chain # deployment. This will disable stuff that shouldn't be part of the on-chain wasm # to make it smaller, like logging for example. diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 7da9869dd2c..e6b5e55bcd3 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -187,10 +187,7 @@ impl pallet_timestamp::Config for Runtime { /// A timestamp: milliseconds since the unix epoch. type Moment = u64; type OnTimestampSet = Aura; - #[cfg(feature = "experimental")] type MinimumPeriod = ConstU64<0>; - #[cfg(not(feature = "experimental"))] - type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; type WeightInfo = weights::pallet_timestamp::WeightInfo; } @@ -723,7 +720,6 @@ impl pallet_aura::Config for Runtime { type DisabledValidators = (); type MaxAuthorities = ConstU32<100_000>; type AllowMultipleBlocksPerSlot = ConstBool; - #[cfg(feature = "experimental")] type SlotDuration = ConstU64; } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index 78c48507a7a..950c6e62d72 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -236,8 +236,6 @@ std = [ "xcm/std", ] -experimental = ["pallet-aura/experimental"] - # A feature that should be enabled when the runtime should be built for on-chain # deployment. This will disable stuff that shouldn't be part of the on-chain wasm # to make it smaller, like logging for example. diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 3d69e104bd5..1ba108234c8 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -171,10 +171,7 @@ impl pallet_timestamp::Config for Runtime { /// A timestamp: milliseconds since the unix epoch. type Moment = u64; type OnTimestampSet = Aura; - #[cfg(feature = "experimental")] type MinimumPeriod = ConstU64<0>; - #[cfg(not(feature = "experimental"))] - type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; type WeightInfo = weights::pallet_timestamp::WeightInfo; } @@ -703,7 +700,6 @@ impl pallet_aura::Config for Runtime { type DisabledValidators = (); type MaxAuthorities = ConstU32<100_000>; type AllowMultipleBlocksPerSlot = ConstBool; - #[cfg(feature = "experimental")] type SlotDuration = ConstU64; } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml index 7a1951fd24b..8a6823ea3ee 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -296,7 +296,6 @@ try-runtime = [ "sp-runtime/try-runtime", ] -experimental = ["pallet-aura/experimental"] fast-runtime = [] # A feature that should be enabled when the runtime should be built for on-chain diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 843acffe03e..31069778e38 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -277,10 +277,7 @@ impl pallet_timestamp::Config for Runtime { /// A timestamp: milliseconds since the unix epoch. type Moment = u64; type OnTimestampSet = Aura; - #[cfg(feature = "experimental")] type MinimumPeriod = ConstU64<0>; - #[cfg(not(feature = "experimental"))] - type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; type WeightInfo = weights::pallet_timestamp::WeightInfo; } @@ -445,7 +442,6 @@ impl pallet_aura::Config for Runtime { type DisabledValidators = (); type MaxAuthorities = ConstU32<100_000>; type AllowMultipleBlocksPerSlot = ConstBool; - #[cfg(feature = "experimental")] type SlotDuration = ConstU64; } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml index 8623f7cb366..4eb201eedc1 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -246,8 +246,6 @@ try-runtime = [ "sp-runtime/try-runtime", ] -experimental = ["pallet-aura/experimental"] - # A feature that should be enabled when the runtime should be built for on-chain # deployment. This will disable stuff that shouldn't be part of the on-chain wasm # to make it smaller, like logging for example. diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index d70d880c50c..d96c762fe19 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -251,10 +251,7 @@ impl pallet_timestamp::Config for Runtime { /// A timestamp: milliseconds since the unix epoch. type Moment = u64; type OnTimestampSet = Aura; - #[cfg(feature = "experimental")] type MinimumPeriod = ConstU64<0>; - #[cfg(not(feature = "experimental"))] - type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; type WeightInfo = weights::pallet_timestamp::WeightInfo; } @@ -407,7 +404,6 @@ impl pallet_aura::Config for Runtime { type DisabledValidators = (); type MaxAuthorities = ConstU32<100_000>; type AllowMultipleBlocksPerSlot = ConstBool; - #[cfg(feature = "experimental")] type SlotDuration = ConstU64; } diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml index ed264f28c26..4224b397139 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml @@ -232,8 +232,6 @@ std = [ "xcm/std", ] -experimental = ["pallet-aura/experimental"] - # A feature that should be enabled when the runtime should be built for on-chain # deployment. This will disable stuff that shouldn't be part of the on-chain wasm # to make it smaller, like logging for example. diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index 15a2391fa5b..5bf3519ac3d 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -184,10 +184,7 @@ impl pallet_timestamp::Config for Runtime { /// A timestamp: milliseconds since the unix epoch. type Moment = u64; type OnTimestampSet = Aura; - #[cfg(feature = "experimental")] type MinimumPeriod = ConstU64<0>; - #[cfg(not(feature = "experimental"))] - type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; type WeightInfo = weights::pallet_timestamp::WeightInfo; } @@ -483,7 +480,6 @@ impl pallet_aura::Config for Runtime { type DisabledValidators = (); type MaxAuthorities = ConstU32<100_000>; type AllowMultipleBlocksPerSlot = ConstBool; - #[cfg(feature = "experimental")] type SlotDuration = ConstU64; } diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index dcc6c4e853a..e4ac2016a72 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -196,8 +196,6 @@ try-runtime = [ "sp-runtime/try-runtime", ] -experimental = ["pallet-aura/experimental"] - # A feature that should be enabled when the runtime should be built for on-chain # deployment. This will disable stuff that shouldn't be part of the on-chain wasm # to make it smaller, like logging for example. diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 928c3ecc532..f148ceadccb 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -193,10 +193,7 @@ impl pallet_timestamp::Config for Runtime { /// A timestamp: milliseconds since the unix epoch. type Moment = u64; type OnTimestampSet = Aura; - #[cfg(feature = "experimental")] type MinimumPeriod = ConstU64<0>; - #[cfg(not(feature = "experimental"))] - type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; type WeightInfo = pallet_timestamp::weights::SubstrateWeight; } @@ -349,7 +346,6 @@ impl pallet_aura::Config for Runtime { type DisabledValidators = (); type MaxAuthorities = ConstU32<100_000>; type AllowMultipleBlocksPerSlot = ConstBool; - #[cfg(feature = "experimental")] type SlotDuration = ConstU64; } diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml b/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml index 0bc3b510ed5..eb92afc4311 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml @@ -194,6 +194,4 @@ try-runtime = [ "sp-runtime/try-runtime", ] -experimental = ["pallet-aura/experimental"] - fast-runtime = [] diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs index 41b9ffa0af8..6efbdde5899 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs @@ -206,10 +206,7 @@ impl pallet_timestamp::Config for Runtime { /// A timestamp: milliseconds since the unix epoch. type Moment = u64; type OnTimestampSet = Aura; - #[cfg(feature = "experimental")] type MinimumPeriod = ConstU64<0>; - #[cfg(not(feature = "experimental"))] - type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; type WeightInfo = weights::pallet_timestamp::WeightInfo; } @@ -369,7 +366,6 @@ impl pallet_aura::Config for Runtime { type DisabledValidators = (); type MaxAuthorities = ConstU32<100_000>; type AllowMultipleBlocksPerSlot = ConstBool; - #[cfg(feature = "experimental")] type SlotDuration = ConstU64; } diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml b/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml index a7d52dfd784..b8efecffc50 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml @@ -190,6 +190,4 @@ try-runtime = [ "sp-runtime/try-runtime", ] -experimental = ["pallet-aura/experimental"] - fast-runtime = [] diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs index d93c2a61ff4..2bb179b5b05 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs @@ -206,10 +206,7 @@ impl pallet_timestamp::Config for Runtime { /// A timestamp: milliseconds since the unix epoch. type Moment = u64; type OnTimestampSet = Aura; - #[cfg(feature = "experimental")] type MinimumPeriod = ConstU64<0>; - #[cfg(not(feature = "experimental"))] - type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; type WeightInfo = weights::pallet_timestamp::WeightInfo; } @@ -369,7 +366,6 @@ impl pallet_aura::Config for Runtime { type DisabledValidators = (); type MaxAuthorities = ConstU32<100_000>; type AllowMultipleBlocksPerSlot = ConstBool; - #[cfg(feature = "experimental")] type SlotDuration = ConstU64; } diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml b/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml index 23c5ce1c7f8..a357bf519e4 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml @@ -135,8 +135,6 @@ try-runtime = [ "sp-runtime/try-runtime", ] -experimental = ["pallet-aura/experimental"] - # A feature that should be enabled when the runtime should be built for on-chain # deployment. This will disable stuff that shouldn't be part of the on-chain wasm # to make it smaller, like logging for example. diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs index 6967ac58e3b..e7fdb53b253 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs @@ -221,10 +221,7 @@ impl cumulus_pallet_aura_ext::Config for Runtime {} impl pallet_timestamp::Config for Runtime { type Moment = u64; type OnTimestampSet = Aura; - #[cfg(feature = "experimental")] type MinimumPeriod = ConstU64<0>; - #[cfg(not(feature = "experimental"))] - type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; type WeightInfo = weights::pallet_timestamp::WeightInfo; } @@ -233,7 +230,6 @@ impl pallet_aura::Config for Runtime { type DisabledValidators = (); type MaxAuthorities = ConstU32<100_000>; type AllowMultipleBlocksPerSlot = ConstBool; - #[cfg(feature = "experimental")] type SlotDuration = ConstU64; } diff --git a/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml b/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml index c0b8fb7636b..eebd662c3fd 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml @@ -188,5 +188,3 @@ try-runtime = [ "polkadot-runtime-common/try-runtime", "sp-runtime/try-runtime", ] - -experimental = ["pallet-aura/experimental"] diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs index 05da00ac555..98f76984dd4 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs @@ -187,10 +187,7 @@ impl pallet_timestamp::Config for Runtime { /// A timestamp: milliseconds since the unix epoch. type Moment = u64; type OnTimestampSet = Aura; - #[cfg(feature = "experimental")] type MinimumPeriod = ConstU64<0>; - #[cfg(not(feature = "experimental"))] - type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; type WeightInfo = weights::pallet_timestamp::WeightInfo; } @@ -337,7 +334,6 @@ impl pallet_aura::Config for Runtime { type DisabledValidators = (); type MaxAuthorities = ConstU32<100_000>; type AllowMultipleBlocksPerSlot = ConstBool; - #[cfg(feature = "experimental")] type SlotDuration = ConstU64; } diff --git a/cumulus/parachains/runtimes/people/people-westend/Cargo.toml b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml index e87e825a34e..39cb69e679c 100644 --- a/cumulus/parachains/runtimes/people/people-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml @@ -188,5 +188,3 @@ try-runtime = [ "polkadot-runtime-common/try-runtime", "sp-runtime/try-runtime", ] - -experimental = ["pallet-aura/experimental"] diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs index e921df1e5da..5adbdc1f38c 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs @@ -187,10 +187,7 @@ impl pallet_timestamp::Config for Runtime { /// A timestamp: milliseconds since the unix epoch. type Moment = u64; type OnTimestampSet = Aura; - #[cfg(feature = "experimental")] type MinimumPeriod = ConstU64<0>; - #[cfg(not(feature = "experimental"))] - type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; type WeightInfo = weights::pallet_timestamp::WeightInfo; } @@ -337,7 +334,6 @@ impl pallet_aura::Config for Runtime { type DisabledValidators = (); type MaxAuthorities = ConstU32<100_000>; type AllowMultipleBlocksPerSlot = ConstBool; - #[cfg(feature = "experimental")] type SlotDuration = ConstU64; } diff --git a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml index 1f5bee7784e..9f08fdf5943 100644 --- a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml @@ -79,5 +79,3 @@ std = [ "sp-version/std", "substrate-wasm-builder", ] - -experimental = ["pallet-aura/experimental"] diff --git a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs index 179bda356ae..bf4768d8457 100644 --- a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs @@ -213,17 +213,13 @@ impl pallet_aura::Config for Runtime { type DisabledValidators = (); type MaxAuthorities = ConstU32<100_000>; type AllowMultipleBlocksPerSlot = ConstBool; - #[cfg(feature = "experimental")] type SlotDuration = pallet_aura::MinimumPeriodTimesTwo; } impl pallet_timestamp::Config for Runtime { type Moment = u64; type OnTimestampSet = Aura; - #[cfg(feature = "experimental")] type MinimumPeriod = ConstU64<0>; - #[cfg(not(feature = "experimental"))] - type MinimumPeriod = ConstU64<{ parachains_common::SLOT_DURATION / 2 }>; type WeightInfo = (); } diff --git a/cumulus/parachains/runtimes/starters/shell/Cargo.toml b/cumulus/parachains/runtimes/starters/shell/Cargo.toml index 5a8f2a9d125..2f82547afe9 100644 --- a/cumulus/parachains/runtimes/starters/shell/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/shell/Cargo.toml @@ -99,5 +99,3 @@ try-runtime = [ "parachain-info/try-runtime", "sp-runtime/try-runtime", ] - -experimental = ["pallet-aura/experimental"] diff --git a/cumulus/parachains/runtimes/starters/shell/src/lib.rs b/cumulus/parachains/runtimes/starters/shell/src/lib.rs index c0904f0faef..51fdfac5b1c 100644 --- a/cumulus/parachains/runtimes/starters/shell/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/shell/src/lib.rs @@ -241,17 +241,13 @@ impl pallet_aura::Config for Runtime { type DisabledValidators = (); type MaxAuthorities = ConstU32<100_000>; type AllowMultipleBlocksPerSlot = ConstBool; - #[cfg(feature = "experimental")] type SlotDuration = pallet_aura::MinimumPeriodTimesTwo; } impl pallet_timestamp::Config for Runtime { type Moment = u64; type OnTimestampSet = Aura; - #[cfg(feature = "experimental")] type MinimumPeriod = ConstU64<0>; - #[cfg(not(feature = "experimental"))] - type MinimumPeriod = ConstU64<{ parachains_common::SLOT_DURATION / 2 }>; type WeightInfo = (); } diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index 7f3e898d923..c18f6571f41 100644 --- a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml @@ -191,5 +191,3 @@ try-runtime = [ "polkadot-runtime-common/try-runtime", "sp-runtime/try-runtime", ] - -experimental = ["pallet-aura/experimental"] diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index 24a325c6f5b..3063601e030 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -582,7 +582,6 @@ impl pallet_aura::Config for Runtime { type DisabledValidators = (); type MaxAuthorities = ConstU32<100_000>; type AllowMultipleBlocksPerSlot = ConstBool; - #[cfg(feature = "experimental")] type SlotDuration = pallet_aura::MinimumPeriodTimesTwo; } diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml index 42169e8949f..577ed749167 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -134,5 +134,3 @@ runtime-benchmarks = [ "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", ] - -experimental = ["pallet-aura/experimental"] diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index aea139fb66e..753d2d12065 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -228,10 +228,7 @@ impl pallet_timestamp::Config for Runtime { /// A timestamp: milliseconds since the unix epoch. type Moment = u64; type OnTimestampSet = Aura; - #[cfg(feature = "experimental")] type MinimumPeriod = ConstU64<0>; - #[cfg(not(feature = "experimental"))] - type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; type WeightInfo = (); } @@ -594,7 +591,6 @@ impl pallet_aura::Config for Runtime { type DisabledValidators = (); type MaxAuthorities = ConstU32<100_000>; type AllowMultipleBlocksPerSlot = ConstBool; - #[cfg(feature = "experimental")] type SlotDuration = ConstU64; } diff --git a/docs/sdk/Cargo.toml b/docs/sdk/Cargo.toml index 8b498d407c0..3f40a950c28 100644 --- a/docs/sdk/Cargo.toml +++ b/docs/sdk/Cargo.toml @@ -86,6 +86,3 @@ sp-version = { path = "../../substrate/primitives/version" } # XCM xcm = { package = "staging-xcm", path = "../../polkadot/xcm" } - -[features] -experimental = ["pallet-aura/experimental"] diff --git a/docs/sdk/src/polkadot_sdk/cumulus.rs b/docs/sdk/src/polkadot_sdk/cumulus.rs index 7d9daf9067c..9bd957c7c1c 100644 --- a/docs/sdk/src/polkadot_sdk/cumulus.rs +++ b/docs/sdk/src/polkadot_sdk/cumulus.rs @@ -110,7 +110,6 @@ mod tests { type DisabledValidators = (); type MaxAuthorities = ConstU32<100_000>; type AllowMultipleBlocksPerSlot = ConstBool; - #[cfg(feature = "experimental")] type SlotDuration = pallet_aura::MinimumPeriodTimesTwo; } diff --git a/prdoc/pr_3654.prdoc b/prdoc/pr_3654.prdoc new file mode 100644 index 00000000000..de4a68d2356 --- /dev/null +++ b/prdoc/pr_3654.prdoc @@ -0,0 +1,14 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Remove `experimental` feature from `pallet-aura` + +doc: + - audience: Runtime Dev + description: | + The `experimental` feature in `pallet-aura`, previously used to gate different experimental + changes, became redundant with the introduction of the async backing which relies on the + mentioned changes, therefore, it is removed. + +crates: + - name: pallet-aura diff --git a/substrate/frame/aura/src/lib.rs b/substrate/frame/aura/src/lib.rs index f7506db05d1..55653de97a8 100644 --- a/substrate/frame/aura/src/lib.rs +++ b/substrate/frame/aura/src/lib.rs @@ -66,9 +66,6 @@ const LOG_TARGET: &str = "runtime::aura"; /// /// This was the default behavior of the Aura pallet and may be used for /// backwards compatibility. -/// -/// Note that this type is likely not useful without the `experimental` -/// feature. pub struct MinimumPeriodTimesTwo(sp_std::marker::PhantomData); impl Get for MinimumPeriodTimesTwo { @@ -117,10 +114,6 @@ pub mod pallet { /// The effective value of this type should not change while the chain is running. /// /// For backwards compatibility either use [`MinimumPeriodTimesTwo`] or a const. - /// - /// This associated type is only present when compiled with the `experimental` - /// feature. - #[cfg(feature = "experimental")] type SlotDuration: Get<::Moment>; } @@ -250,17 +243,7 @@ impl Pallet { /// Determine the Aura slot-duration based on the Timestamp module configuration. pub fn slot_duration() -> T::Moment { - #[cfg(feature = "experimental")] - { - T::SlotDuration::get() - } - - #[cfg(not(feature = "experimental"))] - { - // we double the minimum block-period so each author can always propose within - // the majority of its slot. - ::MinimumPeriod::get().saturating_mul(2u32.into()) - } + T::SlotDuration::get() } /// Ensure the correctness of the state of this pallet. diff --git a/substrate/frame/aura/src/mock.rs b/substrate/frame/aura/src/mock.rs index 535e27fa35e..786e6e2efaf 100644 --- a/substrate/frame/aura/src/mock.rs +++ b/substrate/frame/aura/src/mock.rs @@ -84,8 +84,6 @@ impl pallet_aura::Config for Test { type DisabledValidators = MockDisabledValidators; type MaxAuthorities = ConstU32<10>; type AllowMultipleBlocksPerSlot = AllowMultipleBlocksPerSlot; - - #[cfg(feature = "experimental")] type SlotDuration = ConstU64; } diff --git a/templates/parachain/runtime/Cargo.toml b/templates/parachain/runtime/Cargo.toml index 9d9da2b4b97..41a510c5ed3 100644 --- a/templates/parachain/runtime/Cargo.toml +++ b/templates/parachain/runtime/Cargo.toml @@ -194,5 +194,3 @@ try-runtime = [ "polkadot-runtime-common/try-runtime", "sp-runtime/try-runtime", ] - -experimental = ["pallet-aura/experimental"] diff --git a/templates/parachain/runtime/src/lib.rs b/templates/parachain/runtime/src/lib.rs index dcfab59eb81..acaabc0dbc3 100644 --- a/templates/parachain/runtime/src/lib.rs +++ b/templates/parachain/runtime/src/lib.rs @@ -453,7 +453,6 @@ impl pallet_aura::Config for Runtime { type DisabledValidators = (); type MaxAuthorities = ConstU32<100_000>; type AllowMultipleBlocksPerSlot = ConstBool; - #[cfg(feature = "experimental")] type SlotDuration = pallet_aura::MinimumPeriodTimesTwo; } diff --git a/templates/solochain/runtime/Cargo.toml b/templates/solochain/runtime/Cargo.toml index a7fc0519ba2..33da035878a 100644 --- a/templates/solochain/runtime/Cargo.toml +++ b/templates/solochain/runtime/Cargo.toml @@ -147,5 +147,3 @@ try-runtime = [ "pallet-transaction-payment/try-runtime", "sp-runtime/try-runtime", ] - -experimental = ["pallet-aura/experimental"] diff --git a/templates/solochain/runtime/src/lib.rs b/templates/solochain/runtime/src/lib.rs index 358db0849a0..9b52ee60a63 100644 --- a/templates/solochain/runtime/src/lib.rs +++ b/templates/solochain/runtime/src/lib.rs @@ -180,8 +180,6 @@ impl pallet_aura::Config for Runtime { type DisabledValidators = (); type MaxAuthorities = ConstU32<32>; type AllowMultipleBlocksPerSlot = ConstBool; - - #[cfg(feature = "experimental")] type SlotDuration = pallet_aura::MinimumPeriodTimesTwo; } -- GitLab From fe343cc71cbe85264a1df4ecf4d6848a707f0982 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 17 Mar 2024 21:19:21 +0100 Subject: [PATCH 048/187] Bump the known_good_semver group with 3 updates (#3717) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the known_good_semver group with 3 updates: [log](https://github.com/rust-lang/log), [syn](https://github.com/dtolnay/syn) and [clap](https://github.com/clap-rs/clap). Updates `log` from 0.4.20 to 0.4.21
Changelog

Sourced from log's changelog.

[0.4.21] - 2024-02-27

What's Changed

New Contributors

Commits
  • 3ccdc28 Merge pull request #617 from rust-lang/cargo/0.4.21
  • 6153cb2 prepare for 0.4.21 release
  • f0f7494 Merge pull request #613 from rust-lang/feat/kv-cleanup
  • 2b220bf clean up structured logging example
  • 646e9ab use original Visitor name for VisitValue
  • cf85c38 add needed subfeatures to kv_unstable
  • 73e9539 fix up capturing of :err
  • 31bb4b0 move error macros together
  • ad91711 support field shorthand in macros
  • 90a347b restore removed APIs as deprecated
  • Additional commits viewable in compare view

Updates `syn` from 2.0.50 to 2.0.52
Release notes

Sourced from syn's releases.

2.0.52

  • Add an expression parser that uses match-arm's boundary rules (#1593)

2.0.51

  • Resolve non_local_definitions warnings in generated code under rustc 1.78-nightly
Commits
  • 07ede6a Release 2.0.52
  • acbcfbc Merge pull request #1593 from dtolnay/boundary
  • 4924a99 Add an expression parser that uses match-arm's boundary rules
  • e06122b Resolve unnecessary_get_then_check clippy lint
  • 018fc5a Update test suite to nightly-2024-02-27
  • 5e15a9b Release 2.0.51
  • 7e0d4e1 Resolve non_local_definitions warning in debug impls
  • 8667ad9 Ignore module_name_repetitions pedantic clippy lint in codegen
  • 1fc3200 Update test suite to nightly-2024-02-26
  • 07a2065 Update test suite to nightly-2024-02-23
  • See full diff in compare view

Updates `clap` from 4.5.1 to 4.5.3
Release notes

Sourced from clap's releases.

v4.5.3

[4.5.3] - 2024-03-15

Internal

  • (derive) Update heck

v4.5.2

[4.5.2] - 2024-03-06

Fixes

  • (macros) Silence a warning
Changelog

Sourced from clap's changelog.

[4.5.3] - 2024-03-15

Internal

  • (derive) Update heck

[4.5.2] - 2024-03-06

Fixes

  • (macros) Silence a warning
Commits
  • 4e07b43 chore: Release
  • 8247c7d docs: Update changelog
  • 677c52c chore: Update heck requirement (#5396)
  • f65d421 chore: Release
  • 886b272 docs: Update changelog
  • 3ba4297 Merge pull request #5386 from amaanq/static-var-name
  • 2aea950 fix: Use SCREAMING_SNAKE_CASE for static variable authors
  • 690f555 Merge pull request #5382 from clap-rs/renovate/pre-commit-action-3.x
  • a2aa644 chore(deps): update compatible (dev) (#5381)
  • c233de5 chore(deps): update pre-commit/action action to v3.0.1
  • Additional commits viewable in compare view

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 240 +++++++++--------- Cargo.toml | 4 +- cumulus/client/cli/Cargo.toml | 2 +- cumulus/polkadot-parachain/Cargo.toml | 2 +- cumulus/test/service/Cargo.toml | 2 +- polkadot/cli/Cargo.toml | 2 +- polkadot/node/malus/Cargo.toml | 2 +- polkadot/node/subsystem-bench/Cargo.toml | 2 +- .../test-parachains/adder/collator/Cargo.toml | 2 +- .../undying/collator/Cargo.toml | 2 +- polkadot/utils/generate-bags/Cargo.toml | 2 +- .../remote-ext-tests/bags-list/Cargo.toml | 2 +- substrate/bin/node/bench/Cargo.toml | 2 +- substrate/bin/node/cli/Cargo.toml | 4 +- substrate/bin/node/inspect/Cargo.toml | 2 +- .../bin/utils/chain-spec-builder/Cargo.toml | 2 +- substrate/bin/utils/subkey/Cargo.toml | 2 +- substrate/client/cli/Cargo.toml | 2 +- substrate/client/storage-monitor/Cargo.toml | 2 +- .../solution-type/fuzzer/Cargo.toml | 2 +- .../single-block-migrations/Cargo.toml | 2 +- substrate/frame/migrations/Cargo.toml | 2 +- .../npos-elections/fuzzer/Cargo.toml | 2 +- .../ci/node-template-release/Cargo.toml | 2 +- .../utils/frame/benchmarking-cli/Cargo.toml | 2 +- .../frame/frame-utilities-cli/Cargo.toml | 2 +- .../generate-bags/node-runtime/Cargo.toml | 2 +- .../utils/frame/try-runtime/cli/Cargo.toml | 2 +- templates/minimal/node/Cargo.toml | 2 +- templates/parachain/node/Cargo.toml | 2 +- templates/solochain/node/Cargo.toml | 2 +- 31 files changed, 155 insertions(+), 149 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 699fd35a824..f3535d509ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -191,7 +191,7 @@ checksum = "c0391754c09fab4eae3404d19d0d297aa1c670c1775ab51d8a5312afeca23157" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -202,11 +202,11 @@ checksum = "8a98ad1696a2e17f010ae8e43e9f2a1e930ed176a8e3ff77acfeff6dfb07b42c" dependencies = [ "const-hex", "dunce", - "heck", + "heck 0.4.1", "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", "syn-solidity", "tiny-keccak", ] @@ -347,7 +347,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -1228,7 +1228,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -1245,7 +1245,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -1427,7 +1427,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -2613,12 +2613,12 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.1" +version = "4.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da" +checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813" dependencies = [ "clap_builder", - "clap_derive 4.5.0", + "clap_derive 4.5.3", ] [[package]] @@ -2632,9 +2632,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.1" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ "anstream", "anstyle", @@ -2649,7 +2649,7 @@ version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "586a385f7ef2f8b4d86bddaa0c094794e7ccbfe5ffef1f434fe928143fc783a5" dependencies = [ - "clap 4.5.1", + "clap 4.5.3", ] [[package]] @@ -2658,7 +2658,7 @@ version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro-error", "proc-macro2", "quote", @@ -2667,14 +2667,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.0" +version = "4.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" +checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f" dependencies = [ - "heck", + "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -3383,7 +3383,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.5.1", + "clap 4.5.3", "criterion-plot", "futures", "is-terminal", @@ -3536,7 +3536,7 @@ dependencies = [ name = "cumulus-client-cli" version = "0.7.0" dependencies = [ - "clap 4.5.1", + "clap 4.5.3", "parity-scale-codec", "sc-chain-spec", "sc-cli", @@ -3895,7 +3895,7 @@ dependencies = [ "proc-macro-crate 3.0.0", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -4299,7 +4299,7 @@ name = "cumulus-test-service" version = "0.1.0" dependencies = [ "async-trait", - "clap 4.5.1", + "clap 4.5.3", "criterion 0.5.1", "cumulus-client-cli", "cumulus-client-consensus-common", @@ -4410,7 +4410,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -4450,7 +4450,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -4467,7 +4467,7 @@ checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -4675,7 +4675,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -4745,7 +4745,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.50", + "syn 2.0.52", "termcolor", "walkdir", ] @@ -4762,7 +4762,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.50", + "syn 2.0.52", "termcolor", "toml 0.8.8", "walkdir", @@ -4967,7 +4967,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "quote", "syn 1.0.109", @@ -4990,7 +4990,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -5001,7 +5001,7 @@ checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -5054,9 +5054,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "erased-serde" -version = "0.3.30" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "837c0466252947ada828b975e12daf82e18bb5444e4df87be6038d4469e2a3d2" +checksum = "2b73807008a3c7f171cc40312f37d95ef0396e048b5848d775f54b1a4dd4a0d3" dependencies = [ "serde", ] @@ -5191,7 +5191,7 @@ dependencies = [ "fs-err", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -5512,7 +5512,7 @@ dependencies = [ "Inflector", "array-bytes 6.1.0", "chrono", - "clap 4.5.1", + "clap 4.5.3", "comfy-table", "frame-benchmarking", "frame-support", @@ -5578,7 +5578,7 @@ dependencies = [ "quote", "scale-info", "sp-arithmetic", - "syn 2.0.50", + "syn 2.0.52", "trybuild", ] @@ -5604,7 +5604,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.5.1", + "clap 4.5.3", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -5735,7 +5735,7 @@ dependencies = [ "quote", "regex", "sp-crypto-hashing", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -5746,7 +5746,7 @@ dependencies = [ "proc-macro-crate 3.0.0", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -5755,7 +5755,7 @@ version = "11.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -5988,7 +5988,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -6342,6 +6342,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -6935,7 +6941,7 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69fc56131589f82e57805f7338b87023db4aafef813555708b159787e34ad6bc" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro-crate 3.0.0", "proc-macro2", "quote", @@ -7586,7 +7592,7 @@ version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fba456131824ab6acd4c7bf61e9c0f0a3014b5fc9868ccb8e10d344594cdc4f" dependencies = [ - "heck", + "heck 0.4.1", "quote", "syn 1.0.109", ] @@ -7839,9 +7845,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" dependencies = [ "serde", "value-bag", @@ -7927,7 +7933,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -7941,7 +7947,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -7952,7 +7958,7 @@ checksum = "9ea73aa640dc01d62a590d48c0c3521ed739d53b27f919b25c3551e233481654" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -7963,7 +7969,7 @@ checksum = "ef9d79ae96aaba821963320eb2b6e34d17df1e5a83d8a1985c29cc5be59577b3" dependencies = [ "macro_magic_core", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -8120,7 +8126,7 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" name = "minimal-template-node" version = "0.0.0" dependencies = [ - "clap 4.5.1", + "clap 4.5.3", "frame", "futures", "futures-timer", @@ -8589,7 +8595,7 @@ name = "node-bench" version = "0.9.0-dev" dependencies = [ "array-bytes 6.1.0", - "clap 4.5.1", + "clap 4.5.3", "derive_more", "fs_extra", "futures", @@ -8666,7 +8672,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 4.5.1", + "clap 4.5.3", "generate-bags", "kitchensink-runtime", ] @@ -8675,7 +8681,7 @@ dependencies = [ name = "node-template-release" version = "3.0.0" dependencies = [ - "clap 4.5.1", + "clap 4.5.3", "flate2", "fs_extra", "glob", @@ -9624,7 +9630,7 @@ version = "18.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -10852,7 +10858,7 @@ dependencies = [ "proc-macro2", "quote", "sp-runtime", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -11257,7 +11263,7 @@ dependencies = [ name = "parachain-template-node" version = "0.0.0" dependencies = [ - "clap 4.5.1", + "clap 4.5.3", "color-print", "cumulus-client-cli", "cumulus-client-collator", @@ -11947,7 +11953,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -11988,7 +11994,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -12203,7 +12209,7 @@ name = "polkadot-cli" version = "7.0.0" dependencies = [ "cfg-if", - "clap 4.5.1", + "clap 4.5.3", "frame-benchmarking-cli", "futures", "log", @@ -13053,7 +13059,7 @@ dependencies = [ "async-trait", "bridge-hub-rococo-runtime", "bridge-hub-westend-runtime", - "clap 4.5.1", + "clap 4.5.3", "collectives-westend-runtime", "color-print", "contracts-rococo-runtime", @@ -13589,7 +13595,7 @@ dependencies = [ "async-trait", "bincode", "bitvec", - "clap 4.5.1", + "clap 4.5.3", "clap-num", "color-eyre", "colored", @@ -13683,7 +13689,7 @@ version = "1.0.0" dependencies = [ "assert_matches", "async-trait", - "clap 4.5.1", + "clap 4.5.3", "color-eyre", "futures", "futures-timer", @@ -13830,7 +13836,7 @@ dependencies = [ name = "polkadot-voter-bags" version = "7.0.0" dependencies = [ - "clap 4.5.1", + "clap 4.5.3", "generate-bags", "sp-io", "westend-runtime", @@ -13885,7 +13891,7 @@ dependencies = [ "polkavm-common", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -13895,7 +13901,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429" dependencies = [ "polkavm-derive-impl", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -14091,7 +14097,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" dependencies = [ "proc-macro2", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -14182,7 +14188,7 @@ checksum = "9b698b0b09d40e9b7c1a47b132d66a8b54bcd20583d9b6d06e4535e383b4405c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -14254,7 +14260,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -14316,7 +14322,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" dependencies = [ "bytes", - "heck", + "heck 0.4.1", "itertools 0.10.5", "lazy_static", "log", @@ -14354,7 +14360,7 @@ dependencies = [ "itertools 0.11.0", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -14697,7 +14703,7 @@ checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -14785,7 +14791,7 @@ checksum = "e898588f33fdd5b9420719948f9f2a32c922a246964576f71ba7f24f80610fbc" name = "remote-ext-tests-bags-list" version = "1.0.0" dependencies = [ - "clap 4.5.1", + "clap 4.5.3", "frame-system", "log", "pallet-bags-list-remote-tests", @@ -15188,7 +15194,7 @@ dependencies = [ "regex", "relative-path", "rustc_version 0.4.0", - "syn 2.0.50", + "syn 2.0.52", "unicode-ident", ] @@ -15642,7 +15648,7 @@ dependencies = [ "proc-macro-crate 3.0.0", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -15651,7 +15657,7 @@ version = "0.36.0" dependencies = [ "array-bytes 6.1.0", "chrono", - "clap 4.5.1", + "clap 4.5.3", "fdlimit", "futures", "futures-timer", @@ -16822,7 +16828,7 @@ dependencies = [ name = "sc-storage-monitor" version = "0.16.0" dependencies = [ - "clap 4.5.1", + "clap 4.5.3", "fs4", "log", "sp-core", @@ -16924,7 +16930,7 @@ dependencies = [ "proc-macro-crate 3.0.0", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -17326,7 +17332,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -17426,7 +17432,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -18224,7 +18230,7 @@ dependencies = [ name = "solochain-template-node" version = "0.0.0" dependencies = [ - "clap 4.5.1", + "clap 4.5.3", "frame-benchmarking-cli", "frame-system", "futures", @@ -18334,7 +18340,7 @@ dependencies = [ "proc-macro-crate 3.0.0", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -18728,7 +18734,7 @@ version = "0.0.0" dependencies = [ "quote", "sp-crypto-hashing", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -18746,7 +18752,7 @@ source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf5 dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -18755,7 +18761,7 @@ version = "14.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -18915,7 +18921,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.5.1", + "clap 4.5.3", "honggfuzz", "rand", "sp-npos-elections", @@ -19030,7 +19036,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -19042,7 +19048,7 @@ dependencies = [ "proc-macro-crate 3.0.0", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -19314,7 +19320,7 @@ dependencies = [ "proc-macro2", "quote", "sp-version", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -19438,7 +19444,7 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" name = "staging-chain-spec-builder" version = "2.0.0" dependencies = [ - "clap 4.5.1", + "clap 4.5.3", "log", "sc-chain-spec", "serde_json", @@ -19451,7 +19457,7 @@ version = "3.0.0-dev" dependencies = [ "array-bytes 6.1.0", "assert_cmd", - "clap 4.5.1", + "clap 4.5.3", "clap_complete", "criterion 0.4.0", "frame-benchmarking", @@ -19561,7 +19567,7 @@ dependencies = [ name = "staging-node-inspect" version = "0.12.0" dependencies = [ - "clap 4.5.1", + "clap 4.5.3", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -19742,7 +19748,7 @@ version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "quote", "rustversion", @@ -19755,18 +19761,18 @@ version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "quote", "rustversion", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] name = "subkey" version = "9.0.0" dependencies = [ - "clap 4.5.1", + "clap 4.5.3", "sc-cli", ] @@ -19808,7 +19814,7 @@ dependencies = [ name = "substrate-frame-cli" version = "32.0.0" dependencies = [ - "clap 4.5.1", + "clap 4.5.3", "frame-support", "frame-system", "sc-cli", @@ -20157,9 +20163,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.50" +version = "2.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" dependencies = [ "proc-macro2", "quote", @@ -20175,7 +20181,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -20289,7 +20295,7 @@ dependencies = [ name = "test-parachain-adder-collator" version = "1.0.0" dependencies = [ - "clap 4.5.1", + "clap 4.5.3", "futures", "futures-timer", "log", @@ -20337,7 +20343,7 @@ dependencies = [ name = "test-parachain-undying-collator" version = "1.0.0" dependencies = [ - "clap 4.5.1", + "clap 4.5.3", "futures", "futures-timer", "log", @@ -20440,7 +20446,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -20601,7 +20607,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -20808,7 +20814,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -20850,7 +20856,7 @@ dependencies = [ "proc-macro-crate 3.0.0", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -21032,7 +21038,7 @@ version = "0.38.0" dependencies = [ "assert_cmd", "async-trait", - "clap 4.5.1", + "clap 4.5.3", "frame-remote-externalities", "frame-try-runtime", "hex", @@ -21270,9 +21276,9 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "value-bag" -version = "1.4.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d92ccd67fb88503048c01b59152a04effd0782d035a83a6d256ce6085f08f4a3" +checksum = "8fec26a25bd6fca441cdd0f769fd7f891bae119f996de31f86a5eddccef54c1d" dependencies = [ "value-bag-serde1", "value-bag-sval2", @@ -21280,9 +21286,9 @@ dependencies = [ [[package]] name = "value-bag-serde1" -version = "1.4.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0b9f3feef403a50d4d67e9741a6d8fc688bcbb4e4f31bd4aab72cc690284394" +checksum = "ead5b693d906686203f19a49e88c477fb8c15798b68cf72f60b4b5521b4ad891" dependencies = [ "erased-serde", "serde", @@ -21291,9 +21297,9 @@ dependencies = [ [[package]] name = "value-bag-sval2" -version = "1.4.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b24f4146b6f3361e91cbf527d1fb35e9376c3c0cef72ca5ec5af6d640fad7d" +checksum = "3b9d0f4a816370c3a0d7d82d603b62198af17675b12fe5e91de6b47ceb505882" dependencies = [ "sval", "sval_buffer", @@ -21415,7 +21421,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", "wasm-bindgen-shared", ] @@ -21449,7 +21455,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -22466,7 +22472,7 @@ dependencies = [ "proc-macro2", "quote", "staging-xcm", - "syn 2.0.50", + "syn 2.0.52", "trybuild", ] @@ -22588,7 +22594,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -22608,7 +22614,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index f256d02808a..3acb6c1d055 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -547,14 +547,14 @@ default_constructed_unit_structs = { level = "allow", priority = 2 } # stylistic polkavm = "0.9.3" polkavm-linker = "0.9.2" polkavm-derive = "0.9.1" -log = { version = "0.4.20", default-features = false } +log = { version = "0.4.21", default-features = false } quote = { version = "1.0.33" } serde = { version = "1.0.197", default-features = false } serde-big-array = { version = "0.3.2" } serde_derive = { version = "1.0.117" } serde_json = { version = "1.0.114", default-features = false } serde_yaml = { version = "0.9" } -syn = { version = "2.0.50" } +syn = { version = "2.0.52" } thiserror = { version = "1.0.48" } [profile.release] diff --git a/cumulus/client/cli/Cargo.toml b/cumulus/client/cli/Cargo.toml index eaf0d5d5d7f..0b2edb593c4 100644 --- a/cumulus/client/cli/Cargo.toml +++ b/cumulus/client/cli/Cargo.toml @@ -10,7 +10,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -clap = { version = "4.5.1", features = ["derive"] } +clap = { version = "4.5.3", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } url = "2.4.0" diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index 84a232e954f..70423856d34 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -16,7 +16,7 @@ path = "src/main.rs" [dependencies] async-trait = "0.1.74" -clap = { version = "4.5.1", features = ["derive"] } +clap = { version = "4.5.3", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.28" hex-literal = "0.4.1" diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index 27273f4e0a8..45e21432f5b 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -14,7 +14,7 @@ path = "src/main.rs" [dependencies] async-trait = "0.1.74" -clap = { version = "4.5.1", features = ["derive"] } +clap = { version = "4.5.3", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } criterion = { version = "0.5.1", features = ["async_tokio"] } jsonrpsee = { version = "0.22", features = ["server"] } diff --git a/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml index b9232f95981..f57efa7ba43 100644 --- a/polkadot/cli/Cargo.toml +++ b/polkadot/cli/Cargo.toml @@ -19,7 +19,7 @@ crate-type = ["cdylib", "rlib"] [dependencies] cfg-if = "1.0" -clap = { version = "4.5.1", features = ["derive"], optional = true } +clap = { version = "4.5.3", features = ["derive"], optional = true } log = { workspace = true, default-features = true } thiserror = { workspace = true } futures = "0.3.21" diff --git a/polkadot/node/malus/Cargo.toml b/polkadot/node/malus/Cargo.toml index ea25b9077f3..b3eb856f08e 100644 --- a/polkadot/node/malus/Cargo.toml +++ b/polkadot/node/malus/Cargo.toml @@ -43,7 +43,7 @@ assert_matches = "1.5" async-trait = "0.1.74" sp-keystore = { path = "../../../substrate/primitives/keystore" } sp-core = { path = "../../../substrate/primitives/core" } -clap = { version = "4.5.1", features = ["derive"] } +clap = { version = "4.5.3", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../gum" } diff --git a/polkadot/node/subsystem-bench/Cargo.toml b/polkadot/node/subsystem-bench/Cargo.toml index 7c60ff48269..71711ad0fbd 100644 --- a/polkadot/node/subsystem-bench/Cargo.toml +++ b/polkadot/node/subsystem-bench/Cargo.toml @@ -39,7 +39,7 @@ async-trait = "0.1.57" sp-keystore = { path = "../../../substrate/primitives/keystore" } sc-keystore = { path = "../../../substrate/client/keystore" } sp-core = { path = "../../../substrate/primitives/core" } -clap = { version = "4.5.1", features = ["derive"] } +clap = { version = "4.5.3", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" bincode = "1.3.3" diff --git a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml index 8ce4ceb47c2..cb283c27119 100644 --- a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml @@ -16,7 +16,7 @@ path = "src/main.rs" [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -clap = { version = "4.5.1", features = ["derive"] } +clap = { version = "4.5.3", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" log = { workspace = true, default-features = true } diff --git a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml index 25fdbfa74ea..238b98a6680 100644 --- a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml @@ -16,7 +16,7 @@ path = "src/main.rs" [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -clap = { version = "4.5.1", features = ["derive"] } +clap = { version = "4.5.3", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" log = { workspace = true, default-features = true } diff --git a/polkadot/utils/generate-bags/Cargo.toml b/polkadot/utils/generate-bags/Cargo.toml index c0e9bd332df..ad6d7259d24 100644 --- a/polkadot/utils/generate-bags/Cargo.toml +++ b/polkadot/utils/generate-bags/Cargo.toml @@ -10,7 +10,7 @@ description = "CLI to generate voter bags for Polkadot runtimes" workspace = true [dependencies] -clap = { version = "4.5.1", features = ["derive"] } +clap = { version = "4.5.3", features = ["derive"] } generate-bags = { path = "../../../substrate/utils/frame/generate-bags" } sp-io = { path = "../../../substrate/primitives/io" } diff --git a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml index ddc5af97a16..20e4130f888 100644 --- a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml +++ b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml @@ -18,6 +18,6 @@ sp-tracing = { path = "../../../../substrate/primitives/tracing" } frame-system = { path = "../../../../substrate/frame/system" } sp-core = { path = "../../../../substrate/primitives/core" } -clap = { version = "4.5.1", features = ["derive"] } +clap = { version = "4.5.3", features = ["derive"] } log = { workspace = true, default-features = true } tokio = { version = "1.24.2", features = ["macros"] } diff --git a/substrate/bin/node/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml index 8e0f7fb93b3..d5de1dbe6c4 100644 --- a/substrate/bin/node/bench/Cargo.toml +++ b/substrate/bin/node/bench/Cargo.toml @@ -16,7 +16,7 @@ workspace = true [dependencies] array-bytes = "6.1" -clap = { version = "4.5.1", features = ["derive"] } +clap = { version = "4.5.3", features = ["derive"] } log = { workspace = true, default-features = true } node-primitives = { path = "../primitives" } node-testing = { path = "../testing" } diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index abe284c41da..8bddbbe0482 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -41,7 +41,7 @@ crate-type = ["cdylib", "rlib"] [dependencies] # third-party dependencies array-bytes = "6.1" -clap = { version = "4.5.1", features = ["derive"], optional = true } +clap = { version = "4.5.3", features = ["derive"], optional = true } codec = { package = "parity-scale-codec", version = "3.6.1" } serde = { features = ["derive"], workspace = true, default-features = true } jsonrpsee = { version = "0.22", features = ["server"] } @@ -165,7 +165,7 @@ sp-trie = { path = "../../../primitives/trie" } sp-state-machine = { path = "../../../primitives/state-machine" } [build-dependencies] -clap = { version = "4.5.1", optional = true } +clap = { version = "4.5.3", optional = true } clap_complete = { version = "4.0.2", optional = true } node-inspect = { package = "staging-node-inspect", path = "../inspect", optional = true } frame-benchmarking-cli = { path = "../../../utils/frame/benchmarking-cli", optional = true } diff --git a/substrate/bin/node/inspect/Cargo.toml b/substrate/bin/node/inspect/Cargo.toml index 7db6e3efd3a..8453aa3cdeb 100644 --- a/substrate/bin/node/inspect/Cargo.toml +++ b/substrate/bin/node/inspect/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "4.5.1", features = ["derive"] } +clap = { version = "4.5.3", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1" } thiserror = { workspace = true } sc-cli = { path = "../../../client/cli" } diff --git a/substrate/bin/utils/chain-spec-builder/Cargo.toml b/substrate/bin/utils/chain-spec-builder/Cargo.toml index 996372c8a0f..c126a76b763 100644 --- a/substrate/bin/utils/chain-spec-builder/Cargo.toml +++ b/substrate/bin/utils/chain-spec-builder/Cargo.toml @@ -23,7 +23,7 @@ name = "chain-spec-builder" crate-type = ["rlib"] [dependencies] -clap = { version = "4.5.1", features = ["derive"] } +clap = { version = "4.5.3", features = ["derive"] } log = { workspace = true, default-features = true } sc-chain-spec = { path = "../../../client/chain-spec" } serde_json = { workspace = true, default-features = true } diff --git a/substrate/bin/utils/subkey/Cargo.toml b/substrate/bin/utils/subkey/Cargo.toml index 93b1368ca75..8dc4bf254b2 100644 --- a/substrate/bin/utils/subkey/Cargo.toml +++ b/substrate/bin/utils/subkey/Cargo.toml @@ -20,5 +20,5 @@ path = "src/main.rs" name = "subkey" [dependencies] -clap = { version = "4.5.1", features = ["derive"] } +clap = { version = "4.5.3", features = ["derive"] } sc-cli = { path = "../../../client/cli" } diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index c70a0893c72..47b29555e66 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = "6.1" chrono = "0.4.31" -clap = { version = "4.5.1", features = ["derive", "string", "wrap_help"] } +clap = { version = "4.5.3", features = ["derive", "string", "wrap_help"] } fdlimit = "0.3.0" futures = "0.3.21" itertools = "0.10.3" diff --git a/substrate/client/storage-monitor/Cargo.toml b/substrate/client/storage-monitor/Cargo.toml index b2120b3efc4..5248ebdf9a6 100644 --- a/substrate/client/storage-monitor/Cargo.toml +++ b/substrate/client/storage-monitor/Cargo.toml @@ -12,7 +12,7 @@ homepage = "https://substrate.io" workspace = true [dependencies] -clap = { version = "4.5.1", features = ["derive", "string"] } +clap = { version = "4.5.3", features = ["derive", "string"] } log = { workspace = true, default-features = true } fs4 = "0.7.0" sp-core = { path = "../../primitives/core" } diff --git a/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml b/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml index 8a73dd38fa2..a27f0f7d4dd 100644 --- a/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml +++ b/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "4.5.1", features = ["derive"] } +clap = { version = "4.5.3", features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["small_rng", "std"] } diff --git a/substrate/frame/examples/single-block-migrations/Cargo.toml b/substrate/frame/examples/single-block-migrations/Cargo.toml index 5059b2433c7..613742a6787 100644 --- a/substrate/frame/examples/single-block-migrations/Cargo.toml +++ b/substrate/frame/examples/single-block-migrations/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] docify = { version = "0.2.3", default-features = false } -log = { version = "0.4.20", default-features = false } +log = { version = "0.4.21", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false } diff --git a/substrate/frame/migrations/Cargo.toml b/substrate/frame/migrations/Cargo.toml index 2914aa9ea97..40059fb9ec4 100644 --- a/substrate/frame/migrations/Cargo.toml +++ b/substrate/frame/migrations/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } docify = "0.1.14" impl-trait-for-tuples = "0.2.2" -log = "0.4.18" +log = "0.4.21" scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } frame-benchmarking = { default-features = false, optional = true, path = "../benchmarking" } diff --git a/substrate/primitives/npos-elections/fuzzer/Cargo.toml b/substrate/primitives/npos-elections/fuzzer/Cargo.toml index bcd908b9705..8e1dbaf2377 100644 --- a/substrate/primitives/npos-elections/fuzzer/Cargo.toml +++ b/substrate/primitives/npos-elections/fuzzer/Cargo.toml @@ -17,7 +17,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "4.5.1", features = ["derive"] } +clap = { version = "4.5.3", features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["small_rng", "std"] } sp-npos-elections = { path = ".." } diff --git a/substrate/scripts/ci/node-template-release/Cargo.toml b/substrate/scripts/ci/node-template-release/Cargo.toml index cc60d0a4510..4327b685743 100644 --- a/substrate/scripts/ci/node-template-release/Cargo.toml +++ b/substrate/scripts/ci/node-template-release/Cargo.toml @@ -14,7 +14,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "4.5.1", features = ["derive"] } +clap = { version = "4.5.3", features = ["derive"] } flate2 = "1.0" fs_extra = "1.3" glob = "0.3" diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index a25ab3a8f5b..b7fbb24b1a0 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = "6.1" chrono = "0.4" -clap = { version = "4.5.1", features = ["derive"] } +clap = { version = "4.5.3", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1" } comfy-table = { version = "7.1.0", default-features = false } handlebars = "5.1.0" diff --git a/substrate/utils/frame/frame-utilities-cli/Cargo.toml b/substrate/utils/frame/frame-utilities-cli/Cargo.toml index 919016b2d8f..3952c9fd219 100644 --- a/substrate/utils/frame/frame-utilities-cli/Cargo.toml +++ b/substrate/utils/frame/frame-utilities-cli/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" workspace = true [dependencies] -clap = { version = "4.5.1", features = ["derive"] } +clap = { version = "4.5.3", features = ["derive"] } frame-support = { path = "../../../frame/support" } frame-system = { path = "../../../frame/system" } sc-cli = { path = "../../../client/cli" } diff --git a/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml b/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml index 68d4733614c..37d96d7e12b 100644 --- a/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml +++ b/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml @@ -17,4 +17,4 @@ kitchensink-runtime = { path = "../../../../bin/node/runtime" } generate-bags = { path = ".." } # third-party -clap = { version = "4.5.1", features = ["derive"] } +clap = { version = "4.5.3", features = ["derive"] } diff --git a/substrate/utils/frame/try-runtime/cli/Cargo.toml b/substrate/utils/frame/try-runtime/cli/Cargo.toml index d123fc5f62d..3ff57745a2d 100644 --- a/substrate/utils/frame/try-runtime/cli/Cargo.toml +++ b/substrate/utils/frame/try-runtime/cli/Cargo.toml @@ -38,7 +38,7 @@ frame-try-runtime = { path = "../../../../frame/try-runtime", optional = true } substrate-rpc-client = { path = "../../rpc/client" } async-trait = "0.1.74" -clap = { version = "4.5.1", features = ["derive"] } +clap = { version = "4.5.3", features = ["derive"] } hex = { version = "0.4.3", default-features = false } log = { workspace = true, default-features = true } parity-scale-codec = "3.6.1" diff --git a/templates/minimal/node/Cargo.toml b/templates/minimal/node/Cargo.toml index 410cfc9f6c3..65aa1e20752 100644 --- a/templates/minimal/node/Cargo.toml +++ b/templates/minimal/node/Cargo.toml @@ -17,7 +17,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "4.5.1", features = ["derive"] } +clap = { version = "4.5.3", features = ["derive"] } futures = { version = "0.3.21", features = ["thread-pool"] } futures-timer = "3.0.1" jsonrpsee = { version = "0.22", features = ["server"] } diff --git a/templates/parachain/node/Cargo.toml b/templates/parachain/node/Cargo.toml index b4f3a504a4d..63267acdbca 100644 --- a/templates/parachain/node/Cargo.toml +++ b/templates/parachain/node/Cargo.toml @@ -17,7 +17,7 @@ workspace = true # name = "parachain-template-node" [dependencies] -clap = { version = "4.5.1", features = ["derive"] } +clap = { version = "4.5.3", features = ["derive"] } log = { workspace = true, default-features = true } codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { features = ["derive"], workspace = true, default-features = true } diff --git a/templates/solochain/node/Cargo.toml b/templates/solochain/node/Cargo.toml index 48bb511bfd1..a0bb5c27ed3 100644 --- a/templates/solochain/node/Cargo.toml +++ b/templates/solochain/node/Cargo.toml @@ -18,7 +18,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "4.5.1", features = ["derive"] } +clap = { version = "4.5.3", features = ["derive"] } futures = { version = "0.3.21", features = ["thread-pool"] } serde_json = { workspace = true, default-features = true } jsonrpsee = { version = "0.22", features = ["server"] } -- GitLab From 6b1179f13b4815685769c9f523720ec9ed0e2ff4 Mon Sep 17 00:00:00 2001 From: jokess123 <163112061+jokess123@users.noreply.github.com> Date: Mon, 18 Mar 2024 06:50:54 +0800 Subject: [PATCH 049/187] Fix typo (#3691) --- bridges/modules/grandpa/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridges/modules/grandpa/README.md b/bridges/modules/grandpa/README.md index 43ee5c316d1..992bd2cc472 100644 --- a/bridges/modules/grandpa/README.md +++ b/bridges/modules/grandpa/README.md @@ -27,7 +27,7 @@ for provided header. There are two main things in GRANDPA that help building light clients: - there's no need to import all headers of the bridged chain. Light client may import finalized headers or just - some of finalized headders that it consider useful. While the validators set stays the same, the client may + some of finalized headers that it consider useful. While the validators set stays the same, the client may import any header that is finalized by this set; - when validators set changes, the GRANDPA gadget adds next set to the header. So light client doesn't need to -- GitLab From 1b5f4243d159fbb7cf7067241aca8a37f3dbf7ed Mon Sep 17 00:00:00 2001 From: Squirrel Date: Mon, 18 Mar 2024 05:29:35 +0000 Subject: [PATCH 050/187] sp-std removal from substrate/primitives (#3274) This PR removes sp-std crate from substrate/primitives sub-directories. For now crates that have `pub use` of sp-std or export macros that would necessitate users of the macros to `extern crate alloc` have been excluded from this PR. There should be no breaking changes in this PR. --------- Co-authored-by: Koute --- Cargo.lock | 31 ------------------- substrate/primitives/arithmetic/Cargo.toml | 2 -- .../primitives/arithmetic/src/biguint.rs | 11 ++++--- .../primitives/arithmetic/src/fixed_point.rs | 19 ++++++------ substrate/primitives/arithmetic/src/lib.rs | 7 +++-- .../primitives/arithmetic/src/per_things.rs | 17 +++++----- .../primitives/arithmetic/src/rational.rs | 10 +++--- .../primitives/authority-discovery/Cargo.toml | 2 -- .../primitives/authority-discovery/src/lib.rs | 4 ++- substrate/primitives/block-builder/Cargo.toml | 3 +- substrate/primitives/block-builder/src/lib.rs | 4 ++- .../primitives/consensus/aura/Cargo.toml | 2 -- .../primitives/consensus/aura/src/lib.rs | 4 ++- .../primitives/consensus/babe/Cargo.toml | 2 -- .../primitives/consensus/babe/src/digests.rs | 3 +- .../primitives/consensus/babe/src/lib.rs | 5 ++- .../primitives/consensus/beefy/Cargo.toml | 2 -- .../consensus/beefy/src/commitment.rs | 11 ++++--- .../primitives/consensus/beefy/src/lib.rs | 4 ++- .../primitives/consensus/beefy/src/mmr.rs | 6 ++-- .../primitives/consensus/beefy/src/payload.rs | 2 +- .../primitives/consensus/beefy/src/witness.rs | 3 +- .../primitives/consensus/grandpa/Cargo.toml | 2 -- .../primitives/consensus/grandpa/src/lib.rs | 4 ++- substrate/primitives/consensus/pow/Cargo.toml | 2 -- substrate/primitives/consensus/pow/src/lib.rs | 5 ++- .../primitives/consensus/sassafras/Cargo.toml | 2 -- .../consensus/sassafras/src/digests.rs | 3 +- .../primitives/consensus/sassafras/src/lib.rs | 4 ++- .../primitives/consensus/sassafras/src/vrf.rs | 3 +- .../primitives/consensus/slots/Cargo.toml | 2 -- .../primitives/crypto/ec-utils/Cargo.toml | 4 +-- .../crypto/ec-utils/src/bls12_377.rs | 2 +- .../crypto/ec-utils/src/bls12_381.rs | 2 +- .../primitives/crypto/ec-utils/src/bw6_761.rs | 2 +- .../crypto/ec-utils/src/ed_on_bls12_377.rs | 2 +- .../src/ed_on_bls12_381_bandersnatch.rs | 2 +- .../primitives/crypto/ec-utils/src/lib.rs | 2 ++ .../primitives/crypto/ec-utils/src/utils.rs | 2 +- substrate/primitives/externalities/Cargo.toml | 3 +- .../externalities/src/extensions.rs | 6 ++-- substrate/primitives/externalities/src/lib.rs | 9 +++--- .../primitives/genesis-builder/Cargo.toml | 3 +- .../primitives/genesis-builder/src/lib.rs | 6 ++-- substrate/primitives/inherents/Cargo.toml | 2 -- substrate/primitives/inherents/src/lib.rs | 4 ++- .../merkle-mountain-range/Cargo.toml | 2 -- .../merkle-mountain-range/src/lib.rs | 12 ++++--- .../merkle-mountain-range/src/utils.rs | 6 ++-- substrate/primitives/metadata-ir/Cargo.toml | 3 +- substrate/primitives/metadata-ir/src/lib.rs | 6 ++-- substrate/primitives/mixnet/Cargo.toml | 2 -- substrate/primitives/mixnet/src/lib.rs | 2 ++ .../primitives/mixnet/src/runtime_api.rs | 2 +- substrate/primitives/mixnet/src/types.rs | 6 ++-- .../primitives/npos-elections/Cargo.toml | 2 -- .../npos-elections/src/assignments.rs | 2 +- .../npos-elections/src/balancing.rs | 2 +- .../primitives/npos-elections/src/helpers.rs | 2 +- .../primitives/npos-elections/src/lib.rs | 17 +++++----- .../primitives/npos-elections/src/mock.rs | 10 +++--- .../primitives/npos-elections/src/node.rs | 7 +++-- .../primitives/npos-elections/src/phragmen.rs | 2 +- .../primitives/npos-elections/src/phragmms.rs | 4 +-- .../primitives/npos-elections/src/pjr.rs | 2 +- .../primitives/npos-elections/src/reduce.rs | 7 +++-- .../primitives/npos-elections/src/traits.rs | 2 +- substrate/primitives/session/Cargo.toml | 2 -- substrate/primitives/session/src/lib.rs | 4 ++- .../primitives/session/src/runtime_api.rs | 2 +- substrate/primitives/staking/Cargo.toml | 2 -- substrate/primitives/staking/src/lib.rs | 7 +++-- substrate/primitives/staking/src/offence.rs | 2 +- substrate/primitives/state-machine/Cargo.toml | 2 -- .../primitives/state-machine/src/backend.rs | 4 +-- substrate/primitives/state-machine/src/ext.rs | 8 ++--- substrate/primitives/state-machine/src/lib.rs | 6 ++-- .../src/overlayed_changes/changeset.rs | 14 ++++----- .../src/overlayed_changes/mod.rs | 16 +++++----- .../src/overlayed_changes/offchain.rs | 4 +-- .../state-machine/src/trie_backend.rs | 6 ++-- .../state-machine/src/trie_backend_essence.rs | 9 +++--- .../primitives/statement-store/Cargo.toml | 2 -- .../primitives/statement-store/src/lib.rs | 4 ++- .../statement-store/src/runtime_api.rs | 2 +- substrate/primitives/storage/Cargo.toml | 2 -- substrate/primitives/storage/src/lib.rs | 15 +++++---- .../primitives/test-primitives/Cargo.toml | 2 -- .../primitives/test-primitives/src/lib.rs | 4 ++- substrate/primitives/timestamp/Cargo.toml | 2 -- substrate/primitives/tracing/Cargo.toml | 2 -- substrate/primitives/tracing/src/lib.rs | 2 ++ substrate/primitives/tracing/src/types.rs | 6 ++-- .../primitives/transaction-pool/src/lib.rs | 2 ++ .../transaction-storage-proof/Cargo.toml | 2 -- .../transaction-storage-proof/src/lib.rs | 5 ++- substrate/primitives/trie/Cargo.toml | 2 -- substrate/primitives/trie/src/error.rs | 2 +- substrate/primitives/trie/src/lib.rs | 7 +++-- substrate/primitives/trie/src/node_codec.rs | 5 +-- .../primitives/trie/src/storage_proof.rs | 8 ++--- substrate/primitives/trie/src/trie_codec.rs | 2 +- substrate/primitives/trie/src/trie_stream.rs | 2 +- .../primitives/wasm-interface/Cargo.toml | 3 +- .../primitives/wasm-interface/src/lib.rs | 7 +++-- substrate/primitives/weights/Cargo.toml | 2 -- substrate/test-utils/runtime/Cargo.toml | 2 -- substrate/test-utils/runtime/src/extrinsic.rs | 1 - substrate/test-utils/runtime/src/lib.rs | 13 +++++--- .../runtime/src/substrate_test_pallet.rs | 4 +-- 110 files changed, 254 insertions(+), 278 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f3535d509ff..d641f554431 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18402,7 +18402,6 @@ dependencies = [ "scale-info", "serde", "sp-crypto-hashing", - "sp-std 14.0.0", "static_assertions", ] @@ -18444,7 +18443,6 @@ dependencies = [ "sp-api", "sp-application-crypto", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -18454,7 +18452,6 @@ dependencies = [ "sp-api", "sp-inherents", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -18501,7 +18498,6 @@ dependencies = [ "sp-consensus-slots", "sp-inherents", "sp-runtime", - "sp-std 14.0.0", "sp-timestamp", ] @@ -18519,7 +18515,6 @@ dependencies = [ "sp-core", "sp-inherents", "sp-runtime", - "sp-std 14.0.0", "sp-timestamp", ] @@ -18540,7 +18535,6 @@ dependencies = [ "sp-keystore", "sp-mmr-primitives", "sp-runtime", - "sp-std 14.0.0", "strum 0.24.1", "w3f-bls", ] @@ -18559,7 +18553,6 @@ dependencies = [ "sp-core", "sp-keystore", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -18570,7 +18563,6 @@ dependencies = [ "sp-api", "sp-core", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -18585,7 +18577,6 @@ dependencies = [ "sp-consensus-slots", "sp-core", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -18595,7 +18586,6 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-std 14.0.0", "sp-timestamp", ] @@ -18711,7 +18701,6 @@ dependencies = [ "ark-ed-on-bls12-381-bandersnatch-ext", "ark-scale 0.0.12", "sp-runtime-interface 24.0.0", - "sp-std 14.0.0", ] [[package]] @@ -18781,7 +18770,6 @@ version = "0.25.0" dependencies = [ "environmental", "parity-scale-codec", - "sp-std 14.0.0", "sp-storage 19.0.0", ] @@ -18792,7 +18780,6 @@ dependencies = [ "serde_json", "sp-api", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -18805,7 +18792,6 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-runtime", - "sp-std 14.0.0", "thiserror", ] @@ -18870,7 +18856,6 @@ dependencies = [ "frame-metadata", "parity-scale-codec", "scale-info", - "sp-std 14.0.0", ] [[package]] @@ -18881,7 +18866,6 @@ dependencies = [ "scale-info", "sp-api", "sp-application-crypto", - "sp-std 14.0.0", ] [[package]] @@ -18898,7 +18882,6 @@ dependencies = [ "sp-core", "sp-debug-derive 14.0.0", "sp-runtime", - "sp-std 14.0.0", "thiserror", ] @@ -18913,7 +18896,6 @@ dependencies = [ "sp-arithmetic", "sp-core", "sp-runtime", - "sp-std 14.0.0", "substrate-test-utils", ] @@ -19100,7 +19082,6 @@ dependencies = [ "sp-keystore", "sp-runtime", "sp-staking", - "sp-std 14.0.0", ] [[package]] @@ -19113,7 +19094,6 @@ dependencies = [ "serde", "sp-core", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -19133,7 +19113,6 @@ dependencies = [ "sp-externalities 0.25.0", "sp-panic-handler", "sp-runtime", - "sp-std 14.0.0", "sp-trie", "thiserror", "tracing", @@ -19159,7 +19138,6 @@ dependencies = [ "sp-externalities 0.25.0", "sp-runtime", "sp-runtime-interface 24.0.0", - "sp-std 14.0.0", "thiserror", "x25519-dalek 2.0.0", ] @@ -19195,7 +19173,6 @@ dependencies = [ "ref-cast", "serde", "sp-debug-derive 14.0.0", - "sp-std 14.0.0", ] [[package]] @@ -19208,7 +19185,6 @@ dependencies = [ "sp-application-crypto", "sp-core", "sp-runtime", - "sp-std 14.0.0", ] [[package]] @@ -19219,7 +19195,6 @@ dependencies = [ "parity-scale-codec", "sp-inherents", "sp-runtime", - "sp-std 14.0.0", "thiserror", ] @@ -19240,7 +19215,6 @@ name = "sp-tracing" version = "16.0.0" dependencies = [ "parity-scale-codec", - "sp-std 14.0.0", "tracing", "tracing-core", "tracing-subscriber 0.2.25", @@ -19264,7 +19238,6 @@ dependencies = [ "sp-core", "sp-inherents", "sp-runtime", - "sp-std 14.0.0", "sp-trie", ] @@ -19287,7 +19260,6 @@ dependencies = [ "sp-core", "sp-externalities 0.25.0", "sp-runtime", - "sp-std 14.0.0", "thiserror", "tracing", "trie-bench", @@ -19344,7 +19316,6 @@ dependencies = [ "impl-trait-for-tuples", "log", "parity-scale-codec", - "sp-std 14.0.0", "wasmtime", ] @@ -19360,7 +19331,6 @@ dependencies = [ "smallvec", "sp-arithmetic", "sp-debug-derive 14.0.0", - "sp-std 14.0.0", ] [[package]] @@ -19971,7 +19941,6 @@ dependencies = [ "sp-runtime", "sp-session", "sp-state-machine", - "sp-std 14.0.0", "sp-tracing 16.0.0", "sp-transaction-pool", "sp-trie", diff --git a/substrate/primitives/arithmetic/Cargo.toml b/substrate/primitives/arithmetic/Cargo.toml index 301821ad689..29c406b10b7 100644 --- a/substrate/primitives/arithmetic/Cargo.toml +++ b/substrate/primitives/arithmetic/Cargo.toml @@ -26,7 +26,6 @@ num-traits = { version = "0.2.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], optional = true, workspace = true } static_assertions = "1.1.0" -sp-std = { path = "../std", default-features = false } [dev-dependencies] criterion = "0.4.0" @@ -42,7 +41,6 @@ std = [ "scale-info/std", "serde/std", "sp-crypto-hashing/std", - "sp-std/std", ] # Serde support without relying on std features. serde = ["dep:serde", "scale-info/serde"] diff --git a/substrate/primitives/arithmetic/src/biguint.rs b/substrate/primitives/arithmetic/src/biguint.rs index d92b08c8eca..164ec67a603 100644 --- a/substrate/primitives/arithmetic/src/biguint.rs +++ b/substrate/primitives/arithmetic/src/biguint.rs @@ -17,9 +17,10 @@ //! Infinite precision unsigned integer for substrate runtime. +use alloc::{vec, vec::Vec}; use codec::{Decode, Encode}; +use core::{cell::RefCell, cmp::Ordering, ops}; use num_traits::{One, Zero}; -use sp_std::{cell::RefCell, cmp::Ordering, ops, prelude::*, vec}; // A sensible value for this would be half of the dword size of the host machine. Since the // runtime is compiled to 32bit webassembly, using 32 and 64 for single and double respectively @@ -35,7 +36,7 @@ const SHIFT: usize = 32; const B: Double = Single::max_value() as Double + 1; static_assertions::const_assert!( - sp_std::mem::size_of::() - sp_std::mem::size_of::() == SHIFT / 8 + core::mem::size_of::() - core::mem::size_of::() == SHIFT / 8 ); /// Splits a [`Double`] limb number into a tuple of two [`Single`] limb numbers. @@ -438,9 +439,9 @@ impl BigUint { } } -impl sp_std::fmt::Debug for BigUint { +impl core::fmt::Debug for BigUint { #[cfg(feature = "std")] - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!( f, "BigUint {{ {:?} ({:?})}}", @@ -450,7 +451,7 @@ impl sp_std::fmt::Debug for BigUint { } #[cfg(not(feature = "std"))] - fn fmt(&self, _: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + fn fmt(&self, _: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { Ok(()) } } diff --git a/substrate/primitives/arithmetic/src/fixed_point.rs b/substrate/primitives/arithmetic/src/fixed_point.rs index ce14d2957b5..46c09df2186 100644 --- a/substrate/primitives/arithmetic/src/fixed_point.rs +++ b/substrate/primitives/arithmetic/src/fixed_point.rs @@ -26,17 +26,16 @@ use crate::{ PerThing, Perbill, Rounding, SignedRounding, }; use codec::{CompactAs, Decode, Encode}; -use sp_std::{ +use core::{ fmt::Debug, ops::{self, Add, Div, Mul, Sub}, - prelude::*, }; #[cfg(feature = "serde")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; #[cfg(all(not(feature = "std"), feature = "serde"))] -use sp_std::alloc::string::{String, ToString}; +use alloc::string::{String, ToString}; /// Integer types that can be used to interact with `FixedPointNumber` implementations. pub trait FixedPointOperand: @@ -899,9 +898,9 @@ macro_rules! implement_fixed { } } - impl sp_std::fmt::Debug for $name { + impl ::core::fmt::Debug for $name { #[cfg(feature = "std")] - fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { let integral = { let int = self.0 / Self::accuracy(); let signum_for_zero = if int == 0 && self.is_negative() { "-" } else { "" }; @@ -917,7 +916,7 @@ macro_rules! implement_fixed { } #[cfg(not(feature = "std"))] - fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + fn fmt(&self, _: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { Ok(()) } } @@ -933,13 +932,13 @@ macro_rules! implement_fixed { } } - impl sp_std::fmt::Display for $name { - fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + impl ::core::fmt::Display for $name { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}", self.0) } } - impl sp_std::str::FromStr for $name { + impl ::core::str::FromStr for $name { type Err = &'static str; fn from_str(s: &str) -> Result { @@ -969,7 +968,7 @@ macro_rules! implement_fixed { where D: Deserializer<'de>, { - use sp_std::str::FromStr; + use ::core::str::FromStr; let s = String::deserialize(deserializer)?; $name::from_str(&s).map_err(de::Error::custom) } diff --git a/substrate/primitives/arithmetic/src/lib.rs b/substrate/primitives/arithmetic/src/lib.rs index 900f0b75c3b..33992e15423 100644 --- a/substrate/primitives/arithmetic/src/lib.rs +++ b/substrate/primitives/arithmetic/src/lib.rs @@ -19,6 +19,8 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + /// Copied from `sp-runtime` and documented there. #[macro_export] macro_rules! assert_eq_error_rate { @@ -49,7 +51,8 @@ pub use per_things::{ }; pub use rational::{MultiplyRational, Rational128, RationalInfinite}; -use sp_std::{cmp::Ordering, fmt::Debug, prelude::*}; +use alloc::vec::Vec; +use core::{cmp::Ordering, fmt::Debug}; use traits::{BaseArithmetic, One, SaturatedConversion, Unsigned, Zero}; use codec::{Decode, Encode, MaxEncodedLen}; @@ -429,7 +432,7 @@ mod normalize_tests { mod threshold_compare_tests { use super::*; use crate::traits::Saturating; - use sp_std::cmp::Ordering; + use core::cmp::Ordering; #[test] fn epsilon_ord_works() { diff --git a/substrate/primitives/arithmetic/src/per_things.rs b/substrate/primitives/arithmetic/src/per_things.rs index fe88b72e24c..057bfd7bf88 100644 --- a/substrate/primitives/arithmetic/src/per_things.rs +++ b/substrate/primitives/arithmetic/src/per_things.rs @@ -23,12 +23,11 @@ use crate::traits::{ Saturating, UniqueSaturatedInto, Unsigned, Zero, }; use codec::{CompactAs, Encode}; -use num_traits::{Pow, SaturatingAdd, SaturatingSub}; -use sp_std::{ +use core::{ fmt, ops, ops::{Add, Sub}, - prelude::*, }; +use num_traits::{Pow, SaturatingAdd, SaturatingSub}; /// Get the inner type of a `PerThing`. pub type InnerOf

=

::Inner; @@ -414,7 +413,7 @@ pub trait PerThing: } /// The rounding method to use for unsigned quantities. -#[derive(Copy, Clone, sp_std::fmt::Debug)] +#[derive(Copy, Clone, core::fmt::Debug)] pub enum Rounding { // Towards infinity. Up, @@ -427,7 +426,7 @@ pub enum Rounding { } /// The rounding method to use. -#[derive(Copy, Clone, sp_std::fmt::Debug)] +#[derive(Copy, Clone, core::fmt::Debug)] pub enum SignedRounding { // Towards positive infinity. High, @@ -580,8 +579,8 @@ macro_rules! implement_per_thing { } #[cfg(feature = "std")] - impl sp_std::fmt::Debug for $name { - fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + impl core::fmt::Debug for $name { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { if $max == <$type>::max_value() { // Not a power of ten: show as N/D and approx % let pc = (self.0 as f64) / (self.0 as f64) * 100f64; @@ -606,8 +605,8 @@ macro_rules! implement_per_thing { } #[cfg(not(feature = "std"))] - impl sp_std::fmt::Debug for $name { - fn fmt(&self, fmt: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + impl core::fmt::Debug for $name { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { if $max == <$type>::max_value() { // Not a power of ten: show as N/D and approx % write!(fmt, "{}/{}", self.0, $max) diff --git a/substrate/primitives/arithmetic/src/rational.rs b/substrate/primitives/arithmetic/src/rational.rs index ebd89c615a3..2ec83e6fd86 100644 --- a/substrate/primitives/arithmetic/src/rational.rs +++ b/substrate/primitives/arithmetic/src/rational.rs @@ -16,8 +16,8 @@ // limitations under the License. use crate::{biguint::BigUint, helpers_128bit, Rounding}; +use core::cmp::Ordering; use num_traits::{Bounded, One, Zero}; -use sp_std::{cmp::Ordering, prelude::*}; /// A wrapper for any rational number with infinitely large numerator and denominator. /// @@ -92,15 +92,15 @@ impl From for RationalInfinite { pub struct Rational128(u128, u128); #[cfg(feature = "std")] -impl sp_std::fmt::Debug for Rational128 { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { +impl core::fmt::Debug for Rational128 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "Rational128({} / {} ≈ {:.8})", self.0, self.1, self.0 as f64 / self.1 as f64) } } #[cfg(not(feature = "std"))] -impl sp_std::fmt::Debug for Rational128 { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { +impl core::fmt::Debug for Rational128 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "Rational128({} / {})", self.0, self.1) } } diff --git a/substrate/primitives/authority-discovery/Cargo.toml b/substrate/primitives/authority-discovery/Cargo.toml index 70f00897cdd..8ee8bb94ed9 100644 --- a/substrate/primitives/authority-discovery/Cargo.toml +++ b/substrate/primitives/authority-discovery/Cargo.toml @@ -21,7 +21,6 @@ scale-info = { version = "2.10.0", default-features = false, features = ["derive sp-api = { path = "../api", default-features = false } sp-application-crypto = { path = "../application-crypto", default-features = false } sp-runtime = { path = "../runtime", default-features = false } -sp-std = { path = "../std", default-features = false } [features] default = ["std"] @@ -31,7 +30,6 @@ std = [ "sp-api/std", "sp-application-crypto/std", "sp-runtime/std", - "sp-std/std", ] serde = [ "scale-info/serde", diff --git a/substrate/primitives/authority-discovery/src/lib.rs b/substrate/primitives/authority-discovery/src/lib.rs index 3b25e39d404..5aba76a3abb 100644 --- a/substrate/primitives/authority-discovery/src/lib.rs +++ b/substrate/primitives/authority-discovery/src/lib.rs @@ -19,7 +19,9 @@ #![cfg_attr(not(feature = "std"), no_std)] -use sp_std::vec::Vec; +extern crate alloc; + +use alloc::vec::Vec; mod app { use sp_application_crypto::{app_crypto, key_types::AUTHORITY_DISCOVERY, sr25519}; diff --git a/substrate/primitives/block-builder/Cargo.toml b/substrate/primitives/block-builder/Cargo.toml index c1317facd7f..cc4b1085154 100644 --- a/substrate/primitives/block-builder/Cargo.toml +++ b/substrate/primitives/block-builder/Cargo.toml @@ -19,8 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-api = { path = "../api", default-features = false } sp-inherents = { path = "../inherents", default-features = false } sp-runtime = { path = "../runtime", default-features = false } -sp-std = { path = "../std", default-features = false } [features] default = ["std"] -std = ["sp-api/std", "sp-inherents/std", "sp-runtime/std", "sp-std/std"] +std = ["sp-api/std", "sp-inherents/std", "sp-runtime/std"] diff --git a/substrate/primitives/block-builder/src/lib.rs b/substrate/primitives/block-builder/src/lib.rs index 29e04857f46..9d03aa4d7a0 100644 --- a/substrate/primitives/block-builder/src/lib.rs +++ b/substrate/primitives/block-builder/src/lib.rs @@ -19,6 +19,8 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + use sp_inherents::{CheckInherentsResult, InherentData}; use sp_runtime::{traits::Block as BlockT, ApplyExtrinsicResult}; @@ -44,7 +46,7 @@ sp_api::decl_runtime_apis! { /// Generate inherent extrinsics. The inherent data will vary from chain to chain. fn inherent_extrinsics( inherent: InherentData, - ) -> sp_std::vec::Vec<::Extrinsic>; + ) -> alloc::vec::Vec<::Extrinsic>; /// Check that the inherents are valid. The inherent data will vary from chain to chain. fn check_inherents(block: Block, data: InherentData) -> CheckInherentsResult; diff --git a/substrate/primitives/consensus/aura/Cargo.toml b/substrate/primitives/consensus/aura/Cargo.toml index 52f6bc22ba4..0cedc59ea8f 100644 --- a/substrate/primitives/consensus/aura/Cargo.toml +++ b/substrate/primitives/consensus/aura/Cargo.toml @@ -24,7 +24,6 @@ sp-application-crypto = { path = "../../application-crypto", default-features = sp-consensus-slots = { path = "../slots", default-features = false } sp-inherents = { path = "../../inherents", default-features = false } sp-runtime = { path = "../../runtime", default-features = false } -sp-std = { path = "../../std", default-features = false } sp-timestamp = { path = "../../timestamp", default-features = false } [features] @@ -38,7 +37,6 @@ std = [ "sp-consensus-slots/std", "sp-inherents/std", "sp-runtime/std", - "sp-std/std", "sp-timestamp/std", ] diff --git a/substrate/primitives/consensus/aura/src/lib.rs b/substrate/primitives/consensus/aura/src/lib.rs index 78409e84e93..5173d5516cf 100644 --- a/substrate/primitives/consensus/aura/src/lib.rs +++ b/substrate/primitives/consensus/aura/src/lib.rs @@ -19,9 +19,11 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + +use alloc::vec::Vec; use codec::{Codec, Decode, Encode}; use sp_runtime::ConsensusEngineId; -use sp_std::vec::Vec; pub mod digests; pub mod inherents; diff --git a/substrate/primitives/consensus/babe/Cargo.toml b/substrate/primitives/consensus/babe/Cargo.toml index 8b3006f79a7..724b9fd3e28 100644 --- a/substrate/primitives/consensus/babe/Cargo.toml +++ b/substrate/primitives/consensus/babe/Cargo.toml @@ -26,7 +26,6 @@ sp-consensus-slots = { path = "../slots", default-features = false } sp-core = { path = "../../core", default-features = false } sp-inherents = { path = "../../inherents", default-features = false } sp-runtime = { path = "../../runtime", default-features = false } -sp-std = { path = "../../std", default-features = false } sp-timestamp = { path = "../../timestamp", optional = true } [features] @@ -42,7 +41,6 @@ std = [ "sp-core/std", "sp-inherents/std", "sp-runtime/std", - "sp-std/std", "sp-timestamp/std", ] diff --git a/substrate/primitives/consensus/babe/src/digests.rs b/substrate/primitives/consensus/babe/src/digests.rs index afc967e3af3..e7af8c5763a 100644 --- a/substrate/primitives/consensus/babe/src/digests.rs +++ b/substrate/primitives/consensus/babe/src/digests.rs @@ -22,9 +22,10 @@ use super::{ BabeEpochConfiguration, Randomness, Slot, BABE_ENGINE_ID, }; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; use sp_core::sr25519::vrf::VrfSignature; use sp_runtime::{DigestItem, RuntimeDebug}; -use sp_std::vec::Vec; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; diff --git a/substrate/primitives/consensus/babe/src/lib.rs b/substrate/primitives/consensus/babe/src/lib.rs index ff0b4568226..6eb75b270a0 100644 --- a/substrate/primitives/consensus/babe/src/lib.rs +++ b/substrate/primitives/consensus/babe/src/lib.rs @@ -20,15 +20,18 @@ #![forbid(unsafe_code, missing_docs, unused_variables, unused_imports)] #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + pub mod digests; pub mod inherents; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use sp_runtime::{traits::Header, ConsensusEngineId, RuntimeDebug}; -use sp_std::vec::Vec; use crate::digests::{NextConfigDescriptor, NextEpochDescriptor}; diff --git a/substrate/primitives/consensus/beefy/Cargo.toml b/substrate/primitives/consensus/beefy/Cargo.toml index 8ab817d52ef..fbcc6e0c104 100644 --- a/substrate/primitives/consensus/beefy/Cargo.toml +++ b/substrate/primitives/consensus/beefy/Cargo.toml @@ -26,7 +26,6 @@ sp-io = { path = "../../io", default-features = false } sp-mmr-primitives = { path = "../../merkle-mountain-range", default-features = false } sp-runtime = { path = "../../runtime", default-features = false } sp-keystore = { path = "../../keystore", default-features = false } -sp-std = { path = "../../std", default-features = false } strum = { version = "0.24.1", features = ["derive"], default-features = false } lazy_static = { version = "1.4.0", optional = true } @@ -49,7 +48,6 @@ std = [ "sp-keystore/std", "sp-mmr-primitives/std", "sp-runtime/std", - "sp-std/std", "strum/std", ] diff --git a/substrate/primitives/consensus/beefy/src/commitment.rs b/substrate/primitives/consensus/beefy/src/commitment.rs index 335c6b604f0..4fd9e1b0a6e 100644 --- a/substrate/primitives/consensus/beefy/src/commitment.rs +++ b/substrate/primitives/consensus/beefy/src/commitment.rs @@ -15,9 +15,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +use alloc::{vec, vec::Vec}; use codec::{Decode, Encode, Error, Input}; +use core::cmp; use scale_info::TypeInfo; -use sp_std::{cmp, prelude::*}; use crate::{Payload, ValidatorSetId}; @@ -97,10 +98,10 @@ pub struct SignedCommitment { pub signatures: Vec>, } -impl sp_std::fmt::Display +impl core::fmt::Display for SignedCommitment { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { let signatures_count = self.signatures.iter().filter(|s| s.is_some()).count(); write!( f, @@ -254,8 +255,8 @@ pub enum VersionedFinalityProof { V1(SignedCommitment), } -impl sp_std::fmt::Display for VersionedFinalityProof { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { +impl core::fmt::Display for VersionedFinalityProof { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { VersionedFinalityProof::V1(sc) => write!(f, "VersionedFinalityProof::V1({})", sc), } diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index 1c3801e3a50..b3f62ead736 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -31,6 +31,8 @@ //! it will use a different set of keys. For Polkadot use case we plan to use `secp256k1` for BEEFY, //! while GRANDPA uses `ed25519`. +extern crate alloc; + mod commitment; mod payload; @@ -44,13 +46,13 @@ pub mod test_utils; pub use commitment::{Commitment, SignedCommitment, VersionedFinalityProof}; pub use payload::{known_payloads, BeefyPayloadId, Payload, PayloadProvider}; +use alloc::vec::Vec; use codec::{Codec, Decode, Encode}; use core::fmt::{Debug, Display}; use scale_info::TypeInfo; use sp_application_crypto::{AppCrypto, AppPublic, ByteArray, RuntimeAppPublic}; use sp_core::H256; use sp_runtime::traits::{Hash, Keccak256, NumberFor}; -use sp_std::prelude::*; /// Key type for BEEFY module. pub const KEY_TYPE: sp_core::crypto::KeyTypeId = sp_application_crypto::key_types::BEEFY; diff --git a/substrate/primitives/consensus/beefy/src/mmr.rs b/substrate/primitives/consensus/beefy/src/mmr.rs index 1b9a45f8687..74851ece7ac 100644 --- a/substrate/primitives/consensus/beefy/src/mmr.rs +++ b/substrate/primitives/consensus/beefy/src/mmr.rs @@ -26,7 +26,8 @@ //! but we imagine they will be useful for other chains that either want to bridge with Polkadot //! or are completely standalone, but heavily inspired by Polkadot. -use crate::{ecdsa_crypto::AuthorityId, ConsensusLog, MmrRootHash, Vec, BEEFY_ENGINE_ID}; +use crate::{ecdsa_crypto::AuthorityId, ConsensusLog, MmrRootHash, BEEFY_ENGINE_ID}; +use alloc::vec::Vec; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_runtime::{ @@ -150,10 +151,11 @@ pub use mmr_root_provider::MmrRootProvider; mod mmr_root_provider { use super::*; use crate::{known_payloads, payload::PayloadProvider, Payload}; + use alloc::sync::Arc; + use core::marker::PhantomData; use sp_api::ProvideRuntimeApi; use sp_mmr_primitives::MmrApi; use sp_runtime::traits::NumberFor; - use sp_std::{marker::PhantomData, sync::Arc}; /// A [`crate::Payload`] provider where payload is Merkle Mountain Range root hash. /// diff --git a/substrate/primitives/consensus/beefy/src/payload.rs b/substrate/primitives/consensus/beefy/src/payload.rs index d520de445c9..dff017b49e0 100644 --- a/substrate/primitives/consensus/beefy/src/payload.rs +++ b/substrate/primitives/consensus/beefy/src/payload.rs @@ -15,10 +15,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +use alloc::{vec, vec::Vec}; use codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_runtime::traits::Block; -use sp_std::prelude::*; /// Id of different payloads in the [`crate::Commitment`] data. pub type BeefyPayloadId = [u8; 2]; diff --git a/substrate/primitives/consensus/beefy/src/witness.rs b/substrate/primitives/consensus/beefy/src/witness.rs index b633453340b..cfffc94254a 100644 --- a/substrate/primitives/consensus/beefy/src/witness.rs +++ b/substrate/primitives/consensus/beefy/src/witness.rs @@ -23,9 +23,8 @@ //! verification. This allows lowering the data and computation cost of verifying the //! signed commitment. -use sp_std::prelude::*; - use crate::commitment::{Commitment, SignedCommitment}; +use alloc::vec::Vec; /// A light form of [SignedCommitment]. /// diff --git a/substrate/primitives/consensus/grandpa/Cargo.toml b/substrate/primitives/consensus/grandpa/Cargo.toml index b06208a4308..1f2da55c5a1 100644 --- a/substrate/primitives/consensus/grandpa/Cargo.toml +++ b/substrate/primitives/consensus/grandpa/Cargo.toml @@ -27,7 +27,6 @@ sp-application-crypto = { path = "../../application-crypto", default-features = sp-core = { path = "../../core", default-features = false } sp-keystore = { path = "../../keystore", default-features = false, optional = true } sp-runtime = { path = "../../runtime", default-features = false } -sp-std = { path = "../../std", default-features = false } [features] default = ["std"] @@ -42,7 +41,6 @@ std = [ "sp-core/std", "sp-keystore/std", "sp-runtime/std", - "sp-std/std", ] # Serde support without relying on std features. diff --git a/substrate/primitives/consensus/grandpa/src/lib.rs b/substrate/primitives/consensus/grandpa/src/lib.rs index 1cf5504c5e7..75ed81894c2 100644 --- a/substrate/primitives/consensus/grandpa/src/lib.rs +++ b/substrate/primitives/consensus/grandpa/src/lib.rs @@ -19,9 +19,12 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + #[cfg(feature = "serde")] use serde::Serialize; +use alloc::vec::Vec; use codec::{Codec, Decode, Encode}; use scale_info::TypeInfo; #[cfg(feature = "std")] @@ -30,7 +33,6 @@ use sp_runtime::{ traits::{Header as HeaderT, NumberFor}, ConsensusEngineId, RuntimeDebug, }; -use sp_std::vec::Vec; /// The log target to be used by client code. pub const CLIENT_LOG_TARGET: &str = "grandpa"; diff --git a/substrate/primitives/consensus/pow/Cargo.toml b/substrate/primitives/consensus/pow/Cargo.toml index 8147b063f6d..7a884f865fb 100644 --- a/substrate/primitives/consensus/pow/Cargo.toml +++ b/substrate/primitives/consensus/pow/Cargo.toml @@ -20,7 +20,6 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = sp-api = { path = "../../api", default-features = false } sp-core = { path = "../../core", default-features = false } sp-runtime = { path = "../../runtime", default-features = false } -sp-std = { path = "../../std", default-features = false } [features] default = ["std"] @@ -29,5 +28,4 @@ std = [ "sp-api/std", "sp-core/std", "sp-runtime/std", - "sp-std/std", ] diff --git a/substrate/primitives/consensus/pow/src/lib.rs b/substrate/primitives/consensus/pow/src/lib.rs index f37aae1c5c0..c14d23cf068 100644 --- a/substrate/primitives/consensus/pow/src/lib.rs +++ b/substrate/primitives/consensus/pow/src/lib.rs @@ -19,9 +19,12 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; use codec::Decode; use sp_runtime::ConsensusEngineId; -use sp_std::vec::Vec; /// The `ConsensusEngineId` of PoW. pub const POW_ENGINE_ID: ConsensusEngineId = [b'p', b'o', b'w', b'_']; diff --git a/substrate/primitives/consensus/sassafras/Cargo.toml b/substrate/primitives/consensus/sassafras/Cargo.toml index b707ad18b5b..085709d4c8b 100644 --- a/substrate/primitives/consensus/sassafras/Cargo.toml +++ b/substrate/primitives/consensus/sassafras/Cargo.toml @@ -26,7 +26,6 @@ sp-application-crypto = { path = "../../application-crypto", default-features = sp-consensus-slots = { path = "../slots", default-features = false } sp-core = { path = "../../core", default-features = false, features = ["bandersnatch-experimental"] } sp-runtime = { path = "../../runtime", default-features = false } -sp-std = { path = "../../std", default-features = false } [features] default = ["std"] @@ -39,7 +38,6 @@ std = [ "sp-consensus-slots/std", "sp-core/std", "sp-runtime/std", - "sp-std/std", ] # Serde support without relying on std features. diff --git a/substrate/primitives/consensus/sassafras/src/digests.rs b/substrate/primitives/consensus/sassafras/src/digests.rs index 5274f1309d8..64190a41ce1 100644 --- a/substrate/primitives/consensus/sassafras/src/digests.rs +++ b/substrate/primitives/consensus/sassafras/src/digests.rs @@ -25,8 +25,9 @@ use crate::{ use scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; use sp_runtime::{DigestItem, RuntimeDebug}; -use sp_std::vec::Vec; /// Epoch slot claim digest entry. /// diff --git a/substrate/primitives/consensus/sassafras/src/lib.rs b/substrate/primitives/consensus/sassafras/src/lib.rs index 1752f765886..c1fea74d045 100644 --- a/substrate/primitives/consensus/sassafras/src/lib.rs +++ b/substrate/primitives/consensus/sassafras/src/lib.rs @@ -21,11 +21,13 @@ #![forbid(unsafe_code, missing_docs, unused_variables, unused_imports)] #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + +use alloc::vec::Vec; use scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_core::crypto::KeyTypeId; use sp_runtime::{ConsensusEngineId, RuntimeDebug}; -use sp_std::vec::Vec; pub use sp_consensus_slots::{Slot, SlotDuration}; diff --git a/substrate/primitives/consensus/sassafras/src/vrf.rs b/substrate/primitives/consensus/sassafras/src/vrf.rs index 5deacd8e994..815edb5eb66 100644 --- a/substrate/primitives/consensus/sassafras/src/vrf.rs +++ b/substrate/primitives/consensus/sassafras/src/vrf.rs @@ -18,9 +18,10 @@ //! Utilities related to VRF input, pre-output and signatures. use crate::{Randomness, TicketBody, TicketId}; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; use scale_codec::Encode; use sp_consensus_slots::Slot; -use sp_std::vec::Vec; pub use sp_core::bandersnatch::{ ring_vrf::{RingProver, RingVerifier, RingVerifierData, RingVrfSignature}, diff --git a/substrate/primitives/consensus/slots/Cargo.toml b/substrate/primitives/consensus/slots/Cargo.toml index 8372b2b04a6..94c02dba203 100644 --- a/substrate/primitives/consensus/slots/Cargo.toml +++ b/substrate/primitives/consensus/slots/Cargo.toml @@ -19,7 +19,6 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], optional = true, workspace = true } -sp-std = { path = "../../std", default-features = false } sp-timestamp = { path = "../../timestamp", default-features = false } [features] @@ -28,7 +27,6 @@ std = [ "codec/std", "scale-info/std", "serde/std", - "sp-std/std", "sp-timestamp/std", ] diff --git a/substrate/primitives/crypto/ec-utils/Cargo.toml b/substrate/primitives/crypto/ec-utils/Cargo.toml index 43daad08921..142a5abf9b3 100644 --- a/substrate/primitives/crypto/ec-utils/Cargo.toml +++ b/substrate/primitives/crypto/ec-utils/Cargo.toml @@ -28,7 +28,6 @@ ark-ed-on-bls12-377-ext = { version = "0.4.1", default-features = false, optiona ark-ed-on-bls12-377 = { version = "0.4.0", default-features = false, optional = true } ark-scale = { version = "0.0.12", default-features = false, features = ["hazmat"], optional = true } sp-runtime-interface = { path = "../../runtime-interface", default-features = false, optional = true } -sp-std = { path = "../../std", default-features = false, optional = true } [features] default = ["std"] @@ -47,9 +46,8 @@ std = [ "ark-ed-on-bls12-381-bandersnatch?/std", "ark-scale?/std", "sp-runtime-interface?/std", - "sp-std?/std", ] -common = ["ark-ec", "ark-scale", "sp-runtime-interface", "sp-std"] +common = ["ark-ec", "ark-scale", "sp-runtime-interface"] bls12-377 = ["ark-bls12-377", "ark-bls12-377-ext", "common"] bls12-381 = ["ark-bls12-381", "ark-bls12-381-ext", "common"] bw6-761 = ["ark-bw6-761", "ark-bw6-761-ext", "common"] diff --git a/substrate/primitives/crypto/ec-utils/src/bls12_377.rs b/substrate/primitives/crypto/ec-utils/src/bls12_377.rs index 8f19a2c4a19..a1ea5dbbf93 100644 --- a/substrate/primitives/crypto/ec-utils/src/bls12_377.rs +++ b/substrate/primitives/crypto/ec-utils/src/bls12_377.rs @@ -18,10 +18,10 @@ //! *BLS12-377* types and host functions. use crate::utils; +use alloc::vec::Vec; use ark_bls12_377_ext::CurveHooks; use ark_ec::{pairing::Pairing, CurveConfig}; use sp_runtime_interface::runtime_interface; -use sp_std::vec::Vec; /// First pairing group definitions. pub mod g1 { diff --git a/substrate/primitives/crypto/ec-utils/src/bls12_381.rs b/substrate/primitives/crypto/ec-utils/src/bls12_381.rs index 99a0289b7ad..5e02862ed7b 100644 --- a/substrate/primitives/crypto/ec-utils/src/bls12_381.rs +++ b/substrate/primitives/crypto/ec-utils/src/bls12_381.rs @@ -18,10 +18,10 @@ //! *BLS12-381* types and host functions. use crate::utils; +use alloc::vec::Vec; use ark_bls12_381_ext::CurveHooks; use ark_ec::{pairing::Pairing, CurveConfig}; use sp_runtime_interface::runtime_interface; -use sp_std::vec::Vec; /// First pairing group definitions. pub mod g1 { diff --git a/substrate/primitives/crypto/ec-utils/src/bw6_761.rs b/substrate/primitives/crypto/ec-utils/src/bw6_761.rs index a68abf6e43e..4ee1035f670 100644 --- a/substrate/primitives/crypto/ec-utils/src/bw6_761.rs +++ b/substrate/primitives/crypto/ec-utils/src/bw6_761.rs @@ -18,10 +18,10 @@ //! *BW6-761* types and host functions. use crate::utils; +use alloc::vec::Vec; use ark_bw6_761_ext::CurveHooks; use ark_ec::{pairing::Pairing, CurveConfig}; use sp_runtime_interface::runtime_interface; -use sp_std::vec::Vec; /// First pairing group definitions. pub mod g1 { diff --git a/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_377.rs b/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_377.rs index a03be41b854..e068507b347 100644 --- a/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_377.rs +++ b/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_377.rs @@ -18,10 +18,10 @@ //! *Ed-on-BLS12-377* types and host functions. use crate::utils; +use alloc::vec::Vec; use ark_ec::CurveConfig; use ark_ed_on_bls12_377_ext::CurveHooks; use sp_runtime_interface::runtime_interface; -use sp_std::vec::Vec; /// Curve hooks jumping into [`host_calls`] host functions. #[derive(Copy, Clone)] diff --git a/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_381_bandersnatch.rs b/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_381_bandersnatch.rs index 9d63f358765..487ad98dac6 100644 --- a/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_381_bandersnatch.rs +++ b/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_381_bandersnatch.rs @@ -19,10 +19,10 @@ //! computationally expensive operations. use crate::utils; +use alloc::vec::Vec; use ark_ec::CurveConfig; use ark_ed_on_bls12_381_bandersnatch_ext::CurveHooks; use sp_runtime_interface::runtime_interface; -use sp_std::vec::Vec; /// Curve hooks jumping into [`host_calls`] host functions. #[derive(Copy, Clone)] diff --git a/substrate/primitives/crypto/ec-utils/src/lib.rs b/substrate/primitives/crypto/ec-utils/src/lib.rs index 970ad71765a..3254bbe648f 100644 --- a/substrate/primitives/crypto/ec-utils/src/lib.rs +++ b/substrate/primitives/crypto/ec-utils/src/lib.rs @@ -32,6 +32,8 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + #[cfg(feature = "bls12-377")] pub mod bls12_377; #[cfg(feature = "bls12-381")] diff --git a/substrate/primitives/crypto/ec-utils/src/utils.rs b/substrate/primitives/crypto/ec-utils/src/utils.rs index d0dd8ed8131..47a49fe16cc 100644 --- a/substrate/primitives/crypto/ec-utils/src/utils.rs +++ b/substrate/primitives/crypto/ec-utils/src/utils.rs @@ -21,6 +21,7 @@ // curve may be excluded by the build we resort to `#[allow(unused)]` to // suppress the expected warning. +use alloc::vec::Vec; use ark_ec::{ pairing::{MillerLoopOutput, Pairing}, short_weierstrass::{Affine as SWAffine, Projective as SWProjective, SWCurveConfig}, @@ -31,7 +32,6 @@ use ark_scale::{ ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, Validate}, scale::{Decode, Encode}, }; -use sp_std::vec::Vec; // SCALE encoding parameters shared by all the enabled modules const SCALE_USAGE: u8 = ark_scale::make_usage(Compress::No, Validate::No); diff --git a/substrate/primitives/externalities/Cargo.toml b/substrate/primitives/externalities/Cargo.toml index 6dc4f0a0dad..20fa3e3e397 100644 --- a/substrate/primitives/externalities/Cargo.toml +++ b/substrate/primitives/externalities/Cargo.toml @@ -19,9 +19,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } environmental = { version = "1.1.3", default-features = false } -sp-std = { path = "../std", default-features = false } sp-storage = { path = "../storage", default-features = false } [features] default = ["std"] -std = ["codec/std", "environmental/std", "sp-std/std", "sp-storage/std"] +std = ["codec/std", "environmental/std", "sp-storage/std"] diff --git a/substrate/primitives/externalities/src/extensions.rs b/substrate/primitives/externalities/src/extensions.rs index d99dfe6cf53..a4aa847a1aa 100644 --- a/substrate/primitives/externalities/src/extensions.rs +++ b/substrate/primitives/externalities/src/extensions.rs @@ -23,10 +23,12 @@ //! It is required that each extension implements the [`Extension`] trait. use crate::Error; -use sp_std::{ - any::{Any, TypeId}, +use alloc::{ boxed::Box, collections::btree_map::{BTreeMap, Entry}, +}; +use core::{ + any::{Any, TypeId}, ops::DerefMut, }; diff --git a/substrate/primitives/externalities/src/lib.rs b/substrate/primitives/externalities/src/lib.rs index 411ec97a6b8..142200f614a 100644 --- a/substrate/primitives/externalities/src/lib.rs +++ b/substrate/primitives/externalities/src/lib.rs @@ -25,11 +25,10 @@ //! //! This crate exposes the main [`Externalities`] trait. -use sp_std::{ - any::{Any, TypeId}, - boxed::Box, - vec::Vec, -}; +extern crate alloc; + +use alloc::{boxed::Box, vec::Vec}; +use core::any::{Any, TypeId}; use sp_storage::{ChildInfo, StateVersion, TrackedStorageKey}; diff --git a/substrate/primitives/genesis-builder/Cargo.toml b/substrate/primitives/genesis-builder/Cargo.toml index 15440b4811e..5a8f1c2962c 100644 --- a/substrate/primitives/genesis-builder/Cargo.toml +++ b/substrate/primitives/genesis-builder/Cargo.toml @@ -18,9 +18,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-api = { path = "../api", default-features = false } sp-runtime = { path = "../runtime", default-features = false } -sp-std = { path = "../std", default-features = false } serde_json = { features = ["alloc", "arbitrary_precision"], workspace = true } [features] default = ["std"] -std = ["serde_json/std", "sp-api/std", "sp-runtime/std", "sp-std/std"] +std = ["serde_json/std", "sp-api/std", "sp-runtime/std"] diff --git a/substrate/primitives/genesis-builder/src/lib.rs b/substrate/primitives/genesis-builder/src/lib.rs index bb1a2a35248..4970042187c 100644 --- a/substrate/primitives/genesis-builder/src/lib.rs +++ b/substrate/primitives/genesis-builder/src/lib.rs @@ -31,6 +31,8 @@ //! allows to catch and build the raw storage of `RuntimeGenesisConfig` which is the foundation for //! genesis block. +extern crate alloc; + /// The result type alias, used in build methods. `Err` contains formatted error message. pub type Result = core::result::Result<(), sp_runtime::RuntimeString>; @@ -41,7 +43,7 @@ sp_api::decl_runtime_apis! { /// /// This function instantiates the default `RuntimeGenesisConfig` struct for the runtime and serializes it into a JSON /// blob. It returns a `Vec` containing the JSON representation of the default `RuntimeGenesisConfig`. - fn create_default_config() -> sp_std::vec::Vec; + fn create_default_config() -> alloc::vec::Vec; /// Build `RuntimeGenesisConfig` from a JSON blob not using any defaults and store it in the storage. /// @@ -50,6 +52,6 @@ sp_api::decl_runtime_apis! { /// It is recommended to log any errors encountered during the process. /// /// Please note that provided json blob must contain all `RuntimeGenesisConfig` fields, no defaults will be used. - fn build_config(json: sp_std::vec::Vec) -> Result; + fn build_config(json: alloc::vec::Vec) -> Result; } } diff --git a/substrate/primitives/inherents/Cargo.toml b/substrate/primitives/inherents/Cargo.toml index bfb1d773347..6463c423fe7 100644 --- a/substrate/primitives/inherents/Cargo.toml +++ b/substrate/primitives/inherents/Cargo.toml @@ -23,7 +23,6 @@ scale-info = { version = "2.10.0", default-features = false, features = ["derive impl-trait-for-tuples = "0.2.2" thiserror = { optional = true, workspace = true } sp-runtime = { path = "../runtime", default-features = false, optional = true } -sp-std = { path = "../std", default-features = false } [dev-dependencies] futures = "0.3.21" @@ -35,6 +34,5 @@ std = [ "codec/std", "scale-info/std", "sp-runtime/std", - "sp-std/std", "thiserror", ] diff --git a/substrate/primitives/inherents/src/lib.rs b/substrate/primitives/inherents/src/lib.rs index dd7c294f1e2..80787669856 100644 --- a/substrate/primitives/inherents/src/lib.rs +++ b/substrate/primitives/inherents/src/lib.rs @@ -162,9 +162,11 @@ #![cfg_attr(not(feature = "std"), no_std)] #![warn(missing_docs)] +extern crate alloc; + use codec::{Decode, Encode}; -use sp_std::{ +use alloc::{ collections::btree_map::{BTreeMap, Entry, IntoIter}, vec::Vec, }; diff --git a/substrate/primitives/merkle-mountain-range/Cargo.toml b/substrate/primitives/merkle-mountain-range/Cargo.toml index 50d84778239..9c07f699b37 100644 --- a/substrate/primitives/merkle-mountain-range/Cargo.toml +++ b/substrate/primitives/merkle-mountain-range/Cargo.toml @@ -24,7 +24,6 @@ sp-api = { path = "../api", default-features = false } sp-core = { path = "../core", default-features = false } sp-debug-derive = { path = "../debug-derive", default-features = false } sp-runtime = { path = "../runtime", default-features = false } -sp-std = { path = "../std", default-features = false } thiserror = { optional = true, workspace = true } [dev-dependencies] @@ -43,7 +42,6 @@ std = [ "sp-core/std", "sp-debug-derive/std", "sp-runtime/std", - "sp-std/std", ] # Serde support without relying on std features. diff --git a/substrate/primitives/merkle-mountain-range/src/lib.rs b/substrate/primitives/merkle-mountain-range/src/lib.rs index 6c0e75005ea..c76d66bb08e 100644 --- a/substrate/primitives/merkle-mountain-range/src/lib.rs +++ b/substrate/primitives/merkle-mountain-range/src/lib.rs @@ -20,14 +20,16 @@ #![cfg_attr(not(feature = "std"), no_std)] #![warn(missing_docs)] +extern crate alloc; + pub use mmr_lib; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; +use core::fmt; use scale_info::TypeInfo; use sp_debug_derive::RuntimeDebug; use sp_runtime::traits; -use sp_std::fmt; -#[cfg(not(feature = "std"))] -use sp_std::prelude::Vec; pub mod utils; @@ -248,10 +250,10 @@ impl DataOrHash { pub struct Compact { /// Internal tuple representation. pub tuple: T, - _hash: sp_std::marker::PhantomData, + _hash: core::marker::PhantomData, } -impl sp_std::ops::Deref for Compact { +impl core::ops::Deref for Compact { type Target = T; fn deref(&self) -> &Self::Target { diff --git a/substrate/primitives/merkle-mountain-range/src/utils.rs b/substrate/primitives/merkle-mountain-range/src/utils.rs index b9171c96a62..72674e24a27 100644 --- a/substrate/primitives/merkle-mountain-range/src/utils.rs +++ b/substrate/primitives/merkle-mountain-range/src/utils.rs @@ -20,9 +20,9 @@ use codec::Encode; use mmr_lib::helper; -use sp_runtime::traits::{CheckedAdd, CheckedSub, Header, One}; #[cfg(not(feature = "std"))] -use sp_std::prelude::Vec; +use alloc::vec::Vec; +use sp_runtime::traits::{CheckedAdd, CheckedSub, Header, One}; use crate::{Error, LeafIndex, NodeIndex}; @@ -131,7 +131,7 @@ impl NodesUtils { /// Used for nodes added by now finalized blocks. /// Never read keys using `node_canon_offchain_key` unless you sure that /// there's no `node_offchain_key` key in the storage. - pub fn node_canon_offchain_key(prefix: &[u8], pos: NodeIndex) -> sp_std::prelude::Vec { + pub fn node_canon_offchain_key(prefix: &[u8], pos: NodeIndex) -> alloc::vec::Vec { (prefix, pos).encode() } } diff --git a/substrate/primitives/metadata-ir/Cargo.toml b/substrate/primitives/metadata-ir/Cargo.toml index e4203d0e378..31c839b5c48 100644 --- a/substrate/primitives/metadata-ir/Cargo.toml +++ b/substrate/primitives/metadata-ir/Cargo.toml @@ -19,8 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } frame-metadata = { version = "16.0.0", default-features = false, features = ["current"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -sp-std = { path = "../std", default-features = false } [features] default = ["std"] -std = ["codec/std", "frame-metadata/std", "scale-info/std", "sp-std/std"] +std = ["codec/std", "frame-metadata/std", "scale-info/std"] diff --git a/substrate/primitives/metadata-ir/src/lib.rs b/substrate/primitives/metadata-ir/src/lib.rs index edfa58f8618..18b20f2ccaa 100644 --- a/substrate/primitives/metadata-ir/src/lib.rs +++ b/substrate/primitives/metadata-ir/src/lib.rs @@ -20,6 +20,8 @@ #![cfg_attr(not(feature = "std"), no_std)] #![warn(missing_docs)] +extern crate alloc; + // Re-export. #[doc(hidden)] pub use frame_metadata; @@ -52,8 +54,8 @@ pub fn into_version(metadata: MetadataIR, version: u32) -> Option sp_std::vec::Vec { - sp_std::vec![V14, V15] +pub fn supported_versions() -> alloc::vec::Vec { + alloc::vec![V14, V15] } /// Transform the IR to the latest stable metadata version. diff --git a/substrate/primitives/mixnet/Cargo.toml b/substrate/primitives/mixnet/Cargo.toml index 39cf684b977..8ba7f36da43 100644 --- a/substrate/primitives/mixnet/Cargo.toml +++ b/substrate/primitives/mixnet/Cargo.toml @@ -20,7 +20,6 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } sp-api = { default-features = false, path = "../api" } sp-application-crypto = { default-features = false, path = "../application-crypto" } -sp-std = { default-features = false, path = "../std" } [features] default = ["std"] @@ -29,5 +28,4 @@ std = [ "scale-info/std", "sp-api/std", "sp-application-crypto/std", - "sp-std/std", ] diff --git a/substrate/primitives/mixnet/src/lib.rs b/substrate/primitives/mixnet/src/lib.rs index 58b8a10f0cd..462d7fc61f2 100644 --- a/substrate/primitives/mixnet/src/lib.rs +++ b/substrate/primitives/mixnet/src/lib.rs @@ -20,5 +20,7 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + pub mod runtime_api; pub mod types; diff --git a/substrate/primitives/mixnet/src/runtime_api.rs b/substrate/primitives/mixnet/src/runtime_api.rs index 28ab40e6337..f3260782b0b 100644 --- a/substrate/primitives/mixnet/src/runtime_api.rs +++ b/substrate/primitives/mixnet/src/runtime_api.rs @@ -18,7 +18,7 @@ //! Runtime API for querying mixnet configuration and registering mixnodes. use super::types::{Mixnode, MixnodesErr, SessionIndex, SessionStatus}; -use sp_std::vec::Vec; +use alloc::vec::Vec; sp_api::decl_runtime_apis! { /// API to query the mixnet session status and mixnode sets, and to register mixnodes. diff --git a/substrate/primitives/mixnet/src/types.rs b/substrate/primitives/mixnet/src/types.rs index fc214f94d1c..3b069e1fb3a 100644 --- a/substrate/primitives/mixnet/src/types.rs +++ b/substrate/primitives/mixnet/src/types.rs @@ -17,9 +17,9 @@ //! Mixnet types used by both host and runtime. +use alloc::vec::Vec; use codec::{Decode, Encode}; use scale_info::TypeInfo; -use sp_std::vec::Vec; mod app { use sp_application_crypto::{app_crypto, key_types::MIXNET, sr25519}; @@ -90,8 +90,8 @@ pub enum MixnodesErr { }, } -impl sp_std::fmt::Display for MixnodesErr { - fn fmt(&self, fmt: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { +impl core::fmt::Display for MixnodesErr { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { match self { MixnodesErr::InsufficientRegistrations { num, min } => write!(fmt, "{num} mixnode(s) registered; {min} is the minimum"), diff --git a/substrate/primitives/npos-elections/Cargo.toml b/substrate/primitives/npos-elections/Cargo.toml index 7373aa849cb..b0b9890c061 100644 --- a/substrate/primitives/npos-elections/Cargo.toml +++ b/substrate/primitives/npos-elections/Cargo.toml @@ -22,7 +22,6 @@ serde = { features = ["alloc", "derive"], optional = true, workspace = true } sp-arithmetic = { path = "../arithmetic", default-features = false } sp-core = { path = "../core", default-features = false } sp-runtime = { path = "../runtime", default-features = false } -sp-std = { path = "../std", default-features = false } [dev-dependencies] rand = "0.8.5" @@ -38,7 +37,6 @@ std = [ "sp-arithmetic/std", "sp-core/std", "sp-runtime/std", - "sp-std/std", ] # Serde support without relying on std features. diff --git a/substrate/primitives/npos-elections/src/assignments.rs b/substrate/primitives/npos-elections/src/assignments.rs index 2ac2b9bebd7..0686fdda643 100644 --- a/substrate/primitives/npos-elections/src/assignments.rs +++ b/substrate/primitives/npos-elections/src/assignments.rs @@ -18,6 +18,7 @@ //! Structs and helpers for distributing a voter's stake among various winners. use crate::{ExtendedBalance, IdentifierT, PerThing128}; +use alloc::vec::Vec; #[cfg(feature = "serde")] use codec::{Decode, Encode}; use sp_arithmetic::{ @@ -25,7 +26,6 @@ use sp_arithmetic::{ Normalizable, PerThing, }; use sp_core::RuntimeDebug; -use sp_std::vec::Vec; /// A voter's stake assignment among a set of targets, represented as ratios. #[derive(RuntimeDebug, Clone, Default)] diff --git a/substrate/primitives/npos-elections/src/balancing.rs b/substrate/primitives/npos-elections/src/balancing.rs index 90dbe7eb714..fb14c868658 100644 --- a/substrate/primitives/npos-elections/src/balancing.rs +++ b/substrate/primitives/npos-elections/src/balancing.rs @@ -27,8 +27,8 @@ //! See [`balance`] for more information. use crate::{BalancingConfig, Edge, ExtendedBalance, IdentifierT, Voter}; +use alloc::vec::Vec; use sp_arithmetic::traits::Zero; -use sp_std::prelude::*; /// Balance the weight distribution of a given `voters` at most `iterations` times, or up until the /// point where the biggest difference created per iteration of all stakes is `tolerance`. If this diff --git a/substrate/primitives/npos-elections/src/helpers.rs b/substrate/primitives/npos-elections/src/helpers.rs index 082491ea042..7df6ec9d9db 100644 --- a/substrate/primitives/npos-elections/src/helpers.rs +++ b/substrate/primitives/npos-elections/src/helpers.rs @@ -18,8 +18,8 @@ //! Helper methods for npos-elections. use crate::{Assignment, Error, IdentifierT, PerThing128, StakedAssignment, VoteWeight}; +use alloc::vec::Vec; use sp_arithmetic::PerThing; -use sp_std::prelude::*; /// Converts a vector of ratio assignments into ones with absolute budget value. /// diff --git a/substrate/primitives/npos-elections/src/lib.rs b/substrate/primitives/npos-elections/src/lib.rs index 8d741f4130d..82ac40fe273 100644 --- a/substrate/primitives/npos-elections/src/lib.rs +++ b/substrate/primitives/npos-elections/src/lib.rs @@ -74,15 +74,16 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + +use alloc::{collections::btree_map::BTreeMap, rc::Rc, vec, vec::Vec}; use codec::{Decode, Encode, MaxEncodedLen}; +use core::{cell::RefCell, cmp::Ordering}; use scale_info::TypeInfo; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use sp_arithmetic::{traits::Zero, Normalizable, PerThing, Rational128, ThresholdOrd}; use sp_core::{bounded::BoundedVec, RuntimeDebug}; -use sp_std::{ - cell::RefCell, cmp::Ordering, collections::btree_map::BTreeMap, prelude::*, rc::Rc, vec, -}; #[cfg(test)] mod mock; @@ -198,7 +199,7 @@ impl ElectionScore { } } -impl sp_std::cmp::Ord for ElectionScore { +impl core::cmp::Ord for ElectionScore { fn cmp(&self, other: &Self) -> Ordering { // we delegate this to the lexicographic cmp of slices`, and to incorporate that we want the // third element to be minimized, we swap them. @@ -210,7 +211,7 @@ impl sp_std::cmp::Ord for ElectionScore { } } -impl sp_std::cmp::PartialOrd for ElectionScore { +impl core::cmp::PartialOrd for ElectionScore { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } @@ -278,8 +279,8 @@ impl Edge { } #[cfg(feature = "std")] -impl sp_std::fmt::Debug for Edge { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { +impl core::fmt::Debug for Edge { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "Edge({:?}, weight = {:?})", self.who, self.weight) } } @@ -299,7 +300,7 @@ pub struct Voter { #[cfg(feature = "std")] impl std::fmt::Debug for Voter { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "Voter({:?}, budget = {}, edges = {:?})", self.who, self.budget, self.edges) } } diff --git a/substrate/primitives/npos-elections/src/mock.rs b/substrate/primitives/npos-elections/src/mock.rs index 2fc49fd72cd..91757404145 100644 --- a/substrate/primitives/npos-elections/src/mock.rs +++ b/substrate/primitives/npos-elections/src/mock.rs @@ -19,12 +19,12 @@ #![cfg(test)] +use alloc::collections::btree_map::BTreeMap; use sp_arithmetic::{ traits::{One, SaturatedConversion, Zero}, PerThing, }; use sp_runtime::assert_eq_error_rate; -use sp_std::collections::btree_map::BTreeMap; use crate::{seq_phragmen, Assignment, ElectionResult, ExtendedBalance, PerThing128, VoteWeight}; @@ -131,7 +131,7 @@ where if let Some(winner) = candidates .iter_mut() .filter(|c| !c.elected) - .min_by(|x, y| x.score.partial_cmp(&y.score).unwrap_or(sp_std::cmp::Ordering::Equal)) + .min_by(|x, y| x.score.partial_cmp(&y.score).unwrap_or(core::cmp::Ordering::Equal)) { winner.elected = true; for n in &mut voters { @@ -226,10 +226,10 @@ where if backing_backed_stake.len() > 0 { let max_stake = backing_backed_stake .iter() - .max_by(|x, y| x.partial_cmp(&y).unwrap_or(sp_std::cmp::Ordering::Equal)) + .max_by(|x, y| x.partial_cmp(&y).unwrap_or(core::cmp::Ordering::Equal)) .expect("vector with positive length will have a max; qed"); let min_stake = backed_stakes_iter - .min_by(|x, y| x.partial_cmp(&y).unwrap_or(sp_std::cmp::Ordering::Equal)) + .min_by(|x, y| x.partial_cmp(&y).unwrap_or(core::cmp::Ordering::Equal)) .expect("iterator with positive length will have a min; qed"); difference = max_stake - min_stake; @@ -254,7 +254,7 @@ where support_map .get(&x.0) .and_then(|x| support_map.get(&y.0).and_then(|y| x.total.partial_cmp(&y.total))) - .unwrap_or(sp_std::cmp::Ordering::Equal) + .unwrap_or(core::cmp::Ordering::Equal) }); let mut cumulative_stake = 0.0; diff --git a/substrate/primitives/npos-elections/src/node.rs b/substrate/primitives/npos-elections/src/node.rs index caca9561d83..6fe50ad1d0a 100644 --- a/substrate/primitives/npos-elections/src/node.rs +++ b/substrate/primitives/npos-elections/src/node.rs @@ -17,7 +17,8 @@ //! (very) Basic implementation of a graph node used in the reduce algorithm. -use sp_std::{cell::RefCell, fmt, prelude::*, rc::Rc}; +use alloc::{rc::Rc, vec::Vec}; +use core::{cell::RefCell, fmt}; /// The role that a node can accept. #[derive(PartialEq, Eq, Ord, PartialOrd, Clone, Debug)] @@ -49,8 +50,8 @@ impl NodeId { } #[cfg(feature = "std")] -impl sp_std::fmt::Debug for NodeId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> sp_std::fmt::Result { +impl fmt::Debug for NodeId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "Node({:?}, {:?})", diff --git a/substrate/primitives/npos-elections/src/phragmen.rs b/substrate/primitives/npos-elections/src/phragmen.rs index c3578065f36..f331152e722 100644 --- a/substrate/primitives/npos-elections/src/phragmen.rs +++ b/substrate/primitives/npos-elections/src/phragmen.rs @@ -24,12 +24,12 @@ use crate::{ balancing, setup_inputs, BalancingConfig, CandidatePtr, ElectionResult, ExtendedBalance, IdentifierT, PerThing128, VoteWeight, Voter, }; +use alloc::vec::Vec; use sp_arithmetic::{ helpers_128bit::multiply_by_rational_with_rounding, traits::{Bounded, Zero}, Rational128, Rounding, }; -use sp_std::prelude::*; /// The denominator used for loads. Since votes are collected as u64, the smallest ratio that we /// might collect is `1/approval_stake` where approval stake is the sum of votes. Hence, some number diff --git a/substrate/primitives/npos-elections/src/phragmms.rs b/substrate/primitives/npos-elections/src/phragmms.rs index df6becf4747..9a17f0dfa7c 100644 --- a/substrate/primitives/npos-elections/src/phragmms.rs +++ b/substrate/primitives/npos-elections/src/phragmms.rs @@ -25,8 +25,8 @@ use crate::{ balance, setup_inputs, BalancingConfig, CandidatePtr, ElectionResult, ExtendedBalance, IdentifierT, PerThing128, VoteWeight, Voter, }; +use alloc::{rc::Rc, vec, vec::Vec}; use sp_arithmetic::{traits::Bounded, PerThing, Rational128}; -use sp_std::{prelude::*, rc::Rc}; /// Execute the phragmms method. /// @@ -232,8 +232,8 @@ pub(crate) fn apply_elected( mod tests { use super::*; use crate::{Assignment, ElectionResult}; + use alloc::rc::Rc; use sp_runtime::{Perbill, Percent}; - use sp_std::rc::Rc; #[test] fn basic_election_manual_works() { diff --git a/substrate/primitives/npos-elections/src/pjr.rs b/substrate/primitives/npos-elections/src/pjr.rs index f0e59a25d44..08e40a014ea 100644 --- a/substrate/primitives/npos-elections/src/pjr.rs +++ b/substrate/primitives/npos-elections/src/pjr.rs @@ -26,8 +26,8 @@ use crate::{ Candidate, CandidatePtr, Edge, ExtendedBalance, IdentifierT, Support, SupportMap, Supports, VoteWeight, Voter, }; +use alloc::{collections::btree_map::BTreeMap, rc::Rc, vec::Vec}; use sp_arithmetic::{traits::Zero, Perbill}; -use sp_std::{collections::btree_map::BTreeMap, rc::Rc, vec::Vec}; /// The type used as the threshold. /// /// Just some reading sugar; Must always be same as [`ExtendedBalance`]; diff --git a/substrate/primitives/npos-elections/src/reduce.rs b/substrate/primitives/npos-elections/src/reduce.rs index 6a5a0159e4e..c9ed493daf3 100644 --- a/substrate/primitives/npos-elections/src/reduce.rs +++ b/substrate/primitives/npos-elections/src/reduce.rs @@ -51,11 +51,12 @@ use crate::{ node::{Node, NodeId, NodeRef, NodeRole}, ExtendedBalance, IdentifierT, StakedAssignment, }; -use sp_arithmetic::traits::{Bounded, Zero}; -use sp_std::{ +use alloc::{ collections::btree_map::{BTreeMap, Entry::*}, - prelude::*, + vec, + vec::Vec, }; +use sp_arithmetic::traits::{Bounded, Zero}; /// Map type used for reduce_4. Can be easily swapped with HashMap. type Map = BTreeMap<(A, A), A>; diff --git a/substrate/primitives/npos-elections/src/traits.rs b/substrate/primitives/npos-elections/src/traits.rs index d49970873b7..afa6ac70880 100644 --- a/substrate/primitives/npos-elections/src/traits.rs +++ b/substrate/primitives/npos-elections/src/traits.rs @@ -18,8 +18,8 @@ //! Traits for the npos-election operations. use crate::ExtendedBalance; +use core::{fmt::Debug, ops::Mul}; use sp_arithmetic::PerThing; -use sp_std::{fmt::Debug, ops::Mul, prelude::*}; /// an aggregator trait for a generic type of a voter/target identifier. This usually maps to /// substrate's account id. diff --git a/substrate/primitives/session/Cargo.toml b/substrate/primitives/session/Cargo.toml index 99764c0a17f..784228c42e9 100644 --- a/substrate/primitives/session/Cargo.toml +++ b/substrate/primitives/session/Cargo.toml @@ -22,7 +22,6 @@ sp-api = { path = "../api", default-features = false } sp-core = { path = "../core", default-features = false } sp-runtime = { path = "../runtime", optional = true } sp-staking = { path = "../staking", default-features = false } -sp-std = { path = "../std", default-features = false } sp-keystore = { path = "../keystore", optional = true } [features] @@ -35,5 +34,4 @@ std = [ "sp-keystore/std", "sp-runtime/std", "sp-staking/std", - "sp-std/std", ] diff --git a/substrate/primitives/session/src/lib.rs b/substrate/primitives/session/src/lib.rs index 9933495fd60..fe7a3804733 100644 --- a/substrate/primitives/session/src/lib.rs +++ b/substrate/primitives/session/src/lib.rs @@ -19,6 +19,8 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + use codec::{Decode, Encode}; #[cfg(feature = "std")] @@ -26,9 +28,9 @@ use sp_api::ProvideRuntimeApi; #[cfg(feature = "std")] use sp_runtime::traits::Block as BlockT; +use alloc::vec::Vec; use sp_core::RuntimeDebug; use sp_staking::SessionIndex; -use sp_std::vec::Vec; pub mod runtime_api; pub use runtime_api::*; diff --git a/substrate/primitives/session/src/runtime_api.rs b/substrate/primitives/session/src/runtime_api.rs index 5e508cd3dbd..3acc882aabc 100644 --- a/substrate/primitives/session/src/runtime_api.rs +++ b/substrate/primitives/session/src/runtime_api.rs @@ -15,8 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +use alloc::vec::Vec; pub use sp_core::crypto::KeyTypeId; -use sp_std::prelude::*; sp_api::decl_runtime_apis! { /// Session keys runtime api. diff --git a/substrate/primitives/staking/Cargo.toml b/substrate/primitives/staking/Cargo.toml index 21346fbaca5..6304551b8e6 100644 --- a/substrate/primitives/staking/Cargo.toml +++ b/substrate/primitives/staking/Cargo.toml @@ -23,7 +23,6 @@ impl-trait-for-tuples = "0.2.2" sp-core = { path = "../core", default-features = false } sp-runtime = { path = "../runtime", default-features = false } -sp-std = { path = "../std", default-features = false } [features] default = ["std"] @@ -33,6 +32,5 @@ std = [ "serde/std", "sp-core/std", "sp-runtime/std", - "sp-std/std", ] runtime-benchmarks = ["sp-runtime/runtime-benchmarks"] diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index f5b4a1ed63f..11b7ef41b9a 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -20,14 +20,17 @@ //! A crate which contains primitives that are useful for implementation that uses staking //! approaches in general. Definitions related to sessions, slashing, etc go here. +extern crate alloc; + use crate::currency_to_vote::CurrencyToVote; +use alloc::{collections::btree_map::BTreeMap, vec, vec::Vec}; use codec::{Decode, Encode, FullCodec, HasCompact, MaxEncodedLen}; +use core::ops::Sub; use scale_info::TypeInfo; use sp_runtime::{ traits::{AtLeast32BitUnsigned, Zero}, DispatchError, DispatchResult, RuntimeDebug, Saturating, }; -use sp_std::{collections::btree_map::BTreeMap, ops::Sub, vec, vec::Vec}; pub mod offence; @@ -172,7 +175,7 @@ pub trait StakingInterface { + Saturating; /// AccountId type used by the staking system. - type AccountId: Clone + sp_std::fmt::Debug; + type AccountId: Clone + core::fmt::Debug; /// Means of converting Currency to VoteWeight. type CurrencyToVote: CurrencyToVote; diff --git a/substrate/primitives/staking/src/offence.rs b/substrate/primitives/staking/src/offence.rs index 8013166374e..64aa4692eb5 100644 --- a/substrate/primitives/staking/src/offence.rs +++ b/substrate/primitives/staking/src/offence.rs @@ -18,10 +18,10 @@ //! Common traits and types that are useful for describing offences for usage in environments //! that use staking. +use alloc::vec::Vec; use codec::{Decode, Encode}; use sp_core::Get; use sp_runtime::{transaction_validity::TransactionValidityError, DispatchError, Perbill}; -use sp_std::vec::Vec; use crate::SessionIndex; diff --git a/substrate/primitives/state-machine/Cargo.toml b/substrate/primitives/state-machine/Cargo.toml index 09994f1ae91..aaedb500b59 100644 --- a/substrate/primitives/state-machine/Cargo.toml +++ b/substrate/primitives/state-machine/Cargo.toml @@ -28,7 +28,6 @@ tracing = { version = "0.1.29", optional = true } sp-core = { path = "../core", default-features = false } sp-externalities = { path = "../externalities", default-features = false } sp-panic-handler = { path = "../panic-handler", optional = true } -sp-std = { path = "../std", default-features = false } sp-trie = { path = "../trie", default-features = false } trie-db = { version = "0.28.0", default-features = false } @@ -51,7 +50,6 @@ std = [ "sp-externalities/std", "sp-panic-handler", "sp-runtime/std", - "sp-std/std", "sp-trie/std", "thiserror", "tracing", diff --git a/substrate/primitives/state-machine/src/backend.rs b/substrate/primitives/state-machine/src/backend.rs index ea9cd442d70..90be55d58a4 100644 --- a/substrate/primitives/state-machine/src/backend.rs +++ b/substrate/primitives/state-machine/src/backend.rs @@ -23,13 +23,13 @@ use crate::{ trie_backend_essence::TrieBackendStorage, ChildStorageCollection, StorageCollection, StorageKey, StorageValue, UsageInfo, }; +use alloc::vec::Vec; use codec::Encode; use core::marker::PhantomData; use hash_db::Hasher; use sp_core::storage::{ChildInfo, StateVersion, TrackedStorageKey}; #[cfg(feature = "std")] use sp_core::traits::RuntimeCode; -use sp_std::vec::Vec; use sp_trie::{MerkleValue, PrefixedMemoryDB}; /// A struct containing arguments for iterating over the storage. @@ -179,7 +179,7 @@ pub type BackendTransaction = PrefixedMemoryDB; /// to it. /// /// The clone operation (if implemented) should be cheap. -pub trait Backend: sp_std::fmt::Debug { +pub trait Backend: core::fmt::Debug { /// An error type when fetching data is not possible. type Error: super::Error; diff --git a/substrate/primitives/state-machine/src/ext.rs b/substrate/primitives/state-machine/src/ext.rs index 11df46f2a4a..73110f55cba 100644 --- a/substrate/primitives/state-machine/src/ext.rs +++ b/substrate/primitives/state-machine/src/ext.rs @@ -32,12 +32,10 @@ use sp_core::storage::{ use sp_externalities::{Extension, ExtensionStore, Externalities, MultiRemovalResults}; use crate::{log_error, trace, warn}; -use sp_std::{ +use alloc::{boxed::Box, vec, vec::Vec}; +use core::{ any::{Any, TypeId}, - boxed::Box, cmp::Ordering, - vec, - vec::Vec, }; #[cfg(feature = "std")] use std::error; @@ -739,7 +737,7 @@ impl<'a> StorageAppend<'a> { pub fn append(&mut self, value: Vec) { let value = vec![EncodeOpaqueValue(value)]; - let item = sp_std::mem::take(self.0); + let item = core::mem::take(self.0); *self.0 = match Vec::::append_or_new(item, &value) { Ok(item) => item, diff --git a/substrate/primitives/state-machine/src/lib.rs b/substrate/primitives/state-machine/src/lib.rs index 5909a30a814..200cebe68de 100644 --- a/substrate/primitives/state-machine/src/lib.rs +++ b/substrate/primitives/state-machine/src/lib.rs @@ -20,6 +20,8 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + pub mod backend; #[cfg(feature = "std")] mod basic; @@ -118,8 +120,8 @@ pub type DefaultError = String; pub struct DefaultError; #[cfg(not(feature = "std"))] -impl sp_std::fmt::Display for DefaultError { - fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { +impl core::fmt::Display for DefaultError { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { write!(f, "DefaultError") } } diff --git a/substrate/primitives/state-machine/src/overlayed_changes/changeset.rs b/substrate/primitives/state-machine/src/overlayed_changes/changeset.rs index 59589dbbb37..a25a5b81052 100644 --- a/substrate/primitives/state-machine/src/overlayed_changes/changeset.rs +++ b/substrate/primitives/state-machine/src/overlayed_changes/changeset.rs @@ -20,16 +20,14 @@ use super::{Extrinsics, StorageKey, StorageValue}; #[cfg(not(feature = "std"))] -use sp_std::collections::btree_set::BTreeSet as Set; +use alloc::collections::btree_set::BTreeSet as Set; #[cfg(feature = "std")] use std::collections::HashSet as Set; use crate::warn; +use alloc::collections::{btree_map::BTreeMap, btree_set::BTreeSet}; +use core::hash::Hash; use smallvec::SmallVec; -use sp_std::{ - collections::{btree_map::BTreeMap, btree_set::BTreeSet}, - hash::Hash, -}; const PROOF_OVERLAY_NON_EMPTY: &str = "\ An OverlayValue is always created with at least one transaction and dropped as soon @@ -225,7 +223,7 @@ impl OverlayedMap { /// This changeset might be created when there are already open transactions. /// We need to catch up here so that the child is at the same transaction depth. pub fn spawn_child(&self) -> Self { - use sp_std::iter::repeat; + use core::iter::repeat; Self { changes: Default::default(), dirty_keys: repeat(Set::new()).take(self.transaction_depth()).collect(), @@ -242,7 +240,7 @@ impl OverlayedMap { /// Get an optional reference to the value stored for the specified key. pub fn get(&self, key: &Q) -> Option<&OverlayedEntry> where - K: sp_std::borrow::Borrow, + K: core::borrow::Borrow, Q: Ord + ?Sized, { self.changes.get(key) @@ -448,7 +446,7 @@ impl OverlayedChangeSet { /// Get the iterator over all changes that follow the supplied `key`. pub fn changes_after(&self, key: &[u8]) -> impl Iterator { - use sp_std::ops::Bound; + use core::ops::Bound; let range = (Bound::Excluded(key), Bound::Unbounded); self.changes.range::<[u8], _>(range).map(|(k, v)| (k.as_slice(), v)) } diff --git a/substrate/primitives/state-machine/src/overlayed_changes/mod.rs b/substrate/primitives/state-machine/src/overlayed_changes/mod.rs index 626cf6c3caf..039631e4a63 100644 --- a/substrate/primitives/state-machine/src/overlayed_changes/mod.rs +++ b/substrate/primitives/state-machine/src/overlayed_changes/mod.rs @@ -22,6 +22,7 @@ mod offchain; use self::changeset::OverlayedChangeSet; use crate::{backend::Backend, stats::StateMachineStats, BackendTransaction, DefaultError}; +use alloc::{collections::btree_set::BTreeSet, vec::Vec}; use codec::{Decode, Encode}; use hash_db::Hasher; pub use offchain::OffchainOverlayedChanges; @@ -31,12 +32,13 @@ use sp_core::{ }; #[cfg(feature = "std")] use sp_externalities::{Extension, Extensions}; -#[cfg(not(feature = "std"))] -use sp_std::collections::btree_map::BTreeMap as Map; -use sp_std::{collections::btree_set::BTreeSet, vec::Vec}; use sp_trie::{empty_child_trie_root, LayoutV1}; + +#[cfg(not(feature = "std"))] +use alloc::collections::btree_map::BTreeMap as Map; #[cfg(feature = "std")] use std::collections::{hash_map::Entry as MapEntry, HashMap as Map}; + #[cfg(feature = "std")] use std::{ any::{Any, TypeId}, @@ -136,7 +138,7 @@ impl Clone for OverlayedChanges { } } -impl sp_std::fmt::Debug for OverlayedChanges { +impl core::fmt::Debug for OverlayedChanges { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("OverlayedChanges") .field("top", &self.top) @@ -259,7 +261,7 @@ impl Clone for StorageTransactionCache { } } -impl sp_std::fmt::Debug for StorageTransactionCache { +impl core::fmt::Debug for StorageTransactionCache { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { let mut debug = f.debug_struct("StorageTransactionCache"); @@ -572,7 +574,7 @@ impl OverlayedChanges { }, }; - use sp_std::mem::take; + use core::mem::take; let main_storage_changes = take(&mut self.top).drain_commited(); let child_storage_changes = take(&mut self.children) .into_iter() @@ -777,7 +779,7 @@ where K: Ord, F: FnMut(&K, &mut V) -> bool, { - let old = sp_std::mem::replace(map, Map::default()); + let old = core::mem::replace(map, Map::default()); for (k, mut v) in old.into_iter() { if f(&k, &mut v) { map.insert(k, v); diff --git a/substrate/primitives/state-machine/src/overlayed_changes/offchain.rs b/substrate/primitives/state-machine/src/overlayed_changes/offchain.rs index 66e7ab5864c..1e6965e8747 100644 --- a/substrate/primitives/state-machine/src/overlayed_changes/offchain.rs +++ b/substrate/primitives/state-machine/src/overlayed_changes/offchain.rs @@ -18,8 +18,8 @@ //! Overlayed changes for offchain indexing. use super::changeset::OverlayedMap; +use alloc::vec::Vec; use sp_core::offchain::OffchainOverlayedChange; -use sp_std::prelude::Vec; /// In-memory storage for offchain workers recoding changes for the actual offchain storage /// implementation. @@ -48,7 +48,7 @@ impl OffchainOverlayedChanges { /// Drain all elements of changeset. pub fn drain(&mut self) -> impl Iterator { - sp_std::mem::take(self).into_iter() + core::mem::take(self).into_iter() } /// Remove a key and its associated value from the offchain database. diff --git a/substrate/primitives/state-machine/src/trie_backend.rs b/substrate/primitives/state-machine/src/trie_backend.rs index 7496463e642..f91ce5d2e52 100644 --- a/substrate/primitives/state-machine/src/trie_backend.rs +++ b/substrate/primitives/state-machine/src/trie_backend.rs @@ -297,7 +297,7 @@ struct CachedIter where H: Hasher, { - last_key: sp_std::vec::Vec, + last_key: alloc::vec::Vec, iter: RawIter, } @@ -390,9 +390,9 @@ where } impl, H: Hasher, C: TrieCacheProvider, R: TrieRecorderProvider> - sp_std::fmt::Debug for TrieBackend + core::fmt::Debug for TrieBackend { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "TrieBackend") } } diff --git a/substrate/primitives/state-machine/src/trie_backend_essence.rs b/substrate/primitives/state-machine/src/trie_backend_essence.rs index 3f789111dee..1824a77c370 100644 --- a/substrate/primitives/state-machine/src/trie_backend_essence.rs +++ b/substrate/primitives/state-machine/src/trie_backend_essence.rs @@ -23,14 +23,15 @@ use crate::{ trie_backend::TrieCacheProvider, warn, StorageKey, StorageValue, }; +#[cfg(feature = "std")] +use alloc::sync::Arc; +use alloc::{boxed::Box, vec::Vec}; use codec::Codec; +use core::marker::PhantomData; use hash_db::{self, AsHashDB, HashDB, HashDBRef, Hasher, Prefix}; #[cfg(feature = "std")] use parking_lot::RwLock; use sp_core::storage::{ChildInfo, ChildType, StateVersion}; -#[cfg(feature = "std")] -use sp_std::sync::Arc; -use sp_std::{boxed::Box, marker::PhantomData, vec::Vec}; use sp_trie::{ child_delta_trie_root, delta_trie_root, empty_child_trie_root, read_child_trie_first_descedant_value, read_child_trie_hash, read_child_trie_value, @@ -55,7 +56,7 @@ macro_rules! format { }; } -type Result = sp_std::result::Result; +type Result = core::result::Result; /// Patricia trie-based storage trait. pub trait Storage: Send + Sync { diff --git a/substrate/primitives/statement-store/Cargo.toml b/substrate/primitives/statement-store/Cargo.toml index 652ab3ef13a..000fcd98704 100644 --- a/substrate/primitives/statement-store/Cargo.toml +++ b/substrate/primitives/statement-store/Cargo.toml @@ -21,7 +21,6 @@ scale-info = { version = "2.10.0", default-features = false, features = ["derive sp-core = { path = "../core", default-features = false } sp-crypto-hashing = { path = "../crypto/hashing", default-features = false } sp-runtime = { path = "../runtime", default-features = false } -sp-std = { path = "../std", default-features = false } sp-api = { path = "../api", default-features = false } sp-application-crypto = { path = "../application-crypto", default-features = false } sp-runtime-interface = { path = "../runtime-interface", default-features = false } @@ -57,7 +56,6 @@ std = [ "sp-externalities/std", "sp-runtime-interface/std", "sp-runtime/std", - "sp-std/std", "thiserror", "x25519-dalek", ] diff --git a/substrate/primitives/statement-store/src/lib.rs b/substrate/primitives/statement-store/src/lib.rs index 04175f6d616..bfcd0d1a52a 100644 --- a/substrate/primitives/statement-store/src/lib.rs +++ b/substrate/primitives/statement-store/src/lib.rs @@ -20,13 +20,15 @@ //! A crate which contains statement-store primitives. +extern crate alloc; + +use alloc::vec::Vec; use codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_application_crypto::RuntimeAppPublic; #[cfg(feature = "std")] use sp_core::Pair; use sp_runtime_interface::pass_by::PassByCodec; -use sp_std::vec::Vec; /// Statement topic. pub type Topic = [u8; 32]; diff --git a/substrate/primitives/statement-store/src/runtime_api.rs b/substrate/primitives/statement-store/src/runtime_api.rs index 13f88bc977e..4d25576c801 100644 --- a/substrate/primitives/statement-store/src/runtime_api.rs +++ b/substrate/primitives/statement-store/src/runtime_api.rs @@ -18,11 +18,11 @@ //! Runtime support for the statement store. use crate::{Hash, Statement, Topic}; +use alloc::vec::Vec; use codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_runtime::RuntimeDebug; use sp_runtime_interface::{pass_by::PassByEnum, runtime_interface}; -use sp_std::vec::Vec; #[cfg(feature = "std")] use sp_externalities::ExternalitiesExt; diff --git a/substrate/primitives/storage/Cargo.toml b/substrate/primitives/storage/Cargo.toml index d3ade87ea47..acedc8d0004 100644 --- a/substrate/primitives/storage/Cargo.toml +++ b/substrate/primitives/storage/Cargo.toml @@ -22,7 +22,6 @@ impl-serde = { version = "0.4.0", optional = true, default-features = false } ref-cast = "1.0.0" serde = { features = ["alloc", "derive"], optional = true, workspace = true } sp-debug-derive = { path = "../debug-derive", default-features = false } -sp-std = { path = "../std", default-features = false } [features] default = ["std"] @@ -31,7 +30,6 @@ std = [ "impl-serde/std", "serde/std", "sp-debug-derive/std", - "sp-std/std", ] # Serde support without relying on std features. diff --git a/substrate/primitives/storage/src/lib.rs b/substrate/primitives/storage/src/lib.rs index 79c090cabf8..b55cc8f2174 100644 --- a/substrate/primitives/storage/src/lib.rs +++ b/substrate/primitives/storage/src/lib.rs @@ -19,18 +19,19 @@ #![cfg_attr(not(feature = "std"), no_std)] -use core::fmt::Display; +extern crate alloc; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use sp_debug_derive::RuntimeDebug; +use alloc::vec::Vec; use codec::{Decode, Encode}; -use ref_cast::RefCast; -use sp_std::{ +use core::{ + fmt::Display, ops::{Deref, DerefMut}, - vec::Vec, }; +use ref_cast::RefCast; /// Storage key. #[derive(PartialEq, Eq, RuntimeDebug)] @@ -49,9 +50,7 @@ impl AsRef<[u8]> for StorageKey { } /// Storage key with read/write tracking information. -#[derive( - PartialEq, Eq, Ord, PartialOrd, sp_std::hash::Hash, RuntimeDebug, Clone, Encode, Decode, -)] +#[derive(PartialEq, Eq, Ord, PartialOrd, core::hash::Hash, RuntimeDebug, Clone, Encode, Decode)] pub struct TrackedStorageKey { pub key: Vec, pub reads: u32, @@ -441,7 +440,7 @@ impl From for u8 { impl TryFrom for StateVersion { type Error = (); - fn try_from(val: u8) -> sp_std::result::Result { + fn try_from(val: u8) -> core::result::Result { match val { 0 => Ok(StateVersion::V0), 1 => Ok(StateVersion::V1), diff --git a/substrate/primitives/test-primitives/Cargo.toml b/substrate/primitives/test-primitives/Cargo.toml index f310216dd58..1b51c5f5919 100644 --- a/substrate/primitives/test-primitives/Cargo.toml +++ b/substrate/primitives/test-primitives/Cargo.toml @@ -21,7 +21,6 @@ serde = { features = ["derive"], optional = true, workspace = true } sp-application-crypto = { path = "../application-crypto", default-features = false } sp-core = { path = "../core", default-features = false } sp-runtime = { path = "../runtime", default-features = false } -sp-std = { path = "../std", default-features = false } [features] default = ["std"] @@ -32,7 +31,6 @@ std = [ "sp-application-crypto/std", "sp-core/std", "sp-runtime/std", - "sp-std/std", ] # Serde support without relying on std features. diff --git a/substrate/primitives/test-primitives/src/lib.rs b/substrate/primitives/test-primitives/src/lib.rs index 82bdb6967b8..1e3b912eaf4 100644 --- a/substrate/primitives/test-primitives/src/lib.rs +++ b/substrate/primitives/test-primitives/src/lib.rs @@ -19,14 +19,16 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + use codec::{Decode, Encode}; pub use sp_application_crypto; use sp_application_crypto::sr25519; +use alloc::vec::Vec; pub use sp_core::{hash::H256, RuntimeDebug}; use sp_runtime::traits::{BlakeTwo256, Extrinsic as ExtrinsicT, Verify}; -use sp_std::vec::Vec; /// Extrinsic for test-runtime. #[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, scale_info::TypeInfo)] diff --git a/substrate/primitives/timestamp/Cargo.toml b/substrate/primitives/timestamp/Cargo.toml index 9e2b802bfb1..11afb175590 100644 --- a/substrate/primitives/timestamp/Cargo.toml +++ b/substrate/primitives/timestamp/Cargo.toml @@ -21,7 +21,6 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = thiserror = { optional = true, workspace = true } sp-inherents = { path = "../inherents", default-features = false } sp-runtime = { path = "../runtime", default-features = false } -sp-std = { path = "../std", default-features = false } [features] default = ["std"] @@ -30,6 +29,5 @@ std = [ "codec/std", "sp-inherents/std", "sp-runtime/std", - "sp-std/std", "thiserror", ] diff --git a/substrate/primitives/tracing/Cargo.toml b/substrate/primitives/tracing/Cargo.toml index 58b1e48c462..368f8c096dd 100644 --- a/substrate/primitives/tracing/Cargo.toml +++ b/substrate/primitives/tracing/Cargo.toml @@ -21,7 +21,6 @@ features = ["with-tracing"] targets = ["wasm32-unknown-unknown", "x86_64-unknown-linux-gnu"] [dependencies] -sp-std = { path = "../std", default-features = false } codec = { version = "3.6.1", package = "parity-scale-codec", default-features = false, features = [ "derive", ] } @@ -36,7 +35,6 @@ default = ["std"] with-tracing = ["codec/derive", "codec/full"] std = [ "codec/std", - "sp-std/std", "tracing-core/std", "tracing-subscriber", "tracing/std", diff --git a/substrate/primitives/tracing/src/lib.rs b/substrate/primitives/tracing/src/lib.rs index cc651836846..b8b99230db5 100644 --- a/substrate/primitives/tracing/src/lib.rs +++ b/substrate/primitives/tracing/src/lib.rs @@ -37,6 +37,8 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + #[cfg(feature = "std")] use tracing; pub use tracing::{ diff --git a/substrate/primitives/tracing/src/types.rs b/substrate/primitives/tracing/src/types.rs index 003787f310d..3692a81e03c 100644 --- a/substrate/primitives/tracing/src/types.rs +++ b/substrate/primitives/tracing/src/types.rs @@ -15,11 +15,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +use alloc::{vec, vec::Vec}; use codec::{Decode, Encode}; /// Types for wasm based tracing. Loosly inspired by `tracing-core` but /// optimised for the specific use case. use core::{fmt::Debug, format_args}; -use sp_std::{vec, vec::Vec, Writer}; /// The Tracing Level – the user can filter by this #[derive(Clone, Encode, Decode, Debug)] @@ -132,9 +132,9 @@ impl From for WasmValue { impl From> for WasmValue { fn from(inp: core::fmt::Arguments<'_>) -> WasmValue { - let mut buf = Writer::default(); + let mut buf = alloc::string::String::default(); core::fmt::write(&mut buf, inp).expect("Writing of arguments doesn't fail"); - WasmValue::Formatted(buf.into_inner()) + WasmValue::Formatted(buf.into_bytes()) } } diff --git a/substrate/primitives/transaction-pool/src/lib.rs b/substrate/primitives/transaction-pool/src/lib.rs index 431f429e29f..2ce735491b2 100644 --- a/substrate/primitives/transaction-pool/src/lib.rs +++ b/substrate/primitives/transaction-pool/src/lib.rs @@ -20,4 +20,6 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + pub mod runtime_api; diff --git a/substrate/primitives/transaction-storage-proof/Cargo.toml b/substrate/primitives/transaction-storage-proof/Cargo.toml index e2fb54dafdf..fbd0a4752fc 100644 --- a/substrate/primitives/transaction-storage-proof/Cargo.toml +++ b/substrate/primitives/transaction-storage-proof/Cargo.toml @@ -22,7 +22,6 @@ scale-info = { version = "2.10.0", default-features = false, features = ["derive sp-core = { path = "../core", optional = true } sp-inherents = { path = "../inherents", default-features = false } sp-runtime = { path = "../runtime", default-features = false } -sp-std = { path = "../std", default-features = false } sp-trie = { path = "../trie", optional = true } [features] @@ -34,6 +33,5 @@ std = [ "sp-core/std", "sp-inherents/std", "sp-runtime/std", - "sp-std/std", "sp-trie/std", ] diff --git a/substrate/primitives/transaction-storage-proof/src/lib.rs b/substrate/primitives/transaction-storage-proof/src/lib.rs index 9d540ae68d1..352f2aec26e 100644 --- a/substrate/primitives/transaction-storage-proof/src/lib.rs +++ b/substrate/primitives/transaction-storage-proof/src/lib.rs @@ -20,8 +20,11 @@ #![cfg_attr(not(feature = "std"), no_std)] -use sp_std::{prelude::*, result::Result}; +extern crate alloc; +use core::result::Result; + +use alloc::vec::Vec; use codec::{Decode, Encode}; use sp_inherents::{InherentData, InherentIdentifier, IsFatalError}; use sp_runtime::traits::{Block as BlockT, NumberFor}; diff --git a/substrate/primitives/trie/Cargo.toml b/substrate/primitives/trie/Cargo.toml index 16d3ca19a17..dd7ab080e5f 100644 --- a/substrate/primitives/trie/Cargo.toml +++ b/substrate/primitives/trie/Cargo.toml @@ -35,7 +35,6 @@ tracing = { version = "0.1.29", optional = true } trie-db = { version = "0.28.0", default-features = false } trie-root = { version = "0.18.0", default-features = false } sp-core = { path = "../core", default-features = false } -sp-std = { path = "../std", default-features = false } sp-externalities = { path = "../externalities", default-features = false } schnellru = { version = "0.2.1", optional = true } @@ -62,7 +61,6 @@ std = [ "sp-core/std", "sp-externalities/std", "sp-runtime/std", - "sp-std/std", "thiserror", "tracing", "trie-db/std", diff --git a/substrate/primitives/trie/src/error.rs b/substrate/primitives/trie/src/error.rs index 17be556d348..e3986e50b08 100644 --- a/substrate/primitives/trie/src/error.rs +++ b/substrate/primitives/trie/src/error.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use sp_std::{boxed::Box, vec::Vec}; +use alloc::{boxed::Box, vec::Vec}; /// Error type used for trie related errors. #[derive(Debug, PartialEq, Eq, Clone)] diff --git a/substrate/primitives/trie/src/lib.rs b/substrate/primitives/trie/src/lib.rs index fd1320b3fbc..81b37a0c9a6 100644 --- a/substrate/primitives/trie/src/lib.rs +++ b/substrate/primitives/trie/src/lib.rs @@ -19,6 +19,8 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + #[cfg(feature = "std")] pub mod cache; mod error; @@ -33,6 +35,8 @@ mod trie_stream; #[cfg(feature = "std")] pub mod proof_size_extension; +use alloc::{borrow::Borrow, boxed::Box, vec, vec::Vec}; +use core::marker::PhantomData; /// Our `NodeCodec`-specific error. pub use error::Error; /// Various re-exports from the `hash-db` crate. @@ -42,7 +46,6 @@ use hash_db::{Hasher, Prefix}; pub use memory_db::{prefixed_key, HashKey, KeyFunction, PrefixedKey}; /// The Substrate format implementation of `NodeCodec`. pub use node_codec::NodeCodec; -use sp_std::{borrow::Borrow, boxed::Box, marker::PhantomData, vec::Vec}; pub use storage_proof::{CompactProof, StorageProof}; /// Trie codec reexport, mainly child trie support /// for trie compact proof. @@ -500,7 +503,7 @@ pub struct KeySpacedDBMut<'a, DB: ?Sized, H>(&'a mut DB, &'a [u8], PhantomData (Vec, Option) { - let mut result = sp_std::vec![0; ks.len() + prefix.0.len()]; + let mut result = vec![0; ks.len() + prefix.0.len()]; result[..ks.len()].copy_from_slice(ks); result[ks.len()..].copy_from_slice(prefix.0); (result, prefix.1) diff --git a/substrate/primitives/trie/src/node_codec.rs b/substrate/primitives/trie/src/node_codec.rs index 46acde77c05..78896988ec4 100644 --- a/substrate/primitives/trie/src/node_codec.rs +++ b/substrate/primitives/trie/src/node_codec.rs @@ -19,9 +19,10 @@ use super::node_header::{NodeHeader, NodeKind}; use crate::{error::Error, trie_constants}; +use alloc::{borrow::Borrow, vec::Vec}; use codec::{Compact, Decode, Encode, Input}; +use core::{marker::PhantomData, ops::Range}; use hash_db::Hasher; -use sp_std::{borrow::Borrow, marker::PhantomData, ops::Range, vec::Vec}; use trie_db::{ nibble_ops, node::{NibbleSlicePlan, NodeHandlePlan, NodePlan, Value, ValuePlan}, @@ -30,7 +31,7 @@ use trie_db::{ /// Helper struct for trie node decoder. This implements `codec::Input` on a byte slice, while /// tracking the absolute position. This is similar to `std::io::Cursor` but does not implement -/// `Read` and `io` is not in `sp-std`. +/// `Read` and `io` are not in `core` or `alloc`. struct ByteSliceInput<'a> { data: &'a [u8], offset: usize, diff --git a/substrate/primitives/trie/src/storage_proof.rs b/substrate/primitives/trie/src/storage_proof.rs index 6c871d73b04..e46c49be19c 100644 --- a/substrate/primitives/trie/src/storage_proof.rs +++ b/substrate/primitives/trie/src/storage_proof.rs @@ -15,14 +15,12 @@ // See the License for the specific language governing permissions and // limitations under the License. +use alloc::{collections::btree_set::BTreeSet, vec::Vec}; use codec::{Decode, Encode}; +use core::iter::{DoubleEndedIterator, IntoIterator}; use hash_db::{HashDB, Hasher}; use scale_info::TypeInfo; -use sp_std::{ - collections::btree_set::BTreeSet, - iter::{DoubleEndedIterator, IntoIterator}, - vec::Vec, -}; + // Note that `LayoutV1` usage here (proof compaction) is compatible // with `LayoutV0`. use crate::LayoutV1 as Layout; diff --git a/substrate/primitives/trie/src/trie_codec.rs b/substrate/primitives/trie/src/trie_codec.rs index f29e009c476..65b4f505359 100644 --- a/substrate/primitives/trie/src/trie_codec.rs +++ b/substrate/primitives/trie/src/trie_codec.rs @@ -21,7 +21,7 @@ //! it to substrate specific layout and child trie system. use crate::{CompactProof, HashDBT, TrieConfiguration, TrieHash, EMPTY_PREFIX}; -use sp_std::{boxed::Box, vec::Vec}; +use alloc::{boxed::Box, vec::Vec}; use trie_db::{CError, Trie}; /// Error for trie node decoding. diff --git a/substrate/primitives/trie/src/trie_stream.rs b/substrate/primitives/trie/src/trie_stream.rs index f57b80f978f..459b5895f20 100644 --- a/substrate/primitives/trie/src/trie_stream.rs +++ b/substrate/primitives/trie/src/trie_stream.rs @@ -21,9 +21,9 @@ use crate::{ node_header::{size_and_prefix_iterator, NodeKind}, trie_constants, }; +use alloc::vec::Vec; use codec::{Compact, Encode}; use hash_db::Hasher; -use sp_std::vec::Vec; use trie_root; /// Codec-flavored TrieStream. diff --git a/substrate/primitives/wasm-interface/Cargo.toml b/substrate/primitives/wasm-interface/Cargo.toml index f7d1038903e..6c051b71c8e 100644 --- a/substrate/primitives/wasm-interface/Cargo.toml +++ b/substrate/primitives/wasm-interface/Cargo.toml @@ -22,9 +22,8 @@ impl-trait-for-tuples = "0.2.2" log = { optional = true, workspace = true, default-features = true } wasmtime = { version = "8.0.1", default-features = false, optional = true } anyhow = { version = "1.0.68", optional = true } -sp-std = { path = "../std", default-features = false } [features] default = ["std"] -std = ["codec/std", "log/std", "sp-std/std", "wasmtime"] +std = ["codec/std", "log/std", "wasmtime"] wasmtime = ["anyhow", "dep:wasmtime"] diff --git a/substrate/primitives/wasm-interface/src/lib.rs b/substrate/primitives/wasm-interface/src/lib.rs index 9d5d2bb358d..4fc78ca1553 100644 --- a/substrate/primitives/wasm-interface/src/lib.rs +++ b/substrate/primitives/wasm-interface/src/lib.rs @@ -19,7 +19,10 @@ #![cfg_attr(not(feature = "std"), no_std)] -use sp_std::{borrow::Cow, iter::Iterator, marker::PhantomData, mem, result, vec, vec::Vec}; +extern crate alloc; + +use alloc::{borrow::Cow, vec, vec::Vec}; +use core::{iter::Iterator, marker::PhantomData, mem, result}; #[cfg(not(all(feature = "std", feature = "wasmtime")))] #[macro_export] @@ -76,7 +79,7 @@ impl From for u8 { impl TryFrom for ValueType { type Error = (); - fn try_from(val: u8) -> sp_std::result::Result { + fn try_from(val: u8) -> core::result::Result { match val { 0 => Ok(Self::I32), 1 => Ok(Self::I64), diff --git a/substrate/primitives/weights/Cargo.toml b/substrate/primitives/weights/Cargo.toml index a7d61de001b..d3118defb58 100644 --- a/substrate/primitives/weights/Cargo.toml +++ b/substrate/primitives/weights/Cargo.toml @@ -23,7 +23,6 @@ serde = { optional = true, features = ["alloc", "derive"], workspace = true } smallvec = "1.11.0" sp-arithmetic = { path = "../arithmetic", default-features = false } sp-debug-derive = { path = "../debug-derive", default-features = false } -sp-std = { path = "../std", default-features = false } schemars = { version = "0.8.3", default-features = false, optional = true } [features] @@ -35,7 +34,6 @@ std = [ "serde/std", "sp-arithmetic/std", "sp-debug-derive/std", - "sp-std/std", ] # By default some types have documentation, `full-metadata-docs` allows to add documentation to # more types in the metadata. diff --git a/substrate/test-utils/runtime/Cargo.toml b/substrate/test-utils/runtime/Cargo.toml index b6e6346e801..f49503da8ca 100644 --- a/substrate/test-utils/runtime/Cargo.toml +++ b/substrate/test-utils/runtime/Cargo.toml @@ -28,7 +28,6 @@ sp-keyring = { path = "../../primitives/keyring", default-features = false } sp-offchain = { path = "../../primitives/offchain", default-features = false } sp-core = { path = "../../primitives/core", default-features = false, features = ["serde"] } sp-crypto-hashing = { path = "../../primitives/crypto/hashing", default-features = false } -sp-std = { path = "../../primitives/std", default-features = false } sp-io = { path = "../../primitives/io", default-features = false } frame-support = { path = "../../frame/support", default-features = false } sp-version = { path = "../../primitives/version", default-features = false } @@ -104,7 +103,6 @@ std = [ "sp-runtime/std", "sp-session/std", "sp-state-machine/std", - "sp-std/std", "sp-tracing/std", "sp-transaction-pool/std", "sp-trie/std", diff --git a/substrate/test-utils/runtime/src/extrinsic.rs b/substrate/test-utils/runtime/src/extrinsic.rs index 05ffb7db5d5..e355e5d099a 100644 --- a/substrate/test-utils/runtime/src/extrinsic.rs +++ b/substrate/test-utils/runtime/src/extrinsic.rs @@ -26,7 +26,6 @@ use frame_system::{CheckNonce, CheckWeight}; use sp_core::crypto::Pair as TraitPair; use sp_keyring::AccountKeyring; use sp_runtime::{transaction_validity::TransactionPriority, Perbill}; -use sp_std::prelude::*; /// Transfer used in test substrate pallet. Extrinsic is created and signed using this data. #[derive(Clone)] diff --git a/substrate/test-utils/runtime/src/lib.rs b/substrate/test-utils/runtime/src/lib.rs index 9270978cd12..7148d2b2fc0 100644 --- a/substrate/test-utils/runtime/src/lib.rs +++ b/substrate/test-utils/runtime/src/lib.rs @@ -19,6 +19,8 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + #[cfg(feature = "std")] pub mod extrinsic; #[cfg(feature = "std")] @@ -42,9 +44,10 @@ use frame_system::{ CheckNonce, CheckWeight, }; use scale_info::TypeInfo; -use sp_std::prelude::*; + +use alloc::boxed::Box; #[cfg(not(feature = "std"))] -use sp_std::vec; +use alloc::{vec, vec::Vec}; use sp_application_crypto::{ecdsa, ed25519, sr25519, RuntimeAppPublic}; use sp_core::{OpaqueMetadata, RuntimeDebug}; @@ -265,7 +268,7 @@ impl sp_runtime::traits::SignedExtension for CheckSubstrateCall { fn additional_signed( &self, - ) -> sp_std::result::Result { + ) -> core::result::Result { Ok(()) } @@ -440,7 +443,7 @@ fn code_using_trie() -> u64 { .to_vec(); let mut mdb = PrefixedMemoryDB::default(); - let mut root = sp_std::default::Default::default(); + let mut root = core::default::Default::default(); { let mut t = TrieDBMutBuilderV1::::new(&mut mdb, &mut root).build(); for (key, value) in &pairs { @@ -494,7 +497,7 @@ impl_runtime_apis! { fn metadata_at_version(_version: u32) -> Option { unimplemented!() } - fn metadata_versions() -> sp_std::vec::Vec { + fn metadata_versions() -> alloc::vec::Vec { unimplemented!() } } diff --git a/substrate/test-utils/runtime/src/substrate_test_pallet.rs b/substrate/test-utils/runtime/src/substrate_test_pallet.rs index ed1ad990472..8375a68c8ff 100644 --- a/substrate/test-utils/runtime/src/substrate_test_pallet.rs +++ b/substrate/test-utils/runtime/src/substrate_test_pallet.rs @@ -21,6 +21,7 @@ //! functioning runtime. Some calls are allowed to be submitted as unsigned extrinsics, however most //! of them requires signing. Refer to `pallet::Call` for further details. +use alloc::{vec, vec::Vec}; use frame_support::{pallet_prelude::*, storage}; use sp_core::sr25519::Public; use sp_runtime::{ @@ -29,7 +30,6 @@ use sp_runtime::{ InvalidTransaction, TransactionSource, TransactionValidity, ValidTransaction, }, }; -use sp_std::prelude::*; pub use self::pallet::*; @@ -59,7 +59,7 @@ pub mod pallet { pub struct GenesisConfig { pub authorities: Vec, #[serde(skip)] - pub _config: sp_std::marker::PhantomData, + pub _config: core::marker::PhantomData, } #[pallet::genesis_build] -- GitLab From 816c072abd99947e466e611cd96fa0db918f1854 Mon Sep 17 00:00:00 2001 From: K Gunjan Date: Mon, 18 Mar 2024 15:57:48 +0530 Subject: [PATCH 051/187] Pallet AURA: remove pallet::getter macro and write the corresponding code (#3350) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed the `pallet::getter` macro call from storage type definitions and added the corresponding implementations directly. fixes #3330 polkadot address: 14JzTPPUd8x8phKi8qLxHgNTnTMg6DUukCLXoWprejkaHXPz --------- Co-authored-by: Bastian Köcher --- cumulus/pallets/aura-ext/src/lib.rs | 6 ++-- .../assets/asset-hub-rococo/src/lib.rs | 2 +- .../assets/asset-hub-westend/src/lib.rs | 2 +- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 2 +- .../bridge-hubs/bridge-hub-westend/src/lib.rs | 2 +- .../collectives-westend/src/lib.rs | 2 +- .../contracts/contracts-rococo/src/lib.rs | 2 +- .../coretime/coretime-rococo/src/lib.rs | 2 +- .../coretime/coretime-westend/src/lib.rs | 2 +- .../glutton/glutton-westend/src/lib.rs | 2 +- .../runtimes/people/people-rococo/src/lib.rs | 2 +- .../runtimes/people/people-westend/src/lib.rs | 2 +- .../runtimes/starters/seedling/src/lib.rs | 2 +- .../runtimes/starters/shell/src/lib.rs | 2 +- .../runtimes/testing/penpal/src/lib.rs | 2 +- .../testing/rococo-parachain/src/lib.rs | 2 +- prdoc/pr_3350.prdoc | 31 +++++++++++++++++++ substrate/frame/aura/src/lib.rs | 12 +++---- substrate/frame/aura/src/tests.rs | 7 +++-- templates/parachain/runtime/src/lib.rs | 4 ++- templates/solochain/runtime/src/lib.rs | 2 +- 21 files changed, 62 insertions(+), 30 deletions(-) create mode 100644 prdoc/pr_3350.prdoc diff --git a/cumulus/pallets/aura-ext/src/lib.rs b/cumulus/pallets/aura-ext/src/lib.rs index 31b571816a0..b71ae628954 100644 --- a/cumulus/pallets/aura-ext/src/lib.rs +++ b/cumulus/pallets/aura-ext/src/lib.rs @@ -63,14 +63,14 @@ pub mod pallet { impl Hooks> for Pallet { fn on_finalize(_: BlockNumberFor) { // Update to the latest AuRa authorities. - Authorities::::put(Aura::::authorities()); + Authorities::::put(pallet_aura::Authorities::::get()); } fn on_initialize(_: BlockNumberFor) -> Weight { // Fetch the authorities once to get them into the storage proof of the PoV. Authorities::::get(); - let new_slot = Aura::::current_slot(); + let new_slot = pallet_aura::CurrentSlot::::get(); let (new_slot, authored) = match SlotInfo::::get() { Some((slot, authored)) if slot == new_slot => (slot, authored + 1), @@ -116,7 +116,7 @@ pub mod pallet { #[pallet::genesis_build] impl BuildGenesisConfig for GenesisConfig { fn build(&self) { - let authorities = Aura::::authorities(); + let authorities = pallet_aura::Authorities::::get(); Authorities::::put(authorities); } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index e6b5e55bcd3..d3d8a495ea3 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -1067,7 +1067,7 @@ impl_runtime_apis! { } fn authorities() -> Vec { - Aura::authorities().into_inner() + pallet_aura::Authorities::::get().into_inner() } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 1ba108234c8..711fadff92a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -1098,7 +1098,7 @@ impl_runtime_apis! { } fn authorities() -> Vec { - Aura::authorities().into_inner() + pallet_aura::Authorities::::get().into_inner() } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 31069778e38..bbafcd3c7dd 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -790,7 +790,7 @@ impl_runtime_apis! { } fn authorities() -> Vec { - Aura::authorities().into_inner() + pallet_aura::Authorities::::get().into_inner() } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index d96c762fe19..11ab9aecc61 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -540,7 +540,7 @@ impl_runtime_apis! { } fn authorities() -> Vec { - Aura::authorities().into_inner() + pallet_aura::Authorities::::get().into_inner() } } diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index 5bf3519ac3d..55269283e08 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -777,7 +777,7 @@ impl_runtime_apis! { } fn authorities() -> Vec { - Aura::authorities().into_inner() + pallet_aura::Authorities::::get().into_inner() } } diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index f148ceadccb..17bb45f6b1b 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -440,7 +440,7 @@ impl_runtime_apis! { } fn authorities() -> Vec { - Aura::authorities().into_inner() + pallet_aura::Authorities::::get().into_inner() } } diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs index 6efbdde5899..26add2ee942 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs @@ -495,7 +495,7 @@ impl_runtime_apis! { } fn authorities() -> Vec { - Aura::authorities().into_inner() + pallet_aura::Authorities::::get().into_inner() } } diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs index 2bb179b5b05..76732c3fccc 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs @@ -486,7 +486,7 @@ impl_runtime_apis! { } fn authorities() -> Vec { - Aura::authorities().into_inner() + pallet_aura::Authorities::::get().into_inner() } } diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs index e7fdb53b253..fe18f48fbb3 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs @@ -353,7 +353,7 @@ impl_runtime_apis! { } fn authorities() -> Vec { - Aura::authorities().into_inner() + pallet_aura::Authorities::::get().into_inner() } } diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs index 98f76984dd4..2bb5641b4af 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs @@ -469,7 +469,7 @@ impl_runtime_apis! { } fn authorities() -> Vec { - Aura::authorities().into_inner() + pallet_aura::Authorities::::get().into_inner() } } diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs index 5adbdc1f38c..b81f7a9c969 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs @@ -469,7 +469,7 @@ impl_runtime_apis! { } fn authorities() -> Vec { - Aura::authorities().into_inner() + pallet_aura::Authorities::::get().into_inner() } } diff --git a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs index bf4768d8457..2f4f762408f 100644 --- a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs @@ -283,7 +283,7 @@ impl_runtime_apis! { } fn authorities() -> Vec { - Aura::authorities().into_inner() + pallet_aura::Authorities::::get().into_inner() } } diff --git a/cumulus/parachains/runtimes/starters/shell/src/lib.rs b/cumulus/parachains/runtimes/starters/shell/src/lib.rs index 51fdfac5b1c..0f4957fd802 100644 --- a/cumulus/parachains/runtimes/starters/shell/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/shell/src/lib.rs @@ -340,7 +340,7 @@ impl_runtime_apis! { } fn authorities() -> Vec { - Aura::authorities().into_inner() + pallet_aura::Authorities::::get().into_inner() } } diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index 3063601e030..1e6d485d148 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -688,7 +688,7 @@ impl_runtime_apis! { } fn authorities() -> Vec { - Aura::authorities().into_inner() + pallet_aura::Authorities::::get().into_inner() } } diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index 753d2d12065..a066cab1b6d 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -758,7 +758,7 @@ impl_runtime_apis! { } fn authorities() -> Vec { - Aura::authorities().into_inner() + pallet_aura::Authorities::::get().into_inner() } } diff --git a/prdoc/pr_3350.prdoc b/prdoc/pr_3350.prdoc new file mode 100644 index 00000000000..1171614d67f --- /dev/null +++ b/prdoc/pr_3350.prdoc @@ -0,0 +1,31 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: removed `pallet::getter` from Pallet AURA + +doc: + - audience: Runtime Dev + description: | + This PR removes all the declarations of macro `pallet::getter` in the Pallet AURA and replaces the use of storage getter functions authorities() & current_slot() with `StorageItem::get()` API across the crates as listed bellow. + The purpose is to discourage developers to use this macro, that is currently being removed and soon will be deprecated. + +crates: + - name: pallet-aura + - name: solochain-template-runtime + - name: cumulus-pallet-aura-ext + - name: parachain-template-runtime + - name: people-westend-runtime + - name: people-rococo-runtime + - name: bridge-hub-rococo-runtime + - name: bridge-hub-westend-runtime + - name: rococo-parachain-runtime + - name: penpal-runtime + - name: glutton-westend-runtime + - name: shell-runtime + - name: seedling-runtime + - name: collectives-westend-runtime + - name: asset-hub-rococo-runtime + - name: asset-hub-westend-runtime + - name: contracts-rococo-runtime + - name: coretime-westend-runtime + - name: coretime-rococo-runtime diff --git a/substrate/frame/aura/src/lib.rs b/substrate/frame/aura/src/lib.rs index 55653de97a8..997f51ba428 100644 --- a/substrate/frame/aura/src/lib.rs +++ b/substrate/frame/aura/src/lib.rs @@ -161,16 +161,14 @@ pub mod pallet { /// The current authority set. #[pallet::storage] - #[pallet::getter(fn authorities)] - pub(super) type Authorities = + pub type Authorities = StorageValue<_, BoundedVec, ValueQuery>; /// The current slot of this block. /// /// This will be set in `on_initialize`. #[pallet::storage] - #[pallet::getter(fn current_slot)] - pub(super) type CurrentSlot = StorageValue<_, Slot, ValueQuery>; + pub type CurrentSlot = StorageValue<_, Slot, ValueQuery>; #[pallet::genesis_config] #[derive(frame_support::DefaultNoBound)] @@ -318,7 +316,7 @@ impl OneSessionHandler for Pallet { // instant changes if changed { let next_authorities = validators.map(|(_, k)| k).collect::>(); - let last_authorities = Self::authorities(); + let last_authorities = Authorities::::get(); if last_authorities != next_authorities { if next_authorities.len() as u32 > T::MaxAuthorities::get() { log::warn!( @@ -374,7 +372,7 @@ impl> FindAuthor { let i = Inner::find_author(digests)?; - let validators = >::authorities(); + let validators = Authorities::::get(); validators.get(i as usize).cloned() } } @@ -384,7 +382,7 @@ pub type AuraAuthorId = FindAccountFromAuthorIndex>; impl IsMember for Pallet { fn is_member(authority_id: &T::AuthorityId) -> bool { - Self::authorities().iter().any(|id| id == authority_id) + Authorities::::get().iter().any(|id| id == authority_id) } } diff --git a/substrate/frame/aura/src/tests.rs b/substrate/frame/aura/src/tests.rs index b3a5e144fad..5374105a2f3 100644 --- a/substrate/frame/aura/src/tests.rs +++ b/substrate/frame/aura/src/tests.rs @@ -19,7 +19,8 @@ #![cfg(test)] -use crate::mock::{build_ext_and_execute_test, Aura, MockDisabledValidators, System}; +use super::pallet; +use crate::mock::{build_ext_and_execute_test, Aura, MockDisabledValidators, System, Test}; use codec::Encode; use frame_support::traits::OnInitialize; use sp_consensus_aura::{Slot, AURA_ENGINE_ID}; @@ -28,8 +29,8 @@ use sp_runtime::{Digest, DigestItem}; #[test] fn initial_values() { build_ext_and_execute_test(vec![0, 1, 2, 3], || { - assert_eq!(Aura::current_slot(), 0u64); - assert_eq!(Aura::authorities().len(), Aura::authorities_len()); + assert_eq!(pallet::CurrentSlot::::get(), 0u64); + assert_eq!(pallet::Authorities::::get().len(), Aura::authorities_len()); assert_eq!(Aura::authorities_len(), 4); }); } diff --git a/templates/parachain/runtime/src/lib.rs b/templates/parachain/runtime/src/lib.rs index acaabc0dbc3..ad21b79a5b1 100644 --- a/templates/parachain/runtime/src/lib.rs +++ b/templates/parachain/runtime/src/lib.rs @@ -57,6 +57,8 @@ use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; +use pallet_aura::Authorities; + // XCM Imports use xcm::latest::prelude::BodyId; @@ -547,7 +549,7 @@ impl_runtime_apis! { } fn authorities() -> Vec { - Aura::authorities().into_inner() + Authorities::::get().into_inner() } } diff --git a/templates/solochain/runtime/src/lib.rs b/templates/solochain/runtime/src/lib.rs index 9b52ee60a63..5a97bd2f391 100644 --- a/templates/solochain/runtime/src/lib.rs +++ b/templates/solochain/runtime/src/lib.rs @@ -415,7 +415,7 @@ impl_runtime_apis! { } fn authorities() -> Vec { - Aura::authorities().into_inner() + pallet_aura::Authorities::::get().into_inner() } } -- GitLab From 8d0cd4ffc875726f868b122c8b4b9bee4920c71d Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <49718502+alexggh@users.noreply.github.com> Date: Mon, 18 Mar 2024 13:45:39 +0200 Subject: [PATCH 052/187] Fix kusama validators getting 0 backing rewards the first session they enter the active set (#3722) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a problem in the way we update `authorithy-discovery` next keys and because of that nodes that enter the active set would be noticed at the start of the session they become active, instead of the start of the previous session as it was intended. This is problematic because: 1. The node itself advertises its addresses on the DHT only when it notices it should become active on around ~10m loop, so in this case it would notice after it becomes active. 2. The other nodes won't be able to detect the new nodes addresses at the beginning of the session, so it won't added them to the reserved set. With 1 + 2, we end-up in a situation where the the new node won't be able to properly connect to its peers because it won't be in its peers reserved set. Now, the nodes accept by default`MIN_GOSSIP_PEERS: usize = 25` connections to nodes that are not in the reserved set, but given Kusama size(> 1000 nodes) you could easily have more than`25` new nodes entering the active set or simply the nodes don't have slots anymore because, they already have connections to peers not in the active set. In the end what the node would notice is 0 backing rewards because it wasn't directly connected to the peers in its backing group. ## Root-cause The flow is like this: 1. At BAD_SESSION - 1, in `rotate_session` new nodes are added to QueuedKeys https://github.com/paritytech/polkadot-sdk/blob/02e1a7f476d7d7c67153e975ab9a1bdc02ffea12/substrate/frame/session/src/lib.rs#L609 ``` >::put(queued_amalgamated.clone()); >::put(next_changed); ``` 2. AuthorityDiscovery::on_new_session is called with `changed` being the value of `>:` at BAD_SESSION - **2** because it was saved before being updated https://github.com/paritytech/polkadot-sdk/blob/02e1a7f476d7d7c67153e975ab9a1bdc02ffea12/substrate/frame/session/src/lib.rs#L613 3. At BAD_SESSION - 1, `AuthorityDiscovery::on_new_session` doesn't updated its next_keys because `changed` was false. 4. For the entire durations of `BAD_SESSION - 1` everyone calling runtime api `authorities`(should return past, present and future authorities) won't discover the nodes that should become active . 5. At the beginning of BAD_SESSION, all nodes discover the new nodes are authorities, but it is already too late because reserved_nodes are updated only at the beginning of the session by the `gossip-support`. See above why this bad. ## Fix Update next keys with the queued_validators at every session, not matter the value of `changed` this is the same way babe pallet correctly does it. https://github.com/paritytech/polkadot-sdk/blob/02e1a7f476d7d7c67153e975ab9a1bdc02ffea12/substrate/frame/babe/src/lib.rs#L655 ## Notes - The issue doesn't reproduce with proof-authorities changes like `versi` because `changed` would always be true and `AuthorityDiscovery` correctly updates its next_keys every time. - Confirmed at session `37651` on kusama that this is exactly what it happens by looking at blocks with polkadot.js. ## TODO - [ ] Move versi on proof of stake and properly test before and after fix to confirm there is no other issue. --------- Signed-off-by: Alexandru Gheorghe Co-authored-by: Bastian Köcher --- prdoc/pr_3722.prdoc | 13 ++++ .../frame/authority-discovery/src/lib.rs | 66 ++++++++++++------- substrate/frame/session/src/lib.rs | 6 +- 3 files changed, 62 insertions(+), 23 deletions(-) create mode 100644 prdoc/pr_3722.prdoc diff --git a/prdoc/pr_3722.prdoc b/prdoc/pr_3722.prdoc new file mode 100644 index 00000000000..7e2d7d38795 --- /dev/null +++ b/prdoc/pr_3722.prdoc @@ -0,0 +1,13 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Fix kusama 0 backing rewards when entering active set + +doc: + - audience: Runtime Dev + description: | + This PR fixes getting 0 backing rewards the first session when + a node enters the active set. + +crates: + - name: pallet-authority-discovery diff --git a/substrate/frame/authority-discovery/src/lib.rs b/substrate/frame/authority-discovery/src/lib.rs index aa57378934a..ed9240d99e8 100644 --- a/substrate/frame/authority-discovery/src/lib.rs +++ b/substrate/frame/authority-discovery/src/lib.rs @@ -144,19 +144,21 @@ impl OneSessionHandler for Pallet { ); Keys::::put(bounded_keys); + } - let next_keys = queued_validators.map(|x| x.1).collect::>(); + // `changed` represents if queued_validators changed in the previous session not in the + // current one. + let next_keys = queued_validators.map(|x| x.1).collect::>(); - let next_bounded_keys = WeakBoundedVec::<_, T::MaxAuthorities>::force_from( - next_keys, - Some( - "Warning: The session has more queued validators than expected. \ - A runtime configuration adjustment may be needed.", - ), - ); + let next_bounded_keys = WeakBoundedVec::<_, T::MaxAuthorities>::force_from( + next_keys, + Some( + "Warning: The session has more queued validators than expected. \ + A runtime configuration adjustment may be needed.", + ), + ); - NextKeys::::put(next_bounded_keys); - } + NextKeys::::put(next_bounded_keys); } fn on_disabled(_i: u32) { @@ -270,7 +272,7 @@ mod tests { .map(|id| (&account_id, id)) .collect::>(); - let mut third_authorities: Vec = vec![4, 5] + let third_authorities: Vec = vec![4, 5] .into_iter() .map(|i| AuthorityPair::from_seed_slice(vec![i; 32].as_ref()).unwrap().public()) .map(AuthorityId::from) @@ -282,6 +284,18 @@ mod tests { .map(|id| (&account_id, id)) .collect::>(); + let mut fourth_authorities: Vec = vec![6, 7] + .into_iter() + .map(|i| AuthorityPair::from_seed_slice(vec![i; 32].as_ref()).unwrap().public()) + .map(AuthorityId::from) + .collect(); + // Needed for `pallet_session::OneSessionHandler::on_new_session`. + let fourth_authorities_and_account_ids = fourth_authorities + .clone() + .into_iter() + .map(|id| (&account_id, id)) + .collect::>(); + // Build genesis. let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); @@ -310,25 +324,33 @@ mod tests { third_authorities_and_account_ids.clone().into_iter(), ); let authorities_returned = AuthorityDiscovery::authorities(); + let mut first_and_third_authorities = first_authorities + .iter() + .chain(third_authorities.iter()) + .cloned() + .collect::>(); + first_and_third_authorities.sort(); + assert_eq!( - first_authorities, authorities_returned, + first_and_third_authorities, authorities_returned, "Expected authority set not to change as `changed` was set to false.", ); // When `changed` set to true, the authority set should be updated. AuthorityDiscovery::on_new_session( true, - second_authorities_and_account_ids.into_iter(), - third_authorities_and_account_ids.clone().into_iter(), + third_authorities_and_account_ids.into_iter(), + fourth_authorities_and_account_ids.clone().into_iter(), ); - let mut second_and_third_authorities = second_authorities + + let mut third_and_fourth_authorities = third_authorities .iter() - .chain(third_authorities.iter()) + .chain(fourth_authorities.iter()) .cloned() .collect::>(); - second_and_third_authorities.sort(); + third_and_fourth_authorities.sort(); assert_eq!( - second_and_third_authorities, + third_and_fourth_authorities, AuthorityDiscovery::authorities(), "Expected authority set to contain both the authorities of the new as well as the \ next session." @@ -337,12 +359,12 @@ mod tests { // With overlapping authority sets, `authorities()` should return a deduplicated set. AuthorityDiscovery::on_new_session( true, - third_authorities_and_account_ids.clone().into_iter(), - third_authorities_and_account_ids.clone().into_iter(), + fourth_authorities_and_account_ids.clone().into_iter(), + fourth_authorities_and_account_ids.clone().into_iter(), ); - third_authorities.sort(); + fourth_authorities.sort(); assert_eq!( - third_authorities, + fourth_authorities, AuthorityDiscovery::authorities(), "Expected authority set to be deduplicated." ); diff --git a/substrate/frame/session/src/lib.rs b/substrate/frame/session/src/lib.rs index 7d8128dbc1f..17b6aa7a464 100644 --- a/substrate/frame/session/src/lib.rs +++ b/substrate/frame/session/src/lib.rs @@ -285,7 +285,11 @@ pub trait SessionHandler { /// before initialization of your pallet. /// /// `changed` is true whenever any of the session keys or underlying economic - /// identities or weightings behind those keys has changed. + /// identities or weightings behind `validators` keys has changed. `queued_validators` + /// could change without `validators` changing. Example of possible sequent calls: + /// Session N: on_new_session(false, unchanged_validators, unchanged_queued_validators) + /// Session N + 1: on_new_session(false, unchanged_validators, new_queued_validators) + /// Session N + 2: on_new_session(true, new_queued_validators, new_queued_validators) fn on_new_session( changed: bool, validators: &[(ValidatorId, Ks)], -- GitLab From 1d60f9ca9ae82621380530a19162652c13106a4f Mon Sep 17 00:00:00 2001 From: jokess123 <163112061+jokess123@users.noreply.github.com> Date: Mon, 18 Mar 2024 20:18:40 +0800 Subject: [PATCH 053/187] Fix typos (#3725) --- polkadot/node/subsystem-bench/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/polkadot/node/subsystem-bench/README.md b/polkadot/node/subsystem-bench/README.md index 94a449ed0bb..228fba41c46 100644 --- a/polkadot/node/subsystem-bench/README.md +++ b/polkadot/node/subsystem-bench/README.md @@ -27,7 +27,7 @@ The output binary will be placed in `target/testnet/subsystem-bench`. ### Test metrics Subsystem, CPU usage and network metrics are exposed via a prometheus endpoint during the test execution. -A small subset of these collected metrics are displayed in the CLI, but for an in depth analysys of the test results, +A small subset of these collected metrics are displayed in the CLI, but for an in depth analysis of the test results, a local Grafana/Prometheus stack is needed. ### Run Prometheus, Pyroscope and Graphana in Docker @@ -122,7 +122,7 @@ target/testnet/subsystem-bench polkadot/node/subsystem-bench/examples/availabili ``` Note: test objectives may be wrapped up into a test sequence. -It is tipically used to run a suite of tests like in this [example](examples/availability_read.yaml). +It is typically used to run a suite of tests like in this [example](examples/availability_read.yaml). ### Understanding the test configuration @@ -137,13 +137,13 @@ usage: From the perspective of the subsystem under test, this means that it will receive an `ActiveLeavesUpdate` signal followed by an arbitrary amount of messages. This process repeats itself for `num_blocks`. The messages are generally -test payloads pre-generated before the test run, or constructed on pre-genereated payloads. For example the +test payloads pre-generated before the test run, or constructed on pre-generated payloads. For example the `AvailabilityRecoveryMessage::RecoverAvailableData` message includes a `CandidateReceipt` which is generated before the test is started. ### Example run -Let's run an availabilty read test which will recover availability for 200 cores with max PoV size on a 1000 +Let's run an availability read test which will recover availability for 200 cores with max PoV size on a 1000 node validator network. -- GitLab From 0c6c837f689a287583508506e342ba07687e8d26 Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Mon, 18 Mar 2024 13:37:24 +0100 Subject: [PATCH 054/187] Bridge zombienet tests: remove unneeded accounts (#3700) Bridge zombienet tests: remove unneeded accounts --- .../rococo-westend/bridges_rococo_westend.sh | 26 ------------------- 1 file changed, 26 deletions(-) diff --git a/bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh b/bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh index 479ab833abf..66c9ddc037b 100755 --- a/bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh +++ b/bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh @@ -24,12 +24,6 @@ source "$FRAMEWORK_PATH/utils/bridges.sh" # &MultiLocation { parents: 2, interior: X1(GlobalConsensus(Rococo)) }).unwrap() # ).to_ss58check_with_version(42_u16.into()) # ); -# println!("GLOBAL_CONSENSUS_ROCOCO_ASSET_HUB_ROCOCO_1000_SOVEREIGN_ACCOUNT=\"{}\"", -# frame_support::sp_runtime::AccountId32::new( -# GlobalConsensusParachainConvertsFor::::convert_location( -# &MultiLocation { parents: 2, interior: X2(GlobalConsensus(Rococo), Parachain(1000)) }).unwrap() -# ).to_ss58check_with_version(42_u16.into()) -# ); # println!("ASSET_HUB_WESTEND_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_WESTEND=\"{}\"", # frame_support::sp_runtime::AccountId32::new( # SiblingParachainConvertsVia::::convert_location( @@ -44,12 +38,6 @@ source "$FRAMEWORK_PATH/utils/bridges.sh" # &MultiLocation { parents: 2, interior: X1(GlobalConsensus(Westend)) }).unwrap() # ).to_ss58check_with_version(42_u16.into()) # ); -# println!("GLOBAL_CONSENSUS_WESTEND_ASSET_HUB_WESTEND_1000_SOVEREIGN_ACCOUNT=\"{}\"", -# frame_support::sp_runtime::AccountId32::new( -# GlobalConsensusParachainConvertsFor::::convert_location( -# &MultiLocation { parents: 2, interior: X2(GlobalConsensus(Westend), Parachain(1000)) }).unwrap() -# ).to_ss58check_with_version(42_u16.into()) -# ); # println!("ASSET_HUB_ROCOCO_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_ROCOCO=\"{}\"", # frame_support::sp_runtime::AccountId32::new( # SiblingParachainConvertsVia::::convert_location( @@ -58,10 +46,8 @@ source "$FRAMEWORK_PATH/utils/bridges.sh" # ); # } GLOBAL_CONSENSUS_ROCOCO_SOVEREIGN_ACCOUNT="5GxRGwT8bU1JeBPTUXc7LEjZMxNrK8MyL2NJnkWFQJTQ4sii" -GLOBAL_CONSENSUS_ROCOCO_ASSET_HUB_ROCOCO_1000_SOVEREIGN_ACCOUNT="5CfNu7eH3SJvqqPt3aJh38T8dcFvhGzEohp9tsd41ANhXDnQ" ASSET_HUB_WESTEND_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_WESTEND="5Eg2fntNprdN3FgH4sfEaaZhYtddZQSQUqvYJ1f2mLtinVhV" GLOBAL_CONSENSUS_WESTEND_SOVEREIGN_ACCOUNT="5He2Qdztyxxa4GoagY6q1jaiLMmKy1gXS7PdZkhfj8ZG9hk5" -GLOBAL_CONSENSUS_WESTEND_ASSET_HUB_WESTEND_1000_SOVEREIGN_ACCOUNT="5GUD9X494SnhfBTNReHwhV1599McpyVrAqFY6WnTfVQVYNUM" ASSET_HUB_ROCOCO_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_ROCOCO="5Eg2fntNprdN3FgH4sfEaaZhYtddZQSQUqvYJ1f2mLtinVhV" # Expected sovereign accounts for rewards on BridgeHubs. @@ -201,12 +187,6 @@ case "$1" in "$GLOBAL_CONSENSUS_WESTEND_SOVEREIGN_ACCOUNT" \ 10000000000 \ true - # drip SA which holds reserves - transfer_balance \ - "ws://127.0.0.1:9910" \ - "//Alice" \ - "$GLOBAL_CONSENSUS_WESTEND_ASSET_HUB_WESTEND_1000_SOVEREIGN_ACCOUNT" \ - $((1000000000000 + 50000000000 * 20)) # HRMP open_hrmp_channels \ "ws://127.0.0.1:9942" \ @@ -266,12 +246,6 @@ case "$1" in "$GLOBAL_CONSENSUS_ROCOCO_SOVEREIGN_ACCOUNT" \ 10000000000 \ true - # drip SA which holds reserves - transfer_balance \ - "ws://127.0.0.1:9010" \ - "//Alice" \ - "$GLOBAL_CONSENSUS_ROCOCO_ASSET_HUB_ROCOCO_1000_SOVEREIGN_ACCOUNT" \ - $((1000000000000000 + 50000000000 * 20)) # HRMP open_hrmp_channels \ "ws://127.0.0.1:9945" \ -- GitLab From 610987a19da816a76c296c99f311ce8f6e9ab3d8 Mon Sep 17 00:00:00 2001 From: Matteo Muraca <56828990+muraca@users.noreply.github.com> Date: Mon, 18 Mar 2024 20:19:20 +0100 Subject: [PATCH 055/187] removed `pallet::getter` usage from cumulus pallets (#3471) Part of #3326 @ggwpez @kianenigma @shawntabrizi polkadot address: 12poSUQPtcF1HUPQGY3zZu2P8emuW9YnsPduA4XG3oCEfJVp --------- Signed-off-by: Matteo Muraca --- .../pallets/aura-ext/src/consensus_hook.rs | 6 +- cumulus/pallets/aura-ext/src/lib.rs | 1 - .../collator-selection/src/benchmarking.rs | 76 ++--- cumulus/pallets/collator-selection/src/lib.rs | 83 +++-- .../collator-selection/src/migration.rs | 2 +- .../pallets/collator-selection/src/tests.rs | 316 +++++++++--------- cumulus/pallets/parachain-system/src/lib.rs | 30 +- .../pallets/parachain-info/src/lib.rs | 11 +- prdoc/pr_3471.prdoc | 33 ++ 9 files changed, 292 insertions(+), 266 deletions(-) create mode 100644 prdoc/pr_3471.prdoc diff --git a/cumulus/pallets/aura-ext/src/consensus_hook.rs b/cumulus/pallets/aura-ext/src/consensus_hook.rs index 089ab5c3198..59202980339 100644 --- a/cumulus/pallets/aura-ext/src/consensus_hook.rs +++ b/cumulus/pallets/aura-ext/src/consensus_hook.rs @@ -54,8 +54,8 @@ where let velocity = V.max(1); let relay_chain_slot = state_proof.read_slot().expect("failed to read relay chain slot"); - let (slot, authored) = pallet::Pallet::::slot_info() - .expect("slot info is inserted on block initialization"); + let (slot, authored) = + pallet::SlotInfo::::get().expect("slot info is inserted on block initialization"); // Convert relay chain timestamp. let relay_chain_timestamp = @@ -100,7 +100,7 @@ impl< /// is more recent than the included block itself. pub fn can_build_upon(included_hash: T::Hash, new_slot: Slot) -> bool { let velocity = V.max(1); - let (last_slot, authored_so_far) = match pallet::Pallet::::slot_info() { + let (last_slot, authored_so_far) = match pallet::SlotInfo::::get() { None => return true, Some(x) => x, }; diff --git a/cumulus/pallets/aura-ext/src/lib.rs b/cumulus/pallets/aura-ext/src/lib.rs index b71ae628954..7ca84dff7c5 100644 --- a/cumulus/pallets/aura-ext/src/lib.rs +++ b/cumulus/pallets/aura-ext/src/lib.rs @@ -103,7 +103,6 @@ pub mod pallet { /// /// Updated on each block initialization. #[pallet::storage] - #[pallet::getter(fn slot_info)] pub(crate) type SlotInfo = StorageValue<_, (Slot, u32), OptionQuery>; #[pallet::genesis_config] diff --git a/cumulus/pallets/collator-selection/src/benchmarking.rs b/cumulus/pallets/collator-selection/src/benchmarking.rs index e2af74a6e60..c6b60044528 100644 --- a/cumulus/pallets/collator-selection/src/benchmarking.rs +++ b/cumulus/pallets/collator-selection/src/benchmarking.rs @@ -86,23 +86,23 @@ fn register_validators(count: u32) -> Vec(count: u32) { let candidates = (0..count).map(|c| account("candidate", c, SEED)).collect::>(); - assert!(>::get() > 0u32.into(), "Bond cannot be zero!"); + assert!(CandidacyBond::::get() > 0u32.into(), "Bond cannot be zero!"); for who in candidates { - T::Currency::make_free_balance_be(&who, >::get() * 3u32.into()); + T::Currency::make_free_balance_be(&who, CandidacyBond::::get() * 3u32.into()); >::register_as_candidate(RawOrigin::Signed(who).into()).unwrap(); } } fn min_candidates() -> u32 { let min_collators = T::MinEligibleCollators::get(); - let invulnerable_length = >::get().len(); + let invulnerable_length = Invulnerables::::get().len(); min_collators.saturating_sub(invulnerable_length.try_into().unwrap()) } fn min_invulnerables() -> u32 { let min_collators = T::MinEligibleCollators::get(); - let candidates_length = >::decode_len() + let candidates_length = CandidateList::::decode_len() .unwrap_or_default() .try_into() .unwrap_or_default(); @@ -143,8 +143,8 @@ mod benchmarks { T::UpdateOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; // need to fill up candidates - >::put(T::Currency::minimum_balance()); - >::put(c); + CandidacyBond::::put(T::Currency::minimum_balance()); + DesiredCandidates::::put(c); // get accounts and keys for the `c` candidates let mut candidates = (0..c).map(|cc| validator::(cc)).collect::>(); // add one more to the list. should not be in `b` (invulnerables) because it's the account @@ -159,15 +159,15 @@ mod benchmarks { } // ... and register them. for (who, _) in candidates.iter() { - let deposit = >::get(); + let deposit = CandidacyBond::::get(); T::Currency::make_free_balance_be(who, deposit * 1000_u32.into()); - >::try_mutate(|list| { + CandidateList::::try_mutate(|list| { list.try_push(CandidateInfo { who: who.clone(), deposit }).unwrap(); Ok::<(), BenchmarkError>(()) }) .unwrap(); T::Currency::reserve(who, deposit)?; - >::insert( + LastAuthoredBlock::::insert( who.clone(), frame_system::Pallet::::block_number() + T::KickThreshold::get(), ); @@ -178,7 +178,7 @@ mod benchmarks { invulnerables.sort(); let invulnerables: frame_support::BoundedVec<_, T::MaxInvulnerables> = frame_support::BoundedVec::try_from(invulnerables).unwrap(); - >::put(invulnerables); + Invulnerables::::put(invulnerables); #[extrinsic_call] _(origin as T::RuntimeOrigin, new_invulnerable.clone()); @@ -197,8 +197,8 @@ mod benchmarks { invulnerables.sort(); let invulnerables: frame_support::BoundedVec<_, T::MaxInvulnerables> = frame_support::BoundedVec::try_from(invulnerables).unwrap(); - >::put(invulnerables); - let to_remove = >::get().first().unwrap().clone(); + Invulnerables::::put(invulnerables); + let to_remove = Invulnerables::::get().first().unwrap().clone(); #[extrinsic_call] _(origin as T::RuntimeOrigin, to_remove.clone()); @@ -226,14 +226,14 @@ mod benchmarks { k: Linear<0, { T::MaxCandidates::get() }>, ) -> Result<(), BenchmarkError> { let initial_bond_amount: BalanceOf = T::Currency::minimum_balance() * 2u32.into(); - >::put(initial_bond_amount); + CandidacyBond::::put(initial_bond_amount); register_validators::(c); register_candidates::(c); let kicked = cmp::min(k, c); let origin = T::UpdateOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let bond_amount = if k > 0 { - >::mutate(|candidates| { + CandidateList::::mutate(|candidates| { for info in candidates.iter_mut().skip(kicked as usize) { info.deposit = T::Currency::minimum_balance() * 3u32.into(); } @@ -254,13 +254,13 @@ mod benchmarks { fn update_bond( c: Linear<{ min_candidates::() + 1 }, { T::MaxCandidates::get() }>, ) -> Result<(), BenchmarkError> { - >::put(T::Currency::minimum_balance()); - >::put(c); + CandidacyBond::::put(T::Currency::minimum_balance()); + DesiredCandidates::::put(c); register_validators::(c); register_candidates::(c); - let caller = >::get()[0].who.clone(); + let caller = CandidateList::::get()[0].who.clone(); v2::whitelist!(caller); let bond_amount: BalanceOf = @@ -273,7 +273,7 @@ mod benchmarks { Event::CandidateBondUpdated { account_id: caller, deposit: bond_amount }.into(), ); assert!( - >::get().iter().last().unwrap().deposit == + CandidateList::::get().iter().last().unwrap().deposit == T::Currency::minimum_balance() * 2u32.into() ); Ok(()) @@ -283,8 +283,8 @@ mod benchmarks { // one. #[benchmark] fn register_as_candidate(c: Linear<1, { T::MaxCandidates::get() - 1 }>) { - >::put(T::Currency::minimum_balance()); - >::put(c + 1); + CandidacyBond::::put(T::Currency::minimum_balance()); + DesiredCandidates::::put(c + 1); register_validators::(c); register_candidates::(c); @@ -310,8 +310,8 @@ mod benchmarks { #[benchmark] fn take_candidate_slot(c: Linear<{ min_candidates::() + 1 }, { T::MaxCandidates::get() }>) { - >::put(T::Currency::minimum_balance()); - >::put(1); + CandidacyBond::::put(T::Currency::minimum_balance()); + DesiredCandidates::::put(1); register_validators::(c); register_candidates::(c); @@ -327,7 +327,7 @@ mod benchmarks { ) .unwrap(); - let target = >::get().iter().last().unwrap().who.clone(); + let target = CandidateList::::get().iter().last().unwrap().who.clone(); #[extrinsic_call] _(RawOrigin::Signed(caller.clone()), bond / 2u32.into(), target.clone()); @@ -341,13 +341,13 @@ mod benchmarks { // worse case is the last candidate leaving. #[benchmark] fn leave_intent(c: Linear<{ min_candidates::() + 1 }, { T::MaxCandidates::get() }>) { - >::put(T::Currency::minimum_balance()); - >::put(c); + CandidacyBond::::put(T::Currency::minimum_balance()); + DesiredCandidates::::put(c); register_validators::(c); register_candidates::(c); - let leaving = >::get().iter().last().unwrap().who.clone(); + let leaving = CandidateList::::get().iter().last().unwrap().who.clone(); v2::whitelist!(leaving); #[extrinsic_call] @@ -359,7 +359,7 @@ mod benchmarks { // worse case is paying a non-existing candidate account. #[benchmark] fn note_author() { - >::put(T::Currency::minimum_balance()); + CandidacyBond::::put(T::Currency::minimum_balance()); T::Currency::make_free_balance_be( &>::account_id(), T::Currency::minimum_balance() * 4u32.into(), @@ -385,8 +385,8 @@ mod benchmarks { r: Linear<1, { T::MaxCandidates::get() }>, c: Linear<1, { T::MaxCandidates::get() }>, ) { - >::put(T::Currency::minimum_balance()); - >::put(c); + CandidacyBond::::put(T::Currency::minimum_balance()); + DesiredCandidates::::put(c); frame_system::Pallet::::set_block_number(0u32.into()); register_validators::(c); @@ -394,7 +394,7 @@ mod benchmarks { let new_block: BlockNumberFor = T::KickThreshold::get(); let zero_block: BlockNumberFor = 0u32.into(); - let candidates: Vec = >::get() + let candidates: Vec = CandidateList::::get() .iter() .map(|candidate_info| candidate_info.who.clone()) .collect(); @@ -402,25 +402,25 @@ mod benchmarks { let non_removals = c.saturating_sub(r); for i in 0..c { - >::insert(candidates[i as usize].clone(), zero_block); + LastAuthoredBlock::::insert(candidates[i as usize].clone(), zero_block); } if non_removals > 0 { for i in 0..non_removals { - >::insert(candidates[i as usize].clone(), new_block); + LastAuthoredBlock::::insert(candidates[i as usize].clone(), new_block); } } else { for i in 0..c { - >::insert(candidates[i as usize].clone(), new_block); + LastAuthoredBlock::::insert(candidates[i as usize].clone(), new_block); } } let min_candidates = min_candidates::(); - let pre_length = >::decode_len().unwrap_or_default(); + let pre_length = CandidateList::::decode_len().unwrap_or_default(); frame_system::Pallet::::set_block_number(new_block); - let current_length: u32 = >::decode_len() + let current_length: u32 = CandidateList::::decode_len() .unwrap_or_default() .try_into() .unwrap_or_default(); @@ -434,12 +434,12 @@ mod benchmarks { // candidates > removals and remaining candidates > min candidates // => remaining candidates should be shorter than before removal, i.e. some were // actually removed. - assert!(>::decode_len().unwrap_or_default() < pre_length); + assert!(CandidateList::::decode_len().unwrap_or_default() < pre_length); } else if c > r && non_removals < min_candidates { // candidates > removals and remaining candidates would be less than min candidates // => remaining candidates should equal min candidates, i.e. some were removed up to // the minimum, but then any more were "forced" to stay in candidates. - let current_length: u32 = >::decode_len() + let current_length: u32 = CandidateList::::decode_len() .unwrap_or_default() .try_into() .unwrap_or_default(); @@ -447,7 +447,7 @@ mod benchmarks { } else { // removals >= candidates, non removals must == 0 // can't remove more than exist - assert!(>::decode_len().unwrap_or_default() == pre_length); + assert!(CandidateList::::decode_len().unwrap_or_default() == pre_length); } } diff --git a/cumulus/pallets/collator-selection/src/lib.rs b/cumulus/pallets/collator-selection/src/lib.rs index 62c00737f91..84bde5c9fac 100644 --- a/cumulus/pallets/collator-selection/src/lib.rs +++ b/cumulus/pallets/collator-selection/src/lib.rs @@ -196,7 +196,6 @@ pub mod pallet { /// The invulnerable, permissioned collators. This list must be sorted. #[pallet::storage] - #[pallet::getter(fn invulnerables)] pub type Invulnerables = StorageValue<_, BoundedVec, ValueQuery>; @@ -206,7 +205,6 @@ pub mod pallet { /// This list is sorted in ascending order by deposit and when the deposits are equal, the least /// recently updated is considered greater. #[pallet::storage] - #[pallet::getter(fn candidate_list)] pub type CandidateList = StorageValue< _, BoundedVec>, T::MaxCandidates>, @@ -215,7 +213,6 @@ pub mod pallet { /// Last block authored by collator. #[pallet::storage] - #[pallet::getter(fn last_authored_block)] pub type LastAuthoredBlock = StorageMap<_, Twox64Concat, T::AccountId, BlockNumberFor, ValueQuery>; @@ -223,14 +220,12 @@ pub mod pallet { /// /// This should ideally always be less than [`Config::MaxCandidates`] for weights to be correct. #[pallet::storage] - #[pallet::getter(fn desired_candidates)] pub type DesiredCandidates = StorageValue<_, u32, ValueQuery>; /// Fixed amount to deposit to become a collator. /// /// When a collator calls `leave_intent` they immediately receive the deposit back. #[pallet::storage] - #[pallet::getter(fn candidacy_bond)] pub type CandidacyBond = StorageValue<_, BalanceOf, ValueQuery>; #[pallet::genesis_config] @@ -263,9 +258,9 @@ pub mod pallet { bounded_invulnerables.sort(); - >::put(self.desired_candidates); - >::put(self.candidacy_bond); - >::put(bounded_invulnerables); + DesiredCandidates::::put(self.desired_candidates); + CandidacyBond::::put(self.candidacy_bond); + Invulnerables::::put(bounded_invulnerables); } } @@ -424,7 +419,7 @@ pub mod pallet { // Invulnerables must be sorted for removal. bounded_invulnerables.sort(); - >::put(&bounded_invulnerables); + Invulnerables::::put(&bounded_invulnerables); Self::deposit_event(Event::NewInvulnerables { invulnerables: bounded_invulnerables.to_vec(), }); @@ -448,7 +443,7 @@ pub mod pallet { if max > T::MaxCandidates::get() { log::warn!("max > T::MaxCandidates; you might need to run benchmarks again"); } - >::put(max); + DesiredCandidates::::put(max); Self::deposit_event(Event::NewDesiredCandidates { desired_candidates: max }); Ok(().into()) } @@ -470,17 +465,17 @@ pub mod pallet { bond: BalanceOf, ) -> DispatchResultWithPostInfo { T::UpdateOrigin::ensure_origin(origin)?; - let bond_increased = >::mutate(|old_bond| -> bool { + let bond_increased = CandidacyBond::::mutate(|old_bond| -> bool { let bond_increased = *old_bond < bond; *old_bond = bond; bond_increased }); - let initial_len = >::decode_len().unwrap_or_default(); + let initial_len = CandidateList::::decode_len().unwrap_or_default(); let kicked = (bond_increased && initial_len > 0) .then(|| { // Closure below returns the number of candidates which were kicked because // their deposits were lower than the new candidacy bond. - >::mutate(|candidates| -> usize { + CandidateList::::mutate(|candidates| -> usize { let first_safe_candidate = candidates .iter() .position(|candidate| candidate.deposit >= bond) @@ -488,7 +483,7 @@ pub mod pallet { let kicked_candidates = candidates.drain(..first_safe_candidate); for candidate in kicked_candidates { T::Currency::unreserve(&candidate.who, candidate.deposit); - >::remove(candidate.who); + LastAuthoredBlock::::remove(candidate.who); } first_safe_candidate }) @@ -512,12 +507,12 @@ pub mod pallet { let who = ensure_signed(origin)?; // ensure we are below limit. - let length: u32 = >::decode_len() + let length: u32 = CandidateList::::decode_len() .unwrap_or_default() .try_into() .unwrap_or_default(); ensure!(length < T::MaxCandidates::get(), Error::::TooManyCandidates); - ensure!(!Self::invulnerables().contains(&who), Error::::AlreadyInvulnerable); + ensure!(!Invulnerables::::get().contains(&who), Error::::AlreadyInvulnerable); let validator_key = T::ValidatorIdOf::convert(who.clone()) .ok_or(Error::::NoAssociatedValidatorId)?; @@ -526,15 +521,15 @@ pub mod pallet { Error::::ValidatorNotRegistered ); - let deposit = Self::candidacy_bond(); + let deposit = CandidacyBond::::get(); // First authored block is current block plus kick threshold to handle session delay - >::try_mutate(|candidates| -> Result<(), DispatchError> { + CandidateList::::try_mutate(|candidates| -> Result<(), DispatchError> { ensure!( !candidates.iter().any(|candidate_info| candidate_info.who == who), Error::::AlreadyCandidate ); T::Currency::reserve(&who, deposit)?; - >::insert( + LastAuthoredBlock::::insert( who.clone(), frame_system::Pallet::::block_number() + T::KickThreshold::get(), ); @@ -564,7 +559,7 @@ pub mod pallet { Self::eligible_collators() > T::MinEligibleCollators::get(), Error::::TooFewEligibleCollators ); - let length = >::decode_len().unwrap_or_default(); + let length = CandidateList::::decode_len().unwrap_or_default(); // Do remove their last authored block. Self::try_remove_candidate(&who, true)?; @@ -594,7 +589,7 @@ pub mod pallet { Error::::ValidatorNotRegistered ); - >::try_mutate(|invulnerables| -> DispatchResult { + Invulnerables::::try_mutate(|invulnerables| -> DispatchResult { match invulnerables.binary_search(&who) { Ok(_) => return Err(Error::::AlreadyInvulnerable)?, Err(pos) => invulnerables @@ -615,7 +610,7 @@ pub mod pallet { .unwrap_or_default() .try_into() .unwrap_or(T::MaxInvulnerables::get().saturating_sub(1)), - >::decode_len() + CandidateList::::decode_len() .unwrap_or_default() .try_into() .unwrap_or(T::MaxCandidates::get()), @@ -638,7 +633,7 @@ pub mod pallet { Error::::TooFewEligibleCollators ); - >::try_mutate(|invulnerables| -> DispatchResult { + Invulnerables::::try_mutate(|invulnerables| -> DispatchResult { let pos = invulnerables.binary_search(&who).map_err(|_| Error::::NotInvulnerable)?; invulnerables.remove(pos); @@ -663,12 +658,12 @@ pub mod pallet { new_deposit: BalanceOf, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - ensure!(new_deposit >= >::get(), Error::::DepositTooLow); + ensure!(new_deposit >= CandidacyBond::::get(), Error::::DepositTooLow); // The function below will try to mutate the `CandidateList` entry for the caller to // update their deposit to the new value of `new_deposit`. The return value is the // position of the entry in the list, used for weight calculation. let length = - >::try_mutate(|candidates| -> Result { + CandidateList::::try_mutate(|candidates| -> Result { let idx = candidates .iter() .position(|candidate_info| candidate_info.who == who) @@ -682,7 +677,7 @@ pub mod pallet { } else if new_deposit < old_deposit { // Casting `u32` to `usize` should be safe on all machines running this. ensure!( - idx.saturating_add(>::get() as usize) < + idx.saturating_add(DesiredCandidates::::get() as usize) < candidate_count, Error::::InvalidUnreserve ); @@ -727,8 +722,8 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - ensure!(!Self::invulnerables().contains(&who), Error::::AlreadyInvulnerable); - ensure!(deposit >= Self::candidacy_bond(), Error::::InsufficientBond); + ensure!(!Invulnerables::::get().contains(&who), Error::::AlreadyInvulnerable); + ensure!(deposit >= CandidacyBond::::get(), Error::::InsufficientBond); let validator_key = T::ValidatorIdOf::convert(who.clone()) .ok_or(Error::::NoAssociatedValidatorId)?; @@ -737,12 +732,12 @@ pub mod pallet { Error::::ValidatorNotRegistered ); - let length = >::decode_len().unwrap_or_default(); + let length = CandidateList::::decode_len().unwrap_or_default(); // The closure below iterates through all elements of the candidate list to ensure that // the caller isn't already a candidate and to find the target it's trying to replace in // the list. The return value is a tuple of the position of the candidate to be replaced // in the list along with its candidate information. - let target_info = >::try_mutate( + let target_info = CandidateList::::try_mutate( |candidates| -> Result>, DispatchError> { // Find the position in the list of the candidate that is being replaced. let mut target_info_idx = None; @@ -787,8 +782,8 @@ pub mod pallet { )?; T::Currency::reserve(&who, deposit)?; T::Currency::unreserve(&target_info.who, target_info.deposit); - >::remove(target_info.who.clone()); - >::insert( + LastAuthoredBlock::::remove(target_info.who.clone()); + LastAuthoredBlock::::insert( who.clone(), frame_system::Pallet::::block_number() + T::KickThreshold::get(), ); @@ -807,7 +802,7 @@ pub mod pallet { /// Return the total number of accounts that are eligible collators (candidates and /// invulnerables). fn eligible_collators() -> u32 { - >::decode_len() + CandidateList::::decode_len() .unwrap_or_default() .saturating_add(Invulnerables::::decode_len().unwrap_or_default()) .try_into() @@ -819,7 +814,7 @@ pub mod pallet { who: &T::AccountId, remove_last_authored: bool, ) -> Result<(), DispatchError> { - >::try_mutate(|candidates| -> Result<(), DispatchError> { + CandidateList::::try_mutate(|candidates| -> Result<(), DispatchError> { let idx = candidates .iter() .position(|candidate_info| candidate_info.who == *who) @@ -828,7 +823,7 @@ pub mod pallet { T::Currency::unreserve(who, deposit); candidates.remove(idx); if remove_last_authored { - >::remove(who.clone()) + LastAuthoredBlock::::remove(who.clone()) }; Ok(()) })?; @@ -841,10 +836,10 @@ pub mod pallet { /// This is done on the fly, as frequent as we are told to do so, as the session manager. pub fn assemble_collators() -> Vec { // Casting `u32` to `usize` should be safe on all machines running this. - let desired_candidates = >::get() as usize; - let mut collators = Self::invulnerables().to_vec(); + let desired_candidates = DesiredCandidates::::get() as usize; + let mut collators = Invulnerables::::get().to_vec(); collators.extend( - >::get() + CandidateList::::get() .iter() .rev() .cloned() @@ -865,10 +860,10 @@ pub mod pallet { candidates .into_iter() .filter_map(|c| { - let last_block = >::get(c.clone()); + let last_block = LastAuthoredBlock::::get(c.clone()); let since_last = now.saturating_sub(last_block); - let is_invulnerable = Self::invulnerables().contains(&c); + let is_invulnerable = Invulnerables::::get().contains(&c); let is_lazy = since_last >= kick_threshold; if is_invulnerable { @@ -907,7 +902,7 @@ pub mod pallet { /// or equal to the minimum number of eligible collators. #[cfg(any(test, feature = "try-runtime"))] pub fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { - let desired_candidates = >::get(); + let desired_candidates = DesiredCandidates::::get(); frame_support::ensure!( desired_candidates <= T::MaxCandidates::get(), @@ -939,7 +934,7 @@ pub mod pallet { // `reward` is half of pot account minus ED, this should never fail. let _success = T::Currency::transfer(&pot, &author, reward, KeepAlive); debug_assert!(_success.is_ok()); - >::insert(author, frame_system::Pallet::::block_number()); + LastAuthoredBlock::::insert(author, frame_system::Pallet::::block_number()); frame_system::Pallet::::register_extra_weight_unchecked( T::WeightInfo::note_author(), @@ -960,12 +955,12 @@ pub mod pallet { // The `expect` below is safe because the list is a `BoundedVec` with a max size of // `T::MaxCandidates`, which is a `u32`. When `decode_len` returns `Some(len)`, `len` // must be valid and at most `u32::MAX`, which must always be able to convert to `u32`. - let candidates_len_before: u32 = >::decode_len() + let candidates_len_before: u32 = CandidateList::::decode_len() .unwrap_or_default() .try_into() .expect("length is at most `T::MaxCandidates`, so it must fit in `u32`; qed"); let active_candidates_count = Self::kick_stale_candidates( - >::get() + CandidateList::::get() .iter() .map(|candidate_info| candidate_info.who.clone()), ); diff --git a/cumulus/pallets/collator-selection/src/migration.rs b/cumulus/pallets/collator-selection/src/migration.rs index f384981dbae..5dc2fba4279 100644 --- a/cumulus/pallets/collator-selection/src/migration.rs +++ b/cumulus/pallets/collator-selection/src/migration.rs @@ -34,7 +34,7 @@ pub mod v1 { let on_chain_version = Pallet::::on_chain_storage_version(); if on_chain_version == 0 { let invulnerables_len = Invulnerables::::get().to_vec().len(); - >::mutate(|invulnerables| { + Invulnerables::::mutate(|invulnerables| { invulnerables.sort(); }); diff --git a/cumulus/pallets/collator-selection/src/tests.rs b/cumulus/pallets/collator-selection/src/tests.rs index ed2044ccdfa..e8b2a4e146a 100644 --- a/cumulus/pallets/collator-selection/src/tests.rs +++ b/cumulus/pallets/collator-selection/src/tests.rs @@ -14,7 +14,10 @@ // limitations under the License. use crate as collator_selection; -use crate::{mock::*, CandidateInfo, Error}; +use crate::{ + mock::*, CandidacyBond, CandidateInfo, CandidateList, DesiredCandidates, Error, Invulnerables, + LastAuthoredBlock, +}; use frame_support::{ assert_noop, assert_ok, traits::{Currency, OnInitialize}, @@ -25,12 +28,12 @@ use sp_runtime::{testing::UintAuthorityId, traits::BadOrigin, BuildStorage}; #[test] fn basic_setup_works() { new_test_ext().execute_with(|| { - assert_eq!(CollatorSelection::desired_candidates(), 2); - assert_eq!(CollatorSelection::candidacy_bond(), 10); + assert_eq!(DesiredCandidates::::get(), 2); + assert_eq!(CandidacyBond::::get(), 10); - assert_eq!(>::get().iter().count(), 0); + assert_eq!(CandidateList::::get().iter().count(), 0); // genesis should sort input - assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + assert_eq!(Invulnerables::::get(), vec![1, 2]); }); } @@ -43,7 +46,7 @@ fn it_should_set_invulnerables() { new_set.clone() )); new_set.sort(); - assert_eq!(CollatorSelection::invulnerables(), new_set); + assert_eq!(Invulnerables::::get(), new_set); // cannot set with non-root. assert_noop!( @@ -56,7 +59,7 @@ fn it_should_set_invulnerables() { #[test] fn it_should_set_invulnerables_even_with_some_invalid() { new_test_ext().execute_with(|| { - assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + assert_eq!(Invulnerables::::get(), vec![1, 2]); let new_with_invalid = vec![1, 4, 3, 42, 2]; assert_ok!(CollatorSelection::set_invulnerables( @@ -65,7 +68,7 @@ fn it_should_set_invulnerables_even_with_some_invalid() { )); // should succeed and order them, but not include 42 - assert_eq!(CollatorSelection::invulnerables(), vec![1, 2, 3, 4]); + assert_eq!(Invulnerables::::get(), vec![1, 2, 3, 4]); }); } @@ -73,7 +76,7 @@ fn it_should_set_invulnerables_even_with_some_invalid() { fn add_invulnerable_works() { new_test_ext().execute_with(|| { initialize_to_block(1); - assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + assert_eq!(Invulnerables::::get(), vec![1, 2]); let new = 3; // function runs @@ -93,7 +96,7 @@ fn add_invulnerable_works() { ); // new element is now part of the invulnerables list - assert!(CollatorSelection::invulnerables().to_vec().contains(&new)); + assert!(Invulnerables::::get().to_vec().contains(&new)); // cannot add with non-root assert_noop!(CollatorSelection::add_invulnerable(RuntimeOrigin::signed(1), new), BadOrigin); @@ -113,7 +116,7 @@ fn add_invulnerable_works() { #[test] fn invulnerable_limit_works() { new_test_ext().execute_with(|| { - assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + assert_eq!(Invulnerables::::get(), vec![1, 2]); // MaxInvulnerables: u32 = 20 for ii in 3..=21 { @@ -140,7 +143,7 @@ fn invulnerable_limit_works() { } } let expected: Vec = (1..=20).collect(); - assert_eq!(CollatorSelection::invulnerables(), expected); + assert_eq!(Invulnerables::::get(), expected); // Cannot set too many Invulnerables let too_many_invulnerables: Vec = (1..=21).collect(); @@ -151,7 +154,7 @@ fn invulnerable_limit_works() { ), Error::::TooManyInvulnerables ); - assert_eq!(CollatorSelection::invulnerables(), expected); + assert_eq!(Invulnerables::::get(), expected); }); } @@ -159,7 +162,7 @@ fn invulnerable_limit_works() { fn remove_invulnerable_works() { new_test_ext().execute_with(|| { initialize_to_block(1); - assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + assert_eq!(Invulnerables::::get(), vec![1, 2]); assert_ok!(CollatorSelection::add_invulnerable( RuntimeOrigin::signed(RootAccount::get()), @@ -170,7 +173,7 @@ fn remove_invulnerable_works() { 3 )); - assert_eq!(CollatorSelection::invulnerables(), vec![1, 2, 3, 4]); + assert_eq!(Invulnerables::::get(), vec![1, 2, 3, 4]); assert_ok!(CollatorSelection::remove_invulnerable( RuntimeOrigin::signed(RootAccount::get()), @@ -180,7 +183,7 @@ fn remove_invulnerable_works() { System::assert_last_event(RuntimeEvent::CollatorSelection( crate::Event::InvulnerableRemoved { account_id: 2 }, )); - assert_eq!(CollatorSelection::invulnerables(), vec![1, 3, 4]); + assert_eq!(Invulnerables::::get(), vec![1, 3, 4]); // cannot remove invulnerable not in the list assert_noop!( @@ -200,11 +203,11 @@ fn remove_invulnerable_works() { fn candidate_to_invulnerable_works() { new_test_ext().execute_with(|| { initialize_to_block(1); - assert_eq!(CollatorSelection::desired_candidates(), 2); - assert_eq!(CollatorSelection::candidacy_bond(), 10); + assert_eq!(DesiredCandidates::::get(), 2); + assert_eq!(CandidacyBond::::get(), 10); - assert_eq!(>::get().iter().count(), 0); - assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + assert_eq!(CandidateList::::get().iter().count(), 0); + assert_eq!(Invulnerables::::get(), vec![1, 2]); assert_eq!(Balances::free_balance(3), 100); assert_eq!(Balances::free_balance(4), 100); @@ -225,9 +228,9 @@ fn candidate_to_invulnerable_works() { System::assert_has_event(RuntimeEvent::CollatorSelection( crate::Event::InvulnerableAdded { account_id: 3 }, )); - assert!(CollatorSelection::invulnerables().to_vec().contains(&3)); + assert!(Invulnerables::::get().to_vec().contains(&3)); assert_eq!(Balances::free_balance(3), 100); - assert_eq!(>::get().iter().count(), 1); + assert_eq!(CandidateList::::get().iter().count(), 1); assert_ok!(CollatorSelection::add_invulnerable( RuntimeOrigin::signed(RootAccount::get()), @@ -239,10 +242,10 @@ fn candidate_to_invulnerable_works() { System::assert_has_event(RuntimeEvent::CollatorSelection( crate::Event::InvulnerableAdded { account_id: 4 }, )); - assert!(CollatorSelection::invulnerables().to_vec().contains(&4)); + assert!(Invulnerables::::get().to_vec().contains(&4)); assert_eq!(Balances::free_balance(4), 100); - assert_eq!(>::get().iter().count(), 0); + assert_eq!(CandidateList::::get().iter().count(), 0); }); } @@ -250,14 +253,14 @@ fn candidate_to_invulnerable_works() { fn set_desired_candidates_works() { new_test_ext().execute_with(|| { // given - assert_eq!(CollatorSelection::desired_candidates(), 2); + assert_eq!(DesiredCandidates::::get(), 2); // can set assert_ok!(CollatorSelection::set_desired_candidates( RuntimeOrigin::signed(RootAccount::get()), 7 )); - assert_eq!(CollatorSelection::desired_candidates(), 7); + assert_eq!(DesiredCandidates::::get(), 7); // rejects bad origin assert_noop!( @@ -271,16 +274,16 @@ fn set_desired_candidates_works() { fn set_candidacy_bond_empty_candidate_list() { new_test_ext().execute_with(|| { // given - assert_eq!(CollatorSelection::candidacy_bond(), 10); - assert!(>::get().is_empty()); + assert_eq!(CandidacyBond::::get(), 10); + assert!(CandidateList::::get().is_empty()); // can decrease without candidates assert_ok!(CollatorSelection::set_candidacy_bond( RuntimeOrigin::signed(RootAccount::get()), 7 )); - assert_eq!(CollatorSelection::candidacy_bond(), 7); - assert!(>::get().is_empty()); + assert_eq!(CandidacyBond::::get(), 7); + assert!(CandidateList::::get().is_empty()); // rejects bad origin. assert_noop!(CollatorSelection::set_candidacy_bond(RuntimeOrigin::signed(1), 8), BadOrigin); @@ -290,8 +293,8 @@ fn set_candidacy_bond_empty_candidate_list() { RuntimeOrigin::signed(RootAccount::get()), 20 )); - assert!(>::get().is_empty()); - assert_eq!(CollatorSelection::candidacy_bond(), 20); + assert!(CandidateList::::get().is_empty()); + assert_eq!(CandidacyBond::::get(), 20); }); } @@ -299,36 +302,36 @@ fn set_candidacy_bond_empty_candidate_list() { fn set_candidacy_bond_with_one_candidate() { new_test_ext().execute_with(|| { // given - assert_eq!(CollatorSelection::candidacy_bond(), 10); - assert!(>::get().is_empty()); + assert_eq!(CandidacyBond::::get(), 10); + assert!(CandidateList::::get().is_empty()); let candidate_3 = CandidateInfo { who: 3, deposit: 10 }; assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); - assert_eq!(>::get(), vec![candidate_3.clone()]); + assert_eq!(CandidateList::::get(), vec![candidate_3.clone()]); // can decrease with one candidate assert_ok!(CollatorSelection::set_candidacy_bond( RuntimeOrigin::signed(RootAccount::get()), 7 )); - assert_eq!(CollatorSelection::candidacy_bond(), 7); - assert_eq!(>::get(), vec![candidate_3.clone()]); + assert_eq!(CandidacyBond::::get(), 7); + assert_eq!(CandidateList::::get(), vec![candidate_3.clone()]); // can increase up to initial deposit assert_ok!(CollatorSelection::set_candidacy_bond( RuntimeOrigin::signed(RootAccount::get()), 10 )); - assert_eq!(CollatorSelection::candidacy_bond(), 10); - assert_eq!(>::get(), vec![candidate_3.clone()]); + assert_eq!(CandidacyBond::::get(), 10); + assert_eq!(CandidateList::::get(), vec![candidate_3.clone()]); // can increase past initial deposit, should kick existing candidate assert_ok!(CollatorSelection::set_candidacy_bond( RuntimeOrigin::signed(RootAccount::get()), 20 )); - assert!(>::get().is_empty()); + assert!(CandidateList::::get().is_empty()); }); } @@ -336,8 +339,8 @@ fn set_candidacy_bond_with_one_candidate() { fn set_candidacy_bond_with_many_candidates_same_deposit() { new_test_ext().execute_with(|| { // given - assert_eq!(CollatorSelection::candidacy_bond(), 10); - assert!(>::get().is_empty()); + assert_eq!(CandidacyBond::::get(), 10); + assert!(CandidateList::::get().is_empty()); let candidate_3 = CandidateInfo { who: 3, deposit: 10 }; let candidate_4 = CandidateInfo { who: 4, deposit: 10 }; @@ -347,7 +350,7 @@ fn set_candidacy_bond_with_many_candidates_same_deposit() { assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5))); assert_eq!( - >::get(), + CandidateList::::get(), vec![candidate_5.clone(), candidate_4.clone(), candidate_3.clone()] ); @@ -356,9 +359,9 @@ fn set_candidacy_bond_with_many_candidates_same_deposit() { RuntimeOrigin::signed(RootAccount::get()), 7 )); - assert_eq!(CollatorSelection::candidacy_bond(), 7); + assert_eq!(CandidacyBond::::get(), 7); assert_eq!( - >::get(), + CandidateList::::get(), vec![candidate_5.clone(), candidate_4.clone(), candidate_3.clone()] ); @@ -367,9 +370,9 @@ fn set_candidacy_bond_with_many_candidates_same_deposit() { RuntimeOrigin::signed(RootAccount::get()), 10 )); - assert_eq!(CollatorSelection::candidacy_bond(), 10); + assert_eq!(CandidacyBond::::get(), 10); assert_eq!( - >::get(), + CandidateList::::get(), vec![candidate_5.clone(), candidate_4.clone(), candidate_3.clone()] ); @@ -378,7 +381,7 @@ fn set_candidacy_bond_with_many_candidates_same_deposit() { RuntimeOrigin::signed(RootAccount::get()), 20 )); - assert!(>::get().is_empty()); + assert!(CandidateList::::get().is_empty()); }); } @@ -386,8 +389,8 @@ fn set_candidacy_bond_with_many_candidates_same_deposit() { fn set_candidacy_bond_with_many_candidates_different_deposits() { new_test_ext().execute_with(|| { // given - assert_eq!(CollatorSelection::candidacy_bond(), 10); - assert!(>::get().is_empty()); + assert_eq!(CandidacyBond::::get(), 10); + assert!(CandidateList::::get().is_empty()); let candidate_3 = CandidateInfo { who: 3, deposit: 10 }; let candidate_4 = CandidateInfo { who: 4, deposit: 20 }; @@ -399,7 +402,7 @@ fn set_candidacy_bond_with_many_candidates_different_deposits() { assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 30)); assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 20)); assert_eq!( - >::get(), + CandidateList::::get(), vec![candidate_3.clone(), candidate_4.clone(), candidate_5.clone()] ); @@ -408,9 +411,9 @@ fn set_candidacy_bond_with_many_candidates_different_deposits() { RuntimeOrigin::signed(RootAccount::get()), 7 )); - assert_eq!(CollatorSelection::candidacy_bond(), 7); + assert_eq!(CandidacyBond::::get(), 7); assert_eq!( - >::get(), + CandidateList::::get(), vec![candidate_3.clone(), candidate_4.clone(), candidate_5.clone()] ); // can increase up to initial deposit @@ -418,9 +421,9 @@ fn set_candidacy_bond_with_many_candidates_different_deposits() { RuntimeOrigin::signed(RootAccount::get()), 10 )); - assert_eq!(CollatorSelection::candidacy_bond(), 10); + assert_eq!(CandidacyBond::::get(), 10); assert_eq!( - >::get(), + CandidateList::::get(), vec![candidate_3.clone(), candidate_4.clone(), candidate_5.clone()] ); @@ -429,27 +432,24 @@ fn set_candidacy_bond_with_many_candidates_different_deposits() { RuntimeOrigin::signed(RootAccount::get()), 20 )); - assert_eq!(CollatorSelection::candidacy_bond(), 20); - assert_eq!( - >::get(), - vec![candidate_4.clone(), candidate_5.clone()] - ); + assert_eq!(CandidacyBond::::get(), 20); + assert_eq!(CandidateList::::get(), vec![candidate_4.clone(), candidate_5.clone()]); // can increase past 4's deposit, should kick 4 assert_ok!(CollatorSelection::set_candidacy_bond( RuntimeOrigin::signed(RootAccount::get()), 25 )); - assert_eq!(CollatorSelection::candidacy_bond(), 25); - assert_eq!(>::get(), vec![candidate_5.clone()]); + assert_eq!(CandidacyBond::::get(), 25); + assert_eq!(CandidateList::::get(), vec![candidate_5.clone()]); // lowering the minimum deposit should have no effect assert_ok!(CollatorSelection::set_candidacy_bond( RuntimeOrigin::signed(RootAccount::get()), 5 )); - assert_eq!(CollatorSelection::candidacy_bond(), 5); - assert_eq!(>::get(), vec![candidate_5.clone()]); + assert_eq!(CandidacyBond::::get(), 5); + assert_eq!(CandidateList::::get(), vec![candidate_5.clone()]); // add 3 and 4 back but with higher deposits than minimum assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); @@ -457,7 +457,7 @@ fn set_candidacy_bond_with_many_candidates_different_deposits() { assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 10)); assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 20)); assert_eq!( - >::get(), + CandidateList::::get(), vec![candidate_3.clone(), candidate_4.clone(), candidate_5.clone()] ); @@ -467,8 +467,8 @@ fn set_candidacy_bond_with_many_candidates_different_deposits() { RuntimeOrigin::signed(RootAccount::get()), 40 )); - assert_eq!(CollatorSelection::candidacy_bond(), 40); - assert!(>::get().is_empty()); + assert_eq!(CandidacyBond::::get(), 40); + assert!(CandidateList::::get().is_empty()); }); } @@ -500,8 +500,8 @@ fn cannot_register_candidate_if_too_many() { #[test] fn cannot_unregister_candidate_if_too_few() { new_test_ext().execute_with(|| { - assert_eq!(>::get().iter().count(), 0); - assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + assert_eq!(CandidateList::::get().iter().count(), 0); + assert_eq!(Invulnerables::::get(), vec![1, 2]); assert_ok!(CollatorSelection::remove_invulnerable( RuntimeOrigin::signed(RootAccount::get()), 1 @@ -532,7 +532,7 @@ fn cannot_unregister_candidate_if_too_few() { #[test] fn cannot_register_as_candidate_if_invulnerable() { new_test_ext().execute_with(|| { - assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + assert_eq!(Invulnerables::::get(), vec![1, 2]); // can't 1 because it is invulnerable. assert_noop!( @@ -561,10 +561,10 @@ fn cannot_register_dupe_candidate() { // tuple of (id, deposit). let addition = CandidateInfo { who: 3, deposit: 10 }; assert_eq!( - >::get().iter().cloned().collect::>(), + CandidateList::::get().iter().cloned().collect::>(), vec![addition] ); - assert_eq!(CollatorSelection::last_authored_block(3), 10); + assert_eq!(LastAuthoredBlock::::get(3), 10); assert_eq!(Balances::free_balance(3), 90); // but no more @@ -596,11 +596,11 @@ fn cannot_register_as_candidate_if_poor() { fn register_as_candidate_works() { new_test_ext().execute_with(|| { // given - assert_eq!(CollatorSelection::desired_candidates(), 2); - assert_eq!(CollatorSelection::candidacy_bond(), 10); + assert_eq!(DesiredCandidates::::get(), 2); + assert_eq!(CandidacyBond::::get(), 10); - assert_eq!(>::get().iter().count(), 0); - assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + assert_eq!(CandidateList::::get().iter().count(), 0); + assert_eq!(Invulnerables::::get(), vec![1, 2]); // take two endowed, non-invulnerables accounts. assert_eq!(Balances::free_balance(3), 100); @@ -612,14 +612,14 @@ fn register_as_candidate_works() { assert_eq!(Balances::free_balance(3), 90); assert_eq!(Balances::free_balance(4), 90); - assert_eq!(>::get().iter().count(), 2); + assert_eq!(CandidateList::::get().iter().count(), 2); }); } #[test] fn cannot_take_candidate_slot_if_invulnerable() { new_test_ext().execute_with(|| { - assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + assert_eq!(Invulnerables::::get(), vec![1, 2]); // can't 1 because it is invulnerable. assert_noop!( @@ -649,11 +649,10 @@ fn cannot_take_candidate_slot_if_duplicate() { // tuple of (id, deposit). let candidate_3 = CandidateInfo { who: 3, deposit: 10 }; let candidate_4 = CandidateInfo { who: 4, deposit: 10 }; - let actual_candidates = - >::get().iter().cloned().collect::>(); + let actual_candidates = CandidateList::::get().iter().cloned().collect::>(); assert_eq!(actual_candidates, vec![candidate_4, candidate_3]); - assert_eq!(CollatorSelection::last_authored_block(3), 10); - assert_eq!(CollatorSelection::last_authored_block(4), 10); + assert_eq!(LastAuthoredBlock::::get(3), 10); + assert_eq!(LastAuthoredBlock::::get(4), 10); assert_eq!(Balances::free_balance(3), 90); // but no more @@ -672,10 +671,10 @@ fn cannot_take_candidate_slot_if_target_invalid() { // tuple of (id, deposit). let candidate_3 = CandidateInfo { who: 3, deposit: 10 }; assert_eq!( - >::get().iter().cloned().collect::>(), + CandidateList::::get().iter().cloned().collect::>(), vec![candidate_3] ); - assert_eq!(CollatorSelection::last_authored_block(3), 10); + assert_eq!(LastAuthoredBlock::::get(3), 10); assert_eq!(Balances::free_balance(3), 90); assert_eq!(Balances::free_balance(4), 100); @@ -744,11 +743,11 @@ fn cannot_take_candidate_slot_if_deposit_less_than_target() { fn take_candidate_slot_works() { new_test_ext().execute_with(|| { // given - assert_eq!(CollatorSelection::desired_candidates(), 2); - assert_eq!(CollatorSelection::candidacy_bond(), 10); + assert_eq!(DesiredCandidates::::get(), 2); + assert_eq!(CandidacyBond::::get(), 10); - assert_eq!(>::get().iter().count(), 0); - assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + assert_eq!(CandidateList::::get().iter().count(), 0); + assert_eq!(Invulnerables::::get(), vec![1, 2]); // take two endowed, non-invulnerables accounts. assert_eq!(Balances::free_balance(3), 100); @@ -763,7 +762,7 @@ fn take_candidate_slot_works() { assert_eq!(Balances::free_balance(4), 90); assert_eq!(Balances::free_balance(5), 90); - assert_eq!(>::get().iter().count(), 3); + assert_eq!(CandidateList::::get().iter().count(), 3); Balances::make_free_balance_be(&6, 100); let key = MockSessionKeys { aura: UintAuthorityId(6) }; @@ -785,10 +784,10 @@ fn take_candidate_slot_works() { let candidate_6 = CandidateInfo { who: 6, deposit: 50 }; let candidate_5 = CandidateInfo { who: 5, deposit: 10 }; let mut actual_candidates = - >::get().iter().cloned().collect::>(); + CandidateList::::get().iter().cloned().collect::>(); actual_candidates.sort_by(|info_1, info_2| info_1.deposit.cmp(&info_2.deposit)); assert_eq!( - >::get().iter().cloned().collect::>(), + CandidateList::::get().iter().cloned().collect::>(), vec![candidate_5, candidate_3, candidate_6] ); }); @@ -798,11 +797,11 @@ fn take_candidate_slot_works() { fn increase_candidacy_bond_non_candidate_account() { new_test_ext().execute_with(|| { // given - assert_eq!(CollatorSelection::desired_candidates(), 2); - assert_eq!(CollatorSelection::candidacy_bond(), 10); + assert_eq!(DesiredCandidates::::get(), 2); + assert_eq!(CandidacyBond::::get(), 10); - assert_eq!(>::get().iter().count(), 0); - assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + assert_eq!(CandidateList::::get().iter().count(), 0); + assert_eq!(Invulnerables::::get(), vec![1, 2]); assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); @@ -818,11 +817,11 @@ fn increase_candidacy_bond_non_candidate_account() { fn increase_candidacy_bond_insufficient_balance() { new_test_ext().execute_with(|| { // given - assert_eq!(CollatorSelection::desired_candidates(), 2); - assert_eq!(CollatorSelection::candidacy_bond(), 10); + assert_eq!(DesiredCandidates::::get(), 2); + assert_eq!(CandidacyBond::::get(), 10); - assert_eq!(>::get().iter().count(), 0); - assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + assert_eq!(CandidateList::::get().iter().count(), 0); + assert_eq!(Invulnerables::::get(), vec![1, 2]); // take two endowed, non-invulnerables accounts. assert_eq!(Balances::free_balance(3), 100); @@ -850,11 +849,11 @@ fn increase_candidacy_bond_insufficient_balance() { fn increase_candidacy_bond_works() { new_test_ext().execute_with(|| { // given - assert_eq!(CollatorSelection::desired_candidates(), 2); - assert_eq!(CollatorSelection::candidacy_bond(), 10); + assert_eq!(DesiredCandidates::::get(), 2); + assert_eq!(CandidacyBond::::get(), 10); - assert_eq!(>::get().iter().count(), 0); - assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + assert_eq!(CandidateList::::get().iter().count(), 0); + assert_eq!(Invulnerables::::get(), vec![1, 2]); // take three endowed, non-invulnerables accounts. assert_eq!(Balances::free_balance(3), 100); @@ -873,7 +872,7 @@ fn increase_candidacy_bond_works() { assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 30)); assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 40)); - assert_eq!(>::get().iter().count(), 3); + assert_eq!(CandidateList::::get().iter().count(), 3); assert_eq!(Balances::free_balance(3), 80); assert_eq!(Balances::free_balance(4), 70); assert_eq!(Balances::free_balance(5), 60); @@ -881,7 +880,7 @@ fn increase_candidacy_bond_works() { assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 40)); assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 60)); - assert_eq!(>::get().iter().count(), 3); + assert_eq!(CandidateList::::get().iter().count(), 3); assert_eq!(Balances::free_balance(3), 60); assert_eq!(Balances::free_balance(4), 40); assert_eq!(Balances::free_balance(5), 60); @@ -892,11 +891,11 @@ fn increase_candidacy_bond_works() { fn decrease_candidacy_bond_non_candidate_account() { new_test_ext().execute_with(|| { // given - assert_eq!(CollatorSelection::desired_candidates(), 2); - assert_eq!(CollatorSelection::candidacy_bond(), 10); + assert_eq!(DesiredCandidates::::get(), 2); + assert_eq!(CandidacyBond::::get(), 10); - assert_eq!(>::get().iter().count(), 0); - assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + assert_eq!(CandidateList::::get().iter().count(), 0); + assert_eq!(Invulnerables::::get(), vec![1, 2]); assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); @@ -914,11 +913,11 @@ fn decrease_candidacy_bond_non_candidate_account() { fn decrease_candidacy_bond_insufficient_funds() { new_test_ext().execute_with(|| { // given - assert_eq!(CollatorSelection::desired_candidates(), 2); - assert_eq!(CollatorSelection::candidacy_bond(), 10); + assert_eq!(DesiredCandidates::::get(), 2); + assert_eq!(CandidacyBond::::get(), 10); - assert_eq!(>::get().iter().count(), 0); - assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + assert_eq!(CandidateList::::get().iter().count(), 0); + assert_eq!(Invulnerables::::get(), vec![1, 2]); // take two endowed, non-invulnerables accounts. assert_eq!(Balances::free_balance(3), 100); @@ -961,7 +960,7 @@ fn decrease_candidacy_bond_insufficient_funds() { #[test] fn decrease_candidacy_bond_occupying_top_slot() { new_test_ext().execute_with(|| { - assert_eq!(CollatorSelection::desired_candidates(), 2); + assert_eq!(DesiredCandidates::::get(), 2); // Register 3 candidates. assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); @@ -976,7 +975,7 @@ fn decrease_candidacy_bond_occupying_top_slot() { let candidate_4 = CandidateInfo { who: 4, deposit: 30 }; let candidate_5 = CandidateInfo { who: 5, deposit: 60 }; assert_eq!( - >::get().iter().cloned().collect::>(), + CandidateList::::get().iter().cloned().collect::>(), vec![candidate_4, candidate_3, candidate_5] ); @@ -1000,7 +999,7 @@ fn decrease_candidacy_bond_occupying_top_slot() { let candidate_4 = CandidateInfo { who: 4, deposit: 35 }; let candidate_5 = CandidateInfo { who: 5, deposit: 60 }; assert_eq!( - >::get().iter().cloned().collect::>(), + CandidateList::::get().iter().cloned().collect::>(), vec![candidate_3, candidate_4, candidate_5] ); @@ -1023,11 +1022,11 @@ fn decrease_candidacy_bond_occupying_top_slot() { fn decrease_candidacy_bond_works() { new_test_ext().execute_with(|| { // given - assert_eq!(CollatorSelection::desired_candidates(), 2); - assert_eq!(CollatorSelection::candidacy_bond(), 10); + assert_eq!(DesiredCandidates::::get(), 2); + assert_eq!(CandidacyBond::::get(), 10); - assert_eq!(>::get().iter().count(), 0); - assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + assert_eq!(CandidateList::::get().iter().count(), 0); + assert_eq!(Invulnerables::::get(), vec![1, 2]); // take three endowed, non-invulnerables accounts. assert_eq!(Balances::free_balance(3), 100); @@ -1046,14 +1045,14 @@ fn decrease_candidacy_bond_works() { assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 30)); assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 40)); - assert_eq!(>::get().iter().count(), 3); + assert_eq!(CandidateList::::get().iter().count(), 3); assert_eq!(Balances::free_balance(3), 80); assert_eq!(Balances::free_balance(4), 70); assert_eq!(Balances::free_balance(5), 60); assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 10)); - assert_eq!(>::get().iter().count(), 3); + assert_eq!(CandidateList::::get().iter().count(), 3); assert_eq!(Balances::free_balance(3), 90); assert_eq!(Balances::free_balance(4), 70); assert_eq!(Balances::free_balance(5), 60); @@ -1064,11 +1063,11 @@ fn decrease_candidacy_bond_works() { fn update_candidacy_bond_with_identical_amount() { new_test_ext().execute_with(|| { // given - assert_eq!(CollatorSelection::desired_candidates(), 2); - assert_eq!(CollatorSelection::candidacy_bond(), 10); + assert_eq!(DesiredCandidates::::get(), 2); + assert_eq!(CandidacyBond::::get(), 10); - assert_eq!(>::get().iter().count(), 0); - assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + assert_eq!(CandidateList::::get().iter().count(), 0); + assert_eq!(Invulnerables::::get(), vec![1, 2]); // take three endowed, non-invulnerables accounts. assert_eq!(Balances::free_balance(3), 100); @@ -1087,7 +1086,7 @@ fn update_candidacy_bond_with_identical_amount() { assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 30)); assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 40)); - assert_eq!(>::get().iter().count(), 3); + assert_eq!(CandidateList::::get().iter().count(), 3); assert_eq!(Balances::free_balance(3), 80); assert_eq!(Balances::free_balance(4), 70); assert_eq!(Balances::free_balance(5), 60); @@ -1104,11 +1103,11 @@ fn update_candidacy_bond_with_identical_amount() { fn candidate_list_works() { new_test_ext().execute_with(|| { // given - assert_eq!(CollatorSelection::desired_candidates(), 2); - assert_eq!(CollatorSelection::candidacy_bond(), 10); + assert_eq!(DesiredCandidates::::get(), 2); + assert_eq!(CandidacyBond::::get(), 10); - assert_eq!(>::get().iter().count(), 0); - assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + assert_eq!(CandidateList::::get().iter().count(), 0); + assert_eq!(Invulnerables::::get(), vec![1, 2]); // take three endowed, non-invulnerables accounts. assert_eq!(Balances::free_balance(3), 100); @@ -1131,7 +1130,7 @@ fn candidate_list_works() { let candidate_4 = CandidateInfo { who: 4, deposit: 25 }; let candidate_5 = CandidateInfo { who: 5, deposit: 10 }; assert_eq!( - >::get().iter().cloned().collect::>(), + CandidateList::::get().iter().cloned().collect::>(), vec![candidate_5, candidate_4, candidate_3] ); }); @@ -1157,7 +1156,7 @@ fn leave_intent() { // bond is returned assert_ok!(CollatorSelection::leave_intent(RuntimeOrigin::signed(3))); assert_eq!(Balances::free_balance(3), 100); - assert_eq!(CollatorSelection::last_authored_block(3), 0); + assert_eq!(LastAuthoredBlock::::get(3), 0); }); } @@ -1177,10 +1176,10 @@ fn authorship_event_handler() { let collator = CandidateInfo { who: 4, deposit: 10 }; assert_eq!( - >::get().iter().cloned().collect::>(), + CandidateList::::get().iter().cloned().collect::>(), vec![collator] ); - assert_eq!(CollatorSelection::last_authored_block(4), 0); + assert_eq!(LastAuthoredBlock::::get(4), 0); // half of the pot goes to the collator who's the author (4 in tests). assert_eq!(Balances::free_balance(4), 140); @@ -1206,10 +1205,10 @@ fn fees_edgecases() { let collator = CandidateInfo { who: 4, deposit: 10 }; assert_eq!( - >::get().iter().cloned().collect::>(), + CandidateList::::get().iter().cloned().collect::>(), vec![collator] ); - assert_eq!(CollatorSelection::last_authored_block(4), 0); + assert_eq!(LastAuthoredBlock::::get(4), 0); // Nothing received assert_eq!(Balances::free_balance(4), 90); // all fee stays @@ -1236,7 +1235,7 @@ fn session_management_single_candidate() { // session won't see this. assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); // but we have a new candidate. - assert_eq!(>::get().iter().count(), 1); + assert_eq!(CandidateList::::get().iter().count(), 1); initialize_to_block(10); assert_eq!(SessionChangeBlock::get(), 10); @@ -1274,7 +1273,7 @@ fn session_management_max_candidates() { // session won't see this. assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); // but we have a new candidate. - assert_eq!(>::get().iter().count(), 3); + assert_eq!(CandidateList::::get().iter().count(), 3); initialize_to_block(10); assert_eq!(SessionChangeBlock::get(), 10); @@ -1313,7 +1312,7 @@ fn session_management_increase_bid_with_list_update() { // session won't see this. assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); // but we have a new candidate. - assert_eq!(>::get().iter().count(), 3); + assert_eq!(CandidateList::::get().iter().count(), 3); initialize_to_block(10); assert_eq!(SessionChangeBlock::get(), 10); @@ -1352,7 +1351,7 @@ fn session_management_candidate_list_eager_sort() { // session won't see this. assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); // but we have a new candidate. - assert_eq!(>::get().iter().count(), 3); + assert_eq!(CandidateList::::get().iter().count(), 3); initialize_to_block(10); assert_eq!(SessionChangeBlock::get(), 10); @@ -1399,7 +1398,7 @@ fn session_management_reciprocal_outbidding() { // session won't see this. assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); // but we have a new candidate. - assert_eq!(>::get().iter().count(), 3); + assert_eq!(CandidateList::::get().iter().count(), 3); initialize_to_block(10); assert_eq!(SessionChangeBlock::get(), 10); @@ -1451,7 +1450,7 @@ fn session_management_decrease_bid_after_auction() { // session won't see this. assert_eq!(SessionHandlerCollators::get(), vec![1, 2]); // but we have a new candidate. - assert_eq!(>::get().iter().count(), 3); + assert_eq!(CandidateList::::get().iter().count(), 3); initialize_to_block(10); assert_eq!(SessionChangeBlock::get(), 10); @@ -1476,20 +1475,20 @@ fn kick_mechanism() { assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); initialize_to_block(10); - assert_eq!(>::get().iter().count(), 2); + assert_eq!(CandidateList::::get().iter().count(), 2); initialize_to_block(20); assert_eq!(SessionChangeBlock::get(), 20); // 4 authored this block, gets to stay 3 was kicked - assert_eq!(>::get().iter().count(), 1); + assert_eq!(CandidateList::::get().iter().count(), 1); // 3 will be kicked after 1 session delay assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 3, 4]); // tuple of (id, deposit). let collator = CandidateInfo { who: 4, deposit: 10 }; assert_eq!( - >::get().iter().cloned().collect::>(), + CandidateList::::get().iter().cloned().collect::>(), vec![collator] ); - assert_eq!(CollatorSelection::last_authored_block(4), 20); + assert_eq!(LastAuthoredBlock::::get(4), 20); initialize_to_block(30); // 3 gets kicked after 1 session delay assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 4]); @@ -1503,8 +1502,8 @@ fn should_not_kick_mechanism_too_few() { new_test_ext().execute_with(|| { // remove the invulnerables and add new collators 3 and 5 - assert_eq!(>::get().iter().count(), 0); - assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]); + assert_eq!(CandidateList::::get().iter().count(), 0); + assert_eq!(Invulnerables::::get(), vec![1, 2]); assert_ok!(CollatorSelection::remove_invulnerable( RuntimeOrigin::signed(RootAccount::get()), 1 @@ -1517,21 +1516,21 @@ fn should_not_kick_mechanism_too_few() { )); initialize_to_block(10); - assert_eq!(>::get().iter().count(), 2); + assert_eq!(CandidateList::::get().iter().count(), 2); initialize_to_block(20); assert_eq!(SessionChangeBlock::get(), 20); // 4 authored this block, 3 is kicked, 5 stays because of too few collators - assert_eq!(>::get().iter().count(), 1); + assert_eq!(CandidateList::::get().iter().count(), 1); // 3 will be kicked after 1 session delay assert_eq!(SessionHandlerCollators::get(), vec![3, 5]); // tuple of (id, deposit). let collator = CandidateInfo { who: 3, deposit: 10 }; assert_eq!( - >::get().iter().cloned().collect::>(), + CandidateList::::get().iter().cloned().collect::>(), vec![collator] ); - assert_eq!(CollatorSelection::last_authored_block(4), 20); + assert_eq!(LastAuthoredBlock::::get(4), 20); initialize_to_block(30); // 3 gets kicked after 1 session delay @@ -1544,7 +1543,7 @@ fn should_not_kick_mechanism_too_few() { #[test] fn should_kick_invulnerables_from_candidates_on_session_change() { new_test_ext().execute_with(|| { - assert_eq!(>::get().iter().count(), 0); + assert_eq!(CandidateList::::get().iter().count(), 0); assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3))); assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4))); assert_eq!(Balances::free_balance(3), 90); @@ -1558,20 +1557,19 @@ fn should_kick_invulnerables_from_candidates_on_session_change() { let collator_3 = CandidateInfo { who: 3, deposit: 10 }; let collator_4 = CandidateInfo { who: 4, deposit: 10 }; - let actual_candidates = - >::get().iter().cloned().collect::>(); + let actual_candidates = CandidateList::::get().iter().cloned().collect::>(); assert_eq!(actual_candidates, vec![collator_4.clone(), collator_3]); - assert_eq!(CollatorSelection::invulnerables(), vec![1, 2, 3]); + assert_eq!(Invulnerables::::get(), vec![1, 2, 3]); // session change initialize_to_block(10); // 3 is removed from candidates assert_eq!( - >::get().iter().cloned().collect::>(), + CandidateList::::get().iter().cloned().collect::>(), vec![collator_4] ); // but not from invulnerables - assert_eq!(CollatorSelection::invulnerables(), vec![1, 2, 3]); + assert_eq!(Invulnerables::::get(), vec![1, 2, 3]); // and it got its deposit back assert_eq!(Balances::free_balance(3), 100); }); diff --git a/cumulus/pallets/parachain-system/src/lib.rs b/cumulus/pallets/parachain-system/src/lib.rs index 81965a2a313..1c01ef33c7e 100644 --- a/cumulus/pallets/parachain-system/src/lib.rs +++ b/cumulus/pallets/parachain-system/src/lib.rs @@ -267,7 +267,7 @@ pub mod pallet { LastRelayChainBlockNumber::::put(vfp.relay_parent_number); - let host_config = match Self::host_configuration() { + let host_config = match HostConfiguration::::get() { Some(ok) => ok, None => { debug_assert!( @@ -281,7 +281,7 @@ pub mod pallet { // Before updating the relevant messaging state, we need to extract // the total bandwidth limits for the purpose of updating the unincluded // segment. - let total_bandwidth_out = match Self::relevant_messaging_state() { + let total_bandwidth_out = match RelevantMessagingState::::get() { Some(s) => OutboundBandwidthLimits::from_relay_chain_state(&s), None => { debug_assert!( @@ -298,7 +298,8 @@ pub mod pallet { Self::adjust_egress_bandwidth_limits(); let (ump_msg_count, ump_total_bytes) = >::mutate(|up| { - let (available_capacity, available_size) = match Self::relevant_messaging_state() { + let (available_capacity, available_size) = match RelevantMessagingState::::get() + { Some(limits) => ( limits.relay_dispatch_queue_remaining_capacity.remaining_count, limits.relay_dispatch_queue_remaining_capacity.remaining_size, @@ -476,7 +477,7 @@ pub mod pallet { // than the announced, we would waste some of weight. In the case the actual value is // greater than the announced, we will miss opportunity to send a couple of messages. weight += T::DbWeight::get().reads_writes(1, 1); - let hrmp_max_message_num_per_candidate = Self::host_configuration() + let hrmp_max_message_num_per_candidate = HostConfiguration::::get() .map(|cfg| cfg.hrmp_max_message_num_per_candidate) .unwrap_or(0); >::put(hrmp_max_message_num_per_candidate); @@ -764,7 +765,6 @@ pub mod pallet { /// [`:code`][sp_core::storage::well_known_keys::CODE] which will result the next block process /// with the new validation code. This concludes the upgrade process. #[pallet::storage] - #[pallet::getter(fn new_validation_function)] pub(super) type PendingValidationCode = StorageValue<_, Vec, ValueQuery>; /// Validation code that is set by the parachain and is to be communicated to collator and @@ -779,7 +779,6 @@ pub mod pallet { /// This value is expected to be set only once per block and it's never stored /// in the trie. #[pallet::storage] - #[pallet::getter(fn validation_data)] pub(super) type ValidationData = StorageValue<_, PersistedValidationData>; /// Were the validation data set to notify the relay chain? @@ -820,7 +819,6 @@ pub mod pallet { /// /// This data is also absent from the genesis. #[pallet::storage] - #[pallet::getter(fn relay_state_proof)] pub(super) type RelayStateProof = StorageValue<_, sp_trie::StorageProof>; /// The snapshot of some state related to messaging relevant to the current parachain as per @@ -831,7 +829,6 @@ pub mod pallet { /// /// This data is also absent from the genesis. #[pallet::storage] - #[pallet::getter(fn relevant_messaging_state)] pub(super) type RelevantMessagingState = StorageValue<_, MessagingStateSnapshot>; /// The parachain host configuration that was obtained from the relay parent. @@ -842,7 +839,6 @@ pub mod pallet { /// This data is also absent from the genesis. #[pallet::storage] #[pallet::disable_try_decode_storage] - #[pallet::getter(fn host_configuration)] pub(super) type HostConfiguration = StorageValue<_, AbridgedHostConfiguration>; /// The last downward message queue chain head we have observed. @@ -1041,7 +1037,7 @@ impl GetChannelInfo for Pallet { // // Here it a similar case, with the difference that the realization that the channel is // closed came the same block. - let channels = match Self::relevant_messaging_state() { + let channels = match RelevantMessagingState::::get() { None => { log::warn!("calling `get_channel_status` with no RelevantMessagingState?!"); return ChannelStatus::Closed @@ -1069,7 +1065,7 @@ impl GetChannelInfo for Pallet { } fn get_channel_info(id: ParaId) -> Option { - let channels = Self::relevant_messaging_state()?.egress_channels; + let channels = RelevantMessagingState::::get()?.egress_channels; let index = channels.binary_search_by_key(&id, |item| item.0).ok()?; let info = ChannelInfo { max_capacity: channels[index].1.max_capacity, @@ -1406,7 +1402,7 @@ impl Pallet { ensure!(>::get().is_none(), Error::::ProhibitedByPolkadot); ensure!(!>::exists(), Error::::OverlappingUpgrades); - let cfg = Self::host_configuration().ok_or(Error::::HostConfigurationNotAvailable)?; + let cfg = HostConfiguration::::get().ok_or(Error::::HostConfigurationNotAvailable)?; ensure!(validation_function.len() <= cfg.max_code_size as usize, Error::::TooBig); // When a code upgrade is scheduled, it has to be applied in two @@ -1562,7 +1558,7 @@ impl Pallet { // may change so that the message is no longer valid. // // However, changing this setting is expected to be rare. - if let Some(cfg) = Self::host_configuration() { + if let Some(cfg) = HostConfiguration::::get() { if message_len > cfg.max_upward_message_size as usize { return Err(MessageSendError::TooBig) } @@ -1718,14 +1714,14 @@ impl BlockNumberProvider for RelaychainDataProvider { type BlockNumber = relay_chain::BlockNumber; fn current_block_number() -> relay_chain::BlockNumber { - Pallet::::validation_data() + ValidationData::::get() .map(|d| d.relay_parent_number) .unwrap_or_else(|| Pallet::::last_relay_block_number()) } #[cfg(feature = "runtime-benchmarks")] fn set_block_number(block: Self::BlockNumber) { - let mut validation_data = Pallet::::validation_data().unwrap_or_else(|| + let mut validation_data = ValidationData::::get().unwrap_or_else(|| // PersistedValidationData does not impl default in non-std PersistedValidationData { parent_head: vec![].into(), @@ -1740,7 +1736,7 @@ impl BlockNumberProvider for RelaychainDataProvider { impl RelaychainStateProvider for RelaychainDataProvider { fn current_relay_chain_state() -> RelayChainState { - Pallet::::validation_data() + ValidationData::::get() .map(|d| RelayChainState { number: d.relay_parent_number, state_root: d.relay_parent_storage_root, @@ -1750,7 +1746,7 @@ impl RelaychainStateProvider for RelaychainDataProvider { #[cfg(feature = "runtime-benchmarks")] fn set_current_relay_chain_state(state: RelayChainState) { - let mut validation_data = Pallet::::validation_data().unwrap_or_else(|| + let mut validation_data = ValidationData::::get().unwrap_or_else(|| // PersistedValidationData does not impl default in non-std PersistedValidationData { parent_head: vec![].into(), diff --git a/cumulus/parachains/pallets/parachain-info/src/lib.rs b/cumulus/parachains/pallets/parachain-info/src/lib.rs index c17a6d5e146..a4ef448a6b6 100644 --- a/cumulus/parachains/pallets/parachain-info/src/lib.rs +++ b/cumulus/parachains/pallets/parachain-info/src/lib.rs @@ -54,7 +54,7 @@ pub mod pallet { #[pallet::genesis_build] impl BuildGenesisConfig for GenesisConfig { fn build(&self) { - >::put(self.parachain_id); + ParachainId::::put(self.parachain_id); } } @@ -64,13 +64,18 @@ pub mod pallet { } #[pallet::storage] - #[pallet::getter(fn parachain_id)] pub(super) type ParachainId = StorageValue<_, ParaId, ValueQuery, DefaultForParachainId>; impl Get for Pallet { fn get() -> ParaId { - Self::parachain_id() + ParachainId::::get() + } + } + + impl Pallet { + pub fn parachain_id() -> ParaId { + ParachainId::::get() } } } diff --git a/prdoc/pr_3471.prdoc b/prdoc/pr_3471.prdoc new file mode 100644 index 00000000000..0c16587fc90 --- /dev/null +++ b/prdoc/pr_3471.prdoc @@ -0,0 +1,33 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: removed `pallet::getter` from cumulus pallets + +doc: + - audience: Runtime Dev + description: | + This PR removes all the `pallet::getter` usages from cumulus pallets, and updates depdendant runtimes accordingly. + The ParaId can be retrieved using `>::get()`. + For other storage items, the syntax `StorageItem::::get()` should be used instead. + +crates: + - name: cumulus-pallet-aura-ext + - name: pallet-collator-selection + - name: cumulus-pallet-parachain-system + - name: staging-parachain-info + - name: parachain-template-runtime + - name: asset-hub-rococo-runtime + - name: asset-hub-westend-runtime + - name: bridge-hub-rococo-runtime + - name: bridge-hub-westend-runtime + - name: collectives-westend-runtime + - name: contracts-rococo-runtime + - name: coretime-rococo-runtime + - name: coretime-westend-runtime + - name: glutton-westend-runtime + - name: people-rococo-runtime + - name: people-westend-runtime + - name: shell-runtime + - name: penpal-runtime + - name: rococo-parachain-runtime + -- GitLab From e2ead8887681d2236cae4a0f05b05e4cb5bf63a7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Mar 2024 04:34:17 +0100 Subject: [PATCH 056/187] Bump the known_good_semver group with 2 updates (#3726) Bumps the known_good_semver group with 2 updates: [serde_yaml](https://github.com/dtolnay/serde-yaml) and [syn](https://github.com/dtolnay/syn). Updates `serde_yaml` from 0.9.32 to 0.9.33

Release notes

Sourced from serde_yaml's releases.

0.9.33

Commits
  • f4c9ed9 Release 0.9.33
  • b4edaee Pull in yaml_parser_fetch_more_tokens fix from libyaml
  • 8a5542c Resolve non_local_definitions warning in test
  • See full diff in compare view

Updates `syn` from 2.0.52 to 2.0.53
Release notes

Sourced from syn's releases.

2.0.53

  • Implement Copy, Clone, and ToTokens for syn::parse::Nothing (#1597)
Commits
  • 32dcf8d Release 2.0.53
  • fd1f2aa Merge pull request #1597 from dtolnay/copyprintnothing
  • 4f6c052 Implement ToTokens for syn::parse::Nothing
  • 3f37543 Implement Copy for syn::parse::Nothing
  • 36a4122 Update test suite to nightly-2024-03-16
  • bd93106 Revert "Temporarily disable nightly testing due to libLLVM link issue"
  • 06166a7 Update test suite to nightly-2024-03-09
  • ed545e7 Work around doc_markdown lint in test_precedence
  • 7aef1ed Temporarily disable nightly testing due to libLLVM link issue
  • 556b10b Update test suite to nightly-2024-03-06
  • Additional commits viewable in compare view

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 132 ++++++++++++++++++++++++++--------------------------- Cargo.toml | 2 +- 2 files changed, 67 insertions(+), 67 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d641f554431..5c0066e9728 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -191,7 +191,7 @@ checksum = "c0391754c09fab4eae3404d19d0d297aa1c670c1775ab51d8a5312afeca23157" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -206,7 +206,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", "syn-solidity", "tiny-keccak", ] @@ -347,7 +347,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -1228,7 +1228,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -1245,7 +1245,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -1427,7 +1427,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -2674,7 +2674,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -3895,7 +3895,7 @@ dependencies = [ "proc-macro-crate 3.0.0", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -4410,7 +4410,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -4450,7 +4450,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -4467,7 +4467,7 @@ checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -4675,7 +4675,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -4745,7 +4745,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.52", + "syn 2.0.53", "termcolor", "walkdir", ] @@ -4762,7 +4762,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.52", + "syn 2.0.53", "termcolor", "toml 0.8.8", "walkdir", @@ -4990,7 +4990,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -5001,7 +5001,7 @@ checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -5191,7 +5191,7 @@ dependencies = [ "fs-err", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -5578,7 +5578,7 @@ dependencies = [ "quote", "scale-info", "sp-arithmetic", - "syn 2.0.52", + "syn 2.0.53", "trybuild", ] @@ -5735,7 +5735,7 @@ dependencies = [ "quote", "regex", "sp-crypto-hashing", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -5746,7 +5746,7 @@ dependencies = [ "proc-macro-crate 3.0.0", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -5755,7 +5755,7 @@ version = "11.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -5988,7 +5988,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -7933,7 +7933,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -7947,7 +7947,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -7958,7 +7958,7 @@ checksum = "9ea73aa640dc01d62a590d48c0c3521ed739d53b27f919b25c3551e233481654" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -7969,7 +7969,7 @@ checksum = "ef9d79ae96aaba821963320eb2b6e34d17df1e5a83d8a1985c29cc5be59577b3" dependencies = [ "macro_magic_core", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -9630,7 +9630,7 @@ version = "18.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -10858,7 +10858,7 @@ dependencies = [ "proc-macro2", "quote", "sp-runtime", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -11953,7 +11953,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -11994,7 +11994,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -13891,7 +13891,7 @@ dependencies = [ "polkavm-common", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -13901,7 +13901,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429" dependencies = [ "polkavm-derive-impl", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -14097,7 +14097,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" dependencies = [ "proc-macro2", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -14188,7 +14188,7 @@ checksum = "9b698b0b09d40e9b7c1a47b132d66a8b54bcd20583d9b6d06e4535e383b4405c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -14260,7 +14260,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -14360,7 +14360,7 @@ dependencies = [ "itertools 0.11.0", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -14703,7 +14703,7 @@ checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -15194,7 +15194,7 @@ dependencies = [ "regex", "relative-path", "rustc_version 0.4.0", - "syn 2.0.52", + "syn 2.0.53", "unicode-ident", ] @@ -15648,7 +15648,7 @@ dependencies = [ "proc-macro-crate 3.0.0", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -16930,7 +16930,7 @@ dependencies = [ "proc-macro-crate 3.0.0", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -17332,7 +17332,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -17389,9 +17389,9 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.32" +version = "0.9.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd075d994154d4a774f95b51fb96bdc2832b0ea48425c92546073816cda1f2f" +checksum = "a0623d197252096520c6f2a5e1171ee436e5af99a5d7caa2891e55e61950e6d9" dependencies = [ "indexmap 2.2.3", "itoa", @@ -17432,7 +17432,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -18340,7 +18340,7 @@ dependencies = [ "proc-macro-crate 3.0.0", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -18723,7 +18723,7 @@ version = "0.0.0" dependencies = [ "quote", "sp-crypto-hashing", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -18741,7 +18741,7 @@ source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf5 dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -18750,7 +18750,7 @@ version = "14.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -19018,7 +19018,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -19030,7 +19030,7 @@ dependencies = [ "proc-macro-crate 3.0.0", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -19292,7 +19292,7 @@ dependencies = [ "proc-macro2", "quote", "sp-version", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -19735,7 +19735,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -20132,9 +20132,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.52" +version = "2.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" dependencies = [ "proc-macro2", "quote", @@ -20150,7 +20150,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -20415,7 +20415,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -20576,7 +20576,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -20783,7 +20783,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -20825,7 +20825,7 @@ dependencies = [ "proc-macro-crate 3.0.0", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -21180,9 +21180,9 @@ dependencies = [ [[package]] name = "unsafe-libyaml" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] name = "unsigned-varint" @@ -21390,7 +21390,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", "wasm-bindgen-shared", ] @@ -21424,7 +21424,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -22441,7 +22441,7 @@ dependencies = [ "proc-macro2", "quote", "staging-xcm", - "syn 2.0.52", + "syn 2.0.53", "trybuild", ] @@ -22563,7 +22563,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -22583,7 +22583,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 3acb6c1d055..01d6ef8e87b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -554,7 +554,7 @@ serde-big-array = { version = "0.3.2" } serde_derive = { version = "1.0.117" } serde_json = { version = "1.0.114", default-features = false } serde_yaml = { version = "0.9" } -syn = { version = "2.0.52" } +syn = { version = "2.0.53" } thiserror = { version = "1.0.48" } [profile.release] -- GitLab From 8b3bf39ab85ff7146e06e7c8236475bfa4e3bf39 Mon Sep 17 00:00:00 2001 From: Juan Ignacio Rios <54085674+JuaniRios@users.noreply.github.com> Date: Tue, 19 Mar 2024 09:12:39 +0100 Subject: [PATCH 057/187] Add HRMP notification handlers to the xcm-executor (#3696) Currently the xcm-executor returns an `Unimplemented` error if it receives any HRMP-related instruction. What I propose here, which is what we are currently doing in our forked executor at polimec, is to introduce a trait implemented by the executor which will handle those instructions. This way, if parachains want to keep the default behavior, they just use `()` and it will return unimplemented, but they can also implement their own logic to establish HRMP channels with other chains in an automated fashion, without requiring to go through governance. Our implementation is mentioned in the [polkadot HRMP docs](https://arc.net/l/quote/hduiivbu), and it was suggested to us to submit a PR to add these changes to polkadot-sdk. --------- Co-authored-by: Branislav Kontur Co-authored-by: command-bot <> --- cumulus/pallets/xcmp-queue/src/mock.rs | 3 + .../assets/asset-hub-rococo/src/xcm_config.rs | 3 + .../asset-hub-westend/src/xcm_config.rs | 3 + .../bridge-hub-rococo/src/xcm_config.rs | 3 + .../bridge-hub-westend/src/xcm_config.rs | 3 + .../collectives-westend/src/xcm_config.rs | 3 + .../contracts-rococo/src/xcm_config.rs | 3 + .../coretime-rococo/src/xcm_config.rs | 3 + .../coretime-westend/src/xcm_config.rs | 3 + .../glutton/glutton-westend/src/xcm_config.rs | 3 + .../people/people-rococo/src/xcm_config.rs | 3 + .../people/people-westend/src/xcm_config.rs | 3 + .../runtimes/starters/shell/src/xcm_config.rs | 3 + .../runtimes/testing/penpal/src/xcm_config.rs | 3 + .../testing/rococo-parachain/src/lib.rs | 3 + polkadot/runtime/rococo/src/xcm_config.rs | 3 + .../runtime/test-runtime/src/xcm_config.rs | 3 + polkadot/runtime/westend/src/xcm_config.rs | 3 + .../src/fungible/mock.rs | 3 + .../pallet-xcm-benchmarks/src/generic/mock.rs | 3 + polkadot/xcm/pallet-xcm/src/mock.rs | 3 + polkadot/xcm/xcm-builder/src/tests/mock.rs | 3 + .../xcm/xcm-builder/src/tests/pay/mock.rs | 3 + polkadot/xcm/xcm-builder/tests/mock/mod.rs | 3 + polkadot/xcm/xcm-executor/src/config.rs | 10 +++- polkadot/xcm/xcm-executor/src/lib.rs | 21 +++++-- polkadot/xcm/xcm-executor/src/traits/hrmp.rs | 56 +++++++++++++++++++ polkadot/xcm/xcm-executor/src/traits/mod.rs | 4 ++ .../xcm-simulator/example/src/parachain.rs | 3 + .../xcm-simulator/example/src/relay_chain.rs | 3 + .../xcm/xcm-simulator/fuzzer/src/parachain.rs | 3 + .../xcm-simulator/fuzzer/src/relay_chain.rs | 3 + prdoc/pr_3696.prdoc | 17 ++++++ .../contracts/mock-network/src/parachain.rs | 3 + .../contracts/mock-network/src/relay_chain.rs | 3 + templates/parachain/runtime/src/xcm_config.rs | 3 + 36 files changed, 196 insertions(+), 5 deletions(-) create mode 100644 polkadot/xcm/xcm-executor/src/traits/hrmp.rs create mode 100644 prdoc/pr_3696.prdoc diff --git a/cumulus/pallets/xcmp-queue/src/mock.rs b/cumulus/pallets/xcmp-queue/src/mock.rs index 294f978f6ad..9d9a723cf8b 100644 --- a/cumulus/pallets/xcmp-queue/src/mock.rs +++ b/cumulus/pallets/xcmp-queue/src/mock.rs @@ -175,6 +175,9 @@ impl xcm_executor::Config for XcmConfig { type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } pub type XcmRouter = ( diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index 2584dbdf310..c438361cc17 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -628,6 +628,9 @@ impl xcm_executor::Config for XcmConfig { type SafeCallFilter = SafeCallFilter; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } /// Converts a local signed origin into an XCM location. diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs index 50865c00061..c993d61545a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs @@ -649,6 +649,9 @@ impl xcm_executor::Config for XcmConfig { type SafeCallFilter = SafeCallFilter; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } /// Local origins on this chain are allowed to dispatch XCM sends/executions. diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs index 55c78477b56..8934ff9b227 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs @@ -336,6 +336,9 @@ impl xcm_executor::Config for XcmConfig { type SafeCallFilter = SafeCallFilter; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } pub type PriceForParentDelivery = diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs index e18df6feda8..840d0c9af0e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs @@ -264,6 +264,9 @@ impl xcm_executor::Config for XcmConfig { type SafeCallFilter = SafeCallFilter; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } pub type PriceForParentDelivery = diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs index 87f637d5b59..b83106a5828 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs @@ -288,6 +288,9 @@ impl xcm_executor::Config for XcmConfig { type SafeCallFilter = SafeCallFilter; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } /// Converts a local signed origin into an XCM location. diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs index e8f3209eb67..ac6fe634662 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs @@ -197,6 +197,9 @@ impl xcm_executor::Config for XcmConfig { type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } /// Converts a local signed origin into an XCM location. diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs index 1722e1fcb31..955f2eeba33 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs @@ -257,6 +257,9 @@ impl xcm_executor::Config for XcmConfig { type SafeCallFilter = SafeCallFilter; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } /// Converts a local signed origin into an XCM location. Forms the basis for local origins diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs index b03c7748fe0..fc7d36a8ba1 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs @@ -269,6 +269,9 @@ impl xcm_executor::Config for XcmConfig { type SafeCallFilter = SafeCallFilter; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } /// Converts a local signed origin into an XCM location. Forms the basis for local origins diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs index ad61987c0e7..15bb519e115 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs @@ -88,6 +88,9 @@ impl xcm_executor::Config for XcmConfig { type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs index 534d6519086..a10333fdb62 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs @@ -269,6 +269,9 @@ impl xcm_executor::Config for XcmConfig { type SafeCallFilter = SafeCallFilter; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } /// Converts a local signed origin into an XCM location. Forms the basis for local origins diff --git a/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs index 6353a581352..fee2f5684ac 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs @@ -277,6 +277,9 @@ impl xcm_executor::Config for XcmConfig { type SafeCallFilter = SafeCallFilter; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } /// Converts a local signed origin into an XCM location. Forms the basis for local origins diff --git a/cumulus/parachains/runtimes/starters/shell/src/xcm_config.rs b/cumulus/parachains/runtimes/starters/shell/src/xcm_config.rs index f6af50f76d8..df89158729c 100644 --- a/cumulus/parachains/runtimes/starters/shell/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/starters/shell/src/xcm_config.rs @@ -88,6 +88,9 @@ impl xcm_executor::Config for XcmConfig { type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index bc1aa05a617..d83a877c2f8 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -338,6 +338,9 @@ impl xcm_executor::Config for XcmConfig { type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } /// Multiplier used for dedicated `TakeFirstAssetTrader` with `ForeignAssets` instance. diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index a066cab1b6d..1b7efa6f400 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -484,6 +484,9 @@ impl xcm_executor::Config for XcmConfig { type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } /// Local origins on this chain are allowed to dispatch XCM sends/executions. diff --git a/polkadot/runtime/rococo/src/xcm_config.rs b/polkadot/runtime/rococo/src/xcm_config.rs index 67f34916fe7..328879715de 100644 --- a/polkadot/runtime/rococo/src/xcm_config.rs +++ b/polkadot/runtime/rococo/src/xcm_config.rs @@ -221,6 +221,9 @@ impl xcm_executor::Config for XcmConfig { type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } parameter_types! { diff --git a/polkadot/runtime/test-runtime/src/xcm_config.rs b/polkadot/runtime/test-runtime/src/xcm_config.rs index a48bca17e9f..8411b79f252 100644 --- a/polkadot/runtime/test-runtime/src/xcm_config.rs +++ b/polkadot/runtime/test-runtime/src/xcm_config.rs @@ -153,6 +153,9 @@ impl xcm_executor::Config for XcmConfig { type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } impl pallet_xcm::Config for crate::Runtime { diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index 7281007f006..73127cb1efd 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -219,6 +219,9 @@ impl xcm_executor::Config for XcmConfig { type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } parameter_types! { diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs index c75ecbceb08..c831cd02465 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs @@ -145,6 +145,9 @@ impl xcm_executor::Config for XcmConfig { type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } impl crate::Config for Test { diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs index b037d3dd8b2..534f7d85ea2 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs @@ -135,6 +135,9 @@ impl xcm_executor::Config for XcmConfig { type SafeCallFilter = Everything; type Aliasers = Aliasers; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } parameter_types! { diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index 77b30b1eaa1..b29562fc833 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -513,6 +513,9 @@ impl xcm_executor::Config for XcmConfig { type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } pub type LocalOriginToLocation = SignedToAccountId32; diff --git a/polkadot/xcm/xcm-builder/src/tests/mock.rs b/polkadot/xcm/xcm-builder/src/tests/mock.rs index 4521d5e92a4..4bf347ea771 100644 --- a/polkadot/xcm/xcm-builder/src/tests/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/mock.rs @@ -743,6 +743,9 @@ impl Config for TestConfig { type SafeCallFilter = Everything; type Aliasers = AliasForeignAccountId32; type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } pub fn fungible_multi_asset(location: Location, amount: u128) -> Asset { diff --git a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs index 9feda8fb90b..019113a12b2 100644 --- a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs @@ -218,6 +218,9 @@ impl xcm_executor::Config for XcmConfig { type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } parameter_types! { diff --git a/polkadot/xcm/xcm-builder/tests/mock/mod.rs b/polkadot/xcm/xcm-builder/tests/mock/mod.rs index 536f8851bb4..f3cf5ab2649 100644 --- a/polkadot/xcm/xcm-builder/tests/mock/mod.rs +++ b/polkadot/xcm/xcm-builder/tests/mock/mod.rs @@ -204,6 +204,9 @@ impl xcm_executor::Config for XcmConfig { type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } pub type LocalOriginToLocation = SignedToAccountId32; diff --git a/polkadot/xcm/xcm-executor/src/config.rs b/polkadot/xcm/xcm-executor/src/config.rs index ebe532a42fd..b296d32ca2a 100644 --- a/polkadot/xcm/xcm-executor/src/config.rs +++ b/polkadot/xcm/xcm-executor/src/config.rs @@ -16,7 +16,8 @@ use crate::traits::{ AssetExchange, AssetLock, CallDispatcher, ClaimAssets, ConvertOrigin, DropAssets, ExportXcm, - FeeManager, OnResponse, ProcessTransaction, ShouldExecute, TransactAsset, + FeeManager, HandleHrmpChannelAccepted, HandleHrmpChannelClosing, + HandleHrmpNewChannelOpenRequest, OnResponse, ProcessTransaction, ShouldExecute, TransactAsset, VersionChangeNotifier, WeightBounds, WeightTrader, }; use frame_support::{ @@ -114,4 +115,11 @@ pub trait Config { /// Transactional processor for XCM instructions. type TransactionalProcessor: ProcessTransaction; + + /// Allows optional logic execution for the `HrmpNewChannelOpenRequest` XCM notification. + type HrmpNewChannelOpenRequestHandler: HandleHrmpNewChannelOpenRequest; + /// Allows optional logic execution for the `HrmpChannelAccepted` XCM notification. + type HrmpChannelAcceptedHandler: HandleHrmpChannelAccepted; + /// Allows optional logic execution for the `HrmpChannelClosing` XCM notification. + type HrmpChannelClosingHandler: HandleHrmpChannelClosing; } diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs index c61e1e1d15b..81b81fe6a17 100644 --- a/polkadot/xcm/xcm-executor/src/lib.rs +++ b/polkadot/xcm/xcm-executor/src/lib.rs @@ -31,7 +31,8 @@ use xcm::latest::prelude::*; pub mod traits; use traits::{ validate_export, AssetExchange, AssetLock, CallDispatcher, ClaimAssets, ConvertOrigin, - DropAssets, Enact, ExportXcm, FeeManager, FeeReason, OnResponse, ProcessTransaction, + DropAssets, Enact, ExportXcm, FeeManager, FeeReason, HandleHrmpChannelAccepted, + HandleHrmpChannelClosing, HandleHrmpNewChannelOpenRequest, OnResponse, ProcessTransaction, Properties, ShouldExecute, TransactAsset, VersionChangeNotifier, WeightBounds, WeightTrader, XcmAssetTransfers, }; @@ -1212,9 +1213,21 @@ impl XcmExecutor { ); Ok(()) }, - HrmpNewChannelOpenRequest { .. } => Err(XcmError::Unimplemented), - HrmpChannelAccepted { .. } => Err(XcmError::Unimplemented), - HrmpChannelClosing { .. } => Err(XcmError::Unimplemented), + HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => + Config::TransactionalProcessor::process(|| { + Config::HrmpNewChannelOpenRequestHandler::handle( + sender, + max_message_size, + max_capacity, + ) + }), + HrmpChannelAccepted { recipient } => Config::TransactionalProcessor::process(|| { + Config::HrmpChannelAcceptedHandler::handle(recipient) + }), + HrmpChannelClosing { initiator, sender, recipient } => + Config::TransactionalProcessor::process(|| { + Config::HrmpChannelClosingHandler::handle(initiator, sender, recipient) + }), } } } diff --git a/polkadot/xcm/xcm-executor/src/traits/hrmp.rs b/polkadot/xcm/xcm-executor/src/traits/hrmp.rs new file mode 100644 index 00000000000..b6bbb9316d7 --- /dev/null +++ b/polkadot/xcm/xcm-executor/src/traits/hrmp.rs @@ -0,0 +1,56 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use xcm::latest::Result as XcmResult; + +/// Executes logic when a `HrmpNewChannelOpenRequest` XCM notification is received. +pub trait HandleHrmpNewChannelOpenRequest { + fn handle(sender: u32, max_message_size: u32, max_capacity: u32) -> XcmResult; +} + +/// Executes optional logic when a `HrmpChannelAccepted` XCM notification is received. +pub trait HandleHrmpChannelAccepted { + fn handle(recipient: u32) -> XcmResult; +} + +/// Executes optional logic when a `HrmpChannelClosing` XCM notification is received. +pub trait HandleHrmpChannelClosing { + fn handle(initiator: u32, sender: u32, recipient: u32) -> XcmResult; +} + +#[impl_trait_for_tuples::impl_for_tuples(30)] +impl HandleHrmpNewChannelOpenRequest for Tuple { + fn handle(sender: u32, max_message_size: u32, max_capacity: u32) -> XcmResult { + for_tuples!( #( Tuple::handle(sender, max_message_size, max_capacity)?; )* ); + Ok(()) + } +} + +#[impl_trait_for_tuples::impl_for_tuples(30)] +impl HandleHrmpChannelAccepted for Tuple { + fn handle(recipient: u32) -> XcmResult { + for_tuples!( #( Tuple::handle(recipient)?; )* ); + Ok(()) + } +} + +#[impl_trait_for_tuples::impl_for_tuples(30)] +impl HandleHrmpChannelClosing for Tuple { + fn handle(initiator: u32, sender: u32, recipient: u32) -> XcmResult { + for_tuples!( #( Tuple::handle(initiator, sender, recipient)?; )* ); + Ok(()) + } +} diff --git a/polkadot/xcm/xcm-executor/src/traits/mod.rs b/polkadot/xcm/xcm-executor/src/traits/mod.rs index b445e84d391..aa3f0d26e30 100644 --- a/polkadot/xcm/xcm-executor/src/traits/mod.rs +++ b/polkadot/xcm/xcm-executor/src/traits/mod.rs @@ -45,6 +45,10 @@ mod should_execute; pub use should_execute::{CheckSuspension, Properties, ShouldExecute}; mod transact_asset; pub use transact_asset::TransactAsset; +mod hrmp; +pub use hrmp::{ + HandleHrmpChannelAccepted, HandleHrmpChannelClosing, HandleHrmpNewChannelOpenRequest, +}; mod weight; #[deprecated = "Use `sp_runtime::traits::` instead"] pub use sp_runtime::traits::{Identity, TryConvertInto as JustTry}; diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain.rs b/polkadot/xcm/xcm-simulator/example/src/parachain.rs index 50a12a3a698..86401d756af 100644 --- a/polkadot/xcm/xcm-simulator/example/src/parachain.rs +++ b/polkadot/xcm/xcm-simulator/example/src/parachain.rs @@ -251,6 +251,9 @@ impl Config for XcmConfig { type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } #[frame_support::pallet] diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs index f41e273839b..377c77f30a4 100644 --- a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs @@ -198,6 +198,9 @@ impl Config for XcmConfig { type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } pub type LocalOriginToLocation = SignedToAccountId32; diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs index 1130701a344..cadfc1e7200 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs @@ -156,6 +156,9 @@ impl Config for XcmConfig { type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } #[frame_support::pallet] diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs index 42dd8237cbf..3224df66cbe 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs @@ -157,6 +157,9 @@ impl Config for XcmConfig { type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } pub type LocalOriginToLocation = SignedToAccountId32; diff --git a/prdoc/pr_3696.prdoc b/prdoc/pr_3696.prdoc new file mode 100644 index 00000000000..f3371d1734a --- /dev/null +++ b/prdoc/pr_3696.prdoc @@ -0,0 +1,17 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Add HRMP notification handlers to the xcm-executor + +doc: + - audience: Runtime Dev + description: | + Adds optional HRMP notification handlers to the xcm-executor. These handlers are 3 new config types on the xcm-executor `Config` trait: + - `HrmpNewChannelOpenRequestHandler` + - `HrmpChannelAcceptedHandler` + - `HrmpChannelClosingHandler` + + The traits of these config types are implemented on tuples, and on `()` for the default case. + +crates: + - name: staging-xcm-executor diff --git a/substrate/frame/contracts/mock-network/src/parachain.rs b/substrate/frame/contracts/mock-network/src/parachain.rs index 0848f97b09c..d4ad47581d1 100644 --- a/substrate/frame/contracts/mock-network/src/parachain.rs +++ b/substrate/frame/contracts/mock-network/src/parachain.rs @@ -282,6 +282,9 @@ impl Config for XcmConfig { type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } impl mock_msg_queue::Config for Runtime { diff --git a/substrate/frame/contracts/mock-network/src/relay_chain.rs b/substrate/frame/contracts/mock-network/src/relay_chain.rs index 8c79255728e..e2a8d3d1337 100644 --- a/substrate/frame/contracts/mock-network/src/relay_chain.rs +++ b/substrate/frame/contracts/mock-network/src/relay_chain.rs @@ -182,6 +182,9 @@ impl Config for XcmConfig { type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } pub type LocalOriginToLocation = SignedToAccountId32; diff --git a/templates/parachain/runtime/src/xcm_config.rs b/templates/parachain/runtime/src/xcm_config.rs index b1230ba1e5d..7dce7164888 100644 --- a/templates/parachain/runtime/src/xcm_config.rs +++ b/templates/parachain/runtime/src/xcm_config.rs @@ -137,6 +137,9 @@ impl xcm_executor::Config for XcmConfig { type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); } /// No local origins on this chain are allowed to dispatch XCM sends/executions. -- GitLab From 430ad2f5610dc3d53b4708c651617e34affa97f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 19 Mar 2024 09:27:51 +0100 Subject: [PATCH 058/187] Make `availability-recovery-regression-bench` a benchmark (#3741) Closes: https://github.com/paritytech/polkadot-sdk/issues/3704 --- .gitlab/pipeline/test.yml | 2 +- polkadot/node/network/availability-recovery/Cargo.toml | 4 ++-- .../availability-recovery-regression-bench.rs | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename polkadot/node/network/availability-recovery/{tests => benches}/availability-recovery-regression-bench.rs (100%) diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index 26e55e9385f..d244316000a 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -502,7 +502,7 @@ subsystem-regression-tests: - .common-refs - .run-immediately script: - - cargo test --profile=testnet -p polkadot-availability-recovery --test availability-recovery-regression-bench --features subsystem-benchmarks + - cargo bench --profile=testnet -p polkadot-availability-recovery --bench availability-recovery-regression-bench --features subsystem-benchmarks tags: - benchmark allow_failure: true diff --git a/polkadot/node/network/availability-recovery/Cargo.toml b/polkadot/node/network/availability-recovery/Cargo.toml index 12b6ce7a057..23c4148fa85 100644 --- a/polkadot/node/network/availability-recovery/Cargo.toml +++ b/polkadot/node/network/availability-recovery/Cargo.toml @@ -43,9 +43,9 @@ polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } polkadot-subsystem-bench = { path = "../../subsystem-bench" } -[[test]] +[[bench]] name = "availability-recovery-regression-bench" -path = "tests/availability-recovery-regression-bench.rs" +path = "benches/availability-recovery-regression-bench.rs" harness = false required-features = ["subsystem-benchmarks"] diff --git a/polkadot/node/network/availability-recovery/tests/availability-recovery-regression-bench.rs b/polkadot/node/network/availability-recovery/benches/availability-recovery-regression-bench.rs similarity index 100% rename from polkadot/node/network/availability-recovery/tests/availability-recovery-regression-bench.rs rename to polkadot/node/network/availability-recovery/benches/availability-recovery-regression-bench.rs -- GitLab From abd3f0c49a472fc4e4b52a814493224222921ffb Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 19 Mar 2024 13:35:22 +0200 Subject: [PATCH 059/187] Benchmarking: Add pov_mode to V2 syntax (#3616) Changes: - Port the `pov_mode` attribute from the V1 syntax to V2 - Update `pallet-whitelist` and `frame-benchmarking-pallet-pov` Follow up: also allow this attribute on top-level benchmark modules. --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: command-bot <> --- prdoc/pr_3616.prdoc | 28 + .../benchmarking/pov/src/benchmarking.rs | 412 +++++----- .../frame/benchmarking/pov/src/weights.rs | 710 +++++++++--------- .../frame/support/procedural/src/benchmark.rs | 167 +++- .../tests/benchmark_ui/bad_attr_pov_mode_1.rs | 31 + .../benchmark_ui/bad_attr_pov_mode_1.stderr | 5 + .../tests/benchmark_ui/bad_attr_pov_mode_2.rs | 33 + .../benchmark_ui/bad_attr_pov_mode_2.stderr | 5 + .../tests/benchmark_ui/bad_attr_pov_mode_3.rs | 31 + .../benchmark_ui/bad_attr_pov_mode_3.stderr | 5 + .../tests/benchmark_ui/bad_attr_pov_mode_4.rs | 31 + .../benchmark_ui/bad_attr_pov_mode_4.stderr | 5 + .../tests/benchmark_ui/dup_attr_pov_mode.rs | 32 + .../benchmark_ui/dup_attr_pov_mode.stderr | 14 + .../benchmark_ui/pass/valid_attr_pov_mode.rs | 74 ++ .../tests/benchmark_ui/pass/valid_basic.rs | 2 +- .../benchmark_ui/unrecognized_option.stderr | 2 +- substrate/frame/whitelist/src/benchmarking.rs | 99 ++- 18 files changed, 1085 insertions(+), 601 deletions(-) create mode 100644 prdoc/pr_3616.prdoc create mode 100644 substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_1.rs create mode 100644 substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_1.stderr create mode 100644 substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_2.rs create mode 100644 substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_2.stderr create mode 100644 substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_3.rs create mode 100644 substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_3.stderr create mode 100644 substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_4.rs create mode 100644 substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_4.stderr create mode 100644 substrate/frame/support/test/tests/benchmark_ui/dup_attr_pov_mode.rs create mode 100644 substrate/frame/support/test/tests/benchmark_ui/dup_attr_pov_mode.stderr create mode 100644 substrate/frame/support/test/tests/benchmark_ui/pass/valid_attr_pov_mode.rs diff --git a/prdoc/pr_3616.prdoc b/prdoc/pr_3616.prdoc new file mode 100644 index 00000000000..fcf068dcd17 --- /dev/null +++ b/prdoc/pr_3616.prdoc @@ -0,0 +1,28 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "Benchmarking pallet V2 syntax extension: pov_mode attribute" + +doc: + - audience: Runtime Dev + description: | + Adds the `pov_mode` attribute from the V1 benchmarking syntax to the V2 syntax. This allows to + override the default PoV mode (`MaxEncodedLen`) to either `Measured` or `Ignored`. It can be + overridden for a whole benchmark, a key prefix of a specific key itself. + + Example syntax looks like this: + ```rust + #[benchmark(pov_mode = Measured { + Pallet: Measured, + Pallet::Storage: MaxEncodedLen, + })] + fn do_some() { + .. + } + ``` + +crates: + - name: frame-support-procedural + bump: minor + - name: frame-support + bump: minor diff --git a/substrate/frame/benchmarking/pov/src/benchmarking.rs b/substrate/frame/benchmarking/pov/src/benchmarking.rs index d78cb553318..7e6aa8e6bf6 100644 --- a/substrate/frame/benchmarking/pov/src/benchmarking.rs +++ b/substrate/frame/benchmarking/pov/src/benchmarking.rs @@ -21,54 +21,78 @@ use super::*; +use frame_benchmarking::v2::*; use frame_support::traits::UnfilteredDispatchable; use frame_system::{Pallet as System, RawOrigin}; use sp_runtime::traits::Hash; -frame_benchmarking::benchmarks! { - storage_single_value_read { +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn storage_single_value_read() { Value::::put(123); - }: { - assert_eq!(Value::::get(), Some(123)); + + #[block] + { + assert_eq!(Value::::get(), Some(123)); + } } - #[pov_mode = Ignored] - storage_single_value_ignored_read { + #[benchmark(pov_mode = Ignored)] + fn storage_single_value_ignored_read() { Value::::put(123); - }: { - assert_eq!(Value::::get(), Some(123)); + #[block] + { + assert_eq!(Value::::get(), Some(123)); + } } - #[pov_mode = MaxEncodedLen { + #[benchmark(pov_mode = MaxEncodedLen { Pov::Value2: Ignored - }] - storage_single_value_ignored_some_read { + })] + fn storage_single_value_ignored_some_read() { Value::::put(123); Value2::::put(123); - }: { - assert_eq!(Value::::get(), Some(123)); - assert_eq!(Value2::::get(), Some(123)); + + #[block] + { + assert_eq!(Value::::get(), Some(123)); + assert_eq!(Value2::::get(), Some(123)); + } } - storage_single_value_read_twice { + #[benchmark] + fn storage_single_value_read_twice() { Value::::put(123); - }: { - assert_eq!(Value::::get(), Some(123)); - assert_eq!(Value::::get(), Some(123)); + + #[block] + { + assert_eq!(Value::::get(), Some(123)); + assert_eq!(Value::::get(), Some(123)); + } } - storage_single_value_write { - }: { - Value::::put(123); - } verify { + #[benchmark] + fn storage_single_value_write() { + #[block] + { + Value::::put(123); + } + assert_eq!(Value::::get(), Some(123)); } - storage_single_value_kill { + #[benchmark] + fn storage_single_value_kill() { Value::::put(123); - }: { - Value::::kill(); - } verify { + + #[block] + { + Value::::kill(); + } + assert!(!Value::::exists()); } @@ -78,263 +102,297 @@ frame_benchmarking::benchmarks! { // created. Then the one value is read from the map. This demonstrates that the number of other // nodes in the Trie influences the proof size. The number of inserted nodes can be interpreted // as the number of `StorageMap`/`StorageValue` in the whole runtime. - #[pov_mode = Measured] - storage_1m_map_read_one_value_two_additional_layers { - (0..(1<<10)).for_each(|i| Map1M::::insert(i, i)); + #[benchmark(pov_mode = Measured)] + fn storage_1m_map_read_one_value_two_additional_layers() { + (0..(1 << 10)).for_each(|i| Map1M::::insert(i, i)); // Assume there are 16-256 other storage items. - (0..(1u32<<4)).for_each(|i| { + (0..(1u32 << 4)).for_each(|i| { let k = T::Hashing::hash(&i.to_be_bytes()); frame_support::storage::unhashed::put(k.as_ref(), &i); }); - }: { - assert_eq!(Map1M::::get(1<<9), Some(1<<9)); + + #[block] + { + assert_eq!(Map1M::::get(1 << 9), Some(1 << 9)); + } } - #[pov_mode = Measured] - storage_1m_map_read_one_value_three_additional_layers { - (0..(1<<10)).for_each(|i| Map1M::::insert(i, i)); + #[benchmark(pov_mode = Measured)] + fn storage_1m_map_read_one_value_three_additional_layers() { + (0..(1 << 10)).for_each(|i| Map1M::::insert(i, i)); // Assume there are 256-4096 other storage items. - (0..(1u32<<8)).for_each(|i| { + (0..(1u32 << 8)).for_each(|i| { let k = T::Hashing::hash(&i.to_be_bytes()); frame_support::storage::unhashed::put(k.as_ref(), &i); }); - }: { - assert_eq!(Map1M::::get(1<<9), Some(1<<9)); + + #[block] + { + assert_eq!(Map1M::::get(1 << 9), Some(1 << 9)); + } } - #[pov_mode = Measured] - storage_1m_map_read_one_value_four_additional_layers { - (0..(1<<10)).for_each(|i| Map1M::::insert(i, i)); + #[benchmark(pov_mode = Measured)] + fn storage_1m_map_read_one_value_four_additional_layers() { + (0..(1 << 10)).for_each(|i| Map1M::::insert(i, i)); // Assume there are 4096-65536 other storage items. - (0..(1u32<<12)).for_each(|i| { + (0..(1u32 << 12)).for_each(|i| { let k = T::Hashing::hash(&i.to_be_bytes()); frame_support::storage::unhashed::put(k.as_ref(), &i); }); - }: { - assert_eq!(Map1M::::get(1<<9), Some(1<<9)); + + #[block] + { + assert_eq!(Map1M::::get(1 << 9), Some(1 << 9)); + } } // Reads from both storage maps each `n` and `m` times. Should result in two linear components. - storage_map_read_per_component { - let n in 0 .. 100; - let m in 0 .. 100; + #[benchmark] + fn storage_map_read_per_component(n: Linear<0, 100>, m: Linear<0, 100>) { + (0..m * 10).for_each(|i| Map1M::::insert(i, i)); + (0..n * 10).for_each(|i| Map16M::::insert(i, i)); - (0..m*10).for_each(|i| Map1M::::insert(i, i)); - (0..n*10).for_each(|i| Map16M::::insert(i, i)); - }: { - (0..m).for_each(|i| - assert_eq!(Map1M::::get(i*10), Some(i*10))); - (0..n).for_each(|i| - assert_eq!(Map16M::::get(i*10), Some(i*10))); + #[block] + { + (0..m).for_each(|i| assert_eq!(Map1M::::get(i * 10), Some(i * 10))); + (0..n).for_each(|i| assert_eq!(Map16M::::get(i * 10), Some(i * 10))); + } } - #[pov_mode = MaxEncodedLen { + #[benchmark(pov_mode = MaxEncodedLen { Pov::Map1M: Ignored - }] - storage_map_read_per_component_one_ignored { - let n in 0 .. 100; - let m in 0 .. 100; + })] + fn storage_map_read_per_component_one_ignored(n: Linear<0, 100>, m: Linear<0, 100>) { + (0..m * 10).for_each(|i| Map1M::::insert(i, i)); + (0..n * 10).for_each(|i| Map16M::::insert(i, i)); - (0..m*10).for_each(|i| Map1M::::insert(i, i)); - (0..n*10).for_each(|i| Map16M::::insert(i, i)); - }: { - (0..m).for_each(|i| - assert_eq!(Map1M::::get(i*10), Some(i*10))); - (0..n).for_each(|i| - assert_eq!(Map16M::::get(i*10), Some(i*10))); + #[block] + { + (0..m).for_each(|i| assert_eq!(Map1M::::get(i * 10), Some(i * 10))); + (0..n).for_each(|i| assert_eq!(Map16M::::get(i * 10), Some(i * 10))); + } } // Reads the same value from a storage map. Should not result in a component. - storage_1m_map_one_entry_repeated_read { - let n in 0 .. 100; + #[benchmark] + fn storage_1m_map_one_entry_repeated_read(n: Linear<0, 100>) { Map1M::::insert(0, 0); - }: { - (0..n).for_each(|i| - assert_eq!(Map1M::::get(0), Some(0))); + + #[block] + { + (0..n).for_each(|_| assert_eq!(Map1M::::get(0), Some(0))); + } } // Reads the same values from a storage map. Should result in a `1x` linear component. - storage_1m_map_multiple_entry_repeated_read { - let n in 0 .. 100; + #[benchmark] + fn storage_1m_map_multiple_entry_repeated_read(n: Linear<0, 100>) { (0..n).for_each(|i| Map1M::::insert(i, i)); - }: { - (0..n).for_each(|i| { - // Reading the same value 10 times does nothing. - (0..10).for_each(|j| - assert_eq!(Map1M::::get(i), Some(i))); - }); + + #[block] + { + (0..n).for_each(|i| { + // Reading the same value 10 times does nothing. + (0..10).for_each(|_| assert_eq!(Map1M::::get(i), Some(i))); + }); + } } - storage_1m_double_map_read_per_component { - let n in 0 .. 1024; - (0..(1<<10)).for_each(|i| DoubleMap1M::::insert(i, i, i)); - }: { - (0..n).for_each(|i| - assert_eq!(DoubleMap1M::::get(i, i), Some(i))); + #[benchmark] + fn storage_1m_double_map_read_per_component(n: Linear<0, 1024>) { + (0..(1 << 10)).for_each(|i| DoubleMap1M::::insert(i, i, i)); + + #[block] + { + (0..n).for_each(|i| assert_eq!(DoubleMap1M::::get(i, i), Some(i))); + } } - storage_value_bounded_read { - }: { - assert!(BoundedValue::::get().is_none()); + #[benchmark] + fn storage_value_bounded_read() { + #[block] + { + assert!(BoundedValue::::get().is_none()); + } } // Reading unbounded values will produce no mathematical worst case PoV size for this component. - storage_value_unbounded_read { - }: { - assert!(UnboundedValue::::get().is_none()); + #[benchmark] + fn storage_value_unbounded_read() { + #[block] + { + assert!(UnboundedValue::::get().is_none()); + } } - #[pov_mode = Ignored] - storage_value_unbounded_ignored_read { - }: { - assert!(UnboundedValue::::get().is_none()); + #[benchmark(pov_mode = Ignored)] + fn storage_value_unbounded_ignored_read() { + #[block] + { + assert!(UnboundedValue::::get().is_none()); + } } // Same as above, but we still expect a mathematical worst case PoV size for the bounded one. - storage_value_bounded_and_unbounded_read { + #[benchmark] + fn storage_value_bounded_and_unbounded_read() { (0..1024).for_each(|i| Map1M::::insert(i, i)); - }: { - assert!(UnboundedValue::::get().is_none()); - assert!(BoundedValue::::get().is_none()); + #[block] + { + assert!(UnboundedValue::::get().is_none()); + assert!(BoundedValue::::get().is_none()); + } } - #[pov_mode = Measured] - measured_storage_value_read_linear_size { - let l in 0 .. 1<<22; + #[benchmark(pov_mode = Measured)] + fn measured_storage_value_read_linear_size(l: Linear<0, { 1 << 22 }>) { let v: sp_runtime::BoundedVec = sp_std::vec![0u8; l as usize].try_into().unwrap(); LargeValue::::put(&v); - }: { - assert!(LargeValue::::get().is_some()); + #[block] + { + assert!(LargeValue::::get().is_some()); + } } - #[pov_mode = MaxEncodedLen] - mel_storage_value_read_linear_size { - let l in 0 .. 1<<22; + #[benchmark(pov_mode = MaxEncodedLen)] + fn mel_storage_value_read_linear_size(l: Linear<0, { 1 << 22 }>) { let v: sp_runtime::BoundedVec = sp_std::vec![0u8; l as usize].try_into().unwrap(); LargeValue::::put(&v); - }: { - assert!(LargeValue::::get().is_some()); + #[block] + { + assert!(LargeValue::::get().is_some()); + } } - #[pov_mode = Measured] - measured_storage_double_value_read_linear_size { - let l in 0 .. 1<<22; + #[benchmark(pov_mode = Measured)] + fn measured_storage_double_value_read_linear_size(l: Linear<0, { 1 << 22 }>) { let v: sp_runtime::BoundedVec = sp_std::vec![0u8; l as usize].try_into().unwrap(); LargeValue::::put(&v); LargeValue2::::put(&v); - }: { - assert!(LargeValue::::get().is_some()); - assert!(LargeValue2::::get().is_some()); + #[block] + { + assert!(LargeValue::::get().is_some()); + assert!(LargeValue2::::get().is_some()); + } } - #[pov_mode = MaxEncodedLen] - mel_storage_double_value_read_linear_size { - let l in 0 .. 1<<22; + #[benchmark(pov_mode = MaxEncodedLen)] + fn mel_storage_double_value_read_linear_size(l: Linear<0, { 1 << 22 }>) { let v: sp_runtime::BoundedVec = sp_std::vec![0u8; l as usize].try_into().unwrap(); LargeValue::::put(&v); LargeValue2::::put(&v); - }: { - assert!(LargeValue::::get().is_some()); - assert!(LargeValue2::::get().is_some()); + #[block] + { + assert!(LargeValue::::get().is_some()); + assert!(LargeValue2::::get().is_some()); + } } - #[pov_mode = MaxEncodedLen { + #[benchmark(pov_mode = MaxEncodedLen { Pov::LargeValue2: Measured - }] - mel_mixed_storage_double_value_read_linear_size { - let l in 0 .. 1<<22; + })] + fn mel_mixed_storage_double_value_read_linear_size(l: Linear<0, { 1 << 22 }>) { let v: sp_runtime::BoundedVec = sp_std::vec![0u8; l as usize].try_into().unwrap(); LargeValue::::put(&v); LargeValue2::::put(&v); - }: { - assert!(LargeValue::::get().is_some()); - assert!(LargeValue2::::get().is_some()); + #[block] + { + assert!(LargeValue::::get().is_some()); + assert!(LargeValue2::::get().is_some()); + } } - #[pov_mode = Measured { + #[benchmark(pov_mode = Measured { Pov::LargeValue2: MaxEncodedLen - }] - measured_mixed_storage_double_value_read_linear_size { - let l in 0 .. 1<<22; + })] + fn measured_mixed_storage_double_value_read_linear_size(l: Linear<0, { 1 << 22 }>) { let v: sp_runtime::BoundedVec = sp_std::vec![0u8; l as usize].try_into().unwrap(); LargeValue::::put(&v); LargeValue2::::put(&v); - }: { - assert!(LargeValue::::get().is_some()); - assert!(LargeValue2::::get().is_some()); + #[block] + { + assert!(LargeValue::::get().is_some()); + assert!(LargeValue2::::get().is_some()); + } } - #[pov_mode = Measured] - storage_map_unbounded_both_measured_read { - let i in 0 .. 1000; - + #[benchmark(pov_mode = Measured)] + fn storage_map_unbounded_both_measured_read(i: Linear<0, 1000>) { UnboundedMap::::insert(i, sp_std::vec![0; i as usize]); UnboundedMap2::::insert(i, sp_std::vec![0; i as usize]); - }: { - assert!(UnboundedMap::::get(i).is_some()); - assert!(UnboundedMap2::::get(i).is_some()); + #[block] + { + assert!(UnboundedMap::::get(i).is_some()); + assert!(UnboundedMap2::::get(i).is_some()); + } } - #[pov_mode = MaxEncodedLen { + #[benchmark(pov_mode = MaxEncodedLen { Pov::UnboundedMap: Measured - }] - storage_map_partial_unbounded_read { - let i in 0 .. 1000; - + })] + fn storage_map_partial_unbounded_read(i: Linear<0, 1000>) { Map1M::::insert(i, 0); UnboundedMap::::insert(i, sp_std::vec![0; i as usize]); - }: { - assert!(Map1M::::get(i).is_some()); - assert!(UnboundedMap::::get(i).is_some()); + #[block] + { + assert!(Map1M::::get(i).is_some()); + assert!(UnboundedMap::::get(i).is_some()); + } } - #[pov_mode = MaxEncodedLen { + #[benchmark(pov_mode = MaxEncodedLen { Pov::UnboundedMap: Ignored - }] - storage_map_partial_unbounded_ignored_read { - let i in 0 .. 1000; - + })] + fn storage_map_partial_unbounded_ignored_read(i: Linear<0, 1000>) { Map1M::::insert(i, 0); UnboundedMap::::insert(i, sp_std::vec![0; i as usize]); - }: { - assert!(Map1M::::get(i).is_some()); - assert!(UnboundedMap::::get(i).is_some()); + #[block] + { + assert!(Map1M::::get(i).is_some()); + assert!(UnboundedMap::::get(i).is_some()); + } } // Emitting an event will not incur any PoV. - emit_event { + #[benchmark] + fn emit_event() { // Emit a single event. - let call = Call::::emit_event { }; - }: { call.dispatch_bypass_filter(RawOrigin::Root.into()).unwrap(); } - verify { + let call = Call::::emit_event {}; + #[block] + { + call.dispatch_bypass_filter(RawOrigin::Root.into()).unwrap(); + } assert_eq!(System::::events().len(), 1); } // A No-OP will not incur any PoV. - noop { - let call = Call::::noop { }; - }: { - call.dispatch_bypass_filter(RawOrigin::Root.into()).unwrap(); + #[benchmark] + fn noop() { + let call = Call::::noop {}; + #[block] + { + call.dispatch_bypass_filter(RawOrigin::Root.into()).unwrap(); + } } - storage_iteration { + #[benchmark] + fn storage_iteration() { for i in 0..65000 { UnboundedMapTwox::::insert(i, sp_std::vec![0; 64]); } - }: { - for (key, value) in UnboundedMapTwox::::iter() { - unsafe { - core::ptr::read_volatile(&key); - core::ptr::read_volatile(value.as_ptr()); + #[block] + { + for (key, value) in UnboundedMapTwox::::iter() { + unsafe { + core::ptr::read_volatile(&key); + core::ptr::read_volatile(value.as_ptr()); + } } } } - impl_benchmark_test_suite!( - Pallet, - mock::new_test_ext(), - mock::Test, - ); + impl_benchmark_test_suite!(Pallet, super::mock::new_test_ext(), super::mock::Test,); } #[cfg(test)] diff --git a/substrate/frame/benchmarking/pov/src/weights.rs b/substrate/frame/benchmarking/pov/src/weights.rs index d84ac88c98f..c4fc03d1dd9 100644 --- a/substrate/frame/benchmarking/pov/src/weights.rs +++ b/substrate/frame/benchmarking/pov/src/weights.rs @@ -15,38 +15,36 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for frame_benchmarking_pallet_pov +//! Autogenerated weights for `frame_benchmarking_pallet_pov` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-04-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-03-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` -//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 +//! HOSTNAME: `Olivers-MBP`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: `1024` // Executed Command: -// ./target/release/substrate +// target/release/substrate-node // benchmark // pallet -// --dev // --pallet // frame-benchmarking-pallet-pov // --extrinsic // -// --steps -// 50 -// --repeat -// 20 -// --template=.maintain/frame-weight-template.hbs -// --output=frame/benchmarking/pov/src/weights.rs +// --output +// substrate/frame/benchmarking/pov/src/weights.rs +// --template +// substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] +#![allow(missing_docs)] use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for frame_benchmarking_pallet_pov. +/// Weight functions needed for `frame_benchmarking_pallet_pov`. pub trait WeightInfo { fn storage_single_value_read() -> Weight; fn storage_single_value_ignored_read() -> Weight; @@ -80,361 +78,361 @@ pub trait WeightInfo { fn storage_iteration() -> Weight; } -/// Weights for frame_benchmarking_pallet_pov using the Substrate node and recommended hardware. +/// Weights for `frame_benchmarking_pallet_pov` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: Pov Value (r:1 w:0) - /// Proof: Pov Value (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `Pov::Value` (r:1 w:0) + /// Proof: `Pov::Value` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn storage_single_value_read() -> Weight { // Proof Size summary in bytes: // Measured: `136` // Estimated: `1489` - // Minimum execution time: 1_706_000 picoseconds. - Weight::from_parts(1_788_000, 1489) + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(3_000_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) } - /// Storage: Pov Value (r:1 w:0) - /// Proof: Pov Value (max_values: Some(1), max_size: Some(4), added: 499, mode: Ignored) + /// Storage: `Pov::Value` (r:1 w:0) + /// Proof: `Pov::Value` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `Ignored`) fn storage_single_value_ignored_read() -> Weight { // Proof Size summary in bytes: // Measured: `136` // Estimated: `0` - // Minimum execution time: 1_661_000 picoseconds. - Weight::from_parts(1_718_000, 0) + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(3_000_000, 0) .saturating_add(T::DbWeight::get().reads(1_u64)) } - /// Storage: Pov Value (r:1 w:0) - /// Proof: Pov Value (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Pov Value2 (r:1 w:0) - /// Proof: Pov Value2 (max_values: Some(1), max_size: Some(4), added: 499, mode: Ignored) + /// Storage: `Pov::Value` (r:1 w:0) + /// Proof: `Pov::Value` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Pov::Value2` (r:1 w:0) + /// Proof: `Pov::Value2` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `Ignored`) fn storage_single_value_ignored_some_read() -> Weight { // Proof Size summary in bytes: // Measured: `160` // Estimated: `1489` - // Minimum execution time: 2_226_000 picoseconds. - Weight::from_parts(2_365_000, 1489) + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(4_000_000, 1489) .saturating_add(T::DbWeight::get().reads(2_u64)) } - /// Storage: Pov Value (r:1 w:0) - /// Proof: Pov Value (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `Pov::Value` (r:1 w:0) + /// Proof: `Pov::Value` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn storage_single_value_read_twice() -> Weight { // Proof Size summary in bytes: // Measured: `136` // Estimated: `1489` - // Minimum execution time: 1_785_000 picoseconds. - Weight::from_parts(1_980_000, 1489) + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(4_000_000, 1489) .saturating_add(T::DbWeight::get().reads(1_u64)) } - /// Storage: Pov Value (r:0 w:1) - /// Proof: Pov Value (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `Pov::Value` (r:0 w:1) + /// Proof: `Pov::Value` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn storage_single_value_write() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 254_000 picoseconds. - Weight::from_parts(326_000, 0) + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(1_000_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Pov Value (r:0 w:1) - /// Proof: Pov Value (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `Pov::Value` (r:0 w:1) + /// Proof: `Pov::Value` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn storage_single_value_kill() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 239_000 picoseconds. - Weight::from_parts(277_000, 0) + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(1_000_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: Pov Map1M (r:1 w:0) - /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: Measured) + /// Storage: `Pov::Map1M` (r:1 w:0) + /// Proof: `Pov::Map1M` (`max_values`: Some(1000000), `max_size`: Some(36), added: 2511, mode: `Measured`) fn storage_1m_map_read_one_value_two_additional_layers() -> Weight { // Proof Size summary in bytes: // Measured: `1275` // Estimated: `4740` - // Minimum execution time: 4_760_000 picoseconds. - Weight::from_parts(5_051_000, 4740) + // Minimum execution time: 7_000_000 picoseconds. + Weight::from_parts(7_000_000, 4740) .saturating_add(T::DbWeight::get().reads(1_u64)) } - /// Storage: Pov Map1M (r:1 w:0) - /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: Measured) + /// Storage: `Pov::Map1M` (r:1 w:0) + /// Proof: `Pov::Map1M` (`max_values`: Some(1000000), `max_size`: Some(36), added: 2511, mode: `Measured`) fn storage_1m_map_read_one_value_three_additional_layers() -> Weight { // Proof Size summary in bytes: // Measured: `1544` // Estimated: `5009` - // Minimum execution time: 5_490_000 picoseconds. - Weight::from_parts(5_703_000, 5009) + // Minimum execution time: 8_000_000 picoseconds. + Weight::from_parts(8_000_000, 5009) .saturating_add(T::DbWeight::get().reads(1_u64)) } - /// Storage: Pov Map1M (r:1 w:0) - /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: Measured) + /// Storage: `Pov::Map1M` (r:1 w:0) + /// Proof: `Pov::Map1M` (`max_values`: Some(1000000), `max_size`: Some(36), added: 2511, mode: `Measured`) fn storage_1m_map_read_one_value_four_additional_layers() -> Weight { // Proof Size summary in bytes: // Measured: `2044` // Estimated: `5509` - // Minimum execution time: 6_397_000 picoseconds. - Weight::from_parts(7_084_000, 5509) + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(10_000_000, 5509) .saturating_add(T::DbWeight::get().reads(1_u64)) } - /// Storage: Pov Map1M (r:100 w:0) - /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) - /// Storage: Pov Map16M (r:100 w:0) - /// Proof: Pov Map16M (max_values: Some(16000000), max_size: Some(36), added: 3006, mode: MaxEncodedLen) + /// Storage: `Pov::Map1M` (r:100 w:0) + /// Proof: `Pov::Map1M` (`max_values`: Some(1000000), `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + /// Storage: `Pov::Map16M` (r:100 w:0) + /// Proof: `Pov::Map16M` (`max_values`: Some(16000000), `max_size`: Some(36), added: 3006, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 100]`. /// The range of component `m` is `[0, 100]`. fn storage_map_read_per_component(n: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `515 + m * (188 ±0) + n * (188 ±0)` // Estimated: `990 + m * (2511 ±0) + n * (3006 ±0)` - // Minimum execution time: 181_481_000 picoseconds. - Weight::from_parts(129_275_141, 990) - // Standard Error: 13_049 - .saturating_add(Weight::from_parts(787_667, 0).saturating_mul(n.into())) - // Standard Error: 13_049 - .saturating_add(Weight::from_parts(830_378, 0).saturating_mul(m.into())) + // Minimum execution time: 342_000_000 picoseconds. + Weight::from_parts(179_688_624, 990) + // Standard Error: 26_526 + .saturating_add(Weight::from_parts(2_061_828, 0).saturating_mul(n.into())) + // Standard Error: 26_526 + .saturating_add(Weight::from_parts(1_825_923, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(Weight::from_parts(0, 2511).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 3006).saturating_mul(n.into())) } - /// Storage: Pov Map1M (r:100 w:0) - /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: Ignored) - /// Storage: Pov Map16M (r:100 w:0) - /// Proof: Pov Map16M (max_values: Some(16000000), max_size: Some(36), added: 3006, mode: MaxEncodedLen) + /// Storage: `Pov::Map1M` (r:100 w:0) + /// Proof: `Pov::Map1M` (`max_values`: Some(1000000), `max_size`: Some(36), added: 2511, mode: `Ignored`) + /// Storage: `Pov::Map16M` (r:100 w:0) + /// Proof: `Pov::Map16M` (`max_values`: Some(16000000), `max_size`: Some(36), added: 3006, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 100]`. /// The range of component `m` is `[0, 100]`. fn storage_map_read_per_component_one_ignored(n: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `515 + m * (188 ±0) + n * (188 ±0)` // Estimated: `1685 + m * (189 ±0) + n * (3006 ±0)` - // Minimum execution time: 181_925_000 picoseconds. - Weight::from_parts(134_416_814, 1685) - // Standard Error: 15_678 - .saturating_add(Weight::from_parts(827_168, 0).saturating_mul(n.into())) - // Standard Error: 15_678 - .saturating_add(Weight::from_parts(813_655, 0).saturating_mul(m.into())) + // Minimum execution time: 342_000_000 picoseconds. + Weight::from_parts(204_945_396, 1685) + // Standard Error: 25_217 + .saturating_add(Weight::from_parts(1_827_513, 0).saturating_mul(n.into())) + // Standard Error: 25_217 + .saturating_add(Weight::from_parts(1_661_271, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(Weight::from_parts(0, 189).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 3006).saturating_mul(n.into())) } - /// Storage: Pov Map1M (r:1 w:0) - /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// Storage: `Pov::Map1M` (r:1 w:0) + /// Proof: `Pov::Map1M` (`max_values`: Some(1000000), `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 100]`. fn storage_1m_map_one_entry_repeated_read(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `170` // Estimated: `3501` - // Minimum execution time: 20_000 picoseconds. - Weight::from_parts(2_006_399, 3501) - // Standard Error: 808 - .saturating_add(Weight::from_parts(263_609, 0).saturating_mul(n.into())) + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(3_387_064, 3501) + // Standard Error: 1_445 + .saturating_add(Weight::from_parts(1_143_678, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) } - /// Storage: Pov Map1M (r:100 w:0) - /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// Storage: `Pov::Map1M` (r:100 w:0) + /// Proof: `Pov::Map1M` (`max_values`: Some(1000000), `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 100]`. fn storage_1m_map_multiple_entry_repeated_read(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `147 + n * (40 ±0)` // Estimated: `990 + n * (2511 ±0)` - // Minimum execution time: 21_000 picoseconds. - Weight::from_parts(3_940_044, 990) - // Standard Error: 4_906 - .saturating_add(Weight::from_parts(3_454_882, 0).saturating_mul(n.into())) + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(1_323_684, 990) + // Standard Error: 10_546 + .saturating_add(Weight::from_parts(13_101_864, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2511).saturating_mul(n.into())) } - /// Storage: Pov DoubleMap1M (r:1024 w:0) - /// Proof: Pov DoubleMap1M (max_values: Some(1000000), max_size: Some(68), added: 2543, mode: MaxEncodedLen) + /// Storage: `Pov::DoubleMap1M` (r:1024 w:0) + /// Proof: `Pov::DoubleMap1M` (`max_values`: Some(1000000), `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1024]`. fn storage_1m_double_map_read_per_component(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `21938 + n * (57 ±0)` // Estimated: `990 + n * (2543 ±0)` - // Minimum execution time: 28_000 picoseconds. - Weight::from_parts(20_674_869, 990) - // Standard Error: 3_035 - .saturating_add(Weight::from_parts(1_995_730, 0).saturating_mul(n.into())) + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(39_703_963, 990) + // Standard Error: 10_589 + .saturating_add(Weight::from_parts(3_718_040, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2543).saturating_mul(n.into())) } - /// Storage: Pov BoundedValue (r:1 w:0) - /// Proof: Pov BoundedValue (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) + /// Storage: `Pov::BoundedValue` (r:1 w:0) + /// Proof: `Pov::BoundedValue` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) fn storage_value_bounded_read() -> Weight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1518` - // Minimum execution time: 1_091_000 picoseconds. - Weight::from_parts(1_181_000, 1518) + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 1518) .saturating_add(T::DbWeight::get().reads(1_u64)) } - /// Storage: Pov UnboundedValue (r:1 w:0) - /// Proof Skipped: Pov UnboundedValue (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Pov::UnboundedValue` (r:1 w:0) + /// Proof: `Pov::UnboundedValue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn storage_value_unbounded_read() -> Weight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 1_079_000 picoseconds. - Weight::from_parts(1_176_000, 1594) + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 1594) .saturating_add(T::DbWeight::get().reads(1_u64)) } - /// Storage: Pov UnboundedValue (r:1 w:0) - /// Proof Skipped: Pov UnboundedValue (max_values: Some(1), max_size: None, mode: Ignored) + /// Storage: `Pov::UnboundedValue` (r:1 w:0) + /// Proof: `Pov::UnboundedValue` (`max_values`: Some(1), `max_size`: None, mode: `Ignored`) fn storage_value_unbounded_ignored_read() -> Weight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `0` - // Minimum execution time: 1_101_000 picoseconds. - Weight::from_parts(1_160_000, 0) + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 0) .saturating_add(T::DbWeight::get().reads(1_u64)) } - /// Storage: Pov UnboundedValue (r:1 w:0) - /// Proof Skipped: Pov UnboundedValue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Pov BoundedValue (r:1 w:0) - /// Proof: Pov BoundedValue (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) + /// Storage: `Pov::UnboundedValue` (r:1 w:0) + /// Proof: `Pov::UnboundedValue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Pov::BoundedValue` (r:1 w:0) + /// Proof: `Pov::BoundedValue` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) fn storage_value_bounded_and_unbounded_read() -> Weight { // Proof Size summary in bytes: // Measured: `147` // Estimated: `1632` - // Minimum execution time: 2_143_000 picoseconds. - Weight::from_parts(2_280_000, 1632) + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(5_000_000, 1632) .saturating_add(T::DbWeight::get().reads(2_u64)) } - /// Storage: Pov LargeValue (r:1 w:0) - /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: Measured) + /// Storage: `Pov::LargeValue` (r:1 w:0) + /// Proof: `Pov::LargeValue` (`max_values`: Some(1), `max_size`: Some(4194308), added: 4194803, mode: `Measured`) /// The range of component `l` is `[0, 4194304]`. fn measured_storage_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `142 + l * (1 ±0)` // Estimated: `1626 + l * (1 ±0)` - // Minimum execution time: 1_665_000 picoseconds. - Weight::from_parts(1_725_000, 1626) - // Standard Error: 3 - .saturating_add(Weight::from_parts(376, 0).saturating_mul(l.into())) + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(3_000_000, 1626) + // Standard Error: 1 + .saturating_add(Weight::from_parts(393, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(l.into())) } - /// Storage: Pov LargeValue (r:1 w:0) - /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) + /// Storage: `Pov::LargeValue` (r:1 w:0) + /// Proof: `Pov::LargeValue` (`max_values`: Some(1), `max_size`: Some(4194308), added: 4194803, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 4194304]`. fn mel_storage_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `142 + l * (1 ±0)` // Estimated: `4195793` - // Minimum execution time: 1_640_000 picoseconds. - Weight::from_parts(1_724_000, 4195793) - // Standard Error: 4 - .saturating_add(Weight::from_parts(395, 0).saturating_mul(l.into())) + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(3_000_000, 4195793) + // Standard Error: 1 + .saturating_add(Weight::from_parts(394, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) } - /// Storage: Pov LargeValue (r:1 w:0) - /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: Measured) - /// Storage: Pov LargeValue2 (r:1 w:0) - /// Proof: Pov LargeValue2 (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: Measured) + /// Storage: `Pov::LargeValue` (r:1 w:0) + /// Proof: `Pov::LargeValue` (`max_values`: Some(1), `max_size`: Some(4194308), added: 4194803, mode: `Measured`) + /// Storage: `Pov::LargeValue2` (r:1 w:0) + /// Proof: `Pov::LargeValue2` (`max_values`: Some(1), `max_size`: Some(4194308), added: 4194803, mode: `Measured`) /// The range of component `l` is `[0, 4194304]`. fn measured_storage_double_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `171 + l * (2 ±0)` // Estimated: `1655 + l * (2 ±0)` - // Minimum execution time: 2_263_000 picoseconds. - Weight::from_parts(2_358_000, 1655) - // Standard Error: 8 - .saturating_add(Weight::from_parts(737, 0).saturating_mul(l.into())) + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(4_000_000, 1655) + // Standard Error: 2 + .saturating_add(Weight::from_parts(655, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(Weight::from_parts(0, 2).saturating_mul(l.into())) } - /// Storage: Pov LargeValue (r:1 w:0) - /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) - /// Storage: Pov LargeValue2 (r:1 w:0) - /// Proof: Pov LargeValue2 (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) + /// Storage: `Pov::LargeValue` (r:1 w:0) + /// Proof: `Pov::LargeValue` (`max_values`: Some(1), `max_size`: Some(4194308), added: 4194803, mode: `MaxEncodedLen`) + /// Storage: `Pov::LargeValue2` (r:1 w:0) + /// Proof: `Pov::LargeValue2` (`max_values`: Some(1), `max_size`: Some(4194308), added: 4194803, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 4194304]`. fn mel_storage_double_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `171 + l * (2 ±0)` // Estimated: `4195793` - // Minimum execution time: 2_161_000 picoseconds. - Weight::from_parts(2_233_000, 4195793) - // Standard Error: 5 - .saturating_add(Weight::from_parts(639, 0).saturating_mul(l.into())) + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(4_000_000, 4195793) + // Standard Error: 2 + .saturating_add(Weight::from_parts(660, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) } - /// Storage: Pov LargeValue (r:1 w:0) - /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) - /// Storage: Pov LargeValue2 (r:1 w:0) - /// Proof: Pov LargeValue2 (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: Measured) + /// Storage: `Pov::LargeValue` (r:1 w:0) + /// Proof: `Pov::LargeValue` (`max_values`: Some(1), `max_size`: Some(4194308), added: 4194803, mode: `MaxEncodedLen`) + /// Storage: `Pov::LargeValue2` (r:1 w:0) + /// Proof: `Pov::LargeValue2` (`max_values`: Some(1), `max_size`: Some(4194308), added: 4194803, mode: `Measured`) /// The range of component `l` is `[0, 4194304]`. fn mel_mixed_storage_double_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `171 + l * (2 ±0)` // Estimated: `4195793 + l * (2 ±0)` - // Minimum execution time: 2_149_000 picoseconds. - Weight::from_parts(2_256_000, 4195793) - // Standard Error: 6 - .saturating_add(Weight::from_parts(677, 0).saturating_mul(l.into())) + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(4_000_000, 4195793) + // Standard Error: 4 + .saturating_add(Weight::from_parts(691, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(Weight::from_parts(0, 2).saturating_mul(l.into())) } - /// Storage: Pov LargeValue (r:1 w:0) - /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: Measured) - /// Storage: Pov LargeValue2 (r:1 w:0) - /// Proof: Pov LargeValue2 (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) + /// Storage: `Pov::LargeValue` (r:1 w:0) + /// Proof: `Pov::LargeValue` (`max_values`: Some(1), `max_size`: Some(4194308), added: 4194803, mode: `Measured`) + /// Storage: `Pov::LargeValue2` (r:1 w:0) + /// Proof: `Pov::LargeValue2` (`max_values`: Some(1), `max_size`: Some(4194308), added: 4194803, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 4194304]`. fn measured_mixed_storage_double_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `171 + l * (2 ±0)` // Estimated: `4195793 + l * (2 ±0)` - // Minimum execution time: 2_254_000 picoseconds. - Weight::from_parts(2_319_000, 4195793) - // Standard Error: 5 - .saturating_add(Weight::from_parts(664, 0).saturating_mul(l.into())) + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(4_000_000, 4195793) + // Standard Error: 4 + .saturating_add(Weight::from_parts(691, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(Weight::from_parts(0, 2).saturating_mul(l.into())) } - /// Storage: Pov UnboundedMap (r:1 w:0) - /// Proof Skipped: Pov UnboundedMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Pov UnboundedMap2 (r:1 w:0) - /// Proof Skipped: Pov UnboundedMap2 (max_values: None, max_size: None, mode: Measured) + /// Storage: `Pov::UnboundedMap` (r:1 w:0) + /// Proof: `Pov::UnboundedMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Pov::UnboundedMap2` (r:1 w:0) + /// Proof: `Pov::UnboundedMap2` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `i` is `[0, 1000]`. fn storage_map_unbounded_both_measured_read(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `229 + i * (8 ±0)` // Estimated: `3693 + i * (8 ±0)` - // Minimum execution time: 3_071_000 picoseconds. - Weight::from_parts(3_487_712, 3693) - // Standard Error: 26 - .saturating_add(Weight::from_parts(748, 0).saturating_mul(i.into())) + // Minimum execution time: 6_000_000 picoseconds. + Weight::from_parts(7_274_226, 3693) + // Standard Error: 280 + .saturating_add(Weight::from_parts(3_282, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(i.into())) } - /// Storage: Pov Map1M (r:1 w:0) - /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) - /// Storage: Pov UnboundedMap (r:1 w:0) - /// Proof Skipped: Pov UnboundedMap (max_values: None, max_size: None, mode: Measured) + /// Storage: `Pov::Map1M` (r:1 w:0) + /// Proof: `Pov::Map1M` (`max_values`: Some(1000000), `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + /// Storage: `Pov::UnboundedMap` (r:1 w:0) + /// Proof: `Pov::UnboundedMap` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `i` is `[0, 1000]`. fn storage_map_partial_unbounded_read(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `228 + i * (4 ±0)` // Estimated: `3692 + i * (4 ±0)` - // Minimum execution time: 3_150_000 picoseconds. - Weight::from_parts(3_582_963, 3692) - // Standard Error: 18 - .saturating_add(Weight::from_parts(380, 0).saturating_mul(i.into())) + // Minimum execution time: 7_000_000 picoseconds. + Weight::from_parts(7_507_333, 3692) + // Standard Error: 64 + .saturating_add(Weight::from_parts(982, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(Weight::from_parts(0, 4).saturating_mul(i.into())) } - /// Storage: Pov Map1M (r:1 w:0) - /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) - /// Storage: Pov UnboundedMap (r:1 w:0) - /// Proof Skipped: Pov UnboundedMap (max_values: None, max_size: None, mode: Ignored) + /// Storage: `Pov::Map1M` (r:1 w:0) + /// Proof: `Pov::Map1M` (`max_values`: Some(1000000), `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + /// Storage: `Pov::UnboundedMap` (r:1 w:0) + /// Proof: `Pov::UnboundedMap` (`max_values`: None, `max_size`: None, mode: `Ignored`) /// The range of component `i` is `[0, 1000]`. fn storage_map_partial_unbounded_ignored_read(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `228 + i * (4 ±0)` // Estimated: `3501 + i * (4 ±0)` - // Minimum execution time: 3_092_000 picoseconds. - Weight::from_parts(3_595_328, 3501) - // Standard Error: 20 - .saturating_add(Weight::from_parts(243, 0).saturating_mul(i.into())) + // Minimum execution time: 6_000_000 picoseconds. + Weight::from_parts(7_285_011, 3501) + // Standard Error: 80 + .saturating_add(Weight::from_parts(1_395, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(Weight::from_parts(0, 4).saturating_mul(i.into())) } @@ -442,382 +440,382 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_705_000 picoseconds. - Weight::from_parts(1_818_000, 0) + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(5_000_000, 0) } fn noop() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 533_000 picoseconds. - Weight::from_parts(587_000, 0) + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 0) } - /// Storage: Pov UnboundedMapTwox (r:65001 w:0) - /// Proof Skipped: Pov UnboundedMapTwox (max_values: None, max_size: None, mode: Measured) + /// Storage: `Pov::UnboundedMapTwox` (r:65001 w:0) + /// Proof: `Pov::UnboundedMapTwox` (`max_values`: None, `max_size`: None, mode: `Measured`) fn storage_iteration() -> Weight { // Proof Size summary in bytes: // Measured: `17985289` // Estimated: `178863754` - // Minimum execution time: 118_753_057_000 picoseconds. - Weight::from_parts(121_396_503_000, 178863754) + // Minimum execution time: 218_275_000_000 picoseconds. + Weight::from_parts(222_603_000_000, 178863754) .saturating_add(T::DbWeight::get().reads(65001_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: Pov Value (r:1 w:0) - /// Proof: Pov Value (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `Pov::Value` (r:1 w:0) + /// Proof: `Pov::Value` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn storage_single_value_read() -> Weight { // Proof Size summary in bytes: // Measured: `136` // Estimated: `1489` - // Minimum execution time: 1_706_000 picoseconds. - Weight::from_parts(1_788_000, 1489) + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(3_000_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) } - /// Storage: Pov Value (r:1 w:0) - /// Proof: Pov Value (max_values: Some(1), max_size: Some(4), added: 499, mode: Ignored) + /// Storage: `Pov::Value` (r:1 w:0) + /// Proof: `Pov::Value` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `Ignored`) fn storage_single_value_ignored_read() -> Weight { // Proof Size summary in bytes: // Measured: `136` // Estimated: `0` - // Minimum execution time: 1_661_000 picoseconds. - Weight::from_parts(1_718_000, 0) + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(3_000_000, 0) .saturating_add(RocksDbWeight::get().reads(1_u64)) } - /// Storage: Pov Value (r:1 w:0) - /// Proof: Pov Value (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Pov Value2 (r:1 w:0) - /// Proof: Pov Value2 (max_values: Some(1), max_size: Some(4), added: 499, mode: Ignored) + /// Storage: `Pov::Value` (r:1 w:0) + /// Proof: `Pov::Value` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Pov::Value2` (r:1 w:0) + /// Proof: `Pov::Value2` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `Ignored`) fn storage_single_value_ignored_some_read() -> Weight { // Proof Size summary in bytes: // Measured: `160` // Estimated: `1489` - // Minimum execution time: 2_226_000 picoseconds. - Weight::from_parts(2_365_000, 1489) + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(4_000_000, 1489) .saturating_add(RocksDbWeight::get().reads(2_u64)) } - /// Storage: Pov Value (r:1 w:0) - /// Proof: Pov Value (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `Pov::Value` (r:1 w:0) + /// Proof: `Pov::Value` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn storage_single_value_read_twice() -> Weight { // Proof Size summary in bytes: // Measured: `136` // Estimated: `1489` - // Minimum execution time: 1_785_000 picoseconds. - Weight::from_parts(1_980_000, 1489) + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(4_000_000, 1489) .saturating_add(RocksDbWeight::get().reads(1_u64)) } - /// Storage: Pov Value (r:0 w:1) - /// Proof: Pov Value (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `Pov::Value` (r:0 w:1) + /// Proof: `Pov::Value` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn storage_single_value_write() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 254_000 picoseconds. - Weight::from_parts(326_000, 0) + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(1_000_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Pov Value (r:0 w:1) - /// Proof: Pov Value (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: `Pov::Value` (r:0 w:1) + /// Proof: `Pov::Value` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn storage_single_value_kill() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 239_000 picoseconds. - Weight::from_parts(277_000, 0) + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(1_000_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: Pov Map1M (r:1 w:0) - /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: Measured) + /// Storage: `Pov::Map1M` (r:1 w:0) + /// Proof: `Pov::Map1M` (`max_values`: Some(1000000), `max_size`: Some(36), added: 2511, mode: `Measured`) fn storage_1m_map_read_one_value_two_additional_layers() -> Weight { // Proof Size summary in bytes: // Measured: `1275` // Estimated: `4740` - // Minimum execution time: 4_760_000 picoseconds. - Weight::from_parts(5_051_000, 4740) + // Minimum execution time: 7_000_000 picoseconds. + Weight::from_parts(7_000_000, 4740) .saturating_add(RocksDbWeight::get().reads(1_u64)) } - /// Storage: Pov Map1M (r:1 w:0) - /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: Measured) + /// Storage: `Pov::Map1M` (r:1 w:0) + /// Proof: `Pov::Map1M` (`max_values`: Some(1000000), `max_size`: Some(36), added: 2511, mode: `Measured`) fn storage_1m_map_read_one_value_three_additional_layers() -> Weight { // Proof Size summary in bytes: // Measured: `1544` // Estimated: `5009` - // Minimum execution time: 5_490_000 picoseconds. - Weight::from_parts(5_703_000, 5009) + // Minimum execution time: 8_000_000 picoseconds. + Weight::from_parts(8_000_000, 5009) .saturating_add(RocksDbWeight::get().reads(1_u64)) } - /// Storage: Pov Map1M (r:1 w:0) - /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: Measured) + /// Storage: `Pov::Map1M` (r:1 w:0) + /// Proof: `Pov::Map1M` (`max_values`: Some(1000000), `max_size`: Some(36), added: 2511, mode: `Measured`) fn storage_1m_map_read_one_value_four_additional_layers() -> Weight { // Proof Size summary in bytes: // Measured: `2044` // Estimated: `5509` - // Minimum execution time: 6_397_000 picoseconds. - Weight::from_parts(7_084_000, 5509) + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(10_000_000, 5509) .saturating_add(RocksDbWeight::get().reads(1_u64)) } - /// Storage: Pov Map1M (r:100 w:0) - /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) - /// Storage: Pov Map16M (r:100 w:0) - /// Proof: Pov Map16M (max_values: Some(16000000), max_size: Some(36), added: 3006, mode: MaxEncodedLen) + /// Storage: `Pov::Map1M` (r:100 w:0) + /// Proof: `Pov::Map1M` (`max_values`: Some(1000000), `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + /// Storage: `Pov::Map16M` (r:100 w:0) + /// Proof: `Pov::Map16M` (`max_values`: Some(16000000), `max_size`: Some(36), added: 3006, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 100]`. /// The range of component `m` is `[0, 100]`. fn storage_map_read_per_component(n: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `515 + m * (188 ±0) + n * (188 ±0)` // Estimated: `990 + m * (2511 ±0) + n * (3006 ±0)` - // Minimum execution time: 181_481_000 picoseconds. - Weight::from_parts(129_275_141, 990) - // Standard Error: 13_049 - .saturating_add(Weight::from_parts(787_667, 0).saturating_mul(n.into())) - // Standard Error: 13_049 - .saturating_add(Weight::from_parts(830_378, 0).saturating_mul(m.into())) + // Minimum execution time: 342_000_000 picoseconds. + Weight::from_parts(179_688_624, 990) + // Standard Error: 26_526 + .saturating_add(Weight::from_parts(2_061_828, 0).saturating_mul(n.into())) + // Standard Error: 26_526 + .saturating_add(Weight::from_parts(1_825_923, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(Weight::from_parts(0, 2511).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 3006).saturating_mul(n.into())) } - /// Storage: Pov Map1M (r:100 w:0) - /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: Ignored) - /// Storage: Pov Map16M (r:100 w:0) - /// Proof: Pov Map16M (max_values: Some(16000000), max_size: Some(36), added: 3006, mode: MaxEncodedLen) + /// Storage: `Pov::Map1M` (r:100 w:0) + /// Proof: `Pov::Map1M` (`max_values`: Some(1000000), `max_size`: Some(36), added: 2511, mode: `Ignored`) + /// Storage: `Pov::Map16M` (r:100 w:0) + /// Proof: `Pov::Map16M` (`max_values`: Some(16000000), `max_size`: Some(36), added: 3006, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 100]`. /// The range of component `m` is `[0, 100]`. fn storage_map_read_per_component_one_ignored(n: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `515 + m * (188 ±0) + n * (188 ±0)` // Estimated: `1685 + m * (189 ±0) + n * (3006 ±0)` - // Minimum execution time: 181_925_000 picoseconds. - Weight::from_parts(134_416_814, 1685) - // Standard Error: 15_678 - .saturating_add(Weight::from_parts(827_168, 0).saturating_mul(n.into())) - // Standard Error: 15_678 - .saturating_add(Weight::from_parts(813_655, 0).saturating_mul(m.into())) + // Minimum execution time: 342_000_000 picoseconds. + Weight::from_parts(204_945_396, 1685) + // Standard Error: 25_217 + .saturating_add(Weight::from_parts(1_827_513, 0).saturating_mul(n.into())) + // Standard Error: 25_217 + .saturating_add(Weight::from_parts(1_661_271, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(Weight::from_parts(0, 189).saturating_mul(m.into())) .saturating_add(Weight::from_parts(0, 3006).saturating_mul(n.into())) } - /// Storage: Pov Map1M (r:1 w:0) - /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// Storage: `Pov::Map1M` (r:1 w:0) + /// Proof: `Pov::Map1M` (`max_values`: Some(1000000), `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 100]`. fn storage_1m_map_one_entry_repeated_read(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `170` // Estimated: `3501` - // Minimum execution time: 20_000 picoseconds. - Weight::from_parts(2_006_399, 3501) - // Standard Error: 808 - .saturating_add(Weight::from_parts(263_609, 0).saturating_mul(n.into())) + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(3_387_064, 3501) + // Standard Error: 1_445 + .saturating_add(Weight::from_parts(1_143_678, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) } - /// Storage: Pov Map1M (r:100 w:0) - /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) + /// Storage: `Pov::Map1M` (r:100 w:0) + /// Proof: `Pov::Map1M` (`max_values`: Some(1000000), `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 100]`. fn storage_1m_map_multiple_entry_repeated_read(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `147 + n * (40 ±0)` // Estimated: `990 + n * (2511 ±0)` - // Minimum execution time: 21_000 picoseconds. - Weight::from_parts(3_940_044, 990) - // Standard Error: 4_906 - .saturating_add(Weight::from_parts(3_454_882, 0).saturating_mul(n.into())) + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(1_323_684, 990) + // Standard Error: 10_546 + .saturating_add(Weight::from_parts(13_101_864, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2511).saturating_mul(n.into())) } - /// Storage: Pov DoubleMap1M (r:1024 w:0) - /// Proof: Pov DoubleMap1M (max_values: Some(1000000), max_size: Some(68), added: 2543, mode: MaxEncodedLen) + /// Storage: `Pov::DoubleMap1M` (r:1024 w:0) + /// Proof: `Pov::DoubleMap1M` (`max_values`: Some(1000000), `max_size`: Some(68), added: 2543, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1024]`. fn storage_1m_double_map_read_per_component(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `21938 + n * (57 ±0)` // Estimated: `990 + n * (2543 ±0)` - // Minimum execution time: 28_000 picoseconds. - Weight::from_parts(20_674_869, 990) - // Standard Error: 3_035 - .saturating_add(Weight::from_parts(1_995_730, 0).saturating_mul(n.into())) + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(39_703_963, 990) + // Standard Error: 10_589 + .saturating_add(Weight::from_parts(3_718_040, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2543).saturating_mul(n.into())) } - /// Storage: Pov BoundedValue (r:1 w:0) - /// Proof: Pov BoundedValue (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) + /// Storage: `Pov::BoundedValue` (r:1 w:0) + /// Proof: `Pov::BoundedValue` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) fn storage_value_bounded_read() -> Weight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1518` - // Minimum execution time: 1_091_000 picoseconds. - Weight::from_parts(1_181_000, 1518) + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 1518) .saturating_add(RocksDbWeight::get().reads(1_u64)) } - /// Storage: Pov UnboundedValue (r:1 w:0) - /// Proof Skipped: Pov UnboundedValue (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Pov::UnboundedValue` (r:1 w:0) + /// Proof: `Pov::UnboundedValue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn storage_value_unbounded_read() -> Weight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 1_079_000 picoseconds. - Weight::from_parts(1_176_000, 1594) + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 1594) .saturating_add(RocksDbWeight::get().reads(1_u64)) } - /// Storage: Pov UnboundedValue (r:1 w:0) - /// Proof Skipped: Pov UnboundedValue (max_values: Some(1), max_size: None, mode: Ignored) + /// Storage: `Pov::UnboundedValue` (r:1 w:0) + /// Proof: `Pov::UnboundedValue` (`max_values`: Some(1), `max_size`: None, mode: `Ignored`) fn storage_value_unbounded_ignored_read() -> Weight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `0` - // Minimum execution time: 1_101_000 picoseconds. - Weight::from_parts(1_160_000, 0) + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 0) .saturating_add(RocksDbWeight::get().reads(1_u64)) } - /// Storage: Pov UnboundedValue (r:1 w:0) - /// Proof Skipped: Pov UnboundedValue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Pov BoundedValue (r:1 w:0) - /// Proof: Pov BoundedValue (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) + /// Storage: `Pov::UnboundedValue` (r:1 w:0) + /// Proof: `Pov::UnboundedValue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Pov::BoundedValue` (r:1 w:0) + /// Proof: `Pov::BoundedValue` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) fn storage_value_bounded_and_unbounded_read() -> Weight { // Proof Size summary in bytes: // Measured: `147` // Estimated: `1632` - // Minimum execution time: 2_143_000 picoseconds. - Weight::from_parts(2_280_000, 1632) + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(5_000_000, 1632) .saturating_add(RocksDbWeight::get().reads(2_u64)) } - /// Storage: Pov LargeValue (r:1 w:0) - /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: Measured) + /// Storage: `Pov::LargeValue` (r:1 w:0) + /// Proof: `Pov::LargeValue` (`max_values`: Some(1), `max_size`: Some(4194308), added: 4194803, mode: `Measured`) /// The range of component `l` is `[0, 4194304]`. fn measured_storage_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `142 + l * (1 ±0)` // Estimated: `1626 + l * (1 ±0)` - // Minimum execution time: 1_665_000 picoseconds. - Weight::from_parts(1_725_000, 1626) - // Standard Error: 3 - .saturating_add(Weight::from_parts(376, 0).saturating_mul(l.into())) + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(3_000_000, 1626) + // Standard Error: 1 + .saturating_add(Weight::from_parts(393, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(l.into())) } - /// Storage: Pov LargeValue (r:1 w:0) - /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) + /// Storage: `Pov::LargeValue` (r:1 w:0) + /// Proof: `Pov::LargeValue` (`max_values`: Some(1), `max_size`: Some(4194308), added: 4194803, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 4194304]`. fn mel_storage_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `142 + l * (1 ±0)` // Estimated: `4195793` - // Minimum execution time: 1_640_000 picoseconds. - Weight::from_parts(1_724_000, 4195793) - // Standard Error: 4 - .saturating_add(Weight::from_parts(395, 0).saturating_mul(l.into())) + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(3_000_000, 4195793) + // Standard Error: 1 + .saturating_add(Weight::from_parts(394, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) } - /// Storage: Pov LargeValue (r:1 w:0) - /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: Measured) - /// Storage: Pov LargeValue2 (r:1 w:0) - /// Proof: Pov LargeValue2 (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: Measured) + /// Storage: `Pov::LargeValue` (r:1 w:0) + /// Proof: `Pov::LargeValue` (`max_values`: Some(1), `max_size`: Some(4194308), added: 4194803, mode: `Measured`) + /// Storage: `Pov::LargeValue2` (r:1 w:0) + /// Proof: `Pov::LargeValue2` (`max_values`: Some(1), `max_size`: Some(4194308), added: 4194803, mode: `Measured`) /// The range of component `l` is `[0, 4194304]`. fn measured_storage_double_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `171 + l * (2 ±0)` // Estimated: `1655 + l * (2 ±0)` - // Minimum execution time: 2_263_000 picoseconds. - Weight::from_parts(2_358_000, 1655) - // Standard Error: 8 - .saturating_add(Weight::from_parts(737, 0).saturating_mul(l.into())) + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(4_000_000, 1655) + // Standard Error: 2 + .saturating_add(Weight::from_parts(655, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(Weight::from_parts(0, 2).saturating_mul(l.into())) } - /// Storage: Pov LargeValue (r:1 w:0) - /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) - /// Storage: Pov LargeValue2 (r:1 w:0) - /// Proof: Pov LargeValue2 (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) + /// Storage: `Pov::LargeValue` (r:1 w:0) + /// Proof: `Pov::LargeValue` (`max_values`: Some(1), `max_size`: Some(4194308), added: 4194803, mode: `MaxEncodedLen`) + /// Storage: `Pov::LargeValue2` (r:1 w:0) + /// Proof: `Pov::LargeValue2` (`max_values`: Some(1), `max_size`: Some(4194308), added: 4194803, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 4194304]`. fn mel_storage_double_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `171 + l * (2 ±0)` // Estimated: `4195793` - // Minimum execution time: 2_161_000 picoseconds. - Weight::from_parts(2_233_000, 4195793) - // Standard Error: 5 - .saturating_add(Weight::from_parts(639, 0).saturating_mul(l.into())) + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(4_000_000, 4195793) + // Standard Error: 2 + .saturating_add(Weight::from_parts(660, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) } - /// Storage: Pov LargeValue (r:1 w:0) - /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) - /// Storage: Pov LargeValue2 (r:1 w:0) - /// Proof: Pov LargeValue2 (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: Measured) + /// Storage: `Pov::LargeValue` (r:1 w:0) + /// Proof: `Pov::LargeValue` (`max_values`: Some(1), `max_size`: Some(4194308), added: 4194803, mode: `MaxEncodedLen`) + /// Storage: `Pov::LargeValue2` (r:1 w:0) + /// Proof: `Pov::LargeValue2` (`max_values`: Some(1), `max_size`: Some(4194308), added: 4194803, mode: `Measured`) /// The range of component `l` is `[0, 4194304]`. fn mel_mixed_storage_double_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `171 + l * (2 ±0)` // Estimated: `4195793 + l * (2 ±0)` - // Minimum execution time: 2_149_000 picoseconds. - Weight::from_parts(2_256_000, 4195793) - // Standard Error: 6 - .saturating_add(Weight::from_parts(677, 0).saturating_mul(l.into())) + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(4_000_000, 4195793) + // Standard Error: 4 + .saturating_add(Weight::from_parts(691, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(Weight::from_parts(0, 2).saturating_mul(l.into())) } - /// Storage: Pov LargeValue (r:1 w:0) - /// Proof: Pov LargeValue (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: Measured) - /// Storage: Pov LargeValue2 (r:1 w:0) - /// Proof: Pov LargeValue2 (max_values: Some(1), max_size: Some(4194308), added: 4194803, mode: MaxEncodedLen) + /// Storage: `Pov::LargeValue` (r:1 w:0) + /// Proof: `Pov::LargeValue` (`max_values`: Some(1), `max_size`: Some(4194308), added: 4194803, mode: `Measured`) + /// Storage: `Pov::LargeValue2` (r:1 w:0) + /// Proof: `Pov::LargeValue2` (`max_values`: Some(1), `max_size`: Some(4194308), added: 4194803, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 4194304]`. fn measured_mixed_storage_double_value_read_linear_size(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `171 + l * (2 ±0)` // Estimated: `4195793 + l * (2 ±0)` - // Minimum execution time: 2_254_000 picoseconds. - Weight::from_parts(2_319_000, 4195793) - // Standard Error: 5 - .saturating_add(Weight::from_parts(664, 0).saturating_mul(l.into())) + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(4_000_000, 4195793) + // Standard Error: 4 + .saturating_add(Weight::from_parts(691, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(Weight::from_parts(0, 2).saturating_mul(l.into())) } - /// Storage: Pov UnboundedMap (r:1 w:0) - /// Proof Skipped: Pov UnboundedMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Pov UnboundedMap2 (r:1 w:0) - /// Proof Skipped: Pov UnboundedMap2 (max_values: None, max_size: None, mode: Measured) + /// Storage: `Pov::UnboundedMap` (r:1 w:0) + /// Proof: `Pov::UnboundedMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Pov::UnboundedMap2` (r:1 w:0) + /// Proof: `Pov::UnboundedMap2` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `i` is `[0, 1000]`. fn storage_map_unbounded_both_measured_read(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `229 + i * (8 ±0)` // Estimated: `3693 + i * (8 ±0)` - // Minimum execution time: 3_071_000 picoseconds. - Weight::from_parts(3_487_712, 3693) - // Standard Error: 26 - .saturating_add(Weight::from_parts(748, 0).saturating_mul(i.into())) + // Minimum execution time: 6_000_000 picoseconds. + Weight::from_parts(7_274_226, 3693) + // Standard Error: 280 + .saturating_add(Weight::from_parts(3_282, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(i.into())) } - /// Storage: Pov Map1M (r:1 w:0) - /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) - /// Storage: Pov UnboundedMap (r:1 w:0) - /// Proof Skipped: Pov UnboundedMap (max_values: None, max_size: None, mode: Measured) + /// Storage: `Pov::Map1M` (r:1 w:0) + /// Proof: `Pov::Map1M` (`max_values`: Some(1000000), `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + /// Storage: `Pov::UnboundedMap` (r:1 w:0) + /// Proof: `Pov::UnboundedMap` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `i` is `[0, 1000]`. fn storage_map_partial_unbounded_read(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `228 + i * (4 ±0)` // Estimated: `3692 + i * (4 ±0)` - // Minimum execution time: 3_150_000 picoseconds. - Weight::from_parts(3_582_963, 3692) - // Standard Error: 18 - .saturating_add(Weight::from_parts(380, 0).saturating_mul(i.into())) + // Minimum execution time: 7_000_000 picoseconds. + Weight::from_parts(7_507_333, 3692) + // Standard Error: 64 + .saturating_add(Weight::from_parts(982, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(Weight::from_parts(0, 4).saturating_mul(i.into())) } - /// Storage: Pov Map1M (r:1 w:0) - /// Proof: Pov Map1M (max_values: Some(1000000), max_size: Some(36), added: 2511, mode: MaxEncodedLen) - /// Storage: Pov UnboundedMap (r:1 w:0) - /// Proof Skipped: Pov UnboundedMap (max_values: None, max_size: None, mode: Ignored) + /// Storage: `Pov::Map1M` (r:1 w:0) + /// Proof: `Pov::Map1M` (`max_values`: Some(1000000), `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + /// Storage: `Pov::UnboundedMap` (r:1 w:0) + /// Proof: `Pov::UnboundedMap` (`max_values`: None, `max_size`: None, mode: `Ignored`) /// The range of component `i` is `[0, 1000]`. fn storage_map_partial_unbounded_ignored_read(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `228 + i * (4 ±0)` // Estimated: `3501 + i * (4 ±0)` - // Minimum execution time: 3_092_000 picoseconds. - Weight::from_parts(3_595_328, 3501) - // Standard Error: 20 - .saturating_add(Weight::from_parts(243, 0).saturating_mul(i.into())) + // Minimum execution time: 6_000_000 picoseconds. + Weight::from_parts(7_285_011, 3501) + // Standard Error: 80 + .saturating_add(Weight::from_parts(1_395, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(Weight::from_parts(0, 4).saturating_mul(i.into())) } @@ -825,24 +823,24 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_705_000 picoseconds. - Weight::from_parts(1_818_000, 0) + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(5_000_000, 0) } fn noop() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 533_000 picoseconds. - Weight::from_parts(587_000, 0) + // Minimum execution time: 2_000_000 picoseconds. + Weight::from_parts(2_000_000, 0) } - /// Storage: Pov UnboundedMapTwox (r:65001 w:0) - /// Proof Skipped: Pov UnboundedMapTwox (max_values: None, max_size: None, mode: Measured) + /// Storage: `Pov::UnboundedMapTwox` (r:65001 w:0) + /// Proof: `Pov::UnboundedMapTwox` (`max_values`: None, `max_size`: None, mode: `Measured`) fn storage_iteration() -> Weight { // Proof Size summary in bytes: // Measured: `17985289` // Estimated: `178863754` - // Minimum execution time: 118_753_057_000 picoseconds. - Weight::from_parts(121_396_503_000, 178863754) + // Minimum execution time: 218_275_000_000 picoseconds. + Weight::from_parts(222_603_000_000, 178863754) .saturating_add(RocksDbWeight::get().reads(65001_u64)) } } diff --git a/substrate/frame/support/procedural/src/benchmark.rs b/substrate/frame/support/procedural/src/benchmark.rs index 27c75a7f054..ea53ad263a1 100644 --- a/substrate/frame/support/procedural/src/benchmark.rs +++ b/substrate/frame/support/procedural/src/benchmark.rs @@ -40,10 +40,14 @@ mod keywords { custom_keyword!(benchmarks); custom_keyword!(block); custom_keyword!(extra); + custom_keyword!(pov_mode); custom_keyword!(extrinsic_call); custom_keyword!(skip_meta); custom_keyword!(BenchmarkError); custom_keyword!(Result); + custom_keyword!(MaxEncodedLen); + custom_keyword!(Measured); + custom_keyword!(Ignored); pub const BENCHMARK_TOKEN: &str = stringify!(benchmark); pub const BENCHMARKS_TOKEN: &str = stringify!(benchmarks); @@ -73,51 +77,158 @@ struct RangeArgs { struct BenchmarkAttrs { skip_meta: bool, extra: bool, + pov_mode: Option, } /// Represents a single benchmark option -enum BenchmarkAttrKeyword { +enum BenchmarkAttr { Extra, SkipMeta, + /// How the PoV should be measured. + PoV(PovModeAttr), } -impl syn::parse::Parse for BenchmarkAttrKeyword { +impl syn::parse::Parse for PovModeAttr { + fn parse(input: ParseStream) -> Result { + let _pov: keywords::pov_mode = input.parse()?; + let _eq: Token![=] = input.parse()?; + let root = PovEstimationMode::parse(input)?; + + let mut maybe_content = None; + let _ = || -> Result<()> { + let content; + syn::braced!(content in input); + maybe_content = Some(content); + Ok(()) + }(); + + let per_key = match maybe_content { + Some(content) => { + let per_key = Punctuated::::parse_terminated(&content)?; + per_key.into_iter().collect() + }, + None => Vec::new(), + }; + + Ok(Self { root, per_key }) + } +} + +impl syn::parse::Parse for BenchmarkAttr { fn parse(input: ParseStream) -> Result { let lookahead = input.lookahead1(); if lookahead.peek(keywords::extra) { let _extra: keywords::extra = input.parse()?; - return Ok(BenchmarkAttrKeyword::Extra) + Ok(BenchmarkAttr::Extra) } else if lookahead.peek(keywords::skip_meta) { let _skip_meta: keywords::skip_meta = input.parse()?; - return Ok(BenchmarkAttrKeyword::SkipMeta) + Ok(BenchmarkAttr::SkipMeta) + } else if lookahead.peek(keywords::pov_mode) { + PovModeAttr::parse(input).map(BenchmarkAttr::PoV) + } else { + Err(lookahead.error()) + } + } +} + +/// A `#[pov_mode = .. { .. }]` attribute. +#[derive(Debug, Clone)] +struct PovModeAttr { + /// The root mode for this benchmarks. + root: PovEstimationMode, + /// The pov-mode for a specific key. This overwrites `root` for this key. + per_key: Vec, +} + +/// A single key-value pair inside the `{}` of a `#[pov_mode = .. { .. }]` attribute. +#[derive(Debug, Clone, derive_syn_parse::Parse)] +struct PovModeKeyAttr { + /// A specific storage key for which to set the PoV mode. + key: Path, + _underscore: Token![:], + /// The PoV mode for this key. + mode: PovEstimationMode, +} + +/// How the PoV should be estimated. +#[derive(Debug, Eq, PartialEq, Clone, Copy)] +pub enum PovEstimationMode { + /// Use the maximal encoded length as provided by [`codec::MaxEncodedLen`]. + MaxEncodedLen, + /// Measure the accessed value size in the pallet benchmarking and add some trie overhead. + Measured, + /// Do not estimate the PoV size for this storage item or benchmark. + Ignored, +} + +impl syn::parse::Parse for PovEstimationMode { + fn parse(input: ParseStream) -> Result { + let lookahead = input.lookahead1(); + if lookahead.peek(keywords::MaxEncodedLen) { + let _max_encoded_len: keywords::MaxEncodedLen = input.parse()?; + return Ok(PovEstimationMode::MaxEncodedLen) + } else if lookahead.peek(keywords::Measured) { + let _measured: keywords::Measured = input.parse()?; + return Ok(PovEstimationMode::Measured) + } else if lookahead.peek(keywords::Ignored) { + let _ignored: keywords::Ignored = input.parse()?; + return Ok(PovEstimationMode::Ignored) } else { return Err(lookahead.error()) } } } +impl ToString for PovEstimationMode { + fn to_string(&self) -> String { + match self { + PovEstimationMode::MaxEncodedLen => "MaxEncodedLen".into(), + PovEstimationMode::Measured => "Measured".into(), + PovEstimationMode::Ignored => "Ignored".into(), + } + } +} + +impl quote::ToTokens for PovEstimationMode { + fn to_tokens(&self, tokens: &mut TokenStream2) { + match self { + PovEstimationMode::MaxEncodedLen => tokens.extend(quote!(MaxEncodedLen)), + PovEstimationMode::Measured => tokens.extend(quote!(Measured)), + PovEstimationMode::Ignored => tokens.extend(quote!(Ignored)), + } + } +} + impl syn::parse::Parse for BenchmarkAttrs { fn parse(input: ParseStream) -> syn::Result { let mut extra = false; let mut skip_meta = false; - let args = Punctuated::::parse_terminated(&input)?; + let mut pov_mode = None; + let args = Punctuated::::parse_terminated(&input)?; + for arg in args.into_iter() { match arg { - BenchmarkAttrKeyword::Extra => { + BenchmarkAttr::Extra => { if extra { return Err(input.error("`extra` can only be specified once")) } extra = true; }, - BenchmarkAttrKeyword::SkipMeta => { + BenchmarkAttr::SkipMeta => { if skip_meta { return Err(input.error("`skip_meta` can only be specified once")) } skip_meta = true; }, + BenchmarkAttr::PoV(mode) => { + if pov_mode.is_some() { + return Err(input.error("`pov_mode` can only be specified once")) + } + pov_mode = Some(mode); + }, } } - Ok(BenchmarkAttrs { extra, skip_meta }) + Ok(BenchmarkAttrs { extra, skip_meta, pov_mode }) } } @@ -344,6 +455,7 @@ pub fn benchmarks( tokens: TokenStream, instance: bool, ) -> syn::Result { + let krate = generate_access_from_frame_or_crate("frame-benchmarking")?; // gather module info let module: ItemMod = syn::parse(tokens)?; let mod_span = module.span(); @@ -364,6 +476,8 @@ pub fn benchmarks( let mut benchmark_names: Vec = Vec::new(); let mut extra_benchmark_names: Vec = Vec::new(); let mut skip_meta_benchmark_names: Vec = Vec::new(); + // Map benchmarks to PoV modes. + let mut pov_modes = Vec::new(); let (_brace, mut content) = module.content.ok_or(syn::Error::new(mod_span, "Module cannot be empty!"))?; @@ -400,6 +514,25 @@ pub fn benchmarks( } else if benchmark_attrs.skip_meta { skip_meta_benchmark_names.push(name.clone()); } + + if let Some(mode) = benchmark_attrs.pov_mode { + let mut modes = Vec::new(); + // We cannot expand strings here since it is no-std, but syn does not expand bytes. + let name = name.to_string(); + let m = mode.root.to_string(); + modes.push(quote!(("ALL".as_bytes().to_vec(), #m.as_bytes().to_vec()))); + + for attr in mode.per_key.iter() { + // syn always puts spaces in quoted paths: + let key = attr.key.clone().into_token_stream().to_string().replace(" ", ""); + let mode = attr.mode.to_string(); + modes.push(quote!((#key.as_bytes().to_vec(), #mode.as_bytes().to_vec()))); + } + + pov_modes.push( + quote!((#name.as_bytes().to_vec(), #krate::__private::vec![#(#modes),*])), + ); + } } // expand benchmark @@ -419,7 +552,6 @@ pub fn benchmarks( true => quote!(T: Config, I: 'static), }; - let krate = generate_access_from_frame_or_crate("frame-benchmarking")?; let frame_system = generate_access_from_frame_or_crate("frame-system")?; // benchmark name variables @@ -537,6 +669,16 @@ pub fn benchmarks( ]; all_names.retain(|x| !extra.contains(x)); } + let pov_modes: + #krate::__private::Vec<( + #krate::__private::Vec, + #krate::__private::Vec<( + #krate::__private::Vec, + #krate::__private::Vec + )>, + )> = #krate::__private::vec![ + #( #pov_modes ),* + ]; all_names.into_iter().map(|benchmark| { let selected_benchmark = match benchmark { #(#selected_benchmark_mappings), @@ -544,12 +686,13 @@ pub fn benchmarks( _ => panic!("all benchmarks should be selectable") }; let components = >::components(&selected_benchmark); + let name = benchmark.as_bytes().to_vec(); + let modes = pov_modes.iter().find(|p| p.0 == name).map(|p| p.1.clone()); + #krate::BenchmarkMetadata { name: benchmark.as_bytes().to_vec(), components, - // TODO: Not supported by V2 syntax as of yet. - // https://github.com/paritytech/substrate/issues/13132 - pov_modes: #krate::__private::vec![], + pov_modes: modes.unwrap_or_default(), } }).collect::<#krate::__private::Vec<_>>() } diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_1.rs b/substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_1.rs new file mode 100644 index 00000000000..40ef884bf85 --- /dev/null +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_1.rs @@ -0,0 +1,31 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use frame_benchmarking::v2::*; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark(pov_mode = Wrong)] + fn bench() { + #[block] + {} + } +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_1.stderr b/substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_1.stderr new file mode 100644 index 00000000000..add80da6307 --- /dev/null +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_1.stderr @@ -0,0 +1,5 @@ +error: expected one of: `MaxEncodedLen`, `Measured`, `Ignored` + --> tests/benchmark_ui/bad_attr_pov_mode_1.rs:24:25 + | +24 | #[benchmark(pov_mode = Wrong)] + | ^^^^^ diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_2.rs b/substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_2.rs new file mode 100644 index 00000000000..151bb931e92 --- /dev/null +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_2.rs @@ -0,0 +1,33 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use frame_benchmarking::v2::*; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark(pov_mode = Measured { + Key: Wrong + })] + fn bench() { + #[block] + {} + } +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_2.stderr b/substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_2.stderr new file mode 100644 index 00000000000..0f9961afd89 --- /dev/null +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_2.stderr @@ -0,0 +1,5 @@ +error: expected one of: `MaxEncodedLen`, `Measured`, `Ignored` + --> tests/benchmark_ui/bad_attr_pov_mode_2.rs:25:8 + | +25 | Key: Wrong + | ^^^^^ diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_3.rs b/substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_3.rs new file mode 100644 index 00000000000..9c5e3801b1a --- /dev/null +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_3.rs @@ -0,0 +1,31 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use frame_benchmarking::v2::*; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark(pov_mode)] + fn bench() { + #[block] + {} + } +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_3.stderr b/substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_3.stderr new file mode 100644 index 00000000000..f28a993989a --- /dev/null +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_3.stderr @@ -0,0 +1,5 @@ +error: expected `=` + --> tests/benchmark_ui/bad_attr_pov_mode_3.rs:24:22 + | +24 | #[benchmark(pov_mode)] + | ^ diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_4.rs b/substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_4.rs new file mode 100644 index 00000000000..11ec5124d28 --- /dev/null +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_4.rs @@ -0,0 +1,31 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use frame_benchmarking::v2::*; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark(pov_mode =)] + fn bench() { + #[block] + {} + } +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_4.stderr b/substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_4.stderr new file mode 100644 index 00000000000..572b6b0815d --- /dev/null +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_attr_pov_mode_4.stderr @@ -0,0 +1,5 @@ +error: unexpected end of input, expected one of: `MaxEncodedLen`, `Measured`, `Ignored` + --> tests/benchmark_ui/bad_attr_pov_mode_4.rs:24:24 + | +24 | #[benchmark(pov_mode =)] + | ^ diff --git a/substrate/frame/support/test/tests/benchmark_ui/dup_attr_pov_mode.rs b/substrate/frame/support/test/tests/benchmark_ui/dup_attr_pov_mode.rs new file mode 100644 index 00000000000..f49636d181a --- /dev/null +++ b/substrate/frame/support/test/tests/benchmark_ui/dup_attr_pov_mode.rs @@ -0,0 +1,32 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use frame_benchmarking::v2::*; +use frame_support_test::Config; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark(pov_mode = Measured, pov_mode = MaxEncodedLen)] + fn bench() { + #[block] + {} + } +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/benchmark_ui/dup_attr_pov_mode.stderr b/substrate/frame/support/test/tests/benchmark_ui/dup_attr_pov_mode.stderr new file mode 100644 index 00000000000..aab91d271a6 --- /dev/null +++ b/substrate/frame/support/test/tests/benchmark_ui/dup_attr_pov_mode.stderr @@ -0,0 +1,14 @@ +error: unexpected end of input, `pov_mode` can only be specified once + --> tests/benchmark_ui/dup_attr_pov_mode.rs:25:59 + | +25 | #[benchmark(pov_mode = Measured, pov_mode = MaxEncodedLen)] + | ^ + +error: unused import: `frame_support_test::Config` + --> tests/benchmark_ui/dup_attr_pov_mode.rs:19:5 + | +19 | use frame_support_test::Config; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D unused-imports` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(unused_imports)]` diff --git a/substrate/frame/support/test/tests/benchmark_ui/pass/valid_attr_pov_mode.rs b/substrate/frame/support/test/tests/benchmark_ui/pass/valid_attr_pov_mode.rs new file mode 100644 index 00000000000..35fa1e76ae5 --- /dev/null +++ b/substrate/frame/support/test/tests/benchmark_ui/pass/valid_attr_pov_mode.rs @@ -0,0 +1,74 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use frame_benchmarking::v2::*; +use frame_support_test::Config; + +#[benchmarks] +mod benches { + use super::*; + + #[benchmark(skip_meta, extra, pov_mode = Measured)] + fn bench1() { + #[block] + {} + } + + #[benchmark(pov_mode = Measured, extra, skip_meta)] + fn bench2() { + #[block] + {} + } + + #[benchmark(extra, pov_mode = Measured { + Pallet: Measured, + Pallet::Storage: MaxEncodedLen, + }, skip_meta)] + fn bench3() { + #[block] + {} + } + + #[benchmark(skip_meta, extra, pov_mode = Measured { + Pallet::Storage: MaxEncodedLen, + Pallet::StorageSubKey: Measured, + })] + fn bench4() { + #[block] + {} + } + + #[benchmark(pov_mode = MaxEncodedLen { + Pallet::Storage: Measured, + Pallet::StorageSubKey: Measured + }, extra, skip_meta)] + fn bench5() { + #[block] + {} + } + + #[benchmark(pov_mode = MaxEncodedLen { + Pallet::Storage: Measured, + Pallet::Storage::Nested: Ignored + }, extra, skip_meta)] + fn bench6() { + #[block] + {} + } +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/benchmark_ui/pass/valid_basic.rs b/substrate/frame/support/test/tests/benchmark_ui/pass/valid_basic.rs index 126cee8fa6c..5899eb3562a 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/pass/valid_basic.rs +++ b/substrate/frame/support/test/tests/benchmark_ui/pass/valid_basic.rs @@ -22,7 +22,7 @@ use frame_support_test::Config; mod benches { use super::*; - #[benchmark(skip_meta, extra)] + #[benchmark(skip_meta, pov_mode = Measured, extra)] fn bench() { let a = 2 + 2; #[block] diff --git a/substrate/frame/support/test/tests/benchmark_ui/unrecognized_option.stderr b/substrate/frame/support/test/tests/benchmark_ui/unrecognized_option.stderr index bea770b634e..2eb06e396a8 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/unrecognized_option.stderr +++ b/substrate/frame/support/test/tests/benchmark_ui/unrecognized_option.stderr @@ -1,4 +1,4 @@ -error: expected `extra` or `skip_meta` +error: expected one of: `extra`, `skip_meta`, `pov_mode` --> tests/benchmark_ui/unrecognized_option.rs:26:32 | 26 | #[benchmark(skip_meta, extra, bad)] diff --git a/substrate/frame/whitelist/src/benchmarking.rs b/substrate/frame/whitelist/src/benchmarking.rs index 9d356f09a9d..7fb5632fc00 100644 --- a/substrate/frame/whitelist/src/benchmarking.rs +++ b/substrate/frame/whitelist/src/benchmarking.rs @@ -20,58 +20,57 @@ #![cfg(feature = "runtime-benchmarks")] use super::*; -use frame_benchmarking::v1::{benchmarks, BenchmarkError}; -use frame_support::{ensure, traits::EnsureOrigin}; +use frame_benchmarking::v2::*; +use frame_support::traits::EnsureOrigin; #[cfg(test)] use crate::Pallet as Whitelist; -benchmarks! { - whitelist_call { +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn whitelist_call() -> Result<(), BenchmarkError> { let origin = T::WhitelistOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call_hash = Default::default(); - }: _(origin, call_hash) - verify { - ensure!( - WhitelistedCall::::contains_key(call_hash), - "call not whitelisted" - ); - ensure!( - T::Preimages::is_requested(&call_hash), - "preimage not requested" - ); + + #[extrinsic_call] + _(origin as T::RuntimeOrigin, call_hash); + + ensure!(WhitelistedCall::::contains_key(call_hash), "call not whitelisted"); + ensure!(T::Preimages::is_requested(&call_hash), "preimage not requested"); + Ok(()) } - remove_whitelisted_call { + #[benchmark] + fn remove_whitelisted_call() -> Result<(), BenchmarkError> { let origin = T::WhitelistOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call_hash = Default::default(); Pallet::::whitelist_call(origin.clone(), call_hash) .expect("whitelisting call must be successful"); - }: _(origin, call_hash) - verify { - ensure!( - !WhitelistedCall::::contains_key(call_hash), - "whitelist not removed" - ); - ensure!( - !T::Preimages::is_requested(&call_hash), - "preimage still requested" - ); + + #[extrinsic_call] + _(origin as T::RuntimeOrigin, call_hash); + + ensure!(!WhitelistedCall::::contains_key(call_hash), "whitelist not removed"); + ensure!(!T::Preimages::is_requested(&call_hash), "preimage still requested"); + Ok(()) } // We benchmark with the maximum possible size for a call. // If the resulting weight is too big, maybe it worth having a weight which depends // on the size of the call, with a new witness in parameter. - #[pov_mode = MaxEncodedLen { + #[benchmark(pov_mode = MaxEncodedLen { // Use measured PoV size for the Preimages since we pass in a length witness. Preimage::PreimageFor: Measured - }] - dispatch_whitelisted_call { - // NOTE: we remove `10` because we need some bytes to encode the variants and vec length - let n in 1 .. T::Preimages::MAX_LENGTH as u32 - 10; - + })] + // NOTE: we remove `10` because we need some bytes to encode the variants and vec length + fn dispatch_whitelisted_call( + n: Linear<1, { T::Preimages::MAX_LENGTH as u32 - 10 }>, + ) -> Result<(), BenchmarkError> { let origin = T::DispatchWhitelistedOrigin::try_successful_origin() .map_err(|_| BenchmarkError::Weightless)?; let remark = sp_std::vec![1u8; n as usize]; @@ -86,21 +85,16 @@ benchmarks! { T::Preimages::note(encoded_call.into()).unwrap(); - }: _(origin, call_hash, call_encoded_len, call_weight) - verify { - ensure!( - !WhitelistedCall::::contains_key(call_hash), - "whitelist not removed" - ); - ensure!( - !T::Preimages::is_requested(&call_hash), - "preimage still requested" - ); - } + #[extrinsic_call] + _(origin as T::RuntimeOrigin, call_hash, call_encoded_len, call_weight); - dispatch_whitelisted_call_with_preimage { - let n in 1 .. 10_000; + ensure!(!WhitelistedCall::::contains_key(call_hash), "whitelist not removed"); + ensure!(!T::Preimages::is_requested(&call_hash), "preimage still requested"); + Ok(()) + } + #[benchmark] + fn dispatch_whitelisted_call_with_preimage(n: Linear<1, 10_000>) -> Result<(), BenchmarkError> { let origin = T::DispatchWhitelistedOrigin::try_successful_origin() .map_err(|_| BenchmarkError::Weightless)?; let remark = sp_std::vec![1u8; n as usize]; @@ -110,16 +104,13 @@ benchmarks! { Pallet::::whitelist_call(origin.clone(), call_hash) .expect("whitelisting call must be successful"); - }: _(origin, Box::new(call)) - verify { - ensure!( - !WhitelistedCall::::contains_key(call_hash), - "whitelist not removed" - ); - ensure!( - !T::Preimages::is_requested(&call_hash), - "preimage still requested" - ); + + #[extrinsic_call] + _(origin as T::RuntimeOrigin, Box::new(call)); + + ensure!(!WhitelistedCall::::contains_key(call_hash), "whitelist not removed"); + ensure!(!T::Preimages::is_requested(&call_hash), "preimage still requested"); + Ok(()) } impl_benchmark_test_suite!(Whitelist, crate::mock::new_test_ext(), crate::mock::Test); -- GitLab From 817870e3b25cebb3dd9c0934bcafcafb2532d96a Mon Sep 17 00:00:00 2001 From: Matteo Muraca <56828990+muraca@users.noreply.github.com> Date: Tue, 19 Mar 2024 14:55:23 +0100 Subject: [PATCH 060/187] Removed `pallet::getter` usage from Beefy and MMR pallets (#3740) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part of #3326 cc @kianenigma @ggwpez @liamaharon polkadot address: 12poSUQPtcF1HUPQGY3zZu2P8emuW9YnsPduA4XG3oCEfJVp --------- Signed-off-by: Matteo Muraca --- polkadot/runtime/rococo/src/lib.rs | 6 +-- polkadot/runtime/westend/src/lib.rs | 6 +-- prdoc/pr_3740.prdoc | 18 +++++++ substrate/bin/node/runtime/src/lib.rs | 6 +-- substrate/frame/beefy-mmr/src/lib.rs | 10 ++-- substrate/frame/beefy-mmr/src/tests.rs | 4 +- substrate/frame/beefy/src/equivocation.rs | 2 +- substrate/frame/beefy/src/lib.rs | 48 ++++++++----------- substrate/frame/beefy/src/tests.rs | 26 +++++----- .../frame/merkle-mountain-range/src/lib.rs | 13 +++-- .../merkle-mountain-range/src/mmr/storage.rs | 6 +-- .../frame/merkle-mountain-range/src/tests.rs | 8 ++-- 12 files changed, 81 insertions(+), 72 deletions(-) create mode 100644 prdoc/pr_3740.prdoc diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 1f51258df08..f68870c98ea 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -1991,7 +1991,7 @@ sp_api::impl_runtime_apis! { #[api_version(3)] impl beefy_primitives::BeefyApi for Runtime { fn beefy_genesis() -> Option { - Beefy::genesis_block() + pallet_beefy::GenesisBlock::::get() } fn validator_set() -> Option> { @@ -2029,11 +2029,11 @@ sp_api::impl_runtime_apis! { #[api_version(2)] impl mmr::MmrApi for Runtime { fn mmr_root() -> Result { - Ok(Mmr::mmr_root()) + Ok(pallet_mmr::RootHash::::get()) } fn mmr_leaf_count() -> Result { - Ok(Mmr::mmr_leaves()) + Ok(pallet_mmr::NumberOfLeaves::::get()) } fn generate_proof( diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 15d78706d3a..f1d8841989c 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -2015,7 +2015,7 @@ sp_api::impl_runtime_apis! { impl beefy_primitives::BeefyApi for Runtime { fn beefy_genesis() -> Option { - Beefy::genesis_block() + pallet_beefy::GenesisBlock::::get() } fn validator_set() -> Option> { @@ -2052,11 +2052,11 @@ sp_api::impl_runtime_apis! { impl mmr::MmrApi for Runtime { fn mmr_root() -> Result { - Ok(Mmr::mmr_root()) + Ok(pallet_mmr::RootHash::::get()) } fn mmr_leaf_count() -> Result { - Ok(Mmr::mmr_leaves()) + Ok(pallet_mmr::NumberOfLeaves::::get()) } fn generate_proof( diff --git a/prdoc/pr_3740.prdoc b/prdoc/pr_3740.prdoc new file mode 100644 index 00000000000..03df8ec5fea --- /dev/null +++ b/prdoc/pr_3740.prdoc @@ -0,0 +1,18 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Removed `pallet::getter` usage from Beefy and MMR pallets + +doc: + - audience: Runtime Dev + description: | + This PR removes `pallet::getter` usage from `pallet-beefy`, `pallet-beefy-mmr` and `pallet-mmr`, and updates dependant code and runtimes accordingly. + The syntax `StorageItem::::get()` should be used instead. + +crates: + - name: pallet-beefy + - name: pallet-beefy-mmr + - name: pallet-mmr + - name: kitchensink-runtime + - name: rococo-runtime + - name: westend-runtime diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 0852264ef68..ca7e14f6eb1 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -2979,7 +2979,7 @@ impl_runtime_apis! { #[api_version(3)] impl sp_consensus_beefy::BeefyApi for Runtime { fn beefy_genesis() -> Option { - Beefy::genesis_block() + pallet_beefy::GenesisBlock::::get() } fn validator_set() -> Option> { @@ -3018,11 +3018,11 @@ impl_runtime_apis! { BlockNumber, > for Runtime { fn mmr_root() -> Result { - Ok(Mmr::mmr_root()) + Ok(pallet_mmr::RootHash::::get()) } fn mmr_leaf_count() -> Result { - Ok(Mmr::mmr_leaves()) + Ok(pallet_mmr::NumberOfLeaves::::get()) } fn generate_proof( diff --git a/substrate/frame/beefy-mmr/src/lib.rs b/substrate/frame/beefy-mmr/src/lib.rs index fa3caba7977..e423f1b342f 100644 --- a/substrate/frame/beefy-mmr/src/lib.rs +++ b/substrate/frame/beefy-mmr/src/lib.rs @@ -68,7 +68,7 @@ where ::BeefyId, >::MmrRoot(*root)), ); - >::deposit_log(digest); + frame_system::Pallet::::deposit_log(digest); } } @@ -126,7 +126,6 @@ pub mod pallet { /// Details of current BEEFY authority set. #[pallet::storage] - #[pallet::getter(fn beefy_authorities)] pub type BeefyAuthorities = StorageValue<_, BeefyAuthoritySet>, ValueQuery>; @@ -134,7 +133,6 @@ pub mod pallet { /// /// This storage entry is used as cache for calls to `update_beefy_next_authority_set`. #[pallet::storage] - #[pallet::getter(fn beefy_next_authorities)] pub type BeefyNextAuthorities = StorageValue<_, BeefyNextAuthoritySet>, ValueQuery>; } @@ -152,7 +150,7 @@ impl LeafDataProvider for Pallet { version: T::LeafVersion::get(), parent_number_and_hash: ParentNumberAndHash::::leaf_data(), leaf_extra: T::BeefyDataProvider::extra_data(), - beefy_next_authority_set: Pallet::::beefy_next_authorities(), + beefy_next_authority_set: BeefyNextAuthorities::::get(), } } } @@ -177,12 +175,12 @@ where impl Pallet { /// Return the currently active BEEFY authority set proof. pub fn authority_set_proof() -> BeefyAuthoritySet> { - Pallet::::beefy_authorities() + BeefyAuthorities::::get() } /// Return the next/queued BEEFY authority set proof. pub fn next_authority_set_proof() -> BeefyNextAuthoritySet> { - Pallet::::beefy_next_authorities() + BeefyNextAuthorities::::get() } /// Returns details of a BEEFY authority set. diff --git a/substrate/frame/beefy-mmr/src/tests.rs b/substrate/frame/beefy-mmr/src/tests.rs index ec756f83dff..fac799bf64e 100644 --- a/substrate/frame/beefy-mmr/src/tests.rs +++ b/substrate/frame/beefy-mmr/src/tests.rs @@ -107,7 +107,7 @@ fn should_contain_valid_leaf_data() { let mut ext = new_test_ext(vec![1, 2, 3, 4]); let parent_hash = ext.execute_with(|| { init_block(1); - >::parent_hash() + frame_system::Pallet::::parent_hash() }); let mmr_leaf = read_mmr_leaf(&mut ext, node_offchain_key(0, parent_hash)); @@ -132,7 +132,7 @@ fn should_contain_valid_leaf_data() { // build second block on top let parent_hash = ext.execute_with(|| { init_block(2); - >::parent_hash() + frame_system::Pallet::::parent_hash() }); let mmr_leaf = read_mmr_leaf(&mut ext, node_offchain_key(1, parent_hash)); diff --git a/substrate/frame/beefy/src/equivocation.rs b/substrate/frame/beefy/src/equivocation.rs index 0a7ede327c9..bbc6eae6af2 100644 --- a/substrate/frame/beefy/src/equivocation.rs +++ b/substrate/frame/beefy/src/equivocation.rs @@ -190,7 +190,7 @@ where evidence: EquivocationEvidenceFor, ) -> Result<(), DispatchError> { let (equivocation_proof, key_owner_proof) = evidence; - let reporter = reporter.or_else(|| >::author()); + let reporter = reporter.or_else(|| pallet_authorship::Pallet::::author()); let offender = equivocation_proof.offender_id().clone(); // We check the equivocation within the context of its set id (and diff --git a/substrate/frame/beefy/src/lib.rs b/substrate/frame/beefy/src/lib.rs index 0760446753a..87304eba8ba 100644 --- a/substrate/frame/beefy/src/lib.rs +++ b/substrate/frame/beefy/src/lib.rs @@ -120,20 +120,17 @@ pub mod pallet { /// The current authorities set #[pallet::storage] - #[pallet::getter(fn authorities)] - pub(super) type Authorities = + pub type Authorities = StorageValue<_, BoundedVec, ValueQuery>; /// The current validator set id #[pallet::storage] - #[pallet::getter(fn validator_set_id)] - pub(super) type ValidatorSetId = + pub type ValidatorSetId = StorageValue<_, sp_consensus_beefy::ValidatorSetId, ValueQuery>; /// Authorities set scheduled to be used with the next session #[pallet::storage] - #[pallet::getter(fn next_authorities)] - pub(super) type NextAuthorities = + pub type NextAuthorities = StorageValue<_, BoundedVec, ValueQuery>; /// A mapping from BEEFY set ID to the index of the *most recent* session for which its @@ -147,17 +144,14 @@ pub mod pallet { /// /// TWOX-NOTE: `ValidatorSetId` is not under user control. #[pallet::storage] - #[pallet::getter(fn session_for_set)] - pub(super) type SetIdSession = + pub type SetIdSession = StorageMap<_, Twox64Concat, sp_consensus_beefy::ValidatorSetId, SessionIndex>; /// Block number where BEEFY consensus is enabled/started. /// By changing this (through privileged `set_new_genesis()`), BEEFY consensus is effectively /// restarted from the newly set block number. #[pallet::storage] - #[pallet::getter(fn genesis_block)] - pub(super) type GenesisBlock = - StorageValue<_, Option>, ValueQuery>; + pub type GenesisBlock = StorageValue<_, Option>, ValueQuery>; #[pallet::genesis_config] pub struct GenesisConfig { @@ -186,7 +180,7 @@ pub mod pallet { // we panic here as runtime maintainers can simply reconfigure genesis and restart // the chain easily .expect("Authorities vec too big"); - >::put(&self.genesis_block); + GenesisBlock::::put(&self.genesis_block); } } @@ -303,8 +297,8 @@ pub mod pallet { impl Pallet { /// Return the current active BEEFY validator set. pub fn validator_set() -> Option> { - let validators: BoundedVec = Self::authorities(); - let id: sp_consensus_beefy::ValidatorSetId = Self::validator_set_id(); + let validators: BoundedVec = Authorities::::get(); + let id: sp_consensus_beefy::ValidatorSetId = ValidatorSetId::::get(); ValidatorSet::::new(validators, id) } @@ -326,19 +320,19 @@ impl Pallet { new: BoundedVec, queued: BoundedVec, ) { - >::put(&new); + Authorities::::put(&new); - let new_id = Self::validator_set_id() + 1u64; - >::put(new_id); + let new_id = ValidatorSetId::::get() + 1u64; + ValidatorSetId::::put(new_id); - >::put(&queued); + NextAuthorities::::put(&queued); if let Some(validator_set) = ValidatorSet::::new(new, new_id) { let log = DigestItem::Consensus( BEEFY_ENGINE_ID, ConsensusLog::AuthoritiesChange(validator_set.clone()).encode(), ); - >::deposit_log(log); + frame_system::Pallet::::deposit_log(log); let next_id = new_id + 1; if let Some(next_validator_set) = ValidatorSet::::new(queued, next_id) { @@ -355,7 +349,7 @@ impl Pallet { return Ok(()) } - if !>::get().is_empty() { + if !Authorities::::get().is_empty() { return Err(()) } @@ -364,10 +358,10 @@ impl Pallet { .map_err(|_| ())?; let id = GENESIS_AUTHORITY_SET_ID; - >::put(bounded_authorities); - >::put(id); + Authorities::::put(bounded_authorities); + ValidatorSetId::::put(id); // Like `pallet_session`, initialize the next validator set as well. - >::put(bounded_authorities); + NextAuthorities::::put(bounded_authorities); if let Some(validator_set) = ValidatorSet::::new(authorities.clone(), id) { let next_id = id + 1; @@ -442,9 +436,9 @@ where // We want to have at least one BEEFY mandatory block per session. Self::change_authorities(bounded_next_authorities, bounded_next_queued_authorities); - let validator_set_id = Self::validator_set_id(); + let validator_set_id = ValidatorSetId::::get(); // Update the mapping for the new set id that corresponds to the latest session (i.e. now). - let session_index = >::current_index(); + let session_index = pallet_session::Pallet::::current_index(); SetIdSession::::insert(validator_set_id, &session_index); // Prune old entry if limit reached. let max_set_id_session_entries = T::MaxSetIdSessionEntries::get().max(1); @@ -459,13 +453,13 @@ where ConsensusLog::::OnDisabled(i as AuthorityIndex).encode(), ); - >::deposit_log(log); + frame_system::Pallet::::deposit_log(log); } } impl IsMember for Pallet { fn is_member(authority_id: &T::BeefyId) -> bool { - Self::authorities().iter().any(|id| id == authority_id) + Authorities::::get().iter().any(|id| id == authority_id) } } diff --git a/substrate/frame/beefy/src/tests.rs b/substrate/frame/beefy/src/tests.rs index 453cf19a4fe..2950264e0c3 100644 --- a/substrate/frame/beefy/src/tests.rs +++ b/substrate/frame/beefy/src/tests.rs @@ -31,7 +31,7 @@ use sp_consensus_beefy::{ }; use sp_runtime::DigestItem; -use crate::{mock::*, Call, Config, Error, Weight, WeightInfo}; +use crate::{self as beefy, mock::*, Call, Config, Error, Weight, WeightInfo}; fn init_block(block: u64) { System::set_block_number(block); @@ -48,15 +48,15 @@ fn genesis_session_initializes_authorities() { let want = authorities.clone(); new_test_ext_raw_authorities(authorities).execute_with(|| { - let authorities = Beefy::authorities(); + let authorities = beefy::Authorities::::get(); assert_eq!(authorities.len(), 4); assert_eq!(want[0], authorities[0]); assert_eq!(want[1], authorities[1]); - assert!(Beefy::validator_set_id() == 0); + assert!(beefy::ValidatorSetId::::get() == 0); - let next_authorities = Beefy::next_authorities(); + let next_authorities = beefy::NextAuthorities::::get(); assert_eq!(next_authorities.len(), 4); assert_eq!(want[0], next_authorities[0]); @@ -70,11 +70,11 @@ fn session_change_updates_authorities() { let want_validators = authorities.clone(); new_test_ext(vec![1, 2, 3, 4]).execute_with(|| { - assert!(0 == Beefy::validator_set_id()); + assert!(0 == beefy::ValidatorSetId::::get()); init_block(1); - assert!(1 == Beefy::validator_set_id()); + assert!(1 == beefy::ValidatorSetId::::get()); let want = beefy_log(ConsensusLog::AuthoritiesChange( ValidatorSet::new(want_validators, 1).unwrap(), @@ -85,7 +85,7 @@ fn session_change_updates_authorities() { init_block(2); - assert!(2 == Beefy::validator_set_id()); + assert!(2 == beefy::ValidatorSetId::::get()); let want = beefy_log(ConsensusLog::AuthoritiesChange( ValidatorSet::new(vec![mock_beefy_id(2), mock_beefy_id(4)], 2).unwrap(), @@ -101,7 +101,7 @@ fn session_change_updates_next_authorities() { let want = vec![mock_beefy_id(1), mock_beefy_id(2), mock_beefy_id(3), mock_beefy_id(4)]; new_test_ext(vec![1, 2, 3, 4]).execute_with(|| { - let next_authorities = Beefy::next_authorities(); + let next_authorities = beefy::NextAuthorities::::get(); assert_eq!(next_authorities.len(), 4); assert_eq!(want[0], next_authorities[0]); @@ -111,7 +111,7 @@ fn session_change_updates_next_authorities() { init_block(1); - let next_authorities = Beefy::next_authorities(); + let next_authorities = beefy::NextAuthorities::::get(); assert_eq!(next_authorities.len(), 2); assert_eq!(want[1], next_authorities[0]); @@ -177,7 +177,7 @@ fn cleans_up_old_set_id_session_mappings() { // we should have a session id mapping for all the set ids from // `max_set_id_session_entries` eras we have observed for i in 1..=max_set_id_session_entries { - assert!(Beefy::session_for_set(i as u64).is_some()); + assert!(beefy::SetIdSession::::get(i as u64).is_some()); } // go through another `max_set_id_session_entries` sessions @@ -185,12 +185,12 @@ fn cleans_up_old_set_id_session_mappings() { // we should keep tracking the new mappings for new sessions for i in max_set_id_session_entries + 1..=max_set_id_session_entries * 2 { - assert!(Beefy::session_for_set(i as u64).is_some()); + assert!(beefy::SetIdSession::::get(i as u64).is_some()); } // but the old ones should have been pruned by now for i in 1..=max_set_id_session_entries { - assert!(Beefy::session_for_set(i as u64).is_none()); + assert!(beefy::SetIdSession::::get(i as u64).is_none()); } }); } @@ -804,7 +804,7 @@ fn set_new_genesis_works() { assert_ok!(Beefy::set_new_genesis(RuntimeOrigin::root(), new_genesis_delay,)); let expected = System::block_number() + new_genesis_delay; // verify new genesis was set - assert_eq!(Beefy::genesis_block(), Some(expected)); + assert_eq!(beefy::GenesisBlock::::get(), Some(expected)); // setting delay < 1 should fail assert_err!( diff --git a/substrate/frame/merkle-mountain-range/src/lib.rs b/substrate/frame/merkle-mountain-range/src/lib.rs index 664f4bc7390..e3eb0dc8cf5 100644 --- a/substrate/frame/merkle-mountain-range/src/lib.rs +++ b/substrate/frame/merkle-mountain-range/src/lib.rs @@ -183,7 +183,6 @@ pub mod pallet { /// Latest MMR Root hash. #[pallet::storage] - #[pallet::getter(fn mmr_root_hash)] pub type RootHash, I: 'static = ()> = StorageValue<_, HashOf, ValueQuery>; /// Current size of the MMR (number of leaves). @@ -204,7 +203,7 @@ pub mod pallet { impl, I: 'static> Hooks> for Pallet { fn on_initialize(_n: BlockNumberFor) -> Weight { use primitives::LeafDataProvider; - let leaves = Self::mmr_leaves(); + let leaves = NumberOfLeaves::::get(); let peaks_before = sp_mmr_primitives::utils::NodesUtils::new(leaves).number_of_peaks(); let data = T::LeafData::leaf_data(); @@ -225,8 +224,8 @@ pub mod pallet { }; >::on_new_root(&root); - >::put(leaves); - >::put(root); + NumberOfLeaves::::put(leaves); + RootHash::::put(root); let peaks_after = sp_mmr_primitives::utils::NodesUtils::new(leaves).number_of_peaks(); @@ -301,7 +300,7 @@ impl, I: 'static> Pallet { { let first_mmr_block = utils::first_mmr_block_num::>( >::block_number(), - Self::mmr_leaves(), + NumberOfLeaves::::get(), )?; utils::block_num_to_leaf_index::>(block_num, first_mmr_block) @@ -341,7 +340,7 @@ impl, I: 'static> Pallet { /// Return the on-chain MMR root hash. pub fn mmr_root() -> HashOf { - Self::mmr_root_hash() + RootHash::::get() } /// Verify MMR proof for given `leaves`. @@ -354,7 +353,7 @@ impl, I: 'static> Pallet { leaves: Vec>, proof: primitives::Proof>, ) -> Result<(), primitives::Error> { - if proof.leaf_count > Self::mmr_leaves() || + if proof.leaf_count > NumberOfLeaves::::get() || proof.leaf_count == 0 || (proof.items.len().saturating_add(leaves.len())) as u64 > proof.leaf_count { diff --git a/substrate/frame/merkle-mountain-range/src/mmr/storage.rs b/substrate/frame/merkle-mountain-range/src/mmr/storage.rs index 03039be83ac..96a20c3445e 100644 --- a/substrate/frame/merkle-mountain-range/src/mmr/storage.rs +++ b/substrate/frame/merkle-mountain-range/src/mmr/storage.rs @@ -111,7 +111,7 @@ where L: primitives::FullLeaf, { fn get_elem(&self, pos: NodeIndex) -> mmr_lib::Result>> { - Ok(>::get(pos).map(Node::Hash)) + Ok(Nodes::::get(pos).map(Node::Hash)) } fn append(&mut self, pos: NodeIndex, elems: Vec>) -> mmr_lib::Result<()> { @@ -147,7 +147,7 @@ where for elem in elems { // On-chain we are going to only store new peaks. if peaks_to_store.next_if_eq(&node_index).is_some() { - >::insert(node_index, elem.hash()); + Nodes::::insert(node_index, elem.hash()); } // We are storing full node off-chain (using indexing API). Self::store_to_offchain(node_index, parent_hash, &elem); @@ -164,7 +164,7 @@ where // And remove all remaining items from `peaks_before` collection. for pos in peaks_to_prune { - >::remove(pos); + Nodes::::remove(pos); } Ok(()) diff --git a/substrate/frame/merkle-mountain-range/src/tests.rs b/substrate/frame/merkle-mountain-range/src/tests.rs index 429df75182e..88de7511c9f 100644 --- a/substrate/frame/merkle-mountain-range/src/tests.rs +++ b/substrate/frame/merkle-mountain-range/src/tests.rs @@ -608,9 +608,9 @@ fn verification_should_be_stateless() { let mut ext = new_test_ext(); let (root_6, root_7) = ext.execute_with(|| { add_blocks(6); - let root_6 = crate::Pallet::::mmr_root_hash(); + let root_6 = crate::Pallet::::mmr_root(); add_blocks(1); - let root_7 = crate::Pallet::::mmr_root_hash(); + let root_7 = crate::Pallet::::mmr_root(); (root_6, root_7) }); ext.persist_offchain_overlay(); @@ -656,9 +656,9 @@ fn should_verify_batch_proof_statelessly() { let mut ext = new_test_ext(); let (root_6, root_7) = ext.execute_with(|| { add_blocks(6); - let root_6 = crate::Pallet::::mmr_root_hash(); + let root_6 = crate::Pallet::::mmr_root(); add_blocks(1); - let root_7 = crate::Pallet::::mmr_root_hash(); + let root_7 = crate::Pallet::::mmr_root(); (root_6, root_7) }); ext.persist_offchain_overlay(); -- GitLab From 923f27ccabe802cf1e7a4f31fa94ba8039b6be2c Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Tue, 19 Mar 2024 16:01:22 +0200 Subject: [PATCH 061/187] rpc: Enable `transaction_unstable_broadcast` RPC V2 API (#3713) This PR enables the `transaction_unstable_broadcast ` and `transaction_unstable_stop` RPC API. Since the API is unstable, we don't need to expose this in the release notes. After merging this, we could validate the API in subxt and stabilize it. Spec PR that stabilizes the API: https://github.com/paritytech/json-rpc-interface-spec/pull/139 cc @paritytech/subxt-team Signed-off-by: Alexandru Vasile --- substrate/client/service/src/builder.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/substrate/client/service/src/builder.rs b/substrate/client/service/src/builder.rs index 31d63c6a81d..e71313428da 100644 --- a/substrate/client/service/src/builder.rs +++ b/substrate/client/service/src/builder.rs @@ -64,7 +64,9 @@ use sc_rpc::{ DenyUnsafe, SubscriptionTaskExecutor, }; use sc_rpc_spec_v2::{ - archive::ArchiveApiServer, chain_head::ChainHeadApiServer, transaction::TransactionApiServer, + archive::ArchiveApiServer, + chain_head::ChainHeadApiServer, + transaction::{TransactionApiServer, TransactionBroadcastApiServer}, }; use sc_telemetry::{telemetry, ConnectionMessage, Telemetry, TelemetryHandle, SUBSTRATE_INFO}; use sc_transaction_pool_api::{MaintainedTransactionPool, TransactionPool}; @@ -653,6 +655,13 @@ where (chain, state, child_state) }; + let transaction_broadcast_rpc_v2 = sc_rpc_spec_v2::transaction::TransactionBroadcast::new( + client.clone(), + transaction_pool.clone(), + task_executor.clone(), + ) + .into_rpc(); + let transaction_v2 = sc_rpc_spec_v2::transaction::Transaction::new( client.clone(), transaction_pool.clone(), @@ -708,6 +717,9 @@ where // Part of the RPC v2 spec. rpc_api.merge(transaction_v2).map_err(|e| Error::Application(e.into()))?; + rpc_api + .merge(transaction_broadcast_rpc_v2) + .map_err(|e| Error::Application(e.into()))?; rpc_api.merge(chain_head_v2).map_err(|e| Error::Application(e.into()))?; // Part of the old RPC spec. -- GitLab From 5fd72a1f5e7f4db02b4962fb146e4b8d154a485c Mon Sep 17 00:00:00 2001 From: ordian Date: Tue, 19 Mar 2024 16:01:26 +0100 Subject: [PATCH 062/187] collator-side: send parent head data (#3521) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On top of #3302. We want the validators to upgrade first before we add changes to the collation side to send the new variants, which is why this part is extracted into a separate PR. The detection of when to send the parent head is based on the core assignments at the relay parent of the candidate. We probably want to make it more flexible in the future, but for now, it will work for a simple use case when a para always has multiple cores assigned to it. --------- Signed-off-by: Matteo Muraca Signed-off-by: dependabot[bot] Co-authored-by: Matteo Muraca <56828990+muraca@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Juan Ignacio Rios <54085674+JuaniRios@users.noreply.github.com> Co-authored-by: Branislav Kontur Co-authored-by: Bastian Köcher --- cumulus/polkadot-parachain/Cargo.toml | 10 +- .../node/network/collator-protocol/Cargo.toml | 4 + .../src/collator_side/collation.rs | 9 +- .../src/collator_side/mod.rs | 85 ++++++++----- .../src/collator_side/tests/mod.rs | 15 +++ .../tests/prospective_parachains.rs | 113 ++++++++++++++++++ polkadot/node/service/Cargo.toml | 9 +- polkadot/node/subsystem-types/src/messages.rs | 12 +- prdoc/pr_3521.prdoc | 12 ++ 9 files changed, 222 insertions(+), 47 deletions(-) create mode 100644 prdoc/pr_3521.prdoc diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index 70423856d34..37b7be75ef9 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -42,7 +42,10 @@ jsonrpsee = { version = "0.22", features = ["server"] } people-rococo-runtime = { path = "../parachains/runtimes/people/people-rococo" } people-westend-runtime = { path = "../parachains/runtimes/people/people-westend" } parachains-common = { path = "../parachains/common" } -testnet-parachains-constants = { path = "../parachains/runtimes/constants", default-features = false, features = ["rococo", "westend"] } +testnet-parachains-constants = { path = "../parachains/runtimes/constants", default-features = false, features = [ + "rococo", + "westend", +] } # Substrate frame-benchmarking = { path = "../../substrate/frame/benchmarking" } @@ -168,6 +171,5 @@ try-runtime = [ "shell-runtime/try-runtime", "sp-runtime/try-runtime", ] -fast-runtime = [ - "bridge-hub-rococo-runtime/fast-runtime", -] +fast-runtime = ["bridge-hub-rococo-runtime/fast-runtime"] +elastic-scaling-experimental = ["polkadot-service/elastic-scaling-experimental"] diff --git a/polkadot/node/network/collator-protocol/Cargo.toml b/polkadot/node/network/collator-protocol/Cargo.toml index f0f8be0f7ba..cfd88df958c 100644 --- a/polkadot/node/network/collator-protocol/Cargo.toml +++ b/polkadot/node/network/collator-protocol/Cargo.toml @@ -41,3 +41,7 @@ parity-scale-codec = { version = "3.6.1", features = ["std"] } polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } + +[features] +default = [] +elastic-scaling-experimental = [] diff --git a/polkadot/node/network/collator-protocol/src/collator_side/collation.rs b/polkadot/node/network/collator-protocol/src/collator_side/collation.rs index dc1ee725462..57e1479a449 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/collation.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/collation.rs @@ -27,7 +27,8 @@ use polkadot_node_network_protocol::{ PeerId, }; use polkadot_node_primitives::PoV; -use polkadot_primitives::{CandidateHash, CandidateReceipt, Hash, HeadData, Id as ParaId}; +use polkadot_node_subsystem::messages::ParentHeadData; +use polkadot_primitives::{CandidateHash, CandidateReceipt, Hash, Id as ParaId}; /// The status of a collation as seen from the collator. pub enum CollationStatus { @@ -59,12 +60,10 @@ impl CollationStatus { pub struct Collation { /// Candidate receipt. pub receipt: CandidateReceipt, - /// Parent head-data hash. - pub parent_head_data_hash: Hash, /// Proof to verify the state transition of the parachain. pub pov: PoV, - /// Parent head-data needed for elastic scaling. - pub parent_head_data: HeadData, + /// Parent head-data (or just hash). + pub parent_head_data: ParentHeadData, /// Collation status. pub status: CollationStatus, } diff --git a/polkadot/node/network/collator-protocol/src/collator_side/mod.rs b/polkadot/node/network/collator-protocol/src/collator_side/mod.rs index 19cc1eb1a57..9f306f288a1 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/mod.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/mod.rs @@ -40,7 +40,8 @@ use polkadot_node_primitives::{CollationSecondedSignal, PoV, Statement}; use polkadot_node_subsystem::{ jaeger, messages::{ - CollatorProtocolMessage, NetworkBridgeEvent, NetworkBridgeTxMessage, RuntimeApiMessage, + CollatorProtocolMessage, NetworkBridgeEvent, NetworkBridgeTxMessage, ParentHeadData, + RuntimeApiMessage, }, overseer, CollatorProtocolSenderTrait, FromOrchestra, OverseerSignal, PerLeafSpan, }; @@ -395,12 +396,11 @@ async fn distribute_collation( return Ok(()) } - // Determine which core the para collated-on is assigned to. + // Determine which core(s) the para collated-on is assigned to. // If it is not scheduled then ignore the message. - let (our_core, num_cores) = - match determine_core(ctx.sender(), id, candidate_relay_parent, relay_parent_mode).await? { - Some(core) => core, - None => { + let (our_cores, num_cores) = + match determine_cores(ctx.sender(), id, candidate_relay_parent, relay_parent_mode).await? { + (cores, _num_cores) if cores.is_empty() => { gum::warn!( target: LOG_TARGET, para_id = %id, @@ -409,8 +409,20 @@ async fn distribute_collation( return Ok(()) }, + (cores, num_cores) => (cores, num_cores), }; + let elastic_scaling = our_cores.len() > 1; + if elastic_scaling { + gum::debug!( + target: LOG_TARGET, + para_id = %id, + cores = ?our_cores, + "{} is assigned to {} cores at {}", id, our_cores.len(), candidate_relay_parent, + ); + } + + let our_core = our_cores[0]; // Determine the group on that core. // // When prospective parachains are disabled, candidate relay parent here is @@ -464,15 +476,15 @@ async fn distribute_collation( state.collation_result_senders.insert(candidate_hash, result_sender); } + let parent_head_data = if elastic_scaling { + ParentHeadData::WithData { hash: parent_head_data_hash, head_data: parent_head_data } + } else { + ParentHeadData::OnlyHash(parent_head_data_hash) + }; + per_relay_parent.collations.insert( candidate_hash, - Collation { - receipt, - parent_head_data_hash, - pov, - parent_head_data, - status: CollationStatus::Created, - }, + Collation { receipt, pov, parent_head_data, status: CollationStatus::Created }, ); // If prospective parachains are disabled, a leaf should be known to peer. @@ -513,15 +525,17 @@ async fn distribute_collation( Ok(()) } -/// Get the Id of the Core that is assigned to the para being collated on if any +/// Get the core indices that are assigned to the para being collated on if any /// and the total number of cores. -async fn determine_core( +async fn determine_cores( sender: &mut impl overseer::SubsystemSender, para_id: ParaId, relay_parent: Hash, relay_parent_mode: ProspectiveParachainsMode, -) -> Result> { +) -> Result<(Vec, usize)> { let cores = get_availability_cores(sender, relay_parent).await?; + let n_cores = cores.len(); + let mut assigned_cores = Vec::new(); for (idx, core) in cores.iter().enumerate() { let core_para_id = match core { @@ -538,11 +552,11 @@ async fn determine_core( }; if core_para_id == Some(para_id) { - return Ok(Some(((idx as u32).into(), cores.len()))) + assigned_cores.push(CoreIndex::from(idx as u32)); } } - Ok(None) + Ok((assigned_cores, n_cores)) } /// Validators of a particular group index. @@ -725,7 +739,7 @@ async fn advertise_collation( let wire_message = protocol_v2::CollatorProtocolMessage::AdvertiseCollation { relay_parent, candidate_hash: *candidate_hash, - parent_head_data_hash: collation.parent_head_data_hash, + parent_head_data_hash: collation.parent_head_data.hash(), }; Versioned::V2(protocol_v2::CollationProtocol::CollatorProtocol(wire_message)) }, @@ -849,7 +863,7 @@ async fn send_collation( request: VersionedCollationRequest, receipt: CandidateReceipt, pov: PoV, - _parent_head_data: HeadData, + parent_head_data: ParentHeadData, ) { let (tx, rx) = oneshot::channel(); @@ -857,20 +871,25 @@ async fn send_collation( let peer_id = request.peer_id(); let candidate_hash = receipt.hash(); - // The response payload is the same for v1 and v2 versions of protocol - // and doesn't have v2 alias for simplicity. - // For now, we don't send parent head data to the collation requester. - let result = - // if assigned_multiple_cores { - // Ok(request_v1::CollationFetchingResponse::CollationWithParentHeadData { - // receipt, - // pov, - // parent_head_data, - // }) - // } else { + #[cfg(feature = "elastic-scaling-experimental")] + let result = match parent_head_data { + ParentHeadData::WithData { head_data, .. } => + Ok(request_v2::CollationFetchingResponse::CollationWithParentHeadData { + receipt, + pov, + parent_head_data: head_data, + }), + ParentHeadData::OnlyHash(_) => + Ok(request_v1::CollationFetchingResponse::Collation(receipt, pov)), + }; + #[cfg(not(feature = "elastic-scaling-experimental"))] + let result = { + // suppress unused warning + let _parent_head_data = parent_head_data; + Ok(request_v1::CollationFetchingResponse::Collation(receipt, pov)) - // } - ; + }; + let response = OutgoingResponse { result, reputation_changes: Vec::new(), sent_feedback: Some(tx) }; diff --git a/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs b/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs index beda941d37a..38e6780eb7d 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs @@ -142,6 +142,21 @@ impl Default for TestState { } impl TestState { + /// Adds a few more scheduled cores to the state for the same para id + /// compared to the default. + #[cfg(feature = "elastic-scaling-experimental")] + pub fn with_elastic_scaling() -> Self { + let mut state = Self::default(); + let para_id = state.para_id; + state + .availability_cores + .push(CoreState::Scheduled(ScheduledCore { para_id, collator: None })); + state + .availability_cores + .push(CoreState::Scheduled(ScheduledCore { para_id, collator: None })); + state + } + fn current_group_validator_indices(&self) -> &[ValidatorIndex] { let core_num = self.availability_cores.len(); let GroupIndex(group_idx) = self.group_rotation_info.group_for_core(CoreIndex(0), core_num); diff --git a/polkadot/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs b/polkadot/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs index 2bb7002a4f4..e419cd5444f 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs @@ -372,6 +372,119 @@ fn distribute_collation_up_to_limit() { ) } +/// Tests that collator send the parent head data in +/// case the para is assigned to multiple cores (elastic scaling). +#[test] +#[cfg(feature = "elastic-scaling-experimental")] +fn send_parent_head_data_for_elastic_scaling() { + let test_state = TestState::with_elastic_scaling(); + + let local_peer_id = test_state.local_peer_id; + let collator_pair = test_state.collator_pair.clone(); + + test_harness( + local_peer_id, + collator_pair, + ReputationAggregator::new(|_| true), + |test_harness| async move { + let mut virtual_overseer = test_harness.virtual_overseer; + let req_v1_cfg = test_harness.req_v1_cfg; + let mut req_v2_cfg = test_harness.req_v2_cfg; + + let head_b = Hash::from_low_u64_be(129); + let head_b_num: u32 = 63; + + // Set collating para id. + overseer_send( + &mut virtual_overseer, + CollatorProtocolMessage::CollateOn(test_state.para_id), + ) + .await; + update_view(&mut virtual_overseer, &test_state, vec![(head_b, head_b_num)], 1).await; + + let pov_data = PoV { block_data: BlockData(vec![1 as u8]) }; + let candidate = TestCandidateBuilder { + para_id: test_state.para_id, + relay_parent: head_b, + pov_hash: pov_data.hash(), + ..Default::default() + } + .build(); + + let phd = HeadData(vec![1, 2, 3]); + let phdh = phd.hash(); + + distribute_collation_with_receipt( + &mut virtual_overseer, + &test_state, + head_b, + true, + candidate.clone(), + pov_data.clone(), + phdh, + ) + .await; + + let peer = test_state.validator_peer_id[0]; + let validator_id = test_state.current_group_validator_authority_ids()[0].clone(); + connect_peer( + &mut virtual_overseer, + peer, + CollationVersion::V2, + Some(validator_id.clone()), + ) + .await; + expect_declare_msg_v2(&mut virtual_overseer, &test_state, &peer).await; + + send_peer_view_change(&mut virtual_overseer, &peer, vec![head_b]).await; + let hashes: Vec<_> = vec![candidate.hash()]; + expect_advertise_collation_msg(&mut virtual_overseer, &peer, head_b, Some(hashes)) + .await; + + let (pending_response, rx) = oneshot::channel(); + req_v2_cfg + .inbound_queue + .as_mut() + .unwrap() + .send(RawIncomingRequest { + peer, + payload: request_v2::CollationFetchingRequest { + relay_parent: head_b, + para_id: test_state.para_id, + candidate_hash: candidate.hash(), + } + .encode(), + pending_response, + }) + .await + .unwrap(); + + assert_matches!( + rx.await, + Ok(full_response) => { + let response: request_v2::CollationFetchingResponse = + request_v2::CollationFetchingResponse::decode(&mut + full_response.result + .expect("We should have a proper answer").as_ref() + ).expect("Decoding should work"); + assert_matches!( + response, + request_v1::CollationFetchingResponse::CollationWithParentHeadData { + receipt, pov, parent_head_data + } => { + assert_eq!(receipt, candidate); + assert_eq!(pov, pov_data); + assert_eq!(parent_head_data, phd); + } + ); + } + ); + + TestHarness { virtual_overseer, req_v1_cfg, req_v2_cfg } + }, + ) +} + /// Tests that collator correctly handles peer V2 requests. #[test] fn advertise_and_send_collation_by_hash() { diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 734dcbdeb44..e2bccfa5510 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -218,10 +218,7 @@ try-runtime = [ "sp-runtime/try-runtime", "westend-runtime?/try-runtime", ] -fast-runtime = [ - "rococo-runtime?/fast-runtime", - "westend-runtime?/fast-runtime", -] +fast-runtime = ["rococo-runtime?/fast-runtime", "westend-runtime?/fast-runtime"] malus = ["full-node"] runtime-metrics = [ @@ -229,3 +226,7 @@ runtime-metrics = [ "rococo-runtime?/runtime-metrics", "westend-runtime?/runtime-metrics", ] + +elastic-scaling-experimental = [ + "polkadot-collator-protocol?/elastic-scaling-experimental", +] diff --git a/polkadot/node/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index eeb684149c8..23773f7e325 100644 --- a/polkadot/node/subsystem-types/src/messages.rs +++ b/polkadot/node/subsystem-types/src/messages.rs @@ -1114,7 +1114,7 @@ pub struct ProspectiveValidationDataRequest { } /// The parent head-data hash with optional data itself. -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum ParentHeadData { /// Parent head-data hash. OnlyHash(Hash), @@ -1127,6 +1127,16 @@ pub enum ParentHeadData { }, } +impl ParentHeadData { + /// Return the hash of the parent head-data. + pub fn hash(&self) -> Hash { + match self { + ParentHeadData::OnlyHash(hash) => *hash, + ParentHeadData::WithData { hash, .. } => *hash, + } + } +} + /// Indicates the relay-parents whose fragment tree a candidate /// is present in and the depths of that tree the candidate is present in. pub type FragmentTreeMembership = Vec<(Hash, Vec)>; diff --git a/prdoc/pr_3521.prdoc b/prdoc/pr_3521.prdoc new file mode 100644 index 00000000000..4ad3f03bf0c --- /dev/null +++ b/prdoc/pr_3521.prdoc @@ -0,0 +1,12 @@ +title: Collator side changes for elastic scaling + +doc: + - audience: Node Dev + description: | + Parachain teams wishing to utilize the benefits of + elastic scaling will need to upgrade their collator + code to include these changes. + +crates: +- name: polkadot-collator-protocol + bump: minor -- GitLab From 1e9fd237768a404e40f1332b217f638dd7e3d917 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Tue, 19 Mar 2024 16:47:42 +0100 Subject: [PATCH 063/187] Implement crypto byte array newtypes in term of a shared type (#3684) Introduces `CryptoBytes` type defined as: ```rust pub struct CryptoBytes(pub [u8; N], PhantomData Tag>); ``` The type implements a bunch of methods and traits which are typically expected from a byte array newtype (NOTE: some of the methods and trait implementations IMO are a bit redundant, but I decided to maintain them all to not change too much stuff in this PR) It also introduces two (generic) typical consumers of `CryptoBytes`: `PublicBytes` and `SignatureBytes`. ```rust pub struct PublicTag; pub PublicBytes = CryptoBytes; pub struct SignatureTag; pub SignatureBytes = CryptoBytes; ``` Both of them use a tag to differentiate the two types at a higher level. Downstream specializations will further specialize using a dedicated crypto tag. For example in ECDSA: ```rust pub struct EcdsaTag; pub type Public = PublicBytes; pub type Signature = PublicBytes; ``` Overall we have a cleaner and most importantly **consistent** code for all the types involved All these details are opaque to the end user which can use `Public` and `Signature` for the cryptos as before --- cumulus/client/network/src/tests.rs | 6 +- .../bridge-hub-rococo/tests/snowbridge.rs | 7 +- .../bridge-hub-rococo/tests/tests.rs | 7 +- .../bridge-hub-westend/tests/tests.rs | 7 +- polkadot/node/service/src/benchmarking.rs | 4 +- polkadot/node/test/service/src/lib.rs | 2 +- polkadot/primitives/src/v6/mod.rs | 4 +- polkadot/primitives/test-helpers/src/lib.rs | 6 +- polkadot/runtime/common/src/purchase.rs | 4 +- polkadot/runtime/parachains/src/builder.rs | 2 +- .../client/authority-discovery/src/tests.rs | 2 +- .../client/executor/runtime-test/src/lib.rs | 4 +- .../client/service/test/src/client/mod.rs | 4 +- substrate/frame/contracts/src/exec.rs | 6 +- substrate/frame/sassafras/src/benchmarking.rs | 8 +- ...age_ensure_span_are_ok_on_wrong_gen.stderr | 12 +- ...re_span_are_ok_on_wrong_gen_unnamed.stderr | 12 +- substrate/primitives/core/src/bandersnatch.rs | 119 ++------ substrate/primitives/core/src/bls.rs | 214 +------------- substrate/primitives/core/src/crypto.rs | 5 +- substrate/primitives/core/src/crypto_bytes.rs | 244 ++++++++++++++++ substrate/primitives/core/src/ecdsa.rs | 184 ++---------- substrate/primitives/core/src/ed25519.rs | 255 ++--------------- substrate/primitives/core/src/lib.rs | 1 + .../primitives/core/src/paired_crypto.rs | 267 ++++++------------ substrate/primitives/core/src/sr25519.rs | 249 ++-------------- substrate/primitives/keystore/src/testing.rs | 2 +- substrate/primitives/runtime/src/traits.rs | 2 +- .../primitives/statement-store/src/lib.rs | 12 +- 29 files changed, 490 insertions(+), 1161 deletions(-) create mode 100644 substrate/primitives/core/src/crypto_bytes.rs diff --git a/cumulus/client/network/src/tests.rs b/cumulus/client/network/src/tests.rs index d986635f961..3f5757d5eac 100644 --- a/cumulus/client/network/src/tests.rs +++ b/cumulus/client/network/src/tests.rs @@ -144,7 +144,7 @@ impl RelayChainInterface for DummyRelayChainInterface { persisted_validation_data_hash: PHash::random(), pov_hash: PHash::random(), erasure_root: PHash::random(), - signature: sp_core::sr25519::Signature([0u8; 64]).into(), + signature: sp_core::sr25519::Signature::default().into(), validation_code_hash: ValidationCodeHash::from(PHash::random()), }, commitments: CandidateCommitments { @@ -325,7 +325,7 @@ async fn make_gossip_message_and_header( persisted_validation_data_hash: PHash::random(), pov_hash: PHash::random(), erasure_root: PHash::random(), - signature: sp_core::sr25519::Signature([0u8; 64]).into(), + signature: sp_core::sr25519::Signature::default().into(), para_head: polkadot_parachain_primitives::primitives::HeadData(header.encode()).hash(), validation_code_hash: ValidationCodeHash::from(PHash::random()), }, @@ -516,7 +516,7 @@ async fn check_statement_seconded() { persisted_validation_data_hash: PHash::random(), pov_hash: PHash::random(), erasure_root: PHash::random(), - signature: sp_core::sr25519::Signature([0u8; 64]).into(), + signature: sp_core::sr25519::Signature::default().into(), validation_code_hash: ValidationCodeHash::from(PHash::random()), }, }, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs index 239bd946e75..101b8d86d55 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs @@ -190,12 +190,7 @@ fn construct_extrinsic( ); let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); let signature = payload.using_encoded(|e| sender.sign(e)); - UncheckedExtrinsic::new_signed( - call, - account_id.into(), - Signature::Sr25519(signature.clone()), - extra, - ) + UncheckedExtrinsic::new_signed(call, account_id.into(), Signature::Sr25519(signature), extra) } fn construct_and_apply_extrinsic( diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs index f11954cf165..fad357b0951 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -67,12 +67,7 @@ fn construct_extrinsic( ); let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); let signature = payload.using_encoded(|e| sender.sign(e)); - UncheckedExtrinsic::new_signed( - call, - account_id.into(), - Signature::Sr25519(signature.clone()), - extra, - ) + UncheckedExtrinsic::new_signed(call, account_id.into(), Signature::Sr25519(signature), extra) } fn construct_and_apply_extrinsic( diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs index 149a3bbeb75..235b7f146c8 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs @@ -81,12 +81,7 @@ fn construct_extrinsic( ); let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); let signature = payload.using_encoded(|e| sender.sign(e)); - UncheckedExtrinsic::new_signed( - call, - account_id.into(), - Signature::Sr25519(signature.clone()), - extra, - ) + UncheckedExtrinsic::new_signed(call, account_id.into(), Signature::Sr25519(signature), extra) } fn construct_and_apply_extrinsic( diff --git a/polkadot/node/service/src/benchmarking.rs b/polkadot/node/service/src/benchmarking.rs index 400daf1aee3..a0c4d3b0446 100644 --- a/polkadot/node/service/src/benchmarking.rs +++ b/polkadot/node/service/src/benchmarking.rs @@ -222,7 +222,7 @@ fn westend_sign_call( runtime::UncheckedExtrinsic::new_signed( call, sp_runtime::AccountId32::from(acc.public()).into(), - polkadot_core_primitives::Signature::Sr25519(signature.clone()), + polkadot_core_primitives::Signature::Sr25519(signature), extra, ) .into() @@ -274,7 +274,7 @@ fn rococo_sign_call( runtime::UncheckedExtrinsic::new_signed( call, sp_runtime::AccountId32::from(acc.public()).into(), - polkadot_core_primitives::Signature::Sr25519(signature.clone()), + polkadot_core_primitives::Signature::Sr25519(signature), extra, ) .into() diff --git a/polkadot/node/test/service/src/lib.rs b/polkadot/node/test/service/src/lib.rs index ca904bae28d..eed11e62c21 100644 --- a/polkadot/node/test/service/src/lib.rs +++ b/polkadot/node/test/service/src/lib.rs @@ -410,7 +410,7 @@ pub fn construct_extrinsic( UncheckedExtrinsic::new_signed( function.clone(), polkadot_test_runtime::Address::Id(caller.public().into()), - polkadot_primitives::Signature::Sr25519(signature.clone()), + polkadot_primitives::Signature::Sr25519(signature), extra.clone(), ) } diff --git a/polkadot/primitives/src/v6/mod.rs b/polkadot/primitives/src/v6/mod.rs index cab34deeb50..742dbed1cd8 100644 --- a/polkadot/primitives/src/v6/mod.rs +++ b/polkadot/primitives/src/v6/mod.rs @@ -1953,11 +1953,11 @@ mod tests { descriptor: CandidateDescriptor { para_id: 0.into(), relay_parent: zeros, - collator: CollatorId::from(sr25519::Public::from_raw([0; 32])), + collator: CollatorId::from(sr25519::Public::default()), persisted_validation_data_hash: zeros, pov_hash: zeros, erasure_root: zeros, - signature: CollatorSignature::from(sr25519::Signature([0u8; 64])), + signature: CollatorSignature::from(sr25519::Signature::default()), para_head: zeros, validation_code_hash: ValidationCode(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]).hash(), }, diff --git a/polkadot/primitives/test-helpers/src/lib.rs b/polkadot/primitives/test-helpers/src/lib.rs index c0118f5960a..b7c5d82341a 100644 --- a/polkadot/primitives/test-helpers/src/lib.rs +++ b/polkadot/primitives/test-helpers/src/lib.rs @@ -136,17 +136,17 @@ pub fn dummy_head_data() -> HeadData { /// Create a meaningless collator id. pub fn dummy_collator() -> CollatorId { - CollatorId::from(sr25519::Public::from_raw([0; 32])) + CollatorId::from(sr25519::Public::default()) } /// Create a meaningless validator id. pub fn dummy_validator() -> ValidatorId { - ValidatorId::from(sr25519::Public::from_raw([0; 32])) + ValidatorId::from(sr25519::Public::default()) } /// Create a meaningless collator signature. pub fn dummy_collator_signature() -> CollatorSignature { - CollatorSignature::from(sr25519::Signature([0u8; 64])) + CollatorSignature::from(sr25519::Signature::default()) } /// Create a meaningless persisted validation data. diff --git a/polkadot/runtime/common/src/purchase.rs b/polkadot/runtime/common/src/purchase.rs index 8de93bd68b0..b90bbb3a7cf 100644 --- a/polkadot/runtime/common/src/purchase.rs +++ b/polkadot/runtime/common/src/purchase.rs @@ -425,8 +425,8 @@ pub mod pallet { impl Pallet { fn verify_signature(who: &T::AccountId, signature: &[u8]) -> Result<(), DispatchError> { // sr25519 always expects a 64 byte signature. - let signature: AnySignature = sr25519::Signature::from_slice(signature) - .ok_or(Error::::InvalidSignature)? + let signature: AnySignature = sr25519::Signature::try_from(signature) + .map_err(|_| Error::::InvalidSignature)? .into(); // In Polkadot, the AccountId is always the same as the 32 byte public key. diff --git a/polkadot/runtime/parachains/src/builder.rs b/polkadot/runtime/parachains/src/builder.rs index 23ec80e66fc..05f6845f3b7 100644 --- a/polkadot/runtime/parachains/src/builder.rs +++ b/polkadot/runtime/parachains/src/builder.rs @@ -272,7 +272,7 @@ impl BenchBuilder { persisted_validation_data_hash: Default::default(), pov_hash: Default::default(), erasure_root: Default::default(), - signature: CollatorSignature::from(sr25519::Signature([42u8; 64])), + signature: CollatorSignature::from(sr25519::Signature::from_raw([42u8; 64])), para_head: Default::default(), validation_code_hash: mock_validation_code().hash(), } diff --git a/substrate/client/authority-discovery/src/tests.rs b/substrate/client/authority-discovery/src/tests.rs index 4fbc196c5ec..edd50d073c8 100644 --- a/substrate/client/authority-discovery/src/tests.rs +++ b/substrate/client/authority-discovery/src/tests.rs @@ -100,7 +100,7 @@ fn cryptos_are_compatible() { let sp_core_signature = sp_core_secret.sign(message); // no error expected... assert!(sp_core::ed25519::Pair::verify( - &sp_core::ed25519::Signature::from_slice(&libp2p_signature).unwrap(), + &sp_core::ed25519::Signature::try_from(libp2p_signature.as_slice()).unwrap(), message, &sp_core_public )); diff --git a/substrate/client/executor/runtime-test/src/lib.rs b/substrate/client/executor/runtime-test/src/lib.rs index ec9b2378d4d..40683fbb664 100644 --- a/substrate/client/executor/runtime-test/src/lib.rs +++ b/substrate/client/executor/runtime-test/src/lib.rs @@ -181,7 +181,7 @@ sp_core::wasm_export_functions! { sig.copy_from_slice(&input[32..96]); let msg = b"all ok!"; - ed25519_verify(&ed25519::Signature(sig), &msg[..], &ed25519::Public(pubkey)) + ed25519_verify(&ed25519::Signature::from(sig), &msg[..], &ed25519::Public::from(pubkey)) } fn test_sr25519_verify(input: Vec) -> bool { @@ -192,7 +192,7 @@ sp_core::wasm_export_functions! { sig.copy_from_slice(&input[32..96]); let msg = b"all ok!"; - sr25519_verify(&sr25519::Signature(sig), &msg[..], &sr25519::Public(pubkey)) + sr25519_verify(&sr25519::Signature::from(sig), &msg[..], &sr25519::Public::from(pubkey)) } fn test_ordered_trie_root() -> Vec { diff --git a/substrate/client/service/test/src/client/mod.rs b/substrate/client/service/test/src/client/mod.rs index ba83bec8276..51dcc4966e5 100644 --- a/substrate/client/service/test/src/client/mod.rs +++ b/substrate/client/service/test/src/client/mod.rs @@ -2226,11 +2226,11 @@ fn reorg_triggers_a_notification_even_for_sources_that_should_not_trigger_notifi #[test] fn use_dalek_ext_works() { fn zero_ed_pub() -> sp_core::ed25519::Public { - sp_core::ed25519::Public([0u8; 32]) + sp_core::ed25519::Public::default() } fn zero_ed_sig() -> sp_core::ed25519::Signature { - sp_core::ed25519::Signature::from_raw([0u8; 64]) + sp_core::ed25519::Signature::default() } let mut client = TestClientBuilder::new().build(); diff --git a/substrate/frame/contracts/src/exec.rs b/substrate/frame/contracts/src/exec.rs index 7da321af547..d24657b65b2 100644 --- a/substrate/frame/contracts/src/exec.rs +++ b/substrate/frame/contracts/src/exec.rs @@ -1466,14 +1466,14 @@ where fn sr25519_verify(&self, signature: &[u8; 64], message: &[u8], pub_key: &[u8; 32]) -> bool { sp_io::crypto::sr25519_verify( - &SR25519Signature(*signature), + &SR25519Signature::from(*signature), message, - &SR25519Public(*pub_key), + &SR25519Public::from(*pub_key), ) } fn ecdsa_to_eth_address(&self, pk: &[u8; 33]) -> Result<[u8; 20], ()> { - ECDSAPublic(*pk).to_eth_address() + ECDSAPublic::from(*pk).to_eth_address() } #[cfg(test)] diff --git a/substrate/frame/sassafras/src/benchmarking.rs b/substrate/frame/sassafras/src/benchmarking.rs index 921f2f0793d..1c9626ad260 100644 --- a/substrate/frame/sassafras/src/benchmarking.rs +++ b/substrate/frame/sassafras/src/benchmarking.rs @@ -139,8 +139,8 @@ mod benchmarks { TicketsIds::::insert((epoch_tag as u8, i), id); let body = TicketBody { attempt_idx: i, - erased_public: EphemeralPublic([i as u8; 32]), - revealed_public: EphemeralPublic([i as u8; 32]), + erased_public: EphemeralPublic::from([i as u8; 32]), + revealed_public: EphemeralPublic::from([i as u8; 32]), }; TicketsData::::set(id, Some(body)); }); @@ -236,8 +236,8 @@ mod benchmarks { .map(|i| { let body = TicketBody { attempt_idx: i, - erased_public: EphemeralPublic([i as u8; 32]), - revealed_public: EphemeralPublic([i as u8; 32]), + erased_public: EphemeralPublic::from([i as u8; 32]), + revealed_public: EphemeralPublic::from([i as u8; 32]), }; let id_bytes = crate::hashing::blake2_128(&i.to_le_bytes()); let id = TicketId::from_le_bytes(id_bytes); diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr index 4229d1e8a54..d269e6d2726 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr @@ -13,8 +13,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | = help: the following other types implement trait `WrapperTypeDecode`: Box - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc Arc = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` @@ -65,8 +65,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied bytes::bytes::Bytes Cow<'a, T> parity_scale_codec::Ref<'a, T, U> - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc Arc Vec and $N others @@ -106,8 +106,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | = help: the following other types implement trait `WrapperTypeDecode`: Box - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc Arc = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` @@ -148,8 +148,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied bytes::bytes::Bytes Cow<'a, T> parity_scale_codec::Ref<'a, T, U> - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc Arc Vec and $N others @@ -168,8 +168,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | = help: the following other types implement trait `WrapperTypeDecode`: Box - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc Arc = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` @@ -210,8 +210,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied bytes::bytes::Bytes Cow<'a, T> parity_scale_codec::Ref<'a, T, U> - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc Arc Vec and $N others diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr index 855d289d0a1..13d761d65d2 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr @@ -13,8 +13,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | = help: the following other types implement trait `WrapperTypeDecode`: Box - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc Arc = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` @@ -65,8 +65,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied bytes::bytes::Bytes Cow<'a, T> parity_scale_codec::Ref<'a, T, U> - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc Arc Vec and $N others @@ -106,8 +106,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | = help: the following other types implement trait `WrapperTypeDecode`: Box - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc Arc = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` @@ -148,8 +148,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied bytes::bytes::Bytes Cow<'a, T> parity_scale_codec::Ref<'a, T, U> - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc Arc Vec and $N others @@ -168,8 +168,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | = help: the following other types implement trait `WrapperTypeDecode`: Box - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc Arc = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` @@ -210,8 +210,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied bytes::bytes::Bytes Cow<'a, T> parity_scale_codec::Ref<'a, T, U> - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc Arc Vec and $N others diff --git a/substrate/primitives/core/src/bandersnatch.rs b/substrate/primitives/core/src/bandersnatch.rs index 5cae6047f16..c9d5f27b47b 100644 --- a/substrate/primitives/core/src/bandersnatch.rs +++ b/substrate/primitives/core/src/bandersnatch.rs @@ -26,7 +26,8 @@ use crate::crypto::Ss58Codec; use crate::crypto::VrfSecret; use crate::crypto::{ ByteArray, CryptoType, CryptoTypeId, Derive, DeriveError, DeriveJunction, Pair as TraitPair, - Public as TraitPublic, SecretStringError, UncheckedFrom, VrfPublic, + Public as TraitPublic, PublicBytes, SecretStringError, SignatureBytes, UncheckedFrom, + VrfPublic, }; #[cfg(feature = "serde")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; @@ -37,7 +38,6 @@ use bandersnatch_vrfs::{CanonicalSerialize, SecretKey}; use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; use scale_info::TypeInfo; -use sp_runtime_interface::pass_by::PassByInner; use sp_std::{vec, vec::Vec}; /// Identifier used to match public keys against bandersnatch-vrf keys. @@ -46,69 +46,23 @@ pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"band"); /// Context used to produce a plain signature without any VRF input/output. pub const SIGNING_CTX: &[u8] = b"BandersnatchSigningContext"; -const SEED_SERIALIZED_SIZE: usize = 32; +/// The byte length of secret key seed. +pub const SEED_SERIALIZED_SIZE: usize = 32; -const PUBLIC_SERIALIZED_SIZE: usize = 33; -const SIGNATURE_SERIALIZED_SIZE: usize = 65; -const PREOUT_SERIALIZED_SIZE: usize = 33; +/// The byte length of serialized public key. +pub const PUBLIC_SERIALIZED_SIZE: usize = 33; -/// Bandersnatch public key. -#[derive( - Clone, - Copy, - PartialEq, - Eq, - PartialOrd, - Ord, - Encode, - Decode, - PassByInner, - MaxEncodedLen, - TypeInfo, - Hash, -)] -pub struct Public(pub [u8; PUBLIC_SERIALIZED_SIZE]); - -impl UncheckedFrom<[u8; PUBLIC_SERIALIZED_SIZE]> for Public { - fn unchecked_from(raw: [u8; PUBLIC_SERIALIZED_SIZE]) -> Self { - Public(raw) - } -} +/// The byte length of serialized signature. +pub const SIGNATURE_SERIALIZED_SIZE: usize = 65; -impl AsRef<[u8; PUBLIC_SERIALIZED_SIZE]> for Public { - fn as_ref(&self) -> &[u8; PUBLIC_SERIALIZED_SIZE] { - &self.0 - } -} +/// The byte length of serialized pre-output. +pub const PREOUT_SERIALIZED_SIZE: usize = 33; -impl AsRef<[u8]> for Public { - fn as_ref(&self) -> &[u8] { - &self.0[..] - } -} +#[doc(hidden)] +pub struct BandersnatchTag; -impl AsMut<[u8]> for Public { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.0[..] - } -} - -impl TryFrom<&[u8]> for Public { - type Error = (); - - fn try_from(data: &[u8]) -> Result { - if data.len() != PUBLIC_SERIALIZED_SIZE { - return Err(()) - } - let mut r = [0u8; PUBLIC_SERIALIZED_SIZE]; - r.copy_from_slice(data); - Ok(Self::unchecked_from(r)) - } -} - -impl ByteArray for Public { - const LEN: usize = PUBLIC_SERIALIZED_SIZE; -} +/// Bandersnatch public key. +pub type Public = PublicBytes; impl TraitPublic for Public {} @@ -150,45 +104,7 @@ impl<'de> Deserialize<'de> for Public { /// /// The signature is created via the [`VrfSecret::vrf_sign`] using [`SIGNING_CTX`] as transcript /// `label`. -#[derive( - Clone, Copy, PartialEq, Eq, Encode, Decode, PassByInner, MaxEncodedLen, TypeInfo, Hash, -)] -pub struct Signature([u8; SIGNATURE_SERIALIZED_SIZE]); - -impl UncheckedFrom<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature { - fn unchecked_from(raw: [u8; SIGNATURE_SERIALIZED_SIZE]) -> Self { - Signature(raw) - } -} - -impl AsRef<[u8]> for Signature { - fn as_ref(&self) -> &[u8] { - &self.0[..] - } -} - -impl AsMut<[u8]> for Signature { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.0[..] - } -} - -impl TryFrom<&[u8]> for Signature { - type Error = (); - - fn try_from(data: &[u8]) -> Result { - if data.len() != SIGNATURE_SERIALIZED_SIZE { - return Err(()) - } - let mut r = [0u8; SIGNATURE_SERIALIZED_SIZE]; - r.copy_from_slice(data); - Ok(Self::unchecked_from(r)) - } -} - -impl ByteArray for Signature { - const LEN: usize = SIGNATURE_SERIALIZED_SIZE; -} +pub type Signature = SignatureBytes; impl CryptoType for Signature { type Pair = Pair; @@ -542,8 +458,7 @@ pub mod vrf { thin_signature.preouts.into_iter().map(VrfPreOutput).collect(); let pre_outputs = VrfIosVec::truncate_from(pre_outputs); - let mut signature = - VrfSignature { signature: Signature([0; SIGNATURE_SERIALIZED_SIZE]), pre_outputs }; + let mut signature = VrfSignature { signature: Signature::default(), pre_outputs }; thin_signature .proof @@ -582,7 +497,7 @@ pub mod vrf { // This is another hack used because backend signature type is generic over // the number of ios. let Ok(proof) = ThinVrfSignature::<0>::deserialize_compressed_unchecked( - signature.signature.as_ref(), + signature.signature.as_slice(), ) .map(|s| s.proof) else { return false diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index 2256e4cd823..9492a14ff0d 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -26,28 +26,21 @@ #[cfg(feature = "serde")] use crate::crypto::Ss58Codec; use crate::crypto::{ - ByteArray, CryptoType, Derive, DeriveError, DeriveJunction, Pair as TraitPair, - Public as TraitPublic, SecretStringError, UncheckedFrom, + CryptoType, Derive, DeriveError, DeriveJunction, Pair as TraitPair, Public as TraitPublic, + PublicBytes, SecretStringError, SignatureBytes, UncheckedFrom, }; -use sp_std::vec::Vec; - -use codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; - #[cfg(feature = "serde")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; #[cfg(all(not(feature = "std"), feature = "serde"))] use sp_std::alloc::{format, string::String}; +use sp_std::vec::Vec; use w3f_bls::{ DoublePublicKey, DoublePublicKeyScheme, DoubleSignature, EngineBLS, Keypair, Message, SecretKey, SerializableToBytes, TinyBLS381, }; -use sp_runtime_interface::pass_by::{self, PassBy, PassByInner}; -use sp_std::{convert::TryFrom, marker::PhantomData, ops::Deref}; - /// BLS-377 specialized types pub mod bls377 { pub use super::{PUBLIC_KEY_SERIALIZED_SIZE, SIGNATURE_SERIALIZED_SIZE}; @@ -57,6 +50,9 @@ pub mod bls377 { /// An identifier used to match public keys against BLS12-377 keys pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"bls7"); + #[doc(hidden)] + pub type Bls377Tag = TinyBLS377; + /// BLS12-377 key pair. pub type Pair = super::Pair; /// BLS12-377 public key. @@ -113,114 +109,11 @@ pub const SIGNATURE_SERIALIZED_SIZE: usize = /// will need it later (such as for HDKD). type Seed = [u8; SECRET_KEY_SERIALIZED_SIZE]; -/// A public key. -#[derive(Copy, Encode, Decode, MaxEncodedLen, TypeInfo)] -#[scale_info(skip_type_params(T))] -pub struct Public { - inner: [u8; PUBLIC_KEY_SERIALIZED_SIZE], - _phantom: PhantomData T>, -} - -impl Clone for Public { - fn clone(&self) -> Self { - Self { inner: self.inner, _phantom: PhantomData } - } -} - -impl PartialEq for Public { - fn eq(&self, other: &Self) -> bool { - self.inner == other.inner - } -} - -impl Eq for Public {} - -impl PartialOrd for Public { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Public { - fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering { - self.inner.cmp(&other.inner) - } -} - -impl sp_std::hash::Hash for Public { - fn hash(&self, state: &mut H) { - self.inner.hash(state) - } -} - -impl ByteArray for Public { - const LEN: usize = PUBLIC_KEY_SERIALIZED_SIZE; -} - -impl PassByInner for Public { - type Inner = [u8; PUBLIC_KEY_SERIALIZED_SIZE]; - - fn into_inner(self) -> Self::Inner { - self.inner - } - - fn inner(&self) -> &Self::Inner { - &self.inner - } - - fn from_inner(inner: Self::Inner) -> Self { - Self { inner, _phantom: PhantomData } - } -} - -impl PassBy for Public { - type PassBy = pass_by::Inner; -} - -impl AsRef<[u8; PUBLIC_KEY_SERIALIZED_SIZE]> for Public { - fn as_ref(&self) -> &[u8; PUBLIC_KEY_SERIALIZED_SIZE] { - &self.inner - } -} - -impl AsRef<[u8]> for Public { - fn as_ref(&self) -> &[u8] { - &self.inner[..] - } -} - -impl AsMut<[u8]> for Public { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.inner[..] - } -} - -impl Deref for Public { - type Target = [u8]; +#[doc(hidden)] +pub struct BlsTag; - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -impl TryFrom<&[u8]> for Public { - type Error = (); - - fn try_from(data: &[u8]) -> Result { - if data.len() != PUBLIC_KEY_SERIALIZED_SIZE { - return Err(()) - } - let mut r = [0u8; PUBLIC_KEY_SERIALIZED_SIZE]; - r.copy_from_slice(data); - Ok(Self::unchecked_from(r)) - } -} - -impl From> for [u8; PUBLIC_KEY_SERIALIZED_SIZE] { - fn from(x: Public) -> Self { - x.inner - } -} +/// A public key. +pub type Public = PublicBytes; impl From> for Public { fn from(x: Pair) -> Self { @@ -228,12 +121,6 @@ impl From> for Public { } } -impl UncheckedFrom<[u8; PUBLIC_KEY_SERIALIZED_SIZE]> for Public { - fn unchecked_from(data: [u8; PUBLIC_KEY_SERIALIZED_SIZE]) -> Self { - Public { inner: data, _phantom: PhantomData } - } -} - #[cfg(feature = "std")] impl std::str::FromStr for Public { type Err = crate::crypto::PublicError; @@ -254,7 +141,7 @@ impl std::fmt::Display for Public { impl sp_std::fmt::Debug for Public { fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { let s = self.to_ss58check(); - write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.inner), &s[0..8]) + write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8]) } } @@ -295,49 +182,7 @@ impl CryptoType for Public { } /// A generic BLS signature. -#[derive(Copy, Encode, Decode, MaxEncodedLen, TypeInfo)] -#[scale_info(skip_type_params(T))] -pub struct Signature { - inner: [u8; SIGNATURE_SERIALIZED_SIZE], - _phantom: PhantomData T>, -} - -impl Clone for Signature { - fn clone(&self) -> Self { - Self { inner: self.inner, _phantom: PhantomData } - } -} - -impl PartialEq for Signature { - fn eq(&self, other: &Self) -> bool { - self.inner == other.inner - } -} - -impl Eq for Signature {} - -impl sp_std::hash::Hash for Signature { - fn hash(&self, state: &mut H) { - self.inner.hash(state) - } -} - -impl ByteArray for Signature { - const LEN: usize = SIGNATURE_SERIALIZED_SIZE; -} - -impl TryFrom<&[u8]> for Signature { - type Error = (); - - fn try_from(data: &[u8]) -> Result { - if data.len() != SIGNATURE_SERIALIZED_SIZE { - return Err(()) - } - let mut inner = [0u8; SIGNATURE_SERIALIZED_SIZE]; - inner.copy_from_slice(data); - Ok(Signature::unchecked_from(inner)) - } -} +pub type Signature = SignatureBytes; #[cfg(feature = "serde")] impl Serialize for Signature { @@ -362,34 +207,10 @@ impl<'de, T> Deserialize<'de> for Signature { } } -impl From> for [u8; SIGNATURE_SERIALIZED_SIZE] { - fn from(signature: Signature) -> [u8; SIGNATURE_SERIALIZED_SIZE] { - signature.inner - } -} - -impl AsRef<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature { - fn as_ref(&self) -> &[u8; SIGNATURE_SERIALIZED_SIZE] { - &self.inner - } -} - -impl AsRef<[u8]> for Signature { - fn as_ref(&self) -> &[u8] { - &self.inner[..] - } -} - -impl AsMut<[u8]> for Signature { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.inner[..] - } -} - impl sp_std::fmt::Debug for Signature { #[cfg(feature = "std")] fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.inner)) + write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0)) } #[cfg(not(feature = "std"))] @@ -398,12 +219,6 @@ impl sp_std::fmt::Debug for Signature { } } -impl UncheckedFrom<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature { - fn unchecked_from(data: [u8; SIGNATURE_SERIALIZED_SIZE]) -> Self { - Signature { inner: data, _phantom: PhantomData } - } -} - impl CryptoType for Signature { type Pair = Pair; } @@ -423,6 +238,7 @@ trait HardJunctionId { /// Derive a single hard junction. fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed { + use codec::Encode; (T::ID, secret_seed, cc).using_encoded(sp_crypto_hashing::blake2_256) } @@ -489,7 +305,7 @@ impl TraitPair for Pair { Err(_) => return false, }; - let sig_array = match sig.inner[..].try_into() { + let sig_array = match sig.0[..].try_into() { Ok(s) => s, Err(_) => return false, }; diff --git a/substrate/primitives/core/src/crypto.rs b/substrate/primitives/core/src/crypto.rs index fab865d8c1f..a2bdc6ed58e 100644 --- a/substrate/primitives/core/src/crypto.rs +++ b/substrate/primitives/core/src/crypto.rs @@ -39,7 +39,10 @@ pub use ss58_registry::{from_known_address_format, Ss58AddressFormat, Ss58Addres /// Trait to zeroize a memory buffer. pub use zeroize::Zeroize; -pub use crate::address_uri::{AddressUri, Error as AddressUriError}; +pub use crate::{ + address_uri::{AddressUri, Error as AddressUriError}, + crypto_bytes::{CryptoBytes, PublicBytes, SignatureBytes}, +}; /// The root phrase for our publicly known keys. pub const DEV_PHRASE: &str = diff --git a/substrate/primitives/core/src/crypto_bytes.rs b/substrate/primitives/core/src/crypto_bytes.rs new file mode 100644 index 00000000000..069878e1654 --- /dev/null +++ b/substrate/primitives/core/src/crypto_bytes.rs @@ -0,0 +1,244 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Generic byte array which can be specialized with a marker type. + +use crate::{ + crypto::{FromEntropy, UncheckedFrom}, + hash::{H256, H512}, +}; + +use codec::{Decode, Encode, MaxEncodedLen}; +use core::marker::PhantomData; +use scale_info::TypeInfo; +use sp_runtime_interface::pass_by::{self, PassBy, PassByInner}; + +/// Generic byte array holding some crypto-related raw data. +/// +/// The type is generic over a constant length `N` and a "tag" `T` which +/// can be used to specialize the byte array without requiring newtypes. +/// +/// The tag `T` is held in a `PhantomDataT>`, a trick allowing +/// `CryptoBytes` to be `Send` and `Sync` regardless of `T` properties +/// ([ref](https://doc.rust-lang.org/nomicon/phantom-data.html#table-of-phantomdata-patterns)). +#[derive(Encode, Decode, MaxEncodedLen)] +#[repr(transparent)] +pub struct CryptoBytes(pub [u8; N], PhantomData T>); + +impl Copy for CryptoBytes {} + +impl Clone for CryptoBytes { + fn clone(&self) -> Self { + Self(self.0, PhantomData) + } +} + +impl TypeInfo for CryptoBytes { + type Identity = [u8; N]; + + fn type_info() -> scale_info::Type { + Self::Identity::type_info() + } +} + +impl PartialOrd for CryptoBytes { + fn partial_cmp(&self, other: &Self) -> Option { + self.0.partial_cmp(&other.0) + } +} + +impl Ord for CryptoBytes { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + self.0.cmp(&other.0) + } +} + +impl PartialEq for CryptoBytes { + fn eq(&self, other: &Self) -> bool { + self.0.eq(&other.0) + } +} + +impl core::hash::Hash for CryptoBytes { + fn hash(&self, state: &mut H) { + self.0.hash(state) + } +} + +impl Eq for CryptoBytes {} + +impl Default for CryptoBytes { + fn default() -> Self { + Self([0_u8; N], PhantomData) + } +} + +impl PassByInner for CryptoBytes { + type Inner = [u8; N]; + + fn into_inner(self) -> Self::Inner { + self.0 + } + + fn inner(&self) -> &Self::Inner { + &self.0 + } + + fn from_inner(inner: Self::Inner) -> Self { + Self(inner, PhantomData) + } +} + +impl PassBy for CryptoBytes { + type PassBy = pass_by::Inner; +} + +impl AsRef<[u8]> for CryptoBytes { + fn as_ref(&self) -> &[u8] { + &self.0[..] + } +} + +impl AsMut<[u8]> for CryptoBytes { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0[..] + } +} + +impl From> for [u8; N] { + fn from(v: CryptoBytes) -> [u8; N] { + v.0 + } +} + +impl AsRef<[u8; N]> for CryptoBytes { + fn as_ref(&self) -> &[u8; N] { + &self.0 + } +} + +impl AsMut<[u8; N]> for CryptoBytes { + fn as_mut(&mut self) -> &mut [u8; N] { + &mut self.0 + } +} + +impl From<[u8; N]> for CryptoBytes { + fn from(value: [u8; N]) -> Self { + Self::from_raw(value) + } +} + +impl TryFrom<&[u8]> for CryptoBytes { + type Error = (); + + fn try_from(data: &[u8]) -> Result { + if data.len() != N { + return Err(()) + } + let mut r = [0u8; N]; + r.copy_from_slice(data); + Ok(Self::from_raw(r)) + } +} + +impl UncheckedFrom<[u8; N]> for CryptoBytes { + fn unchecked_from(data: [u8; N]) -> Self { + Self::from_raw(data) + } +} + +impl core::ops::Deref for CryptoBytes { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl CryptoBytes { + /// Construct from raw array. + pub fn from_raw(inner: [u8; N]) -> Self { + Self(inner, PhantomData) + } + + /// Construct from raw array. + pub fn to_raw(self) -> [u8; N] { + self.0 + } + + /// Return a slice filled with raw data. + pub fn as_array_ref(&self) -> &[u8; N] { + &self.0 + } +} + +impl crate::ByteArray for CryptoBytes { + const LEN: usize = N; +} + +impl FromEntropy for CryptoBytes { + fn from_entropy(input: &mut impl codec::Input) -> Result { + let mut result = Self::default(); + input.read(result.as_mut())?; + Ok(result) + } +} + +impl From> for H256 { + fn from(x: CryptoBytes<32, T>) -> H256 { + H256::from(x.0) + } +} + +impl From> for H512 { + fn from(x: CryptoBytes<64, T>) -> H512 { + H512::from(x.0) + } +} + +impl UncheckedFrom for CryptoBytes<32, T> { + fn unchecked_from(x: H256) -> Self { + Self::from_h256(x) + } +} + +impl CryptoBytes<32, T> { + /// A new instance from an H256. + pub fn from_h256(x: H256) -> Self { + Self::from_raw(x.into()) + } +} + +impl CryptoBytes<64, T> { + /// A new instance from an H512. + pub fn from_h512(x: H512) -> Self { + Self::from_raw(x.into()) + } +} + +/// Tag used for generic public key bytes. +pub struct PublicTag; + +/// Generic encoded public key. +pub type PublicBytes = CryptoBytes; + +/// Tag used for generic signature bytes. +pub struct SignatureTag; + +/// Generic encoded signature. +pub type SignatureBytes = CryptoBytes; diff --git a/substrate/primitives/core/src/ecdsa.rs b/substrate/primitives/core/src/ecdsa.rs index fa071e1b03f..0e6b06a34dc 100644 --- a/substrate/primitives/core/src/ecdsa.rs +++ b/substrate/primitives/core/src/ecdsa.rs @@ -17,15 +17,11 @@ //! Simple ECDSA secp256k1 API. -use codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; -use sp_runtime_interface::pass_by::PassByInner; - #[cfg(feature = "serde")] use crate::crypto::Ss58Codec; use crate::crypto::{ - ByteArray, CryptoType, CryptoTypeId, Derive, DeriveError, DeriveJunction, Pair as TraitPair, - Public as TraitPublic, SecretStringError, UncheckedFrom, + CryptoType, CryptoTypeId, Derive, DeriveError, DeriveJunction, Pair as TraitPair, + Public as TraitPublic, PublicBytes, SecretStringError, SignatureBytes, }; #[cfg(not(feature = "std"))] @@ -51,45 +47,18 @@ pub const PUBLIC_KEY_SERIALIZED_SIZE: usize = 33; /// The byte length of signature pub const SIGNATURE_SERIALIZED_SIZE: usize = 65; +#[doc(hidden)] +pub struct EcdsaTag; + /// The secret seed. /// /// The raw secret seed, which can be used to create the `Pair`. type Seed = [u8; 32]; /// The ECDSA compressed public key. -#[derive( - Clone, - Copy, - Encode, - Decode, - PassByInner, - MaxEncodedLen, - TypeInfo, - Eq, - PartialEq, - PartialOrd, - Ord, - Hash, -)] -pub struct Public(pub [u8; PUBLIC_KEY_SERIALIZED_SIZE]); - -impl crate::crypto::FromEntropy for Public { - fn from_entropy(input: &mut impl codec::Input) -> Result { - let mut result = Self([0u8; PUBLIC_KEY_SERIALIZED_SIZE]); - input.read(&mut result.0[..])?; - Ok(result) - } -} +pub type Public = PublicBytes; impl Public { - /// A new instance from the given 33-byte `data`. - /// - /// NOTE: No checking goes on to ensure this is a real public key. Only use it if - /// you are certain that the array actually is a pubkey. GIGO! - pub fn from_raw(data: [u8; PUBLIC_KEY_SERIALIZED_SIZE]) -> Self { - Self(data) - } - /// Create a new instance from the given full public key. /// /// This will convert the full public key into the compressed format. @@ -111,54 +80,22 @@ impl Public { } } -impl ByteArray for Public { - const LEN: usize = PUBLIC_KEY_SERIALIZED_SIZE; -} - impl TraitPublic for Public {} impl Derive for Public {} -impl AsRef<[u8]> for Public { - fn as_ref(&self) -> &[u8] { - &self.0[..] - } -} - -impl AsMut<[u8]> for Public { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.0[..] - } -} - #[cfg(feature = "std")] impl From for Public { fn from(pubkey: PublicKey) -> Self { - Self(pubkey.serialize()) + Self::from(pubkey.serialize()) } } #[cfg(not(feature = "std"))] impl From for Public { fn from(pubkey: VerifyingKey) -> Self { - Self::unchecked_from( - pubkey.to_sec1_bytes()[..] - .try_into() - .expect("valid key is serializable to [u8,33]. qed."), - ) - } -} - -impl TryFrom<&[u8]> for Public { - type Error = (); - - fn try_from(data: &[u8]) -> Result { - if data.len() != Self::LEN { - return Err(()) - } - let mut r = [0u8; Self::LEN]; - r.copy_from_slice(data); - Ok(Self::unchecked_from(r)) + Self::try_from(&pubkey.to_sec1_bytes()[..]) + .expect("Valid key is serializable to [u8; 33]. qed.") } } @@ -169,12 +106,6 @@ impl From for Public { } } -impl UncheckedFrom<[u8; PUBLIC_KEY_SERIALIZED_SIZE]> for Public { - fn unchecked_from(x: [u8; PUBLIC_KEY_SERIALIZED_SIZE]) -> Self { - Public(x) - } -} - #[cfg(feature = "std")] impl std::fmt::Display for Public { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { @@ -217,26 +148,7 @@ impl<'de> Deserialize<'de> for Public { } /// A signature (a 512-bit value, plus 8 bits for recovery ID). -#[derive(Hash, Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)] -pub struct Signature(pub [u8; SIGNATURE_SERIALIZED_SIZE]); - -impl ByteArray for Signature { - const LEN: usize = SIGNATURE_SERIALIZED_SIZE; -} - -impl TryFrom<&[u8]> for Signature { - type Error = (); - - fn try_from(data: &[u8]) -> Result { - if data.len() == SIGNATURE_SERIALIZED_SIZE { - let mut inner = [0u8; SIGNATURE_SERIALIZED_SIZE]; - inner.copy_from_slice(data); - Ok(Signature(inner)) - } else { - Err(()) - } - } -} +pub type Signature = SignatureBytes; #[cfg(feature = "serde")] impl Serialize for Signature { @@ -261,44 +173,6 @@ impl<'de> Deserialize<'de> for Signature { } } -impl Clone for Signature { - fn clone(&self) -> Self { - let mut r = [0u8; SIGNATURE_SERIALIZED_SIZE]; - r.copy_from_slice(&self.0[..]); - Signature(r) - } -} - -impl Default for Signature { - fn default() -> Self { - Signature([0u8; SIGNATURE_SERIALIZED_SIZE]) - } -} - -impl From for [u8; SIGNATURE_SERIALIZED_SIZE] { - fn from(v: Signature) -> [u8; SIGNATURE_SERIALIZED_SIZE] { - v.0 - } -} - -impl AsRef<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature { - fn as_ref(&self) -> &[u8; SIGNATURE_SERIALIZED_SIZE] { - &self.0 - } -} - -impl AsRef<[u8]> for Signature { - fn as_ref(&self) -> &[u8] { - &self.0[..] - } -} - -impl AsMut<[u8]> for Signature { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.0[..] - } -} - impl sp_std::fmt::Debug for Signature { #[cfg(feature = "std")] fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { @@ -311,34 +185,7 @@ impl sp_std::fmt::Debug for Signature { } } -impl UncheckedFrom<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature { - fn unchecked_from(data: [u8; SIGNATURE_SERIALIZED_SIZE]) -> Signature { - Signature(data) - } -} - impl Signature { - /// A new instance from the given 65-byte `data`. - /// - /// NOTE: No checking goes on to ensure this is a real signature. Only use it if - /// you are certain that the array actually is a signature. GIGO! - pub fn from_raw(data: [u8; SIGNATURE_SERIALIZED_SIZE]) -> Signature { - Signature(data) - } - - /// A new instance from the given slice that should be 65 bytes long. - /// - /// NOTE: No checking goes on to ensure this is a real signature. Only use it if - /// you are certain that the array actually is a signature. GIGO! - pub fn from_slice(data: &[u8]) -> Option { - if data.len() != SIGNATURE_SERIALIZED_SIZE { - return None - } - let mut r = [0u8; SIGNATURE_SERIALIZED_SIZE]; - r.copy_from_slice(data); - Some(Signature(r)) - } - /// Recover the public key from this signature and a message. pub fn recover>(&self, message: M) -> Option { self.recover_prehashed(&sp_crypto_hashing::blake2_256(message.as_ref())) @@ -350,7 +197,8 @@ impl Signature { { let rid = RecoveryId::from_i32(self.0[64] as i32).ok()?; let sig = RecoverableSignature::from_compact(&self.0[..64], rid).ok()?; - let message = Message::from_digest_slice(message).expect("Message is 32 bytes; qed"); + let message = + Message::from_digest_slice(message).expect("Message is a 32 bytes hash; qed"); SECP256K1.recover_ecdsa(&message, &sig).ok().map(Public::from) } @@ -387,6 +235,7 @@ impl From for Signature { /// Derive a single hard junction. fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed { + use codec::Encode; ("Secp256k1HDKD", secret_seed, cc).using_encoded(sp_crypto_hashing::blake2_256) } @@ -490,15 +339,18 @@ impl Pair { pub fn sign_prehashed(&self, message: &[u8; 32]) -> Signature { #[cfg(feature = "std")] { - let message = Message::from_digest_slice(message).expect("Message is 32 bytes; qed"); + let message = + Message::from_digest_slice(message).expect("Message is a 32 bytes hash; qed"); SECP256K1.sign_ecdsa_recoverable(&message, &self.secret).into() } #[cfg(not(feature = "std"))] { + // Signing fails only if the `message` number of bytes is less than the field length + // (unfallible as we're using a fixed message length of 32). self.secret .sign_prehash_recoverable(message) - .expect("signing may not fail (???). qed.") + .expect("Signing can't fail when using 32 bytes message hash. qed.") .into() } } diff --git a/substrate/primitives/core/src/ed25519.rs b/substrate/primitives/core/src/ed25519.rs index 9f42b36dc8b..0dda7b95972 100644 --- a/substrate/primitives/core/src/ed25519.rs +++ b/substrate/primitives/core/src/ed25519.rs @@ -15,119 +15,45 @@ // See the License for the specific language governing permissions and // limitations under the License. -// tag::description[] //! Simple Ed25519 API. -// end::description[] - -use sp_std::vec::Vec; - -use crate::{ - crypto::ByteArray, - hash::{H256, H512}, -}; -use codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; #[cfg(feature = "serde")] use crate::crypto::Ss58Codec; use crate::crypto::{ - CryptoType, CryptoTypeId, Derive, DeriveError, DeriveJunction, FromEntropy, Pair as TraitPair, - Public as TraitPublic, SecretStringError, UncheckedFrom, + ByteArray, CryptoType, CryptoTypeId, Derive, DeriveError, DeriveJunction, Pair as TraitPair, + Public as TraitPublic, PublicBytes, SecretStringError, SignatureBytes, }; -#[cfg(feature = "full_crypto")] -use core::convert::TryFrom; + use ed25519_zebra::{SigningKey, VerificationKey}; #[cfg(feature = "serde")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; -use sp_runtime_interface::pass_by::PassByInner; #[cfg(all(not(feature = "std"), feature = "serde"))] use sp_std::alloc::{format, string::String}; -use sp_std::ops::Deref; +use sp_std::vec::Vec; /// An identifier used to match public keys against ed25519 keys pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ed25"); +/// The byte length of public key +pub const PUBLIC_KEY_SERIALIZED_SIZE: usize = 32; + +/// The byte length of signature +pub const SIGNATURE_SERIALIZED_SIZE: usize = 64; + /// A secret seed. It's not called a "secret key" because ring doesn't expose the secret keys /// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we /// will need it later (such as for HDKD). type Seed = [u8; 32]; -/// A public key. -#[derive( - PartialEq, - Eq, - PartialOrd, - Ord, - Clone, - Copy, - Encode, - Decode, - PassByInner, - MaxEncodedLen, - TypeInfo, - Hash, -)] -pub struct Public(pub [u8; 32]); +#[doc(hidden)] +pub struct Ed25519Tag; -/// A key pair. -#[derive(Copy, Clone)] -pub struct Pair { - public: VerificationKey, - secret: SigningKey, -} - -impl FromEntropy for Public { - fn from_entropy(input: &mut impl codec::Input) -> Result { - let mut result = Self([0u8; 32]); - input.read(&mut result.0[..])?; - Ok(result) - } -} - -impl AsRef<[u8; 32]> for Public { - fn as_ref(&self) -> &[u8; 32] { - &self.0 - } -} - -impl AsRef<[u8]> for Public { - fn as_ref(&self) -> &[u8] { - &self.0[..] - } -} - -impl AsMut<[u8]> for Public { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.0[..] - } -} - -impl Deref for Public { - type Target = [u8]; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl TryFrom<&[u8]> for Public { - type Error = (); +/// A public key. +pub type Public = PublicBytes; - fn try_from(data: &[u8]) -> Result { - if data.len() != Self::LEN { - return Err(()) - } - let mut r = [0u8; Self::LEN]; - r.copy_from_slice(data); - Ok(Self::unchecked_from(r)) - } -} +impl TraitPublic for Public {} -impl From for [u8; 32] { - fn from(x: Public) -> Self { - x.0 - } -} +impl Derive for Public {} #[cfg(feature = "full_crypto")] impl From for Public { @@ -136,12 +62,6 @@ impl From for Public { } } -impl From for H256 { - fn from(x: Public) -> Self { - x.0.into() - } -} - #[cfg(feature = "std")] impl std::str::FromStr for Public { type Err = crate::crypto::PublicError; @@ -151,18 +71,6 @@ impl std::str::FromStr for Public { } } -impl UncheckedFrom<[u8; 32]> for Public { - fn unchecked_from(x: [u8; 32]) -> Self { - Public::from_raw(x) - } -} - -impl UncheckedFrom for Public { - fn unchecked_from(x: H256) -> Self { - Public::from_h256(x) - } -} - #[cfg(feature = "std")] impl std::fmt::Display for Public { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { @@ -204,23 +112,8 @@ impl<'de> Deserialize<'de> for Public { } } -/// A signature (a 512-bit value). -#[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq, Hash)] -pub struct Signature(pub [u8; 64]); - -impl TryFrom<&[u8]> for Signature { - type Error = (); - - fn try_from(data: &[u8]) -> Result { - if data.len() == 64 { - let mut inner = [0u8; 64]; - inner.copy_from_slice(data); - Ok(Signature(inner)) - } else { - Err(()) - } - } -} +/// A signature. +pub type Signature = SignatureBytes; #[cfg(feature = "serde")] impl Serialize for Signature { @@ -245,44 +138,6 @@ impl<'de> Deserialize<'de> for Signature { } } -impl Clone for Signature { - fn clone(&self) -> Self { - let mut r = [0u8; 64]; - r.copy_from_slice(&self.0[..]); - Signature(r) - } -} - -impl From for H512 { - fn from(v: Signature) -> H512 { - H512::from(v.0) - } -} - -impl From for [u8; 64] { - fn from(v: Signature) -> [u8; 64] { - v.0 - } -} - -impl AsRef<[u8; 64]> for Signature { - fn as_ref(&self) -> &[u8; 64] { - &self.0 - } -} - -impl AsRef<[u8]> for Signature { - fn as_ref(&self) -> &[u8] { - &self.0[..] - } -} - -impl AsMut<[u8]> for Signature { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.0[..] - } -} - impl sp_std::fmt::Debug for Signature { #[cfg(feature = "std")] fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { @@ -295,76 +150,16 @@ impl sp_std::fmt::Debug for Signature { } } -impl UncheckedFrom<[u8; 64]> for Signature { - fn unchecked_from(data: [u8; 64]) -> Signature { - Signature(data) - } -} - -impl Signature { - /// A new instance from the given 64-byte `data`. - /// - /// NOTE: No checking goes on to ensure this is a real signature. Only use it if - /// you are certain that the array actually is a signature. GIGO! - pub fn from_raw(data: [u8; 64]) -> Signature { - Signature(data) - } - - /// A new instance from the given slice that should be 64 bytes long. - /// - /// NOTE: No checking goes on to ensure this is a real signature. Only use it if - /// you are certain that the array actually is a signature. GIGO! - pub fn from_slice(data: &[u8]) -> Option { - if data.len() != 64 { - return None - } - let mut r = [0u8; 64]; - r.copy_from_slice(data); - Some(Signature(r)) - } - - /// A new instance from an H512. - /// - /// NOTE: No checking goes on to ensure this is a real signature. Only use it if - /// you are certain that the array actually is a signature. GIGO! - pub fn from_h512(v: H512) -> Signature { - Signature(v.into()) - } -} - -impl Public { - /// A new instance from the given 32-byte `data`. - /// - /// NOTE: No checking goes on to ensure this is a real public key. Only use it if - /// you are certain that the array actually is a pubkey. GIGO! - pub fn from_raw(data: [u8; 32]) -> Self { - Public(data) - } - - /// A new instance from an H256. - /// - /// NOTE: No checking goes on to ensure this is a real public key. Only use it if - /// you are certain that the array actually is a pubkey. GIGO! - pub fn from_h256(x: H256) -> Self { - Public(x.into()) - } - - /// Return a slice filled with raw data. - pub fn as_array_ref(&self) -> &[u8; 32] { - self.as_ref() - } -} - -impl ByteArray for Public { - const LEN: usize = 32; +/// A key pair. +#[derive(Copy, Clone)] +pub struct Pair { + public: VerificationKey, + secret: SigningKey, } -impl TraitPublic for Public {} - -impl Derive for Public {} - /// Derive a single hard junction. fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed { + use codec::Encode; ("Ed25519HDKD", secret_seed, cc).using_encoded(sp_crypto_hashing::blake2_256) } @@ -402,7 +197,7 @@ impl TraitPair for Pair { /// Get the public key. fn public(&self) -> Public { - Public(self.public.into()) + Public::from_raw(self.public.into()) } /// Sign a message. diff --git a/substrate/primitives/core/src/lib.rs b/substrate/primitives/core/src/lib.rs index c0b41234460..cf803c6fb49 100644 --- a/substrate/primitives/core/src/lib.rs +++ b/substrate/primitives/core/src/lib.rs @@ -62,6 +62,7 @@ mod address_uri; pub mod bandersnatch; #[cfg(feature = "bls-experimental")] pub mod bls; +pub mod crypto_bytes; pub mod defer; pub mod ecdsa; pub mod ed25519; diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 6d2e6ddf334..27a7ab28dfd 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -17,25 +17,22 @@ //! API for using a pair of crypto schemes together. +use core::marker::PhantomData; + #[cfg(feature = "serde")] use crate::crypto::Ss58Codec; use crate::crypto::{ ByteArray, CryptoType, Derive, DeriveError, DeriveJunction, Pair as PairT, Public as PublicT, - SecretStringError, UncheckedFrom, + PublicBytes, SecretStringError, SignatureBytes, UncheckedFrom, }; use sp_std::vec::Vec; -use codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; #[cfg(feature = "serde")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; #[cfg(all(not(feature = "std"), feature = "serde"))] use sp_std::alloc::{format, string::String}; -use sp_runtime_interface::pass_by::{self, PassBy, PassByInner}; -use sp_std::convert::TryFrom; - /// ECDSA and BLS12-377 paired crypto scheme #[cfg(feature = "bls-experimental")] pub mod ecdsa_bls377 { @@ -54,12 +51,20 @@ pub mod ecdsa_bls377 { const SIGNATURE_LEN: usize = ecdsa::SIGNATURE_SERIALIZED_SIZE + bls377::SIGNATURE_SERIALIZED_SIZE; + #[doc(hidden)] + pub struct EcdsaBls377Tag(ecdsa::EcdsaTag, bls377::Bls377Tag); + + impl super::PairedCryptoSubTagBound for EcdsaBls377Tag {} + /// (ECDSA,BLS12-377) key-pair pair. - pub type Pair = super::Pair; + pub type Pair = + super::Pair; + /// (ECDSA,BLS12-377) public key pair. - pub type Public = super::Public; + pub type Public = super::Public; + /// (ECDSA,BLS12-377) signature pair. - pub type Signature = super::Signature; + pub type Signature = super::Signature; impl super::CryptoType for Public { type Pair = Pair; @@ -110,7 +115,7 @@ pub mod ecdsa_bls377 { let Ok(left_pub) = public.0[..ecdsa::PUBLIC_KEY_SERIALIZED_SIZE].try_into() else { return false }; - let Ok(left_sig) = sig.0[0..ecdsa::SIGNATURE_SERIALIZED_SIZE].try_into() else { + let Ok(left_sig) = sig.0[..ecdsa::SIGNATURE_SERIALIZED_SIZE].try_into() else { return false }; if !ecdsa::Pair::verify_prehashed(&left_sig, &msg_hash, &left_pub) { @@ -140,110 +145,49 @@ const SECURE_SEED_LEN: usize = 32; /// will need it later (such as for HDKD). type Seed = [u8; SECURE_SEED_LEN]; -/// A public key. -#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] -pub struct Public([u8; LEFT_PLUS_RIGHT_LEN]); - -impl sp_std::hash::Hash for Public { - fn hash(&self, state: &mut H) { - self.0.hash(state); - } -} - -impl ByteArray for Public { - const LEN: usize = LEFT_PLUS_RIGHT_LEN; -} - -impl TryFrom<&[u8]> for Public { - type Error = (); - - fn try_from(data: &[u8]) -> Result { - if data.len() != LEFT_PLUS_RIGHT_LEN { - return Err(()) - } - let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; - inner.copy_from_slice(data); - Ok(Public(inner)) - } -} - -impl AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> - for Public -{ - fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] { - &self.0 - } -} - -impl AsRef<[u8]> for Public { - fn as_ref(&self) -> &[u8] { - &self.0[..] - } -} - -impl AsMut<[u8]> for Public { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.0[..] - } -} - -impl PassByInner for Public { - type Inner = [u8; LEFT_PLUS_RIGHT_LEN]; - - fn into_inner(self) -> Self::Inner { - self.0 - } - - fn inner(&self) -> &Self::Inner { - &self.0 - } +#[doc(hidden)] +pub trait PairedCryptoSubTagBound {} +#[doc(hidden)] +pub struct PairedCryptoTag; - fn from_inner(inner: Self::Inner) -> Self { - Self(inner) - } -} - -impl PassBy for Public { - type PassBy = pass_by::Inner; -} +/// A public key. +pub type Public = + PublicBytes; impl< LeftPair: PairT, RightPair: PairT, const LEFT_PLUS_RIGHT_PUBLIC_LEN: usize, const SIGNATURE_LEN: usize, - > From> - for Public + SubTag: PairedCryptoSubTagBound, + > From> + for Public where - Pair: - PairT>, + Pair: + PairT>, { - fn from(x: Pair) -> Self { + fn from( + x: Pair, + ) -> Self { x.public() } } -impl UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> - for Public -{ - fn unchecked_from(data: [u8; LEFT_PLUS_RIGHT_LEN]) -> Self { - Public(data) - } -} - #[cfg(feature = "std")] -impl std::fmt::Display for Public +impl std::fmt::Display + for Public where - Public: CryptoType, + Public: CryptoType, { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.to_ss58check()) } } -impl sp_std::fmt::Debug for Public +impl sp_std::fmt::Debug + for Public where - Public: CryptoType, + Public: CryptoType, [u8; LEFT_PLUS_RIGHT_LEN]: crate::hexdisplay::AsBytesRef, { #[cfg(feature = "std")] @@ -259,9 +203,10 @@ where } #[cfg(feature = "serde")] -impl Serialize for Public +impl Serialize + for Public where - Public: CryptoType, + Public: CryptoType, { fn serialize(&self, serializer: S) -> Result where @@ -272,9 +217,10 @@ where } #[cfg(feature = "serde")] -impl<'de, const LEFT_PLUS_RIGHT_LEN: usize> Deserialize<'de> for Public +impl<'de, const LEFT_PLUS_RIGHT_LEN: usize, SubTag: PairedCryptoSubTagBound> Deserialize<'de> + for Public where - Public: CryptoType, + Public: CryptoType, { fn deserialize(deserializer: D) -> Result where @@ -285,12 +231,17 @@ where } } -impl PublicT for Public where - Public: CryptoType +impl PublicT + for Public +where + Public: CryptoType, { } -impl Derive for Public {} +impl Derive + for Public +{ +} /// Trait characterizing a signature which could be used as individual component of an /// `paired_crypto:Signature` pair. @@ -299,54 +250,13 @@ pub trait SignatureBound: ByteArray {} impl SignatureBound for T {} /// A pair of signatures of different types -#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] -pub struct Signature([u8; LEFT_PLUS_RIGHT_LEN]); - -impl sp_std::hash::Hash for Signature { - fn hash(&self, state: &mut H) { - self.0.hash(state); - } -} - -impl ByteArray for Signature { - const LEN: usize = LEFT_PLUS_RIGHT_LEN; -} - -impl TryFrom<&[u8]> for Signature { - type Error = (); - - fn try_from(data: &[u8]) -> Result { - if data.len() != LEFT_PLUS_RIGHT_LEN { - return Err(()) - } - let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; - inner.copy_from_slice(data); - Ok(Signature(inner)) - } -} - -impl AsMut<[u8]> for Signature { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.0[..] - } -} - -impl AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> - for Signature -{ - fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] { - &self.0 - } -} - -impl AsRef<[u8]> for Signature { - fn as_ref(&self) -> &[u8] { - &self.0[..] - } -} +pub type Signature = + SignatureBytes; #[cfg(feature = "serde")] -impl Serialize for Signature { +impl Serialize + for Signature +{ fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -356,28 +266,23 @@ impl Serialize for Signature Deserialize<'de> for Signature { +impl<'de, const LEFT_PLUS_RIGHT_LEN: usize, SubTag> Deserialize<'de> + for Signature +{ fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let bytes = array_bytes::hex2bytes(&String::deserialize(deserializer)?) .map_err(|e| de::Error::custom(format!("{:?}", e)))?; - Signature::::try_from(bytes.as_ref()).map_err(|e| { + Signature::::try_from(bytes.as_ref()).map_err(|e| { de::Error::custom(format!("Error converting deserialized data into signature: {:?}", e)) }) } } -impl From> - for [u8; LEFT_PLUS_RIGHT_LEN] -{ - fn from(signature: Signature) -> [u8; LEFT_PLUS_RIGHT_LEN] { - signature.0 - } -} - -impl sp_std::fmt::Debug for Signature +impl sp_std::fmt::Debug + for Signature where [u8; LEFT_PLUS_RIGHT_LEN]: crate::hexdisplay::AsBytesRef, { @@ -392,24 +297,30 @@ where } } -impl UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> - for Signature -{ - fn unchecked_from(data: [u8; LEFT_PLUS_RIGHT_LEN]) -> Self { - Signature(data) - } -} - /// A key pair. -#[derive(Clone)] pub struct Pair< LeftPair: PairT, RightPair: PairT, const PUBLIC_KEY_LEN: usize, const SIGNATURE_LEN: usize, + SubTag, > { left: LeftPair, right: RightPair, + _phantom: PhantomData SubTag>, +} + +impl< + LeftPair: PairT + Clone, + RightPair: PairT + Clone, + const PUBLIC_KEY_LEN: usize, + const SIGNATURE_LEN: usize, + SubTag, + > Clone for Pair +{ + fn clone(&self) -> Self { + Self { left: self.left.clone(), right: self.right.clone(), _phantom: PhantomData } + } } impl< @@ -417,18 +328,19 @@ impl< RightPair: PairT, const PUBLIC_KEY_LEN: usize, const SIGNATURE_LEN: usize, - > PairT for Pair + SubTag: PairedCryptoSubTagBound, + > PairT for Pair where - Pair: CryptoType, + Pair: CryptoType, LeftPair::Signature: SignatureBound, RightPair::Signature: SignatureBound, - Public: CryptoType, + Public: CryptoType, LeftPair::Seed: From + Into, RightPair::Seed: From + Into, { type Seed = Seed; - type Public = Public; - type Signature = Signature; + type Public = Public; + type Signature = Signature; fn from_seed_slice(seed_slice: &[u8]) -> Result { if seed_slice.len() != SECURE_SEED_LEN { @@ -436,7 +348,7 @@ where } let left = LeftPair::from_seed_slice(&seed_slice)?; let right = RightPair::from_seed_slice(&seed_slice)?; - Ok(Pair { left, right }) + Ok(Pair { left, right, _phantom: PhantomData }) } /// Derive a child key from a series of given junctions. @@ -459,7 +371,7 @@ where _ => None, }; - Ok((Self { left: left.0, right: right.0 }, seed)) + Ok((Self { left: left.0, right: right.0, _phantom: PhantomData }, seed)) } fn public(&self) -> Self::Public { @@ -479,16 +391,18 @@ where Self::Signature::unchecked_from(raw) } - fn verify>(sig: &Self::Signature, message: M, public: &Self::Public) -> bool { + fn verify>( + sig: &Self::Signature, + message: Msg, + public: &Self::Public, + ) -> bool { let Ok(left_pub) = public.0[..LeftPair::Public::LEN].try_into() else { return false }; let Ok(left_sig) = sig.0[0..LeftPair::Signature::LEN].try_into() else { return false }; if !LeftPair::verify(&left_sig, message.as_ref(), &left_pub) { return false } - let Ok(right_pub) = public.0[LeftPair::Public::LEN..PUBLIC_KEY_LEN].try_into() else { - return false - }; + let Ok(right_pub) = public.0[LeftPair::Public::LEN..].try_into() else { return false }; let Ok(right_sig) = sig.0[LeftPair::Signature::LEN..].try_into() else { return false }; RightPair::verify(&right_sig, message.as_ref(), &right_pub) } @@ -506,6 +420,7 @@ where mod test { use super::*; use crate::{crypto::DEV_PHRASE, KeccakHasher}; + use codec::{Decode, Encode}; use ecdsa_bls377::{Pair, Signature}; use crate::{bls377, ecdsa}; diff --git a/substrate/primitives/core/src/sr25519.rs b/substrate/primitives/core/src/sr25519.rs index 6c04eb8def1..ee0546bc534 100644 --- a/substrate/primitives/core/src/sr25519.rs +++ b/substrate/primitives/core/src/sr25519.rs @@ -19,6 +19,7 @@ //! //! Note: `CHAIN_CODE_LENGTH` must be equal to `crate::crypto::JUNCTION_ID_LEN` //! for this to work. + #[cfg(feature = "serde")] use crate::crypto::Ss58Codec; use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError}; @@ -30,20 +31,16 @@ use schnorrkel::{ }; use sp_std::vec::Vec; -use crate::{ - crypto::{ - ByteArray, CryptoType, CryptoTypeId, Derive, FromEntropy, Public as TraitPublic, - UncheckedFrom, - }, - hash::{H256, H512}, +use crate::crypto::{ + CryptoType, CryptoTypeId, Derive, Public as TraitPublic, PublicBytes, SignatureBytes, }; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; -use sp_std::ops::Deref; use schnorrkel::keys::{MINI_SECRET_KEY_LENGTH, SECRET_KEY_LENGTH}; #[cfg(feature = "serde")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; +#[cfg(feature = "std")] use sp_runtime_interface::pass_by::PassByInner; #[cfg(all(not(feature = "std"), feature = "serde"))] use sp_std::alloc::{format, string::String}; @@ -54,22 +51,17 @@ const SIGNING_CTX: &[u8] = b"substrate"; /// An identifier used to match public keys against sr25519 keys pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"sr25"); +/// The byte length of public key +pub const PUBLIC_KEY_SERIALIZED_SIZE: usize = 32; + +/// The byte length of signature +pub const SIGNATURE_SERIALIZED_SIZE: usize = 64; + +#[doc(hidden)] +pub struct Sr25519Tag; + /// An Schnorrkel/Ristretto x25519 ("sr25519") public key. -#[derive( - PartialEq, - Eq, - PartialOrd, - Ord, - Clone, - Copy, - Encode, - Decode, - PassByInner, - MaxEncodedLen, - TypeInfo, - Hash, -)] -pub struct Public(pub [u8; 32]); +pub type Public = PublicBytes; /// An Schnorrkel/Ristretto x25519 ("sr25519") key pair. pub struct Pair(Keypair); @@ -84,52 +76,6 @@ impl Clone for Pair { } } -impl FromEntropy for Public { - fn from_entropy(input: &mut impl codec::Input) -> Result { - let mut result = Self([0u8; 32]); - input.read(&mut result.0[..])?; - Ok(result) - } -} - -impl AsRef<[u8; 32]> for Public { - fn as_ref(&self) -> &[u8; 32] { - &self.0 - } -} - -impl AsRef<[u8]> for Public { - fn as_ref(&self) -> &[u8] { - &self.0[..] - } -} - -impl AsMut<[u8]> for Public { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.0[..] - } -} - -impl Deref for Public { - type Target = [u8]; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl From for [u8; 32] { - fn from(x: Public) -> [u8; 32] { - x.0 - } -} - -impl From for H256 { - fn from(x: Public) -> H256 { - x.0.into() - } -} - #[cfg(feature = "std")] impl std::str::FromStr for Public { type Err = crate::crypto::PublicError; @@ -139,31 +85,6 @@ impl std::str::FromStr for Public { } } -impl TryFrom<&[u8]> for Public { - type Error = (); - - fn try_from(data: &[u8]) -> Result { - if data.len() != Self::LEN { - return Err(()) - } - let mut r = [0u8; 32]; - r.copy_from_slice(data); - Ok(Self::unchecked_from(r)) - } -} - -impl UncheckedFrom<[u8; 32]> for Public { - fn unchecked_from(x: [u8; 32]) -> Self { - Public::from_raw(x) - } -} - -impl UncheckedFrom for Public { - fn unchecked_from(x: H256) -> Self { - Public::from_h256(x) - } -} - #[cfg(feature = "std")] impl std::fmt::Display for Public { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { @@ -175,7 +96,7 @@ impl sp_std::fmt::Debug for Public { #[cfg(feature = "std")] fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { let s = self.to_ss58check(); - write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8]) + write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(self.inner()), &s[0..8]) } #[cfg(not(feature = "std"))] @@ -206,22 +127,7 @@ impl<'de> Deserialize<'de> for Public { } /// An Schnorrkel/Ristretto x25519 ("sr25519") signature. -#[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq, Hash)] -pub struct Signature(pub [u8; 64]); - -impl TryFrom<&[u8]> for Signature { - type Error = (); - - fn try_from(data: &[u8]) -> Result { - if data.len() == 64 { - let mut inner = [0u8; 64]; - inner.copy_from_slice(data); - Ok(Signature(inner)) - } else { - Err(()) - } - } -} +pub type Signature = SignatureBytes; #[cfg(feature = "serde")] impl Serialize for Signature { @@ -246,48 +152,10 @@ impl<'de> Deserialize<'de> for Signature { } } -impl Clone for Signature { - fn clone(&self) -> Self { - let mut r = [0u8; 64]; - r.copy_from_slice(&self.0[..]); - Signature(r) - } -} - -impl From for [u8; 64] { - fn from(v: Signature) -> [u8; 64] { - v.0 - } -} - -impl From for H512 { - fn from(v: Signature) -> H512 { - H512::from(v.0) - } -} - -impl AsRef<[u8; 64]> for Signature { - fn as_ref(&self) -> &[u8; 64] { - &self.0 - } -} - -impl AsRef<[u8]> for Signature { - fn as_ref(&self) -> &[u8] { - &self.0[..] - } -} - -impl AsMut<[u8]> for Signature { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.0[..] - } -} - #[cfg(feature = "full_crypto")] impl From for Signature { fn from(s: schnorrkel::Signature) -> Signature { - Signature(s.to_bytes()) + Signature::from(s.to_bytes()) } } @@ -303,45 +171,6 @@ impl sp_std::fmt::Debug for Signature { } } -impl UncheckedFrom<[u8; 64]> for Signature { - fn unchecked_from(data: [u8; 64]) -> Signature { - Signature(data) - } -} - -impl Signature { - /// A new instance from the given 64-byte `data`. - /// - /// NOTE: No checking goes on to ensure this is a real signature. Only use - /// it if you are certain that the array actually is a signature, or if you - /// immediately verify the signature. All functions that verify signatures - /// will fail if the `Signature` is not actually a valid signature. - pub fn from_raw(data: [u8; 64]) -> Signature { - Signature(data) - } - - /// A new instance from the given slice that should be 64 bytes long. - /// - /// NOTE: No checking goes on to ensure this is a real signature. Only use it if - /// you are certain that the array actually is a signature. GIGO! - pub fn from_slice(data: &[u8]) -> Option { - if data.len() != 64 { - return None - } - let mut r = [0u8; 64]; - r.copy_from_slice(data); - Some(Signature(r)) - } - - /// A new instance from an H512. - /// - /// NOTE: No checking goes on to ensure this is a real signature. Only use it if - /// you are certain that the array actually is a signature. GIGO! - pub fn from_h512(v: H512) -> Signature { - Signature(v.into()) - } -} - impl Derive for Public { /// Derive a child key from a series of given junctions. /// @@ -355,37 +184,10 @@ impl Derive for Public { DeriveJunction::Hard(_cc) => return None, } } - Some(Self(acc.to_bytes())) - } -} - -impl Public { - /// A new instance from the given 32-byte `data`. - /// - /// NOTE: No checking goes on to ensure this is a real public key. Only use it if - /// you are certain that the array actually is a pubkey. GIGO! - pub fn from_raw(data: [u8; 32]) -> Self { - Public(data) - } - - /// A new instance from an H256. - /// - /// NOTE: No checking goes on to ensure this is a real public key. Only use it if - /// you are certain that the array actually is a pubkey. GIGO! - pub fn from_h256(x: H256) -> Self { - Public(x.into()) - } - - /// Return a slice filled with raw data. - pub fn as_array_ref(&self) -> &[u8; 32] { - self.as_ref() + Some(Self::from(acc.to_bytes())) } } -impl ByteArray for Public { - const LEN: usize = 32; -} - impl TraitPublic for Public {} #[cfg(feature = "std")] @@ -438,9 +240,7 @@ impl TraitPair for Pair { /// Get the public key. fn public(&self) -> Public { - let mut pk = [0u8; 32]; - pk.copy_from_slice(&self.0.public.to_bytes()); - Public(pk) + Public::from(self.0.public.to_bytes()) } /// Make a new key pair from raw secret seed material. @@ -720,7 +520,7 @@ pub mod vrf { impl VrfPublic for Public { fn vrf_verify(&self, data: &Self::VrfSignData, signature: &Self::VrfSignature) -> bool { let do_verify = || { - let public = schnorrkel::PublicKey::from_bytes(self)?; + let public = schnorrkel::PublicKey::from_bytes(&self.0)?; let inout = signature.pre_output.0.attach_input_hash(&public, data.transcript.0.clone())?; @@ -820,7 +620,10 @@ pub mod vrf { #[cfg(test)] mod tests { use super::{vrf::*, *}; - use crate::crypto::{Ss58Codec, VrfPublic, VrfSecret, DEV_ADDRESS, DEV_PHRASE}; + use crate::{ + crypto::{Ss58Codec, VrfPublic, VrfSecret, DEV_ADDRESS, DEV_PHRASE}, + ByteArray as _, + }; use serde_json; #[test] @@ -984,10 +787,10 @@ mod tests { let (pair, _) = Pair::generate(); let public = pair.public(); let message = b"Signed payload"; - let Signature(mut bytes) = pair.sign(&message[..]); + let mut signature = pair.sign(&message[..]); + let bytes = &mut signature.0; bytes[0] = !bytes[0]; bytes[2] = !bytes[2]; - let signature = Signature(bytes); assert!(!Pair::verify(&signature, &message[..], &public)); } diff --git a/substrate/primitives/keystore/src/testing.rs b/substrate/primitives/keystore/src/testing.rs index e10660b126a..d8610ecfa5b 100644 --- a/substrate/primitives/keystore/src/testing.rs +++ b/substrate/primitives/keystore/src/testing.rs @@ -528,7 +528,7 @@ mod tests { assert!(res.is_some()); // does not verify with default out-of-the-box verification - assert!(!ecdsa_bls377::Pair::verify(&res.clone().unwrap(), &msg[..], &pair.public())); + assert!(!ecdsa_bls377::Pair::verify(&res.unwrap(), &msg[..], &pair.public())); // should verify using keccak256 as hasher assert!(ecdsa_bls377::Pair::verify_with_hasher::( diff --git a/substrate/primitives/runtime/src/traits.rs b/substrate/primitives/runtime/src/traits.rs index caede5e2b59..9ee41339d50 100644 --- a/substrate/primitives/runtime/src/traits.rs +++ b/substrate/primitives/runtime/src/traits.rs @@ -133,7 +133,7 @@ impl Verify for sp_core::ecdsa::Signature { self.as_ref(), &sp_io::hashing::blake2_256(msg.get()), ) { - Ok(pubkey) => signer.as_ref() == &pubkey[..], + Ok(pubkey) => signer.0 == pubkey, _ => false, } } diff --git a/substrate/primitives/statement-store/src/lib.rs b/substrate/primitives/statement-store/src/lib.rs index bfcd0d1a52a..dbac017ff64 100644 --- a/substrate/primitives/statement-store/src/lib.rs +++ b/substrate/primitives/statement-store/src/lib.rs @@ -340,8 +340,8 @@ impl Statement { Some(Proof::OnChain { .. }) | None => SignatureVerificationResult::NoSignature, Some(Proof::Sr25519 { signature, signer }) => { let to_sign = self.signature_material(); - let signature = sp_core::sr25519::Signature(*signature); - let public = sp_core::sr25519::Public(*signer); + let signature = sp_core::sr25519::Signature::from(*signature); + let public = sp_core::sr25519::Public::from(*signer); if signature.verify(to_sign.as_slice(), &public) { SignatureVerificationResult::Valid(*signer) } else { @@ -350,8 +350,8 @@ impl Statement { }, Some(Proof::Ed25519 { signature, signer }) => { let to_sign = self.signature_material(); - let signature = sp_core::ed25519::Signature(*signature); - let public = sp_core::ed25519::Public(*signer); + let signature = sp_core::ed25519::Signature::from(*signature); + let public = sp_core::ed25519::Public::from(*signer); if signature.verify(to_sign.as_slice(), &public) { SignatureVerificationResult::Valid(*signer) } else { @@ -360,8 +360,8 @@ impl Statement { }, Some(Proof::Secp256k1Ecdsa { signature, signer }) => { let to_sign = self.signature_material(); - let signature = sp_core::ecdsa::Signature(*signature); - let public = sp_core::ecdsa::Public(*signer); + let signature = sp_core::ecdsa::Signature::from(*signature); + let public = sp_core::ecdsa::Public::from(*signer); if signature.verify(to_sign.as_slice(), &public) { let sender_hash = ::hash(signer); -- GitLab From c486da32b151a5d29276a9b5ee5b705f91b8bd01 Mon Sep 17 00:00:00 2001 From: Javier Viola <363911+pepoviola@users.noreply.github.com> Date: Tue, 19 Mar 2024 18:10:45 +0100 Subject: [PATCH 064/187] chore: bump zombienet version (1.3.95) (#3745) Bump zombienet version, this version have the latest version of `@polkadot/api` module and fix the failures in CI (e.g https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/5570106). Thanks! --- .gitlab/pipeline/zombienet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab/pipeline/zombienet.yml b/.gitlab/pipeline/zombienet.yml index 55120e66d0e..8d308714fab 100644 --- a/.gitlab/pipeline/zombienet.yml +++ b/.gitlab/pipeline/zombienet.yml @@ -1,7 +1,7 @@ .zombienet-refs: extends: .build-refs variables: - ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.91" + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.95" include: # substrate tests -- GitLab From e659c4b3f744b1f04ec210e448485048b6eafa64 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Tue, 19 Mar 2024 20:13:51 +0100 Subject: [PATCH 065/187] Contracts: Test benchmarking v2 (#3585) Co-authored-by: command-bot <> --- .../frame/contracts/src/benchmarking/mod.rs | 2329 +++++++++-------- substrate/frame/contracts/src/weights.rs | 1497 ++++++----- 2 files changed, 2094 insertions(+), 1732 deletions(-) diff --git a/substrate/frame/contracts/src/benchmarking/mod.rs b/substrate/frame/contracts/src/benchmarking/mod.rs index 794777ef05c..ce2cf15d812 100644 --- a/substrate/frame/contracts/src/benchmarking/mod.rs +++ b/substrate/frame/contracts/src/benchmarking/mod.rs @@ -16,7 +16,6 @@ // limitations under the License. //! Benchmarks for the contracts pallet - #![cfg(feature = "runtime-benchmarks")] mod code; @@ -36,7 +35,7 @@ use crate::{ Pallet as Contracts, *, }; use codec::{Encode, MaxEncodedLen}; -use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller}; +use frame_benchmarking::v2::*; use frame_support::{ self, pallet_prelude::StorageVersion, @@ -184,172 +183,215 @@ fn caller_funding() -> BalanceOf { BalanceOf::::max_value() / 10_000u32.into() } -benchmarks! { - where_clause { where +#[benchmarks( + where as codec::HasCompact>::Type: Clone + Eq + PartialEq + sp_std::fmt::Debug + scale_info::TypeInfo + codec::Encode, T: Config + pallet_balances::Config, BalanceOf: From< as Currency>::Balance>, as Currency>::Balance: From>, - } +)] +mod benchmarks { + use super::*; // The base weight consumed on processing contracts deletion queue. - #[pov_mode = Measured] - on_process_deletion_queue_batch {}: { - ContractInfo::::process_deletion_queue_batch(Weight::MAX) + #[benchmark(pov_mode = Measured)] + fn on_process_deletion_queue_batch() { + #[block] + { + ContractInfo::::process_deletion_queue_batch(Weight::MAX); + } } - #[skip_meta] - #[pov_mode = Measured] - on_initialize_per_trie_key { - let k in 0..1024; - let instance = Contract::::with_storage(WasmModule::dummy(), k, T::Schedule::get().limits.payload_len)?; + #[benchmark(skip_meta, pov_mode = Measured)] + fn on_initialize_per_trie_key(k: Linear<0, 1024>) -> Result<(), BenchmarkError> { + let instance = Contract::::with_storage( + WasmModule::dummy(), + k, + T::Schedule::get().limits.payload_len, + )?; instance.info()?.queue_trie_for_deletion(); - }: { - ContractInfo::::process_deletion_queue_batch(Weight::MAX) + + #[block] + { + ContractInfo::::process_deletion_queue_batch(Weight::MAX); + } + + Ok(()) } // This benchmarks the v9 migration step (update codeStorage). - #[pov_mode = Measured] - v9_migration_step { - let c in 0 .. T::MaxCodeLen::get(); + #[benchmark(pov_mode = Measured)] + fn v9_migration_step(c: Linear<0, { T::MaxCodeLen::get() }>) { v09::store_old_dummy_code::(c as usize); let mut m = v09::Migration::::default(); - }: { - m.step(); + #[block] + { + m.step(); + } } // This benchmarks the v10 migration step (use dedicated deposit_account). - #[pov_mode = Measured] - v10_migration_step { - let contract = >::with_caller( - whitelisted_caller(), WasmModule::dummy(), vec![], - )?; - - v10::store_old_contract_info::>(contract.account_id.clone(), contract.info()?); + #[benchmark(pov_mode = Measured)] + fn v10_migration_step() -> Result<(), BenchmarkError> { + let contract = + >::with_caller(whitelisted_caller(), WasmModule::dummy(), vec![])?; + + v10::store_old_contract_info::>( + contract.account_id.clone(), + contract.info()?, + ); let mut m = v10::Migration::>::default(); - }: { - m.step(); + + #[block] + { + m.step(); + } + + Ok(()) } - // This benchmarks the v11 migration step (Don't rely on reserved balances keeping an account alive). - #[pov_mode = Measured] - v11_migration_step { - let k in 0 .. 1024; + // This benchmarks the v11 migration step (Don't rely on reserved balances keeping an account + // alive). + #[benchmark(pov_mode = Measured)] + fn v11_migration_step(k: Linear<0, 1024>) { v11::fill_old_queue::(k as usize); let mut m = v11::Migration::::default(); - }: { - m.step(); + + #[block] + { + m.step(); + } } // This benchmarks the v12 migration step (Move `OwnerInfo` to `CodeInfo`, // add `determinism` field to the latter, clear `CodeStorage` // and repay deposits). - #[pov_mode = Measured] - v12_migration_step { - let c in 0 .. T::MaxCodeLen::get(); - v12::store_old_dummy_code::< - T, - pallet_balances::Pallet - >(c as usize, account::("account", 0, 0)); + #[benchmark(pov_mode = Measured)] + fn v12_migration_step(c: Linear<0, { T::MaxCodeLen::get() }>) { + v12::store_old_dummy_code::>( + c as usize, + account::("account", 0, 0), + ); let mut m = v12::Migration::>::default(); - }: { - m.step(); + + #[block] + { + m.step(); + } } // This benchmarks the v13 migration step (Add delegate_dependencies field). - #[pov_mode = Measured] - v13_migration_step { - let contract = >::with_caller( - whitelisted_caller(), WasmModule::dummy(), vec![], - )?; + #[benchmark(pov_mode = Measured)] + fn v13_migration_step() -> Result<(), BenchmarkError> { + let contract = + >::with_caller(whitelisted_caller(), WasmModule::dummy(), vec![])?; v13::store_old_contract_info::(contract.account_id.clone(), contract.info()?); let mut m = v13::Migration::::default(); - }: { - m.step(); + + #[block] + { + m.step(); + } + Ok(()) } - // This benchmarks the v14 migration step (Move code owners' reserved balance to be held instead). - #[pov_mode = Measured] - v14_migration_step { + // This benchmarks the v14 migration step (Move code owners' reserved balance to be held + // instead). + #[benchmark(pov_mode = Measured)] + fn v14_migration_step() { let account = account::("account", 0, 0); T::Currency::set_balance(&account, caller_funding::()); v14::store_dummy_code::>(account); let mut m = v14::Migration::>::default(); - }: { - m.step(); + + #[block] + { + m.step(); + } } // This benchmarks the v15 migration step (remove deposit account). - #[pov_mode = Measured] - v15_migration_step { - let contract = >::with_caller( - whitelisted_caller(), WasmModule::dummy(), vec![], - )?; + #[benchmark(pov_mode = Measured)] + fn v15_migration_step() -> Result<(), BenchmarkError> { + let contract = + >::with_caller(whitelisted_caller(), WasmModule::dummy(), vec![])?; v15::store_old_contract_info::(contract.account_id.clone(), contract.info()?); let mut m = v15::Migration::::default(); - }: { - m.step(); + + #[block] + { + m.step(); + } + + Ok(()) } // This benchmarks the weight of executing Migration::migrate to execute a noop migration. - #[pov_mode = Measured] - migration_noop { + #[benchmark(pov_mode = Measured)] + fn migration_noop() { let version = LATEST_MIGRATION_VERSION; assert_eq!(StorageVersion::get::>(), version); - }: { - Migration::::migrate(Weight::MAX) - } verify { + #[block] + { + Migration::::migrate(Weight::MAX); + } assert_eq!(StorageVersion::get::>(), version); } // This benchmarks the weight of dispatching migrate to execute 1 `NoopMigraton` - #[pov_mode = Measured] - migrate { + #[benchmark(pov_mode = Measured)] + fn migrate() { let latest_version = LATEST_MIGRATION_VERSION; StorageVersion::new(latest_version - 2).put::>(); - as frame_support::traits::OnRuntimeUpgrade>::on_runtime_upgrade(); - let caller: T::AccountId = whitelisted_caller(); - let origin = RawOrigin::Signed(caller.clone()); - }: _(origin, Weight::MAX) - verify { + as frame_support::traits::OnRuntimeUpgrade>::on_runtime_upgrade(); + + #[extrinsic_call] + _(RawOrigin::Signed(whitelisted_caller()), Weight::MAX); + assert_eq!(StorageVersion::get::>(), latest_version - 1); } - // This benchmarks the weight of running on_runtime_upgrade when there are no migration in progress. - #[pov_mode = Measured] - on_runtime_upgrade_noop { + // This benchmarks the weight of running on_runtime_upgrade when there are no migration in + // progress. + #[benchmark(pov_mode = Measured)] + fn on_runtime_upgrade_noop() { let latest_version = LATEST_MIGRATION_VERSION; assert_eq!(StorageVersion::get::>(), latest_version); - }: { - as frame_support::traits::OnRuntimeUpgrade>::on_runtime_upgrade() - } verify { + #[block] + { + as frame_support::traits::OnRuntimeUpgrade>::on_runtime_upgrade(); + } assert!(MigrationInProgress::::get().is_none()); } - // This benchmarks the weight of running on_runtime_upgrade when there is a migration in progress. - #[pov_mode = Measured] - on_runtime_upgrade_in_progress { + // This benchmarks the weight of running on_runtime_upgrade when there is a migration in + // progress. + #[benchmark(pov_mode = Measured)] + fn on_runtime_upgrade_in_progress() { let latest_version = LATEST_MIGRATION_VERSION; StorageVersion::new(latest_version - 2).put::>(); let v = vec![42u8].try_into().ok(); MigrationInProgress::::set(v.clone()); - }: { - as frame_support::traits::OnRuntimeUpgrade>::on_runtime_upgrade() - } verify { + #[block] + { + as frame_support::traits::OnRuntimeUpgrade>::on_runtime_upgrade(); + } assert!(MigrationInProgress::::get().is_some()); assert_eq!(MigrationInProgress::::get(), v); } - // This benchmarks the weight of running on_runtime_upgrade when there is a migration to process. - #[pov_mode = Measured] - on_runtime_upgrade { + // This benchmarks the weight of running on_runtime_upgrade when there is a migration to + // process. + #[benchmark(pov_mode = Measured)] + fn on_runtime_upgrade() { let latest_version = LATEST_MIGRATION_VERSION; StorageVersion::new(latest_version - 2).put::>(); - }: { - as frame_support::traits::OnRuntimeUpgrade>::on_runtime_upgrade() - } verify { + #[block] + { + as frame_support::traits::OnRuntimeUpgrade>::on_runtime_upgrade(); + } assert!(MigrationInProgress::::get().is_some()); } @@ -357,17 +399,25 @@ benchmarks! { // the sandbox. This does **not** include the actual execution for which the gas meter // is responsible. This is achieved by generating all code to the `deploy` function // which is in the wasm module but not executed on `call`. - // The results are supposed to be used as `call_with_code_per_byte(c) - call_with_code_per_byte(0)`. - #[pov_mode = Measured] - call_with_code_per_byte { - let c in 0 .. T::MaxCodeLen::get(); + // The results are supposed to be used as `call_with_code_per_byte(c) - + // call_with_code_per_byte(0)`. + #[benchmark(pov_mode = Measured)] + fn call_with_code_per_byte( + c: Linear<0, { T::MaxCodeLen::get() }>, + ) -> Result<(), BenchmarkError> { let instance = Contract::::with_caller( - whitelisted_caller(), WasmModule::sized(c, Location::Deploy, false), vec![], + whitelisted_caller(), + WasmModule::sized(c, Location::Deploy, false), + vec![], )?; let value = Pallet::::min_balance(); - let origin = RawOrigin::Signed(instance.caller.clone()); let callee = instance.addr; - }: call(origin, callee, value, Weight::MAX, None, vec![]) + + #[extrinsic_call] + call(RawOrigin::Signed(instance.caller.clone()), callee, value, Weight::MAX, None, vec![]); + + Ok(()) + } // This constructs a contract that is maximal expensive to instrument. // It creates a maximum number of metering blocks per byte. @@ -379,11 +429,12 @@ benchmarks! { // `c`: Size of the code in bytes. // `i`: Size of the input in bytes. // `s`: Size of the salt in bytes. - #[pov_mode = Measured] - instantiate_with_code { - let c in 0 .. T::MaxCodeLen::get(); - let i in 0 .. code::max_pages::() * 64 * 1024; - let s in 0 .. code::max_pages::() * 64 * 1024; + #[benchmark(pov_mode = Measured)] + fn instantiate_with_code( + c: Linear<0, { T::MaxCodeLen::get() }>, + i: Linear<0, { code::max_pages::() * 64 * 1024 }>, + s: Linear<0, { code::max_pages::() * 64 * 1024 }>, + ) { let input = vec![42u8; i as usize]; let salt = vec![42u8; s as usize]; let value = Pallet::::min_balance(); @@ -392,11 +443,14 @@ benchmarks! { let WasmModule { code, hash, .. } = WasmModule::::sized(c, Location::Call, false); let origin = RawOrigin::Signed(caller.clone()); let addr = Contracts::::contract_address(&caller, &hash, &input, &salt); - }: _(origin, value, Weight::MAX, None, code, input, salt) - verify { - let deposit = T::Currency::balance_on_hold(&HoldReason::StorageDepositReserve.into(), &addr); + #[extrinsic_call] + _(origin, value, Weight::MAX, None, code, input, salt); + + let deposit = + T::Currency::balance_on_hold(&HoldReason::StorageDepositReserve.into(), &addr); // uploading the code reserves some balance in the callers account - let code_deposit = T::Currency::balance_on_hold(&HoldReason::CodeUploadDepositReserve.into(), &caller); + let code_deposit = + T::Currency::balance_on_hold(&HoldReason::CodeUploadDepositReserve.into(), &caller); assert_eq!( T::Currency::balance(&caller), caller_funding::() - value - deposit - code_deposit - Pallet::::min_balance(), @@ -408,22 +462,25 @@ benchmarks! { // Instantiate uses a dummy contract constructor to measure the overhead of the instantiate. // `i`: Size of the input in bytes. // `s`: Size of the salt in bytes. - #[pov_mode = Measured] - instantiate { - let i in 0 .. code::max_pages::() * 64 * 1024; - let s in 0 .. code::max_pages::() * 64 * 1024; + #[benchmark(pov_mode = Measured)] + fn instantiate( + i: Linear<0, { code::max_pages::() * 64 * 1024 }>, + s: Linear<0, { code::max_pages::() * 64 * 1024 }>, + ) -> Result<(), BenchmarkError> { let input = vec![42u8; i as usize]; let salt = vec![42u8; s as usize]; let value = Pallet::::min_balance(); let caller = whitelisted_caller(); T::Currency::set_balance(&caller, caller_funding::()); let WasmModule { code, hash, .. } = WasmModule::::dummy(); - let origin = RawOrigin::Signed(caller.clone()); let addr = Contracts::::contract_address(&caller, &hash, &input, &salt); Contracts::::store_code_raw(code, caller.clone())?; - }: _(origin, value, Weight::MAX, None, hash, input, salt) - verify { - let deposit = T::Currency::balance_on_hold(&HoldReason::StorageDepositReserve.into(), &addr); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), value, Weight::MAX, None, hash, input, salt); + + let deposit = + T::Currency::balance_on_hold(&HoldReason::StorageDepositReserve.into(), &addr); // value was removed from the caller assert_eq!( T::Currency::balance(&caller), @@ -431,6 +488,8 @@ benchmarks! { ); // contract has the full value assert_eq!(T::Currency::balance(&addr), value + Pallet::::min_balance()); + + Ok(()) } // We just call a dummy contract to measure the overhead of the call extrinsic. @@ -440,19 +499,21 @@ benchmarks! { // part of `seal_input`. The costs for invoking a contract of a specific size are not part // of this benchmark because we cannot know the size of the contract when issuing a call // transaction. See `call_with_code_per_byte` for this. - #[pov_mode = Measured] - call { + #[benchmark(pov_mode = Measured)] + fn call() -> Result<(), BenchmarkError> { let data = vec![42u8; 1024]; - let instance = Contract::::with_caller( - whitelisted_caller(), WasmModule::dummy(), vec![], - )?; + let instance = + Contract::::with_caller(whitelisted_caller(), WasmModule::dummy(), vec![])?; let value = Pallet::::min_balance(); let origin = RawOrigin::Signed(instance.caller.clone()); let callee = instance.addr.clone(); let before = T::Currency::balance(&instance.account_id); - }: _(origin, callee, value, Weight::MAX, None, data) - verify { - let deposit = T::Currency::balance_on_hold(&HoldReason::StorageDepositReserve.into(), &instance.account_id); + #[extrinsic_call] + _(origin, callee, value, Weight::MAX, None, data); + let deposit = T::Currency::balance_on_hold( + &HoldReason::StorageDepositReserve.into(), + &instance.account_id, + ); // value and value transferred via call should be removed from the caller assert_eq!( T::Currency::balance(&instance.caller), @@ -462,92 +523,93 @@ benchmarks! { assert_eq!(T::Currency::balance(&instance.account_id), before + value); // contract should still exist instance.info()?; + + Ok(()) } // This constructs a contract that is maximal expensive to instrument. // It creates a maximum number of metering blocks per byte. // `c`: Size of the code in bytes. - #[pov_mode = Measured] - upload_code_determinism_enforced { - let c in 0 .. T::MaxCodeLen::get(); + #[benchmark(pov_mode = Measured)] + fn upload_code_determinism_enforced(c: Linear<0, { T::MaxCodeLen::get() }>) { let caller = whitelisted_caller(); T::Currency::set_balance(&caller, caller_funding::()); let WasmModule { code, hash, .. } = WasmModule::::sized(c, Location::Call, false); let origin = RawOrigin::Signed(caller.clone()); - }: upload_code(origin, code, None, Determinism::Enforced) - verify { + #[extrinsic_call] + upload_code(origin, code, None, Determinism::Enforced); // uploading the code reserves some balance in the callers account assert!(T::Currency::total_balance_on_hold(&caller) > 0u32.into()); assert!(>::code_exists(&hash)); } - // Uploading code with [`Determinism::Relaxed`] should be more expensive than uploading code with [`Determinism::Enforced`], - // as we always try to save the code with [`Determinism::Enforced`] first. - #[pov_mode = Measured] - upload_code_determinism_relaxed { - let c in 0 .. T::MaxCodeLen::get(); + // Uploading code with [`Determinism::Relaxed`] should be more expensive than uploading code + // with [`Determinism::Enforced`], as we always try to save the code with + // [`Determinism::Enforced`] first. + #[benchmark(pov_mode = Measured)] + fn upload_code_determinism_relaxed(c: Linear<0, { T::MaxCodeLen::get() }>) { let caller = whitelisted_caller(); T::Currency::set_balance(&caller, caller_funding::()); let WasmModule { code, hash, .. } = WasmModule::::sized(c, Location::Call, true); let origin = RawOrigin::Signed(caller.clone()); - }: upload_code(origin, code, None, Determinism::Relaxed) - verify { + #[extrinsic_call] + upload_code(origin, code, None, Determinism::Relaxed); assert!(T::Currency::total_balance_on_hold(&caller) > 0u32.into()); assert!(>::code_exists(&hash)); - // Ensure that the benchmark follows the most expensive path, i.e., the code is saved with [`Determinism::Relaxed`] after trying to save it with [`Determinism::Enforced`]. + // Ensure that the benchmark follows the most expensive path, i.e., the code is saved with assert_eq!(CodeInfoOf::::get(&hash).unwrap().determinism(), Determinism::Relaxed); } // Removing code does not depend on the size of the contract because all the information // needed to verify the removal claim (refcount, owner) is stored in a separate storage // item (`CodeInfoOf`). - #[pov_mode = Measured] - remove_code { + #[benchmark(pov_mode = Measured)] + fn remove_code() -> Result<(), BenchmarkError> { let caller = whitelisted_caller(); T::Currency::set_balance(&caller, caller_funding::()); let WasmModule { code, hash, .. } = WasmModule::::dummy(); let origin = RawOrigin::Signed(caller.clone()); - let uploaded = >::bare_upload_code(caller.clone(), code, None, Determinism::Enforced)?; + let uploaded = + >::bare_upload_code(caller.clone(), code, None, Determinism::Enforced)?; assert_eq!(uploaded.code_hash, hash); assert_eq!(uploaded.deposit, T::Currency::total_balance_on_hold(&caller)); assert!(>::code_exists(&hash)); - }: _(origin, hash) - verify { + #[extrinsic_call] + _(origin, hash); // removing the code should have unreserved the deposit assert_eq!(T::Currency::total_balance_on_hold(&caller), 0u32.into()); assert!(>::code_removed(&hash)); + Ok(()) } - #[pov_mode = Measured] - set_code { - let instance = >::with_caller( - whitelisted_caller(), WasmModule::dummy(), vec![], - )?; + #[benchmark(pov_mode = Measured)] + fn set_code() -> Result<(), BenchmarkError> { + let instance = + >::with_caller(whitelisted_caller(), WasmModule::dummy(), vec![])?; // we just add some bytes so that the code hash is different let WasmModule { code, hash, .. } = >::dummy_with_bytes(128); >::store_code_raw(code, instance.caller.clone())?; let callee = instance.addr.clone(); assert_ne!(instance.info()?.code_hash, hash); - }: _(RawOrigin::Root, callee, hash) - verify { + #[extrinsic_call] + _(RawOrigin::Root, callee, hash); assert_eq!(instance.info()?.code_hash, hash); + Ok(()) } - #[pov_mode = Measured] - seal_caller { - let r in 0 .. API_BENCHMARK_RUNS; - let instance = Contract::::new(WasmModule::getter( - "seal0", "seal_caller", r - ), vec![])?; + #[benchmark(pov_mode = Measured)] + fn seal_caller(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { + let instance = Contract::::new(WasmModule::getter("seal0", "seal_caller", r), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); - #[pov_mode = Measured] - seal_is_contract { - let r in 0 .. API_BENCHMARK_RUNS; - let accounts = (0 .. r) - .map(|n| account::("account", n, 0)) - .collect::>(); + Ok(()) + } + + #[benchmark(pov_mode = Measured)] + fn seal_is_contract(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { + let accounts = (0..r).map(|n| account::("account", n, 0)).collect::>(); let account_len = accounts.get(0).map(|i| i.encode().len()).unwrap_or(0); let accounts_bytes = accounts.iter().flat_map(|a| a.encode()).collect::>(); let code = WasmModule::::from(ModuleDefinition { @@ -558,18 +620,16 @@ benchmarks! { params: vec![ValueType::I32], return_type: Some(ValueType::I32), }], - data_segments: vec![ - DataSegment { - offset: 0, - value: accounts_bytes - }, - ], - call_body: Some(body::repeated_dyn(r, vec![ - Counter(0, account_len as u32), // address_ptr - Regular(Instruction::Call(0)), - Regular(Instruction::Drop), - ])), - .. Default::default() + data_segments: vec![DataSegment { offset: 0, value: accounts_bytes }], + call_body: Some(body::repeated_dyn( + r, + vec![ + Counter(0, account_len as u32), // address_ptr + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ], + )), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let info = instance.info()?; @@ -578,18 +638,17 @@ benchmarks! { >::insert(acc, info.clone()); } let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); - #[pov_mode = Measured] - seal_code_hash { - let r in 0 .. API_BENCHMARK_RUNS; - let accounts = (0 .. r) - .map(|n| account::("account", n, 0)) - .collect::>(); + Ok(()) + } + + #[benchmark(pov_mode = Measured)] + fn seal_code_hash(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { + let accounts = (0..r).map(|n| account::("account", n, 0)).collect::>(); let account_len = accounts.get(0).map(|i| i.encode().len()).unwrap_or(0); let accounts_bytes = accounts.iter().flat_map(|a| a.encode()).collect::>(); - let accounts_len = accounts_bytes.len(); - let pages = code::max_pages::(); let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -603,19 +662,19 @@ benchmarks! { offset: 0, value: 32u32.to_le_bytes().to_vec(), // output length }, - DataSegment { - offset: 36, - value: accounts_bytes, - }, + DataSegment { offset: 36, value: accounts_bytes }, ], - call_body: Some(body::repeated_dyn(r, vec![ - Counter(36, account_len as u32), // address_ptr - Regular(Instruction::I32Const(4)), // ptr to output data - Regular(Instruction::I32Const(0)), // ptr to output length - Regular(Instruction::Call(0)), - Regular(Instruction::Drop), - ])), - .. Default::default() + call_body: Some(body::repeated_dyn( + r, + vec![ + Counter(36, account_len as u32), // address_ptr + Regular(Instruction::I32Const(4)), // ptr to output data + Regular(Instruction::I32Const(0)), // ptr to output length + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ], + )), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let info = instance.info()?; @@ -624,20 +683,23 @@ benchmarks! { >::insert(acc, info.clone()); } let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - - #[pov_mode = Measured] - seal_own_code_hash { - let r in 0 .. API_BENCHMARK_RUNS; - let instance = Contract::::new(WasmModule::getter( - "seal0", "seal_own_code_hash", r - ), vec![])?; + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } + + #[benchmark(pov_mode = Measured)] + fn seal_own_code_hash(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { + let instance = + Contract::::new(WasmModule::getter("seal0", "seal_own_code_hash", r), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } - #[pov_mode = Measured] - seal_caller_is_origin { - let r in 0 .. API_BENCHMARK_RUNS; + #[benchmark(pov_mode = Measured)] + fn seal_caller_is_origin(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -646,20 +708,18 @@ benchmarks! { params: vec![], return_type: Some(ValueType::I32), }], - call_body: Some(body::repeated(r, &[ - Instruction::Call(0), - Instruction::Drop, - ])), - .. Default::default() + call_body: Some(body::repeated(r, &[Instruction::Call(0), Instruction::Drop])), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - - #[pov_mode = Measured] - seal_caller_is_root { - let r in 0 .. API_BENCHMARK_RUNS; + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } + #[benchmark(pov_mode = Measured)] + fn seal_caller_is_root(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -668,82 +728,84 @@ benchmarks! { params: vec![], return_type: Some(ValueType::I32), }], - call_body: Some(body::repeated(r, &[ - Instruction::Call(0), - Instruction::Drop, - ])), - .. Default::default() + call_body: Some(body::repeated(r, &[Instruction::Call(0), Instruction::Drop])), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Root; - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - - #[pov_mode = Measured] - seal_address { - let r in 0 .. API_BENCHMARK_RUNS; - let instance = Contract::::new(WasmModule::getter( - "seal0", "seal_address", r - ), vec![])?; + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } + + #[benchmark(pov_mode = Measured)] + fn seal_address(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { + let instance = Contract::::new(WasmModule::getter("seal0", "seal_address", r), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - - #[pov_mode = Measured] - seal_gas_left { - let r in 0 .. API_BENCHMARK_RUNS; - let instance = Contract::::new(WasmModule::getter( - "seal1", "gas_left", r - ), vec![])?; + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } + + #[benchmark(pov_mode = Measured)] + fn seal_gas_left(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { + let instance = Contract::::new(WasmModule::getter("seal1", "gas_left", r), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - - #[pov_mode = Measured] - seal_balance { - let r in 0 .. API_BENCHMARK_RUNS; - let instance = Contract::::new(WasmModule::getter( - "seal0", "seal_balance", r - ), vec![])?; + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } + + #[benchmark(pov_mode = Measured)] + fn seal_balance(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { + let instance = Contract::::new(WasmModule::getter("seal0", "seal_balance", r), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - - #[pov_mode = Measured] - seal_value_transferred { - let r in 0 .. API_BENCHMARK_RUNS; - let instance = Contract::::new(WasmModule::getter( - "seal0", "seal_value_transferred", r - ), vec![])?; + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } + + #[benchmark(pov_mode = Measured)] + fn seal_value_transferred(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { + let instance = + Contract::::new(WasmModule::getter("seal0", "seal_value_transferred", r), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - - #[pov_mode = Measured] - seal_minimum_balance { - let r in 0 .. API_BENCHMARK_RUNS; - let instance = Contract::::new(WasmModule::getter( - "seal0", "seal_minimum_balance", r - ), vec![])?; + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } + + #[benchmark(pov_mode = Measured)] + fn seal_minimum_balance(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { + let instance = + Contract::::new(WasmModule::getter("seal0", "seal_minimum_balance", r), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - - #[pov_mode = Measured] - seal_block_number { - let r in 0 .. API_BENCHMARK_RUNS; - let instance = Contract::::new(WasmModule::getter( - "seal0", "seal_block_number", r - ), vec![])?; + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } + + #[benchmark(pov_mode = Measured)] + fn seal_block_number(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { + let instance = + Contract::::new(WasmModule::getter("seal0", "seal_block_number", r), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - - #[pov_mode = Measured] - seal_now { - let r in 0 .. API_BENCHMARK_RUNS; - let instance = Contract::::new(WasmModule::getter( - "seal0", "seal_now", r - ), vec![])?; + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } + + #[benchmark(pov_mode = Measured)] + fn seal_now(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { + let instance = Contract::::new(WasmModule::getter("seal0", "seal_now", r), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } - #[pov_mode = Measured] - seal_weight_to_fee { - let r in 0 .. API_BENCHMARK_RUNS; + #[benchmark(pov_mode = Measured)] + fn seal_weight_to_fee(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { let pages = code::max_pages::(); let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), @@ -757,22 +819,27 @@ benchmarks! { offset: 0, value: (pages * 64 * 1024 - 4).to_le_bytes().to_vec(), }], - call_body: Some(body::repeated(r, &[ - Instruction::I64Const(500_000), - Instruction::I64Const(300_000), - Instruction::I32Const(4), - Instruction::I32Const(0), - Instruction::Call(0), - ])), - .. Default::default() + call_body: Some(body::repeated( + r, + &[ + Instruction::I64Const(500_000), + Instruction::I64Const(300_000), + Instruction::I32Const(4), + Instruction::I32Const(0), + Instruction::Call(0), + ], + )), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } - #[pov_mode = Measured] - seal_input { - let r in 0 .. API_BENCHMARK_RUNS; + #[benchmark(pov_mode = Measured)] + fn seal_input(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -781,26 +848,28 @@ benchmarks! { params: vec![ValueType::I32, ValueType::I32], return_type: None, }], - data_segments: vec![ - DataSegment { - offset: 0, - value: 0u32.to_le_bytes().to_vec(), - }, - ], - call_body: Some(body::repeated(r, &[ - Instruction::I32Const(4), // ptr where to store output - Instruction::I32Const(0), // ptr to length - Instruction::Call(0), - ])), - .. Default::default() + data_segments: vec![DataSegment { offset: 0, value: 0u32.to_le_bytes().to_vec() }], + call_body: Some(body::repeated( + r, + &[ + Instruction::I32Const(4), // ptr where to store output + Instruction::I32Const(0), // ptr to length + Instruction::Call(0), + ], + )), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } - #[pov_mode = Measured] - seal_input_per_byte { - let n in 0 .. code::max_pages::() * 64 * 1024; + #[benchmark(pov_mode = Measured)] + fn seal_input_per_byte( + n: Linear<0, { code::max_pages::() * 64 * 1024 }>, + ) -> Result<(), BenchmarkError> { let buffer_size = code::max_pages::() * 64 * 1024 - 4; let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), @@ -810,31 +879,31 @@ benchmarks! { params: vec![ValueType::I32, ValueType::I32], return_type: None, }], - data_segments: vec![ - DataSegment { - offset: 0, - value: buffer_size.to_le_bytes().to_vec(), - }, - ], + data_segments: vec![DataSegment { + offset: 0, + value: buffer_size.to_le_bytes().to_vec(), + }], call_body: Some(body::plain(vec![ Instruction::I32Const(4), // ptr where to store output Instruction::I32Const(0), // ptr to length Instruction::Call(0), Instruction::End, ])), - .. Default::default() + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let data = vec![42u8; n.min(buffer_size) as usize]; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, data) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, data); + Ok(()) + } // We cannot call `seal_return` multiple times. Therefore our weight determination is not // as precise as with other APIs. Because this function can only be called once per // contract it cannot be used as an attack vector. - #[pov_mode = Measured] - seal_return { - let r in 0 .. 1; + #[benchmark(pov_mode = Measured)] + fn seal_return(r: Linear<0, 1>) -> Result<(), BenchmarkError> { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -843,21 +912,28 @@ benchmarks! { params: vec![ValueType::I32, ValueType::I32, ValueType::I32], return_type: None, }], - call_body: Some(body::repeated(r, &[ - Instruction::I32Const(0), // flags - Instruction::I32Const(0), // data_ptr - Instruction::I32Const(0), // data_len - Instruction::Call(0), - ])), - .. Default::default() + call_body: Some(body::repeated( + r, + &[ + Instruction::I32Const(0), // flags + Instruction::I32Const(0), // data_ptr + Instruction::I32Const(0), // data_len + Instruction::Call(0), + ], + )), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } - #[pov_mode = Measured] - seal_return_per_byte { - let n in 0 .. code::max_pages::() * 64 * 1024; + #[benchmark(pov_mode = Measured)] + fn seal_return_per_byte( + n: Linear<0, { code::max_pages::() * 64 * 1024 }>, + ) -> Result<(), BenchmarkError> { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -867,22 +943,24 @@ benchmarks! { return_type: None, }], call_body: Some(body::plain(vec![ - Instruction::I32Const(0), // flags - Instruction::I32Const(0), // data_ptr + Instruction::I32Const(0), // flags + Instruction::I32Const(0), // data_ptr Instruction::I32Const(n as i32), // data_len Instruction::Call(0), Instruction::End, ])), - .. Default::default() + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } // The same argument as for `seal_return` is true here. - #[pov_mode = Measured] - seal_terminate { - let r in 0 .. 1; + #[benchmark(pov_mode = Measured)] + fn seal_terminate(r: Linear<0, 1>) -> Result<(), BenchmarkError> { let beneficiary = account::("beneficiary", 0, 0); let beneficiary_bytes = beneficiary.encode(); let beneficiary_len = beneficiary_bytes.len(); @@ -915,50 +993,74 @@ benchmarks! { name: "lock_delegate_dependency", params: vec![ValueType::I32], return_type: None, - } + }, ], data_segments: vec![ - DataSegment { - offset: 0, - value: beneficiary_bytes, - }, - DataSegment { - offset: beneficiary_len as u32, - value: code_hashes_bytes, - }, + DataSegment { offset: 0, value: beneficiary_bytes }, + DataSegment { offset: beneficiary_len as u32, value: code_hashes_bytes }, ], - deploy_body: Some(body::repeated_dyn(T::MaxDelegateDependencies::get(), vec![ - Counter(beneficiary_len as u32, code_hash_len as u32), // code_hash_ptr - Regular(Instruction::Call(1)), - ])), - call_body: Some(body::repeated(r, &[ - Instruction::I32Const(0), // beneficiary_ptr - Instruction::I32Const(beneficiary_len as i32), // beneficiary_len - Instruction::Call(0), - ])), - .. Default::default() + deploy_body: Some(body::repeated_dyn( + T::MaxDelegateDependencies::get(), + vec![ + Counter(beneficiary_len as u32, code_hash_len as u32), // code_hash_ptr + Regular(Instruction::Call(1)), + ], + )), + call_body: Some(body::repeated( + r, + &[ + Instruction::I32Const(0), // beneficiary_ptr + Instruction::I32Const(beneficiary_len as i32), // beneficiary_len + Instruction::Call(0), + ], + )), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); assert_eq!(T::Currency::total_balance(&beneficiary), 0u32.into()); - assert_eq!(T::Currency::balance(&instance.account_id), Pallet::::min_balance() * 2u32.into()); - assert_ne!(T::Currency::balance_on_hold(&HoldReason::StorageDepositReserve.into(), &instance.account_id), 0u32.into()); - assert_eq!(ContractInfoOf::::get(&instance.account_id).unwrap().delegate_dependencies_count() as u32, T::MaxDelegateDependencies::get()); - }: call(origin, instance.addr.clone(), 0u32.into(), Weight::MAX, None, vec![]) - verify { + assert_eq!( + T::Currency::balance(&instance.account_id), + Pallet::::min_balance() * 2u32.into() + ); + assert_ne!( + T::Currency::balance_on_hold( + &HoldReason::StorageDepositReserve.into(), + &instance.account_id + ), + 0u32.into() + ); + assert_eq!( + ContractInfoOf::::get(&instance.account_id) + .unwrap() + .delegate_dependencies_count() as u32, + T::MaxDelegateDependencies::get() + ); + #[extrinsic_call] + call(origin, instance.addr.clone(), 0u32.into(), Weight::MAX, None, vec![]); + if r > 0 { assert_eq!(T::Currency::total_balance(&instance.account_id), 0u32.into()); - assert_eq!(T::Currency::balance_on_hold(&HoldReason::StorageDepositReserve.into(), &instance.account_id), 0u32.into()); - assert_eq!(T::Currency::total_balance(&beneficiary), Pallet::::min_balance() * 2u32.into()); + assert_eq!( + T::Currency::balance_on_hold( + &HoldReason::StorageDepositReserve.into(), + &instance.account_id + ), + 0u32.into() + ); + assert_eq!( + T::Currency::total_balance(&beneficiary), + Pallet::::min_balance() * 2u32.into() + ); } + Ok(()) } // We benchmark only for the maximum subject length. We assume that this is some lowish // number (< 1 KB). Therefore we are not overcharging too much in case a smaller subject is // used. - #[pov_mode = Measured] - seal_random { - let r in 0 .. API_BENCHMARK_RUNS; + #[benchmark(pov_mode = Measured)] + fn seal_random(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { let pages = code::max_pages::(); let subject_len = T::Schedule::get().limits.subject_len; assert!(subject_len < 1024); @@ -970,30 +1072,33 @@ benchmarks! { params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: None, }], - data_segments: vec![ - DataSegment { - offset: 0, - value: (pages * 64 * 1024 - subject_len - 4).to_le_bytes().to_vec(), - }, - ], - call_body: Some(body::repeated(r, &[ - Instruction::I32Const(4), // subject_ptr - Instruction::I32Const(subject_len as i32), // subject_len - Instruction::I32Const((subject_len + 4) as i32), // out_ptr - Instruction::I32Const(0), // out_len_ptr - Instruction::Call(0), - ])), - .. Default::default() + data_segments: vec![DataSegment { + offset: 0, + value: (pages * 64 * 1024 - subject_len - 4).to_le_bytes().to_vec(), + }], + call_body: Some(body::repeated( + r, + &[ + Instruction::I32Const(4), // subject_ptr + Instruction::I32Const(subject_len as i32), // subject_len + Instruction::I32Const((subject_len + 4) as i32), // out_ptr + Instruction::I32Const(0), // out_len_ptr + Instruction::Call(0), + ], + )), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } // Overhead of calling the function without any topic. // We benchmark for the worst case (largest event). - #[pov_mode = Measured] - seal_deposit_event { - let r in 0 .. API_BENCHMARK_RUNS; + #[benchmark(pov_mode = Measured)] + fn seal_deposit_event(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -1002,26 +1107,33 @@ benchmarks! { params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: None, }], - call_body: Some(body::repeated(r, &[ - Instruction::I32Const(0), // topics_ptr - Instruction::I32Const(0), // topics_len - Instruction::I32Const(0), // data_ptr - Instruction::I32Const(0), // data_len - Instruction::Call(0), - ])), - .. Default::default() + call_body: Some(body::repeated( + r, + &[ + Instruction::I32Const(0), // topics_ptr + Instruction::I32Const(0), // topics_len + Instruction::I32Const(0), // data_ptr + Instruction::I32Const(0), // data_len + Instruction::Call(0), + ], + )), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } // Benchmark the overhead that topics generate. // `t`: Number of topics // `n`: Size of event payload in bytes - #[pov_mode = Measured] - seal_deposit_event_per_topic_and_byte { - let t in 0 .. T::Schedule::get().limits.event_topics; - let n in 0 .. T::Schedule::get().limits.payload_len; + #[benchmark(pov_mode = Measured)] + fn seal_deposit_event_per_topic_and_byte( + t: Linear<0, { T::Schedule::get().limits.event_topics }>, + n: Linear<0, { T::Schedule::get().limits.payload_len }>, + ) -> Result<(), BenchmarkError> { let topics = (0..t).map(|i| T::Hashing::hash_of(&i)).collect::>().encode(); let topics_len = topics.len(); let code = WasmModule::::from(ModuleDefinition { @@ -1032,32 +1144,29 @@ benchmarks! { params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: None, }], - data_segments: vec![ - DataSegment { - offset: 0, - value: topics, - }, - ], + data_segments: vec![DataSegment { offset: 0, value: topics }], call_body: Some(body::plain(vec![ - Instruction::I32Const(0), // topics_ptr + Instruction::I32Const(0), // topics_ptr Instruction::I32Const(topics_len as i32), // topics_len - Instruction::I32Const(0), // data_ptr - Instruction::I32Const(n as i32), // data_len + Instruction::I32Const(0), // data_ptr + Instruction::I32Const(n as i32), // data_len Instruction::Call(0), Instruction::End, ])), - .. Default::default() + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } // Benchmark debug_message call with zero input data. // Whereas this function is used in RPC mode only, it still should be secured // against an excessive use. - #[pov_mode = Measured] - seal_debug_message { - let r in 0 .. API_BENCHMARK_RUNS; + #[benchmark(pov_mode = Measured)] + fn seal_debug_message(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory { min_pages: 1, max_pages: 1 }), imported_functions: vec![ImportedFunction { @@ -1066,38 +1175,56 @@ benchmarks! { params: vec![ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], - call_body: Some(body::repeated(r, &[ - Instruction::I32Const(0), // value_ptr - Instruction::I32Const(0), // value_len - Instruction::Call(0), - Instruction::Drop, - ])), - .. Default::default() + call_body: Some(body::repeated( + r, + &[ + Instruction::I32Const(0), // value_ptr + Instruction::I32Const(0), // value_len + Instruction::Call(0), + Instruction::Drop, + ], + )), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; - }: { - >::bare_call( - instance.caller, - instance.account_id, - 0u32.into(), - Weight::MAX, - None, - vec![], - DebugInfo::UnsafeDebug, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result?; + + #[block] + { + >::bare_call( + instance.caller, + instance.account_id, + 0u32.into(), + Weight::MAX, + None, + vec![], + DebugInfo::UnsafeDebug, + CollectEvents::Skip, + Determinism::Enforced, + ) + .result?; + } + Ok(()) } - seal_debug_message_per_byte { - // Vary size of input in bytes up to maximum allowed contract memory - // or maximum allowed debug buffer size, whichever is less. - let i in 0 .. (T::Schedule::get().limits.memory_pages * 64 * 1024).min(T::MaxDebugBufferLen::get()); + // Vary size of input in bytes up to maximum allowed contract memory + // or maximum allowed debug buffer size, whichever is less. + #[benchmark] + fn seal_debug_message_per_byte( + i: Linear< + 0, + { + (T::Schedule::get().limits.memory_pages * 64 * 1024) + .min(T::MaxDebugBufferLen::get()) + }, + >, + ) -> Result<(), BenchmarkError> { // We benchmark versus messages containing printable ASCII codes. // About 1Kb goes to the contract code instructions, // whereas all the space left we use for the initialization of the debug messages data. - let message = (0 .. T::MaxCodeLen::get() - 1024).zip((32..127).cycle()).map(|i| i.1).collect::>(); + let message = (0..T::MaxCodeLen::get() - 1024) + .zip((32..127).cycle()) + .map(|i| i.1) + .collect::>(); let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory { min_pages: T::Schedule::get().limits.memory_pages, @@ -1108,15 +1235,10 @@ benchmarks! { name: "seal_debug_message", params: vec![ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), - }], - data_segments: vec![ - DataSegment { - offset: 0, - value: message, - }, - ], + }], + data_segments: vec![DataSegment { offset: 0, value: message }], call_body: Some(body::plain(vec![ - Instruction::I32Const(0), // value_ptr + Instruction::I32Const(0), // value_ptr Instruction::I32Const(i as i32), // value_len Instruction::Call(0), Instruction::Drop, @@ -1125,22 +1247,25 @@ benchmarks! { ..Default::default() }); let instance = Contract::::new(code, vec![])?; - }: { - >::bare_call( - instance.caller, - instance.account_id, - 0u32.into(), - Weight::MAX, - None, - vec![], - DebugInfo::UnsafeDebug, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result?; - } - - // Only the overhead of calling the function itself with minimal arguments. + #[block] + { + >::bare_call( + instance.caller, + instance.account_id, + 0u32.into(), + Weight::MAX, + None, + vec![], + DebugInfo::UnsafeDebug, + CollectEvents::Skip, + Determinism::Enforced, + ) + .result?; + } + Ok(()) + } + + // Only the overhead of calling the function itself with minimal arguments. // The contract is a bit more complex because it needs to use different keys in order // to generate unique storage accesses. However, it is still dominated by the storage // accesses. We store something at all the keys that we are about to write to @@ -1151,15 +1276,16 @@ benchmarks! { // // We need to use a smaller `r` because the keys are big and writing them all into the wasm // might exceed the code size. - #[skip_meta] - #[pov_mode = Measured] - seal_set_storage { - let r in 0 .. API_BENCHMARK_RUNS/2; + #[benchmark(skip_meta, pov_mode = Measured)] + fn seal_set_storage(r: Linear<0, { API_BENCHMARK_RUNS / 2 }>) -> Result<(), BenchmarkError> { let max_key_len = T::MaxStorageKeyLen::get(); - let keys = (0 .. r) - .map(|n| { let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); - h.resize(max_key_len.try_into().unwrap(), n.to_le_bytes()[0]); h }) - .collect::>(); + let keys = (0..r) + .map(|n| { + let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); + h.resize(max_key_len.try_into().unwrap(), n.to_le_bytes()[0]); + h + }) + .collect::>(); let keys_bytes = keys.iter().flatten().cloned().collect::>(); let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), @@ -1169,27 +1295,25 @@ benchmarks! { params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], - data_segments: vec![ - DataSegment { - offset: 0, - value: keys_bytes, - }, - ], - call_body: Some(body::repeated_dyn(r, vec![ - Counter(0, max_key_len as u32), // key_ptr - Regular(Instruction::I32Const(max_key_len as i32)), // key_len - Regular(Instruction::I32Const(0)), // value_ptr - Regular(Instruction::I32Const(0)), // value_len - Regular(Instruction::Call(0)), - Regular(Instruction::Drop), - ])), - .. Default::default() + data_segments: vec![DataSegment { offset: 0, value: keys_bytes }], + call_body: Some(body::repeated_dyn( + r, + vec![ + Counter(0, max_key_len as u32), // key_ptr + Regular(Instruction::I32Const(max_key_len as i32)), // key_len + Regular(Instruction::I32Const(0)), // value_ptr + Regular(Instruction::I32Const(0)), // value_len + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ], + )), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let info = instance.info()?; for key in keys { info.write( - &Key::::try_from_var(key).map_err(|e| "Key has wrong length")?, + &Key::::try_from_var(key).map_err(|_| "Key has wrong length")?, Some(vec![]), None, false, @@ -1197,12 +1321,15 @@ benchmarks! { .map_err(|_| "Failed to write to storage during setup.")?; } let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } - #[skip_meta] - #[pov_mode = Measured] - seal_set_storage_per_new_byte { - let n in 0 .. T::Schedule::get().limits.payload_len; + #[benchmark(skip_meta, pov_mode = Measured)] + fn seal_set_storage_per_new_byte( + n: Linear<0, { T::Schedule::get().limits.payload_len }>, + ) -> Result<(), BenchmarkError> { let max_key_len = T::MaxStorageKeyLen::get(); let key = vec![0u8; max_key_len as usize]; let code = WasmModule::::from(ModuleDefinition { @@ -1213,39 +1340,37 @@ benchmarks! { params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], - data_segments: vec![ - DataSegment { - offset: 0, - value: key.clone(), - }, - ], + data_segments: vec![DataSegment { offset: 0, value: key.clone() }], call_body: Some(body::plain(vec![ - Instruction::I32Const(0), // key_ptr + Instruction::I32Const(0), // key_ptr Instruction::I32Const(max_key_len as i32), // key_len - Instruction::I32Const(0), // value_ptr - Instruction::I32Const(n as i32), // value_len + Instruction::I32Const(0), // value_ptr + Instruction::I32Const(n as i32), // value_len Instruction::Call(0), Instruction::Drop, Instruction::End, ])), - .. Default::default() + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let info = instance.info()?; info.write( - &Key::::try_from_var(key).map_err(|e| "Key has wrong length")?, + &Key::::try_from_var(key).map_err(|_| "Key has wrong length")?, Some(vec![]), None, false, ) .map_err(|_| "Failed to write to storage during setup.")?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } - #[skip_meta] - #[pov_mode = Measured] - seal_set_storage_per_old_byte { - let n in 0 .. T::Schedule::get().limits.payload_len; + #[benchmark(skip_meta, pov_mode = Measured)] + fn seal_set_storage_per_old_byte( + n: Linear<0, { T::Schedule::get().limits.payload_len }>, + ) -> Result<(), BenchmarkError> { let max_key_len = T::MaxStorageKeyLen::get(); let key = vec![0u8; max_key_len as usize]; let code = WasmModule::::from(ModuleDefinition { @@ -1256,48 +1381,48 @@ benchmarks! { params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], - data_segments: vec![ - DataSegment { - offset: 0, - value: key.clone(), - }, - ], + data_segments: vec![DataSegment { offset: 0, value: key.clone() }], call_body: Some(body::plain(vec![ - Instruction::I32Const(0), // key_ptr + Instruction::I32Const(0), // key_ptr Instruction::I32Const(max_key_len as i32), // key_len - Instruction::I32Const(0), // value_ptr - Instruction::I32Const(0), // value_len is 0 as testing vs pre-existing value len + Instruction::I32Const(0), // value_ptr + Instruction::I32Const(0), /* value_len is 0 as testing vs + * pre-existing value len */ Instruction::Call(0), Instruction::Drop, Instruction::End, ])), - .. Default::default() + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let info = instance.info()?; info.write( - &Key::::try_from_var(key).map_err(|e| "Key has wrong length")?, + &Key::::try_from_var(key).map_err(|_| "Key has wrong length")?, Some(vec![42u8; n as usize]), None, false, ) .map_err(|_| "Failed to write to storage during setup.")?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } // Similar to seal_set_storage. We store all the keys that we are about to // delete beforehand in order to prevent any optimizations that could occur when // deleting a non existing key. We generate keys of a maximum length, and have to // the amount of runs in order to make resulting contract code size less than MaxCodeLen. - #[skip_meta] - #[pov_mode = Measured] - seal_clear_storage { - let r in 0 .. API_BENCHMARK_RUNS/2; + #[benchmark(skip_meta, pov_mode = Measured)] + fn seal_clear_storage(r: Linear<0, { API_BENCHMARK_RUNS / 2 }>) -> Result<(), BenchmarkError> { let max_key_len = T::MaxStorageKeyLen::get(); - let keys = (0 .. r) - .map(|n| { let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); - h.resize(max_key_len.try_into().unwrap(), n.to_le_bytes()[0]); h }) - .collect::>(); + let keys = (0..r) + .map(|n| { + let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); + h.resize(max_key_len.try_into().unwrap(), n.to_le_bytes()[0]); + h + }) + .collect::>(); let key_bytes = keys.iter().flatten().cloned().collect::>(); let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), @@ -1307,25 +1432,23 @@ benchmarks! { params: vec![ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], - data_segments: vec![ - DataSegment { - offset: 0, - value: key_bytes, - }, - ], - call_body: Some(body::repeated_dyn(r, vec![ - Counter(0, max_key_len as u32), // key_ptr - Regular(Instruction::I32Const(max_key_len as i32)), // key_len - Regular(Instruction::Call(0)), - Regular(Instruction::Drop), - ])), - .. Default::default() + data_segments: vec![DataSegment { offset: 0, value: key_bytes }], + call_body: Some(body::repeated_dyn( + r, + vec![ + Counter(0, max_key_len as u32), // key_ptr + Regular(Instruction::I32Const(max_key_len as i32)), // key_len + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ], + )), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let info = instance.info()?; for key in keys { info.write( - &Key::::try_from_var(key).map_err(|e| "Key has wrong length")?, + &Key::::try_from_var(key).map_err(|_| "Key has wrong length")?, Some(vec![]), None, false, @@ -1334,12 +1457,15 @@ benchmarks! { } >::insert(&instance.account_id, info); let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } - #[skip_meta] - #[pov_mode = Measured] - seal_clear_storage_per_byte { - let n in 0 .. T::Schedule::get().limits.payload_len; + #[benchmark(skip_meta, pov_mode = Measured)] + fn seal_clear_storage_per_byte( + n: Linear<0, { T::Schedule::get().limits.payload_len }>, + ) -> Result<(), BenchmarkError> { let max_key_len = T::MaxStorageKeyLen::get(); let key = vec![0u8; max_key_len as usize]; let code = WasmModule::::from(ModuleDefinition { @@ -1350,43 +1476,42 @@ benchmarks! { params: vec![ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], - data_segments: vec![ - DataSegment { - offset: 0, - value: key.clone(), - }, - ], + data_segments: vec![DataSegment { offset: 0, value: key.clone() }], call_body: Some(body::plain(vec![ - Instruction::I32Const(0), // key_ptr + Instruction::I32Const(0), // key_ptr Instruction::I32Const(max_key_len as i32), // key_len Instruction::Call(0), Instruction::Drop, Instruction::End, ])), - .. Default::default() + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let info = instance.info()?; info.write( - &Key::::try_from_var(key).map_err(|e| "Key has wrong length")?, + &Key::::try_from_var(key).map_err(|_| "Key has wrong length")?, Some(vec![42u8; n as usize]), None, false, ) .map_err(|_| "Failed to write to storage during setup.")?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } // We make sure that all storage accesses are to unique keys. - #[skip_meta] - #[pov_mode = Measured] - seal_get_storage { - let r in 0 .. API_BENCHMARK_RUNS/2; + #[benchmark(skip_meta, pov_mode = Measured)] + fn seal_get_storage(r: Linear<0, { API_BENCHMARK_RUNS / 2 }>) -> Result<(), BenchmarkError> { let max_key_len = T::MaxStorageKeyLen::get(); - let keys = (0 .. r) - .map(|n| { let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); - h.resize(max_key_len.try_into().unwrap(), n.to_le_bytes()[0]); h }) - .collect::>(); + let keys = (0..r) + .map(|n| { + let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); + h.resize(max_key_len.try_into().unwrap(), n.to_le_bytes()[0]); + h + }) + .collect::>(); let key_bytes = keys.iter().flatten().cloned().collect::>(); let key_bytes_len = key_bytes.len(); let code = WasmModule::::from(ModuleDefinition { @@ -1398,30 +1523,30 @@ benchmarks! { return_type: Some(ValueType::I32), }], data_segments: vec![ - DataSegment { - offset: 0, - value: key_bytes, - }, + DataSegment { offset: 0, value: key_bytes }, DataSegment { offset: key_bytes_len as u32, value: T::Schedule::get().limits.payload_len.to_le_bytes().into(), }, ], - call_body: Some(body::repeated_dyn(r, vec![ - Counter(0, max_key_len), // key_ptr - Regular(Instruction::I32Const(max_key_len as i32)), // key_len - Regular(Instruction::I32Const((key_bytes_len + 4) as i32)), // out_ptr - Regular(Instruction::I32Const(key_bytes_len as i32)), // out_len_ptr - Regular(Instruction::Call(0)), - Regular(Instruction::Drop), - ])), - .. Default::default() + call_body: Some(body::repeated_dyn( + r, + vec![ + Counter(0, max_key_len), // key_ptr + Regular(Instruction::I32Const(max_key_len as i32)), // key_len + Regular(Instruction::I32Const((key_bytes_len + 4) as i32)), // out_ptr + Regular(Instruction::I32Const(key_bytes_len as i32)), // out_len_ptr + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ], + )), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let info = instance.info()?; for key in keys { info.write( - &Key::::try_from_var(key).map_err(|e| "Key has wrong length")?, + &Key::::try_from_var(key).map_err(|_| "Key has wrong length")?, Some(vec![]), None, false, @@ -1430,12 +1555,15 @@ benchmarks! { } >::insert(&instance.account_id, info); let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } - #[skip_meta] - #[pov_mode = Measured] - seal_get_storage_per_byte { - let n in 0 .. T::Schedule::get().limits.payload_len; + #[benchmark(skip_meta, pov_mode = Measured)] + fn seal_get_storage_per_byte( + n: Linear<0, { T::Schedule::get().limits.payload_len }>, + ) -> Result<(), BenchmarkError> { let max_key_len = T::MaxStorageKeyLen::get(); let key = vec![0u8; max_key_len as usize]; let code = WasmModule::::from(ModuleDefinition { @@ -1447,30 +1575,27 @@ benchmarks! { return_type: Some(ValueType::I32), }], data_segments: vec![ - DataSegment { - offset: 0, - value: key.clone(), - }, + DataSegment { offset: 0, value: key.clone() }, DataSegment { offset: max_key_len, value: T::Schedule::get().limits.payload_len.to_le_bytes().into(), }, ], call_body: Some(body::plain(vec![ - Instruction::I32Const(0), // key_ptr - Instruction::I32Const(max_key_len as i32), // key_len + Instruction::I32Const(0), // key_ptr + Instruction::I32Const(max_key_len as i32), // key_len Instruction::I32Const((max_key_len + 4) as i32), // out_ptr - Instruction::I32Const(max_key_len as i32), // out_len_ptr + Instruction::I32Const(max_key_len as i32), // out_len_ptr Instruction::Call(0), Instruction::Drop, Instruction::End, ])), - .. Default::default() + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let info = instance.info()?; info.write( - &Key::::try_from_var(key).map_err(|e| "Key has wrong length")?, + &Key::::try_from_var(key).map_err(|_| "Key has wrong length")?, Some(vec![42u8; n as usize]), None, false, @@ -1478,20 +1603,25 @@ benchmarks! { .map_err(|_| "Failed to write to storage during setup.")?; >::insert(&instance.account_id, info); let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } // We make sure that all storage accesses are to unique keys. - #[skip_meta] - #[pov_mode = Measured] - seal_contains_storage { - let r in 0 .. API_BENCHMARK_RUNS/2; + #[benchmark(skip_meta, pov_mode = Measured)] + fn seal_contains_storage( + r: Linear<0, { API_BENCHMARK_RUNS / 2 }>, + ) -> Result<(), BenchmarkError> { let max_key_len = T::MaxStorageKeyLen::get(); - let keys = (0 .. r) - .map(|n| { let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); - h.resize(max_key_len.try_into().unwrap(), n.to_le_bytes()[0]); h }) - .collect::>(); + let keys = (0..r) + .map(|n| { + let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); + h.resize(max_key_len.try_into().unwrap(), n.to_le_bytes()[0]); + h + }) + .collect::>(); let key_bytes = keys.iter().flatten().cloned().collect::>(); - let key_bytes_len = key_bytes.len(); let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -1500,25 +1630,23 @@ benchmarks! { params: vec![ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], - data_segments: vec![ - DataSegment { - offset: 0, - value: key_bytes, - }, - ], - call_body: Some(body::repeated_dyn(r, vec![ - Counter(0, max_key_len as u32), // key_ptr - Regular(Instruction::I32Const(max_key_len as i32)), // key_len - Regular(Instruction::Call(0)), - Regular(Instruction::Drop), - ])), - .. Default::default() + data_segments: vec![DataSegment { offset: 0, value: key_bytes }], + call_body: Some(body::repeated_dyn( + r, + vec![ + Counter(0, max_key_len as u32), // key_ptr + Regular(Instruction::I32Const(max_key_len as i32)), // key_len + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ], + )), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let info = instance.info()?; for key in keys { info.write( - &Key::::try_from_var(key).map_err(|e| "Key has wrong length")?, + &Key::::try_from_var(key).map_err(|_| "Key has wrong length")?, Some(vec![]), None, false, @@ -1527,12 +1655,15 @@ benchmarks! { } >::insert(&instance.account_id, info); let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } - #[skip_meta] - #[pov_mode = Measured] - seal_contains_storage_per_byte { - let n in 0 .. T::Schedule::get().limits.payload_len; + #[benchmark(skip_meta, pov_mode = Measured)] + fn seal_contains_storage_per_byte( + n: Linear<0, { T::Schedule::get().limits.payload_len }>, + ) -> Result<(), BenchmarkError> { let max_key_len = T::MaxStorageKeyLen::get(); let key = vec![0u8; max_key_len as usize]; let code = WasmModule::::from(ModuleDefinition { @@ -1543,25 +1674,20 @@ benchmarks! { params: vec![ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], - data_segments: vec![ - DataSegment { - offset: 0, - value: key.clone(), - }, - ], + data_segments: vec![DataSegment { offset: 0, value: key.clone() }], call_body: Some(body::plain(vec![ - Instruction::I32Const(0), // key_ptr + Instruction::I32Const(0), // key_ptr Instruction::I32Const(max_key_len as i32), // key_len Instruction::Call(0), Instruction::Drop, Instruction::End, ])), - .. Default::default() + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let info = instance.info()?; info.write( - &Key::::try_from_var(key).map_err(|e| "Key has wrong length")?, + &Key::::try_from_var(key).map_err(|_| "Key has wrong length")?, Some(vec![42u8; n as usize]), None, false, @@ -1569,17 +1695,21 @@ benchmarks! { .map_err(|_| "Failed to write to storage during setup.")?; >::insert(&instance.account_id, info); let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } - #[skip_meta] - #[pov_mode = Measured] - seal_take_storage { - let r in 0 .. API_BENCHMARK_RUNS/2; + #[benchmark(skip_meta, pov_mode = Measured)] + fn seal_take_storage(r: Linear<0, { API_BENCHMARK_RUNS / 2 }>) -> Result<(), BenchmarkError> { let max_key_len = T::MaxStorageKeyLen::get(); - let keys = (0 .. r) - .map(|n| { let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); - h.resize(max_key_len.try_into().unwrap(), n.to_le_bytes()[0]); h }) - .collect::>(); + let keys = (0..r) + .map(|n| { + let mut h = T::Hashing::hash_of(&n).as_ref().to_vec(); + h.resize(max_key_len.try_into().unwrap(), n.to_le_bytes()[0]); + h + }) + .collect::>(); let key_bytes = keys.iter().flatten().cloned().collect::>(); let key_bytes_len = key_bytes.len(); let code = WasmModule::::from(ModuleDefinition { @@ -1591,30 +1721,30 @@ benchmarks! { return_type: Some(ValueType::I32), }], data_segments: vec![ - DataSegment { - offset: 0, - value: key_bytes, - }, + DataSegment { offset: 0, value: key_bytes }, DataSegment { offset: key_bytes_len as u32, value: T::Schedule::get().limits.payload_len.to_le_bytes().into(), }, ], - call_body: Some(body::repeated_dyn(r, vec![ - Counter(0, max_key_len as u32), // key_ptr - Regular(Instruction::I32Const(max_key_len as i32)), // key_len - Regular(Instruction::I32Const((key_bytes_len + 4) as i32)), // out_ptr - Regular(Instruction::I32Const(key_bytes_len as i32)), // out_len_ptr - Regular(Instruction::Call(0)), - Regular(Instruction::Drop), - ])), - .. Default::default() + call_body: Some(body::repeated_dyn( + r, + vec![ + Counter(0, max_key_len as u32), // key_ptr + Regular(Instruction::I32Const(max_key_len as i32)), // key_len + Regular(Instruction::I32Const((key_bytes_len + 4) as i32)), // out_ptr + Regular(Instruction::I32Const(key_bytes_len as i32)), // out_len_ptr + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ], + )), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let info = instance.info()?; for key in keys { info.write( - &Key::::try_from_var(key).map_err(|e| "Key has wrong length")?, + &Key::::try_from_var(key).map_err(|_| "Key has wrong length")?, Some(vec![]), None, false, @@ -1623,12 +1753,15 @@ benchmarks! { } >::insert(&instance.account_id, info); let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } - #[skip_meta] - #[pov_mode = Measured] - seal_take_storage_per_byte { - let n in 0 .. T::Schedule::get().limits.payload_len; + #[benchmark(skip_meta, pov_mode = Measured)] + fn seal_take_storage_per_byte( + n: Linear<0, { T::Schedule::get().limits.payload_len }>, + ) -> Result<(), BenchmarkError> { let max_key_len = T::MaxStorageKeyLen::get(); let key = vec![0u8; max_key_len as usize]; let code = WasmModule::::from(ModuleDefinition { @@ -1640,30 +1773,27 @@ benchmarks! { return_type: Some(ValueType::I32), }], data_segments: vec![ - DataSegment { - offset: 0, - value: key.clone(), - }, + DataSegment { offset: 0, value: key.clone() }, DataSegment { offset: max_key_len, value: T::Schedule::get().limits.payload_len.to_le_bytes().into(), }, ], call_body: Some(body::plain(vec![ - Instruction::I32Const(0), // key_ptr - Instruction::I32Const(max_key_len as i32), // key_len + Instruction::I32Const(0), // key_ptr + Instruction::I32Const(max_key_len as i32), // key_len Instruction::I32Const((max_key_len + 4) as i32), // out_ptr - Instruction::I32Const(max_key_len as i32), // out_len_ptr + Instruction::I32Const(max_key_len as i32), // out_len_ptr Instruction::Call(0), Instruction::Drop, Instruction::End, ])), - .. Default::default() + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let info = instance.info()?; info.write( - &Key::::try_from_var(key).map_err(|e| "Key has wrong length")?, + &Key::::try_from_var(key).map_err(|_| "Key has wrong length")?, Some(vec![42u8; n as usize]), None, false, @@ -1671,15 +1801,16 @@ benchmarks! { .map_err(|_| "Failed to write to storage during setup.")?; >::insert(&instance.account_id, info); let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } // We transfer to unique accounts. - #[pov_mode = Measured] - seal_transfer { - let r in 0 .. API_BENCHMARK_RUNS; - let accounts = (0..r) - .map(|i| account::("receiver", i, 0)) - .collect::>(); + #[benchmark(pov_mode = Measured)] + fn seal_transfer(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { + let accounts = + (0..r).map(|i| account::("receiver", i, 0)).collect::>(); let account_len = accounts.get(0).map(|i| i.encode().len()).unwrap_or(0); let account_bytes = accounts.iter().flat_map(|x| x.encode()).collect(); let value = Pallet::::min_balance(); @@ -1695,24 +1826,21 @@ benchmarks! { return_type: Some(ValueType::I32), }], data_segments: vec![ - DataSegment { - offset: 0, - value: value_bytes, - }, - DataSegment { - offset: value_len as u32, - value: account_bytes, - }, + DataSegment { offset: 0, value: value_bytes }, + DataSegment { offset: value_len as u32, value: account_bytes }, ], - call_body: Some(body::repeated_dyn(r, vec![ - Counter(value_len as u32, account_len as u32), // account_ptr - Regular(Instruction::I32Const(account_len as i32)), // account_len - Regular(Instruction::I32Const(0)), // value_ptr - Regular(Instruction::I32Const(value_len as i32)), // value_len - Regular(Instruction::Call(0)), - Regular(Instruction::Drop), - ])), - .. Default::default() + call_body: Some(body::repeated_dyn( + r, + vec![ + Counter(value_len as u32, account_len as u32), // account_ptr + Regular(Instruction::I32Const(account_len as i32)), // account_len + Regular(Instruction::I32Const(0)), // value_ptr + Regular(Instruction::I32Const(value_len as i32)), // value_len + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ], + )), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; instance.set_balance(value * (r + 1).into()); @@ -1720,19 +1848,20 @@ benchmarks! { for account in &accounts { assert_eq!(T::Currency::total_balance(account), 0u32.into()); } - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) - verify { + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + for account in &accounts { assert_eq!(T::Currency::total_balance(account), value); } + Ok(()) } // We call unique accounts. // // This is a slow call: We redeuce the number of runs. - #[pov_mode = Measured] - seal_call { - let r in 0 .. API_BENCHMARK_RUNS / 2; + #[benchmark(pov_mode = Measured)] + fn seal_call(r: Linear<0, { API_BENCHMARK_RUNS / 2 }>) -> Result<(), BenchmarkError> { let dummy_code = WasmModule::::dummy_with_bytes(0); let callees = (0..r) .map(|i| Contract::with_index(i + 1, dummy_code.clone(), vec![])) @@ -1745,7 +1874,7 @@ benchmarks! { // Set an own limit every 2nd call let own_limit = (u32::MAX - 100).into(); let deposits = (0..r) - .map(|i| if i % 2 == 0 { 0u32.into() } else { own_limit } ) + .map(|i| if i % 2 == 0 { 0u32.into() } else { own_limit }) .collect::>>(); let deposits_bytes: Vec = deposits.iter().flat_map(|i| i.encode()).collect(); let deposits_len = deposits_bytes.len() as u32; @@ -1771,43 +1900,46 @@ benchmarks! { return_type: Some(ValueType::I32), }], data_segments: vec![ - DataSegment { - offset: 0, - value: value_bytes, - }, - DataSegment { - offset: value_len, - value: deposits_bytes, - }, - DataSegment { - offset: callee_offset, - value: callee_bytes, - }, + DataSegment { offset: 0, value: value_bytes }, + DataSegment { offset: value_len, value: deposits_bytes }, + DataSegment { offset: callee_offset, value: callee_bytes }, ], - call_body: Some(body::repeated_dyn(r, vec![ - Regular(Instruction::I32Const(0)), // flags - Counter(callee_offset, callee_len as u32), // callee_ptr - Regular(Instruction::I64Const(0)), // ref_time weight - Regular(Instruction::I64Const(0)), // proof_size weight - Counter(value_len, deposit_len as u32), // deposit_limit_ptr - Regular(Instruction::I32Const(0)), // value_ptr - Regular(Instruction::I32Const(0)), // input_data_ptr - Regular(Instruction::I32Const(0)), // input_data_len - Regular(Instruction::I32Const(SENTINEL as i32)), // output_ptr - Regular(Instruction::I32Const(0)), // output_len_ptr - Regular(Instruction::Call(0)), - Regular(Instruction::Drop), - ])), - .. Default::default() + call_body: Some(body::repeated_dyn( + r, + vec![ + Regular(Instruction::I32Const(0)), // flags + Counter(callee_offset, callee_len as u32), // callee_ptr + Regular(Instruction::I64Const(0)), // ref_time weight + Regular(Instruction::I64Const(0)), // proof_size weight + Counter(value_len, deposit_len as u32), // deposit_limit_ptr + Regular(Instruction::I32Const(0)), // value_ptr + Regular(Instruction::I32Const(0)), // input_data_ptr + Regular(Instruction::I32Const(0)), // input_data_len + Regular(Instruction::I32Const(SENTINEL as i32)), // output_ptr + Regular(Instruction::I32Const(0)), // output_len_ptr + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ], + )), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, Some(BalanceOf::::from(u32::MAX.into()).into()), vec![]) + #[extrinsic_call] + call( + origin, + instance.addr, + 0u32.into(), + Weight::MAX, + Some(BalanceOf::::from(u32::MAX.into()).into()), + vec![], + ); + Ok(()) + } // This is a slow call: We redeuce the number of runs. - #[pov_mode = Measured] - seal_delegate_call { - let r in 0 .. API_BENCHMARK_RUNS / 2; + #[benchmark(pov_mode = Measured)] + fn seal_delegate_call(r: Linear<0, { API_BENCHMARK_RUNS / 2 }>) -> Result<(), BenchmarkError> { let hashes = (0..r) .map(|i| { let code = WasmModule::::dummy_with_bytes(i); @@ -1819,7 +1951,6 @@ benchmarks! { .collect::, &'static str>>()?; let hash_len = hashes.get(0).map(|x| x.encode().len()).unwrap_or(0); let hashes_bytes = hashes.iter().flat_map(|x| x.encode()).collect::>(); - let hashes_len = hashes_bytes.len(); let hashes_offset = 0; let code = WasmModule::::from(ModuleDefinition { @@ -1837,33 +1968,35 @@ benchmarks! { ], return_type: Some(ValueType::I32), }], - data_segments: vec![ - DataSegment { - offset: hashes_offset as u32, - value: hashes_bytes, - }, - ], - call_body: Some(body::repeated_dyn(r, vec![ - Regular(Instruction::I32Const(0)), // flags - Counter(hashes_offset as u32, hash_len as u32), // code_hash_ptr - Regular(Instruction::I32Const(0)), // input_data_ptr - Regular(Instruction::I32Const(0)), // input_data_len - Regular(Instruction::I32Const(u32::max_value() as i32)), // output_ptr - Regular(Instruction::I32Const(0)), // output_len_ptr - Regular(Instruction::Call(0)), - Regular(Instruction::Drop), - ])), - .. Default::default() + data_segments: vec![DataSegment { offset: hashes_offset as u32, value: hashes_bytes }], + call_body: Some(body::repeated_dyn( + r, + vec![ + Regular(Instruction::I32Const(0)), // flags + Counter(hashes_offset as u32, hash_len as u32), // code_hash_ptr + Regular(Instruction::I32Const(0)), // input_data_ptr + Regular(Instruction::I32Const(0)), // input_data_len + Regular(Instruction::I32Const(u32::max_value() as i32)), // output_ptr + Regular(Instruction::I32Const(0)), // output_len_ptr + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ], + )), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let callee = instance.addr.clone(); let origin = RawOrigin::Signed(instance.caller); - }: call(origin, callee, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, callee, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } - #[pov_mode = Measured] - seal_call_per_transfer_clone_byte { - let t in 0 .. 1; - let c in 0 .. code::max_pages::() * 64 * 1024; + #[benchmark(pov_mode = Measured)] + fn seal_call_per_transfer_clone_byte( + t: Linear<0, { 1 }>, + c: Linear<0, { code::max_pages::() * 64 * 1024 }>, + ) -> Result<(), BenchmarkError> { let callee = Contract::with_index(5, >::dummy(), vec![])?; let value: BalanceOf = t.into(); let value_bytes = value.encode(); @@ -1886,40 +2019,36 @@ benchmarks! { return_type: Some(ValueType::I32), }], data_segments: vec![ - DataSegment { - offset: 0, - value: value_bytes, - }, - DataSegment { - offset: value_len as u32, - value: callee.account_id.encode(), - }, + DataSegment { offset: 0, value: value_bytes }, + DataSegment { offset: value_len as u32, value: callee.account_id.encode() }, ], call_body: Some(body::plain(vec![ Instruction::I32Const(CallFlags::CLONE_INPUT.bits() as i32), // flags - Instruction::I32Const(value_len as i32), // callee_ptr - Instruction::I64Const(0), // gas - Instruction::I32Const(0), // value_ptr - Instruction::I32Const(0), // input_data_ptr - Instruction::I32Const(0), // input_data_len - Instruction::I32Const(SENTINEL as i32), // output_ptr - Instruction::I32Const(0), // output_len_ptr + Instruction::I32Const(value_len as i32), // callee_ptr + Instruction::I64Const(0), // gas + Instruction::I32Const(0), // value_ptr + Instruction::I32Const(0), // input_data_ptr + Instruction::I32Const(0), // input_data_len + Instruction::I32Const(SENTINEL as i32), // output_ptr + Instruction::I32Const(0), // output_len_ptr Instruction::Call(0), Instruction::Drop, Instruction::End, ])), - .. Default::default() + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); let bytes = vec![42; c as usize]; - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, bytes) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, bytes); + Ok(()) + } // We assume that every instantiate sends at least the minimum balance. // This is a slow call: we reduce the number of runs. - #[pov_mode = Measured] - seal_instantiate { - let r in 1 .. API_BENCHMARK_RUNS / 2; + #[benchmark(pov_mode = Measured)] + fn seal_instantiate(r: Linear<1, { API_BENCHMARK_RUNS / 2 }>) -> Result<(), BenchmarkError> { let hashes = (0..r) .map(|i| { let code = WasmModule::::from(ModuleDefinition { @@ -1931,7 +2060,7 @@ benchmarks! { Instruction::Drop, Instruction::End, ])), - .. Default::default() + ..Default::default() }); let caller = whitelisted_caller(); T::Currency::set_balance(&caller, caller_funding::()); @@ -1974,37 +2103,35 @@ benchmarks! { return_type: Some(ValueType::I32), }], data_segments: vec![ - DataSegment { - offset: 0, - value: value_bytes, - }, - DataSegment { - offset: hashes_offset as u32, - value: hashes_bytes, - }, + DataSegment { offset: 0, value: value_bytes }, + DataSegment { offset: hashes_offset as u32, value: hashes_bytes }, DataSegment { offset: addr_len_offset as u32, value: addr_len.to_le_bytes().into(), }, ], - call_body: Some(body::repeated_dyn(r, vec![ - Counter(hashes_offset as u32, hash_len as u32), // code_hash_ptr - Regular(Instruction::I64Const(0)), // ref_time weight - Regular(Instruction::I64Const(0)), // proof_size weight - Regular(Instruction::I32Const(SENTINEL as i32)), // deposit limit ptr: use parent's limit - Regular(Instruction::I32Const(0)), // value_ptr - Regular(Instruction::I32Const(0)), // input_data_ptr - Regular(Instruction::I32Const(0)), // input_data_len - Regular(Instruction::I32Const(addr_offset as i32)), // address_ptr - Regular(Instruction::I32Const(addr_len_offset as i32)), // address_len_ptr - Regular(Instruction::I32Const(SENTINEL as i32)), // output_ptr - Regular(Instruction::I32Const(0)), // output_len_ptr - Regular(Instruction::I32Const(0)), // salt_ptr - Regular(Instruction::I32Const(0)), // salt_len_ptr - Regular(Instruction::Call(0)), - Regular(Instruction::Drop), - ])), - .. Default::default() + call_body: Some(body::repeated_dyn( + r, + vec![ + Counter(hashes_offset as u32, hash_len as u32), // code_hash_ptr + Regular(Instruction::I64Const(0)), // ref_time weight + Regular(Instruction::I64Const(0)), // proof_size weight + Regular(Instruction::I32Const(SENTINEL as i32)), /* deposit limit ptr: use + * parent's limit */ + Regular(Instruction::I32Const(0)), // value_ptr + Regular(Instruction::I32Const(0)), // input_data_ptr + Regular(Instruction::I32Const(0)), // input_data_len + Regular(Instruction::I32Const(addr_offset as i32)), // address_ptr + Regular(Instruction::I32Const(addr_len_offset as i32)), // address_len_ptr + Regular(Instruction::I32Const(SENTINEL as i32)), // output_ptr + Regular(Instruction::I32Const(0)), // output_len_ptr + Regular(Instruction::I32Const(0)), // salt_ptr + Regular(Instruction::I32Const(0)), // salt_len_ptr + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ], + )), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; instance.set_balance((value + Pallet::::min_balance()) * (r + 1).into()); @@ -2012,9 +2139,7 @@ benchmarks! { let callee = instance.addr.clone(); let addresses = hashes .iter() - .map(|hash| Contracts::::contract_address( - &instance.account_id, hash, &[], &[], - )) + .map(|hash| Contracts::::contract_address(&instance.account_id, hash, &[], &[])) .collect::>(); for addr in &addresses { @@ -2022,27 +2147,27 @@ benchmarks! { return Err("Expected that contract does not exist at this point.".into()); } } - }: call(origin, callee, 0u32.into(), Weight::MAX, None, vec![]) - verify { + #[extrinsic_call] + call(origin, callee, 0u32.into(), Weight::MAX, None, vec![]); for addr in &addresses { - ContractInfoOf::::get(&addr) - .ok_or("Contract should have been instantiated")?; + ContractInfoOf::::get(&addr).ok_or("Contract should have been instantiated")?; } + Ok(()) } - #[pov_mode = Measured] - seal_instantiate_per_transfer_input_salt_byte { - let t in 0 .. 1; - let i in 0 .. (code::max_pages::() - 1) * 64 * 1024; - let s in 0 .. (code::max_pages::() - 1) * 64 * 1024; + #[benchmark(pov_mode = Measured)] + fn seal_instantiate_per_transfer_input_salt_byte( + t: Linear<0, 1>, + i: Linear<0, { (code::max_pages::() - 1) * 64 * 1024 }>, + s: Linear<0, { (code::max_pages::() - 1) * 64 * 1024 }>, + ) -> Result<(), BenchmarkError> { let callee_code = WasmModule::::dummy(); - let hash = callee_code.hash; let hash_bytes = callee_code.hash.encode(); let hash_len = hash_bytes.len(); let caller = whitelisted_caller(); T::Currency::set_balance(&caller, caller_funding::()); Contracts::::store_code_raw(callee_code.code, caller)?; - let value: BalanceOf = t.into(); + let value: BalanceOf = t.into(); let value_bytes = value.encode(); let code = WasmModule::::from(ModuleDefinition { @@ -2066,27 +2191,21 @@ benchmarks! { return_type: Some(ValueType::I32), }], data_segments: vec![ - DataSegment { - offset: 0, - value: hash_bytes, - }, - DataSegment { - offset: hash_len as u32, - value: value_bytes, - }, + DataSegment { offset: 0, value: hash_bytes }, + DataSegment { offset: hash_len as u32, value: value_bytes }, ], call_body: Some(body::plain(vec![ - Instruction::I32Const(0 as i32), // code_hash_ptr - Instruction::I64Const(0), // gas + Instruction::I32Const(0 as i32), // code_hash_ptr + Instruction::I64Const(0), // gas Instruction::I32Const(hash_len as i32), // value_ptr - Instruction::I32Const(0 as i32), // input_data_ptr - Instruction::I32Const(i as i32), // input_data_len + Instruction::I32Const(0 as i32), // input_data_ptr + Instruction::I32Const(i as i32), // input_data_len Instruction::I32Const(SENTINEL as i32), // address_ptr - Instruction::I32Const(0), // address_len_ptr + Instruction::I32Const(0), // address_len_ptr Instruction::I32Const(SENTINEL as i32), // output_ptr - Instruction::I32Const(0), // output_len_ptr - Instruction::I32Const(0 as i32), // salt_ptr - Instruction::I32Const(s as i32), // salt_len + Instruction::I32Const(0), // output_len_ptr + Instruction::I32Const(0 as i32), // salt_ptr + Instruction::I32Const(s as i32), // salt_len Instruction::Call(0), Instruction::I32Eqz, Instruction::If(BlockType::NoResult), @@ -2096,105 +2215,123 @@ benchmarks! { Instruction::End, Instruction::End, ])), - .. Default::default() + ..Default::default() }); let instance = Contract::::new(code, vec![])?; instance.set_balance(value + (Pallet::::min_balance() * 2u32.into())); let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } // Only the overhead of calling the function itself with minimal arguments. - #[pov_mode = Measured] - seal_hash_sha2_256 { - let r in 0 .. API_BENCHMARK_RUNS; - let instance = Contract::::new(WasmModule::hasher( - "seal_hash_sha2_256", r, 0, - ), vec![])?; + #[benchmark(pov_mode = Measured)] + fn seal_hash_sha2_256(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { + let instance = Contract::::new(WasmModule::hasher("seal_hash_sha2_256", r, 0), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } // `n`: Input to hash in bytes - #[pov_mode = Measured] - seal_hash_sha2_256_per_byte { - let n in 0 .. code::max_pages::() * 64 * 1024; - let instance = Contract::::new(WasmModule::hasher( - "seal_hash_sha2_256", 1, n, - ), vec![])?; + #[benchmark(pov_mode = Measured)] + fn seal_hash_sha2_256_per_byte( + n: Linear<0, { code::max_pages::() * 64 * 1024 }>, + ) -> Result<(), BenchmarkError> { + let instance = Contract::::new(WasmModule::hasher("seal_hash_sha2_256", 1, n), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } // Only the overhead of calling the function itself with minimal arguments. - #[pov_mode = Measured] - seal_hash_keccak_256 { - let r in 0 .. API_BENCHMARK_RUNS; - let instance = Contract::::new(WasmModule::hasher( - "seal_hash_keccak_256", r, 0, - ), vec![])?; + #[benchmark(pov_mode = Measured)] + fn seal_hash_keccak_256(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { + let instance = + Contract::::new(WasmModule::hasher("seal_hash_keccak_256", r, 0), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } // `n`: Input to hash in bytes - #[pov_mode = Measured] - seal_hash_keccak_256_per_byte { - let n in 0 .. code::max_pages::() * 64 * 1024; - let instance = Contract::::new(WasmModule::hasher( - "seal_hash_keccak_256", 1, n, - ), vec![])?; + #[benchmark(pov_mode = Measured)] + fn seal_hash_keccak_256_per_byte( + n: Linear<0, { code::max_pages::() * 64 * 1024 }>, + ) -> Result<(), BenchmarkError> { + let instance = + Contract::::new(WasmModule::hasher("seal_hash_keccak_256", 1, n), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } // Only the overhead of calling the function itself with minimal arguments. - #[pov_mode = Measured] - seal_hash_blake2_256 { - let r in 0 .. API_BENCHMARK_RUNS; - let instance = Contract::::new(WasmModule::hasher( - "seal_hash_blake2_256", r, 0, - ), vec![])?; + #[benchmark(pov_mode = Measured)] + fn seal_hash_blake2_256(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { + let instance = + Contract::::new(WasmModule::hasher("seal_hash_blake2_256", r, 0), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } // `n`: Input to hash in bytes - #[pov_mode = Measured] - seal_hash_blake2_256_per_byte { - let n in 0 .. code::max_pages::() * 64 * 1024; - let instance = Contract::::new(WasmModule::hasher( - "seal_hash_blake2_256", 1, n, - ), vec![])?; + #[benchmark(pov_mode = Measured)] + fn seal_hash_blake2_256_per_byte( + n: Linear<0, { code::max_pages::() * 64 * 1024 }>, + ) -> Result<(), BenchmarkError> { + let instance = + Contract::::new(WasmModule::hasher("seal_hash_blake2_256", 1, n), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } // Only the overhead of calling the function itself with minimal arguments. - #[pov_mode = Measured] - seal_hash_blake2_128 { - let r in 0 .. API_BENCHMARK_RUNS; - let instance = Contract::::new(WasmModule::hasher( - "seal_hash_blake2_128", r, 0, - ), vec![])?; + #[benchmark(pov_mode = Measured)] + fn seal_hash_blake2_128(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { + let instance = + Contract::::new(WasmModule::hasher("seal_hash_blake2_128", r, 0), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } // `n`: Input to hash in bytes - #[pov_mode = Measured] - seal_hash_blake2_128_per_byte { - let n in 0 .. code::max_pages::() * 64 * 1024; - let instance = Contract::::new(WasmModule::hasher( - "seal_hash_blake2_128", 1, n, - ), vec![])?; + #[benchmark(pov_mode = Measured)] + fn seal_hash_blake2_128_per_byte( + n: Linear<0, { code::max_pages::() * 64 * 1024 }>, + ) -> Result<(), BenchmarkError> { + let instance = + Contract::::new(WasmModule::hasher("seal_hash_blake2_128", 1, n), vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } // `n`: Message input length to verify in bytes. - #[pov_mode = Measured] - seal_sr25519_verify_per_byte { - let n in 0 .. T::MaxCodeLen::get() - 255; // need some buffer so the code size does not - // exceed the max code size. - + // need some buffer so the code size does not exceed the max code size. + #[benchmark(pov_mode = Measured)] + fn seal_sr25519_verify_per_byte( + n: Linear<0, { T::MaxCodeLen::get() - 255 }>, + ) -> Result<(), BenchmarkError> { let message = (0..n).zip((32u8..127u8).cycle()).map(|(_, c)| c).collect::>(); let message_len = message.len() as i32; let key_type = sp_core::crypto::KeyTypeId(*b"code"); let pub_key = sp_io::crypto::sr25519_generate(key_type, None); - let sig = sp_io::crypto::sr25519_sign(key_type, &pub_key, &message).expect("Generates signature"); + let sig = + sp_io::crypto::sr25519_sign(key_type, &pub_key, &message).expect("Generates signature"); let sig = AsRef::<[u8; 64]>::as_ref(&sig).to_vec(); let code = WasmModule::::from(ModuleDefinition { @@ -2206,50 +2343,48 @@ benchmarks! { return_type: Some(ValueType::I32), }], data_segments: vec![ - DataSegment { - offset: 0, - value: sig, - }, - DataSegment { - offset: 64, - value: pub_key.to_vec(), - }, - DataSegment { - offset: 96, - value: message, - }, + DataSegment { offset: 0, value: sig }, + DataSegment { offset: 64, value: pub_key.to_vec() }, + DataSegment { offset: 96, value: message }, ], call_body: Some(body::plain(vec![ - Instruction::I32Const(0), // signature_ptr - Instruction::I32Const(64), // pub_key_ptr + Instruction::I32Const(0), // signature_ptr + Instruction::I32Const(64), // pub_key_ptr Instruction::I32Const(message_len), // message_len - Instruction::I32Const(96), // message_ptr + Instruction::I32Const(96), // message_ptr Instruction::Call(0), Instruction::Drop, Instruction::End, ])), - .. Default::default() + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } // Only calling the function itself with valid arguments. // It generates different private keys and signatures for the message "Hello world". // This is a slow call: We reduce the number of runs. - #[pov_mode = Measured] - seal_sr25519_verify { - let r in 0 .. API_BENCHMARK_RUNS / 10; - + #[benchmark(pov_mode = Measured)] + fn seal_sr25519_verify( + r: Linear<0, { API_BENCHMARK_RUNS / 10 }>, + ) -> Result<(), BenchmarkError> { let message = b"Hello world".to_vec(); let message_len = message.len() as i32; let key_type = sp_core::crypto::KeyTypeId(*b"code"); let sig_params = (0..r) - .flat_map(|i| { + .flat_map(|_| { let pub_key = sp_io::crypto::sr25519_generate(key_type, None); - let sig = sp_io::crypto::sr25519_sign(key_type, &pub_key, &message).expect("Generates signature"); - let data: [u8; 96] = [AsRef::<[u8]>::as_ref(&sig), AsRef::<[u8]>::as_ref(&pub_key)].concat().try_into().unwrap(); + let sig = sp_io::crypto::sr25519_sign(key_type, &pub_key, &message) + .expect("Generates signature"); + let data: [u8; 96] = [AsRef::<[u8]>::as_ref(&sig), AsRef::<[u8]>::as_ref(&pub_key)] + .concat() + .try_into() + .unwrap(); data }) .collect::>(); @@ -2264,42 +2399,41 @@ benchmarks! { return_type: Some(ValueType::I32), }], data_segments: vec![ - DataSegment { - offset: 0, - value: sig_params - }, - DataSegment { - offset: sig_params_len as u32, - value: message, - }, + DataSegment { offset: 0, value: sig_params }, + DataSegment { offset: sig_params_len as u32, value: message }, ], - call_body: Some(body::repeated_dyn(r, vec![ - Counter(0, 96), // signature_ptr - Counter(64, 96), // pub_key_ptr - Regular(Instruction::I32Const(message_len)), // message_len - Regular(Instruction::I32Const(sig_params_len)), // message_ptr - Regular(Instruction::Call(0)), - Regular(Instruction::Drop), - ])), - .. Default::default() + call_body: Some(body::repeated_dyn( + r, + vec![ + Counter(0, 96), // signature_ptr + Counter(64, 96), // pub_key_ptr + Regular(Instruction::I32Const(message_len)), // message_len + Regular(Instruction::I32Const(sig_params_len)), // message_ptr + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ], + )), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } // Only calling the function itself with valid arguments. // It generates different private keys and signatures for the message "Hello world". // This is a slow call: We reduce the number of runs. - #[pov_mode = Measured] - seal_ecdsa_recover { - let r in 0 .. API_BENCHMARK_RUNS / 10; - + #[benchmark(pov_mode = Measured)] + fn seal_ecdsa_recover(r: Linear<0, { API_BENCHMARK_RUNS / 10 }>) -> Result<(), BenchmarkError> { let message_hash = sp_io::hashing::blake2_256("Hello world".as_bytes()); let key_type = sp_core::crypto::KeyTypeId(*b"code"); let signatures = (0..r) - .map(|i| { + .map(|_| { let pub_key = sp_io::crypto::ecdsa_generate(key_type, None); - let sig = sp_io::crypto::ecdsa_sign_prehashed(key_type, &pub_key, &message_hash).expect("Generates signature"); + let sig = sp_io::crypto::ecdsa_sign_prehashed(key_type, &pub_key, &message_hash) + .expect("Generates signature"); AsRef::<[u8; 65]>::as_ref(&sig).to_vec() }) .collect::>(); @@ -2315,40 +2449,39 @@ benchmarks! { return_type: Some(ValueType::I32), }], data_segments: vec![ - DataSegment { - offset: 0, - value: message_hash[..].to_vec(), - }, - DataSegment { - offset: 32, - value: signatures, - }, + DataSegment { offset: 0, value: message_hash[..].to_vec() }, + DataSegment { offset: 32, value: signatures }, ], - call_body: Some(body::repeated_dyn(r, vec![ - Counter(32, 65), // signature_ptr - Regular(Instruction::I32Const(0)), // message_hash_ptr - Regular(Instruction::I32Const(signatures_bytes_len + 32)), // output_len_ptr - Regular(Instruction::Call(0)), - Regular(Instruction::Drop), - ])), - .. Default::default() + call_body: Some(body::repeated_dyn( + r, + vec![ + Counter(32, 65), // signature_ptr + Regular(Instruction::I32Const(0)), // message_hash_ptr + Regular(Instruction::I32Const(signatures_bytes_len + 32)), // output_len_ptr + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ], + )), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } // Only calling the function itself for the list of // generated different ECDSA keys. // This is a slow call: We redeuce the number of runs. - #[pov_mode = Measured] - seal_ecdsa_to_eth_address { - let r in 0 .. API_BENCHMARK_RUNS / 10; + #[benchmark(pov_mode = Measured)] + fn seal_ecdsa_to_eth_address( + r: Linear<0, { API_BENCHMARK_RUNS / 10 }>, + ) -> Result<(), BenchmarkError> { let key_type = sp_core::crypto::KeyTypeId(*b"code"); let pub_keys_bytes = (0..r) - .flat_map(|_| { - sp_io::crypto::ecdsa_generate(key_type, None).0 - }) - .collect::>(); + .flat_map(|_| sp_io::crypto::ecdsa_generate(key_type, None).0) + .collect::>(); let pub_keys_bytes_len = pub_keys_bytes.len() as i32; let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), @@ -2358,27 +2491,27 @@ benchmarks! { params: vec![ValueType::I32, ValueType::I32], return_type: Some(ValueType::I32), }], - data_segments: vec![ - DataSegment { - offset: 0, - value: pub_keys_bytes, - }, - ], - call_body: Some(body::repeated_dyn(r, vec![ - Counter(0, 33), // pub_key_ptr - Regular(Instruction::I32Const(pub_keys_bytes_len)), // out_ptr - Regular(Instruction::Call(0)), - Regular(Instruction::Drop), - ])), - .. Default::default() + data_segments: vec![DataSegment { offset: 0, value: pub_keys_bytes }], + call_body: Some(body::repeated_dyn( + r, + vec![ + Counter(0, 33), // pub_key_ptr + Regular(Instruction::I32Const(pub_keys_bytes_len)), // out_ptr + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ], + )), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } - #[pov_mode = Measured] - seal_set_code_hash { - let r in 0 .. API_BENCHMARK_RUNS; + #[benchmark(pov_mode = Measured)] + fn seal_set_code_hash(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { let code_hashes = (0..r) .map(|i| { let new_code = WasmModule::::dummy_with_bytes(i); @@ -2390,38 +2523,37 @@ benchmarks! { .collect::, &'static str>>()?; let code_hash_len = code_hashes.get(0).map(|x| x.encode().len()).unwrap_or(0); let code_hashes_bytes = code_hashes.iter().flat_map(|x| x.encode()).collect::>(); - let code_hashes_len = code_hashes_bytes.len(); let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { module: "seal0", name: "seal_set_code_hash", - params: vec![ - ValueType::I32, - ], + params: vec![ValueType::I32], return_type: Some(ValueType::I32), }], - data_segments: vec![ - DataSegment { - offset: 0, - value: code_hashes_bytes, - }, - ], - call_body: Some(body::repeated_dyn(r, vec![ - Counter(0, code_hash_len as u32), // code_hash_ptr - Regular(Instruction::Call(0)), - Regular(Instruction::Drop), - ])), - .. Default::default() + data_segments: vec![DataSegment { offset: 0, value: code_hashes_bytes }], + call_body: Some(body::repeated_dyn( + r, + vec![ + Counter(0, code_hash_len as u32), // code_hash_ptr + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ], + )), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } - #[pov_mode = Measured] - lock_delegate_dependency { - let r in 0 .. T::MaxDelegateDependencies::get(); + #[benchmark(pov_mode = Measured)] + fn lock_delegate_dependency( + r: Linear<0, { T::MaxDelegateDependencies::get() }>, + ) -> Result<(), BenchmarkError> { let code_hashes = (0..r) .map(|i| { let new_code = WasmModule::::dummy_with_bytes(65 + i); @@ -2442,24 +2574,27 @@ benchmarks! { params: vec![ValueType::I32], return_type: None, }], - data_segments: vec![ - DataSegment { - offset: 0, - value: code_hashes_bytes, - }, - ], - call_body: Some(body::repeated_dyn(r, vec![ - Counter(0, code_hash_len as u32), // code_hash_ptr - Regular(Instruction::Call(0)), - ])), - .. Default::default() + data_segments: vec![DataSegment { offset: 0, value: code_hashes_bytes }], + call_body: Some(body::repeated_dyn( + r, + vec![ + Counter(0, code_hash_len as u32), // code_hash_ptr + Regular(Instruction::Call(0)), + ], + )), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } - unlock_delegate_dependency { - let r in 0 .. T::MaxDelegateDependencies::get(); + #[benchmark] + fn unlock_delegate_dependency( + r: Linear<0, { T::MaxDelegateDependencies::get() }>, + ) -> Result<(), BenchmarkError> { let code_hashes = (0..r) .map(|i| { let new_code = WasmModule::::dummy_with_bytes(65 + i); @@ -2475,40 +2610,46 @@ benchmarks! { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), - imported_functions: vec![ImportedFunction { - module: "seal0", - name: "unlock_delegate_dependency", - params: vec![ValueType::I32], - return_type: None, - }, ImportedFunction { - module: "seal0", - name: "lock_delegate_dependency", - params: vec![ValueType::I32], - return_type: None - }], - data_segments: vec![ - DataSegment { - offset: 0, - value: code_hashes_bytes, + imported_functions: vec![ + ImportedFunction { + module: "seal0", + name: "unlock_delegate_dependency", + params: vec![ValueType::I32], + return_type: None, + }, + ImportedFunction { + module: "seal0", + name: "lock_delegate_dependency", + params: vec![ValueType::I32], + return_type: None, }, ], - deploy_body: Some(body::repeated_dyn(r, vec![ - Counter(0, code_hash_len as u32), // code_hash_ptr - Regular(Instruction::Call(1)), - ])), - call_body: Some(body::repeated_dyn(r, vec![ - Counter(0, code_hash_len as u32), // code_hash_ptr - Regular(Instruction::Call(0)), - ])), - .. Default::default() + data_segments: vec![DataSegment { offset: 0, value: code_hashes_bytes }], + deploy_body: Some(body::repeated_dyn( + r, + vec![ + Counter(0, code_hash_len as u32), // code_hash_ptr + Regular(Instruction::Call(1)), + ], + )), + call_body: Some(body::repeated_dyn( + r, + vec![ + Counter(0, code_hash_len as u32), // code_hash_ptr + Regular(Instruction::Call(0)), + ], + )), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } - #[pov_mode = Measured] - seal_reentrance_count { - let r in 0 .. API_BENCHMARK_RUNS; + #[benchmark(pov_mode = Measured)] + fn seal_reentrance_count(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -2517,19 +2658,20 @@ benchmarks! { params: vec![], return_type: Some(ValueType::I32), }], - call_body: Some(body::repeated(r, &[ - Instruction::Call(0), - Instruction::Drop, - ])), - .. Default::default() + call_body: Some(body::repeated(r, &[Instruction::Call(0), Instruction::Drop])), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } - #[pov_mode = Measured] - seal_account_reentrance_count { - let r in 0 .. API_BENCHMARK_RUNS; + #[benchmark(pov_mode = Measured)] + fn seal_account_reentrance_count( + r: Linear<0, API_BENCHMARK_RUNS>, + ) -> Result<(), BenchmarkError> { let dummy_code = WasmModule::::dummy_with_bytes(0); let accounts = (0..r) .map(|i| Contract::with_index(i + 1, dummy_code.clone(), vec![])) @@ -2544,26 +2686,26 @@ benchmarks! { params: vec![ValueType::I32], return_type: Some(ValueType::I32), }], - data_segments: vec![ - DataSegment { - offset: 0, - value: account_id_bytes, - }, - ], - call_body: Some(body::repeated_dyn(r, vec![ - Counter(0, account_id_len as u32), // account_ptr - Regular(Instruction::Call(0)), - Regular(Instruction::Drop), - ])), - .. Default::default() + data_segments: vec![DataSegment { offset: 0, value: account_id_bytes }], + call_body: Some(body::repeated_dyn( + r, + vec![ + Counter(0, account_id_len as u32), // account_ptr + Regular(Instruction::Call(0)), + Regular(Instruction::Drop), + ], + )), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } - #[pov_mode = Measured] - seal_instantiation_nonce { - let r in 0 .. API_BENCHMARK_RUNS; + #[benchmark(pov_mode = Measured)] + fn seal_instantiation_nonce(r: Linear<0, API_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { let code = WasmModule::::from(ModuleDefinition { memory: Some(ImportedMemory::max::()), imported_functions: vec![ImportedFunction { @@ -2572,29 +2714,27 @@ benchmarks! { params: vec![], return_type: Some(ValueType::I64), }], - call_body: Some(body::repeated(r, &[ - Instruction::Call(0), - Instruction::Drop, - ])), - .. Default::default() + call_body: Some(body::repeated(r, &[Instruction::Call(0), Instruction::Drop])), + ..Default::default() }); let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); - }: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]) + #[extrinsic_call] + call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![]); + Ok(()) + } // We load `i64` values from random linear memory locations and store the loaded // values back into yet another random linear memory location. - // The random addresses are uniformely distributed across the entire span of the linear memory. + // The random addresses are uniformly distributed across the entire span of the linear memory. // We do this to enforce random memory accesses which are particularly expensive. // // The combination of this computation is our weight base `w_base`. - #[pov_mode = Ignored] - instr_i64_load_store { - let r in 0 .. INSTR_BENCHMARK_RUNS; - + #[benchmark(pov_mode = Ignored)] + fn instr_i64_load_store(r: Linear<0, INSTR_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> { use rand::prelude::*; - // We do not need to be secure here. Fixed seed allows for determinstic results. + // We do not need to be secure here. Fixed seed allows for deterministic results. let mut rng = rand_pcg::Pcg32::seed_from_u64(8446744073709551615); let memory = ImportedMemory::max::(); @@ -2614,24 +2754,27 @@ benchmarks! { [ Instruction::I32Const(c0), // address for `i64.load_8s` Instruction::I64Load8S(0, 0), - Instruction::SetLocal(0), // temporarily store value loaded in `i64.load_8s` + Instruction::SetLocal(0), /* temporarily store value loaded in + * `i64.load_8s` */ Instruction::I32Const(c1), // address for `i64.store8` Instruction::GetLocal(0), // value to be stores in `i64.store8` Instruction::I64Store8(0, 0), ] - } + }, )), - .. Default::default() + ..Default::default() })); - }: { - sbox.invoke(); + #[block] + { + sbox.invoke(); + } + Ok(()) } // This is no benchmark. It merely exist to have an easy way to pretty print the currently // configured `Schedule` during benchmark development. Check the README on how to print this. - #[extra] - #[pov_mode = Ignored] - print_schedule { + #[benchmark(extra, pov_mode = Ignored)] + fn print_schedule() -> Result<(), BenchmarkError> { let max_weight = ::BlockWeights::get().max_block; let (weight_per_key, key_budget) = ContractInfo::::deletion_budget(max_weight); let schedule = T::Schedule::get(); @@ -2641,11 +2784,15 @@ benchmarks! { Lazy deletion weight per key: {weight_per_key} Lazy deletion keys per block: {key_budget} "); - }: {} + #[block] + {} + + Err(BenchmarkError::Skip) + } impl_benchmark_test_suite!( Contracts, crate::tests::ExtBuilder::default().build(), crate::tests::Test, - ) + ); } diff --git a/substrate/frame/contracts/src/weights.rs b/substrate/frame/contracts/src/weights.rs index 99bc4d8d3eb..aa75ca8b29e 100644 --- a/substrate/frame/contracts/src/weights.rs +++ b/substrate/frame/contracts/src/weights.rs @@ -18,14 +18,13 @@ //! Autogenerated weights for `pallet_contracts` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-03-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-p5qp1txx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: // target/production/substrate-node -// target/production/substrate-node // benchmark // pallet // --steps=50 @@ -36,12 +35,8 @@ // --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json // --pallet=pallet_contracts // --chain=dev -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_contracts -// --chain=dev // --header=./substrate/HEADER-APACHE2 // --output=./substrate/frame/contracts/src/weights.rs -// --output=./substrate/frame/contracts/src/weights.rs // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -147,8 +142,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1627` - // Minimum execution time: 2_054_000 picoseconds. - Weight::from_parts(2_178_000, 1627) + // Minimum execution time: 2_130_000 picoseconds. + Weight::from_parts(2_247_000, 1627) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -158,10 +153,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `452 + k * (69 ±0)` // Estimated: `442 + k * (70 ±0)` - // Minimum execution time: 12_119_000 picoseconds. - Weight::from_parts(12_536_000, 442) - // Standard Error: 1_254 - .saturating_add(Weight::from_parts(1_161_885, 0).saturating_mul(k.into())) + // Minimum execution time: 12_748_000 picoseconds. + Weight::from_parts(13_001_000, 442) + // Standard Error: 1_206 + .saturating_add(Weight::from_parts(1_146_159, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -175,10 +170,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `211 + c * (1 ±0)` // Estimated: `6149 + c * (1 ±0)` - // Minimum execution time: 8_146_000 picoseconds. - Weight::from_parts(8_560_745, 6149) + // Minimum execution time: 8_636_000 picoseconds. + Weight::from_parts(8_664_917, 6149) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_182, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(1_188, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) @@ -191,8 +186,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `510` // Estimated: `6450` - // Minimum execution time: 16_183_000 picoseconds. - Weight::from_parts(16_825_000, 6450) + // Minimum execution time: 16_838_000 picoseconds. + Weight::from_parts(17_400_000, 6450) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -205,10 +200,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `171 + k * (1 ±0)` // Estimated: `3635 + k * (1 ±0)` - // Minimum execution time: 3_645_000 picoseconds. - Weight::from_parts(604_365, 3635) - // Standard Error: 1_013 - .saturating_add(Weight::from_parts(1_100_277, 0).saturating_mul(k.into())) + // Minimum execution time: 3_876_000 picoseconds. + Weight::from_parts(2_654_935, 3635) + // Standard Error: 2_001 + .saturating_add(Weight::from_parts(1_258_085, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -218,6 +213,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc553053f13fd319a03c211337c76e0fe776df` (r:2 w:0) /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc553022fca90611ba8b7942f8bdb3b97f6580` (r:1 w:1) /// Proof: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc553022fca90611ba8b7942f8bdb3b97f6580` (r:1 w:1) + /// Storage: `Parameters::Parameters` (r:2 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:0 w:1) @@ -227,10 +224,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `328 + c * (1 ±0)` // Estimated: `6266 + c * (1 ±0)` - // Minimum execution time: 19_500_000 picoseconds. - Weight::from_parts(20_074_895, 6266) + // Minimum execution time: 21_038_000 picoseconds. + Weight::from_parts(20_890_548, 6266) // Standard Error: 1 - .saturating_add(Weight::from_parts(422, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(435, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) @@ -241,8 +238,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `440` // Estimated: `6380` - // Minimum execution time: 12_530_000 picoseconds. - Weight::from_parts(13_362_000, 6380) + // Minimum execution time: 12_579_000 picoseconds. + Weight::from_parts(13_486_000, 6380) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -251,13 +248,13 @@ impl WeightInfo for SubstrateWeight { /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:0) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) fn v14_migration_step() -> Weight { // Proof Size summary in bytes: // Measured: `352` // Estimated: `6292` - // Minimum execution time: 44_275_000 picoseconds. - Weight::from_parts(45_718_000, 6292) + // Minimum execution time: 47_123_000 picoseconds. + Weight::from_parts(48_284_000, 6292) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -269,8 +266,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `594` // Estimated: `6534` - // Minimum execution time: 55_095_000 picoseconds. - Weight::from_parts(58_009_000, 6534) + // Minimum execution time: 55_237_000 picoseconds. + Weight::from_parts(57_996_000, 6534) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -280,8 +277,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1627` - // Minimum execution time: 2_455_000 picoseconds. - Weight::from_parts(2_608_000, 1627) + // Minimum execution time: 2_766_000 picoseconds. + Weight::from_parts(2_807_000, 1627) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -293,8 +290,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `166` // Estimated: `3631` - // Minimum execution time: 11_207_000 picoseconds. - Weight::from_parts(11_802_000, 3631) + // Minimum execution time: 12_243_000 picoseconds. + Weight::from_parts(12_890_000, 3631) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -304,8 +301,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 4_581_000 picoseconds. - Weight::from_parts(4_781_000, 3607) + // Minimum execution time: 4_951_000 picoseconds. + Weight::from_parts(5_232_000, 3607) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc55304e7b9012096b41c4eb3aaf947f6ea429` (r:1 w:0) @@ -316,8 +313,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `167` // Estimated: `3632` - // Minimum execution time: 5_887_000 picoseconds. - Weight::from_parts(6_393_000, 3632) + // Minimum execution time: 6_530_000 picoseconds. + Weight::from_parts(6_726_000, 3632) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc55304e7b9012096b41c4eb3aaf947f6ea429` (r:1 w:0) @@ -328,13 +325,15 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 6_025_000 picoseconds. - Weight::from_parts(6_298_000, 3607) + // Minimum execution time: 6_227_000 picoseconds. + Weight::from_parts(6_708_000, 3607) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -352,20 +351,22 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `804 + c * (1 ±0)` // Estimated: `9217 + c * (1 ±0)` - // Minimum execution time: 294_976_000 picoseconds. - Weight::from_parts(277_235_948, 9217) - // Standard Error: 65 - .saturating_add(Weight::from_parts(34_445, 0).saturating_mul(c.into())) + // Minimum execution time: 309_889_000 picoseconds. + Weight::from_parts(277_084_159, 9217) + // Standard Error: 71 + .saturating_add(Weight::from_parts(33_471, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:1) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Balances::Holds` (r:2 w:2) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) /// Storage: `System::EventTopics` (r:3 w:3) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Contracts::Nonce` (r:1 w:1) @@ -385,14 +386,14 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `326` // Estimated: `8740` - // Minimum execution time: 3_864_558_000 picoseconds. - Weight::from_parts(421_676_889, 8740) - // Standard Error: 188 - .saturating_add(Weight::from_parts(103_788, 0).saturating_mul(c.into())) - // Standard Error: 22 - .saturating_add(Weight::from_parts(1_715, 0).saturating_mul(i.into())) - // Standard Error: 22 - .saturating_add(Weight::from_parts(1_774, 0).saturating_mul(s.into())) + // Minimum execution time: 3_909_680_000 picoseconds. + Weight::from_parts(446_471_160, 8740) + // Standard Error: 159 + .saturating_add(Weight::from_parts(101_085, 0).saturating_mul(c.into())) + // Standard Error: 19 + .saturating_add(Weight::from_parts(1_598, 0).saturating_mul(i.into())) + // Standard Error: 19 + .saturating_add(Weight::from_parts(1_879, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(14_u64)) .saturating_add(T::DbWeight::get().writes(10_u64)) } @@ -402,6 +403,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Contracts::PristineCode` (r:1 w:0) /// Proof: `Contracts::PristineCode` (`max_values`: None, `max_size`: Some(125988), added: 128463, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::Nonce` (r:1 w:1) /// Proof: `Contracts::Nonce` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) @@ -413,24 +416,26 @@ impl WeightInfo for SubstrateWeight { /// Storage: `System::EventTopics` (r:2 w:2) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) /// The range of component `i` is `[0, 1048576]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate(i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `563` // Estimated: `8982` - // Minimum execution time: 2_069_276_000 picoseconds. - Weight::from_parts(377_210_279, 8982) - // Standard Error: 9 - .saturating_add(Weight::from_parts(1_719, 0).saturating_mul(i.into())) - // Standard Error: 9 - .saturating_add(Weight::from_parts(1_728, 0).saturating_mul(s.into())) + // Minimum execution time: 1_968_545_000 picoseconds. + Weight::from_parts(420_048_028, 8982) + // Standard Error: 20 + .saturating_add(Weight::from_parts(1_685, 0).saturating_mul(i.into())) + // Standard Error: 20 + .saturating_add(Weight::from_parts(1_645, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -447,17 +452,19 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `829` // Estimated: `9244` - // Minimum execution time: 199_037_000 picoseconds. - Weight::from_parts(213_931_000, 9244) + // Minimum execution time: 207_564_000 picoseconds. + Weight::from_parts(216_983_000, 9244) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:2 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:1) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) /// Storage: `System::EventTopics` (r:1 w:1) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Contracts::PristineCode` (r:0 w:1) @@ -467,10 +474,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `145` // Estimated: `6085` - // Minimum execution time: 278_482_000 picoseconds. - Weight::from_parts(262_753_879, 6085) - // Standard Error: 112 - .saturating_add(Weight::from_parts(66_129, 0).saturating_mul(c.into())) + // Minimum execution time: 273_555_000 picoseconds. + Weight::from_parts(257_517_935, 6085) + // Standard Error: 148 + .saturating_add(Weight::from_parts(64_488, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -491,10 +498,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `145` // Estimated: `6085` - // Minimum execution time: 286_902_000 picoseconds. - Weight::from_parts(269_003_959, 6085) - // Standard Error: 123 - .saturating_add(Weight::from_parts(66_629, 0).saturating_mul(c.into())) + // Minimum execution time: 289_672_000 picoseconds. + Weight::from_parts(297_020_278, 6085) + // Standard Error: 86 + .saturating_add(Weight::from_parts(64_340, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -503,7 +510,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Contracts::CodeInfoOf` (r:1 w:1) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) /// Storage: `System::EventTopics` (r:1 w:1) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Contracts::PristineCode` (r:0 w:1) @@ -512,8 +519,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `315` // Estimated: `3780` - // Minimum execution time: 44_128_000 picoseconds. - Weight::from_parts(46_044_000, 3780) + // Minimum execution time: 45_930_000 picoseconds. + Weight::from_parts(47_288_000, 3780) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -529,8 +536,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `552` // Estimated: `8967` - // Minimum execution time: 33_567_000 picoseconds. - Weight::from_parts(35_057_000, 8967) + // Minimum execution time: 35_421_000 picoseconds. + Weight::from_parts(36_909_000, 8967) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -538,6 +545,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -553,10 +562,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `869 + r * (6 ±0)` // Estimated: `9284 + r * (6 ±0)` - // Minimum execution time: 272_376_000 picoseconds. - Weight::from_parts(284_162_161, 9284) - // Standard Error: 501 - .saturating_add(Weight::from_parts(341_575, 0).saturating_mul(r.into())) + // Minimum execution time: 275_531_000 picoseconds. + Weight::from_parts(292_269_656, 9284) + // Standard Error: 672 + .saturating_add(Weight::from_parts(339_728, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -565,6 +574,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1601 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -580,10 +591,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `925 + r * (209 ±0)` // Estimated: `9304 + r * (2684 ±0)` - // Minimum execution time: 256_990_000 picoseconds. - Weight::from_parts(107_167_044, 9304) - // Standard Error: 7_545 - .saturating_add(Weight::from_parts(3_628_112, 0).saturating_mul(r.into())) + // Minimum execution time: 275_829_000 picoseconds. + Weight::from_parts(124_543_289, 9304) + // Standard Error: 6_085 + .saturating_add(Weight::from_parts(3_702_964, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -593,6 +604,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1601 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -608,10 +621,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `924 + r * (213 ±0)` // Estimated: `9308 + r * (2688 ±0)` - // Minimum execution time: 272_889_000 picoseconds. - Weight::from_parts(110_341_799, 9308) - // Standard Error: 7_881 - .saturating_add(Weight::from_parts(4_427_043, 0).saturating_mul(r.into())) + // Minimum execution time: 276_666_000 picoseconds. + Weight::from_parts(96_951_288, 9308) + // Standard Error: 8_876 + .saturating_add(Weight::from_parts(4_604_699, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -621,6 +634,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -636,10 +651,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `876 + r * (6 ±0)` // Estimated: `9293 + r * (6 ±0)` - // Minimum execution time: 275_027_000 picoseconds. - Weight::from_parts(283_302_223, 9293) - // Standard Error: 1_179 - .saturating_add(Weight::from_parts(436_023, 0).saturating_mul(r.into())) + // Minimum execution time: 271_301_000 picoseconds. + Weight::from_parts(284_126_054, 9293) + // Standard Error: 886 + .saturating_add(Weight::from_parts(437_127, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -648,6 +663,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -663,16 +680,18 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `866 + r * (3 ±0)` // Estimated: `9282 + r * (3 ±0)` - // Minimum execution time: 270_137_000 picoseconds. - Weight::from_parts(282_756_362, 9282) - // Standard Error: 384 - .saturating_add(Weight::from_parts(171_660, 0).saturating_mul(r.into())) + // Minimum execution time: 274_778_000 picoseconds. + Weight::from_parts(289_355_269, 9282) + // Standard Error: 382 + .saturating_add(Weight::from_parts(175_342, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -688,10 +707,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `756 + r * (3 ±0)` // Estimated: `9171 + r * (3 ±0)` - // Minimum execution time: 255_131_000 picoseconds. - Weight::from_parts(269_207_006, 9171) - // Standard Error: 542 - .saturating_add(Weight::from_parts(161_597, 0).saturating_mul(r.into())) + // Minimum execution time: 257_310_000 picoseconds. + Weight::from_parts(276_410_847, 9171) + // Standard Error: 733 + .saturating_add(Weight::from_parts(160_094, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(10_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) @@ -700,6 +719,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -715,10 +736,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `870 + r * (6 ±0)` // Estimated: `9285 + r * (6 ±0)` - // Minimum execution time: 272_172_000 picoseconds. - Weight::from_parts(283_747_134, 9285) - // Standard Error: 885 - .saturating_add(Weight::from_parts(343_968, 0).saturating_mul(r.into())) + // Minimum execution time: 278_305_000 picoseconds. + Weight::from_parts(282_372_935, 9285) + // Standard Error: 1_154 + .saturating_add(Weight::from_parts(343_382, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -727,6 +748,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -742,10 +765,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `866 + r * (6 ±0)` // Estimated: `9284 + r * (6 ±0)` - // Minimum execution time: 263_220_000 picoseconds. - Weight::from_parts(277_062_382, 9284) - // Standard Error: 1_783 - .saturating_add(Weight::from_parts(399_631, 0).saturating_mul(r.into())) + // Minimum execution time: 280_349_000 picoseconds. + Weight::from_parts(294_864_875, 9284) + // Standard Error: 1_010 + .saturating_add(Weight::from_parts(368_740, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -754,6 +777,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:2 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -769,10 +794,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1010 + r * (6 ±0)` // Estimated: `9409 + r * (6 ±0)` - // Minimum execution time: 253_218_000 picoseconds. - Weight::from_parts(282_251_452, 9409) - // Standard Error: 2_367 - .saturating_add(Weight::from_parts(1_604_060, 0).saturating_mul(r.into())) + // Minimum execution time: 274_578_000 picoseconds. + Weight::from_parts(313_285_034, 9409) + // Standard Error: 2_800 + .saturating_add(Weight::from_parts(1_653_468, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -781,6 +806,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -796,10 +823,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `880 + r * (6 ±0)` // Estimated: `9301 + r * (6 ±0)` - // Minimum execution time: 271_797_000 picoseconds. - Weight::from_parts(288_594_393, 9301) - // Standard Error: 846 - .saturating_add(Weight::from_parts(335_063, 0).saturating_mul(r.into())) + // Minimum execution time: 287_127_000 picoseconds. + Weight::from_parts(290_489_909, 9301) + // Standard Error: 864 + .saturating_add(Weight::from_parts(332_977, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -808,6 +835,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -823,10 +852,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `878 + r * (6 ±0)` // Estimated: `9294 + r * (6 ±0)` - // Minimum execution time: 254_997_000 picoseconds. - Weight::from_parts(284_331_894, 9294) - // Standard Error: 885 - .saturating_add(Weight::from_parts(337_073, 0).saturating_mul(r.into())) + // Minimum execution time: 273_291_000 picoseconds. + Weight::from_parts(293_650_716, 9294) + // Standard Error: 725 + .saturating_add(Weight::from_parts(323_281, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -835,6 +864,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -850,10 +881,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `875 + r * (6 ±0)` // Estimated: `9297 + r * (6 ±0)` - // Minimum execution time: 273_845_000 picoseconds. - Weight::from_parts(285_291_242, 9297) - // Standard Error: 690 - .saturating_add(Weight::from_parts(332_783, 0).saturating_mul(r.into())) + // Minimum execution time: 282_061_000 picoseconds. + Weight::from_parts(291_729_751, 9297) + // Standard Error: 929 + .saturating_add(Weight::from_parts(324_683, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -862,6 +893,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -877,10 +910,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `866 + r * (6 ±0)` // Estimated: `9282 + r * (6 ±0)` - // Minimum execution time: 268_302_000 picoseconds. - Weight::from_parts(280_463_257, 9282) - // Standard Error: 1_035 - .saturating_add(Weight::from_parts(345_811, 0).saturating_mul(r.into())) + // Minimum execution time: 264_505_000 picoseconds. + Weight::from_parts(293_440_286, 9282) + // Standard Error: 704 + .saturating_add(Weight::from_parts(329_851, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -889,6 +922,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -906,10 +941,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `940 + r * (14 ±0)` // Estimated: `9350 + r * (14 ±0)` - // Minimum execution time: 263_433_000 picoseconds. - Weight::from_parts(290_098_370, 9350) - // Standard Error: 1_905 - .saturating_add(Weight::from_parts(805_299, 0).saturating_mul(r.into())) + // Minimum execution time: 277_208_000 picoseconds. + Weight::from_parts(304_294_691, 9350) + // Standard Error: 1_083 + .saturating_add(Weight::from_parts(824_245, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 14).saturating_mul(r.into())) @@ -918,6 +953,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -933,10 +970,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `868 + r * (6 ±0)` // Estimated: `9285 + r * (6 ±0)` - // Minimum execution time: 273_588_000 picoseconds. - Weight::from_parts(287_133_565, 9285) - // Standard Error: 799 - .saturating_add(Weight::from_parts(254_114, 0).saturating_mul(r.into())) + // Minimum execution time: 278_293_000 picoseconds. + Weight::from_parts(289_743_005, 9285) + // Standard Error: 672 + .saturating_add(Weight::from_parts(267_553, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -945,6 +982,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -960,10 +999,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `872` // Estimated: `9287` - // Minimum execution time: 257_843_000 picoseconds. - Weight::from_parts(228_177_495, 9287) - // Standard Error: 24 - .saturating_add(Weight::from_parts(985, 0).saturating_mul(n.into())) + // Minimum execution time: 279_495_000 picoseconds. + Weight::from_parts(232_736_994, 9287) + // Standard Error: 23 + .saturating_add(Weight::from_parts(1_008, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -971,6 +1010,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -986,10 +1027,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `856 + r * (45 ±0)` // Estimated: `9271 + r * (45 ±0)` - // Minimum execution time: 248_332_000 picoseconds. - Weight::from_parts(274_998_906, 9271) - // Standard Error: 949_561 - .saturating_add(Weight::from_parts(5_570_693, 0).saturating_mul(r.into())) + // Minimum execution time: 257_920_000 picoseconds. + Weight::from_parts(282_276_265, 9271) + // Standard Error: 948_490 + .saturating_add(Weight::from_parts(2_408_134, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 45).saturating_mul(r.into())) @@ -998,6 +1039,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1013,10 +1056,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `866` // Estimated: `9288` - // Minimum execution time: 272_055_000 picoseconds. - Weight::from_parts(282_280_090, 9288) - // Standard Error: 1 - .saturating_add(Weight::from_parts(330, 0).saturating_mul(n.into())) + // Minimum execution time: 278_149_000 picoseconds. + Weight::from_parts(287_020_337, 9288) + // Standard Error: 0 + .saturating_add(Weight::from_parts(321, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1024,9 +1067,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:3 w:3) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:1 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) - /// Storage: `Contracts::CodeInfoOf` (r:2 w:2) + /// Storage: `Contracts::CodeInfoOf` (r:33 w:33) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Contracts::PristineCode` (r:1 w:0) /// Proof: `Contracts::PristineCode` (`max_values`: None, `max_size`: Some(125988), added: 128463, mode: `Measured`) @@ -1037,28 +1082,30 @@ impl WeightInfo for SubstrateWeight { /// Storage: `System::EventTopics` (r:4 w:4) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) /// Storage: `Contracts::DeletionQueue` (r:0 w:1) /// Proof: `Contracts::DeletionQueue` (`max_values`: None, `max_size`: Some(142), added: 2617, mode: `Measured`) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2902 + r * (529 ±0)` - // Estimated: `11317 + r * (5479 ±0)` - // Minimum execution time: 274_842_000 picoseconds. - Weight::from_parts(299_824_497, 11317) - // Standard Error: 902_686 - .saturating_add(Weight::from_parts(106_562_902, 0).saturating_mul(r.into())) + // Measured: `4805 + r * (2121 ±0)` + // Estimated: `13220 + r * (81321 ±0)` + // Minimum execution time: 307_763_000 picoseconds. + Weight::from_parts(323_648_618, 13220) + // Standard Error: 879_890 + .saturating_add(Weight::from_parts(249_045_481, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) - .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().reads((36_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) - .saturating_add(T::DbWeight::get().writes((10_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 5266).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().writes((41_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 81321).saturating_mul(r.into())) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1076,10 +1123,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `947 + r * (10 ±0)` // Estimated: `9363 + r * (10 ±0)` - // Minimum execution time: 255_393_000 picoseconds. - Weight::from_parts(309_814_338, 9363) - // Standard Error: 2_978 - .saturating_add(Weight::from_parts(1_203_507, 0).saturating_mul(r.into())) + // Minimum execution time: 278_400_000 picoseconds. + Weight::from_parts(293_743_000, 9363) + // Standard Error: 1_686 + .saturating_add(Weight::from_parts(1_288_603, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 10).saturating_mul(r.into())) @@ -1088,6 +1135,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1103,10 +1152,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `866 + r * (10 ±0)` // Estimated: `9283 + r * (10 ±0)` - // Minimum execution time: 250_378_000 picoseconds. - Weight::from_parts(287_003_144, 9283) - // Standard Error: 2_726 - .saturating_add(Weight::from_parts(1_850_967, 0).saturating_mul(r.into())) + // Minimum execution time: 272_110_000 picoseconds. + Weight::from_parts(295_620_726, 9283) + // Standard Error: 5_481 + .saturating_add(Weight::from_parts(2_031_955, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 10).saturating_mul(r.into())) @@ -1115,6 +1164,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1131,12 +1182,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `883 + t * (32 ±0)` // Estimated: `9303 + t * (2508 ±0)` - // Minimum execution time: 266_787_000 picoseconds. - Weight::from_parts(284_368_661, 9303) - // Standard Error: 121_315 - .saturating_add(Weight::from_parts(2_690_211, 0).saturating_mul(t.into())) - // Standard Error: 33 - .saturating_add(Weight::from_parts(789, 0).saturating_mul(n.into())) + // Minimum execution time: 277_409_000 picoseconds. + Weight::from_parts(293_838_037, 9303) + // Standard Error: 87_977 + .saturating_add(Weight::from_parts(2_911_340, 0).saturating_mul(t.into())) + // Standard Error: 24 + .saturating_add(Weight::from_parts(531, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1147,6 +1198,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1162,10 +1215,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `865 + r * (7 ±0)` // Estimated: `9285 + r * (7 ±0)` - // Minimum execution time: 166_804_000 picoseconds. - Weight::from_parts(175_118_291, 9285) - // Standard Error: 398 - .saturating_add(Weight::from_parts(220_961, 0).saturating_mul(r.into())) + // Minimum execution time: 172_634_000 picoseconds. + Weight::from_parts(183_322_840, 9285) + // Standard Error: 384 + .saturating_add(Weight::from_parts(226_007, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 7).saturating_mul(r.into())) @@ -1174,6 +1227,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `MaxEncodedLen`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1189,10 +1244,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `125816` // Estimated: `131758` - // Minimum execution time: 398_436_000 picoseconds. - Weight::from_parts(385_003_285, 131758) + // Minimum execution time: 425_713_000 picoseconds. + Weight::from_parts(394_260_924, 131758) // Standard Error: 12 - .saturating_add(Weight::from_parts(1_038, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_032, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1203,10 +1258,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `927 + r * (292 ±0)` // Estimated: `929 + r * (293 ±0)` - // Minimum execution time: 274_099_000 picoseconds. - Weight::from_parts(174_282_817, 929) - // Standard Error: 10_547 - .saturating_add(Weight::from_parts(6_262_173, 0).saturating_mul(r.into())) + // Minimum execution time: 268_128_000 picoseconds. + Weight::from_parts(186_787_113, 929) + // Standard Error: 10_796 + .saturating_add(Weight::from_parts(6_454_780, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1220,10 +1275,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1450` // Estimated: `1433` - // Minimum execution time: 274_061_000 picoseconds. - Weight::from_parts(334_755_333, 1433) - // Standard Error: 66 - .saturating_add(Weight::from_parts(771, 0).saturating_mul(n.into())) + // Minimum execution time: 286_565_000 picoseconds. + Weight::from_parts(349_504_932, 1433) + // Standard Error: 70 + .saturating_add(Weight::from_parts(530, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(15_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } @@ -1234,8 +1289,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1256 + n * (1 ±0)` // Estimated: `1256 + n * (1 ±0)` - // Minimum execution time: 272_657_000 picoseconds. - Weight::from_parts(299_061_594, 1256) + // Minimum execution time: 282_478_000 picoseconds. + Weight::from_parts(303_448_260, 1256) + // Standard Error: 34 + .saturating_add(Weight::from_parts(712, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1247,10 +1304,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `924 + r * (288 ±0)` // Estimated: `930 + r * (289 ±0)` - // Minimum execution time: 270_524_000 picoseconds. - Weight::from_parts(177_959_667, 930) - // Standard Error: 10_397 - .saturating_add(Weight::from_parts(6_270_181, 0).saturating_mul(r.into())) + // Minimum execution time: 271_793_000 picoseconds. + Weight::from_parts(179_158_648, 930) + // Standard Error: 11_868 + .saturating_add(Weight::from_parts(6_397_986, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1264,8 +1321,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1252 + n * (1 ±0)` // Estimated: `1252 + n * (1 ±0)` - // Minimum execution time: 270_757_000 picoseconds. - Weight::from_parts(298_627_896, 1252) + // Minimum execution time: 273_945_000 picoseconds. + Weight::from_parts(299_855_996, 1252) + // Standard Error: 31 + .saturating_add(Weight::from_parts(309, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1277,10 +1336,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `924 + r * (296 ±0)` // Estimated: `926 + r * (297 ±0)` - // Minimum execution time: 268_082_000 picoseconds. - Weight::from_parts(202_583_730, 926) - // Standard Error: 9_029 - .saturating_add(Weight::from_parts(5_028_517, 0).saturating_mul(r.into())) + // Minimum execution time: 275_285_000 picoseconds. + Weight::from_parts(207_735_572, 926) + // Standard Error: 9_736 + .saturating_add(Weight::from_parts(5_162_837, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1293,10 +1352,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1268 + n * (1 ±0)` // Estimated: `1268 + n * (1 ±0)` - // Minimum execution time: 274_100_000 picoseconds. - Weight::from_parts(296_981_515, 1268) + // Minimum execution time: 278_929_000 picoseconds. + Weight::from_parts(302_251_674, 1268) // Standard Error: 34 - .saturating_add(Weight::from_parts(578, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(583, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1308,10 +1367,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `935 + r * (288 ±0)` // Estimated: `932 + r * (289 ±0)` - // Minimum execution time: 269_697_000 picoseconds. - Weight::from_parts(198_346_516, 932) - // Standard Error: 8_623 - .saturating_add(Weight::from_parts(4_964_116, 0).saturating_mul(r.into())) + // Minimum execution time: 258_476_000 picoseconds. + Weight::from_parts(209_578_051, 932) + // Standard Error: 8_255 + .saturating_add(Weight::from_parts(4_942_572, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1324,10 +1383,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1255 + n * (1 ±0)` // Estimated: `1255 + n * (1 ±0)` - // Minimum execution time: 264_210_000 picoseconds. - Weight::from_parts(291_387_652, 1255) - // Standard Error: 36 - .saturating_add(Weight::from_parts(524, 0).saturating_mul(n.into())) + // Minimum execution time: 273_089_000 picoseconds. + Weight::from_parts(302_452_604, 1255) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1339,10 +1396,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `917 + r * (296 ±0)` // Estimated: `922 + r * (297 ±0)` - // Minimum execution time: 267_219_000 picoseconds. - Weight::from_parts(175_866_982, 922) - // Standard Error: 11_275 - .saturating_add(Weight::from_parts(6_424_755, 0).saturating_mul(r.into())) + // Minimum execution time: 274_301_000 picoseconds. + Weight::from_parts(172_245_469, 922) + // Standard Error: 11_306 + .saturating_add(Weight::from_parts(6_526_825, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1356,10 +1413,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1269 + n * (1 ±0)` // Estimated: `1269 + n * (1 ±0)` - // Minimum execution time: 274_634_000 picoseconds. - Weight::from_parts(294_272_009, 1269) + // Minimum execution time: 280_399_000 picoseconds. + Weight::from_parts(305_970_974, 1269) // Standard Error: 36 - .saturating_add(Weight::from_parts(1_219, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(568, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1368,6 +1425,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1602 w:1601) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1383,10 +1442,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1418 + r * (45 ±0)` // Estimated: `9785 + r * (2520 ±0)` - // Minimum execution time: 266_833_000 picoseconds. - Weight::from_parts(186_049_741, 9785) - // Standard Error: 40_311 - .saturating_add(Weight::from_parts(31_365_585, 0).saturating_mul(r.into())) + // Minimum execution time: 258_452_000 picoseconds. + Weight::from_parts(276_401_000, 9785) + // Standard Error: 65_648 + .saturating_add(Weight::from_parts(33_890_852, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -1397,6 +1456,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:801 w:801) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:2 w:0) @@ -1412,10 +1473,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1263 + r * (245 ±0)` // Estimated: `9635 + r * (2721 ±0)` - // Minimum execution time: 272_140_000 picoseconds. - Weight::from_parts(275_009_000, 9635) - // Standard Error: 99_187 - .saturating_add(Weight::from_parts(240_702_479, 0).saturating_mul(r.into())) + // Minimum execution time: 281_394_000 picoseconds. + Weight::from_parts(286_475_000, 9635) + // Standard Error: 156_302 + .saturating_add(Weight::from_parts(250_370_283, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(14_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -1426,6 +1487,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:736 w:0) @@ -1441,10 +1504,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0 + r * (576 ±0)` // Estimated: `9290 + r * (2637 ±10)` - // Minimum execution time: 263_664_000 picoseconds. - Weight::from_parts(277_240_000, 9290) - // Standard Error: 169_147 - .saturating_add(Weight::from_parts(240_084_929, 0).saturating_mul(r.into())) + // Minimum execution time: 278_193_000 picoseconds. + Weight::from_parts(280_814_000, 9290) + // Standard Error: 164_401 + .saturating_add(Weight::from_parts(251_272_834, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1455,6 +1518,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:3 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:2 w:2) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:2 w:0) @@ -1471,12 +1536,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1310 + t * (277 ±0)` // Estimated: `12200 + t * (5227 ±0)` - // Minimum execution time: 464_644_000 picoseconds. - Weight::from_parts(40_377_313, 12200) - // Standard Error: 12_060_226 - .saturating_add(Weight::from_parts(380_635_982, 0).saturating_mul(t.into())) + // Minimum execution time: 476_812_000 picoseconds. + Weight::from_parts(70_715_306, 12200) + // Standard Error: 12_232_109 + .saturating_add(Weight::from_parts(374_277_042, 0).saturating_mul(t.into())) // Standard Error: 17 - .saturating_add(Weight::from_parts(1_014, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(1_022, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(16_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) @@ -1487,6 +1552,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:802 w:802) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:801 w:801) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:801 w:800) @@ -1500,16 +1567,16 @@ impl WeightInfo for SubstrateWeight { /// Storage: `System::EventTopics` (r:803 w:803) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:800 w:800) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) /// The range of component `r` is `[1, 800]`. fn seal_instantiate(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1281 + r * (255 ±0)` // Estimated: `9623 + r * (2731 ±0)` - // Minimum execution time: 641_845_000 picoseconds. - Weight::from_parts(649_908_000, 9623) - // Standard Error: 278_514 - .saturating_add(Weight::from_parts(361_164_598, 0).saturating_mul(r.into())) + // Minimum execution time: 656_480_000 picoseconds. + Weight::from_parts(668_579_000, 9623) + // Standard Error: 365_458 + .saturating_add(Weight::from_parts(379_238_223, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(14_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(7_u64)) @@ -1520,6 +1587,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:3 w:3) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:2 w:2) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:2 w:1) @@ -1533,7 +1602,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `System::EventTopics` (r:4 w:4) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) /// The range of component `t` is `[0, 1]`. /// The range of component `i` is `[0, 983040]`. /// The range of component `s` is `[0, 983040]`. @@ -1541,12 +1610,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1306 + t * (104 ±0)` // Estimated: `12214 + t * (2549 ±1)` - // Minimum execution time: 2_111_632_000 picoseconds. - Weight::from_parts(1_213_125_745, 12214) - // Standard Error: 22 - .saturating_add(Weight::from_parts(1_055, 0).saturating_mul(i.into())) - // Standard Error: 22 - .saturating_add(Weight::from_parts(1_192, 0).saturating_mul(s.into())) + // Minimum execution time: 2_148_964_000 picoseconds. + Weight::from_parts(1_557_685_999, 12214) + // Standard Error: 36 + .saturating_add(Weight::from_parts(864, 0).saturating_mul(i.into())) + // Standard Error: 36 + .saturating_add(Weight::from_parts(1_092, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(19_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(11_u64)) @@ -1557,6 +1626,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1572,10 +1643,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `865 + r * (8 ±0)` // Estimated: `9279 + r * (8 ±0)` - // Minimum execution time: 264_227_000 picoseconds. - Weight::from_parts(281_015_995, 9279) - // Standard Error: 710 - .saturating_add(Weight::from_parts(365_734, 0).saturating_mul(r.into())) + // Minimum execution time: 279_377_000 picoseconds. + Weight::from_parts(287_951_287, 9279) + // Standard Error: 659 + .saturating_add(Weight::from_parts(376_476, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) @@ -1584,6 +1655,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1599,10 +1672,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `873` // Estimated: `9286` - // Minimum execution time: 270_709_000 picoseconds. - Weight::from_parts(268_416_051, 9286) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_080, 0).saturating_mul(n.into())) + // Minimum execution time: 276_151_000 picoseconds. + Weight::from_parts(267_656_959, 9286) + // Standard Error: 2 + .saturating_add(Weight::from_parts(1_108, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1610,6 +1683,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1625,10 +1700,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `867 + r * (8 ±0)` // Estimated: `9284 + r * (8 ±0)` - // Minimum execution time: 267_283_000 picoseconds. - Weight::from_parts(280_706_659, 9284) - // Standard Error: 540 - .saturating_add(Weight::from_parts(790_312, 0).saturating_mul(r.into())) + // Minimum execution time: 275_247_000 picoseconds. + Weight::from_parts(286_675_317, 9284) + // Standard Error: 601 + .saturating_add(Weight::from_parts(788_160, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) @@ -1637,6 +1712,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1652,10 +1729,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `875` // Estimated: `9292` - // Minimum execution time: 262_010_000 picoseconds. - Weight::from_parts(273_278_744, 9292) + // Minimum execution time: 281_585_000 picoseconds. + Weight::from_parts(287_637_844, 9292) // Standard Error: 1 - .saturating_add(Weight::from_parts(3_362, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_351, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1663,6 +1740,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1678,10 +1757,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `867 + r * (8 ±0)` // Estimated: `9286 + r * (8 ±0)` - // Minimum execution time: 268_698_000 picoseconds. - Weight::from_parts(282_890_578, 9286) - // Standard Error: 622 - .saturating_add(Weight::from_parts(441_131, 0).saturating_mul(r.into())) + // Minimum execution time: 273_678_000 picoseconds. + Weight::from_parts(289_879_306, 9286) + // Standard Error: 607 + .saturating_add(Weight::from_parts(439_482, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) @@ -1690,6 +1769,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1705,10 +1786,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `875` // Estimated: `9291` - // Minimum execution time: 252_846_000 picoseconds. - Weight::from_parts(267_657_561, 9291) + // Minimum execution time: 275_126_000 picoseconds. + Weight::from_parts(276_684_594, 9291) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_208, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_202, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1716,6 +1797,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1731,10 +1814,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `867 + r * (8 ±0)` // Estimated: `9283 + r * (8 ±0)` - // Minimum execution time: 266_899_000 picoseconds. - Weight::from_parts(276_862_067, 9283) - // Standard Error: 1_249 - .saturating_add(Weight::from_parts(443_970, 0).saturating_mul(r.into())) + // Minimum execution time: 273_229_000 picoseconds. + Weight::from_parts(287_793_841, 9283) + // Standard Error: 451 + .saturating_add(Weight::from_parts(447_922, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) @@ -1743,6 +1826,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1758,10 +1843,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `875` // Estimated: `9289` - // Minimum execution time: 265_413_000 picoseconds. - Weight::from_parts(265_600_840, 9289) + // Minimum execution time: 277_843_000 picoseconds. + Weight::from_parts(279_900_099, 9289) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_203, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_204, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1769,6 +1854,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1784,10 +1871,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1000 + n * (1 ±0)` // Estimated: `9412 + n * (1 ±0)` - // Minimum execution time: 328_341_000 picoseconds. - Weight::from_parts(341_038_581, 9412) - // Standard Error: 10 - .saturating_add(Weight::from_parts(5_863, 0).saturating_mul(n.into())) + // Minimum execution time: 331_840_000 picoseconds. + Weight::from_parts(338_767_191, 9412) + // Standard Error: 11 + .saturating_add(Weight::from_parts(5_971, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1796,6 +1883,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1811,10 +1900,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `808 + r * (112 ±0)` // Estimated: `9226 + r * (112 ±0)` - // Minimum execution time: 272_730_000 picoseconds. - Weight::from_parts(339_349_232, 9226) - // Standard Error: 13_004 - .saturating_add(Weight::from_parts(41_649_026, 0).saturating_mul(r.into())) + // Minimum execution time: 277_912_000 picoseconds. + Weight::from_parts(344_538_960, 9226) + // Standard Error: 13_422 + .saturating_add(Weight::from_parts(41_592_887, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 112).saturating_mul(r.into())) @@ -1823,6 +1912,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1838,10 +1929,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `910 + r * (76 ±0)` // Estimated: `9279 + r * (77 ±0)` - // Minimum execution time: 273_892_000 picoseconds. - Weight::from_parts(352_853_960, 9279) - // Standard Error: 16_745 - .saturating_add(Weight::from_parts(45_853_294, 0).saturating_mul(r.into())) + // Minimum execution time: 280_383_000 picoseconds. + Weight::from_parts(348_542_377, 9279) + // Standard Error: 13_985 + .saturating_add(Weight::from_parts(45_983_827, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 77).saturating_mul(r.into())) @@ -1850,6 +1941,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1865,10 +1958,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `880 + r * (42 ±0)` // Estimated: `9294 + r * (42 ±0)` - // Minimum execution time: 268_431_000 picoseconds. - Weight::from_parts(319_727_796, 9294) - // Standard Error: 10_276 - .saturating_add(Weight::from_parts(11_928_882, 0).saturating_mul(r.into())) + // Minimum execution time: 277_764_000 picoseconds. + Weight::from_parts(320_288_180, 9294) + // Standard Error: 10_140 + .saturating_add(Weight::from_parts(12_046_137, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 42).saturating_mul(r.into())) @@ -1877,6 +1970,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1536 w:1536) @@ -1892,10 +1987,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0 + r * (965 ±0)` // Estimated: `9285 + r * (3090 ±7)` - // Minimum execution time: 275_482_000 picoseconds. - Weight::from_parts(279_155_000, 9285) - // Standard Error: 65_388 - .saturating_add(Weight::from_parts(26_634_187, 0).saturating_mul(r.into())) + // Minimum execution time: 271_356_000 picoseconds. + Weight::from_parts(282_924_000, 9285) + // Standard Error: 60_493 + .saturating_add(Weight::from_parts(28_319_267, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1906,6 +2001,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:33 w:32) @@ -1921,20 +2018,22 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `937 + r * (131 ±0)` // Estimated: `9346 + r * (2607 ±0)` - // Minimum execution time: 270_001_000 picoseconds. - Weight::from_parts(286_792_689, 9346) - // Standard Error: 21_074 - .saturating_add(Weight::from_parts(6_465_885, 0).saturating_mul(r.into())) + // Minimum execution time: 269_698_000 picoseconds. + Weight::from_parts(294_325_127, 9346) + // Standard Error: 22_352 + .saturating_add(Weight::from_parts(6_744_117, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 2606).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2607).saturating_mul(r.into())) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `MaxEncodedLen`) /// Storage: `Contracts::CodeInfoOf` (r:33 w:32) @@ -1948,12 +2047,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 32]`. fn unlock_delegate_dependency(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `969 + r * (183 ±0)` + // Measured: `972 + r * (184 ±0)` // Estimated: `129453 + r * (2568 ±0)` - // Minimum execution time: 270_652_000 picoseconds. - Weight::from_parts(293_369_452, 129453) - // Standard Error: 24_321 - .saturating_add(Weight::from_parts(5_575_600, 0).saturating_mul(r.into())) + // Minimum execution time: 261_226_000 picoseconds. + Weight::from_parts(294_299_527, 129453) + // Standard Error: 27_898 + .saturating_add(Weight::from_parts(6_031_601, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -1964,6 +2063,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -1979,10 +2080,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `861 + r * (3 ±0)` // Estimated: `9282 + r * (3 ±0)` - // Minimum execution time: 267_749_000 picoseconds. - Weight::from_parts(280_373_341, 9282) - // Standard Error: 464 - .saturating_add(Weight::from_parts(170_398, 0).saturating_mul(r.into())) + // Minimum execution time: 270_729_000 picoseconds. + Weight::from_parts(289_622_807, 9282) + // Standard Error: 394 + .saturating_add(Weight::from_parts(167_010, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) @@ -1991,6 +2092,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2006,10 +2109,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2112 + r * (39 ±0)` // Estimated: `10377 + r * (40 ±0)` - // Minimum execution time: 270_260_000 picoseconds. - Weight::from_parts(337_969_172, 10377) - // Standard Error: 1_557 - .saturating_add(Weight::from_parts(305_735, 0).saturating_mul(r.into())) + // Minimum execution time: 272_228_000 picoseconds. + Weight::from_parts(351_059_276, 10377) + // Standard Error: 1_761 + .saturating_add(Weight::from_parts(312_269, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -2018,6 +2121,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2035,10 +2140,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `864 + r * (3 ±0)` // Estimated: `9279 + r * (3 ±0)` - // Minimum execution time: 265_607_000 picoseconds. - Weight::from_parts(283_396_630, 9279) - // Standard Error: 449 - .saturating_add(Weight::from_parts(149_018, 0).saturating_mul(r.into())) + // Minimum execution time: 272_497_000 picoseconds. + Weight::from_parts(288_213_060, 9279) + // Standard Error: 469 + .saturating_add(Weight::from_parts(155_530, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) @@ -2048,10 +2153,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_813_000 picoseconds. - Weight::from_parts(1_264_945, 0) - // Standard Error: 19 - .saturating_add(Weight::from_parts(15_098, 0).saturating_mul(r.into())) + // Minimum execution time: 1_990_000 picoseconds. + Weight::from_parts(1_778_221, 0) + // Standard Error: 26 + .saturating_add(Weight::from_parts(14_888, 0).saturating_mul(r.into())) } } @@ -2063,8 +2168,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1627` - // Minimum execution time: 2_054_000 picoseconds. - Weight::from_parts(2_178_000, 1627) + // Minimum execution time: 2_130_000 picoseconds. + Weight::from_parts(2_247_000, 1627) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -2074,10 +2179,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `452 + k * (69 ±0)` // Estimated: `442 + k * (70 ±0)` - // Minimum execution time: 12_119_000 picoseconds. - Weight::from_parts(12_536_000, 442) - // Standard Error: 1_254 - .saturating_add(Weight::from_parts(1_161_885, 0).saturating_mul(k.into())) + // Minimum execution time: 12_748_000 picoseconds. + Weight::from_parts(13_001_000, 442) + // Standard Error: 1_206 + .saturating_add(Weight::from_parts(1_146_159, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -2091,10 +2196,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `211 + c * (1 ±0)` // Estimated: `6149 + c * (1 ±0)` - // Minimum execution time: 8_146_000 picoseconds. - Weight::from_parts(8_560_745, 6149) + // Minimum execution time: 8_636_000 picoseconds. + Weight::from_parts(8_664_917, 6149) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_182, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(1_188, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) @@ -2107,8 +2212,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `510` // Estimated: `6450` - // Minimum execution time: 16_183_000 picoseconds. - Weight::from_parts(16_825_000, 6450) + // Minimum execution time: 16_838_000 picoseconds. + Weight::from_parts(17_400_000, 6450) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -2121,10 +2226,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `171 + k * (1 ±0)` // Estimated: `3635 + k * (1 ±0)` - // Minimum execution time: 3_645_000 picoseconds. - Weight::from_parts(604_365, 3635) - // Standard Error: 1_013 - .saturating_add(Weight::from_parts(1_100_277, 0).saturating_mul(k.into())) + // Minimum execution time: 3_876_000 picoseconds. + Weight::from_parts(2_654_935, 3635) + // Standard Error: 2_001 + .saturating_add(Weight::from_parts(1_258_085, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -2134,6 +2239,8 @@ impl WeightInfo for () { /// Proof: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc553053f13fd319a03c211337c76e0fe776df` (r:2 w:0) /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc553022fca90611ba8b7942f8bdb3b97f6580` (r:1 w:1) /// Proof: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc553022fca90611ba8b7942f8bdb3b97f6580` (r:1 w:1) + /// Storage: `Parameters::Parameters` (r:2 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:0 w:1) @@ -2143,10 +2250,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `328 + c * (1 ±0)` // Estimated: `6266 + c * (1 ±0)` - // Minimum execution time: 19_500_000 picoseconds. - Weight::from_parts(20_074_895, 6266) + // Minimum execution time: 21_038_000 picoseconds. + Weight::from_parts(20_890_548, 6266) // Standard Error: 1 - .saturating_add(Weight::from_parts(422, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(435, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) @@ -2157,8 +2264,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `440` // Estimated: `6380` - // Minimum execution time: 12_530_000 picoseconds. - Weight::from_parts(13_362_000, 6380) + // Minimum execution time: 12_579_000 picoseconds. + Weight::from_parts(13_486_000, 6380) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -2167,13 +2274,13 @@ impl WeightInfo for () { /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:0) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) fn v14_migration_step() -> Weight { // Proof Size summary in bytes: // Measured: `352` // Estimated: `6292` - // Minimum execution time: 44_275_000 picoseconds. - Weight::from_parts(45_718_000, 6292) + // Minimum execution time: 47_123_000 picoseconds. + Weight::from_parts(48_284_000, 6292) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -2185,8 +2292,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `594` // Estimated: `6534` - // Minimum execution time: 55_095_000 picoseconds. - Weight::from_parts(58_009_000, 6534) + // Minimum execution time: 55_237_000 picoseconds. + Weight::from_parts(57_996_000, 6534) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -2196,8 +2303,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1627` - // Minimum execution time: 2_455_000 picoseconds. - Weight::from_parts(2_608_000, 1627) + // Minimum execution time: 2_766_000 picoseconds. + Weight::from_parts(2_807_000, 1627) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -2209,8 +2316,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `166` // Estimated: `3631` - // Minimum execution time: 11_207_000 picoseconds. - Weight::from_parts(11_802_000, 3631) + // Minimum execution time: 12_243_000 picoseconds. + Weight::from_parts(12_890_000, 3631) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -2220,8 +2327,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 4_581_000 picoseconds. - Weight::from_parts(4_781_000, 3607) + // Minimum execution time: 4_951_000 picoseconds. + Weight::from_parts(5_232_000, 3607) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc55304e7b9012096b41c4eb3aaf947f6ea429` (r:1 w:0) @@ -2232,8 +2339,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `167` // Estimated: `3632` - // Minimum execution time: 5_887_000 picoseconds. - Weight::from_parts(6_393_000, 3632) + // Minimum execution time: 6_530_000 picoseconds. + Weight::from_parts(6_726_000, 3632) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc55304e7b9012096b41c4eb3aaf947f6ea429` (r:1 w:0) @@ -2244,13 +2351,15 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 6_025_000 picoseconds. - Weight::from_parts(6_298_000, 3607) + // Minimum execution time: 6_227_000 picoseconds. + Weight::from_parts(6_708_000, 3607) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2268,20 +2377,22 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `804 + c * (1 ±0)` // Estimated: `9217 + c * (1 ±0)` - // Minimum execution time: 294_976_000 picoseconds. - Weight::from_parts(277_235_948, 9217) - // Standard Error: 65 - .saturating_add(Weight::from_parts(34_445, 0).saturating_mul(c.into())) + // Minimum execution time: 309_889_000 picoseconds. + Weight::from_parts(277_084_159, 9217) + // Standard Error: 71 + .saturating_add(Weight::from_parts(33_471, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:1) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Balances::Holds` (r:2 w:2) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) /// Storage: `System::EventTopics` (r:3 w:3) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Contracts::Nonce` (r:1 w:1) @@ -2301,14 +2412,14 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `326` // Estimated: `8740` - // Minimum execution time: 3_864_558_000 picoseconds. - Weight::from_parts(421_676_889, 8740) - // Standard Error: 188 - .saturating_add(Weight::from_parts(103_788, 0).saturating_mul(c.into())) - // Standard Error: 22 - .saturating_add(Weight::from_parts(1_715, 0).saturating_mul(i.into())) - // Standard Error: 22 - .saturating_add(Weight::from_parts(1_774, 0).saturating_mul(s.into())) + // Minimum execution time: 3_909_680_000 picoseconds. + Weight::from_parts(446_471_160, 8740) + // Standard Error: 159 + .saturating_add(Weight::from_parts(101_085, 0).saturating_mul(c.into())) + // Standard Error: 19 + .saturating_add(Weight::from_parts(1_598, 0).saturating_mul(i.into())) + // Standard Error: 19 + .saturating_add(Weight::from_parts(1_879, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(14_u64)) .saturating_add(RocksDbWeight::get().writes(10_u64)) } @@ -2318,6 +2429,8 @@ impl WeightInfo for () { /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Contracts::PristineCode` (r:1 w:0) /// Proof: `Contracts::PristineCode` (`max_values`: None, `max_size`: Some(125988), added: 128463, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::Nonce` (r:1 w:1) /// Proof: `Contracts::Nonce` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) @@ -2329,24 +2442,26 @@ impl WeightInfo for () { /// Storage: `System::EventTopics` (r:2 w:2) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) /// The range of component `i` is `[0, 1048576]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate(i: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `563` // Estimated: `8982` - // Minimum execution time: 2_069_276_000 picoseconds. - Weight::from_parts(377_210_279, 8982) - // Standard Error: 9 - .saturating_add(Weight::from_parts(1_719, 0).saturating_mul(i.into())) - // Standard Error: 9 - .saturating_add(Weight::from_parts(1_728, 0).saturating_mul(s.into())) + // Minimum execution time: 1_968_545_000 picoseconds. + Weight::from_parts(420_048_028, 8982) + // Standard Error: 20 + .saturating_add(Weight::from_parts(1_685, 0).saturating_mul(i.into())) + // Standard Error: 20 + .saturating_add(Weight::from_parts(1_645, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2363,17 +2478,19 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `829` // Estimated: `9244` - // Minimum execution time: 199_037_000 picoseconds. - Weight::from_parts(213_931_000, 9244) + // Minimum execution time: 207_564_000 picoseconds. + Weight::from_parts(216_983_000, 9244) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:2 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:1) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) /// Storage: `System::EventTopics` (r:1 w:1) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Contracts::PristineCode` (r:0 w:1) @@ -2383,10 +2500,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `145` // Estimated: `6085` - // Minimum execution time: 278_482_000 picoseconds. - Weight::from_parts(262_753_879, 6085) - // Standard Error: 112 - .saturating_add(Weight::from_parts(66_129, 0).saturating_mul(c.into())) + // Minimum execution time: 273_555_000 picoseconds. + Weight::from_parts(257_517_935, 6085) + // Standard Error: 148 + .saturating_add(Weight::from_parts(64_488, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2407,10 +2524,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `145` // Estimated: `6085` - // Minimum execution time: 286_902_000 picoseconds. - Weight::from_parts(269_003_959, 6085) - // Standard Error: 123 - .saturating_add(Weight::from_parts(66_629, 0).saturating_mul(c.into())) + // Minimum execution time: 289_672_000 picoseconds. + Weight::from_parts(297_020_278, 6085) + // Standard Error: 86 + .saturating_add(Weight::from_parts(64_340, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2419,7 +2536,7 @@ impl WeightInfo for () { /// Storage: `Contracts::CodeInfoOf` (r:1 w:1) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) /// Storage: `System::EventTopics` (r:1 w:1) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Contracts::PristineCode` (r:0 w:1) @@ -2428,8 +2545,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `315` // Estimated: `3780` - // Minimum execution time: 44_128_000 picoseconds. - Weight::from_parts(46_044_000, 3780) + // Minimum execution time: 45_930_000 picoseconds. + Weight::from_parts(47_288_000, 3780) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -2445,8 +2562,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `552` // Estimated: `8967` - // Minimum execution time: 33_567_000 picoseconds. - Weight::from_parts(35_057_000, 8967) + // Minimum execution time: 35_421_000 picoseconds. + Weight::from_parts(36_909_000, 8967) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -2454,6 +2571,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2469,10 +2588,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `869 + r * (6 ±0)` // Estimated: `9284 + r * (6 ±0)` - // Minimum execution time: 272_376_000 picoseconds. - Weight::from_parts(284_162_161, 9284) - // Standard Error: 501 - .saturating_add(Weight::from_parts(341_575, 0).saturating_mul(r.into())) + // Minimum execution time: 275_531_000 picoseconds. + Weight::from_parts(292_269_656, 9284) + // Standard Error: 672 + .saturating_add(Weight::from_parts(339_728, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -2481,6 +2600,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1601 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2496,10 +2617,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `925 + r * (209 ±0)` // Estimated: `9304 + r * (2684 ±0)` - // Minimum execution time: 256_990_000 picoseconds. - Weight::from_parts(107_167_044, 9304) - // Standard Error: 7_545 - .saturating_add(Weight::from_parts(3_628_112, 0).saturating_mul(r.into())) + // Minimum execution time: 275_829_000 picoseconds. + Weight::from_parts(124_543_289, 9304) + // Standard Error: 6_085 + .saturating_add(Weight::from_parts(3_702_964, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2509,6 +2630,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1601 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2524,10 +2647,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `924 + r * (213 ±0)` // Estimated: `9308 + r * (2688 ±0)` - // Minimum execution time: 272_889_000 picoseconds. - Weight::from_parts(110_341_799, 9308) - // Standard Error: 7_881 - .saturating_add(Weight::from_parts(4_427_043, 0).saturating_mul(r.into())) + // Minimum execution time: 276_666_000 picoseconds. + Weight::from_parts(96_951_288, 9308) + // Standard Error: 8_876 + .saturating_add(Weight::from_parts(4_604_699, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2537,6 +2660,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2552,10 +2677,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `876 + r * (6 ±0)` // Estimated: `9293 + r * (6 ±0)` - // Minimum execution time: 275_027_000 picoseconds. - Weight::from_parts(283_302_223, 9293) - // Standard Error: 1_179 - .saturating_add(Weight::from_parts(436_023, 0).saturating_mul(r.into())) + // Minimum execution time: 271_301_000 picoseconds. + Weight::from_parts(284_126_054, 9293) + // Standard Error: 886 + .saturating_add(Weight::from_parts(437_127, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -2564,6 +2689,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2579,16 +2706,18 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `866 + r * (3 ±0)` // Estimated: `9282 + r * (3 ±0)` - // Minimum execution time: 270_137_000 picoseconds. - Weight::from_parts(282_756_362, 9282) - // Standard Error: 384 - .saturating_add(Weight::from_parts(171_660, 0).saturating_mul(r.into())) + // Minimum execution time: 274_778_000 picoseconds. + Weight::from_parts(289_355_269, 9282) + // Standard Error: 382 + .saturating_add(Weight::from_parts(175_342, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2604,10 +2733,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `756 + r * (3 ±0)` // Estimated: `9171 + r * (3 ±0)` - // Minimum execution time: 255_131_000 picoseconds. - Weight::from_parts(269_207_006, 9171) - // Standard Error: 542 - .saturating_add(Weight::from_parts(161_597, 0).saturating_mul(r.into())) + // Minimum execution time: 257_310_000 picoseconds. + Weight::from_parts(276_410_847, 9171) + // Standard Error: 733 + .saturating_add(Weight::from_parts(160_094, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(10_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) @@ -2616,6 +2745,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2631,10 +2762,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `870 + r * (6 ±0)` // Estimated: `9285 + r * (6 ±0)` - // Minimum execution time: 272_172_000 picoseconds. - Weight::from_parts(283_747_134, 9285) - // Standard Error: 885 - .saturating_add(Weight::from_parts(343_968, 0).saturating_mul(r.into())) + // Minimum execution time: 278_305_000 picoseconds. + Weight::from_parts(282_372_935, 9285) + // Standard Error: 1_154 + .saturating_add(Weight::from_parts(343_382, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -2643,6 +2774,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2658,10 +2791,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `866 + r * (6 ±0)` // Estimated: `9284 + r * (6 ±0)` - // Minimum execution time: 263_220_000 picoseconds. - Weight::from_parts(277_062_382, 9284) - // Standard Error: 1_783 - .saturating_add(Weight::from_parts(399_631, 0).saturating_mul(r.into())) + // Minimum execution time: 280_349_000 picoseconds. + Weight::from_parts(294_864_875, 9284) + // Standard Error: 1_010 + .saturating_add(Weight::from_parts(368_740, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -2670,6 +2803,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:2 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2685,10 +2820,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1010 + r * (6 ±0)` // Estimated: `9409 + r * (6 ±0)` - // Minimum execution time: 253_218_000 picoseconds. - Weight::from_parts(282_251_452, 9409) - // Standard Error: 2_367 - .saturating_add(Weight::from_parts(1_604_060, 0).saturating_mul(r.into())) + // Minimum execution time: 274_578_000 picoseconds. + Weight::from_parts(313_285_034, 9409) + // Standard Error: 2_800 + .saturating_add(Weight::from_parts(1_653_468, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -2697,6 +2832,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2712,10 +2849,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `880 + r * (6 ±0)` // Estimated: `9301 + r * (6 ±0)` - // Minimum execution time: 271_797_000 picoseconds. - Weight::from_parts(288_594_393, 9301) - // Standard Error: 846 - .saturating_add(Weight::from_parts(335_063, 0).saturating_mul(r.into())) + // Minimum execution time: 287_127_000 picoseconds. + Weight::from_parts(290_489_909, 9301) + // Standard Error: 864 + .saturating_add(Weight::from_parts(332_977, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -2724,6 +2861,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2739,10 +2878,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `878 + r * (6 ±0)` // Estimated: `9294 + r * (6 ±0)` - // Minimum execution time: 254_997_000 picoseconds. - Weight::from_parts(284_331_894, 9294) - // Standard Error: 885 - .saturating_add(Weight::from_parts(337_073, 0).saturating_mul(r.into())) + // Minimum execution time: 273_291_000 picoseconds. + Weight::from_parts(293_650_716, 9294) + // Standard Error: 725 + .saturating_add(Weight::from_parts(323_281, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -2751,6 +2890,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2766,10 +2907,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `875 + r * (6 ±0)` // Estimated: `9297 + r * (6 ±0)` - // Minimum execution time: 273_845_000 picoseconds. - Weight::from_parts(285_291_242, 9297) - // Standard Error: 690 - .saturating_add(Weight::from_parts(332_783, 0).saturating_mul(r.into())) + // Minimum execution time: 282_061_000 picoseconds. + Weight::from_parts(291_729_751, 9297) + // Standard Error: 929 + .saturating_add(Weight::from_parts(324_683, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -2778,6 +2919,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2793,10 +2936,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `866 + r * (6 ±0)` // Estimated: `9282 + r * (6 ±0)` - // Minimum execution time: 268_302_000 picoseconds. - Weight::from_parts(280_463_257, 9282) - // Standard Error: 1_035 - .saturating_add(Weight::from_parts(345_811, 0).saturating_mul(r.into())) + // Minimum execution time: 264_505_000 picoseconds. + Weight::from_parts(293_440_286, 9282) + // Standard Error: 704 + .saturating_add(Weight::from_parts(329_851, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -2805,6 +2948,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2822,10 +2967,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `940 + r * (14 ±0)` // Estimated: `9350 + r * (14 ±0)` - // Minimum execution time: 263_433_000 picoseconds. - Weight::from_parts(290_098_370, 9350) - // Standard Error: 1_905 - .saturating_add(Weight::from_parts(805_299, 0).saturating_mul(r.into())) + // Minimum execution time: 277_208_000 picoseconds. + Weight::from_parts(304_294_691, 9350) + // Standard Error: 1_083 + .saturating_add(Weight::from_parts(824_245, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 14).saturating_mul(r.into())) @@ -2834,6 +2979,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2849,10 +2996,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `868 + r * (6 ±0)` // Estimated: `9285 + r * (6 ±0)` - // Minimum execution time: 273_588_000 picoseconds. - Weight::from_parts(287_133_565, 9285) - // Standard Error: 799 - .saturating_add(Weight::from_parts(254_114, 0).saturating_mul(r.into())) + // Minimum execution time: 278_293_000 picoseconds. + Weight::from_parts(289_743_005, 9285) + // Standard Error: 672 + .saturating_add(Weight::from_parts(267_553, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 6).saturating_mul(r.into())) @@ -2861,6 +3008,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2876,10 +3025,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `872` // Estimated: `9287` - // Minimum execution time: 257_843_000 picoseconds. - Weight::from_parts(228_177_495, 9287) - // Standard Error: 24 - .saturating_add(Weight::from_parts(985, 0).saturating_mul(n.into())) + // Minimum execution time: 279_495_000 picoseconds. + Weight::from_parts(232_736_994, 9287) + // Standard Error: 23 + .saturating_add(Weight::from_parts(1_008, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2887,6 +3036,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2902,10 +3053,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `856 + r * (45 ±0)` // Estimated: `9271 + r * (45 ±0)` - // Minimum execution time: 248_332_000 picoseconds. - Weight::from_parts(274_998_906, 9271) - // Standard Error: 949_561 - .saturating_add(Weight::from_parts(5_570_693, 0).saturating_mul(r.into())) + // Minimum execution time: 257_920_000 picoseconds. + Weight::from_parts(282_276_265, 9271) + // Standard Error: 948_490 + .saturating_add(Weight::from_parts(2_408_134, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 45).saturating_mul(r.into())) @@ -2914,6 +3065,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2929,10 +3082,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `866` // Estimated: `9288` - // Minimum execution time: 272_055_000 picoseconds. - Weight::from_parts(282_280_090, 9288) - // Standard Error: 1 - .saturating_add(Weight::from_parts(330, 0).saturating_mul(n.into())) + // Minimum execution time: 278_149_000 picoseconds. + Weight::from_parts(287_020_337, 9288) + // Standard Error: 0 + .saturating_add(Weight::from_parts(321, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2940,9 +3093,11 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:3 w:3) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:1 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) - /// Storage: `Contracts::CodeInfoOf` (r:2 w:2) + /// Storage: `Contracts::CodeInfoOf` (r:33 w:33) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) /// Storage: `Contracts::PristineCode` (r:1 w:0) /// Proof: `Contracts::PristineCode` (`max_values`: None, `max_size`: Some(125988), added: 128463, mode: `Measured`) @@ -2953,28 +3108,30 @@ impl WeightInfo for () { /// Storage: `System::EventTopics` (r:4 w:4) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) /// Storage: `Contracts::DeletionQueue` (r:0 w:1) /// Proof: `Contracts::DeletionQueue` (`max_values`: None, `max_size`: Some(142), added: 2617, mode: `Measured`) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2902 + r * (529 ±0)` - // Estimated: `11317 + r * (5479 ±0)` - // Minimum execution time: 274_842_000 picoseconds. - Weight::from_parts(299_824_497, 11317) - // Standard Error: 902_686 - .saturating_add(Weight::from_parts(106_562_902, 0).saturating_mul(r.into())) + // Measured: `4805 + r * (2121 ±0)` + // Estimated: `13220 + r * (81321 ±0)` + // Minimum execution time: 307_763_000 picoseconds. + Weight::from_parts(323_648_618, 13220) + // Standard Error: 879_890 + .saturating_add(Weight::from_parts(249_045_481, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) - .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().reads((36_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) - .saturating_add(RocksDbWeight::get().writes((10_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 5266).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().writes((41_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 81321).saturating_mul(r.into())) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -2992,10 +3149,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `947 + r * (10 ±0)` // Estimated: `9363 + r * (10 ±0)` - // Minimum execution time: 255_393_000 picoseconds. - Weight::from_parts(309_814_338, 9363) - // Standard Error: 2_978 - .saturating_add(Weight::from_parts(1_203_507, 0).saturating_mul(r.into())) + // Minimum execution time: 278_400_000 picoseconds. + Weight::from_parts(293_743_000, 9363) + // Standard Error: 1_686 + .saturating_add(Weight::from_parts(1_288_603, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 10).saturating_mul(r.into())) @@ -3004,6 +3161,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3019,10 +3178,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `866 + r * (10 ±0)` // Estimated: `9283 + r * (10 ±0)` - // Minimum execution time: 250_378_000 picoseconds. - Weight::from_parts(287_003_144, 9283) - // Standard Error: 2_726 - .saturating_add(Weight::from_parts(1_850_967, 0).saturating_mul(r.into())) + // Minimum execution time: 272_110_000 picoseconds. + Weight::from_parts(295_620_726, 9283) + // Standard Error: 5_481 + .saturating_add(Weight::from_parts(2_031_955, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 10).saturating_mul(r.into())) @@ -3031,6 +3190,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3047,12 +3208,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `883 + t * (32 ±0)` // Estimated: `9303 + t * (2508 ±0)` - // Minimum execution time: 266_787_000 picoseconds. - Weight::from_parts(284_368_661, 9303) - // Standard Error: 121_315 - .saturating_add(Weight::from_parts(2_690_211, 0).saturating_mul(t.into())) - // Standard Error: 33 - .saturating_add(Weight::from_parts(789, 0).saturating_mul(n.into())) + // Minimum execution time: 277_409_000 picoseconds. + Weight::from_parts(293_838_037, 9303) + // Standard Error: 87_977 + .saturating_add(Weight::from_parts(2_911_340, 0).saturating_mul(t.into())) + // Standard Error: 24 + .saturating_add(Weight::from_parts(531, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3063,6 +3224,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3078,10 +3241,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `865 + r * (7 ±0)` // Estimated: `9285 + r * (7 ±0)` - // Minimum execution time: 166_804_000 picoseconds. - Weight::from_parts(175_118_291, 9285) - // Standard Error: 398 - .saturating_add(Weight::from_parts(220_961, 0).saturating_mul(r.into())) + // Minimum execution time: 172_634_000 picoseconds. + Weight::from_parts(183_322_840, 9285) + // Standard Error: 384 + .saturating_add(Weight::from_parts(226_007, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 7).saturating_mul(r.into())) @@ -3090,6 +3253,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `MaxEncodedLen`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3105,10 +3270,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `125816` // Estimated: `131758` - // Minimum execution time: 398_436_000 picoseconds. - Weight::from_parts(385_003_285, 131758) + // Minimum execution time: 425_713_000 picoseconds. + Weight::from_parts(394_260_924, 131758) // Standard Error: 12 - .saturating_add(Weight::from_parts(1_038, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(1_032, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3119,10 +3284,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `927 + r * (292 ±0)` // Estimated: `929 + r * (293 ±0)` - // Minimum execution time: 274_099_000 picoseconds. - Weight::from_parts(174_282_817, 929) - // Standard Error: 10_547 - .saturating_add(Weight::from_parts(6_262_173, 0).saturating_mul(r.into())) + // Minimum execution time: 268_128_000 picoseconds. + Weight::from_parts(186_787_113, 929) + // Standard Error: 10_796 + .saturating_add(Weight::from_parts(6_454_780, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3136,10 +3301,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1450` // Estimated: `1433` - // Minimum execution time: 274_061_000 picoseconds. - Weight::from_parts(334_755_333, 1433) - // Standard Error: 66 - .saturating_add(Weight::from_parts(771, 0).saturating_mul(n.into())) + // Minimum execution time: 286_565_000 picoseconds. + Weight::from_parts(349_504_932, 1433) + // Standard Error: 70 + .saturating_add(Weight::from_parts(530, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(15_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } @@ -3150,8 +3315,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1256 + n * (1 ±0)` // Estimated: `1256 + n * (1 ±0)` - // Minimum execution time: 272_657_000 picoseconds. - Weight::from_parts(299_061_594, 1256) + // Minimum execution time: 282_478_000 picoseconds. + Weight::from_parts(303_448_260, 1256) + // Standard Error: 34 + .saturating_add(Weight::from_parts(712, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3163,10 +3330,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `924 + r * (288 ±0)` // Estimated: `930 + r * (289 ±0)` - // Minimum execution time: 270_524_000 picoseconds. - Weight::from_parts(177_959_667, 930) - // Standard Error: 10_397 - .saturating_add(Weight::from_parts(6_270_181, 0).saturating_mul(r.into())) + // Minimum execution time: 271_793_000 picoseconds. + Weight::from_parts(179_158_648, 930) + // Standard Error: 11_868 + .saturating_add(Weight::from_parts(6_397_986, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3180,8 +3347,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1252 + n * (1 ±0)` // Estimated: `1252 + n * (1 ±0)` - // Minimum execution time: 270_757_000 picoseconds. - Weight::from_parts(298_627_896, 1252) + // Minimum execution time: 273_945_000 picoseconds. + Weight::from_parts(299_855_996, 1252) + // Standard Error: 31 + .saturating_add(Weight::from_parts(309, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3193,10 +3362,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `924 + r * (296 ±0)` // Estimated: `926 + r * (297 ±0)` - // Minimum execution time: 268_082_000 picoseconds. - Weight::from_parts(202_583_730, 926) - // Standard Error: 9_029 - .saturating_add(Weight::from_parts(5_028_517, 0).saturating_mul(r.into())) + // Minimum execution time: 275_285_000 picoseconds. + Weight::from_parts(207_735_572, 926) + // Standard Error: 9_736 + .saturating_add(Weight::from_parts(5_162_837, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3209,10 +3378,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1268 + n * (1 ±0)` // Estimated: `1268 + n * (1 ±0)` - // Minimum execution time: 274_100_000 picoseconds. - Weight::from_parts(296_981_515, 1268) + // Minimum execution time: 278_929_000 picoseconds. + Weight::from_parts(302_251_674, 1268) // Standard Error: 34 - .saturating_add(Weight::from_parts(578, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(583, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3224,10 +3393,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `935 + r * (288 ±0)` // Estimated: `932 + r * (289 ±0)` - // Minimum execution time: 269_697_000 picoseconds. - Weight::from_parts(198_346_516, 932) - // Standard Error: 8_623 - .saturating_add(Weight::from_parts(4_964_116, 0).saturating_mul(r.into())) + // Minimum execution time: 258_476_000 picoseconds. + Weight::from_parts(209_578_051, 932) + // Standard Error: 8_255 + .saturating_add(Weight::from_parts(4_942_572, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3240,10 +3409,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1255 + n * (1 ±0)` // Estimated: `1255 + n * (1 ±0)` - // Minimum execution time: 264_210_000 picoseconds. - Weight::from_parts(291_387_652, 1255) - // Standard Error: 36 - .saturating_add(Weight::from_parts(524, 0).saturating_mul(n.into())) + // Minimum execution time: 273_089_000 picoseconds. + Weight::from_parts(302_452_604, 1255) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3255,10 +3422,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `917 + r * (296 ±0)` // Estimated: `922 + r * (297 ±0)` - // Minimum execution time: 267_219_000 picoseconds. - Weight::from_parts(175_866_982, 922) - // Standard Error: 11_275 - .saturating_add(Weight::from_parts(6_424_755, 0).saturating_mul(r.into())) + // Minimum execution time: 274_301_000 picoseconds. + Weight::from_parts(172_245_469, 922) + // Standard Error: 11_306 + .saturating_add(Weight::from_parts(6_526_825, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3272,10 +3439,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1269 + n * (1 ±0)` // Estimated: `1269 + n * (1 ±0)` - // Minimum execution time: 274_634_000 picoseconds. - Weight::from_parts(294_272_009, 1269) + // Minimum execution time: 280_399_000 picoseconds. + Weight::from_parts(305_970_974, 1269) // Standard Error: 36 - .saturating_add(Weight::from_parts(1_219, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(568, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3284,6 +3451,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1602 w:1601) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3299,10 +3468,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1418 + r * (45 ±0)` // Estimated: `9785 + r * (2520 ±0)` - // Minimum execution time: 266_833_000 picoseconds. - Weight::from_parts(186_049_741, 9785) - // Standard Error: 40_311 - .saturating_add(Weight::from_parts(31_365_585, 0).saturating_mul(r.into())) + // Minimum execution time: 258_452_000 picoseconds. + Weight::from_parts(276_401_000, 9785) + // Standard Error: 65_648 + .saturating_add(Weight::from_parts(33_890_852, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -3313,6 +3482,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:801 w:801) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:2 w:0) @@ -3328,10 +3499,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1263 + r * (245 ±0)` // Estimated: `9635 + r * (2721 ±0)` - // Minimum execution time: 272_140_000 picoseconds. - Weight::from_parts(275_009_000, 9635) - // Standard Error: 99_187 - .saturating_add(Weight::from_parts(240_702_479, 0).saturating_mul(r.into())) + // Minimum execution time: 281_394_000 picoseconds. + Weight::from_parts(286_475_000, 9635) + // Standard Error: 156_302 + .saturating_add(Weight::from_parts(250_370_283, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(14_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -3342,6 +3513,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:736 w:0) @@ -3357,10 +3530,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0 + r * (576 ±0)` // Estimated: `9290 + r * (2637 ±10)` - // Minimum execution time: 263_664_000 picoseconds. - Weight::from_parts(277_240_000, 9290) - // Standard Error: 169_147 - .saturating_add(Weight::from_parts(240_084_929, 0).saturating_mul(r.into())) + // Minimum execution time: 278_193_000 picoseconds. + Weight::from_parts(280_814_000, 9290) + // Standard Error: 164_401 + .saturating_add(Weight::from_parts(251_272_834, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3371,6 +3544,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:3 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:2 w:2) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:2 w:0) @@ -3387,12 +3562,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1310 + t * (277 ±0)` // Estimated: `12200 + t * (5227 ±0)` - // Minimum execution time: 464_644_000 picoseconds. - Weight::from_parts(40_377_313, 12200) - // Standard Error: 12_060_226 - .saturating_add(Weight::from_parts(380_635_982, 0).saturating_mul(t.into())) + // Minimum execution time: 476_812_000 picoseconds. + Weight::from_parts(70_715_306, 12200) + // Standard Error: 12_232_109 + .saturating_add(Weight::from_parts(374_277_042, 0).saturating_mul(t.into())) // Standard Error: 17 - .saturating_add(Weight::from_parts(1_014, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(1_022, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(16_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) @@ -3403,6 +3578,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:802 w:802) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:801 w:801) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:801 w:800) @@ -3416,16 +3593,16 @@ impl WeightInfo for () { /// Storage: `System::EventTopics` (r:803 w:803) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:800 w:800) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) /// The range of component `r` is `[1, 800]`. fn seal_instantiate(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `1281 + r * (255 ±0)` // Estimated: `9623 + r * (2731 ±0)` - // Minimum execution time: 641_845_000 picoseconds. - Weight::from_parts(649_908_000, 9623) - // Standard Error: 278_514 - .saturating_add(Weight::from_parts(361_164_598, 0).saturating_mul(r.into())) + // Minimum execution time: 656_480_000 picoseconds. + Weight::from_parts(668_579_000, 9623) + // Standard Error: 365_458 + .saturating_add(Weight::from_parts(379_238_223, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(14_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(7_u64)) @@ -3436,6 +3613,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:3 w:3) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:2 w:2) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:2 w:1) @@ -3449,7 +3628,7 @@ impl WeightInfo for () { /// Storage: `System::EventTopics` (r:4 w:4) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(157), added: 2632, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `Measured`) /// The range of component `t` is `[0, 1]`. /// The range of component `i` is `[0, 983040]`. /// The range of component `s` is `[0, 983040]`. @@ -3457,12 +3636,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1306 + t * (104 ±0)` // Estimated: `12214 + t * (2549 ±1)` - // Minimum execution time: 2_111_632_000 picoseconds. - Weight::from_parts(1_213_125_745, 12214) - // Standard Error: 22 - .saturating_add(Weight::from_parts(1_055, 0).saturating_mul(i.into())) - // Standard Error: 22 - .saturating_add(Weight::from_parts(1_192, 0).saturating_mul(s.into())) + // Minimum execution time: 2_148_964_000 picoseconds. + Weight::from_parts(1_557_685_999, 12214) + // Standard Error: 36 + .saturating_add(Weight::from_parts(864, 0).saturating_mul(i.into())) + // Standard Error: 36 + .saturating_add(Weight::from_parts(1_092, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(19_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(11_u64)) @@ -3473,6 +3652,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3488,10 +3669,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `865 + r * (8 ±0)` // Estimated: `9279 + r * (8 ±0)` - // Minimum execution time: 264_227_000 picoseconds. - Weight::from_parts(281_015_995, 9279) - // Standard Error: 710 - .saturating_add(Weight::from_parts(365_734, 0).saturating_mul(r.into())) + // Minimum execution time: 279_377_000 picoseconds. + Weight::from_parts(287_951_287, 9279) + // Standard Error: 659 + .saturating_add(Weight::from_parts(376_476, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) @@ -3500,6 +3681,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3515,10 +3698,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `873` // Estimated: `9286` - // Minimum execution time: 270_709_000 picoseconds. - Weight::from_parts(268_416_051, 9286) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_080, 0).saturating_mul(n.into())) + // Minimum execution time: 276_151_000 picoseconds. + Weight::from_parts(267_656_959, 9286) + // Standard Error: 2 + .saturating_add(Weight::from_parts(1_108, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3526,6 +3709,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3541,10 +3726,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `867 + r * (8 ±0)` // Estimated: `9284 + r * (8 ±0)` - // Minimum execution time: 267_283_000 picoseconds. - Weight::from_parts(280_706_659, 9284) - // Standard Error: 540 - .saturating_add(Weight::from_parts(790_312, 0).saturating_mul(r.into())) + // Minimum execution time: 275_247_000 picoseconds. + Weight::from_parts(286_675_317, 9284) + // Standard Error: 601 + .saturating_add(Weight::from_parts(788_160, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) @@ -3553,6 +3738,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3568,10 +3755,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `875` // Estimated: `9292` - // Minimum execution time: 262_010_000 picoseconds. - Weight::from_parts(273_278_744, 9292) + // Minimum execution time: 281_585_000 picoseconds. + Weight::from_parts(287_637_844, 9292) // Standard Error: 1 - .saturating_add(Weight::from_parts(3_362, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_351, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3579,6 +3766,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3594,10 +3783,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `867 + r * (8 ±0)` // Estimated: `9286 + r * (8 ±0)` - // Minimum execution time: 268_698_000 picoseconds. - Weight::from_parts(282_890_578, 9286) - // Standard Error: 622 - .saturating_add(Weight::from_parts(441_131, 0).saturating_mul(r.into())) + // Minimum execution time: 273_678_000 picoseconds. + Weight::from_parts(289_879_306, 9286) + // Standard Error: 607 + .saturating_add(Weight::from_parts(439_482, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) @@ -3606,6 +3795,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3621,10 +3812,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `875` // Estimated: `9291` - // Minimum execution time: 252_846_000 picoseconds. - Weight::from_parts(267_657_561, 9291) + // Minimum execution time: 275_126_000 picoseconds. + Weight::from_parts(276_684_594, 9291) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_208, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_202, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3632,6 +3823,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3647,10 +3840,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `867 + r * (8 ±0)` // Estimated: `9283 + r * (8 ±0)` - // Minimum execution time: 266_899_000 picoseconds. - Weight::from_parts(276_862_067, 9283) - // Standard Error: 1_249 - .saturating_add(Weight::from_parts(443_970, 0).saturating_mul(r.into())) + // Minimum execution time: 273_229_000 picoseconds. + Weight::from_parts(287_793_841, 9283) + // Standard Error: 451 + .saturating_add(Weight::from_parts(447_922, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) @@ -3659,6 +3852,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3674,10 +3869,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `875` // Estimated: `9289` - // Minimum execution time: 265_413_000 picoseconds. - Weight::from_parts(265_600_840, 9289) + // Minimum execution time: 277_843_000 picoseconds. + Weight::from_parts(279_900_099, 9289) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_203, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_204, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -3685,6 +3880,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3700,10 +3897,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1000 + n * (1 ±0)` // Estimated: `9412 + n * (1 ±0)` - // Minimum execution time: 328_341_000 picoseconds. - Weight::from_parts(341_038_581, 9412) - // Standard Error: 10 - .saturating_add(Weight::from_parts(5_863, 0).saturating_mul(n.into())) + // Minimum execution time: 331_840_000 picoseconds. + Weight::from_parts(338_767_191, 9412) + // Standard Error: 11 + .saturating_add(Weight::from_parts(5_971, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -3712,6 +3909,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3727,10 +3926,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `808 + r * (112 ±0)` // Estimated: `9226 + r * (112 ±0)` - // Minimum execution time: 272_730_000 picoseconds. - Weight::from_parts(339_349_232, 9226) - // Standard Error: 13_004 - .saturating_add(Weight::from_parts(41_649_026, 0).saturating_mul(r.into())) + // Minimum execution time: 277_912_000 picoseconds. + Weight::from_parts(344_538_960, 9226) + // Standard Error: 13_422 + .saturating_add(Weight::from_parts(41_592_887, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 112).saturating_mul(r.into())) @@ -3739,6 +3938,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3754,10 +3955,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `910 + r * (76 ±0)` // Estimated: `9279 + r * (77 ±0)` - // Minimum execution time: 273_892_000 picoseconds. - Weight::from_parts(352_853_960, 9279) - // Standard Error: 16_745 - .saturating_add(Weight::from_parts(45_853_294, 0).saturating_mul(r.into())) + // Minimum execution time: 280_383_000 picoseconds. + Weight::from_parts(348_542_377, 9279) + // Standard Error: 13_985 + .saturating_add(Weight::from_parts(45_983_827, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 77).saturating_mul(r.into())) @@ -3766,6 +3967,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3781,10 +3984,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `880 + r * (42 ±0)` // Estimated: `9294 + r * (42 ±0)` - // Minimum execution time: 268_431_000 picoseconds. - Weight::from_parts(319_727_796, 9294) - // Standard Error: 10_276 - .saturating_add(Weight::from_parts(11_928_882, 0).saturating_mul(r.into())) + // Minimum execution time: 277_764_000 picoseconds. + Weight::from_parts(320_288_180, 9294) + // Standard Error: 10_140 + .saturating_add(Weight::from_parts(12_046_137, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 42).saturating_mul(r.into())) @@ -3793,6 +3996,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1536 w:1536) @@ -3808,10 +4013,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0 + r * (965 ±0)` // Estimated: `9285 + r * (3090 ±7)` - // Minimum execution time: 275_482_000 picoseconds. - Weight::from_parts(279_155_000, 9285) - // Standard Error: 65_388 - .saturating_add(Weight::from_parts(26_634_187, 0).saturating_mul(r.into())) + // Minimum execution time: 271_356_000 picoseconds. + Weight::from_parts(282_924_000, 9285) + // Standard Error: 60_493 + .saturating_add(Weight::from_parts(28_319_267, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3822,6 +4027,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:33 w:32) @@ -3837,20 +4044,22 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `937 + r * (131 ±0)` // Estimated: `9346 + r * (2607 ±0)` - // Minimum execution time: 270_001_000 picoseconds. - Weight::from_parts(286_792_689, 9346) - // Standard Error: 21_074 - .saturating_add(Weight::from_parts(6_465_885, 0).saturating_mul(r.into())) + // Minimum execution time: 269_698_000 picoseconds. + Weight::from_parts(294_325_127, 9346) + // Standard Error: 22_352 + .saturating_add(Weight::from_parts(6_744_117, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) - .saturating_add(Weight::from_parts(0, 2606).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2607).saturating_mul(r.into())) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `MaxEncodedLen`) /// Storage: `Contracts::CodeInfoOf` (r:33 w:32) @@ -3864,12 +4073,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 32]`. fn unlock_delegate_dependency(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `969 + r * (183 ±0)` + // Measured: `972 + r * (184 ±0)` // Estimated: `129453 + r * (2568 ±0)` - // Minimum execution time: 270_652_000 picoseconds. - Weight::from_parts(293_369_452, 129453) - // Standard Error: 24_321 - .saturating_add(Weight::from_parts(5_575_600, 0).saturating_mul(r.into())) + // Minimum execution time: 261_226_000 picoseconds. + Weight::from_parts(294_299_527, 129453) + // Standard Error: 27_898 + .saturating_add(Weight::from_parts(6_031_601, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -3880,6 +4089,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3895,10 +4106,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `861 + r * (3 ±0)` // Estimated: `9282 + r * (3 ±0)` - // Minimum execution time: 267_749_000 picoseconds. - Weight::from_parts(280_373_341, 9282) - // Standard Error: 464 - .saturating_add(Weight::from_parts(170_398, 0).saturating_mul(r.into())) + // Minimum execution time: 270_729_000 picoseconds. + Weight::from_parts(289_622_807, 9282) + // Standard Error: 394 + .saturating_add(Weight::from_parts(167_010, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) @@ -3907,6 +4118,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3922,10 +4135,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2112 + r * (39 ±0)` // Estimated: `10377 + r * (40 ±0)` - // Minimum execution time: 270_260_000 picoseconds. - Weight::from_parts(337_969_172, 10377) - // Standard Error: 1_557 - .saturating_add(Weight::from_parts(305_735, 0).saturating_mul(r.into())) + // Minimum execution time: 272_228_000 picoseconds. + Weight::from_parts(351_059_276, 10377) + // Standard Error: 1_761 + .saturating_add(Weight::from_parts(312_269, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(Weight::from_parts(0, 40).saturating_mul(r.into())) @@ -3934,6 +4147,8 @@ impl WeightInfo for () { /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:3 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:1) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) /// Storage: `Contracts::CodeInfoOf` (r:1 w:0) @@ -3951,10 +4166,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `864 + r * (3 ±0)` // Estimated: `9279 + r * (3 ±0)` - // Minimum execution time: 265_607_000 picoseconds. - Weight::from_parts(283_396_630, 9279) - // Standard Error: 449 - .saturating_add(Weight::from_parts(149_018, 0).saturating_mul(r.into())) + // Minimum execution time: 272_497_000 picoseconds. + Weight::from_parts(288_213_060, 9279) + // Standard Error: 469 + .saturating_add(Weight::from_parts(155_530, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(Weight::from_parts(0, 3).saturating_mul(r.into())) @@ -3964,9 +4179,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_813_000 picoseconds. - Weight::from_parts(1_264_945, 0) - // Standard Error: 19 - .saturating_add(Weight::from_parts(15_098, 0).saturating_mul(r.into())) + // Minimum execution time: 1_990_000 picoseconds. + Weight::from_parts(1_778_221, 0) + // Standard Error: 26 + .saturating_add(Weight::from_parts(14_888, 0).saturating_mul(r.into())) } } -- GitLab From e58e854a328aeac9a8876476be21918c21707e64 Mon Sep 17 00:00:00 2001 From: Tsvetomir Dimitrov Date: Wed, 20 Mar 2024 08:55:58 +0200 Subject: [PATCH 066/187] Expose `ClaimQueue` via a runtime api and use it in `collation-generation` (#3580) The PR adds two things: 1. Runtime API exposing the whole claim queue 2. Consumes the API in `collation-generation` to fetch the next scheduled `ParaEntry` for an occupied core. Related to https://github.com/paritytech/polkadot-sdk/issues/1797 --- Cargo.lock | 1 + .../src/blockchain_rpc_client.rs | 13 +- .../src/rpc_client.rs | 17 +- polkadot/node/collation-generation/Cargo.toml | 1 + polkadot/node/collation-generation/src/lib.rs | 74 +++- .../node/collation-generation/src/tests.rs | 329 +++++++++++++++++- polkadot/node/core/runtime-api/src/cache.rs | 29 +- polkadot/node/core/runtime-api/src/lib.rs | 11 + polkadot/node/core/runtime-api/src/tests.rs | 18 +- polkadot/node/subsystem-types/src/messages.rs | 10 +- .../subsystem-types/src/runtime_client.rs | 22 +- polkadot/node/subsystem-util/src/lib.rs | 8 +- polkadot/primitives/src/runtime_api.rs | 17 +- .../src/runtime_api_impl/vstaging.rs | 21 +- prdoc/pr_3580.prdoc | 13 + 15 files changed, 532 insertions(+), 52 deletions(-) create mode 100644 prdoc/pr_3580.prdoc diff --git a/Cargo.lock b/Cargo.lock index 5c0066e9728..ee813b60218 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12396,6 +12396,7 @@ dependencies = [ "polkadot-node-subsystem-util", "polkadot-primitives", "polkadot-primitives-test-helpers", + "rstest", "sp-core", "sp-keyring", "sp-maybe-compressed-blob", diff --git a/cumulus/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs b/cumulus/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs index ab56b62c4ca..8d8a2920b4e 100644 --- a/cumulus/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs +++ b/cumulus/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs @@ -14,7 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use std::pin::Pin; +use std::{ + collections::{BTreeMap, VecDeque}, + pin::Pin, +}; use cumulus_relay_chain_interface::{RelayChainError, RelayChainResult}; use cumulus_relay_chain_rpc_interface::RelayChainRpcClient; @@ -25,6 +28,7 @@ use polkadot_primitives::{ async_backing::{AsyncBackingParams, BackingState}, slashing, vstaging::{ApprovalVotingParams, NodeFeatures}, + CoreIndex, }; use sc_authority_discovery::{AuthorityDiscovery, Error as AuthorityDiscoveryError}; use sc_client_api::AuxStore; @@ -442,6 +446,13 @@ impl RuntimeApiSubsystemClient for BlockChainRpcClient { async fn node_features(&self, at: Hash) -> Result { Ok(self.rpc_client.parachain_host_node_features(at).await?) } + + async fn claim_queue( + &self, + at: Hash, + ) -> Result>, ApiError> { + Ok(self.rpc_client.parachain_host_claim_queue(at).await?) + } } #[async_trait::async_trait] diff --git a/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs index 6578210a259..8cf5ccf0c70 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs @@ -24,6 +24,7 @@ use jsonrpsee::{ }; use serde::de::DeserializeOwned; use serde_json::Value as JsonValue; +use std::collections::VecDeque; use tokio::sync::mpsc::Sender as TokioSender; use parity_scale_codec::{Decode, Encode}; @@ -34,10 +35,10 @@ use cumulus_primitives_core::{ slashing, vstaging::{ApprovalVotingParams, NodeFeatures}, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, - CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo, - Hash as RelayHash, Header as RelayHeader, InboundHrmpMessage, OccupiedCoreAssumption, - PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, - ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, + CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, + GroupRotationInfo, Hash as RelayHash, Header as RelayHeader, InboundHrmpMessage, + OccupiedCoreAssumption, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, + ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, }, InboundDownwardMessage, ParaId, PersistedValidationData, }; @@ -647,6 +648,14 @@ impl RelayChainRpcClient { .await } + pub async fn parachain_host_claim_queue( + &self, + at: RelayHash, + ) -> Result>, RelayChainError> { + self.call_remote_runtime_function("ParachainHost_claim_queue", at, None::<()>) + .await + } + pub async fn validation_code_hash( &self, at: RelayHash, diff --git a/polkadot/node/collation-generation/Cargo.toml b/polkadot/node/collation-generation/Cargo.toml index 8df0c2b1eda..f72af87c15e 100644 --- a/polkadot/node/collation-generation/Cargo.toml +++ b/polkadot/node/collation-generation/Cargo.toml @@ -26,4 +26,5 @@ parity-scale-codec = { version = "3.6.1", default-features = false, features = [ polkadot-node-subsystem-test-helpers = { path = "../subsystem-test-helpers" } test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../primitives/test-helpers" } assert_matches = "1.4.0" +rstest = "0.18.2" sp-keyring = { path = "../../../substrate/primitives/keyring" } diff --git a/polkadot/node/collation-generation/src/lib.rs b/polkadot/node/collation-generation/src/lib.rs index a89351628a0..3b1a8f5ff23 100644 --- a/polkadot/node/collation-generation/src/lib.rs +++ b/polkadot/node/collation-generation/src/lib.rs @@ -38,21 +38,25 @@ use polkadot_node_primitives::{ SubmitCollationParams, }; use polkadot_node_subsystem::{ - messages::{CollationGenerationMessage, CollatorProtocolMessage}, + messages::{CollationGenerationMessage, CollatorProtocolMessage, RuntimeApiRequest}, overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, RuntimeApiError, SpawnedSubsystem, SubsystemContext, SubsystemError, SubsystemResult, }; use polkadot_node_subsystem_util::{ - request_async_backing_params, request_availability_cores, request_persisted_validation_data, - request_validation_code, request_validation_code_hash, request_validators, + has_required_runtime, request_async_backing_params, request_availability_cores, + request_claim_queue, request_persisted_validation_data, request_validation_code, + request_validation_code_hash, request_validators, }; use polkadot_primitives::{ collator_signature_payload, CandidateCommitments, CandidateDescriptor, CandidateReceipt, - CollatorPair, CoreState, Hash, Id as ParaId, OccupiedCoreAssumption, PersistedValidationData, - ValidationCodeHash, + CollatorPair, CoreIndex, CoreState, Hash, Id as ParaId, OccupiedCoreAssumption, + PersistedValidationData, ScheduledCore, ValidationCodeHash, }; use sp_core::crypto::Pair; -use std::sync::Arc; +use std::{ + collections::{BTreeMap, VecDeque}, + sync::Arc, +}; mod error; @@ -223,6 +227,7 @@ async fn handle_new_activations( let availability_cores = availability_cores??; let n_validators = validators??.len(); let async_backing_params = async_backing_params?.ok(); + let maybe_claim_queue = fetch_claim_queue(ctx.sender(), relay_parent).await?; for (core_idx, core) in availability_cores.into_iter().enumerate() { let _availability_core_timer = metrics.time_new_activations_availability_core(); @@ -239,10 +244,25 @@ async fn handle_new_activations( // TODO [now]: this assumes that next up == current. // in practice we should only set `OccupiedCoreAssumption::Included` // when the candidate occupying the core is also of the same para. - if let Some(scheduled) = occupied_core.next_up_on_available { - (scheduled, OccupiedCoreAssumption::Included) - } else { - continue + let res = match maybe_claim_queue { + Some(ref claim_queue) => { + // read what's in the claim queue for this core + fetch_next_scheduled_on_core( + claim_queue, + CoreIndex(core_idx as u32), + ) + }, + None => { + // Runtime doesn't support claim queue runtime api. Fallback to + // `next_up_on_available` + occupied_core.next_up_on_available + }, + } + .map(|scheduled| (scheduled, OccupiedCoreAssumption::Included)); + + match res { + Some(res) => res, + None => continue, } }, _ => { @@ -600,3 +620,37 @@ fn erasure_root( let chunks = polkadot_erasure_coding::obtain_chunks_v1(n_validators, &available_data)?; Ok(polkadot_erasure_coding::branches(&chunks).root()) } + +// Checks if the runtime supports `request_claim_queue` and executes it. Returns `Ok(None)` +// otherwise. Any [`RuntimeApiError`]s are bubbled up to the caller. +async fn fetch_claim_queue( + sender: &mut impl overseer::CollationGenerationSenderTrait, + relay_parent: Hash, +) -> crate::error::Result>>> { + if has_required_runtime( + sender, + relay_parent, + RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT, + ) + .await + { + let res = request_claim_queue(relay_parent, sender).await.await??; + Ok(Some(res)) + } else { + gum::trace!(target: LOG_TARGET, "Runtime doesn't support `request_claim_queue`"); + Ok(None) + } +} + +// Returns the next scheduled `ParaId` for a core in the claim queue, wrapped in `ScheduledCore`. +// This function is supposed to be used in `handle_new_activations` hence the return type. +fn fetch_next_scheduled_on_core( + claim_queue: &BTreeMap>, + core_idx: CoreIndex, +) -> Option { + claim_queue + .get(&core_idx)? + .front() + .cloned() + .map(|para_id| ScheduledCore { para_id, collator: None }) +} diff --git a/polkadot/node/collation-generation/src/tests.rs b/polkadot/node/collation-generation/src/tests.rs index eb0ede6ef6b..9b16980e6af 100644 --- a/polkadot/node/collation-generation/src/tests.rs +++ b/polkadot/node/collation-generation/src/tests.rs @@ -25,15 +25,18 @@ use polkadot_node_primitives::{BlockData, Collation, CollationResult, MaybeCompr use polkadot_node_subsystem::{ errors::RuntimeApiError, messages::{AllMessages, RuntimeApiMessage, RuntimeApiRequest}, + ActivatedLeaf, }; use polkadot_node_subsystem_test_helpers::{subsystem_test_harness, TestSubsystemContextHandle}; use polkadot_node_subsystem_util::TimeoutExt; use polkadot_primitives::{ - CollatorPair, HeadData, Id as ParaId, PersistedValidationData, ScheduledCore, ValidationCode, + AsyncBackingParams, CollatorPair, HeadData, Id as ParaId, Id, PersistedValidationData, + ScheduledCore, ValidationCode, }; +use rstest::rstest; use sp_keyring::sr25519::Keyring as Sr25519Keyring; use std::pin::Pin; -use test_helpers::{dummy_hash, dummy_head_data, dummy_validator}; +use test_helpers::{dummy_candidate_descriptor, dummy_hash, dummy_head_data, dummy_validator}; type VirtualOverseer = TestSubsystemContextHandle; @@ -132,8 +135,10 @@ fn scheduled_core_for>(para_id: Id) -> ScheduledCore { ScheduledCore { para_id: para_id.into(), collator: None } } -#[test] -fn requests_availability_per_relay_parent() { +#[rstest] +#[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT - 1)] +#[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT)] +fn requests_availability_per_relay_parent(#[case] runtime_version: u32) { let activated_hashes: Vec = vec![[1; 32].into(), [4; 32].into(), [9; 32].into(), [16; 32].into()]; @@ -159,6 +164,18 @@ fn requests_availability_per_relay_parent() { ))) => { tx.send(Err(RuntimeApiError::NotSupported { runtime_api_name: "doesnt_matter" })).unwrap(); }, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _hash, + RuntimeApiRequest::Version(tx), + ))) => { + tx.send(Ok(runtime_version)).unwrap(); + }, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _hash, + RuntimeApiRequest::ClaimQueue(tx), + ))) if runtime_version >= RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT => { + tx.send(Ok(BTreeMap::new())).unwrap(); + }, Some(msg) => panic!("didn't expect any other overseer requests given no availability cores; got {:?}", msg), } } @@ -184,8 +201,10 @@ fn requests_availability_per_relay_parent() { assert_eq!(requested_availability_cores, activated_hashes); } -#[test] -fn requests_validation_data_for_scheduled_matches() { +#[rstest] +#[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT - 1)] +#[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT)] +fn requests_validation_data_for_scheduled_matches(#[case] runtime_version: u32) { let activated_hashes: Vec = vec![ Hash::repeat_byte(1), Hash::repeat_byte(4), @@ -242,6 +261,18 @@ fn requests_validation_data_for_scheduled_matches() { })) .unwrap(); }, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _hash, + RuntimeApiRequest::Version(tx), + ))) => { + tx.send(Ok(runtime_version)).unwrap(); + }, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _hash, + RuntimeApiRequest::ClaimQueue(tx), + ))) if runtime_version >= RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT => { + tx.send(Ok(BTreeMap::new())).unwrap(); + }, Some(msg) => { panic!("didn't expect any other overseer requests; got {:?}", msg) }, @@ -271,8 +302,10 @@ fn requests_validation_data_for_scheduled_matches() { assert_eq!(requested_validation_data, vec![[4; 32].into()]); } -#[test] -fn sends_distribute_collation_message() { +#[rstest] +#[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT - 1)] +#[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT)] +fn sends_distribute_collation_message(#[case] runtime_version: u32) { let activated_hashes: Vec = vec![ Hash::repeat_byte(1), Hash::repeat_byte(4), @@ -339,6 +372,18 @@ fn sends_distribute_collation_message() { })) .unwrap(); }, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _hash, + RuntimeApiRequest::Version(tx), + ))) => { + tx.send(Ok(runtime_version)).unwrap(); + }, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _hash, + RuntimeApiRequest::ClaimQueue(tx), + ))) if runtime_version >= RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT => { + tx.send(Ok(BTreeMap::new())).unwrap(); + }, Some(msg @ AllMessages::CollatorProtocol(_)) => { inner_to_collator_protocol.lock().await.push(msg); }, @@ -423,8 +468,10 @@ fn sends_distribute_collation_message() { } } -#[test] -fn fallback_when_no_validation_code_hash_api() { +#[rstest] +#[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT - 1)] +#[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT)] +fn fallback_when_no_validation_code_hash_api(#[case] runtime_version: u32) { // This is a variant of the above test, but with the validation code hash API disabled. let activated_hashes: Vec = vec![ @@ -501,9 +548,22 @@ fn fallback_when_no_validation_code_hash_api() { })) .unwrap(); }, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _hash, + RuntimeApiRequest::Version(tx), + ))) => { + tx.send(Ok(runtime_version)).unwrap(); + }, Some(msg @ AllMessages::CollatorProtocol(_)) => { inner_to_collator_protocol.lock().await.push(msg); }, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _hash, + RuntimeApiRequest::ClaimQueue(tx), + ))) if runtime_version >= RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT => { + let res = BTreeMap::>::new(); + tx.send(Ok(res)).unwrap(); + }, Some(msg) => { panic!("didn't expect any other overseer requests; got {:?}", msg) }, @@ -635,3 +695,252 @@ fn submit_collation_leads_to_distribution() { virtual_overseer }); } + +// There is one core in `Occupied` state and async backing is enabled. On new head activation +// `CollationGeneration` should produce and distribute a new collation. +#[rstest] +#[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT - 1)] +#[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT)] +fn distribute_collation_for_occupied_core_with_async_backing_enabled(#[case] runtime_version: u32) { + let activated_hash: Hash = [1; 32].into(); + let para_id = ParaId::from(5); + + // One core, in occupied state. The data in `CoreState` and `ClaimQueue` should match. + let cores: Vec = vec![CoreState::Occupied(polkadot_primitives::OccupiedCore { + next_up_on_available: Some(ScheduledCore { para_id, collator: None }), + occupied_since: 1, + time_out_at: 10, + next_up_on_time_out: Some(ScheduledCore { para_id, collator: None }), + availability: Default::default(), // doesn't matter + group_responsible: polkadot_primitives::GroupIndex(0), + candidate_hash: Default::default(), + candidate_descriptor: dummy_candidate_descriptor(dummy_hash()), + })]; + let claim_queue = BTreeMap::from([(CoreIndex::from(0), VecDeque::from([para_id]))]); + + test_harness(|mut virtual_overseer| async move { + helpers::initialize_collator(&mut virtual_overseer, para_id).await; + helpers::activate_new_head(&mut virtual_overseer, activated_hash).await; + helpers::handle_runtime_calls_on_new_head_activation( + &mut virtual_overseer, + activated_hash, + AsyncBackingParams { max_candidate_depth: 1, allowed_ancestry_len: 1 }, + cores, + runtime_version, + claim_queue, + ) + .await; + helpers::handle_core_processing_for_a_leaf( + &mut virtual_overseer, + activated_hash, + para_id, + // `CoreState` is `Occupied` => `OccupiedCoreAssumption` is `Included` + OccupiedCoreAssumption::Included, + ) + .await; + + virtual_overseer + }); +} + +// There is one core in `Occupied` state and async backing is disabled. On new head activation +// no new collation should be generated. +#[rstest] +#[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT - 1)] +#[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT)] +fn no_collation_is_distributed_for_occupied_core_with_async_backing_disabled( + #[case] runtime_version: u32, +) { + let activated_hash: Hash = [1; 32].into(); + let para_id = ParaId::from(5); + + // One core, in occupied state. The data in `CoreState` and `ClaimQueue` should match. + let cores: Vec = vec![CoreState::Occupied(polkadot_primitives::OccupiedCore { + next_up_on_available: Some(ScheduledCore { para_id, collator: None }), + occupied_since: 1, + time_out_at: 10, + next_up_on_time_out: Some(ScheduledCore { para_id, collator: None }), + availability: Default::default(), // doesn't matter + group_responsible: polkadot_primitives::GroupIndex(0), + candidate_hash: Default::default(), + candidate_descriptor: dummy_candidate_descriptor(dummy_hash()), + })]; + let claim_queue = BTreeMap::from([(CoreIndex::from(0), VecDeque::from([para_id]))]); + + test_harness(|mut virtual_overseer| async move { + helpers::initialize_collator(&mut virtual_overseer, para_id).await; + helpers::activate_new_head(&mut virtual_overseer, activated_hash).await; + helpers::handle_runtime_calls_on_new_head_activation( + &mut virtual_overseer, + activated_hash, + AsyncBackingParams { max_candidate_depth: 0, allowed_ancestry_len: 0 }, + cores, + runtime_version, + claim_queue, + ) + .await; + + virtual_overseer + }); +} + +mod helpers { + use super::*; + + // Sends `Initialize` with a collator config + pub async fn initialize_collator(virtual_overseer: &mut VirtualOverseer, para_id: ParaId) { + virtual_overseer + .send(FromOrchestra::Communication { + msg: CollationGenerationMessage::Initialize(test_config(para_id)), + }) + .await; + } + + // Sends `ActiveLeaves` for a single leaf with the specified hash. Block number is hardcoded. + pub async fn activate_new_head(virtual_overseer: &mut VirtualOverseer, activated_hash: Hash) { + virtual_overseer + .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves(ActiveLeavesUpdate { + activated: Some(ActivatedLeaf { + hash: activated_hash, + number: 10, + unpin_handle: polkadot_node_subsystem_test_helpers::mock::dummy_unpin_handle( + activated_hash, + ), + span: Arc::new(overseer::jaeger::Span::Disabled), + }), + ..Default::default() + }))) + .await; + } + + // Handle all runtime calls performed in `handle_new_activations`. Conditionally expects a + // `CLAIM_QUEUE_RUNTIME_REQUIREMENT` call if the passed `runtime_version` is greater or equal to + // `CLAIM_QUEUE_RUNTIME_REQUIREMENT` + pub async fn handle_runtime_calls_on_new_head_activation( + virtual_overseer: &mut VirtualOverseer, + activated_hash: Hash, + async_backing_params: AsyncBackingParams, + cores: Vec, + runtime_version: u32, + claim_queue: BTreeMap>, + ) { + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(hash, RuntimeApiRequest::AvailabilityCores(tx))) => { + assert_eq!(hash, activated_hash); + let _ = tx.send(Ok(cores)); + } + ); + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(hash, RuntimeApiRequest::Validators(tx))) => { + assert_eq!(hash, activated_hash); + let _ = tx.send(Ok(vec![ + Sr25519Keyring::Alice.public().into(), + Sr25519Keyring::Bob.public().into(), + Sr25519Keyring::Charlie.public().into(), + ])); + } + ); + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + hash, + RuntimeApiRequest::AsyncBackingParams( + tx, + ), + )) => { + assert_eq!(hash, activated_hash); + let _ = tx.send(Ok(async_backing_params)); + } + ); + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + hash, + RuntimeApiRequest::Version(tx), + )) => { + assert_eq!(hash, activated_hash); + let _ = tx.send(Ok(runtime_version)); + } + ); + + if runtime_version == RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT { + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + hash, + RuntimeApiRequest::ClaimQueue(tx), + )) => { + assert_eq!(hash, activated_hash); + let _ = tx.send(Ok(claim_queue)); + } + ); + } + } + + // Handles all runtime requests performed in `handle_new_activations` for the case when a + // collation should be prepared for the new leaf + pub async fn handle_core_processing_for_a_leaf( + virtual_overseer: &mut VirtualOverseer, + activated_hash: Hash, + para_id: ParaId, + expected_occupied_core_assumption: OccupiedCoreAssumption, + ) { + // Some hardcoded data - if needed, extract to parameters + let validation_code_hash = ValidationCodeHash::from(Hash::repeat_byte(42)); + let parent_head = HeadData::from(vec![1, 2, 3]); + let pvd = PersistedValidationData { + parent_head: parent_head.clone(), + relay_parent_number: 10, + relay_parent_storage_root: Hash::repeat_byte(1), + max_pov_size: 1024, + }; + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(hash, RuntimeApiRequest::PersistedValidationData(id, a, tx))) => { + assert_eq!(hash, activated_hash); + assert_eq!(id, para_id); + assert_eq!(a, expected_occupied_core_assumption); + + let _ = tx.send(Ok(Some(pvd.clone()))); + } + ); + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + hash, + RuntimeApiRequest::ValidationCodeHash( + id, + assumption, + tx, + ), + )) => { + assert_eq!(hash, activated_hash); + assert_eq!(id, para_id); + assert_eq!(assumption, expected_occupied_core_assumption); + + let _ = tx.send(Ok(Some(validation_code_hash))); + } + ); + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation{ + candidate_receipt, + parent_head_data_hash, + .. + }) => { + assert_eq!(parent_head_data_hash, parent_head.hash()); + assert_eq!(candidate_receipt.descriptor().persisted_validation_data_hash, pvd.hash()); + assert_eq!(candidate_receipt.descriptor().para_head, dummy_head_data().hash()); + assert_eq!(candidate_receipt.descriptor().validation_code_hash, validation_code_hash); + } + ); + } +} diff --git a/polkadot/node/core/runtime-api/src/cache.rs b/polkadot/node/core/runtime-api/src/cache.rs index 5eca551db0a..9674cda9838 100644 --- a/polkadot/node/core/runtime-api/src/cache.rs +++ b/polkadot/node/core/runtime-api/src/cache.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use std::collections::btree_map::BTreeMap; +use std::collections::{btree_map::BTreeMap, VecDeque}; use schnellru::{ByLength, LruMap}; use sp_consensus_babe::Epoch; @@ -23,10 +23,11 @@ use polkadot_primitives::{ async_backing, slashing, vstaging::{self, ApprovalVotingParams}, AuthorityDiscoveryId, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, - CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, - Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, OccupiedCoreAssumption, - PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, - ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, + CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, + GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, + OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, + SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, + ValidatorSignature, }; /// For consistency we have the same capacity for all caches. We use 128 as we'll only need that @@ -70,6 +71,7 @@ pub(crate) struct RequestResultCache { async_backing_params: LruMap, node_features: LruMap, approval_voting_params: LruMap, + claim_queue: LruMap>>, } impl Default for RequestResultCache { @@ -105,6 +107,7 @@ impl Default for RequestResultCache { para_backing_state: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), async_backing_params: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), node_features: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + claim_queue: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), } } } @@ -525,6 +528,21 @@ impl RequestResultCache { ) { self.approval_voting_params.insert(session_index, value); } + + pub(crate) fn claim_queue( + &mut self, + relay_parent: &Hash, + ) -> Option<&BTreeMap>> { + self.claim_queue.get(relay_parent).map(|v| &*v) + } + + pub(crate) fn cache_claim_queue( + &mut self, + relay_parent: Hash, + value: BTreeMap>, + ) { + self.claim_queue.insert(relay_parent, value); + } } pub(crate) enum RequestResult { @@ -577,4 +595,5 @@ pub(crate) enum RequestResult { ParaBackingState(Hash, ParaId, Option), AsyncBackingParams(Hash, async_backing::AsyncBackingParams), NodeFeatures(SessionIndex, vstaging::NodeFeatures), + ClaimQueue(Hash, BTreeMap>), } diff --git a/polkadot/node/core/runtime-api/src/lib.rs b/polkadot/node/core/runtime-api/src/lib.rs index 3ff1a35d068..2b7f6fc2d60 100644 --- a/polkadot/node/core/runtime-api/src/lib.rs +++ b/polkadot/node/core/runtime-api/src/lib.rs @@ -177,6 +177,9 @@ where self.requests_cache.cache_async_backing_params(relay_parent, params), NodeFeatures(session_index, params) => self.requests_cache.cache_node_features(session_index, params), + ClaimQueue(relay_parent, sender) => { + self.requests_cache.cache_claim_queue(relay_parent, sender); + }, } } @@ -329,6 +332,8 @@ where Some(Request::NodeFeatures(index, sender)) } }, + Request::ClaimQueue(sender) => + query!(claim_queue(), sender).map(|sender| Request::ClaimQueue(sender)), } } @@ -626,5 +631,11 @@ where sender, result = (index) ), + Request::ClaimQueue(sender) => query!( + ClaimQueue, + claim_queue(), + ver = Request::CLAIM_QUEUE_RUNTIME_REQUIREMENT, + sender + ), } } diff --git a/polkadot/node/core/runtime-api/src/tests.rs b/polkadot/node/core/runtime-api/src/tests.rs index f91723b3d39..fefd2d3f862 100644 --- a/polkadot/node/core/runtime-api/src/tests.rs +++ b/polkadot/node/core/runtime-api/src/tests.rs @@ -23,15 +23,16 @@ use polkadot_primitives::{ async_backing, slashing, vstaging::{ApprovalVotingParams, NodeFeatures}, AuthorityDiscoveryId, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, - CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo, - Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, OccupiedCoreAssumption, - PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, - Slot, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, + CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, + GroupRotationInfo, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, + OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, + SessionIndex, SessionInfo, Slot, ValidationCode, ValidationCodeHash, ValidatorId, + ValidatorIndex, ValidatorSignature, }; use sp_api::ApiError; use sp_core::testing::TaskExecutor; use std::{ - collections::{BTreeMap, HashMap}, + collections::{BTreeMap, HashMap, VecDeque}, sync::{Arc, Mutex}, }; use test_helpers::{dummy_committed_candidate_receipt, dummy_validation_code}; @@ -286,6 +287,13 @@ impl RuntimeApiSubsystemClient for MockSubsystemClient { async fn disabled_validators(&self, _: Hash) -> Result, ApiError> { todo!("Not required for tests") } + + async fn claim_queue( + &self, + _: Hash, + ) -> Result>, ApiError> { + todo!("Not required for tests") + } } #[test] diff --git a/polkadot/node/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index 23773f7e325..5115efa853c 100644 --- a/polkadot/node/subsystem-types/src/messages.rs +++ b/polkadot/node/subsystem-types/src/messages.rs @@ -45,7 +45,7 @@ use polkadot_primitives::{ async_backing, slashing, vstaging::{ApprovalVotingParams, NodeFeatures}, AuthorityDiscoveryId, BackedCandidate, BlockNumber, CandidateEvent, CandidateHash, - CandidateIndex, CandidateReceipt, CollatorId, CommittedCandidateReceipt, CoreState, + CandidateIndex, CandidateReceipt, CollatorId, CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, GroupIndex, GroupRotationInfo, Hash, HeadData, Header as BlockHeader, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, MultiDisputeStatementSet, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, @@ -55,7 +55,7 @@ use polkadot_primitives::{ }; use polkadot_statement_table::v2::Misbehavior; use std::{ - collections::{BTreeMap, HashMap, HashSet}, + collections::{BTreeMap, HashMap, HashSet, VecDeque}, sync::Arc, }; @@ -729,6 +729,9 @@ pub enum RuntimeApiRequest { /// Approval voting params /// `V10` ApprovalVotingParams(SessionIndex, RuntimeApiSender), + /// Fetch the `ClaimQueue` from scheduler pallet + /// `V11` + ClaimQueue(RuntimeApiSender>>), } impl RuntimeApiRequest { @@ -763,6 +766,9 @@ impl RuntimeApiRequest { /// `approval_voting_params` pub const APPROVAL_VOTING_PARAMS_REQUIREMENT: u32 = 10; + + /// `ClaimQueue` + pub const CLAIM_QUEUE_RUNTIME_REQUIREMENT: u32 = 11; } /// A message to the Runtime API subsystem. diff --git a/polkadot/node/subsystem-types/src/runtime_client.rs b/polkadot/node/subsystem-types/src/runtime_client.rs index 4039fc9127d..7474b4120cc 100644 --- a/polkadot/node/subsystem-types/src/runtime_client.rs +++ b/polkadot/node/subsystem-types/src/runtime_client.rs @@ -21,10 +21,11 @@ use polkadot_primitives::{ slashing, vstaging::{self, ApprovalVotingParams}, Block, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, - CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, - Header, Id, InboundDownwardMessage, InboundHrmpMessage, OccupiedCoreAssumption, - PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, - ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, + CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, + GroupRotationInfo, Hash, Header, Id, InboundDownwardMessage, InboundHrmpMessage, + OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, + SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, + ValidatorSignature, }; use sc_client_api::{AuxStore, HeaderBackend}; use sc_transaction_pool_api::OffchainTransactionPoolFactory; @@ -33,7 +34,10 @@ use sp_authority_discovery::AuthorityDiscoveryApi; use sp_blockchain::{BlockStatus, Info}; use sp_consensus_babe::{BabeApi, Epoch}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; -use std::{collections::BTreeMap, sync::Arc}; +use std::{ + collections::{BTreeMap, VecDeque}, + sync::Arc, +}; /// Offers header utilities. /// @@ -329,6 +333,10 @@ pub trait RuntimeApiSubsystemClient { at: Hash, session_index: SessionIndex, ) -> Result; + + // == v11: Claim queue == + /// Fetch the `ClaimQueue` from scheduler pallet + async fn claim_queue(&self, at: Hash) -> Result>, ApiError>; } /// Default implementation of [`RuntimeApiSubsystemClient`] using the client. @@ -594,6 +602,10 @@ where ) -> Result { self.client.runtime_api().approval_voting_params(at) } + + async fn claim_queue(&self, at: Hash) -> Result>, ApiError> { + self.client.runtime_api().claim_queue(at) + } } impl HeaderBackend for DefaultSubsystemClient diff --git a/polkadot/node/subsystem-util/src/lib.rs b/polkadot/node/subsystem-util/src/lib.rs index f13beb3502f..aaae30db50c 100644 --- a/polkadot/node/subsystem-util/src/lib.rs +++ b/polkadot/node/subsystem-util/src/lib.rs @@ -30,7 +30,7 @@ use polkadot_node_subsystem::{ messages::{RuntimeApiMessage, RuntimeApiRequest, RuntimeApiSender}, overseer, SubsystemSender, }; -use polkadot_primitives::{slashing, ExecutorParams}; +use polkadot_primitives::{slashing, CoreIndex, ExecutorParams}; pub use overseer::{ gen::{OrchestraError as OverseerError, Timeout}, @@ -53,7 +53,10 @@ pub use rand; use sp_application_crypto::AppCrypto; use sp_core::ByteArray; use sp_keystore::{Error as KeystoreError, KeystorePtr}; -use std::time::Duration; +use std::{ + collections::{BTreeMap, VecDeque}, + time::Duration, +}; use thiserror::Error; use vstaging::get_disabled_validators_with_fallback; @@ -304,6 +307,7 @@ specialize_requests! { fn request_submit_report_dispute_lost(dp: slashing::DisputeProof, okop: slashing::OpaqueKeyOwnershipProof) -> Option<()>; SubmitReportDisputeLost; fn request_disabled_validators() -> Vec; DisabledValidators; fn request_async_backing_params() -> AsyncBackingParams; AsyncBackingParams; + fn request_claim_queue() -> BTreeMap>; ClaimQueue; } /// Requests executor parameters from the runtime effective at given relay-parent. First obtains diff --git a/polkadot/primitives/src/runtime_api.rs b/polkadot/primitives/src/runtime_api.rs index d661005e32f..6dca33f8823 100644 --- a/polkadot/primitives/src/runtime_api.rs +++ b/polkadot/primitives/src/runtime_api.rs @@ -117,14 +117,18 @@ use crate::{ async_backing, slashing, vstaging::{self, ApprovalVotingParams}, AsyncBackingParams, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, - CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, - OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, - SessionIndex, SessionInfo, ValidatorId, ValidatorIndex, ValidatorSignature, + CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, + GroupRotationInfo, Hash, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, + ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidatorId, ValidatorIndex, + ValidatorSignature, }; use polkadot_core_primitives as pcp; use polkadot_parachain_primitives::primitives as ppp; -use sp_std::{collections::btree_map::BTreeMap, prelude::*}; +use sp_std::{ + collections::{btree_map::BTreeMap, vec_deque::VecDeque}, + prelude::*, +}; sp_api::decl_runtime_apis! { /// The API for querying the state of parachains on-chain. @@ -281,5 +285,10 @@ sp_api::decl_runtime_apis! { /// Approval voting configuration parameters #[api_version(10)] fn approval_voting_params() -> ApprovalVotingParams; + + /***** Added in v11 *****/ + /// Claim queue + #[api_version(11)] + fn claim_queue() -> BTreeMap>; } } diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs b/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs index 1fee1a4097d..296b872e8d4 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs @@ -16,12 +16,15 @@ //! Put implementations of functions from staging APIs here. -use crate::{configuration, initializer, shared}; +use crate::{configuration, initializer, scheduler, shared}; use primitives::{ vstaging::{ApprovalVotingParams, NodeFeatures}, - ValidatorIndex, + CoreIndex, Id as ParaId, ValidatorIndex, +}; +use sp_std::{ + collections::{btree_map::BTreeMap, vec_deque::VecDeque}, + prelude::Vec, }; -use sp_std::prelude::Vec; /// Implementation for `DisabledValidators` // CAVEAT: this should only be called on the node side @@ -38,8 +41,18 @@ pub fn node_features() -> NodeFeatures { >::config().node_features } -/// Approval voting subsystem configuration parameteres +/// Approval voting subsystem configuration parameters pub fn approval_voting_params() -> ApprovalVotingParams { let config = >::config(); config.approval_voting_params } + +/// Returns the claimqueue from the scheduler +pub fn claim_queue() -> BTreeMap> { + >::claimqueue() + .into_iter() + .map(|(core_index, entries)| { + (core_index, entries.into_iter().map(|e| e.para_id()).collect()) + }) + .collect() +} diff --git a/prdoc/pr_3580.prdoc b/prdoc/pr_3580.prdoc new file mode 100644 index 00000000000..042fcf7a1a8 --- /dev/null +++ b/prdoc/pr_3580.prdoc @@ -0,0 +1,13 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Expose `ClaimQueue` via a runtime api and consume it in `collation-generation` + +doc: + - audience: Node Dev + description: | + Creates a new runtime api exposing the `ClaimQueue` from `scheduler` pallet. Consume the api + in collation generation (if available) by getting what's scheduled on a core from the + `ClaimQueue` instead of from `next_up_on_available` (from `AvailabilityCores` runtime api). + +crates: [ ] -- GitLab From bb973aa0550e59b35e8b427cebaf676f433be83a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Mar 2024 07:03:41 +0000 Subject: [PATCH 067/187] Bump anyhow from 1.0.75 to 1.0.81 (#3752) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.75 to 1.0.81.
Release notes

Sourced from anyhow's releases.

1.0.81

  • Make backtrace support available when using -Dwarnings (#354)

1.0.80

  • Fix unused_imports warnings when compiled by rustc 1.78

1.0.79

  • Work around improperly cached build script result by sccache (#340)

1.0.78

  • Reduce spurious rebuilds under RustRover IDE when using a nightly toolchain (#337)

1.0.77

1.0.76

  • Opt in to unsafe_op_in_unsafe_fn lint (#329)
Commits
  • 4aad4ed Release 1.0.81
  • 8be9091 Merge pull request #354 from dtolnay/deadcode
  • a2eb7dd Make compatible with -Dwarnings
  • 5443719 Release 1.0.80
  • dfc7bc0 Work around prelude redundant import warnings
  • 6e4f86b Import from alloc not std, where possible
  • f885a13 Ignore incompatible_msrv clippy false positives in test
  • fefbcbc Ignore incompatible_msrv clippy lint
  • 78f2d81 Update ui test suite to nightly-2024-02-08
  • edd88d3 Update ui test suite to nightly-2024-01-31
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=anyhow&package-manager=cargo&previous-version=1.0.75&new-version=1.0.81)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- substrate/client/executor/wasmtime/Cargo.toml | 2 +- substrate/frame/contracts/fixtures/Cargo.toml | 4 ++-- substrate/primitives/wasm-interface/Cargo.toml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ee813b60218..b055c79cbbf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -309,9 +309,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" [[package]] name = "approx" diff --git a/substrate/client/executor/wasmtime/Cargo.toml b/substrate/client/executor/wasmtime/Cargo.toml index 75cc76a2354..f3fef404691 100644 --- a/substrate/client/executor/wasmtime/Cargo.toml +++ b/substrate/client/executor/wasmtime/Cargo.toml @@ -30,7 +30,7 @@ wasmtime = { version = "8.0.1", default-features = false, features = [ "parallel-compilation", "pooling-allocator", ] } -anyhow = "1.0.68" +anyhow = "1.0.81" sc-allocator = { path = "../../allocator" } sc-executor-common = { path = "../common" } sp-runtime-interface = { path = "../../../primitives/runtime-interface" } diff --git a/substrate/frame/contracts/fixtures/Cargo.toml b/substrate/frame/contracts/fixtures/Cargo.toml index 5ac140cd91b..8c93c6f16f6 100644 --- a/substrate/frame/contracts/fixtures/Cargo.toml +++ b/substrate/frame/contracts/fixtures/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] frame-system = { path = "../../system" } sp-runtime = { path = "../../../primitives/runtime" } -anyhow = "1.0.0" +anyhow = "1.0.81" [build-dependencies] parity-wasm = "0.45.0" @@ -21,7 +21,7 @@ tempfile = "3.8.1" toml = "0.8.2" twox-hash = "1.6.3" polkavm-linker = { workspace = true, optional = true } -anyhow = "1.0.0" +anyhow = "1.0.81" [features] riscv = ["polkavm-linker"] diff --git a/substrate/primitives/wasm-interface/Cargo.toml b/substrate/primitives/wasm-interface/Cargo.toml index 6c051b71c8e..c05cc05ff06 100644 --- a/substrate/primitives/wasm-interface/Cargo.toml +++ b/substrate/primitives/wasm-interface/Cargo.toml @@ -21,7 +21,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = impl-trait-for-tuples = "0.2.2" log = { optional = true, workspace = true, default-features = true } wasmtime = { version = "8.0.1", default-features = false, optional = true } -anyhow = { version = "1.0.68", optional = true } +anyhow = { version = "1.0.81", optional = true } [features] default = ["std"] -- GitLab From 7241a8db7b3496816503c6058dae67f66c666b00 Mon Sep 17 00:00:00 2001 From: slicejoke <163888128+slicejoke@users.noreply.github.com> Date: Wed, 20 Mar 2024 18:20:59 +0800 Subject: [PATCH 068/187] Fix typos (#3753) --- bridges/bin/runtime-common/src/priority_calculator.rs | 2 +- bridges/bin/runtime-common/src/refund_relayer_extension.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bridges/bin/runtime-common/src/priority_calculator.rs b/bridges/bin/runtime-common/src/priority_calculator.rs index a597fb9e2f4..c2737128e34 100644 --- a/bridges/bin/runtime-common/src/priority_calculator.rs +++ b/bridges/bin/runtime-common/src/priority_calculator.rs @@ -128,7 +128,7 @@ mod integrity_tests { Runtime::RuntimeCall: Dispatchable, BalanceOf: Send + Sync + FixedPointOperand, { - // esimate priority of transaction that delivers one message and has large tip + // estimate priority of transaction that delivers one message and has large tip let maximal_messages_in_delivery_transaction = Runtime::MaxUnconfirmedMessagesAtInboundLane::get(); let small_with_tip_priority = diff --git a/bridges/bin/runtime-common/src/refund_relayer_extension.rs b/bridges/bin/runtime-common/src/refund_relayer_extension.rs index bfcb82ad166..8e901d72821 100644 --- a/bridges/bin/runtime-common/src/refund_relayer_extension.rs +++ b/bridges/bin/runtime-common/src/refund_relayer_extension.rs @@ -16,7 +16,7 @@ //! Signed extension that refunds relayer if he has delivered some new messages. //! It also refunds transaction cost if the transaction is an `utility.batchAll()` -//! with calls that are: delivering new messsage and all necessary underlying headers +//! with calls that are: delivering new message and all necessary underlying headers //! (parachain or relay chain). use crate::messages_call_ext::{ -- GitLab From b686bfefba9c9f18261d8cc0ff1afc055645d436 Mon Sep 17 00:00:00 2001 From: bader y Date: Wed, 20 Mar 2024 09:26:59 -0400 Subject: [PATCH 069/187] Defensive Programming in Substrate Reference Document (#2615) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _This PR is being continued from https://github.com/paritytech/polkadot-sdk/pull/2206, which was closed when the developer_hub was merged._ closes https://github.com/paritytech/polkadot-sdk-docs/issues/44 --- # Description This PR adds a reference document to the `developer-hub` crate (see https://github.com/paritytech/polkadot-sdk/pull/2102). This specific reference document covers defensive programming practices common within the context of developing a runtime with Substrate. In particular, this covers the following areas: - Default behavior of how Rust deals with numbers in general - How to deal with floating point numbers in runtime / fixed point arithmetic - How to deal with Integer overflows - General "safe math" / defensive programming practices for common pallet development scenarios - Defensive traits that exist within Substrate, i.e., `defensive_saturating_add `, `defensive_unwrap_or` - More general defensive programming examples (keep it concise) - Link to relevant examples where these practices are actually in production / being used - Unwrapping (or rather lack thereof) 101 todo -- - [x] Apply feedback from previous PR - [x] This may warrant a PR to append some of these docs to `sp_arithmetic` --------- Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Gonçalo Pestana Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Francisco Aguirre Co-authored-by: Radha <86818441+DrW3RK@users.noreply.github.com> --- Cargo.lock | 6 + docs/sdk/Cargo.toml | 7 + docs/sdk/src/guides/your_first_pallet/mod.rs | 6 +- .../reference_docs/defensive_programming.rs | 395 ++++++++++++++++++ docs/sdk/src/reference_docs/mod.rs | 3 +- .../safe_defensive_programming.rs | 1 - substrate/primitives/arithmetic/Cargo.toml | 3 + .../primitives/arithmetic/src/fixed_point.rs | 27 ++ substrate/primitives/arithmetic/src/lib.rs | 138 ++++-- .../primitives/arithmetic/src/per_things.rs | 36 ++ 10 files changed, 588 insertions(+), 34 deletions(-) create mode 100644 docs/sdk/src/reference_docs/defensive_programming.rs delete mode 100644 docs/sdk/src/reference_docs/safe_defensive_programming.rs diff --git a/Cargo.lock b/Cargo.lock index b055c79cbbf..9e48887e17a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13376,7 +13376,9 @@ dependencies = [ "pallet-assets", "pallet-aura", "pallet-authorship", + "pallet-babe", "pallet-balances", + "pallet-broker", "pallet-collective", "pallet-default-config-example", "pallet-democracy", @@ -13385,6 +13387,7 @@ dependencies = [ "pallet-examples", "pallet-multisig", "pallet-proxy", + "pallet-referenda", "pallet-scheduler", "pallet-timestamp", "pallet-transaction-payment", @@ -13404,6 +13407,7 @@ dependencies = [ "scale-info", "simple-mermaid", "sp-api", + "sp-arithmetic", "sp-core", "sp-io", "sp-keyring", @@ -18395,6 +18399,7 @@ name = "sp-arithmetic" version = "23.0.0" dependencies = [ "criterion 0.4.0", + "docify 0.2.7", "integer-sqrt", "num-traits", "parity-scale-codec", @@ -18403,6 +18408,7 @@ dependencies = [ "scale-info", "serde", "sp-crypto-hashing", + "sp-std 14.0.0", "static_assertions", ] diff --git a/docs/sdk/Cargo.toml b/docs/sdk/Cargo.toml index 3f40a950c28..3f84d45640f 100644 --- a/docs/sdk/Cargo.toml +++ b/docs/sdk/Cargo.toml @@ -81,6 +81,13 @@ sp-api = { path = "../../substrate/primitives/api" } sp-core = { path = "../../substrate/primitives/core" } sp-keyring = { path = "../../substrate/primitives/keyring" } sp-runtime = { path = "../../substrate/primitives/runtime" } +sp-arithmetic = { path = "../../substrate/primitives/arithmetic" } + +# Misc pallet dependencies +pallet-referenda = { path = "../../substrate/frame/referenda" } +pallet-broker = { path = "../../substrate/frame/broker" } +pallet-babe = { path = "../../substrate/frame/babe" } + sp-offchain = { path = "../../substrate/primitives/offchain" } sp-version = { path = "../../substrate/primitives/version" } diff --git a/docs/sdk/src/guides/your_first_pallet/mod.rs b/docs/sdk/src/guides/your_first_pallet/mod.rs index c633c0a69ed..c6e0dd0edf8 100644 --- a/docs/sdk/src/guides/your_first_pallet/mod.rs +++ b/docs/sdk/src/guides/your_first_pallet/mod.rs @@ -105,8 +105,8 @@ //! This macro will call `.into()` under the hood. #![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", transfer_better)] //! -//! Moreover, you will learn in the [Safe Defensive Programming -//! section](crate::reference_docs::safe_defensive_programming) that it is always recommended to use +//! Moreover, you will learn in the [Defensive Programming +//! section](crate::reference_docs::defensive_programming) that it is always recommended to use //! safe arithmetic operations in your runtime. By using [`frame::traits::CheckedSub`], we can not //! only take a step in that direction, but also improve the error handing and make it slightly more //! ergonomic. @@ -294,7 +294,7 @@ //! The following topics where used in this guide, but not covered in depth. It is suggested to //! study them subsequently: //! -//! - [`crate::reference_docs::safe_defensive_programming`]. +//! - [`crate::reference_docs::defensive_programming`]. //! - [`crate::reference_docs::frame_origin`]. //! - [`crate::reference_docs::frame_runtime_types`]. //! - The pallet we wrote in this guide was using `dev_mode`, learn more in diff --git a/docs/sdk/src/reference_docs/defensive_programming.rs b/docs/sdk/src/reference_docs/defensive_programming.rs new file mode 100644 index 00000000000..9828e1b5091 --- /dev/null +++ b/docs/sdk/src/reference_docs/defensive_programming.rs @@ -0,0 +1,395 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! [Defensive programming](https://en.wikipedia.org/wiki/Defensive_programming) is a design paradigm that enables a program to continue +//! running despite unexpected behavior, input, or events that may arise in runtime. +//! Usually, unforeseen circumstances may cause the program to stop or, in the Rust context, +//! panic!. Defensive practices allow for these circumstances to be accounted for ahead of time +//! and for them to be handled gracefully, which is in line with the intended fault-tolerant and +//! deterministic nature of blockchains. +//! +//! The Polkadot SDK is built to reflect these principles and to facilitate their usage accordingly. +//! +//! ## General Overview +//! +//! When developing within the context of the Substrate runtime, there is one golden rule: +//! +//! ***DO NOT PANIC***. There are some exceptions, but generally, this is the default precedent. +//! +//! > It’s important to differentiate between the runtime and node. The runtime refers to the core +//! > business logic of a Substrate-based chain, whereas the node refers to the outer client, which +//! > deals with telemetry and gossip from other nodes. For more information, read about +//! > [Substrate's node +//! > architecture](crate::reference_docs::wasm_meta_protocol#node-vs-runtime). It’s also important +//! > to note that the criticality of the node is slightly lesser +//! > than that of the runtime, which is why you may see `unwrap()` or other “non-defensive” +//! > approaches +//! in a few places of the node's code repository. +//! +//! Most of these practices fall within Rust's +//! colloquial usage of proper error propagation, handling, and arithmetic-based edge cases. +//! +//! General guidelines: +//! +//! - **Avoid writing functions that could explicitly panic,** such as directly using `unwrap()` on +//! a [`Result`], or accessing an out-of-bounds index on a collection. Safer methods to access +//! collection types, i.e., `get()` which allow defensive handling of the resulting [`Option`] are +//! recommended to be used. +//! - **It may be acceptable to use `except()`,** but only if one is completely certain (and has +//! performed a check beforehand) that a value won't panic upon unwrapping. *Even this is +//! discouraged*, however, as future changes to that function could then cause that statement to +//! panic. It is important to ensure all possible errors are propagated and handled effectively. +//! - **If a function *can* panic,** it usually is prefaced with `unchecked_` to indicate its +//! unsafety. +//! - **If you are writing a function that could panic,** [document it!](https://doc.rust-lang.org/rustdoc/how-to-write-documentation.html#documenting-components) +//! - **Carefully handle mathematical operations.** Many seemingly, simplistic operations, such as +//! **arithmetic** in the runtime, could present a number of issues [(see more later in this +//! document)](#integer-overflow). Use checked arithmetic wherever possible. +//! +//! These guidelines could be summarized in the following example, where `bad_pop` is prone to +//! panicking, and `good_pop` allows for proper error handling to take place: +//! +//!```ignore +//! // Bad pop always requires that we return something, even if vector/array is empty. +//! fn bad_pop(v: Vec) -> T {} +//! // Good pop allows us to return None from the Option if need be. +//! fn good_pop(v: Vec) -> Option {} +//! ``` +//! +//! ### Defensive Traits +//! +//! The [`Defensive`](frame::traits::Defensive) trait provides a number of functions, all of which +//! provide an alternative to 'vanilla' Rust functions, e.g.,: +//! +//! - [`defensive_unwrap_or()`](frame::traits::Defensive::defensive_unwrap_or) instead of +//! `unwrap_or()` +//! - [`defensive_ok_or()`](frame::traits::DefensiveOption::defensive_ok_or) instead of `ok_or()` +//! +//! Defensive methods use [`debug_assertions`](https://doc.rust-lang.org/reference/conditional-compilation.html#debug_assertions), which panic in development, but in +//! production/release, they will merely log an error (i.e., `log::error`). +//! +//! The [`Defensive`](frame::traits::Defensive) trait and its various implementations can be found +//! [here](frame::traits::Defensive). +//! +//! ## Integer Overflow +//! +//! The Rust compiler prevents static overflow from happening at compile time. +//! The compiler panics in **debug** mode in the event of an integer overflow. In +//! **release** mode, it resorts to silently _wrapping_ the overflowed amount in a modular fashion +//! (from the `MAX` back to zero). +//! +//! In runtime development, we don't always have control over what is being supplied +//! as a parameter. For example, even this simple add function could present one of two outcomes +//! depending on whether it is in **release** or **debug** mode: +//! +//! ```ignore +//! fn naive_add(x: u8, y: u8) -> u8 { +//! x + y +//! } +//! ``` +//! If we passed overflow-able values at runtime, this could panic (or wrap if in release). +//! +//! ```ignore +//! naive_add(250u8, 10u8); // In debug mode, this would panic. In release, this would return 4. +//! ``` +//! +//! It is the silent portion of this behavior that presents a real issue. Such behavior should be +//! made obvious, especially in blockchain development, where unsafe arithmetic could produce +//! unexpected consequences like a user balance over or underflowing. +//! +//! Fortunately, there are ways to both represent and handle these scenarios depending on our +//! specific use case natively built into Rust and libraries like [`sp_arithmetic`]. +//! +//! ## Infallible Arithmetic +//! +//! Both Rust and Substrate provide safe ways to deal with numbers and alternatives to floating +//! point arithmetic. +//! +//! Known scenarios that could be fallible should be avoided: i.e., avoiding the possibility of +//! dividing/modulo by zero at any point should be mitigated. One should be opting for a +//! `checked_*` method to introduce safe arithmetic in their code in most cases. +//! +//! A developer should use fixed-point instead of floating-point arithmetic to mitigate the +//! potential for inaccuracy, rounding errors, or other unexpected behavior. +//! +//! - [Fixed point types](sp_arithmetic::fixed_point) and their associated usage can be found here. +//! - [PerThing](sp_arithmetic::per_things) and its associated types can be found here. +//! +//! Using floating point number types (i.e., f32. f64) in the runtime should be avoided, as a single non-deterministic result could cause chaos for blockchain consensus along with the issues above. For more on the specifics of the peculiarities of floating point calculations, [watch this video by the Computerphile](https://www.youtube.com/watch?v=PZRI1IfStY0). +//! +//! The following methods demonstrate different ways to handle numbers natively in Rust safely, +//! without fear of panic or unexpected behavior from wrapping. +//! +//! ### Checked Arithmetic +//! +//! **Checked operations** utilize an `Option` as a return type. This allows for +//! catching any unexpected behavior in the event of an overflow through simple pattern matching. +//! +//! This is an example of a valid operation: +#![doc = docify::embed!("./src/reference_docs/defensive_programming.rs", checked_add_example)] +//! +//! This is an example of an invalid operation. In this case, a simulated integer overflow, which +//! would simply result in `None`: +#![doc = docify::embed!( + "./src/reference_docs/defensive_programming.rs", + checked_add_handle_error_example +)] +//! +//! Suppose you aren’t sure which operation to use for runtime math. In that case, checked +//! operations are the safest bet, presenting two predictable (and erroring) outcomes that can be +//! handled accordingly (Some and None). +//! +//! The following conventions can be seen within the Polkadot SDK, where it is +//! handled in two ways: +//! +//! - As an [`Option`], using the `if let` / `if` or `match` +//! - As a [`Result`], via `ok_or` (or similar conversion to [`Result`] from [`Option`]) +//! +//! #### Handling via Option - More Verbose +//! +//! Because wrapped operations return `Option`, you can use a more verbose/explicit form of error +//! handling via `if` or `if let`: +#![doc = docify::embed!("./src/reference_docs/defensive_programming.rs", increase_balance)] +//! +//! Optionally, match may also be directly used in a more concise manner: +#![doc = docify::embed!("./src/reference_docs/defensive_programming.rs", increase_balance_match)] +//! +//! This is generally a useful convention for handling checked types and most types that return +//! `Option`. +//! +//! #### Handling via Result - Less Verbose +//! +//! In the Polkadot SDK codebase, checked operations are handled as a `Result` via `ok_or`. This is +//! a less verbose way of expressing the above. This usage often boils down to the developer’s +//! preference: +#![doc = docify::embed!("./src/reference_docs/defensive_programming.rs", increase_balance_result)] +//! +//! ### Saturating Operations +//! +//! Saturating a number limits it to the type’s upper or lower bound, even if the integer type +//! overflowed in runtime. For example, adding to `u32::MAX` would simply limit itself to +//! `u32::MAX`: +#![doc = docify::embed!("./src/reference_docs/defensive_programming.rs", saturated_add_example)] +//! +//! Saturating calculations can be used if one is very sure that something won't overflow, but wants +//! to avoid introducing the notion of any potential-panic or wrapping behavior. +//! +//! There is also a series of defensive alternatives via +//! [`DefensiveSaturating`](frame::traits::DefensiveSaturating), which introduces the same behavior +//! of the [`Defensive`](frame::traits::Defensive) trait, only with saturating, mathematical +//! operations: +#![doc = docify::embed!( + "./src/reference_docs/defensive_programming.rs", + saturated_defensive_example +)] +//! +//! ### Mathematical Operations in Substrate Development - Further Context +//! +//! As a recap, we covered the following concepts: +//! +//! 1. **Checked** operations - using [`Option`] or [`Result`] +//! 2. **Saturating** operations - limited to the lower and upper bounds of a number type +//! 3. **Wrapped** operations (the default) - wrap around to above or below the bounds of a type +//! +//! #### The problem with 'default' wrapped operations +//! +//! **Wrapped operations** cause the overflow to wrap around to either the maximum or minimum of +//! that type. Imagine this in the context of a blockchain, where there are account balances, voting +//! counters, nonces for transactions, and other aspects of a blockchain. +//! +//! While it may seem trivial, choosing how to handle numbers is quite important. As a thought +//! exercise, here are some scenarios of which will shed more light on when to use which. +//! +//! #### Bob's Overflowed Balance +//! +//! **Bob's** balance exceeds the `Balance` type on the `EduChain`. Because the pallet developer did +//! not handle the calculation to add to Bob's balance with any regard to this overflow, **Bob's** +//! balance is now essentially `0`, the operation **wrapped**. +//! +//!
+//! Solution: Saturating or Checked +//! For Bob's balance problems, using a `saturating_add` or `checked_add` could've mitigated +//! this issue. They simply would've reached the upper, or lower bounds, of the particular type for +//! an on-chain balance. In other words: Bob's balance would've stayed at the maximum of the +//! Balance type.
+//! +//! #### Alice's 'Underflowed' Balance +//! +//! Alice’s balance has reached `0` after a transfer to Bob. Suddenly, she has been slashed on +//! EduChain, causing her balance to reach near the limit of `u32::MAX` - a very large amount - as +//! wrapped operations can go both ways. Alice can now successfully vote using her new, overpowered +//! token balance, destroying the chain's integrity. +//! +//!
+//! Solution: Saturating +//! For Alice's balance problem, using `saturated_sub` could've mitigated this issue. A saturating +//! calculation would've simply limited her balance to the lower bound of u32, as having a negative +//! balance is not a concept within blockchains. In other words: Alice's balance would've stayed +//! at "0", even after being slashed. +//! +//! This is also an example that while one system may work in isolation, shared interfaces, such +//! as the notion of balances, are often shared across multiple pallets - meaning these small +//! changes can make a big difference depending on the scenario.
+//! +//! #### Proposal ID Overwrite +//! +//! A `u8` parameter, called `proposals_count`, represents the type for counting the number of +//! proposals on-chain. Every time a new proposal is added to the system, this number increases. +//! With the proposal pallet's high usage, it has reached `u8::MAX`’s limit of 255, causing +//! `proposals_count` to go to 0. Unfortunately, this results in new proposals overwriting old ones, +//! effectively erasing any notion of past proposals! +//! +//!
+//! Solution: Checked +//! For the proposal IDs, proper handling via `checked` math would've been suitable, +//! Saturating could've been used - but it also would've 'failed' silently. Using `checked_add` to +//! ensure that the next proposal ID would've been valid would've been a viable way to let the user +//! know the state of their proposal: +//! +//! ```ignore +//! let next_proposal_id = current_count.checked_add(1).ok_or_else(|| Error::TooManyProposals)?; +//! ``` +//! +//!
+//! +//! From the above, we can clearly see the problematic nature of seemingly simple operations in the +//! runtime, and care should be given to ensure a defensive approach is taken. +//! +//! ### Edge cases of `panic!`-able instances in Substrate +//! +//! As you traverse through the codebase (particularly in `substrate/frame`, where the majority of +//! runtime code lives), you may notice that there (only a few!) occurrences where `panic!` is used +//! explicitly. This is used when the runtime should stall, rather than keep running, as that is +//! considered safer. Particularly when it comes to mission-critical components, such as block +//! authoring, consensus, or other protocol-level dependencies, going through with an action may +//! actually cause harm to the network, and thus stalling would be the better option. +//! +//! Take the example of the BABE pallet ([`pallet_babe`]), which doesn't allow for a validator to +//! participate if it is disabled (see: [`frame::traits::DisabledValidators`]): +//! +//! ```ignore +//! if T::DisabledValidators::is_disabled(authority_index) { +//! panic!( +//! "Validator with index {:?} is disabled and should not be attempting to author blocks.", +//! authority_index, +//! ); +//! } +//! ``` +//! +//! There are other examples in various pallets, mostly those crucial to the blockchain’s +//! functionality. Most of the time, you will not be writing pallets which operate at this level, +//! but these exceptions should be noted regardless. +//! +//! ## Other Resources +//! +//! - [PBA Book - FRAME Tips & Tricks](https://polkadot-blockchain-academy.github.io/pba-book/substrate/tips-tricks/page.html?highlight=perthing#substrate-and-frame-tips-and-tricks) +#![allow(dead_code)] +#[allow(unused_variables)] +mod fake_runtime_types { + // Note: The following types are purely for the purpose of example, and do not contain any + // *real* use case other than demonstrating various concepts. + pub enum RuntimeError { + Overflow, + UserDoesntExist, + } + + pub type Address = (); + + pub struct Runtime; + + impl Runtime { + fn get_balance(account: Address) -> Result { + Ok(0u64) + } + + fn set_balance(account: Address, new_balance: u64) {} + } + + #[docify::export] + fn increase_balance(account: Address, amount: u64) -> Result<(), RuntimeError> { + // Get a user's current balance + let balance = Runtime::get_balance(account)?; + // SAFELY increase the balance by some amount + if let Some(new_balance) = balance.checked_add(amount) { + Runtime::set_balance(account, new_balance); + Ok(()) + } else { + Err(RuntimeError::Overflow) + } + } + + #[docify::export] + fn increase_balance_match(account: Address, amount: u64) -> Result<(), RuntimeError> { + // Get a user's current balance + let balance = Runtime::get_balance(account)?; + // SAFELY increase the balance by some amount + let new_balance = match balance.checked_add(amount) { + Some(balance) => balance, + None => { + return Err(RuntimeError::Overflow); + }, + }; + Runtime::set_balance(account, new_balance); + Ok(()) + } + + #[docify::export] + fn increase_balance_result(account: Address, amount: u64) -> Result<(), RuntimeError> { + // Get a user's current balance + let balance = Runtime::get_balance(account)?; + // SAFELY increase the balance by some amount - this time, by using `ok_or` + let new_balance = balance.checked_add(amount).ok_or(RuntimeError::Overflow)?; + Runtime::set_balance(account, new_balance); + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use frame::traits::DefensiveSaturating; + #[docify::export] + #[test] + fn checked_add_example() { + // This is valid, as 20 is perfectly within the bounds of u32. + let add = (10u32).checked_add(10); + assert_eq!(add, Some(20)) + } + + #[docify::export] + #[test] + fn checked_add_handle_error_example() { + // This is invalid - we are adding something to the max of u32::MAX, which would overflow. + // Luckily, checked_add just marks this as None! + let add = u32::MAX.checked_add(10); + assert_eq!(add, None) + } + + #[docify::export] + #[test] + fn saturated_add_example() { + // Saturating add simply saturates + // to the numeric bound of that type if it overflows. + let add = u32::MAX.saturating_add(10); + assert_eq!(add, u32::MAX) + } + + #[docify::export] + #[test] + #[cfg_attr(debug_assertions, should_panic(expected = "Defensive failure has been triggered!"))] + fn saturated_defensive_example() { + let saturated_defensive = u32::MAX.defensive_saturating_add(10); + assert_eq!(saturated_defensive, u32::MAX); + } +} diff --git a/docs/sdk/src/reference_docs/mod.rs b/docs/sdk/src/reference_docs/mod.rs index de0b012bb12..a0d8d05b449 100644 --- a/docs/sdk/src/reference_docs/mod.rs +++ b/docs/sdk/src/reference_docs/mod.rs @@ -47,8 +47,7 @@ pub mod signed_extensions; pub mod frame_origin; /// Learn about how to write safe and defensive code in your FRAME runtime. -// TODO: @CrackTheCode016 https://github.com/paritytech/polkadot-sdk-docs/issues/44 -pub mod safe_defensive_programming; +pub mod defensive_programming; /// Learn about composite enums and other runtime level types, such as "RuntimeEvent" and /// "RuntimeCall". diff --git a/docs/sdk/src/reference_docs/safe_defensive_programming.rs b/docs/sdk/src/reference_docs/safe_defensive_programming.rs deleted file mode 100644 index 9d0f028e570..00000000000 --- a/docs/sdk/src/reference_docs/safe_defensive_programming.rs +++ /dev/null @@ -1 +0,0 @@ -//! diff --git a/substrate/primitives/arithmetic/Cargo.toml b/substrate/primitives/arithmetic/Cargo.toml index 29c406b10b7..64c1025b585 100644 --- a/substrate/primitives/arithmetic/Cargo.toml +++ b/substrate/primitives/arithmetic/Cargo.toml @@ -26,6 +26,8 @@ num-traits = { version = "0.2.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], optional = true, workspace = true } static_assertions = "1.1.0" +sp-std = { path = "../std", default-features = false } +docify = "0.2.7" [dev-dependencies] criterion = "0.4.0" @@ -41,6 +43,7 @@ std = [ "scale-info/std", "serde/std", "sp-crypto-hashing/std", + "sp-std/std", ] # Serde support without relying on std features. serde = ["dep:serde", "scale-info/serde"] diff --git a/substrate/primitives/arithmetic/src/fixed_point.rs b/substrate/primitives/arithmetic/src/fixed_point.rs index 46c09df2186..736a900bde2 100644 --- a/substrate/primitives/arithmetic/src/fixed_point.rs +++ b/substrate/primitives/arithmetic/src/fixed_point.rs @@ -16,6 +16,33 @@ // limitations under the License. //! Decimal Fixed Point implementations for Substrate runtime. +//! Similar to types that implement [`PerThing`](crate::per_things), these are also +//! fixed-point types, however, they are able to represent larger fractions: +#![doc = docify::embed!("./src/lib.rs", fixed_u64)] +//! +//! ### Fixed Point Types in Practice +//! +//! If one needs to exceed the value of one (1), then +//! [`FixedU64`](FixedU64) (and its signed and `u128` counterparts) can be utilized. +//! Take for example this very rudimentary pricing mechanism, where we wish to calculate the demand +//! / supply to get a price for some on-chain compute: +#![doc = docify::embed!( + "./src/lib.rs", + fixed_u64_block_computation_example +)] +//! +//! For a much more comprehensive example, be sure to look at the source for broker (the "coretime") +//! pallet. +//! +//! #### Fixed Point Types in Practice +//! +//! Just as with [`PerThing`](PerThing), you can also perform regular mathematical +//! expressions: +#![doc = docify::embed!( + "./src/lib.rs", + fixed_u64_operation_example +)] +//! use crate::{ helpers_128bit::{multiply_by_rational_with_rounding, sqrt}, diff --git a/substrate/primitives/arithmetic/src/lib.rs b/substrate/primitives/arithmetic/src/lib.rs index 33992e15423..01c403a7c4a 100644 --- a/substrate/primitives/arithmetic/src/lib.rs +++ b/substrate/primitives/arithmetic/src/lib.rs @@ -101,7 +101,7 @@ where fn tcmp(&self, other: &T, threshold: T) -> Ordering { // early exit. if threshold.is_zero() { - return self.cmp(other) + return self.cmp(other); } let upper_bound = other.saturating_add(threshold); @@ -206,12 +206,12 @@ where // Nothing to do here. if count.is_zero() { - return Ok(Vec::::new()) + return Ok(Vec::::new()); } let diff = targeted_sum.max(sum) - targeted_sum.min(sum); if diff.is_zero() { - return Ok(input.to_vec()) + return Ok(input.to_vec()); } let needs_bump = targeted_sum > sum; @@ -254,7 +254,7 @@ where min_index += 1; min_index %= count; } - leftover -= One::one() + leftover -= One::one(); } } else { // must decrease the stakes a bit. decrement from the max element. index of maximum is now @@ -288,7 +288,7 @@ where if output_with_idx[max_index].1 <= threshold { max_index = max_index.checked_sub(1).unwrap_or(count - 1); } - leftover -= One::one() + leftover -= One::one(); } else { max_index = max_index.checked_sub(1).unwrap_or(count - 1); } @@ -300,7 +300,7 @@ where targeted_sum, "sum({:?}) != {:?}", output_with_idx, - targeted_sum, + targeted_sum ); // sort again based on the original index. @@ -356,7 +356,7 @@ mod normalize_tests { vec![ Perbill::from_parts(333333334), Perbill::from_parts(333333333), - Perbill::from_parts(333333333), + Perbill::from_parts(333333333) ] ); @@ -367,7 +367,7 @@ mod normalize_tests { vec![ Perbill::from_parts(316666668), Perbill::from_parts(383333332), - Perbill::from_parts(300000000), + Perbill::from_parts(300000000) ] ); } @@ -378,13 +378,13 @@ mod normalize_tests { // could have a situation where the sum cannot be calculated in the inner type. Calculating // using the upper type of the per_thing should assure this to be okay. assert_eq!( - vec![PerU16::from_percent(40), PerU16::from_percent(40), PerU16::from_percent(40),] + vec![PerU16::from_percent(40), PerU16::from_percent(40), PerU16::from_percent(40)] .normalize(PerU16::one()) .unwrap(), vec![ PerU16::from_parts(21845), // 33% PerU16::from_parts(21845), // 33% - PerU16::from_parts(21845), // 33% + PerU16::from_parts(21845) // 33% ] ); } @@ -428,6 +428,88 @@ mod normalize_tests { } } +#[cfg(test)] +mod per_and_fixed_examples { + use super::*; + + #[docify::export] + #[test] + fn percent_mult() { + let percent = Percent::from_rational(5u32, 100u32); // aka, 5% + let five_percent_of_100 = percent * 100u32; // 5% of 100 is 5. + assert_eq!(five_percent_of_100, 5) + } + #[docify::export] + #[test] + fn perbill_example() { + let p = Perbill::from_percent(80); + // 800000000 bil, or a representative of 0.800000000. + // Precision is in the billions place. + assert_eq!(p.deconstruct(), 800000000); + } + + #[docify::export] + #[test] + fn percent_example() { + let percent = Percent::from_rational(190u32, 400u32); + assert_eq!(percent.deconstruct(), 47); + } + + #[docify::export] + #[test] + fn fixed_u64_block_computation_example() { + // Calculate a very rudimentary on-chain price from supply / demand + // Supply: Cores available per block + // Demand: Cores being ordered per block + let price = FixedU64::from_rational(5u128, 10u128); + + // 0.5 DOT per core + assert_eq!(price, FixedU64::from_float(0.5)); + + // Now, the story has changed - lots of demand means we buy as many cores as there + // available. This also means that price goes up! For the sake of simplicity, we don't care + // about who gets a core - just about our very simple price model + + // Calculate a very rudimentary on-chain price from supply / demand + // Supply: Cores available per block + // Demand: Cores being ordered per block + let price = FixedU64::from_rational(19u128, 10u128); + + // 1.9 DOT per core + assert_eq!(price, FixedU64::from_float(1.9)); + } + + #[docify::export] + #[test] + fn fixed_u64() { + // The difference between this and perthings is perthings operates within the relam of [0, + // 1] In cases where we need > 1, we can used fixed types such as FixedU64 + + let rational_1 = FixedU64::from_rational(10, 5); //" 200%" aka 2. + let rational_2 = FixedU64::from_rational_with_rounding(5, 10, Rounding::Down); // "50%" aka 0.50... + + assert_eq!(rational_1, (2u64).into()); + assert_eq!(rational_2.into_perbill(), Perbill::from_float(0.5)); + } + + #[docify::export] + #[test] + fn fixed_u64_operation_example() { + let rational_1 = FixedU64::from_rational(10, 5); // "200%" aka 2. + let rational_2 = FixedU64::from_rational(8, 5); // "160%" aka 1.6. + + let addition = rational_1 + rational_2; + let multiplication = rational_1 * rational_2; + let division = rational_1 / rational_2; + let subtraction = rational_1 - rational_2; + + assert_eq!(addition, FixedU64::from_float(3.6)); + assert_eq!(multiplication, FixedU64::from_float(3.2)); + assert_eq!(division, FixedU64::from_float(1.25)); + assert_eq!(subtraction, FixedU64::from_float(0.4)); + } +} + #[cfg(test)] mod threshold_compare_tests { use super::*; @@ -440,15 +522,15 @@ mod threshold_compare_tests { let e = Perbill::from_percent(10).mul_ceil(b); // [115 - 11,5 (103,5), 115 + 11,5 (126,5)] is all equal - assert_eq!(103u32.tcmp(&b, e), Ordering::Equal); - assert_eq!(104u32.tcmp(&b, e), Ordering::Equal); - assert_eq!(115u32.tcmp(&b, e), Ordering::Equal); - assert_eq!(120u32.tcmp(&b, e), Ordering::Equal); - assert_eq!(126u32.tcmp(&b, e), Ordering::Equal); - assert_eq!(127u32.tcmp(&b, e), Ordering::Equal); - - assert_eq!(128u32.tcmp(&b, e), Ordering::Greater); - assert_eq!(102u32.tcmp(&b, e), Ordering::Less); + assert_eq!((103u32).tcmp(&b, e), Ordering::Equal); + assert_eq!((104u32).tcmp(&b, e), Ordering::Equal); + assert_eq!((115u32).tcmp(&b, e), Ordering::Equal); + assert_eq!((120u32).tcmp(&b, e), Ordering::Equal); + assert_eq!((126u32).tcmp(&b, e), Ordering::Equal); + assert_eq!((127u32).tcmp(&b, e), Ordering::Equal); + + assert_eq!((128u32).tcmp(&b, e), Ordering::Greater); + assert_eq!((102u32).tcmp(&b, e), Ordering::Less); } #[test] @@ -458,15 +540,15 @@ mod threshold_compare_tests { let e = Perbill::from_parts(100) * b; // [115 - 11,5 (103,5), 115 + 11,5 (126,5)] is all equal - assert_eq!(103u32.tcmp(&b, e), 103u32.cmp(&b)); - assert_eq!(104u32.tcmp(&b, e), 104u32.cmp(&b)); - assert_eq!(115u32.tcmp(&b, e), 115u32.cmp(&b)); - assert_eq!(120u32.tcmp(&b, e), 120u32.cmp(&b)); - assert_eq!(126u32.tcmp(&b, e), 126u32.cmp(&b)); - assert_eq!(127u32.tcmp(&b, e), 127u32.cmp(&b)); - - assert_eq!(128u32.tcmp(&b, e), 128u32.cmp(&b)); - assert_eq!(102u32.tcmp(&b, e), 102u32.cmp(&b)); + assert_eq!((103u32).tcmp(&b, e), (103u32).cmp(&b)); + assert_eq!((104u32).tcmp(&b, e), (104u32).cmp(&b)); + assert_eq!((115u32).tcmp(&b, e), (115u32).cmp(&b)); + assert_eq!((120u32).tcmp(&b, e), (120u32).cmp(&b)); + assert_eq!((126u32).tcmp(&b, e), (126u32).cmp(&b)); + assert_eq!((127u32).tcmp(&b, e), (127u32).cmp(&b)); + + assert_eq!((128u32).tcmp(&b, e), (128u32).cmp(&b)); + assert_eq!((102u32).tcmp(&b, e), (102u32).cmp(&b)); } #[test] diff --git a/substrate/primitives/arithmetic/src/per_things.rs b/substrate/primitives/arithmetic/src/per_things.rs index 057bfd7bf88..f73dbe30cec 100644 --- a/substrate/primitives/arithmetic/src/per_things.rs +++ b/substrate/primitives/arithmetic/src/per_things.rs @@ -15,6 +15,42 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! Types that implement [`PerThing`](PerThing) can be used as a floating-point alternative for +//! numbers that operate within the realm of `[0, 1]`. The primary types may you encounter in +//! Substrate would be the following: +//! - [`Percent`](Percent) - parts of one hundred. +//! - [`Permill`](Permill) - parts of a million. +//! - [`Perbill`](Perbill) - parts of a billion. +//! +//! In use, you may see them being used as follows: +//! +//! > **[`Perbill`](Perbill), parts of a billion** +#![doc = docify::embed!("./src/lib.rs", perbill_example)] +//! > **[`Percent`](Percent), parts of a hundred** +#![doc = docify::embed!("./src/lib.rs", percent_example)] +//! +//! Note that `Percent` is represented as a _rounded down_, fixed point +//! number (see the example above). Unlike primitive types, types that implement +//! [`PerThing`](PerThing) will also not overflow, and are therefore safe to use. +//! They adopt the same behavior that a saturated calculation would provide, meaning that if one is +//! to go over "100%", it wouldn't overflow, but simply stop at the upper or lower bound. +//! +//! For use cases which require precision beyond the range of `[0, 1]`, there are fixed-point types +//! which can be used. +//! +//! Each of these can be used to construct and represent ratios within our runtime. +//! You will find types like [`Perbill`](Perbill) being used often in pallet +//! development. `pallet_referenda` is a good example of a pallet which makes good use of fixed +//! point arithmetic, as it relies on representing various curves and thresholds relating to +//! governance. +//! +//! #### Fixed Point Arithmetic with [`PerThing`](PerThing) +//! +//! As stated, one can also perform mathematics using these types directly. For example, finding the +//! percentage of a particular item: + +#![doc = docify::embed!("./src/lib.rs", percent_mult)] + #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -- GitLab From b74353d3e94ca685e953f5138f0676214140dcdd Mon Sep 17 00:00:00 2001 From: eskimor Date: Wed, 20 Mar 2024 14:53:55 +0100 Subject: [PATCH 070/187] Fix algorithmic complexity of on-demand scheduler with regards to number of cores. (#3190) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We witnessed really poor performance on Rococo, where we ended up with 50 on-demand cores. This was due to the fact that for each core the full queue was processed. With this change full queue processing will happen way less often (most of the time complexity is O(1) or O(log(n))) and if it happens then only for one core (in expectation). Also spot price is now updated before each order to ensure economic back pressure. TODO: - [x] Implement - [x] Basic tests - [x] Add more tests (see todos) - [x] Run benchmark to confirm better performance, first results suggest > 100x faster. - [x] Write migrations - [x] Bump scale-info version and remove patch in Cargo.toml - [x] Write PR docs: on-demand performance improved, more on-demand cores are now non problematic anymore. If need by also the max queue size can be increased again. (Maybe not to 10k) Optional: Performance can be improved even more, if we called `pop_assignment_for_core()`, before calling `report_processed` (Avoid needless affinity drops). The effect gets smaller the larger the claim queue and I would only go for it, if it does not add complexity to the scheduler. --------- Co-authored-by: eskimor Co-authored-by: antonva Co-authored-by: command-bot <> Co-authored-by: Anton Vilhelm Ásgeirsson Co-authored-by: ordian --- Cargo.lock | 8 +- polkadot/primitives/src/lib.rs | 3 +- polkadot/primitives/src/v6/mod.rs | 7 + polkadot/runtime/parachains/Cargo.toml | 2 +- .../src/assigner_on_demand/benchmarking.rs | 11 +- .../src/assigner_on_demand/migration.rs | 181 +++++ .../parachains/src/assigner_on_demand/mod.rs | 690 ++++++++++++------ .../src/assigner_on_demand/tests.rs | 514 +++++++------ .../runtime/parachains/src/configuration.rs | 10 +- polkadot/runtime/rococo/src/lib.rs | 1 + .../runtime_parachains_assigner_on_demand.rs | 72 +- .../runtime_parachains_assigner_on_demand.rs | 76 +- prdoc/pr_3190.prdoc | 17 + 13 files changed, 1046 insertions(+), 546 deletions(-) create mode 100644 polkadot/runtime/parachains/src/assigner_on_demand/migration.rs create mode 100644 prdoc/pr_3190.prdoc diff --git a/Cargo.lock b/Cargo.lock index 9e48887e17a..5401dc5ecfb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17005,9 +17005,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7d66a1128282b7ef025a8ead62a4a9fcf017382ec53b8ffbf4d7bf77bd3c60" +checksum = "2ef2175c2907e7c8bc0a9c3f86aeb5ec1f3b275300ad58a44d0c3ae379a5e52e" dependencies = [ "bitvec", "cfg-if", @@ -17019,9 +17019,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf2c68b89cafb3b8d918dd07b42be0da66ff202cf1155c5739a4e0c1ea0dc19" +checksum = "634d9b8eb8fd61c5cdd3390d9b2132300a7e7618955b98b8416f118c1b4e144f" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", diff --git a/polkadot/primitives/src/lib.rs b/polkadot/primitives/src/lib.rs index 2ddd9b58dfe..745195ce092 100644 --- a/polkadot/primitives/src/lib.rs +++ b/polkadot/primitives/src/lib.rs @@ -58,7 +58,8 @@ pub use v6::{ ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, ValidityAttestation, ValidityError, ASSIGNMENT_KEY_TYPE_ID, LEGACY_MIN_BACKING_VOTES, LOWEST_PUBLIC_ID, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MAX_POV_SIZE, MIN_CODE_SIZE, - ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, PARACHAINS_INHERENT_IDENTIFIER, PARACHAIN_KEY_TYPE_ID, + ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, ON_DEMAND_MAX_QUEUE_MAX_SIZE, PARACHAINS_INHERENT_IDENTIFIER, + PARACHAIN_KEY_TYPE_ID, }; #[cfg(feature = "std")] diff --git a/polkadot/primitives/src/v6/mod.rs b/polkadot/primitives/src/v6/mod.rs index 742dbed1cd8..9e7f910314c 100644 --- a/polkadot/primitives/src/v6/mod.rs +++ b/polkadot/primitives/src/v6/mod.rs @@ -399,6 +399,13 @@ pub const MAX_POV_SIZE: u32 = 5 * 1024 * 1024; /// Can be adjusted in configuration. pub const ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE: u32 = 10_000; +/// Maximum for maximum queue size. +/// +/// Setting `on_demand_queue_max_size` to a value higher than this is unsound. This is more a +/// theoretical limit, just below enough what the target type supports, so comparisons are possible +/// even with indices that are overflowing the underyling type. +pub const ON_DEMAND_MAX_QUEUE_MAX_SIZE: u32 = 1_000_000_000; + /// Backing votes threshold used from the host prior to runtime API version 6 and from the runtime /// prior to v9 configuration migration. pub const LEGACY_MIN_BACKING_VOTES: u32 = 2; diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index 61040145476..6e693b83ae1 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -15,7 +15,7 @@ bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } log = { workspace = true } rustc-hex = { version = "2.1.0", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], workspace = true } derive_more = "0.99.17" bitflags = "1.3.2" diff --git a/polkadot/runtime/parachains/src/assigner_on_demand/benchmarking.rs b/polkadot/runtime/parachains/src/assigner_on_demand/benchmarking.rs index 8360e7a78d0..779d6f04e39 100644 --- a/polkadot/runtime/parachains/src/assigner_on_demand/benchmarking.rs +++ b/polkadot/runtime/parachains/src/assigner_on_demand/benchmarking.rs @@ -70,11 +70,7 @@ mod benchmarks { let para_id = ParaId::from(111u32); init_parathread::(para_id); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - let order = EnqueuedOrder::new(para_id); - - for _ in 0..s { - Pallet::::add_on_demand_order(order.clone(), QueuePushDirection::Back).unwrap(); - } + Pallet::::populate_queue(para_id, s); #[extrinsic_call] _(RawOrigin::Signed(caller.into()), BalanceOf::::max_value(), para_id) @@ -87,11 +83,8 @@ mod benchmarks { let para_id = ParaId::from(111u32); init_parathread::(para_id); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - let order = EnqueuedOrder::new(para_id); - for _ in 0..s { - Pallet::::add_on_demand_order(order.clone(), QueuePushDirection::Back).unwrap(); - } + Pallet::::populate_queue(para_id, s); #[extrinsic_call] _(RawOrigin::Signed(caller.into()), BalanceOf::::max_value(), para_id) diff --git a/polkadot/runtime/parachains/src/assigner_on_demand/migration.rs b/polkadot/runtime/parachains/src/assigner_on_demand/migration.rs new file mode 100644 index 00000000000..5071653377d --- /dev/null +++ b/polkadot/runtime/parachains/src/assigner_on_demand/migration.rs @@ -0,0 +1,181 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! A module that is responsible for migration of storage. +use super::*; +use frame_support::{ + migrations::VersionedMigration, pallet_prelude::ValueQuery, storage_alias, + traits::OnRuntimeUpgrade, weights::Weight, +}; + +mod v0 { + use super::*; + use sp_std::collections::vec_deque::VecDeque; + + #[derive(Encode, Decode, TypeInfo, Debug, PartialEq, Clone)] + pub(super) struct EnqueuedOrder { + pub para_id: ParaId, + } + + /// Keeps track of the multiplier used to calculate the current spot price for the on demand + /// assigner. + /// NOTE: Ignoring the `OnEmpty` field for the migration. + #[storage_alias] + pub(super) type SpotTraffic = StorageValue, FixedU128, ValueQuery>; + + /// The order storage entry. Uses a VecDeque to be able to push to the front of the + /// queue from the scheduler on session boundaries. + /// NOTE: Ignoring the `OnEmpty` field for the migration. + #[storage_alias] + pub(super) type OnDemandQueue = + StorageValue, VecDeque, ValueQuery>; +} + +mod v1 { + use super::*; + + use crate::assigner_on_demand::LOG_TARGET; + + /// Migration to V1 + pub struct UncheckedMigrateToV1(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for UncheckedMigrateToV1 { + fn on_runtime_upgrade() -> Weight { + let mut weight: Weight = Weight::zero(); + + // Migrate the current traffic value + let config = >::config(); + QueueStatus::::mutate(|mut queue_status| { + Pallet::::update_spot_traffic(&config, &mut queue_status); + + let v0_queue = v0::OnDemandQueue::::take(); + // Process the v0 queue into v1. + v0_queue.into_iter().for_each(|enqueued_order| { + // Readding the old orders will use the new systems. + Pallet::::add_on_demand_order( + queue_status, + enqueued_order.para_id, + QueuePushDirection::Back, + ); + }); + }); + + // Remove the old storage. + v0::OnDemandQueue::::kill(); // 1 write + v0::SpotTraffic::::kill(); // 1 write + + // Config read + weight.saturating_accrue(T::DbWeight::get().reads(1)); + // QueueStatus read write (update_spot_traffic) + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + // Kill x 2 + weight.saturating_accrue(T::DbWeight::get().writes(2)); + + log::info!(target: LOG_TARGET, "Migrated on demand assigner storage to v1"); + weight + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + let n: u32 = v0::OnDemandQueue::::get().len() as u32; + + log::info!( + target: LOG_TARGET, + "Number of orders waiting in the queue before: {n}", + ); + + Ok(n.encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + log::info!(target: LOG_TARGET, "Running post_upgrade()"); + + ensure!( + v0::OnDemandQueue::::get().is_empty(), + "OnDemandQueue should be empty after the migration" + ); + + let expected_len = u32::decode(&mut &state[..]).unwrap(); + let queue_status_size = QueueStatus::::get().size(); + ensure!( + expected_len == queue_status_size, + "Number of orders should be the same before and after migration" + ); + + let n_affinity_entries: u32 = + AffinityEntries::::iter().map(|(_index, heap)| heap.len() as u32).sum(); + let n_para_id_affinity: u32 = ParaIdAffinity::::iter() + .map(|(_para_id, affinity)| affinity.count as u32) + .sum(); + ensure!( + n_para_id_affinity == n_affinity_entries, + "Number of affinity entries should be the same as the counts in ParaIdAffinity" + ); + + Ok(()) + } + } +} + +/// Migrate `V0` to `V1` of the storage format. +pub type MigrateV0ToV1 = VersionedMigration< + 0, + 1, + v1::UncheckedMigrateToV1, + Pallet, + ::DbWeight, +>; + +#[cfg(test)] +mod tests { + use super::{v0, v1, OnRuntimeUpgrade, Weight}; + use crate::mock::{new_test_ext, MockGenesisConfig, OnDemandAssigner, Test}; + use primitives::Id as ParaId; + + #[test] + fn migration_to_v1_preserves_queue_ordering() { + new_test_ext(MockGenesisConfig::default()).execute_with(|| { + // Place orders for paraids 1..5 + for i in 1..=5 { + v0::OnDemandQueue::::mutate(|queue| { + queue.push_back(v0::EnqueuedOrder { para_id: ParaId::new(i) }) + }); + } + + // Queue has 5 orders + let old_queue = v0::OnDemandQueue::::get(); + assert_eq!(old_queue.len(), 5); + // New queue has 0 orders + assert_eq!(OnDemandAssigner::get_queue_status().size(), 0); + + // For tests, db weight is zero. + assert_eq!( + as OnRuntimeUpgrade>::on_runtime_upgrade(), + Weight::zero() + ); + + // New queue has 5 orders + assert_eq!(OnDemandAssigner::get_queue_status().size(), 5); + + // Compare each entry from the old queue with the entry in the new queue. + old_queue.iter().zip(OnDemandAssigner::get_free_entries().iter()).for_each( + |(old_enq, new_enq)| { + assert_eq!(old_enq.para_id, new_enq.para_id); + }, + ); + }); + } +} diff --git a/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs b/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs index bc450dc7812..c47c8745e65 100644 --- a/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs +++ b/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs @@ -16,22 +16,32 @@ //! The parachain on demand assignment module. //! -//! Implements a mechanism for taking in orders for pay as you go (PAYG) or on demand -//! parachain (previously parathreads) assignments. This module is not handled by the -//! initializer but is instead instantiated in the `construct_runtime` macro. +//! Implements a mechanism for taking in orders for on-demand parachain (previously parathreads) +//! assignments. This module is not handled by the initializer but is instead instantiated in the +//! `construct_runtime` macro. //! //! The module currently limits parallel execution of blocks from the same `ParaId` via //! a core affinity mechanism. As long as there exists an affinity for a `CoreIndex` for //! a specific `ParaId`, orders for blockspace for that `ParaId` will only be assigned to -//! that `CoreIndex`. This affinity mechanism can be removed if it can be shown that parallel -//! execution is valid. +//! that `CoreIndex`. +//! +//! NOTE: Once we have elastic scaling implemented we might want to extend this module to support +//! ignoring core affinity up to a certain extend. This should be opt-in though as the parachain +//! needs to support multiple cores in the same block. If we want to enable a single parachain +//! occupying multiple cores in on-demand, we will likely add a separate order type, where the +//! intent can be made explicit. mod benchmarking; +pub mod migration; mod mock_helpers; +extern crate alloc; + #[cfg(test)] mod tests; +use core::mem::take; + use crate::{configuration, paras, scheduler::common::Assignment}; use frame_support::{ @@ -43,13 +53,17 @@ use frame_support::{ }, }; use frame_system::pallet_prelude::*; -use primitives::{CoreIndex, Id as ParaId}; +use primitives::{CoreIndex, Id as ParaId, ON_DEMAND_MAX_QUEUE_MAX_SIZE}; use sp_runtime::{ traits::{One, SaturatedConversion}, FixedPointNumber, FixedPointOperand, FixedU128, Perbill, Saturating, }; -use sp_std::{collections::vec_deque::VecDeque, prelude::*}; +use alloc::collections::BinaryHeap; +use sp_std::{ + cmp::{Ord, Ordering, PartialOrd}, + prelude::*, +}; const LOG_TARGET: &str = "runtime::parachains::assigner-on-demand"; @@ -73,17 +87,116 @@ impl WeightInfo for TestWeightInfo { } } +/// Meta data for full queue. +/// +/// This includes elements with affinity and free entries. +/// +/// The actual queue is implemented via multiple priority queues. One for each core, for entries +/// which currently have a core affinity and one free queue, with entries without any affinity yet. +/// +/// The design aims to have most queue accessess be O(1) or O(log(N)). Absolute worst case is O(N). +/// Importantly this includes all accessess that happen in a single block. Even with 50 cores, the +/// total complexity of all operations in the block should maintain above complexities. In +/// particular O(N) stays O(N), it should never be O(N*cores). +/// +/// More concrete rundown on complexity: +/// +/// - insert: O(1) for placing an order, O(log(N)) for push backs. +/// - pop_assignment_for_core: O(log(N)), O(N) worst case: Can only happen for one core, next core +/// is already less work. +/// - report_processed & push back: If affinity dropped to 0, then O(N) in the worst case. Again +/// this divides per core. +/// +/// Reads still exist, also improved slightly, but worst case we fetch all entries. +#[derive(Encode, Decode, TypeInfo)] +struct QueueStatusType { + /// Last calculated traffic value. + traffic: FixedU128, + /// The next index to use. + next_index: QueueIndex, + /// Smallest index still in use. + /// + /// In case of a completely empty queue (free + affinity queues), `next_index - smallest_index + /// == 0`. + smallest_index: QueueIndex, + /// Indices that have been freed already. + /// + /// But have a hole to `smallest_index`, so we can not yet bump `smallest_index`. This binary + /// heap is roughly bounded in the number of on demand cores: + /// + /// For a single core, elements will always be processed in order. With each core added, a + /// level of out of order execution is added. + freed_indices: BinaryHeap, +} + +impl Default for QueueStatusType { + fn default() -> QueueStatusType { + QueueStatusType { + traffic: FixedU128::default(), + next_index: QueueIndex(0), + smallest_index: QueueIndex(0), + freed_indices: BinaryHeap::new(), + } + } +} + +impl QueueStatusType { + /// How many orders are queued in total? + /// + /// This includes entries which have core affinity. + fn size(&self) -> u32 { + self.next_index + .0 + .overflowing_sub(self.smallest_index.0) + .0 + .saturating_sub(self.freed_indices.len() as u32) + } + + /// Get current next index + /// + /// to use for an element newly pushed to the back of the queue. + fn push_back(&mut self) -> QueueIndex { + let QueueIndex(next_index) = self.next_index; + self.next_index = QueueIndex(next_index.overflowing_add(1).0); + QueueIndex(next_index) + } + + /// Push something to the front of the queue + fn push_front(&mut self) -> QueueIndex { + self.smallest_index = QueueIndex(self.smallest_index.0.overflowing_sub(1).0); + self.smallest_index + } + + /// The given index is no longer part of the queue. + /// + /// This updates `smallest_index` if need be. + fn consume_index(&mut self, removed_index: QueueIndex) { + if removed_index != self.smallest_index { + self.freed_indices.push(removed_index.reverse()); + return + } + let mut index = self.smallest_index.0.overflowing_add(1).0; + // Even more to advance? + while self.freed_indices.peek() == Some(&ReverseQueueIndex(index)) { + index = index.overflowing_add(1).0; + self.freed_indices.pop(); + } + self.smallest_index = QueueIndex(index); + } +} + /// Keeps track of how many assignments a scheduler currently has at a specific `CoreIndex` for a /// specific `ParaId`. #[derive(Encode, Decode, Default, Clone, Copy, TypeInfo)] #[cfg_attr(test, derive(PartialEq, RuntimeDebug))] -pub struct CoreAffinityCount { - core_idx: CoreIndex, +struct CoreAffinityCount { + core_index: CoreIndex, count: u32, } /// An indicator as to which end of the `OnDemandQueue` an assignment will be placed. -pub enum QueuePushDirection { +#[cfg_attr(test, derive(RuntimeDebug))] +enum QueuePushDirection { Back, Front, } @@ -93,9 +206,8 @@ type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; /// Errors that can happen during spot traffic calculation. -#[derive(PartialEq)] -#[cfg_attr(feature = "std", derive(Debug))] -pub enum SpotTrafficCalculationErr { +#[derive(PartialEq, RuntimeDebug)] +enum SpotTrafficCalculationErr { /// The order queue capacity is at 0. QueueCapacityIsZero, /// The queue size is larger than the queue capacity. @@ -104,15 +216,85 @@ pub enum SpotTrafficCalculationErr { Division, } +/// Type used for priority indices. +// NOTE: The `Ord` implementation for this type is unsound in the general case. +// Do not use it for anything but it's intended purpose. +#[derive(Encode, Decode, TypeInfo, Debug, PartialEq, Clone, Eq, Copy)] +struct QueueIndex(u32); + +/// QueueIndex with reverse ordering. +/// +/// Same as `Reverse(QueueIndex)`, but with all the needed traits implemented. +#[derive(Encode, Decode, TypeInfo, Debug, PartialEq, Clone, Eq, Copy)] +struct ReverseQueueIndex(u32); + +impl QueueIndex { + fn reverse(self) -> ReverseQueueIndex { + ReverseQueueIndex(self.0) + } +} + +impl Ord for QueueIndex { + fn cmp(&self, other: &Self) -> Ordering { + let diff = self.0.overflowing_sub(other.0).0; + if diff == 0 { + Ordering::Equal + } else if diff <= ON_DEMAND_MAX_QUEUE_MAX_SIZE { + Ordering::Greater + } else { + Ordering::Less + } + } +} + +impl PartialOrd for QueueIndex { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for ReverseQueueIndex { + fn cmp(&self, other: &Self) -> Ordering { + QueueIndex(other.0).cmp(&QueueIndex(self.0)) + } +} +impl PartialOrd for ReverseQueueIndex { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(&other)) + } +} + /// Internal representation of an order after it has been enqueued already. -#[derive(Encode, Decode, TypeInfo, Debug, PartialEq, Clone)] -pub(super) struct EnqueuedOrder { - pub para_id: ParaId, +/// +/// This data structure is provided for a min BinaryHeap (Ord compares in reverse order with regards +/// to its elements) +#[derive(Encode, Decode, TypeInfo, Debug, PartialEq, Clone, Eq)] +struct EnqueuedOrder { + para_id: ParaId, + idx: QueueIndex, } impl EnqueuedOrder { - pub fn new(para_id: ParaId) -> Self { - Self { para_id } + fn new(idx: QueueIndex, para_id: ParaId) -> Self { + Self { idx, para_id } + } +} + +impl PartialOrd for EnqueuedOrder { + fn partial_cmp(&self, other: &Self) -> Option { + match other.idx.partial_cmp(&self.idx) { + Some(Ordering::Equal) => other.para_id.partial_cmp(&self.para_id), + o => o, + } + } +} + +impl Ord for EnqueuedOrder { + fn cmp(&self, other: &Self) -> Ordering { + match other.idx.cmp(&self.idx) { + Ordering::Equal => other.para_id.cmp(&self.para_id), + o => o, + } } } @@ -121,8 +303,11 @@ pub mod pallet { use super::*; + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + #[pallet::pallet] #[pallet::without_storage_info] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); #[pallet::config] @@ -141,36 +326,44 @@ pub mod pallet { type TrafficDefaultValue: Get; } - /// Creates an empty spot traffic value if one isn't present in storage already. + /// Creates an empty queue status for an empty queue with initial traffic value. #[pallet::type_value] - pub fn SpotTrafficOnEmpty() -> FixedU128 { - T::TrafficDefaultValue::get() + pub(super) fn QueueStatusOnEmpty() -> QueueStatusType { + QueueStatusType { traffic: T::TrafficDefaultValue::get(), ..Default::default() } } - /// Creates an empty on demand queue if one isn't present in storage already. #[pallet::type_value] - pub(super) fn OnDemandQueueOnEmpty() -> VecDeque { - VecDeque::new() + pub(super) fn EntriesOnEmpty() -> BinaryHeap { + BinaryHeap::new() } - /// Keeps track of the multiplier used to calculate the current spot price for the on demand - /// assigner. - #[pallet::storage] - pub(super) type SpotTraffic = - StorageValue<_, FixedU128, ValueQuery, SpotTrafficOnEmpty>; - - /// The order storage entry. Uses a VecDeque to be able to push to the front of the - /// queue from the scheduler on session boundaries. - #[pallet::storage] - pub(super) type OnDemandQueue = - StorageValue<_, VecDeque, ValueQuery, OnDemandQueueOnEmpty>; - /// Maps a `ParaId` to `CoreIndex` and keeps track of how many assignments the scheduler has in /// it's lookahead. Keeping track of this affinity prevents parallel execution of the same /// `ParaId` on two or more `CoreIndex`es. #[pallet::storage] pub(super) type ParaIdAffinity = - StorageMap<_, Twox256, ParaId, CoreAffinityCount, OptionQuery>; + StorageMap<_, Twox64Concat, ParaId, CoreAffinityCount, OptionQuery>; + + /// Overall status of queue (both free + affinity entries) + #[pallet::storage] + pub(super) type QueueStatus = + StorageValue<_, QueueStatusType, ValueQuery, QueueStatusOnEmpty>; + + /// Priority queue for all orders which don't yet (or not any more) have any core affinity. + #[pallet::storage] + pub(super) type FreeEntries = + StorageValue<_, BinaryHeap, ValueQuery, EntriesOnEmpty>; + + /// Queue entries that are currently bound to a particular core due to core affinity. + #[pallet::storage] + pub(super) type AffinityEntries = StorageMap< + _, + Twox64Concat, + CoreIndex, + BinaryHeap, + ValueQuery, + EntriesOnEmpty, + >; #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] @@ -183,9 +376,6 @@ pub mod pallet { #[pallet::error] pub enum Error { - /// The `ParaId` supplied to the `place_order` call is not a valid `ParaThread`, making the - /// call is invalid. - InvalidParaId, /// The order queue is full, `place_order` will not continue. QueueFull, /// The current spot price is higher than the max amount specified in the `place_order` @@ -197,45 +387,14 @@ pub mod pallet { impl Hooks> for Pallet { fn on_initialize(_now: BlockNumberFor) -> Weight { let config = >::config(); - // Calculate spot price multiplier and store it. - let old_traffic = SpotTraffic::::get(); - match Self::calculate_spot_traffic( - old_traffic, - config.scheduler_params.on_demand_queue_max_size, - Self::queue_size(), - config.scheduler_params.on_demand_target_queue_utilization, - config.scheduler_params.on_demand_fee_variability, - ) { - Ok(new_traffic) => { - // Only update storage on change - if new_traffic != old_traffic { - SpotTraffic::::set(new_traffic); - Pallet::::deposit_event(Event::::SpotTrafficSet { - traffic: new_traffic, - }); - return T::DbWeight::get().reads_writes(2, 1) - } - }, - Err(SpotTrafficCalculationErr::QueueCapacityIsZero) => { - log::debug!( - target: LOG_TARGET, - "Error calculating spot traffic: The order queue capacity is at 0." - ); - }, - Err(SpotTrafficCalculationErr::QueueSizeLargerThanCapacity) => { - log::debug!( - target: LOG_TARGET, - "Error calculating spot traffic: The queue size is larger than the queue capacity." - ); - }, - Err(SpotTrafficCalculationErr::Division) => { - log::debug!( - target: LOG_TARGET, - "Error calculating spot traffic: Arithmetic error during division, either division by 0 or over/underflow." - ); - }, - }; - T::DbWeight::get().reads_writes(2, 0) + // We need to update the spot traffic on block initialize in order to account for idle + // blocks. + QueueStatus::::mutate(|queue_status| { + Self::update_spot_traffic(&config, queue_status); + }); + + // 2 reads in config and queuestatus, at maximum 1 write to queuestatus. + T::DbWeight::get().reads_writes(2, 1) } } @@ -258,7 +417,7 @@ pub mod pallet { /// Events: /// - `SpotOrderPlaced` #[pallet::call_index(0)] - #[pallet::weight(::WeightInfo::place_order_allow_death(OnDemandQueue::::get().len() as u32))] + #[pallet::weight(::WeightInfo::place_order_allow_death(QueueStatus::::get().size()))] pub fn place_order_allow_death( origin: OriginFor, max_amount: BalanceOf, @@ -285,7 +444,7 @@ pub mod pallet { /// Events: /// - `SpotOrderPlaced` #[pallet::call_index(1)] - #[pallet::weight(::WeightInfo::place_order_keep_alive(OnDemandQueue::::get().len() as u32))] + #[pallet::weight(::WeightInfo::place_order_keep_alive(QueueStatus::::get().size()))] pub fn place_order_keep_alive( origin: OriginFor, max_amount: BalanceOf, @@ -297,10 +456,78 @@ pub mod pallet { } } +// Internal functions and interface to scheduler/wrapping assignment provider. impl Pallet where BalanceOf: FixedPointOperand, { + /// Take the next queued entry that is available for a given core index. + /// + /// Parameters: + /// - `core_index`: The core index + pub fn pop_assignment_for_core(core_index: CoreIndex) -> Option { + let entry: Result = QueueStatus::::try_mutate(|queue_status| { + AffinityEntries::::try_mutate(core_index, |affinity_entries| { + let free_entry = FreeEntries::::try_mutate(|free_entries| { + let affinity_next = affinity_entries.peek(); + let free_next = free_entries.peek(); + let pick_free = match (affinity_next, free_next) { + (None, _) => true, + (Some(_), None) => false, + (Some(a), Some(f)) => f < a, + }; + if pick_free { + let entry = free_entries.pop().ok_or(())?; + let (mut affinities, free): (BinaryHeap<_>, BinaryHeap<_>) = + take(free_entries) + .into_iter() + .partition(|e| e.para_id == entry.para_id); + affinity_entries.append(&mut affinities); + *free_entries = free; + Ok(entry) + } else { + Err(()) + } + }); + let entry = free_entry.or_else(|()| affinity_entries.pop().ok_or(()))?; + queue_status.consume_index(entry.idx); + Ok(entry) + }) + }); + + let assignment = entry.map(|e| Assignment::Pool { para_id: e.para_id, core_index }).ok()?; + + Pallet::::increase_affinity(assignment.para_id(), core_index); + Some(assignment) + } + + /// Report that the `para_id` & `core_index` combination was processed. + /// + /// This should be called once it is clear that the assignment won't get pushed back anymore. + /// + /// In other words for each `pop_assignment_for_core` a call to this function or + /// `push_back_assignment` must follow, but only one. + pub fn report_processed(para_id: ParaId, core_index: CoreIndex) { + Pallet::::decrease_affinity_update_queue(para_id, core_index); + } + + /// Push an assignment back to the front of the queue. + /// + /// The assignment has not been processed yet. Typically used on session boundaries. + /// + /// NOTE: We are not checking queue size here. So due to push backs it is possible that we + /// exceed the maximum queue size slightly. + /// + /// Parameters: + /// - `para_id`: The para that did not make it. + /// - `core_index`: The core the para was scheduled on. + pub fn push_back_assignment(para_id: ParaId, core_index: CoreIndex) { + Pallet::::decrease_affinity_update_queue(para_id, core_index); + QueueStatus::::mutate(|queue_status| { + Pallet::::add_on_demand_order(queue_status, para_id, QueuePushDirection::Front); + }); + } + /// Helper function for `place_order_*` calls. Used to differentiate between placing orders /// with a keep alive check or to allow the account to be reaped. /// @@ -326,34 +553,62 @@ where ) -> DispatchResult { let config = >::config(); - // Traffic always falls back to 1.0 - let traffic = SpotTraffic::::get(); - - // Calculate spot price - let spot_price: BalanceOf = traffic.saturating_mul_int( - config.scheduler_params.on_demand_base_fee.saturated_into::>(), - ); - - // Is the current price higher than `max_amount` - ensure!(spot_price.le(&max_amount), Error::::SpotPriceHigherThanMaxAmount); + QueueStatus::::mutate(|queue_status| { + Self::update_spot_traffic(&config, queue_status); + let traffic = queue_status.traffic; - // Charge the sending account the spot price - let _ = T::Currency::withdraw( - &sender, - spot_price, - WithdrawReasons::FEE, - existence_requirement, - )?; + // Calculate spot price + let spot_price: BalanceOf = traffic.saturating_mul_int( + config.scheduler_params.on_demand_base_fee.saturated_into::>(), + ); - let order = EnqueuedOrder::new(para_id); + // Is the current price higher than `max_amount` + ensure!(spot_price.le(&max_amount), Error::::SpotPriceHigherThanMaxAmount); - let res = Pallet::::add_on_demand_order(order, QueuePushDirection::Back); + // Charge the sending account the spot price + let _ = T::Currency::withdraw( + &sender, + spot_price, + WithdrawReasons::FEE, + existence_requirement, + )?; - if res.is_ok() { - Pallet::::deposit_event(Event::::OnDemandOrderPlaced { para_id, spot_price }); - } + ensure!( + queue_status.size() < config.scheduler_params.on_demand_queue_max_size, + Error::::QueueFull + ); + Pallet::::add_on_demand_order(queue_status, para_id, QueuePushDirection::Back); + Ok(()) + }) + } - res + /// Calculate and update spot traffic. + fn update_spot_traffic( + config: &configuration::HostConfiguration>, + queue_status: &mut QueueStatusType, + ) { + let old_traffic = queue_status.traffic; + match Self::calculate_spot_traffic( + old_traffic, + config.scheduler_params.on_demand_queue_max_size, + queue_status.size(), + config.scheduler_params.on_demand_target_queue_utilization, + config.scheduler_params.on_demand_fee_variability, + ) { + Ok(new_traffic) => { + // Only update storage on change + if new_traffic != old_traffic { + queue_status.traffic = new_traffic; + Pallet::::deposit_event(Event::::SpotTrafficSet { traffic: new_traffic }); + } + }, + Err(err) => { + log::debug!( + target: LOG_TARGET, + "Error calculating spot traffic: {:?}", err + ); + }, + }; } /// The spot price multiplier. This is based on the transaction fee calculations defined in: @@ -378,7 +633,7 @@ where /// - `SpotTrafficCalculationErr::QueueCapacityIsZero` /// - `SpotTrafficCalculationErr::QueueSizeLargerThanCapacity` /// - `SpotTrafficCalculationErr::Division` - pub(crate) fn calculate_spot_traffic( + fn calculate_spot_traffic( traffic: FixedU128, queue_capacity: u32, queue_size: u32, @@ -430,175 +685,140 @@ where /// Adds an order to the on demand queue. /// /// Paramenters: - /// - `order`: The `EnqueuedOrder` to add to the queue. /// - `location`: Whether to push this entry to the back or the front of the queue. Pushing an /// entry to the front of the queue is only used when the scheduler wants to push back an /// entry it has already popped. - /// Returns: - /// - The unit type on success. - /// - /// Errors: - /// - `InvalidParaId` - /// - `QueueFull` fn add_on_demand_order( - order: EnqueuedOrder, + queue_status: &mut QueueStatusType, + para_id: ParaId, location: QueuePushDirection, - ) -> Result<(), DispatchError> { - // Only parathreads are valid paraids for on the go parachains. - ensure!(>::is_parathread(order.para_id), Error::::InvalidParaId); - - let config = >::config(); - - OnDemandQueue::::try_mutate(|queue| { - // Abort transaction if queue is too large - ensure!( - Self::queue_size() < config.scheduler_params.on_demand_queue_max_size, - Error::::QueueFull - ); - match location { - QueuePushDirection::Back => queue.push_back(order), - QueuePushDirection::Front => queue.push_front(order), - }; - Ok(()) - }) + ) { + let idx = match location { + QueuePushDirection::Back => queue_status.push_back(), + QueuePushDirection::Front => queue_status.push_front(), + }; + + let affinity = ParaIdAffinity::::get(para_id); + let order = EnqueuedOrder::new(idx, para_id); + #[cfg(test)] + log::debug!(target: LOG_TARGET, "add_on_demand_order, order: {:?}, affinity: {:?}, direction: {:?}", order, affinity, location); + + match affinity { + None => FreeEntries::::mutate(|entries| entries.push(order)), + Some(affinity) => + AffinityEntries::::mutate(affinity.core_index, |entries| entries.push(order)), + } } - /// Get the size of the on demand queue. + /// Decrease core affinity for para and update queue /// - /// Returns: - /// - The size of the on demand queue. - fn queue_size() -> u32 { - let config = >::config(); - match OnDemandQueue::::get().len().try_into() { - Ok(size) => return size, - Err(_) => { - log::debug!( - target: LOG_TARGET, - "Failed to fetch the on demand queue size, returning the max size." - ); - return config.scheduler_params.on_demand_queue_max_size - }, + /// if affinity dropped to 0, moving entries back to `FreeEntries`. + fn decrease_affinity_update_queue(para_id: ParaId, core_index: CoreIndex) { + let affinity = Pallet::::decrease_affinity(para_id, core_index); + #[cfg(not(test))] + debug_assert_ne!( + affinity, None, + "Decreased affinity for a para that has not been served on a core?" + ); + if affinity != Some(0) { + return } - } - - /// Getter for the order queue. - #[cfg(test)] - fn get_queue() -> VecDeque { - OnDemandQueue::::get() - } - - /// Getter for the affinity tracker. - pub fn get_affinity_map(para_id: ParaId) -> Option { - ParaIdAffinity::::get(para_id) + // No affinity more for entries on this core, free any entries: + // + // This is necessary to ensure them being served as the core might no longer exist at all. + AffinityEntries::::mutate(core_index, |affinity_entries| { + FreeEntries::::mutate(|free_entries| { + let (mut freed, affinities): (BinaryHeap<_>, BinaryHeap<_>) = + take(affinity_entries).into_iter().partition(|e| e.para_id == para_id); + free_entries.append(&mut freed); + *affinity_entries = affinities; + }) + }); } /// Decreases the affinity of a `ParaId` to a specified `CoreIndex`. - /// Subtracts from the count of the `CoreAffinityCount` if an entry is found and the core_idx + /// + /// Subtracts from the count of the `CoreAffinityCount` if an entry is found and the core_index /// matches. When the count reaches 0, the entry is removed. /// A non-existant entry is a no-op. - fn decrease_affinity(para_id: ParaId, core_idx: CoreIndex) { + /// + /// Returns: The new affinity of the para on that core. `None` if there is no affinity on this + /// core. + fn decrease_affinity(para_id: ParaId, core_index: CoreIndex) -> Option { ParaIdAffinity::::mutate(para_id, |maybe_affinity| { - if let Some(affinity) = maybe_affinity { - if affinity.core_idx == core_idx { - let new_count = affinity.count.saturating_sub(1); - if new_count > 0 { - *maybe_affinity = Some(CoreAffinityCount { core_idx, count: new_count }); - } else { - *maybe_affinity = None; - } + let affinity = maybe_affinity.as_mut()?; + if affinity.core_index == core_index { + let new_count = affinity.count.saturating_sub(1); + if new_count > 0 { + *maybe_affinity = Some(CoreAffinityCount { core_index, count: new_count }); + } else { + *maybe_affinity = None; } + return Some(new_count) + } else { + None } - }); + }) } /// Increases the affinity of a `ParaId` to a specified `CoreIndex`. - /// Adds to the count of the `CoreAffinityCount` if an entry is found and the core_idx matches. - /// A non-existant entry will be initialized with a count of 1 and uses the supplied + /// Adds to the count of the `CoreAffinityCount` if an entry is found and the core_index + /// matches. A non-existant entry will be initialized with a count of 1 and uses the supplied /// `CoreIndex`. - fn increase_affinity(para_id: ParaId, core_idx: CoreIndex) { + fn increase_affinity(para_id: ParaId, core_index: CoreIndex) { ParaIdAffinity::::mutate(para_id, |maybe_affinity| match maybe_affinity { Some(affinity) => - if affinity.core_idx == core_idx { + if affinity.core_index == core_index { *maybe_affinity = Some(CoreAffinityCount { - core_idx, + core_index, count: affinity.count.saturating_add(1), }); }, None => { - *maybe_affinity = Some(CoreAffinityCount { core_idx, count: 1 }); + *maybe_affinity = Some(CoreAffinityCount { core_index, count: 1 }); }, }) } -} -impl Pallet { - /// Take the next queued entry that is available for a given core index. - /// Invalidates and removes orders with a `para_id` that is not `ParaLifecycle::Parathread` - /// but only in [0..P] range slice of the order queue, where P is the element that is - /// removed from the order queue. - /// - /// Parameters: - /// - `core_idx`: The core index - pub fn pop_assignment_for_core(core_idx: CoreIndex) -> Option { - let mut queue: VecDeque = OnDemandQueue::::get(); - - let mut invalidated_para_id_indexes: Vec = vec![]; - - // Get the position of the next `ParaId`. Select either a valid `ParaId` that has an - // affinity to the same `CoreIndex` as the scheduler asks for or a valid `ParaId` with no - // affinity at all. - let pos = queue.iter().enumerate().position(|(index, assignment)| { - if >::is_parathread(assignment.para_id) { - match ParaIdAffinity::::get(&assignment.para_id) { - Some(affinity) => return affinity.core_idx == core_idx, - None => return true, - } - } - // Record no longer valid para_ids. - invalidated_para_id_indexes.push(index); - return false - }); + /// Getter for the affinity tracker. + #[cfg(test)] + fn get_affinity_map(para_id: ParaId) -> Option { + ParaIdAffinity::::get(para_id) + } - // Collect the popped value. - let popped = pos.and_then(|p: usize| { - if let Some(assignment) = queue.remove(p) { - Pallet::::increase_affinity(assignment.para_id, core_idx); - return Some(assignment) - }; - None - }); + /// Getter for the affinity entries. + #[cfg(test)] + fn get_affinity_entries(core_index: CoreIndex) -> BinaryHeap { + AffinityEntries::::get(core_index) + } - // Only remove the invalid indexes *after* using the index. - // Removed in reverse order so that the indexes don't shift. - invalidated_para_id_indexes.iter().rev().for_each(|idx| { - queue.remove(*idx); - }); + /// Getter for the free entries. + #[cfg(test)] + fn get_free_entries() -> BinaryHeap { + FreeEntries::::get() + } - // Write changes to storage. - OnDemandQueue::::set(queue); + #[cfg(feature = "runtime-benchmarks")] + pub fn populate_queue(para_id: ParaId, num: u32) { + QueueStatus::::mutate(|queue_status| { + for _ in 0..num { + Pallet::::add_on_demand_order(queue_status, para_id, QueuePushDirection::Back); + } + }); + } - popped.map(|p| Assignment::Pool { para_id: p.para_id, core_index: core_idx }) + #[cfg(test)] + fn set_queue_status(new_status: QueueStatusType) { + QueueStatus::::set(new_status); } - /// Report that the `para_id` & `core_index` combination was processed. - pub fn report_processed(para_id: ParaId, core_index: CoreIndex) { - Pallet::::decrease_affinity(para_id, core_index) + #[cfg(test)] + fn get_queue_status() -> QueueStatusType { + QueueStatus::::get() } - /// Push an assignment back to the front of the queue. - /// - /// The assignment has not been processed yet. Typically used on session boundaries. - /// Parameters: - /// - `assignment`: The on demand assignment. - pub fn push_back_assignment(para_id: ParaId, core_index: CoreIndex) { - Pallet::::decrease_affinity(para_id, core_index); - // Skip the queue on push backs from scheduler - match Pallet::::add_on_demand_order( - EnqueuedOrder::new(para_id), - QueuePushDirection::Front, - ) { - Ok(_) => {}, - Err(_) => {}, - } + #[cfg(test)] + fn get_traffic_default_value() -> FixedU128 { + ::TrafficDefaultValue::get() } } diff --git a/polkadot/runtime/parachains/src/assigner_on_demand/tests.rs b/polkadot/runtime/parachains/src/assigner_on_demand/tests.rs index 8404700780c..982efe77b93 100644 --- a/polkadot/runtime/parachains/src/assigner_on_demand/tests.rs +++ b/polkadot/runtime/parachains/src/assigner_on_demand/tests.rs @@ -73,11 +73,24 @@ fn run_to_block( Paras::initializer_initialize(b + 1); Scheduler::initializer_initialize(b + 1); + // We need to update the spot traffic on every block. + OnDemandAssigner::on_initialize(b + 1); + // In the real runtime this is expected to be called by the `InclusionInherent` pallet. Scheduler::free_cores_and_fill_claimqueue(BTreeMap::new(), b + 1); } } +fn place_order(para_id: ParaId) { + let alice = 100u64; + let amt = 10_000_000u128; + + Balances::make_free_balance_be(&alice, amt); + + run_to_block(101, |n| if n == 101 { Some(Default::default()) } else { None }); + OnDemandAssigner::place_order_allow_death(RuntimeOrigin::signed(alice), amt, para_id).unwrap() +} + #[test] fn spot_traffic_capacity_zero_returns_none() { match OnDemandAssigner::calculate_spot_traffic( @@ -201,6 +214,42 @@ fn spot_traffic_decreases_over_time() { assert_eq!(traffic, FixedU128::from_inner(3_125_000_000_000_000_000u128)) } +#[test] +fn spot_traffic_decreases_between_idle_blocks() { + // Testing spot traffic assumptions, but using the mock runtime and default on demand + // configuration values. Ensuring that blocks with no on demand activity (idle) + // decrease traffic. + + let para_id = ParaId::from(111); + + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + // Initialize the parathread and wait for it to be ready. + schedule_blank_para(para_id, ParaKind::Parathread); + assert!(!Paras::is_parathread(para_id)); + run_to_block(100, |n| if n == 100 { Some(Default::default()) } else { None }); + assert!(Paras::is_parathread(para_id)); + + // Set the spot traffic to a large number + OnDemandAssigner::set_queue_status(QueueStatusType { + traffic: FixedU128::from_u32(10), + ..Default::default() + }); + + assert_eq!(OnDemandAssigner::get_queue_status().traffic, FixedU128::from_u32(10)); + + // Run to block 101 and ensure that the traffic decreases. + run_to_block(101, |n| if n == 100 { Some(Default::default()) } else { None }); + assert!(OnDemandAssigner::get_queue_status().traffic < FixedU128::from_u32(10)); + + // Run to block 102 and observe that we've hit the default traffic value. + run_to_block(102, |n| if n == 100 { Some(Default::default()) } else { None }); + assert_eq!( + OnDemandAssigner::get_queue_status().traffic, + OnDemandAssigner::get_traffic_default_value() + ); + }) +} + #[test] fn place_order_works() { let alice = 1u64; @@ -278,74 +327,6 @@ fn place_order_keep_alive_keeps_alive() { }); } -#[test] -fn add_on_demand_order_works() { - let para_a = ParaId::from(111); - let order = EnqueuedOrder::new(para_a); - - let mut genesis = GenesisConfigBuilder::default(); - genesis.on_demand_max_queue_size = 1; - new_test_ext(genesis.build()).execute_with(|| { - // Initialize the parathread and wait for it to be ready. - schedule_blank_para(para_a, ParaKind::Parathread); - - // `para_a` is not onboarded as a parathread yet. - assert_noop!( - OnDemandAssigner::add_on_demand_order(order.clone(), QueuePushDirection::Back), - Error::::InvalidParaId - ); - - assert!(!Paras::is_parathread(para_a)); - run_to_block(100, |n| if n == 100 { Some(Default::default()) } else { None }); - assert!(Paras::is_parathread(para_a)); - - // `para_a` is now onboarded as a valid parathread. - assert_ok!(OnDemandAssigner::add_on_demand_order(order.clone(), QueuePushDirection::Back)); - - // Max queue size is 1, queue should be full. - assert_noop!( - OnDemandAssigner::add_on_demand_order(order, QueuePushDirection::Back), - Error::::QueueFull - ); - }); -} - -#[test] -fn spotqueue_push_directions() { - new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { - let para_a = ParaId::from(111); - let para_b = ParaId::from(222); - let para_c = ParaId::from(333); - - schedule_blank_para(para_a, ParaKind::Parathread); - schedule_blank_para(para_b, ParaKind::Parathread); - schedule_blank_para(para_c, ParaKind::Parathread); - - run_to_block(11, |n| if n == 11 { Some(Default::default()) } else { None }); - - let order_a = EnqueuedOrder::new(para_a); - let order_b = EnqueuedOrder::new(para_b); - let order_c = EnqueuedOrder::new(para_c); - - assert_ok!(OnDemandAssigner::add_on_demand_order( - order_a.clone(), - QueuePushDirection::Front - )); - assert_ok!(OnDemandAssigner::add_on_demand_order( - order_b.clone(), - QueuePushDirection::Front - )); - - assert_ok!(OnDemandAssigner::add_on_demand_order( - order_c.clone(), - QueuePushDirection::Back - )); - - assert_eq!(OnDemandAssigner::queue_size(), 3); - assert_eq!(OnDemandAssigner::get_queue(), VecDeque::from(vec![order_b, order_a, order_c])) - }); -} - #[test] fn pop_assignment_for_core_works() { new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { @@ -356,51 +337,32 @@ fn pop_assignment_for_core_works() { run_to_block(11, |n| if n == 11 { Some(Default::default()) } else { None }); - let order_a = EnqueuedOrder::new(para_a); - let order_b = EnqueuedOrder::new(para_b); - let assignment_a = Assignment::Pool { para_id: para_a, core_index: CoreIndex(0) }; - let assignment_b = Assignment::Pool { para_id: para_b, core_index: CoreIndex(1) }; - // Pop should return none with empty queue assert_eq!(OnDemandAssigner::pop_assignment_for_core(CoreIndex(0)), None); // Add enough assignments to the order queue. for _ in 0..2 { - OnDemandAssigner::add_on_demand_order(order_a.clone(), QueuePushDirection::Back) - .expect("Invalid paraid or queue full"); - - OnDemandAssigner::add_on_demand_order(order_b.clone(), QueuePushDirection::Back) - .expect("Invalid paraid or queue full"); - } - - // Queue should contain orders a, b, a, b - { - let queue: Vec = OnDemandQueue::::get().into_iter().collect(); - assert_eq!( - queue, - vec![order_a.clone(), order_b.clone(), order_a.clone(), order_b.clone()] - ); + place_order(para_a); + place_order(para_b); } // Popped assignments should be for the correct paras and cores assert_eq!( - OnDemandAssigner::pop_assignment_for_core(CoreIndex(0)), - Some(assignment_a.clone()) + OnDemandAssigner::pop_assignment_for_core(CoreIndex(0)).map(|a| a.para_id()), + Some(para_a) ); assert_eq!( - OnDemandAssigner::pop_assignment_for_core(CoreIndex(1)), - Some(assignment_b.clone()) + OnDemandAssigner::pop_assignment_for_core(CoreIndex(1)).map(|a| a.para_id()), + Some(para_b) ); assert_eq!( - OnDemandAssigner::pop_assignment_for_core(CoreIndex(0)), - Some(assignment_a.clone()) + OnDemandAssigner::pop_assignment_for_core(CoreIndex(0)).map(|a| a.para_id()), + Some(para_a) + ); + assert_eq!( + OnDemandAssigner::pop_assignment_for_core(CoreIndex(1)).map(|a| a.para_id()), + Some(para_b) ); - - // Queue should contain one left over order - { - let queue: Vec = OnDemandQueue::::get().into_iter().collect(); - assert_eq!(queue, vec![order_b.clone(),]); - } }); } @@ -414,28 +376,19 @@ fn push_back_assignment_works() { run_to_block(11, |n| if n == 11 { Some(Default::default()) } else { None }); - let order_a = EnqueuedOrder::new(para_a); - let order_b = EnqueuedOrder::new(para_b); - // Add enough assignments to the order queue. - OnDemandAssigner::add_on_demand_order(order_a.clone(), QueuePushDirection::Back) - .expect("Invalid paraid or queue full"); - - OnDemandAssigner::add_on_demand_order(order_b.clone(), QueuePushDirection::Back) - .expect("Invalid paraid or queue full"); + place_order(para_a); + place_order(para_b); // Pop order a - OnDemandAssigner::pop_assignment_for_core(CoreIndex(0)); + assert_eq!( + OnDemandAssigner::pop_assignment_for_core(CoreIndex(0)).unwrap().para_id(), + para_a + ); // Para a should have affinity for core 0 assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 1); - assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().core_idx, CoreIndex(0)); - - // Queue should still contain order b - { - let queue: Vec = OnDemandQueue::::get().into_iter().collect(); - assert_eq!(queue, vec![order_b.clone()]); - } + assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().core_index, CoreIndex(0)); // Push back order a OnDemandAssigner::push_back_assignment(para_a, CoreIndex(0)); @@ -444,10 +397,82 @@ fn push_back_assignment_works() { assert_eq!(OnDemandAssigner::get_affinity_map(para_a).is_none(), true); // Queue should contain orders a, b. A in front of b. - { - let queue: Vec = OnDemandQueue::::get().into_iter().collect(); - assert_eq!(queue, vec![order_a.clone(), order_b.clone()]); + assert_eq!( + OnDemandAssigner::pop_assignment_for_core(CoreIndex(0)).unwrap().para_id(), + para_a + ); + assert_eq!( + OnDemandAssigner::pop_assignment_for_core(CoreIndex(0)).unwrap().para_id(), + para_b + ); + }); +} + +#[test] +fn affinity_prohibits_parallel_scheduling() { + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + let para_a = ParaId::from(111); + let para_b = ParaId::from(222); + + schedule_blank_para(para_a, ParaKind::Parathread); + schedule_blank_para(para_b, ParaKind::Parathread); + + run_to_block(11, |n| if n == 11 { Some(Default::default()) } else { None }); + + // There should be no affinity before starting. + assert!(OnDemandAssigner::get_affinity_map(para_a).is_none()); + assert!(OnDemandAssigner::get_affinity_map(para_b).is_none()); + + // Add 2 assignments for para_a for every para_b. + place_order(para_a); + place_order(para_a); + place_order(para_b); + + // Approximate having 1 core. + for _ in 0..3 { + assert!(OnDemandAssigner::pop_assignment_for_core(CoreIndex(0)).is_some()); } + assert!(OnDemandAssigner::pop_assignment_for_core(CoreIndex(0)).is_none()); + + // Affinity on one core is meaningless. + assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 2); + assert_eq!(OnDemandAssigner::get_affinity_map(para_b).unwrap().count, 1); + assert_eq!( + OnDemandAssigner::get_affinity_map(para_a).unwrap().core_index, + OnDemandAssigner::get_affinity_map(para_b).unwrap().core_index, + ); + + // Clear affinity + OnDemandAssigner::report_processed(para_a, 0.into()); + OnDemandAssigner::report_processed(para_a, 0.into()); + OnDemandAssigner::report_processed(para_b, 0.into()); + + // Add 2 assignments for para_a for every para_b. + place_order(para_a); + place_order(para_a); + place_order(para_b); + + // Approximate having 3 cores. CoreIndex 2 should be unable to obtain an assignment + for _ in 0..3 { + OnDemandAssigner::pop_assignment_for_core(CoreIndex(0)); + OnDemandAssigner::pop_assignment_for_core(CoreIndex(1)); + assert!(OnDemandAssigner::pop_assignment_for_core(CoreIndex(2)).is_none()); + } + + // Affinity should be the same as before, but on different cores. + assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 2); + assert_eq!(OnDemandAssigner::get_affinity_map(para_b).unwrap().count, 1); + assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().core_index, CoreIndex(0)); + assert_eq!(OnDemandAssigner::get_affinity_map(para_b).unwrap().core_index, CoreIndex(1)); + + // Clear affinity + OnDemandAssigner::report_processed(para_a, CoreIndex(0)); + OnDemandAssigner::report_processed(para_a, CoreIndex(0)); + OnDemandAssigner::report_processed(para_b, CoreIndex(1)); + + // There should be no affinity after clearing. + assert!(OnDemandAssigner::get_affinity_map(para_a).is_none()); + assert!(OnDemandAssigner::get_affinity_map(para_b).is_none()); }); } @@ -458,7 +483,6 @@ fn affinity_changes_work() { let core_index = CoreIndex(0); schedule_blank_para(para_a, ParaKind::Parathread); - let order_a = EnqueuedOrder::new(para_a); run_to_block(11, |n| if n == 11 { Some(Default::default()) } else { None }); // There should be no affinity before starting. @@ -466,8 +490,7 @@ fn affinity_changes_work() { // Add enough assignments to the order queue. for _ in 0..10 { - OnDemandAssigner::add_on_demand_order(order_a.clone(), QueuePushDirection::Front) - .expect("Invalid paraid or queue full"); + place_order(para_a); } // There should be no affinity before the scheduler pops. @@ -483,7 +506,6 @@ fn affinity_changes_work() { // Affinity count is 1 after popping with a previous para. assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 1); - assert_eq!(OnDemandAssigner::queue_size(), 8); for _ in 0..3 { OnDemandAssigner::pop_assignment_for_core(core_index); @@ -491,147 +513,197 @@ fn affinity_changes_work() { // Affinity count is 4 after popping 3 times without a previous para. assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 4); - assert_eq!(OnDemandAssigner::queue_size(), 5); for _ in 0..5 { OnDemandAssigner::report_processed(para_a, 0.into()); - OnDemandAssigner::pop_assignment_for_core(core_index); + assert!(OnDemandAssigner::pop_assignment_for_core(core_index).is_some()); } // Affinity count should still be 4 but queue should be empty. + assert!(OnDemandAssigner::pop_assignment_for_core(core_index).is_none()); assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 4); - assert_eq!(OnDemandAssigner::queue_size(), 0); // Pop 4 times and get to exactly 0 (None) affinity. for _ in 0..4 { OnDemandAssigner::report_processed(para_a, 0.into()); - OnDemandAssigner::pop_assignment_for_core(core_index); + assert!(OnDemandAssigner::pop_assignment_for_core(core_index).is_none()); } assert!(OnDemandAssigner::get_affinity_map(para_a).is_none()); // Decreasing affinity beyond 0 should still be None. OnDemandAssigner::report_processed(para_a, 0.into()); - OnDemandAssigner::pop_assignment_for_core(core_index); + assert!(OnDemandAssigner::pop_assignment_for_core(core_index).is_none()); assert!(OnDemandAssigner::get_affinity_map(para_a).is_none()); }); } #[test] -fn affinity_prohibits_parallel_scheduling() { - new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { - let para_a = ParaId::from(111); - let para_b = ParaId::from(222); +fn new_affinity_for_a_core_must_come_from_free_entries() { + // If affinity count for a core was zero before, and is 1 now, then the entry + // must have come from free_entries. + let parachains = + vec![ParaId::from(111), ParaId::from(222), ParaId::from(333), ParaId::from(444)]; + let core_indices = vec![CoreIndex(0), CoreIndex(1), CoreIndex(2), CoreIndex(3)]; - schedule_blank_para(para_a, ParaKind::Parathread); - schedule_blank_para(para_b, ParaKind::Parathread); + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + parachains.iter().for_each(|chain| { + schedule_blank_para(*chain, ParaKind::Parathread); + }); run_to_block(11, |n| if n == 11 { Some(Default::default()) } else { None }); - let order_a = EnqueuedOrder::new(para_a); - let order_b = EnqueuedOrder::new(para_b); - - // There should be no affinity before starting. - assert!(OnDemandAssigner::get_affinity_map(para_a).is_none()); - assert!(OnDemandAssigner::get_affinity_map(para_b).is_none()); - - // Add 2 assignments for para_a for every para_b. - OnDemandAssigner::add_on_demand_order(order_a.clone(), QueuePushDirection::Back) - .expect("Invalid paraid or queue full"); - - OnDemandAssigner::add_on_demand_order(order_a.clone(), QueuePushDirection::Back) - .expect("Invalid paraid or queue full"); - - OnDemandAssigner::add_on_demand_order(order_b.clone(), QueuePushDirection::Back) - .expect("Invalid paraid or queue full"); - - assert_eq!(OnDemandAssigner::queue_size(), 3); + // Place orders for all chains. + parachains.iter().for_each(|chain| { + place_order(*chain); + }); + + // There are 4 entries in free_entries. + let start_free_entries = OnDemandAssigner::get_free_entries().len(); + assert_eq!(start_free_entries, 4); + + // Pop assignments on all cores. + core_indices.iter().enumerate().for_each(|(n, core_index)| { + // There is no affinity on the core prior to popping. + assert!(OnDemandAssigner::get_affinity_entries(*core_index).is_empty()); + + // There's always an order to be popped for each core. + let free_entries = OnDemandAssigner::get_free_entries(); + let next_order = free_entries.peek(); + + // There is no affinity on the paraid prior to popping. + assert!(OnDemandAssigner::get_affinity_map(next_order.unwrap().para_id).is_none()); + + match OnDemandAssigner::pop_assignment_for_core(*core_index) { + Some(assignment) => { + // The popped assignment came from free entries. + assert_eq!( + start_free_entries - 1 - n, + OnDemandAssigner::get_free_entries().len() + ); + // The popped assignment has the same para id as the next order. + assert_eq!(assignment.para_id(), next_order.unwrap().para_id); + }, + None => panic!("Should not happen"), + } + }); - // Approximate having 1 core. - for _ in 0..3 { - OnDemandAssigner::pop_assignment_for_core(CoreIndex(0)); - } + // All entries have been removed from free_entries. + assert!(OnDemandAssigner::get_free_entries().is_empty()); - // Affinity on one core is meaningless. - assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 2); - assert_eq!(OnDemandAssigner::get_affinity_map(para_b).unwrap().count, 1); - assert_eq!( - OnDemandAssigner::get_affinity_map(para_a).unwrap().core_idx, - OnDemandAssigner::get_affinity_map(para_b).unwrap().core_idx - ); - - // Clear affinity - OnDemandAssigner::report_processed(para_a, 0.into()); - OnDemandAssigner::report_processed(para_a, 0.into()); - OnDemandAssigner::report_processed(para_b, 0.into()); - - // Add 2 assignments for para_a for every para_b. - OnDemandAssigner::add_on_demand_order(order_a.clone(), QueuePushDirection::Back) - .expect("Invalid paraid or queue full"); + // All chains have an affinity count of 1. + parachains.iter().for_each(|chain| { + assert_eq!(OnDemandAssigner::get_affinity_map(*chain).unwrap().count, 1); + }); + }); +} - OnDemandAssigner::add_on_demand_order(order_a.clone(), QueuePushDirection::Back) - .expect("Invalid paraid or queue full"); +#[test] +#[should_panic] +fn queue_index_ordering_is_unsound_over_max_size() { + // NOTE: Unsoundness proof. If the number goes sufficiently over the max_queue_max_size + // the overflow will cause an opposite comparison to what would be expected. + let max_num = u32::MAX - ON_DEMAND_MAX_QUEUE_MAX_SIZE; + // 0 < some large number. + assert_eq!(QueueIndex(0).cmp(&QueueIndex(max_num + 1)), Ordering::Less); +} - OnDemandAssigner::add_on_demand_order(order_b.clone(), QueuePushDirection::Back) - .expect("Invalid paraid or queue full"); +#[test] +fn queue_index_ordering_works() { + // The largest accepted queue size. + let max_num = ON_DEMAND_MAX_QUEUE_MAX_SIZE; + + // 0 == 0 + assert_eq!(QueueIndex(0).cmp(&QueueIndex(0)), Ordering::Equal); + // 0 < 1 + assert_eq!(QueueIndex(0).cmp(&QueueIndex(1)), Ordering::Less); + // 1 > 0 + assert_eq!(QueueIndex(1).cmp(&QueueIndex(0)), Ordering::Greater); + // 0 < max_num + assert_eq!(QueueIndex(0).cmp(&QueueIndex(max_num)), Ordering::Less); + // 0 > max_num + 1 + assert_eq!(QueueIndex(0).cmp(&QueueIndex(max_num + 1)), Ordering::Less); + + // Ordering within the bounds of ON_DEMAND_MAX_QUEUE_MAX_SIZE works. + let mut v = vec![3, 6, 2, 1, 5, 4]; + v.sort_by_key(|&num| QueueIndex(num)); + assert_eq!(v, vec![1, 2, 3, 4, 5, 6]); + + v = vec![max_num, 4, 5, 1, 6]; + v.sort_by_key(|&num| QueueIndex(num)); + assert_eq!(v, vec![1, 4, 5, 6, max_num]); + + // Ordering with an element outside of the bounds of the max size also works. + v = vec![max_num + 2, 0, 6, 2, 1, 5, 4]; + v.sort_by_key(|&num| QueueIndex(num)); + assert_eq!(v, vec![0, 1, 2, 4, 5, 6, max_num + 2]); + + // Numbers way above the max size will overflow + v = vec![u32::MAX - 1, u32::MAX, 6, 2, 1, 5, 4]; + v.sort_by_key(|&num| QueueIndex(num)); + assert_eq!(v, vec![u32::MAX - 1, u32::MAX, 1, 2, 4, 5, 6]); +} - // Approximate having 3 cores. CoreIndex 2 should be unable to obtain an assignment - for _ in 0..3 { - OnDemandAssigner::pop_assignment_for_core(CoreIndex(0)); - OnDemandAssigner::pop_assignment_for_core(CoreIndex(1)); - assert_eq!(None, OnDemandAssigner::pop_assignment_for_core(CoreIndex(2))); - } +#[test] +fn reverse_queue_index_does_reverse() { + let mut v = vec![1, 2, 3, 4, 5, 6]; - // Affinity should be the same as before, but on different cores. - assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 2); - assert_eq!(OnDemandAssigner::get_affinity_map(para_b).unwrap().count, 1); - assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().core_idx, CoreIndex(0)); - assert_eq!(OnDemandAssigner::get_affinity_map(para_b).unwrap().core_idx, CoreIndex(1)); + // Basic reversal of a vector. + v.sort_by_key(|&num| ReverseQueueIndex(num)); + assert_eq!(v, vec![6, 5, 4, 3, 2, 1]); - // Clear affinity - OnDemandAssigner::report_processed(para_a, 0.into()); - OnDemandAssigner::report_processed(para_a, 0.into()); - OnDemandAssigner::report_processed(para_b, 1.into()); + // Example from rust docs on `Reverse`. Should work identically. + v.sort_by_key(|&num| (num > 3, ReverseQueueIndex(num))); + assert_eq!(v, vec![3, 2, 1, 6, 5, 4]); - // There should be no affinity after clearing. - assert!(OnDemandAssigner::get_affinity_map(para_a).is_none()); - assert!(OnDemandAssigner::get_affinity_map(para_b).is_none()); - }); + let mut v2 = vec![1, 2, u32::MAX]; + v2.sort_by_key(|&num| ReverseQueueIndex(num)); + assert_eq!(v2, vec![2, 1, u32::MAX]); } #[test] -fn on_demand_orders_cannot_be_popped_if_lifecycle_changes() { - let para_id = ParaId::from(10); - let core_index = CoreIndex(0); - let order = EnqueuedOrder::new(para_id); +fn queue_status_size_fn_works() { + // Add orders to the on demand queue, and make sure that they are properly represented + // by the QueueStatusType::size fn. + let parachains = vec![ParaId::from(111), ParaId::from(222), ParaId::from(333)]; + let core_indices = vec![CoreIndex(0), CoreIndex(1)]; new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { - // Register the para_id as a parathread - schedule_blank_para(para_id, ParaKind::Parathread); - - assert!(!Paras::is_parathread(para_id)); - run_to_block(10, |n| if n == 10 { Some(Default::default()) } else { None }); - assert!(Paras::is_parathread(para_id)); + parachains.iter().for_each(|chain| { + schedule_blank_para(*chain, ParaKind::Parathread); + }); - // Add two assignments for a para_id with a valid lifecycle. - assert_ok!(OnDemandAssigner::add_on_demand_order(order.clone(), QueuePushDirection::Back)); - assert_ok!(OnDemandAssigner::add_on_demand_order(order.clone(), QueuePushDirection::Back)); + assert_eq!(OnDemandAssigner::get_queue_status().size(), 0); - // First pop is fine - assert!( - OnDemandAssigner::pop_assignment_for_core(core_index) == - Some(Assignment::Pool { para_id, core_index }) - ); + run_to_block(11, |n| if n == 11 { Some(Default::default()) } else { None }); - // Deregister para - assert_ok!(Paras::schedule_para_cleanup(para_id)); + // Place orders for all chains. + parachains.iter().for_each(|chain| { + // 2 per chain for a total of 6 + place_order(*chain); + place_order(*chain); + }); - // Run to new session and verify that para_id is no longer a valid parathread. - assert!(Paras::is_parathread(para_id)); - run_to_block(20, |n| if n == 20 { Some(Default::default()) } else { None }); - assert!(!Paras::is_parathread(para_id)); + // 6 orders in free entries + assert_eq!(OnDemandAssigner::get_free_entries().len(), 6); + // 6 orders via queue status size + assert_eq!( + OnDemandAssigner::get_free_entries().len(), + OnDemandAssigner::get_queue_status().size() as usize + ); - // Second pop should be None. - OnDemandAssigner::report_processed(para_id, core_index); - assert_eq!(OnDemandAssigner::pop_assignment_for_core(core_index), None); + core_indices.iter().for_each(|core_index| { + OnDemandAssigner::pop_assignment_for_core(*core_index); + }); + + // There should be 2 orders in the scheduler's claimqueue, + // 2 in assorted AffinityMaps and 2 in free. + // ParaId 111 + assert_eq!(OnDemandAssigner::get_affinity_entries(core_indices[0]).len(), 1); + // ParaId 222 + assert_eq!(OnDemandAssigner::get_affinity_entries(core_indices[1]).len(), 1); + // Free entries are from ParaId 333 + assert_eq!(OnDemandAssigner::get_free_entries().len(), 2); + // For a total size of 4. + assert_eq!(OnDemandAssigner::get_queue_status().size(), 4) }); } diff --git a/polkadot/runtime/parachains/src/configuration.rs b/polkadot/runtime/parachains/src/configuration.rs index 364a15215d3..b7635dcd7b2 100644 --- a/polkadot/runtime/parachains/src/configuration.rs +++ b/polkadot/runtime/parachains/src/configuration.rs @@ -29,6 +29,7 @@ use primitives::{ vstaging::{ApprovalVotingParams, NodeFeatures}, AsyncBackingParams, Balance, ExecutorParamError, ExecutorParams, SessionIndex, LEGACY_MIN_BACKING_VOTES, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MAX_POV_SIZE, + ON_DEMAND_MAX_QUEUE_MAX_SIZE, }; use sp_runtime::{traits::Zero, Perbill}; use sp_std::prelude::*; @@ -312,6 +313,8 @@ pub enum InconsistentError { InconsistentExecutorParams { inner: ExecutorParamError }, /// TTL should be bigger than lookahead LookaheadExceedsTTL, + /// Passed in queue size for on-demand was too large. + OnDemandQueueSizeTooLarge, } impl HostConfiguration @@ -405,6 +408,10 @@ where return Err(LookaheadExceedsTTL) } + if self.scheduler_params.on_demand_queue_max_size > ON_DEMAND_MAX_QUEUE_MAX_SIZE { + return Err(OnDemandQueueSizeTooLarge) + } + Ok(()) } @@ -630,7 +637,7 @@ pub mod pallet { /// Set the number of coretime execution cores. /// - /// Note that this configuration is managed by the coretime chain. Only manually change + /// NOTE: that this configuration is managed by the coretime chain. Only manually change /// this, if you really know what you are doing! #[pallet::call_index(6)] #[pallet::weight(( @@ -1133,6 +1140,7 @@ pub mod pallet { config.scheduler_params.on_demand_queue_max_size = new; }) } + /// Set the on demand (parathreads) fee variability. #[pallet::call_index(50)] #[pallet::weight(( diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index f68870c98ea..a773eeb5cbd 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -1659,6 +1659,7 @@ pub mod migrations { // This needs to come after the `parachains_configuration` above as we are reading the configuration. coretime::migration::MigrateToCoretime, parachains_configuration::migration::v12::MigrateToV12, + parachains_assigner_on_demand::migration::MigrateV0ToV1, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_assigner_on_demand.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_assigner_on_demand.rs index ac0f05301b4..dba9e7904c7 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_assigner_on_demand.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_parachains_assigner_on_demand.rs @@ -16,10 +16,10 @@ //! Autogenerated weights for `runtime_parachains::assigner_on_demand` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-08-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-03-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-fljshgub-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -31,11 +31,11 @@ // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json // --pallet=runtime_parachains::assigner_on_demand // --chain=rococo-dev -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -48,44 +48,44 @@ use core::marker::PhantomData; /// Weight functions for `runtime_parachains::assigner_on_demand`. pub struct WeightInfo(PhantomData); impl runtime_parachains::assigner_on_demand::WeightInfo for WeightInfo { - /// Storage: `OnDemandAssignmentProvider::SpotTraffic` (r:1 w:0) - /// Proof: `OnDemandAssignmentProvider::SpotTraffic` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::ParaLifecycles` (r:1 w:0) - /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `OnDemandAssignmentProvider::OnDemandQueue` (r:1 w:1) - /// Proof: `OnDemandAssignmentProvider::OnDemandQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `OnDemandAssignmentProvider::QueueStatus` (r:1 w:1) + /// Proof: `OnDemandAssignmentProvider::QueueStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `OnDemandAssignmentProvider::ParaIdAffinity` (r:1 w:0) + /// Proof: `OnDemandAssignmentProvider::ParaIdAffinity` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `OnDemandAssignmentProvider::FreeEntries` (r:1 w:1) + /// Proof: `OnDemandAssignmentProvider::FreeEntries` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `s` is `[1, 9999]`. fn place_order_keep_alive(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `297 + s * (4 ±0)` - // Estimated: `3762 + s * (4 ±0)` - // Minimum execution time: 33_522_000 picoseconds. - Weight::from_parts(35_436_835, 0) - .saturating_add(Weight::from_parts(0, 3762)) - // Standard Error: 129 - .saturating_add(Weight::from_parts(14_041, 0).saturating_mul(s.into())) + // Measured: `218 + s * (8 ±0)` + // Estimated: `3681 + s * (8 ±0)` + // Minimum execution time: 21_053_000 picoseconds. + Weight::from_parts(17_291_897, 0) + .saturating_add(Weight::from_parts(0, 3681)) + // Standard Error: 104 + .saturating_add(Weight::from_parts(18_779, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(Weight::from_parts(0, 8).saturating_mul(s.into())) } - /// Storage: `OnDemandAssignmentProvider::SpotTraffic` (r:1 w:0) - /// Proof: `OnDemandAssignmentProvider::SpotTraffic` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::ParaLifecycles` (r:1 w:0) - /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `OnDemandAssignmentProvider::OnDemandQueue` (r:1 w:1) - /// Proof: `OnDemandAssignmentProvider::OnDemandQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `OnDemandAssignmentProvider::QueueStatus` (r:1 w:1) + /// Proof: `OnDemandAssignmentProvider::QueueStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `OnDemandAssignmentProvider::ParaIdAffinity` (r:1 w:0) + /// Proof: `OnDemandAssignmentProvider::ParaIdAffinity` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `OnDemandAssignmentProvider::FreeEntries` (r:1 w:1) + /// Proof: `OnDemandAssignmentProvider::FreeEntries` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `s` is `[1, 9999]`. fn place_order_allow_death(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `297 + s * (4 ±0)` - // Estimated: `3762 + s * (4 ±0)` - // Minimum execution time: 33_488_000 picoseconds. - Weight::from_parts(34_848_934, 0) - .saturating_add(Weight::from_parts(0, 3762)) - // Standard Error: 143 - .saturating_add(Weight::from_parts(14_215, 0).saturating_mul(s.into())) + // Measured: `218 + s * (8 ±0)` + // Estimated: `3681 + s * (8 ±0)` + // Minimum execution time: 20_843_000 picoseconds. + Weight::from_parts(16_881_986, 0) + .saturating_add(Weight::from_parts(0, 3681)) + // Standard Error: 104 + .saturating_add(Weight::from_parts(18_788, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(Weight::from_parts(0, 8).saturating_mul(s.into())) } } diff --git a/polkadot/runtime/westend/src/weights/runtime_parachains_assigner_on_demand.rs b/polkadot/runtime/westend/src/weights/runtime_parachains_assigner_on_demand.rs index ac0f05301b4..acd1834f79e 100644 --- a/polkadot/runtime/westend/src/weights/runtime_parachains_assigner_on_demand.rs +++ b/polkadot/runtime/westend/src/weights/runtime_parachains_assigner_on_demand.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `runtime_parachains::assigner_on_demand` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-08-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-03-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-fljshgub-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 // Executed Command: // target/production/polkadot @@ -31,11 +31,11 @@ // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json // --pallet=runtime_parachains::assigner_on_demand -// --chain=rococo-dev -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --chain=westend-dev +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -48,44 +48,44 @@ use core::marker::PhantomData; /// Weight functions for `runtime_parachains::assigner_on_demand`. pub struct WeightInfo(PhantomData); impl runtime_parachains::assigner_on_demand::WeightInfo for WeightInfo { - /// Storage: `OnDemandAssignmentProvider::SpotTraffic` (r:1 w:0) - /// Proof: `OnDemandAssignmentProvider::SpotTraffic` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::ParaLifecycles` (r:1 w:0) - /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `OnDemandAssignmentProvider::OnDemandQueue` (r:1 w:1) - /// Proof: `OnDemandAssignmentProvider::OnDemandQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `OnDemandAssignmentProvider::QueueStatus` (r:1 w:1) + /// Proof: `OnDemandAssignmentProvider::QueueStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `OnDemandAssignmentProvider::ParaIdAffinity` (r:1 w:0) + /// Proof: `OnDemandAssignmentProvider::ParaIdAffinity` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `OnDemandAssignmentProvider::FreeEntries` (r:1 w:1) + /// Proof: `OnDemandAssignmentProvider::FreeEntries` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `s` is `[1, 9999]`. fn place_order_keep_alive(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `297 + s * (4 ±0)` - // Estimated: `3762 + s * (4 ±0)` - // Minimum execution time: 33_522_000 picoseconds. - Weight::from_parts(35_436_835, 0) - .saturating_add(Weight::from_parts(0, 3762)) - // Standard Error: 129 - .saturating_add(Weight::from_parts(14_041, 0).saturating_mul(s.into())) + // Measured: `218 + s * (8 ±0)` + // Estimated: `3681 + s * (8 ±0)` + // Minimum execution time: 21_396_000 picoseconds. + Weight::from_parts(20_585_695, 0) + .saturating_add(Weight::from_parts(0, 3681)) + // Standard Error: 127 + .saturating_add(Weight::from_parts(20_951, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(Weight::from_parts(0, 8).saturating_mul(s.into())) } - /// Storage: `OnDemandAssignmentProvider::SpotTraffic` (r:1 w:0) - /// Proof: `OnDemandAssignmentProvider::SpotTraffic` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Paras::ParaLifecycles` (r:1 w:0) - /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `OnDemandAssignmentProvider::OnDemandQueue` (r:1 w:1) - /// Proof: `OnDemandAssignmentProvider::OnDemandQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `OnDemandAssignmentProvider::QueueStatus` (r:1 w:1) + /// Proof: `OnDemandAssignmentProvider::QueueStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `OnDemandAssignmentProvider::ParaIdAffinity` (r:1 w:0) + /// Proof: `OnDemandAssignmentProvider::ParaIdAffinity` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `OnDemandAssignmentProvider::FreeEntries` (r:1 w:1) + /// Proof: `OnDemandAssignmentProvider::FreeEntries` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `s` is `[1, 9999]`. fn place_order_allow_death(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `297 + s * (4 ±0)` - // Estimated: `3762 + s * (4 ±0)` - // Minimum execution time: 33_488_000 picoseconds. - Weight::from_parts(34_848_934, 0) - .saturating_add(Weight::from_parts(0, 3762)) - // Standard Error: 143 - .saturating_add(Weight::from_parts(14_215, 0).saturating_mul(s.into())) + // Measured: `218 + s * (8 ±0)` + // Estimated: `3681 + s * (8 ±0)` + // Minimum execution time: 21_412_000 picoseconds. + Weight::from_parts(19_731_554, 0) + .saturating_add(Weight::from_parts(0, 3681)) + // Standard Error: 128 + .saturating_add(Weight::from_parts(21_055, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(Weight::from_parts(0, 8).saturating_mul(s.into())) } } diff --git a/prdoc/pr_3190.prdoc b/prdoc/pr_3190.prdoc new file mode 100644 index 00000000000..2f7a89a0b1a --- /dev/null +++ b/prdoc/pr_3190.prdoc @@ -0,0 +1,17 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Fix algorithmic complexity of the on-demand scheduler. + +doc: + - audience: Runtime Dev + description: | + Improves on demand performance by a significant factor. Previously, having many on-demand cores + would cause really poor blocktimes due to the fact that for each core the full order queue was + processed. This allows for increasing the max size of the on-demand queue if needed. + + At the same time, the spot price for on-demand is now checked prior to every order, ensuring + that economic backpressure will be applied. + +crates: + - name: polkadot-runtime-parachains -- GitLab From 1da8a6b88f530b467394a9ead8f3042ebdc50a36 Mon Sep 17 00:00:00 2001 From: s0me0ne-unkn0wn <48632512+s0me0ne-unkn0wn@users.noreply.github.com> Date: Wed, 20 Mar 2024 20:41:43 +0100 Subject: [PATCH 071/187] Enable PoV reclaim on `rococo-parachain` (#3765) This PR proposes enabling PoV reclaim on the `rococo-parachain` testchain to streamline testing and development of high-TPS stuff. --- Cargo.lock | 1 + cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml | 2 ++ cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs | 1 + 3 files changed, 4 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 5401dc5ecfb..bdbf6ddac26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14973,6 +14973,7 @@ dependencies = [ "cumulus-ping", "cumulus-primitives-aura", "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-utility", "frame-benchmarking", "frame-executive", diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml index 577ed749167..790f38d94f5 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -56,6 +56,7 @@ cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-f cumulus-ping = { path = "../../../pallets/ping", default-features = false } cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } +cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } parachains-common = { path = "../../../common", default-features = false } testnet-parachains-constants = { path = "../../constants", default-features = false, features = ["rococo"] } @@ -75,6 +76,7 @@ std = [ "cumulus-ping/std", "cumulus-primitives-aura/std", "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", "cumulus-primitives-utility/std", "frame-benchmarking?/std", "frame-executive/std", diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index 1b7efa6f400..b3bea4d4e65 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -653,6 +653,7 @@ pub type SignedExtra = ( frame_system::CheckNonce, frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = -- GitLab From 93b1abb280cf9d6c64f00b66c3593c2b04d50a9e Mon Sep 17 00:00:00 2001 From: gupnik Date: Thu, 21 Mar 2024 08:41:51 +0530 Subject: [PATCH 072/187] Migrates Westend to Runtime V2 (#3754) Step in https://github.com/paritytech/polkadot-sdk/issues/3688 --- polkadot/runtime/westend/Cargo.toml | 2 +- polkadot/runtime/westend/src/lib.rs | 321 +++++++++++++++++----------- prdoc/pr_3754.prdoc | 13 ++ 3 files changed, 211 insertions(+), 125 deletions(-) create mode 100644 prdoc/pr_3754.prdoc diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index 4180828bcfb..fcead1dd0b5 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -45,7 +45,7 @@ sp-npos-elections = { path = "../../../substrate/primitives/npos-elections", def frame-election-provider-support = { path = "../../../substrate/frame/election-provider-support", default-features = false } frame-executive = { path = "../../../substrate/frame/executive", default-features = false } -frame-support = { path = "../../../substrate/frame/support", default-features = false, features = ["tuples-96"] } +frame-support = { path = "../../../substrate/frame/support", default-features = false, features = ["experimental", "tuples-96"] } frame-system = { path = "../../../substrate/frame/system", default-features = false } frame-system-rpc-runtime-api = { path = "../../../substrate/frame/system/rpc/runtime-api", default-features = false } westend-runtime-constants = { package = "westend-runtime-constants", path = "constants", default-features = false } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index f1d8841989c..62821cae7e4 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -17,7 +17,7 @@ //! The Westend runtime. This can be compiled with `#[no_std]`, ready for Wasm. #![cfg_attr(not(feature = "std"), no_std)] -// `construct_runtime!` does a lot of recursion and requires us to increase the limit. +// `#[frame_support::runtime]!` does a lot of recursion and requires us to increase the limit. #![recursion_limit = "512"] use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId; @@ -27,7 +27,7 @@ use beefy_primitives::{ }; use frame_election_provider_support::{bounds::ElectionBoundsBuilder, onchain, SequentialPhragmen}; use frame_support::{ - construct_runtime, derive_impl, + derive_impl, genesis_builder_helper::{build_config, create_default_config}, parameter_types, traits::{ @@ -1414,128 +1414,201 @@ impl pallet_asset_rate::Config for Runtime { type BenchmarkHelper = runtime_common::impls::benchmarks::AssetRateArguments; } -construct_runtime! { - pub enum Runtime - { - // Basic stuff; balances is uncallable initially. - System: frame_system = 0, - - // Babe must be before session. - Babe: pallet_babe = 1, - - Timestamp: pallet_timestamp = 2, - Indices: pallet_indices = 3, - Balances: pallet_balances = 4, - TransactionPayment: pallet_transaction_payment = 26, - - // Consensus support. - // Authorship must be before session in order to note author in the correct session and era. - Authorship: pallet_authorship = 5, - Staking: pallet_staking = 6, - Offences: pallet_offences = 7, - Historical: session_historical = 27, - - Session: pallet_session = 8, - Grandpa: pallet_grandpa = 10, - AuthorityDiscovery: pallet_authority_discovery = 12, - - // Utility module. - Utility: pallet_utility = 16, - - // Less simple identity module. - Identity: pallet_identity = 17, - - // Social recovery module. - Recovery: pallet_recovery = 18, - - // Vesting. Usable initially, but removed once all vesting is finished. - Vesting: pallet_vesting = 19, - - // System scheduler. - Scheduler: pallet_scheduler = 20, - - // Preimage registrar. - Preimage: pallet_preimage = 28, - - // Sudo. - Sudo: pallet_sudo = 21, - - // Proxy module. Late addition. - Proxy: pallet_proxy = 22, - - // Multisig module. Late addition. - Multisig: pallet_multisig = 23, - - // Election pallet. Only works with staking, but placed here to maintain indices. - ElectionProviderMultiPhase: pallet_election_provider_multi_phase = 24, - - // Provides a semi-sorted list of nominators for staking. - VoterList: pallet_bags_list:: = 25, - - // Nomination pools for staking. - NominationPools: pallet_nomination_pools = 29, - - // Fast unstake pallet: extension to staking. - FastUnstake: pallet_fast_unstake = 30, - - // OpenGov - ConvictionVoting: pallet_conviction_voting = 31, - Referenda: pallet_referenda = 32, - Origins: pallet_custom_origins = 35, - Whitelist: pallet_whitelist = 36, - - // Treasury - Treasury: pallet_treasury = 37, - - // Parachains pallets. Start indices at 40 to leave room. - ParachainsOrigin: parachains_origin = 41, - Configuration: parachains_configuration = 42, - ParasShared: parachains_shared = 43, - ParaInclusion: parachains_inclusion = 44, - ParaInherent: parachains_paras_inherent = 45, - ParaScheduler: parachains_scheduler = 46, - Paras: parachains_paras = 47, - Initializer: parachains_initializer = 48, - Dmp: parachains_dmp = 49, - // RIP Ump 50 - Hrmp: parachains_hrmp = 51, - ParaSessionInfo: parachains_session_info = 52, - ParasDisputes: parachains_disputes = 53, - ParasSlashing: parachains_slashing = 54, - OnDemandAssignmentProvider: parachains_assigner_on_demand = 56, - CoretimeAssignmentProvider: parachains_assigner_coretime = 57, - - // Parachain Onboarding Pallets. Start indices at 60 to leave room. - Registrar: paras_registrar = 60, - Slots: slots = 61, - ParasSudoWrapper: paras_sudo_wrapper = 62, - Auctions: auctions = 63, - Crowdloan: crowdloan = 64, - AssignedSlots: assigned_slots = 65, - Coretime: coretime = 66, - - // Pallet for sending XCM. - XcmPallet: pallet_xcm = 99, - - // Generalized message queue - MessageQueue: pallet_message_queue = 100, - - // Asset rate. - AssetRate: pallet_asset_rate = 101, - - // Root testing pallet. - RootTesting: pallet_root_testing = 102, - - // BEEFY Bridges support. - Beefy: pallet_beefy = 200, - // MMR leaf construction must be after session in order to have a leaf's next_auth_set - // refer to block. See issue polkadot-fellows/runtimes#160 for details. - Mmr: pallet_mmr = 201, - BeefyMmrLeaf: pallet_beefy_mmr = 202, - - // Pallet for migrating Identity to a parachain. To be removed post-migration. - IdentityMigrator: identity_migrator = 248, - } +#[frame_support::runtime(legacy_ordering)] +mod runtime { + #[runtime::runtime] + #[runtime::derive( + RuntimeCall, + RuntimeEvent, + RuntimeError, + RuntimeOrigin, + RuntimeFreezeReason, + RuntimeHoldReason, + RuntimeSlashReason, + RuntimeLockId, + RuntimeTask + )] + pub struct Runtime; + + // Basic stuff; balances is uncallable initially. + #[runtime::pallet_index(0)] + pub type System = frame_system; + + // Babe must be before session. + #[runtime::pallet_index(1)] + pub type Babe = pallet_babe; + + #[runtime::pallet_index(2)] + pub type Timestamp = pallet_timestamp; + #[runtime::pallet_index(3)] + pub type Indices = pallet_indices; + #[runtime::pallet_index(4)] + pub type Balances = pallet_balances; + #[runtime::pallet_index(26)] + pub type TransactionPayment = pallet_transaction_payment; + + // Consensus support. + // Authorship must be before session in order to note author in the correct session and era. + #[runtime::pallet_index(5)] + pub type Authorship = pallet_authorship; + #[runtime::pallet_index(6)] + pub type Staking = pallet_staking; + #[runtime::pallet_index(7)] + pub type Offences = pallet_offences; + #[runtime::pallet_index(27)] + pub type Historical = session_historical; + + #[runtime::pallet_index(8)] + pub type Session = pallet_session; + #[runtime::pallet_index(10)] + pub type Grandpa = pallet_grandpa; + #[runtime::pallet_index(12)] + pub type AuthorityDiscovery = pallet_authority_discovery; + + // Utility module. + #[runtime::pallet_index(16)] + pub type Utility = pallet_utility; + + // Less simple identity module. + #[runtime::pallet_index(17)] + pub type Identity = pallet_identity; + + // Social recovery module. + #[runtime::pallet_index(18)] + pub type Recovery = pallet_recovery; + + // Vesting. Usable initially, but removed once all vesting is finished. + #[runtime::pallet_index(19)] + pub type Vesting = pallet_vesting; + + // System scheduler. + #[runtime::pallet_index(20)] + pub type Scheduler = pallet_scheduler; + + // Preimage registrar. + #[runtime::pallet_index(28)] + pub type Preimage = pallet_preimage; + + // Sudo. + #[runtime::pallet_index(21)] + pub type Sudo = pallet_sudo; + + // Proxy module. Late addition. + #[runtime::pallet_index(22)] + pub type Proxy = pallet_proxy; + + // Multisig module. Late addition. + #[runtime::pallet_index(23)] + pub type Multisig = pallet_multisig; + + // Election pallet. Only works with staking, but placed here to maintain indices. + #[runtime::pallet_index(24)] + pub type ElectionProviderMultiPhase = pallet_election_provider_multi_phase; + + // Provides a semi-sorted list of nominators for staking. + #[runtime::pallet_index(25)] + pub type VoterList = pallet_bags_list; + + // Nomination pools for staking. + #[runtime::pallet_index(29)] + pub type NominationPools = pallet_nomination_pools; + + // Fast unstake pallet = extension to staking. + #[runtime::pallet_index(30)] + pub type FastUnstake = pallet_fast_unstake; + + // OpenGov + #[runtime::pallet_index(31)] + pub type ConvictionVoting = pallet_conviction_voting; + #[runtime::pallet_index(32)] + pub type Referenda = pallet_referenda; + #[runtime::pallet_index(35)] + pub type Origins = pallet_custom_origins; + #[runtime::pallet_index(36)] + pub type Whitelist = pallet_whitelist; + + // Treasury + #[runtime::pallet_index(37)] + pub type Treasury = pallet_treasury; + + // Parachains pallets. Start indices at 40 to leave room. + #[runtime::pallet_index(41)] + pub type ParachainsOrigin = parachains_origin; + #[runtime::pallet_index(42)] + pub type Configuration = parachains_configuration; + #[runtime::pallet_index(43)] + pub type ParasShared = parachains_shared; + #[runtime::pallet_index(44)] + pub type ParaInclusion = parachains_inclusion; + #[runtime::pallet_index(45)] + pub type ParaInherent = parachains_paras_inherent; + #[runtime::pallet_index(46)] + pub type ParaScheduler = parachains_scheduler; + #[runtime::pallet_index(47)] + pub type Paras = parachains_paras; + #[runtime::pallet_index(48)] + pub type Initializer = parachains_initializer; + #[runtime::pallet_index(49)] + pub type Dmp = parachains_dmp; + // RIP Ump 50 + #[runtime::pallet_index(51)] + pub type Hrmp = parachains_hrmp; + #[runtime::pallet_index(52)] + pub type ParaSessionInfo = parachains_session_info; + #[runtime::pallet_index(53)] + pub type ParasDisputes = parachains_disputes; + #[runtime::pallet_index(54)] + pub type ParasSlashing = parachains_slashing; + #[runtime::pallet_index(56)] + pub type OnDemandAssignmentProvider = parachains_assigner_on_demand; + #[runtime::pallet_index(57)] + pub type CoretimeAssignmentProvider = parachains_assigner_coretime; + + // Parachain Onboarding Pallets. Start indices at 60 to leave room. + #[runtime::pallet_index(60)] + pub type Registrar = paras_registrar; + #[runtime::pallet_index(61)] + pub type Slots = slots; + #[runtime::pallet_index(62)] + pub type ParasSudoWrapper = paras_sudo_wrapper; + #[runtime::pallet_index(63)] + pub type Auctions = auctions; + #[runtime::pallet_index(64)] + pub type Crowdloan = crowdloan; + #[runtime::pallet_index(65)] + pub type AssignedSlots = assigned_slots; + #[runtime::pallet_index(66)] + pub type Coretime = coretime; + + // Pallet for sending XCM. + #[runtime::pallet_index(99)] + pub type XcmPallet = pallet_xcm; + + // Generalized message queue + #[runtime::pallet_index(100)] + pub type MessageQueue = pallet_message_queue; + + // Asset rate. + #[runtime::pallet_index(101)] + pub type AssetRate = pallet_asset_rate; + + // Root testing pallet. + #[runtime::pallet_index(102)] + pub type RootTesting = pallet_root_testing; + + // BEEFY Bridges support. + #[runtime::pallet_index(200)] + pub type Beefy = pallet_beefy; + // MMR leaf construction must be after session in order to have a leaf's next_auth_set + // refer to block. See issue polkadot-fellows/runtimes#160 for details. + #[runtime::pallet_index(201)] + pub type Mmr = pallet_mmr; + #[runtime::pallet_index(202)] + pub type BeefyMmrLeaf = pallet_beefy_mmr; + + // Pallet for migrating Identity to a parachain. To be removed post-migration. + #[runtime::pallet_index(248)] + pub type IdentityMigrator = identity_migrator; } /// The address format for describing accounts. diff --git a/prdoc/pr_3754.prdoc b/prdoc/pr_3754.prdoc new file mode 100644 index 00000000000..94ea6d56608 --- /dev/null +++ b/prdoc/pr_3754.prdoc @@ -0,0 +1,13 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Migrates Westend to Runtime V2 + +doc: + - audience: Runtime Dev + description: | + This PR migrates Westend from `construct_runtime` to Runtime V2 + as introduced in https://github.com/paritytech/polkadot-sdk/pull/1378 + +crates: + - name: westend-runtime -- GitLab From 7b6b061e32f65b92574deaf8c199855e2c59d4c6 Mon Sep 17 00:00:00 2001 From: Egor_P Date: Thu, 21 Mar 2024 10:00:10 +0100 Subject: [PATCH 073/187] [Backport] version bumps and prdocs reordering 1.9.0 (#3758) This PR backports: - node version bump - `spec_vesion` bump - reordering of the `prdocs` to the appropriate folder from the `1.9.0` release branch --- .../parachains/runtimes/assets/asset-hub-rococo/src/lib.rs | 4 ++-- .../parachains/runtimes/assets/asset-hub-westend/src/lib.rs | 2 +- .../runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs | 2 +- .../runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs | 2 +- .../runtimes/collectives/collectives-westend/src/lib.rs | 2 +- .../parachains/runtimes/contracts/contracts-rococo/src/lib.rs | 2 +- .../parachains/runtimes/coretime/coretime-rococo/src/lib.rs | 2 +- .../parachains/runtimes/coretime/coretime-westend/src/lib.rs | 2 +- .../parachains/runtimes/glutton/glutton-westend/src/lib.rs | 2 +- cumulus/parachains/runtimes/people/people-rococo/src/lib.rs | 2 +- cumulus/parachains/runtimes/people/people-westend/src/lib.rs | 2 +- .../parachains/runtimes/testing/rococo-parachain/src/lib.rs | 2 +- polkadot/node/primitives/src/lib.rs | 2 +- polkadot/runtime/rococo/src/lib.rs | 2 +- polkadot/runtime/westend/src/lib.rs | 2 +- prdoc/{ => 1.9.0}/pr_1378.prdoc | 0 prdoc/{ => 1.9.0}/pr_1554.prdoc | 0 prdoc/{ => 1.9.0}/pr_1781.prdoc | 0 prdoc/{ => 1.9.0}/pr_2393.prdoc | 0 prdoc/{ => 1.9.0}/pr_3002.prdoc | 0 prdoc/{ => 1.9.0}/pr_3187.prdoc | 0 prdoc/{ => 1.9.0}/pr_3231.prdoc | 0 prdoc/{ => 1.9.0}/pr_3233.prdoc | 0 prdoc/{ => 1.9.0}/pr_3324.prdoc | 0 prdoc/{ => 1.9.0}/pr_3371.prdoc | 0 prdoc/{ => 1.9.0}/pr_3377.prdoc | 0 prdoc/{ => 1.9.0}/pr_3378.prdoc | 0 prdoc/{ => 1.9.0}/pr_3403.prdoc | 0 prdoc/{ => 1.9.0}/pr_3411.prdoc | 0 prdoc/{ => 1.9.0}/pr_3412.prdoc | 0 prdoc/{ => 1.9.0}/pr_3447.prdoc | 0 prdoc/{ => 1.9.0}/pr_3453.prdoc | 0 prdoc/{ => 1.9.0}/pr_3454.prdoc | 0 prdoc/{ => 1.9.0}/pr_3456.prdoc | 0 prdoc/{ => 1.9.0}/pr_3460.prdoc | 0 prdoc/{ => 1.9.0}/pr_3491.prdoc | 0 prdoc/{ => 1.9.0}/pr_3504.prdoc | 0 prdoc/{ => 1.9.0}/pr_3505.prdoc | 0 prdoc/{ => 1.9.0}/pr_3510.prdoc | 0 prdoc/{ => 1.9.0}/pr_3513.prdoc | 0 prdoc/{ => 1.9.0}/pr_3523.prdoc | 0 prdoc/{ => 1.9.0}/pr_3532.prdoc | 0 prdoc/{ => 1.9.0}/pr_3540.prdoc | 0 prdoc/{ => 1.9.0}/pr_3574.prdoc | 0 prdoc/{ => 1.9.0}/pr_3589.prdoc | 0 prdoc/{ => 1.9.0}/pr_3606.prdoc | 0 prdoc/{ => 1.9.0}/pr_3636.prdoc | 0 prdoc/{ => 1.9.0}/pr_3639.prdoc | 0 prdoc/{ => 1.9.0}/pr_3643.prdoc | 0 prdoc/{ => 1.9.0}/pr_3665.prdoc | 0 50 files changed, 16 insertions(+), 16 deletions(-) rename prdoc/{ => 1.9.0}/pr_1378.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_1554.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_1781.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_2393.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3002.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3187.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3231.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3233.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3324.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3371.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3377.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3378.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3403.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3411.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3412.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3447.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3453.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3454.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3456.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3460.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3491.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3504.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3505.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3510.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3513.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3523.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3532.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3540.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3574.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3589.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3606.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3636.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3639.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3643.prdoc (100%) rename prdoc/{ => 1.9.0}/pr_3665.prdoc (100%) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index d3d8a495ea3..689d8d56c48 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -113,7 +113,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("statemine"), impl_name: create_runtime_str!("statemine"), authoring_version: 1, - spec_version: 1_008_000, + spec_version: 1_009_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 14, @@ -126,7 +126,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("statemine"), impl_name: create_runtime_str!("statemine"), authoring_version: 1, - spec_version: 1_008_000, + spec_version: 1_009_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 14, diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 711fadff92a..48106b5f302 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -110,7 +110,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("westmint"), impl_name: create_runtime_str!("westmint"), authoring_version: 1, - spec_version: 1_008_000, + spec_version: 1_009_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 14, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index bbafcd3c7dd..bf7483179f2 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -202,7 +202,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("bridge-hub-rococo"), impl_name: create_runtime_str!("bridge-hub-rococo"), authoring_version: 1, - spec_version: 1_008_000, + spec_version: 1_009_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 4, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index 11ab9aecc61..9bdea6b9a7d 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -176,7 +176,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("bridge-hub-westend"), impl_name: create_runtime_str!("bridge-hub-westend"), authoring_version: 1, - spec_version: 1_008_000, + spec_version: 1_009_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 4, diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index 55269283e08..d3f588bf25f 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -117,7 +117,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("collectives-westend"), impl_name: create_runtime_str!("collectives-westend"), authoring_version: 1, - spec_version: 1_008_000, + spec_version: 1_009_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 5, diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 17bb45f6b1b..e1586c7d9b2 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -133,7 +133,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("contracts-rococo"), impl_name: create_runtime_str!("contracts-rococo"), authoring_version: 1, - spec_version: 1_008_000, + spec_version: 1_009_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 6, diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs index 26add2ee942..86eb5cdfcaf 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs @@ -133,7 +133,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("coretime-rococo"), impl_name: create_runtime_str!("coretime-rococo"), authoring_version: 1, - spec_version: 1_008_000, + spec_version: 1_009_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 0, diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs index 76732c3fccc..c31e474cc2f 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs @@ -133,7 +133,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("coretime-westend"), impl_name: create_runtime_str!("coretime-westend"), authoring_version: 1, - spec_version: 1_008_000, + spec_version: 1_009_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 0, diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs index fe18f48fbb3..cee17cdc7b0 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs @@ -100,7 +100,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("glutton-westend"), impl_name: create_runtime_str!("glutton-westend"), authoring_version: 1, - spec_version: 1_008_000, + spec_version: 1_009_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs index 2bb5641b4af..ad369583f07 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs @@ -126,7 +126,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("people-rococo"), impl_name: create_runtime_str!("people-rococo"), authoring_version: 1, - spec_version: 1_008_000, + spec_version: 1_009_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 0, diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs index b81f7a9c969..c76611ad2a3 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs @@ -126,7 +126,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("people-westend"), impl_name: create_runtime_str!("people-westend"), authoring_version: 1, - spec_version: 1_008_000, + spec_version: 1_009_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 0, diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index b3bea4d4e65..c6006141981 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -107,7 +107,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("test-parachain"), impl_name: create_runtime_str!("test-parachain"), authoring_version: 1, - spec_version: 1_008_000, + spec_version: 1_009_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 6, diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs index d295c21cce1..b6556e0be56 100644 --- a/polkadot/node/primitives/src/lib.rs +++ b/polkadot/node/primitives/src/lib.rs @@ -58,7 +58,7 @@ pub use disputes::{ /// relatively rare. /// /// The associated worker binaries should use the same version as the node that spawns them. -pub const NODE_VERSION: &'static str = "1.8.0"; +pub const NODE_VERSION: &'static str = "1.9.0"; // For a 16-ary Merkle Prefix Trie, we can expect at most 16 32-byte hashes per node // plus some overhead: diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index a773eeb5cbd..c9f5d81d286 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -149,7 +149,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("rococo"), impl_name: create_runtime_str!("parity-rococo-v2.0"), authoring_version: 0, - spec_version: 1_008_000, + spec_version: 1_009_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 24, diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 62821cae7e4..83d47508c7c 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -150,7 +150,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("westend"), impl_name: create_runtime_str!("parity-westend"), authoring_version: 2, - spec_version: 1_008_000, + spec_version: 1_009_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 24, diff --git a/prdoc/pr_1378.prdoc b/prdoc/1.9.0/pr_1378.prdoc similarity index 100% rename from prdoc/pr_1378.prdoc rename to prdoc/1.9.0/pr_1378.prdoc diff --git a/prdoc/pr_1554.prdoc b/prdoc/1.9.0/pr_1554.prdoc similarity index 100% rename from prdoc/pr_1554.prdoc rename to prdoc/1.9.0/pr_1554.prdoc diff --git a/prdoc/pr_1781.prdoc b/prdoc/1.9.0/pr_1781.prdoc similarity index 100% rename from prdoc/pr_1781.prdoc rename to prdoc/1.9.0/pr_1781.prdoc diff --git a/prdoc/pr_2393.prdoc b/prdoc/1.9.0/pr_2393.prdoc similarity index 100% rename from prdoc/pr_2393.prdoc rename to prdoc/1.9.0/pr_2393.prdoc diff --git a/prdoc/pr_3002.prdoc b/prdoc/1.9.0/pr_3002.prdoc similarity index 100% rename from prdoc/pr_3002.prdoc rename to prdoc/1.9.0/pr_3002.prdoc diff --git a/prdoc/pr_3187.prdoc b/prdoc/1.9.0/pr_3187.prdoc similarity index 100% rename from prdoc/pr_3187.prdoc rename to prdoc/1.9.0/pr_3187.prdoc diff --git a/prdoc/pr_3231.prdoc b/prdoc/1.9.0/pr_3231.prdoc similarity index 100% rename from prdoc/pr_3231.prdoc rename to prdoc/1.9.0/pr_3231.prdoc diff --git a/prdoc/pr_3233.prdoc b/prdoc/1.9.0/pr_3233.prdoc similarity index 100% rename from prdoc/pr_3233.prdoc rename to prdoc/1.9.0/pr_3233.prdoc diff --git a/prdoc/pr_3324.prdoc b/prdoc/1.9.0/pr_3324.prdoc similarity index 100% rename from prdoc/pr_3324.prdoc rename to prdoc/1.9.0/pr_3324.prdoc diff --git a/prdoc/pr_3371.prdoc b/prdoc/1.9.0/pr_3371.prdoc similarity index 100% rename from prdoc/pr_3371.prdoc rename to prdoc/1.9.0/pr_3371.prdoc diff --git a/prdoc/pr_3377.prdoc b/prdoc/1.9.0/pr_3377.prdoc similarity index 100% rename from prdoc/pr_3377.prdoc rename to prdoc/1.9.0/pr_3377.prdoc diff --git a/prdoc/pr_3378.prdoc b/prdoc/1.9.0/pr_3378.prdoc similarity index 100% rename from prdoc/pr_3378.prdoc rename to prdoc/1.9.0/pr_3378.prdoc diff --git a/prdoc/pr_3403.prdoc b/prdoc/1.9.0/pr_3403.prdoc similarity index 100% rename from prdoc/pr_3403.prdoc rename to prdoc/1.9.0/pr_3403.prdoc diff --git a/prdoc/pr_3411.prdoc b/prdoc/1.9.0/pr_3411.prdoc similarity index 100% rename from prdoc/pr_3411.prdoc rename to prdoc/1.9.0/pr_3411.prdoc diff --git a/prdoc/pr_3412.prdoc b/prdoc/1.9.0/pr_3412.prdoc similarity index 100% rename from prdoc/pr_3412.prdoc rename to prdoc/1.9.0/pr_3412.prdoc diff --git a/prdoc/pr_3447.prdoc b/prdoc/1.9.0/pr_3447.prdoc similarity index 100% rename from prdoc/pr_3447.prdoc rename to prdoc/1.9.0/pr_3447.prdoc diff --git a/prdoc/pr_3453.prdoc b/prdoc/1.9.0/pr_3453.prdoc similarity index 100% rename from prdoc/pr_3453.prdoc rename to prdoc/1.9.0/pr_3453.prdoc diff --git a/prdoc/pr_3454.prdoc b/prdoc/1.9.0/pr_3454.prdoc similarity index 100% rename from prdoc/pr_3454.prdoc rename to prdoc/1.9.0/pr_3454.prdoc diff --git a/prdoc/pr_3456.prdoc b/prdoc/1.9.0/pr_3456.prdoc similarity index 100% rename from prdoc/pr_3456.prdoc rename to prdoc/1.9.0/pr_3456.prdoc diff --git a/prdoc/pr_3460.prdoc b/prdoc/1.9.0/pr_3460.prdoc similarity index 100% rename from prdoc/pr_3460.prdoc rename to prdoc/1.9.0/pr_3460.prdoc diff --git a/prdoc/pr_3491.prdoc b/prdoc/1.9.0/pr_3491.prdoc similarity index 100% rename from prdoc/pr_3491.prdoc rename to prdoc/1.9.0/pr_3491.prdoc diff --git a/prdoc/pr_3504.prdoc b/prdoc/1.9.0/pr_3504.prdoc similarity index 100% rename from prdoc/pr_3504.prdoc rename to prdoc/1.9.0/pr_3504.prdoc diff --git a/prdoc/pr_3505.prdoc b/prdoc/1.9.0/pr_3505.prdoc similarity index 100% rename from prdoc/pr_3505.prdoc rename to prdoc/1.9.0/pr_3505.prdoc diff --git a/prdoc/pr_3510.prdoc b/prdoc/1.9.0/pr_3510.prdoc similarity index 100% rename from prdoc/pr_3510.prdoc rename to prdoc/1.9.0/pr_3510.prdoc diff --git a/prdoc/pr_3513.prdoc b/prdoc/1.9.0/pr_3513.prdoc similarity index 100% rename from prdoc/pr_3513.prdoc rename to prdoc/1.9.0/pr_3513.prdoc diff --git a/prdoc/pr_3523.prdoc b/prdoc/1.9.0/pr_3523.prdoc similarity index 100% rename from prdoc/pr_3523.prdoc rename to prdoc/1.9.0/pr_3523.prdoc diff --git a/prdoc/pr_3532.prdoc b/prdoc/1.9.0/pr_3532.prdoc similarity index 100% rename from prdoc/pr_3532.prdoc rename to prdoc/1.9.0/pr_3532.prdoc diff --git a/prdoc/pr_3540.prdoc b/prdoc/1.9.0/pr_3540.prdoc similarity index 100% rename from prdoc/pr_3540.prdoc rename to prdoc/1.9.0/pr_3540.prdoc diff --git a/prdoc/pr_3574.prdoc b/prdoc/1.9.0/pr_3574.prdoc similarity index 100% rename from prdoc/pr_3574.prdoc rename to prdoc/1.9.0/pr_3574.prdoc diff --git a/prdoc/pr_3589.prdoc b/prdoc/1.9.0/pr_3589.prdoc similarity index 100% rename from prdoc/pr_3589.prdoc rename to prdoc/1.9.0/pr_3589.prdoc diff --git a/prdoc/pr_3606.prdoc b/prdoc/1.9.0/pr_3606.prdoc similarity index 100% rename from prdoc/pr_3606.prdoc rename to prdoc/1.9.0/pr_3606.prdoc diff --git a/prdoc/pr_3636.prdoc b/prdoc/1.9.0/pr_3636.prdoc similarity index 100% rename from prdoc/pr_3636.prdoc rename to prdoc/1.9.0/pr_3636.prdoc diff --git a/prdoc/pr_3639.prdoc b/prdoc/1.9.0/pr_3639.prdoc similarity index 100% rename from prdoc/pr_3639.prdoc rename to prdoc/1.9.0/pr_3639.prdoc diff --git a/prdoc/pr_3643.prdoc b/prdoc/1.9.0/pr_3643.prdoc similarity index 100% rename from prdoc/pr_3643.prdoc rename to prdoc/1.9.0/pr_3643.prdoc diff --git a/prdoc/pr_3665.prdoc b/prdoc/1.9.0/pr_3665.prdoc similarity index 100% rename from prdoc/pr_3665.prdoc rename to prdoc/1.9.0/pr_3665.prdoc -- GitLab From 75074952a859f90213ea25257b71ec2189dbcfc1 Mon Sep 17 00:00:00 2001 From: Egor_P Date: Thu, 21 Mar 2024 10:00:40 +0100 Subject: [PATCH 074/187] [Backport] Reformat release notes generation (#3759) This PR backports small reformatting of the release notes templates. --- scripts/release/build-changelogs.sh | 1 + scripts/release/templates/audience.md.tera | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/scripts/release/build-changelogs.sh b/scripts/release/build-changelogs.sh index a9275f45a50..cbfb7ad0e48 100755 --- a/scripts/release/build-changelogs.sh +++ b/scripts/release/build-changelogs.sh @@ -48,6 +48,7 @@ for audience in "${audiences[@]}"; do echo "Processing audience: $audience ($audience_id)" export TARGET_AUDIENCE=$audience tera -t "${TEMPLATE_AUDIENCE}" --env --env-key env "${CONTEXT_JSON}" > "$OUTPUT/relnote_${audience_id}.md" + cat "$OUTPUT/relnote_${audience_id}.md" >> "$OUTPUT/relnote_combined.md" done # Show the files diff --git a/scripts/release/templates/audience.md.tera b/scripts/release/templates/audience.md.tera index dc507053dd5..0b47850e3a3 100644 --- a/scripts/release/templates/audience.md.tera +++ b/scripts/release/templates/audience.md.tera @@ -1,11 +1,9 @@ -## Release {{ env.PRODUCT }} {{ env.VERSION }} - -Changelog for `{{ env.TARGET_AUDIENCE }}`. +### Changelog for `{{ env.TARGET_AUDIENCE }}` {% for file in prdoc -%} -#### PR #{{file.doc_filename.number}}: {{ file.content.title }} {% for doc_item in file.content.doc %} {%- if doc_item.audience == env.TARGET_AUDIENCE %} +#### [#{{file.doc_filename.number}}]: {{ file.content.title }} {{ doc_item.description }} {% endif -%} -- GitLab From 4842faf65d3628586d304fbcb6cb19b17b4a629c Mon Sep 17 00:00:00 2001 From: Alin Dima Date: Thu, 21 Mar 2024 12:10:45 +0200 Subject: [PATCH 075/187] Elastic scaling: runtime dependency tracking and enactment (#3479) Changes needed to implement the runtime part of elastic scaling: https://github.com/paritytech/polkadot-sdk/issues/3131, https://github.com/paritytech/polkadot-sdk/issues/3132, https://github.com/paritytech/polkadot-sdk/issues/3202 Also fixes https://github.com/paritytech/polkadot-sdk/issues/3675 TODOs: - [x] storage migration - [x] optimise process_candidates from O(N^2) - [x] drop backable candidates which form cycles - [x] fix unit tests - [x] add more unit tests - [x] check the runtime APIs which use the pending availability storage. We need to expose all of them, see https://github.com/paritytech/polkadot-sdk/issues/3576 - [x] optimise the candidate selection. we're currently picking randomly until we satisfy the weight limit. we need to be smart about not breaking candidate chains while being fair to all paras - https://github.com/paritytech/polkadot-sdk/pull/3573 Relies on the changes made in https://github.com/paritytech/polkadot-sdk/pull/3233 in terms of the inclusion policy and the candidate ordering --------- Signed-off-by: alindima Co-authored-by: command-bot <> Co-authored-by: eskimor --- .../src/runtime/inclusion.md | 11 +- .../src/runtime/parainherent.md | 2 +- .../src/runtime/scheduler.md | 1 - polkadot/runtime/parachains/src/builder.rs | 109 +- .../parachains/src/inclusion/migration.rs | 317 ++++ .../runtime/parachains/src/inclusion/mod.rs | 803 ++++----- .../runtime/parachains/src/inclusion/tests.rs | 1241 ++++++++----- .../src/paras_inherent/benchmarking.rs | 8 - .../parachains/src/paras_inherent/mod.rs | 599 +++--- .../parachains/src/paras_inherent/tests.rs | 1604 +++++++++++++++-- .../parachains/src/runtime_api_impl/v7.rs | 84 +- polkadot/runtime/parachains/src/scheduler.rs | 10 - polkadot/runtime/parachains/src/util.rs | 19 +- polkadot/runtime/rococo/src/lib.rs | 2 + .../runtime_parachains_paras_inherent.rs | 421 +++-- polkadot/runtime/westend/src/lib.rs | 1 + .../runtime_parachains_paras_inherent.rs | 583 +++--- prdoc/pr_3479.prdoc | 8 + 18 files changed, 4075 insertions(+), 1748 deletions(-) create mode 100644 polkadot/runtime/parachains/src/inclusion/migration.rs create mode 100644 prdoc/pr_3479.prdoc diff --git a/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md b/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md index f6a32a01d50..fd74f33253b 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md @@ -147,15 +147,16 @@ All failed checks should lead to an unrecoverable error making the block invalid // return a vector of cleaned-up core IDs. } ``` -* `force_enact(ParaId)`: Forcibly enact the candidate with the given ID as though it had been deemed available by - bitfields. Is a no-op if there is no candidate pending availability for this para-id. This should generally not be - used but it is useful during execution of Runtime APIs, where the changes to the state are expected to be discarded - directly after. +* `force_enact(ParaId)`: Forcibly enact the pending candidates of the given paraid as though they had been deemed + available by bitfields. Is a no-op if there is no candidate pending availability for this para-id. + If there are multiple candidates pending availability for this para-id, it will enact all of + them. This should generally not be used but it is useful during execution of Runtime APIs, + where the changes to the state are expected to be discarded directly after. * `candidate_pending_availability(ParaId) -> Option`: returns the `CommittedCandidateReceipt` pending availability for the para provided, if any. * `pending_availability(ParaId) -> Option`: returns the metadata around the candidate pending availability for the para, if any. -* `collect_disputed(disputed: Vec) -> Vec`: Sweeps through all paras pending availability. If +* `free_disputed(disputed: Vec) -> Vec`: Sweeps through all paras pending availability. If the candidate hash is one of the disputed candidates, then clean up the corresponding storage for that candidate and the commitments. Return a vector of cleaned-up core IDs. diff --git a/polkadot/roadmap/implementers-guide/src/runtime/parainherent.md b/polkadot/roadmap/implementers-guide/src/runtime/parainherent.md index 5419ddae83d..1345f0eea95 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/parainherent.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/parainherent.md @@ -17,7 +17,7 @@ There are a couple of important notes to the operations in this inherent as they this fork. 1. When disputes are initiated, we remove the block from pending availability. This allows us to roll back chains to the block before blocks are included as opposed to backing. It's important to do this before processing bitfields. -1. `Inclusion::collect_disputed` is kind of expensive so it's important to gate this on whether there are actually any +1. `Inclusion::free_disputed` is kind of expensive so it's important to gate this on whether there are actually any new disputes. Which should be never. 1. And we don't accept parablocks that have open disputes or disputes that have concluded against the candidate. It's important to import dispute statements before backing, but this is already the case as disputes are imported before diff --git a/polkadot/roadmap/implementers-guide/src/runtime/scheduler.md b/polkadot/roadmap/implementers-guide/src/runtime/scheduler.md index 32a7fe652db..04b221a83e5 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/scheduler.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/scheduler.md @@ -285,7 +285,6 @@ No finalization routine runs for this module. - This clears them from `Scheduled` and marks each corresponding `core` in the `AvailabilityCores` as occupied. - Since both the availability cores and the newly-occupied cores lists are sorted ascending, this method can be implemented efficiently. -- `core_para(CoreIndex) -> ParaId`: return the currently-scheduled or occupied ParaId for the given core. - `group_validators(GroupIndex) -> Option>`: return all validators in a given group, if the group index is valid for this session. - `availability_timeout_predicate() -> Option bool>`: returns an optional predicate diff --git a/polkadot/runtime/parachains/src/builder.rs b/polkadot/runtime/parachains/src/builder.rs index 05f6845f3b7..73617010f6d 100644 --- a/polkadot/runtime/parachains/src/builder.rs +++ b/polkadot/runtime/parachains/src/builder.rs @@ -40,7 +40,7 @@ use sp_runtime::{ RuntimeAppPublic, }; use sp_std::{ - collections::{btree_map::BTreeMap, vec_deque::VecDeque}, + collections::{btree_map::BTreeMap, btree_set::BTreeSet, vec_deque::VecDeque}, prelude::Vec, vec, }; @@ -104,6 +104,8 @@ pub(crate) struct BenchBuilder { code_upgrade: Option, /// Specifies whether the claimqueue should be filled. fill_claimqueue: bool, + /// Cores which should not be available when being populated with pending candidates. + unavailable_cores: Vec, _phantom: sp_std::marker::PhantomData, } @@ -133,6 +135,7 @@ impl BenchBuilder { elastic_paras: Default::default(), code_upgrade: None, fill_claimqueue: true, + unavailable_cores: vec![], _phantom: sp_std::marker::PhantomData::, } } @@ -149,6 +152,12 @@ impl BenchBuilder { self } + /// Set the cores which should not be available when being populated with pending candidates. + pub(crate) fn set_unavailable_cores(mut self, unavailable_cores: Vec) -> Self { + self.unavailable_cores = unavailable_cores; + self + } + /// Set a map from para id seed to number of validity votes. pub(crate) fn set_backed_and_concluding_paras( mut self, @@ -159,7 +168,6 @@ impl BenchBuilder { } /// Set a map from para id seed to number of cores assigned to it. - #[cfg(feature = "runtime-benchmarks")] pub(crate) fn set_elastic_paras(mut self, elastic_paras: BTreeMap) -> Self { self.elastic_paras = elastic_paras; self @@ -284,11 +292,13 @@ impl BenchBuilder { core_idx: CoreIndex, candidate_hash: CandidateHash, availability_votes: BitVec, + commitments: CandidateCommitments, ) -> inclusion::CandidatePendingAvailability> { inclusion::CandidatePendingAvailability::>::new( core_idx, // core candidate_hash, // hash Self::candidate_descriptor_mock(), // candidate descriptor + commitments, // commitments availability_votes, // availability votes Default::default(), // backers Zero::zero(), // relay parent @@ -309,12 +319,6 @@ impl BenchBuilder { availability_votes: BitVec, candidate_hash: CandidateHash, ) { - let candidate_availability = Self::candidate_availability_mock( - group_idx, - core_idx, - candidate_hash, - availability_votes, - ); let commitments = CandidateCommitments:: { upward_messages: Default::default(), horizontal_messages: Default::default(), @@ -323,16 +327,29 @@ impl BenchBuilder { processed_downward_messages: 0, hrmp_watermark: 0u32.into(), }; - inclusion::PendingAvailability::::insert(para_id, candidate_availability); - inclusion::PendingAvailabilityCommitments::::insert(¶_id, commitments); + let candidate_availability = Self::candidate_availability_mock( + group_idx, + core_idx, + candidate_hash, + availability_votes, + commitments, + ); + inclusion::PendingAvailability::::mutate(para_id, |maybe_andidates| { + if let Some(candidates) = maybe_andidates { + candidates.push_back(candidate_availability); + } else { + *maybe_andidates = + Some([candidate_availability].into_iter().collect::>()); + } + }); } /// Create an `AvailabilityBitfield` where `concluding` is a map where each key is a core index /// that is concluding and `cores` is the total number of cores in the system. - fn availability_bitvec(concluding: &BTreeMap, cores: usize) -> AvailabilityBitfield { + fn availability_bitvec(concluding_cores: &BTreeSet, cores: usize) -> AvailabilityBitfield { let mut bitfields = bitvec::bitvec![u8, bitvec::order::Lsb0; 0; 0]; for i in 0..cores { - if concluding.get(&(i as u32)).is_some() { + if concluding_cores.contains(&(i as u32)) { bitfields.push(true); } else { bitfields.push(false) @@ -356,13 +373,13 @@ impl BenchBuilder { } } - /// Register `cores` count of parachains. + /// Register `n_paras` count of parachains. /// /// Note that this must be called at least 2 sessions before the target session as there is a /// n+2 session delay for the scheduled actions to take effect. - fn setup_para_ids(cores: usize) { + fn setup_para_ids(n_paras: usize) { // make sure parachains exist prior to session change. - for i in 0..cores { + for i in 0..n_paras { let para_id = ParaId::from(i as u32); let validation_code = mock_validation_code(); @@ -472,24 +489,8 @@ impl BenchBuilder { let validators = self.validators.as_ref().expect("must have some validators prior to calling"); - let availability_bitvec = Self::availability_bitvec(concluding_paras, total_cores); - - let bitfields: Vec> = validators - .iter() - .enumerate() - .map(|(i, public)| { - let unchecked_signed = UncheckedSigned::::benchmark_sign( - public, - availability_bitvec.clone(), - &self.signing_context(), - ValidatorIndex(i as u32), - ); - - unchecked_signed - }) - .collect(); - let mut current_core_idx = 0u32; + let mut concluding_cores = BTreeSet::new(); for (seed, _) in concluding_paras.iter() { // make sure the candidates that will be concluding are marked as pending availability. @@ -505,13 +506,34 @@ impl BenchBuilder { para_id, core_idx, group_idx, - Self::validator_availability_votes_yes(validators.len()), + // No validators have made this candidate available yet. + bitvec::bitvec![u8, bitvec::order::Lsb0; 0; validators.len()], CandidateHash(H256::from(byte32_slice_from(current_core_idx))), ); + if !self.unavailable_cores.contains(¤t_core_idx) { + concluding_cores.insert(current_core_idx); + } current_core_idx += 1; } } + let availability_bitvec = Self::availability_bitvec(&concluding_cores, total_cores); + + let bitfields: Vec> = validators + .iter() + .enumerate() + .map(|(i, public)| { + let unchecked_signed = UncheckedSigned::::benchmark_sign( + public, + availability_bitvec.clone(), + &self.signing_context(), + ValidatorIndex(i as u32), + ); + + unchecked_signed + }) + .collect(); + bitfields } @@ -522,7 +544,7 @@ impl BenchBuilder { /// validity votes. fn create_backed_candidates( &self, - cores_with_backed_candidates: &BTreeMap, + paras_with_backed_candidates: &BTreeMap, elastic_paras: &BTreeMap, includes_code_upgrade: Option, ) -> Vec> { @@ -531,7 +553,7 @@ impl BenchBuilder { let config = configuration::Pallet::::config(); let mut current_core_idx = 0u32; - cores_with_backed_candidates + paras_with_backed_candidates .iter() .flat_map(|(seed, num_votes)| { assert!(*num_votes <= validators.len() as u32); @@ -760,7 +782,7 @@ impl BenchBuilder { // NOTE: there is an n+2 session delay for these actions to take effect. // We are currently in Session 0, so these changes will take effect in Session 2. - Self::setup_para_ids(used_cores); + Self::setup_para_ids(used_cores - extra_cores); configuration::ActiveConfig::::mutate(|c| { c.scheduler_params.num_cores = used_cores as u32; }); @@ -782,11 +804,11 @@ impl BenchBuilder { let disputes = builder.create_disputes( builder.backed_and_concluding_paras.len() as u32, - used_cores as u32, + (used_cores - extra_cores) as u32, builder.dispute_sessions.as_slice(), ); let mut disputed_cores = (builder.backed_and_concluding_paras.len() as u32.. - used_cores as u32) + ((used_cores - extra_cores) as u32)) .into_iter() .map(|idx| (idx, 0)) .collect::>(); @@ -794,7 +816,7 @@ impl BenchBuilder { let mut all_cores = builder.backed_and_concluding_paras.clone(); all_cores.append(&mut disputed_cores); - assert_eq!(inclusion::PendingAvailability::::iter().count(), used_cores as usize,); + assert_eq!(inclusion::PendingAvailability::::iter().count(), used_cores - extra_cores); // Mark all the used cores as occupied. We expect that there are // `backed_and_concluding_paras` that are pending availability and that there are @@ -831,7 +853,7 @@ impl BenchBuilder { .keys() .flat_map(|para_id| { (0..elastic_paras.get(¶_id).cloned().unwrap_or(1)) - .map(|_para_local_core_idx| { + .filter_map(|_para_local_core_idx| { let ttl = configuration::Pallet::::config().scheduler_params.ttl; // Load an assignment into provider so that one is present to pop let assignment = @@ -844,8 +866,13 @@ impl BenchBuilder { CoreIndex(core_idx), [ParasEntry::new(assignment, now + ttl)].into(), ); + let res = if builder.unavailable_cores.contains(&core_idx) { + None + } else { + Some(entry) + }; core_idx += 1; - entry + res }) .collect::>)>>() }) diff --git a/polkadot/runtime/parachains/src/inclusion/migration.rs b/polkadot/runtime/parachains/src/inclusion/migration.rs new file mode 100644 index 00000000000..1e63b209f4e --- /dev/null +++ b/polkadot/runtime/parachains/src/inclusion/migration.rs @@ -0,0 +1,317 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +pub use v1::MigrateToV1; + +pub mod v0 { + use crate::inclusion::{Config, Pallet}; + use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; + use frame_support::{storage_alias, Twox64Concat}; + use frame_system::pallet_prelude::BlockNumberFor; + use parity_scale_codec::{Decode, Encode}; + use primitives::{ + AvailabilityBitfield, CandidateCommitments, CandidateDescriptor, CandidateHash, CoreIndex, + GroupIndex, Id as ParaId, ValidatorIndex, + }; + use scale_info::TypeInfo; + + #[derive(Encode, Decode, PartialEq, TypeInfo, Clone, Debug)] + pub struct CandidatePendingAvailability { + pub core: CoreIndex, + pub hash: CandidateHash, + pub descriptor: CandidateDescriptor, + pub availability_votes: BitVec, + pub backers: BitVec, + pub relay_parent_number: N, + pub backed_in_number: N, + pub backing_group: GroupIndex, + } + + #[derive(Encode, Decode, TypeInfo, Debug, PartialEq)] + pub struct AvailabilityBitfieldRecord { + pub bitfield: AvailabilityBitfield, + pub submitted_at: N, + } + + #[storage_alias] + pub type PendingAvailability = StorageMap< + Pallet, + Twox64Concat, + ParaId, + CandidatePendingAvailability<::Hash, BlockNumberFor>, + >; + + #[storage_alias] + pub type PendingAvailabilityCommitments = + StorageMap, Twox64Concat, ParaId, CandidateCommitments>; + + #[storage_alias] + pub type AvailabilityBitfields = StorageMap< + Pallet, + Twox64Concat, + ValidatorIndex, + AvailabilityBitfieldRecord>, + >; +} + +mod v1 { + use super::v0::{ + AvailabilityBitfields, PendingAvailability as V0PendingAvailability, + PendingAvailabilityCommitments as V0PendingAvailabilityCommitments, + }; + use crate::inclusion::{ + CandidatePendingAvailability as V1CandidatePendingAvailability, Config, Pallet, + PendingAvailability as V1PendingAvailability, + }; + use frame_support::{traits::OnRuntimeUpgrade, weights::Weight}; + use sp_core::Get; + use sp_std::{collections::vec_deque::VecDeque, vec::Vec}; + + #[cfg(feature = "try-runtime")] + use frame_support::{ + ensure, + traits::{GetStorageVersion, StorageVersion}, + }; + #[cfg(feature = "try-runtime")] + use parity_scale_codec::{Decode, Encode}; + + pub struct VersionUncheckedMigrateToV1(sp_std::marker::PhantomData); + + impl OnRuntimeUpgrade for VersionUncheckedMigrateToV1 { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + log::trace!(target: crate::inclusion::LOG_TARGET, "Running pre_upgrade() for inclusion MigrateToV1"); + let candidates_before_upgrade = V0PendingAvailability::::iter().count(); + let commitments_before_upgrade = V0PendingAvailabilityCommitments::::iter().count(); + + if candidates_before_upgrade != commitments_before_upgrade { + log::warn!( + target: crate::inclusion::LOG_TARGET, + "Number of pending candidates differ from the number of pending commitments. {} vs {}", + candidates_before_upgrade, + commitments_before_upgrade + ); + } + + Ok((candidates_before_upgrade as u32).encode()) + } + + fn on_runtime_upgrade() -> Weight { + let mut weight: Weight = Weight::zero(); + + let v0_candidates: Vec<_> = V0PendingAvailability::::drain().collect(); + + for (para_id, candidate) in v0_candidates { + let commitments = V0PendingAvailabilityCommitments::::take(para_id); + // One write for each removal (one candidate and one commitment). + weight = weight.saturating_add(T::DbWeight::get().writes(2)); + + if let Some(commitments) = commitments { + let mut per_para = VecDeque::new(); + per_para.push_back(V1CandidatePendingAvailability { + core: candidate.core, + hash: candidate.hash, + descriptor: candidate.descriptor, + availability_votes: candidate.availability_votes, + backers: candidate.backers, + relay_parent_number: candidate.relay_parent_number, + backed_in_number: candidate.backed_in_number, + backing_group: candidate.backing_group, + commitments, + }); + V1PendingAvailability::::insert(para_id, per_para); + + weight = weight.saturating_add(T::DbWeight::get().writes(1)); + } + } + + // should've already been drained by the above for loop, but as a sanity check, in case + // there are more commitments than candidates. + // V0PendingAvailabilityCommitments should not contain too many keys so removing + // everything at once should be safe + let res = V0PendingAvailabilityCommitments::::clear(u32::MAX, None); + weight = weight.saturating_add( + T::DbWeight::get().reads_writes(res.loops as u64, res.backend as u64), + ); + + // AvailabilityBitfields should not contain too many keys so removing everything at once + // should be safe. + let res = AvailabilityBitfields::::clear(u32::MAX, None); + weight = weight.saturating_add( + T::DbWeight::get().reads_writes(res.loops as u64, res.backend as u64), + ); + + weight + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + log::trace!(target: crate::inclusion::LOG_TARGET, "Running post_upgrade() for inclusion MigrateToV1"); + ensure!( + Pallet::::on_chain_storage_version() >= StorageVersion::new(1), + "Storage version should be >= 1 after the migration" + ); + + let candidates_before_upgrade = + u32::decode(&mut &state[..]).expect("Was properly encoded") as usize; + let candidates_after_upgrade = V1PendingAvailability::::iter().fold( + 0usize, + |mut acc, (_paraid, para_candidates)| { + acc += para_candidates.len(); + acc + }, + ); + + ensure!( + candidates_before_upgrade == candidates_after_upgrade, + "Number of pending candidates should be the same as the one before the upgrade." + ); + ensure!( + V0PendingAvailability::::iter().next() == None, + "Pending availability candidates storage v0 should have been removed" + ); + ensure!( + V0PendingAvailabilityCommitments::::iter().next() == None, + "Pending availability commitments storage should have been removed" + ); + ensure!( + AvailabilityBitfields::::iter().next() == None, + "Availability bitfields storage should have been removed" + ); + + Ok(()) + } + } + + /// Migrate to v1 inclusion module storage. + /// - merges the `PendingAvailabilityCommitments` into the `CandidatePendingAvailability` + /// storage + /// - removes the `AvailabilityBitfields` storage, which was never read. + pub type MigrateToV1 = frame_support::migrations::VersionedMigration< + 0, + 1, + VersionUncheckedMigrateToV1, + Pallet, + ::DbWeight, + >; +} + +#[cfg(test)] +mod tests { + use super::{v1::VersionUncheckedMigrateToV1, *}; + use crate::{ + inclusion::{ + CandidatePendingAvailability as V1CandidatePendingAvailability, + PendingAvailability as V1PendingAvailability, *, + }, + mock::{new_test_ext, MockGenesisConfig, Test}, + }; + use frame_support::traits::OnRuntimeUpgrade; + use primitives::{AvailabilityBitfield, Id as ParaId}; + use test_helpers::{dummy_candidate_commitments, dummy_candidate_descriptor, dummy_hash}; + + #[test] + fn migrate_to_v1() { + new_test_ext(MockGenesisConfig::default()).execute_with(|| { + // No data to migrate. + assert_eq!( + as OnRuntimeUpgrade>::on_runtime_upgrade(), + Weight::zero() + ); + assert!(V1PendingAvailability::::iter().next().is_none()); + + let mut expected = vec![]; + + for i in 1..5 { + let descriptor = dummy_candidate_descriptor(dummy_hash()); + v0::PendingAvailability::::insert( + ParaId::from(i), + v0::CandidatePendingAvailability { + core: CoreIndex(i), + descriptor: descriptor.clone(), + relay_parent_number: i, + hash: CandidateHash(dummy_hash()), + availability_votes: Default::default(), + backed_in_number: i, + backers: Default::default(), + backing_group: GroupIndex(i), + }, + ); + v0::PendingAvailabilityCommitments::::insert( + ParaId::from(i), + dummy_candidate_commitments(HeadData(vec![i as _])), + ); + + v0::AvailabilityBitfields::::insert( + ValidatorIndex(i), + v0::AvailabilityBitfieldRecord { + bitfield: AvailabilityBitfield(Default::default()), + submitted_at: i, + }, + ); + + expected.push(( + ParaId::from(i), + [V1CandidatePendingAvailability { + core: CoreIndex(i), + descriptor, + relay_parent_number: i, + hash: CandidateHash(dummy_hash()), + availability_votes: Default::default(), + backed_in_number: i, + backers: Default::default(), + backing_group: GroupIndex(i), + commitments: dummy_candidate_commitments(HeadData(vec![i as _])), + }] + .into_iter() + .collect::>(), + )); + } + // add some wrong data also, candidates without commitments or commitments without + // candidates. + v0::PendingAvailability::::insert( + ParaId::from(6), + v0::CandidatePendingAvailability { + core: CoreIndex(6), + descriptor: dummy_candidate_descriptor(dummy_hash()), + relay_parent_number: 6, + hash: CandidateHash(dummy_hash()), + availability_votes: Default::default(), + backed_in_number: 6, + backers: Default::default(), + backing_group: GroupIndex(6), + }, + ); + v0::PendingAvailabilityCommitments::::insert( + ParaId::from(7), + dummy_candidate_commitments(HeadData(vec![7 as _])), + ); + + // For tests, db weight is zero. + assert_eq!( + as OnRuntimeUpgrade>::on_runtime_upgrade(), + Weight::zero() + ); + + assert_eq!(v0::PendingAvailabilityCommitments::::iter().next(), None); + assert_eq!(v0::PendingAvailability::::iter().next(), None); + assert_eq!(v0::AvailabilityBitfields::::iter().next(), None); + + let mut actual = V1PendingAvailability::::iter().collect::>(); + actual.sort_by(|(id1, _), (id2, _)| id1.cmp(id2)); + expected.sort_by(|(id1, _), (id2, _)| id1.cmp(id2)); + + assert_eq!(actual, expected); + }); + } +} diff --git a/polkadot/runtime/parachains/src/inclusion/mod.rs b/polkadot/runtime/parachains/src/inclusion/mod.rs index 16e2e93b561..e77f8d15b40 100644 --- a/polkadot/runtime/parachains/src/inclusion/mod.rs +++ b/polkadot/runtime/parachains/src/inclusion/mod.rs @@ -23,31 +23,35 @@ use crate::{ configuration::{self, HostConfiguration}, disputes, dmp, hrmp, paras::{self, SetGoAhead}, - scheduler::{self, AvailabilityTimeoutStatus}, + scheduler, shared::{self, AllowedRelayParentsTracker}, + util::make_persisted_validation_data_with_parent, }; use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; use frame_support::{ defensive, pallet_prelude::*, - traits::{Defensive, EnqueueMessage, Footprint, QueueFootprint}, + traits::{EnqueueMessage, Footprint, QueueFootprint}, BoundedSlice, }; use frame_system::pallet_prelude::*; use pallet_message_queue::OnQueueChanged; use parity_scale_codec::{Decode, Encode}; use primitives::{ - effective_minimum_backing_votes, supermajority_threshold, well_known_keys, - AvailabilityBitfield, BackedCandidate, CandidateCommitments, CandidateDescriptor, - CandidateHash, CandidateReceipt, CommittedCandidateReceipt, CoreIndex, GroupIndex, Hash, - HeadData, Id as ParaId, SignedAvailabilityBitfields, SigningContext, UpwardMessage, - ValidatorId, ValidatorIndex, ValidityAttestation, + effective_minimum_backing_votes, supermajority_threshold, well_known_keys, BackedCandidate, + CandidateCommitments, CandidateDescriptor, CandidateHash, CandidateReceipt, + CommittedCandidateReceipt, CoreIndex, GroupIndex, Hash, HeadData, Id as ParaId, + SignedAvailabilityBitfields, SigningContext, UpwardMessage, ValidatorId, ValidatorIndex, + ValidityAttestation, }; use scale_info::TypeInfo; use sp_runtime::{traits::One, DispatchError, SaturatedConversion, Saturating}; #[cfg(feature = "std")] use sp_std::fmt; -use sp_std::{collections::btree_set::BTreeSet, prelude::*}; +use sp_std::{ + collections::{btree_map::BTreeMap, btree_set::BTreeSet, vec_deque::VecDeque}, + prelude::*, +}; pub use pallet::*; @@ -57,6 +61,8 @@ pub(crate) mod tests; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +pub mod migration; + pub trait WeightInfo { fn receive_upward_messages(i: u32) -> Weight; } @@ -80,20 +86,8 @@ impl WeightInfo for () { /// `configuration` pallet to check these values before setting. pub const MAX_UPWARD_MESSAGE_SIZE_BOUND: u32 = 128 * 1024; -/// A bitfield signed by a validator indicating that it is keeping its piece of the erasure-coding -/// for any backed candidates referred to by a `1` bit available. -/// -/// The bitfield's signature should be checked at the point of submission. Afterwards it can be -/// dropped. -#[derive(Encode, Decode, TypeInfo)] -#[cfg_attr(test, derive(Debug))] -pub struct AvailabilityBitfieldRecord { - bitfield: AvailabilityBitfield, // one bit per core. - submitted_at: N, // for accounting, as meaning of bits may change over time. -} - /// A backed candidate pending availability. -#[derive(Encode, Decode, PartialEq, TypeInfo)] +#[derive(Encode, Decode, PartialEq, TypeInfo, Clone)] #[cfg_attr(test, derive(Debug))] pub struct CandidatePendingAvailability { /// The availability core this is assigned to. @@ -102,6 +96,8 @@ pub struct CandidatePendingAvailability { hash: CandidateHash, /// The candidate descriptor. descriptor: CandidateDescriptor, + /// The candidate commitments. + commitments: CandidateCommitments, /// The received availability votes. One bit per validator. availability_votes: BitVec, /// The backers of the candidate pending availability. @@ -121,8 +117,11 @@ impl CandidatePendingAvailability { } /// Get the relay-chain block number this was backed in. - pub(crate) fn backed_in_number(&self) -> &N { - &self.backed_in_number + pub(crate) fn backed_in_number(&self) -> N + where + N: Clone, + { + self.backed_in_number.clone() } /// Get the core index. @@ -140,6 +139,11 @@ impl CandidatePendingAvailability { &self.descriptor } + /// Get the candidate commitments. + pub(crate) fn candidate_commitments(&self) -> &CandidateCommitments { + &self.commitments + } + /// Get the candidate's relay parent's number. pub(crate) fn relay_parent_number(&self) -> N where @@ -148,11 +152,22 @@ impl CandidatePendingAvailability { self.relay_parent_number.clone() } + /// Get the candidate backing group. + pub(crate) fn backing_group(&self) -> GroupIndex { + self.backing_group + } + + /// Get the candidate's backers. + pub(crate) fn backers(&self) -> &BitVec { + &self.backers + } + #[cfg(any(feature = "runtime-benchmarks", test))] pub(crate) fn new( core: CoreIndex, hash: CandidateHash, descriptor: CandidateDescriptor, + commitments: CandidateCommitments, availability_votes: BitVec, backers: BitVec, relay_parent_number: N, @@ -163,6 +178,7 @@ impl CandidatePendingAvailability { core, hash, descriptor, + commitments, availability_votes, backers, relay_parent_number, @@ -253,8 +269,10 @@ pub type MaxUmpMessageLenOf = pub mod pallet { use super::*; + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); #[pallet::pallet] #[pallet::without_storage_info] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); #[pallet::config] @@ -297,30 +315,10 @@ pub mod pallet { #[pallet::error] pub enum Error { - /// Validator indices are out of order or contains duplicates. - UnsortedOrDuplicateValidatorIndices, - /// Dispute statement sets are out of order or contain duplicates. - UnsortedOrDuplicateDisputeStatementSet, - /// Backed candidates are out of order (core index) or contain duplicates. - UnsortedOrDuplicateBackedCandidates, - /// A different relay parent was provided compared to the on-chain stored one. - UnexpectedRelayParent, - /// Availability bitfield has unexpected size. - WrongBitfieldSize, - /// Bitfield consists of zeros only. - BitfieldAllZeros, - /// Multiple bitfields submitted by same validator or validators out of order by index. - BitfieldDuplicateOrUnordered, /// Validator index out of bounds. ValidatorIndexOutOfBounds, - /// Invalid signature - InvalidBitfieldSignature, /// Candidate submitted but para not scheduled. UnscheduledCandidate, - /// Candidate scheduled despite pending candidate already existing for the para. - CandidateScheduledBeforeParaFree, - /// Scheduled cores out of order. - ScheduledOutOfOrder, /// Head data exceeds the configured maximum. HeadDataTooLarge, /// Code upgrade prematurely. @@ -356,31 +354,22 @@ pub mod pallet { /// The `para_head` hash in the candidate descriptor doesn't match the hash of the actual /// para head in the commitments. ParaHeadMismatch, - /// A bitfield that references a freed core, - /// either intentionally or as part of a concluded - /// invalid dispute. - BitfieldReferencesFreedCore, } - /// The latest bitfield for each validator, referred to by their index in the validator set. - #[pallet::storage] - pub(crate) type AvailabilityBitfields = - StorageMap<_, Twox64Concat, ValidatorIndex, AvailabilityBitfieldRecord>>; - - /// Candidates pending availability by `ParaId`. + /// Candidates pending availability by `ParaId`. They form a chain starting from the latest + /// included head of the para. + /// Use a different prefix post-migration to v1, since the v0 `PendingAvailability` storage + /// would otherwise have the exact same prefix which could cause undefined behaviour when doing + /// the migration. #[pallet::storage] + #[pallet::storage_prefix = "V1"] pub(crate) type PendingAvailability = StorageMap< _, Twox64Concat, ParaId, - CandidatePendingAvailability>, + VecDeque>>, >; - /// The commitments of candidates pending availability, by `ParaId`. - #[pallet::storage] - pub(crate) type PendingAvailabilityCommitments = - StorageMap<_, Twox64Concat, ParaId, CandidateCommitments>; - #[pallet::call] impl Pallet {} } @@ -469,9 +458,7 @@ impl Pallet { ) { // unlike most drain methods, drained elements are not cleared on `Drop` of the iterator // and require consumption. - for _ in >::drain() {} for _ in >::drain() {} - for _ in >::drain() {} Self::cleanup_outgoing_ump_dispatch_queues(outgoing_paras); } @@ -490,27 +477,18 @@ impl Pallet { /// /// Bitfields are expected to have been sanitized already. E.g. via `sanitize_bitfields`! /// - /// Updates storage items `PendingAvailability` and `AvailabilityBitfields`. + /// Updates storage items `PendingAvailability`. /// /// Returns a `Vec` of `CandidateHash`es and their respective `AvailabilityCore`s that became /// available, and cores free. - pub(crate) fn update_pending_availability_and_get_freed_cores( - expected_bits: usize, + pub(crate) fn update_pending_availability_and_get_freed_cores( validators: &[ValidatorId], signed_bitfields: SignedAvailabilityBitfields, - core_lookup: F, - ) -> Vec<(CoreIndex, CandidateHash)> - where - F: Fn(CoreIndex) -> Option, - { - let mut assigned_paras_record = (0..expected_bits) - .map(|bit_index| core_lookup(CoreIndex::from(bit_index as u32))) - .map(|opt_para_id| { - opt_para_id.map(|para_id| (para_id, PendingAvailability::::get(¶_id))) - }) - .collect::>(); + ) -> Vec<(CoreIndex, CandidateHash)> { + let threshold = availability_threshold(validators.len()); + + let mut votes_per_core: BTreeMap> = BTreeMap::new(); - let now = >::block_number(); for (checked_bitfield, validator_index) in signed_bitfields.into_iter().map(|signed_bitfield| { let validator_idx = signed_bitfield.validator_index(); @@ -518,310 +496,275 @@ impl Pallet { (checked_bitfield, validator_idx) }) { for (bit_idx, _) in checked_bitfield.0.iter().enumerate().filter(|(_, is_av)| **is_av) { - let pending_availability = if let Some((_, pending_availability)) = - assigned_paras_record[bit_idx].as_mut() - { - pending_availability - } else { - // For honest validators, this happens in case of unoccupied cores, - // which in turn happens in case of a disputed candidate. - // A malicious one might include arbitrary indices, but they are represented - // by `None` values and will be sorted out in the next if case. - continue - }; - - // defensive check - this is constructed by loading the availability bitfield - // record, which is always `Some` if the core is occupied - that's why we're here. - let validator_index = validator_index.0 as usize; - if let Some(mut bit) = - pending_availability.as_mut().and_then(|candidate_pending_availability| { - candidate_pending_availability.availability_votes.get_mut(validator_index) - }) { - *bit = true; - } + let core_index = CoreIndex(bit_idx as u32); + votes_per_core + .entry(core_index) + .or_insert_with(|| BTreeSet::new()) + .insert(validator_index); } - - let record = - AvailabilityBitfieldRecord { bitfield: checked_bitfield, submitted_at: now }; - - >::insert(&validator_index, record); } - let threshold = availability_threshold(validators.len()); + let mut freed_cores = vec![]; + + let pending_paraids: Vec<_> = >::iter_keys().collect(); + for paraid in pending_paraids { + >::mutate(paraid, |candidates| { + if let Some(candidates) = candidates { + let mut last_enacted_index: Option = None; + + for (candidate_index, candidate) in candidates.iter_mut().enumerate() { + if let Some(validator_indices) = votes_per_core.remove(&candidate.core) { + for validator_index in validator_indices.iter() { + // defensive check - this is constructed by loading the + // availability bitfield record, which is always `Some` if + // the core is occupied - that's why we're here. + if let Some(mut bit) = + candidate.availability_votes.get_mut(validator_index.0 as usize) + { + *bit = true; + } + } + } + + // We check for the candidate's availability even if we didn't get any new + // bitfields for its core, as it may have already been available at a + // previous block but wasn't enacted due to its predecessors not being + // available. + if candidate.availability_votes.count_ones() >= threshold { + // We can only enact a candidate if we've enacted all of its + // predecessors already. + let can_enact = if candidate_index == 0 { + last_enacted_index == None + } else { + let prev_candidate_index = usize::try_from(candidate_index - 1) + .expect("Previous `if` would have caught a 0 candidate index."); + matches!(last_enacted_index, Some(old_index) if old_index == prev_candidate_index) + }; + + if can_enact { + last_enacted_index = Some(candidate_index); + } + } + } - let mut freed_cores = Vec::with_capacity(expected_bits); - for (para_id, pending_availability) in assigned_paras_record - .into_iter() - .flatten() - .filter_map(|(id, p)| p.map(|p| (id, p))) - { - if pending_availability.availability_votes.count_ones() >= threshold { - >::remove(¶_id); - let commitments = match PendingAvailabilityCommitments::::take(¶_id) { - Some(commitments) => commitments, - None => { - log::warn!( - target: LOG_TARGET, - "Inclusion::process_bitfields: PendingAvailability and PendingAvailabilityCommitments - are out of sync, did someone mess with the storage?", - ); - continue - }, - }; - - let receipt = CommittedCandidateReceipt { - descriptor: pending_availability.descriptor, - commitments, - }; - let _weight = Self::enact_candidate( - pending_availability.relay_parent_number, - receipt, - pending_availability.backers, - pending_availability.availability_votes, - pending_availability.core, - pending_availability.backing_group, - ); - - freed_cores.push((pending_availability.core, pending_availability.hash)); - } else { - >::insert(¶_id, &pending_availability); - } + // Trim the pending availability candidates storage and enact candidates of this + // para now. + if let Some(last_enacted_index) = last_enacted_index { + let evicted_candidates = candidates.drain(0..=last_enacted_index); + for candidate in evicted_candidates { + freed_cores.push((candidate.core, candidate.hash)); + + let receipt = CommittedCandidateReceipt { + descriptor: candidate.descriptor, + commitments: candidate.commitments, + }; + let _weight = Self::enact_candidate( + candidate.relay_parent_number, + receipt, + candidate.backers, + candidate.availability_votes, + candidate.core, + candidate.backing_group, + ); + } + } + } + }); } freed_cores } - /// Process candidates that have been backed. Provide the relay storage root, a set of - /// candidates and scheduled cores. + /// Process candidates that have been backed. Provide a set of + /// candidates along with their scheduled cores. /// - /// Both should be sorted ascending by core index, and the candidates should be a subset of - /// scheduled cores. If these conditions are not met, the execution of the function fails. + /// Candidates of the same paraid should be sorted according to their dependency order (they + /// should form a chain). If this condition is not met, this function will return an error. + /// (This really should not happen here, if the candidates were properly sanitised in + /// paras_inherent). pub(crate) fn process_candidates( allowed_relay_parents: &AllowedRelayParentsTracker>, - candidates: Vec<(BackedCandidate, CoreIndex)>, + candidates: &BTreeMap, CoreIndex)>>, group_validators: GV, core_index_enabled: bool, ) -> Result, DispatchError> where GV: Fn(GroupIndex) -> Option>, { - let now = >::block_number(); - if candidates.is_empty() { return Ok(ProcessedCandidates::default()) } - let minimum_backing_votes = configuration::Pallet::::config().minimum_backing_votes; + let now = >::block_number(); let validators = shared::Pallet::::active_validator_keys(); // Collect candidate receipts with backers. let mut candidate_receipt_with_backing_validator_indices = Vec::with_capacity(candidates.len()); + let mut core_indices = Vec::with_capacity(candidates.len()); - // Do all checks before writing storage. - let core_indices_and_backers = { - let mut core_indices_and_backers = Vec::with_capacity(candidates.len()); - let mut last_core = None; - - let mut check_assignment_in_order = |core_idx| -> DispatchResult { - ensure!( - last_core.map_or(true, |core| core_idx > core), - Error::::ScheduledOutOfOrder, - ); - - last_core = Some(core_idx); - Ok(()) + for (para_id, para_candidates) in candidates { + let mut latest_head_data = match Self::para_latest_head_data(para_id) { + None => { + defensive!("Latest included head data for paraid {:?} is None", para_id); + continue + }, + Some(latest_head_data) => latest_head_data, }; - // We combine an outer loop over candidates with an inner loop over the scheduled, - // where each iteration of the outer loop picks up at the position - // in scheduled just after the past iteration left off. - // - // If the candidates appear in the same order as they appear in `scheduled`, - // then they should always be found. If the end of `scheduled` is reached, - // then the candidate was either not scheduled or out-of-order. - // - // In the meantime, we do certain sanity checks on the candidates and on the scheduled - // list. - for (candidate_idx, (backed_candidate, core_index)) in candidates.iter().enumerate() { - let relay_parent_hash = backed_candidate.descriptor().relay_parent; - let para_id = backed_candidate.descriptor().para_id; - - let prev_context = >::para_most_recent_context(para_id); - - let check_ctx = CandidateCheckContext::::new(prev_context); - let signing_context = SigningContext { - parent_hash: relay_parent_hash, - session_index: shared::Pallet::::session_index(), - }; - - let relay_parent_number = match check_ctx.verify_backed_candidate( + for (candidate, core) in para_candidates.iter() { + let candidate_hash = candidate.candidate().hash(); + + let check_ctx = CandidateCheckContext::::new(None); + let relay_parent_number = check_ctx.verify_backed_candidate( &allowed_relay_parents, - candidate_idx, - backed_candidate.candidate(), - )? { - Err(FailedToCreatePVD) => { - log::debug!( - target: LOG_TARGET, - "Failed to create PVD for candidate {}", - candidate_idx, - ); - // We don't want to error out here because it will - // brick the relay-chain. So we return early without - // doing anything. - return Ok(ProcessedCandidates::default()) - }, - Ok(rpn) => rpn, - }; - - let (validator_indices, _) = - backed_candidate.validator_indices_and_core_index(core_index_enabled); - - log::debug!( - target: LOG_TARGET, - "Candidate {:?} on {:?}, - core_index_enabled = {}", - backed_candidate.hash(), - core_index, - core_index_enabled - ); - - check_assignment_in_order(core_index)?; - - let mut backers = bitvec::bitvec![u8, BitOrderLsb0; 0; validators.len()]; - - ensure!( - >::get(¶_id).is_none() && - >::get(¶_id).is_none(), - Error::::CandidateScheduledBeforeParaFree, - ); - - // The candidate based upon relay parent `N` should be backed by a group - // assigned to core at block `N + 1`. Thus, `relay_parent_number + 1` - // will always land in the current session. + candidate.candidate(), + latest_head_data.clone(), + )?; + + // The candidate based upon relay parent `N` should be backed by a + // group assigned to core at block `N + 1`. Thus, + // `relay_parent_number + 1` will always land in the current + // session. let group_idx = >::group_assigned_to_core( - *core_index, + *core, relay_parent_number + One::one(), ) .ok_or_else(|| { log::warn!( target: LOG_TARGET, - "Failed to compute group index for candidate {}", - candidate_idx + "Failed to compute group index for candidate {:?}", + candidate_hash ); Error::::InvalidAssignment })?; let group_vals = group_validators(group_idx).ok_or_else(|| Error::::InvalidGroupIndex)?; - // check the signatures in the backing and that it is a majority. - { - let maybe_amount_validated = primitives::check_candidate_backing( - backed_candidate.candidate().hash(), - backed_candidate.validity_votes(), - validator_indices, - &signing_context, - group_vals.len(), - |intra_group_vi| { - group_vals - .get(intra_group_vi) - .and_then(|vi| validators.get(vi.0 as usize)) - .map(|v| v.clone()) - }, - ); - - match maybe_amount_validated { - Ok(amount_validated) => ensure!( - amount_validated >= - effective_minimum_backing_votes( - group_vals.len(), - minimum_backing_votes - ), - Error::::InsufficientBacking, - ), - Err(()) => { - Err(Error::::InvalidBacking)?; - }, - } - - let mut backer_idx_and_attestation = - Vec::<(ValidatorIndex, ValidityAttestation)>::with_capacity( - validator_indices.count_ones(), - ); - let candidate_receipt = backed_candidate.receipt(); - - for ((bit_idx, _), attestation) in validator_indices - .iter() - .enumerate() - .filter(|(_, signed)| **signed) - .zip(backed_candidate.validity_votes().iter().cloned()) - { - let val_idx = - group_vals.get(bit_idx).expect("this query succeeded above; qed"); - backer_idx_and_attestation.push((*val_idx, attestation)); - - backers.set(val_idx.0 as _, true); + // Check backing vote count and validity. + let (backers, backer_idx_and_attestation) = Self::check_backing_votes( + candidate, + &validators, + group_vals, + core_index_enabled, + )?; + + // Found a valid candidate. + latest_head_data = candidate.candidate().commitments.head_data.clone(); + candidate_receipt_with_backing_validator_indices + .push((candidate.receipt(), backer_idx_and_attestation)); + core_indices.push((*core, *para_id)); + + // Update storage now + >::mutate(¶_id, |pending_availability| { + let new_candidate = CandidatePendingAvailability { + core: *core, + hash: candidate_hash, + descriptor: candidate.candidate().descriptor.clone(), + commitments: candidate.candidate().commitments.clone(), + // initialize all availability votes to 0. + availability_votes: bitvec::bitvec![u8, BitOrderLsb0; 0; validators.len()], + relay_parent_number, + backers: backers.to_bitvec(), + backed_in_number: now, + backing_group: group_idx, + }; + + if let Some(pending_availability) = pending_availability { + pending_availability.push_back(new_candidate); + } else { + *pending_availability = + Some([new_candidate].into_iter().collect::>()) } - candidate_receipt_with_backing_validator_indices - .push((candidate_receipt, backer_idx_and_attestation)); - } + }); - core_indices_and_backers.push(( - (*core_index, para_id), - backers, + // Deposit backed event. + Self::deposit_event(Event::::CandidateBacked( + candidate.candidate().to_plain(), + candidate.candidate().commitments.head_data.clone(), + *core, group_idx, - relay_parent_number, )); } + } - core_indices_and_backers - }; + Ok(ProcessedCandidates:: { + core_indices, + candidate_receipt_with_backing_validator_indices, + }) + } - // one more sweep for actually writing to storage. - let core_indices = core_indices_and_backers.iter().map(|(c, ..)| *c).collect(); - for ((candidate, _), (core, backers, group, relay_parent_number)) in - candidates.into_iter().zip(core_indices_and_backers) - { - let para_id = candidate.descriptor().para_id; + // Get the latest backed output head data of this para. + pub(crate) fn para_latest_head_data(para_id: &ParaId) -> Option { + match >::get(para_id).and_then(|pending_candidates| { + pending_candidates.back().map(|x| x.commitments.head_data.clone()) + }) { + Some(head_data) => Some(head_data), + None => >::para_head(para_id), + } + } - // initialize all availability votes to 0. - let availability_votes: BitVec = - bitvec::bitvec![u8, BitOrderLsb0; 0; validators.len()]; + fn check_backing_votes( + backed_candidate: &BackedCandidate, + validators: &[ValidatorId], + group_vals: Vec, + core_index_enabled: bool, + ) -> Result<(BitVec, Vec<(ValidatorIndex, ValidityAttestation)>), Error> { + let minimum_backing_votes = configuration::Pallet::::config().minimum_backing_votes; - Self::deposit_event(Event::::CandidateBacked( - candidate.candidate().to_plain(), - candidate.candidate().commitments.head_data.clone(), - core.0, - group, - )); + let mut backers = bitvec::bitvec![u8, BitOrderLsb0; 0; validators.len()]; + let signing_context = SigningContext { + parent_hash: backed_candidate.descriptor().relay_parent, + session_index: shared::Pallet::::session_index(), + }; - let candidate_hash = candidate.candidate().hash(); + let (validator_indices, _) = + backed_candidate.validator_indices_and_core_index(core_index_enabled); + + // check the signatures in the backing and that it is a majority. + let maybe_amount_validated = primitives::check_candidate_backing( + backed_candidate.candidate().hash(), + backed_candidate.validity_votes(), + validator_indices, + &signing_context, + group_vals.len(), + |intra_group_vi| { + group_vals + .get(intra_group_vi) + .and_then(|vi| validators.get(vi.0 as usize)) + .map(|v| v.clone()) + }, + ); - let (descriptor, commitments) = ( - candidate.candidate().descriptor.clone(), - candidate.candidate().commitments.clone(), - ); + match maybe_amount_validated { + Ok(amount_validated) => ensure!( + amount_validated >= + effective_minimum_backing_votes(group_vals.len(), minimum_backing_votes), + Error::::InsufficientBacking, + ), + Err(()) => { + Err(Error::::InvalidBacking)?; + }, + } - >::insert( - ¶_id, - CandidatePendingAvailability { - core: core.0, - hash: candidate_hash, - descriptor, - availability_votes, - relay_parent_number, - backers: backers.to_bitvec(), - backed_in_number: now, - backing_group: group, - }, + let mut backer_idx_and_attestation = + Vec::<(ValidatorIndex, ValidityAttestation)>::with_capacity( + validator_indices.count_ones(), ); - >::insert(¶_id, commitments); + + for ((bit_idx, _), attestation) in validator_indices + .iter() + .enumerate() + .filter(|(_, signed)| **signed) + .zip(backed_candidate.validity_votes().iter().cloned()) + { + let val_idx = group_vals.get(bit_idx).expect("this query succeeded above; qed"); + backer_idx_and_attestation.push((*val_idx, attestation)); + + backers.set(val_idx.0 as _, true); } - Ok(ProcessedCandidates:: { - core_indices, - candidate_receipt_with_backing_validator_indices, - }) + Ok((backers, backer_idx_and_attestation)) } /// Run the acceptance criteria checks on the given candidate commitments. @@ -1028,110 +971,155 @@ impl Pallet { weight } - /// Cleans up all paras pending availability that the predicate returns true for. - /// - /// The predicate accepts the index of the core and the block number the core has been occupied - /// since (i.e. the block number the candidate was backed at in this fork of the relay chain). + /// Cleans up all timed out candidates as well as their descendant candidates. /// /// Returns a vector of cleaned-up core IDs. - pub(crate) fn collect_pending( - pred: impl Fn(BlockNumberFor) -> AvailabilityTimeoutStatus>, - ) -> Vec { - let mut cleaned_up_ids = Vec::new(); - let mut cleaned_up_cores = Vec::new(); - - for (para_id, pending_record) in >::iter() { - if pred(pending_record.backed_in_number).timed_out { - cleaned_up_ids.push(para_id); - cleaned_up_cores.push(pending_record.core); - } - } - - for para_id in cleaned_up_ids { - let pending = >::take(¶_id); - let commitments = >::take(¶_id); - - if let (Some(pending), Some(commitments)) = (pending, commitments) { - // defensive: this should always be true. - let candidate = CandidateReceipt { - descriptor: pending.descriptor, - commitments_hash: commitments.hash(), - }; + pub(crate) fn free_timedout() -> Vec { + let timeout_pred = >::availability_timeout_predicate(); + + let timed_out: Vec<_> = Self::free_failed_cores( + |candidate| timeout_pred(candidate.backed_in_number).timed_out, + None, + ) + .collect(); + + let mut timed_out_cores = Vec::with_capacity(timed_out.len()); + for candidate in timed_out.iter() { + timed_out_cores.push(candidate.core); + + let receipt = CandidateReceipt { + descriptor: candidate.descriptor.clone(), + commitments_hash: candidate.commitments.hash(), + }; - Self::deposit_event(Event::::CandidateTimedOut( - candidate, - commitments.head_data, - pending.core, - )); - } + Self::deposit_event(Event::::CandidateTimedOut( + receipt, + candidate.commitments.head_data.clone(), + candidate.core, + )); } - cleaned_up_cores + timed_out_cores } - /// Cleans up all paras pending availability that are in the given list of disputed candidates. + /// Cleans up all cores pending availability occupied by one of the disputed candidates or which + /// are descendants of a disputed candidate. /// - /// Returns a vector of cleaned-up core IDs. - pub(crate) fn collect_disputed(disputed: &BTreeSet) -> Vec { - let mut cleaned_up_ids = Vec::new(); - let mut cleaned_up_cores = Vec::new(); - - for (para_id, pending_record) in >::iter() { - if disputed.contains(&pending_record.hash) { - cleaned_up_ids.push(para_id); - cleaned_up_cores.push(pending_record.core); + /// Returns a vector of cleaned-up core IDs, along with the evicted candidate hashes. + pub(crate) fn free_disputed( + disputed: &BTreeSet, + ) -> Vec<(CoreIndex, CandidateHash)> { + Self::free_failed_cores( + |candidate| disputed.contains(&candidate.hash), + Some(disputed.len()), + ) + .map(|candidate| (candidate.core, candidate.hash)) + .collect() + } + + // Clean up cores whose candidates are deemed as failed by the predicate. `pred` returns true if + // a candidate is considered failed. + // A failed candidate also frees all subsequent cores which hold descendants of said candidate. + fn free_failed_cores< + P: Fn(&CandidatePendingAvailability>) -> bool, + >( + pred: P, + capacity_hint: Option, + ) -> impl Iterator>> { + let mut earliest_dropped_indices: BTreeMap = BTreeMap::new(); + + for (para_id, pending_candidates) in >::iter() { + // We assume that pending candidates are stored in dependency order. So we need to store + // the earliest dropped candidate. All others that follow will get freed as well. + let mut earliest_dropped_idx = None; + for (index, candidate) in pending_candidates.iter().enumerate() { + if pred(candidate) { + earliest_dropped_idx = Some(index); + // Since we're looping the candidates in dependency order, we've found the + // earliest failed index for this paraid. + break; + } + } + + if let Some(earliest_dropped_idx) = earliest_dropped_idx { + earliest_dropped_indices.insert(para_id, earliest_dropped_idx); } } - for para_id in cleaned_up_ids { - let _ = >::take(¶_id); - let _ = >::take(¶_id); + let mut cleaned_up_cores = + if let Some(capacity) = capacity_hint { Vec::with_capacity(capacity) } else { vec![] }; + + for (para_id, earliest_dropped_idx) in earliest_dropped_indices { + // Do cleanups and record the cleaned up cores + >::mutate(¶_id, |record| { + if let Some(record) = record { + let cleaned_up = record.drain(earliest_dropped_idx..); + cleaned_up_cores.extend(cleaned_up); + } + }); } - cleaned_up_cores + cleaned_up_cores.into_iter() } - /// Forcibly enact the candidate with the given ID as though it had been deemed available - /// by bitfields. + /// Forcibly enact the pending candidates of the given paraid as though they had been deemed + /// available by bitfields. /// /// Is a no-op if there is no candidate pending availability for this para-id. - /// This should generally not be used but it is useful during execution of Runtime APIs, + /// If there are multiple candidates pending availability for this para-id, it will enact all of + /// them. This should generally not be used but it is useful during execution of Runtime APIs, /// where the changes to the state are expected to be discarded directly after. pub(crate) fn force_enact(para: ParaId) { - let pending = >::take(¶); - let commitments = >::take(¶); - - if let (Some(pending), Some(commitments)) = (pending, commitments) { - let candidate = - CommittedCandidateReceipt { descriptor: pending.descriptor, commitments }; - - Self::enact_candidate( - pending.relay_parent_number, - candidate, - pending.backers, - pending.availability_votes, - pending.core, - pending.backing_group, - ); - } + >::mutate(¶, |candidates| { + if let Some(candidates) = candidates { + for candidate in candidates.drain(..) { + let receipt = CommittedCandidateReceipt { + descriptor: candidate.descriptor, + commitments: candidate.commitments, + }; + + Self::enact_candidate( + candidate.relay_parent_number, + receipt, + candidate.backers, + candidate.availability_votes, + candidate.core, + candidate.backing_group, + ); + } + } + }); } - /// Returns the `CommittedCandidateReceipt` pending availability for the para provided, if any. + /// Returns the first `CommittedCandidateReceipt` pending availability for the para provided, if + /// any. pub(crate) fn candidate_pending_availability( para: ParaId, ) -> Option> { - >::get(¶) - .map(|p| p.descriptor) - .and_then(|d| >::get(¶).map(move |c| (d, c))) - .map(|(d, c)| CommittedCandidateReceipt { descriptor: d, commitments: c }) + >::get(¶).and_then(|p| { + p.get(0).map(|p| CommittedCandidateReceipt { + descriptor: p.descriptor.clone(), + commitments: p.commitments.clone(), + }) + }) } - /// Returns the metadata around the candidate pending availability for the + /// Returns the metadata around the first candidate pending availability for the /// para provided, if any. pub(crate) fn pending_availability( para: ParaId, + ) -> Option>> { + >::get(¶).and_then(|p| p.get(0).cloned()) + } + + /// Returns the metadata around the candidate pending availability occupying the supplied core, + /// if any. + pub(crate) fn pending_availability_with_core( + para: ParaId, + core: CoreIndex, ) -> Option>> { >::get(¶) + .and_then(|p| p.iter().find(|c| c.core == core).cloned()) } } @@ -1182,10 +1170,6 @@ pub(crate) struct CandidateCheckContext { prev_context: Option>, } -/// An error indicating that creating Persisted Validation Data failed -/// while checking a candidate's validity. -pub(crate) struct FailedToCreatePVD; - impl CandidateCheckContext { pub(crate) fn new(prev_context: Option>) -> Self { Self { config: >::config(), prev_context } @@ -1203,9 +1187,9 @@ impl CandidateCheckContext { pub(crate) fn verify_backed_candidate( &self, allowed_relay_parents: &AllowedRelayParentsTracker>, - candidate_idx: usize, backed_candidate_receipt: &CommittedCandidateReceipt<::Hash>, - ) -> Result, FailedToCreatePVD>, Error> { + parent_head_data: HeadData, + ) -> Result, Error> { let para_id = backed_candidate_receipt.descriptor().para_id; let relay_parent = backed_candidate_receipt.descriptor().relay_parent; @@ -1218,16 +1202,11 @@ impl CandidateCheckContext { }; { - let persisted_validation_data = match crate::util::make_persisted_validation_data::( - para_id, + let persisted_validation_data = make_persisted_validation_data_with_parent::( relay_parent_number, relay_parent_storage_root, - ) - .defensive_proof("the para is registered") - { - Some(l) => l, - None => return Ok(Err(FailedToCreatePVD)), - }; + parent_head_data, + ); let expected = persisted_validation_data.hash(); @@ -1268,13 +1247,13 @@ impl CandidateCheckContext { ) { log::debug!( target: LOG_TARGET, - "Validation outputs checking during inclusion of a candidate {} for parachain `{}` failed", - candidate_idx, + "Validation outputs checking during inclusion of a candidate {:?} for parachain `{}` failed", + backed_candidate_receipt.hash(), u32::from(para_id), ); Err(err.strip_into_dispatch_err::())?; }; - Ok(Ok(relay_parent_number)) + Ok(relay_parent_number) } /// Check the given outputs after candidate validation on whether it passes the acceptance diff --git a/polkadot/runtime/parachains/src/inclusion/tests.rs b/polkadot/runtime/parachains/src/inclusion/tests.rs index 3fe7d7f0c7d..5ab3a13324d 100644 --- a/polkadot/runtime/parachains/src/inclusion/tests.rs +++ b/polkadot/runtime/parachains/src/inclusion/tests.rs @@ -27,7 +27,7 @@ use crate::{ shared::AllowedRelayParentsTracker, }; use primitives::{ - effective_minimum_backing_votes, SignedAvailabilityBitfields, + effective_minimum_backing_votes, AvailabilityBitfield, SignedAvailabilityBitfields, UncheckedSignedAvailabilityBitfields, }; @@ -360,81 +360,288 @@ fn simple_sanitize_bitfields( } /// Process a set of already sanitized bitfields. pub(crate) fn process_bitfields( - expected_bits: usize, signed_bitfields: SignedAvailabilityBitfields, - core_lookup: impl Fn(CoreIndex) -> Option, ) -> Vec<(CoreIndex, CandidateHash)> { let validators = shared::Pallet::::active_validator_keys(); - ParaInclusion::update_pending_availability_and_get_freed_cores::<_>( - expected_bits, + ParaInclusion::update_pending_availability_and_get_freed_cores( &validators[..], signed_bitfields, - core_lookup, ) } #[test] -fn collect_pending_cleans_up_pending() { +fn free_timedout() { let chain_a = ParaId::from(1_u32); let chain_b = ParaId::from(2_u32); - let thread_a = ParaId::from(3_u32); + let chain_c = ParaId::from(3_u32); + let chain_d = ParaId::from(4_u32); + let chain_e = ParaId::from(5_u32); + let chain_f = ParaId::from(6_u32); + let thread_a = ParaId::from(7_u32); let paras = vec![ (chain_a, ParaKind::Parachain), (chain_b, ParaKind::Parachain), + (chain_c, ParaKind::Parachain), + (chain_d, ParaKind::Parachain), + (chain_e, ParaKind::Parachain), + (chain_f, ParaKind::Parachain), (thread_a, ParaKind::Parathread), ]; let mut config = genesis_config(paras); config.configuration.config.scheduler_params.group_rotation_frequency = 3; new_test_ext(config).execute_with(|| { - let default_candidate = TestCandidateBuilder::default().build(); - >::insert( - chain_a, + let timed_out_cores = ParaInclusion::free_timedout(); + assert!(timed_out_cores.is_empty()); + + let make_candidate = |core_index: u32, timed_out: bool| { + let default_candidate = TestCandidateBuilder::default().build(); + let backed_in_number = if timed_out { 0 } else { 5 }; + CandidatePendingAvailability { - core: CoreIndex::from(0), + core: CoreIndex::from(core_index), hash: default_candidate.hash(), descriptor: default_candidate.descriptor.clone(), availability_votes: default_availability_votes(), relay_parent_number: 0, - backed_in_number: 0, + backed_in_number, backers: default_backing_bitfield(), - backing_group: GroupIndex::from(0), - }, - ); - PendingAvailabilityCommitments::::insert( + backing_group: GroupIndex::from(core_index), + commitments: default_candidate.commitments.clone(), + } + }; + + >::insert( chain_a, - default_candidate.commitments.clone(), + [make_candidate(0, true)].into_iter().collect::>(), ); >::insert( &chain_b, + [make_candidate(1, false)].into_iter().collect::>(), + ); + + // 2 chained candidates. The first one is timed out. The other will be evicted also. + let mut c_candidates = VecDeque::new(); + c_candidates.push_back(make_candidate(2, true)); + c_candidates.push_back(make_candidate(3, false)); + + >::insert(&chain_c, c_candidates); + + // 2 chained candidates. All are timed out. + let mut d_candidates = VecDeque::new(); + d_candidates.push_back(make_candidate(4, true)); + d_candidates.push_back(make_candidate(5, true)); + + >::insert(&chain_d, d_candidates); + + // 3 chained candidates. The second one is timed out. The first one will remain in place. + // With the current time out predicate this scenario is impossible. But this is not a + // concern for this module. + let mut e_candidates = VecDeque::new(); + e_candidates.push_back(make_candidate(6, false)); + e_candidates.push_back(make_candidate(7, true)); + e_candidates.push_back(make_candidate(8, false)); + + >::insert(&chain_e, e_candidates); + + // 3 chained candidates, none are timed out. + let mut f_candidates = VecDeque::new(); + f_candidates.push_back(make_candidate(9, false)); + f_candidates.push_back(make_candidate(10, false)); + f_candidates.push_back(make_candidate(11, false)); + + >::insert(&chain_f, f_candidates); + + run_to_block(5, |_| None); + + assert_eq!(>::get(&chain_a).unwrap().len(), 1); + assert_eq!(>::get(&chain_b).unwrap().len(), 1); + assert_eq!(>::get(&chain_c).unwrap().len(), 2); + assert_eq!(>::get(&chain_d).unwrap().len(), 2); + assert_eq!(>::get(&chain_e).unwrap().len(), 3); + assert_eq!(>::get(&chain_f).unwrap().len(), 3); + + let timed_out_cores = ParaInclusion::free_timedout(); + + assert_eq!( + timed_out_cores, + vec![ + CoreIndex(0), + CoreIndex(2), + CoreIndex(3), + CoreIndex(4), + CoreIndex(5), + CoreIndex(7), + CoreIndex(8), + ] + ); + + assert!(>::get(&chain_a).unwrap().is_empty()); + assert_eq!(>::get(&chain_b).unwrap().len(), 1); + assert!(>::get(&chain_c).unwrap().is_empty()); + assert!(>::get(&chain_d).unwrap().is_empty()); + assert_eq!( + >::get(&chain_e) + .unwrap() + .into_iter() + .map(|c| c.core) + .collect::>(), + vec![CoreIndex(6)] + ); + assert_eq!( + >::get(&chain_f) + .unwrap() + .into_iter() + .map(|c| c.core) + .collect::>(), + vec![CoreIndex(9), CoreIndex(10), CoreIndex(11)] + ); + }); +} + +#[test] +fn free_disputed() { + let chain_a = ParaId::from(1_u32); + let chain_b = ParaId::from(2_u32); + let chain_c = ParaId::from(3_u32); + let chain_d = ParaId::from(4_u32); + let chain_e = ParaId::from(5_u32); + let chain_f = ParaId::from(6_u32); + let thread_a = ParaId::from(7_u32); + + let paras = vec![ + (chain_a, ParaKind::Parachain), + (chain_b, ParaKind::Parachain), + (chain_c, ParaKind::Parachain), + (chain_d, ParaKind::Parachain), + (chain_e, ParaKind::Parachain), + (chain_f, ParaKind::Parachain), + (thread_a, ParaKind::Parathread), + ]; + let mut config = genesis_config(paras); + config.configuration.config.scheduler_params.group_rotation_frequency = 3; + new_test_ext(config).execute_with(|| { + let disputed_cores = ParaInclusion::free_disputed(&BTreeSet::new()); + assert!(disputed_cores.is_empty()); + + let disputed_cores = ParaInclusion::free_disputed( + &[CandidateHash::default()].into_iter().collect::>(), + ); + assert!(disputed_cores.is_empty()); + + let make_candidate = |core_index: u32| { + let default_candidate = TestCandidateBuilder::default().build(); + CandidatePendingAvailability { - core: CoreIndex::from(1), - hash: default_candidate.hash(), - descriptor: default_candidate.descriptor, + core: CoreIndex::from(core_index), + hash: CandidateHash(Hash::from_low_u64_be(core_index as _)), + descriptor: default_candidate.descriptor.clone(), availability_votes: default_availability_votes(), relay_parent_number: 0, - backed_in_number: 5, + backed_in_number: 0, backers: default_backing_bitfield(), - backing_group: GroupIndex::from(1), - }, + backing_group: GroupIndex::from(core_index), + commitments: default_candidate.commitments.clone(), + } + }; + + // Disputed + >::insert( + chain_a, + [make_candidate(0)].into_iter().collect::>(), + ); + + // Not disputed. + >::insert( + &chain_b, + [make_candidate(1)].into_iter().collect::>(), ); - PendingAvailabilityCommitments::::insert(chain_b, default_candidate.commitments); + + // 2 chained candidates. The first one is disputed. The other will be evicted also. + let mut c_candidates = VecDeque::new(); + c_candidates.push_back(make_candidate(2)); + c_candidates.push_back(make_candidate(3)); + + >::insert(&chain_c, c_candidates); + + // 2 chained candidates. All are disputed. + let mut d_candidates = VecDeque::new(); + d_candidates.push_back(make_candidate(4)); + d_candidates.push_back(make_candidate(5)); + + >::insert(&chain_d, d_candidates); + + // 3 chained candidates. The second one is disputed. The first one will remain in place. + let mut e_candidates = VecDeque::new(); + e_candidates.push_back(make_candidate(6)); + e_candidates.push_back(make_candidate(7)); + e_candidates.push_back(make_candidate(8)); + + >::insert(&chain_e, e_candidates); + + // 3 chained candidates, none are disputed. + let mut f_candidates = VecDeque::new(); + f_candidates.push_back(make_candidate(9)); + f_candidates.push_back(make_candidate(10)); + f_candidates.push_back(make_candidate(11)); + + >::insert(&chain_f, f_candidates); run_to_block(5, |_| None); - assert!(>::get(&chain_a).is_some()); - assert!(>::get(&chain_b).is_some()); - assert!(>::get(&chain_a).is_some()); - assert!(>::get(&chain_b).is_some()); + assert_eq!(>::get(&chain_a).unwrap().len(), 1); + assert_eq!(>::get(&chain_b).unwrap().len(), 1); + assert_eq!(>::get(&chain_c).unwrap().len(), 2); + assert_eq!(>::get(&chain_d).unwrap().len(), 2); + assert_eq!(>::get(&chain_e).unwrap().len(), 3); + assert_eq!(>::get(&chain_f).unwrap().len(), 3); + + let disputed_candidates = [ + CandidateHash(Hash::from_low_u64_be(0)), + CandidateHash(Hash::from_low_u64_be(2)), + CandidateHash(Hash::from_low_u64_be(4)), + CandidateHash(Hash::from_low_u64_be(5)), + CandidateHash(Hash::from_low_u64_be(7)), + ] + .into_iter() + .collect::>(); + let disputed_cores = ParaInclusion::free_disputed(&disputed_candidates); - ParaInclusion::collect_pending(Scheduler::availability_timeout_predicate()); + assert_eq!( + disputed_cores.into_iter().map(|(core, _)| core).collect::>(), + vec![ + CoreIndex(0), + CoreIndex(2), + CoreIndex(3), + CoreIndex(4), + CoreIndex(5), + CoreIndex(7), + CoreIndex(8), + ] + ); - assert!(>::get(&chain_a).is_none()); - assert!(>::get(&chain_b).is_some()); - assert!(>::get(&chain_a).is_none()); - assert!(>::get(&chain_b).is_some()); + assert!(>::get(&chain_a).unwrap().is_empty()); + assert_eq!(>::get(&chain_b).unwrap().len(), 1); + assert!(>::get(&chain_c).unwrap().is_empty()); + assert!(>::get(&chain_d).unwrap().is_empty()); + assert_eq!( + >::get(&chain_e) + .unwrap() + .into_iter() + .map(|c| c.core) + .collect::>(), + vec![CoreIndex(6)] + ); + assert_eq!( + >::get(&chain_f) + .unwrap() + .into_iter() + .map(|c| c.core) + .collect::>(), + vec![CoreIndex(9), CoreIndex(10), CoreIndex(11)] + ); }); } @@ -474,14 +681,6 @@ fn bitfield_checks() { let signing_context = SigningContext { parent_hash: System::parent_hash(), session_index: 5 }; - let core_lookup = |core| match core { - core if core == CoreIndex::from(0) => Some(chain_a), - core if core == CoreIndex::from(1) => Some(chain_b), - core if core == CoreIndex::from(2) => Some(thread_a), - core if core == CoreIndex::from(3) => None, // for the expected_cores() + 1 test below. - _ => panic!("out of bounds for testing"), - }; - // too many bits in bitfield { let mut bare_bitfield = default_bitfield(); @@ -550,7 +749,7 @@ fn bitfield_checks() { ); assert_eq!(checked_bitfields.len(), 1, "No bitfields should have been filtered!"); - let x = process_bitfields(expected_bits(), checked_bitfields, core_lookup); + let x = process_bitfields(checked_bitfields); assert!(x.is_empty(), "No core should be freed."); } @@ -571,7 +770,7 @@ fn bitfield_checks() { ); assert_eq!(checked_bitfields.len(), 1, "No bitfields should have been filtered!"); - let x = process_bitfields(expected_bits(), checked_bitfields, core_lookup); + let x = process_bitfields(checked_bitfields); assert!(x.is_empty(), "No core should be freed."); } @@ -579,12 +778,10 @@ fn bitfield_checks() { { let mut bare_bitfield = default_bitfield(); - assert_eq!(core_lookup(CoreIndex::from(0)), Some(chain_a)); - let default_candidate = TestCandidateBuilder::default().build(); >::insert( chain_a, - CandidatePendingAvailability { + [CandidatePendingAvailability { core: CoreIndex::from(0), hash: default_candidate.hash(), descriptor: default_candidate.descriptor, @@ -593,9 +790,11 @@ fn bitfield_checks() { backed_in_number: 0, backers: default_backing_bitfield(), backing_group: GroupIndex::from(0), - }, + commitments: default_candidate.commitments, + }] + .into_iter() + .collect::>(), ); - PendingAvailabilityCommitments::::insert(chain_a, default_candidate.commitments); *bare_bitfield.0.get_mut(0).unwrap() = true; let signed = sign_bitfield( @@ -613,53 +812,10 @@ fn bitfield_checks() { ); assert_eq!(checked_bitfields.len(), 1, "No bitfields should have been filtered!"); - let x = process_bitfields(expected_bits(), checked_bitfields, core_lookup); + let x = process_bitfields(checked_bitfields); assert!(x.is_empty(), "No core should be freed."); >::remove(chain_a); - PendingAvailabilityCommitments::::remove(chain_a); - } - - // bitfield signed with pending bit signed, but no commitments. - { - let mut bare_bitfield = default_bitfield(); - - assert_eq!(core_lookup(CoreIndex::from(0)), Some(chain_a)); - - let default_candidate = TestCandidateBuilder::default().build(); - >::insert( - chain_a, - CandidatePendingAvailability { - core: CoreIndex::from(0), - hash: default_candidate.hash(), - descriptor: default_candidate.descriptor, - availability_votes: default_availability_votes(), - relay_parent_number: 0, - backed_in_number: 0, - backers: default_backing_bitfield(), - backing_group: GroupIndex::from(0), - }, - ); - - *bare_bitfield.0.get_mut(0).unwrap() = true; - let signed = sign_bitfield( - &keystore, - &validators[0], - ValidatorIndex(0), - bare_bitfield, - &signing_context, - ); - - let checked_bitfields = simple_sanitize_bitfields( - vec![signed.into()], - DisputedBitfield::zeros(expected_bits()), - expected_bits(), - ); - assert_eq!(checked_bitfields.len(), 1, "No bitfields should have been filtered!"); - - let x = process_bitfields(expected_bits(), checked_bitfields, core_lookup); - // no core is freed - assert!(x.is_empty(), "No core should be freed."); } }); } @@ -673,13 +829,17 @@ fn availability_threshold_is_supermajority() { #[test] fn supermajority_bitfields_trigger_availability() { - let chain_a = ParaId::from(1_u32); - let chain_b = ParaId::from(2_u32); - let thread_a = ParaId::from(3_u32); + let chain_a = ParaId::from(0_u32); + let chain_b = ParaId::from(1_u32); + let chain_c = ParaId::from(2_u32); + let chain_d = ParaId::from(3_u32); + let thread_a = ParaId::from(4_u32); let paras = vec![ (chain_a, ParaKind::Parachain), (chain_b, ParaKind::Parachain), + (chain_c, ParaKind::Parachain), + (chain_d, ParaKind::Parachain), (thread_a, ParaKind::Parathread), ]; let validators = vec![ @@ -688,6 +848,8 @@ fn supermajority_bitfields_trigger_availability() { Sr25519Keyring::Charlie, Sr25519Keyring::Dave, Sr25519Keyring::Ferdie, + Sr25519Keyring::One, + Sr25519Keyring::Two, ]; let keystore: KeystorePtr = Arc::new(LocalKeystore::in_memory()); for validator in validators.iter() { @@ -707,13 +869,7 @@ fn supermajority_bitfields_trigger_availability() { let signing_context = SigningContext { parent_hash: System::parent_hash(), session_index: 5 }; - let core_lookup = |core| match core { - core if core == CoreIndex::from(0) => Some(chain_a), - core if core == CoreIndex::from(1) => Some(chain_b), - core if core == CoreIndex::from(2) => Some(thread_a), - _ => panic!("Core out of bounds for 2 parachains and 1 parathread core."), - }; - + // Chain A only has one candidate pending availability. It will be made available now. let candidate_a = TestCandidateBuilder { para_id: chain_a, head_data: vec![1, 2, 3, 4].into(), @@ -723,7 +879,7 @@ fn supermajority_bitfields_trigger_availability() { >::insert( chain_a, - CandidatePendingAvailability { + [CandidatePendingAvailability { core: CoreIndex::from(0), hash: candidate_a.hash(), descriptor: candidate_a.clone().descriptor, @@ -732,10 +888,13 @@ fn supermajority_bitfields_trigger_availability() { backed_in_number: 0, backers: backing_bitfield(&[3, 4]), backing_group: GroupIndex::from(0), - }, + commitments: candidate_a.clone().commitments, + }] + .into_iter() + .collect::>(), ); - PendingAvailabilityCommitments::::insert(chain_a, candidate_a.clone().commitments); + // Chain B only has one candidate pending availability. It won't be made available now. let candidate_b = TestCandidateBuilder { para_id: chain_b, head_data: vec![5, 6, 7, 8].into(), @@ -745,7 +904,7 @@ fn supermajority_bitfields_trigger_availability() { >::insert( chain_b, - CandidatePendingAvailability { + [CandidatePendingAvailability { core: CoreIndex::from(1), hash: candidate_b.hash(), descriptor: candidate_b.descriptor, @@ -754,40 +913,99 @@ fn supermajority_bitfields_trigger_availability() { backed_in_number: 0, backers: backing_bitfield(&[0, 2]), backing_group: GroupIndex::from(1), - }, + commitments: candidate_b.commitments, + }] + .into_iter() + .collect::>(), ); - PendingAvailabilityCommitments::::insert(chain_b, candidate_b.commitments); - // this bitfield signals that a and b are available. - let a_and_b_available = { - let mut bare_bitfield = default_bitfield(); - *bare_bitfield.0.get_mut(0).unwrap() = true; - *bare_bitfield.0.get_mut(1).unwrap() = true; + // Chain C has three candidates pending availability. The first and third candidates will be + // made available. Only the first candidate will be evicted from the core and enacted. + let candidate_c_1 = TestCandidateBuilder { + para_id: chain_c, + head_data: vec![7, 8].into(), + ..Default::default() + } + .build(); + let candidate_c_2 = TestCandidateBuilder { + para_id: chain_c, + head_data: vec![9, 10].into(), + ..Default::default() + } + .build(); + let candidate_c_3 = TestCandidateBuilder { + para_id: chain_c, + head_data: vec![11, 12].into(), + ..Default::default() + } + .build(); - bare_bitfield - }; + let mut c_candidates = VecDeque::new(); + c_candidates.push_back(CandidatePendingAvailability { + core: CoreIndex::from(2), + hash: candidate_c_1.hash(), + descriptor: candidate_c_1.descriptor.clone(), + availability_votes: default_availability_votes(), + relay_parent_number: 0, + backed_in_number: 0, + backers: backing_bitfield(&[1]), + backing_group: GroupIndex::from(2), + commitments: candidate_c_1.commitments.clone(), + }); + c_candidates.push_back(CandidatePendingAvailability { + core: CoreIndex::from(3), + hash: candidate_c_2.hash(), + descriptor: candidate_c_2.descriptor.clone(), + availability_votes: default_availability_votes(), + relay_parent_number: 0, + backed_in_number: 0, + backers: backing_bitfield(&[5]), + backing_group: GroupIndex::from(3), + commitments: candidate_c_2.commitments.clone(), + }); + c_candidates.push_back(CandidatePendingAvailability { + core: CoreIndex::from(4), + hash: candidate_c_3.hash(), + descriptor: candidate_c_3.descriptor.clone(), + availability_votes: default_availability_votes(), + relay_parent_number: 0, + backed_in_number: 0, + backers: backing_bitfield(&[6]), + backing_group: GroupIndex::from(4), + commitments: candidate_c_3.commitments.clone(), + }); - // this bitfield signals that only a is available. - let a_available = { + >::insert(chain_c, c_candidates); + + // this bitfield signals that a and b are available. + let all_available = { let mut bare_bitfield = default_bitfield(); - *bare_bitfield.0.get_mut(0).unwrap() = true; + for bit in 0..=4 { + *bare_bitfield.0.get_mut(bit).unwrap() = true; + } bare_bitfield }; let threshold = availability_threshold(validators.len()); - // 4 of 5 first value >= 2/3 - assert_eq!(threshold, 4); + // 5 of 7 first value >= 2/3 + assert_eq!(threshold, 5); let signed_bitfields = validators .iter() .enumerate() .filter_map(|(i, key)| { - let to_sign = if i < 3 { - a_and_b_available.clone() - } else if i < 4 { - a_available.clone() + let to_sign = if i < 4 { + all_available.clone() + } else if i < 5 { + // this bitfield signals that only a, c1 and c3 are available. + let mut bare_bitfield = default_bitfield(); + *bare_bitfield.0.get_mut(0).unwrap() = true; + *bare_bitfield.0.get_mut(2).unwrap() = true; + *bare_bitfield.0.get_mut(4).unwrap() = true; + + bare_bitfield } else { // sign nothing. return None @@ -814,46 +1032,129 @@ fn supermajority_bitfields_trigger_availability() { ); assert_eq!(checked_bitfields.len(), old_len, "No bitfields should have been filtered!"); - // only chain A's core is freed. - let v = process_bitfields(expected_bits(), checked_bitfields, core_lookup); - assert_eq!(vec![(CoreIndex(0), candidate_a.hash())], v); - - // chain A had 4 signing off, which is >= threshold. - // chain B has 3 signing off, which is < threshold. - assert!(>::get(&chain_a).is_none()); - assert!(>::get(&chain_a).is_none()); - assert!(>::get(&chain_b).is_some()); - assert_eq!(>::get(&chain_b).unwrap().availability_votes, { - // check that votes from first 3 were tracked. + // only chain A's core and candidate's C1 core are freed. + let v = process_bitfields(checked_bitfields); + assert_eq!( + vec![(CoreIndex(2), candidate_c_1.hash()), (CoreIndex(0), candidate_a.hash())], + v + ); + let votes = |bits: &[usize]| { let mut votes = default_availability_votes(); - *votes.get_mut(0).unwrap() = true; - *votes.get_mut(1).unwrap() = true; - *votes.get_mut(2).unwrap() = true; + for bit in bits { + *votes.get_mut(*bit).unwrap() = true; + } votes - }); + }; - // and check that chain head was enacted. + assert!(>::get(&chain_a).unwrap().is_empty()); + assert_eq!( + >::get(&chain_b) + .unwrap() + .pop_front() + .unwrap() + .availability_votes, + votes(&[0, 1, 2, 3]) + ); + let mut pending_c = >::get(&chain_c).unwrap(); + assert_eq!(pending_c.pop_front().unwrap().availability_votes, votes(&[0, 1, 2, 3])); + assert_eq!(pending_c.pop_front().unwrap().availability_votes, votes(&[0, 1, 2, 3, 4])); + assert!(pending_c.is_empty()); + + // and check that chain heads. assert_eq!(Paras::para_head(&chain_a), Some(vec![1, 2, 3, 4].into())); + assert_ne!(Paras::para_head(&chain_b), Some(vec![5, 6, 7, 8].into())); + assert_eq!(Paras::para_head(&chain_c), Some(vec![7, 8].into())); // Check that rewards are applied. { let rewards = crate::mock::availability_rewards(); - assert_eq!(rewards.len(), 4); - assert_eq!(rewards.get(&ValidatorIndex(0)).unwrap(), &1); - assert_eq!(rewards.get(&ValidatorIndex(1)).unwrap(), &1); - assert_eq!(rewards.get(&ValidatorIndex(2)).unwrap(), &1); + assert_eq!(rewards.len(), 5); + assert_eq!(rewards.get(&ValidatorIndex(0)).unwrap(), &2); + assert_eq!(rewards.get(&ValidatorIndex(1)).unwrap(), &2); + assert_eq!(rewards.get(&ValidatorIndex(2)).unwrap(), &2); + assert_eq!(rewards.get(&ValidatorIndex(3)).unwrap(), &2); + assert_eq!(rewards.get(&ValidatorIndex(4)).unwrap(), &2); + } + + { + let rewards = crate::mock::backing_rewards(); + + assert_eq!(rewards.len(), 3); assert_eq!(rewards.get(&ValidatorIndex(3)).unwrap(), &1); + assert_eq!(rewards.get(&ValidatorIndex(4)).unwrap(), &1); + assert_eq!(rewards.get(&ValidatorIndex(1)).unwrap(), &1); + } + + // Add a new bitfield which will make candidate C2 available also. This will also evict and + // enact C3. + let signed_bitfields = vec![sign_bitfield( + &keystore, + &validators[5], + ValidatorIndex(5), + { + let mut bare_bitfield = default_bitfield(); + *bare_bitfield.0.get_mut(3).unwrap() = true; + bare_bitfield + }, + &signing_context, + ) + .into()]; + + let old_len = signed_bitfields.len(); + let checked_bitfields = simple_sanitize_bitfields( + signed_bitfields, + DisputedBitfield::zeros(expected_bits()), + expected_bits(), + ); + assert_eq!(checked_bitfields.len(), old_len, "No bitfields should have been filtered!"); + + let v = process_bitfields(checked_bitfields); + assert_eq!( + vec![(CoreIndex(3), candidate_c_2.hash()), (CoreIndex(4), candidate_c_3.hash())], + v + ); + + assert!(>::get(&chain_a).unwrap().is_empty()); + assert_eq!( + >::get(&chain_b) + .unwrap() + .pop_front() + .unwrap() + .availability_votes, + votes(&[0, 1, 2, 3]) + ); + assert!(>::get(&chain_c).unwrap().is_empty()); + + // and check that chain heads. + assert_eq!(Paras::para_head(&chain_a), Some(vec![1, 2, 3, 4].into())); + assert_ne!(Paras::para_head(&chain_b), Some(vec![5, 6, 7, 8].into())); + assert_eq!(Paras::para_head(&chain_c), Some(vec![11, 12].into())); + + // Check that rewards are applied. + { + let rewards = crate::mock::availability_rewards(); + + assert_eq!(rewards.len(), 6); + assert_eq!(rewards.get(&ValidatorIndex(0)).unwrap(), &4); + assert_eq!(rewards.get(&ValidatorIndex(1)).unwrap(), &4); + assert_eq!(rewards.get(&ValidatorIndex(2)).unwrap(), &4); + assert_eq!(rewards.get(&ValidatorIndex(3)).unwrap(), &4); + assert_eq!(rewards.get(&ValidatorIndex(4)).unwrap(), &3); + assert_eq!(rewards.get(&ValidatorIndex(5)).unwrap(), &1); } { let rewards = crate::mock::backing_rewards(); - assert_eq!(rewards.len(), 2); + assert_eq!(rewards.len(), 5); assert_eq!(rewards.get(&ValidatorIndex(3)).unwrap(), &1); assert_eq!(rewards.get(&ValidatorIndex(4)).unwrap(), &1); + assert_eq!(rewards.get(&ValidatorIndex(1)).unwrap(), &1); + assert_eq!(rewards.get(&ValidatorIndex(5)).unwrap(), &1); + assert_eq!(rewards.get(&ValidatorIndex(6)).unwrap(), &1); } }); } @@ -878,6 +1179,7 @@ fn candidate_checks() { Sr25519Keyring::Charlie, Sr25519Keyring::Dave, Sr25519Keyring::Ferdie, + Sr25519Keyring::One, ]; let keystore: KeystorePtr = Arc::new(LocalKeystore::in_memory()); for validator in validators.iter() { @@ -904,7 +1206,8 @@ fn candidate_checks() { group_index if group_index == GroupIndex::from(0) => Some(vec![0, 1]), group_index if group_index == GroupIndex::from(1) => Some(vec![2, 3]), group_index if group_index == GroupIndex::from(2) => Some(vec![4]), - _ => panic!("Group index out of bounds for 2 parachains and 1 parathread core"), + group_index if group_index == GroupIndex::from(3) => Some(vec![5]), + _ => panic!("Group index out of bounds"), } .map(|m| m.into_iter().map(ValidatorIndex).collect::>()) }; @@ -914,12 +1217,12 @@ fn candidate_checks() { vec![ValidatorIndex(0), ValidatorIndex(1)], vec![ValidatorIndex(2), ValidatorIndex(3)], vec![ValidatorIndex(4)], + vec![ValidatorIndex(5)], ]; Scheduler::set_validator_groups(validator_groups); let thread_collator: CollatorId = Sr25519Keyring::Two.public().into(); let chain_a_assignment = (chain_a, CoreIndex::from(0)); - let chain_b_assignment = (chain_b, CoreIndex::from(1)); let thread_a_assignment = (thread_a, CoreIndex::from(2)); @@ -929,14 +1232,14 @@ fn candidate_checks() { assert_eq!( ParaInclusion::process_candidates( &allowed_relay_parents, - vec![], + &BTreeMap::new(), &group_validators, false ), Ok(ProcessedCandidates::default()) ); - // candidates out of order. + // Check candidate ordering { let mut candidate_a = TestCandidateBuilder { para_id: chain_a, @@ -947,19 +1250,37 @@ fn candidate_checks() { ..Default::default() } .build(); - let mut candidate_b = TestCandidateBuilder { + let mut candidate_b_1 = TestCandidateBuilder { para_id: chain_b, relay_parent: System::parent_hash(), pov_hash: Hash::repeat_byte(2), persisted_validation_data_hash: make_vdata_hash(chain_b).unwrap(), hrmp_watermark: RELAY_PARENT_NUM, + head_data: HeadData(vec![1, 2, 3]), ..Default::default() } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate_a); + // Make candidate b2 a child of b1. + let mut candidate_b_2 = TestCandidateBuilder { + para_id: chain_b, + relay_parent: System::parent_hash(), + pov_hash: Hash::repeat_byte(3), + persisted_validation_data_hash: make_persisted_validation_data_with_parent::( + RELAY_PARENT_NUM, + Default::default(), + candidate_b_1.commitments.head_data.clone(), + ) + .hash(), + hrmp_watermark: RELAY_PARENT_NUM, + head_data: HeadData(vec![5, 6, 7]), + ..Default::default() + } + .build(); - collator_sign_candidate(Sr25519Keyring::Two, &mut candidate_b); + collator_sign_candidate(Sr25519Keyring::One, &mut candidate_a); + collator_sign_candidate(Sr25519Keyring::Two, &mut candidate_b_1); + collator_sign_candidate(Sr25519Keyring::Two, &mut candidate_b_2); let backed_a = back_candidate( candidate_a, @@ -971,8 +1292,18 @@ fn candidate_checks() { None, ); - let backed_b = back_candidate( - candidate_b, + let backed_b_1 = back_candidate( + candidate_b_1.clone(), + &validators, + group_validators(GroupIndex::from(2)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + None, + ); + + let backed_b_2 = back_candidate( + candidate_b_2, &validators, group_validators(GroupIndex::from(1)).unwrap().as_ref(), &keystore, @@ -981,15 +1312,82 @@ fn candidate_checks() { None, ); - // out-of-order manifests as unscheduled. + // candidates are required to be sorted in dependency order. assert_noop!( ParaInclusion::process_candidates( &allowed_relay_parents, - vec![(backed_b, chain_b_assignment.1), (backed_a, chain_a_assignment.1)], + &vec![( + chain_b, + vec![ + (backed_b_2.clone(), CoreIndex(1)), + (backed_b_1.clone(), CoreIndex(2)) + ] + ),] + .into_iter() + .collect(), &group_validators, false ), - Error::::ScheduledOutOfOrder + Error::::ValidationDataHashMismatch + ); + + // candidates are no longer required to be sorted by core index. + ParaInclusion::process_candidates( + &allowed_relay_parents, + &vec![ + ( + chain_b, + vec![ + (backed_b_1.clone(), CoreIndex(2)), + (backed_b_2.clone(), CoreIndex(1)), + ], + ), + (chain_a_assignment.0, vec![(backed_a.clone(), chain_a_assignment.1)]), + ] + .into_iter() + .collect(), + &group_validators, + false, + ) + .unwrap(); + + // candidate does not build on top of the latest unincluded head + + let mut candidate_b_3 = TestCandidateBuilder { + para_id: chain_b, + relay_parent: System::parent_hash(), + pov_hash: Hash::repeat_byte(4), + persisted_validation_data_hash: make_persisted_validation_data_with_parent::( + RELAY_PARENT_NUM, + Default::default(), + candidate_b_1.commitments.head_data.clone(), + ) + .hash(), + hrmp_watermark: RELAY_PARENT_NUM, + head_data: HeadData(vec![8, 9]), + ..Default::default() + } + .build(); + collator_sign_candidate(Sr25519Keyring::Two, &mut candidate_b_3); + + let backed_b_3 = back_candidate( + candidate_b_3, + &validators, + group_validators(GroupIndex::from(3)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + None, + ); + + assert_noop!( + ParaInclusion::process_candidates( + &allowed_relay_parents, + &vec![(chain_b, vec![(backed_b_3, CoreIndex(3))])].into_iter().collect(), + &group_validators, + false + ), + Error::::ValidationDataHashMismatch ); } @@ -1006,8 +1404,9 @@ fn candidate_checks() { .build(); collator_sign_candidate(Sr25519Keyring::One, &mut candidate); + // Insufficient backing. let backed = back_candidate( - candidate, + candidate.clone(), &validators, group_validators(GroupIndex::from(0)).unwrap().as_ref(), &keystore, @@ -1019,12 +1418,37 @@ fn candidate_checks() { assert_noop!( ParaInclusion::process_candidates( &allowed_relay_parents, - vec![(backed, chain_a_assignment.1)], + &vec![(chain_a_assignment.0, vec![(backed, chain_a_assignment.1)])] + .into_iter() + .collect(), &group_validators, false ), Error::::InsufficientBacking ); + + // Wrong backing group. + let backed = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(1)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + None, + ); + + assert_noop!( + ParaInclusion::process_candidates( + &allowed_relay_parents, + &vec![(chain_a_assignment.0, vec![(backed, chain_a_assignment.1)])] + .into_iter() + .collect(), + &group_validators, + false + ), + Error::::InvalidBacking + ); } // one of candidates is not based on allowed relay parent. @@ -1078,7 +1502,12 @@ fn candidate_checks() { assert_noop!( ParaInclusion::process_candidates( &allowed_relay_parents, - vec![(backed_b, chain_b_assignment.1), (backed_a, chain_a_assignment.1)], + &vec![ + (chain_b_assignment.0, vec![(backed_b, chain_b_assignment.1)]), + (chain_a_assignment.0, vec![(backed_a, chain_a_assignment.1)]) + ] + .into_iter() + .collect(), &group_validators, false ), @@ -1117,7 +1546,9 @@ fn candidate_checks() { assert_noop!( ParaInclusion::process_candidates( &allowed_relay_parents, - vec![(backed, thread_a_assignment.1)], + &vec![(thread_a_assignment.0, vec![(backed, thread_a_assignment.1)])] + .into_iter() + .collect(), &group_validators, false ), @@ -1125,100 +1556,6 @@ fn candidate_checks() { ); } - // para occupied - reject. - { - let mut candidate = TestCandidateBuilder { - para_id: chain_a, - relay_parent: System::parent_hash(), - pov_hash: Hash::repeat_byte(1), - persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(), - hrmp_watermark: RELAY_PARENT_NUM, - ..Default::default() - } - .build(); - - collator_sign_candidate(Sr25519Keyring::One, &mut candidate); - - let backed = back_candidate( - candidate, - &validators, - group_validators(GroupIndex::from(0)).unwrap().as_ref(), - &keystore, - &signing_context, - BackingKind::Threshold, - None, - ); - - let candidate = TestCandidateBuilder::default().build(); - >::insert( - &chain_a, - CandidatePendingAvailability { - core: CoreIndex::from(0), - hash: candidate.hash(), - descriptor: candidate.descriptor, - availability_votes: default_availability_votes(), - relay_parent_number: 3, - backed_in_number: 4, - backers: default_backing_bitfield(), - backing_group: GroupIndex::from(0), - }, - ); - >::insert(&chain_a, candidate.commitments); - - assert_noop!( - ParaInclusion::process_candidates( - &allowed_relay_parents, - vec![(backed, chain_a_assignment.1)], - &group_validators, - false - ), - Error::::CandidateScheduledBeforeParaFree - ); - - >::remove(&chain_a); - >::remove(&chain_a); - } - - // messed up commitments storage - do not panic - reject. - { - let mut candidate = TestCandidateBuilder { - para_id: chain_a, - relay_parent: System::parent_hash(), - pov_hash: Hash::repeat_byte(1), - persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(), - hrmp_watermark: RELAY_PARENT_NUM, - ..Default::default() - } - .build(); - - collator_sign_candidate(Sr25519Keyring::One, &mut candidate); - - // this is not supposed to happen - >::insert(&chain_a, candidate.commitments.clone()); - - let backed = back_candidate( - candidate, - &validators, - group_validators(GroupIndex::from(0)).unwrap().as_ref(), - &keystore, - &signing_context, - BackingKind::Threshold, - None, - ); - - assert_noop!( - ParaInclusion::process_candidates( - &allowed_relay_parents, - vec![(backed, chain_a_assignment.1)], - &group_validators, - false - ), - Error::::CandidateScheduledBeforeParaFree - ); - - >::remove(&chain_a); - } - // interfering code upgrade - reject { let mut candidate = TestCandidateBuilder { @@ -1260,7 +1597,9 @@ fn candidate_checks() { assert_noop!( ParaInclusion::process_candidates( &allowed_relay_parents, - vec![(backed, chain_a_assignment.1)], + &vec![(chain_a_assignment.0, vec![(backed, chain_a_assignment.1)])] + .into_iter() + .collect(), &group_validators, false ), @@ -1292,14 +1631,16 @@ fn candidate_checks() { None, ); - assert_eq!( + assert_noop!( ParaInclusion::process_candidates( &allowed_relay_parents, - vec![(backed, chain_a_assignment.1)], + &vec![(chain_a_assignment.0, vec![(backed, chain_a_assignment.1)])] + .into_iter() + .collect(), &group_validators, - false + false, ), - Err(Error::::ValidationDataHashMismatch.into()), + Error::::ValidationDataHashMismatch ); } @@ -1331,7 +1672,9 @@ fn candidate_checks() { assert_noop!( ParaInclusion::process_candidates( &allowed_relay_parents, - vec![(backed, chain_a_assignment.1)], + &vec![(chain_a_assignment.0, vec![(backed, chain_a_assignment.1)])] + .into_iter() + .collect(), &group_validators, false ), @@ -1367,7 +1710,9 @@ fn candidate_checks() { assert_noop!( ParaInclusion::process_candidates( &allowed_relay_parents, - vec![(backed, chain_a_assignment.1)], + &vec![(chain_a_assignment.0, vec![(backed, chain_a_assignment.1)])] + .into_iter() + .collect(), &group_validators, false ), @@ -1506,16 +1851,21 @@ fn backing_works() { ); let backed_candidates = vec![ - (backed_a.clone(), chain_a_assignment.1), - (backed_b.clone(), chain_b_assignment.1), - (backed_c, thread_a_assignment.1), - ]; + (chain_a_assignment.0, vec![(backed_a, chain_a_assignment.1)]), + (chain_b_assignment.0, vec![(backed_b, chain_b_assignment.1)]), + (thread_a_assignment.0, vec![(backed_c, thread_a_assignment.1)]), + ] + .into_iter() + .collect::>(); + let get_backing_group_idx = { // the order defines the group implicitly for this test case let backed_candidates_with_groups = backed_candidates - .iter() + .values() .enumerate() - .map(|(idx, (backed_candidate, _))| (backed_candidate.hash(), GroupIndex(idx as _))) + .map(|(idx, backed_candidates)| { + (backed_candidates.iter().next().unwrap().0.hash(), GroupIndex(idx as _)) + }) .collect::>(); move |candidate_hash_x: CandidateHash| -> Option { @@ -1534,7 +1884,7 @@ fn backing_works() { candidate_receipt_with_backing_validator_indices, } = ParaInclusion::process_candidates( &allowed_relay_parents, - backed_candidates.clone(), + &backed_candidates, &group_validators, false, ) @@ -1555,7 +1905,8 @@ fn backing_works() { CandidateHash, (CandidateReceipt, Vec<(ValidatorIndex, ValidityAttestation)>), >::new(); - backed_candidates.into_iter().for_each(|(backed_candidate, _)| { + backed_candidates.values().for_each(|backed_candidates| { + let backed_candidate = backed_candidates.iter().next().unwrap().0.clone(); let candidate_receipt_with_backers = intermediate .entry(backed_candidate.hash()) .or_insert_with(|| (backed_candidate.receipt(), Vec::new())); @@ -1606,20 +1957,21 @@ fn backing_works() { }; assert_eq!( >::get(&chain_a), - Some(CandidatePendingAvailability { - core: CoreIndex::from(0), - hash: candidate_a.hash(), - descriptor: candidate_a.descriptor, - availability_votes: default_availability_votes(), - relay_parent_number: System::block_number() - 1, - backed_in_number: System::block_number(), - backers, - backing_group: GroupIndex::from(0), - }) - ); - assert_eq!( - >::get(&chain_a), - Some(candidate_a.commitments), + Some( + [CandidatePendingAvailability { + core: CoreIndex::from(0), + hash: candidate_a.hash(), + descriptor: candidate_a.descriptor, + availability_votes: default_availability_votes(), + relay_parent_number: System::block_number() - 1, + backed_in_number: System::block_number(), + backers, + backing_group: GroupIndex::from(0), + commitments: candidate_a.commitments, + }] + .into_iter() + .collect::>() + ) ); let backers = { @@ -1631,38 +1983,40 @@ fn backing_works() { }; assert_eq!( >::get(&chain_b), - Some(CandidatePendingAvailability { - core: CoreIndex::from(1), - hash: candidate_b.hash(), - descriptor: candidate_b.descriptor, - availability_votes: default_availability_votes(), - relay_parent_number: System::block_number() - 1, - backed_in_number: System::block_number(), - backers, - backing_group: GroupIndex::from(1), - }) - ); - assert_eq!( - >::get(&chain_b), - Some(candidate_b.commitments), + Some( + [CandidatePendingAvailability { + core: CoreIndex::from(1), + hash: candidate_b.hash(), + descriptor: candidate_b.descriptor, + availability_votes: default_availability_votes(), + relay_parent_number: System::block_number() - 1, + backed_in_number: System::block_number(), + backers, + backing_group: GroupIndex::from(1), + commitments: candidate_b.commitments, + }] + .into_iter() + .collect::>() + ) ); assert_eq!( >::get(&thread_a), - Some(CandidatePendingAvailability { - core: CoreIndex::from(2), - hash: candidate_c.hash(), - descriptor: candidate_c.descriptor, - availability_votes: default_availability_votes(), - relay_parent_number: System::block_number() - 1, - backed_in_number: System::block_number(), - backers: backing_bitfield(&[4]), - backing_group: GroupIndex::from(2), - }) - ); - assert_eq!( - >::get(&thread_a), - Some(candidate_c.commitments), + Some( + [CandidatePendingAvailability { + core: CoreIndex::from(2), + hash: candidate_c.hash(), + descriptor: candidate_c.descriptor, + availability_votes: default_availability_votes(), + relay_parent_number: System::block_number() - 1, + backed_in_number: System::block_number(), + backers: backing_bitfield(&[4]), + backing_group: GroupIndex::from(2), + commitments: candidate_c.commitments + }] + .into_iter() + .collect::>() + ) ); }); } @@ -1750,11 +2104,17 @@ fn backing_works_with_elastic_scaling_mvp() { .build(); collator_sign_candidate(Sr25519Keyring::One, &mut candidate_b_1); + // Make candidate b2 a child of b1. let mut candidate_b_2 = TestCandidateBuilder { para_id: chain_b, relay_parent: System::parent_hash(), pov_hash: Hash::repeat_byte(3), - persisted_validation_data_hash: make_vdata_hash(chain_b).unwrap(), + persisted_validation_data_hash: make_persisted_validation_data_with_parent::( + RELAY_PARENT_NUM, + Default::default(), + candidate_b_1.commitments.head_data.clone(), + ) + .hash(), hrmp_watermark: RELAY_PARENT_NUM, ..Default::default() } @@ -1791,18 +2151,25 @@ fn backing_works_with_elastic_scaling_mvp() { Some(CoreIndex(2)), ); - let backed_candidates = vec![ - (backed_a.clone(), CoreIndex(0)), - (backed_b_1.clone(), CoreIndex(1)), - (backed_b_2.clone(), CoreIndex(2)), - ]; + let mut backed_candidates = BTreeMap::new(); + backed_candidates.insert(chain_a, vec![(backed_a, CoreIndex(0))]); + backed_candidates + .insert(chain_b, vec![(backed_b_1, CoreIndex(1)), (backed_b_2, CoreIndex(2))]); + let get_backing_group_idx = { // the order defines the group implicitly for this test case let backed_candidates_with_groups = backed_candidates - .iter() + .values() .enumerate() - .map(|(idx, (backed_candidate, _))| (backed_candidate.hash(), GroupIndex(idx as _))) - .collect::>(); + .map(|(idx, backed_candidates)| { + backed_candidates + .iter() + .enumerate() + .map(|(i, c)| (c.0.hash(), GroupIndex((idx + i) as _))) + .collect() + }) + .collect::>>() + .concat(); move |candidate_hash_x: CandidateHash| -> Option { backed_candidates_with_groups.iter().find_map(|(candidate_hash, grp)| { @@ -1820,14 +2187,13 @@ fn backing_works_with_elastic_scaling_mvp() { candidate_receipt_with_backing_validator_indices, } = ParaInclusion::process_candidates( &allowed_relay_parents, - backed_candidates.clone(), + &backed_candidates, &group_validators, true, ) .expect("candidates scheduled, in order, and backed"); - // Both b candidates will be backed. However, only one will be recorded on-chain and proceed - // with being made available. + // Both b candidates will be backed. assert_eq!( occupied_cores, vec![ @@ -1842,26 +2208,29 @@ fn backing_works_with_elastic_scaling_mvp() { CandidateHash, (CandidateReceipt, Vec<(ValidatorIndex, ValidityAttestation)>), >::new(); - backed_candidates.into_iter().for_each(|(backed_candidate, _)| { - let candidate_receipt_with_backers = expected - .entry(backed_candidate.hash()) - .or_insert_with(|| (backed_candidate.receipt(), Vec::new())); - let (validator_indices, _maybe_core_index) = - backed_candidate.validator_indices_and_core_index(true); - assert_eq!(backed_candidate.validity_votes().len(), validator_indices.count_ones()); - candidate_receipt_with_backers.1.extend( - validator_indices - .iter() - .enumerate() - .filter(|(_, signed)| **signed) - .zip(backed_candidate.validity_votes().iter().cloned()) - .filter_map(|((validator_index_within_group, _), attestation)| { - let grp_idx = get_backing_group_idx(backed_candidate.hash()).unwrap(); - group_validators(grp_idx).map(|validator_indices| { - (validator_indices[validator_index_within_group], attestation) - }) - }), - ); + backed_candidates.values().for_each(|backed_candidates| { + for backed_candidate in backed_candidates { + let backed_candidate = backed_candidate.0.clone(); + let candidate_receipt_with_backers = expected + .entry(backed_candidate.hash()) + .or_insert_with(|| (backed_candidate.receipt(), Vec::new())); + let (validator_indices, _maybe_core_index) = + backed_candidate.validator_indices_and_core_index(true); + assert_eq!(backed_candidate.validity_votes().len(), validator_indices.count_ones()); + candidate_receipt_with_backers.1.extend( + validator_indices + .iter() + .enumerate() + .filter(|(_, signed)| **signed) + .zip(backed_candidate.validity_votes().iter().cloned()) + .filter_map(|((validator_index_within_group, _), attestation)| { + let grp_idx = get_backing_group_idx(backed_candidate.hash()).unwrap(); + group_validators(grp_idx).map(|validator_indices| { + (validator_indices[validator_index_within_group], attestation) + }) + }), + ); + } }); assert_eq!( @@ -1881,39 +2250,54 @@ fn backing_works_with_elastic_scaling_mvp() { }; assert_eq!( >::get(&chain_a), - Some(CandidatePendingAvailability { - core: CoreIndex::from(0), - hash: candidate_a.hash(), - descriptor: candidate_a.descriptor, - availability_votes: default_availability_votes(), - relay_parent_number: System::block_number() - 1, - backed_in_number: System::block_number(), - backers, - backing_group: GroupIndex::from(0), - }) - ); - assert_eq!( - >::get(&chain_a), - Some(candidate_a.commitments), + Some( + [CandidatePendingAvailability { + core: CoreIndex::from(0), + hash: candidate_a.hash(), + descriptor: candidate_a.descriptor, + availability_votes: default_availability_votes(), + relay_parent_number: System::block_number() - 1, + backed_in_number: System::block_number(), + backers, + backing_group: GroupIndex::from(0), + commitments: candidate_a.commitments + }] + .into_iter() + .collect::>() + ) ); - // Only one candidate for b will be recorded on chain. + // Both candidates of b will be recorded on chain. assert_eq!( >::get(&chain_b), - Some(CandidatePendingAvailability { - core: CoreIndex::from(2), - hash: candidate_b_2.hash(), - descriptor: candidate_b_2.descriptor, - availability_votes: default_availability_votes(), - relay_parent_number: System::block_number() - 1, - backed_in_number: System::block_number(), - backers: backing_bitfield(&[4]), - backing_group: GroupIndex::from(2), - }) - ); - assert_eq!( - >::get(&chain_b), - Some(candidate_b_2.commitments), + Some( + [ + CandidatePendingAvailability { + core: CoreIndex::from(1), + hash: candidate_b_1.hash(), + descriptor: candidate_b_1.descriptor, + availability_votes: default_availability_votes(), + relay_parent_number: System::block_number() - 1, + backed_in_number: System::block_number(), + backers: backing_bitfield(&[2, 3]), + backing_group: GroupIndex::from(1), + commitments: candidate_b_1.commitments + }, + CandidatePendingAvailability { + core: CoreIndex::from(2), + hash: candidate_b_2.hash(), + descriptor: candidate_b_2.descriptor, + availability_votes: default_availability_votes(), + relay_parent_number: System::block_number() - 1, + backed_in_number: System::block_number(), + backers: backing_bitfield(&[4]), + backing_group: GroupIndex::from(2), + commitments: candidate_b_2.commitments + } + ] + .into_iter() + .collect::>() + ) ); }); } @@ -1998,8 +2382,10 @@ fn can_include_candidate_with_ok_code_upgrade() { let ProcessedCandidates { core_indices: occupied_cores, .. } = ParaInclusion::process_candidates( &allowed_relay_parents, - vec![(backed_a, chain_a_assignment.1)], - &group_validators, + &vec![(chain_a_assignment.0, vec![(backed_a, chain_a_assignment.1)])] + .into_iter() + .collect::>(), + group_validators, false, ) .expect("candidates scheduled, in order, and backed"); @@ -2015,20 +2401,21 @@ fn can_include_candidate_with_ok_code_upgrade() { }; assert_eq!( >::get(&chain_a), - Some(CandidatePendingAvailability { - core: CoreIndex::from(0), - hash: candidate_a.hash(), - descriptor: candidate_a.descriptor, - availability_votes: default_availability_votes(), - relay_parent_number: System::block_number() - 1, - backed_in_number: System::block_number(), - backers, - backing_group: GroupIndex::from(0), - }) - ); - assert_eq!( - >::get(&chain_a), - Some(candidate_a.commitments), + Some( + [CandidatePendingAvailability { + core: CoreIndex::from(0), + hash: candidate_a.hash(), + descriptor: candidate_a.descriptor, + availability_votes: default_availability_votes(), + relay_parent_number: System::block_number() - 1, + backed_in_number: System::block_number(), + backers, + backing_group: GroupIndex::from(0), + commitments: candidate_a.commitments + }] + .into_iter() + .collect::>() + ) ); }); } @@ -2209,14 +2596,16 @@ fn check_allowed_relay_parents() { ); let backed_candidates = vec![ - (backed_a, chain_a_assignment.1), - (backed_b, chain_b_assignment.1), - (backed_c, thread_a_assignment.1), - ]; + (chain_a_assignment.0, vec![(backed_a, chain_a_assignment.1)]), + (chain_b_assignment.0, vec![(backed_b, chain_b_assignment.1)]), + (thread_a_assignment.0, vec![(backed_c, thread_a_assignment.1)]), + ] + .into_iter() + .collect::>(); ParaInclusion::process_candidates( &allowed_relay_parents, - backed_candidates.clone(), + &backed_candidates, &group_validators, false, ) @@ -2264,25 +2653,10 @@ fn session_change_wipes() { run_to_block(10, |_| None); - >::insert( - &ValidatorIndex(0), - AvailabilityBitfieldRecord { bitfield: default_bitfield(), submitted_at: 9 }, - ); - - >::insert( - &ValidatorIndex(1), - AvailabilityBitfieldRecord { bitfield: default_bitfield(), submitted_at: 9 }, - ); - - >::insert( - &ValidatorIndex(4), - AvailabilityBitfieldRecord { bitfield: default_bitfield(), submitted_at: 9 }, - ); - let candidate = TestCandidateBuilder::default().build(); >::insert( &chain_a, - CandidatePendingAvailability { + [CandidatePendingAvailability { core: CoreIndex::from(0), hash: candidate.hash(), descriptor: candidate.descriptor.clone(), @@ -2291,13 +2665,15 @@ fn session_change_wipes() { backed_in_number: 6, backers: default_backing_bitfield(), backing_group: GroupIndex::from(0), - }, + commitments: candidate.commitments.clone(), + }] + .into_iter() + .collect::>(), ); - >::insert(&chain_a, candidate.commitments.clone()); >::insert( &chain_b, - CandidatePendingAvailability { + [CandidatePendingAvailability { core: CoreIndex::from(1), hash: candidate.hash(), descriptor: candidate.descriptor, @@ -2306,22 +2682,18 @@ fn session_change_wipes() { backed_in_number: 7, backers: default_backing_bitfield(), backing_group: GroupIndex::from(1), - }, + commitments: candidate.commitments, + }] + .into_iter() + .collect::>(), ); - >::insert(&chain_b, candidate.commitments); run_to_block(11, |_| None); assert_eq!(shared::Pallet::::session_index(), 5); - assert!(>::get(&ValidatorIndex(0)).is_some()); - assert!(>::get(&ValidatorIndex(1)).is_some()); - assert!(>::get(&ValidatorIndex(4)).is_some()); - assert!(>::get(&chain_a).is_some()); assert!(>::get(&chain_b).is_some()); - assert!(>::get(&chain_a).is_some()); - assert!(>::get(&chain_b).is_some()); run_to_block(12, |n| match n { 12 => Some(SessionChangeNotification { @@ -2337,18 +2709,7 @@ fn session_change_wipes() { assert_eq!(shared::Pallet::::session_index(), 6); - assert!(>::get(&ValidatorIndex(0)).is_none()); - assert!(>::get(&ValidatorIndex(1)).is_none()); - assert!(>::get(&ValidatorIndex(4)).is_none()); - - assert!(>::get(&chain_a).is_none()); - assert!(>::get(&chain_b).is_none()); - assert!(>::get(&chain_a).is_none()); - assert!(>::get(&chain_b).is_none()); - - assert!(>::iter().collect::>().is_empty()); assert!(>::iter().collect::>().is_empty()); - assert!(>::iter().collect::>().is_empty()); }); } @@ -2420,11 +2781,6 @@ fn para_upgrade_delay_scheduled_from_inclusion() { ]]; Scheduler::set_validator_groups(validator_groups); - let core_lookup = |core| match core { - core if core == CoreIndex::from(0) => Some(chain_a), - _ => None, - }; - let allowed_relay_parents = default_allowed_relay_parent_tracker(); let chain_a_assignment = (chain_a, CoreIndex::from(0)); @@ -2453,7 +2809,9 @@ fn para_upgrade_delay_scheduled_from_inclusion() { let ProcessedCandidates { core_indices: occupied_cores, .. } = ParaInclusion::process_candidates( &allowed_relay_parents, - vec![(backed_a, chain_a_assignment.1)], + &vec![(chain_a_assignment.0, vec![(backed_a, chain_a_assignment.1)])] + .into_iter() + .collect::>(), &group_validators, false, ) @@ -2488,11 +2846,10 @@ fn para_upgrade_delay_scheduled_from_inclusion() { expected_bits(), ); - let v = process_bitfields(expected_bits(), checked_bitfields, core_lookup); + let v = process_bitfields(checked_bitfields); assert_eq!(vec![(CoreIndex(0), candidate_a.hash())], v); - assert!(>::get(&chain_a).is_none()); - assert!(>::get(&chain_a).is_none()); + assert!(>::get(&chain_a).unwrap().is_empty()); let active_vote_state = paras::Pallet::::active_vote_state(&new_validation_code_hash) .expect("prechecking must be initiated"); diff --git a/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs b/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs index f3365945758..1b07acffb15 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs @@ -145,10 +145,6 @@ benchmarks! { assert_eq!(backing_validators.1.len(), votes); } - assert_eq!( - inclusion::PendingAvailabilityCommitments::::iter().count(), - cores_with_backed.len() - ); assert_eq!( inclusion::PendingAvailability::::iter().count(), cores_with_backed.len() @@ -209,10 +205,6 @@ benchmarks! { ); } - assert_eq!( - inclusion::PendingAvailabilityCommitments::::iter().count(), - cores_with_backed.len() - ); assert_eq!( inclusion::PendingAvailability::::iter().count(), cores_with_backed.len() diff --git a/polkadot/runtime/parachains/src/paras_inherent/mod.rs b/polkadot/runtime/parachains/src/paras_inherent/mod.rs index 723a15bdba7..02ddfd0acca 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/mod.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/mod.rs @@ -24,8 +24,7 @@ use crate::{ configuration, disputes::DisputesHandler, - inclusion, - inclusion::CandidateCheckContext, + inclusion::{self, CandidateCheckContext}, initializer, metrics::METRICS, paras, @@ -35,6 +34,7 @@ use crate::{ }; use bitvec::prelude::BitVec; use frame_support::{ + defensive, dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}, inherent::{InherentData, InherentIdentifier, MakeFatalError, ProvideInherent}, pallet_prelude::*, @@ -45,7 +45,7 @@ use pallet_babe::{self, ParentBlockRandomness}; use primitives::{ effective_minimum_backing_votes, vstaging::node_features::FeatureIndex, BackedCandidate, CandidateHash, CandidateReceipt, CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, - CoreIndex, DisputeStatementSet, InherentData as ParachainsInherentData, + CoreIndex, DisputeStatementSet, HeadData, InherentData as ParachainsInherentData, MultiDisputeStatementSet, ScrapedOnChainVotes, SessionIndex, SignedAvailabilityBitfields, SigningContext, UncheckedSignedAvailabilityBitfield, UncheckedSignedAvailabilityBitfields, ValidatorId, ValidatorIndex, ValidityAttestation, PARACHAINS_INHERENT_IDENTIFIER, @@ -134,18 +134,11 @@ pub mod pallet { /// The hash of the submitted parent header doesn't correspond to the saved block hash of /// the parent. InvalidParentHeader, - /// Disputed candidate that was concluded invalid. - CandidateConcludedInvalid, /// The data given to the inherent will result in an overweight block. InherentOverweight, - /// The ordering of dispute statements was invalid. - DisputeStatementsUnsortedOrDuplicates, - /// A dispute statement was invalid. - DisputeInvalid, - /// A candidate was backed by a disabled validator - BackedByDisabled, - /// A candidate was backed even though the paraid was not scheduled. - BackedOnUnscheduledCore, + /// A candidate was filtered during inherent execution. This should have only been done + /// during creation. + CandidatesFilteredDuringExecution, /// Too many candidates supplied. UnscheduledCandidate, } @@ -235,35 +228,6 @@ pub mod pallet { } } - /// Collect all freed cores based on storage data. (i.e. append cores freed from timeouts to - /// the given `freed_concluded`). - /// - /// The parameter `freed_concluded` contains all core indicies that became - /// free due to candidate that became available. - pub(crate) fn collect_all_freed_cores( - freed_concluded: I, - ) -> BTreeMap - where - I: core::iter::IntoIterator, - T: Config, - { - // Handle timeouts for any availability core work. - let freed_timeout = if >::availability_timeout_check_required() { - let pred = >::availability_timeout_predicate(); - >::collect_pending(pred) - } else { - Vec::new() - }; - - // Schedule paras again, given freed cores, and reasons for freeing. - let freed = freed_concluded - .into_iter() - .map(|(c, _hash)| (c, FreedReason::Concluded)) - .chain(freed_timeout.into_iter().map(|c| (c, FreedReason::TimedOut))) - .collect::>(); - freed - } - #[pallet::call] impl Pallet { /// Enter the paras inherent. This will process bitfields and backed candidates. @@ -319,7 +283,7 @@ impl Pallet { /// Process inherent data. /// /// The given inherent data is processed and state is altered accordingly. If any data could - /// not be applied (inconsitencies, weight limit, ...) it is removed. + /// not be applied (inconsistencies, weight limit, ...) it is removed. /// /// When called from `create_inherent` the `context` must be set to /// `ProcessInherentDataContext::ProvideInherent` so it guarantees the invariant that inherent @@ -526,7 +490,7 @@ impl Pallet { // Contains the disputes that are concluded in the current session only, // since these are the only ones that are relevant for the occupied cores - // and lightens the load on `collect_disputed` significantly. + // and lightens the load on `free_disputed` significantly. // Cores can't be occupied with candidates of the previous sessions, and only // things with new votes can have just concluded. We only need to collect // cores with disputes that conclude just now, because disputes that @@ -542,21 +506,17 @@ impl Pallet { .map(|(_session, candidate)| candidate) .collect::>(); - let freed_disputed: BTreeMap = - >::collect_disputed(¤t_concluded_invalid_disputes) + // Get the cores freed as a result of concluded invalid candidates. + let (freed_disputed, concluded_invalid_hashes): (Vec, BTreeSet) = + >::free_disputed(¤t_concluded_invalid_disputes) .into_iter() - .map(|core| (core, FreedReason::Concluded)) - .collect(); + .unzip(); // Create a bit index from the set of core indices where each index corresponds to // a core index that was freed due to a dispute. // // I.e. 010100 would indicate, the candidates on Core 1 and 3 would be disputed. - let disputed_bitfield = create_disputed_bitfield(expected_bits, freed_disputed.keys()); - - if !freed_disputed.is_empty() { - >::free_cores_and_fill_claimqueue(freed_disputed.clone(), now); - } + let disputed_bitfield = create_disputed_bitfield(expected_bits, freed_disputed.iter()); let bitfields = sanitize_bitfields::( bitfields, @@ -571,11 +531,9 @@ impl Pallet { // Process new availability bitfields, yielding any availability cores whose // work has now concluded. let freed_concluded = - >::update_pending_availability_and_get_freed_cores::<_>( - expected_bits, + >::update_pending_availability_and_get_freed_cores( &validator_public[..], bitfields.clone(), - >::core_para, ); // Inform the disputes module of all included candidates. @@ -585,8 +543,24 @@ impl Pallet { METRICS.on_candidates_included(freed_concluded.len() as u64); - let freed = collect_all_freed_cores::(freed_concluded.iter().cloned()); + // Get the timed out candidates + let freed_timeout = if >::availability_timeout_check_required() { + >::free_timedout() + } else { + Vec::new() + }; + + if !freed_timeout.is_empty() { + log::debug!(target: LOG_TARGET, "Evicted timed out cores: {:?}", freed_timeout); + } + // We'll schedule paras again, given freed cores, and reasons for freeing. + let freed = freed_concluded + .into_iter() + .map(|(c, _hash)| (c, FreedReason::Concluded)) + .chain(freed_disputed.into_iter().map(|core| (core, FreedReason::Concluded))) + .chain(freed_timeout.into_iter().map(|c| (c, FreedReason::TimedOut))) + .collect::>(); >::free_cores_and_fill_claimqueue(freed, now); METRICS.on_candidates_processed_total(backed_candidates.len() as u64); @@ -605,55 +579,28 @@ impl Pallet { scheduled.entry(para_id).or_default().insert(core_idx); } - let SanitizedBackedCandidates { - backed_candidates_with_core, - votes_from_disabled_were_dropped, - dropped_unscheduled_candidates, - } = sanitize_backed_candidates::( + let initial_candidate_count = backed_candidates.len(); + let backed_candidates_with_core = sanitize_backed_candidates::( backed_candidates, &allowed_relay_parents, - |candidate_idx: usize, - backed_candidate: &BackedCandidate<::Hash>| - -> bool { - let para_id = backed_candidate.descriptor().para_id; - let prev_context = >::para_most_recent_context(para_id); - let check_ctx = CandidateCheckContext::::new(prev_context); - - // never include a concluded-invalid candidate - current_concluded_invalid_disputes.contains(&backed_candidate.hash()) || - // Instead of checking the candidates with code upgrades twice - // move the checking up here and skip it in the training wheels fallback. - // That way we avoid possible duplicate checks while assuring all - // backed candidates fine to pass on. - // - // NOTE: this is the only place where we check the relay-parent. - check_ctx - .verify_backed_candidate(&allowed_relay_parents, candidate_idx, backed_candidate.candidate()) - .is_err() - }, + concluded_invalid_hashes, scheduled, core_index_enabled, ); + let count = count_backed_candidates(&backed_candidates_with_core); - ensure!( - backed_candidates_with_core.len() <= total_scheduled_cores, - Error::::UnscheduledCandidate - ); - - METRICS.on_candidates_sanitized(backed_candidates_with_core.len() as u64); + ensure!(count <= total_scheduled_cores, Error::::UnscheduledCandidate); - // In `Enter` context (invoked during execution) there should be no backing votes from - // disabled validators because they should have been filtered out during inherent data - // preparation (`ProvideInherent` context). Abort in such cases. - if context == ProcessInherentDataContext::Enter { - ensure!(!votes_from_disabled_were_dropped, Error::::BackedByDisabled); - } + METRICS.on_candidates_sanitized(count as u64); - // In `Enter` context (invoked during execution) we shouldn't have filtered any candidates - // due to a para not being scheduled. They have been filtered during inherent data - // preparation (`ProvideInherent` context). Abort in such cases. + // In `Enter` context (invoked during execution) no more candidates should be filtered, + // because they have already been filtered during `ProvideInherent` context. Abort in such + // cases. if context == ProcessInherentDataContext::Enter { - ensure!(!dropped_unscheduled_candidates, Error::::BackedOnUnscheduledCore); + ensure!( + initial_candidate_count == count, + Error::::CandidatesFilteredDuringExecution + ); } // Process backed candidates according to scheduled cores. @@ -662,7 +609,7 @@ impl Pallet { candidate_receipt_with_backing_validator_indices, } = >::process_candidates( &allowed_relay_parents, - backed_candidates_with_core.clone(), + &backed_candidates_with_core, >::group_validators, core_index_enabled, )?; @@ -683,10 +630,13 @@ impl Pallet { let processed = ParachainsInherentData { bitfields, - backed_candidates: backed_candidates_with_core - .into_iter() - .map(|(candidate, _)| candidate) - .collect(), + backed_candidates: backed_candidates_with_core.into_iter().fold( + Vec::with_capacity(count), + |mut acc, (_id, candidates)| { + acc.extend(candidates.into_iter().map(|(c, _)| c)); + acc + }, + ), disputes, parent_header, }; @@ -986,83 +936,86 @@ pub(crate) fn sanitize_bitfields( bitfields } -// Result from `sanitize_backed_candidates` -#[derive(Debug, PartialEq)] -struct SanitizedBackedCandidates { - // Sanitized backed candidates along with the assigned core. The `Vec` is sorted according to - // the occupied core index. - backed_candidates_with_core: Vec<(BackedCandidate, CoreIndex)>, - // Set to true if any votes from disabled validators were dropped from the input. - votes_from_disabled_were_dropped: bool, - // Set to true if any candidates were dropped due to filtering done in - // `map_candidates_to_cores` - dropped_unscheduled_candidates: bool, -} - +/// Performs various filtering on the backed candidates inherent data. +/// Must maintain the invariant that the returned candidate collection contains the candidates +/// sorted in dependency order for each para. When doing any filtering, we must therefore drop any +/// subsequent candidates after the filtered one. +/// /// Filter out: -/// 1. any candidates that have a concluded invalid dispute -/// 2. any unscheduled candidates, as well as candidates whose paraid has multiple cores assigned +/// 1. any candidates which don't form a chain with the other candidates of the paraid (even if they +/// do form a chain but are not in the right order). +/// 2. any candidates that have a concluded invalid dispute or who are descendants of a concluded +/// invalid candidate. +/// 3. any unscheduled candidates, as well as candidates whose paraid has multiple cores assigned /// but have no injected core index. -/// 3. all backing votes from disabled validators -/// 4. any candidates that end up with less than `effective_minimum_backing_votes` backing votes +/// 4. all backing votes from disabled validators +/// 5. any candidates that end up with less than `effective_minimum_backing_votes` backing votes /// -/// `scheduled` follows the same naming scheme as provided in the -/// guide: Currently `free` but might become `occupied`. -/// For the filtering here the relevant part is only the current `free` -/// state. -/// -/// `candidate_has_concluded_invalid_dispute` must return `true` if the candidate -/// is disputed, false otherwise. The passed `usize` is the candidate index. -/// -/// Returns struct `SanitizedBackedCandidates` where `backed_candidates` are sorted according to the -/// occupied core index. -fn sanitize_backed_candidates< - T: crate::inclusion::Config, - F: FnMut(usize, &BackedCandidate) -> bool, ->( - mut backed_candidates: Vec>, +/// Returns the scheduled +/// backed candidates which passed filtering, mapped by para id and in the right dependency order. +fn sanitize_backed_candidates( + backed_candidates: Vec>, allowed_relay_parents: &AllowedRelayParentsTracker>, - mut candidate_has_concluded_invalid_dispute_or_is_invalid: F, + concluded_invalid_with_descendants: BTreeSet, scheduled: BTreeMap>, core_index_enabled: bool, -) -> SanitizedBackedCandidates { - // Remove any candidates that were concluded invalid. - // This does not assume sorting. - backed_candidates.indexed_retain(move |candidate_idx, backed_candidate| { - !candidate_has_concluded_invalid_dispute_or_is_invalid(candidate_idx, backed_candidate) +) -> BTreeMap, CoreIndex)>> { + // Map the candidates to the right paraids, while making sure that the order between candidates + // of the same para is preserved. + let mut candidates_per_para: BTreeMap> = BTreeMap::new(); + for candidate in backed_candidates { + candidates_per_para + .entry(candidate.descriptor().para_id) + .or_default() + .push(candidate); + } + + // Check that candidates pertaining to the same para form a chain. Drop the ones that + // don't, along with the rest of candidates which follow them in the input vector. + filter_unchained_candidates::(&mut candidates_per_para, allowed_relay_parents); + + // Remove any candidates that were concluded invalid or who are descendants of concluded invalid + // candidates (along with their descendants). + retain_candidates::(&mut candidates_per_para, |_, candidate| { + let keep = !concluded_invalid_with_descendants.contains(&candidate.candidate().hash()); + + if !keep { + log::debug!( + target: LOG_TARGET, + "Found backed candidate {:?} which was concluded invalid or is a descendant of a concluded invalid candidate, for paraid {:?}.", + candidate.candidate().hash(), + candidate.descriptor().para_id + ); + } + keep }); - let initial_candidate_count = backed_candidates.len(); - // Map candidates to scheduled cores. Filter out any unscheduled candidates. + // Map candidates to scheduled cores. Filter out any unscheduled candidates along with their + // descendants. let mut backed_candidates_with_core = map_candidates_to_cores::( &allowed_relay_parents, scheduled, core_index_enabled, - backed_candidates, + candidates_per_para, ); - let dropped_unscheduled_candidates = - initial_candidate_count != backed_candidates_with_core.len(); - - // Filter out backing statements from disabled validators - let votes_from_disabled_were_dropped = filter_backed_statements_from_disabled_validators::( + // Filter out backing statements from disabled validators. If by that we render a candidate with + // less backing votes than required, filter that candidate also. As all the other filtering + // operations above, we drop the descendants of the dropped candidates also. + filter_backed_statements_from_disabled_validators::( &mut backed_candidates_with_core, &allowed_relay_parents, core_index_enabled, ); - // Sort the `Vec` last, once there is a guarantee that these - // `BackedCandidates` references the expected relay chain parent, - // but more importantly are scheduled for a free core. - // This both avoids extra work for obviously invalid candidates, - // but also allows this to be done in place. - backed_candidates_with_core.sort_by(|(_x, core_x), (_y, core_y)| core_x.cmp(&core_y)); - - SanitizedBackedCandidates { - dropped_unscheduled_candidates, - votes_from_disabled_were_dropped, - backed_candidates_with_core, - } + backed_candidates_with_core +} + +fn count_backed_candidates(backed_candidates: &BTreeMap>) -> usize { + backed_candidates.iter().fold(0, |mut count, (_id, candidates)| { + count += candidates.len(); + count + }) } /// Derive entropy from babe provided per block randomness. @@ -1146,48 +1099,82 @@ fn limit_and_sanitize_disputes< } } -// Filters statements from disabled validators in `BackedCandidate`, non-scheduled candidates and -// few more sanity checks. Returns `true` if at least one statement is removed and `false` -// otherwise. -fn filter_backed_statements_from_disabled_validators( - backed_candidates_with_core: &mut Vec<( - BackedCandidate<::Hash>, - CoreIndex, - )>, +// Helper function for filtering candidates which don't pass the given predicate. When/if the first +// candidate which failes the predicate is found, all the other candidates that follow are dropped. +fn retain_candidates< + T: inclusion::Config + paras::Config + inclusion::Config, + F: FnMut(ParaId, &mut C) -> bool, + C, +>( + candidates_per_para: &mut BTreeMap>, + mut pred: F, +) { + for (para_id, candidates) in candidates_per_para.iter_mut() { + let mut latest_valid_idx = None; + + for (idx, candidate) in candidates.iter_mut().enumerate() { + if pred(*para_id, candidate) { + // Found a valid candidate. + latest_valid_idx = Some(idx); + } else { + break + } + } + + if let Some(latest_valid_idx) = latest_valid_idx { + candidates.truncate(latest_valid_idx + 1); + } else { + candidates.clear(); + } + } + + candidates_per_para.retain(|_, c| !c.is_empty()); +} + +// Filters statements from disabled validators in `BackedCandidate` and does a few more sanity +// checks. +fn filter_backed_statements_from_disabled_validators< + T: shared::Config + scheduler::Config + inclusion::Config, +>( + backed_candidates_with_core: &mut BTreeMap< + ParaId, + Vec<(BackedCandidate<::Hash>, CoreIndex)>, + >, allowed_relay_parents: &AllowedRelayParentsTracker>, core_index_enabled: bool, -) -> bool { +) { let disabled_validators = BTreeSet::<_>::from_iter(shared::Pallet::::disabled_validators().into_iter()); if disabled_validators.is_empty() { // No disabled validators - nothing to do - return false + return } - let backed_len_before = backed_candidates_with_core.len(); - - // Flag which will be returned. Set to `true` if at least one vote is filtered. - let mut filtered = false; - let minimum_backing_votes = configuration::Pallet::::config().minimum_backing_votes; // Process all backed candidates. `validator_indices` in `BackedCandidates` are indices within // the validator group assigned to the parachain. To obtain this group we need: // 1. Core index assigned to the parachain which has produced the candidate // 2. The relay chain block number of the candidate - backed_candidates_with_core.retain_mut(|(bc, core_idx)| { - let (validator_indices, maybe_core_index) = bc.validator_indices_and_core_index(core_index_enabled); + retain_candidates::(backed_candidates_with_core, |para_id, (bc, core_idx)| { + let (validator_indices, maybe_core_index) = + bc.validator_indices_and_core_index(core_index_enabled); let mut validator_indices = BitVec::<_>::from(validator_indices); - // Get relay parent block number of the candidate. We need this to get the group index assigned to this core at this block number - let relay_parent_block_number = match allowed_relay_parents - .acquire_info(bc.descriptor().relay_parent, None) { + // Get relay parent block number of the candidate. We need this to get the group index + // assigned to this core at this block number + let relay_parent_block_number = + match allowed_relay_parents.acquire_info(bc.descriptor().relay_parent, None) { Some((_, block_num)) => block_num, None => { - log::debug!(target: LOG_TARGET, "Relay parent {:?} for candidate is not in the allowed relay parents. Dropping the candidate.", bc.descriptor().relay_parent); + log::debug!( + target: LOG_TARGET, + "Relay parent {:?} for candidate is not in the allowed relay parents. Dropping the candidate.", + bc.descriptor().relay_parent + ); return false - } + }, }; // Get the group index for the core @@ -1208,12 +1195,15 @@ fn filter_backed_statements_from_disabled_validators { log::debug!(target: LOG_TARGET, "Can't get the validators from group {:?}. Dropping the candidate.", group_idx); return false - } + }, }; // Bitmask with the disabled indices within the validator group - let disabled_indices = BitVec::::from_iter(validator_group.iter().map(|idx| disabled_validators.contains(idx))); - // The indices of statements from disabled validators in `BackedCandidate`. We have to drop these. + let disabled_indices = BitVec::::from_iter( + validator_group.iter().map(|idx| disabled_validators.contains(idx)), + ); + // The indices of statements from disabled validators in `BackedCandidate`. We have to drop + // these. let indices_to_drop = disabled_indices.clone() & &validator_indices; // Apply the bitmask to drop the disabled validator from `validator_indices` validator_indices &= !disabled_indices; @@ -1225,62 +1215,218 @@ fn filter_backed_statements_from_disabled_validators 0 { - filtered = true; - } - // By filtering votes we might render the candidate invalid and cause a failure in // [`process_candidates`]. To avoid this we have to perform a sanity check here. If there // are not enough backing votes after filtering we will remove the whole candidate. - if bc.validity_votes().len() < effective_minimum_backing_votes( - validator_group.len(), - minimum_backing_votes - ) { + if bc.validity_votes().len() < + effective_minimum_backing_votes(validator_group.len(), minimum_backing_votes) + { + log::debug!( + target: LOG_TARGET, + "Dropping candidate {:?} of paraid {:?} because it was left with too few backing votes after votes from disabled validators were filtered.", + bc.candidate().hash(), + para_id + ); + return false } true }); +} + +// Check that candidates pertaining to the same para form a chain. Drop the ones that +// don't, along with the rest of candidates which follow them in the input vector. +// In the process, duplicated candidates will also be dropped (even if they form a valid cycle; +// cycles are not allowed if they entail backing duplicated candidates). +fn filter_unchained_candidates( + candidates: &mut BTreeMap>>, + allowed_relay_parents: &AllowedRelayParentsTracker>, +) { + let mut para_latest_head_data: BTreeMap = BTreeMap::new(); + for para_id in candidates.keys() { + let latest_head_data = match >::para_latest_head_data(¶_id) { + None => { + defensive!("Latest included head data for paraid {:?} is None", para_id); + continue + }, + Some(latest_head_data) => latest_head_data, + }; + para_latest_head_data.insert(*para_id, latest_head_data); + } + + let mut para_visited_candidates: BTreeMap> = BTreeMap::new(); + + retain_candidates::(candidates, |para_id, candidate| { + let Some(latest_head_data) = para_latest_head_data.get(¶_id) else { return false }; + let candidate_hash = candidate.candidate().hash(); + + let visited_candidates = + para_visited_candidates.entry(para_id).or_insert_with(|| BTreeSet::new()); + if visited_candidates.contains(&candidate_hash) { + log::debug!( + target: LOG_TARGET, + "Found duplicate candidates for paraid {:?}. Dropping the candidates with hash {:?}", + para_id, + candidate_hash + ); + + // If we got a duplicate candidate, stop. + return false + } else { + visited_candidates.insert(candidate_hash); + } + + let prev_context = >::para_most_recent_context(para_id); + let check_ctx = CandidateCheckContext::::new(prev_context); + + let res = match check_ctx.verify_backed_candidate( + &allowed_relay_parents, + candidate.candidate(), + latest_head_data.clone(), + ) { + Ok(_) => true, + Err(err) => { + log::debug!( + target: LOG_TARGET, + "Backed candidate verification for candidate {:?} of paraid {:?} failed with {:?}", + candidate_hash, + para_id, + err + ); + false + }, + }; + + if res { + para_latest_head_data + .insert(para_id, candidate.candidate().commitments.head_data.clone()); + } - // Also return `true` if a whole candidate was dropped from the set - filtered || backed_len_before != backed_candidates_with_core.len() + res + }); } /// Map candidates to scheduled cores. -/// If the para only has one scheduled core and no `CoreIndex` is injected, map the candidate to the +/// If the para only has one scheduled core and one candidate supplied, map the candidate to the /// single core. If the para has multiple cores scheduled, only map the candidates which have a /// proper core injected. Filter out the rest. /// Also returns whether or not we dropped any candidates. +/// When dropping a candidate of a para, we must drop all subsequent candidates from that para +/// (because they form a chain). fn map_candidates_to_cores( allowed_relay_parents: &AllowedRelayParentsTracker>, mut scheduled: BTreeMap>, core_index_enabled: bool, - candidates: Vec>, -) -> Vec<(BackedCandidate, CoreIndex)> { - let mut backed_candidates_with_core = Vec::with_capacity(candidates.len()); - - // We keep a candidate if the parachain has only one core assigned or if - // a core index is provided by block author and it's indeed scheduled. - for backed_candidate in candidates { - let maybe_injected_core_index = get_injected_core_index::( - allowed_relay_parents, - &backed_candidate, - core_index_enabled, - ); + candidates: BTreeMap>>, +) -> BTreeMap, CoreIndex)>> { + let mut backed_candidates_with_core = BTreeMap::new(); + + for (para_id, backed_candidates) in candidates.into_iter() { + if backed_candidates.len() == 0 { + defensive!("Backed candidates for paraid {} is empty.", para_id); + continue + } - let scheduled_cores = scheduled.get_mut(&backed_candidate.descriptor().para_id); - // Candidates without scheduled cores are silently filtered out. + let scheduled_cores = scheduled.get_mut(¶_id); + + // ParaIds without scheduled cores are silently filtered out. if let Some(scheduled_cores) = scheduled_cores { - if let Some(core_idx) = maybe_injected_core_index { - if scheduled_cores.contains(&core_idx) { - scheduled_cores.remove(&core_idx); - backed_candidates_with_core.push((backed_candidate, core_idx)); + if scheduled_cores.len() == 0 { + log::debug!( + target: LOG_TARGET, + "Paraid: {:?} has no scheduled cores but {} candidates were supplied.", + para_id, + backed_candidates.len() + ); + + // Non-elastic scaling case. One core per para. + } else if scheduled_cores.len() == 1 && !core_index_enabled { + backed_candidates_with_core.insert( + para_id, + vec![( + // We need the first one here, as we assume candidates of a para are in + // dependency order. + backed_candidates.into_iter().next().expect("Length is at least 1"), + scheduled_cores.pop_first().expect("Length is 1"), + )], + ); + continue; + + // Elastic scaling case. We only allow candidates which have the right core + // indices injected. + } else if scheduled_cores.len() >= 1 && core_index_enabled { + // We must preserve the dependency order given in the input. + let mut temp_backed_candidates = Vec::with_capacity(scheduled_cores.len()); + + for candidate in backed_candidates { + if scheduled_cores.len() == 0 { + // We've got candidates for all of this para's assigned cores. Move on to + // the next para. + log::debug!( + target: LOG_TARGET, + "Found enough candidates for paraid: {:?}.", + candidate.descriptor().para_id + ); + break; + } + let maybe_injected_core_index: Option = + get_injected_core_index::(allowed_relay_parents, &candidate); + + if let Some(core_index) = maybe_injected_core_index { + if scheduled_cores.remove(&core_index) { + temp_backed_candidates.push((candidate, core_index)); + } else { + // if we got a candidate for a core index which is not scheduled, stop + // the work for this para. the already processed candidate chain in + // temp_backed_candidates is still fine though. + log::debug!( + target: LOG_TARGET, + "Found a backed candidate {:?} with injected core index {}, which is not scheduled for paraid {:?}.", + candidate.candidate().hash(), + core_index.0, + candidate.descriptor().para_id + ); + + break; + } + } else { + // if we got a candidate which does not contain its core index, stop the + // work for this para. the already processed candidate chain in + // temp_backed_candidates is still fine though. + + log::debug!( + target: LOG_TARGET, + "Found a backed candidate {:?} with no injected core index, for paraid {:?} which has multiple scheduled cores.", + candidate.candidate().hash(), + candidate.descriptor().para_id + ); + + break; + } } - } else if scheduled_cores.len() == 1 { - backed_candidates_with_core - .push((backed_candidate, scheduled_cores.pop_first().expect("Length is 1"))); + + if !temp_backed_candidates.is_empty() { + backed_candidates_with_core + .entry(para_id) + .or_insert_with(|| vec![]) + .extend(temp_backed_candidates); + } + } else { + log::warn!( + target: LOG_TARGET, + "Found a paraid {:?} which has multiple scheduled cores but ElasticScalingMVP feature is not enabled: {:?}", + para_id, + scheduled_cores + ); } + } else { + log::debug!( + target: LOG_TARGET, + "Paraid: {:?} has no scheduled cores but {} candidates were supplied.", + para_id, + backed_candidates.len() + ); } } @@ -1290,13 +1436,11 @@ fn map_candidates_to_cores( allowed_relay_parents: &AllowedRelayParentsTracker>, candidate: &BackedCandidate, - core_index_enabled: bool, ) -> Option { // After stripping the 8 bit extensions, the `validator_indices` field length is expected // to be equal to backing group size. If these don't match, the `CoreIndex` is badly encoded, // or not supported. - let (validator_indices, maybe_core_idx) = - candidate.validator_indices_and_core_index(core_index_enabled); + let (validator_indices, maybe_core_idx) = candidate.validator_indices_and_core_index(true); let Some(core_idx) = maybe_core_idx else { return None }; @@ -1306,7 +1450,7 @@ fn get_injected_core_index { log::debug!( target: LOG_TARGET, - "Relay parent {:?} for candidate {:?} is not in the allowed relay parents. Dropping the candidate.", + "Relay parent {:?} for candidate {:?} is not in the allowed relay parents.", candidate.descriptor().relay_parent, candidate.candidate().hash(), ); @@ -1323,9 +1467,8 @@ fn get_injected_core_index { log::debug!( target: LOG_TARGET, - "Can't get the group index for core idx {:?}. Dropping the candidate {:?}.", + "Can't get the group index for core idx {:?}.", core_idx, - candidate.candidate().hash(), ); return None }, @@ -1339,6 +1482,14 @@ fn get_injected_core_index MockGenesisConfig { + MockGenesisConfig { + configuration: configuration::GenesisConfig { + config: HostConfiguration { + max_head_data_size: 0b100000, + scheduler_params: SchedulerParams { + group_rotation_frequency: u32::MAX, + ..Default::default() + }, + ..Default::default() + }, + }, + ..Default::default() + } +} + // In order to facilitate benchmarks as tests we have a benchmark feature gated `WeightInfo` impl // that uses 0 for all the weights. Because all the weights are 0, the tests that rely on // weights for limiting data will fail, so we don't run them when using the benchmark feature. #[cfg(not(feature = "runtime-benchmarks"))] mod enter { - use super::{inclusion::tests::TestCandidateBuilder, *}; use crate::{ builder::{Bench, BenchBuilder}, - mock::{mock_assigner, new_test_ext, BlockLength, BlockWeights, MockGenesisConfig, Test}, + mock::{mock_assigner, new_test_ext, BlockLength, BlockWeights, RuntimeOrigin, Test}, scheduler::{ common::{Assignment, AssignmentProvider}, ParasEntry, }, + session_info, }; use assert_matches::assert_matches; + use core::panic; use frame_support::assert_ok; use frame_system::limits; - use primitives::vstaging::SchedulerParams; + use primitives::{vstaging::SchedulerParams, AvailabilityBitfield, UncheckedSigned}; use sp_runtime::Perbill; use sp_std::collections::btree_map::BTreeMap; @@ -45,6 +68,8 @@ mod enter { num_validators_per_core: u32, code_upgrade: Option, fill_claimqueue: bool, + elastic_paras: BTreeMap, + unavailable_cores: Vec, } fn make_inherent_data( @@ -55,25 +80,39 @@ mod enter { num_validators_per_core, code_upgrade, fill_claimqueue, + elastic_paras, + unavailable_cores, }: TestConfig, ) -> Bench { + let extra_cores = elastic_paras + .values() + .map(|count| *count as usize) + .sum::() + .saturating_sub(elastic_paras.len() as usize); + let total_cores = dispute_sessions.len() + backed_and_concluding.len() + extra_cores; + let builder = BenchBuilder::::new() - .set_max_validators( - (dispute_sessions.len() + backed_and_concluding.len()) as u32 * - num_validators_per_core, - ) + .set_max_validators((total_cores) as u32 * num_validators_per_core) + .set_elastic_paras(elastic_paras.clone()) .set_max_validators_per_core(num_validators_per_core) .set_dispute_statements(dispute_statements) - .set_backed_and_concluding_paras(backed_and_concluding) + .set_backed_and_concluding_paras(backed_and_concluding.clone()) .set_dispute_sessions(&dispute_sessions[..]) - .set_fill_claimqueue(fill_claimqueue); + .set_fill_claimqueue(fill_claimqueue) + .set_unavailable_cores(unavailable_cores); // Setup some assignments as needed: mock_assigner::Pallet::::set_core_count(builder.max_cores()); - for core_index in 0..builder.max_cores() { - // Core index == para_id in this case - mock_assigner::Pallet::::add_test_assignment(Assignment::Bulk(core_index.into())); - } + + (0..(builder.max_cores() as usize - extra_cores)).for_each(|para_id| { + (0..elastic_paras.get(&(para_id as u32)).cloned().unwrap_or(1)).for_each( + |_para_local_core_idx| { + mock_assigner::Pallet::::add_test_assignment(Assignment::Bulk( + para_id.into(), + )); + }, + ); + }); if let Some(code_size) = code_upgrade { builder.set_code_upgrade(code_size).build() @@ -104,6 +143,8 @@ mod enter { num_validators_per_core: 1, code_upgrade: None, fill_claimqueue: false, + elastic_paras: BTreeMap::new(), + unavailable_cores: vec![], }); // We expect the scenario to have cores 0 & 1 with pending availability. The backed @@ -145,6 +186,305 @@ mod enter { Pallet::::on_chain_votes().unwrap().session, 2 ); + + assert_eq!( + inclusion::PendingAvailability::::get(ParaId::from(0)) + .unwrap() + .into_iter() + .map(|c| c.core_occupied()) + .collect::>(), + vec![CoreIndex(0)] + ); + assert_eq!( + inclusion::PendingAvailability::::get(ParaId::from(1)) + .unwrap() + .into_iter() + .map(|c| c.core_occupied()) + .collect::>(), + vec![CoreIndex(1)] + ); + }); + } + + #[test] + fn include_backed_candidates_elastic_scaling() { + // ParaId 0 has one pending candidate on core 0. + // ParaId 1 has one pending candidate on core 1. + // ParaId 2 has three pending candidates on cores 2, 3 and 4. + // All of them are being made available in this block. Propose 5 more candidates (one for + // each core) and check that they're successfully backed and the old ones enacted. + let config = default_config(); + assert!(config.configuration.config.scheduler_params.lookahead > 0); + new_test_ext(config).execute_with(|| { + // Set the elastic scaling MVP feature. + >::set_node_feature( + RuntimeOrigin::root(), + FeatureIndex::ElasticScalingMVP as u8, + true, + ) + .unwrap(); + + let dispute_statements = BTreeMap::new(); + + let mut backed_and_concluding = BTreeMap::new(); + backed_and_concluding.insert(0, 1); + backed_and_concluding.insert(1, 1); + backed_and_concluding.insert(2, 1); + + let scenario = make_inherent_data(TestConfig { + dispute_statements, + dispute_sessions: vec![], // No disputes + backed_and_concluding, + num_validators_per_core: 1, + code_upgrade: None, + fill_claimqueue: false, + elastic_paras: [(2, 3)].into_iter().collect(), + unavailable_cores: vec![], + }); + + let expected_para_inherent_data = scenario.data.clone(); + + // Check the para inherent data is as expected: + // * 1 bitfield per validator (5 validators) + assert_eq!(expected_para_inherent_data.bitfields.len(), 5); + // * 1 backed candidate per core (5 cores) + assert_eq!(expected_para_inherent_data.backed_candidates.len(), 5); + // * 0 disputes. + assert_eq!(expected_para_inherent_data.disputes.len(), 0); + let mut inherent_data = InherentData::new(); + inherent_data + .put_data(PARACHAINS_INHERENT_IDENTIFIER, &expected_para_inherent_data) + .unwrap(); + + // The current schedule is empty prior to calling `create_inherent_enter`. + assert!(>::claimqueue_is_empty()); + + assert!(Pallet::::on_chain_votes().is_none()); + + // Nothing is filtered out (including the backed candidates.) + assert_eq!( + Pallet::::create_inherent_inner(&inherent_data.clone()).unwrap(), + expected_para_inherent_data + ); + + assert_eq!( + // The length of this vec is equal to the number of candidates, so we know our 5 + // backed candidates did not get filtered out + Pallet::::on_chain_votes().unwrap().backing_validators_per_candidate.len(), + 5 + ); + + assert_eq!( + // The session of the on chain votes should equal the current session, which is 2 + Pallet::::on_chain_votes().unwrap().session, + 2 + ); + + assert_eq!( + inclusion::PendingAvailability::::get(ParaId::from(0)) + .unwrap() + .into_iter() + .map(|c| c.core_occupied()) + .collect::>(), + vec![CoreIndex(0)] + ); + assert_eq!( + inclusion::PendingAvailability::::get(ParaId::from(1)) + .unwrap() + .into_iter() + .map(|c| c.core_occupied()) + .collect::>(), + vec![CoreIndex(1)] + ); + assert_eq!( + inclusion::PendingAvailability::::get(ParaId::from(2)) + .unwrap() + .into_iter() + .map(|c| c.core_occupied()) + .collect::>(), + vec![CoreIndex(2), CoreIndex(3), CoreIndex(4)] + ); + }); + + // ParaId 0 has one pending candidate on core 0. + // ParaId 1 has one pending candidate on core 1. + // ParaId 2 has 4 pending candidates on cores 2, 3, 4 and 5. + // Cores 1, 2 and 3 are being made available in this block. Propose 6 more candidates (one + // for each core) and check that the right ones are successfully backed and the old ones + // enacted. + let config = default_config(); + assert!(config.configuration.config.scheduler_params.lookahead > 0); + new_test_ext(config).execute_with(|| { + // Set the elastic scaling MVP feature. + >::set_node_feature( + RuntimeOrigin::root(), + FeatureIndex::ElasticScalingMVP as u8, + true, + ) + .unwrap(); + + let mut backed_and_concluding = BTreeMap::new(); + backed_and_concluding.insert(0, 1); + backed_and_concluding.insert(1, 1); + backed_and_concluding.insert(2, 1); + + // Modify the availability bitfields so that cores 0, 4 and 5 are not being made + // available. + let unavailable_cores = vec![0, 4, 5]; + + let scenario = make_inherent_data(TestConfig { + dispute_statements: BTreeMap::new(), + dispute_sessions: vec![], // No disputes + backed_and_concluding, + num_validators_per_core: 1, + code_upgrade: None, + fill_claimqueue: true, + elastic_paras: [(2, 4)].into_iter().collect(), + unavailable_cores: unavailable_cores.clone(), + }); + + let mut expected_para_inherent_data = scenario.data.clone(); + + // Check the para inherent data is as expected: + // * 1 bitfield per validator (6 validators) + assert_eq!(expected_para_inherent_data.bitfields.len(), 6); + // * 1 backed candidate per core (6 cores) + assert_eq!(expected_para_inherent_data.backed_candidates.len(), 6); + // * 0 disputes. + assert_eq!(expected_para_inherent_data.disputes.len(), 0); + assert!(Pallet::::on_chain_votes().is_none()); + + expected_para_inherent_data.backed_candidates = expected_para_inherent_data + .backed_candidates + .into_iter() + .filter(|candidate| { + let (_, Some(core_index)) = candidate.validator_indices_and_core_index(true) + else { + panic!("Core index must have been injected"); + }; + !unavailable_cores.contains(&core_index.0) + }) + .collect(); + + let mut inherent_data = InherentData::new(); + inherent_data.put_data(PARACHAINS_INHERENT_IDENTIFIER, &scenario.data).unwrap(); + + assert!(!>::claimqueue_is_empty()); + + // The right candidates have been filtered out (the ones for cores 0,4,5) + assert_eq!( + Pallet::::create_inherent_inner(&inherent_data.clone()).unwrap(), + expected_para_inherent_data + ); + + // 3 candidates have been backed (for cores 1,2 and 3) + assert_eq!( + Pallet::::on_chain_votes().unwrap().backing_validators_per_candidate.len(), + 3 + ); + + assert_eq!( + // The session of the on chain votes should equal the current session, which is 2 + Pallet::::on_chain_votes().unwrap().session, + 2 + ); + + assert_eq!( + inclusion::PendingAvailability::::get(ParaId::from(1)) + .unwrap() + .into_iter() + .map(|c| c.core_occupied()) + .collect::>(), + vec![CoreIndex(1)] + ); + assert_eq!( + inclusion::PendingAvailability::::get(ParaId::from(2)) + .unwrap() + .into_iter() + .map(|c| c.core_occupied()) + .collect::>(), + vec![CoreIndex(4), CoreIndex(5), CoreIndex(2), CoreIndex(3)] + ); + + let expected_heads = (0..=2) + .map(|id| { + inclusion::PendingAvailability::::get(ParaId::from(id)) + .unwrap() + .back() + .unwrap() + .candidate_commitments() + .head_data + .clone() + }) + .collect::>(); + + // Now just make all candidates available. + let mut data = scenario.data.clone(); + let validators = session_info::Pallet::::session_info(2).unwrap().validators; + let signing_context = SigningContext { + parent_hash: BenchBuilder::::header(4).hash(), + session_index: 2, + }; + + data.backed_candidates.clear(); + + data.bitfields.iter_mut().enumerate().for_each(|(i, bitfield)| { + let unchecked_signed = UncheckedSigned::::benchmark_sign( + validators.get(ValidatorIndex(i as u32)).unwrap(), + bitvec::bitvec![u8, bitvec::order::Lsb0; 1; 6].into(), + &signing_context, + ValidatorIndex(i as u32), + ); + *bitfield = unchecked_signed; + }); + let mut inherent_data = InherentData::new(); + inherent_data.put_data(PARACHAINS_INHERENT_IDENTIFIER, &data).unwrap(); + + // Nothing has been filtered out. + assert_eq!( + Pallet::::create_inherent_inner(&inherent_data.clone()).unwrap(), + data + ); + + // No more candidates have been backed + assert!(Pallet::::on_chain_votes() + .unwrap() + .backing_validators_per_candidate + .is_empty()); + + // No more pending availability candidates + assert_eq!( + inclusion::PendingAvailability::::get(ParaId::from(0)) + .unwrap() + .into_iter() + .map(|c| c.core_occupied()) + .collect::>(), + vec![] + ); + assert_eq!( + inclusion::PendingAvailability::::get(ParaId::from(1)) + .unwrap() + .into_iter() + .map(|c| c.core_occupied()) + .collect::>(), + vec![] + ); + assert_eq!( + inclusion::PendingAvailability::::get(ParaId::from(2)) + .unwrap() + .into_iter() + .map(|c| c.core_occupied()) + .collect::>(), + vec![] + ); + + // Paras have the right on-chain heads now + expected_heads.into_iter().enumerate().for_each(|(id, head)| { + assert_eq!( + paras::Pallet::::para_head(ParaId::from(id as u32)).unwrap(), + head + ); + }); }); } @@ -255,6 +595,8 @@ mod enter { num_validators_per_core: 5, code_upgrade: None, fill_claimqueue: false, + elastic_paras: BTreeMap::new(), + unavailable_cores: vec![], }); let expected_para_inherent_data = scenario.data.clone(); @@ -326,6 +668,8 @@ mod enter { num_validators_per_core: 6, code_upgrade: None, fill_claimqueue: false, + elastic_paras: BTreeMap::new(), + unavailable_cores: vec![], }); let expected_para_inherent_data = scenario.data.clone(); @@ -395,6 +739,8 @@ mod enter { num_validators_per_core: 4, code_upgrade: None, fill_claimqueue: false, + elastic_paras: BTreeMap::new(), + unavailable_cores: vec![], }); let expected_para_inherent_data = scenario.data.clone(); @@ -480,6 +826,8 @@ mod enter { num_validators_per_core: 5, code_upgrade: None, fill_claimqueue: false, + elastic_paras: BTreeMap::new(), + unavailable_cores: vec![], }); let expected_para_inherent_data = scenario.data.clone(); @@ -565,6 +913,8 @@ mod enter { num_validators_per_core: 5, code_upgrade: None, fill_claimqueue: false, + elastic_paras: BTreeMap::new(), + unavailable_cores: vec![], }); let expected_para_inherent_data = scenario.data.clone(); @@ -649,6 +999,8 @@ mod enter { num_validators_per_core: 5, code_upgrade: None, fill_claimqueue: false, + elastic_paras: BTreeMap::new(), + unavailable_cores: vec![], }); let expected_para_inherent_data = scenario.data.clone(); @@ -754,6 +1106,8 @@ mod enter { num_validators_per_core: 5, code_upgrade: None, fill_claimqueue: false, + elastic_paras: BTreeMap::new(), + unavailable_cores: vec![], }); let expected_para_inherent_data = scenario.data.clone(); @@ -820,6 +1174,8 @@ mod enter { num_validators_per_core: 5, code_upgrade: None, fill_claimqueue: false, + elastic_paras: BTreeMap::new(), + unavailable_cores: vec![], }); let expected_para_inherent_data = scenario.data.clone(); @@ -884,6 +1240,8 @@ mod enter { num_validators_per_core: 5, code_upgrade: None, fill_claimqueue: false, + elastic_paras: BTreeMap::new(), + unavailable_cores: vec![], }); let expected_para_inherent_data = scenario.data.clone(); @@ -985,6 +1343,8 @@ mod enter { num_validators_per_core: 5, code_upgrade: None, fill_claimqueue: false, + elastic_paras: BTreeMap::new(), + unavailable_cores: vec![], }); let mut para_inherent_data = scenario.data.clone(); @@ -1072,6 +1432,8 @@ mod enter { num_validators_per_core: 5, code_upgrade: None, fill_claimqueue: false, + elastic_paras: BTreeMap::new(), + unavailable_cores: vec![], }); let expected_para_inherent_data = scenario.data.clone(); @@ -1119,7 +1481,7 @@ mod sanitizers { inclusion::tests::{ back_candidate, collator_sign_candidate, BackingKind, TestCandidateBuilder, }, - mock::{new_test_ext, MockGenesisConfig}, + mock::new_test_ext, }; use bitvec::order::Lsb0; use primitives::{ @@ -1375,9 +1737,11 @@ mod sanitizers { mod candidates { use crate::{ - mock::set_disabled_validators, + mock::{set_disabled_validators, RuntimeOrigin}, scheduler::{common::Assignment, ParasEntry}, + util::{make_persisted_validation_data, make_persisted_validation_data_with_parent}, }; + use primitives::ValidationCode; use sp_std::collections::vec_deque::VecDeque; use super::*; @@ -1385,13 +1749,14 @@ mod sanitizers { // Backed candidates and scheduled parachains used for `sanitize_backed_candidates` testing struct TestData { backed_candidates: Vec, - all_backed_candidates_with_core: Vec<(BackedCandidate, CoreIndex)>, + expected_backed_candidates_with_core: + BTreeMap>, scheduled_paras: BTreeMap>, } - // Generate test data for the candidates and assert that the evnironment is set as expected + // Generate test data for the candidates and assert that the environment is set as expected // (check the comments for details) - fn get_test_data(core_index_enabled: bool) -> TestData { + fn get_test_data_one_core_per_para(core_index_enabled: bool) -> TestData { const RELAY_PARENT_NUM: u32 = 3; // Add the relay parent to `shared` pallet. Otherwise some code (e.g. filtering backing @@ -1467,6 +1832,24 @@ mod sanitizers { ), ])); + // Set the on-chain included head data for paras. + paras::Pallet::::set_current_head(ParaId::from(1), HeadData(vec![1])); + paras::Pallet::::set_current_head(ParaId::from(2), HeadData(vec![2])); + + // Set the current_code_hash + paras::Pallet::::force_set_current_code( + RuntimeOrigin::root(), + ParaId::from(1), + ValidationCode(vec![1]), + ) + .unwrap(); + paras::Pallet::::force_set_current_code( + RuntimeOrigin::root(), + ParaId::from(2), + ValidationCode(vec![2]), + ) + .unwrap(); + // Callback used for backing candidates let group_validators = |group_index: GroupIndex| { match group_index { @@ -1486,8 +1869,15 @@ mod sanitizers { para_id: ParaId::from(idx1), relay_parent, pov_hash: Hash::repeat_byte(idx1 as u8), - persisted_validation_data_hash: [42u8; 32].into(), + persisted_validation_data_hash: make_persisted_validation_data::( + ParaId::from(idx1), + RELAY_PARENT_NUM, + Default::default(), + ) + .unwrap() + .hash(), hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![idx1 as u8]), ..Default::default() } .build(); @@ -1523,36 +1913,34 @@ mod sanitizers { ] ); - let all_backed_candidates_with_core = backed_candidates - .iter() - .map(|candidate| { - // Only one entry for this test data. - ( - candidate.clone(), - scheduled - .get(&candidate.descriptor().para_id) - .unwrap() - .first() - .copied() - .unwrap(), - ) - }) - .collect(); + let mut expected_backed_candidates_with_core = BTreeMap::new(); + + for candidate in backed_candidates.iter() { + let para_id = candidate.descriptor().para_id; + + expected_backed_candidates_with_core.entry(para_id).or_insert(vec![]).push(( + candidate.clone(), + scheduled.get(¶_id).unwrap().first().copied().unwrap(), + )); + } TestData { backed_candidates, scheduled_paras: scheduled, - all_backed_candidates_with_core, + expected_backed_candidates_with_core, } } - // Generate test data for the candidates and assert that the evnironment is set as expected + // Generate test data for the candidates and assert that the environment is set as expected // (check the comments for details) // Para 1 scheduled on core 0 and core 1. Two candidates are supplied. // Para 2 scheduled on cores 2 and 3. One candidate supplied. // Para 3 scheduled on core 4. One candidate supplied. // Para 4 scheduled on core 5. Two candidates supplied. // Para 5 scheduled on core 6. No candidates supplied. + // Para 6 is not scheduled. One candidate supplied. + // Para 7 is scheduled on core 7 and 8, but the candidate contains the wrong core index. + // Para 8 is scheduled on core 9, but the candidate contains the wrong core index. fn get_test_data_multiple_cores_per_para(core_index_enabled: bool) -> TestData { const RELAY_PARENT_NUM: u32 = 3; @@ -1581,6 +1969,7 @@ mod sanitizers { keyring::Sr25519Keyring::Eve, keyring::Sr25519Keyring::Ferdie, keyring::Sr25519Keyring::One, + keyring::Sr25519Keyring::Two, ]; for validator in validators.iter() { Keystore::sr25519_generate_new( @@ -1605,6 +1994,7 @@ mod sanitizers { vec![ValidatorIndex(4)], vec![ValidatorIndex(5)], vec![ValidatorIndex(6)], + vec![ValidatorIndex(7)], ]); // Update scheduler's claimqueue with the parachains @@ -1658,8 +2048,40 @@ mod sanitizers { RELAY_PARENT_NUM, )]), ), + ( + CoreIndex::from(7), + VecDeque::from([ParasEntry::new( + Assignment::Pool { para_id: 7.into(), core_index: CoreIndex(7) }, + RELAY_PARENT_NUM, + )]), + ), + ( + CoreIndex::from(8), + VecDeque::from([ParasEntry::new( + Assignment::Pool { para_id: 7.into(), core_index: CoreIndex(8) }, + RELAY_PARENT_NUM, + )]), + ), + ( + CoreIndex::from(9), + VecDeque::from([ParasEntry::new( + Assignment::Pool { para_id: 8.into(), core_index: CoreIndex(9) }, + RELAY_PARENT_NUM, + )]), + ), ])); + // Set the on-chain included head data and current code hash. + for id in 1..=8u32 { + paras::Pallet::::set_current_head(ParaId::from(id), HeadData(vec![id as u8])); + paras::Pallet::::force_set_current_code( + RuntimeOrigin::root(), + ParaId::from(id), + ValidationCode(vec![id as u8]), + ) + .unwrap(); + } + // Callback used for backing candidates let group_validators = |group_index: GroupIndex| { match group_index { @@ -1670,6 +2092,7 @@ mod sanitizers { group_index if group_index == GroupIndex::from(4) => Some(vec![4]), group_index if group_index == GroupIndex::from(5) => Some(vec![5]), group_index if group_index == GroupIndex::from(6) => Some(vec![6]), + group_index if group_index == GroupIndex::from(7) => Some(vec![7]), _ => panic!("Group index out of bounds"), } @@ -1677,7 +2100,7 @@ mod sanitizers { }; let mut backed_candidates = vec![]; - let mut all_backed_candidates_with_core = vec![]; + let mut expected_backed_candidates_with_core = BTreeMap::new(); // Para 1 { @@ -1685,14 +2108,23 @@ mod sanitizers { para_id: ParaId::from(1), relay_parent, pov_hash: Hash::repeat_byte(1 as u8), - persisted_validation_data_hash: [42u8; 32].into(), + persisted_validation_data_hash: make_persisted_validation_data::( + ParaId::from(1), + RELAY_PARENT_NUM, + Default::default(), + ) + .unwrap() + .hash(), hrmp_watermark: RELAY_PARENT_NUM, + head_data: HeadData(vec![1, 1]), + validation_code: ValidationCode(vec![1]), ..Default::default() } .build(); collator_sign_candidate(Sr25519Keyring::One, &mut candidate); + let prev_candidate = candidate.clone(); let backed: BackedCandidate = back_candidate( candidate, &validators, @@ -1704,15 +2136,26 @@ mod sanitizers { ); backed_candidates.push(backed.clone()); if core_index_enabled { - all_backed_candidates_with_core.push((backed, CoreIndex(0))); + expected_backed_candidates_with_core + .entry(ParaId::from(1)) + .or_insert(vec![]) + .push((backed, CoreIndex(0))); } let mut candidate = TestCandidateBuilder { para_id: ParaId::from(1), relay_parent, pov_hash: Hash::repeat_byte(2 as u8), - persisted_validation_data_hash: [42u8; 32].into(), + persisted_validation_data_hash: make_persisted_validation_data_with_parent::< + Test, + >( + RELAY_PARENT_NUM, + Default::default(), + prev_candidate.commitments.head_data, + ) + .hash(), hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![1]), ..Default::default() } .build(); @@ -1730,7 +2173,10 @@ mod sanitizers { ); backed_candidates.push(backed.clone()); if core_index_enabled { - all_backed_candidates_with_core.push((backed, CoreIndex(1))); + expected_backed_candidates_with_core + .entry(ParaId::from(1)) + .or_insert(vec![]) + .push((backed, CoreIndex(1))); } } @@ -1740,8 +2186,15 @@ mod sanitizers { para_id: ParaId::from(2), relay_parent, pov_hash: Hash::repeat_byte(3 as u8), - persisted_validation_data_hash: [42u8; 32].into(), + persisted_validation_data_hash: make_persisted_validation_data::( + ParaId::from(2), + RELAY_PARENT_NUM, + Default::default(), + ) + .unwrap() + .hash(), hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![2]), ..Default::default() } .build(); @@ -1759,7 +2212,10 @@ mod sanitizers { ); backed_candidates.push(backed.clone()); if core_index_enabled { - all_backed_candidates_with_core.push((backed, CoreIndex(2))); + expected_backed_candidates_with_core + .entry(ParaId::from(2)) + .or_insert(vec![]) + .push((backed, CoreIndex(2))); } } @@ -1769,8 +2225,15 @@ mod sanitizers { para_id: ParaId::from(3), relay_parent, pov_hash: Hash::repeat_byte(4 as u8), - persisted_validation_data_hash: [42u8; 32].into(), + persisted_validation_data_hash: make_persisted_validation_data::( + ParaId::from(3), + RELAY_PARENT_NUM, + Default::default(), + ) + .unwrap() + .hash(), hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![3]), ..Default::default() } .build(); @@ -1787,7 +2250,10 @@ mod sanitizers { core_index_enabled.then_some(CoreIndex(4 as u32)), ); backed_candidates.push(backed.clone()); - all_backed_candidates_with_core.push((backed, CoreIndex(4))); + expected_backed_candidates_with_core + .entry(ParaId::from(3)) + .or_insert(vec![]) + .push((backed, CoreIndex(4))); } // Para 4 @@ -1796,14 +2262,22 @@ mod sanitizers { para_id: ParaId::from(4), relay_parent, pov_hash: Hash::repeat_byte(5 as u8), - persisted_validation_data_hash: [42u8; 32].into(), + persisted_validation_data_hash: make_persisted_validation_data::( + ParaId::from(4), + RELAY_PARENT_NUM, + Default::default(), + ) + .unwrap() + .hash(), hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![4]), ..Default::default() } .build(); collator_sign_candidate(Sr25519Keyring::One, &mut candidate); + let prev_candidate = candidate.clone(); let backed = back_candidate( candidate, &validators, @@ -1811,17 +2285,28 @@ mod sanitizers { &keystore, &signing_context, BackingKind::Threshold, - None, + core_index_enabled.then_some(CoreIndex(5 as u32)), ); backed_candidates.push(backed.clone()); - all_backed_candidates_with_core.push((backed, CoreIndex(5))); + expected_backed_candidates_with_core + .entry(ParaId::from(4)) + .or_insert(vec![]) + .push((backed, CoreIndex(5))); let mut candidate = TestCandidateBuilder { para_id: ParaId::from(4), relay_parent, pov_hash: Hash::repeat_byte(6 as u8), - persisted_validation_data_hash: [42u8; 32].into(), + persisted_validation_data_hash: make_persisted_validation_data_with_parent::< + Test, + >( + RELAY_PARENT_NUM, + Default::default(), + prev_candidate.commitments.head_data, + ) + .hash(), hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![4]), ..Default::default() } .build(); @@ -1842,25 +2327,635 @@ mod sanitizers { // No candidate for para 5. - // State sanity checks - assert_eq!( - >::scheduled_paras().collect::>(), - vec![ - (CoreIndex(0), ParaId::from(1)), - (CoreIndex(1), ParaId::from(1)), - (CoreIndex(2), ParaId::from(2)), - (CoreIndex(3), ParaId::from(2)), - (CoreIndex(4), ParaId::from(3)), - (CoreIndex(5), ParaId::from(4)), - (CoreIndex(6), ParaId::from(5)), - ] - ); - let mut scheduled: BTreeMap> = BTreeMap::new(); - for (core_idx, para_id) in >::scheduled_paras() { - scheduled.entry(para_id).or_default().insert(core_idx); + // Para 6. + { + let mut candidate = TestCandidateBuilder { + para_id: ParaId::from(6), + relay_parent, + pov_hash: Hash::repeat_byte(3 as u8), + persisted_validation_data_hash: make_persisted_validation_data::( + ParaId::from(6), + RELAY_PARENT_NUM, + Default::default(), + ) + .unwrap() + .hash(), + hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![6]), + ..Default::default() + } + .build(); + + collator_sign_candidate(Sr25519Keyring::One, &mut candidate); + + let backed = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(6 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(6 as u32)), + ); + backed_candidates.push(backed.clone()); } - assert_eq!( + // Para 7. + { + let mut candidate = TestCandidateBuilder { + para_id: ParaId::from(7), + relay_parent, + pov_hash: Hash::repeat_byte(3 as u8), + persisted_validation_data_hash: make_persisted_validation_data::( + ParaId::from(7), + RELAY_PARENT_NUM, + Default::default(), + ) + .unwrap() + .hash(), + hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![7]), + ..Default::default() + } + .build(); + + collator_sign_candidate(Sr25519Keyring::One, &mut candidate); + + let backed = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(6 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(6 as u32)), + ); + backed_candidates.push(backed.clone()); + } + + // Para 8. + { + let mut candidate = TestCandidateBuilder { + para_id: ParaId::from(8), + relay_parent, + pov_hash: Hash::repeat_byte(3 as u8), + persisted_validation_data_hash: make_persisted_validation_data::( + ParaId::from(8), + RELAY_PARENT_NUM, + Default::default(), + ) + .unwrap() + .hash(), + hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![8]), + ..Default::default() + } + .build(); + + collator_sign_candidate(Sr25519Keyring::One, &mut candidate); + + let backed = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(6 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(7 as u32)), + ); + backed_candidates.push(backed.clone()); + if !core_index_enabled { + expected_backed_candidates_with_core + .entry(ParaId::from(8)) + .or_insert(vec![]) + .push((backed, CoreIndex(9))); + } + } + + // State sanity checks + assert_eq!( + >::scheduled_paras().collect::>(), + vec![ + (CoreIndex(0), ParaId::from(1)), + (CoreIndex(1), ParaId::from(1)), + (CoreIndex(2), ParaId::from(2)), + (CoreIndex(3), ParaId::from(2)), + (CoreIndex(4), ParaId::from(3)), + (CoreIndex(5), ParaId::from(4)), + (CoreIndex(6), ParaId::from(5)), + (CoreIndex(7), ParaId::from(7)), + (CoreIndex(8), ParaId::from(7)), + (CoreIndex(9), ParaId::from(8)), + ] + ); + let mut scheduled: BTreeMap> = BTreeMap::new(); + for (core_idx, para_id) in >::scheduled_paras() { + scheduled.entry(para_id).or_default().insert(core_idx); + } + + assert_eq!( + shared::Pallet::::active_validator_indices(), + vec![ + ValidatorIndex(0), + ValidatorIndex(1), + ValidatorIndex(2), + ValidatorIndex(3), + ValidatorIndex(4), + ValidatorIndex(5), + ValidatorIndex(6), + ValidatorIndex(7), + ] + ); + + TestData { + backed_candidates, + scheduled_paras: scheduled, + expected_backed_candidates_with_core, + } + } + + // Para 1 scheduled on core 0 and core 1. Two candidates are supplied. They form a chain but + // in the wrong order. + // Para 2 scheduled on core 2, core 3 and core 4. Three candidates are supplied. The second + // one is not part of the chain. + // Para 3 scheduled on core 5 and 6. Two candidates are supplied and they all form a chain. + // Para 4 scheduled on core 7 and 8. Duplicated candidates. + fn get_test_data_for_order_checks(core_index_enabled: bool) -> TestData { + const RELAY_PARENT_NUM: u32 = 3; + + // Add the relay parent to `shared` pallet. Otherwise some code (e.g. filtering backing + // votes) won't behave correctly + shared::Pallet::::add_allowed_relay_parent( + default_header().hash(), + Default::default(), + RELAY_PARENT_NUM, + 1, + ); + + let header = default_header(); + let relay_parent = header.hash(); + let session_index = SessionIndex::from(0_u32); + + let keystore = LocalKeystore::in_memory(); + let keystore = Arc::new(keystore) as KeystorePtr; + let signing_context = SigningContext { parent_hash: relay_parent, session_index }; + + let validators = vec![ + keyring::Sr25519Keyring::Alice, + keyring::Sr25519Keyring::Bob, + keyring::Sr25519Keyring::Charlie, + keyring::Sr25519Keyring::Dave, + keyring::Sr25519Keyring::Eve, + keyring::Sr25519Keyring::Ferdie, + keyring::Sr25519Keyring::One, + keyring::Sr25519Keyring::Two, + keyring::Sr25519Keyring::AliceStash, + ]; + for validator in validators.iter() { + Keystore::sr25519_generate_new( + &*keystore, + PARACHAIN_KEY_TYPE_ID, + Some(&validator.to_seed()), + ) + .unwrap(); + } + + // Set active validators in `shared` pallet + let validator_ids = + validators.iter().map(|v| v.public().into()).collect::>(); + shared::Pallet::::set_active_validators_ascending(validator_ids); + + // Set the validator groups in `scheduler` + scheduler::Pallet::::set_validator_groups(vec![ + vec![ValidatorIndex(0)], + vec![ValidatorIndex(1)], + vec![ValidatorIndex(2)], + vec![ValidatorIndex(3)], + vec![ValidatorIndex(4)], + vec![ValidatorIndex(5)], + vec![ValidatorIndex(6)], + vec![ValidatorIndex(7)], + vec![ValidatorIndex(8)], + ]); + + // Update scheduler's claimqueue with the parachains + scheduler::Pallet::::set_claimqueue(BTreeMap::from([ + ( + CoreIndex::from(0), + VecDeque::from([ParasEntry::new( + Assignment::Pool { para_id: 1.into(), core_index: CoreIndex(0) }, + RELAY_PARENT_NUM, + )]), + ), + ( + CoreIndex::from(1), + VecDeque::from([ParasEntry::new( + Assignment::Pool { para_id: 1.into(), core_index: CoreIndex(1) }, + RELAY_PARENT_NUM, + )]), + ), + ( + CoreIndex::from(2), + VecDeque::from([ParasEntry::new( + Assignment::Pool { para_id: 2.into(), core_index: CoreIndex(2) }, + RELAY_PARENT_NUM, + )]), + ), + ( + CoreIndex::from(3), + VecDeque::from([ParasEntry::new( + Assignment::Pool { para_id: 2.into(), core_index: CoreIndex(3) }, + RELAY_PARENT_NUM, + )]), + ), + ( + CoreIndex::from(4), + VecDeque::from([ParasEntry::new( + Assignment::Pool { para_id: 2.into(), core_index: CoreIndex(4) }, + RELAY_PARENT_NUM, + )]), + ), + ( + CoreIndex::from(5), + VecDeque::from([ParasEntry::new( + Assignment::Pool { para_id: 3.into(), core_index: CoreIndex(5) }, + RELAY_PARENT_NUM, + )]), + ), + ( + CoreIndex::from(6), + VecDeque::from([ParasEntry::new( + Assignment::Pool { para_id: 3.into(), core_index: CoreIndex(6) }, + RELAY_PARENT_NUM, + )]), + ), + ( + CoreIndex::from(7), + VecDeque::from([ParasEntry::new( + Assignment::Pool { para_id: 4.into(), core_index: CoreIndex(7) }, + RELAY_PARENT_NUM, + )]), + ), + ( + CoreIndex::from(8), + VecDeque::from([ParasEntry::new( + Assignment::Pool { para_id: 4.into(), core_index: CoreIndex(8) }, + RELAY_PARENT_NUM, + )]), + ), + ])); + + // Set the on-chain included head data and current code hash. + for id in 1..=4u32 { + paras::Pallet::::set_current_head(ParaId::from(id), HeadData(vec![id as u8])); + paras::Pallet::::force_set_current_code( + RuntimeOrigin::root(), + ParaId::from(id), + ValidationCode(vec![id as u8]), + ) + .unwrap(); + } + + // Callback used for backing candidates + let group_validators = |group_index: GroupIndex| { + match group_index { + group_index if group_index == GroupIndex::from(0) => Some(vec![0]), + group_index if group_index == GroupIndex::from(1) => Some(vec![1]), + group_index if group_index == GroupIndex::from(2) => Some(vec![2]), + group_index if group_index == GroupIndex::from(3) => Some(vec![3]), + group_index if group_index == GroupIndex::from(4) => Some(vec![4]), + group_index if group_index == GroupIndex::from(5) => Some(vec![5]), + group_index if group_index == GroupIndex::from(6) => Some(vec![6]), + group_index if group_index == GroupIndex::from(7) => Some(vec![7]), + group_index if group_index == GroupIndex::from(8) => Some(vec![8]), + + _ => panic!("Group index out of bounds"), + } + .map(|m| m.into_iter().map(ValidatorIndex).collect::>()) + }; + + let mut backed_candidates = vec![]; + let mut expected_backed_candidates_with_core = BTreeMap::new(); + + // Para 1 + { + let mut candidate = TestCandidateBuilder { + para_id: ParaId::from(1), + relay_parent, + pov_hash: Hash::repeat_byte(1 as u8), + persisted_validation_data_hash: make_persisted_validation_data::( + ParaId::from(1), + RELAY_PARENT_NUM, + Default::default(), + ) + .unwrap() + .hash(), + head_data: HeadData(vec![1, 1]), + hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![1]), + ..Default::default() + } + .build(); + + collator_sign_candidate(Sr25519Keyring::One, &mut candidate); + + let prev_candidate = candidate.clone(); + let prev_backed: BackedCandidate = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(0 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(0 as u32)), + ); + + let mut candidate = TestCandidateBuilder { + para_id: ParaId::from(1), + relay_parent, + pov_hash: Hash::repeat_byte(2 as u8), + persisted_validation_data_hash: make_persisted_validation_data_with_parent::< + Test, + >( + RELAY_PARENT_NUM, + Default::default(), + prev_candidate.commitments.head_data, + ) + .hash(), + hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![1]), + ..Default::default() + } + .build(); + + collator_sign_candidate(Sr25519Keyring::One, &mut candidate); + + let backed = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(1 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(1 as u32)), + ); + backed_candidates.push(backed.clone()); + backed_candidates.push(prev_backed.clone()); + } + + // Para 2. + { + let mut candidate_1 = TestCandidateBuilder { + para_id: ParaId::from(2), + relay_parent, + pov_hash: Hash::repeat_byte(3 as u8), + persisted_validation_data_hash: make_persisted_validation_data::( + ParaId::from(2), + RELAY_PARENT_NUM, + Default::default(), + ) + .unwrap() + .hash(), + head_data: HeadData(vec![2, 2]), + hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![2]), + ..Default::default() + } + .build(); + + collator_sign_candidate(Sr25519Keyring::One, &mut candidate_1); + + let backed_1: BackedCandidate = back_candidate( + candidate_1, + &validators, + group_validators(GroupIndex::from(2 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(2 as u32)), + ); + + backed_candidates.push(backed_1.clone()); + if core_index_enabled { + expected_backed_candidates_with_core + .entry(ParaId::from(2)) + .or_insert(vec![]) + .push((backed_1, CoreIndex(2))); + } + + let mut candidate_2 = TestCandidateBuilder { + para_id: ParaId::from(2), + relay_parent, + pov_hash: Hash::repeat_byte(4 as u8), + persisted_validation_data_hash: make_persisted_validation_data::( + ParaId::from(2), + RELAY_PARENT_NUM, + Default::default(), + ) + .unwrap() + .hash(), + hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![2]), + head_data: HeadData(vec![3, 3]), + ..Default::default() + } + .build(); + + collator_sign_candidate(Sr25519Keyring::One, &mut candidate_2); + + let backed_2 = back_candidate( + candidate_2.clone(), + &validators, + group_validators(GroupIndex::from(3 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(3 as u32)), + ); + backed_candidates.push(backed_2.clone()); + + let mut candidate_3 = TestCandidateBuilder { + para_id: ParaId::from(2), + relay_parent, + pov_hash: Hash::repeat_byte(5 as u8), + persisted_validation_data_hash: make_persisted_validation_data_with_parent::< + Test, + >( + RELAY_PARENT_NUM, + Default::default(), + candidate_2.commitments.head_data, + ) + .hash(), + hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![2]), + ..Default::default() + } + .build(); + + collator_sign_candidate(Sr25519Keyring::One, &mut candidate_3); + + let backed_3 = back_candidate( + candidate_3, + &validators, + group_validators(GroupIndex::from(4 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(4 as u32)), + ); + backed_candidates.push(backed_3.clone()); + } + + // Para 3 + { + let mut candidate = TestCandidateBuilder { + para_id: ParaId::from(3), + relay_parent, + pov_hash: Hash::repeat_byte(6 as u8), + persisted_validation_data_hash: make_persisted_validation_data::( + ParaId::from(3), + RELAY_PARENT_NUM, + Default::default(), + ) + .unwrap() + .hash(), + head_data: HeadData(vec![3, 3]), + hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![3]), + ..Default::default() + } + .build(); + + collator_sign_candidate(Sr25519Keyring::One, &mut candidate); + + let prev_candidate = candidate.clone(); + let backed: BackedCandidate = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(5 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(5 as u32)), + ); + backed_candidates.push(backed.clone()); + if core_index_enabled { + expected_backed_candidates_with_core + .entry(ParaId::from(3)) + .or_insert(vec![]) + .push((backed, CoreIndex(5))); + } + + let mut candidate = TestCandidateBuilder { + para_id: ParaId::from(3), + relay_parent, + pov_hash: Hash::repeat_byte(6 as u8), + persisted_validation_data_hash: make_persisted_validation_data_with_parent::< + Test, + >( + RELAY_PARENT_NUM, + Default::default(), + prev_candidate.commitments.head_data, + ) + .hash(), + hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![3]), + ..Default::default() + } + .build(); + + collator_sign_candidate(Sr25519Keyring::One, &mut candidate); + + let backed = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(6 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(6 as u32)), + ); + backed_candidates.push(backed.clone()); + if core_index_enabled { + expected_backed_candidates_with_core + .entry(ParaId::from(3)) + .or_insert(vec![]) + .push((backed, CoreIndex(6))); + } + } + + // Para 4 + { + let mut candidate = TestCandidateBuilder { + para_id: ParaId::from(4), + relay_parent, + pov_hash: Hash::repeat_byte(8 as u8), + persisted_validation_data_hash: make_persisted_validation_data::( + ParaId::from(4), + RELAY_PARENT_NUM, + Default::default(), + ) + .unwrap() + .hash(), + head_data: HeadData(vec![4]), + hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![4]), + ..Default::default() + } + .build(); + + collator_sign_candidate(Sr25519Keyring::One, &mut candidate); + + let backed: BackedCandidate = back_candidate( + candidate.clone(), + &validators, + group_validators(GroupIndex::from(7 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(7 as u32)), + ); + backed_candidates.push(backed.clone()); + if core_index_enabled { + expected_backed_candidates_with_core + .entry(ParaId::from(4)) + .or_insert(vec![]) + .push((backed, CoreIndex(7))); + } + + let backed: BackedCandidate = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(7 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(8 as u32)), + ); + backed_candidates.push(backed.clone()); + } + + // State sanity checks + assert_eq!( + >::scheduled_paras().collect::>(), + vec![ + (CoreIndex(0), ParaId::from(1)), + (CoreIndex(1), ParaId::from(1)), + (CoreIndex(2), ParaId::from(2)), + (CoreIndex(3), ParaId::from(2)), + (CoreIndex(4), ParaId::from(2)), + (CoreIndex(5), ParaId::from(3)), + (CoreIndex(6), ParaId::from(3)), + (CoreIndex(7), ParaId::from(4)), + (CoreIndex(8), ParaId::from(4)), + ] + ); + let mut scheduled: BTreeMap> = BTreeMap::new(); + for (core_idx, para_id) in >::scheduled_paras() { + scheduled.entry(para_id).or_default().insert(core_idx); + } + + assert_eq!( shared::Pallet::::active_validator_indices(), vec![ ValidatorIndex(0), @@ -1870,43 +2965,38 @@ mod sanitizers { ValidatorIndex(4), ValidatorIndex(5), ValidatorIndex(6), + ValidatorIndex(7), + ValidatorIndex(8), ] ); TestData { backed_candidates, scheduled_paras: scheduled, - all_backed_candidates_with_core, + expected_backed_candidates_with_core, } } #[rstest] #[case(false)] #[case(true)] - fn happy_path(#[case] core_index_enabled: bool) { - new_test_ext(MockGenesisConfig::default()).execute_with(|| { + fn happy_path_one_core_per_para(#[case] core_index_enabled: bool) { + new_test_ext(default_config()).execute_with(|| { let TestData { backed_candidates, - all_backed_candidates_with_core, + expected_backed_candidates_with_core, scheduled_paras: scheduled, - } = get_test_data(core_index_enabled); - - let has_concluded_invalid = - |_idx: usize, _backed_candidate: &BackedCandidate| -> bool { false }; + } = get_test_data_one_core_per_para(core_index_enabled); assert_eq!( - sanitize_backed_candidates::( + sanitize_backed_candidates::( backed_candidates.clone(), &>::allowed_relay_parents(), - has_concluded_invalid, + BTreeSet::new(), scheduled, core_index_enabled ), - SanitizedBackedCandidates { - backed_candidates_with_core: all_backed_candidates_with_core, - votes_from_disabled_were_dropped: false, - dropped_unscheduled_candidates: false - } + expected_backed_candidates_with_core, ); }); } @@ -1915,29 +3005,46 @@ mod sanitizers { #[case(false)] #[case(true)] fn test_with_multiple_cores_per_para(#[case] core_index_enabled: bool) { - new_test_ext(MockGenesisConfig::default()).execute_with(|| { + new_test_ext(default_config()).execute_with(|| { let TestData { backed_candidates, - all_backed_candidates_with_core: expected_all_backed_candidates_with_core, + expected_backed_candidates_with_core, scheduled_paras: scheduled, } = get_test_data_multiple_cores_per_para(core_index_enabled); - let has_concluded_invalid = - |_idx: usize, _backed_candidate: &BackedCandidate| -> bool { false }; - assert_eq!( - sanitize_backed_candidates::( + sanitize_backed_candidates::( backed_candidates.clone(), &>::allowed_relay_parents(), - has_concluded_invalid, + BTreeSet::new(), scheduled, core_index_enabled ), - SanitizedBackedCandidates { - backed_candidates_with_core: expected_all_backed_candidates_with_core, - votes_from_disabled_were_dropped: false, - dropped_unscheduled_candidates: true - } + expected_backed_candidates_with_core, + ); + }); + } + + #[rstest] + #[case(false)] + #[case(true)] + fn test_candidate_ordering(#[case] core_index_enabled: bool) { + new_test_ext(default_config()).execute_with(|| { + let TestData { + backed_candidates, + scheduled_paras: scheduled, + expected_backed_candidates_with_core, + } = get_test_data_for_order_checks(core_index_enabled); + + assert_eq!( + sanitize_backed_candidates::( + backed_candidates.clone(), + &>::allowed_relay_parents(), + BTreeSet::new(), + scheduled, + core_index_enabled, + ), + expected_backed_candidates_with_core ); }); } @@ -1952,31 +3059,23 @@ mod sanitizers { #[case] core_index_enabled: bool, #[case] multiple_cores_per_para: bool, ) { - new_test_ext(MockGenesisConfig::default()).execute_with(|| { + new_test_ext(default_config()).execute_with(|| { let TestData { backed_candidates, .. } = if multiple_cores_per_para { get_test_data_multiple_cores_per_para(core_index_enabled) } else { - get_test_data(core_index_enabled) + get_test_data_one_core_per_para(core_index_enabled) }; let scheduled = BTreeMap::new(); - let has_concluded_invalid = - |_idx: usize, _backed_candidate: &BackedCandidate| -> bool { false }; - - let SanitizedBackedCandidates { - backed_candidates_with_core: sanitized_backed_candidates, - votes_from_disabled_were_dropped, - dropped_unscheduled_candidates, - } = sanitize_backed_candidates::( + + let sanitized_backed_candidates = sanitize_backed_candidates::( backed_candidates.clone(), &>::allowed_relay_parents(), - has_concluded_invalid, + BTreeSet::new(), scheduled, core_index_enabled, ); assert!(sanitized_backed_candidates.is_empty()); - assert!(!votes_from_disabled_were_dropped); - assert!(dropped_unscheduled_candidates); }); } @@ -1984,14 +3083,16 @@ mod sanitizers { #[rstest] #[case(false)] #[case(true)] - fn invalid_are_filtered_out(#[case] core_index_enabled: bool) { - new_test_ext(MockGenesisConfig::default()).execute_with(|| { + fn concluded_invalid_are_filtered_out_single_core_per_para( + #[case] core_index_enabled: bool, + ) { + new_test_ext(default_config()).execute_with(|| { let TestData { backed_candidates, scheduled_paras: scheduled, .. } = - get_test_data(core_index_enabled); + get_test_data_one_core_per_para(core_index_enabled); // mark every second one as concluded invalid let set = { - let mut set = std::collections::HashSet::new(); + let mut set = std::collections::BTreeSet::new(); for (idx, backed_candidate) in backed_candidates.iter().enumerate() { if idx & 0x01 == 0 { set.insert(backed_candidate.hash()); @@ -1999,23 +3100,98 @@ mod sanitizers { } set }; - let has_concluded_invalid = - |_idx: usize, candidate: &BackedCandidate| set.contains(&candidate.hash()); - let SanitizedBackedCandidates { - backed_candidates_with_core: sanitized_backed_candidates, - votes_from_disabled_were_dropped, - dropped_unscheduled_candidates, - } = sanitize_backed_candidates::( + let sanitized_backed_candidates: BTreeMap< + ParaId, + Vec<(BackedCandidate<_>, CoreIndex)>, + > = sanitize_backed_candidates::( backed_candidates.clone(), &>::allowed_relay_parents(), - has_concluded_invalid, + set, scheduled, core_index_enabled, ); assert_eq!(sanitized_backed_candidates.len(), backed_candidates.len() / 2); - assert!(!votes_from_disabled_were_dropped); - assert!(!dropped_unscheduled_candidates); + }); + } + + // candidates that have concluded as invalid are filtered out, as well as their descendants. + #[test] + fn concluded_invalid_are_filtered_out_multiple_cores_per_para() { + // Mark the first candidate of paraid 1 as invalid. Its descendant should also + // be dropped. Also mark the candidate of paraid 3 as invalid. + new_test_ext(default_config()).execute_with(|| { + let TestData { + backed_candidates, + scheduled_paras: scheduled, + mut expected_backed_candidates_with_core, + .. + } = get_test_data_multiple_cores_per_para(true); + + let mut invalid_set = std::collections::BTreeSet::new(); + + for (idx, backed_candidate) in backed_candidates.iter().enumerate() { + if backed_candidate.descriptor().para_id == ParaId::from(1) && idx == 0 { + invalid_set.insert(backed_candidate.hash()); + } else if backed_candidate.descriptor().para_id == ParaId::from(3) { + invalid_set.insert(backed_candidate.hash()); + } + } + let sanitized_backed_candidates: BTreeMap< + ParaId, + Vec<(BackedCandidate<_>, CoreIndex)>, + > = sanitize_backed_candidates::( + backed_candidates.clone(), + &>::allowed_relay_parents(), + invalid_set, + scheduled, + true, + ); + + // We'll be left with candidates from paraid 2 and 4. + + expected_backed_candidates_with_core.remove(&ParaId::from(1)).unwrap(); + expected_backed_candidates_with_core.remove(&ParaId::from(3)).unwrap(); + + assert_eq!(sanitized_backed_candidates, sanitized_backed_candidates); + }); + + // Mark the second candidate of paraid 1 as invalid. Its predecessor should be left + // in place. + new_test_ext(default_config()).execute_with(|| { + let TestData { + backed_candidates, + scheduled_paras: scheduled, + mut expected_backed_candidates_with_core, + .. + } = get_test_data_multiple_cores_per_para(true); + + let mut invalid_set = std::collections::BTreeSet::new(); + + for (idx, backed_candidate) in backed_candidates.iter().enumerate() { + if backed_candidate.descriptor().para_id == ParaId::from(1) && idx == 1 { + invalid_set.insert(backed_candidate.hash()); + } + } + let sanitized_backed_candidates: BTreeMap< + ParaId, + Vec<(BackedCandidate<_>, CoreIndex)>, + > = sanitize_backed_candidates::( + backed_candidates.clone(), + &>::allowed_relay_parents(), + invalid_set, + scheduled, + true, + ); + + // Only the second candidate of paraid 1 should be removed. + expected_backed_candidates_with_core + .get_mut(&ParaId::from(1)) + .unwrap() + .remove(1); + + // We'll be left with candidates from paraid 1, 2, 3 and 4. + assert_eq!(sanitized_backed_candidates, expected_backed_candidates_with_core); }); } @@ -2023,34 +3199,35 @@ mod sanitizers { #[case(false)] #[case(true)] fn disabled_non_signing_validator_doesnt_get_filtered(#[case] core_index_enabled: bool) { - new_test_ext(MockGenesisConfig::default()).execute_with(|| { - let TestData { mut all_backed_candidates_with_core, .. } = - get_test_data(core_index_enabled); + new_test_ext(default_config()).execute_with(|| { + let TestData { mut expected_backed_candidates_with_core, .. } = + get_test_data_one_core_per_para(core_index_enabled); // Disable Eve set_disabled_validators(vec![4]); - let before = all_backed_candidates_with_core.clone(); + let before = expected_backed_candidates_with_core.clone(); // Eve is disabled but no backing statement is signed by it so nothing should be // filtered - assert!(!filter_backed_statements_from_disabled_validators::( - &mut all_backed_candidates_with_core, + filter_backed_statements_from_disabled_validators::( + &mut expected_backed_candidates_with_core, &>::allowed_relay_parents(), - core_index_enabled - )); - assert_eq!(all_backed_candidates_with_core, before); + core_index_enabled, + ); + assert_eq!(expected_backed_candidates_with_core, before); }); } + #[rstest] #[case(false)] #[case(true)] fn drop_statements_from_disabled_without_dropping_candidate( #[case] core_index_enabled: bool, ) { - new_test_ext(MockGenesisConfig::default()).execute_with(|| { - let TestData { mut all_backed_candidates_with_core, .. } = - get_test_data(core_index_enabled); + new_test_ext(default_config()).execute_with(|| { + let TestData { mut expected_backed_candidates_with_core, .. } = + get_test_data_one_core_per_para(core_index_enabled); // Disable Alice set_disabled_validators(vec![0]); @@ -2064,11 +3241,22 @@ mod sanitizers { // Verify the initial state is as expected assert_eq!( - all_backed_candidates_with_core.get(0).unwrap().0.validity_votes().len(), + expected_backed_candidates_with_core + .get(&ParaId::from(1)) + .unwrap() + .iter() + .next() + .unwrap() + .0 + .validity_votes() + .len(), 2 ); - let (validator_indices, maybe_core_index) = all_backed_candidates_with_core - .get(0) + let (validator_indices, maybe_core_index) = expected_backed_candidates_with_core + .get(&ParaId::from(1)) + .unwrap() + .iter() + .next() .unwrap() .0 .validator_indices_and_core_index(core_index_enabled); @@ -2080,16 +3268,28 @@ mod sanitizers { assert_eq!(validator_indices.get(0).unwrap(), true); assert_eq!(validator_indices.get(1).unwrap(), true); - let untouched = all_backed_candidates_with_core.get(1).unwrap().0.clone(); + let untouched = expected_backed_candidates_with_core + .get(&ParaId::from(2)) + .unwrap() + .iter() + .next() + .unwrap() + .0 + .clone(); - assert!(filter_backed_statements_from_disabled_validators::( - &mut all_backed_candidates_with_core, + let before = expected_backed_candidates_with_core.clone(); + filter_backed_statements_from_disabled_validators::( + &mut expected_backed_candidates_with_core, &>::allowed_relay_parents(), - core_index_enabled - )); + core_index_enabled, + ); + assert_eq!(before.len(), expected_backed_candidates_with_core.len()); - let (validator_indices, maybe_core_index) = all_backed_candidates_with_core - .get(0) + let (validator_indices, maybe_core_index) = expected_backed_candidates_with_core + .get(&ParaId::from(1)) + .unwrap() + .iter() + .next() .unwrap() .0 .validator_indices_and_core_index(core_index_enabled); @@ -2100,47 +3300,137 @@ mod sanitizers { } // there should still be two backed candidates - assert_eq!(all_backed_candidates_with_core.len(), 2); + assert_eq!(expected_backed_candidates_with_core.len(), 2); // but the first one should have only one validity vote assert_eq!( - all_backed_candidates_with_core.get(0).unwrap().0.validity_votes().len(), + expected_backed_candidates_with_core + .get(&ParaId::from(1)) + .unwrap() + .iter() + .next() + .unwrap() + .0 + .validity_votes() + .len(), 1 ); // Validator 0 vote should be dropped, validator 1 - retained assert_eq!(validator_indices.get(0).unwrap(), false); assert_eq!(validator_indices.get(1).unwrap(), true); // the second candidate shouldn't be modified - assert_eq!(all_backed_candidates_with_core.get(1).unwrap().0, untouched); + assert_eq!( + expected_backed_candidates_with_core + .get(&ParaId::from(2)) + .unwrap() + .iter() + .next() + .unwrap() + .0, + untouched + ); }); } #[rstest] #[case(false)] #[case(true)] - fn drop_candidate_if_all_statements_are_from_disabled(#[case] core_index_enabled: bool) { - new_test_ext(MockGenesisConfig::default()).execute_with(|| { - let TestData { mut all_backed_candidates_with_core, .. } = - get_test_data(core_index_enabled); + fn drop_candidate_if_all_statements_are_from_disabled_single_core_per_para( + #[case] core_index_enabled: bool, + ) { + new_test_ext(default_config()).execute_with(|| { + let TestData { mut expected_backed_candidates_with_core, .. } = + get_test_data_one_core_per_para(core_index_enabled); // Disable Alice and Bob set_disabled_validators(vec![0, 1]); // Verify the initial state is as expected assert_eq!( - all_backed_candidates_with_core.get(0).unwrap().0.validity_votes().len(), + expected_backed_candidates_with_core + .get(&ParaId::from(1)) + .unwrap() + .iter() + .next() + .unwrap() + .0 + .validity_votes() + .len(), 2 ); - let untouched = all_backed_candidates_with_core.get(1).unwrap().0.clone(); + let untouched = expected_backed_candidates_with_core + .get(&ParaId::from(2)) + .unwrap() + .iter() + .next() + .unwrap() + .0 + .clone(); - assert!(filter_backed_statements_from_disabled_validators::( - &mut all_backed_candidates_with_core, + filter_backed_statements_from_disabled_validators::( + &mut expected_backed_candidates_with_core, &>::allowed_relay_parents(), - core_index_enabled - )); + core_index_enabled, + ); + + assert_eq!(expected_backed_candidates_with_core.len(), 1); + assert_eq!( + expected_backed_candidates_with_core + .get(&ParaId::from(2)) + .unwrap() + .iter() + .next() + .unwrap() + .0, + untouched + ); + assert_eq!(expected_backed_candidates_with_core.get(&ParaId::from(1)), None); + }); + } + + #[test] + fn drop_candidate_if_all_statements_are_from_disabled_multiple_cores_per_para() { + // Disable Bob, only the second candidate of paraid 1 should be removed. + new_test_ext(default_config()).execute_with(|| { + let TestData { mut expected_backed_candidates_with_core, .. } = + get_test_data_multiple_cores_per_para(true); - assert_eq!(all_backed_candidates_with_core.len(), 1); - assert_eq!(all_backed_candidates_with_core.get(0).unwrap().0, untouched); + set_disabled_validators(vec![1]); + + let mut untouched = expected_backed_candidates_with_core.clone(); + + filter_backed_statements_from_disabled_validators::( + &mut expected_backed_candidates_with_core, + &>::allowed_relay_parents(), + true, + ); + + untouched.get_mut(&ParaId::from(1)).unwrap().remove(1); + + assert_eq!(expected_backed_candidates_with_core, untouched); }); + + // Disable Alice or disable both Alice and Bob, all candidates of paraid 1 should be + // removed. + for disabled in [vec![0], vec![0, 1]] { + new_test_ext(default_config()).execute_with(|| { + let TestData { mut expected_backed_candidates_with_core, .. } = + get_test_data_multiple_cores_per_para(true); + + set_disabled_validators(disabled); + + let mut untouched = expected_backed_candidates_with_core.clone(); + + filter_backed_statements_from_disabled_validators::( + &mut expected_backed_candidates_with_core, + &>::allowed_relay_parents(), + true, + ); + + untouched.remove(&ParaId::from(1)).unwrap(); + + assert_eq!(expected_backed_candidates_with_core, untouched); + }); + } } } } diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/v7.rs b/polkadot/runtime/parachains/src/runtime_api_impl/v7.rs index 1bbd4dfb716..171f3f746a8 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/v7.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/v7.rs @@ -22,6 +22,7 @@ use crate::{ scheduler::{self, CoreOccupied}, session_info, shared, }; +use frame_support::traits::{GetStorageVersion, StorageVersion}; use frame_system::pallet_prelude::*; use primitives::{ async_backing::{ @@ -92,16 +93,41 @@ pub fn availability_cores() -> Vec { - let pending_availability = - >::pending_availability(entry.para_id()) - .expect("Occupied core always has pending availability; qed"); - - let backed_in_number = *pending_availability.backed_in_number(); + // Due to https://github.com/paritytech/polkadot-sdk/issues/64, using the new storage types would cause + // this runtime API to panic. We explicitly handle the storage for version 0 to + // prevent that. When removing the inclusion v0 -> v1 migration, this bit of code + // can also be removed. + let pending_availability = if >::on_chain_storage_version() == + StorageVersion::new(0) + { + inclusion::migration::v0::PendingAvailability::::get(entry.para_id()) + .expect("Occupied core always has pending availability; qed") + } else { + let candidate = >::pending_availability_with_core( + entry.para_id(), + CoreIndex(i as u32), + ) + .expect("Occupied core always has pending availability; qed"); + + // Translate to the old candidate format, as we don't need the commitments now. + inclusion::migration::v0::CandidatePendingAvailability { + core: candidate.core_occupied(), + hash: candidate.candidate_hash(), + descriptor: candidate.candidate_descriptor().clone(), + availability_votes: candidate.availability_votes().clone(), + backers: candidate.backers().clone(), + relay_parent_number: candidate.relay_parent_number(), + backed_in_number: candidate.backed_in_number(), + backing_group: candidate.backing_group(), + } + }; + + let backed_in_number = pending_availability.backed_in_number; // Use the same block number for determining the responsible group as what the // backing subsystem would use when it calls validator_groups api. let backing_group_allocation_time = - pending_availability.relay_parent_number() + One::one(); + pending_availability.relay_parent_number + One::one(); CoreState::Occupied(OccupiedCore { next_up_on_available: >::next_up_on_available(CoreIndex( i as u32, @@ -111,13 +137,13 @@ pub fn availability_cores() -> Vec>::next_up_on_time_out(CoreIndex( i as u32, )), - availability: pending_availability.availability_votes().clone(), + availability: pending_availability.availability_votes.clone(), group_responsible: group_responsible_for( backing_group_allocation_time, - pending_availability.core_occupied(), + pending_availability.core, ), - candidate_hash: pending_availability.candidate_hash(), - candidate_descriptor: pending_availability.candidate_descriptor().clone(), + candidate_hash: pending_availability.hash, + candidate_descriptor: pending_availability.descriptor, }) }, CoreOccupied::Free => { @@ -200,8 +226,8 @@ pub fn assumed_validation_data( }; let persisted_validation_data = make_validation_data().or_else(|| { - // Try again with force enacting the core. This check only makes sense if - // the core is occupied. + // Try again with force enacting the pending candidates. This check only makes sense if + // there are any pending candidates. >::pending_availability(para_id).and_then(|_| { >::force_enact(para_id); make_validation_data() @@ -465,27 +491,23 @@ pub fn backing_state( }; let pending_availability = { - // Note: the API deals with a `Vec` as it is future-proof for cases - // where there may be multiple candidates pending availability at a time. - // But at the moment only one candidate can be pending availability per - // parachain. crate::inclusion::PendingAvailability::::get(¶_id) - .and_then(|pending| { - let commitments = - crate::inclusion::PendingAvailabilityCommitments::::get(¶_id); - commitments.map(move |c| (pending, c)) - }) - .map(|(pending, commitments)| { - CandidatePendingAvailability { - candidate_hash: pending.candidate_hash(), - descriptor: pending.candidate_descriptor().clone(), - commitments, - relay_parent_number: pending.relay_parent_number(), - max_pov_size: constraints.max_pov_size, // assume always same in session. - } + .map(|pending_candidates| { + pending_candidates + .into_iter() + .map(|candidate| { + CandidatePendingAvailability { + candidate_hash: candidate.candidate_hash(), + descriptor: candidate.candidate_descriptor().clone(), + commitments: candidate.candidate_commitments().clone(), + relay_parent_number: candidate.relay_parent_number(), + max_pov_size: constraints.max_pov_size, /* assume always same in + * session. */ + } + }) + .collect() }) - .into_iter() - .collect() + .unwrap_or_else(|| vec![]) }; Some(BackingState { constraints, pending_availability }) diff --git a/polkadot/runtime/parachains/src/scheduler.rs b/polkadot/runtime/parachains/src/scheduler.rs index f231864a85e..25840d9707d 100644 --- a/polkadot/runtime/parachains/src/scheduler.rs +++ b/polkadot/runtime/parachains/src/scheduler.rs @@ -398,16 +398,6 @@ impl Pallet { }); } - /// Get the para (chain or thread) ID assigned to a particular core or index, if any. Core - /// indices out of bounds will return `None`, as will indices of unassigned cores. - pub(crate) fn core_para(core_index: CoreIndex) -> Option { - let cores = AvailabilityCores::::get(); - match cores.get(core_index.0 as usize) { - None | Some(CoreOccupied::Free) => None, - Some(CoreOccupied::Paras(entry)) => Some(entry.para_id()), - } - } - /// Get the validators in the given group, if the group index is valid for this session. pub(crate) fn group_validators(group_index: GroupIndex) -> Option> { ValidatorGroups::::get().get(group_index.0 as usize).map(|g| g.clone()) diff --git a/polkadot/runtime/parachains/src/util.rs b/polkadot/runtime/parachains/src/util.rs index aa07ef08005..493a9d055ef 100644 --- a/polkadot/runtime/parachains/src/util.rs +++ b/polkadot/runtime/parachains/src/util.rs @@ -18,7 +18,7 @@ //! on all modules. use frame_system::pallet_prelude::BlockNumberFor; -use primitives::{Id as ParaId, PersistedValidationData, ValidatorIndex}; +use primitives::{HeadData, Id as ParaId, PersistedValidationData, ValidatorIndex}; use sp_std::{collections::btree_set::BTreeSet, vec::Vec}; use crate::{configuration, hrmp, paras}; @@ -42,6 +42,23 @@ pub fn make_persisted_validation_data( }) } +/// Make the persisted validation data for a particular parachain, a specified relay-parent, its +/// storage root and parent head data. +pub fn make_persisted_validation_data_with_parent( + relay_parent_number: BlockNumberFor, + relay_parent_storage_root: T::Hash, + parent_head: HeadData, +) -> PersistedValidationData> { + let config = >::config(); + + PersistedValidationData { + parent_head, + relay_parent_number, + relay_parent_storage_root, + max_pov_size: config.max_pov_size, + } +} + /// Take an active subset of a set containing all validators. /// /// First item in pair will be all items in set have indices found in the `active` indices set (in diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index c9f5d81d286..90824a2f6f0 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -1663,6 +1663,8 @@ pub mod migrations { // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, + + parachains_inclusion::migration::MigrateToV1, ); } diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_paras_inherent.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_paras_inherent.rs index a102d1903b2..c250c86665b 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_paras_inherent.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_parachains_paras_inherent.rs @@ -13,161 +13,322 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . + //! Autogenerated weights for `runtime_parachains::paras_inherent` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-11-20, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 128 +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-03-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: -// target/release/polkadot +// target/production/polkadot // benchmark -// --chain=rococo-dev +// pallet // --steps=50 // --repeat=20 -// --pallet=runtime_parachains::paras_inherent // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./runtime/rococo/src/weights/runtime_parachains_paras_inherent.rs -// --header=./file_header.txt +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=runtime_parachains::paras_inherent +// --chain=rococo-dev +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] +#![allow(missing_docs)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions for `runtime_parachains::paras_inherent`. pub struct WeightInfo(PhantomData); impl runtime_parachains::paras_inherent::WeightInfo for WeightInfo { - // Storage: ParaInherent Included (r:1 w:1) - // Storage: System ParentHash (r:1 w:0) - // Storage: ParaScheduler AvailabilityCores (r:1 w:1) - // Storage: ParasShared CurrentSessionIndex (r:1 w:0) - // Storage: Configuration ActiveConfig (r:1 w:0) - // Storage: ParaSessionInfo Sessions (r:1 w:0) - // Storage: ParasDisputes Disputes (r:1 w:1) - // Storage: ParasDisputes Included (r:1 w:1) - // Storage: ParasDisputes SpamSlots (r:1 w:1) - // Storage: ParasDisputes Frozen (r:1 w:0) - // Storage: ParaInclusion PendingAvailability (r:2 w:1) - // Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - // Storage: Paras Parachains (r:1 w:0) - // Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) - // Storage: Dmp DownwardMessageQueues (r:1 w:1) - // Storage: Hrmp HrmpChannelDigests (r:1 w:1) - // Storage: Paras FutureCodeUpgrades (r:1 w:0) - // Storage: ParaScheduler SessionStartBlock (r:1 w:0) - // Storage: ParaScheduler ParathreadQueue (r:1 w:1) - // Storage: ParaScheduler Scheduled (r:1 w:1) - // Storage: ParaScheduler ValidatorGroups (r:1 w:0) - // Storage: Ump NeedsDispatch (r:1 w:1) - // Storage: Ump NextDispatchRoundStartWith (r:1 w:1) - // Storage: ParaInherent OnChainVotes (r:0 w:1) - // Storage: Hrmp HrmpWatermarks (r:0 w:1) - // Storage: Paras Heads (r:0 w:1) + /// Storage: `ParaInherent::Included` (r:1 w:1) + /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::ParentHash` (r:1 w:0) + /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) + /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) + /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) + /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) + /// Storage: `ParaSessionInfo::Sessions` (r:1 w:0) + /// Proof: `ParaSessionInfo::Sessions` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Disputes` (r:1 w:1) + /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::BackersOnDisputes` (r:1 w:1) + /// Proof: `ParasDisputes::BackersOnDisputes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Included` (r:1 w:1) + /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1) + /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Frozen` (r:1 w:0) + /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaInclusion::V1` (r:2 w:1) + /// Proof: `ParaInclusion::V1` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:1) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1) + /// Proof: `Hrmp::HrmpChannelDigests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0) + /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Registrar::Paras` (r:1 w:0) + /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) + /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Session::DisabledValidators` (r:1 w:0) + /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) + /// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:0 w:1) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1) + /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::MostRecentContext` (r:0 w:1) + /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `v` is `[10, 200]`. fn enter_variable_disputes(v: u32, ) -> Weight { - Weight::from_parts(352_590_000 as u64, 0) - // Standard Error: 13_000 - .saturating_add(Weight::from_parts(49_254_000 as u64, 0).saturating_mul(v as u64)) - .saturating_add(T::DbWeight::get().reads(24 as u64)) - .saturating_add(T::DbWeight::get().writes(16 as u64)) + // Proof Size summary in bytes: + // Measured: `67785` + // Estimated: `73725 + v * (23 ±0)` + // Minimum execution time: 949_716_000 picoseconds. + Weight::from_parts(482_361_515, 0) + .saturating_add(Weight::from_parts(0, 73725)) + // Standard Error: 17_471 + .saturating_add(Weight::from_parts(50_100_764, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(25)) + .saturating_add(T::DbWeight::get().writes(15)) + .saturating_add(Weight::from_parts(0, 23).saturating_mul(v.into())) } - // Storage: ParaInherent Included (r:1 w:1) - // Storage: System ParentHash (r:1 w:0) - // Storage: ParaScheduler AvailabilityCores (r:1 w:1) - // Storage: ParasShared CurrentSessionIndex (r:1 w:0) - // Storage: Configuration ActiveConfig (r:1 w:0) - // Storage: ParasDisputes Frozen (r:1 w:0) - // Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - // Storage: Paras Parachains (r:1 w:0) - // Storage: ParaInclusion PendingAvailability (r:2 w:1) - // Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) - // Storage: Dmp DownwardMessageQueues (r:1 w:1) - // Storage: Hrmp HrmpChannelDigests (r:1 w:1) - // Storage: Paras FutureCodeUpgrades (r:1 w:0) - // Storage: ParasDisputes Disputes (r:1 w:0) - // Storage: ParaScheduler SessionStartBlock (r:1 w:0) - // Storage: ParaScheduler ParathreadQueue (r:1 w:1) - // Storage: ParaScheduler Scheduled (r:1 w:1) - // Storage: ParaScheduler ValidatorGroups (r:1 w:0) - // Storage: Ump NeedsDispatch (r:1 w:1) - // Storage: Ump NextDispatchRoundStartWith (r:1 w:1) - // Storage: ParaInclusion AvailabilityBitfields (r:0 w:1) - // Storage: ParaInherent OnChainVotes (r:0 w:1) - // Storage: ParasDisputes Included (r:0 w:1) - // Storage: Hrmp HrmpWatermarks (r:0 w:1) - // Storage: Paras Heads (r:0 w:1) + /// Storage: `ParaInherent::Included` (r:1 w:1) + /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::ParentHash` (r:1 w:0) + /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) + /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) + /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) + /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) + /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1) + /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Frozen` (r:1 w:0) + /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaInclusion::V1` (r:2 w:1) + /// Proof: `ParaInclusion::V1` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:1) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1) + /// Proof: `Hrmp::HrmpChannelDigests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0) + /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Registrar::Paras` (r:1 w:0) + /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Disputes` (r:1 w:0) + /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) + /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Session::DisabledValidators` (r:1 w:0) + /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Included` (r:0 w:1) + /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) + /// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:0 w:1) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1) + /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::MostRecentContext` (r:0 w:1) + /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) fn enter_bitfields() -> Weight { - Weight::from_parts(299_878_000 as u64, 0) - .saturating_add(T::DbWeight::get().reads(21 as u64)) - .saturating_add(T::DbWeight::get().writes(15 as u64)) + // Proof Size summary in bytes: + // Measured: `42757` + // Estimated: `48697` + // Minimum execution time: 437_627_000 picoseconds. + Weight::from_parts(460_975_000, 0) + .saturating_add(Weight::from_parts(0, 48697)) + .saturating_add(T::DbWeight::get().reads(23)) + .saturating_add(T::DbWeight::get().writes(15)) } - // Storage: ParaInherent Included (r:1 w:1) - // Storage: System ParentHash (r:1 w:0) - // Storage: ParaScheduler AvailabilityCores (r:1 w:1) - // Storage: ParasShared CurrentSessionIndex (r:1 w:0) - // Storage: Configuration ActiveConfig (r:1 w:0) - // Storage: ParasDisputes Frozen (r:1 w:0) - // Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - // Storage: Paras Parachains (r:1 w:0) - // Storage: ParaInclusion PendingAvailability (r:2 w:1) - // Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) - // Storage: Dmp DownwardMessageQueues (r:1 w:1) - // Storage: Hrmp HrmpChannelDigests (r:1 w:1) - // Storage: Paras FutureCodeUpgrades (r:1 w:0) - // Storage: ParasDisputes Disputes (r:2 w:0) - // Storage: ParaScheduler SessionStartBlock (r:1 w:0) - // Storage: ParaScheduler ParathreadQueue (r:1 w:1) - // Storage: ParaScheduler Scheduled (r:1 w:1) - // Storage: ParaScheduler ValidatorGroups (r:1 w:0) - // Storage: Paras PastCodeMeta (r:1 w:0) - // Storage: Paras CurrentCodeHash (r:1 w:0) - // Storage: Ump RelayDispatchQueueSize (r:1 w:0) - // Storage: Ump NeedsDispatch (r:1 w:1) - // Storage: Ump NextDispatchRoundStartWith (r:1 w:1) - // Storage: ParaInherent OnChainVotes (r:0 w:1) - // Storage: ParasDisputes Included (r:0 w:1) - // Storage: Hrmp HrmpWatermarks (r:0 w:1) - // Storage: Paras Heads (r:0 w:1) - fn enter_backed_candidates_variable(_v: u32) -> Weight { - Weight::from_parts(442_472_000 as u64, 0) - .saturating_add(T::DbWeight::get().reads(25 as u64)) - .saturating_add(T::DbWeight::get().writes(14 as u64)) + /// Storage: `ParaInherent::Included` (r:1 w:1) + /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::ParentHash` (r:1 w:0) + /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) + /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) + /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) + /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) + /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1) + /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Frozen` (r:1 w:0) + /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaInclusion::V1` (r:2 w:1) + /// Proof: `ParaInclusion::V1` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:1) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1) + /// Proof: `Hrmp::HrmpChannelDigests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0) + /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Registrar::Paras` (r:1 w:0) + /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Disputes` (r:1 w:0) + /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) + /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CurrentCodeHash` (r:1 w:0) + /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:1 w:0) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:0) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Session::DisabledValidators` (r:1 w:0) + /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Included` (r:0 w:1) + /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) + /// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:0 w:1) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1) + /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::MostRecentContext` (r:0 w:1) + /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `v` is `[101, 200]`. + fn enter_backed_candidates_variable(v: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `42829` + // Estimated: `48769` + // Minimum execution time: 1_305_254_000 picoseconds. + Weight::from_parts(1_347_160_667, 0) + .saturating_add(Weight::from_parts(0, 48769)) + // Standard Error: 22_128 + .saturating_add(Weight::from_parts(57_229, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(26)) + .saturating_add(T::DbWeight::get().writes(15)) } - // Storage: ParaInherent Included (r:1 w:1) - // Storage: System ParentHash (r:1 w:0) - // Storage: ParaScheduler AvailabilityCores (r:1 w:1) - // Storage: ParasShared CurrentSessionIndex (r:1 w:0) - // Storage: Configuration ActiveConfig (r:1 w:0) - // Storage: ParasDisputes Frozen (r:1 w:0) - // Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - // Storage: Paras Parachains (r:1 w:0) - // Storage: ParaInclusion PendingAvailability (r:2 w:1) - // Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) - // Storage: Dmp DownwardMessageQueues (r:1 w:1) - // Storage: Hrmp HrmpChannelDigests (r:1 w:1) - // Storage: Paras FutureCodeUpgrades (r:1 w:0) - // Storage: ParasDisputes Disputes (r:2 w:0) - // Storage: ParaScheduler SessionStartBlock (r:1 w:0) - // Storage: ParaScheduler ParathreadQueue (r:1 w:1) - // Storage: ParaScheduler Scheduled (r:1 w:1) - // Storage: ParaScheduler ValidatorGroups (r:1 w:0) - // Storage: Paras PastCodeMeta (r:1 w:0) - // Storage: Paras CurrentCodeHash (r:1 w:0) - // Storage: Ump RelayDispatchQueueSize (r:1 w:0) - // Storage: Ump NeedsDispatch (r:1 w:1) - // Storage: Ump NextDispatchRoundStartWith (r:1 w:1) - // Storage: ParaInherent OnChainVotes (r:0 w:1) - // Storage: ParasDisputes Included (r:0 w:1) - // Storage: Hrmp HrmpWatermarks (r:0 w:1) - // Storage: Paras Heads (r:0 w:1) + /// Storage: `ParaInherent::Included` (r:1 w:1) + /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::ParentHash` (r:1 w:0) + /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) + /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) + /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) + /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) + /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1) + /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Frozen` (r:1 w:0) + /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaInclusion::V1` (r:2 w:1) + /// Proof: `ParaInclusion::V1` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:1) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1) + /// Proof: `Hrmp::HrmpChannelDigests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0) + /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Registrar::Paras` (r:1 w:0) + /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Disputes` (r:1 w:0) + /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) + /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CurrentCodeHash` (r:1 w:0) + /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::FutureCodeHash` (r:1 w:0) + /// Proof: `Paras::FutureCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeRestrictionSignal` (r:1 w:0) + /// Proof: `Paras::UpgradeRestrictionSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:1 w:0) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:0) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Session::DisabledValidators` (r:1 w:0) + /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Included` (r:0 w:1) + /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) + /// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:0 w:1) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1) + /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::MostRecentContext` (r:0 w:1) + /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) fn enter_backed_candidate_code_upgrade() -> Weight { - Weight::from_parts(36_903_411_000 as u64, 0) - .saturating_add(T::DbWeight::get().reads(25 as u64)) - .saturating_add(T::DbWeight::get().writes(14 as u64)) + // Proof Size summary in bytes: + // Measured: `42842` + // Estimated: `48782` + // Minimum execution time: 38_637_547_000 picoseconds. + Weight::from_parts(41_447_412_000, 0) + .saturating_add(Weight::from_parts(0, 48782)) + .saturating_add(T::DbWeight::get().reads(28)) + .saturating_add(T::DbWeight::get().writes(15)) } } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 83d47508c7c..664044b713e 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1781,6 +1781,7 @@ pub mod migrations { crate::xcm_config::XcmRouter, GetLegacyLeaseImpl, >, + parachains_inclusion::migration::MigrateToV1, ); } diff --git a/polkadot/runtime/westend/src/weights/runtime_parachains_paras_inherent.rs b/polkadot/runtime/westend/src/weights/runtime_parachains_paras_inherent.rs index 0dd64f054d0..aa99ac9438c 100644 --- a/polkadot/runtime/westend/src/weights/runtime_parachains_paras_inherent.rs +++ b/polkadot/runtime/westend/src/weights/runtime_parachains_paras_inherent.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `runtime_parachains::paras_inherent` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-03-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-xerhrdyb-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 // Executed Command: // target/production/polkadot @@ -29,14 +29,13 @@ // --steps=50 // --repeat=20 // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json // --pallet=runtime_parachains::paras_inherent // --chain=westend-dev -// --header=./file_header.txt -// --output=./runtime/westend/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,297 +48,311 @@ use core::marker::PhantomData; /// Weight functions for `runtime_parachains::paras_inherent`. pub struct WeightInfo(PhantomData); impl runtime_parachains::paras_inherent::WeightInfo for WeightInfo { - /// Storage: ParaInherent Included (r:1 w:1) - /// Proof Skipped: ParaInherent Included (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System ParentHash (r:1 w:0) - /// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler AvailabilityCores (r:1 w:1) - /// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Babe AuthorVrfRandomness (r:1 w:0) - /// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) - /// Storage: ParaSessionInfo Sessions (r:1 w:0) - /// Proof Skipped: ParaSessionInfo Sessions (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasDisputes Disputes (r:1 w:1) - /// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasDisputes BackersOnDisputes (r:1 w:1) - /// Proof Skipped: ParasDisputes BackersOnDisputes (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasDisputes Included (r:1 w:1) - /// Proof Skipped: ParasDisputes Included (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaSessionInfo AccountKeys (r:1 w:0) - /// Proof Skipped: ParaSessionInfo AccountKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking ActiveEra (r:1 w:0) - /// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen) - /// Storage: Staking ErasRewardPoints (r:1 w:1) - /// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaInherent OnChainVotes (r:1 w:1) - /// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasDisputes Frozen (r:1 w:0) - /// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion PendingAvailability (r:2 w:1) - /// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Parachains (r:1 w:0) - /// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) - /// Proof Skipped: ParaInclusion PendingAvailabilityCommitments (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:1) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpChannelDigests (r:1 w:1) - /// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras FutureCodeUpgrades (r:1 w:0) - /// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaScheduler SessionStartBlock (r:1 w:0) - /// Proof Skipped: ParaScheduler SessionStartBlock (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler ParathreadQueue (r:1 w:1) - /// Proof Skipped: ParaScheduler ParathreadQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler Scheduled (r:1 w:1) - /// Proof Skipped: ParaScheduler Scheduled (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler ValidatorGroups (r:1 w:0) - /// Proof Skipped: ParaScheduler ValidatorGroups (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Hrmp HrmpWatermarks (r:0 w:1) - /// Proof Skipped: Hrmp HrmpWatermarks (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Heads (r:0 w:1) - /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeGoAheadSignal (r:0 w:1) - /// Proof Skipped: Paras UpgradeGoAheadSignal (max_values: None, max_size: None, mode: Measured) + /// Storage: `ParaInherent::Included` (r:1 w:1) + /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::ParentHash` (r:1 w:0) + /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) + /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) + /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) + /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) + /// Storage: `ParaSessionInfo::Sessions` (r:1 w:0) + /// Proof: `ParaSessionInfo::Sessions` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Disputes` (r:1 w:1) + /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::BackersOnDisputes` (r:1 w:1) + /// Proof: `ParasDisputes::BackersOnDisputes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Included` (r:1 w:1) + /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParaSessionInfo::AccountKeys` (r:1 w:0) + /// Proof: `ParaSessionInfo::AccountKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Session::Validators` (r:1 w:0) + /// Proof: `Session::Validators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ActiveEra` (r:1 w:0) + /// Proof: `Staking::ActiveEra` (`max_values`: Some(1), `max_size`: Some(13), added: 508, mode: `MaxEncodedLen`) + /// Storage: `Staking::ErasRewardPoints` (r:1 w:1) + /// Proof: `Staking::ErasRewardPoints` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1) + /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Frozen` (r:1 w:0) + /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaInclusion::V1` (r:2 w:1) + /// Proof: `ParaInclusion::V1` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:1) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1) + /// Proof: `Hrmp::HrmpChannelDigests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0) + /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) + /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Session::DisabledValidators` (r:1 w:0) + /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) + /// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:0 w:1) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1) + /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::MostRecentContext` (r:0 w:1) + /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `v` is `[10, 200]`. fn enter_variable_disputes(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `50518` - // Estimated: `56458 + v * (23 ±0)` - // Minimum execution time: 998_338_000 picoseconds. - Weight::from_parts(468_412_001, 0) - .saturating_add(Weight::from_parts(0, 56458)) - // Standard Error: 20_559 - .saturating_add(Weight::from_parts(56_965_025, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(27)) - .saturating_add(T::DbWeight::get().writes(15)) + // Measured: `67518` + // Estimated: `73458 + v * (23 ±0)` + // Minimum execution time: 844_022_000 picoseconds. + Weight::from_parts(456_682_337, 0) + .saturating_add(Weight::from_parts(0, 73458)) + // Standard Error: 16_403 + .saturating_add(Weight::from_parts(41_871_245, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(28)) + .saturating_add(T::DbWeight::get().writes(16)) .saturating_add(Weight::from_parts(0, 23).saturating_mul(v.into())) } - /// Storage: ParaInherent Included (r:1 w:1) - /// Proof Skipped: ParaInherent Included (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System ParentHash (r:1 w:0) - /// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler AvailabilityCores (r:1 w:1) - /// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Babe AuthorVrfRandomness (r:1 w:0) - /// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) - /// Storage: ParaInherent OnChainVotes (r:1 w:1) - /// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasDisputes Frozen (r:1 w:0) - /// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion PendingAvailability (r:2 w:1) - /// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Parachains (r:1 w:0) - /// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) - /// Proof Skipped: ParaInclusion PendingAvailabilityCommitments (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaSessionInfo AccountKeys (r:1 w:0) - /// Proof Skipped: ParaSessionInfo AccountKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking ActiveEra (r:1 w:0) - /// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen) - /// Storage: Staking ErasRewardPoints (r:1 w:1) - /// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:1) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpChannelDigests (r:1 w:1) - /// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras FutureCodeUpgrades (r:1 w:0) - /// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasDisputes Disputes (r:1 w:0) - /// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaScheduler SessionStartBlock (r:1 w:0) - /// Proof Skipped: ParaScheduler SessionStartBlock (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler ParathreadQueue (r:1 w:1) - /// Proof Skipped: ParaScheduler ParathreadQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler Scheduled (r:1 w:1) - /// Proof Skipped: ParaScheduler Scheduled (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler ValidatorGroups (r:1 w:0) - /// Proof Skipped: ParaScheduler ValidatorGroups (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion AvailabilityBitfields (r:0 w:1) - /// Proof Skipped: ParaInclusion AvailabilityBitfields (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasDisputes Included (r:0 w:1) - /// Proof Skipped: ParasDisputes Included (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpWatermarks (r:0 w:1) - /// Proof Skipped: Hrmp HrmpWatermarks (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Heads (r:0 w:1) - /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeGoAheadSignal (r:0 w:1) - /// Proof Skipped: Paras UpgradeGoAheadSignal (max_values: None, max_size: None, mode: Measured) + /// Storage: `ParaInherent::Included` (r:1 w:1) + /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::ParentHash` (r:1 w:0) + /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) + /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) + /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) + /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) + /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1) + /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Frozen` (r:1 w:0) + /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaInclusion::V1` (r:2 w:1) + /// Proof: `ParaInclusion::V1` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParaSessionInfo::AccountKeys` (r:1 w:0) + /// Proof: `ParaSessionInfo::AccountKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Session::Validators` (r:1 w:0) + /// Proof: `Session::Validators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ActiveEra` (r:1 w:0) + /// Proof: `Staking::ActiveEra` (`max_values`: Some(1), `max_size`: Some(13), added: 508, mode: `MaxEncodedLen`) + /// Storage: `Staking::ErasRewardPoints` (r:1 w:1) + /// Proof: `Staking::ErasRewardPoints` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:1) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1) + /// Proof: `Hrmp::HrmpChannelDigests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0) + /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Disputes` (r:1 w:0) + /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) + /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Session::DisabledValidators` (r:1 w:0) + /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Included` (r:0 w:1) + /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) + /// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:0 w:1) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1) + /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::MostRecentContext` (r:0 w:1) + /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) fn enter_bitfields() -> Weight { // Proof Size summary in bytes: - // Measured: `42352` - // Estimated: `48292` - // Minimum execution time: 457_404_000 picoseconds. - Weight::from_parts(485_416_000, 0) - .saturating_add(Weight::from_parts(0, 48292)) - .saturating_add(T::DbWeight::get().reads(25)) + // Measured: `43196` + // Estimated: `49136` + // Minimum execution time: 438_637_000 picoseconds. + Weight::from_parts(458_342_000, 0) + .saturating_add(Weight::from_parts(0, 49136)) + .saturating_add(T::DbWeight::get().reads(26)) .saturating_add(T::DbWeight::get().writes(16)) } - /// Storage: ParaInherent Included (r:1 w:1) - /// Proof Skipped: ParaInherent Included (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System ParentHash (r:1 w:0) - /// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler AvailabilityCores (r:1 w:1) - /// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Babe AuthorVrfRandomness (r:1 w:0) - /// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) - /// Storage: ParaInherent OnChainVotes (r:1 w:1) - /// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasDisputes Frozen (r:1 w:0) - /// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion PendingAvailability (r:2 w:1) - /// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Parachains (r:1 w:0) - /// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) - /// Proof Skipped: ParaInclusion PendingAvailabilityCommitments (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaSessionInfo AccountKeys (r:1 w:0) - /// Proof Skipped: ParaSessionInfo AccountKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking ActiveEra (r:1 w:0) - /// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen) - /// Storage: Staking ErasRewardPoints (r:1 w:1) - /// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:1) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpChannelDigests (r:1 w:1) - /// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras FutureCodeUpgrades (r:1 w:0) - /// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasDisputes Disputes (r:1 w:0) - /// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaScheduler SessionStartBlock (r:1 w:0) - /// Proof Skipped: ParaScheduler SessionStartBlock (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler ParathreadQueue (r:1 w:1) - /// Proof Skipped: ParaScheduler ParathreadQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler Scheduled (r:1 w:1) - /// Proof Skipped: ParaScheduler Scheduled (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler ValidatorGroups (r:1 w:0) - /// Proof Skipped: ParaScheduler ValidatorGroups (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras CurrentCodeHash (r:1 w:0) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:0) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: MessageQueue BookStateFor (r:1 w:0) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: ParasDisputes Included (r:0 w:1) - /// Proof Skipped: ParasDisputes Included (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpWatermarks (r:0 w:1) - /// Proof Skipped: Hrmp HrmpWatermarks (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Heads (r:0 w:1) - /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeGoAheadSignal (r:0 w:1) - /// Proof Skipped: Paras UpgradeGoAheadSignal (max_values: None, max_size: None, mode: Measured) + /// Storage: `ParaInherent::Included` (r:1 w:1) + /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::ParentHash` (r:1 w:0) + /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) + /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) + /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) + /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) + /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1) + /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Frozen` (r:1 w:0) + /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaInclusion::V1` (r:2 w:1) + /// Proof: `ParaInclusion::V1` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParaSessionInfo::AccountKeys` (r:1 w:0) + /// Proof: `ParaSessionInfo::AccountKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Session::Validators` (r:1 w:0) + /// Proof: `Session::Validators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ActiveEra` (r:1 w:0) + /// Proof: `Staking::ActiveEra` (`max_values`: Some(1), `max_size`: Some(13), added: 508, mode: `MaxEncodedLen`) + /// Storage: `Staking::ErasRewardPoints` (r:1 w:1) + /// Proof: `Staking::ErasRewardPoints` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:1) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1) + /// Proof: `Hrmp::HrmpChannelDigests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0) + /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Disputes` (r:1 w:0) + /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) + /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CurrentCodeHash` (r:1 w:0) + /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:1 w:0) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:0) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Session::DisabledValidators` (r:1 w:0) + /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Included` (r:0 w:1) + /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) + /// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:0 w:1) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1) + /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::MostRecentContext` (r:0 w:1) + /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `v` is `[101, 200]`. fn enter_backed_candidates_variable(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `42387` - // Estimated: `48327` - // Minimum execution time: 6_864_029_000 picoseconds. - Weight::from_parts(1_237_704_892, 0) - .saturating_add(Weight::from_parts(0, 48327)) - // Standard Error: 33_413 - .saturating_add(Weight::from_parts(56_199_819, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(28)) - .saturating_add(T::DbWeight::get().writes(15)) + // Measured: `43269` + // Estimated: `49209` + // Minimum execution time: 5_955_361_000 picoseconds. + Weight::from_parts(1_285_398_956, 0) + .saturating_add(Weight::from_parts(0, 49209)) + // Standard Error: 57_369 + .saturating_add(Weight::from_parts(47_073_853, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(29)) + .saturating_add(T::DbWeight::get().writes(16)) } - /// Storage: ParaInherent Included (r:1 w:1) - /// Proof Skipped: ParaInherent Included (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System ParentHash (r:1 w:0) - /// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler AvailabilityCores (r:1 w:1) - /// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Babe AuthorVrfRandomness (r:1 w:0) - /// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) - /// Storage: ParaInherent OnChainVotes (r:1 w:1) - /// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasDisputes Frozen (r:1 w:0) - /// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion PendingAvailability (r:2 w:1) - /// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Parachains (r:1 w:0) - /// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) - /// Proof Skipped: ParaInclusion PendingAvailabilityCommitments (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaSessionInfo AccountKeys (r:1 w:0) - /// Proof Skipped: ParaSessionInfo AccountKeys (max_values: None, max_size: None, mode: Measured) - /// Storage: Session Validators (r:1 w:0) - /// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Staking ActiveEra (r:1 w:0) - /// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen) - /// Storage: Staking ErasRewardPoints (r:1 w:1) - /// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:1) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpChannelDigests (r:1 w:1) - /// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras FutureCodeUpgrades (r:1 w:0) - /// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasDisputes Disputes (r:1 w:0) - /// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured) - /// Storage: ParaScheduler SessionStartBlock (r:1 w:0) - /// Proof Skipped: ParaScheduler SessionStartBlock (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler ParathreadQueue (r:1 w:1) - /// Proof Skipped: ParaScheduler ParathreadQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler Scheduled (r:1 w:1) - /// Proof Skipped: ParaScheduler Scheduled (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParaScheduler ValidatorGroups (r:1 w:0) - /// Proof Skipped: ParaScheduler ValidatorGroups (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras CurrentCodeHash (r:1 w:0) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras FutureCodeHash (r:1 w:0) - /// Proof Skipped: Paras FutureCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeRestrictionSignal (r:1 w:0) - /// Proof Skipped: Paras UpgradeRestrictionSignal (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:0) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: MessageQueue BookStateFor (r:1 w:0) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: ParasDisputes Included (r:0 w:1) - /// Proof Skipped: ParasDisputes Included (max_values: None, max_size: None, mode: Measured) - /// Storage: Hrmp HrmpWatermarks (r:0 w:1) - /// Proof Skipped: Hrmp HrmpWatermarks (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Heads (r:0 w:1) - /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeGoAheadSignal (r:0 w:1) - /// Proof Skipped: Paras UpgradeGoAheadSignal (max_values: None, max_size: None, mode: Measured) + /// Storage: `ParaInherent::Included` (r:1 w:1) + /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::ParentHash` (r:1 w:0) + /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) + /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) + /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) + /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) + /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1) + /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Frozen` (r:1 w:0) + /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaInclusion::V1` (r:2 w:1) + /// Proof: `ParaInclusion::V1` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParaSessionInfo::AccountKeys` (r:1 w:0) + /// Proof: `ParaSessionInfo::AccountKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Session::Validators` (r:1 w:0) + /// Proof: `Session::Validators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ActiveEra` (r:1 w:0) + /// Proof: `Staking::ActiveEra` (`max_values`: Some(1), `max_size`: Some(13), added: 508, mode: `MaxEncodedLen`) + /// Storage: `Staking::ErasRewardPoints` (r:1 w:1) + /// Proof: `Staking::ErasRewardPoints` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:1) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1) + /// Proof: `Hrmp::HrmpChannelDigests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0) + /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Disputes` (r:1 w:0) + /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) + /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CurrentCodeHash` (r:1 w:0) + /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::FutureCodeHash` (r:1 w:0) + /// Proof: `Paras::FutureCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeRestrictionSignal` (r:1 w:0) + /// Proof: `Paras::UpgradeRestrictionSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:1 w:0) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:0) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Session::DisabledValidators` (r:1 w:0) + /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Included` (r:0 w:1) + /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) + /// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:0 w:1) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1) + /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::MostRecentContext` (r:0 w:1) + /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) fn enter_backed_candidate_code_upgrade() -> Weight { // Proof Size summary in bytes: - // Measured: `42414` - // Estimated: `48354` - // Minimum execution time: 43_320_529_000 picoseconds. - Weight::from_parts(45_622_613_000, 0) - .saturating_add(Weight::from_parts(0, 48354)) - .saturating_add(T::DbWeight::get().reads(30)) - .saturating_add(T::DbWeight::get().writes(15)) + // Measured: `43282` + // Estimated: `49222` + // Minimum execution time: 42_128_606_000 picoseconds. + Weight::from_parts(42_822_806_000, 0) + .saturating_add(Weight::from_parts(0, 49222)) + .saturating_add(T::DbWeight::get().reads(31)) + .saturating_add(T::DbWeight::get().writes(16)) } } diff --git a/prdoc/pr_3479.prdoc b/prdoc/pr_3479.prdoc new file mode 100644 index 00000000000..1e44ce5646b --- /dev/null +++ b/prdoc/pr_3479.prdoc @@ -0,0 +1,8 @@ +title: "Elastic scaling: runtime dependency tracking and enactment" + +doc: + - audience: Node Dev + description: | + Adds support in the inclusion and paras_inherent runtime modules for backing and including multiple candidates of the same para if they form a chain. + +crates: [ ] -- GitLab From 64a707a4824ad12eb9ab715966dbd0d2b0efaf01 Mon Sep 17 00:00:00 2001 From: ordian Date: Thu, 21 Mar 2024 12:22:16 +0100 Subject: [PATCH 076/187] approval-voting: remove some inefficiences on startup (#3747) Small refactoring to reduce the algorithmic complexity of the initial message distribution in approval voting after a sync from O(n_candidates ^ 2) to O(n_candidates). --- polkadot/node/core/approval-voting/src/lib.rs | 274 +++++++++--------- 1 file changed, 129 insertions(+), 145 deletions(-) diff --git a/polkadot/node/core/approval-voting/src/lib.rs b/polkadot/node/core/approval-voting/src/lib.rs index 8cc16a6e1ec..1d7ab3eee21 100644 --- a/polkadot/node/core/approval-voting/src/lib.rs +++ b/polkadot/node/core/approval-voting/src/lib.rs @@ -55,9 +55,9 @@ use polkadot_node_subsystem_util::{ }; use polkadot_primitives::{ vstaging::{ApprovalVoteMultipleCandidates, ApprovalVotingParams}, - BlockNumber, CandidateHash, CandidateIndex, CandidateReceipt, DisputeStatement, ExecutorParams, - GroupIndex, Hash, PvfExecKind, SessionIndex, SessionInfo, ValidDisputeStatementKind, - ValidatorId, ValidatorIndex, ValidatorPair, ValidatorSignature, + BlockNumber, CandidateHash, CandidateIndex, CandidateReceipt, CoreIndex, DisputeStatement, + ExecutorParams, GroupIndex, Hash, PvfExecKind, SessionIndex, SessionInfo, + ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorPair, ValidatorSignature, }; use sc_keystore::LocalKeystore; use sp_application_crypto::Pair; @@ -1285,10 +1285,10 @@ fn cores_to_candidate_indices( // Map from core index to candidate index. for claimed_core_index in core_indices.iter_ones() { - if let Some(candidate_index) = block_entry + // Candidates are sorted by core index. + if let Ok(candidate_index) = block_entry .candidates() - .iter() - .position(|(core_index, _)| core_index.0 == claimed_core_index as u32) + .binary_search_by_key(&(claimed_core_index as u32), |(core_index, _)| core_index.0) { candidate_indices.push(candidate_index as _); } @@ -1297,6 +1297,21 @@ fn cores_to_candidate_indices( CandidateBitfield::try_from(candidate_indices) } +// Returns the claimed core bitfield from the assignment cert and the core index +// from the block entry. +fn get_core_indices_on_startup( + assignment: &AssignmentCertKindV2, + block_entry_core_index: CoreIndex, +) -> CoreBitfield { + match &assignment { + AssignmentCertKindV2::RelayVRFModuloCompact { core_bitfield } => core_bitfield.clone(), + AssignmentCertKindV2::RelayVRFModulo { sample: _ } => + CoreBitfield::try_from(vec![block_entry_core_index]).expect("Not an empty vec; qed"), + AssignmentCertKindV2::RelayVRFDelay { core_index } => + CoreBitfield::try_from(vec![*core_index]).expect("Not an empty vec; qed"), + } +} + // Returns the claimed core bitfield from the assignment cert, the candidate hash and a // `BlockEntry`. Can fail only for VRF Delay assignments for which we cannot find the candidate hash // in the block entry which indicates a bug or corrupted storage. @@ -1367,7 +1382,7 @@ async fn distribution_messages_for_activation( session: block_entry.session(), }); let mut signatures_queued = HashSet::new(); - for (_, candidate_hash) in block_entry.candidates() { + for (core_index, candidate_hash) in block_entry.candidates() { let _candidate_span = distribution_message_span.child("candidate").with_candidate(*candidate_hash); let candidate_entry = match db.load_candidate_entry(&candidate_hash)? { @@ -1389,152 +1404,121 @@ async fn distribution_messages_for_activation( match approval_entry.local_statements() { (None, None) | (None, Some(_)) => {}, // second is impossible case. (Some(assignment), None) => { - if let Some(claimed_core_indices) = get_assignment_core_indices( - &assignment.cert().kind, - &candidate_hash, - &block_entry, - ) { - if block_entry.has_candidates_pending_signature() { - delayed_approvals_timers.maybe_arm_timer( - state.clock.tick_now(), - state.clock.as_ref(), - block_entry.block_hash(), - assignment.validator_index(), - ) - } + let claimed_core_indices = + get_core_indices_on_startup(&assignment.cert().kind, *core_index); + + if block_entry.has_candidates_pending_signature() { + delayed_approvals_timers.maybe_arm_timer( + state.clock.tick_now(), + state.clock.as_ref(), + block_entry.block_hash(), + assignment.validator_index(), + ) + } - match cores_to_candidate_indices( - &claimed_core_indices, - &block_entry, - ) { - Ok(bitfield) => { - gum::debug!( - target: LOG_TARGET, - candidate_hash = ?candidate_entry.candidate_receipt().hash(), - ?block_hash, - "Discovered, triggered assignment, not approved yet", - ); - - let indirect_cert = IndirectAssignmentCertV2 { - block_hash, - validator: assignment.validator_index(), - cert: assignment.cert().clone(), - }; - messages.push( - ApprovalDistributionMessage::DistributeAssignment( - indirect_cert.clone(), - bitfield.clone(), - ), - ); - - if !block_entry - .candidate_is_pending_signature(*candidate_hash) - { - let ExtendedSessionInfo { ref executor_params, .. } = - match get_extended_session_info( - session_info_provider, - ctx.sender(), - block_entry.block_hash(), - block_entry.session(), - ) - .await - { - Some(i) => i, - None => continue, - }; - - actions.push(Action::LaunchApproval { - claimed_candidate_indices: bitfield, - candidate_hash: candidate_entry - .candidate_receipt() - .hash(), - indirect_cert, - assignment_tranche: assignment.tranche(), - relay_block_hash: block_hash, - session: block_entry.session(), - executor_params: executor_params.clone(), - candidate: candidate_entry - .candidate_receipt() - .clone(), - backing_group: approval_entry.backing_group(), - distribute_assignment: false, - }); - } - }, - Err(err) => { - // Should never happen. If we fail here it means the - // assignment is null (no cores claimed). - gum::warn!( - target: LOG_TARGET, - ?block_hash, - ?candidate_hash, - ?err, - "Failed to create assignment bitfield", - ); - }, - } - } else { - gum::warn!( - target: LOG_TARGET, - ?block_hash, - ?candidate_hash, - "Cannot get assignment claimed core indices", - ); + match cores_to_candidate_indices(&claimed_core_indices, &block_entry) { + Ok(bitfield) => { + gum::debug!( + target: LOG_TARGET, + candidate_hash = ?candidate_entry.candidate_receipt().hash(), + ?block_hash, + "Discovered, triggered assignment, not approved yet", + ); + + let indirect_cert = IndirectAssignmentCertV2 { + block_hash, + validator: assignment.validator_index(), + cert: assignment.cert().clone(), + }; + messages.push( + ApprovalDistributionMessage::DistributeAssignment( + indirect_cert.clone(), + bitfield.clone(), + ), + ); + + if !block_entry.candidate_is_pending_signature(*candidate_hash) + { + let ExtendedSessionInfo { ref executor_params, .. } = + match get_extended_session_info( + session_info_provider, + ctx.sender(), + block_entry.block_hash(), + block_entry.session(), + ) + .await + { + Some(i) => i, + None => continue, + }; + + actions.push(Action::LaunchApproval { + claimed_candidate_indices: bitfield, + candidate_hash: candidate_entry + .candidate_receipt() + .hash(), + indirect_cert, + assignment_tranche: assignment.tranche(), + relay_block_hash: block_hash, + session: block_entry.session(), + executor_params: executor_params.clone(), + candidate: candidate_entry.candidate_receipt().clone(), + backing_group: approval_entry.backing_group(), + distribute_assignment: false, + }); + } + }, + Err(err) => { + // Should never happen. If we fail here it means the + // assignment is null (no cores claimed). + gum::warn!( + target: LOG_TARGET, + ?block_hash, + ?candidate_hash, + ?err, + "Failed to create assignment bitfield", + ); + }, } }, (Some(assignment), Some(approval_sig)) => { - if let Some(claimed_core_indices) = get_assignment_core_indices( - &assignment.cert().kind, - &candidate_hash, - &block_entry, - ) { - match cores_to_candidate_indices( - &claimed_core_indices, - &block_entry, - ) { - Ok(bitfield) => messages.push( - ApprovalDistributionMessage::DistributeAssignment( - IndirectAssignmentCertV2 { - block_hash, - validator: assignment.validator_index(), - cert: assignment.cert().clone(), - }, - bitfield, - ), - ), - Err(err) => { - gum::warn!( - target: LOG_TARGET, - ?block_hash, - ?candidate_hash, - ?err, - "Failed to create assignment bitfield", - ); - // If we didn't send assignment, we don't send approval. - continue - }, - } - if signatures_queued - .insert(approval_sig.signed_candidates_indices.clone()) - { - messages.push(ApprovalDistributionMessage::DistributeApproval( - IndirectSignedApprovalVoteV2 { + let claimed_core_indices = + get_core_indices_on_startup(&assignment.cert().kind, *core_index); + match cores_to_candidate_indices(&claimed_core_indices, &block_entry) { + Ok(bitfield) => messages.push( + ApprovalDistributionMessage::DistributeAssignment( + IndirectAssignmentCertV2 { block_hash, - candidate_indices: approval_sig - .signed_candidates_indices, validator: assignment.validator_index(), - signature: approval_sig.signature, + cert: assignment.cert().clone(), }, - )) - }; - } else { - gum::warn!( - target: LOG_TARGET, - ?block_hash, - ?candidate_hash, - "Cannot get assignment claimed core indices", - ); + bitfield, + ), + ), + Err(err) => { + gum::warn!( + target: LOG_TARGET, + ?block_hash, + ?candidate_hash, + ?err, + "Failed to create assignment bitfield", + ); + // If we didn't send assignment, we don't send approval. + continue + }, } + if signatures_queued + .insert(approval_sig.signed_candidates_indices.clone()) + { + messages.push(ApprovalDistributionMessage::DistributeApproval( + IndirectSignedApprovalVoteV2 { + block_hash, + candidate_indices: approval_sig.signed_candidates_indices, + validator: assignment.validator_index(), + signature: approval_sig.signature, + }, + )) + }; }, } }, -- GitLab From 9922fd39437cea5797564145bfd1adb989fd57d1 Mon Sep 17 00:00:00 2001 From: kvalerio <24193167+kevin-valerio@users.noreply.github.com> Date: Thu, 21 Mar 2024 13:18:41 +0100 Subject: [PATCH 077/187] there's a typo (#3779) There was a typo, so now, there's no more typo. Co-authored-by: Liam Aharon --- substrate/primitives/runtime/src/multiaddress.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/primitives/runtime/src/multiaddress.rs b/substrate/primitives/runtime/src/multiaddress.rs index 89b0a3bcf8c..c435606312e 100644 --- a/substrate/primitives/runtime/src/multiaddress.rs +++ b/substrate/primitives/runtime/src/multiaddress.rs @@ -32,7 +32,7 @@ pub enum MultiAddress { Raw(Vec), /// It's a 32 byte representation. Address32([u8; 32]), - /// Its a 20 byte representation. + /// It's a 20 byte representation. Address20([u8; 20]), } -- GitLab From 46ba85500ffc77fa8e267c5f38b2c213550d68fa Mon Sep 17 00:00:00 2001 From: Tsvetomir Dimitrov Date: Thu, 21 Mar 2024 14:46:55 +0200 Subject: [PATCH 078/187] Fix toml formatting (#3782) Make taplo happy --- substrate/primitives/arithmetic/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/primitives/arithmetic/Cargo.toml b/substrate/primitives/arithmetic/Cargo.toml index 64c1025b585..120edd06a66 100644 --- a/substrate/primitives/arithmetic/Cargo.toml +++ b/substrate/primitives/arithmetic/Cargo.toml @@ -43,7 +43,7 @@ std = [ "scale-info/std", "serde/std", "sp-crypto-hashing/std", - "sp-std/std", + "sp-std/std", ] # Serde support without relying on std features. serde = ["dep:serde", "scale-info/serde"] -- GitLab From 01d65f6b995021bfe7be184581895dc374285f06 Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Andres <11448715+al3mart@users.noreply.github.com> Date: Thu, 21 Mar 2024 17:49:23 +0100 Subject: [PATCH 079/187] Revert `SendXcmOrigin` in Rococo & Westend (#2571) Based on issue [#2512](https://github.com/paritytech/polkadot-sdk/issues/2512), it seems that some ecosystem teams are using these networks to set up their staging environments and test certain use cases, some of them involving sending XCMs from the relay with origins not allowed in the current configuration. This change reverts the configuration of `SendXcmOrigin`. --------- Co-authored-by: Adrian Catangiu --- polkadot/runtime/rococo/src/xcm_config.rs | 8 +++----- polkadot/runtime/westend/src/xcm_config.rs | 4 +++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/polkadot/runtime/rococo/src/xcm_config.rs b/polkadot/runtime/rococo/src/xcm_config.rs index 328879715de..c7063bd7ad6 100644 --- a/polkadot/runtime/rococo/src/xcm_config.rs +++ b/polkadot/runtime/rococo/src/xcm_config.rs @@ -259,11 +259,9 @@ pub type LocalPalletOriginToLocation = ( impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; - // We only allow the root, fellows and the staking admin to send messages. - // This is basically safe to enable for everyone (safe the possibility of someone spamming the - // parachain if they're willing to pay the KSM to send from the Relay-chain), but it's useless - // until we bring in XCM v3 which will make `DescendOrigin` a bit more useful. - type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; + // Note that this configuration of `SendXcmOrigin` is different from the one present in + // production. + type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; type XcmRouter = XcmRouter; // Anyone can execute XCM messages locally. type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index 73127cb1efd..400843c5835 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -272,7 +272,9 @@ pub type LocalPalletOriginToLocation = ( impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; + // Note that this configuration of `SendXcmOrigin` is different from the one present in + // production. + type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; type XcmRouter = XcmRouter; // Anyone can execute XCM messages locally... type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; -- GitLab From ea5f4e9a4d78234eb68bbb9130a24b0598c7893a Mon Sep 17 00:00:00 2001 From: "Will | Paradox | ParaNodes.io" <79228812+paradox-tt@users.noreply.github.com> Date: Fri, 22 Mar 2024 00:07:24 +0000 Subject: [PATCH 080/187] Adding LF's bootnodes to relay and system chains (#3514) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Good day, I'm seeking to add the following bootnodes for Kusama and Polkadot's relay and system chains. The following commands can be used to test connectivity. All node keys are backed up. Polkadot: ``` polkadot --chain polkadot --base-path /tmp/node --name "Boot" --reserved-only --reserved-nodes "/dns/boot-polkadot.luckyfriday.io/tcp/443/wss/p2p/12D3KooWAdyiVAaeGdtBt6vn5zVetwA4z4qfm9Fi2QCSykN1wTBJ" --no-hardware-benchmarks ``` Assethub-Polkadot: ``` polkadot-parachain --chain asset-hub-polkadot --base-path /tmp/node --name "Boot" --reserved-only --reserved-nodes "/dns/boot-polkadot-assethub.luckyfriday.io/tcp/443/wss/p2p/12D3KooWDR9M7CjV1xdjCRbRwkFn1E7sjMaL4oYxGyDWxuLrFc2J" --no-hardware-benchmarks ``` Bridgehub-Polkadot: ``` polkadot-parachain --chain bridge-hub-polkadot --base-path /tmp/node --name "Boot" --reserved-only --reserved-nodes "/dns/boot-polkadot-bridgehub.luckyfriday.io/tcp/443/wss/p2p/12D3KooWKf3mBXHjLbwtPqv1BdbQuwbFNcQQYxASS7iQ25264AXH" --no-hardware-benchmarks ``` Collectives-Polkadot ``` polkadot-parachain --chain collectives-polkadot --base-path /tmp/node --name "Boot" --reserved-only --reserved-nodes "/dns/boot-polkadot-collectives.luckyfriday.io/tcp/443/wss/p2p/12D3KooWCzifnPooTt4kvTnXT7FTKTymVL7xn7DURQLsS2AKpf6w" --no-hardware-benchmarks ``` Kusama: ``` polkadot --chain kusama --base-path /tmp/node --name "Boot" --reserved-only --reserved-nodes "/dns/boot-kusama.luckyfriday.io/tcp/443/wss/p2p/12D3KooWS1Lu6DmK8YHSvkErpxpcXmk14vG6y4KVEFEkd9g62PP8" --no-hardware-benchmarks ``` Assethub-Kusama: ``` polkadot-parachain --chain asset-hub-kusama --base-path /tmp/node --name "Boot" --reserved-only --reserved-nodes "/dns/boot-kusama-assethub.luckyfriday.io/tcp/443/wss/p2p/12D3KooWSwaeFs6FNgpgh54fdoxSDAA4nJNaPE3PAcse2GRrG7b3" --no-hardware-benchmarks ``` Bridgehub-Kusama: ``` polkadot-parachain --chain bridge-hub-kusama --base-path /tmp/node --name "Boot" --reserved-only --reserved-nodes "/dns/boot-kusama-bridgehub.luckyfriday.io/tcp/443/wss/p2p/12D3KooWQybw6AFmAvrFfwUQnNxUpS12RovapD6oorh2mAJr4xyd" --no-hardware-benchmarks ``` Co-authored-by: Bastian Köcher --- cumulus/parachains/chain-specs/asset-hub-kusama.json | 3 ++- cumulus/parachains/chain-specs/asset-hub-polkadot.json | 3 ++- cumulus/parachains/chain-specs/bridge-hub-kusama.json | 3 ++- cumulus/parachains/chain-specs/bridge-hub-polkadot.json | 3 ++- cumulus/parachains/chain-specs/collectives-polkadot.json | 3 ++- polkadot/node/service/chain-specs/kusama.json | 1 + polkadot/node/service/chain-specs/polkadot.json | 3 ++- 7 files changed, 13 insertions(+), 6 deletions(-) diff --git a/cumulus/parachains/chain-specs/asset-hub-kusama.json b/cumulus/parachains/chain-specs/asset-hub-kusama.json index 654275eade8..66a705a4086 100644 --- a/cumulus/parachains/chain-specs/asset-hub-kusama.json +++ b/cumulus/parachains/chain-specs/asset-hub-kusama.json @@ -27,7 +27,8 @@ "/dns/mine14.rotko.net/tcp/34524/ws/p2p/12D3KooWJUFnjR2PNbsJhudwPVaWCoZy1acPGKjM2cSuGj345BBu", "/dns/mine14.rotko.net/tcp/35524/wss/p2p/12D3KooWJUFnjR2PNbsJhudwPVaWCoZy1acPGKjM2cSuGj345BBu", "/dns/asset-hub-kusama.bootnodes.polkadotters.com/tcp/30511/p2p/12D3KooWDpk7wVH7RgjErEvbvAZ2kY5VeaAwRJP5ojmn1e8b8UbU", - "/dns/asset-hub-kusama.bootnodes.polkadotters.com/tcp/30513/wss/p2p/12D3KooWDpk7wVH7RgjErEvbvAZ2kY5VeaAwRJP5ojmn1e8b8UbU" + "/dns/asset-hub-kusama.bootnodes.polkadotters.com/tcp/30513/wss/p2p/12D3KooWDpk7wVH7RgjErEvbvAZ2kY5VeaAwRJP5ojmn1e8b8UbU", + "/dns/boot-kusama-assethub.luckyfriday.io/tcp/443/wss/p2p/12D3KooWSwaeFs6FNgpgh54fdoxSDAA4nJNaPE3PAcse2GRrG7b3" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/asset-hub-polkadot.json b/cumulus/parachains/chain-specs/asset-hub-polkadot.json index 454060d2a87..16caa52ba91 100644 --- a/cumulus/parachains/chain-specs/asset-hub-polkadot.json +++ b/cumulus/parachains/chain-specs/asset-hub-polkadot.json @@ -27,7 +27,8 @@ "/dns/mint14.rotko.net/tcp/34514/ws/p2p/12D3KooWKkzLjYF6M5eEs7nYiqEtRqY8SGVouoCwo3nCWsRnThDW", "/dns/mint14.rotko.net/tcp/35514/wss/p2p/12D3KooWKkzLjYF6M5eEs7nYiqEtRqY8SGVouoCwo3nCWsRnThDW", "/dns/asset-hub-polkadot.bootnodes.polkadotters.com/tcp/30508/p2p/12D3KooWKbfY9a9oywxMJKiALmt7yhrdQkjXMtvxhhDDN23vG93R", - "/dns/asset-hub-polkadot.bootnodes.polkadotters.com/tcp/30510/wss/p2p/12D3KooWKbfY9a9oywxMJKiALmt7yhrdQkjXMtvxhhDDN23vG93R" + "/dns/asset-hub-polkadot.bootnodes.polkadotters.com/tcp/30510/wss/p2p/12D3KooWKbfY9a9oywxMJKiALmt7yhrdQkjXMtvxhhDDN23vG93R", + "/dns/boot-polkadot-assethub.luckyfriday.io/tcp/443/wss/p2p/12D3KooWDR9M7CjV1xdjCRbRwkFn1E7sjMaL4oYxGyDWxuLrFc2J" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/bridge-hub-kusama.json b/cumulus/parachains/chain-specs/bridge-hub-kusama.json index 90b70b05016..6644ea41ab7 100644 --- a/cumulus/parachains/chain-specs/bridge-hub-kusama.json +++ b/cumulus/parachains/chain-specs/bridge-hub-kusama.json @@ -27,7 +27,8 @@ "/dns/kbr13.rotko.net/tcp/34553/ws/p2p/12D3KooWAmBp54mUEYtvsk2kxNEsDbAvdUMcaghxKXgUQxmPEQ66", "/dns/kbr13.rotko.net/tcp/35553/wss/p2p/12D3KooWAmBp54mUEYtvsk2kxNEsDbAvdUMcaghxKXgUQxmPEQ66", "/dns/bridge-hub-kusama.bootnodes.polkadotters.com/tcp/30520/p2p/12D3KooWH3pucezRRS5esoYyzZsUkKWcPSByQxEvmM819QL1HPLV", - "/dns/bridge-hub-kusama.bootnodes.polkadotters.com/tcp/30522/wss/p2p/12D3KooWH3pucezRRS5esoYyzZsUkKWcPSByQxEvmM819QL1HPLV" + "/dns/bridge-hub-kusama.bootnodes.polkadotters.com/tcp/30522/wss/p2p/12D3KooWH3pucezRRS5esoYyzZsUkKWcPSByQxEvmM819QL1HPLV", + "/dns/boot-kusama-bridgehub.luckyfriday.io/tcp/443/wss/p2p/12D3KooWQybw6AFmAvrFfwUQnNxUpS12RovapD6oorh2mAJr4xyd" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/bridge-hub-polkadot.json b/cumulus/parachains/chain-specs/bridge-hub-polkadot.json index a9444b89e1e..c51c5eff89b 100644 --- a/cumulus/parachains/chain-specs/bridge-hub-polkadot.json +++ b/cumulus/parachains/chain-specs/bridge-hub-polkadot.json @@ -23,7 +23,8 @@ "/dns/pbr13.rotko.net/tcp/34543/ws/p2p/12D3KooWMxZY7tDc2Rh454VaJJ7RexKAXVS6xSBEvTnXSGCnuGDw", "/dns/pbr13.rotko.net/tcp/35543/wss/p2p/12D3KooWMxZY7tDc2Rh454VaJJ7RexKAXVS6xSBEvTnXSGCnuGDw", "/dns/bridge-hub-polkadot.bootnodes.polkadotters.com/tcp/30517/p2p/12D3KooWLUNE3LHPDa1WrrZaYT7ArK66CLM1bPv7kKz74UcLnQRB", - "/dns/bridge-hub-polkadot.bootnodes.polkadotters.com/tcp/30519/wss/p2p/12D3KooWLUNE3LHPDa1WrrZaYT7ArK66CLM1bPv7kKz74UcLnQRB" + "/dns/bridge-hub-polkadot.bootnodes.polkadotters.com/tcp/30519/wss/p2p/12D3KooWLUNE3LHPDa1WrrZaYT7ArK66CLM1bPv7kKz74UcLnQRB", + "/dns/boot-polkadot-bridgehub.luckyfriday.io/tcp/443/wss/p2p/12D3KooWKf3mBXHjLbwtPqv1BdbQuwbFNcQQYxASS7iQ25264AXH" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/collectives-polkadot.json b/cumulus/parachains/chain-specs/collectives-polkadot.json index 259669cf37a..ce80e21ae62 100644 --- a/cumulus/parachains/chain-specs/collectives-polkadot.json +++ b/cumulus/parachains/chain-specs/collectives-polkadot.json @@ -27,7 +27,8 @@ "/dns/pch13.rotko.net/tcp/34573/ws/p2p/12D3KooWRXudHoazPZ9osMfdY38e8CBxQLD4RhrVeHpRSNNpcDtH", "/dns/pch13.rotko.net/tcp/35573/wss/p2p/12D3KooWRXudHoazPZ9osMfdY38e8CBxQLD4RhrVeHpRSNNpcDtH", "/dns/collectives-polkadot.bootnodes.polkadotters.com/tcp/30526/p2p/12D3KooWNohUjvJtGKUa8Vhy8C1ZBB5N8JATB6e7rdLVCioeb3ff", - "/dns/collectives-polkadot.bootnodes.polkadotters.com/tcp/30528/wss/p2p/12D3KooWNohUjvJtGKUa8Vhy8C1ZBB5N8JATB6e7rdLVCioeb3ff" + "/dns/collectives-polkadot.bootnodes.polkadotters.com/tcp/30528/wss/p2p/12D3KooWNohUjvJtGKUa8Vhy8C1ZBB5N8JATB6e7rdLVCioeb3ff", + "/dns/boot-polkadot-collectives.luckyfriday.io/tcp/443/wss/p2p/12D3KooWCzifnPooTt4kvTnXT7FTKTymVL7xn7DURQLsS2AKpf6w" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/polkadot/node/service/chain-specs/kusama.json b/polkadot/node/service/chain-specs/kusama.json index fd60cb8b6c1..490b39ee696 100644 --- a/polkadot/node/service/chain-specs/kusama.json +++ b/polkadot/node/service/chain-specs/kusama.json @@ -35,6 +35,7 @@ "/dns/ksm14.rotko.net/tcp/35224/wss/p2p/12D3KooWAa5THTw8HPfnhEei23HdL8P9McBXdozG2oTtMMksjZkK", "/dns/ksm14.rotko.net/tcp/33224/p2p/12D3KooWAa5THTw8HPfnhEei23HdL8P9McBXdozG2oTtMMksjZkK", "/dns/ibp-boot-kusama.luckyfriday.io/tcp/30333/p2p/12D3KooW9vu1GWHBuxyhm7rZgD3fhGZpNajPXFexadvhujWMgwfT", + "/dns/boot-kusama.luckyfriday.io/tcp/443/wss/p2p/12D3KooWS1Lu6DmK8YHSvkErpxpcXmk14vG6y4KVEFEkd9g62PP8", "/dns/ibp-boot-kusama.luckyfriday.io/tcp/30334/wss/p2p/12D3KooW9vu1GWHBuxyhm7rZgD3fhGZpNajPXFexadvhujWMgwfT" ], "telemetryEndpoints": [ diff --git a/polkadot/node/service/chain-specs/polkadot.json b/polkadot/node/service/chain-specs/polkadot.json index c235cdd09d8..5f8d88102d7 100644 --- a/polkadot/node/service/chain-specs/polkadot.json +++ b/polkadot/node/service/chain-specs/polkadot.json @@ -36,7 +36,8 @@ "/dns/dot14.rotko.net/tcp/35214/wss/p2p/12D3KooWPyEvPEXghnMC67Gff6PuZiSvfx3fmziKiPZcGStZ5xff", "/dns/dot14.rotko.net/tcp/33214/p2p/12D3KooWPyEvPEXghnMC67Gff6PuZiSvfx3fmziKiPZcGStZ5xff", "/dns/ibp-boot-polkadot.luckyfriday.io/tcp/30333/p2p/12D3KooWEjk6QXrZJ26fLpaajisJGHiz6WiQsR8k7mkM9GmWKnRZ", - "/dns/ibp-boot-polkadot.luckyfriday.io/tcp/30334/wss/p2p/12D3KooWEjk6QXrZJ26fLpaajisJGHiz6WiQsR8k7mkM9GmWKnRZ" + "/dns/ibp-boot-polkadot.luckyfriday.io/tcp/30334/wss/p2p/12D3KooWEjk6QXrZJ26fLpaajisJGHiz6WiQsR8k7mkM9GmWKnRZ", + "/dns/boot-polkadot.luckyfriday.io/tcp/443/wss/p2p/12D3KooWAdyiVAaeGdtBt6vn5zVetwA4z4qfm9Fi2QCSykN1wTBJ" ], "telemetryEndpoints": [ [ -- GitLab From 3410dfb3929462da88be2da813f121d8b1cf46b3 Mon Sep 17 00:00:00 2001 From: Clara van Staden Date: Fri, 22 Mar 2024 11:25:28 +0200 Subject: [PATCH 081/187] Snowbridge Beacon header age check (#3727) ## Bug Explanation Adds a check that prevents finalized headers with a gap larger than the sync committee period being imported, which could cause execution headers in the gap being unprovable. The current version of the Ethereum client checks that there is a header at least every sync committee, but it doesn't check that the headers are within a sync period of each other. For example: Header 100 (sync committee period 1) Header 9000 (sync committee period 2) (8900 blocks apart) These headers are in adjacent sync committees, but more than the sync committee period (8192 blocks) apart. The reason we need a header every 8192 slots at least, is the header is used to prove messages within the last 8192 blocks. If we import header 9000, and we receive a message to be verified at header 200, the `block_roots` field of header 9000 won't contain the header in order to do the ancestry check. ## Environment While running in Rococo, this edge case was discovered after the relayer was offline for a few days. It is unlikely, but not impossible, to happen again and so it should be backported to polkadot-sdk 1.7.0 (so that [polkadot-fellows/runtimes](https://github.com/polkadot-fellows/runtimes) can be updated with the fix). Our Ethereum client has been operational on Rococo for the past few months, and this been the only major issue discovered so far. ### Unrelated Change An unrelated nit: Removes a left over file that should have been deleted when the `parachain` directory was removed. --------- Co-authored-by: claravanstaden --- .../pallets/ethereum-client/src/lib.rs | 15 + .../pallets/ethereum-client/src/tests.rs | 57 +++- .../ethereum-beacon-client/src/mock.rs | 259 ------------------ 3 files changed, 71 insertions(+), 260 deletions(-) delete mode 100644 bridges/snowbridge/parachain/pallets/ethereum-beacon-client/src/mock.rs diff --git a/bridges/snowbridge/pallets/ethereum-client/src/lib.rs b/bridges/snowbridge/pallets/ethereum-client/src/lib.rs index a54d4a05ac5..fc2ab2fbb58 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/lib.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/lib.rs @@ -130,6 +130,10 @@ pub mod pallet { InvalidExecutionHeaderProof, InvalidAncestryMerkleProof, InvalidBlockRootsRootMerkleProof, + /// The gap between the finalized headers is larger than the sync committee period, + /// rendering execution headers unprovable using ancestry proofs (blocks root size is + /// the same as the sync committee period slots). + InvalidFinalizedHeaderGap, HeaderNotFinalized, BlockBodyHashTreeRootFailed, HeaderHashTreeRootFailed, @@ -398,6 +402,17 @@ pub mod pallet { Error::::IrrelevantUpdate ); + // Verify the finalized header gap between the current finalized header and new imported + // header is not larger than the sync committee period, otherwise we cannot do + // ancestry proofs for execution headers in the gap. + ensure!( + latest_finalized_state + .slot + .saturating_add(config::SLOTS_PER_HISTORICAL_ROOT as u64) >= + update.finalized_header.slot, + Error::::InvalidFinalizedHeaderGap + ); + // Verify that the `finality_branch`, if present, confirms `finalized_header` to match // the finalized checkpoint root saved in the state of `attested_header`. let finalized_block_root: H256 = update diff --git a/bridges/snowbridge/pallets/ethereum-client/src/tests.rs b/bridges/snowbridge/pallets/ethereum-client/src/tests.rs index 50b6a25c342..4a7b7b45886 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/tests.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/tests.rs @@ -15,7 +15,7 @@ use crate::mock::{ pub use crate::mock::*; -use crate::config::{EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH}; +use crate::config::{EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT}; use frame_support::{assert_err, assert_noop, assert_ok}; use hex_literal::hex; use primitives::{ @@ -884,6 +884,61 @@ fn submit_execution_header_not_finalized() { }); } +/// Check that a gap of more than 8192 slots between finalized headers is not allowed. +#[test] +fn submit_finalized_header_update_with_too_large_gap() { + let checkpoint = Box::new(load_checkpoint_update_fixture()); + let update = Box::new(load_sync_committee_update_fixture()); + let mut next_update = Box::new(load_next_sync_committee_update_fixture()); + + // Adds 8193 slots, so that the next update is still in the next sync committee, but the + // gap between the finalized headers is more than 8192 slots. + let slot_with_large_gap = checkpoint.header.slot + SLOTS_PER_HISTORICAL_ROOT as u64 + 1; + + next_update.finalized_header.slot = slot_with_large_gap; + // Adding some slots to the attested header and signature slot since they need to be ahead + // of the finalized header. + next_update.attested_header.slot = slot_with_large_gap + 33; + next_update.signature_slot = slot_with_large_gap + 43; + + new_tester().execute_with(|| { + assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); + assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone())); + assert!(>::exists()); + assert_err!( + EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_update.clone()), + Error::::InvalidFinalizedHeaderGap + ); + }); +} + +/// Check that a gap of 8192 slots between finalized headers is allowed. +#[test] +fn submit_finalized_header_update_with_gap_at_limit() { + let checkpoint = Box::new(load_checkpoint_update_fixture()); + let update = Box::new(load_sync_committee_update_fixture()); + let mut next_update = Box::new(load_next_sync_committee_update_fixture()); + + next_update.finalized_header.slot = checkpoint.header.slot + SLOTS_PER_HISTORICAL_ROOT as u64; + // Adding some slots to the attested header and signature slot since they need to be ahead + // of the finalized header. + next_update.attested_header.slot = + checkpoint.header.slot + SLOTS_PER_HISTORICAL_ROOT as u64 + 33; + next_update.signature_slot = checkpoint.header.slot + SLOTS_PER_HISTORICAL_ROOT as u64 + 43; + + new_tester().execute_with(|| { + assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); + assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone())); + assert!(>::exists()); + assert_err!( + EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_update.clone()), + // The test should pass the InvalidFinalizedHeaderGap check, and will fail at the + // next check, the merkle proof, because we changed the next_update slots. + Error::::InvalidHeaderMerkleProof + ); + }); +} + /* IMPLS */ #[test] diff --git a/bridges/snowbridge/parachain/pallets/ethereum-beacon-client/src/mock.rs b/bridges/snowbridge/parachain/pallets/ethereum-beacon-client/src/mock.rs deleted file mode 100644 index d2cca373e92..00000000000 --- a/bridges/snowbridge/parachain/pallets/ethereum-beacon-client/src/mock.rs +++ /dev/null @@ -1,259 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2023 Snowfork -use crate as ethereum_beacon_client; -use frame_support::parameter_types; -use pallet_timestamp; -use primitives::{Fork, ForkVersions}; -use sp_core::H256; -use sp_runtime::traits::{BlakeTwo256, IdentityLookup}; - -#[cfg(not(feature = "beacon-spec-mainnet"))] -pub mod minimal { - use super::*; - - use crate::config; - use frame_support::derive_impl; - use hex_literal::hex; - use primitives::CompactExecutionHeader; - use snowbridge_core::inbound::{Log, Proof}; - use sp_runtime::BuildStorage; - use std::{fs::File, path::PathBuf}; - - type Block = frame_system::mocking::MockBlock; - - frame_support::construct_runtime!( - pub enum Test { - System: frame_system::{Pallet, Call, Storage, Event}, - Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, - EthereumBeaconClient: ethereum_beacon_client::{Pallet, Call, Storage, Event}, - } - ); - - parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const SS58Prefix: u8 = 42; - } - - #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] - impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type RuntimeTask = RuntimeTask; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type PalletInfo = PalletInfo; - type SS58Prefix = SS58Prefix; - type Nonce = u64; - type Block = Block; - } - - impl pallet_timestamp::Config for Test { - type Moment = u64; - type OnTimestampSet = (); - type MinimumPeriod = (); - type WeightInfo = (); - } - - parameter_types! { - pub const ExecutionHeadersPruneThreshold: u32 = 10; - pub const ChainForkVersions: ForkVersions = ForkVersions{ - genesis: Fork { - version: [0, 0, 0, 1], // 0x00000001 - epoch: 0, - }, - altair: Fork { - version: [1, 0, 0, 1], // 0x01000001 - epoch: 0, - }, - bellatrix: Fork { - version: [2, 0, 0, 1], // 0x02000001 - epoch: 0, - }, - capella: Fork { - version: [3, 0, 0, 1], // 0x03000001 - epoch: 0, - }, - }; - } - - impl ethereum_beacon_client::Config for Test { - type RuntimeEvent = RuntimeEvent; - type ForkVersions = ChainForkVersions; - type MaxExecutionHeadersToKeep = ExecutionHeadersPruneThreshold; - type WeightInfo = (); - } - - // Build genesis storage according to the mock runtime. - pub fn new_tester() -> sp_io::TestExternalities { - let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - let mut ext = sp_io::TestExternalities::new(t); - let _ = ext.execute_with(|| Timestamp::set(RuntimeOrigin::signed(1), 30_000)); - ext - } - - fn load_fixture(basename: &str) -> Result - where - T: for<'de> serde::Deserialize<'de>, - { - let filepath: PathBuf = - [env!("CARGO_MANIFEST_DIR"), "tests", "fixtures", basename].iter().collect(); - serde_json::from_reader(File::open(filepath).unwrap()) - } - - pub fn load_execution_header_update_fixture() -> primitives::ExecutionHeaderUpdate { - load_fixture("execution-header-update.minimal.json").unwrap() - } - - pub fn load_checkpoint_update_fixture( - ) -> primitives::CheckpointUpdate<{ config::SYNC_COMMITTEE_SIZE }> { - load_fixture("initial-checkpoint.minimal.json").unwrap() - } - - pub fn load_sync_committee_update_fixture( - ) -> primitives::Update<{ config::SYNC_COMMITTEE_SIZE }, { config::SYNC_COMMITTEE_BITS_SIZE }> { - load_fixture("sync-committee-update.minimal.json").unwrap() - } - - pub fn load_finalized_header_update_fixture( - ) -> primitives::Update<{ config::SYNC_COMMITTEE_SIZE }, { config::SYNC_COMMITTEE_BITS_SIZE }> { - load_fixture("finalized-header-update.minimal.json").unwrap() - } - - pub fn load_next_sync_committee_update_fixture( - ) -> primitives::Update<{ config::SYNC_COMMITTEE_SIZE }, { config::SYNC_COMMITTEE_BITS_SIZE }> { - load_fixture("next-sync-committee-update.minimal.json").unwrap() - } - - pub fn load_next_finalized_header_update_fixture( - ) -> primitives::Update<{ config::SYNC_COMMITTEE_SIZE }, { config::SYNC_COMMITTEE_BITS_SIZE }> { - load_fixture("next-finalized-header-update.minimal.json").unwrap() - } - - pub fn get_message_verification_payload() -> (Log, Proof) { - ( - Log { - address: hex!("ee9170abfbf9421ad6dd07f6bdec9d89f2b581e0").into(), - topics: vec![ - hex!("1b11dcf133cc240f682dab2d3a8e4cd35c5da8c9cf99adac4336f8512584c5ad").into(), - hex!("00000000000000000000000000000000000000000000000000000000000003e8").into(), - hex!("0000000000000000000000000000000000000000000000000000000000000001").into(), - ], - data: hex!("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004b000f000000000000000100d184c103f7acc340847eee82a0b909e3358bc28d440edffa1352b13227e8ee646f3ea37456dec701345772617070656420457468657210574554481235003511000000000000000000000000000000000000000000").into(), - }, - Proof { - block_hash: hex!("05aaa60b0f27cce9e71909508527264b77ee14da7b5bf915fcc4e32715333213").into(), - tx_index: 0, - data: (vec![ - hex!("cf0d1c1ba57d1e0edfb59786c7e30c2b7e12bd54612b00cd21c4eaeecedf44fb").to_vec(), - hex!("d21fc4f68ab05bc4dcb23c67008e92c4d466437cdd6ed7aad0c008944c185510").to_vec(), - hex!("b9890f91ca0d77aa2a4adfaf9b9e40c94cac9e638b6d9797923865872944b646").to_vec(), - ], vec![ - hex!("f90131a0b601337b3aa10a671caa724eba641e759399979856141d3aea6b6b4ac59b889ba00c7d5dd48be9060221a02fb8fa213860b4c50d47046c8fa65ffaba5737d569e0a094601b62a1086cd9c9cb71a7ebff9e718f3217fd6e837efe4246733c0a196f63a06a4b0dd0aefc37b3c77828c8f07d1b7a2455ceb5dbfd3c77d7d6aeeddc2f7e8ca0d6e8e23142cdd8ec219e1f5d8b56aa18e456702b195deeaa210327284d42ade4a08a313d4c87023005d1ab631bbfe3f5de1e405d0e66d0bef3e033f1e5711b5521a0bf09a5d9a48b10ade82b8d6a5362a15921c8b5228a3487479b467db97411d82fa0f95cccae2a7c572ef3c566503e30bac2b2feb2d2f26eebf6d870dcf7f8cf59cea0d21fc4f68ab05bc4dcb23c67008e92c4d466437cdd6ed7aad0c008944c1855108080808080808080").to_vec(), - hex!("f851a0b9890f91ca0d77aa2a4adfaf9b9e40c94cac9e638b6d9797923865872944b646a060a634b9280e3a23fb63375e7bbdd9ab07fd379ab6a67e2312bbc112195fa358808080808080808080808080808080").to_vec(), - hex!("f9030820b9030402f90300018301d6e2b9010000000000000800000000000020040008000000000000000000000000400000008000000000000000000000000000000000000000000000000000000000042010000000001000000000000000000000000000000000040000000000000000000000000000000000000000000000008000000000000000002000000000000000000000000200000000000000200000000000100000000040000001000200008000000000000200000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000f901f5f87a942ffa5ecdbe006d30397c7636d3e015eee251369ff842a0c965575a00553e094ca7c5d14f02e107c258dda06867cbf9e0e69f80e71bbcc1a000000000000000000000000000000000000000000000000000000000000003e8a000000000000000000000000000000000000000000000000000000000000003e8f9011c94ee9170abfbf9421ad6dd07f6bdec9d89f2b581e0f863a01b11dcf133cc240f682dab2d3a8e4cd35c5da8c9cf99adac4336f8512584c5ada000000000000000000000000000000000000000000000000000000000000003e8a00000000000000000000000000000000000000000000000000000000000000001b8a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004b000f000000000000000100d184c103f7acc340847eee82a0b909e3358bc28d440edffa1352b13227e8ee646f3ea37456dec701345772617070656420457468657210574554481235003511000000000000000000000000000000000000000000f858948cf6147918a5cbb672703f879f385036f8793a24e1a01449abf21e49fd025f33495e77f7b1461caefdd3d4bb646424a3f445c4576a5ba0000000000000000000000000440edffa1352b13227e8ee646f3ea37456dec701").to_vec(), - ]), - } - ) - } - - pub fn get_message_verification_header() -> CompactExecutionHeader { - CompactExecutionHeader { - parent_hash: hex!("04a7f6ab8282203562c62f38b0ab41d32aaebe2c7ea687702b463148a6429e04") - .into(), - block_number: 55, - state_root: hex!("894d968712976d613519f973a317cb0781c7b039c89f27ea2b7ca193f7befdb3") - .into(), - receipts_root: hex!("cf0d1c1ba57d1e0edfb59786c7e30c2b7e12bd54612b00cd21c4eaeecedf44fb") - .into(), - } - } -} - -#[cfg(feature = "beacon-spec-mainnet")] -pub mod mainnet { - use super::*; - use frame_support::derive_impl; - - type Block = frame_system::mocking::MockBlock; - use sp_runtime::BuildStorage; - - frame_support::construct_runtime!( - pub enum Test { - System: frame_system::{Pallet, Call, Storage, Event}, - Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, - EthereumBeaconClient: ethereum_beacon_client::{Pallet, Call, Storage, Event}, - } - ); - - parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const SS58Prefix: u8 = 42; - } - - #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] - impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type RuntimeTask = RuntimeTask; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type PalletInfo = PalletInfo; - type SS58Prefix = SS58Prefix; - type Nonce = u64; - type Block = Block; - } - - impl pallet_timestamp::Config for Test { - type Moment = u64; - type OnTimestampSet = (); - type MinimumPeriod = (); - type WeightInfo = (); - } - - parameter_types! { - pub const ChainForkVersions: ForkVersions = ForkVersions{ - genesis: Fork { - version: [0, 0, 16, 32], // 0x00001020 - epoch: 0, - }, - altair: Fork { - version: [1, 0, 16, 32], // 0x01001020 - epoch: 36660, - }, - bellatrix: Fork { - version: [2, 0, 16, 32], // 0x02001020 - epoch: 112260, - }, - capella: Fork { - version: [3, 0, 16, 32], // 0x03001020 - epoch: 162304, - }, - }; - pub const ExecutionHeadersPruneThreshold: u32 = 10; - } - - impl ethereum_beacon_client::Config for Test { - type RuntimeEvent = RuntimeEvent; - type ForkVersions = ChainForkVersions; - type MaxExecutionHeadersToKeep = ExecutionHeadersPruneThreshold; - type WeightInfo = (); - } - - // Build genesis storage according to the mock runtime. - pub fn new_tester() -> sp_io::TestExternalities { - let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - let mut ext = sp_io::TestExternalities::new(t); - let _ = ext.execute_with(|| Timestamp::set(RuntimeOrigin::signed(1), 30_000)); - ext - } -} -- GitLab From 22d5b80d4486f2e9d53bf8ad1eb3efa11a4136af Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Fri, 22 Mar 2024 13:52:51 +0200 Subject: [PATCH 082/187] Add a linear fee multiplier (#127) (#3790) Bridging fees are calculated using a static ETH/DOT exchange rate that can deviate significantly from the real-world exchange rate. We therefore need to add a safety margin to the fee so that users almost aways cover the cost of relaying. # FAQ > Why introduce a `multiplier` parameter instead of configuring an exchange rate which already has a safety factor applied? When converting from ETH to DOT, we need to _divide_ the multiplier by the exchange rate, and to convert from DOT to ETH we need to _multiply_ the multiplier by the exchange rate. > Other input parameters to the fee calculation can also deviate from real-world values. These include substrate weights, gas prices, and so on. Why does the multiplier introduced here not adjust those? A single scalar multiplier won't be able to accommodate the different volatilities efficiently. For example, gas prices are much more volatile than exchange rates, and substrate weights hardly ever change. So the pricing config relating to weights and gas prices should already have some appropriate safety margin pre-applied. # Detailed Changes: * Added `multiplier` field to `PricingParameters` * Outbound-queue fee is multiplied by `multiplier` * This `multiplier` is synced to the Ethereum side * Improved Runtime API for calculating outbound-queue fees. This API makes it much easier to for configure parts of the system in preparation for launch. * Improve and clarify code documentation Upstreamed from https://github.com/Snowfork/polkadot-sdk/pull/127 --------- Co-authored-by: Clara van Staden Co-authored-by: Adrian Catangiu --- .../pallets/inbound-queue/src/mock.rs | 3 +- .../outbound-queue/runtime-api/src/lib.rs | 11 +++-- .../pallets/outbound-queue/src/api.rs | 18 +++++--- .../pallets/outbound-queue/src/lib.rs | 32 +++++++++---- .../pallets/outbound-queue/src/mock.rs | 3 +- .../pallets/outbound-queue/src/test.rs | 46 +++++++++++-------- bridges/snowbridge/pallets/system/src/lib.rs | 2 + bridges/snowbridge/pallets/system/src/mock.rs | 3 +- .../primitives/core/src/outbound.rs | 13 ++++-- .../snowbridge/primitives/core/src/pricing.rs | 5 ++ .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 11 +++-- 11 files changed, 97 insertions(+), 50 deletions(-) diff --git a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs index 086b27cb828..39e9532ed32 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs @@ -173,7 +173,8 @@ parameter_types! { pub Parameters: PricingParameters = PricingParameters { exchange_rate: FixedU128::from_rational(1, 400), fee_per_gas: gwei(20), - rewards: Rewards { local: DOT, remote: meth(1) } + rewards: Rewards { local: DOT, remote: meth(1) }, + multiplier: FixedU128::from_rational(1, 1), }; } diff --git a/bridges/snowbridge/pallets/outbound-queue/runtime-api/src/lib.rs b/bridges/snowbridge/pallets/outbound-queue/runtime-api/src/lib.rs index 51f46a7b49c..e6ddaa43935 100644 --- a/bridges/snowbridge/pallets/outbound-queue/runtime-api/src/lib.rs +++ b/bridges/snowbridge/pallets/outbound-queue/runtime-api/src/lib.rs @@ -3,7 +3,10 @@ #![cfg_attr(not(feature = "std"), no_std)] use frame_support::traits::tokens::Balance as BalanceT; -use snowbridge_core::outbound::Message; +use snowbridge_core::{ + outbound::{Command, Fee}, + PricingParameters, +}; use snowbridge_outbound_queue_merkle_tree::MerkleProof; sp_api::decl_runtime_apis! { @@ -11,10 +14,10 @@ sp_api::decl_runtime_apis! { { /// Generate a merkle proof for a committed message identified by `leaf_index`. /// The merkle root is stored in the block header as a - /// `\[`sp_runtime::generic::DigestItem::Other`\]` + /// `sp_runtime::generic::DigestItem::Other` fn prove_message(leaf_index: u64) -> Option; - /// Calculate the delivery fee for `message` - fn calculate_fee(message: Message) -> Option; + /// Calculate the delivery fee for `command` + fn calculate_fee(command: Command, parameters: Option>) -> Fee; } } diff --git a/bridges/snowbridge/pallets/outbound-queue/src/api.rs b/bridges/snowbridge/pallets/outbound-queue/src/api.rs index 44d63f1e2d2..b904819b1b1 100644 --- a/bridges/snowbridge/pallets/outbound-queue/src/api.rs +++ b/bridges/snowbridge/pallets/outbound-queue/src/api.rs @@ -4,8 +4,12 @@ use crate::{Config, MessageLeaves}; use frame_support::storage::StorageStreamIter; -use snowbridge_core::outbound::{Message, SendMessage}; +use snowbridge_core::{ + outbound::{Command, Fee, GasMeter}, + PricingParameters, +}; use snowbridge_outbound_queue_merkle_tree::{merkle_proof, MerkleProof}; +use sp_core::Get; pub fn prove_message(leaf_index: u64) -> Option where @@ -19,12 +23,14 @@ where Some(proof) } -pub fn calculate_fee(message: Message) -> Option +pub fn calculate_fee( + command: Command, + parameters: Option>, +) -> Fee where T: Config, { - match crate::Pallet::::validate(&message) { - Ok((_, fees)) => Some(fees.total()), - _ => None, - } + let gas_used_at_most = T::GasMeter::maximum_gas_used_at_most(&command); + let parameters = parameters.unwrap_or(T::PricingParameters::get()); + crate::Pallet::::calculate_fee(gas_used_at_most, parameters) } diff --git a/bridges/snowbridge/pallets/outbound-queue/src/lib.rs b/bridges/snowbridge/pallets/outbound-queue/src/lib.rs index 9e949a4791a..9b9dbe854a5 100644 --- a/bridges/snowbridge/pallets/outbound-queue/src/lib.rs +++ b/bridges/snowbridge/pallets/outbound-queue/src/lib.rs @@ -47,24 +47,37 @@ //! consume on Ethereum. Using this upper bound, a final fee can be calculated. //! //! The fee calculation also requires the following parameters: -//! * ETH/DOT exchange rate -//! * Ether fee per unit of gas +//! * Average ETH/DOT exchange rate over some period +//! * Max fee per unit of gas that bridge is willing to refund relayers for //! //! By design, it is expected that governance should manually update these //! parameters every few weeks using the `set_pricing_parameters` extrinsic in the //! system pallet. //! +//! This is an interim measure. Once ETH/DOT liquidity pools are available in the Polkadot network, +//! we'll use them as a source of pricing info, subject to certain safeguards. +//! //! ## Fee Computation Function //! //! ```text //! LocalFee(Message) = WeightToFee(ProcessMessageWeight(Message)) -//! RemoteFee(Message) = MaxGasRequired(Message) * FeePerGas + Reward -//! Fee(Message) = LocalFee(Message) + (RemoteFee(Message) / Ratio("ETH/DOT")) +//! RemoteFee(Message) = MaxGasRequired(Message) * Params.MaxFeePerGas + Params.Reward +//! RemoteFeeAdjusted(Message) = Params.Multiplier * (RemoteFee(Message) / Params.Ratio("ETH/DOT")) +//! Fee(Message) = LocalFee(Message) + RemoteFeeAdjusted(Message) //! ``` //! -//! By design, the computed fee is always going to conservative, to cover worst-case -//! costs of dispatch on Ethereum. In future iterations of the design, we will optimize -//! this, or provide a mechanism to asynchronously refund a portion of collected fees. +//! By design, the computed fee includes a safety factor (the `Multiplier`) to cover +//! unfavourable fluctuations in the ETH/DOT exchange rate. +//! +//! ## Fee Settlement +//! +//! On the remote side, in the gateway contract, the relayer accrues +//! +//! ```text +//! Min(GasPrice, Message.MaxFeePerGas) * GasUsed() + Message.Reward +//! ``` +//! Or in plain english, relayers are refunded for gas consumption, using a +//! price that is a minimum of the actual gas price, or `Message.MaxFeePerGas`. //! //! # Extrinsics //! @@ -106,7 +119,7 @@ pub use snowbridge_outbound_queue_merkle_tree::MerkleProof; use sp_core::{H256, U256}; use sp_runtime::{ traits::{CheckedDiv, Hash}, - DigestItem, + DigestItem, Saturating, }; use sp_std::prelude::*; pub use types::{CommittedMessage, ProcessMessageOriginOf}; @@ -366,8 +379,9 @@ pub mod pallet { // downcast to u128 let fee: u128 = fee.try_into().defensive_unwrap_or(u128::MAX); - // convert to local currency + // multiply by multiplier and convert to local currency let fee = FixedU128::from_inner(fee) + .saturating_mul(params.multiplier) .checked_div(¶ms.exchange_rate) .expect("exchange rate is not zero; qed") .into_inner(); diff --git a/bridges/snowbridge/pallets/outbound-queue/src/mock.rs b/bridges/snowbridge/pallets/outbound-queue/src/mock.rs index 850b13dcf31..67877a05c79 100644 --- a/bridges/snowbridge/pallets/outbound-queue/src/mock.rs +++ b/bridges/snowbridge/pallets/outbound-queue/src/mock.rs @@ -77,7 +77,8 @@ parameter_types! { pub Parameters: PricingParameters = PricingParameters { exchange_rate: FixedU128::from_rational(1, 400), fee_per_gas: gwei(20), - rewards: Rewards { local: DOT, remote: meth(1) } + rewards: Rewards { local: DOT, remote: meth(1) }, + multiplier: FixedU128::from_rational(4, 3), }; } diff --git a/bridges/snowbridge/pallets/outbound-queue/src/test.rs b/bridges/snowbridge/pallets/outbound-queue/src/test.rs index 8ed4a318d68..4e9ea36e24b 100644 --- a/bridges/snowbridge/pallets/outbound-queue/src/test.rs +++ b/bridges/snowbridge/pallets/outbound-queue/src/test.rs @@ -268,28 +268,34 @@ fn encode_digest_item() { } #[test] -fn validate_messages_with_fees() { +fn test_calculate_fees_with_unit_multiplier() { new_tester().execute_with(|| { - let message = mock_message(1000); - let (_, fee) = OutboundQueue::validate(&message).unwrap(); + let gas_used: u64 = 250000; + let price_params: PricingParameters<::Balance> = PricingParameters { + exchange_rate: FixedU128::from_rational(1, 400), + fee_per_gas: 10000_u32.into(), + rewards: Rewards { local: 1_u32.into(), remote: 1_u32.into() }, + multiplier: FixedU128::from_rational(1, 1), + }; + let fee = OutboundQueue::calculate_fee(gas_used, price_params); assert_eq!(fee.local, 698000000); - assert_eq!(fee.remote, 2680000000000); + assert_eq!(fee.remote, 1000000); }); } #[test] -fn test_calculate_fees() { +fn test_calculate_fees_with_multiplier() { new_tester().execute_with(|| { let gas_used: u64 = 250000; - let illegal_price_params: PricingParameters<::Balance> = - PricingParameters { - exchange_rate: FixedU128::from_rational(1, 400), - fee_per_gas: 10000_u32.into(), - rewards: Rewards { local: 1_u32.into(), remote: 1_u32.into() }, - }; - let fee = OutboundQueue::calculate_fee(gas_used, illegal_price_params); + let price_params: PricingParameters<::Balance> = PricingParameters { + exchange_rate: FixedU128::from_rational(1, 400), + fee_per_gas: 10000_u32.into(), + rewards: Rewards { local: 1_u32.into(), remote: 1_u32.into() }, + multiplier: FixedU128::from_rational(4, 3), + }; + let fee = OutboundQueue::calculate_fee(gas_used, price_params); assert_eq!(fee.local, 698000000); - assert_eq!(fee.remote, 1000000); + assert_eq!(fee.remote, 1333333); }); } @@ -297,13 +303,13 @@ fn test_calculate_fees() { fn test_calculate_fees_with_valid_exchange_rate_but_remote_fee_calculated_as_zero() { new_tester().execute_with(|| { let gas_used: u64 = 250000; - let illegal_price_params: PricingParameters<::Balance> = - PricingParameters { - exchange_rate: FixedU128::from_rational(1, 1), - fee_per_gas: 1_u32.into(), - rewards: Rewards { local: 1_u32.into(), remote: 1_u32.into() }, - }; - let fee = OutboundQueue::calculate_fee(gas_used, illegal_price_params.clone()); + let price_params: PricingParameters<::Balance> = PricingParameters { + exchange_rate: FixedU128::from_rational(1, 1), + fee_per_gas: 1_u32.into(), + rewards: Rewards { local: 1_u32.into(), remote: 1_u32.into() }, + multiplier: FixedU128::from_rational(1, 1), + }; + let fee = OutboundQueue::calculate_fee(gas_used, price_params.clone()); assert_eq!(fee.local, 698000000); // Though none zero pricing params the remote fee calculated here is invalid // which should be avoided diff --git a/bridges/snowbridge/pallets/system/src/lib.rs b/bridges/snowbridge/pallets/system/src/lib.rs index 6e5ceb5e9b1..39c73e3630e 100644 --- a/bridges/snowbridge/pallets/system/src/lib.rs +++ b/bridges/snowbridge/pallets/system/src/lib.rs @@ -159,6 +159,7 @@ pub mod pallet { type DefaultPricingParameters: Get>; /// Cost of delivering a message from Ethereum + #[pallet::constant] type InboundDeliveryCost: Get>; type WeightInfo: WeightInfo; @@ -334,6 +335,7 @@ pub mod pallet { let command = Command::SetPricingParameters { exchange_rate: params.exchange_rate.into(), delivery_cost: T::InboundDeliveryCost::get().saturated_into::(), + multiplier: params.multiplier.into(), }; Self::send(PRIMARY_GOVERNANCE_CHANNEL, command, PaysFee::::No)?; diff --git a/bridges/snowbridge/pallets/system/src/mock.rs b/bridges/snowbridge/pallets/system/src/mock.rs index a711eab5d3d..0312456c982 100644 --- a/bridges/snowbridge/pallets/system/src/mock.rs +++ b/bridges/snowbridge/pallets/system/src/mock.rs @@ -193,7 +193,8 @@ parameter_types! { pub Parameters: PricingParameters = PricingParameters { exchange_rate: FixedU128::from_rational(1, 400), fee_per_gas: gwei(20), - rewards: Rewards { local: DOT, remote: meth(1) } + rewards: Rewards { local: DOT, remote: meth(1) }, + multiplier: FixedU128::from_rational(4, 3) }; pub const InboundDeliveryCost: u128 = 1_000_000_000; diff --git a/bridges/snowbridge/primitives/core/src/outbound.rs b/bridges/snowbridge/primitives/core/src/outbound.rs index bce123878d3..0ba0fdb6108 100644 --- a/bridges/snowbridge/primitives/core/src/outbound.rs +++ b/bridges/snowbridge/primitives/core/src/outbound.rs @@ -136,6 +136,8 @@ mod v1 { exchange_rate: UD60x18, // Cost of delivering a message from Ethereum to BridgeHub, in ROC/KSM/DOT delivery_cost: u128, + // Fee multiplier + multiplier: UD60x18, }, } @@ -203,10 +205,11 @@ mod v1 { Token::Uint(U256::from(*transfer_asset_xcm)), Token::Uint(*register_token), ])]), - Command::SetPricingParameters { exchange_rate, delivery_cost } => + Command::SetPricingParameters { exchange_rate, delivery_cost, multiplier } => ethabi::encode(&[Token::Tuple(vec![ Token::Uint(exchange_rate.clone().into_inner()), Token::Uint(U256::from(*delivery_cost)), + Token::Uint(multiplier.clone().into_inner()), ])]), } } @@ -273,7 +276,8 @@ mod v1 { } } -#[cfg_attr(feature = "std", derive(PartialEq, Debug))] +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[cfg_attr(feature = "std", derive(PartialEq))] /// Fee for delivering message pub struct Fee where @@ -346,12 +350,13 @@ pub trait GasMeter { /// the command within the message const MAXIMUM_BASE_GAS: u64; + /// Total gas consumed at most, including verification & dispatch fn maximum_gas_used_at_most(command: &Command) -> u64 { Self::MAXIMUM_BASE_GAS + Self::maximum_dispatch_gas_used_at_most(command) } - /// Measures the maximum amount of gas a command payload will require to dispatch, AFTER - /// validation & verification. + /// Measures the maximum amount of gas a command payload will require to *dispatch*, NOT + /// including validation & verification. fn maximum_dispatch_gas_used_at_most(command: &Command) -> u64; } diff --git a/bridges/snowbridge/primitives/core/src/pricing.rs b/bridges/snowbridge/primitives/core/src/pricing.rs index 33aeda6d15c..0f392c7ad4b 100644 --- a/bridges/snowbridge/primitives/core/src/pricing.rs +++ b/bridges/snowbridge/primitives/core/src/pricing.rs @@ -13,6 +13,8 @@ pub struct PricingParameters { pub rewards: Rewards, /// Ether (wei) fee per gas unit pub fee_per_gas: U256, + /// Fee multiplier + pub multiplier: FixedU128, } #[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] @@ -43,6 +45,9 @@ where if self.rewards.remote.is_zero() { return Err(InvalidPricingParameters) } + if self.multiplier == FixedU128::zero() { + return Err(InvalidPricingParameters) + } Ok(()) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index bf7483179f2..3980fa0d501 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -38,7 +38,9 @@ pub mod xcm_config; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use snowbridge_beacon_primitives::{Fork, ForkVersions}; use snowbridge_core::{ - gwei, meth, outbound::Message, AgentId, AllowSiblingsOnly, PricingParameters, Rewards, + gwei, meth, + outbound::{Command, Fee}, + AgentId, AllowSiblingsOnly, PricingParameters, Rewards, }; use snowbridge_router_primitives::inbound::MessageToXcm; use sp_api::impl_runtime_apis; @@ -503,7 +505,8 @@ parameter_types! { pub Parameters: PricingParameters = PricingParameters { exchange_rate: FixedU128::from_rational(1, 400), fee_per_gas: gwei(20), - rewards: Rewards { local: 1 * UNITS, remote: meth(1) } + rewards: Rewards { local: 1 * UNITS, remote: meth(1) }, + multiplier: FixedU128::from_rational(1, 1), }; } @@ -1022,8 +1025,8 @@ impl_runtime_apis! { snowbridge_pallet_outbound_queue::api::prove_message::(leaf_index) } - fn calculate_fee(message: Message) -> Option { - snowbridge_pallet_outbound_queue::api::calculate_fee::(message) + fn calculate_fee(command: Command, parameters: Option>) -> Fee { + snowbridge_pallet_outbound_queue::api::calculate_fee::(command, parameters) } } -- GitLab From 9d2963c29d9b7ea949851a166e0cb2792fc66fff Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Fri, 22 Mar 2024 14:18:03 +0200 Subject: [PATCH 083/187] Make public addresses go first in authority discovery DHT records (#3757) Make sure explicitly set by the operator public addresses go first in the authority discovery DHT records. Also update `Discovery` behavior to eliminate duplicates in the returned addresses. This PR should improve situation with https://github.com/paritytech/polkadot-sdk/issues/3519. Obsoletes https://github.com/paritytech/polkadot-sdk/pull/3657. --- Cargo.lock | 1 + .../relay-chain-minimal-node/src/lib.rs | 2 + polkadot/node/service/src/lib.rs | 2 + substrate/bin/node/cli/src/service.rs | 2 + .../client/authority-discovery/Cargo.toml | 1 + .../client/authority-discovery/src/lib.rs | 5 + .../client/authority-discovery/src/worker.rs | 92 ++++++++++++++----- substrate/client/network/Cargo.toml | 2 +- substrate/client/network/src/discovery.rs | 19 +++- 9 files changed, 99 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bdbf6ddac26..074b657e767 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15555,6 +15555,7 @@ dependencies = [ "futures-timer", "ip_network", "libp2p", + "linked_hash_set", "log", "multihash 0.18.1", "multihash-codetable", diff --git a/cumulus/client/relay-chain-minimal-node/src/lib.rs b/cumulus/client/relay-chain-minimal-node/src/lib.rs index 4bccca59fe3..6aea043713d 100644 --- a/cumulus/client/relay-chain-minimal-node/src/lib.rs +++ b/cumulus/client/relay-chain-minimal-node/src/lib.rs @@ -55,6 +55,7 @@ fn build_authority_discovery_service( prometheus_registry: Option, ) -> AuthorityDiscoveryService { let auth_disc_publish_non_global_ips = config.network.allow_non_globals_in_dht; + let auth_disc_public_addresses = config.network.public_addresses.clone(); let authority_discovery_role = sc_authority_discovery::Role::Discover; let dht_event_stream = network.event_stream("authority-discovery").filter_map(|e| async move { match e { @@ -65,6 +66,7 @@ fn build_authority_discovery_service( let (worker, service) = sc_authority_discovery::new_worker_and_service_with_config( sc_authority_discovery::WorkerConfig { publish_non_global_ips: auth_disc_publish_non_global_ips, + public_addresses: auth_disc_public_addresses, // Require that authority discovery records are signed. strict_record_validation: true, ..Default::default() diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index 83a0afc077e..4f4ede53705 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -807,6 +807,7 @@ pub fn new_full( let shared_voter_state = rpc_setup; let auth_disc_publish_non_global_ips = config.network.allow_non_globals_in_dht; + let auth_disc_public_addresses = config.network.public_addresses.clone(); let mut net_config = sc_network::config::FullNetworkConfiguration::new(&config.network); let genesis_hash = client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"); @@ -1061,6 +1062,7 @@ pub fn new_full( let (worker, service) = sc_authority_discovery::new_worker_and_service_with_config( sc_authority_discovery::WorkerConfig { publish_non_global_ips: auth_disc_publish_non_global_ips, + public_addresses: auth_disc_public_addresses, // Require that authority discovery records are signed. strict_record_validation: true, ..Default::default() diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index 8f2aba6b44c..e4b425e6f96 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -422,6 +422,7 @@ pub fn new_full_base( let shared_voter_state = rpc_setup; let auth_disc_publish_non_global_ips = config.network.allow_non_globals_in_dht; + let auth_disc_public_addresses = config.network.public_addresses.clone(); let mut net_config = sc_network::config::FullNetworkConfiguration::new(&config.network); let genesis_hash = client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"); @@ -610,6 +611,7 @@ pub fn new_full_base( sc_authority_discovery::new_worker_and_service_with_config( sc_authority_discovery::WorkerConfig { publish_non_global_ips: auth_disc_publish_non_global_ips, + public_addresses: auth_disc_public_addresses, ..Default::default() }, client.clone(), diff --git a/substrate/client/authority-discovery/Cargo.toml b/substrate/client/authority-discovery/Cargo.toml index cdd4052f0b0..26580064b3c 100644 --- a/substrate/client/authority-discovery/Cargo.toml +++ b/substrate/client/authority-discovery/Cargo.toml @@ -29,6 +29,7 @@ multihash = { version = "0.18.1", default-features = false, features = [ "sha2", "std", ] } +linked_hash_set = "0.1.4" log = { workspace = true, default-features = true } prost = "0.12" rand = "0.8.5" diff --git a/substrate/client/authority-discovery/src/lib.rs b/substrate/client/authority-discovery/src/lib.rs index 6bb12804cad..281188de143 100644 --- a/substrate/client/authority-discovery/src/lib.rs +++ b/substrate/client/authority-discovery/src/lib.rs @@ -80,6 +80,10 @@ pub struct WorkerConfig { /// Defaults to `true` to avoid the surprise factor. pub publish_non_global_ips: bool, + /// Public addresses set by the node operator to always publish first in the authority + /// discovery DHT record. + pub public_addresses: Vec, + /// Reject authority discovery records that are not signed by their network identity (PeerId) /// /// Defaults to `false` to provide compatibility with old versions @@ -104,6 +108,7 @@ impl Default for WorkerConfig { // `authority_discovery_dht_event_received`. max_query_interval: Duration::from_secs(10 * 60), publish_non_global_ips: true, + public_addresses: Vec::new(), strict_record_validation: false, } } diff --git a/substrate/client/authority-discovery/src/worker.rs b/substrate/client/authority-discovery/src/worker.rs index 9bccb96ff37..b77f0241ec2 100644 --- a/substrate/client/authority-discovery/src/worker.rs +++ b/substrate/client/authority-discovery/src/worker.rs @@ -35,6 +35,7 @@ use addr_cache::AddrCache; use codec::{Decode, Encode}; use ip_network::IpNetwork; use libp2p::{core::multiaddr, identity::PublicKey, multihash::Multihash, Multiaddr, PeerId}; +use linked_hash_set::LinkedHashSet; use multihash_codetable::{Code, MultihashDigest}; use log::{debug, error, log_enabled}; @@ -120,14 +121,22 @@ pub struct Worker { /// Interval to be proactive, publishing own addresses. publish_interval: ExpIncInterval, + /// Pro-actively publish our own addresses at this interval, if the keys in the keystore /// have changed. publish_if_changed_interval: ExpIncInterval, + /// List of keys onto which addresses have been published at the latest publication. /// Used to check whether they have changed. latest_published_keys: HashSet, + /// Same value as in the configuration. publish_non_global_ips: bool, + + /// Public addresses set by the node operator to always publish first in the authority + /// discovery DHT record. + public_addresses: LinkedHashSet, + /// Same value as in the configuration. strict_record_validation: bool, @@ -136,6 +145,7 @@ pub struct Worker { /// Queue of throttled lookups pending to be passed to the network. pending_lookups: Vec, + /// Set of in-flight lookups. in_flight_lookups: HashMap, @@ -224,6 +234,29 @@ where None => None, }; + let public_addresses = { + let local_peer_id: Multihash = network.local_peer_id().into(); + + config + .public_addresses + .into_iter() + .map(|mut address| { + if let Some(multiaddr::Protocol::P2p(peer_id)) = address.iter().last() { + if peer_id != local_peer_id { + error!( + target: LOG_TARGET, + "Discarding invalid local peer ID in public address {address}.", + ); + } + // Always discard `/p2p/...` protocol for proper address comparison (local + // peer id will be added before publishing). + address.pop(); + } + address + }) + .collect() + }; + Worker { from_service: from_service.fuse(), client, @@ -233,6 +266,7 @@ where publish_if_changed_interval, latest_published_keys: HashSet::new(), publish_non_global_ips: config.publish_non_global_ips, + public_addresses, strict_record_validation: config.strict_record_validation, query_interval, pending_lookups: Vec::new(), @@ -304,32 +338,48 @@ where } fn addresses_to_publish(&self) -> impl Iterator { - let peer_id: Multihash = self.network.local_peer_id().into(); let publish_non_global_ips = self.publish_non_global_ips; - let addresses = self.network.external_addresses().into_iter().filter(move |a| { - if publish_non_global_ips { - return true - } + let addresses = self + .public_addresses + .clone() + .into_iter() + .chain(self.network.external_addresses().into_iter().filter_map(|mut address| { + // Make sure the reported external address does not contain `/p2p/...` protocol. + if let Some(multiaddr::Protocol::P2p(_)) = address.iter().last() { + address.pop(); + } - a.iter().all(|p| match p { - // The `ip_network` library is used because its `is_global()` method is stable, - // while `is_global()` in the standard library currently isn't. - multiaddr::Protocol::Ip4(ip) if !IpNetwork::from(ip).is_global() => false, - multiaddr::Protocol::Ip6(ip) if !IpNetwork::from(ip).is_global() => false, - _ => true, + if self.public_addresses.contains(&address) { + // Already added above. + None + } else { + Some(address) + } + })) + .filter(move |address| { + if publish_non_global_ips { + return true + } + + address.iter().all(|protocol| match protocol { + // The `ip_network` library is used because its `is_global()` method is stable, + // while `is_global()` in the standard library currently isn't. + multiaddr::Protocol::Ip4(ip) if !IpNetwork::from(ip).is_global() => false, + multiaddr::Protocol::Ip6(ip) if !IpNetwork::from(ip).is_global() => false, + _ => true, + }) }) - }); + .collect::>(); - debug!(target: LOG_TARGET, "Authority DHT record peer_id='{:?}' addresses='{:?}'", peer_id, addresses.clone().collect::>()); + let peer_id = self.network.local_peer_id(); + debug!( + target: LOG_TARGET, + "Authority DHT record peer_id='{peer_id}' addresses='{addresses:?}'", + ); - // The address must include the peer id if not already set. - addresses.map(move |a| { - if a.iter().any(|p| matches!(p, multiaddr::Protocol::P2p(_))) { - a - } else { - a.with(multiaddr::Protocol::P2p(peer_id)) - } - }) + // The address must include the peer id. + let peer_id: Multihash = peer_id.into(); + addresses.into_iter().map(move |a| a.with(multiaddr::Protocol::P2p(peer_id))) } /// Publish own public addresses. diff --git a/substrate/client/network/Cargo.toml b/substrate/client/network/Cargo.toml index cbf74440dc1..c6f17647166 100644 --- a/substrate/client/network/Cargo.toml +++ b/substrate/client/network/Cargo.toml @@ -29,7 +29,7 @@ futures = "0.3.21" futures-timer = "3.0.2" ip_network = "0.4.1" libp2p = { version = "0.51.4", features = ["dns", "identify", "kad", "macros", "mdns", "noise", "ping", "request-response", "tcp", "tokio", "websocket", "yamux"] } -linked_hash_set = "0.1.3" +linked_hash_set = "0.1.4" log = { workspace = true, default-features = true } mockall = "0.11.3" parking_lot = "0.12.1" diff --git a/substrate/client/network/src/discovery.rs b/substrate/client/network/src/discovery.rs index 77c26266aac..4e2121c5540 100644 --- a/substrate/client/network/src/discovery.rs +++ b/substrate/client/network/src/discovery.rs @@ -72,6 +72,7 @@ use libp2p::{ }, PeerId, }; +use linked_hash_set::LinkedHashSet; use log::{debug, info, trace, warn}; use sp_core::hexdisplay::HexDisplay; use std::{ @@ -550,14 +551,20 @@ impl NetworkBehaviour for DiscoveryBehaviour { ) -> Result, ConnectionDenied> { let Some(peer_id) = maybe_peer else { return Ok(Vec::new()) }; - let mut list = self + // Collect addresses into [`LinkedHashSet`] to eliminate duplicate entries preserving the + // order of addresses. Give priority to `permanent_addresses` (used with reserved nodes) and + // `ephemeral_addresses` (used for addresses discovered from other sources, like authority + // discovery DHT records). + let mut list: LinkedHashSet<_> = self .permanent_addresses .iter() .filter_map(|(p, a)| (*p == peer_id).then_some(a.clone())) - .collect::>(); + .collect(); if let Some(ephemeral_addresses) = self.ephemeral_addresses.get(&peer_id) { - list.extend(ephemeral_addresses.clone()); + ephemeral_addresses.iter().for_each(|address| { + list.insert_if_absent(address.clone()); + }); } { @@ -583,12 +590,14 @@ impl NetworkBehaviour for DiscoveryBehaviour { }); } - list.extend(list_to_filter); + list_to_filter.into_iter().for_each(|address| { + list.insert_if_absent(address); + }); } trace!(target: "sub-libp2p", "Addresses of {:?}: {:?}", peer_id, list); - Ok(list) + Ok(list.into_iter().collect()) } fn on_swarm_event(&mut self, event: FromSwarm) { -- GitLab From 2f59e9efa8142d02ee4893a1383debd3b6209019 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Fri, 22 Mar 2024 19:45:26 +0100 Subject: [PATCH 084/187] XCM remove extra QueryId types from traits (#3763) We do not need to make these traits generic over QueryId type, we can just use the QueryId alias everywhere --- polkadot/xcm/pallet-xcm/src/lib.rs | 11 +++---- polkadot/xcm/xcm-builder/src/controller.rs | 4 +-- polkadot/xcm/xcm-builder/src/pay.rs | 2 +- polkadot/xcm/xcm-builder/src/tests/mock.rs | 11 +++---- .../xcm-executor/src/traits/on_response.rs | 31 ++++++------------- 5 files changed, 22 insertions(+), 37 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 1a1f8b402a3..0761b375dfb 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -374,7 +374,7 @@ pub mod pallet { origin: OriginFor, timeout: BlockNumberFor, match_querier: VersionedLocation, - ) -> Result { + ) -> Result { let responder = ::ExecuteXcmOrigin::ensure_origin(origin)?; let query_id = ::new_query( responder, @@ -1478,7 +1478,6 @@ impl sp_std::fmt::Debug for FeesHandling { } impl QueryHandler for Pallet { - type QueryId = u64; type BlockNumber = BlockNumberFor; type Error = XcmError; type UniversalLocation = T::UniversalLocation; @@ -1488,7 +1487,7 @@ impl QueryHandler for Pallet { responder: impl Into, timeout: BlockNumberFor, match_querier: impl Into, - ) -> Self::QueryId { + ) -> QueryId { Self::do_new_query(responder, None, timeout, match_querier) } @@ -1498,7 +1497,7 @@ impl QueryHandler for Pallet { message: &mut Xcm<()>, responder: impl Into, timeout: Self::BlockNumber, - ) -> Result { + ) -> Result { let responder = responder.into(); let destination = Self::UniversalLocation::get() .invert_target(&responder) @@ -1511,7 +1510,7 @@ impl QueryHandler for Pallet { } /// Removes response when ready and emits [Event::ResponseTaken] event. - fn take_response(query_id: Self::QueryId) -> QueryResponseStatus { + fn take_response(query_id: QueryId) -> QueryResponseStatus { match Queries::::get(query_id) { Some(QueryStatus::Ready { response, at }) => match response.try_into() { Ok(response) => { @@ -1528,7 +1527,7 @@ impl QueryHandler for Pallet { } #[cfg(feature = "runtime-benchmarks")] - fn expect_response(id: Self::QueryId, response: Response) { + fn expect_response(id: QueryId, response: Response) { let response = response.into(); Queries::::insert( id, diff --git a/polkadot/xcm/xcm-builder/src/controller.rs b/polkadot/xcm/xcm-builder/src/controller.rs index ba2b1fb44b8..04b19eaa587 100644 --- a/polkadot/xcm/xcm-builder/src/controller.rs +++ b/polkadot/xcm/xcm-builder/src/controller.rs @@ -132,7 +132,7 @@ pub trait QueryController: QueryHandler { origin: Origin, timeout: Timeout, match_querier: VersionedLocation, - ) -> Result; + ) -> Result; } impl ExecuteController for () { @@ -186,7 +186,7 @@ impl QueryController for () { _origin: Origin, _timeout: Timeout, _match_querier: VersionedLocation, - ) -> Result { + ) -> Result { Ok(Default::default()) } } diff --git a/polkadot/xcm/xcm-builder/src/pay.rs b/polkadot/xcm/xcm-builder/src/pay.rs index 6b466483cfa..35b624b0415 100644 --- a/polkadot/xcm/xcm-builder/src/pay.rs +++ b/polkadot/xcm/xcm-builder/src/pay.rs @@ -88,7 +88,7 @@ impl< type Beneficiary = Beneficiary; type AssetKind = AssetKind; type Balance = u128; - type Id = Querier::QueryId; + type Id = QueryId; type Error = xcm::latest::Error; fn pay( diff --git a/polkadot/xcm/xcm-builder/src/tests/mock.rs b/polkadot/xcm/xcm-builder/src/tests/mock.rs index 4bf347ea771..3d03ab05424 100644 --- a/polkadot/xcm/xcm-builder/src/tests/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/mock.rs @@ -38,7 +38,7 @@ pub use sp_std::{ collections::{btree_map::BTreeMap, btree_set::BTreeSet}, fmt::Debug, }; -pub use xcm::latest::{prelude::*, Weight}; +pub use xcm::latest::{prelude::*, QueryId, Weight}; use xcm_executor::traits::{Properties, QueryHandler, QueryResponseStatus}; pub use xcm_executor::{ traits::{ @@ -414,7 +414,6 @@ pub struct TestQueryHandler(core::marker::PhantomData<(T, BlockN impl QueryHandler for TestQueryHandler { - type QueryId = u64; type BlockNumber = BlockNumber; type Error = XcmError; type UniversalLocation = T::UniversalLocation; @@ -423,7 +422,7 @@ impl QueryHandler responder: impl Into, _timeout: Self::BlockNumber, _match_querier: impl Into, - ) -> Self::QueryId { + ) -> QueryId { let query_id = 1; expect_response(query_id, responder.into()); query_id @@ -433,7 +432,7 @@ impl QueryHandler message: &mut Xcm<()>, responder: impl Into, timeout: Self::BlockNumber, - ) -> Result { + ) -> Result { let responder = responder.into(); let destination = Self::UniversalLocation::get() .invert_target(&responder) @@ -445,7 +444,7 @@ impl QueryHandler Ok(query_id) } - fn take_response(query_id: Self::QueryId) -> QueryResponseStatus { + fn take_response(query_id: QueryId) -> QueryResponseStatus { QUERIES .with(|q| { q.borrow().get(&query_id).and_then(|v| match v { @@ -460,7 +459,7 @@ impl QueryHandler } #[cfg(feature = "runtime-benchmarks")] - fn expect_response(_id: Self::QueryId, _response: xcm::latest::Response) { + fn expect_response(_id: QueryId, _response: xcm::latest::Response) { // Unnecessary since it's only a test implementation } } diff --git a/polkadot/xcm/xcm-executor/src/traits/on_response.rs b/polkadot/xcm/xcm-executor/src/traits/on_response.rs index 952bd2d0040..1049bacdca5 100644 --- a/polkadot/xcm/xcm-executor/src/traits/on_response.rs +++ b/polkadot/xcm/xcm-executor/src/traits/on_response.rs @@ -16,11 +16,8 @@ use crate::{Junctions::Here, Xcm}; use core::result; -use frame_support::{ - pallet_prelude::{Get, TypeInfo}, - parameter_types, -}; -use parity_scale_codec::{Decode, Encode, FullCodec, MaxEncodedLen}; +use frame_support::{pallet_prelude::Get, parameter_types}; +use parity_scale_codec::{Decode, Encode}; use sp_arithmetic::traits::Zero; use sp_std::fmt::Debug; use xcm::latest::{ @@ -115,15 +112,6 @@ pub enum QueryResponseStatus { /// Provides methods to expect responses from XCMs and query their status. pub trait QueryHandler { - type QueryId: From - + FullCodec - + MaxEncodedLen - + TypeInfo - + Clone - + Eq - + PartialEq - + Debug - + Copy; type BlockNumber: Zero + Encode; type Error; type UniversalLocation: Get; @@ -151,14 +139,14 @@ pub trait QueryHandler { message: &mut Xcm<()>, responder: impl Into, timeout: Self::BlockNumber, - ) -> result::Result; + ) -> result::Result; /// Attempt to remove and return the response of query with ID `query_id`. - fn take_response(id: Self::QueryId) -> QueryResponseStatus; + fn take_response(id: QueryId) -> QueryResponseStatus; /// Makes sure to expect a response with the given id. #[cfg(feature = "runtime-benchmarks")] - fn expect_response(id: Self::QueryId, response: Response); + fn expect_response(id: QueryId, response: Response); } parameter_types! { @@ -168,17 +156,16 @@ parameter_types! { impl QueryHandler for () { type BlockNumber = u64; type Error = (); - type QueryId = u64; type UniversalLocation = UniversalLocation; - fn take_response(_query_id: Self::QueryId) -> QueryResponseStatus { + fn take_response(_query_id: QueryId) -> QueryResponseStatus { QueryResponseStatus::NotFound } fn new_query( _responder: impl Into, _timeout: Self::BlockNumber, _match_querier: impl Into, - ) -> Self::QueryId { + ) -> QueryId { 0u64 } @@ -186,10 +173,10 @@ impl QueryHandler for () { _message: &mut Xcm<()>, _responder: impl Into, _timeout: Self::BlockNumber, - ) -> Result { + ) -> Result { Err(()) } #[cfg(feature = "runtime-benchmarks")] - fn expect_response(_id: Self::QueryId, _response: crate::Response) {} + fn expect_response(_id: QueryId, _response: crate::Response) {} } -- GitLab From 9a04ebbfb0b77f2dcdc46db6a1a2b455881edd03 Mon Sep 17 00:00:00 2001 From: girazoki Date: Fri, 22 Mar 2024 19:48:15 +0100 Subject: [PATCH 085/187] [pallet-xcm] fix transport fees for remote reserve transfers (#3792) Currently `transfer_assets` from pallet-xcm covers 4 main different transfer types: - `localReserve` - `DestinationReserve` - `Teleport` - `RemoteReserve` For the first three, the local execution and the remote message sending are separated, and fees are deducted in pallet-xcm itself: https://github.com/paritytech/polkadot-sdk/blob/3410dfb3929462da88be2da813f121d8b1cf46b3/polkadot/xcm/pallet-xcm/src/lib.rs#L1758. For the 4th case `RemoteReserve`, pallet-xcm is still relying on the xcm-executor itself to send the message (through the `initiateReserveWithdraw` instruction). In this case, if delivery fees need to be charged, it is not possible to do so because the `jit_withdraw` mode has not being set. This PR proposes to still use the `initiateReserveWithdraw` but prepending a `setFeesMode { jit_withdraw: true }` to make sure delivery fees can be paid. A test-case is also added to present the aforementioned case --------- Co-authored-by: Adrian Catangiu --- .../emulated/common/src/macros.rs | 2 +- .../tests/assets/asset-hub-rococo/src/lib.rs | 8 +- .../src/tests/reserve_transfer.rs | 73 ++------ .../asset-hub-rococo/src/tests/teleport.rs | 14 +- .../tests/assets/asset-hub-westend/src/lib.rs | 8 +- .../src/tests/reserve_transfer.rs | 71 ++------ .../asset-hub-westend/src/tests/teleport.rs | 14 +- .../people-rococo/src/tests/teleport.rs | 6 +- .../people-westend/src/tests/teleport.rs | 6 +- .../assets/test-utils/src/test_cases.rs | 4 +- .../assets/test-utils/src/xcm_helpers.rs | 5 +- .../runtimes/testing/penpal/src/lib.rs | 19 +- .../runtimes/testing/penpal/src/xcm_config.rs | 19 +- polkadot/xcm/pallet-xcm/src/lib.rs | 1 + polkadot/xcm/pallet-xcm/src/mock.rs | 15 +- .../pallet-xcm/src/tests/assets_transfer.rs | 171 ++++++++++++++++++ prdoc/pr_3792.prdoc | 19 ++ 17 files changed, 291 insertions(+), 164 deletions(-) create mode 100644 prdoc/pr_3792.prdoc diff --git a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs index 6951de6faa7..6f6bbe41e01 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs @@ -115,7 +115,7 @@ macro_rules! test_parachain_is_trusted_teleporter { let para_receiver_balance_after = <$receiver_para as $crate::macros::Chain>::account_data_of(receiver.clone()).free; let delivery_fees = <$sender_para>::execute_with(|| { - $crate::macros::asset_test_utils::xcm_helpers::transfer_assets_delivery_fees::< + $crate::macros::asset_test_utils::xcm_helpers::teleport_assets_delivery_fees::< <$sender_xcm_config as xcm_executor::Config>::XcmSender, >($assets.clone(), fee_asset_item, weight_limit.clone(), beneficiary, para_destination) }); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs index 21d858f1fe5..a5a4914e21d 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs @@ -63,17 +63,13 @@ mod imports { // Runtimes pub use asset_hub_rococo_runtime::xcm_config::{ - TokenLocation as RelayLocation, UniversalLocation as AssetHubRococoUniversalLocation, - XcmConfig as AssetHubRococoXcmConfig, + TokenLocation as RelayLocation, XcmConfig as AssetHubRococoXcmConfig, }; pub use penpal_runtime::xcm_config::{ LocalReservableFromAssetHub as PenpalLocalReservableFromAssetHub, LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub, - UniversalLocation as PenpalUniversalLocation, XcmConfig as PenpalRococoXcmConfig, - }; - pub use rococo_runtime::xcm_config::{ - UniversalLocation as RococoUniversalLocation, XcmConfig as RococoXcmConfig, }; + pub use rococo_runtime::xcm_config::XcmConfig as RococoXcmConfig; pub const ASSET_ID: u32 = 3; pub const ASSET_MIN_BALANCE: u128 = 1000; diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index 705c9613b64..0a5956dedfd 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -524,7 +524,6 @@ fn reserve_transfer_native_asset_from_relay_to_para() { let destination = Rococo::child_location_of(PenpalA::para_id()); let sender = RococoSender::get(); let amount_to_send: Balance = ROCOCO_ED * 1000; - let assets: Assets = (Here, amount_to_send).into(); // Init values fot Parachain let relay_native_asset_location = @@ -552,15 +551,6 @@ fn reserve_transfer_native_asset_from_relay_to_para() { test.set_dispatchable::(relay_to_para_reserve_transfer_assets); test.assert(); - // Calculate delivery fees - let delivery_fees = Rococo::execute_with(|| { - let reanchored_assets = - assets.reanchored(&destination, &RococoUniversalLocation::get()).unwrap(); - xcm_helpers::transfer_assets_delivery_fees::< - ::XcmSender, - >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - // Query final balances let sender_balance_after = test.sender.balance; let receiver_assets_after = PenpalA::execute_with(|| { @@ -568,8 +558,8 @@ fn reserve_transfer_native_asset_from_relay_to_para() { >::balance(relay_native_asset_location.into(), &receiver) }); - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_balance_after < sender_balance_before - amount_to_send); // Receiver's asset balance is increased assert!(receiver_assets_after > receiver_assets_before); // Receiver's asset balance increased by `amount_to_send - delivery_fees - bought_execution`; @@ -595,7 +585,7 @@ fn reserve_transfer_native_asset_from_para_to_relay() { ::RuntimeOrigin::signed(asset_owner), relay_native_asset_location, sender.clone(), - amount_to_send, + amount_to_send * 2, ); // Init values for Relay @@ -634,15 +624,6 @@ fn reserve_transfer_native_asset_from_para_to_relay() { test.set_dispatchable::(para_to_relay_reserve_transfer_assets); test.assert(); - // Calculate delivery fees - let delivery_fees = PenpalA::execute_with(|| { - let reanchored_assets = - assets.reanchored(&destination, &PenpalUniversalLocation::get()).unwrap(); - xcm_helpers::transfer_assets_delivery_fees::< - ::XcmSender, - >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - // Query final balances let sender_assets_after = PenpalA::execute_with(|| { type ForeignAssets = ::ForeignAssets; @@ -650,8 +631,8 @@ fn reserve_transfer_native_asset_from_para_to_relay() { }); let receiver_balance_after = test.receiver.balance; - // Sender's balance is reduced - assert_eq!(sender_assets_before - amount_to_send - delivery_fees, sender_assets_after); + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_assets_after < sender_assets_before - amount_to_send); // Receiver's asset balance is increased assert!(receiver_balance_after > receiver_balance_before); // Receiver's asset balance increased by `amount_to_send - delivery_fees - bought_execution`; @@ -705,16 +686,6 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { test.set_dispatchable::(system_para_to_para_reserve_transfer_assets); test.assert(); - // Calculate delivery fees - let delivery_fees = AssetHubRococo::execute_with(|| { - let reanchored_assets = assets - .reanchored(&destination, &AssetHubRococoUniversalLocation::get()) - .unwrap(); - xcm_helpers::transfer_assets_delivery_fees::< - ::XcmSender, - >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - // Query final balances let sender_balance_after = test.sender.balance; let receiver_assets_after = PenpalA::execute_with(|| { @@ -722,8 +693,8 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { >::balance(system_para_native_asset_location, &receiver) }); - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_balance_after < sender_balance_before - amount_to_send); // Receiver's assets is increased assert!(receiver_assets_after > receiver_assets_before); // Receiver's assets increased by `amount_to_send - delivery_fees - bought_execution`; @@ -738,7 +709,7 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { // Init values for Parachain let destination = PenpalA::sibling_location_of(AssetHubRococo::para_id()); let sender = PenpalASender::get(); - let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; + let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 10000; let assets: Assets = (Parent, amount_to_send).into(); let system_para_native_asset_location = v3::Location::try_from(RelayLocation::get()).expect("conversion works"); @@ -749,7 +720,7 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { ::RuntimeOrigin::signed(asset_owner), system_para_native_asset_location, sender.clone(), - amount_to_send, + amount_to_send * 2, ); // Init values for System Parachain @@ -788,15 +759,6 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { test.set_dispatchable::(para_to_system_para_reserve_transfer_assets); test.assert(); - // Calculate delivery fees - let delivery_fees = PenpalA::execute_with(|| { - let reanchored_assets = - assets.reanchored(&destination, &PenpalUniversalLocation::get()).unwrap(); - xcm_helpers::transfer_assets_delivery_fees::< - ::XcmSender, - >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - // Query final balances let sender_assets_after = PenpalA::execute_with(|| { type ForeignAssets = ::ForeignAssets; @@ -804,8 +766,8 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { }); let receiver_balance_after = test.receiver.balance; - // Sender's balance is reduced - assert_eq!(sender_assets_before - amount_to_send - delivery_fees, sender_assets_after); + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_assets_after < sender_assets_before - amount_to_send); // Receiver's balance is increased assert!(receiver_balance_after > receiver_balance_before); // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; @@ -1084,7 +1046,7 @@ fn reserve_transfer_native_asset_from_para_to_para_trough_relay() { ::RuntimeOrigin::signed(asset_owner), relay_native_asset_location, sender.clone(), - amount_to_send, + amount_to_send * 2, ); // fund the Parachain Origin's SA on Relay Chain with the native tokens held in reserve @@ -1118,13 +1080,6 @@ fn reserve_transfer_native_asset_from_para_to_para_trough_relay() { test.set_dispatchable::(para_to_para_through_relay_limited_reserve_transfer_assets); test.assert(); - // Calculate delivery fees - let delivery_fees = PenpalA::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - // Query final balances let sender_assets_after = PenpalA::execute_with(|| { type ForeignAssets = ::ForeignAssets; @@ -1135,8 +1090,8 @@ fn reserve_transfer_native_asset_from_para_to_para_trough_relay() { >::balance(relay_native_asset_location, &receiver) }); - // Sender's balance is reduced - assert_eq!(sender_assets_before - amount_to_send - delivery_fees, sender_assets_after); + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_assets_after < sender_assets_before - amount_to_send); // Receiver's balance is increased assert!(receiver_assets_after > receiver_assets_before); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs index 0cc5ddb9f64..4432999aa95 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs @@ -322,7 +322,7 @@ fn limited_teleport_native_assets_from_relay_to_system_para_works() { test.assert(); let delivery_fees = Rococo::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -369,7 +369,7 @@ fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { let receiver_balance_after = test.receiver.balance; let delivery_fees = AssetHubRococo::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -410,7 +410,7 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { let receiver_balance_after = test.receiver.balance; let delivery_fees = AssetHubRococo::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -445,7 +445,7 @@ fn teleport_native_assets_from_relay_to_system_para_works() { test.assert(); let delivery_fees = Rococo::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -492,7 +492,7 @@ fn teleport_native_assets_back_from_system_para_to_relay_works() { let receiver_balance_after = test.receiver.balance; let delivery_fees = AssetHubRococo::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -530,7 +530,7 @@ fn teleport_native_assets_from_system_para_to_relay_fails() { test.assert(); let delivery_fees = AssetHubRococo::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -593,7 +593,7 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { ::RuntimeOrigin::signed(asset_owner.clone()), system_para_native_asset_location, sender.clone(), - fee_amount_to_send, + fee_amount_to_send * 2, ); // No need to create the asset (only mint) as it exists in genesis. PenpalA::mint_asset( diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs index 3f899d1dbdb..c9f5fe0647e 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs @@ -67,17 +67,13 @@ mod imports { // Runtimes pub use asset_hub_westend_runtime::xcm_config::{ - UniversalLocation as AssetHubWestendUniversalLocation, WestendLocation as RelayLocation, - XcmConfig as AssetHubWestendXcmConfig, + WestendLocation as RelayLocation, XcmConfig as AssetHubWestendXcmConfig, }; pub use penpal_runtime::xcm_config::{ LocalReservableFromAssetHub as PenpalLocalReservableFromAssetHub, LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub, - UniversalLocation as PenpalUniversalLocation, XcmConfig as PenpalWestendXcmConfig, - }; - pub use westend_runtime::xcm_config::{ - UniversalLocation as WestendUniversalLocation, XcmConfig as WestendXcmConfig, }; + pub use westend_runtime::xcm_config::XcmConfig as WestendXcmConfig; pub const ASSET_ID: u32 = 3; pub const ASSET_MIN_BALANCE: u128 = 1000; diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs index 8c836132b54..64ad15ca312 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs @@ -524,7 +524,6 @@ fn reserve_transfer_native_asset_from_relay_to_para() { let destination = Westend::child_location_of(PenpalA::para_id()); let sender = WestendSender::get(); let amount_to_send: Balance = WESTEND_ED * 1000; - let assets: Assets = (Here, amount_to_send).into(); // Init values fot Parachain let relay_native_asset_location = @@ -552,15 +551,6 @@ fn reserve_transfer_native_asset_from_relay_to_para() { test.set_dispatchable::(relay_to_para_reserve_transfer_assets); test.assert(); - // Calculate delivery fees - let delivery_fees = Westend::execute_with(|| { - let reanchored_assets = - assets.reanchored(&destination, &WestendUniversalLocation::get()).unwrap(); - xcm_helpers::transfer_assets_delivery_fees::< - ::XcmSender, - >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - // Query final balances let sender_balance_after = test.sender.balance; let receiver_assets_after = PenpalA::execute_with(|| { @@ -568,8 +558,8 @@ fn reserve_transfer_native_asset_from_relay_to_para() { >::balance(relay_native_asset_location.into(), &receiver) }); - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_balance_after < sender_balance_before - amount_to_send); // Receiver's asset balance is increased assert!(receiver_assets_after > receiver_assets_before); // Receiver's asset balance increased by `amount_to_send - delivery_fees - bought_execution`; @@ -595,7 +585,7 @@ fn reserve_transfer_native_asset_from_para_to_relay() { ::RuntimeOrigin::signed(asset_owner), relay_native_asset_location, sender.clone(), - amount_to_send, + amount_to_send * 2, ); // Init values for Relay @@ -634,15 +624,6 @@ fn reserve_transfer_native_asset_from_para_to_relay() { test.set_dispatchable::(para_to_relay_reserve_transfer_assets); test.assert(); - // Calculate delivery fees - let delivery_fees = PenpalA::execute_with(|| { - let reanchored_assets = - assets.reanchored(&destination, &PenpalUniversalLocation::get()).unwrap(); - xcm_helpers::transfer_assets_delivery_fees::< - ::XcmSender, - >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - // Query final balances let sender_assets_after = PenpalA::execute_with(|| { type ForeignAssets = ::ForeignAssets; @@ -650,8 +631,8 @@ fn reserve_transfer_native_asset_from_para_to_relay() { }); let receiver_balance_after = test.receiver.balance; - // Sender's balance is reduced - assert_eq!(sender_assets_before - amount_to_send - delivery_fees, sender_assets_after); + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_assets_after < sender_assets_before - amount_to_send); // Receiver's asset balance is increased assert!(receiver_balance_after > receiver_balance_before); // Receiver's asset balance increased by `amount_to_send - delivery_fees - bought_execution`; @@ -705,16 +686,6 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { test.set_dispatchable::(system_para_to_para_reserve_transfer_assets); test.assert(); - // Calculate delivery fees - let delivery_fees = AssetHubWestend::execute_with(|| { - let reanchored_assets = assets - .reanchored(&destination, &AssetHubWestendUniversalLocation::get()) - .unwrap(); - xcm_helpers::transfer_assets_delivery_fees::< - ::XcmSender, - >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - // Query final balances let sender_balance_after = test.sender.balance; let receiver_assets_after = PenpalA::execute_with(|| { @@ -722,8 +693,8 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { >::balance(system_para_native_asset_location, &receiver) }); - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_balance_after < sender_balance_before - amount_to_send); // Receiver's assets is increased assert!(receiver_assets_after > receiver_assets_before); // Receiver's assets increased by `amount_to_send - delivery_fees - bought_execution`; @@ -749,7 +720,7 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { ::RuntimeOrigin::signed(asset_owner), system_para_native_asset_location, sender.clone(), - amount_to_send, + amount_to_send * 2, ); // Init values for System Parachain @@ -789,15 +760,6 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { test.set_dispatchable::(para_to_system_para_reserve_transfer_assets); test.assert(); - // Calculate delivery fees - let delivery_fees = PenpalA::execute_with(|| { - let reanchored_assets = - assets.reanchored(&destination, &PenpalUniversalLocation::get()).unwrap(); - xcm_helpers::transfer_assets_delivery_fees::< - ::XcmSender, - >(reanchored_assets, 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - // Query final balances let sender_assets_after = PenpalA::execute_with(|| { type ForeignAssets = ::ForeignAssets; @@ -805,8 +767,8 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { }); let receiver_balance_after = test.receiver.balance; - // Sender's balance is reduced - assert_eq!(sender_assets_before - amount_to_send - delivery_fees, sender_assets_after); + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_assets_after < sender_assets_before - amount_to_send); // Receiver's balance is increased assert!(receiver_balance_after > receiver_balance_before); // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; @@ -1086,7 +1048,7 @@ fn reserve_transfer_native_asset_from_para_to_para_trough_relay() { ::RuntimeOrigin::signed(asset_owner), relay_native_asset_location, sender.clone(), - amount_to_send, + amount_to_send * 2, ); // fund the Parachain Origin's SA on Relay Chain with the native tokens held in reserve @@ -1120,13 +1082,6 @@ fn reserve_transfer_native_asset_from_para_to_para_trough_relay() { test.set_dispatchable::(para_to_para_through_relay_limited_reserve_transfer_assets); test.assert(); - // Calculate delivery fees - let delivery_fees = PenpalA::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - // Query final balances let sender_assets_after = PenpalA::execute_with(|| { type ForeignAssets = ::ForeignAssets; @@ -1137,8 +1092,8 @@ fn reserve_transfer_native_asset_from_para_to_para_trough_relay() { >::balance(relay_native_asset_location, &receiver) }); - // Sender's balance is reduced - assert_eq!(sender_assets_before - amount_to_send - delivery_fees, sender_assets_after); + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_assets_after < sender_assets_before - amount_to_send); // Receiver's balance is increased assert!(receiver_assets_after > receiver_assets_before); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs index 61f547fe7c5..aba05ea4322 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs @@ -322,7 +322,7 @@ fn limited_teleport_native_assets_from_relay_to_system_para_works() { test.assert(); let delivery_fees = Westend::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -369,7 +369,7 @@ fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { let receiver_balance_after = test.receiver.balance; let delivery_fees = AssetHubWestend::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -410,7 +410,7 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { let receiver_balance_after = test.receiver.balance; let delivery_fees = AssetHubWestend::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -445,7 +445,7 @@ fn teleport_native_assets_from_relay_to_system_para_works() { test.assert(); let delivery_fees = Westend::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -492,7 +492,7 @@ fn teleport_native_assets_back_from_system_para_to_relay_works() { let receiver_balance_after = test.receiver.balance; let delivery_fees = AssetHubWestend::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -530,7 +530,7 @@ fn teleport_native_assets_from_system_para_to_relay_fails() { test.assert(); let delivery_fees = AssetHubWestend::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -593,7 +593,7 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { ::RuntimeOrigin::signed(asset_owner.clone()), system_para_native_asset_location, sender.clone(), - fee_amount_to_send, + fee_amount_to_send * 2, ); // No need to create the asset (only mint) as it exists in genesis. PenpalA::mint_asset( diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/teleport.rs index 3abe5c6cf66..350d87d638a 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/teleport.rs @@ -155,7 +155,7 @@ fn limited_teleport_native_assets_from_relay_to_system_para_works() { test.assert(); let delivery_fees = Rococo::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -204,7 +204,7 @@ fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { let receiver_balance_after = test.receiver.balance; let delivery_fees = PeopleRococo::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -248,7 +248,7 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { let receiver_balance_after = test.receiver.balance; let delivery_fees = PeopleRococo::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/teleport.rs index eef35a99a83..8697477ba76 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/teleport.rs @@ -155,7 +155,7 @@ fn limited_teleport_native_assets_from_relay_to_system_para_works() { test.assert(); let delivery_fees = Westend::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -204,7 +204,7 @@ fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { let receiver_balance_after = test.receiver.balance; let delivery_fees = PeopleWestend::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); @@ -248,7 +248,7 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { let receiver_balance_after = test.receiver.balance; let delivery_fees = PeopleWestend::execute_with(|| { - xcm_helpers::transfer_assets_delivery_fees::< + xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) }); diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs index 53e10956bd0..2f2624d8e52 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -186,7 +186,7 @@ pub fn teleports_for_native_asset_works< // Mint funds into account to ensure it has enough balance to pay delivery fees let delivery_fees = - xcm_helpers::transfer_assets_delivery_fees::( + xcm_helpers::teleport_assets_delivery_fees::( (native_asset_id.clone(), native_asset_to_teleport_away.into()).into(), 0, Unlimited, @@ -579,7 +579,7 @@ pub fn teleports_for_foreign_assets_works< // Make sure the target account has enough native asset to pay for delivery fees let delivery_fees = - xcm_helpers::transfer_assets_delivery_fees::( + xcm_helpers::teleport_assets_delivery_fees::( (foreign_asset_id_location_latest.clone(), asset_to_teleport_away).into(), 0, Unlimited, diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/xcm_helpers.rs b/cumulus/parachains/runtimes/assets/test-utils/src/xcm_helpers.rs index f509a3a8aca..ca0e81fae42 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/xcm_helpers.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/xcm_helpers.rs @@ -18,11 +18,10 @@ use xcm::latest::prelude::*; -/// Returns the delivery fees amount for pallet xcm's `teleport_assets` and -/// `reserve_transfer_assets` extrinsics. +/// Returns the delivery fees amount for pallet xcm's `teleport_assets` extrinsics. /// Because it returns only a `u128`, it assumes delivery fees are only paid /// in one asset and that asset is known. -pub fn transfer_assets_delivery_fees( +pub fn teleport_assets_delivery_fees( assets: Assets, fee_asset_item: u32, weight_limit: WeightLimit, diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index 1e6d485d148..1d404feac3d 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -57,7 +57,6 @@ use parachains_common::{ impls::{AssetsToBlockAuthor, NonZeroIssuance}, message_queue::{NarrowOriginToSibling, ParaIdToSibling}, }; -use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; use smallvec::smallvec; use sp_api::impl_runtime_apis; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; @@ -85,7 +84,7 @@ use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; // XCM Imports use parachains_common::{AccountId, Signature}; -use xcm::latest::prelude::BodyId; +use xcm::latest::prelude::{AssetId as AssetLocationId, BodyId}; /// Balance of an account. pub type Balance = u128; @@ -545,6 +544,20 @@ impl pallet_message_queue::Config for Runtime { impl cumulus_pallet_aura_ext::Config for Runtime {} +parameter_types! { + /// The asset ID for the asset that we use to pay for message delivery fees. + pub FeeAssetId: AssetLocationId = AssetLocationId(xcm_config::RelayLocation::get()); + /// The base fee for the message delivery fees (3 CENTS). + pub const BaseDeliveryFee: u128 = (1_000_000_000_000u128 / 100).saturating_mul(3); +} + +pub type PriceForSiblingParachainDelivery = polkadot_runtime_common::xcm_sender::ExponentialPrice< + FeeAssetId, + BaseDeliveryFee, + TransactionByteFee, + XcmpQueue, +>; + impl cumulus_pallet_xcmp_queue::Config for Runtime { type RuntimeEvent = RuntimeEvent; type ChannelInfo = ParachainSystem; @@ -555,7 +568,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = (); - type PriceForSiblingDelivery = NoPriceForMessageDelivery; + type PriceForSiblingDelivery = PriceForSiblingParachainDelivery; } parameter_types! { diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index d83a877c2f8..639bfd95834 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -28,6 +28,7 @@ use super::{ ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, }; +use crate::{BaseDeliveryFee, FeeAssetId, TransactionByteFee}; use core::marker::PhantomData; use frame_support::{ parameter_types, @@ -36,10 +37,10 @@ use frame_support::{ }; use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; -use parachains_common::xcm_config::AssetFeeAsExistentialDepositMultiplier; +use parachains_common::{xcm_config::AssetFeeAsExistentialDepositMultiplier, TREASURY_PALLET_ID}; use polkadot_parachain_primitives::primitives::Sibling; -use polkadot_runtime_common::impls::ToAuthor; -use sp_runtime::traits::ConvertInto; +use polkadot_runtime_common::{impls::ToAuthor, xcm_sender::ExponentialPrice}; +use sp_runtime::traits::{AccountIdConversion, ConvertInto}; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, @@ -49,6 +50,7 @@ use xcm_builder::{ SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, StartsWith, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, + XcmFeeManagerFromComponents, XcmFeeToAccount, }; use xcm_executor::{traits::JustTry, XcmExecutor}; @@ -59,6 +61,7 @@ parameter_types! { pub const RelayNetwork: Option = None; pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorLocation = [Parachain(ParachainInfo::parachain_id().into())].into(); + pub TreasuryAccount: AccountId = TREASURY_PALLET_ID.into_account_truncating(); } /// Type for specifying how a `Location` can be converted into an `AccountId`. This is used @@ -331,7 +334,10 @@ impl xcm_executor::Config for XcmConfig { type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type AssetLocker = (); type AssetExchanger = (); - type FeeManager = (); + type FeeManager = XcmFeeManagerFromComponents< + (), + XcmFeeToAccount, + >; type MessageExporter = (); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; @@ -355,11 +361,14 @@ pub type ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger = /// No local origins on this chain are allowed to dispatch XCM sends/executions. pub type LocalOriginToLocation = SignedToAccountId32; +pub type PriceForParentDelivery = + ExponentialPrice; + /// The means for routing XCM messages which are not for local execution into the right message /// queues. pub type XcmRouter = WithUniqueTopic<( // Two routers - use UMP to communicate with the relay chain: - cumulus_primitives_utility::ParentAsUmp, + cumulus_primitives_utility::ParentAsUmp, // ..and XCMP to communicate with the sibling chains. XcmpQueue, )>; diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 0761b375dfb..8a9e5288f2e 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1990,6 +1990,7 @@ impl Pallet { ]); Ok(Xcm(vec![ WithdrawAsset(assets.into()), + SetFeesMode { jit_withdraw: true }, InitiateReserveWithdraw { assets: Wild(AllCounted(max_assets)), reserve, diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index b29562fc833..2cc228476ba 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -361,6 +361,10 @@ parameter_types! { 0, [Parachain(FOREIGN_ASSET_RESERVE_PARA_ID)] ); + pub PaidParaForeignReserveLocation: Location = Location::new( + 0, + [Parachain(Para3000::get())] + ); pub ForeignAsset: Asset = Asset { fun: Fungible(10), id: AssetId(Location::new( @@ -368,6 +372,13 @@ parameter_types! { [Parachain(FOREIGN_ASSET_RESERVE_PARA_ID), FOREIGN_ASSET_INNER_JUNCTION], )), }; + pub PaidParaForeignAsset: Asset = Asset { + fun: Fungible(10), + id: AssetId(Location::new( + 0, + [Parachain(Para3000::get())], + )), + }; pub UsdcReserveLocation: Location = Location::new( 0, [Parachain(USDC_RESERVE_PARA_ID)] @@ -450,6 +461,8 @@ parameter_types! { pub TrustedFilteredTeleport: (AssetFilter, Location) = (FilteredTeleportAsset::get().into(), FilteredTeleportLocation::get()); pub TeleportUsdtToForeign: (AssetFilter, Location) = (Usdt::get().into(), ForeignReserveLocation::get()); pub TrustedForeign: (AssetFilter, Location) = (ForeignAsset::get().into(), ForeignReserveLocation::get()); + pub TrustedPaidParaForeign: (AssetFilter, Location) = (PaidParaForeignAsset::get().into(), PaidParaForeignReserveLocation::get()); + pub TrustedUsdc: (AssetFilter, Location) = (Usdc::get().into(), UsdcReserveLocation::get()); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; @@ -483,7 +496,7 @@ impl xcm_executor::Config for XcmConfig { type XcmSender = XcmRouter; type AssetTransactor = AssetTransactors; type OriginConverter = LocalOriginConverter; - type IsReserve = (Case, Case); + type IsReserve = (Case, Case, Case); type IsTeleporter = ( Case, Case, diff --git a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs index 27be5cce145..7752d1355cd 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs @@ -2604,3 +2604,174 @@ fn teleport_assets_using_destination_reserve_fee_disallowed() { expected_result, ); } + +/// Test `tested_call` transferring single asset using remote reserve. +/// +/// Transferring Para3000 asset (`Para3000` reserve) to +/// `OTHER_PARA_ID` (no teleport trust), therefore triggering remote reserve. +/// Using the same asset asset (Para3000 reserve) for fees. +/// +/// Asserts that the sender's balance is decreased and the beneficiary's balance +/// is increased. Verifies the correct message is sent and event is emitted. +/// +/// Verifies that XCM router fees (`SendXcm::validate` -> `Assets`) are withdrawn from correct +/// user account and deposited to a correct target account (`XcmFeesTargetAccount`). +/// Verifies `expected_result`. +fn remote_asset_reserve_and_remote_fee_reserve_paid_call( + tested_call: Call, + expected_result: DispatchResult, +) where + Call: FnOnce( + OriginFor, + Box, + Box, + Box, + u32, + WeightLimit, + ) -> DispatchResult, +{ + let weight = BaseXcmWeight::get() * 3; + let user_account = AccountId::from(XCM_FEES_NOT_WAIVED_USER_ACCOUNT); + let xcm_router_fee_amount = Para3000PaymentAmount::get(); + let paid_para_id = Para3000::get(); + let balances = vec![ + (user_account.clone(), INITIAL_BALANCE), + (ParaId::from(paid_para_id).into_account_truncating(), INITIAL_BALANCE), + (XcmFeesTargetAccount::get(), INITIAL_BALANCE), + ]; + let beneficiary: Location = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + new_test_ext_with_balances(balances).execute_with(|| { + // create sufficient foreign asset BLA + let foreign_initial_amount = 142; + let (reserve_location, _, foreign_asset_id_location) = set_up_foreign_asset( + paid_para_id, + None, + user_account.clone(), + foreign_initial_amount, + true, + ); + + // transfer destination is another chain that is not the reserve location + // the goal is to trigger the remoteReserve case + let dest = RelayLocation::get().pushed_with_interior(Parachain(OTHER_PARA_ID)).unwrap(); + + let transferred_asset: Assets = (foreign_asset_id_location.clone(), SEND_AMOUNT).into(); + + // balances checks before + assert_eq!( + AssetsPallet::balance(foreign_asset_id_location.clone(), user_account.clone()), + foreign_initial_amount + ); + assert_eq!(Balances::free_balance(user_account.clone()), INITIAL_BALANCE); + + // do the transfer + let result = tested_call( + RuntimeOrigin::signed(user_account.clone()), + Box::new(dest.clone().into()), + Box::new(beneficiary.clone().into()), + Box::new(transferred_asset.into()), + 0 as u32, + Unlimited, + ); + assert_eq!(result, expected_result); + if expected_result.is_err() { + // short-circuit here for tests where we expect failure + return; + } + + let mut last_events = last_events(7).into_iter(); + // asset events + // forceCreate + last_events.next().unwrap(); + // mint tokens + last_events.next().unwrap(); + // burn tokens + last_events.next().unwrap(); + // balance events + // burn delivery fee + last_events.next().unwrap(); + // mint delivery fee + last_events.next().unwrap(); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { + outcome: Outcome::Complete { used: weight } + }) + ); + + // user account spent (transferred) amount + assert_eq!( + AssetsPallet::balance(foreign_asset_id_location.clone(), user_account.clone()), + foreign_initial_amount - SEND_AMOUNT + ); + + // user account spent delivery fees + assert_eq!(Balances::free_balance(user_account), INITIAL_BALANCE - xcm_router_fee_amount); + + // XcmFeesTargetAccount where should lend xcm_router_fee_amount + assert_eq!( + Balances::free_balance(XcmFeesTargetAccount::get()), + INITIAL_BALANCE + xcm_router_fee_amount + ); + + // Verify total and active issuance of foreign BLA have decreased (burned on + // reserve-withdraw) + let expected_issuance = foreign_initial_amount - SEND_AMOUNT; + assert_eq!( + AssetsPallet::total_issuance(foreign_asset_id_location.clone()), + expected_issuance + ); + assert_eq!( + AssetsPallet::active_issuance(foreign_asset_id_location.clone()), + expected_issuance + ); + + let context = UniversalLocation::get(); + let foreign_id_location_reanchored = + foreign_asset_id_location.reanchored(&dest, &context).unwrap(); + let dest_reanchored = dest.reanchored(&reserve_location, &context).unwrap(); + + // Verify sent XCM program + assert_eq!( + sent_xcm(), + vec![( + reserve_location, + // `assets` are burned on source and withdrawn from SA in remote reserve chain + Xcm(vec![ + WithdrawAsset((Location::here(), SEND_AMOUNT).into()), + ClearOrigin, + buy_execution((Location::here(), SEND_AMOUNT / 2)), + DepositReserveAsset { + assets: Wild(AllCounted(1)), + // final destination is `dest` as seen by `reserve` + dest: dest_reanchored, + // message sent onward to `dest` + xcm: Xcm(vec![ + buy_execution((foreign_id_location_reanchored, SEND_AMOUNT / 2)), + DepositAsset { assets: AllCounted(1).into(), beneficiary } + ]) + } + ]) + )] + ); + }); +} +/// Test `transfer_assets` with remote asset reserve and remote fee reserve. +#[test] +fn transfer_assets_with_remote_asset_reserve_and_remote_asset_fee_reserve_paid_works() { + let expected_result = Ok(()); + remote_asset_reserve_and_remote_fee_reserve_paid_call( + XcmPallet::transfer_assets, + expected_result, + ); +} +/// Test `limited_reserve_transfer_assets` with remote asset reserve and remote fee reserve. +#[test] +fn limited_reserve_transfer_assets_with_remote_asset_reserve_and_remote_asset_fee_reserve_paid_works( +) { + let expected_result = Ok(()); + remote_asset_reserve_and_remote_fee_reserve_paid_call( + XcmPallet::limited_reserve_transfer_assets, + expected_result, + ); +} diff --git a/prdoc/pr_3792.prdoc b/prdoc/pr_3792.prdoc new file mode 100644 index 00000000000..cbcdc29a9c6 --- /dev/null +++ b/prdoc/pr_3792.prdoc @@ -0,0 +1,19 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "[pallet-xcm] fix transport fees for remote reserve transfers" + +doc: + - audience: Runtime Dev + description: | + This PR fixes `pallet_xcm::transfer_assets` and + `pallet_xcm::limited_reserve_transfer_assets` extrinsics for transfers + that need to go through remote reserves. The fix is adding a + `SetFeesMode { jit_withdraw: true }` instruction before local execution of + `InitiateReserveWithdraw` so that delivery fees are correctly charged by + the xcm-executor. Without this change, a runtime that has implemented + delivery fees would not be able to execute remote reserve transfers using + these extrinsics. + +crates: + - name: pallet-xcm -- GitLab From 19490abae08570ce87c3cae57542e928aa9a149d Mon Sep 17 00:00:00 2001 From: eskimor Date: Sat, 23 Mar 2024 06:46:15 +0100 Subject: [PATCH 086/187] Fix xcm config for coretime. (#3768) Fixes https://github.com/paritytech/polkadot-sdk/issues/3762 . --------- Co-authored-by: eskimor Co-authored-by: Adrian Catangiu --- polkadot/runtime/westend/src/xcm_config.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index 400843c5835..96d2a124ff9 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -41,10 +41,11 @@ use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, DescribeAllTerminal, DescribeFamily, FrameTransactionalProcessor, - FungibleAdapter, HashedDescription, IsConcrete, MintLocation, OriginToPluralityVoice, - SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, - TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, - XcmFeeManagerFromComponents, XcmFeeToAccount, + FungibleAdapter, HashedDescription, IsChildSystemParachain, IsConcrete, MintLocation, + OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, + WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, + XcmFeeToAccount, }; use xcm_executor::XcmExecutor; @@ -142,13 +143,12 @@ impl Contains for OnlyParachains { } } -pub struct CollectivesOrFellows; -impl Contains for CollectivesOrFellows { +pub struct Fellows; +impl Contains for Fellows { fn contains(location: &Location) -> bool { matches!( location.unpack(), - (0, [Parachain(COLLECTIVES_ID)]) | - (0, [Parachain(COLLECTIVES_ID), Plurality { id: BodyId::Technical, .. }]) + (0, [Parachain(COLLECTIVES_ID), Plurality { id: BodyId::Technical, .. }]) ) } } @@ -172,8 +172,8 @@ pub type Barrier = TrailingSetTopicAsId<( AllowTopLevelPaidExecutionFrom, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, - // Collectives and Fellows plurality get free execution. - AllowExplicitUnpaidExecutionFrom, + // Messages from system parachains or the Fellows plurality need not pay for execution. + AllowExplicitUnpaidExecutionFrom<(IsChildSystemParachain, Fellows)>, ), UniversalLocation, ConstU32<8>, -- GitLab From 463ccb8f9028ebf5f7fc53d7e835c21f43172253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sun, 24 Mar 2024 15:21:18 +0100 Subject: [PATCH 087/187] pallet-aura: Expose `SlotDuration` as constant (#3732) --- substrate/frame/aura/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/substrate/frame/aura/src/lib.rs b/substrate/frame/aura/src/lib.rs index 997f51ba428..3ca1444aaae 100644 --- a/substrate/frame/aura/src/lib.rs +++ b/substrate/frame/aura/src/lib.rs @@ -114,6 +114,7 @@ pub mod pallet { /// The effective value of this type should not change while the chain is running. /// /// For backwards compatibility either use [`MinimumPeriodTimesTwo`] or a const. + #[pallet::constant] type SlotDuration: Get<::Moment>; } -- GitLab From e88d1cb79315792a3dbccb6bdef2543093ecaf5b Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Mon, 25 Mar 2024 10:40:22 +0100 Subject: [PATCH 088/187] [docs] Update ci image in container.md (#3799) cc https://github.com/paritytech/ci_cd/issues/943 --- docs/contributor/container.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/docs/contributor/container.md b/docs/contributor/container.md index dd44b31bfe9..9c542f411c8 100644 --- a/docs/contributor/container.md +++ b/docs/contributor/container.md @@ -16,7 +16,7 @@ Parity builds and publishes a container image that can be found as `docker.io/pa ## Parity CI image Parity maintains and uses internally a generic "CI" image that can be used as a base to build binaries: [Parity CI -container image](https://github.com/paritytech/scripts/tree/master/dockerfiles/ci-linux): +container image](https://github.com/paritytech/scripts/tree/master/dockerfiles/ci-unified): The command below allows building a Linux binary without having to even install Rust or any dependency locally: @@ -24,14 +24,11 @@ The command below allows building a Linux binary without having to even install docker run --rm -it \ -w /polkadot-sdk \ -v $(pwd):/polkadot-sdk \ - paritytech/ci-linux:production \ + paritytech/ci-unified:bullseye-1.75.0-2024-01-22-v20240222 \ cargo build --release --locked -p polkadot-parachain-bin --bin polkadot-parachain sudo chown -R $(id -u):$(id -g) target/ ``` -If you want to reproduce other steps of CI process you can use the following -[guide](https://github.com/paritytech/scripts#gitlab-ci-for-building-docker-images). - ## Injected image Injecting a binary inside a base image is the quickest option to get a working container image. This only works if you -- GitLab From 0711729d251efebf3486db602119ecfa67d98366 Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Mon, 25 Mar 2024 13:11:30 +0100 Subject: [PATCH 089/187] [Bridges] Move chain definitions to separate folder (#3822) Related to https://github.com/paritytech/parity-bridges-common/issues/2538 This PR doesn't contain any functional changes. The PR moves specific bridged chain definitions from `bridges/primitives` to `bridges/chains` folder in order to facilitate the migration of the `parity-bridges-repo` into `polkadot-sdk` as discussed in https://hackmd.io/LprWjZ0bQXKpFeveYHIRXw?view Apart from this it also includes some cosmetic changes to some `Cargo.toml` files as a result of running `diener workspacify`. --- Cargo.toml | 24 +++++++++---------- .../chain-asset-hub-rococo/Cargo.toml | 2 +- .../chain-asset-hub-rococo/src/lib.rs | 0 .../chain-asset-hub-westend/Cargo.toml | 2 +- .../chain-asset-hub-westend/src/lib.rs | 0 .../chain-bridge-hub-cumulus/Cargo.toml | 6 ++--- .../chain-bridge-hub-cumulus/src/lib.rs | 0 .../chain-bridge-hub-kusama/Cargo.toml | 4 ++-- .../chain-bridge-hub-kusama/src/lib.rs | 0 .../chain-bridge-hub-polkadot/Cargo.toml | 4 ++-- .../chain-bridge-hub-polkadot/src/lib.rs | 0 .../chain-bridge-hub-rococo/Cargo.toml | 4 ++-- .../chain-bridge-hub-rococo/src/lib.rs | 0 .../chain-bridge-hub-westend/Cargo.toml | 4 ++-- .../chain-bridge-hub-westend/src/lib.rs | 0 .../chain-kusama/Cargo.toml | 6 ++--- .../chain-kusama/src/lib.rs | 0 .../chain-polkadot-bulletin/Cargo.toml | 8 +++---- .../chain-polkadot-bulletin/src/lib.rs | 0 .../chain-polkadot/Cargo.toml | 6 ++--- .../chain-polkadot/src/lib.rs | 0 .../chain-rococo/Cargo.toml | 6 ++--- .../chain-rococo/src/lib.rs | 0 .../chain-westend/Cargo.toml | 6 ++--- .../chain-westend/src/lib.rs | 0 .../pallets/ethereum-client/Cargo.toml | 4 ++-- .../pallets/inbound-queue/Cargo.toml | 2 +- cumulus/client/consensus/aura/Cargo.toml | 2 +- .../assets/asset-hub-rococo/Cargo.toml | 2 +- .../assets/asset-hub-westend/Cargo.toml | 2 +- .../bridges/bridge-hub-rococo/Cargo.toml | 2 +- .../bridges/bridge-hub-westend/Cargo.toml | 2 +- .../collectives-westend/Cargo.toml | 2 +- .../people/people-rococo/Cargo.toml | 2 +- .../people/people-westend/Cargo.toml | 2 +- .../parachains/testing/penpal/Cargo.toml | 2 +- .../emulated/chains/relays/rococo/Cargo.toml | 2 +- .../emulated/chains/relays/westend/Cargo.toml | 2 +- .../tests/assets/asset-hub-rococo/Cargo.toml | 2 +- .../tests/assets/asset-hub-westend/Cargo.toml | 6 ++--- .../bridges/bridge-hub-rococo/Cargo.toml | 4 ++-- .../bridges/bridge-hub-westend/Cargo.toml | 4 ++-- .../tests/people/people-rococo/Cargo.toml | 2 +- .../tests/people/people-westend/Cargo.toml | 2 +- .../pallets/collective-content/Cargo.toml | 2 +- .../assets/asset-hub-rococo/Cargo.toml | 8 +++---- .../assets/asset-hub-westend/Cargo.toml | 8 +++---- .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 16 ++++++------- .../bridge-hubs/bridge-hub-westend/Cargo.toml | 14 +++++------ .../storage-weight-reclaim/Cargo.toml | 4 ++-- polkadot/Cargo.toml | 2 +- polkadot/node/core/pvf/Cargo.toml | 2 +- templates/solochain/runtime/Cargo.toml | 2 +- 53 files changed, 94 insertions(+), 94 deletions(-) rename bridges/{primitives => chains}/chain-asset-hub-rococo/Cargo.toml (87%) rename bridges/{primitives => chains}/chain-asset-hub-rococo/src/lib.rs (100%) rename bridges/{primitives => chains}/chain-asset-hub-westend/Cargo.toml (87%) rename bridges/{primitives => chains}/chain-asset-hub-westend/src/lib.rs (100%) rename bridges/{primitives => chains}/chain-bridge-hub-cumulus/Cargo.toml (80%) rename bridges/{primitives => chains}/chain-bridge-hub-cumulus/src/lib.rs (100%) rename bridges/{primitives => chains}/chain-bridge-hub-kusama/Cargo.toml (85%) rename bridges/{primitives => chains}/chain-bridge-hub-kusama/src/lib.rs (100%) rename bridges/{primitives => chains}/chain-bridge-hub-polkadot/Cargo.toml (85%) rename bridges/{primitives => chains}/chain-bridge-hub-polkadot/src/lib.rs (100%) rename bridges/{primitives => chains}/chain-bridge-hub-rococo/Cargo.toml (85%) rename bridges/{primitives => chains}/chain-bridge-hub-rococo/src/lib.rs (100%) rename bridges/{primitives => chains}/chain-bridge-hub-westend/Cargo.toml (85%) rename bridges/{primitives => chains}/chain-bridge-hub-westend/src/lib.rs (100%) rename bridges/{primitives => chains}/chain-kusama/Cargo.toml (73%) rename bridges/{primitives => chains}/chain-kusama/src/lib.rs (100%) rename bridges/{primitives => chains}/chain-polkadot-bulletin/Cargo.toml (78%) rename bridges/{primitives => chains}/chain-polkadot-bulletin/src/lib.rs (100%) rename bridges/{primitives => chains}/chain-polkadot/Cargo.toml (73%) rename bridges/{primitives => chains}/chain-polkadot/src/lib.rs (100%) rename bridges/{primitives => chains}/chain-rococo/Cargo.toml (73%) rename bridges/{primitives => chains}/chain-rococo/src/lib.rs (100%) rename bridges/{primitives => chains}/chain-westend/Cargo.toml (73%) rename bridges/{primitives => chains}/chain-westend/src/lib.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 01d6ef8e87b..5eeac597827 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,24 +10,24 @@ resolver = "2" members = [ "bridges/bin/runtime-common", + "bridges/chains/chain-asset-hub-rococo", + "bridges/chains/chain-asset-hub-westend", + "bridges/chains/chain-bridge-hub-cumulus", + "bridges/chains/chain-bridge-hub-kusama", + "bridges/chains/chain-bridge-hub-polkadot", + "bridges/chains/chain-bridge-hub-rococo", + "bridges/chains/chain-bridge-hub-westend", + "bridges/chains/chain-kusama", + "bridges/chains/chain-polkadot", + "bridges/chains/chain-polkadot-bulletin", + "bridges/chains/chain-rococo", + "bridges/chains/chain-westend", "bridges/modules/grandpa", "bridges/modules/messages", "bridges/modules/parachains", "bridges/modules/relayers", "bridges/modules/xcm-bridge-hub", "bridges/modules/xcm-bridge-hub-router", - "bridges/primitives/chain-asset-hub-rococo", - "bridges/primitives/chain-asset-hub-westend", - "bridges/primitives/chain-bridge-hub-cumulus", - "bridges/primitives/chain-bridge-hub-kusama", - "bridges/primitives/chain-bridge-hub-polkadot", - "bridges/primitives/chain-bridge-hub-rococo", - "bridges/primitives/chain-bridge-hub-westend", - "bridges/primitives/chain-kusama", - "bridges/primitives/chain-polkadot", - "bridges/primitives/chain-polkadot-bulletin", - "bridges/primitives/chain-rococo", - "bridges/primitives/chain-westend", "bridges/primitives/header-chain", "bridges/primitives/messages", "bridges/primitives/parachains", diff --git a/bridges/primitives/chain-asset-hub-rococo/Cargo.toml b/bridges/chains/chain-asset-hub-rococo/Cargo.toml similarity index 87% rename from bridges/primitives/chain-asset-hub-rococo/Cargo.toml rename to bridges/chains/chain-asset-hub-rococo/Cargo.toml index 4dfa149e0ea..07c9b3b5289 100644 --- a/bridges/primitives/chain-asset-hub-rococo/Cargo.toml +++ b/bridges/chains/chain-asset-hub-rococo/Cargo.toml @@ -17,7 +17,7 @@ scale-info = { version = "2.10.0", default-features = false, features = ["derive frame-support = { path = "../../../substrate/frame/support", default-features = false } # Bridge Dependencies -bp-xcm-bridge-hub-router = { path = "../xcm-bridge-hub-router", default-features = false } +bp-xcm-bridge-hub-router = { path = "../../primitives/xcm-bridge-hub-router", default-features = false } [features] default = ["std"] diff --git a/bridges/primitives/chain-asset-hub-rococo/src/lib.rs b/bridges/chains/chain-asset-hub-rococo/src/lib.rs similarity index 100% rename from bridges/primitives/chain-asset-hub-rococo/src/lib.rs rename to bridges/chains/chain-asset-hub-rococo/src/lib.rs diff --git a/bridges/primitives/chain-asset-hub-westend/Cargo.toml b/bridges/chains/chain-asset-hub-westend/Cargo.toml similarity index 87% rename from bridges/primitives/chain-asset-hub-westend/Cargo.toml rename to bridges/chains/chain-asset-hub-westend/Cargo.toml index c9bd437562b..f75236ee1b3 100644 --- a/bridges/primitives/chain-asset-hub-westend/Cargo.toml +++ b/bridges/chains/chain-asset-hub-westend/Cargo.toml @@ -17,7 +17,7 @@ scale-info = { version = "2.10.0", default-features = false, features = ["derive frame-support = { path = "../../../substrate/frame/support", default-features = false } # Bridge Dependencies -bp-xcm-bridge-hub-router = { path = "../xcm-bridge-hub-router", default-features = false } +bp-xcm-bridge-hub-router = { path = "../../primitives/xcm-bridge-hub-router", default-features = false } [features] default = ["std"] diff --git a/bridges/primitives/chain-asset-hub-westend/src/lib.rs b/bridges/chains/chain-asset-hub-westend/src/lib.rs similarity index 100% rename from bridges/primitives/chain-asset-hub-westend/src/lib.rs rename to bridges/chains/chain-asset-hub-westend/src/lib.rs diff --git a/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml b/bridges/chains/chain-bridge-hub-cumulus/Cargo.toml similarity index 80% rename from bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml rename to bridges/chains/chain-bridge-hub-cumulus/Cargo.toml index d35eefa1c45..5e14cb052b7 100644 --- a/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-cumulus/Cargo.toml @@ -12,9 +12,9 @@ workspace = true [dependencies] # Bridge Dependencies -bp-polkadot-core = { path = "../polkadot-core", default-features = false } -bp-messages = { path = "../messages", default-features = false } -bp-runtime = { path = "../runtime", default-features = false } +bp-polkadot-core = { path = "../../primitives/polkadot-core", default-features = false } +bp-messages = { path = "../../primitives/messages", default-features = false } +bp-runtime = { path = "../../primitives/runtime", default-features = false } # Substrate Based Dependencies diff --git a/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs b/bridges/chains/chain-bridge-hub-cumulus/src/lib.rs similarity index 100% rename from bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs rename to bridges/chains/chain-bridge-hub-cumulus/src/lib.rs diff --git a/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml b/bridges/chains/chain-bridge-hub-kusama/Cargo.toml similarity index 85% rename from bridges/primitives/chain-bridge-hub-kusama/Cargo.toml rename to bridges/chains/chain-bridge-hub-kusama/Cargo.toml index 8d71b3f5eb7..77bc8e54a9d 100644 --- a/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-kusama/Cargo.toml @@ -13,8 +13,8 @@ workspace = true # Bridge Dependencies bp-bridge-hub-cumulus = { path = "../chain-bridge-hub-cumulus", default-features = false } -bp-runtime = { path = "../runtime", default-features = false } -bp-messages = { path = "../messages", default-features = false } +bp-runtime = { path = "../../primitives/runtime", default-features = false } +bp-messages = { path = "../../primitives/messages", default-features = false } # Substrate Based Dependencies diff --git a/bridges/primitives/chain-bridge-hub-kusama/src/lib.rs b/bridges/chains/chain-bridge-hub-kusama/src/lib.rs similarity index 100% rename from bridges/primitives/chain-bridge-hub-kusama/src/lib.rs rename to bridges/chains/chain-bridge-hub-kusama/src/lib.rs diff --git a/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml b/bridges/chains/chain-bridge-hub-polkadot/Cargo.toml similarity index 85% rename from bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml rename to bridges/chains/chain-bridge-hub-polkadot/Cargo.toml index 4e89e8a5c9a..5d7a3bbcc1d 100644 --- a/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-polkadot/Cargo.toml @@ -14,8 +14,8 @@ workspace = true # Bridge Dependencies bp-bridge-hub-cumulus = { path = "../chain-bridge-hub-cumulus", default-features = false } -bp-runtime = { path = "../runtime", default-features = false } -bp-messages = { path = "../messages", default-features = false } +bp-runtime = { path = "../../primitives/runtime", default-features = false } +bp-messages = { path = "../../primitives/messages", default-features = false } # Substrate Based Dependencies diff --git a/bridges/primitives/chain-bridge-hub-polkadot/src/lib.rs b/bridges/chains/chain-bridge-hub-polkadot/src/lib.rs similarity index 100% rename from bridges/primitives/chain-bridge-hub-polkadot/src/lib.rs rename to bridges/chains/chain-bridge-hub-polkadot/src/lib.rs diff --git a/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml b/bridges/chains/chain-bridge-hub-rococo/Cargo.toml similarity index 85% rename from bridges/primitives/chain-bridge-hub-rococo/Cargo.toml rename to bridges/chains/chain-bridge-hub-rococo/Cargo.toml index 1643d934a98..3966ef72dcb 100644 --- a/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-rococo/Cargo.toml @@ -13,8 +13,8 @@ workspace = true # Bridge Dependencies bp-bridge-hub-cumulus = { path = "../chain-bridge-hub-cumulus", default-features = false } -bp-runtime = { path = "../runtime", default-features = false } -bp-messages = { path = "../messages", default-features = false } +bp-runtime = { path = "../../primitives/runtime", default-features = false } +bp-messages = { path = "../../primitives/messages", default-features = false } # Substrate Based Dependencies diff --git a/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs b/bridges/chains/chain-bridge-hub-rococo/src/lib.rs similarity index 100% rename from bridges/primitives/chain-bridge-hub-rococo/src/lib.rs rename to bridges/chains/chain-bridge-hub-rococo/src/lib.rs diff --git a/bridges/primitives/chain-bridge-hub-westend/Cargo.toml b/bridges/chains/chain-bridge-hub-westend/Cargo.toml similarity index 85% rename from bridges/primitives/chain-bridge-hub-westend/Cargo.toml rename to bridges/chains/chain-bridge-hub-westend/Cargo.toml index 32a7850c539..d35eac8b3fe 100644 --- a/bridges/primitives/chain-bridge-hub-westend/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-westend/Cargo.toml @@ -14,8 +14,8 @@ workspace = true # Bridge Dependencies bp-bridge-hub-cumulus = { path = "../chain-bridge-hub-cumulus", default-features = false } -bp-runtime = { path = "../runtime", default-features = false } -bp-messages = { path = "../messages", default-features = false } +bp-runtime = { path = "../../primitives/runtime", default-features = false } +bp-messages = { path = "../../primitives/messages", default-features = false } # Substrate Based Dependencies diff --git a/bridges/primitives/chain-bridge-hub-westend/src/lib.rs b/bridges/chains/chain-bridge-hub-westend/src/lib.rs similarity index 100% rename from bridges/primitives/chain-bridge-hub-westend/src/lib.rs rename to bridges/chains/chain-bridge-hub-westend/src/lib.rs diff --git a/bridges/primitives/chain-kusama/Cargo.toml b/bridges/chains/chain-kusama/Cargo.toml similarity index 73% rename from bridges/primitives/chain-kusama/Cargo.toml rename to bridges/chains/chain-kusama/Cargo.toml index 0660f346023..4ff4cb46976 100644 --- a/bridges/primitives/chain-kusama/Cargo.toml +++ b/bridges/chains/chain-kusama/Cargo.toml @@ -13,9 +13,9 @@ workspace = true # Bridge Dependencies -bp-header-chain = { path = "../header-chain", default-features = false } -bp-polkadot-core = { path = "../polkadot-core", default-features = false } -bp-runtime = { path = "../runtime", default-features = false } +bp-header-chain = { path = "../../primitives/header-chain", default-features = false } +bp-polkadot-core = { path = "../../primitives/polkadot-core", default-features = false } +bp-runtime = { path = "../../primitives/runtime", default-features = false } # Substrate Based Dependencies diff --git a/bridges/primitives/chain-kusama/src/lib.rs b/bridges/chains/chain-kusama/src/lib.rs similarity index 100% rename from bridges/primitives/chain-kusama/src/lib.rs rename to bridges/chains/chain-kusama/src/lib.rs diff --git a/bridges/primitives/chain-polkadot-bulletin/Cargo.toml b/bridges/chains/chain-polkadot-bulletin/Cargo.toml similarity index 78% rename from bridges/primitives/chain-polkadot-bulletin/Cargo.toml rename to bridges/chains/chain-polkadot-bulletin/Cargo.toml index 15c824fcbdb..d10c4043967 100644 --- a/bridges/primitives/chain-polkadot-bulletin/Cargo.toml +++ b/bridges/chains/chain-polkadot-bulletin/Cargo.toml @@ -15,10 +15,10 @@ scale-info = { version = "2.10.0", default-features = false, features = ["derive # Bridge Dependencies -bp-header-chain = { path = "../header-chain", default-features = false } -bp-messages = { path = "../messages", default-features = false } -bp-polkadot-core = { path = "../polkadot-core", default-features = false } -bp-runtime = { path = "../runtime", default-features = false } +bp-header-chain = { path = "../../primitives/header-chain", default-features = false } +bp-messages = { path = "../../primitives/messages", default-features = false } +bp-polkadot-core = { path = "../../primitives/polkadot-core", default-features = false } +bp-runtime = { path = "../../primitives/runtime", default-features = false } # Substrate Based Dependencies diff --git a/bridges/primitives/chain-polkadot-bulletin/src/lib.rs b/bridges/chains/chain-polkadot-bulletin/src/lib.rs similarity index 100% rename from bridges/primitives/chain-polkadot-bulletin/src/lib.rs rename to bridges/chains/chain-polkadot-bulletin/src/lib.rs diff --git a/bridges/primitives/chain-polkadot/Cargo.toml b/bridges/chains/chain-polkadot/Cargo.toml similarity index 73% rename from bridges/primitives/chain-polkadot/Cargo.toml rename to bridges/chains/chain-polkadot/Cargo.toml index 6421b7f4010..0db6791f66e 100644 --- a/bridges/primitives/chain-polkadot/Cargo.toml +++ b/bridges/chains/chain-polkadot/Cargo.toml @@ -13,9 +13,9 @@ workspace = true # Bridge Dependencies -bp-header-chain = { path = "../header-chain", default-features = false } -bp-polkadot-core = { path = "../polkadot-core", default-features = false } -bp-runtime = { path = "../runtime", default-features = false } +bp-header-chain = { path = "../../primitives/header-chain", default-features = false } +bp-polkadot-core = { path = "../../primitives/polkadot-core", default-features = false } +bp-runtime = { path = "../../primitives/runtime", default-features = false } # Substrate Based Dependencies diff --git a/bridges/primitives/chain-polkadot/src/lib.rs b/bridges/chains/chain-polkadot/src/lib.rs similarity index 100% rename from bridges/primitives/chain-polkadot/src/lib.rs rename to bridges/chains/chain-polkadot/src/lib.rs diff --git a/bridges/primitives/chain-rococo/Cargo.toml b/bridges/chains/chain-rococo/Cargo.toml similarity index 73% rename from bridges/primitives/chain-rococo/Cargo.toml rename to bridges/chains/chain-rococo/Cargo.toml index de373f0ae64..9c63f960ae4 100644 --- a/bridges/primitives/chain-rococo/Cargo.toml +++ b/bridges/chains/chain-rococo/Cargo.toml @@ -13,9 +13,9 @@ workspace = true # Bridge Dependencies -bp-header-chain = { path = "../header-chain", default-features = false } -bp-polkadot-core = { path = "../polkadot-core", default-features = false } -bp-runtime = { path = "../runtime", default-features = false } +bp-header-chain = { path = "../../primitives/header-chain", default-features = false } +bp-polkadot-core = { path = "../../primitives/polkadot-core", default-features = false } +bp-runtime = { path = "../../primitives/runtime", default-features = false } # Substrate Based Dependencies diff --git a/bridges/primitives/chain-rococo/src/lib.rs b/bridges/chains/chain-rococo/src/lib.rs similarity index 100% rename from bridges/primitives/chain-rococo/src/lib.rs rename to bridges/chains/chain-rococo/src/lib.rs diff --git a/bridges/primitives/chain-westend/Cargo.toml b/bridges/chains/chain-westend/Cargo.toml similarity index 73% rename from bridges/primitives/chain-westend/Cargo.toml rename to bridges/chains/chain-westend/Cargo.toml index e55a8d649a8..f5de9b95c82 100644 --- a/bridges/primitives/chain-westend/Cargo.toml +++ b/bridges/chains/chain-westend/Cargo.toml @@ -13,9 +13,9 @@ workspace = true # Bridge Dependencies -bp-header-chain = { path = "../header-chain", default-features = false } -bp-polkadot-core = { path = "../polkadot-core", default-features = false } -bp-runtime = { path = "../runtime", default-features = false } +bp-header-chain = { path = "../../primitives/header-chain", default-features = false } +bp-polkadot-core = { path = "../../primitives/polkadot-core", default-features = false } +bp-runtime = { path = "../../primitives/runtime", default-features = false } # Substrate Based Dependencies diff --git a/bridges/primitives/chain-westend/src/lib.rs b/bridges/chains/chain-westend/src/lib.rs similarity index 100% rename from bridges/primitives/chain-westend/src/lib.rs rename to bridges/chains/chain-westend/src/lib.rs diff --git a/bridges/snowbridge/pallets/ethereum-client/Cargo.toml b/bridges/snowbridge/pallets/ethereum-client/Cargo.toml index c8999633c97..cadd542432e 100644 --- a/bridges/snowbridge/pallets/ethereum-client/Cargo.toml +++ b/bridges/snowbridge/pallets/ethereum-client/Cargo.toml @@ -36,7 +36,7 @@ sp-io = { path = "../../../../substrate/primitives/io", default-features = false snowbridge-core = { path = "../../primitives/core", default-features = false } snowbridge-ethereum = { path = "../../primitives/ethereum", default-features = false } -snowbridge-pallet-ethereum-client-fixtures = { path = "./fixtures", default-features = false, optional = true } +snowbridge-pallet-ethereum-client-fixtures = { path = "fixtures", default-features = false, optional = true } primitives = { package = "snowbridge-beacon-primitives", path = "../../primitives/beacon", default-features = false } static_assertions = { version = "1.1.0", default-features = false } bp-runtime = { path = "../../../primitives/runtime", default-features = false } @@ -48,7 +48,7 @@ sp-keyring = { path = "../../../../substrate/primitives/keyring" } serde_json = { workspace = true, default-features = true } hex-literal = "0.4.1" pallet-timestamp = { path = "../../../../substrate/frame/timestamp" } -snowbridge-pallet-ethereum-client-fixtures = { path = "./fixtures" } +snowbridge-pallet-ethereum-client-fixtures = { path = "fixtures" } sp-io = { path = "../../../../substrate/primitives/io" } serde = { workspace = true, default-features = true } diff --git a/bridges/snowbridge/pallets/inbound-queue/Cargo.toml b/bridges/snowbridge/pallets/inbound-queue/Cargo.toml index b850496cd4e..9fc1f31fbf7 100644 --- a/bridges/snowbridge/pallets/inbound-queue/Cargo.toml +++ b/bridges/snowbridge/pallets/inbound-queue/Cargo.toml @@ -42,7 +42,7 @@ snowbridge-core = { path = "../../primitives/core", default-features = false } snowbridge-ethereum = { path = "../../primitives/ethereum", default-features = false } snowbridge-router-primitives = { path = "../../primitives/router", default-features = false } snowbridge-beacon-primitives = { path = "../../primitives/beacon", default-features = false } -snowbridge-pallet-inbound-queue-fixtures = { path = "./fixtures", default-features = false, optional = true } +snowbridge-pallet-inbound-queue-fixtures = { path = "fixtures", default-features = false, optional = true } [dev-dependencies] frame-benchmarking = { path = "../../../../substrate/frame/benchmarking" } diff --git a/cumulus/client/consensus/aura/Cargo.toml b/cumulus/client/consensus/aura/Cargo.toml index e815e89d8ce..58bb1dd5914 100644 --- a/cumulus/client/consensus/aura/Cargo.toml +++ b/cumulus/client/consensus/aura/Cargo.toml @@ -41,7 +41,7 @@ substrate-prometheus-endpoint = { path = "../../../../substrate/utils/prometheus cumulus-client-consensus-common = { path = "../common" } cumulus-relay-chain-interface = { path = "../../relay-chain-interface" } cumulus-client-consensus-proposer = { path = "../proposer" } -cumulus-client-parachain-inherent = { path = "../../../client/parachain-inherent" } +cumulus-client-parachain-inherent = { path = "../../parachain-inherent" } cumulus-primitives-aura = { path = "../../../primitives/aura" } cumulus-primitives-core = { path = "../../../primitives/core" } cumulus-client-collator = { path = "../../collator" } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml index f4f8b3603ba..98762beb0cb 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml @@ -17,7 +17,7 @@ sp-core = { path = "../../../../../../../../substrate/primitives/core", default- frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } # Cumulus -parachains-common = { path = "../../../../../../../parachains/common" } +parachains-common = { path = "../../../../../../common" } cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } emulated-integration-tests-common = { path = "../../../../common", default-features = false } asset-hub-rococo-runtime = { path = "../../../../../../runtimes/assets/asset-hub-rococo" } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml index d4764f63bf6..a42a9abf618 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml @@ -17,7 +17,7 @@ sp-core = { path = "../../../../../../../../substrate/primitives/core", default- frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } # Cumulus -parachains-common = { path = "../../../../../../../parachains/common" } +parachains-common = { path = "../../../../../../common" } cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } emulated-integration-tests-common = { path = "../../../../common", default-features = false } asset-hub-westend-runtime = { path = "../../../../../../runtimes/assets/asset-hub-westend" } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/Cargo.toml index 322d8b44e6e..789f10a35f2 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/Cargo.toml @@ -17,7 +17,7 @@ sp-core = { path = "../../../../../../../../substrate/primitives/core", default- frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } # Cumulus -parachains-common = { path = "../../../../../../../parachains/common" } +parachains-common = { path = "../../../../../../common" } emulated-integration-tests-common = { path = "../../../../common", default-features = false } bridge-hub-rococo-runtime = { path = "../../../../../../runtimes/bridge-hubs/bridge-hub-rococo" } bridge-hub-common = { path = "../../../../../../runtimes/bridge-hubs/common", default-features = false } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/Cargo.toml index ec1386b7f6e..d82971cf55a 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/Cargo.toml @@ -17,7 +17,7 @@ sp-core = { path = "../../../../../../../../substrate/primitives/core", default- frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } # Cumulus -parachains-common = { path = "../../../../../../../parachains/common" } +parachains-common = { path = "../../../../../../common" } emulated-integration-tests-common = { path = "../../../../common", default-features = false } bridge-hub-westend-runtime = { path = "../../../../../../runtimes/bridge-hubs/bridge-hub-westend" } bridge-hub-common = { path = "../../../../../../runtimes/bridge-hubs/common", default-features = false } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/Cargo.toml index 03f755b666a..4c2a7d3c274 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/Cargo.toml @@ -17,7 +17,7 @@ sp-core = { path = "../../../../../../../../substrate/primitives/core", default- frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } # Cumulus -parachains-common = { path = "../../../../../../../parachains/common" } +parachains-common = { path = "../../../../../../common" } cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } emulated-integration-tests-common = { path = "../../../../common", default-features = false } collectives-westend-runtime = { path = "../../../../../../runtimes/collectives/collectives-westend" } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-rococo/Cargo.toml index 65a358d0ef2..f7fe93d2777 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-rococo/Cargo.toml @@ -14,7 +14,7 @@ sp-core = { path = "../../../../../../../../substrate/primitives/core", default- frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } # Cumulus -parachains-common = { path = "../../../../../../../parachains/common" } +parachains-common = { path = "../../../../../../common" } cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } emulated-integration-tests-common = { path = "../../../../common", default-features = false } people-rococo-runtime = { path = "../../../../../../runtimes/people/people-rococo" } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend/Cargo.toml index 075698848bc..57a767e0c2a 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend/Cargo.toml @@ -14,7 +14,7 @@ sp-core = { path = "../../../../../../../../substrate/primitives/core", default- frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } # Cumulus -parachains-common = { path = "../../../../../../../parachains/common" } +parachains-common = { path = "../../../../../../common" } cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } emulated-integration-tests-common = { path = "../../../../common", default-features = false } people-westend-runtime = { path = "../../../../../../runtimes/people/people-westend" } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml index f47350b00eb..2ac508273c6 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml @@ -20,7 +20,7 @@ frame-support = { path = "../../../../../../../../substrate/frame/support", defa xcm = { package = "staging-xcm", path = "../../../../../../../../polkadot/xcm", default-features = false } # Cumulus -parachains-common = { path = "../../../../../../../parachains/common" } +parachains-common = { path = "../../../../../../common" } cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } emulated-integration-tests-common = { path = "../../../../common", default-features = false } penpal-runtime = { path = "../../../../../../runtimes/testing/penpal" } diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml index 2d27426cca7..7ac65b0ee1d 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml @@ -25,5 +25,5 @@ rococo-runtime-constants = { path = "../../../../../../../polkadot/runtime/rococ rococo-runtime = { path = "../../../../../../../polkadot/runtime/rococo" } # Cumulus -parachains-common = { path = "../../../../../../parachains/common" } +parachains-common = { path = "../../../../../common" } emulated-integration-tests-common = { path = "../../../common", default-features = false } diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml index abc40c20406..20aedb50e6a 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml @@ -27,5 +27,5 @@ westend-runtime-constants = { path = "../../../../../../../polkadot/runtime/west westend-runtime = { path = "../../../../../../../polkadot/runtime/westend" } # Cumulus -parachains-common = { path = "../../../../../../parachains/common" } +parachains-common = { path = "../../../../../common" } emulated-integration-tests-common = { path = "../../../common", default-features = false } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml index 13eb7d8dfc4..9b519da4b1d 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml @@ -30,7 +30,7 @@ rococo-runtime = { path = "../../../../../../../polkadot/runtime/rococo" } # Cumulus asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" } -parachains-common = { path = "../../../../../../parachains/common" } +parachains-common = { path = "../../../../../common" } cumulus-pallet-parachain-system = { path = "../../../../../../pallets/parachain-system", default-features = false } testnet-parachains-constants = { path = "../../../../../runtimes/constants", features = ["rococo"] } asset-hub-rococo-runtime = { path = "../../../../../runtimes/assets/asset-hub-rococo" } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml index 8ac8efb5218..3121ed028eb 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml @@ -31,12 +31,12 @@ pallet-xcm = { path = "../../../../../../../polkadot/xcm/pallet-xcm", default-fe westend-runtime = { path = "../../../../../../../polkadot/runtime/westend" } # Cumulus -parachains-common = { path = "../../../../../../parachains/common" } +parachains-common = { path = "../../../../../common" } testnet-parachains-constants = { path = "../../../../../runtimes/constants", features = ["westend"] } penpal-runtime = { path = "../../../../../runtimes/testing/penpal" } asset-hub-westend-runtime = { path = "../../../../../runtimes/assets/asset-hub-westend" } asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" } -cumulus-pallet-xcmp-queue = { default-features = false, path = "../../../../../../pallets/xcmp-queue" } -cumulus-pallet-parachain-system = { default-features = false, path = "../../../../../../pallets/parachain-system" } +cumulus-pallet-xcmp-queue = { path = "../../../../../../pallets/xcmp-queue", default-features = false } +cumulus-pallet-parachain-system = { path = "../../../../../../pallets/parachain-system", default-features = false } emulated-integration-tests-common = { path = "../../../common", default-features = false } westend-system-emulated-network = { path = "../../../networks/westend-system" } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml index 89f0d2a9ca6..18c39f895fa 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml @@ -34,10 +34,10 @@ pallet-bridge-messages = { path = "../../../../../../../bridges/modules/messages bp-messages = { path = "../../../../../../../bridges/primitives/messages", default-features = false } # Cumulus -parachains-common = { path = "../../../../../../parachains/common" } +parachains-common = { path = "../../../../../common" } testnet-parachains-constants = { path = "../../../../../runtimes/constants", features = ["rococo"] } cumulus-pallet-xcmp-queue = { path = "../../../../../../pallets/xcmp-queue", default-features = false } -bridge-hub-rococo-runtime = { path = "../../../../../../parachains/runtimes/bridge-hubs/bridge-hub-rococo", default-features = false } +bridge-hub-rococo-runtime = { path = "../../../../../runtimes/bridge-hubs/bridge-hub-rococo", default-features = false } emulated-integration-tests-common = { path = "../../../common", default-features = false } rococo-westend-system-emulated-network = { path = "../../../networks/rococo-westend-system" } rococo-system-emulated-network = { path = "../../../networks/rococo-system" } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml index 9d55903c858..9059d841a48 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml @@ -30,8 +30,8 @@ pallet-bridge-messages = { path = "../../../../../../../bridges/modules/messages bp-messages = { path = "../../../../../../../bridges/primitives/messages", default-features = false } # Cumulus -parachains-common = { path = "../../../../../../parachains/common" } +parachains-common = { path = "../../../../../common" } cumulus-pallet-xcmp-queue = { path = "../../../../../../pallets/xcmp-queue", default-features = false } -bridge-hub-westend-runtime = { path = "../../../../../../parachains/runtimes/bridge-hubs/bridge-hub-westend", default-features = false } +bridge-hub-westend-runtime = { path = "../../../../../runtimes/bridge-hubs/bridge-hub-westend", default-features = false } emulated-integration-tests-common = { path = "../../../common", default-features = false } rococo-westend-system-emulated-network = { path = "../../../networks/rococo-westend-system" } diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/Cargo.toml index 609376c1fee..1570aa7662f 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/Cargo.toml @@ -26,7 +26,7 @@ polkadot-runtime-common = { path = "../../../../../../../polkadot/runtime/common # Cumulus asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" } -parachains-common = { path = "../../../../../../parachains/common" } +parachains-common = { path = "../../../../../common" } people-rococo-runtime = { path = "../../../../../runtimes/people/people-rococo" } emulated-integration-tests-common = { path = "../../../common", default-features = false } rococo-system-emulated-network = { path = "../../../networks/rococo-system" } diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/Cargo.toml index f2f3366798a..bc093dc0de6 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/Cargo.toml @@ -26,7 +26,7 @@ polkadot-runtime-common = { path = "../../../../../../../polkadot/runtime/common # Cumulus asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" } -parachains-common = { path = "../../../../../../parachains/common" } +parachains-common = { path = "../../../../../common" } people-westend-runtime = { path = "../../../../../runtimes/people/people-westend" } emulated-integration-tests-common = { path = "../../../common", default-features = false } westend-system-emulated-network = { path = "../../../networks/westend-system" } diff --git a/cumulus/parachains/pallets/collective-content/Cargo.toml b/cumulus/parachains/pallets/collective-content/Cargo.toml index 691be02f5b8..d4290dd2de2 100644 --- a/cumulus/parachains/pallets/collective-content/Cargo.toml +++ b/cumulus/parachains/pallets/collective-content/Cargo.toml @@ -13,7 +13,7 @@ workspace = true codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -frame-benchmarking = { path = "../../../../substrate/frame/benchmarking", optional = true, default-features = false } +frame-benchmarking = { path = "../../../../substrate/frame/benchmarking", default-features = false, optional = true } frame-support = { path = "../../../../substrate/frame/support", default-features = false } frame-system = { path = "../../../../substrate/frame/system", default-features = false } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index 95691a045b7..53abb620022 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -86,10 +86,10 @@ assets-common = { path = "../common", default-features = false } # Bridges pallet-xcm-bridge-hub-router = { path = "../../../../../bridges/modules/xcm-bridge-hub-router", default-features = false } -bp-asset-hub-rococo = { path = "../../../../../bridges/primitives/chain-asset-hub-rococo", default-features = false } -bp-asset-hub-westend = { path = "../../../../../bridges/primitives/chain-asset-hub-westend", default-features = false } -bp-bridge-hub-rococo = { path = "../../../../../bridges/primitives/chain-bridge-hub-rococo", default-features = false } -bp-bridge-hub-westend = { path = "../../../../../bridges/primitives/chain-bridge-hub-westend", default-features = false } +bp-asset-hub-rococo = { path = "../../../../../bridges/chains/chain-asset-hub-rococo", default-features = false } +bp-asset-hub-westend = { path = "../../../../../bridges/chains/chain-asset-hub-westend", default-features = false } +bp-bridge-hub-rococo = { path = "../../../../../bridges/chains/chain-bridge-hub-rococo", default-features = false } +bp-bridge-hub-westend = { path = "../../../../../bridges/chains/chain-bridge-hub-westend", default-features = false } snowbridge-router-primitives = { path = "../../../../../bridges/snowbridge/primitives/router", default-features = false } [dev-dependencies] diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index 950c6e62d72..0f8a1182cd7 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -84,10 +84,10 @@ assets-common = { path = "../common", default-features = false } # Bridges pallet-xcm-bridge-hub-router = { path = "../../../../../bridges/modules/xcm-bridge-hub-router", default-features = false } -bp-asset-hub-rococo = { path = "../../../../../bridges/primitives/chain-asset-hub-rococo", default-features = false } -bp-asset-hub-westend = { path = "../../../../../bridges/primitives/chain-asset-hub-westend", default-features = false } -bp-bridge-hub-rococo = { path = "../../../../../bridges/primitives/chain-bridge-hub-rococo", default-features = false } -bp-bridge-hub-westend = { path = "../../../../../bridges/primitives/chain-bridge-hub-westend", default-features = false } +bp-asset-hub-rococo = { path = "../../../../../bridges/chains/chain-asset-hub-rococo", default-features = false } +bp-asset-hub-westend = { path = "../../../../../bridges/chains/chain-asset-hub-westend", default-features = false } +bp-bridge-hub-rococo = { path = "../../../../../bridges/chains/chain-bridge-hub-rococo", default-features = false } +bp-bridge-hub-westend = { path = "../../../../../bridges/chains/chain-bridge-hub-westend", default-features = false } [dev-dependencies] hex-literal = "0.4.1" diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml index 8a6823ea3ee..13b4b624eef 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -85,20 +85,20 @@ parachains-common = { path = "../../../common", default-features = false } testnet-parachains-constants = { path = "../../constants", default-features = false, features = ["rococo"] } # Bridges -bp-asset-hub-rococo = { path = "../../../../../bridges/primitives/chain-asset-hub-rococo", default-features = false } -bp-asset-hub-westend = { path = "../../../../../bridges/primitives/chain-asset-hub-westend", default-features = false } -bp-bridge-hub-polkadot = { path = "../../../../../bridges/primitives/chain-bridge-hub-polkadot", default-features = false } -bp-bridge-hub-rococo = { path = "../../../../../bridges/primitives/chain-bridge-hub-rococo", default-features = false } -bp-bridge-hub-westend = { path = "../../../../../bridges/primitives/chain-bridge-hub-westend", default-features = false } +bp-asset-hub-rococo = { path = "../../../../../bridges/chains/chain-asset-hub-rococo", default-features = false } +bp-asset-hub-westend = { path = "../../../../../bridges/chains/chain-asset-hub-westend", default-features = false } +bp-bridge-hub-polkadot = { path = "../../../../../bridges/chains/chain-bridge-hub-polkadot", default-features = false } +bp-bridge-hub-rococo = { path = "../../../../../bridges/chains/chain-bridge-hub-rococo", default-features = false } +bp-bridge-hub-westend = { path = "../../../../../bridges/chains/chain-bridge-hub-westend", default-features = false } bp-header-chain = { path = "../../../../../bridges/primitives/header-chain", default-features = false } bp-messages = { path = "../../../../../bridges/primitives/messages", default-features = false } bp-parachains = { path = "../../../../../bridges/primitives/parachains", default-features = false } -bp-polkadot-bulletin = { path = "../../../../../bridges/primitives/chain-polkadot-bulletin", default-features = false } +bp-polkadot-bulletin = { path = "../../../../../bridges/chains/chain-polkadot-bulletin", default-features = false } bp-polkadot-core = { path = "../../../../../bridges/primitives/polkadot-core", default-features = false } bp-relayers = { path = "../../../../../bridges/primitives/relayers", default-features = false } bp-runtime = { path = "../../../../../bridges/primitives/runtime", default-features = false } -bp-rococo = { path = "../../../../../bridges/primitives/chain-rococo", default-features = false } -bp-westend = { path = "../../../../../bridges/primitives/chain-westend", default-features = false } +bp-rococo = { path = "../../../../../bridges/chains/chain-rococo", default-features = false } +bp-westend = { path = "../../../../../bridges/chains/chain-westend", default-features = false } pallet-bridge-grandpa = { path = "../../../../../bridges/modules/grandpa", default-features = false } pallet-bridge-messages = { path = "../../../../../bridges/modules/messages", default-features = false } pallet-bridge-parachains = { path = "../../../../../bridges/modules/parachains", default-features = false } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml index 4eb201eedc1..0c46e6c2e14 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -77,25 +77,25 @@ parachains-common = { path = "../../../common", default-features = false } testnet-parachains-constants = { path = "../../constants", default-features = false, features = ["westend"] } # Bridges -bp-asset-hub-rococo = { path = "../../../../../bridges/primitives/chain-asset-hub-rococo", default-features = false } -bp-asset-hub-westend = { path = "../../../../../bridges/primitives/chain-asset-hub-westend", default-features = false } -bp-bridge-hub-rococo = { path = "../../../../../bridges/primitives/chain-bridge-hub-rococo", default-features = false } -bp-bridge-hub-westend = { path = "../../../../../bridges/primitives/chain-bridge-hub-westend", default-features = false } +bp-asset-hub-rococo = { path = "../../../../../bridges/chains/chain-asset-hub-rococo", default-features = false } +bp-asset-hub-westend = { path = "../../../../../bridges/chains/chain-asset-hub-westend", default-features = false } +bp-bridge-hub-rococo = { path = "../../../../../bridges/chains/chain-bridge-hub-rococo", default-features = false } +bp-bridge-hub-westend = { path = "../../../../../bridges/chains/chain-bridge-hub-westend", default-features = false } bp-header-chain = { path = "../../../../../bridges/primitives/header-chain", default-features = false } bp-messages = { path = "../../../../../bridges/primitives/messages", default-features = false } bp-parachains = { path = "../../../../../bridges/primitives/parachains", default-features = false } bp-polkadot-core = { path = "../../../../../bridges/primitives/polkadot-core", default-features = false } bp-relayers = { path = "../../../../../bridges/primitives/relayers", default-features = false } bp-runtime = { path = "../../../../../bridges/primitives/runtime", default-features = false } -bp-rococo = { path = "../../../../../bridges/primitives/chain-rococo", default-features = false } -bp-westend = { path = "../../../../../bridges/primitives/chain-westend", default-features = false } +bp-rococo = { path = "../../../../../bridges/chains/chain-rococo", default-features = false } +bp-westend = { path = "../../../../../bridges/chains/chain-westend", default-features = false } pallet-bridge-grandpa = { path = "../../../../../bridges/modules/grandpa", default-features = false } pallet-bridge-messages = { path = "../../../../../bridges/modules/messages", default-features = false } pallet-bridge-parachains = { path = "../../../../../bridges/modules/parachains", default-features = false } pallet-bridge-relayers = { path = "../../../../../bridges/modules/relayers", default-features = false } pallet-xcm-bridge-hub = { path = "../../../../../bridges/modules/xcm-bridge-hub", default-features = false } bridge-runtime-common = { path = "../../../../../bridges/bin/runtime-common", default-features = false } -bridge-hub-common = { path = "../../bridge-hubs/common", default-features = false } +bridge-hub-common = { path = "../common", default-features = false } [dev-dependencies] static_assertions = "1.1" diff --git a/cumulus/primitives/storage-weight-reclaim/Cargo.toml b/cumulus/primitives/storage-weight-reclaim/Cargo.toml index 4835fb5192b..73e0f03cd37 100644 --- a/cumulus/primitives/storage-weight-reclaim/Cargo.toml +++ b/cumulus/primitives/storage-weight-reclaim/Cargo.toml @@ -20,8 +20,8 @@ frame-system = { path = "../../../substrate/frame/system", default-features = fa sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } sp-std = { path = "../../../substrate/primitives/std", default-features = false } -cumulus-primitives-core = { path = "../../primitives/core", default-features = false } -cumulus-primitives-proof-size-hostfunction = { path = "../../primitives/proof-size-hostfunction", default-features = false } +cumulus-primitives-core = { path = "../core", default-features = false } +cumulus-primitives-proof-size-hostfunction = { path = "../proof-size-hostfunction", default-features = false } docify = "0.2.7" [dev-dependencies] diff --git a/polkadot/Cargo.toml b/polkadot/Cargo.toml index b0d71a18eaa..883568b23f7 100644 --- a/polkadot/Cargo.toml +++ b/polkadot/Cargo.toml @@ -46,7 +46,7 @@ assert_cmd = "2.0.4" nix = { version = "0.26.1", features = ["signal"] } tempfile = "3.2.0" tokio = "1.24.2" -substrate-rpc-client = { path = "../substrate/utils/frame/rpc/client/" } +substrate-rpc-client = { path = "../substrate/utils/frame/rpc/client" } polkadot-core-primitives = { path = "core-primitives" } [build-dependencies] diff --git a/polkadot/node/core/pvf/Cargo.toml b/polkadot/node/core/pvf/Cargo.toml index 9ed64b88ffd..6ad36a39be6 100644 --- a/polkadot/node/core/pvf/Cargo.toml +++ b/polkadot/node/core/pvf/Cargo.toml @@ -50,7 +50,7 @@ hex-literal = "0.4.1" polkadot-node-core-pvf-common = { path = "common", features = ["test-utils"] } # For benches and integration tests, depend on ourselves with the test-utils # feature. -polkadot-node-core-pvf = { path = ".", features = ["test-utils"] } +polkadot-node-core-pvf = { path = "", features = ["test-utils"] } rococo-runtime = { path = "../../../runtime/rococo" } adder = { package = "test-parachain-adder", path = "../../../parachain/test-parachains/adder" } diff --git a/templates/solochain/runtime/Cargo.toml b/templates/solochain/runtime/Cargo.toml index 33da035878a..90dd823eb64 100644 --- a/templates/solochain/runtime/Cargo.toml +++ b/templates/solochain/runtime/Cargo.toml @@ -62,7 +62,7 @@ sp-transaction-pool = { path = "../../../substrate/primitives/transaction-pool", sp-version = { path = "../../../substrate/primitives/version", default-features = false, features = [ "serde", ] } -sp-genesis-builder = { default-features = false, path = "../../../substrate/primitives/genesis-builder" } +sp-genesis-builder = { path = "../../../substrate/primitives/genesis-builder", default-features = false } # RPC related frame-system-rpc-runtime-api = { path = "../../../substrate/frame/system/rpc/runtime-api", default-features = false } -- GitLab From c6f7ccf51a54d0272643b2beaeab7458df8492e0 Mon Sep 17 00:00:00 2001 From: Alin Dima Date: Mon, 25 Mar 2024 15:38:13 +0200 Subject: [PATCH 090/187] elastic scaling: preserve candidate ordering in provisioner (#3778) https://github.com/paritytech/polkadot-sdk/issues/3742 --- polkadot/node/core/backing/src/error.rs | 6 +- polkadot/node/core/backing/src/lib.rs | 32 +- polkadot/node/core/backing/src/tests/mod.rs | 343 +++++++++++++++++- polkadot/node/core/provisioner/src/lib.rs | 61 ++-- polkadot/node/core/provisioner/src/tests.rs | 176 +++++++-- polkadot/node/overseer/src/tests.rs | 2 +- polkadot/node/subsystem-types/src/messages.rs | 11 +- .../src/types/overseer-protocol.md | 12 +- 8 files changed, 569 insertions(+), 74 deletions(-) diff --git a/polkadot/node/core/backing/src/error.rs b/polkadot/node/core/backing/src/error.rs index 64955a39396..52684f3fe30 100644 --- a/polkadot/node/core/backing/src/error.rs +++ b/polkadot/node/core/backing/src/error.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +use std::collections::HashMap; + use fatality::Nested; use futures::channel::{mpsc, oneshot}; @@ -24,7 +26,7 @@ use polkadot_node_subsystem::{ use polkadot_node_subsystem_util::{runtime, Error as UtilError}; use polkadot_primitives::{BackedCandidate, ValidationCodeHash}; -use crate::LOG_TARGET; +use crate::{ParaId, LOG_TARGET}; pub type Result = std::result::Result; pub type FatalResult = std::result::Result; @@ -55,7 +57,7 @@ pub enum Error { InvalidSignature, #[error("Failed to send candidates {0:?}")] - Send(Vec), + Send(HashMap>), #[error("FetchPoV failed")] FetchPoV, diff --git a/polkadot/node/core/backing/src/lib.rs b/polkadot/node/core/backing/src/lib.rs index 69bf2e956a0..532ae2bd7cb 100644 --- a/polkadot/node/core/backing/src/lib.rs +++ b/polkadot/node/core/backing/src/lib.rs @@ -2231,15 +2231,16 @@ async fn handle_statement_message( fn handle_get_backed_candidates_message( state: &State, - requested_candidates: Vec<(CandidateHash, Hash)>, - tx: oneshot::Sender>, + requested_candidates: HashMap>, + tx: oneshot::Sender>>, metrics: &Metrics, ) -> Result<(), Error> { let _timer = metrics.time_get_backed_candidates(); - let backed = requested_candidates - .into_iter() - .filter_map(|(candidate_hash, relay_parent)| { + let mut backed = HashMap::with_capacity(requested_candidates.len()); + + for (para_id, para_candidates) in requested_candidates { + for (candidate_hash, relay_parent) in para_candidates.iter() { let rp_state = match state.per_relay_parent.get(&relay_parent) { Some(rp_state) => rp_state, None => { @@ -2249,13 +2250,13 @@ fn handle_get_backed_candidates_message( ?candidate_hash, "Requested candidate's relay parent is out of view", ); - return None + break }, }; - rp_state + let maybe_backed_candidate = rp_state .table .attested_candidate( - &candidate_hash, + candidate_hash, &rp_state.table_context, rp_state.minimum_backing_votes, ) @@ -2265,9 +2266,18 @@ fn handle_get_backed_candidates_message( &rp_state.table_context, rp_state.inject_core_index, ) - }) - }) - .collect(); + }); + + if let Some(backed_candidate) = maybe_backed_candidate { + backed + .entry(para_id) + .or_insert_with(|| Vec::with_capacity(para_candidates.len())) + .push(backed_candidate); + } else { + break + } + } + } tx.send(backed).map_err(|data| Error::Send(data))?; Ok(()) diff --git a/polkadot/node/core/backing/src/tests/mod.rs b/polkadot/node/core/backing/src/tests/mod.rs index e3cc5727435..fdb47581ea3 100644 --- a/polkadot/node/core/backing/src/tests/mod.rs +++ b/polkadot/node/core/backing/src/tests/mod.rs @@ -663,13 +663,19 @@ fn backing_works(#[case] elastic_scaling_mvp: bool) { let (tx, rx) = oneshot::channel(); let msg = CandidateBackingMessage::GetBackedCandidates( - vec![(candidate_a_hash, test_state.relay_parent)], + std::iter::once(( + test_state.chain_ids[0], + vec![(candidate_a_hash, test_state.relay_parent)], + )) + .collect(), tx, ); virtual_overseer.send(FromOrchestra::Communication { msg }).await; - let candidates = rx.await.unwrap(); + let mut candidates = rx.await.unwrap(); + assert_eq!(1, candidates.len()); + let candidates = candidates.remove(&test_state.chain_ids[0]).unwrap(); assert_eq!(1, candidates.len()); assert_eq!(candidates[0].validity_votes().len(), 3); @@ -695,6 +701,323 @@ fn backing_works(#[case] elastic_scaling_mvp: bool) { }); } +#[test] +fn get_backed_candidate_preserves_order() { + let mut test_state = TestState::default(); + test_state + .node_features + .resize((node_features::FeatureIndex::ElasticScalingMVP as u8 + 1) as usize, false); + test_state + .node_features + .set(node_features::FeatureIndex::ElasticScalingMVP as u8 as usize, true); + + // Set a single validator as the first validator group. It simplifies the test. + test_state.validator_groups.0[0] = vec![ValidatorIndex(2)]; + // Add another validator group for the third core. + test_state.validator_groups.0.push(vec![ValidatorIndex(3)]); + // Assign the second core to the same para as the first one. + test_state.availability_cores[1] = + CoreState::Scheduled(ScheduledCore { para_id: test_state.chain_ids[0], collator: None }); + // Add another availability core for paraid 2. + test_state.availability_cores.push(CoreState::Scheduled(ScheduledCore { + para_id: test_state.chain_ids[1], + collator: None, + })); + + test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { + test_startup(&mut virtual_overseer, &test_state).await; + + let pov_a = PoV { block_data: BlockData(vec![1, 2, 3]) }; + let pov_b = PoV { block_data: BlockData(vec![3, 4, 5]) }; + let pov_c = PoV { block_data: BlockData(vec![5, 6, 7]) }; + let validation_code_ab = ValidationCode(vec![1, 2, 3]); + let validation_code_c = ValidationCode(vec![4, 5, 6]); + + let parent_head_data_a = test_state.head_data.get(&test_state.chain_ids[0]).unwrap(); + let parent_head_data_b = { + let mut head = parent_head_data_a.clone(); + head.0[0] = 98; + head + }; + let output_head_data_b = { + let mut head = parent_head_data_a.clone(); + head.0[0] = 99; + head + }; + let parent_head_data_c = test_state.head_data.get(&test_state.chain_ids[1]).unwrap(); + let output_head_data_c = { + let mut head = parent_head_data_c.clone(); + head.0[0] = 97; + head + }; + + let pvd_a = PersistedValidationData { + parent_head: parent_head_data_a.clone(), + relay_parent_number: 0_u32.into(), + max_pov_size: 1024, + relay_parent_storage_root: dummy_hash(), + }; + let pvd_b = PersistedValidationData { + parent_head: parent_head_data_b.clone(), + relay_parent_number: 0_u32.into(), + max_pov_size: 1024, + relay_parent_storage_root: dummy_hash(), + }; + let pvd_c = PersistedValidationData { + parent_head: parent_head_data_c.clone(), + relay_parent_number: 0_u32.into(), + max_pov_size: 1024, + relay_parent_storage_root: dummy_hash(), + }; + + let candidate_a = TestCandidateBuilder { + para_id: test_state.chain_ids[0], + relay_parent: test_state.relay_parent, + pov_hash: pov_a.hash(), + head_data: parent_head_data_b.clone(), + erasure_root: make_erasure_root(&test_state, pov_a.clone(), pvd_a.clone()), + validation_code: validation_code_ab.0.clone(), + persisted_validation_data_hash: pvd_a.hash(), + } + .build(); + let candidate_b = TestCandidateBuilder { + para_id: test_state.chain_ids[0], + relay_parent: test_state.relay_parent, + pov_hash: pov_b.hash(), + head_data: output_head_data_b.clone(), + erasure_root: make_erasure_root(&test_state, pov_b.clone(), pvd_b.clone()), + validation_code: validation_code_ab.0.clone(), + persisted_validation_data_hash: pvd_b.hash(), + } + .build(); + let candidate_c = TestCandidateBuilder { + para_id: test_state.chain_ids[1], + relay_parent: test_state.relay_parent, + pov_hash: pov_c.hash(), + head_data: output_head_data_c.clone(), + erasure_root: make_erasure_root(&test_state, pov_b.clone(), pvd_c.clone()), + validation_code: validation_code_c.0.clone(), + persisted_validation_data_hash: pvd_c.hash(), + } + .build(); + let candidate_a_hash = candidate_a.hash(); + let candidate_b_hash = candidate_b.hash(); + let candidate_c_hash = candidate_c.hash(); + + // Back a chain of two candidates for the first paraid. Back one candidate for the second + // paraid. + for (candidate, pvd, validator_index) in [ + (candidate_a, pvd_a, ValidatorIndex(2)), + (candidate_b, pvd_b, ValidatorIndex(1)), + (candidate_c, pvd_c, ValidatorIndex(3)), + ] { + let public = Keystore::sr25519_generate_new( + &*test_state.keystore, + ValidatorId::ID, + Some(&test_state.validators[validator_index.0 as usize].to_seed()), + ) + .expect("Insert key into keystore"); + + let signed = SignedFullStatementWithPVD::sign( + &test_state.keystore, + StatementWithPVD::Seconded(candidate.clone(), pvd.clone()), + &test_state.signing_context, + validator_index, + &public.into(), + ) + .ok() + .flatten() + .expect("should be signed"); + + let statement = + CandidateBackingMessage::Statement(test_state.relay_parent, signed.clone()); + + virtual_overseer.send(FromOrchestra::Communication { msg: statement }).await; + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::Provisioner( + ProvisionerMessage::ProvisionableData( + _, + ProvisionableData::BackedCandidate(candidate_receipt) + ) + ) => { + assert_eq!(candidate_receipt, candidate.to_plain()); + } + ); + } + + // Happy case, all candidates should be present. + let (tx, rx) = oneshot::channel(); + let msg = CandidateBackingMessage::GetBackedCandidates( + [ + ( + test_state.chain_ids[0], + vec![ + (candidate_a_hash, test_state.relay_parent), + (candidate_b_hash, test_state.relay_parent), + ], + ), + (test_state.chain_ids[1], vec![(candidate_c_hash, test_state.relay_parent)]), + ] + .into_iter() + .collect(), + tx, + ); + virtual_overseer.send(FromOrchestra::Communication { msg }).await; + let mut candidates = rx.await.unwrap(); + assert_eq!(2, candidates.len()); + assert_eq!( + candidates + .remove(&test_state.chain_ids[0]) + .unwrap() + .iter() + .map(|c| c.hash()) + .collect::>(), + vec![candidate_a_hash, candidate_b_hash] + ); + assert_eq!( + candidates + .remove(&test_state.chain_ids[1]) + .unwrap() + .iter() + .map(|c| c.hash()) + .collect::>(), + vec![candidate_c_hash] + ); + + // The first candidate of the first para is invalid (we supply the wrong relay parent or a + // wrong candidate hash). No candidates should be returned for paraid 1. ParaId 2 should be + // fine. + for candidates in [ + vec![ + (candidate_a_hash, Hash::repeat_byte(9)), + (candidate_b_hash, test_state.relay_parent), + ], + vec![ + (CandidateHash(Hash::repeat_byte(9)), test_state.relay_parent), + (candidate_b_hash, test_state.relay_parent), + ], + ] { + let (tx, rx) = oneshot::channel(); + let msg = CandidateBackingMessage::GetBackedCandidates( + [ + (test_state.chain_ids[0], candidates), + (test_state.chain_ids[1], vec![(candidate_c_hash, test_state.relay_parent)]), + ] + .into_iter() + .collect(), + tx, + ); + virtual_overseer.send(FromOrchestra::Communication { msg }).await; + let mut candidates = rx.await.unwrap(); + assert_eq!(candidates.len(), 1); + + assert!(candidates.remove(&test_state.chain_ids[0]).is_none()); + assert_eq!( + candidates + .remove(&test_state.chain_ids[1]) + .unwrap() + .iter() + .map(|c| c.hash()) + .collect::>(), + vec![candidate_c_hash] + ); + } + + // The second candidate of the first para is invalid (we supply the wrong relay parent or a + // wrong candidate hash). The first candidate of the first para should still be present. + // ParaId 2 is fine. + for candidates in [ + vec![ + (candidate_a_hash, test_state.relay_parent), + (candidate_b_hash, Hash::repeat_byte(9)), + ], + vec![ + (candidate_a_hash, test_state.relay_parent), + (CandidateHash(Hash::repeat_byte(9)), test_state.relay_parent), + ], + ] { + let (tx, rx) = oneshot::channel(); + let msg = CandidateBackingMessage::GetBackedCandidates( + [ + (test_state.chain_ids[0], candidates), + (test_state.chain_ids[1], vec![(candidate_c_hash, test_state.relay_parent)]), + ] + .into_iter() + .collect(), + tx, + ); + virtual_overseer.send(FromOrchestra::Communication { msg }).await; + let mut candidates = rx.await.unwrap(); + assert_eq!(2, candidates.len()); + assert_eq!( + candidates + .remove(&test_state.chain_ids[0]) + .unwrap() + .iter() + .map(|c| c.hash()) + .collect::>(), + vec![candidate_a_hash] + ); + assert_eq!( + candidates + .remove(&test_state.chain_ids[1]) + .unwrap() + .iter() + .map(|c| c.hash()) + .collect::>(), + vec![candidate_c_hash] + ); + } + + // Both candidates of para id 1 are invalid (we supply the wrong relay parent or a wrong + // candidate hash). No candidates should be returned for para id 1. Para Id 2 is fine. + for candidates in [ + vec![ + (CandidateHash(Hash::repeat_byte(9)), test_state.relay_parent), + (CandidateHash(Hash::repeat_byte(10)), test_state.relay_parent), + ], + vec![ + (candidate_a_hash, Hash::repeat_byte(9)), + (candidate_b_hash, Hash::repeat_byte(10)), + ], + ] { + let (tx, rx) = oneshot::channel(); + let msg = CandidateBackingMessage::GetBackedCandidates( + [ + (test_state.chain_ids[0], candidates), + (test_state.chain_ids[1], vec![(candidate_c_hash, test_state.relay_parent)]), + ] + .into_iter() + .collect(), + tx, + ); + virtual_overseer.send(FromOrchestra::Communication { msg }).await; + let mut candidates = rx.await.unwrap(); + assert_eq!(candidates.len(), 1); + + assert!(candidates.remove(&test_state.chain_ids[0]).is_none()); + assert_eq!( + candidates + .remove(&test_state.chain_ids[1]) + .unwrap() + .iter() + .map(|c| c.hash()) + .collect::>(), + vec![candidate_c_hash] + ); + } + + virtual_overseer + .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( + ActiveLeavesUpdate::stop_work(test_state.relay_parent), + ))) + .await; + virtual_overseer + }); +} + #[test] fn extract_core_index_from_statement_works() { let test_state = TestState::default(); @@ -950,13 +1273,19 @@ fn backing_works_while_validation_ongoing() { let (tx, rx) = oneshot::channel(); let msg = CandidateBackingMessage::GetBackedCandidates( - vec![(candidate_a.hash(), test_state.relay_parent)], + std::iter::once(( + test_state.chain_ids[0], + vec![(candidate_a.hash(), test_state.relay_parent)], + )) + .collect(), tx, ); virtual_overseer.send(FromOrchestra::Communication { msg }).await; - let candidates = rx.await.unwrap(); + let mut candidates = rx.await.unwrap(); + assert_eq!(candidates.len(), 1); + let candidates = candidates.remove(&test_state.chain_ids[0]).unwrap(); assert_eq!(1, candidates.len()); assert_eq!(candidates[0].validity_votes().len(), 3); @@ -1565,7 +1894,11 @@ fn backing_works_after_failed_validation() { // and check that it is still alive. let (tx, rx) = oneshot::channel(); let msg = CandidateBackingMessage::GetBackedCandidates( - vec![(candidate.hash(), test_state.relay_parent)], + std::iter::once(( + test_state.chain_ids[0], + vec![(candidate.hash(), test_state.relay_parent)], + )) + .collect(), tx, ); diff --git a/polkadot/node/core/provisioner/src/lib.rs b/polkadot/node/core/provisioner/src/lib.rs index c9ed873d3c2..3ccf499f325 100644 --- a/polkadot/node/core/provisioner/src/lib.rs +++ b/polkadot/node/core/provisioner/src/lib.rs @@ -46,7 +46,7 @@ use polkadot_primitives::{ BackedCandidate, BlockNumber, CandidateHash, CandidateReceipt, CoreIndex, CoreState, Hash, Id as ParaId, OccupiedCoreAssumption, SessionIndex, SignedAvailabilityBitfield, ValidatorIndex, }; -use std::collections::{BTreeMap, HashMap, HashSet}; +use std::collections::{BTreeMap, HashMap}; mod disputes; mod error; @@ -598,13 +598,11 @@ async fn select_candidate_hashes_from_tracked( candidates: &[CandidateReceipt], relay_parent: Hash, sender: &mut impl overseer::ProvisionerSenderTrait, -) -> Result, Error> { +) -> Result>, Error> { let block_number = get_block_number_under_construction(relay_parent, sender).await?; let mut selected_candidates = - Vec::with_capacity(candidates.len().min(availability_cores.len())); - let mut selected_parachains = - HashSet::with_capacity(candidates.len().min(availability_cores.len())); + HashMap::with_capacity(candidates.len().min(availability_cores.len())); gum::debug!( target: LOG_TARGET, @@ -638,7 +636,7 @@ async fn select_candidate_hashes_from_tracked( CoreState::Free => continue, }; - if selected_parachains.contains(&scheduled_core.para_id) { + if selected_candidates.contains_key(&scheduled_core.para_id) { // We already picked a candidate for this parachain. Elastic scaling only works with // prospective parachains mode. continue @@ -677,8 +675,10 @@ async fn select_candidate_hashes_from_tracked( "Selected candidate receipt", ); - selected_parachains.insert(candidate.descriptor.para_id); - selected_candidates.push((candidate_hash, candidate.descriptor.relay_parent)); + selected_candidates.insert( + candidate.descriptor.para_id, + vec![(candidate_hash, candidate.descriptor.relay_parent)], + ); } } @@ -695,12 +695,12 @@ async fn request_backable_candidates( bitfields: &[SignedAvailabilityBitfield], relay_parent: Hash, sender: &mut impl overseer::ProvisionerSenderTrait, -) -> Result, Error> { +) -> Result>, Error> { let block_number = get_block_number_under_construction(relay_parent, sender).await?; // Record how many cores are scheduled for each paraid. Use a BTreeMap because // we'll need to iterate through them. - let mut scheduled_cores: BTreeMap = BTreeMap::new(); + let mut scheduled_cores_per_para: BTreeMap = BTreeMap::new(); // The on-chain ancestors of a para present in availability-cores. let mut ancestors: HashMap = HashMap::with_capacity(availability_cores.len()); @@ -709,7 +709,7 @@ async fn request_backable_candidates( let core_idx = CoreIndex(core_idx as u32); match core { CoreState::Scheduled(scheduled_core) => { - *scheduled_cores.entry(scheduled_core.para_id).or_insert(0) += 1; + *scheduled_cores_per_para.entry(scheduled_core.para_id).or_insert(0) += 1; }, CoreState::Occupied(occupied_core) => { let is_available = bitfields_indicate_availability( @@ -726,14 +726,14 @@ async fn request_backable_candidates( if let Some(ref scheduled_core) = occupied_core.next_up_on_available { // Request a new backable candidate for the newly scheduled para id. - *scheduled_cores.entry(scheduled_core.para_id).or_insert(0) += 1; + *scheduled_cores_per_para.entry(scheduled_core.para_id).or_insert(0) += 1; } } else if occupied_core.time_out_at <= block_number { // Timed out before being available. if let Some(ref scheduled_core) = occupied_core.next_up_on_time_out { // Candidate's availability timed out, practically same as scheduled. - *scheduled_cores.entry(scheduled_core.para_id).or_insert(0) += 1; + *scheduled_cores_per_para.entry(scheduled_core.para_id).or_insert(0) += 1; } } else { // Not timed out and not available. @@ -747,10 +747,10 @@ async fn request_backable_candidates( }; } - let mut selected_candidates: Vec<(CandidateHash, Hash)> = - Vec::with_capacity(availability_cores.len()); + let mut selected_candidates: HashMap> = + HashMap::with_capacity(scheduled_cores_per_para.len()); - for (para_id, core_count) in scheduled_cores { + for (para_id, core_count) in scheduled_cores_per_para { let para_ancestors = ancestors.remove(¶_id).unwrap_or_default(); // If elastic scaling MVP is disabled, only allow one candidate per parachain. @@ -777,7 +777,7 @@ async fn request_backable_candidates( continue } - selected_candidates.extend(response.into_iter().take(core_count)); + selected_candidates.insert(para_id, response); } Ok(selected_candidates) @@ -826,33 +826,38 @@ async fn select_candidates( selected_candidates.clone(), tx, )); - let mut candidates = rx.await.map_err(|err| Error::CanceledBackedCandidates(err))?; + let candidates = rx.await.map_err(|err| Error::CanceledBackedCandidates(err))?; gum::trace!(target: LOG_TARGET, leaf_hash=?relay_parent, "Got {} backed candidates", candidates.len()); // keep only one candidate with validation code. let mut with_validation_code = false; - candidates.retain(|c| { - if c.candidate().commitments.new_validation_code.is_some() { - if with_validation_code { - return false + // merge the candidates into a common collection, preserving the order + let mut merged_candidates = Vec::with_capacity(availability_cores.len()); + + for para_candidates in candidates.into_values() { + for candidate in para_candidates { + if candidate.candidate().commitments.new_validation_code.is_some() { + if with_validation_code { + break + } else { + with_validation_code = true; + } } - with_validation_code = true; + merged_candidates.push(candidate); } - - true - }); + } gum::debug!( target: LOG_TARGET, - n_candidates = candidates.len(), + n_candidates = merged_candidates.len(), n_cores = availability_cores.len(), ?relay_parent, "Selected backed candidates", ); - Ok(candidates) + Ok(merged_candidates) } /// Produces a block number 1 higher than that of the relay parent diff --git a/polkadot/node/core/provisioner/src/tests.rs b/polkadot/node/core/provisioner/src/tests.rs index bdb4f85f400..823b1d86e46 100644 --- a/polkadot/node/core/provisioner/src/tests.rs +++ b/polkadot/node/core/provisioner/src/tests.rs @@ -258,6 +258,8 @@ mod select_candidates { BlockNumber, CandidateCommitments, CommittedCandidateReceipt, PersistedValidationData, }; use rstest::rstest; + use std::ops::Not; + use CoreState::{Free, Scheduled}; const BLOCK_UNDER_PRODUCTION: BlockNumber = 128; @@ -323,9 +325,6 @@ mod select_candidates { // 11: Occupied(next_up_on_available and available, but different successor para_id) // ] fn mock_availability_cores_one_per_para() -> Vec { - use std::ops::Not; - use CoreState::{Free, Scheduled}; - vec![ // 0: Free, Free, @@ -389,9 +388,6 @@ mod select_candidates { // For test purposes with multiple possible cores assigned to a para, we always return this set // of availability cores: fn mock_availability_cores_multiple_per_para() -> Vec { - use std::ops::Not; - use CoreState::{Free, Scheduled}; - vec![ // 0: Free, Free, @@ -562,7 +558,10 @@ mod select_candidates { use ChainApiMessage::BlockNumber; use RuntimeApiMessage::Request; - let mut backed_iter = expected.clone().into_iter(); + let mut backed = expected.clone().into_iter().fold(HashMap::new(), |mut acc, candidate| { + acc.entry(candidate.descriptor().para_id).or_insert(vec![]).push(candidate); + acc + }); expected.sort_by_key(|c| c.candidate().descriptor.para_id); let mut candidates_iter = expected @@ -583,11 +582,30 @@ mod select_candidates { hashes, sender, )) => { - let response: Vec = - backed_iter.by_ref().take(hashes.len()).collect(); - let expected_hashes: Vec<(CandidateHash, Hash)> = response + let mut response: HashMap> = HashMap::new(); + for (para_id, requested_candidates) in hashes.clone() { + response.insert( + para_id, + backed + .get_mut(¶_id) + .unwrap() + .drain(0..requested_candidates.len()) + .collect(), + ); + } + let expected_hashes: HashMap> = response .iter() - .map(|candidate| (candidate.hash(), candidate.descriptor().relay_parent)) + .map(|(para_id, candidates)| { + ( + *para_id, + candidates + .iter() + .map(|candidate| { + (candidate.hash(), candidate.descriptor().relay_parent) + }) + .collect(), + ) + }) .collect(); assert_eq!(expected_hashes, hashes); @@ -768,7 +786,7 @@ mod select_candidates { #[rstest] #[case(ProspectiveParachainsMode::Disabled)] #[case(ProspectiveParachainsMode::Enabled {max_candidate_depth: 0, allowed_ancestry_len: 0})] - fn selects_max_one_code_upgrade( + fn selects_max_one_code_upgrade_one_core_per_para( #[case] prospective_parachains_mode: ProspectiveParachainsMode, ) { let mock_cores = mock_availability_cores_one_per_para(); @@ -780,7 +798,12 @@ mod select_candidates { let cores = [1, 4, 7, 8, 10, 12]; let cores_with_code = [1, 4, 8]; - let expected_cores = [1, 7, 10, 12]; + // We can't be sure which one code upgrade the provisioner will pick. We can only assert + // that it only picks one. These are the possible cores for which the provisioner will + // supply candidates. + // There are multiple possibilities depending on which code upgrade it + // chooses. + let possible_expected_cores = [[1, 7, 10, 12], [4, 7, 10, 12], [7, 8, 10, 12]]; let committed_receipts: Vec<_> = (0..=mock_cores.len()) .map(|i| { @@ -820,8 +843,10 @@ mod select_candidates { // Then, some of them get filtered due to new validation code rule. let expected_backed: Vec<_> = cores.iter().map(|&idx| backed_candidates[idx].clone()).collect(); - let expected_backed_filtered: Vec<_> = - expected_cores.iter().map(|&idx| candidates[idx].clone()).collect(); + let expected_backed_filtered: Vec> = possible_expected_cores + .iter() + .map(|indices| indices.iter().map(|&idx| candidates[idx].clone()).collect()) + .collect(); let mock_cores_clone = mock_cores.clone(); @@ -850,13 +875,120 @@ mod select_candidates { assert_eq!(result.len(), 4); - result.into_iter().for_each(|c| { - assert!( - expected_backed_filtered.iter().any(|c2| c.candidate().corresponds_to(c2)), - "Failed to find candidate: {:?}", - c, - ) - }); + assert!(expected_backed_filtered.iter().any(|expected_backed_filtered| { + result.clone().into_iter().all(|c| { + expected_backed_filtered.iter().any(|c2| c.candidate().corresponds_to(c2)) + }) + })); + }, + ) + } + + #[test] + fn selects_max_one_code_upgrade_multiple_cores_per_para() { + let prospective_parachains_mode = + ProspectiveParachainsMode::Enabled { max_candidate_depth: 0, allowed_ancestry_len: 0 }; + let mock_cores = vec![ + // 0: Scheduled(default), + Scheduled(scheduled_core(1)), + // 1: Scheduled(default), + Scheduled(scheduled_core(2)), + // 2: Scheduled(default), + Scheduled(scheduled_core(2)), + // 3: Scheduled(default), + Scheduled(scheduled_core(2)), + // 4: Scheduled(default), + Scheduled(scheduled_core(3)), + // 5: Scheduled(default), + Scheduled(scheduled_core(3)), + // 6: Scheduled(default), + Scheduled(scheduled_core(3)), + ]; + + let empty_hash = PersistedValidationData::::default().hash(); + let cores_with_code = [0, 2, 4, 5]; + + // We can't be sure which one code upgrade the provisioner will pick. We can only assert + // that it only picks one. + // These are the possible cores for which the provisioner will + // supply candidates. There are multiple possibilities depending on which code upgrade it + // chooses. + let possible_expected_cores = [vec![0, 1], vec![1, 2, 3], vec![4, 1]]; + + let committed_receipts: Vec<_> = (0..mock_cores.len()) + .map(|i| { + let mut descriptor = dummy_candidate_descriptor(dummy_hash()); + descriptor.para_id = mock_cores[i].para_id().unwrap(); + descriptor.persisted_validation_data_hash = empty_hash; + descriptor.pov_hash = Hash::from_low_u64_be(i as u64); + CommittedCandidateReceipt { + descriptor, + commitments: CandidateCommitments { + new_validation_code: if cores_with_code.contains(&i) { + Some(vec![].into()) + } else { + None + }, + ..Default::default() + }, + } + }) + .collect(); + + // Input to select_candidates + let candidates: Vec<_> = committed_receipts.iter().map(|r| r.to_plain()).collect(); + // Build possible outputs from select_candidates + let backed_candidates: Vec<_> = committed_receipts + .iter() + .map(|committed_receipt| { + BackedCandidate::new( + committed_receipt.clone(), + Vec::new(), + default_bitvec(MOCK_GROUP_SIZE), + None, + ) + }) + .collect(); + + // First, provisioner will request backable candidates for each scheduled core. + // Then, some of them get filtered due to new validation code rule. + let expected_backed: Vec<_> = + (0..mock_cores.len()).map(|idx| backed_candidates[idx].clone()).collect(); + let expected_backed_filtered: Vec> = possible_expected_cores + .iter() + .map(|indices| indices.iter().map(|&idx| candidates[idx].clone()).collect()) + .collect(); + + let mock_cores_clone = mock_cores.clone(); + + test_harness( + |r| { + mock_overseer( + r, + mock_cores_clone, + expected_backed, + HashMap::new(), + prospective_parachains_mode, + ) + }, + |mut tx: TestSubsystemSender| async move { + let result = select_candidates( + &mock_cores, + &[], + &candidates, + prospective_parachains_mode, + true, + Default::default(), + &mut tx, + ) + .await + .unwrap(); + + assert!(expected_backed_filtered.iter().any(|expected_backed_filtered| { + result.clone().into_iter().all(|c| { + expected_backed_filtered.iter().any(|c2| c.candidate().corresponds_to(c2)) + }) && (expected_backed_filtered.len() == result.len()) + })); }, ) } diff --git a/polkadot/node/overseer/src/tests.rs b/polkadot/node/overseer/src/tests.rs index 0494274367d..55a6bdb74ba 100644 --- a/polkadot/node/overseer/src/tests.rs +++ b/polkadot/node/overseer/src/tests.rs @@ -811,7 +811,7 @@ fn test_candidate_validation_msg() -> CandidateValidationMessage { fn test_candidate_backing_msg() -> CandidateBackingMessage { let (sender, _) = oneshot::channel(); - CandidateBackingMessage::GetBackedCandidates(Vec::new(), sender) + CandidateBackingMessage::GetBackedCandidates(Default::default(), sender) } fn test_chain_api_msg() -> ChainApiMessage { diff --git a/polkadot/node/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index 5115efa853c..92c35d1b7b9 100644 --- a/polkadot/node/subsystem-types/src/messages.rs +++ b/polkadot/node/subsystem-types/src/messages.rs @@ -82,8 +82,15 @@ pub struct CanSecondRequest { pub enum CandidateBackingMessage { /// Requests a set of backable candidates attested by the subsystem. /// - /// Each pair is (candidate_hash, candidate_relay_parent). - GetBackedCandidates(Vec<(CandidateHash, Hash)>, oneshot::Sender>), + /// The order of candidates of the same para must be preserved in the response. + /// If a backed candidate of a para cannot be retrieved, the response should not contain any + /// candidates of the same para that follow it in the input vector. In other words, assuming + /// candidates are supplied in dependency order, we must ensure that this dependency order is + /// preserved. + GetBackedCandidates( + HashMap>, + oneshot::Sender>>, + ), /// Request the subsystem to check whether it's allowed to second given candidate. /// The rule is to only fetch collations that are either built on top of the root /// of some fragment tree or have a parent node which represents backed candidate. diff --git a/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md b/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md index 54cdc2edd12..acfe309ba7b 100644 --- a/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md +++ b/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md @@ -340,9 +340,15 @@ enum BitfieldSigningMessage { } ```rust enum CandidateBackingMessage { /// Requests a set of backable candidates attested by the subsystem. - /// - /// Each pair is (candidate_hash, candidate_relay_parent). - GetBackedCandidates(Vec<(CandidateHash, Hash)>, oneshot::Sender>), + /// The order of candidates of the same para must be preserved in the response. + /// If a backed candidate of a para cannot be retrieved, the response should not contain any + /// candidates of the same para that follow it in the input vector. In other words, assuming + /// candidates are supplied in dependency order, we must ensure that this dependency order is + /// preserved. + GetBackedCandidates( + HashMap>, + oneshot::Sender>>, + ), /// Note that the Candidate Backing subsystem should second the given candidate in the context of the /// given relay-parent (ref. by hash). This candidate must be validated using the provided PoV. /// The PoV is expected to match the `pov_hash` in the descriptor. -- GitLab From ce7613a49ff15652c6b33927f2ac64a64ba09783 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Mon, 25 Mar 2024 16:24:58 +0200 Subject: [PATCH 091/187] =?UTF-8?q?[prdoc]=C2=A0Remove=20default=20audienc?= =?UTF-8?q?e=20(#3723)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Devs seem to not realize that this should be filled out manually. The default is also often wrong. --- prdoc/.template.prdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prdoc/.template.prdoc b/prdoc/.template.prdoc index 097741f388c..03a458876df 100644 --- a/prdoc/.template.prdoc +++ b/prdoc/.template.prdoc @@ -4,7 +4,7 @@ title: ... doc: - - audience: Node Dev + - audience: ... description: | ... -- GitLab From 9d122401f1d434235dfc08ee0509ab6e921bb286 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Mon, 25 Mar 2024 15:26:38 +0000 Subject: [PATCH 092/187] Refactor crypto-related traits implementations in term of Public/Signature Bytes (#3806) Another simple refactory to prune some duplicate code Follow up of: https://github.com/paritytech/polkadot-sdk/pull/3684 --- .../primitives/application-crypto/src/lib.rs | 14 +- substrate/primitives/core/src/bandersnatch.rs | 55 +------ substrate/primitives/core/src/bls.rs | 111 +------------ substrate/primitives/core/src/crypto.rs | 115 ++++--------- substrate/primitives/core/src/crypto_bytes.rs | 153 ++++++++++++++++-- substrate/primitives/core/src/ecdsa.rs | 92 +---------- substrate/primitives/core/src/ed25519.rs | 111 +------------ substrate/primitives/core/src/lib.rs | 20 +-- .../primitives/core/src/paired_crypto.rs | 144 +---------------- substrate/primitives/core/src/sr25519.rs | 95 ++++------- .../primitives/statement-store/src/ecies.rs | 2 +- 11 files changed, 254 insertions(+), 658 deletions(-) diff --git a/substrate/primitives/application-crypto/src/lib.rs b/substrate/primitives/application-crypto/src/lib.rs index ea2e5a83127..2355f1ba527 100644 --- a/substrate/primitives/application-crypto/src/lib.rs +++ b/substrate/primitives/application-crypto/src/lib.rs @@ -26,7 +26,7 @@ pub use sp_core::crypto::{DeriveError, Pair, SecretStringError}; #[doc(hidden)] pub use sp_core::{ self, - crypto::{ByteArray, CryptoType, Derive, IsWrappedBy, Public, UncheckedFrom, Wraps}, + crypto::{ByteArray, CryptoType, Derive, IsWrappedBy, Public, Signature, UncheckedFrom, Wraps}, RuntimeDebug, }; @@ -505,6 +505,12 @@ macro_rules! app_crypto_signature_common { } } + impl AsMut<[u8]> for Signature { + fn as_mut(&mut self) -> &mut [u8] { + self.0.as_mut() + } + } + impl $crate::AppSignature for Signature { type Generic = $sig; } @@ -525,6 +531,12 @@ macro_rules! app_crypto_signature_common { } } + impl $crate::Signature for Signature {} + + impl $crate::ByteArray for Signature { + const LEN: usize = <$sig>::LEN; + } + impl Signature { /// Convert into wrapped generic signature type. pub fn into_inner(self) -> $sig { diff --git a/substrate/primitives/core/src/bandersnatch.rs b/substrate/primitives/core/src/bandersnatch.rs index c9d5f27b47b..42c8b293634 100644 --- a/substrate/primitives/core/src/bandersnatch.rs +++ b/substrate/primitives/core/src/bandersnatch.rs @@ -20,19 +20,12 @@ //! //! The primitive can operate both as a regular VRF or as an anonymized Ring VRF. -#[cfg(feature = "serde")] -use crate::crypto::Ss58Codec; #[cfg(feature = "full_crypto")] use crate::crypto::VrfSecret; use crate::crypto::{ - ByteArray, CryptoType, CryptoTypeId, Derive, DeriveError, DeriveJunction, Pair as TraitPair, - Public as TraitPublic, PublicBytes, SecretStringError, SignatureBytes, UncheckedFrom, - VrfPublic, + ByteArray, CryptoType, CryptoTypeId, DeriveError, DeriveJunction, Pair as TraitPair, + PublicBytes, SecretStringError, SignatureBytes, UncheckedFrom, VrfPublic, }; -#[cfg(feature = "serde")] -use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; -#[cfg(all(not(feature = "std"), feature = "serde"))] -use sp_std::alloc::{format, string::String}; use bandersnatch_vrfs::{CanonicalSerialize, SecretKey}; use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; @@ -64,42 +57,10 @@ pub struct BandersnatchTag; /// Bandersnatch public key. pub type Public = PublicBytes; -impl TraitPublic for Public {} - impl CryptoType for Public { type Pair = Pair; } -impl Derive for Public {} - -impl sp_std::fmt::Debug for Public { - #[cfg(feature = "std")] - fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - let s = self.to_ss58check(); - write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.as_ref()), &s[0..8]) - } - - #[cfg(not(feature = "std"))] - fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - Ok(()) - } -} - -#[cfg(feature = "serde")] -impl Serialize for Public { - fn serialize(&self, serializer: S) -> Result { - serializer.serialize_str(&self.to_ss58check()) - } -} - -#[cfg(feature = "serde")] -impl<'de> Deserialize<'de> for Public { - fn deserialize>(deserializer: D) -> Result { - Public::from_ss58check(&String::deserialize(deserializer)?) - .map_err(|e| de::Error::custom(format!("{:?}", e))) - } -} - /// Bandersnatch signature. /// /// The signature is created via the [`VrfSecret::vrf_sign`] using [`SIGNING_CTX`] as transcript @@ -110,18 +71,6 @@ impl CryptoType for Signature { type Pair = Pair; } -impl sp_std::fmt::Debug for Signature { - #[cfg(feature = "std")] - fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0)) - } - - #[cfg(not(feature = "std"))] - fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - Ok(()) - } -} - /// The raw secret seed, which can be used to reconstruct the secret [`Pair`]. type Seed = [u8; SEED_SERIALIZED_SIZE]; diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index 9492a14ff0d..bb04babb3f1 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -23,17 +23,11 @@ //! Chaum-Pedersen proof uses the same hash-to-field specified in RFC 9380 for the field of the BLS //! curve. -#[cfg(feature = "serde")] -use crate::crypto::Ss58Codec; use crate::crypto::{ - CryptoType, Derive, DeriveError, DeriveJunction, Pair as TraitPair, Public as TraitPublic, - PublicBytes, SecretStringError, SignatureBytes, UncheckedFrom, + CryptoType, DeriveError, DeriveJunction, Pair as TraitPair, PublicBytes, SecretStringError, + SignatureBytes, UncheckedFrom, }; -#[cfg(feature = "serde")] -use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; -#[cfg(all(not(feature = "std"), feature = "serde"))] -use sp_std::alloc::{format, string::String}; use sp_std::vec::Vec; use w3f_bls::{ @@ -115,68 +109,6 @@ pub struct BlsTag; /// A public key. pub type Public = PublicBytes; -impl From> for Public { - fn from(x: Pair) -> Self { - x.public() - } -} - -#[cfg(feature = "std")] -impl std::str::FromStr for Public { - type Err = crate::crypto::PublicError; - - fn from_str(s: &str) -> Result { - Self::from_ss58check(s) - } -} - -#[cfg(feature = "std")] -impl std::fmt::Display for Public { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", self.to_ss58check()) - } -} - -#[cfg(feature = "std")] -impl sp_std::fmt::Debug for Public { - fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - let s = self.to_ss58check(); - write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8]) - } -} - -#[cfg(not(feature = "std"))] -impl sp_std::fmt::Debug for Public { - fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - Ok(()) - } -} - -#[cfg(feature = "serde")] -impl Serialize for Public { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&self.to_ss58check()) - } -} - -#[cfg(feature = "serde")] -impl<'de, T: BlsBound> Deserialize<'de> for Public { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - Public::from_ss58check(&String::deserialize(deserializer)?) - .map_err(|e| de::Error::custom(format!("{:?}", e))) - } -} - -impl TraitPublic for Public {} - -impl Derive for Public {} - impl CryptoType for Public { type Pair = Pair; } @@ -184,41 +116,6 @@ impl CryptoType for Public { /// A generic BLS signature. pub type Signature = SignatureBytes; -#[cfg(feature = "serde")] -impl Serialize for Signature { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&array_bytes::bytes2hex("", self)) - } -} - -#[cfg(feature = "serde")] -impl<'de, T> Deserialize<'de> for Signature { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let signature_hex = array_bytes::hex2bytes(&String::deserialize(deserializer)?) - .map_err(|e| de::Error::custom(format!("{:?}", e)))?; - Signature::try_from(signature_hex.as_ref()) - .map_err(|e| de::Error::custom(format!("{:?}", e))) - } -} - -impl sp_std::fmt::Debug for Signature { - #[cfg(feature = "std")] - fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0)) - } - - #[cfg(not(feature = "std"))] - fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - Ok(()) - } -} - impl CryptoType for Signature { type Pair = Pair; } @@ -333,8 +230,10 @@ impl CryptoType for Pair { // Test set exercising the BLS12-377 implementation #[cfg(test)] -mod test { +mod tests { use super::*; + #[cfg(feature = "serde")] + use crate::crypto::Ss58Codec; use crate::crypto::DEV_PHRASE; use bls377::{Pair, Signature}; diff --git a/substrate/primitives/core/src/crypto.rs b/substrate/primitives/core/src/crypto.rs index a2bdc6ed58e..b13899fff51 100644 --- a/substrate/primitives/core/src/crypto.rs +++ b/substrate/primitives/core/src/crypto.rs @@ -485,8 +485,11 @@ pub trait ByteArray: AsRef<[u8]> + AsMut<[u8]> + for<'a> TryFrom<&'a [u8], Error } } -/// Trait suitable for typical cryptographic key public type. -pub trait Public: CryptoType + ByteArray + Derive + PartialEq + Eq + Clone + Send + Sync {} +/// Trait suitable for cryptographic public keys. +pub trait Public: CryptoType + ByteArray + PartialEq + Eq + Clone + Send + Sync + Derive {} + +/// Trait suitable for cryptographic signatures. +pub trait Signature: CryptoType + ByteArray + PartialEq + Eq + Clone + Send + Sync {} /// An opaque 32-byte cryptographic identifier. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, MaxEncodedLen, TypeInfo)] @@ -648,32 +651,11 @@ pub use self::dummy::*; mod dummy { use super::*; - /// Dummy cryptography. Doesn't do anything. - #[derive(Clone, Hash, Default, Eq, PartialEq)] - pub struct Dummy; - - impl AsRef<[u8]> for Dummy { - fn as_ref(&self) -> &[u8] { - &b""[..] - } - } + #[doc(hidden)] + pub struct DummyTag; - impl AsMut<[u8]> for Dummy { - fn as_mut(&mut self) -> &mut [u8] { - unsafe { - #[allow(mutable_transmutes)] - sp_std::mem::transmute::<_, &'static mut [u8]>(&b""[..]) - } - } - } - - impl<'a> TryFrom<&'a [u8]> for Dummy { - type Error = (); - - fn try_from(_: &'a [u8]) -> Result { - Ok(Self) - } - } + /// Dummy cryptography. Doesn't do anything. + pub type Dummy = CryptoBytes<0, DummyTag>; impl CryptoType for Dummy { type Pair = Dummy; @@ -681,21 +663,10 @@ mod dummy { impl Derive for Dummy {} - impl ByteArray for Dummy { - const LEN: usize = 0; - fn from_slice(_: &[u8]) -> Result { - Ok(Self) - } - #[cfg(feature = "std")] - fn to_raw_vec(&self) -> Vec { - vec![] - } - fn as_slice(&self) -> &[u8] { - b"" - } - } impl Public for Dummy {} + impl Signature for Dummy {} + impl Pair for Dummy { type Public = Dummy; type Seed = Dummy; @@ -716,15 +687,15 @@ mod dummy { _: Iter, _: Option, ) -> Result<(Self, Option), DeriveError> { - Ok((Self, None)) + Ok((Self::default(), None)) } fn from_seed_slice(_: &[u8]) -> Result { - Ok(Self) + Ok(Self::default()) } fn sign(&self, _: &[u8]) -> Self::Signature { - Self + Self::default() } fn verify>(_: &Self::Signature, _: M, _: &Self::Public) -> bool { @@ -732,11 +703,11 @@ mod dummy { } fn public(&self) -> Self::Public { - Self + Self::default() } fn to_raw_vec(&self) -> Vec { - vec![] + Default::default() } } } @@ -845,7 +816,7 @@ pub trait Pair: CryptoType + Sized { /// The type used to represent a signature. Can be created from a key pair and a message /// and verified with the message and a public key. - type Signature: AsRef<[u8]>; + type Signature: Signature; /// Generate new secure (random) key pair. /// @@ -1218,6 +1189,8 @@ mod tests { use super::*; use crate::DeriveJunction; + struct TestCryptoTag; + #[derive(Clone, Eq, PartialEq, Debug)] enum TestPair { Generated, @@ -1226,59 +1199,33 @@ mod tests { Standard { phrase: String, password: Option, path: Vec }, Seed(Vec), } + impl Default for TestPair { fn default() -> Self { TestPair::Generated } } + impl CryptoType for TestPair { type Pair = Self; } - #[derive(Clone, PartialEq, Eq, Hash, Default)] - struct TestPublic; - impl AsRef<[u8]> for TestPublic { - fn as_ref(&self) -> &[u8] { - &[] - } - } - impl AsMut<[u8]> for TestPublic { - fn as_mut(&mut self) -> &mut [u8] { - &mut [] - } - } - impl<'a> TryFrom<&'a [u8]> for TestPublic { - type Error = (); + type TestPublic = PublicBytes<0, TestCryptoTag>; - fn try_from(data: &'a [u8]) -> Result { - Self::from_slice(data) - } - } impl CryptoType for TestPublic { type Pair = TestPair; } - impl Derive for TestPublic {} - impl ByteArray for TestPublic { - const LEN: usize = 0; - fn from_slice(bytes: &[u8]) -> Result { - if bytes.is_empty() { - Ok(Self) - } else { - Err(()) - } - } - fn as_slice(&self) -> &[u8] { - &[] - } - fn to_raw_vec(&self) -> Vec { - vec![] - } + + type TestSignature = SignatureBytes<0, TestCryptoTag>; + + impl CryptoType for TestSignature { + type Pair = TestPair; } - impl Public for TestPublic {} + impl Pair for TestPair { type Public = TestPublic; type Seed = [u8; 8]; - type Signature = [u8; 0]; + type Signature = TestSignature; fn generate() -> (Self, ::Seed) { (TestPair::Generated, [0u8; 8]) @@ -1327,7 +1274,7 @@ mod tests { } fn sign(&self, _message: &[u8]) -> Self::Signature { - [] + TestSignature::default() } fn verify>(_: &Self::Signature, _: M, _: &Self::Public) -> bool { @@ -1335,7 +1282,7 @@ mod tests { } fn public(&self) -> Self::Public { - TestPublic + TestPublic::default() } fn from_seed_slice(seed: &[u8]) -> Result { diff --git a/substrate/primitives/core/src/crypto_bytes.rs b/substrate/primitives/core/src/crypto_bytes.rs index 069878e1654..ee5f3482f74 100644 --- a/substrate/primitives/core/src/crypto_bytes.rs +++ b/substrate/primitives/core/src/crypto_bytes.rs @@ -18,15 +18,27 @@ //! Generic byte array which can be specialized with a marker type. use crate::{ - crypto::{FromEntropy, UncheckedFrom}, + crypto::{CryptoType, Derive, FromEntropy, Public, Signature, UncheckedFrom}, hash::{H256, H512}, }; use codec::{Decode, Encode, MaxEncodedLen}; use core::marker::PhantomData; use scale_info::TypeInfo; + use sp_runtime_interface::pass_by::{self, PassBy, PassByInner}; +#[cfg(feature = "serde")] +use crate::crypto::Ss58Codec; +#[cfg(feature = "serde")] +use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; + +#[cfg(all(not(feature = "std"), feature = "serde"))] +use sp_std::alloc::{format, string::String}; + +pub use public_bytes::*; +pub use signature_bytes::*; + /// Generic byte array holding some crypto-related raw data. /// /// The type is generic over a constant length `N` and a "tag" `T` which @@ -231,14 +243,137 @@ impl CryptoBytes<64, T> { } } -/// Tag used for generic public key bytes. -pub struct PublicTag; +mod public_bytes { + use super::*; + + /// Tag used for generic public key bytes. + pub struct PublicTag; + + /// Generic encoded public key. + pub type PublicBytes = CryptoBytes; + + impl Derive for PublicBytes where Self: CryptoType {} + + impl Public for PublicBytes where Self: CryptoType {} + + impl sp_std::fmt::Debug for PublicBytes + where + Self: CryptoType, + { + #[cfg(feature = "std")] + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let s = self.to_ss58check(); + write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.as_ref()), &s[0..8]) + } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + Ok(()) + } + } + + #[cfg(feature = "std")] + impl std::fmt::Display for PublicBytes + where + Self: CryptoType, + { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.to_ss58check()) + } + } + + #[cfg(feature = "std")] + impl std::str::FromStr for PublicBytes + where + Self: CryptoType, + { + type Err = crate::crypto::PublicError; + + fn from_str(s: &str) -> Result { + Self::from_ss58check(s) + } + } + + #[cfg(feature = "serde")] + impl Serialize for PublicBytes + where + Self: CryptoType, + { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&self.to_ss58check()) + } + } + + #[cfg(feature = "serde")] + impl<'de, const N: usize, SubTag> Deserialize<'de> for PublicBytes + where + Self: CryptoType, + { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Self::from_ss58check(&String::deserialize(deserializer)?) + .map_err(|e| de::Error::custom(format!("{:?}", e))) + } + } +} + +mod signature_bytes { + use super::*; + + /// Tag used for generic signature bytes. + pub struct SignatureTag; + + /// Generic encoded signature. + pub type SignatureBytes = CryptoBytes; -/// Generic encoded public key. -pub type PublicBytes = CryptoBytes; + impl Signature for SignatureBytes where Self: CryptoType {} -/// Tag used for generic signature bytes. -pub struct SignatureTag; + #[cfg(feature = "serde")] + impl Serialize for SignatureBytes + where + Self: CryptoType, + { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&array_bytes::bytes2hex("", self)) + } + } + + #[cfg(feature = "serde")] + impl<'de, const N: usize, SubTag> Deserialize<'de> for SignatureBytes + where + Self: CryptoType, + { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let signature_hex = array_bytes::hex2bytes(&String::deserialize(deserializer)?) + .map_err(|e| de::Error::custom(format!("{:?}", e)))?; + Self::try_from(signature_hex.as_ref()) + .map_err(|e| de::Error::custom(format!("{:?}", e))) + } + } -/// Generic encoded signature. -pub type SignatureBytes = CryptoBytes; + impl sp_std::fmt::Debug for SignatureBytes + where + Self: CryptoType, + { + #[cfg(feature = "std")] + fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + write!(f, "{}", crate::hexdisplay::HexDisplay::from(&&self.0[..])) + } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + Ok(()) + } + } +} diff --git a/substrate/primitives/core/src/ecdsa.rs b/substrate/primitives/core/src/ecdsa.rs index 0e6b06a34dc..9cba8cc3d35 100644 --- a/substrate/primitives/core/src/ecdsa.rs +++ b/substrate/primitives/core/src/ecdsa.rs @@ -17,11 +17,9 @@ //! Simple ECDSA secp256k1 API. -#[cfg(feature = "serde")] -use crate::crypto::Ss58Codec; use crate::crypto::{ - CryptoType, CryptoTypeId, Derive, DeriveError, DeriveJunction, Pair as TraitPair, - Public as TraitPublic, PublicBytes, SecretStringError, SignatureBytes, + CryptoType, CryptoTypeId, DeriveError, DeriveJunction, Pair as TraitPair, PublicBytes, + SecretStringError, SignatureBytes, }; #[cfg(not(feature = "std"))] @@ -31,10 +29,6 @@ use secp256k1::{ ecdsa::{RecoverableSignature, RecoveryId}, Message, PublicKey, SecretKey, SECP256K1, }; -#[cfg(feature = "serde")] -use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; -#[cfg(all(not(feature = "std"), feature = "serde"))] -use sp_std::alloc::{format, string::String}; #[cfg(not(feature = "std"))] use sp_std::vec::Vec; @@ -80,10 +74,6 @@ impl Public { } } -impl TraitPublic for Public {} - -impl Derive for Public {} - #[cfg(feature = "std")] impl From for Public { fn from(pubkey: PublicKey) -> Self { @@ -106,85 +96,9 @@ impl From for Public { } } -#[cfg(feature = "std")] -impl std::fmt::Display for Public { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", self.to_ss58check()) - } -} - -impl sp_std::fmt::Debug for Public { - #[cfg(feature = "std")] - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - let s = self.to_ss58check(); - write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.as_ref()), &s[0..8]) - } - - #[cfg(not(feature = "std"))] - fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - Ok(()) - } -} - -#[cfg(feature = "serde")] -impl Serialize for Public { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&self.to_ss58check()) - } -} - -#[cfg(feature = "serde")] -impl<'de> Deserialize<'de> for Public { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - Public::from_ss58check(&String::deserialize(deserializer)?) - .map_err(|e| de::Error::custom(format!("{:?}", e))) - } -} - /// A signature (a 512-bit value, plus 8 bits for recovery ID). pub type Signature = SignatureBytes; -#[cfg(feature = "serde")] -impl Serialize for Signature { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&array_bytes::bytes2hex("", self)) - } -} - -#[cfg(feature = "serde")] -impl<'de> Deserialize<'de> for Signature { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let signature_hex = array_bytes::hex2bytes(&String::deserialize(deserializer)?) - .map_err(|e| de::Error::custom(format!("{:?}", e)))?; - Signature::try_from(signature_hex.as_ref()) - .map_err(|e| de::Error::custom(format!("{:?}", e))) - } -} - -impl sp_std::fmt::Debug for Signature { - #[cfg(feature = "std")] - fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0)) - } - - #[cfg(not(feature = "std"))] - fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - Ok(()) - } -} - impl Signature { /// Recover the public key from this signature and a message. pub fn recover>(&self, message: M) -> Option { @@ -417,7 +331,7 @@ mod test { use super::*; use crate::crypto::{ set_default_ss58_version, PublicError, Ss58AddressFormat, Ss58AddressFormatRegistry, - DEV_PHRASE, + Ss58Codec, DEV_PHRASE, }; use serde_json; diff --git a/substrate/primitives/core/src/ed25519.rs b/substrate/primitives/core/src/ed25519.rs index 0dda7b95972..a9494f2860b 100644 --- a/substrate/primitives/core/src/ed25519.rs +++ b/substrate/primitives/core/src/ed25519.rs @@ -17,18 +17,13 @@ //! Simple Ed25519 API. -#[cfg(feature = "serde")] -use crate::crypto::Ss58Codec; use crate::crypto::{ - ByteArray, CryptoType, CryptoTypeId, Derive, DeriveError, DeriveJunction, Pair as TraitPair, - Public as TraitPublic, PublicBytes, SecretStringError, SignatureBytes, + ByteArray, CryptoType, CryptoTypeId, DeriveError, DeriveJunction, Pair as TraitPair, + PublicBytes, SecretStringError, SignatureBytes, }; use ed25519_zebra::{SigningKey, VerificationKey}; -#[cfg(feature = "serde")] -use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; -#[cfg(all(not(feature = "std"), feature = "serde"))] -use sp_std::alloc::{format, string::String}; + use sp_std::vec::Vec; /// An identifier used to match public keys against ed25519 keys @@ -51,105 +46,9 @@ pub struct Ed25519Tag; /// A public key. pub type Public = PublicBytes; -impl TraitPublic for Public {} - -impl Derive for Public {} - -#[cfg(feature = "full_crypto")] -impl From for Public { - fn from(x: Pair) -> Self { - x.public() - } -} - -#[cfg(feature = "std")] -impl std::str::FromStr for Public { - type Err = crate::crypto::PublicError; - - fn from_str(s: &str) -> Result { - Self::from_ss58check(s) - } -} - -#[cfg(feature = "std")] -impl std::fmt::Display for Public { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", self.to_ss58check()) - } -} - -impl sp_std::fmt::Debug for Public { - #[cfg(feature = "std")] - fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - let s = self.to_ss58check(); - write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8]) - } - - #[cfg(not(feature = "std"))] - fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - Ok(()) - } -} - -#[cfg(feature = "serde")] -impl Serialize for Public { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&self.to_ss58check()) - } -} - -#[cfg(feature = "serde")] -impl<'de> Deserialize<'de> for Public { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - Public::from_ss58check(&String::deserialize(deserializer)?) - .map_err(|e| de::Error::custom(format!("{:?}", e))) - } -} - /// A signature. pub type Signature = SignatureBytes; -#[cfg(feature = "serde")] -impl Serialize for Signature { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&array_bytes::bytes2hex("", self)) - } -} - -#[cfg(feature = "serde")] -impl<'de> Deserialize<'de> for Signature { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let signature_hex = array_bytes::hex2bytes(&String::deserialize(deserializer)?) - .map_err(|e| de::Error::custom(format!("{:?}", e)))?; - Signature::try_from(signature_hex.as_ref()) - .map_err(|e| de::Error::custom(format!("{:?}", e))) - } -} - -impl sp_std::fmt::Debug for Signature { - #[cfg(feature = "std")] - fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0)) - } - - #[cfg(not(feature = "std"))] - fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - Ok(()) - } -} - /// A key pair. #[derive(Copy, Clone)] pub struct Pair { @@ -253,8 +152,10 @@ impl CryptoType for Pair { } #[cfg(test)] -mod test { +mod tests { use super::*; + #[cfg(feature = "serde")] + use crate::crypto::Ss58Codec; use crate::crypto::DEV_PHRASE; use serde_json; diff --git a/substrate/primitives/core/src/lib.rs b/substrate/primitives/core/src/lib.rs index cf803c6fb49..098bd135bfe 100644 --- a/substrate/primitives/core/src/lib.rs +++ b/substrate/primitives/core/src/lib.rs @@ -56,27 +56,27 @@ pub mod const_hex2array; pub mod crypto; pub mod hexdisplay; pub use paste; - mod address_uri; -#[cfg(feature = "bandersnatch-experimental")] -pub mod bandersnatch; -#[cfg(feature = "bls-experimental")] -pub mod bls; -pub mod crypto_bytes; pub mod defer; -pub mod ecdsa; -pub mod ed25519; pub mod hash; #[cfg(feature = "std")] mod hasher; pub mod offchain; -pub mod paired_crypto; -pub mod sr25519; pub mod testing; #[cfg(feature = "std")] pub mod traits; pub mod uint; +#[cfg(feature = "bandersnatch-experimental")] +pub mod bandersnatch; +#[cfg(feature = "bls-experimental")] +pub mod bls; +pub mod crypto_bytes; +pub mod ecdsa; +pub mod ed25519; +pub mod paired_crypto; +pub mod sr25519; + #[cfg(feature = "bls-experimental")] pub use bls::{bls377, bls381}; #[cfg(feature = "bls-experimental")] diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 27a7ab28dfd..3901846b375 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -19,20 +19,13 @@ use core::marker::PhantomData; -#[cfg(feature = "serde")] -use crate::crypto::Ss58Codec; use crate::crypto::{ - ByteArray, CryptoType, Derive, DeriveError, DeriveJunction, Pair as PairT, Public as PublicT, - PublicBytes, SecretStringError, SignatureBytes, UncheckedFrom, + ByteArray, CryptoType, DeriveError, DeriveJunction, Pair as PairT, Public as PublicT, + PublicBytes, SecretStringError, Signature as SignatureT, SignatureBytes, UncheckedFrom, }; use sp_std::vec::Vec; -#[cfg(feature = "serde")] -use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; -#[cfg(all(not(feature = "std"), feature = "serde"))] -use sp_std::alloc::{format, string::String}; - /// ECDSA and BLS12-377 paired crypto scheme #[cfg(feature = "bls-experimental")] pub mod ecdsa_bls377 { @@ -173,130 +166,10 @@ where } } -#[cfg(feature = "std")] -impl std::fmt::Display - for Public -where - Public: CryptoType, -{ - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", self.to_ss58check()) - } -} - -impl sp_std::fmt::Debug - for Public -where - Public: CryptoType, - [u8; LEFT_PLUS_RIGHT_LEN]: crate::hexdisplay::AsBytesRef, -{ - #[cfg(feature = "std")] - fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - let s = self.to_ss58check(); - write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8]) - } - - #[cfg(not(feature = "std"))] - fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - Ok(()) - } -} - -#[cfg(feature = "serde")] -impl Serialize - for Public -where - Public: CryptoType, -{ - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&self.to_ss58check()) - } -} - -#[cfg(feature = "serde")] -impl<'de, const LEFT_PLUS_RIGHT_LEN: usize, SubTag: PairedCryptoSubTagBound> Deserialize<'de> - for Public -where - Public: CryptoType, -{ - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - Public::from_ss58check(&String::deserialize(deserializer)?) - .map_err(|e| de::Error::custom(format!("{:?}", e))) - } -} - -impl PublicT - for Public -where - Public: CryptoType, -{ -} - -impl Derive - for Public -{ -} - -/// Trait characterizing a signature which could be used as individual component of an -/// `paired_crypto:Signature` pair. -pub trait SignatureBound: ByteArray {} - -impl SignatureBound for T {} - /// A pair of signatures of different types pub type Signature = SignatureBytes; -#[cfg(feature = "serde")] -impl Serialize - for Signature -{ - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&array_bytes::bytes2hex("", self)) - } -} - -#[cfg(feature = "serde")] -impl<'de, const LEFT_PLUS_RIGHT_LEN: usize, SubTag> Deserialize<'de> - for Signature -{ - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let bytes = array_bytes::hex2bytes(&String::deserialize(deserializer)?) - .map_err(|e| de::Error::custom(format!("{:?}", e)))?; - Signature::::try_from(bytes.as_ref()).map_err(|e| { - de::Error::custom(format!("Error converting deserialized data into signature: {:?}", e)) - }) - } -} - -impl sp_std::fmt::Debug - for Signature -where - [u8; LEFT_PLUS_RIGHT_LEN]: crate::hexdisplay::AsBytesRef, -{ - #[cfg(feature = "std")] - fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0)) - } - - #[cfg(not(feature = "std"))] - fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - Ok(()) - } -} - /// A key pair. pub struct Pair< LeftPair: PairT, @@ -332,9 +205,8 @@ impl< > PairT for Pair where Pair: CryptoType, - LeftPair::Signature: SignatureBound, - RightPair::Signature: SignatureBound, - Public: CryptoType, + Public: PublicT, + Signature: SignatureT, LeftPair::Seed: From + Into, RightPair::Seed: From + Into, { @@ -417,14 +289,14 @@ where // Test set exercising the (ECDSA,BLS12-377) implementation #[cfg(all(test, feature = "bls-experimental"))] -mod test { +mod tests { use super::*; - use crate::{crypto::DEV_PHRASE, KeccakHasher}; + #[cfg(feature = "serde")] + use crate::crypto::Ss58Codec; + use crate::{bls377, crypto::DEV_PHRASE, ecdsa, KeccakHasher}; use codec::{Decode, Encode}; use ecdsa_bls377::{Pair, Signature}; - use crate::{bls377, ecdsa}; - #[test] fn test_length_of_paired_ecdsa_and_bls377_public_key_and_signature_is_correct() { assert_eq!( diff --git a/substrate/primitives/core/src/sr25519.rs b/substrate/primitives/core/src/sr25519.rs index ee0546bc534..54b9a98db3d 100644 --- a/substrate/primitives/core/src/sr25519.rs +++ b/substrate/primitives/core/src/sr25519.rs @@ -22,7 +22,9 @@ #[cfg(feature = "serde")] use crate::crypto::Ss58Codec; -use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError}; +use crate::crypto::{ + CryptoBytes, DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError, +}; #[cfg(feature = "full_crypto")] use schnorrkel::signing_context; use schnorrkel::{ @@ -31,9 +33,7 @@ use schnorrkel::{ }; use sp_std::vec::Vec; -use crate::crypto::{ - CryptoType, CryptoTypeId, Derive, Public as TraitPublic, PublicBytes, SignatureBytes, -}; +use crate::crypto::{CryptoType, CryptoTypeId, Derive, Public as TraitPublic, SignatureBytes}; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; @@ -59,20 +59,28 @@ pub const SIGNATURE_SERIALIZED_SIZE: usize = 64; #[doc(hidden)] pub struct Sr25519Tag; +#[doc(hidden)] +pub struct Sr25519PublicTag; /// An Schnorrkel/Ristretto x25519 ("sr25519") public key. -pub type Public = PublicBytes; +pub type Public = CryptoBytes; -/// An Schnorrkel/Ristretto x25519 ("sr25519") key pair. -pub struct Pair(Keypair); +impl TraitPublic for Public {} -impl Clone for Pair { - fn clone(&self) -> Self { - Pair(schnorrkel::Keypair { - public: self.0.public, - secret: schnorrkel::SecretKey::from_bytes(&self.0.secret.to_bytes()[..]) - .expect("key is always the correct size; qed"), - }) +impl Derive for Public { + /// Derive a child key from a series of given junctions. + /// + /// `None` if there are any hard junctions in there. + #[cfg(feature = "serde")] + fn derive>(&self, path: Iter) -> Option { + let mut acc = PublicKey::from_bytes(self.as_ref()).ok()?; + for j in path { + match j { + DeriveJunction::Soft(cc) => acc = acc.derived_key_simple(ChainCode(cc), &[]).0, + DeriveJunction::Hard(_cc) => return None, + } + } + Some(Self::from(acc.to_bytes())) } } @@ -129,29 +137,6 @@ impl<'de> Deserialize<'de> for Public { /// An Schnorrkel/Ristretto x25519 ("sr25519") signature. pub type Signature = SignatureBytes; -#[cfg(feature = "serde")] -impl Serialize for Signature { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&array_bytes::bytes2hex("", self)) - } -} - -#[cfg(feature = "serde")] -impl<'de> Deserialize<'de> for Signature { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let signature_hex = array_bytes::hex2bytes(&String::deserialize(deserializer)?) - .map_err(|e| de::Error::custom(format!("{:?}", e)))?; - Signature::try_from(signature_hex.as_ref()) - .map_err(|e| de::Error::custom(format!("{:?}", e))) - } -} - #[cfg(feature = "full_crypto")] impl From for Signature { fn from(s: schnorrkel::Signature) -> Signature { @@ -159,37 +144,19 @@ impl From for Signature { } } -impl sp_std::fmt::Debug for Signature { - #[cfg(feature = "std")] - fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0)) - } - - #[cfg(not(feature = "std"))] - fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - Ok(()) - } -} +/// An Schnorrkel/Ristretto x25519 ("sr25519") key pair. +pub struct Pair(Keypair); -impl Derive for Public { - /// Derive a child key from a series of given junctions. - /// - /// `None` if there are any hard junctions in there. - #[cfg(feature = "serde")] - fn derive>(&self, path: Iter) -> Option { - let mut acc = PublicKey::from_bytes(self.as_ref()).ok()?; - for j in path { - match j { - DeriveJunction::Soft(cc) => acc = acc.derived_key_simple(ChainCode(cc), &[]).0, - DeriveJunction::Hard(_cc) => return None, - } - } - Some(Self::from(acc.to_bytes())) +impl Clone for Pair { + fn clone(&self) -> Self { + Pair(schnorrkel::Keypair { + public: self.0.public, + secret: schnorrkel::SecretKey::from_bytes(&self.0.secret.to_bytes()[..]) + .expect("key is always the correct size; qed"), + }) } } -impl TraitPublic for Public {} - #[cfg(feature = "std")] impl From for Pair { fn from(sec: MiniSecretKey) -> Pair { diff --git a/substrate/primitives/statement-store/src/ecies.rs b/substrate/primitives/statement-store/src/ecies.rs index 80a040fd4c8..6fa16658e00 100644 --- a/substrate/primitives/statement-store/src/ecies.rs +++ b/substrate/primitives/statement-store/src/ecies.rs @@ -148,7 +148,7 @@ mod test { #[test] fn basic_ed25519_encryption() { let (pair, _) = sp_core::ed25519::Pair::generate(); - let pk = pair.into(); + let pk = pair.public(); let plain_message = b"An important secret message"; let encrypted = encrypt_ed25519(&pk, plain_message).unwrap(); -- GitLab From cc1e6ac301ea88e3cb3253a84e4c6aa28f2d8f87 Mon Sep 17 00:00:00 2001 From: Andrei Eres Date: Mon, 25 Mar 2024 16:57:46 +0100 Subject: [PATCH 093/187] [subsystem-benchmarks] Fix availability-write regression tests (#3698) Adds availability-write regression tests. The results for the `availability-distribution` subsystem are volatile, so I had to reduce the precision of the test. --- .gitlab/pipeline/test.yml | 1 + .../availability-distribution/Cargo.toml | 4 +- ...ilability-distribution-regression-bench.rs | 59 +-- .../availability-recovery-regression-bench.rs | 53 ++- polkadot/node/subsystem-bench/Cargo.toml | 2 +- .../src/cli/subsystem-bench.rs | 14 +- .../src/lib/availability/mod.rs | 396 ++++-------------- .../src/lib/availability/test_state.rs | 268 ++++++++++++ .../subsystem-bench/src/lib/environment.rs | 1 + polkadot/node/subsystem-bench/src/lib/lib.rs | 1 - .../subsystem-bench/src/lib/mock/av_store.rs | 1 + .../src/lib/mock/runtime_api.rs | 2 + .../node/subsystem-bench/src/lib/usage.rs | 15 +- .../node/subsystem-bench/src/lib/utils.rs | 76 ---- 14 files changed, 435 insertions(+), 458 deletions(-) rename polkadot/node/network/availability-distribution/{tests => benches}/availability-distribution-regression-bench.rs (57%) create mode 100644 polkadot/node/subsystem-bench/src/lib/availability/test_state.rs delete mode 100644 polkadot/node/subsystem-bench/src/lib/utils.rs diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index d244316000a..476ac6333f5 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -503,6 +503,7 @@ subsystem-regression-tests: - .run-immediately script: - cargo bench --profile=testnet -p polkadot-availability-recovery --bench availability-recovery-regression-bench --features subsystem-benchmarks + - cargo bench --profile=testnet -p polkadot-availability-distribution --bench availability-distribution-regression-bench --features subsystem-benchmarks tags: - benchmark allow_failure: true diff --git a/polkadot/node/network/availability-distribution/Cargo.toml b/polkadot/node/network/availability-distribution/Cargo.toml index 182d92cb163..ac606bd377f 100644 --- a/polkadot/node/network/availability-distribution/Cargo.toml +++ b/polkadot/node/network/availability-distribution/Cargo.toml @@ -39,9 +39,9 @@ polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } polkadot-subsystem-bench = { path = "../../subsystem-bench" } -[[test]] +[[bench]] name = "availability-distribution-regression-bench" -path = "tests/availability-distribution-regression-bench.rs" +path = "benches/availability-distribution-regression-bench.rs" harness = false required-features = ["subsystem-benchmarks"] diff --git a/polkadot/node/network/availability-distribution/tests/availability-distribution-regression-bench.rs b/polkadot/node/network/availability-distribution/benches/availability-distribution-regression-bench.rs similarity index 57% rename from polkadot/node/network/availability-distribution/tests/availability-distribution-regression-bench.rs rename to polkadot/node/network/availability-distribution/benches/availability-distribution-regression-bench.rs index bdab11298d5..019eb122208 100644 --- a/polkadot/node/network/availability-distribution/tests/availability-distribution-regression-bench.rs +++ b/polkadot/node/network/availability-distribution/benches/availability-distribution-regression-bench.rs @@ -24,46 +24,55 @@ //! - availability-store use polkadot_subsystem_bench::{ - availability::{benchmark_availability_write, prepare_test, TestDataAvailability, TestState}, + availability::{benchmark_availability_write, prepare_test, TestState}, configuration::TestConfiguration, - utils::{warm_up_and_benchmark, WarmUpOptions}, + usage::BenchmarkUsage, }; +use std::io::Write; + +const BENCH_COUNT: usize = 50; fn main() -> Result<(), String> { let mut messages = vec![]; let mut config = TestConfiguration::default(); - // A single node effort roughly n_cores * needed_approvals / n_validators = 60 * 30 / 300 - config.n_cores = 6; + // A single node effort roughly + config.n_cores = 10; + config.n_validators = 500; config.num_blocks = 3; config.generate_pov_sizes(); + let state = TestState::new(&config); - let usage = warm_up_and_benchmark( - WarmUpOptions::new(&[ - "availability-distribution", - "bitfield-distribution", - "availability-store", - ]), - || { - let mut state = TestState::new(&config); - let (mut env, _protocol_config) = - prepare_test(config.clone(), &mut state, TestDataAvailability::Write, false); + println!("Benchmarking..."); + let usages: Vec = (0..BENCH_COUNT) + .map(|n| { + print!("\r[{}{}]", "#".repeat(n), "_".repeat(BENCH_COUNT - n)); + std::io::stdout().flush().unwrap(); + let (mut env, _cfgs) = prepare_test( + &state, + polkadot_subsystem_bench::availability::TestDataAvailability::Write, + false, + ); env.runtime().block_on(benchmark_availability_write( "data_availability_write", &mut env, - state, + &state, )) - }, - )?; - println!("{}", usage); + }) + .collect(); + println!("\rDone!{}", " ".repeat(BENCH_COUNT)); + let average_usage = BenchmarkUsage::average(&usages); + println!("{}", average_usage); - messages.extend(usage.check_network_usage(&[ - ("Received from peers", 443.333, 0.05), - ("Sent to peers", 21818.555, 0.05), + // We expect no variance for received and sent + // but use 0.001 because we operate with floats + messages.extend(average_usage.check_network_usage(&[ + ("Received from peers", 433.3, 0.001), + ("Sent to peers", 18480.0, 0.001), ])); - messages.extend(usage.check_cpu_usage(&[ - ("availability-distribution", 0.011, 0.05), - ("bitfield-distribution", 0.029, 0.05), - ("availability-store", 0.232, 0.05), + messages.extend(average_usage.check_cpu_usage(&[ + ("availability-distribution", 0.012, 0.05), + ("availability-store", 0.153, 0.05), + ("bitfield-distribution", 0.026, 0.05), ])); if messages.is_empty() { diff --git a/polkadot/node/network/availability-recovery/benches/availability-recovery-regression-bench.rs b/polkadot/node/network/availability-recovery/benches/availability-recovery-regression-bench.rs index 42b1787e045..5e8b81be82d 100644 --- a/polkadot/node/network/availability-recovery/benches/availability-recovery-regression-bench.rs +++ b/polkadot/node/network/availability-recovery/benches/availability-recovery-regression-bench.rs @@ -14,9 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! availability-write regression tests +//! availability-read regression tests //! -//! Availability write benchmark based on Kusama parameters and scale. +//! Availability read benchmark based on Kusama parameters and scale. //! //! Subsystems involved: //! - availability-recovery @@ -27,8 +27,11 @@ use polkadot_subsystem_bench::{ TestDataAvailability, TestState, }, configuration::TestConfiguration, - utils::{warm_up_and_benchmark, WarmUpOptions}, + usage::BenchmarkUsage, }; +use std::io::Write; + +const BENCH_COUNT: usize = 50; fn main() -> Result<(), String> { let mut messages = vec![]; @@ -38,27 +41,33 @@ fn main() -> Result<(), String> { config.num_blocks = 3; config.generate_pov_sizes(); - let usage = warm_up_and_benchmark(WarmUpOptions::new(&["availability-recovery"]), || { - let mut state = TestState::new(&config); - let (mut env, _protocol_config) = prepare_test( - config.clone(), - &mut state, - TestDataAvailability::Read(options.clone()), - false, - ); - env.runtime().block_on(benchmark_availability_read( - "data_availability_read", - &mut env, - state, - )) - })?; - println!("{}", usage); + let state = TestState::new(&config); + + println!("Benchmarking..."); + let usages: Vec = (0..BENCH_COUNT) + .map(|n| { + print!("\r[{}{}]", "#".repeat(n), "_".repeat(BENCH_COUNT - n)); + std::io::stdout().flush().unwrap(); + let (mut env, _cfgs) = + prepare_test(&state, TestDataAvailability::Read(options.clone()), false); + env.runtime().block_on(benchmark_availability_read( + "data_availability_read", + &mut env, + &state, + )) + }) + .collect(); + println!("\rDone!{}", " ".repeat(BENCH_COUNT)); + let average_usage = BenchmarkUsage::average(&usages); + println!("{}", average_usage); - messages.extend(usage.check_network_usage(&[ - ("Received from peers", 307200.000, 0.05), - ("Sent to peers", 1.667, 0.05), + // We expect no variance for received and sent + // but use 0.001 because we operate with floats + messages.extend(average_usage.check_network_usage(&[ + ("Received from peers", 307200.000, 0.001), + ("Sent to peers", 1.667, 0.001), ])); - messages.extend(usage.check_cpu_usage(&[("availability-recovery", 11.500, 0.05)])); + messages.extend(average_usage.check_cpu_usage(&[("availability-recovery", 11.500, 0.05)])); if messages.is_empty() { Ok(()) diff --git a/polkadot/node/subsystem-bench/Cargo.toml b/polkadot/node/subsystem-bench/Cargo.toml index 71711ad0fbd..2570fe9cfa2 100644 --- a/polkadot/node/subsystem-bench/Cargo.toml +++ b/polkadot/node/subsystem-bench/Cargo.toml @@ -56,7 +56,7 @@ bitvec = "1.0.1" kvdb-memorydb = "0.13.0" parity-scale-codec = { version = "3.6.1", features = ["derive", "std"] } -tokio = "1.24.2" +tokio = { version = "1.24.2", features = ["rt-multi-thread", "parking_lot"] } clap-num = "1.0.2" polkadot-node-subsystem-test-helpers = { path = "../subsystem-test-helpers" } sp-keyring = { path = "../../../substrate/primitives/keyring" } diff --git a/polkadot/node/subsystem-bench/src/cli/subsystem-bench.rs b/polkadot/node/subsystem-bench/src/cli/subsystem-bench.rs index deb351360d7..10953b6c783 100644 --- a/polkadot/node/subsystem-bench/src/cli/subsystem-bench.rs +++ b/polkadot/node/subsystem-bench/src/cli/subsystem-bench.rs @@ -136,31 +136,29 @@ impl BenchCli { let usage = match objective { TestObjective::DataAvailabilityRead(opts) => { - let mut state = availability::TestState::new(&test_config); + let state = availability::TestState::new(&test_config); let (mut env, _protocol_config) = availability::prepare_test( - test_config, - &mut state, + &state, availability::TestDataAvailability::Read(opts), true, ); env.runtime().block_on(availability::benchmark_availability_read( &benchmark_name, &mut env, - state, + &state, )) }, TestObjective::DataAvailabilityWrite => { - let mut state = availability::TestState::new(&test_config); + let state = availability::TestState::new(&test_config); let (mut env, _protocol_config) = availability::prepare_test( - test_config, - &mut state, + &state, availability::TestDataAvailability::Write, true, ); env.runtime().block_on(availability::benchmark_availability_write( &benchmark_name, &mut env, - state, + &state, )) }, TestObjective::ApprovalVoting(ref options) => { diff --git a/polkadot/node/subsystem-bench/src/lib/availability/mod.rs b/polkadot/node/subsystem-bench/src/lib/availability/mod.rs index dc4e1e40310..765afdd5912 100644 --- a/polkadot/node/subsystem-bench/src/lib/availability/mod.rs +++ b/polkadot/node/subsystem-bench/src/lib/availability/mod.rs @@ -15,11 +15,11 @@ // along with Polkadot. If not, see . use crate::{ - configuration::TestConfiguration, + availability::av_store_helpers::new_av_store, dummy_builder, environment::{TestEnvironment, TestEnvironmentDependencies, GENESIS_HASH}, mock::{ - av_store::{self, MockAvailabilityStore}, + av_store::{self, MockAvailabilityStore, NetworkAvailabilityState}, chain_api::{ChainApiState, MockChainApi}, network_bridge::{self, MockNetworkBridgeRx, MockNetworkBridgeTx}, runtime_api::{self, MockRuntimeApi}, @@ -28,12 +28,8 @@ use crate::{ network::new_network, usage::BenchmarkUsage, }; -use av_store::NetworkAvailabilityState; -use av_store_helpers::new_av_store; -use bitvec::bitvec; use colored::Colorize; use futures::{channel::oneshot, stream::FuturesUnordered, StreamExt}; -use itertools::Itertools; use parity_scale_codec::Encode; use polkadot_availability_bitfield_distribution::BitfieldDistribution; use polkadot_availability_distribution::{ @@ -43,37 +39,27 @@ use polkadot_availability_recovery::AvailabilityRecoverySubsystem; use polkadot_node_core_av_store::AvailabilityStoreSubsystem; use polkadot_node_metrics::metrics::Metrics; use polkadot_node_network_protocol::{ - request_response::{v1::ChunkFetchingRequest, IncomingRequest, ReqProtocolNames}, - OurView, Versioned, VersionedValidationProtocol, + request_response::{IncomingRequest, ReqProtocolNames}, + OurView, }; -use polkadot_node_primitives::{AvailableData, BlockData, ErasureChunk, PoV}; use polkadot_node_subsystem::{ messages::{AllMessages, AvailabilityRecoveryMessage}, Overseer, OverseerConnector, SpawnGlue, }; -use polkadot_node_subsystem_test_helpers::{ - derive_erasure_chunks_with_proofs_and_root, mock::new_block_import_info, -}; use polkadot_node_subsystem_types::{ messages::{AvailabilityStoreMessage, NetworkBridgeEvent}, Span, }; use polkadot_overseer::{metrics::Metrics as OverseerMetrics, Handle as OverseerHandle}; -use polkadot_primitives::{ - AvailabilityBitfield, BlockNumber, CandidateHash, CandidateReceipt, GroupIndex, Hash, HeadData, - Header, PersistedValidationData, Signed, SigningContext, ValidatorIndex, -}; -use polkadot_primitives_test_helpers::{dummy_candidate_receipt, dummy_hash}; -use sc_network::{ - request_responses::{IncomingRequest as RawIncomingRequest, ProtocolConfig}, - PeerId, -}; +use polkadot_primitives::GroupIndex; +use sc_network::request_responses::{IncomingRequest as RawIncomingRequest, ProtocolConfig}; use sc_service::SpawnTaskHandle; use serde::{Deserialize, Serialize}; -use sp_core::H256; -use std::{collections::HashMap, iter::Cycle, ops::Sub, sync::Arc, time::Instant}; +use std::{ops::Sub, sync::Arc, time::Instant}; +pub use test_state::TestState; mod av_store_helpers; +mod test_state; const LOG_TARGET: &str = "subsystem-bench::availability"; @@ -149,94 +135,48 @@ fn build_overseer_for_availability_write( (overseer, OverseerHandle::new(raw_handle)) } -/// Takes a test configuration and uses it to create the `TestEnvironment`. pub fn prepare_test( - config: TestConfiguration, - state: &mut TestState, - mode: TestDataAvailability, - with_prometheus_endpoint: bool, -) -> (TestEnvironment, Vec) { - prepare_test_inner( - config, - state, - mode, - TestEnvironmentDependencies::default(), - with_prometheus_endpoint, - ) -} - -fn prepare_test_inner( - config: TestConfiguration, - state: &mut TestState, + state: &TestState, mode: TestDataAvailability, - dependencies: TestEnvironmentDependencies, with_prometheus_endpoint: bool, ) -> (TestEnvironment, Vec) { - // Generate test authorities. - let test_authorities = config.generate_authorities(); - - let mut candidate_hashes: HashMap> = HashMap::new(); - - // Prepare per block candidates. - // Genesis block is always finalized, so we start at 1. - for block_num in 1..=config.num_blocks { - for _ in 0..config.n_cores { - candidate_hashes - .entry(Hash::repeat_byte(block_num as u8)) - .or_default() - .push(state.next_candidate().expect("Cycle iterator")) - } - - // First candidate is our backed candidate. - state.backed_candidates.push( - candidate_hashes - .get(&Hash::repeat_byte(block_num as u8)) - .expect("just inserted above") - .first() - .expect("just inserted above") - .clone(), - ); - } - - let runtime_api = runtime_api::MockRuntimeApi::new( - config.clone(), - test_authorities.clone(), - candidate_hashes, - Default::default(), - Default::default(), - 0, - ); - - let availability_state = NetworkAvailabilityState { - candidate_hashes: state.candidate_hashes.clone(), - available_data: state.available_data.clone(), - chunks: state.chunks.clone(), - }; - - let mut req_cfgs = Vec::new(); - let (collation_req_receiver, collation_req_cfg) = IncomingRequest::get_config_receiver(&ReqProtocolNames::new(GENESIS_HASH, None)); - req_cfgs.push(collation_req_cfg); - let (pov_req_receiver, pov_req_cfg) = IncomingRequest::get_config_receiver(&ReqProtocolNames::new(GENESIS_HASH, None)); - let (chunk_req_receiver, chunk_req_cfg) = IncomingRequest::get_config_receiver(&ReqProtocolNames::new(GENESIS_HASH, None)); - req_cfgs.push(pov_req_cfg); + let req_cfgs = vec![collation_req_cfg, pov_req_cfg]; - let (network, network_interface, network_receiver) = - new_network(&config, &dependencies, &test_authorities, vec![Arc::new(availability_state)]); + let dependencies = TestEnvironmentDependencies::default(); + let availability_state = NetworkAvailabilityState { + candidate_hashes: state.candidate_hashes.clone(), + available_data: state.available_data.clone(), + chunks: state.chunks.clone(), + }; + let (network, network_interface, network_receiver) = new_network( + &state.config, + &dependencies, + &state.test_authorities, + vec![Arc::new(availability_state.clone())], + ); let network_bridge_tx = network_bridge::MockNetworkBridgeTx::new( network.clone(), network_interface.subsystem_sender(), - test_authorities.clone(), + state.test_authorities.clone(), ); - let network_bridge_rx = - network_bridge::MockNetworkBridgeRx::new(network_receiver, Some(chunk_req_cfg.clone())); + network_bridge::MockNetworkBridgeRx::new(network_receiver, Some(chunk_req_cfg)); + + let runtime_api = runtime_api::MockRuntimeApi::new( + state.config.clone(), + state.test_authorities.clone(), + state.candidate_receipts.clone(), + Default::default(), + Default::default(), + 0, + ); let (overseer, overseer_handle) = match &mode { TestDataAvailability::Read(options) => { @@ -271,27 +211,12 @@ fn prepare_test_inner( }, TestDataAvailability::Write => { let availability_distribution = AvailabilityDistributionSubsystem::new( - test_authorities.keyring.keystore(), + state.test_authorities.keyring.keystore(), IncomingRequestReceivers { pov_req_receiver, chunk_req_receiver }, Metrics::try_register(&dependencies.registry).unwrap(), ); - let block_headers = (1..=config.num_blocks) - .map(|block_number| { - ( - Hash::repeat_byte(block_number as u8), - Header { - digest: Default::default(), - number: block_number as BlockNumber, - parent_hash: Default::default(), - extrinsics_root: Default::default(), - state_root: Default::default(), - }, - ) - }) - .collect::>(); - - let chain_api_state = ChainApiState { block_headers }; + let chain_api_state = ChainApiState { block_headers: state.block_headers.clone() }; let chain_api = MockChainApi::new(chain_api_state); let bitfield_distribution = BitfieldDistribution::new(Metrics::try_register(&dependencies.registry).unwrap()); @@ -311,167 +236,42 @@ fn prepare_test_inner( ( TestEnvironment::new( dependencies, - config, + state.config.clone(), network, overseer, overseer_handle, - test_authorities, + state.test_authorities.clone(), with_prometheus_endpoint, ), req_cfgs, ) } -#[derive(Clone)] -pub struct TestState { - // Full test configuration - config: TestConfiguration, - // A cycle iterator on all PoV sizes used in the test. - pov_sizes: Cycle>, - // Generated candidate receipts to be used in the test - candidates: Cycle>, - // Map from pov size to candidate index - pov_size_to_candidate: HashMap, - // Map from generated candidate hashes to candidate index in `available_data` - // and `chunks`. - candidate_hashes: HashMap, - // Per candidate index receipts. - candidate_receipt_templates: Vec, - // Per candidate index `AvailableData` - available_data: Vec, - // Per candiadte index chunks - chunks: Vec>, - // Per relay chain block - candidate backed by our backing group - backed_candidates: Vec, -} - -impl TestState { - pub fn next_candidate(&mut self) -> Option { - let candidate = self.candidates.next(); - let candidate_hash = candidate.as_ref().unwrap().hash(); - gum::trace!(target: LOG_TARGET, "Next candidate selected {:?}", candidate_hash); - candidate - } - - /// Generate candidates to be used in the test. - fn generate_candidates(&mut self) { - let count = self.config.n_cores * self.config.num_blocks; - gum::info!(target: LOG_TARGET,"{}", format!("Pre-generating {} candidates.", count).bright_blue()); - - // Generate all candidates - self.candidates = (0..count) - .map(|index| { - let pov_size = self.pov_sizes.next().expect("This is a cycle; qed"); - let candidate_index = *self - .pov_size_to_candidate - .get(&pov_size) - .expect("pov_size always exists; qed"); - let mut candidate_receipt = - self.candidate_receipt_templates[candidate_index].clone(); - - // Make it unique. - candidate_receipt.descriptor.relay_parent = Hash::from_low_u64_be(index as u64); - // Store the new candidate in the state - self.candidate_hashes.insert(candidate_receipt.hash(), candidate_index); - - gum::debug!(target: LOG_TARGET, candidate_hash = ?candidate_receipt.hash(), "new candidate"); - - candidate_receipt - }) - .collect::>() - .into_iter() - .cycle(); - } - - pub fn new(config: &TestConfiguration) -> Self { - let config = config.clone(); - - let mut chunks = Vec::new(); - let mut available_data = Vec::new(); - let mut candidate_receipt_templates = Vec::new(); - let mut pov_size_to_candidate = HashMap::new(); - - // we use it for all candidates. - let persisted_validation_data = PersistedValidationData { - parent_head: HeadData(vec![7, 8, 9]), - relay_parent_number: Default::default(), - max_pov_size: 1024, - relay_parent_storage_root: Default::default(), - }; - - // For each unique pov we create a candidate receipt. - for (index, pov_size) in config.pov_sizes().iter().cloned().unique().enumerate() { - gum::info!(target: LOG_TARGET, index, pov_size, "{}", "Generating template candidate".bright_blue()); - - let mut candidate_receipt = dummy_candidate_receipt(dummy_hash()); - let pov = PoV { block_data: BlockData(vec![index as u8; pov_size]) }; - - let new_available_data = AvailableData { - validation_data: persisted_validation_data.clone(), - pov: Arc::new(pov), - }; - - let (new_chunks, erasure_root) = derive_erasure_chunks_with_proofs_and_root( - config.n_validators, - &new_available_data, - |_, _| {}, - ); - - candidate_receipt.descriptor.erasure_root = erasure_root; - - chunks.push(new_chunks); - available_data.push(new_available_data); - pov_size_to_candidate.insert(pov_size, index); - candidate_receipt_templates.push(candidate_receipt); - } - - gum::info!(target: LOG_TARGET, "{}","Created test environment.".bright_blue()); - - let mut _self = Self { - available_data, - candidate_receipt_templates, - chunks, - pov_size_to_candidate, - pov_sizes: Vec::from(config.pov_sizes()).into_iter().cycle(), - candidate_hashes: HashMap::new(), - candidates: Vec::new().into_iter().cycle(), - backed_candidates: Vec::new(), - config, - }; - - _self.generate_candidates(); - _self - } - - pub fn backed_candidates(&mut self) -> &mut Vec { - &mut self.backed_candidates - } -} - pub async fn benchmark_availability_read( benchmark_name: &str, env: &mut TestEnvironment, - mut state: TestState, + state: &TestState, ) -> BenchmarkUsage { let config = env.config().clone(); - env.import_block(new_block_import_info(Hash::repeat_byte(1), 1)).await; - - let test_start = Instant::now(); - let mut batch = FuturesUnordered::new(); - let mut availability_bytes = 0u128; - env.metrics().set_n_validators(config.n_validators); env.metrics().set_n_cores(config.n_cores); - for block_num in 1..=env.config().num_blocks { + let mut batch = FuturesUnordered::new(); + let mut availability_bytes = 0u128; + let mut candidates = state.candidates.clone(); + let test_start = Instant::now(); + for block_info in state.block_infos.iter() { + let block_num = block_info.number as usize; gum::info!(target: LOG_TARGET, "Current block {}/{}", block_num, env.config().num_blocks); env.metrics().set_current_block(block_num); let block_start_ts = Instant::now(); + env.import_block(block_info.clone()).await; + for candidate_num in 0..config.n_cores as u64 { let candidate = - state.next_candidate().expect("We always send up to n_cores*num_blocks; qed"); + candidates.next().expect("We always send up to n_cores*num_blocks; qed"); let (tx, rx) = oneshot::channel(); batch.push(rx); @@ -519,7 +319,7 @@ pub async fn benchmark_availability_read( pub async fn benchmark_availability_write( benchmark_name: &str, env: &mut TestEnvironment, - mut state: TestState, + state: &TestState, ) -> BenchmarkUsage { let config = env.config().clone(); @@ -527,7 +327,7 @@ pub async fn benchmark_availability_write( env.metrics().set_n_cores(config.n_cores); gum::info!(target: LOG_TARGET, "Seeding availability store with candidates ..."); - for backed_candidate in state.backed_candidates().clone() { + for backed_candidate in state.backed_candidates.clone() { let candidate_index = *state.candidate_hashes.get(&backed_candidate.hash()).unwrap(); let available_data = state.available_data[candidate_index].clone(); let (tx, rx) = oneshot::channel(); @@ -550,15 +350,14 @@ pub async fn benchmark_availability_write( gum::info!(target: LOG_TARGET, "Done"); let test_start = Instant::now(); - - for block_num in 1..=env.config().num_blocks { + for block_info in state.block_infos.iter() { + let block_num = block_info.number as usize; gum::info!(target: LOG_TARGET, "Current block #{}", block_num); env.metrics().set_current_block(block_num); let block_start_ts = Instant::now(); - let relay_block_hash = Hash::repeat_byte(block_num as u8); - env.import_block(new_block_import_info(relay_block_hash, block_num as BlockNumber)) - .await; + let relay_block_hash = block_info.hash; + env.import_block(block_info.clone()).await; // Inform bitfield distribution about our view of current test block let message = polkadot_node_subsystem_types::messages::BitfieldDistributionMessage::NetworkBridgeUpdate( @@ -569,20 +368,13 @@ pub async fn benchmark_availability_write( let chunk_fetch_start_ts = Instant::now(); // Request chunks of our own backed candidate from all other validators. - let mut receivers = Vec::new(); - for index in 1..config.n_validators { + let payloads = state.chunk_fetching_requests.get(block_num - 1).expect("pregenerated"); + let receivers = (1..config.n_validators).filter_map(|index| { let (pending_response, pending_response_receiver) = oneshot::channel(); - let request = RawIncomingRequest { - peer: PeerId::random(), - payload: ChunkFetchingRequest { - candidate_hash: state.backed_candidates()[block_num - 1].hash(), - index: ValidatorIndex(index as u32), - } - .encode(), - pending_response, - }; - + let peer_id = *env.authorities().peer_ids.get(index).expect("all validators have ids"); + let payload = payloads.get(index).expect("pregenerated").clone(); + let request = RawIncomingRequest { peer: peer_id, payload, pending_response }; let peer = env .authorities() .validator_authority_id @@ -592,59 +384,39 @@ pub async fn benchmark_availability_write( if env.network().is_peer_connected(peer) && env.network().send_request_from_peer(peer, request).is_ok() { - receivers.push(pending_response_receiver); + Some(pending_response_receiver) + } else { + None } - } + }); gum::info!(target: LOG_TARGET, "Waiting for all emulated peers to receive their chunk from us ..."); - for receiver in receivers.into_iter() { - let response = receiver.await.expect("Chunk is always served successfully"); - // TODO: check if chunk is the one the peer expects to receive. - assert!(response.result.is_ok()); - } - let chunk_fetch_duration = Instant::now().sub(chunk_fetch_start_ts).as_millis(); + let responses = futures::future::try_join_all(receivers) + .await + .expect("Chunk is always served successfully"); + // TODO: check if chunk is the one the peer expects to receive. + assert!(responses.iter().all(|v| v.result.is_ok())); + let chunk_fetch_duration = Instant::now().sub(chunk_fetch_start_ts).as_millis(); gum::info!(target: LOG_TARGET, "All chunks received in {}ms", chunk_fetch_duration); - let signing_context = SigningContext { session_index: 0, parent_hash: relay_block_hash }; let network = env.network().clone(); let authorities = env.authorities().clone(); - let n_validators = config.n_validators; // Spawn a task that will generate `n_validator` - 1 signed bitfiends and // send them from the emulated peers to the subsystem. // TODO: Implement topology. - env.spawn_blocking("send-bitfields", async move { - for index in 1..n_validators { - let validator_public = - authorities.validator_public.get(index).expect("All validator keys are known"); - - // Node has all the chunks in the world. - let payload: AvailabilityBitfield = - AvailabilityBitfield(bitvec![u8, bitvec::order::Lsb0; 1u8; 32]); - // TODO(soon): Use pre-signed messages. This is quite intensive on the CPU. - let signed_bitfield = Signed::::sign( - &authorities.keyring.keystore(), - payload, - &signing_context, - ValidatorIndex(index as u32), - validator_public, - ) - .ok() - .flatten() - .expect("should be signed"); - - let from_peer = &authorities.validator_authority_id[index]; - - let message = peer_bitfield_message_v2(relay_block_hash, signed_bitfield); + let messages = state.signed_bitfields.get(&relay_block_hash).expect("pregenerated").clone(); + for index in 1..config.n_validators { + let from_peer = &authorities.validator_authority_id[index]; + let message = messages.get(index).expect("pregenerated").clone(); - // Send the action from peer only if it is connected to our node. - if network.is_peer_connected(from_peer) { - let _ = network.send_message_from_peer(from_peer, message); - } + // Send the action from peer only if it is connected to our node. + if network.is_peer_connected(from_peer) { + let _ = network.send_message_from_peer(from_peer, message); } - }); + } gum::info!( "Waiting for {} bitfields to be received and processed", @@ -679,17 +451,3 @@ pub async fn benchmark_availability_write( &["availability-distribution", "bitfield-distribution", "availability-store"], ) } - -pub fn peer_bitfield_message_v2( - relay_hash: H256, - signed_bitfield: Signed, -) -> VersionedValidationProtocol { - let bitfield = polkadot_node_network_protocol::v2::BitfieldDistributionMessage::Bitfield( - relay_hash, - signed_bitfield.into(), - ); - - Versioned::V2(polkadot_node_network_protocol::v2::ValidationProtocol::BitfieldDistribution( - bitfield, - )) -} diff --git a/polkadot/node/subsystem-bench/src/lib/availability/test_state.rs b/polkadot/node/subsystem-bench/src/lib/availability/test_state.rs new file mode 100644 index 00000000000..c328ffedf91 --- /dev/null +++ b/polkadot/node/subsystem-bench/src/lib/availability/test_state.rs @@ -0,0 +1,268 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use crate::configuration::{TestAuthorities, TestConfiguration}; +use bitvec::bitvec; +use colored::Colorize; +use itertools::Itertools; +use parity_scale_codec::Encode; +use polkadot_node_network_protocol::{ + request_response::v1::ChunkFetchingRequest, Versioned, VersionedValidationProtocol, +}; +use polkadot_node_primitives::{AvailableData, BlockData, ErasureChunk, PoV}; +use polkadot_node_subsystem_test_helpers::{ + derive_erasure_chunks_with_proofs_and_root, mock::new_block_import_info, +}; +use polkadot_overseer::BlockInfo; +use polkadot_primitives::{ + AvailabilityBitfield, BlockNumber, CandidateHash, CandidateReceipt, Hash, HeadData, Header, + PersistedValidationData, Signed, SigningContext, ValidatorIndex, +}; +use polkadot_primitives_test_helpers::{dummy_candidate_receipt, dummy_hash}; +use sp_core::H256; +use std::{collections::HashMap, iter::Cycle, sync::Arc}; + +const LOG_TARGET: &str = "subsystem-bench::availability::test_state"; + +#[derive(Clone)] +pub struct TestState { + // Full test configuration + pub config: TestConfiguration, + // A cycle iterator on all PoV sizes used in the test. + pub pov_sizes: Cycle>, + // Generated candidate receipts to be used in the test + pub candidates: Cycle>, + // Map from pov size to candidate index + pub pov_size_to_candidate: HashMap, + // Map from generated candidate hashes to candidate index in `available_data` and `chunks`. + pub candidate_hashes: HashMap, + // Per candidate index receipts. + pub candidate_receipt_templates: Vec, + // Per candidate index `AvailableData` + pub available_data: Vec, + // Per candiadte index chunks + pub chunks: Vec>, + // Per relay chain block - candidate backed by our backing group + pub backed_candidates: Vec, + // Relay chain block infos + pub block_infos: Vec, + // Chung fetching requests for backed candidates + pub chunk_fetching_requests: Vec>>, + // Pregenerated signed availability bitfields + pub signed_bitfields: HashMap>, + // Relay chain block headers + pub block_headers: HashMap, + // Authority keys for the network emulation. + pub test_authorities: TestAuthorities, + // Map from generated candidate receipts + pub candidate_receipts: HashMap>, +} + +impl TestState { + pub fn new(config: &TestConfiguration) -> Self { + let mut test_state = Self { + available_data: Default::default(), + candidate_receipt_templates: Default::default(), + chunks: Default::default(), + pov_size_to_candidate: Default::default(), + pov_sizes: Vec::from(config.pov_sizes()).into_iter().cycle(), + candidate_hashes: HashMap::new(), + candidates: Vec::new().into_iter().cycle(), + backed_candidates: Vec::new(), + config: config.clone(), + block_infos: Default::default(), + chunk_fetching_requests: Default::default(), + signed_bitfields: Default::default(), + candidate_receipts: Default::default(), + block_headers: Default::default(), + test_authorities: config.generate_authorities(), + }; + + // we use it for all candidates. + let persisted_validation_data = PersistedValidationData { + parent_head: HeadData(vec![7, 8, 9]), + relay_parent_number: Default::default(), + max_pov_size: 1024, + relay_parent_storage_root: Default::default(), + }; + + // For each unique pov we create a candidate receipt. + for (index, pov_size) in config.pov_sizes().iter().cloned().unique().enumerate() { + gum::info!(target: LOG_TARGET, index, pov_size, "{}", "Generating template candidate".bright_blue()); + + let mut candidate_receipt = dummy_candidate_receipt(dummy_hash()); + let pov = PoV { block_data: BlockData(vec![index as u8; pov_size]) }; + + let new_available_data = AvailableData { + validation_data: persisted_validation_data.clone(), + pov: Arc::new(pov), + }; + + let (new_chunks, erasure_root) = derive_erasure_chunks_with_proofs_and_root( + config.n_validators, + &new_available_data, + |_, _| {}, + ); + + candidate_receipt.descriptor.erasure_root = erasure_root; + + test_state.chunks.push(new_chunks); + test_state.available_data.push(new_available_data); + test_state.pov_size_to_candidate.insert(pov_size, index); + test_state.candidate_receipt_templates.push(candidate_receipt); + } + + test_state.block_infos = (1..=config.num_blocks) + .map(|block_num| { + let relay_block_hash = Hash::repeat_byte(block_num as u8); + new_block_import_info(relay_block_hash, block_num as BlockNumber) + }) + .collect(); + + test_state.block_headers = test_state + .block_infos + .iter() + .map(|info| { + ( + info.hash, + Header { + digest: Default::default(), + number: info.number, + parent_hash: info.parent_hash, + extrinsics_root: Default::default(), + state_root: Default::default(), + }, + ) + }) + .collect::>(); + + // Generate all candidates + let candidates_count = config.n_cores * config.num_blocks; + gum::info!(target: LOG_TARGET,"{}", format!("Pre-generating {} candidates.", candidates_count).bright_blue()); + test_state.candidates = (0..candidates_count) + .map(|index| { + let pov_size = test_state.pov_sizes.next().expect("This is a cycle; qed"); + let candidate_index = *test_state + .pov_size_to_candidate + .get(&pov_size) + .expect("pov_size always exists; qed"); + let mut candidate_receipt = + test_state.candidate_receipt_templates[candidate_index].clone(); + + // Make it unique. + candidate_receipt.descriptor.relay_parent = Hash::from_low_u64_be(index as u64); + // Store the new candidate in the state + test_state.candidate_hashes.insert(candidate_receipt.hash(), candidate_index); + + gum::debug!(target: LOG_TARGET, candidate_hash = ?candidate_receipt.hash(), "new candidate"); + + candidate_receipt + }) + .collect::>() + .into_iter() + .cycle(); + + // Prepare per block candidates. + // Genesis block is always finalized, so we start at 1. + for info in test_state.block_infos.iter() { + for _ in 0..config.n_cores { + let receipt = test_state.candidates.next().expect("Cycle iterator"); + test_state.candidate_receipts.entry(info.hash).or_default().push(receipt); + } + + // First candidate is our backed candidate. + test_state.backed_candidates.push( + test_state + .candidate_receipts + .get(&info.hash) + .expect("just inserted above") + .first() + .expect("just inserted above") + .clone(), + ); + } + + test_state.chunk_fetching_requests = test_state + .backed_candidates + .iter() + .map(|candidate| { + (0..config.n_validators) + .map(|index| { + ChunkFetchingRequest { + candidate_hash: candidate.hash(), + index: ValidatorIndex(index as u32), + } + .encode() + }) + .collect::>() + }) + .collect::>(); + + test_state.signed_bitfields = test_state + .block_infos + .iter() + .map(|block_info| { + let signing_context = + SigningContext { session_index: 0, parent_hash: block_info.hash }; + let messages = (0..config.n_validators) + .map(|index| { + let validator_public = test_state + .test_authorities + .validator_public + .get(index) + .expect("All validator keys are known"); + + // Node has all the chunks in the world. + let payload: AvailabilityBitfield = + AvailabilityBitfield(bitvec![u8, bitvec::order::Lsb0; 1u8; 32]); + let signed_bitfield = Signed::::sign( + &test_state.test_authorities.keyring.keystore(), + payload, + &signing_context, + ValidatorIndex(index as u32), + validator_public, + ) + .ok() + .flatten() + .expect("should be signed"); + + peer_bitfield_message_v2(block_info.hash, signed_bitfield) + }) + .collect::>(); + + (block_info.hash, messages) + }) + .collect(); + + gum::info!(target: LOG_TARGET, "{}","Created test environment.".bright_blue()); + + test_state + } +} + +fn peer_bitfield_message_v2( + relay_hash: H256, + signed_bitfield: Signed, +) -> VersionedValidationProtocol { + let bitfield = polkadot_node_network_protocol::v2::BitfieldDistributionMessage::Bitfield( + relay_hash, + signed_bitfield.into(), + ); + + Versioned::V2(polkadot_node_network_protocol::v2::ValidationProtocol::BitfieldDistribution( + bitfield, + )) +} diff --git a/polkadot/node/subsystem-bench/src/lib/environment.rs b/polkadot/node/subsystem-bench/src/lib/environment.rs index 958ed50d089..2d80d75a14a 100644 --- a/polkadot/node/subsystem-bench/src/lib/environment.rs +++ b/polkadot/node/subsystem-bench/src/lib/environment.rs @@ -118,6 +118,7 @@ fn new_runtime() -> tokio::runtime::Runtime { .thread_name("subsystem-bench") .enable_all() .thread_stack_size(3 * 1024 * 1024) + .worker_threads(4) .build() .unwrap() } diff --git a/polkadot/node/subsystem-bench/src/lib/lib.rs b/polkadot/node/subsystem-bench/src/lib/lib.rs index ef2724abc98..d06f2822a89 100644 --- a/polkadot/node/subsystem-bench/src/lib/lib.rs +++ b/polkadot/node/subsystem-bench/src/lib/lib.rs @@ -26,4 +26,3 @@ pub(crate) mod keyring; pub(crate) mod mock; pub(crate) mod network; pub mod usage; -pub mod utils; diff --git a/polkadot/node/subsystem-bench/src/lib/mock/av_store.rs b/polkadot/node/subsystem-bench/src/lib/mock/av_store.rs index 9064f17940f..080644da92a 100644 --- a/polkadot/node/subsystem-bench/src/lib/mock/av_store.rs +++ b/polkadot/node/subsystem-bench/src/lib/mock/av_store.rs @@ -41,6 +41,7 @@ const LOG_TARGET: &str = "subsystem-bench::av-store-mock"; /// Mockup helper. Contains Ccunks and full availability data of all parachain blocks /// used in a test. +#[derive(Clone)] pub struct NetworkAvailabilityState { pub candidate_hashes: HashMap, pub available_data: Vec, diff --git a/polkadot/node/subsystem-bench/src/lib/mock/runtime_api.rs b/polkadot/node/subsystem-bench/src/lib/mock/runtime_api.rs index 53faf562f03..3c39de870a2 100644 --- a/polkadot/node/subsystem-bench/src/lib/mock/runtime_api.rs +++ b/polkadot/node/subsystem-bench/src/lib/mock/runtime_api.rs @@ -36,6 +36,7 @@ use std::collections::HashMap; const LOG_TARGET: &str = "subsystem-bench::runtime-api-mock"; /// Minimal state to answer requests. +#[derive(Clone)] pub struct RuntimeApiState { // All authorities in the test, authorities: TestAuthorities, @@ -49,6 +50,7 @@ pub struct RuntimeApiState { } /// A mocked `runtime-api` subsystem. +#[derive(Clone)] pub struct MockRuntimeApi { state: RuntimeApiState, config: TestConfiguration, diff --git a/polkadot/node/subsystem-bench/src/lib/usage.rs b/polkadot/node/subsystem-bench/src/lib/usage.rs index ef60d67372a..7172969a8f9 100644 --- a/polkadot/node/subsystem-bench/src/lib/usage.rs +++ b/polkadot/node/subsystem-bench/src/lib/usage.rs @@ -17,6 +17,7 @@ //! Test usage implementation use colored::Colorize; +use itertools::Itertools; use serde::{Deserialize, Serialize}; use std::collections::HashMap; @@ -37,10 +38,16 @@ impl std::fmt::Display for BenchmarkUsage { self.network_usage .iter() .map(|v| v.to_string()) + .sorted() .collect::>() .join("\n"), format!("{:<32}{:>12}{:>12}", "CPU usage, seconds", "total", "per block").blue(), - self.cpu_usage.iter().map(|v| v.to_string()).collect::>().join("\n") + self.cpu_usage + .iter() + .map(|v| v.to_string()) + .sorted() + .collect::>() + .join("\n") ) } } @@ -101,8 +108,8 @@ fn check_resource_usage( None } else { Some(format!( - "The resource `{}` is expected to be equal to {} with a precision {}, but the current value is {}", - resource_name, base, precision, usage.per_block + "The resource `{}` is expected to be equal to {} with a precision {}, but the current value is {} ({})", + resource_name, base, precision, usage.per_block, diff )) } } else { @@ -119,7 +126,7 @@ pub struct ResourceUsage { impl std::fmt::Display for ResourceUsage { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{:<32}{:>12.3}{:>12.3}", self.resource_name.cyan(), self.total, self.per_block) + write!(f, "{:<32}{:>12.4}{:>12.4}", self.resource_name.cyan(), self.total, self.per_block) } } diff --git a/polkadot/node/subsystem-bench/src/lib/utils.rs b/polkadot/node/subsystem-bench/src/lib/utils.rs deleted file mode 100644 index 75b72cc11b9..00000000000 --- a/polkadot/node/subsystem-bench/src/lib/utils.rs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Polkadot is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . - -//! Test utils - -use crate::usage::BenchmarkUsage; -use std::io::{stdout, Write}; - -pub struct WarmUpOptions<'a> { - /// The maximum number of runs considered for marming up. - pub warm_up: usize, - /// The number of runs considered for benchmarking. - pub bench: usize, - /// The difference in CPU usage between runs considered as normal - pub precision: f64, - /// The subsystems whose CPU usage is checked during warm-up cycles - pub subsystems: &'a [&'a str], -} - -impl<'a> WarmUpOptions<'a> { - pub fn new(subsystems: &'a [&'a str]) -> Self { - Self { warm_up: 100, bench: 3, precision: 0.02, subsystems } - } -} - -pub fn warm_up_and_benchmark( - options: WarmUpOptions, - run: impl Fn() -> BenchmarkUsage, -) -> Result { - println!("Warming up..."); - let mut usages = Vec::with_capacity(options.bench); - - for n in 1..=options.warm_up { - let curr = run(); - if let Some(prev) = usages.last() { - let diffs = options - .subsystems - .iter() - .map(|&v| { - curr.cpu_usage_diff(prev, v) - .ok_or(format!("{} not found in benchmark {:?}", v, prev)) - }) - .collect::, String>>()?; - if !diffs.iter().all(|&v| v < options.precision) { - usages.clear(); - } - } - usages.push(curr); - print!("\r{}%", n * 100 / options.warm_up); - if usages.len() == options.bench { - println!("\rTook {} runs to warm up", n.saturating_sub(options.bench)); - break; - } - stdout().flush().unwrap(); - } - - if usages.len() != options.bench { - println!("Didn't warm up after {} runs", options.warm_up); - return Err("Can't warm up".to_string()) - } - - Ok(BenchmarkUsage::average(&usages)) -} -- GitLab From ea97863c56c573879564891fc83a9543f46bd95f Mon Sep 17 00:00:00 2001 From: Dcompoze Date: Tue, 26 Mar 2024 12:45:53 +0000 Subject: [PATCH 094/187] Fix formatting in Cargo.toml (#3842) Fixes formatting for https://github.com/paritytech/polkadot-sdk/pull/3698 --- polkadot/node/subsystem-bench/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/node/subsystem-bench/Cargo.toml b/polkadot/node/subsystem-bench/Cargo.toml index 2570fe9cfa2..05907e428f9 100644 --- a/polkadot/node/subsystem-bench/Cargo.toml +++ b/polkadot/node/subsystem-bench/Cargo.toml @@ -56,7 +56,7 @@ bitvec = "1.0.1" kvdb-memorydb = "0.13.0" parity-scale-codec = { version = "3.6.1", features = ["derive", "std"] } -tokio = { version = "1.24.2", features = ["rt-multi-thread", "parking_lot"] } +tokio = { version = "1.24.2", features = ["parking_lot", "rt-multi-thread"] } clap-num = "1.0.2" polkadot-node-subsystem-test-helpers = { path = "../subsystem-test-helpers" } sp-keyring = { path = "../../../substrate/primitives/keyring" } -- GitLab From b839c995c0b889508f2f8ee6a1807f38c043e922 Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Tue, 26 Mar 2024 14:09:11 +0100 Subject: [PATCH 095/187] Update bridges subtree (#3841) Updating the bridges subtree hopefully just one last time in this formula in order to make the final migration less verbose. --- bridges/bin/runtime-common/Cargo.toml | 2 +- .../chains/chain-asset-hub-rococo/Cargo.toml | 2 +- .../chains/chain-asset-hub-westend/Cargo.toml | 2 +- .../chains/chain-polkadot-bulletin/Cargo.toml | 2 +- .../docs/bridge-relayers-claim-rewards.png | Bin 0 -> 35621 bytes bridges/docs/bridge-relayers-deregister.png | Bin 0 -> 10115 bytes bridges/docs/bridge-relayers-register.png | Bin 0 -> 51026 bytes bridges/docs/running-relayer.md | 343 ++++++++++++++++++ bridges/modules/grandpa/Cargo.toml | 2 +- bridges/modules/messages/Cargo.toml | 2 +- bridges/modules/parachains/Cargo.toml | 2 +- bridges/modules/relayers/Cargo.toml | 2 +- .../modules/xcm-bridge-hub-router/Cargo.toml | 2 +- bridges/modules/xcm-bridge-hub/Cargo.toml | 2 +- bridges/primitives/header-chain/Cargo.toml | 2 +- bridges/primitives/messages/Cargo.toml | 2 +- bridges/primitives/parachains/Cargo.toml | 2 +- bridges/primitives/polkadot-core/Cargo.toml | 2 +- bridges/primitives/relayers/Cargo.toml | 2 +- bridges/primitives/runtime/Cargo.toml | 2 +- .../xcm-bridge-hub-router/Cargo.toml | 2 +- bridges/scripts/verify-pallets-build.sh | 3 + 22 files changed, 363 insertions(+), 17 deletions(-) create mode 100644 bridges/docs/bridge-relayers-claim-rewards.png create mode 100644 bridges/docs/bridge-relayers-deregister.png create mode 100644 bridges/docs/bridge-relayers-register.png create mode 100644 bridges/docs/running-relayer.md diff --git a/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml index fac88b20ca5..f00ba1c9734 100644 --- a/bridges/bin/runtime-common/Cargo.toml +++ b/bridges/bin/runtime-common/Cargo.toml @@ -14,7 +14,7 @@ workspace = true codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } hash-db = { version = "0.16.0", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } static_assertions = { version = "1.1", optional = true } # Bridge dependencies diff --git a/bridges/chains/chain-asset-hub-rococo/Cargo.toml b/bridges/chains/chain-asset-hub-rococo/Cargo.toml index 07c9b3b5289..55dc384badd 100644 --- a/bridges/chains/chain-asset-hub-rococo/Cargo.toml +++ b/bridges/chains/chain-asset-hub-rococo/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } # Substrate Dependencies frame-support = { path = "../../../substrate/frame/support", default-features = false } diff --git a/bridges/chains/chain-asset-hub-westend/Cargo.toml b/bridges/chains/chain-asset-hub-westend/Cargo.toml index f75236ee1b3..1379b099a2a 100644 --- a/bridges/chains/chain-asset-hub-westend/Cargo.toml +++ b/bridges/chains/chain-asset-hub-westend/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } # Substrate Dependencies frame-support = { path = "../../../substrate/frame/support", default-features = false } diff --git a/bridges/chains/chain-polkadot-bulletin/Cargo.toml b/bridges/chains/chain-polkadot-bulletin/Cargo.toml index d10c4043967..37e060d897c 100644 --- a/bridges/chains/chain-polkadot-bulletin/Cargo.toml +++ b/bridges/chains/chain-polkadot-bulletin/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } # Bridge Dependencies diff --git a/bridges/docs/bridge-relayers-claim-rewards.png b/bridges/docs/bridge-relayers-claim-rewards.png new file mode 100644 index 0000000000000000000000000000000000000000..d56b8dd871e8445e7cab49517123b0092ce09137 GIT binary patch literal 35621 zcmb@tbzD^6+CB`TAd-U8ogzp|mjcqEfP}=*4MR7KG>Ej)r4l0D-JK)S-QC^HZ*jio zd5-7(=lSQ|A4F%|Ywxw!y5qX9``RII6{WBqkvu{|Lc)@fmQY4QLd`@%LdJcF3clgr z_1*%1-FFa^QGEyw&xc0A;4`t~8x2PlsEMPCzP&M$sSVWH_=SU^y|J;4gBjFu52aBA zoWyFbs^KVZZ>;ZV4z;0DHMcefUm_v>&K~roV&|h8^#5J{yM&69o%1CX2e$zGO96H+ zPqo{xNJvyjG7_&$Dn zWI4CLRG2cFT;{s@nwPNQIH@Ga+%MlSB!4BtS&ToVq<|lj9!N*`PAWuVyA2K2r^up;6KN zbwIpjWkdctr7KuPSytk&Lozv9`LFY7I2XTs!F&9lBkFN>#+Sb?5d4|XuY}Ou=P1Ej!?v~{($RhaYuOjiAtk>{@}>Ux8fY)T<-Y&k4W+iPDOu@ zxX}7DG$bx3hoNXn+q}f0o)S-@w!z~fsAkFTkV+JbqkVoFJcdtNqSW4r8ef zrNHK9;mPLuHVxJMCJ)Qs&jArZMn-mYbk;d>Zu}Y{oNG)yGDZ(z&CBDBwT0$5!l5V7ogznVFf!s*AXP-K9F3l$B}4zWO{4 zc0o8=2tia=3{6e-a>0dKRg{EJs_|r5<3b^b%dxui#n3cnijVnPm4~^In@^0XuD)Zs z9@brl;It==7yVEqGYgBwgHFn|LfFmLTKH0(rPF80)+uOXzv#`7=sOjaqlD4Ms4dq2 ztbx67%|f&?Ma0_o+1F|Bp-{H+^73SUhrodW#YY$z7duc`Z>q2dstzMFb13BYFm8Bc zMCS>7qSRE>MFXn&MIL81_V)H>R#t6BoE#pfRzegwZ{ECd_3$WlJupyKRz^Bs zqC`kLIBkd%w{>aG4cy4LU)mTj{iCoYj&7F7f#`9Q{AOS-Vx;CTIQMuZR|N6C^G0oE#xQ4^p0KKpKQ3IC5lctfafU02pXwVxp|2 zC8wc5Bp1g@&%@)a(Rl_YYGh>e_QQuyX=#*9OiV1=RgonnoVVwlqS5j3U6bXO6SXdE zg$oys0VUo#n6!NHQuW>m9B3CkuPThKFOfw6thc+taILD?Uj7 z_3M+%tXmNH_u$CL8)@l>p@eKE1IhexZKn%ClqC*pieQI>LqhaddcJC~5TtsYYRbyV zUDP&S32r+J!iA17fmK~^n~IVilNpJtf_&-*Q}tQ-K7JsLNRcuYdl zb9u6rlbhSR_9a-d?QnyB|M0I5+^0`xX2@glE*(_uj1Q5*B7F6$3+{co6nM4|Cz2ssDPP z%Z}+c27#sM)H;JlZJu$NQ;?SKN?%)V@<9QU29Mdf+#LfJsKE?IPEP(MHg*w=`%KKW zzP)WUlm(tf_4mw7e;^hqpT{W+?~Eh9N|rn|JNtfgyoZN}+d=^0cq2@7VPOG05DP(X z4{r9(RX`ug*M~-;R6X6Ww6?p01R{Cz*VEclYj1N z_N?k`)?))irO{;B&Iro2l-#n9PU# z%FWFU#`!`-Yy5+uo<+Z9%5mEFpx4i`GJ#*D?z~NIR*hsl@TIMM2aCMq}+1s(2w$ZK00IAjVCGW zYOk>oLH0E^_RrLmoRSibVQ08;$7kYc7~&?5{ID=1!~fT>=ZlMr=U0sg4+{5nYMbhn z*wSgp3@tlH!j->;=@(*m9&LRm18yS*N=pMZ>oKXdA5$ensh#x^LT(*>JF_Z+M z0o<0OdYmUt@`4D&+kvqh5IleWeD*6h7x~iT9x#W&nHdEoB_$YnZA}fUCgCNX=FZN} zjW~8kXQv@&!d)m55fNe0EXjbm3MBPAPb^)SqeMU*9bbYSpQ&{j`tzq{V<;OV19&^XQ#r>#O^qxn+NhuMBiHU$AYK$EQfkt_=!YYs zw>6q?WNcjQyfYcvld8m%Dw_J&a@adbaxB06gISf0F8Tr8JZ@j#O zLGYNF}kTFlCd1#vTn=+9C}(g5pNG%z?~0fnxCsDu*3 zsI;r(97fEw8f{-(Tznr5O+`ba3)nwQuUO+DI(qdlYQ{JJiF3EHVVlXy!otE|;^InO z_H==ZwjQqZ5{r5ZQBzZU9wp7S0qgcd!&y9VEt=W^cw}j5NgU(}Fysj#AwCgNSI<}G zYLFR3)mgy3SHlH&o2I6cT7z)TaK?CkgAM5c2<~oafiabpm0?!TKs}d8r=6#)%PK2X zR8=KZRECUWDB|!zx;<+|crnPwgE+;nudgq(--L1_ehBi{XAp!z_9YT@W?@z@prfMt z2*TFgRPP4h;ot`vYDOy{<0KjFPl0f-CODqw%Ix;!! zxS`>krmVF`_q<1BvAHX3r<*aY&7$0Z2vsVa>|1trP}5Vw*r~ec#U2)=?n*0m; z;z|!*{{D$Q#|WXIhzR=l5vixQ7X*K5A)#b?x!7ma^nW?b$7p5yFrvU_U<$2+*y4Z9 zqCn+`K=yx?Mc3AE|F62?|0=Ai0I221figNMjd0J|>@@Ef?bM%6-Q@i`wK8fwJ^a@U z3M3skG+`4GuR)<_?{%n37+GG9yT;xtC_14yAafSn;rK!adWL8JAfMi7?^%Xh+0s9l zsk);AIyV4JysN7VDZRG#D$%MEB;@R)7RYf}SeUC&s%6Q}H(*lp&U1WlG)ZLu9(8nd z)LFRpljCAzqobl;OG=^|8ynM-&ju5ZWT@`krYt`hvwt7wA%&jgeH3xM7C!m7gVo4{}iEmka^D4w3K0Fib{;u@TB~oqH1FdR8Mza01OSetG_?9 zrsmQCTG`N$8XD7Bd{p?x~i`!!yJp{~$UO?nAX=v=duIj9Z4iv6e8yzn3^cYZDMg3(sxMb=L(L!2Qu@cCt_HDgWq!o`j9eG}lqDQ&ZpmpZ=#)EVfvQPo&$rIn560ovnk|sbJN=ZopE{zJl$dXSG z)7B=_)zuyIM4(}lr32^TcUaXvvW885VNwAgm$o5oOViBkS#xtUnUHHFz{X+Dd}DoK zXBoXlv?t9$jZNe==FWag13}fj$T}|+6$y+=Pn6)l_h-_IEH2~Dk(0pw!`G~n1SV}= zCZxUe=tGcos#4xR*`4f=gZ(t@hmUcdNqVDw{}G(5G~HGxz1r)+ypd(APGM6@JSH{q zWxC-}XP8US1INMH%?^*%M-(+)c#c)Ju>_Gf0}et%`|L`2w%V1v;R}@+^WzC`bj<~r z4I~9g{$(*2T6Wjxc3@fVlB7v#LRJ>T_05fx6$}sypo+p3ZET1$sI9Ht*xp_S>9)g& zbHTp43l7iz@xxF8PioC$+w(C%;*CXKI&gp*6f7;b%!2F`!Y)f6D80wtO6^PEmM5J3 zhE3q<#Jz#;r8FnRSUM4zAf@Sq(yybJa)zWdZOO3JZOQ~W$DmNyU>@`23ss-%$y~l0 z_0Hcz2$x%rv7g>*?o0PB?faK5#PRtH)EICOWqVS|g`x z8jYn;>1UYPjVm_D6= zFZ|TMW4jjLGs}dte>8bC=lRtdtv5$_3$@hmxX~kC^+%*ap>Z^1H^cICKxD>OA$KT^ zY-UJs^4d3NC__@kn#$^Si{P_QZ_Y&J6VI}H`Mb3cED7z3)50csQ6Vh1m(_F4!YfAD zW=TSwm8CYl6wgVut7@CbHuajt(E0=1o}^ecS^LkQ_dFlXm|(jW;kkHBVcoflBf%dW z%3*t(CVz-sn;8 zuMbxh)vi0O8H)FnG&$NS1exKDZG#`gMsxR+-|B`8VXYo82^|j^kE2;HrJt`rN(QRq zAve#;3#|(V7F`4BVN>5(3 z;fh7aaGfu9++Oooez_8(^+fs*CDiVQ-ftSE*Om^;${ek_gMn+FB9nmEM9gHSl{RMN58KwvC_?!ch<@_5$Z97kd95YDbj}9}PTZ$~;7V z^MYInruwSe9xZ$+LFh;pyS$%*J!naz$d}s%Fri&uQ@o2m>sv0W_!PNDaogpkMi_F7+E>}wp;Ag+Q$D0>lZXt z+N^nM%mBe55z=P>_T?@Tm6YJMvP(-#H`!F;R9iiZlXDLv7mNjn6_3v!(_9zOn+hc3COck)ta1WJ)XJAfOH);Bj7 zN420UOA(^G2v2VW;CdV#9dRir6lG<5-dq7XY31f@F1x(^jzj=Cv!l#>=wrje6@yZ0 z-*Aq~1SoU?r2vM^Z*9o|_@1ql*0JHZxV9!`Z+{qB{|lQ^L>{0n0R91Dbhz571jt_O z^=o7-EG)pGL`O$I#KvY|V~YSYJ!L$-L*D>ez^pViHTx2|F<>wlAT9vkMg^c5h{f#Q z*RDv;d$Tj5>T#_LdZ2s-t980FC8eT*4{93#{LVUEK$Ht7;}-*2TP^qN@USXUU0ofh z7Kjd$XQU;Cncl?lRt$g52qYO^ZIl~LgXnD|Zqd#0zvWi=f8TtitX@bpJLflLiie6t zSO`gJ$AArVa51NF_qHA+Gf_jex&u~(-y7YG36yx?$w2BclO`0p!^4c?1UBwrD)DO~ z%2Vso>GQ5_FjpsqcwxF=n#{oV{2wrD)=rBZ-MVzU zx}o^sQ_wqIXXa`d5*AtY=-hX&&FSx@TN=S+cq7_2ZI0bi>!MrHdafR7HtYw$% zqRj<5G23@jPYe9N1bb3f*v#}Sv<9)&ZVS#`V1qjJ%9pmLZdHkAf7{YnV!Gion!&vd z3uk<@2Z^FOoVZsndNpE5f~$LF7HWx&>L|jOq;lepkv8pP-;ENrM04i`AKPRZNuf^7 z{iL&z5y*w&w0Q|7eLmwU>OW9o2_>Urhlpavpt(pvv>e)bs02Rk?+SlWZ=HTN-zW22 zOSr0sSw9uU*1n`gL0bC>K@(9P`5~IA3^jcg-KeK2gIWx!*o)uq#8xp#yDBqm$10Z| zZscX!j#Xe3t63R}tI?l6#VMZLRnV%(Xq<0&gO&Y!<55Duj_1-+!S{1Blm(Xp{r6vp zm4YZ2#LMll1v`?yesQB3{J44;^U~FVsc`?*Pvra+)f5iHhzewNGgGwOIovb60Ugrr zXFR1w{Xg0sI1kPrGZ;1D+LcqTz2mV%&dus?=VlBwJvua3l-+<;8~?W4{_gR`(JGLX zk%y&zTwL3BnBYPq*GfAaDTM0A1U>bnqKMp*TklZ~xGQ8nugjN!aK8WG0kRi*RdO;}OKWQaFO=fN zix+@HL;gK60V*#~F$;_5uV25enxW+~Jv=$gvl)(24iru}{!&f!YPt+}@>ipi4d_-N|t6}=q^1vS;UmgiVutZ^FF=-EJKyl81a?1 z+Vl1qhbszS`O~b!{n95C_R;QFnZzHCmL>4uUKJ58@7_kfal`5h3#VmuWPZ^3OD_>i zXyuD~b4Jq6s~2v9p%1Tn4D%A_&VKiM7shyHr}8xeR|FTpVs@>X|j)G<$`ON5~|)(b;w_I!j-*S z(4*oi@OQJGf2!QcxKAp#$bvb8+BW}iQnowfL-3>Q>N5Wilw8TrzY(A<Y&1X$fgDewmdHHdcL)mC#0oDkh7+DBvDG z+i?4aqgc_`$WV**AZvG;@LT(Gt46V#*f)X?_j0q3Wz62F^A3g4gTqI;tk4(JzN6mHon z(xL0QQ+i|ZYx|1!TMSXRN8D@fo+(4gQm49vc4s0TB@S#|dIWJFCzQ^&@{{Z@%El_I@WX6HcIXt$t+tTgx;KKp>; z;>C^B>>HitAu_%Zq#=0!kCTn7iiPBebeT3K2fcZ!43V_&I6HkQalte9!$mX>DAR2(HT!ZMnvEMK9P?M8?^I?d2PsUZ*M_}CV06ygQ>0Ou;|;6p&Aj? zaw59gxfXZfALF_vo|gzkPRtS7X;Y~Pf!sO{1)O*^O>XO8x(60SudGtUHIWFi()C@uaD2CO`PRZ8BnD$DQ6m zne{yQQglElYO++#hGj{XGpDIAdG27Rn}Zc^#mL$rKX725I3)IrnO|YpI#kaEon8S~ zSyQZffvO!_-6{xm@U0fcYdZ<7(HlC3fHxIRMz@`N&l2KfEiCZD?YyMQa(`f8F7BZGmw9W3)isKvBj)f!5P2S^re{0?6;SszCeJbz! zAd#}0*L-=LO~{o3!Nn$aMc)ZbyaOky#q#}sOM3LaeIWc2c1|XW*q@GL;95Z6$h(o83+3JY zM8*k9-k({>ye4&mLiam#7Z$5~jvn)|;!d+(!Z=w7uGd?3Q2RnM`rsxv%!q-ZH{C3< z^^xo5%Lu#P8p40l|x= zbE*m09uDVi4bWI)l_dgD-R_^33p*wXC1o0Q<%)AH)AQ%wfBpoN(FaWKm$Q0P#1=oB zKx-7h>ajGs16LvO0WDBpw8wK8UV0ea)g7s+6g9QAfL7@%TC%jZ&IIK}e-iH*tPn6S zr>D*x5tK@=ULiR-IlbiOeoRc<-5tYdZej7gqM|}{(0R3w82Bjoym^)MrFm@z@XMW@ zoogi=B!SH!nsk74{*09s(E2{05!h?Ba#RicNCzUr^l{g+HhgWGn_a_Z5QW`_)v}@S zd@<;q2c@-mu6y>IxwnlLaiN4@uIyVQL=|P;>fb~#e~A`)=(Z?MN4UNd(5ZSAJmHB z4RM-cDM`c@nVvb9KyJxvkJR?ZT~t^RYK_5N+|CWfQzgb2=;-Ku$^3n+6p%9g=~6xy zsGc}$MxKUv^oz)X9|?ILrtwo}Jo~F+N%v=o(r$&VN}^8dNBSO_{aD_K>k`73R$Xq_ zOlK}ferJbW2YHc|F(TXD{faDf&46r1=HS4jrB{~fl42WGyh2=^bG_A@QqWxVl5r7x zwZuV-0ls1qb2%fW$u2Ya%!TgYHTLeZZBFo=?LmG-VRU{+WnM zz}nBypIS>-lPmBKjm$H!&q@p5V771T7?Z38M~{|wB}RoR0wqF&qU$`9^KEo5J1HS` ziVhU?8_c%J2>0`|_Ey7tO7O4IuhUrPTo{MBKl7WvC{;UX+KJge9y0N&`zw$0*R@vmx^JdUS^8d zYXefQbp3&^=P21+J#gINjQ=9_IHT{OpoD~m{zy+pfqkt?^luOKQK#kE|@zxZZZal>$yN zqoyVi9JkfQz(s;)Z0>qApa9+nWi(ceC@5Jcr>210+@RCbwJt`A-vS_VwgQl&$ zMscs&@|W4ZU1Sa2m3RuOEwjeoCjCyAUvRLqLU3ZFc~+u^B0?V+oaiX9{(O1})bqfBB^p8m-$ zOM06vF7NCoTAs*5aX}`&)#fOopalIg@wmqZr3+pa{!69>Z@Y{-c$mYuMQ_o28F(X) z-l0=8kvw_Gx<*y{G==N)}AGhVZeo4DNW+c4zV#7+>LVD0Cq+Zt{#^Ar? zRgsLhmQCP46`UR&9fRWjC*{RL)libH7M~u&?>SNzuhz^T^4KwHmAsB+4jXA`s2VNB zN)`H~qEyrmY%5|X)tEzaa@yWZK1?HPKc|+AJ!cu4ddm{koguo9Pf;rzc{nZ9GcaRV zJy6qRK)-)kQ~UIe@`++A{`BdQVwwmbRGC53H#08}Gqn9q9CO#rN8H}L+=&p7qN1WeiDi3vY(8zndv}@AQv7rnQ7w>9 zkdTsY?Cxe|WMqg=aPJ>o?5Mtf52OKCfoIv!s@klqtlM!U5YIv9r`pQiECa|+^mvk( zo;?HDDgngoTSFvvfam~mY+E}6svrH*iMy_Tp#Cuq|2PngQD#rCZ-Wc zMK@PlySpCZ6(BJH@Bn((mxXCZou1E7A}(yhPD^Xv?J=$JYsn09V63t-(pPIPmkDST zH;HVY>|m(aEkg}jLs3Hs`HBDuBDCe>a3qzmq#}I?>8xe5Zn+9ixL=doCAu5fu!U-P zc~3bHUVM^?MHCuSq}k-v5#XZDX&1NSV?@6~>SDLQAdTSLa zGUwAi6;_J9&E(|}5r5O~8vZm|eTRx)D7h)z)4qbxpet=D#jL0H>zIce;^H~@l}wSZ z!sZxh>=nU?j;O1S+&m0vMyJH5KUzZ=SrYhQkb60qKhyoI&9U@T!aujNqpX0PuvXJP%o+7Ds0BdPn65^*vrb?J^^XnR~mn%WsFD zD!N8e>Nu^ubacZv;ISoKdFSspBI9g@;=(>C|HpsFs+Y}R<+!c6uy`YfPAiRms~yW$ z3Xg~DWo4pWpA6kemUUjQXNbIV$dQws?H12-@fbI{Z+oNtBDB~?kcxv%5AO^Kt@%Fl z>DKiJPO0rY=nhB7C8dUXczl9l(y9Dy*5ByKawB3|wynr8$nTS|CaZgI>~N(-ygpHV zS5!+-DxCaE`^#{d&qQ3q<3BU1sTNH_6W-lT-T&?iW#;FH0iDV$c#*ZvCGG^`!K0w{RRpupsg{twr(FAi_?PEe+B%(UFvai;s(j39rS$zFbM5W zw>3eduA`RdoS&038o(?7hU{u*02fNYrYkQmj|p1BcUJ@rX3(>91%#sfKD2kSFa>4c8-3~Y$2LgeBWOXMJvbMJV44@s5A&H5xay^- z6nOm_G9?$m79AN%;8CB+UT)?T6(a2ep)5s@+p02NGLv&v)f3Ofct83*yMf$}K6 z{Jqn50j?;SJ=H}ohd%)lZKgSQ#AU&zpVd@CNa={*0;S@x?|YV{m2dk>^tknjRdT20#Y`cfV|sm7NfJ0>YD-CjVu+FZbf6+>s}(*=ikXX z@8dCa6{vT=uT-t1!kIS79%4MBh7&j;CcVr;Qy`>$_JAW)(@Tqlv6`FZqv8p(Vn3ES`KylD}h`sexSw3yW6Emya=g^mT;z*5)0yD2dA~yfS zaNI}h7g_rm3FlLcUV&Jl|0;God4S*~j(ipS(w#O%$yU3+Bo~OF+Qu4hPjbWIy}hBp zu})zrk&&+e@92AoO#cS_p0 z7ip=fB4%XjhZ~08wEGs;HYE1@?UU||@7|q0##s$r__hykH2P5-IOol51KQmFG25a- z3J1w)`?jBE&z?SxB25U2=1n!y(Rr>U6#ZS7g_Fj@<(g4xul#5n9;YKD_4A)156fz* z!Wz&LNNNSz{5^x(b0AHlr3`JHPC+T7E)p8dKyl}J*v)u+ddlgts|~udQi60nJw50+ zwKdtoKSVs|x^gqwv&lMw@C|mqf1``*Yelu2tB7#ci?dD3Y1!}z^u?^;W-LB65w5`p zvr6$+cE<4{u<_dzUsAC(5+qtbE(ebEs5nwu@Bigcs6Fp*P`l{x*;E>Otz%Qip-u zazS~ottUsTDPWyHvsgZ2-nDz@dBa_Qn5k#-$Mw%&lOoOdTm;MhpBVq|-?WM{O#k%K{`pO8_y4=>ze=Az6U^#PzP+LGmlQ@~ zSzv5v$S*E#?0q3`Ud9)=1{A1^3f!0ep5WoipFe+m;Tn6nx=;-nCeczhp!H{slM~MR z`%1T{C&$NtOtKXq1uqZio?QOx4Tn~yaq#v)|BRxPDPetm>xaJtR}vBpbYM>V#9Lu$ z6NFIc(&iYY&40^qmP<)S_r3m}3r$+k|M!)Lz^`APi@I54{97#Z&l*Otah&{LuR;`# zu4c^+VvGI#6b;kED*ye8#dJ}$@(QC;m?If4S%hgBZ6v9f2gXi~T0yvX)qh4dd>K~R zv`D%AxP~}UzqXVdG?StktHw`gT%z>8x;OPpQZSlSLWxPU5%B_XeRak+!Zq3aAH(P> zH~H+0#G4#$k~k%VS<5Ch(_(_WFN~K8kd_$X#}VHv6+9 z8AO>P+&f-LhwZmktCYucNx}49i=4u&;)$D_J$GB~@}+}EdcKAvQTnrdN>58pR!)pk z>fQyaAN^jn$jF@0tE2VtA7{GnlDfE$sB7t{4{QA}H=>~=CwPDSdjg4mhmObR2u{dy z=JY}y%nQ6Ylu_J|(yS6Mz>n!L#e}`*owCOD$eeg*UL>@`)0xs7Ej^Pj?q*D%ep=yV zINAC_6>myhOAaGd*KeL_C|-b`h(vbcY!{+|czyHi&GY}YRL;YK%J2t-WnW92hCIml z-Yfl>^5b9)c`vH1Xk|&Q#Z@{18I-Pt5}{)>b_gFa&TC!rAb{3r=K!*nwkOwCy2p0C zl@yk7J^wCN{@F@C3<8%*LHFEZM1*#X-L{0sgq67v-}i5~-rF2htcG@X^QxZo~TIkGkZL9Avcdco(a-tgX#EBfWdC+_s2IE{3v=~3zo!S;s zRWOWT!#7X?g3<@_2LT<^PS;bl+3_{ob`;5kO$%X-i!0&;$_;0RfBZsSEtj0bhk1s! zZO{gLDOd4D{j}=#vjS++(roTolT$h7qeWP+8ZcPC>q}|!eQfG3$!O0 zXlkVg@G1W3-@cv8y{;a3F8Osa!*akJ>0 z{0_3T@IEB&^yR@LlhZ#V8G*jp>rO!2959?}bKm#ii_IEbGeDIeu7k5sJpIKPO%C-G z^$46=f+k)0+G8PC=wwn~k(^($*VpKtz}+HwEI&zUnK0BhFd$+6gHH@gNXt8=g_g1& zA)WN^%;Wd9wY^lENs%7gHNCj0AYr&Jl)4!F&TiJVaxvE^b+RmYadAd4KgHg~t%MO& zs%t9s4m{V6t7nUJ_1?SKbDf36`wR?oy?z+J&0jl@5T`uZ;RJSnVx)Zs2Xb_vQRRC? zBMN%Oj8P5Oig?$bTrcKy7mA|V{6rxGs%vQ13kf@}a~FJ~8uPsi>fXJ*L0;7>f)QL> zZ2~;2?}x@0nv3MAs81~Ol6jF0BQ=KnLc1mpDXw}*56;o_9I=E9UXab43ha4%eyYKK z_%PhK`zE(~V>%~iA`YIji)3ILzSh>PEYefBmR0Dl!#B(5;Ks!q)S5ljOxDrg+t{j} zeT9AK#rO4!0J=)>ZpZ@HN=|R^u(sN~4*C7w!PT0BT?Z@%0^>?O_1d~PiB)D`x!@4} zKr{`z;i)JanzhCiGA59Vo$Jqw#Ng(Sx)8jj#{Zl!w>*}cbqrBQmupn0!4i_vUCY4= z7=A+eYJ#z_!ui^O~bX>OjWPv&7(!8to4sqnd?w86$0 zynRyl^*~ntw!jCaULuGuV|K~v?F0GWRE7WR+xB6YTXu#Q-72)?ote|zWWpcBX`9T6LOt#{}hIPjGUk^wu ze_Eg#miXnEpgXvb#G!hS_#Nxq{VHH4v!(SB%}&Y+bwEq7ah7aqa;apH5@oU4H;9UdvF z6Qlja`7MXgtEG_E@6*0_OoX@dgyr~9SYWS4JJhA@cZFyO zZ1UH5an&lK>;xEDcQ2{d2IR<;#&ehpH7|J{Bj{`PyPXwn_Nfhn159vf36E&+0XKc8+5O4h@OLv9 z`1p(H>s2k>b3h zGPeca;=D#@`H(1)$2PpY28j>-#TplPdrg7%OW1$nM}kGU9{M5q@l}`yWFgZ9BWDBM zaPtYquF8d#`-XKmcHb+U#p@Hx@L+mp-`5VB6vSGGte4f8@n4!09Ac{6Hdlfgj$Nzv zJ=z_=HvaG|eB1CN>hP2M2YLOrjzImFv4?}Zo)%#t5`n~Js;f~4-qbs<6n0HYK5aI~ zb}57m5m6Gz7vcTq-Bf!lokrozfuy33@6YHLe1*q1%K{53*>44|f-(FO-6HH5~*TN^gDz6G^tFCBlM22&I@o;u-G;QnpYzW4*YHtIodQG}~4yLLGEiGz?9@F!^G$w}M=PZblvKl}i zPV&#D`g>ECNX6MNaW4_O|H9a$DzrAEa?|8cVK9y!69}m5;kJS~(Mn~-Msy@<4<9bF>3vM3+(CGIl`k(n)&C2P^1J;O zs;(ekShsLZoH5Jw^-DY*o%ahVS9+df5z9AX+WcEwrrS&-Cv$CTsaJ!_YUR7ebGJO} zyk8b&+#;hotzDGvQMqLVrrq=oS0HXFJTaEu^IAUR2t_;~4PatR~xQ!CQwJmUa|`|ZkZ&HOO3Q5{C=q%9mQWn$rzQ{ zYpa#uSS=!}$12h-+S zG%AV~lOjqFjJ}hn1SB>!2{C93#xT(;5spPehxa$Bi7uneKlhUjynjP%HCq-HCTPOp zEcP+$WaK3|2D|fVT=klglIU92r&97csg)Qo(_X{V6o|=cFrAjVcU+p)cvsCBbm7xb zzxvwXNy8e{aHa9~%Spe&OXn{fzbs$6Z07fgmS?M~S8ukx)@6ps4ju4$(4v{sHjT@) zV;ZkNxCy)0wRL*UNx+)ea{6>`!8A#4u``xkv@tNvbIrVB*Da==JTrq4`5q=2PpYMf zg1(i>9AeIoP9_@sWSqsFjTDAk7t^N5tyy~}L#>6pgnmy-Mq?H{qfpY5LkWY8%U;_u zxLp)^n4)YAk;08KyP$yzCIdTZtCvy4pPwbR1y@40GQ8dTZhPVq_*uH6 zb}U_wi_5J%Z{HNuY{opP+Zq0L;pT5fMIk75IQ*20h{Nt4aV^h~BVCjKM4F-VYot?0 z;h6Og-q-o%rrIkHi%T<#&&snkt1W01iiggGeio)>NxZ;ObhGYpKteWvRKyW4)HPMU`H3H7m3E`5f#YNZk&em1bcs1TI0? zrV=E3*Vu|xK1%ZDiwTqEdFO~f?v0@>rSCIP+mM3Zf~!s+@~2!%aZ( zks$4M@FE`QT9bCbm%22KSBo%h1&G(;G@=?=}1QJDUYR$E+tmpS{;$uegd~_4(XKg-pe+Pk;d> zauB%adzaG5NTBi?Mmja7HWaJd*FyT|Vq}TbZ3D+T(t|w4UT+TrUb1=OwXAbRY=V$M zokDD7tJb?U#HTz+_Uo@TH{^pt9=`Z7k9xZe?HSjp4P@-i)kJKE%HPH)MVH&r)+!<8 z*G|+O^sP)Mx|Tara@lNO9@H39_Fw5Ac3(=F1mhN+HQ6LawD`y9uxg5f`fDy9{{NaNulX;gv{vokmijeoIIy2Q}^K zHvP(-FeT#jg7z})`XTk(}3%_lY7?{Ak1q=-eixwyPvlp@JYd)j1 zUHj%Yx}`Q9AQ=|28sCo;+7oQt%S$^<-ZL6I5B?Kz5WpmOG2z#!cNEK=H!Bh{#gObt z8RXFKtCe7XXyj{zgMuo**fY(YH>uoy`GdM3RZDU^BwMrcl*;<1Q&~G184G^c*Nasa zmNL*1LC~6Is#$zHUri}x^7ANVwlb#U$57ScPK1c{GZhgB${6TmN6lJl=HdyrYMpYA z@YwEh`Q^Z`vF4rfJW<1*s28LYmj?#m9mtO$bV{YqFP~A{o-UbFmvH%Xb?+HOuk!wQ z^)auRnkZ5cM&-6lWyfd9wC^|o^+Nm^5=6{QM$ePa^?J7^*ulN}`e9oO^&^C*yqjVJ zqHdw^58AyfCcDCCN7-TA*PC(h(&9}`-OHFpZz=EpF;<)ULV?VCaY`${^7`}Ubh}kv z7NluOy;c-IH&@(=gjivq*)*}rF$#+X3Iq{8>i^*q@9 zyiA$fl3%RGLJs|4b6vq@UOIAT$YdE76H8V*qRHP-!X2HNv{8M+XXnDlA-OL{uc9 z^CRPRbM)zO`fV}f>tAJAc%Sau91fk9c!?Ux$M-CMi{x;|q`l-WI&+CQTJri~HaFtO z`g1_3Yd@-0|H#H0G5n)V67`{C-Pa5C6quSji7id@EIF2ysAur`!P)6`sYSkVJ8U?z zk6d=&Y)nPkZ#foWv;ns??@b*LhB@^L#_bE*MUHuwC$Anmf3GDO_rm1-^huHM`lDAP zEHUjR8sGTuSJCnXi9!^vTY+N4Z%X5JN)n!G@sw`z3MP1N8D(h~2ksO?SF24IpJ2j2 zN+kDf?HaX!w>ux*Lvz~^g*E%Xi9!E=t(|pTRNMFWK`;=Iln@DJC_!3ULK+DP>5^8E zZjcb^?gr_SMmhxP6p(HhKstubXV1MC^nQQwyq?$V;U5@g=A3=jS$nOu*E#3&PDk|h zU}a-9UspD~J)Ofa`%S#N@*TC>2r(p9wtHVAQEI9lwq+hwM6JpFv2o?g@U5Z}7ox(UiemFlT(1k4rxULGW@p+k z>JqMbJ;~F@sJ#}>2VWN)a%xjxH5_!}R)bjWbc=EGXq6^to{vVS6gp%`raFE^!4!O^ zFR-kfTuO?HAPokxOjQqtpr{x#e2HM`1ZQS4C z7qYJ$TwaX9&Sv8}kP#x=UCYh)eILiGss2`ZeZNpy9kKL%4(6)e&SK;{uNWvGMX`-x z!nY6}N+`N#5Sx)%+VQ^XaKpHeju8_JFQ-3B4SUHk0%LAW2dAMrtt&H*H^OQ8_BaWF z#drMU0a2=Oe2(@5_VRvkot`JI;~8p0`+NCT>~|kZVJzhk@iIfk<8Uo#d5$hhYuu;{ zHUBhJO}W-wb=megxk1Txx!f-Eyh-6iXMBgG2sGHR`P-)1n$MbYfqSMZFBe~``Q8FoSsbYiG3-*7lLb=~_1ZMchlh*md8N%w2vH59 z!(yNNVId)*^$-aks7?PuKq~bL>u(6G+m9bpANeNW#WFXprc!G@u6C*zX7Qkc4O5D! z7s{DzXxcxv`ZZQE_L)cRg}M3n2QH*t&^Vcyj`t%0RMzWKO_^NF1pM60s=#iS zZe}lKWU|R-EX1T>-t+1EfTO{_os6-JfF2*%64AsciEnt4ZFL^yRwoT~-y^`HMe>dw zV{!Ug4V%8@avfbvM{O`J%e*p9gVT<%%SZ&oO33ih#yWE>^JQih<9yo#LnhWDZZnc6nsYsGw zk&PF{ZpadFnb3KD@10;7%F(7oKYEeigMYvDlbdVJR9JrW&j!QNF&McsuD%@>VTt$W zi*wa^Z<#$??CTAlXqU=MT)(0jNlR6zET$Q9*z>(As377J=>PW(eh_zZ3L6$85)J-p zHUFtXBpS2oX&?@N?-5b#c29fZ2E}IOU-M&^(`Bs!M>$PKg86u+~pB&o$9>a$h z%nk|V<;dRmh##{W&ECY%bS!h$sw`g7ps-_dBsVZl4NMXA4vUR_D{%d#6*PB#SCGUB zxvZ)4ealgkwvyxwIUK(v1_T65OAB5NCa15ny?ypq@d0X*q3kLec#QqCt1I`lsl$3R zTrV%cGa2(Am;Wvz4?Z$D7dw(?UYk?yyEM&}p&=RS!T%V)pGxO?EHuy7BdQg`Q09H7 zrEiE)I&mXqg!L)?GlZX_DiPJl*oC~UBbS?NJSA)cPU6--fcy z>;L(5Ixqc?@bJ5+t(jcGyjU#y;}hcPwXZOt+gL`1lG+zLO+|* zms+7?TtIKywqQfTG4FV_6S8>5!j@#&a&H&D6ph(6;}cuFz|^<9#K4p0c}{h<&hD_y zE?Z)D@?@s++2sp9?U|DIH!ruhh9Hy-^J=baUk$a={dY;8Yh4|&qi>>|V_q}jJs}*( z?fY_$HZ;QIgPcYAe)nH?Wg_IKFf%^9^4U8GM?zUm zvJcUZzae>PruD|Okz32-+fgiCeHyM$(UPmHx8IV6km_gZ{HRF24?%%Fx4B?M%yD5D zeRDYM_pxpm`C_g4g_|gMnc4MfZxZ+@DivoK%jE0vh}^h?xHCd)zdH7A^^o!oT70u8 zZ&ip&ivXFlMhkPNYlTO<>>Yg>oy{qKnl9e9okv(tT+1ScxKknHNS{O`=gDFC%xk;7 z+~G!FQqPnke|n`s?qGNJ>JPNx6>qPakO>^I%gELj1ZjAa89Nigc)5cIOvtb@EsyVN zX8U7qkwR)_4WcHWhrWRs2rFOi+_GT zE_og=8Im_%J`~EL2~izF$Id2hzG9T=Zs=0v9D&38Z{9!m zC8Ey1gi-%Eo4?!1F09?H&{;tL$WDlDZ0dute_*S<75<%G0=Gx}?Y!FVah-F1D@tz~_uBV$YtPK4N{3XxGQ^xCq8se=2tW zYvE9-`TVbnR*qUvDRglHwr~oqSkXsc=}u3;Wn8l8Si9*qpQ#nx$b_%AZyyZHem&gd z6BNZTCqo>g!hrT^_lGfqCG~dVR{kS(4MC_^6|}s(e;l!~n4S5#6(=qG>ta)9yl1CK z5zdacz{8y%mxKa@ZhsodPva!~taqV77l#cwneaZ^gzf({dC6#l331;OIL7^OWRMxO z+F82ru&pC=J?NAgNlYaBtYYg`Jd)j<6{ z-XgI2=tz7`r&Sy`{@fyrszxnHkh}JMY&luVD@?H;F1Xm<3lM~NBnzbPq?7L(iPu^M zXGRe)xvi^P4%&<2OOe$SSvgc&-BGWLxxGp48FlBi3{P{Xl(GG0`)5Qj~kcSEqV-f02k^C=dQNkei+T0*EGS1;z1=rz+)hF%HnKB;-9GPh2 zTlf0BSYu8+PifATiC_2e2p=!q?Q~_2JT>j)UEA^Oh*U5M3b~vU?yh?xcJ4}_QBt+0 z7{EZro}bh{F6wY(j@4MlEj^Q8M)$(QElRzUmpwVhLq=bq_l`C{3aoxNc(PKLxbF+K zq2Qu?E#o3lH}^978qswYOs~%r70xl&9i-S&Uk!}O!S3#SOzd-J%ekmqKRPrPMpjan zbRsCL)8=HG$ZtV7cxyzi?*09)-~e4~Jc#N?$vRyo;pQ1fOQXB`6n(M{IdS?kfpReu zodxm}qQco{!MAhlS@=6PF55Lm>a9>3^aLq_&#jR*cJ9o1-AUJ%mkUFs>Y@$Ib6D@^ z8jr8Q+;p29pn+xyoGBYB$pF1SWWSh;(8uLpJP1kYkyDWe+=C$bZQ85enV~fWVN20T zI{Je~C4*tjTz8etWw1I%ly=XDZnqOB2{R8z+Pn5TBxIsZl$%CcriZdm$j zP&VpP>FIvqFy;emgPT;*Z%1(Dj!j}#BWZnc^>8F9eFAG^3)Pckj*h))%oXc}Qmaftkzt1E9dySxT(gBuzDNJD# z|3qaFi;R&v{;YTmZGDrg5gTu^#%C`wZ*26H%v2IW3YKuK)q8d~OnI|Q=KRL2?8!2Z zYA&t?TqurYmrnDj$&K3{(B=C47RnewX=?s6^O$iZcSM1bwg~3)Oowh_e7AFr<&3XZ zvw=^AxIaR*xTA$jVTeZWH@*aLKkJnbd~h+&1;5yNfX6xRXs906YqxfV!iooOg(uS}tmzsp7F8tlT!-$<;l04q*w4}((>W>@eAX<{M7g@+fa%-%E4=%N8zESqkhse+O}%G}9ve*ZB#-^B z@~ib6f70x?HT|wG(>LqlrE^F&cyUZk9FJ@Gg#&EDOiuR^LHq0;rCH?A3>#iBV9k~-5sZqocU_cJ~W=tz2WJ|kYQdkQN=H-M87pl}*xnG^t4Hsmr|ReBD$P4JvXf2;MbVcrc4{b% ze+_1un3c3=Zg(dudXToZHe@!1k$c{nn*_t#_a=DubQfyG<|(XF#=b!|(0|V1ky&y? zbXaPyh@vulz2-ULFO`2XG>+38^nwugj<{FyXfIpw%9Audv)anG@&FAV+2SLM4FWQ z0l6)1Nr|)_Bk?E+WfX}U`&#zY#P=$EZeD63Mb(eP4#!)d?P~dmtXO+`y`G=qo?j;+E$8++9C02tauq}6mhb_GyrQ0 zjUPU*yxPynLjUEO*6HbG)?Zx#G(zSh?DWAJCN)(YG-593^ZIvOoQ>2Bg*lXyu6I=O z_s>RHBG-x8qx+=$bP+6aT~A!IiR;`b*rh)gX(LP|IR$y8j93n33ruxyY>rO_+_r3g z_aRWL;po(2QS*z8VvSH=k?Ihi|nQ(lFkLW2Ki3K z3kW0+7Yu!V7G#z$$Q=C|a!{1GuG<#w5pxMGebzptN=gA)Seb#My>TEH$56u+Z-OoDS@n4xd%TSBOM7|ZIZ$IJqB=?@|(Hyp= zXp)nu-N>d3PvD~k|8`D=u9wD7a;EWge+Kkfwe{!{@?*4~>dPrJ$2G4p?8MKU1&w=f zs&ilZch{t@QLLMuq5Y0#j+gfA!Z|KacfM0qbJI+YT6Y}UgMuOSgKTRcZEZT!)j@_gBLV`XCsDjyqGsfomY3A#Bfdut=XK;`Dp_QCbXKMVtP%$1SCnVWs3)HYs- z(HVoo!^0DAuW}M(Uj;k_0lFsVpb=s0OUfJi(Rn(0d?LJAO_h*Y?@r?^|H)y6!Br0_ z3^_!SBrE@EW249Ij?RZdj*hb*m((I0;|~rX`MzvHB*x3lC}x3I7QnVP^gMr`89(h3wZ+YAf3>t~xHgmYMUPEX!Y2HatKzaBCzEqwLi9GTp=T+Ih{7N&_D zM<18=v+q++j_wtNRTI=LOw+}9ib~Y z;qUa>Mbz8*+JeT?H(dpatewTeo~)wyFn!CxyY+RoUbBJE&($>!luGw*%V5!{G%J}g zP}pP9h>kp6Jf&SDMcx(z1cKrCbNfeVsl z6cinA&_GIbpp!oLzyIZU3eQ$(0dnfy{xqh!TZTTJ6^lHsGNf-PgW?4w2~y21f!3=P zv6{VD+~5>2j;KGmAB;-lp!O)|Tr9wzxuc!LtCv1WU}f}0HEl|ZR-v}TvFhq!c{r~g zYep%4$?W)~mCKvQ3=E4g`18zH_X0Fht%>1wFA#zIru%JJ-WU?UCL({{eSIJp@G_)LdhjWM|JOo}Go zqlV#L-H2sD-1l0TwF07frJp{Zir@!T-VCK>^VxmX++_QJAHPmxPY(*7kyWK7v?Udg zTda!tgvBq(?mB*a=P!44>Je=vG~_~O=oi=Wbjog9#aMrTfj6xn7Q*qhk4|?#Q$y$; zh1k7z{iU!|n%oQem&PBvkGjklT^~Zq^WThh;%CpyNHa#bh#(^W@{v1r=FD?#@LaMF z<7bSYJX=#XKcu@mNLJ;FbYG?*Gjj*QH$Yv2&ygF|0BUDTEo@BVnwqfcMZMwiB0YJ` z<*V+q#b>ev3QcDX%1r^GiG?qjNwS_JTfaZOf4uK;wgKBnHw;c&FBk5vVMZqYZ~IxIzJt;j*=;};jlNzADX^!mr+8bS*w*lmLy^a-t#eZ7XOMWs_Mke=6FD)rS-OF~>J zvxF#HInX(8S`PE$4d=z6oKL;SkT8>@oe^cl=oh5ahf=h^EbhB}{hO>&dtW83iTmr6YLC_y0((o`?L zZckzqk!<9GiukWmY#(C%kgT>UX-N>#@}&d~VYtj@NJWqF z*f+mq#a9*hmVQ)Bj<4LHIgOAxzYL!8%qXKGpOQ6+jt!rI$s!LUZu7FFUC}7nV-Z@F zmT-a*z9z58VCz;&iJ@J61yg_QcG@>`oBY2xh|8-AlBh#8*bWs0?vi2Nt+VN<`(fng zXN4lPmZN@w`xS-kzxKp%HfM=-YMNNLWH28-^9?&gC}z)9z7QHxLFMUqzsOTZK5MqHurm7*`LOb+DvjO#%RO;R?La|1T4@qEY z9@AY&&gGE2LfdZaepPHhc{A-lfo^~k%80$5i%@hBLSiFzWUPkU- zIpy)4agkJH>f@hERdyX3bO|nwh~K_NqE>EgwoE!5s^4W;>glZy;w0_#ih_5A1oo34 zDf2nFo}afD>@2pTH|Oh*DT=J_(~bytBsy@HwxQMfxLr-!58GoC{iq+mTXv)dDZl&( znOZkPhN$X5+`mk&m+}2=QU!(meQEGTtS+V_qj9-zg$Et!DLP1Wj%Q-ce*~-17rwxVlwS{ zcOzsc3OPi$ce`||f~*SXC4*6NuC5_xl*t$EmM+;B@_3eq-PZ3qlT&wx^ywPrUCl?n zR^du@+{FHQVem9Gh|KeLF10JAL^_hsu-uO2qYBr`9}L&!v*EA)t);7+=8z*~$A*LS z(L?aLBSPaVJof?z6w4XaRtch>MNffTwqe;Da>dP8h>@6qSO;m?4I7uE#R!n!u93wMOLD)RJMKjunXAG6)WlPFTcwqJB&WyrCPZ90B05#v}Y}br#YX>SNThShAlx#F# za6?Vam)qxNS1x^SvC`km{nuqiPy%O4INI_GlMAMcuH{VOxnogut6Jh)we4-+0BxqT zRrs~%Z){#z6MCML|Ew=@ zC*G)v=+)?M%JYB(Q@p)hQqtSd7j;z?JLdhlHi;fw3yirm8zQNu_`I~-@ZCXk(4^`_kTPQRLsQt`IKXZuqBQ8qX z@nsCy69ML9*G~1No(eJ>w*L3871)}oYxSR0;q!2dJCVhobrtG~bU4&=5#P?%QW9Uh z@E23K+9pN}iH*d0v3-N>b&m$3A+ePyzp6o}O?h4AYQ%sN30(Ki=}nVqj<_<2+`G|# zEexptSS5g7M{bd}NiOUc4ilfx#Yy31b%p#tm(n5PCGx9sKBk(2$JI+#$wh`p_wN(= z)Os_8o0)#rdHuBGa69hG8^yO2|G4g&DFOY8pPlQUP|6=+l$%mgouu66gwN9dN_g>v zachp^dH~bU{^zUM?nwy>SIvi<2$KSxm5OAYwhP+<@B2*WOg4LJ!PI;nQu=TEJ9bF|45R)=)T$g5RXg__V7NR!>6u`)x7QpL(iu9ya&eE<(ZKm z7ruT~uS2M!Ti^Kw>qouW?fp}$nB(J{xEU2V$AT1n&o40h%NpM73_apdl{qHw%0}tY z?j@#xKJojPTRg)qOvl#?Tf(tvmeQnDj(9v`QZ<}L@GZ&@T=k7z5DWP>KdKboh^ z|LMdFP`|OQ z)ljmop+|Q$$i3;+{-o=5h4?@VXdvgZNA;h6rklEMBS50JoV4thcU_(z)&Xi$oz(SR z94i{XWV8Oe8$%ASlP2gGtNi)m?;9xo?&@9}|3B^|`J)j-D7MyCtk*^nd{thC?YUUc zjR}zD!f-hw9)yd7i zihsqh{@o8(dGNXcPxEZ@f9xGC|6z3r&VNOqKaT$TT&MrMvuAtbgVdil)6f!K?+Fp! zOakp97DmucJ@Jf=0SBH^_guU-Bl3};7b6e37}<}83i)e$ui}JtER=nv-~fP+6agfL zO2(l=3YSsa&-C89qU{fOVgx*H?b|-N{`?0yph{T$-J38W(m?>`SeEsZ)IY6lyraGS z*9Pmgg-*T%1fYSgQp2pnKc0WogrCQ*lLXXEFU~beWUjWiqJDC?)#r-?Z;&MZ_C5*D z-%DI^iK;)A+P_Dh^Cm0eBmyu+%%Sa})6xqcsA44#Z0}xeIZ^446p(92%()0Qv_hXfk3bpv)OeLFBNyqQsG5ET{eM@i_&}qfPtzW-p zGom$hrmAg((qx&LnPXVrVp}bBzuBH`tc%G1$J9Al>h&^PMTUJOL8N@WLrPje`(**> z)y<3YonQg2y%pO{a0tF4X=ntDZlI-T1@xwe^VQlgT(*&bm)~pJ@1iV&Up)lfe@>7)w)A8iM`iXnW52Y=LyykG5bI zaGEj!45HzDqCp>=&9gzia~wbrd(#m{0SCeH97Dr_3BADqz`6kPPT}_8_S|=sBJIYU zphO^>2?t~471m2MxSYoTAQK$ahIyyR<=hb0*ryG@_mLI5WMQgcm z0>Ts-fc*i>Cpq5p75W$!hP_z}lU6L$>;VippyES8Mdj_ZS+%Ti*yDzX1m|KQ!Xa6O zwYzr##s#i42jDd&mWvVqCL&FZJD)~+P7N@HPXShI{un$jaB+4F$T1#p`U;>4?(~?s zgo{C%?CN2}fYMh5&_PFY7_MR*4=H0Mncw}S<^{AmAgCB)wKP6D3P<0-!Bi=)emy;; z1%BO(BLhdR0XF1uyC`o{8}9)V0)R4Q=j6OOJKBLW+-5E>4#BytLN+IpxK!RwSnKd8OWi1IUFLEEn+>yJoOOb29HDF0g>)7r zQ`WPFcMrtV-_~KJU$irQo=3+uE2{D_aYwJLG8uLHe(X^q{YpXdW6Tol1U2dFFpS5z z@FvT4>=ukCXpCpu_}juxk=YEdgoFeT$9Tla8Ef`oO^yA%U6uM7fGjQm#Ugti5^&ET z95x6v<$$wZY9DS+@$CPUhm(;irXBr(^X&j*`VSdISj3F)l_$;m$ z&I`O;TwF&x!LDfE;O7^pv$h2hlLLKtIP(yw&;pcY7m-#j=S1Q+9Njc1 zjRogD7U-dAIxOC=-;FE;zJ3GF4YZtZMoDtLa9CYiqoJo?0;eC05w33!NO6EncC&JY zdmIRB0@bAK{QQixG>^}p$y^Rfljjx|th^hr{!p#3SD>-M2jG}(FlCbfstJfp0V1Rh zAW^ATS$e{y=z%aYP#;VKVpM<%l!i|B>=_`L;QNP^8 z{m$ci-X7iElHCR@;GWL;M7!y#l;HY$UO?OfEE@#CTN(t2Eih+p19l-$vT8FZg(Jb{ zthu}sy@8r8;5h>KMe_dM2#(vx%#4bK1;-8Wun>Ba`7q!?8tC!X0$H4x9s@Wx1xWn6 zUci#w-Ji$MYg7vXNFR`s1A4tck_zs~!1&-74j!JZ;OOAUh$sk-KsNguztQrJ{b;of zT=z~NNcI4`+pdqg550Sqv^Kk}255guO88PzQi4fq+FC%I3rN_#Qc^Np&v`bf?&Rob zf4)Bg@=k+@ni z!!8V_JCH68=!=6te+oG}^H^9|ByigW0SY1F?Nv^hg2dz#9IQn48^6T- zf;=~(WccUwerHB8fmIn$`kS?_3CsloYzACKBNsz~%vI z<)6dD*tobt>gox_*3%$T!ecWW*9pR^dYxk=m}3$zUjlEM9WzYMC@c)tI$u?S>!X9Y zMg+5;_oWK(O9y@nP*?%lP)DHNERuZ_lYl@>O^pbMjv)ZGv|`gKE+9e+kBh+CfF3l! z(Ew5yzNUTS(FFjkQE_p_0ifH0WfeSp0BYp)ZW<%E*%5|uY|Re2fqS@HXzE*#Kg2dT8!kjzczyN@L_lI#U2$%MS>^~BqK=Sh%W4sr7J^LxzA9S^(~NFc)V4ZveU0C)mUKm!*CVbE|H zY;Y{VVnEFquo|_=5+0yw-8%erGCopoFu4%*R1HK}!jg*Nwq;e2VF3vcUM=**JpRAr{psz72Jw%2f^IsXap!+o9|W+r2&WyL=Bc)_z!S~+qZHDL27!Rz+Gvk zXm5WM!h5S>YkeJA`($rLK~WJz1YI7bydeoNLI4;1@`Y|;8EqCsJ}Mxi8%V@1_xkls zehZ78_cQ%RNA{ptVNX59{Vf-RNPag1I!K5H0RmEp0TLL%Z2`#xh~g_KDZyte@YQGr zttEi_7&T!t0EZ7v{^fCtRvRb`GsXAp?eF(bPImh<)Egz}GRK;7Q2|vs01&E=C&55L znFHkx03%1IranH{oazE%`YNEL2!Vmg2Nb1KN=gPQW!!)sA0XHP%~mp2)`+ZRmj`Y@ zMi>E90i5Z%nfdt}UX0ld4auM?l2uoiR8oqz-~+ndAPNH^CGe%$_E2(AJP;rb&l1D~ z=Inr$n%YFsVO&Cjq^T)A1qH>~K}7=vIk|^nl0)kqZ4eR1#>Rl=IIbI<9}FS~!2&>h z%BiYy={;m%U;rEC04z}uDZT;CJ^(cUryx5oj~omQsN(@VE4STdI$$1DOuXk=i{EH? zR%r*IY|TY&$@cRo)6Os{pxZYJ6!r3y3MpAw29cn2>UH zIe-E>h{s3A$5VSe01N|<55@%}Gc#t$H}U*ivXy-U1NF~O z_Te)Pz!HJRp#wBjG{8v{$R>j5EW!tz5BLq@C0_`@;OYXEQ^_QrSOA?f--U{U@N1$D z&-6fY)PAe(kTF&g3WXvdJ@WoOHw%c+xlGfu1OO-d-6aanFa_$nfN^LAlurTmMQ7bY zk1ZZ7EYJaE@F9n}8=xRYqZ6?aB%cEJRVmT)?Vr)+2MD)DP{V`r00K%BAhigm)PU>& zib8~0PzERPIE39Mv3CQ)z}rA&Zb*6BjKf3s9{rAeop?B9F(56&!4q)cbZ;VeM|U^t zi&!w!?j6xW*-5`Tz^bYib4!y=wt- zd7zj^(Df|>Lk7MMtXq3|ae8!gMDVh9$`2^nAI`Y)!QroPx+XwO0>mzyCoCs7P&BeW z(*Q4f!$7V9#gQq;^w3ZX5J3i~bZ)-IA3^X2bHzjth%a!x*_@oWqvwG@s~N~BFN0-N zMp01+*fTs4gL($6@c?R<(R7jn%&0!TOP;#AI#5dhfGAL&W&G#`aEPGNkg>9YgPYe_88(L ztpL;#kmIV%=Wc+c2WqT9ko4f21|(yEF)c4=gM*y4wH;YBWdnGE#QiMEc+Twp|SrX@(l(pfnEEzEkc zognfbY|X&c*8!R7s5JY~knoaYhz2BUy`l4KX12FyI#PD8ATxeO7rw- z#@DYyclru|IAjml#@%l~%@yQq=fj#AIEow;;8j-3zqYp6pVWbU1{lVI;_tEP%t}a`c__o&!}$X(?iWo82}c5UPij>mpS+|B)Y{;Vd>><7TJHipEkK z8inc){F&ZM*@9rSwHlKw+HkhWV8QY5>|~^Yq?B`gq5@8^2e?qsg1Ny^yWR9On)Y`= zffd>(ZSys<9p#Okbs%_ft}g?S)Ip6R2;^-6COzQBANq`;P6;n)s&t6}vtx}0&VLWw z$NlZ2LeP5w*|ktphBS6X-9HGXKJCAL#2H>|NP$0?S4D6oRE*z=I*}YU$NcLZE(Mz3 zr8IaaO*-XYxYB@XEKfP#aBPvkzN*{eQtftjX-s_XUY#FNtMx7Cpr7J9oq9q??xdWk=y&*V_PZZy z8OJ0hf%s%ZEZzC8j@+jCreGEpzq0kif*)=&gMZ7U{w;v$ED%V&93n%{43Hw3)d=hd zB^v8IL~SKmq-4XW+vS+cH;2^@v?&*h(aBLG9%hZ!J8)<5h(qa>8wbQtIq0o+UND%l z{D9GzHq%CVUfO)m`o;gp=ixPRh@Uyn;FPm zWG85Dg7-2>_50b8dz;lkKK|Hn%}1^LzSi|}+1+003zq@E?+Y^Kdq`g{8+9R$Hdaqu z@%0M;AY-Rg&l~L^K}2zruVEeeM3veBM!{=hHM<)Kp)n*hCVfdhiuz5uquiD1@=M|- zuWJ*fezD%-UCY$&ABGgJgAKYL%*khxNdr!G5Y=W*eOjZ8In-zQc!OeJDwUcTq-#F8 zu6VJqsv3QEJ&Kh@wzS@?)N^AeG=*i1eR7!KbRtWxl{)}qWnoo92ri77`U?dWw<8p${R>%YzU)AX5*<977 zT=U~&LsxIk^P189Xfe4YEwNFXsmk>sg$l3I?YunkosCw-a__UmiQ?wVPc1ln6Tu>X z7@D^VF5fIG%d}n$#~Oe7H2FmNXgxc7k>pKMNK=f|{9&!UWpGxWX4U2Qo!EMTe%We3GMs#=dY^@8*TNL71_4d>8 zjU(repZb&A@3;J#q91^dj3CW zYO5Gb#!oWc#x5cRr5VOH%HHL8zRRsIu4DlxP47)k zdTgaR-9i}Yrl&>=MmJ5qSWLG@A6!oM9$*xP?rIJ1PLVn%?_*HSyNZ55tlTnj{=-=a zZ9EzkKpKWaC)V6?sUuFDflqFv3^`vm=K*MhwdtK<>EF`@&nw{DuGCMME8tnR-WP`+ zA*d_mmsQrH9I_)_=()b7p}3?Ceji`RblDi2E_Af8YLap>@N7Pcw{?TLuc)1oL%GRa z_l=(L?QcWIxlY)>2Orw^>Fyg|!-8iCOWzuu*Aq><-9sVIi{kVT&#gl1d|}5+7)>J?kumW>Y-S-0l-r!Of?8Ht zSlcpzs~umm$PXL$ae;B&#-*oQ) zuGbQvV|4w~o-I%Pzvovjn3&9-Jr4l?1%Wk3oZ7mG(|kHI0?2{y1)U;%o=lR+1^3iw;>0SfqOlh@w^ ze%*5vl~H{FF0TiWQ1EYJCkYKF6S@!>{sv1!>w%okkOU!Kw3=V2h?zJ|#+R?`xm7&b>c1{M zFZ2}gzb?oW9)DQqKiAJv2B*h=y&}dy z9^&e4Io)5+vLJWkNfBIp+Db- z4Q^x=6-DIcnsi2l?GOrLF*t46rFB@4OR1`k;WH@z{qbUJ$t?D0{HmHN_D-^4SHx?Q z&7FfsI5_tE(rJNfdNTTvacut*x;xcTN%JmX@TS`2QY30StqXzpA?W0Df}~FVtyp z(SV&@`J{TEXr}sHY#Q8`EGjCx?DD-t^}Rk!3sJ*vUGGmihuQk}u11LrklHrd4_~GE zT$rbN9mpUJB)@1c@i}I^2Jf<+ay}x-cjO{j@IhE#AM4$GQpr=)nb_A`J7xK2iX0@( zb{Vmg+c3`h4F@p)WJP)`EG#Ey=QmnfJ#e2>0T=j!&=ULk`T6BKZ_D!0=BW3Uxw$#9 zix4U{#oD~<;{7L2pWaXEcNsR~7Z5-eadmZ#a^pKVcjTH0c8Ksu;dlNJ8Tk;5%Td!? z#}cmd&&=1fOi5sOC85J+Yh_&&?c2wX2?!(|9XTT+BF?;;??mMn6tw?x(24O7zB*Dt z+HFSIkUi|e-&|Gpz9x&P&UlxlyNFmg{aR8&FD!greo;TM(C`mhepcD2iscm-v*`L> zIrsGT?jx>f>F5sHDX*ikh0osCEObeJcBTn`Y({7UY_Uw=%DMbcw zl?46T^z~16rVHQIJ&x`E5lJrajEO0`u8ufs_~*`a#lA;V+^0_lJV~1MP7Iownn;4D zbB?v|SZ+i1Qek_t#PsUo7y^OV4GNvUE8WdY^+10w0B?*nAI-h`($`^v15sORp37Vifr3?p$4=M%mrie0aWy=Lr+ipva9Nl3YBKLB|JtRdw}`pFf9; zZbB~4_UBw?t>x2%y`?v5a&m&ONO{1EWi&L1z;Ga@rYdS`9gc%SQXU@sb#--M$RU%u zo)J=%-f=Rqbo;h9C$=ES`)jdECoiO=q9}|AKt0O>gKgPy_`>8lMK8jo}V}l_c#HL*a z1_s`{#W28Al+el4`^jgltWoVD*rOvO{@sw3X2fpR*RP>b!WW@Z6z+iu2}BdcI=!2t zdG-zSfgvFkknWGI@U{%G5H|#@#@xaJ0M1|&-p`aHQCdbOqoEheeh0>(?(|y=r@JotKjnlb9&u zL2+ctHCQ2I!V zir%H7qDtnozxx}l4+-G#c8>ryp?&)F7^9Pfl=OxB0qvVNZ~7A0k@H5ods$n;yH+!@ zvH}Qo-Tah<&jZKCRC5(mWOa1r?^`mnu$TZ~Cdku)puKSV{ivk*;yFry-*~}WBaXzg zZM~ZwF!~qvEB6-9I(b7QBPsSsKE=fiO-)J5%A)V@?}wA}7AyItq@;i_8?q7A?$&Sr z-r6!;?Ti2;^xxgJnJChhl9R*GL(EJj2)c8Cfn8agAg&tER-j~jc1TJ6l3+qHF)@Tq z5C0AqeijM8v#TreBT~{{=9;#D$1m|IB^>r7Llt>CBM|AWv`lf7g7*15hRy} z6vS>rRAC|0rH=?VH#Z1SOibI>ctLkxADLYmSi4VPO0fV|Zq^5D-D~UX4&b#&uhrCo zW??3SsX{+~{D@9U>h(UI59u&mZuLV(u5N;KKUOc%?e9zEWO)Ak`}T3U#rSidvvx{{ zE^^nU!}H+E+~K@5AFz<*6{dsh86gxarXmPpuzG;A4Y)`Wg}wRv`}+YnBPoQ?UphNG zKVgznP#`}d11#yCos%=XurL4+{=#AH0SpFXdRH6W0B`mjI-De}pZA0}%{fo%fbE=e z8#A!03=Iu6$_(!-=EVYRfdKY=55hnk-<(@QxJbJD`+s$bT-&z{<$s>H*+4Ab_$-mA zsjIJ?BKFU{?xCVO&O1-;U%`EE{8bLrR8?PVYs-Q7iQJqIx-a>mYLx1?y@$W~i;4?O zRP!daYwf7gybjPBT;V40g(fE5#ssjC_yKKfYdoFd!~xxq`Xw#7CK`3HG49-@QSrzt zZ+Ps1*!lfCy{Za7ZBR-~47ug{xC9x2d3*(ea)-@+MLeB8S>WcljfQdUlmfrTZvtSknQ1z0p$X|M+o9pS{BDDO{BTTAMp zSaVN>#wR8|CM5jqj->~S<&KGhJU>4V5?ib1k(=OEWKe4Q7T_8`hC3=MD(oZ?jW^c_ zz?r31)8(y4_AU)q{u_sf10pRlGBQAexa>^5($*#gm_nxDb=lE)$3h4&<(l?JhMk=q z$!ew&4J^O7_&wW}D;|)Y1A~IFHc50oEG!0`A8y?8mGIdTGLP+oypNACSQGCP7#6PQ zVBSCZGW3Z1TgE6rp_GCG7TC0Y!%~1-{g8|hC$O=}NynY3GM}!Av9VGY*i7q~9q*i7 zd#Od)EDY&32h7Z9bw-l+)-)d%`5^EJ2@iW1OZ01IWdQh{V0qEek3b09udfj9s}a1R z5fM3nobF=~93_6SeR8Y%95KY9FFJI1X!w3j~E;j7j zx98P1^F1pa&_p(ayHB4!y-m1WJUjsM$SU7K5Tn6b4`)f$0Y;KmRHWnLimR^XDK9T) zIlt`q@x$(P-t};|0bXvqDEz&>-47#btEaDT?ME1H8+SCI|WU%!6ca+Rx;Hc)H7`izCGc2kAI>ikC3u`1ts3j!92{qF$uc5r~EhSa!W(@ruR3 zz<^B9?NQ039AL=h%X>1Pa0WmT0<<@~MO0EmtOWTmXG-kHd0%0guEPFh|bQ{-YeDuK_Q z8Vn_zQX~~botMpcq307LNLx8TU@tA{gO34lq&GFCfPwlPWl_e&$9DoKqoJd(RL|OM zR|t>H)j8g|<$tzB`Rwd$Bq2*Wok$=J_E>KYSOu?+Mu7%FPE#;Mx~P_H@>j&@TI*yJ3c=CEhEm_ zG!!lR01%*3dPNg+nk+f-zwkIR)1Q(2XMJ(*h&61>-_)%OcWEw)8ybGcXO(Q8O7+-c zC{$+zk4A}H6QvDy8AS;ZB#bEiLw(}SWZAABn)08~0< z#RCW-xAm{OW{puaBR2d2(1c397o)>0Vt>6$viocC=6}^hdJq4vMHSDt43*L4qBU4C z`MygEYR$(M)3w>AcU28~rt=e9|N4IL4~cVxJD$3`R73Qe;Ywe|psu+k%SFGWY5ix;TN?(#^%xAHoeylgp5LEc%)aee5 z45G=}kM)jAt#{eN!HIcww)N~PJ^H|7@b|bKb((4F8S6o$4n*WF^DoLt4#T>kL~5SG z#kM?VB#PvaL$|Ax4{{Ak(0>!tPwsyB>FOy$v&sU0dV1PTkm8oYq@=n^XIVgo-rR9_ z(bLl#1S*Lyd$qoy0f_w1e$K z)C@H}eaO_*RIl*cw*lsr7`2dfwnE(1y>N^M{;N7U&C@ad4?03obMo=hnXr7wT&4e0 zPU;dxENbe5al^1qp0?m|jx(Eq%t?&~-XN*#=}7M>J(_*xt0-pGA1v$pngp$)6Fuj6 z&9$HAd0+f2e^}%F2dl)-Yi9ca8RnOibiq$?ad6ri-48=Qd?49x?la*8#XW!=;ng2NEz~ zx59Z_U0GQ<6bfx96b2%Kh}VV;lxh&bU!TW2&CXVW6eR_qyPkW`U4D1|Lg_j{tsB3S zT1^*;Pgr^$H8|pS!>TE?O09Gca4L(MJe{Rayt^}EhbhahC24GybF=@md>BTe$TG3Z zuKmZVITz>cKNCAgp9NZ*A}XWq0t{(xYfI@O@OJcTh~mPGsIG?v zvKkgeANxZBpFN6HW|k;4=(yzfNp%M}htwb%pNiu3h1UnhluD8; zd!~2YI=w10*8C$Yzc1jX&(6O3ClhZbAf4uEPwx%b^jK;eSWzd|6q)=g z#PDTqblE;EoL84nq1Px3gZMadGn#7I!#q-NE|Y>9u7y6=ZQPxoalL_>%9$Sg%wjAh zogdrnp|SO3P*ZqhtYo^mMaE&I@E$r+qifXLW|7QnQ_82YAB(C9d2YN)>b_H8^BosY z#!2!a_F_zACI?Q8uFdo6X2pd_4vTq{!hN1T9lLA#GySyv0ilwLvh?sTD1^J|(jzTb z&*~1TSv_p+)1J}7`|rvsaV>ZHJByNS))X52>XSBmwv?C$l|IkYD>HmtD?G4K#p|j( zyo3Uc7_$|Ax!ag}-IP~z(3hosCp7uyNlVk{9bNhkchYHPWeKCt_h-X9*5>L$?_mt- zzPh&b&8w{srsLJ1gY36vF@_a9&znnnshGy9GL?{MVsyA1!1sCf_0Au9ba1Y$uKoy0 zI-+T(>j!xtSAT#)&8@6xK^YkyjtOL<>##K;*dD_hi$G$7l$1^%$M3R3l&6#iDx||< zDato0Dgnc0kd+@{pwNDVhsR}x0NnlY<6{d8i`%3GiY}l%rcytDMr{R}5{Szs%9}G( zz$BoGi9B8KjLKKZTe0KYa}(T|t-;P44eN$bKYR8d309FuAQefLk(qg0(d5b}ih?2< z37d0nm zEWrBh+-z;>LApz_sYiq6Y@Ex&kNnjOK7ozyKD1q7)b;R7QW7u~_{bib3?zrO>Hl`s zDR$1H;9q7p(u-@)B*Go=_NBjJWqo|9)B@?I-Q#0?CP3Vg*L|gdN~@l{(*YzO^YQ1 zNke!tBDRbVI(0U|uUjEJfP9FOAUtSB)pyq^Mf=x^(;e0;b5f>0DpxhyVq{;_cE;_{ zFK28}x+9S}es3y9`bF8e>4=JFQCKC`PgpkZtSdU|Z!f&+U{4UhYE@8hril*}-;uO~ zd8UY57R4Od7A>nMg(xk~wr=}Y>w9`VMdMQTt|fC_fz2fmhvbinjq&kHY)_Px2tdcN zO&%#QDn=>z#fHAaPvW&*-&<}coI44iyj;o@i!O=J{r=hA+>s_-D za}Lz2lUFTH*`QCqAKS!`yPk^fF^h|>`LnfOga>BwT9O0UxsRrGdIyfrRrv(;*Ee>B z790-rn9~_xEEKg}!FBUto;#*72@G_x+;z}WV!u7JR)zD<&u*~Md+KxNkI+wR%L%e^h&672q^Tm{xa{#utx3~9u39>+iX@(=57IlR4pcxf=jxALn40|M+2xIZ_@33k7SsDN+LJuuK|ShlwuLOC)qF#-1`=d*hc^kHmr zGDy&<85tRV)))j#tu{4AY(y*`-dkH+KYMx%K^f6rtA*U4HMk`yd=Czw6 zQk;3>uMWQq-c29D!s9x!VTEiYsyg^o2RdOy6Ls}u_;BQMrxcOww32#;_>#T$K{ zE+_hNMdAug6gJtQLgoGpDhQnOA(XCr2=st%v%Fn$R zvXLGIdrR_1%A|3t%#Yn$Efn`{z9}0Pcb*(_LaA*fWcVW&A!|8#dAP*HGVbm#K)H2m zFNL(f0@e=jo|rVt?_~{3TUb1&^u1&U{xpy%*tIZ+34aS48xvp#op}iZcmsga($gb9 zBA!0PPha(phd}_w!y5nZQ+e>4sO+4OT^vJ4h_0aJ6r13^`QbNV< zYv7FSR9RYaW<6(2P&dJz`fJA-sN**0rQx=F|GB(|_U0*OdB~^m9Vc`>AVZFc=MtJi zgDSX2WW!RUcMx)6Z#~$fWB;m@}}QxzgdA`*jcnwP@E5 z`_Rdw6|&_^Ay3ETh8*Atmi6{p>)|BA1cqY_@Z*5}1q>p(XU{^x@&nNgEK(JHy_Utn z=?WlXwn*$|e+4Q62LU()Sip$_$`yGT?I?UVKR>^1bzh&2D1pPcC*AsZ;sj{%BX=P> zllQ2n$RG#%tYo;F3r7^cxn_lY<^bBk!r@YZrjcvrgw z4F?)^h!rLqJH@#{aS;|ycrla`rBXTnb#;bX_|N>~u3GMH{JO!f8|H2IE#Mn$txxV+DRzq3&G z$^Y#&lw6|b@aL7L2I_-NadAmyc>hj6?;RRQc-Aev`(o}>Q|QizJAAnxKzNGROMrPxd(a3 zF4jQEnkIm&%Ss`CPtVhr{g0pH_4G$)=VMCBD9|UEsWbnqEuJ#X`##-4xNS32?}}*xd1<&V`& zYR*^T3%M0Ah^*7~P;_-1ioKU!G0d`~EJ*iwZ>z7}rJa!z|Lu1g zquwqbVNHqO$mT-IR~GaRek#0Cg)?RLpc>$V-QuRE^yK8^pp#0cl-lQqjA~|M(+P7y&2{HY z>c4e@LF)$Odoye6oQjIr@83oF`8`rSypD#Y#>U4D*oeSZ0`5&%vN8QJ&Of|M`|trBG~ZY^6Bw@wZN^$^cC7O=cBE+ulyLC{4jHUm?GWDs zsVLK;n;vvEM-(C|!g4UkHTrEVv>N@K>6!91A%QJF7WEcF&*Kxt>nx{F^GOGaI*h-R zMKf(5TKTw>=jISk(X`DEeR%OSHVz~5N%=?TjUqBHx+tt!jJ(m!RpP&B?XyG6w*JB_@`?Uz*D5Js+>YxO+I}xBrBO4aOuiZ zn#1{}PpxUS$f|G9rPT2XMVDg3WSNVRAPPFeLJD2StW=Io+7d#Tk&{YQ-X~#9vLnq3 z9l7+NrrwzP+4v%byrgkJ?u|`+t_J%X8J>A?7Gd!AEP%86(Aw1wihJ4M8Ajby(^KPD zDAi5(8!sjC7+Xx*Ro=?GA0jQL?u{!qwue1!lf)}hP2NJ1duH%5Tj(LQAkg0*5*m;@ zV8&r;QffCrpnE;5#p6N9&N<;f`77Jm3MDZNc@Zgd6_z0KHDdy+`q0I3Vr(gq4WnU~ z{EzefRsp2(+X4q50+9HQivS>JfFR(OK4W27zdBvKbtWh&l_VuQ(`Ny9eJ$uu;ss49 z1!?IApihYWlt`xr969df!G%T#APjgK1w}GG> z1r5ntRDf%YAe zvWg05gQ2)<@pK)0HjQ>Z!oBba>K?OKO5P$RUmbD7UJPV&#U7NUv zi*x=Rnp_ba;^l5N_pxh+d^Z&_94Nl7J$Qv<9|Is*KhsYn7 zM=*AFcH|aZ7;+Vo2p)U{)hE|Ojm2!4*aR+f<)y`qNkfiA6if}^xraqX!4GG?sTJH6 zVbyCE+;e>W`cZ{Rzag-(v+P8DLFLzVphFMII6!0#uiF-CKKcZH!H2zEs4fP5;dp>oR#yae_ZR@VTV1~tT zpj>v%pv&JB+C|y(9o>#8ieB$4-S%hfir*s>$A20FF_x-;J#Cwg2|(Kew5Ow_rH_rB z_Lg2fXJiCs0BD4B8g*gR z?-mLAG&3t1Wrpsft&ui0dJ+z_0MSFLQ_gK|e6eL5|7Sg)$#lTc`b3bxEDWDBKe zJHB0cKn(i;1my>_{G3{SRBnah)Xj?>2BwBnZAj$FQQicT&5b(auML|R^)3zv8~Jne z%d-ERQleRAF>MrUV-9#VnQACz|blJPiAe*TvPV3bEu-a@ z-x&9gyT(w5Yp?aLH=cLSXFhYjp>i^x(O$fM0RsbrCN3td00V>A1Oo%h_#6?q!+%p~ z1^k2HASkZ%9JoB68-)P>CvX%|b5yi3adgqQH-<5_wy`p1a4@ttHnw*7V&ixM-^LF- z#Av3Z<|t%utnX-MV@;-HW@QZAgn{|>ecYFfnUich;8)GBDl%4P*7syA>^$$ec$m3z zT(sL@V8~#^g+D2|rXMbQIVx?pfFE3_u{&j0;icfP(_xUA+Yyj43K8B+=yklSEeuwx zpYC+c!X0fm0 z(SAl^Cb6gkhf>}?2!fr8uFw5`@7Aa!rf7NS&eniQ(n}x%;01YxjyxIRrx)Uzp@dA| zkSAAvkHQ=k`IE~(v6B(&$wlz91fE@v%W~p1kEo_c@~8|SwbYX)w}vR+y$hRr!_rM4 z6dJnM7GnOfv&?pG>x&|0upz=|00KQOPJHN-4|=8ulVhc(rJdeIu^J?ouELeWA~$IW z_1SWX>eVeG8E`%MHde!+8hzq%NkMKyiarZ6WYVVXVj{TqiWwOh!lwW9L4xL&FJFGK zzyNFdz`t~Ma&|V~6MXu6he749`T2Pt$fc(2lfjac!%OKWJ?UKts>X|^C&Lpq`gJ=I zq`hwYz;|6Dkeufx(u;-wx4i1&>^!lw^&0bOs>{jw z`GHAUfsr^_emC(?%D`^|&`p8sP0|Nf@pD+UHgCSR`)ww-t(ecQd$~!sOV9xt(AH@m zDN%jSZ zr6H0{%Ox%hNfc84H~XyRS3;-0XrT7ZxNG6(>c$In@w9 z{W4y{rG%_rMU@);{h_Hq*L&%WjSVjMi??WKXu{+%)yEFMf4%wIv1Xhy*6MW!Q-4s_ zWZSfyWE_Fw^uJq=dbo}v;54F6|jp7Ln>6~!$r88sHO3hL_OrlvGz zW@bwsCoRo)$4$*w3l>Y>cSpk+ACmBNJ!7h>SiNs2K`%*3G1^T*UcK2-{1Qq^uh>k6 z$v8Rjil+zjq|@Hg(ysp=&sL+yH5pF!GfO>OX-P{?#>ZvQ5O#LvfN6VxoFF6m^WJR5 zEjzg1Y$v$^e+Gt!x0+TV#{|2OZfsc?+dg6!X0r)On5&c3u`UdO;a}f{)GPF0xw*NQ z`_z<_y8B3dq=4^Mn~WHoZuF>?wlFPM8ur1sUd@}rs@2=R3CCkHd4NJ*;o@$b-{5oG zQ`W7x)5X!q@|T}4&drH^`UHCiKA~Y`j66KF+!+JODl6kW_G_TOUvIw3*z->ZQi*zX zP%w#mh(%dLkk4J6Pc|?`z*n1Rxo| zqvLyB$i8aBUS8VhfyO^D2J(uTi{ZBj^sV@lAbi`3_$Mg z?Nv}v=v=gEL;GlD#qc?j=nXr20v3fRFj=G(4!bhcQpq1RH3`d`&t3pOa$B?kI5ILe zX0hAouC`|Lx^=9os&Z#w|5BrI>dNcr=qRVA)(>C^vAwvwbr8VYXM1~A^kDyu4TG@o z@UaCj(D#ACL4)CBmiO=9|5N*GZx4&0t~yZ{DFqhRr?!D9bM# z*9*sk(z-K$(t8+~q@f-@@RAU)6EiY0reYN|Cl(gJI@ zEI|0dnf|er1KkH67-ePU0Kqr>*K6>xv9W5kmIUA>2aF*73aiE1>Z=ypbwQww!JlT6 zZy6YR-b-6I9dR7DfOV|fAkO45{ce2K=Buq~@2roT&t<4(Glw(zJib_2QPI+d_JreYp5MHsr+-B6a2n^y&r{hJ zQQYuA3_c<`R_y0#L5g55fG>Qnak5m%H7ueo0-SESj2{$Ov$NcGf8a9EYWo7e!{P=oyW)GnG(Ru)` zkcxw&wyA}wD+mof3z#GTV7|wYvE0H!WUdCHE#zk)8xO=%HQ(+R->+l%ka2UT08_4~;lQgt0suamFD4`{=PLYwCDy}7{DtFvvAx#epPU!kwa!&~BrIlct~N10@3v4& zBbYifGgBSOZqy&mU$@8I8!FdhQXK;VMfFT5hq!FCd2!oG0T{^1&3)YTzQ=>P091H* zctV89m;3P1gJl=-8sVx8`y!o~T9Pv}BYOZHk(j z;mg)1Wwl|Ek;mvVD}Yf23}UArJd(^}U2ScmaF5~&S?*xU4vFmem>}YUZ=9MayXqkE=mBJoTTF(y0vAbp{dyby*=+E1$Z2iV@%356 zYxc0C#k%vm)rZWWAVdKAO-U<~Vq#pfdx=QsZ8FK z2k6Oz$#SF9*6uE7mc3D~FOqoErR|Q`us324ef&puw(O!cUJ|rvhBg}knv~NJLBJLS*zSYw?(PbU*|KBf1NYPq zE{trZqd7G-2`wIAz+)_#wz(|XA#pC*!UH`v1RpQIXJ^k~k>ZX6e6aU*7b&az#h0Su zVgi6)2hhb0IG^$H@g?_z z(w0mgc8eK$n6j2DjS>|)fF=HRr=IBnSOfLL8Ph{2KyC-_Z_fSVBtKs{0=_*C@an++ zpKtNt1o=R@fmR%yozDj8$}tHEhekM8hk@qpnwH~}k`$Gdopfe@3)cMn2_vVY6FGZe z49xH2H}kDbYc$j=4W23HNp%2(1K=IbOi@oK8IP%mYR>UC)e|!8(k-i@vA<0sir7Gt z=?WLz%=7HKh4E_GLaLgmVC0ugj<(hIX?|~`m=H? z{`CMNL!kB(xRA4cp*?*0Pm@?NpDg5pwV~RCv`ZSZCy-lb%bef-&=au1w3YVI{g^~FW=gZOvS558BO|@{>aw%p+g4X0w*VPV-sxGgxHi~x^9G-+$^!KB*|TR#%F5au z>e?j!Jcnmi9>K8^q<9yJR_9g6r@DU@>%2_o+jEYyFD>WJs1PZfP&(iZ0Ug)fJxAsc@rkMD6S-VX1oWw_4v0E_;8q^7I zx(LO@IZ2drqx95S2J>*{M@}C&;jfkn&a|$#RIFnEJ;Pg7dxwWc$4d=c+uN`eZs#WG zB)qNz5E3AE08BjT?-#Bd)=OfVnu~5n9#n#r06mr0&~P8M0;~rUEow=5`R=mID%HzS z7-sK#*R!)TF&UY>>gw|!cP$#~)~6Ux zklFbbuFloN!R&wutPxf34yAECF~!c(;*G>?#XbcF#{E*@LF|KPPtNUwb$eQ~@8>+i zq=k8LQSwoF8KT|EZJOenp7U)}^b>j+dlJ{=XS;6J6tvJBUn46n_v9Wm!1Rm{Oe0=;6>k42M=9=Bu9-RbmA7CT^<(2mE_yBCRNAC%c zGhPx5d3kvVKlJKo5g-hJVXj`i<4=;$76tr#g@bjq-KHon$(RV}4zLlA4m*W>63#<;OwoS)+dyrHUsgMPA z%j*$NZY~LrE@!Y?kvNF*_3U7H8m%5S{}%dtYu!}M)!C2&Y;`z=4XKOyi@7;DKR>kU zn`zx*ihvKlot<_MEkH?s*43SVv+;xv?-3-!%ql5~sI9FXdMTDs;Qsmx5E&dgq(PGx zf!X?EX4bIfjp+Z0)H%h8s>Jh$Z_zC?i@5cU*SQR?>`_rNE5@tp#)|kNe>8-ywPY{O zs3mK;i*7chF`xLm>ZV$h<97xls~nr97}#;~L6h&_l=hK*Vj`TysoIO<`KnJB)Fr;J zYTs~2?J|pOS(Nj8n|u&__gw9z-Pq9fXd2%|$s((0lQ`c>zK8jXqlcSUJ*4gfX|aAd z&yNmN>p(TeU7(yrwT+DePQD45Ii}V#7$~lIp*fXnHffih6tx zHXaV+Ydz9zTi**a?2l2h#1}~l7+fzbK1f!+4nDm1P^~OhfEf4 z?=7EC$ID%tv*56M3*vK$=0=}hdfMmDKliGL?OUm+zOT%!XTZGA31Kg{?$soP>k_}^ zOsckYo;3|{bES~w`-ug!n2vLQhR&JHKZr70sqcY?zs|LqWM>`wjePgef^J!N+i!UlqhMO?OVq#w zZ$T{hzIs$#ues8{ukQX^zGF z`oiZwMf8x_H6wuw;+8LYIK6a;X(sb{)Y~kOTGKM#9{+8Bx$8cX`F5?7(b6Jkss1uf zrCzMF$*--&1#|xbyP0#z*1_vl;2Exh@rNf{Xyh2bAlDaEefR~Ol z>CZTa-Io)a(t?$=YG%J%9y-V~9~4=3E_$|Bce+c!3XL5eReTDc#~;+i?I`_wTy{2C z1zlHlBu~8s^xMr<6fb;KN@nXH}|uPoEE&f{arH!#}0N{v_2!xv*uS zd$=P`PU@>#v_zLv0T$_E_B(0<=Xb*{v3)G}IAU^+4oK2Fl9=K! ze`5sh1$4g~5|_?j+<8yMRAKK0zlU;SbgD+@2g$YMT0C#Q^>eU%!E&M`KZ`gzH^dqF zAA-=2*8$J~KwCmdNJx-MX7+m{6y#WEwc45iI2b@BdX4~Rxzd~h_zOU59i4Zkh4X^} z4D_6(Hdqqi)8aBR)BuVev_Xj36|^8Da@(Kwbg@ zFc?f691#Np1F%E0yZ7qURDeGIFh~Go%Oz!LNpEayY|3{Gv}C{4j|J#oQTq6gs>yp! zP7p^M5YRt5Ick}7F$)Vipn0%30Adkg5s`5~b4_H>wB^YFq@73Ncm};Ysdhaz zfB_<_M|}@)n{7D`-W;lTEscOfP*<#0OXowOTT6)-vshNNT-Y#PKk9o}@d$wjzvnEZ z$uxesN9^oY7q5^M-{rqLzzuE2=5&=T;9Id)Y3%rx%Msy~(Jokv<@vcOTu{u%C8s33;s>;=nn-b4dMb+ANVK!LaQqUh z^WPxF7!{6@#TKiJkVEgPfUrg_1#K9W!_Bu&EX4BinaE-jN5?L<2Ga9nfXZGHoFK~^=zig4N^ z!QXx;J`iO~a(yHN4C_}yFg{`Wt&c(Yw{9a-)wySw^x4PSjSp(3FZ{noK(28a>>U35}@DM7(b?nTC4fKG{0 zz63G@kHVB{>lu#k@isavAYsi{o63T`lvP#P0A29-MZwRX?*ZgY6`z&tp11c#k^1zW zz#14DvY=)+o$YJ&wE(hASsT=yD6-7so`uEK8>V5}{0O~c)N$;fd+9YHp_#R{$$DoX z5aI)p9iS=80y}B$$QcIMMvc2Ot7TUnPX7Fd`#l@vRwbWK^+`W1?b_LX@(dQjH=K+_ z($2RiD5g04!_2aGc=SCwYB~zaR_wu1e~*wwcNmteRB~$yy%E+diHk@}s&Qo zAEjOs*+-(`V*l`*>nkkRk5)%*bS};j>w-tHMhdMeg?vr(=X3j(C+D&utf4CK=ILcTMHal9YMvDB}oscA0G&-!%yv z>7f$y#M}7XE#6<2`{cH^w%&EIQBY)`WRzC`5JD&{MbV2mC&FmF)ia9b%THGJxslCW z$msc+PMFNTL!ZzE)5?RM@~L_3A$>vz%^L1|^$D&uivRQiWZq0_pj{dk$3xmg8l&Cwo1I-F`dLF=|!1BS@Ay7Lns_Rlkp*4}iw#`?q6hC>nXX@|h z%HCQgA3J|ioD5SBheIDTm z12WO0z6z)pfSlUhd({#l`Sz6o5LN?e0>a-fzQ`cRC2eT+Ew8LZnx!t|nC-Fxa#gL( z>L{U2^Cu0B*ML9mGT??FN=izi0KU5!2z{3Y4gjHauF`N>e|FokX0`avAW$2I7}6Bw zc28hyI;z!yfX@+rPs+GYoUDFC141*X+|cnPZBR6LZb_%7Y?myLt>7LgI#Vd=x|Y@g z-FLu~2YKNIEu-0vKl%$Ar@;-2W;eec0v@p>O2)5mw%E&S#( z?@pa3d$*sZJA=ZpW@LCb#!jc!dO_?oyiH$m?SH7Bkru_QzNqC;V7!u-p6UcxfBF>Ycrj_$5zLFaxh-sTBec$J}(VR=Gn~ zaD(|sxFpwbunFNAsHyvWxS4s4WWIh4TTb4DKP;$>I~`GixldE6c4sqU8lagprfJTP zPOwQoIfWtCM?6%;oTQ9Mc%$3A>iT!Y$4J+-9ND+|y}3CZ$kEW_qM+c?b1}T#KRo2M zSnLUlilX6Z1dqhYy%h!oA0YigNlguGVj;kRfV|KEfZA>LvbddXO)k*mN`hGf@%BAO z#oxZ#KTk0L)S<_$5#Zh)wS7-dUThkfZi7n9P+@oCU_e5sU9>*HfkDqHzR_96qpM;r zF671RJeK%=()_AjRH7>57cA4XshhwDQJ$>I$fC8B#fHGlqlT$)jNzE+}^15iXv zVSSn1x_Y|ov8zCj5ABb}QVaA^c@8NMs3O~iH1e9nWhb&NUkEfij(I@6n}@1UZnyCo zBv?Mo;fAhWhBzotq~~JHFj_d-D9BkHCojHs{;UF=zWWxbmcP@cxJ&w~PUTNOxH@FM zDWx=ctfeJH%;zOx za!fpIc&olIN9@;cV;Rt<*n2NYJmQbi6B;7dou6NO(C2=MKE=T}WXR8PL{g?OiDAzx z?omDP2U;0)+>~&Rl^Qav@+DPY78Jqovc3rv2)uxO3_cFFl z0c?QF@i!&|1H*d`4h3c9z!8&2-U(#Is;m|{B1!lpfMwAcJ=U^<6joPP-xZraN6?mp zt*xmUUswq1F?dYk&doh%58NgCQPtr$vHJnds^aCKSoOtpR8zuwIQ|BuJPTuIp zRZb<)>;#eXB`$;a^Hli%tpyOA;z(T{yJViI9*EE#NMkCY*g2T22;P6Yi1&4K%(Yr3 z<#X+(`b=BJ>w_OsS{%=(kwQ+5*0~LP;{6XlSnKyG2EJ;J8}R3BvNc`xJ@CIQfyO2D zI4sQ>2wr0dnLE#(%SE`tJJ>wSMOrrE&X`*qd^@k^HytOI?v{*sQSY}$#x^89PWa67 zizMYiE%v3c%+9b&_02Y%4nCH_3MG;#mzZ`_TzZPB$4k|aeT>29sIqUyeS;w0g18@? zOAX(W+sgn{*R^b{`$nFHso97IOefPBJXpxGSGe&0>?dw>FS+1^|BQQ@UDx%MI*FZ095w(lG ztU={ysZUI}!VKp{FR{|O-w}Zd+V88?D(d=|*Czfc*sH&o|GTZkWA+3frDO55ir2rhqwx9M-vdg2E|6;lsOk8`L?@tsrT{vvP!OvAQoS7! zuWR(>!7MhQe*!|OnWg0+db+!}5A`n3F~Ec6R8)FzFAoSSAq1;QsYOeNI$KwhSAo+eIf`Xg3 zCBN&z2l^~YaIJ_-pwd`u7%Xo=C+$lP!d!QA6A-#oEXA#Hb4@zt6OkN^s*OI;%0gDj zCCYVWRL%sCn`R|C2&rD(n^C+$B`Q4c2gSjv*qSnt8?L6kYEhKlalwmeo0ILxo94Ys zM6N{S`26CSBq6#sW!?ztMU@*#*e`X=a+q$sgh!iGQ6D|s^CrY8IyU9=jMS_;bU`4X z+@4LO$rC}EPE_FqK^>FvXoAm7dPx6tY57=?T?73?*}wuCp_(#Dr(HApp45^C~ zADwP2EFqeh*mUTshz*i>jto&;c33Vea*`cEc&@cw?c8)x7iNsCi7TI>gn@u6mKuwT zT|6Sv%Q-Pd;H*w#vQ}GW3|_&k&I5@xEg6|E(0Vb&lpM$;Zho+-k88e#<0$b++`v>r zBfJ_CV?t8RynxHmlHG3j?lWXy7$FBXL zTD7bf@eli?sBXuxf!simzcs%SAU){WyA91McHg(`7;IQz>;~#IZm#OuygJUq!@>-p z_czPs`7#-gVnma!Z0h?^@i^*?T3snAsd5NRS<`VNn>Pr^NiIMEXhlY%n~bK512To* zM_&fb+UVqDR}I}q@3{$m1W{g^_5Niw5cW^*cyu<5F3w-@wstTAs``{$1JWt+X2nip{Sj_71O z+x|yhUI8sTo$|H*>*h4tCF7p+s6thDgM8%a*>%qE-kr|lEq_~xrYOmem%C|H;RF*h*qOYb9!<>y`1+1dW@9<6)wbbC)PFgF%Z2lJL z8!Uk`5y#woW<8*g#95hd)*R@Nsz|$2!`s7s$$r_(KEk&jUXjfK+FfA8Qqw@o3mdo@ zT!FD_O`$n0f~6{YJeR|S%$Sgnba_MK?VhxPOQfd6GAFnCyxJC^tE}t)KSu#n zdI13>kUIZ}`mYi))k-l+Ag8Rl4ZSMdh%2Z(|4dDGR*c90f}^$pR2du%#k^qt~70SG11e021Sm~kmOZ6 zd<=T^^qpd1py;Mj$RLC*=q0w{QJXi?yMN_Yu=Z@=t0MlJ6ZtE8?BCA%Kk_rBKuuZ^ zh9?JR*Wcmgf1XQ<0HU5Jm(j2Pvv^KLNwT8wTtZgx$y35x25LZNfid59E{EMQ0w`b0 z$QZnM`aoGcFpmbo-I%7RRMdG7e&CM+c;$m4bg`7}=rN1(iqLT8b#|WX7%>0HW z)_wZ24C@GbBr(ck5e@@?*?;QkczDR+S)`aszZ*X0DzC4vVM#TgzT;l4ku44+QUUh$ zQ4zb#;N@+uu4LPVJ&w5r2AkvWUvzwEPv#VBPyhF??>}pT?@HT%o*}v;3;B+Y%KXT# zaeO+D{nL~@JgK9jquvKL05pF8X0n7$c{+bupWtH!iFsYWkOe($J%%X-Xmz3M2%aV4 z>EoUQU%WbCjSz*B@v6MG$dO(=Lr&Rs^~%-$WtS45!RU2n5>D##=N&iljxuW$Tf-bU z{hzn{aahUpXW6skkPMQGRdXVL(D;mwJ*dJqQD~QQ@l9ehM(1&Ry&@OR$f_8zK_U?bZW@C)}}taJL!Db`w}W4@P;^=qv2?ovGPGCiE; zaUhT#1+Sx|UJHP+VTL)d$yt^c({FDLl7k0n-8YE`ucomMnQbG-HWC*d2E^c`NO2BU zjfD2B_chuRx2O+lKdAHeI0t3k$2T`-?(30bA0a{+=-hUsnf#(dLvbuT$;~q9t#3@w z3r|0G=dgQ#nC2Z}v5*WnM_b#(zqKo=kj2OI*0vM}l z{^$16oLZ9GP|Q#>0#{MZ(<26xOG&D0zh7mX>P?k!Z81Tn&BW)nRD=)ruW?M@_3+3E zo_b>+z>vlAPDHa^{otZu&ehh`>log&6AG6qT9Sffvb@PJUm z#kB`s&sY{@0ojWYF7?r^-Yv#B_dYifq=B(TZ4j|-Ir$Lxj$s)6XDZLaACM@#(CB~}&n26SKH3@7 zN{g^h+gC5%ncIsKyX1lYt3Lv!r+?b`ek^4`+XNhH~bLUjs!<@j88@U=l)cIQ>QJ86+u>k zC7N}S(?0Y+-Wf#mc<_|5W%&COxQ0K-&mTNV^=|KVnBaa4$oq=53QbXSQP5=0Ex~%5C&Qa;C+SJBd%qtd> zr7o#`e#Sgkn~<%auMVyF->qs4eL(UUh2Mx>s{c%Q4Nj=o=`rx+i!A>^8#z^Iy%DJ* zcac9GkK`vuoRHvjE#A#GEtEPWz7cBtf&xtm;L-_W-9-21iWgOb&~$`b=2>P`A=XaOVA#b zPqOf9@iSRV+39U8eraP&+^wphjxi%n;EJj@VW1)fM~+#fHMIGl9d>fgCSX&XUu3m- zYS?p*fl=jI>u0m6c%N5r%sRX(J_sko{h1LFsSY1n5sIPneIk{f@>2kkV#w6-J*30DN&Dz`Y%IpyJi zk1#3?%D&0XOOW_f#!i4+wjv$m8XIDxd&EbhNGM%~2awZ42q7osCen(}`wl&iTL-4^ zMo#+4AE-abmcPqg+kREW=t>~)VQ*D!H1@izsJzjlYM_lXIB1q+x9)^PPL=R0_82tm z(sroj#z^k-dYr7hmg1*ef#6@Ko9FcEGEhhOhdfi)eFi3D520ZmdE@QDHxI`po5}{C zieQ*eN&jpJw1!%_q9a($H&Z;1v`pmtiBOjdcv6sop)sv7lwM{EhNrD6z!*gqdiV2N zg+7d5FCy2`i+@%jM9T}2@{l!Ru9fpOWkg|0y&+xUQcK3*_q&2{wNoQ!hM`?L&7piG^29m<*1xL97yvOWavw-PX6gA*@!0_n>$TT>8&6^-t@6Ok^o3x4{q5 zM-*)iE}=yvqR-V+WXIn#$|d}z(vilLq(E#}eSM5mq84lCt}PWD>bCI0O~sM}{<+*; z%EMG|_$z86{&R~-UFn`kp0D{zj0BY|FbJ>VcMs>qB&eKnaL7v$;91Rs6RE#;o!$$#<6HMt z5b0JiA7)?uNx5?wRTt~6z?>E-etW$o703L?lP#)5pSq=*)<0P-E7wnNaehoXDY=z{ ztFSb2zYE6suuHZXqom$it2gXU#nESbq&~#aUX9!tMNap#6(Q!S`~h2sL7#Wz*HSq$ zVSMHdCVFLYx$PT=1bt6 z&BIG~ET{l9@rS<(uM0GGyIL0Uwdg)qIxbVIbg}D9lHhf9oLSVvvZ-6+D}{7K1oKms z6wH%eHbgFfQ}AO)2$v`msyV=r1#Jy$;mYh0By-t*tL^X;QkwlVlM}}fyrMg_&xgsY zATs@_-MQK3P+M66iKD{Y>jiiu#oxjLYen@TF29!QWl>r0Pp;&+ZNw6zQG0nUrM}(= z2qAie-N(0xV=jqKO!KBrMpYLd`U<>S114&oxsnXhY))Z+aqS-&$=VphSso%auw%80 z_%v`Oq2pmqg%d>j@Qle}PH1i@NSSWlGv{?VX@r@&RGr^Zqg1+Pc%etRuM;SDts)tL ze6#;9hLG`s0Sna8Y$oC=z_=dxP(;07ERACHsR>_#m^D~`c^(d@E@2J2EzGkc?K@694bOz{}N5SO#&RDtnIly zQ?FrzL?4?snUsHyO4|>RG^^6=B2fxn@{BqOF>+%QcfWsT_Ko|pCIbkN)zD}dcWJ$7 zR)wLl>h(d0e~uTVOU=5td%v-fbh2=~9MNe0@UEZ)IfjcRoC>@XqwhQan+68+O#a4> zd)s(BJ}IGU(ZzjRDYft0r|9Ly=49WPwRU|q!IQe6x%)fd35bj;@f`_IcbJJXXOI?o~S`Nt1ko z_sW}m<~{6uN!t&}J?hnrlS7f(pF+TE;!XYfPhx*WwZB48dkmnSRM6A&ew!o@Zxu_x z%&ZWeC-0&IpkM>53QHUMdlW+hJbm`=tbe{5)46T*NJJdoxfzM?x5s<^Q#Rh81jzL4 zqcM1=_#ig?=)p2S^v11s#?r>)rPUQR%8K#?%@frzI$sZ0RHXY8KOK`lds5fP>WV66 zJUgEKnSjNh`>`9!&f2AbV4cDht32a09g1*zQ_2+=(OQS|Pc+zo;9pi%Oq=zNgu6rT zms3sE+$+a_xORUQ8`-~)YxQq419uF4lbHV{0x$&w5#^yXgXWWfi<}(t7?%2G{#OzH z50H~Od;_$h*`JXN@c-!s7S>H{rOqBQs>bDZiMKTxH2rgfK+`VkH)nzD^(puQ1Pk7=AI#$QA-#p60#OEv5yh z<+BGn}QlcSrj+A5J&6&iI!4*dMP)%UcTLr+w6-Y%Umk8?I0mK=L?hq_^mSJCJFixej!}GBt$pQOxjqz7M3>*k{rfg!`nBl=wL}zUYel=AA zRqk0MlHz9Yv?xhcu6amf>A71Ym5MD50gYk;KS|%_=1|9^=SudcZs^Z&o~gfY^czW| zW7%t32J0iQyh+*erXd{5LB;iUVaZHnm8cC~<6U?HZDGU(V6A}k(PMWiWYh=SphNb! zvMw(j%nfr=_g~vax;Pk23m&*~(oQL88+NY0+h2H@!Uf%`@+-tvWO-d&_`-hRsAJz8 zPV}AG0F4H5PUBI4z++;pcsb|T7eisGUe?I<)Ou+^PE#A@Vw&+EQ%BDF2cR-M3aiYR zU0QDIn0_40FC*dv!fOnp0zZ-=Fnof;@~^)pxtlwhL&o~D9=izN0h6b%cQS8TEhHJO za%+x(`Gq4il+&HJeYs4s0m|V3saWyk0LtX&9m1in z-;pbQ5edV6l^gF~xAIftV75xT>2BF#S-Wi!>I^w9TeNPQaW1Y^-bbr?`@_UfR7nnV zJPSc8K+ix-j5_6wR4f5&+?LVV9mS_EX=-Gtpr+Z)M)$quF>VlecX-X|^!P4)%ye$^ z>F8tdVoX#uG|VX{(!IyylH;E-)ZB4R9J87qaJ36l8>f+Zk*lAUdg^%m9+KQ|E$9OA zhN6_DpPj~w$BCWIo{F5uWCzcwPJXhSd1fSx;j$#GVvR^N*N6AHQ9T%3Sx!JLllmOh zMeB(KMtNocg|4^V2IzvLbeD&pL%9x$ccMeYxn1m3L$qYWE-Z_Sk9AiVa1$F38!ik5bVW> zQ9OmhZc51erpBfwiWt!+%OyO@hGpi=&Yku@-Tucx0Hiu15O{yXV3YiRc;DDWCPeu4 z(_V0o3FpjDFA_%lPq%H?K2lEn!_$EX-;J7lq-^pHAe*kNtW5q}BqhkHt4k^3Rht8C~jfd`>=m-Cc3w&1$m)P`lpfqX2 z%&h+DfW!p4ep6xo**tX>tBRoDn0b|GH#TpAcfr}r1A%R9^!R=7!PMsI5udFHJfN)3 zQ;R+nd8dNCkxX!;tPyf4H8?_W@c!vU+h>k1c>n9hjKaUqF^p>LUSvLT=;Y+~){|-f zzVUy*^KSt3s}H>@6mDs00S>SLrx>~B+eHij6khwHa1LXNUuNRgolPw zdu(*G@tfec5PjjLo>?67^E;Qy!>2Ye{>H_@)fZ~Ol80Z_M`nVLi1a!wC?dr`T55Qh zH`{=ZkMBJPcW^{cZ%^#DZMqgcM`Fove>Z?XGkcDxcer?jpG|fG*!X9rrvs}SjQiC* zwTRIBQb=r(}!tMhK*COup4x(9x>g|9E;mp&@4j&&9vte_B&*u9nIOpyyKS|Ca-X$8< zM90S3FBlLL>!7=d;t_(3fMaXlxMqNJ;4Utl;^N{IMa81;_ABaIm@Ko=z84pxBrT3~ zm(c(C@uQa~<1e)LC;#5t`#!K|Bq%D{-zmlZAC0R&6c{6VEeYl1IvF)JHNBx|&iuA> zQ>9u7C1r9SPr~1?p54J;d+GpZL!);K5dTwDO`xHxtE)ze8iBqj_NKe1uecxkaSz5g z2nv2piI1Op`XrFNIU*+3Cu9OP+Nrqse~rUSEEbmUlC;ww{{z_XZoF3dgml0&JANZf z|8bV1&z$ZKgh*7;DF1rqB{yI&o;5c9*A8q&WW5&q%c4-e*F3wf_=Xc>@~@Ns{aBlQ zAmfp;h>Huc9B!+KHE|vM_nlm!Fs&a$#=5k=4^$hbY*0v%I6& z#qUBIw=AS2cx&7coLjoH+q?q#PLr4oC+au(qel4tGoNy!;jh1ZO_P@89|f(P7;WU@ z#j;Y@5v?rjeL-YD$XpAZZu*_3)tQrdbiZDiufC{fIAffWp4OK2_xLxK7?CAPjvlm@UKRHJdy`a5^ZfK1;xL(G%;qKWl8|m!@I^!MZ;N7@!BtUR8%}u^ zy9+8x?1Xfo_?GB`L%I-&G@hMvZYFcG$ybT@zhO-ft+oO#zZJ)A_iQ_EvTc9+%36G6E2u%PxQRwI9mX@$ZewQNieJx*)W+{w-R_NH&>cd zcxW`cLSXTCv-Ebz6Nd+SQT6Hz-_mVoWL(xaO3j_^*zIPpiJjOhw6?~(@LP3azu$bD zJo1fmlsx}|Je{<8a44T^rkZS43y1Q0k8~6}gIv z2=bg+HC*JcZmFF)T%RW&z0&r==G57{Hjjt|;1_d*xvdA)Jd)3D6}K>g4)!eMqQlzg1x~H#vwcoC! z%lct$tZuZ>p#18J>g-hxj$HJN5G1(R?UaEAW^{y3T~SAtj3xN1IBhq2O-ayrd!qn< zU*0>6x%_BQ!q*XVzc1J()d@=|`SPCM(Ylny=NF`>qU>qAe}Q2tPfZl6P~I{Qce&4r z_Yjt!b*#}4#ht%xZ4TH=+S2<*(sA>bp)$-GyQFQ&9oq9c!Ruph44Q6?S^;~1ve~o0 z)dFQILB$)m-$a2(*?)~kaL}-ikf2JUi{LG=)TmT%Z!5fmhq12ZeIPP!N+T;yPMKt7 zsc9&jKiQcRnHHLn(XJ`ctxRR8@h-u`jV3(G`*9&#vdH-*9{Ez*M|&qVO)~74jz1f@A8>tCv-D*U9<$I`P&s5j8lH#O)!&ydZRvmU_1@8NesA=s z79xU#=skkyy$>RVB!o{$^j=2v-bZgCdhZf~h;FpedpDvRox$jgUIur<=kvYyuKQcp z9~O&u)_LFeoafokv-jDj^*GFyF>{l#AIE@=c@77!(dq1AQ3htq`}dppVd>1q^wWI| z^m7t!|48h^w{VPhrh+vOp8gq@!>}_!&^GGGn{lU2#2@TRi~2FA$;eaj{T8i%2>P*$ z$&j$62Hu5h0raKUzdR_XI{Gqn+vpG%Zp|1XMV-O+BOyEZ>j#g$Hg=es@@#y(dTQ#? zDew6+LGo`@`=g_TM??+orUH*?4(k3?seW&l$M|l<5~T(r6LrSr6GPJKN={bf75QI8 zmd;-bMEnHyX0=Cj9ye55au#MzDZy4CT-qXL2JZ5AIVlc}_Ju{#1k-TC@-ZSyc~>ub z^*_^wnv1N9pKQx=sTKJaj=wXeSm`G2h_lkj!Rs`h6RLaowIbF;Ja$L{j!C>iuj)=m zC0OwFji|1y$G{7~#QQ}2bn@?=?{Y}PDuSCh!MV+h$3hT%gPRH+M{C|(t0eLc{Wxxm~tZLxOUf3sveL8$YNR26jxt^u| z>+lxYv~iumrprX@nrJWKW=!)W)uIi5L4jC651hKGIi0gDk1^ZANKC%3n%n+ zVKD+5Eq)`E@Q2O1xzY!2LNvmjH`y@@Usi*cMU@UzKb%Eal{9;bsFU0L1fII+o$<11 z4)a(L`HSB;gjpGIvNK)f42~s9b(YEuu?)k-JqG+E#U7MX#}aHfe2WCvQ~U(<}?#@xkej z7V}`!3yhA|o(ayHr*>E6S^3_daS$POA(UV5f#{SrEkFE`c;0)axQ$%=J=Zfjw8tDO z1RNr=Z~D8I-clYzqzU^+f_~uCNXdTM40@fb56E*@>ZJON9TChPWtqhD9bUz~J*O=j zG7g&6)4ke8ujtXBBu8@k_d|ML4VsPD29S?{9m*K$ae^VyET>$+wR>ve zYg#80b@$J(HOzR7ynkS)x|W$9s#!>I|1^^<>%uq(*CHM862Ifw{&7MfT3^n++SRc+ zyLd8EzXhvy7o6E7u(NcZf0bSoFZs` z_o+=?8UN(?Y{MEAXrSG`pX76u|N2AIu1OxpD}i4+S7Npn6vK_HXSEMInYDPqTq-oxeLaAb^)+SE|9w`bkgh4t&uLEBk(R5PNIQ0cJZa0 z^M_CAtAWV%6{`XD8>h2i^)2ZOqFp8q>&;&WM0wQf8suT*GB1XgN2Q4GE>xY09jcJ} zR|%&ihsN@Tbi5McG^0NYpJuAxj`nq=h&SjgRrj$w*m6L`jQsC~F^*bU^%hf(Mu*L^ zs3JVfb?btko`~Q4Lz1&~2fzL9u6t=|YfG%%&iT~Vh2>fDf88D^znArKd!}*SKFtfC z9L`wxS0Dc?^HTGR|H2V;7iV^sB=oMs;Sd>mP!n;cbCbo;dV`RE8e3!IvkpwQV7wiF zOi$=rutJ*Pt;1MP@A}q`H0R;(e`{6z!9-Bv4vfW&8hf%kx5&Ld_TmI%ZA^2v3WSNS zDDSwDaGg(zv*zY*Z#p~P0P=5PQP24^ol9rgz*Jr18ga1SVY|A!yDHgkJ8)ao%n|+p z+(XrRa8{x$TIQ{KPuPZ`W4b3pBy@q9 zp^b{T>ZU~MO7r`B6De+9YoeS14qKI_-rEy9Mef$T<&L(?mlRq|Us$E6K@5QQoZPAa zTs~D0VgYP*(6c7AeSABcbHX${BC;jC7Glr~-v#n{Sr4_8O)+_ZH zOyVr7+4nitxT4TXV~gU&!3vd3hNRvF5T~aJ#EUS#xzVp8Y7=RgzyE6+_t>^%B|*7( zKo3L!nfn}HtlfJU+7IzbB(wvsb|!%SsJ9W;C^J>N2$mLmN4m{8teHiur19H*wq6~q z`0$Bdh>wikv9jDR?+nW(P4(^d_Zo=i$XsDP1K75}KojZF^EhDRRLxeU)#n7wva?$j86VHWNi<=g8I6Y4;y8d4gJJiY5S zAS9G$G$;OV%tgI8xN-;cPlsU0!-=Yer<1Rm$pyTy z_+XJWC-&$T+n}gz=EzNs^C#7l3v?@J)-A_+Wk{nX))IIA;a1V|pflNimA1xMZR~M3 z$T4_0U|6#^Oy1=P?||a4XO86v7c05TELNt~9yK|~hf05W_v{=<@=NnnTW>0* zW&Cuue-^(z>NMAYdy8Jb7f+5~#_fxtNunmP1ngkMV!rs$DEh^2cqdmqE3u%og$Np? zcoJsXyzNWtuV4XRs9&r*R9FvM%oiYET0CC3-ZctSje1D={W=5T*5pFn-z;N16~cF$ zN1p-E2$?z#&A=aziN3r@2Sfq{%~Rv$$#b`Dg_5PL$-k|sAzy2j*-$2pgyI|n3=?nesM_Jfz zv-DUQdRo&DllfBX7=3G)ePbvmHiF5m5hJ#9?Fj|sikUk_XQegIZ?x#aalZC(=g@$K z_Q&v_+fhD0iz)&oc}3wKH=nEdl2(Z+Mj)$H-e|S;c}#al zivbsqmjP!}5W@#aq@!zQMs5RqU}>5LZ~iy6>~6G#mlF=@TUr1`VZyU?H_6tmL!)Hy zJ8ICBQIHZthVREKOa`YXc5pAp=K|OeqLRz(Sc=~k_&U-NkGYdcth*9z*sl8XGW{M~ z2c@c?k2jZe#mBejF6aypj_xE=dMmZ--o^w6f$WjImzySE=0sP-8}X!BS#!Py+Fqdo zy92BVa}-h~ATp)tIR9%#L4)771hP~$dkcDCQQG%TEn{%4DDzT@bt|cbg$CPT@Bh;{ zsc>C2TJ}0%HLSmPx*{sIgd_~U^Tc~gy5zVNk)*9Wx^tUR(%-aI1u~&~SWif!)YSD5BpCyw7m5;Nn62|u*YhN@>W7Fg z2yLg!IW_(rL(jXf>J^ZjnKEqb*Mq>sL^CW%1qA*cM;&zPb|^ImFz`yd2uB&>WLSA@Mm2b~Fdn8}J{Mav z%5mr16E+bzoFTt2vWV1t7g}gE=wsCZI>ahs<<(<|wqTQ?pseHNyiI)pl{L2$wRdfx zeC=AafQZ;5?)S{M8iJyU(gV8RmMt`v{%aN-#89J?#o&bAmmY~hM@3c+Idg!EX_pgd z)=Ol|YLk@Z`BkcxgH2OZT0T)-$m2D7mF%FO>mCw#rB=(w%WRmIPm{UT6f-a-e3|R@ z?}7B*Hu%2ARbx?1?W(9>Tc(`#4J#)}jFlLc9j+p<-}6d8<=kSDv7HhpbiI2qy! zx{scdqln+s2kE;Rg~0%k-#QyXfAM8}H&q<<7p~gsgY7WFvD0MxmDQLr>dtUn-Q`wq3!M5qG%E>~-^P%=?;X>F! zkROZXgL5FUFkO@EmVXfIGct{3mcWh`H2O*l@0z zK;Hr1m50(ahk$Xqb@uWm6INXBX4?6F0>NcA9D{d4w7VFD;Ox( zK5b2G_sWLUwz-^cC>nlz1MkPfmy*<|0`gYha|LfN8_(aTdAIw|h=6^E=da>R3z6eX zn)~5Hz}S0M;xLV?<845!UdPs!t4F&MzTuucOat9hpUzy`p-?wY z)edjR@_VJHsQO;6vZx2&{r6O5f0Wc{FckxIPTOtL8eS2Ey=RY3fd9RodmlF_NTm*C z{bw>M!L-AI49_^OmdnD0MTGyUrE;5Y@J%SvnHiR+t~u;0O#5YpG&~~2@r=^+xO%41 zt<8_wIEU-xahYaT?bjF>AfH9EzJDyEqfs6!&)F1~CV@@q+Y1OvNt$B!86vEHnTN=F zo!`H|v>{}yAmCS;_`8mN1OdYcNR6Pe({zoiFfx-67Tg_Lj3upF*Hv;4Zg0(JP zF5b=dq{0+KEuLkmJK7>k2Y<`F-i*3vPm1`5T<_O&%6kKrru)Kfs4KyCpNJ-9oOr?3 zKOBjNUPFaz%6?jMn_6ZWD^w<+QfkUfCSLeaS(}{{*Ze`gXWzqSx8_RRK#3XrD>>q@&6vzSVceUCxhIR#D!*v zC9T#BF<$*nOTOx}@ID_ZHL9RE+}R@>#@&lU2 z{>Cb-?__z`Vp&#v4kRbWlI?U@<{lGw} zmsxa98Lr3HgcPj3`4P0@qz+y~BA)N@8Ky+PN+d&N;6L#>^&F^#zz)W2H4%M=!`KAt zT31g@2VK^#*D==$A-6@0gW4Bcnf{Y)37Rm#-MvY^)~`%X4r+eN(YPPq75bj{8E~nz zYbBxtoQo^4%Cm^q5B!L39Zg$Uq+?>u4eNN!VTG}=E*4Dp<++|ZJZ}v)&W?E9!taO) z<}EYa+#ja$L?L3p|9}pqxat5Qfl!Z=U1w5Cv-X&s7FxpOe7kljg_IOqY*%hi8MJdU zx^3fci@=?iHi(us#uOZ-9k^D*uhwJJzGmx?9=uJ~4suBJwlwP^bSOiY|7Z_gD&veh z*$7n7>vCdL`&goKm*)IUL0l*r$o%S^%y63jR}6t>aQ|%w{0S~Blw*EM!;wMvUsC|a zYH{G4%&ITH&?GDS)mNU&9DO`|lYRt}IZSgu)-X>_5&N zzxXfBLRh+97B29R%>C|erT>4s9#0>CtZ9~BvHx!*F{EgQ`@i1HVd(#E*Q$4E2F7Dk?bLeA|K@3^xOC=PBDnw^5!y_LIY#C7 zGoNjT&+E>1;yv(E!+haHpyzk^MZXd{E_Q!X9I3Yin7lZup#Yf3LP`;n-05)By)^YBJt7Ii5pB!OK#PNA^J%wagE9HyF9J4bpd3`Nz17f=o($8XP5wh z`%C9gTkUi5`C1f%fz5O%uF(Ihesy9qRR(nCRll^k49R^`#Smv3KYF|aYdOr7v~y;Q zmb7H=Uo$z48m{{$eAAeztj)yk!&AePA$w6q=Hz?fnh8IjHs`vze#j-?Cd;;WtxQ(^ z#;5m`Esb9S`)aF5$Y!xT-{nu-9~ry8@aDy9Td`m$T@i4wxnyN@-H&yl1H#qp^$-2u zXB-25TYIvF^%dQv+#{IzayS3{7Z}8RPIoNk`bvGOFwN#)92OX2M@d1*lqayf4{|hr zGB`W<9++JR30D!V-K=5{L`=65@LHKP8$TxI<)#(umOl^EF9T+UF3;Q~nyRK3U5=|- zAwO){y0}O7il#zv(fH$x)e61A0Hn=r>0N_)II^mfwPQRZ*!*KN+w<(2jI~c66n2pA zS$kt~`N!D#6S7NzW(tnIcczKj%SqM!+_1k+#B-e{`8<-r>4PWfx@pvr3#++W{9TU(klCXj$HL@9_!i?+l1y^ElD4 z-Nq51uXZZ!9#_HU-JdrBAio-%GqLte{XCPl??jbcL=?6* z-x146+f9*DtnI!g8Zh4=FdLs#l53?d)%2wwKWR~rL;YZ12BY^jE1WHyadUEzB)jju z;_4$>;J%OmQId1cyJoE+FZv;uSezLj^w#%>4XX{zXIn}qaB5u&B3_qQvqnfOmynpq@YM5>J>-6_ft!W9=b(j}RW&kBA-IPyTIAc_&7S5XJ5`9iaG{#^ zIr7xZKr$umwyiBbcpFd^{)?yLne0*7?Bsni^F#9<0cb>*dcl}qR@Mx0IHm*LSTKJ1 z=VlF#+La=Xuwm?|R>R3abJwrp1I}F+`nSiJJzePHBrMS-0uSl{%!zWv^X&w-SI!W) zgKMRUHz&`_^E8-x6;xV6hg5n{wtnSi!Wk3ST{KgW%@VxiH1a0*WGi=&qZ|(dXzaB? zBFpPtOrYc&M}@OR^<$xXW(K3zw`s|N{J|tiFvbOE`R!DEn{4`%xL$Hxv*q0B5 z4GUjhm%zTkmgDfU4XIs}yYim6ir-zVttL zQfA^(q)>#%uFzRsI$@jY;^w^@tsTStKX9t@`m@G%IyBFx--q4%Vn4DTm|bKX*?p4q zORhy39wUUcccWPf&z{yH`_Fqql5v@opu#*0GzsZguI_NS4De-gte4RnJlqpq+QW_WdazJy&VzWV{rUE8l{2eP${Oc# z|COh`O%@id;WK>MwUOCXAh^okI0da9v;ifvbFg<|JsNEei7#z`=T(fag}3ut82VmC zNQ_1ViIPk~8B8x??mW>;Y@gZMf>kctQ?tU>oroj=(xje%S_{#Gqr=O$Pa|M8P)QG^ zVe(iKzgM2@p5~H~x!o(5awoqY==P7@o0V~HMdFR**&has)}Bwf8PPl1dig@SyK)X| zz0VgMu0ms9Q#i~p2X*6ED>j>ok19J|KZ4MyFAOf|NOeTq1-kCa#k;+kZ+Fa!E;Lpp~aQN#B%io*PqbJWCCUf{pHkE4*!4bs2?iFi;LDE%$b9 zo1>l5mZjaI+e0LkdDf(RmY_Mtc*NDqlAu~2sChv+jVO;*dF9v>wB;K5Oc*yWV^W0= z<%U&S;%E~uI=uzWAxO;lNxQBR6C0o5*eY;k?G=4 z-qC?Gvg0Cg<*mbW`pXDTLRvPnLwj;*&mhj*s_5Y%k>Q6?LO!|A?}L$K=~RvbP6-cp zLS18U8-}Bm*{OJIW|2{5XyHs*=Q4cRPK@=>t@M}0s(g3XCN+H!qocDcCWWd=1MN|& znL^~@;qk@FA=874Cy}drm|wLhG&CiJGPu>RD^E4DGufyI+Lw*ig$H9t3KV;^!{#c{-~_Eg|O(#20eiO9iWjK zIoc1(IODD)H5ovk1Y=aL@ii(+W={1EQ;S;$Ilc-1x(yp29`=*s{t$78@Wr=S!fE8u zUuXo5H@|(Wlzbdh{#T{00|EfS;v@yP(ED}Qr)(H%Rbcg%ctv>S?TYxCp3E%{P@sH? z<~8AQvHxjlpFI^2sARh%m3s>APkQS<`TAm9!myvNDmw;e+VT*2<{5CHx9X4s#9Pbh;b-F@cmrOz@C z5N<~|sBkid5WUhHH?#;B6)W$3@+6HY^8$cXueXelxunR1?Mg2pTEl-=0ZxWw;FEiF zKHDaNp0@>Y47e3tVdi^2K->>_f#{XO`QqfUf7W(}v2@>ASag588_zt#ZB0-?_ZR`V zgzVwSqqe6$4)#OmzYc}AFwIYC^G&`+d-oo>866pL#beXs`YqG64;yCrK^mHYR z)2AM>vT$EAaro7D-VQ`-2$mkeZ=Wo1iC+2dJ6f??JPq+)+K=ng!Q@U`u$!y+e&9<-he{J{R#47-vdnt zvVH0L$d^WAoBl@W=8c$)TSAiP=cS{xvS+ladd}kP`ptgapO0xDX!W8+zGhx_zeqUgD@ z1=-WSHd7!ha~s;*X1PfJ^q1rjsj%s|Ipq-S@7VrGe{wA?>7QH4otEXrb{QY?uCXkd zjpt!IXx+3MVFNnRDUo37Ys%T{K7B(*Y%SiwqW+`;Q1xxHW^DgYmzbWGnEh1VKY&MR ziS7FOB1D!5CcW$Li6Npa2YuP0KbOtgPb5yXz#87>B=+=d$~HIQ%?f4Surn$VS2G%0 zkj7wKf_0_9ZtdmNmF&H!i4KSUStFhed*sT*gKOoshnckl0{-xJALS2K`ukg_r{LaE z1r+~a9uI=)_XijH#$}iXxOsPYb8Zbr&20G*g*1 zWcU}PxSf1fsjk4AQQrMt+y6>8gGSju!2cV`{@8@d`P#QzywcuaZjV}|642;2^)i!=kG|V0NxHv##c=;&IqHr6BdndHd(#_^KDb$p zL~F>`6ri+Z^MxE<5oE_CVLL6uMMUBYb+L&s$)QS{)szLRmXw;?-Vyj%TyK6pu$zMM zk7Zk;>Hw;ffL*#8{%5?UF8`({kzBA-;fA6=FCrWJ@LXxF#MORfavEtx)qHla7&36I z*Oq51i7QPLzbA>KNx^^BGqmT7Tv?;;BXSy{HU%O=7V@SG9miSu{VW&>z?`Z|C}C$SSm3s^sd_yRZe_9Tu;Q_{vyiA<0r2E0b%wA z|BRzw^Gx<>b8UTe?3b2(u=%AKKy&p6)c2D%tBkh8W0sG4^KJ;$%wpuonAuZ7=chML zhfjFK4{qowcdVvu?U1=t*n?R-E+Q|ctlw|xgZ)ln7WK;SePb+ zcY)XYvSn@ej#N%zde`tAp!D&{V@YVAH9^T@3BKuo9>W8STwo=3N1o!E)=~##$(7b@HSUuBvc!z4Jfq7#ta_t zdd{-{^q8|MJQ{ftIJS<{1YX|)A$pE@%4ENNYqqq>Nib2_SkCwd(*5d~Edk)k7sQ|! zH_*RF3$}Gp=H&GuH|RU+KVKTdVI;Kl(l>m!d0$;0GKgQnr1VE+kK#{PT0_8-~UJJ}J+u)jxt6mIqs9NS= ztHuI$?(VzHOxz@nmcLJsptQ5r%8!r7gli37N@;U|qCd4+6LaM)zE$n22_XIrLhneK zp-0`o>Q8Hbl>&xtc*9;kD8f?sHG(CJg-`jB-zZy7!lHYMwK$Z&cY19EqR8fzqEs!K zk}@}lsy6d*nVExa9OcxEj!N|cW1SF2W)Y#G)zrpMtV`+My$*Q%5J&cTG1mKn*x&xy zXIGdGAAe!JiCDV=0Z;*lSKdRbo=RT1O$<=+Z$12Cu%oR76`gDROQ|3+qQs@vxAWNy z$bBKw66@wwbq1HKr;{oZ?mO!+E-yQtjim?S&3bP(5T;_bK>?;VU+v2lhr8L|AsKM+{T$x(ljfWVVv1W%l*U#xwlH`!74thNbODTc8=bf#5 z3KXl+o_Pnj1W_PQk_Bq~a7w@SKT5s)qAbDXsO^(-vHP;`0Y|XYUm3WQ?}$=qQA65R z8g1S#yOM2=G#ovbyT^(|qWf(jRYEH($XRQkT;v7Gs;n&!m%d=8_N{DNh$u%n# z^%X9y{XaLoW&m~4Ze{|T<+TpJc*UCjFXybL?tz_d;WP9b{fo~WAir?wV6oFgA9FJ>gn zb_10T+Aeb&tnK!%?z#UwpKE|@F)HIOOJFPDu+Jai578+v$Ji>GI)FII^O0eonlYDIy%-_S2;Rgxs2^~yZPI9O4|)0 z+Yvf04qOnh8JN1|@SbhfTvDPQ%WV6)F|tY(f3{oUn@H}z3rc(=cahST~{PeukC|;CEakT`j>90jW50) z2sf`}O&rl8vre)ct65JX0-TtABlumIh1|?fg32m! zFbHx~FH$O;Scmd5P?upDje@yUGEL-+(BN^8-Q31|smdf6v{WfxKAJWK*=HHfRx-=1 zc56v}$$vEULBV~2;=MR$=9UpU!Nw;q!U)I@Jok)5j(W6We5^BckI=|9O&QL#JWL!wV8nu%zWsTWT93A_I^97~Z)6OZS zs%EmcjD-dyQMBg-&1dV3n%!wB*AcLRovY{f#m_^Mh$;#QmsJJaY=9Qcm-XX5dR>Jd z$mtyT@{gJ;|-eM!49cLD$QYv!{3S~xm1Ka?8Zjm}3Z0+|)tjH@o?j3^+vDvM= z-A|5Jc)OoO~d? zL-0J2U`Ft7Rox^IEa>9&&R@43(yKwt3quyURt5hSrBbl!pd8yiYlnyq4K0Lxr)ZyT zW;haN)8VP;G9z*Ws4yx*16uvXAMfMcKfWlT_;P~D%2l8Sy@|Xm5F3}BsC|avPtTy_ zNTTW0^tu{cUlCe;q+_$o(F3!i*54Pp*&kuO{&8BsUMz$SG-6Lr=uV$J1sAX+WX-wn zZf62lUug5W*n(^$>&jzNqe>7XOeRhNq91qQ# z7z0tX`!Dob*Bwh->r%~W#8cb!VjdmV4(pJXEPp2;r_uUF#J2Bi>^n)##Jig5@|(t0 zaBEa=V@ZRSd*{VAWQXcuPSC33$k}3smNXb~uoeimu&F#8^AfesM?7QLE?iC#wr_CT ztCAAD@a^IyIvA)P9k`tMFiW#aY{Z+e4nIfzTv0Z4mVWd=#r|h(maSxupqwD5E&V`6 zVEI7C4dEIVPQ#NV5OnC943oFX;~|qyIfxp1MwQ^SQ%TlkBYY9F|M*_PGsIkrO?S$L zih>^vEP=yK|6dQ1JbzCDwEJPZ64)w#?hT$7&X7lL(ODbQI;)PqY?tAhNfx^=t zl9Jl?nDhrzhxy!CT7Zix#V$)zk<;ueY5mW+wL5uzlHPe3-S_FE-9;P8f1Zbb{=}MW zcbeJ&tZ>5Z(WzfB^|~;gwLcjm#l5VuT@)B1w{@Qiz*PL#pMfC(x&F3soa>eJI~L?Smyt zH%NP0zHAbu9*QUq(^G)W| zLknUp4@<8#1l@M))m-R`md2H3maeghu95S-1H#yBN@auSpeJrNC=gb${1&9fQ%atD z@{Zbd-s_uPx*m;s-zgi>{ zDkwrut-F0-l0jA$#=>Iygq=O-d1X+6cVlWzlx{y*Gee%HkO&DMWJ^H}ZU7uVlp^_h zD)8dbagEK~#&5SkgTE3@gd7xC}_${~slO6A>S((^P@o6KL*vd4qu1Ng`eyrF^R z%@s@hmoFD!dKk%E0~uaYZ`Lcl2er-5b4IX%o+4Cg#%7tP(p}3NFb%D(0#tTb9q{Yc#p;~2r#SIK zVpRM3kAuSpvxb5vM~YTvJ`{o74FhrmTVLbR@)~wmXMCzo zE;kb^>%bBRLo8FV9j5|BtpKM8*$QF}xv$lB_ie4kFQvs>hRXs_=ih2gt&RY<+Wp{H zXFb77nst0CR9Vf+=$~aXEW@H`EAQh3w13PkoOw&|4)=R?@?_0~9I@Lm^MqE5)agJ= zScunNNp6wpS1Oa0gXK1%itrrw&3USZ^Ng4D<=wH`d=a91%_$2$%=df^cJN)Q*aS~g zGxyXZ$6}JPr8gsh6-ABLnsre8jFs`IO)CD}XbM{auqOiXBcDe>`=2#CV;{8U4Q z7Jhb}or2mLb0ebvg#d#CKIV}23RK#C_x81?Hd|XWCv~?!e+{gXaIdd8YzUC2{-Q|L zo-U}5j37TK`p3HnU%#2E({XU!%|F7sA+hO{otvLL9C#4>12y#yS`ykW9a}rf#=b#@ zj~o|9=C&%@a70@$4gG0rO2wT1li=#5%2_bcWSZ~PC?b|Gg-Z~(Qx4K}t*Do3^&nnd zdYva$hh>t7G#O+Uoez>B@LoYL=ginS*T?VY6VY-~e{X z*x{U>2+LIiFJ+AK?A>S5--6gfhoj`_hT5|;=3hw<8ZzZprFiWMvU|VZyy}Rc>O508 zsQ$ZInx|$doK813MYp{<(2#g5@EpKrcn!f*0UoaSWX&BO{@mMFzR8)iSH%VIdZue4 zbk+?fM!Hj~oO};hp@^l>t9U#E2R_T*oB^$o1zACH$ENl;M_h|{#5s-8oj#v?mcb*4 z`I{W*#wDWcW7(1X6E3=Sgx=@$lSiC+$Eb8igb%PY!_2#nvNn8%9${;{#U^ERXLv)w zlUE$H-_5HVThYeQ{Mu@QR$`fiIWu2VyS+sy=3Wf~&d$^Ad4Xz9Pjy&xG&8){yx{74 ztPPBh?Fm zkg=>$SM?cu=AB~NYBjhPknkCB0|~fs_X3QEG#j{jl0e9raZ=fNir2pPb}{STqva~d z>)193Y77V?)%^%~_0XIhI1v2BRQ_>NTO;WQ0A!Dm_nCFz$mG-6Xhs;}PJAHfVcO^k;k z;m+j;c8@}=pOO22qAge^RK_B(g}Ch{qv!m}2sLzSm<8X35W#AEi_;E{N4yuK9*GH` z5g5roa@`RPeYbv2G%~!F-?*#V#%9T^Pb2o`(oe?dIf!f7+}nq7xk<-(`=oX9)UyAp z@tW&d?|`6;+0l7GXT#-nCfRAmd2g40{o=SFgJ#6R%4IZu3RDCCi zfyp4RO_FT0BOJ%N@}sscpe@DaA~0uJ?r>~QHFUuxP&7>DN4XRl#BxT34}Rx6q2vW^ znn7o2Qmk;w_FK3lEkzR#U1T|;rf5MoG=!*0U9@oL9{LO=q}47TPQ8}4xQ1Tuw63gw zM=TKCEI5a)P>WfvCB#5#$Pd7}A?~ZZc<%LN1Bp*E--F{Oo%}^lGqNS7lp5Im+EAf@ z6ib|>Z*%jno1Co|=F(JH71u=R$N>5dfo85wvao^0#PbeuW~xvQ<$gY}&;89s zrEO+>vB3Tn2DX{j`{r@^2c@6(w_=$A^)fhlF9eO0r3v&2c<>!K?bnU~-1)D6_)LiGY=$Bw4k2+YQC7GgvNV$^n zzC@j;hN3FgAIU7ZMl;lOMW?wFHa9ravcK5x=XGl}UyH%3+l)?cRgJT7H?n2HEA3~V zUl^Deq1F?l^Ph6-%9lKYi8?~W>06W`Gs0h=ompig(Jz)(urf1%^s~sf@biWM-5nv3^u--){eKq7zqy+{6E(Wo zzD>?6oQ3f9$RC57SVnTmmmfsK`&yj(1u5lBUqcz~euHNT>`-T+1a*2%9MkLtR&Am# z4@G?T@&@Y`mQjD%XPs1oNjn>XJFSL31Kn}fLrd@Ak5rUko2EsF z4@l(WC_MjGrg4R)?3eUmQNhXa84^9YDf?CF?2m%oK#Pqw2-W$ zcI~{oTGF`>nV$Y@SLYCPyUtT!&YNR@66yZ7_8vdRT;HFNm+E%g0elzy<6O{pe2M)y zDyn=Yr1)PaN%frDjA)RA`04-eDCqs?WwSPK7W2a<=$C`4(f1AZYLB*S~Yzewr^CQ6b|H6JHHkiU$MdL6u5S!b8yj@1WQ>%>ac2Rp`wc`U#F zGL_d2EX#(fAW#R~&%jR1^3Dd(VVvr31a+qoNApj|WNqh3uI}|`k9J2{tw_Uaw{~GB zM5dk5UDyrBef4f(nM-(rgLA!p(~Y27cit?udi+k!cWGj2^-WUP@+*6lbA4*p;i7%e zj5&j>LuPM>G-iuAY`l5XV>YJ$tGvJ9ifie*Kw%`fyE}p4?v?<7Bv>E>cXx-zA-EIV zAvnR^T^fhr?(R1h2VGl?Y30H(zn&lstgIvw|8*h#v2j9-uY9 zFxq=aBwH=W>e}(4&?OVG5-b*C9f={fi&Rt^Xn(K3#eu^Biwu{Cds|;$OdI=N2se&@ z38;5Nuks$1y8Z5f_;!9EttzBt*LX@>Jbvp(b6Y8RN?x?&NYHzW`n0+3$Thy5LUsvO zx}oZ!jVzuoh+P0#tLi0^?PfuW7dJ`i;Pyj$!o|1Un!6|lCo=NuM#LucD#In6 zTOW0W8f#GnF~QuD7n?70W%^Su?yXWx0(`97nM)2Wi>JAsNAUHD%3pmL12_aCTQ%|R z$K_1n275#;Zt<@66c~%Fd`V7yQu`M6xCN?#*xq2Dxvv7=0^nLt1As%G2Tqyw#OX>O zcHOes7DpJ$J+suwRAn4X39k~Di73W$%x7^#=G=|$%nmB8N4^?;4~B$DXhL%u+g*dx zrnj&-s2lf7S?|V!Dx)u>SB-o6zc>0xl^)!WXii$91}-0KHUyPr&1|8iRcebtq;{Ne z8;qj3*cW)45TeCmz-;cM6{M#c@s?%t0#b2MD<}0;7PK<{js8HYYBj%uuISuwZmq5l zyS@k6_Y-1x%-ZhG0GNfn!14QRA`+sEARE2sSy+D9p9_1xf))7A^2P-HTTB+%c@r-; z3Y=R-IU_rsRe-+^6KmFyyuVIg`L&NW#WlPrE6CS7e|4@XDW{Kj7D6d70Xa=xU{-CJ z*v+x<$`)EKRGD+xwpwnTk+U9K*doqlXLvULPOc8Z1crJY;a15?(0yF<^7E_L0c3A$ zt5DR(Z4vg~Z|Y86S2HKktaG-ShKUPsqu51ETGn z3E;Qw3*qE{)?Z)-Zbwy^7g9~rUMLK6q=%dBsAX%yIj#@S6!Ej`FF%mZQV16S3xj!( z_HW)K_`T$q-7>or}^mvlaB+2>lWIRLv>zrI|R2zY@?q)+-ufMHKnxl)-- z9USUg6M(_jHY}7&`m~Nu;!j4KIVCXX?J&`r zdx+eT>ZSYUw&gfVF=n7G}we(TTc_f}j-bLB>HTjr+j>EHMtFFFbS2g`WXqo9_s&ngu4UA8NCvt(=P1tNX$|)08 zlSXfzj&$(j6_qxQO=;eR&>nwAKI{%LOncpO4i~wjS31#9BYs2a zB-;5M0XGgmZD`RY%`f{8E$Y0c)O32nH&15?9t&&yfz&RSXJCy8`w5@z4RaI3mW7MS z@MHP5X!@jGgC_^BvtzWcc93%Jd}X<3x05O+B2U~k%>eG=!H1yB zN8Pd=GebnfFT7j?wXJ zavRjVCWPDV(y|3+PFR{OXMaBiR|X7EIC{gg3Koh5s`V9eDo-m^jQyVSYo4FX}Vn9s#`#a0)ZmZ(M~J%j7K zrTf)MEp+KpRo_%bzJkvfReCwFc6wR5o&9XHN?SiJZDb6cmSkqIkmfov+G(uDIPYmSE%a!(k;* z-x`0x$t910(f@0oQFFFdv8?&nxGY_s6I>q=Lq6<&f?#on0R{us2#KP$GCBK;W7@P%V@ zwIfB23EUY%@e#v-4cDbqpddx?BE+}ht1H%!uDs&yAG1HWT$?wWfK&|I%De! zB2>jgielrb5~hVD;iMMwA>cNv{>j7l(s~y-%^$l{-Vs5Vth$IT_odM~J@PtUUI-&< zBd}|{TS9kOXJzhbc~#Nh;uk^FjzAo}2=2_>+YCO3B^c<%Pn1=2s8}AUXrlHT=>8&$ z7qle!Uw#*zvswL5H(nm;I~})sUkU+qM4d37e!V-H{DaaY6%^5 z{{19>+ML=}5o`?NV@>w}D3Qa1DY6Vb97EoCuzn0D;9^>NgT}+}uR>>X69C|>;bK22 z%U?u@T9t_i^5h4R{hIta*lIaes_Gsh=Ck=D-oU$IQ~L=XWy>~sJflIb*Fx{>*3ebb z_ooA8s_2(sEsfb58<}eloGR<<(UK02y@i_CHQS4yd>|YA2(HaCR((tBieX~VCGd=I zGF}8SSRK6&{f@--(#j zE(uen&-ZT9+`P&nJ6hNXXcR@mwRa50OuO2ys@@dOSDBMl)T+C>FZ9;DVC)wvK%=S@ ztU>bSEm){X5d}dYw(WZquYU8Aq+Jz5Fqh1u$4d}|RpExmC4jzK@4%B32t`hsjBugV zpdt6Bn5hWKB#sCpQ-fY799EhW6MY>+-0yec36R63bb8Y&Ky+fs8>}0$TE6e~mRc8q zV=KHfUbx7s#&B2!>S5TU>_hwFZS2b<+0e1jGrPEo1TJ zLqwwSXwxIr@526vH-z1gO+#|x2Z7sJ#`lQd_Axd4qL(-bBlhnzpO5AbN4D!*93Ge1 z4Na&}Ok7Sw6Os(``|dSep7X<+0Jq*tl*^qVU8gGh;2TK8JxlCa}VNKemg`k2h zU;k3Hopf3`cXNn>Sbr=i9;v*=Acqs@;#8PqIE{=;$=cx8`!S9ys~dri!fL2|4$YNXbUfn`N@)czg+ z)g5UO#7`;9k08sc=eTJBe2X`H!`WDvABIPQp-43Lb{zA*2GO@`s8_%-Srnf#=>iz{ zbT;F0Kg}1TzWdG#*%!;P*#C5<#E;4fI}JuospI&~DIFkQ&-SI3@hkpY6ovN^Ns zp=g-<9M^t?Mn(EPz;UaD$?d?6{(dXFfKze;_NoP@h$sTknHZZfy*)-Xh1)&1oiDO1 zwWPjueDeqvpLRjZsgT^Z?D+|@?#{PGcWr&1r|*p#q~Fj4PeYEf4K8|5(IgN=GKgMk zRQ=Fn-?aZ5sfej)`5TDQ9;9aM_}1*_+w9z`hkI!(}Ei`pQTw!3ua@mmaYy%5l=<=~pxFxv3CL^?blu=007zyR{^Ul1?6#M5}^8vXGp@5@a zTetc~RdO<^QXNVThiAuhc^GIu2scm1h02*=o|_rGEa9N;CGNe9FFw7o5MT8}+g#@Z zu8bqhbjCSmv3h?Pc-GQF9zo4Z^nn?|7`TN5KfxEc+?1C%H`mr3rVS+(0ii?+%osMM zlM;~kE!ZOe#HJ@zADU`Hv&ts(&QUI}2sG&id;MHlE8@ty_V@vs+>}U@uVNE$#=n*MkG7TBex9O_HGeZnwyX#UNrK?n(zhsiHye=^8;nWHk-}XmGqS^H>luIp zAl7Z*iW%*5;t2FZk95XVID<$_)-O54xtB<*dBv`YI2}TLYFu>v6A=>UUl2EkFDVY^ zM3hnYndtE$J|&V5idO1@`F0Kan>)OV%b)ceAy%HRSvo}n<7-d}N4mRZVce$&pr$qO zRm1PG&+i11(y!)^7`Gt+xT;t_L+XQ7WD5;T{%dnQK2zD=h=ddw0!7fS;EQ#i2~-44 zL_j6y1a_Ow#1hYSJ9bQo>T&!TCM$T#x28p7c=r8rXIJ4L0!?_`WQLS^hP7;(A@kI_ ze@}qu|MkmP@&AdWuWZU@_;`6Y&*}CxxL?3`863EMo>$fm=Nm)pXL@Iu>@^l^7juVR zv5^lb9?*JtBSVi$eLm%F6MMBzm8wL?SqGX7@-OuOMvG~$cKgwIpi7>M9;7hJiLDSjko)z=bN&C@GJxDe0TLgS|ky?t_85@|9@Bjq0F4nS%CjO$x-}U zVF7cj_HR0$LblE|$1l9C=nk~4Bb|huj35LNCdOS;;mMhZH6~+5Ye(Q<5MMm!%|!PY zFqqiqXZ_`;{6w|}_8Q6Mx&$-q<(ayu!mTPH|<78OXcT3vuVtpplN8`y5?s80bVakZumyNn<5%UNCJ3Qpm3N!U!`BnhWN z@AgjBY+)MTH$thsGlRy~U$@6A*YBso$egOUn2IgGM)ys4x&~a`UtpL@xA9>uxtNrq zI-QLzFWV`cK8Kyqmz5{;sV3>Cv?NPkTKCq)U#^~kZbj(Dvp$kWlf93K%sFE>!} z6;Sh>(1(W}Hn|JJDf_hB7iqqrhH<9 z#M%!5F?k!i0z_V3&s1DSu?J9d6O1t0pR*4&4nG-sy3c8L2W7NgnX>VTp3|I?>W(MY zd0e12Prhxvkr$W^jIOqtquqHY7+R(3G<0>{Zm9K6ER4Sv_tMyb$DN6!M?}04R0Ny#H33z>y0D@$$3= z>1?4fJOSuYH81Rd+MXX5%6Q-9{LPMt(7r2Ya&Fo=wTVPd7fO-TCu} zQPDa+ON2sF6(rHwpgP{;S;UI;9$zYScEg4gq$XhqU7^#cZ`G?hWyFao{c;^mqP9JH*@Y$wm1J7g{#tgV zAV2I2L7r(rMjG0+r%iKB6gw-b3NVlOf~@4g&E;;n@ky$bf$o!B57t?Bar54wl4EV+ zdk3ii^$;m>Z68LP+ColZg0W_<1PuF4SDc7yjzvskEh0#;`R?1(w%F~HW~yy>a?MW) zA5-{SGZ3A|QqGD{ZlsfDNHdMdRxulwOIqlAIlM8uHJTqd@~N9O45@rEBUQYl>gH+> zqq$iQEmQD>(Yz#vsO0H|*bl2U%2%DxzfQ*uz@EA)>%b_(P7ED|tXo|$isuW2rO49F z%a*i3xYn~%9SAGpBOP63DEwV!X8{Z?RiZjCrwyy70WkN>*5A}a@dUS(^|A?F6T`V@sWRdgT!a%3`l zHoo`c_k_PHk5GgCv{onV0d#tQ#)`4ViHfW?n~p@`AwvbXp~cnLCIDB9X0^I7O)h<$ z9*eWhr^g_}5a+Y3qfTD*Kr5pNPAm)iZ&kU;#4@Z`)j?a{&h{?t`{{hA$Jrc>M=N#m z;tV*0!jIAVXbZ9(UBLF}xhhdFDn8og`SvE#shit9945(q8fl#k`#l<5Gb1&DD?R-{QqdBcGOG%y=fD`@h+>ya^=G>;S@V+)_PT)N z1+-W_Hxr#FKgOwE%hC{9xM083*hmWhmoT@ZXeoTzaUdx{=T^{23XX@L5NuQ-%E{w9 zFW5K48I7sS)A31_k6Xl>Cd_-~I$Xb~$r^OxM)xsf?#^>%ZPJc?3nZ+b=R+9)RJ;<` z?a{L?j}V&S`zyiO_M`P%bNuuczHgaoojvz-oznNW*r`%NmGs0&+}|rrW#E9vZ_|H! zZ`ymeS*SU|1ZpvbQt?6ma{NB9?}cwKOozwrsKj9l(LIZQ ztmqcy0z7S62jOHXY{MSZkGK1^)jt@A$M{}BX^IwiE8V?|8}Z+tx_Ur$Av(W5G8s>l z=-pY7(~I-<41 zkfkLqe4y&?_rf<>0rO>Vx=(YPz=PZMV$t5ymA8#j<9jihTn|qU91szkSmY^!m?IS= zJ*9<|`){@CobRs2GUrmj>;m@PeaRfDE3ZZfCxkF>WB4fc&EI6%sw@uv#eT!u&IwD& z9iRj25dvv(0O5`}v1Zi&=8beyaA8S{=k#APIo`=1?NgT5m>$PgY`ZTi0bx3vY=b(M z7UD?b2FVn}<%0ZVQ&ODUk_5A* zW={bRTTSk0fZ?P#xk!!eWT=LGE&O?zN6h7_vAjn}7V9Wnu0LF~u;gZzr~&A)qKd(+ zmwWPyi48G6tZ&M7sVpNS?X*gokFr^tow#K$7YoZ5ZNcp2OCz^D6&sdZ2J(X@Iwtyi*pb%W^6|EYkN6nSvdPvd zvby!@aHb}L^LyuaJyNSnwMifq8ya6E%U#q&xvcpshDi3m#t+t#l%b!qzEzZ! zjaGd~PH4RjM)bRWu3bm47uBqd`moGW%jr?xTVZ#PxmC@H2S@-l4q4r$BYNhD_X=1- zC2I}`IqHGsb^+zxiiUT*q8Kqu(ak>zyn|TJp89i_q5gyf1(5en9IdLYv3m`^Jh?wT z$kW%F`thYWZMDZlx_GQKu84(D@f}Q9_A(c=^`rHm6h?LGPo1_P4_I9g12~fKd`#rx zGPc59=}1om@KwL;V2fYyUhXpQWtwY?;8<&Y#JO0NwA8HiK-gsfUACP|&Enf`N3Q%B zGtFj+Bayy|IFcsky<81yD}CuP5w|xXbXzK9DFXn&5B8;B!*lzN`GUN$K(3!7S!uci>0Y7oe$Kzu~Y@|AY`^-uU!K(}(@z zIPD}$lTr?3l5o^oV#;jW1{Nuk`;ER`Q=Fc@bd1&5qIEF2=vNtYZjeM@u9qH{w>^x7 ze627$37b`=zN|A&egt9KQa#;2_9X4y0MG^g7>7}~MzcftQw6=J^c~D2(s>P@J`)L< z+}(;tL0}4a)@R25`lj*cF=zo|-bgS6mB)b$L_LvfB-fLH5?HA4_Dw5B5L$v`x4%rc zAzFhlKcJ*?v2yM2UW)EtrIh3EMX-F6>+u&co?`6ovx4xiA-INtN8YM$?Gn;jVlu?2 z5E>-H>vk>HhO|U{F(~t>st7_3zlVpd+WIE z86g#2g(4R2yjuGMbHYgAaH5K)sK-HO~EG#iL(VmRra!d@p; z&5#yA;sHXwQ>H9@t@;dG|ItgGQS*qh983q7S} zLlBCD6hX`r*4VhQl=cjnr{d^YCotzinivu>WNj4o>VKWu`@=s#f>&@vUpSF2H}ePP*FQ8}66Rz%Y?S8K24w%W zkF-Q&FD{Z=kY5+uk0NI_jJ1^R=_{t8pu!HFa+iG-$H#MTBwk0oH1E~Cqvl3{h|Gz+rQnd1u6IM zln1=pZm+Kc_l>k%Evc!gtRFdEJC!6EzUK2kT_|a5BZG8{A?$B)0Ia4WjVEaNN6(}d z;{X4Hy=jS!jkV)zWc#T2`W=DXyXmN<6KV#A0|(W=$Q((@W-SP7zo4LCNN8x+)`ea1 z0*dd74GjksbkdTXOt_DkdA%}(`NW=&+wQ?>_&&dhgntE+7|hPbT05A6npgTpDB!SN znV(+}0kq~|qOdQ{6+bx=vB;?V`WO=vzs+~}YW%imXomHfz ze`|la{aHTKqJ6z~0`fV-YqiKIHZD%U`4BfVu8@`ATG;_RS1NK-*^!HUd@wvVG2N)k zqHc2eIDc@9sGhrGPR8(?sYYzy$o@nw+q==dtBF7JP0GLfgkvELA^I|0(WIX(ERYKo zvVbdpToos!=;#b;@*(w){f1ZA?G^_lt$yz%B_=2Pu9)QZo%QcHU@%x48Nl$SMNWB( zopSBHO@=Up)V_gflyA%_yoYVnl8}*MPa)(2My*k-_p%p2XhEU?Gvl}v!WdpfQY^MHp+j3uZ$kHX{SyVoyzbuC5B66Bv1v zw#Hsagvw!LVublu?p?afIXE~X#z%hT=KAOI)b%97fAy*j;({Fd(7CR?NFjohS+x7B zQ=%Zln8JbX-}PS3nq}iWu+TU{hMt!$0 zmc%^&YGu8yScoEE9pnu9_rt%d*#BRg)W6?4^eI)!yvpC}Yq=Wo{|Mm#p3J|}`YM80 zO$H4Adlyw^xPM94Uaznnmaq3ebpW-haF1UF?e!8dOo{(r>4b6XGTtlW%0G|ZgzY?? z@JA8EK~_F~U{>z0=eYOdj@BS{GPFupLG~fCH;+JPH7xAc1*2+1^3>`#vZNO5|C>G4 zu=9<&fZ^4^Z#@1jlma*sFDry}%K*s|Cts}L^3pK#It)evhwPyW>H{f zwEk{%=;t<@WJ@{+)=1TRLB;<}J8hWVca9Bfre8Fk`b2$%>?3aY61U46MTws}xOH}p zq&)t!A|x@(86gLy#DeH+qU-=V$dm(pkpAjQ2MudO|GPpUrzR?jqk?EMxQv3-U6+s{ z+YqWp`{hjmq@C)2R~IT}>mDCLJFb?GV0VUFI4TXKW6l3vk9iauJ(dS{3EH(!LR!WF z7!_@1_pq+$wuaB5dmmZ0jz%FKU*xeUaq}`>6C;obn*LFASxWt?k436n^uIT{rqQ}R zb<;LwUm|o{lS%GqA-)2rav29Q~dwEYGah>eO-~`<3ua1q#s+9l(-^m2%9YP!z=fV%+j4a)G4Ax6N6?*X0Zmo|FR`K^Z7xz|0e?hq_Ta zt1(44wOyOy7%Siv!*wD%K5{T}(8O)Mm?>XKZ$V;-R;9!K1!+~O6_ZK_yVQUZD_rs` zzzIiv2xcri5-Q*X7Fc<& zYRH3yl+spfHBnmMY$B@hUh4S0sq-_nHaWJiO%Cd>n#}6Cuqu?7 z1UM5mnb8b6E7$vm=@l^PTGm0+uB$bW>uE}&y$fT&d^7UOKnkrrl+7<2r{euNl(DT% zesO!~tP5-*kpkrv)vf|)i}X*ajqkv_5sr)6H8S*{yN5H(YjNE*qT}fSzqXn4tMp>y9_?iz=Q-r1a>l&fLax%YiFxbQqPLFt~iLLC0Cv#34D8`Px4V=t3jmhsDvAlSEoZ@E{Q#=h%m1CQk6qVR$ z(<+NJE-B(uP~3iZQiwVkkW{o*M^Bq(ncgO!Q$4D^9oAvp82C&=GpiuKDr^$%7&ty- zYq$_(L97s1x!6T?L~k0FHJfUIPL5_kMEB$O)w|Tp5S+@@XIL=?$C`ZvxD}K=UP$4Q zevBrQeg_I$gcxkj;O6d@!EQSM`dBqIOBQ=j>yKx<2ZzO>feSkgD7v=2{>@B z?oV^g`4w#T5_FYyd3Dov+w$YBR{CS&Rub%1l}*MlRJ*-Q#C*SZMAjM4kXj&j7136k z5U`uJx?QBqS!?zLWdxg9aIxdGN@gO|6nDFg2<>f zd^tx7u1ErbH=7XgyZZwS2I!EqF;G@kU&?pz*yZh$%y?5>V%gEq!o>%fJCQ8@aOtZ_ zb}|uR(_j=^3-o)qDWnL}uZ_#xU;d-cwepW-4J-E2AyrudhL^UQx@a*U4w>l2dik}7 z+ZVNBn{kw3O-Sw>t_CA{%oa4|7sA%KAnGld1O8Y6GUTCy{tEa%2^YSsEWNeT21HD! z)Fg|IMt<+esN3nYy6xyp@69CULmcrAda{St!xWjPa*3t^g~GtlFsFhNYV4gkPCYUW zrP4pn01a*-2^jEiR0G5bD-ZWlT#FSje21oUz(kW9bK_jVx;JlmSz&g9U3JO0w=d3; z`hy0X(O%6u7D3sWwSn~oiDa}}>M}p#sYX}z=m#a!5yM*%`0VK71&5Mbl$MdNp{hY1 zq4qtQpki}kF}$^3Lrqq8`CN~o>WyXYj6<_Ec`KtRAIVX^5sF0nb4os>weB(Ge(v4zNATz5MGVJ6HQwIaUYAj05W>3fowQ zGfIlherp-J10WP7R*^jq6t$oF;zgNZlMX8F2U`e%3=*7G+_?R(1(p8l4a*FnsUrp& z_L^}`g!K3OxooN`&{yDgzq(;?8VGxGU}#W(C_qw6jp+L80 zE5qGHcu{-8Aepw{4vC+V{fY2Vw3yz_fbMryXHu@&{1qb_1w2*NUa#+!4TjDcnwkZ# zEX-DOe~i^1J3Bb%o3fD*%YF;Eo+J97$33CZnSgs_rMhR#+dFZ5&$le;>}J;4IeG0_ z&y8mD-v_HWYVNvJ=>l-xBE@i%dnSM|-VA1#)I4Umr>BH7q#j_fl_R8cE6?FHzbxox zQDIl`W4krl;g9z1v|j4Y2yO_i-8a}cbw34^Nx(1iy2C}`4>`Wd; z|41L3Is1Ip8*H`!wp@Mmzy#_PVUx&Ok+}93V99@@!}dAF{BBFSlZ;mIUE-s2$aH@u z4fsbUXIM-!ImW6^G4qK(-myif>FpJqY!uvi+_Bk4VM#-csmf6P9%s8`={lSwJGdOzN zBVD<+_D>ji5zZiqgb&|z9Hz>*Cv*vIR^X_)kdrcKaNo=fxel6~PX4puUNPR&cqnRt zY|59hJ95UBV>)87plvH3Fetb=hr&#lyw^r;T*15XWs*l*ufE=oEN3V0Lw7ALODU); zML5H@)os5e=VFBywceovEBvu_r~lU}hj=07 zywt>{3hu%)-ghjd6BnwaB)o#pn;qk4K3;l{l#zGGr3v~EgYNSRv)fK8FD7u7!&9HU zgpo+~0Jqget7%c9V;_knVaPHFJb)qlEluNxE9{+uJ~!X3o#uIaB1995g0(GHc(Q-` z$d{Ue#;lcb!G2^jj&3gckn;q_&Y%s#^=gpuGZf+0?xj_xm}jHr_9q5g%I?KaB=Vc{j%A8?S%>H#4pvuJ+SV z?LH3FEntIt4{8P3lBDgfri_lJ&9e=ha8^1D_;mjL(~>nUZy0ia zuP#b_hDK>(HG02V@#se!?Hl!TA4puuWeAK%&j5mhevFde{gA4~KGBG(Wmuf*|tP@JrD*TYVj}mPk&FWxhln=zA+KKXxNHxf>QbZ%%{P(^tTOG-d-YODdzud>R&8FhSUb0`PK#2kQ*Mz{uYS&>!A`k zP-D||J=$I$Ena!3PR`sSodmx)T&Qh(IffG26JWj=X+3Tkt1&A6q{V+`Yg;BM}Dm-$-2`esnY(HiLKL-c)F6z{9XYynoo!&%A z@IL%1nRKb*w--D?9Qk1G%ZH@lY^aPqwIsx{@VB$BDFFkEWq z15U9Ib>b^hSJ_{N(Chy!>aRzHnm!rA$%etp>$v6ffh?K%8&a!>3=*w*Lq4-}`077D zr)K~J71%h{G*t!{@s=v>4Csu%#V5eSH_{1r0R&|j7Bq$~GgR(U++&lSKxNt%6vP+E z^Y9Z<_{F?uhK>W>QBE6jvh+TR3-zB zyR}jOFe*UOb3)^MDZVSr?dvuFu$k5MG$>cP)a(a7vfCUTFx5(}@cACoMikRc6F8+_ zSLL_U!PMtM$iG4dT_Z+wDpDVr?k4Q+Afh?Tmfa20bI>h92Rp|OMSpOWnNwsXqB#`4 zumCU5l^_smerGV1%*E$F2eG^ADYSBHQnI{_t5JITk8QosW)qa^bFi5vY26H{!Y`GA zl>0W{OL`IuuI$Z`{oh7#DtTL6xbD>Bd*&z^t#8y-!TPdt0a{64YKtHH(?6#p%!p+8 zQZmOSdm!T|zy>Z(EZxhZ0R_?C1+n&(EDtLG$LE@am3|Nw1Uz|mf}At&lWX3xVR8s- zu}#{yg2smhCil?XJsnt%KJj?Sw_K#!P?s6DcI3x?%hXbO=-`>RmbqXAaK8OdoXmZl zFiBw!VFz{<1?d-;>o!+K=y|~wVUk#K_Gh*+QZd;KzZNSJFWG4}P;>FX`29hM$^LR-^hJ_F}6A=?eq=a2G|<>GpN{|_~{ BGcy1H literal 0 HcmV?d00001 diff --git a/bridges/docs/running-relayer.md b/bridges/docs/running-relayer.md new file mode 100644 index 00000000000..710810a476e --- /dev/null +++ b/bridges/docs/running-relayer.md @@ -0,0 +1,343 @@ +# Running your own bridge relayer + +:warning: :construction: Please read the [Disclaimer](#disclaimer) section first :construction: :warning: + +## Disclaimer + +There are several things you should know before running your own relayer: + +- initial bridge version (we call it bridges v1) supports any number of relayers, but **there's no guaranteed +compensation** for running a relayer and/or submitting valid bridge transactions. Most probably you'll end up +spending more funds than getting from rewards - please accept this fact; + +- even if your relayer has managed to submit a valid bridge transaction that has been included into the bridge +hub block, there's no guarantee that you will be able to claim your compensation for that transaction. That's +because compensations are paid from the account, controlled by relay chain governance and it could have no funds +to compensate your useful actions. We'll be working on a proper process to resupply it on-time, but we can't +provide any guarantee until that process is well established. + +## A Brief Introduction into Relayers and our Compensations Scheme + +Omitting details, relayer is an offchain process that is connected to both bridged chains. It looks at the +outbound bridge messages queue and submits message delivery transactions to the target chain. There's a lot +of details behind that simple phrase - you could find more info in the +[High-Level Bridge Overview](./high-level-overview.md) document. + +Reward that is paid to relayer has two parts. The first part static and is controlled by the governance. +It is rather small initially - e.g. you need to deliver `10_000` Kusama -> Polkadot messages to gain single +KSM token. + +The other reward part is dynamic. So to deliver an XCM message from one BridgeHub to another, we'll need to +submit two transactions on different chains. Every transaction has its cost, which is: + +- dynamic, because e.g. message size can change and/or fee factor of the target chain may change; + +- quite large, because those transactions are quite heavy (mostly in terms of size, not weight). + +We are compensating the cost of **valid**, **minimal** and **useful** bridge-related transactions to +relayer, that has submitted such transaction. Valid here means that the transaction doesn't fail. Minimal +means that all data within transaction call is actually required for the transaction to succeed. Useful +means that all supplied data in transaction is new and yet unknown to the target chain. + +We have implemented a relayer that is able to craft such transactions. The rest of document contains a detailed +information on how to deploy this software on your own node. + +## Relayers Concurrency + +As it has been said above, we are not compensating cost of transactions that are not **useful**. For +example, if message `100` has already been delivered from Kusama Bridge Hub to Polkadot Bridge Hub, then another +transaction that delivers the same message `100` won't be **useful**. Hence, no compensation to relayer that +has submitted that second transaction. + +But what if there are several relayers running? They are noticing the same queued message `100` and +simultaneously submit identical message delivery transactions. You may expect that there'll be one lucky +relayer, whose transaction would win the "race" and which will receive the compensation and reward. And +there'll be several other relayers, losing some funds on their unuseful transactions. + +But actually, we have a solution that invalidates transactions of "unlucky" relayers before they are +included into the block. So at least you may be sure that you won't waste your funds on duplicate transactions. + +
+Some details? + +All **unuseful** transactions are rejected by our +[transaction extension](https://github.com/paritytech/polkadot-sdk/blob/master/bridges/bin/runtime-common/src/refund_relayer_extension.rs), +which also handles transaction fee compensations. You may find more info on unuseful (aka obsolete) transactions +by lurking in the code. + +We also have the WiP prototype of relayers coordination protocol, where relayers will get some guarantee +that their transactions will be prioritized over other relayers transactions at their assigned slots. +That is planned for the future version of bridge and the progress is +[tracked here](https://github.com/paritytech/parity-bridges-common/issues/2486). + +
+ +## Prerequisites + +Let's focus on the bridge between Polkadot and Kusama Bridge Hubs. Let's also assume that we want to start +a relayer that "serves" an initial lane [`0x00000001`](https://github.com/polkadot-fellows/runtimes/blob/9ce1bbbbcd7843b3c76ba4d43c036bc311959e9f/system-parachains/bridge-hubs/bridge-hub-kusama/src/bridge_to_polkadot_config.rs#L54). + +
+Lane? + +Think of lane as a queue of messages that need to be delivered to the other/bridged chain. The lane is +bidirectional, meaning that there are four "endpoints". Two "outbound" endpoints (one at every chain), contain +messages that need to be delivered to the bridged chain. Two "inbound" are accepting messages from the bridged +chain and also remember the relayer, who has delivered message(s) to reward it later. + +
+ +The same steps may be performed for other lanes and bridges as well - you'll just need to change several parameters. + +So to start your relayer instance, you'll need to prepare: + +- an address of ws/wss RPC endpoint of the Kusama relay chain; + +- an address of ws/wss RPC endpoint of the Polkadot relay chain; + +- an address of ws/wss RPC endpoint of the Kusama Bridge Hub chain; + +- an address of ws/wss RPC endpoint of the Polkadot Bridge Hub chain; + +- an account on Kusama Bridge Hub; + +- an account on Polkadot Bridge Hub. + +For RPC endpoints, you could start your own nodes, or use some public community nodes. Nodes are not meant to be +archive or provide access to insecure RPC calls. + +To create an account on Bridge Hubs, you could use XCM teleport functionality. E.g. if you have an account on +the relay chain, you could use the `teleportAssets` call of `xcmPallet` and send asset +`V3 { id: Concrete(0, Here), Fungible: }` to beneficiary `V3(0, X1(AccountId32()))` +on destination `V3(0, X1(Parachain(1002)))`. To estimate amounts you need, please refer to the [Costs](#costs) +section of the document. + +## Registering your Relayer Account (Optional, But Please Read) + +Bridge transactions are quite heavy and expensive. We want to minimize block space that can be occupied by +invalid bridge transactions and prioritize valid transactions over invalid. That is achieved by **optional** +relayer registration. Transactions, signed by relayers with active registration, gain huge priority boost. +In exchange, such relayers may be slashed if they submit **invalid** or **non-minimal** transaction. + +Transactions, signed by relayers **without** active registration, on the other hand, receive no priority +boost. It means that if there is active registered relayer, most likely all transactions from unregistered +will be counted as **unuseful**, not included into the block and unregistered relayer won't get any reward +for his operations. + +Before registering, you should know several things about your funds: + +- to register, you need to hold significant amount of funds on your relayer account. As of now, it is + [100 KSM](https://github.com/polkadot-fellows/runtimes/blob/9ce1bbbbcd7843b3c76ba4d43c036bc311959e9f/system-parachains/bridge-hubs/bridge-hub-kusama/src/bridge_to_polkadot_config.rs#L71C14-L71C43) + for registration on Kusama Bridge Hub and + [500 DOT](https://github.com/polkadot-fellows/runtimes/blob/9ce1bbbbcd7843b3c76ba4d43c036bc311959e9f/system-parachains/bridge-hubs/bridge-hub-polkadot/src/bridge_to_kusama_config.rs#L71C14-L71C43) + for registration on Polkadot Bridge Hub; + +- when you are registered, those funds are reserved on relayer account and you can't transfer them. + +The registration itself, has three states: active, inactive or expired. Initially, it is active, meaning that all +your transactions that are **validated** on top of block, where it is active get priority boost. Registration +becomes expired when the block with the number you have specified during registration is "mined". It is the +`validTill` parameter of the `register` call (see below). After that `validTill` block, you may unregister and get +your reserved funds back. There's also an intermediate point between those blocks - it is the `validTill - LEASE`, +where `LEASE` is the the chain constant, controlled by the governance. Initially it is set to `300` blocks. +All your transactions, **validated** between the `validTill - LEASE` and `validTill` blocks do not get the +priority boost. Also, it is forbidden to specify `validTill` such that the `validTill - currentBlock` is less +than the `LEASE`. + +
+Example? + +| Bridge Hub Block | Registration State | Comment | +| ----------------- | ------------------ | ------------------------------------------------------ | +| 100 | Active | You have submitted a tx with the `register(1000)` call | +| 101 | Active | Your message delivery transactions are boosted | +| 102 | Active | Your message delivery transactions are boosted | +| ... | Active | Your message delivery transactions are boosted | +| 700 | Inactive | Your message delivery transactions are not boosted | +| 701 | Inactive | Your message delivery transactions are not boosted | +| ... | Inactive | Your message delivery transactions are not boosted | +| 1000 | Expired | Your may submit a tx with the `deregister` call | + +
+ +So once you have enough funds on your account and have selected the `validTill` parameter value, you +could use the Polkadot JS apps to submit an extrinsic. If you want priority boost for your transactions +on the Kusama Bridge Hub, open the +[Polkadot JS Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fkusama-bridge-hub-rpc.polkadot.io#/extrinsics) +and submit the `register` extrinsic from the `bridgeRelayers` pallet: + +![Register Extrinsic](./bridge-relayers-register.png) + +To deregister, submit the simple `deregister` extrinsic when registration is expired: + +![Deregister Extrinsic](./bridge-relayers-deregister.png) + +At any time, you can prolong your registration by calling the `register` with the larger `validTill`. + +## Costs + +Your relayer account (on both Bridge Hubs) must hold enough funds to be able to pay costs of bridge +transactions. If your relayer behaves correctly, those costs will be compensated and you will be +able to claim it later. + +**IMPORTANT**: you may add tip to your bridge transactions to boost their priority. But our +compensation mechanism never refunds transaction tip, so all tip tokens will be lost. + +
+Types of bridge transactions + +There are two types of bridge transactions: + +- message delivery transaction brings queued message(s) from one Bridge Hub to another. We record + the fact that this specific (your) relayer has delivered those messages; + +- message confirmation transaction confirms that some message have been delivered and also brings + back information on how many messages (your) relayer has delivered. We use this information later + to register delivery rewards on the source chain. + +Several messages/confirmations may be included in a single bridge transaction. Apart from this +data, bridge transaction may include finality and storage proofs, required to prove authenticity of +this data. + +
+ +To deliver and get reward for a single message, the relayer needs to submit two transactions. One +at the source Bridge Hub and one at the target Bridge Hub. Below are costs for Polkadot <> Kusama +messages (as of today): + +- to deliver a single Polkadot -> Kusama message, you would need to pay around `0.06 KSM` at Kusama + Bridge Hub and around `1.62 DOT` at Polkadot Bridge Hub; + +- to deliver a single Kusama -> Polkadot message, you would need to pay around `1.70 DOT` at Polkadot + Bridge Hub and around `0.05 KSM` at Kusama Bridge Hub. + +Those values are not constants - they depend on call weights (that may change from release to release), +on transaction sizes (that depends on message size and chain state) and congestion factor. In any +case - it is your duty to make sure that the relayer has enough funds to pay transaction fees. + +## Claiming your Compensations and Rewards + +Hopefully you have successfully delivered some messages and now can claim your compensation and reward. +This requires submitting several transactions. But first, let's check that you actually have something to +claim. For that, let's check the state of the pallet that tracks all rewards. + +To check your rewards at the Kusama Bridge Hub, go to the +[Polkadot JS Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fkusama-bridge-hub-rpc.polkadot.io#/chainstate) +targeting Kusama Bridge Hub, select the `bridgeRelayers` pallet, choose `relayerRewards` map and +your relayer account. Then: + +- set the `laneId` to `0x00000001` + +- set the `bridgedChainId` to `bhpd`; + +- check the both variants of the `owner` field: `ThisChain` is used to pay for message delivery transactions + and `BridgedChain` is used to pay for message confirmation transactions. + +If check shows that you have some rewards, you can craft the claim transaction, with similar parameters. +For that, go to `Extrinsics` tab of the +[Polkadot JS Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fkusama-bridge-hub-rpc.polkadot.io#/extrinsics) +and submit the following transaction (make sure to change `owner` before): + +![Claim Rewards Extrinsic](./bridge-relayers-claim-rewards.png) + +To claim rewards on Polkadot Bridge Hub you can follow the same process. The only difference is that you +need to set value of the `bridgedChainId` to `bhks`. + +## Starting your Relayer + +### Starting your Rococo <> Westend Relayer + +You may find the relayer image reference in the +[Releases](https://github.com/paritytech/parity-bridges-common/releases) +of this repository. Make sure to check supported (bundled) versions +of release there. For Rococo <> Westend bridge, normally you may use the +latest published release. The release notes always contain the docker +image reference and source files, required to build relayer manually. + +Once you have the docker image, update variables and run the following script: +```sh +export DOCKER_IMAGE= + +export ROCOCO_HOST= +export ROCOCO_PORT= +# or set it to '--rococo-secure' if wss is used above +export ROCOCO_IS_SECURE= +export BRIDGE_HUB_ROCOCO_HOST= +export BRIDGE_HUB_ROCOCO_PORT= +# or set it to '--bridge-hub-rococo-secure' if wss is used above +export BRIDGE_HUB_ROCOCO_IS_SECURE= +export BRIDGE_HUB_ROCOCO_KEY_FILE= + +export WESTEND_HOST= +export WESTEND_PORT= +# or set it to '--westend-secure' if wss is used above +export WESTEND_IS_SECURE= +export BRIDGE_HUB_WESTEND_HOST= +export BRIDGE_HUB_WESTEND_PORT= +# or set it to '--bridge-hub-westend-secure ' if wss is used above +export BRIDGE_HUB_WESTEND_IS_SECURE= +export BRIDGE_HUB_WESTEND_KEY_FILE= + +# you can get extended relay logs (e.g. for debugging issues) by passing `-e RUST_LOG=bridge=trace` +# argument to the `docker` binary +docker run \ + -v $BRIDGE_HUB_ROCOCO_KEY_FILE:/bhr.key \ + -v $BRIDGE_HUB_WESTEND_KEY_FILE:/bhw.key \ + $DOCKER_IMAGE \ + relay-headers-and-messages bridge-hub-rococo-bridge-hub-westend \ + --rococo-host $ROCOCO_HOST \ + --rococo-port $ROCOCO_PORT \ + $ROCOCO_IS_SECURE \ + --rococo-version-mode Auto \ + --bridge-hub-rococo-host $BRIDGE_HUB_ROCOCO_HOST \ + --bridge-hub-rococo-port $BRIDGE_HUB_ROCOCO_PORT \ + $BRIDGE_HUB_ROCOCO_IS_SECURE \ + --bridge-hub-rococo-version-mode Auto \ + --bridge-hub-rococo-signer-file /bhr.key \ + --bridge-hub-rococo-transactions-mortality 16 \ + --westend-host $WESTEND_HOST \ + --westend-port $WESTEND_PORT \ + $WESTEND_IS_SECURE \ + --westend-version-mode Auto \ + --bridge-hub-westend-host $BRIDGE_HUB_WESTEND_HOST \ + --bridge-hub-westend-port $BRIDGE_HUB_WESTEND_PORT \ + $BRIDGE_HUB_WESTEND_IS_SECURE \ + --bridge-hub-westend-version-mode Auto \ + --bridge-hub-westend-signer-file /bhw.key \ + --bridge-hub-westend-transactions-mortality 16 \ + --lane 00000002 +``` + +### Starting your Polkadot <> Kusama Relayer + +*Work in progress, coming soon* + +### Watching your relayer state + +Our relayer provides some Prometheus metrics that you may convert into some fancy Grafana dashboards +and alerts. By default, metrics are exposed at port `9616`. To expose endpoint to the localhost, change +the docker command by adding following two lines: + +```sh +docker run \ + .. + -p 127.0.0.1:9616:9616 \ # tell Docker to bind container port 9616 to host port 9616 + # and listen for connections on the host' localhost interface + .. + $DOCKER_IMAGE \ + relay-headers-and-messages bridge-hub-rococo-bridge-hub-westend \ + --prometheus-host 0.0.0.0 \ # tell `substrate-relay` binary to accept Prometheus endpoint + # connections from everywhere + .. +``` + +You can find more info on configuring Prometheus and Grafana in the +[Monitor your node](https://wiki.polkadot.network/docs/maintain-guides-how-to-monitor-your-node) +guide from Polkadot wiki. + +We have our own set of Grafana dashboards and alerts. You may use them for inspiration. +Please find them in this folder: + +- for Rococo <> Westend bridge: [rococo-westend](https://github.com/paritytech/parity-bridges-common/tree/master/deployments/bridges/rococo-westend). + +- for Polkadot <> Kusama bridge: *work in progress, coming soon* diff --git a/bridges/modules/grandpa/Cargo.toml b/bridges/modules/grandpa/Cargo.toml index dccd7b3bdca..25c6c4e03d5 100644 --- a/bridges/modules/grandpa/Cargo.toml +++ b/bridges/modules/grandpa/Cargo.toml @@ -15,7 +15,7 @@ workspace = true codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } finality-grandpa = { version = "0.16.2", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } # Bridge Dependencies diff --git a/bridges/modules/messages/Cargo.toml b/bridges/modules/messages/Cargo.toml index 173d6f1c164..7d0e1b94959 100644 --- a/bridges/modules/messages/Cargo.toml +++ b/bridges/modules/messages/Cargo.toml @@ -13,7 +13,7 @@ workspace = true codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } log = { workspace = true } num-traits = { version = "0.2", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } # Bridge dependencies diff --git a/bridges/modules/parachains/Cargo.toml b/bridges/modules/parachains/Cargo.toml index e454a6f2888..a9dd9beeb1f 100644 --- a/bridges/modules/parachains/Cargo.toml +++ b/bridges/modules/parachains/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } # Bridge Dependencies diff --git a/bridges/modules/relayers/Cargo.toml b/bridges/modules/relayers/Cargo.toml index b78da5cbeec..f3de72da771 100644 --- a/bridges/modules/relayers/Cargo.toml +++ b/bridges/modules/relayers/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } # Bridge dependencies diff --git a/bridges/modules/xcm-bridge-hub-router/Cargo.toml b/bridges/modules/xcm-bridge-hub-router/Cargo.toml index 20f8ff4407b..98477f2df18 100644 --- a/bridges/modules/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub-router/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["bit-vec", "derive", "serde"] } +scale-info = { version = "2.11.0", default-features = false, features = ["bit-vec", "derive", "serde"] } # Bridge dependencies diff --git a/bridges/modules/xcm-bridge-hub/Cargo.toml b/bridges/modules/xcm-bridge-hub/Cargo.toml index e10119e8649..d910319d9bf 100644 --- a/bridges/modules/xcm-bridge-hub/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } # Bridge Dependencies bp-messages = { path = "../../primitives/messages", default-features = false } diff --git a/bridges/primitives/header-chain/Cargo.toml b/bridges/primitives/header-chain/Cargo.toml index 205b593365e..d96a02efba8 100644 --- a/bridges/primitives/header-chain/Cargo.toml +++ b/bridges/primitives/header-chain/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } finality-grandpa = { version = "0.16.2", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], workspace = true } # Bridge dependencies diff --git a/bridges/primitives/messages/Cargo.toml b/bridges/primitives/messages/Cargo.toml index 8aa6b4b05e5..9d742e3eded 100644 --- a/bridges/primitives/messages/Cargo.toml +++ b/bridges/primitives/messages/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["bit-vec", "derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["bit-vec", "derive"] } +scale-info = { version = "2.11.0", default-features = false, features = ["bit-vec", "derive"] } serde = { features = ["alloc", "derive"], workspace = true } # Bridge dependencies diff --git a/bridges/primitives/parachains/Cargo.toml b/bridges/primitives/parachains/Cargo.toml index 575f26193eb..3846c563575 100644 --- a/bridges/primitives/parachains/Cargo.toml +++ b/bridges/primitives/parachains/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2" -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } # Bridge dependencies diff --git a/bridges/primitives/polkadot-core/Cargo.toml b/bridges/primitives/polkadot-core/Cargo.toml index c0dae684b5f..5ab502569e4 100644 --- a/bridges/primitives/polkadot-core/Cargo.toml +++ b/bridges/primitives/polkadot-core/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } parity-util-mem = { version = "0.12.0", optional = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } # Bridge Dependencies diff --git a/bridges/primitives/relayers/Cargo.toml b/bridges/primitives/relayers/Cargo.toml index 3bd6809d278..71d0fbf2ec3 100644 --- a/bridges/primitives/relayers/Cargo.toml +++ b/bridges/primitives/relayers/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["bit-vec", "derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["bit-vec", "derive"] } +scale-info = { version = "2.11.0", default-features = false, features = ["bit-vec", "derive"] } # Bridge Dependencies diff --git a/bridges/primitives/runtime/Cargo.toml b/bridges/primitives/runtime/Cargo.toml index 22206fb2c37..2d454d264a1 100644 --- a/bridges/primitives/runtime/Cargo.toml +++ b/bridges/primitives/runtime/Cargo.toml @@ -15,7 +15,7 @@ hash-db = { version = "0.16.0", default-features = false } impl-trait-for-tuples = "0.2.2" log = { workspace = true } num-traits = { version = "0.2", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], workspace = true } # Substrate Dependencies diff --git a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml index 9297a8603c0..734930f18c4 100644 --- a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["bit-vec", "derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["bit-vec", "derive"] } +scale-info = { version = "2.11.0", default-features = false, features = ["bit-vec", "derive"] } # Substrate Dependencies sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } diff --git a/bridges/scripts/verify-pallets-build.sh b/bridges/scripts/verify-pallets-build.sh index b96bbf1833b..4eefaa8efa0 100755 --- a/bridges/scripts/verify-pallets-build.sh +++ b/bridges/scripts/verify-pallets-build.sh @@ -68,6 +68,7 @@ rm -rf $BRIDGES_FOLDER/modules/beefy rm -rf $BRIDGES_FOLDER/modules/shift-session-manager rm -rf $BRIDGES_FOLDER/primitives/beefy rm -rf $BRIDGES_FOLDER/relays +rm -rf $BRIDGES_FOLDER/relay-clients rm -rf $BRIDGES_FOLDER/scripts/add_license.sh rm -rf $BRIDGES_FOLDER/scripts/build-containers.sh rm -rf $BRIDGES_FOLDER/scripts/ci-cache.sh @@ -77,6 +78,7 @@ rm -rf $BRIDGES_FOLDER/scripts/regenerate_runtimes.sh rm -rf $BRIDGES_FOLDER/scripts/update-weights.sh rm -rf $BRIDGES_FOLDER/scripts/update-weights-setup.sh rm -rf $BRIDGES_FOLDER/scripts/update_substrate.sh +rm -rf $BRIDGES_FOLDER/substrate-relay rm -rf $BRIDGES_FOLDER/tools rm -f $BRIDGES_FOLDER/.dockerignore rm -f $BRIDGES_FOLDER/local.Dockerfile.dockerignore @@ -89,6 +91,7 @@ rm -f $BRIDGES_FOLDER/local.Dockerfile rm -f $BRIDGES_FOLDER/CODEOWNERS rm -f $BRIDGES_FOLDER/Dockerfile rm -f $BRIDGES_FOLDER/rustfmt.toml +rm -f $BRIDGES_FOLDER/RELEASE.md # let's fix Cargo.toml a bit (it'll be helpful if we are in the bridges repo) if [[ ! -f "Cargo.toml" ]]; then -- GitLab From 002d9260f9a0f844f87eefd0abce8bd95aae351b Mon Sep 17 00:00:00 2001 From: Dcompoze Date: Tue, 26 Mar 2024 13:57:57 +0000 Subject: [PATCH 096/187] Fix spelling mistakes across the whole repository (#3808) **Update:** Pushed additional changes based on the review comments. **This pull request fixes various spelling mistakes in this repository.** Most of the changes are contained in the first **3** commits: - `Fix spelling mistakes in comments and docs` - `Fix spelling mistakes in test names` - `Fix spelling mistakes in error messages, panic messages, logs and tracing` Other source code spelling mistakes are separated into individual commits for easier reviewing: - `Fix the spelling of 'authority'` - `Fix the spelling of 'REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY'` - `Fix the spelling of 'prev_enqueud_messages'` - `Fix the spelling of 'endpoint'` - `Fix the spelling of 'children'` - `Fix the spelling of 'PenpalSiblingSovereignAccount'` - `Fix the spelling of 'PenpalSudoAccount'` - `Fix the spelling of 'insufficient'` - `Fix the spelling of 'PalletXcmExtrinsicsBenchmark'` - `Fix the spelling of 'subtracted'` - `Fix the spelling of 'CandidatePendingAvailability'` - `Fix the spelling of 'exclusive'` - `Fix the spelling of 'until'` - `Fix the spelling of 'discriminator'` - `Fix the spelling of 'nonexistent'` - `Fix the spelling of 'subsystem'` - `Fix the spelling of 'indices'` - `Fix the spelling of 'committed'` - `Fix the spelling of 'topology'` - `Fix the spelling of 'response'` - `Fix the spelling of 'beneficiary'` - `Fix the spelling of 'formatted'` - `Fix the spelling of 'UNKNOWN_PROOF_REQUEST'` - `Fix the spelling of 'succeeded'` - `Fix the spelling of 'reopened'` - `Fix the spelling of 'proposer'` - `Fix the spelling of 'InstantiationNonce'` - `Fix the spelling of 'depositor'` - `Fix the spelling of 'expiration'` - `Fix the spelling of 'phantom'` - `Fix the spelling of 'AggregatedKeyValue'` - `Fix the spelling of 'randomness'` - `Fix the spelling of 'defendant'` - `Fix the spelling of 'AquaticMammal'` - `Fix the spelling of 'transactions'` - `Fix the spelling of 'PassingTracingSubscriber'` - `Fix the spelling of 'TxSignaturePayload'` - `Fix the spelling of 'versioning'` - `Fix the spelling of 'descendant'` - `Fix the spelling of 'overridden'` - `Fix the spelling of 'network'` Let me know if this structure is adequate. **Note:** The usage of the words `Merkle`, `Merkelize`, `Merklization`, `Merkelization`, `Merkleization`, is somewhat inconsistent but I left it as it is. ~~**Note:** In some places the term `Receival` is used to refer to message reception, IMO `Reception` is the correct word here, but I left it as it is.~~ ~~**Note:** In some places the term `Overlayed` is used instead of the more acceptable version `Overlaid` but I also left it as it is.~~ ~~**Note:** In some places the term `Applyable` is used instead of the correct version `Applicable` but I also left it as it is.~~ **Note:** Some usage of British vs American english e.g. `judgement` vs `judgment`, `initialise` vs `initialize`, `optimise` vs `optimize` etc. are both present in different places, but I suppose that's understandable given the number of contributors. ~~**Note:** There is a spelling mistake in `.github/CODEOWNERS` but it triggers errors in CI when I make changes to it, so I left it as it is.~~ --- .github/CODEOWNERS | 2 +- .github/scripts/common/lib.sh | 2 +- .gitlab/pipeline/build.yml | 2 +- .gitlab/rust-features.sh | 2 +- .../bin/runtime-common/src/messages_api.rs | 2 +- .../src/messages_xcm_extension.rs | 2 +- bridges/bin/runtime-common/src/mock.rs | 2 +- .../runtime-common/src/priority_calculator.rs | 2 +- .../src/refund_relayer_extension.rs | 4 +- bridges/chains/chain-kusama/src/lib.rs | 4 +- .../chains/chain-polkadot-bulletin/src/lib.rs | 8 +- bridges/chains/chain-polkadot/src/lib.rs | 4 +- bridges/chains/chain-rococo/src/lib.rs | 4 +- bridges/chains/chain-westend/src/lib.rs | 4 +- bridges/modules/grandpa/README.md | 2 +- bridges/modules/grandpa/src/call_ext.rs | 8 +- bridges/modules/grandpa/src/lib.rs | 4 +- bridges/modules/grandpa/src/mock.rs | 2 +- bridges/modules/messages/src/inbound_lane.rs | 40 +++++----- bridges/modules/messages/src/lib.rs | 30 ++++---- bridges/modules/messages/src/outbound_lane.rs | 30 ++++---- bridges/modules/parachains/src/mock.rs | 4 +- .../modules/xcm-bridge-hub-router/src/lib.rs | 2 +- bridges/modules/xcm-bridge-hub/Cargo.toml | 2 +- .../header-chain/src/justification/mod.rs | 2 +- .../src/justification/verification/mod.rs | 2 +- bridges/primitives/header-chain/src/lib.rs | 8 +- bridges/primitives/messages/src/lib.rs | 8 +- bridges/primitives/polkadot-core/src/lib.rs | 2 +- bridges/primitives/runtime/src/chain.rs | 6 +- bridges/primitives/runtime/src/lib.rs | 4 +- bridges/primitives/test-utils/src/lib.rs | 2 +- bridges/scripts/verify-pallets-build.sh | 2 +- .../pallets/ethereum-client/src/lib.rs | 2 +- .../pallets/ethereum-client/src/tests.rs | 2 +- .../register_token_with_insufficient_fee.rs | 2 +- .../environments/rococo-westend/rococo.zndsl | 4 +- .../environments/rococo-westend/westend.zndsl | 4 +- .../utils/generate_hex_encoded_call/index.js | 18 ++--- bridges/testing/run-tests.sh | 2 +- .../run.sh | 2 +- .../consensus/common/src/level_monitor.rs | 2 +- cumulus/client/consensus/common/src/tests.rs | 2 +- cumulus/client/pov-recovery/src/lib.rs | 10 +-- .../src/reconnecting_ws_client.rs | 3 +- cumulus/pallets/parachain-system/src/lib.rs | 2 +- .../src/relay_state_snapshot.rs | 2 +- cumulus/pallets/xcmp-queue/src/lib.rs | 2 +- .../assets/asset-hub-rococo/src/genesis.rs | 4 +- .../assets/asset-hub-westend/src/genesis.rs | 4 +- .../parachains/testing/penpal/src/genesis.rs | 6 +- .../parachains/testing/penpal/src/lib.rs | 2 +- .../emulated/common/src/impls.rs | 6 +- .../emulated/common/src/lib.rs | 2 +- .../src/tests/reserve_transfer.rs | 2 +- .../src/tests/reserve_transfer.rs | 6 +- .../bridge-hub-rococo/src/tests/snowbridge.rs | 4 +- .../assets/asset-hub-rococo/src/xcm_config.rs | 2 +- .../asset-hub-westend/src/xcm_config.rs | 2 +- .../assets/asset-hub-westend/tests/tests.rs | 4 +- .../assets/test-utils/src/test_cases.rs | 2 +- .../test-utils/src/test_cases_over_bridge.rs | 2 +- .../runtimes/people/people-rococo/src/lib.rs | 6 +- .../runtimes/people/people-westend/src/lib.rs | 8 +- .../runtimes/testing/penpal/src/xcm_config.rs | 2 +- cumulus/polkadot-parachain/src/command.rs | 2 +- .../storage-weight-reclaim/src/lib.rs | 8 +- cumulus/primitives/timestamp/src/lib.rs | 2 +- cumulus/primitives/utility/src/lib.rs | 25 +++--- cumulus/scripts/scale_encode_genesis/index.js | 8 +- cumulus/scripts/temp_parachain_types.json | 2 +- cumulus/test/runtime/src/lib.rs | 2 +- .../test/service/benches/validate_block.rs | 2 +- cumulus/test/service/src/lib.rs | 4 +- docker/dockerfiles/binary_injected.Dockerfile | 2 +- docker/scripts/build-injected.sh | 2 +- docs/sdk/Cargo.toml | 2 +- .../frame_runtime_upgrades_and_migrations.rs | 8 +- polkadot/cli/src/cli.rs | 2 +- polkadot/grafana/README.md | 2 +- .../src/approval_db/v1/tests.rs | 2 +- .../src/approval_db/v2/migration_helpers.rs | 2 +- .../src/approval_db/v2/tests.rs | 2 +- .../src/approval_db/v3/migration_helpers.rs | 4 +- .../src/approval_db/v3/tests.rs | 2 +- .../node/core/approval-voting/src/criteria.rs | 2 +- .../node/core/approval-voting/src/import.rs | 2 +- polkadot/node/core/approval-voting/src/lib.rs | 2 +- .../node/core/approval-voting/src/tests.rs | 24 +++--- .../node/core/approval-voting/src/time.rs | 4 +- polkadot/node/core/av-store/src/lib.rs | 2 +- polkadot/node/core/backing/src/lib.rs | 2 +- .../node/core/candidate-validation/src/lib.rs | 2 +- polkadot/node/core/chain-selection/src/lib.rs | 4 +- .../node/core/chain-selection/src/tests.rs | 4 +- .../core/dispute-coordinator/src/db/v1.rs | 2 +- .../node/core/dispute-coordinator/src/lib.rs | 2 +- .../src/scraping/candidates.rs | 2 +- .../dispute-coordinator/src/scraping/mod.rs | 2 +- .../dispute-coordinator/src/scraping/tests.rs | 4 +- .../core/dispute-coordinator/src/tests.rs | 6 +- .../src/disputes/prioritized_selection/mod.rs | 2 +- polkadot/node/core/pvf-checker/src/tests.rs | 6 +- polkadot/node/core/pvf/common/src/pvf.rs | 4 +- polkadot/node/core/pvf/src/host.rs | 2 +- polkadot/node/core/pvf/src/priority.rs | 2 +- .../node/core/pvf/src/worker_interface.rs | 6 +- polkadot/node/core/pvf/tests/it/main.rs | 4 +- polkadot/node/core/runtime-api/src/tests.rs | 8 +- polkadot/node/jaeger/src/spans.rs | 2 +- polkadot/node/malus/README.md | 2 +- .../network/approval-distribution/src/lib.rs | 16 ++-- .../approval-distribution/src/metrics.rs | 2 +- .../approval-distribution/src/tests.rs | 32 ++++---- .../src/requester/fetch_task/mod.rs | 4 +- .../network/availability-recovery/src/lib.rs | 2 +- .../availability-recovery/src/metrics.rs | 4 +- .../bitfield-distribution/src/metrics.rs | 4 +- .../bitfield-distribution/src/tests.rs | 2 +- .../dispute-distribution/src/sender/mod.rs | 10 +-- .../dispute-distribution/src/tests/mock.rs | 2 +- .../node/network/gossip-support/src/tests.rs | 4 +- .../network/protocol/src/grid_topology.rs | 6 +- polkadot/node/network/protocol/src/lib.rs | 2 +- .../node/network/protocol/src/peer_set.rs | 2 +- .../src/request_response/incoming/mod.rs | 2 +- .../protocol/src/request_response/mod.rs | 2 +- .../protocol/src/request_response/v1.rs | 2 +- .../src/legacy_v1/responder.rs | 2 +- .../src/legacy_v1/tests.rs | 2 +- .../statement-distribution/src/v2/cluster.rs | 4 +- .../statement-distribution/src/v2/mod.rs | 6 +- .../statement-distribution/src/v2/requests.rs | 2 +- polkadot/node/overseer/src/lib.rs | 2 +- polkadot/node/primitives/src/approval.rs | 2 +- polkadot/node/primitives/src/disputes/mod.rs | 4 +- polkadot/node/primitives/src/lib.rs | 2 +- polkadot/node/service/src/overseer.rs | 2 +- .../node/service/src/parachains_db/upgrade.rs | 4 +- .../node/service/src/relay_chain_selection.rs | 4 +- .../grafana/availability-read.json | 6 +- .../src/lib/approval/message_generator.rs | 10 +-- .../subsystem-bench/src/lib/approval/mod.rs | 16 ++-- .../src/lib/approval/test_message.rs | 14 ++-- .../src/lib/availability/mod.rs | 6 +- .../subsystem-bench/src/lib/configuration.rs | 6 +- .../subsystem-bench/src/lib/mock/av_store.rs | 2 +- .../subsystem-bench/src/lib/mock/chain_api.rs | 2 +- .../src/lib/mock/network_bridge.rs | 12 +-- .../node/subsystem-bench/src/lib/network.rs | 10 +-- .../node/subsystem-bench/src/lib/utils.rs | 76 +++++++++++++++++++ polkadot/node/subsystem-types/src/messages.rs | 2 +- .../src/inclusion_emulator/mod.rs | 2 +- polkadot/node/subsystem-util/src/lib.rs | 2 +- polkadot/primitives/src/v6/mod.rs | 4 +- polkadot/primitives/src/vstaging/mod.rs | 4 +- polkadot/primitives/test-helpers/src/lib.rs | 2 +- .../implementers-guide/src/disputes-flow.md | 2 +- .../node/approval/approval-distribution.md | 4 +- .../availability/availability-recovery.md | 2 +- .../src/node/disputes/dispute-coordinator.md | 8 +- .../implementers-guide/src/node/overseer.md | 4 +- .../src/node/utility/pvf-prechecker.md | 2 +- .../implementers-guide/src/runtime/README.md | 2 +- .../implementers-guide/src/runtime/hrmp.md | 4 +- .../src/runtime/parainherent.md | 2 +- .../implementers-guide/src/types/approval.md | 4 +- .../implementers-guide/src/types/disputes.md | 2 +- .../src/types/overseer-protocol.md | 2 +- polkadot/roadmap/phase-1.toml | 2 +- polkadot/runtime/common/src/xcm_sender.rs | 2 +- .../parachains/src/assigner_coretime/tests.rs | 2 +- .../parachains/src/assigner_on_demand/mod.rs | 4 +- .../parachains/src/coretime/migration.rs | 2 +- polkadot/runtime/parachains/src/disputes.rs | 2 +- .../parachains/src/disputes/slashing.rs | 2 +- polkadot/runtime/parachains/src/hrmp.rs | 6 +- polkadot/runtime/parachains/src/hrmp/tests.rs | 2 +- polkadot/runtime/parachains/src/paras/mod.rs | 2 +- .../runtime/parachains/src/paras/tests.rs | 4 +- .../parachains/src/paras_inherent/mod.rs | 4 +- .../parachains/src/scheduler/migration.rs | 2 +- .../runtime/parachains/src/scheduler/tests.rs | 2 +- .../runtime/parachains/src/session_info.rs | 2 +- polkadot/runtime/parachains/src/ump_tests.rs | 4 +- polkadot/runtime/rococo/README.md | 2 +- .../runtime/westend/src/weights/xcm/mod.rs | 2 +- polkadot/tests/common.rs | 4 +- .../tests/running_the_node_and_interrupt.rs | 2 +- .../pallet-xcm/src/tests/assets_transfer.rs | 4 +- polkadot/xcm/src/v2/multilocation.rs | 2 +- polkadot/xcm/src/v3/multilocation.rs | 2 +- polkadot/xcm/src/v4/location.rs | 2 +- polkadot/xcm/xcm-builder/src/barriers.rs | 2 +- polkadot/xcm/xcm-builder/src/tests/origins.rs | 4 +- polkadot/xcm/xcm-builder/tests/scenarios.rs | 2 +- .../xcm-executor/integration-tests/src/lib.rs | 2 +- .../xcm-executor/src/traits/should_execute.rs | 2 +- polkadot/xcm/xcm-simulator/example/src/lib.rs | 4 +- prdoc/pr_3808.prdoc | 20 +++++ scripts/bridges_update_subtree.sh | 2 +- scripts/snowbridge_update_subtree.sh | 2 +- .../bin/node/cli/benches/block_production.rs | 4 +- substrate/bin/node/cli/src/cli.rs | 2 +- substrate/bin/node/cli/src/service.rs | 2 +- substrate/bin/node/cli/tests/fees.rs | 2 +- substrate/bin/node/testing/src/bench.rs | 6 +- .../bin/utils/chain-spec-builder/src/lib.rs | 2 +- substrate/bin/utils/subkey/README.md | 4 +- substrate/bin/utils/subkey/src/lib.rs | 10 +-- .../basic-authorship/src/basic_authorship.rs | 2 +- substrate/client/chain-spec/src/chain_spec.rs | 10 +-- substrate/client/chain-spec/src/extension.rs | 2 +- .../chain-spec/src/genesis_config_builder.rs | 2 +- substrate/client/chain-spec/src/lib.rs | 2 +- substrate/client/cli/src/commands/vanity.rs | 4 +- .../client/cli/src/params/network_params.rs | 2 +- substrate/client/consensus/aura/src/lib.rs | 2 +- .../client/consensus/babe/src/authorship.rs | 2 +- substrate/client/consensus/babe/src/lib.rs | 2 +- .../client/consensus/babe/src/migration.rs | 2 +- substrate/client/consensus/beefy/README.md | 2 +- .../consensus/beefy/src/communication/mod.rs | 2 +- .../incoming_requests_handler.rs | 2 +- .../client/consensus/beefy/src/keystore.rs | 8 +- .../client/consensus/beefy/src/worker.rs | 6 +- substrate/client/consensus/common/Cargo.toml | 2 +- .../consensus/common/src/import_queue.rs | 2 +- .../common/src/import_queue/basic_queue.rs | 4 +- substrate/client/consensus/epochs/src/lib.rs | 4 +- .../grandpa/src/communication/mod.rs | 6 +- .../grandpa/src/communication/periodic.rs | 2 +- .../client/consensus/grandpa/src/tests.rs | 4 +- .../consensus/grandpa/src/until_imported.rs | 2 +- .../consensus/grandpa/src/voting_rule.rs | 2 +- .../consensus/grandpa/src/warp_proof.rs | 2 +- .../manual-seal/src/consensus/babe.rs | 2 +- substrate/client/consensus/slots/src/lib.rs | 6 +- substrate/client/db/src/upgrade.rs | 2 +- substrate/client/db/src/utils.rs | 2 +- substrate/client/executor/common/src/error.rs | 2 +- .../client/executor/wasmtime/src/runtime.rs | 2 +- .../client/executor/wasmtime/src/tests.rs | 4 +- substrate/client/network/bitswap/src/lib.rs | 2 +- .../src/protocol/notifications/behaviour.rs | 2 +- .../src/protocol/notifications/handler.rs | 2 +- .../src/protocol/notifications/service/mod.rs | 6 +- .../protocol/notifications/service/tests.rs | 2 +- .../notifications/upgrade/notifications.rs | 4 +- .../client/network/src/protocol_controller.rs | 4 +- substrate/client/network/sync/src/engine.rs | 6 +- substrate/client/network/sync/src/strategy.rs | 12 +-- .../network/sync/src/strategy/chain_sync.rs | 4 +- .../sync/src/strategy/chain_sync/test.rs | 8 +- .../client/network/sync/src/strategy/state.rs | 16 ++-- .../client/network/sync/src/strategy/warp.rs | 2 +- .../network/sync/src/warp_request_handler.rs | 2 +- substrate/client/network/test/src/sync.rs | 2 +- substrate/client/offchain/src/api/http.rs | 2 +- .../rpc-servers/src/middleware/metrics.rs | 2 +- .../client/rpc-spec-v2/src/archive/tests.rs | 4 +- .../rpc-spec-v2/src/chain_head/event.rs | 4 +- .../rpc-spec-v2/src/chain_head/tests.rs | 6 +- .../tests/transaction_broadcast_tests.rs | 6 +- .../src/transaction/transaction_broadcast.rs | 4 +- substrate/client/rpc/src/statement/mod.rs | 2 +- .../service/src/chain_ops/import_blocks.rs | 2 +- substrate/client/service/src/config.rs | 2 +- substrate/client/state-db/src/lib.rs | 4 +- substrate/client/state-db/src/noncanonical.rs | 10 +-- substrate/client/telemetry/src/lib.rs | 2 +- substrate/client/transaction-pool/README.md | 2 +- .../client/transaction-pool/tests/pool.rs | 2 +- substrate/client/utils/src/notification.rs | 2 +- substrate/frame/alliance/README.md | 2 +- substrate/frame/alliance/src/lib.rs | 6 +- substrate/frame/alliance/src/tests.rs | 2 +- substrate/frame/asset-conversion/src/lib.rs | 2 +- substrate/frame/asset-rate/src/lib.rs | 2 +- substrate/frame/assets/src/lib.rs | 2 +- substrate/frame/assets/src/tests.rs | 2 +- substrate/frame/babe/src/benchmarking.rs | 2 +- substrate/frame/bags-list/src/list/tests.rs | 2 +- substrate/frame/balances/src/lib.rs | 6 +- .../balances/src/tests/currency_tests.rs | 4 +- .../balances/src/tests/reentrancy_tests.rs | 4 +- substrate/frame/benchmarking/src/analysis.rs | 2 +- substrate/frame/benchmarking/src/lib.rs | 2 +- substrate/frame/benchmarking/src/v1.rs | 6 +- substrate/frame/broker/src/lib.rs | 2 +- substrate/frame/broker/src/types.rs | 4 +- substrate/frame/collective/README.md | 2 +- substrate/frame/collective/src/lib.rs | 2 +- substrate/frame/collective/src/tests.rs | 2 +- substrate/frame/contracts/README.md | 2 +- .../fixtures/contracts/multi_store.rs | 2 +- .../frame/contracts/src/benchmarking/code.rs | 2 +- .../frame/contracts/src/benchmarking/mod.rs | 8 +- substrate/frame/contracts/src/exec.rs | 4 +- substrate/frame/contracts/src/gas.rs | 2 +- substrate/frame/contracts/src/lib.rs | 2 +- .../frame/contracts/src/migration/v09.rs | 2 +- substrate/frame/contracts/src/schedule.rs | 2 +- substrate/frame/contracts/src/tests.rs | 18 ++--- substrate/frame/contracts/src/wasm/mod.rs | 2 +- substrate/frame/contracts/src/wasm/runtime.rs | 6 +- .../frame/conviction-voting/src/tests.rs | 2 +- .../core-fellowship/src/tests/integration.rs | 2 +- substrate/frame/democracy/src/lib.rs | 2 +- .../unlock_and_unreserve_all_funds.rs | 42 +++++----- substrate/frame/democracy/src/tests.rs | 2 +- .../frame/democracy/src/tests/cancellation.rs | 2 +- .../src/helpers.rs | 4 +- .../election-provider-multi-phase/src/lib.rs | 4 +- .../src/unsigned.rs | 4 +- .../test-staking-e2e/src/lib.rs | 10 +-- .../test-staking-e2e/src/mock.rs | 4 +- .../election-provider-support/src/bounds.rs | 4 +- .../frame/examples/offchain-worker/src/lib.rs | 2 +- .../single-block-migrations/src/lib.rs | 4 +- substrate/frame/examples/split/Cargo.toml | 2 +- substrate/frame/examples/tasks/Cargo.toml | 2 +- substrate/frame/fast-unstake/src/tests.rs | 2 +- substrate/frame/grandpa/src/benchmarking.rs | 2 +- substrate/frame/grandpa/src/tests.rs | 2 +- substrate/frame/identity/src/benchmarking.rs | 4 +- substrate/frame/identity/src/lib.rs | 2 +- substrate/frame/im-online/src/tests.rs | 2 +- .../frame/merkle-mountain-range/src/lib.rs | 2 +- substrate/frame/message-queue/src/lib.rs | 2 +- substrate/frame/message-queue/src/tests.rs | 2 +- .../frame/migrations/src/mock_helpers.rs | 2 +- substrate/frame/nis/README.md | 2 +- substrate/frame/nis/src/lib.rs | 4 +- substrate/frame/nis/src/tests.rs | 2 +- substrate/frame/node-authorization/src/lib.rs | 10 +-- substrate/frame/nomination-pools/src/lib.rs | 8 +- .../frame/nomination-pools/src/migration.rs | 2 +- substrate/frame/offences/src/tests.rs | 2 +- substrate/frame/paged-list/src/paged_list.rs | 2 +- substrate/frame/parameters/src/lib.rs | 34 ++++----- substrate/frame/parameters/src/tests/unit.rs | 2 +- substrate/frame/proxy/src/lib.rs | 2 +- substrate/frame/root-testing/src/lib.rs | 2 +- .../frame/salary/src/tests/integration.rs | 2 +- substrate/frame/salary/src/tests/unit.rs | 8 +- substrate/frame/sassafras/src/benchmarking.rs | 2 +- substrate/frame/sassafras/src/lib.rs | 8 +- substrate/frame/scheduler/README.md | 2 +- substrate/frame/scheduler/src/benchmarking.rs | 4 +- substrate/frame/scheduler/src/lib.rs | 2 +- substrate/frame/scheduler/src/tests.rs | 4 +- substrate/frame/society/src/lib.rs | 8 +- substrate/frame/society/src/migrations.rs | 8 +- substrate/frame/society/src/tests.rs | 2 +- substrate/frame/staking/src/ledger.rs | 2 +- substrate/frame/staking/src/migrations.rs | 2 +- substrate/frame/staking/src/pallet/impls.rs | 4 +- substrate/frame/staking/src/pallet/mod.rs | 8 +- substrate/frame/staking/src/tests.rs | 10 +-- substrate/frame/sudo/src/lib.rs | 2 +- .../frame/support/procedural/src/benchmark.rs | 4 +- .../procedural/src/construct_runtime/mod.rs | 6 +- .../procedural/src/construct_runtime/parse.rs | 10 +-- .../support/procedural/src/derive_impl.rs | 2 +- .../support/procedural/src/dynamic_params.rs | 18 ++--- substrate/frame/support/procedural/src/lib.rs | 6 +- .../procedural/src/pallet/parse/mod.rs | 2 +- .../frame/support/src/dispatch_context.rs | 4 +- substrate/frame/support/src/instances.rs | 32 ++++---- substrate/frame/support/src/lib.rs | 12 +-- .../frame/support/src/storage/migration.rs | 8 +- substrate/frame/support/src/storage/mod.rs | 21 ++--- .../frame/support/src/storage/stream_iter.rs | 2 +- .../support/src/storage/types/counted_map.rs | 10 +-- .../support/src/storage/types/counted_nmap.rs | 2 +- .../support/src/storage/types/double_map.rs | 5 +- .../frame/support/src/storage/types/map.rs | 5 +- .../frame/support/src/storage/types/mod.rs | 2 +- .../frame/support/src/storage/types/nmap.rs | 2 +- .../frame/support/src/storage/types/value.rs | 5 +- .../frame/support/src/traits/dispatch.rs | 2 +- .../support/src/traits/dynamic_params.rs | 40 +++++----- substrate/frame/support/src/traits/hooks.rs | 2 +- substrate/frame/support/src/traits/misc.rs | 2 +- .../conformance_tests/regular/unbalanced.rs | 2 +- .../traits/tokens/imbalance/split_two_ways.rs | 2 +- .../frame/support/src/traits/tokens/misc.rs | 2 +- .../derive_impl_ui/attached_to_non_impl.rs | 2 +- .../derive_impl_ui/bad_default_impl_path.rs | 4 +- .../derive_impl_ui/bad_disambiguation_path.rs | 4 +- .../missing_disambiguation_path.rs | 4 +- .../derive_impl_ui/pass/basic_overriding.rs | 12 +-- .../test/tests/pallet_outer_enums_explicit.rs | 2 +- .../test/tests/pallet_outer_enums_implicit.rs | 6 +- .../pallet_ui/pass/inherited_call_weight3.rs | 2 +- substrate/frame/system/src/limits.rs | 2 +- substrate/frame/system/src/offchain.rs | 6 +- substrate/frame/tips/src/migrations/mod.rs | 2 +- .../frame/transaction-payment/src/tests.rs | 2 +- substrate/frame/transaction-storage/README.md | 2 +- .../frame/transaction-storage/src/lib.rs | 2 +- .../frame/transaction-storage/src/tests.rs | 6 +- substrate/frame/treasury/src/lib.rs | 6 +- substrate/frame/uniques/src/tests.rs | 4 +- substrate/frame/utility/README.md | 2 +- substrate/frame/vesting/src/migrations.rs | 2 +- .../arithmetic/fuzzer/src/fixed_point.rs | 2 +- .../primitives/arithmetic/src/fixed_point.rs | 2 +- .../primitives/blockchain/src/backend.rs | 2 +- substrate/primitives/blockchain/src/error.rs | 2 +- .../blockchain/src/header_metadata.rs | 4 +- .../primitives/consensus/babe/src/lib.rs | 4 +- .../primitives/consensus/beefy/src/lib.rs | 2 +- .../primitives/consensus/beefy/src/mmr.rs | 4 +- .../primitives/consensus/beefy/src/payload.rs | 2 +- .../primitives/consensus/common/src/lib.rs | 2 +- .../consensus/sassafras/src/ticket.rs | 2 +- .../primitives/consensus/sassafras/src/vrf.rs | 2 +- substrate/primitives/core/src/address_uri.rs | 2 +- substrate/primitives/core/src/bandersnatch.rs | 2 +- .../primitives/core/src/paired_crypto.rs | 2 +- .../primitives/inherents/src/client_side.rs | 2 +- substrate/primitives/io/Cargo.toml | 2 +- substrate/primitives/io/src/lib.rs | 8 +- .../maybe-compressed-blob/Cargo.toml | 2 +- substrate/primitives/metadata-ir/src/types.rs | 2 +- .../primitives/npos-elections/src/pjr.rs | 2 +- .../primitives/npos-elections/src/reduce.rs | 2 +- .../primitives/runtime-interface/src/lib.rs | 2 +- .../test-wasm-deprecated/src/lib.rs | 12 +-- .../runtime-interface/test-wasm/src/lib.rs | 22 +++--- .../runtime-interface/test/src/lib.rs | 10 +-- .../src/generic/unchecked_extrinsic.rs | 2 +- .../runtime/src/offchain/storage_lock.rs | 2 +- substrate/primitives/runtime/src/testing.rs | 8 +- substrate/primitives/runtime/src/traits.rs | 4 +- substrate/primitives/staking/src/offence.rs | 2 +- substrate/primitives/state-machine/src/ext.rs | 4 +- substrate/primitives/state-machine/src/lib.rs | 12 +-- .../src/overlayed_changes/changeset.rs | 14 ++-- .../src/overlayed_changes/mod.rs | 8 +- .../primitives/state-machine/src/testing.rs | 2 +- .../state-machine/src/trie_backend_essence.rs | 8 +- substrate/primitives/storage/src/lib.rs | 2 +- substrate/primitives/tracing/src/lib.rs | 8 +- substrate/primitives/tracing/src/types.rs | 10 +-- .../transaction-storage-proof/src/lib.rs | 2 +- substrate/primitives/trie/src/cache/mod.rs | 2 +- substrate/primitives/trie/src/lib.rs | 4 +- .../proc-macro/src/decl_runtime_version.rs | 2 +- substrate/primitives/version/src/lib.rs | 2 +- substrate/utils/fork-tree/src/lib.rs | 6 +- .../benchmarking-cli/src/pallet/command.rs | 6 +- .../utils/frame/generate-bags/src/lib.rs | 2 +- .../frame/remote-externalities/src/lib.rs | 2 +- .../rpc/state-trie-migration-rpc/src/lib.rs | 2 +- substrate/utils/substrate-bip39/README.md | 8 +- substrate/utils/substrate-bip39/src/lib.rs | 2 +- substrate/utils/wasm-builder/src/lib.rs | 2 +- .../utils/wasm-builder/src/wasm_project.rs | 14 ++-- templates/minimal/node/Cargo.toml | 2 +- templates/minimal/runtime/Cargo.toml | 2 +- 463 files changed, 1119 insertions(+), 1017 deletions(-) create mode 100644 polkadot/node/subsystem-bench/src/lib/utils.rs create mode 100644 prdoc/pr_3808.prdoc diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index fdaa0c8628f..4fc5b97caae 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -13,7 +13,7 @@ # - Multiple owners are supported. # - Either handle (e.g, @github_user or @github/team) or email can be used. Keep in mind, # that handles might work better because they are more recognizable on GitHub, -# eyou can use them for mentioning unlike an email. +# you can use them for mentioning unlike an email. # - The latest matching rule, if multiple, takes precedence. # CI diff --git a/.github/scripts/common/lib.sh b/.github/scripts/common/lib.sh index 29dc269ffd2..932a6d546c3 100755 --- a/.github/scripts/common/lib.sh +++ b/.github/scripts/common/lib.sh @@ -237,7 +237,7 @@ fetch_release_artifacts() { popd > /dev/null } -# Fetch the release artifacts like binary and sigantures from S3. Assumes the ENV are set: +# Fetch the release artifacts like binary and signatures from S3. Assumes the ENV are set: # - RELEASE_ID # - GITHUB_TOKEN # - REPO in the form paritytech/polkadot diff --git a/.gitlab/pipeline/build.yml b/.gitlab/pipeline/build.yml index f8de6135572..44d66eb2f5e 100644 --- a/.gitlab/pipeline/build.yml +++ b/.gitlab/pipeline/build.yml @@ -350,7 +350,7 @@ build-runtimes-polkavm: - .run-immediately # - .collect-artifact variables: - # this variable gets overriden by "rusty-cachier environment inject", use the value as default + # this variable gets overridden by "rusty-cachier environment inject", use the value as default CARGO_TARGET_DIR: "$CI_PROJECT_DIR/target" before_script: - mkdir -p ./artifacts/subkey diff --git a/.gitlab/rust-features.sh b/.gitlab/rust-features.sh index c0ac192a6ec..c3ec61ab871 100755 --- a/.gitlab/rust-features.sh +++ b/.gitlab/rust-features.sh @@ -15,7 +15,7 @@ # # The steps of this script: # 1. Check that all required dependencies are installed. -# 2. Check that all rules are fullfilled for the whole workspace. If not: +# 2. Check that all rules are fulfilled for the whole workspace. If not: # 4. Check all crates to find the offending ones. # 5. Print all offending crates and exit with code 1. # diff --git a/bridges/bin/runtime-common/src/messages_api.rs b/bridges/bin/runtime-common/src/messages_api.rs index ccf1c754041..7fbdeb36612 100644 --- a/bridges/bin/runtime-common/src/messages_api.rs +++ b/bridges/bin/runtime-common/src/messages_api.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -//! Helpers for implementing various message-related runtime API mthods. +//! Helpers for implementing various message-related runtime API methods. use bp_messages::{ InboundMessageDetails, LaneId, MessageNonce, MessagePayload, OutboundMessageDetails, diff --git a/bridges/bin/runtime-common/src/messages_xcm_extension.rs b/bridges/bin/runtime-common/src/messages_xcm_extension.rs index e3da6155f08..46ed4da0d85 100644 --- a/bridges/bin/runtime-common/src/messages_xcm_extension.rs +++ b/bridges/bin/runtime-common/src/messages_xcm_extension.rs @@ -248,7 +248,7 @@ impl LocalXcmQueueManager { sender_and_lane: &SenderAndLane, enqueued_messages: MessageNonce, ) { - // skip if we dont want to handle congestion + // skip if we don't want to handle congestion if !H::supports_congestion_detection() { return } diff --git a/bridges/bin/runtime-common/src/mock.rs b/bridges/bin/runtime-common/src/mock.rs index deee4524e85..8c4cb2233e1 100644 --- a/bridges/bin/runtime-common/src/mock.rs +++ b/bridges/bin/runtime-common/src/mock.rs @@ -379,7 +379,7 @@ impl Chain for BridgedUnderlyingChain { impl ChainWithGrandpa for BridgedUnderlyingChain { const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = ""; const MAX_AUTHORITIES_COUNT: u32 = 16; - const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = 8; + const REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY: u32 = 8; const MAX_MANDATORY_HEADER_SIZE: u32 = 256; const AVERAGE_HEADER_SIZE: u32 = 64; } diff --git a/bridges/bin/runtime-common/src/priority_calculator.rs b/bridges/bin/runtime-common/src/priority_calculator.rs index c2737128e34..5035553f508 100644 --- a/bridges/bin/runtime-common/src/priority_calculator.rs +++ b/bridges/bin/runtime-common/src/priority_calculator.rs @@ -163,7 +163,7 @@ mod integrity_tests { { // just an estimation of extra transaction bytes that are added to every transaction // (including signature, signed extensions extra and etc + in our case it includes - // all call arguments extept the proof itself) + // all call arguments except the proof itself) let base_tx_size = 512; // let's say we are relaying similar small messages and for every message we add more trie // nodes to the proof (x0.5 because we expect some nodes to be reused) diff --git a/bridges/bin/runtime-common/src/refund_relayer_extension.rs b/bridges/bin/runtime-common/src/refund_relayer_extension.rs index 8e901d72821..455392a0a27 100644 --- a/bridges/bin/runtime-common/src/refund_relayer_extension.rs +++ b/bridges/bin/runtime-common/src/refund_relayer_extension.rs @@ -1538,7 +1538,7 @@ mod tests { } #[test] - fn validate_boosts_priority_of_message_delivery_transactons() { + fn validate_boosts_priority_of_message_delivery_transactions() { run_test(|| { initialize_environment(100, 100, 100); @@ -1568,7 +1568,7 @@ mod tests { } #[test] - fn validate_does_not_boost_priority_of_message_delivery_transactons_with_too_many_messages() { + fn validate_does_not_boost_priority_of_message_delivery_transactions_with_too_many_messages() { run_test(|| { initialize_environment(100, 100, 100); diff --git a/bridges/chains/chain-kusama/src/lib.rs b/bridges/chains/chain-kusama/src/lib.rs index e3b4d0520f6..a81004afe81 100644 --- a/bridges/chains/chain-kusama/src/lib.rs +++ b/bridges/chains/chain-kusama/src/lib.rs @@ -53,8 +53,8 @@ impl Chain for Kusama { impl ChainWithGrandpa for Kusama { const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = WITH_KUSAMA_GRANDPA_PALLET_NAME; const MAX_AUTHORITIES_COUNT: u32 = MAX_AUTHORITIES_COUNT; - const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = - REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY; + const REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY: u32 = + REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY; const MAX_MANDATORY_HEADER_SIZE: u32 = MAX_MANDATORY_HEADER_SIZE; const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } diff --git a/bridges/chains/chain-polkadot-bulletin/src/lib.rs b/bridges/chains/chain-polkadot-bulletin/src/lib.rs index f2eebf93124..f3d300567f2 100644 --- a/bridges/chains/chain-polkadot-bulletin/src/lib.rs +++ b/bridges/chains/chain-polkadot-bulletin/src/lib.rs @@ -43,7 +43,7 @@ use sp_runtime::{traits::DispatchInfoOf, transaction_validity::TransactionValidi pub use bp_polkadot_core::{ AccountAddress, AccountId, Balance, Block, BlockNumber, Hash, Hasher, Header, Nonce, Signature, SignedBlock, UncheckedExtrinsic, AVERAGE_HEADER_SIZE, EXTRA_STORAGE_PROOF_SIZE, - MAX_MANDATORY_HEADER_SIZE, REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY, + MAX_MANDATORY_HEADER_SIZE, REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY, }; /// Maximal number of GRANDPA authorities at Polkadot Bulletin chain. @@ -62,7 +62,7 @@ const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(90); // Re following constants - we are using the same values at Cumulus parachains. They are limited // by the maximal transaction weight/size. Since block limits at Bulletin Chain are larger than -// at the Cumulus Bridgeg Hubs, we could reuse the same values. +// at the Cumulus Bridge Hubs, we could reuse the same values. /// Maximal number of unrewarded relayer entries at inbound lane for Cumulus-based parachains. pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 1024; @@ -207,8 +207,8 @@ impl Chain for PolkadotBulletin { impl ChainWithGrandpa for PolkadotBulletin { const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = WITH_POLKADOT_BULLETIN_GRANDPA_PALLET_NAME; const MAX_AUTHORITIES_COUNT: u32 = MAX_AUTHORITIES_COUNT; - const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = - REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY; + const REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY: u32 = + REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY; const MAX_MANDATORY_HEADER_SIZE: u32 = MAX_MANDATORY_HEADER_SIZE; const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } diff --git a/bridges/chains/chain-polkadot/src/lib.rs b/bridges/chains/chain-polkadot/src/lib.rs index fc5e10308a8..00d35783a9b 100644 --- a/bridges/chains/chain-polkadot/src/lib.rs +++ b/bridges/chains/chain-polkadot/src/lib.rs @@ -55,8 +55,8 @@ impl Chain for Polkadot { impl ChainWithGrandpa for Polkadot { const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = WITH_POLKADOT_GRANDPA_PALLET_NAME; const MAX_AUTHORITIES_COUNT: u32 = MAX_AUTHORITIES_COUNT; - const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = - REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY; + const REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY: u32 = + REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY; const MAX_MANDATORY_HEADER_SIZE: u32 = MAX_MANDATORY_HEADER_SIZE; const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } diff --git a/bridges/chains/chain-rococo/src/lib.rs b/bridges/chains/chain-rococo/src/lib.rs index f1b256f0f09..2385dd2cbb2 100644 --- a/bridges/chains/chain-rococo/src/lib.rs +++ b/bridges/chains/chain-rococo/src/lib.rs @@ -53,8 +53,8 @@ impl Chain for Rococo { impl ChainWithGrandpa for Rococo { const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = WITH_ROCOCO_GRANDPA_PALLET_NAME; const MAX_AUTHORITIES_COUNT: u32 = MAX_AUTHORITIES_COUNT; - const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = - REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY; + const REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY: u32 = + REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY; const MAX_MANDATORY_HEADER_SIZE: u32 = MAX_MANDATORY_HEADER_SIZE; const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } diff --git a/bridges/chains/chain-westend/src/lib.rs b/bridges/chains/chain-westend/src/lib.rs index f03fd2160a7..b344b7f4bf9 100644 --- a/bridges/chains/chain-westend/src/lib.rs +++ b/bridges/chains/chain-westend/src/lib.rs @@ -53,8 +53,8 @@ impl Chain for Westend { impl ChainWithGrandpa for Westend { const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = WITH_WESTEND_GRANDPA_PALLET_NAME; const MAX_AUTHORITIES_COUNT: u32 = MAX_AUTHORITIES_COUNT; - const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = - REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY; + const REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY: u32 = + REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY; const MAX_MANDATORY_HEADER_SIZE: u32 = MAX_MANDATORY_HEADER_SIZE; const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } diff --git a/bridges/modules/grandpa/README.md b/bridges/modules/grandpa/README.md index 992bd2cc472..4a3099b8afc 100644 --- a/bridges/modules/grandpa/README.md +++ b/bridges/modules/grandpa/README.md @@ -10,7 +10,7 @@ It is used by the parachains light client (bridge parachains pallet) and by mess ## A Brief Introduction into GRANDPA Finality You can find detailed information on GRANDPA, by exploring its [repository](https://github.com/paritytech/finality-grandpa). -Here is the minimal reqiuired GRANDPA information to understand how pallet works. +Here is the minimal required GRANDPA information to understand how pallet works. Any Substrate chain may use different block authorship algorithms (like BABE or Aura) to determine block producers and generate blocks. This has nothing common with finality, though - the task of block authorship is to coordinate diff --git a/bridges/modules/grandpa/src/call_ext.rs b/bridges/modules/grandpa/src/call_ext.rs index e3c778b480b..4a7ebb3cc8d 100644 --- a/bridges/modules/grandpa/src/call_ext.rs +++ b/bridges/modules/grandpa/src/call_ext.rs @@ -205,7 +205,7 @@ pub(crate) fn submit_finality_proof_info_from_args, I: 'static>( // as an extra weight. let votes_ancestries_len = justification.votes_ancestries.len().saturated_into(); let extra_weight = - if votes_ancestries_len > T::BridgedChain::REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY { + if votes_ancestries_len > T::BridgedChain::REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY { T::WeightInfo::submit_finality_proof(precommits_len, votes_ancestries_len) } else { Weight::zero() @@ -396,11 +396,11 @@ mod tests { let finality_target = test_header(1); let mut justification_params = JustificationGeneratorParams { header: finality_target.clone(), - ancestors: TestBridgedChain::REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY, + ancestors: TestBridgedChain::REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY, ..Default::default() }; - // when there are `REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY` headers => no refund + // when there are `REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY` headers => no refund let justification = make_justification_for_header(justification_params.clone()); let call = RuntimeCall::Grandpa(crate::Call::submit_finality_proof_ex { finality_target: Box::new(finality_target.clone()), @@ -409,7 +409,7 @@ mod tests { }); assert_eq!(call.submit_finality_proof_info().unwrap().extra_weight, Weight::zero()); - // when there are `REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY + 1` headers => full refund + // when there are `REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY + 1` headers => full refund justification_params.ancestors += 1; let justification = make_justification_for_header(justification_params); let call_weight = ::WeightInfo::submit_finality_proof( diff --git a/bridges/modules/grandpa/src/lib.rs b/bridges/modules/grandpa/src/lib.rs index ce2c47da954..9e095651ef8 100644 --- a/bridges/modules/grandpa/src/lib.rs +++ b/bridges/modules/grandpa/src/lib.rs @@ -935,7 +935,7 @@ mod tests { } #[test] - fn succesfully_imports_header_with_valid_finality() { + fn successfully_imports_header_with_valid_finality() { run_test(|| { initialize_substrate_bridge(); @@ -1192,7 +1192,7 @@ mod tests { header.digest = change_log(0); let justification = make_justification_for_header(JustificationGeneratorParams { header: header.clone(), - ancestors: TestBridgedChain::REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY + 1, + ancestors: TestBridgedChain::REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY + 1, ..Default::default() }); diff --git a/bridges/modules/grandpa/src/mock.rs b/bridges/modules/grandpa/src/mock.rs index 4318d663a2e..e689e520c92 100644 --- a/bridges/modules/grandpa/src/mock.rs +++ b/bridges/modules/grandpa/src/mock.rs @@ -87,7 +87,7 @@ impl Chain for TestBridgedChain { impl ChainWithGrandpa for TestBridgedChain { const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = ""; const MAX_AUTHORITIES_COUNT: u32 = MAX_BRIDGED_AUTHORITIES; - const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = 8; + const REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY: u32 = 8; const MAX_MANDATORY_HEADER_SIZE: u32 = 256; const AVERAGE_HEADER_SIZE: u32 = 64; } diff --git a/bridges/modules/messages/src/inbound_lane.rs b/bridges/modules/messages/src/inbound_lane.rs index 966ec939e70..da1698e6e03 100644 --- a/bridges/modules/messages/src/inbound_lane.rs +++ b/bridges/modules/messages/src/inbound_lane.rs @@ -21,7 +21,7 @@ use crate::Config; use bp_messages::{ target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, DeliveredMessages, InboundLaneData, LaneId, MessageKey, MessageNonce, OutboundLaneData, - ReceivalResult, UnrewardedRelayer, + ReceptionResult, UnrewardedRelayer, }; use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; use frame_support::traits::Get; @@ -170,21 +170,21 @@ impl InboundLane { relayer_at_bridged_chain: &S::Relayer, nonce: MessageNonce, message_data: DispatchMessageData, - ) -> ReceivalResult { + ) -> ReceptionResult { let mut data = self.storage.get_or_init_data(); if Some(nonce) != data.last_delivered_nonce().checked_add(1) { - return ReceivalResult::InvalidNonce + return ReceptionResult::InvalidNonce } // if there are more unrewarded relayer entries than we may accept, reject this message if data.relayers.len() as MessageNonce >= self.storage.max_unrewarded_relayer_entries() { - return ReceivalResult::TooManyUnrewardedRelayers + return ReceptionResult::TooManyUnrewardedRelayers } // if there are more unconfirmed messages than we may accept, reject this message let unconfirmed_messages_count = nonce.saturating_sub(data.last_confirmed_nonce); if unconfirmed_messages_count > self.storage.max_unconfirmed_messages() { - return ReceivalResult::TooManyUnconfirmedMessages + return ReceptionResult::TooManyUnconfirmedMessages } // then, dispatch message @@ -207,7 +207,7 @@ impl InboundLane { }; self.storage.set_data(data); - ReceivalResult::Dispatched(dispatch_result) + ReceptionResult::Dispatched(dispatch_result) } } @@ -235,7 +235,7 @@ mod tests { nonce, inbound_message_data(REGULAR_PAYLOAD) ), - ReceivalResult::Dispatched(dispatch_result(0)) + ReceptionResult::Dispatched(dispatch_result(0)) ); } @@ -362,7 +362,7 @@ mod tests { 10, inbound_message_data(REGULAR_PAYLOAD) ), - ReceivalResult::InvalidNonce + ReceptionResult::InvalidNonce ); assert_eq!(lane.storage.get_or_init_data().last_delivered_nonce(), 0); }); @@ -381,7 +381,7 @@ mod tests { current_nonce, inbound_message_data(REGULAR_PAYLOAD) ), - ReceivalResult::Dispatched(dispatch_result(0)) + ReceptionResult::Dispatched(dispatch_result(0)) ); } // Fails to dispatch new message from different than latest relayer. @@ -391,7 +391,7 @@ mod tests { max_nonce + 1, inbound_message_data(REGULAR_PAYLOAD) ), - ReceivalResult::TooManyUnrewardedRelayers, + ReceptionResult::TooManyUnrewardedRelayers, ); // Fails to dispatch new messages from latest relayer. Prevents griefing attacks. assert_eq!( @@ -400,7 +400,7 @@ mod tests { max_nonce + 1, inbound_message_data(REGULAR_PAYLOAD) ), - ReceivalResult::TooManyUnrewardedRelayers, + ReceptionResult::TooManyUnrewardedRelayers, ); }); } @@ -417,7 +417,7 @@ mod tests { current_nonce, inbound_message_data(REGULAR_PAYLOAD) ), - ReceivalResult::Dispatched(dispatch_result(0)) + ReceptionResult::Dispatched(dispatch_result(0)) ); } // Fails to dispatch new message from different than latest relayer. @@ -427,7 +427,7 @@ mod tests { max_nonce + 1, inbound_message_data(REGULAR_PAYLOAD) ), - ReceivalResult::TooManyUnconfirmedMessages, + ReceptionResult::TooManyUnconfirmedMessages, ); // Fails to dispatch new messages from latest relayer. assert_eq!( @@ -436,7 +436,7 @@ mod tests { max_nonce + 1, inbound_message_data(REGULAR_PAYLOAD) ), - ReceivalResult::TooManyUnconfirmedMessages, + ReceptionResult::TooManyUnconfirmedMessages, ); }); } @@ -451,7 +451,7 @@ mod tests { 1, inbound_message_data(REGULAR_PAYLOAD) ), - ReceivalResult::Dispatched(dispatch_result(0)) + ReceptionResult::Dispatched(dispatch_result(0)) ); assert_eq!( lane.receive_message::( @@ -459,7 +459,7 @@ mod tests { 2, inbound_message_data(REGULAR_PAYLOAD) ), - ReceivalResult::Dispatched(dispatch_result(0)) + ReceptionResult::Dispatched(dispatch_result(0)) ); assert_eq!( lane.receive_message::( @@ -467,7 +467,7 @@ mod tests { 3, inbound_message_data(REGULAR_PAYLOAD) ), - ReceivalResult::Dispatched(dispatch_result(0)) + ReceptionResult::Dispatched(dispatch_result(0)) ); assert_eq!( lane.storage.get_or_init_data().relayers, @@ -490,7 +490,7 @@ mod tests { 1, inbound_message_data(REGULAR_PAYLOAD) ), - ReceivalResult::Dispatched(dispatch_result(0)) + ReceptionResult::Dispatched(dispatch_result(0)) ); assert_eq!( lane.receive_message::( @@ -498,7 +498,7 @@ mod tests { 1, inbound_message_data(REGULAR_PAYLOAD) ), - ReceivalResult::InvalidNonce, + ReceptionResult::InvalidNonce, ); }); } @@ -524,7 +524,7 @@ mod tests { 1, inbound_message_data(payload) ), - ReceivalResult::Dispatched(dispatch_result(1)) + ReceptionResult::Dispatched(dispatch_result(1)) ); }); } diff --git a/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs index a86cb326cf0..bc00db9eba5 100644 --- a/bridges/modules/messages/src/lib.rs +++ b/bridges/modules/messages/src/lib.rs @@ -47,7 +47,7 @@ pub use weights_ext::{ use crate::{ inbound_lane::{InboundLane, InboundLaneStorage}, - outbound_lane::{OutboundLane, OutboundLaneStorage, ReceivalConfirmationError}, + outbound_lane::{OutboundLane, OutboundLaneStorage, ReceptionConfirmationError}, }; use bp_messages::{ @@ -90,7 +90,7 @@ pub const LOG_TARGET: &str = "runtime::bridge-messages"; #[frame_support::pallet] pub mod pallet { use super::*; - use bp_messages::{ReceivalResult, ReceivedMessages}; + use bp_messages::{ReceivedMessages, ReceptionResult}; use bp_runtime::RangeInclusiveExt; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; @@ -376,13 +376,13 @@ pub mod pallet { // delivery transaction cost anyway. And base cost covers everything except // dispatch, so we have a balance here. let unspent_weight = match &receival_result { - ReceivalResult::Dispatched(dispatch_result) => { + ReceptionResult::Dispatched(dispatch_result) => { valid_messages += 1; dispatch_result.unspent_weight }, - ReceivalResult::InvalidNonce | - ReceivalResult::TooManyUnrewardedRelayers | - ReceivalResult::TooManyUnconfirmedMessages => message_dispatch_weight, + ReceptionResult::InvalidNonce | + ReceptionResult::TooManyUnrewardedRelayers | + ReceptionResult::TooManyUnconfirmedMessages => message_dispatch_weight, }; lane_messages_received_status.push(message.key.nonce, receival_result); @@ -455,7 +455,7 @@ pub mod pallet { last_delivered_nonce, &lane_data.relayers, ) - .map_err(Error::::ReceivalConfirmation)?; + .map_err(Error::::ReceptionConfirmation)?; if let Some(confirmed_messages) = confirmed_messages { // emit 'delivered' event @@ -563,7 +563,7 @@ pub mod pallet { /// The message someone is trying to work with (i.e. increase fee) is not yet sent. MessageIsNotYetSent, /// Error confirming messages receival. - ReceivalConfirmation(ReceivalConfirmationError), + ReceptionConfirmation(ReceptionConfirmationError), /// Error generated by the `OwnedBridgeModule` trait. BridgeModule(bp_runtime::OwnedBridgeModuleError), } @@ -923,7 +923,7 @@ mod tests { PAYLOAD_REJECTED_BY_TARGET_CHAIN, REGULAR_PAYLOAD, TEST_LANE_ID, TEST_LANE_ID_2, TEST_LANE_ID_3, TEST_RELAYER_A, TEST_RELAYER_B, }, - outbound_lane::ReceivalConfirmationError, + outbound_lane::ReceptionConfirmationError, }; use bp_messages::{ source_chain::MessagesBridge, BridgeMessagesCall, UnrewardedRelayer, @@ -950,11 +950,11 @@ mod tests { let outbound_lane = outbound_lane::(lane_id); let message_nonce = outbound_lane.data().latest_generated_nonce + 1; - let prev_enqueud_messages = outbound_lane.data().queued_messages().saturating_len(); + let prev_enqueued_messages = outbound_lane.data().queued_messages().saturating_len(); let valid_message = Pallet::::validate_message(lane_id, ®ULAR_PAYLOAD) .expect("validate_message has failed"); let artifacts = Pallet::::send_message(valid_message); - assert_eq!(artifacts.enqueued_messages, prev_enqueud_messages + 1); + assert_eq!(artifacts.enqueued_messages, prev_enqueued_messages + 1); // check event with assigned nonce assert_eq!( @@ -1541,7 +1541,7 @@ mod tests { } #[test] - fn actual_dispatch_weight_does_not_overlow() { + fn actual_dispatch_weight_does_not_overflow() { run_test(|| { let message1 = message(1, message_payload(0, u64::MAX / 2)); let message2 = message(2, message_payload(0, u64::MAX / 2)); @@ -1775,7 +1775,7 @@ mod tests { // returns `last_confirmed_nonce`; // 3) it means that we're going to confirm delivery of messages 1..=1; // 4) so the number of declared messages (see `UnrewardedRelayersState`) is `0` and - // numer of actually confirmed messages is `1`. + // number of actually confirmed messages is `1`. assert_noop!( Pallet::::receive_messages_delivery_proof( RuntimeOrigin::signed(1), @@ -1785,8 +1785,8 @@ mod tests { ))), UnrewardedRelayersState { last_delivered_nonce: 1, ..Default::default() }, ), - Error::::ReceivalConfirmation( - ReceivalConfirmationError::TryingToConfirmMoreMessagesThanExpected + Error::::ReceptionConfirmation( + ReceptionConfirmationError::TryingToConfirmMoreMessagesThanExpected ), ); }); diff --git a/bridges/modules/messages/src/outbound_lane.rs b/bridges/modules/messages/src/outbound_lane.rs index 431c2cfb7ee..acef5546d2a 100644 --- a/bridges/modules/messages/src/outbound_lane.rs +++ b/bridges/modules/messages/src/outbound_lane.rs @@ -53,7 +53,7 @@ pub type StoredMessagePayload = BoundedVec>::MaximalOu /// Result of messages receival confirmation. #[derive(Encode, Decode, RuntimeDebug, PartialEq, Eq, PalletError, TypeInfo)] -pub enum ReceivalConfirmationError { +pub enum ReceptionConfirmationError { /// Bridged chain is trying to confirm more messages than we have generated. May be a result /// of invalid bridged chain storage. FailedToConfirmFutureMessages, @@ -103,7 +103,7 @@ impl OutboundLane { max_allowed_messages: MessageNonce, latest_delivered_nonce: MessageNonce, relayers: &VecDeque>, - ) -> Result, ReceivalConfirmationError> { + ) -> Result, ReceptionConfirmationError> { let mut data = self.storage.data(); let confirmed_messages = DeliveredMessages { begin: data.latest_received_nonce.saturating_add(1), @@ -113,7 +113,7 @@ impl OutboundLane { return Ok(None) } if confirmed_messages.end > data.latest_generated_nonce { - return Err(ReceivalConfirmationError::FailedToConfirmFutureMessages) + return Err(ReceptionConfirmationError::FailedToConfirmFutureMessages) } if confirmed_messages.total_messages() > max_allowed_messages { // that the relayer has declared correct number of messages that the proof contains (it @@ -127,7 +127,7 @@ impl OutboundLane { confirmed_messages.total_messages(), max_allowed_messages, ); - return Err(ReceivalConfirmationError::TryingToConfirmMoreMessagesThanExpected) + return Err(ReceptionConfirmationError::TryingToConfirmMoreMessagesThanExpected) } ensure_unrewarded_relayers_are_correct(confirmed_messages.end, relayers)?; @@ -176,24 +176,24 @@ impl OutboundLane { fn ensure_unrewarded_relayers_are_correct( latest_received_nonce: MessageNonce, relayers: &VecDeque>, -) -> Result<(), ReceivalConfirmationError> { +) -> Result<(), ReceptionConfirmationError> { let mut expected_entry_begin = relayers.front().map(|entry| entry.messages.begin); for entry in relayers { // unrewarded relayer entry must have at least 1 unconfirmed message // (guaranteed by the `InboundLane::receive_message()`) if entry.messages.end < entry.messages.begin { - return Err(ReceivalConfirmationError::EmptyUnrewardedRelayerEntry) + return Err(ReceptionConfirmationError::EmptyUnrewardedRelayerEntry) } // every entry must confirm range of messages that follows previous entry range // (guaranteed by the `InboundLane::receive_message()`) if expected_entry_begin != Some(entry.messages.begin) { - return Err(ReceivalConfirmationError::NonConsecutiveUnrewardedRelayerEntries) + return Err(ReceptionConfirmationError::NonConsecutiveUnrewardedRelayerEntries) } expected_entry_begin = entry.messages.end.checked_add(1); // entry can't confirm messages larger than `inbound_lane_data.latest_received_nonce()` // (guaranteed by the `InboundLane::receive_message()`) if entry.messages.end > latest_received_nonce { - return Err(ReceivalConfirmationError::FailedToConfirmFutureMessages) + return Err(ReceptionConfirmationError::FailedToConfirmFutureMessages) } } @@ -228,7 +228,7 @@ mod tests { fn assert_3_messages_confirmation_fails( latest_received_nonce: MessageNonce, relayers: &VecDeque>, - ) -> Result, ReceivalConfirmationError> { + ) -> Result, ReceptionConfirmationError> { run_test(|| { let mut lane = outbound_lane::(TEST_LANE_ID); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); @@ -299,7 +299,7 @@ mod tests { fn confirm_delivery_rejects_nonce_larger_than_last_generated() { assert_eq!( assert_3_messages_confirmation_fails(10, &unrewarded_relayers(1..=10),), - Err(ReceivalConfirmationError::FailedToConfirmFutureMessages), + Err(ReceptionConfirmationError::FailedToConfirmFutureMessages), ); } @@ -314,7 +314,7 @@ mod tests { .chain(unrewarded_relayers(3..=3).into_iter()) .collect(), ), - Err(ReceivalConfirmationError::FailedToConfirmFutureMessages), + Err(ReceptionConfirmationError::FailedToConfirmFutureMessages), ); } @@ -330,7 +330,7 @@ mod tests { .chain(unrewarded_relayers(2..=3).into_iter()) .collect(), ), - Err(ReceivalConfirmationError::EmptyUnrewardedRelayerEntry), + Err(ReceptionConfirmationError::EmptyUnrewardedRelayerEntry), ); } @@ -345,7 +345,7 @@ mod tests { .chain(unrewarded_relayers(2..=2).into_iter()) .collect(), ), - Err(ReceivalConfirmationError::NonConsecutiveUnrewardedRelayerEntries), + Err(ReceptionConfirmationError::NonConsecutiveUnrewardedRelayerEntries), ); } @@ -409,11 +409,11 @@ mod tests { lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); assert_eq!( lane.confirm_delivery(0, 3, &unrewarded_relayers(1..=3)), - Err(ReceivalConfirmationError::TryingToConfirmMoreMessagesThanExpected), + Err(ReceptionConfirmationError::TryingToConfirmMoreMessagesThanExpected), ); assert_eq!( lane.confirm_delivery(2, 3, &unrewarded_relayers(1..=3)), - Err(ReceivalConfirmationError::TryingToConfirmMoreMessagesThanExpected), + Err(ReceptionConfirmationError::TryingToConfirmMoreMessagesThanExpected), ); assert_eq!( lane.confirm_delivery(3, 3, &unrewarded_relayers(1..=3)), diff --git a/bridges/modules/parachains/src/mock.rs b/bridges/modules/parachains/src/mock.rs index 3af3fd3e763..d9cbabf850e 100644 --- a/bridges/modules/parachains/src/mock.rs +++ b/bridges/modules/parachains/src/mock.rs @@ -261,7 +261,7 @@ impl Chain for TestBridgedChain { impl ChainWithGrandpa for TestBridgedChain { const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = ""; const MAX_AUTHORITIES_COUNT: u32 = 16; - const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = 8; + const REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY: u32 = 8; const MAX_MANDATORY_HEADER_SIZE: u32 = 256; const AVERAGE_HEADER_SIZE: u32 = 64; } @@ -294,7 +294,7 @@ impl Chain for OtherBridgedChain { impl ChainWithGrandpa for OtherBridgedChain { const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = ""; const MAX_AUTHORITIES_COUNT: u32 = 16; - const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = 8; + const REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY: u32 = 8; const MAX_MANDATORY_HEADER_SIZE: u32 = 256; const AVERAGE_HEADER_SIZE: u32 = 64; } diff --git a/bridges/modules/xcm-bridge-hub-router/src/lib.rs b/bridges/modules/xcm-bridge-hub-router/src/lib.rs index f219be78f9e..5d0be41b1b5 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/lib.rs @@ -427,7 +427,7 @@ mod tests { run_test(|| { Bridge::::put(uncongested_bridge(FixedU128::from_rational(125, 100))); - // it shold eventually decreased to one + // it should eventually decreased to one while XcmBridgeHubRouter::bridge().delivery_fee_factor > MINIMAL_DELIVERY_FEE_FACTOR { XcmBridgeHubRouter::on_initialize(One::one()); } diff --git a/bridges/modules/xcm-bridge-hub/Cargo.toml b/bridges/modules/xcm-bridge-hub/Cargo.toml index d910319d9bf..68ac32281f3 100644 --- a/bridges/modules/xcm-bridge-hub/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pallet-xcm-bridge-hub" -description = "Module that adds dynamic bridges/lanes support to XCM infrastucture at the bridge hub." +description = "Module that adds dynamic bridges/lanes support to XCM infrastructure at the bridge hub." version = "0.2.0" authors.workspace = true edition.workspace = true diff --git a/bridges/primitives/header-chain/src/justification/mod.rs b/bridges/primitives/header-chain/src/justification/mod.rs index b32d8bdb5f1..d7c2cbf429e 100644 --- a/bridges/primitives/header-chain/src/justification/mod.rs +++ b/bridges/primitives/header-chain/src/justification/mod.rs @@ -83,7 +83,7 @@ impl GrandpaJustification { .saturating_add(HashOf::::max_encoded_len().saturated_into()); let max_expected_votes_ancestries_size = - C::REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY.saturating_mul(C::AVERAGE_HEADER_SIZE); + C::REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY.saturating_mul(C::AVERAGE_HEADER_SIZE); // justification is round number (u64=8b), a signed GRANDPA commit and the // `votes_ancestries` vector diff --git a/bridges/primitives/header-chain/src/justification/verification/mod.rs b/bridges/primitives/header-chain/src/justification/verification/mod.rs index c71149bf9c2..9df3511e103 100644 --- a/bridges/primitives/header-chain/src/justification/verification/mod.rs +++ b/bridges/primitives/header-chain/src/justification/verification/mod.rs @@ -318,7 +318,7 @@ trait JustificationVerifier { } // check that the cumulative weight of validators that voted for the justification target - // (or one of its descendents) is larger than the required threshold. + // (or one of its descendants) is larger than the required threshold. if cumulative_weight < threshold { return Err(Error::TooLowCumulativeWeight) } diff --git a/bridges/primitives/header-chain/src/lib.rs b/bridges/primitives/header-chain/src/lib.rs index 84a6a881a83..98fb9ff83d8 100644 --- a/bridges/primitives/header-chain/src/lib.rs +++ b/bridges/primitives/header-chain/src/lib.rs @@ -283,7 +283,7 @@ pub trait ChainWithGrandpa: Chain { /// ancestry and the pallet will accept such justification. The limit is only used to compute /// maximal refund amount and submitting justifications which exceed the limit, may be costly /// to submitter. - const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32; + const REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY: u32; /// Maximal size of the mandatory chain header. Mandatory header is the header that enacts new /// GRANDPA authorities set (so it has large digest inside). @@ -317,8 +317,8 @@ where const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = ::WITH_CHAIN_GRANDPA_PALLET_NAME; const MAX_AUTHORITIES_COUNT: u32 = ::MAX_AUTHORITIES_COUNT; - const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = - ::REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY; + const REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY: u32 = + ::REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY; const MAX_MANDATORY_HEADER_SIZE: u32 = ::MAX_MANDATORY_HEADER_SIZE; const AVERAGE_HEADER_SIZE: u32 = ::AVERAGE_HEADER_SIZE; @@ -373,7 +373,7 @@ mod tests { impl ChainWithGrandpa for TestChain { const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = "Test"; const MAX_AUTHORITIES_COUNT: u32 = 128; - const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = 2; + const REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY: u32 = 2; const MAX_MANDATORY_HEADER_SIZE: u32 = 100_000; const AVERAGE_HEADER_SIZE: u32 = 1_024; } diff --git a/bridges/primitives/messages/src/lib.rs b/bridges/primitives/messages/src/lib.rs index 51b3f25f715..c3f79b3ee38 100644 --- a/bridges/primitives/messages/src/lib.rs +++ b/bridges/primitives/messages/src/lib.rs @@ -289,27 +289,27 @@ pub struct ReceivedMessages { /// Id of the lane which is receiving messages. pub lane: LaneId, /// Result of messages which we tried to dispatch - pub receive_results: Vec<(MessageNonce, ReceivalResult)>, + pub receive_results: Vec<(MessageNonce, ReceptionResult)>, } impl ReceivedMessages { /// Creates new `ReceivedMessages` structure from given results. pub fn new( lane: LaneId, - receive_results: Vec<(MessageNonce, ReceivalResult)>, + receive_results: Vec<(MessageNonce, ReceptionResult)>, ) -> Self { ReceivedMessages { lane, receive_results } } /// Push `result` of the `message` delivery onto `receive_results` vector. - pub fn push(&mut self, message: MessageNonce, result: ReceivalResult) { + pub fn push(&mut self, message: MessageNonce, result: ReceptionResult) { self.receive_results.push((message, result)); } } /// Result of single message receival. #[derive(RuntimeDebug, Encode, Decode, PartialEq, Eq, Clone, TypeInfo)] -pub enum ReceivalResult { +pub enum ReceptionResult { /// Message has been received and dispatched. Note that we don't care whether dispatch has /// been successful or not - in both case message falls into this category. /// diff --git a/bridges/primitives/polkadot-core/src/lib.rs b/bridges/primitives/polkadot-core/src/lib.rs index df2836495bb..e83be59b238 100644 --- a/bridges/primitives/polkadot-core/src/lib.rs +++ b/bridges/primitives/polkadot-core/src/lib.rs @@ -71,7 +71,7 @@ pub const MAX_AUTHORITIES_COUNT: u32 = 1_256; /// justifications with any additional headers in votes ancestry, so reasonable headers may /// be set to zero. But we assume that there may be small GRANDPA lags, so we're leaving some /// reserve here. -pub const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = 2; +pub const REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY: u32 = 2; /// Average header size in `votes_ancestries` field of justification on Polkadot-like /// chains. diff --git a/bridges/primitives/runtime/src/chain.rs b/bridges/primitives/runtime/src/chain.rs index 9ba21a1cddf..4ec5a001a99 100644 --- a/bridges/primitives/runtime/src/chain.rs +++ b/bridges/primitives/runtime/src/chain.rs @@ -104,7 +104,7 @@ pub trait Chain: Send + Sync + 'static { const ID: ChainId; /// A type that fulfills the abstract idea of what a Substrate block number is. - // Constraits come from the associated Number type of `sp_runtime::traits::Header` + // Constraints come from the associated Number type of `sp_runtime::traits::Header` // See here for more info: // https://crates.parity.io/sp_runtime/traits/trait.Header.html#associatedtype.Number // @@ -125,7 +125,7 @@ pub trait Chain: Send + Sync + 'static { + MaxEncodedLen; /// A type that fulfills the abstract idea of what a Substrate hash is. - // Constraits come from the associated Hash type of `sp_runtime::traits::Header` + // Constraints come from the associated Hash type of `sp_runtime::traits::Header` // See here for more info: // https://crates.parity.io/sp_runtime/traits/trait.Header.html#associatedtype.Hash type Hash: Parameter @@ -143,7 +143,7 @@ pub trait Chain: Send + Sync + 'static { /// A type that fulfills the abstract idea of what a Substrate hasher (a type /// that produces hashes) is. - // Constraits come from the associated Hashing type of `sp_runtime::traits::Header` + // Constraints come from the associated Hashing type of `sp_runtime::traits::Header` // See here for more info: // https://crates.parity.io/sp_runtime/traits/trait.Header.html#associatedtype.Hashing type Hasher: HashT; diff --git a/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs index 850318923dc..c9c5c941291 100644 --- a/bridges/primitives/runtime/src/lib.rs +++ b/bridges/primitives/runtime/src/lib.rs @@ -56,7 +56,7 @@ mod chain; mod storage_proof; mod storage_types; -// Re-export macro to aviod include paste dependency everywhere +// Re-export macro to avoid include paste dependency everywhere pub use sp_runtime::paste; /// Use this when something must be shared among all instances. @@ -461,7 +461,7 @@ macro_rules! generate_static_str_provider { }; } -/// Error message that is only dispayable in `std` environment. +/// Error message that is only displayable in `std` environment. #[derive(Encode, Decode, Clone, Eq, PartialEq, PalletError, TypeInfo)] #[scale_info(skip_type_params(T))] pub struct StrippableError { diff --git a/bridges/primitives/test-utils/src/lib.rs b/bridges/primitives/test-utils/src/lib.rs index 1d80890779b..f4fe4a242e7 100644 --- a/bridges/primitives/test-utils/src/lib.rs +++ b/bridges/primitives/test-utils/src/lib.rs @@ -88,7 +88,7 @@ pub fn make_default_justification(header: &H) -> GrandpaJustificatio /// Generate justifications in a way where we are able to tune the number of pre-commits /// and vote ancestries which are included in the justification. /// -/// This is useful for benchmarkings where we want to generate valid justifications with +/// This is useful for benchmarks where we want to generate valid justifications with /// a specific number of pre-commits (tuned with the number of "authorities") and/or a specific /// number of vote ancestries (tuned with the "votes" parameter). /// diff --git a/bridges/scripts/verify-pallets-build.sh b/bridges/scripts/verify-pallets-build.sh index 4eefaa8efa0..9c57a2a3c47 100755 --- a/bridges/scripts/verify-pallets-build.sh +++ b/bridges/scripts/verify-pallets-build.sh @@ -134,7 +134,7 @@ cargo check -p bridge-runtime-common cargo check -p bridge-runtime-common --features runtime-benchmarks cargo check -p bridge-runtime-common --features integrity-test -# we're removing lock file after all chechs are done. Otherwise we may use different +# we're removing lock file after all checks are done. Otherwise we may use different # Substrate/Polkadot/Cumulus commits and our checks will fail rm -f $BRIDGES_FOLDER/Cargo.lock diff --git a/bridges/snowbridge/pallets/ethereum-client/src/lib.rs b/bridges/snowbridge/pallets/ethereum-client/src/lib.rs index fc2ab2fbb58..f57f5199020 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/lib.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/lib.rs @@ -10,7 +10,7 @@ //! //! * [`Call::force_checkpoint`]: Set the initial trusted consensus checkpoint. //! * [`Call::set_operating_mode`]: Set the operating mode of the pallet. Can be used to disable -//! processing of conensus updates. +//! processing of consensus updates. //! //! ## Consensus Updates //! diff --git a/bridges/snowbridge/pallets/ethereum-client/src/tests.rs b/bridges/snowbridge/pallets/ethereum-client/src/tests.rs index 4a7b7b45886..20a184490fd 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/tests.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/tests.rs @@ -249,7 +249,7 @@ pub fn execution_header_pruning() { stored_hashes.push(hash); } - // We should have only stored upto `execution_header_prune_threshold` + // We should have only stored up to `execution_header_prune_threshold` assert_eq!( ExecutionHeaders::::iter().count() as u32, execution_header_prune_threshold diff --git a/bridges/snowbridge/pallets/inbound-queue/fixtures/src/register_token_with_insufficient_fee.rs b/bridges/snowbridge/pallets/inbound-queue/fixtures/src/register_token_with_insufficient_fee.rs index 82ff2283101..dfda0b2b427 100644 --- a/bridges/snowbridge/pallets/inbound-queue/fixtures/src/register_token_with_insufficient_fee.rs +++ b/bridges/snowbridge/pallets/inbound-queue/fixtures/src/register_token_with_insufficient_fee.rs @@ -9,7 +9,7 @@ use snowbridge_beacon_primitives::CompactExecutionHeader; use snowbridge_core::inbound::{Log, Message, Proof}; use sp_std::vec; -pub fn make_register_token_with_infufficient_fee_message() -> InboundQueueFixture { +pub fn make_register_token_with_insufficient_fee_message() -> InboundQueueFixture { InboundQueueFixture { execution_header: CompactExecutionHeader{ parent_hash: hex!("998e81dc6df788a920b67e058fbde0dc3f4ec6f11f3f7cd8c3148e6d99584885").into(), diff --git a/bridges/testing/environments/rococo-westend/rococo.zndsl b/bridges/testing/environments/rococo-westend/rococo.zndsl index 5b49c7c632f..a75286445a2 100644 --- a/bridges/testing/environments/rococo-westend/rococo.zndsl +++ b/bridges/testing/environments/rococo-westend/rococo.zndsl @@ -1,7 +1,7 @@ -Description: Check if the with-Westend GRANPDA pallet was initialized at Rococo BH +Description: Check if the with-Westend GRANDPA pallet was initialized at Rococo BH Network: ./bridge_hub_rococo_local_network.toml Creds: config -# relay is already started - let's wait until with-Westend GRANPDA pallet is initialized at Rococo +# relay is already started - let's wait until with-Westend GRANDPA pallet is initialized at Rococo bridge-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/best-finalized-header-at-bridged-chain.js with "Westend,0" within 400 seconds diff --git a/bridges/testing/environments/rococo-westend/westend.zndsl b/bridges/testing/environments/rococo-westend/westend.zndsl index 07968838852..21d4ebf3b05 100644 --- a/bridges/testing/environments/rococo-westend/westend.zndsl +++ b/bridges/testing/environments/rococo-westend/westend.zndsl @@ -1,6 +1,6 @@ -Description: Check if the with-Rococo GRANPDA pallet was initialized at Westend BH +Description: Check if the with-Rococo GRANDPA pallet was initialized at Westend BH Network: ./bridge_hub_westend_local_network.toml Creds: config -# relay is already started - let's wait until with-Rococo GRANPDA pallet is initialized at Westend +# relay is already started - let's wait until with-Rococo GRANDPA pallet is initialized at Westend bridge-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/best-finalized-header-at-bridged-chain.js with "Rococo,0" within 400 seconds diff --git a/bridges/testing/framework/utils/generate_hex_encoded_call/index.js b/bridges/testing/framework/utils/generate_hex_encoded_call/index.js index 30f89d754ce..c8e361b25a9 100644 --- a/bridges/testing/framework/utils/generate_hex_encoded_call/index.js +++ b/bridges/testing/framework/utils/generate_hex_encoded_call/index.js @@ -126,36 +126,36 @@ if (!process.argv[2] || !process.argv[3]) { } const type = process.argv[2]; -const rpcEnpoint = process.argv[3]; +const rpcEndpoint = process.argv[3]; const output = process.argv[4]; const inputArgs = process.argv.slice(5, process.argv.length); console.log(`Generating hex-encoded call data for:`); console.log(` type: ${type}`); -console.log(` rpcEnpoint: ${rpcEnpoint}`); +console.log(` rpcEndpoint: ${rpcEndpoint}`); console.log(` output: ${output}`); console.log(` inputArgs: ${inputArgs}`); switch (type) { case 'remark-with-event': - remarkWithEvent(rpcEnpoint, output); + remarkWithEvent(rpcEndpoint, output); break; case 'add-exporter-config': - addExporterConfig(rpcEnpoint, output, inputArgs[0], inputArgs[1]); + addExporterConfig(rpcEndpoint, output, inputArgs[0], inputArgs[1]); break; case 'remove-exporter-config': - removeExporterConfig(rpcEnpoint, output, inputArgs[0], inputArgs[1]); + removeExporterConfig(rpcEndpoint, output, inputArgs[0], inputArgs[1]); break; case 'add-universal-alias': - addUniversalAlias(rpcEnpoint, output, inputArgs[0], inputArgs[1]); + addUniversalAlias(rpcEndpoint, output, inputArgs[0], inputArgs[1]); break; case 'add-reserve-location': - addReserveLocation(rpcEnpoint, output, inputArgs[0]); + addReserveLocation(rpcEndpoint, output, inputArgs[0]); break; case 'force-create-asset': - forceCreateAsset(rpcEnpoint, output, inputArgs[0], inputArgs[1], inputArgs[2], inputArgs[3]); + forceCreateAsset(rpcEndpoint, output, inputArgs[0], inputArgs[1], inputArgs[2], inputArgs[3]); break; case 'force-xcm-version': - forceXcmVersion(rpcEnpoint, output, inputArgs[0], inputArgs[1]); + forceXcmVersion(rpcEndpoint, output, inputArgs[0], inputArgs[1]); break; case 'check': console.log(`Checking nodejs installation, if you see this everything is ready!`); diff --git a/bridges/testing/run-tests.sh b/bridges/testing/run-tests.sh index 6149d991265..fd12b57f533 100755 --- a/bridges/testing/run-tests.sh +++ b/bridges/testing/run-tests.sh @@ -30,7 +30,7 @@ done export POLKADOT_SDK_PATH=`realpath $(dirname "$0")/../..` export BRIDGE_TESTS_FOLDER=$POLKADOT_SDK_PATH/bridges/testing/tests -# set pathc to binaries +# set path to binaries if [ "$ZOMBIENET_DOCKER_PATHS" -eq 1 ]; then export POLKADOT_BINARY=/usr/local/bin/polkadot export POLKADOT_PARACHAIN_BINARY=/usr/local/bin/polkadot-parachain diff --git a/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/run.sh b/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/run.sh index 7d5b8d92736..3a604b3876d 100755 --- a/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/run.sh +++ b/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/run.sh @@ -24,7 +24,7 @@ echo -e "Sleeping 90s before starting relayer ...\n" sleep 90 ${BASH_SOURCE%/*}/../../environments/rococo-westend/start_relayer.sh $rococo_dir $westend_dir relayer_pid -# Sometimes the relayer syncs multiple parachain heads in the begining leading to test failures. +# Sometimes the relayer syncs multiple parachain heads in the beginning leading to test failures. # See issue: https://github.com/paritytech/parity-bridges-common/issues/2838. # TODO: Remove this sleep after the issue is fixed. echo -e "Sleeping 180s before runing the tests ...\n" diff --git a/cumulus/client/consensus/common/src/level_monitor.rs b/cumulus/client/consensus/common/src/level_monitor.rs index 270e3f57ae5..fb4b0498f68 100644 --- a/cumulus/client/consensus/common/src/level_monitor.rs +++ b/cumulus/client/consensus/common/src/level_monitor.rs @@ -158,7 +158,7 @@ where /// the limit passed to the constructor. /// /// If the given level is found to have a number of blocks greater than or equal the limit - /// then the limit is enforced by chosing one (or more) blocks to remove. + /// then the limit is enforced by choosing one (or more) blocks to remove. /// /// The removal strategy is driven by the block freshness. /// diff --git a/cumulus/client/consensus/common/src/tests.rs b/cumulus/client/consensus/common/src/tests.rs index bfb95ae388a..7816d3a4c40 100644 --- a/cumulus/client/consensus/common/src/tests.rs +++ b/cumulus/client/consensus/common/src/tests.rs @@ -832,7 +832,7 @@ fn restore_limit_monitor() { .collect::>(); // Scenario before limit application (with B11 imported as best) - // Import order (freshess): B00, B10, B11, B12, B20, B21 + // Import order (freshness): B00, B10, B11, B12, B20, B21 // // B00 --+-- B10 --+-- B20 // | +-- B21 diff --git a/cumulus/client/pov-recovery/src/lib.rs b/cumulus/client/pov-recovery/src/lib.rs index 32aba6c8993..0ca21749c3e 100644 --- a/cumulus/client/pov-recovery/src/lib.rs +++ b/cumulus/client/pov-recovery/src/lib.rs @@ -18,7 +18,7 @@ //! //! A parachain needs to build PoVs that are send to the relay chain to progress. These PoVs are //! erasure encoded and one piece of it is stored by each relay chain validator. As the relay chain -//! decides on which PoV per parachain to include and thus, to progess the parachain it can happen +//! decides on which PoV per parachain to include and thus, to progress the parachain it can happen //! that the block corresponding to this PoV isn't propagated in the parachain network. This can //! have several reasons, either a malicious collator that managed to include its own PoV and //! doesn't want to share it with the rest of the network or maybe a collator went down before it @@ -338,8 +338,8 @@ where let mut blocks_to_delete = vec![hash]; while let Some(delete) = blocks_to_delete.pop() { - if let Some(childs) = self.waiting_for_parent.remove(&delete) { - blocks_to_delete.extend(childs.iter().map(BlockT::hash)); + if let Some(children) = self.waiting_for_parent.remove(&delete) { + blocks_to_delete.extend(children.iter().map(BlockT::hash)); } } self.clear_waiting_recovery(&hash); @@ -448,7 +448,7 @@ where /// Import the given `block`. /// - /// This will also recursivley drain `waiting_for_parent` and import them as well. + /// This will also recursively drain `waiting_for_parent` and import them as well. fn import_block(&mut self, block: Block) { let mut blocks = VecDeque::new(); @@ -495,7 +495,7 @@ where tracing::debug!( target: LOG_TARGET, block_hash = ?hash, - "Cound not recover. Block was never announced as candidate" + "Could not recover. Block was never announced as candidate" ); return }, diff --git a/cumulus/client/relay-chain-rpc-interface/src/reconnecting_ws_client.rs b/cumulus/client/relay-chain-rpc-interface/src/reconnecting_ws_client.rs index b716feef1c9..48d35dd3a55 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/reconnecting_ws_client.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/reconnecting_ws_client.rs @@ -293,7 +293,8 @@ impl ReconnectingWebsocketWorker { /// listeners. If an error occurs during sending, the receiver has been closed and we remove /// the sender from the list. /// - Find a new valid RPC server to connect to in case the websocket connection is terminated. - /// If the worker is not able to connec to an RPC server from the list, the worker shuts down. + /// If the worker is not able to connect to an RPC server from the list, the worker shuts + /// down. pub async fn run(mut self) { let mut pending_requests = FuturesUnordered::new(); diff --git a/cumulus/pallets/parachain-system/src/lib.rs b/cumulus/pallets/parachain-system/src/lib.rs index 1c01ef33c7e..54a1def5960 100644 --- a/cumulus/pallets/parachain-system/src/lib.rs +++ b/cumulus/pallets/parachain-system/src/lib.rs @@ -464,7 +464,7 @@ pub mod pallet { // One complication here, is that the `host_configuration` is updated by an inherent // and those are processed after the block initialization phase. Therefore, we have to // be content only with the configuration as per the previous block. That means that - // the configuration can be either stale (or be abscent altogether in case of the + // the configuration can be either stale (or be absent altogether in case of the // beginning of the chain). // // In order to mitigate this, we do the following. At the time, we are only concerned diff --git a/cumulus/pallets/parachain-system/src/relay_state_snapshot.rs b/cumulus/pallets/parachain-system/src/relay_state_snapshot.rs index 5519d1521ea..60eccfb072f 100644 --- a/cumulus/pallets/parachain-system/src/relay_state_snapshot.rs +++ b/cumulus/pallets/parachain-system/src/relay_state_snapshot.rs @@ -90,7 +90,7 @@ pub enum Error { DmqMqcHead(ReadEntryErr), /// Relay dispatch queue cannot be extracted. RelayDispatchQueueRemainingCapacity(ReadEntryErr), - /// The hrmp inress channel index cannot be extracted. + /// The hrmp ingress channel index cannot be extracted. HrmpIngressChannelIndex(ReadEntryErr), /// The hrmp egress channel index cannot be extracted. HrmpEgressChannelIndex(ReadEntryErr), diff --git a/cumulus/pallets/xcmp-queue/src/lib.rs b/cumulus/pallets/xcmp-queue/src/lib.rs index e92169be16b..b4cd925d540 100644 --- a/cumulus/pallets/xcmp-queue/src/lib.rs +++ b/cumulus/pallets/xcmp-queue/src/lib.rs @@ -462,7 +462,7 @@ impl Pallet { // Max message size refers to aggregates, or pages. Not to individual fragments. let max_message_size = channel_info.max_message_size as usize; let format_size = format.encoded_size(); - // We check the encoded fragment length plus the format size agains the max message size + // We check the encoded fragment length plus the format size against the max message size // because the format is concatenated if a new page is needed. let size_to_check = encoded_fragment .len() diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs index 2acccb9649b..e5378b35f5e 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs @@ -20,7 +20,7 @@ use sp_core::{sr25519, storage::Storage}; // Cumulus use emulated_integration_tests_common::{ accounts, build_genesis_storage, collators, get_account_id_from_seed, - PenpalSiblingSovereigAccount, PenpalTeleportableAssetLocation, RESERVABLE_ASSET_ID, + PenpalSiblingSovereignAccount, PenpalTeleportableAssetLocation, RESERVABLE_ASSET_ID, SAFE_XCM_VERSION, }; use parachains_common::{AccountId, Balance}; @@ -76,7 +76,7 @@ pub fn genesis() -> Storage { // Penpal's teleportable asset representation ( PenpalTeleportableAssetLocation::get(), - PenpalSiblingSovereigAccount::get(), + PenpalSiblingSovereignAccount::get(), true, ED, ), diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs index e30529aff42..219d1306906 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/genesis.rs @@ -20,7 +20,7 @@ use sp_core::{sr25519, storage::Storage}; // Cumulus use emulated_integration_tests_common::{ accounts, build_genesis_storage, collators, get_account_id_from_seed, - PenpalSiblingSovereigAccount, PenpalTeleportableAssetLocation, RESERVABLE_ASSET_ID, + PenpalSiblingSovereignAccount, PenpalTeleportableAssetLocation, RESERVABLE_ASSET_ID, SAFE_XCM_VERSION, }; use parachains_common::{AccountId, Balance}; @@ -72,7 +72,7 @@ pub fn genesis() -> Storage { // Penpal's teleportable asset representation ( PenpalTeleportableAssetLocation::get(), - PenpalSiblingSovereigAccount::get(), + PenpalSiblingSovereignAccount::get(), true, ED, ), diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs index 48901647fd0..d81ab8143dd 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs @@ -31,8 +31,8 @@ pub const PARA_ID_B: u32 = 2001; pub const ED: Balance = penpal_runtime::EXISTENTIAL_DEPOSIT; parameter_types! { - pub PenpalSudoAcccount: AccountId = get_account_id_from_seed::("Alice"); - pub PenpalAssetOwner: AccountId = PenpalSudoAcccount::get(); + pub PenpalSudoAccount: AccountId = get_account_id_from_seed::("Alice"); + pub PenpalAssetOwner: AccountId = PenpalSudoAccount::get(); } pub fn genesis(para_id: u32) -> Storage { @@ -66,7 +66,7 @@ pub fn genesis(para_id: u32) -> Storage { safe_xcm_version: Some(SAFE_XCM_VERSION), ..Default::default() }, - sudo: penpal_runtime::SudoConfig { key: Some(PenpalSudoAcccount::get()) }, + sudo: penpal_runtime::SudoConfig { key: Some(PenpalSudoAccount::get()) }, assets: penpal_runtime::AssetsConfig { assets: vec![( penpal_runtime::xcm_config::TELEPORTABLE_ASSET_ID, diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs index 651b3a52306..0b49c7a3e09 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs @@ -14,7 +14,7 @@ // limitations under the License. mod genesis; -pub use genesis::{genesis, PenpalAssetOwner, PenpalSudoAcccount, ED, PARA_ID_A, PARA_ID_B}; +pub use genesis::{genesis, PenpalAssetOwner, PenpalSudoAccount, ED, PARA_ID_A, PARA_ID_B}; pub use penpal_runtime::xcm_config::{ CustomizableAssetFromSystemAssetHub, LocalTeleportableToAssetHub, XcmConfig, }; diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index 5fc08dff32c..ae69bf991e5 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -114,7 +114,7 @@ where .expect("Bridge message does not exist") .into(); let payload = Vec::::decode(&mut &encoded_payload[..]) - .expect("Decodign XCM message failed"); + .expect("Decoding XCM message failed"); let id: u32 = LaneIdWrapper(*lane).into(); let message = BridgeMessage { id, nonce, payload }; @@ -265,7 +265,7 @@ macro_rules! impl_assert_events_helpers_for_relay_chain { $crate::impls::assert_expected_events!( Self, vec![ - // XCM is successfully received and proccessed + // XCM is successfully received and processed [<$chain RuntimeEvent>]::::MessageQueue($crate::impls::pallet_message_queue::Event::Processed { origin: $crate::impls::AggregateMessageOrigin::Ump($crate::impls::UmpQueueId::Para(id)), weight_used, @@ -343,7 +343,7 @@ macro_rules! impl_hrmp_channels_helpers_for_relay_chain { ::Runtime, >::contains_key(&channel_id); - // Check the HRMP channel has been successfully registrered + // Check the HRMP channel has been successfully registered assert!(hrmp_channel_exist) }); } diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index 40204ca297a..cbde0642f1a 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -67,7 +67,7 @@ parameter_types! { xcm::v3::Junction::GeneralIndex(TELEPORTABLE_ASSET_ID.into()), ] ); - pub PenpalSiblingSovereigAccount: AccountId = Sibling::from(PENPAL_ID).into_account_truncating(); + pub PenpalSiblingSovereignAccount: AccountId = Sibling::from(PENPAL_ID).into_account_truncating(); } /// Helper function to generate a crypto pair from seed diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index 0a5956dedfd..a0738839087 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -1052,7 +1052,7 @@ fn reserve_transfer_native_asset_from_para_to_para_trough_relay() { // fund the Parachain Origin's SA on Relay Chain with the native tokens held in reserve Rococo::fund_accounts(vec![(sov_of_sender_on_relay.into(), amount_to_send * 2)]); - // Init values for Parachain Desitnation + // Init values for Parachain Destination let receiver = PenpalBReceiver::get(); // Init Test diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs index 64ad15ca312..a26dfef8e8e 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs @@ -215,7 +215,7 @@ fn para_to_system_para_assets_sender_assertions(t: ParaToSystemParaTest) { let system_para_native_asset_location = v3::Location::try_from(RelayLocation::get()).expect("conversion works"); let reservable_asset_location = - v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).expect("coversion works"); + v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).expect("conversion works"); PenpalA::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8799))); assert_expected_events!( PenpalA, @@ -246,7 +246,7 @@ fn para_to_system_para_assets_sender_assertions(t: ParaToSystemParaTest) { fn system_para_to_para_assets_receiver_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; let system_para_asset_location = - v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).expect("coversion works"); + v3::Location::try_from(PenpalLocalReservableFromAssetHub::get()).expect("conversion works"); PenpalA::assert_xcmp_queue_success(None); assert_expected_events!( PenpalA, @@ -1054,7 +1054,7 @@ fn reserve_transfer_native_asset_from_para_to_para_trough_relay() { // fund the Parachain Origin's SA on Relay Chain with the native tokens held in reserve Westend::fund_accounts(vec![(sov_of_sender_on_relay.into(), amount_to_send * 2)]); - // Init values for Parachain Desitnation + // Init values for Parachain Destination let receiver = PenpalBReceiver::get(); // Init Test diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs index 1e74d63e1d5..26b82375e07 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs @@ -23,7 +23,7 @@ use rococo_westend_system_emulated_network::BridgeHubRococoParaSender as BridgeH use snowbridge_core::outbound::OperatingMode; use snowbridge_pallet_inbound_queue_fixtures::{ register_token::make_register_token_message, - register_token_with_insufficient_fee::make_register_token_with_infufficient_fee_message, + register_token_with_insufficient_fee::make_register_token_with_insufficient_fee_message, send_token::make_send_token_message, send_token_to_penpal::make_send_token_to_penpal_message, InboundQueueFixture, }; @@ -514,7 +514,7 @@ fn register_weth_token_in_asset_hub_fail_for_insufficient_fee() { type RuntimeEvent = ::RuntimeEvent; // Construct RegisterToken message and sent to inbound queue - let message = make_register_token_with_infufficient_fee_message(); + let message = make_register_token_with_insufficient_fee_message(); send_inbound_message(message).unwrap(); assert_expected_events!( diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index c438361cc17..47c3ed36888 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -192,7 +192,7 @@ pub type ForeignFungiblesTransactor = FungiblesAdapter< LocationToAccountId, // Our chain's account ID type (we can't get away without mentioning it explicitly): AccountId, - // We dont need to check teleports here. + // We don't need to check teleports here. NoChecking, // The account to use for tracking teleports. CheckingAccount, diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs index c993d61545a..7d3ed650e6b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs @@ -185,7 +185,7 @@ pub type ForeignFungiblesTransactor = FungiblesAdapter< LocationToAccountId, // Our chain's account ID type (we can't get away without mentioning it explicitly): AccountId, - // We dont need to check teleports here. + // We don't need to check teleports here. NoChecking, // The account to use for tracking teleports. CheckingAccount, diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs index 3ba9b9587d8..6696cb23223 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -618,7 +618,7 @@ fn test_asset_xcm_take_first_trader_with_refund() { // We actually use half of the weight let weight_used = bought / 2; - // Make sure refurnd works. + // Make sure refund works. let amount_refunded = WeightToFee::weight_to_fee(&(bought - weight_used)); assert_eq!( @@ -745,7 +745,7 @@ fn test_that_buying_ed_refund_does_not_refund_for_take_first_trader() { // Buy weight should work assert_ok!(trader.buy_weight(bought, asset.into(), &ctx)); - // Should return None. We have a specific check making sure we dont go below ED for + // Should return None. We have a specific check making sure we don't go below ED for // drop payment assert_eq!(trader.refund_weight(bought, &ctx), None); diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs index 2f2624d8e52..884b71369e7 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -1120,7 +1120,7 @@ pub fn create_and_manage_foreign_assets_for_local_consensus_parachain_assets_wor AssetId: Clone, AssetIdConverter: MaybeEquivalence, { - // foreign parachain with the same consenus currency as asset + // foreign parachain with the same consensus currency as asset let foreign_asset_id_location = Location::new(1, [Parachain(2222), GeneralIndex(1234567)]); let asset_id = AssetIdConverter::convert(&foreign_asset_id_location).unwrap(); diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs index 1cce3b647cf..0b2364dbb8b 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs @@ -386,7 +386,7 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works< existential_deposit, ); - // create foreign asset for wrapped/derivated representation + // create foreign asset for wrapped/derived representation assert_ok!( >::force_create( RuntimeHelper::::root_origin(), diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs index ad369583f07..cd5f1ad3272 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs @@ -456,7 +456,7 @@ mod benches { [cumulus_pallet_xcmp_queue, XcmpQueue] [pallet_collator_selection, CollatorSelection] // XCM - [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] + [pallet_xcm, PalletXcmExtrinsicsBenchmark::] [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] ); @@ -644,7 +644,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; // This is defined once again in dispatch_benchmark, because list_benchmarks! // and add_benchmarks! are macros exported by define_benchmarks! macros and those types @@ -680,7 +680,7 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; impl pallet_xcm::benchmarking::Config for Runtime { type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< xcm_config::XcmConfig, diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs index c76611ad2a3..e840a40f5ac 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs @@ -344,7 +344,7 @@ parameter_types! { pub const StakingAdminBodyId: BodyId = BodyId::Defense; } -/// We allow Root and the `StakingAdmi` to execute privileged collator selection operations. +/// We allow Root and the `StakingAdmin` to execute privileged collator selection operations. pub type CollatorSelectionUpdateOrigin = EitherOfDiverse< EnsureRoot, EnsureXcm>, @@ -456,7 +456,7 @@ mod benches { [cumulus_pallet_xcmp_queue, XcmpQueue] [pallet_collator_selection, CollatorSelection] // XCM - [pallet_xcm, PalletXcmExtrinsiscsBenchmark::] + [pallet_xcm, PalletXcmExtrinsicsBenchmark::] [pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::generic, XcmGeneric] ); @@ -644,7 +644,7 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; // This is defined once again in dispatch_benchmark, because list_benchmarks! // and add_benchmarks! are macros exported by define_benchmarks! macros and those types @@ -680,7 +680,7 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; impl pallet_xcm::benchmarking::Config for Runtime { type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< xcm_config::XcmConfig, diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index 639bfd95834..7b8e40e0428 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -145,7 +145,7 @@ pub type ForeignFungiblesTransactor = FungiblesAdapter< LocationToAccountId, // Our chain's account ID type (we can't get away without mentioning it explicitly): AccountId, - // We dont need to check teleports here. + // We don't need to check teleports here. NoChecking, // The account to use for tracking teleports. CheckingAccount, diff --git a/cumulus/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs index 9ba7b7876b3..ac9c6b6f978 100644 --- a/cumulus/polkadot-parachain/src/command.rs +++ b/cumulus/polkadot-parachain/src/command.rs @@ -135,7 +135,7 @@ fn runtime(id: &str) -> Runtime { fn load_spec(id: &str) -> std::result::Result, String> { let (id, _, para_id) = extract_parachain_id(id); Ok(match id { - // - Defaul-like + // - Default-like "staging" => Box::new(chain_spec::rococo_parachain::staging_rococo_parachain_local_config()), "tick" => Box::new(GenericChainSpec::from_json_bytes( diff --git a/cumulus/primitives/storage-weight-reclaim/src/lib.rs b/cumulus/primitives/storage-weight-reclaim/src/lib.rs index 5dddc92e395..c09c12d7a0a 100644 --- a/cumulus/primitives/storage-weight-reclaim/src/lib.rs +++ b/cumulus/primitives/storage-weight-reclaim/src/lib.rs @@ -421,7 +421,7 @@ mod tests { .unwrap(); assert_eq!(pre, Some(100)); - // The `CheckWeight` extension will refunt `actual_weight` from `PostDispatchInfo` + // The `CheckWeight` extension will refund `actual_weight` from `PostDispatchInfo` // we always need to call `post_dispatch` to verify that they interoperate correctly. assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); assert_ok!(StorageWeightReclaim::::post_dispatch( @@ -456,7 +456,7 @@ mod tests { .unwrap(); assert_eq!(pre, Some(100)); - // The `CheckWeight` extension will refunt `actual_weight` from `PostDispatchInfo` + // The `CheckWeight` extension will refund `actual_weight` from `PostDispatchInfo` // we always need to call `post_dispatch` to verify that they interoperate correctly. assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); assert_ok!(StorageWeightReclaim::::post_dispatch( @@ -500,7 +500,7 @@ mod tests { &Ok(()) )); // `CheckWeight` gets called after `StorageWeightReclaim` this time. - // The `CheckWeight` extension will refunt `actual_weight` from `PostDispatchInfo` + // The `CheckWeight` extension will refund `actual_weight` from `PostDispatchInfo` // we always need to call `post_dispatch` to verify that they interoperate correctly. assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); @@ -536,7 +536,7 @@ mod tests { &Ok(()) )); // `CheckWeight` gets called after `StorageWeightReclaim` this time. - // The `CheckWeight` extension will refunt `actual_weight` from `PostDispatchInfo` + // The `CheckWeight` extension will refund `actual_weight` from `PostDispatchInfo` // we always need to call `post_dispatch` to verify that they interoperate correctly. assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); diff --git a/cumulus/primitives/timestamp/src/lib.rs b/cumulus/primitives/timestamp/src/lib.rs index 535c4a2a726..e6aba6d0bb7 100644 --- a/cumulus/primitives/timestamp/src/lib.rs +++ b/cumulus/primitives/timestamp/src/lib.rs @@ -22,7 +22,7 @@ //! access to any clock from the runtime the timestamp is always passed as an inherent into the //! runtime. To check this inherent when validating the block, we will use the relay chain slot. As //! the relay chain slot is derived from a timestamp, we can easily convert it back to a timestamp -//! by muliplying it with the slot duration. By comparing the relay chain slot derived timestamp +//! by multiplying it with the slot duration. By comparing the relay chain slot derived timestamp //! with the timestamp we can ensure that the parachain timestamp is reasonable. #![cfg_attr(not(feature = "std"), no_std)] diff --git a/cumulus/primitives/utility/src/lib.rs b/cumulus/primitives/utility/src/lib.rs index abc391bdcb8..d5d411356dc 100644 --- a/cumulus/primitives/utility/src/lib.rs +++ b/cumulus/primitives/utility/src/lib.rs @@ -141,7 +141,7 @@ impl< ) -> Result { log::trace!(target: "xcm::weight", "TakeFirstAssetTrader::buy_weight weight: {:?}, payment: {:?}, context: {:?}", weight, payment, context); - // Make sure we dont enter twice + // Make sure we don't enter twice if self.0.is_some() { return Err(XcmError::NotWithdrawable) } @@ -176,7 +176,7 @@ impl< // Convert to the same kind of asset, with the required fungible balance let required = first.id.clone().into_asset(asset_balance.into()); - // Substract payment + // Subtract payment let unused = payment.checked_sub(required.clone()).map_err(|_| XcmError::TooExpensive)?; // record weight and asset @@ -203,7 +203,7 @@ impl< // Calculate asset_balance // This read should have already be cached in buy_weight - let (asset_balance, outstanding_minus_substracted) = + let (asset_balance, outstanding_minus_subtracted) = FeeCharger::charge_weight_in_fungibles(local_asset_id, weight).ok().map( |asset_balance| { // Require at least a drop of minimum_balance @@ -221,16 +221,15 @@ impl< )?; // Convert balances into u128 - let outstanding_minus_substracted: u128 = - outstanding_minus_substracted.saturated_into(); + let outstanding_minus_subtracted: u128 = outstanding_minus_subtracted.saturated_into(); let asset_balance: u128 = asset_balance.saturated_into(); - // Construct outstanding_concrete_asset with the same location id and substracted + // Construct outstanding_concrete_asset with the same location id and subtracted // balance let outstanding_concrete_asset: Asset = - (id.clone(), outstanding_minus_substracted).into(); + (id.clone(), outstanding_minus_subtracted).into(); - // Substract from existing weight and balance + // Subtract from existing weight and balance weight_outstanding = weight_outstanding.saturating_sub(weight); // Override AssetTraderRefunder @@ -263,9 +262,10 @@ impl< } } -/// XCM fee depositor to which we implement the TakeRevenue trait -/// It receives a Transact implemented argument, a 32 byte convertible acocuntId, and the fee -/// receiver account FungiblesMutateAdapter should be identical to that implemented by WithdrawAsset +/// XCM fee depositor to which we implement the `TakeRevenue` trait. +/// It receives a `Transact` implemented argument and a 32 byte convertible `AccountId`, and the fee +/// receiver account's `FungiblesMutateAdapter` should be identical to that implemented by +/// `WithdrawAsset`. pub struct XcmFeesTo32ByteAccount( PhantomData<(FungiblesMutateAdapter, AccountId, ReceiverAccount)>, ); @@ -763,7 +763,8 @@ mod test_trader { /// Implementation of `xcm_builder::EnsureDelivery` which helps to ensure delivery to the /// parent relay chain. Deposits existential deposit for origin (if needed). /// Deposits estimated fee to the origin account (if needed). -/// Allows to trigger additional logic for specific `ParaId` (e.g. open HRMP channel) (if neeeded). +/// Allows triggering of additional logic for a specific `ParaId` (e.g. to open an HRMP channel) if +/// needed. #[cfg(feature = "runtime-benchmarks")] pub struct ToParentDeliveryHelper( sp_std::marker::PhantomData<(XcmConfig, ExistentialDeposit, PriceForDelivery)>, diff --git a/cumulus/scripts/scale_encode_genesis/index.js b/cumulus/scripts/scale_encode_genesis/index.js index f612e6da79d..c6600e40636 100644 --- a/cumulus/scripts/scale_encode_genesis/index.js +++ b/cumulus/scripts/scale_encode_genesis/index.js @@ -19,14 +19,14 @@ async function connect(endpoint, types = {}) { } if (!process.argv[2] || !process.argv[3]) { - console.log("usage: node generate_keys [rpc enpoint]"); + console.log("usage: node generate_keys [rpc endpoint]"); exit(); } const input = process.argv[2]; const output = process.argv[3]; // default to localhost and the default Substrate port -const rpcEnpoint = process.argv[4] || "ws://localhost:9944"; +const rpcEndpoint = process.argv[4] || "ws://localhost:9944"; console.log("Processing", input, output); fs.readFile(input, "utf8", (err, data) => { @@ -38,8 +38,8 @@ fs.readFile(input, "utf8", (err, data) => { const genesis = JSON.parse(data); console.log("loaded genesis, length = ", genesis.length); - console.log(`Connecting to RPC endpoint: ${rpcEnpoint}`); - connect(rpcEnpoint) + console.log(`Connecting to RPC endpoint: ${rpcEndpoint}`); + connect(rpcEndpoint) .then((api) => { console.log('Connected'); const setStorage = api.tx.system.setStorage(genesis); diff --git a/cumulus/scripts/temp_parachain_types.json b/cumulus/scripts/temp_parachain_types.json index f550a677445..2509d32be9f 100644 --- a/cumulus/scripts/temp_parachain_types.json +++ b/cumulus/scripts/temp_parachain_types.json @@ -54,7 +54,7 @@ "validity_votes": "Vec", "validator_indices": "BitVec" }, - "CandidatePendingAvailablility": { + "CandidatePendingAvailability": { "core": "u32", "descriptor": "CandidateDescriptor", "availability_votes": "BitVec", diff --git a/cumulus/test/runtime/src/lib.rs b/cumulus/test/runtime/src/lib.rs index 8e3569b02a1..5127b63f271 100644 --- a/cumulus/test/runtime/src/lib.rs +++ b/cumulus/test/runtime/src/lib.rs @@ -139,7 +139,7 @@ pub fn native_version() -> NativeVersion { NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } } -/// We assume that ~10% of the block weight is consumed by `on_initalize` handlers. +/// We assume that ~10% of the block weight is consumed by `on_initialize` handlers. /// This is used to limit the maximal weight of a single extrinsic. const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); /// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used diff --git a/cumulus/test/service/benches/validate_block.rs b/cumulus/test/service/benches/validate_block.rs index a614863803e..d95f733969b 100644 --- a/cumulus/test/service/benches/validate_block.rs +++ b/cumulus/test/service/benches/validate_block.rs @@ -47,7 +47,7 @@ fn create_extrinsics( src_accounts: &[sr25519::Pair], dst_accounts: &[sr25519::Pair], ) -> (usize, Vec) { - // Add as many tranfer extrinsics as possible into a single block. + // Add as many transfer extrinsics as possible into a single block. let mut block_builder = BlockBuilderBuilder::new(client) .on_parent_block(client.chain_info().best_hash) .with_parent_block_number(client.chain_info().best_number) diff --git a/cumulus/test/service/src/lib.rs b/cumulus/test/service/src/lib.rs index 3554a383f21..3af3901d175 100644 --- a/cumulus/test/service/src/lib.rs +++ b/cumulus/test/service/src/lib.rs @@ -735,7 +735,7 @@ pub fn node_config( tokio_handle: tokio::runtime::Handle, key: Sr25519Keyring, nodes: Vec, - nodes_exlusive: bool, + nodes_exclusive: bool, para_id: ParaId, is_collator: bool, endowed_accounts: Vec, @@ -759,7 +759,7 @@ pub fn node_config( None, ); - if nodes_exlusive { + if nodes_exclusive { network_config.default_peers_set.reserved_nodes = nodes; network_config.default_peers_set.non_reserved_mode = sc_network::config::NonReservedPeerMode::Deny; diff --git a/docker/dockerfiles/binary_injected.Dockerfile b/docker/dockerfiles/binary_injected.Dockerfile index ac1fd5317c6..c8930bd83f0 100644 --- a/docker/dockerfiles/binary_injected.Dockerfile +++ b/docker/dockerfiles/binary_injected.Dockerfile @@ -2,7 +2,7 @@ FROM docker.io/parity/base-bin # This file allows building a Generic container image # based on one or multiple pre-built Linux binaries. -# Some defaults are set to polkadot but all can be overriden. +# Some defaults are set to polkadot but all can be overridden. SHELL ["/bin/bash", "-c"] diff --git a/docker/scripts/build-injected.sh b/docker/scripts/build-injected.sh index f415cf43c0e..749d0fa335c 100755 --- a/docker/scripts/build-injected.sh +++ b/docker/scripts/build-injected.sh @@ -20,7 +20,7 @@ PROJECT_ROOT=${PROJECT_ROOT:-$(git rev-parse --show-toplevel)} DOCKERFILE=${DOCKERFILE:-docker/dockerfiles/binary_injected.Dockerfile} VERSION_TOML=$(grep "^version " $PROJECT_ROOT/Cargo.toml | grep -oE "([0-9\.]+-?[0-9]+)") -#n The following VAR have default that can be overriden +#n The following VAR have default that can be overridden DOCKER_OWNER=${DOCKER_OWNER:-parity} # We may get 1..n binaries, comma separated diff --git a/docs/sdk/Cargo.toml b/docs/sdk/Cargo.toml index 3f84d45640f..434202ed693 100644 --- a/docs/sdk/Cargo.toml +++ b/docs/sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-sdk-docs" -description = "The one stop shop for developers of the polakdot-sdk" +description = "The one stop shop for developers of the polkadot-sdk" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "paritytech.github.io" repository.workspace = true diff --git a/docs/sdk/src/reference_docs/frame_runtime_upgrades_and_migrations.rs b/docs/sdk/src/reference_docs/frame_runtime_upgrades_and_migrations.rs index 7d870b43221..cbbf611f9dc 100644 --- a/docs/sdk/src/reference_docs/frame_runtime_upgrades_and_migrations.rs +++ b/docs/sdk/src/reference_docs/frame_runtime_upgrades_and_migrations.rs @@ -16,7 +16,7 @@ //! in a process called "Runtime Upgrades". //! //! Forkless runtime upgrades are a defining feature of the Substrate framework. Updating the -//! runtime logic without forking the code base enables your blockchain to seemlessly evolve +//! runtime logic without forking the code base enables your blockchain to seamlessly evolve //! over time in a deterministic, rules-based manner. It also removes ambiguity for node operators //! and other participants in the network about what is the canonical runtime. //! @@ -24,7 +24,7 @@ //! //! ## Performing a Runtime Upgrade //! -//! To upgrade a runtime, an [`Origin`](frame_system::RawOrigin) with the necesarry permissions +//! To upgrade a runtime, an [`Origin`](frame_system::RawOrigin) with the necessary permissions //! (usually via governance) changes the `:code` storage. Usually, this is performed via a call to //! [`set_code`] (or [`set_code_without_checks`]) with the desired new runtime blob, scheduled //! using [`pallet_scheduler`]. @@ -41,7 +41,7 @@ //! //! The typical use case of a migration is to 'migrate' pallet storage from one layout to another, //! for example when the encoding of a storage item is changed. However, they can also execute -//! arbitary logic such as: +//! arbitrary logic such as: //! //! - Calling arbitrary pallet methods //! - Mutating arbitrary on-chain state @@ -88,7 +88,7 @@ //! //! Prior to deploying migrations, it is critical to perform additional checks to ensure that when //! run in our real runtime they will not brick the chain due to: -//! - Panicing +//! - Panicking //! - Touching too many storage keys and resulting in an excessively large PoV //! - Taking too long to execute //! diff --git a/polkadot/cli/src/cli.rs b/polkadot/cli/src/cli.rs index e1bc2309a94..74e19044469 100644 --- a/polkadot/cli/src/cli.rs +++ b/polkadot/cli/src/cli.rs @@ -122,7 +122,7 @@ pub struct RunCmd { /// Overseer message capacity override. /// - /// **Dangerous!** Do not touch unless explicitly adviced to. + /// **Dangerous!** Do not touch unless explicitly advised to. #[arg(long)] pub overseer_channel_capacity_override: Option, diff --git a/polkadot/grafana/README.md b/polkadot/grafana/README.md index 7350001bfa1..e909fdd29a7 100644 --- a/polkadot/grafana/README.md +++ b/polkadot/grafana/README.md @@ -8,7 +8,7 @@ monitor the liveliness and performance of a network and its validators. # How does it work ? Just import the dashboard JSON files from this folder in your Grafana installation. All dashboards are grouped in -folder percategory (like for example `parachains`). The files have been created by Grafana export functionality and +folder per category (like for example `parachains`). The files have been created by Grafana export functionality and follow the data model specified [here](https://grafana.com/docs/grafana/latest/dashboards/json-model/). We aim to keep the dashboards here in sync with the implementation, except dashboards for development and diff --git a/polkadot/node/core/approval-voting/src/approval_db/v1/tests.rs b/polkadot/node/core/approval-voting/src/approval_db/v1/tests.rs index b979cb7ef45..b0966ad01f7 100644 --- a/polkadot/node/core/approval-voting/src/approval_db/v1/tests.rs +++ b/polkadot/node/core/approval-voting/src/approval_db/v1/tests.rs @@ -254,7 +254,7 @@ fn canonicalize_works() { // -> B1 -> C1 -> D1 // A -> B2 -> C2 -> D2 // - // We'll canonicalize C1. Everytning except D1 should disappear. + // We'll canonicalize C1. Everything except D1 should disappear. // // Candidates: // Cand1 in B2 diff --git a/polkadot/node/core/approval-voting/src/approval_db/v2/migration_helpers.rs b/polkadot/node/core/approval-voting/src/approval_db/v2/migration_helpers.rs index df6e4754dbd..1081d79884f 100644 --- a/polkadot/node/core/approval-voting/src/approval_db/v2/migration_helpers.rs +++ b/polkadot/node/core/approval-voting/src/approval_db/v2/migration_helpers.rs @@ -79,7 +79,7 @@ pub fn v1_to_latest(db: Arc, config: Config) -> Result<()> { block.candidates().iter().enumerate() { // Loading the candidate will also perform the conversion to the updated format and - // return that represantation. + // return that representation. if let Some(candidate_entry) = backend .load_candidate_entry_v1(&candidate_hash, candidate_index as CandidateIndex) .map_err(|e| Error::InternalError(e))? diff --git a/polkadot/node/core/approval-voting/src/approval_db/v2/tests.rs b/polkadot/node/core/approval-voting/src/approval_db/v2/tests.rs index 6021b44c276..5fa915add41 100644 --- a/polkadot/node/core/approval-voting/src/approval_db/v2/tests.rs +++ b/polkadot/node/core/approval-voting/src/approval_db/v2/tests.rs @@ -269,7 +269,7 @@ fn canonicalize_works() { // -> B1 -> C1 -> D1 // A -> B2 -> C2 -> D2 // - // We'll canonicalize C1. Everytning except D1 should disappear. + // We'll canonicalize C1. Everything except D1 should disappear. // // Candidates: // Cand1 in B2 diff --git a/polkadot/node/core/approval-voting/src/approval_db/v3/migration_helpers.rs b/polkadot/node/core/approval-voting/src/approval_db/v3/migration_helpers.rs index ad5e89ef3de..d1e7ee08225 100644 --- a/polkadot/node/core/approval-voting/src/approval_db/v3/migration_helpers.rs +++ b/polkadot/node/core/approval-voting/src/approval_db/v3/migration_helpers.rs @@ -60,7 +60,7 @@ pub fn v2_to_latest(db: Arc, config: Config) -> Result<()> { block.candidates().iter().enumerate() { // Loading the candidate will also perform the conversion to the updated format and - // return that represantation. + // return that representation. if let Some(candidate_entry) = backend .load_candidate_entry_v2(&candidate_hash, candidate_index as CandidateIndex) .map_err(|e| Error::InternalError(e))? @@ -104,7 +104,7 @@ pub fn v1_to_latest_sanity_check( for block in all_blocks { for (_core_index, candidate_hash) in block.candidates() { // Loading the candidate will also perform the conversion to the updated format and - // return that represantation. + // return that representation. if let Some(candidate_entry) = backend.load_candidate_entry(&candidate_hash).unwrap() { candidates.insert(candidate_entry.candidate.hash()); } diff --git a/polkadot/node/core/approval-voting/src/approval_db/v3/tests.rs b/polkadot/node/core/approval-voting/src/approval_db/v3/tests.rs index 08c65461bca..7c0cf9d4f7d 100644 --- a/polkadot/node/core/approval-voting/src/approval_db/v3/tests.rs +++ b/polkadot/node/core/approval-voting/src/approval_db/v3/tests.rs @@ -264,7 +264,7 @@ fn canonicalize_works() { // -> B1 -> C1 -> D1 // A -> B2 -> C2 -> D2 // - // We'll canonicalize C1. Everytning except D1 should disappear. + // We'll canonicalize C1. Everything except D1 should disappear. // // Candidates: // Cand1 in B2 diff --git a/polkadot/node/core/approval-voting/src/criteria.rs b/polkadot/node/core/approval-voting/src/criteria.rs index 1ebea2641b6..57c0ac272dc 100644 --- a/polkadot/node/core/approval-voting/src/criteria.rs +++ b/polkadot/node/core/approval-voting/src/criteria.rs @@ -148,7 +148,7 @@ fn relay_vrf_modulo_cores( generate_samples(rand_chacha, num_samples as usize, max_cores as usize) } -/// Generates `num_sumples` randomly from (0..max_cores) range +/// Generates `num_samples` randomly from (0..max_cores) range /// /// Note! The algorithm can't change because validators on the other /// side won't be able to check the assignments until they update. diff --git a/polkadot/node/core/approval-voting/src/import.rs b/polkadot/node/core/approval-voting/src/import.rs index 7a56e9fd112..d34191fba31 100644 --- a/polkadot/node/core/approval-voting/src/import.rs +++ b/polkadot/node/core/approval-voting/src/import.rs @@ -91,7 +91,7 @@ enum ImportedBlockInfoError { #[error(transparent)] RuntimeError(RuntimeApiError), - #[error("future cancalled while requesting {0}")] + #[error("future cancelled while requesting {0}")] FutureCancelled(&'static str, futures::channel::oneshot::Canceled), #[error(transparent)] diff --git a/polkadot/node/core/approval-voting/src/lib.rs b/polkadot/node/core/approval-voting/src/lib.rs index 1d7ab3eee21..1a62c9ee55e 100644 --- a/polkadot/node/core/approval-voting/src/lib.rs +++ b/polkadot/node/core/approval-voting/src/lib.rs @@ -1850,7 +1850,7 @@ async fn get_approval_signatures_for_candidate( gum::trace!( target: LOG_TARGET, ?candidate_hash, - "Spawning task for fetching sinatures from approval-distribution" + "Spawning task for fetching signatures from approval-distribution" ); ctx.spawn("get-approval-signatures", Box::pin(get_approvals)) } diff --git a/polkadot/node/core/approval-voting/src/tests.rs b/polkadot/node/core/approval-voting/src/tests.rs index c9053232a4c..a3013eab46d 100644 --- a/polkadot/node/core/approval-voting/src/tests.rs +++ b/polkadot/node/core/approval-voting/src/tests.rs @@ -3154,7 +3154,7 @@ where // starting configuration. The relevant ticks (all scheduled wakeups) are printed after no further // ticks are scheduled. To create a valid test, a prefix of the relevant ticks should be included // in the final test configuration, ending at the tick with the desired inputs to -// should_trigger_assignemnt. +// should_trigger_assignment. async fn step_until_done(clock: &MockClock) { let mut relevant_ticks = Vec::new(); loop { @@ -3837,7 +3837,7 @@ fn test_approval_is_sent_on_max_approval_coalesce_count() { async fn handle_approval_on_max_coalesce_count( virtual_overseer: &mut VirtualOverseer, - candidate_indicies: Vec, + candidate_indices: Vec, ) { assert_matches!( overseer_recv(virtual_overseer).await, @@ -3845,16 +3845,16 @@ async fn handle_approval_on_max_coalesce_count( _, c_indices, )) => { - assert_eq!(TryInto::::try_into(candidate_indicies.clone()).unwrap(), c_indices); + assert_eq!(TryInto::::try_into(candidate_indices.clone()).unwrap(), c_indices); } ); - for _ in &candidate_indicies { + for _ in &candidate_indices { recover_available_data(virtual_overseer).await; fetch_validation_code(virtual_overseer).await; } - for _ in &candidate_indicies { + for _ in &candidate_indices { assert_matches!( overseer_recv(virtual_overseer).await, AllMessages::CandidateValidation(CandidateValidationMessage::ValidateFromExhaustive{exec_kind, response_sender, ..}) if exec_kind == PvfExecKind::Approval => { @@ -3885,7 +3885,7 @@ async fn handle_approval_on_max_coalesce_count( assert_matches!( overseer_recv(virtual_overseer).await, AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeApproval(vote)) => { - assert_eq!(TryInto::::try_into(candidate_indicies).unwrap(), vote.candidate_indices); + assert_eq!(TryInto::::try_into(candidate_indices).unwrap(), vote.candidate_indices); } ); @@ -3895,7 +3895,7 @@ async fn handle_approval_on_max_coalesce_count( async fn handle_approval_on_max_wait_time( virtual_overseer: &mut VirtualOverseer, - candidate_indicies: Vec, + candidate_indices: Vec, clock: Box, ) { const TICK_NOW_BEGIN: u64 = 1; @@ -3909,16 +3909,16 @@ async fn handle_approval_on_max_wait_time( _, c_indices, )) => { - assert_eq!(TryInto::::try_into(candidate_indicies.clone()).unwrap(), c_indices); + assert_eq!(TryInto::::try_into(candidate_indices.clone()).unwrap(), c_indices); } ); - for _ in &candidate_indicies { + for _ in &candidate_indices { recover_available_data(virtual_overseer).await; fetch_validation_code(virtual_overseer).await; } - for _ in &candidate_indicies { + for _ in &candidate_indices { assert_matches!( overseer_recv(virtual_overseer).await, AllMessages::CandidateValidation(CandidateValidationMessage::ValidateFromExhaustive{exec_kind, response_sender, ..}) if exec_kind == PvfExecKind::Approval => { @@ -3978,7 +3978,7 @@ async fn handle_approval_on_max_wait_time( assert_matches!( overseer_recv(virtual_overseer).await, AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeApproval(vote)) => { - assert_eq!(TryInto::::try_into(candidate_indicies).unwrap(), vote.candidate_indices); + assert_eq!(TryInto::::try_into(candidate_indices).unwrap(), vote.candidate_indices); } ); @@ -4319,7 +4319,7 @@ fn subsystem_relaunches_approval_work_on_restart() { virtual_overseer }); - // Restart a new approval voting subsystem with the same database and major syncing true untill + // Restart a new approval voting subsystem with the same database and major syncing true until // the last leaf. let config = HarnessConfigBuilder::default().backend(store_clone).major_syncing(true).build(); diff --git a/polkadot/node/core/approval-voting/src/time.rs b/polkadot/node/core/approval-voting/src/time.rs index 99dfbe07678..5c3e7e85a17 100644 --- a/polkadot/node/core/approval-voting/src/time.rs +++ b/polkadot/node/core/approval-voting/src/time.rs @@ -126,13 +126,13 @@ impl DelayedApprovalTimer { /// no additional timer is started. pub(crate) fn maybe_arm_timer( &mut self, - wait_untill: Tick, + wait_until: Tick, clock: &dyn Clock, block_hash: Hash, validator_index: ValidatorIndex, ) { if self.blocks.insert(block_hash) { - let clock_wait = clock.wait(wait_untill); + let clock_wait = clock.wait(wait_until); self.timers.push(Box::pin(async move { clock_wait.await; (block_hash, validator_index) diff --git a/polkadot/node/core/av-store/src/lib.rs b/polkadot/node/core/av-store/src/lib.rs index ef7dcecac07..68db4686a97 100644 --- a/polkadot/node/core/av-store/src/lib.rs +++ b/polkadot/node/core/av-store/src/lib.rs @@ -1218,7 +1218,7 @@ fn process_message( // tx channel is dropped and that error is caught by the caller subsystem. // // We bubble up the specific error here so `av-store` logs still tell what - // happend. + // happened. return Err(e.into()) }, } diff --git a/polkadot/node/core/backing/src/lib.rs b/polkadot/node/core/backing/src/lib.rs index 532ae2bd7cb..4b6beb5592e 100644 --- a/polkadot/node/core/backing/src/lib.rs +++ b/polkadot/node/core/backing/src/lib.rs @@ -292,7 +292,7 @@ struct State { /// Cache the per-session Validator->Group mapping. validator_to_group_cache: LruMap>>>, - /// A cloneable sender which is dispatched to background candidate validation tasks to inform + /// A clonable sender which is dispatched to background candidate validation tasks to inform /// the main task of the result. background_validation_tx: mpsc::Sender<(Hash, ValidatedCandidateCommand)>, /// The handle to the keystore used for signing. diff --git a/polkadot/node/core/candidate-validation/src/lib.rs b/polkadot/node/core/candidate-validation/src/lib.rs index 8237137fdca..ec24434db24 100644 --- a/polkadot/node/core/candidate-validation/src/lib.rs +++ b/polkadot/node/core/candidate-validation/src/lib.rs @@ -617,7 +617,7 @@ async fn validate_candidate_exhaustive( Err(e) => { gum::info!(target: LOG_TARGET, ?para_id, err=?e, "Invalid candidate (validation code)"); - // Code already passed pre-checking, if decompression fails now this most likley means + // Code already passed pre-checking, if decompression fails now this most likely means // some local corruption happened. return Err(ValidationFailed("Code decompression failed".to_string())) }, diff --git a/polkadot/node/core/chain-selection/src/lib.rs b/polkadot/node/core/chain-selection/src/lib.rs index aa5bb9548ad..6f864fefb61 100644 --- a/polkadot/node/core/chain-selection/src/lib.rs +++ b/polkadot/node/core/chain-selection/src/lib.rs @@ -51,7 +51,7 @@ type Timestamp = u64; // If a block isn't approved in 120 seconds, nodes will abandon it // and begin building on another chain. const STAGNANT_TIMEOUT: Timestamp = 120; -// Delay prunning of the stagnant keys in prune only mode by 25 hours to avoid interception with the +// Delay pruning of the stagnant keys in prune only mode by 25 hours to avoid interception with the // finality const STAGNANT_PRUNE_DELAY: Timestamp = 25 * 60 * 60; // Maximum number of stagnant entries cleaned during one `STAGNANT_TIMEOUT` iteration @@ -237,7 +237,7 @@ impl Clock for SystemClock { // // The exact time that a block becomes stagnant in the local node is always expected // to differ from other nodes due to network asynchrony and delays in block propagation. - // Non-monotonicity exarcerbates that somewhat, but not meaningfully. + // Non-monotonicity exacerbates that somewhat, but not meaningfully. match SystemTime::now().duration_since(UNIX_EPOCH) { Ok(d) => d.as_secs(), diff --git a/polkadot/node/core/chain-selection/src/tests.rs b/polkadot/node/core/chain-selection/src/tests.rs index cf021c0efeb..bc998f268a0 100644 --- a/polkadot/node/core/chain-selection/src/tests.rs +++ b/polkadot/node/core/chain-selection/src/tests.rs @@ -406,7 +406,7 @@ async fn import_chains_into_empty( // some pre-blocks may need to be supplied to answer ancestry requests // that gather batches beyond the beginning of the new chain. // pre-blocks are those already known by the subsystem, however, -// the subsystem has no way of knowin that until requesting ancestry. +// the subsystem has no way of knowing that until requesting ancestry. async fn import_all_blocks_into( virtual_overseer: &mut VirtualOverseer, backend: &TestBackend, @@ -1300,7 +1300,7 @@ fn finalize_erases_unviable_from_one_but_not_all_reverts() { // F <- A1 <- A2 <- A3 // // A3 reverts A2 and A1. - // Finalize A1. A2 is stil unviable. + // Finalize A1. A2 is still unviable. let (a3_hash, chain_a) = construct_chain_on_base(vec![1, 2, 3], finalized_number, finalized_hash, |h| { diff --git a/polkadot/node/core/dispute-coordinator/src/db/v1.rs b/polkadot/node/core/dispute-coordinator/src/db/v1.rs index f0f17d2325d..4950765cf51 100644 --- a/polkadot/node/core/dispute-coordinator/src/db/v1.rs +++ b/polkadot/node/core/dispute-coordinator/src/db/v1.rs @@ -341,7 +341,7 @@ pub(crate) fn note_earliest_session( let lower_bound = (new_earliest_session, CandidateHash(Hash::repeat_byte(0x00))); let new_recent_disputes = recent_disputes.split_off(&lower_bound); - // Any remanining disputes are considered ancient and must be pruned. + // Any remaining disputes are considered ancient and must be pruned. let pruned_disputes = recent_disputes; if pruned_disputes.len() != 0 { diff --git a/polkadot/node/core/dispute-coordinator/src/lib.rs b/polkadot/node/core/dispute-coordinator/src/lib.rs index 4b511e7430a..daa384b36ff 100644 --- a/polkadot/node/core/dispute-coordinator/src/lib.rs +++ b/polkadot/node/core/dispute-coordinator/src/lib.rs @@ -462,7 +462,7 @@ async fn wait_for_first_leaf(ctx: &mut Context) -> Result { // Rare case where same candidate was present on multiple heights, but all are // pruned at the same time. This candidate was already pruned in the previous - // occurence so it is skipped now. + // occurrence so it is skipped now. }, Entry::Occupied(mut e) => { let mut blocks_including = std::mem::take(e.get_mut()); diff --git a/polkadot/node/core/dispute-coordinator/src/scraping/tests.rs b/polkadot/node/core/dispute-coordinator/src/scraping/tests.rs index 748f9a16f49..726dda596d7 100644 --- a/polkadot/node/core/dispute-coordinator/src/scraping/tests.rs +++ b/polkadot/node/core/dispute-coordinator/src/scraping/tests.rs @@ -542,8 +542,8 @@ fn scraper_handles_backed_but_not_included_candidate() { } #[test] -fn scraper_handles_the_same_candidate_incuded_in_two_different_block_heights() { - // Same candidate will be inclued in these two leaves +fn scraper_handles_the_same_candidate_included_in_two_different_block_heights() { + // Same candidate will be included in these two leaves let test_targets = vec![2, 3]; // How many blocks should we skip before sending a leaf update. diff --git a/polkadot/node/core/dispute-coordinator/src/tests.rs b/polkadot/node/core/dispute-coordinator/src/tests.rs index 0360e357bee..7c1f4ff241d 100644 --- a/polkadot/node/core/dispute-coordinator/src/tests.rs +++ b/polkadot/node/core/dispute-coordinator/src/tests.rs @@ -2226,7 +2226,7 @@ fn resume_dispute_without_local_statement() { test_state }) }) - // Alice should send a DisputeParticiationMessage::Participate on restart since she has no + // Alice should send a DisputeParticipationMessage::Participate on restart since she has no // local statement for the active dispute. .resume(|mut test_state, mut virtual_overseer| { Box::pin(async move { @@ -2390,7 +2390,7 @@ fn resume_dispute_with_local_statement() { test_state }) }) - // Alice should not send a DisputeParticiationMessage::Participate on restart since she has a + // Alice should not send a DisputeParticipationMessage::Participate on restart since she has a // local statement for the active dispute, instead she should try to (re-)send her vote. .resume(|mut test_state, mut virtual_overseer| { let candidate_receipt = make_valid_candidate_receipt(); @@ -2495,7 +2495,7 @@ fn resume_dispute_without_local_statement_or_local_key() { test_state }) }) - // Two should not send a DisputeParticiationMessage::Participate on restart since she is no + // Two should not send a DisputeParticipationMessage::Participate on restart since she is no // validator in that dispute. .resume(|mut test_state, mut virtual_overseer| { Box::pin(async move { diff --git a/polkadot/node/core/provisioner/src/disputes/prioritized_selection/mod.rs b/polkadot/node/core/provisioner/src/disputes/prioritized_selection/mod.rs index cb55ce39bc8..d7a5a811336 100644 --- a/polkadot/node/core/provisioner/src/disputes/prioritized_selection/mod.rs +++ b/polkadot/node/core/provisioner/src/disputes/prioritized_selection/mod.rs @@ -52,7 +52,7 @@ pub const MAX_DISPUTE_VOTES_FORWARDED_TO_RUNTIME: usize = 200; /// `dispute-coordinator`. /// /// This value should be less than `MAX_DISPUTE_VOTES_FORWARDED_TO_RUNTIME`. Increase it in case -/// `provisioner` sends too many `QueryCandidateVotes` messages to `dispite-coordinator`. +/// `provisioner` sends too many `QueryCandidateVotes` messages to `dispute-coordinator`. #[cfg(not(test))] const VOTES_SELECTION_BATCH_SIZE: usize = 1_100; #[cfg(test)] diff --git a/polkadot/node/core/pvf-checker/src/tests.rs b/polkadot/node/core/pvf-checker/src/tests.rs index b0401ecdc3b..b2365fe53e5 100644 --- a/polkadot/node/core/pvf-checker/src/tests.rs +++ b/polkadot/node/core/pvf-checker/src/tests.rs @@ -39,8 +39,8 @@ use std::{collections::HashMap, sync::Arc, time::Duration}; type VirtualOverseer = TestSubsystemContextHandle; -fn dummy_validation_code_hash(descriminator: u8) -> ValidationCodeHash { - ValidationCode(vec![descriminator]).hash() +fn dummy_validation_code_hash(discriminator: u8) -> ValidationCodeHash { + ValidationCode(vec![discriminator]).hash() } struct StartsNewSession { @@ -511,7 +511,7 @@ fn reactivating_pvf_leads_to_second_check() { .reply(PreCheckOutcome::Valid); test_state.expect_submit_vote(&mut handle).await.reply_ok(); - // Now activate a descdedant leaf, where the PVF is not present. + // Now activate a descendant leaf, where the PVF is not present. test_state .active_leaves_update( &mut handle, diff --git a/polkadot/node/core/pvf/common/src/pvf.rs b/polkadot/node/core/pvf/common/src/pvf.rs index 3f5b4d7ca70..340dffe07c3 100644 --- a/polkadot/node/core/pvf/common/src/pvf.rs +++ b/polkadot/node/core/pvf/common/src/pvf.rs @@ -85,9 +85,9 @@ impl PvfPrepData { /// Creates a structure for tests. #[cfg(feature = "test-utils")] pub fn from_discriminator_and_timeout(num: u32, timeout: Duration) -> Self { - let descriminator_buf = num.to_le_bytes().to_vec(); + let discriminator_buf = num.to_le_bytes().to_vec(); Self::from_code( - descriminator_buf, + discriminator_buf, ExecutorParams::default(), timeout, PrepareJobKind::Compilation, diff --git a/polkadot/node/core/pvf/src/host.rs b/polkadot/node/core/pvf/src/host.rs index 8ec46f4b08f..59d5a7e20a8 100644 --- a/polkadot/node/core/pvf/src/host.rs +++ b/polkadot/node/core/pvf/src/host.rs @@ -917,7 +917,7 @@ async fn sweeper_task(mut sweeper_rx: mpsc::Receiver) { gum::trace!( target: LOG_TARGET, ?result, - "Sweeped the artifact file {}", + "Swept the artifact file {}", condemned.display(), ); }, diff --git a/polkadot/node/core/pvf/src/priority.rs b/polkadot/node/core/pvf/src/priority.rs index d4bd49eaee8..d1ef9c604b1 100644 --- a/polkadot/node/core/pvf/src/priority.rs +++ b/polkadot/node/core/pvf/src/priority.rs @@ -29,7 +29,7 @@ pub enum Priority { } impl Priority { - /// Returns `true` if `self` is `Crticial` + /// Returns `true` if `self` is `Critical` pub fn is_critical(self) -> bool { self == Priority::Critical } diff --git a/polkadot/node/core/pvf/src/worker_interface.rs b/polkadot/node/core/pvf/src/worker_interface.rs index ad9f0294c09..93fffc80662 100644 --- a/polkadot/node/core/pvf/src/worker_interface.rs +++ b/polkadot/node/core/pvf/src/worker_interface.rs @@ -130,11 +130,11 @@ where fn make_tmppath(prefix: &str, dir: &Path) -> PathBuf { use rand::distributions::Alphanumeric; - const DESCRIMINATOR_LEN: usize = 10; + const DISCRIMINATOR_LEN: usize = 10; - let mut buf = Vec::with_capacity(prefix.len() + DESCRIMINATOR_LEN); + let mut buf = Vec::with_capacity(prefix.len() + DISCRIMINATOR_LEN); buf.extend(prefix.as_bytes()); - buf.extend(rand::thread_rng().sample_iter(&Alphanumeric).take(DESCRIMINATOR_LEN)); + buf.extend(rand::thread_rng().sample_iter(&Alphanumeric).take(DISCRIMINATOR_LEN)); let s = std::str::from_utf8(&buf) .expect("the string is collected from a valid utf-8 sequence; qed"); diff --git a/polkadot/node/core/pvf/tests/it/main.rs b/polkadot/node/core/pvf/tests/it/main.rs index cdfbcd8e578..16ef23c69ca 100644 --- a/polkadot/node/core/pvf/tests/it/main.rs +++ b/polkadot/node/core/pvf/tests/it/main.rs @@ -543,9 +543,9 @@ async fn all_security_features_work() { // artifacts cache existing. #[cfg(all(feature = "ci-only-tests", target_os = "linux"))] #[tokio::test] -async fn nonexistant_cache_dir() { +async fn nonexistent_cache_dir() { let host = TestHost::new_with_config(|cfg| { - cfg.cache_path = cfg.cache_path.join("nonexistant_cache_dir"); + cfg.cache_path = cfg.cache_path.join("nonexistent_cache_dir"); }) .await; diff --git a/polkadot/node/core/runtime-api/src/tests.rs b/polkadot/node/core/runtime-api/src/tests.rs index fefd2d3f862..b51682aa0f4 100644 --- a/polkadot/node/core/runtime-api/src/tests.rs +++ b/polkadot/node/core/runtime-api/src/tests.rs @@ -299,12 +299,12 @@ impl RuntimeApiSubsystemClient for MockSubsystemClient { #[test] fn requests_authorities() { let (ctx, mut ctx_handle) = make_subsystem_context(TaskExecutor::new()); - let substem_client = Arc::new(MockSubsystemClient::default()); + let subsystem_client = Arc::new(MockSubsystemClient::default()); let relay_parent = [1; 32].into(); let spawner = sp_core::testing::TaskExecutor::new(); let subsystem = - RuntimeApiSubsystem::new(substem_client.clone(), Metrics(None), SpawnGlue(spawner)); + RuntimeApiSubsystem::new(subsystem_client.clone(), Metrics(None), SpawnGlue(spawner)); let subsystem_task = run(ctx, subsystem).map(|x| x.unwrap()); let test_task = async move { let (tx, rx) = oneshot::channel(); @@ -315,7 +315,7 @@ fn requests_authorities() { }) .await; - assert_eq!(rx.await.unwrap().unwrap(), substem_client.authorities); + assert_eq!(rx.await.unwrap().unwrap(), subsystem_client.authorities); ctx_handle.send(FromOrchestra::Signal(OverseerSignal::Conclude)).await; }; @@ -1042,7 +1042,7 @@ fn requests_submit_pvf_check_statement() { let _ = rx.await.unwrap().unwrap(); assert_eq!( - &*subsystem_client.submitted_pvf_check_statement.lock().expect("poisened mutex"), + &*subsystem_client.submitted_pvf_check_statement.lock().expect("poisoned mutex"), &[(stmt.clone(), sig.clone()), (stmt.clone(), sig.clone())] ); diff --git a/polkadot/node/jaeger/src/spans.rs b/polkadot/node/jaeger/src/spans.rs index 4038d41344f..4816fccf3b9 100644 --- a/polkadot/node/jaeger/src/spans.rs +++ b/polkadot/node/jaeger/src/spans.rs @@ -70,7 +70,7 @@ //! let root_span = //! jaeger::Span::new(relay_parent, "root_of_aaall_spans"); //! -//! // the prefered way of adding additional delayed information: +//! // the preferred way of adding additional delayed information: //! let span = root_span.child("inner"); //! //! // ... more operations ... diff --git a/polkadot/node/malus/README.md b/polkadot/node/malus/README.md index e0c7893a753..25453a1980e 100644 --- a/polkadot/node/malus/README.md +++ b/polkadot/node/malus/README.md @@ -18,7 +18,7 @@ defined in the [(DSL[(**D**omain **S**pecific **L**anguage)]) doc](https://parit ## Usage -> Assumes you already gained permissiones, ping in element `@javier:matrix.parity.io` to get access. +> Assumes you already gained permissions, ping in element `@javier:matrix.parity.io` to get access. > and you have cloned the [zombienet][zombienet] repo. To launch a test case in the development cluster use (e.g. for the ./node/malus/integrationtests/0001-dispute-valid-block.toml): diff --git a/polkadot/node/network/approval-distribution/src/lib.rs b/polkadot/node/network/approval-distribution/src/lib.rs index f4e40270160..d360a18423e 100644 --- a/polkadot/node/network/approval-distribution/src/lib.rs +++ b/polkadot/node/network/approval-distribution/src/lib.rs @@ -230,7 +230,7 @@ impl ApprovalEntry { Ok(()) } - // Get the assignment certiticate and claimed candidates. + // Get the assignment certificate and claimed candidates. pub fn assignment(&self) -> (IndirectAssignmentCertV2, CandidateBitfield) { (self.assignment.clone(), self.assignment_claimed_candidates.clone()) } @@ -404,7 +404,7 @@ impl Knowledge { }, }; - // In case of succesful insertion of multiple candidate assignments create additional + // In case of successful insertion of multiple candidate assignments create additional // entries for each assigned candidate. This fakes knowledge of individual assignments, but // we need to share the same `MessageSubject` with the followup approval candidate index. if kind == MessageKind::Assignment && success && message.1.count_ones() > 1 { @@ -1897,10 +1897,10 @@ impl State { _ => break, }; - // Any peer which is in the `known_by` see and we know its peer_id authorithy id + // Any peer which is in the `known_by` see and we know its peer_id authority id // mapping has already been sent all messages it's meant to get for that block and // all in-scope prior blocks. In case, we just learnt about its peer_id - // authorithy-id mapping we have to retry sending the messages that should be sent + // authority-id mapping we have to retry sending the messages that should be sent // to it for all un-finalized blocks. if entry.known_by.contains_key(&peer_id) && !retry_known_blocks { break @@ -2199,7 +2199,7 @@ impl State { sanitized_assignments } - // Filter out obviously invalid candidate indicies. + // Filter out obviously invalid candidate indices. async fn sanitize_v1_approvals( &mut self, peer_id: PeerId, @@ -2226,7 +2226,7 @@ impl State { sanitized_approvals } - // Filter out obviously invalid candidate indicies. + // Filter out obviously invalid candidate indices. async fn sanitize_v2_approvals( &mut self, peer_id: PeerId, @@ -2260,7 +2260,7 @@ impl State { // The modifier accepts as inputs the current required-routing state, whether // the message is locally originating, and the validator index of the message issuer. // -// Then, if the topology is known, this progates messages to all peers in the required +// Then, if the topology is known, this propagates messages to all peers in the required // routing set which are aware of the block. Peers which are unaware of the block // will have the message sent when it enters their view in `unify_with_peer`. // @@ -2440,7 +2440,7 @@ impl ApprovalDistribution { gum::trace!(target: LOG_TARGET, "active leaves signal (ignored)"); // the relay chain blocks relevant to the approval subsystems // are those that are available, but not finalized yet - // actived and deactivated heads hence are irrelevant to this subsystem, other than + // activated and deactivated heads hence are irrelevant to this subsystem, other than // for tracing purposes. if let Some(activated) = update.activated { let head = activated.hash; diff --git a/polkadot/node/network/approval-distribution/src/metrics.rs b/polkadot/node/network/approval-distribution/src/metrics.rs index 0642b1b2e0c..60c7f2f6d3b 100644 --- a/polkadot/node/network/approval-distribution/src/metrics.rs +++ b/polkadot/node/network/approval-distribution/src/metrics.rs @@ -299,7 +299,7 @@ impl MetricsTrait for Metrics { prometheus::CounterVec::new( prometheus::Opts::new( "polkadot_parachain_assignments_received_result", - "Result of a processed assignement", + "Result of a processed assignment", ), &["status"] )?, diff --git a/polkadot/node/network/approval-distribution/src/tests.rs b/polkadot/node/network/approval-distribution/src/tests.rs index 6c88dd53ad3..3159fe2ae5e 100644 --- a/polkadot/node/network/approval-distribution/src/tests.rs +++ b/polkadot/node/network/approval-distribution/src/tests.rs @@ -394,7 +394,7 @@ fn try_import_the_same_assignment() { setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V1).await; setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V1).await; - // Set up a gossip topology, where a, b, c and d are topology neighboors to the node under + // Set up a gossip topology, where a, b, c and d are topology neighbors to the node under // testing. let peers_with_optional_peer_id = peers .iter() @@ -491,7 +491,7 @@ fn try_import_the_same_assignment_v2() { setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V3).await; setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V3).await; - // Set up a gossip topology, where a, b, c and d are topology neighboors to the node under + // Set up a gossip topology, where a, b, c and d are topology neighbors to the node under // testing. let peers_with_optional_peer_id = peers .iter() @@ -744,7 +744,7 @@ fn peer_sending_us_the_same_we_just_sent_them_is_ok() { .iter() .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) .collect_vec(); - // Setup a topology where peer_a is neigboor to current node. + // Setup a topology where peer_a is neighbor to current node. setup_gossip_topology( overseer, make_gossip_topology(1, &peers_with_optional_peer_id, &[0], &[2], 1), @@ -850,7 +850,7 @@ fn import_approval_happy_path_v1_v2_peers() { .iter() .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) .collect_vec(); - // Set up a gossip topology, where a, b, and c are topology neighboors to the node. + // Set up a gossip topology, where a, b, and c are topology neighbors to the node. setup_gossip_topology( overseer, make_gossip_topology(1, &peers_with_optional_peer_id, &[0, 1], &[2, 4], 3), @@ -972,7 +972,7 @@ fn import_approval_happy_path_v2() { .iter() .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) .collect_vec(); - // Set up a gossip topology, where a, b, and c are topology neighboors to the node. + // Set up a gossip topology, where a, b, and c are topology neighbors to the node. setup_gossip_topology( overseer, make_gossip_topology(1, &peers_with_optional_peer_id, &[0, 1], &[2, 4], 3), @@ -1083,7 +1083,7 @@ fn multiple_assignments_covered_with_one_approval_vote() { .iter() .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) .collect_vec(); - // Set up a gossip topology, where a, b, and c, d are topology neighboors to the node. + // Set up a gossip topology, where a, b, and c, d are topology neighbors to the node. setup_gossip_topology( overseer, make_gossip_topology(1, &peers_with_optional_peer_id, &[0, 1], &[2, 4], 3), @@ -1273,7 +1273,7 @@ fn unify_with_peer_multiple_assignments_covered_with_one_approval_vote() { .iter() .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) .collect_vec(); - // Set up a gossip topology, where a, b, and c, d are topology neighboors to the node. + // Set up a gossip topology, where a, b, and c, d are topology neighbors to the node. setup_gossip_topology( overseer, make_gossip_topology(1, &peers_with_optional_peer_id, &[0, 1], &[2, 4], 3), @@ -1631,7 +1631,7 @@ fn update_peer_view() { .iter() .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) .collect_vec(); - // Setup a topology where peer_a is neigboor to current node. + // Setup a topology where peer_a is neighbor to current node. setup_gossip_topology( overseer, make_gossip_topology(1, &peers_with_optional_peer_id, &[0], &[2], 1), @@ -1758,7 +1758,7 @@ fn update_peer_view() { assert!(state.blocks.get(&hash_c).unwrap().known_by.get(peer).is_none()); } -// Tests that updating the known peer_id for a given authorithy updates the topology +// Tests that updating the known peer_id for a given authority updates the topology // and sends the required messages #[test] fn update_peer_authority_id() { @@ -1770,9 +1770,9 @@ fn update_peer_authority_id() { let neighbour_x_index = 0; let neighbour_y_index = 2; let local_index = 1; - // X neighbour, we simulate that PeerId is not known in the beginining. + // X neighbour, we simulate that PeerId is not known in the beginning. let neighbour_x = peers.get(neighbour_x_index).unwrap().0; - // Y neighbour, we simulate that PeerId is not known in the beginining. + // Y neighbour, we simulate that PeerId is not known in the beginning. let neighbour_y = peers.get(neighbour_y_index).unwrap().0; let _state = test_harness(State::default(), |mut virtual_overseer| async move { @@ -1814,7 +1814,7 @@ fn update_peer_authority_id() { }) .collect_vec(); - // Setup a topology where peer_a is neigboor to current node. + // Setup a topology where peer_a is neighbor to current node. setup_gossip_topology( overseer, make_gossip_topology( @@ -2053,7 +2053,7 @@ fn sends_assignments_even_when_state_is_approved() { .iter() .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) .collect_vec(); - // Setup a topology where peer_a is neigboor to current node. + // Setup a topology where peer_a is neighbor to current node. setup_gossip_topology( overseer, make_gossip_topology(1, &peers_with_optional_peer_id, &[0], &[2], 1), @@ -2125,7 +2125,7 @@ fn sends_assignments_even_when_state_is_approved() { } /// Same as `sends_assignments_even_when_state_is_approved_v2` but with `VRFModuloCompact` -/// assignemnts. +/// assignments. #[test] fn sends_assignments_even_when_state_is_approved_v2() { let peers = make_peers_and_authority_ids(8); @@ -2153,7 +2153,7 @@ fn sends_assignments_even_when_state_is_approved_v2() { .iter() .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) .collect_vec(); - // Setup a topology where peer_a is neigboor to current node. + // Setup a topology where peer_a is neighbor to current node. setup_gossip_topology( overseer, make_gossip_topology(1, &peers_with_optional_peer_id, &[0], &[2], 1), @@ -3509,7 +3509,7 @@ fn import_versioned_approval() { setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V1).await; setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V2).await; - // Set up a gossip topology, where a, b, c and d are topology neighboors to the node under + // Set up a gossip topology, where a, b, c and d are topology neighbors to the node under // testing. let peers_with_optional_peer_id = peers .iter() diff --git a/polkadot/node/network/availability-distribution/src/requester/fetch_task/mod.rs b/polkadot/node/network/availability-distribution/src/requester/fetch_task/mod.rs index 191ee2acd97..f478defcaa9 100644 --- a/polkadot/node/network/availability-distribution/src/requester/fetch_task/mod.rs +++ b/polkadot/node/network/availability-distribution/src/requester/fetch_task/mod.rs @@ -348,7 +348,7 @@ impl RunningTask { async fn do_request( &mut self, validator: &AuthorityDiscoveryId, - nerwork_error_freq: &mut gum::Freq, + network_error_freq: &mut gum::Freq, canceled_freq: &mut gum::Freq, ) -> std::result::Result { gum::trace!( @@ -395,7 +395,7 @@ impl RunningTask { }, Err(RequestError::NetworkError(err)) => { gum::warn_if_frequent!( - freq: nerwork_error_freq, + freq: network_error_freq, max_rate: gum::Times::PerHour(100), target: LOG_TARGET, origin = ?validator, diff --git a/polkadot/node/network/availability-recovery/src/lib.rs b/polkadot/node/network/availability-recovery/src/lib.rs index fb8064878f4..94b9d9546cd 100644 --- a/polkadot/node/network/availability-recovery/src/lib.rs +++ b/polkadot/node/network/availability-recovery/src/lib.rs @@ -408,7 +408,7 @@ async fn handle_recover( ) -> error::Result<()> { let candidate_hash = receipt.hash(); - let span = jaeger::Span::new(candidate_hash, "availbility-recovery") + let span = jaeger::Span::new(candidate_hash, "availability-recovery") .with_stage(jaeger::Stage::AvailabilityRecovery); if let Some(result) = diff --git a/polkadot/node/network/availability-recovery/src/metrics.rs b/polkadot/node/network/availability-recovery/src/metrics.rs index d82a8f9ae5f..9f4cddc57e4 100644 --- a/polkadot/node/network/availability-recovery/src/metrics.rs +++ b/polkadot/node/network/availability-recovery/src/metrics.rs @@ -31,7 +31,7 @@ struct MetricsInner { chunk_requests_issued: Counter, /// Total number of bytes recovered /// - /// Gets incremented on each succesful recovery + /// Gets incremented on each successful recovery recovered_bytes_total: Counter, /// A counter for finished chunk requests. /// @@ -232,7 +232,7 @@ impl metrics::Metrics for Metrics { )?, full_recoveries_started: prometheus::register( Counter::new( - "polkadot_parachain_availability_recovery_recovieries_started", + "polkadot_parachain_availability_recovery_recoveries_started", "Total number of started recoveries.", )?, registry, diff --git a/polkadot/node/network/bitfield-distribution/src/metrics.rs b/polkadot/node/network/bitfield-distribution/src/metrics.rs index 71d8a01300f..bd956bcbe4a 100644 --- a/polkadot/node/network/bitfield-distribution/src/metrics.rs +++ b/polkadot/node/network/bitfield-distribution/src/metrics.rs @@ -69,14 +69,14 @@ impl MetricsTrait for Metrics { let metrics = MetricsInner { sent_own_availability_bitfields: prometheus::register( prometheus::Counter::new( - "polkadot_parachain_sent_own_availabilty_bitfields_total", + "polkadot_parachain_sent_own_availability_bitfields_total", "Number of own availability bitfields sent to other peers.", )?, registry, )?, received_availability_bitfields: prometheus::register( prometheus::Counter::new( - "polkadot_parachain_received_availabilty_bitfields_total", + "polkadot_parachain_received_availability_bitfields_total", "Number of valid availability bitfields received from other peers.", )?, registry, diff --git a/polkadot/node/network/bitfield-distribution/src/tests.rs b/polkadot/node/network/bitfield-distribution/src/tests.rs index ba2434ea47d..188b51ebccc 100644 --- a/polkadot/node/network/bitfield-distribution/src/tests.rs +++ b/polkadot/node/network/bitfield-distribution/src/tests.rs @@ -150,7 +150,7 @@ fn receive_invalid_signature() { let signing_context = SigningContext { session_index: 1, parent_hash: hash_a }; - // another validator not part of the validatorset + // another validator not part of the validator set let keystore: KeystorePtr = Arc::new(MemoryKeystore::new()); let malicious = Keystore::sr25519_generate_new(&*keystore, ValidatorId::ID, None) .expect("Malicious key created"); diff --git a/polkadot/node/network/dispute-distribution/src/sender/mod.rs b/polkadot/node/network/dispute-distribution/src/sender/mod.rs index f4acc72318a..8187f20146c 100644 --- a/polkadot/node/network/dispute-distribution/src/sender/mod.rs +++ b/polkadot/node/network/dispute-distribution/src/sender/mod.rs @@ -76,7 +76,7 @@ pub struct DisputeSender { /// Value is the hash that was used for the query. active_sessions: HashMap, - /// All ongoing dispute sendings this subsystem is aware of. + /// All ongoing dispute sending this subsystem is aware of. /// /// Using an `IndexMap` so items can be iterated in the order of insertion. disputes: IndexMap>, @@ -105,7 +105,7 @@ struct WaitForActiveDisputesState { #[overseer::contextbounds(DisputeDistribution, prefix = self::overseer)] impl DisputeSender { - /// Create a new `DisputeSender` which can be used to start dispute sendings. + /// Create a new `DisputeSender` which can be used to start dispute sending. pub fn new(tx: NestingSender, metrics: Metrics) -> Self { Self { active_heads: Vec::new(), @@ -362,7 +362,7 @@ async fn get_active_session_indices( runtime: &mut RuntimeInfo, active_heads: &Vec, ) -> Result> { - let mut indeces = HashMap::new(); + let mut indices = HashMap::new(); // Iterate all heads we track as active and fetch the child' session indices. for head in active_heads { let session_index = runtime.get_session_index_for_child(ctx.sender(), *head).await?; @@ -372,9 +372,9 @@ async fn get_active_session_indices( { gum::debug!(target: LOG_TARGET, ?err, ?session_index, "Can't cache SessionInfo"); } - indeces.insert(session_index, *head); + indices.insert(session_index, *head); } - Ok(indeces) + Ok(indices) } /// Retrieve Set of active disputes from the dispute coordinator. diff --git a/polkadot/node/network/dispute-distribution/src/tests/mock.rs b/polkadot/node/network/dispute-distribution/src/tests/mock.rs index e6a49f14c09..ccc050233e8 100644 --- a/polkadot/node/network/dispute-distribution/src/tests/mock.rs +++ b/polkadot/node/network/dispute-distribution/src/tests/mock.rs @@ -163,7 +163,7 @@ pub fn make_dispute_message( let invalid_vote = make_explicit_signed(MOCK_VALIDATORS[invalid_validator.0 as usize], candidate_hash, false); gum::trace!( - "Passed time for invald vote: {:#?}", + "Passed time for invalid vote: {:#?}", Instant::now().saturating_duration_since(before_request) ); DisputeMessage::from_signed_statements( diff --git a/polkadot/node/network/gossip-support/src/tests.rs b/polkadot/node/network/gossip-support/src/tests.rs index 6817c85f98d..cce78df38f3 100644 --- a/polkadot/node/network/gossip-support/src/tests.rs +++ b/polkadot/node/network/gossip-support/src/tests.rs @@ -122,7 +122,7 @@ impl MockAuthorityDiscovery { self.authorities.lock().clone() } - fn add_more_authorties( + fn add_more_authorities( &self, new_known: Vec, ) -> HashMap> { @@ -720,7 +720,7 @@ fn issues_update_authorities_after_session() { assert!(overseer.recv().timeout(TIMEOUT).await.is_none()); // 4. Connect more authorities except one - let newly_added = authority_discovery_mock.add_more_authorties(unknown_at_session); + let newly_added = authority_discovery_mock.add_more_authorities(unknown_at_session); let mut newly_added_iter = newly_added.iter(); let unconnected_at_last_retry = newly_added_iter .next() diff --git a/polkadot/node/network/protocol/src/grid_topology.rs b/polkadot/node/network/protocol/src/grid_topology.rs index 3c4372a27a2..a14d2461072 100644 --- a/polkadot/node/network/protocol/src/grid_topology.rs +++ b/polkadot/node/network/protocol/src/grid_topology.rs @@ -89,7 +89,7 @@ impl SessionGridTopology { SessionGridTopology { shuffled_indices, canonical_shuffling, peer_ids } } - /// Updates the known peer ids for the passed authorithies ids. + /// Updates the known peer ids for the passed authorities ids. pub fn update_authority_ids( &mut self, peer_id: PeerId, @@ -313,7 +313,7 @@ impl SessionGridTopologyEntry { self.topology.is_validator(peer) } - /// Updates the known peer ids for the passed authorithies ids. + /// Updates the known peer ids for the passed authorities ids. pub fn update_authority_ids( &mut self, peer_id: PeerId, @@ -345,7 +345,7 @@ impl SessionGridTopologies { self.inner.get(&session).and_then(|val| val.0.as_ref()) } - /// Updates the known peer ids for the passed authorithies ids. + /// Updates the known peer ids for the passed authorities ids. pub fn update_authority_ids( &mut self, peer_id: PeerId, diff --git a/polkadot/node/network/protocol/src/lib.rs b/polkadot/node/network/protocol/src/lib.rs index 7a0ff9f4fa9..4dd94b5eac4 100644 --- a/polkadot/node/network/protocol/src/lib.rs +++ b/polkadot/node/network/protocol/src/lib.rs @@ -871,7 +871,7 @@ pub mod v2 { } /// v3 network protocol types. -/// Purpose is for chaning ApprovalDistributionMessage to +/// Purpose is for changing ApprovalDistributionMessage to /// include more than one assignment and approval in a message. pub mod v3 { use parity_scale_codec::{Decode, Encode}; diff --git a/polkadot/node/network/protocol/src/peer_set.rs b/polkadot/node/network/protocol/src/peer_set.rs index cb329607ad6..d0ae5b4a1bf 100644 --- a/polkadot/node/network/protocol/src/peer_set.rs +++ b/polkadot/node/network/protocol/src/peer_set.rs @@ -234,7 +234,7 @@ pub enum ValidationVersion { /// The second version. V2 = 2, /// The third version where changes to ApprovalDistributionMessage had been made. - /// The changes are translatable to V2 format untill assignments v2 and approvals + /// The changes are translatable to V2 format until assignments v2 and approvals /// coalescing is enabled through a runtime upgrade. V3 = 3, } diff --git a/polkadot/node/network/protocol/src/request_response/incoming/mod.rs b/polkadot/node/network/protocol/src/request_response/incoming/mod.rs index 44554483867..1d7c4a63e0c 100644 --- a/polkadot/node/network/protocol/src/request_response/incoming/mod.rs +++ b/polkadot/node/network/protocol/src/request_response/incoming/mod.rs @@ -47,7 +47,7 @@ where Req: IsRequest + Decode + Encode, Req::Response: Encode, { - /// Create configuration for `NetworkConfiguration::request_response_porotocols` and a + /// Create configuration for `NetworkConfiguration::request_response_protocols` and a /// corresponding typed receiver. /// /// This Register that config with substrate networking and receive incoming requests via the diff --git a/polkadot/node/network/protocol/src/request_response/mod.rs b/polkadot/node/network/protocol/src/request_response/mod.rs index 2fb62f56d10..87217bf084f 100644 --- a/polkadot/node/network/protocol/src/request_response/mod.rs +++ b/polkadot/node/network/protocol/src/request_response/mod.rs @@ -287,7 +287,7 @@ impl Protocol { match self { // Hundreds of validators will start requesting their chunks once they see a candidate // awaiting availability on chain. Given that they will see that block at different - // times (due to network delays), 100 seems big enough to accomodate for "bursts", + // times (due to network delays), 100 seems big enough to accommodate for "bursts", // assuming we can service requests relatively quickly, which would need to be measured // as well. Protocol::ChunkFetchingV1 => 100, diff --git a/polkadot/node/network/protocol/src/request_response/v1.rs b/polkadot/node/network/protocol/src/request_response/v1.rs index ba29b32c4ce..60eecb69f73 100644 --- a/polkadot/node/network/protocol/src/request_response/v1.rs +++ b/polkadot/node/network/protocol/src/request_response/v1.rs @@ -183,7 +183,7 @@ impl IsRequest for AvailableDataFetchingRequest { pub struct StatementFetchingRequest { /// Data needed to locate and identify the needed statement. pub relay_parent: Hash, - /// Hash of candidate that was used create the `CommitedCandidateRecept`. + /// Hash of candidate that was used create the `CommittedCandidateReceipt`. pub candidate_hash: CandidateHash, } diff --git a/polkadot/node/network/statement-distribution/src/legacy_v1/responder.rs b/polkadot/node/network/statement-distribution/src/legacy_v1/responder.rs index 81e226c4ff8..8d1683759a0 100644 --- a/polkadot/node/network/statement-distribution/src/legacy_v1/responder.rs +++ b/polkadot/node/network/statement-distribution/src/legacy_v1/responder.rs @@ -64,7 +64,7 @@ pub async fn respond( // late, as each requester having the data will help distributing it. // 2. If we take too long, the requests timing out will not yet have had any data sent, thus // we wasted no bandwidth. - // 3. If the queue is full, requestes will get an immediate error instead of running in a + // 3. If the queue is full, requests will get an immediate error instead of running in a // timeout, thus requesters can immediately try another peer and be faster. // // From this perspective we would not want parallel response sending at all, but we don't diff --git a/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs b/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs index 2766ec9815a..08e9d69d8ee 100644 --- a/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs +++ b/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs @@ -1494,7 +1494,7 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing( Err(()) => {} ); - // And now the succeding request from peer_b: + // And now the succeeding request from peer_b: let (pending_response, response_rx) = oneshot::channel(); let inner_req = StatementFetchingRequest { relay_parent: metadata.relay_parent, diff --git a/polkadot/node/network/statement-distribution/src/v2/cluster.rs b/polkadot/node/network/statement-distribution/src/v2/cluster.rs index c09916e5620..87cdc389cb3 100644 --- a/polkadot/node/network/statement-distribution/src/v2/cluster.rs +++ b/polkadot/node/network/statement-distribution/src/v2/cluster.rs @@ -430,8 +430,8 @@ impl ClusterTracker { /// /// Normally we should not have pending statements to validators in our cluster, /// but if we do for all validators in our cluster, then we don't participate - /// in backing. Ocasional pending statements are expected if two authorities - /// can't detect each otehr or after restart, where it takes a while to discover + /// in backing. Occasional pending statements are expected if two authorities + /// can't detect each other or after restart, where it takes a while to discover /// the whole network. pub fn warn_if_too_many_pending_statements(&self, parent_hash: Hash) { diff --git a/polkadot/node/network/statement-distribution/src/v2/mod.rs b/polkadot/node/network/statement-distribution/src/v2/mod.rs index 2c9cdba4ea8..d782e37f10b 100644 --- a/polkadot/node/network/statement-distribution/src/v2/mod.rs +++ b/polkadot/node/network/statement-distribution/src/v2/mod.rs @@ -112,7 +112,7 @@ const COST_EXCESSIVE_SECONDED: Rep = Rep::CostMinor("Sent Excessive `Seconded` S const COST_DISABLED_VALIDATOR: Rep = Rep::CostMinor("Sent a statement from a disabled validator"); const COST_UNEXPECTED_MANIFEST_MISSING_KNOWLEDGE: Rep = - Rep::CostMinor("Unexpected Manifest, missing knowlege for relay parent"); + Rep::CostMinor("Unexpected Manifest, missing knowledge for relay parent"); const COST_UNEXPECTED_MANIFEST_DISALLOWED: Rep = Rep::CostMinor("Unexpected Manifest, Peer Disallowed"); const COST_UNEXPECTED_MANIFEST_PEER_UNKNOWN: Rep = @@ -628,8 +628,8 @@ pub(crate) async fn handle_active_leaves_update( request_min_backing_votes(new_relay_parent, session_index, ctx.sender()).await?; let mut per_session_state = PerSessionState::new(session_info, &state.keystore, minimum_backing_votes); - if let Some(toplogy) = state.unused_topologies.remove(&session_index) { - per_session_state.supply_topology(&toplogy.topology, toplogy.local_index); + if let Some(topology) = state.unused_topologies.remove(&session_index) { + per_session_state.supply_topology(&topology.topology, topology.local_index); } state.per_session.insert(session_index, per_session_state); } diff --git a/polkadot/node/network/statement-distribution/src/v2/requests.rs b/polkadot/node/network/statement-distribution/src/v2/requests.rs index bbcb268415e..fe270c8a58e 100644 --- a/polkadot/node/network/statement-distribution/src/v2/requests.rs +++ b/polkadot/node/network/statement-distribution/src/v2/requests.rs @@ -320,7 +320,7 @@ impl RequestManager { // need for the current node to limit itself to the same amount the // requests, because the requests are going to different nodes anyways. // While looking at https://github.com/paritytech/polkadot-sdk/issues/3314, - // found out that this requests take around 100ms to fullfill, so it + // found out that this requests take around 100ms to fulfill, so it // would make sense to try to request things as early as we can, given // we would need to request it for each candidate, around 25 right now // on kusama. diff --git a/polkadot/node/overseer/src/lib.rs b/polkadot/node/overseer/src/lib.rs index e16a3fd27ab..167b32a15bc 100644 --- a/polkadot/node/overseer/src/lib.rs +++ b/polkadot/node/overseer/src/lib.rs @@ -871,7 +871,7 @@ where gum::trace!( target: LOG_TARGET, relay_parent = ?hash, - "Leaf got activated, notifying exterinal listeners" + "Leaf got activated, notifying external listeners" ); for listener in listeners { // it's fine if the listener is no longer interested diff --git a/polkadot/node/primitives/src/approval.rs b/polkadot/node/primitives/src/approval.rs index f2a79e025af..b73cb4c717d 100644 --- a/polkadot/node/primitives/src/approval.rs +++ b/polkadot/node/primitives/src/approval.rs @@ -382,7 +382,7 @@ pub mod v2 { /// The core index chosen in this cert. core_index: CoreIndex, }, - /// Deprectated assignment. Soon to be removed. + /// Deprecated assignment. Soon to be removed. /// An assignment story based on the VRF that authorized the relay-chain block where the /// candidate was included combined with a sample number. /// diff --git a/polkadot/node/primitives/src/disputes/mod.rs b/polkadot/node/primitives/src/disputes/mod.rs index 768b95f6553..5814ecee44f 100644 --- a/polkadot/node/primitives/src/disputes/mod.rs +++ b/polkadot/node/primitives/src/disputes/mod.rs @@ -84,7 +84,7 @@ impl CandidateVotes { #[derive(Debug, Clone)] /// Valid candidate votes. /// -/// Prefere backing votes over other votes. +/// Prefer backing votes over other votes. pub struct ValidCandidateVotes { votes: BTreeMap, } @@ -133,7 +133,7 @@ impl ValidCandidateVotes { self.votes.retain(f) } - /// Get all the validator indeces we have votes for. + /// Get all the validator indices we have votes for. pub fn keys( &self, ) -> Bkeys<'_, ValidatorIndex, (ValidDisputeStatementKind, ValidatorSignature)> { diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs index b6556e0be56..b102cf06c38 100644 --- a/polkadot/node/primitives/src/lib.rs +++ b/polkadot/node/primitives/src/lib.rs @@ -74,7 +74,7 @@ pub const VALIDATION_CODE_BOMB_LIMIT: usize = (MAX_CODE_SIZE * 4u32) as usize; pub const POV_BOMB_LIMIT: usize = (MAX_POV_SIZE * 4u32) as usize; /// How many blocks after finalization an information about backed/included candidate should be -/// pre-loaded (when scraoing onchain votes) and kept locally (when pruning). +/// pre-loaded (when scraping onchain votes) and kept locally (when pruning). /// /// We don't want to remove scraped candidates on finalization because we want to /// be sure that disputes will conclude on abandoned forks. diff --git a/polkadot/node/service/src/overseer.rs b/polkadot/node/service/src/overseer.rs index a8167370464..9575b2458a2 100644 --- a/polkadot/node/service/src/overseer.rs +++ b/polkadot/node/service/src/overseer.rs @@ -77,7 +77,7 @@ pub struct OverseerGenArgs<'a, Spawner, RuntimeClient> where Spawner: 'static + SpawnNamed + Clone + Unpin, { - /// Runtime client generic, providing the `ProvieRuntimeApi` trait besides others. + /// Runtime client generic, providing the `ProvideRuntimeApi` trait besides others. pub runtime_client: Arc, /// Underlying network service implementation. pub network_service: Arc>, diff --git a/polkadot/node/service/src/parachains_db/upgrade.rs b/polkadot/node/service/src/parachains_db/upgrade.rs index 2eceb391b15..4d737085960 100644 --- a/polkadot/node/service/src/parachains_db/upgrade.rs +++ b/polkadot/node/service/src/parachains_db/upgrade.rs @@ -115,7 +115,7 @@ pub(crate) fn try_upgrade_db_to_next_version( Some(CURRENT_VERSION) => CURRENT_VERSION, // This is an arbitrary future version, we don't handle it. Some(v) => return Err(Error::FutureVersion { current: CURRENT_VERSION, got: v }), - // No version file. For `RocksDB` we dont need to do anything. + // No version file. For `RocksDB` we don't need to do anything. None if db_kind == DatabaseKind::RocksDB => CURRENT_VERSION, // No version file. `ParityDB` did not previously have a version defined. // We handle this as a `0 -> 1` migration. @@ -183,7 +183,7 @@ fn migrate_from_version_1_to_2(path: &Path, db_kind: DatabaseKind) -> Result { // The total lag accounting for disputes. let lag_disputes = initial_leaf_number.saturating_sub(subchain_number); diff --git a/polkadot/node/subsystem-bench/grafana/availability-read.json b/polkadot/node/subsystem-bench/grafana/availability-read.json index 31c4ad3c795..96a83d2d70f 100644 --- a/polkadot/node/subsystem-bench/grafana/availability-read.json +++ b/polkadot/node/subsystem-bench/grafana/availability-read.json @@ -119,7 +119,7 @@ "editorMode": "code", "expr": "subsystem_benchmark_n_validators{}", "instant": false, - "legendFormat": "n_vaidators", + "legendFormat": "n_validators", "range": true, "refId": "A" }, @@ -1046,7 +1046,7 @@ "refId": "A" } ], - "title": "Availability subystem metrics", + "title": "Availability subsystem metrics", "type": "row" }, { @@ -1397,7 +1397,7 @@ "refId": "B" } ], - "title": "Recovery throughtput", + "title": "Recovery throughput", "transformations": [], "type": "timeseries" }, diff --git a/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs b/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs index c1b31a509f6..3b08d0ed861 100644 --- a/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs +++ b/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs @@ -74,8 +74,8 @@ pub struct PeerMessagesGenerator { pub validator_index: ValidatorIndex, /// An array of pre-generated random samplings, that is used to determine, which nodes would /// send a given assignment, to the node under test because of the random samplings. - /// As an optimization we generate this sampling at the begining of the test and just pick - /// one randomly, because always taking the samples would be too expensive for benchamrk. + /// As an optimization we generate this sampling at the beginning of the test and just pick + /// one randomly, because always taking the samples would be too expensive for benchmark. pub random_samplings: Vec>, /// Channel for sending the generated messages to the aggregator pub tx_messages: futures::channel::mpsc::UnboundedSender<(Hash, Vec)>, @@ -234,7 +234,7 @@ impl PeerMessagesGenerator { let all_messages = all_messages .into_iter() .flat_map(|(_, mut messages)| { - // Shuffle the messages inside the same tick, so that we don't priorites messages + // Shuffle the messages inside the same tick, so that we don't priorities messages // for older nodes. we try to simulate the same behaviour as in real world. messages.shuffle(&mut rand_chacha); messages @@ -560,12 +560,12 @@ struct TestSignInfo { candidate_index: CandidateIndex, /// The validator sending the assignments validator_index: ValidatorIndex, - /// The assignments convering this candidate + /// The assignments covering this candidate assignment: TestMessageInfo, } impl TestSignInfo { - /// Helper function to create a signture for all candidates in `to_sign` parameter. + /// Helper function to create a signature for all candidates in `to_sign` parameter. /// Returns a TestMessage fn sign_candidates( to_sign: &mut Vec, diff --git a/polkadot/node/subsystem-bench/src/lib/approval/mod.rs b/polkadot/node/subsystem-bench/src/lib/approval/mod.rs index 450faf06123..6ab5b86baed 100644 --- a/polkadot/node/subsystem-bench/src/lib/approval/mod.rs +++ b/polkadot/node/subsystem-bench/src/lib/approval/mod.rs @@ -115,7 +115,7 @@ pub struct ApprovalsOptions { #[clap(short, long, default_value_t = 1.0)] /// Max candidate to be signed in a single approval. pub coalesce_std_dev: f32, - /// The maximum tranche diff between approvals coalesced toghther. + /// The maximum tranche diff between approvals coalesced together. pub coalesce_tranche_diff: u32, #[clap(short, long, default_value_t = false)] /// Enable assignments v2. @@ -170,7 +170,7 @@ struct BlockTestData { total_candidates_before: u64, /// The votes we sent. /// votes[validator_index][candidate_index] tells if validator sent vote for candidate. - /// We use this to mark the test as succesfull if GetApprovalSignatures returns all the votes + /// We use this to mark the test as successful if GetApprovalSignatures returns all the votes /// from here. votes: Arc>>, } @@ -237,7 +237,7 @@ struct GeneratedState { } /// Approval test state used by all mock subsystems to be able to answer messages emitted -/// by the approval-voting and approval-distribution-subystems. +/// by the approval-voting and approval-distribution-subsystems. /// /// This gets cloned across all mock subsystems, so if there is any information that gets /// updated between subsystems, they would have to be wrapped in Arc's. @@ -498,7 +498,7 @@ struct PeerMessageProducer { impl PeerMessageProducer { /// Generates messages by spawning a blocking task in the background which begins creating - /// the assignments/approvals and peer view changes at the begining of each block. + /// the assignments/approvals and peer view changes at the beginning of each block. fn produce_messages( mut self, env: &TestEnvironment, @@ -740,7 +740,7 @@ impl PeerMessageProducer { } } - // Initializes the candidates test data. This is used for bookeeping if more assignments and + // Initializes the candidates test data. This is used for bookkeeping if more assignments and // approvals would be needed. fn initialize_candidates_test_data( &self, @@ -767,7 +767,7 @@ impl PeerMessageProducer { } /// Helper function to build an overseer with the real implementation for `ApprovalDistribution` and -/// `ApprovalVoting` subystems and mock subsytems for all others. +/// `ApprovalVoting` subsystems and mock subsystems for all others. fn build_overseer( state: &ApprovalTestState, network: &NetworkEmulatorHandle, @@ -936,7 +936,7 @@ pub async fn bench_approvals_run( for block_num in 0..env.config().num_blocks { let mut current_slot = tick_to_slot_number(SLOT_DURATION_MILLIS, system_clock.tick_now()); - // Wait untill the time arrieves at the first slot under test. + // Wait until the time arrives at the first slot under test. while current_slot < state.generated_state.initial_slot { sleep(Duration::from_millis(5)).await; current_slot = tick_to_slot_number(SLOT_DURATION_MILLIS, system_clock.tick_now()); @@ -961,7 +961,7 @@ pub async fn bench_approvals_run( } // Wait for all blocks to be approved before exiting. - // This is an invariant of the benchmark, if this does not happen something went teribbly wrong. + // This is an invariant of the benchmark, if this does not happen something went terribly wrong. while state.last_approved_block.load(std::sync::atomic::Ordering::SeqCst) < env.config().num_blocks as u32 { diff --git a/polkadot/node/subsystem-bench/src/lib/approval/test_message.rs b/polkadot/node/subsystem-bench/src/lib/approval/test_message.rs index 63e383509be..f55ed99205e 100644 --- a/polkadot/node/subsystem-bench/src/lib/approval/test_message.rs +++ b/polkadot/node/subsystem-bench/src/lib/approval/test_message.rs @@ -31,7 +31,7 @@ pub struct TestMessageInfo { pub msg: protocol_v3::ApprovalDistributionMessage, /// The list of peers that would sends this message in a real topology. /// It includes both the peers that would send the message because of the topology - /// or because of randomly chosing so. + /// or because of randomly choosing so. pub sent_by: Vec, /// The tranche at which this message should be sent. pub tranche: u32, @@ -90,7 +90,7 @@ impl MessagesBundle { /// Tells if the bundle is needed for sending. /// We either send it because we need more assignments and approvals to approve the candidates - /// or because we configured the test to send messages untill a given tranche. + /// or because we configured the test to send messages until a given tranche. pub fn should_send( &self, candidates_test_data: &HashMap<(Hash, CandidateIndex), CandidateTestData>, @@ -174,24 +174,24 @@ impl TestMessageInfo { } } - /// Returns a list of candidates indicies in this message + /// Returns a list of candidates indices in this message pub fn candidate_indices(&self) -> HashSet { - let mut unique_candidate_indicies = HashSet::new(); + let mut unique_candidate_indices = HashSet::new(); match &self.msg { protocol_v3::ApprovalDistributionMessage::Assignments(assignments) => for (_assignment, candidate_indices) in assignments { for candidate_index in candidate_indices.iter_ones() { - unique_candidate_indicies.insert(candidate_index); + unique_candidate_indices.insert(candidate_index); } }, protocol_v3::ApprovalDistributionMessage::Approvals(approvals) => for approval in approvals { for candidate_index in approval.candidate_indices.iter_ones() { - unique_candidate_indicies.insert(candidate_index); + unique_candidate_indices.insert(candidate_index); } }, } - unique_candidate_indicies + unique_candidate_indices } /// Marks this message as no-shows if the number of configured no-shows is above the registered diff --git a/polkadot/node/subsystem-bench/src/lib/availability/mod.rs b/polkadot/node/subsystem-bench/src/lib/availability/mod.rs index 765afdd5912..fe986669061 100644 --- a/polkadot/node/subsystem-bench/src/lib/availability/mod.rs +++ b/polkadot/node/subsystem-bench/src/lib/availability/mod.rs @@ -69,7 +69,7 @@ const LOG_TARGET: &str = "subsystem-bench::availability"; pub struct DataAvailabilityReadOptions { #[clap(short, long, default_value_t = false)] /// Turbo boost AD Read by fetching the full availability datafrom backers first. Saves CPU as - /// we don't need to re-construct from chunks. Tipically this is only faster if nodes have + /// we don't need to re-construct from chunks. Typically this is only faster if nodes have /// enough bandwidth. pub fetch_from_backers: bool, } @@ -404,7 +404,7 @@ pub async fn benchmark_availability_write( let network = env.network().clone(); let authorities = env.authorities().clone(); - // Spawn a task that will generate `n_validator` - 1 signed bitfiends and + // Spawn a task that will generate `n_validator` - 1 signed bitfields and // send them from the emulated peers to the subsystem. // TODO: Implement topology. let messages = state.signed_bitfields.get(&relay_block_hash).expect("pregenerated").clone(); @@ -425,7 +425,7 @@ pub async fn benchmark_availability_write( // Wait for all bitfields to be processed. env.wait_until_metric( - "polkadot_parachain_received_availabilty_bitfields_total", + "polkadot_parachain_received_availability_bitfields_total", None, |value| value == (config.connected_count() * block_num) as f64, ) diff --git a/polkadot/node/subsystem-bench/src/lib/configuration.rs b/polkadot/node/subsystem-bench/src/lib/configuration.rs index 17c81c4fd35..5725a5137ec 100644 --- a/polkadot/node/subsystem-bench/src/lib/configuration.rs +++ b/polkadot/node/subsystem-bench/src/lib/configuration.rs @@ -122,10 +122,10 @@ pub struct TestConfiguration { /// Randomly sampled pov_sizes #[serde(skip)] pub pov_sizes: Vec, - /// The amount of bandiwdth remote validators have. + /// The amount of bandwidth remote validators have. #[serde(default = "default_bandwidth")] pub peer_bandwidth: usize, - /// The amount of bandiwdth our node has. + /// The amount of bandwidth our node has. #[serde(default = "default_bandwidth")] pub bandwidth: usize, /// Optional peer emulation latency (round trip time) wrt node under test @@ -205,7 +205,7 @@ impl TestConfiguration { let peer_id_to_authority = peer_ids .iter() .zip(validator_authority_id.iter()) - .map(|(peer_id, authorithy_id)| (*peer_id, authorithy_id.clone())) + .map(|(peer_id, authority_id)| (*peer_id, authority_id.clone())) .collect(); TestAuthorities { diff --git a/polkadot/node/subsystem-bench/src/lib/mock/av_store.rs b/polkadot/node/subsystem-bench/src/lib/mock/av_store.rs index 080644da92a..fba33523be8 100644 --- a/polkadot/node/subsystem-bench/src/lib/mock/av_store.rs +++ b/polkadot/node/subsystem-bench/src/lib/mock/av_store.rs @@ -39,7 +39,7 @@ pub struct AvailabilityStoreState { const LOG_TARGET: &str = "subsystem-bench::av-store-mock"; -/// Mockup helper. Contains Ccunks and full availability data of all parachain blocks +/// Mockup helper. Contains Chunks and full availability data of all parachain blocks /// used in a test. #[derive(Clone)] pub struct NetworkAvailabilityState { diff --git a/polkadot/node/subsystem-bench/src/lib/mock/chain_api.rs b/polkadot/node/subsystem-bench/src/lib/mock/chain_api.rs index bee15c3cefd..86b030fb6fd 100644 --- a/polkadot/node/subsystem-bench/src/lib/mock/chain_api.rs +++ b/polkadot/node/subsystem-bench/src/lib/mock/chain_api.rs @@ -89,7 +89,7 @@ impl MockChainApi { let hash = self .state .get_header_by_number(requested_number) - .expect("Unknow block number") + .expect("Unknown block number") .hash(); sender.send(Ok(Some(hash))).unwrap(); }, diff --git a/polkadot/node/subsystem-bench/src/lib/mock/network_bridge.rs b/polkadot/node/subsystem-bench/src/lib/mock/network_bridge.rs index d598f6447d3..ec66ad4e279 100644 --- a/polkadot/node/subsystem-bench/src/lib/mock/network_bridge.rs +++ b/polkadot/node/subsystem-bench/src/lib/mock/network_bridge.rs @@ -42,8 +42,8 @@ pub struct MockNetworkBridgeTx { network: NetworkEmulatorHandle, /// A channel to the network interface, to_network_interface: UnboundedSender, - /// Test authorithies - test_authorithies: TestAuthorities, + /// Test authorities + test_authorities: TestAuthorities, } /// A mock of the network bridge tx subsystem. @@ -58,9 +58,9 @@ impl MockNetworkBridgeTx { pub fn new( network: NetworkEmulatorHandle, to_network_interface: UnboundedSender, - test_authorithies: TestAuthorities, + test_authorities: TestAuthorities, ) -> MockNetworkBridgeTx { - Self { network, to_network_interface, test_authorithies } + Self { network, to_network_interface, test_authorities } } } @@ -125,13 +125,13 @@ impl MockNetworkBridgeTx { } }, NetworkBridgeTxMessage::ReportPeer(_) => { - // ingore rep changes + // ignore rep changes }, NetworkBridgeTxMessage::SendValidationMessage(peers, message) => { for peer in peers { self.to_network_interface .unbounded_send(NetworkMessage::MessageFromNode( - self.test_authorithies + self.test_authorities .peer_id_to_authority .get(&peer) .unwrap() diff --git a/polkadot/node/subsystem-bench/src/lib/network.rs b/polkadot/node/subsystem-bench/src/lib/network.rs index 1bc35a014ff..0f7b7d741e7 100644 --- a/polkadot/node/subsystem-bench/src/lib/network.rs +++ b/polkadot/node/subsystem-bench/src/lib/network.rs @@ -154,7 +154,7 @@ pub enum NetworkMessage { MessageFromNode(AuthorityDiscoveryId, VersionedValidationProtocol), /// A request originating from our node RequestFromNode(AuthorityDiscoveryId, Requests), - /// A request originating from an emultated peer + /// A request originating from an emulated peer RequestFromPeer(IncomingRequest), } @@ -790,9 +790,9 @@ pub fn new_network( let connected_count = config.connected_count(); - let mut peers_indicies = (0..n_peers).collect_vec(); + let mut peers_indices = (0..n_peers).collect_vec(); let (_connected, to_disconnect) = - peers_indicies.partial_shuffle(&mut thread_rng(), connected_count); + peers_indices.partial_shuffle(&mut thread_rng(), connected_count); // Node under test is always mark as disconnected. peers[NODE_UNDER_TEST as usize].disconnect(); @@ -958,7 +958,7 @@ impl Metrics { .inc_by(bytes as u64); } - /// Increment total receioved for a peer. + /// Increment total received for a peer. pub fn on_peer_received(&self, peer_index: usize, bytes: usize) { self.peer_total_received .with_label_values(vec![format!("node{}", peer_index).as_str()].as_slice()) @@ -1041,7 +1041,7 @@ mod tests { async fn test_expected_rate() { let tick_rate = 200; let budget = 1_000_000; - // rate must not exceeed 100 credits per second + // rate must not exceed 100 credits per second let mut rate_limiter = RateLimit::new(tick_rate, budget); let mut total_sent = 0usize; let start = Instant::now(); diff --git a/polkadot/node/subsystem-bench/src/lib/utils.rs b/polkadot/node/subsystem-bench/src/lib/utils.rs new file mode 100644 index 00000000000..cd206d8f322 --- /dev/null +++ b/polkadot/node/subsystem-bench/src/lib/utils.rs @@ -0,0 +1,76 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Test utils + +use crate::usage::BenchmarkUsage; +use std::io::{stdout, Write}; + +pub struct WarmUpOptions<'a> { + /// The maximum number of runs considered for warming up. + pub warm_up: usize, + /// The number of runs considered for benchmarking. + pub bench: usize, + /// The difference in CPU usage between runs considered as normal + pub precision: f64, + /// The subsystems whose CPU usage is checked during warm-up cycles + pub subsystems: &'a [&'a str], +} + +impl<'a> WarmUpOptions<'a> { + pub fn new(subsystems: &'a [&'a str]) -> Self { + Self { warm_up: 100, bench: 3, precision: 0.02, subsystems } + } +} + +pub fn warm_up_and_benchmark( + options: WarmUpOptions, + run: impl Fn() -> BenchmarkUsage, +) -> Result { + println!("Warming up..."); + let mut usages = Vec::with_capacity(options.bench); + + for n in 1..=options.warm_up { + let curr = run(); + if let Some(prev) = usages.last() { + let diffs = options + .subsystems + .iter() + .map(|&v| { + curr.cpu_usage_diff(prev, v) + .ok_or(format!("{} not found in benchmark {:?}", v, prev)) + }) + .collect::, String>>()?; + if !diffs.iter().all(|&v| v < options.precision) { + usages.clear(); + } + } + usages.push(curr); + print!("\r{}%", n * 100 / options.warm_up); + if usages.len() == options.bench { + println!("\rTook {} runs to warm up", n.saturating_sub(options.bench)); + break; + } + stdout().flush().unwrap(); + } + + if usages.len() != options.bench { + println!("Didn't warm up after {} runs", options.warm_up); + return Err("Can't warm up".to_string()) + } + + Ok(BenchmarkUsage::average(&usages)) +} diff --git a/polkadot/node/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index 92c35d1b7b9..5d05d2b56ed 100644 --- a/polkadot/node/subsystem-types/src/messages.rs +++ b/polkadot/node/subsystem-types/src/messages.rs @@ -805,7 +805,7 @@ pub enum StatementDistributionMessage { /// This data becomes intrinsics or extrinsics which should be included in a future relay chain /// block. -// It needs to be cloneable because multiple potential block authors can request copies. +// It needs to be clonable because multiple potential block authors can request copies. #[derive(Debug, Clone)] pub enum ProvisionableData { /// This bitfield indicates the availability of various candidate blocks. diff --git a/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs b/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs index c7b91bffb3d..d38d838fede 100644 --- a/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs +++ b/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs @@ -78,7 +78,7 @@ /// /// 2. The root fragment is invalid under the new constraints because it has been subsumed by /// the relay-chain. In this case, we can discard the root and split & re-root the fragment -/// tree under its descendents and compare to the new constraints again. This is the +/// tree under its descendants and compare to the new constraints again. This is the /// "prediction came true" case. /// /// 3. The root fragment is invalid under the new constraints because a competing parachain diff --git a/polkadot/node/subsystem-util/src/lib.rs b/polkadot/node/subsystem-util/src/lib.rs index aaae30db50c..6ff09ed5f22 100644 --- a/polkadot/node/subsystem-util/src/lib.rs +++ b/polkadot/node/subsystem-util/src/lib.rs @@ -382,7 +382,7 @@ pub fn signing_key_and_index<'a>( /// Sign the given data with the given validator ID. /// -/// Returns `Ok(None)` if the private key that correponds to that validator ID is not found in the +/// Returns `Ok(None)` if the private key that corresponds to that validator ID is not found in the /// given keystore. Returns an error if the key could not be used for signing. pub fn sign( keystore: &KeystorePtr, diff --git a/polkadot/primitives/src/v6/mod.rs b/polkadot/primitives/src/v6/mod.rs index 9e7f910314c..21cee753265 100644 --- a/polkadot/primitives/src/v6/mod.rs +++ b/polkadot/primitives/src/v6/mod.rs @@ -1457,7 +1457,7 @@ pub enum ValidDisputeStatementKind { #[codec(index = 3)] ApprovalChecking, /// An approval vote from the new version. - /// We can't create this version untill all nodes + /// We can't create this version until all nodes /// have been updated to support it and max_approval_coalesce_count /// is set to more than 1. #[codec(index = 4)] @@ -1604,7 +1604,7 @@ impl ValidityAttestation { pub fn to_compact_statement(&self, candidate_hash: CandidateHash) -> CompactStatement { // Explicit and implicit map directly from // `ValidityVote::Valid` and `ValidityVote::Issued`, and hence there is a - // `1:1` relationshow which enables the conversion. + // `1:1` relationship which enables the conversion. match *self { ValidityAttestation::Implicit(_) => CompactStatement::Seconded(candidate_hash), ValidityAttestation::Explicit(_) => CompactStatement::Valid(candidate_hash), diff --git a/polkadot/primitives/src/vstaging/mod.rs b/polkadot/primitives/src/vstaging/mod.rs index bd2a5106c44..94e9e892029 100644 --- a/polkadot/primitives/src/vstaging/mod.rs +++ b/polkadot/primitives/src/vstaging/mod.rs @@ -102,7 +102,7 @@ pub struct SchedulerParams { pub on_demand_fee_variability: Perbill, /// The minimum amount needed to claim a slot in the spot pricing queue. pub on_demand_base_fee: Balance, - /// The number of blocks a claim stays in the scheduler's claimqueue before getting cleared. + /// The number of blocks a claim stays in the scheduler's claim queue before getting cleared. /// This number should go reasonably higher than the number of blocks in the async backing /// lookahead. pub ttl: BlockNumber, @@ -133,7 +133,7 @@ pub type NodeFeatures = BitVec; /// Module containing feature-specific bit indices into the `NodeFeatures` bitvec. pub mod node_features { - /// A feature index used to indentify a bit into the node_features array stored + /// A feature index used to identify a bit into the node_features array stored /// in the HostConfiguration. #[repr(u8)] pub enum FeatureIndex { diff --git a/polkadot/primitives/test-helpers/src/lib.rs b/polkadot/primitives/test-helpers/src/lib.rs index b7c5d82341a..d43cf3317e5 100644 --- a/polkadot/primitives/test-helpers/src/lib.rs +++ b/polkadot/primitives/test-helpers/src/lib.rs @@ -249,7 +249,7 @@ pub fn resign_candidate_descriptor_with_collator>( descriptor.signature = signature; } -/// Extracts validators's public keus (`ValidatorId`) from `Sr25519Keyring` +/// Extracts validators's public keys (`ValidatorId`) from `Sr25519Keyring` pub fn validator_pubkeys(val_ids: &[Sr25519Keyring]) -> Vec { val_ids.iter().map(|v| v.public().into()).collect() } diff --git a/polkadot/roadmap/implementers-guide/src/disputes-flow.md b/polkadot/roadmap/implementers-guide/src/disputes-flow.md index b5cc5611c6f..540b3c45bad 100644 --- a/polkadot/roadmap/implementers-guide/src/disputes-flow.md +++ b/polkadot/roadmap/implementers-guide/src/disputes-flow.md @@ -74,7 +74,7 @@ The set of validators eligible to vote consists of the validators that had duty votes by the backing validators. If a validator receives an initial dispute message (a set of votes where there are at least two opposing votes -contained), and the PoV or Code are hence not reconstructable from local storage, that validator must request the +contained), and the PoV or Code are hence not reconstructible from local storage, that validator must request the required data from its peers. The dispute availability message must contain code, persisted validation data, and the proof of validity. diff --git a/polkadot/roadmap/implementers-guide/src/node/approval/approval-distribution.md b/polkadot/roadmap/implementers-guide/src/node/approval/approval-distribution.md index ce71de6f76b..c987b7fe5be 100644 --- a/polkadot/roadmap/implementers-guide/src/node/approval/approval-distribution.md +++ b/polkadot/roadmap/implementers-guide/src/node/approval/approval-distribution.md @@ -101,7 +101,7 @@ struct State { } enum MessageFingerprint { - Assigment(Hash, u32, ValidatorIndex), + Assignment(Hash, u32, ValidatorIndex), Approval(Hash, u32, ValidatorIndex), } @@ -203,7 +203,7 @@ For all peers: * Compute `view_intersection` as the intersection of the peer's view blocks with the hashes of the new blocks. * Invoke `unify_with_peer(peer, view_intersection)`. -#### `ApprovalDistributionMessage::DistributeAsignment` +#### `ApprovalDistributionMessage::DistributeAssignment` Call `import_and_circulate_assignment` with `MessageSource::Local`. diff --git a/polkadot/roadmap/implementers-guide/src/node/availability/availability-recovery.md b/polkadot/roadmap/implementers-guide/src/node/availability/availability-recovery.md index e3bb14db3a5..c57c4589244 100644 --- a/polkadot/roadmap/implementers-guide/src/node/availability/availability-recovery.md +++ b/polkadot/roadmap/implementers-guide/src/node/availability/availability-recovery.md @@ -115,7 +115,7 @@ On `Conclude`, shut down the subsystem. Launch the source as a background task running `run(recovery_task)`. -#### `run(recovery_task) -> Result` +#### `run(recovery_task) -> Result` ```rust // How many parallel requests to have going at once. diff --git a/polkadot/roadmap/implementers-guide/src/node/disputes/dispute-coordinator.md b/polkadot/roadmap/implementers-guide/src/node/disputes/dispute-coordinator.md index e0738e219d1..90b29249f3e 100644 --- a/polkadot/roadmap/implementers-guide/src/node/disputes/dispute-coordinator.md +++ b/polkadot/roadmap/implementers-guide/src/node/disputes/dispute-coordinator.md @@ -76,7 +76,7 @@ dispute is raised reconsider their vote and send an explicit invalid vote. If th recorded, then they could avoid a slash. This is not a problem for our basic security assumptions: The backers are the ones to be supposed to have skin in the -game, so we are not too woried about colluding approval voters getting away slash free as the gambler's ruin property is +game, so we are not too worried about colluding approval voters getting away slash free as the gambler's ruin property is maintained anyway. There is however a separate problem, from colluding approval-voters, that is "lazy" approval voters. If it were easy and reliable for approval-voters to reconsider their vote, in case of an actual dispute, then they don't have a direct incentive (apart from playing a part in securing the network) to properly run the validation function at @@ -331,13 +331,13 @@ off-chain. The reason for this is a dispute can be raised for a candidate in a p validator that is going to be slashed for it might not even be in the current active set. That means it can't be disabled on-chain. We need a way to prevent someone from disputing all valid candidates in the previous era. We do this by keeping track of the validators who lost a dispute in the past few sessions and use that list in addition to the -on-chain disabled validators state. In addition to past session misbehavior, this also heps in case a slash is delayed. +on-chain disabled validators state. In addition to past session misbehavior, this also helps in case a slash is delayed. When we receive a dispute statements set, we do the following: 1. Take the on-chain state of disabled validators at the relay parent block. 1. Take a list of those who lost a dispute in that session in the order that prioritizes the biggest and newest offence. 1. Combine the two lists and take the first byzantine threshold validators from it. -1. If the dispute is unconfimed, check if all votes against the candidate are from disabled validators. +1. If the dispute is unconfirmed, check if all votes against the candidate are from disabled validators. If so, we don't participate in the dispute, but record the votes. ### Backing Votes @@ -591,7 +591,7 @@ Initiates processing via the `Participation` module and updates the internal sta ### On `MuxedMessage::Participation` -This message is sent from `Participatuion` module and indicates a processed dispute participation. It's the result of +This message is sent from `Participation` module and indicates a processed dispute participation. It's the result of the processing job initiated with `OverseerSignal::ActiveLeaves`. The subsystem issues a `DisputeMessage` with the result. diff --git a/polkadot/roadmap/implementers-guide/src/node/overseer.md b/polkadot/roadmap/implementers-guide/src/node/overseer.md index 53a11530810..960539b8499 100644 --- a/polkadot/roadmap/implementers-guide/src/node/overseer.md +++ b/polkadot/roadmap/implementers-guide/src/node/overseer.md @@ -108,11 +108,11 @@ way that the receiving subsystem can further address the communication to one of This communication prevents a certain class of race conditions. When the Overseer determines that it is time for subsystems to begin working on top of a particular relay-parent, it will dispatch a `ActiveLeavesUpdate` message to all subsystems to do so, and those messages will be handled asynchronously by those subsystems. Some subsystems will receive -those messsages before others, and it is important that a message sent by subsystem A after receiving +those messages before others, and it is important that a message sent by subsystem A after receiving `ActiveLeavesUpdate` message will arrive at subsystem B after its `ActiveLeavesUpdate` message. If subsystem A maintained an independent channel with subsystem B to communicate, it would be possible for subsystem B to handle the side message before the `ActiveLeavesUpdate` message, but it wouldn't have any logical course of action to take with the -side message - leading to it being discarded or improperly handled. Well-architectured state machines should have a +side message - leading to it being discarded or improperly handled. Well-architected state machines should have a single source of inputs, so that is what we do here. One exception is reasonable to make for responses to requests. A request should be made via the overseer in order to diff --git a/polkadot/roadmap/implementers-guide/src/node/utility/pvf-prechecker.md b/polkadot/roadmap/implementers-guide/src/node/utility/pvf-prechecker.md index 7f6fef7ddf6..f8e88a67fcb 100644 --- a/polkadot/roadmap/implementers-guide/src/node/utility/pvf-prechecker.md +++ b/polkadot/roadmap/implementers-guide/src/node/utility/pvf-prechecker.md @@ -8,7 +8,7 @@ pre-checking. Head over to [overview] for the PVF pre-checking process overview. There is no dedicated input mechanism for PVF pre-checker. Instead, PVF pre-checker looks on the `ActiveLeavesUpdate` event stream for work. -This subsytem does not produce any output messages either. The subsystem will, however, send messages to the +This subsystem does not produce any output messages either. The subsystem will, however, send messages to the [Runtime API] subsystem to query for the pending PVFs and to submit votes. In addition to that, it will also communicate with [Candidate Validation] Subsystem to request PVF pre-check. diff --git a/polkadot/roadmap/implementers-guide/src/runtime/README.md b/polkadot/roadmap/implementers-guide/src/runtime/README.md index 459f0e6b69d..10eedb49ec3 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/README.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/README.md @@ -89,7 +89,7 @@ struct SessionChangeNotification { prev_config: HostConfiguration, // The configuration after handling the session change. new_config: HostConfiguration, - // A secure randomn seed for the session, gathered from BABE. + // A secure random seed for the session, gathered from BABE. random_seed: [u8; 32], // The session index of the beginning session. session_index: SessionIndex, diff --git a/polkadot/roadmap/implementers-guide/src/runtime/hrmp.md b/polkadot/roadmap/implementers-guide/src/runtime/hrmp.md index 69d33ca8670..ed765634b59 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/hrmp.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/hrmp.md @@ -62,7 +62,7 @@ HRMP related storage layout HrmpOpenChannelRequests: map HrmpChannelId => Option; HrmpOpenChannelRequestsList: Vec; -/// This mapping tracks how many open channel requests are inititated by a given sender para. +/// This mapping tracks how many open channel requests are initiated by a given sender para. /// Invariant: `HrmpOpenChannelRequests` should contain the same number of items that has `(X, _)` /// as the number of `HrmpOpenChannelRequestCount` for `X`. HrmpOpenChannelRequestCount: map ParaId => u32; @@ -233,7 +233,7 @@ executed the message. 1. Send a downward message to the opposite party notifying about the channel closing. * The DM is sent using `queue_downward_message`. * The DM is represented by the `HrmpChannelClosing` XCM message with: - * `initator` is set to `origin`, + * `initiator` is set to `origin`, * `sender` is set to `ch.sender`, * `recipient` is set to `ch.recipient`. * The opposite party is `ch.sender` if `origin` is `ch.recipient` and `ch.recipient` if `origin` is `ch.sender`. diff --git a/polkadot/roadmap/implementers-guide/src/runtime/parainherent.md b/polkadot/roadmap/implementers-guide/src/runtime/parainherent.md index 1345f0eea95..7972c706b9e 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/parainherent.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/parainherent.md @@ -88,7 +88,7 @@ to `sanitize_bitfields` function for implementation details. Backed candidates sanitization removes malformed ones, candidates which have got concluded invalid disputes against them or candidates produced by unassigned cores. Furthermore any backing votes from disabled validators for a candidate are dropped. This is part of the validator disabling strategy. After filtering the statements from disabled validators a -backed candidate may end up with votes count less than `minimum_backing_votes` (a parameter from `HostConfiguiration`). +backed candidate may end up with votes count less than `minimum_backing_votes` (a parameter from `HostConfiguration`). In this case the whole candidate is dropped otherwise it will be rejected by `process_candidates` from pallet inclusion. All checks related to backed candidates are implemented in `sanitize_backed_candidates` and `filter_backed_statements_from_disabled_validators`. diff --git a/polkadot/roadmap/implementers-guide/src/types/approval.md b/polkadot/roadmap/implementers-guide/src/types/approval.md index c19ffa53762..29d973ca0ab 100644 --- a/polkadot/roadmap/implementers-guide/src/types/approval.md +++ b/polkadot/roadmap/implementers-guide/src/types/approval.md @@ -39,7 +39,7 @@ enum AssignmentCertKindV2 { /// The core index chosen in this cert. core_index: CoreIndex, }, - /// Deprectated assignment. Soon to be removed. + /// Deprecated assignment. Soon to be removed. /// /// An assignment story based on the VRF that authorized the relay-chain block where the /// candidate was included combined with a sample number. @@ -117,7 +117,7 @@ struct IndirectSignedApprovalVote { ## `CheckedAssignmentCert` An assignment cert which has checked both the VRF and the validity of the implied assignment according to the selection -criteria rules of the protocol. This type should be declared in such a way as to be instantiatable only when the checks +criteria rules of the protocol. This type should be declared in such a way as to be instantiable only when the checks have actually been done. Fields should be accessible via getters, not direct struct access. ```rust diff --git a/polkadot/roadmap/implementers-guide/src/types/disputes.md b/polkadot/roadmap/implementers-guide/src/types/disputes.md index c49e0fea262..ac09084c48a 100644 --- a/polkadot/roadmap/implementers-guide/src/types/disputes.md +++ b/polkadot/roadmap/implementers-guide/src/types/disputes.md @@ -82,7 +82,7 @@ struct DisputeState { struct ScrapedOnChainVotes { /// The session index at which the block was included. session: SessionIndex, - /// The backing and seconding validity attestations for all candidates, provigind the full candidate receipt. + /// The backing and seconding validity attestations for all candidates, providing the full candidate receipt. backing_validators_per_candidate: Vec<(CandidateReceipt, Vec<(ValidatorIndex, ValidityAttestation)>)> /// Set of concluded disputes that were recorded /// on chain within the inherent. diff --git a/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md b/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md index acfe309ba7b..e011afb9708 100644 --- a/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md +++ b/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md @@ -22,7 +22,7 @@ All subsystems have their own message types; all of them need to be able to list are currently two proposals for how to handle that with unified communication channels: 1. Retaining the `OverseerSignal` definition above, add `enum FromOrchestra {Signal(OverseerSignal), Message(T)}`. -1. Add a generic varint to `OverseerSignal`: `Message(T)`. +1. Add a generic variant to `OverseerSignal`: `Message(T)`. Either way, there will be some top-level type encapsulating messages from the overseer to each subsystem. diff --git a/polkadot/roadmap/phase-1.toml b/polkadot/roadmap/phase-1.toml index 3a5f0d752de..9b9374d234b 100644 --- a/polkadot/roadmap/phase-1.toml +++ b/polkadot/roadmap/phase-1.toml @@ -34,7 +34,7 @@ requires = ["two-phase-inclusion"] items = [ { label = "Submit secondary checks to runtime", port = "submitsecondary", requires = ["secondary-checking"] }, { label = "Track all candidates within the slash period as well as their session" }, - { label = "Track reports and attestatations for candidates" }, + { label = "Track reports and attestations for candidates" }, ] [[group]] diff --git a/polkadot/runtime/common/src/xcm_sender.rs b/polkadot/runtime/common/src/xcm_sender.rs index 46d09afcfb2..4bbf6a14a40 100644 --- a/polkadot/runtime/common/src/xcm_sender.rs +++ b/polkadot/runtime/common/src/xcm_sender.rs @@ -139,7 +139,7 @@ where /// Implementation of `xcm_builder::EnsureDelivery` which helps to ensure delivery to the /// `ParaId` parachain (sibling or child). Deposits existential deposit for origin (if needed). /// Deposits estimated fee to the origin account (if needed). -/// Allows to trigger additional logic for specific `ParaId` (e.g. open HRMP channel) (if neeeded). +/// Allows to trigger additional logic for specific `ParaId` (e.g. open HRMP channel) (if needed). #[cfg(feature = "runtime-benchmarks")] pub struct ToParachainDeliveryHelper< XcmConfig, diff --git a/polkadot/runtime/parachains/src/assigner_coretime/tests.rs b/polkadot/runtime/parachains/src/assigner_coretime/tests.rs index 998e39670f9..5d42a9d0c8e 100644 --- a/polkadot/runtime/parachains/src/assigner_coretime/tests.rs +++ b/polkadot/runtime/parachains/src/assigner_coretime/tests.rs @@ -622,7 +622,7 @@ fn assignment_proportions_in_core_state_work() { ); } - // Case 2: Current assignment remaning < step after pop + // Case 2: Current assignment remaining < step after pop { assert_eq!( CoretimeAssigner::pop_assignment_for_core(core_idx), diff --git a/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs b/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs index c47c8745e65..26951f34252 100644 --- a/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs +++ b/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs @@ -684,7 +684,7 @@ where /// Adds an order to the on demand queue. /// - /// Paramenters: + /// Parameters: /// - `location`: Whether to push this entry to the back or the front of the queue. Pushing an /// entry to the front of the queue is only used when the scheduler wants to push back an /// entry it has already popped. @@ -763,7 +763,7 @@ where /// Increases the affinity of a `ParaId` to a specified `CoreIndex`. /// Adds to the count of the `CoreAffinityCount` if an entry is found and the core_index - /// matches. A non-existant entry will be initialized with a count of 1 and uses the supplied + /// matches. A non-existent entry will be initialized with a count of 1 and uses the supplied /// `CoreIndex`. fn increase_affinity(para_id: ParaId, core_index: CoreIndex) { ParaIdAffinity::::mutate(para_id, |maybe_affinity| match maybe_affinity { diff --git a/polkadot/runtime/parachains/src/coretime/migration.rs b/polkadot/runtime/parachains/src/coretime/migration.rs index 03fecc58570..193a5e46b99 100644 --- a/polkadot/runtime/parachains/src/coretime/migration.rs +++ b/polkadot/runtime/parachains/src/coretime/migration.rs @@ -238,7 +238,7 @@ mod v_coretime { return None }, }; - // We assume the coretime chain set this parameter to the recommened value in RFC-1: + // We assume the coretime chain set this parameter to the recommended value in RFC-1: const TIME_SLICE_PERIOD: u32 = 80; let round_up = if valid_until % TIME_SLICE_PERIOD > 0 { 1 } else { 0 }; let time_slice = valid_until / TIME_SLICE_PERIOD + TIME_SLICE_PERIOD * round_up; diff --git a/polkadot/runtime/parachains/src/disputes.rs b/polkadot/runtime/parachains/src/disputes.rs index da95b060c14..cffad42e0ec 100644 --- a/polkadot/runtime/parachains/src/disputes.rs +++ b/polkadot/runtime/parachains/src/disputes.rs @@ -181,7 +181,7 @@ pub trait DisputesHandler { fn is_frozen() -> bool; /// Remove dispute statement duplicates and sort the non-duplicates based on - /// local (lower indicies) vs remotes (higher indices) and age (older with lower indices). + /// local (lower indices) vs remotes (higher indices) and age (older with lower indices). /// /// Returns `Ok(())` if no duplicates were present, `Err(())` otherwise. /// diff --git a/polkadot/runtime/parachains/src/disputes/slashing.rs b/polkadot/runtime/parachains/src/disputes/slashing.rs index 9b2b7a48dc8..9f8fa123918 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing.rs @@ -643,7 +643,7 @@ fn is_known_offence( } } -/// Actual `HandleReports` implemention. +/// Actual `HandleReports` implementation. /// /// When configured properly, should be instantiated with /// `T::KeyOwnerIdentification, Offences, ReportLongevity` parameters. diff --git a/polkadot/runtime/parachains/src/hrmp.rs b/polkadot/runtime/parachains/src/hrmp.rs index 42592d9d9f1..d62533dc919 100644 --- a/polkadot/runtime/parachains/src/hrmp.rs +++ b/polkadot/runtime/parachains/src/hrmp.rs @@ -229,12 +229,12 @@ impl fmt::Debug for OutboundHrmpAcceptanceErr { ), TotalSizeExceeded { idx, total_size, limit } => write!( fmt, - "sending the HRMP message at index {} would exceed the neogitiated channel total size ({} > {})", + "sending the HRMP message at index {} would exceed the negotiated channel total size ({} > {})", idx, total_size, limit, ), CapacityExceeded { idx, count, limit } => write!( fmt, - "sending the HRMP message at index {} would exceed the neogitiated channel capacity ({} > {})", + "sending the HRMP message at index {} would exceed the negotiated channel capacity ({} > {})", idx, count, limit, ), } @@ -790,7 +790,7 @@ pub mod pallet { .ok_or(ArithmeticError::Underflow)?; T::Currency::unreserve( &channel_id.sender.into_account_truncating(), - // The difference should always be convertable into `Balance`, but be + // The difference should always be convertible into `Balance`, but be // paranoid and do nothing in case. amount.try_into().unwrap_or(Zero::zero()), ); diff --git a/polkadot/runtime/parachains/src/hrmp/tests.rs b/polkadot/runtime/parachains/src/hrmp/tests.rs index 7e7b67c8059..162c1412160 100644 --- a/polkadot/runtime/parachains/src/hrmp/tests.rs +++ b/polkadot/runtime/parachains/src/hrmp/tests.rs @@ -702,7 +702,7 @@ fn verify_externally_accessible() { sp_io::storage::get(&well_known_keys::hrmp_ingress_channel_index(para_b)) .expect("the ingress index must be present for para_b"); let ingress_index = >::decode(&mut &raw_ingress_index[..]) - .expect("ingress indexx should be decodable as a list of para ids"); + .expect("ingress index should be decodable as a list of para ids"); assert_eq!(ingress_index, vec![para_a]); // Now, verify that we can access and decode the egress index. diff --git a/polkadot/runtime/parachains/src/paras/mod.rs b/polkadot/runtime/parachains/src/paras/mod.rs index 5acdb9683bb..017cd87f13b 100644 --- a/polkadot/runtime/parachains/src/paras/mod.rs +++ b/polkadot/runtime/parachains/src/paras/mod.rs @@ -1756,7 +1756,7 @@ impl Pallet { // // - Empty value is treated as the current code is already inserted during the onboarding. // - // This is only an intermediate solution and should be fixed in foreseable future. + // This is only an intermediate solution and should be fixed in foreseeable future. // // [soaking issue]: https://github.com/paritytech/polkadot/issues/3918 let validation_code = diff --git a/polkadot/runtime/parachains/src/paras/tests.rs b/polkadot/runtime/parachains/src/paras/tests.rs index 262ec9d3fdb..39abd2367b7 100644 --- a/polkadot/runtime/parachains/src/paras/tests.rs +++ b/polkadot/runtime/parachains/src/paras/tests.rs @@ -1210,7 +1210,7 @@ fn code_hash_at_returns_up_to_end_of_code_retention_period() { assert_eq!(Paras::past_code_meta(¶_id).upgrade_times, vec![upgrade_at(4, 10)]); assert_eq!(Paras::current_code(¶_id), Some(new_code.clone())); - // Make sure that the old code is available **before** the code retion period passes. + // Make sure that the old code is available **before** the code retention period passes. run_to_block(10 + code_retention_period, None); assert_eq!(Paras::code_by_hash(&old_code.hash()), Some(old_code.clone())); assert_eq!(Paras::code_by_hash(&new_code.hash()), Some(new_code.clone())); @@ -1717,7 +1717,7 @@ fn poke_unused_validation_code_doesnt_remove_code_with_users() { #[test] fn increase_code_ref_doesnt_have_allergy_on_add_trusted_validation_code() { - // Verify that accidential calling of increase_code_ref or decrease_code_ref does not lead + // Verify that accidental calling of increase_code_ref or decrease_code_ref does not lead // to a disaster. // NOTE that this test is extra paranoid, as it is not really possible to hit // `decrease_code_ref` without calling `increase_code_ref` first. diff --git a/polkadot/runtime/parachains/src/paras_inherent/mod.rs b/polkadot/runtime/parachains/src/paras_inherent/mod.rs index 02ddfd0acca..6a20a10a8d7 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/mod.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/mod.rs @@ -733,7 +733,7 @@ fn random_sel Weight>( /// are preferred. And for disputes, local and older disputes are preferred (see /// `limit_and_sanitize_disputes`). for backed candidates, since with a increasing number of /// parachains their chances of inclusion become slim. All backed candidates are checked -/// beforehands in `fn create_inherent_inner` which guarantees sanity. +/// beforehand in `fn create_inherent_inner` which guarantees sanity. /// /// Assumes disputes are already filtered by the time this is called. /// @@ -1070,7 +1070,7 @@ fn limit_and_sanitize_disputes< log::debug!(target: LOG_TARGET, "Above max consumable weight: {}/{}", disputes_weight, max_consumable_weight); let mut checked_acc = Vec::::with_capacity(disputes.len()); - // Accumualated weight of all disputes picked, that passed the checks. + // Accumulated weight of all disputes picked, that passed the checks. let mut weight_acc = Weight::zero(); // Select disputes in-order until the remaining weight is attained diff --git a/polkadot/runtime/parachains/src/scheduler/migration.rs b/polkadot/runtime/parachains/src/scheduler/migration.rs index 4c0a07d7367..c47fbab046f 100644 --- a/polkadot/runtime/parachains/src/scheduler/migration.rs +++ b/polkadot/runtime/parachains/src/scheduler/migration.rs @@ -24,7 +24,7 @@ use frame_support::{ /// Old/legacy assignment representation (v0). /// -/// `Assignment` used to be a concrete type with the same layout V0Assignment, idential on all +/// `Assignment` used to be a concrete type with the same layout V0Assignment, identical on all /// assignment providers. This can be removed once storage has been migrated. #[derive(Encode, Decode, RuntimeDebug, TypeInfo, PartialEq, Clone)] struct V0Assignment { diff --git a/polkadot/runtime/parachains/src/scheduler/tests.rs b/polkadot/runtime/parachains/src/scheduler/tests.rs index e6a1e66b3a5..720f645e3bd 100644 --- a/polkadot/runtime/parachains/src/scheduler/tests.rs +++ b/polkadot/runtime/parachains/src/scheduler/tests.rs @@ -836,7 +836,7 @@ fn on_demand_claims_are_pruned_after_timing_out() { // #26 now += 1; - // Run to block #n but this time have group 1 conclude the availabilty. + // Run to block #n but this time have group 1 conclude the availability. for n in now..=(now + max_timeouts + 1) { // #n run_to_block(n, |_| None); diff --git a/polkadot/runtime/parachains/src/session_info.rs b/polkadot/runtime/parachains/src/session_info.rs index 9e1b3d05842..4ca5a73d42b 100644 --- a/polkadot/runtime/parachains/src/session_info.rs +++ b/polkadot/runtime/parachains/src/session_info.rs @@ -158,7 +158,7 @@ impl Pallet { for idx in old_earliest_stored_session..new_earliest_stored_session { Sessions::::remove(&idx); // Idx will be missing for a few sessions after the runtime upgrade. - // But it shouldn'be be a problem. + // But it shouldn't be a problem. AccountKeys::::remove(&idx); SessionExecutorParams::::remove(&idx); } diff --git a/polkadot/runtime/parachains/src/ump_tests.rs b/polkadot/runtime/parachains/src/ump_tests.rs index 2ed1d64336b..5867a8fca66 100644 --- a/polkadot/runtime/parachains/src/ump_tests.rs +++ b/polkadot/runtime/parachains/src/ump_tests.rs @@ -456,7 +456,7 @@ fn verify_relay_dispatch_queue_size_is_externally_accessible() { fn assert_queue_size(para: ParaId, count: u32, size: u32) { #[allow(deprecated)] let raw_queue_size = sp_io::storage::get(&well_known_keys::relay_dispatch_queue_size(para)).expect( - "enqueing a message should create the dispatch queue\ + "enqueuing a message should create the dispatch queue\ and it should be accessible via the well known keys", ); let (c, s) = <(u32, u32)>::decode(&mut &raw_queue_size[..]) @@ -466,7 +466,7 @@ fn assert_queue_size(para: ParaId, count: u32, size: u32) { // Test the deprecated but at least type-safe `relay_dispatch_queue_size_typed`: #[allow(deprecated)] let (c, s) = well_known_keys::relay_dispatch_queue_size_typed(para).get().expect( - "enqueing a message should create the dispatch queue\ + "enqueuing a message should create the dispatch queue\ and it should be accessible via the well known keys", ); assert_eq!((c, s), (count, size)); diff --git a/polkadot/runtime/rococo/README.md b/polkadot/runtime/rococo/README.md index 5b2c296f0ce..c19c3654fe4 100644 --- a/polkadot/runtime/rococo/README.md +++ b/polkadot/runtime/rococo/README.md @@ -4,7 +4,7 @@ Rococo is a testnet runtime with no stability guarantees. ## How to build `rococo` runtime `EpochDurationInBlocks` parameter is configurable via `ROCOCO_EPOCH_DURATION` environment variable. To build wasm -runtime blob with customized epoch duration the following command shall be exectuted: +runtime blob with customized epoch duration the following command shall be executed: ```bash ROCOCO_EPOCH_DURATION=10 ./polkadot/scripts/build-only-wasm.sh rococo-runtime /path/to/output/directory/ ``` diff --git a/polkadot/runtime/westend/src/weights/xcm/mod.rs b/polkadot/runtime/westend/src/weights/xcm/mod.rs index 0162012825f..09e883a9f7a 100644 --- a/polkadot/runtime/westend/src/weights/xcm/mod.rs +++ b/polkadot/runtime/westend/src/weights/xcm/mod.rs @@ -142,7 +142,7 @@ impl XcmWeightInfo for WestendXcmWeight { fn descend_origin(_who: &InteriorLocation) -> Weight { XcmGeneric::::descend_origin() } - fn report_error(_query_repsonse_info: &QueryResponseInfo) -> Weight { + fn report_error(_query_response_info: &QueryResponseInfo) -> Weight { XcmGeneric::::report_error() } diff --git a/polkadot/tests/common.rs b/polkadot/tests/common.rs index 15721c990e0..dbee2d36503 100644 --- a/polkadot/tests/common.rs +++ b/polkadot/tests/common.rs @@ -48,8 +48,8 @@ pub async fn wait_n_finalized_blocks(n: usize, url: &str) { /// Read the WS address from the output. /// -/// This is hack to get the actual binded sockaddr because -/// polkadot assigns a random port if the specified port was already binded. +/// This is hack to get the actual bound sockaddr because +/// polkadot assigns a random port if the specified port was already bound. /// /// You must call /// `Command::new("cmd").stdout(process::Stdio::piped()).stderr(process::Stdio::piped())` diff --git a/polkadot/tests/running_the_node_and_interrupt.rs b/polkadot/tests/running_the_node_and_interrupt.rs index 079c34e0421..85c073d3023 100644 --- a/polkadot/tests/running_the_node_and_interrupt.rs +++ b/polkadot/tests/running_the_node_and_interrupt.rs @@ -32,7 +32,7 @@ async fn running_the_node_works_and_can_be_interrupted() { }; async fn run_command_and_kill(signal: Signal) { - let tmpdir = tempdir().expect("coult not create temp dir"); + let tmpdir = tempdir().expect("could not create temp dir"); let mut cmd = Command::new(cargo_bin("polkadot")) .stdout(process::Stdio::piped()) diff --git a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs index 7752d1355cd..92d23cfd281 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs @@ -248,7 +248,7 @@ fn reserve_transfer_assets_with_paid_router_works() { pub(crate) fn set_up_foreign_asset( reserve_para_id: u32, inner_junction: Option, - benficiary: AccountId, + beneficiary: AccountId, initial_amount: u128, is_sufficient: bool, ) -> (Location, AccountId, Location) { @@ -276,7 +276,7 @@ pub(crate) fn set_up_foreign_asset( assert_ok!(AssetsPallet::mint( RuntimeOrigin::signed(BOB), foreign_asset_id_location.clone(), - benficiary, + beneficiary, initial_amount )); diff --git a/polkadot/xcm/src/v2/multilocation.rs b/polkadot/xcm/src/v2/multilocation.rs index 60aa1f6cead..ac98da8d08c 100644 --- a/polkadot/xcm/src/v2/multilocation.rs +++ b/polkadot/xcm/src/v2/multilocation.rs @@ -176,7 +176,7 @@ impl MultiLocation { } /// Consumes `self` and returns a `MultiLocation` suffixed with `new`, or an `Err` with - /// theoriginal value of `self` in case of overflow. + /// the original value of `self` in case of overflow. pub fn pushed_with_interior(self, new: Junction) -> result::Result { match self.interior.pushed_with(new) { Ok(i) => Ok(MultiLocation { interior: i, parents: self.parents }), diff --git a/polkadot/xcm/src/v3/multilocation.rs b/polkadot/xcm/src/v3/multilocation.rs index c588b924ac7..18fe01ec8fa 100644 --- a/polkadot/xcm/src/v3/multilocation.rs +++ b/polkadot/xcm/src/v3/multilocation.rs @@ -205,7 +205,7 @@ impl MultiLocation { } /// Consumes `self` and returns a `MultiLocation` suffixed with `new`, or an `Err` with - /// theoriginal value of `self` in case of overflow. + /// the original value of `self` in case of overflow. pub fn pushed_with_interior( self, new: impl Into, diff --git a/polkadot/xcm/src/v4/location.rs b/polkadot/xcm/src/v4/location.rs index db55c3d3034..0e7c69864fa 100644 --- a/polkadot/xcm/src/v4/location.rs +++ b/polkadot/xcm/src/v4/location.rs @@ -210,7 +210,7 @@ impl Location { } /// Consumes `self` and returns a `Location` suffixed with `new`, or an `Err` with - /// theoriginal value of `self` in case of overflow. + /// the original value of `self` in case of overflow. pub fn pushed_with_interior( self, new: impl Into, diff --git a/polkadot/xcm/xcm-builder/src/barriers.rs b/polkadot/xcm/xcm-builder/src/barriers.rs index 80411ab5a22..b8923a4d5c6 100644 --- a/polkadot/xcm/xcm-builder/src/barriers.rs +++ b/polkadot/xcm/xcm-builder/src/barriers.rs @@ -142,7 +142,7 @@ impl> ShouldExecute for AllowTopLevelPaidExecutionFrom /// In the above example, `AllowUnpaidExecutionFrom` appears once underneath /// `WithComputedOrigin`. This is in order to distinguish between messages which are notionally /// from a derivative location of `ParentLocation` but that just happened to be sent via -/// `ParentLocaction` rather than messages that were sent by the parent. +/// `ParentLocation` rather than messages that were sent by the parent. /// /// Similarly `AllowTopLevelPaidExecutionFrom` appears twice: once inside of `WithComputedOrigin` /// where we provide the list of origins which are derivative origins, and then secondly outside diff --git a/polkadot/xcm/xcm-builder/src/tests/origins.rs b/polkadot/xcm/xcm-builder/src/tests/origins.rs index c717d1e2af8..b6a1a9f1052 100644 --- a/polkadot/xcm/xcm-builder/src/tests/origins.rs +++ b/polkadot/xcm/xcm-builder/src/tests/origins.rs @@ -80,8 +80,8 @@ fn universal_origin_should_work() { fn export_message_should_work() { // Bridge chain (assumed to be Relay) lets Parachain #1 have message execution for free. AllowUnpaidFrom::set(vec![[Parachain(1)].into()]); - // Local parachain #1 issues a transfer asset on Polkadot Relay-chain, transfering 100 Planck to - // Polkadot parachain #2. + // Local parachain #1 issues a transfer asset on Polkadot Relay-chain, transferring 100 Planck + // to Polkadot parachain #2. let expected_message = Xcm(vec![TransferAsset { assets: (Here, 100u128).into(), beneficiary: Parachain(2).into(), diff --git a/polkadot/xcm/xcm-builder/tests/scenarios.rs b/polkadot/xcm/xcm-builder/tests/scenarios.rs index db37f85acdb..ee1aeffbb4e 100644 --- a/polkadot/xcm/xcm-builder/tests/scenarios.rs +++ b/polkadot/xcm/xcm-builder/tests/scenarios.rs @@ -132,7 +132,7 @@ fn report_holding_works() { assets: AllCounted(1).into(), beneficiary: OnlyChild.into(), // invalid destination }, - // is not triggered becasue the deposit fails + // is not triggered because the deposit fails ReportHolding { response_info: response_info.clone(), assets: All.into() }, ]); let mut hash = fake_message_hash(&message); diff --git a/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs b/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs index da7fc0d9782..1d1ee40d092 100644 --- a/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs +++ b/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs @@ -328,7 +328,7 @@ fn query_response_elicits_handler() { /// Simulates a cross-chain message from Parachain to Parachain through Relay Chain /// that deposits assets into the reserve of the destination. -/// Regression test for `DepostiReserveAsset` changes in +/// Regression test for `DepositReserveAsset` changes in /// #[test] fn deposit_reserve_asset_works_for_any_xcm_sender() { diff --git a/polkadot/xcm/xcm-executor/src/traits/should_execute.rs b/polkadot/xcm/xcm-executor/src/traits/should_execute.rs index 449e82b5a6e..12e8fd6b87f 100644 --- a/polkadot/xcm/xcm-executor/src/traits/should_execute.rs +++ b/polkadot/xcm/xcm-executor/src/traits/should_execute.rs @@ -18,7 +18,7 @@ use frame_support::traits::ProcessMessageError; use sp_std::result::Result; use xcm::latest::{Instruction, Location, Weight, XcmHash}; -/// Properyies of an XCM message and its imminent execution. +/// Properties of an XCM message and its imminent execution. #[derive(Clone, Eq, PartialEq, Debug)] pub struct Properties { /// The amount of weight that the system has determined this diff --git a/polkadot/xcm/xcm-simulator/example/src/lib.rs b/polkadot/xcm/xcm-simulator/example/src/lib.rs index d134957fbc1..13210179e91 100644 --- a/polkadot/xcm/xcm-simulator/example/src/lib.rs +++ b/polkadot/xcm/xcm-simulator/example/src/lib.rs @@ -424,7 +424,7 @@ mod tests { /// Scenario: /// The relay-chain transfers an NFT into a parachain's sovereign account, who then mints a - /// trustless-backed-derivated locally. + /// trustless-backed-derived locally. /// /// Asserts that the parachain accounts are updated as expected. #[test] @@ -479,7 +479,7 @@ mod tests { assert_ok!(ParachainPalletXcm::send_xcm(alice, Parent, message)); }); ParaA::execute_with(|| { - log::debug!(target: "xcm-exceutor", "Hello"); + log::debug!(target: "xcm-executor", "Hello"); assert_eq!( parachain::ForeignUniques::owner((Parent, GeneralIndex(2)).into(), 69u32.into()), Some(ALICE), diff --git a/prdoc/pr_3808.prdoc b/prdoc/pr_3808.prdoc new file mode 100644 index 00000000000..9b50f721df3 --- /dev/null +++ b/prdoc/pr_3808.prdoc @@ -0,0 +1,20 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Fix spelling mistakes in source code + +doc: + - audience: Node Operator + description: | + Some spelling mistakes in log output, error messages and tracing (prometheus/grafana) have been fixed. + - audience: Runtime Dev + description: | + Public crate changes: + - The public trait `RuntimeParameterStore` in `substrate/frame/support` had the associated type renamed from `AggregratedKeyValue` to `AggregatedKeyValue`. + - The public trait `AggregratedKeyValue` in `substrate/frame/support` was similarly renamed to `AggregatedKeyValue`. + - The public methods `test_versioning` and `test_versioning_register_only` of the `TestApi` trait in `substrate/primitives/runtime-interface/test-wasm` had the spelling of `versionning` changed to `versioning`. + - The public functions `read_trie_first_descendant_value` and `read_child_trie_first_descendant_value` in `substrate/primitives/trie` had the spelling of `descedant` changed to `descendant`. +crates: + - name: frame-support + - name: sp-runtime-interface-test-wasm + - name: sp-trie diff --git a/scripts/bridges_update_subtree.sh b/scripts/bridges_update_subtree.sh index 5c5c7a322a1..2cd6d968d2b 100755 --- a/scripts/bridges_update_subtree.sh +++ b/scripts/bridges_update_subtree.sh @@ -1,6 +1,6 @@ #!/bin/bash -# A script to udpate bridges repo as subtree to Cumulus +# A script to update bridges repo as subtree to Cumulus # Usage: # ./scripts/bridges_update_subtree.sh fetch # ./scripts/bridges_update_subtree.sh patch diff --git a/scripts/snowbridge_update_subtree.sh b/scripts/snowbridge_update_subtree.sh index 2276bb35469..c572eaa18fa 100755 --- a/scripts/snowbridge_update_subtree.sh +++ b/scripts/snowbridge_update_subtree.sh @@ -1,6 +1,6 @@ #!/bin/bash -# A script to udpate bridges repo as subtree to Cumulus +# A script to update bridges repo as subtree to Cumulus # Usage: # ./scripts/update_subtree_snowbridge.sh fetch # ./scripts/update_subtree_snowbridge.sh patch diff --git a/substrate/bin/node/cli/benches/block_production.rs b/substrate/bin/node/cli/benches/block_production.rs index 23a62cc0bd2..d04780d5f95 100644 --- a/substrate/bin/node/cli/benches/block_production.rs +++ b/substrate/bin/node/cli/benches/block_production.rs @@ -145,7 +145,7 @@ fn prepare_benchmark(client: &FullClient) -> (usize, Vec) { let src = Sr25519Keyring::Alice.pair(); let dst: MultiAddress = Sr25519Keyring::Bob.to_account_id().into(); - // Add as many tranfer extrinsics as possible into a single block. + // Add as many transfer extrinsics as possible into a single block. for nonce in 0.. { let extrinsic: OpaqueExtrinsic = create_extrinsic( client, @@ -179,7 +179,7 @@ fn block_production(c: &mut Criterion) { let node = new_node(tokio_handle.clone()); let client = &*node.client; - // Buliding the very first block is around ~30x slower than any subsequent one, + // Building the very first block is around ~30x slower than any subsequent one, // so let's make sure it's built and imported before we benchmark anything. let mut block_builder = BlockBuilderBuilder::new(client) .on_parent_block(client.chain_info().best_hash) diff --git a/substrate/bin/node/cli/src/cli.rs b/substrate/bin/node/cli/src/cli.rs index 3345afae4fd..56fbed51f8a 100644 --- a/substrate/bin/node/cli/src/cli.rs +++ b/substrate/bin/node/cli/src/cli.rs @@ -49,7 +49,7 @@ pub struct Cli { /// Possible subcommands of the main binary. #[derive(Debug, clap::Subcommand)] pub enum Subcommand { - /// The custom inspect subcommmand for decoding blocks and extrinsics. + /// The custom inspect subcommand for decoding blocks and extrinsics. #[command( name = "inspect", about = "Decode given block or extrinsic using current native runtime." diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index e4b425e6f96..dddb261a71d 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -53,7 +53,7 @@ pub type HostFunctions = ( frame_benchmarking::benchmarking::HostFunctions, ); -/// A specialized `WasmExecutor` intended to use accross substrate node. It provides all required +/// A specialized `WasmExecutor` intended to use across substrate node. It provides all required /// HostFunctions. pub type RuntimeExecutor = sc_executor::WasmExecutor; diff --git a/substrate/bin/node/cli/tests/fees.rs b/substrate/bin/node/cli/tests/fees.rs index 8c7b3c87315..69c96bf63a6 100644 --- a/substrate/bin/node/cli/tests/fees.rs +++ b/substrate/bin/node/cli/tests/fees.rs @@ -135,7 +135,7 @@ fn transaction_fee_is_correct() { // if weight of the cheapest weight would be 10^7, this would be 10^9, which is: // - 1 MILLICENTS in substrate node. // - 1 milli-dot based on current polkadot runtime. - // (this baed on assigning 0.1 CENT to the cheapest tx with `weight = 100`) + // (this based on assigning 0.1 CENT to the cheapest tx with `weight = 100`) let mut t = new_test_ext(compact_code_unwrap()); t.insert(>::hashed_key_for(alice()), new_account_info(100)); t.insert(>::hashed_key_for(bob()), new_account_info(10)); diff --git a/substrate/bin/node/testing/src/bench.rs b/substrate/bin/node/testing/src/bench.rs index df302a6453b..e5c2563905e 100644 --- a/substrate/bin/node/testing/src/bench.rs +++ b/substrate/bin/node/testing/src/bench.rs @@ -84,7 +84,7 @@ impl BenchPair { /// Drop system cache. /// -/// Will panic if cache drop is impossbile. +/// Will panic if cache drop is impossible. pub fn drop_system_cache() { #[cfg(target_os = "windows")] { @@ -173,7 +173,7 @@ impl Clone for BenchDb { // We clear system cache after db clone but before any warmups. // This populates system cache with some data unrelated to actual - // data we will be quering further under benchmark (like what + // data we will be querying further under benchmark (like what // would have happened in real system that queries random entries // from database). drop_system_cache(); @@ -443,7 +443,7 @@ impl BenchDb { BlockContentIterator::new(content, &self.keyring, client) } - /// Get cliet for this database operations. + /// Get client for this database operations. pub fn client(&mut self) -> Client { let (client, _backend, _task_executor) = Self::bench_client(self.database_type, self.directory_guard.path(), &self.keyring); diff --git a/substrate/bin/utils/chain-spec-builder/src/lib.rs b/substrate/bin/utils/chain-spec-builder/src/lib.rs index 8c78030c885..dbd0437921f 100644 --- a/substrate/bin/utils/chain-spec-builder/src/lib.rs +++ b/substrate/bin/utils/chain-spec-builder/src/lib.rs @@ -185,7 +185,7 @@ pub struct ConvertToRawCmd { /// Verifies the provided input chain spec. /// /// Silently checks if given input chain spec can be converted to raw. It allows to check if all -/// RuntimeGenesisConfig fiels are properly initialized and if the json does not contain invalid +/// RuntimeGenesisConfig fields are properly initialized and if the json does not contain invalid /// fields. #[derive(Parser, Debug, Clone)] pub struct VerifyCmd { diff --git a/substrate/bin/utils/subkey/README.md b/substrate/bin/utils/subkey/README.md index a5f27cfd370..fc1053e232d 100644 --- a/substrate/bin/utils/subkey/README.md +++ b/substrate/bin/utils/subkey/README.md @@ -77,7 +77,7 @@ below can be derived from those secrets. The output above also show the **public key** and the **Account ID**. Those are the independent from the network where you will use the key. -The **SS58 address** (or **Public Address**) of a new account is a reprensentation of the public keys of an account for +The **SS58 address** (or **Public Address**) of a new account is a representation of the public keys of an account for a given network (for instance Kusama or Polkadot). You can read more about the [SS58 format in the Substrate Docs](https://docs.substrate.io/reference/address-formats/) @@ -143,7 +143,7 @@ Secret phrase `soup lyrics media market way crouch elevator put moon useful ques SS58 Address: 5He5pZpc7AJ8evPuab37vJF6KkFDqq9uDq2WXh877Qw6iaVC ``` -Using the `inspect` command (see more details below), we see that knowning only the **secret seed** is no longer +Using the `inspect` command (see more details below), we see that knowing only the **secret seed** is no longer sufficient to recover the account: ```bash diff --git a/substrate/bin/utils/subkey/src/lib.rs b/substrate/bin/utils/subkey/src/lib.rs index f3023acde40..33f28ef46a5 100644 --- a/substrate/bin/utils/subkey/src/lib.rs +++ b/substrate/bin/utils/subkey/src/lib.rs @@ -94,10 +94,10 @@ //! seed** (also called **Private Key**). Those 2 secrets are the pieces of information you MUST //! keep safe and secret. All the other information below can be derived from those secrets. //! -//! The output above also show the **public key** and the **Account ID**. Those are the independant +//! The output above also show the **public key** and the **Account ID**. Those are the independent //! from the network where you will use the key. //! -//! The **SS58 address** (or **Public Address**) of a new account is a reprensentation of the public +//! The **SS58 address** (or **Public Address**) of a new account is a representation of the public //! keys of an account for a given network (for instance Kusama or Polkadot). //! //! You can read more about the [SS58 format in the Substrate Docs](https://docs.substrate.io/reference/address-formats/) and see the list of reserved prefixes in the [SS58 Registry](https://github.com/paritytech/ss58-registry). @@ -110,7 +110,7 @@ //! //! ### Json output //! -//! `subkey` can calso generate the output as *json*. This is useful for automation. +//! `subkey` can also generate the output as *json*. This is useful for automation. //! //! command: //! @@ -163,7 +163,7 @@ //! SS58 Address: 5He5pZpc7AJ8evPuab37vJF6KkFDqq9uDq2WXh877Qw6iaVC //! ``` //! -//! Using the `inspect` command (see more details below), we see that knowning only the **secret +//! Using the `inspect` command (see more details below), we see that knowing only the **secret //! seed** is no longer sufficient to recover the account: //! //! ```bash @@ -184,7 +184,7 @@ //! //! ### Inspecting a key //! -//! If you have *some data* about a key, `subkey inpsect` will help you discover more information +//! If you have *some data* about a key, `subkey inspect` will help you discover more information //! about it. //! //! If you have **secrets** that you would like to verify for instance, you can use: diff --git a/substrate/client/basic-authorship/src/basic_authorship.rs b/substrate/client/basic-authorship/src/basic_authorship.rs index 932287ac865..1519c76c42c 100644 --- a/substrate/client/basic-authorship/src/basic_authorship.rs +++ b/substrate/client/basic-authorship/src/basic_authorship.rs @@ -180,7 +180,7 @@ impl ProposerFactory { /// The soft deadline indicates where we should stop attempting to add transactions /// to the block, which exhaust resources. After soft deadline is reached, /// we switch to a fixed-amount mode, in which after we see `MAX_SKIPPED_TRANSACTIONS` - /// transactions which exhaust resrouces, we will conclude that the block is full. + /// transactions which exhaust resources, we will conclude that the block is full. /// /// Setting the value too low will significantly limit the amount of transactions /// we try in case they exhaust resources. Setting the value too high can diff --git a/substrate/client/chain-spec/src/chain_spec.rs b/substrate/client/chain-spec/src/chain_spec.rs index 78e81e10d2b..4ec8527de26 100644 --- a/substrate/client/chain-spec/src/chain_spec.rs +++ b/substrate/client/chain-spec/src/chain_spec.rs @@ -52,7 +52,7 @@ enum GenesisSource { File(PathBuf), Binary(Cow<'static, [u8]>), /// factory function + code - //Factory and G type parameter shall be removed togheter with `ChainSpec::from_genesis` + //Factory and G type parameter shall be removed together with `ChainSpec::from_genesis` Factory(Arc G + Send + Sync>, Vec), Storage(Storage), /// build action + code @@ -264,7 +264,7 @@ struct RuntimeInnerWrapper { enum Genesis { /// (Deprecated) Contains the JSON representation of G (the native type representing the /// runtime's `RuntimeGenesisConfig` struct) (will be removed with `ChainSpec::from_genesis`) - /// without the runtime code. It is required to deserialize the legacy chainspecs genereted + /// without the runtime code. It is required to deserialize the legacy chainspecs generated /// with `ChainsSpec::from_genesis` method. Runtime(G), /// (Deprecated) Contains the JSON representation of G (the native type representing the @@ -276,13 +276,13 @@ enum Genesis { Raw(RawGenesis), /// State root hash of the genesis storage. StateRootHash(StorageData), - /// Represents the runtime genesis config in JSON format toghether with runtime code. + /// Represents the runtime genesis config in JSON format together with runtime code. RuntimeGenesis(RuntimeGenesisInner), } /// A configuration of a client. Does not include runtime storage initialization. /// Note: `genesis` field is ignored due to way how the chain specification is serialized into -/// JSON file. Refer to [`ChainSpecJsonContainer`], which flattens [`ClientSpec`] and denies uknown +/// JSON file. Refer to [`ChainSpecJsonContainer`], which flattens [`ClientSpec`] and denies unknown /// fields. #[derive(Serialize, Deserialize, Clone, Debug)] #[serde(rename_all = "camelCase")] @@ -508,7 +508,7 @@ impl ChainSpec { self.client_spec.fork_id.as_deref() } - /// Additional loosly-typed properties of the chain. + /// Additional loosely-typed properties of the chain. /// /// Returns an empty JSON object if 'properties' not defined in config pub fn properties(&self) -> Properties { diff --git a/substrate/client/chain-spec/src/extension.rs b/substrate/client/chain-spec/src/extension.rs index f2939741535..d1f03539349 100644 --- a/substrate/client/chain-spec/src/extension.rs +++ b/substrate/client/chain-spec/src/extension.rs @@ -284,7 +284,7 @@ where } } -/// A subset of the `Extension` trait that only allows for quering extensions. +/// A subset of the `Extension` trait that only allows for querying extensions. pub trait GetExtension { /// Get an extension of specific type. fn get_any(&self, t: TypeId) -> &dyn Any; diff --git a/substrate/client/chain-spec/src/genesis_config_builder.rs b/substrate/client/chain-spec/src/genesis_config_builder.rs index c8b54f66be6..61f065e213c 100644 --- a/substrate/client/chain-spec/src/genesis_config_builder.rs +++ b/substrate/client/chain-spec/src/genesis_config_builder.rs @@ -33,7 +33,7 @@ use std::borrow::Cow; /// A utility that facilitates calling the GenesisBuilder API from the runtime wasm code blob. /// /// `EHF` type allows to specify the extended host function required for building runtime's genesis -/// config. The type will be compbined with default `sp_io::SubstrateHostFunctions`. +/// config. The type will be combined with default `sp_io::SubstrateHostFunctions`. pub struct GenesisConfigBuilderRuntimeCaller<'a, EHF = ()> where EHF: HostFunctions, diff --git a/substrate/client/chain-spec/src/lib.rs b/substrate/client/chain-spec/src/lib.rs index eab5f789f29..e8b87a60404 100644 --- a/substrate/client/chain-spec/src/lib.rs +++ b/substrate/client/chain-spec/src/lib.rs @@ -393,7 +393,7 @@ pub trait ChainSpec: BuildStorage + Send + Sync { fn protocol_id(&self) -> Option<&str>; /// Optional network fork identifier. `None` by default. fn fork_id(&self) -> Option<&str>; - /// Additional loosly-typed properties of the chain. + /// Additional loosely-typed properties of the chain. /// /// Returns an empty JSON object if 'properties' not defined in config fn properties(&self) -> Properties; diff --git a/substrate/client/cli/src/commands/vanity.rs b/substrate/client/cli/src/commands/vanity.rs index ce751613298..330a59493ef 100644 --- a/substrate/client/cli/src/commands/vanity.rs +++ b/substrate/client/cli/src/commands/vanity.rs @@ -51,7 +51,7 @@ pub struct VanityCmd { impl VanityCmd { /// Run the command pub fn run(&self) -> error::Result<()> { - let formated_seed = with_crypto_scheme!( + let formatted_seed = with_crypto_scheme!( self.crypto_scheme.scheme, generate_key( &self.pattern, @@ -62,7 +62,7 @@ impl VanityCmd { with_crypto_scheme!( self.crypto_scheme.scheme, print_from_uri( - &formated_seed, + &formatted_seed, None, self.network_scheme.network, self.output_scheme.output_type, diff --git a/substrate/client/cli/src/params/network_params.rs b/substrate/client/cli/src/params/network_params.rs index 12f19df2a68..94efb428091 100644 --- a/substrate/client/cli/src/params/network_params.rs +++ b/substrate/client/cli/src/params/network_params.rs @@ -310,7 +310,7 @@ mod tests { } #[test] - fn sync_ingores_case() { + fn sync_ignores_case() { let params = Cli::try_parse_from(["", "--sync", "wArP"]).expect("Parses network params"); assert_eq!(SyncMode::Warp, params.network_params.sync); diff --git a/substrate/client/consensus/aura/src/lib.rs b/substrate/client/consensus/aura/src/lib.rs index 1be7be8eeea..e220aaac508 100644 --- a/substrate/client/consensus/aura/src/lib.rs +++ b/substrate/client/consensus/aura/src/lib.rs @@ -82,7 +82,7 @@ pub enum CompatibilityMode { None, /// Call `initialize_block` before doing any runtime calls. /// - /// Previously the node would execute `initialize_block` before fetchting the authorities + /// Previously the node would execute `initialize_block` before fetching the authorities /// from the runtime. This behaviour changed in: /// /// By calling `initialize_block` before fetching the authorities, on a block that diff --git a/substrate/client/consensus/babe/src/authorship.rs b/substrate/client/consensus/babe/src/authorship.rs index 11f5233abc6..57ee706a04f 100644 --- a/substrate/client/consensus/babe/src/authorship.rs +++ b/substrate/client/consensus/babe/src/authorship.rs @@ -59,7 +59,7 @@ pub(super) fn calculate_primary_threshold( assert!(theta > 0.0, "authority with weight 0."); // NOTE: in the equation `p = 1 - (1 - c)^theta` the value of `p` is always - // capped by `c`. For all pratical purposes `c` should always be set to a + // capped by `c`. For all practical purposes `c` should always be set to a // value < 0.5, as such in the computations below we should never be near // edge cases like `0.999999`. diff --git a/substrate/client/consensus/babe/src/lib.rs b/substrate/client/consensus/babe/src/lib.rs index ccf72939631..d10bdd8c7e4 100644 --- a/substrate/client/consensus/babe/src/lib.rs +++ b/substrate/client/consensus/babe/src/lib.rs @@ -1418,7 +1418,7 @@ where // Skip babe logic if block already in chain or importing blocks during initial sync, // otherwise the check for epoch changes will error because trying to re-import an - // epoch change or because of missing epoch data in the tree, respectivelly. + // epoch change or because of missing epoch data in the tree, respectively. if info.block_gap.map_or(false, |(s, e)| s <= number && number <= e) || block_status == BlockStatus::InChain { diff --git a/substrate/client/consensus/babe/src/migration.rs b/substrate/client/consensus/babe/src/migration.rs index bec2d0a61f4..5f1ece3ec0e 100644 --- a/substrate/client/consensus/babe/src/migration.rs +++ b/substrate/client/consensus/babe/src/migration.rs @@ -64,7 +64,7 @@ impl EpochT for EpochV0 { // Implement From for Epoch impl EpochV0 { - /// Migrate the sturct to current epoch version. + /// Migrate the struct to current epoch version. pub fn migrate(self, config: &BabeConfiguration) -> Epoch { sp_consensus_babe::Epoch { epoch_index: self.epoch_index, diff --git a/substrate/client/consensus/beefy/README.md b/substrate/client/consensus/beefy/README.md index 13f88303a97..a7956cfcd42 100644 --- a/substrate/client/consensus/beefy/README.md +++ b/substrate/client/consensus/beefy/README.md @@ -297,7 +297,7 @@ periodically on the global topic. Let's now dive into description of the message - Justification is considered worthwhile to gossip when: - It is for a recent (implementation specific) round or the latest mandatory round. - All signatures are valid and there is at least `2/3rd + 1` of them. - - Signatorees are part of the current validator set. + - Signatories are part of the current validator set. - Mandatory justifications should be announced periodically. ## Misbehavior diff --git a/substrate/client/consensus/beefy/src/communication/mod.rs b/substrate/client/consensus/beefy/src/communication/mod.rs index 6fda63688e6..09c540e3b8a 100644 --- a/substrate/client/consensus/beefy/src/communication/mod.rs +++ b/substrate/client/consensus/beefy/src/communication/mod.rs @@ -99,7 +99,7 @@ mod cost { // On-demand request was refused by peer. pub(super) const REFUSAL_RESPONSE: Rep = Rep::new(-100, "BEEFY: Proof request refused"); // On-demand request for a proof that can't be found in the backend. - pub(super) const UNKOWN_PROOF_REQUEST: Rep = Rep::new(-150, "BEEFY: Unknown proof request"); + pub(super) const UNKNOWN_PROOF_REQUEST: Rep = Rep::new(-150, "BEEFY: Unknown proof request"); } // benefit scalars for reporting peers. diff --git a/substrate/client/consensus/beefy/src/communication/request_response/incoming_requests_handler.rs b/substrate/client/consensus/beefy/src/communication/request_response/incoming_requests_handler.rs index d856e9748a1..ce184769fa7 100644 --- a/substrate/client/consensus/beefy/src/communication/request_response/incoming_requests_handler.rs +++ b/substrate/client/consensus/beefy/src/communication/request_response/incoming_requests_handler.rs @@ -170,7 +170,7 @@ where .flatten() .and_then(|hash| self.client.justifications(hash).ok().flatten()) .and_then(|justifs| justifs.get(BEEFY_ENGINE_ID).cloned()) - .ok_or_else(|| reputation_changes.push(cost::UNKOWN_PROOF_REQUEST)); + .ok_or_else(|| reputation_changes.push(cost::UNKNOWN_PROOF_REQUEST)); request .pending_response .send(netconfig::OutgoingResponse { diff --git a/substrate/client/consensus/beefy/src/keystore.rs b/substrate/client/consensus/beefy/src/keystore.rs index 2ddc938fbc6..9582c2661c3 100644 --- a/substrate/client/consensus/beefy/src/keystore.rs +++ b/substrate/client/consensus/beefy/src/keystore.rs @@ -404,7 +404,7 @@ pub mod tests { let store: BeefyKeystore = Some(store).into(); - let msg = b"are you involved or commited?"; + let msg = b"are you involved or committed?"; let sig1 = store.sign(&alice, msg).unwrap(); let sig2 = Keyring::::Alice.sign(msg); @@ -440,7 +440,7 @@ pub mod tests { let alice = Keyring::Alice.public(); - let msg = b"are you involved or commited?"; + let msg = b"are you involved or committed?"; let sig = store.sign(&alice, msg).err().unwrap(); let err = Error::Signature(expected_error_message.to_string()); @@ -463,7 +463,7 @@ pub mod tests { let store: BeefyKeystore = None.into(); let alice = Keyring::Alice.public(); - let msg = b"are you involved or commited"; + let msg = b"are you involved or committed"; let sig = store.sign(&alice, msg).err().unwrap(); let err = Error::Keystore("no Keystore".to_string()); @@ -487,7 +487,7 @@ pub mod tests { let alice = Keyring::Alice.public(); // `msg` and `sig` match - let msg = b"are you involved or commited?"; + let msg = b"are you involved or committed?"; let sig = store.sign(&alice, msg).unwrap(); assert!(BeefyKeystore::verify(&alice, &sig, msg)); diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index c8eb19621ba..7a47f286ef7 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -76,13 +76,13 @@ pub(crate) enum RoundAction { pub(crate) struct VoterOracle { /// Queue of known sessions. Keeps track of voting rounds (block numbers) within each session. /// - /// There are three voter states coresponding to three queue states: + /// There are three voter states corresponding to three queue states: /// 1. voter uninitialized: queue empty, /// 2. up-to-date - all mandatory blocks leading up to current GRANDPA finalized: queue has ONE /// element, the 'current session' where `mandatory_done == true`, /// 3. lagging behind GRANDPA: queue has [1, N] elements, where all `mandatory_done == false`. - /// In this state, everytime a session gets its mandatory block BEEFY finalized, it's popped - /// off the queue, eventually getting to state `2. up-to-date`. + /// In this state, every time a session gets its mandatory block BEEFY finalized, it's + /// popped off the queue, eventually getting to state `2. up-to-date`. sessions: VecDeque>, /// Min delta in block numbers between two blocks, BEEFY should vote on. min_block_delta: u32, diff --git a/substrate/client/consensus/common/Cargo.toml b/substrate/client/consensus/common/Cargo.toml index 7f36dfc09ef..f691e84717d 100644 --- a/substrate/client/consensus/common/Cargo.toml +++ b/substrate/client/consensus/common/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository.workspace = true -description = "Collection of common consensus specific imlementations for Substrate (client)" +description = "Collection of common consensus specific implementations for Substrate (client)" readme = "README.md" [lints] diff --git a/substrate/client/consensus/common/src/import_queue.rs b/substrate/client/consensus/common/src/import_queue.rs index 39d5bf8ed35..062e244a912 100644 --- a/substrate/client/consensus/common/src/import_queue.rs +++ b/substrate/client/consensus/common/src/import_queue.rs @@ -133,7 +133,7 @@ pub trait ImportQueue: Send { /// Start asynchronous runner for import queue. /// /// Takes an object implementing [`Link`] which allows the import queue to - /// influece the synchronization process. + /// influence the synchronization process. async fn run(self, link: Box>); } diff --git a/substrate/client/consensus/common/src/import_queue/basic_queue.rs b/substrate/client/consensus/common/src/import_queue/basic_queue.rs index 1cc7ec26fd1..125d4f104c1 100644 --- a/substrate/client/consensus/common/src/import_queue/basic_queue.rs +++ b/substrate/client/consensus/common/src/import_queue/basic_queue.rs @@ -187,7 +187,7 @@ impl ImportQueue for BasicQueue { /// Start asynchronous runner for import queue. /// /// Takes an object implementing [`Link`] which allows the import queue to - /// influece the synchronization process. + /// influence the synchronization process. async fn run(mut self, mut link: Box>) { loop { if let Err(_) = self.result_port.next_action(&mut *link).await { @@ -198,7 +198,7 @@ impl ImportQueue for BasicQueue { } } -/// Messages destinated to the background worker. +/// Messages designated to the background worker. mod worker_messages { use super::*; diff --git a/substrate/client/consensus/epochs/src/lib.rs b/substrate/client/consensus/epochs/src/lib.rs index 29bb18e147c..bbc143b7bd3 100644 --- a/substrate/client/consensus/epochs/src/lib.rs +++ b/substrate/client/consensus/epochs/src/lib.rs @@ -326,7 +326,7 @@ impl AsRef for IncrementedEpoch { /// /// The first epoch, epoch_0, is special cased by saying that it starts at /// slot number of the first block in the chain. When bootstrapping a chain, -/// there can be multiple competing block #1s, so we have to ensure that the overlayed +/// there can be multiple competing block #1s, so we have to ensure that the overlaid /// DAG doesn't get confused. /// /// The first block of every epoch should be producing a descriptor for the next @@ -655,7 +655,7 @@ where /// Revert to a specified block given its `hash` and `number`. /// This removes all the epoch changes information that were announced by - /// all the given block descendents. + /// all the given block descendants. pub fn revert>( &mut self, descendent_of_builder: D, diff --git a/substrate/client/consensus/grandpa/src/communication/mod.rs b/substrate/client/consensus/grandpa/src/communication/mod.rs index 5c7e1276297..6e87d6bf9a2 100644 --- a/substrate/client/consensus/grandpa/src/communication/mod.rs +++ b/substrate/client/consensus/grandpa/src/communication/mod.rs @@ -222,13 +222,13 @@ pub(crate) struct NetworkBridge, S: Syncing> { neighbor_sender: periodic::NeighborPacketSender, /// `NeighborPacketWorker` processing packets sent through the `NeighborPacketSender`. - // `NetworkBridge` is required to be cloneable, thus one needs to be able to clone its + // `NetworkBridge` is required to be clonable, thus one needs to be able to clone its // children, thus one has to wrap `neighbor_packet_worker` with an `Arc` `Mutex`. neighbor_packet_worker: Arc>>, /// Receiver side of the peer report stream populated by the gossip validator, forwarded to the /// gossip engine. - // `NetworkBridge` is required to be cloneable, thus one needs to be able to clone its + // `NetworkBridge` is required to be clonable, thus one needs to be able to clone its // children, thus one has to wrap gossip_validator_report_stream with an `Arc` `Mutex`. Given // that it is just an `UnboundedReceiver`, one could also switch to a // multi-producer-*multi*-consumer channel implementation. @@ -766,7 +766,7 @@ impl Sink> for OutgoingMessages { ) .ok_or_else(|| { Error::Signing(format!( - "Failed to sign GRANDPA vote for round {} targetting {:?}", + "Failed to sign GRANDPA vote for round {} targeting {:?}", self.round, target_hash )) })?; diff --git a/substrate/client/consensus/grandpa/src/communication/periodic.rs b/substrate/client/consensus/grandpa/src/communication/periodic.rs index daa75292028..9d0e76b7c80 100644 --- a/substrate/client/consensus/grandpa/src/communication/periodic.rs +++ b/substrate/client/consensus/grandpa/src/communication/periodic.rs @@ -106,7 +106,7 @@ impl Stream for NeighborPacketWorker { // Make sure the underlying task is scheduled for wake-up. // - // Note: In case poll_unpin is called after the resetted delay fires again, this + // Note: In case poll_unpin is called after the reset delay fires again, this // will drop one tick. Deemed as very unlikely and also not critical. while this.delay.poll_unpin(cx).is_ready() {} diff --git a/substrate/client/consensus/grandpa/src/tests.rs b/substrate/client/consensus/grandpa/src/tests.rs index 7e42c2d45c7..14708cc89e8 100644 --- a/substrate/client/consensus/grandpa/src/tests.rs +++ b/substrate/client/consensus/grandpa/src/tests.rs @@ -1805,7 +1805,7 @@ async fn grandpa_environment_checks_if_best_block_is_descendent_of_finality_targ ); // best block is higher than finality target and it's on the same fork, - // the best block passed to the voting rule should not be overriden + // the best block passed to the voting rule should not be overridden select_chain.set_best_chain(client.expect_header(hashof10_a).unwrap()); select_chain.set_finality_target(client.expect_header(hashof5_a).unwrap().hash()); voting_rule.set_expected_best_block(hashof10_a); @@ -1940,7 +1940,7 @@ async fn justification_with_equivocation() { precommits.push(precommit); } - // we create an equivocation for the 67th validator targetting blocks #1 and #2. + // we create an equivocation for the 67th validator targeting blocks #1 and #2. // this should be accounted as "voting for all blocks" and therefore block #3 will // have 67/100 votes, reaching finality threshold. { diff --git a/substrate/client/consensus/grandpa/src/until_imported.rs b/substrate/client/consensus/grandpa/src/until_imported.rs index 14f32ecc883..f3874086b58 100644 --- a/substrate/client/consensus/grandpa/src/until_imported.rs +++ b/substrate/client/consensus/grandpa/src/until_imported.rs @@ -1002,7 +1002,7 @@ mod tests { } #[test] - fn block_global_message_wait_completed_return_none_on_block_number_missmatch() { + fn block_global_message_wait_completed_return_none_on_block_number_mismatch() { let msg_inner = test_catch_up(); let waiting_block_1 = diff --git a/substrate/client/consensus/grandpa/src/voting_rule.rs b/substrate/client/consensus/grandpa/src/voting_rule.rs index e09780739c7..c37596d20f6 100644 --- a/substrate/client/consensus/grandpa/src/voting_rule.rs +++ b/substrate/client/consensus/grandpa/src/voting_rule.rs @@ -196,7 +196,7 @@ where target_header = backend .header(target_hash) .ok()? - .expect("Header known to exist due to the existence of one of its descendents; qed"); + .expect("Header known to exist due to the existence of one of its descendants; qed"); } } diff --git a/substrate/client/consensus/grandpa/src/warp_proof.rs b/substrate/client/consensus/grandpa/src/warp_proof.rs index 29111712ec3..7169a424c14 100644 --- a/substrate/client/consensus/grandpa/src/warp_proof.rs +++ b/substrate/client/consensus/grandpa/src/warp_proof.rs @@ -249,7 +249,7 @@ impl> NetworkProvider: BlockNumberOps, { - /// Create a new istance for a given backend and authority set. + /// Create a new instance for a given backend and authority set. pub fn new( backend: Arc, authority_set: SharedAuthoritySet>, diff --git a/substrate/client/consensus/manual-seal/src/consensus/babe.rs b/substrate/client/consensus/manual-seal/src/consensus/babe.rs index 26fa8145980..bc56ce02271 100644 --- a/substrate/client/consensus/manual-seal/src/consensus/babe.rs +++ b/substrate/client/consensus/manual-seal/src/consensus/babe.rs @@ -82,7 +82,7 @@ pub struct BabeVerifier { } impl BabeVerifier { - /// create a nrew verifier + /// create a new verifier pub fn new(epoch_changes: SharedEpochChanges, client: Arc) -> BabeVerifier { BabeVerifier { epoch_changes, client } } diff --git a/substrate/client/consensus/slots/src/lib.rs b/substrate/client/consensus/slots/src/lib.rs index 12636aae7a4..d9d79200531 100644 --- a/substrate/client/consensus/slots/src/lib.rs +++ b/substrate/client/consensus/slots/src/lib.rs @@ -555,7 +555,7 @@ impl SlotProportion { Self(inner.clamp(0.0, 1.0)) } - /// Returns the inner that is guaranted to be in the range `[0,1]`. + /// Returns the inner that is guaranteed to be in the range `[0,1]`. pub fn get(&self) -> f32 { self.0 } @@ -648,7 +648,7 @@ pub fn proposing_remaining_duration( } /// Calculate a slot duration lenience based on the number of missed slots from current -/// to parent. If the number of skipped slots is greated than 0 this method will apply +/// to parent. If the number of skipped slots is greater than 0 this method will apply /// an exponential backoff of at most `2^7 * slot_duration`, if no slots were skipped /// this method will return `None.` pub fn slot_lenience_exponential( @@ -680,7 +680,7 @@ pub fn slot_lenience_exponential( } /// Calculate a slot duration lenience based on the number of missed slots from current -/// to parent. If the number of skipped slots is greated than 0 this method will apply +/// to parent. If the number of skipped slots is greater than 0 this method will apply /// a linear backoff of at most `20 * slot_duration`, if no slots were skipped /// this method will return `None.` pub fn slot_lenience_linear( diff --git a/substrate/client/db/src/upgrade.rs b/substrate/client/db/src/upgrade.rs index f1e503867df..475220d9991 100644 --- a/substrate/client/db/src/upgrade.rs +++ b/substrate/client/db/src/upgrade.rs @@ -79,7 +79,7 @@ impl fmt::Display for UpgradeError { write!(f, "Database version comes from future version of the client: {}", version) }, UpgradeError::DecodingJustificationBlock => { - write!(f, "Decodoning justification block failed") + write!(f, "Decoding justification block failed") }, UpgradeError::Io(err) => write!(f, "Io error: {}", err), } diff --git a/substrate/client/db/src/utils.rs b/substrate/client/db/src/utils.rs index abf9c4629ce..b532e0d4666 100644 --- a/substrate/client/db/src/utils.rs +++ b/substrate/client/db/src/utils.rs @@ -338,7 +338,7 @@ fn open_kvdb_rocksdb( db_config.memory_budget = memory_budget; let db = kvdb_rocksdb::Database::open(&db_config, path)?; - // write database version only after the database is succesfully opened + // write database version only after the database is successfully opened crate::upgrade::update_version(path)?; Ok(sp_database::as_database(db)) } diff --git a/substrate/client/executor/common/src/error.rs b/substrate/client/executor/common/src/error.rs index b7c7e2b7019..9d489eaae42 100644 --- a/substrate/client/executor/common/src/error.rs +++ b/substrate/client/executor/common/src/error.rs @@ -145,7 +145,7 @@ pub enum WasmError { #[error("{0}")] Instantiation(String), - /// Other error happenend. + /// Other error happened. #[error("Other error happened while constructing the runtime: {0}")] Other(String), } diff --git a/substrate/client/executor/wasmtime/src/runtime.rs b/substrate/client/executor/wasmtime/src/runtime.rs index 595cc503272..286d134ecd1 100644 --- a/substrate/client/executor/wasmtime/src/runtime.rs +++ b/substrate/client/executor/wasmtime/src/runtime.rs @@ -462,7 +462,7 @@ pub struct Semantics { pub struct Config { /// The WebAssembly standard requires all imports of an instantiated module to be resolved, /// otherwise, the instantiation fails. If this option is set to `true`, then this behavior is - /// overriden and imports that are requested by the module and not provided by the host + /// overridden and imports that are requested by the module and not provided by the host /// functions will be resolved using stubs. These stubs will trap upon a call. pub allow_missing_func_imports: bool, diff --git a/substrate/client/executor/wasmtime/src/tests.rs b/substrate/client/executor/wasmtime/src/tests.rs index 1c06da1e3c1..f86a4275769 100644 --- a/substrate/client/executor/wasmtime/src/tests.rs +++ b/substrate/client/executor/wasmtime/src/tests.rs @@ -254,7 +254,7 @@ fn test_nan_canonicalization(instantiation_strategy: InstantiationStrategy) { /// A NaN with canonical payload bits. const CANONICAL_NAN_BITS: u32 = 0x7fc00000; - /// A NaN value with an abitrary payload. + /// A NaN value with an arbitrary payload. const ARBITRARY_NAN_BITS: u32 = 0x7f812345; // This test works like this: we essentially do @@ -272,7 +272,7 @@ fn test_nan_canonicalization(instantiation_strategy: InstantiationStrategy) { // However, with the `canonicalize_nans` option turned on above, we expect that the output will // be a canonical NaN. // - // We exterpolate the results of this tests so that we assume that all intermediate computations + // We extrapolate the results of this tests so that we assume that all intermediate computations // that involve floats are sanitized and cannot produce a non-deterministic NaN. let params = (u32::to_le_bytes(ARBITRARY_NAN_BITS), u32::to_le_bytes(1)).encode(); diff --git a/substrate/client/network/bitswap/src/lib.rs b/substrate/client/network/bitswap/src/lib.rs index 0586354d6a0..1ba95e30bad 100644 --- a/substrate/client/network/bitswap/src/lib.rs +++ b/substrate/client/network/bitswap/src/lib.rs @@ -301,7 +301,7 @@ mod tests { use substrate_test_runtime_client::{self, prelude::*, TestClientBuilder}; #[tokio::test] - async fn undecodeable_message() { + async fn undecodable_message() { let client = substrate_test_runtime_client::new(); let (bitswap, config) = BitswapRequestHandler::new(Arc::new(client)); diff --git a/substrate/client/network/src/protocol/notifications/behaviour.rs b/substrate/client/network/src/protocol/notifications/behaviour.rs index 9ad41e376e8..b945d4bfc60 100644 --- a/substrate/client/network/src/protocol/notifications/behaviour.rs +++ b/substrate/client/network/src/protocol/notifications/behaviour.rs @@ -2668,7 +2668,7 @@ mod tests { // // there is not straight-forward way of adding backoff to `PeerState::Disabled` // so manually adjust the value in order to progress on to the next stage. - // This modification together with `ConnectionClosed` will conver the peer + // This modification together with `ConnectionClosed` will convert the peer // state into `PeerState::Backoff`. if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = notif.peers.get_mut(&(peer, set_id)) diff --git a/substrate/client/network/src/protocol/notifications/handler.rs b/substrate/client/network/src/protocol/notifications/handler.rs index 28662be29fe..391252c3ffe 100644 --- a/substrate/client/network/src/protocol/notifications/handler.rs +++ b/substrate/client/network/src/protocol/notifications/handler.rs @@ -211,7 +211,7 @@ enum State { /// consequently trying to open the various notifications substreams. /// /// A [`NotifsHandlerOut::OpenResultOk`] or a [`NotifsHandlerOut::OpenResultErr`] event must - /// be emitted when transitionning to respectively [`State::Open`] or [`State::Closed`]. + /// be emitted when transitioning to respectively [`State::Open`] or [`State::Closed`]. Opening { /// Substream opened by the remote. If `Some`, has been accepted. in_substream: Option>, diff --git a/substrate/client/network/src/protocol/notifications/service/mod.rs b/substrate/client/network/src/protocol/notifications/service/mod.rs index 62e6d88a3d5..6d9873f45d5 100644 --- a/substrate/client/network/src/protocol/notifications/service/mod.rs +++ b/substrate/client/network/src/protocol/notifications/service/mod.rs @@ -54,7 +54,7 @@ const COMMAND_QUEUE_SIZE: usize = 64; /// Type representing subscribers of a notification protocol. type Subscribers = Arc>>>; -/// Type represending a distributable message sink. +/// Type representing a distributable message sink. /// Detached message sink must carry the protocol name for registering metrics. /// /// See documentation for [`PeerContext`] for more details. @@ -175,11 +175,11 @@ pub enum NotificationCommand { /// and an additional, distributable `NotificationsSink` which the protocol may acquire /// if it wishes to send notifications through `NotificationsSink` directly. /// -/// The distributable `NoticationsSink` is wrapped in an `Arc>` to allow +/// The distributable `NotificationsSink` is wrapped in an `Arc>` to allow /// `NotificationsService` to swap the underlying sink in case it's replaced. #[derive(Debug, Clone)] struct PeerContext { - /// Sink for sending notificaitons. + /// Sink for sending notifications. sink: NotificationsSink, /// Distributable notification sink. diff --git a/substrate/client/network/src/protocol/notifications/service/tests.rs b/substrate/client/network/src/protocol/notifications/service/tests.rs index 02ba9e1711c..238e0ccf566 100644 --- a/substrate/client/network/src/protocol/notifications/service/tests.rs +++ b/substrate/client/network/src/protocol/notifications/service/tests.rs @@ -437,7 +437,7 @@ async fn peer_disconnects_then_async_notification_is_sent() { notif.send_async_notification(&peer_id, vec![1, 3, 3, 7]).await { } else { - panic!("invalid state after calling `send_async_notificatio()` on closed connection") + panic!("invalid state after calling `send_async_notification()` on closed connection") } } diff --git a/substrate/client/network/src/protocol/notifications/upgrade/notifications.rs b/substrate/client/network/src/protocol/notifications/upgrade/notifications.rs index 4e1c033f33b..85209a888cd 100644 --- a/substrate/client/network/src/protocol/notifications/upgrade/notifications.rs +++ b/substrate/client/network/src/protocol/notifications/upgrade/notifications.rs @@ -188,7 +188,7 @@ where } } -/// Yielded by the [`NotificationsIn`] after a successfuly upgrade. +/// Yielded by the [`NotificationsIn`] after a successfully upgrade. pub struct NotificationsInOpen { /// Handshake sent by the remote. pub handshake: Vec, @@ -415,7 +415,7 @@ where } } -/// Yielded by the [`NotificationsOut`] after a successfuly upgrade. +/// Yielded by the [`NotificationsOut`] after a successfully upgrade. pub struct NotificationsOutOpen { /// Handshake returned by the remote. pub handshake: Vec, diff --git a/substrate/client/network/src/protocol_controller.rs b/substrate/client/network/src/protocol_controller.rs index 4c8f119baa2..7f851fd8e9c 100644 --- a/substrate/client/network/src/protocol_controller.rs +++ b/substrate/client/network/src/protocol_controller.rs @@ -448,7 +448,7 @@ impl ProtocolController { self.peer_store.report_disconnect(peer_id); } - /// Ask `Peerset` if the peer has a reputation value not sufficent for connection with it. + /// Ask `Peerset` if the peer has a reputation value not sufficient for connection with it. fn is_banned(&self, peer_id: &PeerId) -> bool { self.peer_store.is_banned(peer_id) } @@ -2020,7 +2020,7 @@ mod tests { ProtocolController::new(SetId::from(0), config, tx, Box::new(peer_store)); assert!(matches!(controller.reserved_nodes.get(&reserved1), Some(PeerState::NotConnected))); - // Initiate connectios + // Initiate connections controller.alloc_slots(); assert!(matches!(controller.reserved_nodes.get(&reserved1), Some(PeerState::NotConnected))); assert_eq!(rx.try_recv().unwrap_err(), TryRecvError::Empty); diff --git a/substrate/client/network/sync/src/engine.rs b/substrate/client/network/sync/src/engine.rs index 24640fdc455..ff40ae95624 100644 --- a/substrate/client/network/sync/src/engine.rs +++ b/substrate/client/network/sync/src/engine.rs @@ -110,7 +110,7 @@ const INACTIVITY_EVICT_THRESHOLD: Duration = Duration::from_secs(30); /// Parachain collator may incorrectly get evicted because it's waiting to receive a number of /// relaychain blocks before it can start creating parachain blocks. During this wait, /// `SyncingEngine` still counts it as active and as the peer is not sending blocks, it may get -/// evicted if a block is not received within the first 30 secons since the peer connected. +/// evicted if a block is not received within the first 30 seconds since the peer connected. /// /// To prevent this from happening, define a threshold for how long `SyncingEngine` should wait /// before it starts evicting peers. @@ -424,7 +424,7 @@ where .expect("Genesis block exists; qed"), ); - // Split warp sync params into warp sync config and a channel to retreive target block + // Split warp sync params into warp sync config and a channel to retrieve target block // header. let (warp_sync_config, warp_sync_target_block_header_rx) = warp_sync_params.map_or((None, None), |params| { @@ -1057,7 +1057,7 @@ where // still be under validation. If the peer has different genesis than the // local node the validation fails but the peer cannot be reported in // `validate_connection()` as that is also called by - // `ValiateInboundSubstream` which means that the peer is still being + // `ValidateInboundSubstream` which means that the peer is still being // validated and banning the peer when handling that event would // result in peer getting dropped twice. // diff --git a/substrate/client/network/sync/src/strategy.rs b/substrate/client/network/sync/src/strategy.rs index dabcf37ae63..610fd7c6560 100644 --- a/substrate/client/network/sync/src/strategy.rs +++ b/substrate/client/network/sync/src/strategy.rs @@ -185,7 +185,7 @@ where + Sync + 'static, { - /// Initialize a new syncing startegy. + /// Initialize a new syncing strategy. pub fn new( config: SyncingConfig, client: Arc, @@ -418,7 +418,7 @@ where self.state.is_some() || match self.chain_sync { Some(ref s) => s.status().state.is_major_syncing(), - None => unreachable!("At least one syncing startegy is active; qed"), + None => unreachable!("At least one syncing strategy is active; qed"), } } @@ -429,7 +429,7 @@ where /// Returns the current sync status. pub fn status(&self) -> SyncStatus { - // This function presumes that startegies are executed serially and must be refactored + // This function presumes that strategies are executed serially and must be refactored // once we have parallel strategies. if let Some(ref warp) = self.warp { warp.status() @@ -438,7 +438,7 @@ where } else if let Some(ref chain_sync) = self.chain_sync { chain_sync.status() } else { - unreachable!("At least one syncing startegy is always active; qed") + unreachable!("At least one syncing strategy is always active; qed") } } @@ -518,7 +518,7 @@ where /// Proceed with the next strategy if the active one finished. pub fn proceed_to_next(&mut self) -> Result<(), ClientError> { - // The strategies are switched as `WarpSync` -> `StateStartegy` -> `ChainSync`. + // The strategies are switched as `WarpSync` -> `StateStrategy` -> `ChainSync`. if let Some(ref mut warp) = self.warp { match warp.take_result() { Some(res) => { @@ -569,7 +569,7 @@ where }, } } else if let Some(state) = &self.state { - if state.is_succeded() { + if state.is_succeeded() { info!(target: LOG_TARGET, "State sync is complete, continuing with block sync."); } else { error!(target: LOG_TARGET, "State sync failed. Falling back to full sync."); diff --git a/substrate/client/network/sync/src/strategy/chain_sync.rs b/substrate/client/network/sync/src/strategy/chain_sync.rs index ad0c75363e7..da04bbbeccc 100644 --- a/substrate/client/network/sync/src/strategy/chain_sync.rs +++ b/substrate/client/network/sync/src/strategy/chain_sync.rs @@ -117,7 +117,7 @@ mod rep { /// Reputation change for peers which send us a block with bad justifications. pub const BAD_JUSTIFICATION: Rep = Rep::new(-(1 << 16), "Bad justification"); - /// Reputation change when a peer sent us invlid ancestry result. + /// Reputation change when a peer sent us invalid ancestry result. pub const UNKNOWN_ANCESTOR: Rep = Rep::new(-(1 << 16), "DB Error"); /// Peer response data does not have requested bits. @@ -1334,7 +1334,7 @@ where PeerSyncState::DownloadingJustification(_) => { // Peers that were downloading justifications // should be kept in that state. - // We make sure our commmon number is at least something we have. + // We make sure our common number is at least something we have. trace!( target: LOG_TARGET, "Keeping peer {} after restart, updating common number from={} => to={} (our best).", diff --git a/substrate/client/network/sync/src/strategy/chain_sync/test.rs b/substrate/client/network/sync/src/strategy/chain_sync/test.rs index 127b6862f0e..cd955113542 100644 --- a/substrate/client/network/sync/src/strategy/chain_sync/test.rs +++ b/substrate/client/network/sync/src/strategy/chain_sync/test.rs @@ -189,7 +189,7 @@ fn restart_doesnt_affect_peers_downloading_finality_data() { assert_eq!(sync.peers.get(&peer_id3).unwrap().common_number, 50); } -/// Send a block annoucnement for the given `header`. +/// Send a block announcement for the given `header`. fn send_block_announce(header: Header, peer_id: PeerId, sync: &mut ChainSync) { let announce = BlockAnnounce { header: header.clone(), @@ -278,7 +278,7 @@ fn unwrap_from_block_number(from: FromBlock) -> u64 { /// announcement from this node in its sync process. Meaning our common number didn't change. It /// is now expected that we start an ancestor search to find the common number. #[test] -fn do_ancestor_search_when_common_block_to_best_qeued_gap_is_to_big() { +fn do_ancestor_search_when_common_block_to_best_queued_gap_is_to_big() { sp_tracing::try_init_simple(); let blocks = { @@ -472,7 +472,7 @@ fn can_sync_huge_fork() { let actions = sync.take_actions().collect::>(); request = if actions.is_empty() { - // We found the ancenstor + // We found the ancestor break } else { assert_eq!(actions.len(), 1); @@ -607,7 +607,7 @@ fn syncs_fork_without_duplicate_requests() { let actions = sync.take_actions().collect::>(); request = if actions.is_empty() { - // We found the ancenstor + // We found the ancestor break } else { assert_eq!(actions.len(), 1); diff --git a/substrate/client/network/sync/src/strategy/state.rs b/substrate/client/network/sync/src/strategy/state.rs index 12d36ff9e01..6d3b215f7f3 100644 --- a/substrate/client/network/sync/src/strategy/state.rs +++ b/substrate/client/network/sync/src/strategy/state.rs @@ -79,7 +79,7 @@ pub struct StateStrategy { state_sync: Box>, peers: HashMap>, actions: Vec>, - succeded: bool, + succeeded: bool, } impl StateStrategy { @@ -110,7 +110,7 @@ impl StateStrategy { )), peers, actions: Vec::new(), - succeded: false, + succeeded: false, } } @@ -129,7 +129,7 @@ impl StateStrategy { }) .collect(), actions: Vec::new(), - succeded: false, + succeeded: false, } } @@ -260,7 +260,7 @@ impl StateStrategy { "Failed to import target block with state: {e:?}." ); }); - self.succeded |= results.into_iter().any(|result| result.is_ok()); + self.succeeded |= results.into_iter().any(|result| result.is_ok()); self.actions.push(StateStrategyAction::Finished); } } @@ -342,10 +342,10 @@ impl StateStrategy { std::mem::take(&mut self.actions).into_iter() } - /// Check if state sync has succeded. + /// Check if state sync has succeeded. #[must_use] - pub fn is_succeded(&self) -> bool { - self.succeded + pub fn is_succeeded(&self) -> bool { + self.succeeded } } @@ -669,7 +669,7 @@ mod test { } #[test] - fn succesfully_importing_target_block_finishes_strategy() { + fn successfully_importing_target_block_finishes_strategy() { let target_hash = Hash::random(); let mut state_sync_provider = MockStateSync::::new(); state_sync_provider.expect_target_hash().return_const(target_hash); diff --git a/substrate/client/network/sync/src/strategy/warp.rs b/substrate/client/network/sync/src/strategy/warp.rs index 7935b5f29b6..c7b79228efe 100644 --- a/substrate/client/network/sync/src/strategy/warp.rs +++ b/substrate/client/network/sync/src/strategy/warp.rs @@ -968,7 +968,7 @@ mod test { warp_sync.on_warp_proof_response(&request_peer_id, EncodedProof(Vec::new())); - // We only interested in alredy generated actions, not new requests. + // We only interested in already generated actions, not new requests. let actions = std::mem::take(&mut warp_sync.actions); assert_eq!(actions.len(), 1); assert!(matches!( diff --git a/substrate/client/network/sync/src/warp_request_handler.rs b/substrate/client/network/sync/src/warp_request_handler.rs index 39cf1c5d806..eda67cac95f 100644 --- a/substrate/client/network/sync/src/warp_request_handler.rs +++ b/substrate/client/network/sync/src/warp_request_handler.rs @@ -57,7 +57,7 @@ pub fn generate_request_response_config>( } } -/// Generate the grandpa warp sync protocol name from the genesi hash and fork id. +/// Generate the grandpa warp sync protocol name from the genesis hash and fork id. fn generate_protocol_name>(genesis_hash: Hash, fork_id: Option<&str>) -> String { let genesis_hash = genesis_hash.as_ref(); if let Some(fork_id) = fork_id { diff --git a/substrate/client/network/test/src/sync.rs b/substrate/client/network/test/src/sync.rs index c025a8262f0..f1c1b741430 100644 --- a/substrate/client/network/test/src/sync.rs +++ b/substrate/client/network/test/src/sync.rs @@ -749,7 +749,7 @@ async fn sync_blocks_when_block_announce_validator_says_it_is_new_best() { } } -/// Waits for some time until the validation is successfull. +/// Waits for some time until the validation is successful. struct DeferredBlockAnnounceValidator; impl BlockAnnounceValidator for DeferredBlockAnnounceValidator { diff --git a/substrate/client/offchain/src/api/http.rs b/substrate/client/offchain/src/api/http.rs index 7ca5e3fd13a..46f573341c5 100644 --- a/substrate/client/offchain/src/api/http.rs +++ b/substrate/client/offchain/src/api/http.rs @@ -604,7 +604,7 @@ enum WorkerToApi { /// because we don't want the `HttpApi` to have to drive the reading. /// Instead, reading an item from the channel will notify the worker task, which will push /// the next item. - /// Can also be used to send an error, in case an error happend on the HTTP socket. After + /// Can also be used to send an error, in case an error happened on the HTTP socket. After /// an error is sent, the channel will close. body: mpsc::Receiver>, }, diff --git a/substrate/client/rpc-servers/src/middleware/metrics.rs b/substrate/client/rpc-servers/src/middleware/metrics.rs index 17849dc0c44..688c3c2a9fc 100644 --- a/substrate/client/rpc-servers/src/middleware/metrics.rs +++ b/substrate/client/rpc-servers/src/middleware/metrics.rs @@ -182,7 +182,7 @@ impl RpcMetrics { transport_label, req.method_name(), // the label "is_error", so `success` should be regarded as false - // and vice-versa to be registrered correctly. + // and vice-versa to be registered correctly. if rp.is_success() { "false" } else { "true" }, if is_rate_limited { "true" } else { "false" }, ]) diff --git a/substrate/client/rpc-spec-v2/src/archive/tests.rs b/substrate/client/rpc-spec-v2/src/archive/tests.rs index 1803ffa3a31..de71ed82a12 100644 --- a/substrate/client/rpc-spec-v2/src/archive/tests.rs +++ b/substrate/client/rpc-spec-v2/src/archive/tests.rs @@ -435,7 +435,7 @@ async fn archive_storage_closest_merkle_value() { /// The core of this test. /// - /// Checks keys that are exact match, keys with descedant and keys that should not return + /// Checks keys that are exact match, keys with descendant and keys that should not return /// values. /// /// Returns (key, merkle value) pairs. @@ -459,7 +459,7 @@ async fn archive_storage_closest_merkle_value() { query_type: StorageQueryType::ClosestDescendantMerkleValue, pagination_start_key: None, }, - // Key with descedent. + // Key with descendant. PaginatedStorageQuery { key: hex_string(b":A"), query_type: StorageQueryType::ClosestDescendantMerkleValue, diff --git a/substrate/client/rpc-spec-v2/src/chain_head/event.rs b/substrate/client/rpc-spec-v2/src/chain_head/event.rs index e0c804d16eb..bd986306091 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/event.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/event.rs @@ -111,7 +111,7 @@ impl From for RuntimeEvent { #[derive(Debug, Clone, PartialEq, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Initialized { - /// The hash of the lastest finalized blocks. + /// The hash of the latest finalized blocks. pub finalized_block_hashes: Vec, /// The runtime version of the finalized block. /// @@ -315,7 +315,7 @@ pub enum FollowEvent { Stop, } -/// The method respose of `chainHead_body`, `chainHead_call` and `chainHead_storage`. +/// The method response of `chainHead_body`, `chainHead_call` and `chainHead_storage`. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] #[serde(tag = "result")] diff --git a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs index 4d9dfb24e0a..30152efb5b6 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs @@ -2786,7 +2786,7 @@ async fn ensure_operation_limits_works() { FollowEvent::OperationStorageDone(done) if done.operation_id == operation_id ); - // The storage is finished and capactiy must be released. + // The storage is finished and capacity must be released. let alice_id = AccountKeyring::Alice.to_account_id(); // Hex encoded scale encoded bytes representing the call parameters. let call_parameters = hex_string(&alice_id.encode()); @@ -3113,7 +3113,7 @@ async fn storage_closest_merkle_value() { /// The core of this test. /// - /// Checks keys that are exact match, keys with descedant and keys that should not return + /// Checks keys that are exact match, keys with descendant and keys that should not return /// values. /// /// Returns (key, merkle value) pairs. @@ -3139,7 +3139,7 @@ async fn storage_closest_merkle_value() { key: hex_string(b":AAAB"), query_type: StorageQueryType::ClosestDescendantMerkleValue }, - // Key with descedent. + // Key with descendant. StorageQuery { key: hex_string(b":A"), query_type: StorageQueryType::ClosestDescendantMerkleValue diff --git a/substrate/client/rpc-spec-v2/src/transaction/tests/transaction_broadcast_tests.rs b/substrate/client/rpc-spec-v2/src/transaction/tests/transaction_broadcast_tests.rs index 690a1a64d74..77a28968aed 100644 --- a/substrate/client/rpc-spec-v2/src/transaction/tests/transaction_broadcast_tests.rs +++ b/substrate/client/rpc-spec-v2/src/transaction/tests/transaction_broadcast_tests.rs @@ -372,7 +372,7 @@ async fn tx_broadcast_resubmits_invalid_tx() { client_mock.trigger_import_stream(block_2_header).await; // Ensure we propagate the temporary ban error to `submit_and_watch`. - // This ensures we'll loop again with the next annmounced block and try to resubmit the + // This ensures we'll loop again with the next announced block and try to resubmit the // transaction. The transaction remains temporarily banned until the pool is maintained. let event = get_next_event!(&mut pool_middleware); assert_matches!(event, MiddlewarePoolEvent::PoolError { transaction, err } if transaction == xt && err.contains("Transaction temporarily Banned")); @@ -429,7 +429,7 @@ async fn tx_broadcast_resubmits_invalid_tx() { } /// This is similar to `tx_broadcast_resubmits_invalid_tx`. -/// However, it forces the tx to be resubmited because of the pool +/// However, it forces the tx to be resubmitted because of the pool /// limits. Which is a different code path than the invalid tx. #[tokio::test] async fn tx_broadcast_resubmits_dropped_tx() { @@ -509,7 +509,7 @@ async fn tx_broadcast_resubmits_dropped_tx() { pool.inner_pool.maintain(event).await; client_mock.trigger_import_stream(block_3_header.clone()).await; - // The first tx is in a finalzied block; the future tx must enter the pool. + // The first tx is in a finalized block; the future tx must enter the pool. let events = get_next_tx_events!(&mut pool_middleware, 3); assert_eq!( events.get(¤t_xt).unwrap(), diff --git a/substrate/client/rpc-spec-v2/src/transaction/transaction_broadcast.rs b/substrate/client/rpc-spec-v2/src/transaction/transaction_broadcast.rs index 92c83826187..6eaf50d6b2e 100644 --- a/substrate/client/rpc-spec-v2/src/transaction/transaction_broadcast.rs +++ b/substrate/client/rpc-spec-v2/src/transaction/transaction_broadcast.rs @@ -44,7 +44,7 @@ pub struct TransactionBroadcast { pool: Arc, /// Executor to spawn subscriptions. executor: SubscriptionTaskExecutor, - /// The brodcast operation IDs. + /// The broadcast operation IDs. broadcast_ids: Arc>>, } @@ -200,7 +200,7 @@ where } } -/// Returns the last element of the providided stream, or `None` if the stream is closed. +/// Returns the last element of the provided stream, or `None` if the stream is closed. async fn last_stream_element(stream: &mut S) -> Option where S: Stream + Unpin, diff --git a/substrate/client/rpc/src/statement/mod.rs b/substrate/client/rpc/src/statement/mod.rs index b4f432bbbb0..e99135aec38 100644 --- a/substrate/client/rpc/src/statement/mod.rs +++ b/substrate/client/rpc/src/statement/mod.rs @@ -89,7 +89,7 @@ impl StatementApiServer for StatementStore { fn submit(&self, encoded: Bytes) -> RpcResult<()> { let statement = Decode::decode(&mut &*encoded) - .map_err(|e| Error::StatementStore(format!("Eror decoding statement: {:?}", e)))?; + .map_err(|e| Error::StatementStore(format!("Error decoding statement: {:?}", e)))?; match self.store.submit(statement, StatementSource::Local) { SubmitResult::New(_) | SubmitResult::Known => Ok(()), // `KnownExpired` should not happen. Expired statements submitted with diff --git a/substrate/client/service/src/chain_ops/import_blocks.rs b/substrate/client/service/src/chain_ops/import_blocks.rs index 34f7669d010..661fc09a8f1 100644 --- a/substrate/client/service/src/chain_ops/import_blocks.rs +++ b/substrate/client/service/src/chain_ops/import_blocks.rs @@ -73,7 +73,7 @@ where reader: CodecIoReader, }, Json { - // Nubmer of blocks we have decoded thus far. + // Number of blocks we have decoded thus far. read_block_count: u64, // Stream to the data, used for decoding new blocks. reader: StreamDeserializer<'static, JsonIoRead, SignedBlock>, diff --git a/substrate/client/service/src/config.rs b/substrate/client/service/src/config.rs index 35262ff493b..59e307d7f93 100644 --- a/substrate/client/service/src/config.rs +++ b/substrate/client/service/src/config.rs @@ -236,7 +236,7 @@ impl Configuration { ProtocolId::from(protocol_id_full) } - /// Returns true if the genesis state writting will be skipped while initializing the genesis + /// Returns true if the genesis state writing will be skipped while initializing the genesis /// block. pub fn no_genesis(&self) -> bool { matches!(self.network.sync_mode, SyncMode::LightState { .. } | SyncMode::Warp { .. }) diff --git a/substrate/client/state-db/src/lib.rs b/substrate/client/state-db/src/lib.rs index 41c231c31aa..6c37c87a611 100644 --- a/substrate/client/state-db/src/lib.rs +++ b/substrate/client/state-db/src/lib.rs @@ -872,7 +872,7 @@ mod tests { fn check_stored_and_requested_mode_compatibility( mode_when_created: Option, mode_when_reopened: Option, - expected_effective_mode_when_reopenned: Result, + expected_effective_mode_when_reopened: Result, ) { let mut db = make_db(&[]); let (state_db_init, state_db) = @@ -883,7 +883,7 @@ mod tests { let state_db_reopen_result = StateDb::::open(db.clone(), mode_when_reopened, false, false); - if let Ok(expected_mode) = expected_effective_mode_when_reopenned { + if let Ok(expected_mode) = expected_effective_mode_when_reopened { let (state_db_init, state_db_reopened) = state_db_reopen_result.unwrap(); db.commit(&state_db_init); assert_eq!(state_db_reopened.pruning_mode(), expected_mode,) diff --git a/substrate/client/state-db/src/noncanonical.rs b/substrate/client/state-db/src/noncanonical.rs index bdbe8318371..4492a7bd077 100644 --- a/substrate/client/state-db/src/noncanonical.rs +++ b/substrate/client/state-db/src/noncanonical.rs @@ -46,26 +46,26 @@ pub struct NonCanonicalOverlay { #[cfg_attr(test, derive(PartialEq, Debug))] struct OverlayLevel { blocks: Vec>, - used_indicies: u64, // Bitmask of available journal indicies. + used_indices: u64, // Bitmask of available journal indices. } impl OverlayLevel { fn push(&mut self, overlay: BlockOverlay) { - self.used_indicies |= 1 << overlay.journal_index; + self.used_indices |= 1 << overlay.journal_index; self.blocks.push(overlay) } fn available_index(&self) -> u64 { - self.used_indicies.trailing_ones() as u64 + self.used_indices.trailing_ones() as u64 } fn remove(&mut self, index: usize) -> BlockOverlay { - self.used_indicies &= !(1 << self.blocks[index].journal_index); + self.used_indices &= !(1 << self.blocks[index].journal_index); self.blocks.remove(index) } fn new() -> OverlayLevel { - OverlayLevel { blocks: Vec::new(), used_indicies: 0 } + OverlayLevel { blocks: Vec::new(), used_indices: 0 } } } diff --git a/substrate/client/telemetry/src/lib.rs b/substrate/client/telemetry/src/lib.rs index 113d8303a20..7e3a4ee8639 100644 --- a/substrate/client/telemetry/src/lib.rs +++ b/substrate/client/telemetry/src/lib.rs @@ -413,7 +413,7 @@ impl Telemetry { .map_err(|_| Error::TelemetryWorkerDropped) } - /// Make a new cloneable handle to this [`Telemetry`]. This is used for reporting telemetries. + /// Make a new clonable handle to this [`Telemetry`]. This is used for reporting telemetries. pub fn handle(&self) -> TelemetryHandle { TelemetryHandle { message_sender: Arc::new(Mutex::new(self.message_sender.clone())), diff --git a/substrate/client/transaction-pool/README.md b/substrate/client/transaction-pool/README.md index b55dc6482d6..7a53727d576 100644 --- a/substrate/client/transaction-pool/README.md +++ b/substrate/client/transaction-pool/README.md @@ -171,7 +171,7 @@ This parameter instructs the pool propagate/gossip a transaction to node peers. By default this should be `true`, however in some cases it might be undesirable to propagate transactions further. Examples might include heavy transactions produced by block authors in offchain workers (DoS) or risking being front -runned by someone else after finding some non trivial solution or equivocation, +ran by someone else after finding some non trivial solution or equivocation, etc. ### 'TransactionSource` diff --git a/substrate/client/transaction-pool/tests/pool.rs b/substrate/client/transaction-pool/tests/pool.rs index 461b9860d41..49bd2203c12 100644 --- a/substrate/client/transaction-pool/tests/pool.rs +++ b/substrate/client/transaction-pool/tests/pool.rs @@ -999,7 +999,7 @@ fn import_notification_to_pool_maintain_works() { .0, ); - // Prepare the extrisic, push it to the pool and check that it was added. + // Prepare the extrinsic, push it to the pool and check that it was added. let xt = uxt(Alice, 0); block_on(pool.submit_one( pool.api().block_id_to_hash(&BlockId::Number(0)).unwrap().unwrap(), diff --git a/substrate/client/utils/src/notification.rs b/substrate/client/utils/src/notification.rs index dabb85d613c..3f606aabe3a 100644 --- a/substrate/client/utils/src/notification.rs +++ b/substrate/client/utils/src/notification.rs @@ -44,7 +44,7 @@ mod tests; /// and identify the mpsc channels. pub trait TracingKeyStr { /// Const `str` representing the "tracing key" used to tag and identify - /// the mpsc channels owned by the object implemeting this trait. + /// the mpsc channels owned by the object implementing this trait. const TRACING_KEY: &'static str; } diff --git a/substrate/frame/alliance/README.md b/substrate/frame/alliance/README.md index 9930008e2d6..16335a98f59 100644 --- a/substrate/frame/alliance/README.md +++ b/substrate/frame/alliance/README.md @@ -58,7 +58,7 @@ to update the Alliance's rule and make announcements. - `add_unscrupulous_items` - Add some items, either accounts or websites, to the list of unscrupulous items. - `remove_unscrupulous_items` - Remove some items from the list of unscrupulous items. -- `abdicate_fellow_status` - Abdicate one's voting rights, demoting themself to Ally. +- `abdicate_fellow_status` - Abdicate one's voting rights, demoting themselves to Ally. #### Root Calls diff --git a/substrate/frame/alliance/src/lib.rs b/substrate/frame/alliance/src/lib.rs index d4703db68db..414d550c53a 100644 --- a/substrate/frame/alliance/src/lib.rs +++ b/substrate/frame/alliance/src/lib.rs @@ -505,10 +505,10 @@ pub mod pallet { proposal: Box<>::Proposal>, #[pallet::compact] length_bound: u32, ) -> DispatchResult { - let proposor = ensure_signed(origin)?; - ensure!(Self::has_voting_rights(&proposor), Error::::NoVotingRights); + let proposer = ensure_signed(origin)?; + ensure!(Self::has_voting_rights(&proposer), Error::::NoVotingRights); - T::ProposalProvider::propose_proposal(proposor, threshold, proposal, length_bound)?; + T::ProposalProvider::propose_proposal(proposer, threshold, proposal, length_bound)?; Ok(()) } diff --git a/substrate/frame/alliance/src/tests.rs b/substrate/frame/alliance/src/tests.rs index 710de5a54bc..c65f10228e7 100644 --- a/substrate/frame/alliance/src/tests.rs +++ b/substrate/frame/alliance/src/tests.rs @@ -26,7 +26,7 @@ use crate::mock::*; type AllianceMotionEvent = pallet_collective::Event; fn assert_powerless(user: RuntimeOrigin, user_is_member: bool) { - //vote / veto with a valid propsal + //vote / veto with a valid proposal let cid = test_cid(); let (proposal, _, _) = make_kick_member_proposal(42); diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index c9725f9d39d..0bf73e8809c 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -205,7 +205,7 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// A successful call of the `CretaPool` extrinsic will create this event. + /// A successful call of the `CreatePool` extrinsic will create this event. PoolCreated { /// The account that created the pool. creator: T::AccountId, diff --git a/substrate/frame/asset-rate/src/lib.rs b/substrate/frame/asset-rate/src/lib.rs index befabfe54aa..69f8267a4f2 100644 --- a/substrate/frame/asset-rate/src/lib.rs +++ b/substrate/frame/asset-rate/src/lib.rs @@ -112,7 +112,7 @@ pub mod pallet { /// The origin permissioned to remove an existing conversion rate for an asset. type RemoveOrigin: EnsureOrigin; - /// The origin permissioned to update an existiing conversion rate for an asset. + /// The origin permissioned to update an existing conversion rate for an asset. type UpdateOrigin: EnsureOrigin; /// The currency mechanism for this pallet. diff --git a/substrate/frame/assets/src/lib.rs b/substrate/frame/assets/src/lib.rs index 583c75b3827..c5468e4237d 100644 --- a/substrate/frame/assets/src/lib.rs +++ b/substrate/frame/assets/src/lib.rs @@ -183,7 +183,7 @@ pub use weights::WeightInfo; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; const LOG_TARGET: &str = "runtime::assets"; -/// Trait with callbacks that are executed after successfull asset creation or destruction. +/// Trait with callbacks that are executed after successful asset creation or destruction. pub trait AssetsCallback { /// Indicates that asset with `id` was successfully created by the `owner` fn created(_id: &AssetId, _owner: &AccountId) -> Result<(), ()> { diff --git a/substrate/frame/assets/src/tests.rs b/substrate/frame/assets/src/tests.rs index e09648a51ec..c7021bcad53 100644 --- a/substrate/frame/assets/src/tests.rs +++ b/substrate/frame/assets/src/tests.rs @@ -1453,7 +1453,7 @@ fn force_asset_status_should_work() { )); assert_eq!(Assets::balance(0, 1), 50); - // account can recieve assets for balance < min_balance + // account can receive assets for balance < min_balance assert_ok!(Assets::transfer(RuntimeOrigin::signed(2), 0, 1, 1)); assert_eq!(Assets::balance(0, 1), 51); diff --git a/substrate/frame/babe/src/benchmarking.rs b/substrate/frame/babe/src/benchmarking.rs index 92f55665913..6b0e31e8471 100644 --- a/substrate/frame/babe/src/benchmarking.rs +++ b/substrate/frame/babe/src/benchmarking.rs @@ -31,7 +31,7 @@ benchmarks! { // NOTE: generated with the test below `test_generate_equivocation_report_blob`. // the output is not deterministic since keys are generated randomly (and therefore // signature content changes). it should not affect the benchmark. - // with the current benchmark setup it is not possible to generate this programatically + // with the current benchmark setup it is not possible to generate this programmatically // from the benchmark setup. const EQUIVOCATION_PROOF_BLOB: [u8; 416] = [ 222, 241, 46, 66, 243, 228, 135, 233, 177, 64, 149, 170, 141, 92, 193, 106, 51, 73, 31, diff --git a/substrate/frame/bags-list/src/list/tests.rs b/substrate/frame/bags-list/src/list/tests.rs index fd4ad8f893a..cd39b083172 100644 --- a/substrate/frame/bags-list/src/list/tests.rs +++ b/substrate/frame/bags-list/src/list/tests.rs @@ -431,7 +431,7 @@ mod list { #[test] fn insert_at_unchecked_at_is_only_node() { // Note that this `insert_at_unchecked` test should fail post checks because node 42 does - // not get re-assigned the correct bagu pper. This is because `insert_at_unchecked` assumes + // not get re-assigned the correct bag upper. This is because `insert_at_unchecked` assumes // both nodes are already in the same bag with the correct bag upper. ExtBuilder::default().build_and_execute_no_post_check(|| { // given diff --git a/substrate/frame/balances/src/lib.rs b/substrate/frame/balances/src/lib.rs index 3fd3102cd35..80278752207 100644 --- a/substrate/frame/balances/src/lib.rs +++ b/substrate/frame/balances/src/lib.rs @@ -677,7 +677,7 @@ pub mod pallet { /// /// This will waive the transaction fee if at least all but 10% of the accounts needed to /// be upgraded. (We let some not have to be upgraded just in order to allow for the - /// possibililty of churn). + /// possibility of churn). #[pallet::call_index(6)] #[pallet::weight(T::WeightInfo::upgrade_accounts(who.len() as u32))] pub fn upgrade_accounts( @@ -905,14 +905,14 @@ pub mod pallet { Self::try_mutate_account(who, |a, _| -> Result { Ok(f(a)) }) } - /// Returns `true` when `who` has some providers or `insecure_zero_ed` feature is disnabled. + /// Returns `true` when `who` has some providers or `insecure_zero_ed` feature is disabled. /// Returns `false` otherwise. #[cfg(not(feature = "insecure_zero_ed"))] fn have_providers_or_no_zero_ed(_: &T::AccountId) -> bool { true } - /// Returns `true` when `who` has some providers or `insecure_zero_ed` feature is disnabled. + /// Returns `true` when `who` has some providers or `insecure_zero_ed` feature is disabled. /// Returns `false` otherwise. #[cfg(feature = "insecure_zero_ed")] fn have_providers_or_no_zero_ed(who: &T::AccountId) -> bool { diff --git a/substrate/frame/balances/src/tests/currency_tests.rs b/substrate/frame/balances/src/tests/currency_tests.rs index 46a4c4caefc..bd4ff762c74 100644 --- a/substrate/frame/balances/src/tests/currency_tests.rs +++ b/substrate/frame/balances/src/tests/currency_tests.rs @@ -1024,7 +1024,7 @@ fn slash_consumed_slash_partial_works() { } #[test] -fn slash_on_non_existant_works() { +fn slash_on_non_existent_works() { ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { // Slash on non-existent account is okay. assert_eq!(Balances::slash(&12345, 1_300), (NegativeImbalance::new(0), 1300)); @@ -1071,7 +1071,7 @@ fn slash_reserved_overslash_does_not_touch_free_balance() { } #[test] -fn slash_reserved_on_non_existant_works() { +fn slash_reserved_on_non_existent_works() { ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { // Slash on non-existent account is okay. assert_eq!(Balances::slash_reserved(&12345, 1_300), (NegativeImbalance::new(0), 1300)); diff --git a/substrate/frame/balances/src/tests/reentrancy_tests.rs b/substrate/frame/balances/src/tests/reentrancy_tests.rs index 1afbe82c7e2..717f0497857 100644 --- a/substrate/frame/balances/src/tests/reentrancy_tests.rs +++ b/substrate/frame/balances/src/tests/reentrancy_tests.rs @@ -44,7 +44,7 @@ fn transfer_dust_removal_tst1_should_work() { assert_eq!(Balances::free_balance(&2), 0); // As expected beneficiary account 3 - // received the transfered fund. + // received the transferred fund. assert_eq!(Balances::free_balance(&3), 450); // Dust balance is deposited to account 1 @@ -123,7 +123,7 @@ fn repatriating_reserved_balance_dust_removal_should_work() { // Reserve a value on account 2, // Such that free balance is lower than - // Exestintial deposit. + // Existential deposit. assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(2), 1, 450)); // Since free balance of account 2 is lower than diff --git a/substrate/frame/benchmarking/src/analysis.rs b/substrate/frame/benchmarking/src/analysis.rs index 5fc3abb5a27..987078ff79a 100644 --- a/substrate/frame/benchmarking/src/analysis.rs +++ b/substrate/frame/benchmarking/src/analysis.rs @@ -41,7 +41,7 @@ pub enum BenchmarkSelector { /// Multiplies the value by 1000 and converts it into an u128. fn mul_1000_into_u128(value: f64) -> u128 { - // This is slighly more precise than the alternative of `(value * 1000.0) as u128`. + // This is slightly more precise than the alternative of `(value * 1000.0) as u128`. (value as u128) .saturating_mul(1000) .saturating_add((value.fract() * 1000.0) as u128) diff --git a/substrate/frame/benchmarking/src/lib.rs b/substrate/frame/benchmarking/src/lib.rs index f79582d03e5..d4ee0abbecc 100644 --- a/substrate/frame/benchmarking/src/lib.rs +++ b/substrate/frame/benchmarking/src/lib.rs @@ -203,7 +203,7 @@ pub use v1::*; /// ## Where Clause /// /// Some pallets require a where clause specifying constraints on their generics to make -/// writing benchmarks feasible. To accomodate this situation, you can provide such a where +/// writing benchmarks feasible. To accommodate this situation, you can provide such a where /// clause as the (only) argument to the `#[benchmarks]` or `#[instance_benchmarks]` attribute /// macros. Below is an example of this taken from the `message-queue` pallet. /// diff --git a/substrate/frame/benchmarking/src/v1.rs b/substrate/frame/benchmarking/src/v1.rs index 4ad8cc0edd4..b2449db3d67 100644 --- a/substrate/frame/benchmarking/src/v1.rs +++ b/substrate/frame/benchmarking/src/v1.rs @@ -874,7 +874,7 @@ macro_rules! impl_bench_name_tests { $crate::BenchmarkError::Override(_) => { // This is still considered a success condition. $crate::__private::log::error!( - "WARNING: benchmark error overrided - {}", + "WARNING: benchmark error overridden - {}", stringify!($name), ); }, @@ -1704,7 +1704,7 @@ macro_rules! impl_test_function { $crate::BenchmarkError::Override(_) => { // This is still considered a success condition. $crate::__private::log::error!( - "WARNING: benchmark error overrided - {}", + "WARNING: benchmark error overridden - {}", $crate::__private::str::from_utf8(benchmark_name) .expect("benchmark name is always a valid string!"), ); @@ -1851,7 +1851,7 @@ macro_rules! add_benchmark { Err($crate::BenchmarkError::Override(mut result)) => { // Insert override warning as the first storage key. $crate::__private::log::error!( - "WARNING: benchmark error overrided - {}", + "WARNING: benchmark error overridden - {}", $crate::__private::str::from_utf8(benchmark) .expect("benchmark name is always a valid string!") ); diff --git a/substrate/frame/broker/src/lib.rs b/substrate/frame/broker/src/lib.rs index a669463aa02..f1b49a73a52 100644 --- a/substrate/frame/broker/src/lib.rs +++ b/substrate/frame/broker/src/lib.rs @@ -683,7 +683,7 @@ pub mod pallet { /// - `origin`: Must be a Signed origin of the account which owns the Region `region_id`. /// - `region_id`: The Region which was assigned to the Pool. /// - `max_timeslices`: The maximum number of timeslices which should be processed. This may - /// effect the weight of the call but should be ideally made equivalant to the length of + /// effect the weight of the call but should be ideally made equivalent to the length of /// the Region `region_id`. If it is less than this, then further dispatches will be /// required with the `region_id` which makes up any remainders of the region to be /// collected. diff --git a/substrate/frame/broker/src/types.rs b/substrate/frame/broker/src/types.rs index 7e9f351723a..e8119d29ef5 100644 --- a/substrate/frame/broker/src/types.rs +++ b/substrate/frame/broker/src/types.rs @@ -55,7 +55,7 @@ pub enum Finality { pub struct RegionId { /// The timeslice at which this Region begins. pub begin: Timeslice, - /// The index of the Polakdot Core on which this Region will be scheduled. + /// The index of the Polkadot Core on which this Region will be scheduled. pub core: CoreIndex, /// The regularity parts in which this Region will be scheduled. pub mask: CoreMask, @@ -198,7 +198,7 @@ pub struct PoolIoRecord { /// The total change of the portion of the pool supplied by purchased Bulk Coretime, measured /// in Core Mask Bits. pub private: SignedCoreMaskBitCount, - /// The total change of the portion of the pool supplied by the Polkaot System, measured in + /// The total change of the portion of the pool supplied by the Polkadot System, measured in /// Core Mask Bits. pub system: SignedCoreMaskBitCount, } diff --git a/substrate/frame/collective/README.md b/substrate/frame/collective/README.md index 444927e51da..e860edbd484 100644 --- a/substrate/frame/collective/README.md +++ b/substrate/frame/collective/README.md @@ -9,7 +9,7 @@ calculations, but enforces this neither in `set_members` nor in `change_members_ A "prime" member may be set to help determine the default vote behavior based on chain config. If `PrimeDefaultVote` is used, the prime vote acts as the default vote in case of any abstentions after the voting period. If `MoreThanMajorityThenPrimeDefaultVote` is used, then -abstentations will first follow the majority of the collective voting, and then the prime +abstentions will first follow the majority of the collective voting, and then the prime member. Voting happens through motions comprising a proposal (i.e. a dispatchable) plus a diff --git a/substrate/frame/collective/src/lib.rs b/substrate/frame/collective/src/lib.rs index 882e99a6d00..d0009d02f68 100644 --- a/substrate/frame/collective/src/lib.rs +++ b/substrate/frame/collective/src/lib.rs @@ -283,7 +283,7 @@ pub mod pallet { pub type Members, I: 'static = ()> = StorageValue<_, Vec, ValueQuery>; - /// The prime member that helps determine the default vote behavior in case of absentations. + /// The prime member that helps determine the default vote behavior in case of abstentions. #[pallet::storage] pub type Prime, I: 'static = ()> = StorageValue<_, T::AccountId, OptionQuery>; diff --git a/substrate/frame/collective/src/tests.rs b/substrate/frame/collective/src/tests.rs index 8a80dd167e3..5240dc215ff 100644 --- a/substrate/frame/collective/src/tests.rs +++ b/substrate/frame/collective/src/tests.rs @@ -995,7 +995,7 @@ fn motions_all_first_vote_free_works() { Collective::vote(RuntimeOrigin::signed(3), hash, 0, false); assert_eq!(vote_rval.unwrap().pays_fee, Pays::Yes); - // Test close() Extrincis | Check DispatchResultWithPostInfo with Pay Info + // Test close() Extrinsics | Check DispatchResultWithPostInfo with Pay Info let proposal_weight = proposal.get_dispatch_info().weight; let close_rval: DispatchResultWithPostInfo = diff --git a/substrate/frame/contracts/README.md b/substrate/frame/contracts/README.md index 6e817292e66..09dc770300c 100644 --- a/substrate/frame/contracts/README.md +++ b/substrate/frame/contracts/README.md @@ -59,7 +59,7 @@ In general, a contract execution needs to be deterministic so that all nodes com it. To that end we disallow any instructions that could cause indeterminism. Most notable are any floating point arithmetic. That said, sometimes contracts are executed off-chain and hence are not subject to consensus. If code is only executed by a single node and implicitly trusted by other actors is such a case. Trusted execution environments -come to mind. To that end we allow the execution of indeterminstic code for off-chain usages with the following +come to mind. To that end we allow the execution of indeterministic code for off-chain usages with the following constraints: 1. No contract can ever be instantiated from an indeterministic code. The only way to execute the code is to use a diff --git a/substrate/frame/contracts/fixtures/contracts/multi_store.rs b/substrate/frame/contracts/fixtures/contracts/multi_store.rs index b83f3995a42..a78115f0148 100644 --- a/substrate/frame/contracts/fixtures/contracts/multi_store.rs +++ b/substrate/frame/contracts/fixtures/contracts/multi_store.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Does two stores to two seperate storage items +//! Does two stores to two separate storage items #![no_std] #![no_main] diff --git a/substrate/frame/contracts/src/benchmarking/code.rs b/substrate/frame/contracts/src/benchmarking/code.rs index 96ce11f8c41..b97cf168e26 100644 --- a/substrate/frame/contracts/src/benchmarking/code.rs +++ b/substrate/frame/contracts/src/benchmarking/code.rs @@ -164,7 +164,7 @@ impl From for WasmModule { // Grant access to linear memory. // Every contract module is required to have an imported memory. - // If no memory is specified in the passed ModuleDefenition, then + // If no memory is specified in the passed ModuleDefinition, then // default to (1, 1). let (init, max) = if let Some(memory) = &def.memory { (memory.min_pages, Some(memory.max_pages)) diff --git a/substrate/frame/contracts/src/benchmarking/mod.rs b/substrate/frame/contracts/src/benchmarking/mod.rs index ce2cf15d812..9fb107537ba 100644 --- a/substrate/frame/contracts/src/benchmarking/mod.rs +++ b/substrate/frame/contracts/src/benchmarking/mod.rs @@ -340,7 +340,7 @@ mod benchmarks { assert_eq!(StorageVersion::get::>(), version); } - // This benchmarks the weight of dispatching migrate to execute 1 `NoopMigraton` + // This benchmarks the weight of dispatching migrate to execute 1 `NoopMigration` #[benchmark(pov_mode = Measured)] fn migrate() { let latest_version = LATEST_MIGRATION_VERSION; @@ -1859,7 +1859,7 @@ mod benchmarks { // We call unique accounts. // - // This is a slow call: We redeuce the number of runs. + // This is a slow call: We reduce the number of runs. #[benchmark(pov_mode = Measured)] fn seal_call(r: Linear<0, { API_BENCHMARK_RUNS / 2 }>) -> Result<(), BenchmarkError> { let dummy_code = WasmModule::::dummy_with_bytes(0); @@ -1937,7 +1937,7 @@ mod benchmarks { Ok(()) } - // This is a slow call: We redeuce the number of runs. + // This is a slow call: We reduce the number of runs. #[benchmark(pov_mode = Measured)] fn seal_delegate_call(r: Linear<0, { API_BENCHMARK_RUNS / 2 }>) -> Result<(), BenchmarkError> { let hashes = (0..r) @@ -2473,7 +2473,7 @@ mod benchmarks { // Only calling the function itself for the list of // generated different ECDSA keys. - // This is a slow call: We redeuce the number of runs. + // This is a slow call: We reduce the number of runs. #[benchmark(pov_mode = Measured)] fn seal_ecdsa_to_eth_address( r: Linear<0, { API_BENCHMARK_RUNS / 10 }>, diff --git a/substrate/frame/contracts/src/exec.rs b/substrate/frame/contracts/src/exec.rs index d24657b65b2..41a0383811f 100644 --- a/substrate/frame/contracts/src/exec.rs +++ b/substrate/frame/contracts/src/exec.rs @@ -531,9 +531,9 @@ enum FrameArgs<'a, T: Config, E> { nonce: u64, /// The executable whose `deploy` function is run. executable: E, - /// A salt used in the contract address deriviation of the new contract. + /// A salt used in the contract address derivation of the new contract. salt: &'a [u8], - /// The input data is used in the contract address deriviation of the new contract. + /// The input data is used in the contract address derivation of the new contract. input_data: &'a [u8], }, } diff --git a/substrate/frame/contracts/src/gas.rs b/substrate/frame/contracts/src/gas.rs index b9d91f38f16..32fad2140f1 100644 --- a/substrate/frame/contracts/src/gas.rs +++ b/substrate/frame/contracts/src/gas.rs @@ -352,7 +352,7 @@ mod tests { assert!(gas_meter.charge(SimpleToken(1)).is_err()); } - // Make sure that the gas meter does not charge in case of overcharger + // Make sure that the gas meter does not charge in case of overcharge #[test] fn overcharge_does_not_charge() { let mut gas_meter = GasMeter::::new(Weight::from_parts(200, 0)); diff --git a/substrate/frame/contracts/src/lib.rs b/substrate/frame/contracts/src/lib.rs index de84d5220c5..6433d4eecdc 100644 --- a/substrate/frame/contracts/src/lib.rs +++ b/substrate/frame/contracts/src/lib.rs @@ -1104,7 +1104,7 @@ pub mod pallet { /// A more detailed error can be found on the node console if debug messages are enabled /// by supplying `-lruntime::contracts=debug`. CodeRejected, - /// An indetermistic code was used in a context where this is not permitted. + /// An indeterministic code was used in a context where this is not permitted. Indeterministic, /// A pending migration needs to complete before the extrinsic can be called. MigrationInProgress, diff --git a/substrate/frame/contracts/src/migration/v09.rs b/substrate/frame/contracts/src/migration/v09.rs index f19bff9d674..8e718871ecb 100644 --- a/substrate/frame/contracts/src/migration/v09.rs +++ b/substrate/frame/contracts/src/migration/v09.rs @@ -131,7 +131,7 @@ impl MigrationStep for Migration { let module = CodeStorage::::get(&code_hash).unwrap(); ensure!( module.instruction_weights_version == old.instruction_weights_version, - "invalid isntruction weights version" + "invalid instruction weights version" ); ensure!(module.determinism == Determinism::Enforced, "invalid determinism"); ensure!(module.initial == old.initial, "invalid initial"); diff --git a/substrate/frame/contracts/src/schedule.rs b/substrate/frame/contracts/src/schedule.rs index b2e3801deae..06a7c2005aa 100644 --- a/substrate/frame/contracts/src/schedule.rs +++ b/substrate/frame/contracts/src/schedule.rs @@ -193,7 +193,7 @@ pub struct HostFnWeights { /// Weight of calling `seal_set_storage`. pub set_storage: Weight, - /// Weight per written byten of an item stored with `seal_set_storage`. + /// Weight per written byte of an item stored with `seal_set_storage`. pub set_storage_per_new_byte: Weight, /// Weight per overwritten byte of an item stored with `seal_set_storage`. diff --git a/substrate/frame/contracts/src/tests.rs b/substrate/frame/contracts/src/tests.rs index db6b2e80d07..ed486fc4a67 100644 --- a/substrate/frame/contracts/src/tests.rs +++ b/substrate/frame/contracts/src/tests.rs @@ -1347,7 +1347,7 @@ fn transfer_expendable_cannot_kill_account() { } #[test] -fn cannot_self_destruct_through_draning() { +fn cannot_self_destruct_through_draining() { let (wasm, _code_hash) = compile_module::("drain").unwrap(); ExtBuilder::default().existential_deposit(200).build().execute_with(|| { let _ = ::Currency::set_balance(&ALICE, 1_000_000); @@ -1662,7 +1662,7 @@ fn cannot_self_destruct_in_constructor() { ExtBuilder::default().existential_deposit(50).build().execute_with(|| { let _ = ::Currency::set_balance(&ALICE, 1_000_000); - // Fail to instantiate the BOB because the contructor calls seal_terminate. + // Fail to instantiate the BOB because the constructor calls seal_terminate. assert_err_ignore_postinfo!( Contracts::instantiate_with_code( RuntimeOrigin::signed(ALICE), @@ -5096,7 +5096,7 @@ fn cannot_instantiate_indeterministic_code() { >::CodeRejected, ); - // Try to upload a non deterministic code as deterministic + // Try to upload a non-deterministic code as deterministic assert_err!( Contracts::upload_code( RuntimeOrigin::signed(ALICE), @@ -5176,7 +5176,7 @@ fn cannot_instantiate_indeterministic_code() { >::Indeterministic, ); - // Instantiations are not allowed even in non determinism mode + // Instantiations are not allowed even in non-determinism mode assert_err!( >::bare_call( ALICE, @@ -5202,7 +5202,7 @@ fn cannot_set_code_indeterministic_code() { ExtBuilder::default().existential_deposit(200).build().execute_with(|| { let _ = ::Currency::set_balance(&ALICE, 1_000_000); - // Put the non deterministic contract on-chain + // Put the non-deterministic contract on-chain assert_ok!(Contracts::upload_code( RuntimeOrigin::signed(ALICE), wasm, @@ -5226,7 +5226,7 @@ fn cannot_set_code_indeterministic_code() { .unwrap() .account_id; - // We do not allow to set the code hash to a non determinstic wasm + // We do not allow to set the code hash to a non-deterministic wasm assert_err!( >::bare_call( ALICE, @@ -5252,7 +5252,7 @@ fn delegate_call_indeterministic_code() { ExtBuilder::default().existential_deposit(200).build().execute_with(|| { let _ = ::Currency::set_balance(&ALICE, 1_000_000); - // Put the non deterministic contract on-chain + // Put the non-deterministic contract on-chain assert_ok!(Contracts::upload_code( RuntimeOrigin::signed(ALICE), wasm, @@ -5293,7 +5293,7 @@ fn delegate_call_indeterministic_code() { >::Indeterministic, ); - // The delegate call will work on non deterministic mode + // The delegate call will work on non-deterministic mode assert_ok!( >::bare_call( ALICE, @@ -5429,7 +5429,7 @@ fn locking_delegate_dependency_works() { contract.storage_base_deposit() - ED ); - // Removing an unexisting dependency should fail. + // Removing a nonexistent dependency should fail. assert_err!( call(&addr_caller, &unlock_delegate_dependency_input).result, Error::::DelegateDependencyNotFound diff --git a/substrate/frame/contracts/src/wasm/mod.rs b/substrate/frame/contracts/src/wasm/mod.rs index af287a6f2df..e6af62c7289 100644 --- a/substrate/frame/contracts/src/wasm/mod.rs +++ b/substrate/frame/contracts/src/wasm/mod.rs @@ -1425,7 +1425,7 @@ mod tests { #[test] fn contract_ecdsa_to_eth_address() { - /// calls `seal_ecdsa_to_eth_address` for the contstant and ensures the result equals the + /// calls `seal_ecdsa_to_eth_address` for the constant and ensures the result equals the /// expected one. const CODE_ECDSA_TO_ETH_ADDRESS: &str = r#" (module diff --git a/substrate/frame/contracts/src/wasm/runtime.rs b/substrate/frame/contracts/src/wasm/runtime.rs index 7d43d30ba58..160dfa0d2f3 100644 --- a/substrate/frame/contracts/src/wasm/runtime.rs +++ b/substrate/frame/contracts/src/wasm/runtime.rs @@ -245,7 +245,7 @@ pub enum RuntimeCosts { /// Weight of calling `account_reentrance_count` AccountEntranceCount, /// Weight of calling `instantiation_nonce` - InstantationNonce, + InstantiationNonce, /// Weight of calling `lock_delegate_dependency` LockDelegateDependency, /// Weight of calling `unlock_delegate_dependency` @@ -337,7 +337,7 @@ impl Token for RuntimeCosts { EcdsaToEthAddress => s.ecdsa_to_eth_address, ReentrantCount => s.reentrance_count, AccountEntranceCount => s.account_reentrance_count, - InstantationNonce => s.instantiation_nonce, + InstantiationNonce => s.instantiation_nonce, LockDelegateDependency => s.lock_delegate_dependency, UnlockDelegateDependency => s.unlock_delegate_dependency, } @@ -2298,7 +2298,7 @@ pub mod env { /// Returns a nonce that is unique per contract instantiation. /// See [`pallet_contracts_uapi::HostFn::instantiation_nonce`]. fn instantiation_nonce(ctx: _, _memory: _) -> Result { - ctx.charge_gas(RuntimeCosts::InstantationNonce)?; + ctx.charge_gas(RuntimeCosts::InstantiationNonce)?; Ok(ctx.ext.nonce()) } diff --git a/substrate/frame/conviction-voting/src/tests.rs b/substrate/frame/conviction-voting/src/tests.rs index 5c582a35362..74baeace898 100644 --- a/substrate/frame/conviction-voting/src/tests.rs +++ b/substrate/frame/conviction-voting/src/tests.rs @@ -39,7 +39,7 @@ frame_support::construct_runtime!( } ); -// Test that a fitlered call can be dispatched. +// Test that a filtered call can be dispatched. pub struct BaseFilter; impl Contains for BaseFilter { fn contains(call: &RuntimeCall) -> bool { diff --git a/substrate/frame/core-fellowship/src/tests/integration.rs b/substrate/frame/core-fellowship/src/tests/integration.rs index 3c2dc1de595..d3bbac15805 100644 --- a/substrate/frame/core-fellowship/src/tests/integration.rs +++ b/substrate/frame/core-fellowship/src/tests/integration.rs @@ -251,7 +251,7 @@ fn swap_exhaustive_works() { }); assert_eq!(root_add, root_swap); - // Ensure that we dont compare trivial stuff like `()` from a type error above. + // Ensure that we don't compare trivial stuff like `()` from a type error above. assert_eq!(root_add.len(), 32); }); } diff --git a/substrate/frame/democracy/src/lib.rs b/substrate/frame/democracy/src/lib.rs index 08e2a7599f5..f3d33a72f3a 100644 --- a/substrate/frame/democracy/src/lib.rs +++ b/substrate/frame/democracy/src/lib.rs @@ -484,7 +484,7 @@ pub mod pallet { Blacklisted { proposal_hash: T::Hash }, /// An account has voted in a referendum Voted { voter: T::AccountId, ref_index: ReferendumIndex, vote: AccountVote> }, - /// An account has secconded a proposal + /// An account has seconded a proposal Seconded { seconder: T::AccountId, prop_index: PropIndex }, /// A proposal got canceled. ProposalCanceled { prop_index: PropIndex }, diff --git a/substrate/frame/democracy/src/migrations/unlock_and_unreserve_all_funds.rs b/substrate/frame/democracy/src/migrations/unlock_and_unreserve_all_funds.rs index 188c475f64d..1cb50a157b1 100644 --- a/substrate/frame/democracy/src/migrations/unlock_and_unreserve_all_funds.rs +++ b/substrate/frame/democracy/src/migrations/unlock_and_unreserve_all_funds.rs @@ -321,40 +321,40 @@ mod test { } #[test] - fn unreserve_works_for_depositer() { - let depositer_0 = 10; - let depositer_1 = 11; + fn unreserve_works_for_depositor() { + let depositor_0 = 10; + let depositor_1 = 11; let deposit = 25; - let depositer_0_initial_reserved = 0; - let depositer_1_initial_reserved = 15; + let depositor_0_initial_reserved = 0; + let depositor_1_initial_reserved = 15; let initial_balance = 100_000; new_test_ext().execute_with(|| { // Set up initial state. - ::Currency::make_free_balance_be(&depositer_0, initial_balance); - ::Currency::make_free_balance_be(&depositer_1, initial_balance); + ::Currency::make_free_balance_be(&depositor_0, initial_balance); + ::Currency::make_free_balance_be(&depositor_1, initial_balance); assert_ok!(::Currency::reserve( - &depositer_0, - depositer_0_initial_reserved + deposit + &depositor_0, + depositor_0_initial_reserved + deposit )); assert_ok!(::Currency::reserve( - &depositer_1, - depositer_1_initial_reserved + deposit + &depositor_1, + depositor_1_initial_reserved + deposit )); let depositors = BoundedVec::<_, ::MaxDeposits>::truncate_from(vec![ - depositer_0, - depositer_1, + depositor_0, + depositor_1, ]); DepositOf::::insert(0, (depositors, deposit)); // Sanity check: ensure initial reserved balance was set correctly. assert_eq!( - ::Currency::reserved_balance(&depositer_0), - depositer_0_initial_reserved + deposit + ::Currency::reserved_balance(&depositor_0), + depositor_0_initial_reserved + deposit ); assert_eq!( - ::Currency::reserved_balance(&depositer_1), - depositer_1_initial_reserved + deposit + ::Currency::reserved_balance(&depositor_1), + depositor_1_initial_reserved + deposit ); // Run the migration. @@ -365,12 +365,12 @@ mod test { // Assert the reserved balance was reduced by the expected amount. assert_eq!( - ::Currency::reserved_balance(&depositer_0), - depositer_0_initial_reserved + ::Currency::reserved_balance(&depositor_0), + depositor_0_initial_reserved ); assert_eq!( - ::Currency::reserved_balance(&depositer_1), - depositer_1_initial_reserved + ::Currency::reserved_balance(&depositor_1), + depositor_1_initial_reserved ); }); } diff --git a/substrate/frame/democracy/src/tests.rs b/substrate/frame/democracy/src/tests.rs index dd69f48dbc1..e2946ba9815 100644 --- a/substrate/frame/democracy/src/tests.rs +++ b/substrate/frame/democracy/src/tests.rs @@ -62,7 +62,7 @@ frame_support::construct_runtime!( } ); -// Test that a fitlered call can be dispatched. +// Test that a filtered call can be dispatched. pub struct BaseFilter; impl Contains for BaseFilter { fn contains(call: &RuntimeCall) -> bool { diff --git a/substrate/frame/democracy/src/tests/cancellation.rs b/substrate/frame/democracy/src/tests/cancellation.rs index 4384fe6a164..b4c42f9c790 100644 --- a/substrate/frame/democracy/src/tests/cancellation.rs +++ b/substrate/frame/democracy/src/tests/cancellation.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! The tests for cancelation functionality. +//! The tests for cancellation functionality. use super::*; diff --git a/substrate/frame/election-provider-multi-phase/src/helpers.rs b/substrate/frame/election-provider-multi-phase/src/helpers.rs index 57d580e9301..a3f27fc18f0 100644 --- a/substrate/frame/election-provider-multi-phase/src/helpers.rs +++ b/substrate/frame/election-provider-multi-phase/src/helpers.rs @@ -160,7 +160,7 @@ pub fn target_index_fn_linear( } /// Create a function that can map a voter index ([`SolutionVoterIndexOf`]) to the actual voter -/// account using a linearly indexible snapshot. +/// account using a linearly indexable snapshot. pub fn voter_at_fn( snapshot: &Vec>, ) -> impl Fn(SolutionVoterIndexOf) -> Option + '_ { @@ -172,7 +172,7 @@ pub fn voter_at_fn( } /// Create a function that can map a target index ([`SolutionTargetIndexOf`]) to the actual target -/// account using a linearly indexible snapshot. +/// account using a linearly indexable snapshot. pub fn target_at_fn( snapshot: &Vec, ) -> impl Fn(SolutionTargetIndexOf) -> Option + '_ { diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index 6bf4dfe4f1e..31a79577d1f 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -1134,7 +1134,7 @@ pub mod pallet { /// A solution was stored with the given compute. /// /// The `origin` indicates the origin of the solution. If `origin` is `Some(AccountId)`, - /// the stored solution was submited in the signed phase by a miner with the `AccountId`. + /// the stored solution was submitted in the signed phase by a miner with the `AccountId`. /// Otherwise, the solution was stored either during the unsigned phase or by /// `T::ForceOrigin`. The `bool` is `true` when a previous solution was ejected to make /// room for this one. @@ -1192,7 +1192,7 @@ pub mod pallet { BoundNotMet, /// Submitted solution has too many winners TooManyWinners, - /// Sumission was prepared for a different round. + /// Submission was prepared for a different round. PreDispatchDifferentRound, } diff --git a/substrate/frame/election-provider-multi-phase/src/unsigned.rs b/substrate/frame/election-provider-multi-phase/src/unsigned.rs index 94348181334..8b25815eca1 100644 --- a/substrate/frame/election-provider-multi-phase/src/unsigned.rs +++ b/substrate/frame/election-provider-multi-phase/src/unsigned.rs @@ -1445,7 +1445,7 @@ mod tests { ) .unwrap(); let solution = RawSolution { solution: raw, score, round: MultiPhase::round() }; - // 12 is not better than 12. We need score of atleast 13 to be accepted. + // 12 is not better than 12. We need score of at least 13 to be accepted. assert_eq!(solution.score.minimal_stake, 12); // submitting this will panic. assert_noop!( @@ -1483,7 +1483,7 @@ mod tests { )); // trial 4: a solution who's minimal stake is 17, i.e. 4 better than the last - // soluton. + // solution. let result = ElectionResult { winners: vec![(10, 12)], assignments: vec![ diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs index 53bff50f748..83083c91209 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs @@ -208,8 +208,8 @@ fn enters_emergency_phase_after_forcing_before_elect() { /// active validators. Thus, slashing a percentage of the current validators that is lower than /// `OffendingValidatorsThreshold` will never force a new era. However, as the slashes progress, if /// the subsequent elections do not meet the minimum election untrusted score, the election will -/// fail and enter in emenergency mode. -fn continous_slashes_below_offending_threshold() { +/// fail and enter in emergency mode. +fn continuous_slashes_below_offending_threshold() { let staking_builder = StakingExtBuilder::default().validator_count(10); let epm_builder = EpmExtBuilder::default().disable_emergency_throttling(); @@ -323,7 +323,7 @@ fn set_validation_intention_after_chilled() { } #[test] -/// Active ledger balance may fall below ED if account chills before unbounding. +/// Active ledger balance may fall below ED if account chills before unbonding. /// /// Unbonding call fails if the remaining ledger's stash balance falls below the existential /// deposit. However, if the stash is chilled before unbonding, the ledger's active balance may @@ -350,7 +350,7 @@ fn ledger_consistency_active_balance_below_ed() { // however, chilling works as expected. assert_ok!(Staking::chill(RuntimeOrigin::signed(11))); - // now unbonding the full active balance works, since remainer of the active balance is + // now unbonding the full active balance works, since remainder of the active balance is // not enforced to be below `MinNominatorBond` if the stash has been chilled. assert_ok!(Staking::unbond(RuntimeOrigin::signed(11), 1000)); @@ -479,7 +479,7 @@ fn automatic_unbonding_pools() { staking_events(), [ // auto-withdraw happened as expected to release 2's unbonding funds, but the funds - // were not transfered to 2 and stay in the pool's tranferrable balance instead. + // were not transferred to 2 and stay in the pool's transferrable balance instead. pallet_staking::Event::Withdrawn { stash: 7939698191839293293, amount: 10 }, pallet_staking::Event::Unbonded { stash: 7939698191839293293, amount: 10 } ] diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs index d7d2006d219..7efcc4701e2 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs @@ -167,7 +167,7 @@ parameter_types! { pub static SignedPhase: BlockNumber = 10; pub static UnsignedPhase: BlockNumber = 10; // we expect a minimum of 3 blocks in signed phase and unsigned phases before trying - // enetering in emergency phase after the election failed. + // entering in emergency phase after the election failed. pub static MinBlocksBeforeEmergency: BlockNumber = 3; pub static MaxActiveValidators: u32 = 1000; pub static OffchainRepeat: u32 = 5; @@ -661,7 +661,7 @@ pub fn roll_to(n: BlockNumber, delay_solution: bool) { Session::on_initialize(b); Timestamp::set_timestamp(System::block_number() * BLOCK_TIME + INIT_TIMESTAMP); - // TODO(gpestana): implement a realistic OCW worker insted of simulating it + // TODO(gpestana): implement a realistic OCW worker instead of simulating it // https://github.com/paritytech/substrate/issues/13589 // if there's no solution queued and the solution should not be delayed, try mining and // queue a solution. diff --git a/substrate/frame/election-provider-support/src/bounds.rs b/substrate/frame/election-provider-support/src/bounds.rs index b9ae21e49ca..6b2423b7fec 100644 --- a/substrate/frame/election-provider-support/src/bounds.rs +++ b/substrate/frame/election-provider-support/src/bounds.rs @@ -62,7 +62,7 @@ use sp_runtime::traits::Zero; /// Encapsulates the counting of things that can be bounded in an election, such as voters, /// targets or anything else. /// -/// This struct is defined mostly to prevent callers from mistankingly using `CountBound` instead of +/// This struct is defined mostly to prevent callers from mistakenly using `CountBound` instead of /// `SizeBound` and vice-versa. #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub struct CountBound(pub u32); @@ -96,7 +96,7 @@ impl Zero for CountBound { /// logic and implementation, but it most likely will represent bytes in SCALE encoding in this /// context. /// -/// This struct is defined mostly to prevent callers from mistankingly using `CountBound` instead of +/// This struct is defined mostly to prevent callers from mistakenly using `CountBound` instead of /// `SizeBound` and vice-versa. #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub struct SizeBound(pub u32); diff --git a/substrate/frame/examples/offchain-worker/src/lib.rs b/substrate/frame/examples/offchain-worker/src/lib.rs index d21c8b4cfd2..0a90e896188 100644 --- a/substrate/frame/examples/offchain-worker/src/lib.rs +++ b/substrate/frame/examples/offchain-worker/src/lib.rs @@ -495,7 +495,7 @@ impl Pallet { // Here we showcase two ways to send an unsigned transaction / unsigned payload (raw) // // By default unsigned transactions are disallowed, so we need to whitelist this case - // by writing `UnsignedValidator`. Note that it's EXTREMELY important to carefuly + // by writing `UnsignedValidator`. Note that it's EXTREMELY important to carefully // implement unsigned validation logic, as any mistakes can lead to opening DoS or spam // attack vectors. See validation logic docs for more details. // diff --git a/substrate/frame/examples/single-block-migrations/src/lib.rs b/substrate/frame/examples/single-block-migrations/src/lib.rs index 86a9e5d6e95..b36d5262267 100644 --- a/substrate/frame/examples/single-block-migrations/src/lib.rs +++ b/substrate/frame/examples/single-block-migrations/src/lib.rs @@ -20,7 +20,7 @@ //! An example pallet demonstrating best-practices for writing single-block migrations in the //! context of upgrading pallet storage. //! -//! ## Forwarning +//! ## Forewarning //! //! Single block migrations **MUST** execute in a single block, therefore when executed on a //! parachain are only appropriate when guaranteed to not exceed block weight limits. If a @@ -66,7 +66,7 @@ //! //! ## Adding a migration module //! -//! Writing a pallets migrations in a seperate module is strongly recommended. +//! Writing a pallets migrations in a separate module is strongly recommended. //! //! Here's how the migration module is defined for this pallet: //! diff --git a/substrate/frame/examples/split/Cargo.toml b/substrate/frame/examples/split/Cargo.toml index d140fc3eef4..230dc980b1a 100644 --- a/substrate/frame/examples/split/Cargo.toml +++ b/substrate/frame/examples/split/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace = true license = "MIT-0" homepage = "https://substrate.io" repository.workspace = true -description = "FRAME example splitted pallet" +description = "FRAME example split pallet" readme = "README.md" [lints] diff --git a/substrate/frame/examples/tasks/Cargo.toml b/substrate/frame/examples/tasks/Cargo.toml index 41521114366..4d14bf313d7 100644 --- a/substrate/frame/examples/tasks/Cargo.toml +++ b/substrate/frame/examples/tasks/Cargo.toml @@ -5,7 +5,7 @@ authors.workspace = true edition.workspace = true license.workspace = true repository.workspace = true -description = "Pallet to demonstrate the usage of Tasks to recongnize and execute service work" +description = "Pallet to demonstrate the usage of Tasks to recognize and execute service work" [lints] workspace = true diff --git a/substrate/frame/fast-unstake/src/tests.rs b/substrate/frame/fast-unstake/src/tests.rs index b19fe3b8c46..77128872f28 100644 --- a/substrate/frame/fast-unstake/src/tests.rs +++ b/substrate/frame/fast-unstake/src/tests.rs @@ -110,7 +110,7 @@ fn cannot_register_if_head() { stashes: bounded_vec![(1, Deposit::get())], checked: bounded_vec![], }); - // Controller attempts to regsiter + // Controller attempts to register assert_noop!( FastUnstake::register_fast_unstake(RuntimeOrigin::signed(1)), Error::::AlreadyHead diff --git a/substrate/frame/grandpa/src/benchmarking.rs b/substrate/frame/grandpa/src/benchmarking.rs index 7a87f0c4b07..c89592b3b35 100644 --- a/substrate/frame/grandpa/src/benchmarking.rs +++ b/substrate/frame/grandpa/src/benchmarking.rs @@ -29,7 +29,7 @@ benchmarks! { // NOTE: generated with the test below `test_generate_equivocation_report_blob`. // the output should be deterministic since the keys we use are static. // with the current benchmark setup it is not possible to generate this - // programatically from the benchmark setup. + // programmatically from the benchmark setup. const EQUIVOCATION_PROOF_BLOB: [u8; 257] = [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 136, 220, 52, 23, 213, 5, 142, 196, 180, 80, 62, 12, 18, 234, 26, 10, 137, 190, 32, diff --git a/substrate/frame/grandpa/src/tests.rs b/substrate/frame/grandpa/src/tests.rs index 993d72af6d4..8b12d63adaa 100644 --- a/substrate/frame/grandpa/src/tests.rs +++ b/substrate/frame/grandpa/src/tests.rs @@ -634,7 +634,7 @@ fn report_equivocation_invalid_equivocation_proof() { (1, H256::zero(), 10, &equivocation_keyring), )); - // votes targetting different rounds, there is no equivocation. + // votes targeting different rounds, there is no equivocation. assert_invalid_equivocation_proof(generate_equivocation_proof( set_id, (1, H256::random(), 10, &equivocation_keyring), diff --git a/substrate/frame/identity/src/benchmarking.rs b/substrate/frame/identity/src/benchmarking.rs index e0b45eeecd1..cdcdb952261 100644 --- a/substrate/frame/identity/src/benchmarking.rs +++ b/substrate/frame/identity/src/benchmarking.rs @@ -671,10 +671,10 @@ mod benchmarks { let username = bounded_username::(bench_username(), bench_suffix()); Identity::::queue_acceptance(&caller, username.clone()); - let expected_exiration = + let expected_expiration = frame_system::Pallet::::block_number() + T::PendingUsernameExpiration::get(); - run_to_block::(expected_exiration + One::one()); + run_to_block::(expected_expiration + One::one()); #[extrinsic_call] _(RawOrigin::Signed(caller.clone()), username); diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index 78d59180b3f..4a977880b31 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -161,7 +161,7 @@ pub mod pallet { /// Structure holding information about an identity. type IdentityInformation: IdentityInformationProvider; - /// Maxmimum number of registrars allowed in the system. Needed to bound the complexity + /// Maximum number of registrars allowed in the system. Needed to bound the complexity /// of, e.g., updating judgements. #[pallet::constant] type MaxRegistrars: Get; diff --git a/substrate/frame/im-online/src/tests.rs b/substrate/frame/im-online/src/tests.rs index 5e5212e1d56..f9959593494 100644 --- a/substrate/frame/im-online/src/tests.rs +++ b/substrate/frame/im-online/src/tests.rs @@ -416,7 +416,7 @@ fn should_handle_non_linear_session_progress() { Session::rotate_session(); - // if we don't have valid results for the current session progres then + // if we don't have valid results for the current session progress then // we'll fallback to `HeartbeatAfter` and only heartbeat on block 5. MockCurrentSessionProgress::mutate(|p| *p = Some(None)); assert_eq!(ImOnline::send_heartbeats(2).err(), Some(OffchainErr::TooEarly)); diff --git a/substrate/frame/merkle-mountain-range/src/lib.rs b/substrate/frame/merkle-mountain-range/src/lib.rs index e3eb0dc8cf5..7b6edb37b7f 100644 --- a/substrate/frame/merkle-mountain-range/src/lib.rs +++ b/substrate/frame/merkle-mountain-range/src/lib.rs @@ -89,7 +89,7 @@ mod tests; /// is not available (since the block is not finished yet), /// we use the `parent_hash` here along with parent block number. pub struct ParentNumberAndHash { - _phanthom: sp_std::marker::PhantomData, + _phantom: sp_std::marker::PhantomData, } impl LeafDataProvider for ParentNumberAndHash { diff --git a/substrate/frame/message-queue/src/lib.rs b/substrate/frame/message-queue/src/lib.rs index 61028057394..93cd760eeb9 100644 --- a/substrate/frame/message-queue/src/lib.rs +++ b/substrate/frame/message-queue/src/lib.rs @@ -1460,7 +1460,7 @@ impl Pallet { /// Run a closure that errors on re-entrance. Meant to be used by anything that services queues. pub(crate) fn with_service_mutex R, R>(f: F) -> Result { - // Holds the singelton token instance. + // Holds the singleton token instance. environmental::environmental!(token: Option<()>); token::using_once(&mut Some(()), || { diff --git a/substrate/frame/message-queue/src/tests.rs b/substrate/frame/message-queue/src/tests.rs index dbef94b3b10..1f6e7777f01 100644 --- a/substrate/frame/message-queue/src/tests.rs +++ b/substrate/frame/message-queue/src/tests.rs @@ -90,7 +90,7 @@ fn queue_priority_retains() { MessageQueue::enqueue_message(msg("d"), Everywhere(2)); assert_ring(&[Everywhere(1), Everywhere(2), Everywhere(3)]); // service head is 1, it will process a, leaving service head at 2. it also processes b but - // doees not empty queue 2, so service head will end at 2. + // does not empty queue 2, so service head will end at 2. assert_eq!(MessageQueue::service_queues(2.into_weight()), 2.into_weight()); assert_eq!( MessagesProcessed::take(), diff --git a/substrate/frame/migrations/src/mock_helpers.rs b/substrate/frame/migrations/src/mock_helpers.rs index c5e23efb4e3..995ec0a922c 100644 --- a/substrate/frame/migrations/src/mock_helpers.rs +++ b/substrate/frame/migrations/src/mock_helpers.rs @@ -107,7 +107,7 @@ impl SteppedMigrations for MockedMigrations { cursor: Option>, meter: &mut WeightMeter, ) -> Option>, SteppedMigrationError>> { - // This is a hack but should be fine. We dont need it in testing. + // This is a hack but should be fine. We don't need it in testing. Self::nth_step(n, cursor, meter) } diff --git a/substrate/frame/nis/README.md b/substrate/frame/nis/README.md index 032df7d0186..8a1a30f17e1 100644 --- a/substrate/frame/nis/README.md +++ b/substrate/frame/nis/README.md @@ -1,5 +1,5 @@ # NIS Module -Provides a non-interactiove variant of staking. +Provides a non-interactive variant of staking. License: Apache-2.0 diff --git a/substrate/frame/nis/src/lib.rs b/substrate/frame/nis/src/lib.rs index 5e547b63e54..7655cd1a824 100644 --- a/substrate/frame/nis/src/lib.rs +++ b/substrate/frame/nis/src/lib.rs @@ -426,7 +426,7 @@ pub mod pallet { }, /// An automatic funding of the deficit was made. Funded { deficit: BalanceOf }, - /// A receipt was transfered. + /// A receipt was transferred. Transferred { from: T::AccountId, to: T::AccountId, index: ReceiptIndex }, } @@ -457,7 +457,7 @@ pub mod pallet { AlreadyFunded, /// The thaw throttle has been reached for this period. Throttled, - /// The operation would result in a receipt worth an insignficant value. + /// The operation would result in a receipt worth an insignificant value. MakesDust, /// The receipt is already communal. AlreadyCommunal, diff --git a/substrate/frame/nis/src/tests.rs b/substrate/frame/nis/src/tests.rs index 7350da97dc6..01724999ae7 100644 --- a/substrate/frame/nis/src/tests.rs +++ b/substrate/frame/nis/src/tests.rs @@ -414,7 +414,7 @@ fn thaw_respects_transfers() { assert_eq!(Balances::reserved_balance(&1), 0); assert_eq!(Balances::reserved_balance(&2), 40); - // Transfering the receipt... + // Transferring the receipt... assert_noop!(Nis::thaw_private(signed(1), 0, None), Error::::NotOwner); // ...and thawing is possible. diff --git a/substrate/frame/node-authorization/src/lib.rs b/substrate/frame/node-authorization/src/lib.rs index 8a823d29f23..9019a863ad8 100644 --- a/substrate/frame/node-authorization/src/lib.rs +++ b/substrate/frame/node-authorization/src/lib.rs @@ -18,7 +18,7 @@ //! # Node authorization pallet //! //! This pallet manages a configurable set of nodes for a permissioned network. -//! Each node is dentified by a PeerId (i.e. `Vec`). It provides two ways to +//! Each node is identified by a PeerId (i.e. `Vec`). It provides two ways to //! authorize a node, //! //! - a set of well known nodes across different organizations in which the @@ -102,7 +102,7 @@ pub mod pallet { #[pallet::getter(fn owners)] pub type Owners = StorageMap<_, Blake2_128Concat, PeerId, T::AccountId>; - /// The additional adapative connections of each node. + /// The additional adaptive connections of each node. #[pallet::storage] #[pallet::getter(fn additional_connection)] pub type AdditionalConnections = @@ -161,7 +161,7 @@ pub mod pallet { NotClaimed, /// You are not the owner of the node. NotOwner, - /// No permisson to perform specific operation. + /// No permission to perform specific operation. PermissionDenied, } @@ -377,7 +377,7 @@ pub mod pallet { /// Add additional connections to a given node. /// /// - `node`: identifier of the node. - /// - `connections`: additonal nodes from which the connections are allowed. + /// - `connections`: additional nodes from which the connections are allowed. #[pallet::call_index(7)] #[pallet::weight(T::WeightInfo::add_connections())] pub fn add_connections( @@ -412,7 +412,7 @@ pub mod pallet { /// Remove additional connections of a given node. /// /// - `node`: identifier of the node. - /// - `connections`: additonal nodes from which the connections are not allowed anymore. + /// - `connections`: additional nodes from which the connections are not allowed anymore. #[pallet::call_index(8)] #[pallet::weight(T::WeightInfo::remove_connections())] pub fn remove_connections( diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs index a0dbdb3aaa4..f29a49a2b1b 100644 --- a/substrate/frame/nomination-pools/src/lib.rs +++ b/substrate/frame/nomination-pools/src/lib.rs @@ -451,7 +451,7 @@ enum AccountType { /// The permission a pool member can set for other accounts to claim rewards on their behalf. #[derive(Encode, Decode, MaxEncodedLen, Clone, Copy, Debug, PartialEq, Eq, TypeInfo)] pub enum ClaimPermission { - /// Only the pool member themself can claim their rewards. + /// Only the pool member themselves can claim their rewards. Permissioned, /// Anyone can compound rewards on a pool member's behalf. PermissionlessCompound, @@ -2066,7 +2066,7 @@ pub mod pallet { /// The member will earn rewards pro rata based on the members stake vs the sum of the /// members in the pools stake. Rewards do not "expire". /// - /// See `claim_payout_other` to caim rewards on bahalf of some `other` pool member. + /// See `claim_payout_other` to claim rewards on behalf of some `other` pool member. #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::claim_payout())] pub fn claim_payout(origin: OriginFor) -> DispatchResult { @@ -2797,7 +2797,7 @@ pub mod pallet { /// Set or remove a pool's commission claim permission. /// /// Determines who can claim the pool's pending commission. Only the `Root` role of the pool - /// is able to conifigure commission claim permissions. + /// is able to configure commission claim permissions. #[pallet::call_index(22)] #[pallet::weight(T::WeightInfo::set_commission_claim_permission())] pub fn set_commission_claim_permission( @@ -2836,7 +2836,7 @@ pub mod pallet { assert!( T::Staking::bonding_duration() < TotalUnbondingPools::::get(), "There must be more unbonding pools then the bonding duration / - so a slash can be applied to relevant unboding pools. (We assume / + so a slash can be applied to relevant unbonding pools. (We assume / the bonding duration > slash deffer duration.", ); } diff --git a/substrate/frame/nomination-pools/src/migration.rs b/substrate/frame/nomination-pools/src/migration.rs index 14410339f59..ca9c0874a83 100644 --- a/substrate/frame/nomination-pools/src/migration.rs +++ b/substrate/frame/nomination-pools/src/migration.rs @@ -70,7 +70,7 @@ pub mod unversioned { fn on_runtime_upgrade() -> Weight { let migrated = BondedPools::::count(); - // recalcuate the `TotalValueLocked` to compare with the current on-chain TVL which may + // recalculate the `TotalValueLocked` to compare with the current on-chain TVL which may // be out of sync. let tvl: BalanceOf = helpers::calculate_tvl_by_total_stake::(); let onchain_tvl = TotalValueLocked::::get(); diff --git a/substrate/frame/offences/src/tests.rs b/substrate/frame/offences/src/tests.rs index d525c7c3ab1..4897b78f3e4 100644 --- a/substrate/frame/offences/src/tests.rs +++ b/substrate/frame/offences/src/tests.rs @@ -204,7 +204,7 @@ fn reports_if_an_offence_is_dup() { assert_eq!(Offences::report_offence(vec![], test_offence.clone()), Ok(())); // creating a new offence for the same authorities on the next slot - // should be considered a new offence and thefore not known + // should be considered a new offence and therefore not known let test_offence_next_slot = offence(time_slot + 1, vec![0, 1]); assert!(!>::is_known_offence( &test_offence_next_slot.offenders, diff --git a/substrate/frame/paged-list/src/paged_list.rs b/substrate/frame/paged-list/src/paged_list.rs index 75467f3ceeb..eecc728cd62 100644 --- a/substrate/frame/paged-list/src/paged_list.rs +++ b/substrate/frame/paged-list/src/paged_list.rs @@ -190,7 +190,7 @@ impl Page { let values = sp_io::storage::get(&key) .and_then(|raw| sp_std::vec::Vec::::decode(&mut &raw[..]).ok())?; if values.is_empty() { - // Dont create empty pages. + // Don't create empty pages. return None } let values = values.into_iter().skip(value_index as usize); diff --git a/substrate/frame/parameters/src/lib.rs b/substrate/frame/parameters/src/lib.rs index 3e54eb6d67f..55a6f1ff91d 100644 --- a/substrate/frame/parameters/src/lib.rs +++ b/substrate/frame/parameters/src/lib.rs @@ -122,7 +122,7 @@ use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; use frame_support::traits::{ - dynamic_params::{AggregratedKeyValue, IntoKey, Key, RuntimeParameterStore, TryIntoKey}, + dynamic_params::{AggregatedKeyValue, IntoKey, Key, RuntimeParameterStore, TryIntoKey}, EnsureOriginWithArg, }; @@ -135,10 +135,10 @@ pub use pallet::*; pub use weights::WeightInfo; /// The key type of a parameter. -type KeyOf = <::RuntimeParameters as AggregratedKeyValue>::Key; +type KeyOf = <::RuntimeParameters as AggregatedKeyValue>::Key; /// The value type of a parameter. -type ValueOf = <::RuntimeParameters as AggregratedKeyValue>::Value; +type ValueOf = <::RuntimeParameters as AggregatedKeyValue>::Value; #[frame_support::pallet] pub mod pallet { @@ -154,7 +154,7 @@ pub mod pallet { /// /// Usually created by [`frame_support::dynamic_params`] or equivalent. #[pallet::no_default_bounds] - type RuntimeParameters: AggregratedKeyValue; + type RuntimeParameters: AggregatedKeyValue; /// The origin which may update a parameter. /// @@ -175,11 +175,11 @@ pub mod pallet { /// Is also emitted when the value was not changed. Updated { /// The key that was updated. - key: ::Key, + key: ::Key, /// The old value before this call. - old_value: Option<::Value>, + old_value: Option<::Value>, /// The new value after this call. - new_value: Option<::Value>, + new_value: Option<::Value>, }, } @@ -245,23 +245,23 @@ pub mod pallet { } impl RuntimeParameterStore for Pallet { - type AggregratedKeyValue = T::RuntimeParameters; + type AggregatedKeyValue = T::RuntimeParameters; fn get(key: K) -> Option where - KV: AggregratedKeyValue, - K: Key + Into<::Key>, - ::Key: IntoKey< - <::AggregratedKeyValue as AggregratedKeyValue>::Key, + KV: AggregatedKeyValue, + K: Key + Into<::Key>, + ::Key: IntoKey< + <::AggregatedKeyValue as AggregatedKeyValue>::Key, >, - <::AggregratedKeyValue as AggregratedKeyValue>::Value: - TryIntoKey<::Value>, - ::Value: TryInto, + <::AggregatedKeyValue as AggregatedKeyValue>::Value: + TryIntoKey<::Value>, + ::Value: TryInto, { - let key: ::Key = key.into(); + let key: ::Key = key.into(); let val = Parameters::::get(key.into_key()); val.and_then(|v| { - let val: ::Value = v.try_into_key().ok()?; + let val: ::Value = v.try_into_key().ok()?; let val: K::WrappedValue = val.try_into().ok()?; let val = val.into(); Some(val) diff --git a/substrate/frame/parameters/src/tests/unit.rs b/substrate/frame/parameters/src/tests/unit.rs index d3f11ba9640..d811a835646 100644 --- a/substrate/frame/parameters/src/tests/unit.rs +++ b/substrate/frame/parameters/src/tests/unit.rs @@ -25,7 +25,7 @@ use crate::tests::mock::{ RuntimeParametersValue, }; use codec::Encode; -use frame_support::{assert_noop, assert_ok, traits::dynamic_params::AggregratedKeyValue}; +use frame_support::{assert_noop, assert_ok, traits::dynamic_params::AggregatedKeyValue}; use sp_core::Get; use sp_runtime::DispatchError; diff --git a/substrate/frame/proxy/src/lib.rs b/substrate/frame/proxy/src/lib.rs index 4d4da0433af..2b3fac5f59e 100644 --- a/substrate/frame/proxy/src/lib.rs +++ b/substrate/frame/proxy/src/lib.rs @@ -119,7 +119,7 @@ pub mod pallet { /// The currency mechanism. type Currency: ReservableCurrency; - /// A kind of proxy; specified with the proxy and passed in to the `IsProxyable` fitler. + /// A kind of proxy; specified with the proxy and passed in to the `IsProxyable` filter. /// The instance filter determines whether a given call may be proxied under this type. /// /// IMPORTANT: `Default` must be provided and MUST BE the the *most permissive* value. diff --git a/substrate/frame/root-testing/src/lib.rs b/substrate/frame/root-testing/src/lib.rs index 51fd835409a..98e1f5c5b66 100644 --- a/substrate/frame/root-testing/src/lib.rs +++ b/substrate/frame/root-testing/src/lib.rs @@ -17,7 +17,7 @@ //! # Root Testing Pallet //! -//! Pallet that contains extrinsics that can be usefull in testing. +//! Pallet that contains extrinsics that can be useful in testing. //! //! NOTE: This pallet should only be used for testing purposes and should not be used in production //! runtimes! diff --git a/substrate/frame/salary/src/tests/integration.rs b/substrate/frame/salary/src/tests/integration.rs index 26afb2d8aba..124ab38c565 100644 --- a/substrate/frame/salary/src/tests/integration.rs +++ b/substrate/frame/salary/src/tests/integration.rs @@ -250,7 +250,7 @@ fn swap_exhaustive_works() { }); assert_eq!(root_add, root_swap); - // Ensure that we dont compare trivial stuff like `()` from a type error above. + // Ensure that we don't compare trivial stuff like `()` from a type error above. assert_eq!(root_add.len(), 32); }); } diff --git a/substrate/frame/salary/src/tests/unit.rs b/substrate/frame/salary/src/tests/unit.rs index 5e308354116..db1c8b947ef 100644 --- a/substrate/frame/salary/src/tests/unit.rs +++ b/substrate/frame/salary/src/tests/unit.rs @@ -508,7 +508,7 @@ fn zero_payment_fails() { } #[test] -fn unregistered_bankrupcy_fails_gracefully() { +fn unregistered_bankruptcy_fails_gracefully() { new_test_ext().execute_with(|| { assert_ok!(Salary::init(RuntimeOrigin::signed(1))); set_rank(1, 2); @@ -532,7 +532,7 @@ fn unregistered_bankrupcy_fails_gracefully() { } #[test] -fn registered_bankrupcy_fails_gracefully() { +fn registered_bankruptcy_fails_gracefully() { new_test_ext().execute_with(|| { assert_ok!(Salary::init(RuntimeOrigin::signed(1))); set_rank(1, 2); @@ -561,7 +561,7 @@ fn registered_bankrupcy_fails_gracefully() { } #[test] -fn mixed_bankrupcy_fails_gracefully() { +fn mixed_bankruptcy_fails_gracefully() { new_test_ext().execute_with(|| { assert_ok!(Salary::init(RuntimeOrigin::signed(1))); set_rank(1, 2); @@ -589,7 +589,7 @@ fn mixed_bankrupcy_fails_gracefully() { } #[test] -fn other_mixed_bankrupcy_fails_gracefully() { +fn other_mixed_bankruptcy_fails_gracefully() { new_test_ext().execute_with(|| { assert_ok!(Salary::init(RuntimeOrigin::signed(1))); set_rank(1, 2); diff --git a/substrate/frame/sassafras/src/benchmarking.rs b/substrate/frame/sassafras/src/benchmarking.rs index 1c9626ad260..2b2467c6f84 100644 --- a/substrate/frame/sassafras/src/benchmarking.rs +++ b/substrate/frame/sassafras/src/benchmarking.rs @@ -84,7 +84,7 @@ mod benchmarks { // - load the full ring context. // - recompute the ring verifier. // - sorting the epoch tickets in one shot - // (here we account for the very unluky scenario where we haven't done any sort work yet) + // (here we account for the very unlucky scenario where we haven't done any sort work yet) // - pending epoch change config. // // For this bench we assume a redundancy factor of 2 (suggested value to be used in prod). diff --git a/substrate/frame/sassafras/src/lib.rs b/substrate/frame/sassafras/src/lib.rs index 0ee8657489b..8cbf1e47e32 100644 --- a/substrate/frame/sassafras/src/lib.rs +++ b/substrate/frame/sassafras/src/lib.rs @@ -234,7 +234,7 @@ pub mod pallet { /// Epoch X first N-th ticket has key (X mod 2, N) /// /// Note that the ticket's index doesn't directly correspond to the slot index within the epoch. - /// The assigment is computed dynamically using an *outside-in* strategy. + /// The assignment is computed dynamically using an *outside-in* strategy. /// /// Be aware that entries within this map are never removed, only overwritten. /// Last element index should be fetched from the [`TicketsMeta`] value. @@ -465,7 +465,7 @@ pub mod pallet { /// Plan an epoch configuration change. /// - /// The epoch configuration change is recorded and will be announced at the begining + /// The epoch configuration change is recorded and will be announced at the beginning /// of the next epoch together with next epoch authorities information. /// In other words, the configuration will be enacted one epoch later. /// @@ -758,11 +758,11 @@ impl Pallet { let randomness = hashing::blake2_256(buf.as_slice()); RandomnessAccumulator::::put(randomness); - let next_randoness = Self::update_epoch_randomness(1); + let next_randomness = Self::update_epoch_randomness(1); // Deposit a log as this is the first block in first epoch. let next_epoch = NextEpochDescriptor { - randomness: next_randoness, + randomness: next_randomness, authorities: Self::next_authorities().into_inner(), config: None, }; diff --git a/substrate/frame/scheduler/README.md b/substrate/frame/scheduler/README.md index 6aec2ddb0e4..5e233fdbdb0 100644 --- a/substrate/frame/scheduler/README.md +++ b/substrate/frame/scheduler/README.md @@ -16,7 +16,7 @@ for the origin: namely `frame_system::Config::BaseCallFilter` for all origin except root which will get no filter. And not the filter contained in origin use to call `fn schedule`. -If a call is scheduled using proxy or whatever mecanism which adds filter, +If a call is scheduled using proxy or whatever mechanism which adds filter, then those filter will not be used when dispatching the schedule call. ## Interface diff --git a/substrate/frame/scheduler/src/benchmarking.rs b/substrate/frame/scheduler/src/benchmarking.rs index 18441d54b39..884f7800038 100644 --- a/substrate/frame/scheduler/src/benchmarking.rs +++ b/substrate/frame/scheduler/src/benchmarking.rs @@ -211,7 +211,7 @@ benchmarks! { } verify { } - // `execute_dispatch` when the origin is `Signed`, not counting the dispatable's weight. + // `execute_dispatch` when the origin is `Signed`, not counting the dispatchable's weight. execute_dispatch_signed { let mut counter = WeightMeter::new(); let origin = make_origin::(true); @@ -222,7 +222,7 @@ benchmarks! { verify { } - // `execute_dispatch` when the origin is not `Signed`, not counting the dispatable's weight. + // `execute_dispatch` when the origin is not `Signed`, not counting the dispatchable's weight. execute_dispatch_unsigned { let mut counter = WeightMeter::new(); let origin = make_origin::(false); diff --git a/substrate/frame/scheduler/src/lib.rs b/substrate/frame/scheduler/src/lib.rs index af3abd8ac4f..62417b8d2cc 100644 --- a/substrate/frame/scheduler/src/lib.rs +++ b/substrate/frame/scheduler/src/lib.rs @@ -46,7 +46,7 @@ //! 1. Scheduling a runtime call at a specific block. #![doc = docify::embed!("src/tests.rs", basic_scheduling_works)] //! -//! 2. Scheduling a preimage hash of a runtime call at a specifc block +//! 2. Scheduling a preimage hash of a runtime call at a specific block #![doc = docify::embed!("src/tests.rs", scheduling_with_preimages_works)] //! diff --git a/substrate/frame/scheduler/src/tests.rs b/substrate/frame/scheduler/src/tests.rs index 1ed2ca9e2f3..bb02320ad75 100644 --- a/substrate/frame/scheduler/src/tests.rs +++ b/substrate/frame/scheduler/src/tests.rs @@ -1119,7 +1119,7 @@ fn reschedule_named_works() { } #[test] -fn reschedule_named_perodic_works() { +fn reschedule_named_periodic_works() { new_test_ext().execute_with(|| { let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_parts(10, 0) }); @@ -2980,7 +2980,7 @@ fn reschedule_named_last_task_removes_agenda() { }); } -/// Ensures that an unvailable call sends an event. +/// Ensures that an unavailable call sends an event. #[test] fn unavailable_call_is_detected() { use frame_support::traits::schedule::v3::Named; diff --git a/substrate/frame/society/src/lib.rs b/substrate/frame/society/src/lib.rs index 99dd580a403..5bce245f73f 100644 --- a/substrate/frame/society/src/lib.rs +++ b/substrate/frame/society/src/lib.rs @@ -1509,7 +1509,7 @@ impl, I: 'static> Pallet { // the Founder. if MemberCount::::get() > 2 { let defender = next_defender - .or_else(|| Self::pick_defendent(rng)) + .or_else(|| Self::pick_defendant(rng)) .expect("exited if members empty; qed"); let skeptic = Self::pick_member_except(rng, &defender).expect("exited if members empty; qed"); @@ -1871,7 +1871,7 @@ impl, I: 'static> Pallet { /// /// If only the Founder and Head members exist (or the state is inconsistent), then `None` /// may be returned. - fn pick_defendent(rng: &mut impl RngCore) -> Option { + fn pick_defendant(rng: &mut impl RngCore) -> Option { let member_count = MemberCount::::get(); if member_count <= 2 { return None @@ -1976,7 +1976,7 @@ impl, I: 'static> Pallet { /// Transfer some `amount` from the main account into the payouts account and reduce the Pot /// by this amount. fn reserve_payout(amount: BalanceOf) { - // Tramsfer payout from the Pot into the payouts account. + // Transfer payout from the Pot into the payouts account. Pot::::mutate(|pot| pot.saturating_reduce(amount)); // this should never fail since we ensure we can afford the payouts in a previous @@ -1988,7 +1988,7 @@ impl, I: 'static> Pallet { /// Transfer some `amount` from the main account into the payouts account and increase the Pot /// by this amount. fn unreserve_payout(amount: BalanceOf) { - // Tramsfer payout from the Pot into the payouts account. + // Transfer payout from the Pot into the payouts account. Pot::::mutate(|pot| pot.saturating_accrue(amount)); // this should never fail since we ensure we can afford the payouts in a previous diff --git a/substrate/frame/society/src/migrations.rs b/substrate/frame/society/src/migrations.rs index 6a102911451..8fd87b1163a 100644 --- a/substrate/frame/society/src/migrations.rs +++ b/substrate/frame/society/src/migrations.rs @@ -240,7 +240,7 @@ pub fn assert_internal_consistency, I: Instance + 'static>() { pub fn from_original, I: Instance + 'static>( past_payouts: &mut [(::AccountId, BalanceOf)], ) -> Result { - // Migrate Bids from old::Bids (just a trunctation). + // Migrate Bids from old::Bids (just a truncation). Bids::::put(BoundedVec::<_, T::MaxBids>::truncate_from(v0::Bids::::take())); // Initialise round counter. @@ -287,13 +287,13 @@ pub fn from_original, I: Instance + 'static>( .defensive_ok_or("member_count > 0, we must have at least 1 member")?; // Swap the founder with the first member in MemberByIndex. MemberByIndex::::swap(0, member_count); - // Update the indicies of the swapped member MemberRecords. + // Update the indices of the swapped member MemberRecords. Members::::mutate(&member, |m| { if let Some(member) = m { member.index = 0; } else { frame_support::defensive!( - "Member somehow disapeared from storage after it was inserted" + "Member somehow disappeared from storage after it was inserted" ); } }); @@ -302,7 +302,7 @@ pub fn from_original, I: Instance + 'static>( member.index = member_count; } else { frame_support::defensive!( - "Member somehow disapeared from storage after it was queried" + "Member somehow disappeared from storage after it was queried" ); } }); diff --git a/substrate/frame/society/src/tests.rs b/substrate/frame/society/src/tests.rs index 411567e1ded..5f8ecc9a7c5 100644 --- a/substrate/frame/society/src/tests.rs +++ b/substrate/frame/society/src/tests.rs @@ -541,7 +541,7 @@ fn suspended_candidate_rejected_works() { assert_ok!(Society::vote(Origin::signed(30), x, true)); } - // Voting continues, as no canidate is clearly accepted yet and the founder chooses not to + // Voting continues, as no candidate is clearly accepted yet and the founder chooses not to // act. conclude_intake(false, None); assert_eq!(members(), vec![10, 20, 30]); diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index 67be1e15bc6..9461daefed6 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -130,7 +130,7 @@ impl StakingLedger { // if ledger bond is in a bad state, return error to prevent applying operations that may // further spoil the ledger's state. A bond is in bad state when the bonded controller is - // associted with a different ledger (i.e. a ledger with a different stash). + // associated with a different ledger (i.e. a ledger with a different stash). // // See for more details. ensure!( diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 3e3b1113a81..d5b18421d5b 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -30,7 +30,7 @@ use frame_support::ensure; #[cfg(feature = "try-runtime")] use sp_runtime::TryRuntimeError; -/// Used for release versioning upto v12. +/// Used for release versioning up to v12. /// /// Obsolete from v13. Keeping around to make encoding/decoding of old migration code easier. #[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index d42456e53b1..407b301fad2 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1906,7 +1906,7 @@ impl Pallet { /// Invariants: /// * A bonded ledger should always have an assigned `Payee`. /// * The number of entries in `Payee` and of bonded staking ledgers *must* match. - /// * The stash account in the ledger must match that of the bonded acount. + /// * The stash account in the ledger must match that of the bonded account. fn check_payees() -> Result<(), TryRuntimeError> { for (stash, _) in Bonded::::iter() { ensure!(Payee::::get(&stash).is_some(), "bonded ledger does not have payee set"); @@ -1947,7 +1947,7 @@ impl Pallet { /// Invariants: /// * `ledger.controller` is not stored in the storage (but populated at retrieval). /// * Stake consistency: ledger.total == ledger.active + sum(ledger.unlocking). - /// * The controller keyeing the ledger and the ledger stash matches the state of the `Bonded` + /// * The controller keying the ledger and the ledger stash matches the state of the `Bonded` /// storage. fn check_ledgers() -> Result<(), TryRuntimeError> { Bonded::::iter() diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 1bf8bd8b09c..6afbf12032d 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -54,7 +54,7 @@ use crate::{ }; // The speculative number of spans are used as an input of the weight annotation of -// [`Call::unbond`], as the post dipatch weight may depend on the number of slashing span on the +// [`Call::unbond`], as the post dispatch weight may depend on the number of slashing span on the // account which is not provided as an input. The value set should be conservative but sensible. pub(crate) const SPECULATIVE_NUM_SPANS: u32 = 32; @@ -1134,7 +1134,7 @@ pub mod pallet { /// this call results in a complete removal of all the data related to the stash account. /// In this case, the `num_slashing_spans` must be larger or equal to the number of /// slashing spans associated with the stash account in the [`SlashingSpans`] storage type, - /// otherwise the call will fail. The call weight is directly propotional to + /// otherwise the call will fail. The call weight is directly proportional to /// `num_slashing_spans`. /// /// ## Complexity @@ -1376,7 +1376,7 @@ pub mod pallet { Ok(()) } - /// Increments the ideal number of validators upto maximum of + /// Increments the ideal number of validators up to maximum of /// `ElectionProviderBase::MaxWinners`. /// /// The dispatch origin must be Root. @@ -1401,7 +1401,7 @@ pub mod pallet { Ok(()) } - /// Scale up the ideal number of validators by a factor upto maximum of + /// Scale up the ideal number of validators by a factor up to maximum of /// `ElectionProviderBase::MaxWinners`. /// /// The dispatch origin must be Root. diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 3725c9e3c2c..ef156e19552 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -270,7 +270,7 @@ fn change_controller_works() { assert_eq!(ledger.controller(), Some(stash)); // the raw storage ledger's controller is always `None`. however, we can still fetch the - // correct controller with `ledger.controler()`. + // correct controller with `ledger.controller()`. let raw_ledger = >::get(&stash).unwrap(); assert_eq!(raw_ledger.controller, None); @@ -1257,7 +1257,7 @@ fn bond_extra_controller_bad_state_works() { Bonded::::insert(31, 41); // we confirm that the ledger is in bad state: 31 has 41 as controller and when fetching - // the ledger associated with the controler 41, its stash is 41 (and not 31). + // the ledger associated with the controller 41, its stash is 41 (and not 31). assert_eq!(Ledger::::get(41).unwrap().stash, 41); // if the ledger is in this bad state, the `bond_extra` should fail. @@ -1815,7 +1815,7 @@ fn max_staked_rewards_works() { let total_payout = treasury_payout + validators_payout; // max stakers payout (without max staked rewards cap applied) is larger than the final - // validator rewards. The final payment and remainder should be adjusted by redestributing + // validator rewards. The final payment and remainder should be adjusted by redistributing // the era inflation to apply the cap... assert!(max_stakers_payout > validators_payout); @@ -4686,7 +4686,7 @@ fn bond_during_era_does_not_populate_legacy_claimed_rewards() { } ); - // make sure only era upto history depth is stored + // make sure only era up to history depth is stored let current_era = 99; mock::start_active_era(current_era); bond_validator(13, 1000); @@ -5412,7 +5412,7 @@ mod election_data_provider { Event::SnapshotVotersSizeExceeded { size: 75 } ); - // however, if the election voter size bounds were largers, the snapshot would + // however, if the election voter size bounds were larger, the snapshot would // include the electing voters of 70. let bounds = ElectionBoundsBuilder::default().voters_size(1_000.into()).build(); assert_eq!( diff --git a/substrate/frame/sudo/src/lib.rs b/substrate/frame/sudo/src/lib.rs index d8b734e6bbe..63b68e69430 100644 --- a/substrate/frame/sudo/src/lib.rs +++ b/substrate/frame/sudo/src/lib.rs @@ -38,7 +38,7 @@ //! In Substrate blockchains, pallets may contain dispatchable calls that can only be called at //! the system level of the chain (i.e. dispatchables that require a `Root` origin). //! Setting a privileged account, called the _sudo key_, allows you to make such calls as an -//! extrinisic. +//! extrinsic. //! //! Here's an example of a privileged function in another pallet: //! diff --git a/substrate/frame/support/procedural/src/benchmark.rs b/substrate/frame/support/procedural/src/benchmark.rs index ea53ad263a1..0a62c3f92a6 100644 --- a/substrate/frame/support/procedural/src/benchmark.rs +++ b/substrate/frame/support/procedural/src/benchmark.rs @@ -249,7 +249,7 @@ impl BenchmarkCallDef { } } -/// Represents a parsed `#[benchmark]` or `#[instance_banchmark]` item. +/// Represents a parsed `#[benchmark]` or `#[instance_benchmark]` item. #[derive(Clone)] struct BenchmarkDef { params: Vec, @@ -466,7 +466,7 @@ pub fn benchmarks( let mod_vis = module.vis; let mod_name = module.ident; - // consume #[benchmarks] attribute by exclusing it from mod_attrs + // consume #[benchmarks] attribute by excluding it from mod_attrs let mod_attrs: Vec<&Attribute> = module .attrs .iter() diff --git a/substrate/frame/support/procedural/src/construct_runtime/mod.rs b/substrate/frame/support/procedural/src/construct_runtime/mod.rs index 1937dfa9ca4..b083abbb2a8 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/mod.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/mod.rs @@ -24,7 +24,7 @@ //! - Implicitly: `System: frame_system` //! - Explicitly: `System: frame_system::{Pallet, Call}` //! -//! The `construct_runtime` transitions from the implicit definition to the explict one. +//! The `construct_runtime` transitions from the implicit definition to the explicit one. //! From the explicit state, Substrate expands the pallets with additional information //! that is to be included in the runtime metadata. This expansion makes visible some extra //! parts of the pallets, mainly the `Error` if defined. The expanded state looks like @@ -55,7 +55,7 @@ //! +----------+ +------------------+ //! ``` //! -//! When all pallet parts are implcit, then the `construct_runtime!` macro expands to its final +//! When all pallet parts are implicit, then the `construct_runtime!` macro expands to its final //! state, the `ExplicitExpanded`. Otherwise, all implicit parts are converted to an explicit //! expanded part allow the `construct_runtime!` to expand any remaining explicit parts to an //! explicit expanded part. @@ -202,7 +202,7 @@ //! Similarly to the previous transition, the macro expansion transforms `System: //! frame_system::{Pallet, Call}` into `System: frame_system expanded::{Error} ::{Pallet, Call}`. //! The `expanded` section adds extra parts that the Substrate would like to expose for each pallet -//! by default. This is done to expose the approprite types for metadata construction. +//! by default. This is done to expose the appropriate types for metadata construction. //! //! This time, instead of calling `tt_default_parts` we are using the `tt_extra_parts` macro. //! This macro returns the ` :: expanded { Error }` list of additional parts we would like to diff --git a/substrate/frame/support/procedural/src/construct_runtime/parse.rs b/substrate/frame/support/procedural/src/construct_runtime/parse.rs index 88f3f14dc86..31866c787b0 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/parse.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/parse.rs @@ -322,7 +322,7 @@ impl Parse for PalletDeclaration { /// A struct representing a path to a pallet. `PalletPath` is almost identical to the standard /// Rust path with a few restrictions: /// - No leading colons allowed -/// - Path segments can only consist of identifers separated by colons +/// - Path segments can only consist of identifiers separated by colons #[derive(Debug, Clone)] pub struct PalletPath { pub inner: Path, @@ -595,7 +595,7 @@ pub struct Pallet { pub is_expanded: bool, /// The name of the pallet, e.g.`System` in `System: frame_system`. pub name: Ident, - /// Either automatically infered, or defined (e.g. `MyPallet ... = 3,`). + /// Either automatically inferred, or defined (e.g. `MyPallet ... = 3,`). pub index: u8, /// The path of the pallet, e.g. `frame_system` in `System: frame_system`. pub path: PalletPath, @@ -634,7 +634,7 @@ impl Pallet { /// +----------+ +----------+ +------------------+ /// ``` enum PalletsConversion { - /// Pallets implicitely declare parts. + /// Pallets implicitly declare parts. /// /// `System: frame_system`. Implicit(Vec), @@ -648,7 +648,7 @@ enum PalletsConversion { /// Pallets explicitly declare parts that are fully expanded. /// /// This is the end state that contains extra parts included by - /// default by Subtrate. + /// default by Substrate. /// /// `System: frame_system expanded::{Error} ::{Pallet, Call}` /// @@ -660,7 +660,7 @@ enum PalletsConversion { /// /// Check if all pallet have explicit declaration of their parts, if so then assign index to each /// pallet using same rules as rust for fieldless enum. I.e. implicit are assigned number -/// incrementedly from last explicit or 0. +/// incrementally from last explicit or 0. fn convert_pallets(pallets: Vec) -> syn::Result { if pallets.iter().any(|pallet| pallet.pallet_parts.is_none()) { return Ok(PalletsConversion::Implicit(pallets)) diff --git a/substrate/frame/support/procedural/src/derive_impl.rs b/substrate/frame/support/procedural/src/derive_impl.rs index 8740ccd401a..54755f1163a 100644 --- a/substrate/frame/support/procedural/src/derive_impl.rs +++ b/substrate/frame/support/procedural/src/derive_impl.rs @@ -279,7 +279,7 @@ fn test_runtime_type_with_doc() { } #[test] -fn test_disambugation_path() { +fn test_disambiguation_path() { let foreign_impl: ItemImpl = parse_quote!(impl SomeTrait for SomeType {}); let default_impl_path: Path = parse_quote!(SomeScope::SomeType); diff --git a/substrate/frame/support/procedural/src/dynamic_params.rs b/substrate/frame/support/procedural/src/dynamic_params.rs index b718ccbc955..29399a885bc 100644 --- a/substrate/frame/support/procedural/src/dynamic_params.rs +++ b/substrate/frame/support/procedural/src/dynamic_params.rs @@ -147,8 +147,8 @@ fn ensure_codec_index(attrs: &Vec, span: Span) -> Result<()> { /// Used to inject arguments into the inner `#[dynamic_pallet_params(..)]` attribute. /// -/// This allows the outer `#[dynamic_params(..)]` attribute to specify some arguments that dont need -/// to be repeated every time. +/// This allows the outer `#[dynamic_params(..)]` attribute to specify some arguments that don't +/// need to be repeated every time. struct MacroInjectArgs { runtime_params: syn::Ident, params_pallet: syn::Type, @@ -311,7 +311,7 @@ impl ToTokens for DynamicPalletParamAttr { )* } - impl #scrate::traits::dynamic_params::AggregratedKeyValue for Parameters { + impl #scrate::traits::dynamic_params::AggregatedKeyValue for Parameters { type Key = #key_ident; type Value = #value_ident; @@ -497,7 +497,7 @@ impl ToTokens for DynamicParamAggregatedEnum { #vis enum #params_key_ident { #( #(#attributes)* - #param_names(<#param_types as #scrate::traits::dynamic_params::AggregratedKeyValue>::Key), + #param_names(<#param_types as #scrate::traits::dynamic_params::AggregatedKeyValue>::Key), )* } @@ -515,11 +515,11 @@ impl ToTokens for DynamicParamAggregatedEnum { #vis enum #params_value_ident { #( #(#attributes)* - #param_names(<#param_types as #scrate::traits::dynamic_params::AggregratedKeyValue>::Value), + #param_names(<#param_types as #scrate::traits::dynamic_params::AggregatedKeyValue>::Value), )* } - impl #scrate::traits::dynamic_params::AggregratedKeyValue for #name { + impl #scrate::traits::dynamic_params::AggregatedKeyValue for #name { type Key = #params_key_ident; type Value = #params_value_ident; @@ -536,13 +536,13 @@ impl ToTokens for DynamicParamAggregatedEnum { } #( - impl ::core::convert::From<<#param_types as #scrate::traits::dynamic_params::AggregratedKeyValue>::Key> for #params_key_ident { - fn from(key: <#param_types as #scrate::traits::dynamic_params::AggregratedKeyValue>::Key) -> Self { + impl ::core::convert::From<<#param_types as #scrate::traits::dynamic_params::AggregatedKeyValue>::Key> for #params_key_ident { + fn from(key: <#param_types as #scrate::traits::dynamic_params::AggregatedKeyValue>::Key) -> Self { #params_key_ident::#param_names(key) } } - impl ::core::convert::TryFrom<#params_value_ident> for <#param_types as #scrate::traits::dynamic_params::AggregratedKeyValue>::Value { + impl ::core::convert::TryFrom<#params_value_ident> for <#param_types as #scrate::traits::dynamic_params::AggregatedKeyValue>::Value { type Error = (); fn try_from(value: #params_value_ident) -> Result { diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index dee6d522d25..bc62c0509b0 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -137,7 +137,7 @@ fn counter_prefix(prefix: &str) -> String { /// - `Call` - If the pallet has callable functions /// - `Storage` - If the pallet uses storage /// - `Event` or `Event` (if the event is generic) - If the pallet emits events -/// - `Origin` or `Origin` (if the origin is generic) - If the pallet has instanciable origins +/// - `Origin` or `Origin` (if the origin is generic) - If the pallet has instantiable origins /// - `Config` or `Config` (if the config is generic) - If the pallet builds the genesis /// storage with `GenesisConfig` /// - `Inherent` - If the pallet provides/can check inherents. @@ -166,7 +166,7 @@ fn counter_prefix(prefix: &str) -> String { /// and `Event` are encoded, and to define the ModuleToIndex value. /// /// if `= $n` is not given, then index is resolved in the same way as fieldless enum in Rust -/// (i.e. incrementedly from previous index): +/// (i.e. incrementally from previous index): /// ```nocompile /// pallet1 .. = 2, /// pallet2 .., // Here pallet2 is given index 3 @@ -460,7 +460,7 @@ pub fn storage_alias(attributes: TokenStream, input: TokenStream) -> TokenStream } /// This attribute can be used to derive a full implementation of a trait based on a local partial -/// impl and an external impl containing defaults that can be overriden in the local impl. +/// impl and an external impl containing defaults that can be overridden in the local impl. /// /// For a full end-to-end example, see [below](#use-case-auto-derive-test-pallet-config-traits). /// diff --git a/substrate/frame/support/procedural/src/pallet/parse/mod.rs b/substrate/frame/support/procedural/src/pallet/parse/mod.rs index b55f130a93a..6e12774611d 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/mod.rs @@ -321,7 +321,7 @@ impl Def { Ok(()) } - /// Tries to locate a manual tasks impl (an impl impling a trait whose last path segment is + /// Tries to locate a manual tasks impl (an impl implementing a trait whose last path segment is /// `Task`) in the event that one has not been found already via the attribute macro pub fn resolve_manual_tasks_impl( tasks: &mut Option, diff --git a/substrate/frame/support/src/dispatch_context.rs b/substrate/frame/support/src/dispatch_context.rs index 608187b7220..254302c8f14 100644 --- a/substrate/frame/support/src/dispatch_context.rs +++ b/substrate/frame/support/src/dispatch_context.rs @@ -18,7 +18,7 @@ //! Provides functions to interact with the dispatch context. //! //! A Dispatch context is created by calling [`run_in_context`] and then the given closure will be -//! executed in this dispatch context. Everyting run in this `closure` will have access to the same +//! executed in this dispatch context. Everything run in this `closure` will have access to the same //! dispatch context. This also applies to nested calls of [`run_in_context`]. The dispatch context //! can be used to store and retrieve information locally in this context. The dispatch context can //! be accessed by using [`with_context`]. This function will execute the given closure and give it @@ -51,7 +51,7 @@ //! //! run_in_context(|| { //! with_context::(|v| { -//! // Intitialize the value to the default value. +//! // Initialize the value to the default value. //! assert_eq!(0, v.or_default().0); //! v.or_default().0 = 10; //! }); diff --git a/substrate/frame/support/src/instances.rs b/substrate/frame/support/src/instances.rs index 396018d5cbd..ecb356af50b 100644 --- a/substrate/frame/support/src/instances.rs +++ b/substrate/frame/support/src/instances.rs @@ -31,83 +31,83 @@ //! NOTE: [`frame_support::pallet`] will reexport them inside the module, in order to make them //! accessible to [`frame_support::construct_runtime`]. -/// `Instance1` to be used for instantiable palllets defined with the +/// `Instance1` to be used for instantiable pallets defined with the /// [`#[pallet]`](`frame_support::pallet`) macro. Instances 2-16 are also available but are hidden /// from docs. #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance1; -/// `Instance2` to be used for instantiable palllets defined with the `#[pallet]` macro. +/// `Instance2` to be used for instantiable pallets defined with the `#[pallet]` macro. #[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance2; -/// `Instance3` to be used for instantiable palllets defined with the `#[pallet]` macro. +/// `Instance3` to be used for instantiable pallets defined with the `#[pallet]` macro. #[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance3; -/// `Instance4` to be used for instantiable palllets defined with the `#[pallet]` macro. +/// `Instance4` to be used for instantiable pallets defined with the `#[pallet]` macro. #[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance4; -/// `Instance5` to be used for instantiable palllets defined with the `#[pallet]` macro. +/// `Instance5` to be used for instantiable pallets defined with the `#[pallet]` macro. #[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance5; -/// `Instance6` to be used for instantiable palllets defined with the `#[pallet]` macro. +/// `Instance6` to be used for instantiable pallets defined with the `#[pallet]` macro. #[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance6; -/// `Instance7` to be used for instantiable palllets defined with the `#[pallet]` macro. +/// `Instance7` to be used for instantiable pallets defined with the `#[pallet]` macro. #[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance7; -/// `Instance8` to be used for instantiable palllets defined with the `#[pallet]` macro. +/// `Instance8` to be used for instantiable pallets defined with the `#[pallet]` macro. #[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance8; -/// `Instance9` to be used for instantiable palllets defined with the `#[pallet]` macro. +/// `Instance9` to be used for instantiable pallets defined with the `#[pallet]` macro. #[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance9; -/// `Instance10` to be used for instantiable palllets defined with the `#[pallet]` macro. +/// `Instance10` to be used for instantiable pallets defined with the `#[pallet]` macro. #[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance10; -/// `Instance11` to be used for instantiable palllets defined with the `#[pallet]` macro. +/// `Instance11` to be used for instantiable pallets defined with the `#[pallet]` macro. #[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance11; -/// `Instance12` to be used for instantiable palllets defined with the `#[pallet]` macro. +/// `Instance12` to be used for instantiable pallets defined with the `#[pallet]` macro. #[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance12; -/// `Instance13` to be used for instantiable palllets defined with the `#[pallet]` macro. +/// `Instance13` to be used for instantiable pallets defined with the `#[pallet]` macro. #[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance13; -/// `Instance14` to be used for instantiable palllets defined with the `#[pallet]` macro. +/// `Instance14` to be used for instantiable pallets defined with the `#[pallet]` macro. #[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance14; -/// `Instance15` to be used for instantiable palllets defined with the `#[pallet]` macro. +/// `Instance15` to be used for instantiable pallets defined with the `#[pallet]` macro. #[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance15; -/// `Instance16` to be used for instantiable palllets defined with the `#[pallet]` macro. +/// `Instance16` to be used for instantiable pallets defined with the `#[pallet]` macro. #[doc(hidden)] #[derive(Clone, Copy, PartialEq, Eq, crate::RuntimeDebugNoBound)] pub struct Instance16; diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index c524f8953a4..895215d364e 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -145,7 +145,7 @@ impl TypeId for PalletId { /// # Examples /// /// There are different ways to declare the `prefix` to use. The `prefix` type can either be -/// declared explicetly by passing it to the macro as an attribute or by letting the macro +/// declared explicitly by passing it to the macro as an attribute or by letting the macro /// guess on what the `prefix` type is. The `prefix` is always passed as the first generic /// argument to the type declaration. When using [`#[pallet::storage]`](pallet_macros::storage) /// this first generic argument is always `_`. Besides declaring the `prefix`, the rest of the @@ -1110,7 +1110,7 @@ pub mod pallet_macros { /// Declares a storage as unbounded in potential size. /// - /// When implementating the storage info (when `#[pallet::generate_storage_info]` is + /// When implementing the storage info (when `#[pallet::generate_storage_info]` is /// specified on the pallet struct placeholder), the size of the storage will be declared /// as unbounded. This can be useful for storage which can never go into PoV (Proof of /// Validity). @@ -2340,7 +2340,7 @@ pub mod pallet_macros { /// Allows defining conditions for a task to run. /// - /// This attribute is attached to a function inside an `impl` block annoated with + /// This attribute is attached to a function inside an `impl` block annotated with /// [`pallet::tasks_experimental`](`tasks_experimental`) to define the conditions for a /// given work item to be valid. /// @@ -2351,7 +2351,7 @@ pub mod pallet_macros { /// Allows defining an index for a task. /// - /// This attribute is attached to a function inside an `impl` block annoated with + /// This attribute is attached to a function inside an `impl` block annotated with /// [`pallet::tasks_experimental`](`tasks_experimental`) to define the index of a given /// work item. /// @@ -2361,7 +2361,7 @@ pub mod pallet_macros { /// Allows defining an iterator over available work items for a task. /// - /// This attribute is attached to a function inside an `impl` block annoated with + /// This attribute is attached to a function inside an `impl` block annotated with /// [`pallet::tasks_experimental`](`tasks_experimental`). /// /// It takes an iterator as input that yields a tuple with same types as the function @@ -2370,7 +2370,7 @@ pub mod pallet_macros { /// Allows defining the weight of a task. /// - /// This attribute is attached to a function inside an `impl` block annoated with + /// This attribute is attached to a function inside an `impl` block annotated with /// [`pallet::tasks_experimental`](`tasks_experimental`) define the weight of a given work /// item. /// diff --git a/substrate/frame/support/src/storage/migration.rs b/substrate/frame/support/src/storage/migration.rs index 568c475bdc6..252625cf4f7 100644 --- a/substrate/frame/support/src/storage/migration.rs +++ b/substrate/frame/support/src/storage/migration.rs @@ -303,11 +303,11 @@ pub fn take_storage_item /// Move a storage from a pallet prefix to another pallet prefix. /// /// Keys used in pallet storages always start with: -/// `concat(twox_128(pallet_name), towx_128(storage_name))`. +/// `concat(twox_128(pallet_name), twox_128(storage_name))`. /// /// This function will remove all value for which the key start with -/// `concat(twox_128(old_pallet_name), towx_128(storage_name))` and insert them at the key with -/// the start replaced by `concat(twox_128(new_pallet_name), towx_128(storage_name))`. +/// `concat(twox_128(old_pallet_name), twox_128(storage_name))` and insert them at the key with +/// the start replaced by `concat(twox_128(new_pallet_name), twox_128(storage_name))`. /// /// # Example /// @@ -339,7 +339,7 @@ pub fn move_storage_from_pallet( /// Move all storages from a pallet prefix to another pallet prefix. /// /// Keys used in pallet storages always start with: -/// `concat(twox_128(pallet_name), towx_128(storage_name))`. +/// `concat(twox_128(pallet_name), twox_128(storage_name))`. /// /// This function will remove all value for which the key start with `twox_128(old_pallet_name)` /// and insert them at the key with the start replaced by `twox_128(new_pallet_name)`. diff --git a/substrate/frame/support/src/storage/mod.rs b/substrate/frame/support/src/storage/mod.rs index 8ebe7b31da8..f7d7447482d 100644 --- a/substrate/frame/support/src/storage/mod.rs +++ b/substrate/frame/support/src/storage/mod.rs @@ -159,7 +159,7 @@ pub trait StorageValue { /// /// # Warning /// - /// `None` does not mean that `get()` does not return a value. The default value is completly + /// `None` does not mean that `get()` does not return a value. The default value is completely /// ignored by this function. fn decode_len() -> Option where @@ -363,7 +363,7 @@ pub trait StorageMap { /// /// # Warning /// - /// `None` does not mean that `get()` does not return a value. The default value is completly + /// `None` does not mean that `get()` does not return a value. The default value is completely /// ignored by this function. fn decode_len>(key: KeyArg) -> Option where @@ -381,7 +381,8 @@ pub trait StorageMap { /// /// # Warning /// - /// - `None` does not mean that `get()` does not return a value. The default value is completly + /// - `None` does not mean that `get()` does not return a value. The default value is + /// completely /// ignored by this function. /// /// - The value returned is the non-deduplicated length of the underlying Vector in storage.This @@ -410,7 +411,7 @@ pub trait StorageMap { pub trait IterableStorageMap: StorageMap { /// The type that iterates over all `(key, value)`. type Iterator: Iterator; - /// The type that itereates over all `key`s. + /// The type that iterates over all `key`s. type KeyIterator: Iterator; /// Enumerate all elements in the map in lexicographical order of the encoded key. If you @@ -777,7 +778,7 @@ pub trait StorageDoubleMap { /// /// # Warning /// - /// `None` does not mean that `get()` does not return a value. The default value is completly + /// `None` does not mean that `get()` does not return a value. The default value is completely /// ignored by this function. fn decode_len(key1: KArg1, key2: KArg2) -> Option where @@ -798,7 +799,7 @@ pub trait StorageDoubleMap { /// /// # Warning /// - /// `None` does not mean that `get()` does not return a value. The default value is completly + /// `None` does not mean that `get()` does not return a value. The default value is completely /// ignored by this function. fn decode_non_dedup_len(key1: KArg1, key2: KArg2) -> Option where @@ -980,7 +981,7 @@ pub trait StorageNMap { /// /// # Warning /// - /// `None` does not mean that `get()` does not return a value. The default value is completly + /// `None` does not mean that `get()` does not return a value. The default value is completely /// ignored by this function. fn decode_len + TupleToEncodedIter>(key: KArg) -> Option where @@ -1488,8 +1489,8 @@ pub trait StorageDecodeLength: private::Sealed + codec::DecodeLength { } } -/// It is expected that the length is at the beginning of the encoded objectand that the length is a -/// `Compact`. +/// It is expected that the length is at the beginning of the encoded object and that the length is +/// a `Compact`. /// /// # Note /// The length returned by this trait is not deduplicated, i.e. it is the length of the underlying @@ -1790,7 +1791,7 @@ mod test { }); } - // This test ensures that the Digest encoding does not change without being noticied. + // This test ensures that the Digest encoding does not change without being noticed. #[test] fn digest_storage_append_works_as_expected() { TestExternalities::default().execute_with(|| { diff --git a/substrate/frame/support/src/storage/stream_iter.rs b/substrate/frame/support/src/storage/stream_iter.rs index 2205601938b..529b2f387c7 100644 --- a/substrate/frame/support/src/storage/stream_iter.rs +++ b/substrate/frame/support/src/storage/stream_iter.rs @@ -217,7 +217,7 @@ const STORAGE_INPUT_BUFFER_CAPACITY: usize = 2 * 1024; /// Implementation of [`codec::Input`] using [`sp_io::storage::read`]. /// /// Keeps an internal buffer with a size of [`STORAGE_INPUT_BUFFER_CAPACITY`]. All read accesses -/// are tried to be served by this buffer. If the buffer doesn't hold enough bytes to fullfill the +/// are tried to be served by this buffer. If the buffer doesn't hold enough bytes to fulfill the /// current read access, the buffer is re-filled from the state. A read request that is bigger than /// the internal buffer is directly forwarded to the state to reduce the number of reads from the /// state. diff --git a/substrate/frame/support/src/storage/types/counted_map.rs b/substrate/frame/support/src/storage/types/counted_map.rs index 04e69751c16..0444e269928 100644 --- a/substrate/frame/support/src/storage/types/counted_map.rs +++ b/substrate/frame/support/src/storage/types/counted_map.rs @@ -310,7 +310,7 @@ where /// /// # Warning /// - /// `None` does not mean that `get()` does not return a value. The default value is completly + /// `None` does not mean that `get()` does not return a value. The default value is completely /// ignored by this function. pub fn decode_len>(key: KeyArg) -> Option where @@ -775,13 +775,13 @@ mod test { assert_eq!(A::try_get(1), Err(())); assert_eq!(A::count(), 3); - // Take exsisting. + // Take existing. assert_eq!(A::take(4), 10); assert_eq!(A::try_get(4), Err(())); assert_eq!(A::count(), 2); - // Take non-exsisting. + // Take non-existing. assert_eq!(A::take(4), ADefault::get()); assert_eq!(A::try_get(4), Err(())); @@ -1022,13 +1022,13 @@ mod test { assert_eq!(B::try_get(1), Err(())); assert_eq!(B::count(), 3); - // Take exsisting. + // Take existing. assert_eq!(B::take(4), Some(10)); assert_eq!(B::try_get(4), Err(())); assert_eq!(B::count(), 2); - // Take non-exsisting. + // Take non-existing. assert_eq!(B::take(4), None); assert_eq!(B::try_get(4), Err(())); diff --git a/substrate/frame/support/src/storage/types/counted_nmap.rs b/substrate/frame/support/src/storage/types/counted_nmap.rs index 279894ee973..51cde93f28c 100644 --- a/substrate/frame/support/src/storage/types/counted_nmap.rs +++ b/substrate/frame/support/src/storage/types/counted_nmap.rs @@ -378,7 +378,7 @@ where /// /// # Warning /// - /// `None` does not mean that `get()` does not return a value. The default value is completly + /// `None` does not mean that `get()` does not return a value. The default value is completely /// ignored by this function. pub fn decode_len + TupleToEncodedIter>( key: KArg, diff --git a/substrate/frame/support/src/storage/types/double_map.rs b/substrate/frame/support/src/storage/types/double_map.rs index cb9479d491c..2a7af7a9846 100644 --- a/substrate/frame/support/src/storage/types/double_map.rs +++ b/substrate/frame/support/src/storage/types/double_map.rs @@ -445,7 +445,7 @@ where /// /// # Warning /// - /// `None` does not mean that `get()` does not return a value. The default value is completly + /// `None` does not mean that `get()` does not return a value. The default value is completely /// ignored by this function. pub fn decode_len(key1: KArg1, key2: KArg2) -> Option where @@ -465,7 +465,8 @@ where /// /// # Warning /// - /// - `None` does not mean that `get()` does not return a value. The default value is completly + /// - `None` does not mean that `get()` does not return a value. The default value is + /// completely /// ignored by this function. /// /// - The value returned is the non-deduplicated length of the underlying Vector in storage.This diff --git a/substrate/frame/support/src/storage/types/map.rs b/substrate/frame/support/src/storage/types/map.rs index ee5db74583b..b79a6ae9b84 100644 --- a/substrate/frame/support/src/storage/types/map.rs +++ b/substrate/frame/support/src/storage/types/map.rs @@ -277,7 +277,7 @@ where /// /// # Warning /// - /// `None` does not mean that `get()` does not return a value. The default value is completly + /// `None` does not mean that `get()` does not return a value. The default value is completely /// ignored by this function. pub fn decode_len>(key: KeyArg) -> Option where @@ -295,7 +295,8 @@ where /// /// # Warning /// - /// - `None` does not mean that `get()` does not return a value. The default value is completly + /// - `None` does not mean that `get()` does not return a value. The default value is + /// completely /// ignored by this function. /// /// - The value returned is the non-deduplicated length of the underlying Vector in storage.This diff --git a/substrate/frame/support/src/storage/types/mod.rs b/substrate/frame/support/src/storage/types/mod.rs index 9dd6f4066e4..631410f425d 100644 --- a/substrate/frame/support/src/storage/types/mod.rs +++ b/substrate/frame/support/src/storage/types/mod.rs @@ -195,7 +195,7 @@ mod test { // result query returns error assert_eq!(C::get(), Err(())); - // value query with custom onempty returns 42 + // value query with custom on empty returns 42 assert_eq!(D::get(), 42); }); } diff --git a/substrate/frame/support/src/storage/types/nmap.rs b/substrate/frame/support/src/storage/types/nmap.rs index 0723db68900..253f02a14f0 100755 --- a/substrate/frame/support/src/storage/types/nmap.rs +++ b/substrate/frame/support/src/storage/types/nmap.rs @@ -348,7 +348,7 @@ where /// /// # Warning /// - /// `None` does not mean that `get()` does not return a value. The default value is completly + /// `None` does not mean that `get()` does not return a value. The default value is completely /// ignored by this function. pub fn decode_len + TupleToEncodedIter>( key: KArg, diff --git a/substrate/frame/support/src/storage/types/value.rs b/substrate/frame/support/src/storage/types/value.rs index 263091dd252..a2d93a6a165 100644 --- a/substrate/frame/support/src/storage/types/value.rs +++ b/substrate/frame/support/src/storage/types/value.rs @@ -225,7 +225,7 @@ where /// /// # Warning /// - /// `None` does not mean that `get()` does not return a value. The default value is completly + /// `None` does not mean that `get()` does not return a value. The default value is completely /// ignored by this function. pub fn decode_len() -> Option where @@ -243,7 +243,8 @@ where /// /// # Warning /// - /// - `None` does not mean that `get()` does not return a value. The default value is completly + /// - `None` does not mean that `get()` does not return a value. The default value is + /// completely /// ignored by this function. /// /// - The value returned is the non-deduplicated length of the underlying Vector in storage.This diff --git a/substrate/frame/support/src/traits/dispatch.rs b/substrate/frame/support/src/traits/dispatch.rs index de50ce7a26c..7dc8d3e4f5a 100644 --- a/substrate/frame/support/src/traits/dispatch.rs +++ b/substrate/frame/support/src/traits/dispatch.rs @@ -540,7 +540,7 @@ pub trait OriginTrait: Sized { }) } - /// Extract a reference to the sytsem origin, if that's what the caller is. + /// Extract a reference to the system origin, if that's what the caller is. fn as_system_ref(&self) -> Option<&RawOrigin> { self.caller().as_system_ref() } diff --git a/substrate/frame/support/src/traits/dynamic_params.rs b/substrate/frame/support/src/traits/dynamic_params.rs index 8881df04141..32dae6799ea 100644 --- a/substrate/frame/support/src/traits/dynamic_params.rs +++ b/substrate/frame/support/src/traits/dynamic_params.rs @@ -25,30 +25,30 @@ use frame_support::Parameter; /// A dynamic parameter store across an aggregated KV type. pub trait RuntimeParameterStore { - type AggregratedKeyValue: AggregratedKeyValue; + type AggregatedKeyValue: AggregatedKeyValue; /// Get the value of a parametrized key. /// /// Should return `None` if no explicit value was set instead of a default. fn get(key: K) -> Option where - KV: AggregratedKeyValue, - K: Key + Into<::Key>, - ::Key: IntoKey< - <::AggregratedKeyValue as AggregratedKeyValue>::Key, + KV: AggregatedKeyValue, + K: Key + Into<::Key>, + ::Key: IntoKey< + <::AggregatedKeyValue as AggregatedKeyValue>::Key, >, - <::AggregratedKeyValue as AggregratedKeyValue>::Value: - TryIntoKey<::Value>, - ::Value: TryInto; + <::AggregatedKeyValue as AggregatedKeyValue>::Value: + TryIntoKey<::Value>, + ::Value: TryInto; } /// A dynamic parameter store across a concrete KV type. -pub trait ParameterStore { +pub trait ParameterStore { /// Get the value of a parametrized key. fn get(key: K) -> Option where - K: Key + Into<::Key>, - ::Value: TryInto; + K: Key + Into<::Key>, + ::Value: TryInto; } /// Key of a dynamic parameter. @@ -61,7 +61,7 @@ pub trait Key { } /// The aggregated key-value type of a dynamic parameter store. -pub trait AggregratedKeyValue: Parameter { +pub trait AggregatedKeyValue: Parameter { /// The aggregated key type. type Key: Parameter + MaxEncodedLen; @@ -72,7 +72,7 @@ pub trait AggregratedKeyValue: Parameter { fn into_parts(self) -> (Self::Key, Option); } -impl AggregratedKeyValue for () { +impl AggregatedKeyValue for () { type Key = (); type Value = (); @@ -90,17 +90,17 @@ pub struct ParameterStoreAdapter(sp_std::marker::PhantomData<(PS, KV)>); impl ParameterStore for ParameterStoreAdapter where PS: RuntimeParameterStore, - KV: AggregratedKeyValue, - ::Key: - IntoKey<<::AggregratedKeyValue as AggregratedKeyValue>::Key>, - ::Value: TryFromKey< - <::AggregratedKeyValue as AggregratedKeyValue>::Value, + KV: AggregatedKeyValue, + ::Key: + IntoKey<<::AggregatedKeyValue as AggregatedKeyValue>::Key>, + ::Value: TryFromKey< + <::AggregatedKeyValue as AggregatedKeyValue>::Value, >, { fn get(key: K) -> Option where - K: Key + Into<::Key>, - ::Value: TryInto, + K: Key + Into<::Key>, + ::Value: TryInto, { PS::get::(key) } diff --git a/substrate/frame/support/src/traits/hooks.rs b/substrate/frame/support/src/traits/hooks.rs index 7d0e5aa1e89..d83e2704745 100644 --- a/substrate/frame/support/src/traits/hooks.rs +++ b/substrate/frame/support/src/traits/hooks.rs @@ -167,7 +167,7 @@ pub trait OnGenesis { /// /// This hook is intended to be used internally in FRAME and not be exposed to FRAME developers. /// -/// It is defined as a seperate trait from [`OnRuntimeUpgrade`] precisely to not pollute the public +/// It is defined as a separate trait from [`OnRuntimeUpgrade`] precisely to not pollute the public /// API. pub trait BeforeAllRuntimeMigrations { /// Something that should happen before runtime migrations are executed. diff --git a/substrate/frame/support/src/traits/misc.rs b/substrate/frame/support/src/traits/misc.rs index 1f634a64282..bc7407a7be6 100644 --- a/substrate/frame/support/src/traits/misc.rs +++ b/substrate/frame/support/src/traits/misc.rs @@ -1424,7 +1424,7 @@ mod test { assert_eq!(>::max_encoded_len(), 2usize.pow(14) + 4); let data = 4u64; - // Ensure that we check that the `Vec` is consumed completly on decode. + // Ensure that we check that the `Vec` is consumed completely on decode. assert!(WrapperOpaque::::decode(&mut &data.encode().encode()[..]).is_err()); } diff --git a/substrate/frame/support/src/traits/tokens/fungible/conformance_tests/regular/unbalanced.rs b/substrate/frame/support/src/traits/tokens/fungible/conformance_tests/regular/unbalanced.rs index e7fcc15472e..a5220736898 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/conformance_tests/regular/unbalanced.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/conformance_tests/regular/unbalanced.rs @@ -94,7 +94,7 @@ where ); assert_eq!(T::balance(&account_0), account_0_initial_balance - amount); - // Decreasing the balance below funds avalibale should fail when Precision::Exact + // Decreasing the balance below funds available should fail when Precision::Exact let balance_before = T::balance(&account_0); assert_eq!( T::decrease_balance( diff --git a/substrate/frame/support/src/traits/tokens/imbalance/split_two_ways.rs b/substrate/frame/support/src/traits/tokens/imbalance/split_two_ways.rs index c1afac35fc9..59a582389ba 100644 --- a/substrate/frame/support/src/traits/tokens/imbalance/split_two_ways.rs +++ b/substrate/frame/support/src/traits/tokens/imbalance/split_two_ways.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Means for splitting an imbalance into two and hanlding them differently. +//! Means for splitting an imbalance into two and handling them differently. use super::super::imbalance::{Imbalance, OnUnbalanced}; use sp_runtime::traits::Saturating; diff --git a/substrate/frame/support/src/traits/tokens/misc.rs b/substrate/frame/support/src/traits/tokens/misc.rs index fd497bc4eda..a4dd5e49142 100644 --- a/substrate/frame/support/src/traits/tokens/misc.rs +++ b/substrate/frame/support/src/traits/tokens/misc.rs @@ -130,7 +130,7 @@ impl WithdrawConsequence { pub enum DepositConsequence { /// Deposit couldn't happen due to the amount being too low. This is usually because the /// account doesn't yet exist and the deposit wouldn't bring it to at least the minimum needed - /// for existance. + /// for existence. BelowMinimum, /// Deposit cannot happen since the account cannot be created (usually because it's a consumer /// and there exists no provider reference). diff --git a/substrate/frame/support/test/tests/derive_impl_ui/attached_to_non_impl.rs b/substrate/frame/support/test/tests/derive_impl_ui/attached_to_non_impl.rs index 332e1e78730..3f3148a03a9 100644 --- a/substrate/frame/support/test/tests/derive_impl_ui/attached_to_non_impl.rs +++ b/substrate/frame/support/test/tests/derive_impl_ui/attached_to_non_impl.rs @@ -50,7 +50,7 @@ impl Animal for FourLeggedAnimal { } } -pub struct AcquaticMammal {} +pub struct AquaticMammal {} #[derive_impl(FourLeggedAnimal as Animal)] struct Something {} diff --git a/substrate/frame/support/test/tests/derive_impl_ui/bad_default_impl_path.rs b/substrate/frame/support/test/tests/derive_impl_ui/bad_default_impl_path.rs index bc118acdf1e..7093c32400b 100644 --- a/substrate/frame/support/test/tests/derive_impl_ui/bad_default_impl_path.rs +++ b/substrate/frame/support/test/tests/derive_impl_ui/bad_default_impl_path.rs @@ -50,14 +50,14 @@ impl Animal for FourLeggedAnimal { } } -pub struct AcquaticMammal {} +pub struct AquaticMammal {} // Should throw: `error: cannot find macro `__export_tokens_tt_tiger` in this scope` // // Note that there is really no better way to clean up this error, tt_call suffers from the // same downside but this is really the only rough edge when using macro magic. #[derive_impl(Tiger as Animal)] -impl Animal for AcquaticMammal { +impl Animal for AquaticMammal { type Locomotion = (Swims, RunsOnFourLegs); type Environment = (Land, Sea); } diff --git a/substrate/frame/support/test/tests/derive_impl_ui/bad_disambiguation_path.rs b/substrate/frame/support/test/tests/derive_impl_ui/bad_disambiguation_path.rs index 9535ac3deda..8e0253e45c1 100644 --- a/substrate/frame/support/test/tests/derive_impl_ui/bad_disambiguation_path.rs +++ b/substrate/frame/support/test/tests/derive_impl_ui/bad_disambiguation_path.rs @@ -50,10 +50,10 @@ impl Animal for FourLeggedAnimal { } } -pub struct AcquaticMammal {} +pub struct AquaticMammal {} #[derive_impl(FourLeggedAnimal as Insect)] -impl Animal for AcquaticMammal { +impl Animal for AquaticMammal { type Locomotion = (Swims, RunsOnFourLegs); type Environment = (Land, Sea); } diff --git a/substrate/frame/support/test/tests/derive_impl_ui/missing_disambiguation_path.rs b/substrate/frame/support/test/tests/derive_impl_ui/missing_disambiguation_path.rs index f26c28313e5..4914ceea0b6 100644 --- a/substrate/frame/support/test/tests/derive_impl_ui/missing_disambiguation_path.rs +++ b/substrate/frame/support/test/tests/derive_impl_ui/missing_disambiguation_path.rs @@ -50,10 +50,10 @@ impl Animal for FourLeggedAnimal { } } -pub struct AcquaticMammal {} +pub struct AquaticMammal {} #[derive_impl(FourLeggedAnimal as)] -impl Animal for AcquaticMammal { +impl Animal for AquaticMammal { type Locomotion = (Swims, RunsOnFourLegs); type Environment = (Land, Sea); } diff --git a/substrate/frame/support/test/tests/derive_impl_ui/pass/basic_overriding.rs b/substrate/frame/support/test/tests/derive_impl_ui/pass/basic_overriding.rs index 37c0742f195..20744b8cba2 100644 --- a/substrate/frame/support/test/tests/derive_impl_ui/pass/basic_overriding.rs +++ b/substrate/frame/support/test/tests/derive_impl_ui/pass/basic_overriding.rs @@ -51,19 +51,19 @@ impl Animal for FourLeggedAnimal { } } -pub struct AcquaticMammal {} +pub struct AquaticMammal {} // without omitting the `as X` #[derive_impl(FourLeggedAnimal as Animal)] -impl Animal for AcquaticMammal { +impl Animal for AquaticMammal { type Locomotion = (Swims, RunsOnFourLegs); type Environment = (Land, Sea); } -assert_type_eq_all!(::Locomotion, (Swims, RunsOnFourLegs)); -assert_type_eq_all!(::Environment, (Land, Sea)); -assert_type_eq_all!(::Diet, Omnivore); -assert_type_eq_all!(::SleepingStrategy, Diurnal); +assert_type_eq_all!(::Locomotion, (Swims, RunsOnFourLegs)); +assert_type_eq_all!(::Environment, (Land, Sea)); +assert_type_eq_all!(::Diet, Omnivore); +assert_type_eq_all!(::SleepingStrategy, Diurnal); pub struct Lion {} diff --git a/substrate/frame/support/test/tests/pallet_outer_enums_explicit.rs b/substrate/frame/support/test/tests/pallet_outer_enums_explicit.rs index 8e8079b183c..6c71b544426 100644 --- a/substrate/frame/support/test/tests/pallet_outer_enums_explicit.rs +++ b/substrate/frame/support/test/tests/pallet_outer_enums_explicit.rs @@ -82,7 +82,7 @@ fn module_error_outer_enum_expand_explicit() { // Check that all error types are propagated match RuntimeError::Example(pallet::Error::InsufficientProposersBalance) { - // Error passed implicitely to the pallet system. + // Error passed implicitly to the pallet system. RuntimeError::System(system) => match system { frame_system::Error::InvalidSpecName => (), frame_system::Error::SpecVersionNeedsToIncrease => (), diff --git a/substrate/frame/support/test/tests/pallet_outer_enums_implicit.rs b/substrate/frame/support/test/tests/pallet_outer_enums_implicit.rs index 08b0b919e21..79828119742 100644 --- a/substrate/frame/support/test/tests/pallet_outer_enums_implicit.rs +++ b/substrate/frame/support/test/tests/pallet_outer_enums_implicit.rs @@ -62,11 +62,11 @@ frame_support::construct_runtime!( // Exclude part `Storage` in order not to check its metadata in tests. System: frame_system exclude_parts { Storage }, - // Pallet exposes `Error` implicitely. + // Pallet exposes `Error` implicitly. Example: common::outer_enums::pallet, Instance1Example: common::outer_enums::pallet::, - // Pallet exposes `Error` implicitely. + // Pallet exposes `Error` implicitly. Example2: common::outer_enums::pallet2, Instance1Example2: common::outer_enums::pallet2::, @@ -82,7 +82,7 @@ fn module_error_outer_enum_expand_implicit() { // Check that all error types are propagated match RuntimeError::Example(pallet::Error::InsufficientProposersBalance) { - // Error passed implicitely to the pallet system. + // Error passed implicitly to the pallet system. RuntimeError::System(system) => match system { frame_system::Error::InvalidSpecName => (), frame_system::Error::SpecVersionNeedsToIncrease => (), diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/inherited_call_weight3.rs b/substrate/frame/support/test/tests/pallet_ui/pass/inherited_call_weight3.rs index f40d1040858..ddccd0b3e19 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pass/inherited_call_weight3.rs +++ b/substrate/frame/support/test/tests/pallet_ui/pass/inherited_call_weight3.rs @@ -18,7 +18,7 @@ use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; -// If, for whatever reason, you dont to not use a `WeightInfo` trait - it will still work. +// If, for whatever reason, you don't to not use a `WeightInfo` trait - it will still work. struct Impl; impl Impl { diff --git a/substrate/frame/system/src/limits.rs b/substrate/frame/system/src/limits.rs index 5fd7a5af875..ab5a98a6b97 100644 --- a/substrate/frame/system/src/limits.rs +++ b/substrate/frame/system/src/limits.rs @@ -378,7 +378,7 @@ impl BlockWeightsBuilder { /// class, based on the allowance. /// /// This is to make sure that extrinsics don't stay forever in the pool, - /// because they could seamingly fit the block (since they are below `max_block`), + /// because they could seemingly fit the block (since they are below `max_block`), /// but the cost of calling `on_initialize` always prevents them from being included. pub fn avg_block_initialization(mut self, init_cost: Perbill) -> Self { self.init_cost = Some(init_cost); diff --git a/substrate/frame/system/src/offchain.rs b/substrate/frame/system/src/offchain.rs index a019cfd666e..a64b3261964 100644 --- a/substrate/frame/system/src/offchain.rs +++ b/substrate/frame/system/src/offchain.rs @@ -22,7 +22,7 @@ //! This module provides transaction related helpers to: //! - Submit a raw unsigned transaction //! - Submit an unsigned transaction with a signed payload -//! - Submit a signed transction. +//! - Submit a signed transaction. //! //! ## Usage //! @@ -384,7 +384,7 @@ where /// /// // runtime-specific public key /// type Public = MultiSigner: From; -/// type Signature = MulitSignature: From; +/// type Signature = MultiSignature: From; /// ``` // TODO [#5662] Potentially use `IsWrappedBy` types, or find some other way to make it easy to // obtain unwrapped crypto (and wrap it back). @@ -444,7 +444,7 @@ pub trait SigningTypes: crate::Config { /// A public key that is capable of identifying `AccountId`s. /// /// Usually that's either a raw crypto public key (e.g. `sr25519::Public`) or - /// an aggregate type for multiple crypto public keys, like `MulitSigner`. + /// an aggregate type for multiple crypto public keys, like `MultiSigner`. type Public: Clone + PartialEq + IdentifyAccount diff --git a/substrate/frame/tips/src/migrations/mod.rs b/substrate/frame/tips/src/migrations/mod.rs index 9cdd01c17fb..a7917bfce16 100644 --- a/substrate/frame/tips/src/migrations/mod.rs +++ b/substrate/frame/tips/src/migrations/mod.rs @@ -17,7 +17,7 @@ /// Version 4. /// -/// For backward compatability reasons, pallet-tips uses `Treasury` for storage module prefix +/// For backward compatibility reasons, pallet-tips uses `Treasury` for storage module prefix /// before calling this migration. After calling this migration, it will get replaced with /// own storage identifier. pub mod v4; diff --git a/substrate/frame/transaction-payment/src/tests.rs b/substrate/frame/transaction-payment/src/tests.rs index d3a1721ccb9..bc0efd2d64a 100644 --- a/substrate/frame/transaction-payment/src/tests.rs +++ b/substrate/frame/transaction-payment/src/tests.rs @@ -384,7 +384,7 @@ fn query_call_info_and_fee_details_works() { adjusted_weight_fee: info .weight .min(BlockWeights::get().max_block) - .ref_time() as u64 * 2 * 3 / 2 /* weight * weight_fee * multipler */ + .ref_time() as u64 * 2 * 3 / 2 /* weight * weight_fee * multiplier */ }), tip: 0, }, diff --git a/substrate/frame/transaction-storage/README.md b/substrate/frame/transaction-storage/README.md index 1066968469d..b173c0a84d5 100644 --- a/substrate/frame/transaction-storage/README.md +++ b/substrate/frame/transaction-storage/README.md @@ -79,7 +79,7 @@ ipfs block get /ipfs/ > kitten.jpeg ``` To renew data and prevent it from being disposed after the storage period, use `transactionStorage.renew(block, index)` -where `block` is the block number of the previous store or renew transction, and index is the index of that transaction +where `block` is the block number of the previous store or renew transaction, and index is the index of that transaction in the block. diff --git a/substrate/frame/transaction-storage/src/lib.rs b/substrate/frame/transaction-storage/src/lib.rs index d32cfe169ce..398cb350c50 100644 --- a/substrate/frame/transaction-storage/src/lib.rs +++ b/substrate/frame/transaction-storage/src/lib.rs @@ -137,7 +137,7 @@ pub mod pallet { InvalidProof, /// Missing storage proof. MissingProof, - /// Unable to verify proof becasue state data is missing. + /// Unable to verify proof because state data is missing. MissingStateData, /// Double proof check in the block. DoubleCheck, diff --git a/substrate/frame/transaction-storage/src/tests.rs b/substrate/frame/transaction-storage/src/tests.rs index e17b3ca3beb..621f74804ec 100644 --- a/substrate/frame/transaction-storage/src/tests.rs +++ b/substrate/frame/transaction-storage/src/tests.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Tests for transction-storage pallet. +//! Tests for transaction-storage pallet. use super::{Pallet as TransactionStorage, *}; use crate::mock::*; @@ -53,8 +53,8 @@ fn discards_data() { }; run_to_block(11, proof_provider); assert!(Transactions::::get(1).is_some()); - let transctions = Transactions::::get(1).unwrap(); - assert_eq!(transctions.len(), 2); + let transactions = Transactions::::get(1).unwrap(); + assert_eq!(transactions.len(), 2); assert_eq!(ChunkCount::::get(1), 16); run_to_block(12, proof_provider); assert!(Transactions::::get(1).is_none()); diff --git a/substrate/frame/treasury/src/lib.rs b/substrate/frame/treasury/src/lib.rs index 5e429d3914b..d569ae406ea 100644 --- a/substrate/frame/treasury/src/lib.rs +++ b/substrate/frame/treasury/src/lib.rs @@ -621,7 +621,7 @@ pub mod pallet { with_context::>, _>(|v| { let context = v.or_default(); - // We group based on `max_amount`, to dinstinguish between different kind of + // We group based on `max_amount`, to distinguish between different kind of // origins. (assumes that all origins have different `max_amount`) // // Worst case is that we reject some "valid" request. @@ -1042,7 +1042,7 @@ impl, I: 'static> Pallet { /// ### Invariants of proposal storage items /// /// 1. [`ProposalCount`] >= Number of elements in [`Proposals`]. - /// 2. Each entry in [`Proposals`] should be saved under a key stricly less than current + /// 2. Each entry in [`Proposals`] should be saved under a key strictly less than current /// [`ProposalCount`]. /// 3. Each [`ProposalIndex`] contained in [`Approvals`] should exist in [`Proposals`]. /// Note, that this automatically implies [`Approvals`].count() <= [`Proposals`].count(). @@ -1078,7 +1078,7 @@ impl, I: 'static> Pallet { /// ## Invariants of spend storage items /// /// 1. [`SpendCount`] >= Number of elements in [`Spends`]. - /// 2. Each entry in [`Spends`] should be saved under a key stricly less than current + /// 2. Each entry in [`Spends`] should be saved under a key strictly less than current /// [`SpendCount`]. /// 3. For each spend entry contained in [`Spends`] we should have spend.expire_at /// > spend.valid_from. diff --git a/substrate/frame/uniques/src/tests.rs b/substrate/frame/uniques/src/tests.rs index 351dac09f7f..afd0352bf90 100644 --- a/substrate/frame/uniques/src/tests.rs +++ b/substrate/frame/uniques/src/tests.rs @@ -289,7 +289,7 @@ fn transfer_owner_should_work() { assert_eq!(Balances::reserved_balance(&2), 0); assert_eq!(Balances::reserved_balance(&3), 45); - // 2's acceptence from before is reset when it became owner, so it cannot be transfered + // 2's acceptance from before is reset when it became owner, so it cannot be transferred // without a fresh acceptance. assert_noop!( Uniques::transfer_ownership(RuntimeOrigin::signed(3), 0, 2), @@ -692,7 +692,7 @@ fn approved_account_gets_reset_after_transfer() { assert_ok!(Uniques::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3)); assert_ok!(Uniques::transfer(RuntimeOrigin::signed(2), 0, 42, 5)); - // this shouldn't work because we have just transfered the item to another account. + // this shouldn't work because we have just transferred the item to another account. assert_noop!( Uniques::transfer(RuntimeOrigin::signed(3), 0, 42, 4), Error::::NoPermission diff --git a/substrate/frame/utility/README.md b/substrate/frame/utility/README.md index 00fff76cd62..0a6769ae1c7 100644 --- a/substrate/frame/utility/README.md +++ b/substrate/frame/utility/README.md @@ -17,7 +17,7 @@ This module contains two basic pieces of functionality: need multiple distinct accounts (e.g. as controllers for many staking accounts), but where it's perfectly fine to have each of them controlled by the same underlying keypair. Derivative accounts are, for the purposes of proxy filtering considered exactly the same as - the oigin and are thus hampered with the origin's filters. + the origin and are thus hampered with the origin's filters. Since proxy filters are respected in all dispatches of this module, it should never need to be filtered by any proxy. diff --git a/substrate/frame/vesting/src/migrations.rs b/substrate/frame/vesting/src/migrations.rs index cac3c90b403..6fe82312b63 100644 --- a/substrate/frame/vesting/src/migrations.rs +++ b/substrate/frame/vesting/src/migrations.rs @@ -29,7 +29,7 @@ pub mod v1 { log::debug!( target: "runtime::vesting", - "migration: Vesting storage version v1 PRE migration checks succesful!" + "migration: Vesting storage version v1 PRE migration checks successful!" ); Ok(()) diff --git a/substrate/primitives/arithmetic/fuzzer/src/fixed_point.rs b/substrate/primitives/arithmetic/fuzzer/src/fixed_point.rs index e76dd1503e3..e2d31065635 100644 --- a/substrate/primitives/arithmetic/fuzzer/src/fixed_point.rs +++ b/substrate/primitives/arithmetic/fuzzer/src/fixed_point.rs @@ -66,7 +66,7 @@ fn main() { let c = FixedI64::saturating_from_integer(x.saturating_add(y)); assert_eq!(a.saturating_add(b), c); - // Check substraction. + // Check subtraction. let a = FixedI64::saturating_from_integer(x); let b = FixedI64::saturating_from_integer(y); let c = FixedI64::saturating_from_integer(x.saturating_sub(y)); diff --git a/substrate/primitives/arithmetic/src/fixed_point.rs b/substrate/primitives/arithmetic/src/fixed_point.rs index 736a900bde2..c4e9259c5fc 100644 --- a/substrate/primitives/arithmetic/src/fixed_point.rs +++ b/substrate/primitives/arithmetic/src/fixed_point.rs @@ -568,7 +568,7 @@ macro_rules! implement_fixed { let v = self.0 as u128; // Want x' = sqrt(x) where x = n/D and x' = n'/D (D is fixed) - // Our prefered way is: + // Our preferred way is: // sqrt(n/D) = sqrt(nD / D^2) = sqrt(nD)/sqrt(D^2) = sqrt(nD)/D // ergo n' = sqrt(nD) // but this requires nD to fit into our type. diff --git a/substrate/primitives/blockchain/src/backend.rs b/substrate/primitives/blockchain/src/backend.rs index 8208f9128e7..7a09865f858 100644 --- a/substrate/primitives/blockchain/src/backend.rs +++ b/substrate/primitives/blockchain/src/backend.rs @@ -187,7 +187,7 @@ pub trait Backend: /// a block with the given `base_hash`. /// /// The search space is always limited to blocks which are in the finalized - /// chain or descendents of it. + /// chain or descendants of it. /// /// Returns `Ok(None)` if `base_hash` is not found in search space. // TODO: document time complexity of this, see [#1444](https://github.com/paritytech/substrate/issues/1444) diff --git a/substrate/primitives/blockchain/src/error.rs b/substrate/primitives/blockchain/src/error.rs index 74a2ed3fba5..e8ac148d751 100644 --- a/substrate/primitives/blockchain/src/error.rs +++ b/substrate/primitives/blockchain/src/error.rs @@ -34,7 +34,7 @@ pub enum ApplyExtrinsicFailed { /// The transaction cannot be included into the current block. /// /// This doesn't necessary mean that the transaction itself is invalid, but it might be just - /// unappliable onto the current block. + /// unapplicable onto the current block. #[error("Extrinsic is not valid: {0:?}")] Validity(#[from] TransactionValidityError), diff --git a/substrate/primitives/blockchain/src/header_metadata.rs b/substrate/primitives/blockchain/src/header_metadata.rs index 08b3c9ab3df..ccd640c0567 100644 --- a/substrate/primitives/blockchain/src/header_metadata.rs +++ b/substrate/primitives/blockchain/src/header_metadata.rs @@ -178,7 +178,7 @@ pub struct TreeRoute { impl TreeRoute { /// Creates a new `TreeRoute`. /// - /// To preserve the structure safety invariats it is required that `pivot < route.len()`. + /// To preserve the structure safety invariants it is required that `pivot < route.len()`. pub fn new(route: Vec>, pivot: usize) -> Result { if pivot < route.len() { Ok(TreeRoute { route, pivot }) @@ -212,7 +212,7 @@ impl TreeRoute { ) } - /// Get a slice of enacted blocks (descendents of the common ancestor) + /// Get a slice of enacted blocks (descendants of the common ancestor) pub fn enacted(&self) -> &[HashAndNumber] { &self.route[self.pivot + 1..] } diff --git a/substrate/primitives/consensus/babe/src/lib.rs b/substrate/primitives/consensus/babe/src/lib.rs index 6eb75b270a0..ee07da6829f 100644 --- a/substrate/primitives/consensus/babe/src/lib.rs +++ b/substrate/primitives/consensus/babe/src/lib.rs @@ -266,7 +266,7 @@ impl Default for BabeEpochConfiguration { } /// Verifies the equivocation proof by making sure that: both headers have -/// different hashes, are targetting the same slot, and have valid signatures by +/// different hashes, are targeting the same slot, and have valid signatures by /// the same authority. pub fn check_equivocation_proof(proof: EquivocationProof) -> bool where @@ -298,7 +298,7 @@ where let first_pre_digest = find_pre_digest(&proof.first_header)?; let second_pre_digest = find_pre_digest(&proof.second_header)?; - // both headers must be targetting the same slot and it must + // both headers must be targeting the same slot and it must // be the same as the one in the proof. if proof.slot != first_pre_digest.slot() || first_pre_digest.slot() != second_pre_digest.slot() diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index b3f62ead736..70978ca559d 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -200,7 +200,7 @@ pub mod ecdsa_bls_crypto { fn verify(&self, signature: &::Signature, msg: &[u8]) -> bool { // We can not simply call // `EcdsaBlsPair::verify(signature.as_inner_ref(), msg, self.as_inner_ref())` - // because that invokes ECDSA default verification which perfoms Blake2b hash + // because that invokes ECDSA default verification which performs Blake2b hash // which we don't want. This is because ECDSA signatures are meant to be verified // on Ethereum network where Keccak hasher is significantly cheaper than Blake2b. // See Figure 3 of [OnSc21](https://www.scitepress.org/Papers/2021/106066/106066.pdf) diff --git a/substrate/primitives/consensus/beefy/src/mmr.rs b/substrate/primitives/consensus/beefy/src/mmr.rs index 74851ece7ac..0bc303d51c0 100644 --- a/substrate/primitives/consensus/beefy/src/mmr.rs +++ b/substrate/primitives/consensus/beefy/src/mmr.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! BEEFY + MMR utilties. +//! BEEFY + MMR utilities. //! //! While BEEFY can be used completely independently as an additional consensus gadget, //! it is designed around a main use case of bridging standalone networks together. @@ -77,7 +77,7 @@ pub struct MmrLeaf { /// /// Given that adding new struct elements in SCALE is backward compatible (i.e. old format can be /// still decoded, the new fields will simply be ignored). We expect the major version to be bumped -/// very rarely (hopefuly never). +/// very rarely (hopefully never). #[derive(Debug, Default, PartialEq, Eq, Clone, Encode, Decode, TypeInfo)] pub struct MmrLeafVersion(u8); impl MmrLeafVersion { diff --git a/substrate/primitives/consensus/beefy/src/payload.rs b/substrate/primitives/consensus/beefy/src/payload.rs index dff017b49e0..1a06e620e7a 100644 --- a/substrate/primitives/consensus/beefy/src/payload.rs +++ b/substrate/primitives/consensus/beefy/src/payload.rs @@ -43,7 +43,7 @@ pub mod known_payloads { pub struct Payload(Vec<(BeefyPayloadId, Vec)>); impl Payload { - /// Construct a new payload given an initial vallue + /// Construct a new payload given an initial value pub fn from_single_entry(id: BeefyPayloadId, value: Vec) -> Self { Self(vec![(id, value)]) } diff --git a/substrate/primitives/consensus/common/src/lib.rs b/substrate/primitives/consensus/common/src/lib.rs index 6505d005deb..01d3b7a24f9 100644 --- a/substrate/primitives/consensus/common/src/lib.rs +++ b/substrate/primitives/consensus/common/src/lib.rs @@ -182,7 +182,7 @@ pub trait Proposer { + Send + Unpin + 'static; - /// The supported proof recording by the implementator of this trait. See [`ProofRecording`] + /// The supported proof recording by the implementor of this trait. See [`ProofRecording`] /// for more information. type ProofRecording: self::ProofRecording + Send + Sync + 'static; /// The proof type used by [`Self::ProofRecording`]. diff --git a/substrate/primitives/consensus/sassafras/src/ticket.rs b/substrate/primitives/consensus/sassafras/src/ticket.rs index dc0a61990d3..345de99be28 100644 --- a/substrate/primitives/consensus/sassafras/src/ticket.rs +++ b/substrate/primitives/consensus/sassafras/src/ticket.rs @@ -115,7 +115,7 @@ mod tests { let threshold = ticket_id_threshold(redundancy, slots, attempts, validators); let threshold = threshold as f64 / TicketId::MAX as f64; - // We expect that the total number of tickets allowed to be submited + // We expect that the total number of tickets allowed to be submitted // is slots*redundancy let avt = ((attempts * validators) as f64 * threshold) as u32; assert_eq!(avt, slots * redundancy); diff --git a/substrate/primitives/consensus/sassafras/src/vrf.rs b/substrate/primitives/consensus/sassafras/src/vrf.rs index 815edb5eb66..537cff52ab6 100644 --- a/substrate/primitives/consensus/sassafras/src/vrf.rs +++ b/substrate/primitives/consensus/sassafras/src/vrf.rs @@ -101,7 +101,7 @@ pub fn make_ticket_id(input: &VrfInput, pre_output: &VrfPreOutput) -> TicketId { u128::from_le_bytes(bytes) } -/// Make revealed key seed from a given VRF input and pre-ouput. +/// Make revealed key seed from a given VRF input and pre-output. /// /// Input should have been obtained via [`revealed_key_input`]. /// Pre-output should have been obtained from the input directly using the vrf diff --git a/substrate/primitives/core/src/address_uri.rs b/substrate/primitives/core/src/address_uri.rs index 2e32d0cd86d..d44f3c0c87c 100644 --- a/substrate/primitives/core/src/address_uri.rs +++ b/substrate/primitives/core/src/address_uri.rs @@ -85,7 +85,7 @@ impl Error { /// Complementary error information. /// -/// Strucutre contains complementary information about parsing address URI string. +/// Structure contains complementary information about parsing address URI string. /// String contains a copy of an original URI string, 0-based integer indicates position of invalid /// character. #[derive(Debug, PartialEq, Eq, Clone)] diff --git a/substrate/primitives/core/src/bandersnatch.rs b/substrate/primitives/core/src/bandersnatch.rs index 42c8b293634..71ee2da5383 100644 --- a/substrate/primitives/core/src/bandersnatch.rs +++ b/substrate/primitives/core/src/bandersnatch.rs @@ -249,7 +249,7 @@ pub mod vrf { /// /// The `transcript` summarizes a set of messages which are defining a particular /// protocol by automating the Fiat-Shamir transform for challenge generation. - /// A good explaination of the topic can be found in Merlin [docs](https://merlin.cool/) + /// A good explanation of the topic can be found in Merlin [docs](https://merlin.cool/) /// /// The `inputs` is a sequence of [`VrfInput`]s which, during the signing procedure, are /// first transformed to [`VrfPreOutput`]s. Both inputs and pre-outputs are then appended to diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 3901846b375..260e86b6ff9 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -73,7 +73,7 @@ pub mod ecdsa_bls377 { #[cfg(feature = "full_crypto")] impl Pair { - /// Hashes the `message` with the specified [`Hasher`] before signing sith the ECDSA secret + /// Hashes the `message` with the specified [`Hasher`] before signing with the ECDSA secret /// component. /// /// The hasher does not affect the BLS12-377 component. This generates BLS12-377 Signature diff --git a/substrate/primitives/inherents/src/client_side.rs b/substrate/primitives/inherents/src/client_side.rs index 27479de136f..3c299dfa4ee 100644 --- a/substrate/primitives/inherents/src/client_side.rs +++ b/substrate/primitives/inherents/src/client_side.rs @@ -23,7 +23,7 @@ use sp_runtime::traits::Block as BlockT; /// It is possible for the caller to provide custom arguments to the callee by setting the /// `ExtraArgs` generic parameter. /// -/// The crate already provides some convience implementations of this trait for +/// The crate already provides some convince implementations of this trait for /// `Box` and closures. So, it should not be required to implement /// this trait manually. #[async_trait::async_trait] diff --git a/substrate/primitives/io/Cargo.toml b/substrate/primitives/io/Cargo.toml index e47775d56d9..dddea4ffa23 100644 --- a/substrate/primitives/io/Cargo.toml +++ b/substrate/primitives/io/Cargo.toml @@ -85,7 +85,7 @@ disable_allocator = [] # This gives the caller direct programmatic access to the error message. # # When disabled the error message will only be printed out in the -# logs, with the caller receving a generic "wasm `unreachable` instruction executed" +# logs, with the caller receiving a generic "wasm `unreachable` instruction executed" # error message. # # This has no effect if both `disable_panic_handler` and `disable_oom` diff --git a/substrate/primitives/io/src/lib.rs b/substrate/primitives/io/src/lib.rs index 684854ea5c8..ec32b729033 100644 --- a/substrate/primitives/io/src/lib.rs +++ b/substrate/primitives/io/src/lib.rs @@ -1081,7 +1081,7 @@ pub trait Crypto { /// Register a `ecdsa` signature for batch verification. /// /// Batch verification must be enabled by calling [`start_batch_verify`]. - /// If batch verification is not enabled, the signature will be verified immediatley. + /// If batch verification is not enabled, the signature will be verified immediately. /// To get the result of the batch verification, [`finish_batch_verify`] /// needs to be called. /// @@ -1696,9 +1696,9 @@ mod tracing_setup { /// The PassingTracingSubscriber implements `tracing_core::Subscriber` /// and pushes the information across the runtime interface to the host - struct PassingTracingSubsciber; + struct PassingTracingSubscriber; - impl tracing_core::Subscriber for PassingTracingSubsciber { + impl tracing_core::Subscriber for PassingTracingSubscriber { fn enabled(&self, metadata: &Metadata<'_>) -> bool { wasm_tracing::enabled(Crossing(metadata.into())) } @@ -1731,7 +1731,7 @@ mod tracing_setup { /// set the global bridging subscriber once. pub fn init_tracing() { if TRACING_SET.load(Ordering::Relaxed) == false { - set_global_default(Dispatch::new(PassingTracingSubsciber {})) + set_global_default(Dispatch::new(PassingTracingSubscriber {})) .expect("We only ever call this once"); TRACING_SET.store(true, Ordering::Relaxed); } diff --git a/substrate/primitives/maybe-compressed-blob/Cargo.toml b/substrate/primitives/maybe-compressed-blob/Cargo.toml index fa5383d03b1..178c915ce83 100644 --- a/substrate/primitives/maybe-compressed-blob/Cargo.toml +++ b/substrate/primitives/maybe-compressed-blob/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" repository.workspace = true -description = "Handling of blobs, usually Wasm code, which may be compresed" +description = "Handling of blobs, usually Wasm code, which may be compressed" documentation = "https://docs.rs/sp-maybe-compressed-blob" readme = "README.md" diff --git a/substrate/primitives/metadata-ir/src/types.rs b/substrate/primitives/metadata-ir/src/types.rs index b107d20a8e2..b05f26ff55d 100644 --- a/substrate/primitives/metadata-ir/src/types.rs +++ b/substrate/primitives/metadata-ir/src/types.rs @@ -160,7 +160,7 @@ pub struct ExtrinsicMetadataIR { pub ty: T::Type, /// Extrinsic version. pub version: u8, - /// The type of the address that signes the extrinsic + /// The type of the address that signs the extrinsic pub address_ty: T::Type, /// The type of the outermost Call enum. pub call_ty: T::Type, diff --git a/substrate/primitives/npos-elections/src/pjr.rs b/substrate/primitives/npos-elections/src/pjr.rs index 08e40a014ea..6e3775199a2 100644 --- a/substrate/primitives/npos-elections/src/pjr.rs +++ b/substrate/primitives/npos-elections/src/pjr.rs @@ -261,7 +261,7 @@ fn prepare_pjr_input( } } - // Convert Suppports into a SupportMap + // Convert Supports into a SupportMap // // As a flat list, we're limited to linear search. That gives the production of `candidates`, // below, a complexity of `O(s*c)`, where `s == supports.len()` and `c == all_candidates.len()`. diff --git a/substrate/primitives/npos-elections/src/reduce.rs b/substrate/primitives/npos-elections/src/reduce.rs index c9ed493daf3..3fd291f88ab 100644 --- a/substrate/primitives/npos-elections/src/reduce.rs +++ b/substrate/primitives/npos-elections/src/reduce.rs @@ -393,7 +393,7 @@ fn reduce_all(assignments: &mut Vec>) -> u32 // voter_root_path.last().unwrap()); TODO: @kian // the common path must be non-void.. debug_assert!(common_count > 0); - // and smaller than btoh + // and smaller than both debug_assert!(common_count <= voter_root_path.len()); debug_assert!(common_count <= target_root_path.len()); diff --git a/substrate/primitives/runtime-interface/src/lib.rs b/substrate/primitives/runtime-interface/src/lib.rs index 8b0edf1ec81..f6ef27789b3 100644 --- a/substrate/primitives/runtime-interface/src/lib.rs +++ b/substrate/primitives/runtime-interface/src/lib.rs @@ -283,7 +283,7 @@ pub use sp_std; /// /// `key` holds the pointer and the length to the `data` slice. /// pub fn call(data: &[u8]) -> Vec { /// extern "C" { pub fn ext_call_version_2(key: u64); } -/// // Should call into extenal `ext_call_version_2(<[u8] as IntoFFIValue>::into_ffi_value(key))` +/// // Should call into external `ext_call_version_2(<[u8] as IntoFFIValue>::into_ffi_value(key))` /// // But this is too much to replicate in a doc test so here we just return a dummy vector. /// // Note that we jump into the latest version not marked as `register_only` (i.e. version 2). /// Vec::new() diff --git a/substrate/primitives/runtime-interface/test-wasm-deprecated/src/lib.rs b/substrate/primitives/runtime-interface/test-wasm-deprecated/src/lib.rs index 2f42e60504e..871a4922ce3 100644 --- a/substrate/primitives/runtime-interface/test-wasm-deprecated/src/lib.rs +++ b/substrate/primitives/runtime-interface/test-wasm-deprecated/src/lib.rs @@ -45,19 +45,19 @@ pub fn import_sp_io() { #[runtime_interface] pub trait TestApi { - fn test_versionning(&self, _data: u32) -> bool { + fn test_versioning(&self, _data: u32) -> bool { // should not be called unimplemented!() } } wasm_export_functions! { - fn test_versionning_works() { + fn test_versioning_works() { // old api allows only 42 and 50 - assert!(test_api::test_versionning(42)); - assert!(test_api::test_versionning(50)); + assert!(test_api::test_versioning(42)); + assert!(test_api::test_versioning(50)); - assert!(!test_api::test_versionning(142)); - assert!(!test_api::test_versionning(0)); + assert!(!test_api::test_versioning(142)); + assert!(!test_api::test_versioning(0)); } } diff --git a/substrate/primitives/runtime-interface/test-wasm/src/lib.rs b/substrate/primitives/runtime-interface/test-wasm/src/lib.rs index cf1ff3bca08..2b3fc728f6f 100644 --- a/substrate/primitives/runtime-interface/test-wasm/src/lib.rs +++ b/substrate/primitives/runtime-interface/test-wasm/src/lib.rs @@ -126,21 +126,21 @@ pub trait TestApi { val } - fn test_versionning(&self, data: u32) -> bool { + fn test_versioning(&self, data: u32) -> bool { data == 42 || data == 50 } #[version(2)] - fn test_versionning(&self, data: u32) -> bool { + fn test_versioning(&self, data: u32) -> bool { data == 42 } - fn test_versionning_register_only(&self, data: u32) -> bool { + fn test_versioning_register_only(&self, data: u32) -> bool { data == 80 } #[version(2, register_only)] - fn test_versionning_register_only(&self, data: u32) -> bool { + fn test_versioning_register_only(&self, data: u32) -> bool { data == 42 } @@ -282,21 +282,21 @@ wasm_export_functions! { assert_eq!(0, len); } - fn test_versionning_works() { + fn test_versioning_works() { // we fix new api to accept only 42 as a proper input // as opposed to sp-runtime-interface-test-wasm-deprecated::test_api::verify_input // which accepted 42 and 50. - assert!(test_api::test_versionning(42)); + assert!(test_api::test_versioning(42)); - assert!(!test_api::test_versionning(50)); - assert!(!test_api::test_versionning(102)); + assert!(!test_api::test_versioning(50)); + assert!(!test_api::test_versioning(102)); } - fn test_versionning_register_only_works() { + fn test_versioning_register_only_works() { // Ensure that we will import the version of the runtime interface function that // isn't tagged with `register_only`. - assert!(!test_api::test_versionning_register_only(42)); - assert!(test_api::test_versionning_register_only(80)); + assert!(!test_api::test_versioning_register_only(42)); + assert!(test_api::test_versioning_register_only(80)); } fn test_return_input_as_tuple() { diff --git a/substrate/primitives/runtime-interface/test/src/lib.rs b/substrate/primitives/runtime-interface/test/src/lib.rs index 215704a1121..05a955fbe3f 100644 --- a/substrate/primitives/runtime-interface/test/src/lib.rs +++ b/substrate/primitives/runtime-interface/test/src/lib.rs @@ -163,18 +163,18 @@ fn test_array_return_value_memory_is_freed() { } #[test] -fn test_versionining_with_new_host_works() { +fn test_versioning_with_new_host_works() { // We call to the new wasm binary with new host function. - call_wasm_method::(wasm_binary_unwrap(), "test_versionning_works"); + call_wasm_method::(wasm_binary_unwrap(), "test_versioning_works"); // we call to the old wasm binary with a new host functions // old versions of host functions should be called and test should be ok! - call_wasm_method::(wasm_binary_deprecated_unwrap(), "test_versionning_works"); + call_wasm_method::(wasm_binary_deprecated_unwrap(), "test_versioning_works"); } #[test] -fn test_versionining_register_only() { - call_wasm_method::(wasm_binary_unwrap(), "test_versionning_register_only_works"); +fn test_versioning_register_only() { + call_wasm_method::(wasm_binary_unwrap(), "test_versioning_register_only_works"); } fn run_test_in_another_process( diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index 5b54caf597b..8f6c0c6f650 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -40,7 +40,7 @@ use sp_std::{fmt, prelude::*}; /// the decoding fails. const EXTRINSIC_FORMAT_VERSION: u8 = 4; -/// The `SingaturePayload` of `UncheckedExtrinsic`. +/// The `SignaturePayload` of `UncheckedExtrinsic`. type UncheckedSignaturePayload = (Address, Signature, Extra); /// An extrinsic right from the external world. This is unchecked and so can contain a signature. diff --git a/substrate/primitives/runtime/src/offchain/storage_lock.rs b/substrate/primitives/runtime/src/offchain/storage_lock.rs index 56d0eeae527..cfdaa954fe5 100644 --- a/substrate/primitives/runtime/src/offchain/storage_lock.rs +++ b/substrate/primitives/runtime/src/offchain/storage_lock.rs @@ -556,7 +556,7 @@ mod tests { let res = lock.try_lock(); assert_eq!(res.is_ok(), false); - // sleep again untill sleep_until > deadline + // sleep again until sleep_until > deadline offchain::sleep_until(offchain::timestamp().add(Duration::from_millis(200))); // the lock has expired, failed to extend it diff --git a/substrate/primitives/runtime/src/testing.rs b/substrate/primitives/runtime/src/testing.rs index 5f94c834a8f..b4aeda5a0e7 100644 --- a/substrate/primitives/runtime/src/testing.rs +++ b/substrate/primitives/runtime/src/testing.rs @@ -284,9 +284,9 @@ where } /// The signature payload of a `TestXt`. -type TxSingaturePayload = (u64, Extra); +type TxSignaturePayload = (u64, Extra); -impl SignaturePayload for TxSingaturePayload { +impl SignaturePayload for TxSignaturePayload { type SignatureAddress = u64; type Signature = (); type SignatureExtra = Extra; @@ -299,7 +299,7 @@ impl SignaturePayload for TxSingaturePayload { #[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo)] pub struct TestXt { /// Signature of the extrinsic. - pub signature: Option>, + pub signature: Option>, /// Call of the extrinsic. pub call: Call, } @@ -348,7 +348,7 @@ impl traits::Extrinsic for TestXt { type Call = Call; - type SignaturePayload = TxSingaturePayload; + type SignaturePayload = TxSignaturePayload; fn is_signed(&self) -> Option { Some(self.signature.is_some()) diff --git a/substrate/primitives/runtime/src/traits.rs b/substrate/primitives/runtime/src/traits.rs index 9ee41339d50..5a6c306dd2a 100644 --- a/substrate/primitives/runtime/src/traits.rs +++ b/substrate/primitives/runtime/src/traits.rs @@ -330,7 +330,7 @@ impl> Morph
for MorphInto { } } -/// Implementation of `TryMorph` which attmepts to convert between types using `TryInto`. +/// Implementation of `TryMorph` which attempts to convert between types using `TryInto`. pub struct TryMorphInto(sp_std::marker::PhantomData); impl> TryMorph for TryMorphInto { type Outcome = T; @@ -1449,7 +1449,7 @@ pub trait Dispatchable { /// to represent the dispatch class and weight. type Info; /// Additional information that is returned by `dispatch`. Can be used to supply the caller - /// with information about a `Dispatchable` that is ownly known post dispatch. + /// with information about a `Dispatchable` that is only known post dispatch. type PostInfo: Eq + PartialEq + Clone + Copy + Encode + Decode + Printable; /// Actually dispatch this call and return the result of it. fn dispatch(self, origin: Self::RuntimeOrigin) diff --git a/substrate/primitives/staking/src/offence.rs b/substrate/primitives/staking/src/offence.rs index 64aa4692eb5..30d96d0cbaf 100644 --- a/substrate/primitives/staking/src/offence.rs +++ b/substrate/primitives/staking/src/offence.rs @@ -117,7 +117,7 @@ pub trait Offence { /// Errors that may happen on offence reports. #[derive(PartialEq, sp_runtime::RuntimeDebug)] pub enum OffenceError { - /// The report has already been sumbmitted. + /// The report has already been submitted. DuplicateReport, /// Other error has happened. diff --git a/substrate/primitives/state-machine/src/ext.rs b/substrate/primitives/state-machine/src/ext.rs index 73110f55cba..9aa32bc866c 100644 --- a/substrate/primitives/state-machine/src/ext.rs +++ b/substrate/primitives/state-machine/src/ext.rs @@ -44,7 +44,7 @@ const EXT_NOT_ALLOWED_TO_FAIL: &str = "Externalities not allowed to fail within const BENCHMARKING_FN: &str = "\ This is a special fn only for benchmarking where a database commit happens from the runtime. For that reason client started transactions before calling into runtime are not allowed. - Without client transactions the loop condition garantuees the success of the tx close."; + Without client transactions the loop condition guarantees the success of the tx close."; #[cfg(feature = "std")] fn guard() -> sp_panic_handler::AbortGuard { @@ -722,7 +722,7 @@ impl Encode for EncodeOpaqueValue { } } -/// Auxialiary structure for appending a value to a storage item. +/// Auxiliary structure for appending a value to a storage item. pub(crate) struct StorageAppend<'a>(&'a mut Vec); impl<'a> StorageAppend<'a> { diff --git a/substrate/primitives/state-machine/src/lib.rs b/substrate/primitives/state-machine/src/lib.rs index 200cebe68de..13087431d38 100644 --- a/substrate/primitives/state-machine/src/lib.rs +++ b/substrate/primitives/state-machine/src/lib.rs @@ -1451,7 +1451,7 @@ mod tests { enum Item { InitializationItem, DiscardedItem, - CommitedItem, + CommittedItem, } let key = b"events".to_vec(); @@ -1488,21 +1488,21 @@ mod tests { assert_eq!(ext.storage(key.as_slice()), Some(vec![Item::InitializationItem].encode())); - ext.storage_append(key.clone(), Item::CommitedItem.encode()); + ext.storage_append(key.clone(), Item::CommittedItem.encode()); assert_eq!( ext.storage(key.as_slice()), - Some(vec![Item::InitializationItem, Item::CommitedItem].encode()), + Some(vec![Item::InitializationItem, Item::CommittedItem].encode()), ); } overlay.start_transaction(); - // Then only initlaization item and second (committed) item should persist. + // Then only initialization item and second (committed) item should persist. { let ext = Ext::new(&mut overlay, backend, None); assert_eq!( ext.storage(key.as_slice()), - Some(vec![Item::InitializationItem, Item::CommitedItem].encode()), + Some(vec![Item::InitializationItem, Item::CommittedItem].encode()), ); } } @@ -1866,7 +1866,7 @@ mod tests { // a inner hashable node (&b"k"[..], Some(&long_vec[..])), // need to ensure this is not an inline node - // otherwhise we do not know what is accessed when + // otherwise we do not know what is accessed when // storing proof. (&b"key1"[..], Some(&vec![5u8; 32][..])), (&b"key2"[..], Some(&b"val3"[..])), diff --git a/substrate/primitives/state-machine/src/overlayed_changes/changeset.rs b/substrate/primitives/state-machine/src/overlayed_changes/changeset.rs index a25a5b81052..601bc2e2919 100644 --- a/substrate/primitives/state-machine/src/overlayed_changes/changeset.rs +++ b/substrate/primitives/state-machine/src/overlayed_changes/changeset.rs @@ -47,7 +47,7 @@ pub struct NoOpenTransaction; #[cfg_attr(test, derive(PartialEq))] pub struct AlreadyInRuntime; -/// Error when calling `exit_runtime` when not being in runtime exection mdde. +/// Error when calling `exit_runtime` when not being in runtime execution mode. #[derive(Debug)] #[cfg_attr(test, derive(PartialEq))] pub struct NotInRuntime; @@ -269,7 +269,7 @@ impl OverlayedMap { /// /// Panics: /// Panics if there are open transactions: `transaction_depth() > 0` - pub fn drain_commited(self) -> impl Iterator { + pub fn drain_committed(self) -> impl Iterator { assert!(self.transaction_depth() == 0, "Drain is not allowed with open transactions."); self.changes.into_iter().map(|(k, mut v)| (k, v.pop_transaction().value)) } @@ -281,7 +281,7 @@ impl OverlayedMap { self.dirty_keys.len() } - /// Call this before transfering control to the runtime. + /// Call this before transferring control to the runtime. /// /// This protects all existing transactions from being removed by the runtime. /// Calling this while already inside the runtime will return an error. @@ -471,7 +471,7 @@ mod test { } fn assert_drained_changes(is: OverlayedChangeSet, expected: Changes) { - let is = is.drain_commited().collect::>(); + let is = is.drain_committed().collect::>(); let expected = expected .iter() .map(|(k, v)| (k.to_vec(), v.0.map(From::from))) @@ -480,7 +480,7 @@ mod test { } fn assert_drained(is: OverlayedChangeSet, expected: Drained) { - let is = is.drain_commited().collect::>(); + let is = is.drain_committed().collect::>(); let expected = expected .iter() .map(|(k, v)| (k.to_vec(), v.map(From::from))) @@ -526,7 +526,7 @@ mod test { changeset.set(b"key0".to_vec(), Some(b"val0-rolled".to_vec()), Some(1000)); changeset.set(b"key5".to_vec(), Some(b"val5-rolled".to_vec()), None); - // changes contain all changes not only the commmited ones. + // changes contain all changes not only the committed ones. let all_changes: Changes = vec![ (b"key0", (Some(b"val0-rolled"), vec![1, 10, 1000])), (b"key1", (Some(b"val1"), vec![1])), @@ -807,7 +807,7 @@ mod test { fn drain_with_open_transaction_panics() { let mut changeset = OverlayedChangeSet::default(); changeset.start_transaction(); - let _ = changeset.drain_commited(); + let _ = changeset.drain_committed(); } #[test] diff --git a/substrate/primitives/state-machine/src/overlayed_changes/mod.rs b/substrate/primitives/state-machine/src/overlayed_changes/mod.rs index 039631e4a63..d6fc404e84f 100644 --- a/substrate/primitives/state-machine/src/overlayed_changes/mod.rs +++ b/substrate/primitives/state-machine/src/overlayed_changes/mod.rs @@ -480,7 +480,7 @@ impl OverlayedChanges { Ok(()) } - /// Call this before transfering control to the runtime. + /// Call this before transferring control to the runtime. /// /// This protects all existing transactions from being removed by the runtime. /// Calling this while already inside the runtime will return an error. @@ -575,10 +575,10 @@ impl OverlayedChanges { }; use core::mem::take; - let main_storage_changes = take(&mut self.top).drain_commited(); + let main_storage_changes = take(&mut self.top).drain_committed(); let child_storage_changes = take(&mut self.children) .into_iter() - .map(|(key, (val, info))| (key, (val.drain_commited(), info))); + .map(|(key, (val, info))| (key, (val.drain_committed(), info))); let offchain_storage_changes = self.offchain_drain_committed().collect(); @@ -809,7 +809,7 @@ pub struct OverlayedExtensions<'a> { #[cfg(feature = "std")] impl<'a> OverlayedExtensions<'a> { - /// Create a new instance of overalyed extensions from the given extensions. + /// Create a new instance of overlaid extensions from the given extensions. pub fn new(extensions: &'a mut Extensions) -> Self { Self { extensions: extensions diff --git a/substrate/primitives/state-machine/src/testing.rs b/substrate/primitives/state-machine/src/testing.rs index 0eb7b6d1118..e19ba95755c 100644 --- a/substrate/primitives/state-machine/src/testing.rs +++ b/substrate/primitives/state-machine/src/testing.rs @@ -417,7 +417,7 @@ mod tests { original_ext.backend.clone().into_storage(), ); - // Ensure all have the correct ref counrt + // Ensure all have the correct ref count assert!(original_ext.backend.backend_storage().keys().values().all(|r| *r == 2)); // Drain the raw storage and root. diff --git a/substrate/primitives/state-machine/src/trie_backend_essence.rs b/substrate/primitives/state-machine/src/trie_backend_essence.rs index 1824a77c370..a1f00579874 100644 --- a/substrate/primitives/state-machine/src/trie_backend_essence.rs +++ b/substrate/primitives/state-machine/src/trie_backend_essence.rs @@ -34,8 +34,8 @@ use parking_lot::RwLock; use sp_core::storage::{ChildInfo, ChildType, StateVersion}; use sp_trie::{ child_delta_trie_root, delta_trie_root, empty_child_trie_root, - read_child_trie_first_descedant_value, read_child_trie_hash, read_child_trie_value, - read_trie_first_descedant_value, read_trie_value, + read_child_trie_first_descendant_value, read_child_trie_hash, read_child_trie_value, + read_trie_first_descendant_value, read_trie_value, trie_types::{TrieDBBuilder, TrieError}, DBValue, KeySpacedDB, MerkleValue, NodeCodec, PrefixedMemoryDB, Trie, TrieCache, TrieDBRawIterator, TrieRecorder, TrieRecorderProvider, @@ -554,7 +554,7 @@ where let map_e = |e| format!("Trie lookup error: {}", e); self.with_recorder_and_cache(None, |recorder, cache| { - read_trie_first_descedant_value::, _>(self, &self.root, key, recorder, cache) + read_trie_first_descendant_value::, _>(self, &self.root, key, recorder, cache) .map_err(map_e) }) } @@ -570,7 +570,7 @@ where let map_e = |e| format!("Trie lookup error: {}", e); self.with_recorder_and_cache(Some(child_root), |recorder, cache| { - read_child_trie_first_descedant_value::, _>( + read_child_trie_first_descendant_value::, _>( child_info.keyspace(), self, &child_root, diff --git a/substrate/primitives/storage/src/lib.rs b/substrate/primitives/storage/src/lib.rs index b55cc8f2174..197994f5747 100644 --- a/substrate/primitives/storage/src/lib.rs +++ b/substrate/primitives/storage/src/lib.rs @@ -452,7 +452,7 @@ impl TryFrom for StateVersion { impl StateVersion { /// If defined, values in state of size bigger or equal /// to this threshold will use a separate trie node. - /// Otherwhise, value will be inlined in branch or leaf + /// Otherwise, value will be inlined in branch or leaf /// node. pub fn state_value_threshold(&self) -> Option { match self { diff --git a/substrate/primitives/tracing/src/lib.rs b/substrate/primitives/tracing/src/lib.rs index b8b99230db5..34ed088aed0 100644 --- a/substrate/primitives/tracing/src/lib.rs +++ b/substrate/primitives/tracing/src/lib.rs @@ -17,7 +17,7 @@ //! Substrate tracing primitives and macros. //! -//! To trace functions or invidual code in Substrate, this crate provides [`within_span`] +//! To trace functions or individual code in Substrate, this crate provides [`within_span`] //! and [`enter_span`]. See the individual docs for how to use these macros. //! //! Note that to allow traces from wasm execution environment there are @@ -70,7 +70,7 @@ pub use crate::types::{WASM_NAME_KEY, WASM_TARGET_KEY, WASM_TRACE_IDENTIFIER}; /// directly as they yield nothing without the feature present. Instead you should use /// `enter_span!` and `within_span!` – which would strip away even any parameter conversion /// you do within the span-definition (and thus optimise your performance). For your -/// convineience you directly specify the `Level` and name of the span or use the full +/// convenience you directly specify the `Level` and name of the span or use the full /// feature set of `span!`/`span_*!` on it: /// /// # Example @@ -98,7 +98,7 @@ pub use crate::types::{WASM_NAME_KEY, WASM_TARGET_KEY, WASM_TRACE_IDENTIFIER}; /// This project only provides the macros and facilities to manage tracing /// it doesn't implement the tracing subscriber or backend directly – that is /// up to the developer integrating it into a specific environment. In native -/// this can and must be done through the regular `tracing`-facitilies, please +/// this can and must be done through the regular `tracing`-facilities, please /// see their documentation for details. /// /// On the wasm-side we've adopted a similar approach of having a global @@ -139,7 +139,7 @@ pub fn init_for_tests() { /// Runs given code within a tracing span, measuring it's execution time. /// /// If tracing is not enabled, the code is still executed. Pass in level and name or -/// use any valid `sp_tracing::Span`followe by `;` and the code to execute, +/// use any valid `sp_tracing::Span`followed by `;` and the code to execute, /// /// # Example /// diff --git a/substrate/primitives/tracing/src/types.rs b/substrate/primitives/tracing/src/types.rs index 3692a81e03c..46f38383d98 100644 --- a/substrate/primitives/tracing/src/types.rs +++ b/substrate/primitives/tracing/src/types.rs @@ -17,7 +17,7 @@ use alloc::{vec, vec::Vec}; use codec::{Decode, Encode}; -/// Types for wasm based tracing. Loosly inspired by `tracing-core` but +/// Types for wasm based tracing. Loosely inspired by `tracing-core` but /// optimised for the specific use case. use core::{fmt::Debug, format_args}; @@ -54,7 +54,7 @@ impl core::default::Default for WasmLevel { } } -/// A paramter value provided to the span/event +/// A parameter value provided to the span/event #[derive(Encode, Decode, Clone)] pub enum WasmValue { U8(u8), @@ -180,9 +180,9 @@ impl From for WasmValue { } } -/// The name of a field provided as the argument name when contstructing an +/// The name of a field provided as the argument name when constructing an /// `event!` or `span!`. -/// Generally generated automaticaly via `stringify` from an `'static &str`. +/// Generally generated automatically via `stringify` from an `'static &str`. /// Likely print-able. #[derive(Encode, Decode, Clone)] pub struct WasmFieldName(Vec); @@ -320,7 +320,7 @@ impl tracing_core::field::Visit for WasmValuesSet { self.0.push((field.name().into(), Some(WasmValue::from(value)))) } } -/// Metadata provides generic information about the specifc location of the +/// Metadata provides generic information about the specific location of the /// `span!` or `event!` call on the wasm-side. #[derive(Encode, Decode, Clone)] pub struct WasmMetadata { diff --git a/substrate/primitives/transaction-storage-proof/src/lib.rs b/substrate/primitives/transaction-storage-proof/src/lib.rs index 352f2aec26e..893b2e33bee 100644 --- a/substrate/primitives/transaction-storage-proof/src/lib.rs +++ b/substrate/primitives/transaction-storage-proof/src/lib.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Storage proof primitives. Constains types and basic code to extract storage +//! Storage proof primitives. Contains types and basic code to extract storage //! proofs for indexed transactions. #![cfg_attr(not(feature = "std"), no_std)] diff --git a/substrate/primitives/trie/src/cache/mod.rs b/substrate/primitives/trie/src/cache/mod.rs index 01f08a78adc..32078169b50 100644 --- a/substrate/primitives/trie/src/cache/mod.rs +++ b/substrate/primitives/trie/src/cache/mod.rs @@ -323,7 +323,7 @@ type ValueAccessSet = /// /// This cache should be used per state instance created by the backend. One state instance is /// referring to the state of one block. It will cache all the accesses that are done to the state -/// which could not be fullfilled by the [`SharedTrieCache`]. These locally cached items are merged +/// which could not be fulfilled by the [`SharedTrieCache`]. These locally cached items are merged /// back to the shared trie cache when this instance is dropped. /// /// When using [`Self::as_trie_db_cache`] or [`Self::as_trie_db_mut_cache`], it will lock Mutexes. diff --git a/substrate/primitives/trie/src/lib.rs b/substrate/primitives/trie/src/lib.rs index 81b37a0c9a6..0ae448aff6e 100644 --- a/substrate/primitives/trie/src/lib.rs +++ b/substrate/primitives/trie/src/lib.rs @@ -326,7 +326,7 @@ pub fn read_trie_value( +pub fn read_trie_first_descendant_value( db: &DB, root: &TrieHash, key: &[u8], @@ -447,7 +447,7 @@ where /// Read the [`trie_db::MerkleValue`] of the node that is the closest descendant for /// the provided child key. -pub fn read_child_trie_first_descedant_value( +pub fn read_child_trie_first_descendant_value( keyspace: &[u8], db: &DB, root: &TrieHash, diff --git a/substrate/primitives/version/proc-macro/src/decl_runtime_version.rs b/substrate/primitives/version/proc-macro/src/decl_runtime_version.rs index 7ca2d9b71f6..3671d4aff6b 100644 --- a/substrate/primitives/version/proc-macro/src/decl_runtime_version.rs +++ b/substrate/primitives/version/proc-macro/src/decl_runtime_version.rs @@ -52,7 +52,7 @@ fn decl_runtime_version_impl_inner(item: ItemConst) -> Result { /// enable `std` feature even for `no_std` wasm runtime builds. /// /// One difference from the original definition is the `apis` field. Since we don't actually parse -/// `apis` from this macro it will always be emitteed as empty. An empty vector can be encoded as +/// `apis` from this macro it will always be emitted as empty. An empty vector can be encoded as /// a zero-byte, thus `u8` is sufficient here. #[derive(Encode)] struct RuntimeVersion { diff --git a/substrate/primitives/version/src/lib.rs b/substrate/primitives/version/src/lib.rs index 9b14a809ac1..789c507742f 100644 --- a/substrate/primitives/version/src/lib.rs +++ b/substrate/primitives/version/src/lib.rs @@ -327,7 +327,7 @@ impl RuntimeVersion { /// /// For runtime with core api version less than 4, /// V0 trie version will be applied to state. - /// Otherwhise, V1 trie version will be use. + /// Otherwise, V1 trie version will be use. pub fn state_version(&self) -> StateVersion { // If version > than 1, keep using latest version. self.state_version.try_into().unwrap_or(StateVersion::V1) diff --git a/substrate/utils/fork-tree/src/lib.rs b/substrate/utils/fork-tree/src/lib.rs index cd175166b9c..ff86467c85d 100644 --- a/substrate/utils/fork-tree/src/lib.rs +++ b/substrate/utils/fork-tree/src/lib.rs @@ -683,7 +683,7 @@ where node.data }); - // Retain only roots that are descendents of the finalized block (this + // Retain only roots that are descendants of the finalized block (this // happens if the node has been properly finalized) or that are // ancestors (or equal) to the finalized block (in this case the node // wasn't finalized earlier presumably because the predicate didn't @@ -1168,7 +1168,7 @@ mod test { Ok(Some(false)), ); - // finalizing "E" is not allowed since there are not finalized anchestors. + // finalizing "E" is not allowed since there are not finalized ancestors. assert_eq!( tree.finalizes_any_with_descendent_if(&"E", 15, &is_descendent_of, |c| c.effective == 10), @@ -1309,7 +1309,7 @@ mod test { fn map_works() { let (mut tree, _) = test_fork_tree(); - // Extend the single root fork-tree to also excercise the roots order during map. + // Extend the single root fork-tree to also exercise the roots order during map. let is_descendent_of = |_: &&str, _: &&str| -> Result { Ok(false) }; let is_root = tree.import("A1", 10, 1, &is_descendent_of).unwrap(); assert!(is_root); diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs index c6ba2824016..80a5d27d8c2 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -415,7 +415,7 @@ impl PalletCmd { .map_err(|e| { format!("Error executing and verifying runtime benchmark: {}", e) })?; - // Dont use these results since verification code will add overhead. + // Don't use these results since verification code will add overhead. let _batch = , String> as Decode>::decode( &mut &result[..], @@ -437,7 +437,7 @@ impl PalletCmd { &pallet.clone(), &extrinsic.clone(), &selected_components.clone(), - false, // dont run verification code for final values + false, // don't run verification code for final values self.repeat, ) .encode(), @@ -469,7 +469,7 @@ impl PalletCmd { &pallet.clone(), &extrinsic.clone(), &selected_components.clone(), - false, // dont run verification code for final values + false, // don't run verification code for final values self.repeat, ) .encode(), diff --git a/substrate/utils/frame/generate-bags/src/lib.rs b/substrate/utils/frame/generate-bags/src/lib.rs index 923017261a4..62485c442d3 100644 --- a/substrate/utils/frame/generate-bags/src/lib.rs +++ b/substrate/utils/frame/generate-bags/src/lib.rs @@ -183,7 +183,7 @@ pub fn generate_thresholds( total_issuance: u128, minimum_balance: u128, ) -> Result<(), std::io::Error> { - // ensure the file is accessable + // ensure the file is accessible if let Some(parent) = output.parent() { if !parent.exists() { std::fs::create_dir_all(parent)?; diff --git a/substrate/utils/frame/remote-externalities/src/lib.rs b/substrate/utils/frame/remote-externalities/src/lib.rs index c7399468da9..254d33deec8 100644 --- a/substrate/utils/frame/remote-externalities/src/lib.rs +++ b/substrate/utils/frame/remote-externalities/src/lib.rs @@ -762,7 +762,7 @@ where let mut sp = Spinner::with_timer(Spinners::Dots, "Inserting keys into DB...".into()); let start = Instant::now(); pending_ext.batch_insert(key_values.clone().into_iter().filter_map(|(k, v)| { - // Don't insert the child keys here, they need to be inserted seperately with all their + // Don't insert the child keys here, they need to be inserted separately with all their // data in the load_child_remote function. match is_default_child_storage_key(&k.0) { true => None, diff --git a/substrate/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs b/substrate/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs index f45258ea593..c0333bb7dac 100644 --- a/substrate/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs +++ b/substrate/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs @@ -132,7 +132,7 @@ pub trait StateMigrationApi { /// Check current migration state. /// /// This call is performed locally without submitting any transactions. Thus executing this - /// won't change any state. Nonetheless it is a VERY costy call that should be + /// won't change any state. Nonetheless it is a VERY costly call that should be /// only exposed to trusted peers. #[method(name = "state_trieMigrationStatus")] fn call(&self, at: Option) -> RpcResult; diff --git a/substrate/utils/substrate-bip39/README.md b/substrate/utils/substrate-bip39/README.md index 368d18f406b..e7a80ca5f2c 100644 --- a/substrate/utils/substrate-bip39/README.md +++ b/substrate/utils/substrate-bip39/README.md @@ -21,12 +21,12 @@ to wallets providing their own dictionaries and checksum mechanism. Issues with to CSPRNG supplied dictionary phrases. 2. Providing own dictionaries felt into the _you ain't gonna need it_ anti-pattern category on day 1. Wallet providers - (be it hardware or software) typically want their products to be compatibile with other wallets so that users can + (be it hardware or software) typically want their products to be compatible with other wallets so that users can migrate to their product without having to migrate all their assets. To achieve the above phrases have to be precisely encoded in _The One True Canonical Encoding_, for which UTF-8 NFKD was chosen. This is largely irrelevant (and even ignored) for English phrases, as they encode to basically just ASCII in -virtualy every character encoding known to mankind, but immedietly becomes a problem for dictionaries that do use +virtually every character encoding known to mankind, but immediately becomes a problem for dictionaries that do use non-ASCII characters. Even if the right encoding is used and implemented correctly, there are still [other caveats present for some non-english dictionaries](https://github.com/bitcoin/bips/blob/master/bip-0039/bip-0039-wordlists.md), such as normalizing spaces to a canonical form, or making some latin based characters equivalent to their base in @@ -34,8 +34,8 @@ dictionary lookups (eg. Spanish `ñ` and `n` are meant to be interchangeable). T headache, and opens doors for disagreements between buggy implementations, breaking compatibility. BIP39 does already provide a form of the mnemonic that is free from all of these issues: the entropy byte array. Since -veryfing the checksum requires that we recover the entropy from which the phrase was generated, no extra work is -actually needed here. Wallet implementators can encode the dictionaries in whatever encoding they find convenient (as +verifying the checksum requires that we recover the entropy from which the phrase was generated, no extra work is +actually needed here. Wallet implementors can encode the dictionaries in whatever encoding they find convenient (as long as they are the standard BIP39 dictionaries), no harm in using UTF-16 string primitives that Java and JavaScript provide. Since the dictionary is fixed and known, and the checksum is done on the entropy itself, the exact character encoding used becomes irrelevant, as are the precise codepoints and amount of whitespace around the words. It is thus diff --git a/substrate/utils/substrate-bip39/src/lib.rs b/substrate/utils/substrate-bip39/src/lib.rs index 3673d20faed..5b68bef0c39 100644 --- a/substrate/utils/substrate-bip39/src/lib.rs +++ b/substrate/utils/substrate-bip39/src/lib.rs @@ -43,7 +43,7 @@ pub enum Error { /// /// Any other length will return an error. /// -/// `password` is analog to BIP39 seed generation itself, with an empty string being defalt. +/// `password` is analog to BIP39 seed generation itself, with an empty string being default. pub fn mini_secret_from_entropy(entropy: &[u8], password: &str) -> Result { let seed = seed_from_entropy(entropy, password)?; Ok(MiniSecretKey::from_bytes(&seed[..32]).expect("Length is always correct; qed")) diff --git a/substrate/utils/wasm-builder/src/lib.rs b/substrate/utils/wasm-builder/src/lib.rs index 5cde48c0950..178e499e8f5 100644 --- a/substrate/utils/wasm-builder/src/lib.rs +++ b/substrate/utils/wasm-builder/src/lib.rs @@ -207,7 +207,7 @@ fn get_cargo_command(target: RuntimeTarget) -> CargoCommand { } else { // If no command before provided us with a cargo that supports our Substrate wasm env, we // try to search one with rustup. If that fails as well, we return the default cargo and let - // the prequisities check fail. + // the perquisites check fail. get_rustup_command(target).unwrap_or(default_cargo) } } diff --git a/substrate/utils/wasm-builder/src/wasm_project.rs b/substrate/utils/wasm-builder/src/wasm_project.rs index 13db9fce431..b58e6bfa36b 100644 --- a/substrate/utils/wasm-builder/src/wasm_project.rs +++ b/substrate/utils/wasm-builder/src/wasm_project.rs @@ -695,7 +695,7 @@ impl BuildConfiguration { /// "production". It would only contain the builtin profile where the custom profile /// inherits from. This is why we inspect the build path to learn which profile is used. /// - /// When not overriden by a env variable we always default to building wasm with the `Release` + /// When not overridden by a env variable we always default to building wasm with the `Release` /// profile even when the main build uses the debug build. This is because wasm built with the /// `Debug` profile is too slow for normal development activities and almost never intended. /// @@ -704,9 +704,9 @@ impl BuildConfiguration { /// /// # Note /// - /// Can be overriden by setting [`crate::WASM_BUILD_TYPE_ENV`]. + /// Can be overridden by setting [`crate::WASM_BUILD_TYPE_ENV`]. fn detect(target: RuntimeTarget, wasm_project: &Path) -> Self { - let (name, overriden) = if let Ok(name) = env::var(crate::WASM_BUILD_TYPE_ENV) { + let (name, overridden) = if let Ok(name) = env::var(crate::WASM_BUILD_TYPE_ENV) { (name, true) } else { // First go backwards to the beginning of the target directory. @@ -731,14 +731,14 @@ impl BuildConfiguration { (name, false) }; let outer_build_profile = Profile::iter().find(|p| p.directory() == name); - let blob_build_profile = match (outer_build_profile.clone(), overriden) { - // When not overriden by a env variable we default to using the `Release` profile + let blob_build_profile = match (outer_build_profile.clone(), overridden) { + // When not overridden by a env variable we default to using the `Release` profile // for the wasm build even when the main build uses the debug build. This // is because the `Debug` profile is too slow for normal development activities. (Some(Profile::Debug), false) => Profile::Release, - // For any other profile or when overriden we take it at face value. + // For any other profile or when overridden we take it at face value. (Some(profile), _) => profile, - // For non overriden unknown profiles we fall back to `Release`. + // For non overridden unknown profiles we fall back to `Release`. // This allows us to continue building when a custom profile is used for the // main builds cargo. When explicitly passing a profile via env variable we are // not doing a fallback. diff --git a/templates/minimal/node/Cargo.toml b/templates/minimal/node/Cargo.toml index 65aa1e20752..41d9708ea60 100644 --- a/templates/minimal/node/Cargo.toml +++ b/templates/minimal/node/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "minimal-template-node" -description = "A miniaml Substrate-based Substrate node, ready for hacking." +description = "A minimal Substrate-based Substrate node, ready for hacking." version = "0.0.0" license = "MIT-0" authors.workspace = true diff --git a/templates/minimal/runtime/Cargo.toml b/templates/minimal/runtime/Cargo.toml index 20ffb706eb4..a99a1e43f85 100644 --- a/templates/minimal/runtime/Cargo.toml +++ b/templates/minimal/runtime/Cargo.toml @@ -29,7 +29,7 @@ pallet-timestamp = { path = "../../../substrate/frame/timestamp", default-featur pallet-transaction-payment = { path = "../../../substrate/frame/transaction-payment", default-features = false } pallet-transaction-payment-rpc-runtime-api = { path = "../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } -# genesis builder that allows us to interacto with runtime genesis config +# genesis builder that allows us to interact with runtime genesis config sp-genesis-builder = { path = "../../../substrate/primitives/genesis-builder", default-features = false } # local pallet templates -- GitLab From fd79b3b08a9bd8f57cd6183b84fd34705e83a7a0 Mon Sep 17 00:00:00 2001 From: Andrei Eres Date: Tue, 26 Mar 2024 16:51:47 +0100 Subject: [PATCH 097/187] [subsystem-benchmarks] Save results to json (#3829) Here we add the ability to save subsystem benchmark results in JSON format to display them as graphs To draw graphs, CI team will use [github-action-benchmark](https://github.com/benchmark-action/github-action-benchmark). Since we are using custom benchmarks, we need to prepare [a specific data type](https://github.com/benchmark-action/github-action-benchmark?tab=readme-ov-file#examples): ``` [ { "name": "CPU Load", "unit": "Percent", "value": 50 } ] ``` Then we'll get graphs like this: ![example](https://raw.githubusercontent.com/rhysd/ss/master/github-action-benchmark/main.png) [A live page with graphs](https://benchmark-action.github.io/github-action-benchmark/dev/bench/) --------- Co-authored-by: ordian --- Cargo.lock | 1 + ...ilability-distribution-regression-bench.rs | 7 ++ .../availability-recovery-regression-bench.rs | 7 ++ polkadot/node/subsystem-bench/Cargo.toml | 1 + .../subsystem-bench/src/lib/environment.rs | 2 +- polkadot/node/subsystem-bench/src/lib/lib.rs | 1 + .../node/subsystem-bench/src/lib/usage.rs | 28 +++++++ .../node/subsystem-bench/src/lib/utils.rs | 75 +++++-------------- 8 files changed, 66 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 074b657e767..9e52bfcf9a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13644,6 +13644,7 @@ dependencies = [ "sc-service", "schnorrkel 0.11.4", "serde", + "serde_json", "serde_yaml", "sha1", "sp-application-crypto", diff --git a/polkadot/node/network/availability-distribution/benches/availability-distribution-regression-bench.rs b/polkadot/node/network/availability-distribution/benches/availability-distribution-regression-bench.rs index 019eb122208..c33674a8f2f 100644 --- a/polkadot/node/network/availability-distribution/benches/availability-distribution-regression-bench.rs +++ b/polkadot/node/network/availability-distribution/benches/availability-distribution-regression-bench.rs @@ -27,6 +27,7 @@ use polkadot_subsystem_bench::{ availability::{benchmark_availability_write, prepare_test, TestState}, configuration::TestConfiguration, usage::BenchmarkUsage, + utils::save_to_file, }; use std::io::Write; @@ -60,7 +61,13 @@ fn main() -> Result<(), String> { }) .collect(); println!("\rDone!{}", " ".repeat(BENCH_COUNT)); + let average_usage = BenchmarkUsage::average(&usages); + save_to_file( + "charts/availability-distribution-regression-bench.json", + average_usage.to_chart_json().map_err(|e| e.to_string())?, + ) + .map_err(|e| e.to_string())?; println!("{}", average_usage); // We expect no variance for received and sent diff --git a/polkadot/node/network/availability-recovery/benches/availability-recovery-regression-bench.rs b/polkadot/node/network/availability-recovery/benches/availability-recovery-regression-bench.rs index 5e8b81be82d..46a38516898 100644 --- a/polkadot/node/network/availability-recovery/benches/availability-recovery-regression-bench.rs +++ b/polkadot/node/network/availability-recovery/benches/availability-recovery-regression-bench.rs @@ -28,6 +28,7 @@ use polkadot_subsystem_bench::{ }, configuration::TestConfiguration, usage::BenchmarkUsage, + utils::save_to_file, }; use std::io::Write; @@ -58,7 +59,13 @@ fn main() -> Result<(), String> { }) .collect(); println!("\rDone!{}", " ".repeat(BENCH_COUNT)); + let average_usage = BenchmarkUsage::average(&usages); + save_to_file( + "charts/availability-recovery-regression-bench.json", + average_usage.to_chart_json().map_err(|e| e.to_string())?, + ) + .map_err(|e| e.to_string())?; println!("{}", average_usage); // We expect no variance for received and sent diff --git a/polkadot/node/subsystem-bench/Cargo.toml b/polkadot/node/subsystem-bench/Cargo.toml index 05907e428f9..b494f05180d 100644 --- a/polkadot/node/subsystem-bench/Cargo.toml +++ b/polkadot/node/subsystem-bench/Cargo.toml @@ -71,6 +71,7 @@ prometheus_endpoint = { package = "substrate-prometheus-endpoint", path = "../.. prometheus = { version = "0.13.0", default-features = false } serde = { workspace = true, default-features = true } serde_yaml = { workspace = true } +serde_json = { workspace = true } polkadot-node-core-approval-voting = { path = "../core/approval-voting" } polkadot-approval-distribution = { path = "../network/approval-distribution" } diff --git a/polkadot/node/subsystem-bench/src/lib/environment.rs b/polkadot/node/subsystem-bench/src/lib/environment.rs index 2d80d75a14a..42955d03022 100644 --- a/polkadot/node/subsystem-bench/src/lib/environment.rs +++ b/polkadot/node/subsystem-bench/src/lib/environment.rs @@ -404,7 +404,7 @@ impl TestEnvironment { let total_cpu = test_env_cpu_metrics.sum_by("substrate_tasks_polling_duration_sum"); usage.push(ResourceUsage { - resource_name: "Test environment".to_string(), + resource_name: "test-environment".to_string(), total: total_cpu, per_block: total_cpu / num_blocks, }); diff --git a/polkadot/node/subsystem-bench/src/lib/lib.rs b/polkadot/node/subsystem-bench/src/lib/lib.rs index d06f2822a89..ef2724abc98 100644 --- a/polkadot/node/subsystem-bench/src/lib/lib.rs +++ b/polkadot/node/subsystem-bench/src/lib/lib.rs @@ -26,3 +26,4 @@ pub(crate) mod keyring; pub(crate) mod mock; pub(crate) mod network; pub mod usage; +pub mod utils; diff --git a/polkadot/node/subsystem-bench/src/lib/usage.rs b/polkadot/node/subsystem-bench/src/lib/usage.rs index 7172969a8f9..59296746ec3 100644 --- a/polkadot/node/subsystem-bench/src/lib/usage.rs +++ b/polkadot/node/subsystem-bench/src/lib/usage.rs @@ -82,6 +82,27 @@ impl BenchmarkUsage { _ => None, } } + + // Prepares a json string for a graph representation + // See: https://github.com/benchmark-action/github-action-benchmark?tab=readme-ov-file#examples + pub fn to_chart_json(&self) -> color_eyre::eyre::Result { + let chart = self + .network_usage + .iter() + .map(|v| ChartItem { + name: v.resource_name.clone(), + unit: "KiB".to_string(), + value: v.per_block, + }) + .chain(self.cpu_usage.iter().map(|v| ChartItem { + name: v.resource_name.clone(), + unit: "seconds".to_string(), + value: v.per_block, + })) + .collect::>(); + + Ok(serde_json::to_string(&chart)?) + } } fn check_usage( @@ -151,3 +172,10 @@ impl ResourceUsage { } type ResourceUsageCheck<'a> = (&'a str, f64, f64); + +#[derive(Debug, Serialize)] +pub struct ChartItem { + pub name: String, + pub unit: String, + pub value: f64, +} diff --git a/polkadot/node/subsystem-bench/src/lib/utils.rs b/polkadot/node/subsystem-bench/src/lib/utils.rs index cd206d8f322..b3cd3a88b6c 100644 --- a/polkadot/node/subsystem-bench/src/lib/utils.rs +++ b/polkadot/node/subsystem-bench/src/lib/utils.rs @@ -16,61 +16,26 @@ //! Test utils -use crate::usage::BenchmarkUsage; -use std::io::{stdout, Write}; - -pub struct WarmUpOptions<'a> { - /// The maximum number of runs considered for warming up. - pub warm_up: usize, - /// The number of runs considered for benchmarking. - pub bench: usize, - /// The difference in CPU usage between runs considered as normal - pub precision: f64, - /// The subsystems whose CPU usage is checked during warm-up cycles - pub subsystems: &'a [&'a str], -} - -impl<'a> WarmUpOptions<'a> { - pub fn new(subsystems: &'a [&'a str]) -> Self { - Self { warm_up: 100, bench: 3, precision: 0.02, subsystems } - } -} - -pub fn warm_up_and_benchmark( - options: WarmUpOptions, - run: impl Fn() -> BenchmarkUsage, -) -> Result { - println!("Warming up..."); - let mut usages = Vec::with_capacity(options.bench); - - for n in 1..=options.warm_up { - let curr = run(); - if let Some(prev) = usages.last() { - let diffs = options - .subsystems - .iter() - .map(|&v| { - curr.cpu_usage_diff(prev, v) - .ok_or(format!("{} not found in benchmark {:?}", v, prev)) - }) - .collect::, String>>()?; - if !diffs.iter().all(|&v| v < options.precision) { - usages.clear(); - } - } - usages.push(curr); - print!("\r{}%", n * 100 / options.warm_up); - if usages.len() == options.bench { - println!("\rTook {} runs to warm up", n.saturating_sub(options.bench)); - break; - } - stdout().flush().unwrap(); - } - - if usages.len() != options.bench { - println!("Didn't warm up after {} runs", options.warm_up); - return Err("Can't warm up".to_string()) +use std::{fs::File, io::Write}; + +// Saves a given string to a file +pub fn save_to_file(path: &str, value: String) -> color_eyre::eyre::Result<()> { + let output = std::process::Command::new(env!("CARGO")) + .arg("locate-project") + .arg("--workspace") + .arg("--message-format=plain") + .output() + .unwrap() + .stdout; + let workspace_dir = std::path::Path::new(std::str::from_utf8(&output).unwrap().trim()) + .parent() + .unwrap(); + let path = workspace_dir.join(path); + if let Some(dir) = path.parent() { + std::fs::create_dir_all(dir)?; } + let mut file = File::create(path)?; + file.write_all(value.as_bytes())?; - Ok(BenchmarkUsage::average(&usages)) + Ok(()) } -- GitLab From 90234543f3039ce29bf0c9badfc6ec2037308eea Mon Sep 17 00:00:00 2001 From: Tsvetomir Dimitrov Date: Tue, 26 Mar 2024 17:54:24 +0200 Subject: [PATCH 098/187] Migrate parachain swaps to Coretime (#3714) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR notifies broker pallet for any parachain slot swaps performed on the relay chain. This is achieved by registering an `OnSwap` for the the `coretime` pallet. The hook sends XCM message to the broker chain and invokes a new extrinsic `swap_leases` which updates `Leases` storage item (which keeps the legacy parachain leases). I made two assumptions in this PR: 1. [`Leases`](https://github.com/paritytech/polkadot-sdk/blob/4987d7982461e2e5ffe219cdf71ec697284cea7c/substrate/frame/broker/src/lib.rs#L120) in `broker` pallet and [`Leases`](https://github.com/paritytech/polkadot-sdk/blob/4987d7982461e2e5ffe219cdf71ec697284cea7c/polkadot/runtime/common/src/slots/mod.rs#L118) in `slots` pallet are in sync. 2. `swap_leases` extrinsic from `broker` pallet can be triggered only by root or by the XCM message from the relay chain. If not - the extrinsic will generate an error and do nothing. As a side effect from the changes `OnSwap` trait is moved from runtime/common/traits.rs to runtime/parachains. Otherwise it is not accessible from `broker` pallet. Closes https://github.com/paritytech/polkadot-sdk/issues/3552 TODOs: - [x] Weights - [x] Tests --------- Co-authored-by: command-bot <> Co-authored-by: eskimor Co-authored-by: Bastian Köcher --- .../src/weights/pallet_broker.rs | 158 ++++---- .../src/weights/pallet_broker.rs | 160 ++++---- .../runtime/parachains/src/coretime/mod.rs | 20 + polkadot/runtime/rococo/src/lib.rs | 12 +- polkadot/runtime/westend/src/lib.rs | 12 +- prdoc/pr_3714.prdoc | 10 + substrate/frame/broker/src/benchmarking.rs | 17 + .../frame/broker/src/dispatchable_impls.rs | 18 + substrate/frame/broker/src/lib.rs | 8 + substrate/frame/broker/src/weights.rs | 368 ++++++++++-------- 10 files changed, 461 insertions(+), 322 deletions(-) create mode 100644 prdoc/pr_3714.prdoc diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_broker.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_broker.rs index 2d30ddc612c..89b1c4c8663 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_broker.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_broker.rs @@ -16,26 +16,24 @@ //! Autogenerated weights for `pallet_broker` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2024-01-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-03-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-j8vvqcjr-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot-parachain +// target/production/polkadot-parachain // benchmark // pallet -// --chain=coretime-rococo-dev -// --wasm-execution=compiled -// --pallet=pallet_broker -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* // --steps=50 // --repeat=20 -// --json +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_broker +// --chain=coretime-rococo-dev // --header=./cumulus/file_header.txt // --output=./cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/ @@ -56,8 +54,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_462_000 picoseconds. - Weight::from_parts(2_552_000, 0) + // Minimum execution time: 1_918_000 picoseconds. + Weight::from_parts(2_092_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -67,8 +65,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `10888` // Estimated: `13506` - // Minimum execution time: 25_494_000 picoseconds. - Weight::from_parts(26_063_000, 0) + // Minimum execution time: 21_943_000 picoseconds. + Weight::from_parts(22_570_000, 0) .saturating_add(Weight::from_parts(0, 13506)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -79,8 +77,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `12090` // Estimated: `13506` - // Minimum execution time: 22_299_000 picoseconds. - Weight::from_parts(22_911_000, 0) + // Minimum execution time: 20_923_000 picoseconds. + Weight::from_parts(21_354_000, 0) .saturating_add(Weight::from_parts(0, 13506)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -95,8 +93,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `466` // Estimated: `1951` - // Minimum execution time: 11_590_000 picoseconds. - Weight::from_parts(12_007_000, 0) + // Minimum execution time: 10_687_000 picoseconds. + Weight::from_parts(11_409_000, 0) .saturating_add(Weight::from_parts(0, 1951)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -124,11 +122,11 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `12567` // Estimated: `14052` - // Minimum execution time: 120_928_000 picoseconds. - Weight::from_parts(124_947_252, 0) + // Minimum execution time: 111_288_000 picoseconds. + Weight::from_parts(117_804_282, 0) .saturating_add(Weight::from_parts(0, 14052)) - // Standard Error: 435 - .saturating_add(Weight::from_parts(1_246, 0).saturating_mul(n.into())) + // Standard Error: 391 + .saturating_add(Weight::from_parts(1_243, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(66)) } @@ -144,8 +142,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `316` // Estimated: `3593` - // Minimum execution time: 32_826_000 picoseconds. - Weight::from_parts(33_889_000, 0) + // Minimum execution time: 33_006_000 picoseconds. + Weight::from_parts(34_256_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -166,8 +164,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `434` // Estimated: `4698` - // Minimum execution time: 57_362_000 picoseconds. - Weight::from_parts(58_994_000, 0) + // Minimum execution time: 61_473_000 picoseconds. + Weight::from_parts(66_476_000, 0) .saturating_add(Weight::from_parts(0, 4698)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) @@ -178,8 +176,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `357` // Estimated: `3550` - // Minimum execution time: 13_982_000 picoseconds. - Weight::from_parts(14_447_000, 0) + // Minimum execution time: 13_771_000 picoseconds. + Weight::from_parts(14_374_000, 0) .saturating_add(Weight::from_parts(0, 3550)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -190,8 +188,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `357` // Estimated: `3550` - // Minimum execution time: 15_070_000 picoseconds. - Weight::from_parts(15_735_000, 0) + // Minimum execution time: 15_162_000 picoseconds. + Weight::from_parts(15_742_000, 0) .saturating_add(Weight::from_parts(0, 3550)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -202,8 +200,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `357` // Estimated: `3550` - // Minimum execution time: 16_527_000 picoseconds. - Weight::from_parts(16_894_000, 0) + // Minimum execution time: 16_196_000 picoseconds. + Weight::from_parts(16_796_000, 0) .saturating_add(Weight::from_parts(0, 3550)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(3)) @@ -220,8 +218,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `936` // Estimated: `4681` - // Minimum execution time: 25_493_000 picoseconds. - Weight::from_parts(26_091_000, 0) + // Minimum execution time: 25_653_000 picoseconds. + Weight::from_parts(27_006_000, 0) .saturating_add(Weight::from_parts(0, 4681)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -240,8 +238,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1002` // Estimated: `5996` - // Minimum execution time: 31_498_000 picoseconds. - Weight::from_parts(32_560_000, 0) + // Minimum execution time: 31_114_000 picoseconds. + Weight::from_parts(32_235_000, 0) .saturating_add(Weight::from_parts(0, 5996)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(5)) @@ -257,11 +255,11 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `652` // Estimated: `6196 + m * (2520 ±0)` - // Minimum execution time: 57_183_000 picoseconds. - Weight::from_parts(58_024_898, 0) + // Minimum execution time: 57_280_000 picoseconds. + Weight::from_parts(58_127_480, 0) .saturating_add(Weight::from_parts(0, 6196)) - // Standard Error: 35_831 - .saturating_add(Weight::from_parts(1_384_446, 0).saturating_mul(m.into())) + // Standard Error: 41_670 + .saturating_add(Weight::from_parts(1_203_066, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(T::DbWeight::get().writes(5)) @@ -283,8 +281,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `215` // Estimated: `3680` - // Minimum execution time: 59_762_000 picoseconds. - Weight::from_parts(61_114_000, 0) + // Minimum execution time: 59_968_000 picoseconds. + Weight::from_parts(62_315_000, 0) .saturating_add(Weight::from_parts(0, 3680)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) @@ -297,8 +295,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `465` // Estimated: `3550` - // Minimum execution time: 41_473_000 picoseconds. - Weight::from_parts(44_155_000, 0) + // Minimum execution time: 50_887_000 picoseconds. + Weight::from_parts(57_366_000, 0) .saturating_add(Weight::from_parts(0, 3550)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -313,8 +311,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `463` // Estimated: `3533` - // Minimum execution time: 56_672_000 picoseconds. - Weight::from_parts(58_086_000, 0) + // Minimum execution time: 84_472_000 picoseconds. + Weight::from_parts(96_536_000, 0) .saturating_add(Weight::from_parts(0, 3533)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -331,8 +329,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `857` // Estimated: `3593` - // Minimum execution time: 64_460_000 picoseconds. - Weight::from_parts(65_894_000, 0) + // Minimum execution time: 96_371_000 picoseconds. + Weight::from_parts(104_659_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) @@ -345,8 +343,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `957` // Estimated: `4698` - // Minimum execution time: 37_447_000 picoseconds. - Weight::from_parts(42_318_000, 0) + // Minimum execution time: 51_741_000 picoseconds. + Weight::from_parts(54_461_000, 0) .saturating_add(Weight::from_parts(0, 4698)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -366,8 +364,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 21_219_000 picoseconds. - Weight::from_parts(22_084_648, 0) + // Minimum execution time: 19_901_000 picoseconds. + Weight::from_parts(21_028_116, 0) .saturating_add(Weight::from_parts(0, 3539)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -379,11 +377,11 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `266` // Estimated: `1487` - // Minimum execution time: 5_792_000 picoseconds. - Weight::from_parts(6_358_588, 0) + // Minimum execution time: 5_987_000 picoseconds. + Weight::from_parts(6_412_478, 0) .saturating_add(Weight::from_parts(0, 1487)) - // Standard Error: 20 - .saturating_add(Weight::from_parts(26, 0).saturating_mul(n.into())) + // Standard Error: 16 + .saturating_add(Weight::from_parts(47, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -397,8 +395,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `447` // Estimated: `6196` - // Minimum execution time: 38_690_000 picoseconds. - Weight::from_parts(39_706_000, 0) + // Minimum execution time: 38_623_000 picoseconds. + Weight::from_parts(39_773_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -414,15 +412,13 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Storage: `Broker::Workplan` (r:0 w:60) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. - fn rotate_sale(n: u32, ) -> Weight { + fn rotate_sale(_n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `12514` // Estimated: `13506` - // Minimum execution time: 93_531_000 picoseconds. - Weight::from_parts(95_836_318, 0) + // Minimum execution time: 97_074_000 picoseconds. + Weight::from_parts(101_247_740, 0) .saturating_add(Weight::from_parts(0, 13506)) - // Standard Error: 113 - .saturating_add(Weight::from_parts(329, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(65)) } @@ -434,8 +430,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3493` - // Minimum execution time: 6_506_000 picoseconds. - Weight::from_parts(6_783_000, 0) + // Minimum execution time: 6_317_000 picoseconds. + Weight::from_parts(6_521_000, 0) .saturating_add(Weight::from_parts(0, 3493)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -458,8 +454,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1321` // Estimated: `4786` - // Minimum execution time: 31_927_000 picoseconds. - Weight::from_parts(32_748_000, 0) + // Minimum execution time: 32_575_000 picoseconds. + Weight::from_parts(33_299_000, 0) .saturating_add(Weight::from_parts(0, 4786)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -478,8 +474,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 15_682_000 picoseconds. - Weight::from_parts(16_012_000, 0) + // Minimum execution time: 15_256_000 picoseconds. + Weight::from_parts(15_927_000, 0) .saturating_add(Weight::from_parts(0, 3539)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -490,8 +486,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_147_000 picoseconds. - Weight::from_parts(2_281_000, 0) + // Minimum execution time: 1_783_000 picoseconds. + Weight::from_parts(1_904_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -509,10 +505,22 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `398` // Estimated: `3863` - // Minimum execution time: 12_015_000 picoseconds. - Weight::from_parts(12_619_000, 0) + // Minimum execution time: 12_307_000 picoseconds. + Weight::from_parts(12_967_000, 0) .saturating_add(Weight::from_parts(0, 3863)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } + /// Storage: `Broker::Leases` (r:1 w:1) + /// Proof: `Broker::Leases` (`max_values`: Some(1), `max_size`: Some(401), added: 896, mode: `MaxEncodedLen`) + fn swap_leases() -> Weight { + // Proof Size summary in bytes: + // Measured: `470` + // Estimated: `1886` + // Minimum execution time: 6_597_000 picoseconds. + Weight::from_parts(6_969_000, 0) + .saturating_add(Weight::from_parts(0, 1886)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_broker.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_broker.rs index 8727b9633b1..13d5fcf3898 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_broker.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_broker.rs @@ -17,25 +17,23 @@ //! Autogenerated weights for `pallet_broker` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-03-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-westend-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot-parachain +// target/production/polkadot-parachain // benchmark // pallet -// --chain=coretime-westend-dev -// --wasm-execution=compiled -// --pallet=pallet_broker -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* // --steps=50 // --repeat=20 -// --json +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_broker +// --chain=coretime-westend-dev // --header=./cumulus/file_header.txt // --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/ @@ -56,8 +54,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_944_000 picoseconds. - Weight::from_parts(2_045_000, 0) + // Minimum execution time: 1_897_000 picoseconds. + Weight::from_parts(2_053_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -67,8 +65,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `10888` // Estimated: `13506` - // Minimum execution time: 21_158_000 picoseconds. - Weight::from_parts(21_572_000, 0) + // Minimum execution time: 22_550_000 picoseconds. + Weight::from_parts(22_871_000, 0) .saturating_add(Weight::from_parts(0, 13506)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -79,8 +77,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `12090` // Estimated: `13506` - // Minimum execution time: 20_497_000 picoseconds. - Weight::from_parts(20_995_000, 0) + // Minimum execution time: 21_170_000 picoseconds. + Weight::from_parts(21_645_000, 0) .saturating_add(Weight::from_parts(0, 13506)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -95,8 +93,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `146` // Estimated: `1631` - // Minimum execution time: 10_280_000 picoseconds. - Weight::from_parts(10_686_000, 0) + // Minimum execution time: 10_494_000 picoseconds. + Weight::from_parts(10_942_000, 0) .saturating_add(Weight::from_parts(0, 1631)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -120,15 +118,13 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Storage: `Broker::Workplan` (r:0 w:20) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. - fn start_sales(n: u32, ) -> Weight { + fn start_sales(_n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `12247` // Estimated: `13732` - // Minimum execution time: 61_020_000 picoseconds. - Weight::from_parts(63_240_622, 0) + // Minimum execution time: 61_014_000 picoseconds. + Weight::from_parts(63_267_651, 0) .saturating_add(Weight::from_parts(0, 13732)) - // Standard Error: 102 - .saturating_add(Weight::from_parts(255, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(26)) } @@ -144,8 +140,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `316` // Estimated: `3593` - // Minimum execution time: 30_627_000 picoseconds. - Weight::from_parts(31_648_000, 0) + // Minimum execution time: 30_931_000 picoseconds. + Weight::from_parts(31_941_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -166,8 +162,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `434` // Estimated: `4698` - // Minimum execution time: 57_701_000 picoseconds. - Weight::from_parts(59_825_000, 0) + // Minimum execution time: 57_466_000 picoseconds. + Weight::from_parts(65_042_000, 0) .saturating_add(Weight::from_parts(0, 4698)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) @@ -178,8 +174,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `357` // Estimated: `3550` - // Minimum execution time: 12_898_000 picoseconds. - Weight::from_parts(13_506_000, 0) + // Minimum execution time: 12_799_000 picoseconds. + Weight::from_parts(13_401_000, 0) .saturating_add(Weight::from_parts(0, 3550)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -190,8 +186,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `357` // Estimated: `3550` - // Minimum execution time: 14_284_000 picoseconds. - Weight::from_parts(14_791_000, 0) + // Minimum execution time: 14_107_000 picoseconds. + Weight::from_parts(14_630_000, 0) .saturating_add(Weight::from_parts(0, 3550)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -202,8 +198,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `357` // Estimated: `3550` - // Minimum execution time: 15_570_000 picoseconds. - Weight::from_parts(16_158_000, 0) + // Minimum execution time: 15_254_000 picoseconds. + Weight::from_parts(16_062_000, 0) .saturating_add(Weight::from_parts(0, 3550)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(3)) @@ -220,8 +216,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `735` // Estimated: `4681` - // Minimum execution time: 23_329_000 picoseconds. - Weight::from_parts(24_196_000, 0) + // Minimum execution time: 23_557_000 picoseconds. + Weight::from_parts(24_382_000, 0) .saturating_add(Weight::from_parts(0, 4681)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -240,8 +236,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `801` // Estimated: `5996` - // Minimum execution time: 29_288_000 picoseconds. - Weight::from_parts(30_066_000, 0) + // Minimum execution time: 29_371_000 picoseconds. + Weight::from_parts(30_200_000, 0) .saturating_add(Weight::from_parts(0, 5996)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(5)) @@ -257,11 +253,11 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `652` // Estimated: `6196 + m * (2520 ±0)` - // Minimum execution time: 54_833_000 picoseconds. - Weight::from_parts(55_577_423, 0) + // Minimum execution time: 54_331_000 picoseconds. + Weight::from_parts(55_322_165, 0) .saturating_add(Weight::from_parts(0, 6196)) - // Standard Error: 35_105 - .saturating_add(Weight::from_parts(1_267_911, 0).saturating_mul(m.into())) + // Standard Error: 35_225 + .saturating_add(Weight::from_parts(1_099_614, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(T::DbWeight::get().writes(5)) @@ -283,8 +279,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `215` // Estimated: `3680` - // Minimum execution time: 55_289_000 picoseconds. - Weight::from_parts(56_552_000, 0) + // Minimum execution time: 53_789_000 picoseconds. + Weight::from_parts(55_439_000, 0) .saturating_add(Weight::from_parts(0, 3680)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) @@ -297,8 +293,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `465` // Estimated: `3550` - // Minimum execution time: 39_736_000 picoseconds. - Weight::from_parts(41_346_000, 0) + // Minimum execution time: 43_941_000 picoseconds. + Weight::from_parts(49_776_000, 0) .saturating_add(Weight::from_parts(0, 3550)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -313,8 +309,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `463` // Estimated: `3533` - // Minimum execution time: 57_319_000 picoseconds. - Weight::from_parts(60_204_000, 0) + // Minimum execution time: 64_917_000 picoseconds. + Weight::from_parts(70_403_000, 0) .saturating_add(Weight::from_parts(0, 3533)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -331,8 +327,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `857` // Estimated: `3593` - // Minimum execution time: 85_216_000 picoseconds. - Weight::from_parts(91_144_000, 0) + // Minimum execution time: 72_633_000 picoseconds. + Weight::from_parts(79_305_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) @@ -345,8 +341,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `556` // Estimated: `4698` - // Minimum execution time: 32_331_000 picoseconds. - Weight::from_parts(39_877_000, 0) + // Minimum execution time: 36_643_000 picoseconds. + Weight::from_parts(48_218_000, 0) .saturating_add(Weight::from_parts(0, 4698)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -362,28 +358,28 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `n` is `[0, 1000]`. - fn request_core_count(n: u32, ) -> Weight { + fn request_core_count(_n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 18_128_000 picoseconds. - Weight::from_parts(19_061_234, 0) + // Minimum execution time: 17_617_000 picoseconds. + Weight::from_parts(18_904_788, 0) .saturating_add(Weight::from_parts(0, 3539)) - // Standard Error: 48 - .saturating_add(Weight::from_parts(141, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Broker::CoreCountInbox` (r:1 w:1) /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. - fn process_core_count(_n: u32, ) -> Weight { + fn process_core_count(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `266` // Estimated: `1487` - // Minimum execution time: 5_368_000 picoseconds. - Weight::from_parts(5_837_005, 0) + // Minimum execution time: 5_575_000 picoseconds. + Weight::from_parts(5_887_598, 0) .saturating_add(Weight::from_parts(0, 1487)) + // Standard Error: 16 + .saturating_add(Weight::from_parts(41, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -397,8 +393,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `447` // Estimated: `6196` - // Minimum execution time: 36_047_000 picoseconds. - Weight::from_parts(37_101_000, 0) + // Minimum execution time: 36_415_000 picoseconds. + Weight::from_parts(37_588_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -414,13 +410,15 @@ impl pallet_broker::WeightInfo for WeightInfo { /// Storage: `Broker::Workplan` (r:0 w:20) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. - fn rotate_sale(_n: u32, ) -> Weight { + fn rotate_sale(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `12194` // Estimated: `13506` - // Minimum execution time: 48_158_000 picoseconds. - Weight::from_parts(49_891_920, 0) + // Minimum execution time: 48_362_000 picoseconds. + Weight::from_parts(49_616_106, 0) .saturating_add(Weight::from_parts(0, 13506)) + // Standard Error: 61 + .saturating_add(Weight::from_parts(59, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(25)) } @@ -432,8 +430,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3493` - // Minimum execution time: 5_911_000 picoseconds. - Weight::from_parts(6_173_000, 0) + // Minimum execution time: 6_148_000 picoseconds. + Weight::from_parts(6_374_000, 0) .saturating_add(Weight::from_parts(0, 3493)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -456,8 +454,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1321` // Estimated: `4786` - // Minimum execution time: 30_140_000 picoseconds. - Weight::from_parts(30_912_000, 0) + // Minimum execution time: 30_267_000 picoseconds. + Weight::from_parts(30_825_000, 0) .saturating_add(Weight::from_parts(0, 4786)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -476,8 +474,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 13_684_000 picoseconds. - Weight::from_parts(14_252_000, 0) + // Minimum execution time: 13_491_000 picoseconds. + Weight::from_parts(13_949_000, 0) .saturating_add(Weight::from_parts(0, 3539)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -488,8 +486,8 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_718_000 picoseconds. - Weight::from_parts(1_843_000, 0) + // Minimum execution time: 1_711_000 picoseconds. + Weight::from_parts(1_913_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -507,10 +505,22 @@ impl pallet_broker::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `398` // Estimated: `3863` - // Minimum execution time: 11_771_000 picoseconds. - Weight::from_parts(12_120_000, 0) + // Minimum execution time: 12_035_000 picoseconds. + Weight::from_parts(12_383_000, 0) .saturating_add(Weight::from_parts(0, 3863)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } + /// Storage: `Broker::Leases` (r:1 w:1) + /// Proof: `Broker::Leases` (`max_values`: Some(1), `max_size`: Some(81), added: 576, mode: `MaxEncodedLen`) + fn swap_leases() -> Weight { + // Proof Size summary in bytes: + // Measured: `150` + // Estimated: `1566` + // Minimum execution time: 6_142_000 picoseconds. + Weight::from_parts(6_538_000, 0) + .saturating_add(Weight::from_parts(0, 1566)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } diff --git a/polkadot/runtime/parachains/src/coretime/mod.rs b/polkadot/runtime/parachains/src/coretime/mod.rs index eb9646d7e86..9095cd90ae0 100644 --- a/polkadot/runtime/parachains/src/coretime/mod.rs +++ b/polkadot/runtime/parachains/src/coretime/mod.rs @@ -83,6 +83,8 @@ enum CoretimeCalls { SetLease(pallet_broker::TaskId, pallet_broker::Timeslice), #[codec(index = 19)] NotifyCoreCount(u16), + #[codec(index = 99)] + SwapLeases(ParaId, ParaId), } #[frame_support::pallet] @@ -233,6 +235,24 @@ impl Pallet { } } } + + // Handle legacy swaps in coretime. Notifies broker parachain that a lease swap has occurred via + // XCM message. This function is meant to be used in an implementation of `OnSwap` trait. + pub fn on_legacy_lease_swap(one: ParaId, other: ParaId) { + let message = Xcm(vec![ + Instruction::UnpaidExecution { + weight_limit: WeightLimit::Unlimited, + check_origin: None, + }, + mk_coretime_call(crate::coretime::CoretimeCalls::SwapLeases(one, other)), + ]); + if let Err(err) = send_xcm::( + Location::new(0, [Junction::Parachain(T::BrokerId::get())]), + message, + ) { + log::error!("Sending `SwapLeases` to coretime chain failed: {:?}", err); + } + } } impl OnNewSession> for Pallet { diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 90824a2f6f0..b26317490cd 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -38,7 +38,7 @@ use runtime_common::{ LocatableAssetConverter, ToAuthor, VersionedLocatableAsset, VersionedLocationConverter, }, paras_registrar, paras_sudo_wrapper, prod_or_fast, slots, - traits::Leaser, + traits::{Leaser, OnSwap}, BlockHashCount, BlockLength, SlowAdjustingFeeUpdate, }; use scale_info::TypeInfo; @@ -1078,7 +1078,7 @@ impl paras_registrar::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeEvent = RuntimeEvent; type Currency = Balances; - type OnSwap = (Crowdloan, Slots); + type OnSwap = (Crowdloan, Slots, SwapLeases); type ParaDeposit = ParaDeposit; type DataDepositPerByte = DataDepositPerByte; type WeightInfo = weights::runtime_common_paras_registrar::WeightInfo; @@ -1306,6 +1306,14 @@ impl pallet_asset_rate::Config for Runtime { type BenchmarkHelper = runtime_common::impls::benchmarks::AssetRateArguments; } +// Notify `coretime` pallet when a lease swap occurs +pub struct SwapLeases; +impl OnSwap for SwapLeases { + fn on_swap(one: ParaId, other: ParaId) { + coretime::Pallet::::on_legacy_lease_swap(one, other); + } +} + construct_runtime! { pub enum Runtime { diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 664044b713e..12e6174ab6c 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -62,7 +62,7 @@ use runtime_common::{ LocatableAssetConverter, ToAuthor, VersionedLocatableAsset, VersionedLocationConverter, }, paras_registrar, paras_sudo_wrapper, prod_or_fast, slots, - traits::Leaser, + traits::{Leaser, OnSwap}, BalanceToU256, BlockHashCount, BlockLength, CurrencyToVote, SlowAdjustingFeeUpdate, U256ToBalance, }; @@ -1302,7 +1302,7 @@ impl paras_registrar::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeEvent = RuntimeEvent; type Currency = Balances; - type OnSwap = (Crowdloan, Slots); + type OnSwap = (Crowdloan, Slots, SwapLeases); type ParaDeposit = ParaDeposit; type DataDepositPerByte = RegistrarDataDepositPerByte; type WeightInfo = weights::runtime_common_paras_registrar::WeightInfo; @@ -1414,6 +1414,14 @@ impl pallet_asset_rate::Config for Runtime { type BenchmarkHelper = runtime_common::impls::benchmarks::AssetRateArguments; } +// Notify `coretime` pallet when a lease swap occurs +pub struct SwapLeases; +impl OnSwap for SwapLeases { + fn on_swap(one: ParaId, other: ParaId) { + coretime::Pallet::::on_legacy_lease_swap(one, other); + } +} + #[frame_support::runtime(legacy_ordering)] mod runtime { #[runtime::runtime] diff --git a/prdoc/pr_3714.prdoc b/prdoc/pr_3714.prdoc new file mode 100644 index 00000000000..e276d0d2d37 --- /dev/null +++ b/prdoc/pr_3714.prdoc @@ -0,0 +1,10 @@ +title: Handle legacy lease swaps on coretime + +doc: + - audience: Runtime Dev + description: | + When a `registar::swap` extrinsic is executed it swaps two leases on the relay chain but the + broker chain never knows about this swap. This change notifies the broker chain via a XCM + message for a swap so that it can update its state. +crates: + - name: pallet-broker diff --git a/substrate/frame/broker/src/benchmarking.rs b/substrate/frame/broker/src/benchmarking.rs index 70f488e998c..98ac074ca91 100644 --- a/substrate/frame/broker/src/benchmarking.rs +++ b/substrate/frame/broker/src/benchmarking.rs @@ -918,6 +918,23 @@ mod benches { Ok(()) } + #[benchmark] + fn swap_leases() -> Result<(), BenchmarkError> { + let admin_origin = + T::AdminOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + + // Add two leases in `Leases` + let n = (T::MaxLeasedCores::get() / 2) as usize; + let mut leases = vec![LeaseRecordItem { task: 1, until: 10u32.into() }; n]; + leases.extend(vec![LeaseRecordItem { task: 2, until: 20u32.into() }; n]); + Leases::::put(BoundedVec::try_from(leases).unwrap()); + + #[extrinsic_call] + _(admin_origin as T::RuntimeOrigin, 1, 2); + + Ok(()) + } + // Implements a test for each benchmark. Execute with: // `cargo test -p pallet-broker --features runtime-benchmarks`. impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); diff --git a/substrate/frame/broker/src/dispatchable_impls.rs b/substrate/frame/broker/src/dispatchable_impls.rs index f2451013251..74cda9c4f4c 100644 --- a/substrate/frame/broker/src/dispatchable_impls.rs +++ b/substrate/frame/broker/src/dispatchable_impls.rs @@ -437,4 +437,22 @@ impl Pallet { Self::deposit_event(Event::AllowedRenewalDropped { core, when }); Ok(()) } + + pub(crate) fn do_swap_leases(id: TaskId, other: TaskId) -> DispatchResult { + let mut id_leases_count = 0; + let mut other_leases_count = 0; + Leases::::mutate(|leases| { + leases.iter_mut().for_each(|lease| { + if lease.task == id { + lease.task = other; + id_leases_count += 1; + } else if lease.task == other { + lease.task = id; + other_leases_count += 1; + } + }) + }); + + Ok(()) + } } diff --git a/substrate/frame/broker/src/lib.rs b/substrate/frame/broker/src/lib.rs index f1b49a73a52..b9b5e309ca9 100644 --- a/substrate/frame/broker/src/lib.rs +++ b/substrate/frame/broker/src/lib.rs @@ -786,5 +786,13 @@ pub mod pallet { Self::do_notify_core_count(core_count)?; Ok(()) } + + #[pallet::call_index(99)] + #[pallet::weight(T::WeightInfo::swap_leases())] + pub fn swap_leases(origin: OriginFor, id: TaskId, other: TaskId) -> DispatchResult { + T::AdminOrigin::ensure_origin_or_root(origin)?; + Self::do_swap_leases(id, other)?; + Ok(()) + } } } diff --git a/substrate/frame/broker/src/weights.rs b/substrate/frame/broker/src/weights.rs index a8f50eeee6e..a8b9fb598b8 100644 --- a/substrate/frame/broker/src/weights.rs +++ b/substrate/frame/broker/src/weights.rs @@ -17,10 +17,10 @@ //! Autogenerated weights for `pallet_broker` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-09-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-03-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-pzhd7p6z-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -76,6 +76,7 @@ pub trait WeightInfo { fn request_revenue_info_at() -> Weight; fn notify_core_count() -> Weight; fn do_tick_base() -> Weight; + fn swap_leases() -> Weight; } /// Weights for `pallet_broker` using the Substrate node and recommended hardware. @@ -87,8 +88,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_040_000 picoseconds. - Weight::from_parts(3_344_000, 0) + // Minimum execution time: 2_865_000 picoseconds. + Weight::from_parts(3_061_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Broker::Reservations` (r:1 w:1) @@ -97,8 +98,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `5016` // Estimated: `7496` - // Minimum execution time: 21_259_000 picoseconds. - Weight::from_parts(22_110_000, 7496) + // Minimum execution time: 18_431_000 picoseconds. + Weight::from_parts(19_558_000, 7496) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -108,8 +109,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `6218` // Estimated: `7496` - // Minimum execution time: 20_330_000 picoseconds. - Weight::from_parts(20_826_000, 7496) + // Minimum execution time: 17_724_000 picoseconds. + Weight::from_parts(18_688_000, 7496) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -119,8 +120,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `239` // Estimated: `1526` - // Minimum execution time: 13_411_000 picoseconds. - Weight::from_parts(13_960_000, 1526) + // Minimum execution time: 10_513_000 picoseconds. + Weight::from_parts(11_138_000, 1526) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -139,14 +140,12 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Broker::Workplan` (r:0 w:10) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. - fn start_sales(n: u32, ) -> Weight { + fn start_sales(_n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `6330` // Estimated: `8499` - // Minimum execution time: 57_770_000 picoseconds. - Weight::from_parts(61_047_512, 8499) - // Standard Error: 165 - .saturating_add(Weight::from_parts(3, 0).saturating_mul(n.into())) + // Minimum execution time: 50_864_000 picoseconds. + Weight::from_parts(54_000_280, 8499) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(16_u64)) } @@ -162,10 +161,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) fn purchase() -> Weight { // Proof Size summary in bytes: - // Measured: `568` - // Estimated: `2053` - // Minimum execution time: 51_196_000 picoseconds. - Weight::from_parts(52_382_000, 2053) + // Measured: `635` + // Estimated: `2120` + // Minimum execution time: 43_630_000 picoseconds. + Weight::from_parts(44_622_000, 2120) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -185,10 +184,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) fn renew() -> Weight { // Proof Size summary in bytes: - // Measured: `686` + // Measured: `753` // Estimated: `4698` - // Minimum execution time: 71_636_000 picoseconds. - Weight::from_parts(73_679_000, 4698) + // Minimum execution time: 62_453_000 picoseconds. + Weight::from_parts(63_882_000, 4698) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -198,8 +197,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3550` - // Minimum execution time: 19_182_000 picoseconds. - Weight::from_parts(19_775_000, 3550) + // Minimum execution time: 17_237_000 picoseconds. + Weight::from_parts(17_757_000, 3550) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -209,21 +208,21 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3550` - // Minimum execution time: 20_688_000 picoseconds. - Weight::from_parts(21_557_000, 3550) + // Minimum execution time: 18_504_000 picoseconds. + Weight::from_parts(19_273_000, 3550) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - /// Storage: `Broker::Regions` (r:1 w:2) + /// Storage: `Broker::Regions` (r:1 w:3) /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) fn interlace() -> Weight { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3550` - // Minimum execution time: 21_190_000 picoseconds. - Weight::from_parts(22_215_000, 3550) + // Minimum execution time: 20_477_000 picoseconds. + Weight::from_parts(21_328_000, 3550) .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Broker::Configuration` (r:1 w:0) /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) @@ -237,8 +236,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `740` // Estimated: `4681` - // Minimum execution time: 34_591_000 picoseconds. - Weight::from_parts(36_227_000, 4681) + // Minimum execution time: 31_815_000 picoseconds. + Weight::from_parts(32_700_000, 4681) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -256,8 +255,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `775` // Estimated: `5996` - // Minimum execution time: 40_346_000 picoseconds. - Weight::from_parts(41_951_000, 5996) + // Minimum execution time: 38_313_000 picoseconds. + Weight::from_parts(38_985_000, 5996) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -272,10 +271,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `859` // Estimated: `6196 + m * (2520 ±0)` - // Minimum execution time: 75_734_000 picoseconds. - Weight::from_parts(78_168_395, 6196) - // Standard Error: 63_180 - .saturating_add(Weight::from_parts(1_076_259, 0).saturating_mul(m.into())) + // Minimum execution time: 70_170_000 picoseconds. + Weight::from_parts(71_245_388, 6196) + // Standard Error: 54_382 + .saturating_add(Weight::from_parts(1_488_794, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(T::DbWeight::get().writes(5_u64)) @@ -287,8 +286,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 46_383_000 picoseconds. - Weight::from_parts(47_405_000, 3593) + // Minimum execution time: 43_414_000 picoseconds. + Weight::from_parts(44_475_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -300,8 +299,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `603` // Estimated: `3550` - // Minimum execution time: 30_994_000 picoseconds. - Weight::from_parts(31_979_000, 3550) + // Minimum execution time: 31_327_000 picoseconds. + Weight::from_parts(32_050_000, 3550) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -315,8 +314,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `601` // Estimated: `3533` - // Minimum execution time: 37_584_000 picoseconds. - Weight::from_parts(44_010_000, 3533) + // Minimum execution time: 41_315_000 picoseconds. + Weight::from_parts(42_421_000, 3533) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -330,10 +329,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn drop_history() -> Weight { // Proof Size summary in bytes: - // Measured: `830` + // Measured: `995` // Estimated: `3593` - // Minimum execution time: 45_266_000 picoseconds. - Weight::from_parts(48_000_000, 3593) + // Minimum execution time: 49_707_000 picoseconds. + Weight::from_parts(51_516_000, 3593) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -343,10 +342,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Broker::AllowedRenewals` (`max_values`: None, `max_size`: Some(1233), added: 3708, mode: `MaxEncodedLen`) fn drop_renewal() -> Weight { // Proof Size summary in bytes: - // Measured: `525` + // Measured: `661` // Estimated: `4698` - // Minimum execution time: 25_365_000 picoseconds. - Weight::from_parts(26_920_000, 4698) + // Minimum execution time: 26_207_000 picoseconds. + Weight::from_parts(27_227_000, 4698) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -355,22 +354,22 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_519_000 picoseconds. - Weight::from_parts(7_098_698, 0) - // Standard Error: 20 - .saturating_add(Weight::from_parts(8, 0).saturating_mul(n.into())) + // Minimum execution time: 4_670_000 picoseconds. + Weight::from_parts(5_170_450, 0) + // Standard Error: 16 + .saturating_add(Weight::from_parts(37, 0).saturating_mul(n.into())) } - /// Storage: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) - /// Proof: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) + /// Storage: `Broker::CoreCountInbox` (r:1 w:1) + /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. fn process_core_count(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `98` - // Estimated: `3563` - // Minimum execution time: 7_608_000 picoseconds. - Weight::from_parts(8_157_815, 3563) - // Standard Error: 26 - .saturating_add(Weight::from_parts(48, 0).saturating_mul(n.into())) + // Measured: `404` + // Estimated: `1487` + // Minimum execution time: 6_916_000 picoseconds. + Weight::from_parts(7_485_053, 1487) + // Standard Error: 23 + .saturating_add(Weight::from_parts(30, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -386,10 +385,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn process_revenue() -> Weight { // Proof Size summary in bytes: - // Measured: `905` - // Estimated: `4370` - // Minimum execution time: 59_993_000 picoseconds. - Weight::from_parts(61_752_000, 4370) + // Measured: `972` + // Estimated: `4437` + // Minimum execution time: 50_987_000 picoseconds. + Weight::from_parts(52_303_000, 4437) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -408,10 +407,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `6281` // Estimated: `8499` - // Minimum execution time: 41_863_000 picoseconds. - Weight::from_parts(44_033_031, 8499) - // Standard Error: 116 - .saturating_add(Weight::from_parts(764, 0).saturating_mul(n.into())) + // Minimum execution time: 38_334_000 picoseconds. + Weight::from_parts(40_517_609, 8499) + // Standard Error: 90 + .saturating_add(Weight::from_parts(338, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(15_u64)) } @@ -423,8 +422,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3493` - // Minimum execution time: 9_588_000 picoseconds. - Weight::from_parts(9_925_000, 3493) + // Minimum execution time: 7_850_000 picoseconds. + Weight::from_parts(8_157_000, 3493) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -436,8 +435,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1423` // Estimated: `4681` - // Minimum execution time: 19_308_000 picoseconds. - Weight::from_parts(20_482_000, 4681) + // Minimum execution time: 17_313_000 picoseconds. + Weight::from_parts(17_727_000, 4681) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -445,28 +444,46 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 147_000 picoseconds. - Weight::from_parts(184_000, 0) + // Minimum execution time: 171_000 picoseconds. + Weight::from_parts(196_000, 0) } + /// Storage: `Broker::CoreCountInbox` (r:0 w:1) + /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) fn notify_core_count() -> Weight { - T::DbWeight::get().reads_writes(1, 1) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_413_000 picoseconds. + Weight::from_parts(2_587_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Broker::Status` (r:1 w:1) /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) /// Storage: `Broker::Configuration` (r:1 w:0) /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) - /// Proof: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) + /// Storage: `Broker::CoreCountInbox` (r:1 w:0) + /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) /// Proof: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) fn do_tick_base() -> Weight { // Proof Size summary in bytes: - // Measured: `699` - // Estimated: `4164` - // Minimum execution time: 19_824_000 picoseconds. - Weight::from_parts(20_983_000, 4164) + // Measured: `603` + // Estimated: `4068` + // Minimum execution time: 13_121_000 picoseconds. + Weight::from_parts(13_685_000, 4068) .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Broker::Leases` (r:1 w:1) + /// Proof: `Broker::Leases` (`max_values`: Some(1), `max_size`: Some(41), added: 536, mode: `MaxEncodedLen`) + fn swap_leases() -> Weight { + // Proof Size summary in bytes: + // Measured: `239` + // Estimated: `1526` + // Minimum execution time: 6_847_000 picoseconds. + Weight::from_parts(7_185_000, 1526) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } } @@ -478,8 +495,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_040_000 picoseconds. - Weight::from_parts(3_344_000, 0) + // Minimum execution time: 2_865_000 picoseconds. + Weight::from_parts(3_061_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Broker::Reservations` (r:1 w:1) @@ -488,8 +505,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `5016` // Estimated: `7496` - // Minimum execution time: 21_259_000 picoseconds. - Weight::from_parts(22_110_000, 7496) + // Minimum execution time: 18_431_000 picoseconds. + Weight::from_parts(19_558_000, 7496) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -499,8 +516,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `6218` // Estimated: `7496` - // Minimum execution time: 20_330_000 picoseconds. - Weight::from_parts(20_826_000, 7496) + // Minimum execution time: 17_724_000 picoseconds. + Weight::from_parts(18_688_000, 7496) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -510,8 +527,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `239` // Estimated: `1526` - // Minimum execution time: 13_411_000 picoseconds. - Weight::from_parts(13_960_000, 1526) + // Minimum execution time: 10_513_000 picoseconds. + Weight::from_parts(11_138_000, 1526) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -530,14 +547,12 @@ impl WeightInfo for () { /// Storage: `Broker::Workplan` (r:0 w:10) /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. - fn start_sales(n: u32, ) -> Weight { + fn start_sales(_n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `6330` // Estimated: `8499` - // Minimum execution time: 57_770_000 picoseconds. - Weight::from_parts(61_047_512, 8499) - // Standard Error: 165 - .saturating_add(Weight::from_parts(3, 0).saturating_mul(n.into())) + // Minimum execution time: 50_864_000 picoseconds. + Weight::from_parts(54_000_280, 8499) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(16_u64)) } @@ -553,10 +568,10 @@ impl WeightInfo for () { /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) fn purchase() -> Weight { // Proof Size summary in bytes: - // Measured: `568` - // Estimated: `2053` - // Minimum execution time: 51_196_000 picoseconds. - Weight::from_parts(52_382_000, 2053) + // Measured: `635` + // Estimated: `2120` + // Minimum execution time: 43_630_000 picoseconds. + Weight::from_parts(44_622_000, 2120) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -576,10 +591,10 @@ impl WeightInfo for () { /// Proof: `Broker::Workplan` (`max_values`: None, `max_size`: Some(1216), added: 3691, mode: `MaxEncodedLen`) fn renew() -> Weight { // Proof Size summary in bytes: - // Measured: `686` + // Measured: `753` // Estimated: `4698` - // Minimum execution time: 71_636_000 picoseconds. - Weight::from_parts(73_679_000, 4698) + // Minimum execution time: 62_453_000 picoseconds. + Weight::from_parts(63_882_000, 4698) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -589,8 +604,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3550` - // Minimum execution time: 19_182_000 picoseconds. - Weight::from_parts(19_775_000, 3550) + // Minimum execution time: 17_237_000 picoseconds. + Weight::from_parts(17_757_000, 3550) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -600,21 +615,21 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3550` - // Minimum execution time: 20_688_000 picoseconds. - Weight::from_parts(21_557_000, 3550) + // Minimum execution time: 18_504_000 picoseconds. + Weight::from_parts(19_273_000, 3550) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - /// Storage: `Broker::Regions` (r:1 w:2) + /// Storage: `Broker::Regions` (r:1 w:3) /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) fn interlace() -> Weight { // Proof Size summary in bytes: // Measured: `495` // Estimated: `3550` - // Minimum execution time: 21_190_000 picoseconds. - Weight::from_parts(22_215_000, 3550) + // Minimum execution time: 20_477_000 picoseconds. + Weight::from_parts(21_328_000, 3550) .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Broker::Configuration` (r:1 w:0) /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) @@ -628,8 +643,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `740` // Estimated: `4681` - // Minimum execution time: 34_591_000 picoseconds. - Weight::from_parts(36_227_000, 4681) + // Minimum execution time: 31_815_000 picoseconds. + Weight::from_parts(32_700_000, 4681) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -647,8 +662,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `775` // Estimated: `5996` - // Minimum execution time: 40_346_000 picoseconds. - Weight::from_parts(41_951_000, 5996) + // Minimum execution time: 38_313_000 picoseconds. + Weight::from_parts(38_985_000, 5996) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -663,10 +678,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `859` // Estimated: `6196 + m * (2520 ±0)` - // Minimum execution time: 75_734_000 picoseconds. - Weight::from_parts(78_168_395, 6196) - // Standard Error: 63_180 - .saturating_add(Weight::from_parts(1_076_259, 0).saturating_mul(m.into())) + // Minimum execution time: 70_170_000 picoseconds. + Weight::from_parts(71_245_388, 6196) + // Standard Error: 54_382 + .saturating_add(Weight::from_parts(1_488_794, 0).saturating_mul(m.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(m.into()))) .saturating_add(RocksDbWeight::get().writes(5_u64)) @@ -678,8 +693,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 46_383_000 picoseconds. - Weight::from_parts(47_405_000, 3593) + // Minimum execution time: 43_414_000 picoseconds. + Weight::from_parts(44_475_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -691,8 +706,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `603` // Estimated: `3550` - // Minimum execution time: 30_994_000 picoseconds. - Weight::from_parts(31_979_000, 3550) + // Minimum execution time: 31_327_000 picoseconds. + Weight::from_parts(32_050_000, 3550) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -706,8 +721,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `601` // Estimated: `3533` - // Minimum execution time: 37_584_000 picoseconds. - Weight::from_parts(44_010_000, 3533) + // Minimum execution time: 41_315_000 picoseconds. + Weight::from_parts(42_421_000, 3533) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -721,10 +736,10 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn drop_history() -> Weight { // Proof Size summary in bytes: - // Measured: `830` + // Measured: `995` // Estimated: `3593` - // Minimum execution time: 45_266_000 picoseconds. - Weight::from_parts(48_000_000, 3593) + // Minimum execution time: 49_707_000 picoseconds. + Weight::from_parts(51_516_000, 3593) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -734,10 +749,10 @@ impl WeightInfo for () { /// Proof: `Broker::AllowedRenewals` (`max_values`: None, `max_size`: Some(1233), added: 3708, mode: `MaxEncodedLen`) fn drop_renewal() -> Weight { // Proof Size summary in bytes: - // Measured: `525` + // Measured: `661` // Estimated: `4698` - // Minimum execution time: 25_365_000 picoseconds. - Weight::from_parts(26_920_000, 4698) + // Minimum execution time: 26_207_000 picoseconds. + Weight::from_parts(27_227_000, 4698) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -746,22 +761,22 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_519_000 picoseconds. - Weight::from_parts(7_098_698, 0) - // Standard Error: 20 - .saturating_add(Weight::from_parts(8, 0).saturating_mul(n.into())) + // Minimum execution time: 4_670_000 picoseconds. + Weight::from_parts(5_170_450, 0) + // Standard Error: 16 + .saturating_add(Weight::from_parts(37, 0).saturating_mul(n.into())) } - /// Storage: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) - /// Proof: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) + /// Storage: `Broker::CoreCountInbox` (r:1 w:1) + /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 1000]`. fn process_core_count(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `98` - // Estimated: `3563` - // Minimum execution time: 7_608_000 picoseconds. - Weight::from_parts(8_157_815, 3563) - // Standard Error: 26 - .saturating_add(Weight::from_parts(48, 0).saturating_mul(n.into())) + // Measured: `404` + // Estimated: `1487` + // Minimum execution time: 6_916_000 picoseconds. + Weight::from_parts(7_485_053, 1487) + // Standard Error: 23 + .saturating_add(Weight::from_parts(30, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -777,10 +792,10 @@ impl WeightInfo for () { /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn process_revenue() -> Weight { // Proof Size summary in bytes: - // Measured: `905` - // Estimated: `4370` - // Minimum execution time: 59_993_000 picoseconds. - Weight::from_parts(61_752_000, 4370) + // Measured: `972` + // Estimated: `4437` + // Minimum execution time: 50_987_000 picoseconds. + Weight::from_parts(52_303_000, 4437) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -799,10 +814,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `6281` // Estimated: `8499` - // Minimum execution time: 41_863_000 picoseconds. - Weight::from_parts(44_033_031, 8499) - // Standard Error: 116 - .saturating_add(Weight::from_parts(764, 0).saturating_mul(n.into())) + // Minimum execution time: 38_334_000 picoseconds. + Weight::from_parts(40_517_609, 8499) + // Standard Error: 90 + .saturating_add(Weight::from_parts(338, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(15_u64)) } @@ -814,8 +829,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3493` - // Minimum execution time: 9_588_000 picoseconds. - Weight::from_parts(9_925_000, 3493) + // Minimum execution time: 7_850_000 picoseconds. + Weight::from_parts(8_157_000, 3493) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -827,8 +842,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1423` // Estimated: `4681` - // Minimum execution time: 19_308_000 picoseconds. - Weight::from_parts(20_482_000, 4681) + // Minimum execution time: 17_313_000 picoseconds. + Weight::from_parts(17_727_000, 4681) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -836,28 +851,45 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 147_000 picoseconds. - Weight::from_parts(184_000, 0) + // Minimum execution time: 171_000 picoseconds. + Weight::from_parts(196_000, 0) } + /// Storage: `Broker::CoreCountInbox` (r:0 w:1) + /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) fn notify_core_count() -> Weight { - RocksDbWeight::get().reads(1) - .saturating_add(RocksDbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_413_000 picoseconds. + Weight::from_parts(2_587_000, 0) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Broker::Status` (r:1 w:1) /// Proof: `Broker::Status` (`max_values`: Some(1), `max_size`: Some(18), added: 513, mode: `MaxEncodedLen`) /// Storage: `Broker::Configuration` (r:1 w:0) /// Proof: `Broker::Configuration` (`max_values`: Some(1), `max_size`: Some(31), added: 526, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) - /// Proof: UNKNOWN KEY `0x18194fcb5c1fcace44d2d0a004272614` (r:1 w:1) + /// Storage: `Broker::CoreCountInbox` (r:1 w:0) + /// Proof: `Broker::CoreCountInbox` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) /// Proof: UNKNOWN KEY `0xf308d869daf021a7724e69c557dd8dbe` (r:1 w:1) fn do_tick_base() -> Weight { // Proof Size summary in bytes: - // Measured: `699` - // Estimated: `4164` - // Minimum execution time: 19_824_000 picoseconds. - Weight::from_parts(20_983_000, 4164) + // Measured: `603` + // Estimated: `4068` + // Minimum execution time: 13_121_000 picoseconds. + Weight::from_parts(13_685_000, 4068) .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: `Broker::Leases` (r:1 w:1) + /// Proof: `Broker::Leases` (`max_values`: Some(1), `max_size`: Some(41), added: 536, mode: `MaxEncodedLen`) + fn swap_leases() -> Weight { + // Proof Size summary in bytes: + // Measured: `239` + // Estimated: `1526` + // Minimum execution time: 6_847_000 picoseconds. + Weight::from_parts(7_185_000, 1526) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } } -- GitLab From 0c15d887519d58c50880ccd149b6ee9a7635b5bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 26 Mar 2024 18:00:39 +0000 Subject: [PATCH 099/187] westend: `SignedPhase` is a constant (#3646) In preparation for the merkleized metadata, we need to ensure that constants are actually constant. If we want to test the unsigned phase we could for example just disable signed voter. Or we add some extra mechanism to the pallet to disable the signed phase from time to time. --------- Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- substrate/frame/election-provider-multi-phase/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index 31a79577d1f..11577cd3526 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -586,10 +586,8 @@ pub mod pallet { type EstimateCallFee: EstimateCallFee, BalanceOf>; /// Duration of the unsigned phase. - #[pallet::constant] type UnsignedPhase: Get>; /// Duration of the signed phase. - #[pallet::constant] type SignedPhase: Get>; /// The minimum amount of improvement to the solution score that defines a solution as -- GitLab From 3c972fc19e14b55e8a077145cf2620bccb0a6f8d Mon Sep 17 00:00:00 2001 From: Pavel Orlov <45266194+PraetorP@users.noreply.github.com> Date: Wed, 27 Mar 2024 01:34:28 +0700 Subject: [PATCH 100/187] XCM Fee Payment Runtime API (#3607) The PR provides API for obtaining: - the weight required to execute an XCM message, - a list of acceptable `AssetId`s for message execution payment, - the cost of the weight in the specified acceptable `AssetId`. It is meant to address an issue where one has to guess how much fee to pay for execution. Also, at the moment, a client has to guess which assets are acceptable for fee execution payment. See the related issue https://github.com/paritytech/polkadot-sdk/issues/690. With this API, a client is supposed to query the list of the supported asset IDs (in the XCM version format the client understands), weigh the XCM program the client wants to execute and convert the weight into one of the acceptable assets. Note that the client is supposed to know what program will be executed on what chains. However, having a small companion JS library for the pallet-xcm and xtokens should be enough to determine what XCM programs will be executed and where (since these pallets compose a known small set of programs). ```Rust pub trait XcmPaymentApi where Call: Codec, { /// Returns a list of acceptable payment assets. /// /// # Arguments /// /// * `xcm_version`: Version. fn query_acceptable_payment_assets(xcm_version: Version) -> Result, Error>; /// Returns a weight needed to execute a XCM. /// /// # Arguments /// /// * `message`: `VersionedXcm`. fn query_xcm_weight(message: VersionedXcm) -> Result; /// Converts a weight into a fee for the specified `AssetId`. /// /// # Arguments /// /// * `weight`: convertible `Weight`. /// * `asset`: `VersionedAssetId`. fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result; /// Get delivery fees for sending a specific `message` to a `destination`. /// These always come in a specific asset, defined by the chain. /// /// # Arguments /// * `message`: The message that'll be sent, necessary because most delivery fees are based on the /// size of the message. /// * `destination`: The destination to send the message to. Different destinations may use /// different senders that charge different fees. fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result; } ``` An [example](https://gist.github.com/PraetorP/4bc323ff85401abe253897ba990ec29d) of a client side code. --------- Co-authored-by: Francisco Aguirre Co-authored-by: Adrian Catangiu Co-authored-by: Daniel Shiposha --- Cargo.lock | 19 ++++ Cargo.toml | 1 + polkadot/node/service/Cargo.toml | 3 + polkadot/node/service/src/fake_runtime_api.rs | 21 +++- polkadot/runtime/rococo/Cargo.toml | 2 + polkadot/runtime/rococo/src/lib.rs | 53 ++++++++-- polkadot/runtime/westend/Cargo.toml | 2 + polkadot/runtime/westend/src/lib.rs | 51 ++++++++-- polkadot/runtime/westend/src/tests.rs | 1 - polkadot/xcm/pallet-xcm/Cargo.toml | 2 + polkadot/xcm/pallet-xcm/src/lib.rs | 32 ++++++ polkadot/xcm/src/lib.rs | 10 ++ .../xcm-fee-payment-runtime-api/Cargo.toml | 40 ++++++++ .../xcm-fee-payment-runtime-api/src/lib.rs | 99 +++++++++++++++++++ prdoc/pr_3607.prdoc | 26 +++++ 15 files changed, 342 insertions(+), 20 deletions(-) create mode 100644 polkadot/xcm/xcm-fee-payment-runtime-api/Cargo.toml create mode 100644 polkadot/xcm/xcm-fee-payment-runtime-api/src/lib.rs create mode 100644 prdoc/pr_3607.prdoc diff --git a/Cargo.lock b/Cargo.lock index 9e52bfcf9a4..f246a978fd2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11188,6 +11188,7 @@ dependencies = [ "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -13540,12 +13541,14 @@ dependencies = [ "sp-transaction-pool", "sp-version", "sp-weights", + "staging-xcm", "substrate-prometheus-endpoint", "tempfile", "thiserror", "tracing-gum", "westend-runtime", "westend-runtime-constants", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -15116,6 +15119,7 @@ dependencies = [ "substrate-wasm-builder", "tiny-keccak", "tokio", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -21970,6 +21974,7 @@ dependencies = [ "tiny-keccak", "tokio", "westend-runtime-constants", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -22443,6 +22448,20 @@ dependencies = [ "staging-xcm-executor", ] +[[package]] +name = "xcm-fee-payment-runtime-api" +version = "0.1.0" +dependencies = [ + "frame-support", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-runtime", + "sp-std 14.0.0", + "sp-weights", + "staging-xcm", +] + [[package]] name = "xcm-procedural" version = "7.0.0" diff --git a/Cargo.toml b/Cargo.toml index 5eeac597827..e6162830375 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -214,6 +214,7 @@ members = [ "polkadot/xcm/xcm-builder", "polkadot/xcm/xcm-executor", "polkadot/xcm/xcm-executor/integration-tests", + "polkadot/xcm/xcm-fee-payment-runtime-api", "polkadot/xcm/xcm-simulator", "polkadot/xcm/xcm-simulator/example", "polkadot/xcm/xcm-simulator/fuzzer", diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index e2bccfa5510..5a42443c84c 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -142,6 +142,9 @@ polkadot-node-core-pvf-checker = { path = "../core/pvf-checker", optional = true polkadot-node-core-runtime-api = { path = "../core/runtime-api", optional = true } polkadot-statement-distribution = { path = "../network/statement-distribution", optional = true } +xcm = { package = "staging-xcm", path = "../../xcm" } +xcm-fee-payment-runtime-api = { path = "../../xcm/xcm-fee-payment-runtime-api" } + [dev-dependencies] polkadot-test-client = { path = "../test/client" } polkadot-node-subsystem-test-helpers = { path = "../subsystem-test-helpers" } diff --git a/polkadot/node/service/src/fake_runtime_api.rs b/polkadot/node/service/src/fake_runtime_api.rs index 085ea93fdc7..c6cfb7a27d0 100644 --- a/polkadot/node/service/src/fake_runtime_api.rs +++ b/polkadot/node/service/src/fake_runtime_api.rs @@ -30,6 +30,7 @@ use polkadot_primitives::{ ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, }; + use sp_core::OpaqueMetadata; use sp_runtime::{ traits::Block as BlockT, @@ -39,7 +40,7 @@ use sp_runtime::{ use sp_version::RuntimeVersion; use sp_weights::Weight; use std::collections::BTreeMap; - +use xcm::{VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm}; sp_api::decl_runtime_apis! { /// This runtime API is only implemented for the test runtime! pub trait GetLastTimestamp { @@ -396,4 +397,22 @@ sp_api::impl_runtime_apis! { unimplemented!() } } + + impl xcm_fee_payment_runtime_api::XcmPaymentApi for Runtime { + fn query_acceptable_payment_assets(_: xcm::Version) -> Result, xcm_fee_payment_runtime_api::Error> { + unimplemented!() + } + + fn query_weight_to_asset_fee(_: Weight, _: VersionedAssetId) -> Result { + unimplemented!() + } + + fn query_xcm_weight(_: VersionedXcm<()>) -> Result { + unimplemented!() + } + + fn query_delivery_fees(_: VersionedLocation, _: VersionedXcm<()>) -> Result { + unimplemented!() + } + } } diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 3dc59cc1728..6f63a93cebe 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -104,6 +104,7 @@ polkadot-parachain-primitives = { path = "../../parachain", default-features = f xcm = { package = "staging-xcm", path = "../../xcm", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = "../../xcm/xcm-executor", default-features = false } xcm-builder = { package = "staging-xcm-builder", path = "../../xcm/xcm-builder", default-features = false } +xcm-fee-payment-runtime-api = { path = "../../xcm/xcm-fee-payment-runtime-api", default-features = false } [dev-dependencies] tiny-keccak = { version = "2.0.2", features = ["keccak"] } @@ -208,6 +209,7 @@ std = [ "tx-pool-api/std", "xcm-builder/std", "xcm-executor/std", + "xcm-fee-payment-runtime-api/std", "xcm/std", ] runtime-benchmarks = [ diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index b26317490cd..8c8abe97ede 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -75,7 +75,7 @@ use frame_support::{ InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, ProcessMessageError, StorageMapShim, WithdrawReasons, }, - weights::{ConstantMultiplier, WeightMeter}, + weights::{ConstantMultiplier, WeightMeter, WeightToFee as _}, PalletId, }; use frame_system::{EnsureRoot, EnsureSigned}; @@ -98,7 +98,10 @@ use sp_staking::SessionIndex; #[cfg(any(feature = "std", test))] use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use xcm::{latest::prelude::*, VersionedLocation}; +use xcm::{ + latest::prelude::*, IntoVersion, VersionedAssetId, VersionedAssets, VersionedLocation, + VersionedXcm, +}; use xcm_builder::PayOverXcm; pub use frame_system::Call as SystemCall; @@ -123,6 +126,7 @@ use governance::{ pallet_custom_origins, AuctionAdmin, Fellows, GeneralAdmin, LeaseAdmin, Treasurer, TreasurySpender, }; +use xcm_fee_payment_runtime_api::Error as XcmPaymentApiError; #[cfg(test)] mod tests; @@ -216,7 +220,7 @@ pub struct OriginPrivilegeCmp; impl PrivilegeCmp for OriginPrivilegeCmp { fn cmp_privilege(left: &OriginCaller, right: &OriginCaller) -> Option { if left == right { - return Some(Ordering::Equal) + return Some(Ordering::Equal); } match (left, right) { @@ -1493,11 +1497,11 @@ pub mod migrations { let now = frame_system::Pallet::::block_number(); let lease = slots::Pallet::::lease(para); if lease.is_empty() { - return None + return None; } // Lease not yet started, ignore: if lease.iter().any(Option::is_none) { - return None + return None; } let (index, _) = as Leaser>::lease_period_index(now)?; @@ -1559,7 +1563,7 @@ pub mod migrations { fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC { log::warn!(target: "runtime::session_keys", "Skipping session keys migration pre-upgrade check due to spec version (already applied?)"); - return Ok(Vec::new()) + return Ok(Vec::new()); } log::info!(target: "runtime::session_keys", "Collecting pre-upgrade session keys state"); @@ -1588,7 +1592,7 @@ pub mod migrations { fn on_runtime_upgrade() -> Weight { if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC { log::info!("Skipping session keys upgrade: already applied"); - return ::DbWeight::get().reads(1) + return ::DbWeight::get().reads(1); } log::trace!("Upgrading session keys"); Session::upgrade_keys::(transform_session_keys); @@ -1601,7 +1605,7 @@ pub mod migrations { ) -> Result<(), sp_runtime::TryRuntimeError> { if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC { log::warn!(target: "runtime::session_keys", "Skipping session keys migration post-upgrade check due to spec version (already applied?)"); - return Ok(()) + return Ok(()); } let key_ids = SessionKeys::key_ids(); @@ -1785,6 +1789,37 @@ sp_api::impl_runtime_apis! { } } + impl xcm_fee_payment_runtime_api::XcmPaymentApi for Runtime { + fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { + if !matches!(xcm_version, 3 | 4) { + return Err(XcmPaymentApiError::UnhandledXcmVersion); + } + Ok([VersionedAssetId::V4(xcm_config::TokenLocation::get().into())] + .into_iter() + .filter_map(|asset| asset.into_version(xcm_version).ok()) + .collect()) + } + + fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { + let local_asset = VersionedAssetId::V4(xcm_config::TokenLocation::get().into()); + let asset = asset + .into_version(4) + .map_err(|_| XcmPaymentApiError::VersionedConversionFailed)?; + + if asset != local_asset { return Err(XcmPaymentApiError::AssetNotFound); } + + Ok(WeightToFee::weight_to_fee(&weight)) + } + + fn query_xcm_weight(message: VersionedXcm<()>) -> Result { + XcmPallet::query_xcm_weight(message) + } + + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + XcmPallet::query_delivery_fees(destination, message) + } + } + impl sp_api::Metadata for Runtime { fn metadata() -> OpaqueMetadata { OpaqueMetadata::new(Runtime::metadata().into()) @@ -2493,7 +2528,7 @@ mod remote_tests { #[tokio::test] async fn run_migrations() { if var("RUN_MIGRATION_TESTS").is_err() { - return + return; } sp_tracing::try_init_simple(); diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index fcead1dd0b5..587a6c9a590 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -114,6 +114,7 @@ runtime-parachains = { package = "polkadot-runtime-parachains", path = "../parac xcm = { package = "staging-xcm", path = "../../xcm", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = "../../xcm/xcm-executor", default-features = false } xcm-builder = { package = "staging-xcm-builder", path = "../../xcm/xcm-builder", default-features = false } +xcm-fee-payment-runtime-api = { path = "../../xcm/xcm-fee-payment-runtime-api", default-features = false } [dev-dependencies] hex-literal = "0.4.1" @@ -227,6 +228,7 @@ std = [ "westend-runtime-constants/std", "xcm-builder/std", "xcm-executor/std", + "xcm-fee-payment-runtime-api/std", "xcm/std", ] runtime-benchmarks = [ diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 12e6174ab6c..02397f35368 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -35,7 +35,7 @@ use frame_support::{ InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, ProcessMessage, ProcessMessageError, WithdrawReasons, }, - weights::{ConstantMultiplier, WeightMeter}, + weights::{ConstantMultiplier, WeightMeter, WeightToFee as _}, PalletId, }; use frame_system::{EnsureRoot, EnsureSigned}; @@ -101,11 +101,13 @@ use sp_std::{collections::btree_map::BTreeMap, prelude::*}; use sp_version::NativeVersion; use sp_version::RuntimeVersion; use xcm::{ - latest::{InteriorLocation, Junction, Junction::PalletInstance}, - VersionedLocation, + latest::prelude::*, IntoVersion, VersionedAssetId, VersionedAssets, VersionedLocation, + VersionedXcm, }; use xcm_builder::PayOverXcm; +use xcm_fee_payment_runtime_api::Error as XcmPaymentApiError; + pub use frame_system::Call as SystemCall; pub use pallet_balances::Call as BalancesCall; pub use pallet_election_provider_multi_phase::{Call as EPMCall, GeometricDepositBase}; @@ -1667,11 +1669,11 @@ pub mod migrations { let now = frame_system::Pallet::::block_number(); let lease = slots::Pallet::::lease(para); if lease.is_empty() { - return None + return None; } // Lease not yet started, ignore: if lease.iter().any(Option::is_none) { - return None + return None; } let (index, _) = as Leaser>::lease_period_index(now)?; @@ -1693,7 +1695,7 @@ pub mod migrations { fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC { log::warn!(target: "runtime::session_keys", "Skipping session keys migration pre-upgrade check due to spec version (already applied?)"); - return Ok(Vec::new()) + return Ok(Vec::new()); } log::info!(target: "runtime::session_keys", "Collecting pre-upgrade session keys state"); @@ -1722,7 +1724,7 @@ pub mod migrations { fn on_runtime_upgrade() -> Weight { if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC { log::warn!("Skipping session keys upgrade: already applied"); - return ::DbWeight::get().reads(1) + return ::DbWeight::get().reads(1); } log::info!("Upgrading session keys"); Session::upgrade_keys::(transform_session_keys); @@ -1735,7 +1737,7 @@ pub mod migrations { ) -> Result<(), sp_runtime::TryRuntimeError> { if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC { log::warn!(target: "runtime::session_keys", "Skipping session keys migration post-upgrade check due to spec version (already applied?)"); - return Ok(()) + return Ok(()); } let key_ids = SessionKeys::key_ids(); @@ -2332,6 +2334,37 @@ sp_api::impl_runtime_apis! { } } + impl xcm_fee_payment_runtime_api::XcmPaymentApi for Runtime { + fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { + if !matches!(xcm_version, 3 | 4) { + return Err(XcmPaymentApiError::UnhandledXcmVersion); + } + Ok([VersionedAssetId::V4(xcm_config::TokenLocation::get().into())] + .into_iter() + .filter_map(|asset| asset.into_version(xcm_version).ok()) + .collect()) + } + + fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { + let local_asset = VersionedAssetId::V4(xcm_config::TokenLocation::get().into()); + let asset = asset + .into_version(4) + .map_err(|_| XcmPaymentApiError::VersionedConversionFailed)?; + + if asset != local_asset { return Err(XcmPaymentApiError::AssetNotFound); } + + Ok(WeightToFee::weight_to_fee(&weight)) + } + + fn query_xcm_weight(message: VersionedXcm<()>) -> Result { + XcmPallet::query_xcm_weight(message) + } + + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + XcmPallet::query_delivery_fees(destination, message) + } + } + impl pallet_nomination_pools_runtime_api::NominationPoolsApi< Block, AccountId, @@ -2650,7 +2683,7 @@ mod remote_tests { #[tokio::test] async fn run_migrations() { if var("RUN_MIGRATION_TESTS").is_err() { - return + return; } sp_tracing::try_init_simple(); diff --git a/polkadot/runtime/westend/src/tests.rs b/polkadot/runtime/westend/src/tests.rs index 9f996316059..bdd599d2b75 100644 --- a/polkadot/runtime/westend/src/tests.rs +++ b/polkadot/runtime/westend/src/tests.rs @@ -21,7 +21,6 @@ use std::collections::HashSet; use crate::*; use frame_support::traits::WhitelistedStorageKeys; use sp_core::hexdisplay::HexDisplay; -use xcm::latest::prelude::*; #[test] fn remove_keys_weight_is_sensible() { diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index 4840b6127f5..08307c34f8a 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -26,6 +26,7 @@ sp-std = { path = "../../../substrate/primitives/std", default-features = false xcm = { package = "staging-xcm", path = "..", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor", default-features = false } xcm-builder = { package = "staging-xcm-builder", path = "../xcm-builder", default-features = false } +xcm-fee-payment-runtime-api = { path = "../xcm-fee-payment-runtime-api", default-features = false } # marked optional, used in benchmarking frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } @@ -54,6 +55,7 @@ std = [ "sp-std/std", "xcm-builder/std", "xcm-executor/std", + "xcm-fee-payment-runtime-api/std", "xcm/std", ] runtime-benchmarks = [ diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 8a9e5288f2e..58a597de5ab 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -61,6 +61,7 @@ use xcm_executor::{ }, AssetsInHolding, }; +use xcm_fee_payment_runtime_api::Error as FeePaymentError; #[cfg(any(feature = "try-runtime", test))] use sp_runtime::TryRuntimeError; @@ -2363,6 +2364,37 @@ impl Pallet { AccountIdConversion::::into_account_truncating(&ID) } + pub fn query_xcm_weight(message: VersionedXcm<()>) -> Result { + let message = + Xcm::<()>::try_from(message).map_err(|_| FeePaymentError::VersionedConversionFailed)?; + + T::Weigher::weight(&mut message.into()).map_err(|()| { + log::error!(target: "xcm::pallet_xcm::query_xcm_weight", "Error when querying XCM weight"); + FeePaymentError::WeightNotComputable + }) + } + + pub fn query_delivery_fees( + destination: VersionedLocation, + message: VersionedXcm<()>, + ) -> Result { + let result_version = destination.identify_version().max(message.identify_version()); + + let destination = + destination.try_into().map_err(|_| FeePaymentError::VersionedConversionFailed)?; + + let message = message.try_into().map_err(|_| FeePaymentError::VersionedConversionFailed)?; + + let (_, fees) = validate_send::(destination, message).map_err(|error| { + log::error!(target: "xcm::pallet_xcm::query_delivery_fees", "Error when querying delivery fees: {:?}", error); + FeePaymentError::Unroutable + })?; + + VersionedAssets::from(fees) + .into_version(result_version) + .map_err(|_| FeePaymentError::VersionedConversionFailed) + } + /// Create a new expectation of a query response with the querier being here. fn do_new_query( responder: impl Into, diff --git a/polkadot/xcm/src/lib.rs b/polkadot/xcm/src/lib.rs index ba8d726aecf..86a17fa1e88 100644 --- a/polkadot/xcm/src/lib.rs +++ b/polkadot/xcm/src/lib.rs @@ -443,6 +443,16 @@ impl IntoVersion for VersionedXcm { } } +impl IdentifyVersion for VersionedXcm { + fn identify_version(&self) -> Version { + match self { + Self::V2(_) => v2::VERSION, + Self::V3(_) => v3::VERSION, + Self::V4(_) => v4::VERSION, + } + } +} + impl From> for VersionedXcm { fn from(x: v2::Xcm) -> Self { VersionedXcm::V2(x) diff --git a/polkadot/xcm/xcm-fee-payment-runtime-api/Cargo.toml b/polkadot/xcm/xcm-fee-payment-runtime-api/Cargo.toml new file mode 100644 index 00000000000..682642d13c3 --- /dev/null +++ b/polkadot/xcm/xcm-fee-payment-runtime-api/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "xcm-fee-payment-runtime-api" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +repository.workspace = true +description = "XCM fee payment runtime API" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ + "derive", +] } + +sp-api = { path = "../../../substrate/primitives/api", default-features = false } +scale-info = { version = "2.10.0", default-features = false, features = [ + "derive", + "serde", +] } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } +sp-weights = { path = "../../../substrate/primitives/weights", default-features = false } +xcm = { package = "staging-xcm", path = "../", default-features = false } +frame-support = { path = "../../../substrate/frame/support", default-features = false } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-support/std", + "scale-info/std", + "sp-api/std", + "sp-runtime/std", + "sp-std/std", + "sp-weights/std", + "xcm/std", +] diff --git a/polkadot/xcm/xcm-fee-payment-runtime-api/src/lib.rs b/polkadot/xcm/xcm-fee-payment-runtime-api/src/lib.rs new file mode 100644 index 00000000000..20bf9236f1f --- /dev/null +++ b/polkadot/xcm/xcm-fee-payment-runtime-api/src/lib.rs @@ -0,0 +1,99 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Runtime API definition for xcm transaction payment. + +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::{Decode, Encode}; +use frame_support::pallet_prelude::TypeInfo; +use sp_std::vec::Vec; +use sp_weights::Weight; +use xcm::{Version, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm}; + +sp_api::decl_runtime_apis! { + /// A trait of XCM payment API. + /// + /// API provides functionality for obtaining: + /// + /// * the weight required to execute an XCM message, + /// * a list of acceptable `AssetId`s for message execution payment, + /// * the cost of the weight in the specified acceptable `AssetId`. + /// * the fees for an XCM message delivery. + /// + /// To determine the execution weight of the calls required for + /// [`xcm::latest::Instruction::Transact`] instruction, `TransactionPaymentCallApi` can be used. + pub trait XcmPaymentApi { + /// Returns a list of acceptable payment assets. + /// + /// # Arguments + /// + /// * `xcm_version`: Version. + fn query_acceptable_payment_assets(xcm_version: Version) -> Result, Error>; + + /// Returns a weight needed to execute a XCM. + /// + /// # Arguments + /// + /// * `message`: `VersionedXcm`. + fn query_xcm_weight(message: VersionedXcm<()>) -> Result; + + /// Converts a weight into a fee for the specified `AssetId`. + /// + /// # Arguments + /// + /// * `weight`: convertible `Weight`. + /// * `asset`: `VersionedAssetId`. + fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result; + + /// Get delivery fees for sending a specific `message` to a `destination`. + /// These always come in a specific asset, defined by the chain. + /// + /// # Arguments + /// * `message`: The message that'll be sent, necessary because most delivery fees are based on the + /// size of the message. + /// * `destination`: The destination to send the message to. Different destinations may use + /// different senders that charge different fees. + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result; + } +} + +#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)] +pub enum Error { + /// An API part is unsupported. + #[codec(index = 0)] + Unimplemented, + + /// Converting a versioned data structure from one version to another failed. + #[codec(index = 1)] + VersionedConversionFailed, + + /// XCM message weight calculation failed. + #[codec(index = 2)] + WeightNotComputable, + + /// XCM version not able to be handled. + #[codec(index = 3)] + UnhandledXcmVersion, + + /// The given asset is not handled as a fee asset. + #[codec(index = 4)] + AssetNotFound, + + /// Destination is known to be unroutable. + #[codec(index = 5)] + Unroutable, +} diff --git a/prdoc/pr_3607.prdoc b/prdoc/pr_3607.prdoc new file mode 100644 index 00000000000..1a69b25ad25 --- /dev/null +++ b/prdoc/pr_3607.prdoc @@ -0,0 +1,26 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "XCM fee payment API" + +doc: + - audience: Runtime Dev + description: | + A runtime API was added for estimating the fees required for XCM execution and delivery. + This is the basic building block needed for UIs to accurately estimate fees. + An example implementation is shown in the PR. Ideally it's simple to implement, you only need to call existing parts of your XCM config. + The API looks like so: + ```rust + fn query_acceptable_payment_assets(xcm_version: Version) -> Result, Error>; + fn query_xcm_weight(message: VersionedXcm) -> Result; + fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result; + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result; + ``` + The first three relate to XCM execution fees, given an XCM, you can query its weight, then which assets are acceptable for buying weight and convert weight to a number of those assets. + The last one takes in a destination and a message you want to send from the runtime you're executing this on, it will give you the delivery fees. + +crates: + - name: xcm-fee-payment-runtime-api + - name: rococo-runtime + - name: westend-runtime + -- GitLab From ed907819c64fd0a185ff4109dfc7512d6162f7e9 Mon Sep 17 00:00:00 2001 From: Derek Colley Date: Tue, 26 Mar 2024 22:31:15 +0000 Subject: [PATCH 101/187] add metaspan boot node to coretime-westend.json (#3781) --- cumulus/parachains/chain-specs/coretime-westend.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cumulus/parachains/chain-specs/coretime-westend.json b/cumulus/parachains/chain-specs/coretime-westend.json index c79fd582348..adb35b8a349 100644 --- a/cumulus/parachains/chain-specs/coretime-westend.json +++ b/cumulus/parachains/chain-specs/coretime-westend.json @@ -4,7 +4,8 @@ "chainType": "Live", "bootNodes": [ "/dns/westend-coretime-collator-node-0.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWP93Dzk8T7GWxyWw9jhLcz8Pksokk3R9vL2eEH337bNkT", - "/dns/westend-coretime-collator-node-1.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWMh2imeAzsZKGQgm2cv6Uoep3GBYtwGfujt1bs5YfVzkH" + "/dns/westend-coretime-collator-node-1.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWMh2imeAzsZKGQgm2cv6Uoep3GBYtwGfujt1bs5YfVzkH", + "/dns/boot.metaspan.io/tcp/33019/p2p/12D3KooWCa1uNnEZqiqJY9jkKNQxwSLGPeZ5MjWHhjQMGwga9JMM" ], "telemetryEndpoints": null, "protocolId": null, -- GitLab From 3fc5b826534438313d03f6e0404db44099be6d9d Mon Sep 17 00:00:00 2001 From: ordian Date: Tue, 26 Mar 2024 23:59:47 +0100 Subject: [PATCH 102/187] fix regression in approval-voting introduced in #3747 (#3831) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #3826. The docs on the `candidates` field of `BlockEntry` were incorrectly stating that they are sorted by core index. The (incorrect) optimization was introduced in #3747 based on this assumption. The actual ordering is based on `CandidateIncluded` events ordering in the runtime. We revert this optimization here. - [x] verify the underlying issue - [x] add a regression test --------- Co-authored-by: Bastian Köcher --- polkadot/node/core/approval-voting/src/lib.rs | 6 +- .../approval-voting/src/persisted_entries.rs | 2 +- .../node/core/approval-voting/src/tests.rs | 167 ++++++++++++++++++ 3 files changed, 171 insertions(+), 4 deletions(-) diff --git a/polkadot/node/core/approval-voting/src/lib.rs b/polkadot/node/core/approval-voting/src/lib.rs index 1a62c9ee55e..76b3d476e28 100644 --- a/polkadot/node/core/approval-voting/src/lib.rs +++ b/polkadot/node/core/approval-voting/src/lib.rs @@ -1285,10 +1285,10 @@ fn cores_to_candidate_indices( // Map from core index to candidate index. for claimed_core_index in core_indices.iter_ones() { - // Candidates are sorted by core index. - if let Ok(candidate_index) = block_entry + if let Some(candidate_index) = block_entry .candidates() - .binary_search_by_key(&(claimed_core_index as u32), |(core_index, _)| core_index.0) + .iter() + .position(|(core_index, _)| core_index.0 == claimed_core_index as u32) { candidate_indices.push(candidate_index as _); } diff --git a/polkadot/node/core/approval-voting/src/persisted_entries.rs b/polkadot/node/core/approval-voting/src/persisted_entries.rs index b924a1b52cc..6eeb99cb99f 100644 --- a/polkadot/node/core/approval-voting/src/persisted_entries.rs +++ b/polkadot/node/core/approval-voting/src/persisted_entries.rs @@ -454,7 +454,7 @@ pub struct BlockEntry { slot: Slot, relay_vrf_story: RelayVRFStory, // The candidates included as-of this block and the index of the core they are - // leaving. Sorted ascending by core index. + // leaving. candidates: Vec<(CoreIndex, CandidateHash)>, // A bitfield where the i'th bit corresponds to the i'th candidate in `candidates`. // The i'th bit is `true` iff the candidate has been approved in the context of this diff --git a/polkadot/node/core/approval-voting/src/tests.rs b/polkadot/node/core/approval-voting/src/tests.rs index a3013eab46d..1483af56585 100644 --- a/polkadot/node/core/approval-voting/src/tests.rs +++ b/polkadot/node/core/approval-voting/src/tests.rs @@ -2479,6 +2479,173 @@ fn subsystem_import_checked_approval_sets_one_block_bit_at_a_time() { }); } +// See https://github.com/paritytech/polkadot-sdk/issues/3826 +#[test] +fn inclusion_events_can_be_unordered_by_core_index() { + let assignment_criteria = Box::new(MockAssignmentCriteria( + || { + let mut assignments = HashMap::new(); + for core in 0..3 { + let _ = assignments.insert( + CoreIndex(core), + approval_db::v2::OurAssignment { + cert: garbage_assignment_cert_v2( + AssignmentCertKindV2::RelayVRFModuloCompact { + core_bitfield: vec![CoreIndex(0), CoreIndex(1), CoreIndex(2)] + .try_into() + .unwrap(), + }, + ), + tranche: 0, + validator_index: ValidatorIndex(0), + triggered: false, + } + .into(), + ); + } + assignments + }, + |_| Ok(0), + )); + let config = HarnessConfigBuilder::default().assignment_criteria(assignment_criteria).build(); + let store = config.backend(); + + test_harness(config, |test_harness| async move { + let TestHarness { + mut virtual_overseer, + clock, + sync_oracle_handle: _sync_oracle_handle, + .. + } = test_harness; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ChainApi(ChainApiMessage::FinalizedBlockNumber(rx)) => { + rx.send(Ok(0)).unwrap(); + } + ); + + let block_hash = Hash::repeat_byte(0x01); + + let candidate_receipt0 = { + let mut receipt = dummy_candidate_receipt(block_hash); + receipt.descriptor.para_id = ParaId::from(0_u32); + receipt + }; + let candidate_receipt1 = { + let mut receipt = dummy_candidate_receipt(block_hash); + receipt.descriptor.para_id = ParaId::from(1_u32); + receipt + }; + let candidate_receipt2 = { + let mut receipt = dummy_candidate_receipt(block_hash); + receipt.descriptor.para_id = ParaId::from(2_u32); + receipt + }; + let candidate_index0 = 0; + let candidate_index1 = 1; + let candidate_index2 = 2; + + let validator0 = ValidatorIndex(0); + let validator1 = ValidatorIndex(1); + let validator2 = ValidatorIndex(2); + let validator3 = ValidatorIndex(3); + + let validators = vec![ + Sr25519Keyring::Alice, + Sr25519Keyring::Bob, + Sr25519Keyring::Charlie, + Sr25519Keyring::Dave, + Sr25519Keyring::Eve, + ]; + let session_info = SessionInfo { + validator_groups: IndexedVec::>::from(vec![ + vec![validator0, validator1], + vec![validator2], + vec![validator3], + ]), + needed_approvals: 1, + zeroth_delay_tranche_width: 1, + relay_vrf_modulo_samples: 1, + n_delay_tranches: 1, + no_show_slots: 1, + ..session_info(&validators) + }; + + ChainBuilder::new() + .add_block( + block_hash, + ChainBuilder::GENESIS_HASH, + 1, + BlockConfig { + slot: Slot::from(0), + candidates: Some(vec![ + (candidate_receipt0.clone(), CoreIndex(2), GroupIndex(2)), + (candidate_receipt1.clone(), CoreIndex(1), GroupIndex(0)), + (candidate_receipt2.clone(), CoreIndex(0), GroupIndex(1)), + ]), + session_info: Some(session_info), + end_syncing: true, + }, + ) + .build(&mut virtual_overseer) + .await; + + assert_eq!(clock.inner.lock().next_wakeup().unwrap(), 2); + clock.inner.lock().wakeup_all(100); + + assert_eq!(clock.inner.lock().wakeups.len(), 0); + + futures_timer::Delay::new(Duration::from_millis(100)).await; + + // Assignment is distributed only once from `approval-voting` + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeAssignment( + _, + c_indices, + )) => { + assert_eq!(c_indices, vec![candidate_index0, candidate_index1, candidate_index2].try_into().unwrap()); + } + ); + + // Candidate 0 + recover_available_data(&mut virtual_overseer).await; + fetch_validation_code(&mut virtual_overseer).await; + + // Candidate 1 + recover_available_data(&mut virtual_overseer).await; + fetch_validation_code(&mut virtual_overseer).await; + + // Candidate 2 + recover_available_data(&mut virtual_overseer).await; + fetch_validation_code(&mut virtual_overseer).await; + + // Check if assignment was triggered for candidate 0. + let candidate_entry = + store.load_candidate_entry(&candidate_receipt0.hash()).unwrap().unwrap(); + let our_assignment = + candidate_entry.approval_entry(&block_hash).unwrap().our_assignment().unwrap(); + assert!(our_assignment.triggered()); + + // Check if assignment was triggered for candidate 1. + let candidate_entry = + store.load_candidate_entry(&candidate_receipt1.hash()).unwrap().unwrap(); + let our_assignment = + candidate_entry.approval_entry(&block_hash).unwrap().our_assignment().unwrap(); + assert!(our_assignment.triggered()); + + // Check if assignment was triggered for candidate 2. + let candidate_entry = + store.load_candidate_entry(&candidate_receipt2.hash()).unwrap().unwrap(); + let our_assignment = + candidate_entry.approval_entry(&block_hash).unwrap().our_assignment().unwrap(); + assert!(our_assignment.triggered()); + + virtual_overseer + }); +} + fn approved_ancestor_test( skip_approval: impl Fn(BlockNumber) -> bool, approved_height: BlockNumber, -- GitLab From f394477988ac8b610862565c31dc7d3a96d73122 Mon Sep 17 00:00:00 2001 From: Javier Viola <363911+pepoviola@users.noreply.github.com> Date: Wed, 27 Mar 2024 03:45:29 +0100 Subject: [PATCH 103/187] chore: bump zombienet version (#3830) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bump version to `1.3.97` (follow up from https://github.com/paritytech/polkadot-sdk/pull/3805) --------- Co-authored-by: Bastian Köcher --- .gitlab/pipeline/zombienet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab/pipeline/zombienet.yml b/.gitlab/pipeline/zombienet.yml index 8d308714fab..82341eb709f 100644 --- a/.gitlab/pipeline/zombienet.yml +++ b/.gitlab/pipeline/zombienet.yml @@ -1,7 +1,7 @@ .zombienet-refs: extends: .build-refs variables: - ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.95" + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.98" include: # substrate tests -- GitLab From 66051adb619d2119771920218e2de75fa037d7e8 Mon Sep 17 00:00:00 2001 From: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Date: Wed, 27 Mar 2024 06:16:03 +0200 Subject: [PATCH 104/187] testnet genesis: enable approval voting v2 assignments and coalescing (#3827) This is a long due chore ... --------- Signed-off-by: Andrei Sandu Co-authored-by: ordian --- polkadot/node/service/src/chain_spec.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/polkadot/node/service/src/chain_spec.rs b/polkadot/node/service/src/chain_spec.rs index 1c44b17b6fd..c03ce1db094 100644 --- a/polkadot/node/service/src/chain_spec.rs +++ b/polkadot/node/service/src/chain_spec.rs @@ -123,7 +123,8 @@ fn default_parachains_host_configuration( ) -> polkadot_runtime_parachains::configuration::HostConfiguration { use polkadot_primitives::{ - vstaging::node_features::FeatureIndex, AsyncBackingParams, MAX_CODE_SIZE, MAX_POV_SIZE, + vstaging::{node_features::FeatureIndex, ApprovalVotingParams}, + AsyncBackingParams, MAX_CODE_SIZE, MAX_POV_SIZE, }; polkadot_runtime_parachains::configuration::HostConfiguration { @@ -158,7 +159,8 @@ fn default_parachains_host_configuration( allowed_ancestry_len: 2, }, node_features: bitvec::vec::BitVec::from_element( - 1u8 << (FeatureIndex::ElasticScalingMVP as usize), + 1u8 << (FeatureIndex::ElasticScalingMVP as usize) | + 1u8 << (FeatureIndex::EnableAssignmentsV2 as usize), ), scheduler_params: SchedulerParams { lookahead: 2, @@ -166,6 +168,7 @@ fn default_parachains_host_configuration( paras_availability_period: 4, ..Default::default() }, + approval_voting_params: ApprovalVotingParams { max_approval_coalesce_count: 5 }, ..Default::default() } } -- GitLab From feee773d15d5237765b520b03854d46652181de5 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Wed, 27 Mar 2024 09:31:01 +0100 Subject: [PATCH 105/187] pallet-xcm: Deprecate `execute` and `send` in favor of `execute_blob` and `send_blob` (#3749) `execute` and `send` try to decode the xcm in the parameters before reaching the filter line. The new extrinsics decode only after the filter line. These should be used instead of the old ones. ## TODO - [x] Tests - [x] Generate weights - [x] Deprecation issue -> https://github.com/paritytech/polkadot-sdk/issues/3771 - [x] PRDoc - [x] Handle error in pallet-contracts This would make writing XCMs in PJS Apps more difficult, but here's the fix for that: https://github.com/polkadot-js/apps/pull/10350. Already deployed! https://polkadot.js.org/apps/#/utilities/xcm Supersedes https://github.com/paritytech/polkadot-sdk/pull/1798/ --------- Co-authored-by: PG Herveou Co-authored-by: command-bot <> Co-authored-by: Adrian Catangiu --- Cargo.lock | 1 + .../emulated/chains/relays/westend/Cargo.toml | 1 - .../emulated/common/src/impls.rs | 6 +- .../assets/asset-hub-rococo/src/tests/send.rs | 8 +- .../assets/asset-hub-rococo/src/tests/swap.rs | 4 +- .../asset-hub-westend/src/tests/send.rs | 8 +- .../asset-hub-westend/src/tests/swap.rs | 4 +- .../bridge-hub-rococo/src/tests/send_xcm.rs | 7 +- .../bridge-hub-rococo/src/tests/snowbridge.rs | 18 +- .../bridges/bridge-hub-westend/Cargo.toml | 1 + .../bridge-hub-westend/src/tests/send_xcm.rs | 7 +- .../src/weights/pallet_xcm.rs | 112 ++++++---- .../src/weights/pallet_xcm.rs | 114 ++++++---- .../src/weights/pallet_xcm.rs | 108 ++++++---- .../src/weights/pallet_xcm.rs | 108 ++++++---- .../src/weights/pallet_xcm.rs | 106 +++++---- .../coretime-rococo/src/weights/pallet_xcm.rs | 102 +++++---- .../src/weights/pallet_xcm.rs | 102 +++++---- .../people-rococo/src/weights/pallet_xcm.rs | 102 +++++---- .../people-westend/src/weights/pallet_xcm.rs | 102 +++++---- polkadot/runtime/rococo/src/impls.rs | 9 +- .../runtime/rococo/src/weights/pallet_xcm.rs | 110 ++++++---- polkadot/runtime/westend/src/impls.rs | 9 +- .../runtime/westend/src/weights/pallet_xcm.rs | 108 ++++++---- polkadot/xcm/pallet-xcm/src/benchmarking.rs | 29 +++ polkadot/xcm/pallet-xcm/src/lib.rs | 202 +++++++++++++----- polkadot/xcm/pallet-xcm/src/tests/mod.rs | 77 ++++--- polkadot/xcm/src/lib.rs | 3 + polkadot/xcm/src/v4/mod.rs | 20 +- polkadot/xcm/xcm-builder/src/controller.rs | 39 ++-- polkadot/xcm/xcm-builder/src/lib.rs | 2 +- prdoc/pr_3749.prdoc | 47 ++++ .../frame/contracts/mock-network/src/tests.rs | 40 +--- substrate/frame/contracts/src/lib.rs | 3 + substrate/frame/contracts/src/wasm/runtime.rs | 54 +---- substrate/frame/contracts/uapi/src/host.rs | 2 +- 36 files changed, 1133 insertions(+), 642 deletions(-) create mode 100644 prdoc/pr_3749.prdoc diff --git a/Cargo.lock b/Cargo.lock index f246a978fd2..2382dc8d162 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2148,6 +2148,7 @@ dependencies = [ "pallet-message-queue", "pallet-xcm", "parachains-common", + "parity-scale-codec", "rococo-westend-system-emulated-network", "sp-runtime", "staging-xcm", diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml index 20aedb50e6a..12a3ad60e0e 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml @@ -11,7 +11,6 @@ publish = false workspace = true [dependencies] - # Substrate sp-core = { path = "../../../../../../../substrate/primitives/core", default-features = false } sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false } diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index ae69bf991e5..618c3addc5d 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -362,7 +362,7 @@ macro_rules! impl_send_transact_helpers_for_relay_chain { recipient: $crate::impls::ParaId, call: $crate::impls::DoubleEncoded<()> ) { - use $crate::impls::{bx, Chain, RelayChain}; + use $crate::impls::{bx, Chain, RelayChain, Encode}; ::execute_with(|| { let root_origin = ::RuntimeOrigin::root(); @@ -370,10 +370,10 @@ macro_rules! impl_send_transact_helpers_for_relay_chain { let xcm = $crate::impls::xcm_transact_unpaid_execution(call, $crate::impls::OriginKind::Superuser); // Send XCM `Transact` - $crate::impls::assert_ok!(]>::XcmPallet::send( + $crate::impls::assert_ok!(]>::XcmPallet::send_blob( root_origin, bx!(destination.into()), - bx!(xcm), + xcm.encode().try_into().unwrap(), )); Self::assert_xcm_pallet_sent(); }); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs index 364fbd0d439..1d120f1dc4c 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs @@ -75,10 +75,10 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_system_assets_works() { )]); PenpalA::execute_with(|| { - assert_ok!(::PolkadotXcm::send( + assert_ok!(::PolkadotXcm::send_blob( root_origin, bx!(system_para_destination), - bx!(xcm), + xcm.encode().try_into().unwrap(), )); PenpalA::assert_xcm_pallet_sent(); @@ -159,10 +159,10 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { )]); PenpalA::execute_with(|| { - assert_ok!(::PolkadotXcm::send( + assert_ok!(::PolkadotXcm::send_blob( root_origin, bx!(system_para_destination), - bx!(xcm), + xcm.encode().try_into().unwrap(), )); PenpalA::assert_xcm_pallet_sent(); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs index 87f0b3d9f90..e13300b7c11 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs @@ -370,10 +370,10 @@ fn pay_xcm_fee_with_some_asset_swapped_for_native() { penpal.clone(), ); - assert_ok!(::PolkadotXcm::send( + assert_ok!(::PolkadotXcm::send_blob( penpal_root, bx!(asset_hub_location), - bx!(xcm), + xcm.encode().try_into().unwrap(), )); PenpalA::assert_xcm_pallet_sent(); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs index eb0e985cc0c..f218b539c38 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs @@ -75,10 +75,10 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_system_assets_works() { )]); PenpalA::execute_with(|| { - assert_ok!(::PolkadotXcm::send( + assert_ok!(::PolkadotXcm::send_blob( root_origin, bx!(system_para_destination), - bx!(xcm), + xcm.encode().try_into().unwrap(), )); PenpalA::assert_xcm_pallet_sent(); @@ -159,10 +159,10 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { )]); PenpalA::execute_with(|| { - assert_ok!(::PolkadotXcm::send( + assert_ok!(::PolkadotXcm::send_blob( root_origin, bx!(system_para_destination), - bx!(xcm), + xcm.encode().try_into().unwrap(), )); PenpalA::assert_xcm_pallet_sent(); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs index 04740d31158..aa673c03483 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs @@ -369,10 +369,10 @@ fn pay_xcm_fee_with_some_asset_swapped_for_native() { penpal.clone(), ); - assert_ok!(::PolkadotXcm::send( + assert_ok!(::PolkadotXcm::send_blob( penpal_root, bx!(asset_hub_location), - bx!(xcm), + xcm.encode().try_into().unwrap(), )); PenpalA::assert_xcm_pallet_sent(); diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs index a1d871cdb61..4bd041dc03f 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs @@ -14,6 +14,7 @@ // limitations under the License. use crate::tests::*; +use codec::Encode; #[test] fn send_xcm_from_rococo_relay_to_westend_asset_hub_should_fail_on_not_applicable() { @@ -26,7 +27,7 @@ fn send_xcm_from_rococo_relay_to_westend_asset_hub_should_fail_on_not_applicable let remote_xcm = Xcm(vec![ClearOrigin]); - let xcm = VersionedXcm::from(Xcm(vec![ + let xcm = VersionedXcm::from(Xcm::<()>(vec![ UnpaidExecution { weight_limit, check_origin }, ExportMessage { network: WestendId.into(), @@ -38,10 +39,10 @@ fn send_xcm_from_rococo_relay_to_westend_asset_hub_should_fail_on_not_applicable // Rococo Global Consensus // Send XCM message from Relay Chain to Bridge Hub source Parachain Rococo::execute_with(|| { - assert_ok!(::XcmPallet::send( + assert_ok!(::XcmPallet::send_blob( sudo_origin, bx!(destination), - bx!(xcm), + xcm.encode().try_into().unwrap(), )); type RuntimeEvent = ::RuntimeEvent; diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs index 26b82375e07..caaf24e00a8 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs @@ -83,7 +83,7 @@ fn create_agent() { let create_agent_call = SnowbridgeControl::Control(ControlCall::CreateAgent {}); // Construct XCM to create an agent for para 1001 - let remote_xcm = VersionedXcm::from(Xcm(vec![ + let remote_xcm = VersionedXcm::from(Xcm::<()>(vec![ UnpaidExecution { weight_limit: Unlimited, check_origin: None }, DescendOrigin(Parachain(origin_para).into()), Transact { @@ -96,10 +96,10 @@ fn create_agent() { // Rococo Global Consensus // Send XCM message from Relay Chain to Bridge Hub source Parachain Rococo::execute_with(|| { - assert_ok!(::XcmPallet::send( + assert_ok!(::XcmPallet::send_blob( sudo_origin, bx!(destination), - bx!(remote_xcm), + remote_xcm.encode().try_into().unwrap(), )); type RuntimeEvent = ::RuntimeEvent; @@ -141,7 +141,7 @@ fn create_channel() { let create_agent_call = SnowbridgeControl::Control(ControlCall::CreateAgent {}); // Construct XCM to create an agent for para 1001 - let create_agent_xcm = VersionedXcm::from(Xcm(vec![ + let create_agent_xcm = VersionedXcm::from(Xcm::<()>(vec![ UnpaidExecution { weight_limit: Unlimited, check_origin: None }, DescendOrigin(Parachain(origin_para).into()), Transact { @@ -154,7 +154,7 @@ fn create_channel() { let create_channel_call = SnowbridgeControl::Control(ControlCall::CreateChannel { mode: OperatingMode::Normal }); // Construct XCM to create a channel for para 1001 - let create_channel_xcm = VersionedXcm::from(Xcm(vec![ + let create_channel_xcm = VersionedXcm::from(Xcm::<()>(vec![ UnpaidExecution { weight_limit: Unlimited, check_origin: None }, DescendOrigin(Parachain(origin_para).into()), Transact { @@ -167,16 +167,16 @@ fn create_channel() { // Rococo Global Consensus // Send XCM message from Relay Chain to Bridge Hub source Parachain Rococo::execute_with(|| { - assert_ok!(::XcmPallet::send( + assert_ok!(::XcmPallet::send_blob( sudo_origin.clone(), bx!(destination.clone()), - bx!(create_agent_xcm), + create_agent_xcm.encode().try_into().unwrap(), )); - assert_ok!(::XcmPallet::send( + assert_ok!(::XcmPallet::send_blob( sudo_origin, bx!(destination), - bx!(create_channel_xcm), + create_channel_xcm.encode().try_into().unwrap(), )); type RuntimeEvent = ::RuntimeEvent; diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml index 9059d841a48..9c45a7adeb4 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml @@ -11,6 +11,7 @@ publish = false workspace = true [dependencies] +codec = { package = "parity-scale-codec", version = "3.6.0" } # Substrate frame-support = { path = "../../../../../../../substrate/frame/support", default-features = false } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs index b01be5e8dc8..f69747c1770 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs @@ -14,6 +14,7 @@ // limitations under the License. use crate::tests::*; +use codec::Encode; #[test] fn send_xcm_from_westend_relay_to_rococo_asset_hub_should_fail_on_not_applicable() { @@ -26,7 +27,7 @@ fn send_xcm_from_westend_relay_to_rococo_asset_hub_should_fail_on_not_applicable let remote_xcm = Xcm(vec![ClearOrigin]); - let xcm = VersionedXcm::from(Xcm(vec![ + let xcm = VersionedXcm::from(Xcm::<()>(vec![ UnpaidExecution { weight_limit, check_origin }, ExportMessage { network: RococoId, @@ -38,10 +39,10 @@ fn send_xcm_from_westend_relay_to_rococo_asset_hub_should_fail_on_not_applicable // Westend Global Consensus // Send XCM message from Relay Chain to Bridge Hub source Parachain Westend::execute_with(|| { - assert_ok!(::XcmPallet::send( + assert_ok!(::XcmPallet::send_blob( sudo_origin, bx!(destination), - bx!(xcm), + xcm.encode().try_into().unwrap(), )); type RuntimeEvent = ::RuntimeEvent; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs index 51b6543bae8..e0e231d7da2 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -64,8 +64,30 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 22_136_000 picoseconds. - Weight::from_parts(22_518_000, 0) + // Minimum execution time: 21_224_000 picoseconds. + Weight::from_parts(21_821_000, 0) + .saturating_add(Weight::from_parts(0, 3610)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn send_blob() -> Weight { + // Proof Size summary in bytes: + // Measured: `145` + // Estimated: `3610` + // Minimum execution time: 21_474_000 picoseconds. + Weight::from_parts(22_072_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) @@ -90,8 +112,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 92_277_000 picoseconds. - Weight::from_parts(94_843_000, 0) + // Minimum execution time: 90_677_000 picoseconds. + Weight::from_parts(93_658_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -118,8 +140,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `400` // Estimated: `6196` - // Minimum execution time: 120_110_000 picoseconds. - Weight::from_parts(122_968_000, 0) + // Minimum execution time: 116_767_000 picoseconds. + Weight::from_parts(118_843_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(5)) @@ -148,8 +170,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `496` // Estimated: `6208` - // Minimum execution time: 143_116_000 picoseconds. - Weight::from_parts(147_355_000, 0) + // Minimum execution time: 137_983_000 picoseconds. + Weight::from_parts(141_396_000, 0) .saturating_add(Weight::from_parts(0, 6208)) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(7)) @@ -164,14 +186,24 @@ impl pallet_xcm::WeightInfo for WeightInfo { Weight::from_parts(18_446_744_073_709_551_000, 0) .saturating_add(Weight::from_parts(0, 0)) } + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn execute_blob() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_xcm_version() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_517_000 picoseconds. - Weight::from_parts(6_756_000, 0) + // Minimum execution time: 6_232_000 picoseconds. + Weight::from_parts(6_507_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -181,8 +213,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_894_000 picoseconds. - Weight::from_parts(2_024_000, 0) + // Minimum execution time: 1_884_000 picoseconds. + Weight::from_parts(2_016_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -208,8 +240,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 27_314_000 picoseconds. - Weight::from_parts(28_787_000, 0) + // Minimum execution time: 26_637_000 picoseconds. + Weight::from_parts(27_616_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) @@ -234,8 +266,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `363` // Estimated: `3828` - // Minimum execution time: 29_840_000 picoseconds. - Weight::from_parts(30_589_000, 0) + // Minimum execution time: 28_668_000 picoseconds. + Weight::from_parts(29_413_000, 0) .saturating_add(Weight::from_parts(0, 3828)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -246,8 +278,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_893_000 picoseconds. - Weight::from_parts(2_017_000, 0) + // Minimum execution time: 1_990_000 picoseconds. + Weight::from_parts(2_114_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -257,8 +289,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `159` // Estimated: `13524` - // Minimum execution time: 19_211_000 picoseconds. - Weight::from_parts(19_552_000, 0) + // Minimum execution time: 18_856_000 picoseconds. + Weight::from_parts(19_430_000, 0) .saturating_add(Weight::from_parts(0, 13524)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -269,8 +301,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `163` // Estimated: `13528` - // Minimum execution time: 19_177_000 picoseconds. - Weight::from_parts(19_704_000, 0) + // Minimum execution time: 19_068_000 picoseconds. + Weight::from_parts(19_434_000, 0) .saturating_add(Weight::from_parts(0, 13528)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -281,8 +313,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `173` // Estimated: `16013` - // Minimum execution time: 20_449_000 picoseconds. - Weight::from_parts(21_075_000, 0) + // Minimum execution time: 21_055_000 picoseconds. + Weight::from_parts(21_379_000, 0) .saturating_add(Weight::from_parts(0, 16013)) .saturating_add(T::DbWeight::get().reads(6)) } @@ -304,8 +336,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `212` // Estimated: `6152` - // Minimum execution time: 26_578_000 picoseconds. - Weight::from_parts(27_545_000, 0) + // Minimum execution time: 25_736_000 picoseconds. + Weight::from_parts(26_423_000, 0) .saturating_add(Weight::from_parts(0, 6152)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -316,8 +348,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `206` // Estimated: `11096` - // Minimum execution time: 11_646_000 picoseconds. - Weight::from_parts(11_944_000, 0) + // Minimum execution time: 11_853_000 picoseconds. + Weight::from_parts(12_215_000, 0) .saturating_add(Weight::from_parts(0, 11096)) .saturating_add(T::DbWeight::get().reads(4)) } @@ -327,8 +359,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `170` // Estimated: `13535` - // Minimum execution time: 19_301_000 picoseconds. - Weight::from_parts(19_664_000, 0) + // Minimum execution time: 19_418_000 picoseconds. + Weight::from_parts(19_794_000, 0) .saturating_add(Weight::from_parts(0, 13535)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -351,8 +383,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `212` // Estimated: `13577` - // Minimum execution time: 35_715_000 picoseconds. - Weight::from_parts(36_915_000, 0) + // Minimum execution time: 34_719_000 picoseconds. + Weight::from_parts(35_260_000, 0) .saturating_add(Weight::from_parts(0, 13577)) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(4)) @@ -365,8 +397,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `1588` - // Minimum execution time: 4_871_000 picoseconds. - Weight::from_parts(5_066_000, 0) + // Minimum execution time: 4_937_000 picoseconds. + Weight::from_parts(5_203_000, 0) .saturating_add(Weight::from_parts(0, 1588)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -377,8 +409,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7740` // Estimated: `11205` - // Minimum execution time: 25_150_000 picoseconds. - Weight::from_parts(26_119_000, 0) + // Minimum execution time: 26_064_000 picoseconds. + Weight::from_parts(26_497_000, 0) .saturating_add(Weight::from_parts(0, 11205)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -389,8 +421,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `160` // Estimated: `3625` - // Minimum execution time: 38_248_000 picoseconds. - Weight::from_parts(39_122_000, 0) + // Minimum execution time: 37_132_000 picoseconds. + Weight::from_parts(37_868_000, 0) .saturating_add(Weight::from_parts(0, 3625)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs index 71facff87d3..299e4b8b3cd 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -64,8 +64,30 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 21_630_000 picoseconds. - Weight::from_parts(22_306_000, 0) + // Minimum execution time: 21_722_000 picoseconds. + Weight::from_parts(22_253_000, 0) + .saturating_add(Weight::from_parts(0, 3610)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn send_blob() -> Weight { + // Proof Size summary in bytes: + // Measured: `145` + // Estimated: `3610` + // Minimum execution time: 21_694_000 picoseconds. + Weight::from_parts(22_326_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) @@ -90,8 +112,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 91_802_000 picoseconds. - Weight::from_parts(93_672_000, 0) + // Minimum execution time: 94_422_000 picoseconds. + Weight::from_parts(96_997_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -118,8 +140,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `367` // Estimated: `6196` - // Minimum execution time: 118_930_000 picoseconds. - Weight::from_parts(122_306_000, 0) + // Minimum execution time: 123_368_000 picoseconds. + Weight::from_parts(125_798_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(5)) @@ -148,8 +170,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `496` // Estimated: `6208` - // Minimum execution time: 140_527_000 picoseconds. - Weight::from_parts(144_501_000, 0) + // Minimum execution time: 142_033_000 picoseconds. + Weight::from_parts(145_702_000, 0) .saturating_add(Weight::from_parts(0, 6208)) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(7)) @@ -158,8 +180,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_556_000 picoseconds. - Weight::from_parts(7_798_000, 0) + // Minimum execution time: 7_558_000 picoseconds. + Weight::from_parts(7_916_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn execute_blob() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_978_000 picoseconds. + Weight::from_parts(8_210_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) @@ -168,8 +198,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_373_000 picoseconds. - Weight::from_parts(6_603_000, 0) + // Minimum execution time: 6_439_000 picoseconds. + Weight::from_parts(6_711_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -179,8 +209,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_941_000 picoseconds. - Weight::from_parts(2_088_000, 0) + // Minimum execution time: 1_982_000 picoseconds. + Weight::from_parts(2_260_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -206,8 +236,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 27_080_000 picoseconds. - Weight::from_parts(27_820_000, 0) + // Minimum execution time: 27_120_000 picoseconds. + Weight::from_parts(28_048_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) @@ -232,8 +262,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `363` // Estimated: `3828` - // Minimum execution time: 28_850_000 picoseconds. - Weight::from_parts(29_506_000, 0) + // Minimum execution time: 29_354_000 picoseconds. + Weight::from_parts(30_205_000, 0) .saturating_add(Weight::from_parts(0, 3828)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -244,8 +274,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_033_000 picoseconds. - Weight::from_parts(2_201_000, 0) + // Minimum execution time: 1_926_000 picoseconds. + Weight::from_parts(2_013_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -255,8 +285,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `159` // Estimated: `13524` - // Minimum execution time: 18_844_000 picoseconds. - Weight::from_parts(19_197_000, 0) + // Minimum execution time: 18_611_000 picoseconds. + Weight::from_parts(19_120_000, 0) .saturating_add(Weight::from_parts(0, 13524)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -267,8 +297,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `163` // Estimated: `13528` - // Minimum execution time: 18_940_000 picoseconds. - Weight::from_parts(19_450_000, 0) + // Minimum execution time: 18_373_000 picoseconds. + Weight::from_parts(18_945_000, 0) .saturating_add(Weight::from_parts(0, 13528)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -279,8 +309,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `173` // Estimated: `16013` - // Minimum execution time: 20_521_000 picoseconds. - Weight::from_parts(21_076_000, 0) + // Minimum execution time: 20_459_000 picoseconds. + Weight::from_parts(20_951_000, 0) .saturating_add(Weight::from_parts(0, 16013)) .saturating_add(T::DbWeight::get().reads(6)) } @@ -302,8 +332,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `212` // Estimated: `6152` - // Minimum execution time: 26_007_000 picoseconds. - Weight::from_parts(26_448_000, 0) + // Minimum execution time: 26_003_000 picoseconds. + Weight::from_parts(26_678_000, 0) .saturating_add(Weight::from_parts(0, 6152)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -314,8 +344,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `206` // Estimated: `11096` - // Minimum execution time: 11_584_000 picoseconds. - Weight::from_parts(12_080_000, 0) + // Minimum execution time: 11_557_000 picoseconds. + Weight::from_parts(11_868_000, 0) .saturating_add(Weight::from_parts(0, 11096)) .saturating_add(T::DbWeight::get().reads(4)) } @@ -325,8 +355,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `170` // Estimated: `13535` - // Minimum execution time: 19_157_000 picoseconds. - Weight::from_parts(19_513_000, 0) + // Minimum execution time: 18_710_000 picoseconds. + Weight::from_parts(19_240_000, 0) .saturating_add(Weight::from_parts(0, 13535)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -349,8 +379,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `212` // Estimated: `13577` - // Minimum execution time: 34_878_000 picoseconds. - Weight::from_parts(35_623_000, 0) + // Minimum execution time: 34_393_000 picoseconds. + Weight::from_parts(35_138_000, 0) .saturating_add(Weight::from_parts(0, 13577)) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(4)) @@ -363,8 +393,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `1588` - // Minimum execution time: 3_900_000 picoseconds. - Weight::from_parts(4_161_000, 0) + // Minimum execution time: 4_043_000 picoseconds. + Weight::from_parts(4_216_000, 0) .saturating_add(Weight::from_parts(0, 1588)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -375,8 +405,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7740` // Estimated: `11205` - // Minimum execution time: 25_731_000 picoseconds. - Weight::from_parts(26_160_000, 0) + // Minimum execution time: 25_410_000 picoseconds. + Weight::from_parts(26_019_000, 0) .saturating_add(Weight::from_parts(0, 11205)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -387,8 +417,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `160` // Estimated: `3625` - // Minimum execution time: 37_251_000 picoseconds. - Weight::from_parts(38_075_000, 0) + // Minimum execution time: 38_850_000 picoseconds. + Weight::from_parts(39_593_000, 0) .saturating_add(Weight::from_parts(0, 3625)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs index a732e1a5734..adfaa9ea202 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -64,8 +64,30 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 18_513_000 picoseconds. - Weight::from_parts(19_156_000, 0) + // Minimum execution time: 18_732_000 picoseconds. + Weight::from_parts(19_386_000, 0) + .saturating_add(Weight::from_parts(0, 3503)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn send_blob() -> Weight { + // Proof Size summary in bytes: + // Measured: `38` + // Estimated: `3503` + // Minimum execution time: 18_943_000 picoseconds. + Weight::from_parts(19_455_000, 0) .saturating_add(Weight::from_parts(0, 3503)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) @@ -90,8 +112,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3593` - // Minimum execution time: 88_096_000 picoseconds. - Weight::from_parts(89_732_000, 0) + // Minimum execution time: 88_917_000 picoseconds. + Weight::from_parts(91_611_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -126,8 +148,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3593` - // Minimum execution time: 88_239_000 picoseconds. - Weight::from_parts(89_729_000, 0) + // Minimum execution time: 88_587_000 picoseconds. + Weight::from_parts(90_303_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -142,14 +164,24 @@ impl pallet_xcm::WeightInfo for WeightInfo { Weight::from_parts(18_446_744_073_709_551_000, 0) .saturating_add(Weight::from_parts(0, 0)) } + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn execute_blob() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_xcm_version() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_955_000 picoseconds. - Weight::from_parts(6_266_000, 0) + // Minimum execution time: 5_856_000 picoseconds. + Weight::from_parts(6_202_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -159,8 +191,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_868_000 picoseconds. - Weight::from_parts(1_961_000, 0) + // Minimum execution time: 1_797_000 picoseconds. + Weight::from_parts(1_970_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -186,8 +218,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 24_388_000 picoseconds. - Weight::from_parts(25_072_000, 0) + // Minimum execution time: 24_479_000 picoseconds. + Weight::from_parts(25_058_000, 0) .saturating_add(Weight::from_parts(0, 3503)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) @@ -212,8 +244,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `255` // Estimated: `3720` - // Minimum execution time: 26_762_000 picoseconds. - Weight::from_parts(27_631_000, 0) + // Minimum execution time: 27_282_000 picoseconds. + Weight::from_parts(27_924_000, 0) .saturating_add(Weight::from_parts(0, 3720)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -224,8 +256,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_856_000 picoseconds. - Weight::from_parts(2_033_000, 0) + // Minimum execution time: 1_801_000 picoseconds. + Weight::from_parts(1_988_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -235,8 +267,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `89` // Estimated: `13454` - // Minimum execution time: 17_718_000 picoseconds. - Weight::from_parts(18_208_000, 0) + // Minimum execution time: 16_509_000 picoseconds. + Weight::from_parts(16_939_000, 0) .saturating_add(Weight::from_parts(0, 13454)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -247,8 +279,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `93` // Estimated: `13458` - // Minimum execution time: 17_597_000 picoseconds. - Weight::from_parts(18_090_000, 0) + // Minimum execution time: 16_140_000 picoseconds. + Weight::from_parts(16_843_000, 0) .saturating_add(Weight::from_parts(0, 13458)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -259,8 +291,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `15946` - // Minimum execution time: 19_533_000 picoseconds. - Weight::from_parts(20_164_000, 0) + // Minimum execution time: 18_160_000 picoseconds. + Weight::from_parts(18_948_000, 0) .saturating_add(Weight::from_parts(0, 15946)) .saturating_add(T::DbWeight::get().reads(6)) } @@ -282,8 +314,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `6046` - // Minimum execution time: 24_958_000 picoseconds. - Weight::from_parts(25_628_000, 0) + // Minimum execution time: 24_409_000 picoseconds. + Weight::from_parts(25_261_000, 0) .saturating_add(Weight::from_parts(0, 6046)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -294,8 +326,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `136` // Estimated: `11026` - // Minimum execution time: 12_209_000 picoseconds. - Weight::from_parts(12_612_000, 0) + // Minimum execution time: 10_848_000 picoseconds. + Weight::from_parts(11_241_000, 0) .saturating_add(Weight::from_parts(0, 11026)) .saturating_add(T::DbWeight::get().reads(4)) } @@ -305,8 +337,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `100` // Estimated: `13465` - // Minimum execution time: 17_844_000 picoseconds. - Weight::from_parts(18_266_000, 0) + // Minimum execution time: 16_609_000 picoseconds. + Weight::from_parts(17_044_000, 0) .saturating_add(Weight::from_parts(0, 13465)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -329,8 +361,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `13471` - // Minimum execution time: 34_131_000 picoseconds. - Weight::from_parts(34_766_000, 0) + // Minimum execution time: 32_500_000 picoseconds. + Weight::from_parts(33_475_000, 0) .saturating_add(Weight::from_parts(0, 13471)) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(4)) @@ -343,8 +375,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1517` - // Minimum execution time: 3_525_000 picoseconds. - Weight::from_parts(3_724_000, 0) + // Minimum execution time: 3_484_000 picoseconds. + Weight::from_parts(3_673_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -355,8 +387,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7669` // Estimated: `11134` - // Minimum execution time: 24_975_000 picoseconds. - Weight::from_parts(25_517_000, 0) + // Minimum execution time: 25_225_000 picoseconds. + Weight::from_parts(25_731_000, 0) .saturating_add(Weight::from_parts(0, 11134)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -367,8 +399,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 33_761_000 picoseconds. - Weight::from_parts(34_674_000, 0) + // Minimum execution time: 33_961_000 picoseconds. + Weight::from_parts(34_818_000, 0) .saturating_add(Weight::from_parts(0, 3555)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs index a78ff2355ef..9cf4c61466a 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-03-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -64,8 +64,30 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 19_527_000 picoseconds. - Weight::from_parts(19_839_000, 0) + // Minimum execution time: 19_702_000 picoseconds. + Weight::from_parts(20_410_000, 0) + .saturating_add(Weight::from_parts(0, 3503)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn send_blob() -> Weight { + // Proof Size summary in bytes: + // Measured: `38` + // Estimated: `3503` + // Minimum execution time: 19_525_000 picoseconds. + Weight::from_parts(20_071_000, 0) .saturating_add(Weight::from_parts(0, 3503)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) @@ -90,8 +112,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `107` // Estimated: `3593` - // Minimum execution time: 90_938_000 picoseconds. - Weight::from_parts(92_822_000, 0) + // Minimum execution time: 91_793_000 picoseconds. + Weight::from_parts(93_761_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -126,8 +148,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `107` // Estimated: `3593` - // Minimum execution time: 90_133_000 picoseconds. - Weight::from_parts(92_308_000, 0) + // Minimum execution time: 91_819_000 picoseconds. + Weight::from_parts(93_198_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -142,14 +164,24 @@ impl pallet_xcm::WeightInfo for WeightInfo { Weight::from_parts(18_446_744_073_709_551_000, 0) .saturating_add(Weight::from_parts(0, 0)) } + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn execute_blob() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_xcm_version() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_205_000 picoseconds. - Weight::from_parts(6_595_000, 0) + // Minimum execution time: 6_183_000 picoseconds. + Weight::from_parts(6_598_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -159,8 +191,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_927_000 picoseconds. - Weight::from_parts(2_062_000, 0) + // Minimum execution time: 1_987_000 picoseconds. + Weight::from_parts(2_076_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -186,8 +218,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 25_078_000 picoseconds. - Weight::from_parts(25_782_000, 0) + // Minimum execution time: 25_375_000 picoseconds. + Weight::from_parts(26_165_000, 0) .saturating_add(Weight::from_parts(0, 3503)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) @@ -212,8 +244,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `255` // Estimated: `3720` - // Minimum execution time: 28_188_000 picoseconds. - Weight::from_parts(28_826_000, 0) + // Minimum execution time: 28_167_000 picoseconds. + Weight::from_parts(28_792_000, 0) .saturating_add(Weight::from_parts(0, 3720)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -224,8 +256,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_886_000 picoseconds. - Weight::from_parts(1_991_000, 0) + // Minimum execution time: 2_039_000 picoseconds. + Weight::from_parts(2_211_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -235,8 +267,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `89` // Estimated: `13454` - // Minimum execution time: 17_443_000 picoseconds. - Weight::from_parts(17_964_000, 0) + // Minimum execution time: 17_127_000 picoseconds. + Weight::from_parts(17_519_000, 0) .saturating_add(Weight::from_parts(0, 13454)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -247,8 +279,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `93` // Estimated: `13458` - // Minimum execution time: 17_357_000 picoseconds. - Weight::from_parts(18_006_000, 0) + // Minimum execution time: 16_701_000 picoseconds. + Weight::from_parts(17_250_000, 0) .saturating_add(Weight::from_parts(0, 13458)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -259,8 +291,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `15946` - // Minimum execution time: 18_838_000 picoseconds. - Weight::from_parts(19_688_000, 0) + // Minimum execution time: 18_795_000 picoseconds. + Weight::from_parts(19_302_000, 0) .saturating_add(Weight::from_parts(0, 15946)) .saturating_add(T::DbWeight::get().reads(6)) } @@ -282,8 +314,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `6046` - // Minimum execution time: 25_517_000 picoseconds. - Weight::from_parts(26_131_000, 0) + // Minimum execution time: 25_007_000 picoseconds. + Weight::from_parts(25_786_000, 0) .saturating_add(Weight::from_parts(0, 6046)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -294,8 +326,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `136` // Estimated: `11026` - // Minimum execution time: 11_587_000 picoseconds. - Weight::from_parts(11_963_000, 0) + // Minimum execution time: 11_534_000 picoseconds. + Weight::from_parts(11_798_000, 0) .saturating_add(Weight::from_parts(0, 11026)) .saturating_add(T::DbWeight::get().reads(4)) } @@ -305,8 +337,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `100` // Estimated: `13465` - // Minimum execution time: 17_490_000 picoseconds. - Weight::from_parts(18_160_000, 0) + // Minimum execution time: 17_357_000 picoseconds. + Weight::from_parts(17_629_000, 0) .saturating_add(Weight::from_parts(0, 13465)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -329,8 +361,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `13471` - // Minimum execution time: 34_088_000 picoseconds. - Weight::from_parts(34_598_000, 0) + // Minimum execution time: 33_487_000 picoseconds. + Weight::from_parts(34_033_000, 0) .saturating_add(Weight::from_parts(0, 13471)) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(4)) @@ -343,8 +375,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1517` - // Minimum execution time: 3_566_000 picoseconds. - Weight::from_parts(3_754_000, 0) + // Minimum execution time: 3_688_000 picoseconds. + Weight::from_parts(3_854_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -355,8 +387,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7669` // Estimated: `11134` - // Minimum execution time: 25_078_000 picoseconds. - Weight::from_parts(25_477_000, 0) + // Minimum execution time: 26_336_000 picoseconds. + Weight::from_parts(26_873_000, 0) .saturating_add(Weight::from_parts(0, 11134)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -367,8 +399,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 34_661_000 picoseconds. - Weight::from_parts(35_411_000, 0) + // Minimum execution time: 34_633_000 picoseconds. + Weight::from_parts(35_171_000, 0) .saturating_add(Weight::from_parts(0, 3555)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs index 5d427d85004..0edd5dfff2b 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -64,8 +64,30 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 21_813_000 picoseconds. - Weight::from_parts(22_332_000, 0) + // Minimum execution time: 21_911_000 picoseconds. + Weight::from_parts(22_431_000, 0) + .saturating_add(Weight::from_parts(0, 3610)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn send_blob() -> Weight { + // Proof Size summary in bytes: + // Measured: `145` + // Estimated: `3610` + // Minimum execution time: 22_143_000 picoseconds. + Weight::from_parts(22_843_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) @@ -90,8 +112,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `214` // Estimated: `3679` - // Minimum execution time: 93_243_000 picoseconds. - Weight::from_parts(95_650_000, 0) + // Minimum execution time: 96_273_000 picoseconds. + Weight::from_parts(98_351_000, 0) .saturating_add(Weight::from_parts(0, 3679)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -126,8 +148,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `214` // Estimated: `3679` - // Minimum execution time: 96_199_000 picoseconds. - Weight::from_parts(98_620_000, 0) + // Minimum execution time: 95_571_000 picoseconds. + Weight::from_parts(96_251_000, 0) .saturating_add(Weight::from_parts(0, 3679)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -142,14 +164,24 @@ impl pallet_xcm::WeightInfo for WeightInfo { Weight::from_parts(18_446_744_073_709_551_000, 0) .saturating_add(Weight::from_parts(0, 0)) } + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn execute_blob() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_xcm_version() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_442_000 picoseconds. - Weight::from_parts(6_682_000, 0) + // Minimum execution time: 6_227_000 picoseconds. + Weight::from_parts(6_419_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -159,8 +191,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_833_000 picoseconds. - Weight::from_parts(1_973_000, 0) + // Minimum execution time: 1_851_000 picoseconds. + Weight::from_parts(1_940_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -186,8 +218,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 27_318_000 picoseconds. - Weight::from_parts(28_224_000, 0) + // Minimum execution time: 27_449_000 picoseconds. + Weight::from_parts(28_513_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) @@ -212,8 +244,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `363` // Estimated: `3828` - // Minimum execution time: 29_070_000 picoseconds. - Weight::from_parts(30_205_000, 0) + // Minimum execution time: 29_477_000 picoseconds. + Weight::from_parts(30_251_000, 0) .saturating_add(Weight::from_parts(0, 3828)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -224,8 +256,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_904_000 picoseconds. - Weight::from_parts(2_033_000, 0) + // Minimum execution time: 1_894_000 picoseconds. + Weight::from_parts(2_009_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -235,8 +267,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `159` // Estimated: `13524` - // Minimum execution time: 18_348_000 picoseconds. - Weight::from_parts(18_853_000, 0) + // Minimum execution time: 17_991_000 picoseconds. + Weight::from_parts(18_651_000, 0) .saturating_add(Weight::from_parts(0, 13524)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -247,8 +279,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `163` // Estimated: `13528` - // Minimum execution time: 17_964_000 picoseconds. - Weight::from_parts(18_548_000, 0) + // Minimum execution time: 18_321_000 picoseconds. + Weight::from_parts(18_701_000, 0) .saturating_add(Weight::from_parts(0, 13528)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -259,8 +291,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `173` // Estimated: `16013` - // Minimum execution time: 19_708_000 picoseconds. - Weight::from_parts(20_157_000, 0) + // Minimum execution time: 19_762_000 picoseconds. + Weight::from_parts(20_529_000, 0) .saturating_add(Weight::from_parts(0, 16013)) .saturating_add(T::DbWeight::get().reads(6)) } @@ -282,8 +314,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `212` // Estimated: `6152` - // Minimum execution time: 26_632_000 picoseconds. - Weight::from_parts(27_314_000, 0) + // Minimum execution time: 26_927_000 picoseconds. + Weight::from_parts(27_629_000, 0) .saturating_add(Weight::from_parts(0, 6152)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -294,8 +326,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `206` // Estimated: `11096` - // Minimum execution time: 11_929_000 picoseconds. - Weight::from_parts(12_304_000, 0) + // Minimum execution time: 11_957_000 picoseconds. + Weight::from_parts(12_119_000, 0) .saturating_add(Weight::from_parts(0, 11096)) .saturating_add(T::DbWeight::get().reads(4)) } @@ -305,8 +337,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `170` // Estimated: `13535` - // Minimum execution time: 18_599_000 picoseconds. - Weight::from_parts(19_195_000, 0) + // Minimum execution time: 17_942_000 picoseconds. + Weight::from_parts(18_878_000, 0) .saturating_add(Weight::from_parts(0, 13535)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -329,8 +361,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `212` // Estimated: `13577` - // Minimum execution time: 35_524_000 picoseconds. - Weight::from_parts(36_272_000, 0) + // Minimum execution time: 35_640_000 picoseconds. + Weight::from_parts(36_340_000, 0) .saturating_add(Weight::from_parts(0, 13577)) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(4)) @@ -344,7 +376,7 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Measured: `103` // Estimated: `1588` // Minimum execution time: 4_044_000 picoseconds. - Weight::from_parts(4_238_000, 0) + Weight::from_parts(4_229_000, 0) .saturating_add(Weight::from_parts(0, 1588)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -355,8 +387,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7740` // Estimated: `11205` - // Minimum execution time: 25_741_000 picoseconds. - Weight::from_parts(26_301_000, 0) + // Minimum execution time: 26_262_000 picoseconds. + Weight::from_parts(26_842_000, 0) .saturating_add(Weight::from_parts(0, 11205)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -367,8 +399,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `160` // Estimated: `3625` - // Minimum execution time: 35_925_000 picoseconds. - Weight::from_parts(36_978_000, 0) + // Minimum execution time: 36_775_000 picoseconds. + Weight::from_parts(37_265_000, 0) .saturating_add(Weight::from_parts(0, 3625)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs index c5d315467c1..df0044089c8 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -62,8 +62,28 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 35_051_000 picoseconds. - Weight::from_parts(35_200_000, 0) + // Minimum execution time: 18_767_000 picoseconds. + Weight::from_parts(19_420_000, 0) + .saturating_add(Weight::from_parts(0, 3539)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn send_blob() -> Weight { + // Proof Size summary in bytes: + // Measured: `74` + // Estimated: `3539` + // Minimum execution time: 19_184_000 picoseconds. + Weight::from_parts(19_695_000, 0) .saturating_add(Weight::from_parts(0, 3539)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -84,8 +104,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 56_235_000 picoseconds. - Weight::from_parts(58_178_000, 0) + // Minimum execution time: 58_120_000 picoseconds. + Weight::from_parts(59_533_000, 0) .saturating_add(Weight::from_parts(0, 3571)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) @@ -120,14 +140,24 @@ impl pallet_xcm::WeightInfo for WeightInfo { Weight::from_parts(18_446_744_073_709_551_000, 0) .saturating_add(Weight::from_parts(0, 0)) } + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn execute_blob() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_xcm_version() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_226_000 picoseconds. - Weight::from_parts(6_403_000, 0) + // Minimum execution time: 6_074_000 picoseconds. + Weight::from_parts(6_398_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -137,8 +167,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_020_000 picoseconds. - Weight::from_parts(2_100_000, 0) + // Minimum execution time: 2_036_000 picoseconds. + Weight::from_parts(2_180_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -162,8 +192,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 24_387_000 picoseconds. - Weight::from_parts(24_814_000, 0) + // Minimum execution time: 25_014_000 picoseconds. + Weight::from_parts(25_374_000, 0) .saturating_add(Weight::from_parts(0, 3539)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) @@ -186,8 +216,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `292` // Estimated: `3757` - // Minimum execution time: 27_039_000 picoseconds. - Weight::from_parts(27_693_000, 0) + // Minimum execution time: 27_616_000 picoseconds. + Weight::from_parts(28_499_000, 0) .saturating_add(Weight::from_parts(0, 3757)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) @@ -198,8 +228,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_920_000 picoseconds. - Weight::from_parts(2_082_000, 0) + // Minimum execution time: 2_061_000 picoseconds. + Weight::from_parts(2_153_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -209,8 +239,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `89` // Estimated: `13454` - // Minimum execution time: 17_141_000 picoseconds. - Weight::from_parts(17_500_000, 0) + // Minimum execution time: 16_592_000 picoseconds. + Weight::from_parts(16_900_000, 0) .saturating_add(Weight::from_parts(0, 13454)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -221,8 +251,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `93` // Estimated: `13458` - // Minimum execution time: 17_074_000 picoseconds. - Weight::from_parts(17_431_000, 0) + // Minimum execution time: 16_694_000 picoseconds. + Weight::from_parts(16_905_000, 0) .saturating_add(Weight::from_parts(0, 13458)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -233,8 +263,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `15946` - // Minimum execution time: 19_139_000 picoseconds. - Weight::from_parts(19_474_000, 0) + // Minimum execution time: 17_779_000 picoseconds. + Weight::from_parts(18_490_000, 0) .saturating_add(Weight::from_parts(0, 15946)) .saturating_add(T::DbWeight::get().reads(6)) } @@ -254,8 +284,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `142` // Estimated: `6082` - // Minimum execution time: 24_346_000 picoseconds. - Weight::from_parts(25_318_000, 0) + // Minimum execution time: 24_526_000 picoseconds. + Weight::from_parts(25_182_000, 0) .saturating_add(Weight::from_parts(0, 6082)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) @@ -266,8 +296,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `136` // Estimated: `11026` - // Minimum execution time: 11_777_000 picoseconds. - Weight::from_parts(12_051_000, 0) + // Minimum execution time: 10_467_000 picoseconds. + Weight::from_parts(10_934_000, 0) .saturating_add(Weight::from_parts(0, 11026)) .saturating_add(T::DbWeight::get().reads(4)) } @@ -277,8 +307,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `100` // Estimated: `13465` - // Minimum execution time: 17_538_000 picoseconds. - Weight::from_parts(17_832_000, 0) + // Minimum execution time: 16_377_000 picoseconds. + Weight::from_parts(17_114_000, 0) .saturating_add(Weight::from_parts(0, 13465)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -299,8 +329,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `142` // Estimated: `13507` - // Minimum execution time: 33_623_000 picoseconds. - Weight::from_parts(34_186_000, 0) + // Minimum execution time: 32_575_000 picoseconds. + Weight::from_parts(33_483_000, 0) .saturating_add(Weight::from_parts(0, 13507)) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) @@ -313,8 +343,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1517` - // Minimum execution time: 3_363_000 picoseconds. - Weight::from_parts(3_511_000, 0) + // Minimum execution time: 3_604_000 picoseconds. + Weight::from_parts(3_744_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -325,8 +355,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7669` // Estimated: `11134` - // Minimum execution time: 23_969_000 picoseconds. - Weight::from_parts(24_347_000, 0) + // Minimum execution time: 23_983_000 picoseconds. + Weight::from_parts(24_404_000, 0) .saturating_add(Weight::from_parts(0, 11134)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -337,8 +367,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 34_071_000 picoseconds. - Weight::from_parts(35_031_000, 0) + // Minimum execution time: 34_446_000 picoseconds. + Weight::from_parts(35_465_000, 0) .saturating_add(Weight::from_parts(0, 3555)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs index 0082db3099d..a1701c5f1c2 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -62,8 +62,28 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 18_410_000 picoseconds. - Weight::from_parts(18_657_000, 0) + // Minimum execution time: 17_681_000 picoseconds. + Weight::from_parts(18_350_000, 0) + .saturating_add(Weight::from_parts(0, 3539)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn send_blob() -> Weight { + // Proof Size summary in bytes: + // Measured: `74` + // Estimated: `3539` + // Minimum execution time: 18_091_000 picoseconds. + Weight::from_parts(18_327_000, 0) .saturating_add(Weight::from_parts(0, 3539)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -84,8 +104,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 56_616_000 picoseconds. - Weight::from_parts(57_751_000, 0) + // Minimum execution time: 54_943_000 picoseconds. + Weight::from_parts(56_519_000, 0) .saturating_add(Weight::from_parts(0, 3571)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) @@ -120,14 +140,24 @@ impl pallet_xcm::WeightInfo for WeightInfo { Weight::from_parts(18_446_744_073_709_551_000, 0) .saturating_add(Weight::from_parts(0, 0)) } + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn execute_blob() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_xcm_version() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_014_000 picoseconds. - Weight::from_parts(6_412_000, 0) + // Minimum execution time: 5_887_000 picoseconds. + Weight::from_parts(6_101_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -137,8 +167,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_844_000 picoseconds. - Weight::from_parts(1_957_000, 0) + // Minimum execution time: 1_940_000 picoseconds. + Weight::from_parts(2_022_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -162,8 +192,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 24_067_000 picoseconds. - Weight::from_parts(24_553_000, 0) + // Minimum execution time: 23_165_000 picoseconds. + Weight::from_parts(23_800_000, 0) .saturating_add(Weight::from_parts(0, 3539)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) @@ -186,8 +216,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `292` // Estimated: `3757` - // Minimum execution time: 27_023_000 picoseconds. - Weight::from_parts(27_620_000, 0) + // Minimum execution time: 26_506_000 picoseconds. + Weight::from_parts(27_180_000, 0) .saturating_add(Weight::from_parts(0, 3757)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) @@ -198,8 +228,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_866_000 picoseconds. - Weight::from_parts(1_984_000, 0) + // Minimum execution time: 1_868_000 picoseconds. + Weight::from_parts(2_002_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -209,8 +239,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `89` // Estimated: `13454` - // Minimum execution time: 16_425_000 picoseconds. - Weight::from_parts(16_680_000, 0) + // Minimum execution time: 16_138_000 picoseconds. + Weight::from_parts(16_447_000, 0) .saturating_add(Weight::from_parts(0, 13454)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -221,8 +251,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `93` // Estimated: `13458` - // Minimum execution time: 16_171_000 picoseconds. - Weight::from_parts(16_564_000, 0) + // Minimum execution time: 16_099_000 picoseconds. + Weight::from_parts(16_592_000, 0) .saturating_add(Weight::from_parts(0, 13458)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -233,8 +263,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `15946` - // Minimum execution time: 17_785_000 picoseconds. - Weight::from_parts(18_123_000, 0) + // Minimum execution time: 17_972_000 picoseconds. + Weight::from_parts(18_379_000, 0) .saturating_add(Weight::from_parts(0, 15946)) .saturating_add(T::DbWeight::get().reads(6)) } @@ -254,8 +284,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `142` // Estimated: `6082` - // Minimum execution time: 23_903_000 picoseconds. - Weight::from_parts(24_769_000, 0) + // Minimum execution time: 23_554_000 picoseconds. + Weight::from_parts(24_446_000, 0) .saturating_add(Weight::from_parts(0, 6082)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) @@ -266,8 +296,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `136` // Estimated: `11026` - // Minimum execution time: 10_617_000 picoseconds. - Weight::from_parts(10_843_000, 0) + // Minimum execution time: 10_541_000 picoseconds. + Weight::from_parts(10_894_000, 0) .saturating_add(Weight::from_parts(0, 11026)) .saturating_add(T::DbWeight::get().reads(4)) } @@ -277,8 +307,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `100` // Estimated: `13465` - // Minimum execution time: 16_656_000 picoseconds. - Weight::from_parts(17_106_000, 0) + // Minimum execution time: 16_404_000 picoseconds. + Weight::from_parts(16_818_000, 0) .saturating_add(Weight::from_parts(0, 13465)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -299,8 +329,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `142` // Estimated: `13507` - // Minimum execution time: 31_721_000 picoseconds. - Weight::from_parts(32_547_000, 0) + // Minimum execution time: 31_617_000 picoseconds. + Weight::from_parts(32_336_000, 0) .saturating_add(Weight::from_parts(0, 13507)) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) @@ -313,8 +343,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1517` - // Minimum execution time: 3_439_000 picoseconds. - Weight::from_parts(3_619_000, 0) + // Minimum execution time: 3_328_000 picoseconds. + Weight::from_parts(3_501_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -325,8 +355,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7669` // Estimated: `11134` - // Minimum execution time: 24_657_000 picoseconds. - Weight::from_parts(24_971_000, 0) + // Minimum execution time: 23_571_000 picoseconds. + Weight::from_parts(24_312_000, 0) .saturating_add(Weight::from_parts(0, 11134)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -337,8 +367,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 34_028_000 picoseconds. - Weight::from_parts(34_697_000, 0) + // Minimum execution time: 32_879_000 picoseconds. + Weight::from_parts(33_385_000, 0) .saturating_add(Weight::from_parts(0, 3555)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs index fabce29b5fd..ac494fdc719 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("people-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -62,8 +62,28 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 17_830_000 picoseconds. - Weight::from_parts(18_411_000, 0) + // Minimum execution time: 17_935_000 picoseconds. + Weight::from_parts(18_482_000, 0) + .saturating_add(Weight::from_parts(0, 3503)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn send_blob() -> Weight { + // Proof Size summary in bytes: + // Measured: `38` + // Estimated: `3503` + // Minimum execution time: 18_311_000 picoseconds. + Weight::from_parts(18_850_000, 0) .saturating_add(Weight::from_parts(0, 3503)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -84,8 +104,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3535` - // Minimum execution time: 55_456_000 picoseconds. - Weight::from_parts(56_808_000, 0) + // Minimum execution time: 56_182_000 picoseconds. + Weight::from_parts(58_136_000, 0) .saturating_add(Weight::from_parts(0, 3535)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) @@ -120,14 +140,24 @@ impl pallet_xcm::WeightInfo for WeightInfo { Weight::from_parts(18_446_744_073_709_551_000, 0) .saturating_add(Weight::from_parts(0, 0)) } + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn execute_blob() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_xcm_version() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_996_000 picoseconds. - Weight::from_parts(6_154_000, 0) + // Minimum execution time: 5_979_000 picoseconds. + Weight::from_parts(6_289_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -137,8 +167,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_768_000 picoseconds. - Weight::from_parts(1_914_000, 0) + // Minimum execution time: 1_853_000 picoseconds. + Weight::from_parts(2_045_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -162,8 +192,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 24_120_000 picoseconds. - Weight::from_parts(24_745_000, 0) + // Minimum execution time: 23_827_000 picoseconds. + Weight::from_parts(24_493_000, 0) .saturating_add(Weight::from_parts(0, 3503)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) @@ -186,8 +216,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `255` // Estimated: `3720` - // Minimum execution time: 26_630_000 picoseconds. - Weight::from_parts(27_289_000, 0) + // Minimum execution time: 26_755_000 picoseconds. + Weight::from_parts(27_125_000, 0) .saturating_add(Weight::from_parts(0, 3720)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) @@ -198,8 +228,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_821_000 picoseconds. - Weight::from_parts(1_946_000, 0) + // Minimum execution time: 1_898_000 picoseconds. + Weight::from_parts(2_028_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -209,8 +239,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `89` // Estimated: `13454` - // Minimum execution time: 16_586_000 picoseconds. - Weight::from_parts(16_977_000, 0) + // Minimum execution time: 16_300_000 picoseconds. + Weight::from_parts(16_995_000, 0) .saturating_add(Weight::from_parts(0, 13454)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -221,8 +251,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `93` // Estimated: `13458` - // Minimum execution time: 16_923_000 picoseconds. - Weight::from_parts(17_415_000, 0) + // Minimum execution time: 16_495_000 picoseconds. + Weight::from_parts(16_950_000, 0) .saturating_add(Weight::from_parts(0, 13458)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -233,8 +263,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `15946` - // Minimum execution time: 18_596_000 picoseconds. - Weight::from_parts(18_823_000, 0) + // Minimum execution time: 18_153_000 picoseconds. + Weight::from_parts(18_595_000, 0) .saturating_add(Weight::from_parts(0, 15946)) .saturating_add(T::DbWeight::get().reads(6)) } @@ -254,8 +284,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `6046` - // Minimum execution time: 23_817_000 picoseconds. - Weight::from_parts(24_520_000, 0) + // Minimum execution time: 23_387_000 picoseconds. + Weight::from_parts(24_677_000, 0) .saturating_add(Weight::from_parts(0, 6046)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) @@ -266,8 +296,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `136` // Estimated: `11026` - // Minimum execution time: 11_042_000 picoseconds. - Weight::from_parts(11_578_000, 0) + // Minimum execution time: 10_939_000 picoseconds. + Weight::from_parts(11_210_000, 0) .saturating_add(Weight::from_parts(0, 11026)) .saturating_add(T::DbWeight::get().reads(4)) } @@ -277,8 +307,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `100` // Estimated: `13465` - // Minimum execution time: 17_306_000 picoseconds. - Weight::from_parts(17_817_000, 0) + // Minimum execution time: 16_850_000 picoseconds. + Weight::from_parts(17_195_000, 0) .saturating_add(Weight::from_parts(0, 13465)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -299,8 +329,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `13471` - // Minimum execution time: 32_141_000 picoseconds. - Weight::from_parts(32_954_000, 0) + // Minimum execution time: 31_931_000 picoseconds. + Weight::from_parts(32_494_000, 0) .saturating_add(Weight::from_parts(0, 13471)) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) @@ -313,8 +343,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1517` - // Minimum execution time: 3_410_000 picoseconds. - Weight::from_parts(3_556_000, 0) + // Minimum execution time: 3_514_000 picoseconds. + Weight::from_parts(3_709_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -325,8 +355,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7669` // Estimated: `11134` - // Minimum execution time: 25_021_000 picoseconds. - Weight::from_parts(25_240_000, 0) + // Minimum execution time: 24_863_000 picoseconds. + Weight::from_parts(25_293_000, 0) .saturating_add(Weight::from_parts(0, 11134)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -337,8 +367,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 33_801_000 picoseconds. - Weight::from_parts(34_655_000, 0) + // Minimum execution time: 33_799_000 picoseconds. + Weight::from_parts(34_665_000, 0) .saturating_add(Weight::from_parts(0, 3555)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs index c337289243b..62a9c802808 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("people-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -62,8 +62,28 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 17_856_000 picoseconds. - Weight::from_parts(18_473_000, 0) + // Minimum execution time: 17_450_000 picoseconds. + Weight::from_parts(17_913_000, 0) + .saturating_add(Weight::from_parts(0, 3503)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn send_blob() -> Weight { + // Proof Size summary in bytes: + // Measured: `38` + // Estimated: `3503` + // Minimum execution time: 18_082_000 picoseconds. + Weight::from_parts(18_293_000, 0) .saturating_add(Weight::from_parts(0, 3503)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -84,8 +104,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3535` - // Minimum execution time: 56_112_000 picoseconds. - Weight::from_parts(57_287_000, 0) + // Minimum execution time: 54_939_000 picoseconds. + Weight::from_parts(55_721_000, 0) .saturating_add(Weight::from_parts(0, 3535)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) @@ -120,14 +140,24 @@ impl pallet_xcm::WeightInfo for WeightInfo { Weight::from_parts(18_446_744_073_709_551_000, 0) .saturating_add(Weight::from_parts(0, 0)) } + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn execute_blob() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_xcm_version() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_186_000 picoseconds. - Weight::from_parts(6_420_000, 0) + // Minimum execution time: 5_789_000 picoseconds. + Weight::from_parts(5_995_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -137,8 +167,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_824_000 picoseconds. - Weight::from_parts(1_999_000, 0) + // Minimum execution time: 1_795_000 picoseconds. + Weight::from_parts(1_924_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -162,8 +192,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 23_833_000 picoseconds. - Weight::from_parts(24_636_000, 0) + // Minimum execution time: 23_445_000 picoseconds. + Weight::from_parts(23_906_000, 0) .saturating_add(Weight::from_parts(0, 3503)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) @@ -186,8 +216,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `255` // Estimated: `3720` - // Minimum execution time: 26_557_000 picoseconds. - Weight::from_parts(27_275_000, 0) + // Minimum execution time: 26_590_000 picoseconds. + Weight::from_parts(27_056_000, 0) .saturating_add(Weight::from_parts(0, 3720)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) @@ -198,8 +228,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_921_000 picoseconds. - Weight::from_parts(2_040_000, 0) + // Minimum execution time: 1_889_000 picoseconds. + Weight::from_parts(1_962_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -209,8 +239,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `89` // Estimated: `13454` - // Minimum execution time: 16_832_000 picoseconds. - Weight::from_parts(17_312_000, 0) + // Minimum execution time: 16_408_000 picoseconds. + Weight::from_parts(16_877_000, 0) .saturating_add(Weight::from_parts(0, 13454)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -221,8 +251,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `93` // Estimated: `13458` - // Minimum execution time: 16_687_000 picoseconds. - Weight::from_parts(17_123_000, 0) + // Minimum execution time: 16_791_000 picoseconds. + Weight::from_parts(17_111_000, 0) .saturating_add(Weight::from_parts(0, 13458)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -233,8 +263,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `15946` - // Minimum execution time: 18_164_000 picoseconds. - Weight::from_parts(18_580_000, 0) + // Minimum execution time: 18_355_000 picoseconds. + Weight::from_parts(19_110_000, 0) .saturating_add(Weight::from_parts(0, 15946)) .saturating_add(T::DbWeight::get().reads(6)) } @@ -254,8 +284,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `6046` - // Minimum execution time: 23_577_000 picoseconds. - Weight::from_parts(24_324_000, 0) + // Minimum execution time: 23_354_000 picoseconds. + Weight::from_parts(23_999_000, 0) .saturating_add(Weight::from_parts(0, 6046)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) @@ -266,8 +296,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `136` // Estimated: `11026` - // Minimum execution time: 11_014_000 picoseconds. - Weight::from_parts(11_223_000, 0) + // Minimum execution time: 11_065_000 picoseconds. + Weight::from_parts(11_302_000, 0) .saturating_add(Weight::from_parts(0, 11026)) .saturating_add(T::DbWeight::get().reads(4)) } @@ -277,8 +307,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `100` // Estimated: `13465` - // Minimum execution time: 16_887_000 picoseconds. - Weight::from_parts(17_361_000, 0) + // Minimum execution time: 16_998_000 picoseconds. + Weight::from_parts(17_509_000, 0) .saturating_add(Weight::from_parts(0, 13465)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -299,8 +329,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `13471` - // Minimum execution time: 31_705_000 picoseconds. - Weight::from_parts(32_166_000, 0) + // Minimum execution time: 31_068_000 picoseconds. + Weight::from_parts(31_978_000, 0) .saturating_add(Weight::from_parts(0, 13471)) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) @@ -313,8 +343,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1517` - // Minimum execution time: 3_568_000 picoseconds. - Weight::from_parts(3_669_000, 0) + // Minimum execution time: 3_478_000 picoseconds. + Weight::from_parts(3_595_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -325,8 +355,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7669` // Estimated: `11134` - // Minimum execution time: 24_823_000 picoseconds. - Weight::from_parts(25_344_000, 0) + // Minimum execution time: 24_962_000 picoseconds. + Weight::from_parts(25_404_000, 0) .saturating_add(Weight::from_parts(0, 11134)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -337,8 +367,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 34_516_000 picoseconds. - Weight::from_parts(35_478_000, 0) + // Minimum execution time: 32_685_000 picoseconds. + Weight::from_parts(33_592_000, 0) .saturating_add(Weight::from_parts(0, 3555)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/polkadot/runtime/rococo/src/impls.rs b/polkadot/runtime/rococo/src/impls.rs index ac7100d7858..cf364b6ac79 100644 --- a/polkadot/runtime/rococo/src/impls.rs +++ b/polkadot/runtime/rococo/src/impls.rs @@ -167,11 +167,16 @@ where }, ]); + let encoded_versioned_xcm = + VersionedXcm::V4(program).encode().try_into().map_err(|error| { + log::error!(target: "runtime::on_reap_identity", "XCM too large, error: {:?}", error); + pallet_xcm::Error::::XcmTooLarge + })?; // send - let _ = >::send( + let _ = >::send_blob( RawOrigin::Root.into(), Box::new(VersionedLocation::V4(destination)), - Box::new(VersionedXcm::V4(program)), + encoded_versioned_xcm, )?; Ok(()) } diff --git a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs index 5544ca44658..42972baa1c8 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -60,8 +60,26 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3645` - // Minimum execution time: 25_043_000 picoseconds. - Weight::from_parts(25_682_000, 0) + // Minimum execution time: 24_724_000 picoseconds. + Weight::from_parts(25_615_000, 0) + .saturating_add(Weight::from_parts(0, 3645)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn send_blob() -> Weight { + // Proof Size summary in bytes: + // Measured: `180` + // Estimated: `3645` + // Minimum execution time: 24_709_000 picoseconds. + Weight::from_parts(25_326_000, 0) .saturating_add(Weight::from_parts(0, 3645)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -80,8 +98,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3645` - // Minimum execution time: 107_570_000 picoseconds. - Weight::from_parts(109_878_000, 0) + // Minimum execution time: 106_600_000 picoseconds. + Weight::from_parts(110_781_000, 0) .saturating_add(Weight::from_parts(0, 3645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) @@ -100,8 +118,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `232` // Estimated: `3697` - // Minimum execution time: 106_341_000 picoseconds. - Weight::from_parts(109_135_000, 0) + // Minimum execution time: 103_030_000 picoseconds. + Weight::from_parts(106_018_000, 0) .saturating_add(Weight::from_parts(0, 3697)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) @@ -120,8 +138,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3645` - // Minimum execution time: 108_372_000 picoseconds. - Weight::from_parts(112_890_000, 0) + // Minimum execution time: 107_017_000 picoseconds. + Weight::from_parts(109_214_000, 0) .saturating_add(Weight::from_parts(0, 3645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) @@ -130,8 +148,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_957_000 picoseconds. - Weight::from_parts(7_417_000, 0) + // Minimum execution time: 6_864_000 picoseconds. + Weight::from_parts(7_135_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn execute_blob() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_955_000 picoseconds. + Weight::from_parts(7_165_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `XcmPallet::SupportedVersion` (r:0 w:1) @@ -140,8 +166,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_053_000 picoseconds. - Weight::from_parts(7_462_000, 0) + // Minimum execution time: 6_827_000 picoseconds. + Weight::from_parts(7_211_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -149,8 +175,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_918_000 picoseconds. - Weight::from_parts(2_037_000, 0) + // Minimum execution time: 1_788_000 picoseconds. + Weight::from_parts(2_021_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `XcmPallet::VersionNotifiers` (r:1 w:1) @@ -171,8 +197,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3645` - // Minimum execution time: 30_417_000 picoseconds. - Weight::from_parts(31_191_000, 0) + // Minimum execution time: 30_627_000 picoseconds. + Weight::from_parts(31_350_000, 0) .saturating_add(Weight::from_parts(0, 3645)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) @@ -193,8 +219,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `360` // Estimated: `3825` - // Minimum execution time: 36_666_000 picoseconds. - Weight::from_parts(37_779_000, 0) + // Minimum execution time: 36_688_000 picoseconds. + Weight::from_parts(37_345_000, 0) .saturating_add(Weight::from_parts(0, 3825)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) @@ -205,8 +231,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_869_000 picoseconds. - Weight::from_parts(2_003_000, 0) + // Minimum execution time: 1_829_000 picoseconds. + Weight::from_parts(1_986_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -216,8 +242,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `22` // Estimated: `13387` - // Minimum execution time: 16_188_000 picoseconds. - Weight::from_parts(16_435_000, 0) + // Minimum execution time: 16_104_000 picoseconds. + Weight::from_parts(16_464_000, 0) .saturating_add(Weight::from_parts(0, 13387)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -228,8 +254,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `26` // Estimated: `13391` - // Minimum execution time: 16_431_000 picoseconds. - Weight::from_parts(16_935_000, 0) + // Minimum execution time: 16_267_000 picoseconds. + Weight::from_parts(16_675_000, 0) .saturating_add(Weight::from_parts(0, 13391)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -240,8 +266,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `40` // Estimated: `15880` - // Minimum execution time: 18_460_000 picoseconds. - Weight::from_parts(18_885_000, 0) + // Minimum execution time: 18_487_000 picoseconds. + Weight::from_parts(19_102_000, 0) .saturating_add(Weight::from_parts(0, 15880)) .saturating_add(T::DbWeight::get().reads(6)) } @@ -259,8 +285,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `216` // Estimated: `6156` - // Minimum execution time: 29_623_000 picoseconds. - Weight::from_parts(30_661_000, 0) + // Minimum execution time: 29_603_000 picoseconds. + Weight::from_parts(31_002_000, 0) .saturating_add(Weight::from_parts(0, 6156)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) @@ -271,8 +297,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `69` // Estimated: `10959` - // Minimum execution time: 12_043_000 picoseconds. - Weight::from_parts(12_360_000, 0) + // Minimum execution time: 12_183_000 picoseconds. + Weight::from_parts(12_587_000, 0) .saturating_add(Weight::from_parts(0, 10959)) .saturating_add(T::DbWeight::get().reads(4)) } @@ -282,8 +308,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `33` // Estimated: `13398` - // Minimum execution time: 16_511_000 picoseconds. - Weight::from_parts(17_011_000, 0) + // Minimum execution time: 16_372_000 picoseconds. + Weight::from_parts(16_967_000, 0) .saturating_add(Weight::from_parts(0, 13398)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -302,8 +328,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `216` // Estimated: `13581` - // Minimum execution time: 39_041_000 picoseconds. - Weight::from_parts(39_883_000, 0) + // Minimum execution time: 38_904_000 picoseconds. + Weight::from_parts(39_983_000, 0) .saturating_add(Weight::from_parts(0, 13581)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) @@ -316,8 +342,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1485` - // Minimum execution time: 2_030_000 picoseconds. - Weight::from_parts(2_150_000, 0) + // Minimum execution time: 2_067_000 picoseconds. + Weight::from_parts(2_195_000, 0) .saturating_add(Weight::from_parts(0, 1485)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -328,8 +354,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7576` // Estimated: `11041` - // Minimum execution time: 22_615_000 picoseconds. - Weight::from_parts(23_008_000, 0) + // Minimum execution time: 23_982_000 picoseconds. + Weight::from_parts(24_409_000, 0) .saturating_add(Weight::from_parts(0, 11041)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -340,8 +366,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `23` // Estimated: `3488` - // Minimum execution time: 34_438_000 picoseconds. - Weight::from_parts(35_514_000, 0) + // Minimum execution time: 33_430_000 picoseconds. + Weight::from_parts(34_433_000, 0) .saturating_add(Weight::from_parts(0, 3488)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/polkadot/runtime/westend/src/impls.rs b/polkadot/runtime/westend/src/impls.rs index 71e6b696a20..d8741c939a5 100644 --- a/polkadot/runtime/westend/src/impls.rs +++ b/polkadot/runtime/westend/src/impls.rs @@ -167,11 +167,16 @@ where }, ]); + let encoded_versioned_xcm = + VersionedXcm::V4(program).encode().try_into().map_err(|error| { + log::error!(target: "runtime::on_reap_identity", "XCM too large, error: {:?}", error); + pallet_xcm::Error::::XcmTooLarge + })?; // send - let _ = >::send( + let _ = >::send_blob( RawOrigin::Root.into(), Box::new(VersionedLocation::V4(destination)), - Box::new(VersionedXcm::V4(program)), + encoded_versioned_xcm, )?; Ok(()) } diff --git a/polkadot/runtime/westend/src/weights/pallet_xcm.rs b/polkadot/runtime/westend/src/weights/pallet_xcm.rs index 10725cecf24..80bc551ba1e 100644 --- a/polkadot/runtime/westend/src/weights/pallet_xcm.rs +++ b/polkadot/runtime/westend/src/weights/pallet_xcm.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -60,8 +60,26 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `147` // Estimated: `3612` - // Minimum execution time: 25_725_000 picoseconds. - Weight::from_parts(26_174_000, 0) + // Minimum execution time: 24_535_000 picoseconds. + Weight::from_parts(25_618_000, 0) + .saturating_add(Weight::from_parts(0, 3612)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn send_blob() -> Weight { + // Proof Size summary in bytes: + // Measured: `147` + // Estimated: `3612` + // Minimum execution time: 25_376_000 picoseconds. + Weight::from_parts(26_180_000, 0) .saturating_add(Weight::from_parts(0, 3612)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -80,8 +98,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `250` // Estimated: `6196` - // Minimum execution time: 113_140_000 picoseconds. - Weight::from_parts(116_204_000, 0) + // Minimum execution time: 108_786_000 picoseconds. + Weight::from_parts(112_208_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) @@ -100,8 +118,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `302` // Estimated: `6196` - // Minimum execution time: 108_571_000 picoseconds. - Weight::from_parts(110_650_000, 0) + // Minimum execution time: 105_190_000 picoseconds. + Weight::from_parts(107_140_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) @@ -120,8 +138,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `250` // Estimated: `6196` - // Minimum execution time: 111_836_000 picoseconds. - Weight::from_parts(114_435_000, 0) + // Minimum execution time: 109_027_000 picoseconds. + Weight::from_parts(111_404_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) @@ -136,14 +154,24 @@ impl pallet_xcm::WeightInfo for WeightInfo { Weight::from_parts(18_446_744_073_709_551_000, 0) .saturating_add(Weight::from_parts(0, 0)) } + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn execute_blob() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } /// Storage: `XcmPallet::SupportedVersion` (r:0 w:1) /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_xcm_version() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_160_000 picoseconds. - Weight::from_parts(7_477_000, 0) + // Minimum execution time: 6_668_000 picoseconds. + Weight::from_parts(7_013_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -151,8 +179,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_934_000 picoseconds. - Weight::from_parts(2_053_000, 0) + // Minimum execution time: 1_740_000 picoseconds. + Weight::from_parts(1_884_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `XcmPallet::VersionNotifiers` (r:1 w:1) @@ -173,8 +201,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `147` // Estimated: `3612` - // Minimum execution time: 31_123_000 picoseconds. - Weight::from_parts(31_798_000, 0) + // Minimum execution time: 30_200_000 picoseconds. + Weight::from_parts(30_768_000, 0) .saturating_add(Weight::from_parts(0, 3612)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) @@ -195,8 +223,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `327` // Estimated: `3792` - // Minimum execution time: 35_175_000 picoseconds. - Weight::from_parts(36_098_000, 0) + // Minimum execution time: 33_928_000 picoseconds. + Weight::from_parts(35_551_000, 0) .saturating_add(Weight::from_parts(0, 3792)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) @@ -207,8 +235,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_974_000 picoseconds. - Weight::from_parts(2_096_000, 0) + // Minimum execution time: 1_759_000 picoseconds. + Weight::from_parts(1_880_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -218,8 +246,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `22` // Estimated: `13387` - // Minimum execution time: 16_626_000 picoseconds. - Weight::from_parts(17_170_000, 0) + // Minimum execution time: 16_507_000 picoseconds. + Weight::from_parts(17_219_000, 0) .saturating_add(Weight::from_parts(0, 13387)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -230,8 +258,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `26` // Estimated: `13391` - // Minimum execution time: 16_937_000 picoseconds. - Weight::from_parts(17_447_000, 0) + // Minimum execution time: 16_633_000 picoseconds. + Weight::from_parts(16_889_000, 0) .saturating_add(Weight::from_parts(0, 13391)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -242,8 +270,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `40` // Estimated: `15880` - // Minimum execution time: 19_157_000 picoseconds. - Weight::from_parts(19_659_000, 0) + // Minimum execution time: 19_297_000 picoseconds. + Weight::from_parts(19_820_000, 0) .saturating_add(Weight::from_parts(0, 15880)) .saturating_add(T::DbWeight::get().reads(6)) } @@ -261,8 +289,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `183` // Estimated: `6123` - // Minimum execution time: 30_699_000 picoseconds. - Weight::from_parts(31_537_000, 0) + // Minimum execution time: 30_364_000 picoseconds. + Weight::from_parts(31_122_000, 0) .saturating_add(Weight::from_parts(0, 6123)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) @@ -273,8 +301,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `69` // Estimated: `10959` - // Minimum execution time: 12_303_000 picoseconds. - Weight::from_parts(12_670_000, 0) + // Minimum execution time: 11_997_000 picoseconds. + Weight::from_parts(12_392_000, 0) .saturating_add(Weight::from_parts(0, 10959)) .saturating_add(T::DbWeight::get().reads(4)) } @@ -284,8 +312,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `33` // Estimated: `13398` - // Minimum execution time: 17_129_000 picoseconds. - Weight::from_parts(17_668_000, 0) + // Minimum execution time: 16_894_000 picoseconds. + Weight::from_parts(17_452_000, 0) .saturating_add(Weight::from_parts(0, 13398)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -304,8 +332,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `183` // Estimated: `13548` - // Minimum execution time: 39_960_000 picoseconds. - Weight::from_parts(41_068_000, 0) + // Minimum execution time: 39_864_000 picoseconds. + Weight::from_parts(40_859_000, 0) .saturating_add(Weight::from_parts(0, 13548)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) @@ -318,8 +346,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1485` - // Minimum execution time: 2_333_000 picoseconds. - Weight::from_parts(2_504_000, 0) + // Minimum execution time: 2_363_000 picoseconds. + Weight::from_parts(2_519_000, 0) .saturating_add(Weight::from_parts(0, 1485)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -330,8 +358,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7576` // Estimated: `11041` - // Minimum execution time: 22_932_000 picoseconds. - Weight::from_parts(23_307_000, 0) + // Minimum execution time: 22_409_000 picoseconds. + Weight::from_parts(22_776_000, 0) .saturating_add(Weight::from_parts(0, 11041)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -342,8 +370,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `23` // Estimated: `3488` - // Minimum execution time: 34_558_000 picoseconds. - Weight::from_parts(35_299_000, 0) + // Minimum execution time: 33_551_000 picoseconds. + Weight::from_parts(34_127_000, 0) .saturating_add(Weight::from_parts(0, 3488)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/polkadot/xcm/pallet-xcm/src/benchmarking.rs b/polkadot/xcm/pallet-xcm/src/benchmarking.rs index ed42f93692b..e2903d592dc 100644 --- a/polkadot/xcm/pallet-xcm/src/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm/src/benchmarking.rs @@ -16,6 +16,7 @@ use super::*; use bounded_collections::{ConstU32, WeakBoundedVec}; +use codec::Encode; use frame_benchmarking::{benchmarks, whitelisted_caller, BenchmarkError, BenchmarkResult}; use frame_support::{ traits::fungible::{Inspect, Mutate}, @@ -108,6 +109,21 @@ benchmarks! { let versioned_msg = VersionedXcm::from(msg); }: _>(send_origin, Box::new(versioned_dest), Box::new(versioned_msg)) + send_blob { + let send_origin = + T::SendXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + if T::SendXcmOrigin::try_origin(send_origin.clone()).is_err() { + return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))) + } + let msg = Xcm::<()>(vec![ClearOrigin]); + let versioned_dest: VersionedLocation = T::reachable_dest().ok_or( + BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), + )? + .into(); + let versioned_msg = VersionedXcm::from(msg); + let encoded_versioned_msg = versioned_msg.encode().try_into().unwrap(); + }: _>(send_origin, Box::new(versioned_dest), encoded_versioned_msg) + teleport_assets { let (asset, destination) = T::teleportable_asset_and_dest().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), @@ -227,6 +243,19 @@ benchmarks! { let versioned_msg = VersionedXcm::from(msg); }: _>(execute_origin, Box::new(versioned_msg), Weight::MAX) + execute_blob { + let execute_origin = + T::ExecuteXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let origin_location = T::ExecuteXcmOrigin::try_origin(execute_origin.clone()) + .map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; + let msg = Xcm(vec![ClearOrigin]); + if !T::XcmExecuteFilter::contains(&(origin_location, msg.clone())) { + return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))) + } + let versioned_msg = VersionedXcm::from(msg); + let encoded_versioned_msg = versioned_msg.encode().try_into().unwrap(); + }: _>(execute_origin, encoded_versioned_msg, Weight::MAX) + force_xcm_version { let loc = T::reachable_dest().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 58a597de5ab..29b61988f73 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -50,8 +50,8 @@ use sp_runtime::{ use sp_std::{boxed::Box, marker::PhantomData, prelude::*, result::Result, vec}; use xcm::{latest::QueryResponseInfo, prelude::*}; use xcm_builder::{ - ExecuteController, ExecuteControllerWeightInfo, QueryController, QueryControllerWeightInfo, - SendController, SendControllerWeightInfo, + ExecuteController, ExecuteControllerWeightInfo, MaxXcmEncodedSize, QueryController, + QueryControllerWeightInfo, SendController, SendControllerWeightInfo, }; use xcm_executor::{ traits::{ @@ -87,6 +87,8 @@ pub trait WeightInfo { fn new_query() -> Weight; fn take_response() -> Weight; fn claim_assets() -> Weight; + fn execute_blob() -> Weight; + fn send_blob() -> Weight; } /// fallback implementation @@ -171,6 +173,14 @@ impl WeightInfo for TestWeightInfo { fn claim_assets() -> Weight { Weight::from_parts(100_000_000, 0) } + + fn execute_blob() -> Weight { + Weight::from_parts(100_000_000, 0) + } + + fn send_blob() -> Weight { + Weight::from_parts(100_000_000, 0) + } } #[frame_support::pallet] @@ -286,76 +296,49 @@ pub mod pallet { } impl ExecuteControllerWeightInfo for Pallet { - fn execute() -> Weight { - T::WeightInfo::execute() + fn execute_blob() -> Weight { + T::WeightInfo::execute_blob() } } impl ExecuteController, ::RuntimeCall> for Pallet { type WeightInfo = Self; - fn execute( + fn execute_blob( origin: OriginFor, - message: Box::RuntimeCall>>, + encoded_message: BoundedVec, max_weight: Weight, ) -> Result { - log::trace!(target: "xcm::pallet_xcm::execute", "message {:?}, max_weight {:?}", message, max_weight); - let outcome = (|| { - let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; - let mut hash = message.using_encoded(sp_io::hashing::blake2_256); - let message = (*message).try_into().map_err(|()| Error::::BadVersion)?; - let value = (origin_location, message); - ensure!(T::XcmExecuteFilter::contains(&value), Error::::Filtered); - let (origin_location, message) = value; - Ok(T::XcmExecutor::prepare_and_execute( - origin_location, - message, - &mut hash, - max_weight, - max_weight, - )) - })() - .map_err(|e: DispatchError| { - e.with_weight(::execute()) - })?; - - Self::deposit_event(Event::Attempted { outcome: outcome.clone() }); - let weight_used = outcome.weight_used(); - outcome.ensure_complete().map_err(|error| { - log::error!(target: "xcm::pallet_xcm::execute", "XCM execution failed with error {:?}", error); - Error::::LocalExecutionIncomplete.with_weight( - weight_used.saturating_add( - ::execute(), - ), - ) - })?; - Ok(weight_used) + let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; + let message = + VersionedXcm::<::RuntimeCall>::decode(&mut &encoded_message[..]) + .map_err(|error| { + log::error!(target: "xcm::execute_blob", "Unable to decode XCM, error: {:?}", error); + Error::::UnableToDecode + })?; + Self::execute_base(origin_location, Box::new(message), max_weight) } } impl SendControllerWeightInfo for Pallet { - fn send() -> Weight { - T::WeightInfo::send() + fn send_blob() -> Weight { + T::WeightInfo::send_blob() } } impl SendController> for Pallet { type WeightInfo = Self; - fn send( + fn send_blob( origin: OriginFor, dest: Box, - message: Box>, + encoded_message: BoundedVec, ) -> Result { let origin_location = T::SendXcmOrigin::ensure_origin(origin)?; - let interior: Junctions = - origin_location.clone().try_into().map_err(|_| Error::::InvalidOrigin)?; - let dest = Location::try_from(*dest).map_err(|()| Error::::BadVersion)?; - let message: Xcm<()> = (*message).try_into().map_err(|()| Error::::BadVersion)?; - - let message_id = Self::send_xcm(interior, dest.clone(), message.clone()) - .map_err(Error::::from)?; - let e = Event::Sent { origin: origin_location, destination: dest, message, message_id }; - Self::deposit_event(e); - Ok(message_id) + let message = + VersionedXcm::<()>::decode(&mut &encoded_message[..]).map_err(|error| { + log::error!(target: "xcm::send_blob", "Unable to decode XCM, error: {:?}", error); + Error::::UnableToDecode + })?; + Self::send_base(origin_location, dest, Box::new(message)) } } @@ -562,6 +545,11 @@ pub mod pallet { TooManyReserves, /// Local XCM execution incomplete. LocalExecutionIncomplete, + /// Could not decode XCM. + UnableToDecode, + /// XCM encoded length is too large. + /// Returned when an XCM encoded length is larger than `MaxXcmEncodedSize`. + XcmTooLarge, } impl From for Error { @@ -899,8 +887,64 @@ pub mod pallet { } } + impl Pallet { + /// Underlying logic for both [`execute_blob`] and [`execute`]. + fn execute_base( + origin_location: Location, + message: Box::RuntimeCall>>, + max_weight: Weight, + ) -> Result { + log::trace!(target: "xcm::pallet_xcm::execute", "message {:?}, max_weight {:?}", message, max_weight); + let outcome = (|| { + let mut hash = message.using_encoded(sp_io::hashing::blake2_256); + let message = (*message).try_into().map_err(|()| Error::::BadVersion)?; + let value = (origin_location, message); + ensure!(T::XcmExecuteFilter::contains(&value), Error::::Filtered); + let (origin_location, message) = value; + Ok(T::XcmExecutor::prepare_and_execute( + origin_location, + message, + &mut hash, + max_weight, + max_weight, + )) + })() + .map_err(|e: DispatchError| e.with_weight(T::WeightInfo::execute()))?; + + Self::deposit_event(Event::Attempted { outcome: outcome.clone() }); + let weight_used = outcome.weight_used(); + outcome.ensure_complete().map_err(|error| { + log::error!(target: "xcm::pallet_xcm::execute", "XCM execution failed with error {:?}", error); + Error::::LocalExecutionIncomplete + .with_weight(weight_used.saturating_add(T::WeightInfo::execute())) + })?; + Ok(weight_used) + } + + /// Underlying logic for both [`send_blob`] and [`send`]. + fn send_base( + origin_location: Location, + dest: Box, + message: Box>, + ) -> Result { + let interior: Junctions = + origin_location.clone().try_into().map_err(|_| Error::::InvalidOrigin)?; + let dest = Location::try_from(*dest).map_err(|()| Error::::BadVersion)?; + let message: Xcm<()> = (*message).try_into().map_err(|()| Error::::BadVersion)?; + + let message_id = Self::send_xcm(interior, dest.clone(), message.clone()) + .map_err(Error::::from)?; + let e = Event::Sent { origin: origin_location, destination: dest, message, message_id }; + Self::deposit_event(e); + Ok(message_id) + } + } + #[pallet::call] impl Pallet { + /// WARNING: DEPRECATED. `send` will be removed after June 2024. Use `send_blob` instead. + #[allow(deprecated)] + #[deprecated(note = "`send` will be removed after June 2024. Use `send_blob` instead.")] #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::send())] pub fn send( @@ -908,7 +952,8 @@ pub mod pallet { dest: Box, message: Box>, ) -> DispatchResult { - >::send(origin, dest, message)?; + let origin_location = T::SendXcmOrigin::ensure_origin(origin)?; + Self::send_base(origin_location, dest, message)?; Ok(()) } @@ -1031,6 +1076,13 @@ pub mod pallet { /// No more than `max_weight` will be used in its attempted execution. If this is less than /// the maximum amount of weight that the message could take to be executed, then no /// execution attempt will be made. + /// + /// WARNING: DEPRECATED. `execute` will be removed after June 2024. Use `execute_blob` + /// instead. + #[allow(deprecated)] + #[deprecated( + note = "`execute` will be removed after June 2024. Use `execute_blob` instead." + )] #[pallet::call_index(3)] #[pallet::weight(max_weight.saturating_add(T::WeightInfo::execute()))] pub fn execute( @@ -1038,8 +1090,8 @@ pub mod pallet { message: Box::RuntimeCall>>, max_weight: Weight, ) -> DispatchResultWithPostInfo { - let weight_used = - >::execute(origin, message, max_weight)?; + let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; + let weight_used = Self::execute_base(origin_location, message, max_weight)?; Ok(Some(weight_used.saturating_add(T::WeightInfo::execute())).into()) } @@ -1450,6 +1502,48 @@ pub mod pallet { })?; Ok(()) } + + /// Execute an XCM from a local, signed, origin. + /// + /// An event is deposited indicating whether the message could be executed completely + /// or only partially. + /// + /// No more than `max_weight` will be used in its attempted execution. If this is less than + /// the maximum amount of weight that the message could take to be executed, then no + /// execution attempt will be made. + /// + /// The message is passed in encoded. It needs to be decodable as a [`VersionedXcm`]. + #[pallet::call_index(13)] + #[pallet::weight(T::WeightInfo::execute_blob())] + pub fn execute_blob( + origin: OriginFor, + encoded_message: BoundedVec, + max_weight: Weight, + ) -> DispatchResultWithPostInfo { + let weight_used = >::execute_blob( + origin, + encoded_message, + max_weight, + )?; + Ok(Some(weight_used.saturating_add(T::WeightInfo::execute_blob())).into()) + } + + /// Send an XCM from a local, signed, origin. + /// + /// The destination, `dest`, will receive this message with a `DescendOrigin` instruction + /// that makes the origin of the message be the origin on this system. + /// + /// The message is passed in encoded. It needs to be decodable as a [`VersionedXcm`]. + #[pallet::call_index(14)] + #[pallet::weight(T::WeightInfo::send_blob())] + pub fn send_blob( + origin: OriginFor, + dest: Box, + encoded_message: BoundedVec, + ) -> DispatchResult { + >::send_blob(origin, dest, encoded_message)?; + Ok(()) + } } } diff --git a/polkadot/xcm/pallet-xcm/src/tests/mod.rs b/polkadot/xcm/pallet-xcm/src/tests/mod.rs index 13022d9a8b1..763d768e154 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/mod.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/mod.rs @@ -20,10 +20,10 @@ pub(crate) mod assets_transfer; use crate::{ mock::*, pallet::SupportedVersion, AssetTraps, Config, CurrentMigration, Error, - ExecuteControllerWeightInfo, LatestVersionedLocation, Pallet, Queries, QueryStatus, - VersionDiscoveryQueue, VersionMigrationStage, VersionNotifiers, VersionNotifyTargets, - WeightInfo, + LatestVersionedLocation, Pallet, Queries, QueryStatus, VersionDiscoveryQueue, + VersionMigrationStage, VersionNotifiers, VersionNotifyTargets, WeightInfo, }; +use codec::Encode; use frame_support::{ assert_err_ignore_postinfo, assert_noop, assert_ok, traits::{Currency, Hooks}, @@ -305,11 +305,12 @@ fn send_works() { ]); let versioned_dest = Box::new(RelayLocation::get().into()); - let versioned_message = Box::new(VersionedXcm::from(message.clone())); - assert_ok!(XcmPallet::send( + let versioned_message = VersionedXcm::from(message.clone()); + let encoded_versioned_message = versioned_message.encode().try_into().unwrap(); + assert_ok!(XcmPallet::send_blob( RuntimeOrigin::signed(ALICE), versioned_dest, - versioned_message + encoded_versioned_message )); let sent_message = Xcm(Some(DescendOrigin(sender.clone().try_into().unwrap())) .into_iter() @@ -341,16 +342,16 @@ fn send_fails_when_xcm_router_blocks() { ]; new_test_ext_with_balances(balances).execute_with(|| { let sender: Location = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); - let message = Xcm(vec![ + let message = Xcm::<()>(vec![ ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), buy_execution((Parent, SEND_AMOUNT)), DepositAsset { assets: AllCounted(1).into(), beneficiary: sender }, ]); assert_noop!( - XcmPallet::send( + XcmPallet::send_blob( RuntimeOrigin::signed(ALICE), Box::new(Location::ancestor(8).into()), - Box::new(VersionedXcm::from(message.clone())), + VersionedXcm::from(message.clone()).encode().try_into().unwrap(), ), crate::Error::::SendFailure ); @@ -371,13 +372,16 @@ fn execute_withdraw_to_deposit_works() { let weight = BaseXcmWeight::get() * 3; let dest: Location = Junction::AccountId32 { network: None, id: BOB.into() }.into(); assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); - assert_ok!(XcmPallet::execute( + assert_ok!(XcmPallet::execute_blob( RuntimeOrigin::signed(ALICE), - Box::new(VersionedXcm::from(Xcm(vec![ + VersionedXcm::from(Xcm::(vec![ WithdrawAsset((Here, SEND_AMOUNT).into()), buy_execution((Here, SEND_AMOUNT)), DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, - ]))), + ])) + .encode() + .try_into() + .unwrap(), weight )); assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT); @@ -399,18 +403,21 @@ fn trapped_assets_can_be_claimed() { let weight = BaseXcmWeight::get() * 6; let dest: Location = Junction::AccountId32 { network: None, id: BOB.into() }.into(); - assert_ok!(XcmPallet::execute( + assert_ok!(XcmPallet::execute_blob( RuntimeOrigin::signed(ALICE), - Box::new(VersionedXcm::from(Xcm(vec![ + VersionedXcm::from(Xcm(vec![ WithdrawAsset((Here, SEND_AMOUNT).into()), buy_execution((Here, SEND_AMOUNT)), // Don't propagated the error into the result. - SetErrorHandler(Xcm(vec![ClearError])), + SetErrorHandler(Xcm::(vec![ClearError])), // This will make an error. Trap(0), // This would succeed, but we never get to it. DepositAsset { assets: AllCounted(1).into(), beneficiary: dest.clone() }, - ]))), + ])) + .encode() + .try_into() + .unwrap(), weight )); let source: Location = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); @@ -437,13 +444,16 @@ fn trapped_assets_can_be_claimed() { assert_eq!(trapped, expected); let weight = BaseXcmWeight::get() * 3; - assert_ok!(XcmPallet::execute( + assert_ok!(XcmPallet::execute_blob( RuntimeOrigin::signed(ALICE), - Box::new(VersionedXcm::from(Xcm(vec![ + VersionedXcm::from(Xcm::(vec![ ClaimAsset { assets: (Here, SEND_AMOUNT).into(), ticket: Here.into() }, buy_execution((Here, SEND_AMOUNT)), DepositAsset { assets: AllCounted(1).into(), beneficiary: dest.clone() }, - ]))), + ])) + .encode() + .try_into() + .unwrap(), weight )); @@ -453,13 +463,16 @@ fn trapped_assets_can_be_claimed() { // Can't claim twice. assert_err_ignore_postinfo!( - XcmPallet::execute( + XcmPallet::execute_blob( RuntimeOrigin::signed(ALICE), - Box::new(VersionedXcm::from(Xcm(vec![ + VersionedXcm::from(Xcm::(vec![ ClaimAsset { assets: (Here, SEND_AMOUNT).into(), ticket: Here.into() }, buy_execution((Here, SEND_AMOUNT)), DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, - ]))), + ])) + .encode() + .try_into() + .unwrap(), weight ), Error::::LocalExecutionIncomplete @@ -473,12 +486,13 @@ fn claim_assets_works() { let balances = vec![(ALICE, INITIAL_BALANCE)]; new_test_ext_with_balances(balances).execute_with(|| { // First trap some assets. - let trapping_program = - Xcm::builder_unsafe().withdraw_asset((Here, SEND_AMOUNT).into()).build(); + let trapping_program = Xcm::::builder_unsafe() + .withdraw_asset((Here, SEND_AMOUNT).into()) + .build(); // Even though assets are trapped, the extrinsic returns success. - assert_ok!(XcmPallet::execute( + assert_ok!(XcmPallet::execute_blob( RuntimeOrigin::signed(ALICE), - Box::new(VersionedXcm::V4(trapping_program)), + VersionedXcm::V4(trapping_program).encode().try_into().unwrap(), BaseXcmWeight::get() * 2, )); assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT); @@ -531,9 +545,9 @@ fn incomplete_execute_reverts_side_effects() { assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); let amount_to_send = INITIAL_BALANCE - ExistentialDeposit::get(); let assets: Assets = (Here, amount_to_send).into(); - let result = XcmPallet::execute( + let result = XcmPallet::execute_blob( RuntimeOrigin::signed(ALICE), - Box::new(VersionedXcm::from(Xcm(vec![ + VersionedXcm::from(Xcm::(vec![ // Withdraw + BuyExec + Deposit should work WithdrawAsset(assets.clone()), buy_execution(assets.inner()[0].clone()), @@ -541,7 +555,10 @@ fn incomplete_execute_reverts_side_effects() { // Withdrawing once more will fail because of InsufficientBalance, and we expect to // revert the effects of the above instructions as well WithdrawAsset(assets), - ]))), + ])) + .encode() + .try_into() + .unwrap(), weight, ); // all effects are reverted and balances unchanged for either sender or receiver @@ -553,7 +570,7 @@ fn incomplete_execute_reverts_side_effects() { Err(sp_runtime::DispatchErrorWithPostInfo { post_info: frame_support::dispatch::PostDispatchInfo { actual_weight: Some( - as ExecuteControllerWeightInfo>::execute() + weight + <::WeightInfo>::execute_blob() + weight ), pays_fee: frame_support::dispatch::Pays::Yes, }, diff --git a/polkadot/xcm/src/lib.rs b/polkadot/xcm/src/lib.rs index 86a17fa1e88..e836486e86e 100644 --- a/polkadot/xcm/src/lib.rs +++ b/polkadot/xcm/src/lib.rs @@ -48,6 +48,9 @@ mod tests; /// Maximum nesting level for XCM decoding. pub const MAX_XCM_DECODE_DEPTH: u32 = 8; +/// Maximum encoded size. +/// See `decoding_respects_limit` test for more reasoning behind this value. +pub const MAX_XCM_ENCODED_SIZE: u32 = 12402; /// A version of XCM. pub type Version = u32; diff --git a/polkadot/xcm/src/v4/mod.rs b/polkadot/xcm/src/v4/mod.rs index 30ee485589a..6635408282e 100644 --- a/polkadot/xcm/src/v4/mod.rs +++ b/polkadot/xcm/src/v4/mod.rs @@ -1488,7 +1488,21 @@ mod tests { let encoded = big_xcm.encode(); assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err()); - let nested_xcm = Xcm::<()>(vec![ + let mut many_assets = Assets::new(); + for index in 0..MAX_ITEMS_IN_ASSETS { + many_assets.push((GeneralIndex(index as u128), 1u128).into()); + } + + let full_xcm_pass = + Xcm::<()>(vec![ + TransferAsset { assets: many_assets, beneficiary: Here.into() }; + MAX_INSTRUCTIONS_TO_DECODE as usize + ]); + let encoded = full_xcm_pass.encode(); + assert_eq!(encoded.len(), 12402); + assert!(Xcm::<()>::decode(&mut &encoded[..]).is_ok()); + + let nested_xcm_fail = Xcm::<()>(vec![ DepositReserveAsset { assets: All.into(), dest: Here.into(), @@ -1496,10 +1510,10 @@ mod tests { }; (MAX_INSTRUCTIONS_TO_DECODE / 2) as usize ]); - let encoded = nested_xcm.encode(); + let encoded = nested_xcm_fail.encode(); assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err()); - let even_more_nested_xcm = Xcm::<()>(vec![SetAppendix(nested_xcm); 64]); + let even_more_nested_xcm = Xcm::<()>(vec![SetAppendix(nested_xcm_fail); 64]); let encoded = even_more_nested_xcm.encode(); assert_eq!(encoded.len(), 342530); // This should not decode since the limit is 100 diff --git a/polkadot/xcm/xcm-builder/src/controller.rs b/polkadot/xcm/xcm-builder/src/controller.rs index 04b19eaa587..6bdde2a967d 100644 --- a/polkadot/xcm/xcm-builder/src/controller.rs +++ b/polkadot/xcm/xcm-builder/src/controller.rs @@ -21,6 +21,7 @@ use frame_support::{ dispatch::{DispatchErrorWithPostInfo, WithPostDispatchInfo}, pallet_prelude::DispatchError, + parameter_types, BoundedVec, }; use sp_std::boxed::Box; use xcm::prelude::*; @@ -41,8 +42,12 @@ impl Controller f /// Weight functions needed for [`ExecuteController`]. pub trait ExecuteControllerWeightInfo { - /// Weight for [`ExecuteController::execute`] - fn execute() -> Weight; + /// Weight for [`ExecuteController::execute_blob`] + fn execute_blob() -> Weight; +} + +parameter_types! { + pub const MaxXcmEncodedSize: u32 = xcm::MAX_XCM_ENCODED_SIZE; } /// Execute an XCM locally, for a given origin. @@ -61,19 +66,19 @@ pub trait ExecuteController { /// # Parameters /// /// - `origin`: the origin of the call. - /// - `message`: the XCM program to be executed. + /// - `msg`: the encoded XCM to be executed, should be decodable as a [`VersionedXcm`] /// - `max_weight`: the maximum weight that can be consumed by the execution. - fn execute( + fn execute_blob( origin: Origin, - message: Box>, + message: BoundedVec, max_weight: Weight, ) -> Result; } /// Weight functions needed for [`SendController`]. pub trait SendControllerWeightInfo { - /// Weight for [`SendController::send`] - fn send() -> Weight; + /// Weight for [`SendController::send_blob`] + fn send_blob() -> Weight; } /// Send an XCM from a given origin. @@ -93,11 +98,11 @@ pub trait SendController { /// /// - `origin`: the origin of the call. /// - `dest`: the destination of the message. - /// - `msg`: the XCM to be sent. - fn send( + /// - `msg`: the encoded XCM to be sent, should be decodable as a [`VersionedXcm`] + fn send_blob( origin: Origin, dest: Box, - message: Box>, + message: BoundedVec, ) -> Result; } @@ -137,35 +142,35 @@ pub trait QueryController: QueryHandler { impl ExecuteController for () { type WeightInfo = (); - fn execute( + fn execute_blob( _origin: Origin, - _message: Box>, + _message: BoundedVec, _max_weight: Weight, ) -> Result { - Err(DispatchError::Other("ExecuteController::execute not implemented") + Err(DispatchError::Other("ExecuteController::execute_blob not implemented") .with_weight(Weight::zero())) } } impl ExecuteControllerWeightInfo for () { - fn execute() -> Weight { + fn execute_blob() -> Weight { Weight::zero() } } impl SendController for () { type WeightInfo = (); - fn send( + fn send_blob( _origin: Origin, _dest: Box, - _message: Box>, + _message: BoundedVec, ) -> Result { Ok(Default::default()) } } impl SendControllerWeightInfo for () { - fn send() -> Weight { + fn send_blob() -> Weight { Weight::zero() } } diff --git a/polkadot/xcm/xcm-builder/src/lib.rs b/polkadot/xcm/xcm-builder/src/lib.rs index e2af8187136..46d0ad227bf 100644 --- a/polkadot/xcm/xcm-builder/src/lib.rs +++ b/polkadot/xcm/xcm-builder/src/lib.rs @@ -43,7 +43,7 @@ pub use barriers::{ mod controller; pub use controller::{ - Controller, ExecuteController, ExecuteControllerWeightInfo, QueryController, + Controller, ExecuteController, ExecuteControllerWeightInfo, MaxXcmEncodedSize, QueryController, QueryControllerWeightInfo, QueryHandler, SendController, SendControllerWeightInfo, }; diff --git a/prdoc/pr_3749.prdoc b/prdoc/pr_3749.prdoc new file mode 100644 index 00000000000..1ebde9670e0 --- /dev/null +++ b/prdoc/pr_3749.prdoc @@ -0,0 +1,47 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "pallet-xcm: deprecate execute and send in favor of execute_blob and send_blob" + +doc: + - audience: Runtime Dev + description: | + pallet-xcm's extrinsics `execute` and `send` have been marked as deprecated. + Please change their usage to the new `execute_blob` and `send_blob`. + The migration from the old extrinsic to the new is very simple. + If you have your message `xcm: VersionedXcm`, then instead of passing in + `Box::new(xcm)` to both `execute` and `send`, you would pass in + `xcm.encode().try_into()` and handle the potential error of its encoded length + being bigger than `MAX_XCM_ENCODED_SIZE`. + + pallet-contracts takes the XCM encoded now as well. It follows the same API as + `execute_blob` and `send_blob`. + - audience: Runtime User + description: | + pallet-xcm has a new pair of extrinsics, `execute_blob` and `send_blob`. + These are meant to be used instead of `execute` and `send`, which are now deprecated + and will be removed eventually. + These new extrinsics just require you to input the encoded XCM. + There's a new utility in PolkadotJS Apps for encoding XCMs you can use: + https://polkadot.js.org/apps/#/utilities/xcm + Just pass in the encoded XCM to the new extrinsics and you're done. + + pallet-contracts takes the XCM encoded now as well. It follows the same API as + `execute_blob` and `send_blob`. + +crates: +- name: pallet-xcm +- name: staging-xcm +- name: staging-xcm-builder +- name: pallet-contracts +- name: asset-hub-rococo-runtime +- name: asset-hub-westend-runtime +- name: bridge-hub-rococo-runtime +- name: bridge-hub-westend-runtime +- name: collectives-westend-runtime +- name: coretime-rococo-runtime +- name: coretime-westend-runtime +- name: people-rococo-runtime +- name: people-westend-runtime +- name: rococo-runtime +- name: westend-runtime diff --git a/substrate/frame/contracts/mock-network/src/tests.rs b/substrate/frame/contracts/mock-network/src/tests.rs index d22221fe8ee..39aa9bebc0f 100644 --- a/substrate/frame/contracts/mock-network/src/tests.rs +++ b/substrate/frame/contracts/mock-network/src/tests.rs @@ -23,7 +23,6 @@ use crate::{ }; use codec::{Decode, Encode}; use frame_support::{ - assert_err, pallet_prelude::Weight, traits::{fungibles::Mutate, Currency}, }; @@ -102,7 +101,7 @@ fn test_xcm_execute() { 0, Weight::MAX, None, - VersionedXcm::V4(message).encode(), + VersionedXcm::V4(message).encode().encode(), DebugInfo::UnsafeDebug, CollectEvents::UnsafeCollect, Determinism::Enforced, @@ -146,7 +145,7 @@ fn test_xcm_execute_incomplete() { 0, Weight::MAX, None, - VersionedXcm::V4(message).encode(), + VersionedXcm::V4(message).encode().encode(), DebugInfo::UnsafeDebug, CollectEvents::UnsafeCollect, Determinism::Enforced, @@ -160,37 +159,6 @@ fn test_xcm_execute_incomplete() { }); } -#[test] -fn test_xcm_execute_filtered_call() { - MockNet::reset(); - - let contract_addr = instantiate_test_contract("xcm_execute"); - - ParaA::execute_with(|| { - // `remark` should be rejected, as it is not allowed by our CallFilter. - let call = parachain::RuntimeCall::System(frame_system::Call::remark { remark: vec![] }); - let message: Xcm = Xcm(vec![Transact { - origin_kind: OriginKind::Native, - require_weight_at_most: Weight::MAX, - call: call.encode().into(), - }]); - - let result = ParachainContracts::bare_call( - ALICE, - contract_addr.clone(), - 0, - Weight::MAX, - None, - VersionedXcm::V4(message).encode(), - DebugInfo::UnsafeDebug, - CollectEvents::UnsafeCollect, - Determinism::Enforced, - ); - - assert_err!(result.result, frame_system::Error::::CallFiltered); - }); -} - #[test] fn test_xcm_execute_reentrant_call() { MockNet::reset(); @@ -222,7 +190,7 @@ fn test_xcm_execute_reentrant_call() { 0, Weight::MAX, None, - VersionedXcm::V4(message).encode(), + VersionedXcm::V4(message).encode().encode(), DebugInfo::UnsafeDebug, CollectEvents::UnsafeCollect, Determinism::Enforced, @@ -258,7 +226,7 @@ fn test_xcm_send() { 0, Weight::MAX, None, - (dest, message).encode(), + (dest, message.encode()).encode(), DebugInfo::UnsafeDebug, CollectEvents::UnsafeCollect, Determinism::Enforced, diff --git a/substrate/frame/contracts/src/lib.rs b/substrate/frame/contracts/src/lib.rs index 6433d4eecdc..e14a4b8bcb8 100644 --- a/substrate/frame/contracts/src/lib.rs +++ b/substrate/frame/contracts/src/lib.rs @@ -298,6 +298,9 @@ pub mod pallet { /// Therefore please make sure to be restrictive about which dispatchables are allowed /// in order to not introduce a new DoS vector like memory allocation patterns that can /// be exploited to drive the runtime into a panic. + /// + /// This filter does not apply to XCM transact calls. To impose restrictions on XCM transact + /// calls, you must configure them separately within the XCM pallet itself. type CallFilter: Contains<::RuntimeCall>; /// Used to answer contracts' queries regarding the current weight price. This is **not** diff --git a/substrate/frame/contracts/src/wasm/runtime.rs b/substrate/frame/contracts/src/wasm/runtime.rs index 160dfa0d2f3..28a08ab0224 100644 --- a/substrate/frame/contracts/src/wasm/runtime.rs +++ b/substrate/frame/contracts/src/wasm/runtime.rs @@ -25,12 +25,8 @@ use crate::{ }; use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen}; use frame_support::{ - dispatch::DispatchInfo, - ensure, - pallet_prelude::{DispatchResult, DispatchResultWithPostInfo}, - parameter_types, - traits::Get, - weights::Weight, + dispatch::DispatchInfo, ensure, pallet_prelude::DispatchResultWithPostInfo, parameter_types, + traits::Get, weights::Weight, }; use pallet_contracts_proc_macro::define_env; use pallet_contracts_uapi::{CallFlags, ReturnFlags}; @@ -41,9 +37,6 @@ use sp_runtime::{ }; use sp_std::{fmt, prelude::*}; use wasmi::{core::HostError, errors::LinkerError, Linker, Memory, Store}; -use xcm::VersionedXcm; - -type CallOf = ::RuntimeCall; /// The maximum nesting depth a contract can use when encoding types. const MAX_DECODE_NESTING: u32 = 256; @@ -378,29 +371,6 @@ fn already_charged(_: u32) -> Option { None } -/// Ensure that the XCM program is executable, by checking that it does not contain any [`Transact`] -/// instruction with a call that is not allowed by the CallFilter. -fn ensure_executable(message: &VersionedXcm>) -> DispatchResult { - use frame_support::traits::Contains; - use xcm::prelude::{Transact, Xcm}; - - let mut message: Xcm> = - message.clone().try_into().map_err(|_| Error::::XCMDecodeFailed)?; - - message.iter_mut().try_for_each(|inst| -> DispatchResult { - let Transact { ref mut call, .. } = inst else { return Ok(()) }; - let call = call.ensure_decoded().map_err(|_| Error::::XCMDecodeFailed)?; - - if !::CallFilter::contains(call) { - return Err(frame_system::Error::::CallFiltered.into()) - } - - Ok(()) - })?; - - Ok(()) -} - /// Can only be used for one call. pub struct Runtime<'a, E: Ext + 'a> { ext: &'a mut E, @@ -2112,16 +2082,13 @@ pub mod env { msg_len: u32, ) -> Result { use frame_support::dispatch::DispatchInfo; - use xcm::VersionedXcm; use xcm_builder::{ExecuteController, ExecuteControllerWeightInfo}; ctx.charge_gas(RuntimeCosts::CopyFromContract(msg_len))?; - let message: VersionedXcm> = - ctx.read_sandbox_memory_as_unbounded(memory, msg_ptr, msg_len)?; - ensure_executable::(&message)?; + let message = ctx.read_sandbox_memory_as_unbounded(memory, msg_ptr, msg_len)?; let execute_weight = - <::Xcm as ExecuteController<_, _>>::WeightInfo::execute(); + <::Xcm as ExecuteController<_, _>>::WeightInfo::execute_blob(); let weight = ctx.ext.gas_meter().gas_left().max(execute_weight); let dispatch_info = DispatchInfo { weight, ..Default::default() }; @@ -2130,9 +2097,9 @@ pub mod env { RuntimeCosts::CallXcmExecute, |ctx| { let origin = crate::RawOrigin::Signed(ctx.ext.address().clone()).into(); - let weight_used = <::Xcm>::execute( + let weight_used = <::Xcm>::execute_blob( origin, - Box::new(message), + message, weight.saturating_sub(execute_weight), )?; @@ -2152,19 +2119,18 @@ pub mod env { msg_len: u32, output_ptr: u32, ) -> Result { - use xcm::{VersionedLocation, VersionedXcm}; + use xcm::VersionedLocation; use xcm_builder::{SendController, SendControllerWeightInfo}; ctx.charge_gas(RuntimeCosts::CopyFromContract(msg_len))?; let dest: VersionedLocation = ctx.read_sandbox_memory_as(memory, dest_ptr)?; - let message: VersionedXcm<()> = - ctx.read_sandbox_memory_as_unbounded(memory, msg_ptr, msg_len)?; - let weight = <::Xcm as SendController<_>>::WeightInfo::send(); + let message = ctx.read_sandbox_memory_as_unbounded(memory, msg_ptr, msg_len)?; + let weight = <::Xcm as SendController<_>>::WeightInfo::send_blob(); ctx.charge_gas(RuntimeCosts::CallRuntime(weight))?; let origin = crate::RawOrigin::Signed(ctx.ext.address().clone()).into(); - match <::Xcm>::send(origin, dest.into(), message.into()) { + match <::Xcm>::send_blob(origin, dest.into(), message) { Ok(message_id) => { ctx.write_sandbox_memory(memory, output_ptr, &message_id.encode())?; Ok(ReturnErrorCode::Success) diff --git a/substrate/frame/contracts/uapi/src/host.rs b/substrate/frame/contracts/uapi/src/host.rs index 04f58895ab4..459cb59bead 100644 --- a/substrate/frame/contracts/uapi/src/host.rs +++ b/substrate/frame/contracts/uapi/src/host.rs @@ -790,7 +790,7 @@ pub trait HostFn { /// /// # Parameters /// - /// - `dest`: The XCM destination, should be decodable as [VersionedMultiLocation](https://paritytech.github.io/polkadot-sdk/master/staging_xcm/enum.VersionedMultiLocation.html), + /// - `dest`: The XCM destination, should be decodable as [MultiLocation](https://paritytech.github.io/polkadot-sdk/master/staging_xcm/enum.VersionedLocation.html), /// traps otherwise. /// - `msg`: The message, should be decodable as a [VersionedXcm](https://paritytech.github.io/polkadot-sdk/master/staging_xcm/enum.VersionedXcm.html), /// traps otherwise. -- GitLab From 5ac32ee2bdd9df47e4578c51810db4d2139757eb Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Wed, 27 Mar 2024 11:49:10 +0200 Subject: [PATCH 106/187] authority-discovery: Set intervals to start when authority keys changes (#3764) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The authority-discovery mechanism has implemented a few exponential timers for: - publishing the authority records - goes from 2 seconds (when freshly booted) to 1 hour if the node is long-running - set to 1 hour after successfully publishing the authority record - discovering other authority records - goes from 2 seconds (when freshly booted) to 10 minutes if the node is long-running This PR resets the exponential publishing and discovery interval to defaults ensuring that long-running nodes: - will retry publishing the authority records as aggressively as freshly booted nodes - Currently, if a long-running node fails to publish the DHT record when the keys change (ie DhtEvent::ValuePutFailed), it will only retry after 1 hour - will rediscover other authorities faster (since there is a chance that other authority keys changed) The subp2p-explorer has difficulties discovering the authorities when the authority set changes in the first few hours. This might be entirely due to the recursive nature of the DHT and the needed time to propagate the records. However, there is a small chance that the authority publishing failed and is only retried in 1h. Let me know if this makes sense 🙏 cc @paritytech/networking --------- Signed-off-by: Alexandru Vasile Co-authored-by: Dmitry Markin --- .../authority-discovery/src/interval.rs | 20 +++++++++++-- .../client/authority-discovery/src/worker.rs | 28 +++++++++++++++++-- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/substrate/client/authority-discovery/src/interval.rs b/substrate/client/authority-discovery/src/interval.rs index 23c7ce266e3..0eee0d159cd 100644 --- a/substrate/client/authority-discovery/src/interval.rs +++ b/substrate/client/authority-discovery/src/interval.rs @@ -28,6 +28,7 @@ use std::{ /// /// Doubles interval duration on each tick until the configured maximum is reached. pub struct ExpIncInterval { + start: Duration, max: Duration, next: Duration, delay: Delay, @@ -37,14 +38,29 @@ impl ExpIncInterval { /// Create a new [`ExpIncInterval`]. pub fn new(start: Duration, max: Duration) -> Self { let delay = Delay::new(start); - Self { max, next: start * 2, delay } + Self { start, max, next: start * 2, delay } } - /// Fast forward the exponentially increasing interval to the configured maximum. + /// Fast forward the exponentially increasing interval to the configured maximum, if not already + /// set. pub fn set_to_max(&mut self) { + if self.next == self.max { + return; + } + self.next = self.max; self.delay = Delay::new(self.next); } + + /// Rewind the exponentially increasing interval to the configured start, if not already set. + pub fn set_to_start(&mut self) { + if self.next == self.start * 2 { + return; + } + + self.next = self.start * 2; + self.delay = Delay::new(self.start); + } } impl Stream for ExpIncInterval { diff --git a/substrate/client/authority-discovery/src/worker.rs b/substrate/client/authority-discovery/src/worker.rs index b77f0241ec2..4ad7db5f7da 100644 --- a/substrate/client/authority-discovery/src/worker.rs +++ b/substrate/client/authority-discovery/src/worker.rs @@ -129,6 +129,9 @@ pub struct Worker { /// List of keys onto which addresses have been published at the latest publication. /// Used to check whether they have changed. latest_published_keys: HashSet, + /// List of the kademlia keys that have been published at the latest publication. + /// Used to associate DHT events with our published records. + latest_published_kad_keys: HashSet, /// Same value as in the configuration. publish_non_global_ips: bool, @@ -265,6 +268,7 @@ where publish_interval, publish_if_changed_interval, latest_published_keys: HashSet::new(), + latest_published_kad_keys: HashSet::new(), publish_non_global_ips: config.publish_non_global_ips, public_addresses, strict_record_validation: config.strict_record_validation, @@ -397,8 +401,17 @@ where self.client.as_ref(), ).await?.into_iter().collect::>(); - if only_if_changed && keys == self.latest_published_keys { - return Ok(()) + if only_if_changed { + // If the authority keys did not change and the `publish_if_changed_interval` was + // triggered then do nothing. + if keys == self.latest_published_keys { + return Ok(()) + } + + // We have detected a change in the authority keys, reset the timers to + // publish and gather data faster. + self.publish_interval.set_to_start(); + self.query_interval.set_to_start(); } let addresses = serialize_addresses(self.addresses_to_publish()); @@ -422,6 +435,8 @@ where keys_vec, )?; + self.latest_published_kad_keys = kv_pairs.iter().map(|(k, _)| k.clone()).collect(); + for (key, value) in kv_pairs.into_iter() { self.network.put_value(key, value); } @@ -523,6 +538,10 @@ where } }, DhtEvent::ValuePut(hash) => { + if !self.latest_published_kad_keys.contains(&hash) { + return; + } + // Fast forward the exponentially increasing interval to the configured maximum. In // case this was the first successful address publishing there is no need for a // timely retry. @@ -535,6 +554,11 @@ where debug!(target: LOG_TARGET, "Successfully put hash '{:?}' on Dht.", hash) }, DhtEvent::ValuePutFailed(hash) => { + if !self.latest_published_kad_keys.contains(&hash) { + // Not a value we have published or received multiple times. + return; + } + if let Some(metrics) = &self.metrics { metrics.dht_event_received.with_label_values(&["value_put_failed"]).inc(); } -- GitLab From 25af0adf7836c67e28083276ec6f06d974e4f685 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Wed, 27 Mar 2024 12:50:03 +0100 Subject: [PATCH 107/187] [ci] Collect subsystem-benchmarks results and add graphs for them (#3853) PR adds CI jobs that collect subsystem-benchmarks results and publishes them to gh-pages. cc https://github.com/paritytech/ci_cd/issues/934 cc @AndreiEres --- .github/workflows/subsystem-benchmarks.yml | 42 ++++++++++++ .gitlab-ci.yml | 7 ++ .gitlab/pipeline/publish.yml | 76 ++++++++++++++++++++-- .gitlab/pipeline/test.yml | 6 ++ 4 files changed, 125 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/subsystem-benchmarks.yml diff --git a/.github/workflows/subsystem-benchmarks.yml b/.github/workflows/subsystem-benchmarks.yml new file mode 100644 index 00000000000..37a9e0f4680 --- /dev/null +++ b/.github/workflows/subsystem-benchmarks.yml @@ -0,0 +1,42 @@ +# The actions takes json file as input and runs github-action-benchmark for it. + +on: + workflow_dispatch: + inputs: + benchmark-data-dir-path: + description: "Path to the benchmark data directory" + required: true + type: string + output-file-path: + description: "Path to the benchmark data file" + required: true + type: string + +jobs: + subsystem-benchmarks: + runs-on: ubuntu-latest + steps: + - name: Checkout Sources + uses: actions/checkout@v4.1.2 + with: + fetch-depth: 0 + ref: "gh-pages" + + - name: Copy bench results + id: step_one + run: | + cp bench/gitlab/${{ github.event.inputs.output-file-path }} ${{ github.event.inputs.output-file-path }} + + - name: Switch branch + id: step_two + run: | + git checkout master + + - name: Store benchmark result + uses: benchmark-action/github-action-benchmark@v1 + with: + tool: "customSmallerIsBetter" + output-file-path: ${{ github.event.inputs.output-file-path }} + benchmark-data-dir-path: "bench/${{ github.event.inputs.benchmark-data-dir-path }}" + github-token: ${{ secrets.GITHUB_TOKEN }} + auto-push: true diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7f8796ca512..93a6ccb9f8f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -147,6 +147,13 @@ default: - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - if: $CI_COMMIT_REF_NAME =~ /^gh-readonly-queue.*$/ # merge queues +.publish-gh-pages-refs: + rules: + - if: $CI_PIPELINE_SOURCE == "pipeline" + when: never + - if: $CI_PIPELINE_SOURCE == "web" && $CI_COMMIT_REF_NAME == "master" + - if: $CI_COMMIT_REF_NAME == "master" + # handle the specific case where benches could store incorrect bench data because of the downstream staging runs # exclude cargo-check-benches from such runs .test-refs-check-benches: diff --git a/.gitlab/pipeline/publish.yml b/.gitlab/pipeline/publish.yml index b73acb560f6..bd9387f3c07 100644 --- a/.gitlab/pipeline/publish.yml +++ b/.gitlab/pipeline/publish.yml @@ -3,16 +3,13 @@ publish-rustdoc: stage: publish - extends: .kubernetes-env + extends: + - .kubernetes-env + - .publish-gh-pages-refs variables: CI_IMAGE: node:18 GIT_DEPTH: 100 RUSTDOCS_DEPLOY_REFS: "master" - rules: - - if: $CI_PIPELINE_SOURCE == "pipeline" - when: never - - if: $CI_PIPELINE_SOURCE == "web" && $CI_COMMIT_REF_NAME == "master" - - if: $CI_COMMIT_REF_NAME == "master" needs: - job: build-rustdoc artifacts: true @@ -60,9 +57,76 @@ publish-rustdoc: - git commit -m "___Updated docs for ${CI_COMMIT_REF_NAME}___" || echo "___Nothing to commit___" - git push origin gh-pages --force + # artificial sleep to publish gh-pages + - sleep 300 after_script: - rm -rf .git/ ./* +publish-subsystem-benchmarks: + stage: publish + variables: + CI_IMAGE: "paritytech/tools:latest" + extends: + - .kubernetes-env + - .publish-gh-pages-refs + needs: + - job: subsystem-regression-tests + artifacts: true + - job: publish-rustdoc + artifacts: false + script: + # setup ssh + - eval $(ssh-agent) + - ssh-add - <<< ${GITHUB_SSH_PRIV_KEY} + - mkdir ~/.ssh && touch ~/.ssh/known_hosts + - ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts + # Set git config + - rm -rf .git/config + - git config user.email "devops-team@parity.io" + - git config user.name "${GITHUB_USER}" + - git config remote.origin.url "git@github.com:/paritytech/${CI_PROJECT_NAME}.git" + - git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" + - git fetch origin gh-pages + # Push result to github + - git checkout gh-pages + - mkdir -p bench/gitlab/ || echo "Directory exists" + - rm -rf bench/gitlab/*.json || echo "No json files" + - cp -r charts/*.json bench/gitlab/ + - git add bench/gitlab/ + - git commit -m "Add json files with benchmark results for ${CI_COMMIT_REF_NAME}" + - git push origin gh-pages + # artificial sleep to publish gh-pages + - sleep 300 + allow_failure: true + after_script: + - rm -rf .git/ ./* + +trigger_workflow: + stage: deploy + extends: + - .kubernetes-env + - .publish-gh-pages-refs + needs: + - job: publish-subsystem-benchmarks + artifacts: false + - job: subsystem-regression-tests + artifacts: true + script: + - echo "Triggering workflow" + - | + for benchmark in $(ls charts/*.json); do + export bencmark_name=$(basename $benchmark) + echo "Benchmark: $bencmark_name" + export benchmark_dir=$(echo $bencmark_name | sed 's/\.json//') + curl -q -X POST \ + -H "Accept: application/vnd.github.v3+json" \ + -H "Authorization: token $GITHUB_TOKEN" \ + https://api.github.com/repos/paritytech-stg/${CI_PROJECT_NAME}/actions/workflows/subsystem-benchmarks.yml/dispatches \ + -d '{"ref":"refs/heads/master","inputs":{"benchmark-data-dir-path":"'$benchmark_dir'","output-file-path":"'$bencmark_name'"}}' + sleep 300 + done + allow_failure: true + # note: images are used not only in zombienet but also in rococo, wococo and versi .build-push-image: image: $BUILDAH_IMAGE diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index 476ac6333f5..d97f9da986c 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -497,6 +497,12 @@ test-syscalls: subsystem-regression-tests: stage: test + artifacts: + name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" + when: on_success + expire_in: 1 days + paths: + - charts/ extends: - .docker-env - .common-refs -- GitLab From 417c54c61c3fc77bd0402eec2c1ccfdb4ad38f8e Mon Sep 17 00:00:00 2001 From: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Date: Wed, 27 Mar 2024 16:44:10 +0200 Subject: [PATCH 108/187] collation-generation + collator-protocol: collate on multiple assigned cores (#3795) This works only for collators that implement the `collator_fn` allowing `collation-generation` subsystem to pull collations triggered on new heads. Also enables `request_v2::CollationFetchingResponse::CollationWithParentHeadData` for test adder/undying collators. TODO: - [x] fix tests - [x] new tests - [x] PR doc --------- Signed-off-by: Andrei Sandu --- .../consensus/aura/src/collators/lookahead.rs | 39 ++- .../node/collation-generation/src/error.rs | 2 + polkadot/node/collation-generation/src/lib.rs | 183 +++++++----- .../node/collation-generation/src/tests.rs | 261 +++++++++++++++++- .../src/collator_side/mod.rs | 129 ++++++--- .../src/collator_side/tests/mod.rs | 1 + .../tests/prospective_parachains.rs | 2 + .../src/collator_side/validators_buffer.rs | 18 +- polkadot/node/primitives/src/lib.rs | 6 +- polkadot/node/subsystem-types/src/messages.rs | 2 + polkadot/node/subsystem-util/src/lib.rs | 3 +- .../test-parachains/adder/collator/Cargo.toml | 2 +- .../undying/collator/Cargo.toml | 2 +- polkadot/runtime/test-runtime/src/lib.rs | 34 ++- prdoc/pr_3795.prdoc | 14 + 15 files changed, 557 insertions(+), 141 deletions(-) create mode 100644 prdoc/pr_3795.prdoc diff --git a/cumulus/client/consensus/aura/src/collators/lookahead.rs b/cumulus/client/consensus/aura/src/collators/lookahead.rs index 161f10d55a1..58005833617 100644 --- a/cumulus/client/consensus/aura/src/collators/lookahead.rs +++ b/cumulus/client/consensus/aura/src/collators/lookahead.rs @@ -49,7 +49,7 @@ use polkadot_node_subsystem::messages::{ CollationGenerationMessage, RuntimeApiMessage, RuntimeApiRequest, }; use polkadot_overseer::Handle as OverseerHandle; -use polkadot_primitives::{CollatorPair, Id as ParaId, OccupiedCoreAssumption}; +use polkadot_primitives::{CollatorPair, CoreIndex, Id as ParaId, OccupiedCoreAssumption}; use futures::{channel::oneshot, prelude::*}; use sc_client_api::{backend::AuxStore, BlockBackend, BlockOf}; @@ -184,7 +184,15 @@ where while let Some(relay_parent_header) = import_notifications.next().await { let relay_parent = relay_parent_header.hash(); - if !is_para_scheduled(relay_parent, params.para_id, &mut params.overseer_handle).await { + // TODO: Currently we use just the first core here, but for elastic scaling + // we iterate and build on all of the cores returned. + let core_index = if let Some(core_index) = + cores_scheduled_for_para(relay_parent, params.para_id, &mut params.overseer_handle) + .await + .get(0) + { + *core_index + } else { tracing::trace!( target: crate::LOG_TARGET, ?relay_parent, @@ -193,7 +201,7 @@ where ); continue - } + }; let max_pov_size = match params .relay_client @@ -396,6 +404,7 @@ where parent_head: parent_header.encode().into(), validation_code_hash, result_sender: None, + core_index, }, ), "SubmitCollation", @@ -480,14 +489,12 @@ async fn max_ancestry_lookback( } } -// Checks if there exists a scheduled core for the para at the provided relay parent. -// -// Falls back to `false` in case of an error. -async fn is_para_scheduled( +// Return all the cores assigned to the para at the provided relay parent. +async fn cores_scheduled_for_para( relay_parent: PHash, para_id: ParaId, overseer_handle: &mut OverseerHandle, -) -> bool { +) -> Vec { let (tx, rx) = oneshot::channel(); let request = RuntimeApiRequest::AvailabilityCores(tx); overseer_handle @@ -503,7 +510,7 @@ async fn is_para_scheduled( ?relay_parent, "Failed to query availability cores runtime API", ); - return false + return Vec::new() }, Err(oneshot::Canceled) => { tracing::error!( @@ -511,9 +518,19 @@ async fn is_para_scheduled( ?relay_parent, "Sender for availability cores runtime request dropped", ); - return false + return Vec::new() }, }; - cores.iter().any(|core| core.para_id() == Some(para_id)) + cores + .iter() + .enumerate() + .filter_map(|(index, core)| { + if core.para_id() == Some(para_id) { + Some(CoreIndex(index as u32)) + } else { + None + } + }) + .collect() } diff --git a/polkadot/node/collation-generation/src/error.rs b/polkadot/node/collation-generation/src/error.rs index ac5db6cd7f2..852c50f3068 100644 --- a/polkadot/node/collation-generation/src/error.rs +++ b/polkadot/node/collation-generation/src/error.rs @@ -28,6 +28,8 @@ pub enum Error { Util(#[from] polkadot_node_subsystem_util::Error), #[error(transparent)] Erasure(#[from] polkadot_erasure_coding::Error), + #[error("Parachain backing state not available in runtime.")] + MissingParaBackingState, } pub type Result = std::result::Result; diff --git a/polkadot/node/collation-generation/src/lib.rs b/polkadot/node/collation-generation/src/lib.rs index 3b1a8f5ff23..3164f6078bc 100644 --- a/polkadot/node/collation-generation/src/lib.rs +++ b/polkadot/node/collation-generation/src/lib.rs @@ -44,8 +44,8 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_util::{ has_required_runtime, request_async_backing_params, request_availability_cores, - request_claim_queue, request_persisted_validation_data, request_validation_code, - request_validation_code_hash, request_validators, + request_claim_queue, request_para_backing_state, request_persisted_validation_data, + request_validation_code, request_validation_code_hash, request_validators, }; use polkadot_primitives::{ collator_signature_payload, CandidateCommitments, CandidateDescriptor, CandidateReceipt, @@ -212,6 +212,7 @@ async fn handle_new_activations( if config.collator.is_none() { return Ok(()) } + let para_id = config.para_id; let _overall_timer = metrics.time_new_activations(); @@ -225,25 +226,23 @@ async fn handle_new_activations( ); let availability_cores = availability_cores??; - let n_validators = validators??.len(); let async_backing_params = async_backing_params?.ok(); + let n_validators = validators??.len(); let maybe_claim_queue = fetch_claim_queue(ctx.sender(), relay_parent).await?; - for (core_idx, core) in availability_cores.into_iter().enumerate() { - let _availability_core_timer = metrics.time_new_activations_availability_core(); + // The loop bellow will fill in cores that the para is allowed to build on. + let mut cores_to_build_on = Vec::new(); - let (scheduled_core, assumption) = match core { - CoreState::Scheduled(scheduled_core) => - (scheduled_core, OccupiedCoreAssumption::Free), + for (core_idx, core) in availability_cores.into_iter().enumerate() { + let scheduled_core = match core { + CoreState::Scheduled(scheduled_core) => scheduled_core, CoreState::Occupied(occupied_core) => match async_backing_params { Some(params) if params.max_candidate_depth >= 1 => { // maximum candidate depth when building on top of a block // pending availability is necessarily 1 - the depth of the // pending block is 0 so the child has depth 1. - // TODO [now]: this assumes that next up == current. - // in practice we should only set `OccupiedCoreAssumption::Included` - // when the candidate occupying the core is also of the same para. + // Use claim queue if available, or fallback to `next_up_on_available` let res = match maybe_claim_queue { Some(ref claim_queue) => { // read what's in the claim queue for this core @@ -257,8 +256,7 @@ async fn handle_new_activations( // `next_up_on_available` occupied_core.next_up_on_available }, - } - .map(|scheduled| (scheduled, OccupiedCoreAssumption::Included)); + }; match res { Some(res) => res, @@ -279,7 +277,7 @@ async fn handle_new_activations( gum::trace!( target: LOG_TARGET, core_idx = %core_idx, - "core is free. Keep going.", + "core is not assigned to any para. Keep going.", ); continue }, @@ -294,64 +292,90 @@ async fn handle_new_activations( their_para = %scheduled_core.para_id, "core is not assigned to our para. Keep going.", ); - continue + } else { + // Accumulate cores for building collation(s) outside the loop. + cores_to_build_on.push(CoreIndex(core_idx as u32)); } + } - // we get validation data and validation code synchronously for each core instead of - // within the subtask loop, because we have only a single mutable handle to the - // context, so the work can't really be distributed - - let validation_data = match request_persisted_validation_data( - relay_parent, - scheduled_core.para_id, - assumption, - ctx.sender(), - ) - .await - .await?? - { - Some(v) => v, - None => { - gum::trace!( - target: LOG_TARGET, - core_idx = %core_idx, - relay_parent = ?relay_parent, - our_para = %config.para_id, - their_para = %scheduled_core.para_id, - "validation data is not available", - ); - continue - }, - }; + // Skip to next relay parent if there is no core assigned to us. + if cores_to_build_on.is_empty() { + continue + } - let validation_code_hash = match obtain_validation_code_hash_with_assumption( - relay_parent, - scheduled_core.para_id, - assumption, - ctx.sender(), - ) - .await? - { - Some(v) => v, - None => { - gum::trace!( - target: LOG_TARGET, - core_idx = %core_idx, - relay_parent = ?relay_parent, - our_para = %config.para_id, - their_para = %scheduled_core.para_id, - "validation code hash is not found.", - ); - continue - }, - }; + let para_backing_state = + request_para_backing_state(relay_parent, config.para_id, ctx.sender()) + .await + .await?? + .ok_or(crate::error::Error::MissingParaBackingState)?; + + // We are being very optimistic here, but one of the cores could pend availability some more + // block, ore even time out. + // For timeout assumption the collator can't really know because it doesn't receive bitfield + // gossip. + let assumption = if para_backing_state.pending_availability.is_empty() { + OccupiedCoreAssumption::Free + } else { + OccupiedCoreAssumption::Included + }; + + gum::debug!( + target: LOG_TARGET, + relay_parent = ?relay_parent, + our_para = %config.para_id, + ?assumption, + "Occupied core(s) assumption", + ); + + let mut validation_data = match request_persisted_validation_data( + relay_parent, + config.para_id, + assumption, + ctx.sender(), + ) + .await + .await?? + { + Some(v) => v, + None => { + gum::debug!( + target: LOG_TARGET, + relay_parent = ?relay_parent, + our_para = %config.para_id, + "validation data is not available", + ); + continue + }, + }; - let task_config = config.clone(); - let metrics = metrics.clone(); - let mut task_sender = ctx.sender().clone(); - ctx.spawn( - "collation-builder", - Box::pin(async move { + let validation_code_hash = match obtain_validation_code_hash_with_assumption( + relay_parent, + config.para_id, + assumption, + ctx.sender(), + ) + .await? + { + Some(v) => v, + None => { + gum::debug!( + target: LOG_TARGET, + relay_parent = ?relay_parent, + our_para = %config.para_id, + "validation code hash is not found.", + ); + continue + }, + }; + + let task_config = config.clone(); + let metrics = metrics.clone(); + let mut task_sender = ctx.sender().clone(); + + ctx.spawn( + "chained-collation-builder", + Box::pin(async move { + for core_index in cores_to_build_on { let collator_fn = match task_config.collator.as_ref() { Some(x) => x, None => return, @@ -363,21 +387,23 @@ async fn handle_new_activations( None => { gum::debug!( target: LOG_TARGET, - para_id = %scheduled_core.para_id, + ?para_id, "collator returned no collation on collate", ); return }, }; + let parent_head = collation.head_data.clone(); construct_and_distribute_receipt( PreparedCollation { collation, - para_id: scheduled_core.para_id, + para_id, relay_parent, - validation_data, + validation_data: validation_data.clone(), validation_code_hash, n_validators, + core_index, }, task_config.key.clone(), &mut task_sender, @@ -385,9 +411,13 @@ async fn handle_new_activations( &metrics, ) .await; - }), - )?; - } + + // Chain the collations. All else stays the same as we build the chained + // collation on same relay parent. + validation_data.parent_head = parent_head; + } + }), + )?; } Ok(()) @@ -408,6 +438,7 @@ async fn handle_submit_collation( parent_head, validation_code_hash, result_sender, + core_index, } = params; let validators = request_validators(relay_parent, ctx.sender()).await.await??; @@ -444,6 +475,7 @@ async fn handle_submit_collation( validation_data, validation_code_hash, n_validators, + core_index, }; construct_and_distribute_receipt( @@ -465,6 +497,7 @@ struct PreparedCollation { validation_data: PersistedValidationData, validation_code_hash: ValidationCodeHash, n_validators: usize, + core_index: CoreIndex, } /// Takes a prepared collation, along with its context, and produces a candidate receipt @@ -483,6 +516,7 @@ async fn construct_and_distribute_receipt( validation_data, validation_code_hash, n_validators, + core_index, } = collation; let persisted_validation_data_hash = validation_data.hash(); @@ -578,6 +612,7 @@ async fn construct_and_distribute_receipt( pov, parent_head_data, result_sender, + core_index, }) .await; } diff --git a/polkadot/node/collation-generation/src/tests.rs b/polkadot/node/collation-generation/src/tests.rs index 9b16980e6af..3cb3e61a35a 100644 --- a/polkadot/node/collation-generation/src/tests.rs +++ b/polkadot/node/collation-generation/src/tests.rs @@ -30,13 +30,16 @@ use polkadot_node_subsystem::{ use polkadot_node_subsystem_test_helpers::{subsystem_test_harness, TestSubsystemContextHandle}; use polkadot_node_subsystem_util::TimeoutExt; use polkadot_primitives::{ - AsyncBackingParams, CollatorPair, HeadData, Id as ParaId, Id, PersistedValidationData, + async_backing::{BackingState, CandidatePendingAvailability}, + AsyncBackingParams, BlockNumber, CollatorPair, HeadData, PersistedValidationData, ScheduledCore, ValidationCode, }; use rstest::rstest; use sp_keyring::sr25519::Keyring as Sr25519Keyring; use std::pin::Pin; -use test_helpers::{dummy_candidate_descriptor, dummy_hash, dummy_head_data, dummy_validator}; +use test_helpers::{ + dummy_candidate_descriptor, dummy_hash, dummy_head_data, dummy_validator, make_candidate, +}; type VirtualOverseer = TestSubsystemContextHandle; @@ -105,9 +108,9 @@ impl Future for TestCollator { impl Unpin for TestCollator {} -async fn overseer_recv(overseer: &mut VirtualOverseer) -> AllMessages { - const TIMEOUT: std::time::Duration = std::time::Duration::from_millis(2000); +const TIMEOUT: std::time::Duration = std::time::Duration::from_millis(2000); +async fn overseer_recv(overseer: &mut VirtualOverseer) -> AllMessages { overseer .recv() .timeout(TIMEOUT) @@ -135,6 +138,41 @@ fn scheduled_core_for>(para_id: Id) -> ScheduledCore { ScheduledCore { para_id: para_id.into(), collator: None } } +fn dummy_candidate_pending_availability( + para_id: ParaId, + candidate_relay_parent: Hash, + relay_parent_number: BlockNumber, +) -> CandidatePendingAvailability { + let (candidate, _pvd) = make_candidate( + candidate_relay_parent, + relay_parent_number, + para_id, + dummy_head_data(), + HeadData(vec![1]), + ValidationCode(vec![1, 2, 3]).hash(), + ); + let candidate_hash = candidate.hash(); + + CandidatePendingAvailability { + candidate_hash, + descriptor: candidate.descriptor, + commitments: candidate.commitments, + relay_parent_number, + max_pov_size: 5 * 1024 * 1024, + } +} + +fn dummy_backing_state(pending_availability: Vec) -> BackingState { + let constraints = helpers::dummy_constraints( + 0, + vec![0], + dummy_head_data(), + ValidationCodeHash::from(Hash::repeat_byte(42)), + ); + + BackingState { constraints, pending_availability } +} + #[rstest] #[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT - 1)] #[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT)] @@ -176,6 +214,12 @@ fn requests_availability_per_relay_parent(#[case] runtime_version: u32) { ))) if runtime_version >= RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT => { tx.send(Ok(BTreeMap::new())).unwrap(); }, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _hash, + RuntimeApiRequest::ParaBackingState(_para_id, tx), + ))) => { + tx.send(Ok(Some(dummy_backing_state(vec![])))).unwrap(); + }, Some(msg) => panic!("didn't expect any other overseer requests given no availability cores; got {:?}", msg), } } @@ -273,6 +317,12 @@ fn requests_validation_data_for_scheduled_matches(#[case] runtime_version: u32) ))) if runtime_version >= RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT => { tx.send(Ok(BTreeMap::new())).unwrap(); }, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _hash, + RuntimeApiRequest::ParaBackingState(_para_id, tx), + ))) => { + tx.send(Ok(Some(dummy_backing_state(vec![])))).unwrap(); + }, Some(msg) => { panic!("didn't expect any other overseer requests; got {:?}", msg) }, @@ -384,6 +434,12 @@ fn sends_distribute_collation_message(#[case] runtime_version: u32) { ))) if runtime_version >= RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT => { tx.send(Ok(BTreeMap::new())).unwrap(); }, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _hash, + RuntimeApiRequest::ParaBackingState(_para_id, tx), + ))) => { + tx.send(Ok(Some(dummy_backing_state(vec![])))).unwrap(); + }, Some(msg @ AllMessages::CollatorProtocol(_)) => { inner_to_collator_protocol.lock().await.push(msg); }, @@ -564,6 +620,12 @@ fn fallback_when_no_validation_code_hash_api(#[case] runtime_version: u32) { let res = BTreeMap::>::new(); tx.send(Ok(res)).unwrap(); }, + Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _hash, + RuntimeApiRequest::ParaBackingState(_para_id, tx), + ))) => { + tx.send(Ok(Some(dummy_backing_state(vec![])))).unwrap(); + }, Some(msg) => { panic!("didn't expect any other overseer requests; got {:?}", msg) }, @@ -611,6 +673,7 @@ fn submit_collation_is_no_op_before_initialization() { parent_head: vec![1, 2, 3].into(), validation_code_hash: Hash::repeat_byte(1).into(), result_sender: None, + core_index: CoreIndex(0), }), }) .await; @@ -647,6 +710,7 @@ fn submit_collation_leads_to_distribution() { parent_head: vec![1, 2, 3].into(), validation_code_hash, result_sender: None, + core_index: CoreIndex(0), }), }) .await; @@ -721,6 +785,9 @@ fn distribute_collation_for_occupied_core_with_async_backing_enabled(#[case] run test_harness(|mut virtual_overseer| async move { helpers::initialize_collator(&mut virtual_overseer, para_id).await; helpers::activate_new_head(&mut virtual_overseer, activated_hash).await; + + let pending_availability = + vec![dummy_candidate_pending_availability(para_id, activated_hash, 1)]; helpers::handle_runtime_calls_on_new_head_activation( &mut virtual_overseer, activated_hash, @@ -728,14 +795,140 @@ fn distribute_collation_for_occupied_core_with_async_backing_enabled(#[case] run cores, runtime_version, claim_queue, + pending_availability, + ) + .await; + helpers::handle_core_processing_for_a_leaf( + &mut virtual_overseer, + activated_hash, + para_id, + // `CoreState` is `Occupied` => `OccupiedCoreAssumption` is `Included` + OccupiedCoreAssumption::Included, + 1, + ) + .await; + + virtual_overseer + }); +} + +// There are variable number of cores of cores in `Occupied` state and async backing is enabled. +// On new head activation `CollationGeneration` should produce and distribute a new collation +// with proper assumption about the para candidate chain availability at next block. +#[rstest] +#[case(0)] +#[case(1)] +#[case(2)] +fn distribute_collation_for_occupied_cores_with_async_backing_enabled_and_elastic_scaling( + #[case] candidates_pending_avail: u32, +) { + let activated_hash: Hash = [1; 32].into(); + let para_id = ParaId::from(5); + + let cores = (0..candidates_pending_avail) + .into_iter() + .map(|idx| { + CoreState::Occupied(polkadot_primitives::OccupiedCore { + next_up_on_available: Some(ScheduledCore { para_id, collator: None }), + occupied_since: 0, + time_out_at: 10, + next_up_on_time_out: Some(ScheduledCore { para_id, collator: None }), + availability: Default::default(), // doesn't matter + group_responsible: polkadot_primitives::GroupIndex(idx as u32), + candidate_hash: Default::default(), + candidate_descriptor: dummy_candidate_descriptor(dummy_hash()), + }) + }) + .collect::>(); + + let pending_availability = (0..candidates_pending_avail) + .into_iter() + .map(|_idx| dummy_candidate_pending_availability(para_id, activated_hash, 0)) + .collect::>(); + + let claim_queue = cores + .iter() + .enumerate() + .map(|(idx, _core)| (CoreIndex::from(idx as u32), VecDeque::from([para_id]))) + .collect::>(); + let total_cores = cores.len(); + + test_harness(|mut virtual_overseer| async move { + helpers::initialize_collator(&mut virtual_overseer, para_id).await; + helpers::activate_new_head(&mut virtual_overseer, activated_hash).await; + helpers::handle_runtime_calls_on_new_head_activation( + &mut virtual_overseer, + activated_hash, + AsyncBackingParams { max_candidate_depth: 1, allowed_ancestry_len: 1 }, + cores, + // Using latest runtime with the fancy claim queue exposed. + RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT, + claim_queue, + pending_availability, ) .await; + helpers::handle_core_processing_for_a_leaf( &mut virtual_overseer, activated_hash, para_id, // `CoreState` is `Occupied` => `OccupiedCoreAssumption` is `Included` OccupiedCoreAssumption::Included, + total_cores, + ) + .await; + + virtual_overseer + }); +} + +// There are variable number of cores of cores in `Free` state and async backing is enabled. +// On new head activation `CollationGeneration` should produce and distribute a new collation +// with proper assumption about the para candidate chain availability at next block. +#[rstest] +#[case(0)] +#[case(1)] +#[case(2)] +fn distribute_collation_for_free_cores_with_async_backing_enabled_and_elastic_scaling( + #[case] candidates_pending_avail: u32, +) { + let activated_hash: Hash = [1; 32].into(); + let para_id = ParaId::from(5); + + let cores = (0..candidates_pending_avail) + .into_iter() + .map(|_idx| CoreState::Scheduled(ScheduledCore { para_id, collator: None })) + .collect::>(); + + let claim_queue = cores + .iter() + .enumerate() + .map(|(idx, _core)| (CoreIndex::from(idx as u32), VecDeque::from([para_id]))) + .collect::>(); + let total_cores = cores.len(); + + test_harness(|mut virtual_overseer| async move { + helpers::initialize_collator(&mut virtual_overseer, para_id).await; + helpers::activate_new_head(&mut virtual_overseer, activated_hash).await; + helpers::handle_runtime_calls_on_new_head_activation( + &mut virtual_overseer, + activated_hash, + AsyncBackingParams { max_candidate_depth: 1, allowed_ancestry_len: 1 }, + cores, + // Using latest runtime with the fancy claim queue exposed. + RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT, + claim_queue, + vec![], + ) + .await; + + helpers::handle_core_processing_for_a_leaf( + &mut virtual_overseer, + activated_hash, + para_id, + // `CoreState` is `Free` => `OccupiedCoreAssumption` is `Free` + OccupiedCoreAssumption::Free, + total_cores, ) .await; @@ -777,6 +970,7 @@ fn no_collation_is_distributed_for_occupied_core_with_async_backing_disabled( cores, runtime_version, claim_queue, + vec![], ) .await; @@ -785,8 +979,38 @@ fn no_collation_is_distributed_for_occupied_core_with_async_backing_disabled( } mod helpers { + use polkadot_primitives::{ + async_backing::{Constraints, InboundHrmpLimitations}, + BlockNumber, + }; + use super::*; + // A set for dummy constraints for `ParaBackingState`` + pub(crate) fn dummy_constraints( + min_relay_parent_number: BlockNumber, + valid_watermarks: Vec, + required_parent: HeadData, + validation_code_hash: ValidationCodeHash, + ) -> Constraints { + Constraints { + min_relay_parent_number, + max_pov_size: 5 * 1024 * 1024, + max_code_size: 1_000_000, + ump_remaining: 10, + ump_remaining_bytes: 1_000, + max_ump_num_per_candidate: 10, + dmp_remaining_messages: vec![], + hrmp_inbound: InboundHrmpLimitations { valid_watermarks }, + hrmp_channels_out: vec![], + max_hrmp_num_per_candidate: 0, + required_parent, + validation_code_hash, + upgrade_restriction: None, + future_validation_code: None, + } + } + // Sends `Initialize` with a collator config pub async fn initialize_collator(virtual_overseer: &mut VirtualOverseer, para_id: ParaId) { virtual_overseer @@ -822,7 +1046,8 @@ mod helpers { async_backing_params: AsyncBackingParams, cores: Vec, runtime_version: u32, - claim_queue: BTreeMap>, + claim_queue: BTreeMap>, + pending_availability: Vec, ) { assert_matches!( overseer_recv(virtual_overseer).await, @@ -857,6 +1082,25 @@ mod helpers { } ); + // Process the `ParaBackingState` message, and return some dummy state. + let message = overseer_recv(virtual_overseer).await; + let para_id = match message { + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::ParaBackingState(p_id, _), + )) => p_id, + _ => panic!("received unexpected message {:?}", message), + }; + + assert_matches!( + message, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::ParaBackingState(p_id, tx)) + ) if parent == activated_hash && p_id == para_id => { + tx.send(Ok(Some(dummy_backing_state(pending_availability)))).unwrap(); + } + ); + assert_matches!( overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( @@ -889,7 +1133,14 @@ mod helpers { activated_hash: Hash, para_id: ParaId, expected_occupied_core_assumption: OccupiedCoreAssumption, + cores_assigned: usize, ) { + // Expect no messages if no cores is assigned to the para + if cores_assigned == 0 { + assert!(overseer_recv(virtual_overseer).timeout(TIMEOUT / 2).await.is_none()); + return + } + // Some hardcoded data - if needed, extract to parameters let validation_code_hash = ValidationCodeHash::from(Hash::repeat_byte(42)); let parent_head = HeadData::from(vec![1, 2, 3]); diff --git a/polkadot/node/network/collator-protocol/src/collator_side/mod.rs b/polkadot/node/network/collator-protocol/src/collator_side/mod.rs index 9f306f288a1..e6aa55235b7 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/mod.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/mod.rs @@ -203,20 +203,40 @@ struct PeerData { version: CollationVersion, } +/// A type wrapping a collation and it's designated core index. +struct CollationWithCoreIndex(Collation, CoreIndex); + +impl CollationWithCoreIndex { + /// Returns inner collation ref. + pub fn collation(&self) -> &Collation { + &self.0 + } + + /// Returns inner collation mut ref. + pub fn collation_mut(&mut self) -> &mut Collation { + &mut self.0 + } + + /// Returns inner core index. + pub fn core_index(&self) -> &CoreIndex { + &self.1 + } +} + struct PerRelayParent { prospective_parachains_mode: ProspectiveParachainsMode, - /// Validators group responsible for backing candidates built + /// Per core index validators group responsible for backing candidates built /// on top of this relay parent. - validator_group: ValidatorGroup, + validator_group: HashMap, /// Distributed collations. - collations: HashMap, + collations: HashMap, } impl PerRelayParent { fn new(mode: ProspectiveParachainsMode) -> Self { Self { prospective_parachains_mode: mode, - validator_group: ValidatorGroup::default(), + validator_group: HashMap::default(), collations: HashMap::new(), } } @@ -350,6 +370,7 @@ async fn distribute_collation( pov: PoV, parent_head_data: HeadData, result_sender: Option>, + core_index: CoreIndex, ) -> Result<()> { let candidate_relay_parent = receipt.descriptor.relay_parent; let candidate_hash = receipt.hash(); @@ -422,7 +443,22 @@ async fn distribute_collation( ); } - let our_core = our_cores[0]; + // Double check that the specified `core_index` is among the ones our para has assignments for. + if !our_cores.iter().any(|assigned_core| assigned_core == &core_index) { + gum::warn!( + target: LOG_TARGET, + para_id = %id, + relay_parent = ?candidate_relay_parent, + cores = ?our_cores, + ?core_index, + "Attempting to distribute collation for a core we are not assigned to ", + ); + + return Ok(()) + } + + let our_core = core_index; + // Determine the group on that core. // // When prospective parachains are disabled, candidate relay parent here is @@ -464,10 +500,12 @@ async fn distribute_collation( "Accepted collation, connecting to validators." ); - let validators_at_relay_parent = &mut per_relay_parent.validator_group.validators; - if validators_at_relay_parent.is_empty() { - *validators_at_relay_parent = validators; - } + // Insert validator group for the `core_index` at relay parent. + per_relay_parent.validator_group.entry(core_index).or_insert_with(|| { + let mut group = ValidatorGroup::default(); + group.validators = validators; + group + }); // Update a set of connected validators if necessary. connect_to_validators(ctx, &state.validator_groups_buf).await; @@ -484,7 +522,10 @@ async fn distribute_collation( per_relay_parent.collations.insert( candidate_hash, - Collation { receipt, pov, parent_head_data, status: CollationStatus::Created }, + CollationWithCoreIndex( + Collation { receipt, pov, parent_head_data, status: CollationStatus::Created }, + core_index, + ), ); // If prospective parachains are disabled, a leaf should be known to peer. @@ -690,7 +731,10 @@ async fn advertise_collation( advertisement_timeouts: &mut FuturesUnordered, metrics: &Metrics, ) { - for (candidate_hash, collation) in per_relay_parent.collations.iter_mut() { + for (candidate_hash, collation_and_core) in per_relay_parent.collations.iter_mut() { + let core_index = *collation_and_core.core_index(); + let collation = collation_and_core.collation_mut(); + // Check that peer will be able to request the collation. if let CollationVersion::V1 = protocol_version { if per_relay_parent.prospective_parachains_mode.is_enabled() { @@ -704,11 +748,17 @@ async fn advertise_collation( } } - let should_advertise = - per_relay_parent - .validator_group - .should_advertise_to(candidate_hash, peer_ids, &peer); + let Some(validator_group) = per_relay_parent.validator_group.get_mut(&core_index) else { + gum::debug!( + target: LOG_TARGET, + ?relay_parent, + ?core_index, + "Skipping advertising to validator, validator group for core not found", + ); + return + }; + let should_advertise = validator_group.should_advertise_to(candidate_hash, peer_ids, &peer); match should_advertise { ShouldAdvertiseTo::Yes => {}, ShouldAdvertiseTo::NotAuthority | ShouldAdvertiseTo::AlreadyAdvertised => { @@ -756,9 +806,7 @@ async fn advertise_collation( )) .await; - per_relay_parent - .validator_group - .advertised_to_peer(candidate_hash, &peer_ids, peer); + validator_group.advertised_to_peer(candidate_hash, &peer_ids, peer); advertisement_timeouts.push(ResetInterestTimeout::new( *candidate_hash, @@ -790,6 +838,7 @@ async fn process_msg( pov, parent_head_data, result_sender, + core_index, } => { let _span1 = state .span_per_relay_parent @@ -820,6 +869,7 @@ async fn process_msg( pov, parent_head_data, result_sender, + core_index, ) .await?; }, @@ -1053,7 +1103,7 @@ async fn handle_incoming_request( }; let mode = per_relay_parent.prospective_parachains_mode; - let collation = match &req { + let collation_with_core = match &req { VersionedCollationRequest::V1(_) if !mode.is_enabled() => per_relay_parent.collations.values_mut().next(), VersionedCollationRequest::V2(req) => @@ -1070,22 +1120,24 @@ async fn handle_incoming_request( return Ok(()) }, }; - let (receipt, pov, parent_head_data) = if let Some(collation) = collation { - collation.status.advance_to_requested(); - ( - collation.receipt.clone(), - collation.pov.clone(), - collation.parent_head_data.clone(), - ) - } else { - gum::warn!( - target: LOG_TARGET, - relay_parent = %relay_parent, - "received a `RequestCollation` for a relay parent we don't have collation stored.", - ); + let (receipt, pov, parent_head_data) = + if let Some(collation_with_core) = collation_with_core { + let collation = collation_with_core.collation_mut(); + collation.status.advance_to_requested(); + ( + collation.receipt.clone(), + collation.pov.clone(), + collation.parent_head_data.clone(), + ) + } else { + gum::warn!( + target: LOG_TARGET, + relay_parent = %relay_parent, + "received a `RequestCollation` for a relay parent we don't have collation stored.", + ); - return Ok(()) - }; + return Ok(()) + }; state.metrics.on_collation_sent_requested(); @@ -1340,7 +1392,9 @@ where .remove(removed) .map(|per_relay_parent| per_relay_parent.collations) .unwrap_or_default(); - for collation in collations.into_values() { + for collation_with_core in collations.into_values() { + let collation = collation_with_core.collation(); + let candidate_hash = collation.receipt.hash(); state.collation_result_senders.remove(&candidate_hash); state.validator_groups_buf.remove_candidate(&candidate_hash); @@ -1477,7 +1531,7 @@ async fn run_inner( continue }; - let next_collation = { + let next_collation_with_core = { let per_relay_parent = match state.per_relay_parent.get(&relay_parent) { Some(per_relay_parent) => per_relay_parent, None => continue, @@ -1497,7 +1551,8 @@ async fn run_inner( } }; - if let Some(collation) = next_collation { + if let Some(collation_with_core) = next_collation_with_core { + let collation = collation_with_core.collation(); let receipt = collation.receipt.clone(); let pov = collation.pov.clone(); let parent_head_data = collation.parent_head_data.clone(); diff --git a/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs b/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs index 38e6780eb7d..bcf0b34e631 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs @@ -377,6 +377,7 @@ async fn distribute_collation_with_receipt( pov: pov.clone(), parent_head_data: HeadData(vec![1, 2, 3]), result_sender: None, + core_index: CoreIndex(0), }, ) .await; diff --git a/polkadot/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs b/polkadot/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs index e419cd5444f..70705354563 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs @@ -277,6 +277,7 @@ fn distribute_collation_from_implicit_view() { pov: pov.clone(), parent_head_data: HeadData(vec![1, 2, 3]), result_sender: None, + core_index: CoreIndex(0), }, ) .await; @@ -358,6 +359,7 @@ fn distribute_collation_up_to_limit() { pov: pov.clone(), parent_head_data: HeadData(vec![1, 2, 3]), result_sender: None, + core_index: CoreIndex(0), }, ) .await; diff --git a/polkadot/node/network/collator-protocol/src/collator_side/validators_buffer.rs b/polkadot/node/network/collator-protocol/src/collator_side/validators_buffer.rs index 1533f2eda5a..fbb3ff4328a 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/validators_buffer.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/validators_buffer.rs @@ -45,14 +45,22 @@ use futures::FutureExt; use polkadot_node_network_protocol::PeerId; use polkadot_primitives::{AuthorityDiscoveryId, CandidateHash, GroupIndex, SessionIndex}; +/// Elastic scaling: how many candidates per relay chain block the collator supports building. +pub const MAX_CHAINED_CANDIDATES_PER_RCB: NonZeroUsize = match NonZeroUsize::new(3) { + Some(cap) => cap, + None => panic!("max candidates per rcb cannot be zero"), +}; + /// The ring buffer stores at most this many unique validator groups. /// /// This value should be chosen in way that all groups assigned to our para -/// in the view can fit into the buffer. -pub const VALIDATORS_BUFFER_CAPACITY: NonZeroUsize = match NonZeroUsize::new(3) { - Some(cap) => cap, - None => panic!("buffer capacity must be non-zero"), -}; +/// in the view can fit into the buffer multiplied by amount of candidates we support per relay +/// chain block in the case of elastic scaling. +pub const VALIDATORS_BUFFER_CAPACITY: NonZeroUsize = + match NonZeroUsize::new(3 * MAX_CHAINED_CANDIDATES_PER_RCB.get()) { + Some(cap) => cap, + None => panic!("buffer capacity must be non-zero"), + }; /// Unique identifier of a validators group. #[derive(Debug)] diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs index b102cf06c38..b127d87d4ea 100644 --- a/polkadot/node/primitives/src/lib.rs +++ b/polkadot/node/primitives/src/lib.rs @@ -31,8 +31,8 @@ use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use polkadot_primitives::{ BlakeTwo256, BlockNumber, CandidateCommitments, CandidateHash, CollatorPair, - CommittedCandidateReceipt, CompactStatement, EncodeAs, Hash, HashT, HeadData, Id as ParaId, - PersistedValidationData, SessionIndex, Signed, UncheckedSigned, ValidationCode, + CommittedCandidateReceipt, CompactStatement, CoreIndex, EncodeAs, Hash, HashT, HeadData, + Id as ParaId, PersistedValidationData, SessionIndex, Signed, UncheckedSigned, ValidationCode, ValidationCodeHash, ValidatorIndex, MAX_CODE_SIZE, MAX_POV_SIZE, }; pub use sp_consensus_babe::{ @@ -524,6 +524,8 @@ pub struct SubmitCollationParams { /// okay to just drop it. However, if it is called, it should be called with the signed /// statement of a parachain validator seconding the collation. pub result_sender: Option>, + /// The core index on which the resulting candidate should be backed + pub core_index: CoreIndex, } /// This is the data we keep available for each candidate included in the relay chain. diff --git a/polkadot/node/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index 5d05d2b56ed..d84b0b6dd14 100644 --- a/polkadot/node/subsystem-types/src/messages.rs +++ b/polkadot/node/subsystem-types/src/messages.rs @@ -228,6 +228,8 @@ pub enum CollatorProtocolMessage { /// The result sender should be informed when at least one parachain validator seconded the /// collation. It is also completely okay to just drop the sender. result_sender: Option>, + /// The core index where the candidate should be backed. + core_index: CoreIndex, }, /// Report a collator as having provided an invalid collation. This should lead to disconnect /// and blacklist of the collator. diff --git a/polkadot/node/subsystem-util/src/lib.rs b/polkadot/node/subsystem-util/src/lib.rs index 6ff09ed5f22..83b046f0bf0 100644 --- a/polkadot/node/subsystem-util/src/lib.rs +++ b/polkadot/node/subsystem-util/src/lib.rs @@ -30,7 +30,7 @@ use polkadot_node_subsystem::{ messages::{RuntimeApiMessage, RuntimeApiRequest, RuntimeApiSender}, overseer, SubsystemSender, }; -use polkadot_primitives::{slashing, CoreIndex, ExecutorParams}; +use polkadot_primitives::{async_backing::BackingState, slashing, CoreIndex, ExecutorParams}; pub use overseer::{ gen::{OrchestraError as OverseerError, Timeout}, @@ -308,6 +308,7 @@ specialize_requests! { fn request_disabled_validators() -> Vec; DisabledValidators; fn request_async_backing_params() -> AsyncBackingParams; AsyncBackingParams; fn request_claim_queue() -> BTreeMap>; ClaimQueue; + fn request_para_backing_state(para_id: ParaId) -> Option; ParaBackingState; } /// Requests executor parameters from the runtime effective at given relay-parent. First obtains diff --git a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml index cb283c27119..30bce806f9f 100644 --- a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml @@ -24,7 +24,7 @@ log = { workspace = true, default-features = true } test-parachain-adder = { path = ".." } polkadot-primitives = { path = "../../../../primitives" } polkadot-cli = { path = "../../../../cli" } -polkadot-service = { path = "../../../../node/service", features = ["rococo-native"] } +polkadot-service = { path = "../../../../node/service", features = ["elastic-scaling-experimental", "rococo-native"] } polkadot-node-primitives = { path = "../../../../node/primitives" } polkadot-node-subsystem = { path = "../../../../node/subsystem" } diff --git a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml index 238b98a6680..bede10a7673 100644 --- a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml @@ -24,7 +24,7 @@ log = { workspace = true, default-features = true } test-parachain-undying = { path = ".." } polkadot-primitives = { path = "../../../../primitives" } polkadot-cli = { path = "../../../../cli" } -polkadot-service = { path = "../../../../node/service", features = ["rococo-native"] } +polkadot-service = { path = "../../../../node/service", features = ["elastic-scaling-experimental", "rococo-native"] } polkadot-node-primitives = { path = "../../../../node/primitives" } polkadot-node-subsystem = { path = "../../../../node/subsystem" } diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 8a3cd9309db..62c3741c56d 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -27,10 +27,11 @@ use sp_std::{collections::btree_map::BTreeMap, prelude::*}; use polkadot_runtime_parachains::{ assigner_parachains as parachains_assigner_parachains, configuration as parachains_configuration, disputes as parachains_disputes, - disputes::slashing as parachains_slashing, dmp as parachains_dmp, hrmp as parachains_hrmp, - inclusion as parachains_inclusion, initializer as parachains_initializer, - origin as parachains_origin, paras as parachains_paras, - paras_inherent as parachains_paras_inherent, runtime_api_impl::v7 as runtime_impl, + disputes::slashing as parachains_slashing, + dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion, + initializer as parachains_initializer, origin as parachains_origin, paras as parachains_paras, + paras_inherent as parachains_paras_inherent, + runtime_api_impl::{v7 as runtime_impl, vstaging as staging_runtime_impl}, scheduler as parachains_scheduler, session_info as parachains_session_info, shared as parachains_shared, }; @@ -829,6 +830,7 @@ sp_api::impl_runtime_apis! { } } + #[api_version(10)] impl primitives::runtime_api::ParachainHost for Runtime { fn validators() -> Vec { runtime_impl::validators::() @@ -956,6 +958,30 @@ sp_api::impl_runtime_apis! { key_ownership_proof, ) } + + fn minimum_backing_votes() -> u32 { + runtime_impl::minimum_backing_votes::() + } + + fn para_backing_state(para_id: ParaId) -> Option { + runtime_impl::backing_state::(para_id) + } + + fn async_backing_params() -> primitives::AsyncBackingParams { + runtime_impl::async_backing_params::() + } + + fn approval_voting_params() -> primitives::vstaging::ApprovalVotingParams { + staging_runtime_impl::approval_voting_params::() + } + + fn disabled_validators() -> Vec { + staging_runtime_impl::disabled_validators::() + } + + fn node_features() -> primitives::vstaging::NodeFeatures { + staging_runtime_impl::node_features::() + } } impl beefy_primitives::BeefyApi for Runtime { diff --git a/prdoc/pr_3795.prdoc b/prdoc/pr_3795.prdoc new file mode 100644 index 00000000000..da01fcbec82 --- /dev/null +++ b/prdoc/pr_3795.prdoc @@ -0,0 +1,14 @@ +title: Enable collators to build on multiple cores + +doc: + - audience: Node Dev + description: | + Introduces a `CoreIndex` parameter in `SubmitCollationParams`. This enables + the collators to make use of potentially multiple cores assigned at some relay + chain block. This extra parameter is used by the collator protocol and collation + generation subsystems to forward the collation to the approapriate backing group. + +crates: +- name: polkadot-node-collation-generation +- name: polkadot-collator-protocol + bump: minor -- GitLab From 8342947b8e22d398ab981d33d9d48756a3160f77 Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Wed, 27 Mar 2024 15:51:45 +0100 Subject: [PATCH 109/187] process enqueued messages on idle (#3844) This will make it possible to use remaining weight on idle for processing enqueued messages. More context here https://github.com/paritytech/polkadot-sdk/issues/3709 --------- Co-authored-by: Adrian Catangiu --- .../pallets/outbound-queue/src/mock.rs | 1 + bridges/snowbridge/pallets/system/src/mock.rs | 1 + cumulus/pallets/parachain-system/src/mock.rs | 1 + .../assets/asset-hub-rococo/src/lib.rs | 1 + .../assets/asset-hub-westend/src/lib.rs | 1 + .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 1 + .../bridge-hubs/bridge-hub-westend/src/lib.rs | 1 + .../collectives-westend/src/lib.rs | 1 + .../contracts/contracts-rococo/src/lib.rs | 1 + .../coretime/coretime-rococo/src/lib.rs | 1 + .../coretime/coretime-westend/src/lib.rs | 1 + .../glutton/glutton-westend/src/lib.rs | 1 + .../runtimes/people/people-rococo/src/lib.rs | 1 + .../runtimes/people/people-westend/src/lib.rs | 1 + .../runtimes/starters/shell/src/lib.rs | 1 + .../runtimes/testing/penpal/src/lib.rs | 1 + .../testing/rococo-parachain/src/lib.rs | 1 + polkadot/runtime/parachains/src/mock.rs | 1 + polkadot/runtime/rococo/src/lib.rs | 1 + polkadot/runtime/westend/src/lib.rs | 1 + .../xcm-simulator/example/src/relay_chain.rs | 1 + .../xcm-simulator/fuzzer/src/relay_chain.rs | 1 + prdoc/pr_3844.prdoc | 25 +++++++++++ substrate/bin/node/runtime/src/lib.rs | 1 + .../contracts/mock-network/src/relay_chain.rs | 1 + .../message-queue/src/integration_test.rs | 1 + substrate/frame/message-queue/src/lib.rs | 22 +++++++++- substrate/frame/message-queue/src/mock.rs | 1 + substrate/frame/message-queue/src/tests.rs | 42 +++++++++++++++++++ templates/parachain/runtime/src/lib.rs | 1 + 30 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 prdoc/pr_3844.prdoc diff --git a/bridges/snowbridge/pallets/outbound-queue/src/mock.rs b/bridges/snowbridge/pallets/outbound-queue/src/mock.rs index 67877a05c79..5eeeeead140 100644 --- a/bridges/snowbridge/pallets/outbound-queue/src/mock.rs +++ b/bridges/snowbridge/pallets/outbound-queue/src/mock.rs @@ -69,6 +69,7 @@ impl pallet_message_queue::Config for Test { type HeapSize = HeapSize; type MaxStale = MaxStale; type ServiceWeight = ServiceWeight; + type IdleMaxServiceWeight = (); type QueuePausedQuery = (); } diff --git a/bridges/snowbridge/pallets/system/src/mock.rs b/bridges/snowbridge/pallets/system/src/mock.rs index 0312456c982..687072a49e2 100644 --- a/bridges/snowbridge/pallets/system/src/mock.rs +++ b/bridges/snowbridge/pallets/system/src/mock.rs @@ -148,6 +148,7 @@ impl pallet_message_queue::Config for Test { type HeapSize = HeapSize; type MaxStale = MaxStale; type ServiceWeight = ServiceWeight; + type IdleMaxServiceWeight = (); type QueuePausedQuery = (); } diff --git a/cumulus/pallets/parachain-system/src/mock.rs b/cumulus/pallets/parachain-system/src/mock.rs index 0b1d536ba7c..fe89dfe68c6 100644 --- a/cumulus/pallets/parachain-system/src/mock.rs +++ b/cumulus/pallets/parachain-system/src/mock.rs @@ -125,6 +125,7 @@ impl pallet_message_queue::Config for Test { type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MaxWeight; + type IdleMaxServiceWeight = (); type WeightInfo = (); } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 689d8d56c48..293416ab2a9 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -660,6 +660,7 @@ impl pallet_message_queue::Config for Runtime { type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; + type IdleMaxServiceWeight = MessageQueueServiceWeight; } impl parachain_info::Config for Runtime {} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 48106b5f302..e92e801e9f5 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -641,6 +641,7 @@ impl pallet_message_queue::Config for Runtime { type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; + type IdleMaxServiceWeight = MessageQueueServiceWeight; } impl cumulus_pallet_aura_ext::Config for Runtime {} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 3980fa0d501..f0aa4f8e91c 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -387,6 +387,7 @@ impl pallet_message_queue::Config for Runtime { type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; + type IdleMaxServiceWeight = MessageQueueServiceWeight; } impl cumulus_pallet_aura_ext::Config for Runtime {} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index 9bdea6b9a7d..3b759301d0e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -348,6 +348,7 @@ impl pallet_message_queue::Config for Runtime { type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; + type IdleMaxServiceWeight = MessageQueueServiceWeight; } impl cumulus_pallet_aura_ext::Config for Runtime {} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index d3f588bf25f..e1c2e1a6237 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -423,6 +423,7 @@ impl pallet_message_queue::Config for Runtime { type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; + type IdleMaxServiceWeight = MessageQueueServiceWeight; } impl cumulus_pallet_aura_ext::Config for Runtime {} diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index e1586c7d9b2..ec0a5f6fc96 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -318,6 +318,7 @@ impl pallet_message_queue::Config for Runtime { type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; + type IdleMaxServiceWeight = MessageQueueServiceWeight; } impl cumulus_pallet_aura_ext::Config for Runtime {} diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs index 86eb5cdfcaf..67f48689353 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs @@ -301,6 +301,7 @@ impl pallet_message_queue::Config for Runtime { type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; + type IdleMaxServiceWeight = MessageQueueServiceWeight; } impl parachain_info::Config for Runtime {} diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs index c31e474cc2f..609ea5a38a8 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs @@ -301,6 +301,7 @@ impl pallet_message_queue::Config for Runtime { type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; + type IdleMaxServiceWeight = MessageQueueServiceWeight; } impl parachain_info::Config for Runtime {} diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs index cee17cdc7b0..ca1a915ba74 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs @@ -212,6 +212,7 @@ impl pallet_message_queue::Config for Runtime { type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; + type IdleMaxServiceWeight = MessageQueueServiceWeight; } impl parachain_info::Config for Runtime {} diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs index cd5f1ad3272..7c9427a2493 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs @@ -282,6 +282,7 @@ impl pallet_message_queue::Config for Runtime { type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; + type IdleMaxServiceWeight = MessageQueueServiceWeight; type WeightInfo = weights::pallet_message_queue::WeightInfo; } diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs index e840a40f5ac..3e331e5e8eb 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs @@ -282,6 +282,7 @@ impl pallet_message_queue::Config for Runtime { type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; + type IdleMaxServiceWeight = MessageQueueServiceWeight; type WeightInfo = weights::pallet_message_queue::WeightInfo; } diff --git a/cumulus/parachains/runtimes/starters/shell/src/lib.rs b/cumulus/parachains/runtimes/starters/shell/src/lib.rs index 0f4957fd802..ad79d6849bd 100644 --- a/cumulus/parachains/runtimes/starters/shell/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/shell/src/lib.rs @@ -232,6 +232,7 @@ impl pallet_message_queue::Config for Runtime { type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; + type IdleMaxServiceWeight = MessageQueueServiceWeight; } impl cumulus_pallet_aura_ext::Config for Runtime {} diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index 1d404feac3d..0a55d2dcfe5 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -540,6 +540,7 @@ impl pallet_message_queue::Config for Runtime { type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; + type IdleMaxServiceWeight = MessageQueueServiceWeight; } impl cumulus_pallet_aura_ext::Config for Runtime {} diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index c6006141981..034d16267d4 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -320,6 +320,7 @@ impl pallet_message_queue::Config for Runtime { type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; + type IdleMaxServiceWeight = (); } impl cumulus_pallet_aura_ext::Config for Runtime {} diff --git a/polkadot/runtime/parachains/src/mock.rs b/polkadot/runtime/parachains/src/mock.rs index 7ed62a392e4..461b9f4b431 100644 --- a/polkadot/runtime/parachains/src/mock.rs +++ b/polkadot/runtime/parachains/src/mock.rs @@ -365,6 +365,7 @@ impl pallet_message_queue::Config for Test { type HeapSize = ConstU32<65536>; type MaxStale = ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; + type IdleMaxServiceWeight = (); } parameter_types! { diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 8c8abe97ede..c41ffdbe72d 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -987,6 +987,7 @@ impl pallet_message_queue::Config for Runtime { type HeapSize = MessageQueueHeapSize; type MaxStale = MessageQueueMaxStale; type ServiceWeight = MessageQueueServiceWeight; + type IdleMaxServiceWeight = MessageQueueServiceWeight; #[cfg(not(feature = "runtime-benchmarks"))] type MessageProcessor = MessageProcessor; #[cfg(feature = "runtime-benchmarks")] diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 02397f35368..e6381513170 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1190,6 +1190,7 @@ impl pallet_message_queue::Config for Runtime { type HeapSize = MessageQueueHeapSize; type MaxStale = MessageQueueMaxStale; type ServiceWeight = MessageQueueServiceWeight; + type IdleMaxServiceWeight = MessageQueueServiceWeight; #[cfg(not(feature = "runtime-benchmarks"))] type MessageProcessor = MessageProcessor; #[cfg(feature = "runtime-benchmarks")] diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs index 377c77f30a4..286d0038e18 100644 --- a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs @@ -275,6 +275,7 @@ impl pallet_message_queue::Config for Runtime { type HeapSize = MessageQueueHeapSize; type MaxStale = MessageQueueMaxStale; type ServiceWeight = MessageQueueServiceWeight; + type IdleMaxServiceWeight = (); type MessageProcessor = MessageProcessor; type QueueChangeHandler = (); type QueuePausedQuery = (); diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs index 3224df66cbe..6790b535d16 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs @@ -232,6 +232,7 @@ impl pallet_message_queue::Config for Runtime { type HeapSize = MessageQueueHeapSize; type MaxStale = MessageQueueMaxStale; type ServiceWeight = MessageQueueServiceWeight; + type IdleMaxServiceWeight = (); #[cfg(not(feature = "runtime-benchmarks"))] type MessageProcessor = MessageProcessor; #[cfg(feature = "runtime-benchmarks")] diff --git a/prdoc/pr_3844.prdoc b/prdoc/pr_3844.prdoc new file mode 100644 index 00000000000..a92092f91b2 --- /dev/null +++ b/prdoc/pr_3844.prdoc @@ -0,0 +1,25 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Add the ability for MessageQueue to process enqueued messages on idle + +doc: + - audience: Runtime Dev + description: | + Add the option to use remaining weight on idle for processing enqueued messages. + This will increase the chances of the messages enqueued during inherent extrinsics to be processed in the same block. + New config types is added on the message-queue `Config` trait: + - `IdleMaxServiceWeight` + + example: + ```rust + parameter_types! { + // The maximum weight to be used from remaining weight for processing enqueued messages on idle + pub const IdleMaxServiceWeight: Weight = Some(Weight); + } + + type IdleMaxServiceWeight = IdleMaxServiceWeight; // or `()` to not use this feature + ``` + +crates: + - name: pallet-message-queue diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index ca7e14f6eb1..a9606ac0bb7 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -1303,6 +1303,7 @@ impl pallet_message_queue::Config for Runtime { type HeapSize = ConstU32<{ 64 * 1024 }>; type MaxStale = ConstU32<128>; type ServiceWeight = MessageQueueServiceWeight; + type IdleMaxServiceWeight = (); } parameter_types! { diff --git a/substrate/frame/contracts/mock-network/src/relay_chain.rs b/substrate/frame/contracts/mock-network/src/relay_chain.rs index e2a8d3d1337..470304ed357 100644 --- a/substrate/frame/contracts/mock-network/src/relay_chain.rs +++ b/substrate/frame/contracts/mock-network/src/relay_chain.rs @@ -225,6 +225,7 @@ impl pallet_message_queue::Config for Runtime { type HeapSize = MessageQueueHeapSize; type MaxStale = MessageQueueMaxStale; type ServiceWeight = MessageQueueServiceWeight; + type IdleMaxServiceWeight = (); type MessageProcessor = MessageProcessor; type QueueChangeHandler = (); type WeightInfo = (); diff --git a/substrate/frame/message-queue/src/integration_test.rs b/substrate/frame/message-queue/src/integration_test.rs index 26a330cc88e..14b8d2217eb 100644 --- a/substrate/frame/message-queue/src/integration_test.rs +++ b/substrate/frame/message-queue/src/integration_test.rs @@ -73,6 +73,7 @@ impl Config for Test { type HeapSize = HeapSize; type MaxStale = MaxStale; type ServiceWeight = ServiceWeight; + type IdleMaxServiceWeight = (); } /// Simulates heavy usage by enqueueing and processing large amounts of messages. diff --git a/substrate/frame/message-queue/src/lib.rs b/substrate/frame/message-queue/src/lib.rs index 93cd760eeb9..ec85c785f79 100644 --- a/substrate/frame/message-queue/src/lib.rs +++ b/substrate/frame/message-queue/src/lib.rs @@ -525,12 +525,21 @@ pub mod pallet { type MaxStale: Get; /// The amount of weight (if any) which should be provided to the message queue for - /// servicing enqueued items. + /// servicing enqueued items `on_initialize`. /// /// This may be legitimately `None` in the case that you will call - /// `ServiceQueues::service_queues` manually. + /// `ServiceQueues::service_queues` manually or set [`Self::IdleMaxServiceWeight`] to have + /// it run in `on_idle`. #[pallet::constant] type ServiceWeight: Get>; + + /// The maximum amount of weight (if any) to be used from remaining weight `on_idle` which + /// should be provided to the message queue for servicing enqueued items `on_idle`. + /// Useful for parachains to process messages at the same block they are received. + /// + /// If `None`, it will not call `ServiceQueues::service_queues` in `on_idle`. + #[pallet::constant] + type IdleMaxServiceWeight: Get>; } #[pallet::event] @@ -643,6 +652,15 @@ pub mod pallet { } } + fn on_idle(_n: BlockNumberFor, remaining_weight: Weight) -> Weight { + if let Some(weight_limit) = T::IdleMaxServiceWeight::get() { + // Make use of the remaining weight to process enqueued messages. + Self::service_queues(weight_limit.min(remaining_weight)) + } else { + Weight::zero() + } + } + #[cfg(feature = "try-runtime")] fn try_state(_: BlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { Self::do_try_state() diff --git a/substrate/frame/message-queue/src/mock.rs b/substrate/frame/message-queue/src/mock.rs index f22f318b8ef..1281de6b0a6 100644 --- a/substrate/frame/message-queue/src/mock.rs +++ b/substrate/frame/message-queue/src/mock.rs @@ -56,6 +56,7 @@ impl Config for Test { type HeapSize = HeapSize; type MaxStale = MaxStale; type ServiceWeight = ServiceWeight; + type IdleMaxServiceWeight = ServiceWeight; } /// Mocked `WeightInfo` impl with allows to set the weight per call. diff --git a/substrate/frame/message-queue/src/tests.rs b/substrate/frame/message-queue/src/tests.rs index 1f6e7777f01..d6788847d57 100644 --- a/substrate/frame/message-queue/src/tests.rs +++ b/substrate/frame/message-queue/src/tests.rs @@ -1838,3 +1838,45 @@ fn with_service_mutex_works() { with_service_mutex(|| called = 3).unwrap(); assert_eq!(called, 3); } + +#[test] +fn process_enqueued_on_idle() { + use MessageOrigin::*; + build_and_execute::(|| { + // Some messages enqueued on previous block. + MessageQueue::enqueue_messages(vec![msg("a"), msg("ab"), msg("abc")].into_iter(), Here); + assert_eq!(BookStateFor::::iter().count(), 1); + + // Process enqueued messages from previous block. + Pallet::::on_initialize(1); + assert_eq!( + MessagesProcessed::take(), + vec![(b"a".to_vec(), Here), (b"ab".to_vec(), Here), (b"abc".to_vec(), Here),] + ); + + MessageQueue::enqueue_messages(vec![msg("x"), msg("xy"), msg("xyz")].into_iter(), There); + assert_eq!(BookStateFor::::iter().count(), 2); + + // Enough weight to process on idle. + Pallet::::on_idle(1, Weight::from_parts(100, 100)); + assert_eq!( + MessagesProcessed::take(), + vec![(b"x".to_vec(), There), (b"xy".to_vec(), There), (b"xyz".to_vec(), There)] + ); + }) +} + +#[test] +fn process_enqueued_on_idle_requires_enough_weight() { + use MessageOrigin::*; + build_and_execute::(|| { + Pallet::::on_initialize(1); + + MessageQueue::enqueue_messages(vec![msg("x"), msg("xy"), msg("xyz")].into_iter(), There); + assert_eq!(BookStateFor::::iter().count(), 1); + + // Not enough weight to process on idle. + Pallet::::on_idle(1, Weight::from_parts(0, 0)); + assert_eq!(MessagesProcessed::take(), vec![]); + }) +} diff --git a/templates/parachain/runtime/src/lib.rs b/templates/parachain/runtime/src/lib.rs index ad21b79a5b1..88b0f5a1474 100644 --- a/templates/parachain/runtime/src/lib.rs +++ b/templates/parachain/runtime/src/lib.rs @@ -414,6 +414,7 @@ impl pallet_message_queue::Config for Runtime { type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; + type IdleMaxServiceWeight = (); } impl cumulus_pallet_aura_ext::Config for Runtime {} -- GitLab From 374aefa4f2d3754e5a6e9464f5d1692af9a1c6be Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Wed, 27 Mar 2024 17:03:53 +0100 Subject: [PATCH 110/187] [ci] Fix publish benchmarks job (#3864) Few fixes in CI to publish benchmarks jobs. cc https://github.com/paritytech/ci_cd/issues/934 --- .gitlab/pipeline/publish.yml | 4 ++-- .gitlab/pipeline/test.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab/pipeline/publish.yml b/.gitlab/pipeline/publish.yml index bd9387f3c07..a37ba012a8a 100644 --- a/.gitlab/pipeline/publish.yml +++ b/.gitlab/pipeline/publish.yml @@ -88,7 +88,7 @@ publish-subsystem-benchmarks: - git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" - git fetch origin gh-pages # Push result to github - - git checkout gh-pages + - git checkout gh-pages --force - mkdir -p bench/gitlab/ || echo "Directory exists" - rm -rf bench/gitlab/*.json || echo "No json files" - cp -r charts/*.json bench/gitlab/ @@ -121,7 +121,7 @@ trigger_workflow: curl -q -X POST \ -H "Accept: application/vnd.github.v3+json" \ -H "Authorization: token $GITHUB_TOKEN" \ - https://api.github.com/repos/paritytech-stg/${CI_PROJECT_NAME}/actions/workflows/subsystem-benchmarks.yml/dispatches \ + https://api.github.com/repos/paritytech/${CI_PROJECT_NAME}/actions/workflows/subsystem-benchmarks.yml/dispatches \ -d '{"ref":"refs/heads/master","inputs":{"benchmark-data-dir-path":"'$benchmark_dir'","output-file-path":"'$bencmark_name'"}}' sleep 300 done diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index d97f9da986c..af261a893da 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -499,7 +499,7 @@ subsystem-regression-tests: stage: test artifacts: name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" - when: on_success + when: always expire_in: 1 days paths: - charts/ -- GitLab From bbdbeb7ec66e81ff2f571655113b5259198e1611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 27 Mar 2024 18:20:24 +0100 Subject: [PATCH 111/187] Extrinsic to restore corrupt staking ledgers (#3706) This PR adds a new extrinsic `Call::restore_ledger ` gated by `StakingAdmin` origin that restores a corrupted staking ledger. This extrinsic will be used to recover ledgers that were affected by the issue discussed in https://github.com/paritytech/polkadot-sdk/issues/3245. The extrinsic will re-write the storage items associated with a stash account provided as input parameter. The data used to reset the ledger can be either i) fetched on-chain or ii) partially/totally set by the input parameters of the call. In order to use on-chain data to restore the staking locks, we need a way to read the current lock in the balances pallet. This PR adds a `InspectLockableCurrency` trait and implements it in the pallet balances. An alternative would be to tightly couple staking with the pallet balances but that's inelegant (an example of how it would look like in [this branch](https://github.com/paritytech/polkadot-sdk/tree/gpestana/ledger-badstate-clean_tightly)). More details on the type of corruptions and corresponding fixes https://hackmd.io/DLb5jEYWSmmvqXC9ae4yRg?view#/ We verified that the `Call::restore_ledger` does fix all current corrupted ledgers in Polkadot and Kusama. You can verify it here https://hackmd.io/v-XNrEoGRpe7APR-EZGhOA. **Changes introduced** - Adds `Call::restore_ledger ` extrinsic to recover a corrupted ledger; - Adds trait `frame_support::traits::currency::InspectLockableCurrency` to allow external pallets to read current locks given an account and lock ID; - Implements the `InspectLockableCurrency` in the pallet-balances. - Adds staking locks try-runtime checks (https://github.com/paritytech/polkadot-sdk/issues/3751) **Todo** - [x] benchmark `Call::restore_ledger` - [x] throughout testing of all ledger recovering cases - [x] consider adding the staking locks try-runtime checks to this PR (https://github.com/paritytech/polkadot-sdk/issues/3751) - [x] simulate restoring all ledgers (https://hackmd.io/Dsa2tvhISNSs7zcqriTaxQ?view) in Polkadot and Kusama using chopsticks -- https://hackmd.io/v-XNrEoGRpe7APR-EZGhOA Related to https://github.com/paritytech/polkadot-sdk/issues/3245 Closes https://github.com/paritytech/polkadot-sdk/issues/3751 --------- Co-authored-by: command-bot <> --- .../westend/src/weights/pallet_staking.rs | 286 +++++---- prdoc/pr_3706.prdoc | 20 + substrate/frame/balances/src/impl_currency.rs | 13 +- .../balances/src/tests/currency_tests.rs | 22 +- substrate/frame/staking/Cargo.toml | 2 +- substrate/frame/staking/src/benchmarking.rs | 9 + substrate/frame/staking/src/lib.rs | 14 + substrate/frame/staking/src/mock.rs | 115 ++-- substrate/frame/staking/src/pallet/impls.rs | 60 +- substrate/frame/staking/src/pallet/mod.rs | 121 +++- substrate/frame/staking/src/tests.rs | 446 +++++++++++++- substrate/frame/staking/src/weights.rs | 577 ++++++++++-------- substrate/frame/support/src/traits.rs | 4 +- .../support/src/traits/tokens/currency.rs | 2 +- .../src/traits/tokens/currency/lockable.rs | 6 + 15 files changed, 1206 insertions(+), 491 deletions(-) create mode 100644 prdoc/pr_3706.prdoc diff --git a/polkadot/runtime/westend/src/weights/pallet_staking.rs b/polkadot/runtime/westend/src/weights/pallet_staking.rs index 7a641e36a12..393fa0b3717 100644 --- a/polkadot/runtime/westend/src/weights/pallet_staking.rs +++ b/polkadot/runtime/westend/src/weights/pallet_staking.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_staking` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-01-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-03-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-8idpd4bs-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -50,22 +50,22 @@ pub struct WeightInfo(PhantomData); impl pallet_staking::WeightInfo for WeightInfo { /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:0 w:1) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:0 w:1) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn bond() -> Weight { // Proof Size summary in bytes: - // Measured: `894` + // Measured: `1009` // Estimated: `4764` - // Minimum execution time: 37_340_000 picoseconds. - Weight::from_parts(38_930_000, 0) + // Minimum execution time: 40_585_000 picoseconds. + Weight::from_parts(41_800_000, 0) .saturating_add(Weight::from_parts(0, 4764)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `Staking::Bonded` (r:1 w:0) @@ -84,22 +84,22 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1921` // Estimated: `8877` - // Minimum execution time: 80_630_000 picoseconds. - Weight::from_parts(82_196_000, 0) + // Minimum execution time: 81_809_000 picoseconds. + Weight::from_parts(84_387_000, 0) .saturating_add(Weight::from_parts(0, 8877)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(7)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:0) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::MinNominatorBond` (r:1 w:0) /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) @@ -112,43 +112,45 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `2128` // Estimated: `8877` - // Minimum execution time: 83_523_000 picoseconds. - Weight::from_parts(86_639_000, 0) + // Minimum execution time: 89_419_000 picoseconds. + Weight::from_parts(91_237_000, 0) .saturating_add(Weight::from_parts(0, 8877)) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(7)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::CurrentEra` (r:1 w:0) - /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:0) + /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1075` + // Measured: `1223` // Estimated: `4764` - // Minimum execution time: 38_636_000 picoseconds. - Weight::from_parts(40_399_283, 0) + // Minimum execution time: 45_152_000 picoseconds. + Weight::from_parts(46_460_819, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 869 - .saturating_add(Weight::from_parts(37_752, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(5)) + // Standard Error: 972 + .saturating_add(Weight::from_parts(55_473, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:1) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Staking::Bonded` (r:1 w:1) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) @@ -174,11 +176,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `2127 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 81_301_000 picoseconds. - Weight::from_parts(88_609_205, 0) + // Minimum execution time: 82_762_000 picoseconds. + Weight::from_parts(91_035_077, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 3_388 - .saturating_add(Weight::from_parts(1_253_692, 0).saturating_mul(s.into())) + // Standard Error: 3_771 + .saturating_add(Weight::from_parts(1_217_871, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13)) .saturating_add(T::DbWeight::get().writes(11)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -186,6 +188,8 @@ impl pallet_staking::WeightInfo for WeightInfo { } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::MinValidatorBond` (r:1 w:0) /// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::MinCommission` (r:1 w:0) @@ -196,8 +200,6 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:0) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:1 w:1) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:1 w:1) @@ -210,33 +212,37 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1301` // Estimated: `4556` - // Minimum execution time: 47_292_000 picoseconds. - Weight::from_parts(48_566_000, 0) + // Minimum execution time: 50_555_000 picoseconds. + Weight::from_parts(52_052_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:128 w:128) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1243 + k * (569 ±0)` + // Measured: `1778 + k * (572 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 28_840_000 picoseconds. - Weight::from_parts(27_510_817, 0) + // Minimum execution time: 35_037_000 picoseconds. + Weight::from_parts(35_081_878, 0) .saturating_add(Weight::from_parts(0, 4556)) - // Standard Error: 6_603 - .saturating_add(Weight::from_parts(6_268_853, 0).saturating_mul(k.into())) - .saturating_add(T::DbWeight::get().reads(1)) + // Standard Error: 5_473 + .saturating_add(Weight::from_parts(6_667_924, 0).saturating_mul(k.into())) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) .saturating_add(Weight::from_parts(0, 3033).saturating_mul(k.into())) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::MinNominatorBond` (r:1 w:0) /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) @@ -247,8 +253,6 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:2 w:2) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:1 w:1) @@ -262,11 +266,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1797 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 57_537_000 picoseconds. - Weight::from_parts(55_854_233, 0) + // Minimum execution time: 62_098_000 picoseconds. + Weight::from_parts(60_154_061, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 14_427 - .saturating_add(Weight::from_parts(3_844_957, 0).saturating_mul(n.into())) + // Standard Error: 19_257 + .saturating_add(Weight::from_parts(3_839_855, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6)) @@ -274,6 +278,8 @@ impl pallet_staking::WeightInfo for WeightInfo { } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) @@ -288,12 +294,12 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `1581` + // Measured: `1747` // Estimated: `6248` - // Minimum execution time: 49_997_000 picoseconds. - Weight::from_parts(51_266_000, 0) + // Minimum execution time: 54_993_000 picoseconds. + Weight::from_parts(56_698_000, 0) .saturating_add(Weight::from_parts(0, 6248)) - .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(6)) } /// Storage: `Staking::Ledger` (r:1 w:0) @@ -306,40 +312,40 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `865` // Estimated: `4556` - // Minimum execution time: 15_342_000 picoseconds. - Weight::from_parts(15_970_000, 0) + // Minimum execution time: 18_100_000 picoseconds. + Weight::from_parts(18_547_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::Payee` (r:1 w:1) - /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Payee` (r:1 w:1) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn update_payee() -> Weight { // Proof Size summary in bytes: // Measured: `932` // Estimated: `4556` - // Minimum execution time: 20_719_000 picoseconds. - Weight::from_parts(21_373_000, 0) + // Minimum execution time: 23_428_000 picoseconds. + Weight::from_parts(24_080_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:1 w:2) + /// Storage: `Staking::Ledger` (r:2 w:2) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) fn set_controller() -> Weight { // Proof Size summary in bytes: // Measured: `865` - // Estimated: `4556` - // Minimum execution time: 18_237_000 picoseconds. - Weight::from_parts(18_896_000, 0) - .saturating_add(Weight::from_parts(0, 4556)) - .saturating_add(T::DbWeight::get().reads(2)) + // Estimated: `8122` + // Minimum execution time: 21_159_000 picoseconds. + Weight::from_parts(21_706_000, 0) + .saturating_add(Weight::from_parts(0, 8122)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Staking::ValidatorCount` (r:0 w:1) @@ -348,8 +354,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_946_000 picoseconds. - Weight::from_parts(2_131_000, 0) + // Minimum execution time: 1_910_000 picoseconds. + Weight::from_parts(2_003_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -359,8 +365,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_840_000 picoseconds. - Weight::from_parts(7_208_000, 0) + // Minimum execution time: 7_076_000 picoseconds. + Weight::from_parts(7_349_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -370,8 +376,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_812_000 picoseconds. - Weight::from_parts(7_254_000, 0) + // Minimum execution time: 7_067_000 picoseconds. + Weight::from_parts(7_389_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -381,8 +387,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_787_000 picoseconds. - Weight::from_parts(7_206_000, 0) + // Minimum execution time: 7_148_000 picoseconds. + Weight::from_parts(7_446_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -393,32 +399,32 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_045_000 picoseconds. - Weight::from_parts(2_281_841, 0) + // Minimum execution time: 2_025_000 picoseconds. + Weight::from_parts(2_229_953, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 70 - .saturating_add(Weight::from_parts(11_592, 0).saturating_mul(v.into())) + // Standard Error: 67 + .saturating_add(Weight::from_parts(11_785, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Staking::Ledger` (r:751 w:1502) + /// Storage: `Staking::Ledger` (r:1502 w:1502) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:751 w:751) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:751 w:0) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:0 w:751) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 751]`. fn deprecate_controller_batch(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `668 + i * (148 ±0)` - // Estimated: `990 + i * (3566 ±0)` - // Minimum execution time: 1_657_000 picoseconds. - Weight::from_parts(1_702_000, 0) + // Measured: `680 + i * (227 ±0)` + // Estimated: `990 + i * (7132 ±0)` + // Minimum execution time: 4_321_000 picoseconds. + Weight::from_parts(4_407_000, 0) .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 20_041 - .saturating_add(Weight::from_parts(13_165_254, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(i.into()))) + // Standard Error: 37_239 + .saturating_add(Weight::from_parts(21_300_598, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(i.into()))) - .saturating_add(Weight::from_parts(0, 3566).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(0, 7132).saturating_mul(i.into())) } /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -453,11 +459,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `2127 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 78_774_000 picoseconds. - Weight::from_parts(85_770_713, 0) + // Minimum execution time: 78_908_000 picoseconds. + Weight::from_parts(84_886_373, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 2_815 - .saturating_add(Weight::from_parts(1_244_494, 0).saturating_mul(s.into())) + // Standard Error: 3_376 + .saturating_add(Weight::from_parts(1_217_850, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13)) .saturating_add(T::DbWeight::get().writes(12)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -470,11 +476,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `66639` // Estimated: `70104` - // Minimum execution time: 129_905_000 picoseconds. - Weight::from_parts(932_195_554, 0) + // Minimum execution time: 136_389_000 picoseconds. + Weight::from_parts(1_207_241_524, 0) .saturating_add(Weight::from_parts(0, 70104)) - // Standard Error: 57_492 - .saturating_add(Weight::from_parts(4_826_754, 0).saturating_mul(s.into())) + // Standard Error: 77_138 + .saturating_add(Weight::from_parts(6_443_948, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -511,11 +517,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `8249 + n * (396 ±0)` // Estimated: `10779 + n * (3774 ±0)` - // Minimum execution time: 127_094_000 picoseconds. - Weight::from_parts(160_088_053, 0) + // Minimum execution time: 130_222_000 picoseconds. + Weight::from_parts(167_236_150, 0) .saturating_add(Weight::from_parts(0, 10779)) - // Standard Error: 32_978 - .saturating_add(Weight::from_parts(39_845_710, 0).saturating_mul(n.into())) + // Standard Error: 34_051 + .saturating_add(Weight::from_parts(39_899_917, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(14)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(4)) @@ -539,11 +545,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1922 + l * (5 ±0)` // Estimated: `8877` - // Minimum execution time: 75_672_000 picoseconds. - Weight::from_parts(78_708_335, 0) + // Minimum execution time: 79_136_000 picoseconds. + Weight::from_parts(82_129_497, 0) .saturating_add(Weight::from_parts(0, 8877)) - // Standard Error: 3_387 - .saturating_add(Weight::from_parts(37_084, 0).saturating_mul(l.into())) + // Standard Error: 3_867 + .saturating_add(Weight::from_parts(75_156, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -578,11 +584,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `2127 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 87_991_000 picoseconds. - Weight::from_parts(90_272_005, 0) + // Minimum execution time: 89_375_000 picoseconds. + Weight::from_parts(91_224_907, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 2_815 - .saturating_add(Weight::from_parts(1_232_322, 0).saturating_mul(s.into())) + // Standard Error: 3_424 + .saturating_add(Weight::from_parts(1_219_542, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(11)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -627,14 +633,14 @@ impl pallet_staking::WeightInfo for WeightInfo { fn new_era(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + n * (716 ±0) + v * (3594 ±0)` - // Estimated: `456136 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 528_862_000 picoseconds. - Weight::from_parts(534_620_000, 0) + // Estimated: `456136 + n * (3566 ±4) + v * (3566 ±0)` + // Minimum execution time: 520_905_000 picoseconds. + Weight::from_parts(523_771_000, 0) .saturating_add(Weight::from_parts(0, 456136)) - // Standard Error: 2_005_553 - .saturating_add(Weight::from_parts(65_586_008, 0).saturating_mul(v.into())) - // Standard Error: 199_842 - .saturating_add(Weight::from_parts(18_155_389, 0).saturating_mul(n.into())) + // Standard Error: 2_142_714 + .saturating_add(Weight::from_parts(68_631_588, 0).saturating_mul(v.into())) + // Standard Error: 213_509 + .saturating_add(Weight::from_parts(19_343_025, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(184)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -665,13 +671,13 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `3108 + n * (907 ±0) + v * (391 ±0)` // Estimated: `456136 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 33_532_110_000 picoseconds. - Weight::from_parts(33_926_321_000, 0) + // Minimum execution time: 36_848_619_000 picoseconds. + Weight::from_parts(37_362_442_000, 0) .saturating_add(Weight::from_parts(0, 456136)) - // Standard Error: 374_134 - .saturating_add(Weight::from_parts(4_627_629, 0).saturating_mul(v.into())) - // Standard Error: 374_134 - .saturating_add(Weight::from_parts(4_068_168, 0).saturating_mul(n.into())) + // Standard Error: 415_031 + .saturating_add(Weight::from_parts(5_204_987, 0).saturating_mul(v.into())) + // Standard Error: 415_031 + .saturating_add(Weight::from_parts(4_132_636, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(179)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -688,11 +694,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `946 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_395_956_000 picoseconds. - Weight::from_parts(88_416_870, 0) + // Minimum execution time: 2_512_817_000 picoseconds. + Weight::from_parts(119_401_374, 0) .saturating_add(Weight::from_parts(0, 3510)) - // Standard Error: 8_731 - .saturating_add(Weight::from_parts(4_750_956, 0).saturating_mul(v.into())) + // Standard Error: 8_463 + .saturating_add(Weight::from_parts(4_860_364, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -715,8 +721,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_761_000 picoseconds. - Weight::from_parts(4_013_000, 0) + // Minimum execution time: 3_686_000 picoseconds. + Weight::from_parts(3_881_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -738,8 +744,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_325_000 picoseconds. - Weight::from_parts(3_519_000, 0) + // Minimum execution time: 3_143_000 picoseconds. + Weight::from_parts(3_424_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -769,8 +775,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1870` // Estimated: `6248` - // Minimum execution time: 63_583_000 picoseconds. - Weight::from_parts(65_917_000, 0) + // Minimum execution time: 66_946_000 picoseconds. + Weight::from_parts(69_382_000, 0) .saturating_add(Weight::from_parts(0, 6248)) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(6)) @@ -783,8 +789,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `658` // Estimated: `3510` - // Minimum execution time: 10_975_000 picoseconds. - Weight::from_parts(11_328_000, 0) + // Minimum execution time: 11_278_000 picoseconds. + Weight::from_parts(11_603_000, 0) .saturating_add(Weight::from_parts(0, 3510)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -795,9 +801,29 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_954_000 picoseconds. - Weight::from_parts(2_081_000, 0) + // Minimum execution time: 1_963_000 picoseconds. + Weight::from_parts(2_077_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:1) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + fn restore_ledger() -> Weight { + // Proof Size summary in bytes: + // Measured: `1014` + // Estimated: `4764` + // Minimum execution time: 40_258_000 picoseconds. + Weight::from_parts(41_210_000, 0) + .saturating_add(Weight::from_parts(0, 4764)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) + } } diff --git a/prdoc/pr_3706.prdoc b/prdoc/pr_3706.prdoc new file mode 100644 index 00000000000..edeb08241be --- /dev/null +++ b/prdoc/pr_3706.prdoc @@ -0,0 +1,20 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Extrinsic to restore corrupted staking ledgers + +doc: + - audience: Runtime User + description: | + This PR adds a new extrinsic `Call::restore_ledger ` gated by `StakingAdmin` origin that restores a corrupted staking ledger. This extrinsic will be used to recover ledgers that were affected by the issue discussed in https://github.com/paritytech/polkadot-sdk/issues/3245. + The extrinsic will re-write the storage items associated with a stash account provided as input parameter. The data used to reset the ledger can be either i) fetched on-chain or ii) partially/totally set by the input parameters of the call. + + Changes introduced: + - Adds `Call::restore_ledger ` extrinsic to recover a corrupted ledger; + - Adds trait `frame_support::traits::currency::InspectLockableCurrency` to allow external pallets to read current locks given an account and lock ID; + - Implements the `InspectLockableCurrency` in the pallet-balances. + - Adds staking locks try-runtime checks (https://github.com/paritytech/polkadot-sdk/issues/3751) + +crates: + - name: pallet-staking + - name: pallet-balances diff --git a/substrate/frame/balances/src/impl_currency.rs b/substrate/frame/balances/src/impl_currency.rs index 1ac882ade70..d5fe9934e23 100644 --- a/substrate/frame/balances/src/impl_currency.rs +++ b/substrate/frame/balances/src/impl_currency.rs @@ -28,8 +28,8 @@ use frame_support::{ tokens::{fungible, BalanceStatus as Status, Fortitude::Polite, Precision::BestEffort}, Currency, DefensiveSaturating, ExistenceRequirement, ExistenceRequirement::AllowDeath, - Get, Imbalance, LockIdentifier, LockableCurrency, NamedReservableCurrency, - ReservableCurrency, SignedImbalance, TryDrop, WithdrawReasons, + Get, Imbalance, InspectLockableCurrency, LockIdentifier, LockableCurrency, + NamedReservableCurrency, ReservableCurrency, SignedImbalance, TryDrop, WithdrawReasons, }, }; use frame_system::pallet_prelude::BlockNumberFor; @@ -918,3 +918,12 @@ where Self::update_locks(who, &locks[..]); } } + +impl, I: 'static> InspectLockableCurrency for Pallet { + fn balance_locked(id: LockIdentifier, who: &T::AccountId) -> Self::Balance { + Self::locks(who) + .into_iter() + .filter(|l| l.id == id) + .fold(Zero::zero(), |acc, l| acc + l.amount) + } +} diff --git a/substrate/frame/balances/src/tests/currency_tests.rs b/substrate/frame/balances/src/tests/currency_tests.rs index bd4ff762c74..450b1a84aa8 100644 --- a/substrate/frame/balances/src/tests/currency_tests.rs +++ b/substrate/frame/balances/src/tests/currency_tests.rs @@ -24,8 +24,8 @@ use frame_support::{ BalanceStatus::{Free, Reserved}, Currency, ExistenceRequirement::{self, AllowDeath, KeepAlive}, - Hooks, LockIdentifier, LockableCurrency, NamedReservableCurrency, ReservableCurrency, - WithdrawReasons, + Hooks, InspectLockableCurrency, LockIdentifier, LockableCurrency, NamedReservableCurrency, + ReservableCurrency, WithdrawReasons, }, StorageNoopGuard, }; @@ -88,6 +88,24 @@ fn basic_locking_should_work() { }); } +#[test] +fn inspect_lock_should_work() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + Balances::set_lock(ID_1, &1, 10, WithdrawReasons::all()); + Balances::set_lock(ID_2, &1, 10, WithdrawReasons::all()); + Balances::set_lock(ID_1, &2, 20, WithdrawReasons::all()); + + assert_eq!(>::balance_locked(ID_1, &1), 10); + assert_eq!(>::balance_locked(ID_2, &1), 10); + assert_eq!(>::balance_locked(ID_1, &2), 20); + assert_eq!(>::balance_locked(ID_2, &2), 0); + assert_eq!(>::balance_locked(ID_1, &3), 0); + }) +} + #[test] fn account_should_be_reaped() { ExtBuilder::default() diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index d2a46146931..15c4bf9e290 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -40,10 +40,10 @@ frame-benchmarking = { path = "../benchmarking", default-features = false, optio rand_chacha = { version = "0.2", default-features = false, optional = true } [dev-dependencies] +pallet-balances = { path = "../balances" } sp-tracing = { path = "../../primitives/tracing" } sp-core = { path = "../../primitives/core" } sp-npos-elections = { path = "../../primitives/npos-elections" } -pallet-balances = { path = "../balances" } pallet-timestamp = { path = "../timestamp" } pallet-staking-reward-curve = { path = "reward-curve" } pallet-bags-list = { path = "../bags-list" } diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index a8306087397..0b67cd46039 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -953,6 +953,15 @@ benchmarks! { assert_eq!(MinCommission::::get(), Perbill::from_percent(100)); } + restore_ledger { + let (stash, controller) = create_stash_controller::(0, 100, RewardDestination::Staked)?; + // corrupt ledger. + Ledger::::remove(controller); + }: _(RawOrigin::Root, stash.clone(), None, None, None) + verify { + assert_eq!(Staking::::inspect_bond_state(&stash), Ok(LedgerIntegrityState::Ok)); + } + impl_benchmark_test_suite!( Staking, crate::mock::ExtBuilder::default().has_stakers(true), diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 5a92b6c855f..f5b7e3eca3d 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -491,6 +491,20 @@ pub struct StakingLedger { controller: Option, } +/// State of a ledger with regards with its data and metadata integrity. +#[derive(PartialEq, Debug)] +enum LedgerIntegrityState { + /// Ledger, bond and corresponding staking lock is OK. + Ok, + /// Ledger and/or bond is corrupted. This means that the bond has a ledger with a different + /// stash than the bonded stash. + Corrupted, + /// Ledger was corrupted and it has been killed. + CorruptedKilled, + /// Ledger and bond are OK, however the ledger's stash lock is out of sync. + LockCorrupted, +} + impl StakingLedger { /// Remove entries from `unlocking` that are sufficiently old and reduce the /// total by the sum of their balances. diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 6c2ea225ff1..6db462c1a70 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -25,8 +25,8 @@ use frame_election_provider_support::{ use frame_support::{ assert_ok, derive_impl, ord_parameter_types, parameter_types, traits::{ - ConstU64, Currency, EitherOfDiverse, FindAuthor, Get, Hooks, Imbalance, OnUnbalanced, - OneSessionHandler, + ConstU64, Currency, EitherOfDiverse, FindAuthor, Get, Hooks, Imbalance, LockableCurrency, + OnUnbalanced, OneSessionHandler, WithdrawReasons, }, weights::constants::RocksDbWeight, }; @@ -786,55 +786,86 @@ pub(crate) fn bond_controller_stash(controller: AccountId, stash: AccountId) -> Ok(()) } +// simulates `set_controller` without corrupted ledger checks for testing purposes. +pub(crate) fn set_controller_no_checks(stash: &AccountId) { + let controller = Bonded::::get(stash).expect("testing stash should be bonded"); + let ledger = Ledger::::get(&controller).expect("testing ledger should exist"); + + Ledger::::remove(&controller); + Ledger::::insert(stash, ledger); + Bonded::::insert(stash, stash); +} + +// simulates `bond_extra` without corrupted ledger checks for testing purposes. +pub(crate) fn bond_extra_no_checks(stash: &AccountId, amount: Balance) { + let controller = Bonded::::get(stash).expect("bond must exist to bond_extra"); + let mut ledger = Ledger::::get(&controller).expect("ledger must exist to bond_extra"); + + let new_total = ledger.total + amount; + Balances::set_lock(crate::STAKING_ID, stash, new_total, WithdrawReasons::all()); + ledger.total = new_total; + ledger.active = new_total; + Ledger::::insert(controller, ledger); +} + pub(crate) fn setup_double_bonded_ledgers() { - assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 10, RewardDestination::Staked)); - assert_ok!(Staking::bond(RuntimeOrigin::signed(2), 20, RewardDestination::Staked)); - assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 20, RewardDestination::Staked)); + let init_ledgers = Ledger::::iter().count(); + + let _ = Balances::make_free_balance_be(&333, 2000); + let _ = Balances::make_free_balance_be(&444, 2000); + let _ = Balances::make_free_balance_be(&555, 2000); + let _ = Balances::make_free_balance_be(&777, 2000); + + assert_ok!(Staking::bond(RuntimeOrigin::signed(333), 10, RewardDestination::Staked)); + assert_ok!(Staking::bond(RuntimeOrigin::signed(444), 20, RewardDestination::Staked)); + assert_ok!(Staking::bond(RuntimeOrigin::signed(555), 20, RewardDestination::Staked)); // not relevant to the test case, but ensures try-runtime checks pass. - [1, 2, 3] + [333, 444, 555] .iter() .for_each(|s| Payee::::insert(s, RewardDestination::Staked)); // we want to test the case where a controller can also be a stash of another ledger. // for that, we change the controller/stash bonding so that: - // * 2 becomes controller of 1. - // * 3 becomes controller of 2. - // * 4 becomes controller of 3. - let ledger_1 = Ledger::::get(1).unwrap(); - let ledger_2 = Ledger::::get(2).unwrap(); - let ledger_3 = Ledger::::get(3).unwrap(); - - // 4 becomes controller of 3. - Bonded::::mutate(3, |controller| *controller = Some(4)); - Ledger::::insert(4, ledger_3); - - // 3 becomes controller of 2. - Bonded::::mutate(2, |controller| *controller = Some(3)); - Ledger::::insert(3, ledger_2); - - // 2 becomes controller of 1 - Bonded::::mutate(1, |controller| *controller = Some(2)); - Ledger::::insert(2, ledger_1); - // 1 is not controller anymore. - Ledger::::remove(1); + // * 444 becomes controller of 333. + // * 555 becomes controller of 444. + // * 777 becomes controller of 555. + let ledger_333 = Ledger::::get(333).unwrap(); + let ledger_444 = Ledger::::get(444).unwrap(); + let ledger_555 = Ledger::::get(555).unwrap(); + + // 777 becomes controller of 555. + Bonded::::mutate(555, |controller| *controller = Some(777)); + Ledger::::insert(777, ledger_555); + + // 555 becomes controller of 444. + Bonded::::mutate(444, |controller| *controller = Some(555)); + Ledger::::insert(555, ledger_444); + + // 444 becomes controller of 333. + Bonded::::mutate(333, |controller| *controller = Some(444)); + Ledger::::insert(444, ledger_333); + + // 333 is not controller anymore. + Ledger::::remove(333); // checks. now we have: - // * 3 ledgers - assert_eq!(Ledger::::iter().count(), 3); - // * stash 1 has controller 2. - assert_eq!(Bonded::::get(1), Some(2)); - assert_eq!(StakingLedger::::paired_account(StakingAccount::Stash(1)), Some(2)); - assert_eq!(Ledger::::get(2).unwrap().stash, 1); - - // * stash 2 has controller 3. - assert_eq!(Bonded::::get(2), Some(3)); - assert_eq!(StakingLedger::::paired_account(StakingAccount::Stash(2)), Some(3)); - assert_eq!(Ledger::::get(3).unwrap().stash, 2); - - // * stash 3 has controller 4. - assert_eq!(Bonded::::get(3), Some(4)); - assert_eq!(StakingLedger::::paired_account(StakingAccount::Stash(3)), Some(4)); - assert_eq!(Ledger::::get(4).unwrap().stash, 3); + // * +3 ledgers + assert_eq!(Ledger::::iter().count(), 3 + init_ledgers); + + // * stash 333 has controller 444. + assert_eq!(Bonded::::get(333), Some(444)); + assert_eq!(StakingLedger::::paired_account(StakingAccount::Stash(333)), Some(444)); + assert_eq!(Ledger::::get(444).unwrap().stash, 333); + + // * stash 444 has controller 555. + assert_eq!(Bonded::::get(444), Some(555)); + assert_eq!(StakingLedger::::paired_account(StakingAccount::Stash(444)), Some(555)); + assert_eq!(Ledger::::get(555).unwrap().stash, 444); + + // * stash 555 has controller 777. + assert_eq!(Bonded::::get(555), Some(777)); + assert_eq!(StakingLedger::::paired_account(StakingAccount::Stash(555)), Some(777)); + assert_eq!(Ledger::::get(777).unwrap().stash, 555); } #[macro_export] diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 407b301fad2..2f43e4847e4 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -27,8 +27,8 @@ use frame_support::{ dispatch::WithPostDispatchInfo, pallet_prelude::*, traits::{ - Currency, Defensive, DefensiveSaturating, EstimateNextNewSession, Get, Imbalance, Len, - OnUnbalanced, TryCollect, UnixTime, + Currency, Defensive, DefensiveSaturating, EstimateNextNewSession, Get, Imbalance, + InspectLockableCurrency, Len, OnUnbalanced, TryCollect, UnixTime, }, weights::Weight, }; @@ -50,8 +50,8 @@ use sp_std::prelude::*; use crate::{ election_size_tracker::StaticTracker, log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraInfo, EraPayout, Exposure, ExposureOf, Forcing, IndividualExposure, - MaxNominationsOf, MaxWinnersOf, Nominations, NominationsQuota, PositiveImbalanceOf, - RewardDestination, SessionInterface, StakingLedger, ValidatorPrefs, + LedgerIntegrityState, MaxNominationsOf, MaxWinnersOf, Nominations, NominationsQuota, + PositiveImbalanceOf, RewardDestination, SessionInterface, StakingLedger, ValidatorPrefs, }; use super::pallet::*; @@ -84,6 +84,38 @@ impl Pallet { StakingLedger::::paired_account(Stash(stash.clone())) } + /// Inspects and returns the corruption state of a ledger and bond, if any. + /// + /// Note: all operations in this method access directly the `Bonded` and `Ledger` storage maps + /// instead of using the [`StakingLedger`] API since the bond and/or ledger may be corrupted. + pub(crate) fn inspect_bond_state( + stash: &T::AccountId, + ) -> Result> { + let lock = T::Currency::balance_locked(crate::STAKING_ID, &stash); + + let controller = >::get(stash).ok_or_else(|| { + if lock == Zero::zero() { + Error::::NotStash + } else { + Error::::BadState + } + })?; + + match Ledger::::get(controller) { + Some(ledger) => + if ledger.stash != *stash { + Ok(LedgerIntegrityState::Corrupted) + } else { + if lock != ledger.total { + Ok(LedgerIntegrityState::LockCorrupted) + } else { + Ok(LedgerIntegrityState::Ok) + } + }, + None => Ok(LedgerIntegrityState::CorruptedKilled), + } + } + /// The total balance that can be slashed from a stash account as of right now. pub fn slashable_balance_of(stash: &T::AccountId) -> BalanceOf { // Weight note: consider making the stake accessible through stash. @@ -1837,12 +1869,12 @@ impl Pallet { "VoterList contains non-staker" ); + Self::check_ledgers()?; Self::check_bonded_consistency()?; Self::check_payees()?; Self::check_nominators()?; Self::check_exposures()?; Self::check_paged_exposures()?; - Self::check_ledgers()?; Self::check_count() } @@ -1851,6 +1883,7 @@ impl Pallet { /// * A bonded (stash, controller) pair should have only one associated ledger. I.e. if the /// ledger is bonded by stash, the controller account must not bond a different ledger. /// * A bonded (stash, controller) pair must have an associated ledger. + /// /// NOTE: these checks result in warnings only. Once /// is resolved, turn warns into check /// failures. @@ -1945,19 +1978,18 @@ impl Pallet { } /// Invariants: - /// * `ledger.controller` is not stored in the storage (but populated at retrieval). /// * Stake consistency: ledger.total == ledger.active + sum(ledger.unlocking). - /// * The controller keying the ledger and the ledger stash matches the state of the `Bonded` - /// storage. + /// * The ledger's controller and stash matches the associated `Bonded` tuple. + /// * Staking locked funds for every bonded stash should be the same as its ledger's total. + /// * Staking ledger and bond are not corrupted. fn check_ledgers() -> Result<(), TryRuntimeError> { Bonded::::iter() .map(|(stash, ctrl)| { - // `ledger.controller` is never stored in raw storage. - let raw = Ledger::::get(stash).unwrap_or_else(|| { - Ledger::::get(ctrl.clone()) - .expect("try_check: bonded stash/ctrl does not have an associated ledger") - }); - ensure!(raw.controller.is_none(), "raw storage controller should be None"); + // ensure locks consistency. + ensure!( + Self::inspect_bond_state(&stash) == Ok(LedgerIntegrityState::Ok), + "bond, ledger and/or staking lock inconsistent for a bonded stash." + ); // ensure ledger consistency. Self::ensure_ledger_consistent(ctrl) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 6afbf12032d..2e5b3aa7b87 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -25,7 +25,7 @@ use frame_support::{ pallet_prelude::*, traits::{ Currency, Defensive, DefensiveSaturating, EnsureOrigin, EstimateNextNewSession, Get, - LockableCurrency, OnUnbalanced, UnixTime, + InspectLockableCurrency, LockableCurrency, OnUnbalanced, UnixTime, WithdrawReasons, }, weights::Weight, BoundedVec, @@ -48,9 +48,9 @@ pub use impls::*; use crate::{ slashing, weights::WeightInfo, AccountIdLookupOf, ActiveEraInfo, BalanceOf, EraPayout, - EraRewardPoints, Exposure, ExposurePage, Forcing, MaxNominationsOf, NegativeImbalanceOf, - Nominations, NominationsQuota, PositiveImbalanceOf, RewardDestination, SessionInterface, - StakingLedger, UnappliedSlash, UnlockChunk, ValidatorPrefs, + EraRewardPoints, Exposure, ExposurePage, Forcing, LedgerIntegrityState, MaxNominationsOf, + NegativeImbalanceOf, Nominations, NominationsQuota, PositiveImbalanceOf, RewardDestination, + SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, ValidatorPrefs, }; // The speculative number of spans are used as an input of the weight annotation of @@ -88,10 +88,10 @@ pub mod pallet { pub trait Config: frame_system::Config { /// The staking balance. type Currency: LockableCurrency< - Self::AccountId, - Moment = BlockNumberFor, - Balance = Self::CurrencyBalance, - >; + Self::AccountId, + Moment = BlockNumberFor, + Balance = Self::CurrencyBalance, + > + InspectLockableCurrency; /// Just the `Currency::Balance` type; we have this item to allow us to constrain it to /// `From`. type CurrencyBalance: sp_runtime::traits::AtLeast32BitUnsigned @@ -796,6 +796,7 @@ pub mod pallet { } #[pallet::error] + #[derive(PartialEq)] pub enum Error { /// Not a controller account. NotController, @@ -855,6 +856,8 @@ pub mod pallet { BoundNotMet, /// Used when attempting to use deprecated controller account logic. ControllerDeprecated, + /// Cannot reset a ledger. + CannotRestoreLedger, } #[pallet::hooks] @@ -1980,6 +1983,108 @@ pub mod pallet { Ok(Some(T::WeightInfo::deprecate_controller_batch(controllers.len() as u32)).into()) } + + /// Restores the state of a ledger which is in an inconsistent state. + /// + /// The requirements to restore a ledger are the following: + /// * The stash is bonded; or + /// * The stash is not bonded but it has a staking lock left behind; or + /// * If the stash has an associated ledger and its state is inconsistent; or + /// * If the ledger is not corrupted *but* its staking lock is out of sync. + /// + /// The `maybe_*` input parameters will overwrite the corresponding data and metadata of the + /// ledger associated with the stash. If the input parameters are not set, the ledger will + /// be reset values from on-chain state. + #[pallet::call_index(29)] + #[pallet::weight(T::WeightInfo::restore_ledger())] + pub fn restore_ledger( + origin: OriginFor, + stash: T::AccountId, + maybe_controller: Option, + maybe_total: Option>, + maybe_unlocking: Option>, T::MaxUnlockingChunks>>, + ) -> DispatchResult { + T::AdminOrigin::ensure_origin(origin)?; + + let current_lock = T::Currency::balance_locked(crate::STAKING_ID, &stash); + let stash_balance = T::Currency::free_balance(&stash); + + let (new_controller, new_total) = match Self::inspect_bond_state(&stash) { + Ok(LedgerIntegrityState::Corrupted) => { + let new_controller = maybe_controller.unwrap_or(stash.clone()); + + let new_total = if let Some(total) = maybe_total { + let new_total = total.min(stash_balance); + // enforce lock == ledger.amount. + T::Currency::set_lock( + crate::STAKING_ID, + &stash, + new_total, + WithdrawReasons::all(), + ); + new_total + } else { + current_lock + }; + + Ok((new_controller, new_total)) + }, + Ok(LedgerIntegrityState::CorruptedKilled) => { + if current_lock == Zero::zero() { + // this case needs to restore both lock and ledger, so the new total needs + // to be given by the called since there's no way to restore the total + // on-chain. + ensure!(maybe_total.is_some(), Error::::CannotRestoreLedger); + Ok(( + stash.clone(), + maybe_total.expect("total exists as per the check above; qed."), + )) + } else { + Ok((stash.clone(), current_lock)) + } + }, + Ok(LedgerIntegrityState::LockCorrupted) => { + // ledger is not corrupted but its locks are out of sync. In this case, we need + // to enforce a new ledger.total and staking lock for this stash. + let new_total = + maybe_total.ok_or(Error::::CannotRestoreLedger)?.min(stash_balance); + T::Currency::set_lock( + crate::STAKING_ID, + &stash, + new_total, + WithdrawReasons::all(), + ); + + Ok((stash.clone(), new_total)) + }, + Err(Error::::BadState) => { + // the stash and ledger do not exist but lock is lingering. + T::Currency::remove_lock(crate::STAKING_ID, &stash); + ensure!( + Self::inspect_bond_state(&stash) == Err(Error::::NotStash), + Error::::BadState + ); + + return Ok(()); + }, + Ok(LedgerIntegrityState::Ok) | Err(_) => Err(Error::::CannotRestoreLedger), + }?; + + // re-bond stash and controller tuple. + Bonded::::insert(&stash, &new_controller); + + // resoter ledger state. + let mut ledger = StakingLedger::::new(stash.clone(), new_total); + ledger.controller = Some(new_controller); + ledger.unlocking = maybe_unlocking.unwrap_or_default(); + ledger.update()?; + + ensure!( + Self::inspect_bond_state(&stash) == Ok(LedgerIntegrityState::Ok), + Error::::BadState + ); + Ok(()) + } } } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index ef156e19552..a5c9abe2f17 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -6933,40 +6933,43 @@ mod ledger { setup_double_bonded_ledgers(); // Case 1: double bonded but not corrupted: - // stash 2 has controller 3: - assert_eq!(Bonded::::get(2), Some(3)); - assert_eq!(Ledger::::get(3).unwrap().stash, 2); + // stash 444 has controller 555: + assert_eq!(Bonded::::get(444), Some(555)); + assert_eq!(Ledger::::get(555).unwrap().stash, 444); - // stash 2 is also a controller of 1: - assert_eq!(Bonded::::get(1), Some(2)); - assert_eq!(StakingLedger::::paired_account(StakingAccount::Stash(1)), Some(2)); - assert_eq!(Ledger::::get(2).unwrap().stash, 1); + // stash 444 is also a controller of 333: + assert_eq!(Bonded::::get(333), Some(444)); + assert_eq!( + StakingLedger::::paired_account(StakingAccount::Stash(333)), + Some(444) + ); + assert_eq!(Ledger::::get(444).unwrap().stash, 333); - // although 2 is double bonded (it is a controller and a stash of different ledgers), + // although 444 is double bonded (it is a controller and a stash of different ledgers), // we can safely retrieve the ledger and mutate it since the correct ledger is // returned. - let ledger_result = StakingLedger::::get(StakingAccount::Stash(2)); - assert_eq!(ledger_result.unwrap().stash, 2); // correct ledger. + let ledger_result = StakingLedger::::get(StakingAccount::Stash(444)); + assert_eq!(ledger_result.unwrap().stash, 444); // correct ledger. - let ledger_result = StakingLedger::::get(StakingAccount::Controller(2)); - assert_eq!(ledger_result.unwrap().stash, 1); // correct ledger. + let ledger_result = StakingLedger::::get(StakingAccount::Controller(444)); + assert_eq!(ledger_result.unwrap().stash, 333); // correct ledger. - // fetching ledger 1 by its stash works. - let ledger_result = StakingLedger::::get(StakingAccount::Stash(1)); - assert_eq!(ledger_result.unwrap().stash, 1); + // fetching ledger 333 by its stash works. + let ledger_result = StakingLedger::::get(StakingAccount::Stash(333)); + assert_eq!(ledger_result.unwrap().stash, 333); // Case 2: corrupted ledger bonding. // in this case, we simulate what happens when fetching a ledger by stash returns a // ledger with a different stash. when this happens, we return an error instead of the // ledger to prevent ledger mutations. - let mut ledger = Ledger::::get(2).unwrap(); - assert_eq!(ledger.stash, 1); - ledger.stash = 2; - Ledger::::insert(2, ledger); + let mut ledger = Ledger::::get(444).unwrap(); + assert_eq!(ledger.stash, 333); + ledger.stash = 444; + Ledger::::insert(444, ledger); // now, we are prevented from fetching the ledger by stash from 1. It's associated // controller (2) is now bonding a ledger with a different stash (2, not 1). - assert!(StakingLedger::::get(StakingAccount::Stash(1)).is_err()); + assert!(StakingLedger::::get(StakingAccount::Stash(333)).is_err()); }) } @@ -7069,7 +7072,7 @@ mod ledger { #[test] fn deprecate_controller_batch_works_full_weight() { - ExtBuilder::default().build_and_execute(|| { + ExtBuilder::default().try_state(false).build_and_execute(|| { // Given: let start = 1001; @@ -7253,7 +7256,7 @@ mod ledger { let bounded_controllers: BoundedVec< _, ::MaxControllersInDeprecationBatch, - > = BoundedVec::try_from(vec![1, 2, 3, 4]).unwrap(); + > = BoundedVec::try_from(vec![333, 444, 555, 777]).unwrap(); assert_ok!(Staking::deprecate_controller_batch( RuntimeOrigin::root(), @@ -7276,7 +7279,7 @@ mod ledger { let bounded_controllers: BoundedVec< _, ::MaxControllersInDeprecationBatch, - > = BoundedVec::try_from(vec![4, 3, 2, 1]).unwrap(); + > = BoundedVec::try_from(vec![777, 555, 444, 333]).unwrap(); assert_ok!(Staking::deprecate_controller_batch( RuntimeOrigin::root(), @@ -7296,9 +7299,9 @@ mod ledger { setup_double_bonded_ledgers(); // in this case, setting controller works due to the ordering of the calls. - assert_ok!(Staking::set_controller(RuntimeOrigin::signed(1))); - assert_ok!(Staking::set_controller(RuntimeOrigin::signed(2))); - assert_ok!(Staking::set_controller(RuntimeOrigin::signed(3))); + assert_ok!(Staking::set_controller(RuntimeOrigin::signed(333))); + assert_ok!(Staking::set_controller(RuntimeOrigin::signed(444))); + assert_ok!(Staking::set_controller(RuntimeOrigin::signed(555))); }) } @@ -7307,17 +7310,400 @@ mod ledger { ExtBuilder::default().has_stakers(false).try_state(false).build_and_execute(|| { setup_double_bonded_ledgers(); - // setting the controller of ledger associated with stash 3 fails since its stash is a + // setting the controller of ledger associated with stash 555 fails since its stash is a // controller of another ledger. assert_noop!( - Staking::set_controller(RuntimeOrigin::signed(3)), + Staking::set_controller(RuntimeOrigin::signed(555)), Error::::BadState ); assert_noop!( - Staking::set_controller(RuntimeOrigin::signed(2)), + Staking::set_controller(RuntimeOrigin::signed(444)), Error::::BadState ); - assert_ok!(Staking::set_controller(RuntimeOrigin::signed(1))); + assert_ok!(Staking::set_controller(RuntimeOrigin::signed(333))); + }) + } +} + +mod ledger_recovery { + use super::*; + use frame_support::traits::InspectLockableCurrency; + + #[test] + fn inspect_recovery_ledger_simple_works() { + ExtBuilder::default().has_stakers(true).try_state(false).build_and_execute(|| { + setup_double_bonded_ledgers(); + + // non corrupted ledger. + assert_eq!(Staking::inspect_bond_state(&11).unwrap(), LedgerIntegrityState::Ok); + + // non bonded stash. + assert!(Bonded::::get(&1111).is_none()); + assert!(Staking::inspect_bond_state(&1111).is_err()); + + // double bonded but not corrupted. + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok); + }) + } + + #[test] + fn inspect_recovery_ledger_corupted_killed_works() { + ExtBuilder::default().has_stakers(true).try_state(false).build_and_execute(|| { + setup_double_bonded_ledgers(); + + let lock_333_before = Balances::balance_locked(crate::STAKING_ID, &333); + + // get into corrupted and killed ledger state by killing a corrupted ledger: + // init state: + // (333, 444) + // (444, 555) + // set_controller(444) to 444 + // (333, 444) -> corrupted + // (444, 444) + // kill(333) + // (444, 444) -> corrupted and None. + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok); + set_controller_no_checks(&444); + + // now try-state fails. + assert!(Staking::do_try_state(System::block_number()).is_err()); + + // 333 is corrupted since it's controller is linking 444 ledger. + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Corrupted); + // 444 however is OK. + assert_eq!(Staking::inspect_bond_state(&444).unwrap(), LedgerIntegrityState::Ok); + + // kill the corrupted ledger that is associated with stash 333. + assert_ok!(StakingLedger::::kill(&333)); + + // 333 bond is no more but it returns `BadState` because the lock on this stash is + // still set (see checks below). + assert_eq!(Staking::inspect_bond_state(&333), Err(Error::::BadState)); + // now the *other* ledger associated with 444 has been corrupted and killed (None). + assert_eq!( + Staking::inspect_bond_state(&444), + Ok(LedgerIntegrityState::CorruptedKilled) + ); + + // side effects on 333 - ledger, bonded, payee, lock should be completely empty. + // however, 333 lock remains. + assert_eq!(Balances::balance_locked(crate::STAKING_ID, &333), lock_333_before); // NOK + assert!(Bonded::::get(&333).is_none()); // OK + assert!(Payee::::get(&333).is_none()); // OK + assert!(Ledger::::get(&444).is_none()); // OK + + // side effects on 444 - ledger, bonded, payee, lock should remain be intact. + // however, 444 lock was removed. + assert_eq!(Balances::balance_locked(crate::STAKING_ID, &444), 0); // NOK + assert!(Bonded::::get(&444).is_some()); // OK + assert!(Payee::::get(&444).is_some()); // OK + assert!(Ledger::::get(&555).is_none()); // NOK + + assert!(Staking::do_try_state(System::block_number()).is_err()); + }) + } + + #[test] + fn inspect_recovery_ledger_corupted_killed_other_works() { + ExtBuilder::default().has_stakers(true).try_state(false).build_and_execute(|| { + setup_double_bonded_ledgers(); + + let lock_333_before = Balances::balance_locked(crate::STAKING_ID, &333); + + // get into corrupted and killed ledger state by killing a corrupted ledger: + // init state: + // (333, 444) + // (444, 555) + // set_controller(444) to 444 + // (333, 444) -> corrupted + // (444, 444) + // kill(444) + // (333, 444) -> corrupted and None + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok); + set_controller_no_checks(&444); + + // now try-state fails. + assert!(Staking::do_try_state(System::block_number()).is_err()); + + // 333 is corrupted since it's controller is linking 444 ledger. + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Corrupted); + // 444 however is OK. + assert_eq!(Staking::inspect_bond_state(&444).unwrap(), LedgerIntegrityState::Ok); + + // kill the *other* ledger that is double bonded but not corrupted. + assert_ok!(StakingLedger::::kill(&444)); + + // now 333 is corrupted and None through the *other* ledger being killed. + assert_eq!( + Staking::inspect_bond_state(&333).unwrap(), + LedgerIntegrityState::CorruptedKilled, + ); + // 444 is cleaned and not a stash anymore; no lock left behind. + assert_eq!(Ledger::::get(&444), None); + assert_eq!(Staking::inspect_bond_state(&444), Err(Error::::NotStash)); + + // side effects on 333 - ledger, bonded, payee, lock should be intact. + assert_eq!(Balances::balance_locked(crate::STAKING_ID, &333), lock_333_before); // OK + assert_eq!(Bonded::::get(&333), Some(444)); // OK + assert!(Payee::::get(&333).is_some()); // OK + // however, ledger associated with its controller was killed. + assert!(Ledger::::get(&444).is_none()); // NOK + + // side effects on 444 - ledger, bonded, payee, lock should be completely removed. + assert_eq!(Balances::balance_locked(crate::STAKING_ID, &444), 0); // OK + assert!(Bonded::::get(&444).is_none()); // OK + assert!(Payee::::get(&444).is_none()); // OK + assert!(Ledger::::get(&555).is_none()); // OK + + assert!(Staking::do_try_state(System::block_number()).is_err()); + }) + } + + #[test] + fn inspect_recovery_ledger_lock_corrupted_works() { + ExtBuilder::default().has_stakers(true).try_state(false).build_and_execute(|| { + setup_double_bonded_ledgers(); + + // get into lock corrupted ledger state by bond_extra on a ledger that is double bonded + // with a corrupted ledger. + // init state: + // (333, 444) + // (444, 555) + // set_controller(444) to 444 + // (333, 444) -> corrupted + // (444, 444) + // bond_extra(333, 10) -> lock corrupted on 444 + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok); + set_controller_no_checks(&444); + bond_extra_no_checks(&333, 10); + + // now try-state fails. + assert!(Staking::do_try_state(System::block_number()).is_err()); + + // 333 is corrupted since it's controller is linking 444 ledger. + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Corrupted); + // 444 ledger is not corrupted but locks got out of sync. + assert_eq!( + Staking::inspect_bond_state(&444).unwrap(), + LedgerIntegrityState::LockCorrupted + ); + }) + } + + // Corrupted ledger restore. + // + // * Double bonded and corrupted ledger. + #[test] + fn restore_ledger_corrupted_works() { + ExtBuilder::default().has_stakers(true).build_and_execute(|| { + setup_double_bonded_ledgers(); + + // get into corrupted and killed ledger state. + // init state: + // (333, 444) + // (444, 555) + // set_controller(444) to 444 + // (333, 444) -> corrupted + // (444, 444) + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok); + set_controller_no_checks(&444); + + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Corrupted); + + // now try-state fails. + assert!(Staking::do_try_state(System::block_number()).is_err()); + + // recover the ledger bonded by 333 stash. + assert_ok!(Staking::restore_ledger(RuntimeOrigin::root(), 333, None, None, None)); + + // try-state checks are ok now. + assert_ok!(Staking::do_try_state(System::block_number())); + }) + } + + // Corrupted and killed ledger restore. + // + // * Double bonded and corrupted ledger. + // * Ledger killed by own controller. + #[test] + fn restore_ledger_corrupted_killed_works() { + ExtBuilder::default().has_stakers(true).build_and_execute(|| { + setup_double_bonded_ledgers(); + + // ledger.total == lock + let total_444_before_corruption = Balances::balance_locked(crate::STAKING_ID, &444); + + // get into corrupted and killed ledger state by killing a corrupted ledger: + // init state: + // (333, 444) + // (444, 555) + // set_controller(444) to 444 + // (333, 444) -> corrupted + // (444, 444) + // kill(333) + // (444, 444) -> corrupted and None. + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok); + set_controller_no_checks(&444); + + // kill the corrupted ledger that is associated with stash 333. + assert_ok!(StakingLedger::::kill(&333)); + + // 333 bond is no more but it returns `BadState` because the lock on this stash is + // still set (see checks below). + assert_eq!(Staking::inspect_bond_state(&333), Err(Error::::BadState)); + // now the *other* ledger associated with 444 has been corrupted and killed (None). + assert!(Staking::ledger(StakingAccount::Stash(444)).is_err()); + + // try-state should fail. + assert!(Staking::do_try_state(System::block_number()).is_err()); + + // recover the ledger bonded by 333 stash. + assert_ok!(Staking::restore_ledger(RuntimeOrigin::root(), 333, None, None, None)); + + // for the try-state checks to pass, we also need to recover the stash 444 which is + // corrupted too by proxy of kill(333). Currently, both the lock and the ledger of 444 + // have been cleared so we need to provide the new amount to restore the ledger. + assert_noop!( + Staking::restore_ledger(RuntimeOrigin::root(), 444, None, None, None), + Error::::CannotRestoreLedger + ); + + assert_ok!(Staking::restore_ledger( + RuntimeOrigin::root(), + 444, + None, + Some(total_444_before_corruption), + None, + )); + + // try-state checks are ok now. + assert_ok!(Staking::do_try_state(System::block_number())); + }) + } + + // Corrupted and killed by *other* ledger restore. + // + // * Double bonded and corrupted ledger. + // * Ledger killed by own controller. + #[test] + fn restore_ledger_corrupted_killed_other_works() { + ExtBuilder::default().has_stakers(true).build_and_execute(|| { + setup_double_bonded_ledgers(); + + // get into corrupted and killed ledger state by killing a corrupted ledger: + // init state: + // (333, 444) + // (444, 555) + // set_controller(444) to 444 + // (333, 444) -> corrupted + // (444, 444) + // kill(444) + // (333, 444) -> corrupted and None + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok); + set_controller_no_checks(&444); + + // now try-state fails. + assert!(Staking::do_try_state(System::block_number()).is_err()); + + // 333 is corrupted since it's controller is linking 444 ledger. + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Corrupted); + // 444 however is OK. + assert_eq!(Staking::inspect_bond_state(&444).unwrap(), LedgerIntegrityState::Ok); + + // kill the *other* ledger that is double bonded but not corrupted. + assert_ok!(StakingLedger::::kill(&444)); + + // recover the ledger bonded by 333 stash. + assert_ok!(Staking::restore_ledger(RuntimeOrigin::root(), 333, None, None, None)); + + // 444 does not need recover in this case since it's been killed successfully. + assert_eq!(Staking::inspect_bond_state(&444), Err(Error::::NotStash)); + + // try-state checks are ok now. + assert_ok!(Staking::do_try_state(System::block_number())); + }) + } + + // Corrupted with bond_extra. + // + // * Double bonded and corrupted ledger. + // * Corrupted ledger calls `bond_extra` + #[test] + fn restore_ledger_corrupted_bond_extra_works() { + ExtBuilder::default().has_stakers(true).build_and_execute(|| { + setup_double_bonded_ledgers(); + + let lock_333_before = Balances::balance_locked(crate::STAKING_ID, &333); + let lock_444_before = Balances::balance_locked(crate::STAKING_ID, &444); + + // get into corrupted and killed ledger state by killing a corrupted ledger: + // init state: + // (333, 444) + // (444, 555) + // set_controller(444) to 444 + // (333, 444) -> corrupted + // (444, 444) + // bond_extra(444, 40) -> OK + // bond_extra(333, 30) -> locks out of sync + + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok); + set_controller_no_checks(&444); + + // now try-state fails. + assert!(Staking::do_try_state(System::block_number()).is_err()); + + // if 444 bonds extra, the locks remain in sync. + bond_extra_no_checks(&444, 40); + assert_eq!(Balances::balance_locked(crate::STAKING_ID, &333), lock_333_before); + assert_eq!(Balances::balance_locked(crate::STAKING_ID, &444), lock_444_before + 40); + + // however if 333 bonds extra, the wrong lock is updated. + bond_extra_no_checks(&333, 30); + assert_eq!( + Balances::balance_locked(crate::STAKING_ID, &333), + lock_444_before + 40 + 30 + ); //not OK + assert_eq!(Balances::balance_locked(crate::STAKING_ID, &444), lock_444_before + 40); // OK + + // recover the ledger bonded by 333 stash. Note that the total/lock needs to be + // re-written since on-chain data lock has become out of sync. + assert_ok!(Staking::restore_ledger( + RuntimeOrigin::root(), + 333, + None, + Some(lock_333_before + 30), + None + )); + + // now recover 444 that although it's not corrupted, its lock and ledger.total are out + // of sync. in which case, we need to explicitly set the ledger's lock and amount, + // otherwise the ledger recover will fail. + assert_noop!( + Staking::restore_ledger(RuntimeOrigin::root(), 444, None, None, None), + Error::::CannotRestoreLedger + ); + + //and enforcing a new ledger lock/total on this non-corrupted ledger will work. + assert_ok!(Staking::restore_ledger( + RuntimeOrigin::root(), + 444, + None, + Some(lock_444_before + 40), + None + )); + + // double-check that ledgers got to expected state and bond_extra done during the + // corrupted state is part of the recovered ledgers. + let ledger_333 = Bonded::::get(&333).and_then(Ledger::::get).unwrap(); + let ledger_444 = Bonded::::get(&444).and_then(Ledger::::get).unwrap(); + + assert_eq!(ledger_333.total, lock_333_before + 30); + assert_eq!(Balances::balance_locked(crate::STAKING_ID, &333), ledger_333.total); + assert_eq!(ledger_444.total, lock_444_before + 40); + assert_eq!(Balances::balance_locked(crate::STAKING_ID, &444), ledger_444.total); + + // try-state checks are ok now. + assert_ok!(Staking::do_try_state(System::block_number())); }) } } diff --git a/substrate/frame/staking/src/weights.rs b/substrate/frame/staking/src/weights.rs index 6f729e08ba5..8a04a3dfb3f 100644 --- a/substrate/frame/staking/src/weights.rs +++ b/substrate/frame/staking/src/weights.rs @@ -17,10 +17,10 @@ //! Autogenerated weights for `pallet_staking` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2024-01-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-03-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-q7z7ruxr-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -80,6 +80,7 @@ pub trait WeightInfo { fn chill_other() -> Weight; fn force_apply_min_commission() -> Weight; fn set_min_commission() -> Weight; + fn restore_ledger() -> Weight; } /// Weights for `pallet_staking` using the Substrate node and recommended hardware. @@ -87,21 +88,21 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:0 w:1) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:0 w:1) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn bond() -> Weight { // Proof Size summary in bytes: - // Measured: `927` + // Measured: `1042` // Estimated: `4764` - // Minimum execution time: 42_042_000 picoseconds. - Weight::from_parts(43_292_000, 4764) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Minimum execution time: 48_753_000 picoseconds. + Weight::from_parts(50_539_000, 4764) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: `Staking::Bonded` (r:1 w:0) @@ -120,21 +121,21 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1990` // Estimated: `8877` - // Minimum execution time: 85_050_000 picoseconds. - Weight::from_parts(87_567_000, 8877) + // Minimum execution time: 92_701_000 picoseconds. + Weight::from_parts(95_657_000, 8877) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:0) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::MinNominatorBond` (r:1 w:0) /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) @@ -147,41 +148,43 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2195` // Estimated: `8877` - // Minimum execution time: 89_076_000 picoseconds. - Weight::from_parts(92_715_000, 8877) + // Minimum execution time: 101_049_000 picoseconds. + Weight::from_parts(103_729_000, 8877) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::CurrentEra` (r:1 w:0) - /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:0) + /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1115` + // Measured: `1297` // Estimated: `4764` - // Minimum execution time: 42_067_000 picoseconds. - Weight::from_parts(43_239_807, 4764) - // Standard Error: 831 - .saturating_add(Weight::from_parts(46_257, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(5_u64)) + // Minimum execution time: 51_672_000 picoseconds. + Weight::from_parts(53_817_441, 4764) + // Standard Error: 1_124 + .saturating_add(Weight::from_parts(49_168, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:1) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Staking::Bonded` (r:1 w:1) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) @@ -207,10 +210,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 86_490_000 picoseconds. - Weight::from_parts(95_358_751, 6248) - // Standard Error: 3_952 - .saturating_add(Weight::from_parts(1_294_907, 0).saturating_mul(s.into())) + // Minimum execution time: 92_846_000 picoseconds. + Weight::from_parts(102_158_606, 6248) + // Standard Error: 4_187 + .saturating_add(Weight::from_parts(1_436_364, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(11_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -218,6 +221,8 @@ impl WeightInfo for SubstrateWeight { } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::MinValidatorBond` (r:1 w:0) /// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::MinCommission` (r:1 w:0) @@ -228,8 +233,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:0) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:1 w:1) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:1 w:1) @@ -242,31 +245,35 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1372` // Estimated: `4556` - // Minimum execution time: 50_326_000 picoseconds. - Weight::from_parts(52_253_000, 4556) + // Minimum execution time: 58_162_000 picoseconds. + Weight::from_parts(60_124_000, 4556) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:128 w:128) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1280 + k * (569 ±0)` + // Measured: `1815 + k * (572 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 29_305_000 picoseconds. - Weight::from_parts(32_199_604, 4556) - // Standard Error: 7_150 - .saturating_add(Weight::from_parts(6_437_124, 0).saturating_mul(k.into())) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Minimum execution time: 37_950_000 picoseconds. + Weight::from_parts(34_461_075, 4556) + // Standard Error: 8_013 + .saturating_add(Weight::from_parts(6_696_510, 0).saturating_mul(k.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) .saturating_add(Weight::from_parts(0, 3033).saturating_mul(k.into())) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::MinNominatorBond` (r:1 w:0) /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) @@ -277,8 +284,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:2 w:2) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:1 w:1) @@ -292,10 +297,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1866 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 63_267_000 picoseconds. - Weight::from_parts(61_741_404, 6248) - // Standard Error: 12_955 - .saturating_add(Weight::from_parts(3_811_743, 0).saturating_mul(n.into())) + // Minimum execution time: 70_167_000 picoseconds. + Weight::from_parts(68_024_084, 6248) + // Standard Error: 14_256 + .saturating_add(Weight::from_parts(4_195_757, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) @@ -303,6 +308,8 @@ impl WeightInfo for SubstrateWeight { } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) @@ -317,11 +324,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `1650` + // Measured: `1816` // Estimated: `6248` - // Minimum execution time: 52_862_000 picoseconds. - Weight::from_parts(54_108_000, 6248) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Minimum execution time: 61_730_000 picoseconds. + Weight::from_parts(63_430_000, 6248) + .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: `Staking::Ledger` (r:1 w:0) @@ -334,37 +341,37 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `902` // Estimated: `4556` - // Minimum execution time: 16_350_000 picoseconds. - Weight::from_parts(16_802_000, 4556) + // Minimum execution time: 20_857_000 picoseconds. + Weight::from_parts(21_615_000, 4556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::Payee` (r:1 w:1) - /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Payee` (r:1 w:1) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn update_payee() -> Weight { // Proof Size summary in bytes: // Measured: `969` // Estimated: `4556` - // Minimum execution time: 19_981_000 picoseconds. - Weight::from_parts(20_539_000, 4556) + // Minimum execution time: 24_739_000 picoseconds. + Weight::from_parts(25_785_000, 4556) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:1 w:2) + /// Storage: `Staking::Ledger` (r:2 w:2) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) fn set_controller() -> Weight { // Proof Size summary in bytes: // Measured: `902` - // Estimated: `4556` - // Minimum execution time: 19_304_000 picoseconds. - Weight::from_parts(20_000_000, 4556) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Estimated: `8122` + // Minimum execution time: 24_622_000 picoseconds. + Weight::from_parts(25_220_000, 8122) + .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Staking::ValidatorCount` (r:0 w:1) @@ -373,8 +380,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_568_000 picoseconds. - Weight::from_parts(2_708_000, 0) + // Minimum execution time: 2_634_000 picoseconds. + Weight::from_parts(2_842_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -383,8 +390,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_950_000 picoseconds. - Weight::from_parts(8_348_000, 0) + // Minimum execution time: 8_496_000 picoseconds. + Weight::from_parts(9_016_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -393,8 +400,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_967_000 picoseconds. - Weight::from_parts(8_222_000, 0) + // Minimum execution time: 8_510_000 picoseconds. + Weight::from_parts(8_893_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -403,8 +410,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_006_000 picoseconds. - Weight::from_parts(8_440_000, 0) + // Minimum execution time: 8_243_000 picoseconds. + Weight::from_parts(8_678_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::Invulnerables` (r:0 w:1) @@ -414,30 +421,30 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_524_000 picoseconds. - Weight::from_parts(3_123_608, 0) - // Standard Error: 59 - .saturating_add(Weight::from_parts(11_596, 0).saturating_mul(v.into())) + // Minimum execution time: 2_781_000 picoseconds. + Weight::from_parts(3_441_708, 0) + // Standard Error: 58 + .saturating_add(Weight::from_parts(11_811, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Staking::Ledger` (r:5900 w:11800) + /// Storage: `Staking::Ledger` (r:11800 w:11800) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:5900 w:5900) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:5900 w:0) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:0 w:5900) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 5900]`. fn deprecate_controller_batch(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1356 + i * (151 ±0)` - // Estimated: `990 + i * (3566 ±0)` - // Minimum execution time: 2_092_000 picoseconds. - Weight::from_parts(2_258_000, 990) - // Standard Error: 32_695 - .saturating_add(Weight::from_parts(16_669_219, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(i.into()))) + // Measured: `1746 + i * (229 ±0)` + // Estimated: `990 + i * (7132 ±0)` + // Minimum execution time: 5_331_000 picoseconds. + Weight::from_parts(5_511_000, 990) + // Standard Error: 66_734 + .saturating_add(Weight::from_parts(31_157_413, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(i.into()))) - .saturating_add(Weight::from_parts(0, 3566).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(0, 7132).saturating_mul(i.into())) } /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -472,10 +479,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 84_275_000 picoseconds. - Weight::from_parts(92_512_416, 6248) - // Standard Error: 3_633 - .saturating_add(Weight::from_parts(1_315_923, 0).saturating_mul(s.into())) + // Minimum execution time: 89_473_000 picoseconds. + Weight::from_parts(98_055_990, 6248) + // Standard Error: 4_159 + .saturating_add(Weight::from_parts(1_398_203, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -488,10 +495,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `66672` // Estimated: `70137` - // Minimum execution time: 101_707_000 picoseconds. - Weight::from_parts(912_819_462, 70137) - // Standard Error: 57_547 - .saturating_add(Weight::from_parts(4_856_799, 0).saturating_mul(s.into())) + // Minimum execution time: 102_480_000 picoseconds. + Weight::from_parts(1_165_789_820, 70137) + // Standard Error: 77_157 + .saturating_add(Weight::from_parts(6_489_253, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -528,10 +535,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `33297 + n * (377 ±0)` // Estimated: `30944 + n * (3774 ±0)` - // Minimum execution time: 138_657_000 picoseconds. - Weight::from_parts(167_173_445, 30944) - // Standard Error: 25_130 - .saturating_add(Weight::from_parts(44_566_012, 0).saturating_mul(n.into())) + // Minimum execution time: 156_890_000 picoseconds. + Weight::from_parts(202_972_688, 30944) + // Standard Error: 29_972 + .saturating_add(Weight::from_parts(48_226_698, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(14_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -555,10 +562,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1991 + l * (7 ±0)` // Estimated: `8877` - // Minimum execution time: 80_061_000 picoseconds. - Weight::from_parts(82_836_434, 8877) - // Standard Error: 4_348 - .saturating_add(Weight::from_parts(75_744, 0).saturating_mul(l.into())) + // Minimum execution time: 88_482_000 picoseconds. + Weight::from_parts(92_616_600, 8877) + // Standard Error: 4_411 + .saturating_add(Weight::from_parts(117_722, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -593,10 +600,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 92_560_000 picoseconds. - Weight::from_parts(97_684_741, 6248) - // Standard Error: 3_361 - .saturating_add(Weight::from_parts(1_292_732, 0).saturating_mul(s.into())) + // Minimum execution time: 98_489_000 picoseconds. + Weight::from_parts(102_968_643, 6248) + // Standard Error: 4_823 + .saturating_add(Weight::from_parts(1_420_838, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(11_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -642,12 +649,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0 + n * (720 ±0) + v * (3598 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 564_963_000 picoseconds. - Weight::from_parts(569_206_000, 512390) - // Standard Error: 2_033_235 - .saturating_add(Weight::from_parts(68_025_841, 0).saturating_mul(v.into())) - // Standard Error: 202_600 - .saturating_add(Weight::from_parts(17_916_770, 0).saturating_mul(n.into())) + // Minimum execution time: 604_820_000 picoseconds. + Weight::from_parts(608_838_000, 512390) + // Standard Error: 2_300_345 + .saturating_add(Weight::from_parts(72_980_573, 0).saturating_mul(v.into())) + // Standard Error: 229_216 + .saturating_add(Weight::from_parts(20_739_416, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(206_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -678,12 +685,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3175 + n * (911 ±0) + v * (395 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 32_196_540_000 picoseconds. - Weight::from_parts(32_341_871_000, 512390) - // Standard Error: 354_657 - .saturating_add(Weight::from_parts(5_143_440, 0).saturating_mul(v.into())) - // Standard Error: 354_657 - .saturating_add(Weight::from_parts(3_328_189, 0).saturating_mul(n.into())) + // Minimum execution time: 37_380_439_000 picoseconds. + Weight::from_parts(38_187_734_000, 512390) + // Standard Error: 425_319 + .saturating_add(Weight::from_parts(6_001_288, 0).saturating_mul(v.into())) + // Standard Error: 425_319 + .saturating_add(Weight::from_parts(4_129_446, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(201_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -700,10 +707,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `979 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_381_903_000 picoseconds. - Weight::from_parts(32_693_059, 3510) - // Standard Error: 10_000 - .saturating_add(Weight::from_parts(4_736_173, 0).saturating_mul(v.into())) + // Minimum execution time: 2_572_838_000 picoseconds. + Weight::from_parts(67_632_557, 3510) + // Standard Error: 12_028 + .saturating_add(Weight::from_parts(5_117_459, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -714,6 +721,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxValidatorsCount` (r:0 w:1) /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::MaxStakedRewards` (r:0 w:1) + /// Proof: `Staking::MaxStakedRewards` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::ChillThreshold` (r:0 w:1) /// Proof: `Staking::ChillThreshold` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxNominatorsCount` (r:0 w:1) @@ -724,9 +733,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_434_000 picoseconds. - Weight::from_parts(5_742_000, 0) - .saturating_add(T::DbWeight::get().writes(6_u64)) + // Minimum execution time: 5_962_000 picoseconds. + Weight::from_parts(6_497_000, 0) + .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `Staking::MinCommission` (r:0 w:1) /// Proof: `Staking::MinCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -734,6 +743,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxValidatorsCount` (r:0 w:1) /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::MaxStakedRewards` (r:0 w:1) + /// Proof: `Staking::MaxStakedRewards` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::ChillThreshold` (r:0 w:1) /// Proof: `Staking::ChillThreshold` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxNominatorsCount` (r:0 w:1) @@ -744,9 +755,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_588_000 picoseconds. - Weight::from_parts(4_854_000, 0) - .saturating_add(T::DbWeight::get().writes(6_u64)) + // Minimum execution time: 5_227_000 picoseconds. + Weight::from_parts(5_496_000, 0) + .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) @@ -774,8 +785,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1939` // Estimated: `6248` - // Minimum execution time: 68_780_000 picoseconds. - Weight::from_parts(71_479_000, 6248) + // Minimum execution time: 75_129_000 picoseconds. + Weight::from_parts(77_498_000, 6248) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -787,8 +798,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `691` // Estimated: `3510` - // Minimum execution time: 12_268_000 picoseconds. - Weight::from_parts(12_661_000, 3510) + // Minimum execution time: 13_488_000 picoseconds. + Weight::from_parts(14_183_000, 3510) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -798,31 +809,50 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_071_000 picoseconds. - Weight::from_parts(3_334_000, 0) + // Minimum execution time: 3_368_000 picoseconds. + Weight::from_parts(3_582_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:1) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + fn restore_ledger() -> Weight { + // Proof Size summary in bytes: + // Measured: `1047` + // Estimated: `4764` + // Minimum execution time: 44_876_000 picoseconds. + Weight::from_parts(46_353_000, 4764) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } } // For backwards compatibility and tests. impl WeightInfo for () { /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:0 w:1) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:0 w:1) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn bond() -> Weight { // Proof Size summary in bytes: - // Measured: `927` + // Measured: `1042` // Estimated: `4764` - // Minimum execution time: 42_042_000 picoseconds. - Weight::from_parts(43_292_000, 4764) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Minimum execution time: 48_753_000 picoseconds. + Weight::from_parts(50_539_000, 4764) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: `Staking::Bonded` (r:1 w:0) @@ -841,21 +871,21 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1990` // Estimated: `8877` - // Minimum execution time: 85_050_000 picoseconds. - Weight::from_parts(87_567_000, 8877) + // Minimum execution time: 92_701_000 picoseconds. + Weight::from_parts(95_657_000, 8877) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:0) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::MinNominatorBond` (r:1 w:0) /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) @@ -868,41 +898,43 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2195` // Estimated: `8877` - // Minimum execution time: 89_076_000 picoseconds. - Weight::from_parts(92_715_000, 8877) + // Minimum execution time: 101_049_000 picoseconds. + Weight::from_parts(103_729_000, 8877) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::CurrentEra` (r:1 w:0) - /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:0) + /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1115` + // Measured: `1297` // Estimated: `4764` - // Minimum execution time: 42_067_000 picoseconds. - Weight::from_parts(43_239_807, 4764) - // Standard Error: 831 - .saturating_add(Weight::from_parts(46_257, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(5_u64)) + // Minimum execution time: 51_672_000 picoseconds. + Weight::from_parts(53_817_441, 4764) + // Standard Error: 1_124 + .saturating_add(Weight::from_parts(49_168, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:1) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Staking::Bonded` (r:1 w:1) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) @@ -928,10 +960,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 86_490_000 picoseconds. - Weight::from_parts(95_358_751, 6248) - // Standard Error: 3_952 - .saturating_add(Weight::from_parts(1_294_907, 0).saturating_mul(s.into())) + // Minimum execution time: 92_846_000 picoseconds. + Weight::from_parts(102_158_606, 6248) + // Standard Error: 4_187 + .saturating_add(Weight::from_parts(1_436_364, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(11_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -939,6 +971,8 @@ impl WeightInfo for () { } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::MinValidatorBond` (r:1 w:0) /// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::MinCommission` (r:1 w:0) @@ -949,8 +983,6 @@ impl WeightInfo for () { /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:0) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:1 w:1) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:1 w:1) @@ -963,31 +995,35 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1372` // Estimated: `4556` - // Minimum execution time: 50_326_000 picoseconds. - Weight::from_parts(52_253_000, 4556) + // Minimum execution time: 58_162_000 picoseconds. + Weight::from_parts(60_124_000, 4556) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:128 w:128) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1280 + k * (569 ±0)` + // Measured: `1815 + k * (572 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 29_305_000 picoseconds. - Weight::from_parts(32_199_604, 4556) - // Standard Error: 7_150 - .saturating_add(Weight::from_parts(6_437_124, 0).saturating_mul(k.into())) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Minimum execution time: 37_950_000 picoseconds. + Weight::from_parts(34_461_075, 4556) + // Standard Error: 8_013 + .saturating_add(Weight::from_parts(6_696_510, 0).saturating_mul(k.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) .saturating_add(Weight::from_parts(0, 3033).saturating_mul(k.into())) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::MinNominatorBond` (r:1 w:0) /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) @@ -998,8 +1034,6 @@ impl WeightInfo for () { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:2 w:2) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:1 w:1) @@ -1013,10 +1047,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1866 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 63_267_000 picoseconds. - Weight::from_parts(61_741_404, 6248) - // Standard Error: 12_955 - .saturating_add(Weight::from_parts(3_811_743, 0).saturating_mul(n.into())) + // Minimum execution time: 70_167_000 picoseconds. + Weight::from_parts(68_024_084, 6248) + // Standard Error: 14_256 + .saturating_add(Weight::from_parts(4_195_757, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) @@ -1024,6 +1058,8 @@ impl WeightInfo for () { } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) @@ -1038,11 +1074,11 @@ impl WeightInfo for () { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `1650` + // Measured: `1816` // Estimated: `6248` - // Minimum execution time: 52_862_000 picoseconds. - Weight::from_parts(54_108_000, 6248) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Minimum execution time: 61_730_000 picoseconds. + Weight::from_parts(63_430_000, 6248) + .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: `Staking::Ledger` (r:1 w:0) @@ -1055,37 +1091,37 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `902` // Estimated: `4556` - // Minimum execution time: 16_350_000 picoseconds. - Weight::from_parts(16_802_000, 4556) + // Minimum execution time: 20_857_000 picoseconds. + Weight::from_parts(21_615_000, 4556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::Payee` (r:1 w:1) - /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Payee` (r:1 w:1) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn update_payee() -> Weight { // Proof Size summary in bytes: // Measured: `969` // Estimated: `4556` - // Minimum execution time: 19_981_000 picoseconds. - Weight::from_parts(20_539_000, 4556) + // Minimum execution time: 24_739_000 picoseconds. + Weight::from_parts(25_785_000, 4556) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:1 w:2) + /// Storage: `Staking::Ledger` (r:2 w:2) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) fn set_controller() -> Weight { // Proof Size summary in bytes: // Measured: `902` - // Estimated: `4556` - // Minimum execution time: 19_304_000 picoseconds. - Weight::from_parts(20_000_000, 4556) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Estimated: `8122` + // Minimum execution time: 24_622_000 picoseconds. + Weight::from_parts(25_220_000, 8122) + .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Staking::ValidatorCount` (r:0 w:1) @@ -1094,8 +1130,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_568_000 picoseconds. - Weight::from_parts(2_708_000, 0) + // Minimum execution time: 2_634_000 picoseconds. + Weight::from_parts(2_842_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1104,8 +1140,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_950_000 picoseconds. - Weight::from_parts(8_348_000, 0) + // Minimum execution time: 8_496_000 picoseconds. + Weight::from_parts(9_016_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1114,8 +1150,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_967_000 picoseconds. - Weight::from_parts(8_222_000, 0) + // Minimum execution time: 8_510_000 picoseconds. + Weight::from_parts(8_893_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1124,8 +1160,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_006_000 picoseconds. - Weight::from_parts(8_440_000, 0) + // Minimum execution time: 8_243_000 picoseconds. + Weight::from_parts(8_678_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::Invulnerables` (r:0 w:1) @@ -1135,30 +1171,30 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_524_000 picoseconds. - Weight::from_parts(3_123_608, 0) - // Standard Error: 59 - .saturating_add(Weight::from_parts(11_596, 0).saturating_mul(v.into())) + // Minimum execution time: 2_781_000 picoseconds. + Weight::from_parts(3_441_708, 0) + // Standard Error: 58 + .saturating_add(Weight::from_parts(11_811, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Staking::Ledger` (r:5900 w:11800) + /// Storage: `Staking::Ledger` (r:11800 w:11800) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:5900 w:5900) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:5900 w:0) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:0 w:5900) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 5900]`. fn deprecate_controller_batch(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1356 + i * (151 ±0)` - // Estimated: `990 + i * (3566 ±0)` - // Minimum execution time: 2_092_000 picoseconds. - Weight::from_parts(2_258_000, 990) - // Standard Error: 32_695 - .saturating_add(Weight::from_parts(16_669_219, 0).saturating_mul(i.into())) - .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(i.into()))) + // Measured: `1746 + i * (229 ±0)` + // Estimated: `990 + i * (7132 ±0)` + // Minimum execution time: 5_331_000 picoseconds. + Weight::from_parts(5_511_000, 990) + // Standard Error: 66_734 + .saturating_add(Weight::from_parts(31_157_413, 0).saturating_mul(i.into())) + .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(i.into()))) - .saturating_add(Weight::from_parts(0, 3566).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(0, 7132).saturating_mul(i.into())) } /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -1193,10 +1229,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 84_275_000 picoseconds. - Weight::from_parts(92_512_416, 6248) - // Standard Error: 3_633 - .saturating_add(Weight::from_parts(1_315_923, 0).saturating_mul(s.into())) + // Minimum execution time: 89_473_000 picoseconds. + Weight::from_parts(98_055_990, 6248) + // Standard Error: 4_159 + .saturating_add(Weight::from_parts(1_398_203, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -1209,10 +1245,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `66672` // Estimated: `70137` - // Minimum execution time: 101_707_000 picoseconds. - Weight::from_parts(912_819_462, 70137) - // Standard Error: 57_547 - .saturating_add(Weight::from_parts(4_856_799, 0).saturating_mul(s.into())) + // Minimum execution time: 102_480_000 picoseconds. + Weight::from_parts(1_165_789_820, 70137) + // Standard Error: 77_157 + .saturating_add(Weight::from_parts(6_489_253, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1249,10 +1285,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `33297 + n * (377 ±0)` // Estimated: `30944 + n * (3774 ±0)` - // Minimum execution time: 138_657_000 picoseconds. - Weight::from_parts(167_173_445, 30944) - // Standard Error: 25_130 - .saturating_add(Weight::from_parts(44_566_012, 0).saturating_mul(n.into())) + // Minimum execution time: 156_890_000 picoseconds. + Weight::from_parts(202_972_688, 30944) + // Standard Error: 29_972 + .saturating_add(Weight::from_parts(48_226_698, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(14_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -1276,10 +1312,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1991 + l * (7 ±0)` // Estimated: `8877` - // Minimum execution time: 80_061_000 picoseconds. - Weight::from_parts(82_836_434, 8877) - // Standard Error: 4_348 - .saturating_add(Weight::from_parts(75_744, 0).saturating_mul(l.into())) + // Minimum execution time: 88_482_000 picoseconds. + Weight::from_parts(92_616_600, 8877) + // Standard Error: 4_411 + .saturating_add(Weight::from_parts(117_722, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -1314,10 +1350,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 92_560_000 picoseconds. - Weight::from_parts(97_684_741, 6248) - // Standard Error: 3_361 - .saturating_add(Weight::from_parts(1_292_732, 0).saturating_mul(s.into())) + // Minimum execution time: 98_489_000 picoseconds. + Weight::from_parts(102_968_643, 6248) + // Standard Error: 4_823 + .saturating_add(Weight::from_parts(1_420_838, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(11_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -1363,12 +1399,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0 + n * (720 ±0) + v * (3598 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 564_963_000 picoseconds. - Weight::from_parts(569_206_000, 512390) - // Standard Error: 2_033_235 - .saturating_add(Weight::from_parts(68_025_841, 0).saturating_mul(v.into())) - // Standard Error: 202_600 - .saturating_add(Weight::from_parts(17_916_770, 0).saturating_mul(n.into())) + // Minimum execution time: 604_820_000 picoseconds. + Weight::from_parts(608_838_000, 512390) + // Standard Error: 2_300_345 + .saturating_add(Weight::from_parts(72_980_573, 0).saturating_mul(v.into())) + // Standard Error: 229_216 + .saturating_add(Weight::from_parts(20_739_416, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(206_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -1399,12 +1435,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3175 + n * (911 ±0) + v * (395 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 32_196_540_000 picoseconds. - Weight::from_parts(32_341_871_000, 512390) - // Standard Error: 354_657 - .saturating_add(Weight::from_parts(5_143_440, 0).saturating_mul(v.into())) - // Standard Error: 354_657 - .saturating_add(Weight::from_parts(3_328_189, 0).saturating_mul(n.into())) + // Minimum execution time: 37_380_439_000 picoseconds. + Weight::from_parts(38_187_734_000, 512390) + // Standard Error: 425_319 + .saturating_add(Weight::from_parts(6_001_288, 0).saturating_mul(v.into())) + // Standard Error: 425_319 + .saturating_add(Weight::from_parts(4_129_446, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(201_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -1421,10 +1457,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `979 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_381_903_000 picoseconds. - Weight::from_parts(32_693_059, 3510) - // Standard Error: 10_000 - .saturating_add(Weight::from_parts(4_736_173, 0).saturating_mul(v.into())) + // Minimum execution time: 2_572_838_000 picoseconds. + Weight::from_parts(67_632_557, 3510) + // Standard Error: 12_028 + .saturating_add(Weight::from_parts(5_117_459, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -1435,6 +1471,8 @@ impl WeightInfo for () { /// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxValidatorsCount` (r:0 w:1) /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::MaxStakedRewards` (r:0 w:1) + /// Proof: `Staking::MaxStakedRewards` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::ChillThreshold` (r:0 w:1) /// Proof: `Staking::ChillThreshold` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxNominatorsCount` (r:0 w:1) @@ -1445,9 +1483,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_434_000 picoseconds. - Weight::from_parts(5_742_000, 0) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + // Minimum execution time: 5_962_000 picoseconds. + Weight::from_parts(6_497_000, 0) + .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `Staking::MinCommission` (r:0 w:1) /// Proof: `Staking::MinCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -1455,6 +1493,8 @@ impl WeightInfo for () { /// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxValidatorsCount` (r:0 w:1) /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::MaxStakedRewards` (r:0 w:1) + /// Proof: `Staking::MaxStakedRewards` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::ChillThreshold` (r:0 w:1) /// Proof: `Staking::ChillThreshold` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxNominatorsCount` (r:0 w:1) @@ -1465,9 +1505,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_588_000 picoseconds. - Weight::from_parts(4_854_000, 0) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + // Minimum execution time: 5_227_000 picoseconds. + Weight::from_parts(5_496_000, 0) + .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) @@ -1495,8 +1535,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1939` // Estimated: `6248` - // Minimum execution time: 68_780_000 picoseconds. - Weight::from_parts(71_479_000, 6248) + // Minimum execution time: 75_129_000 picoseconds. + Weight::from_parts(77_498_000, 6248) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1508,8 +1548,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `691` // Estimated: `3510` - // Minimum execution time: 12_268_000 picoseconds. - Weight::from_parts(12_661_000, 3510) + // Minimum execution time: 13_488_000 picoseconds. + Weight::from_parts(14_183_000, 3510) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1519,8 +1559,27 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_071_000 picoseconds. - Weight::from_parts(3_334_000, 0) + // Minimum execution time: 3_368_000 picoseconds. + Weight::from_parts(3_582_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:1) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + fn restore_ledger() -> Weight { + // Proof Size summary in bytes: + // Measured: `1047` + // Estimated: `4764` + // Minimum execution time: 44_876_000 picoseconds. + Weight::from_parts(46_353_000, 4764) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } } diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 1997d8fc223..24e7e1c8a65 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -22,8 +22,8 @@ pub mod tokens; pub use tokens::{ currency::{ - ActiveIssuanceOf, Currency, LockIdentifier, LockableCurrency, NamedReservableCurrency, - ReservableCurrency, TotalIssuanceOf, VestingSchedule, + ActiveIssuanceOf, Currency, InspectLockableCurrency, LockIdentifier, LockableCurrency, + NamedReservableCurrency, ReservableCurrency, TotalIssuanceOf, VestingSchedule, }, fungible, fungibles, imbalance::{Imbalance, OnUnbalanced, SignedImbalance}, diff --git a/substrate/frame/support/src/traits/tokens/currency.rs b/substrate/frame/support/src/traits/tokens/currency.rs index 8b773115011..282e7f64473 100644 --- a/substrate/frame/support/src/traits/tokens/currency.rs +++ b/substrate/frame/support/src/traits/tokens/currency.rs @@ -27,7 +27,7 @@ use sp_runtime::{traits::MaybeSerializeDeserialize, DispatchError}; mod reservable; pub use reservable::{NamedReservableCurrency, ReservableCurrency}; mod lockable; -pub use lockable::{LockIdentifier, LockableCurrency, VestingSchedule}; +pub use lockable::{InspectLockableCurrency, LockIdentifier, LockableCurrency, VestingSchedule}; /// Abstraction over a fungible assets system. pub trait Currency { diff --git a/substrate/frame/support/src/traits/tokens/currency/lockable.rs b/substrate/frame/support/src/traits/tokens/currency/lockable.rs index 955814f5aa9..51a48dd15ce 100644 --- a/substrate/frame/support/src/traits/tokens/currency/lockable.rs +++ b/substrate/frame/support/src/traits/tokens/currency/lockable.rs @@ -64,6 +64,12 @@ pub trait LockableCurrency: Currency { fn remove_lock(id: LockIdentifier, who: &AccountId); } +/// A inspect interface for a currency whose accounts can have liquidity restrictions. +pub trait InspectLockableCurrency: LockableCurrency { + /// Amount of funds locked for `who` associated with `id`. + fn balance_locked(id: LockIdentifier, who: &AccountId) -> Self::Balance; +} + /// A vesting schedule over a currency. This allows a particular currency to have vesting limits /// applied to it. pub trait VestingSchedule { -- GitLab From 597ea9203ad57d48b766fa7fb1fcc1d388118cb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 27 Mar 2024 23:02:37 +0000 Subject: [PATCH 112/187] pallet-scheduler: Unrequest call on failed lookup (#3849) When the scheduler fails to lookup a `call`, it should unrequest it, because it will not be required anymore. --- prdoc/pr_3849.prdoc | 13 +++++++++++++ substrate/frame/scheduler/src/lib.rs | 11 +++++++++++ substrate/frame/scheduler/src/tests.rs | 4 ++++ 3 files changed, 28 insertions(+) create mode 100644 prdoc/pr_3849.prdoc diff --git a/prdoc/pr_3849.prdoc b/prdoc/pr_3849.prdoc new file mode 100644 index 00000000000..a1372b60ffc --- /dev/null +++ b/prdoc/pr_3849.prdoc @@ -0,0 +1,13 @@ +title: Unrequest a pre-image when it failed to execute + +doc: + - audience: Runtime User + description: | + When a referenda finished the proposal will be scheduled. When it is scheduled, + the pre-image is requested. The pre-image is unrequested after the proposal + was executed. However, if the proposal failed to execute it wasn't unrequested. + Thus, it could not be removed from the on-chain state. This issue is now solved + by ensuring to unrequest the pre-image when it failed to execute. + +crates: + - name: pallet-scheduler diff --git a/substrate/frame/scheduler/src/lib.rs b/substrate/frame/scheduler/src/lib.rs index 62417b8d2cc..a53742679e0 100644 --- a/substrate/frame/scheduler/src/lib.rs +++ b/substrate/frame/scheduler/src/lib.rs @@ -1267,6 +1267,17 @@ impl Pallet { id: task.maybe_id, }); + // It was not available when we needed it, so we don't need to have requested it + // anymore. + T::Preimages::drop(&task.call); + + // We don't know why `peek` failed, thus we most account here for the "full weight". + let _ = weight.try_consume(T::WeightInfo::service_task( + task.call.lookup_len().map(|x| x as usize), + task.maybe_id.is_some(), + task.maybe_periodic.is_some(), + )); + return Err((Unavailable, Some(task))) }, }; diff --git a/substrate/frame/scheduler/src/tests.rs b/substrate/frame/scheduler/src/tests.rs index bb02320ad75..44035533639 100644 --- a/substrate/frame/scheduler/src/tests.rs +++ b/substrate/frame/scheduler/src/tests.rs @@ -3008,6 +3008,8 @@ fn unavailable_call_is_detected() { // Ensure the preimage isn't available assert!(!Preimage::have(&bound)); + // But we have requested it + assert!(Preimage::is_requested(&hash)); // Executes in block 4. run_to_block(4); @@ -3016,5 +3018,7 @@ fn unavailable_call_is_detected() { System::events().last().unwrap().event, crate::Event::CallUnavailable { task: (4, 0), id: Some(name) }.into() ); + // It should not be requested anymore. + assert!(!Preimage::is_requested(&hash)); }); } -- GitLab From 5d314eb03ed03d9030bb38b3d2e205f2f5c266ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 27 Mar 2024 23:52:50 +0000 Subject: [PATCH 113/187] pallet-referenda: Detect incorrect pre-image length (#3850) There has been a case that a referenda failed because the length given to `submit` was incorrect. The pallet can actually check the length if the pre-image already exists to ensure that these kind of issues are not happening again. --- prdoc/pr_3850.prdoc | 15 +++++++++++++++ substrate/frame/referenda/src/lib.rs | 12 ++++++++++++ substrate/frame/referenda/src/tests.rs | 16 ++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 prdoc/pr_3850.prdoc diff --git a/prdoc/pr_3850.prdoc b/prdoc/pr_3850.prdoc new file mode 100644 index 00000000000..8f7ce16076e --- /dev/null +++ b/prdoc/pr_3850.prdoc @@ -0,0 +1,15 @@ +title: Detect incorrect pre-image length when submitting a referenda + +doc: + - audience: Runtime User + description: | + When submitting a referenda the `proposal` is passed as argument. + The `proposal` is most of the time a reference to a `pre-image` and + which also contains the length of the `pre-image`. This pull request + adds some logic to check that if the `pre-image` already exists and if + it exists, it ensures that the length is passed correctly. This prevents + that the referenda can not be executed because of a mismatch of this + length. + +crates: + - name: pallet-referenda diff --git a/substrate/frame/referenda/src/lib.rs b/substrate/frame/referenda/src/lib.rs index e616056c302..fbe27e1a478 100644 --- a/substrate/frame/referenda/src/lib.rs +++ b/substrate/frame/referenda/src/lib.rs @@ -424,6 +424,8 @@ pub mod pallet { BadStatus, /// The preimage does not exist. PreimageNotExist, + /// The preimage is stored with a different length than the one provided. + PreimageStoredWithDifferentLength, } #[pallet::hooks] @@ -462,6 +464,16 @@ pub mod pallet { let proposal_origin = *proposal_origin; let who = T::SubmitOrigin::ensure_origin(origin, &proposal_origin)?; + // If the pre-image is already stored, ensure that it has the same length as given in + // `proposal`. + if let (Some(preimage_len), Some(proposal_len)) = + (proposal.lookup_hash().and_then(|h| T::Preimages::len(&h)), proposal.lookup_len()) + { + if preimage_len != proposal_len { + return Err(Error::::PreimageStoredWithDifferentLength.into()) + } + } + let track = T::Tracks::track_for(&proposal_origin).map_err(|_| Error::::NoTrack)?; let submission_deposit = Self::take_deposit(who, T::SubmissionDeposit::get())?; diff --git a/substrate/frame/referenda/src/tests.rs b/substrate/frame/referenda/src/tests.rs index 8f51136de0b..52251fcbdbe 100644 --- a/substrate/frame/referenda/src/tests.rs +++ b/substrate/frame/referenda/src/tests.rs @@ -666,3 +666,19 @@ fn clear_metadata_works() { })); }); } + +#[test] +fn detects_incorrect_len() { + ExtBuilder::default().build_and_execute(|| { + let hash = note_preimage(1); + assert_noop!( + Referenda::submit( + RuntimeOrigin::signed(1), + Box::new(RawOrigin::Root.into()), + frame_support::traits::Bounded::Lookup { hash, len: 3 }, + DispatchTime::At(1), + ), + Error::::PreimageStoredWithDifferentLength + ); + }); +} -- GitLab From daf04f01823a64dc734c79344314e378e9588546 Mon Sep 17 00:00:00 2001 From: Tin Chung <56880684+chungquantin@users.noreply.github.com> Date: Thu, 28 Mar 2024 14:56:23 +0700 Subject: [PATCH 114/187] Deprecate scheduler traits v1 and v2 (#3718) This PR add `#[deprecated]` attribute to v1 and v2 of the schedule trait. Proposed in this issue: https://github.com/paritytech/polkadot-sdk/issues/3676 ```rust #[allow(deprecated)] #[deprecated = "traits::schedule::v1 is deprecated. Please use v3 instead."] pub mod v1 { ... } #[allow(deprecated)] #[deprecated = "traits::schedule::v2 is deprecated. Please use v3 instead."] pub mod v2 { ... } ``` polkadot address: 19nSqFQorfF2HxD3oBzWM3oCh4SaCRKWt1yvmgaPYGCo71J --------- Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Liam Aharon --- prdoc/pr_3718.prdoc | 13 +++++++++++++ substrate/frame/scheduler/src/lib.rs | 3 +++ substrate/frame/support/src/traits/schedule.rs | 18 ++++++++++++++++-- 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 prdoc/pr_3718.prdoc diff --git a/prdoc/pr_3718.prdoc b/prdoc/pr_3718.prdoc new file mode 100644 index 00000000000..b2b24cc9704 --- /dev/null +++ b/prdoc/pr_3718.prdoc @@ -0,0 +1,13 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Deprecate scheduler traits v1 and v2 + +doc: + - audience: Runtime Dev + description: | + Add `#[deprecated]` attribute to scheduler traits v1 and v2 to deprecate old versions + +crates: + - name: frame-support + - name: pallet-scheduler diff --git a/substrate/frame/scheduler/src/lib.rs b/substrate/frame/scheduler/src/lib.rs index a53742679e0..d19a1e0001d 100644 --- a/substrate/frame/scheduler/src/lib.rs +++ b/substrate/frame/scheduler/src/lib.rs @@ -1446,6 +1446,7 @@ impl Pallet { } } +#[allow(deprecated)] impl schedule::v2::Anon, ::RuntimeCall, T::PalletsOrigin> for Pallet { @@ -1480,6 +1481,8 @@ impl schedule::v2::Anon, ::RuntimeCall } } +// TODO: migrate `schedule::v2::Anon` to `v3` +#[allow(deprecated)] impl schedule::v2::Named, ::RuntimeCall, T::PalletsOrigin> for Pallet { diff --git a/substrate/frame/support/src/traits/schedule.rs b/substrate/frame/support/src/traits/schedule.rs index 7a7d1357da1..f41c73fe69a 100644 --- a/substrate/frame/support/src/traits/schedule.rs +++ b/substrate/frame/support/src/traits/schedule.rs @@ -130,7 +130,7 @@ impl MaybeHashed { } } -// TODO: deprecate +#[deprecated(note = "Use `v3` instead. Will be removed after September 2024.")] pub mod v1 { use super::*; @@ -218,10 +218,12 @@ pub mod v1 { fn next_dispatch_time(id: Vec) -> Result; } + #[allow(deprecated)] impl Anon for T where T: v2::Anon, { + #[allow(deprecated)] type Address = T::Address; fn schedule( @@ -232,10 +234,13 @@ pub mod v1 { call: Call, ) -> Result { let c = MaybeHashed::::Value(call); + + #[allow(deprecated)] T::schedule(when, maybe_periodic, priority, origin, c) } fn cancel(address: Self::Address) -> Result<(), ()> { + #[allow(deprecated)] T::cancel(address) } @@ -243,18 +248,22 @@ pub mod v1 { address: Self::Address, when: DispatchTime, ) -> Result { + #[allow(deprecated)] T::reschedule(address, when) } fn next_dispatch_time(address: Self::Address) -> Result { + #[allow(deprecated)] T::next_dispatch_time(address) } } + #[allow(deprecated)] impl Named for T where T: v2::Named, { + #[allow(deprecated)] type Address = T::Address; fn schedule_named( @@ -266,10 +275,12 @@ pub mod v1 { call: Call, ) -> Result { let c = MaybeHashed::::Value(call); + #[allow(deprecated)] T::schedule_named(id, when, maybe_periodic, priority, origin, c) } fn cancel_named(id: Vec) -> Result<(), ()> { + #[allow(deprecated)] T::cancel_named(id) } @@ -277,16 +288,18 @@ pub mod v1 { id: Vec, when: DispatchTime, ) -> Result { + #[allow(deprecated)] T::reschedule_named(id, when) } fn next_dispatch_time(id: Vec) -> Result { + #[allow(deprecated)] T::next_dispatch_time(id) } } } -// TODO: deprecate +#[deprecated(note = "Use `v3` instead. Will be removed after September 2024.")] pub mod v2 { use super::*; @@ -478,4 +491,5 @@ pub mod v3 { } } +#[allow(deprecated)] pub use v1::*; -- GitLab From 1ed44af368cc06c67c0b58b5d8a6ae65d6c80030 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Thu, 28 Mar 2024 19:01:37 +1100 Subject: [PATCH 115/187] [prdoc] Require SemVer bump level (#3816) A prerequisite for adding a stable branch and respecting SemVer on new stable releases is including SemVer bump levels in our PRDocs. Next release is scheduled for April 3rd, so it would be great to get this merged before then. Also added "None" as a valid bump option, to support test/benchmark changes and CI to ensure changed crates have an entry. --- prdoc/schema_user.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/prdoc/schema_user.json b/prdoc/schema_user.json index 1bd0b3b93ee..593113cf326 100644 --- a/prdoc/schema_user.json +++ b/prdoc/schema_user.json @@ -132,7 +132,8 @@ } }, "required": [ - "name" + "name", + "bump" ] }, "migration_db": { @@ -187,6 +188,11 @@ "const": "patch", "title": "Patch", "description": "A bump to the third leftmost non-zero digit of the version number." + }, + { + "const": "none", + "title": "None", + "description": "This change requires no SemVer bump (e.g. change was a test or benchmark)." } ] }, -- GitLab From 60846a081fac6ddb17957606e8ff2efb1d4606ed Mon Sep 17 00:00:00 2001 From: Alessandro Siniscalchi Date: Thu, 28 Mar 2024 10:12:37 +0100 Subject: [PATCH 116/187] [parachain-template] runtime API Implementations into `mod apis` (#3817) This PR significantly refactors the runtime API implementations to improve project structure, maintainability, and readability. Key changes include: 1. **Enhancing Visibility**: Adjusts the visibility of `RUNTIME_API_VERSIONS` in `impl_runtime_apis.rs` to `pub`, making it accessible throughout the runtime module. 2. **Centralizing API Implementations**: Introduces a new file, `apis.rs`, within the parachain template's runtime directory. 3. **Streamlining `lib.rs`**: Updates the main runtime library file to reflect these structural changes. It removes redundant API implementations and points `VERSION` to the newly exposed `RUNTIME_API_VERSIONS` from `apis.rs`, simplifying the overall runtime configuration. ### Motivations Behind the Refactoring: - **Improved Project Structure**: Centralizing API implementations in `apis.rs` offers a clearer, more navigable project structure. - **Better Readability**: Streamlining `lib.rs` and reducing clutter enhance readability, making it easier for new contributors to understand the project layout and logic. ### Summary of Changes: - Made `RUNTIME_API_VERSIONS` public in `impl_runtime_apis.rs`. - Added `apis.rs` to centralize runtime API implementations. - Streamlined `lib.rs` to adjust to the refactored project structure. --- prdoc/pr_3817.prdoc | 23 ++ .../api/proc-macro/src/impl_runtime_apis.rs | 2 +- templates/parachain/node/src/service.rs | 4 +- templates/parachain/runtime/src/apis.rs | 275 ++++++++++++++++++ templates/parachain/runtime/src/lib.rs | 237 +-------------- 5 files changed, 305 insertions(+), 236 deletions(-) create mode 100644 prdoc/pr_3817.prdoc create mode 100644 templates/parachain/runtime/src/apis.rs diff --git a/prdoc/pr_3817.prdoc b/prdoc/pr_3817.prdoc new file mode 100644 index 00000000000..bf9d397122f --- /dev/null +++ b/prdoc/pr_3817.prdoc @@ -0,0 +1,23 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Parachain Runtime API Implementations into mod apis Refactoring + +doc: + - audience: Runtime Dev + description: | + This PR introduces a refactoring to the runtime API implementations within the parachain template project. The primary changes include enhancing the visibility of `RUNTIME_API_VERSIONS` to `pub` in `impl_runtime_apis.rs`, centralizing API implementations in a new `apis.rs` file, and streamlining `lib.rs`. These changes aim to improve project structure, maintainability, and readability. + + Key Changes: + - `RUNTIME_API_VERSIONS` is now publicly accessible, enhancing module-wide visibility. + - Introduction of `apis.rs` centralizes runtime API implementations, promoting a cleaner and more navigable project structure. + - The main runtime library file, `lib.rs`, has been updated to reflect these structural changes, removing redundant API implementations and simplifying runtime configuration by pointing `VERSION` to the newly exposed `RUNTIME_API_VERSIONS` from `apis.rs`. + + Motivations: + - **Improved Project Structure**: Centralizing API implementations offers a more organized and understandable project layout. + - **Enhanced Readability**: The refactoring efforts aim to declutter `lib.rs`, facilitating easier comprehension for new contributors. + +crates: + - name: sp-api-proc-macro + - name: parachain-template-node + - name: parachain-template-runtime diff --git a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs index b7e5600a017..87a381fd7bf 100644 --- a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -797,7 +797,7 @@ fn generate_runtime_api_versions(impls: &[ItemImpl]) -> Result { } Ok(quote!( - const RUNTIME_API_VERSIONS: #c::ApisVec = #c::create_apis_vec!([ #( #result ),* ]); + pub const RUNTIME_API_VERSIONS: #c::ApisVec = #c::create_apis_vec!([ #( #result ),* ]); #( #sections )* )) diff --git a/templates/parachain/node/src/service.rs b/templates/parachain/node/src/service.rs index 4dd24803e9b..bb4a5394958 100644 --- a/templates/parachain/node/src/service.rs +++ b/templates/parachain/node/src/service.rs @@ -6,8 +6,8 @@ use std::{sync::Arc, time::Duration}; use cumulus_client_cli::CollatorOptions; // Local Runtime Types use parachain_template_runtime::{ + apis::RuntimeApi, opaque::{Block, Hash}, - RuntimeApi, }; // Cumulus Imports @@ -46,7 +46,7 @@ impl sc_executor::NativeExecutionDispatch for ParachainNativeExecutor { ); fn dispatch(method: &str, data: &[u8]) -> Option> { - parachain_template_runtime::api::dispatch(method, data) + parachain_template_runtime::apis::api::dispatch(method, data) } fn native_version() -> sc_executor::NativeVersion { diff --git a/templates/parachain/runtime/src/apis.rs b/templates/parachain/runtime/src/apis.rs new file mode 100644 index 00000000000..aa0cae843c3 --- /dev/null +++ b/templates/parachain/runtime/src/apis.rs @@ -0,0 +1,275 @@ +// This is free and unencumbered software released into the public domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +// For more information, please refer to + +// External crates imports +use frame_support::{ + genesis_builder_helper::{build_config, create_default_config}, + weights::Weight, +}; +use pallet_aura::Authorities; +use sp_api::impl_runtime_apis; +use sp_consensus_aura::sr25519::AuthorityId as AuraId; +use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; +use sp_runtime::{ + traits::Block as BlockT, + transaction_validity::{TransactionSource, TransactionValidity}, + ApplyExtrinsicResult, +}; +use sp_std::prelude::Vec; +use sp_version::RuntimeVersion; + +// Local module imports +use super::{ + AccountId, Aura, Balance, Block, Executive, InherentDataExt, Nonce, ParachainSystem, Runtime, + RuntimeCall, RuntimeGenesisConfig, SessionKeys, System, TransactionPayment, VERSION, +}; + +impl_runtime_apis! { + impl sp_consensus_aura::AuraApi for Runtime { + fn slot_duration() -> sp_consensus_aura::SlotDuration { + sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration()) + } + + fn authorities() -> Vec { + Authorities::::get().into_inner() + } + } + + impl sp_api::Core for Runtime { + fn version() -> RuntimeVersion { + VERSION + } + + fn execute_block(block: Block) { + Executive::execute_block(block) + } + + fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { + Executive::initialize_block(header) + } + } + + impl sp_api::Metadata for Runtime { + fn metadata() -> OpaqueMetadata { + OpaqueMetadata::new(Runtime::metadata().into()) + } + + fn metadata_at_version(version: u32) -> Option { + Runtime::metadata_at_version(version) + } + + fn metadata_versions() -> sp_std::vec::Vec { + Runtime::metadata_versions() + } + } + + impl sp_block_builder::BlockBuilder for Runtime { + fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { + Executive::apply_extrinsic(extrinsic) + } + + fn finalize_block() -> ::Header { + Executive::finalize_block() + } + + fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<::Extrinsic> { + data.create_extrinsics() + } + + fn check_inherents( + block: Block, + data: sp_inherents::InherentData, + ) -> sp_inherents::CheckInherentsResult { + data.check_extrinsics(&block) + } + } + + impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { + fn validate_transaction( + source: TransactionSource, + tx: ::Extrinsic, + block_hash: ::Hash, + ) -> TransactionValidity { + Executive::validate_transaction(source, tx, block_hash) + } + } + + impl sp_offchain::OffchainWorkerApi for Runtime { + fn offchain_worker(header: &::Header) { + Executive::offchain_worker(header) + } + } + + impl sp_session::SessionKeys for Runtime { + fn generate_session_keys(seed: Option>) -> Vec { + SessionKeys::generate(seed) + } + + fn decode_session_keys( + encoded: Vec, + ) -> Option, KeyTypeId)>> { + SessionKeys::decode_into_raw_public_keys(&encoded) + } + } + + impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(account: AccountId) -> Nonce { + System::account_nonce(account) + } + } + + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi for Runtime { + fn query_info( + uxt: ::Extrinsic, + len: u32, + ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { + TransactionPayment::query_info(uxt, len) + } + fn query_fee_details( + uxt: ::Extrinsic, + len: u32, + ) -> pallet_transaction_payment::FeeDetails { + TransactionPayment::query_fee_details(uxt, len) + } + fn query_weight_to_fee(weight: Weight) -> Balance { + TransactionPayment::weight_to_fee(weight) + } + fn query_length_to_fee(length: u32) -> Balance { + TransactionPayment::length_to_fee(length) + } + } + + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi + for Runtime + { + fn query_call_info( + call: RuntimeCall, + len: u32, + ) -> pallet_transaction_payment::RuntimeDispatchInfo { + TransactionPayment::query_call_info(call, len) + } + fn query_call_fee_details( + call: RuntimeCall, + len: u32, + ) -> pallet_transaction_payment::FeeDetails { + TransactionPayment::query_call_fee_details(call, len) + } + fn query_weight_to_fee(weight: Weight) -> Balance { + TransactionPayment::weight_to_fee(weight) + } + fn query_length_to_fee(length: u32) -> Balance { + TransactionPayment::length_to_fee(length) + } + } + + impl cumulus_primitives_core::CollectCollationInfo for Runtime { + fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { + ParachainSystem::collect_collation_info(header) + } + } + + #[cfg(feature = "try-runtime")] + impl frame_try_runtime::TryRuntime for Runtime { + fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { + use super::RuntimeBlockWeights; + + let weight = Executive::try_runtime_upgrade(checks).unwrap(); + (weight, RuntimeBlockWeights::get().max_block) + } + + fn execute_block( + block: Block, + state_root_check: bool, + signature_check: bool, + select: frame_try_runtime::TryStateSelect, + ) -> Weight { + // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to + // have a backtrace here. + Executive::try_execute_block(block, state_root_check, signature_check, select).unwrap() + } + } + + #[cfg(feature = "runtime-benchmarks")] + impl frame_benchmarking::Benchmark for Runtime { + fn benchmark_metadata(extra: bool) -> ( + Vec, + Vec, + ) { + use frame_benchmarking::{Benchmarking, BenchmarkList}; + use frame_support::traits::StorageInfoTrait; + use frame_system_benchmarking::Pallet as SystemBench; + use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + use super::*; + + let mut list = Vec::::new(); + list_benchmarks!(list, extra); + + let storage_info = AllPalletsWithSystem::storage_info(); + (list, storage_info) + } + + fn dispatch_benchmark( + config: frame_benchmarking::BenchmarkConfig + ) -> Result, sp_runtime::RuntimeString> { + use frame_benchmarking::{BenchmarkError, Benchmarking, BenchmarkBatch}; + use super::*; + + use frame_system_benchmarking::Pallet as SystemBench; + impl frame_system_benchmarking::Config for Runtime { + fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { + ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); + Ok(()) + } + + fn verify_set_code() { + System::assert_last_event(cumulus_pallet_parachain_system::Event::::ValidationFunctionStored.into()); + } + } + + use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + impl cumulus_pallet_session_benchmarking::Config for Runtime {} + + use frame_support::traits::WhitelistedStorageKeys; + let whitelist = AllPalletsWithSystem::whitelisted_storage_keys(); + + let mut batches = Vec::::new(); + let params = (&config, &whitelist); + add_benchmarks!(params, batches); + + if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } + Ok(batches) + } + } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn create_default_config() -> Vec { + create_default_config::() + } + + fn build_config(config: Vec) -> sp_genesis_builder::Result { + build_config::(config) + } + } +} diff --git a/templates/parachain/runtime/src/lib.rs b/templates/parachain/runtime/src/lib.rs index 88b0f5a1474..5cfee123b01 100644 --- a/templates/parachain/runtime/src/lib.rs +++ b/templates/parachain/runtime/src/lib.rs @@ -6,19 +6,17 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +pub mod apis; mod weights; pub mod xcm_config; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; use smallvec::smallvec; -use sp_api::impl_runtime_apis; -use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, - traits::{BlakeTwo256, Block as BlockT, IdentifyAccount, Verify}, - transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, MultiSignature, + traits::{BlakeTwo256, IdentifyAccount, Verify}, + MultiSignature, }; use sp_std::prelude::*; @@ -30,7 +28,6 @@ use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; use frame_support::{ construct_runtime, derive_impl, dispatch::DispatchClass, - genesis_builder_helper::{build_config, create_default_config}, parameter_types, traits::{ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, TransformOrigin}, weights::{ @@ -57,8 +54,6 @@ use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; -use pallet_aura::Authorities; - // XCM Imports use xcm::latest::prelude::BodyId; @@ -187,7 +182,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { authoring_version: 1, spec_version: 1, impl_version: 0, - apis: RUNTIME_API_VERSIONS, + apis: apis::RUNTIME_API_VERSIONS, transaction_version: 1, state_version: 1, }; @@ -543,230 +538,6 @@ mod benches { ); } -impl_runtime_apis! { - impl sp_consensus_aura::AuraApi for Runtime { - fn slot_duration() -> sp_consensus_aura::SlotDuration { - sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration()) - } - - fn authorities() -> Vec { - Authorities::::get().into_inner() - } - } - - impl sp_api::Core for Runtime { - fn version() -> RuntimeVersion { - VERSION - } - - fn execute_block(block: Block) { - Executive::execute_block(block) - } - - fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { - Executive::initialize_block(header) - } - } - - impl sp_api::Metadata for Runtime { - fn metadata() -> OpaqueMetadata { - OpaqueMetadata::new(Runtime::metadata().into()) - } - - fn metadata_at_version(version: u32) -> Option { - Runtime::metadata_at_version(version) - } - - fn metadata_versions() -> sp_std::vec::Vec { - Runtime::metadata_versions() - } - } - - impl sp_block_builder::BlockBuilder for Runtime { - fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { - Executive::apply_extrinsic(extrinsic) - } - - fn finalize_block() -> ::Header { - Executive::finalize_block() - } - - fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<::Extrinsic> { - data.create_extrinsics() - } - - fn check_inherents( - block: Block, - data: sp_inherents::InherentData, - ) -> sp_inherents::CheckInherentsResult { - data.check_extrinsics(&block) - } - } - - impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { - fn validate_transaction( - source: TransactionSource, - tx: ::Extrinsic, - block_hash: ::Hash, - ) -> TransactionValidity { - Executive::validate_transaction(source, tx, block_hash) - } - } - - impl sp_offchain::OffchainWorkerApi for Runtime { - fn offchain_worker(header: &::Header) { - Executive::offchain_worker(header) - } - } - - impl sp_session::SessionKeys for Runtime { - fn generate_session_keys(seed: Option>) -> Vec { - SessionKeys::generate(seed) - } - - fn decode_session_keys( - encoded: Vec, - ) -> Option, KeyTypeId)>> { - SessionKeys::decode_into_raw_public_keys(&encoded) - } - } - - impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { - fn account_nonce(account: AccountId) -> Nonce { - System::account_nonce(account) - } - } - - impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi for Runtime { - fn query_info( - uxt: ::Extrinsic, - len: u32, - ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { - TransactionPayment::query_info(uxt, len) - } - fn query_fee_details( - uxt: ::Extrinsic, - len: u32, - ) -> pallet_transaction_payment::FeeDetails { - TransactionPayment::query_fee_details(uxt, len) - } - fn query_weight_to_fee(weight: Weight) -> Balance { - TransactionPayment::weight_to_fee(weight) - } - fn query_length_to_fee(length: u32) -> Balance { - TransactionPayment::length_to_fee(length) - } - } - - impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi - for Runtime - { - fn query_call_info( - call: RuntimeCall, - len: u32, - ) -> pallet_transaction_payment::RuntimeDispatchInfo { - TransactionPayment::query_call_info(call, len) - } - fn query_call_fee_details( - call: RuntimeCall, - len: u32, - ) -> pallet_transaction_payment::FeeDetails { - TransactionPayment::query_call_fee_details(call, len) - } - fn query_weight_to_fee(weight: Weight) -> Balance { - TransactionPayment::weight_to_fee(weight) - } - fn query_length_to_fee(length: u32) -> Balance { - TransactionPayment::length_to_fee(length) - } - } - - impl cumulus_primitives_core::CollectCollationInfo for Runtime { - fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { - ParachainSystem::collect_collation_info(header) - } - } - - #[cfg(feature = "try-runtime")] - impl frame_try_runtime::TryRuntime for Runtime { - fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { - let weight = Executive::try_runtime_upgrade(checks).unwrap(); - (weight, RuntimeBlockWeights::get().max_block) - } - - fn execute_block( - block: Block, - state_root_check: bool, - signature_check: bool, - select: frame_try_runtime::TryStateSelect, - ) -> Weight { - // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to - // have a backtrace here. - Executive::try_execute_block(block, state_root_check, signature_check, select).unwrap() - } - } - - #[cfg(feature = "runtime-benchmarks")] - impl frame_benchmarking::Benchmark for Runtime { - fn benchmark_metadata(extra: bool) -> ( - Vec, - Vec, - ) { - use frame_benchmarking::{Benchmarking, BenchmarkList}; - use frame_support::traits::StorageInfoTrait; - use frame_system_benchmarking::Pallet as SystemBench; - use cumulus_pallet_session_benchmarking::Pallet as SessionBench; - - let mut list = Vec::::new(); - list_benchmarks!(list, extra); - - let storage_info = AllPalletsWithSystem::storage_info(); - (list, storage_info) - } - - fn dispatch_benchmark( - config: frame_benchmarking::BenchmarkConfig - ) -> Result, sp_runtime::RuntimeString> { - use frame_benchmarking::{BenchmarkError, Benchmarking, BenchmarkBatch}; - - use frame_system_benchmarking::Pallet as SystemBench; - impl frame_system_benchmarking::Config for Runtime { - fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { - ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); - Ok(()) - } - - fn verify_set_code() { - System::assert_last_event(cumulus_pallet_parachain_system::Event::::ValidationFunctionStored.into()); - } - } - - use cumulus_pallet_session_benchmarking::Pallet as SessionBench; - impl cumulus_pallet_session_benchmarking::Config for Runtime {} - - use frame_support::traits::WhitelistedStorageKeys; - let whitelist = AllPalletsWithSystem::whitelisted_storage_keys(); - - let mut batches = Vec::::new(); - let params = (&config, &whitelist); - add_benchmarks!(params, batches); - - if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } - Ok(batches) - } - } - - impl sp_genesis_builder::GenesisBuilder for Runtime { - fn create_default_config() -> Vec { - create_default_config::() - } - - fn build_config(config: Vec) -> sp_genesis_builder::Result { - build_config::(config) - } - } -} - cumulus_pallet_parachain_system::register_validate_block! { Runtime = Runtime, BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, -- GitLab From 78b1cab9e8064557b2ebab9d3d039ab448aacd72 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Thu, 28 Mar 2024 11:40:06 +0100 Subject: [PATCH 117/187] Contracts: add test builders (#3796) Cleanup tests (-2.7k lines !) using some builder patterns to build pallet_contracts api calls --- Cargo.lock | 1 + substrate/frame/contracts/Cargo.toml | 1 + substrate/frame/contracts/src/tests.rs | 2729 ++++------------- .../frame/contracts/src/tests/builder.rs | 219 ++ 4 files changed, 733 insertions(+), 2217 deletions(-) create mode 100644 substrate/frame/contracts/src/tests/builder.rs diff --git a/Cargo.lock b/Cargo.lock index 2382dc8d162..8188e571fcd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9553,6 +9553,7 @@ dependencies = [ "pallet-timestamp", "pallet-utility", "parity-scale-codec", + "paste", "pretty_assertions", "rand", "rand_pcg", diff --git a/substrate/frame/contracts/Cargo.toml b/substrate/frame/contracts/Cargo.toml index be3bafcd23f..2aa37a2bf21 100644 --- a/substrate/frame/contracts/Cargo.toml +++ b/substrate/frame/contracts/Cargo.toml @@ -18,6 +18,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] +paste = { version = "1.0", default-features = false } bitflags = "1.3" codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", diff --git a/substrate/frame/contracts/src/tests.rs b/substrate/frame/contracts/src/tests.rs index ed486fc4a67..a51faa88c41 100644 --- a/substrate/frame/contracts/src/tests.rs +++ b/substrate/frame/contracts/src/tests.rs @@ -15,6 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +mod builder; mod pallet_dummy; mod test_debug; @@ -610,7 +611,7 @@ fn calling_plain_account_fails() { let base_cost = <::WeightInfo as WeightInfo>::call(); assert_eq!( - Contracts::call(RuntimeOrigin::signed(ALICE), BOB, 0, GAS_LIMIT, None, Vec::new()), + builder::call(BOB).build(), Err(DispatchErrorWithPostInfo { error: Error::::ContractNotFound.into(), post_info: PostDispatchInfo { @@ -668,32 +669,13 @@ fn migration_in_progress_works() { Contracts::set_code(RuntimeOrigin::signed(ALICE), BOB.clone(), code_hash), Error::::MigrationInProgress, ); + assert_err_ignore_postinfo!(builder::call(BOB).build(), Error::::MigrationInProgress); assert_err_ignore_postinfo!( - Contracts::call(RuntimeOrigin::signed(ALICE), BOB, 0, GAS_LIMIT, None, vec![],), + builder::instantiate_with_code(wasm).value(100_000).build(), Error::::MigrationInProgress, ); assert_err_ignore_postinfo!( - Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), - 100_000, - GAS_LIMIT, - None, - wasm, - vec![], - vec![], - ), - Error::::MigrationInProgress, - ); - assert_err_ignore_postinfo!( - Contracts::instantiate( - RuntimeOrigin::signed(ALICE), - 100_000, - GAS_LIMIT, - None, - code_hash, - vec![], - vec![], - ), + builder::instantiate(code_hash).value(100_000).build(), Error::::MigrationInProgress, ); }); @@ -721,20 +703,9 @@ fn instantiate_and_call_and_deposit_event() { initialize_block(2); // Check at the end to get hash on error easily - let addr = Contracts::bare_instantiate( - ALICE, - value, - GAS_LIMIT, - None, - Code::Existing(code_hash), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Existing(code_hash)) + .value(value) + .build_and_unwrap_account_id(); assert!(ContractInfoOf::::contains_key(&addr)); assert_eq!( @@ -812,41 +783,21 @@ fn deposit_event_max_value_limit() { ExtBuilder::default().existential_deposit(50).build().execute_with(|| { // Create let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let addr = Contracts::bare_instantiate( - ALICE, - 30_000, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm)) + .value(30_000) + .build_and_unwrap_account_id(); // Call contract with allowed storage value. - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr.clone(), - 0, - GAS_LIMIT.set_ref_time(GAS_LIMIT.ref_time() * 2), // we are copying a huge buffer, - None, - ::Schedule::get().limits.payload_len.encode(), - )); + assert_ok!(builder::call(addr.clone()) + .gas_limit(GAS_LIMIT.set_ref_time(GAS_LIMIT.ref_time() * 2)) // we are copying a huge buffer, + .data(::Schedule::get().limits.payload_len.encode()) + .build()); // Call contract with too large a storage value. assert_err_ignore_postinfo!( - Contracts::call( - RuntimeOrigin::signed(ALICE), - addr, - 0, - GAS_LIMIT, - None, - (::Schedule::get().limits.payload_len + 1).encode(), - ), + builder::call(addr) + .data((::Schedule::get().limits.payload_len + 1).encode()) + .build(), Error::::ValueTooLarge, ); }); @@ -860,32 +811,16 @@ fn run_out_of_fuel_engine() { let min_balance = Contracts::min_balance(); let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let addr = Contracts::bare_instantiate( - ALICE, - 100 * min_balance, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm)) + .value(100 * min_balance) + .build_and_unwrap_account_id(); // Call the contract with a fixed gas limit. It must run out of gas because it just // loops forever. assert_err_ignore_postinfo!( - Contracts::call( - RuntimeOrigin::signed(ALICE), - addr, // newly created account - 0, - Weight::from_parts(1_000_000_000_000, u64::MAX), - None, - vec![], - ), + builder::call(addr) + .gas_limit(Weight::from_parts(1_000_000_000_000, u64::MAX)) + .build(), Error::::OutOfGas, ); }); @@ -899,36 +834,18 @@ fn run_out_of_fuel_host() { let min_balance = Contracts::min_balance(); let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let addr = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(code), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(code)) + .value(min_balance * 100) + .build_and_unwrap_account_id(); let gas_limit = Weight::from_parts(u32::MAX as u64, GAS_LIMIT.proof_size()); // Use chain extension to charge more ref_time than it is available. - let result = Contracts::bare_call( - ALICE, - addr.clone(), - 0, - gas_limit, - None, - ExtensionInput { extension_id: 0, func_id: 2, extra: &u32::MAX.encode() }.into(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result; + let result = builder::bare_call(addr.clone()) + .gas_limit(gas_limit) + .data(ExtensionInput { extension_id: 0, func_id: 2, extra: &u32::MAX.encode() }.into()) + .build() + .result; assert_err!(result, >::OutOfGas); }); } @@ -938,63 +855,20 @@ fn gas_syncs_work() { let (code, _code_hash) = compile_module::("caller_is_origin_n").unwrap(); ExtBuilder::default().existential_deposit(200).build().execute_with(|| { let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let addr = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(code), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_account_id(); - let result = Contracts::bare_call( - ALICE, - addr.clone(), - 0, - GAS_LIMIT, - None, - 0u32.encode(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ); + let result = builder::bare_call(addr.clone()).data(0u32.encode()).build(); assert_ok!(result.result); let engine_consumed_noop = result.gas_consumed.ref_time(); - let result = Contracts::bare_call( - ALICE, - addr.clone(), - 0, - GAS_LIMIT, - None, - 1u32.encode(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ); + let result = builder::bare_call(addr.clone()).data(1u32.encode()).build(); assert_ok!(result.result); let gas_consumed_once = result.gas_consumed.ref_time(); let host_consumed_once = ::Schedule::get().host_fn_weights.caller_is_origin.ref_time(); let engine_consumed_once = gas_consumed_once - host_consumed_once - engine_consumed_noop; - let result = Contracts::bare_call( - ALICE, - addr, - 0, - GAS_LIMIT, - None, - 2u32.encode(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ); + let result = builder::bare_call(addr).data(2u32.encode()).build(); assert_ok!(result.result); let gas_consumed_twice = result.gas_consumed.ref_time(); let host_consumed_twice = host_consumed_once * 2; @@ -1018,56 +892,21 @@ fn instantiate_unique_trie_id() { .unwrap(); // Instantiate the contract and store its trie id for later comparison. - let addr = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Existing(code_hash), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = + builder::bare_instantiate(Code::Existing(code_hash)).build_and_unwrap_account_id(); let trie_id = get_contract(&addr).trie_id; // Try to instantiate it again without termination should yield an error. assert_err_ignore_postinfo!( - Contracts::instantiate( - RuntimeOrigin::signed(ALICE), - 0, - GAS_LIMIT, - None, - code_hash, - vec![], - vec![], - ), + builder::instantiate(code_hash).build(), >::DuplicateContract, ); // Terminate the contract. - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr.clone(), - 0, - GAS_LIMIT, - None, - vec![] - )); + assert_ok!(builder::call(addr.clone()).build()); // Re-Instantiate after termination. - assert_ok!(Contracts::instantiate( - RuntimeOrigin::signed(ALICE), - 0, - GAS_LIMIT, - None, - code_hash, - vec![], - vec![], - )); + assert_ok!(builder::instantiate(code_hash).build()); // Trie ids shouldn't match or we might have a collision assert_ne!(trie_id, get_contract(&addr).trie_id); @@ -1081,42 +920,22 @@ fn storage_max_value_limit() { ExtBuilder::default().existential_deposit(50).build().execute_with(|| { // Create let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let addr = Contracts::bare_instantiate( - ALICE, - 30_000, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm)) + .value(30_000) + .build_and_unwrap_account_id(); get_contract(&addr); // Call contract with allowed storage value. - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr.clone(), - 0, - GAS_LIMIT.set_ref_time(GAS_LIMIT.ref_time() * 2), // we are copying a huge buffer - None, - ::Schedule::get().limits.payload_len.encode(), - )); + assert_ok!(builder::call(addr.clone()) + .gas_limit(GAS_LIMIT.set_ref_time(GAS_LIMIT.ref_time() * 2)) // we are copying a huge buffer + .data(::Schedule::get().limits.payload_len.encode()) + .build()); // Call contract with too large a storage value. assert_err_ignore_postinfo!( - Contracts::call( - RuntimeOrigin::signed(ALICE), - addr, - 0, - GAS_LIMIT, - None, - (::Schedule::get().limits.payload_len + 1).encode(), - ), + builder::call(addr) + .data((::Schedule::get().limits.payload_len + 1).encode()) + .build(), Error::::ValueTooLarge, ); }); @@ -1132,20 +951,9 @@ fn deploy_and_call_other_contract() { // Create let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let caller_addr = Contracts::bare_instantiate( - ALICE, - 100_000, - GAS_LIMIT, - None, - Code::Upload(caller_wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let caller_addr = builder::bare_instantiate(Code::Upload(caller_wasm)) + .value(100_000) + .build_and_unwrap_account_id(); Contracts::bare_upload_code(ALICE, callee_wasm, None, Determinism::Enforced).unwrap(); let callee_addr = Contracts::contract_address( @@ -1160,14 +968,9 @@ fn deploy_and_call_other_contract() { // Call BOB contract, which attempts to instantiate and call the callee contract and // makes various assertions on the results from those calls. - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - caller_addr.clone(), - 0, - GAS_LIMIT, - None, - callee_code_hash.as_ref().to_vec(), - )); + assert_ok!(builder::call(caller_addr.clone()) + .data(callee_code_hash.as_ref().to_vec()) + .build()); assert_eq!( System::events(), @@ -1266,20 +1069,9 @@ fn delegate_call() { let _ = ::Currency::set_balance(&ALICE, 1_000_000); // Instantiate the 'caller' - let caller_addr = Contracts::bare_instantiate( - ALICE, - 300_000, - GAS_LIMIT, - None, - Code::Upload(caller_wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let caller_addr = builder::bare_instantiate(Code::Upload(caller_wasm)) + .value(300_000) + .build_and_unwrap_account_id(); // Only upload 'callee' code assert_ok!(Contracts::upload_code( RuntimeOrigin::signed(ALICE), @@ -1288,14 +1080,10 @@ fn delegate_call() { Determinism::Enforced, )); - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - caller_addr.clone(), - 1337, - GAS_LIMIT, - None, - callee_code_hash.as_ref().to_vec(), - )); + assert_ok!(builder::call(caller_addr.clone()) + .value(1337) + .data(callee_code_hash.as_ref().to_vec()) + .build()); }); } @@ -1306,20 +1094,9 @@ fn transfer_expendable_cannot_kill_account() { let _ = ::Currency::set_balance(&ALICE, 1_000_000); // Instantiate the BOB contract. - let addr = Contracts::bare_instantiate( - ALICE, - 1_000, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm)) + .value(1_000) + .build_and_unwrap_account_id(); // Check that the BOB contract has been instantiated. get_contract(&addr); @@ -1355,34 +1132,16 @@ fn cannot_self_destruct_through_draining() { let min_balance = Contracts::min_balance(); // Instantiate the BOB contract. - let addr = Contracts::bare_instantiate( - ALICE, - value, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm)) + .value(value) + .build_and_unwrap_account_id(); // Check that the BOB contract has been instantiated. get_contract(&addr); // Call BOB which makes it send all funds to the zero address // The contract code asserts that the transfer fails with the correct error code - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr.clone(), - 0, - GAS_LIMIT, - None, - vec![] - )); + assert_ok!(builder::call(addr.clone()).build()); // Make sure the account wasn't remove by sending all free balance away. assert_eq!( @@ -1400,20 +1159,7 @@ fn cannot_self_destruct_through_storage_refund_after_price_change() { let min_balance = Contracts::min_balance(); // Instantiate the BOB contract. - let addr = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_account_id(); let info_deposit = test_utils::contract_info_storage_deposit(&addr); @@ -1423,27 +1169,13 @@ fn cannot_self_destruct_through_storage_refund_after_price_change() { assert_eq!(::Currency::total_balance(&addr), info_deposit + min_balance); // Create 100 bytes of storage with a price of per byte and a single storage item of price 2 - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr.clone(), - 0, - GAS_LIMIT, - None, - 100u32.to_le_bytes().to_vec() - )); + assert_ok!(builder::call(addr.clone()).data(100u32.to_le_bytes().to_vec()).build()); assert_eq!(get_contract(&addr).total_deposit(), info_deposit + 102); // Increase the byte price and trigger a refund. This should not have any influence because // the removal is pro rata and exactly those 100 bytes should have been removed. DEPOSIT_PER_BYTE.with(|c| *c.borrow_mut() = 500); - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr.clone(), - 0, - GAS_LIMIT, - None, - 0u32.to_le_bytes().to_vec() - )); + assert_ok!(builder::call(addr.clone()).data(0u32.to_le_bytes().to_vec()).build()); // Make sure the account wasn't removed by the refund assert_eq!( @@ -1461,20 +1193,9 @@ fn cannot_self_destruct_while_live() { let _ = ::Currency::set_balance(&ALICE, 1_000_000); // Instantiate the BOB contract. - let addr = Contracts::bare_instantiate( - ALICE, - 100_000, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm)) + .value(100_000) + .build_and_unwrap_account_id(); // Check that the BOB contract has been instantiated. get_contract(&addr); @@ -1482,14 +1203,7 @@ fn cannot_self_destruct_while_live() { // Call BOB with input data, forcing it make a recursive call to itself to // self-destruct, resulting in a trap. assert_err_ignore_postinfo!( - Contracts::call( - RuntimeOrigin::signed(ALICE), - addr.clone(), - 0, - GAS_LIMIT, - None, - vec![0], - ), + builder::call(addr.clone()).data(vec![0]).build(), Error::::ContractTrapped, ); @@ -1507,20 +1221,9 @@ fn self_destruct_works() { let min_balance = Contracts::min_balance(); // Instantiate the BOB contract. - let addr = Contracts::bare_instantiate( - ALICE, - 100_000, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm)) + .value(100_000) + .build_and_unwrap_account_id(); // Check that the BOB contract has been instantiated. let _ = get_contract(&addr); @@ -1531,10 +1234,7 @@ fn self_destruct_works() { initialize_block(2); // Call BOB without input data which triggers termination. - assert_matches!( - Contracts::call(RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, vec![],), - Ok(_) - ); + assert_matches!(builder::call(addr.clone()).build(), Ok(_)); // Check that code is still there but refcount dropped to zero. assert_refcount!(&code_hash, 0); @@ -1621,20 +1321,10 @@ fn destroy_contract_and_transfer_funds() { // This deploys the BOB contract, which in turn deploys the CHARLIE contract during // construction. - let addr_bob = Contracts::bare_instantiate( - ALICE, - 200_000, - GAS_LIMIT, - None, - Code::Upload(caller_wasm), - callee_code_hash.as_ref().to_vec(), - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr_bob = builder::bare_instantiate(Code::Upload(caller_wasm)) + .value(200_000) + .data(callee_code_hash.as_ref().to_vec()) + .build_and_unwrap_account_id(); // Check that the CHARLIE contract has been instantiated. let addr_charlie = @@ -1642,14 +1332,7 @@ fn destroy_contract_and_transfer_funds() { get_contract(&addr_charlie); // Call BOB, which calls CHARLIE, forcing CHARLIE to self-destruct. - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr_bob, - 0, - GAS_LIMIT, - None, - addr_charlie.encode(), - )); + assert_ok!(builder::call(addr_bob).data(addr_charlie.encode()).build()); // Check that CHARLIE has moved on to the great beyond (ie. died). assert!(get_contract_checked(&addr_charlie).is_none()); @@ -1664,15 +1347,7 @@ fn cannot_self_destruct_in_constructor() { // Fail to instantiate the BOB because the constructor calls seal_terminate. assert_err_ignore_postinfo!( - Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), - 100_000, - GAS_LIMIT, - None, - wasm, - vec![], - vec![], - ), + builder::instantiate_with_code(wasm).value(100_000).build(), Error::::TerminatedInConstructor, ); }); @@ -1686,20 +1361,9 @@ fn crypto_hashes() { let _ = ::Currency::set_balance(&ALICE, 1_000_000); // Instantiate the CRYPTO_HASHES contract. - let addr = Contracts::bare_instantiate( - ALICE, - 100_000, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm)) + .value(100_000) + .build_and_unwrap_account_id(); // Perform the call. let input = b"_DEAD_BEEF"; use sp_io::hashing::*; @@ -1748,36 +1412,13 @@ fn transfer_return_code() { let min_balance = Contracts::min_balance(); let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let addr = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm)) + .value(min_balance * 100) + .build_and_unwrap_account_id(); // Contract has only the minimal balance so any transfer will fail. ::Currency::set_balance(&addr, min_balance); - let result = Contracts::bare_call( - ALICE, - addr.clone(), - 0, - GAS_LIMIT, - None, - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result - .unwrap(); + let result = builder::bare_call(addr.clone()).build_and_unwrap_result(); assert_return_code!(result, RuntimeReturnCode::TransferFailed); }); } @@ -1791,113 +1432,60 @@ fn call_return_code() { let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); let _ = ::Currency::set_balance(&CHARLIE, 1000 * min_balance); - let addr_bob = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(caller_code), - vec![0], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr_bob = builder::bare_instantiate(Code::Upload(caller_code)) + .value(min_balance * 100) + .data(vec![0]) + .build_and_unwrap_account_id(); ::Currency::set_balance(&addr_bob, min_balance); // Contract calls into Django which is no valid contract - let result = Contracts::bare_call( - ALICE, - addr_bob.clone(), - 0, - GAS_LIMIT, - None, - AsRef::<[u8]>::as_ref(&DJANGO).to_vec(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result - .unwrap(); + let result = builder::bare_call(addr_bob.clone()) + .data(AsRef::<[u8]>::as_ref(&DJANGO).to_vec()) + .build_and_unwrap_result(); assert_return_code!(result, RuntimeReturnCode::NotCallable); - let addr_django = Contracts::bare_instantiate( - CHARLIE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(callee_code), - vec![0], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr_django = builder::bare_instantiate(Code::Upload(callee_code)) + .origin(CHARLIE) + .value(min_balance * 100) + .data(vec![0]) + .build_and_unwrap_account_id(); ::Currency::set_balance(&addr_django, min_balance); // Contract has only the minimal balance so any transfer will fail. - let result = Contracts::bare_call( - ALICE, - addr_bob.clone(), - 0, - GAS_LIMIT, - None, - AsRef::<[u8]>::as_ref(&addr_django) - .iter() - .chain(&0u32.to_le_bytes()) - .cloned() - .collect(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result - .unwrap(); + let result = builder::bare_call(addr_bob.clone()) + .data( + AsRef::<[u8]>::as_ref(&addr_django) + .iter() + .chain(&0u32.to_le_bytes()) + .cloned() + .collect(), + ) + .build_and_unwrap_result(); assert_return_code!(result, RuntimeReturnCode::TransferFailed); // Contract has enough balance but callee reverts because "1" is passed. ::Currency::set_balance(&addr_bob, min_balance + 1000); - let result = Contracts::bare_call( - ALICE, - addr_bob.clone(), - 0, - GAS_LIMIT, - None, - AsRef::<[u8]>::as_ref(&addr_django) - .iter() - .chain(&1u32.to_le_bytes()) - .cloned() - .collect(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result - .unwrap(); + let result = builder::bare_call(addr_bob.clone()) + .data( + AsRef::<[u8]>::as_ref(&addr_django) + .iter() + .chain(&1u32.to_le_bytes()) + .cloned() + .collect(), + ) + .build_and_unwrap_result(); assert_return_code!(result, RuntimeReturnCode::CalleeReverted); // Contract has enough balance but callee traps because "2" is passed. - let result = Contracts::bare_call( - ALICE, - addr_bob, - 0, - GAS_LIMIT, - None, - AsRef::<[u8]>::as_ref(&addr_django) - .iter() - .chain(&2u32.to_le_bytes()) - .cloned() - .collect(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result - .unwrap(); + let result = builder::bare_call(addr_bob) + .data( + AsRef::<[u8]>::as_ref(&addr_django) + .iter() + .chain(&2u32.to_le_bytes()) + .cloned() + .collect(), + ) + .build_and_unwrap_result(); assert_return_code!(result, RuntimeReturnCode::CalleeTrapped); }); } @@ -1912,95 +1500,34 @@ fn instantiate_return_code() { let _ = ::Currency::set_balance(&CHARLIE, 1000 * min_balance); let callee_hash = callee_hash.as_ref().to_vec(); - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), - min_balance * 100, - GAS_LIMIT, - None, - callee_code, - vec![], - vec![], - )); + assert_ok!(builder::instantiate_with_code(callee_code).value(min_balance * 100).build()); - let addr = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(caller_code), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(caller_code)) + .value(min_balance * 100) + .build_and_unwrap_account_id(); // Contract has only the minimal balance so any transfer will fail. ::Currency::set_balance(&addr, min_balance); - let result = Contracts::bare_call( - ALICE, - addr.clone(), - 0, - GAS_LIMIT, - None, - callee_hash.clone(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result - .unwrap(); + let result = builder::bare_call(addr.clone()) + .data(callee_hash.clone()) + .build_and_unwrap_result(); assert_return_code!(result, RuntimeReturnCode::TransferFailed); // Contract has enough balance but the passed code hash is invalid ::Currency::set_balance(&addr, min_balance + 10_000); - let result = Contracts::bare_call( - ALICE, - addr.clone(), - 0, - GAS_LIMIT, - None, - vec![0; 33], - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result - .unwrap(); + let result = builder::bare_call(addr.clone()).data(vec![0; 33]).build_and_unwrap_result(); assert_return_code!(result, RuntimeReturnCode::CodeNotFound); // Contract has enough balance but callee reverts because "1" is passed. - let result = Contracts::bare_call( - ALICE, - addr.clone(), - 0, - GAS_LIMIT, - None, - callee_hash.iter().chain(&1u32.to_le_bytes()).cloned().collect(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result - .unwrap(); + let result = builder::bare_call(addr.clone()) + .data(callee_hash.iter().chain(&1u32.to_le_bytes()).cloned().collect()) + .build_and_unwrap_result(); assert_return_code!(result, RuntimeReturnCode::CalleeReverted); // Contract has enough balance but callee traps because "2" is passed. - let result = Contracts::bare_call( - ALICE, - addr, - 0, - GAS_LIMIT, - None, - callee_hash.iter().chain(&2u32.to_le_bytes()).cloned().collect(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result - .unwrap(); + let result = builder::bare_call(addr) + .data(callee_hash.iter().chain(&2u32.to_le_bytes()).cloned().collect()) + .build_and_unwrap_result(); assert_return_code!(result, RuntimeReturnCode::CalleeTrapped); }); } @@ -2013,15 +1540,7 @@ fn disabled_chain_extension_wont_deploy() { let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); TestExtension::disable(); assert_err_ignore_postinfo!( - Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), - 3 * min_balance, - GAS_LIMIT, - None, - code, - vec![], - vec![], - ), + builder::instantiate_with_code(code).value(3 * min_balance).build(), >::CodeRejected, ); }); @@ -2033,23 +1552,12 @@ fn disabled_chain_extension_errors_on_call() { ExtBuilder::default().existential_deposit(50).build().execute_with(|| { let min_balance = Contracts::min_balance(); let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let addr = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(code), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(code)) + .value(min_balance * 100) + .build_and_unwrap_account_id(); TestExtension::disable(); assert_err_ignore_postinfo!( - Contracts::call(RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, vec![],), + builder::call(addr.clone()).build(), Error::::CodeRejected, ); }); @@ -2061,141 +1569,61 @@ fn chain_extension_works() { ExtBuilder::default().existential_deposit(50).build().execute_with(|| { let min_balance = Contracts::min_balance(); let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let addr = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(code), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(code)) + .value(min_balance * 100) + .build_and_unwrap_account_id(); // 0 = read input buffer and pass it through as output let input: Vec = ExtensionInput { extension_id: 0, func_id: 0, extra: &[99] }.into(); - let result = Contracts::bare_call( - ALICE, - addr.clone(), - 0, - GAS_LIMIT, - None, - input.clone(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ); + let result = builder::bare_call(addr.clone()).data(input.clone()).build(); assert_eq!(TestExtension::last_seen_buffer(), input); assert_eq!(result.result.unwrap().data, input); // 1 = treat inputs as integer primitives and store the supplied integers - Contracts::bare_call( - ALICE, - addr.clone(), - 0, - GAS_LIMIT, - None, - ExtensionInput { extension_id: 0, func_id: 1, extra: &[] }.into(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result - .unwrap(); + builder::bare_call(addr.clone()) + .data(ExtensionInput { extension_id: 0, func_id: 1, extra: &[] }.into()) + .build_and_unwrap_result(); assert_eq!(TestExtension::last_seen_input_len(), 4); // 2 = charge some extra weight (amount supplied in the fifth byte) - let result = Contracts::bare_call( - ALICE, - addr.clone(), - 0, - GAS_LIMIT, - None, - ExtensionInput { extension_id: 0, func_id: 2, extra: &0u32.encode() }.into(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ); + let result = builder::bare_call(addr.clone()) + .data(ExtensionInput { extension_id: 0, func_id: 2, extra: &0u32.encode() }.into()) + .build(); assert_ok!(result.result); let gas_consumed = result.gas_consumed; - let result = Contracts::bare_call( - ALICE, - addr.clone(), - 0, - GAS_LIMIT, - None, - ExtensionInput { extension_id: 0, func_id: 2, extra: &42u32.encode() }.into(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ); + let result = builder::bare_call(addr.clone()) + .data(ExtensionInput { extension_id: 0, func_id: 2, extra: &42u32.encode() }.into()) + .build(); assert_ok!(result.result); assert_eq!(result.gas_consumed.ref_time(), gas_consumed.ref_time() + 42); - let result = Contracts::bare_call( - ALICE, - addr.clone(), - 0, - GAS_LIMIT, - None, - ExtensionInput { extension_id: 0, func_id: 2, extra: &95u32.encode() }.into(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ); + let result = builder::bare_call(addr.clone()) + .data(ExtensionInput { extension_id: 0, func_id: 2, extra: &95u32.encode() }.into()) + .build(); assert_ok!(result.result); assert_eq!(result.gas_consumed.ref_time(), gas_consumed.ref_time() + 95); // 3 = diverging chain extension call that sets flags to 0x1 and returns a fixed buffer - let result = Contracts::bare_call( - ALICE, - addr.clone(), - 0, - GAS_LIMIT, - None, - ExtensionInput { extension_id: 0, func_id: 3, extra: &[] }.into(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result - .unwrap(); + let result = builder::bare_call(addr.clone()) + .data(ExtensionInput { extension_id: 0, func_id: 3, extra: &[] }.into()) + .build_and_unwrap_result(); assert_eq!(result.flags, ReturnFlags::REVERT); assert_eq!(result.data, vec![42, 99]); // diverging to second chain extension that sets flags to 0x1 and returns a fixed buffer // We set the MSB part to 1 (instead of 0) which routes the request into the second // extension - let result = Contracts::bare_call( - ALICE, - addr.clone(), - 0, - GAS_LIMIT, - None, - ExtensionInput { extension_id: 1, func_id: 0, extra: &[] }.into(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result - .unwrap(); + let result = builder::bare_call(addr.clone()) + .data(ExtensionInput { extension_id: 1, func_id: 0, extra: &[] }.into()) + .build_and_unwrap_result(); assert_eq!(result.flags, ReturnFlags::REVERT); assert_eq!(result.data, vec![0x4B, 0x1D]); // Diverging to third chain extension that is disabled // We set the MSB part to 2 (instead of 0) which routes the request into the third extension assert_err_ignore_postinfo!( - Contracts::call( - RuntimeOrigin::signed(ALICE), - addr.clone(), - 0, - GAS_LIMIT, - None, - ExtensionInput { extension_id: 2, func_id: 0, extra: &[] }.into(), - ), + builder::call(addr.clone()) + .data(ExtensionInput { extension_id: 2, func_id: 0, extra: &[] }.into()) + .build(), Error::::NoChainExtension, ); }); @@ -2207,20 +1635,9 @@ fn chain_extension_temp_storage_works() { ExtBuilder::default().existential_deposit(50).build().execute_with(|| { let min_balance = Contracts::min_balance(); let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let addr = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(code), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(code)) + .value(min_balance * 100) + .build_and_unwrap_account_id(); // Call func 0 and func 1 back to back. let stop_recursion = 0u8; @@ -2231,20 +1648,7 @@ fn chain_extension_temp_storage_works() { .as_ref(), ); - assert_ok!( - Contracts::bare_call( - ALICE, - addr.clone(), - 0, - GAS_LIMIT, - None, - input.clone(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result - ); + assert_ok!(builder::bare_call(addr.clone()).data(input.clone()).build().result); }) } @@ -2255,20 +1659,9 @@ fn lazy_removal_works() { let min_balance = Contracts::min_balance(); let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let addr = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(code), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(code)) + .value(min_balance * 100) + .build_and_unwrap_account_id(); let info = get_contract(&addr); let trie = &info.child_trie_info(); @@ -2277,14 +1670,7 @@ fn lazy_removal_works() { child::put(trie, &[99], &42); // Terminate the contract - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr.clone(), - 0, - GAS_LIMIT, - None, - vec![] - )); + assert_ok!(builder::call(addr.clone()).build()); // Contract info should be gone assert!(!>::contains_key(&addr)); @@ -2309,20 +1695,10 @@ fn lazy_batch_removal_works() { let mut tries: Vec = vec![]; for i in 0..3u8 { - let addr = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(code.clone()), - vec![], - vec![i], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(code.clone())) + .value(min_balance * 100) + .salt(vec![i]) + .build_and_unwrap_account_id(); let info = get_contract(&addr); let trie = &info.child_trie_info(); @@ -2332,14 +1708,7 @@ fn lazy_batch_removal_works() { // Terminate the contract. Contract info should be gone, but value should be still there // as the lazy removal did not run, yet. - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr.clone(), - 0, - GAS_LIMIT, - None, - vec![] - )); + assert_ok!(builder::call(addr.clone()).build()); assert!(!>::contains_key(&addr)); assert_matches!(child::get(trie, &[99]), Some(42)); @@ -2375,20 +1744,9 @@ fn lazy_removal_partial_remove_works() { let min_balance = Contracts::min_balance(); let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let addr = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(code), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(code)) + .value(min_balance * 100) + .build_and_unwrap_account_id(); let info = get_contract(&addr); @@ -2399,14 +1757,7 @@ fn lazy_removal_partial_remove_works() { >::insert(&addr, info.clone()); // Terminate the contract - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr.clone(), - 0, - GAS_LIMIT, - None, - vec![] - )); + assert_ok!(builder::call(addr.clone()).build()); // Contract info should be gone assert!(!>::contains_key(&addr)); @@ -2457,20 +1808,9 @@ fn lazy_removal_does_no_run_on_low_remaining_weight() { let min_balance = Contracts::min_balance(); let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let addr = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(code), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(code)) + .value(min_balance * 100) + .build_and_unwrap_account_id(); let info = get_contract(&addr); let trie = &info.child_trie_info(); @@ -2479,14 +1819,7 @@ fn lazy_removal_does_no_run_on_low_remaining_weight() { child::put(trie, &[99], &42); // Terminate the contract - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr.clone(), - 0, - GAS_LIMIT, - None, - vec![] - )); + assert_ok!(builder::call(addr.clone()).build()); // Contract info should be gone assert!(!>::contains_key(&addr)); @@ -2529,20 +1862,9 @@ fn lazy_removal_does_not_use_all_weight() { let min_balance = Contracts::min_balance(); let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let addr = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(code), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(code)) + .value(min_balance * 100) + .build_and_unwrap_account_id(); let info = get_contract(&addr); let (weight_per_key, max_keys) = ContractInfo::::deletion_budget(weight_limit); @@ -2559,14 +1881,7 @@ fn lazy_removal_does_not_use_all_weight() { >::insert(&addr, info.clone()); // Terminate the contract - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr.clone(), - 0, - GAS_LIMIT, - None, - vec![] - )); + assert_ok!(builder::call(addr.clone()).build()); // Contract info should be gone assert!(!>::contains_key(&addr)); @@ -2620,20 +1935,10 @@ fn deletion_queue_ring_buffer_overflow() { // add 3 contracts to the deletion queue for i in 0..3u8 { - let addr = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(code.clone()), - vec![], - vec![i], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(code.clone())) + .value(min_balance * 100) + .salt(vec![i]) + .build_and_unwrap_account_id(); let info = get_contract(&addr); let trie = &info.child_trie_info(); @@ -2643,14 +1948,7 @@ fn deletion_queue_ring_buffer_overflow() { // Terminate the contract. Contract info should be gone, but value should be still // there as the lazy removal did not run, yet. - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr.clone(), - 0, - GAS_LIMIT, - None, - vec![] - )); + assert_ok!(builder::call(addr.clone()).build()); assert!(!>::contains_key(&addr)); assert_matches!(child::get(trie, &[99]), Some(42)); @@ -2678,87 +1976,36 @@ fn refcounter() { let min_balance = Contracts::min_balance(); // Create two contracts with the same code and check that they do in fact share it. - let addr0 = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(wasm.clone()), - vec![], - vec![0], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; - let addr1 = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(wasm.clone()), - vec![], - vec![1], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr0 = builder::bare_instantiate(Code::Upload(wasm.clone())) + .value(min_balance * 100) + .salt(vec![0]) + .build_and_unwrap_account_id(); + let addr1 = builder::bare_instantiate(Code::Upload(wasm.clone())) + .value(min_balance * 100) + .salt(vec![1]) + .build_and_unwrap_account_id(); assert_refcount!(code_hash, 2); // Sharing should also work with the usual instantiate call - let addr2 = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Existing(code_hash), - vec![], - vec![2], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr2 = builder::bare_instantiate(Code::Existing(code_hash)) + .value(min_balance * 100) + .salt(vec![2]) + .build_and_unwrap_account_id(); assert_refcount!(code_hash, 3); - - // Terminating one contract should decrement the refcount - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr0, - 0, - GAS_LIMIT, - None, - vec![] - )); + + // Terminating one contract should decrement the refcount + assert_ok!(builder::call(addr0).build()); assert_refcount!(code_hash, 2); // remove another one - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr1, - 0, - GAS_LIMIT, - None, - vec![] - )); + assert_ok!(builder::call(addr1).build()); assert_refcount!(code_hash, 1); // Pristine code should still be there PristineCode::::get(code_hash).unwrap(); // remove the last contract - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr2, - 0, - GAS_LIMIT, - None, - vec![] - )); + assert_ok!(builder::call(addr2).build()); assert_refcount!(code_hash, 0); // refcount is `0` but code should still exists because it needs to be removed manually @@ -2772,31 +2019,10 @@ fn debug_message_works() { ExtBuilder::default().existential_deposit(50).build().execute_with(|| { let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let addr = Contracts::bare_instantiate( - ALICE, - 30_000, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; - let result = Contracts::bare_call( - ALICE, - addr, - 0, - GAS_LIMIT, - None, - vec![], - DebugInfo::UnsafeDebug, - CollectEvents::Skip, - Determinism::Enforced, - ); + let addr = builder::bare_instantiate(Code::Upload(wasm)) + .value(30_000) + .build_and_unwrap_account_id(); + let result = builder::bare_call(addr).debug(DebugInfo::UnsafeDebug).build(); assert_matches!(result.result, Ok(_)); assert_eq!(std::str::from_utf8(&result.debug_message).unwrap(), "Hello World!"); @@ -2809,32 +2035,11 @@ fn debug_message_logging_disabled() { ExtBuilder::default().existential_deposit(50).build().execute_with(|| { let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let addr = Contracts::bare_instantiate( - ALICE, - 30_000, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm)) + .value(30_000) + .build_and_unwrap_account_id(); // disable logging by passing `false` - let result = Contracts::bare_call( - ALICE, - addr.clone(), - 0, - GAS_LIMIT, - None, - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ); + let result = builder::bare_call(addr.clone()).build(); assert_matches!(result.result, Ok(_)); // the dispatchables always run without debugging assert_ok!(Contracts::call(RuntimeOrigin::signed(ALICE), addr, 0, GAS_LIMIT, None, vec![])); @@ -2848,31 +2053,10 @@ fn debug_message_invalid_utf8() { ExtBuilder::default().existential_deposit(50).build().execute_with(|| { let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let addr = Contracts::bare_instantiate( - ALICE, - 30_000, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; - let result = Contracts::bare_call( - ALICE, - addr, - 0, - GAS_LIMIT, - None, - vec![], - DebugInfo::UnsafeDebug, - CollectEvents::Skip, - Determinism::Enforced, - ); + let addr = builder::bare_instantiate(Code::Upload(wasm)) + .value(30_000) + .build_and_unwrap_account_id(); + let result = builder::bare_call(addr).debug(DebugInfo::UnsafeDebug).build(); assert_ok!(result.result); assert!(result.debug_message.is_empty()); }); @@ -2887,50 +2071,17 @@ fn gas_estimation_for_subcalls() { let min_balance = Contracts::min_balance(); let _ = ::Currency::set_balance(&ALICE, 2_000 * min_balance); - let addr_caller = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(caller_code), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr_caller = builder::bare_instantiate(Code::Upload(caller_code)) + .value(min_balance * 100) + .build_and_unwrap_account_id(); - let addr_dummy = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(dummy_code), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr_dummy = builder::bare_instantiate(Code::Upload(dummy_code)) + .value(min_balance * 100) + .build_and_unwrap_account_id(); - let addr_call_runtime = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(call_runtime_code), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr_call_runtime = builder::bare_instantiate(Code::Upload(call_runtime_code)) + .value(min_balance * 100) + .build_and_unwrap_account_id(); // Run the test for all of those weight limits for the subcall let weights = [ @@ -2966,17 +2117,7 @@ fn gas_estimation_for_subcalls() { .collect(); // Call in order to determine the gas that is required for this call - let result = Contracts::bare_call( - ALICE, - addr_caller.clone(), - 0, - GAS_LIMIT, - None, - input.clone(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ); + let result = builder::bare_call(addr_caller.clone()).data(input.clone()).build(); assert_ok!(&result.result); // If the out of gas happens in the subcall the caller contract @@ -2992,51 +2133,33 @@ fn gas_estimation_for_subcalls() { // Make the same call using the estimated gas. Should succeed. assert_ok!( - Contracts::bare_call( - ALICE, - addr_caller.clone(), - 0, - result.gas_required, - Some(result.storage_deposit.charge_or_zero()), - input.clone(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result + builder::bare_call(addr_caller.clone()) + .gas_limit(result.gas_required) + .storage_deposit_limit(Some(result.storage_deposit.charge_or_zero())) + .data(input.clone()) + .build() + .result ); // Check that it fails with too little ref_time assert_err!( - Contracts::bare_call( - ALICE, - addr_caller.clone(), - 0, - result.gas_required.sub_ref_time(1), - Some(result.storage_deposit.charge_or_zero()), - input.clone(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result, + builder::bare_call(addr_caller.clone()) + .gas_limit(result.gas_required.sub_ref_time(1)) + .storage_deposit_limit(Some(result.storage_deposit.charge_or_zero())) + .data(input.clone()) + .build() + .result, error, ); // Check that it fails with too little proof_size assert_err!( - Contracts::bare_call( - ALICE, - addr_caller.clone(), - 0, - result.gas_required.sub_proof_size(1), - Some(result.storage_deposit.charge_or_zero()), - input, - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result, + builder::bare_call(addr_caller.clone()) + .gas_limit(result.gas_required.sub_proof_size(1)) + .storage_deposit_limit(Some(result.storage_deposit.charge_or_zero())) + .data(input) + .build() + .result, error, ); } @@ -3052,20 +2175,10 @@ fn gas_estimation_call_runtime() { let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); let _ = ::Currency::set_balance(&CHARLIE, 1000 * min_balance); - let addr_caller = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(caller_code), - vec![], - vec![0], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr_caller = builder::bare_instantiate(Code::Upload(caller_code)) + .value(min_balance * 100) + .salt(vec![0]) + .build_and_unwrap_account_id(); // Call something trivial with a huge gas limit so that we can observe the effects // of pre-charging. This should create a difference between consumed and required. @@ -3073,17 +2186,7 @@ fn gas_estimation_call_runtime() { pre_charge: Weight::from_parts(10_000_000, 1_000), actual_weight: Weight::from_parts(100, 100), }); - let result = Contracts::bare_call( - ALICE, - addr_caller.clone(), - 0, - GAS_LIMIT, - None, - call.encode(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ); + let result = builder::bare_call(addr_caller.clone()).data(call.encode()).build(); // contract encodes the result of the dispatch runtime let outcome = u32::decode(&mut result.result.unwrap().data.as_ref()).unwrap(); assert_eq!(outcome, 0); @@ -3091,18 +2194,11 @@ fn gas_estimation_call_runtime() { // Make the same call using the required gas. Should succeed. assert_ok!( - Contracts::bare_call( - ALICE, - addr_caller, - 0, - result.gas_required, - None, - call.encode(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result + builder::bare_call(addr_caller) + .gas_limit(result.gas_required) + .data(call.encode()) + .build() + .result ); }); } @@ -3116,35 +2212,15 @@ fn call_runtime_reentrancy_guarded() { let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); let _ = ::Currency::set_balance(&CHARLIE, 1000 * min_balance); - let addr_caller = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(caller_code), - vec![], - vec![0], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr_caller = builder::bare_instantiate(Code::Upload(caller_code)) + .value(min_balance * 100) + .salt(vec![0]) + .build_and_unwrap_account_id(); - let addr_callee = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(callee_code), - vec![], - vec![1], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr_callee = builder::bare_instantiate(Code::Upload(callee_code)) + .value(min_balance * 100) + .salt(vec![1]) + .build_and_unwrap_account_id(); // Call pallet_contracts call() dispatchable let call = RuntimeCall::Contracts(crate::Call::call { @@ -3157,19 +2233,9 @@ fn call_runtime_reentrancy_guarded() { // Call runtime to re-enter back to contracts engine by // calling dummy contract - let result = Contracts::bare_call( - ALICE, - addr_caller.clone(), - 0, - GAS_LIMIT, - None, - call.encode(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result - .unwrap(); + let result = builder::bare_call(addr_caller.clone()) + .data(call.encode()) + .build_and_unwrap_result(); // Call to runtime should fail because of the re-entrancy guard assert_return_code!(result, RuntimeReturnCode::CallRuntimeFailed); }); @@ -3183,20 +2249,9 @@ fn ecdsa_recover() { let _ = ::Currency::set_balance(&ALICE, 1_000_000); // Instantiate the ecdsa_recover contract. - let addr = Contracts::bare_instantiate( - ALICE, - 100_000, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm)) + .value(100_000) + .build_and_unwrap_account_id(); #[rustfmt::skip] let signature: [u8; 65] = [ @@ -3246,17 +2301,10 @@ fn bare_instantiate_returns_events() { let min_balance = Contracts::min_balance(); let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let result = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::UnsafeCollect, - ); + let result = builder::bare_instantiate(Code::Upload(wasm)) + .value(min_balance * 100) + .collect_events(CollectEvents::UnsafeCollect) + .build(); let events = result.events.unwrap(); assert!(!events.is_empty()); @@ -3271,17 +2319,7 @@ fn bare_instantiate_does_not_return_events() { let min_balance = Contracts::min_balance(); let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let result = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ); + let result = builder::bare_instantiate(Code::Upload(wasm)).value(min_balance * 100).build(); let events = result.events; assert!(!System::events().is_empty()); @@ -3296,32 +2334,13 @@ fn bare_call_returns_events() { let min_balance = Contracts::min_balance(); let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let addr = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm)) + .value(min_balance * 100) + .build_and_unwrap_account_id(); - let result = Contracts::bare_call( - ALICE, - addr.clone(), - 0, - GAS_LIMIT, - None, - vec![], - DebugInfo::Skip, - CollectEvents::UnsafeCollect, - Determinism::Enforced, - ); + let result = builder::bare_call(addr.clone()) + .collect_events(CollectEvents::UnsafeCollect) + .build(); let events = result.events.unwrap(); assert_return_code!(&result.result.unwrap(), RuntimeReturnCode::Success); @@ -3337,32 +2356,11 @@ fn bare_call_does_not_return_events() { let min_balance = Contracts::min_balance(); let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let addr = Contracts::bare_instantiate( - ALICE, - min_balance * 100, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm)) + .value(min_balance * 100) + .build_and_unwrap_account_id(); - let result = Contracts::bare_call( - ALICE, - addr.clone(), - 0, - GAS_LIMIT, - None, - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ); + let result = builder::bare_call(addr.clone()).build(); let events = result.events; assert_return_code!(&result.result.unwrap(), RuntimeReturnCode::Success); @@ -3379,20 +2377,9 @@ fn sr25519_verify() { let _ = ::Currency::set_balance(&ALICE, 1_000_000); // Instantiate the sr25519_verify contract. - let addr = Contracts::bare_instantiate( - ALICE, - 100_000, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm)) + .value(100_000) + .build_and_unwrap_account_id(); let call_with = |message: &[u8; 11]| { // Alice's signature for "hello world" @@ -3450,34 +2437,10 @@ fn failed_deposit_charge_should_roll_back_call() { let _ = ::Currency::set_balance(&ALICE, 1_000_000); // Instantiate both contracts. - let addr_caller = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(wasm_caller.clone()), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; - let addr_callee = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(wasm_callee.clone()), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr_caller = builder::bare_instantiate(Code::Upload(wasm_caller.clone())) + .build_and_unwrap_account_id(); + let addr_callee = builder::bare_instantiate(Code::Upload(wasm_callee.clone())) + .build_and_unwrap_account_id(); // Give caller proxy access to Alice. assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(ALICE), addr_caller.clone(), (), 0)); @@ -3701,15 +2664,7 @@ fn remove_code_in_use() { ExtBuilder::default().existential_deposit(100).build().execute_with(|| { let _ = ::Currency::set_balance(&ALICE, 1_000_000); - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), - 0, - GAS_LIMIT, - None, - wasm, - vec![], - vec![], - )); + assert_ok!(builder::instantiate_with_code(wasm).build()); // Drop previous events initialize_block(2); @@ -3753,20 +2708,7 @@ fn instantiate_with_zero_balance_works() { initialize_block(2); // Instantiate the BOB contract. - let addr = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_account_id(); // Ensure the contract was stored and get expected deposit amount to be reserved. let deposit_expected = expected_deposit(ensure_stored(code_hash)); @@ -3850,20 +2792,9 @@ fn instantiate_with_below_existential_deposit_works() { initialize_block(2); // Instantiate the BOB contract. - let addr = Contracts::bare_instantiate( - ALICE, - value, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm)) + .value(value) + .build_and_unwrap_account_id(); // Ensure the contract was stored and get expected deposit amount to be reserved. let deposit_expected = expected_deposit(ensure_stored(code_hash)); @@ -3949,20 +2880,7 @@ fn storage_deposit_works() { ExtBuilder::default().existential_deposit(200).build().execute_with(|| { let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let addr = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_account_id(); let mut deposit = test_utils::contract_info_storage_deposit(&addr); @@ -3970,41 +2888,23 @@ fn storage_deposit_works() { initialize_block(2); // Create storage - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr.clone(), - 42, - GAS_LIMIT, - None, - (1_000u32, 5_000u32).encode(), - )); + assert_ok!(builder::call(addr.clone()) + .value(42) + .data((1_000u32, 5_000u32).encode()) + .build()); // 4 is for creating 2 storage items let charged0 = 4 + 1_000 + 5_000; deposit += charged0; assert_eq!(get_contract(&addr).total_deposit(), deposit); - - // Add more storage (but also remove some) - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr.clone(), - 0, - GAS_LIMIT, - None, - (2_000u32, 4_900u32).encode(), - )); + + // Add more storage (but also remove some) + assert_ok!(builder::call(addr.clone()).data((2_000u32, 4_900u32).encode()).build()); let charged1 = 1_000 - 100; deposit += charged1; assert_eq!(get_contract(&addr).total_deposit(), deposit); // Remove more storage (but also add some) - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr.clone(), - 0, - GAS_LIMIT, - None, - (2_100u32, 900u32).encode(), - )); + assert_ok!(builder::call(addr.clone()).data((2_100u32, 900u32).encode()).build()); // -1 for numeric instability let refunded0 = 4_000 - 100 - 1; deposit -= refunded0; @@ -4093,43 +2993,12 @@ fn storage_deposit_callee_works() { let min_balance = Contracts::min_balance(); // Create both contracts: Constructors do nothing. - let addr_caller = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(wasm_caller), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; - let addr_callee = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(wasm_callee), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr_caller = + builder::bare_instantiate(Code::Upload(wasm_caller)).build_and_unwrap_account_id(); + let addr_callee = + builder::bare_instantiate(Code::Upload(wasm_callee)).build_and_unwrap_account_id(); - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr_caller, - 0, - GAS_LIMIT, - None, - (100u32, &addr_callee).encode() - )); + assert_ok!(builder::call(addr_caller).data((100u32, &addr_callee).encode()).build()); let callee = get_contract(&addr_callee); let deposit = DepositPerByte::get() * 100 + DepositPerItem::get() * 1; @@ -4152,20 +3021,7 @@ fn set_code_extrinsic() { ExtBuilder::default().existential_deposit(100).build().execute_with(|| { let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let addr = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_account_id(); assert_ok!(Contracts::upload_code( RuntimeOrigin::signed(ALICE), @@ -4189,7 +3045,7 @@ fn set_code_extrinsic() { assert_eq!(get_contract(&addr).code_hash, code_hash); assert_refcount!(&code_hash, 1); assert_refcount!(&new_code_hash, 0); - assert_eq!(System::events(), vec![],); + assert_eq!(System::events(), vec![]); // contract must exist assert_noop!( @@ -4199,7 +3055,7 @@ fn set_code_extrinsic() { assert_eq!(get_contract(&addr).code_hash, code_hash); assert_refcount!(&code_hash, 1); assert_refcount!(&new_code_hash, 0); - assert_eq!(System::events(), vec![],); + assert_eq!(System::events(), vec![]); // new code hash must exist assert_noop!( @@ -4209,7 +3065,7 @@ fn set_code_extrinsic() { assert_eq!(get_contract(&addr).code_hash, code_hash); assert_refcount!(&code_hash, 1); assert_refcount!(&new_code_hash, 0); - assert_eq!(System::events(), vec![],); + assert_eq!(System::events(), vec![]); // successful call assert_ok!(Contracts::set_code(RuntimeOrigin::root(), addr.clone(), new_code_hash)); @@ -4239,20 +3095,9 @@ fn slash_cannot_kill_account() { let _ = ::Currency::set_balance(&ALICE, 1_000_000); let min_balance = Contracts::min_balance(); - let addr = Contracts::bare_instantiate( - ALICE, - value, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm)) + .value(value) + .build_and_unwrap_account_id(); // Drop previous events initialize_block(2); @@ -4303,29 +3148,13 @@ fn contract_reverted() { // Calling extrinsic: revert leads to an error assert_err_ignore_postinfo!( - Contracts::instantiate( - RuntimeOrigin::signed(ALICE), - 0, - GAS_LIMIT, - None, - code_hash, - input.clone(), - vec![], - ), + builder::instantiate(code_hash).data(input.clone()).build(), >::ContractReverted, ); // Calling extrinsic: revert leads to an error assert_err_ignore_postinfo!( - Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), - 0, - GAS_LIMIT, - None, - wasm, - input.clone(), - vec![], - ), + builder::instantiate_with_code(wasm).data(input.clone()).build(), >::ContractReverted, ); @@ -4333,66 +3162,26 @@ fn contract_reverted() { // This is just a different way of transporting the error that allows the read out // the `data` which is only there on success. Obviously, the contract isn't // instantiated. - let result = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Existing(code_hash), - input.clone(), - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap(); + let result = builder::bare_instantiate(Code::Existing(code_hash)) + .data(input.clone()) + .build_and_unwrap_result(); assert_eq!(result.result.flags, flags); assert_eq!(result.result.data, buffer); assert!(!>::contains_key(result.account_id)); // Pass empty flags and therefore successfully instantiate the contract for later use. - let addr = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Existing(code_hash), - ReturnFlags::empty().bits().encode(), - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Existing(code_hash)) + .data(ReturnFlags::empty().bits().encode()) + .build_and_unwrap_account_id(); // Calling extrinsic: revert leads to an error assert_err_ignore_postinfo!( - Contracts::call( - RuntimeOrigin::signed(ALICE), - addr.clone(), - 0, - GAS_LIMIT, - None, - input.clone() - ), + builder::call(addr.clone()).data(input.clone()).build(), >::ContractReverted, ); // Calling directly: revert leads to success but the flags indicate the error - let result = Contracts::bare_call( - ALICE, - addr.clone(), - 0, - GAS_LIMIT, - None, - input, - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result - .unwrap(); + let result = builder::bare_call(addr.clone()).data(input).build_and_unwrap_result(); assert_eq!(result.flags, flags); assert_eq!(result.data, buffer); }); @@ -4407,20 +3196,9 @@ fn set_code_hash() { let _ = ::Currency::set_balance(&ALICE, 1_000_000); // Instantiate the 'caller' - let contract_addr = Contracts::bare_instantiate( - ALICE, - 300_000, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let contract_addr = builder::bare_instantiate(Code::Upload(wasm)) + .value(300_000) + .build_and_unwrap_account_id(); // upload new code assert_ok!(Contracts::upload_code( RuntimeOrigin::signed(ALICE), @@ -4432,35 +3210,16 @@ fn set_code_hash() { System::reset_events(); // First call sets new code_hash and returns 1 - let result = Contracts::bare_call( - ALICE, - contract_addr.clone(), - 0, - GAS_LIMIT, - None, - new_code_hash.as_ref().to_vec(), - DebugInfo::UnsafeDebug, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result - .unwrap(); + let result = builder::bare_call(contract_addr.clone()) + .data(new_code_hash.as_ref().to_vec()) + .debug(DebugInfo::UnsafeDebug) + .build_and_unwrap_result(); assert_return_code!(result, 1); // Second calls new contract code that returns 2 - let result = Contracts::bare_call( - ALICE, - contract_addr.clone(), - 0, - GAS_LIMIT, - None, - vec![], - DebugInfo::UnsafeDebug, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result - .unwrap(); + let result = builder::bare_call(contract_addr.clone()) + .debug(DebugInfo::UnsafeDebug) + .build_and_unwrap_result(); assert_return_code!(result, 2); // Checking for the last event only @@ -4512,37 +3271,16 @@ fn storage_deposit_limit_is_enforced() { // Setting insufficient storage_deposit should fail. assert_err!( - Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - Some((2 * min_balance + 3 - 1).into()), /* expected deposit is 2 * ed + 3 for - * the call */ - Code::Upload(wasm.clone()), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result, + builder::bare_instantiate(Code::Upload(wasm.clone())) + // expected deposit is 2 * ed + 3 for the call + .storage_deposit_limit(Some((2 * min_balance + 3 - 1).into())) + .build() + .result, >::StorageDepositLimitExhausted, ); // Instantiate the BOB contract. - let addr = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_account_id(); let info_deposit = test_utils::contract_info_storage_deposit(&addr); // Check that the BOB contract has been instantiated and has the minimum balance @@ -4553,14 +3291,10 @@ fn storage_deposit_limit_is_enforced() { // setting insufficient deposit limit, as it requires 3 Balance: // 2 for the item added + 1 for the new storage item. assert_err_ignore_postinfo!( - Contracts::call( - RuntimeOrigin::signed(ALICE), - addr.clone(), - 0, - GAS_LIMIT, - Some(codec::Compact(2)), - 1u32.to_le_bytes().to_vec() - ), + builder::call(addr.clone()) + .storage_deposit_limit(Some(codec::Compact(2))) + .data(1u32.to_le_bytes().to_vec()) + .build(), >::StorageDepositLimitExhausted, ); @@ -4571,26 +3305,12 @@ fn storage_deposit_limit_is_enforced() { // Create 1 byte of storage, should cost 3 Balance: // 2 for the item added + 1 for the new storage item. // Should pass as it fallbacks to DefaultDepositLimit. - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr.clone(), - 0, - GAS_LIMIT, - None, - 1u32.to_le_bytes().to_vec() - )); + assert_ok!(builder::call(addr.clone()).data(1u32.to_le_bytes().to_vec()).build()); // Use 4 more bytes of the storage for the same item, which requires 4 Balance. // Should fail as DefaultDepositLimit is 3 and hence isn't enough. assert_err_ignore_postinfo!( - Contracts::call( - RuntimeOrigin::signed(ALICE), - addr.clone(), - 0, - GAS_LIMIT, - None, - 5u32.to_le_bytes().to_vec() - ), + builder::call(addr.clone()).data(5u32.to_le_bytes().to_vec()).build(), >::StorageDepositLimitExhausted, ); }); @@ -4605,45 +3325,17 @@ fn deposit_limit_in_nested_calls() { let _ = ::Currency::set_balance(&ALICE, 1_000_000); // Create both contracts: Constructors do nothing. - let addr_caller = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(wasm_caller), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; - let addr_callee = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(wasm_callee), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr_caller = + builder::bare_instantiate(Code::Upload(wasm_caller)).build_and_unwrap_account_id(); + let addr_callee = + builder::bare_instantiate(Code::Upload(wasm_callee)).build_and_unwrap_account_id(); // Create 100 bytes of storage with a price of per byte // This is 100 Balance + 2 Balance for the item - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr_callee.clone(), - 0, - GAS_LIMIT, - Some(codec::Compact(102)), - 100u32.to_le_bytes().to_vec() - )); + assert_ok!(builder::call(addr_callee.clone()) + .storage_deposit_limit(Some(codec::Compact(102))) + .data(100u32.to_le_bytes().to_vec()) + .build()); // We do not remove any storage but add a storage item of 12 bytes in the caller // contract. This would cost 12 + 2 = 14 Balance. @@ -4651,14 +3343,10 @@ fn deposit_limit_in_nested_calls() { // This should fail as the specified parent's limit is less than the cost: 13 < // 14. assert_err_ignore_postinfo!( - Contracts::call( - RuntimeOrigin::signed(ALICE), - addr_caller.clone(), - 0, - GAS_LIMIT, - Some(codec::Compact(13)), - (100u32, &addr_callee, 0u64).encode(), - ), + builder::call(addr_caller.clone()) + .storage_deposit_limit(Some(codec::Compact(13))) + .data((100u32, &addr_callee, 0u64).encode()) + .build(), >::StorageDepositLimitExhausted, ); // Now we specify the parent's limit high enough to cover the caller's storage additions. @@ -4668,14 +3356,10 @@ fn deposit_limit_in_nested_calls() { // This should fail as the specified parent's limit is less than the cost: 14 // < 15. assert_err_ignore_postinfo!( - Contracts::call( - RuntimeOrigin::signed(ALICE), - addr_caller.clone(), - 0, - GAS_LIMIT, - Some(codec::Compact(14)), - (101u32, &addr_callee, 0u64).encode(), - ), + builder::call(addr_caller.clone()) + .storage_deposit_limit(Some(codec::Compact(14))) + .data((101u32, &addr_callee, 0u64).encode()) + .build(), >::StorageDepositLimitExhausted, ); @@ -4685,14 +3369,10 @@ fn deposit_limit_in_nested_calls() { // call should have a deposit limit of at least 2 Balance. The sub-call should be rolled // back, which is covered by the next test case. assert_err_ignore_postinfo!( - Contracts::call( - RuntimeOrigin::signed(ALICE), - addr_caller.clone(), - 0, - GAS_LIMIT, - Some(codec::Compact(16)), - (102u32, &addr_callee, 1u64).encode(), - ), + builder::call(addr_caller.clone()) + .storage_deposit_limit(Some(codec::Compact(16))) + .data((102u32, &addr_callee, 1u64).encode()) + .build(), >::StorageDepositLimitExhausted, ); @@ -4700,14 +3380,10 @@ fn deposit_limit_in_nested_calls() { // caller. Note that if previous sub-call wouldn't roll back, this call would pass making // the test case fail. We don't set a special limit for the nested call here. assert_err_ignore_postinfo!( - Contracts::call( - RuntimeOrigin::signed(ALICE), - addr_caller.clone(), - 0, - GAS_LIMIT, - Some(codec::Compact(0)), - (87u32, &addr_callee, 0u64).encode(), - ), + builder::call(addr_caller.clone()) + .storage_deposit_limit(Some(codec::Compact(0))) + .data((87u32, &addr_callee, 0u64).encode()) + .build(), >::StorageDepositLimitExhausted, ); @@ -4716,28 +3392,19 @@ fn deposit_limit_in_nested_calls() { // Require more than the sender's balance. // We don't set a special limit for the nested call. assert_err_ignore_postinfo!( - Contracts::call( - RuntimeOrigin::signed(ALICE), - addr_caller.clone(), - 0, - GAS_LIMIT, - None, - (1200u32, &addr_callee, 1u64).encode(), - ), + builder::call(addr_caller.clone()) + .data((1200u32, &addr_callee, 1u64).encode()) + .build(), >::StorageDepositLimitExhausted, ); // Same as above but allow for the additional deposit of 1 Balance in parent. // We set the special deposit limit of 1 Balance for the nested call, which isn't // enforced as callee frees up storage. This should pass. - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr_caller.clone(), - 0, - GAS_LIMIT, - Some(codec::Compact(1)), - (87u32, &addr_callee, 1u64).encode(), - )); + assert_ok!(builder::call(addr_caller.clone()) + .storage_deposit_limit(Some(codec::Compact(1))) + .data((87u32, &addr_callee, 1u64).encode()) + .build()); }); } @@ -4751,35 +3418,13 @@ fn deposit_limit_in_nested_instantiate() { let _ = ::Currency::set_balance(&ALICE, 1_000_000); let _ = ::Currency::set_balance(&BOB, 1_000_000); // Create caller contract - let addr_caller = Contracts::bare_instantiate( - ALICE, - 10_000u64, // this balance is later passed to the deployed contract - GAS_LIMIT, - None, - Code::Upload(wasm_caller), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr_caller = builder::bare_instantiate(Code::Upload(wasm_caller)) + .value(10_000u64) // this balance is later passed to the deployed contract + .build_and_unwrap_account_id(); // Deploy a contract to get its occupied storage size - let addr = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(wasm_callee), - vec![0, 0, 0, 0], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm_callee)) + .data(vec![0, 0, 0, 0]) + .build_and_unwrap_account_id(); let callee_info_len = ContractInfoOf::::get(&addr).unwrap().encoded_size() as u64; @@ -4795,14 +3440,11 @@ fn deposit_limit_in_nested_instantiate() { // Provided the limit is set to be 1 Balance less, // this call should fail on the return from the caller contract. assert_err_ignore_postinfo!( - Contracts::call( - RuntimeOrigin::signed(BOB), - addr_caller.clone(), - 0, - GAS_LIMIT, - Some(codec::Compact(callee_info_len + 2 + ED + 1)), - (0u32, &code_hash_callee, 0u64).encode(), - ), + builder::call(addr_caller.clone()) + .origin(RuntimeOrigin::signed(BOB)) + .storage_deposit_limit(Some(codec::Compact(callee_info_len + 2 + ED + 1))) + .data((0u32, &code_hash_callee, 0u64).encode()) + .build(), >::StorageDepositLimitExhausted, ); // The charges made on instantiation should be rolled back. @@ -4812,14 +3454,11 @@ fn deposit_limit_in_nested_instantiate() { // byte in the constructor. Hence +1 Balance to the limit is needed. This should fail on the // return from constructor. assert_err_ignore_postinfo!( - Contracts::call( - RuntimeOrigin::signed(BOB), - addr_caller.clone(), - 0, - GAS_LIMIT, - Some(codec::Compact(callee_info_len + 2 + ED + 2)), - (1u32, &code_hash_callee, 0u64).encode(), - ), + builder::call(addr_caller.clone()) + .origin(RuntimeOrigin::signed(BOB)) + .storage_deposit_limit(Some(codec::Compact(callee_info_len + 2 + ED + 2))) + .data((1u32, &code_hash_callee, 0u64).encode()) + .build(), >::StorageDepositLimitExhausted, ); // The charges made on the instantiation should be rolled back. @@ -4829,14 +3468,11 @@ fn deposit_limit_in_nested_instantiate() { // This should fail during the charging for the instantiation in // `RawMeter::charge_instantiate()` assert_err_ignore_postinfo!( - Contracts::call( - RuntimeOrigin::signed(BOB), - addr_caller.clone(), - 0, - GAS_LIMIT, - Some(codec::Compact(callee_info_len + 2 + ED + 2)), - (0u32, &code_hash_callee, callee_info_len + 2 + ED + 1).encode(), - ), + builder::call(addr_caller.clone()) + .origin(RuntimeOrigin::signed(BOB)) + .storage_deposit_limit(Some(codec::Compact(callee_info_len + 2 + ED + 2))) + .data((0u32, &code_hash_callee, callee_info_len + 2 + ED + 1).encode()) + .build(), >::StorageDepositLimitExhausted, ); // The charges made on the instantiation should be rolled back. @@ -4847,31 +3483,22 @@ fn deposit_limit_in_nested_instantiate() { // Now we set enough limit for the parent call, but insufficient limit for child // instantiate. This should fail right after the constructor execution. assert_err_ignore_postinfo!( - Contracts::call( - RuntimeOrigin::signed(BOB), - addr_caller.clone(), - 0, - GAS_LIMIT, - Some(codec::Compact(callee_info_len + 2 + ED + 3)), // enough parent limit - (1u32, &code_hash_callee, callee_info_len + 2 + ED + 2).encode(), - ), + builder::call(addr_caller.clone()) + .origin(RuntimeOrigin::signed(BOB)) + .storage_deposit_limit(Some(codec::Compact(callee_info_len + 2 + ED + 3))) // enough parent limit + .data((1u32, &code_hash_callee, callee_info_len + 2 + ED + 2).encode()) + .build(), >::StorageDepositLimitExhausted, ); // The charges made on the instantiation should be rolled back. assert_eq!(::Currency::free_balance(&BOB), 1_000_000); // Set enough deposit limit for the child instantiate. This should succeed. - let result = Contracts::bare_call( - BOB, - addr_caller.clone(), - 0, - GAS_LIMIT, - Some(codec::Compact(callee_info_len + 2 + ED + 4).into()), - (1u32, &code_hash_callee, callee_info_len + 2 + ED + 3).encode(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ); + let result = builder::bare_call(addr_caller.clone()) + .origin(BOB) + .storage_deposit_limit(Some(codec::Compact(callee_info_len + 2 + ED + 4).into())) + .data((1u32, &code_hash_callee, callee_info_len + 2 + ED + 3).encode()) + .build(); let returned = result.result.unwrap(); // All balance of the caller except ED has been transferred to the callee. @@ -4891,7 +3518,7 @@ fn deposit_limit_in_nested_instantiate() { 1_000_000 - (callee_info_len + 2 + ED + 3) ); // Check that deposit due to be charged still includes these 3 Balance - assert_eq!(result.storage_deposit.charge_or_zero(), (callee_info_len + 2 + ED + 3),) + assert_eq!(result.storage_deposit.charge_or_zero(), (callee_info_len + 2 + ED + 3)) }); } @@ -4905,20 +3532,7 @@ fn deposit_limit_honors_liquidity_restrictions() { let min_balance = Contracts::min_balance(); // Instantiate the BOB contract. - let addr = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_account_id(); let info_deposit = test_utils::contract_info_storage_deposit(&addr); // Check that the contract has been instantiated and has the minimum balance @@ -4933,14 +3547,11 @@ fn deposit_limit_honors_liquidity_restrictions() { ) .unwrap(); assert_err_ignore_postinfo!( - Contracts::call( - RuntimeOrigin::signed(BOB), - addr.clone(), - 0, - GAS_LIMIT, - Some(codec::Compact(200)), - 100u32.to_le_bytes().to_vec() - ), + builder::call(addr.clone()) + .origin(RuntimeOrigin::signed(BOB)) + .storage_deposit_limit(Some(codec::Compact(200))) + .data(100u32.to_le_bytes().to_vec()) + .build(), >::StorageDepositNotEnoughFunds, ); assert_eq!(::Currency::free_balance(&BOB), min_balance); @@ -4956,20 +3567,7 @@ fn deposit_limit_honors_existential_deposit() { let min_balance = Contracts::min_balance(); // Instantiate the BOB contract. - let addr = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_account_id(); let info_deposit = test_utils::contract_info_storage_deposit(&addr); @@ -4979,14 +3577,11 @@ fn deposit_limit_honors_existential_deposit() { // check that the deposit can't bring the account below the existential deposit assert_err_ignore_postinfo!( - Contracts::call( - RuntimeOrigin::signed(BOB), - addr.clone(), - 0, - GAS_LIMIT, - Some(codec::Compact(900)), - 100u32.to_le_bytes().to_vec() - ), + builder::call(addr.clone()) + .origin(RuntimeOrigin::signed(BOB)) + .storage_deposit_limit(Some(codec::Compact(900))) + .data(100u32.to_le_bytes().to_vec()) + .build(), >::StorageDepositNotEnoughFunds, ); assert_eq!(::Currency::free_balance(&BOB), 1_000); @@ -5002,20 +3597,7 @@ fn deposit_limit_honors_min_leftover() { let min_balance = Contracts::min_balance(); // Instantiate the BOB contract. - let addr = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_account_id(); let info_deposit = test_utils::contract_info_storage_deposit(&addr); @@ -5026,14 +3608,12 @@ fn deposit_limit_honors_min_leftover() { // check that the minimum leftover (value send) is considered assert_err_ignore_postinfo!( - Contracts::call( - RuntimeOrigin::signed(BOB), - addr.clone(), - 400, - GAS_LIMIT, - Some(codec::Compact(500)), - 100u32.to_le_bytes().to_vec() - ), + builder::call(addr.clone()) + .origin(RuntimeOrigin::signed(BOB)) + .value(400) + .storage_deposit_limit(Some(codec::Compact(500))) + .data(100u32.to_le_bytes().to_vec()) + .build(), >::StorageDepositNotEnoughFunds, ); assert_eq!(::Currency::free_balance(&BOB), 1_000); @@ -5069,30 +3649,11 @@ fn cannot_instantiate_indeterministic_code() { // Try to instantiate directly from code assert_err_ignore_postinfo!( - Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), - 0, - GAS_LIMIT, - None, - wasm.clone(), - vec![], - vec![], - ), + builder::instantiate_with_code(wasm.clone()).build(), >::CodeRejected, ); assert_err!( - Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(wasm.clone()), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result, + builder::bare_instantiate(Code::Upload(wasm.clone())).build().result, >::CodeRejected, ); @@ -5116,48 +3677,17 @@ fn cannot_instantiate_indeterministic_code() { )); assert_err_ignore_postinfo!( - Contracts::instantiate( - RuntimeOrigin::signed(ALICE), - 0, - GAS_LIMIT, - None, - code_hash, - vec![], - vec![], - ), + builder::instantiate(code_hash).build(), >::Indeterministic, ); assert_err!( - Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Existing(code_hash), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result, + builder::bare_instantiate(Code::Existing(code_hash)).build().result, >::Indeterministic, ); // Deploy contract which instantiates another contract - let addr = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(caller_wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = + builder::bare_instantiate(Code::Upload(caller_wasm)).build_and_unwrap_account_id(); // Try to instantiate `code_hash` from another contract in deterministic mode assert_err!( @@ -5211,20 +3741,8 @@ fn cannot_set_code_indeterministic_code() { )); // Create the contract that will call `seal_set_code_hash` - let caller_addr = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(caller_wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let caller_addr = + builder::bare_instantiate(Code::Upload(caller_wasm)).build_and_unwrap_account_id(); // We do not allow to set the code hash to a non-deterministic wasm assert_err!( @@ -5261,20 +3779,8 @@ fn delegate_call_indeterministic_code() { )); // Create the contract that will call `seal_delegate_call` - let caller_addr = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(caller_wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let caller_addr = + builder::bare_instantiate(Code::Upload(caller_wasm)).build_and_unwrap_account_id(); // The delegate call will fail in deterministic mode assert_err!( @@ -5331,17 +3837,9 @@ fn locking_delegate_dependency_works() { // Instantiate the caller contract with the given input. let instantiate = |input: &(u32, H256)| { - Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(wasm_caller.clone()), - input.encode(), - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) + builder::bare_instantiate(Code::Upload(wasm_caller.clone())) + .data(input.encode()) + .build() }; // Call contract with the given input. @@ -5509,17 +4007,7 @@ fn native_dependency_deposit_works() { }; // Instantiate the set_code_hash contract. - let res = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - code, - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ); + let res = builder::bare_instantiate(code).build(); let addr = res.result.unwrap().account_id; let base_deposit = ED + test_utils::contract_info_storage_deposit(&addr); @@ -5567,37 +4055,17 @@ fn reentrance_count_works_with_call() { ExtBuilder::default().existential_deposit(100).build().execute_with(|| { let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let contract_addr = Contracts::bare_instantiate( - ALICE, - 300_000, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let contract_addr = builder::bare_instantiate(Code::Upload(wasm)) + .value(300_000) + .build_and_unwrap_account_id(); // passing reentrant count to the input let input = 0.encode(); - Contracts::bare_call( - ALICE, - contract_addr, - 0, - GAS_LIMIT, - None, - input, - DebugInfo::UnsafeDebug, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result - .unwrap(); + builder::bare_call(contract_addr) + .data(input) + .debug(DebugInfo::UnsafeDebug) + .build_and_unwrap_result(); }); } @@ -5608,37 +4076,17 @@ fn reentrance_count_works_with_delegated_call() { ExtBuilder::default().existential_deposit(100).build().execute_with(|| { let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let contract_addr = Contracts::bare_instantiate( - ALICE, - 300_000, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let contract_addr = builder::bare_instantiate(Code::Upload(wasm)) + .value(300_000) + .build_and_unwrap_account_id(); // adding a callstack height to the input let input = (code_hash, 1).encode(); - Contracts::bare_call( - ALICE, - contract_addr.clone(), - 0, - GAS_LIMIT, - None, - input, - DebugInfo::UnsafeDebug, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result - .unwrap(); + builder::bare_call(contract_addr.clone()) + .data(input) + .debug(DebugInfo::UnsafeDebug) + .build_and_unwrap_result(); }); } @@ -5651,63 +4099,23 @@ fn account_reentrance_count_works() { ExtBuilder::default().existential_deposit(100).build().execute_with(|| { let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let contract_addr = Contracts::bare_instantiate( - ALICE, - 300_000, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let contract_addr = builder::bare_instantiate(Code::Upload(wasm)) + .value(300_000) + .build_and_unwrap_account_id(); - let another_contract_addr = Contracts::bare_instantiate( - ALICE, - 300_000, - GAS_LIMIT, - None, - Code::Upload(wasm_reentrance_count), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let another_contract_addr = builder::bare_instantiate(Code::Upload(wasm_reentrance_count)) + .value(300_000) + .build_and_unwrap_account_id(); - let result1 = Contracts::bare_call( - ALICE, - contract_addr.clone(), - 0, - GAS_LIMIT, - None, - contract_addr.encode(), - DebugInfo::UnsafeDebug, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result - .unwrap(); + let result1 = builder::bare_call(contract_addr.clone()) + .data(contract_addr.encode()) + .debug(DebugInfo::UnsafeDebug) + .build_and_unwrap_result(); - let result2 = Contracts::bare_call( - ALICE, - contract_addr.clone(), - 0, - GAS_LIMIT, - None, - another_contract_addr.encode(), - DebugInfo::UnsafeDebug, - CollectEvents::Skip, - Determinism::Enforced, - ) - .result - .unwrap(); + let result2 = builder::bare_call(contract_addr.clone()) + .data(another_contract_addr.encode()) + .debug(DebugInfo::UnsafeDebug) + .build_and_unwrap_result(); assert_eq!(result1.data, 1.encode()); assert_eq!(result2.data, 0.encode()); @@ -5754,7 +4162,7 @@ fn signed_cannot_set_code() { fn none_cannot_call_code() { ExtBuilder::default().build().execute_with(|| { assert_noop!( - Contracts::call(RuntimeOrigin::none(), BOB, 0, GAS_LIMIT, None, Vec::new()), + builder::call(BOB).origin(RuntimeOrigin::none()).build(), DispatchError::BadOrigin, ); }); @@ -5767,30 +4175,10 @@ fn root_can_call() { ExtBuilder::default().existential_deposit(100).build().execute_with(|| { let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let addr = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_account_id(); // Call the contract. - assert_ok!(Contracts::call( - RuntimeOrigin::root(), - addr.clone(), - 0, - GAS_LIMIT, - None, - vec![] - )); + assert_ok!(builder::call(addr.clone()).origin(RuntimeOrigin::root()).build()); }); } @@ -5800,15 +4188,7 @@ fn root_cannot_instantiate_with_code() { ExtBuilder::default().build().execute_with(|| { assert_err_ignore_postinfo!( - Contracts::instantiate_with_code( - RuntimeOrigin::root(), - 0, - GAS_LIMIT, - None, - wasm, - vec![], - vec![], - ), + builder::instantiate_with_code(wasm).origin(RuntimeOrigin::root()).build(), DispatchError::BadOrigin ); }); @@ -5820,15 +4200,7 @@ fn root_cannot_instantiate() { ExtBuilder::default().build().execute_with(|| { assert_err_ignore_postinfo!( - Contracts::instantiate( - RuntimeOrigin::root(), - 0, - GAS_LIMIT, - None, - code_hash, - vec![], - vec![], - ), + builder::instantiate(code_hash).origin(RuntimeOrigin::root()).build(), DispatchError::BadOrigin ); }); @@ -5881,53 +4253,25 @@ fn only_instantiation_origin_can_instantiate() { let _ = Balances::set_balance(&BOB, 1_000_000); assert_err_ignore_postinfo!( - Contracts::instantiate_with_code( - RuntimeOrigin::root(), - 0, - GAS_LIMIT, - None, - code.clone(), - vec![], - vec![], - ), + builder::instantiate_with_code(code.clone()) + .origin(RuntimeOrigin::root()) + .build(), DispatchError::BadOrigin ); assert_err_ignore_postinfo!( - Contracts::instantiate_with_code( - RuntimeOrigin::signed(BOB), - 0, - GAS_LIMIT, - None, - code.clone(), - vec![], - vec![], - ), + builder::instantiate_with_code(code.clone()) + .origin(RuntimeOrigin::signed(BOB)) + .build(), DispatchError::BadOrigin ); // Only Alice can instantiate - assert_ok!(Contracts::instantiate_with_code( - RuntimeOrigin::signed(ALICE), - 0, - GAS_LIMIT, - None, - code, - vec![], - vec![], - ),); + assert_ok!(builder::instantiate_with_code(code).build()); // Bob cannot instantiate with either `instantiate_with_code` or `instantiate`. assert_err_ignore_postinfo!( - Contracts::instantiate( - RuntimeOrigin::signed(BOB), - 0, - GAS_LIMIT, - None, - code_hash, - vec![], - vec![], - ), + builder::instantiate(code_hash).origin(RuntimeOrigin::signed(BOB)).build(), DispatchError::BadOrigin ); }); @@ -5940,44 +4284,18 @@ fn balance_api_returns_free_balance() { let _ = ::Currency::set_balance(&ALICE, 1_000_000); // Instantiate the BOB contract without any extra balance. - let addr = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(wasm.to_vec()), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = + builder::bare_instantiate(Code::Upload(wasm.to_vec())).build_and_unwrap_account_id(); let value = 0; // Call BOB which makes it call the balance runtime API. // The contract code asserts that the returned balance is 0. - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr.clone(), - value, - GAS_LIMIT, - None, - vec![] - )); + assert_ok!(builder::call(addr.clone()).value(value).build()); let value = 1; // Calling with value will trap the contract. assert_err_ignore_postinfo!( - Contracts::call( - RuntimeOrigin::signed(ALICE), - addr.clone(), - value, - GAS_LIMIT, - None, - vec![] - ), + builder::call(addr.clone()).value(value).build(), >::ContractTrapped ); }); @@ -5989,37 +4307,14 @@ fn gas_consumed_is_linear_for_nested_calls() { ExtBuilder::default().existential_deposit(200).build().execute_with(|| { let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let addr = Contracts::bare_instantiate( - ALICE, - 0, - GAS_LIMIT, - None, - Code::Upload(code), - vec![], - vec![], - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id; + let addr = builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_account_id(); let max_call_depth = ::CallStack::size() as u32; let [gas_0, gas_1, gas_2, gas_max] = { [0u32, 1u32, 2u32, max_call_depth] .iter() .map(|i| { - let result = Contracts::bare_call( - ALICE, - addr.clone(), - 0, - GAS_LIMIT, - None, - i.encode(), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ); + let result = builder::bare_call(addr.clone()).data(i.encode()).build(); assert_ok!(result.result); result.gas_consumed }) diff --git a/substrate/frame/contracts/src/tests/builder.rs b/substrate/frame/contracts/src/tests/builder.rs new file mode 100644 index 00000000000..08d12503a29 --- /dev/null +++ b/substrate/frame/contracts/src/tests/builder.rs @@ -0,0 +1,219 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::{AccountId32, Test, ALICE, GAS_LIMIT}; +use crate::{ + tests::RuntimeOrigin, AccountIdLookupOf, AccountIdOf, BalanceOf, Code, CodeHash, CollectEvents, + ContractExecResult, ContractInstantiateResult, DebugInfo, Determinism, EventRecordOf, + ExecReturnValue, OriginFor, Pallet, Weight, +}; +use codec::Compact; +use frame_support::pallet_prelude::DispatchResultWithPostInfo; +use paste::paste; + +/// Helper macro to generate a builder for contract API calls. +macro_rules! builder { + // Entry point to generate a builder for the given method. + ( + $method:ident($($field:ident: $type:ty,)*) -> $result:ty + ) => { + paste!{ + builder!([< $method:camel Builder >], $method($($field: $type,)* ) -> $result); + } + }; + // Generate the builder struct and its methods. + ( + $name:ident, + $method:ident( + $($field:ident: $type:ty,)* + ) -> $result:ty + ) => { + #[doc = concat!("A builder to construct a ", stringify!($method), " call")] + pub struct $name { + $($field: $type,)* + } + + #[allow(dead_code)] + impl $name + { + $( + #[doc = concat!("Set the ", stringify!($field))] + pub fn $field(mut self, value: $type) -> Self { + self.$field = value; + self + } + )* + + #[doc = concat!("Build the ", stringify!($method), " call")] + pub fn build(self) -> $result { + Pallet::::$method( + $(self.$field,)* + ) + } + } + } +} + +builder!( + instantiate_with_code( + origin: OriginFor, + value: BalanceOf, + gas_limit: Weight, + storage_deposit_limit: Option>>, + code: Vec, + data: Vec, + salt: Vec, + ) -> DispatchResultWithPostInfo +); + +builder!( + instantiate( + origin: OriginFor, + value: BalanceOf, + gas_limit: Weight, + storage_deposit_limit: Option>>, + code_hash: CodeHash, + data: Vec, + salt: Vec, + ) -> DispatchResultWithPostInfo +); + +builder!( + bare_instantiate( + origin: AccountIdOf, + value: BalanceOf, + gas_limit: Weight, + storage_deposit_limit: Option>, + code: Code>, + data: Vec, + salt: Vec, + debug: DebugInfo, + collect_events: CollectEvents, + ) -> ContractInstantiateResult, BalanceOf, EventRecordOf> +); + +builder!( + call( + origin: OriginFor, + dest: AccountIdLookupOf, + value: BalanceOf, + gas_limit: Weight, + storage_deposit_limit: Option>>, + data: Vec, + ) -> DispatchResultWithPostInfo +); + +builder!( + bare_call( + origin: AccountIdOf, + dest: AccountIdOf, + value: BalanceOf, + gas_limit: Weight, + storage_deposit_limit: Option>, + data: Vec, + debug: DebugInfo, + collect_events: CollectEvents, + determinism: Determinism, + ) -> ContractExecResult, EventRecordOf> +); + +/// Create a [`BareInstantiateBuilder`] with default values. +pub fn bare_instantiate(code: Code>) -> BareInstantiateBuilder { + BareInstantiateBuilder { + origin: ALICE, + value: 0, + gas_limit: GAS_LIMIT, + storage_deposit_limit: None, + code, + data: vec![], + salt: vec![], + debug: DebugInfo::Skip, + collect_events: CollectEvents::Skip, + } +} + +impl BareInstantiateBuilder { + /// Build the instantiate call and unwrap the result. + pub fn build_and_unwrap_result(self) -> crate::InstantiateReturnValue> { + self.build().result.unwrap() + } + + /// Build the instantiate call and unwrap the account id. + pub fn build_and_unwrap_account_id(self) -> AccountIdOf { + self.build().result.unwrap().account_id + } +} + +/// Create a [`BareCallBuilder`] with default values. +pub fn bare_call(dest: AccountId32) -> BareCallBuilder { + BareCallBuilder { + origin: ALICE, + dest, + value: 0, + gas_limit: GAS_LIMIT, + storage_deposit_limit: None, + data: vec![], + debug: DebugInfo::Skip, + collect_events: CollectEvents::Skip, + determinism: Determinism::Enforced, + } +} + +impl BareCallBuilder { + /// Build the call and unwrap the result. + pub fn build_and_unwrap_result(self) -> ExecReturnValue { + self.build().result.unwrap() + } +} + +/// Create an [`InstantiateWithCodeBuilder`] with default values. +pub fn instantiate_with_code(code: Vec) -> InstantiateWithCodeBuilder { + InstantiateWithCodeBuilder { + origin: RuntimeOrigin::signed(ALICE), + value: 0, + gas_limit: GAS_LIMIT, + storage_deposit_limit: None, + code, + data: vec![], + salt: vec![], + } +} + +/// Create an [`InstantiateBuilder`] with default values. +pub fn instantiate(code_hash: CodeHash) -> InstantiateBuilder { + InstantiateBuilder { + origin: RuntimeOrigin::signed(ALICE), + value: 0, + gas_limit: GAS_LIMIT, + storage_deposit_limit: None, + code_hash, + data: vec![], + salt: vec![], + } +} + +/// Create a [`CallBuilder`] with default values. +pub fn call(dest: AccountIdLookupOf) -> CallBuilder { + CallBuilder { + origin: RuntimeOrigin::signed(ALICE), + dest, + value: 0, + gas_limit: GAS_LIMIT, + storage_deposit_limit: None, + data: vec![], + } +} -- GitLab From 987f1c24b679a310b77445b95375027fc8236768 Mon Sep 17 00:00:00 2001 From: Rodrigo Quelhas <22591718+RomarQ@users.noreply.github.com> Date: Thu, 28 Mar 2024 12:50:06 +0000 Subject: [PATCH 118/187] Update benchmarking README.md (#3862) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix reference links Co-authored-by: Bastian Köcher --- substrate/frame/benchmarking/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/benchmarking/README.md b/substrate/frame/benchmarking/README.md index bf0bde2c3df..0b3680e1154 100644 --- a/substrate/frame/benchmarking/README.md +++ b/substrate/frame/benchmarking/README.md @@ -177,8 +177,8 @@ requirements. The benchmarking CLI uses a Handlebars template to format the final output file. You can optionally pass the flag `--template` pointing to a custom template that can be used instead. Within the template, you have access to all the data provided by the `TemplateData` struct in the [benchmarking CLI -writer](../../utils/frame/benchmarking-cli/src/writer.rs). You can find the default template used -[here](../../utils/frame/benchmarking-cli/src/template.hbs). +writer](../../utils/frame/benchmarking-cli/src/pallet/writer.rs). You can find the default template used +[here](../../utils/frame/benchmarking-cli/src/pallet/template.hbs). There are some custom Handlebars helpers included with our output generation: -- GitLab From 2e4e65711233c6f3a1adc9ce49af8f4537de5439 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Thu, 28 Mar 2024 14:10:56 +0100 Subject: [PATCH 119/187] Export unified ParachainHostFunctions (#3854) This PR exports unified hostfunctions needed for parachains. Basicaly `SubstrateHostFunctions` + `storage_proof_size::HostFunctions`. Also removes the native executor from the parachain template. --------- Co-authored-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> --- Cargo.lock | 1 + cumulus/client/service/Cargo.toml | 1 + cumulus/client/service/src/lib.rs | 9 +++++++ cumulus/polkadot-parachain/src/service.rs | 6 ++--- prdoc/pr_3854.prdoc | 15 +++++++++++ templates/parachain/node/src/service.rs | 31 ++++------------------- 6 files changed, 33 insertions(+), 30 deletions(-) create mode 100644 prdoc/pr_3854.prdoc diff --git a/Cargo.lock b/Cargo.lock index 8188e571fcd..413bd28abe0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3803,6 +3803,7 @@ dependencies = [ "sp-blockchain", "sp-consensus", "sp-core", + "sp-io", "sp-runtime", "sp-transaction-pool", ] diff --git a/cumulus/client/service/Cargo.toml b/cumulus/client/service/Cargo.toml index 2bafbee951a..e03e20fe5b4 100644 --- a/cumulus/client/service/Cargo.toml +++ b/cumulus/client/service/Cargo.toml @@ -30,6 +30,7 @@ sp-consensus = { path = "../../../substrate/primitives/consensus/common" } sp-core = { path = "../../../substrate/primitives/core" } sp-runtime = { path = "../../../substrate/primitives/runtime" } sp-transaction-pool = { path = "../../../substrate/primitives/transaction-pool" } +sp-io = { path = "../../../substrate/primitives/io" } # Polkadot polkadot-primitives = { path = "../../../polkadot/primitives" } diff --git a/cumulus/client/service/src/lib.rs b/cumulus/client/service/src/lib.rs index 950e59aff24..91e884d6f7e 100644 --- a/cumulus/client/service/src/lib.rs +++ b/cumulus/client/service/src/lib.rs @@ -54,6 +54,15 @@ use std::{sync::Arc, time::Duration}; pub use cumulus_primitives_proof_size_hostfunction::storage_proof_size; +/// Host functions that should be used in parachain nodes. +/// +/// Contains the standard substrate host functions, as well as a +/// host function to enable PoV-reclaim on parachain nodes. +pub type ParachainHostFunctions = ( + cumulus_primitives_proof_size_hostfunction::storage_proof_size::HostFunctions, + sp_io::SubstrateHostFunctions, +); + // Given the sporadic nature of the explicit recovery operation and the // possibility to retry infinite times this value is more than enough. // In practice here we expect no more than one queued messages. diff --git a/cumulus/polkadot-parachain/src/service.rs b/cumulus/polkadot-parachain/src/service.rs index ddf595ca70c..e9bb5947522 100644 --- a/cumulus/polkadot-parachain/src/service.rs +++ b/cumulus/polkadot-parachain/src/service.rs @@ -69,13 +69,11 @@ use substrate_prometheus_endpoint::Registry; use polkadot_primitives::CollatorPair; #[cfg(not(feature = "runtime-benchmarks"))] -type HostFunctions = - (sp_io::SubstrateHostFunctions, cumulus_client_service::storage_proof_size::HostFunctions); +type HostFunctions = cumulus_client_service::ParachainHostFunctions; #[cfg(feature = "runtime-benchmarks")] type HostFunctions = ( - sp_io::SubstrateHostFunctions, - cumulus_client_service::storage_proof_size::HostFunctions, + cumulus_client_service::ParachainHostFunctions, frame_benchmarking::benchmarking::HostFunctions, ); diff --git a/prdoc/pr_3854.prdoc b/prdoc/pr_3854.prdoc new file mode 100644 index 00000000000..cfc8e246d7e --- /dev/null +++ b/prdoc/pr_3854.prdoc @@ -0,0 +1,15 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Export unified `ParachainHostFunctions` from `cumulus-client-service` + +doc: + - audience: Node Dev + description: | + Exports `ParachainHostFunctions` to have a bundled version of `SubstrateHostFunctions` and + `cumulus_primitives_proof_size_hostfunction::storage_proof_size::HostFunctions`. This increases discoverability and makes + it more obvious that they should be used together in parachain nodes. + +crates: + - name: cumulus-client-service + bump: minor diff --git a/templates/parachain/node/src/service.rs b/templates/parachain/node/src/service.rs index bb4a5394958..7e7bf1726b5 100644 --- a/templates/parachain/node/src/service.rs +++ b/templates/parachain/node/src/service.rs @@ -16,7 +16,8 @@ use cumulus_client_consensus_common::ParachainBlockImport as TParachainBlockImpo use cumulus_client_consensus_proposer::Proposer; use cumulus_client_service::{ build_network, build_relay_chain_interface, prepare_node_config, start_relay_chain_tasks, - BuildNetworkParams, CollatorSybilResistance, DARecoveryProfile, StartRelayChainTasksParams, + BuildNetworkParams, CollatorSybilResistance, DARecoveryProfile, ParachainHostFunctions, + StartRelayChainTasksParams, }; use cumulus_primitives_core::{relay_chain::CollatorPair, ParaId}; use cumulus_relay_chain_interface::{OverseerHandle, RelayChainInterface}; @@ -25,9 +26,7 @@ use cumulus_relay_chain_interface::{OverseerHandle, RelayChainInterface}; use frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE; use sc_client_api::Backend; use sc_consensus::ImportQueue; -use sc_executor::{ - HeapAllocStrategy, NativeElseWasmExecutor, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY, -}; +use sc_executor::{HeapAllocStrategy, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY}; use sc_network::NetworkBlock; use sc_network_sync::SyncingService; use sc_service::{Configuration, PartialComponents, TFullBackend, TFullClient, TaskManager}; @@ -36,25 +35,7 @@ use sc_transaction_pool_api::OffchainTransactionPoolFactory; use sp_keystore::KeystorePtr; use substrate_prometheus_endpoint::Registry; -/// Native executor type. -pub struct ParachainNativeExecutor; - -impl sc_executor::NativeExecutionDispatch for ParachainNativeExecutor { - type ExtendHostFunctions = ( - cumulus_client_service::storage_proof_size::HostFunctions, - frame_benchmarking::benchmarking::HostFunctions, - ); - - fn dispatch(method: &str, data: &[u8]) -> Option> { - parachain_template_runtime::apis::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - parachain_template_runtime::native_version() - } -} - -type ParachainExecutor = NativeElseWasmExecutor; +type ParachainExecutor = WasmExecutor; type ParachainClient = TFullClient; @@ -92,7 +73,7 @@ pub fn new_partial(config: &Configuration) -> Result .default_heap_pages .map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| HeapAllocStrategy::Static { extra_pages: h as _ }); - let wasm = WasmExecutor::builder() + let executor = ParachainExecutor::builder() .with_execution_method(config.wasm_method) .with_onchain_heap_alloc_strategy(heap_pages) .with_offchain_heap_alloc_strategy(heap_pages) @@ -100,8 +81,6 @@ pub fn new_partial(config: &Configuration) -> Result .with_runtime_cache_size(config.runtime_cache_size) .build(); - let executor = ParachainExecutor::new_with_wasm_executor(wasm); - let (client, backend, keystore_container, task_manager) = sc_service::new_full_parts_record_import::( config, -- GitLab From 79b08d884773443f5f306ee4a95eb435f944ac72 Mon Sep 17 00:00:00 2001 From: dharjeezy Date: Thu, 28 Mar 2024 14:12:14 +0100 Subject: [PATCH 120/187] Try State Hook for Beefy (#3246) Part of: https://github.com/paritytech/polkadot-sdk/issues/239 Polkadot address: 12GyGD3QhT4i2JJpNzvMf96sxxBLWymz4RdGCxRH5Rj5agKW --- prdoc/pr_3246.prdoc | 11 ++ substrate/frame/beefy/src/lib.rs | 62 ++++++++++ substrate/frame/beefy/src/mock.rs | 116 ++++++++++-------- substrate/frame/beefy/src/tests.rs | 190 +++++++++++++++-------------- 4 files changed, 240 insertions(+), 139 deletions(-) create mode 100644 prdoc/pr_3246.prdoc diff --git a/prdoc/pr_3246.prdoc b/prdoc/pr_3246.prdoc new file mode 100644 index 00000000000..19a823e5028 --- /dev/null +++ b/prdoc/pr_3246.prdoc @@ -0,0 +1,11 @@ +title: Try State Hook for Beefy. + +doc: + - audience: Runtime User + description: | + Invariants for storage items in the beefy pallet. Enforces the following Invariants: + 1. `Authorities` should not exceed the `MaxAuthorities` capacity. + 2. `NextAuthorities` should not exceed the `MaxAuthorities` capacity. + 3. `ValidatorSetId` must be present in `SetIdSession`. +crates: +- name: pallet-beefy diff --git a/substrate/frame/beefy/src/lib.rs b/substrate/frame/beefy/src/lib.rs index 87304eba8ba..09cd13ab70a 100644 --- a/substrate/frame/beefy/src/lib.rs +++ b/substrate/frame/beefy/src/lib.rs @@ -280,6 +280,14 @@ pub mod pallet { } } + #[pallet::hooks] + impl Hooks> for Pallet { + #[cfg(feature = "try-runtime")] + fn try_state(_n: BlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { + Self::do_try_state() + } + } + #[pallet::validate_unsigned] impl ValidateUnsigned for Pallet { type Call = Call; @@ -294,6 +302,60 @@ pub mod pallet { } } +#[cfg(any(feature = "try-runtime", test))] +impl Pallet { + /// Ensure the correctness of the state of this pallet. + /// + /// This should be valid before or after each state transition of this pallet. + pub fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { + Self::try_state_authorities()?; + Self::try_state_validators()?; + + Ok(()) + } + + /// # Invariants + /// + /// * `Authorities` should not exceed the `MaxAuthorities` capacity. + /// * `NextAuthorities` should not exceed the `MaxAuthorities` capacity. + fn try_state_authorities() -> Result<(), sp_runtime::TryRuntimeError> { + if let Some(authorities_len) = >::decode_len() { + ensure!( + authorities_len as u32 <= T::MaxAuthorities::get(), + "Authorities number exceeds what the pallet config allows." + ); + } else { + return Err(sp_runtime::TryRuntimeError::Other( + "Failed to decode length of authorities", + )); + } + + if let Some(next_authorities_len) = >::decode_len() { + ensure!( + next_authorities_len as u32 <= T::MaxAuthorities::get(), + "Next authorities number exceeds what the pallet config allows." + ); + } else { + return Err(sp_runtime::TryRuntimeError::Other( + "Failed to decode length of next authorities", + )); + } + Ok(()) + } + + /// # Invariants + /// + /// `ValidatorSetId` must be present in `SetIdSession` + fn try_state_validators() -> Result<(), sp_runtime::TryRuntimeError> { + let validator_set_id = >::get(); + ensure!( + SetIdSession::::get(validator_set_id).is_some(), + "Validator set id must be present in SetIdSession" + ); + Ok(()) + } +} + impl Pallet { /// Return the current active BEEFY validator set. pub fn validator_set() -> Option> { diff --git a/substrate/frame/beefy/src/mock.rs b/substrate/frame/beefy/src/mock.rs index fccc63bd1b4..1c55adc8de4 100644 --- a/substrate/frame/beefy/src/mock.rs +++ b/substrate/frame/beefy/src/mock.rs @@ -27,7 +27,6 @@ use frame_support::{ }; use pallet_session::historical as pallet_session_historical; use sp_core::{crypto::KeyTypeId, ConstU128}; -use sp_io::TestExternalities; use sp_runtime::{ app_crypto::ecdsa::Public, curve::PiecewiseLinear, impl_opaque_keys, testing::TestXt, traits::OpaqueKeys, BuildStorage, Perbill, @@ -210,6 +209,73 @@ impl pallet_offences::Config for Test { type OnOffenceHandler = Staking; } +#[derive(Default)] +pub struct ExtBuilder { + authorities: Vec, +} + +impl ExtBuilder { + /// Add some AccountIds to insert into `List`. + #[cfg(test)] + pub(crate) fn add_authorities(mut self, ids: Vec) -> Self { + self.authorities = ids; + self + } + + pub fn build(self) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + let balances: Vec<_> = + (0..self.authorities.len()).map(|i| (i as u64, 10_000_000)).collect(); + + pallet_balances::GenesisConfig:: { balances } + .assimilate_storage(&mut t) + .unwrap(); + + let session_keys: Vec<_> = self + .authorities + .iter() + .enumerate() + .map(|(i, k)| (i as u64, i as u64, MockSessionKeys { dummy: k.clone() })) + .collect(); + + BasicExternalities::execute_with_storage(&mut t, || { + for (ref id, ..) in &session_keys { + frame_system::Pallet::::inc_providers(id); + } + }); + + pallet_session::GenesisConfig:: { keys: session_keys } + .assimilate_storage(&mut t) + .unwrap(); + + // controllers are same as stash + let stakers: Vec<_> = (0..self.authorities.len()) + .map(|i| (i as u64, i as u64, 10_000, pallet_staking::StakerStatus::::Validator)) + .collect(); + + let staking_config = pallet_staking::GenesisConfig:: { + stakers, + validator_count: 2, + force_era: pallet_staking::Forcing::ForceNew, + minimum_validator_count: 0, + invulnerables: vec![], + ..Default::default() + }; + + staking_config.assimilate_storage(&mut t).unwrap(); + + t.into() + } + + pub fn build_and_execute(self, test: impl FnOnce() -> ()) { + self.build().execute_with(|| { + test(); + Beefy::do_try_state().expect("All invariants must hold after a test"); + }) + } +} + // Note, that we can't use `UintAuthorityId` here. Reason is that the implementation // of `to_public_key()` assumes, that a public key is 32 bytes long. This is true for // ed25519 and sr25519 but *not* for ecdsa. A compressed ecdsa public key is 33 bytes, @@ -226,54 +292,6 @@ pub fn mock_authorities(vec: Vec) -> Vec { vec.into_iter().map(|id| mock_beefy_id(id)).collect() } -pub fn new_test_ext(ids: Vec) -> TestExternalities { - new_test_ext_raw_authorities(mock_authorities(ids)) -} - -pub fn new_test_ext_raw_authorities(authorities: Vec) -> TestExternalities { - let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - - let balances: Vec<_> = (0..authorities.len()).map(|i| (i as u64, 10_000_000)).collect(); - - pallet_balances::GenesisConfig:: { balances } - .assimilate_storage(&mut t) - .unwrap(); - - let session_keys: Vec<_> = authorities - .iter() - .enumerate() - .map(|(i, k)| (i as u64, i as u64, MockSessionKeys { dummy: k.clone() })) - .collect(); - - BasicExternalities::execute_with_storage(&mut t, || { - for (ref id, ..) in &session_keys { - frame_system::Pallet::::inc_providers(id); - } - }); - - pallet_session::GenesisConfig:: { keys: session_keys } - .assimilate_storage(&mut t) - .unwrap(); - - // controllers are same as stash - let stakers: Vec<_> = (0..authorities.len()) - .map(|i| (i as u64, i as u64, 10_000, pallet_staking::StakerStatus::::Validator)) - .collect(); - - let staking_config = pallet_staking::GenesisConfig:: { - stakers, - validator_count: 2, - force_era: pallet_staking::Forcing::ForceNew, - minimum_validator_count: 0, - invulnerables: vec![], - ..Default::default() - }; - - staking_config.assimilate_storage(&mut t).unwrap(); - - t.into() -} - pub fn start_session(session_index: SessionIndex) { for i in Session::current_index()..session_index { System::on_finalize(System::block_number()); diff --git a/substrate/frame/beefy/src/tests.rs b/substrate/frame/beefy/src/tests.rs index 2950264e0c3..6a6aa245ce1 100644 --- a/substrate/frame/beefy/src/tests.rs +++ b/substrate/frame/beefy/src/tests.rs @@ -47,7 +47,7 @@ fn genesis_session_initializes_authorities() { let authorities = mock_authorities(vec![1, 2, 3, 4]); let want = authorities.clone(); - new_test_ext_raw_authorities(authorities).execute_with(|| { + ExtBuilder::default().add_authorities(authorities).build_and_execute(|| { let authorities = beefy::Authorities::::get(); assert_eq!(authorities.len(), 4); @@ -69,130 +69,140 @@ fn session_change_updates_authorities() { let authorities = mock_authorities(vec![1, 2, 3, 4]); let want_validators = authorities.clone(); - new_test_ext(vec![1, 2, 3, 4]).execute_with(|| { - assert!(0 == beefy::ValidatorSetId::::get()); + ExtBuilder::default() + .add_authorities(mock_authorities(vec![1, 2, 3, 4])) + .build_and_execute(|| { + assert!(0 == beefy::ValidatorSetId::::get()); - init_block(1); + init_block(1); - assert!(1 == beefy::ValidatorSetId::::get()); + assert!(1 == beefy::ValidatorSetId::::get()); - let want = beefy_log(ConsensusLog::AuthoritiesChange( - ValidatorSet::new(want_validators, 1).unwrap(), - )); + let want = beefy_log(ConsensusLog::AuthoritiesChange( + ValidatorSet::new(want_validators, 1).unwrap(), + )); - let log = System::digest().logs[0].clone(); - assert_eq!(want, log); + let log = System::digest().logs[0].clone(); + assert_eq!(want, log); - init_block(2); + init_block(2); - assert!(2 == beefy::ValidatorSetId::::get()); + assert!(2 == beefy::ValidatorSetId::::get()); - let want = beefy_log(ConsensusLog::AuthoritiesChange( - ValidatorSet::new(vec![mock_beefy_id(2), mock_beefy_id(4)], 2).unwrap(), - )); + let want = beefy_log(ConsensusLog::AuthoritiesChange( + ValidatorSet::new(vec![mock_beefy_id(2), mock_beefy_id(4)], 2).unwrap(), + )); - let log = System::digest().logs[1].clone(); - assert_eq!(want, log); - }); + let log = System::digest().logs[1].clone(); + assert_eq!(want, log); + }); } #[test] fn session_change_updates_next_authorities() { let want = vec![mock_beefy_id(1), mock_beefy_id(2), mock_beefy_id(3), mock_beefy_id(4)]; - new_test_ext(vec![1, 2, 3, 4]).execute_with(|| { - let next_authorities = beefy::NextAuthorities::::get(); + ExtBuilder::default() + .add_authorities(mock_authorities(vec![1, 2, 3, 4])) + .build_and_execute(|| { + let next_authorities = beefy::NextAuthorities::::get(); - assert_eq!(next_authorities.len(), 4); - assert_eq!(want[0], next_authorities[0]); - assert_eq!(want[1], next_authorities[1]); - assert_eq!(want[2], next_authorities[2]); - assert_eq!(want[3], next_authorities[3]); + assert_eq!(next_authorities.len(), 4); + assert_eq!(want[0], next_authorities[0]); + assert_eq!(want[1], next_authorities[1]); + assert_eq!(want[2], next_authorities[2]); + assert_eq!(want[3], next_authorities[3]); - init_block(1); + init_block(1); - let next_authorities = beefy::NextAuthorities::::get(); + let next_authorities = beefy::NextAuthorities::::get(); - assert_eq!(next_authorities.len(), 2); - assert_eq!(want[1], next_authorities[0]); - assert_eq!(want[3], next_authorities[1]); - }); + assert_eq!(next_authorities.len(), 2); + assert_eq!(want[1], next_authorities[0]); + assert_eq!(want[3], next_authorities[1]); + }); } #[test] fn validator_set_at_genesis() { let want = vec![mock_beefy_id(1), mock_beefy_id(2)]; - new_test_ext(vec![1, 2, 3, 4]).execute_with(|| { - let vs = Beefy::validator_set().unwrap(); + ExtBuilder::default() + .add_authorities(mock_authorities(vec![1, 2, 3, 4])) + .build_and_execute(|| { + let vs = Beefy::validator_set().unwrap(); - assert_eq!(vs.id(), 0u64); - assert_eq!(vs.validators()[0], want[0]); - assert_eq!(vs.validators()[1], want[1]); - }); + assert_eq!(vs.id(), 0u64); + assert_eq!(vs.validators()[0], want[0]); + assert_eq!(vs.validators()[1], want[1]); + }); } #[test] fn validator_set_updates_work() { let want = vec![mock_beefy_id(1), mock_beefy_id(2), mock_beefy_id(3), mock_beefy_id(4)]; - new_test_ext(vec![1, 2, 3, 4]).execute_with(|| { - let vs = Beefy::validator_set().unwrap(); - assert_eq!(vs.id(), 0u64); - assert_eq!(want[0], vs.validators()[0]); - assert_eq!(want[1], vs.validators()[1]); - assert_eq!(want[2], vs.validators()[2]); - assert_eq!(want[3], vs.validators()[3]); + ExtBuilder::default() + .add_authorities(mock_authorities(vec![1, 2, 3, 4])) + .build_and_execute(|| { + let vs = Beefy::validator_set().unwrap(); + assert_eq!(vs.id(), 0u64); + assert_eq!(want[0], vs.validators()[0]); + assert_eq!(want[1], vs.validators()[1]); + assert_eq!(want[2], vs.validators()[2]); + assert_eq!(want[3], vs.validators()[3]); - init_block(1); + init_block(1); - let vs = Beefy::validator_set().unwrap(); + let vs = Beefy::validator_set().unwrap(); - assert_eq!(vs.id(), 1u64); - assert_eq!(want[0], vs.validators()[0]); - assert_eq!(want[1], vs.validators()[1]); + assert_eq!(vs.id(), 1u64); + assert_eq!(want[0], vs.validators()[0]); + assert_eq!(want[1], vs.validators()[1]); - init_block(2); + init_block(2); - let vs = Beefy::validator_set().unwrap(); + let vs = Beefy::validator_set().unwrap(); - assert_eq!(vs.id(), 2u64); - assert_eq!(want[1], vs.validators()[0]); - assert_eq!(want[3], vs.validators()[1]); - }); + assert_eq!(vs.id(), 2u64); + assert_eq!(want[1], vs.validators()[0]); + assert_eq!(want[3], vs.validators()[1]); + }); } #[test] fn cleans_up_old_set_id_session_mappings() { - new_test_ext(vec![1, 2, 3, 4]).execute_with(|| { - let max_set_id_session_entries = MaxSetIdSessionEntries::get(); - - // we have 3 sessions per era - let era_limit = max_set_id_session_entries / 3; - // sanity check against division precision loss - assert_eq!(0, max_set_id_session_entries % 3); - // go through `max_set_id_session_entries` sessions - start_era(era_limit); - - // we should have a session id mapping for all the set ids from - // `max_set_id_session_entries` eras we have observed - for i in 1..=max_set_id_session_entries { - assert!(beefy::SetIdSession::::get(i as u64).is_some()); - } + ExtBuilder::default() + .add_authorities(mock_authorities(vec![1, 2, 3, 4])) + .build_and_execute(|| { + let max_set_id_session_entries = MaxSetIdSessionEntries::get(); + + // we have 3 sessions per era + let era_limit = max_set_id_session_entries / 3; + // sanity check against division precision loss + assert_eq!(0, max_set_id_session_entries % 3); + // go through `max_set_id_session_entries` sessions + start_era(era_limit); + + // we should have a session id mapping for all the set ids from + // `max_set_id_session_entries` eras we have observed + for i in 1..=max_set_id_session_entries { + assert!(beefy::SetIdSession::::get(i as u64).is_some()); + } - // go through another `max_set_id_session_entries` sessions - start_era(era_limit * 2); + // go through another `max_set_id_session_entries` sessions + start_era(era_limit * 2); - // we should keep tracking the new mappings for new sessions - for i in max_set_id_session_entries + 1..=max_set_id_session_entries * 2 { - assert!(beefy::SetIdSession::::get(i as u64).is_some()); - } + // we should keep tracking the new mappings for new sessions + for i in max_set_id_session_entries + 1..=max_set_id_session_entries * 2 { + assert!(beefy::SetIdSession::::get(i as u64).is_some()); + } - // but the old ones should have been pruned by now - for i in 1..=max_set_id_session_entries { - assert!(beefy::SetIdSession::::get(i as u64).is_none()); - } - }); + // but the old ones should have been pruned by now + for i in 1..=max_set_id_session_entries { + assert!(beefy::SetIdSession::::get(i as u64).is_none()); + } + }); } /// Returns a list with 3 authorities with known keys: @@ -259,7 +269,7 @@ fn should_sign_and_verify() { fn report_equivocation_current_set_works() { let authorities = test_authorities(); - new_test_ext_raw_authorities(authorities).execute_with(|| { + ExtBuilder::default().add_authorities(authorities).build_and_execute(|| { assert_eq!(Staking::current_era(), Some(0)); assert_eq!(Session::current_index(), 0); @@ -339,7 +349,7 @@ fn report_equivocation_current_set_works() { fn report_equivocation_old_set_works() { let authorities = test_authorities(); - new_test_ext_raw_authorities(authorities).execute_with(|| { + ExtBuilder::default().add_authorities(authorities).build_and_execute(|| { start_era(1); let block_num = System::block_number(); @@ -422,7 +432,7 @@ fn report_equivocation_old_set_works() { fn report_equivocation_invalid_set_id() { let authorities = test_authorities(); - new_test_ext_raw_authorities(authorities).execute_with(|| { + ExtBuilder::default().add_authorities(authorities).build_and_execute(|| { start_era(1); let block_num = System::block_number(); @@ -460,7 +470,7 @@ fn report_equivocation_invalid_set_id() { fn report_equivocation_invalid_session() { let authorities = test_authorities(); - new_test_ext_raw_authorities(authorities).execute_with(|| { + ExtBuilder::default().add_authorities(authorities).build_and_execute(|| { start_era(1); let block_num = System::block_number(); @@ -503,7 +513,7 @@ fn report_equivocation_invalid_session() { fn report_equivocation_invalid_key_owner_proof() { let authorities = test_authorities(); - new_test_ext_raw_authorities(authorities).execute_with(|| { + ExtBuilder::default().add_authorities(authorities).build_and_execute(|| { start_era(1); let block_num = System::block_number(); @@ -551,7 +561,7 @@ fn report_equivocation_invalid_key_owner_proof() { fn report_equivocation_invalid_equivocation_proof() { let authorities = test_authorities(); - new_test_ext_raw_authorities(authorities).execute_with(|| { + ExtBuilder::default().add_authorities(authorities).build_and_execute(|| { start_era(1); let block_num = System::block_number(); @@ -624,7 +634,7 @@ fn report_equivocation_validate_unsigned_prevents_duplicates() { let authorities = test_authorities(); - new_test_ext_raw_authorities(authorities).execute_with(|| { + ExtBuilder::default().add_authorities(authorities).build_and_execute(|| { start_era(1); let block_num = System::block_number(); @@ -728,7 +738,7 @@ fn report_equivocation_has_valid_weight() { fn valid_equivocation_reports_dont_pay_fees() { let authorities = test_authorities(); - new_test_ext_raw_authorities(authorities).execute_with(|| { + ExtBuilder::default().add_authorities(authorities).build_and_execute(|| { start_era(1); let block_num = System::block_number(); @@ -796,7 +806,7 @@ fn valid_equivocation_reports_dont_pay_fees() { fn set_new_genesis_works() { let authorities = test_authorities(); - new_test_ext_raw_authorities(authorities).execute_with(|| { + ExtBuilder::default().add_authorities(authorities).build_and_execute(|| { start_era(1); let new_genesis_delay = 10u64; -- GitLab From 6a0859ebf70db45e632219d95e932ea824488312 Mon Sep 17 00:00:00 2001 From: Alin Dima Date: Thu, 28 Mar 2024 15:14:17 +0200 Subject: [PATCH 121/187] bugfix: request fragment tree membership for all candidates (#3874) --- polkadot/node/core/backing/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/node/core/backing/src/lib.rs b/polkadot/node/core/backing/src/lib.rs index 4b6beb5592e..b5cad4cf5f0 100644 --- a/polkadot/node/core/backing/src/lib.rs +++ b/polkadot/node/core/backing/src/lib.rs @@ -911,7 +911,7 @@ async fn handle_active_leaves_update( } let mut seconded_at_depth = HashMap::new(); - if let Some(response) = membership_answers.next().await { + while let Some(response) = membership_answers.next().await { match response { Err(oneshot::Canceled) => { gum::warn!( -- GitLab From c106dbd095cddb3254ab85eca99bdaa997db2ca3 Mon Sep 17 00:00:00 2001 From: tugy <33746108+tugytur@users.noreply.github.com> Date: Thu, 28 Mar 2024 15:07:52 +0100 Subject: [PATCH 122/187] add missing syscalls for workers (#2212) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description Since the binary split additional syscalls are getting blocked in relation to the workers. With the hardened systemd file it shows the following warning: ``` Cannot fully enable landlock, a Linux kernel security feature. Running validation of malicious PVF code has a higher risk of compromising this machine. Consider upgrading the kernel version for maximum security. status=Ok(NotEnforced) abi=1 ``` For it to work we need to allow additionally: - mount - umount2 - pivot_root and set `RestrictNamespaces=false` Added new line `SystemCallFilter=pivot_root` because otherwise it would get blocked by ~\@\privileged Co-authored-by: s0me0ne-unkn0wn <48632512+s0me0ne-unkn0wn@users.noreply.github.com> Co-authored-by: Bastian Köcher --- polkadot/scripts/packaging/polkadot.service | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/polkadot/scripts/packaging/polkadot.service b/polkadot/scripts/packaging/polkadot.service index 7fb549c97f8..8c5a483d424 100644 --- a/polkadot/scripts/packaging/polkadot.service +++ b/polkadot/scripts/packaging/polkadot.service @@ -25,12 +25,13 @@ ProtectKernelTunables=true ProtectSystem=strict RemoveIPC=true RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX -RestrictNamespaces=true +RestrictNamespaces=false RestrictSUIDSGID=true SystemCallArchitectures=native SystemCallFilter=@system-service -SystemCallFilter=landlock_add_rule landlock_create_ruleset landlock_restrict_self seccomp -SystemCallFilter=~@clock @module @mount @reboot @swap @privileged +SystemCallFilter=landlock_add_rule landlock_create_ruleset landlock_restrict_self seccomp mount umount2 +SystemCallFilter=~@clock @module @reboot @swap @privileged +SystemCallFilter=pivot_root UMask=0027 [Install] -- GitLab From eb6f5abee64e979dba25924f71ef86d2b3ca2deb Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Thu, 28 Mar 2024 17:42:20 +0100 Subject: [PATCH 123/187] [ci] fix subsystem-benchmarks gha (#3876) PR adds variables validation and app credentials for pushing into gh-pages cc https://github.com/paritytech/ci_cd/issues/934 --- .github/workflows/subsystem-benchmarks.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/subsystem-benchmarks.yml b/.github/workflows/subsystem-benchmarks.yml index 37a9e0f4680..f0d56bf6e9d 100644 --- a/.github/workflows/subsystem-benchmarks.yml +++ b/.github/workflows/subsystem-benchmarks.yml @@ -15,7 +15,13 @@ on: jobs: subsystem-benchmarks: runs-on: ubuntu-latest + environment: subsystem-benchmarks steps: + - name: Validate inputs + run: | + echo "${{ github.event.inputs.benchmark-data-dir-path }}" | grep -P '^[a-z\-]' + echo "${{ github.event.inputs.output-file-path }}" | grep -P '^[a-z\-]+\.json' + - name: Checkout Sources uses: actions/checkout@v4.1.2 with: @@ -30,7 +36,13 @@ jobs: - name: Switch branch id: step_two run: | - git checkout master + git checkout master -- + + - uses: actions/create-github-app-token@v1 + id: app-token + with: + app-id: ${{ secrets.POLKADOTSDK_GHPAGES_APP_ID }} + private-key: ${{ secrets.POLKADOTSDK_GHPAGES_APP_KEY }} - name: Store benchmark result uses: benchmark-action/github-action-benchmark@v1 @@ -38,5 +50,5 @@ jobs: tool: "customSmallerIsBetter" output-file-path: ${{ github.event.inputs.output-file-path }} benchmark-data-dir-path: "bench/${{ github.event.inputs.benchmark-data-dir-path }}" - github-token: ${{ secrets.GITHUB_TOKEN }} + github-token: ${{ steps.app-token.outputs.token }} auto-push: true -- GitLab From 30ef8651ed0ba821e59121545815280a3e9b2862 Mon Sep 17 00:00:00 2001 From: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Date: Fri, 29 Mar 2024 09:49:34 +0200 Subject: [PATCH 124/187] collation-genereation: fix tests (#3883) Somehow https://github.com/paritytech/polkadot-sdk/pull/3795 was merged but tests are failing now on master. I suspect that CI is not even running these tests anymore which is a big issue. --------- Signed-off-by: Andrei Sandu --- .../node/collation-generation/src/tests.rs | 96 +++++++++---------- 1 file changed, 46 insertions(+), 50 deletions(-) diff --git a/polkadot/node/collation-generation/src/tests.rs b/polkadot/node/collation-generation/src/tests.rs index 3cb3e61a35a..923a21e86fb 100644 --- a/polkadot/node/collation-generation/src/tests.rs +++ b/polkadot/node/collation-generation/src/tests.rs @@ -686,7 +686,7 @@ fn submit_collation_is_no_op_before_initialization() { fn submit_collation_leads_to_distribution() { let relay_parent = Hash::repeat_byte(0); let validation_code_hash = ValidationCodeHash::from(Hash::repeat_byte(42)); - let parent_head = HeadData::from(vec![1, 2, 3]); + let parent_head = dummy_head_data(); let para_id = ParaId::from(5); let expected_pvd = PersistedValidationData { parent_head: parent_head.clone(), @@ -707,7 +707,7 @@ fn submit_collation_leads_to_distribution() { msg: CollationGenerationMessage::SubmitCollation(SubmitCollationParams { relay_parent, collation: test_collation(), - parent_head: vec![1, 2, 3].into(), + parent_head: dummy_head_data(), validation_code_hash, result_sender: None, core_index: CoreIndex(0), @@ -795,16 +795,16 @@ fn distribute_collation_for_occupied_core_with_async_backing_enabled(#[case] run cores, runtime_version, claim_queue, - pending_availability, ) .await; - helpers::handle_core_processing_for_a_leaf( + helpers::handle_cores_processing_for_a_leaf( &mut virtual_overseer, activated_hash, para_id, // `CoreState` is `Occupied` => `OccupiedCoreAssumption` is `Included` OccupiedCoreAssumption::Included, 1, + pending_availability, ) .await; @@ -825,7 +825,7 @@ fn distribute_collation_for_occupied_cores_with_async_backing_enabled_and_elasti let activated_hash: Hash = [1; 32].into(); let para_id = ParaId::from(5); - let cores = (0..candidates_pending_avail) + let cores = (0..3) .into_iter() .map(|idx| { CoreState::Occupied(polkadot_primitives::OccupiedCore { @@ -864,17 +864,22 @@ fn distribute_collation_for_occupied_cores_with_async_backing_enabled_and_elasti // Using latest runtime with the fancy claim queue exposed. RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT, claim_queue, - pending_availability, ) .await; - helpers::handle_core_processing_for_a_leaf( + helpers::handle_cores_processing_for_a_leaf( &mut virtual_overseer, activated_hash, para_id, - // `CoreState` is `Occupied` => `OccupiedCoreAssumption` is `Included` - OccupiedCoreAssumption::Included, + // if at least 1 cores is occupied => `OccupiedCoreAssumption` is `Included` + // else assumption is `Free`. + if candidates_pending_avail > 0 { + OccupiedCoreAssumption::Included + } else { + OccupiedCoreAssumption::Free + }, total_cores, + pending_availability, ) .await; @@ -890,12 +895,12 @@ fn distribute_collation_for_occupied_cores_with_async_backing_enabled_and_elasti #[case(1)] #[case(2)] fn distribute_collation_for_free_cores_with_async_backing_enabled_and_elastic_scaling( - #[case] candidates_pending_avail: u32, + #[case] total_cores: usize, ) { let activated_hash: Hash = [1; 32].into(); let para_id = ParaId::from(5); - let cores = (0..candidates_pending_avail) + let cores = (0..total_cores) .into_iter() .map(|_idx| CoreState::Scheduled(ScheduledCore { para_id, collator: None })) .collect::>(); @@ -905,7 +910,6 @@ fn distribute_collation_for_free_cores_with_async_backing_enabled_and_elastic_sc .enumerate() .map(|(idx, _core)| (CoreIndex::from(idx as u32), VecDeque::from([para_id]))) .collect::>(); - let total_cores = cores.len(); test_harness(|mut virtual_overseer| async move { helpers::initialize_collator(&mut virtual_overseer, para_id).await; @@ -918,17 +922,17 @@ fn distribute_collation_for_free_cores_with_async_backing_enabled_and_elastic_sc // Using latest runtime with the fancy claim queue exposed. RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT, claim_queue, - vec![], ) .await; - helpers::handle_core_processing_for_a_leaf( + helpers::handle_cores_processing_for_a_leaf( &mut virtual_overseer, activated_hash, para_id, // `CoreState` is `Free` => `OccupiedCoreAssumption` is `Free` OccupiedCoreAssumption::Free, total_cores, + vec![], ) .await; @@ -963,6 +967,7 @@ fn no_collation_is_distributed_for_occupied_core_with_async_backing_disabled( test_harness(|mut virtual_overseer| async move { helpers::initialize_collator(&mut virtual_overseer, para_id).await; helpers::activate_new_head(&mut virtual_overseer, activated_hash).await; + helpers::handle_runtime_calls_on_new_head_activation( &mut virtual_overseer, activated_hash, @@ -970,7 +975,6 @@ fn no_collation_is_distributed_for_occupied_core_with_async_backing_disabled( cores, runtime_version, claim_queue, - vec![], ) .await; @@ -1047,7 +1051,6 @@ mod helpers { cores: Vec, runtime_version: u32, claim_queue: BTreeMap>, - pending_availability: Vec, ) { assert_matches!( overseer_recv(virtual_overseer).await, @@ -1082,25 +1085,6 @@ mod helpers { } ); - // Process the `ParaBackingState` message, and return some dummy state. - let message = overseer_recv(virtual_overseer).await; - let para_id = match message { - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _, - RuntimeApiRequest::ParaBackingState(p_id, _), - )) => p_id, - _ => panic!("received unexpected message {:?}", message), - }; - - assert_matches!( - message, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::ParaBackingState(p_id, tx)) - ) if parent == activated_hash && p_id == para_id => { - tx.send(Ok(Some(dummy_backing_state(pending_availability)))).unwrap(); - } - ); - assert_matches!( overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( @@ -1128,12 +1112,13 @@ mod helpers { // Handles all runtime requests performed in `handle_new_activations` for the case when a // collation should be prepared for the new leaf - pub async fn handle_core_processing_for_a_leaf( + pub async fn handle_cores_processing_for_a_leaf( virtual_overseer: &mut VirtualOverseer, activated_hash: Hash, para_id: ParaId, expected_occupied_core_assumption: OccupiedCoreAssumption, cores_assigned: usize, + pending_availability: Vec, ) { // Expect no messages if no cores is assigned to the para if cores_assigned == 0 { @@ -1143,7 +1128,7 @@ mod helpers { // Some hardcoded data - if needed, extract to parameters let validation_code_hash = ValidationCodeHash::from(Hash::repeat_byte(42)); - let parent_head = HeadData::from(vec![1, 2, 3]); + let parent_head = dummy_head_data(); let pvd = PersistedValidationData { parent_head: parent_head.clone(), relay_parent_number: 10, @@ -1151,6 +1136,15 @@ mod helpers { max_pov_size: 1024, }; + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(parent, RuntimeApiRequest::ParaBackingState(p_id, tx)) + ) if parent == activated_hash && p_id == para_id => { + tx.send(Ok(Some(dummy_backing_state(pending_availability)))).unwrap(); + } + ); + assert_matches!( overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request(hash, RuntimeApiRequest::PersistedValidationData(id, a, tx))) => { @@ -1180,18 +1174,20 @@ mod helpers { } ); - assert_matches!( - overseer_recv(virtual_overseer).await, - AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation{ - candidate_receipt, - parent_head_data_hash, - .. - }) => { - assert_eq!(parent_head_data_hash, parent_head.hash()); - assert_eq!(candidate_receipt.descriptor().persisted_validation_data_hash, pvd.hash()); - assert_eq!(candidate_receipt.descriptor().para_head, dummy_head_data().hash()); - assert_eq!(candidate_receipt.descriptor().validation_code_hash, validation_code_hash); - } - ); + for _ in 0..cores_assigned { + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation{ + candidate_receipt, + parent_head_data_hash, + .. + }) => { + assert_eq!(parent_head_data_hash, parent_head.hash()); + assert_eq!(candidate_receipt.descriptor().persisted_validation_data_hash, pvd.hash()); + assert_eq!(candidate_receipt.descriptor().para_head, dummy_head_data().hash()); + assert_eq!(candidate_receipt.descriptor().validation_code_hash, validation_code_hash); + } + ); + } } } -- GitLab From b310b575cd73928cf061e1ae0d184f7e900976d5 Mon Sep 17 00:00:00 2001 From: s0me0ne-unkn0wn <48632512+s0me0ne-unkn0wn@users.noreply.github.com> Date: Fri, 29 Mar 2024 10:12:40 +0100 Subject: [PATCH 125/187] Remove transient code after `im-online` pallet removal (#3383) Removes transient code introduced to clean up offchain database after `im-online` pallet removal. Should be merged after #2290 has been enacted. --- polkadot/runtime/rococo/src/lib.rs | 6 ------ polkadot/runtime/westend/src/lib.rs | 6 ------ 2 files changed, 12 deletions(-) diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index c41ffdbe72d..f37c901475a 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -1868,12 +1868,6 @@ sp_api::impl_runtime_apis! { impl offchain_primitives::OffchainWorkerApi for Runtime { fn offchain_worker(header: &::Header) { - use sp_runtime::{traits::Header, DigestItem}; - - if header.digest().logs().iter().any(|di| di == &DigestItem::RuntimeEnvironmentUpdated) { - pallet_im_online::migration::clear_offchain_storage(Session::validators().len() as u32); - } - Executive::offchain_worker(header) } } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index e6381513170..d75c1011d5f 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1931,12 +1931,6 @@ sp_api::impl_runtime_apis! { impl offchain_primitives::OffchainWorkerApi for Runtime { fn offchain_worker(header: &::Header) { - use sp_runtime::{traits::Header, DigestItem}; - - if header.digest().logs().iter().any(|di| di == &DigestItem::RuntimeEnvironmentUpdated) { - pallet_im_online::migration::clear_offchain_storage(Session::validators().len() as u32); - } - Executive::offchain_worker(header) } } -- GitLab From 5638d1a830dc70f56e5fdd7eded21a4f592d382c Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <49718502+alexggh@users.noreply.github.com> Date: Fri, 29 Mar 2024 13:24:26 +0200 Subject: [PATCH 126/187] Decorate mpsc-notification-to-protocol with the protocol name (#3873) Currently, all protocols use the same metric name for `mpsc-notification-to-protocol` this is bad because we can't actually tell which protocol might cause problems. This patch proposes we derive the name of the metric from the protocol name, so that we have separate metrics for each protocol and properly detect which one is having problem processing its messages. --------- Signed-off-by: Alexandru Gheorghe --- .../src/protocol/notifications/service/mod.rs | 18 ++++++++++++++++-- substrate/client/utils/src/mpsc.rs | 7 ++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/substrate/client/network/src/protocol/notifications/service/mod.rs b/substrate/client/network/src/protocol/notifications/service/mod.rs index 6d9873f45d5..dfb19daa28e 100644 --- a/substrate/client/network/src/protocol/notifications/service/mod.rs +++ b/substrate/client/network/src/protocol/notifications/service/mod.rs @@ -338,7 +338,8 @@ impl NotificationService for NotificationHandle { // Clone [`NotificationService`] fn clone(&mut self) -> Result, ()> { let mut subscribers = self.subscribers.lock(); - let (event_tx, event_rx) = tracing_unbounded("mpsc-notification-to-protocol", 100_000); + + let (event_tx, event_rx) = tracing_unbounded(self.rx.name(), 100_000); subscribers.push(event_tx); Ok(Box::new(NotificationHandle { @@ -624,7 +625,9 @@ pub fn notification_service( protocol: ProtocolName, ) -> (ProtocolHandlePair, Box) { let (cmd_tx, cmd_rx) = mpsc::channel(COMMAND_QUEUE_SIZE); - let (event_tx, event_rx) = tracing_unbounded("mpsc-notification-to-protocol", 100_000); + + let (event_tx, event_rx) = + tracing_unbounded(metric_label_for_protocol(&protocol).leak(), 100_000); let subscribers = Arc::new(Mutex::new(vec![event_tx])); ( @@ -632,3 +635,14 @@ pub fn notification_service( Box::new(NotificationHandle::new(protocol.clone(), cmd_tx, event_rx, subscribers)), ) } + +// Decorates the mpsc-notification-to-protocol metric with the name of the protocol, +// to be able to distiguish between different protocols in dashboards. +fn metric_label_for_protocol(protocol: &ProtocolName) -> String { + let protocol_name = protocol.to_string(); + let keys = protocol_name.split("/").collect::>(); + keys.iter() + .rev() + .take(2) // Last two tokens give the protocol name and version + .fold("mpsc-notification-to-protocol".into(), |acc, val| format!("{}-{}", acc, val)) +} diff --git a/substrate/client/utils/src/mpsc.rs b/substrate/client/utils/src/mpsc.rs index c24a5bd8904..91db7e1e7b0 100644 --- a/substrate/client/utils/src/mpsc.rs +++ b/substrate/client/utils/src/mpsc.rs @@ -86,7 +86,7 @@ pub fn tracing_unbounded( warning_fired: Arc::new(AtomicBool::new(false)), creation_backtrace: Arc::new(Backtrace::force_capture()), }; - let receiver = TracingUnboundedReceiver { inner: r, name }; + let receiver = TracingUnboundedReceiver { inner: r, name: name.into() }; (sender, receiver) } @@ -157,6 +157,11 @@ impl TracingUnboundedReceiver { pub fn len(&self) -> usize { self.inner.len() } + + /// The name of this receiver + pub fn name(&self) -> &'static str { + self.name + } } impl Drop for TracingUnboundedReceiver { -- GitLab From 0d9324847391e902bb42f84f0e76096b1f764efe Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Fri, 29 Mar 2024 15:13:21 +0200 Subject: [PATCH 127/187] Fix `addresses_to_publish_respects_existing_p2p_protocol` test in sc-authority-discovery (#3895) Fixes https://github.com/paritytech/polkadot-sdk/issues/3887. --- .../client/authority-discovery/src/worker.rs | 22 ++++++++++++++----- .../authority-discovery/src/worker/tests.rs | 14 +++++++----- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/substrate/client/authority-discovery/src/worker.rs b/substrate/client/authority-discovery/src/worker.rs index 4ad7db5f7da..546f8cdbffd 100644 --- a/substrate/client/authority-discovery/src/worker.rs +++ b/substrate/client/authority-discovery/src/worker.rs @@ -342,6 +342,7 @@ where } fn addresses_to_publish(&self) -> impl Iterator { + let local_peer_id = self.network.local_peer_id(); let publish_non_global_ips = self.publish_non_global_ips; let addresses = self .public_addresses @@ -349,7 +350,15 @@ where .into_iter() .chain(self.network.external_addresses().into_iter().filter_map(|mut address| { // Make sure the reported external address does not contain `/p2p/...` protocol. - if let Some(multiaddr::Protocol::P2p(_)) = address.iter().last() { + if let Some(multiaddr::Protocol::P2p(peer_id)) = address.iter().last() { + if peer_id != *local_peer_id.as_ref() { + error!( + target: LOG_TARGET, + "Network returned external address '{address}' with peer id \ + not matching the local peer id '{local_peer_id}'.", + ); + debug_assert!(false); + } address.pop(); } @@ -375,15 +384,16 @@ where }) .collect::>(); - let peer_id = self.network.local_peer_id(); debug!( target: LOG_TARGET, - "Authority DHT record peer_id='{peer_id}' addresses='{addresses:?}'", + "Authority DHT record peer_id='{local_peer_id}' addresses='{addresses:?}'", ); - // The address must include the peer id. - let peer_id: Multihash = peer_id.into(); - addresses.into_iter().map(move |a| a.with(multiaddr::Protocol::P2p(peer_id))) + // The address must include the local peer id. + let local_peer_id: Multihash = local_peer_id.into(); + addresses + .into_iter() + .map(move |a| a.with(multiaddr::Protocol::P2p(local_peer_id))) } /// Publish own public addresses. diff --git a/substrate/client/authority-discovery/src/worker/tests.rs b/substrate/client/authority-discovery/src/worker/tests.rs index c2912088194..6c684d88e50 100644 --- a/substrate/client/authority-discovery/src/worker/tests.rs +++ b/substrate/client/authority-discovery/src/worker/tests.rs @@ -716,12 +716,16 @@ fn addresses_to_publish_adds_p2p() { #[test] fn addresses_to_publish_respects_existing_p2p_protocol() { let (_dht_event_tx, dht_event_rx) = channel(1000); + let identity = Keypair::generate_ed25519(); + let peer_id = identity.public().to_peer_id(); + let external_address = "/ip6/2001:db8::/tcp/30333" + .parse::() + .unwrap() + .with(multiaddr::Protocol::P2p(peer_id.into())); let network: Arc = Arc::new(TestNetwork { - external_addresses: vec![ - "/ip6/2001:db8::/tcp/30333/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC" - .parse() - .unwrap(), - ], + peer_id, + identity, + external_addresses: vec![external_address], ..Default::default() }); -- GitLab From 41257069b062ea7feb2277f11a2e992d3c9d5089 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Sun, 31 Mar 2024 20:59:33 +1100 Subject: [PATCH 128/187] Tokens in FRAME Docs (#2802) Closes https://github.com/paritytech/polkadot-sdk-docs/issues/70 WIP PR for an overview of how to develop tokens in FRAME. - [x] Tokens in Substrate Ref Doc - High-level overview of the token-related logic in FRAME - Improve docs with better explanation of how holds, freezes, ed, free balance, etc, all work - [x] Update `pallet_balances` docs - Clearly mark what is deprecated (currency) - [x] Write fungible trait docs - [x] Evaluate and if required update `pallet_assets`, `pallet_uniques`, `pallet_nfts` docs - [x] Absorb https://github.com/paritytech/polkadot-sdk/pull/2683/ - [x] Audit individual trait method docs, and improve if possible Feel free to suggest additional TODOs for this PR in the comments --------- Co-authored-by: Bill Laboon Co-authored-by: Francisco Aguirre Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Sebastian Kunert --- Cargo.lock | 3 + docs/sdk/Cargo.toml | 3 + docs/sdk/src/reference_docs/frame_currency.rs | 8 - .../reference_docs/frame_pallet_coupling.rs | 2 +- .../frame_runtime_upgrades_and_migrations.rs | 1 - docs/sdk/src/reference_docs/frame_tokens.rs | 131 +++++++++++++++++ docs/sdk/src/reference_docs/mod.rs | 6 +- substrate/frame/assets/src/lib.rs | 13 +- substrate/frame/balances/src/lib.rs | 83 +++++------ .../support/src/traits/tokens/currency.rs | 3 + .../src/traits/tokens/fungible/freeze.rs | 17 ++- .../src/traits/tokens/fungible/hold.rs | 7 +- .../src/traits/tokens/fungible/imbalance.rs | 2 + .../src/traits/tokens/fungible/item_of.rs | 5 + .../support/src/traits/tokens/fungible/mod.rs | 139 ++++++++++++++++-- .../src/traits/tokens/fungible/regular.rs | 2 + .../src/traits/tokens/fungible/union_of.rs | 2 + .../src/traits/tokens/fungibles/approvals.rs | 2 + .../src/traits/tokens/fungibles/enumerable.rs | 4 + .../src/traits/tokens/fungibles/freeze.rs | 2 + .../src/traits/tokens/fungibles/hold.rs | 2 + .../src/traits/tokens/fungibles/imbalance.rs | 2 + .../src/traits/tokens/fungibles/lifetime.rs | 2 + .../src/traits/tokens/fungibles/metadata.rs | 2 + .../src/traits/tokens/fungibles/mod.rs | 11 +- .../src/traits/tokens/fungibles/regular.rs | 2 + .../src/traits/tokens/fungibles/roles.rs | 2 + .../src/traits/tokens/fungibles/union_of.rs | 2 + 28 files changed, 377 insertions(+), 83 deletions(-) delete mode 100644 docs/sdk/src/reference_docs/frame_currency.rs create mode 100644 docs/sdk/src/reference_docs/frame_tokens.rs diff --git a/Cargo.lock b/Cargo.lock index 413bd28abe0..81eb682a27d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13390,11 +13390,14 @@ dependencies = [ "pallet-example-single-block-migrations", "pallet-examples", "pallet-multisig", + "pallet-nfts", + "pallet-preimage", "pallet-proxy", "pallet-referenda", "pallet-scheduler", "pallet-timestamp", "pallet-transaction-payment", + "pallet-uniques", "pallet-utility", "parity-scale-codec", "sc-cli", diff --git a/docs/sdk/Cargo.toml b/docs/sdk/Cargo.toml index 434202ed693..3b8f45d7756 100644 --- a/docs/sdk/Cargo.toml +++ b/docs/sdk/Cargo.toml @@ -66,6 +66,7 @@ pallet-aura = { path = "../../substrate/frame/aura", default-features = false } pallet-timestamp = { path = "../../substrate/frame/timestamp" } pallet-balances = { path = "../../substrate/frame/balances" } pallet-assets = { path = "../../substrate/frame/assets" } +pallet-preimage = { path = "../../substrate/frame/preimage" } pallet-transaction-payment = { path = "../../substrate/frame/transaction-payment" } pallet-utility = { path = "../../substrate/frame/utility" } pallet-multisig = { path = "../../substrate/frame/multisig" } @@ -73,6 +74,8 @@ pallet-proxy = { path = "../../substrate/frame/proxy" } pallet-authorship = { path = "../../substrate/frame/authorship" } pallet-collective = { path = "../../substrate/frame/collective" } pallet-democracy = { path = "../../substrate/frame/democracy" } +pallet-uniques = { path = "../../substrate/frame/uniques" } +pallet-nfts = { path = "../../substrate/frame/nfts" } pallet-scheduler = { path = "../../substrate/frame/scheduler" } # Primitives diff --git a/docs/sdk/src/reference_docs/frame_currency.rs b/docs/sdk/src/reference_docs/frame_currency.rs deleted file mode 100644 index 6987d51aec8..00000000000 --- a/docs/sdk/src/reference_docs/frame_currency.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! FRAME Currency Abstractions and Traits -//! -//! Notes: -//! -//! - History, `Currency` trait. -//! - `Hold` and `Freeze` with diagram. -//! - `HoldReason` and `FreezeReason` -//! - This footgun: diff --git a/docs/sdk/src/reference_docs/frame_pallet_coupling.rs b/docs/sdk/src/reference_docs/frame_pallet_coupling.rs index cca7f9feb3f..be464bbbf83 100644 --- a/docs/sdk/src/reference_docs/frame_pallet_coupling.rs +++ b/docs/sdk/src/reference_docs/frame_pallet_coupling.rs @@ -143,7 +143,7 @@ //! For example, all pallets in `polkadot-sdk` that needed to work with currencies could have been //! tightly coupled with [`pallet_balances`]. But, `polkadot-sdk` also provides [`pallet_assets`] //! (and more implementations by the community), therefore all pallets use traits to loosely couple -//! with balances or assets pallet. More on this in [`crate::reference_docs::frame_currency`]. +//! with balances or assets pallet. More on this in [`crate::reference_docs::frame_tokens`]. //! //! ## Further References //! diff --git a/docs/sdk/src/reference_docs/frame_runtime_upgrades_and_migrations.rs b/docs/sdk/src/reference_docs/frame_runtime_upgrades_and_migrations.rs index cbbf611f9dc..f9a69b892a3 100644 --- a/docs/sdk/src/reference_docs/frame_runtime_upgrades_and_migrations.rs +++ b/docs/sdk/src/reference_docs/frame_runtime_upgrades_and_migrations.rs @@ -131,7 +131,6 @@ //! //! TODO: Link to multi block migration example/s once PR is merged (). //! -//! [`GetStorageVersion`]: frame_support::traits::GetStorageVersion //! [`OnRuntimeUpgrade`]: frame_support::traits::OnRuntimeUpgrade //! [`StorageVersion`]: frame_support::traits::StorageVersion //! [`set_code`]: frame_system::Call::set_code diff --git a/docs/sdk/src/reference_docs/frame_tokens.rs b/docs/sdk/src/reference_docs/frame_tokens.rs new file mode 100644 index 00000000000..c9d34e2091d --- /dev/null +++ b/docs/sdk/src/reference_docs/frame_tokens.rs @@ -0,0 +1,131 @@ +// This file is part of polkadot-sdk. +// +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # FRAME Tokens +//! +//! This reference doc serves as a high-level overview of the token-related logic in FRAME, and +//! how to properly apply it to your use case. +//! +//! On completion of reading this doc, you should have a good understanding of: +//! - The distinction between token traits and trait implementations in FRAME, and why this +//! distinction is helpful +//! - Token-related traits avaliable in FRAME +//! - Token-related trait implementations in FRAME +//! - How to choose the right trait or trait implementation for your use case +//! - Where to go next +//! +//! ## Getting Started +//! +//! The most ubiquitous way to add a token to a FRAME runtime is [`pallet_balances`]. Read +//! more about pallets [here](crate::polkadot_sdk::frame_runtime#pallets). +//! +//! You may then write custom pallets that interact with [`pallet_balances`]. The fastest way to +//! get started with that is by +//! [tightly coupling](crate::reference_docs::frame_pallet_coupling#tight-coupling-pallets) your +//! custom pallet to [`pallet_balances`]. +//! +//! However, to keep pallets flexible and modular, it is often prefered to +//! [loosely couple](crate::reference_docs::frame_pallet_coupling#loosely--coupling-pallets). +//! +//! To achieve loose coupling, +//! we separate token logic into traits and trait implementations. +//! +//! ## Traits and Trait Implementations +//! +//! Broadly speaking, token logic in FRAME can be divided into two categories: traits and +//! trait implementations. +//! +//! **Traits** define common interfaces that types of tokens should implement. For example, the +//! [`fungible::Inspect`](`frame_support::traits::fungible::Inspect`) trait specifies an interface +//! for *inspecting* token state such as the total issuance of the token, the balance of individual +//! accounts, etc. +//! +//! **Trait implementations** are concrete implementations of these traits. For example, one of the +//! many traits [`pallet_balances`] implements is +//! [`fungible::Inspect`](`frame_support::traits::fungible::Inspect`)*. It provides the concrete way +//! of inspecting the total issuance, balance of accounts, etc. There can be many implementations of +//! the same traits. +//! +//! The distinction between traits and trait implementations is helpful because it allows pallets +//! and other logic to be generic over their dependencies, avoiding tight coupling. +//! +//! To illustrate this with an example let's consider [`pallet_preimage`]. This pallet takes a +//! deposit in exchange for storing a preimage for later use. A naive implementation of the +//! pallet may use [`pallet_balances`] in a tightly coupled manner, directly calling methods +//! on the pallet to reserve and unreserve deposits. This approach works well, +//! until someone has a use case requiring that an asset from a different pallet such as +//! [`pallet_assets`] is used for the deposit. Rather than tightly couple [`pallet_preimage`] to +//! [`pallet_balances`], [`pallet_assets`], and every other token-handling pallet a user +//! could possibly specify, [`pallet_preimage`] does not specify a concrete pallet as a dependency +//! but instead accepts any dependency which implements the +//! [`currency::ReservableCurrency`](`frame_support::traits::tokens::currency::ReservableCurrency`) +//! trait, namely via its [`Config::Currency`](`pallet_preimage::pallet::Config::Currency`) +//! associated type. This allows [`pallet_preimage`] to support any arbitrary pallet implementing +//! this trait, without needing any knowledge of what those pallets may be or requiring changes to +//! support new pallets which may be written in the future. +//! +//! Read more about coupling, and the benefits of loose coupling +//! [here](crate::reference_docs::frame_pallet_coupling). +//! +//! ##### *Rust Advanced Tip +//! +//! The knowledge that [`pallet_balances`] implements +//! [`fungible::Inspect`](`frame_support::traits::fungible::Inspect`) is not some arcane knowledge +//! that you have to know by heart or memorize. One can simply look at the list of the implementors +//! of any trait in the Rust Doc to find all implementors (e.g. +//! ), +//! or use the `rust-analyzer` `Implementations` action. +//! +//! ## Fungible Token Traits in FRAME +//! +//! The [`fungible`](`frame_support::traits::fungible`) crate contains the latest set of FRAME +//! fungible token traits, and is recommended to use for all new logic requiring a fungible token. +//! See the crate documentation for more info about these fungible traits. +//! +//! [`fungibles`](`frame_support::traits::fungibles`) provides very similar functionality to +//! [`fungible`](`frame_support::traits::fungible`), except it supports managing multiple tokens. +//! +//! You may notice the trait [`Currency`](`frame_support::traits::Currency`) with similar +//! functionality is also used in the codebase, however this trait is deprecated and existing logic +//! is in the process of being migrated to [`fungible`](`frame_support::traits::fungible`) ([tracking issue](https://github.com/paritytech/polkadot-sdk/issues/226)). +//! +//! ## Fungible Token Trait Implementations in FRAME +//! +//! [`pallet_balances`] implements [`fungible`](`frame_support::traits::fungible`), and is the most +//! commonly used fungible implementation in FRAME. Most of the time, it's used for managing the +//! native token of the blockchain network it's used in. +//! +//! [`pallet_assets`] implements [`fungibles`](`frame_support::traits::fungibles`), and is another +//! popular fungible token implementation. It supports the creation and management of multiple +//! assets in a single crate, making it a good choice when a network requires more assets in +//! addition to its native token. +//! +//! ## Non-Fungible Tokens in FRAME +//! +//! [`pallet_nfts`] is recommended to use for all NFT use cases in FRAME. +//! See the crate documentation for more info about this pallet. +//! +//! [`pallet_uniques`] is deprecated and should not be used. +//! +//! +//! # What Next? +//! +//! - If you are interested in implementing a single fungible token, continue reading the +//! [`fungible`](`frame_support::traits::fungible`) and [`pallet_balances`] docs. +//! - If you are interested in implementing a set of fungible tokens, continue reading the +//! [`fungibles`](`frame_support::traits::fungibles`) trait and [`pallet_assets`] docs. +//! - If you are interested in implementing an NFT, continue reading the [`pallet_nfts`] docs. diff --git a/docs/sdk/src/reference_docs/mod.rs b/docs/sdk/src/reference_docs/mod.rs index a0d8d05b449..145df8844f2 100644 --- a/docs/sdk/src/reference_docs/mod.rs +++ b/docs/sdk/src/reference_docs/mod.rs @@ -65,9 +65,6 @@ pub mod metadata; /// Learn about how frame-system handles `account-ids`, nonces, consumers and providers. pub mod frame_system_accounts; -/// Learn about the currency-related abstractions provided in FRAME. -pub mod frame_currency; - /// Advice for configuring your development environment for Substrate development. pub mod development_environment_advice; @@ -75,6 +72,9 @@ pub mod development_environment_advice; // TODO: @shawntabrizi @ggwpez https://github.com/paritytech/polkadot-sdk-docs/issues/50 pub mod frame_benchmarking_weight; +/// Learn about the token-related logic in FRAME and how to apply it to your use case. +pub mod frame_tokens; + /// Learn about chain specification file and the genesis state of the blockchain. // TODO: @michalkucharczyk https://github.com/paritytech/polkadot-sdk-docs/issues/51 pub mod chain_spec_genesis; diff --git a/substrate/frame/assets/src/lib.rs b/substrate/frame/assets/src/lib.rs index c5468e4237d..e5fe2a3d1fd 100644 --- a/substrate/frame/assets/src/lib.rs +++ b/substrate/frame/assets/src/lib.rs @@ -17,7 +17,16 @@ //! # Assets Pallet //! -//! A simple, secure module for dealing with fungible assets. +//! A simple, secure module for dealing with sets of assets implementing +//! [`fungible`](frame_support::traits::fungible) traits, via +//! [`fungibles`](frame_support::traits::fungibles) traits. +//! +//! The pallet makes heavy use of concepts such as Holds and Freezes from the +//! [`frame_support::traits::fungible`] traits, therefore you should read and understand those docs +//! as a prerequisite to understanding this pallet. +//! +//! See the [`frame_tokens`] reference docs for more information about the place of the +//! Assets pallet in FRAME. //! //! ## Overview //! @@ -133,6 +142,8 @@ //! //! * [`System`](../frame_system/index.html) //! * [`Support`](../frame_support/index.html) +//! +//! [`frame_tokens`]: ../polkadot_sdk_docs/reference_docs/frame_tokens/index.html // This recursion limit is needed because we have too many benchmarks and benchmarking will fail if // we add more without this limit. diff --git a/substrate/frame/balances/src/lib.rs b/substrate/frame/balances/src/lib.rs index 80278752207..685b12499ac 100644 --- a/substrate/frame/balances/src/lib.rs +++ b/substrate/frame/balances/src/lib.rs @@ -17,11 +17,15 @@ //! # Balances Pallet //! -//! The Balances pallet provides functionality for handling accounts and balances. +//! The Balances pallet provides functionality for handling accounts and balances for a single +//! token. //! -//! - [`Config`] -//! - [`Call`] -//! - [`Pallet`] +//! It makes heavy use of concepts such as Holds and Freezes from the +//! [`frame_support::traits::fungible`] traits, therefore you should read and understand those docs +//! as a prerequisite to understanding this pallet. +//! +//! Also see the [`frame_tokens`] reference docs for higher level information regarding the +//! place of this palet in FRAME. //! //! ## Overview //! @@ -38,42 +42,30 @@ //! //! ### Terminology //! -//! - **Existential Deposit:** The minimum balance required to create or keep an account open. This -//! prevents "dust accounts" from filling storage. When the free plus the reserved balance (i.e. -//! the total balance) fall below this, then the account is said to be dead; and it loses its -//! functionality as well as any prior history and all information on it is removed from the -//! chain's state. No account should ever have a total balance that is strictly between 0 and the -//! existential deposit (exclusive). If this ever happens, it indicates either a bug in this -//! pallet or an erroneous raw mutation of storage. -//! -//! - **Total Issuance:** The total number of units in existence in a system. -//! //! - **Reaping an account:** The act of removing an account by resetting its nonce. Happens after -//! its total balance has become zero (or, strictly speaking, less than the Existential Deposit). -//! -//! - **Free Balance:** The portion of a balance that is not reserved. The free balance is the only -//! balance that matters for most operations. +//! its total balance has become less than the Existential Deposit. //! -//! - **Reserved Balance:** Reserved balance still belongs to the account holder, but is suspended. -//! Reserved balance can still be slashed, but only after all the free balance has been slashed. -//! -//! - **Imbalance:** A condition when some funds were credited or debited without equal and opposite -//! accounting (i.e. a difference between total issuance and account balances). Functions that -//! result in an imbalance will return an object of the `Imbalance` trait that can be managed within -//! your runtime logic. (If an imbalance is simply dropped, it should automatically maintain any -//! book-keeping such as total issuance.) +//! ### Implementations //! -//! - **Lock:** A freeze on a specified amount of an account's free balance until a specified block -//! number. Multiple locks always operate over the same funds, so they "overlay" rather than -//! "stack". +//! The Balances pallet provides implementations for the following [`fungible`] traits. If these +//! traits provide the functionality that you need, then you should avoid tight coupling with the +//! Balances pallet. //! -//! ### Implementations +//! - [`fungible::Inspect`] +//! - [`fungible::Mutate`] +//! - [`fungible::Unbalanced`] +//! - [`fungible::Balanced`] +//! - [`fungible::BalancedHold`] +//! - [`fungible::InspectHold`] +//! - [`fungible::MutateHold`] +//! - [`fungible::InspectFreeze`] +//! - [`fungible::MutateFreeze`] +//! - [`fungible::Imbalance`] //! -//! The Balances pallet provides implementations for the following traits. If these traits provide -//! the functionality that you need, then you can avoid coupling with the Balances pallet. +//! It also implements the following [`Currency`] related traits, however they are deprecated and +//! will eventually be removed. //! -//! - [`Currency`]: Functions for dealing with a -//! fungible assets system. +//! - [`Currency`]: Functions for dealing with a fungible assets system. //! - [`ReservableCurrency`] //! - [`NamedReservableCurrency`](frame_support::traits::NamedReservableCurrency): //! Functions for dealing with assets that can be reserved from an account. @@ -83,14 +75,6 @@ //! imbalances between total issuance in the system and account balances. Must be used when a //! function creates new funds (e.g. a reward) or destroys some funds (e.g. a system fee). //! -//! ## Interface -//! -//! ### Dispatchable Functions -//! -//! - `transfer_allow_death` - Transfer some liquid free balance to another account. -//! - `force_set_balance` - Set the balances of a given account. The origin of this call must be -//! root. -//! //! ## Usage //! //! The following examples show how to use the Balances pallet in your custom pallet. @@ -151,8 +135,11 @@ //! * Total issued balanced of all accounts should be less than `Config::Balance::max_value()`. //! * Existential Deposit is set to a value greater than zero. //! -//! Note, you may find the Balances pallet still functions with an ED of zero in some circumstances, -//! however this is not a configuration which is generally supported, nor will it be. +//! Note, you may find the Balances pallet still functions with an ED of zero when the +//! `insecure_zero_ed` cargo feature is enabled. However this is not a configuration which is +//! generally supported, nor will it be. +//! +//! [`frame_tokens`]: ../polkadot_sdk_docs/reference_docs/frame_tokens/index.html #![cfg_attr(not(feature = "std"), no_std)] mod benchmarking; @@ -308,10 +295,14 @@ pub mod pallet { /// The maximum number of locks that should exist on an account. /// Not strictly enforced, but used for weight estimation. + /// + /// Use of locks is deprecated in favour of freezes. See `https://github.com/paritytech/substrate/pull/12951/` #[pallet::constant] type MaxLocks: Get; /// The maximum number of named reserves that can exist on an account. + /// + /// Use of reserves is deprecated in favour of holds. See `https://github.com/paritytech/substrate/pull/12951/` #[pallet::constant] type MaxReserves: Get; @@ -455,6 +446,8 @@ pub mod pallet { /// Any liquidity locks on some account balances. /// NOTE: Should only be accessed when setting, changing and freeing a lock. + /// + /// Use of locks is deprecated in favour of freezes. See `https://github.com/paritytech/substrate/pull/12951/` #[pallet::storage] #[pallet::getter(fn locks)] pub type Locks, I: 'static = ()> = StorageMap< @@ -466,6 +459,8 @@ pub mod pallet { >; /// Named reserves on some account balances. + /// + /// Use of reserves is deprecated in favour of holds. See `https://github.com/paritytech/substrate/pull/12951/` #[pallet::storage] #[pallet::getter(fn reserves)] pub type Reserves, I: 'static = ()> = StorageMap< diff --git a/substrate/frame/support/src/traits/tokens/currency.rs b/substrate/frame/support/src/traits/tokens/currency.rs index 282e7f64473..b3db4c98001 100644 --- a/substrate/frame/support/src/traits/tokens/currency.rs +++ b/substrate/frame/support/src/traits/tokens/currency.rs @@ -16,6 +16,9 @@ // limitations under the License. //! The Currency trait and associated types. +//! +//! Note Currency and related traits are deprecated, instead +//! [`fungible`](frame_support::traits::fungible) traits should be used. use super::{ imbalance::{Imbalance, SignedImbalance}, diff --git a/substrate/frame/support/src/traits/tokens/fungible/freeze.rs b/substrate/frame/support/src/traits/tokens/fungible/freeze.rs index 8b542ee4c60..96efbc6ab89 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/freeze.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/freeze.rs @@ -16,6 +16,9 @@ // limitations under the License. //! The traits for putting freezes within a single fungible token class. +//! +//! See the [`crate::traits::fungible`] doc for more information about fungible traits +//! including the place of the Freezes in FRAME. use scale_info::TypeInfo; use sp_arithmetic::{ @@ -35,7 +38,7 @@ pub trait Inspect: super::Inspect { /// An identifier for a freeze. type Id: codec::Encode + TypeInfo + 'static; - /// Amount of funds held in reserve by `who` for the given `id`. + /// Amount of funds frozen in reserve by `who` for the given `id`. fn balance_frozen(id: &Self::Id, who: &AccountId) -> Self::Balance; /// The amount of the balance which can become frozen. Defaults to `total_balance()`. @@ -45,11 +48,11 @@ pub trait Inspect: super::Inspect { /// Returns `true` if it's possible to introduce a freeze for the given `id` onto the /// account of `who`. This will be true as long as the implementor supports as many - /// concurrent freeze locks as there are possible values of `id`. + /// concurrent freezes as there are possible values of `id`. fn can_freeze(id: &Self::Id, who: &AccountId) -> bool; } -/// Trait for introducing, altering and removing locks to freeze an account's funds so they never +/// Trait for introducing, altering and removing freezes for an account for its funds never /// go below a set minimum. pub trait Mutate: Inspect { /// Prevent actions which would reduce the balance of the account of `who` below the given @@ -66,16 +69,16 @@ pub trait Mutate: Inspect { /// counteract any pre-existing freezes in place for `who` under the `id`. Also unlike /// `set_freeze`, in the case that `amount` is zero, this is no-op and never fails. /// - /// Note that more funds can be locked than the total balance, if desired. + /// Note that more funds can be frozen than the total balance, if desired. fn extend_freeze(id: &Self::Id, who: &AccountId, amount: Self::Balance) -> DispatchResult; - /// Remove an existing lock. + /// Remove an existing freeze. fn thaw(id: &Self::Id, who: &AccountId) -> DispatchResult; /// Attempt to alter the amount frozen under the given `id` to `amount`. /// /// Fail if the account of `who` has fewer freezable funds than `amount`, unless `fortitude` is - /// `Fortitude::Force`. + /// [`Fortitude::Force`]. fn set_frozen( id: &Self::Id, who: &AccountId, @@ -91,7 +94,7 @@ pub trait Mutate: Inspect { /// the amount frozen under `id`. Do nothing otherwise. /// /// Fail if the account of `who` has fewer freezable funds than `amount`, unless `fortitude` is - /// `Fortitude::Force`. + /// [`Fortitude::Force`]. fn ensure_frozen( id: &Self::Id, who: &AccountId, diff --git a/substrate/frame/support/src/traits/tokens/fungible/hold.rs b/substrate/frame/support/src/traits/tokens/fungible/hold.rs index 6da652d2998..28ece25c91d 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/hold.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/hold.rs @@ -16,6 +16,9 @@ // limitations under the License. //! The traits for putting holds within a single fungible token class. +//! +//! See the [`crate::traits::fungible`] doc for more information about fungible traits +//! including the place of the Holds in FRAME. use crate::{ ensure, @@ -214,8 +217,8 @@ pub trait Mutate: /// /// The actual amount released is returned with `Ok`. /// - /// If `precision` is `BestEffort`, then the amount actually unreserved and returned as the - /// inner value of `Ok` may be smaller than the `amount` passed. + /// If `precision` is [`Precision::BestEffort`], then the amount actually unreserved and + /// returned as the inner value of `Ok` may be smaller than the `amount` passed. /// /// NOTE! The inner of the `Ok` result variant returns the *actual* amount released. This is the /// opposite of the `ReservableCurrency::unreserve()` result, which gives the amount not able diff --git a/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs b/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs index 0e251021970..020dffe28c8 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs @@ -17,6 +17,8 @@ //! The imbalance type and its associates, which handles keeps everything adding up properly with //! unbalanced operations. +//! +//! See the [`crate::traits::fungible`] doc for more information about fungible traits. use super::{super::Imbalance as ImbalanceT, Balanced, *}; use crate::traits::{ diff --git a/substrate/frame/support/src/traits/tokens/fungible/item_of.rs b/substrate/frame/support/src/traits/tokens/fungible/item_of.rs index 37749d39600..5374cc52bab 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/item_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/item_of.rs @@ -16,6 +16,11 @@ // limitations under the License. //! Adapter to use `fungibles::*` implementations as `fungible::*`. +//! +//! This allows for a `fungibles` asset, e.g. from the `pallet_assets` pallet, to be used when a +//! `fungible` asset is expected. +//! +//! See the [`crate::traits::fungible`] doc for more information about fungible traits. use super::*; use crate::traits::{ diff --git a/substrate/frame/support/src/traits/tokens/fungible/mod.rs b/substrate/frame/support/src/traits/tokens/fungible/mod.rs index ba4a2e5e21a..4a0cda2dbc7 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/mod.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/mod.rs @@ -17,26 +17,135 @@ //! The traits for dealing with a single fungible token class and any associated types. //! -//! ### User-implememted traits -//! - `Inspect`: Regular balance inspector functions. -//! - `Unbalanced`: Low-level balance mutating functions. Does not guarantee proper book-keeping and -//! so should not be called into directly from application code. Other traits depend on this and -//! provide default implementations based on it. -//! - `UnbalancedHold`: Low-level balance mutating functions for balances placed on hold. Does not +//! Also see the [`frame_tokens`] reference docs for more information about the place of +//! `fungible` traits in Substrate. +//! +//! # Avaliable Traits +//! - [`Inspect`]: Regular balance inspector functions. +//! - [`Unbalanced`]: Low-level balance mutating functions. Does not guarantee proper book-keeping +//! and so should not be called into directly from application code. Other traits depend on this +//! and provide default implementations based on it. +//! - [`UnbalancedHold`]: Low-level balance mutating functions for balances placed on hold. Does not //! guarantee proper book-keeping and so should not be called into directly from application code. //! Other traits depend on this and provide default implementations based on it. -//! - `Mutate`: Regular balance mutator functions. Pre-implemented using `Unbalanced`, though the -//! `done_*` functions should likely be reimplemented in case you want to do something following -//! the operation such as emit events. -//! - `InspectHold`: Inspector functions for balances on hold. -//! - `MutateHold`: Mutator functions for balances on hold. Mostly pre-implemented using -//! `UnbalancedHold`. -//! - `InspectFreeze`: Inspector functions for frozen balance. -//! - `MutateFreeze`: Mutator functions for frozen balance. -//! - `Balanced`: One-sided mutator functions for regular balances, which return imbalance objects +//! - [`Mutate`]: Regular balance mutator functions. Pre-implemented using [`Unbalanced`], though +//! the `done_*` functions should likely be reimplemented in case you want to do something +//! following the operation such as emit events. +//! - [`InspectHold`]: Inspector functions for balances on hold. +//! - [`MutateHold`]: Mutator functions for balances on hold. Mostly pre-implemented using +//! [`UnbalancedHold`]. +//! - [`InspectFreeze`]: Inspector functions for frozen balance. +//! - [`MutateFreeze`]: Mutator functions for frozen balance. +//! - [`Balanced`]: One-sided mutator functions for regular balances, which return imbalance objects //! which guarantee eventual book-keeping. May be useful for some sophisticated operations where //! funds must be removed from an account before it is known precisely what should be done with //! them. +//! +//! ## Terminology +//! +//! - **Total Issuance**: The total number of units in existence in a system. +//! +//! - **Total Balance**: The sum of an account's free and held balances. +//! +//! - **Free Balance**: A portion of an account's total balance that is not held. Note this is +//! distinct from the Spendable Balance, which represents how much Balance the user can actually +//! transfer. +//! +//! - **Held Balance**: Held balance still belongs to the account holder, but is suspended. It can +//! be slashed, but only after all the free balance has been slashed. +//! +//! Multiple holds stack rather than overlay. This means that if an account has +//! 3 holds for 100 units, the account can spend its funds for any reason down to 300 units, at +//! which point the holds will start to come into play. +//! +//! - **Frozen Balance**: A freeze on a specified amount of an account's free balance until a +//! specified block number. +//! +//! Multiple freezes always operate over the same funds, so they "overlay" rather than +//! "stack". This means that if an account has 3 freezes for 100 units, the account can spend its +//! funds for any reason down to 100 units, at which point the freezes will start to come into +//! play. +//! +//! - **Minimum Balance (a.k.a. Existential Deposit, a.k.a. ED)**: The minimum balance required to +//! create or keep an account open. This is to prevent "dust accounts" from filling storage. When +//! the free plus the held balance (i.e. the total balance) falls below this, then the account is +//! said to be dead. It loses its functionality as well as any prior history and all information +//! on it is removed from the chain's state. No account should ever have a total balance that is +//! strictly between 0 and the existential deposit (exclusive). If this ever happens, it indicates +//! either a bug in the implementation of this trait or an erroneous raw mutation of storage. +//! +//! - **Untouchable Balance**: The part of a user's free balance they cannot spend, due to ED or +//! Freeze(s). +//! +//! - **Spendable Balance**: The part of a user's free balance they can actually transfer, after +//! accounting for Holds and Freezes. +//! +//! - **Imbalance**: A condition when some funds were credited or debited without equal and opposite +//! accounting (i.e. a difference between total issuance and account balances). Functions that +//! result in an imbalance will return an object of the [`imbalance::Credit`] or +//! [`imbalance::Debt`] traits that can be managed within your runtime logic. +//! +//! If an imbalance is simply dropped, it should automatically maintain any book-keeping such as +//! total issuance. +//! +//! ## Visualising Balance Components Together 💫 +//! +//! ```ignore +//! |__total__________________________________| +//! |__on_hold__|_____________free____________| +//! |__________frozen___________| +//! |__on_hold__|__ed__| +//! |__untouchable__|__spendable__| +//! ``` +//! +//! ## Holds and Freezes +//! +//! Both holds and freezes are used to prevent an account from using some of its balance. +//! +//! The primary distinction between the two are that: +//! - Holds are cumulative (do not overlap) and are distinct from the free balance +//! - Freezes are not cumulative, and can overlap with each other or with holds +//! +//! ```ignore +//! |__total_____________________________| +//! |__hold_a__|__hold_b__|_____free_____| +//! |__on_hold____________| // <- the sum of all holds +//! |__freeze_a_______________| +//! |__freeze_b____| +//! |__freeze_c________| +//! |__frozen_________________| // <- the max of all freezes +//! ``` +//! +//! Holds are designed to be infallibly slashed, meaning that any logic using a `Freeze` +//! must handle the possibility of the frozen amount being reduced, potentially to zero. A +//! permissionless function should be provided in order to allow bookkeeping to be updated in this +//! instance. E.g. some balance is frozen when it is used for voting, one could use held balance for +//! voting, but nothing prevents this frozen balance from being reduced if the overlapping hold is +//! slashed. +//! +//! Every Hold and Freeze is accompanied by a unique `Reason`, making it clear for each instance +//! what the originating pallet and purpose is. These reasons are amalgomated into a single enum +//! `RuntimeHoldReason` and `RuntimeFreezeReason` respectively, when the runtime is compiled. +//! +//! Note that `Hold` and `Freeze` reasons should remain in your runtime for as long as storage +//! could exist in your runtime with those reasons, otherwise your runtime state could become +//! undecodable. +//! +//! ### Should I use a Hold or Freeze? +//! +//! If you require a balance to be infaillibly slashed, then you should use Holds. +//! +//! If you require setting a minimum account balance amount, then you should use a Freezes. Note +//! Freezes do not carry the same guarantees as Holds. Although the account cannot voluntarily +//! reduce their balance below the largest freeze, if Holds on the account are slashed then the +//! balance could drop below the freeze amount. +//! +//! ## Sets of Tokens +//! +//! For managing sets of tokens, see the [`fungibles`](`frame_support::traits::fungibles`) trait +//! which is a wrapper around this trait but supporting multiple asset instances. +//! +//! [`frame_tokens`]: ../../../../polkadot_sdk_docs/reference_docs/frame_tokens/index.html pub mod conformance_tests; pub mod freeze; diff --git a/substrate/frame/support/src/traits/tokens/fungible/regular.rs b/substrate/frame/support/src/traits/tokens/fungible/regular.rs index 0157b08bd13..4ed31dcf9fb 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/regular.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/regular.rs @@ -16,6 +16,8 @@ // limitations under the License. //! `Inspect` and `Mutate` traits for working with regular balances. +//! +//! See the [`crate::traits::fungible`] doc for more information about fungible traits. use crate::{ ensure, diff --git a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs index 33711d7a16c..575b771a614 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs @@ -17,6 +17,8 @@ //! Types to combine some `fungible::*` and `fungibles::*` implementations into one union //! `fungibles::*` implementation. +//! +//! See the [`crate::traits::fungible`] doc for more information about fungible traits. use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::traits::{ diff --git a/substrate/frame/support/src/traits/tokens/fungibles/approvals.rs b/substrate/frame/support/src/traits/tokens/fungibles/approvals.rs index 7a80279b019..09e3d20756a 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/approvals.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/approvals.rs @@ -16,6 +16,8 @@ // limitations under the License. //! Inspect and Mutate traits for Asset approvals +//! +//! See the [`crate::traits::fungibles`] doc for more information about fungibles traits. use crate::dispatch::DispatchResult; pub trait Inspect: super::Inspect { diff --git a/substrate/frame/support/src/traits/tokens/fungibles/enumerable.rs b/substrate/frame/support/src/traits/tokens/fungibles/enumerable.rs index 08bb784a7db..81dbb93b0b8 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/enumerable.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/enumerable.rs @@ -15,6 +15,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! Contains an interface for enumerating assets in existence or owned by a given account. +//! +//! See the [`crate::traits::fungibles`] doc for more information about fungibles traits. + /// Interface for enumerating assets in existence or owned by a given account. pub trait Inspect: super::Inspect { type AssetsIterator; diff --git a/substrate/frame/support/src/traits/tokens/fungibles/freeze.rs b/substrate/frame/support/src/traits/tokens/fungibles/freeze.rs index b07d20d6c41..244f7005899 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/freeze.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/freeze.rs @@ -16,6 +16,8 @@ // limitations under the License. //! The traits for putting freezes within a single fungible token class. +//! +//! See the [`crate::traits::fungibles`] doc for more information about fungibles traits. use crate::{ensure, traits::tokens::Fortitude}; use scale_info::TypeInfo; diff --git a/substrate/frame/support/src/traits/tokens/fungibles/hold.rs b/substrate/frame/support/src/traits/tokens/fungibles/hold.rs index 1efd1594213..ef3fef7a300 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/hold.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/hold.rs @@ -16,6 +16,8 @@ // limitations under the License. //! The traits for putting holds within a single fungible token class. +//! +//! See the [`crate::traits::fungibles`] doc for more information about fungibles traits. use crate::{ ensure, diff --git a/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs b/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs index 54c1e900b6e..bb0d83721a4 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs @@ -17,6 +17,8 @@ //! The imbalance type and its associates, which handles keeps everything adding up properly with //! unbalanced operations. +//! +//! See the [`crate::traits::fungibles`] doc for more information about fungibles traits. use super::*; use crate::traits::{ diff --git a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs index 0e195a52318..49f6c846ccd 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs @@ -16,6 +16,8 @@ // limitations under the License. //! Traits for creating and destroying assets. +//! +//! See the [`crate::traits::fungibles`] doc for more information about fungibles traits. use sp_runtime::{DispatchError, DispatchResult}; diff --git a/substrate/frame/support/src/traits/tokens/fungibles/metadata.rs b/substrate/frame/support/src/traits/tokens/fungibles/metadata.rs index ab310119e58..ab722426dad 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/metadata.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/metadata.rs @@ -16,6 +16,8 @@ // limitations under the License. //! Inspect and Mutate traits for Asset metadata +//! +//! See the [`crate::traits::fungibles`] doc for more information about fungibles traits. use crate::dispatch::DispatchResult; use sp_std::vec::Vec; diff --git a/substrate/frame/support/src/traits/tokens/fungibles/mod.rs b/substrate/frame/support/src/traits/tokens/fungibles/mod.rs index 1db0706ba4f..2122fdeaed3 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/mod.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/mod.rs @@ -15,7 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! The traits for sets of fungible tokens and any associated types. +//! The traits for *sets* of [`fungible`](`frame_support::traits::fungible`) tokens and any +//! associated types. +//! +//! Individual tokens in the `fungibles` set may be used when a `fungible` trait is expected using +//! [`crate::traits::tokens::fungible::ItemOf`]. +//! +//! Also see the [`frame_tokens`] reference docs for more information about the place of +//! `fungible` traits in Substrate. +//! +//! [`frame_tokens`]: ../../../../polkadot_sdk_docs/reference_docs/frame_tokens/index.html pub mod approvals; mod enumerable; diff --git a/substrate/frame/support/src/traits/tokens/fungibles/regular.rs b/substrate/frame/support/src/traits/tokens/fungibles/regular.rs index 8cc97802da6..b30e0ae3a2a 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/regular.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/regular.rs @@ -16,6 +16,8 @@ // limitations under the License. //! `Inspect` and `Mutate` traits for working with regular balances. +//! +//! See the [`crate::traits::fungibles`] doc for more information about fungibles traits. use sp_std::marker::PhantomData; diff --git a/substrate/frame/support/src/traits/tokens/fungibles/roles.rs b/substrate/frame/support/src/traits/tokens/fungibles/roles.rs index 5cd1228afbc..4f95ad8368c 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/roles.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/roles.rs @@ -16,6 +16,8 @@ // limitations under the License. //! Inspect traits for Asset roles +//! +//! See the [`crate::traits::fungibles`] doc for more information about fungibles traits. pub trait Inspect: super::Inspect { // Get owner for an AssetId. diff --git a/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs b/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs index 9d2a783df2a..c8a1ec37e78 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs @@ -16,6 +16,8 @@ // limitations under the License. //! Type to combine two `fungibles::*` implementations into one union `fungibles::*` implementation. +//! +//! See the [`crate::traits::fungibles`] doc for more information about fungibles traits. use frame_support::traits::{ tokens::{ -- GitLab From 256d5aefdc83928090aa2e3f8c022484fab38e0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sun, 31 Mar 2024 22:47:01 +0200 Subject: [PATCH 129/187] Revert log level changes (#3913) Closes: https://github.com/paritytech/polkadot-sdk/issues/3906 --- polkadot/node/network/gossip-support/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/node/network/gossip-support/src/lib.rs b/polkadot/node/network/gossip-support/src/lib.rs index 9f33cd5d8a3..4dfdd1f7208 100644 --- a/polkadot/node/network/gossip-support/src/lib.rs +++ b/polkadot/node/network/gossip-support/src/lib.rs @@ -508,7 +508,7 @@ where ); } let pretty = PrettyAuthorities(unconnected_authorities); - gum::info!( + gum::debug!( target: LOG_TARGET, ?connected_ratio, ?absolute_connected, -- GitLab From aa44384e05e05705cbdfacd8d73972404be4be6f Mon Sep 17 00:00:00 2001 From: gemini132 <164285545+gemini132@users.noreply.github.com> Date: Mon, 1 Apr 2024 06:28:38 +0800 Subject: [PATCH 130/187] Fix two typos (#3812) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher -- GitLab From a2c9ab8c043221f4902739d678739b1fa9319cef Mon Sep 17 00:00:00 2001 From: Matteo Muraca <56828990+muraca@users.noreply.github.com> Date: Mon, 1 Apr 2024 07:17:20 +0200 Subject: [PATCH 131/187] Removed `pallet::getter` usage from `pallet-alliance` (#3738) Part of #3326 cc @kianenigma @ggwpez @liamaharon polkadot address: 12poSUQPtcF1HUPQGY3zZu2P8emuW9YnsPduA4XG3oCEfJVp --------- Signed-off-by: Matteo Muraca Co-authored-by: Liam Aharon Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- prdoc/pr_3738.prdoc | 14 +++++ substrate/frame/alliance/src/benchmarking.rs | 10 ++-- substrate/frame/alliance/src/lib.rs | 7 --- substrate/frame/alliance/src/migration.rs | 12 ++--- substrate/frame/alliance/src/tests.rs | 55 +++++++++++--------- 5 files changed, 54 insertions(+), 44 deletions(-) create mode 100644 prdoc/pr_3738.prdoc diff --git a/prdoc/pr_3738.prdoc b/prdoc/pr_3738.prdoc new file mode 100644 index 00000000000..cbf19b95c36 --- /dev/null +++ b/prdoc/pr_3738.prdoc @@ -0,0 +1,14 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Removed `pallet::getter` usage from `pallet-alliance` + +doc: + - audience: Runtime Dev + description: | + This PR removes `pallet::getter` usage from `pallet-alliance`, and updates dependant code accordingly. + The syntax `StorageItem::::get()` should be used instead. + +crates: + - name: pallet-alliance + bump: major diff --git a/substrate/frame/alliance/src/benchmarking.rs b/substrate/frame/alliance/src/benchmarking.rs index 4ccd0fc08f6..710c32a848d 100644 --- a/substrate/frame/alliance/src/benchmarking.rs +++ b/substrate/frame/alliance/src/benchmarking.rs @@ -505,8 +505,8 @@ mod benchmarks { assert_last_event::( Event::MembersInitialized { fellows: fellows.clone(), allies: allies.clone() }.into(), ); - assert_eq!(Alliance::::members(MemberRole::Fellow), fellows); - assert_eq!(Alliance::::members(MemberRole::Ally), allies); + assert_eq!(Members::::get(MemberRole::Fellow), fellows); + assert_eq!(Members::::get(MemberRole::Ally), allies); Ok(()) } @@ -563,7 +563,7 @@ mod benchmarks { { call.dispatch_bypass_filter(origin)?; } - assert_eq!(Alliance::::rule(), Some(rule.clone())); + assert_eq!(Rule::::get(), Some(rule.clone())); assert_last_event::(Event::NewRuleSet { rule }.into()); Ok(()) } @@ -583,7 +583,7 @@ mod benchmarks { call.dispatch_bypass_filter(origin)?; } - assert!(Alliance::::announcements().contains(&announcement)); + assert!(Announcements::::get().contains(&announcement)); assert_last_event::(Event::Announced { announcement }.into()); Ok(()) } @@ -606,7 +606,7 @@ mod benchmarks { call.dispatch_bypass_filter(origin)?; } - assert!(!Alliance::::announcements().contains(&announcement)); + assert!(!Announcements::::get().contains(&announcement)); assert_last_event::(Event::AnnouncementRemoved { announcement }.into()); Ok(()) } diff --git a/substrate/frame/alliance/src/lib.rs b/substrate/frame/alliance/src/lib.rs index 414d550c53a..1f06241e9c8 100644 --- a/substrate/frame/alliance/src/lib.rs +++ b/substrate/frame/alliance/src/lib.rs @@ -442,24 +442,20 @@ pub mod pallet { /// The IPFS CID of the alliance rule. /// Fellows can propose a new rule with a super-majority. #[pallet::storage] - #[pallet::getter(fn rule)] pub type Rule, I: 'static = ()> = StorageValue<_, Cid, OptionQuery>; /// The current IPFS CIDs of any announcements. #[pallet::storage] - #[pallet::getter(fn announcements)] pub type Announcements, I: 'static = ()> = StorageValue<_, BoundedVec, ValueQuery>; /// Maps members to their candidacy deposit. #[pallet::storage] - #[pallet::getter(fn deposit_of)] pub type DepositOf, I: 'static = ()> = StorageMap<_, Blake2_128Concat, T::AccountId, BalanceOf, OptionQuery>; /// Maps member type to members of each type. #[pallet::storage] - #[pallet::getter(fn members)] pub type Members, I: 'static = ()> = StorageMap< _, Twox64Concat, @@ -471,20 +467,17 @@ pub mod pallet { /// A set of members who gave a retirement notice. They can retire after the end of retirement /// period stored as a future block number. #[pallet::storage] - #[pallet::getter(fn retiring_members)] pub type RetiringMembers, I: 'static = ()> = StorageMap<_, Blake2_128Concat, T::AccountId, BlockNumberFor, OptionQuery>; /// The current list of accounts deemed unscrupulous. These accounts non grata cannot submit /// candidacy. #[pallet::storage] - #[pallet::getter(fn unscrupulous_accounts)] pub type UnscrupulousAccounts, I: 'static = ()> = StorageValue<_, BoundedVec, ValueQuery>; /// The current list of websites deemed unscrupulous. #[pallet::storage] - #[pallet::getter(fn unscrupulous_websites)] pub type UnscrupulousWebsites, I: 'static = ()> = StorageValue<_, BoundedVec, T::MaxUnscrupulousItems>, ValueQuery>; diff --git a/substrate/frame/alliance/src/migration.rs b/substrate/frame/alliance/src/migration.rs index 432f09a16f4..b4ecc181944 100644 --- a/substrate/frame/alliance/src/migration.rs +++ b/substrate/frame/alliance/src/migration.rs @@ -162,18 +162,18 @@ pub(crate) mod v1_to_v2 { #[cfg(test)] mod test { use super::*; - use crate::{mock::*, MemberRole}; + use crate::{mock::*, MemberRole, Members}; #[test] fn migration_v1_to_v2_works() { new_test_ext().execute_with(|| { assert_ok!(Alliance::join_alliance(RuntimeOrigin::signed(4))); - assert_eq!(Alliance::members(MemberRole::Ally), vec![4]); - assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2, 3]); + assert_eq!(Members::::get(MemberRole::Ally), vec![4]); + assert_eq!(Members::::get(MemberRole::Fellow), vec![1, 2, 3]); v1_to_v2::migrate::(); - assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2, 3, 4]); - assert_eq!(Alliance::members(MemberRole::Ally), vec![]); - assert_eq!(Alliance::members(MemberRole::Retiring), vec![]); + assert_eq!(Members::::get(MemberRole::Fellow), vec![1, 2, 3, 4]); + assert_eq!(Members::::get(MemberRole::Ally), vec![]); + assert_eq!(Members::::get(MemberRole::Retiring), vec![]); }); } } diff --git a/substrate/frame/alliance/src/tests.rs b/substrate/frame/alliance/src/tests.rs index c65f10228e7..edb515b8115 100644 --- a/substrate/frame/alliance/src/tests.rs +++ b/substrate/frame/alliance/src/tests.rs @@ -21,7 +21,7 @@ use frame_support::{assert_noop, assert_ok, error::BadOrigin}; use frame_system::{EventRecord, Phase}; use super::*; -use crate::mock::*; +use crate::{self as alliance, mock::*}; type AllianceMotionEvent = pallet_collective::Event; @@ -118,7 +118,7 @@ fn disband_works() { // join alliance and reserve funds assert_eq!(Balances::free_balance(9), 1000 - id_deposit); assert_ok!(Alliance::join_alliance(RuntimeOrigin::signed(9))); - assert_eq!(Alliance::deposit_of(9), Some(expected_join_deposit)); + assert_eq!(alliance::DepositOf::::get(9), Some(expected_join_deposit)); assert_eq!(Balances::free_balance(9), 1000 - id_deposit - expected_join_deposit); assert!(Alliance::is_member_of(&9, MemberRole::Ally)); @@ -314,7 +314,7 @@ fn set_rule_works() { new_test_ext().execute_with(|| { let cid = test_cid(); assert_ok!(Alliance::set_rule(RuntimeOrigin::signed(1), cid.clone())); - assert_eq!(Alliance::rule(), Some(cid.clone())); + assert_eq!(alliance::Rule::::get(), Some(cid.clone())); System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::NewRuleSet { rule: cid, @@ -330,7 +330,7 @@ fn announce_works() { assert_noop!(Alliance::announce(RuntimeOrigin::signed(2), cid.clone()), BadOrigin); assert_ok!(Alliance::announce(RuntimeOrigin::signed(3), cid.clone())); - assert_eq!(Alliance::announcements(), vec![cid.clone()]); + assert_eq!(alliance::Announcements::::get(), vec![cid.clone()]); System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::Announced { announcement: cid, @@ -343,7 +343,7 @@ fn remove_announcement_works() { new_test_ext().execute_with(|| { let cid = test_cid(); assert_ok!(Alliance::announce(RuntimeOrigin::signed(3), cid.clone())); - assert_eq!(Alliance::announcements(), vec![cid.clone()]); + assert_eq!(alliance::Announcements::::get(), vec![cid.clone()]); System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::Announced { announcement: cid.clone(), })); @@ -351,7 +351,7 @@ fn remove_announcement_works() { System::set_block_number(2); assert_ok!(Alliance::remove_announcement(RuntimeOrigin::signed(3), cid.clone())); - assert_eq!(Alliance::announcements(), vec![]); + assert_eq!(alliance::Announcements::::get(), vec![]); System::assert_last_event(mock::RuntimeEvent::Alliance( crate::Event::AnnouncementRemoved { announcement: cid }, )); @@ -394,8 +394,8 @@ fn join_alliance_works() { // success to submit assert_ok!(Alliance::join_alliance(RuntimeOrigin::signed(4))); assert_eq!(Balances::free_balance(4), 1000 - id_deposit - join_deposit); - assert_eq!(Alliance::deposit_of(4), Some(25)); - assert_eq!(Alliance::members(MemberRole::Ally), vec![4]); + assert_eq!(alliance::DepositOf::::get(4), Some(25)); + assert_eq!(alliance::Members::::get(MemberRole::Ally), vec![4]); // check already member assert_noop!( @@ -449,8 +449,8 @@ fn nominate_ally_works() { // success to nominate assert_ok!(Alliance::nominate_ally(RuntimeOrigin::signed(1), 4)); - assert_eq!(Alliance::deposit_of(4), None); - assert_eq!(Alliance::members(MemberRole::Ally), vec![4]); + assert_eq!(alliance::DepositOf::::get(4), None); + assert_eq!(alliance::Members::::get(MemberRole::Ally), vec![4]); // check already member assert_noop!( @@ -482,12 +482,12 @@ fn elevate_ally_works() { ); assert_ok!(Alliance::join_alliance(RuntimeOrigin::signed(4))); - assert_eq!(Alliance::members(MemberRole::Ally), vec![4]); - assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2, 3]); + assert_eq!(alliance::Members::::get(MemberRole::Ally), vec![4]); + assert_eq!(alliance::Members::::get(MemberRole::Fellow), vec![1, 2, 3]); assert_ok!(Alliance::elevate_ally(RuntimeOrigin::signed(2), 4)); - assert_eq!(Alliance::members(MemberRole::Ally), Vec::::new()); - assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2, 3, 4]); + assert_eq!(alliance::Members::::get(MemberRole::Ally), Vec::::new()); + assert_eq!(alliance::Members::::get(MemberRole::Fellow), vec![1, 2, 3, 4]); }); } @@ -499,10 +499,10 @@ fn give_retirement_notice_work() { Error::::NotMember ); - assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2, 3]); + assert_eq!(alliance::Members::::get(MemberRole::Fellow), vec![1, 2, 3]); assert_ok!(Alliance::give_retirement_notice(RuntimeOrigin::signed(3))); - assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2]); - assert_eq!(Alliance::members(MemberRole::Retiring), vec![3]); + assert_eq!(alliance::Members::::get(MemberRole::Fellow), vec![1, 2]); + assert_eq!(alliance::Members::::get(MemberRole::Retiring), vec![3]); System::assert_last_event(mock::RuntimeEvent::Alliance( crate::Event::MemberRetirementPeriodStarted { member: (3) }, )); @@ -527,7 +527,7 @@ fn retire_works() { Error::::RetirementNoticeNotGiven ); - assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2, 3]); + assert_eq!(alliance::Members::::get(MemberRole::Fellow), vec![1, 2, 3]); assert_ok!(Alliance::give_retirement_notice(RuntimeOrigin::signed(3))); assert_noop!( Alliance::retire(RuntimeOrigin::signed(3)), @@ -535,7 +535,7 @@ fn retire_works() { ); System::set_block_number(System::block_number() + RetirementPeriod::get()); assert_ok!(Alliance::retire(RuntimeOrigin::signed(3))); - assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2]); + assert_eq!(alliance::Members::::get(MemberRole::Fellow), vec![1, 2]); System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::MemberRetired { member: (3), unreserved: None, @@ -551,7 +551,7 @@ fn retire_works() { #[test] fn abdicate_works() { new_test_ext().execute_with(|| { - assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2, 3]); + assert_eq!(alliance::Members::::get(MemberRole::Fellow), vec![1, 2, 3]); assert_ok!(Alliance::abdicate_fellow_status(RuntimeOrigin::signed(3))); System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::FellowAbdicated { @@ -573,9 +573,9 @@ fn kick_member_works() { ); >::insert(2, 25); - assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2, 3]); + assert_eq!(alliance::Members::::get(MemberRole::Fellow), vec![1, 2, 3]); assert_ok!(Alliance::kick_member(RuntimeOrigin::signed(2), 2)); - assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 3]); + assert_eq!(alliance::Members::::get(MemberRole::Fellow), vec![1, 3]); assert_eq!(>::get(2), None); System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::MemberKicked { member: (2), @@ -596,8 +596,11 @@ fn add_unscrupulous_items_works() { UnscrupulousItem::Website("abc".as_bytes().to_vec().try_into().unwrap()) ] )); - assert_eq!(Alliance::unscrupulous_accounts().into_inner(), vec![3]); - assert_eq!(Alliance::unscrupulous_websites().into_inner(), vec!["abc".as_bytes().to_vec()]); + assert_eq!(alliance::UnscrupulousAccounts::::get().into_inner(), vec![3]); + assert_eq!( + alliance::UnscrupulousWebsites::::get().into_inner(), + vec!["abc".as_bytes().to_vec()] + ); assert_noop!( Alliance::add_unscrupulous_items( @@ -629,12 +632,12 @@ fn remove_unscrupulous_items_works() { RuntimeOrigin::signed(3), vec![UnscrupulousItem::AccountId(3)] )); - assert_eq!(Alliance::unscrupulous_accounts(), vec![3]); + assert_eq!(alliance::UnscrupulousAccounts::::get(), vec![3]); assert_ok!(Alliance::remove_unscrupulous_items( RuntimeOrigin::signed(3), vec![UnscrupulousItem::AccountId(3)] )); - assert_eq!(Alliance::unscrupulous_accounts(), Vec::::new()); + assert_eq!(alliance::UnscrupulousAccounts::::get(), Vec::::new()); }); } -- GitLab From e0c081dbd46c1e6edca1ce2c62298f5f3622afdd Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <49718502+alexggh@users.noreply.github.com> Date: Mon, 1 Apr 2024 09:29:22 +0300 Subject: [PATCH 132/187] network:bridge: fix peer_count metric (#3711) The metric records the current protocol_version of the validator that just connected with the peer_map.len(), which contains all peers that connected, that has the effect the metric will be wrong since it won't tell us how many peers we have connected per version because it will always record the total number of peers Fix this by counting by version inside peer_map, additionally because that might be a bit heavier than len(), publish it only on-active leaves. --------- Signed-off-by: Alexandru Gheorghe --- polkadot/node/network/bridge/src/lib.rs | 24 ++++++++++++++++++++++ polkadot/node/network/bridge/src/rx/mod.rs | 6 +----- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/polkadot/node/network/bridge/src/lib.rs b/polkadot/node/network/bridge/src/lib.rs index ddce99d5c2a..0305aaa067c 100644 --- a/polkadot/node/network/bridge/src/lib.rs +++ b/polkadot/node/network/bridge/src/lib.rs @@ -102,6 +102,30 @@ struct SharedInner { collation_peers: HashMap, } +// Counts the number of peers that are connectioned using `version` +fn count_peers_by_version(peers: &HashMap) -> HashMap { + let mut by_version_count = HashMap::new(); + for peer in peers.values() { + *(by_version_count.entry(peer.version).or_default()) += 1; + } + by_version_count +} + +// Notes the peer count +fn note_peers_count(metrics: &Metrics, shared: &Shared) { + let guard = shared.0.lock(); + let validation_stats = count_peers_by_version(&guard.validation_peers); + let collation_stats = count_peers_by_version(&guard.collation_peers); + + for (version, count) in validation_stats { + metrics.note_peer_count(PeerSet::Validation, version, count) + } + + for (version, count) in collation_stats { + metrics.note_peer_count(PeerSet::Collation, version, count) + } +} + pub(crate) enum Mode { Syncing(Box), Active, diff --git a/polkadot/node/network/bridge/src/rx/mod.rs b/polkadot/node/network/bridge/src/rx/mod.rs index 11ac73259e3..0a4497fc4b5 100644 --- a/polkadot/node/network/bridge/src/rx/mod.rs +++ b/polkadot/node/network/bridge/src/rx/mod.rs @@ -262,7 +262,6 @@ async fn handle_validation_message( } metrics.on_peer_connected(peer_set, version); - metrics.note_peer_count(peer_set, version, peer_map.len()); shared.local_view.clone().unwrap_or(View::default()) }; @@ -320,8 +319,6 @@ async fn handle_validation_message( let w = peer_map.remove(&peer).is_some(); metrics.on_peer_disconnected(peer_set, version); - metrics.note_peer_count(peer_set, version, peer_map.len()); - w }; @@ -524,7 +521,6 @@ async fn handle_collation_message( } metrics.on_peer_connected(peer_set, version); - metrics.note_peer_count(peer_set, version, peer_map.len()); shared.local_view.clone().unwrap_or(View::default()) }; @@ -575,7 +571,6 @@ async fn handle_collation_message( let w = peer_map.remove(&peer).is_some(); metrics.on_peer_disconnected(peer_set, version); - metrics.note_peer_count(peer_set, version, peer_map.len()); w }; @@ -832,6 +827,7 @@ where &metrics, ¬ification_sinks, ); + note_peers_count(&metrics, &shared); } } }, -- GitLab From 8d305343c7a488d3e8504600b5d9f94af899f25b Mon Sep 17 00:00:00 2001 From: Alessandro Siniscalchi Date: Mon, 1 Apr 2024 10:54:23 +0200 Subject: [PATCH 133/187] [parachain-template] pallet configurations into `mod configs` (#3809) This PR introduces a refactor of the parachain runtime configuration by consolidating all pallet configurations into a new module named `configs`. This change aims to improve the readability and maintainability of the runtime configuration by centralizing all configuration parameters. ## Changes - **Creation of `configs.rs`**: A new file `configs.rs` has been added under `templates/parachain/runtime/src/`, containing all the runtime configurations previously scattered across `lib.rs`. - **Refactoring of `lib.rs`**: The `lib.rs` file has been significantly slimmed down by removing the inline pallet configurations and importing them from `configs.rs` instead. - **Optimization of Import Statements**: Reorganized import statements to clarify the runtime's dependency structure. ### Benefits - **Improved Readability**: With configurations being centralized, developers can now easily locate and review runtime parameters without navigating through the `lib.rs` file. This refactor does not introduce any changes to the runtime logic but improves the project structure for better development experience. --------- Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- templates/parachain/runtime/src/apis.rs | 2 +- .../parachain/runtime/src/configs/mod.rs | 311 ++++++++++++++++++ .../runtime/src/{ => configs}/xcm_config.rs | 2 +- templates/parachain/runtime/src/lib.rs | 276 +--------------- 4 files changed, 317 insertions(+), 274 deletions(-) create mode 100644 templates/parachain/runtime/src/configs/mod.rs rename templates/parachain/runtime/src/{ => configs}/xcm_config.rs (99%) diff --git a/templates/parachain/runtime/src/apis.rs b/templates/parachain/runtime/src/apis.rs index aa0cae843c3..74c7476e152 100644 --- a/templates/parachain/runtime/src/apis.rs +++ b/templates/parachain/runtime/src/apis.rs @@ -193,7 +193,7 @@ impl_runtime_apis! { #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { - use super::RuntimeBlockWeights; + use super::configs::RuntimeBlockWeights; let weight = Executive::try_runtime_upgrade(checks).unwrap(); (weight, RuntimeBlockWeights::get().max_block) diff --git a/templates/parachain/runtime/src/configs/mod.rs b/templates/parachain/runtime/src/configs/mod.rs new file mode 100644 index 00000000000..e2c51e07d37 --- /dev/null +++ b/templates/parachain/runtime/src/configs/mod.rs @@ -0,0 +1,311 @@ +// This is free and unencumbered software released into the public domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +// For more information, please refer to + +mod xcm_config; + +// Substrate and Polkadot dependencies +use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; +use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; +use frame_support::{ + derive_impl, + dispatch::DispatchClass, + parameter_types, + traits::{ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, TransformOrigin}, + weights::{ConstantMultiplier, Weight}, + PalletId, +}; +use frame_system::{ + limits::{BlockLength, BlockWeights}, + EnsureRoot, +}; +use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; +use parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling}; +use polkadot_runtime_common::{ + xcm_sender::NoPriceForMessageDelivery, BlockHashCount, SlowAdjustingFeeUpdate, +}; +use sp_consensus_aura::sr25519::AuthorityId as AuraId; +use sp_runtime::Perbill; +use sp_version::RuntimeVersion; +use xcm::latest::prelude::BodyId; + +// Local module imports +use super::{ + weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}, + AccountId, Aura, Balance, Balances, Block, BlockNumber, CollatorSelection, Hash, MessageQueue, + Nonce, PalletInfo, ParachainSystem, Runtime, RuntimeCall, RuntimeEvent, RuntimeFreezeReason, + RuntimeHoldReason, RuntimeOrigin, RuntimeTask, Session, SessionKeys, System, WeightToFee, + XcmpQueue, AVERAGE_ON_INITIALIZE_RATIO, BLOCK_PROCESSING_VELOCITY, EXISTENTIAL_DEPOSIT, HOURS, + MAXIMUM_BLOCK_WEIGHT, MICROUNIT, NORMAL_DISPATCH_RATIO, RELAY_CHAIN_SLOT_DURATION_MILLIS, + SLOT_DURATION, UNINCLUDED_SEGMENT_CAPACITY, VERSION, +}; +use xcm_config::{RelayLocation, XcmOriginToTransactDispatchOrigin}; + +parameter_types! { + pub const Version: RuntimeVersion = VERSION; + + // This part is copied from Substrate's `bin/node/runtime/src/lib.rs`. + // The `RuntimeBlockLength` and `RuntimeBlockWeights` exist here because the + // `DeletionWeightLimit` and `DeletionQueueDepth` depend on those to parameterize + // the lazy contract deletion. + pub RuntimeBlockLength: BlockLength = + BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); + pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder() + .base_block(BlockExecutionWeight::get()) + .for_class(DispatchClass::all(), |weights| { + weights.base_extrinsic = ExtrinsicBaseWeight::get(); + }) + .for_class(DispatchClass::Normal, |weights| { + weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT); + }) + .for_class(DispatchClass::Operational, |weights| { + weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT); + // Operational transactions have some extra reserved space, so that they + // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`. + weights.reserved = Some( + MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT + ); + }) + .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) + .build_or_panic(); + pub const SS58Prefix: u16 = 42; +} + +/// The default types are being injected by [`derive_impl`](`frame_support::derive_impl`) from +/// [`ParaChainDefaultConfig`](`struct@frame_system::config_preludes::ParaChainDefaultConfig`), +/// but overridden as needed. +#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig)] +impl frame_system::Config for Runtime { + /// The identifier used to distinguish between accounts. + type AccountId = AccountId; + /// The index type for storing how many extrinsics an account has signed. + type Nonce = Nonce; + /// The type for hashing blocks and tries. + type Hash = Hash; + /// The block type. + type Block = Block; + /// Maximum number of block number to block hash mappings to keep (oldest pruned first). + type BlockHashCount = BlockHashCount; + /// Runtime version. + type Version = Version; + /// The data to be stored in an account. + type AccountData = pallet_balances::AccountData; + /// The weight of database operations that the runtime can invoke. + type DbWeight = RocksDbWeight; + /// Block & extrinsics weights: base values and limits. + type BlockWeights = RuntimeBlockWeights; + /// The maximum length of a block (in bytes). + type BlockLength = RuntimeBlockLength; + /// This is used as an identifier of the chain. 42 is the generic substrate prefix. + type SS58Prefix = SS58Prefix; + /// The action to take on a Runtime Upgrade + type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +impl pallet_timestamp::Config for Runtime { + /// A timestamp: milliseconds since the unix epoch. + type Moment = u64; + type OnTimestampSet = Aura; + type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; + type WeightInfo = (); +} + +impl pallet_authorship::Config for Runtime { + type FindAuthor = pallet_session::FindAccountFromAuthorIndex; + type EventHandler = (CollatorSelection,); +} + +parameter_types! { + pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = ConstU32<50>; + /// The type for recording an account's balance. + type Balance = Balance; + /// The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = pallet_balances::weights::SubstrateWeight; + type MaxReserves = ConstU32<50>; + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; + type FreezeIdentifier = (); + type MaxFreezes = ConstU32<0>; +} + +parameter_types! { + /// Relay Chain `TransactionByteFee` / 10 + pub const TransactionByteFee: Balance = 10 * MICROUNIT; +} + +impl pallet_transaction_payment::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; + type WeightToFee = WeightToFee; + type LengthToFee = ConstantMultiplier; + type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; + type OperationalFeeMultiplier = ConstU8<5>; +} + +impl pallet_sudo::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type WeightInfo = (); +} + +parameter_types! { + pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); + pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + +impl cumulus_pallet_parachain_system::Config for Runtime { + type WeightInfo = (); + type RuntimeEvent = RuntimeEvent; + type OnSystemEvent = (); + type SelfParaId = parachain_info::Pallet; + type OutboundXcmpMessageSource = XcmpQueue; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; + type ReservedDmpWeight = ReservedDmpWeight; + type XcmpMessageHandler = XcmpQueue; + type ReservedXcmpWeight = ReservedXcmpWeight; + type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases; + type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< + Runtime, + RELAY_CHAIN_SLOT_DURATION_MILLIS, + BLOCK_PROCESSING_VELOCITY, + UNINCLUDED_SEGMENT_CAPACITY, + >; +} + +impl parachain_info::Config for Runtime {} + +parameter_types! { + pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + #[cfg(feature = "runtime-benchmarks")] + type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< + cumulus_primitives_core::AggregateMessageOrigin, + >; + #[cfg(not(feature = "runtime-benchmarks"))] + type MessageProcessor = xcm_builder::ProcessXcmMessage< + AggregateMessageOrigin, + xcm_executor::XcmExecutor, + RuntimeCall, + >; + type Size = u32; + // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: + type QueueChangeHandler = NarrowOriginToSibling; + type QueuePausedQuery = NarrowOriginToSibling; + type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type MaxStale = sp_core::ConstU32<8>; + type ServiceWeight = MessageQueueServiceWeight; + type IdleMaxServiceWeight = (); +} + +impl cumulus_pallet_aura_ext::Config for Runtime {} + +impl cumulus_pallet_xcmp_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ChannelInfo = ParachainSystem; + type VersionWrapper = (); + // Enqueue XCMP messages from siblings for later processing. + type XcmpQueue = TransformOrigin; + type MaxInboundSuspended = sp_core::ConstU32<1_000>; + type ControllerOrigin = EnsureRoot; + type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; + type WeightInfo = (); + type PriceForSiblingDelivery = NoPriceForMessageDelivery; +} + +parameter_types! { + pub const Period: u32 = 6 * HOURS; + pub const Offset: u32 = 0; +} + +impl pallet_session::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ValidatorId = ::AccountId; + // we don't have stash and controller, thus we don't need the convert as well. + type ValidatorIdOf = pallet_collator_selection::IdentityCollator; + type ShouldEndSession = pallet_session::PeriodicSessions; + type NextSessionRotation = pallet_session::PeriodicSessions; + type SessionManager = CollatorSelection; + // Essentially just Aura, but let's be pedantic. + type SessionHandler = ::KeyTypeIdProviders; + type Keys = SessionKeys; + type WeightInfo = (); +} + +impl pallet_aura::Config for Runtime { + type AuthorityId = AuraId; + type DisabledValidators = (); + type MaxAuthorities = ConstU32<100_000>; + type AllowMultipleBlocksPerSlot = ConstBool; + type SlotDuration = pallet_aura::MinimumPeriodTimesTwo; +} + +parameter_types! { + pub const PotId: PalletId = PalletId(*b"PotStake"); + pub const SessionLength: BlockNumber = 6 * HOURS; + // StakingAdmin pluralistic body. + pub const StakingAdminBodyId: BodyId = BodyId::Defense; +} + +/// We allow root and the StakingAdmin to execute privileged collator selection operations. +pub type CollatorSelectionUpdateOrigin = EitherOfDiverse< + EnsureRoot, + EnsureXcm>, +>; + +impl pallet_collator_selection::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type UpdateOrigin = CollatorSelectionUpdateOrigin; + type PotId = PotId; + type MaxCandidates = ConstU32<100>; + type MinEligibleCollators = ConstU32<4>; + type MaxInvulnerables = ConstU32<20>; + // should be a multiple of session or things will get inconsistent + type KickThreshold = Period; + type ValidatorId = ::AccountId; + type ValidatorIdOf = pallet_collator_selection::IdentityCollator; + type ValidatorRegistration = Session; + type WeightInfo = (); +} + +/// Configure the pallet template in pallets/template. +impl pallet_parachain_template::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = pallet_parachain_template::weights::SubstrateWeight; +} diff --git a/templates/parachain/runtime/src/xcm_config.rs b/templates/parachain/runtime/src/configs/xcm_config.rs similarity index 99% rename from templates/parachain/runtime/src/xcm_config.rs rename to templates/parachain/runtime/src/configs/xcm_config.rs index 7dce7164888..13da2363b05 100644 --- a/templates/parachain/runtime/src/xcm_config.rs +++ b/templates/parachain/runtime/src/configs/xcm_config.rs @@ -1,4 +1,4 @@ -use super::{ +use crate::{ AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, }; diff --git a/templates/parachain/runtime/src/lib.rs b/templates/parachain/runtime/src/lib.rs index 5cfee123b01..e2da9309ecc 100644 --- a/templates/parachain/runtime/src/lib.rs +++ b/templates/parachain/runtime/src/lib.rs @@ -7,11 +7,9 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); pub mod apis; +mod configs; mod weights; -pub mod xcm_config; -use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; -use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; use smallvec::smallvec; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, @@ -24,38 +22,20 @@ use sp_std::prelude::*; use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; use frame_support::{ - construct_runtime, derive_impl, - dispatch::DispatchClass, - parameter_types, - traits::{ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, TransformOrigin}, + construct_runtime, weights::{ - constants::WEIGHT_REF_TIME_PER_SECOND, ConstantMultiplier, Weight, WeightToFeeCoefficient, + constants::WEIGHT_REF_TIME_PER_SECOND, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, }, - PalletId, }; -use frame_system::{ - limits::{BlockLength, BlockWeights}, - EnsureRoot, -}; -use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; -use parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling}; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::{MultiAddress, Perbill, Permill}; -use xcm_config::{RelayLocation, XcmOriginToTransactDispatchOrigin}; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; -// Polkadot imports -use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; - -use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; - -// XCM Imports -use xcm::latest::prelude::BodyId; +use weights::ExtrinsicBaseWeight; /// Import the template pallet. pub use pallet_parachain_template; @@ -241,254 +221,6 @@ pub fn native_version() -> NativeVersion { NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } } -parameter_types! { - pub const Version: RuntimeVersion = VERSION; - - // This part is copied from Substrate's `bin/node/runtime/src/lib.rs`. - // The `RuntimeBlockLength` and `RuntimeBlockWeights` exist here because the - // `DeletionWeightLimit` and `DeletionQueueDepth` depend on those to parameterize - // the lazy contract deletion. - pub RuntimeBlockLength: BlockLength = - BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); - pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder() - .base_block(BlockExecutionWeight::get()) - .for_class(DispatchClass::all(), |weights| { - weights.base_extrinsic = ExtrinsicBaseWeight::get(); - }) - .for_class(DispatchClass::Normal, |weights| { - weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT); - }) - .for_class(DispatchClass::Operational, |weights| { - weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT); - // Operational transactions have some extra reserved space, so that they - // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`. - weights.reserved = Some( - MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT - ); - }) - .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) - .build_or_panic(); - pub const SS58Prefix: u16 = 42; -} - -/// The default types are being injected by [`derive_impl`](`frame_support::derive_impl`) from -/// [`ParaChainDefaultConfig`](`struct@frame_system::config_preludes::ParaChainDefaultConfig`), -/// but overridden as needed. -#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig)] -impl frame_system::Config for Runtime { - /// The identifier used to distinguish between accounts. - type AccountId = AccountId; - /// The index type for storing how many extrinsics an account has signed. - type Nonce = Nonce; - /// The type for hashing blocks and tries. - type Hash = Hash; - /// The block type. - type Block = Block; - /// Maximum number of block number to block hash mappings to keep (oldest pruned first). - type BlockHashCount = BlockHashCount; - /// Runtime version. - type Version = Version; - /// The data to be stored in an account. - type AccountData = pallet_balances::AccountData; - /// The weight of database operations that the runtime can invoke. - type DbWeight = RocksDbWeight; - /// Block & extrinsics weights: base values and limits. - type BlockWeights = RuntimeBlockWeights; - /// The maximum length of a block (in bytes). - type BlockLength = RuntimeBlockLength; - /// This is used as an identifier of the chain. 42 is the generic substrate prefix. - type SS58Prefix = SS58Prefix; - /// The action to take on a Runtime Upgrade - type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; - type MaxConsumers = frame_support::traits::ConstU32<16>; -} - -impl pallet_timestamp::Config for Runtime { - /// A timestamp: milliseconds since the unix epoch. - type Moment = u64; - type OnTimestampSet = Aura; - type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; - type WeightInfo = (); -} - -impl pallet_authorship::Config for Runtime { - type FindAuthor = pallet_session::FindAccountFromAuthorIndex; - type EventHandler = (CollatorSelection,); -} - -parameter_types! { - pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT; -} - -impl pallet_balances::Config for Runtime { - type MaxLocks = ConstU32<50>; - /// The type for recording an account's balance. - type Balance = Balance; - /// The ubiquitous event type. - type RuntimeEvent = RuntimeEvent; - type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = pallet_balances::weights::SubstrateWeight; - type MaxReserves = ConstU32<50>; - type ReserveIdentifier = [u8; 8]; - type RuntimeHoldReason = RuntimeHoldReason; - type RuntimeFreezeReason = RuntimeFreezeReason; - type FreezeIdentifier = (); - type MaxFreezes = ConstU32<0>; -} - -parameter_types! { - /// Relay Chain `TransactionByteFee` / 10 - pub const TransactionByteFee: Balance = 10 * MICROUNIT; -} - -impl pallet_transaction_payment::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; - type WeightToFee = WeightToFee; - type LengthToFee = ConstantMultiplier; - type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; - type OperationalFeeMultiplier = ConstU8<5>; -} - -impl pallet_sudo::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type WeightInfo = (); -} - -parameter_types! { - pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); - pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); - pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; -} - -impl cumulus_pallet_parachain_system::Config for Runtime { - type WeightInfo = (); - type RuntimeEvent = RuntimeEvent; - type OnSystemEvent = (); - type SelfParaId = parachain_info::Pallet; - type OutboundXcmpMessageSource = XcmpQueue; - type DmpQueue = frame_support::traits::EnqueueWithOrigin; - type ReservedDmpWeight = ReservedDmpWeight; - type XcmpMessageHandler = XcmpQueue; - type ReservedXcmpWeight = ReservedXcmpWeight; - type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases; - type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< - Runtime, - RELAY_CHAIN_SLOT_DURATION_MILLIS, - BLOCK_PROCESSING_VELOCITY, - UNINCLUDED_SEGMENT_CAPACITY, - >; -} - -impl parachain_info::Config for Runtime {} - -parameter_types! { - pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; -} - -impl pallet_message_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); - #[cfg(feature = "runtime-benchmarks")] - type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< - cumulus_primitives_core::AggregateMessageOrigin, - >; - #[cfg(not(feature = "runtime-benchmarks"))] - type MessageProcessor = xcm_builder::ProcessXcmMessage< - AggregateMessageOrigin, - xcm_executor::XcmExecutor, - RuntimeCall, - >; - type Size = u32; - // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: - type QueueChangeHandler = NarrowOriginToSibling; - type QueuePausedQuery = NarrowOriginToSibling; - type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; - type MaxStale = sp_core::ConstU32<8>; - type ServiceWeight = MessageQueueServiceWeight; - type IdleMaxServiceWeight = (); -} - -impl cumulus_pallet_aura_ext::Config for Runtime {} - -impl cumulus_pallet_xcmp_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type ChannelInfo = ParachainSystem; - type VersionWrapper = (); - // Enqueue XCMP messages from siblings for later processing. - type XcmpQueue = TransformOrigin; - type MaxInboundSuspended = sp_core::ConstU32<1_000>; - type ControllerOrigin = EnsureRoot; - type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; - type WeightInfo = (); - type PriceForSiblingDelivery = NoPriceForMessageDelivery; -} - -parameter_types! { - pub const Period: u32 = 6 * HOURS; - pub const Offset: u32 = 0; -} - -impl pallet_session::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type ValidatorId = ::AccountId; - // we don't have stash and controller, thus we don't need the convert as well. - type ValidatorIdOf = pallet_collator_selection::IdentityCollator; - type ShouldEndSession = pallet_session::PeriodicSessions; - type NextSessionRotation = pallet_session::PeriodicSessions; - type SessionManager = CollatorSelection; - // Essentially just Aura, but let's be pedantic. - type SessionHandler = ::KeyTypeIdProviders; - type Keys = SessionKeys; - type WeightInfo = (); -} - -impl pallet_aura::Config for Runtime { - type AuthorityId = AuraId; - type DisabledValidators = (); - type MaxAuthorities = ConstU32<100_000>; - type AllowMultipleBlocksPerSlot = ConstBool; - type SlotDuration = pallet_aura::MinimumPeriodTimesTwo; -} - -parameter_types! { - pub const PotId: PalletId = PalletId(*b"PotStake"); - pub const SessionLength: BlockNumber = 6 * HOURS; - // StakingAdmin pluralistic body. - pub const StakingAdminBodyId: BodyId = BodyId::Defense; -} - -/// We allow root and the StakingAdmin to execute privileged collator selection operations. -pub type CollatorSelectionUpdateOrigin = EitherOfDiverse< - EnsureRoot, - EnsureXcm>, ->; - -impl pallet_collator_selection::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type UpdateOrigin = CollatorSelectionUpdateOrigin; - type PotId = PotId; - type MaxCandidates = ConstU32<100>; - type MinEligibleCollators = ConstU32<4>; - type MaxInvulnerables = ConstU32<20>; - // should be a multiple of session or things will get inconsistent - type KickThreshold = Period; - type ValidatorId = ::AccountId; - type ValidatorIdOf = pallet_collator_selection::IdentityCollator; - type ValidatorRegistration = Session; - type WeightInfo = (); -} - -/// Configure the pallet template in pallets/template. -impl pallet_parachain_template::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = pallet_parachain_template::weights::SubstrateWeight; -} - // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime { -- GitLab From 07720dd1208e31f45cb20317cb15aa789428508b Mon Sep 17 00:00:00 2001 From: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Date: Mon, 1 Apr 2024 12:23:44 +0300 Subject: [PATCH 134/187] Improve `HostConfiguration` consistency check (#3897) fixes https://github.com/paritytech/polkadot-sdk/issues/3886 --------- Signed-off-by: Andrei Sandu --- polkadot/runtime/parachains/src/configuration.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/polkadot/runtime/parachains/src/configuration.rs b/polkadot/runtime/parachains/src/configuration.rs index b7635dcd7b2..17022272c0c 100644 --- a/polkadot/runtime/parachains/src/configuration.rs +++ b/polkadot/runtime/parachains/src/configuration.rs @@ -187,7 +187,7 @@ pub struct HostConfiguration { /// /// Must be at least 1. pub no_show_slots: u32, - /// The number of delay tranches in total. + /// The number of delay tranches in total. Must be at least 1. pub n_delay_tranches: u32, /// The width of the zeroth delay tranche for approval assignments. This many delay tranches /// beyond 0 are all consolidated to form a wide 0 tranche. @@ -247,7 +247,7 @@ impl> Default for HostConfiguration { LookaheadExceedsTTL, /// Passed in queue size for on-demand was too large. OnDemandQueueSizeTooLarge, + /// Number of delay tranches cannot be 0. + ZeroDelayTranches, } impl HostConfiguration @@ -412,6 +414,10 @@ where return Err(OnDemandQueueSizeTooLarge) } + if self.n_delay_tranches.is_zero() { + return Err(ZeroDelayTranches) + } + Ok(()) } -- GitLab From b772cb576d03cf67dc5f8eaf19c07dc23b37d34a Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Mon, 1 Apr 2024 16:35:36 +0700 Subject: [PATCH 135/187] Pools: Make `PermissionlessWithdraw` the default claim permission (#3438) Related Issue https://github.com/paritytech/polkadot-sdk/issues/3398 This PR makes permissionless withdrawing the default option, giving any network participant access to claim pool rewards on member's behalf. Of course, members can still opt out of this by setting a `Permissioned` claim permission. Permissionless claiming has been a part of the nomination pool pallet for around 9 months now, with very limited uptake (~4% of total pool members). 1.6% of pool members are using `PermissionlessAll`, strongly suggesting it is not wanted - it is too ambiguous and doesn't provide guidance to claimers. Stakers expect rewards to be claimed on their behalf by default - I have expanded upon this in detail within the [accompanying issue's discussion](https://github.com/paritytech/polkadot-sdk/issues/3398). Other protocols have this behaviour, whereby staking rewards are received without the staker having to take any action. From this perspective, permissionless claiming is not intuitive for pool members. As evidence of this, over 150,000 DOT is currently unclaimed on Polkadot, and is growing at a non-linear rate. --- prdoc/pr_3438.prdoc | 13 +++++++ .../nomination-pools/benchmarking/src/lib.rs | 4 +- substrate/frame/nomination-pools/src/lib.rs | 31 ++++++++------- substrate/frame/nomination-pools/src/tests.rs | 39 +++++++------------ 4 files changed, 45 insertions(+), 42 deletions(-) create mode 100644 prdoc/pr_3438.prdoc diff --git a/prdoc/pr_3438.prdoc b/prdoc/pr_3438.prdoc new file mode 100644 index 00000000000..5f4a0e3d57a --- /dev/null +++ b/prdoc/pr_3438.prdoc @@ -0,0 +1,13 @@ +title: "Pools: Make PermissionlessWithdraw the default claim permission" + +doc: + - audience: Runtime User + description: | + Makes permissionless withdrawing the default claim permission, giving any network participant + access to claim pool rewards on member's behalf, by default. + +crates: + - name: pallet-nomination-pools + bump: minor + - name: pallet-nomination-pools-benchmarking + bump: minor diff --git a/substrate/frame/nomination-pools/benchmarking/src/lib.rs b/substrate/frame/nomination-pools/benchmarking/src/lib.rs index 48d7dae29ef..f7df173ec04 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/lib.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/lib.rs @@ -795,9 +795,9 @@ frame_benchmarking::benchmarks! { T::Staking::active_stake(&pool_account).unwrap(), min_create_bond + min_join_bond ); - }:_(RuntimeOrigin::Signed(joiner.clone()), ClaimPermission::PermissionlessAll) + }:_(RuntimeOrigin::Signed(joiner.clone()), ClaimPermission::Permissioned) verify { - assert_eq!(ClaimPermissions::::get(joiner), ClaimPermission::PermissionlessAll); + assert_eq!(ClaimPermissions::::get(joiner), ClaimPermission::Permissioned); } claim_commission { diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs index f29a49a2b1b..23501cd89d2 100644 --- a/substrate/frame/nomination-pools/src/lib.rs +++ b/substrate/frame/nomination-pools/src/lib.rs @@ -461,22 +461,26 @@ pub enum ClaimPermission { PermissionlessAll, } +impl Default for ClaimPermission { + fn default() -> Self { + Self::PermissionlessWithdraw + } +} + impl ClaimPermission { + /// Permissionless compounding of pool rewards is allowed if the current permission is + /// `PermissionlessCompound`, or permissionless. fn can_bond_extra(&self) -> bool { matches!(self, ClaimPermission::PermissionlessAll | ClaimPermission::PermissionlessCompound) } + /// Permissionless payout claiming is allowed if the current permission is + /// `PermissionlessWithdraw`, or permissionless. fn can_claim_payout(&self) -> bool { matches!(self, ClaimPermission::PermissionlessAll | ClaimPermission::PermissionlessWithdraw) } } -impl Default for ClaimPermission { - fn default() -> Self { - Self::Permissioned - } -} - /// A member in a pool. #[derive( Encode, @@ -2630,7 +2634,7 @@ pub mod pallet { /// /// In the case of `origin != other`, `origin` can only bond extra pending rewards of /// `other` members assuming set_claim_permission for the given member is - /// `PermissionlessAll` or `PermissionlessCompound`. + /// `PermissionlessCompound` or `PermissionlessAll`. #[pallet::call_index(14)] #[pallet::weight( T::WeightInfo::bond_extra_transfer() @@ -2648,15 +2652,10 @@ pub mod pallet { /// Allows a pool member to set a claim permission to allow or disallow permissionless /// bonding and withdrawing. /// - /// By default, this is `Permissioned`, which implies only the pool member themselves can - /// claim their pending rewards. If a pool member wishes so, they can set this to - /// `PermissionlessAll` to allow any account to claim their rewards and bond extra to the - /// pool. - /// /// # Arguments /// /// * `origin` - Member of a pool. - /// * `actor` - Account to claim reward. // improve this + /// * `permission` - The permission to be applied. #[pallet::call_index(15)] #[pallet::weight(T::DbWeight::get().reads_writes(1, 1))] pub fn set_claim_permission( @@ -2666,16 +2665,18 @@ pub mod pallet { let who = ensure_signed(origin)?; ensure!(PoolMembers::::contains_key(&who), Error::::PoolMemberNotFound); + ClaimPermissions::::mutate(who, |source| { *source = permission; }); + Ok(()) } /// `origin` can claim payouts on some pool member `other`'s behalf. /// - /// Pool member `other` must have a `PermissionlessAll` or `PermissionlessWithdraw` in order - /// for this call to be successful. + /// Pool member `other` must have a `PermissionlessWithdraw` or `PermissionlessAll` claim + /// permission for this call to be successful. #[pallet::call_index(16)] #[pallet::weight(T::WeightInfo::claim_payout())] pub fn claim_payout_other(origin: OriginFor, other: T::AccountId) -> DispatchResult { diff --git a/substrate/frame/nomination-pools/src/tests.rs b/substrate/frame/nomination-pools/src/tests.rs index 8fb2b41b88a..32b3e9af3cd 100644 --- a/substrate/frame/nomination-pools/src/tests.rs +++ b/substrate/frame/nomination-pools/src/tests.rs @@ -2441,16 +2441,10 @@ mod claim_payout { // given assert_eq!(Currency::free_balance(&10), 35); - // Permissioned by default - assert_noop!( - Pools::claim_payout_other(RuntimeOrigin::signed(80), 10), - Error::::DoesNotHavePermission - ); + // when - assert_ok!(Pools::set_claim_permission( - RuntimeOrigin::signed(10), - ClaimPermission::PermissionlessWithdraw - )); + // NOTE: Claim permission of `PermissionlessWithdraw` allows payout claiming as default, + // so a claim permission does not need to be set for non-pool members prior to claiming. assert_ok!(Pools::claim_payout_other(RuntimeOrigin::signed(80), 10)); // then @@ -2489,7 +2483,6 @@ mod unbond { ); // Make permissionless - assert_eq!(ClaimPermissions::::get(10), ClaimPermission::Permissioned); assert_ok!(Pools::set_claim_permission( RuntimeOrigin::signed(20), ClaimPermission::PermissionlessAll @@ -4563,12 +4556,11 @@ mod withdraw_unbonded { CurrentEra::set(1); assert_eq!(PoolMembers::::get(20).unwrap().points, 20); - assert_ok!(Pools::set_claim_permission( - RuntimeOrigin::signed(20), - ClaimPermission::PermissionlessAll - )); assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 20)); - assert_eq!(ClaimPermissions::::get(20), ClaimPermission::PermissionlessAll); + assert_eq!( + ClaimPermissions::::get(20), + ClaimPermission::PermissionlessWithdraw + ); assert_eq!( pool_events_since_last_call(), @@ -4792,7 +4784,7 @@ mod create { } #[test] -fn set_claimable_actor_works() { +fn set_claim_permission_works() { ExtBuilder::default().build_and_execute(|| { // Given Currency::set_balance(&11, ExistentialDeposit::get() + 2); @@ -4811,22 +4803,19 @@ fn set_claimable_actor_works() { ] ); - // Make permissionless - assert_eq!(ClaimPermissions::::get(11), ClaimPermission::Permissioned); + // Make permissioned + assert_eq!(ClaimPermissions::::get(11), ClaimPermission::PermissionlessWithdraw); assert_noop!( - Pools::set_claim_permission( - RuntimeOrigin::signed(12), - ClaimPermission::PermissionlessAll - ), + Pools::set_claim_permission(RuntimeOrigin::signed(12), ClaimPermission::Permissioned), Error::::PoolMemberNotFound ); assert_ok!(Pools::set_claim_permission( RuntimeOrigin::signed(11), - ClaimPermission::PermissionlessAll + ClaimPermission::Permissioned )); // then - assert_eq!(ClaimPermissions::::get(11), ClaimPermission::PermissionlessAll); + assert_eq!(ClaimPermissions::::get(11), ClaimPermission::Permissioned); }); } @@ -5224,7 +5213,7 @@ mod bond_extra { assert_ok!(Pools::set_claim_permission( RuntimeOrigin::signed(10), - ClaimPermission::PermissionlessAll + ClaimPermission::PermissionlessCompound )); assert_ok!(Pools::bond_extra_other(RuntimeOrigin::signed(50), 10, BondExtra::Rewards)); assert_eq!(Currency::free_balance(&default_reward_account()), 7); -- GitLab From e6bd9205432bb524e94c9bd13048d645ec9aa5c7 Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <49718502+alexggh@users.noreply.github.com> Date: Mon, 1 Apr 2024 13:23:29 +0300 Subject: [PATCH 136/187] Fix 0007-dispute-freshly-finalized.zndsl failing (#3893) Test started failing after https://github.com/paritytech/polkadot-sdk/commit/66051adb619d2119771920218e2de75fa037d7e8 which enabled approval coalescing, that was expected to happen because the test required an polkadot_parachain_approval_checking_finality_lag of 0, which can't happen with max_approval_coalesce_count greater than 1 because we always delay the approval for no_show_duration_ticks/2 in case we can coalesce it with other approvals. So relax a bit the restrictions, since we don't actually care that the lags are 0, but the fact the finalities are progressing and are not stuck. Signed-off-by: Alexandru Gheorghe --- .../functional/0007-dispute-freshly-finalized.zndsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/polkadot/zombienet_tests/functional/0007-dispute-freshly-finalized.zndsl b/polkadot/zombienet_tests/functional/0007-dispute-freshly-finalized.zndsl index 62d5a9768f9..d1ed0250d4d 100644 --- a/polkadot/zombienet_tests/functional/0007-dispute-freshly-finalized.zndsl +++ b/polkadot/zombienet_tests/functional/0007-dispute-freshly-finalized.zndsl @@ -21,9 +21,9 @@ honest: reports polkadot_parachain_candidate_dispute_concluded{validity="valid"} honest: reports polkadot_parachain_candidate_dispute_concluded{validity="invalid"} is 0 within 100 seconds # Check lag - approval -honest: reports polkadot_parachain_approval_checking_finality_lag is 0 +honest: reports polkadot_parachain_approval_checking_finality_lag is lower than 2 # Check lag - dispute conclusion -honest: reports polkadot_parachain_disputes_finality_lag is 0 +honest: reports polkadot_parachain_disputes_finality_lag is lower than 2 -- GitLab From d6f68bb9062167537211cc05286809771fc8861a Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <49718502+alexggh@users.noreply.github.com> Date: Mon, 1 Apr 2024 16:03:26 +0300 Subject: [PATCH 137/187] primitives: Move out of staging released APIs (#3925) Runtime release 1.2 includes bumping of the ParachainHost APIs up to v10, so let's move all the released APIs out of vstaging folder, this PR does not include any logic changes only renaming of the modules and some moving around. Signed-off-by: Alexandru Gheorghe --- .../src/blockchain_rpc_client.rs | 4 +- .../src/rpc_client.rs | 13 +++-- .../node/core/approval-voting/src/import.rs | 8 +-- polkadot/node/core/approval-voting/src/lib.rs | 8 +-- .../node/core/approval-voting/src/tests.rs | 4 +- polkadot/node/core/backing/src/lib.rs | 11 ++-- polkadot/node/core/backing/src/tests/mod.rs | 4 +- .../core/dispute-coordinator/src/tests.rs | 6 +-- polkadot/node/core/provisioner/src/lib.rs | 6 +-- polkadot/node/core/runtime-api/src/cache.rs | 25 ++++----- polkadot/node/core/runtime-api/src/tests.rs | 14 +++-- .../src/pov_requester/mod.rs | 4 +- .../src/requester/tests.rs | 2 +- .../src/tests/state.rs | 4 +- .../src/collator_side/tests/mod.rs | 5 +- .../dispute-distribution/src/tests/mod.rs | 4 +- .../src/legacy_v1/tests.rs | 2 +- .../src/v2/statement_store.rs | 2 +- polkadot/node/service/src/chain_spec.rs | 4 +- .../src/lib/approval/message_generator.rs | 4 +- .../src/lib/mock/runtime_api.rs | 2 +- polkadot/node/subsystem-types/src/messages.rs | 18 +++---- .../subsystem-types/src/runtime_client.rs | 20 +++---- .../node/subsystem-util/src/runtime/mod.rs | 11 ++-- polkadot/primitives/src/lib.rs | 37 ++++++------- polkadot/primitives/src/runtime_api.rs | 14 +++-- .../src/{v6 => v7}/async_backing.rs | 0 .../src/{v6 => v7}/executor_params.rs | 0 polkadot/primitives/src/{v6 => v7}/metrics.rs | 0 polkadot/primitives/src/{v6 => v7}/mod.rs | 51 +++++++++++++++++- polkadot/primitives/src/{v6 => v7}/signed.rs | 0 .../primitives/src/{v6 => v7}/slashing.rs | 0 polkadot/primitives/src/vstaging/mod.rs | 53 +------------------ polkadot/runtime/parachains/src/builder.rs | 14 ++--- .../runtime/parachains/src/configuration.rs | 7 ++- .../src/configuration/migration/v10.rs | 2 +- .../src/configuration/migration/v11.rs | 3 +- polkadot/runtime/parachains/src/disputes.rs | 10 ++-- .../src/paras_inherent/benchmarking.rs | 2 +- .../parachains/src/paras_inherent/mod.rs | 6 +-- .../parachains/src/runtime_api_impl/mod.rs | 2 +- .../src/runtime_api_impl/{v7.rs => v10.rs} | 34 +++++++++--- .../src/runtime_api_impl/vstaging.rs | 33 ++---------- polkadot/runtime/rococo/src/lib.rs | 23 ++++---- polkadot/runtime/test-runtime/src/lib.rs | 19 ++++--- polkadot/runtime/westend/src/lib.rs | 24 ++++----- 46 files changed, 240 insertions(+), 279 deletions(-) rename polkadot/primitives/src/{v6 => v7}/async_backing.rs (100%) rename polkadot/primitives/src/{v6 => v7}/executor_params.rs (100%) rename polkadot/primitives/src/{v6 => v7}/metrics.rs (100%) rename polkadot/primitives/src/{v6 => v7}/mod.rs (97%) rename polkadot/primitives/src/{v6 => v7}/signed.rs (100%) rename polkadot/primitives/src/{v6 => v7}/slashing.rs (100%) rename polkadot/runtime/parachains/src/runtime_api_impl/{v7.rs => v10.rs} (93%) diff --git a/cumulus/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs b/cumulus/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs index 8d8a2920b4e..aa5e67e453f 100644 --- a/cumulus/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs +++ b/cumulus/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs @@ -26,9 +26,7 @@ use polkadot_core_primitives::{Block, BlockNumber, Hash, Header}; use polkadot_overseer::{ChainApiBackend, RuntimeApiSubsystemClient}; use polkadot_primitives::{ async_backing::{AsyncBackingParams, BackingState}, - slashing, - vstaging::{ApprovalVotingParams, NodeFeatures}, - CoreIndex, + slashing, ApprovalVotingParams, CoreIndex, NodeFeatures, }; use sc_authority_discovery::{AuthorityDiscovery, Error as AuthorityDiscoveryError}; use sc_client_api::AuxStore; diff --git a/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs index 8cf5ccf0c70..547803865c2 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs @@ -32,13 +32,12 @@ use parity_scale_codec::{Decode, Encode}; use cumulus_primitives_core::{ relay_chain::{ async_backing::{AsyncBackingParams, BackingState}, - slashing, - vstaging::{ApprovalVotingParams, NodeFeatures}, - BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, - CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, - GroupRotationInfo, Hash as RelayHash, Header as RelayHeader, InboundHrmpMessage, - OccupiedCoreAssumption, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, - ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, + slashing, ApprovalVotingParams, BlockNumber, CandidateCommitments, CandidateEvent, + CandidateHash, CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, + ExecutorParams, GroupRotationInfo, Hash as RelayHash, Header as RelayHeader, + InboundHrmpMessage, NodeFeatures, OccupiedCoreAssumption, PvfCheckStatement, + ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, + ValidatorId, ValidatorIndex, ValidatorSignature, }, InboundDownwardMessage, ParaId, PersistedValidationData, }; diff --git a/polkadot/node/core/approval-voting/src/import.rs b/polkadot/node/core/approval-voting/src/import.rs index d34191fba31..f4be42a4845 100644 --- a/polkadot/node/core/approval-voting/src/import.rs +++ b/polkadot/node/core/approval-voting/src/import.rs @@ -45,8 +45,8 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_util::{determine_new_blocks, runtime::RuntimeInfo}; use polkadot_primitives::{ - vstaging::node_features, BlockNumber, CandidateEvent, CandidateHash, CandidateReceipt, - ConsensusLog, CoreIndex, GroupIndex, Hash, Header, SessionIndex, + node_features, BlockNumber, CandidateEvent, CandidateHash, CandidateReceipt, ConsensusLog, + CoreIndex, GroupIndex, Hash, Header, SessionIndex, }; use sc_keystore::LocalKeystore; use sp_consensus_slots::Slot; @@ -619,8 +619,8 @@ pub(crate) mod tests { use polkadot_node_subsystem_test_helpers::make_subsystem_context; use polkadot_node_subsystem_util::database::Database; use polkadot_primitives::{ - vstaging::{node_features::FeatureIndex, NodeFeatures}, - ExecutorParams, Id as ParaId, IndexedVec, SessionInfo, ValidatorId, ValidatorIndex, + node_features::FeatureIndex, ExecutorParams, Id as ParaId, IndexedVec, NodeFeatures, + SessionInfo, ValidatorId, ValidatorIndex, }; pub(crate) use sp_consensus_babe::{ digests::{CompatibleDigestItem, PreDigest, SecondaryVRFPreDigest}, diff --git a/polkadot/node/core/approval-voting/src/lib.rs b/polkadot/node/core/approval-voting/src/lib.rs index 76b3d476e28..57e9af4a518 100644 --- a/polkadot/node/core/approval-voting/src/lib.rs +++ b/polkadot/node/core/approval-voting/src/lib.rs @@ -54,10 +54,10 @@ use polkadot_node_subsystem_util::{ TimeoutExt, }; use polkadot_primitives::{ - vstaging::{ApprovalVoteMultipleCandidates, ApprovalVotingParams}, - BlockNumber, CandidateHash, CandidateIndex, CandidateReceipt, CoreIndex, DisputeStatement, - ExecutorParams, GroupIndex, Hash, PvfExecKind, SessionIndex, SessionInfo, - ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorPair, ValidatorSignature, + ApprovalVoteMultipleCandidates, ApprovalVotingParams, BlockNumber, CandidateHash, + CandidateIndex, CandidateReceipt, CoreIndex, DisputeStatement, ExecutorParams, GroupIndex, + Hash, PvfExecKind, SessionIndex, SessionInfo, ValidDisputeStatementKind, ValidatorId, + ValidatorIndex, ValidatorPair, ValidatorSignature, }; use sc_keystore::LocalKeystore; use sp_application_crypto::Pair; diff --git a/polkadot/node/core/approval-voting/src/tests.rs b/polkadot/node/core/approval-voting/src/tests.rs index 1483af56585..f7bbbca4b8a 100644 --- a/polkadot/node/core/approval-voting/src/tests.rs +++ b/polkadot/node/core/approval-voting/src/tests.rs @@ -37,8 +37,8 @@ use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_util::TimeoutExt; use polkadot_overseer::HeadSupportsParachains; use polkadot_primitives::{ - vstaging::NodeFeatures, ApprovalVote, CandidateCommitments, CandidateEvent, CoreIndex, - GroupIndex, Header, Id as ParaId, IndexedVec, ValidationCode, ValidatorSignature, + ApprovalVote, CandidateCommitments, CandidateEvent, CoreIndex, GroupIndex, Header, + Id as ParaId, IndexedVec, NodeFeatures, ValidationCode, ValidatorSignature, }; use std::time::Duration; diff --git a/polkadot/node/core/backing/src/lib.rs b/polkadot/node/core/backing/src/lib.rs index b5cad4cf5f0..23acb045094 100644 --- a/polkadot/node/core/backing/src/lib.rs +++ b/polkadot/node/core/backing/src/lib.rs @@ -105,12 +105,11 @@ use polkadot_node_subsystem_util::{ Validator, }; use polkadot_primitives::{ - vstaging::{node_features::FeatureIndex, NodeFeatures}, - BackedCandidate, CandidateCommitments, CandidateHash, CandidateReceipt, - CommittedCandidateReceipt, CoreIndex, CoreState, ExecutorParams, GroupIndex, GroupRotationInfo, - Hash, Id as ParaId, IndexedVec, PersistedValidationData, PvfExecKind, SessionIndex, - SigningContext, ValidationCode, ValidatorId, ValidatorIndex, ValidatorSignature, - ValidityAttestation, + node_features::FeatureIndex, BackedCandidate, CandidateCommitments, CandidateHash, + CandidateReceipt, CommittedCandidateReceipt, CoreIndex, CoreState, ExecutorParams, GroupIndex, + GroupRotationInfo, Hash, Id as ParaId, IndexedVec, NodeFeatures, PersistedValidationData, + PvfExecKind, SessionIndex, SigningContext, ValidationCode, ValidatorId, ValidatorIndex, + ValidatorSignature, ValidityAttestation, }; use sp_keystore::KeystorePtr; use statement_table::{ diff --git a/polkadot/node/core/backing/src/tests/mod.rs b/polkadot/node/core/backing/src/tests/mod.rs index fdb47581ea3..d1969e656db 100644 --- a/polkadot/node/core/backing/src/tests/mod.rs +++ b/polkadot/node/core/backing/src/tests/mod.rs @@ -33,8 +33,8 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_primitives::{ - vstaging::node_features, CandidateDescriptor, GroupRotationInfo, HeadData, - PersistedValidationData, PvfExecKind, ScheduledCore, SessionIndex, LEGACY_MIN_BACKING_VOTES, + node_features, CandidateDescriptor, GroupRotationInfo, HeadData, PersistedValidationData, + PvfExecKind, ScheduledCore, SessionIndex, LEGACY_MIN_BACKING_VOTES, }; use rstest::rstest; use sp_application_crypto::AppCrypto; diff --git a/polkadot/node/core/dispute-coordinator/src/tests.rs b/polkadot/node/core/dispute-coordinator/src/tests.rs index 7c1f4ff241d..13cf2df8822 100644 --- a/polkadot/node/core/dispute-coordinator/src/tests.rs +++ b/polkadot/node/core/dispute-coordinator/src/tests.rs @@ -61,9 +61,9 @@ use polkadot_node_subsystem_test_helpers::{ make_buffered_subsystem_context, mock::new_leaf, TestSubsystemContextHandle, }; use polkadot_primitives::{ - vstaging::NodeFeatures, ApprovalVote, BlockNumber, CandidateCommitments, CandidateEvent, - CandidateHash, CandidateReceipt, CoreIndex, DisputeStatement, ExecutorParams, GroupIndex, Hash, - HeadData, Header, IndexedVec, MultiDisputeStatementSet, ScrapedOnChainVotes, SessionIndex, + ApprovalVote, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, + CandidateReceipt, CoreIndex, DisputeStatement, ExecutorParams, GroupIndex, Hash, HeadData, + Header, IndexedVec, MultiDisputeStatementSet, NodeFeatures, ScrapedOnChainVotes, SessionIndex, SessionInfo, SigningContext, ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorSignature, }; diff --git a/polkadot/node/core/provisioner/src/lib.rs b/polkadot/node/core/provisioner/src/lib.rs index 3ccf499f325..5cfcb96dc2b 100644 --- a/polkadot/node/core/provisioner/src/lib.rs +++ b/polkadot/node/core/provisioner/src/lib.rs @@ -42,9 +42,9 @@ use polkadot_node_subsystem_util::{ TimeoutExt, }; use polkadot_primitives::{ - vstaging::{node_features::FeatureIndex, NodeFeatures}, - BackedCandidate, BlockNumber, CandidateHash, CandidateReceipt, CoreIndex, CoreState, Hash, - Id as ParaId, OccupiedCoreAssumption, SessionIndex, SignedAvailabilityBitfield, ValidatorIndex, + node_features::FeatureIndex, BackedCandidate, BlockNumber, CandidateHash, CandidateReceipt, + CoreIndex, CoreState, Hash, Id as ParaId, NodeFeatures, OccupiedCoreAssumption, SessionIndex, + SignedAvailabilityBitfield, ValidatorIndex, }; use std::collections::{BTreeMap, HashMap}; diff --git a/polkadot/node/core/runtime-api/src/cache.rs b/polkadot/node/core/runtime-api/src/cache.rs index 9674cda9838..acdb256ab36 100644 --- a/polkadot/node/core/runtime-api/src/cache.rs +++ b/polkadot/node/core/runtime-api/src/cache.rs @@ -20,14 +20,12 @@ use schnellru::{ByLength, LruMap}; use sp_consensus_babe::Epoch; use polkadot_primitives::{ - async_backing, slashing, - vstaging::{self, ApprovalVotingParams}, - AuthorityDiscoveryId, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, - CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, - GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, - OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, - SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, - ValidatorSignature, + async_backing, slashing, ApprovalVotingParams, AuthorityDiscoveryId, BlockNumber, + CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreIndex, + CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, Id as ParaId, + InboundDownwardMessage, InboundHrmpMessage, NodeFeatures, OccupiedCoreAssumption, + PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, + ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, }; /// For consistency we have the same capacity for all caches. We use 128 as we'll only need that @@ -69,7 +67,7 @@ pub(crate) struct RequestResultCache { disabled_validators: LruMap>, para_backing_state: LruMap<(Hash, ParaId), Option>, async_backing_params: LruMap, - node_features: LruMap, + node_features: LruMap, approval_voting_params: LruMap, claim_queue: LruMap>>, } @@ -454,17 +452,14 @@ impl RequestResultCache { self.minimum_backing_votes.insert(session_index, minimum_backing_votes); } - pub(crate) fn node_features( - &mut self, - session_index: SessionIndex, - ) -> Option<&vstaging::NodeFeatures> { + pub(crate) fn node_features(&mut self, session_index: SessionIndex) -> Option<&NodeFeatures> { self.node_features.get(&session_index).map(|f| &*f) } pub(crate) fn cache_node_features( &mut self, session_index: SessionIndex, - features: vstaging::NodeFeatures, + features: NodeFeatures, ) { self.node_features.insert(session_index, features); } @@ -594,6 +589,6 @@ pub(crate) enum RequestResult { DisabledValidators(Hash, Vec), ParaBackingState(Hash, ParaId, Option), AsyncBackingParams(Hash, async_backing::AsyncBackingParams), - NodeFeatures(SessionIndex, vstaging::NodeFeatures), + NodeFeatures(SessionIndex, NodeFeatures), ClaimQueue(Hash, BTreeMap>), } diff --git a/polkadot/node/core/runtime-api/src/tests.rs b/polkadot/node/core/runtime-api/src/tests.rs index b51682aa0f4..73c661c4076 100644 --- a/polkadot/node/core/runtime-api/src/tests.rs +++ b/polkadot/node/core/runtime-api/src/tests.rs @@ -20,14 +20,12 @@ use polkadot_node_primitives::{BabeAllowedSlots, BabeEpoch, BabeEpochConfigurati use polkadot_node_subsystem::SpawnGlue; use polkadot_node_subsystem_test_helpers::make_subsystem_context; use polkadot_primitives::{ - async_backing, slashing, - vstaging::{ApprovalVotingParams, NodeFeatures}, - AuthorityDiscoveryId, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, - CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, - GroupRotationInfo, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, - OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, - SessionIndex, SessionInfo, Slot, ValidationCode, ValidationCodeHash, ValidatorId, - ValidatorIndex, ValidatorSignature, + async_backing, slashing, ApprovalVotingParams, AuthorityDiscoveryId, BlockNumber, + CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreIndex, + CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Id as ParaId, + InboundDownwardMessage, InboundHrmpMessage, NodeFeatures, OccupiedCoreAssumption, + PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, + Slot, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, }; use sp_api::ApiError; use sp_core::testing::TaskExecutor; diff --git a/polkadot/node/network/availability-distribution/src/pov_requester/mod.rs b/polkadot/node/network/availability-distribution/src/pov_requester/mod.rs index 4e23030aa49..f99002d4188 100644 --- a/polkadot/node/network/availability-distribution/src/pov_requester/mod.rs +++ b/polkadot/node/network/availability-distribution/src/pov_requester/mod.rs @@ -147,9 +147,7 @@ mod tests { AllMessages, AvailabilityDistributionMessage, RuntimeApiMessage, RuntimeApiRequest, }; use polkadot_node_subsystem_test_helpers as test_helpers; - use polkadot_primitives::{ - vstaging::NodeFeatures, CandidateHash, ExecutorParams, Hash, ValidatorIndex, - }; + use polkadot_primitives::{CandidateHash, ExecutorParams, Hash, NodeFeatures, ValidatorIndex}; use test_helpers::mock::make_ferdie_keystore; use super::*; diff --git a/polkadot/node/network/availability-distribution/src/requester/tests.rs b/polkadot/node/network/availability-distribution/src/requester/tests.rs index 2f5d900b037..0dedd4f091a 100644 --- a/polkadot/node/network/availability-distribution/src/requester/tests.rs +++ b/polkadot/node/network/availability-distribution/src/requester/tests.rs @@ -25,7 +25,7 @@ use polkadot_node_primitives::{BlockData, ErasureChunk, PoV}; use polkadot_node_subsystem_test_helpers::mock::new_leaf; use polkadot_node_subsystem_util::runtime::RuntimeInfo; use polkadot_primitives::{ - vstaging::NodeFeatures, BlockNumber, CoreState, ExecutorParams, GroupIndex, Hash, Id as ParaId, + BlockNumber, CoreState, ExecutorParams, GroupIndex, Hash, Id as ParaId, NodeFeatures, ScheduledCore, SessionIndex, SessionInfo, }; use sp_core::traits::SpawnNamed; diff --git a/polkadot/node/network/availability-distribution/src/tests/state.rs b/polkadot/node/network/availability-distribution/src/tests/state.rs index 66a8d8fcdcf..1d814b4fd0e 100644 --- a/polkadot/node/network/availability-distribution/src/tests/state.rs +++ b/polkadot/node/network/availability-distribution/src/tests/state.rs @@ -47,8 +47,8 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_primitives::{ - vstaging::NodeFeatures, CandidateHash, CoreState, ExecutorParams, GroupIndex, Hash, - Id as ParaId, ScheduledCore, SessionInfo, ValidatorIndex, + CandidateHash, CoreState, ExecutorParams, GroupIndex, Hash, Id as ParaId, NodeFeatures, + ScheduledCore, SessionInfo, ValidatorIndex, }; use test_helpers::mock::{make_ferdie_keystore, new_leaf}; diff --git a/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs b/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs index bcf0b34e631..de561e9f77f 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs @@ -45,9 +45,8 @@ use polkadot_node_subsystem::{ use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_util::{reputation::add_reputation, TimeoutExt}; use polkadot_primitives::{ - vstaging::NodeFeatures, AuthorityDiscoveryId, CollatorPair, ExecutorParams, GroupIndex, - GroupRotationInfo, IndexedVec, ScheduledCore, SessionIndex, SessionInfo, ValidatorId, - ValidatorIndex, + AuthorityDiscoveryId, CollatorPair, ExecutorParams, GroupIndex, GroupRotationInfo, IndexedVec, + NodeFeatures, ScheduledCore, SessionIndex, SessionInfo, ValidatorId, ValidatorIndex, }; use polkadot_primitives_test_helpers::TestCandidateBuilder; use test_helpers::mock::new_leaf; diff --git a/polkadot/node/network/dispute-distribution/src/tests/mod.rs b/polkadot/node/network/dispute-distribution/src/tests/mod.rs index 880d1b18032..5ad790fb01c 100644 --- a/polkadot/node/network/dispute-distribution/src/tests/mod.rs +++ b/polkadot/node/network/dispute-distribution/src/tests/mod.rs @@ -57,8 +57,8 @@ use polkadot_node_subsystem_test_helpers::{ subsystem_test_harness, TestSubsystemContextHandle, }; use polkadot_primitives::{ - vstaging::NodeFeatures, AuthorityDiscoveryId, CandidateHash, CandidateReceipt, ExecutorParams, - Hash, SessionIndex, SessionInfo, + AuthorityDiscoveryId, CandidateHash, CandidateReceipt, ExecutorParams, Hash, NodeFeatures, + SessionIndex, SessionInfo, }; use self::mock::{ diff --git a/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs b/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs index 08e9d69d8ee..7d355cc8872 100644 --- a/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs +++ b/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs @@ -43,7 +43,7 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_test_helpers::mock::{make_ferdie_keystore, new_leaf}; use polkadot_primitives::{ - vstaging::NodeFeatures, ExecutorParams, GroupIndex, Hash, HeadData, Id as ParaId, IndexedVec, + ExecutorParams, GroupIndex, Hash, HeadData, Id as ParaId, IndexedVec, NodeFeatures, SessionInfo, ValidationCode, }; use polkadot_primitives_test_helpers::{ diff --git a/polkadot/node/network/statement-distribution/src/v2/statement_store.rs b/polkadot/node/network/statement-distribution/src/v2/statement_store.rs index 022461e5551..a3b2636d2ff 100644 --- a/polkadot/node/network/statement-distribution/src/v2/statement_store.rs +++ b/polkadot/node/network/statement-distribution/src/v2/statement_store.rs @@ -292,7 +292,7 @@ impl GroupStatements { mod tests { use super::*; - use polkadot_primitives::v6::{Hash, SigningContext, ValidatorPair}; + use polkadot_primitives::v7::{Hash, SigningContext, ValidatorPair}; use sp_application_crypto::Pair as PairT; #[test] diff --git a/polkadot/node/service/src/chain_spec.rs b/polkadot/node/service/src/chain_spec.rs index c03ce1db094..1b6ba99777b 100644 --- a/polkadot/node/service/src/chain_spec.rs +++ b/polkadot/node/service/src/chain_spec.rs @@ -123,8 +123,8 @@ fn default_parachains_host_configuration( ) -> polkadot_runtime_parachains::configuration::HostConfiguration { use polkadot_primitives::{ - vstaging::{node_features::FeatureIndex, ApprovalVotingParams}, - AsyncBackingParams, MAX_CODE_SIZE, MAX_POV_SIZE, + node_features::FeatureIndex, ApprovalVotingParams, AsyncBackingParams, MAX_CODE_SIZE, + MAX_POV_SIZE, }; polkadot_runtime_parachains::configuration::HostConfiguration { diff --git a/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs b/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs index 3b08d0ed861..619a3617ca4 100644 --- a/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs +++ b/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs @@ -41,8 +41,8 @@ use polkadot_node_primitives::approval::{ v2::{CoreBitfield, IndirectAssignmentCertV2, IndirectSignedApprovalVoteV2}, }; use polkadot_primitives::{ - vstaging::ApprovalVoteMultipleCandidates, CandidateEvent, CandidateHash, CandidateIndex, - CoreIndex, Hash, SessionInfo, Slot, ValidatorId, ValidatorIndex, ASSIGNMENT_KEY_TYPE_ID, + ApprovalVoteMultipleCandidates, CandidateEvent, CandidateHash, CandidateIndex, CoreIndex, Hash, + SessionInfo, Slot, ValidatorId, ValidatorIndex, ASSIGNMENT_KEY_TYPE_ID, }; use rand::{seq::SliceRandom, RngCore, SeedableRng}; use rand_chacha::ChaCha20Rng; diff --git a/polkadot/node/subsystem-bench/src/lib/mock/runtime_api.rs b/polkadot/node/subsystem-bench/src/lib/mock/runtime_api.rs index 3c39de870a2..b73d61321cd 100644 --- a/polkadot/node/subsystem-bench/src/lib/mock/runtime_api.rs +++ b/polkadot/node/subsystem-bench/src/lib/mock/runtime_api.rs @@ -26,7 +26,7 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_types::OverseerSignal; use polkadot_primitives::{ - vstaging::NodeFeatures, CandidateEvent, CandidateReceipt, CoreState, GroupIndex, IndexedVec, + CandidateEvent, CandidateReceipt, CoreState, GroupIndex, IndexedVec, NodeFeatures, OccupiedCore, SessionIndex, SessionInfo, ValidatorIndex, }; use sp_consensus_babe::Epoch as BabeEpoch; diff --git a/polkadot/node/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index d84b0b6dd14..2ca6728af01 100644 --- a/polkadot/node/subsystem-types/src/messages.rs +++ b/polkadot/node/subsystem-types/src/messages.rs @@ -42,16 +42,14 @@ use polkadot_node_primitives::{ ValidationResult, }; use polkadot_primitives::{ - async_backing, slashing, - vstaging::{ApprovalVotingParams, NodeFeatures}, - AuthorityDiscoveryId, BackedCandidate, BlockNumber, CandidateEvent, CandidateHash, - CandidateIndex, CandidateReceipt, CollatorId, CommittedCandidateReceipt, CoreIndex, CoreState, - DisputeState, ExecutorParams, GroupIndex, GroupRotationInfo, Hash, HeadData, - Header as BlockHeader, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, - MultiDisputeStatementSet, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, - PvfExecKind, SessionIndex, SessionInfo, SignedAvailabilityBitfield, - SignedAvailabilityBitfields, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, - ValidatorSignature, + async_backing, slashing, ApprovalVotingParams, AuthorityDiscoveryId, BackedCandidate, + BlockNumber, CandidateEvent, CandidateHash, CandidateIndex, CandidateReceipt, CollatorId, + CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, GroupIndex, + GroupRotationInfo, Hash, HeadData, Header as BlockHeader, Id as ParaId, InboundDownwardMessage, + InboundHrmpMessage, MultiDisputeStatementSet, NodeFeatures, OccupiedCoreAssumption, + PersistedValidationData, PvfCheckStatement, PvfExecKind, SessionIndex, SessionInfo, + SignedAvailabilityBitfield, SignedAvailabilityBitfields, ValidationCode, ValidationCodeHash, + ValidatorId, ValidatorIndex, ValidatorSignature, }; use polkadot_statement_table::v2::Misbehavior; use std::{ diff --git a/polkadot/node/subsystem-types/src/runtime_client.rs b/polkadot/node/subsystem-types/src/runtime_client.rs index 7474b4120cc..664d10ed1af 100644 --- a/polkadot/node/subsystem-types/src/runtime_client.rs +++ b/polkadot/node/subsystem-types/src/runtime_client.rs @@ -16,16 +16,12 @@ use async_trait::async_trait; use polkadot_primitives::{ - async_backing, - runtime_api::ParachainHost, - slashing, - vstaging::{self, ApprovalVotingParams}, - Block, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, - CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, - GroupRotationInfo, Hash, Header, Id, InboundDownwardMessage, InboundHrmpMessage, - OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, - SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, - ValidatorSignature, + async_backing, runtime_api::ParachainHost, slashing, ApprovalVotingParams, Block, BlockNumber, + CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreIndex, + CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, Header, Id, + InboundDownwardMessage, InboundHrmpMessage, NodeFeatures, OccupiedCoreAssumption, + PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, + ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, }; use sc_client_api::{AuxStore, HeaderBackend}; use sc_transaction_pool_api::OffchainTransactionPoolFactory; @@ -324,7 +320,7 @@ pub trait RuntimeApiSubsystemClient { // === v9 === /// Get the node features. - async fn node_features(&self, at: Hash) -> Result; + async fn node_features(&self, at: Hash) -> Result; // == v10: Approval voting params == /// Approval voting configuration parameters @@ -586,7 +582,7 @@ where self.client.runtime_api().async_backing_params(at) } - async fn node_features(&self, at: Hash) -> Result { + async fn node_features(&self, at: Hash) -> Result { self.client.runtime_api().node_features(at) } diff --git a/polkadot/node/subsystem-util/src/runtime/mod.rs b/polkadot/node/subsystem-util/src/runtime/mod.rs index 481625acb32..714384b32e3 100644 --- a/polkadot/node/subsystem-util/src/runtime/mod.rs +++ b/polkadot/node/subsystem-util/src/runtime/mod.rs @@ -30,12 +30,11 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_types::UnpinHandle; use polkadot_primitives::{ - slashing, - vstaging::{node_features::FeatureIndex, NodeFeatures}, - AsyncBackingParams, CandidateEvent, CandidateHash, CoreState, EncodeAs, ExecutorParams, - GroupIndex, GroupRotationInfo, Hash, IndexedVec, OccupiedCore, ScrapedOnChainVotes, - SessionIndex, SessionInfo, Signed, SigningContext, UncheckedSigned, ValidationCode, - ValidationCodeHash, ValidatorId, ValidatorIndex, LEGACY_MIN_BACKING_VOTES, + node_features::FeatureIndex, slashing, AsyncBackingParams, CandidateEvent, CandidateHash, + CoreState, EncodeAs, ExecutorParams, GroupIndex, GroupRotationInfo, Hash, IndexedVec, + NodeFeatures, OccupiedCore, ScrapedOnChainVotes, SessionIndex, SessionInfo, Signed, + SigningContext, UncheckedSigned, ValidationCode, ValidationCodeHash, ValidatorId, + ValidatorIndex, LEGACY_MIN_BACKING_VOTES, }; use crate::{ diff --git a/polkadot/primitives/src/lib.rs b/polkadot/primitives/src/lib.rs index 745195ce092..d4eeb3cc3d2 100644 --- a/polkadot/primitives/src/lib.rs +++ b/polkadot/primitives/src/lib.rs @@ -20,7 +20,7 @@ #![cfg_attr(not(feature = "std"), no_std)] // `v6` is currently the latest stable version of the runtime API. -pub mod v6; +pub mod v7; // The 'staging' version is special - it contains primitives which are // still in development. Once they are considered stable, they will be @@ -33,26 +33,27 @@ pub mod runtime_api; // Current primitives not requiring versioning are exported here. // Primitives requiring versioning must not be exported and must be referred by an exact version. -pub use v6::{ +pub use v7::{ async_backing, byzantine_threshold, check_candidate_backing, collator_signature_payload, - effective_minimum_backing_votes, executor_params, metric_definitions, slashing, + effective_minimum_backing_votes, executor_params, metric_definitions, node_features, slashing, supermajority_threshold, well_known_keys, AbridgedHostConfiguration, AbridgedHrmpChannel, - AccountId, AccountIndex, AccountPublic, ApprovalVote, AssignmentId, AsyncBackingParams, - AuthorityDiscoveryId, AvailabilityBitfield, BackedCandidate, Balance, BlakeTwo256, Block, - BlockId, BlockNumber, CandidateCommitments, CandidateDescriptor, CandidateEvent, CandidateHash, - CandidateIndex, CandidateReceipt, CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, - CollatorId, CollatorSignature, CommittedCandidateReceipt, CompactStatement, ConsensusLog, - CoreIndex, CoreState, DisputeState, DisputeStatement, DisputeStatementSet, DownwardMessage, - EncodeAs, ExecutorParam, ExecutorParamError, ExecutorParams, ExecutorParamsHash, + AccountId, AccountIndex, AccountPublic, ApprovalVote, ApprovalVoteMultipleCandidates, + ApprovalVotingParams, AssignmentId, AsyncBackingParams, AuthorityDiscoveryId, + AvailabilityBitfield, BackedCandidate, Balance, BlakeTwo256, Block, BlockId, BlockNumber, + CandidateCommitments, CandidateDescriptor, CandidateEvent, CandidateHash, CandidateIndex, + CandidateReceipt, CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, CollatorId, + CollatorSignature, CommittedCandidateReceipt, CompactStatement, ConsensusLog, CoreIndex, + CoreState, DisputeState, DisputeStatement, DisputeStatementSet, DownwardMessage, EncodeAs, + ExecutorParam, ExecutorParamError, ExecutorParams, ExecutorParamsHash, ExplicitDisputeStatement, GroupIndex, GroupRotationInfo, Hash, HashT, HeadData, Header, HorizontalMessages, HrmpChannelId, Id, InboundDownwardMessage, InboundHrmpMessage, IndexedVec, - InherentData, InvalidDisputeStatementKind, Moment, MultiDisputeStatementSet, Nonce, - OccupiedCore, OccupiedCoreAssumption, OutboundHrmpMessage, ParathreadClaim, ParathreadEntry, - PersistedValidationData, PvfCheckStatement, PvfExecKind, PvfPrepKind, RuntimeMetricLabel, - RuntimeMetricLabelValue, RuntimeMetricLabelValues, RuntimeMetricLabels, RuntimeMetricOp, - RuntimeMetricUpdate, ScheduledCore, ScrapedOnChainVotes, SessionIndex, SessionInfo, Signature, - Signed, SignedAvailabilityBitfield, SignedAvailabilityBitfields, SignedStatement, - SigningContext, Slot, UncheckedSigned, UncheckedSignedAvailabilityBitfield, + InherentData, InvalidDisputeStatementKind, Moment, MultiDisputeStatementSet, NodeFeatures, + Nonce, OccupiedCore, OccupiedCoreAssumption, OutboundHrmpMessage, ParathreadClaim, + ParathreadEntry, PersistedValidationData, PvfCheckStatement, PvfExecKind, PvfPrepKind, + RuntimeMetricLabel, RuntimeMetricLabelValue, RuntimeMetricLabelValues, RuntimeMetricLabels, + RuntimeMetricOp, RuntimeMetricUpdate, ScheduledCore, ScrapedOnChainVotes, SessionIndex, + SessionInfo, Signature, Signed, SignedAvailabilityBitfield, SignedAvailabilityBitfields, + SignedStatement, SigningContext, Slot, UncheckedSigned, UncheckedSignedAvailabilityBitfield, UncheckedSignedAvailabilityBitfields, UncheckedSignedStatement, UpgradeGoAhead, UpgradeRestriction, UpwardMessage, ValidDisputeStatementKind, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, ValidityAttestation, @@ -63,4 +64,4 @@ pub use v6::{ }; #[cfg(feature = "std")] -pub use v6::{AssignmentPair, CollatorPair, ValidatorPair}; +pub use v7::{AssignmentPair, CollatorPair, ValidatorPair}; diff --git a/polkadot/primitives/src/runtime_api.rs b/polkadot/primitives/src/runtime_api.rs index 6dca33f8823..f611936f270 100644 --- a/polkadot/primitives/src/runtime_api.rs +++ b/polkadot/primitives/src/runtime_api.rs @@ -114,13 +114,11 @@ //! separated from the stable primitives. use crate::{ - async_backing, slashing, - vstaging::{self, ApprovalVotingParams}, - AsyncBackingParams, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, - CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, - GroupRotationInfo, Hash, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, - ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidatorId, ValidatorIndex, - ValidatorSignature, + async_backing, slashing, ApprovalVotingParams, AsyncBackingParams, BlockNumber, + CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreIndex, + CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, NodeFeatures, + OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, + SessionIndex, SessionInfo, ValidatorId, ValidatorIndex, ValidatorSignature, }; use polkadot_core_primitives as pcp; @@ -279,7 +277,7 @@ sp_api::decl_runtime_apis! { /// Get node features. /// This is a staging method! Do not use on production runtimes! #[api_version(9)] - fn node_features() -> vstaging::NodeFeatures; + fn node_features() -> NodeFeatures; /***** Added in v10 *****/ /// Approval voting configuration parameters diff --git a/polkadot/primitives/src/v6/async_backing.rs b/polkadot/primitives/src/v7/async_backing.rs similarity index 100% rename from polkadot/primitives/src/v6/async_backing.rs rename to polkadot/primitives/src/v7/async_backing.rs diff --git a/polkadot/primitives/src/v6/executor_params.rs b/polkadot/primitives/src/v7/executor_params.rs similarity index 100% rename from polkadot/primitives/src/v6/executor_params.rs rename to polkadot/primitives/src/v7/executor_params.rs diff --git a/polkadot/primitives/src/v6/metrics.rs b/polkadot/primitives/src/v7/metrics.rs similarity index 100% rename from polkadot/primitives/src/v6/metrics.rs rename to polkadot/primitives/src/v7/metrics.rs diff --git a/polkadot/primitives/src/v6/mod.rs b/polkadot/primitives/src/v7/mod.rs similarity index 97% rename from polkadot/primitives/src/v6/mod.rs rename to polkadot/primitives/src/v7/mod.rs index 21cee753265..d4f4a633577 100644 --- a/polkadot/primitives/src/v6/mod.rs +++ b/polkadot/primitives/src/v7/mod.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! `V6` Primitives. +//! `V7` Primitives. use bitvec::{field::BitField, slice::BitSlice, vec::BitVec}; use parity_scale_codec::{Decode, Encode}; @@ -1184,6 +1184,32 @@ impl<'a> ApprovalVoteMultipleCandidates<'a> { } } +/// Approval voting configuration parameters +#[derive( + RuntimeDebug, + Copy, + Clone, + PartialEq, + Encode, + Decode, + TypeInfo, + serde::Serialize, + serde::Deserialize, +)] +pub struct ApprovalVotingParams { + /// The maximum number of candidates `approval-voting` can vote for with + /// a single signatures. + /// + /// Setting it to 1, means we send the approval as soon as we have it available. + pub max_approval_coalesce_count: u32, +} + +impl Default for ApprovalVotingParams { + fn default() -> Self { + Self { max_approval_coalesce_count: 1 } + } +} + /// Custom validity errors used in Polkadot while validating transactions. #[repr(u8)] pub enum ValidityError { @@ -1947,6 +1973,29 @@ pub enum PvfExecKind { Approval, } +/// Bit indices in the `HostConfiguration.node_features` that correspond to different node features. +pub type NodeFeatures = BitVec; + +/// Module containing feature-specific bit indices into the `NodeFeatures` bitvec. +pub mod node_features { + /// A feature index used to identify a bit into the node_features array stored + /// in the HostConfiguration. + #[repr(u8)] + pub enum FeatureIndex { + /// Tells if tranch0 assignments could be sent in a single certificate. + /// Reserved for: `` + EnableAssignmentsV2 = 0, + /// This feature enables the extension of `BackedCandidate::validator_indices` by 8 bits. + /// The value stored there represents the assumed core index where the candidates + /// are backed. This is needed for the elastic scaling MVP. + ElasticScalingMVP = 1, + /// First unassigned feature bit. + /// Every time a new feature flag is assigned it should take this value. + /// and this should be incremented. + FirstUnassigned = 2, + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/polkadot/primitives/src/v6/signed.rs b/polkadot/primitives/src/v7/signed.rs similarity index 100% rename from polkadot/primitives/src/v6/signed.rs rename to polkadot/primitives/src/v7/signed.rs diff --git a/polkadot/primitives/src/v6/slashing.rs b/polkadot/primitives/src/v7/slashing.rs similarity index 100% rename from polkadot/primitives/src/v6/slashing.rs rename to polkadot/primitives/src/v7/slashing.rs diff --git a/polkadot/primitives/src/vstaging/mod.rs b/polkadot/primitives/src/vstaging/mod.rs index 94e9e892029..1af73993f64 100644 --- a/polkadot/primitives/src/vstaging/mod.rs +++ b/polkadot/primitives/src/vstaging/mod.rs @@ -17,7 +17,7 @@ //! Staging Primitives. // Put any primitives used by staging APIs functions here -pub use crate::v6::*; +use crate::v7::*; use sp_std::prelude::*; use parity_scale_codec::{Decode, Encode}; @@ -25,32 +25,6 @@ use primitives::RuntimeDebug; use scale_info::TypeInfo; use sp_arithmetic::Perbill; -/// Approval voting configuration parameters -#[derive( - RuntimeDebug, - Copy, - Clone, - PartialEq, - Encode, - Decode, - TypeInfo, - serde::Serialize, - serde::Deserialize, -)] -pub struct ApprovalVotingParams { - /// The maximum number of candidates `approval-voting` can vote for with - /// a single signatures. - /// - /// Setting it to 1, means we send the approval as soon as we have it available. - pub max_approval_coalesce_count: u32, -} - -impl Default for ApprovalVotingParams { - fn default() -> Self { - Self { max_approval_coalesce_count: 1 } - } -} - /// Scheduler configuration parameters. All coretime/ondemand parameters are here. #[derive( RuntimeDebug, @@ -125,28 +99,3 @@ impl> Default for SchedulerParams } } } - -use bitvec::vec::BitVec; - -/// Bit indices in the `HostConfiguration.node_features` that correspond to different node features. -pub type NodeFeatures = BitVec; - -/// Module containing feature-specific bit indices into the `NodeFeatures` bitvec. -pub mod node_features { - /// A feature index used to identify a bit into the node_features array stored - /// in the HostConfiguration. - #[repr(u8)] - pub enum FeatureIndex { - /// Tells if tranch0 assignments could be sent in a single certificate. - /// Reserved for: `` - EnableAssignmentsV2 = 0, - /// This feature enables the extension of `BackedCandidate::validator_indices` by 8 bits. - /// The value stored there represents the assumed core index where the candidates - /// are backed. This is needed for the elastic scaling MVP. - ElasticScalingMVP = 1, - /// First unassigned feature bit. - /// Every time a new feature flag is assigned it should take this value. - /// and this should be incremented. - FirstUnassigned = 2, - } -} diff --git a/polkadot/runtime/parachains/src/builder.rs b/polkadot/runtime/parachains/src/builder.rs index 73617010f6d..e29c2e218ed 100644 --- a/polkadot/runtime/parachains/src/builder.rs +++ b/polkadot/runtime/parachains/src/builder.rs @@ -25,13 +25,13 @@ use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; use primitives::{ - collator_signature_payload, vstaging::node_features::FeatureIndex, AvailabilityBitfield, - BackedCandidate, CandidateCommitments, CandidateDescriptor, CandidateHash, CollatorId, - CollatorSignature, CommittedCandidateReceipt, CompactStatement, CoreIndex, DisputeStatement, - DisputeStatementSet, GroupIndex, HeadData, Id as ParaId, IndexedVec, - InherentData as ParachainsInherentData, InvalidDisputeStatementKind, PersistedValidationData, - SessionIndex, SigningContext, UncheckedSigned, ValidDisputeStatementKind, ValidationCode, - ValidatorId, ValidatorIndex, ValidityAttestation, + collator_signature_payload, node_features::FeatureIndex, AvailabilityBitfield, BackedCandidate, + CandidateCommitments, CandidateDescriptor, CandidateHash, CollatorId, CollatorSignature, + CommittedCandidateReceipt, CompactStatement, CoreIndex, DisputeStatement, DisputeStatementSet, + GroupIndex, HeadData, Id as ParaId, IndexedVec, InherentData as ParachainsInherentData, + InvalidDisputeStatementKind, PersistedValidationData, SessionIndex, SigningContext, + UncheckedSigned, ValidDisputeStatementKind, ValidationCode, ValidatorId, ValidatorIndex, + ValidityAttestation, }; use sp_core::{sr25519, H256}; use sp_runtime::{ diff --git a/polkadot/runtime/parachains/src/configuration.rs b/polkadot/runtime/parachains/src/configuration.rs index 17022272c0c..e1246fb8897 100644 --- a/polkadot/runtime/parachains/src/configuration.rs +++ b/polkadot/runtime/parachains/src/configuration.rs @@ -26,10 +26,9 @@ use polkadot_parachain_primitives::primitives::{ MAX_HORIZONTAL_MESSAGE_NUM, MAX_UPWARD_MESSAGE_NUM, }; use primitives::{ - vstaging::{ApprovalVotingParams, NodeFeatures}, - AsyncBackingParams, Balance, ExecutorParamError, ExecutorParams, SessionIndex, - LEGACY_MIN_BACKING_VOTES, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MAX_POV_SIZE, - ON_DEMAND_MAX_QUEUE_MAX_SIZE, + ApprovalVotingParams, AsyncBackingParams, Balance, ExecutorParamError, ExecutorParams, + NodeFeatures, SessionIndex, LEGACY_MIN_BACKING_VOTES, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, + MAX_POV_SIZE, ON_DEMAND_MAX_QUEUE_MAX_SIZE, }; use sp_runtime::{traits::Zero, Perbill}; use sp_std::prelude::*; diff --git a/polkadot/runtime/parachains/src/configuration/migration/v10.rs b/polkadot/runtime/parachains/src/configuration/migration/v10.rs index cf228610e5c..3c8d6084ace 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v10.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v10.rs @@ -20,7 +20,7 @@ use crate::configuration::{Config, Pallet}; use frame_support::{pallet_prelude::*, traits::Defensive, weights::Weight}; use frame_system::pallet_prelude::BlockNumberFor; use primitives::{ - vstaging::NodeFeatures, AsyncBackingParams, Balance, ExecutorParams, SessionIndex, + AsyncBackingParams, Balance, ExecutorParams, NodeFeatures, SessionIndex, LEGACY_MIN_BACKING_VOTES, ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, }; use sp_runtime::Perbill; diff --git a/polkadot/runtime/parachains/src/configuration/migration/v11.rs b/polkadot/runtime/parachains/src/configuration/migration/v11.rs index f6e0e043164..7ed9d086885 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v11.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v11.rs @@ -22,14 +22,13 @@ use frame_support::{ }; use frame_system::pallet_prelude::BlockNumberFor; use primitives::{ - vstaging::ApprovalVotingParams, AsyncBackingParams, ExecutorParams, SessionIndex, + ApprovalVotingParams, AsyncBackingParams, ExecutorParams, NodeFeatures, SessionIndex, LEGACY_MIN_BACKING_VOTES, ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, }; use sp_std::vec::Vec; use frame_support::traits::OnRuntimeUpgrade; use polkadot_core_primitives::Balance; -use primitives::vstaging::NodeFeatures; use sp_arithmetic::Perbill; use super::v10::V10HostConfiguration; diff --git a/polkadot/runtime/parachains/src/disputes.rs b/polkadot/runtime/parachains/src/disputes.rs index cffad42e0ec..8bba97ce4bc 100644 --- a/polkadot/runtime/parachains/src/disputes.rs +++ b/polkadot/runtime/parachains/src/disputes.rs @@ -25,11 +25,11 @@ use frame_system::pallet_prelude::*; use parity_scale_codec::{Decode, Encode}; use polkadot_runtime_metrics::get_current_time; use primitives::{ - byzantine_threshold, supermajority_threshold, vstaging::ApprovalVoteMultipleCandidates, - ApprovalVote, CandidateHash, CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, - CompactStatement, ConsensusLog, DisputeState, DisputeStatement, DisputeStatementSet, - ExplicitDisputeStatement, InvalidDisputeStatementKind, MultiDisputeStatementSet, SessionIndex, - SigningContext, ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorSignature, + byzantine_threshold, supermajority_threshold, ApprovalVote, ApprovalVoteMultipleCandidates, + CandidateHash, CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, CompactStatement, + ConsensusLog, DisputeState, DisputeStatement, DisputeStatementSet, ExplicitDisputeStatement, + InvalidDisputeStatementKind, MultiDisputeStatementSet, SessionIndex, SigningContext, + ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorSignature, }; use scale_info::TypeInfo; use sp_runtime::{ diff --git a/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs b/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs index 1b07acffb15..8f6f2166a66 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs @@ -20,7 +20,7 @@ use frame_benchmarking::{benchmarks, impl_benchmark_test_suite}; use frame_system::RawOrigin; use sp_std::{cmp::min, collections::btree_map::BTreeMap}; -use primitives::v6::GroupIndex; +use primitives::v7::GroupIndex; use crate::builder::BenchBuilder; diff --git a/polkadot/runtime/parachains/src/paras_inherent/mod.rs b/polkadot/runtime/parachains/src/paras_inherent/mod.rs index 6a20a10a8d7..31c9ab84b60 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/mod.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/mod.rs @@ -43,9 +43,9 @@ use frame_support::{ use frame_system::pallet_prelude::*; use pallet_babe::{self, ParentBlockRandomness}; use primitives::{ - effective_minimum_backing_votes, vstaging::node_features::FeatureIndex, BackedCandidate, - CandidateHash, CandidateReceipt, CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, - CoreIndex, DisputeStatementSet, HeadData, InherentData as ParachainsInherentData, + effective_minimum_backing_votes, node_features::FeatureIndex, BackedCandidate, CandidateHash, + CandidateReceipt, CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, CoreIndex, + DisputeStatementSet, HeadData, InherentData as ParachainsInherentData, MultiDisputeStatementSet, ScrapedOnChainVotes, SessionIndex, SignedAvailabilityBitfields, SigningContext, UncheckedSignedAvailabilityBitfield, UncheckedSignedAvailabilityBitfields, ValidatorId, ValidatorIndex, ValidityAttestation, PARACHAINS_INHERENT_IDENTIFIER, diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/mod.rs b/polkadot/runtime/parachains/src/runtime_api_impl/mod.rs index ba74e488cd3..ed2e95b3cfa 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/mod.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/mod.rs @@ -26,5 +26,5 @@ //! 2. Move methods from `vstaging` to `v3`. The new stable version should include all methods from //! `vstaging` tagged with the new version number (e.g. all `v3` methods). -pub mod v7; +pub mod v10; pub mod vstaging; diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/v7.rs b/polkadot/runtime/parachains/src/runtime_api_impl/v10.rs similarity index 93% rename from polkadot/runtime/parachains/src/runtime_api_impl/v7.rs rename to polkadot/runtime/parachains/src/runtime_api_impl/v10.rs index 171f3f746a8..21f54121ab1 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/v7.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/v10.rs @@ -14,7 +14,7 @@ //! A module exporting runtime API implementation functions for all runtime APIs using `v5` //! primitives. //! -//! Runtimes implementing the v2 runtime API are recommended to forward directly to these +//! Runtimes implementing the v10 runtime API are recommended to forward directly to these //! functions. use crate::{ @@ -29,11 +29,12 @@ use primitives::{ AsyncBackingParams, BackingState, CandidatePendingAvailability, Constraints, InboundHrmpLimitations, OutboundHrmpChannelLimitations, }, - slashing, AuthorityDiscoveryId, CandidateEvent, CandidateHash, CommittedCandidateReceipt, - CoreIndex, CoreState, DisputeState, ExecutorParams, GroupIndex, GroupRotationInfo, Hash, - Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, OccupiedCore, OccupiedCoreAssumption, - PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, - ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, + slashing, ApprovalVotingParams, AuthorityDiscoveryId, CandidateEvent, CandidateHash, + CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, GroupIndex, + GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, + NodeFeatures, OccupiedCore, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, + ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, + ValidatorId, ValidatorIndex, ValidatorSignature, }; use sp_runtime::traits::One; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; @@ -517,3 +518,24 @@ pub fn backing_state( pub fn async_backing_params() -> AsyncBackingParams { >::config().async_backing_params } + +/// Implementation for `DisabledValidators` +// CAVEAT: this should only be called on the node side +// as it might produce incorrect results on session boundaries +pub fn disabled_validators() -> Vec +where + T: shared::Config, +{ + >::disabled_validators() +} + +/// Returns the current state of the node features. +pub fn node_features() -> NodeFeatures { + >::config().node_features +} + +/// Approval voting subsystem configuration parameters +pub fn approval_voting_params() -> ApprovalVotingParams { + let config = >::config(); + config.approval_voting_params +} diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs b/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs index 296b872e8d4..28be3f53863 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs @@ -16,36 +16,9 @@ //! Put implementations of functions from staging APIs here. -use crate::{configuration, initializer, scheduler, shared}; -use primitives::{ - vstaging::{ApprovalVotingParams, NodeFeatures}, - CoreIndex, Id as ParaId, ValidatorIndex, -}; -use sp_std::{ - collections::{btree_map::BTreeMap, vec_deque::VecDeque}, - prelude::Vec, -}; - -/// Implementation for `DisabledValidators` -// CAVEAT: this should only be called on the node side -// as it might produce incorrect results on session boundaries -pub fn disabled_validators() -> Vec -where - T: shared::Config, -{ - >::disabled_validators() -} - -/// Returns the current state of the node features. -pub fn node_features() -> NodeFeatures { - >::config().node_features -} - -/// Approval voting subsystem configuration parameters -pub fn approval_voting_params() -> ApprovalVotingParams { - let config = >::config(); - config.approval_voting_params -} +use crate::scheduler; +use primitives::{CoreIndex, Id as ParaId}; +use sp_std::collections::{btree_map::BTreeMap, vec_deque::VecDeque}; /// Returns the claimqueue from the scheduler pub fn claim_queue() -> BTreeMap> { diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index f37c901475a..84f98a3dba1 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -23,13 +23,12 @@ use pallet_nis::WithMaximumOf; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use primitives::{ - slashing, - vstaging::{ApprovalVotingParams, NodeFeatures}, - AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CandidateHash, - CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, - Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, Moment, Nonce, - OccupiedCoreAssumption, PersistedValidationData, ScrapedOnChainVotes, SessionInfo, Signature, - ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, PARACHAIN_KEY_TYPE_ID, + slashing, AccountId, AccountIndex, ApprovalVotingParams, Balance, BlockNumber, CandidateEvent, + CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, + GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, Moment, + NodeFeatures, Nonce, OccupiedCoreAssumption, PersistedValidationData, ScrapedOnChainVotes, + SessionInfo, Signature, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, + PARACHAIN_KEY_TYPE_ID, }; use rococo_runtime_constants::system_parachain::BROKER_ID; use runtime_common::{ @@ -53,9 +52,7 @@ use runtime_parachains::{ inclusion::{AggregateMessageOrigin, UmpQueueId}, initializer as parachains_initializer, origin as parachains_origin, paras as parachains_paras, paras_inherent as parachains_paras_inherent, - runtime_api_impl::{ - v7 as parachains_runtime_api_impl, vstaging as parachains_staging_runtime_api_impl, - }, + runtime_api_impl::v10 as parachains_runtime_api_impl, scheduler as parachains_scheduler, session_info as parachains_session_info, shared as parachains_shared, }; @@ -2017,15 +2014,15 @@ sp_api::impl_runtime_apis! { } fn approval_voting_params() -> ApprovalVotingParams { - parachains_staging_runtime_api_impl::approval_voting_params::() + parachains_runtime_api_impl::approval_voting_params::() } fn disabled_validators() -> Vec { - parachains_staging_runtime_api_impl::disabled_validators::() + parachains_runtime_api_impl::disabled_validators::() } fn node_features() -> NodeFeatures { - parachains_staging_runtime_api_impl::node_features::() + parachains_runtime_api_impl::node_features::() } } diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 62c3741c56d..446cd101eff 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -27,11 +27,10 @@ use sp_std::{collections::btree_map::BTreeMap, prelude::*}; use polkadot_runtime_parachains::{ assigner_parachains as parachains_assigner_parachains, configuration as parachains_configuration, disputes as parachains_disputes, - disputes::slashing as parachains_slashing, - dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion, - initializer as parachains_initializer, origin as parachains_origin, paras as parachains_paras, - paras_inherent as parachains_paras_inherent, - runtime_api_impl::{v7 as runtime_impl, vstaging as staging_runtime_impl}, + disputes::slashing as parachains_slashing, dmp as parachains_dmp, hrmp as parachains_hrmp, + inclusion as parachains_inclusion, initializer as parachains_initializer, + origin as parachains_origin, paras as parachains_paras, + paras_inherent as parachains_paras_inherent, runtime_api_impl::v10 as runtime_impl, scheduler as parachains_scheduler, session_info as parachains_session_info, shared as parachains_shared, }; @@ -971,16 +970,16 @@ sp_api::impl_runtime_apis! { runtime_impl::async_backing_params::() } - fn approval_voting_params() -> primitives::vstaging::ApprovalVotingParams { - staging_runtime_impl::approval_voting_params::() + fn approval_voting_params() -> primitives::ApprovalVotingParams { + runtime_impl::approval_voting_params::() } fn disabled_validators() -> Vec { - staging_runtime_impl::disabled_validators::() + runtime_impl::disabled_validators::() } - fn node_features() -> primitives::vstaging::NodeFeatures { - staging_runtime_impl::node_features::() + fn node_features() -> primitives::NodeFeatures { + runtime_impl::node_features::() } } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index d75c1011d5f..c2651c4a447 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -45,14 +45,12 @@ use pallet_session::historical as session_historical; use pallet_transaction_payment::{CurrencyAdapter, FeeDetails, RuntimeDispatchInfo}; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use primitives::{ - slashing, - vstaging::{ApprovalVotingParams, NodeFeatures}, - AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CandidateHash, - CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, - Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, Moment, Nonce, - OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, - SessionInfo, Signature, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, - ValidatorSignature, PARACHAIN_KEY_TYPE_ID, + slashing, AccountId, AccountIndex, ApprovalVotingParams, Balance, BlockNumber, CandidateEvent, + CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, + GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, Moment, + NodeFeatures, Nonce, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, + ScrapedOnChainVotes, SessionInfo, Signature, ValidationCode, ValidationCodeHash, ValidatorId, + ValidatorIndex, ValidatorSignature, PARACHAIN_KEY_TYPE_ID, }; use runtime_common::{ assigned_slots, auctions, crowdloan, @@ -75,9 +73,7 @@ use runtime_parachains::{ inclusion::{AggregateMessageOrigin, UmpQueueId}, initializer as parachains_initializer, origin as parachains_origin, paras as parachains_paras, paras_inherent as parachains_paras_inherent, reward_points as parachains_reward_points, - runtime_api_impl::{ - v7 as parachains_runtime_api_impl, vstaging as parachains_staging_runtime_api_impl, - }, + runtime_api_impl::v10 as parachains_runtime_api_impl, scheduler as parachains_scheduler, session_info as parachains_session_info, shared as parachains_shared, }; @@ -2080,15 +2076,15 @@ sp_api::impl_runtime_apis! { } fn approval_voting_params() -> ApprovalVotingParams { - parachains_staging_runtime_api_impl::approval_voting_params::() + parachains_runtime_api_impl::approval_voting_params::() } fn disabled_validators() -> Vec { - parachains_staging_runtime_api_impl::disabled_validators::() + parachains_runtime_api_impl::disabled_validators::() } fn node_features() -> NodeFeatures { - parachains_staging_runtime_api_impl::node_features::() + parachains_runtime_api_impl::node_features::() } } -- GitLab From 9805ba2cd01922f81621e0f3ac8adc0180fb7a49 Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Mon, 1 Apr 2024 23:18:57 +0300 Subject: [PATCH 138/187] Fix links (#3928) Fix links Related CI failure: https://github.com/paritytech/polkadot-sdk/actions/runs/8455425042/job/23162858534?pr=3859 --- .github/workflows/check-links.yml | 4 ++-- docs/sdk/src/polkadot_sdk/substrate.rs | 2 +- docs/sdk/src/polkadot_sdk/templates.rs | 5 ++--- docs/sdk/src/reference_docs/runtime_vs_smart_contract.rs | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/check-links.yml b/.github/workflows/check-links.yml index 903d7a3fcb3..58065f369c9 100644 --- a/.github/workflows/check-links.yml +++ b/.github/workflows/check-links.yml @@ -3,8 +3,8 @@ name: Check links on: pull_request: paths: - - "*.rs" - - "*.prdoc" + - "**.rs" + - "**.prdoc" - ".github/workflows/check-links.yml" - ".config/lychee.toml" types: [opened, synchronize, reopened, ready_for_review] diff --git a/docs/sdk/src/polkadot_sdk/substrate.rs b/docs/sdk/src/polkadot_sdk/substrate.rs index 5021c55e581..69d74d86db1 100644 --- a/docs/sdk/src/polkadot_sdk/substrate.rs +++ b/docs/sdk/src/polkadot_sdk/substrate.rs @@ -99,7 +99,7 @@ //! demonstration. //! * [`chain_spec_builder`]: Utility to build more detailed chain-specs for the aforementioned //! node. Other projects typically contain a `build-spec` subcommand that does the same. -//! * [`node_template`](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/bin/node-template): +//! * [`node_template`](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/bin/node): //! a template node that contains a minimal set of features and can act as a starting point of a //! project. //! * [`subkey`]: Substrate's key management utility. diff --git a/docs/sdk/src/polkadot_sdk/templates.rs b/docs/sdk/src/polkadot_sdk/templates.rs index f60c75b8f21..4bf0e839c79 100644 --- a/docs/sdk/src/polkadot_sdk/templates.rs +++ b/docs/sdk/src/polkadot_sdk/templates.rs @@ -22,9 +22,8 @@ //! - [`frontier-parachain-template`](https://github.com/paritytech/frontier-parachain-template): A //! parachain template for launching EVM-compatible parachains. //! -//! [`substrate-node-template`]: https://github.com/paritytech/polkadot-sdk/blob/master/substrate/bin/node-template/ -//! [`substrate-minimal-template`]: https://github.com/paritytech/polkadot-sdk/blob/master/substrate/bin/minimal/ -//! [`cumulus-parachain-template`]: https://github.com/paritytech/polkadot-sdk/blob/master/cumulus/parachain-template/ +//! [`minimal-template`]: https://github.com/paritytech/polkadot-sdk/blob/master/templates/minimal/ +//! [`parachain-template`]: https://github.com/paritytech/polkadot-sdk/blob/master/templates/parachain/ // TODO: in general, we need to make a deliberate choice here of moving a few key templates to this // repo (nothing stays in `substrate-developer-hub`) and the everything else should be community diff --git a/docs/sdk/src/reference_docs/runtime_vs_smart_contract.rs b/docs/sdk/src/reference_docs/runtime_vs_smart_contract.rs index 099512cf4ee..379b0c11b2a 100644 --- a/docs/sdk/src/reference_docs/runtime_vs_smart_contract.rs +++ b/docs/sdk/src/reference_docs/runtime_vs_smart_contract.rs @@ -117,7 +117,7 @@ //! - **Contract Code Updates**: Once deployed, although typically immutable, Smart Contracts can be //! upgraded, but lack of migration logic. The [pallet_contracts](../../../pallet_contracts/index.html) //! allows for contracts to be upgraded by exposing the `set_code` dispatchable. More details on this -//! can be found in [Ink! documentation on upgradeable contracts](https://use.ink/5.x/basics/upgradeable-contracts). +//! can be found in [Ink! documentation on upgradeable contracts](https://use.ink/basics/upgradeable-contracts). //! - **Isolated Impact**: Upgrades or changes to a smart contract generally impact only that //! contract and its users, unlike Runtime upgrades that have a network-wide effect. //! - **Simplicity and Rapid Development**: The development cycle for Smart Contracts is usually -- GitLab From bf1ca86f87f4dbdc137928e0e6b1b6a9eee1bb09 Mon Sep 17 00:00:00 2001 From: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Date: Tue, 2 Apr 2024 00:36:18 +0300 Subject: [PATCH 139/187] pallet-scheduler: fix test (#3923) fix https://github.com/paritytech/polkadot-sdk/issues/3921 --------- Signed-off-by: Andrei Sandu --- substrate/frame/scheduler/src/tests.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/substrate/frame/scheduler/src/tests.rs b/substrate/frame/scheduler/src/tests.rs index 44035533639..f251dde99a8 100644 --- a/substrate/frame/scheduler/src/tests.rs +++ b/substrate/frame/scheduler/src/tests.rs @@ -2285,9 +2285,18 @@ fn postponed_named_task_cannot_be_rescheduled() { // Run to a very large block. run_to_block(10); + // It was not executed. assert!(logger::log().is_empty()); - assert!(Preimage::is_requested(&hash)); + + // Preimage was not available + assert_eq!( + System::events().last().unwrap().event, + crate::Event::CallUnavailable { task: (4, 0), id: Some(name) }.into() + ); + + // So it should not be requested. + assert!(!Preimage::is_requested(&hash)); // Postponing removes the lookup. assert!(!Lookup::::contains_key(name)); @@ -2307,11 +2316,12 @@ fn postponed_named_task_cannot_be_rescheduled() { ); // Finally add the preimage. - assert_ok!(Preimage::note(call.encode().into())); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(0), call.encode())); + run_to_block(1000); // It did not execute. assert!(logger::log().is_empty()); - assert!(Preimage::is_requested(&hash)); + assert!(!Preimage::is_requested(&hash)); // Manually re-schedule the call by name does not work. assert_err!( -- GitLab From 52e103784945997cb3808cdfaaf72c468f8fc938 Mon Sep 17 00:00:00 2001 From: s0me0ne-unkn0wn <48632512+s0me0ne-unkn0wn@users.noreply.github.com> Date: Mon, 1 Apr 2024 23:40:38 +0200 Subject: [PATCH 140/187] `im-online` removal final cleanup (#3902) Rejoice! Rejoice! The story is nearly over. This PR removes stale migrations, auxiliary structures, and package dependencies, thus making Rococo and Westend totally free from any `im-online`-related stuff. `im-online` still stays a part of the Substrate node and its runtime: https://github.com/paritytech/polkadot-sdk/blob/0d9324847391e902bb42f84f0e76096b1f764efe/substrate/bin/node/runtime/src/lib.rs#L2276-L2277 I'm not sure if it makes sense to remove it from there considering that we're not removing `im-online` from FRAME. Please share your opinion. --- Cargo.lock | 4 - cumulus/test/service/Cargo.toml | 2 - polkadot/node/service/Cargo.toml | 3 - polkadot/runtime/rococo/Cargo.toml | 4 - polkadot/runtime/rococo/src/lib.rs | 137 +-------------------------- polkadot/runtime/westend/Cargo.toml | 4 - polkadot/runtime/westend/src/lib.rs | 139 +--------------------------- 7 files changed, 2 insertions(+), 291 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 81eb682a27d..02071ca38c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4322,7 +4322,6 @@ dependencies = [ "frame-system-rpc-runtime-api", "futures", "jsonrpsee", - "pallet-im-online", "pallet-timestamp", "pallet-transaction-payment", "parachains-common", @@ -13450,7 +13449,6 @@ dependencies = [ "log", "mmr-gadget", "pallet-babe", - "pallet-im-online", "pallet-staking", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", @@ -15054,7 +15052,6 @@ dependencies = [ "pallet-elections-phragmen", "pallet-grandpa", "pallet-identity", - "pallet-im-online", "pallet-indices", "pallet-membership", "pallet-message-queue", @@ -21905,7 +21902,6 @@ dependencies = [ "pallet-fast-unstake", "pallet-grandpa", "pallet-identity", - "pallet-im-online", "pallet-indices", "pallet-membership", "pallet-message-queue", diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index 45e21432f5b..113e0aca68a 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -88,7 +88,6 @@ pallet-timestamp = { path = "../../../substrate/frame/timestamp" } futures = "0.3.28" portpicker = "0.1.1" rococo-parachain-runtime = { path = "../../parachains/runtimes/testing/rococo-parachain" } -pallet-im-online = { path = "../../../substrate/frame/im-online" } sp-consensus-grandpa = { path = "../../../substrate/primitives/consensus/grandpa" } sp-authority-discovery = { path = "../../../substrate/primitives/authority-discovery" } cumulus-test-client = { path = "../client" } @@ -106,7 +105,6 @@ runtime-benchmarks = [ "cumulus-primitives-core/runtime-benchmarks", "cumulus-test-client/runtime-benchmarks", "frame-system/runtime-benchmarks", - "pallet-im-online/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "parachains-common/runtime-benchmarks", "polkadot-cli/runtime-benchmarks", diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 5a42443c84c..932f3e679f4 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -65,7 +65,6 @@ sp-version = { path = "../../../substrate/primitives/version" } # Substrate Pallets pallet-babe = { path = "../../../substrate/frame/babe" } -pallet-im-online = { path = "../../../substrate/frame/im-online" } pallet-staking = { path = "../../../substrate/frame/staking" } pallet-transaction-payment-rpc-runtime-api = { path = "../../../substrate/frame/transaction-payment/rpc/runtime-api" } frame-system = { path = "../../../substrate/frame/system" } @@ -197,7 +196,6 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-babe/runtime-benchmarks", - "pallet-im-online/runtime-benchmarks", "pallet-staking/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", @@ -213,7 +211,6 @@ try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", "pallet-babe/try-runtime", - "pallet-im-online/try-runtime", "pallet-staking/try-runtime", "pallet-transaction-payment/try-runtime", "polkadot-runtime-parachains/try-runtime", diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 6f63a93cebe..ff178b17070 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -60,7 +60,6 @@ pallet-asset-rate = { path = "../../../substrate/frame/asset-rate", default-feat frame-executive = { path = "../../../substrate/frame/executive", default-features = false } pallet-grandpa = { path = "../../../substrate/frame/grandpa", default-features = false } pallet-identity = { path = "../../../substrate/frame/identity", default-features = false } -pallet-im-online = { path = "../../../substrate/frame/im-online", default-features = false } pallet-indices = { path = "../../../substrate/frame/indices", default-features = false } pallet-membership = { path = "../../../substrate/frame/membership", default-features = false } pallet-message-queue = { path = "../../../substrate/frame/message-queue", default-features = false } @@ -153,7 +152,6 @@ std = [ "pallet-elections-phragmen/std", "pallet-grandpa/std", "pallet-identity/std", - "pallet-im-online/std", "pallet-indices/std", "pallet-membership/std", "pallet-message-queue/std", @@ -228,7 +226,6 @@ runtime-benchmarks = [ "pallet-elections-phragmen/runtime-benchmarks", "pallet-grandpa/runtime-benchmarks", "pallet-identity/runtime-benchmarks", - "pallet-im-online/runtime-benchmarks", "pallet-indices/runtime-benchmarks", "pallet-membership/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", @@ -284,7 +281,6 @@ try-runtime = [ "pallet-elections-phragmen/try-runtime", "pallet-grandpa/try-runtime", "pallet-identity/try-runtime", - "pallet-im-online/try-runtime", "pallet-indices/try-runtime", "pallet-membership/try-runtime", "pallet-message-queue/try-runtime", diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 84f98a3dba1..7d16d2dbf16 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -88,8 +88,7 @@ use sp_runtime::{ IdentityLookup, Keccak256, OpaqueKeys, SaturatedConversion, Verify, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, BoundToRuntimeAppPublic, FixedU128, KeyTypeId, Perbill, Percent, Permill, - RuntimeAppPublic, RuntimeDebug, + ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, Permill, RuntimeDebug, }; use sp_staking::SessionIndex; #[cfg(any(feature = "std", test))] @@ -347,46 +346,6 @@ impl pallet_authorship::Config for Runtime { type EventHandler = (); } -#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode)] -pub struct OldSessionKeys { - pub grandpa: ::Public, - pub babe: ::Public, - pub im_online: pallet_im_online::sr25519::AuthorityId, - pub para_validator: ::Public, - pub para_assignment: ::Public, - pub authority_discovery: ::Public, - pub beefy: ::Public, -} - -impl OpaqueKeys for OldSessionKeys { - type KeyTypeIdProviders = (); - fn key_ids() -> &'static [KeyTypeId] { - &[ - <::Public>::ID, - <::Public>::ID, - sp_core::crypto::key_types::IM_ONLINE, - <::Public>::ID, - <::Public>::ID, - <::Public>::ID, - <::Public>::ID, - ] - } - fn get_raw(&self, i: KeyTypeId) -> &[u8] { - match i { - <::Public>::ID => self.grandpa.as_ref(), - <::Public>::ID => self.babe.as_ref(), - sp_core::crypto::key_types::IM_ONLINE => self.im_online.as_ref(), - <::Public>::ID => self.para_validator.as_ref(), - <::Public>::ID => - self.para_assignment.as_ref(), - <::Public>::ID => - self.authority_discovery.as_ref(), - <::Public>::ID => self.beefy.as_ref(), - _ => &[], - } - } -} - impl_opaque_keys! { pub struct SessionKeys { pub grandpa: Grandpa, @@ -398,18 +357,6 @@ impl_opaque_keys! { } } -// remove this when removing `OldSessionKeys` -fn transform_session_keys(_val: AccountId, old: OldSessionKeys) -> SessionKeys { - SessionKeys { - grandpa: old.grandpa, - babe: old.babe, - para_validator: old.para_validator, - para_assignment: old.para_assignment, - authority_discovery: old.authority_discovery, - beefy: old.beefy, - } -} - /// Special `ValidatorIdOf` implementation that is just returning the input as result. pub struct ValidatorIdOf; impl sp_runtime::traits::Convert> for ValidatorIdOf { @@ -1486,8 +1433,6 @@ pub mod migrations { use frame_support::traits::LockIdentifier; use frame_system::pallet_prelude::BlockNumberFor; - #[cfg(feature = "try-runtime")] - use sp_core::crypto::ByteArray; pub struct GetLegacyLeaseImpl; impl coretime::migration::GetLegacyLease for GetLegacyLeaseImpl { @@ -1514,7 +1459,6 @@ pub mod migrations { pub const PhragmenElectionPalletName: &'static str = "PhragmenElection"; pub const TechnicalMembershipPalletName: &'static str = "TechnicalMembership"; pub const TipsPalletName: &'static str = "Tips"; - pub const ImOnlinePalletName: &'static str = "ImOnline"; pub const PhragmenElectionPalletId: LockIdentifier = *b"phrelect"; } @@ -1551,79 +1495,6 @@ pub mod migrations { type PalletName = TipsPalletName; } - /// Upgrade Session keys to exclude `ImOnline` key. - /// When this is removed, should also remove `OldSessionKeys`. - pub struct UpgradeSessionKeys; - const UPGRADE_SESSION_KEYS_FROM_SPEC: u32 = 104000; - - impl frame_support::traits::OnRuntimeUpgrade for UpgradeSessionKeys { - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { - if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC { - log::warn!(target: "runtime::session_keys", "Skipping session keys migration pre-upgrade check due to spec version (already applied?)"); - return Ok(Vec::new()); - } - - log::info!(target: "runtime::session_keys", "Collecting pre-upgrade session keys state"); - let key_ids = SessionKeys::key_ids(); - frame_support::ensure!( - key_ids.into_iter().find(|&k| *k == sp_core::crypto::key_types::IM_ONLINE) == None, - "New session keys contain the ImOnline key that should have been removed", - ); - let storage_key = pallet_session::QueuedKeys::::hashed_key(); - let mut state: Vec = Vec::new(); - frame_support::storage::unhashed::get::>( - &storage_key, - ) - .ok_or::("Queued keys are not available".into())? - .into_iter() - .for_each(|(id, keys)| { - state.extend_from_slice(id.as_slice()); - for key_id in key_ids { - state.extend_from_slice(keys.get_raw(*key_id)); - } - }); - frame_support::ensure!(state.len() > 0, "Queued keys are not empty before upgrade"); - Ok(state) - } - - fn on_runtime_upgrade() -> Weight { - if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC { - log::info!("Skipping session keys upgrade: already applied"); - return ::DbWeight::get().reads(1); - } - log::trace!("Upgrading session keys"); - Session::upgrade_keys::(transform_session_keys); - Perbill::from_percent(50) * BlockWeights::get().max_block - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade( - old_state: sp_std::vec::Vec, - ) -> Result<(), sp_runtime::TryRuntimeError> { - if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC { - log::warn!(target: "runtime::session_keys", "Skipping session keys migration post-upgrade check due to spec version (already applied?)"); - return Ok(()); - } - - let key_ids = SessionKeys::key_ids(); - let mut new_state: Vec = Vec::new(); - pallet_session::QueuedKeys::::get().into_iter().for_each(|(id, keys)| { - new_state.extend_from_slice(id.as_slice()); - for key_id in key_ids { - new_state.extend_from_slice(keys.get_raw(*key_id)); - } - }); - frame_support::ensure!(new_state.len() > 0, "Queued keys are not empty after upgrade"); - frame_support::ensure!( - old_state == new_state, - "Pre-upgrade and post-upgrade keys do not match!" - ); - log::info!(target: "runtime::session_keys", "Session keys migrated successfully"); - Ok(()) - } - } - // We don't have a limit in the Relay Chain. const IDENTITY_MIGRATION_KEY_LIMIT: u64 = u64::MAX; @@ -1657,12 +1528,6 @@ pub mod migrations { pallet_grandpa::migrations::MigrateV4ToV5, parachains_configuration::migration::v10::MigrateToV10, - // Upgrade `SessionKeys` to exclude `ImOnline` - UpgradeSessionKeys, - - // Remove `im-online` pallet on-chain storage - frame_support::migrations::RemovePallet::DbWeight>, - // Migrate Identity pallet for Usernames pallet_identity::migration::versioned::V0ToV1, parachains_configuration::migration::v11::MigrateToV11, diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index 587a6c9a590..4c27d4f6d1f 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -64,7 +64,6 @@ pallet-election-provider-multi-phase = { path = "../../../substrate/frame/electi pallet-fast-unstake = { path = "../../../substrate/frame/fast-unstake", default-features = false } pallet-grandpa = { path = "../../../substrate/frame/grandpa", default-features = false } pallet-identity = { path = "../../../substrate/frame/identity", default-features = false } -pallet-im-online = { path = "../../../substrate/frame/im-online", default-features = false } pallet-indices = { path = "../../../substrate/frame/indices", default-features = false } pallet-membership = { path = "../../../substrate/frame/membership", default-features = false } pallet-message-queue = { path = "../../../substrate/frame/message-queue", default-features = false } @@ -167,7 +166,6 @@ std = [ "pallet-fast-unstake/std", "pallet-grandpa/std", "pallet-identity/std", - "pallet-im-online/std", "pallet-indices/std", "pallet-membership/std", "pallet-message-queue/std", @@ -251,7 +249,6 @@ runtime-benchmarks = [ "pallet-fast-unstake/runtime-benchmarks", "pallet-grandpa/runtime-benchmarks", "pallet-identity/runtime-benchmarks", - "pallet-im-online/runtime-benchmarks", "pallet-indices/runtime-benchmarks", "pallet-membership/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", @@ -310,7 +307,6 @@ try-runtime = [ "pallet-fast-unstake/try-runtime", "pallet-grandpa/try-runtime", "pallet-identity/try-runtime", - "pallet-im-online/try-runtime", "pallet-indices/try-runtime", "pallet-membership/try-runtime", "pallet-message-queue/try-runtime", diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index c2651c4a447..9445e27f0e5 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -88,8 +88,7 @@ use sp_runtime::{ Keccak256, OpaqueKeys, SaturatedConversion, Verify, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, BoundToRuntimeAppPublic, FixedU128, KeyTypeId, Perbill, Percent, Permill, - RuntimeAppPublic, + ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, Permill, }; use sp_staking::SessionIndex; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; @@ -405,46 +404,6 @@ parameter_types! { pub const Offset: BlockNumber = 0; } -#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode)] -pub struct OldSessionKeys { - pub grandpa: ::Public, - pub babe: ::Public, - pub im_online: pallet_im_online::sr25519::AuthorityId, - pub para_validator: ::Public, - pub para_assignment: ::Public, - pub authority_discovery: ::Public, - pub beefy: ::Public, -} - -impl OpaqueKeys for OldSessionKeys { - type KeyTypeIdProviders = (); - fn key_ids() -> &'static [KeyTypeId] { - &[ - <::Public>::ID, - <::Public>::ID, - sp_core::crypto::key_types::IM_ONLINE, - <::Public>::ID, - <::Public>::ID, - <::Public>::ID, - <::Public>::ID, - ] - } - fn get_raw(&self, i: KeyTypeId) -> &[u8] { - match i { - <::Public>::ID => self.grandpa.as_ref(), - <::Public>::ID => self.babe.as_ref(), - sp_core::crypto::key_types::IM_ONLINE => self.im_online.as_ref(), - <::Public>::ID => self.para_validator.as_ref(), - <::Public>::ID => - self.para_assignment.as_ref(), - <::Public>::ID => - self.authority_discovery.as_ref(), - <::Public>::ID => self.beefy.as_ref(), - _ => &[], - } - } -} - impl_opaque_keys! { pub struct SessionKeys { pub grandpa: Grandpa, @@ -456,18 +415,6 @@ impl_opaque_keys! { } } -// remove this when removing `OldSessionKeys` -fn transform_session_keys(_v: AccountId, old: OldSessionKeys) -> SessionKeys { - SessionKeys { - grandpa: old.grandpa, - babe: old.babe, - para_validator: old.para_validator, - para_assignment: old.para_assignment, - authority_discovery: old.authority_discovery, - beefy: old.beefy, - } -} - impl pallet_session::Config for Runtime { type RuntimeEvent = RuntimeEvent; type ValidatorId = AccountId; @@ -1657,8 +1604,6 @@ pub type Migrations = migrations::Unreleased; #[allow(deprecated, missing_docs)] pub mod migrations { use super::*; - #[cfg(feature = "try-runtime")] - use sp_core::crypto::ByteArray; pub struct GetLegacyLeaseImpl; impl coretime::migration::GetLegacyLease for GetLegacyLeaseImpl { @@ -1678,83 +1623,6 @@ pub mod migrations { } } - parameter_types! { - pub const ImOnlinePalletName: &'static str = "ImOnline"; - } - - /// Upgrade Session keys to exclude `ImOnline` key. - /// When this is removed, should also remove `OldSessionKeys`. - pub struct UpgradeSessionKeys; - const UPGRADE_SESSION_KEYS_FROM_SPEC: u32 = 104000; - - impl frame_support::traits::OnRuntimeUpgrade for UpgradeSessionKeys { - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { - if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC { - log::warn!(target: "runtime::session_keys", "Skipping session keys migration pre-upgrade check due to spec version (already applied?)"); - return Ok(Vec::new()); - } - - log::info!(target: "runtime::session_keys", "Collecting pre-upgrade session keys state"); - let key_ids = SessionKeys::key_ids(); - frame_support::ensure!( - key_ids.into_iter().find(|&k| *k == sp_core::crypto::key_types::IM_ONLINE) == None, - "New session keys contain the ImOnline key that should have been removed", - ); - let storage_key = pallet_session::QueuedKeys::::hashed_key(); - let mut state: Vec = Vec::new(); - frame_support::storage::unhashed::get::>( - &storage_key, - ) - .ok_or::("Queued keys are not available".into())? - .into_iter() - .for_each(|(id, keys)| { - state.extend_from_slice(id.as_slice()); - for key_id in key_ids { - state.extend_from_slice(keys.get_raw(*key_id)); - } - }); - frame_support::ensure!(state.len() > 0, "Queued keys are not empty before upgrade"); - Ok(state) - } - - fn on_runtime_upgrade() -> Weight { - if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC { - log::warn!("Skipping session keys upgrade: already applied"); - return ::DbWeight::get().reads(1); - } - log::info!("Upgrading session keys"); - Session::upgrade_keys::(transform_session_keys); - Perbill::from_percent(50) * BlockWeights::get().max_block - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade( - old_state: sp_std::vec::Vec, - ) -> Result<(), sp_runtime::TryRuntimeError> { - if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC { - log::warn!(target: "runtime::session_keys", "Skipping session keys migration post-upgrade check due to spec version (already applied?)"); - return Ok(()); - } - - let key_ids = SessionKeys::key_ids(); - let mut new_state: Vec = Vec::new(); - pallet_session::QueuedKeys::::get().into_iter().for_each(|(id, keys)| { - new_state.extend_from_slice(id.as_slice()); - for key_id in key_ids { - new_state.extend_from_slice(keys.get_raw(*key_id)); - } - }); - frame_support::ensure!(new_state.len() > 0, "Queued keys are not empty after upgrade"); - frame_support::ensure!( - old_state == new_state, - "Pre-upgrade and post-upgrade keys do not match!" - ); - log::info!(target: "runtime::session_keys", "Session keys migrated successfully"); - Ok(()) - } - } - // We don't have a limit in the Relay Chain. const IDENTITY_MIGRATION_KEY_LIMIT: u64 = u64::MAX; @@ -1771,11 +1639,6 @@ pub mod migrations { pallet_grandpa::migrations::MigrateV4ToV5, parachains_configuration::migration::v10::MigrateToV10, pallet_nomination_pools::migration::unversioned::TotalValueLockedSync, - UpgradeSessionKeys, - frame_support::migrations::RemovePallet< - ImOnlinePalletName, - ::DbWeight, - >, // Migrate Identity pallet for Usernames pallet_identity::migration::versioned::V0ToV1, parachains_configuration::migration::v11::MigrateToV11, -- GitLab From 9a62de27a98312741b4ece2fcd1c6e61b47ee3c2 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 2 Apr 2024 01:53:51 -0400 Subject: [PATCH 141/187] Update derive syn parse 0.2.0 (+ docify) (#3920) derive-syn-parse v0.2.0 came out recently which (finally) adds support for syn 2x. Upgrading to this will remove many of the places where syn 1x was still compiling alongside syn 2x in the polkadot-sdk workspace. This also upgrades `docify` to 0.2.8 which is the version that upgrades derive-syn-pasre to 0.2.0. Additionally, this consolidates the `docify` versions in the repo to all use the latest, and in one case upgrades to the 0.2x syntax where 0.1.x was still being used. --------- Co-authored-by: Liam Aharon --- Cargo.lock | 95 ++++++++----------- .../storage-weight-reclaim/Cargo.toml | 2 +- docs/sdk/Cargo.toml | 2 +- substrate/client/chain-spec/Cargo.toml | 2 +- substrate/frame/Cargo.toml | 2 +- substrate/frame/bags-list/Cargo.toml | 2 +- substrate/frame/balances/Cargo.toml | 2 +- .../single-block-migrations/Cargo.toml | 2 +- substrate/frame/fast-unstake/Cargo.toml | 2 +- substrate/frame/migrations/Cargo.toml | 2 +- substrate/frame/migrations/src/lib.rs | 2 +- substrate/frame/paged-list/Cargo.toml | 2 +- substrate/frame/parameters/Cargo.toml | 2 +- substrate/frame/safe-mode/Cargo.toml | 2 +- substrate/frame/scheduler/Cargo.toml | 2 +- substrate/frame/sudo/Cargo.toml | 2 +- substrate/frame/support/Cargo.toml | 2 +- substrate/frame/support/procedural/Cargo.toml | 2 +- substrate/frame/system/Cargo.toml | 2 +- substrate/frame/timestamp/Cargo.toml | 2 +- substrate/frame/treasury/Cargo.toml | 2 +- substrate/frame/tx-pause/Cargo.toml | 2 +- substrate/primitives/arithmetic/Cargo.toml | 2 +- substrate/primitives/runtime/Cargo.toml | 2 +- 24 files changed, 63 insertions(+), 78 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 02071ca38c8..88fde5ed154 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4049,7 +4049,7 @@ dependencies = [ "cumulus-primitives-core", "cumulus-primitives-proof-size-hostfunction", "cumulus-test-runtime", - "docify 0.2.7", + "docify", "frame-support", "frame-system", "log", @@ -4571,6 +4571,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive-syn-parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -4718,47 +4729,21 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "docify" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1b04e6ef3d21119d3eb7b032bca17f99fe041e9c072f30f32cc0e1a2b1f3c4" -dependencies = [ - "docify_macros 0.1.16", -] - -[[package]] -name = "docify" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cc4fd38aaa9fb98ac70794c82a00360d1e165a87fbf96a8a91f9dfc602aaee2" +checksum = "43a2f138ad521dc4a2ced1a4576148a6a610b4c5923933b062a263130a6802ce" dependencies = [ - "docify_macros 0.2.7", + "docify_macros", ] [[package]] name = "docify_macros" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b5610df7f2acf89a1bb5d1a66ae56b1c7fcdcfe3948856fb3ace3f644d70eb7" -dependencies = [ - "common-path", - "derive-syn-parse", - "lazy_static", - "proc-macro2", - "quote", - "regex", - "syn 2.0.53", - "termcolor", - "walkdir", -] - -[[package]] -name = "docify_macros" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63fa215f3a0d40fb2a221b3aa90d8e1fbb8379785a990cb60d62ac71ebdc6460" +checksum = "1a081e51fb188742f5a7a1164ad752121abcb22874b21e2c3b0dd040c515fdad" dependencies = [ "common-path", - "derive-syn-parse", + "derive-syn-parse 0.2.0", "once_cell", "proc-macro2", "quote", @@ -5454,7 +5439,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" name = "frame" version = "0.0.1-dev" dependencies = [ - "docify 0.2.7", + "docify", "frame-executive", "frame-support", "frame-system", @@ -5683,7 +5668,7 @@ dependencies = [ "array-bytes 6.1.0", "assert_matches", "bitflags 1.3.2", - "docify 0.2.7", + "docify", "environmental", "frame-metadata", "frame-support-procedural", @@ -5726,7 +5711,7 @@ version = "23.0.0" dependencies = [ "Inflector", "cfg-expr", - "derive-syn-parse", + "derive-syn-parse 0.2.0", "expander 2.0.0", "frame-support-procedural-tools", "itertools 0.10.5", @@ -5827,7 +5812,7 @@ version = "28.0.0" dependencies = [ "cfg-if", "criterion 0.4.0", - "docify 0.2.7", + "docify", "frame-support", "log", "parity-scale-codec", @@ -7944,7 +7929,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "468155613a44cfd825f1fb0ffa532b018253920d404e6fca1e8d43155198a46d" dependencies = [ "const-random", - "derive-syn-parse", + "derive-syn-parse 0.1.5", "macro_magic_core_macros", "proc-macro2", "quote", @@ -9216,7 +9201,7 @@ name = "pallet-bags-list" version = "27.0.0" dependencies = [ "aquamarine 0.5.0", - "docify 0.2.7", + "docify", "frame-benchmarking", "frame-election-provider-support", "frame-support", @@ -9264,7 +9249,7 @@ dependencies = [ name = "pallet-balances" version = "28.0.0" dependencies = [ - "docify 0.2.7", + "docify", "frame-benchmarking", "frame-support", "frame-system", @@ -9883,7 +9868,7 @@ dependencies = [ name = "pallet-example-single-block-migrations" version = "0.0.1" dependencies = [ - "docify 0.2.7", + "docify", "frame-executive", "frame-support", "frame-system", @@ -9949,7 +9934,7 @@ dependencies = [ name = "pallet-fast-unstake" version = "27.0.0" dependencies = [ - "docify 0.2.7", + "docify", "frame-benchmarking", "frame-election-provider-support", "frame-support", @@ -10150,7 +10135,7 @@ dependencies = [ name = "pallet-migrations" version = "1.0.0" dependencies = [ - "docify 0.1.16", + "docify", "frame-benchmarking", "frame-executive", "frame-support", @@ -10454,7 +10439,7 @@ dependencies = [ name = "pallet-paged-list" version = "0.6.0" dependencies = [ - "docify 0.2.7", + "docify", "frame-benchmarking", "frame-support", "frame-system", @@ -10496,7 +10481,7 @@ dependencies = [ name = "pallet-parameters" version = "0.0.1" dependencies = [ - "docify 0.2.7", + "docify", "frame-benchmarking", "frame-support", "frame-system", @@ -10657,7 +10642,7 @@ dependencies = [ name = "pallet-safe-mode" version = "9.0.0" dependencies = [ - "docify 0.2.7", + "docify", "frame-benchmarking", "frame-support", "frame-system", @@ -10714,7 +10699,7 @@ dependencies = [ name = "pallet-scheduler" version = "29.0.0" dependencies = [ - "docify 0.2.7", + "docify", "frame-benchmarking", "frame-support", "frame-system", @@ -10927,7 +10912,7 @@ dependencies = [ name = "pallet-sudo" version = "28.0.0" dependencies = [ - "docify 0.2.7", + "docify", "frame-benchmarking", "frame-support", "frame-system", @@ -10957,7 +10942,7 @@ dependencies = [ name = "pallet-timestamp" version = "27.0.0" dependencies = [ - "docify 0.2.7", + "docify", "frame-benchmarking", "frame-support", "frame-system", @@ -11061,7 +11046,7 @@ dependencies = [ name = "pallet-treasury" version = "27.0.0" dependencies = [ - "docify 0.2.7", + "docify", "frame-benchmarking", "frame-support", "frame-system", @@ -11081,7 +11066,7 @@ dependencies = [ name = "pallet-tx-pause" version = "9.0.0" dependencies = [ - "docify 0.2.7", + "docify", "frame-benchmarking", "frame-support", "frame-system", @@ -13370,7 +13355,7 @@ version = "0.0.1" dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-parachain-system", - "docify 0.2.7", + "docify", "frame", "frame-executive", "frame-support", @@ -15632,7 +15617,7 @@ name = "sc-chain-spec" version = "27.0.0" dependencies = [ "array-bytes 6.1.0", - "docify 0.2.7", + "docify", "log", "memmap2 0.9.3", "parity-scale-codec", @@ -18409,7 +18394,7 @@ name = "sp-arithmetic" version = "23.0.0" dependencies = [ "criterion 0.4.0", - "docify 0.2.7", + "docify", "integer-sqrt", "num-traits", "parity-scale-codec", @@ -18959,7 +18944,7 @@ dependencies = [ name = "sp-runtime" version = "31.0.1" dependencies = [ - "docify 0.2.7", + "docify", "either", "hash256-std-hasher", "impl-trait-for-tuples", diff --git a/cumulus/primitives/storage-weight-reclaim/Cargo.toml b/cumulus/primitives/storage-weight-reclaim/Cargo.toml index 73e0f03cd37..54eec3ffb5e 100644 --- a/cumulus/primitives/storage-weight-reclaim/Cargo.toml +++ b/cumulus/primitives/storage-weight-reclaim/Cargo.toml @@ -22,7 +22,7 @@ sp-std = { path = "../../../substrate/primitives/std", default-features = false cumulus-primitives-core = { path = "../core", default-features = false } cumulus-primitives-proof-size-hostfunction = { path = "../proof-size-hostfunction", default-features = false } -docify = "0.2.7" +docify = "0.2.8" [dev-dependencies] sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } diff --git a/docs/sdk/Cargo.toml b/docs/sdk/Cargo.toml index 3b8f45d7756..64b23866f0c 100644 --- a/docs/sdk/Cargo.toml +++ b/docs/sdk/Cargo.toml @@ -27,7 +27,7 @@ pallet-example-offchain-worker = { path = "../../substrate/frame/examples/offcha # How we build docs in rust-docs simple-mermaid = "0.1.1" -docify = "0.2.7" +docify = "0.2.8" # Polkadot SDK deps, typically all should only be in scope such that we can link to their doc item. node-cli = { package = "staging-node-cli", path = "../../substrate/bin/node/cli" } diff --git a/substrate/client/chain-spec/Cargo.toml b/substrate/client/chain-spec/Cargo.toml index f2138c07d71..f569b5f14a6 100644 --- a/substrate/client/chain-spec/Cargo.toml +++ b/substrate/client/chain-spec/Cargo.toml @@ -34,7 +34,7 @@ sp-runtime = { path = "../../primitives/runtime" } sp-state-machine = { path = "../../primitives/state-machine" } log = { workspace = true } array-bytes = { version = "6.1" } -docify = "0.2.7" +docify = "0.2.8" [dev-dependencies] substrate-test-runtime = { path = "../../test-utils/runtime" } diff --git a/substrate/frame/Cargo.toml b/substrate/frame/Cargo.toml index 6746723e72f..ab394592071 100644 --- a/substrate/frame/Cargo.toml +++ b/substrate/frame/Cargo.toml @@ -51,7 +51,7 @@ sp-inherents = { default-features = false, path = "../primitives/inherents", opt frame-executive = { default-features = false, path = "../frame/executive", optional = true } frame-system-rpc-runtime-api = { default-features = false, path = "../frame/system/rpc/runtime-api", optional = true } -docify = "0.2.7" +docify = "0.2.8" log = { workspace = true } [dev-dependencies] diff --git a/substrate/frame/bags-list/Cargo.toml b/substrate/frame/bags-list/Cargo.toml index f9ae462e16d..49d28482c32 100644 --- a/substrate/frame/bags-list/Cargo.toml +++ b/substrate/frame/bags-list/Cargo.toml @@ -34,7 +34,7 @@ frame-election-provider-support = { path = "../election-provider-support", defau # third party log = { workspace = true } -docify = "0.2.7" +docify = "0.2.8" aquamarine = { version = "0.5.0" } # Optional imports for benchmarking diff --git a/substrate/frame/balances/Cargo.toml b/substrate/frame/balances/Cargo.toml index 64ae90c6757..b27a5bb2478 100644 --- a/substrate/frame/balances/Cargo.toml +++ b/substrate/frame/balances/Cargo.toml @@ -24,7 +24,7 @@ frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } -docify = "0.2.6" +docify = "0.2.8" [dev-dependencies] pallet-transaction-payment = { path = "../transaction-payment" } diff --git a/substrate/frame/examples/single-block-migrations/Cargo.toml b/substrate/frame/examples/single-block-migrations/Cargo.toml index 613742a6787..1020cc9e2bb 100644 --- a/substrate/frame/examples/single-block-migrations/Cargo.toml +++ b/substrate/frame/examples/single-block-migrations/Cargo.toml @@ -13,7 +13,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -docify = { version = "0.2.3", default-features = false } +docify = "0.2.8" log = { version = "0.4.21", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } diff --git a/substrate/frame/fast-unstake/Cargo.toml b/substrate/frame/fast-unstake/Cargo.toml index eca8247845e..fb425dc310d 100644 --- a/substrate/frame/fast-unstake/Cargo.toml +++ b/substrate/frame/fast-unstake/Cargo.toml @@ -30,7 +30,7 @@ frame-election-provider-support = { path = "../election-provider-support", defau frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } -docify = "0.2.7" +docify = "0.2.8" [dev-dependencies] pallet-staking-reward-curve = { path = "../staking/reward-curve" } diff --git a/substrate/frame/migrations/Cargo.toml b/substrate/frame/migrations/Cargo.toml index 40059fb9ec4..0a91d2f94c4 100644 --- a/substrate/frame/migrations/Cargo.toml +++ b/substrate/frame/migrations/Cargo.toml @@ -12,7 +12,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -docify = "0.1.14" +docify = "0.2.8" impl-trait-for-tuples = "0.2.2" log = "0.4.21" scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } diff --git a/substrate/frame/migrations/src/lib.rs b/substrate/frame/migrations/src/lib.rs index cd57d89f440..30ed9c08830 100644 --- a/substrate/frame/migrations/src/lib.rs +++ b/substrate/frame/migrations/src/lib.rs @@ -35,7 +35,7 @@ //! succeeding after two steps. A runtime upgrade is then enacted and the block number is advanced //! until all migrations finish executing. Afterwards, the recorded historic migrations are //! checked and events are asserted. -#![doc = docify::embed!("substrate/frame/migrations/src/tests.rs", simple_works)] +#![doc = docify::embed!("src/tests.rs", simple_works)] //! //! ## Pallet API //! diff --git a/substrate/frame/paged-list/Cargo.toml b/substrate/frame/paged-list/Cargo.toml index 6a2af120f32..bbe8e33d484 100644 --- a/substrate/frame/paged-list/Cargo.toml +++ b/substrate/frame/paged-list/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -docify = "0.2.7" +docify = "0.2.8" scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } diff --git a/substrate/frame/parameters/Cargo.toml b/substrate/frame/parameters/Cargo.toml index 07ebeea52d5..ab93be14e6c 100644 --- a/substrate/frame/parameters/Cargo.toml +++ b/substrate/frame/parameters/Cargo.toml @@ -12,7 +12,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.1.2", default-features = false, features = ["derive"] } paste = { version = "1.0.14", default-features = false } serde = { features = ["derive"], optional = true, workspace = true, default-features = true } -docify = "0.2.5" +docify = "0.2.8" frame-support = { path = "../support", default-features = false, features = ["experimental"] } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/safe-mode/Cargo.toml b/substrate/frame/safe-mode/Cargo.toml index 0c59740bef3..6ddeff263c1 100644 --- a/substrate/frame/safe-mode/Cargo.toml +++ b/substrate/frame/safe-mode/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } -docify = "0.2.7" +docify = "0.2.8" frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/scheduler/Cargo.toml b/substrate/frame/scheduler/Cargo.toml index f50f6afdc06..a3e684a2083 100644 --- a/substrate/frame/scheduler/Cargo.toml +++ b/substrate/frame/scheduler/Cargo.toml @@ -23,7 +23,7 @@ sp-io = { path = "../../primitives/io", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } sp-weights = { path = "../../primitives/weights", default-features = false } -docify = "0.2.7" +docify = "0.2.8" [dev-dependencies] pallet-preimage = { path = "../preimage" } diff --git a/substrate/frame/sudo/Cargo.toml b/substrate/frame/sudo/Cargo.toml index 409104aeca1..a60324847f1 100644 --- a/substrate/frame/sudo/Cargo.toml +++ b/substrate/frame/sudo/Cargo.toml @@ -25,7 +25,7 @@ sp-io = { path = "../../primitives/io", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } -docify = "0.2.7" +docify = "0.2.8" [dev-dependencies] sp-core = { path = "../../primitives/core" } diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index be60068f122..3a61cfa6fac 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -58,7 +58,7 @@ k256 = { version = "0.13.1", default-features = false, features = ["ecdsa"] } environmental = { version = "1.1.4", default-features = false } sp-genesis-builder = { path = "../../primitives/genesis-builder", default-features = false } serde_json = { features = ["alloc"], workspace = true } -docify = "0.2.7" +docify = "0.2.8" static_assertions = "1.1.0" aquamarine = { version = "0.5.0" } diff --git a/substrate/frame/support/procedural/Cargo.toml b/substrate/frame/support/procedural/Cargo.toml index dd0688f2ad0..9f8727f7ade 100644 --- a/substrate/frame/support/procedural/Cargo.toml +++ b/substrate/frame/support/procedural/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -derive-syn-parse = "0.1.5" +derive-syn-parse = "0.2.0" Inflector = "0.11.4" cfg-expr = "0.15.5" itertools = "0.10.3" diff --git a/substrate/frame/system/Cargo.toml b/substrate/frame/system/Cargo.toml index 416969e9c47..d094c6bf984 100644 --- a/substrate/frame/system/Cargo.toml +++ b/substrate/frame/system/Cargo.toml @@ -28,7 +28,7 @@ sp-runtime = { path = "../../primitives/runtime", default-features = false, feat sp-std = { path = "../../primitives/std", default-features = false } sp-version = { path = "../../primitives/version", default-features = false, features = ["serde"] } sp-weights = { path = "../../primitives/weights", default-features = false, features = ["serde"] } -docify = "0.2.7" +docify = "0.2.8" [dev-dependencies] criterion = "0.4.0" diff --git a/substrate/frame/timestamp/Cargo.toml b/substrate/frame/timestamp/Cargo.toml index 28e57fcab0a..d8ba45a2ad2 100644 --- a/substrate/frame/timestamp/Cargo.toml +++ b/substrate/frame/timestamp/Cargo.toml @@ -30,7 +30,7 @@ sp-std = { path = "../../primitives/std", default-features = false } sp-storage = { path = "../../primitives/storage", default-features = false } sp-timestamp = { path = "../../primitives/timestamp", default-features = false } -docify = "0.2.7" +docify = "0.2.8" [dev-dependencies] sp-core = { path = "../../primitives/core" } diff --git a/substrate/frame/treasury/Cargo.toml b/substrate/frame/treasury/Cargo.toml index 5f90904123d..16bb4e92520 100644 --- a/substrate/frame/treasury/Cargo.toml +++ b/substrate/frame/treasury/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", "max-encoded-len", ] } -docify = "0.2.7" +docify = "0.2.8" impl-trait-for-tuples = "0.2.2" scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { features = ["derive"], optional = true, workspace = true, default-features = true } diff --git a/substrate/frame/tx-pause/Cargo.toml b/substrate/frame/tx-pause/Cargo.toml index ace2172454e..a5916c048f4 100644 --- a/substrate/frame/tx-pause/Cargo.toml +++ b/substrate/frame/tx-pause/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } -docify = "0.2.7" +docify = "0.2.8" frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/primitives/arithmetic/Cargo.toml b/substrate/primitives/arithmetic/Cargo.toml index 120edd06a66..45f48d77a31 100644 --- a/substrate/primitives/arithmetic/Cargo.toml +++ b/substrate/primitives/arithmetic/Cargo.toml @@ -27,7 +27,7 @@ scale-info = { version = "2.10.0", default-features = false, features = ["derive serde = { features = ["alloc", "derive"], optional = true, workspace = true } static_assertions = "1.1.0" sp-std = { path = "../std", default-features = false } -docify = "0.2.7" +docify = "0.2.8" [dev-dependencies] criterion = "0.4.0" diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml index cacfc059722..3128ebce8f7 100644 --- a/substrate/primitives/runtime/Cargo.toml +++ b/substrate/primitives/runtime/Cargo.toml @@ -32,7 +32,7 @@ sp-core = { path = "../core", default-features = false } sp-io = { path = "../io", default-features = false } sp-std = { path = "../std", default-features = false } sp-weights = { path = "../weights", default-features = false } -docify = { version = "0.2.7" } +docify = "0.2.8" simple-mermaid = { version = "0.1.1", optional = true } -- GitLab From d0ebb850ed2cefeb3e4ef8b8e0a16eb7fb6b3f3e Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 2 Apr 2024 10:57:35 +0300 Subject: [PATCH 142/187] pallet-xcm: fix weights for all XTs and deprecate unlimited weight ones (#3927) Fix "double-weights" for extrinsics, use only the ones benchmarked in the runtime. Deprecate extrinsics that don't specify WeightLimit, remove their usage across the repo. --------- Signed-off-by: Adrian Catangiu Co-authored-by: command-bot <> --- .../asset-hub-rococo/src/tests/teleport.rs | 143 ------------------ .../asset-hub-westend/src/tests/teleport.rs | 143 ------------------ .../bridge-hub-rococo/src/tests/snowbridge.rs | 3 +- .../src/weights/pallet_xcm.rs | 92 +++++------ .../parachains/runtimes/test-utils/src/lib.rs | 3 +- polkadot/runtime/westend/src/tests.rs | 3 +- polkadot/xcm/pallet-xcm/src/lib.rs | 131 ++-------------- .../pallet-xcm/src/tests/assets_transfer.rs | 81 +++------- polkadot/xcm/xcm-simulator/example/src/lib.rs | 3 +- prdoc/pr_3927.prdoc | 13 ++ 10 files changed, 103 insertions(+), 512 deletions(-) create mode 100644 prdoc/pr_3927.prdoc diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs index 4432999aa95..1cbb7fb8c19 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs @@ -245,16 +245,6 @@ fn relay_limited_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { ) } -fn relay_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { - ::XcmPallet::teleport_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - ) -} - fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { ::PolkadotXcm::limited_teleport_assets( t.signed_origin, @@ -266,16 +256,6 @@ fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResu ) } -fn system_para_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { - ::PolkadotXcm::teleport_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - ) -} - fn para_to_system_para_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { ::PolkadotXcm::transfer_assets( t.signed_origin, @@ -421,129 +401,6 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { assert_eq!(receiver_balance_after, receiver_balance_before); } -/// Teleport of native asset from Relay Chain to the System Parachain should work -#[test] -fn teleport_native_assets_from_relay_to_system_para_works() { - // Init values for Relay Chain - let amount_to_send: Balance = ROCOCO_ED * 1000; - let dest = Rococo::child_location_of(AssetHubRococo::para_id()); - let beneficiary_id = AssetHubRococoReceiver::get(); - let test_args = TestContext { - sender: RococoSender::get(), - receiver: AssetHubRococoReceiver::get(), - args: TestArgs::new_relay(dest, beneficiary_id, amount_to_send), - }; - - let mut test = RelayToSystemParaTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(relay_origin_assertions); - test.set_assertion::(para_dest_assertions); - test.set_dispatchable::(relay_teleport_assets); - test.assert(); - - let delivery_fees = Rococo::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); -} - -/// Teleport of native asset from System Parachains to the Relay Chain -/// should work when there is enough balance in Relay Chain's `CheckAccount` -#[test] -fn teleport_native_assets_back_from_system_para_to_relay_works() { - // Dependency - Relay Chain's `CheckAccount` should have enough balance - teleport_native_assets_from_relay_to_system_para_works(); - - // Init values for Relay Chain - let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; - let destination = AssetHubRococo::parent_location(); - let beneficiary_id = RococoReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubRococoSender::get(), - receiver: RococoReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions); - test.set_dispatchable::(system_para_teleport_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - let delivery_fees = AssetHubRococo::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); -} - -/// Teleport of native asset from System Parachain to Relay Chain -/// shouldn't work when there is not enough balance in Relay Chain's `CheckAccount` -#[test] -fn teleport_native_assets_from_system_para_to_relay_fails() { - // Init values for Relay Chain - let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; - let destination = AssetHubRococo::parent_location(); - let beneficiary_id = RococoReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubRococoSender::get(), - receiver: RococoReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions_fail); - test.set_dispatchable::(system_para_teleport_assets); - test.assert(); - - let delivery_fees = AssetHubRococo::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance does not change - assert_eq!(receiver_balance_after, receiver_balance_before); -} - #[test] fn teleport_to_other_system_parachains_works() { let amount = ASSET_HUB_ROCOCO_ED * 100; diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs index aba05ea4322..ac518d2ed4a 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs @@ -245,16 +245,6 @@ fn relay_limited_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { ) } -fn relay_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { - ::XcmPallet::teleport_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - ) -} - fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { ::PolkadotXcm::limited_teleport_assets( t.signed_origin, @@ -266,16 +256,6 @@ fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResu ) } -fn system_para_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { - ::PolkadotXcm::teleport_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - ) -} - fn para_to_system_para_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { ::PolkadotXcm::transfer_assets( t.signed_origin, @@ -421,129 +401,6 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { assert_eq!(receiver_balance_after, receiver_balance_before); } -/// Teleport of native asset from Relay Chain to the System Parachain should work -#[test] -fn teleport_native_assets_from_relay_to_system_para_works() { - // Init values for Relay Chain - let amount_to_send: Balance = WESTEND_ED * 1000; - let dest = Westend::child_location_of(AssetHubWestend::para_id()); - let beneficiary_id = AssetHubWestendReceiver::get(); - let test_args = TestContext { - sender: WestendSender::get(), - receiver: AssetHubWestendReceiver::get(), - args: TestArgs::new_relay(dest, beneficiary_id, amount_to_send), - }; - - let mut test = RelayToSystemParaTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(relay_origin_assertions); - test.set_assertion::(para_dest_assertions); - test.set_dispatchable::(relay_teleport_assets); - test.assert(); - - let delivery_fees = Westend::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); -} - -/// Teleport of native asset from System Parachains to the Relay Chain -/// should work when there is enough balance in Relay Chain's `CheckAccount` -#[test] -fn teleport_native_assets_back_from_system_para_to_relay_works() { - // Dependency - Relay Chain's `CheckAccount` should have enough balance - teleport_native_assets_from_relay_to_system_para_works(); - - // Init values for Relay Chain - let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; - let destination = AssetHubWestend::parent_location(); - let beneficiary_id = WestendReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubWestendSender::get(), - receiver: WestendReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions); - test.set_dispatchable::(system_para_teleport_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - let delivery_fees = AssetHubWestend::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); -} - -/// Teleport of native asset from System Parachain to Relay Chain -/// shouldn't work when there is not enough balance in Relay Chain's `CheckAccount` -#[test] -fn teleport_native_assets_from_system_para_to_relay_fails() { - // Init values for Relay Chain - let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; - let destination = AssetHubWestend::parent_location(); - let beneficiary_id = WestendReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubWestendSender::get(), - receiver: WestendReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions_fail); - test.set_dispatchable::(system_para_teleport_assets); - test.assert(); - - let delivery_fees = AssetHubWestend::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance does not change - assert_eq!(receiver_balance_after, receiver_balance_before); -} - #[test] fn teleport_to_other_system_parachains_works() { let amount = ASSET_HUB_WESTEND_ED * 100; diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs index caaf24e00a8..1804f9d4b67 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs @@ -458,12 +458,13 @@ fn send_weth_asset_from_asset_hub_to_ethereum() { AssetHubRococoReceiver::get(), ); // Send the Weth back to Ethereum - ::PolkadotXcm::reserve_transfer_assets( + ::PolkadotXcm::limited_reserve_transfer_assets( RuntimeOrigin::signed(AssetHubRococoReceiver::get()), Box::new(destination), Box::new(beneficiary), Box::new(multi_assets), 0, + Unlimited, ) .unwrap(); let free_balance_after = ::Balances::free_balance( diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs index 299e4b8b3cd..a36c25f9604 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-04-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-f3xfxtob-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -64,8 +64,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 21_722_000 picoseconds. - Weight::from_parts(22_253_000, 0) + // Minimum execution time: 21_050_000 picoseconds. + Weight::from_parts(21_834_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) @@ -86,8 +86,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 21_694_000 picoseconds. - Weight::from_parts(22_326_000, 0) + // Minimum execution time: 21_164_000 picoseconds. + Weight::from_parts(21_656_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) @@ -112,8 +112,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 94_422_000 picoseconds. - Weight::from_parts(96_997_000, 0) + // Minimum execution time: 92_497_000 picoseconds. + Weight::from_parts(95_473_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -140,8 +140,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `367` // Estimated: `6196` - // Minimum execution time: 123_368_000 picoseconds. - Weight::from_parts(125_798_000, 0) + // Minimum execution time: 120_059_000 picoseconds. + Weight::from_parts(122_894_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(5)) @@ -170,8 +170,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `496` // Estimated: `6208` - // Minimum execution time: 142_033_000 picoseconds. - Weight::from_parts(145_702_000, 0) + // Minimum execution time: 141_977_000 picoseconds. + Weight::from_parts(145_981_000, 0) .saturating_add(Weight::from_parts(0, 6208)) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(7)) @@ -180,16 +180,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_558_000 picoseconds. - Weight::from_parts(7_916_000, 0) + // Minimum execution time: 7_426_000 picoseconds. + Weight::from_parts(7_791_000, 0) .saturating_add(Weight::from_parts(0, 0)) } fn execute_blob() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_978_000 picoseconds. - Weight::from_parts(8_210_000, 0) + // Minimum execution time: 7_585_000 picoseconds. + Weight::from_parts(7_897_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) @@ -198,8 +198,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_439_000 picoseconds. - Weight::from_parts(6_711_000, 0) + // Minimum execution time: 6_224_000 picoseconds. + Weight::from_parts(6_793_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -209,8 +209,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_982_000 picoseconds. - Weight::from_parts(2_260_000, 0) + // Minimum execution time: 1_812_000 picoseconds. + Weight::from_parts(2_008_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -236,8 +236,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 27_120_000 picoseconds. - Weight::from_parts(28_048_000, 0) + // Minimum execution time: 26_586_000 picoseconds. + Weight::from_parts(27_181_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) @@ -262,8 +262,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `363` // Estimated: `3828` - // Minimum execution time: 29_354_000 picoseconds. - Weight::from_parts(30_205_000, 0) + // Minimum execution time: 28_295_000 picoseconds. + Weight::from_parts(29_280_000, 0) .saturating_add(Weight::from_parts(0, 3828)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -274,8 +274,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_926_000 picoseconds. - Weight::from_parts(2_013_000, 0) + // Minimum execution time: 1_803_000 picoseconds. + Weight::from_parts(1_876_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -285,8 +285,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `159` // Estimated: `13524` - // Minimum execution time: 18_611_000 picoseconds. - Weight::from_parts(19_120_000, 0) + // Minimum execution time: 18_946_000 picoseconds. + Weight::from_parts(19_456_000, 0) .saturating_add(Weight::from_parts(0, 13524)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -297,8 +297,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `163` // Estimated: `13528` - // Minimum execution time: 18_373_000 picoseconds. - Weight::from_parts(18_945_000, 0) + // Minimum execution time: 19_080_000 picoseconds. + Weight::from_parts(19_498_000, 0) .saturating_add(Weight::from_parts(0, 13528)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -309,8 +309,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `173` // Estimated: `16013` - // Minimum execution time: 20_459_000 picoseconds. - Weight::from_parts(20_951_000, 0) + // Minimum execution time: 20_637_000 picoseconds. + Weight::from_parts(21_388_000, 0) .saturating_add(Weight::from_parts(0, 16013)) .saturating_add(T::DbWeight::get().reads(6)) } @@ -332,8 +332,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `212` // Estimated: `6152` - // Minimum execution time: 26_003_000 picoseconds. - Weight::from_parts(26_678_000, 0) + // Minimum execution time: 25_701_000 picoseconds. + Weight::from_parts(26_269_000, 0) .saturating_add(Weight::from_parts(0, 6152)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -344,8 +344,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `206` // Estimated: `11096` - // Minimum execution time: 11_557_000 picoseconds. - Weight::from_parts(11_868_000, 0) + // Minimum execution time: 11_949_000 picoseconds. + Weight::from_parts(12_249_000, 0) .saturating_add(Weight::from_parts(0, 11096)) .saturating_add(T::DbWeight::get().reads(4)) } @@ -355,8 +355,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `170` // Estimated: `13535` - // Minimum execution time: 18_710_000 picoseconds. - Weight::from_parts(19_240_000, 0) + // Minimum execution time: 19_278_000 picoseconds. + Weight::from_parts(19_538_000, 0) .saturating_add(Weight::from_parts(0, 13535)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -379,8 +379,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `212` // Estimated: `13577` - // Minimum execution time: 34_393_000 picoseconds. - Weight::from_parts(35_138_000, 0) + // Minimum execution time: 35_098_000 picoseconds. + Weight::from_parts(35_871_000, 0) .saturating_add(Weight::from_parts(0, 13577)) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(4)) @@ -393,8 +393,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `1588` - // Minimum execution time: 4_043_000 picoseconds. - Weight::from_parts(4_216_000, 0) + // Minimum execution time: 3_862_000 picoseconds. + Weight::from_parts(4_082_000, 0) .saturating_add(Weight::from_parts(0, 1588)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -405,8 +405,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7740` // Estimated: `11205` - // Minimum execution time: 25_410_000 picoseconds. - Weight::from_parts(26_019_000, 0) + // Minimum execution time: 25_423_000 picoseconds. + Weight::from_parts(25_872_000, 0) .saturating_add(Weight::from_parts(0, 11205)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -417,8 +417,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `160` // Estimated: `3625` - // Minimum execution time: 38_850_000 picoseconds. - Weight::from_parts(39_593_000, 0) + // Minimum execution time: 37_148_000 picoseconds. + Weight::from_parts(37_709_000, 0) .saturating_add(Weight::from_parts(0, 3625)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/cumulus/parachains/runtimes/test-utils/src/lib.rs b/cumulus/parachains/runtimes/test-utils/src/lib.rs index e62daa16a12..3c84243306f 100644 --- a/cumulus/parachains/runtimes/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/test-utils/src/lib.rs @@ -425,12 +425,13 @@ impl< } // do teleport - >::teleport_assets( + >::limited_teleport_assets( origin, Box::new(dest.into()), Box::new(beneficiary.into()), Box::new((AssetId(asset), amount).into()), 0, + Unlimited, ) } } diff --git a/polkadot/runtime/westend/src/tests.rs b/polkadot/runtime/westend/src/tests.rs index bdd599d2b75..4acb81e963b 100644 --- a/polkadot/runtime/westend/src/tests.rs +++ b/polkadot/runtime/westend/src/tests.rs @@ -54,11 +54,12 @@ fn sanity_check_teleport_assets_weight() { // Usually when XCM runs into an issue, it will return a weight of `Weight::MAX`, // so this test will certainly ensure that this problem does not occur. use frame_support::dispatch::GetDispatchInfo; - let weight = pallet_xcm::Call::::teleport_assets { + let weight = pallet_xcm::Call::::limited_teleport_assets { dest: Box::new(Here.into()), beneficiary: Box::new(Here.into()), assets: Box::new((Here, 200_000).into()), fee_asset_item: 0, + weight_limit: Unlimited, } .get_dispatch_info() .weight; diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 29b61988f73..ef255068734 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -940,13 +940,12 @@ pub mod pallet { } } - #[pallet::call] + #[pallet::call(weight(::WeightInfo))] impl Pallet { /// WARNING: DEPRECATED. `send` will be removed after June 2024. Use `send_blob` instead. #[allow(deprecated)] #[deprecated(note = "`send` will be removed after June 2024. Use `send_blob` instead.")] #[pallet::call_index(0)] - #[pallet::weight(T::WeightInfo::send())] pub fn send( origin: OriginFor, dest: Box, @@ -976,23 +975,10 @@ pub mod pallet { /// - `fee_asset_item`: The index into `assets` of the item which should be used to pay /// fees. #[pallet::call_index(1)] - #[pallet::weight({ - let maybe_assets: Result = (*assets.clone()).try_into(); - let maybe_dest: Result = (*dest.clone()).try_into(); - match (maybe_assets, maybe_dest) { - (Ok(assets), Ok(dest)) => { - use sp_std::vec; - let count = assets.len() as u32; - let mut message = Xcm(vec![ - WithdrawAsset(assets), - SetFeesMode { jit_withdraw: true }, - InitiateTeleport { assets: Wild(AllCounted(count)), dest, xcm: Xcm(vec![]) }, - ]); - T::Weigher::weight(&mut message).map_or(Weight::MAX, |w| T::WeightInfo::teleport_assets().saturating_add(w)) - } - _ => Weight::MAX, - } - })] + #[allow(deprecated)] + #[deprecated( + note = "This extrinsic uses `WeightLimit::Unlimited`, please migrate to `limited_teleport_assets` or `transfer_assets`" + )] pub fn teleport_assets( origin: OriginFor, dest: Box, @@ -1034,23 +1020,10 @@ pub mod pallet { /// - `fee_asset_item`: The index into `assets` of the item which should be used to pay /// fees. #[pallet::call_index(2)] - #[pallet::weight({ - let maybe_assets: Result = (*assets.clone()).try_into(); - let maybe_dest: Result = (*dest.clone()).try_into(); - match (maybe_assets, maybe_dest) { - (Ok(assets), Ok(dest)) => { - use sp_std::vec; - // heaviest version of locally executed XCM program: equivalent in weight to - // transfer assets to SA, reanchor them, extend XCM program, and send onward XCM - let mut message = Xcm(vec![ - SetFeesMode { jit_withdraw: true }, - TransferReserveAsset { assets, dest, xcm: Xcm(vec![]) } - ]); - T::Weigher::weight(&mut message).map_or(Weight::MAX, |w| T::WeightInfo::reserve_transfer_assets().saturating_add(w)) - } - _ => Weight::MAX, - } - })] + #[allow(deprecated)] + #[deprecated( + note = "This extrinsic uses `WeightLimit::Unlimited`, please migrate to `limited_reserve_transfer_assets` or `transfer_assets`" + )] pub fn reserve_transfer_assets( origin: OriginFor, dest: Box, @@ -1102,7 +1075,6 @@ pub mod pallet { /// - `location`: The destination that is being described. /// - `xcm_version`: The latest version of XCM that `location` supports. #[pallet::call_index(4)] - #[pallet::weight(T::WeightInfo::force_xcm_version())] pub fn force_xcm_version( origin: OriginFor, location: Box, @@ -1121,7 +1093,6 @@ pub mod pallet { /// - `origin`: Must be an origin specified by AdminOrigin. /// - `maybe_xcm_version`: The default XCM encoding version, or `None` to disable. #[pallet::call_index(5)] - #[pallet::weight(T::WeightInfo::force_default_xcm_version())] pub fn force_default_xcm_version( origin: OriginFor, maybe_xcm_version: Option, @@ -1136,7 +1107,6 @@ pub mod pallet { /// - `origin`: Must be an origin specified by AdminOrigin. /// - `location`: The location to which we should subscribe for XCM version notifications. #[pallet::call_index(6)] - #[pallet::weight(T::WeightInfo::force_subscribe_version_notify())] pub fn force_subscribe_version_notify( origin: OriginFor, location: Box, @@ -1160,7 +1130,6 @@ pub mod pallet { /// - `location`: The location to which we are currently subscribed for XCM version /// notifications which we no longer desire. #[pallet::call_index(7)] - #[pallet::weight(T::WeightInfo::force_unsubscribe_version_notify())] pub fn force_unsubscribe_version_notify( origin: OriginFor, location: Box, @@ -1193,7 +1162,7 @@ pub mod pallet { /// /// Fee payment on the destination side is made from the asset in the `assets` vector of /// index `fee_asset_item`, up to enough to pay for `weight_limit` of weight. If more weight - /// is needed than `weight_limit`, then the operation will fail and the assets send may be + /// is needed than `weight_limit`, then the operation will fail and the sent assets may be /// at risk. /// /// - `origin`: Must be capable of withdrawing the `assets` and executing XCM. @@ -1208,23 +1177,7 @@ pub mod pallet { /// fees. /// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase. #[pallet::call_index(8)] - #[pallet::weight({ - let maybe_assets: Result = (*assets.clone()).try_into(); - let maybe_dest: Result = (*dest.clone()).try_into(); - match (maybe_assets, maybe_dest) { - (Ok(assets), Ok(dest)) => { - use sp_std::vec; - // heaviest version of locally executed XCM program: equivalent in weight to - // transfer assets to SA, reanchor them, extend XCM program, and send onward XCM - let mut message = Xcm(vec![ - SetFeesMode { jit_withdraw: true }, - TransferReserveAsset { assets, dest, xcm: Xcm(vec![]) } - ]); - T::Weigher::weight(&mut message).map_or(Weight::MAX, |w| T::WeightInfo::reserve_transfer_assets().saturating_add(w)) - } - _ => Weight::MAX, - } - })] + #[pallet::weight(T::WeightInfo::reserve_transfer_assets())] pub fn limited_reserve_transfer_assets( origin: OriginFor, dest: Box, @@ -1247,7 +1200,7 @@ pub mod pallet { /// /// Fee payment on the destination side is made from the asset in the `assets` vector of /// index `fee_asset_item`, up to enough to pay for `weight_limit` of weight. If more weight - /// is needed than `weight_limit`, then the operation will fail and the assets send may be + /// is needed than `weight_limit`, then the operation will fail and the sent assets may be /// at risk. /// /// - `origin`: Must be capable of withdrawing the `assets` and executing XCM. @@ -1262,23 +1215,7 @@ pub mod pallet { /// fees. /// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase. #[pallet::call_index(9)] - #[pallet::weight({ - let maybe_assets: Result = (*assets.clone()).try_into(); - let maybe_dest: Result = (*dest.clone()).try_into(); - match (maybe_assets, maybe_dest) { - (Ok(assets), Ok(dest)) => { - use sp_std::vec; - let count = assets.len() as u32; - let mut message = Xcm(vec![ - WithdrawAsset(assets), - SetFeesMode { jit_withdraw: true }, - InitiateTeleport { assets: Wild(AllCounted(count)), dest, xcm: Xcm(vec![]) }, - ]); - T::Weigher::weight(&mut message).map_or(Weight::MAX, |w| T::WeightInfo::teleport_assets().saturating_add(w)) - } - _ => Weight::MAX, - } - })] + #[pallet::weight(T::WeightInfo::teleport_assets())] pub fn limited_teleport_assets( origin: OriginFor, dest: Box, @@ -1302,7 +1239,6 @@ pub mod pallet { /// - `origin`: Must be an origin specified by AdminOrigin. /// - `suspended`: `true` to suspend, `false` to resume. #[pallet::call_index(10)] - #[pallet::weight(T::WeightInfo::force_suspension())] pub fn force_suspension(origin: OriginFor, suspended: bool) -> DispatchResult { T::AdminOrigin::ensure_origin(origin)?; XcmExecutionSuspended::::set(suspended); @@ -1315,7 +1251,7 @@ pub mod pallet { /// Fee payment on the destination side is made from the asset in the `assets` vector of /// index `fee_asset_item` (hence referred to as `fees`), up to enough to pay for /// `weight_limit` of weight. If more weight is needed than `weight_limit`, then the - /// operation will fail and the assets sent may be at risk. + /// operation will fail and the sent assets may be at risk. /// /// `assets` (excluding `fees`) must have same reserve location or otherwise be teleportable /// to `dest`, no limitations imposed on `fees`. @@ -1343,26 +1279,6 @@ pub mod pallet { /// fees. /// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase. #[pallet::call_index(11)] - #[pallet::weight({ - let maybe_assets: Result = (*assets.clone()).try_into(); - let maybe_dest: Result = (*dest.clone()).try_into(); - match (maybe_assets, maybe_dest) { - (Ok(assets), Ok(dest)) => { - use sp_std::vec; - // heaviest version of locally executed XCM program: equivalent in weight to withdrawing fees, - // burning them, transferring rest of assets to SA, reanchoring them, extending XCM program, - // and sending onward XCM - let mut message = Xcm(vec![ - SetFeesMode { jit_withdraw: true }, - WithdrawAsset(assets.clone()), - BurnAsset(assets.clone()), - TransferReserveAsset { assets, dest, xcm: Xcm(vec![]) } - ]); - T::Weigher::weight(&mut message).map_or(Weight::MAX, |w| T::WeightInfo::transfer_assets().saturating_add(w)) - } - _ => Weight::MAX, - } - })] pub fn transfer_assets( origin: OriginFor, dest: Box, @@ -1452,22 +1368,6 @@ pub mod pallet { /// was the latest when they were trapped. /// - `beneficiary`: The location/account where the claimed assets will be deposited. #[pallet::call_index(12)] - #[pallet::weight({ - let assets_version = assets.identify_version(); - let maybe_assets: Result = (*assets.clone()).try_into(); - let maybe_beneficiary: Result = (*beneficiary.clone()).try_into(); - match (maybe_assets, maybe_beneficiary) { - (Ok(assets), Ok(beneficiary)) => { - let ticket: Location = GeneralIndex(assets_version as u128).into(); - let mut message = Xcm(vec![ - ClaimAsset { assets: assets.clone(), ticket }, - DepositAsset { assets: AllCounted(assets.len() as u32).into(), beneficiary }, - ]); - T::Weigher::weight(&mut message).map_or(Weight::MAX, |w| T::WeightInfo::claim_assets().saturating_add(w)) - } - _ => Weight::MAX - } - })] pub fn claim_assets( origin: OriginFor, assets: Box, @@ -1514,7 +1414,7 @@ pub mod pallet { /// /// The message is passed in encoded. It needs to be decodable as a [`VersionedXcm`]. #[pallet::call_index(13)] - #[pallet::weight(T::WeightInfo::execute_blob())] + #[pallet::weight(max_weight.saturating_add(T::WeightInfo::execute_blob()))] pub fn execute_blob( origin: OriginFor, encoded_message: BoundedVec, @@ -1535,7 +1435,6 @@ pub mod pallet { /// /// The message is passed in encoded. It needs to be decodable as a [`VersionedXcm`]. #[pallet::call_index(14)] - #[pallet::weight(T::WeightInfo::send_blob())] pub fn send_blob( origin: OriginFor, dest: Box, diff --git a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs index 92d23cfd281..7dc05c1cc70 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs @@ -31,13 +31,17 @@ use sp_runtime::{traits::AccountIdConversion, DispatchError, ModuleError}; use xcm::prelude::*; use xcm_executor::traits::ConvertLocation; -// Helper function to deduplicate testing different teleport types. -fn do_test_and_verify_teleport_assets( - origin_location: Location, - expected_beneficiary: Location, - call: Call, - expected_weight_limit: WeightLimit, -) { +/// Test `limited_teleport_assets` +/// +/// Asserts that the sender's balance is decreased as a result of execution of +/// local effects. +#[test] +fn limited_teleport_assets_works() { + let origin_location: Location = AccountId32 { network: None, id: ALICE.into() }.into(); + let expected_beneficiary: Location = AccountId32 { network: None, id: BOB.into() }.into(); + let weight_limit = WeightLimit::Limited(Weight::from_parts(5000, 5000)); + let expected_weight_limit = weight_limit.clone(); + let balances = vec![ (ALICE, INITIAL_BALANCE), (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), @@ -47,7 +51,14 @@ fn do_test_and_verify_teleport_assets( let weight = BaseXcmWeight::get() * 2; assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); // call extrinsic - call(); + assert_ok!(XcmPallet::limited_teleport_assets( + RuntimeOrigin::signed(ALICE), + Box::new(RelayLocation::get().into()), + Box::new(expected_beneficiary.clone().into()), + Box::new((Here, SEND_AMOUNT).into()), + 0, + weight_limit, + )); assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT); assert_eq!( sent_xcm(), @@ -88,57 +99,6 @@ fn do_test_and_verify_teleport_assets( }); } -/// Test `teleport_assets` -/// -/// Asserts that the sender's balance is decreased as a result of execution of -/// local effects. -#[test] -fn teleport_assets_works() { - let origin_location: Location = AccountId32 { network: None, id: ALICE.into() }.into(); - let beneficiary: Location = AccountId32 { network: None, id: BOB.into() }.into(); - do_test_and_verify_teleport_assets( - origin_location.clone(), - beneficiary.clone(), - || { - assert_ok!(XcmPallet::teleport_assets( - RuntimeOrigin::signed(ALICE), - Box::new(RelayLocation::get().into()), - Box::new(beneficiary.into()), - Box::new((Here, SEND_AMOUNT).into()), - 0, - )); - }, - Unlimited, - ); -} - -/// Test `limited_teleport_assets` -/// -/// Asserts that the sender's balance is decreased as a result of execution of -/// local effects. -#[test] -fn limited_teleport_assets_works() { - let origin_location: Location = AccountId32 { network: None, id: ALICE.into() }.into(); - let beneficiary: Location = AccountId32 { network: None, id: BOB.into() }.into(); - let weight_limit = WeightLimit::Limited(Weight::from_parts(5000, 5000)); - let expected_weight_limit = weight_limit.clone(); - do_test_and_verify_teleport_assets( - origin_location.clone(), - beneficiary.clone(), - || { - assert_ok!(XcmPallet::limited_teleport_assets( - RuntimeOrigin::signed(ALICE), - Box::new(RelayLocation::get().into()), - Box::new(beneficiary.into()), - Box::new((Here, SEND_AMOUNT).into()), - 0, - weight_limit, - )); - }, - expected_weight_limit, - ); -} - /// `limited_teleport_assets` should fail for filtered assets #[test] fn limited_teleport_filtered_assets_disallowed() { @@ -184,12 +144,13 @@ fn reserve_transfer_assets_with_paid_router_works() { let dest: Location = Junction::AccountId32 { network: None, id: user_account.clone().into() }.into(); assert_eq!(Balances::total_balance(&user_account), INITIAL_BALANCE); - assert_ok!(XcmPallet::reserve_transfer_assets( + assert_ok!(XcmPallet::limited_reserve_transfer_assets( RuntimeOrigin::signed(user_account.clone()), Box::new(Parachain(paid_para_id).into()), Box::new(dest.clone().into()), Box::new((Here, SEND_AMOUNT).into()), 0, + Unlimited, )); // XCM_FEES_NOT_WAIVED_USER_ACCOUNT spent amount diff --git a/polkadot/xcm/xcm-simulator/example/src/lib.rs b/polkadot/xcm/xcm-simulator/example/src/lib.rs index 13210179e91..56e204bf571 100644 --- a/polkadot/xcm/xcm-simulator/example/src/lib.rs +++ b/polkadot/xcm/xcm-simulator/example/src/lib.rs @@ -250,12 +250,13 @@ mod tests { let withdraw_amount = 123; Relay::execute_with(|| { - assert_ok!(RelayChainPalletXcm::reserve_transfer_assets( + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( relay_chain::RuntimeOrigin::signed(ALICE), Box::new(Parachain(1).into()), Box::new(AccountId32 { network: None, id: ALICE.into() }.into()), Box::new((Here, withdraw_amount).into()), 0, + Unlimited, )); assert_eq!( relay_chain::Balances::free_balance(&child_account_id(1)), diff --git a/prdoc/pr_3927.prdoc b/prdoc/pr_3927.prdoc new file mode 100644 index 00000000000..a568636d0bd --- /dev/null +++ b/prdoc/pr_3927.prdoc @@ -0,0 +1,13 @@ +title: "pallet-xcm: deprecate transfer extrinsics without weight limit" + +doc: + - audience: Runtime Dev + description: | + pallet-xcm's extrinsics `teleport_assets` and `reserve_transfer_assets` have been + marked as deprecated. Please change their usage to the `limited_teleport_assets` + and `limited_reserve_transfer_assets`, respectively; or use the generic/flexible + `transfer_assets` extrinsic. + +crates: +- name: pallet-xcm + bump: minor -- GitLab From 12eb285dbe6271c365db7ba17cf643bfc77fe753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 2 Apr 2024 11:44:23 +0200 Subject: [PATCH 143/187] Fix parachain upgrade scheduling when done by the owner/root (#3341) When using `schedule_code_upgrade` to change the code of a parachain in the relay chain runtime, we had already fixed to not set the `GoAhead` signal. This was done to not brick any parachain after the upgrade, because they were seeing the signal without having any upgrade prepared. The remaining problem is that the parachain code is only upgraded after a parachain header was enacted, aka the parachain made some progress. However, this is quite complicated if the parachain is bricked (which is the most common scenario why to manually schedule a code upgrade). Thus, this pull request replaces `SetGoAhead` with `UpgradeStrategy` to signal to the logic kind of strategy want to use. The strategies are either `SetGoAheadSignal` or `ApplyAtExpectedBlock`. `SetGoAheadSignal` sets the go ahead signal as before and awaits a parachain block. `ApplyAtExpectedBlock` schedules the upgrade and applies it directly at the `expected_block` without waiting for the parachain to make any kind of progress. --- .../runtime/common/src/paras_registrar/mod.rs | 15 +- .../runtime/parachains/src/inclusion/mod.rs | 4 +- .../runtime/parachains/src/inclusion/tests.rs | 4 +- polkadot/runtime/parachains/src/lib.rs | 4 +- .../parachains/src/paras/benchmarking.rs | 2 +- .../src/paras/benchmarking/pvf_check.rs | 2 +- polkadot/runtime/parachains/src/paras/mod.rs | 226 ++++++++++++------ .../runtime/parachains/src/paras/tests.rs | 131 ++++------ prdoc/pr_3341.prdoc | 18 ++ 9 files changed, 237 insertions(+), 169 deletions(-) create mode 100644 prdoc/pr_3341.prdoc diff --git a/polkadot/runtime/common/src/paras_registrar/mod.rs b/polkadot/runtime/common/src/paras_registrar/mod.rs index 5b2098388d8..7abe23917e4 100644 --- a/polkadot/runtime/common/src/paras_registrar/mod.rs +++ b/polkadot/runtime/common/src/paras_registrar/mod.rs @@ -29,7 +29,7 @@ use frame_system::{self, ensure_root, ensure_signed}; use primitives::{HeadData, Id as ParaId, ValidationCode, LOWEST_PUBLIC_ID, MIN_CODE_SIZE}; use runtime_parachains::{ configuration, ensure_parachain, - paras::{self, ParaGenesisArgs, SetGoAhead}, + paras::{self, ParaGenesisArgs, UpgradeStrategy}, Origin, ParaLifecycle, }; use sp_std::{prelude::*, result}; @@ -408,6 +408,13 @@ pub mod pallet { /// Schedule a parachain upgrade. /// + /// This will kick off a check of `new_code` by all validators. After the majority of the + /// validators have reported on the validity of the code, the code will either be enacted + /// or the upgrade will be rejected. If the code will be enacted, the current code of the + /// parachain will be overwritten directly. This means that any PoV will be checked by this + /// new code. The parachain itself will not be informed explictely that the validation code + /// has changed. + /// /// Can be called by Root, the parachain, or the parachain manager if the parachain is /// unlocked. #[pallet::call_index(7)] @@ -418,7 +425,11 @@ pub mod pallet { new_code: ValidationCode, ) -> DispatchResult { Self::ensure_root_para_or_owner(origin, para)?; - runtime_parachains::schedule_code_upgrade::(para, new_code, SetGoAhead::No)?; + runtime_parachains::schedule_code_upgrade::( + para, + new_code, + UpgradeStrategy::ApplyAtExpectedBlock, + )?; Ok(()) } diff --git a/polkadot/runtime/parachains/src/inclusion/mod.rs b/polkadot/runtime/parachains/src/inclusion/mod.rs index e77f8d15b40..34afdec724a 100644 --- a/polkadot/runtime/parachains/src/inclusion/mod.rs +++ b/polkadot/runtime/parachains/src/inclusion/mod.rs @@ -22,7 +22,7 @@ use crate::{ configuration::{self, HostConfiguration}, disputes, dmp, hrmp, - paras::{self, SetGoAhead}, + paras::{self, UpgradeStrategy}, scheduler, shared::{self, AllowedRelayParentsTracker}, util::make_persisted_validation_data_with_parent, @@ -839,7 +839,7 @@ impl Pallet { new_code, now, &config, - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, )); } diff --git a/polkadot/runtime/parachains/src/inclusion/tests.rs b/polkadot/runtime/parachains/src/inclusion/tests.rs index 5ab3a13324d..97bf67ef934 100644 --- a/polkadot/runtime/parachains/src/inclusion/tests.rs +++ b/polkadot/runtime/parachains/src/inclusion/tests.rs @@ -1590,7 +1590,7 @@ fn candidate_checks() { vec![9, 8, 7, 6, 5, 4, 3, 2, 1].into(), expected_at, &cfg, - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); } @@ -2857,7 +2857,7 @@ fn para_upgrade_delay_scheduled_from_inclusion() { let cause = &active_vote_state.causes()[0]; // Upgrade block is the block of inclusion, not candidate's parent. assert_matches!(cause, - paras::PvfCheckCause::Upgrade { id, included_at, set_go_ahead: SetGoAhead::Yes } + paras::PvfCheckCause::Upgrade { id, included_at, upgrade_strategy: UpgradeStrategy::SetGoAheadSignal } if id == &chain_a && included_at == &7 ); }); diff --git a/polkadot/runtime/parachains/src/lib.rs b/polkadot/runtime/parachains/src/lib.rs index b0dc27b7286..466bc7685dd 100644 --- a/polkadot/runtime/parachains/src/lib.rs +++ b/polkadot/runtime/parachains/src/lib.rs @@ -54,7 +54,7 @@ mod mock; mod ump_tests; pub use origin::{ensure_parachain, Origin}; -pub use paras::{ParaLifecycle, SetGoAhead}; +pub use paras::{ParaLifecycle, UpgradeStrategy}; use primitives::{HeadData, Id as ParaId, ValidationCode}; use sp_runtime::{DispatchResult, FixedU128}; @@ -104,7 +104,7 @@ pub fn schedule_parachain_downgrade(id: ParaId) -> Result<(), pub fn schedule_code_upgrade( id: ParaId, new_code: ValidationCode, - set_go_ahead: SetGoAhead, + set_go_ahead: UpgradeStrategy, ) -> DispatchResult { paras::Pallet::::schedule_code_upgrade_external(id, new_code, set_go_ahead) } diff --git a/polkadot/runtime/parachains/src/paras/benchmarking.rs b/polkadot/runtime/parachains/src/paras/benchmarking.rs index 554f0c15af2..56e6ff153c1 100644 --- a/polkadot/runtime/parachains/src/paras/benchmarking.rs +++ b/polkadot/runtime/parachains/src/paras/benchmarking.rs @@ -129,7 +129,7 @@ benchmarks! { ValidationCode(vec![0]), expired, &config, - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); }: _(RawOrigin::Root, para_id, new_head) verify { diff --git a/polkadot/runtime/parachains/src/paras/benchmarking/pvf_check.rs b/polkadot/runtime/parachains/src/paras/benchmarking/pvf_check.rs index 53ccc35c477..0bf5aa86c40 100644 --- a/polkadot/runtime/parachains/src/paras/benchmarking/pvf_check.rs +++ b/polkadot/runtime/parachains/src/paras/benchmarking/pvf_check.rs @@ -177,7 +177,7 @@ where validation_code, /* relay_parent_number */ 1u32.into(), &configuration::Pallet::::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); } else { let r = Pallet::::schedule_para_initialize( diff --git a/polkadot/runtime/parachains/src/paras/mod.rs b/polkadot/runtime/parachains/src/paras/mod.rs index 017cd87f13b..3eb66112fed 100644 --- a/polkadot/runtime/parachains/src/paras/mod.rs +++ b/polkadot/runtime/parachains/src/paras/mod.rs @@ -386,16 +386,32 @@ pub(crate) enum PvfCheckCause { /// /// See https://github.com/paritytech/polkadot/issues/4601 for detailed explanation. included_at: BlockNumber, - /// Whether or not the given para should be sent the `GoAhead` signal. - set_go_ahead: SetGoAhead, + /// Whether or not the upgrade should be enacted directly. + /// + /// If set to `Yes` it means that no `GoAheadSignal` will be set and the parachain code + /// will also be overwritten directly. + upgrade_strategy: UpgradeStrategy, }, } -/// Should the `GoAhead` signal be set after a successful check of the new wasm binary? +/// The strategy on how to handle a validation code upgrade. +/// +/// When scheduling a parachain code upgrade the upgrade first is checked by all validators. The +/// validators ensure that the new validation code can be compiled and instantiated. After the +/// majority of the validators have reported their checking result the upgrade is either scheduled +/// or aborted. This strategy then comes into play around the relay chain block this upgrade was +/// scheduled in. #[derive(Debug, Copy, Clone, PartialEq, TypeInfo, Decode, Encode)] -pub enum SetGoAhead { - Yes, - No, +pub enum UpgradeStrategy { + /// Set the `GoAhead` signal to inform the parachain that it is time to upgrade. + /// + /// The upgrade will then be applied after the first parachain block was enacted that must have + /// observed the `GoAhead` signal. + SetGoAheadSignal, + /// Apply the upgrade directly at the expected relay chain block. + /// + /// This doesn't wait for the parachain to make any kind of progress. + ApplyAtExpectedBlock, } impl PvfCheckCause { @@ -758,7 +774,8 @@ pub mod pallet { pub(super) type PastCodePruning = StorageValue<_, Vec<(ParaId, BlockNumberFor)>, ValueQuery>; - /// The block number at which the planned code change is expected for a para. + /// The block number at which the planned code change is expected for a parachain. + /// /// The change will be applied after the first parablock for this ID included which executes /// in the context of a relay chain block with a number >= `expected_at`. #[pallet::storage] @@ -766,6 +783,18 @@ pub mod pallet { pub(super) type FutureCodeUpgrades = StorageMap<_, Twox64Concat, ParaId, BlockNumberFor>; + /// The list of upcoming future code upgrades. + /// + /// Each item is a pair of the parachain and the expected block at which the upgrade should be + /// applied. The upgrade will be applied at the given relay chain block. In contrast to + /// [`FutureCodeUpgrades`] this code upgrade will be applied regardless the parachain making any + /// progress or not. + /// + /// Ordered ascending by block number. + #[pallet::storage] + pub(super) type FutureCodeUpgradesAt = + StorageValue<_, Vec<(ParaId, BlockNumberFor)>, ValueQuery>; + /// The actual future code hash of a para. /// /// Corresponding code can be retrieved with [`CodeByHash`]. @@ -809,8 +838,10 @@ pub mod pallet { pub(super) type UpgradeCooldowns = StorageValue<_, Vec<(ParaId, BlockNumberFor)>, ValueQuery>; - /// The list of upcoming code upgrades. Each item is a pair of which para performs a code - /// upgrade and at which relay-chain block it is expected at. + /// The list of upcoming code upgrades. + /// + /// Each item is a pair of which para performs a code upgrade and at which relay-chain block it + /// is expected at. /// /// Ordered ascending by block number. #[pallet::storage] @@ -880,21 +911,9 @@ pub mod pallet { new_code: ValidationCode, ) -> DispatchResult { ensure_root(origin)?; - let maybe_prior_code_hash = CurrentCodeHash::::get(¶); let new_code_hash = new_code.hash(); Self::increase_code_ref(&new_code_hash, &new_code); - CurrentCodeHash::::insert(¶, new_code_hash); - - let now = frame_system::Pallet::::block_number(); - if let Some(prior_code_hash) = maybe_prior_code_hash { - Self::note_past_code(para, now, now, prior_code_hash); - } else { - log::error!( - target: LOG_TARGET, - "Pallet paras storage is inconsistent, prior code not found {:?}", - ¶ - ); - } + Self::set_current_code(para, new_code_hash, frame_system::Pallet::::block_number()); Self::deposit_event(Event::CurrentCodeUpdated(para)); Ok(()) } @@ -928,7 +947,7 @@ pub mod pallet { new_code, relay_parent_number, &config, - SetGoAhead::No, + UpgradeStrategy::ApplyAtExpectedBlock, ); Self::deposit_event(Event::CodeUpgradeScheduled(para)); Ok(()) @@ -1227,7 +1246,7 @@ impl Pallet { pub(crate) fn schedule_code_upgrade_external( id: ParaId, new_code: ValidationCode, - set_go_ahead: SetGoAhead, + upgrade_strategy: UpgradeStrategy, ) -> DispatchResult { // Check that we can schedule an upgrade at all. ensure!(Self::can_upgrade_validation_code(id), Error::::CannotUpgradeCode); @@ -1239,7 +1258,7 @@ impl Pallet { let current_block = frame_system::Pallet::::block_number(); // Schedule the upgrade with a delay just like if a parachain triggered the upgrade. let upgrade_block = current_block.saturating_add(config.validation_upgrade_delay); - Self::schedule_code_upgrade(id, new_code, upgrade_block, &config, set_go_ahead); + Self::schedule_code_upgrade(id, new_code, upgrade_block, &config, upgrade_strategy); Self::deposit_event(Event::CodeUpgradeScheduled(id)); Ok(()) } @@ -1252,8 +1271,9 @@ impl Pallet { /// Called by the initializer to initialize the paras pallet. pub(crate) fn initializer_initialize(now: BlockNumberFor) -> Weight { - let weight = Self::prune_old_code(now); - weight + Self::process_scheduled_upgrade_changes(now) + Self::prune_old_code(now) + + Self::process_scheduled_upgrade_changes(now) + + Self::process_future_code_upgrades_at(now) } /// Called by the initializer to finalize the paras pallet. @@ -1355,16 +1375,13 @@ impl Pallet { // NOTE both of those iterates over the list and the outgoing. We do not expect either // of these to be large. Thus should be fine. UpcomingUpgrades::::mutate(|upcoming_upgrades| { - *upcoming_upgrades = mem::take(upcoming_upgrades) - .into_iter() - .filter(|(para, _)| !outgoing.contains(para)) - .collect(); + upcoming_upgrades.retain(|(para, _)| !outgoing.contains(para)); }); UpgradeCooldowns::::mutate(|upgrade_cooldowns| { - *upgrade_cooldowns = mem::take(upgrade_cooldowns) - .into_iter() - .filter(|(para, _)| !outgoing.contains(para)) - .collect(); + upgrade_cooldowns.retain(|(para, _)| !outgoing.contains(para)); + }); + FutureCodeUpgradesAt::::mutate(|future_upgrades| { + future_upgrades.retain(|(para, _)| !outgoing.contains(para)); }); } @@ -1460,6 +1477,37 @@ impl Pallet { T::DbWeight::get().reads_writes(1 + pruning_tasks_done, 2 * pruning_tasks_done) } + /// Process the future code upgrades that should be applied directly. + /// + /// Upgrades that should not be applied directly are being processed in + /// [`Self::process_scheduled_upgrade_changes`]. + fn process_future_code_upgrades_at(now: BlockNumberFor) -> Weight { + // account weight for `FutureCodeUpgradeAt::mutate`. + let mut weight = T::DbWeight::get().reads_writes(1, 1); + FutureCodeUpgradesAt::::mutate( + |upcoming_upgrades: &mut Vec<(ParaId, BlockNumberFor)>| { + let num = upcoming_upgrades.iter().take_while(|&(_, at)| at <= &now).count(); + for (id, expected_at) in upcoming_upgrades.drain(..num) { + weight += T::DbWeight::get().reads_writes(1, 1); + + // Both should always be `Some` in this case, since a code upgrade is scheduled. + let new_code_hash = if let Some(new_code_hash) = FutureCodeHash::::take(&id) + { + new_code_hash + } else { + log::error!(target: LOG_TARGET, "Missing future code hash for {:?}", &id); + continue + }; + + weight += Self::set_current_code(id, new_code_hash, expected_at); + } + num + }, + ); + + weight + } + /// Process the timers related to upgrades. Specifically, the upgrade go ahead signals toggle /// and the upgrade cooldown restrictions. However, this function does not actually unset /// the upgrade restriction, that will happen in the `initializer_finalize` function. However, @@ -1580,14 +1628,14 @@ impl Pallet { PvfCheckCause::Onboarding(id) => { weight += Self::proceed_with_onboarding(*id, sessions_observed); }, - PvfCheckCause::Upgrade { id, included_at, set_go_ahead } => { + PvfCheckCause::Upgrade { id, included_at, upgrade_strategy } => { weight += Self::proceed_with_upgrade( *id, code_hash, now, *included_at, cfg, - *set_go_ahead, + *upgrade_strategy, ); }, } @@ -1621,38 +1669,50 @@ impl Pallet { now: BlockNumberFor, relay_parent_number: BlockNumberFor, cfg: &configuration::HostConfiguration>, - set_go_ahead: SetGoAhead, + upgrade_strategy: UpgradeStrategy, ) -> Weight { let mut weight = Weight::zero(); - // Compute the relay-chain block number starting at which the code upgrade is ready to be - // applied. + // Compute the relay-chain block number starting at which the code upgrade is ready to + // be applied. // - // The first parablock that has a relay-parent higher or at the same height of `expected_at` - // will trigger the code upgrade. The parablock that comes after that will be validated - // against the new validation code. + // The first parablock that has a relay-parent higher or at the same height of + // `expected_at` will trigger the code upgrade. The parablock that comes after that will + // be validated against the new validation code. // - // Here we are trying to choose the block number that will have `validation_upgrade_delay` - // blocks from the relay-parent of inclusion of the the block that scheduled code upgrade - // but no less than `minimum_validation_upgrade_delay`. We want this delay out of caution - // so that when the last vote for pre-checking comes the parachain will have some time until - // the upgrade finally takes place. + // Here we are trying to choose the block number that will have + // `validation_upgrade_delay` blocks from the relay-parent of inclusion of the the block + // that scheduled code upgrade but no less than `minimum_validation_upgrade_delay`. We + // want this delay out of caution so that when the last vote for pre-checking comes the + // parachain will have some time until the upgrade finally takes place. let expected_at = cmp::max( relay_parent_number + cfg.validation_upgrade_delay, now + cfg.minimum_validation_upgrade_delay, ); - weight += T::DbWeight::get().reads_writes(1, 4); - FutureCodeUpgrades::::insert(&id, expected_at); + match upgrade_strategy { + UpgradeStrategy::ApplyAtExpectedBlock => { + FutureCodeUpgradesAt::::mutate(|future_upgrades| { + let insert_idx = future_upgrades + .binary_search_by_key(&expected_at, |&(_, b)| b) + .unwrap_or_else(|idx| idx); + future_upgrades.insert(insert_idx, (id, expected_at)); + }); - // Only set an upcoming upgrade if `GoAhead` signal should be set for the respective para. - if set_go_ahead == SetGoAhead::Yes { - UpcomingUpgrades::::mutate(|upcoming_upgrades| { - let insert_idx = upcoming_upgrades - .binary_search_by_key(&expected_at, |&(_, b)| b) - .unwrap_or_else(|idx| idx); - upcoming_upgrades.insert(insert_idx, (id, expected_at)); - }); + weight += T::DbWeight::get().reads_writes(0, 2); + }, + UpgradeStrategy::SetGoAheadSignal => { + FutureCodeUpgrades::::insert(&id, expected_at); + + UpcomingUpgrades::::mutate(|upcoming_upgrades| { + let insert_idx = upcoming_upgrades + .binary_search_by_key(&expected_at, |&(_, b)| b) + .unwrap_or_else(|idx| idx); + upcoming_upgrades.insert(insert_idx, (id, expected_at)); + }); + + weight += T::DbWeight::get().reads_writes(1, 3); + }, } let expected_at = expected_at.saturated_into(); @@ -1892,7 +1952,7 @@ impl Pallet { new_code: ValidationCode, inclusion_block_number: BlockNumberFor, cfg: &configuration::HostConfiguration>, - set_go_ahead: SetGoAhead, + upgrade_strategy: UpgradeStrategy, ) -> Weight { let mut weight = T::DbWeight::get().reads(1); @@ -1949,7 +2009,7 @@ impl Pallet { }); weight += Self::kick_off_pvf_check( - PvfCheckCause::Upgrade { id, included_at: inclusion_block_number, set_go_ahead }, + PvfCheckCause::Upgrade { id, included_at: inclusion_block_number, upgrade_strategy }, code_hash, new_code, cfg, @@ -2061,24 +2121,10 @@ impl Pallet { log::error!(target: LOG_TARGET, "Missing future code hash for {:?}", &id); return T::DbWeight::get().reads_writes(3, 1 + 3) }; - let maybe_prior_code_hash = CurrentCodeHash::::get(&id); - CurrentCodeHash::::insert(&id, &new_code_hash); - let log = ConsensusLog::ParaUpgradeCode(id, new_code_hash); - >::deposit_log(log.into()); + let weight = Self::set_current_code(id, new_code_hash, expected_at); - // `now` is only used for registering pruning as part of `fn note_past_code` - let now = >::block_number(); - - let weight = if let Some(prior_code_hash) = maybe_prior_code_hash { - Self::note_past_code(id, expected_at, now, prior_code_hash) - } else { - log::error!(target: LOG_TARGET, "Missing prior code hash for para {:?}", &id); - Weight::zero() - }; - - // add 1 to writes due to heads update. - weight + T::DbWeight::get().reads_writes(3, 1 + 3) + weight + T::DbWeight::get().reads_writes(3, 3) } else { T::DbWeight::get().reads_writes(1, 1 + 0) } @@ -2094,6 +2140,34 @@ impl Pallet { weight.saturating_add(T::OnNewHead::on_new_head(id, &new_head)) } + /// Set the current code for the given parachain. + // `at` for para-triggered replacement is the block number of the relay-chain + // block in whose context the parablock was executed + // (i.e. number of `relay_parent` in the receipt) + pub(crate) fn set_current_code( + id: ParaId, + new_code_hash: ValidationCodeHash, + at: BlockNumberFor, + ) -> Weight { + let maybe_prior_code_hash = CurrentCodeHash::::get(&id); + CurrentCodeHash::::insert(&id, &new_code_hash); + + let log = ConsensusLog::ParaUpgradeCode(id, new_code_hash); + >::deposit_log(log.into()); + + // `now` is only used for registering pruning as part of `fn note_past_code` + let now = >::block_number(); + + let weight = if let Some(prior_code_hash) = maybe_prior_code_hash { + Self::note_past_code(id, at, now, prior_code_hash) + } else { + log::error!(target: LOG_TARGET, "Missing prior code hash for para {:?}", &id); + Weight::zero() + }; + + weight + T::DbWeight::get().writes(1) + } + /// Returns the list of PVFs (aka validation code) that require casting a vote by a validator in /// the active validator set. pub(crate) fn pvfs_require_precheck() -> Vec { diff --git a/polkadot/runtime/parachains/src/paras/tests.rs b/polkadot/runtime/parachains/src/paras/tests.rs index 39abd2367b7..ad75166271e 100644 --- a/polkadot/runtime/parachains/src/paras/tests.rs +++ b/polkadot/runtime/parachains/src/paras/tests.rs @@ -451,7 +451,7 @@ fn code_upgrade_applied_after_delay() { new_code.clone(), 1, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); // Include votes for super-majority. submit_super_majority_pvf_votes(&new_code, EXPECTED_SESSION, true); @@ -521,7 +521,7 @@ fn code_upgrade_applied_after_delay() { } #[test] -fn code_upgrade_applied_without_setting_go_ahead_signal() { +fn upgrade_strategy_apply_at_expected_block_works() { let code_retention_period = 10; let validation_upgrade_delay = 5; let validation_upgrade_cooldown = 10; @@ -560,77 +560,42 @@ fn code_upgrade_applied_without_setting_go_ahead_signal() { run_to_block(2, Some(vec![1])); assert_eq!(Paras::current_code(¶_id), Some(original_code.clone())); - let (expected_at, next_possible_upgrade_at) = { - // this parablock is in the context of block 1. - let expected_at = 1 + validation_upgrade_delay; - let next_possible_upgrade_at = 1 + validation_upgrade_cooldown; - // `set_go_ahead` parameter set to `false` which prevents signaling the parachain - // with the `GoAhead` signal. - Paras::schedule_code_upgrade( - para_id, - new_code.clone(), - 1, - &Configuration::config(), - SetGoAhead::No, - ); - // Include votes for super-majority. - submit_super_majority_pvf_votes(&new_code, EXPECTED_SESSION, true); - - Paras::note_new_head(para_id, Default::default(), 1); - - assert!(Paras::past_code_meta(¶_id).most_recent_change().is_none()); - assert_eq!(FutureCodeUpgrades::::get(¶_id), Some(expected_at)); - assert_eq!(FutureCodeHash::::get(¶_id), Some(new_code.hash())); - assert_eq!(UpcomingUpgrades::::get(), vec![]); - assert_eq!(UpgradeCooldowns::::get(), vec![(para_id, next_possible_upgrade_at)]); - assert_eq!(Paras::current_code(¶_id), Some(original_code.clone())); - check_code_is_stored(&original_code); - check_code_is_stored(&new_code); - - (expected_at, next_possible_upgrade_at) - }; + // this parablock is in the context of block 1. + let expected_at = 1 + validation_upgrade_delay; + let next_possible_upgrade_at = 1 + validation_upgrade_cooldown; + // `set_go_ahead` parameter set to `false` which prevents signaling the parachain + // with the `GoAhead` signal. + Paras::schedule_code_upgrade( + para_id, + new_code.clone(), + 1, + &Configuration::config(), + UpgradeStrategy::ApplyAtExpectedBlock, + ); + // Include votes for super-majority. + submit_super_majority_pvf_votes(&new_code, EXPECTED_SESSION, true); + assert!(FutureCodeUpgradesAt::::get().iter().any(|(id, _)| *id == para_id)); + // Going to the expected block triggers the upgrade directly. run_to_block(expected_at, None); - // the candidate is in the context of the parent of `expected_at`, - // thus does not trigger the code upgrade. However, now the `UpgradeGoAheadSignal` - // should not be set. - { - Paras::note_new_head(para_id, Default::default(), expected_at - 1); - - assert!(Paras::past_code_meta(¶_id).most_recent_change().is_none()); - assert_eq!(FutureCodeUpgrades::::get(¶_id), Some(expected_at)); - assert_eq!(FutureCodeHash::::get(¶_id), Some(new_code.hash())); - assert!(UpgradeGoAheadSignal::::get(¶_id).is_none()); - assert_eq!(Paras::current_code(¶_id), Some(original_code.clone())); - check_code_is_stored(&original_code); - check_code_is_stored(&new_code); - } - - run_to_block(expected_at + 1, None); - - // the candidate is in the context of `expected_at`, and triggers - // the upgrade. - { - Paras::note_new_head(para_id, Default::default(), expected_at); + // Reporting a head doesn't change anything. + Paras::note_new_head(para_id, Default::default(), expected_at - 1); - assert_eq!(Paras::past_code_meta(¶_id).most_recent_change(), Some(expected_at)); - assert_eq!( - PastCodeHash::::get(&(para_id, expected_at)), - Some(original_code.hash()), - ); - assert!(FutureCodeUpgrades::::get(¶_id).is_none()); - assert!(FutureCodeHash::::get(¶_id).is_none()); - assert!(UpgradeGoAheadSignal::::get(¶_id).is_none()); - assert_eq!(Paras::current_code(¶_id), Some(new_code.clone())); - assert_eq!( - UpgradeRestrictionSignal::::get(¶_id), - Some(UpgradeRestriction::Present), - ); - assert_eq!(UpgradeCooldowns::::get(), vec![(para_id, next_possible_upgrade_at)]); - check_code_is_stored(&original_code); - check_code_is_stored(&new_code); - } + assert_eq!(Paras::past_code_meta(¶_id).most_recent_change(), Some(expected_at)); + assert_eq!(PastCodeHash::::get(&(para_id, expected_at)), Some(original_code.hash())); + assert!(FutureCodeUpgrades::::get(¶_id).is_none()); + assert!(FutureCodeUpgradesAt::::get().iter().all(|(id, _)| *id != para_id)); + assert!(FutureCodeHash::::get(¶_id).is_none()); + assert!(UpgradeGoAheadSignal::::get(¶_id).is_none()); + assert_eq!(Paras::current_code(¶_id), Some(new_code.clone())); + assert_eq!( + UpgradeRestrictionSignal::::get(¶_id), + Some(UpgradeRestriction::Present), + ); + assert_eq!(UpgradeCooldowns::::get(), vec![(para_id, next_possible_upgrade_at)]); + check_code_is_stored(&original_code); + check_code_is_stored(&new_code); run_to_block(next_possible_upgrade_at + 1, None); @@ -688,7 +653,7 @@ fn code_upgrade_applied_after_delay_even_when_late() { new_code.clone(), 1, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); // Include votes for super-majority. submit_super_majority_pvf_votes(&new_code, EXPECTED_SESSION, true); @@ -772,7 +737,7 @@ fn submit_code_change_when_not_allowed_is_err() { new_code.clone(), 1, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); // Include votes for super-majority. submit_super_majority_pvf_votes(&new_code, EXPECTED_SESSION, true); @@ -790,7 +755,7 @@ fn submit_code_change_when_not_allowed_is_err() { newer_code.clone(), 2, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); assert_eq!( FutureCodeUpgrades::::get(¶_id), @@ -854,7 +819,7 @@ fn upgrade_restriction_elapsed_doesnt_mean_can_upgrade() { new_code.clone(), 0, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); // Include votes for super-majority. submit_super_majority_pvf_votes(&new_code, EXPECTED_SESSION, true); @@ -879,7 +844,7 @@ fn upgrade_restriction_elapsed_doesnt_mean_can_upgrade() { newer_code.clone(), 30, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); assert_eq!(FutureCodeUpgrades::::get(¶_id), Some(0 + validation_upgrade_delay)); }); @@ -940,7 +905,7 @@ fn full_parachain_cleanup_storage() { new_code.clone(), 1, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); // Include votes for super-majority. submit_super_majority_pvf_votes(&new_code, EXPECTED_SESSION, true); @@ -1036,7 +1001,7 @@ fn cannot_offboard_ongoing_pvf_check() { new_code.clone(), RELAY_PARENT, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); assert!(!Paras::pvfs_require_precheck().is_empty()); @@ -1194,7 +1159,7 @@ fn code_hash_at_returns_up_to_end_of_code_retention_period() { new_code.clone(), 0, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); // Include votes for super-majority. submit_super_majority_pvf_votes(&new_code, EXPECTED_SESSION, true); @@ -1303,7 +1268,7 @@ fn pvf_check_coalescing_onboarding_and_upgrade() { validation_code.clone(), RELAY_PARENT, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); assert!(!Paras::pvfs_require_precheck().is_empty()); @@ -1413,7 +1378,7 @@ fn pvf_check_upgrade_reject() { new_code.clone(), RELAY_PARENT, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); check_code_is_stored(&new_code); @@ -1599,7 +1564,7 @@ fn include_pvf_check_statement_refunds_weight() { new_code.clone(), RELAY_PARENT, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); let mut stmts = IntoIterator::into_iter([0, 1, 2, 3]) @@ -1700,7 +1665,7 @@ fn poke_unused_validation_code_doesnt_remove_code_with_users() { validation_code.clone(), 1, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); Paras::note_new_head(para_id, HeadData::default(), 1); @@ -1771,7 +1736,7 @@ fn add_trusted_validation_code_insta_approval() { validation_code.clone(), 1, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); Paras::note_new_head(para_id, HeadData::default(), 1); @@ -1813,7 +1778,7 @@ fn add_trusted_validation_code_enacts_existing_pvf_vote() { validation_code.clone(), 1, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); Paras::note_new_head(para_id, HeadData::default(), 1); diff --git a/prdoc/pr_3341.prdoc b/prdoc/pr_3341.prdoc new file mode 100644 index 00000000000..de714fa5a1e --- /dev/null +++ b/prdoc/pr_3341.prdoc @@ -0,0 +1,18 @@ +title: "Fix `schedule_code_upgrade` when called by the owner/root" + +doc: + - audience: Runtime User + description: | + Fixes `schedule_code_upgrade` when being used by the owner/root. The call is used for + manually upgrading the validation code of a parachain on the relay chain. It was failing + before because the relay chain waited for the parachain to make progress. However, this + call is mostly used for when a parachain are bricked which means that they are not able + anymore to build any blocks. The fix is to schedule the validation code upgrade and then + to enact it at the scheduled block. The enacting happens now without requiring the parachain + to make any progress. + +crates: + - name: polkadot-runtime-common + bump: minor + - name: polkadot-runtime-parachains + bump: major -- GitLab From db1af43c39f052fbf85a330e74c02a75f65f59a0 Mon Sep 17 00:00:00 2001 From: Javier Viola <363911+pepoviola@users.noreply.github.com> Date: Tue, 2 Apr 2024 13:22:21 +0200 Subject: [PATCH 144/187] chore(zombienet): bump version (#3933) This version includes: - Internal metrics of zombienet (used to benchmark with v2). --- .gitlab/pipeline/zombienet.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab/pipeline/zombienet.yml b/.gitlab/pipeline/zombienet.yml index 82341eb709f..52948e1eb71 100644 --- a/.gitlab/pipeline/zombienet.yml +++ b/.gitlab/pipeline/zombienet.yml @@ -1,7 +1,8 @@ .zombienet-refs: extends: .build-refs variables: - ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.98" + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.99" + PUSHGATEWAY_URL: "http://zombienet-prometheus-pushgateway.managed-monitoring:9091/metrics/job/zombie-metrics" include: # substrate tests -- GitLab From d5617cf3cd69fb3b7de338c46d8a8778452ce769 Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Tue, 2 Apr 2024 15:25:56 +0300 Subject: [PATCH 145/187] Update bridges subtree (#3938) Pulling the latest changes from `parity-bridges-common` --- Cargo.lock | 8 ++++---- bridges/README.md | 6 +++--- bridges/bin/runtime-common/Cargo.toml | 4 ++-- bridges/chains/chain-asset-hub-rococo/Cargo.toml | 5 +++-- bridges/chains/chain-asset-hub-westend/Cargo.toml | 5 +++-- bridges/chains/chain-bridge-hub-cumulus/Cargo.toml | 1 + bridges/chains/chain-bridge-hub-kusama/Cargo.toml | 1 + bridges/chains/chain-bridge-hub-polkadot/Cargo.toml | 1 + bridges/chains/chain-bridge-hub-rococo/Cargo.toml | 1 + bridges/chains/chain-bridge-hub-westend/Cargo.toml | 1 + bridges/chains/chain-kusama/Cargo.toml | 1 + bridges/chains/chain-polkadot-bulletin/Cargo.toml | 5 +++-- bridges/chains/chain-polkadot/Cargo.toml | 1 + bridges/chains/chain-rococo/Cargo.toml | 1 + bridges/chains/chain-westend/Cargo.toml | 1 + bridges/modules/grandpa/Cargo.toml | 5 +++-- bridges/modules/messages/Cargo.toml | 5 +++-- bridges/modules/parachains/Cargo.toml | 5 +++-- bridges/modules/relayers/Cargo.toml | 5 +++-- bridges/modules/xcm-bridge-hub-router/Cargo.toml | 5 +++-- bridges/modules/xcm-bridge-hub/Cargo.toml | 5 +++-- bridges/primitives/header-chain/Cargo.toml | 5 +++-- bridges/primitives/messages/Cargo.toml | 5 +++-- bridges/primitives/parachains/Cargo.toml | 5 +++-- bridges/primitives/polkadot-core/Cargo.toml | 5 +++-- bridges/primitives/relayers/Cargo.toml | 5 +++-- bridges/primitives/runtime/Cargo.toml | 5 +++-- bridges/primitives/test-utils/Cargo.toml | 3 ++- bridges/primitives/xcm-bridge-hub-router/Cargo.toml | 5 +++-- bridges/primitives/xcm-bridge-hub/Cargo.toml | 1 + 30 files changed, 69 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 88fde5ed154..9a8eff4691e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17000,9 +17000,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ef2175c2907e7c8bc0a9c3f86aeb5ec1f3b275300ad58a44d0c3ae379a5e52e" +checksum = "788745a868b0e751750388f4e6546eb921ef714a4317fa6954f7cde114eb2eb7" dependencies = [ "bitvec", "cfg-if", @@ -17014,9 +17014,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b8eb8fd61c5cdd3390d9b2132300a7e7618955b98b8416f118c1b4e144f" +checksum = "7dc2f4e8bc344b9fc3d5f74f72c2e55bfc38d28dc2ebc69c194a3df424e4d9ac" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", diff --git a/bridges/README.md b/bridges/README.md index a2ce213d254..8bfa39841f5 100644 --- a/bridges/README.md +++ b/bridges/README.md @@ -38,10 +38,10 @@ cargo test --all ``` Also you can build the repo with [Parity CI Docker -image](https://github.com/paritytech/scripts/tree/master/dockerfiles/bridges-ci): +image](https://github.com/paritytech/scripts/tree/master/dockerfiles/ci-unified): ```bash -docker pull paritytech/bridges-ci:production +docker pull paritytech/ci-unified:latest mkdir ~/cache chown 1000:1000 ~/cache #processes in the container runs as "nonroot" user with UID 1000 docker run --rm -it -w /shellhere/parity-bridges-common \ @@ -49,7 +49,7 @@ docker run --rm -it -w /shellhere/parity-bridges-common \ -v "$(pwd)":/shellhere/parity-bridges-common \ -e CARGO_HOME=/cache/cargo/ \ -e SCCACHE_DIR=/cache/sccache/ \ - -e CARGO_TARGET_DIR=/cache/target/ paritytech/bridges-ci:production cargo build --all + -e CARGO_TARGET_DIR=/cache/target/ paritytech/ci-unified:latest cargo build --all #artifacts can be found in ~/cache/target ``` diff --git a/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml index f00ba1c9734..67b91a16a30 100644 --- a/bridges/bin/runtime-common/Cargo.toml +++ b/bridges/bin/runtime-common/Cargo.toml @@ -11,10 +11,10 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } hash-db = { version = "0.16.0", default-features = false } log = { workspace = true } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } static_assertions = { version = "1.1", optional = true } # Bridge dependencies diff --git a/bridges/chains/chain-asset-hub-rococo/Cargo.toml b/bridges/chains/chain-asset-hub-rococo/Cargo.toml index 55dc384badd..9a6419a5b40 100644 --- a/bridges/chains/chain-asset-hub-rococo/Cargo.toml +++ b/bridges/chains/chain-asset-hub-rococo/Cargo.toml @@ -5,13 +5,14 @@ version = "0.4.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate Dependencies frame-support = { path = "../../../substrate/frame/support", default-features = false } diff --git a/bridges/chains/chain-asset-hub-westend/Cargo.toml b/bridges/chains/chain-asset-hub-westend/Cargo.toml index 1379b099a2a..1c08ee28e41 100644 --- a/bridges/chains/chain-asset-hub-westend/Cargo.toml +++ b/bridges/chains/chain-asset-hub-westend/Cargo.toml @@ -5,13 +5,14 @@ version = "0.3.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate Dependencies frame-support = { path = "../../../substrate/frame/support", default-features = false } diff --git a/bridges/chains/chain-bridge-hub-cumulus/Cargo.toml b/bridges/chains/chain-bridge-hub-cumulus/Cargo.toml index 5e14cb052b7..4b900002a4d 100644 --- a/bridges/chains/chain-bridge-hub-cumulus/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-cumulus/Cargo.toml @@ -5,6 +5,7 @@ version = "0.7.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true diff --git a/bridges/chains/chain-bridge-hub-kusama/Cargo.toml b/bridges/chains/chain-bridge-hub-kusama/Cargo.toml index 77bc8e54a9d..ff6dd8849ab 100644 --- a/bridges/chains/chain-bridge-hub-kusama/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-kusama/Cargo.toml @@ -5,6 +5,7 @@ version = "0.6.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true diff --git a/bridges/chains/chain-bridge-hub-polkadot/Cargo.toml b/bridges/chains/chain-bridge-hub-polkadot/Cargo.toml index 5d7a3bbcc1d..da8b8a82fa7 100644 --- a/bridges/chains/chain-bridge-hub-polkadot/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-polkadot/Cargo.toml @@ -5,6 +5,7 @@ version = "0.6.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true diff --git a/bridges/chains/chain-bridge-hub-rococo/Cargo.toml b/bridges/chains/chain-bridge-hub-rococo/Cargo.toml index 3966ef72dcb..f7672df012f 100644 --- a/bridges/chains/chain-bridge-hub-rococo/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-rococo/Cargo.toml @@ -5,6 +5,7 @@ version = "0.7.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true diff --git a/bridges/chains/chain-bridge-hub-westend/Cargo.toml b/bridges/chains/chain-bridge-hub-westend/Cargo.toml index d35eac8b3fe..ec74c4b947d 100644 --- a/bridges/chains/chain-bridge-hub-westend/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-westend/Cargo.toml @@ -5,6 +5,7 @@ version = "0.3.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true diff --git a/bridges/chains/chain-kusama/Cargo.toml b/bridges/chains/chain-kusama/Cargo.toml index 4ff4cb46976..66061ff2793 100644 --- a/bridges/chains/chain-kusama/Cargo.toml +++ b/bridges/chains/chain-kusama/Cargo.toml @@ -5,6 +5,7 @@ version = "0.5.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true diff --git a/bridges/chains/chain-polkadot-bulletin/Cargo.toml b/bridges/chains/chain-polkadot-bulletin/Cargo.toml index 37e060d897c..2db16a00e92 100644 --- a/bridges/chains/chain-polkadot-bulletin/Cargo.toml +++ b/bridges/chains/chain-polkadot-bulletin/Cargo.toml @@ -5,13 +5,14 @@ version = "0.4.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Bridge Dependencies diff --git a/bridges/chains/chain-polkadot/Cargo.toml b/bridges/chains/chain-polkadot/Cargo.toml index 0db6791f66e..c700935f308 100644 --- a/bridges/chains/chain-polkadot/Cargo.toml +++ b/bridges/chains/chain-polkadot/Cargo.toml @@ -5,6 +5,7 @@ version = "0.5.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true diff --git a/bridges/chains/chain-rococo/Cargo.toml b/bridges/chains/chain-rococo/Cargo.toml index 9c63f960ae4..5a5613bb376 100644 --- a/bridges/chains/chain-rococo/Cargo.toml +++ b/bridges/chains/chain-rococo/Cargo.toml @@ -5,6 +5,7 @@ version = "0.6.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true diff --git a/bridges/chains/chain-westend/Cargo.toml b/bridges/chains/chain-westend/Cargo.toml index f5de9b95c82..10b06d76507 100644 --- a/bridges/chains/chain-westend/Cargo.toml +++ b/bridges/chains/chain-westend/Cargo.toml @@ -5,6 +5,7 @@ version = "0.3.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true diff --git a/bridges/modules/grandpa/Cargo.toml b/bridges/modules/grandpa/Cargo.toml index 25c6c4e03d5..0db1827211a 100644 --- a/bridges/modules/grandpa/Cargo.toml +++ b/bridges/modules/grandpa/Cargo.toml @@ -5,6 +5,7 @@ description = "Module implementing GRANDPA on-chain light client used for bridgi authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true @@ -12,10 +13,10 @@ workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } finality-grandpa = { version = "0.16.2", default-features = false } log = { workspace = true } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Bridge Dependencies diff --git a/bridges/modules/messages/Cargo.toml b/bridges/modules/messages/Cargo.toml index 7d0e1b94959..df5b92db740 100644 --- a/bridges/modules/messages/Cargo.toml +++ b/bridges/modules/messages/Cargo.toml @@ -5,15 +5,16 @@ version = "0.7.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } num-traits = { version = "0.2", default-features = false } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Bridge dependencies diff --git a/bridges/modules/parachains/Cargo.toml b/bridges/modules/parachains/Cargo.toml index a9dd9beeb1f..35213be0674 100644 --- a/bridges/modules/parachains/Cargo.toml +++ b/bridges/modules/parachains/Cargo.toml @@ -5,14 +5,15 @@ description = "Module that allows bridged relay chains to exchange information o authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Bridge Dependencies diff --git a/bridges/modules/relayers/Cargo.toml b/bridges/modules/relayers/Cargo.toml index f3de72da771..e2b7aca9224 100644 --- a/bridges/modules/relayers/Cargo.toml +++ b/bridges/modules/relayers/Cargo.toml @@ -5,14 +5,15 @@ version = "0.7.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Bridge dependencies diff --git a/bridges/modules/xcm-bridge-hub-router/Cargo.toml b/bridges/modules/xcm-bridge-hub-router/Cargo.toml index 98477f2df18..06f2a339bed 100644 --- a/bridges/modules/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub-router/Cargo.toml @@ -5,14 +5,15 @@ version = "0.5.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.11.0", default-features = false, features = ["bit-vec", "derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["bit-vec", "derive", "serde"] } # Bridge dependencies diff --git a/bridges/modules/xcm-bridge-hub/Cargo.toml b/bridges/modules/xcm-bridge-hub/Cargo.toml index 68ac32281f3..4483a379090 100644 --- a/bridges/modules/xcm-bridge-hub/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub/Cargo.toml @@ -5,14 +5,15 @@ version = "0.2.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Bridge Dependencies bp-messages = { path = "../../primitives/messages", default-features = false } diff --git a/bridges/primitives/header-chain/Cargo.toml b/bridges/primitives/header-chain/Cargo.toml index d96a02efba8..f7a61a9ff32 100644 --- a/bridges/primitives/header-chain/Cargo.toml +++ b/bridges/primitives/header-chain/Cargo.toml @@ -5,14 +5,15 @@ version = "0.7.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } finality-grandpa = { version = "0.16.2", default-features = false } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], workspace = true } # Bridge dependencies diff --git a/bridges/primitives/messages/Cargo.toml b/bridges/primitives/messages/Cargo.toml index 9d742e3eded..d41acfb9d32 100644 --- a/bridges/primitives/messages/Cargo.toml +++ b/bridges/primitives/messages/Cargo.toml @@ -5,13 +5,14 @@ version = "0.7.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["bit-vec", "derive"] } -scale-info = { version = "2.11.0", default-features = false, features = ["bit-vec", "derive"] } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["bit-vec", "derive"] } serde = { features = ["alloc", "derive"], workspace = true } # Bridge dependencies diff --git a/bridges/primitives/parachains/Cargo.toml b/bridges/primitives/parachains/Cargo.toml index 3846c563575..2e7000b86a5 100644 --- a/bridges/primitives/parachains/Cargo.toml +++ b/bridges/primitives/parachains/Cargo.toml @@ -5,14 +5,15 @@ version = "0.7.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2" -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Bridge dependencies diff --git a/bridges/primitives/polkadot-core/Cargo.toml b/bridges/primitives/polkadot-core/Cargo.toml index 5ab502569e4..53b1e574cb1 100644 --- a/bridges/primitives/polkadot-core/Cargo.toml +++ b/bridges/primitives/polkadot-core/Cargo.toml @@ -5,14 +5,15 @@ version = "0.7.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } parity-util-mem = { version = "0.12.0", optional = true } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } # Bridge Dependencies diff --git a/bridges/primitives/relayers/Cargo.toml b/bridges/primitives/relayers/Cargo.toml index 71d0fbf2ec3..1be7f1dc6eb 100644 --- a/bridges/primitives/relayers/Cargo.toml +++ b/bridges/primitives/relayers/Cargo.toml @@ -5,13 +5,14 @@ version = "0.7.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["bit-vec", "derive"] } -scale-info = { version = "2.11.0", default-features = false, features = ["bit-vec", "derive"] } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["bit-vec", "derive"] } # Bridge Dependencies diff --git a/bridges/primitives/runtime/Cargo.toml b/bridges/primitives/runtime/Cargo.toml index 2d454d264a1..cca9c21a608 100644 --- a/bridges/primitives/runtime/Cargo.toml +++ b/bridges/primitives/runtime/Cargo.toml @@ -5,17 +5,18 @@ version = "0.7.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } hash-db = { version = "0.16.0", default-features = false } impl-trait-for-tuples = "0.2.2" log = { workspace = true } num-traits = { version = "0.2", default-features = false } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], workspace = true } # Substrate Dependencies diff --git a/bridges/primitives/test-utils/Cargo.toml b/bridges/primitives/test-utils/Cargo.toml index d379e950b86..d314c38683c 100644 --- a/bridges/primitives/test-utils/Cargo.toml +++ b/bridges/primitives/test-utils/Cargo.toml @@ -5,6 +5,7 @@ description = "Utilities for testing substrate-based runtime bridge code" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true @@ -14,7 +15,7 @@ bp-header-chain = { path = "../header-chain", default-features = false } bp-parachains = { path = "../parachains", default-features = false } bp-polkadot-core = { path = "../polkadot-core", default-features = false } bp-runtime = { path = "../runtime", default-features = false } -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } ed25519-dalek = { version = "2.1", default-features = false } finality-grandpa = { version = "0.16.2", default-features = false } sp-application-crypto = { path = "../../../substrate/primitives/application-crypto", default-features = false } diff --git a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml index 734930f18c4..94eece16d57 100644 --- a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml @@ -5,13 +5,14 @@ version = "0.6.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["bit-vec", "derive"] } -scale-info = { version = "2.11.0", default-features = false, features = ["bit-vec", "derive"] } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["bit-vec", "derive"] } # Substrate Dependencies sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } diff --git a/bridges/primitives/xcm-bridge-hub/Cargo.toml b/bridges/primitives/xcm-bridge-hub/Cargo.toml index ad49ec1e831..27881bc99d1 100644 --- a/bridges/primitives/xcm-bridge-hub/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub/Cargo.toml @@ -5,6 +5,7 @@ version = "0.2.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true -- GitLab From 5eff3f94beb768a7ba56d9091f6137fa6dff6bb1 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 2 Apr 2024 15:28:48 +0300 Subject: [PATCH 146/187] beefy: error logs for validators with dummy keys (#3939) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This outputs: ``` 2024-04-02 14:36:02.135 ERROR tokio-runtime-worker beefy: 🥩 for session starting at block 21990151 no BEEFY authority key found in store, you must generate valid session keys (https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#generating-the-session-keys) ``` error log entry, once every session, for nodes running with `Role::Authority` that have no public BEEFY key in their keystore --------- Co-authored-by: Bastian Köcher --- polkadot/node/service/src/lib.rs | 25 +++--- substrate/bin/node/cli/src/service.rs | 1 + substrate/client/consensus/beefy/src/lib.rs | 18 ++++- substrate/client/consensus/beefy/src/tests.rs | 2 + .../client/consensus/beefy/src/worker.rs | 77 ++++--------------- 5 files changed, 50 insertions(+), 73 deletions(-) diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index 4f4ede53705..61076477f8e 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -1233,6 +1233,7 @@ pub fn new_full( prometheus_registry: prometheus_registry.clone(), links: beefy_links, on_demand_justifications_handler: beefy_on_demand_justifications_handler, + is_authority: role.is_authority(), }; let gadget = beefy::start_beefy_gadget::<_, _, _, _, _, _, _>(beefy_params); @@ -1242,18 +1243,18 @@ pub fn new_full( task_manager .spawn_essential_handle() .spawn_blocking("beefy-gadget", None, gadget); - // When offchain indexing is enabled, MMR gadget should also run. - if is_offchain_indexing_enabled { - task_manager.spawn_essential_handle().spawn_blocking( - "mmr-gadget", - None, - MmrGadget::start( - client.clone(), - backend.clone(), - sp_mmr_primitives::INDEXING_PREFIX.to_vec(), - ), - ); - } + } + // When offchain indexing is enabled, MMR gadget should also run. + if is_offchain_indexing_enabled { + task_manager.spawn_essential_handle().spawn_blocking( + "mmr-gadget", + None, + MmrGadget::start( + client.clone(), + backend.clone(), + sp_mmr_primitives::INDEXING_PREFIX.to_vec(), + ), + ); } let config = grandpa::Config { diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index dddb261a71d..d6e2a29d30b 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -652,6 +652,7 @@ pub fn new_full_base( prometheus_registry: prometheus_registry.clone(), links: beefy_links, on_demand_justifications_handler: beefy_on_demand_justifications_handler, + is_authority: role.is_authority(), }; let beefy_gadget = beefy::start_beefy_gadget::<_, _, _, _, _, _, _>(beefy_params); diff --git a/substrate/client/consensus/beefy/src/lib.rs b/substrate/client/consensus/beefy/src/lib.rs index 323af1bc830..714a0fb7c88 100644 --- a/substrate/client/consensus/beefy/src/lib.rs +++ b/substrate/client/consensus/beefy/src/lib.rs @@ -222,6 +222,8 @@ pub struct BeefyParams { pub links: BeefyVoterLinks, /// Handler for incoming BEEFY justifications requests from a remote peer. pub on_demand_justifications_handler: BeefyJustifsRequestHandler, + /// Whether running under "Authority" role. + pub is_authority: bool, } /// Helper object holding BEEFY worker communication/gossip components. /// @@ -270,6 +272,7 @@ where min_block_delta: u32, gossip_validator: Arc>, finality_notifications: &mut Fuse>, + is_authority: bool, ) -> Result { // Wait for BEEFY pallet to be active before starting voter. let (beefy_genesis, best_grandpa) = @@ -283,6 +286,7 @@ where runtime.clone(), &key_store, &metrics, + is_authority, ) .await?; // Update the gossip validator with the right starting round and set id. @@ -301,6 +305,7 @@ where comms: BeefyComms, links: BeefyVoterLinks, pending_justifications: BTreeMap, BeefyVersionedFinalityProof>, + is_authority: bool, ) -> BeefyWorker { BeefyWorker { backend: self.backend, @@ -313,6 +318,7 @@ where comms, links, pending_justifications, + is_authority, } } @@ -423,6 +429,7 @@ where runtime: Arc, key_store: &BeefyKeystore, metrics: &Option, + is_authority: bool, ) -> Result, Error> { // Initialize voter state from AUX DB if compatible. if let Some(mut state) = crate::aux_schema::load_persistent(backend.as_ref())? @@ -455,7 +462,13 @@ where "🥩 Handling missed BEEFY session after node restart: {:?}.", new_session_start ); - state.init_session_at(new_session_start, validator_set, key_store, metrics); + state.init_session_at( + new_session_start, + validator_set, + key_store, + metrics, + is_authority, + ); } return Ok(state) } @@ -491,6 +504,7 @@ pub async fn start_beefy_gadget( prometheus_registry, links, mut on_demand_justifications_handler, + is_authority, } = beefy_params; let BeefyNetworkParams { @@ -553,6 +567,7 @@ pub async fn start_beefy_gadget( min_block_delta, beefy_comms.gossip_validator.clone(), &mut finality_notifications, + is_authority, ).fuse() => { match builder_init_result { Ok(builder) => break builder, @@ -580,6 +595,7 @@ pub async fn start_beefy_gadget( beefy_comms, links.clone(), BTreeMap::new(), + is_authority, ); match futures::future::select( diff --git a/substrate/client/consensus/beefy/src/tests.rs b/substrate/client/consensus/beefy/src/tests.rs index d106c9dcd88..aecfec7b9ed 100644 --- a/substrate/client/consensus/beefy/src/tests.rs +++ b/substrate/client/consensus/beefy/src/tests.rs @@ -379,6 +379,7 @@ async fn voter_init_setup( Arc::new(api.clone()), &key_store, &metrics, + true, ) .await } @@ -438,6 +439,7 @@ where min_block_delta, prometheus_registry: None, on_demand_justifications_handler: on_demand_justif_handler, + is_authority: true, }; let task = crate::start_beefy_gadget::<_, _, _, _, _, _, _>(beefy_params); diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index 7a47f286ef7..ac6b72d1ea4 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -33,7 +33,7 @@ use crate::{ }; use codec::{Codec, Decode, DecodeAll, Encode}; use futures::{stream::Fuse, FutureExt, StreamExt}; -use log::{debug, error, info, log_enabled, trace, warn}; +use log::{debug, error, info, trace, warn}; use sc_client_api::{Backend, FinalityNotification, FinalityNotifications, HeaderBackend}; use sc_utils::notification::NotificationReceiver; use sp_api::ProvideRuntimeApi; @@ -51,7 +51,7 @@ use sp_runtime::{ SaturatedConversion, }; use std::{ - collections::{BTreeMap, BTreeSet, VecDeque}, + collections::{BTreeMap, VecDeque}, fmt::Debug, sync::Arc, }; @@ -332,6 +332,7 @@ impl PersistedState { validator_set: ValidatorSet, key_store: &BeefyKeystore, metrics: &Option, + is_authority: bool, ) { debug!(target: LOG_TARGET, "🥩 New active validator set: {:?}", validator_set); @@ -348,11 +349,16 @@ impl PersistedState { } } - if log_enabled!(target: LOG_TARGET, log::Level::Debug) { - // verify the new validator set - only do it if we're also logging the warning - if verify_validator_set::(&new_session_start, &validator_set, key_store).is_err() { - metric_inc!(metrics, beefy_no_authority_found_in_store); - } + // verify we have some BEEFY key available in keystore when role is authority. + if is_authority && key_store.public_keys().map_or(false, |k| k.is_empty()) { + error!( + target: LOG_TARGET, + "🥩 for session starting at block {:?} no BEEFY authority key found in store, \ + you must generate valid session keys \ + (https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#generating-the-session-keys)", + new_session_start, + ); + metric_inc!(metrics, beefy_no_authority_found_in_store); } let id = validator_set.id(); @@ -390,6 +396,8 @@ pub(crate) struct BeefyWorker { pub persisted_state: PersistedState, /// BEEFY voter metrics pub metrics: Option, + /// Node runs under "Authority" role. + pub is_authority: bool, } impl BeefyWorker @@ -425,6 +433,7 @@ where validator_set, &self.key_store, &self.metrics, + self.is_authority, ); } @@ -1040,33 +1049,6 @@ where } } -/// Verify `active` validator set for `block` against the key store -/// -/// We want to make sure that we have _at least one_ key in our keystore that -/// is part of the validator set, that's because if there are no local keys -/// then we can't perform our job as a validator. -/// -/// Note that for a non-authority node there will be no keystore, and we will -/// return an error and don't check. The error can usually be ignored. -fn verify_validator_set( - block: &NumberFor, - active: &ValidatorSet, - key_store: &BeefyKeystore, -) -> Result<(), Error> { - let active: BTreeSet<&AuthorityId> = active.validators().iter().collect(); - - let public_keys = key_store.public_keys()?; - let store: BTreeSet<&AuthorityId> = public_keys.iter().collect(); - - if store.intersection(&active).count() == 0 { - let msg = "no authority public key found in store".to_string(); - debug!(target: LOG_TARGET, "🥩 for block {:?} {}", block, msg); - Err(Error::Keystore(msg)) - } else { - Ok(()) - } -} - #[cfg(test)] pub(crate) mod tests { use super::*; @@ -1208,6 +1190,7 @@ pub(crate) mod tests { comms, pending_justifications: BTreeMap::new(), persisted_state, + is_authority: true, } } @@ -1471,32 +1454,6 @@ pub(crate) mod tests { assert_eq!(extracted, Some(validator_set)); } - #[tokio::test] - async fn keystore_vs_validator_set() { - let keys = &[Keyring::Alice]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1); - let mut worker = create_beefy_worker(net.peer(0), &keys[0], 1, validator_set.clone()); - - // keystore doesn't contain other keys than validators' - assert_eq!(verify_validator_set::(&1, &validator_set, &worker.key_store), Ok(())); - - // unknown `Bob` key - let keys = &[Keyring::Bob]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let err_msg = "no authority public key found in store".to_string(); - let expected = Err(Error::Keystore(err_msg)); - assert_eq!(verify_validator_set::(&1, &validator_set, &worker.key_store), expected); - - // worker has no keystore - worker.key_store = None.into(); - let expected_err = Err(Error::Keystore("no Keystore".into())); - assert_eq!( - verify_validator_set::(&1, &validator_set, &worker.key_store), - expected_err - ); - } - #[tokio::test] async fn should_finalize_correctly() { let keys = [Keyring::Alice]; -- GitLab From 7430f413503f8008fe60eb2e4ebd76d14af12ea9 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Tue, 2 Apr 2024 16:12:34 +0300 Subject: [PATCH 147/187] chainHead: Allow methods to be called from within a single connection context and limit connections (#3481) This PR ensures that the chainHead RPC class can be called only from within the same connection context. The chainHead methods are now registered as raw methods. - https://github.com/paritytech/jsonrpsee/pull/1297 The concept of raw methods is introduced in jsonrpsee, which is an async method that exposes the connection ID: The raw method doesn't have the concept of a blocking method. Previously blocking methods are now spawning a blocking task to handle their blocking (ie DB) access. We spawn the same number of tasks as before, however we do that explicitly. Another approach would be implementing a RPC middleware that captures and decodes the method parameters: - https://github.com/paritytech/polkadot-sdk/pull/3343 However, that approach is prone to errors since the methods are hardcoded by name. Performace is affected by the double deserialization that needs to happen to extract the subscription ID we'd like to limit. Once from the middleware, and once from the methods itself. This PR paves the way to implement the chainHead connection limiter: - https://github.com/paritytech/polkadot-sdk/issues/1505 Registering tokens (subscription ID / operation ID) on the `RpcConnections` could be extended to return an error when the maximum number of operations is reached. While at it, have added an integration-test to ensure that chainHead methods can be called from within the same connection context. Before this is merged, a new JsonRPC release should be made to expose the `raw-methods`: - [x] Use jsonrpsee from crates io (blocked by: https://github.com/paritytech/jsonrpsee/pull/1297) Closes: https://github.com/paritytech/polkadot-sdk/issues/3207 cc @paritytech/subxt-team --------- Signed-off-by: Alexandru Vasile Co-authored-by: Niklas Adolfsson --- Cargo.lock | 34 +- substrate/client/rpc-spec-v2/Cargo.toml | 1 + .../client/rpc-spec-v2/src/chain_head/api.rs | 30 +- .../rpc-spec-v2/src/chain_head/chain_head.rs | 321 ++++++++++++------ .../src/chain_head/chain_head_follow.rs | 17 +- .../rpc-spec-v2/src/chain_head/error.rs | 7 + .../src/chain_head/subscription/inner.rs | 53 +++ .../src/chain_head/subscription/mod.rs | 132 ++++++- .../rpc-spec-v2/src/chain_head/tests.rs | 230 ++++++++++++- .../rpc-spec-v2/src/common/connections.rs | 262 ++++++++++++++ .../client/rpc-spec-v2/src/common/mod.rs | 1 + 11 files changed, 934 insertions(+), 154 deletions(-) create mode 100644 substrate/client/rpc-spec-v2/src/common/connections.rs diff --git a/Cargo.lock b/Cargo.lock index 9a8eff4691e..24612391d3f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6840,9 +6840,9 @@ checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" [[package]] name = "jsonrpsee" -version = "0.22.0" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a95f7cc23d5fab0cdeeaf6bad8c8f5e7a3aa7f0d211957ea78232b327ab27b0" +checksum = "87f3ae45a64cfc0882934f963be9431b2a165d667f53140358181f262aca0702" dependencies = [ "jsonrpsee-core", "jsonrpsee-http-client", @@ -6856,9 +6856,9 @@ dependencies = [ [[package]] name = "jsonrpsee-client-transport" -version = "0.22.0" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b1736cfa3845fd9f8f43751f2b8e0e83f7b6081e754502f7d63b6587692cc83" +checksum = "455fc882e56f58228df2aee36b88a1340eafd707c76af2fa68cf94b37d461131" dependencies = [ "futures-util", "http", @@ -6877,9 +6877,9 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.22.0" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82030d038658974732103e623ba2e0abec03bbbe175b39c0a2fafbada60c5868" +checksum = "b75568f4f9696e3a47426e1985b548e1a9fcb13372a5e320372acaf04aca30d1" dependencies = [ "anyhow", "async-lock 3.3.0", @@ -6903,9 +6903,9 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.22.0" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36a06ef0de060005fddf772d54597bb6a8b0413da47dcffd304b0306147b9678" +checksum = "9e7a95e346f55df84fb167b7e06470e196e7d5b9488a21d69c5d9732043ba7ba" dependencies = [ "async-trait", "hyper", @@ -6923,22 +6923,22 @@ dependencies = [ [[package]] name = "jsonrpsee-proc-macros" -version = "0.22.0" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69fc56131589f82e57805f7338b87023db4aafef813555708b159787e34ad6bc" +checksum = "30ca066e73dd70294aebc5c2675d8ffae43be944af027c857ce0d4c51785f014" dependencies = [ "heck 0.4.1", "proc-macro-crate 3.0.0", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.53", ] [[package]] name = "jsonrpsee-server" -version = "0.22.0" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d85be77fe5b2a94589e3164fb780017f7aff7d646b49278c0d0346af16975c8e" +checksum = "0e29c1bd1f9bba83c864977c73404e505f74f730fa0db89dd490ec174e36d7f0" dependencies = [ "futures-util", "http", @@ -6960,9 +6960,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.22.0" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a48fdc1202eafc51c63e00406575e59493284ace8b8b61aa16f3a6db5d64f1a" +checksum = "3467fd35feeee179f71ab294516bdf3a81139e7aeebdd860e46897c12e1a3368" dependencies = [ "anyhow", "beef", @@ -6973,9 +6973,9 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-client" -version = "0.22.0" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5ce25d70a8e4d3cc574bbc3cad0137c326ad64b194793d5e7bbdd3fa4504181" +checksum = "68ca71e74983f624c0cb67828e480a981586074da8ad3a2f214c6a3f884edab9" dependencies = [ "http", "jsonrpsee-client-transport", diff --git a/substrate/client/rpc-spec-v2/Cargo.toml b/substrate/client/rpc-spec-v2/Cargo.toml index c62b3e789d3..937e5c6b626 100644 --- a/substrate/client/rpc-spec-v2/Cargo.toml +++ b/substrate/client/rpc-spec-v2/Cargo.toml @@ -44,6 +44,7 @@ futures-util = { version = "0.3.30", default-features = false } rand = "0.8.5" [dev-dependencies] +jsonrpsee = { version = "0.22", features = ["server", "ws-client"] } serde_json = { workspace = true, default-features = true } tokio = { version = "1.22.0", features = ["macros"] } substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } diff --git a/substrate/client/rpc-spec-v2/src/chain_head/api.rs b/substrate/client/rpc-spec-v2/src/chain_head/api.rs index 00000e1fb27..3851adac264 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/api.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/api.rs @@ -27,7 +27,7 @@ use crate::{ common::events::StorageQuery, }; use jsonrpsee::{proc_macros::rpc, server::ResponsePayload}; -use sp_rpc::list::ListOrValue; +pub use sp_rpc::list::ListOrValue; #[rpc(client, server)] pub trait ChainHeadApi { @@ -54,8 +54,8 @@ pub trait ChainHeadApi { /// # Unstable /// /// This method is unstable and subject to change in the future. - #[method(name = "chainHead_unstable_body", blocking)] - fn chain_head_unstable_body( + #[method(name = "chainHead_unstable_body", raw_method)] + async fn chain_head_unstable_body( &self, follow_subscription: String, hash: Hash, @@ -73,8 +73,8 @@ pub trait ChainHeadApi { /// # Unstable /// /// This method is unstable and subject to change in the future. - #[method(name = "chainHead_unstable_header", blocking)] - fn chain_head_unstable_header( + #[method(name = "chainHead_unstable_header", raw_method)] + async fn chain_head_unstable_header( &self, follow_subscription: String, hash: Hash, @@ -85,8 +85,8 @@ pub trait ChainHeadApi { /// # Unstable /// /// This method is unstable and subject to change in the future. - #[method(name = "chainHead_unstable_storage", blocking)] - fn chain_head_unstable_storage( + #[method(name = "chainHead_unstable_storage", raw_method)] + async fn chain_head_unstable_storage( &self, follow_subscription: String, hash: Hash, @@ -99,8 +99,8 @@ pub trait ChainHeadApi { /// # Unstable /// /// This method is unstable and subject to change in the future. - #[method(name = "chainHead_unstable_call", blocking)] - fn chain_head_unstable_call( + #[method(name = "chainHead_unstable_call", raw_method)] + async fn chain_head_unstable_call( &self, follow_subscription: String, hash: Hash, @@ -118,8 +118,8 @@ pub trait ChainHeadApi { /// # Unstable /// /// This method is unstable and subject to change in the future. - #[method(name = "chainHead_unstable_unpin", blocking)] - fn chain_head_unstable_unpin( + #[method(name = "chainHead_unstable_unpin", raw_method)] + async fn chain_head_unstable_unpin( &self, follow_subscription: String, hash_or_hashes: ListOrValue, @@ -131,8 +131,8 @@ pub trait ChainHeadApi { /// # Unstable /// /// This method is unstable and subject to change in the future. - #[method(name = "chainHead_unstable_continue", blocking)] - fn chain_head_unstable_continue( + #[method(name = "chainHead_unstable_continue", raw_method)] + async fn chain_head_unstable_continue( &self, follow_subscription: String, operation_id: String, @@ -145,8 +145,8 @@ pub trait ChainHeadApi { /// # Unstable /// /// This method is unstable and subject to change in the future. - #[method(name = "chainHead_unstable_stopOperation", blocking)] - fn chain_head_unstable_stop_operation( + #[method(name = "chainHead_unstable_stopOperation", raw_method)] + async fn chain_head_unstable_stop_operation( &self, follow_subscription: String, operation_id: String, diff --git a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs index 2bda22b4523..975abbca4b6 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs @@ -34,10 +34,10 @@ use crate::{ hex_string, SubscriptionTaskExecutor, }; use codec::Encode; -use futures::future::FutureExt; +use futures::{channel::oneshot, future::FutureExt}; use jsonrpsee::{ - core::async_trait, server::ResponsePayload, types::SubscriptionId, MethodResponseFuture, - PendingSubscriptionSink, SubscriptionSink, + core::async_trait, server::ResponsePayload, types::SubscriptionId, ConnectionDetails, + MethodResponseFuture, PendingSubscriptionSink, SubscriptionSink, }; use log::debug; use sc_client_api::{ @@ -65,6 +65,8 @@ pub struct ChainHeadConfig { /// The maximum number of items reported by the `chainHead_storage` before /// pagination is required. pub operation_max_storage_items: usize, + /// The maximum number of `chainHead_follow` subscriptions per connection. + pub max_follow_subscriptions_per_connection: usize, } /// Maximum pinned blocks across all connections. @@ -86,6 +88,9 @@ const MAX_ONGOING_OPERATIONS: usize = 16; /// before paginations is required. const MAX_STORAGE_ITER_ITEMS: usize = 5; +/// The maximum number of `chainHead_follow` subscriptions per connection. +const MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION: usize = 4; + impl Default for ChainHeadConfig { fn default() -> Self { ChainHeadConfig { @@ -93,6 +98,7 @@ impl Default for ChainHeadConfig { subscription_max_pinned_duration: MAX_PINNED_DURATION, subscription_max_ongoing_operations: MAX_ONGOING_OPERATIONS, operation_max_storage_items: MAX_STORAGE_ITER_ITEMS, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, } } } @@ -106,7 +112,7 @@ pub struct ChainHead, Block: BlockT, Client> { /// Executor to spawn subscriptions. executor: SubscriptionTaskExecutor, /// Keep track of the pinned blocks for each subscription. - subscriptions: Arc>, + subscriptions: SubscriptionManagement, /// The maximum number of items reported by the `chainHead_storage` before /// pagination is required. operation_max_storage_items: usize, @@ -126,12 +132,13 @@ impl, Block: BlockT, Client> ChainHead { client, backend: backend.clone(), executor, - subscriptions: Arc::new(SubscriptionManagement::new( + subscriptions: SubscriptionManagement::new( config.global_max_pinned_blocks, config.subscription_max_pinned_duration, config.subscription_max_ongoing_operations, + config.max_follow_subscriptions_per_connection, backend, - )), + ), operation_max_storage_items: config.operation_max_storage_items, _phantom: PhantomData, } @@ -182,12 +189,23 @@ where let client = self.client.clone(); let fut = async move { + // Ensure the current connection ID has enough space to accept a new subscription. + let connection_id = pending.connection_id(); + // The RAII `reserved_subscription` will clean up resources on drop: + // - free the reserved subscription for the connection ID. + // - remove the subscription ID from the subscription management. + let Some(mut reserved_subscription) = subscriptions.reserve_subscription(connection_id) + else { + pending.reject(ChainHeadRpcError::ReachedLimits).await; + return + }; + let Ok(sink) = pending.accept().await else { return }; let sub_id = read_subscription_id_as_string(&sink); - // Keep track of the subscription. - let Some(sub_data) = subscriptions.insert_subscription(sub_id.clone(), with_runtime) + let Some(sub_data) = + reserved_subscription.insert_subscription(sub_id.clone(), with_runtime) else { // Inserting the subscription can only fail if the JsonRPSee // generated a duplicate subscription ID. @@ -201,91 +219,117 @@ where let mut chain_head_follow = ChainHeadFollower::new( client, backend, - subscriptions.clone(), + subscriptions, with_runtime, sub_id.clone(), ); chain_head_follow.generate_events(sink, sub_data).await; - subscriptions.remove_subscription(&sub_id); debug!(target: LOG_TARGET, "[follow][id={:?}] Subscription removed", sub_id); }; self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); } - fn chain_head_unstable_body( + async fn chain_head_unstable_body( &self, + connection_details: ConnectionDetails, follow_subscription: String, hash: Block::Hash, ) -> ResponsePayload<'static, MethodResponse> { - let mut block_guard = match self.subscriptions.lock_block(&follow_subscription, hash, 1) { - Ok(block) => block, - Err(SubscriptionManagementError::SubscriptionAbsent) | - Err(SubscriptionManagementError::ExceededLimits) => - return ResponsePayload::success(MethodResponse::LimitReached), - Err(SubscriptionManagementError::BlockHashAbsent) => { - // Block is not part of the subscription. - return ResponsePayload::error(ChainHeadRpcError::InvalidBlock); - }, - Err(_) => return ResponsePayload::error(ChainHeadRpcError::InvalidBlock), - }; + if !self + .subscriptions + .contains_subscription(connection_details.id(), &follow_subscription) + { + // The spec says to return `LimitReached` if the follow subscription is invalid or + // stale. + return ResponsePayload::success(MethodResponse::LimitReached); + } - let operation_id = block_guard.operation().operation_id(); + let client = self.client.clone(); + let subscriptions = self.subscriptions.clone(); + let executor = self.executor.clone(); + + let result = spawn_blocking(&self.executor, async move { + let mut block_guard = match subscriptions.lock_block(&follow_subscription, hash, 1) { + Ok(block) => block, + Err(SubscriptionManagementError::SubscriptionAbsent) | + Err(SubscriptionManagementError::ExceededLimits) => + return ResponsePayload::success(MethodResponse::LimitReached), + Err(SubscriptionManagementError::BlockHashAbsent) => { + // Block is not part of the subscription. + return ResponsePayload::error(ChainHeadRpcError::InvalidBlock); + }, + Err(_) => return ResponsePayload::error(ChainHeadRpcError::InvalidBlock), + }; - let event = match self.client.block(hash) { - Ok(Some(signed_block)) => { - let extrinsics = signed_block - .block - .extrinsics() - .iter() - .map(|extrinsic| hex_string(&extrinsic.encode())) - .collect(); - FollowEvent::::OperationBodyDone(OperationBodyDone { + let operation_id = block_guard.operation().operation_id(); + + let event = match client.block(hash) { + Ok(Some(signed_block)) => { + let extrinsics = signed_block + .block + .extrinsics() + .iter() + .map(|extrinsic| hex_string(&extrinsic.encode())) + .collect(); + FollowEvent::::OperationBodyDone(OperationBodyDone { + operation_id: operation_id.clone(), + value: extrinsics, + }) + }, + Ok(None) => { + // The block's body was pruned. This subscription ID has become invalid. + debug!( + target: LOG_TARGET, + "[body][id={:?}] Stopping subscription because hash={:?} was pruned", + &follow_subscription, + hash + ); + subscriptions.remove_subscription(&follow_subscription); + return ResponsePayload::error(ChainHeadRpcError::InvalidBlock) + }, + Err(error) => FollowEvent::::OperationError(OperationError { operation_id: operation_id.clone(), - value: extrinsics, - }) - }, - Ok(None) => { - // The block's body was pruned. This subscription ID has become invalid. - debug!( - target: LOG_TARGET, - "[body][id={:?}] Stopping subscription because hash={:?} was pruned", - &follow_subscription, - hash - ); - self.subscriptions.remove_subscription(&follow_subscription); - return ResponsePayload::error(ChainHeadRpcError::InvalidBlock) - }, - Err(error) => FollowEvent::::OperationError(OperationError { - operation_id: operation_id.clone(), - error: error.to_string(), - }), - }; + error: error.to_string(), + }), + }; - let (rp, rp_fut) = method_started_response(operation_id, None); + let (rp, rp_fut) = method_started_response(operation_id, None); + let fut = async move { + // Wait for the server to send out the response and if it produces an error no event + // should be generated. + if rp_fut.await.is_err() { + return; + } - let fut = async move { - // Events should only by generated - // if the response was successfully propagated. - if rp_fut.await.is_err() { - return; - } - let _ = block_guard.response_sender().unbounded_send(event); - }; + let _ = block_guard.response_sender().unbounded_send(event); + }; + executor.spawn_blocking("substrate-rpc-subscription", Some("rpc"), fut.boxed()); - self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); + rp + }); - rp + result + .await + .unwrap_or_else(|_| ResponsePayload::success(MethodResponse::LimitReached)) } - fn chain_head_unstable_header( + async fn chain_head_unstable_header( &self, + connection_details: ConnectionDetails, follow_subscription: String, hash: Block::Hash, ) -> Result, ChainHeadRpcError> { - let _block_guard = match self.subscriptions.lock_block(&follow_subscription, hash, 1) { + if !self + .subscriptions + .contains_subscription(connection_details.id(), &follow_subscription) + { + return Ok(None); + } + + let block_guard = match self.subscriptions.lock_block(&follow_subscription, hash, 1) { Ok(block) => block, Err(SubscriptionManagementError::SubscriptionAbsent) | Err(SubscriptionManagementError::ExceededLimits) => return Ok(None), @@ -296,19 +340,35 @@ where Err(_) => return Err(ChainHeadRpcError::InvalidBlock.into()), }; - self.client - .header(hash) - .map(|opt_header| opt_header.map(|h| hex_string(&h.encode()))) - .map_err(|err| ChainHeadRpcError::InternalError(err.to_string())) + let client = self.client.clone(); + let result = spawn_blocking(&self.executor, async move { + let _block_guard = block_guard; + + client + .header(hash) + .map(|opt_header| opt_header.map(|h| hex_string(&h.encode()))) + .map_err(|err| ChainHeadRpcError::InternalError(err.to_string())) + }); + result.await.unwrap_or_else(|_| Ok(None)) } - fn chain_head_unstable_storage( + async fn chain_head_unstable_storage( &self, + connection_details: ConnectionDetails, follow_subscription: String, hash: Block::Hash, items: Vec>, child_trie: Option, ) -> ResponsePayload<'static, MethodResponse> { + if !self + .subscriptions + .contains_subscription(connection_details.id(), &follow_subscription) + { + // The spec says to return `LimitReached` if the follow subscription is invalid or + // stale. + return ResponsePayload::success(MethodResponse::LimitReached); + } + // Gain control over parameter parsing and returned error. let items = match items .into_iter() @@ -357,25 +417,25 @@ where let mut items = items; items.truncate(num_operations); - let (rp, rp_is_success) = method_started_response(operation_id, Some(discarded)); - + let (rp, rp_fut) = method_started_response(operation_id, Some(discarded)); let fut = async move { - // Events should only by generated - // if the response was successfully propagated. - if rp_is_success.await.is_err() { + // Wait for the server to send out the response and if it produces an error no event + // should be generated. + if rp_fut.await.is_err() { return; } + storage_client.generate_events(block_guard, hash, items, child_trie).await; }; - self.executor .spawn_blocking("substrate-rpc-subscription", Some("rpc"), fut.boxed()); rp } - fn chain_head_unstable_call( + async fn chain_head_unstable_call( &self, + connection_details: ConnectionDetails, follow_subscription: String, hash: Block::Hash, function: String, @@ -386,6 +446,15 @@ where Err(err) => return ResponsePayload::error(err), }; + if !self + .subscriptions + .contains_subscription(connection_details.id(), &follow_subscription) + { + // The spec says to return `LimitReached` if the follow subscription is invalid or + // stale. + return ResponsePayload::success(MethodResponse::LimitReached); + } + let mut block_guard = match self.subscriptions.lock_block(&follow_subscription, hash, 1) { Ok(block) => block, Err(SubscriptionManagementError::SubscriptionAbsent) | @@ -408,44 +477,53 @@ where } let operation_id = block_guard.operation().operation_id(); - let event = self - .client - .executor() - .call(hash, &function, &call_parameters, CallContext::Offchain) - .map(|result| { - FollowEvent::::OperationCallDone(OperationCallDone { - operation_id: operation_id.clone(), - output: hex_string(&result), - }) - }) - .unwrap_or_else(|error| { - FollowEvent::::OperationError(OperationError { - operation_id: operation_id.clone(), - error: error.to_string(), - }) - }); - - let (rp, rp_fut) = method_started_response(operation_id, None); + let client = self.client.clone(); + let (rp, rp_fut) = method_started_response(operation_id.clone(), None); let fut = async move { - // Events should only by generated - // if the response was successfully propagated. + // Wait for the server to send out the response and if it produces an error no event + // should be generated. if rp_fut.await.is_err() { - return; + return } + + let event = client + .executor() + .call(hash, &function, &call_parameters, CallContext::Offchain) + .map(|result| { + FollowEvent::::OperationCallDone(OperationCallDone { + operation_id: operation_id.clone(), + output: hex_string(&result), + }) + }) + .unwrap_or_else(|error| { + FollowEvent::::OperationError(OperationError { + operation_id: operation_id.clone(), + error: error.to_string(), + }) + }); + let _ = block_guard.response_sender().unbounded_send(event); }; - - self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); + self.executor + .spawn_blocking("substrate-rpc-subscription", Some("rpc"), fut.boxed()); rp } - fn chain_head_unstable_unpin( + async fn chain_head_unstable_unpin( &self, + connection_details: ConnectionDetails, follow_subscription: String, hash_or_hashes: ListOrValue, ) -> Result<(), ChainHeadRpcError> { + if !self + .subscriptions + .contains_subscription(connection_details.id(), &follow_subscription) + { + return Ok(()); + } + let result = match hash_or_hashes { ListOrValue::Value(hash) => self.subscriptions.unpin_blocks(&follow_subscription, [hash]), @@ -469,11 +547,19 @@ where } } - fn chain_head_unstable_continue( + async fn chain_head_unstable_continue( &self, + connection_details: ConnectionDetails, follow_subscription: String, operation_id: String, ) -> Result<(), ChainHeadRpcError> { + if !self + .subscriptions + .contains_subscription(connection_details.id(), &follow_subscription) + { + return Ok(()) + } + let Some(operation) = self.subscriptions.get_operation(&follow_subscription, &operation_id) else { return Ok(()) @@ -487,11 +573,19 @@ where } } - fn chain_head_unstable_stop_operation( + async fn chain_head_unstable_stop_operation( &self, + connection_details: ConnectionDetails, follow_subscription: String, operation_id: String, ) -> Result<(), ChainHeadRpcError> { + if !self + .subscriptions + .contains_subscription(connection_details.id(), &follow_subscription) + { + return Ok(()) + } + let Some(operation) = self.subscriptions.get_operation(&follow_subscription, &operation_id) else { return Ok(()) @@ -510,3 +604,26 @@ fn method_started_response( let rp = MethodResponse::Started(MethodResponseStarted { operation_id, discarded_items }); ResponsePayload::success(rp).notify_on_completion() } + +/// Spawn a blocking future on the provided executor and return the result on a oneshot channel. +/// +/// This is a wrapper to extract the result of a `executor.spawn_blocking` future. +fn spawn_blocking( + executor: &SubscriptionTaskExecutor, + fut: impl std::future::Future + Send + 'static, +) -> oneshot::Receiver +where + R: Send + 'static, +{ + let (tx, rx) = oneshot::channel(); + + let blocking_fut = async move { + let result = fut.await; + // Send the result back on the channel. + let _ = tx.send(result); + }; + + executor.spawn_blocking("substrate-rpc-subscription", Some("rpc"), blocking_fut.boxed()); + + rx +} diff --git a/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs b/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs index afa99f3aa16..90cc62a36fa 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs @@ -60,7 +60,7 @@ pub struct ChainHeadFollower, Block: BlockT, Client> { /// Backend of the chain. backend: Arc, /// Subscriptions handle. - sub_handle: Arc>, + sub_handle: SubscriptionManagement, /// Subscription was started with the runtime updates flag. with_runtime: bool, /// Subscription ID. @@ -74,7 +74,7 @@ impl, Block: BlockT, Client> ChainHeadFollower, backend: Arc, - sub_handle: Arc>, + sub_handle: SubscriptionManagement, with_runtime: bool, sub_id: String, ) -> Self { @@ -546,7 +546,12 @@ where EventStream: Stream> + Unpin, { let mut stream_item = stream.next(); - let mut stop_event = rx_stop; + + // The stop event can be triggered by the chainHead logic when the pinned + // block guarantee cannot be hold. Or when the client is disconnected. + let connection_closed = sink.closed(); + tokio::pin!(connection_closed); + let mut stop_event = futures_util::future::select(rx_stop, connection_closed); while let Either::Left((Some(event), next_stop_event)) = futures_util::future::select(stream_item, stop_event).await @@ -594,8 +599,10 @@ where stop_event = next_stop_event; } - // If we got here either the substrate streams have closed - // or the `Stop` receiver was triggered. + // If we got here either: + // - the substrate streams have closed + // - the `Stop` receiver was triggered internally (cannot hold the pinned block guarantee) + // - the client disconnected. let msg = to_sub_message(&sink, &FollowEvent::::Stop); let _ = sink.send(msg).await; } diff --git a/substrate/client/rpc-spec-v2/src/chain_head/error.rs b/substrate/client/rpc-spec-v2/src/chain_head/error.rs index 8c50e445aa0..35604db0660 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/error.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/error.rs @@ -23,6 +23,9 @@ use jsonrpsee::types::error::ErrorObject; /// ChainHead RPC errors. #[derive(Debug, thiserror::Error)] pub enum Error { + /// Maximum number of chainHead_follow has been reached. + #[error("Maximum number of chainHead_follow has been reached")] + ReachedLimits, /// The provided block hash is invalid. #[error("Invalid block hash")] InvalidBlock, @@ -46,6 +49,8 @@ pub enum Error { /// Errors for `chainHead` RPC module, as defined in /// . pub mod rpc_spec_v2 { + /// Maximum number of chainHead_follow has been reached. + pub const REACHED_LIMITS: i32 = -32800; /// The provided block hash is invalid. pub const INVALID_BLOCK_ERROR: i32 = -32801; /// The follow subscription was started with `withRuntime` set to `false`. @@ -70,6 +75,8 @@ impl From for ErrorObject<'static> { let msg = e.to_string(); match e { + Error::ReachedLimits => + ErrorObject::owned(rpc_spec_v2::REACHED_LIMITS, msg, None::<()>), Error::InvalidBlock => ErrorObject::owned(rpc_spec_v2::INVALID_BLOCK_ERROR, msg, None::<()>), Error::InvalidRuntimeCall(_) => diff --git a/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs b/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs index d2879679501..1ebee3c80fc 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs @@ -1455,4 +1455,57 @@ mod tests { let permit_three = ops.reserve_at_most(1).unwrap(); assert_eq!(permit_three.num_ops, 1); } + + #[test] + fn reserved_subscription_cleans_resources() { + let builder = TestClientBuilder::new(); + let backend = builder.backend(); + let subs = Arc::new(parking_lot::RwLock::new(SubscriptionsInner::new( + 10, + Duration::from_secs(10), + MAX_OPERATIONS_PER_SUB, + backend, + ))); + + // Maximum 2 subscriptions per connection. + let rpc_connections = crate::common::connections::RpcConnections::new(2); + + let subscription_management = + crate::chain_head::subscription::SubscriptionManagement::_from_inner( + subs.clone(), + rpc_connections.clone(), + ); + + let reserved_sub_first = subscription_management.reserve_subscription(1).unwrap(); + let mut reserved_sub_second = subscription_management.reserve_subscription(1).unwrap(); + // Subscriptions reserved but not yet populated. + assert_eq!(subs.read().subs.len(), 0); + + // Cannot reserve anymore. + assert!(subscription_management.reserve_subscription(1).is_none()); + // Drop the first subscription. + drop(reserved_sub_first); + // Space is freed-up for the rpc connections. + let mut reserved_sub_first = subscription_management.reserve_subscription(1).unwrap(); + + // Insert subscriptions. + let _sub_data_first = + reserved_sub_first.insert_subscription("sub1".to_string(), true).unwrap(); + let _sub_data_second = + reserved_sub_second.insert_subscription("sub2".to_string(), true).unwrap(); + // Check we have 2 subscriptions under management. + assert_eq!(subs.read().subs.len(), 2); + + // Drop first reserved subscription. + drop(reserved_sub_first); + // Check that the subscription is removed. + assert_eq!(subs.read().subs.len(), 1); + // Space is freed-up for the rpc connections. + let reserved_sub_first = subscription_management.reserve_subscription(1).unwrap(); + + // Drop all subscriptions. + drop(reserved_sub_first); + drop(reserved_sub_second); + assert_eq!(subs.read().subs.len(), 0); + } } diff --git a/substrate/client/rpc-spec-v2/src/chain_head/subscription/mod.rs b/substrate/client/rpc-spec-v2/src/chain_head/subscription/mod.rs index c830e662da2..5b016af1aa4 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/subscription/mod.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/subscription/mod.rs @@ -16,6 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use jsonrpsee::ConnectionId; use parking_lot::RwLock; use sc_client_api::Backend; use sp_runtime::traits::Block as BlockT; @@ -24,6 +25,11 @@ use std::{sync::Arc, time::Duration}; mod error; mod inner; +use crate::{ + chain_head::chain_head::LOG_TARGET, + common::connections::{RegisteredConnection, ReservedConnection, RpcConnections}, +}; + use self::inner::SubscriptionsInner; pub use self::inner::OperationState; @@ -34,7 +40,22 @@ pub use inner::{BlockGuard, InsertedSubscriptionData}; pub struct SubscriptionManagement> { /// Manage subscription by mapping the subscription ID /// to a set of block hashes. - inner: RwLock>, + inner: Arc>>, + + /// Ensures that chainHead methods can be called from a single connection context. + /// + /// For example, `chainHead_storage` cannot be called with a subscription ID that + /// was obtained from a different connection. + rpc_connections: RpcConnections, +} + +impl> Clone for SubscriptionManagement { + fn clone(&self) -> Self { + SubscriptionManagement { + inner: self.inner.clone(), + rpc_connections: self.rpc_connections.clone(), + } + } } impl> SubscriptionManagement { @@ -43,30 +64,55 @@ impl> SubscriptionManagement { global_max_pinned_blocks: usize, local_max_pin_duration: Duration, max_ongoing_operations: usize, + max_follow_subscriptions_per_connection: usize, backend: Arc, ) -> Self { SubscriptionManagement { - inner: RwLock::new(SubscriptionsInner::new( + inner: Arc::new(RwLock::new(SubscriptionsInner::new( global_max_pinned_blocks, local_max_pin_duration, max_ongoing_operations, backend, - )), + ))), + rpc_connections: RpcConnections::new(max_follow_subscriptions_per_connection), } } - /// Insert a new subscription ID. + /// Create a new instance from the inner state. /// - /// If the subscription was not previously inserted, returns the receiver that is - /// triggered upon the "Stop" event. Otherwise, if the subscription ID was already - /// inserted returns none. - pub fn insert_subscription( + /// # Note + /// + /// Used for testing. + #[cfg(test)] + pub(crate) fn _from_inner( + inner: Arc>>, + rpc_connections: RpcConnections, + ) -> Self { + SubscriptionManagement { inner, rpc_connections } + } + + /// Reserve space for a subscriptions. + /// + /// Fails if the connection ID is has reached the maximum number of active subscriptions. + pub fn reserve_subscription( &self, - sub_id: String, - runtime_updates: bool, - ) -> Option> { - let mut inner = self.inner.write(); - inner.insert_subscription(sub_id, runtime_updates) + connection_id: ConnectionId, + ) -> Option> { + let reserved_token = self.rpc_connections.reserve_space(connection_id)?; + + Some(ReservedSubscription { + state: ConnectionState::Reserved(reserved_token), + inner: self.inner.clone(), + }) + } + + /// Check if the given connection contains the given subscription. + pub fn contains_subscription( + &self, + connection_id: ConnectionId, + subscription_id: &str, + ) -> bool { + self.rpc_connections.contains_identifier(connection_id, subscription_id) } /// Remove the subscription ID with associated pinned blocks. @@ -136,3 +182,63 @@ impl> SubscriptionManagement { inner.get_operation(sub_id, operation_id) } } + +/// The state of the connection. +/// +/// The state starts in a [`ConnectionState::Reserved`] state and then transitions to +/// [`ConnectionState::Registered`] when the subscription is inserted. +enum ConnectionState { + Reserved(ReservedConnection), + Registered { _unregister_on_drop: RegisteredConnection, sub_id: String }, + Empty, +} + +/// RAII wrapper that removes the subscription from internal mappings and +/// gives back the reserved space for the connection. +pub struct ReservedSubscription> { + state: ConnectionState, + inner: Arc>>, +} + +impl> ReservedSubscription { + /// Insert a new subscription ID. + /// + /// If the subscription was not previously inserted, returns the receiver that is + /// triggered upon the "Stop" event. Otherwise, if the subscription ID was already + /// inserted returns none. + /// + /// # Note + /// + /// This method should be called only once. + pub fn insert_subscription( + &mut self, + sub_id: String, + runtime_updates: bool, + ) -> Option> { + match std::mem::replace(&mut self.state, ConnectionState::Empty) { + ConnectionState::Reserved(reserved) => { + let registered_token = reserved.register(sub_id.clone())?; + self.state = ConnectionState::Registered { + _unregister_on_drop: registered_token, + sub_id: sub_id.clone(), + }; + + let mut inner = self.inner.write(); + inner.insert_subscription(sub_id, runtime_updates) + }, + // Cannot insert multiple subscriptions into one single reserved space. + ConnectionState::Registered { .. } | ConnectionState::Empty => { + log::error!(target: LOG_TARGET, "Called insert_subscription on a connection that is not reserved"); + None + }, + } + } +} + +impl> Drop for ReservedSubscription { + fn drop(&mut self) { + if let ConnectionState::Registered { sub_id, .. } = &self.state { + self.inner.write().remove_subscription(sub_id); + } + } +} diff --git a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs index 30152efb5b6..c3f10a201c5 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use crate::{ - chain_head::{event::MethodResponse, test_utils::ChainHeadMockClient}, + chain_head::{api::ChainHeadApiClient, event::MethodResponse, test_utils::ChainHeadMockClient}, common::events::{StorageQuery, StorageQueryType, StorageResultType}, hex_string, }; @@ -27,8 +27,12 @@ use assert_matches::assert_matches; use codec::{Decode, Encode}; use futures::Future; use jsonrpsee::{ - core::server::Subscription as RpcSubscription, rpc_params, MethodsError as Error, RpcModule, + core::{ + client::Subscription as RpcClientSubscription, server::Subscription as RpcSubscription, + }, + rpc_params, MethodsError as Error, RpcModule, }; + use sc_block_builder::BlockBuilderBuilder; use sc_client_api::ChildInfo; use sc_service::client::new_in_mem; @@ -59,6 +63,8 @@ const MAX_PINNED_BLOCKS: usize = 32; const MAX_PINNED_SECS: u64 = 60; const MAX_OPERATIONS: usize = 16; const MAX_PAGINATION_LIMIT: usize = 5; +const MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION: usize = 4; + const INVALID_HASH: [u8; 32] = [1; 32]; const KEY: &[u8] = b":mock"; const VALUE: &[u8] = b"hello world"; @@ -66,6 +72,35 @@ const CHILD_STORAGE_KEY: &[u8] = b"child"; const CHILD_VALUE: &[u8] = b"child value"; const DOES_NOT_PRODUCE_EVENTS_SECONDS: u64 = 10; +/// Start an RPC server with the chainHead module. +pub async fn run_server() -> std::net::SocketAddr { + let builder = TestClientBuilder::new(); + let backend = builder.backend(); + let client = Arc::new(builder.build()); + + let api = ChainHead::new( + client, + backend, + Arc::new(TaskExecutor::default()), + ChainHeadConfig { + global_max_pinned_blocks: MAX_PINNED_BLOCKS, + subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), + subscription_max_ongoing_operations: MAX_OPERATIONS, + operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: 1, + }, + ) + .into_rpc(); + + let server = jsonrpsee::server::ServerBuilder::default().build("127.0.0.1:0").await.unwrap(); + + let addr = server.local_addr().unwrap(); + let handle = server.start(api); + + tokio::spawn(handle.stopped()); + addr +} + async fn get_next_event(sub: &mut RpcSubscription) -> T { let (event, _sub_id) = tokio::time::timeout(std::time::Duration::from_secs(60), sub.next()) .await @@ -113,6 +148,7 @@ async fn setup_api() -> ( subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -163,6 +199,7 @@ async fn follow_subscription_produces_blocks() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -231,6 +268,7 @@ async fn follow_with_runtime() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -543,6 +581,7 @@ async fn call_runtime_without_flag() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -1201,6 +1240,7 @@ async fn separate_operation_ids_for_subscriptions() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -1289,6 +1329,7 @@ async fn follow_generates_initial_blocks() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -1444,6 +1485,7 @@ async fn follow_exceeding_pinned_blocks() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -1520,6 +1562,7 @@ async fn follow_with_unpin() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -1631,6 +1674,7 @@ async fn unpin_duplicate_hashes() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -1733,6 +1777,7 @@ async fn follow_with_multiple_unpin_hashes() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -1886,6 +1931,7 @@ async fn follow_prune_best_block() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -2071,6 +2117,7 @@ async fn follow_forks_pruned_block() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -2230,6 +2277,7 @@ async fn follow_report_multiple_pruned_block() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -2475,6 +2523,7 @@ async fn pin_block_references() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -2612,6 +2661,7 @@ async fn follow_finalized_before_new_block() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -2726,6 +2776,7 @@ async fn ensure_operation_limits_works() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: 1, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -2830,6 +2881,7 @@ async fn check_continue_operation() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: 1, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -3012,6 +3064,7 @@ async fn stop_storage_operation() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: 1, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -3297,3 +3350,176 @@ async fn storage_closest_merkle_value() { merkle_values_rhs.get(&hex_string(b":AAAA")).unwrap() ); } + +#[tokio::test] +async fn chain_head_single_connection_context() { + let server_addr = run_server().await; + let server_url = format!("ws://{}", server_addr); + let client = jsonrpsee::ws_client::WsClientBuilder::default() + .build(&server_url) + .await + .unwrap(); + // Calls cannot be made from a different connection context. + let second_client = jsonrpsee::ws_client::WsClientBuilder::default() + .build(&server_url) + .await + .unwrap(); + + let mut sub: RpcClientSubscription> = + ChainHeadApiClient::::chain_head_unstable_follow(&client, true) + .await + .unwrap(); + + let event = tokio::time::timeout(std::time::Duration::from_secs(60), sub.next()) + .await + .unwrap() + .unwrap() + .unwrap(); + let finalized_hash = match event { + FollowEvent::Initialized(init) => init.finalized_block_hashes.into_iter().last().unwrap(), + _ => panic!("Expected FollowEvent::Initialized"), + }; + + let first_sub_id = match sub.kind() { + jsonrpsee::core::client::SubscriptionKind::Subscription(id) => match id { + jsonrpsee::types::SubscriptionId::Num(num) => num.to_string(), + jsonrpsee::types::SubscriptionId::Str(s) => s.to_string(), + }, + _ => panic!("Unexpected subscription ID"), + }; + + // Trying to unpin from a different connection will have no effect. + let _response = ChainHeadApiClient::::chain_head_unstable_unpin( + &second_client, + first_sub_id.clone(), + crate::chain_head::api::ListOrValue::Value(finalized_hash.clone()), + ) + .await + .unwrap(); + + // Body can still be fetched from the first subscription. + let response: MethodResponse = ChainHeadApiClient::::chain_head_unstable_body( + &client, + first_sub_id.clone(), + finalized_hash.clone(), + ) + .await + .unwrap(); + assert_matches!(response, MethodResponse::Started(_started)); + + // Cannot make a call from a different connection context. + let response: MethodResponse = ChainHeadApiClient::::chain_head_unstable_body( + &second_client, + first_sub_id.clone(), + finalized_hash.clone(), + ) + .await + .unwrap(); + assert_matches!(response, MethodResponse::LimitReached); + + let response: Option = ChainHeadApiClient::::chain_head_unstable_header( + &client, + first_sub_id.clone(), + finalized_hash.clone(), + ) + .await + .unwrap(); + assert!(response.is_some()); + // Cannot make a call from a different connection context. + let response: Option = ChainHeadApiClient::::chain_head_unstable_header( + &second_client, + first_sub_id.clone(), + finalized_hash.clone(), + ) + .await + .unwrap(); + assert!(response.is_none()); + + let key = hex_string(&KEY); + let response: MethodResponse = ChainHeadApiClient::::chain_head_unstable_storage( + &client, + first_sub_id.clone(), + finalized_hash.clone(), + vec![StorageQuery { key: key.clone(), query_type: StorageQueryType::Hash }], + None, + ) + .await + .unwrap(); + assert_matches!(response, MethodResponse::Started(_started)); + // Cannot make a call from a different connection context. + let response: MethodResponse = ChainHeadApiClient::::chain_head_unstable_storage( + &second_client, + first_sub_id.clone(), + finalized_hash.clone(), + vec![StorageQuery { key: key.clone(), query_type: StorageQueryType::Hash }], + None, + ) + .await + .unwrap(); + assert_matches!(response, MethodResponse::LimitReached); + + let alice_id = AccountKeyring::Alice.to_account_id(); + // Hex encoded scale encoded bytes representing the call parameters. + let call_parameters = hex_string(&alice_id.encode()); + let response: MethodResponse = ChainHeadApiClient::::chain_head_unstable_call( + &client, + first_sub_id.clone(), + finalized_hash.clone(), + "AccountNonceApi_account_nonce".into(), + call_parameters.clone(), + ) + .await + .unwrap(); + assert_matches!(response, MethodResponse::Started(_started)); + // Cannot make a call from a different connection context. + let response: MethodResponse = ChainHeadApiClient::::chain_head_unstable_call( + &second_client, + first_sub_id.clone(), + finalized_hash.clone(), + "AccountNonceApi_account_nonce".into(), + call_parameters.clone(), + ) + .await + .unwrap(); + assert_matches!(response, MethodResponse::LimitReached); +} + +#[tokio::test] +async fn chain_head_limit_reached() { + let builder = TestClientBuilder::new(); + let backend = builder.backend(); + let client = Arc::new(builder.build()); + + // Maximum of 1 chainHead_follow subscription. + let api = ChainHead::new( + client.clone(), + backend, + Arc::new(TaskExecutor::default()), + ChainHeadConfig { + global_max_pinned_blocks: MAX_PINNED_BLOCKS, + subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), + subscription_max_ongoing_operations: MAX_OPERATIONS, + operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: 1, + }, + ) + .into_rpc(); + + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + // Initialized must always be reported first. + let _event: FollowEvent = get_next_event(&mut sub).await; + + let error = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap_err(); + assert!(error + .to_string() + .contains("Maximum number of chainHead_follow has been reached")); + + // After dropping the subscription, other subscriptions are allowed to be created. + drop(sub); + // Ensure the `chainHead_unfollow` is propagated to the server. + tokio::time::sleep(std::time::Duration::from_secs(5)).await; + + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + // Initialized must always be reported first. + let _event: FollowEvent = get_next_event(&mut sub).await; +} diff --git a/substrate/client/rpc-spec-v2/src/common/connections.rs b/substrate/client/rpc-spec-v2/src/common/connections.rs new file mode 100644 index 00000000000..c16a80bf49d --- /dev/null +++ b/substrate/client/rpc-spec-v2/src/common/connections.rs @@ -0,0 +1,262 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use jsonrpsee::ConnectionId; +use parking_lot::Mutex; +use std::{ + collections::{HashMap, HashSet}, + sync::Arc, +}; + +/// Connection state which keeps track whether a connection exist and +/// the number of concurrent operations. +#[derive(Default, Clone)] +pub struct RpcConnections { + /// The number of identifiers that can be registered for each connection. + /// + /// # Example + /// + /// This is used to limit how many `chainHead_follow` subscriptions are active at one time. + capacity: usize, + /// Map the connecton ID to a set of identifiers. + data: Arc>>, +} + +#[derive(Default)] +struct ConnectionData { + /// The total number of identifiers for the given connection. + /// + /// An identifier for a connection might be: + /// - the subscription ID for chainHead_follow + /// - the operation ID for the transactionBroadcast API + /// - or simply how many times the transaction API has been called. + /// + /// # Note + /// + /// Because a pending subscription sink does not expose the future subscription ID, + /// we cannot register a subscription ID before the pending subscription is accepted. + /// This variable ensures that we have enough capacity to register an identifier, after + /// the subscription is accepted. Otherwise, a jsonrpc error object should be returned. + num_identifiers: usize, + /// Active registered identifiers for the given connection. + /// + /// # Note + /// + /// For chainHead, this represents the subscription ID. + /// For transactionBroadcast, this represents the operation ID. + /// For transaction, this is empty and the number of active calls is tracked by + /// [`Self::num_identifiers`]. + identifiers: HashSet, +} + +impl RpcConnections { + /// Constructs a new instance of [`RpcConnections`]. + pub fn new(capacity: usize) -> Self { + RpcConnections { capacity, data: Default::default() } + } + + /// Reserve space for a new connection identifier. + /// + /// If the number of active identifiers for the given connection exceeds the capacity, + /// returns None. + pub fn reserve_space(&self, connection_id: ConnectionId) -> Option { + let mut data = self.data.lock(); + + let entry = data.entry(connection_id).or_insert_with(ConnectionData::default); + if entry.num_identifiers >= self.capacity { + return None; + } + entry.num_identifiers = entry.num_identifiers.saturating_add(1); + + Some(ReservedConnection { connection_id, rpc_connections: Some(self.clone()) }) + } + + /// Gives back the reserved space before the connection identifier is registered. + /// + /// # Note + /// + /// This may happen if the pending subscription cannot be accepted (unlikely). + fn unreserve_space(&self, connection_id: ConnectionId) { + let mut data = self.data.lock(); + + let entry = data.entry(connection_id).or_insert_with(ConnectionData::default); + entry.num_identifiers = entry.num_identifiers.saturating_sub(1); + + if entry.num_identifiers == 0 { + data.remove(&connection_id); + } + } + + /// Register an identifier for the given connection. + /// + /// Users must call [`Self::reserve_space`] before calling this method to ensure enough + /// space is available. + /// + /// Returns true if the identifier was inserted successfully, false if the identifier was + /// already inserted or reached capacity. + fn register_identifier(&self, connection_id: ConnectionId, identifier: String) -> bool { + let mut data = self.data.lock(); + + let entry = data.entry(connection_id).or_insert_with(ConnectionData::default); + // Should be already checked `Self::reserve_space`. + if entry.identifiers.len() >= self.capacity { + return false; + } + + entry.identifiers.insert(identifier) + } + + /// Unregister an identifier for the given connection. + fn unregister_identifier(&self, connection_id: ConnectionId, identifier: &str) { + let mut data = self.data.lock(); + if let Some(connection_data) = data.get_mut(&connection_id) { + connection_data.identifiers.remove(identifier); + connection_data.num_identifiers = connection_data.num_identifiers.saturating_sub(1); + + if connection_data.num_identifiers == 0 { + data.remove(&connection_id); + } + } + } + + /// Check if the given connection contains the given identifier. + pub fn contains_identifier(&self, connection_id: ConnectionId, identifier: &str) -> bool { + let data = self.data.lock(); + data.get(&connection_id) + .map(|connection_data| connection_data.identifiers.contains(identifier)) + .unwrap_or(false) + } +} + +/// RAII wrapper that ensures the reserved space is given back if the object is +/// dropped before the identifier is registered. +pub struct ReservedConnection { + connection_id: ConnectionId, + rpc_connections: Option, +} + +impl ReservedConnection { + /// Register the identifier for the given connection. + pub fn register(mut self, identifier: String) -> Option { + let rpc_connections = self.rpc_connections.take()?; + + if rpc_connections.register_identifier(self.connection_id, identifier.clone()) { + Some(RegisteredConnection { + connection_id: self.connection_id, + identifier, + rpc_connections, + }) + } else { + None + } + } +} + +impl Drop for ReservedConnection { + fn drop(&mut self) { + if let Some(rpc_connections) = self.rpc_connections.take() { + rpc_connections.unreserve_space(self.connection_id); + } + } +} + +/// RAII wrapper that ensures the identifier is unregistered if the object is dropped. +pub struct RegisteredConnection { + connection_id: ConnectionId, + identifier: String, + rpc_connections: RpcConnections, +} + +impl Drop for RegisteredConnection { + fn drop(&mut self) { + self.rpc_connections.unregister_identifier(self.connection_id, &self.identifier); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn reserve_space() { + let rpc_connections = RpcConnections::new(2); + let reserved = rpc_connections.reserve_space(1); + assert!(reserved.is_some()); + assert_eq!(1, rpc_connections.data.lock().get(&1).unwrap().num_identifiers); + assert_eq!(rpc_connections.data.lock().len(), 1); + + let reserved = reserved.unwrap(); + let registered = reserved.register("identifier1".to_string()).unwrap(); + assert!(rpc_connections.contains_identifier(1, "identifier1")); + assert_eq!(1, rpc_connections.data.lock().get(&1).unwrap().num_identifiers); + drop(registered); + + // Data is dropped. + assert!(rpc_connections.data.lock().get(&1).is_none()); + assert!(rpc_connections.data.lock().is_empty()); + // Checks can still happen. + assert!(!rpc_connections.contains_identifier(1, "identifier1")); + } + + #[test] + fn reserve_space_capacity_reached() { + let rpc_connections = RpcConnections::new(2); + + // Reserve identifier for connection 1. + let reserved = rpc_connections.reserve_space(1); + assert!(reserved.is_some()); + assert_eq!(1, rpc_connections.data.lock().get(&1).unwrap().num_identifiers); + + // Add identifier for connection 1. + let reserved = reserved.unwrap(); + let registered = reserved.register("identifier1".to_string()).unwrap(); + assert!(rpc_connections.contains_identifier(1, "identifier1")); + assert_eq!(1, rpc_connections.data.lock().get(&1).unwrap().num_identifiers); + + // Reserve identifier for connection 1 again. + let reserved = rpc_connections.reserve_space(1); + assert!(reserved.is_some()); + assert_eq!(2, rpc_connections.data.lock().get(&1).unwrap().num_identifiers); + + // Add identifier for connection 1 again. + let reserved = reserved.unwrap(); + let registered_second = reserved.register("identifier2".to_string()).unwrap(); + assert!(rpc_connections.contains_identifier(1, "identifier2")); + assert_eq!(2, rpc_connections.data.lock().get(&1).unwrap().num_identifiers); + + // Cannot reserve more identifiers. + let reserved = rpc_connections.reserve_space(1); + assert!(reserved.is_none()); + + // Drop the first identifier. + drop(registered); + assert_eq!(1, rpc_connections.data.lock().get(&1).unwrap().num_identifiers); + assert!(rpc_connections.contains_identifier(1, "identifier2")); + assert!(!rpc_connections.contains_identifier(1, "identifier1")); + + // Can reserve again after clearing the space. + let reserved = rpc_connections.reserve_space(1); + assert!(reserved.is_some()); + assert_eq!(2, rpc_connections.data.lock().get(&1).unwrap().num_identifiers); + + // Ensure data is cleared. + drop(reserved); + drop(registered_second); + assert!(rpc_connections.data.lock().get(&1).is_none()); + } +} diff --git a/substrate/client/rpc-spec-v2/src/common/mod.rs b/substrate/client/rpc-spec-v2/src/common/mod.rs index ac1af8fce3c..3167561d649 100644 --- a/substrate/client/rpc-spec-v2/src/common/mod.rs +++ b/substrate/client/rpc-spec-v2/src/common/mod.rs @@ -13,5 +13,6 @@ //! Common types and functionality for the RPC-V2 spec. +pub mod connections; pub mod events; pub mod storage; -- GitLab From 8e95a3e1aa9c1c7ec5ca468f46714f1a5eff2485 Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Tue, 2 Apr 2024 16:41:01 +0300 Subject: [PATCH 148/187] Align dependencies with `parity-bridges-common` (#3937) Working towards migrating the `parity-bridges-common` repo inside `polkadot-sdk`. This PR upgrades some dependencies in order to align them with the versions used in `parity-bridges-common` Related to https://github.com/paritytech/parity-bridges-common/issues/2538 --- Cargo.lock | 116 +++++++++++------- .../outbound-queue/merkle-tree/Cargo.toml | 2 +- .../snowbridge/runtime/test-common/Cargo.toml | 2 +- cumulus/client/collator/Cargo.toml | 4 +- cumulus/client/consensus/aura/Cargo.toml | 2 +- cumulus/client/consensus/common/Cargo.toml | 2 +- cumulus/client/consensus/proposer/Cargo.toml | 2 +- .../client/consensus/relay-chain/Cargo.toml | 2 +- cumulus/client/network/Cargo.toml | 2 +- cumulus/client/parachain-inherent/Cargo.toml | 4 +- cumulus/client/pov-recovery/Cargo.toml | 2 +- .../Cargo.toml | 2 +- .../client/relay-chain-interface/Cargo.toml | 2 +- .../relay-chain-minimal-node/Cargo.toml | 2 +- .../relay-chain-rpc-interface/Cargo.toml | 2 +- cumulus/pallets/aura-ext/Cargo.toml | 2 +- cumulus/pallets/collator-selection/Cargo.toml | 2 +- cumulus/pallets/dmp-queue/Cargo.toml | 2 +- cumulus/pallets/parachain-system/Cargo.toml | 2 +- cumulus/pallets/solo-to-para/Cargo.toml | 2 +- cumulus/pallets/xcm/Cargo.toml | 2 +- cumulus/pallets/xcmp-queue/Cargo.toml | 2 +- cumulus/parachains/common/Cargo.toml | 2 +- .../bridges/bridge-hub-rococo/Cargo.toml | 2 +- .../pallets/collective-content/Cargo.toml | 2 +- .../pallets/parachain-info/Cargo.toml | 2 +- cumulus/parachains/pallets/ping/Cargo.toml | 2 +- .../assets/asset-hub-rococo/Cargo.toml | 2 +- .../assets/asset-hub-westend/Cargo.toml | 2 +- .../runtimes/assets/common/Cargo.toml | 2 +- .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 2 +- .../bridge-hubs/bridge-hub-westend/Cargo.toml | 2 +- .../runtimes/bridge-hubs/common/Cargo.toml | 2 +- .../collectives-westend/Cargo.toml | 2 +- .../contracts/contracts-rococo/Cargo.toml | 2 +- .../glutton/glutton-westend/Cargo.toml | 2 +- .../runtimes/starters/seedling/Cargo.toml | 2 +- .../runtimes/starters/shell/Cargo.toml | 2 +- .../runtimes/testing/penpal/Cargo.toml | 2 +- .../testing/rococo-parachain/Cargo.toml | 2 +- cumulus/polkadot-parachain/Cargo.toml | 2 +- cumulus/primitives/core/Cargo.toml | 2 +- .../primitives/parachain-inherent/Cargo.toml | 4 +- .../storage-weight-reclaim/Cargo.toml | 2 +- cumulus/test/runtime/Cargo.toml | 2 +- cumulus/test/service/Cargo.toml | 2 +- polkadot/Cargo.toml | 2 +- polkadot/cli/Cargo.toml | 2 +- polkadot/core-primitives/Cargo.toml | 2 +- polkadot/node/collation-generation/Cargo.toml | 2 +- polkadot/node/core/approval-voting/Cargo.toml | 6 +- polkadot/node/core/av-store/Cargo.toml | 4 +- polkadot/node/core/backing/Cargo.toml | 4 +- .../node/core/bitfield-signing/Cargo.toml | 2 +- .../node/core/candidate-validation/Cargo.toml | 6 +- polkadot/node/core/chain-api/Cargo.toml | 4 +- polkadot/node/core/chain-selection/Cargo.toml | 2 +- .../node/core/dispute-coordinator/Cargo.toml | 2 +- .../node/core/parachains-inherent/Cargo.toml | 4 +- .../core/prospective-parachains/Cargo.toml | 2 +- polkadot/node/core/provisioner/Cargo.toml | 2 +- polkadot/node/core/pvf-checker/Cargo.toml | 2 +- polkadot/node/core/pvf/Cargo.toml | 2 +- polkadot/node/core/pvf/common/Cargo.toml | 2 +- polkadot/node/core/runtime-api/Cargo.toml | 6 +- polkadot/node/jaeger/Cargo.toml | 2 +- polkadot/node/malus/Cargo.toml | 6 +- polkadot/node/metrics/Cargo.toml | 4 +- .../network/approval-distribution/Cargo.toml | 4 +- .../availability-distribution/Cargo.toml | 2 +- .../network/availability-recovery/Cargo.toml | 8 +- .../network/bitfield-distribution/Cargo.toml | 4 +- polkadot/node/network/bridge/Cargo.toml | 4 +- .../node/network/collator-protocol/Cargo.toml | 4 +- .../network/dispute-distribution/Cargo.toml | 4 +- .../node/network/gossip-support/Cargo.toml | 4 +- polkadot/node/network/protocol/Cargo.toml | 6 +- .../network/statement-distribution/Cargo.toml | 2 +- polkadot/node/overseer/Cargo.toml | 6 +- polkadot/node/primitives/Cargo.toml | 2 +- polkadot/node/service/Cargo.toml | 6 +- polkadot/node/subsystem-bench/Cargo.toml | 6 +- .../node/subsystem-test-helpers/Cargo.toml | 4 +- polkadot/node/subsystem-types/Cargo.toml | 4 +- polkadot/node/subsystem-util/Cargo.toml | 8 +- polkadot/node/test/client/Cargo.toml | 2 +- polkadot/node/test/service/Cargo.toml | 6 +- polkadot/parachain/Cargo.toml | 2 +- .../test-parachains/adder/collator/Cargo.toml | 2 +- .../undying/collator/Cargo.toml | 2 +- polkadot/primitives/Cargo.toml | 2 +- polkadot/runtime/common/Cargo.toml | 2 +- polkadot/runtime/parachains/Cargo.toml | 4 +- polkadot/runtime/rococo/Cargo.toml | 2 +- polkadot/runtime/test-runtime/Cargo.toml | 2 +- polkadot/runtime/westend/Cargo.toml | 2 +- polkadot/xcm/Cargo.toml | 2 +- polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml | 2 +- polkadot/xcm/pallet-xcm/Cargo.toml | 2 +- polkadot/xcm/xcm-builder/Cargo.toml | 2 +- polkadot/xcm/xcm-executor/Cargo.toml | 2 +- .../xcm-executor/integration-tests/Cargo.toml | 2 +- .../xcm-fee-payment-runtime-api/Cargo.toml | 2 +- polkadot/xcm/xcm-simulator/example/Cargo.toml | 2 +- polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml | 2 +- substrate/bin/node/bench/Cargo.toml | 2 +- substrate/bin/node/cli/Cargo.toml | 6 +- substrate/bin/node/runtime/Cargo.toml | 2 +- substrate/bin/node/testing/Cargo.toml | 2 +- substrate/client/api/Cargo.toml | 2 +- .../client/authority-discovery/Cargo.toml | 4 +- substrate/client/basic-authorship/Cargo.toml | 2 +- substrate/client/cli/Cargo.toml | 2 +- substrate/client/consensus/aura/Cargo.toml | 4 +- substrate/client/consensus/babe/Cargo.toml | 6 +- .../client/consensus/babe/rpc/Cargo.toml | 4 +- substrate/client/consensus/beefy/Cargo.toml | 6 +- .../client/consensus/beefy/rpc/Cargo.toml | 2 +- substrate/client/consensus/common/Cargo.toml | 4 +- substrate/client/consensus/grandpa/Cargo.toml | 6 +- .../client/consensus/grandpa/rpc/Cargo.toml | 2 +- .../client/consensus/manual-seal/Cargo.toml | 4 +- substrate/client/consensus/pow/Cargo.toml | 4 +- substrate/client/consensus/slots/Cargo.toml | 4 +- substrate/client/executor/Cargo.toml | 2 +- substrate/client/informant/Cargo.toml | 2 +- .../client/merkle-mountain-range/Cargo.toml | 4 +- substrate/client/mixnet/Cargo.toml | 2 +- substrate/client/network-gossip/Cargo.toml | 6 +- substrate/client/network/Cargo.toml | 4 +- substrate/client/network/bitswap/Cargo.toml | 2 +- substrate/client/network/common/Cargo.toml | 4 +- substrate/client/network/light/Cargo.toml | 2 +- substrate/client/network/statement/Cargo.toml | 2 +- substrate/client/network/sync/Cargo.toml | 4 +- substrate/client/network/test/Cargo.toml | 6 +- .../client/network/transactions/Cargo.toml | 2 +- substrate/client/offchain/Cargo.toml | 4 +- substrate/client/rpc-api/Cargo.toml | 2 +- substrate/client/rpc-servers/Cargo.toml | 2 +- substrate/client/rpc-spec-v2/Cargo.toml | 2 +- substrate/client/rpc/Cargo.toml | 8 +- substrate/client/service/Cargo.toml | 4 +- substrate/client/service/test/Cargo.toml | 2 +- substrate/client/statement-store/Cargo.toml | 2 +- substrate/client/sysinfo/Cargo.toml | 2 +- substrate/client/telemetry/Cargo.toml | 2 +- substrate/client/transaction-pool/Cargo.toml | 4 +- .../client/transaction-pool/api/Cargo.toml | 4 +- substrate/client/utils/Cargo.toml | 2 +- substrate/frame/Cargo.toml | 2 +- substrate/frame/alliance/Cargo.toml | 2 +- substrate/frame/asset-conversion/Cargo.toml | 2 +- substrate/frame/asset-rate/Cargo.toml | 2 +- substrate/frame/assets/Cargo.toml | 2 +- substrate/frame/atomic-swap/Cargo.toml | 2 +- substrate/frame/aura/Cargo.toml | 2 +- .../frame/authority-discovery/Cargo.toml | 2 +- substrate/frame/authorship/Cargo.toml | 2 +- substrate/frame/babe/Cargo.toml | 2 +- substrate/frame/bags-list/Cargo.toml | 2 +- substrate/frame/balances/Cargo.toml | 2 +- substrate/frame/beefy-mmr/Cargo.toml | 2 +- substrate/frame/beefy/Cargo.toml | 2 +- substrate/frame/benchmarking/Cargo.toml | 2 +- substrate/frame/benchmarking/pov/Cargo.toml | 2 +- substrate/frame/bounties/Cargo.toml | 2 +- substrate/frame/broker/Cargo.toml | 2 +- substrate/frame/child-bounties/Cargo.toml | 2 +- substrate/frame/collective/Cargo.toml | 2 +- substrate/frame/contracts/Cargo.toml | 4 +- .../frame/contracts/mock-network/Cargo.toml | 2 +- substrate/frame/contracts/uapi/Cargo.toml | 2 +- substrate/frame/conviction-voting/Cargo.toml | 2 +- substrate/frame/core-fellowship/Cargo.toml | 2 +- substrate/frame/democracy/Cargo.toml | 2 +- .../election-provider-multi-phase/Cargo.toml | 4 +- .../test-staking-e2e/Cargo.toml | 2 +- .../election-provider-support/Cargo.toml | 2 +- .../solution-type/Cargo.toml | 2 +- .../solution-type/fuzzer/Cargo.toml | 2 +- substrate/frame/elections-phragmen/Cargo.toml | 2 +- substrate/frame/examples/basic/Cargo.toml | 2 +- .../frame/examples/default-config/Cargo.toml | 2 +- substrate/frame/examples/dev-mode/Cargo.toml | 2 +- .../frame/examples/frame-crate/Cargo.toml | 2 +- .../frame/examples/kitchensink/Cargo.toml | 2 +- .../frame/examples/offchain-worker/Cargo.toml | 2 +- .../single-block-migrations/Cargo.toml | 2 +- substrate/frame/examples/split/Cargo.toml | 2 +- substrate/frame/examples/tasks/Cargo.toml | 2 +- substrate/frame/executive/Cargo.toml | 2 +- substrate/frame/fast-unstake/Cargo.toml | 2 +- substrate/frame/glutton/Cargo.toml | 2 +- substrate/frame/grandpa/Cargo.toml | 2 +- substrate/frame/identity/Cargo.toml | 2 +- substrate/frame/im-online/Cargo.toml | 2 +- substrate/frame/indices/Cargo.toml | 2 +- .../Cargo.toml | 2 +- substrate/frame/lottery/Cargo.toml | 2 +- substrate/frame/membership/Cargo.toml | 2 +- .../frame/merkle-mountain-range/Cargo.toml | 4 +- substrate/frame/message-queue/Cargo.toml | 2 +- substrate/frame/migrations/Cargo.toml | 2 +- substrate/frame/mixnet/Cargo.toml | 2 +- substrate/frame/multisig/Cargo.toml | 2 +- .../frame/nft-fractionalization/Cargo.toml | 2 +- substrate/frame/nfts/Cargo.toml | 2 +- substrate/frame/nis/Cargo.toml | 2 +- substrate/frame/node-authorization/Cargo.toml | 2 +- substrate/frame/nomination-pools/Cargo.toml | 2 +- .../nomination-pools/benchmarking/Cargo.toml | 2 +- .../nomination-pools/test-staking/Cargo.toml | 2 +- substrate/frame/offences/Cargo.toml | 2 +- .../frame/offences/benchmarking/Cargo.toml | 2 +- substrate/frame/paged-list/Cargo.toml | 2 +- substrate/frame/parameters/Cargo.toml | 2 +- substrate/frame/preimage/Cargo.toml | 2 +- substrate/frame/proxy/Cargo.toml | 2 +- substrate/frame/ranked-collective/Cargo.toml | 2 +- substrate/frame/recovery/Cargo.toml | 2 +- substrate/frame/referenda/Cargo.toml | 2 +- substrate/frame/remark/Cargo.toml | 2 +- substrate/frame/root-offences/Cargo.toml | 2 +- substrate/frame/root-testing/Cargo.toml | 2 +- substrate/frame/safe-mode/Cargo.toml | 2 +- substrate/frame/salary/Cargo.toml | 2 +- substrate/frame/sassafras/Cargo.toml | 2 +- substrate/frame/scheduler/Cargo.toml | 2 +- substrate/frame/scored-pool/Cargo.toml | 2 +- substrate/frame/session/Cargo.toml | 2 +- .../frame/session/benchmarking/Cargo.toml | 2 +- substrate/frame/society/Cargo.toml | 2 +- substrate/frame/staking/Cargo.toml | 2 +- .../frame/state-trie-migration/Cargo.toml | 2 +- substrate/frame/statement/Cargo.toml | 2 +- substrate/frame/sudo/Cargo.toml | 2 +- substrate/frame/support/Cargo.toml | 2 +- substrate/frame/support/test/Cargo.toml | 2 +- .../support/test/compile_pass/Cargo.toml | 2 +- .../frame/support/test/pallet/Cargo.toml | 2 +- .../support/test/stg_frame_crate/Cargo.toml | 2 +- substrate/frame/system/Cargo.toml | 2 +- .../frame/system/benchmarking/Cargo.toml | 2 +- substrate/frame/timestamp/Cargo.toml | 2 +- substrate/frame/tips/Cargo.toml | 2 +- .../frame/transaction-payment/Cargo.toml | 2 +- .../asset-conversion-tx-payment/Cargo.toml | 2 +- .../asset-tx-payment/Cargo.toml | 2 +- .../frame/transaction-storage/Cargo.toml | 2 +- substrate/frame/treasury/Cargo.toml | 2 +- substrate/frame/tx-pause/Cargo.toml | 2 +- substrate/frame/uniques/Cargo.toml | 2 +- substrate/frame/utility/Cargo.toml | 2 +- substrate/frame/vesting/Cargo.toml | 2 +- substrate/frame/whitelist/Cargo.toml | 2 +- substrate/primitives/api/Cargo.toml | 2 +- substrate/primitives/api/test/Cargo.toml | 4 +- .../primitives/application-crypto/Cargo.toml | 2 +- substrate/primitives/arithmetic/Cargo.toml | 2 +- .../primitives/authority-discovery/Cargo.toml | 2 +- substrate/primitives/blockchain/Cargo.toml | 2 +- .../primitives/consensus/aura/Cargo.toml | 4 +- .../primitives/consensus/babe/Cargo.toml | 4 +- .../primitives/consensus/beefy/Cargo.toml | 4 +- .../primitives/consensus/common/Cargo.toml | 6 +- .../primitives/consensus/grandpa/Cargo.toml | 2 +- .../primitives/consensus/sassafras/Cargo.toml | 2 +- .../primitives/consensus/slots/Cargo.toml | 2 +- substrate/primitives/core/Cargo.toml | 2 +- substrate/primitives/inherents/Cargo.toml | 6 +- substrate/primitives/keyring/Cargo.toml | 2 +- .../merkle-mountain-range/Cargo.toml | 2 +- substrate/primitives/metadata-ir/Cargo.toml | 2 +- substrate/primitives/mixnet/Cargo.toml | 2 +- .../primitives/npos-elections/Cargo.toml | 2 +- substrate/primitives/runtime/Cargo.toml | 2 +- substrate/primitives/session/Cargo.toml | 2 +- substrate/primitives/staking/Cargo.toml | 2 +- .../primitives/statement-store/Cargo.toml | 2 +- .../primitives/test-primitives/Cargo.toml | 2 +- substrate/primitives/timestamp/Cargo.toml | 2 +- .../transaction-storage-proof/Cargo.toml | 4 +- substrate/primitives/trie/Cargo.toml | 2 +- substrate/primitives/version/Cargo.toml | 2 +- substrate/primitives/weights/Cargo.toml | 2 +- substrate/test-utils/Cargo.toml | 2 +- substrate/test-utils/client/Cargo.toml | 4 +- substrate/test-utils/runtime/Cargo.toml | 4 +- .../test-utils/runtime/client/Cargo.toml | 2 +- .../runtime/transaction-pool/Cargo.toml | 2 +- substrate/utils/binary-merkle-tree/Cargo.toml | 2 +- .../frame/remote-externalities/Cargo.toml | 2 +- substrate/utils/frame/rpc/client/Cargo.toml | 2 +- substrate/utils/frame/rpc/support/Cargo.toml | 4 +- substrate/utils/frame/rpc/system/Cargo.toml | 4 +- .../utils/frame/try-runtime/cli/Cargo.toml | 4 +- substrate/utils/wasm-builder/Cargo.toml | 2 +- templates/minimal/node/Cargo.toml | 2 +- templates/minimal/pallets/template/Cargo.toml | 2 +- .../parachain/pallets/template/Cargo.toml | 2 +- templates/parachain/runtime/Cargo.toml | 2 +- templates/solochain/node/Cargo.toml | 2 +- .../solochain/pallets/template/Cargo.toml | 2 +- templates/solochain/runtime/Cargo.toml | 2 +- 305 files changed, 466 insertions(+), 434 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 24612391d3f..9393f8d606d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -275,9 +275,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.2" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" [[package]] name = "anstyle-parse" @@ -1239,9 +1239,9 @@ checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae" [[package]] name = "async-trait" -version = "0.1.74" +version = "0.1.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" dependencies = [ "proc-macro2", "quote", @@ -1393,7 +1393,7 @@ name = "binary-merkle-tree" version = "13.0.0" dependencies = [ "array-bytes 6.1.0", - "env_logger 0.9.3", + "env_logger 0.11.3", "hash-db", "log", "sp-core", @@ -4991,10 +4991,10 @@ dependencies = [ ] [[package]] -name = "env_logger" -version = "0.8.4" +name = "env_filter" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" dependencies = [ "log", "regex", @@ -5002,15 +5002,12 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.9.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" dependencies = [ - "atty", - "humantime", "log", "regex", - "termcolor", ] [[package]] @@ -5026,6 +5023,19 @@ dependencies = [ "termcolor", ] +[[package]] +name = "env_logger" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + [[package]] name = "environmental" version = "1.1.4" @@ -6758,7 +6768,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ - "socket2 0.5.3", + "socket2 0.5.6", "widestring", "windows-sys 0.48.0", "winreg", @@ -9520,7 +9530,7 @@ dependencies = [ "array-bytes 6.1.0", "assert_matches", "bitflags 1.3.2", - "env_logger 0.9.3", + "env_logger 0.11.3", "environmental", "frame-benchmarking", "frame-support", @@ -9767,7 +9777,7 @@ dependencies = [ "sp-runtime", "sp-std 14.0.0", "sp-tracing 16.0.0", - "strum 0.24.1", + "strum 0.26.2", ] [[package]] @@ -10188,7 +10198,7 @@ name = "pallet-mmr" version = "27.0.0" dependencies = [ "array-bytes 6.1.0", - "env_logger 0.9.3", + "env_logger 0.11.3", "frame-benchmarking", "frame-support", "frame-system", @@ -12080,7 +12090,7 @@ version = "7.0.0" dependencies = [ "assert_matches", "bitvec", - "env_logger 0.9.3", + "env_logger 0.11.3", "futures", "futures-timer", "itertools 0.10.5", @@ -12110,7 +12120,7 @@ dependencies = [ "always-assert", "assert_matches", "bitvec", - "env_logger 0.9.3", + "env_logger 0.11.3", "futures", "futures-timer", "log", @@ -12166,7 +12176,7 @@ version = "7.0.0" dependencies = [ "assert_matches", "async-trait", - "env_logger 0.9.3", + "env_logger 0.11.3", "fatality", "futures", "futures-timer", @@ -12228,7 +12238,7 @@ version = "7.0.0" dependencies = [ "assert_matches", "bitvec", - "env_logger 0.9.3", + "env_logger 0.11.3", "fatality", "futures", "futures-timer", @@ -12400,7 +12410,7 @@ dependencies = [ "async-trait", "bitvec", "derive_more", - "env_logger 0.9.3", + "env_logger 0.11.3", "futures", "futures-timer", "itertools 0.10.5", @@ -12442,7 +12452,7 @@ version = "7.0.0" dependencies = [ "assert_matches", "bitvec", - "env_logger 0.9.3", + "env_logger 0.11.3", "futures", "futures-timer", "kvdb", @@ -12884,7 +12894,7 @@ dependencies = [ "rand_chacha 0.3.1", "sc-authority-discovery", "sc-network", - "strum 0.24.1", + "strum 0.26.2", "thiserror", "tracing-gum", ] @@ -12976,7 +12986,7 @@ dependencies = [ "assert_matches", "async-trait", "derive_more", - "env_logger 0.9.3", + "env_logger 0.11.3", "fatality", "futures", "futures-channel", @@ -13420,7 +13430,7 @@ dependencies = [ "assert_matches", "async-trait", "bitvec", - "env_logger 0.9.3", + "env_logger 0.11.3", "frame-benchmarking", "frame-benchmarking-cli", "frame-support", @@ -13596,7 +13606,7 @@ dependencies = [ "clap-num", "color-eyre", "colored", - "env_logger 0.9.3", + "env_logger 0.11.3", "futures", "futures-timer", "hex", @@ -16130,7 +16140,7 @@ dependencies = [ "array-bytes 6.1.0", "assert_matches", "criterion 0.4.0", - "env_logger 0.9.3", + "env_logger 0.11.3", "num_cpus", "parity-scale-codec", "parking_lot 0.12.1", @@ -16566,7 +16576,7 @@ name = "sc-rpc" version = "29.0.0" dependencies = [ "assert_matches", - "env_logger 0.9.3", + "env_logger 0.11.3", "futures", "jsonrpsee", "log", @@ -16808,7 +16818,7 @@ dependencies = [ name = "sc-statement-store" version = "10.0.0" dependencies = [ - "env_logger 0.9.3", + "env_logger 0.11.3", "log", "parity-db", "parking_lot 0.12.1", @@ -17891,7 +17901,7 @@ name = "snowbridge-outbound-queue-merkle-tree" version = "0.3.0" dependencies = [ "array-bytes 4.2.0", - "env_logger 0.9.3", + "env_logger 0.11.3", "hex", "hex-literal", "parity-scale-codec", @@ -18201,12 +18211,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.3" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -18537,7 +18547,7 @@ dependencies = [ "sp-keystore", "sp-mmr-primitives", "sp-runtime", - "strum 0.24.1", + "strum 0.26.2", "w3f-bls", ] @@ -18828,7 +18838,7 @@ version = "31.0.0" dependencies = [ "sp-core", "sp-runtime", - "strum 0.24.1", + "strum 0.26.2", ] [[package]] @@ -19714,6 +19724,15 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +[[package]] +name = "strum" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" +dependencies = [ + "strum_macros 0.26.2", +] + [[package]] name = "strum_macros" version = "0.24.3" @@ -19740,6 +19759,19 @@ dependencies = [ "syn 2.0.53", ] +[[package]] +name = "strum_macros" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.53", +] + [[package]] name = "subkey" version = "9.0.0" @@ -20005,7 +20037,7 @@ dependencies = [ "parity-wasm", "polkavm-linker", "sp-maybe-compressed-blob", - "strum 0.24.1", + "strum 0.26.2", "tempfile", "toml 0.8.8", "walkdir", @@ -20553,9 +20585,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.33.0" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", "bytes", @@ -20565,16 +20597,16 @@ dependencies = [ "parking_lot 0.12.1", "pin-project-lite 0.2.12", "signal-hook-registry", - "socket2 0.5.3", + "socket2 0.5.6", "tokio-macros", "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", diff --git a/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml b/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml index 0606e9de330..5315d6b4adb 100644 --- a/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml +++ b/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml @@ -23,7 +23,7 @@ sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-fea [dev-dependencies] hex-literal = { version = "0.4.1" } -env_logger = "0.9" +env_logger = "0.11" hex = "0.4" array-bytes = "4.1" sp-crypto-hashing = { path = "../../../../../substrate/primitives/crypto/hashing" } diff --git a/bridges/snowbridge/runtime/test-common/Cargo.toml b/bridges/snowbridge/runtime/test-common/Cargo.toml index 4e8b311cb97..90b4f38e721 100644 --- a/bridges/snowbridge/runtime/test-common/Cargo.toml +++ b/bridges/snowbridge/runtime/test-common/Cargo.toml @@ -14,7 +14,7 @@ workspace = true codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.4.1" } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } smallvec = "1.11.0" diff --git a/cumulus/client/collator/Cargo.toml b/cumulus/client/collator/Cargo.toml index 0e911b9f3ab..42f7342d1a5 100644 --- a/cumulus/client/collator/Cargo.toml +++ b/cumulus/client/collator/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] parking_lot = "0.12.1" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } -futures = "0.3.21" +futures = "0.3.30" tracing = "0.1.25" # Substrate @@ -34,7 +34,7 @@ cumulus-client-network = { path = "../network" } cumulus-primitives-core = { path = "../../primitives/core" } [dev-dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" # Substrate sp-maybe-compressed-blob = { path = "../../../substrate/primitives/maybe-compressed-blob" } diff --git a/cumulus/client/consensus/aura/Cargo.toml b/cumulus/client/consensus/aura/Cargo.toml index 58bb1dd5914..70dd67cb9a0 100644 --- a/cumulus/client/consensus/aura/Cargo.toml +++ b/cumulus/client/consensus/aura/Cargo.toml @@ -10,7 +10,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } futures = "0.3.28" tracing = "0.1.37" diff --git a/cumulus/client/consensus/common/Cargo.toml b/cumulus/client/consensus/common/Cargo.toml index 5a014b10e35..fb4a85ad122 100644 --- a/cumulus/client/consensus/common/Cargo.toml +++ b/cumulus/client/consensus/common/Cargo.toml @@ -10,7 +10,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } dyn-clone = "1.0.16" futures = "0.3.28" diff --git a/cumulus/client/consensus/proposer/Cargo.toml b/cumulus/client/consensus/proposer/Cargo.toml index b37232bb448..42ca4e06f8f 100644 --- a/cumulus/client/consensus/proposer/Cargo.toml +++ b/cumulus/client/consensus/proposer/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] anyhow = "1.0" -async-trait = "0.1.74" +async-trait = "0.1.79" thiserror = { workspace = true } # Substrate diff --git a/cumulus/client/consensus/relay-chain/Cargo.toml b/cumulus/client/consensus/relay-chain/Cargo.toml index 3d06d6b89ef..cb32b980457 100644 --- a/cumulus/client/consensus/relay-chain/Cargo.toml +++ b/cumulus/client/consensus/relay-chain/Cargo.toml @@ -10,7 +10,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" futures = "0.3.28" parking_lot = "0.12.1" tracing = "0.1.37" diff --git a/cumulus/client/network/Cargo.toml b/cumulus/client/network/Cargo.toml index 995ef606d27..1210975ef69 100644 --- a/cumulus/client/network/Cargo.toml +++ b/cumulus/client/network/Cargo.toml @@ -10,7 +10,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } futures = "0.3.28" futures-timer = "3.0.2" diff --git a/cumulus/client/parachain-inherent/Cargo.toml b/cumulus/client/parachain-inherent/Cargo.toml index e00f3ba2606..6e9adab1ffc 100644 --- a/cumulus/client/parachain-inherent/Cargo.toml +++ b/cumulus/client/parachain-inherent/Cargo.toml @@ -7,9 +7,9 @@ description = "Inherent that needs to be present in every parachain block. Conta license = "Apache-2.0" [dependencies] -async-trait = "0.1.73" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } -scale-info = { version = "2.10.0", features = ["derive"] } +scale-info = { version = "2.11.1", features = ["derive"] } tracing = { version = "0.1.37" } # Substrate diff --git a/cumulus/client/pov-recovery/Cargo.toml b/cumulus/client/pov-recovery/Cargo.toml index 375a57a87c2..571935620d6 100644 --- a/cumulus/client/pov-recovery/Cargo.toml +++ b/cumulus/client/pov-recovery/Cargo.toml @@ -32,7 +32,7 @@ polkadot-primitives = { path = "../../../polkadot/primitives" } # Cumulus cumulus-primitives-core = { path = "../../primitives/core" } cumulus-relay-chain-interface = { path = "../relay-chain-interface" } -async-trait = "0.1.74" +async-trait = "0.1.79" [dev-dependencies] tokio = { version = "1.32.0", features = ["macros"] } diff --git a/cumulus/client/relay-chain-inprocess-interface/Cargo.toml b/cumulus/client/relay-chain-inprocess-interface/Cargo.toml index aa16230cd8a..7629b6c631a 100644 --- a/cumulus/client/relay-chain-inprocess-interface/Cargo.toml +++ b/cumulus/client/relay-chain-inprocess-interface/Cargo.toml @@ -10,7 +10,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" futures = "0.3.28" futures-timer = "3.0.2" diff --git a/cumulus/client/relay-chain-interface/Cargo.toml b/cumulus/client/relay-chain-interface/Cargo.toml index 6e652b89210..6df9847252f 100644 --- a/cumulus/client/relay-chain-interface/Cargo.toml +++ b/cumulus/client/relay-chain-interface/Cargo.toml @@ -20,7 +20,7 @@ sp-state-machine = { path = "../../../substrate/primitives/state-machine" } sc-client-api = { path = "../../../substrate/client/api" } futures = "0.3.28" -async-trait = "0.1.74" +async-trait = "0.1.79" thiserror = { workspace = true } jsonrpsee-core = "0.22" parity-scale-codec = "3.6.4" diff --git a/cumulus/client/relay-chain-minimal-node/Cargo.toml b/cumulus/client/relay-chain-minimal-node/Cargo.toml index 98240c92ada..6860b42a507 100644 --- a/cumulus/client/relay-chain-minimal-node/Cargo.toml +++ b/cumulus/client/relay-chain-minimal-node/Cargo.toml @@ -49,6 +49,6 @@ cumulus-primitives-core = { path = "../../primitives/core" } array-bytes = "6.1" tracing = "0.1.37" -async-trait = "0.1.74" +async-trait = "0.1.79" futures = "0.3.28" parking_lot = "0.12.1" diff --git a/cumulus/client/relay-chain-rpc-interface/Cargo.toml b/cumulus/client/relay-chain-rpc-interface/Cargo.toml index 801712b1ad1..14981677289 100644 --- a/cumulus/client/relay-chain-rpc-interface/Cargo.toml +++ b/cumulus/client/relay-chain-rpc-interface/Cargo.toml @@ -35,7 +35,7 @@ futures-timer = "3.0.2" parity-scale-codec = "3.6.4" jsonrpsee = { version = "0.22", features = ["ws-client"] } tracing = "0.1.37" -async-trait = "0.1.74" +async-trait = "0.1.79" url = "2.4.0" serde_json = { workspace = true, default-features = true } serde = { workspace = true, default-features = true } diff --git a/cumulus/pallets/aura-ext/Cargo.toml b/cumulus/pallets/aura-ext/Cargo.toml index ff30dce7b03..fe717596f9b 100644 --- a/cumulus/pallets/aura-ext/Cargo.toml +++ b/cumulus/pallets/aura-ext/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-support = { path = "../../../substrate/frame/support", default-features = false } diff --git a/cumulus/pallets/collator-selection/Cargo.toml b/cumulus/pallets/collator-selection/Cargo.toml index 241a78466d6..c04d9e1403e 100644 --- a/cumulus/pallets/collator-selection/Cargo.toml +++ b/cumulus/pallets/collator-selection/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] log = { workspace = true } codec = { default-features = false, features = ["derive"], package = "parity-scale-codec", version = "3.0.0" } rand = { version = "0.8.5", features = ["std_rng"], default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-std = { path = "../../../substrate/primitives/std", default-features = false } sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } diff --git a/cumulus/pallets/dmp-queue/Cargo.toml b/cumulus/pallets/dmp-queue/Cargo.toml index 83ed994d041..b2b24aeed72 100644 --- a/cumulus/pallets/dmp-queue/Cargo.toml +++ b/cumulus/pallets/dmp-queue/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } frame-support = { path = "../../../substrate/frame/support", default-features = false } diff --git a/cumulus/pallets/parachain-system/Cargo.toml b/cumulus/pallets/parachain-system/Cargo.toml index 7e0442f0b58..a905df5b94a 100644 --- a/cumulus/pallets/parachain-system/Cargo.toml +++ b/cumulus/pallets/parachain-system/Cargo.toml @@ -16,7 +16,7 @@ environmental = { version = "1.1.4", default-features = false } impl-trait-for-tuples = "0.2.1" log = { workspace = true } trie-db = { version = "0.28.0", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } diff --git a/cumulus/pallets/solo-to-para/Cargo.toml b/cumulus/pallets/solo-to-para/Cargo.toml index f7dc5fe4de3..417038d7833 100644 --- a/cumulus/pallets/solo-to-para/Cargo.toml +++ b/cumulus/pallets/solo-to-para/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-support = { path = "../../../substrate/frame/support", default-features = false } diff --git a/cumulus/pallets/xcm/Cargo.toml b/cumulus/pallets/xcm/Cargo.toml index 63cb14b16e7..9122e110fb9 100644 --- a/cumulus/pallets/xcm/Cargo.toml +++ b/cumulus/pallets/xcm/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-std = { path = "../../../substrate/primitives/std", default-features = false } sp-io = { path = "../../../substrate/primitives/io", default-features = false } diff --git a/cumulus/pallets/xcmp-queue/Cargo.toml b/cumulus/pallets/xcmp-queue/Cargo.toml index 9078d5eda99..ab196c6d3ec 100644 --- a/cumulus/pallets/xcmp-queue/Cargo.toml +++ b/cumulus/pallets/xcmp-queue/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"], default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-support = { path = "../../../substrate/frame/support", default-features = false } diff --git a/cumulus/parachains/common/Cargo.toml b/cumulus/parachains/common/Cargo.toml index ebc9f822beb..fa16205d0fd 100644 --- a/cumulus/parachains/common/Cargo.toml +++ b/cumulus/parachains/common/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"], default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-support = { path = "../../../substrate/frame/support", default-features = false } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml index 18c39f895fa..010c252658c 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } hex-literal = "0.4.1" # Substrate diff --git a/cumulus/parachains/pallets/collective-content/Cargo.toml b/cumulus/parachains/pallets/collective-content/Cargo.toml index d4290dd2de2..b3fac47cb4a 100644 --- a/cumulus/parachains/pallets/collective-content/Cargo.toml +++ b/cumulus/parachains/pallets/collective-content/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../../../../substrate/frame/benchmarking", default-features = false, optional = true } frame-support = { path = "../../../../substrate/frame/support", default-features = false } diff --git a/cumulus/parachains/pallets/parachain-info/Cargo.toml b/cumulus/parachains/pallets/parachain-info/Cargo.toml index 0e2f965e1cf..17981d238fd 100644 --- a/cumulus/parachains/pallets/parachain-info/Cargo.toml +++ b/cumulus/parachains/pallets/parachain-info/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../../../substrate/frame/support", default-features = false } frame-system = { path = "../../../../substrate/frame/system", default-features = false } diff --git a/cumulus/parachains/pallets/ping/Cargo.toml b/cumulus/parachains/pallets/ping/Cargo.toml index 1afd55eb0b9..15169b08b91 100644 --- a/cumulus/parachains/pallets/ping/Cargo.toml +++ b/cumulus/parachains/pallets/ping/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-std = { path = "../../../../substrate/primitives/std", default-features = false } sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index 53abb620022..f5ea0937dec 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -13,7 +13,7 @@ workspace = true codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } hex-literal = { version = "0.4.1" } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index 0f8a1182cd7..b792d64c03e 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -13,7 +13,7 @@ workspace = true codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } hex-literal = { version = "0.4.1", optional = true } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } diff --git a/cumulus/parachains/runtimes/assets/common/Cargo.toml b/cumulus/parachains/runtimes/assets/common/Cargo.toml index c9252375cfb..12dfd9da1ff 100644 --- a/cumulus/parachains/runtimes/assets/common/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/common/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } log = { workspace = true } impl-trait-for-tuples = "0.2.2" diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml index 13b4b624eef..1dd4f499b4d 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } hex-literal = { version = "0.4.1" } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml index 0c46e6c2e14..1501ed12e3a 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -16,7 +16,7 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.4.1" } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } # Substrate diff --git a/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml index a4dcd19dc9e..2ab6ee7995f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml @@ -8,7 +8,7 @@ license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../../../../substrate/frame/support", default-features = false } sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml index 4224b397139..9c3acf6ad93 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml @@ -13,7 +13,7 @@ workspace = true codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } hex-literal = { version = "0.4.1" } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index e4ac2016a72..a0aeb642df0 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -19,7 +19,7 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.4.1", optional = true } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate sp-api = { path = "../../../../../substrate/primitives/api", default-features = false } diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml b/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml index a357bf519e4..fe9cd25841b 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } diff --git a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml index 9f08fdf5943..eb702c9f2cd 100644 --- a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-executive = { path = "../../../../../substrate/frame/executive", default-features = false } diff --git a/cumulus/parachains/runtimes/starters/shell/Cargo.toml b/cumulus/parachains/runtimes/starters/shell/Cargo.toml index 2f82547afe9..f66d04fec1f 100644 --- a/cumulus/parachains/runtimes/starters/shell/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/shell/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-executive = { path = "../../../../../substrate/frame/executive", default-features = false } diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index c18f6571f41..028aa002a91 100644 --- a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml @@ -21,7 +21,7 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.4.1", optional = true } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } smallvec = "1.11.0" # Substrate diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml index 790f38d94f5..df3aaa92c79 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index 37b7be75ef9..280ece30fb6 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -15,7 +15,7 @@ name = "polkadot-parachain" path = "src/main.rs" [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" clap = { version = "4.5.3", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.28" diff --git a/cumulus/primitives/core/Cargo.toml b/cumulus/primitives/core/Cargo.toml index 32c5054f359..62c3f675191 100644 --- a/cumulus/primitives/core/Cargo.toml +++ b/cumulus/primitives/core/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate sp-api = { path = "../../../substrate/primitives/api", default-features = false } diff --git a/cumulus/primitives/parachain-inherent/Cargo.toml b/cumulus/primitives/parachain-inherent/Cargo.toml index f434305a0ce..fcf4c93bc2f 100644 --- a/cumulus/primitives/parachain-inherent/Cargo.toml +++ b/cumulus/primitives/parachain-inherent/Cargo.toml @@ -10,9 +10,9 @@ license = "Apache-2.0" workspace = true [dependencies] -async-trait = { version = "0.1.74", optional = true } +async-trait = { version = "0.1.79", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate sp-core = { path = "../../../substrate/primitives/core", default-features = false } diff --git a/cumulus/primitives/storage-weight-reclaim/Cargo.toml b/cumulus/primitives/storage-weight-reclaim/Cargo.toml index 54eec3ffb5e..6dbf7904bf7 100644 --- a/cumulus/primitives/storage-weight-reclaim/Cargo.toml +++ b/cumulus/primitives/storage-weight-reclaim/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../../substrate/frame/support", default-features = false } frame-system = { path = "../../../substrate/frame/system", default-features = false } diff --git a/cumulus/test/runtime/Cargo.toml b/cumulus/test/runtime/Cargo.toml index 449a8b819bc..b430b118fa1 100644 --- a/cumulus/test/runtime/Cargo.toml +++ b/cumulus/test/runtime/Cargo.toml @@ -10,7 +10,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-executive = { path = "../../../substrate/frame/executive", default-features = false } diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index 113e0aca68a..040fb479f6e 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -13,7 +13,7 @@ name = "test-parachain" path = "src/main.rs" [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" clap = { version = "4.5.3", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } criterion = { version = "0.5.1", features = ["async_tokio"] } diff --git a/polkadot/Cargo.toml b/polkadot/Cargo.toml index 883568b23f7..659edcb041c 100644 --- a/polkadot/Cargo.toml +++ b/polkadot/Cargo.toml @@ -45,7 +45,7 @@ tikv-jemallocator = { version = "0.5.0", features = ["unprefixed_malloc_on_suppo assert_cmd = "2.0.4" nix = { version = "0.26.1", features = ["signal"] } tempfile = "3.2.0" -tokio = "1.24.2" +tokio = "1.37" substrate-rpc-client = { path = "../substrate/utils/frame/rpc/client" } polkadot-core-primitives = { path = "core-primitives" } diff --git a/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml index f57efa7ba43..b0c22c5a97f 100644 --- a/polkadot/cli/Cargo.toml +++ b/polkadot/cli/Cargo.toml @@ -22,7 +22,7 @@ cfg-if = "1.0" clap = { version = "4.5.3", features = ["derive"], optional = true } log = { workspace = true, default-features = true } thiserror = { workspace = true } -futures = "0.3.21" +futures = "0.3.30" pyro = { package = "pyroscope", version = "0.5.3", optional = true } pyroscope_pprofrs = { version = "0.2", optional = true } diff --git a/polkadot/core-primitives/Cargo.toml b/polkadot/core-primitives/Cargo.toml index d3aef89cb74..8dfa0b87328 100644 --- a/polkadot/core-primitives/Cargo.toml +++ b/polkadot/core-primitives/Cargo.toml @@ -13,7 +13,7 @@ workspace = true sp-core = { path = "../../substrate/primitives/core", default-features = false } sp-std = { path = "../../substrate/primitives/std", default-features = false } sp-runtime = { path = "../../substrate/primitives/runtime", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } [features] diff --git a/polkadot/node/collation-generation/Cargo.toml b/polkadot/node/collation-generation/Cargo.toml index f72af87c15e..ebc53a9e01b 100644 --- a/polkadot/node/collation-generation/Cargo.toml +++ b/polkadot/node/collation-generation/Cargo.toml @@ -10,7 +10,7 @@ description = "Collator-side subsystem that handles incoming candidate submissio workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" gum = { package = "tracing-gum", path = "../gum" } polkadot-erasure-coding = { path = "../../erasure-coding" } polkadot-node-primitives = { path = "../primitives" } diff --git a/polkadot/node/core/approval-voting/Cargo.toml b/polkadot/node/core/approval-voting/Cargo.toml index 2a5b6198b9a..ced7706c40a 100644 --- a/polkadot/node/core/approval-voting/Cargo.toml +++ b/polkadot/node/core/approval-voting/Cargo.toml @@ -10,7 +10,7 @@ description = "Approval Voting Subsystem of the Polkadot node" workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } gum = { package = "tracing-gum", path = "../../gum" } @@ -41,7 +41,7 @@ rand_chacha = { version = "0.3.1" } rand = "0.8.5" [dev-dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" parking_lot = "0.12.1" sp-keyring = { path = "../../../../substrate/primitives/keyring" } sp-keystore = { path = "../../../../substrate/primitives/keystore" } @@ -52,4 +52,4 @@ assert_matches = "1.4.0" kvdb-memorydb = "0.13.0" test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../../primitives/test-helpers" } log = { workspace = true, default-features = true } -env_logger = "0.9.0" +env_logger = "0.11" diff --git a/polkadot/node/core/av-store/Cargo.toml b/polkadot/node/core/av-store/Cargo.toml index 05212da7479..bc9b979228a 100644 --- a/polkadot/node/core/av-store/Cargo.toml +++ b/polkadot/node/core/av-store/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" kvdb = "0.13.0" thiserror = { workspace = true } @@ -29,7 +29,7 @@ polkadot-node-jaeger = { path = "../../jaeger" } [dev-dependencies] log = { workspace = true, default-features = true } -env_logger = "0.9.0" +env_logger = "0.11" assert_matches = "1.4.0" kvdb-memorydb = "0.13.0" diff --git a/polkadot/node/core/backing/Cargo.toml b/polkadot/node/core/backing/Cargo.toml index d0c1f9aa483..26fa54470fb 100644 --- a/polkadot/node/core/backing/Cargo.toml +++ b/polkadot/node/core/backing/Cargo.toml @@ -10,7 +10,7 @@ description = "The Candidate Backing Subsystem. Tracks parachain candidates that workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" sp-keystore = { path = "../../../../substrate/primitives/keystore" } polkadot-primitives = { path = "../../../primitives" } polkadot-node-primitives = { path = "../../primitives" } @@ -30,7 +30,7 @@ sp-application-crypto = { path = "../../../../substrate/primitives/application-c sp-keyring = { path = "../../../../substrate/primitives/keyring" } sc-keystore = { path = "../../../../substrate/client/keystore" } sp-tracing = { path = "../../../../substrate/primitives/tracing" } -futures = { version = "0.3.21", features = ["thread-pool"] } +futures = { version = "0.3.30", features = ["thread-pool"] } assert_matches = "1.4.0" rstest = "0.18.2" polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } diff --git a/polkadot/node/core/bitfield-signing/Cargo.toml b/polkadot/node/core/bitfield-signing/Cargo.toml index 6ecfffd7249..0663e0f1b69 100644 --- a/polkadot/node/core/bitfield-signing/Cargo.toml +++ b/polkadot/node/core/bitfield-signing/Cargo.toml @@ -10,7 +10,7 @@ description = "Bitfield signing subsystem for the Polkadot node" workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" gum = { package = "tracing-gum", path = "../../gum" } polkadot-primitives = { path = "../../../primitives" } polkadot-node-subsystem = { path = "../../subsystem" } diff --git a/polkadot/node/core/candidate-validation/Cargo.toml b/polkadot/node/core/candidate-validation/Cargo.toml index 15fc8c940d3..0cf4707aad2 100644 --- a/polkadot/node/core/candidate-validation/Cargo.toml +++ b/polkadot/node/core/candidate-validation/Cargo.toml @@ -10,8 +10,8 @@ license.workspace = true workspace = true [dependencies] -async-trait = "0.1.74" -futures = "0.3.21" +async-trait = "0.1.79" +futures = "0.3.30" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../../gum" } @@ -31,7 +31,7 @@ polkadot-node-core-pvf = { path = "../pvf" } [dev-dependencies] sp-keyring = { path = "../../../../substrate/primitives/keyring" } -futures = { version = "0.3.21", features = ["thread-pool"] } +futures = { version = "0.3.30", features = ["thread-pool"] } assert_matches = "1.4.0" polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } sp-core = { path = "../../../../substrate/primitives/core" } diff --git a/polkadot/node/core/chain-api/Cargo.toml b/polkadot/node/core/chain-api/Cargo.toml index 9aa017ecba3..f4d02d3f47b 100644 --- a/polkadot/node/core/chain-api/Cargo.toml +++ b/polkadot/node/core/chain-api/Cargo.toml @@ -10,7 +10,7 @@ description = "The Chain API subsystem provides access to chain related utility workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" gum = { package = "tracing-gum", path = "../../gum" } polkadot-node-metrics = { path = "../../metrics" } polkadot-node-subsystem = { path = "../../subsystem" } @@ -19,7 +19,7 @@ sc-client-api = { path = "../../../../substrate/client/api" } sc-consensus-babe = { path = "../../../../substrate/client/consensus/babe" } [dev-dependencies] -futures = { version = "0.3.21", features = ["thread-pool"] } +futures = { version = "0.3.30", features = ["thread-pool"] } maplit = "1.0.2" parity-scale-codec = "3.6.1" polkadot-node-primitives = { path = "../../primitives" } diff --git a/polkadot/node/core/chain-selection/Cargo.toml b/polkadot/node/core/chain-selection/Cargo.toml index 96fd42785cd..318f27a4308 100644 --- a/polkadot/node/core/chain-selection/Cargo.toml +++ b/polkadot/node/core/chain-selection/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3" gum = { package = "tracing-gum", path = "../../gum" } polkadot-primitives = { path = "../../../primitives" } diff --git a/polkadot/node/core/dispute-coordinator/Cargo.toml b/polkadot/node/core/dispute-coordinator/Cargo.toml index 1fff0a77170..cd3238449be 100644 --- a/polkadot/node/core/dispute-coordinator/Cargo.toml +++ b/polkadot/node/core/dispute-coordinator/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" gum = { package = "tracing-gum", path = "../../gum" } parity-scale-codec = "3.6.1" kvdb = "0.13.0" diff --git a/polkadot/node/core/parachains-inherent/Cargo.toml b/polkadot/node/core/parachains-inherent/Cargo.toml index 24da4dc1e31..4f6090f90e9 100644 --- a/polkadot/node/core/parachains-inherent/Cargo.toml +++ b/polkadot/node/core/parachains-inherent/Cargo.toml @@ -10,11 +10,11 @@ description = "Parachains inherent data provider for Polkadot node" workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../../gum" } thiserror = { workspace = true } -async-trait = "0.1.74" +async-trait = "0.1.79" polkadot-node-subsystem = { path = "../../subsystem" } polkadot-overseer = { path = "../../overseer" } polkadot-primitives = { path = "../../../primitives" } diff --git a/polkadot/node/core/prospective-parachains/Cargo.toml b/polkadot/node/core/prospective-parachains/Cargo.toml index f66a66e859e..ab3cef99e54 100644 --- a/polkadot/node/core/prospective-parachains/Cargo.toml +++ b/polkadot/node/core/prospective-parachains/Cargo.toml @@ -10,7 +10,7 @@ description = "The Prospective Parachains subsystem. Tracks and handles prospect workspace = true [dependencies] -futures = "0.3.19" +futures = "0.3.30" gum = { package = "tracing-gum", path = "../../gum" } parity-scale-codec = "3.6.4" thiserror = { workspace = true } diff --git a/polkadot/node/core/provisioner/Cargo.toml b/polkadot/node/core/provisioner/Cargo.toml index 2a09e2b5b2c..ec1a4abb3ec 100644 --- a/polkadot/node/core/provisioner/Cargo.toml +++ b/polkadot/node/core/provisioner/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } -futures = "0.3.21" +futures = "0.3.30" gum = { package = "tracing-gum", path = "../../gum" } thiserror = { workspace = true } polkadot-primitives = { path = "../../../primitives" } diff --git a/polkadot/node/core/pvf-checker/Cargo.toml b/polkadot/node/core/pvf-checker/Cargo.toml index f4f954e316c..91b12b86809 100644 --- a/polkadot/node/core/pvf-checker/Cargo.toml +++ b/polkadot/node/core/pvf-checker/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" thiserror = { workspace = true } gum = { package = "tracing-gum", path = "../../gum" } diff --git a/polkadot/node/core/pvf/Cargo.toml b/polkadot/node/core/pvf/Cargo.toml index 6ad36a39be6..a0233d6b751 100644 --- a/polkadot/node/core/pvf/Cargo.toml +++ b/polkadot/node/core/pvf/Cargo.toml @@ -14,7 +14,7 @@ always-assert = "0.1" array-bytes = "6.1" blake3 = "1.5" cfg-if = "1.0" -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../../gum" } is_executable = "1.0.1" diff --git a/polkadot/node/core/pvf/common/Cargo.toml b/polkadot/node/core/pvf/common/Cargo.toml index 56bad9792fa..f3eb9d919aa 100644 --- a/polkadot/node/core/pvf/common/Cargo.toml +++ b/polkadot/node/core/pvf/common/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] cfg-if = "1.0" cpu-time = "1.0.0" -futures = "0.3.21" +futures = "0.3.30" gum = { package = "tracing-gum", path = "../../../gum" } libc = "0.2.152" thiserror = { workspace = true } diff --git a/polkadot/node/core/runtime-api/Cargo.toml b/polkadot/node/core/runtime-api/Cargo.toml index 2de3a6ee325..91f5c35b279 100644 --- a/polkadot/node/core/runtime-api/Cargo.toml +++ b/polkadot/node/core/runtime-api/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" gum = { package = "tracing-gum", path = "../../gum" } schnellru = "0.2.1" @@ -25,8 +25,8 @@ polkadot-node-subsystem-types = { path = "../../subsystem-types" } sp-api = { path = "../../../../substrate/primitives/api" } sp-core = { path = "../../../../substrate/primitives/core" } sp-keyring = { path = "../../../../substrate/primitives/keyring" } -async-trait = "0.1.74" -futures = { version = "0.3.21", features = ["thread-pool"] } +async-trait = "0.1.79" +futures = { version = "0.3.30", features = ["thread-pool"] } polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } polkadot-node-primitives = { path = "../../primitives" } test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../../primitives/test-helpers" } diff --git a/polkadot/node/jaeger/Cargo.toml b/polkadot/node/jaeger/Cargo.toml index 23ab8f84210..6fa3d41eddb 100644 --- a/polkadot/node/jaeger/Cargo.toml +++ b/polkadot/node/jaeger/Cargo.toml @@ -18,6 +18,6 @@ polkadot-node-primitives = { path = "../primitives" } sc-network = { path = "../../../substrate/client/network" } sp-core = { path = "../../../substrate/primitives/core" } thiserror = { workspace = true } -tokio = "1.24.2" +tokio = "1.37" log = { workspace = true, default-features = true } parity-scale-codec = { version = "3.6.1", default-features = false } diff --git a/polkadot/node/malus/Cargo.toml b/polkadot/node/malus/Cargo.toml index b3eb856f08e..2f63c2f0938 100644 --- a/polkadot/node/malus/Cargo.toml +++ b/polkadot/node/malus/Cargo.toml @@ -40,11 +40,11 @@ polkadot-node-primitives = { path = "../primitives" } polkadot-primitives = { path = "../../primitives" } color-eyre = { version = "0.6.1", default-features = false } assert_matches = "1.5" -async-trait = "0.1.74" +async-trait = "0.1.79" sp-keystore = { path = "../../../substrate/primitives/keystore" } sp-core = { path = "../../../substrate/primitives/core" } clap = { version = "4.5.3", features = ["derive"] } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../gum" } erasure = { package = "polkadot-erasure-coding", path = "../../erasure-coding" } @@ -58,7 +58,7 @@ polkadot-node-core-pvf-prepare-worker = { path = "../core/pvf/prepare-worker" } [dev-dependencies] polkadot-node-subsystem-test-helpers = { path = "../subsystem-test-helpers" } sp-core = { path = "../../../substrate/primitives/core" } -futures = { version = "0.3.21", features = ["thread-pool"] } +futures = { version = "0.3.30", features = ["thread-pool"] } [build-dependencies] substrate-build-script-utils = { path = "../../../substrate/utils/build-script-utils" } diff --git a/polkadot/node/metrics/Cargo.toml b/polkadot/node/metrics/Cargo.toml index c567278f70e..fbf0abf829e 100644 --- a/polkadot/node/metrics/Cargo.toml +++ b/polkadot/node/metrics/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../gum" } @@ -30,7 +30,7 @@ log = { workspace = true, default-features = true } assert_cmd = "2.0.4" tempfile = "3.2.0" hyper = { version = "0.14.20", default-features = false, features = ["http1", "tcp"] } -tokio = "1.24.2" +tokio = "1.37" polkadot-test-service = { path = "../test/service", features = ["runtime-metrics"] } substrate-test-utils = { path = "../../../substrate/test-utils" } sc-service = { path = "../../../substrate/client/service" } diff --git a/polkadot/node/network/approval-distribution/Cargo.toml b/polkadot/node/network/approval-distribution/Cargo.toml index 2bc09c5f42a..4c04ad83f84 100644 --- a/polkadot/node/network/approval-distribution/Cargo.toml +++ b/polkadot/node/network/approval-distribution/Cargo.toml @@ -20,7 +20,7 @@ polkadot-node-jaeger = { path = "../../jaeger" } rand = "0.8" itertools = "0.10.5" -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../../gum" } bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } @@ -37,5 +37,5 @@ schnorrkel = { version = "0.11.4", default-features = false } # rand_core should match schnorrkel rand_core = "0.6.2" rand_chacha = "0.3.1" -env_logger = "0.9.0" +env_logger = "0.11" log = { workspace = true, default-features = true } diff --git a/polkadot/node/network/availability-distribution/Cargo.toml b/polkadot/node/network/availability-distribution/Cargo.toml index ac606bd377f..b5636203f16 100644 --- a/polkadot/node/network/availability-distribution/Cargo.toml +++ b/polkadot/node/network/availability-distribution/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" gum = { package = "tracing-gum", path = "../../gum" } parity-scale-codec = { version = "3.6.1", features = ["std"] } polkadot-primitives = { path = "../../../primitives" } diff --git a/polkadot/node/network/availability-recovery/Cargo.toml b/polkadot/node/network/availability-recovery/Cargo.toml index 23c4148fa85..dd0e0c43234 100644 --- a/polkadot/node/network/availability-recovery/Cargo.toml +++ b/polkadot/node/network/availability-recovery/Cargo.toml @@ -10,13 +10,13 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.21" -tokio = "1.24.2" +futures = "0.3.30" +tokio = "1.37" schnellru = "0.2.1" rand = "0.8.5" fatality = "0.0.6" thiserror = { workspace = true } -async-trait = "0.1.74" +async-trait = "0.1.79" gum = { package = "tracing-gum", path = "../../gum" } polkadot-erasure-coding = { path = "../../../erasure-coding" } @@ -30,7 +30,7 @@ sc-network = { path = "../../../../substrate/client/network" } [dev-dependencies] assert_matches = "1.4.0" -env_logger = "0.9.0" +env_logger = "0.11" futures-timer = "3.0.2" log = { workspace = true, default-features = true } diff --git a/polkadot/node/network/bitfield-distribution/Cargo.toml b/polkadot/node/network/bitfield-distribution/Cargo.toml index 0ddb5f643b8..6b5b784b7fd 100644 --- a/polkadot/node/network/bitfield-distribution/Cargo.toml +++ b/polkadot/node/network/bitfield-distribution/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] always-assert = "0.1" -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../../gum" } polkadot-primitives = { path = "../../../primitives" } @@ -30,6 +30,6 @@ sp-keystore = { path = "../../../../substrate/primitives/keystore" } sp-keyring = { path = "../../../../substrate/primitives/keyring" } maplit = "1.0.2" log = { workspace = true, default-features = true } -env_logger = "0.9.0" +env_logger = "0.11" assert_matches = "1.4.0" rand_chacha = "0.3.1" diff --git a/polkadot/node/network/bridge/Cargo.toml b/polkadot/node/network/bridge/Cargo.toml index 2e889fc30eb..9c2423e7e58 100644 --- a/polkadot/node/network/bridge/Cargo.toml +++ b/polkadot/node/network/bridge/Cargo.toml @@ -11,8 +11,8 @@ workspace = true [dependencies] always-assert = "0.1" -async-trait = "0.1.74" -futures = "0.3.21" +async-trait = "0.1.79" +futures = "0.3.30" gum = { package = "tracing-gum", path = "../../gum" } polkadot-primitives = { path = "../../../primitives" } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } diff --git a/polkadot/node/network/collator-protocol/Cargo.toml b/polkadot/node/network/collator-protocol/Cargo.toml index cfd88df958c..2c7135742f5 100644 --- a/polkadot/node/network/collator-protocol/Cargo.toml +++ b/polkadot/node/network/collator-protocol/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] bitvec = { version = "1.0.1", default-features = false, features = ["alloc"] } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3" gum = { package = "tracing-gum", path = "../../gum" } @@ -30,7 +30,7 @@ tokio-util = "0.7.1" [dev-dependencies] log = { workspace = true, default-features = true } -env_logger = "0.9.0" +env_logger = "0.11" assert_matches = "1.4.0" sp-core = { path = "../../../../substrate/primitives/core", features = ["std"] } diff --git a/polkadot/node/network/dispute-distribution/Cargo.toml b/polkadot/node/network/dispute-distribution/Cargo.toml index 14d59d04f2b..ff9c302c731 100644 --- a/polkadot/node/network/dispute-distribution/Cargo.toml +++ b/polkadot/node/network/dispute-distribution/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../../gum" } derive_more = "0.99.17" @@ -31,7 +31,7 @@ indexmap = "2.0.0" [dev-dependencies] async-channel = "1.8.0" -async-trait = "0.1.74" +async-trait = "0.1.79" polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } sp-keyring = { path = "../../../../substrate/primitives/keyring" } sp-tracing = { path = "../../../../substrate/primitives/tracing" } diff --git a/polkadot/node/network/gossip-support/Cargo.toml b/polkadot/node/network/gossip-support/Cargo.toml index 8d0edc206d7..2d6f2f954c6 100644 --- a/polkadot/node/network/gossip-support/Cargo.toml +++ b/polkadot/node/network/gossip-support/Cargo.toml @@ -22,7 +22,7 @@ polkadot-node-subsystem = { path = "../../subsystem" } polkadot-node-subsystem-util = { path = "../../subsystem-util" } polkadot-primitives = { path = "../../../primitives" } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" rand = { version = "0.8.5", default-features = false } rand_chacha = { version = "0.3.1", default-features = false } @@ -37,7 +37,7 @@ sp-authority-discovery = { path = "../../../../substrate/primitives/authority-di polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } assert_matches = "1.4.0" -async-trait = "0.1.74" +async-trait = "0.1.79" parking_lot = "0.12.1" lazy_static = "1.4.0" quickcheck = "1.0.3" diff --git a/polkadot/node/network/protocol/Cargo.toml b/polkadot/node/network/protocol/Cargo.toml index 7efa0b8ca82..81936364897 100644 --- a/polkadot/node/network/protocol/Cargo.toml +++ b/polkadot/node/network/protocol/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] async-channel = "1.8.0" -async-trait = "0.1.74" +async-trait = "0.1.79" hex = "0.4.3" polkadot-primitives = { path = "../../../primitives" } polkadot-node-primitives = { path = "../../primitives" } @@ -19,8 +19,8 @@ polkadot-node-jaeger = { path = "../../jaeger" } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } sc-network = { path = "../../../../substrate/client/network" } sc-authority-discovery = { path = "../../../../substrate/client/authority-discovery" } -strum = { version = "0.24", features = ["derive"] } -futures = "0.3.21" +strum = { version = "0.26.2", features = ["derive"] } +futures = "0.3.30" thiserror = { workspace = true } fatality = "0.0.6" rand = "0.8" diff --git a/polkadot/node/network/statement-distribution/Cargo.toml b/polkadot/node/network/statement-distribution/Cargo.toml index 01f7d818c1c..d8ae031cbf3 100644 --- a/polkadot/node/network/statement-distribution/Cargo.toml +++ b/polkadot/node/network/statement-distribution/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../../gum" } polkadot-primitives = { path = "../../../primitives" } diff --git a/polkadot/node/overseer/Cargo.toml b/polkadot/node/overseer/Cargo.toml index f91ec80d944..ef79cfe2f70 100644 --- a/polkadot/node/overseer/Cargo.toml +++ b/polkadot/node/overseer/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] client = { package = "sc-client-api", path = "../../../substrate/client/api" } sp-api = { path = "../../../substrate/primitives/api" } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" parking_lot = "0.12.1" polkadot-node-network-protocol = { path = "../network/protocol" } @@ -23,13 +23,13 @@ polkadot-primitives = { path = "../../primitives" } orchestra = { version = "0.3.5", default-features = false, features = ["futures_channel"] } gum = { package = "tracing-gum", path = "../gum" } sp-core = { path = "../../../substrate/primitives/core" } -async-trait = "0.1.74" +async-trait = "0.1.79" tikv-jemalloc-ctl = { version = "0.5.0", optional = true } [dev-dependencies] metered = { package = "prioritized-metered-channel", version = "0.6.1", default-features = false, features = ["futures_channel"] } sp-core = { path = "../../../substrate/primitives/core" } -futures = { version = "0.3.21", features = ["thread-pool"] } +futures = { version = "0.3.30", features = ["thread-pool"] } femme = "2.2.1" assert_matches = "1.4.0" test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../primitives/test-helpers" } diff --git a/polkadot/node/primitives/Cargo.toml b/polkadot/node/primitives/Cargo.toml index b4541bcc346..a4bbd824e67 100644 --- a/polkadot/node/primitives/Cargo.toml +++ b/polkadot/node/primitives/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] bounded-vec = "0.7" -futures = "0.3.21" +futures = "0.3.30" polkadot-primitives = { path = "../../primitives" } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } sp-core = { path = "../../../substrate/primitives/core" } diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 932f3e679f4..9688ab55647 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -77,8 +77,8 @@ frame-benchmarking-cli = { path = "../../../substrate/utils/frame/benchmarking-c frame-benchmarking = { path = "../../../substrate/frame/benchmarking" } # External Crates -async-trait = "0.1.74" -futures = "0.3.21" +async-trait = "0.1.79" +futures = "0.3.30" hex-literal = "0.4.1" is_executable = "1.0.1" gum = { package = "tracing-gum", path = "../gum" } @@ -148,7 +148,7 @@ xcm-fee-payment-runtime-api = { path = "../../xcm/xcm-fee-payment-runtime-api" } polkadot-test-client = { path = "../test/client" } polkadot-node-subsystem-test-helpers = { path = "../subsystem-test-helpers" } test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../primitives/test-helpers" } -env_logger = "0.9.0" +env_logger = "0.11" assert_matches = "1.5.0" serial_test = "2.0.0" tempfile = "3.2" diff --git a/polkadot/node/subsystem-bench/Cargo.toml b/polkadot/node/subsystem-bench/Cargo.toml index b494f05180d..37224d110e8 100644 --- a/polkadot/node/subsystem-bench/Cargo.toml +++ b/polkadot/node/subsystem-bench/Cargo.toml @@ -35,12 +35,12 @@ color-eyre = { version = "0.6.1", default-features = false } polkadot-overseer = { path = "../overseer" } colored = "2.0.4" assert_matches = "1.5" -async-trait = "0.1.57" +async-trait = "0.1.79" sp-keystore = { path = "../../../substrate/primitives/keystore" } sc-keystore = { path = "../../../substrate/client/keystore" } sp-core = { path = "../../../substrate/primitives/core" } clap = { version = "4.5.3", features = ["derive"] } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" bincode = "1.3.3" sha1 = "0.10.6" @@ -48,7 +48,7 @@ hex = "0.4.3" gum = { package = "tracing-gum", path = "../gum" } polkadot-erasure-coding = { package = "polkadot-erasure-coding", path = "../../erasure-coding" } log = { workspace = true, default-features = true } -env_logger = "0.9.0" +env_logger = "0.11" rand = "0.8.5" # `rand` only supports uniform distribution, we need normal distribution for latency. rand_distr = "0.4.3" diff --git a/polkadot/node/subsystem-test-helpers/Cargo.toml b/polkadot/node/subsystem-test-helpers/Cargo.toml index c71f030568d..57678e8e8d4 100644 --- a/polkadot/node/subsystem-test-helpers/Cargo.toml +++ b/polkadot/node/subsystem-test-helpers/Cargo.toml @@ -11,8 +11,8 @@ license.workspace = true workspace = true [dependencies] -async-trait = "0.1.74" -futures = "0.3.21" +async-trait = "0.1.79" +futures = "0.3.30" parking_lot = "0.12.1" polkadot-node-subsystem = { path = "../subsystem" } polkadot-erasure-coding = { path = "../../erasure-coding" } diff --git a/polkadot/node/subsystem-types/Cargo.toml b/polkadot/node/subsystem-types/Cargo.toml index 54c8f7e2ade..10190776387 100644 --- a/polkadot/node/subsystem-types/Cargo.toml +++ b/polkadot/node/subsystem-types/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] derive_more = "0.99.17" -futures = "0.3.21" +futures = "0.3.30" polkadot-primitives = { path = "../../primitives" } polkadot-node-primitives = { path = "../primitives" } polkadot-node-network-protocol = { path = "../network/protocol" } @@ -29,5 +29,5 @@ sc-transaction-pool-api = { path = "../../../substrate/client/transaction-pool/a smallvec = "1.8.0" substrate-prometheus-endpoint = { path = "../../../substrate/utils/prometheus" } thiserror = { workspace = true } -async-trait = "0.1.74" +async-trait = "0.1.79" bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } diff --git a/polkadot/node/subsystem-util/Cargo.toml b/polkadot/node/subsystem-util/Cargo.toml index a668f8de76a..79a6a75e4cd 100644 --- a/polkadot/node/subsystem-util/Cargo.toml +++ b/polkadot/node/subsystem-util/Cargo.toml @@ -10,8 +10,8 @@ license.workspace = true workspace = true [dependencies] -async-trait = "0.1.74" -futures = "0.3.21" +async-trait = "0.1.79" +futures = "0.3.30" futures-channel = "0.3.23" itertools = "0.10" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } @@ -44,8 +44,8 @@ parity-db = { version = "0.4.12" } [dev-dependencies] assert_matches = "1.4.0" -env_logger = "0.9.0" -futures = { version = "0.3.21", features = ["thread-pool"] } +env_logger = "0.11" +futures = { version = "0.3.30", features = ["thread-pool"] } log = { workspace = true, default-features = true } polkadot-node-subsystem-test-helpers = { path = "../subsystem-test-helpers" } lazy_static = "1.4.0" diff --git a/polkadot/node/test/client/Cargo.toml b/polkadot/node/test/client/Cargo.toml index 36748c3b455..7db00404eb8 100644 --- a/polkadot/node/test/client/Cargo.toml +++ b/polkadot/node/test/client/Cargo.toml @@ -38,7 +38,7 @@ frame-benchmarking = { path = "../../../../substrate/frame/benchmarking" } [dev-dependencies] sp-keyring = { path = "../../../../substrate/primitives/keyring" } -futures = "0.3.21" +futures = "0.3.30" [features] runtime-benchmarks = [ diff --git a/polkadot/node/test/service/Cargo.toml b/polkadot/node/test/service/Cargo.toml index e7892abcd87..48a206f23c6 100644 --- a/polkadot/node/test/service/Cargo.toml +++ b/polkadot/node/test/service/Cargo.toml @@ -10,13 +10,13 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" hex = "0.4.3" gum = { package = "tracing-gum", path = "../../gum" } rand = "0.8.5" serde_json = { workspace = true, default-features = true } tempfile = "3.2.0" -tokio = "1.24.2" +tokio = "1.37" # Polkadot dependencies polkadot-overseer = { path = "../../overseer" } @@ -63,7 +63,7 @@ substrate-test-client = { path = "../../../../substrate/test-utils/client" } [dev-dependencies] pallet-balances = { path = "../../../../substrate/frame/balances", default-features = false } substrate-test-utils = { path = "../../../../substrate/test-utils" } -tokio = { version = "1.24.2", features = ["macros"] } +tokio = { version = "1.37", features = ["macros"] } [features] runtime-metrics = ["polkadot-test-runtime/runtime-metrics"] diff --git a/polkadot/parachain/Cargo.toml b/polkadot/parachain/Cargo.toml index d8c3cea7ad8..15eea2addc8 100644 --- a/polkadot/parachain/Cargo.toml +++ b/polkadot/parachain/Cargo.toml @@ -14,7 +14,7 @@ workspace = true # this crate for WASM. This is critical to avoid forcing all parachain WASM into implementing # various unnecessary Substrate-specific endpoints. parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } sp-std = { path = "../../substrate/primitives/std", default-features = false } sp-runtime = { path = "../../substrate/primitives/runtime", default-features = false, features = ["serde"] } sp-core = { path = "../../substrate/primitives/core", default-features = false, features = ["serde"] } diff --git a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml index 30bce806f9f..5a2b5405741 100644 --- a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml @@ -17,7 +17,7 @@ path = "src/main.rs" [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } clap = { version = "4.5.3", features = ["derive"] } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" log = { workspace = true, default-features = true } diff --git a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml index bede10a7673..cacf7304f90 100644 --- a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml @@ -17,7 +17,7 @@ path = "src/main.rs" [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } clap = { version = "4.5.3", features = ["derive"] } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" log = { workspace = true, default-features = true } diff --git a/polkadot/primitives/Cargo.toml b/polkadot/primitives/Cargo.toml index e63fb621c78..004fa62acf3 100644 --- a/polkadot/primitives/Cargo.toml +++ b/polkadot/primitives/Cargo.toml @@ -13,7 +13,7 @@ workspace = true bitvec = { version = "1.0.0", default-features = false, features = ["alloc", "serde"] } hex-literal = "0.4.1" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["bit-vec", "derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["bit-vec", "derive", "serde"] } log = { workspace = true, default-features = false } serde = { features = ["alloc", "derive"], workspace = true } diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index eae5d4fb2ef..4219a7e7b0d 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -15,7 +15,7 @@ bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } rustc-hex = { version = "2.1.0", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc"], workspace = true } serde_derive = { workspace = true } static_assertions = "1.1.0" diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index 6e693b83ae1..dff8549f29f 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -15,7 +15,7 @@ bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } log = { workspace = true } rustc-hex = { version = "2.1.0", default-features = false } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], workspace = true } derive_more = "0.99.17" bitflags = "1.3.2" @@ -59,7 +59,7 @@ polkadot-runtime-metrics = { path = "../metrics", default-features = false } polkadot-core-primitives = { path = "../../core-primitives", default-features = false } [dev-dependencies] -futures = "0.3.21" +futures = "0.3.30" hex-literal = "0.4.1" keyring = { package = "sp-keyring", path = "../../../substrate/primitives/keyring" } frame-support-test = { path = "../../../substrate/frame/support/test" } diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index ff178b17070..19cc984e582 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } log = { workspace = true } serde = { workspace = true } serde_derive = { optional = true, workspace = true } diff --git a/polkadot/runtime/test-runtime/Cargo.toml b/polkadot/runtime/test-runtime/Cargo.toml index 9753a409304..35fb684597e 100644 --- a/polkadot/runtime/test-runtime/Cargo.toml +++ b/polkadot/runtime/test-runtime/Cargo.toml @@ -15,7 +15,7 @@ bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } rustc-hex = { version = "2.1.0", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { workspace = true } serde_derive = { optional = true, workspace = true } smallvec = "1.8.0" diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index 4c27d4f6d1f..d726adfb8e6 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } log = { workspace = true } rustc-hex = { version = "2.1.0", default-features = false } serde = { workspace = true } diff --git a/polkadot/xcm/Cargo.toml b/polkadot/xcm/Cargo.toml index f9ccfb9833a..b214342d2f4 100644 --- a/polkadot/xcm/Cargo.toml +++ b/polkadot/xcm/Cargo.toml @@ -16,7 +16,7 @@ derivative = { version = "2.2.0", default-features = false, features = ["use_cor impl-trait-for-tuples = "0.2.2" log = { workspace = true } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } sp-weights = { path = "../../substrate/primitives/weights", default-features = false, features = ["serde"] } serde = { features = ["alloc", "derive", "rc"], workspace = true } schemars = { version = "0.8.13", default-features = true, optional = true } diff --git a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml index 80f2d1deedf..8c71426a6fa 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml +++ b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../../substrate/frame/support", default-features = false } frame-system = { path = "../../../substrate/frame/system", default-features = false } sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index 08307c34f8a..460597e6649 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] bounded-collections = { version = "0.2.0", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } log = { workspace = true } diff --git a/polkadot/xcm/xcm-builder/Cargo.toml b/polkadot/xcm/xcm-builder/Cargo.toml index 10726b0f511..997ca99fb12 100644 --- a/polkadot/xcm/xcm-builder/Cargo.toml +++ b/polkadot/xcm/xcm-builder/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] impl-trait-for-tuples = "0.2.1" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } xcm = { package = "staging-xcm", path = "..", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor", default-features = false } sp-std = { path = "../../../substrate/primitives/std", default-features = false } diff --git a/polkadot/xcm/xcm-executor/Cargo.toml b/polkadot/xcm/xcm-executor/Cargo.toml index 71bd58073db..aebc768bb90 100644 --- a/polkadot/xcm/xcm-executor/Cargo.toml +++ b/polkadot/xcm/xcm-executor/Cargo.toml @@ -13,7 +13,7 @@ workspace = true impl-trait-for-tuples = "0.2.2" environmental = { version = "1.1.4", default-features = false } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } xcm = { package = "staging-xcm", path = "..", default-features = false } sp-std = { path = "../../../substrate/primitives/std", default-features = false } sp-io = { path = "../../../substrate/primitives/io", default-features = false } diff --git a/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml b/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml index 1e572e6210a..9c9c53f0ee1 100644 --- a/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml +++ b/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml @@ -14,7 +14,7 @@ workspace = true codec = { package = "parity-scale-codec", version = "3.6.1" } frame-support = { path = "../../../../substrate/frame/support", default-features = false } frame-system = { path = "../../../../substrate/frame/system" } -futures = "0.3.21" +futures = "0.3.30" pallet-transaction-payment = { path = "../../../../substrate/frame/transaction-payment" } pallet-xcm = { path = "../../pallet-xcm" } polkadot-test-client = { path = "../../../node/test/client" } diff --git a/polkadot/xcm/xcm-fee-payment-runtime-api/Cargo.toml b/polkadot/xcm/xcm-fee-payment-runtime-api/Cargo.toml index 682642d13c3..30c7c0bac14 100644 --- a/polkadot/xcm/xcm-fee-payment-runtime-api/Cargo.toml +++ b/polkadot/xcm/xcm-fee-payment-runtime-api/Cargo.toml @@ -16,7 +16,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = ] } sp-api = { path = "../../../substrate/primitives/api", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", "serde", ] } diff --git a/polkadot/xcm/xcm-simulator/example/Cargo.toml b/polkadot/xcm/xcm-simulator/example/Cargo.toml index af471df60ab..0e13a10a141 100644 --- a/polkadot/xcm/xcm-simulator/example/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/example/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -scale-info = { version = "2.10.0", features = ["derive"] } +scale-info = { version = "2.11.1", features = ["derive"] } log = { workspace = true } frame-system = { path = "../../../../substrate/frame/system" } diff --git a/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml b/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml index 30644dc0e0a..ca794a07bfb 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml @@ -14,7 +14,7 @@ workspace = true codec = { package = "parity-scale-codec", version = "3.6.1" } honggfuzz = "0.5.55" arbitrary = "1.3.2" -scale-info = { version = "2.10.0", features = ["derive"] } +scale-info = { version = "2.11.1", features = ["derive"] } frame-system = { path = "../../../../substrate/frame/system" } frame-support = { path = "../../../../substrate/frame/support" } diff --git a/substrate/bin/node/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml index d5de1dbe6c4..49485fe2a1b 100644 --- a/substrate/bin/node/bench/Cargo.toml +++ b/substrate/bin/node/bench/Cargo.toml @@ -44,4 +44,4 @@ lazy_static = "1.4.0" parity-db = "0.4.12" sc-transaction-pool = { path = "../../../client/transaction-pool" } sc-transaction-pool-api = { path = "../../../client/transaction-pool/api" } -futures = { version = "0.3.21", features = ["thread-pool"] } +futures = { version = "0.3.30", features = ["thread-pool"] } diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index 8bddbbe0482..6346063b9d2 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -45,7 +45,7 @@ clap = { version = "4.5.3", features = ["derive"], optional = true } codec = { package = "parity-scale-codec", version = "3.6.1" } serde = { features = ["derive"], workspace = true, default-features = true } jsonrpsee = { version = "0.22", features = ["server"] } -futures = "0.3.21" +futures = "0.3.30" log = { workspace = true, default-features = true } rand = "0.8" @@ -129,7 +129,7 @@ sc-block-builder = { path = "../../../client/block-builder" } sp-tracing = { path = "../../../primitives/tracing" } sp-blockchain = { path = "../../../primitives/blockchain" } sp-crypto-hashing = { path = "../../../primitives/crypto/hashing" } -futures = "0.3.21" +futures = "0.3.30" tempfile = "3.1.0" assert_cmd = "2.0.2" nix = { version = "0.26.1", features = ["signal"] } @@ -160,7 +160,7 @@ sp-externalities = { path = "../../../primitives/externalities" } sp-keyring = { path = "../../../primitives/keyring" } sp-runtime = { path = "../../../primitives/runtime" } serde_json = { workspace = true, default-features = true } -scale-info = { version = "2.10.0", features = ["derive", "serde"] } +scale-info = { version = "2.11.1", features = ["derive", "serde"] } sp-trie = { path = "../../../primitives/trie" } sp-state-machine = { path = "../../../primitives/state-machine" } diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index 4d342ceb460..8f68b1d3e2f 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -23,7 +23,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", "max-encoded-len", ] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } static_assertions = "1.1.0" log = { workspace = true } serde_json = { features = ["alloc", "arbitrary_precision"], workspace = true } diff --git a/substrate/bin/node/testing/Cargo.toml b/substrate/bin/node/testing/Cargo.toml index 31f8689d46c..fa3f90193ba 100644 --- a/substrate/bin/node/testing/Cargo.toml +++ b/substrate/bin/node/testing/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } fs_extra = "1" -futures = "0.3.21" +futures = "0.3.30" log = { workspace = true, default-features = true } tempfile = "3.1.0" frame-system = { path = "../../../frame/system" } diff --git a/substrate/client/api/Cargo.toml b/substrate/client/api/Cargo.toml index cd7b613e277..fb650c5b532 100644 --- a/substrate/client/api/Cargo.toml +++ b/substrate/client/api/Cargo.toml @@ -21,7 +21,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } fnv = "1.0.6" -futures = "0.3.21" +futures = "0.3.30" log = { workspace = true, default-features = true } parking_lot = "0.12.1" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } diff --git a/substrate/client/authority-discovery/Cargo.toml b/substrate/client/authority-discovery/Cargo.toml index 26580064b3c..dbd9ba0131a 100644 --- a/substrate/client/authority-discovery/Cargo.toml +++ b/substrate/client/authority-discovery/Cargo.toml @@ -21,7 +21,7 @@ prost-build = "0.11" [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.1" ip_network = "0.4.1" libp2p = { version = "0.51.4", features = ["ed25519", "kad"] } @@ -43,7 +43,7 @@ sp-blockchain = { path = "../../primitives/blockchain" } sp-core = { path = "../../primitives/core" } sp-keystore = { path = "../../primitives/keystore" } sp-runtime = { path = "../../primitives/runtime" } -async-trait = "0.1.74" +async-trait = "0.1.79" multihash-codetable = { version = "0.1.1", features = [ "digest", "serde", diff --git a/substrate/client/basic-authorship/Cargo.toml b/substrate/client/basic-authorship/Cargo.toml index 51a06464d0d..4890b66c9b2 100644 --- a/substrate/client/basic-authorship/Cargo.toml +++ b/substrate/client/basic-authorship/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.1" log = { workspace = true, default-features = true } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index 47b29555e66..805d3ee117f 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -20,7 +20,7 @@ array-bytes = "6.1" chrono = "0.4.31" clap = { version = "4.5.3", features = ["derive", "string", "wrap_help"] } fdlimit = "0.3.0" -futures = "0.3.21" +futures = "0.3.30" itertools = "0.10.3" libp2p-identity = { version = "0.1.3", features = ["ed25519", "peerid"] } log = { workspace = true, default-features = true } diff --git a/substrate/client/consensus/aura/Cargo.toml b/substrate/client/consensus/aura/Cargo.toml index 213f75974da..64e2d16cd91 100644 --- a/substrate/client/consensus/aura/Cargo.toml +++ b/substrate/client/consensus/aura/Cargo.toml @@ -16,9 +16,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.6.1" } -futures = "0.3.21" +futures = "0.3.30" log = { workspace = true, default-features = true } thiserror = { workspace = true } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } diff --git a/substrate/client/consensus/babe/Cargo.toml b/substrate/client/consensus/babe/Cargo.toml index c98fb7112b7..b001e3d117a 100644 --- a/substrate/client/consensus/babe/Cargo.toml +++ b/substrate/client/consensus/babe/Cargo.toml @@ -17,9 +17,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } -futures = "0.3.21" +futures = "0.3.30" log = { workspace = true, default-features = true } num-bigint = "0.4.3" num-rational = "0.4.1" @@ -54,4 +54,4 @@ sc-network-test = { path = "../../network/test" } sp-timestamp = { path = "../../../primitives/timestamp" } sp-tracing = { path = "../../../primitives/tracing" } substrate-test-runtime-client = { path = "../../../test-utils/runtime/client" } -tokio = "1.22.0" +tokio = "1.37" diff --git a/substrate/client/consensus/babe/rpc/Cargo.toml b/substrate/client/consensus/babe/rpc/Cargo.toml index 043b566673e..b2661bbde27 100644 --- a/substrate/client/consensus/babe/rpc/Cargo.toml +++ b/substrate/client/consensus/babe/rpc/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } -futures = "0.3.21" +futures = "0.3.30" serde = { features = ["derive"], workspace = true, default-features = true } thiserror = { workspace = true } sc-consensus-babe = { path = ".." } @@ -34,7 +34,7 @@ sp-runtime = { path = "../../../../primitives/runtime" } [dev-dependencies] serde_json = { workspace = true, default-features = true } -tokio = "1.22.0" +tokio = "1.37" sc-consensus = { path = "../../common" } sc-keystore = { path = "../../../keystore" } sc-transaction-pool-api = { path = "../../../transaction-pool/api" } diff --git a/substrate/client/consensus/beefy/Cargo.toml b/substrate/client/consensus/beefy/Cargo.toml index 8552a490022..c1d57baa394 100644 --- a/substrate/client/consensus/beefy/Cargo.toml +++ b/substrate/client/consensus/beefy/Cargo.toml @@ -14,10 +14,10 @@ workspace = true [dependencies] array-bytes = "6.1" async-channel = "1.8.0" -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } fnv = "1.0.6" -futures = "0.3" +futures = "0.3.30" log = { workspace = true, default-features = true } parking_lot = "0.12.1" thiserror = { workspace = true } @@ -40,7 +40,7 @@ sp-crypto-hashing = { path = "../../../primitives/crypto/hashing" } sp-keystore = { path = "../../../primitives/keystore" } sp-mmr-primitives = { path = "../../../primitives/merkle-mountain-range" } sp-runtime = { path = "../../../primitives/runtime" } -tokio = "1.22.0" +tokio = "1.37" [dev-dependencies] diff --git a/substrate/client/consensus/beefy/rpc/Cargo.toml b/substrate/client/consensus/beefy/rpc/Cargo.toml index bb2ae4a0896..e46fc4f4410 100644 --- a/substrate/client/consensus/beefy/rpc/Cargo.toml +++ b/substrate/client/consensus/beefy/rpc/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } -futures = "0.3.21" +futures = "0.3.30" jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } log = { workspace = true, default-features = true } parking_lot = "0.12.1" diff --git a/substrate/client/consensus/common/Cargo.toml b/substrate/client/consensus/common/Cargo.toml index f691e84717d..b2738a1d12d 100644 --- a/substrate/client/consensus/common/Cargo.toml +++ b/substrate/client/consensus/common/Cargo.toml @@ -16,8 +16,8 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.74" -futures = { version = "0.3.21", features = ["thread-pool"] } +async-trait = "0.1.79" +futures = { version = "0.3.30", features = ["thread-pool"] } futures-timer = "3.0.1" libp2p-identity = { version = "0.1.3", features = ["ed25519", "peerid"] } log = { workspace = true, default-features = true } diff --git a/substrate/client/consensus/grandpa/Cargo.toml b/substrate/client/consensus/grandpa/Cargo.toml index 1ab95352522..797b4ea35b2 100644 --- a/substrate/client/consensus/grandpa/Cargo.toml +++ b/substrate/client/consensus/grandpa/Cargo.toml @@ -19,10 +19,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] ahash = "0.8.2" array-bytes = "6.1" -async-trait = "0.1.74" +async-trait = "0.1.79" dyn-clone = "1.0" finality-grandpa = { version = "0.16.2", features = ["derive-codec"] } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.1" log = { workspace = true, default-features = true } parity-scale-codec = { version = "3.6.1", features = ["derive"] } @@ -58,7 +58,7 @@ sp-runtime = { path = "../../../primitives/runtime" } assert_matches = "1.3.0" finality-grandpa = { version = "0.16.2", features = ["derive-codec", "test-helpers"] } serde = { workspace = true, default-features = true } -tokio = "1.22.0" +tokio = "1.37" sc-network = { path = "../../network" } sc-network-test = { path = "../../network/test" } sp-keyring = { path = "../../../primitives/keyring" } diff --git a/substrate/client/consensus/grandpa/rpc/Cargo.toml b/substrate/client/consensus/grandpa/rpc/Cargo.toml index f7e87415448..0789a429ac4 100644 --- a/substrate/client/consensus/grandpa/rpc/Cargo.toml +++ b/substrate/client/consensus/grandpa/rpc/Cargo.toml @@ -14,7 +14,7 @@ workspace = true [dependencies] finality-grandpa = { version = "0.16.2", features = ["derive-codec"] } -futures = "0.3.16" +futures = "0.3.30" jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } log = { workspace = true, default-features = true } parity-scale-codec = { version = "3.6.1", features = ["derive"] } diff --git a/substrate/client/consensus/manual-seal/Cargo.toml b/substrate/client/consensus/manual-seal/Cargo.toml index ac32fed7228..1422d46105b 100644 --- a/substrate/client/consensus/manual-seal/Cargo.toml +++ b/substrate/client/consensus/manual-seal/Cargo.toml @@ -18,9 +18,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } assert_matches = "1.3.0" -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.6.1" } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.1" log = { workspace = true, default-features = true } serde = { features = ["derive"], workspace = true, default-features = true } diff --git a/substrate/client/consensus/pow/Cargo.toml b/substrate/client/consensus/pow/Cargo.toml index 0791514035b..ecfa29aa194 100644 --- a/substrate/client/consensus/pow/Cargo.toml +++ b/substrate/client/consensus/pow/Cargo.toml @@ -16,9 +16,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.1" log = { workspace = true, default-features = true } parking_lot = "0.12.1" diff --git a/substrate/client/consensus/slots/Cargo.toml b/substrate/client/consensus/slots/Cargo.toml index 75f8b29a2fd..4ac6ce90713 100644 --- a/substrate/client/consensus/slots/Cargo.toml +++ b/substrate/client/consensus/slots/Cargo.toml @@ -17,9 +17,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.6.1" } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.1" log = { workspace = true, default-features = true } sc-client-api = { path = "../../api" } diff --git a/substrate/client/executor/Cargo.toml b/substrate/client/executor/Cargo.toml index 7fad7e3a2a0..cb0befe9871 100644 --- a/substrate/client/executor/Cargo.toml +++ b/substrate/client/executor/Cargo.toml @@ -51,7 +51,7 @@ tracing-subscriber = "0.2.19" paste = "1.0" regex = "1.6.0" criterion = "0.4.0" -env_logger = "0.9" +env_logger = "0.11" num_cpus = "1.13.1" tempfile = "3.3.0" diff --git a/substrate/client/informant/Cargo.toml b/substrate/client/informant/Cargo.toml index bd15e94ebaf..191ef5f19f8 100644 --- a/substrate/client/informant/Cargo.toml +++ b/substrate/client/informant/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] ansi_term = "0.12.1" -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.1" log = { workspace = true, default-features = true } sc-client-api = { path = "../api" } diff --git a/substrate/client/merkle-mountain-range/Cargo.toml b/substrate/client/merkle-mountain-range/Cargo.toml index 60232bccb0e..46b7a1011c4 100644 --- a/substrate/client/merkle-mountain-range/Cargo.toml +++ b/substrate/client/merkle-mountain-range/Cargo.toml @@ -15,7 +15,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -futures = "0.3" +futures = "0.3.30" log = { workspace = true, default-features = true } sp-api = { path = "../../primitives/api" } sp-blockchain = { path = "../../primitives/blockchain" } @@ -32,4 +32,4 @@ parking_lot = "0.12.1" sc-block-builder = { path = "../block-builder" } sp-tracing = { path = "../../primitives/tracing" } substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } -tokio = "1.17.0" +tokio = "1.37" diff --git a/substrate/client/mixnet/Cargo.toml b/substrate/client/mixnet/Cargo.toml index 736184f4668..3beeae9f9b1 100644 --- a/substrate/client/mixnet/Cargo.toml +++ b/substrate/client/mixnet/Cargo.toml @@ -21,7 +21,7 @@ arrayvec = "0.7.2" blake2 = "0.10.4" bytes = "1" codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -futures = "0.3.25" +futures = "0.3.30" futures-timer = "3.0.2" libp2p-identity = { version = "0.1.3", features = ["peerid"] } log = { workspace = true, default-features = true } diff --git a/substrate/client/network-gossip/Cargo.toml b/substrate/client/network-gossip/Cargo.toml index a14761c0d6e..346e6bd6a5c 100644 --- a/substrate/client/network-gossip/Cargo.toml +++ b/substrate/client/network-gossip/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] ahash = "0.8.2" -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.1" libp2p = "0.51.4" log = { workspace = true, default-features = true } @@ -31,8 +31,8 @@ sc-network-sync = { path = "../network/sync" } sp-runtime = { path = "../../primitives/runtime" } [dev-dependencies] -tokio = "1.22.0" -async-trait = "0.1.74" +tokio = "1.37" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } quickcheck = { version = "1.0.3", default-features = false } substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } diff --git a/substrate/client/network/Cargo.toml b/substrate/client/network/Cargo.toml index c6f17647166..a891336d241 100644 --- a/substrate/client/network/Cargo.toml +++ b/substrate/client/network/Cargo.toml @@ -19,13 +19,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = "6.1" async-channel = "1.8.0" -async-trait = "0.1" +async-trait = "0.1.79" asynchronous-codec = "0.6" bytes = "1" codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } either = "1.5.3" fnv = "1.0.6" -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" ip_network = "0.4.1" libp2p = { version = "0.51.4", features = ["dns", "identify", "kad", "macros", "mdns", "noise", "ping", "request-response", "tcp", "tokio", "websocket", "yamux"] } diff --git a/substrate/client/network/bitswap/Cargo.toml b/substrate/client/network/bitswap/Cargo.toml index 7ef3ea21242..587e2e70867 100644 --- a/substrate/client/network/bitswap/Cargo.toml +++ b/substrate/client/network/bitswap/Cargo.toml @@ -21,7 +21,7 @@ prost-build = "0.11" [dependencies] async-channel = "1.8.0" cid = "0.9.0" -futures = "0.3.21" +futures = "0.3.30" libp2p-identity = { version = "0.1.3", features = ["peerid"] } log = { workspace = true, default-features = true } prost = "0.12" diff --git a/substrate/client/network/common/Cargo.toml b/substrate/client/network/common/Cargo.toml index 7a6d904b74b..f9248b0bb51 100644 --- a/substrate/client/network/common/Cargo.toml +++ b/substrate/client/network/common/Cargo.toml @@ -19,12 +19,12 @@ targets = ["x86_64-unknown-linux-gnu"] prost-build = "0.11" [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" bitflags = "1.3.2" codec = { package = "parity-scale-codec", version = "3.6.1", features = [ "derive", ] } -futures = "0.3.21" +futures = "0.3.30" libp2p-identity = { version = "0.1.3", features = ["peerid"] } sc-consensus = { path = "../../consensus/common" } sp-consensus = { path = "../../../primitives/consensus/common" } diff --git a/substrate/client/network/light/Cargo.toml b/substrate/client/network/light/Cargo.toml index c757f727fb7..2628fd07d3e 100644 --- a/substrate/client/network/light/Cargo.toml +++ b/substrate/client/network/light/Cargo.toml @@ -24,7 +24,7 @@ array-bytes = "6.1" codec = { package = "parity-scale-codec", version = "3.6.1", features = [ "derive", ] } -futures = "0.3.21" +futures = "0.3.30" libp2p-identity = { version = "0.1.3", features = ["peerid"] } log = { workspace = true, default-features = true } prost = "0.12" diff --git a/substrate/client/network/statement/Cargo.toml b/substrate/client/network/statement/Cargo.toml index b6efee5d9d3..635cfc5d0d5 100644 --- a/substrate/client/network/statement/Cargo.toml +++ b/substrate/client/network/statement/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] array-bytes = "6.1" async-channel = "1.8.0" codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } -futures = "0.3.21" +futures = "0.3.30" libp2p = "0.51.4" log = { workspace = true, default-features = true } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } diff --git a/substrate/client/network/sync/Cargo.toml b/substrate/client/network/sync/Cargo.toml index 32ba3b6356c..6b46d67a3ca 100644 --- a/substrate/client/network/sync/Cargo.toml +++ b/substrate/client/network/sync/Cargo.toml @@ -21,9 +21,9 @@ prost-build = "0.11" [dependencies] array-bytes = "6.1" async-channel = "1.8.0" -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" libp2p = "0.51.4" log = { workspace = true, default-features = true } diff --git a/substrate/client/network/test/Cargo.toml b/substrate/client/network/test/Cargo.toml index 4f57287a39c..56fc89e1b2b 100644 --- a/substrate/client/network/test/Cargo.toml +++ b/substrate/client/network/test/Cargo.toml @@ -16,9 +16,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -tokio = "1.22.0" -async-trait = "0.1.74" -futures = "0.3.21" +tokio = "1.37" +async-trait = "0.1.79" +futures = "0.3.30" futures-timer = "3.0.1" libp2p = "0.51.4" log = { workspace = true, default-features = true } diff --git a/substrate/client/network/transactions/Cargo.toml b/substrate/client/network/transactions/Cargo.toml index 01c8ac8814d..0ab7386ef21 100644 --- a/substrate/client/network/transactions/Cargo.toml +++ b/substrate/client/network/transactions/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = "6.1" codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } -futures = "0.3.21" +futures = "0.3.30" libp2p = "0.51.4" log = { workspace = true, default-features = true } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } diff --git a/substrate/client/offchain/Cargo.toml b/substrate/client/offchain/Cargo.toml index caa4bb03f40..a3a3cfaa8fc 100644 --- a/substrate/client/offchain/Cargo.toml +++ b/substrate/client/offchain/Cargo.toml @@ -20,7 +20,7 @@ array-bytes = "6.1" bytes = "1.1" codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } fnv = "1.0.6" -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" hyper = { version = "0.14.16", features = ["http2", "stream"] } hyper-rustls = { version = "0.24.0", features = ["http2"] } @@ -46,7 +46,7 @@ log = { workspace = true, default-features = true } [dev-dependencies] lazy_static = "1.4.0" -tokio = "1.22.0" +tokio = "1.37" sc-block-builder = { path = "../block-builder" } sc-client-db = { path = "../db", default-features = true } sc-transaction-pool = { path = "../transaction-pool" } diff --git a/substrate/client/rpc-api/Cargo.toml b/substrate/client/rpc-api/Cargo.toml index 1b7af6a4a52..169714d2245 100644 --- a/substrate/client/rpc-api/Cargo.toml +++ b/substrate/client/rpc-api/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["derive"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } thiserror = { workspace = true } diff --git a/substrate/client/rpc-servers/Cargo.toml b/substrate/client/rpc-servers/Cargo.toml index 3adc81c57d5..bc21b5b1582 100644 --- a/substrate/client/rpc-servers/Cargo.toml +++ b/substrate/client/rpc-servers/Cargo.toml @@ -25,5 +25,5 @@ tower-http = { version = "0.4.0", features = ["cors"] } tower = { version = "0.4.13", features = ["util"] } http = "0.2.8" hyper = "0.14.27" -futures = "0.3.29" +futures = "0.3.30" governor = "0.6.0" diff --git a/substrate/client/rpc-spec-v2/Cargo.toml b/substrate/client/rpc-spec-v2/Cargo.toml index 937e5c6b626..e2612d91454 100644 --- a/substrate/client/rpc-spec-v2/Cargo.toml +++ b/substrate/client/rpc-spec-v2/Cargo.toml @@ -34,7 +34,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1" } thiserror = { workspace = true } serde = { workspace = true, default-features = true } hex = "0.4" -futures = "0.3.21" +futures = "0.3.30" parking_lot = "0.12.1" tokio-stream = { version = "0.1.14", features = ["sync"] } tokio = { version = "1.22.0", features = ["sync"] } diff --git a/substrate/client/rpc/Cargo.toml b/substrate/client/rpc/Cargo.toml index f65e6c9a59e..dff34215b02 100644 --- a/substrate/client/rpc/Cargo.toml +++ b/substrate/client/rpc/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -futures = "0.3.21" +futures = "0.3.30" jsonrpsee = { version = "0.22", features = ["server"] } log = { workspace = true, default-features = true } parking_lot = "0.12.1" @@ -40,10 +40,10 @@ sp-runtime = { path = "../../primitives/runtime" } sp-session = { path = "../../primitives/session" } sp-version = { path = "../../primitives/version" } sp-statement-store = { path = "../../primitives/statement-store" } -tokio = "1.22.0" +tokio = "1.37" [dev-dependencies] -env_logger = "0.9" +env_logger = "0.11" assert_matches = "1.3.0" sc-block-builder = { path = "../block-builder" } sc-network = { path = "../network" } @@ -51,7 +51,7 @@ sc-network-common = { path = "../network/common" } sc-transaction-pool = { path = "../transaction-pool" } sp-consensus = { path = "../../primitives/consensus/common" } sp-crypto-hashing = { path = "../../primitives/crypto/hashing" } -tokio = "1.22.0" +tokio = "1.37" sp-io = { path = "../../primitives/io" } substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } pretty_assertions = "1.2.1" diff --git a/substrate/client/service/Cargo.toml b/substrate/client/service/Cargo.toml index bbf67d1fbd0..b81f2e2f55a 100644 --- a/substrate/client/service/Cargo.toml +++ b/substrate/client/service/Cargo.toml @@ -30,7 +30,7 @@ runtime-benchmarks = [ [dependencies] jsonrpsee = { version = "0.22", features = ["server"] } thiserror = { workspace = true } -futures = "0.3.21" +futures = "0.3.30" rand = "0.8.5" parking_lot = "0.12.1" log = { workspace = true, default-features = true } @@ -79,7 +79,7 @@ sc-tracing = { path = "../tracing" } sc-sysinfo = { path = "../sysinfo" } tracing = "0.1.29" tracing-futures = { version = "0.2.4" } -async-trait = "0.1.74" +async-trait = "0.1.79" tokio = { version = "1.22.0", features = ["parking_lot", "rt-multi-thread", "time"] } tempfile = "3.1.0" directories = "5.0.1" diff --git a/substrate/client/service/test/Cargo.toml b/substrate/client/service/test/Cargo.toml index ee7e60f6011..2de984689ba 100644 --- a/substrate/client/service/test/Cargo.toml +++ b/substrate/client/service/test/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] async-channel = "1.8.0" array-bytes = "6.1" fdlimit = "0.3.0" -futures = "0.3.21" +futures = "0.3.30" log = { workspace = true, default-features = true } parity-scale-codec = "3.6.1" parking_lot = "0.12.1" diff --git a/substrate/client/statement-store/Cargo.toml b/substrate/client/statement-store/Cargo.toml index 676f6cb36f6..8ca6d11dbe0 100644 --- a/substrate/client/statement-store/Cargo.toml +++ b/substrate/client/statement-store/Cargo.toml @@ -31,4 +31,4 @@ sc-keystore = { path = "../keystore" } [dev-dependencies] tempfile = "3.1.0" -env_logger = "0.9" +env_logger = "0.11" diff --git a/substrate/client/sysinfo/Cargo.toml b/substrate/client/sysinfo/Cargo.toml index ba58452ffb5..32b7755c64b 100644 --- a/substrate/client/sysinfo/Cargo.toml +++ b/substrate/client/sysinfo/Cargo.toml @@ -17,7 +17,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -futures = "0.3.19" +futures = "0.3.30" libc = "0.2" log = { workspace = true, default-features = true } rand = "0.8.5" diff --git a/substrate/client/telemetry/Cargo.toml b/substrate/client/telemetry/Cargo.toml index 8ab00202f0b..9a29a33a591 100644 --- a/substrate/client/telemetry/Cargo.toml +++ b/substrate/client/telemetry/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] chrono = "0.4.31" -futures = "0.3.21" +futures = "0.3.30" libp2p = { version = "0.51.4", features = ["dns", "tcp", "tokio", "wasm-ext", "websocket"] } log = { workspace = true, default-features = true } parking_lot = "0.12.1" diff --git a/substrate/client/transaction-pool/Cargo.toml b/substrate/client/transaction-pool/Cargo.toml index 2ca37afd61b..e2a0b87eaab 100644 --- a/substrate/client/transaction-pool/Cargo.toml +++ b/substrate/client/transaction-pool/Cargo.toml @@ -16,9 +16,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.6.1" } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" linked-hash-map = "0.5.4" log = { workspace = true, default-features = true } diff --git a/substrate/client/transaction-pool/api/Cargo.toml b/substrate/client/transaction-pool/api/Cargo.toml index d52e4783fab..1bb72ef5544 100644 --- a/substrate/client/transaction-pool/api/Cargo.toml +++ b/substrate/client/transaction-pool/api/Cargo.toml @@ -12,9 +12,9 @@ description = "Transaction pool client facing API." workspace = true [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.6.1" } -futures = "0.3.21" +futures = "0.3.30" log = { workspace = true, default-features = true } serde = { features = ["derive"], workspace = true, default-features = true } thiserror = { workspace = true } diff --git a/substrate/client/utils/Cargo.toml b/substrate/client/utils/Cargo.toml index 7f604219bc0..a101f4b3f3a 100644 --- a/substrate/client/utils/Cargo.toml +++ b/substrate/client/utils/Cargo.toml @@ -14,7 +14,7 @@ workspace = true [dependencies] async-channel = "1.8.0" -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" lazy_static = "1.4.0" log = { workspace = true, default-features = true } diff --git a/substrate/frame/Cargo.toml b/substrate/frame/Cargo.toml index ab394592071..27001ee5afd 100644 --- a/substrate/frame/Cargo.toml +++ b/substrate/frame/Cargo.toml @@ -22,7 +22,7 @@ targets = ["x86_64-unknown-linux-gnu"] parity-scale-codec = { version = "3.2.2", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.6.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } diff --git a/substrate/frame/alliance/Cargo.toml b/substrate/frame/alliance/Cargo.toml index bc873ad69c8..af1fcb296f6 100644 --- a/substrate/frame/alliance/Cargo.toml +++ b/substrate/frame/alliance/Cargo.toml @@ -20,7 +20,7 @@ array-bytes = { version = "6.1", optional = true } log = { workspace = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-std = { path = "../../primitives/std", default-features = false } sp-core = { path = "../../primitives/core", default-features = false } diff --git a/substrate/frame/asset-conversion/Cargo.toml b/substrate/frame/asset-conversion/Cargo.toml index 1f2db14dac2..1a8e8eea484 100644 --- a/substrate/frame/asset-conversion/Cargo.toml +++ b/substrate/frame/asset-conversion/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-api = { path = "../../primitives/api", default-features = false } sp-core = { path = "../../primitives/core", default-features = false } sp-io = { path = "../../primitives/io", default-features = false } diff --git a/substrate/frame/asset-rate/Cargo.toml b/substrate/frame/asset-rate/Cargo.toml index 6e7bbf29fc4..cd502148a8d 100644 --- a/substrate/frame/asset-rate/Cargo.toml +++ b/substrate/frame/asset-rate/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/assets/Cargo.toml b/substrate/frame/assets/Cargo.toml index 2efc96348cb..3b95750c14c 100644 --- a/substrate/frame/assets/Cargo.toml +++ b/substrate/frame/assets/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-std = { path = "../../primitives/std", default-features = false } # Needed for various traits. In our case, `OnFinalize`. sp-runtime = { path = "../../primitives/runtime", default-features = false } diff --git a/substrate/frame/atomic-swap/Cargo.toml b/substrate/frame/atomic-swap/Cargo.toml index 0283af1d1b0..c641071df90 100644 --- a/substrate/frame/atomic-swap/Cargo.toml +++ b/substrate/frame/atomic-swap/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } sp-core = { path = "../../primitives/core", default-features = false } diff --git a/substrate/frame/aura/Cargo.toml b/substrate/frame/aura/Cargo.toml index de698487efa..97349107f1f 100644 --- a/substrate/frame/aura/Cargo.toml +++ b/substrate/frame/aura/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } pallet-timestamp = { path = "../timestamp", default-features = false } diff --git a/substrate/frame/authority-discovery/Cargo.toml b/substrate/frame/authority-discovery/Cargo.toml index 0922007e57e..a7aba711a56 100644 --- a/substrate/frame/authority-discovery/Cargo.toml +++ b/substrate/frame/authority-discovery/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } pallet-session = { path = "../session", default-features = false, features = [ diff --git a/substrate/frame/authorship/Cargo.toml b/substrate/frame/authorship/Cargo.toml index 4b318f12519..2bfd59a48e1 100644 --- a/substrate/frame/authorship/Cargo.toml +++ b/substrate/frame/authorship/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } impl-trait-for-tuples = "0.2.2" -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false } diff --git a/substrate/frame/babe/Cargo.toml b/substrate/frame/babe/Cargo.toml index fc7385efa1f..9f6ef2bc05e 100644 --- a/substrate/frame/babe/Cargo.toml +++ b/substrate/frame/babe/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/bags-list/Cargo.toml b/substrate/frame/bags-list/Cargo.toml index 49d28482c32..5deb504d0a4 100644 --- a/substrate/frame/bags-list/Cargo.toml +++ b/substrate/frame/bags-list/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } diff --git a/substrate/frame/balances/Cargo.toml b/substrate/frame/balances/Cargo.toml index b27a5bb2478..28eabdaf506 100644 --- a/substrate/frame/balances/Cargo.toml +++ b/substrate/frame/balances/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/beefy-mmr/Cargo.toml b/substrate/frame/beefy-mmr/Cargo.toml index 17707731773..8fcb8e1d559 100644 --- a/substrate/frame/beefy-mmr/Cargo.toml +++ b/substrate/frame/beefy-mmr/Cargo.toml @@ -15,7 +15,7 @@ workspace = true array-bytes = { version = "6.1", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, workspace = true, default-features = true } binary-merkle-tree = { path = "../../utils/binary-merkle-tree", default-features = false } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/beefy/Cargo.toml b/substrate/frame/beefy/Cargo.toml index e38eaa6fb07..f181f4d41cd 100644 --- a/substrate/frame/beefy/Cargo.toml +++ b/substrate/frame/beefy/Cargo.toml @@ -14,7 +14,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } serde = { optional = true, workspace = true, default-features = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/benchmarking/Cargo.toml b/substrate/frame/benchmarking/Cargo.toml index bf42aae979c..8210e8cfa62 100644 --- a/substrate/frame/benchmarking/Cargo.toml +++ b/substrate/frame/benchmarking/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = linregress = { version = "0.5.1", optional = true } log = { workspace = true } paste = "1.0" -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, workspace = true, default-features = true } frame-support = { path = "../support", default-features = false } frame-support-procedural = { path = "../support/procedural", default-features = false } diff --git a/substrate/frame/benchmarking/pov/Cargo.toml b/substrate/frame/benchmarking/pov/Cargo.toml index ce5daeb5b7b..5d3aaa78904 100644 --- a/substrate/frame/benchmarking/pov/Cargo.toml +++ b/substrate/frame/benchmarking/pov/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "..", default-features = false } frame-support = { path = "../../support", default-features = false } frame-system = { path = "../../system", default-features = false } diff --git a/substrate/frame/bounties/Cargo.toml b/substrate/frame/bounties/Cargo.toml index 191a38d20b2..3307e47e981 100644 --- a/substrate/frame/bounties/Cargo.toml +++ b/substrate/frame/bounties/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/broker/Cargo.toml b/substrate/frame/broker/Cargo.toml index 31f9a6b6317..3b6bd2019cc 100644 --- a/substrate/frame/broker/Cargo.toml +++ b/substrate/frame/broker/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } bitvec = { version = "1.0.0", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false } diff --git a/substrate/frame/child-bounties/Cargo.toml b/substrate/frame/child-bounties/Cargo.toml index 589ca95a751..14a5e25e13d 100644 --- a/substrate/frame/child-bounties/Cargo.toml +++ b/substrate/frame/child-bounties/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/collective/Cargo.toml b/substrate/frame/collective/Cargo.toml index e19e1496e7b..850390409ab 100644 --- a/substrate/frame/collective/Cargo.toml +++ b/substrate/frame/collective/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/contracts/Cargo.toml b/substrate/frame/contracts/Cargo.toml index 2aa37a2bf21..d963ac261d1 100644 --- a/substrate/frame/contracts/Cargo.toml +++ b/substrate/frame/contracts/Cargo.toml @@ -24,7 +24,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", "max-encoded-len", ] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } log = { workspace = true } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } smallvec = { version = "1", default-features = false, features = [ @@ -58,7 +58,7 @@ xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/x [dev-dependencies] array-bytes = "6.1" assert_matches = "1" -env_logger = "0.9" +env_logger = "0.11" pretty_assertions = "1" wat = "1" pallet-contracts-fixtures = { path = "./fixtures" } diff --git a/substrate/frame/contracts/mock-network/Cargo.toml b/substrate/frame/contracts/mock-network/Cargo.toml index 0c4cd1356f4..387c3ca39d0 100644 --- a/substrate/frame/contracts/mock-network/Cargo.toml +++ b/substrate/frame/contracts/mock-network/Cargo.toml @@ -30,7 +30,7 @@ pallet-xcm = { path = "../../../../polkadot/xcm/pallet-xcm", default-features = polkadot-parachain-primitives = { path = "../../../../polkadot/parachain" } polkadot-primitives = { path = "../../../../polkadot/primitives" } polkadot-runtime-parachains = { path = "../../../../polkadot/runtime/parachains" } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-api = { path = "../../../primitives/api", default-features = false } sp-core = { path = "../../../primitives/core", default-features = false } sp-io = { path = "../../../primitives/io", default-features = false } diff --git a/substrate/frame/contracts/uapi/Cargo.toml b/substrate/frame/contracts/uapi/Cargo.toml index 12bb6b8fc2c..d9a5ee14f05 100644 --- a/substrate/frame/contracts/uapi/Cargo.toml +++ b/substrate/frame/contracts/uapi/Cargo.toml @@ -14,7 +14,7 @@ workspace = true [dependencies] paste = { version = "1.0", default-features = false } bitflags = "1.0" -scale-info = { version = "2.10.0", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"], optional = true } scale = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", "max-encoded-len", diff --git a/substrate/frame/conviction-voting/Cargo.toml b/substrate/frame/conviction-voting/Cargo.toml index ff5af995026..ffb5122ed7f 100644 --- a/substrate/frame/conviction-voting/Cargo.toml +++ b/substrate/frame/conviction-voting/Cargo.toml @@ -21,7 +21,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", "max-encoded-len", ] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["derive"], optional = true, workspace = true, default-features = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/core-fellowship/Cargo.toml b/substrate/frame/core-fellowship/Cargo.toml index 3e678d32744..b4258281b70 100644 --- a/substrate/frame/core-fellowship/Cargo.toml +++ b/substrate/frame/core-fellowship/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/democracy/Cargo.toml b/substrate/frame/democracy/Cargo.toml index 9a55cda5340..edd2d742b50 100644 --- a/substrate/frame/democracy/Cargo.toml +++ b/substrate/frame/democracy/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["derive"], optional = true, workspace = true, default-features = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/election-provider-multi-phase/Cargo.toml b/substrate/frame/election-provider-multi-phase/Cargo.toml index eadce8c1ff8..2074b51f50f 100644 --- a/substrate/frame/election-provider-multi-phase/Cargo.toml +++ b/substrate/frame/election-provider-multi-phase/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } log = { workspace = true } @@ -38,7 +38,7 @@ frame-election-provider-support = { path = "../election-provider-support", defau frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } pallet-election-provider-support-benchmarking = { path = "../election-provider-support/benchmarking", default-features = false, optional = true } rand = { version = "0.8.5", default-features = false, features = ["alloc", "small_rng"], optional = true } -strum = { version = "0.24.1", default-features = false, features = ["derive"], optional = true } +strum = { version = "0.26.2", default-features = false, features = ["derive"], optional = true } [dev-dependencies] parking_lot = "0.12.1" diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml index e6384450a6f..25c280921f8 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dev-dependencies] parking_lot = "0.12.1" codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } -scale-info = { version = "2.10.0", features = ["derive"] } +scale-info = { version = "2.11.1", features = ["derive"] } log = { workspace = true } sp-runtime = { path = "../../../primitives/runtime" } diff --git a/substrate/frame/election-provider-support/Cargo.toml b/substrate/frame/election-provider-support/Cargo.toml index b182b831ea0..0d9748ee34e 100644 --- a/substrate/frame/election-provider-support/Cargo.toml +++ b/substrate/frame/election-provider-support/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-election-provider-solution-type = { path = "solution-type" } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/election-provider-support/solution-type/Cargo.toml b/substrate/frame/election-provider-support/solution-type/Cargo.toml index 1bf1165229a..09c6a492dd0 100644 --- a/substrate/frame/election-provider-support/solution-type/Cargo.toml +++ b/substrate/frame/election-provider-support/solution-type/Cargo.toml @@ -25,7 +25,7 @@ proc-macro-crate = "3.0.0" [dev-dependencies] parity-scale-codec = "3.6.1" -scale-info = "2.10.0" +scale-info = "2.11.1" sp-arithmetic = { path = "../../../primitives/arithmetic" } # used by generate_solution_type: frame-election-provider-support = { path = ".." } diff --git a/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml b/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml index a27f0f7d4dd..1fb9e2387ed 100644 --- a/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml +++ b/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml @@ -21,7 +21,7 @@ honggfuzz = "0.5" rand = { version = "0.8", features = ["small_rng", "std"] } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-election-provider-solution-type = { path = ".." } frame-election-provider-support = { path = "../.." } sp-arithmetic = { path = "../../../../primitives/arithmetic" } diff --git a/substrate/frame/elections-phragmen/Cargo.toml b/substrate/frame/elections-phragmen/Cargo.toml index 4dc4a3454aa..81dc48476a0 100644 --- a/substrate/frame/elections-phragmen/Cargo.toml +++ b/substrate/frame/elections-phragmen/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/examples/basic/Cargo.toml b/substrate/frame/examples/basic/Cargo.toml index e4ab5112201..43b37c6beba 100644 --- a/substrate/frame/examples/basic/Cargo.toml +++ b/substrate/frame/examples/basic/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true } frame-support = { path = "../../support", default-features = false } frame-system = { path = "../../system", default-features = false } diff --git a/substrate/frame/examples/default-config/Cargo.toml b/substrate/frame/examples/default-config/Cargo.toml index e40845a425a..2aa062ee6c1 100644 --- a/substrate/frame/examples/default-config/Cargo.toml +++ b/substrate/frame/examples/default-config/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false } frame-system = { path = "../../system", default-features = false } diff --git a/substrate/frame/examples/dev-mode/Cargo.toml b/substrate/frame/examples/dev-mode/Cargo.toml index a9c4e3f3b1f..71b97796ecd 100644 --- a/substrate/frame/examples/dev-mode/Cargo.toml +++ b/substrate/frame/examples/dev-mode/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false } frame-system = { path = "../../system", default-features = false } pallet-balances = { path = "../../balances", default-features = false } diff --git a/substrate/frame/examples/frame-crate/Cargo.toml b/substrate/frame/examples/frame-crate/Cargo.toml index 93a46ba7b24..76bfd65282a 100644 --- a/substrate/frame/examples/frame-crate/Cargo.toml +++ b/substrate/frame/examples/frame-crate/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame = { path = "../..", default-features = false, features = ["experimental", "runtime"] } diff --git a/substrate/frame/examples/kitchensink/Cargo.toml b/substrate/frame/examples/kitchensink/Cargo.toml index 37384107530..d8311897c6e 100644 --- a/substrate/frame/examples/kitchensink/Cargo.toml +++ b/substrate/frame/examples/kitchensink/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false, features = ["experimental"] } frame-system = { path = "../../system", default-features = false } diff --git a/substrate/frame/examples/offchain-worker/Cargo.toml b/substrate/frame/examples/offchain-worker/Cargo.toml index fc5151ff292..468af0345ca 100644 --- a/substrate/frame/examples/offchain-worker/Cargo.toml +++ b/substrate/frame/examples/offchain-worker/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } lite-json = { version = "0.2.0", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false } frame-system = { path = "../../system", default-features = false } sp-core = { path = "../../../primitives/core", default-features = false } diff --git a/substrate/frame/examples/single-block-migrations/Cargo.toml b/substrate/frame/examples/single-block-migrations/Cargo.toml index 1020cc9e2bb..b1d560a85f3 100644 --- a/substrate/frame/examples/single-block-migrations/Cargo.toml +++ b/substrate/frame/examples/single-block-migrations/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] docify = "0.2.8" log = { version = "0.4.21", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false } frame-executive = { path = "../../executive", default-features = false } frame-system = { path = "../../system", default-features = false } diff --git a/substrate/frame/examples/split/Cargo.toml b/substrate/frame/examples/split/Cargo.toml index 230dc980b1a..1ef3521e060 100644 --- a/substrate/frame/examples/split/Cargo.toml +++ b/substrate/frame/examples/split/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false } frame-system = { path = "../../system", default-features = false } diff --git a/substrate/frame/examples/tasks/Cargo.toml b/substrate/frame/examples/tasks/Cargo.toml index 4d14bf313d7..3f59d57ea0f 100644 --- a/substrate/frame/examples/tasks/Cargo.toml +++ b/substrate/frame/examples/tasks/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false } frame-system = { path = "../../system", default-features = false } diff --git a/substrate/frame/executive/Cargo.toml b/substrate/frame/executive/Cargo.toml index 63285e4cb49..95de7c3f3d1 100644 --- a/substrate/frame/executive/Cargo.toml +++ b/substrate/frame/executive/Cargo.toml @@ -21,7 +21,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } frame-try-runtime = { path = "../try-runtime", default-features = false, optional = true } diff --git a/substrate/frame/fast-unstake/Cargo.toml b/substrate/frame/fast-unstake/Cargo.toml index fb425dc310d..f05f22f7641 100644 --- a/substrate/frame/fast-unstake/Cargo.toml +++ b/substrate/frame/fast-unstake/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/glutton/Cargo.toml b/substrate/frame/glutton/Cargo.toml index 7de18080b87..5ce010f1c26 100644 --- a/substrate/frame/glutton/Cargo.toml +++ b/substrate/frame/glutton/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] blake2 = { version = "0.10.4", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } log = { workspace = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/grandpa/Cargo.toml b/substrate/frame/grandpa/Cargo.toml index db540564fbe..f4dd92129f3 100644 --- a/substrate/frame/grandpa/Cargo.toml +++ b/substrate/frame/grandpa/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/identity/Cargo.toml b/substrate/frame/identity/Cargo.toml index 912444bf603..8c0052004ae 100644 --- a/substrate/frame/identity/Cargo.toml +++ b/substrate/frame/identity/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } enumflags2 = { version = "0.7.7" } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/im-online/Cargo.toml b/substrate/frame/im-online/Cargo.toml index 038cbbcd678..46b416f0f9a 100644 --- a/substrate/frame/im-online/Cargo.toml +++ b/substrate/frame/im-online/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/indices/Cargo.toml b/substrate/frame/indices/Cargo.toml index f810ea36a70..7b14bf358f1 100644 --- a/substrate/frame/indices/Cargo.toml +++ b/substrate/frame/indices/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/insecure-randomness-collective-flip/Cargo.toml b/substrate/frame/insecure-randomness-collective-flip/Cargo.toml index f26bfa95bfd..f4d65d9e560 100644 --- a/substrate/frame/insecure-randomness-collective-flip/Cargo.toml +++ b/substrate/frame/insecure-randomness-collective-flip/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } safe-mix = { version = "1.0", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false } diff --git a/substrate/frame/lottery/Cargo.toml b/substrate/frame/lottery/Cargo.toml index 3930ff32fc9..5f79704445f 100644 --- a/substrate/frame/lottery/Cargo.toml +++ b/substrate/frame/lottery/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/membership/Cargo.toml b/substrate/frame/membership/Cargo.toml index 64214670292..6f67db0ae70 100644 --- a/substrate/frame/membership/Cargo.toml +++ b/substrate/frame/membership/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/merkle-mountain-range/Cargo.toml b/substrate/frame/merkle-mountain-range/Cargo.toml index d623e25cec2..6dc919e1650 100644 --- a/substrate/frame/merkle-mountain-range/Cargo.toml +++ b/substrate/frame/merkle-mountain-range/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } @@ -29,7 +29,7 @@ sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] array-bytes = "6.1" -env_logger = "0.9" +env_logger = "0.11" itertools = "0.10.3" [features] diff --git a/substrate/frame/message-queue/Cargo.toml b/substrate/frame/message-queue/Cargo.toml index 8d9da7df39e..f263c41831b 100644 --- a/substrate/frame/message-queue/Cargo.toml +++ b/substrate/frame/message-queue/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } log = { workspace = true } environmental = { version = "1.1.4", default-features = false } diff --git a/substrate/frame/migrations/Cargo.toml b/substrate/frame/migrations/Cargo.toml index 0a91d2f94c4..4726ac5c521 100644 --- a/substrate/frame/migrations/Cargo.toml +++ b/substrate/frame/migrations/Cargo.toml @@ -15,7 +15,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = docify = "0.2.8" impl-trait-for-tuples = "0.2.2" log = "0.4.21" -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { default-features = false, optional = true, path = "../benchmarking" } frame-support = { default-features = false, path = "../support" } diff --git a/substrate/frame/mixnet/Cargo.toml b/substrate/frame/mixnet/Cargo.toml index d1bb01dde1a..6a4ef5c29ac 100644 --- a/substrate/frame/mixnet/Cargo.toml +++ b/substrate/frame/mixnet/Cargo.toml @@ -21,7 +21,7 @@ frame-benchmarking = { default-features = false, optional = true, path = "../ben frame-support = { default-features = false, path = "../support" } frame-system = { default-features = false, path = "../system" } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["derive"], workspace = true } sp-application-crypto = { default-features = false, path = "../../primitives/application-crypto" } sp-arithmetic = { default-features = false, path = "../../primitives/arithmetic" } diff --git a/substrate/frame/multisig/Cargo.toml b/substrate/frame/multisig/Cargo.toml index 1d2a79bdc52..2437acbc2e2 100644 --- a/substrate/frame/multisig/Cargo.toml +++ b/substrate/frame/multisig/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/nft-fractionalization/Cargo.toml b/substrate/frame/nft-fractionalization/Cargo.toml index 8002b7e1165..b5a929468f7 100644 --- a/substrate/frame/nft-fractionalization/Cargo.toml +++ b/substrate/frame/nft-fractionalization/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/nfts/Cargo.toml b/substrate/frame/nfts/Cargo.toml index 69e9ea170b1..4f818ea3e08 100644 --- a/substrate/frame/nfts/Cargo.toml +++ b/substrate/frame/nfts/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } enumflags2 = { version = "0.7.7" } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/nis/Cargo.toml b/substrate/frame/nis/Cargo.toml index 025daa07b0c..d0ba74a9273 100644 --- a/substrate/frame/nis/Cargo.toml +++ b/substrate/frame/nis/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/node-authorization/Cargo.toml b/substrate/frame/node-authorization/Cargo.toml index a39b0ec4eff..63376163cdc 100644 --- a/substrate/frame/node-authorization/Cargo.toml +++ b/substrate/frame/node-authorization/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } sp-core = { path = "../../primitives/core", default-features = false } diff --git a/substrate/frame/nomination-pools/Cargo.toml b/substrate/frame/nomination-pools/Cargo.toml index 9830f31d5fa..55e9ef6fbd3 100644 --- a/substrate/frame/nomination-pools/Cargo.toml +++ b/substrate/frame/nomination-pools/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } diff --git a/substrate/frame/nomination-pools/benchmarking/Cargo.toml b/substrate/frame/nomination-pools/benchmarking/Cargo.toml index 3693ad1866d..4985d7acbec 100644 --- a/substrate/frame/nomination-pools/benchmarking/Cargo.toml +++ b/substrate/frame/nomination-pools/benchmarking/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # parity codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # FRAME frame-benchmarking = { path = "../../benchmarking", default-features = false } diff --git a/substrate/frame/nomination-pools/test-staking/Cargo.toml b/substrate/frame/nomination-pools/test-staking/Cargo.toml index 9c7b12e4c63..130a27752bf 100644 --- a/substrate/frame/nomination-pools/test-staking/Cargo.toml +++ b/substrate/frame/nomination-pools/test-staking/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dev-dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } -scale-info = { version = "2.10.0", features = ["derive"] } +scale-info = { version = "2.11.1", features = ["derive"] } sp-runtime = { path = "../../../primitives/runtime" } sp-io = { path = "../../../primitives/io" } diff --git a/substrate/frame/offences/Cargo.toml b/substrate/frame/offences/Cargo.toml index b3ef4671ce5..f8efc88bafc 100644 --- a/substrate/frame/offences/Cargo.toml +++ b/substrate/frame/offences/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, workspace = true, default-features = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/offences/benchmarking/Cargo.toml b/substrate/frame/offences/benchmarking/Cargo.toml index 8dcce84d257..07905a1e0aa 100644 --- a/substrate/frame/offences/benchmarking/Cargo.toml +++ b/substrate/frame/offences/benchmarking/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../../benchmarking", default-features = false } frame-election-provider-support = { path = "../../election-provider-support", default-features = false } frame-support = { path = "../../support", default-features = false } diff --git a/substrate/frame/paged-list/Cargo.toml b/substrate/frame/paged-list/Cargo.toml index bbe8e33d484..26f3d7e48ce 100644 --- a/substrate/frame/paged-list/Cargo.toml +++ b/substrate/frame/paged-list/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } docify = "0.2.8" -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/parameters/Cargo.toml b/substrate/frame/parameters/Cargo.toml index ab93be14e6c..2527bdf3a71 100644 --- a/substrate/frame/parameters/Cargo.toml +++ b/substrate/frame/parameters/Cargo.toml @@ -9,7 +9,7 @@ edition.workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["max-encoded-len"] } -scale-info = { version = "2.1.2", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } paste = { version = "1.0.14", default-features = false } serde = { features = ["derive"], optional = true, workspace = true, default-features = true } docify = "0.2.8" diff --git a/substrate/frame/preimage/Cargo.toml b/substrate/frame/preimage/Cargo.toml index 10a15f97bd5..d67fc7bead0 100644 --- a/substrate/frame/preimage/Cargo.toml +++ b/substrate/frame/preimage/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/proxy/Cargo.toml b/substrate/frame/proxy/Cargo.toml index 17930079afd..0a3b39e471d 100644 --- a/substrate/frame/proxy/Cargo.toml +++ b/substrate/frame/proxy/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["max-encoded-len"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/ranked-collective/Cargo.toml b/substrate/frame/ranked-collective/Cargo.toml index 54e84c0b558..0a659580775 100644 --- a/substrate/frame/ranked-collective/Cargo.toml +++ b/substrate/frame/ranked-collective/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/recovery/Cargo.toml b/substrate/frame/recovery/Cargo.toml index 421c7995137..43608de37fc 100644 --- a/substrate/frame/recovery/Cargo.toml +++ b/substrate/frame/recovery/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/referenda/Cargo.toml b/substrate/frame/referenda/Cargo.toml index 2dfb25a2fd3..f4e0171443a 100644 --- a/substrate/frame/referenda/Cargo.toml +++ b/substrate/frame/referenda/Cargo.toml @@ -20,7 +20,7 @@ assert_matches = { version = "1.5", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["derive"], optional = true, workspace = true, default-features = true } sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } diff --git a/substrate/frame/remark/Cargo.toml b/substrate/frame/remark/Cargo.toml index 45710f0539e..e746b0382ae 100644 --- a/substrate/frame/remark/Cargo.toml +++ b/substrate/frame/remark/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, workspace = true, default-features = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/root-offences/Cargo.toml b/substrate/frame/root-offences/Cargo.toml index 80b33095068..ad3dcf1f90e 100644 --- a/substrate/frame/root-offences/Cargo.toml +++ b/substrate/frame/root-offences/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } pallet-session = { path = "../session", default-features = false, features = ["historical"] } pallet-staking = { path = "../staking", default-features = false } diff --git a/substrate/frame/root-testing/Cargo.toml b/substrate/frame/root-testing/Cargo.toml index 51b72665b81..bf14516ee32 100644 --- a/substrate/frame/root-testing/Cargo.toml +++ b/substrate/frame/root-testing/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } sp-core = { path = "../../primitives/core", default-features = false } diff --git a/substrate/frame/safe-mode/Cargo.toml b/substrate/frame/safe-mode/Cargo.toml index 6ddeff263c1..b6b7e5a67e4 100644 --- a/substrate/frame/safe-mode/Cargo.toml +++ b/substrate/frame/safe-mode/Cargo.toml @@ -20,7 +20,7 @@ docify = "0.2.8" frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } diff --git a/substrate/frame/salary/Cargo.toml b/substrate/frame/salary/Cargo.toml index ba57fd46eeb..8c77edcb173 100644 --- a/substrate/frame/salary/Cargo.toml +++ b/substrate/frame/salary/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/sassafras/Cargo.toml b/substrate/frame/sassafras/Cargo.toml index 325a39bf597..09977142efc 100644 --- a/substrate/frame/sassafras/Cargo.toml +++ b/substrate/frame/sassafras/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] scale-codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/scheduler/Cargo.toml b/substrate/frame/scheduler/Cargo.toml index a3e684a2083..40a71736447 100644 --- a/substrate/frame/scheduler/Cargo.toml +++ b/substrate/frame/scheduler/Cargo.toml @@ -15,7 +15,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/scored-pool/Cargo.toml b/substrate/frame/scored-pool/Cargo.toml index ae6ade5189d..92b70e01b9a 100644 --- a/substrate/frame/scored-pool/Cargo.toml +++ b/substrate/frame/scored-pool/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } sp-io = { path = "../../primitives/io", default-features = false } diff --git a/substrate/frame/session/Cargo.toml b/substrate/frame/session/Cargo.toml index de041307f70..86814f8276e 100644 --- a/substrate/frame/session/Cargo.toml +++ b/substrate/frame/session/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } pallet-timestamp = { path = "../timestamp", default-features = false } diff --git a/substrate/frame/session/benchmarking/Cargo.toml b/substrate/frame/session/benchmarking/Cargo.toml index 291fda3c4c7..a00fbd8f6fd 100644 --- a/substrate/frame/session/benchmarking/Cargo.toml +++ b/substrate/frame/session/benchmarking/Cargo.toml @@ -29,7 +29,7 @@ sp-std = { path = "../../../primitives/std", default-features = false } [dev-dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } -scale-info = "2.10.0" +scale-info = "2.11.1" frame-election-provider-support = { path = "../../election-provider-support" } pallet-balances = { path = "../../balances" } pallet-staking-reward-curve = { path = "../../staking/reward-curve" } diff --git a/substrate/frame/society/Cargo.toml b/substrate/frame/society/Cargo.toml index 3dab082b395..3d99ddba392 100644 --- a/substrate/frame/society/Cargo.toml +++ b/substrate/frame/society/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = { workspace = true } rand_chacha = { version = "0.2", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } sp-std = { path = "../../primitives/std", default-features = false } diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index 15c4bf9e290..4fd0cedbae6 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -20,7 +20,7 @@ serde = { features = ["alloc", "derive"], workspace = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } sp-io = { path = "../../primitives/io", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false, features = ["serde"] } sp-staking = { path = "../../primitives/staking", default-features = false, features = ["serde"] } diff --git a/substrate/frame/state-trie-migration/Cargo.toml b/substrate/frame/state-trie-migration/Cargo.toml index e837956613e..613308c308e 100644 --- a/substrate/frame/state-trie-migration/Cargo.toml +++ b/substrate/frame/state-trie-migration/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, workspace = true, default-features = true } thousands = { version = "0.2.0", optional = true } zstd = { version = "0.12.4", default-features = false, optional = true } diff --git a/substrate/frame/statement/Cargo.toml b/substrate/frame/statement/Cargo.toml index 6827dbda962..92bc32191ab 100644 --- a/substrate/frame/statement/Cargo.toml +++ b/substrate/frame/statement/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } sp-statement-store = { path = "../../primitives/statement-store", default-features = false } diff --git a/substrate/frame/sudo/Cargo.toml b/substrate/frame/sudo/Cargo.toml index a60324847f1..805f46a77f2 100644 --- a/substrate/frame/sudo/Cargo.toml +++ b/substrate/frame/sudo/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } sp-io = { path = "../../primitives/io", default-features = false } diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index 3a61cfa6fac..ecdd9382632 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -22,7 +22,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", "max-encoded-len", ] } -scale-info = { version = "2.10.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } frame-metadata = { version = "16.0.0", default-features = false, features = [ diff --git a/substrate/frame/support/test/Cargo.toml b/substrate/frame/support/test/Cargo.toml index 2f12cc00ed9..88124e0a43b 100644 --- a/substrate/frame/support/test/Cargo.toml +++ b/substrate/frame/support/test/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] static_assertions = "1.1.0" serde = { features = ["derive"], workspace = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-metadata = { version = "16.0.0", default-features = false, features = ["current"] } sp-api = { path = "../../../primitives/api", default-features = false } sp-arithmetic = { path = "../../../primitives/arithmetic", default-features = false } diff --git a/substrate/frame/support/test/compile_pass/Cargo.toml b/substrate/frame/support/test/compile_pass/Cargo.toml index 0617aa105a2..3f52b4664b1 100644 --- a/substrate/frame/support/test/compile_pass/Cargo.toml +++ b/substrate/frame/support/test/compile_pass/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } renamed-frame-support = { package = "frame-support", path = "../..", default-features = false } renamed-frame-system = { package = "frame-system", path = "../../../system", default-features = false } sp-core = { path = "../../../../primitives/core", default-features = false } diff --git a/substrate/frame/support/test/pallet/Cargo.toml b/substrate/frame/support/test/pallet/Cargo.toml index ca889faef87..7a20c3f2730 100644 --- a/substrate/frame/support/test/pallet/Cargo.toml +++ b/substrate/frame/support/test/pallet/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["derive"], workspace = true } frame-support = { path = "../..", default-features = false } frame-system = { path = "../../../system", default-features = false } diff --git a/substrate/frame/support/test/stg_frame_crate/Cargo.toml b/substrate/frame/support/test/stg_frame_crate/Cargo.toml index 632ea4e794f..295b2a1a524 100644 --- a/substrate/frame/support/test/stg_frame_crate/Cargo.toml +++ b/substrate/frame/support/test/stg_frame_crate/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } frame = { path = "../../..", default-features = false, features = ["experimental", "runtime"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } [features] default = ["std"] diff --git a/substrate/frame/system/Cargo.toml b/substrate/frame/system/Cargo.toml index d094c6bf984..16b3b946e22 100644 --- a/substrate/frame/system/Cargo.toml +++ b/substrate/frame/system/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] cfg-if = "1.0" codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } serde = { features = ["alloc", "derive"], workspace = true } frame-support = { path = "../support", default-features = false } sp-core = { path = "../../primitives/core", default-features = false, features = ["serde"] } diff --git a/substrate/frame/system/benchmarking/Cargo.toml b/substrate/frame/system/benchmarking/Cargo.toml index 80fdff756c0..473a6bb132d 100644 --- a/substrate/frame/system/benchmarking/Cargo.toml +++ b/substrate/frame/system/benchmarking/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../../benchmarking", default-features = false } frame-support = { path = "../../support", default-features = false } frame-system = { path = "..", default-features = false } diff --git a/substrate/frame/timestamp/Cargo.toml b/substrate/frame/timestamp/Cargo.toml index d8ba45a2ad2..da49b29c89b 100644 --- a/substrate/frame/timestamp/Cargo.toml +++ b/substrate/frame/timestamp/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/tips/Cargo.toml b/substrate/frame/tips/Cargo.toml index 7339cf0a8cc..a2acf0638ff 100644 --- a/substrate/frame/tips/Cargo.toml +++ b/substrate/frame/tips/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["derive"], optional = true, workspace = true, default-features = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/transaction-payment/Cargo.toml b/substrate/frame/transaction-payment/Cargo.toml index 275e1c01f92..24e5a714f0f 100644 --- a/substrate/frame/transaction-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, workspace = true, default-features = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml b/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml index 7640cc815e5..fef9afdee05 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml @@ -24,7 +24,7 @@ frame-system = { path = "../../system", default-features = false } pallet-asset-conversion = { path = "../../asset-conversion", default-features = false } pallet-transaction-payment = { path = "..", default-features = false } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } [dev-dependencies] sp-core = { path = "../../../primitives/core", default-features = false } diff --git a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml index 1da3237df08..fc4f1aecc15 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -29,7 +29,7 @@ frame-benchmarking = { path = "../../benchmarking", default-features = false, op # Other dependencies codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, workspace = true, default-features = true } [dev-dependencies] diff --git a/substrate/frame/transaction-storage/Cargo.toml b/substrate/frame/transaction-storage/Cargo.toml index 1386d9b5a56..31741cf32d8 100644 --- a/substrate/frame/transaction-storage/Cargo.toml +++ b/substrate/frame/transaction-storage/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = { version = "6.1", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, workspace = true, default-features = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/treasury/Cargo.toml b/substrate/frame/treasury/Cargo.toml index 16bb4e92520..34037338a52 100644 --- a/substrate/frame/treasury/Cargo.toml +++ b/substrate/frame/treasury/Cargo.toml @@ -22,7 +22,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = ] } docify = "0.2.8" impl-trait-for-tuples = "0.2.2" -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["derive"], optional = true, workspace = true, default-features = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/tx-pause/Cargo.toml b/substrate/frame/tx-pause/Cargo.toml index a5916c048f4..5f028179037 100644 --- a/substrate/frame/tx-pause/Cargo.toml +++ b/substrate/frame/tx-pause/Cargo.toml @@ -20,7 +20,7 @@ docify = "0.2.8" frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-runtime = { path = "../../primitives/runtime", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } pallet-balances = { path = "../balances", default-features = false, optional = true } diff --git a/substrate/frame/uniques/Cargo.toml b/substrate/frame/uniques/Cargo.toml index 4e5f21b3d8d..ee6af191d33 100644 --- a/substrate/frame/uniques/Cargo.toml +++ b/substrate/frame/uniques/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/utility/Cargo.toml b/substrate/frame/utility/Cargo.toml index ce5cd0fa61f..2ad575ed51f 100644 --- a/substrate/frame/utility/Cargo.toml +++ b/substrate/frame/utility/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/vesting/Cargo.toml b/substrate/frame/vesting/Cargo.toml index 96938b95a2a..e71731e3977 100644 --- a/substrate/frame/vesting/Cargo.toml +++ b/substrate/frame/vesting/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/whitelist/Cargo.toml b/substrate/frame/whitelist/Cargo.toml index 1a867f8075d..5c28fe29142 100644 --- a/substrate/frame/whitelist/Cargo.toml +++ b/substrate/frame/whitelist/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/primitives/api/Cargo.toml b/substrate/primitives/api/Cargo.toml index f4b1d13c520..544ba72141e 100644 --- a/substrate/primitives/api/Cargo.toml +++ b/substrate/primitives/api/Cargo.toml @@ -28,7 +28,7 @@ sp-state-machine = { path = "../state-machine", default-features = false, option sp-trie = { path = "../trie", default-features = false, optional = true } hash-db = { version = "0.16.0", optional = true } thiserror = { optional = true, workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } sp-metadata-ir = { path = "../metadata-ir", default-features = false, optional = true } diff --git a/substrate/primitives/api/test/Cargo.toml b/substrate/primitives/api/test/Cargo.toml index 3a90553bbf0..52a4bd7bda3 100644 --- a/substrate/primitives/api/test/Cargo.toml +++ b/substrate/primitives/api/test/Cargo.toml @@ -26,11 +26,11 @@ codec = { package = "parity-scale-codec", version = "3.6.1" } sp-state-machine = { path = "../../state-machine" } trybuild = "1.0.88" rustversion = "1.0.6" -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } [dev-dependencies] criterion = "0.4.0" -futures = "0.3.21" +futures = "0.3.30" log = { workspace = true, default-features = true } sp-core = { path = "../../core" } static_assertions = "1.1.0" diff --git a/substrate/primitives/application-crypto/Cargo.toml b/substrate/primitives/application-crypto/Cargo.toml index 6f90a2b6262..20e2be4d155 100644 --- a/substrate/primitives/application-crypto/Cargo.toml +++ b/substrate/primitives/application-crypto/Cargo.toml @@ -20,7 +20,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-core = { path = "../core", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, features = ["alloc", "derive"], workspace = true } sp-std = { path = "../std", default-features = false } sp-io = { path = "../io", default-features = false } diff --git a/substrate/primitives/arithmetic/Cargo.toml b/substrate/primitives/arithmetic/Cargo.toml index 45f48d77a31..16eae43c73f 100644 --- a/substrate/primitives/arithmetic/Cargo.toml +++ b/substrate/primitives/arithmetic/Cargo.toml @@ -23,7 +23,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = ] } integer-sqrt = "0.1.2" num-traits = { version = "0.2.17", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], optional = true, workspace = true } static_assertions = "1.1.0" sp-std = { path = "../std", default-features = false } diff --git a/substrate/primitives/authority-discovery/Cargo.toml b/substrate/primitives/authority-discovery/Cargo.toml index 8ee8bb94ed9..88d93f40059 100644 --- a/substrate/primitives/authority-discovery/Cargo.toml +++ b/substrate/primitives/authority-discovery/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-api = { path = "../api", default-features = false } sp-application-crypto = { path = "../application-crypto", default-features = false } sp-runtime = { path = "../runtime", default-features = false } diff --git a/substrate/primitives/blockchain/Cargo.toml b/substrate/primitives/blockchain/Cargo.toml index 9d13d627eeb..e716b61bfeb 100644 --- a/substrate/primitives/blockchain/Cargo.toml +++ b/substrate/primitives/blockchain/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -futures = "0.3.21" +futures = "0.3.30" log = { workspace = true, default-features = true } parking_lot = "0.12.1" schnellru = "0.2.1" diff --git a/substrate/primitives/consensus/aura/Cargo.toml b/substrate/primitives/consensus/aura/Cargo.toml index 0cedc59ea8f..b689c84f158 100644 --- a/substrate/primitives/consensus/aura/Cargo.toml +++ b/substrate/primitives/consensus/aura/Cargo.toml @@ -16,9 +16,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = { version = "0.1.74", optional = true } +async-trait = { version = "0.1.79", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-api = { path = "../../api", default-features = false } sp-application-crypto = { path = "../../application-crypto", default-features = false } sp-consensus-slots = { path = "../slots", default-features = false } diff --git a/substrate/primitives/consensus/babe/Cargo.toml b/substrate/primitives/consensus/babe/Cargo.toml index 724b9fd3e28..2420f48b1f4 100644 --- a/substrate/primitives/consensus/babe/Cargo.toml +++ b/substrate/primitives/consensus/babe/Cargo.toml @@ -16,9 +16,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = { version = "0.1.74", optional = true } +async-trait = { version = "0.1.79", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], optional = true, workspace = true } sp-api = { path = "../../api", default-features = false } sp-application-crypto = { path = "../../application-crypto", default-features = false } diff --git a/substrate/primitives/consensus/beefy/Cargo.toml b/substrate/primitives/consensus/beefy/Cargo.toml index fbcc6e0c104..a16d943b914 100644 --- a/substrate/primitives/consensus/beefy/Cargo.toml +++ b/substrate/primitives/consensus/beefy/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, features = ["alloc", "derive"], workspace = true } sp-api = { path = "../../api", default-features = false } sp-application-crypto = { path = "../../application-crypto", default-features = false } @@ -26,7 +26,7 @@ sp-io = { path = "../../io", default-features = false } sp-mmr-primitives = { path = "../../merkle-mountain-range", default-features = false } sp-runtime = { path = "../../runtime", default-features = false } sp-keystore = { path = "../../keystore", default-features = false } -strum = { version = "0.24.1", features = ["derive"], default-features = false } +strum = { version = "0.26.2", features = ["derive"], default-features = false } lazy_static = { version = "1.4.0", optional = true } [dev-dependencies] diff --git a/substrate/primitives/consensus/common/Cargo.toml b/substrate/primitives/consensus/common/Cargo.toml index 048e31b0265..90aeadd5055 100644 --- a/substrate/primitives/consensus/common/Cargo.toml +++ b/substrate/primitives/consensus/common/Cargo.toml @@ -17,8 +17,8 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.74" -futures = { version = "0.3.21", features = ["thread-pool"] } +async-trait = "0.1.79" +futures = { version = "0.3.30", features = ["thread-pool"] } log = { workspace = true, default-features = true } thiserror = { workspace = true } sp-core = { path = "../../core" } @@ -27,7 +27,7 @@ sp-runtime = { path = "../../runtime" } sp-state-machine = { path = "../../state-machine" } [dev-dependencies] -futures = "0.3.21" +futures = "0.3.30" sp-test-primitives = { path = "../../test-primitives" } [features] diff --git a/substrate/primitives/consensus/grandpa/Cargo.toml b/substrate/primitives/consensus/grandpa/Cargo.toml index 1f2da55c5a1..6c228383d00 100644 --- a/substrate/primitives/consensus/grandpa/Cargo.toml +++ b/substrate/primitives/consensus/grandpa/Cargo.toml @@ -20,7 +20,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } grandpa = { package = "finality-grandpa", version = "0.16.2", default-features = false, features = ["derive-codec"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], optional = true, workspace = true } sp-api = { path = "../../api", default-features = false } sp-application-crypto = { path = "../../application-crypto", default-features = false } diff --git a/substrate/primitives/consensus/sassafras/Cargo.toml b/substrate/primitives/consensus/sassafras/Cargo.toml index 085709d4c8b..07304ed9b24 100644 --- a/substrate/primitives/consensus/sassafras/Cargo.toml +++ b/substrate/primitives/consensus/sassafras/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] scale-codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["derive"], optional = true, workspace = true } sp-api = { path = "../../api", default-features = false } sp-application-crypto = { path = "../../application-crypto", default-features = false, features = ["bandersnatch-experimental"] } diff --git a/substrate/primitives/consensus/slots/Cargo.toml b/substrate/primitives/consensus/slots/Cargo.toml index 94c02dba203..a8b12900617 100644 --- a/substrate/primitives/consensus/slots/Cargo.toml +++ b/substrate/primitives/consensus/slots/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], optional = true, workspace = true } sp-timestamp = { path = "../../timestamp", default-features = false } diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 908f2498de5..833b2af95cd 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -38,7 +38,7 @@ sp-std = { path = "../std", default-features = false } sp-debug-derive = { path = "../debug-derive", default-features = false } sp-storage = { path = "../storage", default-features = false } sp-externalities = { path = "../externalities", optional = true } -futures = { version = "0.3.21", optional = true } +futures = { version = "0.3.30", optional = true } dyn-clonable = { version = "0.9.0", optional = true } thiserror = { optional = true, workspace = true } tracing = { version = "0.1.29", optional = true } diff --git a/substrate/primitives/inherents/Cargo.toml b/substrate/primitives/inherents/Cargo.toml index 6463c423fe7..c08ac459de5 100644 --- a/substrate/primitives/inherents/Cargo.toml +++ b/substrate/primitives/inherents/Cargo.toml @@ -17,15 +17,15 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = { version = "0.1.74", optional = true } +async-trait = { version = "0.1.79", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" thiserror = { optional = true, workspace = true } sp-runtime = { path = "../runtime", default-features = false, optional = true } [dev-dependencies] -futures = "0.3.21" +futures = "0.3.30" [features] default = ["std"] diff --git a/substrate/primitives/keyring/Cargo.toml b/substrate/primitives/keyring/Cargo.toml index 940fe90916d..7471e9cf8ff 100644 --- a/substrate/primitives/keyring/Cargo.toml +++ b/substrate/primitives/keyring/Cargo.toml @@ -17,7 +17,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -strum = { version = "0.24.1", features = ["derive"], default-features = false } +strum = { version = "0.26.2", features = ["derive"], default-features = false } sp-core = { path = "../core", default-features = false } sp-runtime = { path = "../runtime", default-features = false } diff --git a/substrate/primitives/merkle-mountain-range/Cargo.toml b/substrate/primitives/merkle-mountain-range/Cargo.toml index 9c07f699b37..891f893a0c9 100644 --- a/substrate/primitives/merkle-mountain-range/Cargo.toml +++ b/substrate/primitives/merkle-mountain-range/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } log = { workspace = true } mmr-lib = { package = "ckb-merkle-mountain-range", version = "0.5.2", default-features = false } serde = { features = ["alloc", "derive"], optional = true, workspace = true } diff --git a/substrate/primitives/metadata-ir/Cargo.toml b/substrate/primitives/metadata-ir/Cargo.toml index 31c839b5c48..ca8408d0ad9 100644 --- a/substrate/primitives/metadata-ir/Cargo.toml +++ b/substrate/primitives/metadata-ir/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } frame-metadata = { version = "16.0.0", default-features = false, features = ["current"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } [features] default = ["std"] diff --git a/substrate/primitives/mixnet/Cargo.toml b/substrate/primitives/mixnet/Cargo.toml index 8ba7f36da43..07840ca63cb 100644 --- a/substrate/primitives/mixnet/Cargo.toml +++ b/substrate/primitives/mixnet/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-api = { default-features = false, path = "../api" } sp-application-crypto = { default-features = false, path = "../application-crypto" } diff --git a/substrate/primitives/npos-elections/Cargo.toml b/substrate/primitives/npos-elections/Cargo.toml index b0b9890c061..afa59af64d6 100644 --- a/substrate/primitives/npos-elections/Cargo.toml +++ b/substrate/primitives/npos-elections/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], optional = true, workspace = true } sp-arithmetic = { path = "../arithmetic", default-features = false } sp-core = { path = "../core", default-features = false } diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml index 3128ebce8f7..fb5fd60fbbf 100644 --- a/substrate/primitives/runtime/Cargo.toml +++ b/substrate/primitives/runtime/Cargo.toml @@ -24,7 +24,7 @@ impl-trait-for-tuples = "0.2.2" log = { workspace = true } paste = "1.0" rand = { version = "0.8.5", optional = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], optional = true, workspace = true } sp-application-crypto = { path = "../application-crypto", default-features = false } sp-arithmetic = { path = "../arithmetic", default-features = false } diff --git a/substrate/primitives/session/Cargo.toml b/substrate/primitives/session/Cargo.toml index 784228c42e9..cdee4fb03e1 100644 --- a/substrate/primitives/session/Cargo.toml +++ b/substrate/primitives/session/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-api = { path = "../api", default-features = false } sp-core = { path = "../core", default-features = false } sp-runtime = { path = "../runtime", optional = true } diff --git a/substrate/primitives/staking/Cargo.toml b/substrate/primitives/staking/Cargo.toml index 6304551b8e6..e380abb6a8c 100644 --- a/substrate/primitives/staking/Cargo.toml +++ b/substrate/primitives/staking/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { features = ["alloc", "derive"], optional = true, workspace = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" sp-core = { path = "../core", default-features = false } diff --git a/substrate/primitives/statement-store/Cargo.toml b/substrate/primitives/statement-store/Cargo.toml index 000fcd98704..b36bff69a00 100644 --- a/substrate/primitives/statement-store/Cargo.toml +++ b/substrate/primitives/statement-store/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-core = { path = "../core", default-features = false } sp-crypto-hashing = { path = "../crypto/hashing", default-features = false } sp-runtime = { path = "../runtime", default-features = false } diff --git a/substrate/primitives/test-primitives/Cargo.toml b/substrate/primitives/test-primitives/Cargo.toml index 1b51c5f5919..05135554315 100644 --- a/substrate/primitives/test-primitives/Cargo.toml +++ b/substrate/primitives/test-primitives/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["derive"], optional = true, workspace = true } sp-application-crypto = { path = "../application-crypto", default-features = false } sp-core = { path = "../core", default-features = false } diff --git a/substrate/primitives/timestamp/Cargo.toml b/substrate/primitives/timestamp/Cargo.toml index 11afb175590..5a1d4fcc985 100644 --- a/substrate/primitives/timestamp/Cargo.toml +++ b/substrate/primitives/timestamp/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = { version = "0.1.74", optional = true } +async-trait = { version = "0.1.79", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } thiserror = { optional = true, workspace = true } sp-inherents = { path = "../inherents", default-features = false } diff --git a/substrate/primitives/transaction-storage-proof/Cargo.toml b/substrate/primitives/transaction-storage-proof/Cargo.toml index fbd0a4752fc..137a232fce7 100644 --- a/substrate/primitives/transaction-storage-proof/Cargo.toml +++ b/substrate/primitives/transaction-storage-proof/Cargo.toml @@ -16,9 +16,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = { version = "0.1.74", optional = true } +async-trait = { version = "0.1.79", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-core = { path = "../core", optional = true } sp-inherents = { path = "../inherents", default-features = false } sp-runtime = { path = "../runtime", default-features = false } diff --git a/substrate/primitives/trie/Cargo.toml b/substrate/primitives/trie/Cargo.toml index dd7ab080e5f..28c496d7a8e 100644 --- a/substrate/primitives/trie/Cargo.toml +++ b/substrate/primitives/trie/Cargo.toml @@ -29,7 +29,7 @@ memory-db = { version = "0.32.0", default-features = false } nohash-hasher = { version = "0.2.0", optional = true } parking_lot = { version = "0.12.1", optional = true } rand = { version = "0.8", optional = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } thiserror = { optional = true, workspace = true } tracing = { version = "0.1.29", optional = true } trie-db = { version = "0.28.0", default-features = false } diff --git a/substrate/primitives/version/Cargo.toml b/substrate/primitives/version/Cargo.toml index a94e2322430..d686b0c7551 100644 --- a/substrate/primitives/version/Cargo.toml +++ b/substrate/primitives/version/Cargo.toml @@ -20,7 +20,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } impl-serde = { version = "0.4.0", default-features = false, optional = true } parity-wasm = { version = "0.45", optional = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], optional = true, workspace = true } thiserror = { optional = true, workspace = true } sp-crypto-hashing-proc-macro = { path = "../crypto/hashing/proc-macro" } diff --git a/substrate/primitives/weights/Cargo.toml b/substrate/primitives/weights/Cargo.toml index d3118defb58..e73d4a702b4 100644 --- a/substrate/primitives/weights/Cargo.toml +++ b/substrate/primitives/weights/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bounded-collections = { version = "0.2.0", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, features = ["alloc", "derive"], workspace = true } smallvec = "1.11.0" sp-arithmetic = { path = "../arithmetic", default-features = false } diff --git a/substrate/test-utils/Cargo.toml b/substrate/test-utils/Cargo.toml index af8b01cdef0..56b1c038199 100644 --- a/substrate/test-utils/Cargo.toml +++ b/substrate/test-utils/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -futures = "0.3.16" +futures = "0.3.30" tokio = { version = "1.22.0", features = ["macros", "time"] } [dev-dependencies] diff --git a/substrate/test-utils/client/Cargo.toml b/substrate/test-utils/client/Cargo.toml index 349b04d32d7..4e4e65314fc 100644 --- a/substrate/test-utils/client/Cargo.toml +++ b/substrate/test-utils/client/Cargo.toml @@ -17,9 +17,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = "6.1" -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.6.1" } -futures = "0.3.21" +futures = "0.3.30" serde = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } sc-client-api = { path = "../../client/api" } diff --git a/substrate/test-utils/runtime/Cargo.toml b/substrate/test-utils/runtime/Cargo.toml index f49503da8ca..ffbd59f39ad 100644 --- a/substrate/test-utils/runtime/Cargo.toml +++ b/substrate/test-utils/runtime/Cargo.toml @@ -22,7 +22,7 @@ sp-consensus-babe = { path = "../../primitives/consensus/babe", default-features sp-genesis-builder = { path = "../../primitives/genesis-builder", default-features = false } sp-block-builder = { path = "../../primitives/block-builder", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-inherents = { path = "../../primitives/inherents", default-features = false } sp-keyring = { path = "../../primitives/keyring", default-features = false } sp-offchain = { path = "../../primitives/offchain", default-features = false } @@ -53,7 +53,7 @@ array-bytes = { version = "6.1", optional = true } log = { workspace = true } [dev-dependencies] -futures = "0.3.21" +futures = "0.3.30" sc-block-builder = { path = "../../client/block-builder" } sc-chain-spec = { path = "../../client/chain-spec" } sc-executor = { path = "../../client/executor" } diff --git a/substrate/test-utils/runtime/client/Cargo.toml b/substrate/test-utils/runtime/client/Cargo.toml index cbb964f6785..5ca24fea33e 100644 --- a/substrate/test-utils/runtime/client/Cargo.toml +++ b/substrate/test-utils/runtime/client/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -futures = "0.3.21" +futures = "0.3.30" sc-block-builder = { path = "../../../client/block-builder" } sc-client-api = { path = "../../../client/api" } sc-consensus = { path = "../../../client/consensus/common" } diff --git a/substrate/test-utils/runtime/transaction-pool/Cargo.toml b/substrate/test-utils/runtime/transaction-pool/Cargo.toml index 33e56e8e55e..9b52706c739 100644 --- a/substrate/test-utils/runtime/transaction-pool/Cargo.toml +++ b/substrate/test-utils/runtime/transaction-pool/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -futures = "0.3.21" +futures = "0.3.30" parking_lot = "0.12.1" thiserror = { workspace = true } sc-transaction-pool = { path = "../../../client/transaction-pool" } diff --git a/substrate/utils/binary-merkle-tree/Cargo.toml b/substrate/utils/binary-merkle-tree/Cargo.toml index 6ba515afee1..a89006d94dc 100644 --- a/substrate/utils/binary-merkle-tree/Cargo.toml +++ b/substrate/utils/binary-merkle-tree/Cargo.toml @@ -18,7 +18,7 @@ hash-db = { version = "0.16.0", default-features = false } [dev-dependencies] array-bytes = "6.1" -env_logger = "0.9" +env_logger = "0.11" sp-core = { path = "../../primitives/core" } sp-runtime = { path = "../../primitives/runtime" } diff --git a/substrate/utils/frame/remote-externalities/Cargo.toml b/substrate/utils/frame/remote-externalities/Cargo.toml index 61e0a861ee0..82b01915483 100644 --- a/substrate/utils/frame/remote-externalities/Cargo.toml +++ b/substrate/utils/frame/remote-externalities/Cargo.toml @@ -26,7 +26,7 @@ sp-io = { path = "../../../primitives/io" } sp-runtime = { path = "../../../primitives/runtime" } tokio = { version = "1.22.0", features = ["macros", "rt-multi-thread"] } substrate-rpc-client = { path = "../rpc/client" } -futures = "0.3" +futures = "0.3.30" indicatif = "0.17.7" spinners = "4.1.0" tokio-retry = "0.3.0" diff --git a/substrate/utils/frame/rpc/client/Cargo.toml b/substrate/utils/frame/rpc/client/Cargo.toml index b51e3f44f4e..501bb95b257 100644 --- a/substrate/utils/frame/rpc/client/Cargo.toml +++ b/substrate/utils/frame/rpc/client/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] jsonrpsee = { version = "0.22", features = ["ws-client"] } sc-rpc-api = { path = "../../../../client/rpc-api" } -async-trait = "0.1.74" +async-trait = "0.1.79" serde = { workspace = true, default-features = true } sp-runtime = { path = "../../../../primitives/runtime" } log = { workspace = true, default-features = true } diff --git a/substrate/utils/frame/rpc/support/Cargo.toml b/substrate/utils/frame/rpc/support/Cargo.toml index 2e4bb6a1057..84db06da7b0 100644 --- a/substrate/utils/frame/rpc/support/Cargo.toml +++ b/substrate/utils/frame/rpc/support/Cargo.toml @@ -23,9 +23,9 @@ sc-rpc-api = { path = "../../../../client/rpc-api" } sp-storage = { path = "../../../../primitives/storage" } [dev-dependencies] -scale-info = "2.10.0" +scale-info = "2.11.1" jsonrpsee = { version = "0.22", features = ["jsonrpsee-types", "ws-client"] } -tokio = "1.22.0" +tokio = "1.37" sp-core = { path = "../../../../primitives/core" } sp-runtime = { path = "../../../../primitives/runtime" } frame-system = { path = "../../../../frame/system" } diff --git a/substrate/utils/frame/rpc/system/Cargo.toml b/substrate/utils/frame/rpc/system/Cargo.toml index f9a84a01af8..9e571bef9d0 100644 --- a/substrate/utils/frame/rpc/system/Cargo.toml +++ b/substrate/utils/frame/rpc/system/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } -futures = "0.3.21" +futures = "0.3.30" log = { workspace = true, default-features = true } frame-system-rpc-runtime-api = { path = "../../../../frame/system/rpc/runtime-api" } sc-rpc-api = { path = "../../../../client/rpc-api" } @@ -31,7 +31,7 @@ sp-runtime = { path = "../../../../primitives/runtime" } [dev-dependencies] sc-transaction-pool = { path = "../../../../client/transaction-pool" } -tokio = "1.22.0" +tokio = "1.37" assert_matches = "1.3.0" sp-tracing = { path = "../../../../primitives/tracing" } substrate-test-runtime-client = { path = "../../../../test-utils/runtime/client" } diff --git a/substrate/utils/frame/try-runtime/cli/Cargo.toml b/substrate/utils/frame/try-runtime/cli/Cargo.toml index 3ff57745a2d..618cb645475 100644 --- a/substrate/utils/frame/try-runtime/cli/Cargo.toml +++ b/substrate/utils/frame/try-runtime/cli/Cargo.toml @@ -37,7 +37,7 @@ sp-weights = { path = "../../../../primitives/weights" } frame-try-runtime = { path = "../../../../frame/try-runtime", optional = true } substrate-rpc-client = { path = "../../rpc/client" } -async-trait = "0.1.74" +async-trait = "0.1.79" clap = { version = "4.5.3", features = ["derive"] } hex = { version = "0.4.3", default-features = false } log = { workspace = true, default-features = true } @@ -52,7 +52,7 @@ node-primitives = { path = "../../../../bin/node/primitives" } regex = "1.7.3" substrate-cli-test-utils = { path = "../../../../test-utils/cli" } tempfile = "3.1.0" -tokio = "1.27.0" +tokio = "1.37" [features] try-runtime = [ diff --git a/substrate/utils/wasm-builder/Cargo.toml b/substrate/utils/wasm-builder/Cargo.toml index 7abd1a20284..bac323e2e6a 100644 --- a/substrate/utils/wasm-builder/Cargo.toml +++ b/substrate/utils/wasm-builder/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] build-helper = "0.1.1" cargo_metadata = "0.15.4" console = "0.15.8" -strum = { version = "0.24.1", features = ["derive"] } +strum = { version = "0.26.2", features = ["derive"] } tempfile = "3.1.0" toml = "0.8.8" walkdir = "2.4.0" diff --git a/templates/minimal/node/Cargo.toml b/templates/minimal/node/Cargo.toml index 41d9708ea60..0668304e502 100644 --- a/templates/minimal/node/Cargo.toml +++ b/templates/minimal/node/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] clap = { version = "4.5.3", features = ["derive"] } -futures = { version = "0.3.21", features = ["thread-pool"] } +futures = { version = "0.3.30", features = ["thread-pool"] } futures-timer = "3.0.1" jsonrpsee = { version = "0.22", features = ["server"] } serde_json = { workspace = true, default-features = true } diff --git a/templates/minimal/pallets/template/Cargo.toml b/templates/minimal/pallets/template/Cargo.toml index 9982e5ea53b..a85391f2942 100644 --- a/templates/minimal/pallets/template/Cargo.toml +++ b/templates/minimal/pallets/template/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ], default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } frame = { path = "../../../../substrate/frame", default-features = false, features = [ diff --git a/templates/parachain/pallets/template/Cargo.toml b/templates/parachain/pallets/template/Cargo.toml index 89eb9d51716..199da2f12d2 100644 --- a/templates/parachain/pallets/template/Cargo.toml +++ b/templates/parachain/pallets/template/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } diff --git a/templates/parachain/runtime/Cargo.toml b/templates/parachain/runtime/Cargo.toml index 41a510c5ed3..0d985796a11 100644 --- a/templates/parachain/runtime/Cargo.toml +++ b/templates/parachain/runtime/Cargo.toml @@ -24,7 +24,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } hex-literal = { version = "0.4.1", optional = true } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } smallvec = "1.11.0" diff --git a/templates/solochain/node/Cargo.toml b/templates/solochain/node/Cargo.toml index a0bb5c27ed3..1ddd1cb3a7b 100644 --- a/templates/solochain/node/Cargo.toml +++ b/templates/solochain/node/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] clap = { version = "4.5.3", features = ["derive"] } -futures = { version = "0.3.21", features = ["thread-pool"] } +futures = { version = "0.3.30", features = ["thread-pool"] } serde_json = { workspace = true, default-features = true } jsonrpsee = { version = "0.22", features = ["server"] } diff --git a/templates/solochain/pallets/template/Cargo.toml b/templates/solochain/pallets/template/Cargo.toml index bd234715198..24519f1d22e 100644 --- a/templates/solochain/pallets/template/Cargo.toml +++ b/templates/solochain/pallets/template/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } diff --git a/templates/solochain/runtime/Cargo.toml b/templates/solochain/runtime/Cargo.toml index 90dd823eb64..7a81f192043 100644 --- a/templates/solochain/runtime/Cargo.toml +++ b/templates/solochain/runtime/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", "serde", ] } -- GitLab From e54279699b646b0be4b48e898f0b7e3d5fe1b033 Mon Sep 17 00:00:00 2001 From: Dastan <88332432+dastansam@users.noreply.github.com> Date: Tue, 2 Apr 2024 15:43:09 +0200 Subject: [PATCH 149/187] migrations: prevent accidentally using unversioned migrations instead of `VersionedMigration` (#3835) closes #1324 #### Problem Currently, it is possible to accidentally use inner unversioned migration instead of `VersionedMigration` since both implement `OnRuntimeUpgrade`. #### Solution With this change, we make it clear that value of `Inner` is not intended to be used directly. It is achieved by bounding `Inner` to new trait `UncheckedOnRuntimeUpgrade`, which has the same interface (except `unchecked_` prefix) as `OnRuntimeUpgrade`. #### `try-runtime` functions Since developers can implement `try-runtime` for `Inner` value in `VersionedMigration` and have custom logic for it, I added the same `try-runtime` functions to `UncheckedOnRuntimeUpgrade`. I looked for a ways to not duplicate functions, but couldn't find anything that doesn't significantly change the codebase. So I would appreciate If you have any suggestions to improve this cc @liamaharon @xlc polkadot address: 16FqwPZ8GRC5U5D4Fu7W33nA55ZXzXGWHwmbnE1eT6pxuqcT --------- Co-authored-by: Liam Aharon --- cumulus/pallets/xcmp-queue/src/migration.rs | 9 +- .../common/src/assigned_slots/migration.rs | 5 +- .../common/src/paras_registrar/migration.rs | 4 +- .../src/assigner_on_demand/migration.rs | 8 +- .../src/configuration/migration/v10.rs | 10 +- .../src/configuration/migration/v11.rs | 8 +- .../src/configuration/migration/v12.rs | 4 +- .../parachains/src/inclusion/migration.rs | 10 +- .../parachains/src/scheduler/migration.rs | 9 +- polkadot/xcm/pallet-xcm/src/migration.rs | 4 +- prdoc/pr_3835.prdoc | 54 +++++ .../single-block-migrations/src/lib.rs | 24 +-- .../src/migrations/v1.rs | 196 ++++++++---------- substrate/frame/grandpa/src/migrations/v5.rs | 15 +- substrate/frame/identity/src/migration.rs | 6 +- .../frame/nomination-pools/src/migration.rs | 8 +- substrate/frame/society/src/migrations.rs | 4 +- substrate/frame/support/src/migrations.rs | 22 +- substrate/frame/support/src/traits.rs | 2 +- substrate/frame/support/src/traits/hooks.rs | 28 ++- .../support/test/tests/versioned_migration.rs | 8 +- substrate/frame/uniques/src/migration.rs | 8 +- 22 files changed, 257 insertions(+), 189 deletions(-) create mode 100644 prdoc/pr_3835.prdoc diff --git a/cumulus/pallets/xcmp-queue/src/migration.rs b/cumulus/pallets/xcmp-queue/src/migration.rs index c7fa61a3e3f..1702cd70bc2 100644 --- a/cumulus/pallets/xcmp-queue/src/migration.rs +++ b/cumulus/pallets/xcmp-queue/src/migration.rs @@ -20,7 +20,7 @@ use crate::{Config, OverweightIndex, Pallet, QueueConfig, QueueConfigData, DEFAU use cumulus_primitives_core::XcmpMessageFormat; use frame_support::{ pallet_prelude::*, - traits::{EnqueueMessage, OnRuntimeUpgrade, StorageVersion}, + traits::{EnqueueMessage, StorageVersion, UncheckedOnRuntimeUpgrade}, weights::{constants::WEIGHT_REF_TIME_PER_MILLIS, Weight}, }; @@ -96,7 +96,7 @@ pub mod v2 { /// 2D weights). pub struct UncheckedMigrationToV2(PhantomData); - impl OnRuntimeUpgrade for UncheckedMigrationToV2 { + impl UncheckedOnRuntimeUpgrade for UncheckedMigrationToV2 { #[allow(deprecated)] fn on_runtime_upgrade() -> Weight { let translate = |pre: v1::QueueConfigData| -> v2::QueueConfigData { @@ -187,7 +187,7 @@ pub mod v3 { /// Migrates the pallet storage to v3. pub struct UncheckedMigrationToV3(PhantomData); - impl OnRuntimeUpgrade for UncheckedMigrationToV3 { + impl UncheckedOnRuntimeUpgrade for UncheckedMigrationToV3 { fn on_runtime_upgrade() -> Weight { #[frame_support::storage_alias] type Overweight = @@ -266,7 +266,7 @@ pub mod v4 { /// thresholds to at least the default values. pub struct UncheckedMigrationToV4(PhantomData); - impl OnRuntimeUpgrade for UncheckedMigrationToV4 { + impl UncheckedOnRuntimeUpgrade for UncheckedMigrationToV4 { fn on_runtime_upgrade() -> Weight { let translate = |pre: v2::QueueConfigData| -> QueueConfigData { let pre_default = v2::QueueConfigData::default(); @@ -315,6 +315,7 @@ pub mod v4 { mod tests { use super::*; use crate::mock::{new_test_ext, Test}; + use frame_support::traits::OnRuntimeUpgrade; #[test] #[allow(deprecated)] diff --git a/polkadot/runtime/common/src/assigned_slots/migration.rs b/polkadot/runtime/common/src/assigned_slots/migration.rs index def6bad692a..7e582dfa596 100644 --- a/polkadot/runtime/common/src/assigned_slots/migration.rs +++ b/polkadot/runtime/common/src/assigned_slots/migration.rs @@ -15,7 +15,7 @@ // along with Polkadot. If not, see . use super::{Config, MaxPermanentSlots, MaxTemporarySlots, Pallet, LOG_TARGET}; -use frame_support::traits::{Get, GetStorageVersion, OnRuntimeUpgrade}; +use frame_support::traits::{Get, GetStorageVersion, UncheckedOnRuntimeUpgrade}; #[cfg(feature = "try-runtime")] use frame_support::ensure; @@ -23,10 +23,9 @@ use frame_support::ensure; use sp_std::vec::Vec; pub mod v1 { - use super::*; pub struct VersionUncheckedMigrateToV1(sp_std::marker::PhantomData); - impl OnRuntimeUpgrade for VersionUncheckedMigrateToV1 { + impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateToV1 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { let on_chain_version = Pallet::::on_chain_storage_version(); diff --git a/polkadot/runtime/common/src/paras_registrar/migration.rs b/polkadot/runtime/common/src/paras_registrar/migration.rs index f977674a1e4..18bb6bbfb55 100644 --- a/polkadot/runtime/common/src/paras_registrar/migration.rs +++ b/polkadot/runtime/common/src/paras_registrar/migration.rs @@ -15,7 +15,7 @@ // along with Polkadot. If not, see . use super::*; -use frame_support::traits::{Contains, OnRuntimeUpgrade}; +use frame_support::traits::{Contains, UncheckedOnRuntimeUpgrade}; #[derive(Encode, Decode)] pub struct ParaInfoV1 { @@ -27,7 +27,7 @@ pub struct ParaInfoV1 { pub struct VersionUncheckedMigrateToV1( sp_std::marker::PhantomData<(T, UnlockParaIds)>, ); -impl> OnRuntimeUpgrade +impl> UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateToV1 { fn on_runtime_upgrade() -> Weight { diff --git a/polkadot/runtime/parachains/src/assigner_on_demand/migration.rs b/polkadot/runtime/parachains/src/assigner_on_demand/migration.rs index 5071653377d..8589ddc292b 100644 --- a/polkadot/runtime/parachains/src/assigner_on_demand/migration.rs +++ b/polkadot/runtime/parachains/src/assigner_on_demand/migration.rs @@ -18,7 +18,7 @@ use super::*; use frame_support::{ migrations::VersionedMigration, pallet_prelude::ValueQuery, storage_alias, - traits::OnRuntimeUpgrade, weights::Weight, + traits::UncheckedOnRuntimeUpgrade, weights::Weight, }; mod v0 { @@ -51,7 +51,7 @@ mod v1 { /// Migration to V1 pub struct UncheckedMigrateToV1(sp_std::marker::PhantomData); - impl OnRuntimeUpgrade for UncheckedMigrateToV1 { + impl UncheckedOnRuntimeUpgrade for UncheckedMigrateToV1 { fn on_runtime_upgrade() -> Weight { let mut weight: Weight = Weight::zero(); @@ -141,7 +141,7 @@ pub type MigrateV0ToV1 = VersionedMigration< #[cfg(test)] mod tests { - use super::{v0, v1, OnRuntimeUpgrade, Weight}; + use super::{v0, v1, UncheckedOnRuntimeUpgrade, Weight}; use crate::mock::{new_test_ext, MockGenesisConfig, OnDemandAssigner, Test}; use primitives::Id as ParaId; @@ -163,7 +163,7 @@ mod tests { // For tests, db weight is zero. assert_eq!( - as OnRuntimeUpgrade>::on_runtime_upgrade(), + as UncheckedOnRuntimeUpgrade>::on_runtime_upgrade(), Weight::zero() ); diff --git a/polkadot/runtime/parachains/src/configuration/migration/v10.rs b/polkadot/runtime/parachains/src/configuration/migration/v10.rs index 3c8d6084ace..fa72c357d7d 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v10.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v10.rs @@ -17,7 +17,11 @@ //! A module that is responsible for migration of storage. use crate::configuration::{Config, Pallet}; -use frame_support::{pallet_prelude::*, traits::Defensive, weights::Weight}; +use frame_support::{ + pallet_prelude::*, + traits::{Defensive, UncheckedOnRuntimeUpgrade}, + weights::Weight, +}; use frame_system::pallet_prelude::BlockNumberFor; use primitives::{ AsyncBackingParams, Balance, ExecutorParams, NodeFeatures, SessionIndex, @@ -26,8 +30,6 @@ use primitives::{ use sp_runtime::Perbill; use sp_std::vec::Vec; -use frame_support::traits::OnRuntimeUpgrade; - use super::v9::V9HostConfiguration; // All configuration of the runtime with respect to paras. #[derive(Clone, Encode, PartialEq, Decode, Debug)] @@ -163,7 +165,7 @@ mod v10 { } pub struct VersionUncheckedMigrateToV10(sp_std::marker::PhantomData); -impl OnRuntimeUpgrade for VersionUncheckedMigrateToV10 { +impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateToV10 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { log::trace!(target: crate::configuration::LOG_TARGET, "Running pre_upgrade() for HostConfiguration MigrateToV10"); diff --git a/polkadot/runtime/parachains/src/configuration/migration/v11.rs b/polkadot/runtime/parachains/src/configuration/migration/v11.rs index 7ed9d086885..65656e8d7c0 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v11.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v11.rs @@ -18,7 +18,10 @@ use crate::configuration::{self, Config, Pallet}; use frame_support::{ - migrations::VersionedMigration, pallet_prelude::*, traits::Defensive, weights::Weight, + migrations::VersionedMigration, + pallet_prelude::*, + traits::{Defensive, UncheckedOnRuntimeUpgrade}, + weights::Weight, }; use frame_system::pallet_prelude::BlockNumberFor; use primitives::{ @@ -27,7 +30,6 @@ use primitives::{ }; use sp_std::vec::Vec; -use frame_support::traits::OnRuntimeUpgrade; use polkadot_core_primitives::Balance; use sp_arithmetic::Perbill; @@ -176,7 +178,7 @@ pub type MigrateToV11 = VersionedMigration< >; pub struct UncheckedMigrateToV11(sp_std::marker::PhantomData); -impl OnRuntimeUpgrade for UncheckedMigrateToV11 { +impl UncheckedOnRuntimeUpgrade for UncheckedMigrateToV11 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { log::trace!(target: crate::configuration::LOG_TARGET, "Running pre_upgrade() for HostConfiguration MigrateToV11"); diff --git a/polkadot/runtime/parachains/src/configuration/migration/v12.rs b/polkadot/runtime/parachains/src/configuration/migration/v12.rs index 4295a79893e..69bacc83d04 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v12.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v12.rs @@ -20,7 +20,7 @@ use crate::configuration::{self, migration::v11::V11HostConfiguration, Config, P use frame_support::{ migrations::VersionedMigration, pallet_prelude::*, - traits::{Defensive, OnRuntimeUpgrade}, + traits::{Defensive, UncheckedOnRuntimeUpgrade}, }; use frame_system::pallet_prelude::BlockNumberFor; use primitives::vstaging::SchedulerParams; @@ -70,7 +70,7 @@ pub type MigrateToV12 = VersionedMigration< pub struct UncheckedMigrateToV12(sp_std::marker::PhantomData); -impl OnRuntimeUpgrade for UncheckedMigrateToV12 { +impl UncheckedOnRuntimeUpgrade for UncheckedMigrateToV12 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { log::trace!(target: crate::configuration::LOG_TARGET, "Running pre_upgrade() for HostConfiguration MigrateToV12"); diff --git a/polkadot/runtime/parachains/src/inclusion/migration.rs b/polkadot/runtime/parachains/src/inclusion/migration.rs index 1e63b209f4e..5f35680ee69 100644 --- a/polkadot/runtime/parachains/src/inclusion/migration.rs +++ b/polkadot/runtime/parachains/src/inclusion/migration.rs @@ -73,7 +73,7 @@ mod v1 { CandidatePendingAvailability as V1CandidatePendingAvailability, Config, Pallet, PendingAvailability as V1PendingAvailability, }; - use frame_support::{traits::OnRuntimeUpgrade, weights::Weight}; + use frame_support::{traits::UncheckedOnRuntimeUpgrade, weights::Weight}; use sp_core::Get; use sp_std::{collections::vec_deque::VecDeque, vec::Vec}; @@ -87,7 +87,7 @@ mod v1 { pub struct VersionUncheckedMigrateToV1(sp_std::marker::PhantomData); - impl OnRuntimeUpgrade for VersionUncheckedMigrateToV1 { + impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateToV1 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { log::trace!(target: crate::inclusion::LOG_TARGET, "Running pre_upgrade() for inclusion MigrateToV1"); @@ -216,7 +216,7 @@ mod tests { }, mock::{new_test_ext, MockGenesisConfig, Test}, }; - use frame_support::traits::OnRuntimeUpgrade; + use frame_support::traits::UncheckedOnRuntimeUpgrade; use primitives::{AvailabilityBitfield, Id as ParaId}; use test_helpers::{dummy_candidate_commitments, dummy_candidate_descriptor, dummy_hash}; @@ -225,7 +225,7 @@ mod tests { new_test_ext(MockGenesisConfig::default()).execute_with(|| { // No data to migrate. assert_eq!( - as OnRuntimeUpgrade>::on_runtime_upgrade(), + as UncheckedOnRuntimeUpgrade>::on_runtime_upgrade(), Weight::zero() ); assert!(V1PendingAvailability::::iter().next().is_none()); @@ -299,7 +299,7 @@ mod tests { // For tests, db weight is zero. assert_eq!( - as OnRuntimeUpgrade>::on_runtime_upgrade(), + as UncheckedOnRuntimeUpgrade>::on_runtime_upgrade(), Weight::zero() ); diff --git a/polkadot/runtime/parachains/src/scheduler/migration.rs b/polkadot/runtime/parachains/src/scheduler/migration.rs index c47fbab046f..b030940fb41 100644 --- a/polkadot/runtime/parachains/src/scheduler/migration.rs +++ b/polkadot/runtime/parachains/src/scheduler/migration.rs @@ -19,7 +19,7 @@ use super::*; use frame_support::{ migrations::VersionedMigration, pallet_prelude::ValueQuery, storage_alias, - traits::OnRuntimeUpgrade, weights::Weight, + traits::UncheckedOnRuntimeUpgrade, weights::Weight, }; /// Old/legacy assignment representation (v0). @@ -105,7 +105,8 @@ mod v0 { // - Assignments only consist of `ParaId`, `Assignment` is a concrete type (Same as V0Assignment). mod v1 { use frame_support::{ - pallet_prelude::ValueQuery, storage_alias, traits::OnRuntimeUpgrade, weights::Weight, + pallet_prelude::ValueQuery, storage_alias, traits::UncheckedOnRuntimeUpgrade, + weights::Weight, }; use frame_system::pallet_prelude::BlockNumberFor; @@ -164,7 +165,7 @@ mod v1 { /// Migration to V1 pub struct UncheckedMigrateToV1(sp_std::marker::PhantomData); - impl OnRuntimeUpgrade for UncheckedMigrateToV1 { + impl UncheckedOnRuntimeUpgrade for UncheckedMigrateToV1 { fn on_runtime_upgrade() -> Weight { let mut weight: Weight = Weight::zero(); @@ -302,7 +303,7 @@ mod v2 { /// Migration to V2 pub struct UncheckedMigrateToV2(sp_std::marker::PhantomData); - impl OnRuntimeUpgrade for UncheckedMigrateToV2 { + impl UncheckedOnRuntimeUpgrade for UncheckedMigrateToV2 { fn on_runtime_upgrade() -> Weight { let mut weight: Weight = Weight::zero(); diff --git a/polkadot/xcm/pallet-xcm/src/migration.rs b/polkadot/xcm/pallet-xcm/src/migration.rs index 018436aa3c9..b157e6b5c3d 100644 --- a/polkadot/xcm/pallet-xcm/src/migration.rs +++ b/polkadot/xcm/pallet-xcm/src/migration.rs @@ -19,7 +19,7 @@ use crate::{ }; use frame_support::{ pallet_prelude::*, - traits::{OnRuntimeUpgrade, StorageVersion}, + traits::{OnRuntimeUpgrade, StorageVersion, UncheckedOnRuntimeUpgrade}, weights::Weight, }; @@ -35,7 +35,7 @@ pub mod v1 { /// /// Use experimental [`MigrateToV1`] instead. pub struct VersionUncheckedMigrateToV1(sp_std::marker::PhantomData); - impl OnRuntimeUpgrade for VersionUncheckedMigrateToV1 { + impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateToV1 { fn on_runtime_upgrade() -> Weight { let mut weight = T::DbWeight::get().reads(1); diff --git a/prdoc/pr_3835.prdoc b/prdoc/pr_3835.prdoc new file mode 100644 index 00000000000..d2f49f8fc11 --- /dev/null +++ b/prdoc/pr_3835.prdoc @@ -0,0 +1,54 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "migrations: prevent accidentally using inner unversioned migration instead of `VersionedMigration`" + +doc: + - audience: Runtime Dev + description: | + Currently, it is possible to accidentally use inner unversioned migration instead of `VersionedMigration` + since both implement `OnRuntimeUpgrade`. With this change, we make it clear that `Inner` is not intended + to be used directly. It is achieved by bounding `Inner` to new trait `UncheckedOnRuntimeUpgrade`, which + has the same interface as `OnRuntimeUpgrade`, but can not be used directly for runtime upgrade migrations. + + This change will break all existing migrations passed to `VersionedMigration`. Developers should simply change + those migrations to implement `UncheckedOnRuntimeUpgrade` instead of `OnRuntimeUpgrade`. + + Example: + + ``` + --- a/path/to/migration.rs + +++ b/path/to/migration.rs + @@ -1,7 +1,7 @@ + -impl OnRuntimeUpgrade for MigrateVNToVM { + +impl UncheckedOnRuntimeUpgrade for MigrateVNToVM { + fn on_runtime_upgrade() -> Weight { + // Migration logic here + // Adjust the migration logic if necessary to align with the expectations + // of new `UncheckedOnRuntimeUpgrade` trait. + 0 + } + } + ``` + +crates: + - name: "pallet-example-single-block-migrations" + bump: "major" + - name: "pallet-xcm" + bump: "major" + - name: "pallet-grandpa" + bump: "major" + - name: "pallet-identity" + bump: "major" + - name: "pallet-nomination-pools" + bump: "major" + - name: "pallet-society" + bump: "major" + - name: "frame-support" + bump: "major" + - name: "pallet-uniques" + bump: "major" + - name: "polkadot-runtime-parachains" + bump: "major" + - name: "polkadot-runtime-common" + bump: "major" diff --git a/substrate/frame/examples/single-block-migrations/src/lib.rs b/substrate/frame/examples/single-block-migrations/src/lib.rs index b36d5262267..411537aa8c6 100644 --- a/substrate/frame/examples/single-block-migrations/src/lib.rs +++ b/substrate/frame/examples/single-block-migrations/src/lib.rs @@ -89,7 +89,7 @@ //! //! See the migration source code for detailed comments. //! -//! To keep the migration logic organised, it is split across additional modules: +//! Here's a brief overview of modules and types defined in `v1.rs`: //! //! ### `mod v0` //! @@ -98,28 +98,29 @@ //! //! This allows reading the old v0 value from storage during the migration. //! -//! ### `mod version_unchecked` +//! ### `InnerMigrateV0ToV1` //! //! Here we define our raw migration logic, -//! `version_unchecked::MigrateV0ToV1` which implements the [`OnRuntimeUpgrade`] trait. +//! `InnerMigrateV0ToV1` which implements the [`UncheckedOnRuntimeUpgrade`] trait. //! -//! Importantly, it is kept in a private module so that it cannot be accidentally used in a runtime. +//! #### Why [`UncheckedOnRuntimeUpgrade`]? //! -//! Private modules cannot be referenced in docs, so please read the code directly. +//! Otherwise, we would have two implementations of [`OnRuntimeUpgrade`] which could be confusing, +//! and may lead to accidentally using the wrong one. //! //! #### Standalone Struct or Pallet Hook? //! //! Note that the storage migration logic is attached to a standalone struct implementing -//! [`OnRuntimeUpgrade`], rather than implementing the +//! [`UncheckedOnRuntimeUpgrade`], rather than implementing the //! [`Hooks::on_runtime_upgrade`](frame_support::traits::Hooks::on_runtime_upgrade) hook directly on //! the pallet. The pallet hook is better suited for special types of logic that need to execute on //! every runtime upgrade, but not so much for one-off storage migrations. //! -//! ### `pub mod versioned` +//! ### `MigrateV0ToV1` //! -//! Here, `version_unchecked::MigrateV0ToV1` is wrapped in a +//! Here, `InnerMigrateV0ToV1` is wrapped in a //! [`VersionedMigration`] to define -//! [`versioned::MigrateV0ToV1`](crate::migrations::v1::versioned::MigrateV0ToV1), which may be used +//! [`MigrateV0ToV1`](crate::migrations::v1::MigrateV0ToV1), which may be used //! in runtimes. //! //! Using [`VersionedMigration`] ensures that @@ -128,8 +129,6 @@ //! - Reads and writes from checking and setting the on-chain storage version are accounted for in //! the final [`Weight`](frame_support::weights::Weight) //! -//! This is the only public module exported from `v1`. -//! //! ### `mod test` //! //! Here basic unit tests are defined for the migration. @@ -142,7 +141,8 @@ //! [`VersionedMigration`]: frame_support::migrations::VersionedMigration //! [`GetStorageVersion`]: frame_support::traits::GetStorageVersion //! [`OnRuntimeUpgrade`]: frame_support::traits::OnRuntimeUpgrade -//! [`MigrateV0ToV1`]: crate::migrations::v1::versioned::MigrationV0ToV1 +//! [`UncheckedOnRuntimeUpgrade`]: frame_support::traits::UncheckedOnRuntimeUpgrade +//! [`MigrateV0ToV1`]: crate::migrations::v1::MigrateV0ToV1 // We make sure this pallet uses `no_std` for compiling to Wasm. #![cfg_attr(not(feature = "std"), no_std)] diff --git a/substrate/frame/examples/single-block-migrations/src/migrations/v1.rs b/substrate/frame/examples/single-block-migrations/src/migrations/v1.rs index b46640a3202..18ef4e72cc4 100644 --- a/substrate/frame/examples/single-block-migrations/src/migrations/v1.rs +++ b/substrate/frame/examples/single-block-migrations/src/migrations/v1.rs @@ -17,7 +17,7 @@ use frame_support::{ storage_alias, - traits::{Get, OnRuntimeUpgrade}, + traits::{Get, UncheckedOnRuntimeUpgrade}, }; #[cfg(feature = "try-runtime")] @@ -34,118 +34,92 @@ mod v0 { pub type Value = StorageValue, u32>; } -/// Private module containing *version unchecked* migration logic. +/// Implements [`UncheckedOnRuntimeUpgrade`], migrating the state of this pallet from V0 to V1. /// -/// Should only be used by the [`VersionedMigration`](frame_support::migrations::VersionedMigration) -/// type in this module to create something to export. +/// In V0 of the template [`crate::Value`] is just a `u32`. In V1, it has been upgraded to +/// contain the struct [`crate::CurrentAndPreviousValue`]. /// -/// The unversioned migration should be kept private so the unversioned migration cannot -/// accidentally be used in any runtimes. -/// -/// For more about this pattern of keeping items private, see -/// - -/// - -mod version_unchecked { - use super::*; +/// In this migration, update the on-chain storage for the pallet to reflect the new storage +/// layout. +pub struct InnerMigrateV0ToV1(sp_std::marker::PhantomData); + +impl UncheckedOnRuntimeUpgrade for InnerMigrateV0ToV1 { + /// Return the existing [`crate::Value`] so we can check that it was correctly set in + /// `InnerMigrateV0ToV1::post_upgrade`. + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + use codec::Encode; + + // Access the old value using the `storage_alias` type + let old_value = v0::Value::::get(); + // Return it as an encoded `Vec` + Ok(old_value.encode()) + } - /// Implements [`OnRuntimeUpgrade`], migrating the state of this pallet from V0 to V1. - /// - /// In V0 of the template [`crate::Value`] is just a `u32`. In V1, it has been upgraded to - /// contain the struct [`crate::CurrentAndPreviousValue`]. + /// Migrate the storage from V0 to V1. /// - /// In this migration, update the on-chain storage for the pallet to reflect the new storage - /// layout. - pub struct MigrateV0ToV1(sp_std::marker::PhantomData); - - impl OnRuntimeUpgrade for MigrateV0ToV1 { - /// Return the existing [`crate::Value`] so we can check that it was correctly set in - /// `version_unchecked::MigrateV0ToV1::post_upgrade`. - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { - use codec::Encode; - - // Access the old value using the `storage_alias` type - let old_value = v0::Value::::get(); - // Return it as an encoded `Vec` - Ok(old_value.encode()) - } - - /// Migrate the storage from V0 to V1. - /// - /// - If the value doesn't exist, there is nothing to do. - /// - If the value exists, it is read and then written back to storage inside a - /// [`crate::CurrentAndPreviousValue`]. - fn on_runtime_upgrade() -> frame_support::weights::Weight { - // Read the old value from storage - if let Some(old_value) = v0::Value::::take() { - // Write the new value to storage - let new = crate::CurrentAndPreviousValue { current: old_value, previous: None }; - crate::Value::::put(new); - // One read for the old value, one write for the new value - T::DbWeight::get().reads_writes(1, 1) - } else { - // One read for trying to access the old value - T::DbWeight::get().reads(1) - } + /// - If the value doesn't exist, there is nothing to do. + /// - If the value exists, it is read and then written back to storage inside a + /// [`crate::CurrentAndPreviousValue`]. + fn on_runtime_upgrade() -> frame_support::weights::Weight { + // Read the old value from storage + if let Some(old_value) = v0::Value::::take() { + // Write the new value to storage + let new = crate::CurrentAndPreviousValue { current: old_value, previous: None }; + crate::Value::::put(new); + // One read for the old value, one write for the new value + T::DbWeight::get().reads_writes(1, 1) + } else { + // One read for trying to access the old value + T::DbWeight::get().reads(1) } + } - /// Verifies the storage was migrated correctly. - /// - /// - If there was no old value, the new value should not be set. - /// - If there was an old value, the new value should be a - /// [`crate::CurrentAndPreviousValue`]. - #[cfg(feature = "try-runtime")] - fn post_upgrade(state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { - use codec::Decode; - use frame_support::ensure; - - let maybe_old_value = Option::::decode(&mut &state[..]).map_err(|_| { - sp_runtime::TryRuntimeError::Other("Failed to decode old value from storage") - })?; - - match maybe_old_value { - Some(old_value) => { - let expected_new_value = - crate::CurrentAndPreviousValue { current: old_value, previous: None }; - let actual_new_value = crate::Value::::get(); - - ensure!(actual_new_value.is_some(), "New value not set"); - ensure!( - actual_new_value == Some(expected_new_value), - "New value not set correctly" - ); - }, - None => { - ensure!(crate::Value::::get().is_none(), "New value unexpectedly set"); - }, - }; - Ok(()) - } + /// Verifies the storage was migrated correctly. + /// + /// - If there was no old value, the new value should not be set. + /// - If there was an old value, the new value should be a [`crate::CurrentAndPreviousValue`]. + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + use codec::Decode; + use frame_support::ensure; + + let maybe_old_value = Option::::decode(&mut &state[..]).map_err(|_| { + sp_runtime::TryRuntimeError::Other("Failed to decode old value from storage") + })?; + + match maybe_old_value { + Some(old_value) => { + let expected_new_value = + crate::CurrentAndPreviousValue { current: old_value, previous: None }; + let actual_new_value = crate::Value::::get(); + + ensure!(actual_new_value.is_some(), "New value not set"); + ensure!( + actual_new_value == Some(expected_new_value), + "New value not set correctly" + ); + }, + None => { + ensure!(crate::Value::::get().is_none(), "New value unexpectedly set"); + }, + }; + Ok(()) } } -/// Public module containing *version checked* migration logic. -/// -/// This is the only module that should be exported from this module. -/// -/// See [`VersionedMigration`](frame_support::migrations::VersionedMigration) docs for more about -/// how it works. -pub mod versioned { - use super::*; - - /// `version_unchecked::MigrateV0ToV1` wrapped in a - /// [`VersionedMigration`](frame_support::migrations::VersionedMigration), which ensures that: - /// - The migration only runs once when the on-chain storage version is 0 - /// - The on-chain storage version is updated to `1` after the migration executes - /// - Reads/Writes from checking/settings the on-chain storage version are accounted for - pub type MigrateV0ToV1 = frame_support::migrations::VersionedMigration< - 0, // The migration will only execute when the on-chain storage version is 0 - 1, // The on-chain storage version will be set to 1 after the migration is complete - version_unchecked::MigrateV0ToV1, - crate::pallet::Pallet, - ::DbWeight, - >; -} +/// [`UncheckedOnRuntimeUpgrade`] implementation [`InnerMigrateV0ToV1`] wrapped in a +/// [`VersionedMigration`](frame_support::migrations::VersionedMigration), which ensures that: +/// - The migration only runs once when the on-chain storage version is 0 +/// - The on-chain storage version is updated to `1` after the migration executes +/// - Reads/Writes from checking/settings the on-chain storage version are accounted for +pub type MigrateV0ToV1 = frame_support::migrations::VersionedMigration< + 0, // The migration will only execute when the on-chain storage version is 0 + 1, // The on-chain storage version will be set to 1 after the migration is complete + InnerMigrateV0ToV1, + crate::pallet::Pallet, + ::DbWeight, +>; /// Tests for our migration. /// @@ -155,10 +129,10 @@ pub mod versioned { /// 3. The storage is in the expected state after the migration #[cfg(any(all(feature = "try-runtime", test), doc))] mod test { + use self::InnerMigrateV0ToV1; use super::*; use crate::mock::{new_test_ext, MockRuntime}; use frame_support::assert_ok; - use version_unchecked::MigrateV0ToV1; #[test] fn handles_no_existing_value() { @@ -168,16 +142,16 @@ mod test { assert!(v0::Value::::get().is_none()); // Get the pre_upgrade bytes - let bytes = match MigrateV0ToV1::::pre_upgrade() { + let bytes = match InnerMigrateV0ToV1::::pre_upgrade() { Ok(bytes) => bytes, Err(e) => panic!("pre_upgrade failed: {:?}", e), }; // Execute the migration - let weight = MigrateV0ToV1::::on_runtime_upgrade(); + let weight = InnerMigrateV0ToV1::::on_runtime_upgrade(); // Verify post_upgrade succeeds - assert_ok!(MigrateV0ToV1::::post_upgrade(bytes)); + assert_ok!(InnerMigrateV0ToV1::::post_upgrade(bytes)); // The weight should be just 1 read for trying to access the old value. assert_eq!(weight, ::DbWeight::get().reads(1)); @@ -195,16 +169,16 @@ mod test { v0::Value::::put(initial_value); // Get the pre_upgrade bytes - let bytes = match MigrateV0ToV1::::pre_upgrade() { + let bytes = match InnerMigrateV0ToV1::::pre_upgrade() { Ok(bytes) => bytes, Err(e) => panic!("pre_upgrade failed: {:?}", e), }; // Execute the migration - let weight = MigrateV0ToV1::::on_runtime_upgrade(); + let weight = InnerMigrateV0ToV1::::on_runtime_upgrade(); // Verify post_upgrade succeeds - assert_ok!(MigrateV0ToV1::::post_upgrade(bytes)); + assert_ok!(InnerMigrateV0ToV1::::post_upgrade(bytes)); // The weight used should be 1 read for the old value, and 1 write for the new // value. diff --git a/substrate/frame/grandpa/src/migrations/v5.rs b/substrate/frame/grandpa/src/migrations/v5.rs index 24cfc34104b..a0865a3f2bf 100644 --- a/substrate/frame/grandpa/src/migrations/v5.rs +++ b/substrate/frame/grandpa/src/migrations/v5.rs @@ -20,7 +20,7 @@ use codec::Decode; use frame_support::{ migrations::VersionedMigration, storage, - traits::{Get, OnRuntimeUpgrade}, + traits::{Get, UncheckedOnRuntimeUpgrade}, weights::Weight, }; use sp_consensus_grandpa::AuthorityList; @@ -36,9 +36,9 @@ fn load_authority_list() -> AuthorityList { } /// Actual implementation of [`MigrateV4ToV5`]. -pub struct MigrateImpl(PhantomData); +pub struct UncheckedMigrateImpl(PhantomData); -impl OnRuntimeUpgrade for MigrateImpl { +impl UncheckedOnRuntimeUpgrade for UncheckedMigrateImpl { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { use codec::Encode; @@ -92,5 +92,10 @@ impl OnRuntimeUpgrade for MigrateImpl { /// Migrate the storage from V4 to V5. /// /// Switches from `GRANDPA_AUTHORITIES_KEY` to a normal FRAME storage item. -pub type MigrateV4ToV5 = - VersionedMigration<4, 5, MigrateImpl, Pallet, ::DbWeight>; +pub type MigrateV4ToV5 = VersionedMigration< + 4, + 5, + UncheckedMigrateImpl, + Pallet, + ::DbWeight, +>; diff --git a/substrate/frame/identity/src/migration.rs b/substrate/frame/identity/src/migration.rs index 88ac08d1bf5..8725bfd39df 100644 --- a/substrate/frame/identity/src/migration.rs +++ b/substrate/frame/identity/src/migration.rs @@ -16,7 +16,9 @@ //! Storage migrations for the Identity pallet. use super::*; -use frame_support::{migrations::VersionedMigration, pallet_prelude::*, traits::OnRuntimeUpgrade}; +use frame_support::{ + migrations::VersionedMigration, pallet_prelude::*, traits::UncheckedOnRuntimeUpgrade, +}; #[cfg(feature = "try-runtime")] use codec::{Decode, Encode}; @@ -66,7 +68,7 @@ pub mod v1 { /// prevent stalling a parachain by accumulating too much weight in the migration. To have an /// unlimited migration (e.g. in a chain without PoV limits), set this to `u64::MAX`. pub struct VersionUncheckedMigrateV0ToV1(PhantomData); - impl OnRuntimeUpgrade for VersionUncheckedMigrateV0ToV1 { + impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV0ToV1 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, TryRuntimeError> { let identities = v0::IdentityOf::::iter().count(); diff --git a/substrate/frame/nomination-pools/src/migration.rs b/substrate/frame/nomination-pools/src/migration.rs index ca9c0874a83..796b310862a 100644 --- a/substrate/frame/nomination-pools/src/migration.rs +++ b/substrate/frame/nomination-pools/src/migration.rs @@ -17,7 +17,7 @@ use super::*; use crate::log; -use frame_support::traits::OnRuntimeUpgrade; +use frame_support::traits::{OnRuntimeUpgrade, UncheckedOnRuntimeUpgrade}; use sp_std::{collections::btree_map::BTreeMap, vec::Vec}; #[cfg(feature = "try-runtime")] @@ -132,7 +132,7 @@ pub mod v8 { } pub struct VersionUncheckedMigrateV7ToV8(sp_std::marker::PhantomData); - impl OnRuntimeUpgrade for VersionUncheckedMigrateV7ToV8 { + impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV7ToV8 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, TryRuntimeError> { Ok(Vec::new()) @@ -211,7 +211,7 @@ pub(crate) mod v7 { CountedStorageMap, Twox64Concat, PoolId, V7BondedPoolInner>; pub struct VersionUncheckedMigrateV6ToV7(sp_std::marker::PhantomData); - impl OnRuntimeUpgrade for VersionUncheckedMigrateV6ToV7 { + impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV6ToV7 { fn on_runtime_upgrade() -> Weight { let migrated = BondedPools::::count(); // The TVL should be the sum of all the funds that are actively staked and in the @@ -282,7 +282,7 @@ mod v6 { }) } } - impl OnRuntimeUpgrade for MigrateToV6 { + impl UncheckedOnRuntimeUpgrade for MigrateToV6 { fn on_runtime_upgrade() -> Weight { let mut success = 0u64; let mut fail = 0u64; diff --git a/substrate/frame/society/src/migrations.rs b/substrate/frame/society/src/migrations.rs index 8fd87b1163a..7ded1f84f58 100644 --- a/substrate/frame/society/src/migrations.rs +++ b/substrate/frame/society/src/migrations.rs @@ -19,7 +19,7 @@ use super::*; use codec::{Decode, Encode}; -use frame_support::traits::{Defensive, DefensiveOption, Instance, OnRuntimeUpgrade}; +use frame_support::traits::{Defensive, DefensiveOption, Instance, UncheckedOnRuntimeUpgrade}; #[cfg(feature = "try-runtime")] use sp_runtime::TryRuntimeError; @@ -36,7 +36,7 @@ impl< T: Config, I: Instance + 'static, PastPayouts: Get::AccountId, BalanceOf)>>, - > OnRuntimeUpgrade for VersionUncheckedMigrateToV2 + > UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateToV2 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, TryRuntimeError> { diff --git a/substrate/frame/support/src/migrations.rs b/substrate/frame/support/src/migrations.rs index 2ceab44cb16..b8cbcd69048 100644 --- a/substrate/frame/support/src/migrations.rs +++ b/substrate/frame/support/src/migrations.rs @@ -41,19 +41,19 @@ use sp_std::{marker::PhantomData, vec::Vec}; /// It takes 5 type parameters: /// - `From`: The version being upgraded from. /// - `To`: The version being upgraded to. -/// - `Inner`: An implementation of `OnRuntimeUpgrade`. +/// - `Inner`: An implementation of `UncheckedOnRuntimeUpgrade`. /// - `Pallet`: The Pallet being upgraded. /// - `Weight`: The runtime's RuntimeDbWeight implementation. /// /// When a [`VersionedMigration`] `on_runtime_upgrade`, `pre_upgrade`, or `post_upgrade` method is /// called, the on-chain version of the pallet is compared to `From`. If they match, the `Inner` -/// equivalent is called and the pallets on-chain version is set to `To` after the migration. -/// Otherwise, a warning is logged notifying the developer that the upgrade was a noop and should -/// probably be removed. +/// `UncheckedOnRuntimeUpgrade` is called and the pallets on-chain version is set to `To` +/// after the migration. Otherwise, a warning is logged notifying the developer that the upgrade was +/// a noop and should probably be removed. /// -/// It is STRONGLY RECOMMENDED to write the unversioned migration logic in a private module and -/// only export the versioned migration logic to prevent accidentally using the unversioned -/// migration in any runtimes. +/// By not bounding `Inner` with `OnRuntimeUpgrade`, we prevent developers from +/// accidentally using the unchecked version of the migration in a runtime upgrade instead of +/// [`VersionedMigration`]. /// /// ### Examples /// ```ignore @@ -71,9 +71,9 @@ use sp_std::{marker::PhantomData, vec::Vec}; /// /// - https://internals.rust-lang.org/t/lang-team-minutes-private-in-public-rules/4504/40 /// mod version_unchecked { /// use super::*; -/// pub struct MigrateV5ToV6(sp_std::marker::PhantomData); -/// impl OnRuntimeUpgrade for VersionUncheckedMigrateV5ToV6 { -/// // OnRuntimeUpgrade implementation... +/// pub struct VersionUncheckedMigrateV5ToV6(sp_std::marker::PhantomData); +/// impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV5ToV6 { +/// // `UncheckedOnRuntimeUpgrade` implementation... /// } /// } /// @@ -116,7 +116,7 @@ pub enum VersionedPostUpgradeData { impl< const FROM: u16, const TO: u16, - Inner: crate::traits::OnRuntimeUpgrade, + Inner: crate::traits::UncheckedOnRuntimeUpgrade, Pallet: GetStorageVersion + PalletInfoAccess, DbWeight: Get, > crate::traits::OnRuntimeUpgrade for VersionedMigration diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 24e7e1c8a65..66777cef7b8 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -87,7 +87,7 @@ pub use hooks::GenesisBuild; pub use hooks::{ BeforeAllRuntimeMigrations, BuildGenesisConfig, Hooks, IntegrityTest, OnFinalize, OnGenesis, OnIdle, OnInitialize, OnPoll, OnRuntimeUpgrade, OnTimestampSet, PostInherents, - PostTransactions, PreInherents, + PostTransactions, PreInherents, UncheckedOnRuntimeUpgrade, }; pub mod schedule; diff --git a/substrate/frame/support/src/traits/hooks.rs b/substrate/frame/support/src/traits/hooks.rs index d83e2704745..ccccc506328 100644 --- a/substrate/frame/support/src/traits/hooks.rs +++ b/substrate/frame/support/src/traits/hooks.rs @@ -227,6 +227,30 @@ pub trait OnRuntimeUpgrade { } } +/// This trait is intended for use within `VersionedMigration` to execute storage migrations without +/// automatic version checks. Implementations should ensure migration logic is safe and idempotent. +pub trait UncheckedOnRuntimeUpgrade { + /// Called within `VersionedMigration` to execute the actual migration. It is also + /// expected that no version checks are performed within this function. + /// + /// See also [`Hooks::on_runtime_upgrade`]. + fn on_runtime_upgrade() -> Weight { + Weight::zero() + } + + /// See [`Hooks::pre_upgrade`]. + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, TryRuntimeError> { + Ok(Vec::new()) + } + + /// See [`Hooks::post_upgrade`]. + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), TryRuntimeError> { + Ok(()) + } +} + #[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] #[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] #[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] @@ -459,7 +483,9 @@ pub trait Hooks { /// ## Implementation Note: Standalone Migrations /// /// Additional migrations can be created by directly implementing [`OnRuntimeUpgrade`] on - /// structs and passing them to `Executive`. + /// structs and passing them to `Executive`. Or alternatively, by implementing + /// [`UncheckedOnRuntimeUpgrade`], passing it to [`crate::migrations::VersionedMigration`], + /// which already implements [`OnRuntimeUpgrade`]. /// /// ## Implementation Note: Pallet Versioning /// diff --git a/substrate/frame/support/test/tests/versioned_migration.rs b/substrate/frame/support/test/tests/versioned_migration.rs index 3fdfb902129..e7d146940cb 100644 --- a/substrate/frame/support/test/tests/versioned_migration.rs +++ b/substrate/frame/support/test/tests/versioned_migration.rs @@ -23,7 +23,7 @@ use frame_support::{ construct_runtime, derive_impl, migrations::VersionedMigration, parameter_types, - traits::{GetStorageVersion, OnRuntimeUpgrade, StorageVersion}, + traits::{GetStorageVersion, OnRuntimeUpgrade, StorageVersion, UncheckedOnRuntimeUpgrade}, weights::constants::RocksDbWeight, }; use frame_system::Config; @@ -103,9 +103,11 @@ parameter_types! { static PostUpgradeCalledWith: Vec = Vec::new(); } -/// Implement `OnRuntimeUpgrade` for `SomeUnversionedMigration`. +/// Implement `UncheckedOnRuntimeUpgrade` for `SomeUnversionedMigration`. /// It sets SomeStorage to S, and returns a weight derived from UpgradeReads and UpgradeWrites. -impl OnRuntimeUpgrade for SomeUnversionedMigration { +impl UncheckedOnRuntimeUpgrade + for SomeUnversionedMigration +{ fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { PreUpgradeCalled::set(true); Ok(PreUpgradeReturnBytes::get().to_vec()) diff --git a/substrate/frame/uniques/src/migration.rs b/substrate/frame/uniques/src/migration.rs index ba0855a6bb6..90d44e7790d 100644 --- a/substrate/frame/uniques/src/migration.rs +++ b/substrate/frame/uniques/src/migration.rs @@ -18,15 +18,15 @@ //! Various pieces of common functionality. use super::*; use core::marker::PhantomData; -use frame_support::traits::{Get, OnRuntimeUpgrade}; +use frame_support::traits::{Get, UncheckedOnRuntimeUpgrade}; mod v1 { use super::*; /// Actual implementation of the storage migration. - pub struct MigrateToV1Impl(PhantomData<(T, I)>); + pub struct UncheckedMigrateToV1Impl(PhantomData<(T, I)>); - impl, I: 'static> OnRuntimeUpgrade for MigrateToV1Impl { + impl, I: 'static> UncheckedOnRuntimeUpgrade for UncheckedMigrateToV1Impl { fn on_runtime_upgrade() -> frame_support::weights::Weight { let mut count = 0; for (collection, detail) in Collection::::iter() { @@ -49,7 +49,7 @@ mod v1 { pub type MigrateV0ToV1 = frame_support::migrations::VersionedMigration< 0, 1, - v1::MigrateToV1Impl, + v1::UncheckedMigrateToV1Impl, Pallet, ::DbWeight, >; -- GitLab From 5d9826c2620aff205811edf0e6a07b55a52cbf50 Mon Sep 17 00:00:00 2001 From: Clara van Staden Date: Tue, 2 Apr 2024 15:53:05 +0200 Subject: [PATCH 150/187] Snowbridge: Synchronize from Snowfork repository (#3761) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR includes the following 2 improvements: ## Ethereum Client Author: @yrong ### Original Upstream PRs - https://github.com/Snowfork/polkadot-sdk/pull/123 - https://github.com/Snowfork/polkadot-sdk/pull/125 ### Description The Ethereum client syncs beacon headers as they are finalized, and imports every execution header. When a message is received, it is verified against the import execution header. This is unnecessary, since the execution header can be sent with the message as proof. The recent Deneb Ethereum upgrade made it easier to locate the relevant beacon header from an execution header, and so this improvement was made possible. This resolves a concern @svyatonik had in our initial Rococo PR: https://github.com/paritytech/polkadot-sdk/pull/2522#discussion_r1431270691 ## Inbound Queue Author: @yrong ### Original Upstream PR - https://github.com/Snowfork/polkadot-sdk/pull/118 ### Description When the AH sovereign account (who pays relayer rewards) is depleted, the inbound message will not fail. The relayer just will not receive rewards. Both these changes were done by @yrong, many thanks. ❤️ --------- Co-authored-by: claravanstaden Co-authored-by: Ron Co-authored-by: Vincent Geddes Co-authored-by: Svyatoslav Nikolsky --- .../ethereum-client/fixtures/src/lib.rs | 272 ++++++---- .../ethereum-client/src/benchmarking/mod.rs | 18 - .../pallets/ethereum-client/src/impls.rs | 138 +++-- .../pallets/ethereum-client/src/lib.rs | 237 +-------- .../pallets/ethereum-client/src/mock.rs | 61 +-- .../pallets/ethereum-client/src/tests.rs | 474 +++++------------- .../pallets/ethereum-client/src/types.rs | 12 +- .../pallets/ethereum-client/src/weights.rs | 7 - .../fixtures/execution-header-update.json | 54 -- .../tests/fixtures/execution-proof.json | 54 ++ .../fixtures/finalized-header-update.json | 48 +- .../tests/fixtures/inbound-message.json | 94 +++- .../tests/fixtures/initial-checkpoint.json | 30 +- .../tests/fixtures/sync-committee-update.json | 42 +- .../pallets/inbound-queue/fixtures/src/lib.rs | 11 - .../fixtures/src/register_token.rs | 84 +++- .../register_token_with_insufficient_fee.rs | 42 -- .../inbound-queue/fixtures/src/send_token.rs | 82 ++- .../fixtures/src/send_token_to_penpal.rs | 86 +++- .../inbound-queue/src/benchmarking/mod.rs | 4 +- .../pallets/inbound-queue/src/lib.rs | 25 +- .../pallets/inbound-queue/src/mock.rs | 45 +- .../pallets/inbound-queue/src/test.rs | 83 ++- .../snowbridge/primitives/beacon/src/lib.rs | 8 +- .../snowbridge/primitives/beacon/src/types.rs | 100 ++-- .../primitives/beacon/src/updates.rs | 47 +- .../snowbridge/primitives/core/src/inbound.rs | 18 +- .../snowbridge/runtime/test-common/src/lib.rs | 22 - .../snowbridge/scripts/contribute-upstream.sh | 6 + .../bridge-hub-rococo/src/tests/snowbridge.rs | 148 +++--- .../assets/asset-hub-rococo/src/xcm_config.rs | 4 +- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 13 +- .../snowbridge_pallet_ethereum_client.rs | 22 - .../snowbridge_pallet_inbound_queue.rs | 14 +- prdoc/pr_3761.prdoc | 25 + 35 files changed, 1123 insertions(+), 1307 deletions(-) delete mode 100755 bridges/snowbridge/pallets/ethereum-client/tests/fixtures/execution-header-update.json create mode 100755 bridges/snowbridge/pallets/ethereum-client/tests/fixtures/execution-proof.json delete mode 100644 bridges/snowbridge/pallets/inbound-queue/fixtures/src/register_token_with_insufficient_fee.rs create mode 100644 prdoc/pr_3761.prdoc diff --git a/bridges/snowbridge/pallets/ethereum-client/fixtures/src/lib.rs b/bridges/snowbridge/pallets/ethereum-client/fixtures/src/lib.rs index facaffb8149..37fe45ba60b 100644 --- a/bridges/snowbridge/pallets/ethereum-client/fixtures/src/lib.rs +++ b/bridges/snowbridge/pallets/ethereum-client/fixtures/src/lib.rs @@ -6,9 +6,10 @@ use hex_literal::hex; use snowbridge_beacon_primitives::{ - types::deneb, updates::AncestryProof, BeaconHeader, ExecutionHeaderUpdate, - NextSyncCommitteeUpdate, SyncAggregate, SyncCommittee, VersionedExecutionPayloadHeader, + types::deneb, AncestryProof, BeaconHeader, ExecutionProof, NextSyncCommitteeUpdate, + SyncAggregate, SyncCommittee, VersionedExecutionPayloadHeader, }; +use snowbridge_core::inbound::{InboundQueueFixture, Log, Message, Proof}; use sp_core::U256; use sp_std::{boxed::Box, vec}; @@ -20,11 +21,11 @@ type Update = snowbridge_beacon_primitives::Update; pub fn make_checkpoint() -> Box { Box::new(CheckpointUpdate { header: BeaconHeader { - slot: 2496, - proposer_index: 2, - parent_root: hex!("c99e49787106733eeebab4d93eb326e1f2214575c9d928f0c4ab0da0776f1622").into(), - state_root: hex!("fbf8a08c86ef36bd173e37e733da4a78aa8e85fee99a990e858dd12a59087fde").into(), - body_root: hex!("a2a8ad06901447b2807a9059580a4c40d8a941f325b1343c69f7c7c6c90e4ab0").into(), + slot: 864, + proposer_index: 4, + parent_root: hex!("614e7672f991ac268cd841055973f55e1e42228831a211adef207bb7329be614").into(), + state_root: hex!("5fa8dfca3d760e4242ab46d529144627aa85348a19173b6e081172c701197a4a").into(), + body_root: hex!("0f34c083b1803666bb1ac5e73fa71582731a2cf37d279ff0a3b0cad5a2ff371e").into(), }, current_sync_committee: SyncCommittee { pubkeys: [ @@ -544,20 +545,20 @@ pub fn make_checkpoint() -> Box { aggregate_pubkey: hex!("8fbd66eeec2ff69ef0b836f04b1d67d88bcd4dfd495061964ad757c77abe822a39fa1cd8ed0d4d9bc9276cea73fd745c").into(), }, current_sync_committee_branch: vec![ - hex!("3ade38d498a062b50880a9409e1ca3a7fd4315d91eeb3bb83e56ac6bfe8d6a59").into(), - hex!("93880225bf99a0c5ec22b266ff829837754e9c5edf37a68c05b8f803fd82fa45").into(), - hex!("4c60656ec9a95fcf11030ad309c716b5b15beb7f60a0bcfc7c9d4eff505472ff").into(), - hex!("22d1645fceb4bf9a695043dda19a53e784ec70df6a6b1bd66ea30eba1cca5f2f").into(), - hex!("a8fc6cad84ceefc633ec56c2d031d525e1cb4b51c70eb252919fce5bba9a1fde").into(), + hex!("3ade38d498a062b50880a9409e1ca3a7fd4315d91eeb3bb83e56ac6bfe8d6a59").into(), + hex!("a9e90f89e7f90fd5d79a6bbcaf40ba5cfc05ab1b561ac51c84867c32248d5b1e").into(), + hex!("bd1a76b03e02402bb24a627de1980a80ab17691980271f597b844b89b497ef75").into(), + hex!("07bbcd27c7cad089023db046eda17e8209842b7d97add8b873519e84fe6480e7").into(), + hex!("94c11eeee4cb6192bf40810f23486d8c75dfbc2b6f28d988d6f74435ede243b0").into(), ], validators_root: hex!("270d43e74ce340de4bca2b1936beca0f4f5408d9e78aec4850920baf659d5b69").into(), - block_roots_root: hex!("d160b7687041891b73e54b06fc4e04f82d0fa8fdd76705895e216c6b24709dfe").into(), + block_roots_root: hex!("b9aab9c388c4e4fcd899b71f62c498fc73406e38e8eb14aa440e9affa06f2a10").into(), block_roots_branch: vec![ - hex!("105290e42d98ab6a0ada6e55453cede36c672abf645eeb986b88d7487616e135").into(), - hex!("9da41f274bcdf6122335443d9ce94d07163b48dba3e2f9499ff56f4e48b48b99").into(), - hex!("ecea7e1d3152d8130e83afdfe34b4de4ba2b69a33c9471991096daf454de9cf5").into(), - hex!("b2bf1758e50b2bfff29169fbc70fdb884b2b05bb615dbc53567574da6f4f1ae2").into(), - hex!("cd87069daf70975779126d6af833b7d636c75ca4d5e750ebcad0e76408a5e5bf").into(), + hex!("733422bd810895dab74cbbe07c69dd440cbb51f573181ad4dddac30fcdd0f41f").into(), + hex!("9b9eca73ab01d14549c325ba1b4610bb20bf1f8ec2dbd649f9d8cc7f3cea75fa").into(), + hex!("bcc666ad0ad9f9725cbd682bc95589d35b1b53b2a615f1e6e8dd5e086336becf").into(), + hex!("3069b547a08f703a1715016e926cbd64e71f93f64fb68d98d8c8f1ab745c46e5").into(), + hex!("c2de7e1097239404e17b263cfa0473533cc41e903cb03440d633bc5c27314cb4").into(), ], }) } @@ -567,13 +568,13 @@ pub fn make_sync_committee_update() -> Box { attested_header: BeaconHeader { slot: 129, proposer_index: 5, - parent_root: hex!("e32b6c18f029e755b0273dc1c4fa2bc4979794c8286ad40276c1b8a8e36049d8").into(), - state_root: hex!("5ec9dacf25a5f09f20be0c59246b3d8dcfe64bd085b4bac5cec180690339801e").into(), - body_root: hex!("4080cf2412d6ff77fc3164ad6155423a7112f207f173145ec16371a93f481f87").into(), + parent_root: hex!("c2def03fe44a2802130ca1a6d8406e4ccf4f344fec7075d4d84431cd4a8b0904").into(), + state_root: hex!("fa62cde6666add7353d7aedcb61ebe3c6c84b5361e34f814825b1250affb5be4").into(), + body_root: hex!("0f9c69f243fe7b5fa5860396c66c720a9e8b1e526e7914188930497cc4a9134c").into(), }, sync_aggregate: SyncAggregate{ sync_committee_bits: hex!("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), - sync_committee_signature: hex!("a761c3333fbb3d36bc8f65454f898da38001499dcd37494cf3d86940a995399ae649216ba4c985af154f83f72c8b1856079b7636a7a8d7d3f7602df2cbf699edb72b65253e82de4d9cc4db7377eafb22f799129f63f094a21c00675bdd5cc243").into(), + sync_committee_signature: hex!("810cfde2afea3e276256c09bdf1cd321c33dcadeefddcfd24f488e6f756d917cfda90b5b437b3a4b4ef880985afa28a40cf565ec0a82877ddee36adc01d55d9d4a911ae3e22556e4c2636f1c707366fba019fb49450440fcd263d0b054b04bf0").into(), }, signature_slot: 130, next_sync_committee_update: Some(NextSyncCommitteeUpdate { @@ -1096,34 +1097,34 @@ pub fn make_sync_committee_update() -> Box { }, next_sync_committee_branch: vec![ hex!("3ade38d498a062b50880a9409e1ca3a7fd4315d91eeb3bb83e56ac6bfe8d6a59").into(), - hex!("fd1e5ff5d4a15081efe3ff17857b1f95984c9a271b1c41c2f81f43e60c2cc541").into(), - hex!("e1c97f93bb7352d395d1ff8ee29881572cb7eb5d71634783701171dcd30cd93d").into(), - hex!("77fa2170ddbd89b15dae02f2e6cf9f76c8e00d1c4217320acffbe01576d0da61").into(), - hex!("e97288e0627219087a024078d69445f34f0583a6350a7c3c40c39fd1fa6f8d68").into(), + hex!("43276bee17fc9fba3f4866e902f0e5b5b308d79db91154bb8bf819973837a7d9").into(), + hex!("5572348e13ce59446ca0ea7cfeed07579da05f121920a76559e19bda94dd81cd").into(), + hex!("2d58adca9f3c742530de037f1933d6de1920ea4b68581613d4bc32b71547f221").into(), + hex!("7072b3c6577cd5a89b3234968f316f54630bb97eafbdb59e5b61637a9640255f").into(), ], }), finalized_header: BeaconHeader{ slot: 64, proposer_index: 4, - parent_root: hex!("0f7bc2353778c14c7f6dba0fc5fe6eec87228b0d3a5447b61dce67b4d9338de3").into(), - state_root: hex!("feb990de653ce494c0a263f820eaf05a9300dbdc30cb6065ede602827bfccde4").into(), - body_root: hex!("f5235cd8c24f2695fc5b7989926305c10ad8cf5a87d62a739f675f5543df2ec1").into(), + parent_root: hex!("a876486aaad7ddb897f369fd22d0a9903cd61d00c9e0dfe7998dd68d1008c678").into(), + state_root: hex!("818e21c3388575f8ccc9ff17ec79d5a57915bcd31bccf47770f65a18e068416b").into(), + body_root: hex!("1d1f73b864b3bb7e11ff91b56ca1381e0f9ca8122b2c542db88243604c763019").into(), }, finality_branch: vec![ hex!("0200000000000000000000000000000000000000000000000000000000000000").into(), hex!("10c726fac935bf9657cc7476d3cfa7bedec5983dcfb59e8a7df6d0a619e108d7").into(), hex!("98e9116c6bb7f20de18800dc63e73e689d06d6a47d35b5e2b32cf093d475840d").into(), - hex!("e1c97f93bb7352d395d1ff8ee29881572cb7eb5d71634783701171dcd30cd93d").into(), - hex!("77fa2170ddbd89b15dae02f2e6cf9f76c8e00d1c4217320acffbe01576d0da61").into(), - hex!("e97288e0627219087a024078d69445f34f0583a6350a7c3c40c39fd1fa6f8d68").into(), + hex!("5572348e13ce59446ca0ea7cfeed07579da05f121920a76559e19bda94dd81cd").into(), + hex!("2d58adca9f3c742530de037f1933d6de1920ea4b68581613d4bc32b71547f221").into(), + hex!("7072b3c6577cd5a89b3234968f316f54630bb97eafbdb59e5b61637a9640255f").into(), ], - block_roots_root: hex!("6fcdfd1c3fb1bdd421fe59dddfff3855b5ed5e30373887991a0059d019ad12bc").into(), + block_roots_root: hex!("715b08694bef183a6d94b3113d16a7129f89fc3edec85a7e0eaf6ef9153552ef").into(), block_roots_branch: vec![ - hex!("94b59531f172bc24f914bc0c10104ccb158676850f8cc3b47b6ddb7f096ebdd7").into(), - hex!("22470ed9155a938587d44d5fa19217c0f939d8862e504e67cd8cb4d1b960795e").into(), - hex!("feec3ef1a68f93849e71e84f90b99602cccc31868137b6887ca8244a4b979e8e").into(), + hex!("4028c72c71b6ce80ea7d18b2c9471f4e4fa39746261a9921e832a4a2f9bdf7bb").into(), + hex!("75f98062661785d3290b7bd998b64446582baa49210733fd4603e1a97cd45a44").into(), + hex!("6fb757f44052f30c464810f01b0132adfa1a5446d8715b41e9af88eee1ee3e65").into(), hex!("5340ad5877c72dca689ca04bc8fedb78d67a4801d99887937edd8ccd29f87e82").into(), - hex!("f5ff4b0c6190005015889879568f5f0d9c40134c7ec4ffdda47950dcd92395ad").into(), + hex!("f2b3cb56753939a728ccad399a434ca490f018f2f331529ec0d8b2d59c509271").into(), ], }) } @@ -1131,95 +1132,180 @@ pub fn make_sync_committee_update() -> Box { pub fn make_finalized_header_update() -> Box { Box::new(Update { attested_header: BeaconHeader { - slot: 2566, - proposer_index: 6, - parent_root: hex!("6eb9f13a2c496318ce1ab3087bbd872f5c9519a1a7ca8231a2453e3cb523af00").into(), - state_root: hex!("c8cb12766113dff7e46d2917267bf33d0626d99dd47715fcdbc5c65fad3c04b4").into(), - body_root: hex!("d8cfd0d7bc9bc3724417a1655bb0a67c0765ca36197320f4d834150b52ef1420").into(), + slot: 933, + proposer_index: 1, + parent_root: hex!("f5fc63e2780ca302b97aea73fc95d74d702b5afe9a772c2b68f695026337b620").into(), + state_root: hex!("d856d11636bc4d866e78be9e747b222b0977556a367ab42e4085277301438050").into(), + body_root: hex!("5689091ab4eb76c2e876271add4924e1c66ce987c300c24aac2ad8c703e9a33f").into(), }, sync_aggregate: SyncAggregate{ sync_committee_bits: hex!("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), - sync_committee_signature: hex!("9296f9a0387f2cac47008e22ad7c3cd3d49d35384c13e6aa1eacca7dca7c3d2ca81515e50eb3396b9550ed20ef7d8fa2049a186598feb2c00e93728045fcff917733d1827481b8fc95f3913e27fc70112c2490496eb57bb7181f02c3f9fd471f").into(), + sync_committee_signature: hex!("93a3d482fe2a2f7fd2b634169752a8fddf1dc28b23a020b398be8526faf37a74ca0f6db1bed78a9c7256c09a6115235e108e0e8a7ce09287317b0856c4b77dfa5adba6cf4c3ebea5bfa4cd2fcde80fd0a532f2defe65d530201d5d2258796559").into(), }, - signature_slot: 2567, + signature_slot: 934, next_sync_committee_update: None, finalized_header: BeaconHeader { - slot: 2496, - proposer_index: 2, - parent_root: hex!("c99e49787106733eeebab4d93eb326e1f2214575c9d928f0c4ab0da0776f1622").into(), - state_root: hex!("fbf8a08c86ef36bd173e37e733da4a78aa8e85fee99a990e858dd12a59087fde").into(), - body_root: hex!("a2a8ad06901447b2807a9059580a4c40d8a941f325b1343c69f7c7c6c90e4ab0").into(), + slot: 864, + proposer_index: 4, + parent_root: hex!("614e7672f991ac268cd841055973f55e1e42228831a211adef207bb7329be614").into(), + state_root: hex!("5fa8dfca3d760e4242ab46d529144627aa85348a19173b6e081172c701197a4a").into(), + body_root: hex!("0f34c083b1803666bb1ac5e73fa71582731a2cf37d279ff0a3b0cad5a2ff371e").into(), }, finality_branch: vec![ - hex!("4e00000000000000000000000000000000000000000000000000000000000000").into(), + hex!("1b00000000000000000000000000000000000000000000000000000000000000").into(), hex!("10c726fac935bf9657cc7476d3cfa7bedec5983dcfb59e8a7df6d0a619e108d7").into(), hex!("98e9116c6bb7f20de18800dc63e73e689d06d6a47d35b5e2b32cf093d475840d").into(), - hex!("958b8e43347f6df6fa5eb3d62d06a862381a6585aa40640dd1c0de11f1cf89c1").into(), - hex!("f107dce04faa86a28fc5d4a618be9cb8d4fc3c23d6c42c3624f3ff4bf6586a03").into(), - hex!("a501cdc02e86969ac3e4d0c5a36f4f049efaa1ab8cb6693f51d130eb52a80f30").into(), + hex!("f12d9aededc72724e417b518fe6f847684f26f81616243dedf8c551cc7d504f5").into(), + hex!("89a85d0907ab3fd6e00ae385f61d456c6191646404ae7b8d23d0e60440cf4d00").into(), + hex!("9fc943b6020eb61d780d78bcc6f6102a81d2c868d58f36e61c6e286a2dc4d8c2").into(), ], - block_roots_root: hex!("d160b7687041891b73e54b06fc4e04f82d0fa8fdd76705895e216c6b24709dfe").into(), + block_roots_root: hex!("b9aab9c388c4e4fcd899b71f62c498fc73406e38e8eb14aa440e9affa06f2a10").into(), block_roots_branch: vec![ - hex!("105290e42d98ab6a0ada6e55453cede36c672abf645eeb986b88d7487616e135").into(), - hex!("9da41f274bcdf6122335443d9ce94d07163b48dba3e2f9499ff56f4e48b48b99").into(), - hex!("ecea7e1d3152d8130e83afdfe34b4de4ba2b69a33c9471991096daf454de9cf5").into(), - hex!("b2bf1758e50b2bfff29169fbc70fdb884b2b05bb615dbc53567574da6f4f1ae2").into(), - hex!("cd87069daf70975779126d6af833b7d636c75ca4d5e750ebcad0e76408a5e5bf").into(), + hex!("733422bd810895dab74cbbe07c69dd440cbb51f573181ad4dddac30fcdd0f41f").into(), + hex!("9b9eca73ab01d14549c325ba1b4610bb20bf1f8ec2dbd649f9d8cc7f3cea75fa").into(), + hex!("bcc666ad0ad9f9725cbd682bc95589d35b1b53b2a615f1e6e8dd5e086336becf").into(), + hex!("3069b547a08f703a1715016e926cbd64e71f93f64fb68d98d8c8f1ab745c46e5").into(), + hex!("c2de7e1097239404e17b263cfa0473533cc41e903cb03440d633bc5c27314cb4").into(), ] }) } -pub fn make_execution_header_update() -> Box { - Box::new(ExecutionHeaderUpdate { +pub fn make_execution_proof() -> Box { + Box::new(ExecutionProof { header: BeaconHeader { - slot: 215, - proposer_index: 2, - parent_root: hex!("97518f531a252bb6ca547b21aca9da767943ec99211d3b15c804e34c3a523f45").into(), - state_root: hex!("b088b5a3a8c90d6dc919a695cd7bb0267c6f983ea2e675c559ceb8f46cb90b67").into(), - body_root: hex!("0ba23c8224fdd01531d5ad51486353bd524a0b4c20bca704e26d3210616f829b").into(), + slot: 393, + proposer_index: 4, + parent_root: hex!("6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef").into(), + state_root: hex!("b62ac34a8cb82497be9542fe2114410c9f6021855b766015406101a1f3d86434").into(), + body_root: hex!("04005fe231e11a5b7b1580cb73b177ae8b338bedd745497e6bb7122126a806db").into(), }, ancestry_proof: Some(AncestryProof { header_branch: vec![ - hex!("97518f531a252bb6ca547b21aca9da767943ec99211d3b15c804e34c3a523f45").into(), - hex!("5ce0db996bd499c2b4f7a93263d5aafd052f420efb617cce6fdd54e25516aa45").into(), - hex!("84f0e373b66011ce774c7061440c0a50a51cce2b4b335395eee3e563d605597f").into(), - hex!("48f9ccc5f9594142c18c3b5c39a99f0549329c6ab3ba06c9a50030eadca87770").into(), - hex!("f89d6e311e05bc75a6f63ce118bccce254551f1a88d54c3b4f773f81f946bd99").into(), - hex!("2edd6d893c22636675147c07dfcdb541a146e87c3f15b51c388be4868246dc9b").into(), - hex!("d76b7de5f856e3208a91a42c9c398a7f4fab35e667bf916346050ae742514a2d").into(), - hex!("83a2e233e76385953ca41de4c3afe60471a61f0cc1b3846b4a0670e3e563b747").into(), - hex!("e783a5a109c2ad74e4eb53e8f6b11b31266a92a9e16c1fd5873109c5d41b282c").into(), - hex!("d4ea1ef3869ee6a0fd0b19d7d70027d144eecd4f1d32cbf47632a0a9069164b9").into(), - hex!("f8179564b58eb93a850d35e4156a04db651106442ad891c3e85155c1762792f1").into(), - hex!("4cbb1edb48cf1e32fb30db60aaaeaf6190ffe4d0c8dbc96cec307daecb78be12").into(), + hex!("6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef").into(), + hex!("fa84cc88ca53a72181599ff4eb07d8b444bce023fe2347c3b4f51004c43439d3").into(), + hex!("cadc8ae211c6f2221c9138e829249adf902419c78eb4727a150baa4d9a02cc9d").into(), + hex!("33a89962df08a35c52bd7e1d887cd71fa7803e68787d05c714036f6edf75947c").into(), + hex!("2c9760fce5c2829ef3f25595a703c21eb22d0186ce223295556ed5da663a82cf").into(), + hex!("e1aa87654db79c8a0ecd6c89726bb662fcb1684badaef5cd5256f479e3c622e1").into(), + hex!("aa70d5f314e4a1fbb9c362f3db79b21bf68b328887248651fbd29fc501d0ca97").into(), + hex!("160b6c235b3a1ed4ef5f80b03ee1c76f7bf3f591c92fca9d8663e9221b9f9f0f").into(), + hex!("f68d7dcd6a07a18e9de7b5d2aa1980eb962e11d7dcb584c96e81a7635c8d2535").into(), + hex!("1d5f912dfd6697110dd1ecb5cb8e77952eef57d85deb373572572df62bb157fc").into(), + hex!("ffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b").into(), + hex!("6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220").into(), hex!("b7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f").into(), ], - finalized_block_root: hex!("890a7f23b9ed2160901654be9efc575d6830ca860e2a97866ae3423fb7bd7231").into(), + finalized_block_root: hex!("751414cd97c0624f922b3e80285e9f776b08fa22fd5f87391f2ed7ef571a8d46").into(), }), execution_header: VersionedExecutionPayloadHeader::Deneb(deneb::ExecutionPayloadHeader { - parent_hash: hex!("d82ec63f5c5e6ba61d62f09c188f158e6449b94bdcc31941e68639eec3c4cf7a").into(), + parent_hash: hex!("8092290aa21b7751576440f77edd02a94058429ce50e63a92d620951fb25eda2").into(), fee_recipient: hex!("0000000000000000000000000000000000000000").into(), - state_root: hex!("8b65545fe5f3216b47b6339b9c91ca2b7f1032a970b04246d9e9fb4460ee34c3").into(), - receipts_root: hex!("7b1f61b9714c080ef0be014e01657a15f45f0304b477beebc7ca5596c8033095").into(), - logs_bloom: hex!("00000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000000000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040004000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000200000000000010").into(), - prev_randao: hex!("6d9e2a012d82b1b6cb0a2c1c1ed24cc16dbb56e6e39ae545371e0666ab057862").into(), - block_number: 215, - gas_limit: 64842908, - gas_used: 119301, - timestamp: 1705859527, - extra_data: hex!("d983010d0a846765746888676f312e32312e358664617277696e").into(), + state_root: hex!("96a83e9ddf745346fafcb0b03d57314623df669ed543c110662b21302a0fae8b").into(), + receipts_root: hex!("dccdfceea05036f7b61dcdabadc937945d31e68a8d3dfd4dc85684457988c284").into(), + logs_bloom: hex!("00000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000400000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000080000000000000000000000000000040004000000000000002002002000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000200000200000010").into(), + prev_randao: hex!("62e309d4f5119d1f5c783abc20fc1a549efbab546d8d0b25ff1cfd58be524e67").into(), + block_number: 393, + gas_limit: 54492273, + gas_used: 199644, + timestamp: 1710552813, + extra_data: hex!("d983010d0b846765746888676f312e32312e368664617277696e").into(), base_fee_per_gas: U256::from(7u64), - block_hash: hex!("48498dbfbcfae53a7f4c289ee00747aceea925f6260c50ead5a33e1c55c40f98").into(), - transactions_root: hex!("5ebc1347fe3df0611d4f66b19bd8e1c6f4eaed0371d850f14c83b1c77ea234e6").into(), + block_hash: hex!("6a9810efb9581d30c1a5c9074f27c68ea779a8c1ae31c213241df16225f4e131").into(), + transactions_root: hex!("2cfa6ed7327e8807c7973516c5c32a68ef2459e586e8067e113d081c3bd8c07d").into(), withdrawals_root: hex!("792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535").into(), blob_gas_used: 0, excess_blob_gas: 0, }), execution_branch: vec![ - hex!("f8c69d3830406d668619bcccc13c8dddde41e863326f7418b241d5924c4ad34a").into(), + hex!("a6833fa629f3286b6916c6e50b8bf089fc9126bee6f64d0413b4e59c1265834d").into(), hex!("b46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb").into(), hex!("db56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71").into(), - hex!("f4d6b5cf9c6e212615c3674fa625d04eb1114153fb221ef5ad02aa433fc67cfb").into(), + hex!("d3af7c05c516726be7505239e0b9c7cb53d24abce6b91cdb3b3995f0164a75da").into(), ], }) } + +pub fn make_inbound_fixture() -> InboundQueueFixture { + InboundQueueFixture { + message: Message { + event_log: Log { + address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(), + topics: vec![ + hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(), + hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into(), + hex!("5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0").into(), + ], + data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000").into(), + }, + proof: Proof { + receipt_proof: (vec![ + hex!("dccdfceea05036f7b61dcdabadc937945d31e68a8d3dfd4dc85684457988c284").to_vec(), + hex!("4a98e45a319168b0fc6005ce6b744ee9bf54338e2c0784b976a8578d241ced0f").to_vec(), + ], vec![ + hex!("f851a09c01dd6d2d8de951c45af23d3ad00829ce021c04d6c8acbe1612d456ee320d4980808080808080a04a98e45a319168b0fc6005ce6b744ee9bf54338e2c0784b976a8578d241ced0f8080808080808080").to_vec(), + hex!("f9028c30b9028802f90284018301d205b9010000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000000000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040004000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000200000000000010f90179f85894eda338e4dc46038493b885327842fd3e301cab39e1a0f78bb28d4b1d7da699e5c0bc2be29c2b04b5aab6aacf6298fe5304f9db9c6d7ea000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7df9011c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a05f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0b8a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000").to_vec(), + ]), + execution_proof: ExecutionProof { + header: BeaconHeader { + slot: 393, + proposer_index: 4, + parent_root: hex!("6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef").into(), + state_root: hex!("b62ac34a8cb82497be9542fe2114410c9f6021855b766015406101a1f3d86434").into(), + body_root: hex!("04005fe231e11a5b7b1580cb73b177ae8b338bedd745497e6bb7122126a806db").into(), + }, + ancestry_proof: Some(AncestryProof { + header_branch: vec![ + hex!("6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef").into(), + hex!("fa84cc88ca53a72181599ff4eb07d8b444bce023fe2347c3b4f51004c43439d3").into(), + hex!("cadc8ae211c6f2221c9138e829249adf902419c78eb4727a150baa4d9a02cc9d").into(), + hex!("33a89962df08a35c52bd7e1d887cd71fa7803e68787d05c714036f6edf75947c").into(), + hex!("2c9760fce5c2829ef3f25595a703c21eb22d0186ce223295556ed5da663a82cf").into(), + hex!("e1aa87654db79c8a0ecd6c89726bb662fcb1684badaef5cd5256f479e3c622e1").into(), + hex!("aa70d5f314e4a1fbb9c362f3db79b21bf68b328887248651fbd29fc501d0ca97").into(), + hex!("160b6c235b3a1ed4ef5f80b03ee1c76f7bf3f591c92fca9d8663e9221b9f9f0f").into(), + hex!("f68d7dcd6a07a18e9de7b5d2aa1980eb962e11d7dcb584c96e81a7635c8d2535").into(), + hex!("1d5f912dfd6697110dd1ecb5cb8e77952eef57d85deb373572572df62bb157fc").into(), + hex!("ffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b").into(), + hex!("6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220").into(), + hex!("b7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f").into(), + ], + finalized_block_root: hex!("751414cd97c0624f922b3e80285e9f776b08fa22fd5f87391f2ed7ef571a8d46").into(), + }), + execution_header: VersionedExecutionPayloadHeader::Deneb(deneb::ExecutionPayloadHeader { + parent_hash: hex!("8092290aa21b7751576440f77edd02a94058429ce50e63a92d620951fb25eda2").into(), + fee_recipient: hex!("0000000000000000000000000000000000000000").into(), + state_root: hex!("96a83e9ddf745346fafcb0b03d57314623df669ed543c110662b21302a0fae8b").into(), + receipts_root: hex!("dccdfceea05036f7b61dcdabadc937945d31e68a8d3dfd4dc85684457988c284").into(), + logs_bloom: hex!("00000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000400000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000080000000000000000000000000000040004000000000000002002002000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000200000200000010").into(), + prev_randao: hex!("62e309d4f5119d1f5c783abc20fc1a549efbab546d8d0b25ff1cfd58be524e67").into(), + block_number: 393, + gas_limit: 54492273, + gas_used: 199644, + timestamp: 1710552813, + extra_data: hex!("d983010d0b846765746888676f312e32312e368664617277696e").into(), + base_fee_per_gas: U256::from(7u64), + block_hash: hex!("6a9810efb9581d30c1a5c9074f27c68ea779a8c1ae31c213241df16225f4e131").into(), + transactions_root: hex!("2cfa6ed7327e8807c7973516c5c32a68ef2459e586e8067e113d081c3bd8c07d").into(), + withdrawals_root: hex!("792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535").into(), + blob_gas_used: 0, + excess_blob_gas: 0, + }), + execution_branch: vec![ + hex!("a6833fa629f3286b6916c6e50b8bf089fc9126bee6f64d0413b4e59c1265834d").into(), + hex!("b46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb").into(), + hex!("db56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71").into(), + hex!("d3af7c05c516726be7505239e0b9c7cb53d24abce6b91cdb3b3995f0164a75da").into(), + ], + } + }, + }, + finalized_header: BeaconHeader { + slot: 864, + proposer_index: 4, + parent_root: hex!("614e7672f991ac268cd841055973f55e1e42228831a211adef207bb7329be614").into(), + state_root: hex!("5fa8dfca3d760e4242ab46d529144627aa85348a19173b6e081172c701197a4a").into(), + body_root: hex!("0f34c083b1803666bb1ac5e73fa71582731a2cf37d279ff0a3b0cad5a2ff371e").into(), + }, + block_roots_root: hex!("b9aab9c388c4e4fcd899b71f62c498fc73406e38e8eb14aa440e9affa06f2a10").into(), + } +} diff --git a/bridges/snowbridge/pallets/ethereum-client/src/benchmarking/mod.rs b/bridges/snowbridge/pallets/ethereum-client/src/benchmarking/mod.rs index e1520cd7153..4b8796b628d 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/benchmarking/mod.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/benchmarking/mod.rs @@ -65,24 +65,6 @@ mod benchmarks { Ok(()) } - #[benchmark] - fn submit_execution_header() -> Result<(), BenchmarkError> { - let caller: T::AccountId = whitelisted_caller(); - let checkpoint_update = make_checkpoint(); - let finalized_header_update = make_finalized_header_update(); - let execution_header_update = make_execution_header_update(); - let execution_header_hash = execution_header_update.execution_header.block_hash(); - EthereumBeaconClient::::process_checkpoint_update(&checkpoint_update)?; - EthereumBeaconClient::::process_update(&finalized_header_update)?; - - #[extrinsic_call] - _(RawOrigin::Signed(caller.clone()), Box::new(*execution_header_update)); - - assert!(>::contains_key(execution_header_hash)); - - Ok(()) - } - #[benchmark(extra)] fn bls_fast_aggregate_verify_pre_aggregated() -> Result<(), BenchmarkError> { EthereumBeaconClient::::process_checkpoint_update(&make_checkpoint())?; diff --git a/bridges/snowbridge/pallets/ethereum-client/src/impls.rs b/bridges/snowbridge/pallets/ethereum-client/src/impls.rs index 300431d8770..f600b1f67e2 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/impls.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/impls.rs @@ -1,6 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023 Snowfork use super::*; +use frame_support::ensure; +use primitives::ExecutionProof; use snowbridge_core::inbound::{ VerificationError::{self, *}, @@ -14,32 +16,13 @@ impl Verifier for Pallet { /// the log should be in the beacon client storage, meaning it has been verified and is an /// ancestor of a finalized beacon block. fn verify(event_log: &Log, proof: &Proof) -> Result<(), VerificationError> { - log::info!( - target: "ethereum-client", - "💫 Verifying message with block hash {}", - proof.block_hash, - ); + Self::verify_execution_proof(&proof.execution_proof) + .map_err(|e| InvalidExecutionProof(e.into()))?; - let header = >::get(proof.block_hash).ok_or(HeaderNotFound)?; - - let receipt = match Self::verify_receipt_inclusion(header.receipts_root, proof) { - Ok(receipt) => receipt, - Err(err) => { - log::error!( - target: "ethereum-client", - "💫 Verification of receipt inclusion failed for block {}: {:?}", - proof.block_hash, - err - ); - return Err(err) - }, - }; - - log::trace!( - target: "ethereum-client", - "💫 Verified receipt inclusion for transaction at index {} in block {}", - proof.tx_index, proof.block_hash, - ); + let receipt = Self::verify_receipt_inclusion( + proof.execution_proof.execution_header.receipts_root(), + &proof.receipt_proof.1, + )?; event_log.validate().map_err(|_| InvalidLog)?; @@ -53,18 +36,11 @@ impl Verifier for Pallet { if !receipt.contains_log(&event_log) { log::error!( target: "ethereum-client", - "💫 Event log not found in receipt for transaction at index {} in block {}", - proof.tx_index, proof.block_hash, + "💫 Event log not found in receipt for transaction", ); return Err(LogNotFound) } - log::info!( - target: "ethereum-client", - "💫 Receipt verification successful for {}", - proof.block_hash, - ); - Ok(()) } } @@ -74,9 +50,9 @@ impl Pallet { /// `proof.block_hash`. pub fn verify_receipt_inclusion( receipts_root: H256, - proof: &Proof, + receipt_proof: &[Vec], ) -> Result { - let result = verify_receipt_proof(receipts_root, &proof.data.1).ok_or(InvalidProof)?; + let result = verify_receipt_proof(receipts_root, receipt_proof).ok_or(InvalidProof)?; match result { Ok(receipt) => Ok(receipt), @@ -90,4 +66,96 @@ impl Pallet { }, } } + + /// Validates an execution header with ancestry_proof against a finalized checkpoint on + /// chain.The beacon header containing the execution header is sent, plus the execution header, + /// along with a proof that the execution header is rooted in the beacon header body. + pub(crate) fn verify_execution_proof(execution_proof: &ExecutionProof) -> DispatchResult { + let latest_finalized_state = + FinalizedBeaconState::::get(LatestFinalizedBlockRoot::::get()) + .ok_or(Error::::NotBootstrapped)?; + // Checks that the header is an ancestor of a finalized header, using slot number. + ensure!( + execution_proof.header.slot <= latest_finalized_state.slot, + Error::::HeaderNotFinalized + ); + + // Gets the hash tree root of the execution header, in preparation for the execution + // header proof (used to check that the execution header is rooted in the beacon + // header body. + let execution_header_root: H256 = execution_proof + .execution_header + .hash_tree_root() + .map_err(|_| Error::::BlockBodyHashTreeRootFailed)?; + + ensure!( + verify_merkle_branch( + execution_header_root, + &execution_proof.execution_branch, + config::EXECUTION_HEADER_SUBTREE_INDEX, + config::EXECUTION_HEADER_DEPTH, + execution_proof.header.body_root + ), + Error::::InvalidExecutionHeaderProof + ); + + let beacon_block_root: H256 = execution_proof + .header + .hash_tree_root() + .map_err(|_| Error::::HeaderHashTreeRootFailed)?; + + match &execution_proof.ancestry_proof { + Some(proof) => { + Self::verify_ancestry_proof( + beacon_block_root, + execution_proof.header.slot, + &proof.header_branch, + proof.finalized_block_root, + )?; + }, + None => { + // If the ancestry proof is not provided, we expect this beacon header to be a + // finalized beacon header. We need to check that the header hash matches the + // finalized header root at the expected slot. + let state = >::get(beacon_block_root) + .ok_or(Error::::ExpectedFinalizedHeaderNotStored)?; + if execution_proof.header.slot != state.slot { + return Err(Error::::ExpectedFinalizedHeaderNotStored.into()) + } + }, + } + + Ok(()) + } + + /// Verify that `block_root` is an ancestor of `finalized_block_root` Used to prove that + /// an execution header is an ancestor of a finalized header (i.e. the blocks are + /// on the same chain). + fn verify_ancestry_proof( + block_root: H256, + block_slot: u64, + block_root_proof: &[H256], + finalized_block_root: H256, + ) -> DispatchResult { + let state = >::get(finalized_block_root) + .ok_or(Error::::ExpectedFinalizedHeaderNotStored)?; + + ensure!(block_slot < state.slot, Error::::HeaderNotFinalized); + + let index_in_array = block_slot % (SLOTS_PER_HISTORICAL_ROOT as u64); + let leaf_index = (SLOTS_PER_HISTORICAL_ROOT as u64) + index_in_array; + + ensure!( + verify_merkle_branch( + block_root, + block_root_proof, + leaf_index as usize, + config::BLOCK_ROOT_AT_INDEX_DEPTH, + state.block_roots_root + ), + Error::::InvalidAncestryMerkleProof + ); + + Ok(()) + } } diff --git a/bridges/snowbridge/pallets/ethereum-client/src/lib.rs b/bridges/snowbridge/pallets/ethereum-client/src/lib.rs index f57f5199020..c1b9e19729b 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/lib.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/lib.rs @@ -15,8 +15,6 @@ //! ## Consensus Updates //! //! * [`Call::submit`]: Submit a finalized beacon header with an optional sync committee update -//! * [`Call::submit_execution_header`]: Submit an execution header together with an ancestry proof -//! that can be verified against an already imported finalized beacon header. #![cfg_attr(not(feature = "std"), no_std)] pub mod config; @@ -40,8 +38,7 @@ use frame_support::{ use frame_system::ensure_signed; use primitives::{ fast_aggregate_verify, verify_merkle_branch, verify_receipt_proof, BeaconHeader, BlsError, - CompactBeaconState, CompactExecutionHeader, ExecutionHeaderState, ForkData, ForkVersion, - ForkVersions, PublicKeyPrepared, SigningData, + CompactBeaconState, ForkData, ForkVersion, ForkVersions, PublicKeyPrepared, SigningData, }; use snowbridge_core::{BasicOperatingMode, RingBufferMap}; use sp_core::H256; @@ -51,11 +48,7 @@ pub use weights::WeightInfo; use functions::{ compute_epoch, compute_period, decompress_sync_committee_bits, sync_committee_sum, }; -pub use types::ExecutionHeaderBuffer; -use types::{ - CheckpointUpdate, ExecutionHeaderUpdate, FinalizedBeaconStateBuffer, SyncCommitteePrepared, - Update, -}; +use types::{CheckpointUpdate, FinalizedBeaconStateBuffer, SyncCommitteePrepared, Update}; pub use pallet::*; @@ -76,10 +69,7 @@ pub mod pallet { pub struct MaxFinalizedHeadersToKeep(PhantomData); impl Get for MaxFinalizedHeadersToKeep { fn get() -> u32 { - // Consider max latency allowed between LatestFinalizedState and LatestExecutionState is - // the total slots in one sync_committee_period so 1 should be fine we keep 2 periods - // here for redundancy. - const MAX_REDUNDANCY: u32 = 2; + const MAX_REDUNDANCY: u32 = 20; config::EPOCHS_PER_SYNC_COMMITTEE_PERIOD as u32 * MAX_REDUNDANCY } } @@ -92,9 +82,6 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; #[pallet::constant] type ForkVersions: Get; - /// Maximum number of execution headers to keep - #[pallet::constant] - type MaxExecutionHeadersToKeep: Get; type WeightInfo: WeightInfo; } @@ -105,10 +92,6 @@ pub mod pallet { block_hash: H256, slot: u64, }, - ExecutionHeaderImported { - block_hash: H256, - block_number: u64, - }, SyncCommitteeUpdated { period: u64, }, @@ -191,25 +174,6 @@ pub mod pallet { pub(super) type NextSyncCommittee = StorageValue<_, SyncCommitteePrepared, ValueQuery>; - /// Latest imported execution header - #[pallet::storage] - #[pallet::getter(fn latest_execution_state)] - pub(super) type LatestExecutionState = - StorageValue<_, ExecutionHeaderState, ValueQuery>; - - /// Execution Headers - #[pallet::storage] - pub type ExecutionHeaders = - StorageMap<_, Identity, H256, CompactExecutionHeader, OptionQuery>; - - /// Execution Headers: Current position in ring buffer - #[pallet::storage] - pub type ExecutionHeaderIndex = StorageValue<_, u32, ValueQuery>; - - /// Execution Headers: Mapping of ring buffer index to a pruning candidate - #[pallet::storage] - pub type ExecutionHeaderMapping = StorageMap<_, Identity, u32, H256, ValueQuery>; - /// The current operating mode of the pallet. #[pallet::storage] #[pallet::getter(fn operating_mode)] @@ -248,21 +212,6 @@ pub mod pallet { Ok(()) } - #[pallet::call_index(2)] - #[pallet::weight(T::WeightInfo::submit_execution_header())] - #[transactional] - /// Submits a new execution header update. The relevant related beacon header - /// is also included to prove the execution header, as well as ancestry proof data. - pub fn submit_execution_header( - origin: OriginFor, - update: Box, - ) -> DispatchResult { - ensure_signed(origin)?; - ensure!(!Self::operating_mode().is_halted(), Error::::Halted); - Self::process_execution_header_update(&update)?; - Ok(()) - } - /// Halt or resume all pallet operations. May only be called by root. #[pallet::call_index(3)] #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] @@ -325,41 +274,19 @@ pub mod pallet { >::set(sync_committee_prepared); >::kill(); InitialCheckpointRoot::::set(header_root); - >::kill(); Self::store_validators_root(update.validators_root); - Self::store_finalized_header(header_root, update.header, update.block_roots_root)?; + Self::store_finalized_header(update.header, update.block_roots_root)?; Ok(()) } pub(crate) fn process_update(update: &Update) -> DispatchResult { - Self::cross_check_execution_state()?; Self::verify_update(update)?; Self::apply_update(update)?; Ok(()) } - /// Cross check to make sure that execution header import does not fall too far behind - /// finalised beacon header import. If that happens just return an error and pause - /// processing until execution header processing has caught up. - pub(crate) fn cross_check_execution_state() -> DispatchResult { - let latest_finalized_state = - FinalizedBeaconState::::get(LatestFinalizedBlockRoot::::get()) - .ok_or(Error::::NotBootstrapped)?; - let latest_execution_state = Self::latest_execution_state(); - // The execution header import should be at least within the slot range of a sync - // committee period. - let max_latency = config::EPOCHS_PER_SYNC_COMMITTEE_PERIOD * config::SLOTS_PER_EPOCH; - ensure!( - latest_execution_state.beacon_slot == 0 || - latest_finalized_state.slot < - latest_execution_state.beacon_slot + max_latency as u64, - Error::::ExecutionHeaderTooFarBehind - ); - Ok(()) - } - /// References and strictly follows /// Verifies that provided next sync committee is valid through a series of checks /// (including checking that a sync committee period isn't skipped and that the header is @@ -534,130 +461,12 @@ pub mod pallet { }; if update.finalized_header.slot > latest_finalized_state.slot { - let finalized_block_root: H256 = update - .finalized_header - .hash_tree_root() - .map_err(|_| Error::::HeaderHashTreeRootFailed)?; - Self::store_finalized_header( - finalized_block_root, - update.finalized_header, - update.block_roots_root, - )?; + Self::store_finalized_header(update.finalized_header, update.block_roots_root)?; } Ok(()) } - /// Validates an execution header for import. The beacon header containing the execution - /// header is sent, plus the execution header, along with a proof that the execution header - /// is rooted in the beacon header body. - pub(crate) fn process_execution_header_update( - update: &ExecutionHeaderUpdate, - ) -> DispatchResult { - let latest_finalized_state = - FinalizedBeaconState::::get(LatestFinalizedBlockRoot::::get()) - .ok_or(Error::::NotBootstrapped)?; - // Checks that the header is an ancestor of a finalized header, using slot number. - ensure!( - update.header.slot <= latest_finalized_state.slot, - Error::::HeaderNotFinalized - ); - - // Checks that we don't skip execution headers, they need to be imported sequentially. - let latest_execution_state: ExecutionHeaderState = Self::latest_execution_state(); - ensure!( - latest_execution_state.block_number == 0 || - update.execution_header.block_number() == - latest_execution_state.block_number + 1, - Error::::ExecutionHeaderSkippedBlock - ); - - // Gets the hash tree root of the execution header, in preparation for the execution - // header proof (used to check that the execution header is rooted in the beacon - // header body. - let execution_header_root: H256 = update - .execution_header - .hash_tree_root() - .map_err(|_| Error::::BlockBodyHashTreeRootFailed)?; - - ensure!( - verify_merkle_branch( - execution_header_root, - &update.execution_branch, - config::EXECUTION_HEADER_SUBTREE_INDEX, - config::EXECUTION_HEADER_DEPTH, - update.header.body_root - ), - Error::::InvalidExecutionHeaderProof - ); - - let block_root: H256 = update - .header - .hash_tree_root() - .map_err(|_| Error::::HeaderHashTreeRootFailed)?; - - match &update.ancestry_proof { - Some(proof) => { - Self::verify_ancestry_proof( - block_root, - update.header.slot, - &proof.header_branch, - proof.finalized_block_root, - )?; - }, - None => { - // If the ancestry proof is not provided, we expect this header to be a - // finalized header. We need to check that the header hash matches the finalized - // header root at the expected slot. - let state = >::get(block_root) - .ok_or(Error::::ExpectedFinalizedHeaderNotStored)?; - if update.header.slot != state.slot { - return Err(Error::::ExpectedFinalizedHeaderNotStored.into()) - } - }, - } - - Self::store_execution_header( - update.execution_header.block_hash(), - update.execution_header.clone().into(), - update.header.slot, - block_root, - ); - - Ok(()) - } - - /// Verify that `block_root` is an ancestor of `finalized_block_root` Used to prove that - /// an execution header is an ancestor of a finalized header (i.e. the blocks are - /// on the same chain). - fn verify_ancestry_proof( - block_root: H256, - block_slot: u64, - block_root_proof: &[H256], - finalized_block_root: H256, - ) -> DispatchResult { - let state = >::get(finalized_block_root) - .ok_or(Error::::ExpectedFinalizedHeaderNotStored)?; - - ensure!(block_slot < state.slot, Error::::HeaderNotFinalized); - - let index_in_array = block_slot % (SLOTS_PER_HISTORICAL_ROOT as u64); - let leaf_index = (SLOTS_PER_HISTORICAL_ROOT as u64) + index_in_array; - - ensure!( - verify_merkle_branch( - block_root, - block_root_proof, - leaf_index as usize, - config::BLOCK_ROOT_AT_INDEX_DEPTH, - state.block_roots_root - ), - Error::::InvalidAncestryMerkleProof - ); - - Ok(()) - } - /// Computes the signing root for a given beacon header and domain. The hash tree root /// of the beacon header is computed, and then the combination of the beacon header hash /// and the domain makes up the signing root. @@ -679,13 +488,15 @@ pub mod pallet { /// Stores a compacted (slot and block roots root (hash of the `block_roots` beacon state /// field, used for ancestry proof)) beacon state in a ring buffer map, with the header root /// as map key. - fn store_finalized_header( - header_root: H256, + pub fn store_finalized_header( header: BeaconHeader, block_roots_root: H256, ) -> DispatchResult { let slot = header.slot; + let header_root: H256 = + header.hash_tree_root().map_err(|_| Error::::HeaderHashTreeRootFailed)?; + >::insert( header_root, CompactBeaconState { slot: header.slot, block_roots_root }, @@ -704,36 +515,6 @@ pub mod pallet { Ok(()) } - /// Stores the provided execution header in pallet storage. The header is stored - /// in a ring buffer map, with the block hash as map key. The last imported execution - /// header is also kept in storage, for the relayer to check import progress. - pub fn store_execution_header( - block_hash: H256, - header: CompactExecutionHeader, - beacon_slot: u64, - beacon_block_root: H256, - ) { - let block_number = header.block_number; - - >::insert(block_hash, header); - - log::trace!( - target: LOG_TARGET, - "💫 Updated latest execution block at {} to number {}.", - block_hash, - block_number - ); - - LatestExecutionState::::mutate(|s| { - s.beacon_block_root = beacon_block_root; - s.beacon_slot = beacon_slot; - s.block_hash = block_hash; - s.block_number = block_number; - }); - - Self::deposit_event(Event::ExecutionHeaderImported { block_hash, block_number }); - } - /// Stores the validators root in storage. Validators root is the hash tree root of all the /// validators at genesis and is used to used to identify the chain that we are on /// (used in conjunction with the fork version). diff --git a/bridges/snowbridge/pallets/ethereum-client/src/mock.rs b/bridges/snowbridge/pallets/ethereum-client/src/mock.rs index 799b14f4773..bd6144ebd8f 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/mock.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/mock.rs @@ -2,12 +2,13 @@ // SPDX-FileCopyrightText: 2023 Snowfork use crate as ethereum_beacon_client; use crate::config; -use frame_support::{derive_impl, parameter_types}; -use hex_literal::hex; +use frame_support::{derive_impl, dispatch::DispatchResult, parameter_types}; use pallet_timestamp; -use primitives::{CompactExecutionHeader, Fork, ForkVersions}; +use primitives::{Fork, ForkVersions}; use snowbridge_core::inbound::{Log, Proof}; +use sp_std::default::Default; use std::{fs::File, path::PathBuf}; + type Block = frame_system::mocking::MockBlock; use sp_runtime::BuildStorage; @@ -20,8 +21,8 @@ where serde_json::from_reader(File::open(filepath).unwrap()) } -pub fn load_execution_header_update_fixture() -> primitives::ExecutionHeaderUpdate { - load_fixture("execution-header-update.json".to_string()).unwrap() +pub fn load_execution_proof_fixture() -> primitives::ExecutionProof { + load_fixture("execution-proof.json".to_string()).unwrap() } pub fn load_checkpoint_update_fixture( @@ -50,41 +51,8 @@ pub fn load_next_finalized_header_update_fixture( } pub fn get_message_verification_payload() -> (Log, Proof) { - ( - Log { - address: hex!("ee9170abfbf9421ad6dd07f6bdec9d89f2b581e0").into(), - topics: vec![ - hex!("1b11dcf133cc240f682dab2d3a8e4cd35c5da8c9cf99adac4336f8512584c5ad").into(), - hex!("00000000000000000000000000000000000000000000000000000000000003e8").into(), - hex!("0000000000000000000000000000000000000000000000000000000000000001").into(), - ], - data: hex!("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004b000f000000000000000100d184c103f7acc340847eee82a0b909e3358bc28d440edffa1352b13227e8ee646f3ea37456dec701345772617070656420457468657210574554481235003511000000000000000000000000000000000000000000").into(), - }, - Proof { - block_hash: hex!("05aaa60b0f27cce9e71909508527264b77ee14da7b5bf915fcc4e32715333213").into(), - tx_index: 0, - data: (vec![ - hex!("cf0d1c1ba57d1e0edfb59786c7e30c2b7e12bd54612b00cd21c4eaeecedf44fb").to_vec(), - hex!("d21fc4f68ab05bc4dcb23c67008e92c4d466437cdd6ed7aad0c008944c185510").to_vec(), - hex!("b9890f91ca0d77aa2a4adfaf9b9e40c94cac9e638b6d9797923865872944b646").to_vec(), - ], vec![ - hex!("f90131a0b601337b3aa10a671caa724eba641e759399979856141d3aea6b6b4ac59b889ba00c7d5dd48be9060221a02fb8fa213860b4c50d47046c8fa65ffaba5737d569e0a094601b62a1086cd9c9cb71a7ebff9e718f3217fd6e837efe4246733c0a196f63a06a4b0dd0aefc37b3c77828c8f07d1b7a2455ceb5dbfd3c77d7d6aeeddc2f7e8ca0d6e8e23142cdd8ec219e1f5d8b56aa18e456702b195deeaa210327284d42ade4a08a313d4c87023005d1ab631bbfe3f5de1e405d0e66d0bef3e033f1e5711b5521a0bf09a5d9a48b10ade82b8d6a5362a15921c8b5228a3487479b467db97411d82fa0f95cccae2a7c572ef3c566503e30bac2b2feb2d2f26eebf6d870dcf7f8cf59cea0d21fc4f68ab05bc4dcb23c67008e92c4d466437cdd6ed7aad0c008944c1855108080808080808080").to_vec(), - hex!("f851a0b9890f91ca0d77aa2a4adfaf9b9e40c94cac9e638b6d9797923865872944b646a060a634b9280e3a23fb63375e7bbdd9ab07fd379ab6a67e2312bbc112195fa358808080808080808080808080808080").to_vec(), - hex!("f9030820b9030402f90300018301d6e2b9010000000000000800000000000020040008000000000000000000000000400000008000000000000000000000000000000000000000000000000000000000042010000000001000000000000000000000000000000000040000000000000000000000000000000000000000000000008000000000000000002000000000000000000000000200000000000000200000000000100000000040000001000200008000000000000200000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000f901f5f87a942ffa5ecdbe006d30397c7636d3e015eee251369ff842a0c965575a00553e094ca7c5d14f02e107c258dda06867cbf9e0e69f80e71bbcc1a000000000000000000000000000000000000000000000000000000000000003e8a000000000000000000000000000000000000000000000000000000000000003e8f9011c94ee9170abfbf9421ad6dd07f6bdec9d89f2b581e0f863a01b11dcf133cc240f682dab2d3a8e4cd35c5da8c9cf99adac4336f8512584c5ada000000000000000000000000000000000000000000000000000000000000003e8a00000000000000000000000000000000000000000000000000000000000000001b8a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004b000f000000000000000100d184c103f7acc340847eee82a0b909e3358bc28d440edffa1352b13227e8ee646f3ea37456dec701345772617070656420457468657210574554481235003511000000000000000000000000000000000000000000f858948cf6147918a5cbb672703f879f385036f8793a24e1a01449abf21e49fd025f33495e77f7b1461caefdd3d4bb646424a3f445c4576a5ba0000000000000000000000000440edffa1352b13227e8ee646f3ea37456dec701").to_vec(), - ]), - } - ) -} - -pub fn get_message_verification_header() -> CompactExecutionHeader { - CompactExecutionHeader { - parent_hash: hex!("04a7f6ab8282203562c62f38b0ab41d32aaebe2c7ea687702b463148a6429e04") - .into(), - block_number: 55, - state_root: hex!("894d968712976d613519f973a317cb0781c7b039c89f27ea2b7ca193f7befdb3").into(), - receipts_root: hex!("cf0d1c1ba57d1e0edfb59786c7e30c2b7e12bd54612b00cd21c4eaeecedf44fb") - .into(), - } + let inbound_fixture = snowbridge_pallet_ethereum_client_fixtures::make_inbound_fixture(); + (inbound_fixture.message.event_log, inbound_fixture.message.proof) } frame_support::construct_runtime!( @@ -130,20 +98,25 @@ parameter_types! { epoch: 0, } }; - pub const ExecutionHeadersPruneThreshold: u32 = 8192; } impl ethereum_beacon_client::Config for Test { type RuntimeEvent = RuntimeEvent; type ForkVersions = ChainForkVersions; - type MaxExecutionHeadersToKeep = ExecutionHeadersPruneThreshold; type WeightInfo = (); } // Build genesis storage according to the mock runtime. pub fn new_tester() -> sp_io::TestExternalities { let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - let mut ext = sp_io::TestExternalities::new(t); - let _ = ext.execute_with(|| Timestamp::set(RuntimeOrigin::signed(1), 30_000)); + let ext = sp_io::TestExternalities::new(t); ext } + +pub fn initialize_storage() -> DispatchResult { + let inbound_fixture = snowbridge_pallet_ethereum_client_fixtures::make_inbound_fixture(); + EthereumBeaconClient::store_finalized_header( + inbound_fixture.finalized_header, + inbound_fixture.block_roots_root, + ) +} diff --git a/bridges/snowbridge/pallets/ethereum-client/src/tests.rs b/bridges/snowbridge/pallets/ethereum-client/src/tests.rs index 20a184490fd..765958c1282 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/tests.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/tests.rs @@ -1,14 +1,13 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023 Snowfork use crate::{ - functions::compute_period, pallet::ExecutionHeaders, sync_committee_sum, verify_merkle_branch, - BeaconHeader, CompactBeaconState, Error, ExecutionHeaderBuffer, FinalizedBeaconState, - LatestExecutionState, LatestFinalizedBlockRoot, NextSyncCommittee, SyncCommitteePrepared, + functions::compute_period, sync_committee_sum, verify_merkle_branch, BeaconHeader, + CompactBeaconState, Error, FinalizedBeaconState, LatestFinalizedBlockRoot, NextSyncCommittee, + SyncCommitteePrepared, }; use crate::mock::{ - get_message_verification_header, get_message_verification_payload, - load_checkpoint_update_fixture, load_execution_header_update_fixture, + get_message_verification_payload, load_checkpoint_update_fixture, load_finalized_header_update_fixture, load_next_finalized_header_update_fixture, load_next_sync_committee_update_fixture, load_sync_committee_update_fixture, }; @@ -19,14 +18,9 @@ use crate::config::{EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH, SLOTS_PER use frame_support::{assert_err, assert_noop, assert_ok}; use hex_literal::hex; use primitives::{ - CompactExecutionHeader, ExecutionHeaderState, Fork, ForkVersions, NextSyncCommitteeUpdate, - VersionedExecutionPayloadHeader, -}; -use rand::{thread_rng, Rng}; -use snowbridge_core::{ - inbound::{VerificationError, Verifier}, - RingBufferMap, + types::deneb, Fork, ForkVersions, NextSyncCommitteeUpdate, VersionedExecutionPayloadHeader, }; +use snowbridge_core::inbound::{VerificationError, Verifier}; use sp_core::H256; use sp_runtime::DispatchError; @@ -212,61 +206,6 @@ pub fn sync_committee_participation_is_supermajority_errors_when_not_supermajori }); } -#[test] -pub fn execution_header_pruning() { - new_tester().execute_with(|| { - let execution_header_prune_threshold = ExecutionHeadersPruneThreshold::get(); - let to_be_deleted = execution_header_prune_threshold / 2; - - let mut stored_hashes = vec![]; - - for i in 0..execution_header_prune_threshold { - let mut hash = H256::default(); - thread_rng().try_fill(&mut hash.0[..]).unwrap(); - EthereumBeaconClient::store_execution_header( - hash, - CompactExecutionHeader::default(), - i as u64, - hash, - ); - stored_hashes.push(hash); - } - - // We should have stored everything until now - assert_eq!({ ExecutionHeaders::::iter().count() }, stored_hashes.len()); - - // Let's push extra entries so that some of the previous entries are deleted. - for i in 0..to_be_deleted { - let mut hash = H256::default(); - thread_rng().try_fill(&mut hash.0[..]).unwrap(); - EthereumBeaconClient::store_execution_header( - hash, - CompactExecutionHeader::default(), - (i + execution_header_prune_threshold) as u64, - hash, - ); - - stored_hashes.push(hash); - } - - // We should have only stored up to `execution_header_prune_threshold` - assert_eq!( - ExecutionHeaders::::iter().count() as u32, - execution_header_prune_threshold - ); - - // First `to_be_deleted` items must be deleted - for i in 0..to_be_deleted { - assert!(!ExecutionHeaders::::contains_key(stored_hashes[i as usize])); - } - - // Other entries should be part of data - for i in to_be_deleted..(to_be_deleted + execution_header_prune_threshold) { - assert!(ExecutionHeaders::::contains_key(stored_hashes[i as usize])); - } - }); -} - #[test] fn compute_fork_version() { let mock_fork_versions = ForkVersions { @@ -348,34 +287,6 @@ fn find_present_keys() { }); } -#[test] -fn cross_check_execution_state() { - new_tester().execute_with(|| { - let header_root: H256 = TEST_HASH.into(); - >::insert( - header_root, - CompactBeaconState { - // set slot to period 5 - slot: ((EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH) * 5) as u64, - block_roots_root: Default::default(), - }, - ); - LatestFinalizedBlockRoot::::set(header_root); - >::set(ExecutionHeaderState { - beacon_block_root: Default::default(), - // set slot to period 2 - beacon_slot: ((EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH) * 2) as u64, - block_hash: Default::default(), - block_number: 0, - }); - - assert_err!( - EthereumBeaconClient::cross_check_execution_state(), - Error::::ExecutionHeaderTooFarBehind - ); - }); -} - /* SYNC PROCESS TESTS */ #[test] @@ -608,40 +519,6 @@ fn submit_update_with_skipped_sync_committee_period() { }); } -#[test] -fn submit_update_execution_headers_too_far_behind() { - let checkpoint = Box::new(load_checkpoint_update_fixture()); - let finalized_header_update = Box::new(load_finalized_header_update_fixture()); - let execution_header_update = Box::new(load_execution_header_update_fixture()); - let next_update = Box::new(load_next_sync_committee_update_fixture()); - - new_tester().execute_with(|| { - let far_ahead_finalized_header_slot = finalized_header_update.finalized_header.slot + - (EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH * 2) as u64; - assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); - assert_ok!(EthereumBeaconClient::submit_execution_header( - RuntimeOrigin::signed(1), - execution_header_update - )); - - let header_root: H256 = TEST_HASH.into(); - >::insert( - header_root, - CompactBeaconState { - slot: far_ahead_finalized_header_slot, - block_roots_root: Default::default(), - }, - ); - LatestFinalizedBlockRoot::::set(header_root); - - assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_update), - Error::::ExecutionHeaderTooFarBehind - ); - }); -} - #[test] fn submit_irrelevant_update() { let checkpoint = Box::new(load_checkpoint_update_fixture()); @@ -703,187 +580,6 @@ fn submit_update_with_invalid_sync_committee_update() { }); } -#[test] -fn submit_execution_header_update() { - let checkpoint = Box::new(load_checkpoint_update_fixture()); - let finalized_header_update = Box::new(load_finalized_header_update_fixture()); - let execution_header_update = Box::new(load_execution_header_update_fixture()); - - new_tester().execute_with(|| { - assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); - assert_ok!(EthereumBeaconClient::submit_execution_header( - RuntimeOrigin::signed(1), - execution_header_update.clone() - )); - assert!(>::contains_key( - execution_header_update.execution_header.block_hash() - )); - }); -} - -#[test] -fn submit_execution_header_update_invalid_ancestry_proof() { - let checkpoint = Box::new(load_checkpoint_update_fixture()); - let finalized_header_update = Box::new(load_finalized_header_update_fixture()); - let mut execution_header_update = Box::new(load_execution_header_update_fixture()); - if let Some(ref mut ancestry_proof) = execution_header_update.ancestry_proof { - ancestry_proof.header_branch[0] = TEST_HASH.into() - } - - new_tester().execute_with(|| { - assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); - assert_err!( - EthereumBeaconClient::submit_execution_header( - RuntimeOrigin::signed(1), - execution_header_update - ), - Error::::InvalidAncestryMerkleProof - ); - }); -} - -#[test] -fn submit_execution_header_update_invalid_execution_header_proof() { - let checkpoint = Box::new(load_checkpoint_update_fixture()); - let finalized_header_update = Box::new(load_finalized_header_update_fixture()); - let mut execution_header_update = Box::new(load_execution_header_update_fixture()); - execution_header_update.execution_branch[0] = TEST_HASH.into(); - - new_tester().execute_with(|| { - assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); - assert_err!( - EthereumBeaconClient::submit_execution_header( - RuntimeOrigin::signed(1), - execution_header_update - ), - Error::::InvalidExecutionHeaderProof - ); - }); -} - -#[test] -fn submit_execution_header_update_that_skips_block() { - let checkpoint = Box::new(load_checkpoint_update_fixture()); - let finalized_header_update = Box::new(load_finalized_header_update_fixture()); - let execution_header_update = Box::new(load_execution_header_update_fixture()); - let mut skipped_block_execution_header_update = - Box::new(load_execution_header_update_fixture()); - let mut skipped_execution_header = - skipped_block_execution_header_update.execution_header.clone(); - - skipped_execution_header = match skipped_execution_header { - VersionedExecutionPayloadHeader::Capella(execution_payload_header) => { - let mut mut_execution_payload_header = execution_payload_header.clone(); - mut_execution_payload_header.block_number = execution_payload_header.block_number + 2; - VersionedExecutionPayloadHeader::Capella(mut_execution_payload_header) - }, - VersionedExecutionPayloadHeader::Deneb(execution_payload_header) => { - let mut mut_execution_payload_header = execution_payload_header.clone(); - mut_execution_payload_header.block_number = execution_payload_header.block_number + 2; - VersionedExecutionPayloadHeader::Deneb(mut_execution_payload_header) - }, - }; - - skipped_block_execution_header_update.execution_header = skipped_execution_header; - - new_tester().execute_with(|| { - assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); - assert_ok!(EthereumBeaconClient::submit_execution_header( - RuntimeOrigin::signed(1), - execution_header_update.clone() - )); - assert!(>::contains_key( - execution_header_update.execution_header.block_hash() - )); - assert_err!( - EthereumBeaconClient::submit_execution_header( - RuntimeOrigin::signed(1), - skipped_block_execution_header_update - ), - Error::::ExecutionHeaderSkippedBlock - ); - }); -} - -#[test] -fn submit_execution_header_update_that_is_also_finalized_header_which_is_not_stored() { - let checkpoint = Box::new(load_checkpoint_update_fixture()); - let finalized_header_update = Box::new(load_finalized_header_update_fixture()); - let mut execution_header_update = Box::new(load_execution_header_update_fixture()); - execution_header_update.ancestry_proof = None; - - new_tester().execute_with(|| { - assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); - assert_err!( - EthereumBeaconClient::submit_execution_header( - RuntimeOrigin::signed(1), - execution_header_update - ), - Error::::ExpectedFinalizedHeaderNotStored - ); - }); -} - -#[test] -fn submit_execution_header_update_that_is_also_finalized_header_which_is_stored_but_slots_dont_match( -) { - let checkpoint = Box::new(load_checkpoint_update_fixture()); - let finalized_header_update = Box::new(load_finalized_header_update_fixture()); - let mut execution_header_update = Box::new(load_execution_header_update_fixture()); - execution_header_update.ancestry_proof = None; - - new_tester().execute_with(|| { - assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); - - let block_root: H256 = execution_header_update.header.hash_tree_root().unwrap(); - - >::insert( - block_root, - CompactBeaconState { - slot: execution_header_update.header.slot + 1, - block_roots_root: Default::default(), - }, - ); - LatestFinalizedBlockRoot::::set(block_root); - - assert_err!( - EthereumBeaconClient::submit_execution_header( - RuntimeOrigin::signed(1), - execution_header_update - ), - Error::::ExpectedFinalizedHeaderNotStored - ); - }); -} - -#[test] -fn submit_execution_header_not_finalized() { - let checkpoint = Box::new(load_checkpoint_update_fixture()); - let finalized_header_update = Box::new(load_finalized_header_update_fixture()); - let update = Box::new(load_execution_header_update_fixture()); - - new_tester().execute_with(|| { - assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); - - >::mutate(>::get(), |x| { - let prev = x.unwrap(); - *x = Some(CompactBeaconState { slot: update.header.slot - 1, ..prev }); - }); - - assert_err!( - EthereumBeaconClient::submit_execution_header(RuntimeOrigin::signed(1), update), - Error::::HeaderNotFinalized - ); - }); -} - /// Check that a gap of more than 8192 slots between finalized headers is not allowed. #[test] fn submit_finalized_header_update_with_too_large_gap() { @@ -943,37 +639,21 @@ fn submit_finalized_header_update_with_gap_at_limit() { #[test] fn verify_message() { - let header = get_message_verification_header(); let (event_log, proof) = get_message_verification_payload(); - let block_hash = proof.block_hash; new_tester().execute_with(|| { - >::insert(block_hash, header); + assert_ok!(initialize_storage()); assert_ok!(EthereumBeaconClient::verify(&event_log, &proof)); }); } -#[test] -fn verify_message_missing_header() { - let (event_log, proof) = get_message_verification_payload(); - - new_tester().execute_with(|| { - assert_err!( - EthereumBeaconClient::verify(&event_log, &proof), - VerificationError::HeaderNotFound - ); - }); -} - #[test] fn verify_message_invalid_proof() { - let header = get_message_verification_header(); let (event_log, mut proof) = get_message_verification_payload(); - proof.data.1[0] = TEST_HASH.into(); - let block_hash = proof.block_hash; + proof.receipt_proof.1[0] = TEST_HASH.into(); new_tester().execute_with(|| { - >::insert(block_hash, header); + assert_ok!(initialize_storage()); assert_err!( EthereumBeaconClient::verify(&event_log, &proof), VerificationError::InvalidProof @@ -983,29 +663,28 @@ fn verify_message_invalid_proof() { #[test] fn verify_message_invalid_receipts_root() { - let mut header = get_message_verification_header(); - let (event_log, proof) = get_message_verification_payload(); - let block_hash = proof.block_hash; - header.receipts_root = TEST_HASH.into(); + let (event_log, mut proof) = get_message_verification_payload(); + let mut payload = deneb::ExecutionPayloadHeader::default(); + payload.receipts_root = TEST_HASH.into(); + proof.execution_proof.execution_header = VersionedExecutionPayloadHeader::Deneb(payload); new_tester().execute_with(|| { - >::insert(block_hash, header); + assert_ok!(initialize_storage()); assert_err!( EthereumBeaconClient::verify(&event_log, &proof), - VerificationError::InvalidProof + VerificationError::InvalidExecutionProof( + Error::::BlockBodyHashTreeRootFailed.into() + ) ); }); } #[test] fn verify_message_invalid_log() { - let header = get_message_verification_header(); let (mut event_log, proof) = get_message_verification_payload(); - let block_hash = proof.block_hash; event_log.topics = vec![H256::zero(); 10]; - new_tester().execute_with(|| { - >::insert(block_hash, header); + assert_ok!(initialize_storage()); assert_err!( EthereumBeaconClient::verify(&event_log, &proof), VerificationError::InvalidLog @@ -1015,13 +694,11 @@ fn verify_message_invalid_log() { #[test] fn verify_message_receipt_does_not_contain_log() { - let header = get_message_verification_header(); let (mut event_log, proof) = get_message_verification_payload(); - let block_hash = proof.block_hash; event_log.data = hex!("f9013c94ee9170abfbf9421ad6dd07f6bdec9d89f2b581e0f863a01b11dcf133cc240f682dab2d3a8e4cd35c5da8c9cf99adac4336f8512584c5ada000000000000000000000000000000000000000000000000000000000000003e8a00000000000000000000000000000000000000000000000000000000000000002b8c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000068000f000000000000000101d184c103f7acc340847eee82a0b909e3358bc28d440edffa1352b13227e8ee646f3ea37456dec70100000101001cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c0000e8890423c78a0000000000000000000000000000000000000000000000000000000000000000").to_vec(); new_tester().execute_with(|| { - >::insert(block_hash, header); + assert_ok!(initialize_storage()); assert_err!( EthereumBeaconClient::verify(&event_log, &proof), VerificationError::LogNotFound @@ -1033,7 +710,6 @@ fn verify_message_receipt_does_not_contain_log() { fn set_operating_mode() { let checkpoint = Box::new(load_checkpoint_update_fixture()); let update = Box::new(load_finalized_header_update_fixture()); - let execution_header_update = Box::new(load_execution_header_update_fixture()); new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); @@ -1047,14 +723,6 @@ fn set_operating_mode() { EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update), Error::::Halted ); - - assert_noop!( - EthereumBeaconClient::submit_execution_header( - RuntimeOrigin::signed(1), - execution_header_update - ), - Error::::Halted - ); }); } @@ -1070,3 +738,107 @@ fn set_operating_mode_root_only() { ); }); } + +#[test] +fn verify_execution_proof_invalid_ancestry_proof() { + let checkpoint = Box::new(load_checkpoint_update_fixture()); + let finalized_header_update = Box::new(load_finalized_header_update_fixture()); + let mut execution_header_update = Box::new(load_execution_proof_fixture()); + if let Some(ref mut ancestry_proof) = execution_header_update.ancestry_proof { + ancestry_proof.header_branch[0] = TEST_HASH.into() + } + + new_tester().execute_with(|| { + assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); + assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); + assert_err!( + EthereumBeaconClient::verify_execution_proof(&execution_header_update), + Error::::InvalidAncestryMerkleProof + ); + }); +} + +#[test] +fn verify_execution_proof_invalid_execution_header_proof() { + let checkpoint = Box::new(load_checkpoint_update_fixture()); + let finalized_header_update = Box::new(load_finalized_header_update_fixture()); + let mut execution_header_update = Box::new(load_execution_proof_fixture()); + execution_header_update.execution_branch[0] = TEST_HASH.into(); + + new_tester().execute_with(|| { + assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); + assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); + assert_err!( + EthereumBeaconClient::verify_execution_proof(&execution_header_update), + Error::::InvalidExecutionHeaderProof + ); + }); +} + +#[test] +fn verify_execution_proof_that_is_also_finalized_header_which_is_not_stored() { + let checkpoint = Box::new(load_checkpoint_update_fixture()); + let finalized_header_update = Box::new(load_finalized_header_update_fixture()); + let mut execution_header_update = Box::new(load_execution_proof_fixture()); + execution_header_update.ancestry_proof = None; + + new_tester().execute_with(|| { + assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); + assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); + assert_err!( + EthereumBeaconClient::verify_execution_proof(&execution_header_update), + Error::::ExpectedFinalizedHeaderNotStored + ); + }); +} + +#[test] +fn submit_execution_proof_that_is_also_finalized_header_which_is_stored_but_slots_dont_match() { + let checkpoint = Box::new(load_checkpoint_update_fixture()); + let finalized_header_update = Box::new(load_finalized_header_update_fixture()); + let mut execution_header_update = Box::new(load_execution_proof_fixture()); + execution_header_update.ancestry_proof = None; + + new_tester().execute_with(|| { + assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); + assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); + + let block_root: H256 = execution_header_update.header.hash_tree_root().unwrap(); + + >::insert( + block_root, + CompactBeaconState { + slot: execution_header_update.header.slot + 1, + block_roots_root: Default::default(), + }, + ); + LatestFinalizedBlockRoot::::set(block_root); + + assert_err!( + EthereumBeaconClient::verify_execution_proof(&execution_header_update), + Error::::ExpectedFinalizedHeaderNotStored + ); + }); +} + +#[test] +fn verify_execution_proof_not_finalized() { + let checkpoint = Box::new(load_checkpoint_update_fixture()); + let finalized_header_update = Box::new(load_finalized_header_update_fixture()); + let update = Box::new(load_execution_proof_fixture()); + + new_tester().execute_with(|| { + assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); + assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); + + >::mutate(>::get(), |x| { + let prev = x.unwrap(); + *x = Some(CompactBeaconState { slot: update.header.slot - 1, ..prev }); + }); + + assert_err!( + EthereumBeaconClient::verify_execution_proof(&update), + Error::::HeaderNotFinalized + ); + }); +} diff --git a/bridges/snowbridge/pallets/ethereum-client/src/types.rs b/bridges/snowbridge/pallets/ethereum-client/src/types.rs index 5dcefea9f80..8808f989754 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/types.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/types.rs @@ -15,17 +15,7 @@ pub type CheckpointUpdate = primitives::CheckpointUpdate; pub type Update = primitives::Update; pub type NextSyncCommitteeUpdate = primitives::NextSyncCommitteeUpdate; -pub use primitives::ExecutionHeaderUpdate; - -/// ExecutionHeader ring buffer implementation -pub type ExecutionHeaderBuffer = RingBufferMapImpl< - u32, - ::MaxExecutionHeadersToKeep, - crate::ExecutionHeaderIndex, - crate::ExecutionHeaderMapping, - crate::ExecutionHeaders, - OptionQuery, ->; +pub use primitives::{AncestryProof, ExecutionProof}; /// FinalizedState ring buffer implementation pub(crate) type FinalizedBeaconStateBuffer = RingBufferMapImpl< diff --git a/bridges/snowbridge/pallets/ethereum-client/src/weights.rs b/bridges/snowbridge/pallets/ethereum-client/src/weights.rs index e1a5578f466..e4629746aa2 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/weights.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/weights.rs @@ -36,7 +36,6 @@ pub trait WeightInfo { fn force_checkpoint() -> Weight; fn submit() -> Weight; fn submit_with_sync_committee() -> Weight; - fn submit_execution_header() -> Weight; } // For backwards compatibility and tests @@ -59,10 +58,4 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(1)) } - fn submit_execution_header() -> Weight { - Weight::from_parts(113_158_000_u64, 0) - .saturating_add(Weight::from_parts(0, 3537)) - .saturating_add(RocksDbWeight::get().reads(5)) - .saturating_add(RocksDbWeight::get().writes(4)) - } } diff --git a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/execution-header-update.json b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/execution-header-update.json deleted file mode 100755 index 319014249c1..00000000000 --- a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/execution-header-update.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "header": { - "slot": 215, - "proposer_index": 2, - "parent_root": "0x97518f531a252bb6ca547b21aca9da767943ec99211d3b15c804e34c3a523f45", - "state_root": "0xb088b5a3a8c90d6dc919a695cd7bb0267c6f983ea2e675c559ceb8f46cb90b67", - "body_root": "0x0ba23c8224fdd01531d5ad51486353bd524a0b4c20bca704e26d3210616f829b" - }, - "ancestry_proof": { - "header_branch": [ - "0x97518f531a252bb6ca547b21aca9da767943ec99211d3b15c804e34c3a523f45", - "0x5ce0db996bd499c2b4f7a93263d5aafd052f420efb617cce6fdd54e25516aa45", - "0x84f0e373b66011ce774c7061440c0a50a51cce2b4b335395eee3e563d605597f", - "0x48f9ccc5f9594142c18c3b5c39a99f0549329c6ab3ba06c9a50030eadca87770", - "0xf89d6e311e05bc75a6f63ce118bccce254551f1a88d54c3b4f773f81f946bd99", - "0x2edd6d893c22636675147c07dfcdb541a146e87c3f15b51c388be4868246dc9b", - "0xd76b7de5f856e3208a91a42c9c398a7f4fab35e667bf916346050ae742514a2d", - "0x83a2e233e76385953ca41de4c3afe60471a61f0cc1b3846b4a0670e3e563b747", - "0xe783a5a109c2ad74e4eb53e8f6b11b31266a92a9e16c1fd5873109c5d41b282c", - "0xd4ea1ef3869ee6a0fd0b19d7d70027d144eecd4f1d32cbf47632a0a9069164b9", - "0xf8179564b58eb93a850d35e4156a04db651106442ad891c3e85155c1762792f1", - "0x4cbb1edb48cf1e32fb30db60aaaeaf6190ffe4d0c8dbc96cec307daecb78be12", - "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f" - ], - "finalized_block_root": "0x890a7f23b9ed2160901654be9efc575d6830ca860e2a97866ae3423fb7bd7231" - }, - "execution_header": { - "Deneb": { - "parent_hash": "0xd82ec63f5c5e6ba61d62f09c188f158e6449b94bdcc31941e68639eec3c4cf7a", - "fee_recipient": "0x0000000000000000000000000000000000000000", - "state_root": "0x8b65545fe5f3216b47b6339b9c91ca2b7f1032a970b04246d9e9fb4460ee34c3", - "receipts_root": "0x7b1f61b9714c080ef0be014e01657a15f45f0304b477beebc7ca5596c8033095", - "logs_bloom": "0x00000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000000000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040004000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000200000000000010", - "prev_randao": "0x6d9e2a012d82b1b6cb0a2c1c1ed24cc16dbb56e6e39ae545371e0666ab057862", - "block_number": 215, - "gas_limit": 64842908, - "gas_used": 119301, - "timestamp": 1705859527, - "extra_data": "0xd983010d0a846765746888676f312e32312e358664617277696e", - "base_fee_per_gas": 7, - "block_hash": "0x48498dbfbcfae53a7f4c289ee00747aceea925f6260c50ead5a33e1c55c40f98", - "transactions_root": "0x5ebc1347fe3df0611d4f66b19bd8e1c6f4eaed0371d850f14c83b1c77ea234e6", - "withdrawals_root": "0x792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535", - "blob_gas_used": 0, - "excess_blob_gas": 0 - } - }, - "execution_branch": [ - "0xf8c69d3830406d668619bcccc13c8dddde41e863326f7418b241d5924c4ad34a", - "0xb46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb", - "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", - "0xf4d6b5cf9c6e212615c3674fa625d04eb1114153fb221ef5ad02aa433fc67cfb" - ] -} \ No newline at end of file diff --git a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/execution-proof.json b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/execution-proof.json new file mode 100755 index 00000000000..f55898087df --- /dev/null +++ b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/execution-proof.json @@ -0,0 +1,54 @@ +{ + "header": { + "slot": 393, + "proposer_index": 4, + "parent_root": "0x6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef", + "state_root": "0xb62ac34a8cb82497be9542fe2114410c9f6021855b766015406101a1f3d86434", + "body_root": "0x04005fe231e11a5b7b1580cb73b177ae8b338bedd745497e6bb7122126a806db" + }, + "ancestry_proof": { + "header_branch": [ + "0x6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef", + "0xfa84cc88ca53a72181599ff4eb07d8b444bce023fe2347c3b4f51004c43439d3", + "0xcadc8ae211c6f2221c9138e829249adf902419c78eb4727a150baa4d9a02cc9d", + "0x33a89962df08a35c52bd7e1d887cd71fa7803e68787d05c714036f6edf75947c", + "0x2c9760fce5c2829ef3f25595a703c21eb22d0186ce223295556ed5da663a82cf", + "0xe1aa87654db79c8a0ecd6c89726bb662fcb1684badaef5cd5256f479e3c622e1", + "0xaa70d5f314e4a1fbb9c362f3db79b21bf68b328887248651fbd29fc501d0ca97", + "0x160b6c235b3a1ed4ef5f80b03ee1c76f7bf3f591c92fca9d8663e9221b9f9f0f", + "0xf68d7dcd6a07a18e9de7b5d2aa1980eb962e11d7dcb584c96e81a7635c8d2535", + "0x1d5f912dfd6697110dd1ecb5cb8e77952eef57d85deb373572572df62bb157fc", + "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", + "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", + "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f" + ], + "finalized_block_root": "0x751414cd97c0624f922b3e80285e9f776b08fa22fd5f87391f2ed7ef571a8d46" + }, + "execution_header": { + "Deneb": { + "parent_hash": "0x8092290aa21b7751576440f77edd02a94058429ce50e63a92d620951fb25eda2", + "fee_recipient": "0x0000000000000000000000000000000000000000", + "state_root": "0x96a83e9ddf745346fafcb0b03d57314623df669ed543c110662b21302a0fae8b", + "receipts_root": "0xdccdfceea05036f7b61dcdabadc937945d31e68a8d3dfd4dc85684457988c284", + "logs_bloom": "0x00000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000400000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000080000000000000000000000000000040004000000000000002002002000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000200000200000010", + "prev_randao": "0x62e309d4f5119d1f5c783abc20fc1a549efbab546d8d0b25ff1cfd58be524e67", + "block_number": 393, + "gas_limit": 54492273, + "gas_used": 199644, + "timestamp": 1710552813, + "extra_data": "0xd983010d0b846765746888676f312e32312e368664617277696e", + "base_fee_per_gas": 7, + "block_hash": "0x6a9810efb9581d30c1a5c9074f27c68ea779a8c1ae31c213241df16225f4e131", + "transactions_root": "0x2cfa6ed7327e8807c7973516c5c32a68ef2459e586e8067e113d081c3bd8c07d", + "withdrawals_root": "0x792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535", + "blob_gas_used": 0, + "excess_blob_gas": 0 + } + }, + "execution_branch": [ + "0xa6833fa629f3286b6916c6e50b8bf089fc9126bee6f64d0413b4e59c1265834d", + "0xb46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb", + "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", + "0xd3af7c05c516726be7505239e0b9c7cb53d24abce6b91cdb3b3995f0164a75da" + ] +} \ No newline at end of file diff --git a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/finalized-header-update.json b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/finalized-header-update.json index f9d5324d57b..2dec5cc56fa 100755 --- a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/finalized-header-update.json +++ b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/finalized-header-update.json @@ -1,38 +1,40 @@ { "attested_header": { - "slot": 2566, - "proposer_index": 6, - "parent_root": "0x6eb9f13a2c496318ce1ab3087bbd872f5c9519a1a7ca8231a2453e3cb523af00", - "state_root": "0xc8cb12766113dff7e46d2917267bf33d0626d99dd47715fcdbc5c65fad3c04b4", - "body_root": "0xd8cfd0d7bc9bc3724417a1655bb0a67c0765ca36197320f4d834150b52ef1420" + "slot": 933, + "proposer_index": 1, + "parent_root": "0xf5fc63e2780ca302b97aea73fc95d74d702b5afe9a772c2b68f695026337b620", + "state_root": "0xd856d11636bc4d866e78be9e747b222b0977556a367ab42e4085277301438050", + "body_root": "0x5689091ab4eb76c2e876271add4924e1c66ce987c300c24aac2ad8c703e9a33f" }, "sync_aggregate": { "sync_committee_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "sync_committee_signature": "0x9296f9a0387f2cac47008e22ad7c3cd3d49d35384c13e6aa1eacca7dca7c3d2ca81515e50eb3396b9550ed20ef7d8fa2049a186598feb2c00e93728045fcff917733d1827481b8fc95f3913e27fc70112c2490496eb57bb7181f02c3f9fd471f" + "sync_committee_signature": "0x93a3d482fe2a2f7fd2b634169752a8fddf1dc28b23a020b398be8526faf37a74ca0f6db1bed78a9c7256c09a6115235e108e0e8a7ce09287317b0856c4b77dfa5adba6cf4c3ebea5bfa4cd2fcde80fd0a532f2defe65d530201d5d2258796559" }, - "signature_slot": 2567, + "signature_slot": 934, "next_sync_committee_update": null, "finalized_header": { - "slot": 2496, - "proposer_index": 2, - "parent_root": "0xc99e49787106733eeebab4d93eb326e1f2214575c9d928f0c4ab0da0776f1622", - "state_root": "0xfbf8a08c86ef36bd173e37e733da4a78aa8e85fee99a990e858dd12a59087fde", - "body_root": "0xa2a8ad06901447b2807a9059580a4c40d8a941f325b1343c69f7c7c6c90e4ab0" + "slot": 864, + "proposer_index": 4, + "parent_root": "0x614e7672f991ac268cd841055973f55e1e42228831a211adef207bb7329be614", + "state_root": "0x5fa8dfca3d760e4242ab46d529144627aa85348a19173b6e081172c701197a4a", + "body_root": "0x0f34c083b1803666bb1ac5e73fa71582731a2cf37d279ff0a3b0cad5a2ff371e" }, "finality_branch": [ - "0x4e00000000000000000000000000000000000000000000000000000000000000", + "0x1b00000000000000000000000000000000000000000000000000000000000000", "0x10c726fac935bf9657cc7476d3cfa7bedec5983dcfb59e8a7df6d0a619e108d7", "0x98e9116c6bb7f20de18800dc63e73e689d06d6a47d35b5e2b32cf093d475840d", - "0x958b8e43347f6df6fa5eb3d62d06a862381a6585aa40640dd1c0de11f1cf89c1", - "0xf107dce04faa86a28fc5d4a618be9cb8d4fc3c23d6c42c3624f3ff4bf6586a03", - "0xa501cdc02e86969ac3e4d0c5a36f4f049efaa1ab8cb6693f51d130eb52a80f30" + "0xf12d9aededc72724e417b518fe6f847684f26f81616243dedf8c551cc7d504f5", + "0x89a85d0907ab3fd6e00ae385f61d456c6191646404ae7b8d23d0e60440cf4d00", + "0x9fc943b6020eb61d780d78bcc6f6102a81d2c868d58f36e61c6e286a2dc4d8c2" ], - "block_roots_root": "0xd160b7687041891b73e54b06fc4e04f82d0fa8fdd76705895e216c6b24709dfe", + "block_roots_root": "0xb9aab9c388c4e4fcd899b71f62c498fc73406e38e8eb14aa440e9affa06f2a10", "block_roots_branch": [ - "0x105290e42d98ab6a0ada6e55453cede36c672abf645eeb986b88d7487616e135", - "0x9da41f274bcdf6122335443d9ce94d07163b48dba3e2f9499ff56f4e48b48b99", - "0xecea7e1d3152d8130e83afdfe34b4de4ba2b69a33c9471991096daf454de9cf5", - "0xb2bf1758e50b2bfff29169fbc70fdb884b2b05bb615dbc53567574da6f4f1ae2", - "0xcd87069daf70975779126d6af833b7d636c75ca4d5e750ebcad0e76408a5e5bf" - ] + "0x733422bd810895dab74cbbe07c69dd440cbb51f573181ad4dddac30fcdd0f41f", + "0x9b9eca73ab01d14549c325ba1b4610bb20bf1f8ec2dbd649f9d8cc7f3cea75fa", + "0xbcc666ad0ad9f9725cbd682bc95589d35b1b53b2a615f1e6e8dd5e086336becf", + "0x3069b547a08f703a1715016e926cbd64e71f93f64fb68d98d8c8f1ab745c46e5", + "0xc2de7e1097239404e17b263cfa0473533cc41e903cb03440d633bc5c27314cb4" + ], + "execution_header": null, + "execution_branch": null } \ No newline at end of file diff --git a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/inbound-message.json b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/inbound-message.json index 5aa5a59f023..6589dca5fb4 100644 --- a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/inbound-message.json +++ b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/inbound-message.json @@ -1,31 +1,79 @@ { - "execution_header": { - "parent_hash": "0xd82ec63f5c5e6ba61d62f09c188f158e6449b94bdcc31941e68639eec3c4cf7a", - "state_root": "0x8b65545fe5f3216b47b6339b9c91ca2b7f1032a970b04246d9e9fb4460ee34c3", - "receipts_root": "0x7b1f61b9714c080ef0be014e01657a15f45f0304b477beebc7ca5596c8033095", - "block_number": 215 + "event_log": { + "address": "0xeda338e4dc46038493b885327842fd3e301cab39", + "topics": [ + "0x7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f", + "0xc173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539", + "0x5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000" }, - "message": { - "event_log": { - "address": "0xeda338e4dc46038493b885327842fd3e301cab39", - "topics": [ - "0x7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f", - "0xc173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539", - "0x5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0" + "proof": { + "block_hash": "0x6a9810efb9581d30c1a5c9074f27c68ea779a8c1ae31c213241df16225f4e131", + "tx_index": 0, + "receipt_proof": { + "keys": [ + "0xdccdfceea05036f7b61dcdabadc937945d31e68a8d3dfd4dc85684457988c284", + "0x4a98e45a319168b0fc6005ce6b744ee9bf54338e2c0784b976a8578d241ced0f" ], - "data": "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000" + "values": [ + "0xf851a09c01dd6d2d8de951c45af23d3ad00829ce021c04d6c8acbe1612d456ee320d4980808080808080a04a98e45a319168b0fc6005ce6b744ee9bf54338e2c0784b976a8578d241ced0f8080808080808080", + "0xf9028c30b9028802f90284018301d205b9010000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000000000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040004000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000200000000000010f90179f85894eda338e4dc46038493b885327842fd3e301cab39e1a0f78bb28d4b1d7da699e5c0bc2be29c2b04b5aab6aacf6298fe5304f9db9c6d7ea000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7df9011c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a05f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0b8a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000" + ] }, - "Proof": { - "block_hash": "0x48498dbfbcfae53a7f4c289ee00747aceea925f6260c50ead5a33e1c55c40f98", - "tx_index": 0, - "data": { - "keys": [ - "0x7b1f61b9714c080ef0be014e01657a15f45f0304b477beebc7ca5596c8033095" + "execution_proof": { + "header": { + "slot": 393, + "proposer_index": 4, + "parent_root": "0x6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef", + "state_root": "0xb62ac34a8cb82497be9542fe2114410c9f6021855b766015406101a1f3d86434", + "body_root": "0x04005fe231e11a5b7b1580cb73b177ae8b338bedd745497e6bb7122126a806db" + }, + "ancestry_proof": { + "header_branch": [ + "0x6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef", + "0xfa84cc88ca53a72181599ff4eb07d8b444bce023fe2347c3b4f51004c43439d3", + "0xcadc8ae211c6f2221c9138e829249adf902419c78eb4727a150baa4d9a02cc9d", + "0x33a89962df08a35c52bd7e1d887cd71fa7803e68787d05c714036f6edf75947c", + "0x2c9760fce5c2829ef3f25595a703c21eb22d0186ce223295556ed5da663a82cf", + "0xe1aa87654db79c8a0ecd6c89726bb662fcb1684badaef5cd5256f479e3c622e1", + "0xaa70d5f314e4a1fbb9c362f3db79b21bf68b328887248651fbd29fc501d0ca97", + "0x160b6c235b3a1ed4ef5f80b03ee1c76f7bf3f591c92fca9d8663e9221b9f9f0f", + "0xf68d7dcd6a07a18e9de7b5d2aa1980eb962e11d7dcb584c96e81a7635c8d2535", + "0x1d5f912dfd6697110dd1ecb5cb8e77952eef57d85deb373572572df62bb157fc", + "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", + "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", + "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f" ], - "values": [ - "0xf9028e822080b9028802f90284018301d205b9010000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000000000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040004000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000200000000000010f90179f85894eda338e4dc46038493b885327842fd3e301cab39e1a0f78bb28d4b1d7da699e5c0bc2be29c2b04b5aab6aacf6298fe5304f9db9c6d7ea000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7df9011c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a05f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0b8a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000" - ] - } + "finalized_block_root": "0x751414cd97c0624f922b3e80285e9f776b08fa22fd5f87391f2ed7ef571a8d46" + }, + "execution_header": { + "Deneb": { + "parent_hash": "0x8092290aa21b7751576440f77edd02a94058429ce50e63a92d620951fb25eda2", + "fee_recipient": "0x0000000000000000000000000000000000000000", + "state_root": "0x96a83e9ddf745346fafcb0b03d57314623df669ed543c110662b21302a0fae8b", + "receipts_root": "0xdccdfceea05036f7b61dcdabadc937945d31e68a8d3dfd4dc85684457988c284", + "logs_bloom": "0x00000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000400000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000080000000000000000000000000000040004000000000000002002002000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000200000200000010", + "prev_randao": "0x62e309d4f5119d1f5c783abc20fc1a549efbab546d8d0b25ff1cfd58be524e67", + "block_number": 393, + "gas_limit": 54492273, + "gas_used": 199644, + "timestamp": 1710552813, + "extra_data": "0xd983010d0b846765746888676f312e32312e368664617277696e", + "base_fee_per_gas": 7, + "block_hash": "0x6a9810efb9581d30c1a5c9074f27c68ea779a8c1ae31c213241df16225f4e131", + "transactions_root": "0x2cfa6ed7327e8807c7973516c5c32a68ef2459e586e8067e113d081c3bd8c07d", + "withdrawals_root": "0x792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535", + "blob_gas_used": 0, + "excess_blob_gas": 0 + } + }, + "execution_branch": [ + "0xa6833fa629f3286b6916c6e50b8bf089fc9126bee6f64d0413b4e59c1265834d", + "0xb46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb", + "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", + "0xd3af7c05c516726be7505239e0b9c7cb53d24abce6b91cdb3b3995f0164a75da" + ] } } } \ No newline at end of file diff --git a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/initial-checkpoint.json b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/initial-checkpoint.json index 202790c1db5..a62d646617e 100755 --- a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/initial-checkpoint.json +++ b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/initial-checkpoint.json @@ -1,10 +1,10 @@ { "header": { - "slot": 2496, - "proposer_index": 2, - "parent_root": "0xc99e49787106733eeebab4d93eb326e1f2214575c9d928f0c4ab0da0776f1622", - "state_root": "0xfbf8a08c86ef36bd173e37e733da4a78aa8e85fee99a990e858dd12a59087fde", - "body_root": "0xa2a8ad06901447b2807a9059580a4c40d8a941f325b1343c69f7c7c6c90e4ab0" + "slot": 864, + "proposer_index": 4, + "parent_root": "0x614e7672f991ac268cd841055973f55e1e42228831a211adef207bb7329be614", + "state_root": "0x5fa8dfca3d760e4242ab46d529144627aa85348a19173b6e081172c701197a4a", + "body_root": "0x0f34c083b1803666bb1ac5e73fa71582731a2cf37d279ff0a3b0cad5a2ff371e" }, "current_sync_committee": { "pubkeys": [ @@ -525,18 +525,18 @@ }, "current_sync_committee_branch": [ "0x3ade38d498a062b50880a9409e1ca3a7fd4315d91eeb3bb83e56ac6bfe8d6a59", - "0x93880225bf99a0c5ec22b266ff829837754e9c5edf37a68c05b8f803fd82fa45", - "0x4c60656ec9a95fcf11030ad309c716b5b15beb7f60a0bcfc7c9d4eff505472ff", - "0x22d1645fceb4bf9a695043dda19a53e784ec70df6a6b1bd66ea30eba1cca5f2f", - "0xa8fc6cad84ceefc633ec56c2d031d525e1cb4b51c70eb252919fce5bba9a1fde" + "0xa9e90f89e7f90fd5d79a6bbcaf40ba5cfc05ab1b561ac51c84867c32248d5b1e", + "0xbd1a76b03e02402bb24a627de1980a80ab17691980271f597b844b89b497ef75", + "0x07bbcd27c7cad089023db046eda17e8209842b7d97add8b873519e84fe6480e7", + "0x94c11eeee4cb6192bf40810f23486d8c75dfbc2b6f28d988d6f74435ede243b0" ], "validators_root": "0x270d43e74ce340de4bca2b1936beca0f4f5408d9e78aec4850920baf659d5b69", - "block_roots_root": "0xd160b7687041891b73e54b06fc4e04f82d0fa8fdd76705895e216c6b24709dfe", + "block_roots_root": "0xb9aab9c388c4e4fcd899b71f62c498fc73406e38e8eb14aa440e9affa06f2a10", "block_roots_branch": [ - "0x105290e42d98ab6a0ada6e55453cede36c672abf645eeb986b88d7487616e135", - "0x9da41f274bcdf6122335443d9ce94d07163b48dba3e2f9499ff56f4e48b48b99", - "0xecea7e1d3152d8130e83afdfe34b4de4ba2b69a33c9471991096daf454de9cf5", - "0xb2bf1758e50b2bfff29169fbc70fdb884b2b05bb615dbc53567574da6f4f1ae2", - "0xcd87069daf70975779126d6af833b7d636c75ca4d5e750ebcad0e76408a5e5bf" + "0x733422bd810895dab74cbbe07c69dd440cbb51f573181ad4dddac30fcdd0f41f", + "0x9b9eca73ab01d14549c325ba1b4610bb20bf1f8ec2dbd649f9d8cc7f3cea75fa", + "0xbcc666ad0ad9f9725cbd682bc95589d35b1b53b2a615f1e6e8dd5e086336becf", + "0x3069b547a08f703a1715016e926cbd64e71f93f64fb68d98d8c8f1ab745c46e5", + "0xc2de7e1097239404e17b263cfa0473533cc41e903cb03440d633bc5c27314cb4" ] } \ No newline at end of file diff --git a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/sync-committee-update.json b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/sync-committee-update.json index 6bf20355c7a..4d601d7d8f0 100755 --- a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/sync-committee-update.json +++ b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/sync-committee-update.json @@ -2,13 +2,13 @@ "attested_header": { "slot": 129, "proposer_index": 5, - "parent_root": "0xe32b6c18f029e755b0273dc1c4fa2bc4979794c8286ad40276c1b8a8e36049d8", - "state_root": "0x5ec9dacf25a5f09f20be0c59246b3d8dcfe64bd085b4bac5cec180690339801e", - "body_root": "0x4080cf2412d6ff77fc3164ad6155423a7112f207f173145ec16371a93f481f87" + "parent_root": "0xc2def03fe44a2802130ca1a6d8406e4ccf4f344fec7075d4d84431cd4a8b0904", + "state_root": "0xfa62cde6666add7353d7aedcb61ebe3c6c84b5361e34f814825b1250affb5be4", + "body_root": "0x0f9c69f243fe7b5fa5860396c66c720a9e8b1e526e7914188930497cc4a9134c" }, "sync_aggregate": { "sync_committee_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "sync_committee_signature": "0xa761c3333fbb3d36bc8f65454f898da38001499dcd37494cf3d86940a995399ae649216ba4c985af154f83f72c8b1856079b7636a7a8d7d3f7602df2cbf699edb72b65253e82de4d9cc4db7377eafb22f799129f63f094a21c00675bdd5cc243" + "sync_committee_signature": "0x810cfde2afea3e276256c09bdf1cd321c33dcadeefddcfd24f488e6f756d917cfda90b5b437b3a4b4ef880985afa28a40cf565ec0a82877ddee36adc01d55d9d4a911ae3e22556e4c2636f1c707366fba019fb49450440fcd263d0b054b04bf0" }, "signature_slot": 130, "next_sync_committee_update": { @@ -531,33 +531,35 @@ }, "next_sync_committee_branch": [ "0x3ade38d498a062b50880a9409e1ca3a7fd4315d91eeb3bb83e56ac6bfe8d6a59", - "0xfd1e5ff5d4a15081efe3ff17857b1f95984c9a271b1c41c2f81f43e60c2cc541", - "0xe1c97f93bb7352d395d1ff8ee29881572cb7eb5d71634783701171dcd30cd93d", - "0x77fa2170ddbd89b15dae02f2e6cf9f76c8e00d1c4217320acffbe01576d0da61", - "0xe97288e0627219087a024078d69445f34f0583a6350a7c3c40c39fd1fa6f8d68" + "0x43276bee17fc9fba3f4866e902f0e5b5b308d79db91154bb8bf819973837a7d9", + "0x5572348e13ce59446ca0ea7cfeed07579da05f121920a76559e19bda94dd81cd", + "0x2d58adca9f3c742530de037f1933d6de1920ea4b68581613d4bc32b71547f221", + "0x7072b3c6577cd5a89b3234968f316f54630bb97eafbdb59e5b61637a9640255f" ] }, "finalized_header": { "slot": 64, "proposer_index": 4, - "parent_root": "0x0f7bc2353778c14c7f6dba0fc5fe6eec87228b0d3a5447b61dce67b4d9338de3", - "state_root": "0xfeb990de653ce494c0a263f820eaf05a9300dbdc30cb6065ede602827bfccde4", - "body_root": "0xf5235cd8c24f2695fc5b7989926305c10ad8cf5a87d62a739f675f5543df2ec1" + "parent_root": "0xa876486aaad7ddb897f369fd22d0a9903cd61d00c9e0dfe7998dd68d1008c678", + "state_root": "0x818e21c3388575f8ccc9ff17ec79d5a57915bcd31bccf47770f65a18e068416b", + "body_root": "0x1d1f73b864b3bb7e11ff91b56ca1381e0f9ca8122b2c542db88243604c763019" }, "finality_branch": [ "0x0200000000000000000000000000000000000000000000000000000000000000", "0x10c726fac935bf9657cc7476d3cfa7bedec5983dcfb59e8a7df6d0a619e108d7", "0x98e9116c6bb7f20de18800dc63e73e689d06d6a47d35b5e2b32cf093d475840d", - "0xe1c97f93bb7352d395d1ff8ee29881572cb7eb5d71634783701171dcd30cd93d", - "0x77fa2170ddbd89b15dae02f2e6cf9f76c8e00d1c4217320acffbe01576d0da61", - "0xe97288e0627219087a024078d69445f34f0583a6350a7c3c40c39fd1fa6f8d68" + "0x5572348e13ce59446ca0ea7cfeed07579da05f121920a76559e19bda94dd81cd", + "0x2d58adca9f3c742530de037f1933d6de1920ea4b68581613d4bc32b71547f221", + "0x7072b3c6577cd5a89b3234968f316f54630bb97eafbdb59e5b61637a9640255f" ], - "block_roots_root": "0x6fcdfd1c3fb1bdd421fe59dddfff3855b5ed5e30373887991a0059d019ad12bc", + "block_roots_root": "0x715b08694bef183a6d94b3113d16a7129f89fc3edec85a7e0eaf6ef9153552ef", "block_roots_branch": [ - "0x94b59531f172bc24f914bc0c10104ccb158676850f8cc3b47b6ddb7f096ebdd7", - "0x22470ed9155a938587d44d5fa19217c0f939d8862e504e67cd8cb4d1b960795e", - "0xfeec3ef1a68f93849e71e84f90b99602cccc31868137b6887ca8244a4b979e8e", + "0x4028c72c71b6ce80ea7d18b2c9471f4e4fa39746261a9921e832a4a2f9bdf7bb", + "0x75f98062661785d3290b7bd998b64446582baa49210733fd4603e1a97cd45a44", + "0x6fb757f44052f30c464810f01b0132adfa1a5446d8715b41e9af88eee1ee3e65", "0x5340ad5877c72dca689ca04bc8fedb78d67a4801d99887937edd8ccd29f87e82", - "0xf5ff4b0c6190005015889879568f5f0d9c40134c7ec4ffdda47950dcd92395ad" - ] + "0xf2b3cb56753939a728ccad399a434ca490f018f2f331529ec0d8b2d59c509271" + ], + "execution_header": null, + "execution_branch": null } \ No newline at end of file diff --git a/bridges/snowbridge/pallets/inbound-queue/fixtures/src/lib.rs b/bridges/snowbridge/pallets/inbound-queue/fixtures/src/lib.rs index 4f3445b2905..00adcdfa186 100644 --- a/bridges/snowbridge/pallets/inbound-queue/fixtures/src/lib.rs +++ b/bridges/snowbridge/pallets/inbound-queue/fixtures/src/lib.rs @@ -2,17 +2,6 @@ // SPDX-FileCopyrightText: 2023 Snowfork #![cfg_attr(not(feature = "std"), no_std)] -use snowbridge_beacon_primitives::CompactExecutionHeader; -use snowbridge_core::inbound::Message; -use sp_core::RuntimeDebug; - pub mod register_token; -pub mod register_token_with_insufficient_fee; pub mod send_token; pub mod send_token_to_penpal; - -#[derive(Clone, RuntimeDebug)] -pub struct InboundQueueFixture { - pub execution_header: CompactExecutionHeader, - pub message: Message, -} diff --git a/bridges/snowbridge/pallets/inbound-queue/fixtures/src/register_token.rs b/bridges/snowbridge/pallets/inbound-queue/fixtures/src/register_token.rs index b8d510e6b13..340b2fadfac 100644 --- a/bridges/snowbridge/pallets/inbound-queue/fixtures/src/register_token.rs +++ b/bridges/snowbridge/pallets/inbound-queue/fixtures/src/register_token.rs @@ -3,20 +3,16 @@ // Generated, do not edit! // See ethereum client README.md for instructions to generate -use crate::InboundQueueFixture; use hex_literal::hex; -use snowbridge_beacon_primitives::CompactExecutionHeader; -use snowbridge_core::inbound::{Log, Message, Proof}; +use snowbridge_beacon_primitives::{ + types::deneb, AncestryProof, BeaconHeader, ExecutionProof, VersionedExecutionPayloadHeader, +}; +use snowbridge_core::inbound::{InboundQueueFixture, Log, Message, Proof}; +use sp_core::U256; use sp_std::vec; pub fn make_register_token_message() -> InboundQueueFixture { InboundQueueFixture { - execution_header: CompactExecutionHeader{ - parent_hash: hex!("d5de3dd02c96dbdc8aaa4db70a1e9fdab5ded5f4d52f18798acd56a3d37d1ad6").into(), - block_number: 772, - state_root: hex!("49cba2a79b23ad74cefe80c3a96699825d1cda0f75bfceb587c5549211c86245").into(), - receipts_root: hex!("7b1f61b9714c080ef0be014e01657a15f45f0304b477beebc7ca5596c8033095").into(), - }, message: Message { event_log: Log { address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(), @@ -28,14 +24,74 @@ pub fn make_register_token_message() -> InboundQueueFixture { data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000").into(), }, proof: Proof { - block_hash: hex!("392182a385b3a417e8ddea8b252953ee81e6ec0fb09d9056c96c89fbeb703a3f").into(), - tx_index: 0, - data: (vec![ - hex!("7b1f61b9714c080ef0be014e01657a15f45f0304b477beebc7ca5596c8033095").to_vec(), + receipt_proof: (vec![ + hex!("dccdfceea05036f7b61dcdabadc937945d31e68a8d3dfd4dc85684457988c284").to_vec(), + hex!("4a98e45a319168b0fc6005ce6b744ee9bf54338e2c0784b976a8578d241ced0f").to_vec(), ], vec![ - hex!("f9028e822080b9028802f90284018301d205b9010000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000000000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040004000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000200000000000010f90179f85894eda338e4dc46038493b885327842fd3e301cab39e1a0f78bb28d4b1d7da699e5c0bc2be29c2b04b5aab6aacf6298fe5304f9db9c6d7ea000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7df9011c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a05f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0b8a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000").to_vec(), + hex!("f851a09c01dd6d2d8de951c45af23d3ad00829ce021c04d6c8acbe1612d456ee320d4980808080808080a04a98e45a319168b0fc6005ce6b744ee9bf54338e2c0784b976a8578d241ced0f8080808080808080").to_vec(), + hex!("f9028c30b9028802f90284018301d205b9010000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000000000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040004000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000200000000000010f90179f85894eda338e4dc46038493b885327842fd3e301cab39e1a0f78bb28d4b1d7da699e5c0bc2be29c2b04b5aab6aacf6298fe5304f9db9c6d7ea000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7df9011c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a05f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0b8a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000").to_vec(), ]), + execution_proof: ExecutionProof { + header: BeaconHeader { + slot: 393, + proposer_index: 4, + parent_root: hex!("6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef").into(), + state_root: hex!("b62ac34a8cb82497be9542fe2114410c9f6021855b766015406101a1f3d86434").into(), + body_root: hex!("04005fe231e11a5b7b1580cb73b177ae8b338bedd745497e6bb7122126a806db").into(), + }, + ancestry_proof: Some(AncestryProof { + header_branch: vec![ + hex!("6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef").into(), + hex!("fa84cc88ca53a72181599ff4eb07d8b444bce023fe2347c3b4f51004c43439d3").into(), + hex!("cadc8ae211c6f2221c9138e829249adf902419c78eb4727a150baa4d9a02cc9d").into(), + hex!("33a89962df08a35c52bd7e1d887cd71fa7803e68787d05c714036f6edf75947c").into(), + hex!("2c9760fce5c2829ef3f25595a703c21eb22d0186ce223295556ed5da663a82cf").into(), + hex!("e1aa87654db79c8a0ecd6c89726bb662fcb1684badaef5cd5256f479e3c622e1").into(), + hex!("aa70d5f314e4a1fbb9c362f3db79b21bf68b328887248651fbd29fc501d0ca97").into(), + hex!("160b6c235b3a1ed4ef5f80b03ee1c76f7bf3f591c92fca9d8663e9221b9f9f0f").into(), + hex!("f68d7dcd6a07a18e9de7b5d2aa1980eb962e11d7dcb584c96e81a7635c8d2535").into(), + hex!("1d5f912dfd6697110dd1ecb5cb8e77952eef57d85deb373572572df62bb157fc").into(), + hex!("ffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b").into(), + hex!("6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220").into(), + hex!("b7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f").into(), + ], + finalized_block_root: hex!("751414cd97c0624f922b3e80285e9f776b08fa22fd5f87391f2ed7ef571a8d46").into(), + }), + execution_header: VersionedExecutionPayloadHeader::Deneb(deneb::ExecutionPayloadHeader { + parent_hash: hex!("8092290aa21b7751576440f77edd02a94058429ce50e63a92d620951fb25eda2").into(), + fee_recipient: hex!("0000000000000000000000000000000000000000").into(), + state_root: hex!("96a83e9ddf745346fafcb0b03d57314623df669ed543c110662b21302a0fae8b").into(), + receipts_root: hex!("dccdfceea05036f7b61dcdabadc937945d31e68a8d3dfd4dc85684457988c284").into(), + logs_bloom: hex!("00000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000400000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000080000000000000000000000000000040004000000000000002002002000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000200000200000010").into(), + prev_randao: hex!("62e309d4f5119d1f5c783abc20fc1a549efbab546d8d0b25ff1cfd58be524e67").into(), + block_number: 393, + gas_limit: 54492273, + gas_used: 199644, + timestamp: 1710552813, + extra_data: hex!("d983010d0b846765746888676f312e32312e368664617277696e").into(), + base_fee_per_gas: U256::from(7u64), + block_hash: hex!("6a9810efb9581d30c1a5c9074f27c68ea779a8c1ae31c213241df16225f4e131").into(), + transactions_root: hex!("2cfa6ed7327e8807c7973516c5c32a68ef2459e586e8067e113d081c3bd8c07d").into(), + withdrawals_root: hex!("792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535").into(), + blob_gas_used: 0, + excess_blob_gas: 0, + }), + execution_branch: vec![ + hex!("a6833fa629f3286b6916c6e50b8bf089fc9126bee6f64d0413b4e59c1265834d").into(), + hex!("b46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb").into(), + hex!("db56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71").into(), + hex!("d3af7c05c516726be7505239e0b9c7cb53d24abce6b91cdb3b3995f0164a75da").into(), + ], + } }, }, + finalized_header: BeaconHeader { + slot: 864, + proposer_index: 4, + parent_root: hex!("614e7672f991ac268cd841055973f55e1e42228831a211adef207bb7329be614").into(), + state_root: hex!("5fa8dfca3d760e4242ab46d529144627aa85348a19173b6e081172c701197a4a").into(), + body_root: hex!("0f34c083b1803666bb1ac5e73fa71582731a2cf37d279ff0a3b0cad5a2ff371e").into(), + }, + block_roots_root: hex!("b9aab9c388c4e4fcd899b71f62c498fc73406e38e8eb14aa440e9affa06f2a10").into(), } } diff --git a/bridges/snowbridge/pallets/inbound-queue/fixtures/src/register_token_with_insufficient_fee.rs b/bridges/snowbridge/pallets/inbound-queue/fixtures/src/register_token_with_insufficient_fee.rs deleted file mode 100644 index dfda0b2b427..00000000000 --- a/bridges/snowbridge/pallets/inbound-queue/fixtures/src/register_token_with_insufficient_fee.rs +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2023 Snowfork -// Generated, do not edit! -// See ethereum client README.md for instructions to generate - -use crate::InboundQueueFixture; -use hex_literal::hex; -use snowbridge_beacon_primitives::CompactExecutionHeader; -use snowbridge_core::inbound::{Log, Message, Proof}; -use sp_std::vec; - -pub fn make_register_token_with_insufficient_fee_message() -> InboundQueueFixture { - InboundQueueFixture { - execution_header: CompactExecutionHeader{ - parent_hash: hex!("998e81dc6df788a920b67e058fbde0dc3f4ec6f11f3f7cd8c3148e6d99584885").into(), - block_number: 338, - state_root: hex!("30ef9c9db2609de19bbc6c3cbeddac889e82bbcb2db20304b3abdfbdc7134cbf").into(), - receipts_root: hex!("969335c3132a007cb8b5886a3c23dd8da63cba04aeda29857a86ee1c13dae782").into(), - }, - message: Message { - event_log: Log { - address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(), - topics: vec![ - hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(), - hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into(), - hex!("5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0").into(), - ], - // insufficient xcm fee as only 1000(hex:e803) - data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7de8030000000000000000000000000000000000000000000000000000000000000000").into(), - }, - proof: Proof { - block_hash: hex!("5976f37f0e331d194eb331df74355ef47565c3a1bd11c95a45b681f6917085c1").into(), - tx_index: 0, - data: (vec![ - hex!("969335c3132a007cb8b5886a3c23dd8da63cba04aeda29857a86ee1c13dae782").to_vec(), - ], vec![ - hex!("f9028e822080b9028802f90284018301d205b9010000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000000000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040004000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000200000000000010f90179f85894eda338e4dc46038493b885327842fd3e301cab39e1a0f78bb28d4b1d7da699e5c0bc2be29c2b04b5aab6aacf6298fe5304f9db9c6d7ea000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7df9011c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a05f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0b8a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7de8030000000000000000000000000000000000000000000000000000000000000000").to_vec(), - ]), - }, - }, - } -} diff --git a/bridges/snowbridge/pallets/inbound-queue/fixtures/src/send_token.rs b/bridges/snowbridge/pallets/inbound-queue/fixtures/src/send_token.rs index 2562217100e..4075febab59 100755 --- a/bridges/snowbridge/pallets/inbound-queue/fixtures/src/send_token.rs +++ b/bridges/snowbridge/pallets/inbound-queue/fixtures/src/send_token.rs @@ -3,20 +3,16 @@ // Generated, do not edit! // See ethereum client README.md for instructions to generate -use crate::InboundQueueFixture; use hex_literal::hex; -use snowbridge_beacon_primitives::CompactExecutionHeader; -use snowbridge_core::inbound::{Log, Message, Proof}; +use snowbridge_beacon_primitives::{ + types::deneb, AncestryProof, BeaconHeader, ExecutionProof, VersionedExecutionPayloadHeader, +}; +use snowbridge_core::inbound::{InboundQueueFixture, Log, Message, Proof}; +use sp_core::U256; use sp_std::vec; pub fn make_send_token_message() -> InboundQueueFixture { InboundQueueFixture { - execution_header: CompactExecutionHeader{ - parent_hash: hex!("920cecde45d428e3a77590b70f8533cf4c2c36917b8a7b74c915e7fa3dae7075").into(), - block_number: 1148, - state_root: hex!("bbc6ba0e9940d641afecbbaf3f97abd2b9ffaf2f6bd4879c4a71e659eca89978").into(), - receipts_root: hex!("9f3340b57eddc1f86de30776db57faeca80269a3dd459031741988dec240ce34").into(), - }, message: Message { event_log: Log { address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(), @@ -28,14 +24,72 @@ pub fn make_send_token_message() -> InboundQueueFixture { data: hex!("00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005f00a736aa00000000000187d1f7fdfee7f651fabc8bfcb6e086c278b77a7d008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48000064a7b3b6e00d000000000000000000e40b5402000000000000000000000000").into(), }, proof: Proof { - block_hash: hex!("d3c155f123c3cbff22f3d7869283e02179edea9ffa7a5e9a4d8414c2a6b8991f").into(), - tx_index: 0, - data: (vec![ - hex!("9f3340b57eddc1f86de30776db57faeca80269a3dd459031741988dec240ce34").to_vec(), + receipt_proof: (vec![ + hex!("f9d844c5b79638609ba385b910fec3b5d891c9d7b189f135f0432f33473de915").to_vec(), ], vec![ - hex!("f90451822080b9044b02f90447018301bcb9b9010000800000000000000000000020000000000000000000004000000000000000000400000000000000000000001000000010000000000000000000000008000000200000000000000001000008000000000000000000000000000000008000080000000000200000000000000000000000000100000000000000000011000000000000020200000000000000000000000000003000000040080008000000000000000000040044000021000000002000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000200800000000000f9033cf89b9487d1f7fdfee7f651fabc8bfcb6e086c278b77a7df863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa000000000000000000000000090a987b944cb1dcce5564e5fdecd7a54d3de27fea000000000000000000000000057a2d4ff0c3866d96556884bf09fecdd7ccd530ca00000000000000000000000000000000000000000000000000de0b6b3a7640000f9015d94eda338e4dc46038493b885327842fd3e301cab39f884a024c5d2de620c6e25186ae16f6919eba93b6e2c1a33857cc419d9f3a00d6967e9a000000000000000000000000090a987b944cb1dcce5564e5fdecd7a54d3de27fea000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7da000000000000000000000000000000000000000000000000000000000000003e8b8c000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000208eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48f9013c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a0c8eaf22f2cb07bac4679df0a660e7115ed87fcfd4e32ac269f6540265bbbd26fb8c000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005f00a736aa00000000000187d1f7fdfee7f651fabc8bfcb6e086c278b77a7d008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48000064a7b3b6e00d000000000000000000e40b5402000000000000000000000000").to_vec(), + hex!("f90451822080b9044b02f90447018301bcb6b9010000800000000000000000000020000000000000000000004000000000000000000400000000000000000000001000000010000000000000000000000008000000200000000000000001000008000000000000000000000000000000008000080000000000200000000000000000000000000100000000000000000011000000000000020200000000000000000000000000003000000040080008000000000000000000040044000021000000002000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000200800000000000f9033cf89b9487d1f7fdfee7f651fabc8bfcb6e086c278b77a7df863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa000000000000000000000000090a987b944cb1dcce5564e5fdecd7a54d3de27fea000000000000000000000000057a2d4ff0c3866d96556884bf09fecdd7ccd530ca00000000000000000000000000000000000000000000000000de0b6b3a7640000f9015d94eda338e4dc46038493b885327842fd3e301cab39f884a024c5d2de620c6e25186ae16f6919eba93b6e2c1a33857cc419d9f3a00d6967e9a000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7da000000000000000000000000090a987b944cb1dcce5564e5fdecd7a54d3de27fea000000000000000000000000000000000000000000000000000000000000003e8b8c000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000208eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48f9013c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a0c8eaf22f2cb07bac4679df0a660e7115ed87fcfd4e32ac269f6540265bbbd26fb8c000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005f00a736aa00000000000187d1f7fdfee7f651fabc8bfcb6e086c278b77a7d008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48000064a7b3b6e00d000000000000000000e40b5402000000000000000000000000").to_vec(), ]), + execution_proof: ExecutionProof { + header: BeaconHeader { + slot: 2321, + proposer_index: 5, + parent_root: hex!("2add14727840d3a5ea061e14baa47030bb81380a65999200d119e73b86411d20").into(), + state_root: hex!("d962981467920bb2b7efa4a7a1baf64745582c3250857f49a957c5dae9a0da39").into(), + body_root: hex!("18e3f7f51a350f371ad35d166f2683b42af51d1836b295e4093be08acb0dcb7a").into(), + }, + ancestry_proof: Some(AncestryProof { + header_branch: vec![ + hex!("2add14727840d3a5ea061e14baa47030bb81380a65999200d119e73b86411d20").into(), + hex!("48b2e2f5256906a564e5058698f70e3406765fefd6a2edc064bb5fb88aa2ed0a").into(), + hex!("e5ed7c704e845418219b2fda42cd2f3438ffbe4c4b320935ae49439c6189f7a7").into(), + hex!("4a7ce24526b3f571548ad69679e4e260653a1b3b911a344e7f988f25a5c917a7").into(), + hex!("46fc859727ab0d0e8c344011f7d7a4426ccb537bb51363397e56cc7153f56391").into(), + hex!("f496b6f85a7c6c28a9048f2153550a7c5bcb4b23844ed3b87f6baa646124d8a3").into(), + hex!("7318644e474beb46e595a1875acc7444b937f5208065241911d2a71ac50c2de3").into(), + hex!("5cf48519e518ac64286aef5391319782dd38831d5dcc960578a6b9746d5f8cee").into(), + hex!("efb3e50fa39ca9fe7f76adbfa36fa8451ec2fd5d07b22aaf822137c04cf95a76").into(), + hex!("2206cd50750355ffaef4a67634c21168f2b564c58ffd04f33b0dc7af7dab3291").into(), + hex!("1a4014f6c4fcce9949fba74cb0f9e88df086706f9e05560cc9f0926f8c90e373").into(), + hex!("2df7cc0bcf3060be4132c63da7599c2600d9bbadf37ab001f15629bc2255698e").into(), + hex!("b7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f").into(), + ], + finalized_block_root: hex!("f869dd1c9598043008a3ac2a5d91b3d6c7b0bb3295b3843bc84c083d70b0e604").into(), + }), + execution_header: VersionedExecutionPayloadHeader::Deneb(deneb::ExecutionPayloadHeader { + parent_hash: hex!("5d7859883dde1eba6c98b20eac18426134b25da2a89e5e360f3343b15e0e0a31").into(), + fee_recipient: hex!("0000000000000000000000000000000000000000").into(), + state_root: hex!("f8fbebed4c84d46231bd293bb9fbc9340d5c28c284d99fdaddb77238b8960ae2").into(), + receipts_root: hex!("f9d844c5b79638609ba385b910fec3b5d891c9d7b189f135f0432f33473de915").into(), + logs_bloom: hex!("00800000000000000000000020000000000000000000004000000000000000000400000000000000000000001000000010000000000000000000000008000000200000000000000001000008000000000000000000000000000000008000080000000000200000000000000000000000000100000000000000000011000000000000020200000000000000000000000000003000000040080008000000000000000000040044000021000000002000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000200800000000000").into(), + prev_randao: hex!("15533eeb366c6386bea5aeb8f425871928348c092209e4377f2418a6dedd7fd0").into(), + block_number: 2321, + gas_limit: 30000000, + gas_used: 113846, + timestamp: 1710554741, + extra_data: hex!("d983010d0b846765746888676f312e32312e368664617277696e").into(), + base_fee_per_gas: U256::from(7u64), + block_hash: hex!("585a07122a30339b03b6481eae67c2d3de2b6b64f9f426230986519bf0f1bdfe").into(), + transactions_root: hex!("09cd60ee2207d804397c81f7b7e1e5d3307712b136e5376623a80317a4bdcd7a").into(), + withdrawals_root: hex!("792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535").into(), + blob_gas_used: 0, + excess_blob_gas: 0, + }), + execution_branch: vec![ + hex!("9d419471a9a4719b40e7607781fbe32d9a7766b79805505c78c0c58133496ba2").into(), + hex!("b46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb").into(), + hex!("db56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71").into(), + hex!("bee375b8f1bbe4cd0e783c78026c1829ae72741c2dead5cab05d6834c5e5df65").into(), + ], + } }, }, + finalized_header: BeaconHeader { + slot: 4032, + proposer_index: 5, + parent_root: hex!("180aaaec59d38c3860e8af203f01f41c9bc41665f4d17916567c80f6cd23e8a2").into(), + state_root: hex!("3341790429ed3bf894cafa3004351d0b99e08baf6c38eb2a54d58e69fd2d19c6").into(), + body_root: hex!("a221e0c695ac7b7d04ce39b28b954d8a682ecd57961d81b44783527c6295f455").into(), + }, + block_roots_root: hex!("5744385ef06f82e67606f49aa29cd162f2e837a68fb7bd82f1fc6155d9f8640f").into(), } } diff --git a/bridges/snowbridge/pallets/inbound-queue/fixtures/src/send_token_to_penpal.rs b/bridges/snowbridge/pallets/inbound-queue/fixtures/src/send_token_to_penpal.rs index 86ba3f7ecc1..6a951b568ae 100755 --- a/bridges/snowbridge/pallets/inbound-queue/fixtures/src/send_token_to_penpal.rs +++ b/bridges/snowbridge/pallets/inbound-queue/fixtures/src/send_token_to_penpal.rs @@ -3,39 +3,93 @@ // Generated, do not edit! // See ethereum client README.md for instructions to generate -use crate::InboundQueueFixture; use hex_literal::hex; -use snowbridge_beacon_primitives::CompactExecutionHeader; -use snowbridge_core::inbound::{Log, Message, Proof}; +use snowbridge_beacon_primitives::{ + types::deneb, AncestryProof, BeaconHeader, ExecutionProof, VersionedExecutionPayloadHeader, +}; +use snowbridge_core::inbound::{InboundQueueFixture, Log, Message, Proof}; +use sp_core::U256; use sp_std::vec; pub fn make_send_token_to_penpal_message() -> InboundQueueFixture { InboundQueueFixture { - execution_header: CompactExecutionHeader{ - parent_hash: hex!("434148c290f27ee4be34fa344cd7608bf942a4541b27c9d868439631b3f37a8d").into(), - block_number: 816, - state_root: hex!("595e643f9095870e30e85e2bbef7d9e3a39df5aae839d26cf455d3dbf3e5a539").into(), - receipts_root: hex!("c40ab2c4abcfdea4f42195e0ad822806e5423108021c3b542646c7193319a6c1").into(), - }, message: Message { event_log: Log { address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(), topics: vec![ hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(), hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into(), - hex!("c8eaf22f2cb07bac4679df0a660e7115ed87fcfd4e32ac269f6540265bbbd26f").into(), + hex!("be323bced46a1a49c8da2ab62ad5e974fd50f1dabaeed70b23ca5bcf14bfe4aa").into(), ], - data: hex!("00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000007300a736aa00000000000187d1f7fdfee7f651fabc8bfcb6e086c278b77a7d01d00700001cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c00286bee000000000000000000000000000064a7b3b6e00d000000000000000000e40b5402000000000000000000000000000000000000000000000000").into(), + data: hex!("00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000007300a736aa00000000000187d1f7fdfee7f651fabc8bfcb6e086c278b77a7d01d00700001cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c00286bee000000000000000000000000000064a7b3b6e00d000000000000000000e40b5402000000000000000000000000000000000000000000000000").into(), }, proof: Proof { - block_hash: hex!("6c49a7f8fb2014a23e58a949c95a6743174589a7ce83434b073dc05dec402f3d").into(), - tx_index: 0, - data: (vec![ - hex!("c40ab2c4abcfdea4f42195e0ad822806e5423108021c3b542646c7193319a6c1").to_vec(), + receipt_proof: (vec![ + hex!("106f1eaeac04e469da0020ad5c8a72af66323638bd3f561a3c8236063202c120").to_vec(), ], vec![ - hex!("f90471822080b9046b02f90467018301d30fb9010000800000000000000000000000000000000000000000004000000000000000000400000000004000000000001000000010000000000000000000000008000000200000000000000001000008000000000000000000000000000000008000080000000000200000000000000000000000000100000000000000000011000000000000020000000000000000000000000000003000000000080018000000000000000000040044000021000000002000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000200820000000000f9035cf89b9487d1f7fdfee7f651fabc8bfcb6e086c278b77a7df863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa000000000000000000000000090a987b944cb1dcce5564e5fdecd7a54d3de27fea000000000000000000000000057a2d4ff0c3866d96556884bf09fecdd7ccd530ca00000000000000000000000000000000000000000000000000de0b6b3a7640000f9015d94eda338e4dc46038493b885327842fd3e301cab39f884a024c5d2de620c6e25186ae16f6919eba93b6e2c1a33857cc419d9f3a00d6967e9a000000000000000000000000090a987b944cb1dcce5564e5fdecd7a54d3de27fea000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7da000000000000000000000000000000000000000000000000000000000000007d0b8c000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000201cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07cf9015c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a0c8eaf22f2cb07bac4679df0a660e7115ed87fcfd4e32ac269f6540265bbbd26fb8e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000007300a736aa00000000000187d1f7fdfee7f651fabc8bfcb6e086c278b77a7d01d00700001cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c00286bee000000000000000000000000000064a7b3b6e00d000000000000000000e40b5402000000000000000000000000000000000000000000000000").to_vec(), + hex!("f90471822080b9046b02f904670183017d9cb9010000800000000000008000000000000000000000000000004000000000000000000400000000004000000000001000000010000000000000000000001008000000000000000000000001000008000040000000000000000000000000008000080000000000200000000000000000000000000100000000000000000010000000000000020000000000000000000000000000003000000000080018000000000000000000040004000021000000002000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000200820000000000f9035cf89b9487d1f7fdfee7f651fabc8bfcb6e086c278b77a7df863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa000000000000000000000000090a987b944cb1dcce5564e5fdecd7a54d3de27fea000000000000000000000000057a2d4ff0c3866d96556884bf09fecdd7ccd530ca00000000000000000000000000000000000000000000000000de0b6b3a7640000f9015d94eda338e4dc46038493b885327842fd3e301cab39f884a024c5d2de620c6e25186ae16f6919eba93b6e2c1a33857cc419d9f3a00d6967e9a000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7da000000000000000000000000090a987b944cb1dcce5564e5fdecd7a54d3de27fea000000000000000000000000000000000000000000000000000000000000007d0b8c000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000201cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07cf9015c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a0be323bced46a1a49c8da2ab62ad5e974fd50f1dabaeed70b23ca5bcf14bfe4aab8e000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000007300a736aa00000000000187d1f7fdfee7f651fabc8bfcb6e086c278b77a7d01d00700001cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c00286bee000000000000000000000000000064a7b3b6e00d000000000000000000e40b5402000000000000000000000000000000000000000000000000").to_vec(), ]), + execution_proof: ExecutionProof { + header: BeaconHeader { + slot: 4235, + proposer_index: 4, + parent_root: hex!("1b31e6264c19bcad120e434e0aede892e7d7c8ed80ab505cb593d9a4a16bc566").into(), + state_root: hex!("725f51771a0ecf72c647a283ab814ca088f998eb8c203181496b0b8e01f624fa").into(), + body_root: hex!("6f1c326d192e7e97e21e27b16fd7f000b8fa09b435ff028849927e382302b0ce").into(), + }, + ancestry_proof: Some(AncestryProof { + header_branch: vec![ + hex!("1b31e6264c19bcad120e434e0aede892e7d7c8ed80ab505cb593d9a4a16bc566").into(), + hex!("335eb186c077fa7053ec96dcc5d34502c997713d2d5bc4eb74842118d8cd5a64").into(), + hex!("326607faf2a7dfc9cfc4b6895f8f3d92a659552deb2c8fd1e892ec00c86c734c").into(), + hex!("4e20002125d7b6504df7c774f3f48e018e1e6762d03489149670a8335bba1425").into(), + hex!("e76af5cd61aade5aec8282b6f1df9046efa756b0466bba5e49032410f7739a1b").into(), + hex!("ee4dcd9527712116380cddafd120484a3bedf867225bbb86850b84decf6da730").into(), + hex!("e4687a07421d3150439a2cd2f09f3b468145d75b359a2e5fa88dfbec51725b15").into(), + hex!("38eaa78978e95759aa9b6f8504a8dbe36151f20ae41907e6a1ea165700ceefcd").into(), + hex!("1c1b071ec6f13e15c47d07d1bfbcc9135d6a6c819e68e7e6078a2007418c1a23").into(), + hex!("0b3ad7ad193c691c8c4ba1606ad2a90482cd1d033c7db58cfe739d0e20431e9e").into(), + hex!("ffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b").into(), + hex!("6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220").into(), + hex!("b2ffec5f2c14640305dd941330f09216c53b99d198e93735a400a6d3a4de191f").into(), + ], + finalized_block_root: hex!("08be7a59e947f08cd95c4ef470758730bf9e3b0db0824cb663ea541c39b0e65c").into(), + }), + execution_header: VersionedExecutionPayloadHeader::Deneb(deneb::ExecutionPayloadHeader { + parent_hash: hex!("5d1186ae041f58785edb2f01248e95832f2e5e5d6c4eb8f7ff2f58980bfc2de9").into(), + fee_recipient: hex!("0000000000000000000000000000000000000000").into(), + state_root: hex!("2a66114d20e93082c8e9b47c8d401a937013487d757c9c2f3123cf43dc1f656d").into(), + receipts_root: hex!("106f1eaeac04e469da0020ad5c8a72af66323638bd3f561a3c8236063202c120").into(), + logs_bloom: hex!("00800000000000008000000000000000000000000000004000000000000000000400000000004000000000001000000010000000000000000000001008000000000000000000000001000008000040000000000000000000000000008000080000000000200000000000000000000000000100000000000000000010000000000000020000000000000000000000000000003000000000080018000000000000000000040004000021000000002000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000200820000000000").into(), + prev_randao: hex!("92e063c7e369b74149fdd1d7132ed2f635a19b9d8bff57637b8ee4736576426e").into(), + block_number: 4235, + gas_limit: 30000000, + gas_used: 97692, + timestamp: 1710556655, + extra_data: hex!("d983010d0b846765746888676f312e32312e368664617277696e").into(), + base_fee_per_gas: U256::from(7u64), + block_hash: hex!("ce24fe3047aa20a8f222cd1d04567c12b39455400d681141962c2130e690953f").into(), + transactions_root: hex!("0c8388731de94771777c60d452077065354d90d6e5088db61fc6a134684195cc").into(), + withdrawals_root: hex!("792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535").into(), + blob_gas_used: 0, + excess_blob_gas: 0, + }), + execution_branch: vec![ + hex!("99d397fa180078e66cd3a3b77bcb07553052f4e21d447167f3a406f663b14e6a").into(), + hex!("b46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb").into(), + hex!("db56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71").into(), + hex!("53ddf17147819c1abb918178b0230d965d1bc2c0d389f45e91e54cb1d2d468aa").into(), + ], + } }, }, + finalized_header: BeaconHeader { + slot: 4672, + proposer_index: 4, + parent_root: hex!("951233bf9f4bddfb2fa8f54e3bd0c7883779ef850e13e076baae3130dd7732db").into(), + state_root: hex!("4d303003b8cb097cbcc14b0f551ee70dac42de2c1cc2f4acfca7058ca9713291").into(), + body_root: hex!("664d13952b6f369bf4cf3af74d067ec33616eb57ed3a8a403fd5bae4fbf737dd").into(), + }, + block_roots_root: hex!("af71048297c070e6539cf3b9b90ae07d86d363454606bc239734629e6b49b983").into(), } } diff --git a/bridges/snowbridge/pallets/inbound-queue/src/benchmarking/mod.rs b/bridges/snowbridge/pallets/inbound-queue/src/benchmarking/mod.rs index 931befa2ac6..d59d9275772 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/benchmarking/mod.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/benchmarking/mod.rs @@ -19,8 +19,8 @@ mod benchmarks { let create_message = make_register_token_message(); T::Helper::initialize_storage( - create_message.message.proof.block_hash, - create_message.execution_header, + create_message.finalized_header, + create_message.block_roots_root, ); let sovereign_account = sibling_sovereign_account::(1000u32.into()); diff --git a/bridges/snowbridge/pallets/inbound-queue/src/lib.rs b/bridges/snowbridge/pallets/inbound-queue/src/lib.rs index bdc21fcf037..8acbb0c2916 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/lib.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/lib.rs @@ -28,9 +28,6 @@ mod envelope; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; -#[cfg(feature = "runtime-benchmarks")] -use snowbridge_beacon_primitives::CompactExecutionHeader; - pub mod weights; #[cfg(test)] @@ -44,7 +41,7 @@ use envelope::Envelope; use frame_support::{ traits::{ fungible::{Inspect, Mutate}, - tokens::Preservation, + tokens::{Fortitude, Preservation}, }, weights::WeightToFee, PalletError, @@ -52,6 +49,7 @@ use frame_support::{ use frame_system::ensure_signed; use scale_info::TypeInfo; use sp_core::{H160, H256}; +use sp_runtime::traits::Zero; use sp_std::{convert::TryFrom, vec}; use xcm::prelude::{ send_xcm, Instruction::SetTopic, Junction::*, Location, SendError as XcmpSendError, SendXcm, @@ -72,6 +70,9 @@ use sp_runtime::{traits::Saturating, SaturatedConversion, TokenError}; pub use weights::WeightInfo; +#[cfg(feature = "runtime-benchmarks")] +use snowbridge_beacon_primitives::BeaconHeader; + type BalanceOf = <::Token as Inspect<::AccountId>>::Balance; @@ -91,7 +92,7 @@ pub mod pallet { #[cfg(feature = "runtime-benchmarks")] pub trait BenchmarkHelper { - fn initialize_storage(block_hash: H256, header: CompactExecutionHeader); + fn initialize_storage(beacon_header: BeaconHeader, block_roots_root: H256); } #[pallet::config] @@ -261,11 +262,19 @@ pub mod pallet { } })?; - // Reward relayer from the sovereign account of the destination parachain - // Expected to fail if sovereign account has no funds + // Reward relayer from the sovereign account of the destination parachain, only if funds + // are available let sovereign_account = sibling_sovereign_account::(channel.para_id); let delivery_cost = Self::calculate_delivery_cost(message.encode().len() as u32); - T::Token::transfer(&sovereign_account, &who, delivery_cost, Preservation::Preserve)?; + let amount = T::Token::reducible_balance( + &sovereign_account, + Preservation::Preserve, + Fortitude::Polite, + ) + .min(delivery_cost); + if !amount.is_zero() { + T::Token::transfer(&sovereign_account, &who, amount, Preservation::Preserve)?; + } // Decode message into XCM let (xcm, fee) = diff --git a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs index 39e9532ed32..c96c868bc26 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs @@ -4,11 +4,13 @@ use super::*; use frame_support::{ derive_impl, parameter_types, - traits::{ConstU128, ConstU32, Everything}, + traits::{ConstU32, Everything}, weights::IdentityFee, }; use hex_literal::hex; -use snowbridge_beacon_primitives::{Fork, ForkVersions}; +use snowbridge_beacon_primitives::{ + types::deneb, BeaconHeader, ExecutionProof, Fork, ForkVersions, VersionedExecutionPayloadHeader, +}; use snowbridge_core::{ gwei, inbound::{Log, Proof, VerificationError}, @@ -20,7 +22,7 @@ use sp_runtime::{ traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, BuildStorage, FixedU128, MultiSignature, }; -use sp_std::convert::From; +use sp_std::{convert::From, default::Default}; use xcm::{latest::SendXcm, prelude::*}; use xcm_executor::AssetsInHolding; @@ -65,6 +67,10 @@ impl frame_system::Config for Test { type Block = Block; } +parameter_types! { + pub const ExistentialDeposit: u128 = 1; +} + impl pallet_balances::Config for Test { type MaxLocks = (); type MaxReserves = (); @@ -72,7 +78,7 @@ impl pallet_balances::Config for Test { type Balance = Balance; type RuntimeEvent = RuntimeEvent; type DustRemoval = (); - type ExistentialDeposit = ConstU128<1>; + type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; type WeightInfo = (); type FreezeIdentifier = (); @@ -82,7 +88,6 @@ impl pallet_balances::Config for Test { } parameter_types! { - pub const ExecutionHeadersPruneThreshold: u32 = 10; pub const ChainForkVersions: ForkVersions = ForkVersions{ genesis: Fork { version: [0, 0, 0, 1], // 0x00000001 @@ -110,7 +115,6 @@ parameter_types! { impl snowbridge_pallet_ethereum_client::Config for Test { type RuntimeEvent = RuntimeEvent; type ForkVersions = ChainForkVersions; - type MaxExecutionHeadersToKeep = ExecutionHeadersPruneThreshold; type WeightInfo = (); } @@ -139,7 +143,7 @@ parameter_types! { #[cfg(feature = "runtime-benchmarks")] impl BenchmarkHelper for Test { // not implemented since the MockVerifier is used for tests - fn initialize_storage(_: H256, _: CompactExecutionHeader) {} + fn initialize_storage(_: BeaconHeader, _: H256) {} } // Mock XCM sender that always succeeds @@ -335,5 +339,32 @@ pub fn mock_event_log_invalid_gateway() -> Log { } } +pub fn mock_execution_proof() -> ExecutionProof { + ExecutionProof { + header: BeaconHeader::default(), + ancestry_proof: None, + execution_header: VersionedExecutionPayloadHeader::Deneb(deneb::ExecutionPayloadHeader { + parent_hash: Default::default(), + fee_recipient: Default::default(), + state_root: Default::default(), + receipts_root: Default::default(), + logs_bloom: vec![], + prev_randao: Default::default(), + block_number: 0, + gas_limit: 0, + gas_used: 0, + timestamp: 0, + extra_data: vec![], + base_fee_per_gas: Default::default(), + block_hash: Default::default(), + transactions_root: Default::default(), + withdrawals_root: Default::default(), + blob_gas_used: 0, + excess_blob_gas: 0, + }), + execution_branch: vec![], + } +} + pub const ASSET_HUB_PARAID: u32 = 1000u32; pub const TEMPLATE_PARAID: u32 = 1001u32; diff --git a/bridges/snowbridge/pallets/inbound-queue/src/test.rs b/bridges/snowbridge/pallets/inbound-queue/src/test.rs index 9a47e475b8c..bd993c968df 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/test.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/test.rs @@ -6,7 +6,7 @@ use frame_support::{assert_noop, assert_ok}; use hex_literal::hex; use snowbridge_core::{inbound::Proof, ChannelId}; use sp_keyring::AccountKeyring as Keyring; -use sp_runtime::{DispatchError, TokenError}; +use sp_runtime::DispatchError; use sp_std::convert::From; use crate::{Error, Event as InboundQueueEvent}; @@ -25,9 +25,8 @@ fn test_submit_happy_path() { let message = Message { event_log: mock_event_log(), proof: Proof { - block_hash: Default::default(), - tx_index: Default::default(), - data: Default::default(), + receipt_proof: Default::default(), + execution_proof: mock_execution_proof(), }, }; @@ -77,9 +76,8 @@ fn test_submit_xcm_invalid_channel() { let message = Message { event_log: mock_event_log_invalid_channel(), proof: Proof { - block_hash: Default::default(), - tx_index: Default::default(), - data: Default::default(), + receipt_proof: Default::default(), + execution_proof: mock_execution_proof(), }, }; assert_noop!( @@ -103,9 +101,8 @@ fn test_submit_with_invalid_gateway() { let message = Message { event_log: mock_event_log_invalid_gateway(), proof: Proof { - block_hash: Default::default(), - tx_index: Default::default(), - data: Default::default(), + receipt_proof: Default::default(), + execution_proof: mock_execution_proof(), }, }; assert_noop!( @@ -129,9 +126,8 @@ fn test_submit_with_invalid_nonce() { let message = Message { event_log: mock_event_log(), proof: Proof { - block_hash: Default::default(), - tx_index: Default::default(), - data: Default::default(), + receipt_proof: Default::default(), + execution_proof: mock_execution_proof(), }, }; assert_ok!(InboundQueue::submit(origin.clone(), message.clone())); @@ -150,12 +146,12 @@ fn test_submit_with_invalid_nonce() { } #[test] -fn test_submit_no_funds_to_reward_relayers() { +fn test_submit_no_funds_to_reward_relayers_just_ignore() { new_tester().execute_with(|| { let relayer: AccountId = Keyring::Bob.into(); let origin = RuntimeOrigin::signed(relayer); - // Reset balance of sovereign_account to zero so to trigger the FundsUnavailable error + // Reset balance of sovereign_account to zero first let sovereign_account = sibling_sovereign_account::(ASSET_HUB_PARAID.into()); Balances::set_balance(&sovereign_account, 0); @@ -163,15 +159,12 @@ fn test_submit_no_funds_to_reward_relayers() { let message = Message { event_log: mock_event_log(), proof: Proof { - block_hash: Default::default(), - tx_index: Default::default(), - data: Default::default(), + receipt_proof: Default::default(), + execution_proof: mock_execution_proof(), }, }; - assert_noop!( - InboundQueue::submit(origin.clone(), message.clone()), - TokenError::FundsUnavailable - ); + // Check submit successfully in case no funds available + assert_ok!(InboundQueue::submit(origin.clone(), message.clone())); }); } @@ -183,9 +176,8 @@ fn test_set_operating_mode() { let message = Message { event_log: mock_event_log(), proof: Proof { - block_hash: Default::default(), - tx_index: Default::default(), - data: Default::default(), + receipt_proof: Default::default(), + execution_proof: mock_execution_proof(), }, }; @@ -210,3 +202,44 @@ fn test_set_operating_mode_root_only() { ); }); } + +#[test] +fn test_submit_no_funds_to_reward_relayers_and_ed_preserved() { + new_tester().execute_with(|| { + let relayer: AccountId = Keyring::Bob.into(); + let origin = RuntimeOrigin::signed(relayer); + + // Reset balance of sovereign account to (ED+1) first + let sovereign_account = sibling_sovereign_account::(ASSET_HUB_PARAID.into()); + Balances::set_balance(&sovereign_account, ExistentialDeposit::get() + 1); + + // Submit message successfully + let message = Message { + event_log: mock_event_log(), + proof: Proof { + receipt_proof: Default::default(), + execution_proof: mock_execution_proof(), + }, + }; + assert_ok!(InboundQueue::submit(origin.clone(), message.clone())); + + // Check balance of sovereign account to ED + let amount = Balances::balance(&sovereign_account); + assert_eq!(amount, ExistentialDeposit::get()); + + // Submit another message with nonce set as 2 + let mut event_log = mock_event_log(); + event_log.data[31] = 2; + let message = Message { + event_log, + proof: Proof { + receipt_proof: Default::default(), + execution_proof: mock_execution_proof(), + }, + }; + assert_ok!(InboundQueue::submit(origin.clone(), message.clone())); + // Check balance of sovereign account as ED does not change + let amount = Balances::balance(&sovereign_account); + assert_eq!(amount, ExistentialDeposit::get()); + }); +} diff --git a/bridges/snowbridge/primitives/beacon/src/lib.rs b/bridges/snowbridge/primitives/beacon/src/lib.rs index 4c569d0176c..6579d0f6096 100644 --- a/bridges/snowbridge/primitives/beacon/src/lib.rs +++ b/bridges/snowbridge/primitives/beacon/src/lib.rs @@ -15,12 +15,12 @@ pub mod updates; mod serde_utils; pub use types::{ - BeaconHeader, CompactBeaconState, CompactExecutionHeader, ExecutionHeaderState, - ExecutionPayloadHeader, FinalizedHeaderState, Fork, ForkData, ForkVersion, ForkVersions, Mode, - PublicKey, Signature, SigningData, SyncAggregate, SyncCommittee, SyncCommitteePrepared, + AncestryProof, BeaconHeader, CompactBeaconState, ExecutionPayloadHeader, ExecutionProof, + FinalizedHeaderState, Fork, ForkData, ForkVersion, ForkVersions, Mode, PublicKey, Signature, + SigningData, SyncAggregate, SyncCommittee, SyncCommitteePrepared, VersionedExecutionPayloadHeader, }; -pub use updates::{CheckpointUpdate, ExecutionHeaderUpdate, NextSyncCommitteeUpdate, Update}; +pub use updates::{CheckpointUpdate, NextSyncCommitteeUpdate, Update}; pub use bits::decompress_sync_committee_bits; pub use bls::{ diff --git a/bridges/snowbridge/primitives/beacon/src/types.rs b/bridges/snowbridge/primitives/beacon/src/types.rs index 2af522f56b0..e12350510c9 100644 --- a/bridges/snowbridge/primitives/beacon/src/types.rs +++ b/bridges/snowbridge/primitives/beacon/src/types.rs @@ -110,14 +110,6 @@ impl<'de> Deserialize<'de> for Signature { } } -#[derive(Copy, Clone, Default, Encode, Decode, TypeInfo, MaxEncodedLen)] -pub struct ExecutionHeaderState { - pub beacon_block_root: H256, - pub beacon_slot: u64, - pub block_hash: H256, - pub block_number: u64, -} - #[derive(Copy, Clone, Default, Encode, Decode, TypeInfo, MaxEncodedLen)] pub struct FinalizedHeaderState { pub beacon_block_root: H256, @@ -346,35 +338,6 @@ impl ExecutionPayloadHeader { } } -#[derive( - Default, - Encode, - Decode, - CloneNoBound, - PartialEqNoBound, - RuntimeDebugNoBound, - TypeInfo, - MaxEncodedLen, -)] -pub struct CompactExecutionHeader { - pub parent_hash: H256, - #[codec(compact)] - pub block_number: u64, - pub state_root: H256, - pub receipts_root: H256, -} - -impl From for CompactExecutionHeader { - fn from(execution_payload: ExecutionPayloadHeader) -> Self { - Self { - parent_hash: execution_payload.parent_hash, - block_number: execution_payload.block_number, - state_root: execution_payload.state_root, - receipts_root: execution_payload.receipts_root, - } - } -} - #[derive( Default, Encode, @@ -405,18 +368,6 @@ pub enum VersionedExecutionPayloadHeader { Deneb(deneb::ExecutionPayloadHeader), } -/// Convert VersionedExecutionPayloadHeader to CompactExecutionHeader -impl From for CompactExecutionHeader { - fn from(versioned_execution_header: VersionedExecutionPayloadHeader) -> Self { - match versioned_execution_header { - VersionedExecutionPayloadHeader::Capella(execution_payload_header) => - execution_payload_header.into(), - VersionedExecutionPayloadHeader::Deneb(execution_payload_header) => - execution_payload_header.into(), - } - } -} - impl VersionedExecutionPayloadHeader { pub fn hash_tree_root(&self) -> Result { match self { @@ -448,6 +399,45 @@ impl VersionedExecutionPayloadHeader { execution_payload_header.block_number, } } + + pub fn receipts_root(&self) -> H256 { + match self { + VersionedExecutionPayloadHeader::Capella(execution_payload_header) => + execution_payload_header.receipts_root, + VersionedExecutionPayloadHeader::Deneb(execution_payload_header) => + execution_payload_header.receipts_root, + } + } +} + +#[derive(Encode, Decode, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo)] +#[cfg_attr( + feature = "std", + derive(serde::Deserialize), + serde(deny_unknown_fields, bound(serialize = ""), bound(deserialize = "")) +)] +pub struct ExecutionProof { + /// Header for the beacon block containing the execution payload + pub header: BeaconHeader, + /// Proof that `header` is an ancestor of a finalized header + pub ancestry_proof: Option, + /// The execution header to be verified + pub execution_header: VersionedExecutionPayloadHeader, + /// Merkle proof that execution payload is contained within `header` + pub execution_branch: Vec, +} + +#[derive(Encode, Decode, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo)] +#[cfg_attr( + feature = "std", + derive(serde::Deserialize), + serde(deny_unknown_fields, bound(serialize = ""), bound(deserialize = "")) +)] +pub struct AncestryProof { + /// Merkle proof that `header` is an ancestor of `finalized_header` + pub header_branch: Vec, + /// Root of a finalized block that has already been imported into the light client + pub finalized_block_root: H256, } #[cfg(test)] @@ -576,7 +566,6 @@ pub enum Mode { } pub mod deneb { - use crate::CompactExecutionHeader; use codec::{Decode, Encode}; use frame_support::{CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound}; use scale_info::TypeInfo; @@ -627,15 +616,4 @@ pub mod deneb { pub blob_gas_used: u64, // [New in Deneb:EIP4844] pub excess_blob_gas: u64, // [New in Deneb:EIP4844] } - - impl From for CompactExecutionHeader { - fn from(execution_payload: ExecutionPayloadHeader) -> Self { - Self { - parent_hash: execution_payload.parent_hash, - block_number: execution_payload.block_number, - state_root: execution_payload.state_root, - receipts_root: execution_payload.receipts_root, - } - } - } } diff --git a/bridges/snowbridge/primitives/beacon/src/updates.rs b/bridges/snowbridge/primitives/beacon/src/updates.rs index 1ecd32c6d7b..ca651b5806f 100644 --- a/bridges/snowbridge/primitives/beacon/src/updates.rs +++ b/bridges/snowbridge/primitives/beacon/src/updates.rs @@ -6,7 +6,7 @@ use scale_info::TypeInfo; use sp_core::H256; use sp_std::prelude::*; -use crate::types::{BeaconHeader, SyncAggregate, SyncCommittee, VersionedExecutionPayloadHeader}; +use crate::types::{BeaconHeader, SyncAggregate, SyncCommittee}; #[derive(Encode, Decode, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo)] #[cfg_attr( @@ -23,26 +23,13 @@ pub struct CheckpointUpdate { pub block_roots_branch: Vec, } -impl Default for CheckpointUpdate { - fn default() -> Self { - CheckpointUpdate { - header: Default::default(), - current_sync_committee: Default::default(), - current_sync_committee_branch: Default::default(), - validators_root: Default::default(), - block_roots_root: Default::default(), - block_roots_branch: Default::default(), - } - } -} - #[derive( Default, Encode, Decode, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo, )] #[cfg_attr( feature = "std", derive(serde::Deserialize), - serde(deny_unknown_fields, bound(serialize = ""), bound(deserialize = "")) + serde(bound(serialize = ""), bound(deserialize = "")) )] pub struct Update { /// A recent header attesting to the finalized header, using its `state_root`. @@ -78,33 +65,3 @@ pub struct NextSyncCommitteeUpdate { pub next_sync_committee: SyncCommittee, pub next_sync_committee_branch: Vec, } - -#[derive(Encode, Decode, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo)] -#[cfg_attr( - feature = "std", - derive(serde::Deserialize), - serde(deny_unknown_fields, bound(serialize = ""), bound(deserialize = "")) -)] -pub struct ExecutionHeaderUpdate { - /// Header for the beacon block containing the execution payload - pub header: BeaconHeader, - /// Proof that `header` is an ancestor of a finalized header - pub ancestry_proof: Option, - /// Execution header to be imported - pub execution_header: VersionedExecutionPayloadHeader, - /// Merkle proof that execution payload is contained within `header` - pub execution_branch: Vec, -} - -#[derive(Encode, Decode, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo)] -#[cfg_attr( - feature = "std", - derive(serde::Deserialize), - serde(deny_unknown_fields, bound(serialize = ""), bound(deserialize = "")) -)] -pub struct AncestryProof { - /// Merkle proof that `header` is an ancestor of `finalized_header` - pub header_branch: Vec, - /// Root of a finalized block that has already been imported into the light client - pub finalized_block_root: H256, -} diff --git a/bridges/snowbridge/primitives/core/src/inbound.rs b/bridges/snowbridge/primitives/core/src/inbound.rs index 4b04470ad02..9e8ed789ab5 100644 --- a/bridges/snowbridge/primitives/core/src/inbound.rs +++ b/bridges/snowbridge/primitives/core/src/inbound.rs @@ -5,6 +5,7 @@ use codec::{Decode, Encode}; use frame_support::PalletError; use scale_info::TypeInfo; +use snowbridge_beacon_primitives::{BeaconHeader, ExecutionProof}; use sp_core::{H160, H256}; use sp_runtime::RuntimeDebug; use sp_std::vec::Vec; @@ -25,6 +26,8 @@ pub enum VerificationError { InvalidLog, /// Unable to verify the transaction receipt with the provided proof InvalidProof, + /// Unable to verify the execution header with ancestry proof + InvalidExecutionProof(#[codec(skip)] &'static str), } pub type MessageNonce = u64; @@ -65,10 +68,15 @@ impl Log { /// Inclusion proof for a transaction receipt #[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)] pub struct Proof { - // The block hash of the block in which the receipt was included. - pub block_hash: H256, - // The index of the transaction (and receipt) within the block. - pub tx_index: u32, // Proof keys and values (receipts tree) - pub data: (Vec>, Vec>), + pub receipt_proof: (Vec>, Vec>), + // Proof that an execution header was finalized by the beacon chain + pub execution_proof: ExecutionProof, +} + +#[derive(Clone, RuntimeDebug)] +pub struct InboundQueueFixture { + pub message: Message, + pub finalized_header: BeaconHeader, + pub block_roots_root: H256, } diff --git a/bridges/snowbridge/runtime/test-common/src/lib.rs b/bridges/snowbridge/runtime/test-common/src/lib.rs index 7455adf7617..3e2de0e481b 100644 --- a/bridges/snowbridge/runtime/test-common/src/lib.rs +++ b/bridges/snowbridge/runtime/test-common/src/lib.rs @@ -467,7 +467,6 @@ pub fn ethereum_extrinsic( let initial_checkpoint = make_checkpoint(); let update = make_finalized_header_update(); let sync_committee_update = make_sync_committee_update(); - let execution_header_update = make_execution_header_update(); let alice = Alice; let alice_account = alice.to_account_id(); @@ -494,22 +493,12 @@ pub fn ethereum_extrinsic( } .into(); - let execution_header_call: ::RuntimeCall = - snowbridge_pallet_ethereum_client::Call::::submit_execution_header { - update: Box::new(*execution_header_update), - } - .into(); - let update_outcome = construct_and_apply_extrinsic(alice, update_call.into()); assert_ok!(update_outcome); let sync_committee_outcome = construct_and_apply_extrinsic(alice, update_sync_committee_call.into()); assert_ok!(sync_committee_outcome); - - let execution_header_outcome = - construct_and_apply_extrinsic(alice, execution_header_call.into()); - assert_ok!(execution_header_outcome); }); } @@ -548,7 +537,6 @@ pub fn ethereum_to_polkadot_message_extrinsics_work( .execute_with(|| { let initial_checkpoint = make_checkpoint(); let sync_committee_update = make_sync_committee_update(); - let execution_header_update = make_execution_header_update(); let alice = Alice; let alice_account = alice.to_account_id(); @@ -569,18 +557,8 @@ pub fn ethereum_to_polkadot_message_extrinsics_work( } .into(); - let execution_header_call: ::RuntimeCall = - snowbridge_pallet_ethereum_client::Call::::submit_execution_header { - update: Box::new(*execution_header_update), - } - .into(); - let sync_committee_outcome = construct_and_apply_extrinsic(alice, update_sync_committee_call.into()); assert_ok!(sync_committee_outcome); - - let execution_header_outcome = - construct_and_apply_extrinsic(alice, execution_header_call.into()); - assert_ok!(execution_header_outcome); }); } diff --git a/bridges/snowbridge/scripts/contribute-upstream.sh b/bridges/snowbridge/scripts/contribute-upstream.sh index 32005b770ec..529057c3f26 100755 --- a/bridges/snowbridge/scripts/contribute-upstream.sh +++ b/bridges/snowbridge/scripts/contribute-upstream.sh @@ -79,4 +79,10 @@ git fetch parity master git checkout parity/master -- .github git add -- .github +git commit -m "cleanup branch" + +# Fetch the latest from parity master +echo "Fetching latest from Parity master. Resolve merge conflicts, if there are any." +git fetch parity master +git merge parity/master echo "OK" diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs index 1804f9d4b67..780ba57f78a 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs @@ -20,17 +20,17 @@ use frame_support::pallet_prelude::TypeInfo; use hex_literal::hex; use rococo_system_emulated_network::penpal_emulated_chain::CustomizableAssetFromSystemAssetHub; use rococo_westend_system_emulated_network::BridgeHubRococoParaSender as BridgeHubRococoSender; -use snowbridge_core::outbound::OperatingMode; +use snowbridge_core::{inbound::InboundQueueFixture, outbound::OperatingMode}; use snowbridge_pallet_inbound_queue_fixtures::{ - register_token::make_register_token_message, - register_token_with_insufficient_fee::make_register_token_with_insufficient_fee_message, - send_token::make_send_token_message, send_token_to_penpal::make_send_token_to_penpal_message, - InboundQueueFixture, + register_token::make_register_token_message, send_token::make_send_token_message, + send_token_to_penpal::make_send_token_to_penpal_message, }; use snowbridge_pallet_system; -use snowbridge_router_primitives::inbound::GlobalConsensusEthereumConvertsFor; +use snowbridge_router_primitives::inbound::{ + Command, GlobalConsensusEthereumConvertsFor, MessageV1, VersionedMessage, +}; use sp_core::H256; -use sp_runtime::{ArithmeticError::Underflow, DispatchError::Arithmetic}; +use sp_runtime::{DispatchError::Token, TokenError::FundsUnavailable}; use testnet_parachains_constants::rococo::snowbridge::EthereumNetwork; const INITIAL_FUND: u128 = 5_000_000_000 * ROCOCO_ED; @@ -39,6 +39,7 @@ const TREASURY_ACCOUNT: [u8; 32] = hex!("6d6f646c70792f74727372790000000000000000000000000000000000000000"); const WETH: [u8; 20] = hex!("87d1f7fdfEe7f651FaBc8bFCB6E086C278b77A7d"); const ETHEREUM_DESTINATION_ADDRESS: [u8; 20] = hex!("44a57ee2f2FCcb85FDa2B0B18EBD0D8D2333700e"); +const INSUFFICIENT_XCM_FEE: u128 = 1000; #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] pub enum ControlCall { @@ -56,13 +57,11 @@ pub enum SnowbridgeControl { } pub fn send_inbound_message(fixture: InboundQueueFixture) -> DispatchResult { - EthereumBeaconClient::store_execution_header( - fixture.message.proof.block_hash, - fixture.execution_header, - 0, - H256::default(), - ); - + EthereumBeaconClient::store_finalized_header( + fixture.finalized_header, + fixture.block_roots_root, + ) + .unwrap(); EthereumInboundQueue::submit( RuntimeOrigin::signed(BridgeHubRococoSender::get()), fixture.message, @@ -237,6 +236,46 @@ fn register_weth_token_from_ethereum_to_asset_hub() { }); } +/// Tests the registering of a token as an asset on AssetHub, and then subsequently sending +/// a token from Ethereum to AssetHub. +#[test] +fn send_token_from_ethereum_to_asset_hub() { + BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id().into(), INITIAL_FUND); + + // Fund ethereum sovereign on AssetHub + AssetHubRococo::fund_accounts(vec![(AssetHubRococoReceiver::get(), INITIAL_FUND)]); + + BridgeHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + // Construct RegisterToken message and sent to inbound queue + send_inbound_message(make_register_token_message()).unwrap(); + + // Construct SendToken message and sent to inbound queue + send_inbound_message(make_send_token_message()).unwrap(); + + // Check that the message was sent + assert_expected_events!( + BridgeHubRococo, + vec![ + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, + ] + ); + }); + + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + // Check that the token was received and issued as a foreign asset on AssetHub + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {}, + ] + ); + }); +} + /// Tests sending a token to a 3rd party parachain, called PenPal. The token reserve is /// still located on AssetHub. #[test] @@ -296,6 +335,10 @@ fn send_token_from_ethereum_to_penpal() { // Construct RegisterToken message and sent to inbound queue send_inbound_message(make_register_token_message()).unwrap(); + // Construct SendToken message to AssetHub(only for increase the nonce as the same order in + // smoke test) + send_inbound_message(make_send_token_message()).unwrap(); + // Construct SendToken message and sent to inbound queue send_inbound_message(make_send_token_to_penpal_message()).unwrap(); @@ -331,46 +374,6 @@ fn send_token_from_ethereum_to_penpal() { }); } -/// Tests the registering of a token as an asset on AssetHub, and then subsequently sending -/// a token from Ethereum to AssetHub. -#[test] -fn send_token_from_ethereum_to_asset_hub() { - BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id().into(), INITIAL_FUND); - - // Fund ethereum sovereign on AssetHub - AssetHubRococo::fund_accounts(vec![(AssetHubRococoReceiver::get(), INITIAL_FUND)]); - - BridgeHubRococo::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - // Construct RegisterToken message and sent to inbound queue - send_inbound_message(make_register_token_message()).unwrap(); - - // Construct SendToken message and sent to inbound queue - send_inbound_message(make_send_token_message()).unwrap(); - - // Check that the message was sent - assert_expected_events!( - BridgeHubRococo, - vec![ - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, - ] - ); - }); - - AssetHubRococo::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - // Check that the token was received and issued as a foreign asset on AssetHub - assert_expected_events!( - AssetHubRococo, - vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {}, - ] - ); - }); -} - /// Tests the full cycle of token transfers: /// - registering a token on AssetHub /// - sending a token to AssetHub @@ -507,16 +510,35 @@ fn send_weth_asset_from_asset_hub_to_ethereum() { }); } +#[test] +fn send_token_from_ethereum_to_asset_hub_fail_for_insufficient_fund() { + // Insufficient fund + BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id().into(), 1_000); + + BridgeHubRococo::execute_with(|| { + assert_err!(send_inbound_message(make_register_token_message()), Token(FundsUnavailable)); + }); +} + #[test] fn register_weth_token_in_asset_hub_fail_for_insufficient_fee() { BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id().into(), INITIAL_FUND); BridgeHubRococo::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; - - // Construct RegisterToken message and sent to inbound queue - let message = make_register_token_with_insufficient_fee_message(); - send_inbound_message(message).unwrap(); + type EthereumInboundQueue = + ::EthereumInboundQueue; + let message_id: H256 = [0; 32].into(); + let message = VersionedMessage::V1(MessageV1 { + chain_id: CHAIN_ID, + command: Command::RegisterToken { + token: WETH.into(), + // Insufficient fee which should trigger the trap + fee: INSUFFICIENT_XCM_FEE, + }, + }); + let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); + let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubRococo::para_id().into()).unwrap(); assert_expected_events!( BridgeHubRococo, @@ -537,13 +559,3 @@ fn register_weth_token_in_asset_hub_fail_for_insufficient_fee() { ); }); } - -#[test] -fn send_token_from_ethereum_to_asset_hub_fail_for_insufficient_fund() { - // Insufficient fund - BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id().into(), 1_000); - - BridgeHubRococo::execute_with(|| { - assert_err!(send_inbound_message(make_register_token_message()), Arithmetic(Underflow)); - }); -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index 47c3ed36888..f4ff985e277 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -286,8 +286,8 @@ impl Contains for SafeCallFilter { match call { RuntimeCall::System(frame_system::Call::set_storage { items }) if items.iter().all(|(k, _)| { - k.eq(&bridging::XcmBridgeHubRouterByteFee::key()) | - k.eq(&bridging::XcmBridgeHubRouterBaseFee::key()) | + k.eq(&bridging::XcmBridgeHubRouterByteFee::key()) || + k.eq(&bridging::XcmBridgeHubRouterBaseFee::key()) || k.eq(&bridging::to_ethereum::BridgeHubEthereumBaseFee::key()) }) => return true, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index f0aa4f8e91c..fd6d44ec275 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -100,8 +100,6 @@ use parachains_common::{ AVERAGE_ON_INITIALIZE_RATIO, NORMAL_DISPATCH_RATIO, }; -use polkadot_runtime_common::prod_or_fast; - #[cfg(feature = "runtime-benchmarks")] use benchmark_helpers::DoNothingRouter; @@ -515,14 +513,14 @@ parameter_types! { pub mod benchmark_helpers { use crate::{EthereumBeaconClient, Runtime, RuntimeOrigin}; use codec::Encode; - use snowbridge_beacon_primitives::CompactExecutionHeader; + use snowbridge_beacon_primitives::BeaconHeader; use snowbridge_pallet_inbound_queue::BenchmarkHelper; use sp_core::H256; use xcm::latest::{Assets, Location, SendError, SendResult, SendXcm, Xcm, XcmHash}; impl BenchmarkHelper for Runtime { - fn initialize_storage(block_hash: H256, header: CompactExecutionHeader) { - EthereumBeaconClient::store_execution_header(block_hash, header, 0, H256::default()) + fn initialize_storage(beacon_header: BeaconHeader, block_roots_root: H256) { + EthereumBeaconClient::store_finalized_header(beacon_header, block_roots_root).unwrap(); } } @@ -643,14 +641,9 @@ parameter_types! { }; } -parameter_types! { - pub const MaxExecutionHeadersToKeep: u32 = prod_or_fast!(8192 * 2, 1000); -} - impl snowbridge_pallet_ethereum_client::Config for Runtime { type RuntimeEvent = RuntimeEvent; type ForkVersions = ChainForkVersions; - type MaxExecutionHeadersToKeep = MaxExecutionHeadersToKeep; type WeightInfo = weights::snowbridge_pallet_ethereum_client::WeightInfo; } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_ethereum_client.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_ethereum_client.rs index 0d5f29c6ff2..c8017939b62 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_ethereum_client.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_ethereum_client.rs @@ -126,26 +126,4 @@ impl snowbridge_pallet_ethereum_client::WeightInfo for .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: EthereumBeaconClient LatestFinalizedBlockRoot (r:1 w:0) - /// Proof: EthereumBeaconClient LatestFinalizedBlockRoot (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: EthereumBeaconClient FinalizedBeaconState (r:1 w:0) - /// Proof: EthereumBeaconClient FinalizedBeaconState (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: EthereumBeaconClient LatestExecutionState (r:1 w:1) - /// Proof: EthereumBeaconClient LatestExecutionState (max_values: Some(1), max_size: Some(80), added: 575, mode: MaxEncodedLen) - /// Storage: EthereumBeaconClient ExecutionHeaderIndex (r:1 w:1) - /// Proof: EthereumBeaconClient ExecutionHeaderIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: EthereumBeaconClient ExecutionHeaderMapping (r:1 w:1) - /// Proof: EthereumBeaconClient ExecutionHeaderMapping (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) - /// Storage: EthereumBeaconClient ExecutionHeaders (r:0 w:1) - /// Proof: EthereumBeaconClient ExecutionHeaders (max_values: None, max_size: Some(136), added: 2611, mode: MaxEncodedLen) - fn submit_execution_header() -> Weight { - // Proof Size summary in bytes: - // Measured: `386` - // Estimated: `3537` - // Minimum execution time: 108_761_000 picoseconds. - Weight::from_parts(113_158_000, 0) - .saturating_add(Weight::from_parts(0, 3537)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) - } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_inbound_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_inbound_queue.rs index faf404f90cb..153c1d363be 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_inbound_queue.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_inbound_queue.rs @@ -58,12 +58,12 @@ impl snowbridge_pallet_inbound_queue::WeightInfo for We /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn submit() -> Weight { // Proof Size summary in bytes: - // Measured: `457` - // Estimated: `3601` - // Minimum execution time: 69_000_000 picoseconds. - Weight::from_parts(70_000_000, 0) - .saturating_add(Weight::from_parts(0, 3601)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `800` + // Estimated: `7200` + // Minimum execution time: 200_000_000 picoseconds. + Weight::from_parts(200_000_000, 0) + .saturating_add(Weight::from_parts(0, 7200)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(6)) } } diff --git a/prdoc/pr_3761.prdoc b/prdoc/pr_3761.prdoc new file mode 100644 index 00000000000..65b8c396fe3 --- /dev/null +++ b/prdoc/pr_3761.prdoc @@ -0,0 +1,25 @@ +title: "Snowbridge: Synchronize from Snowfork repository" + +doc: + - audience: Runtime Dev + description: | + This PR improves the beacon client to send the execution header along with the message as proof and removes the verification and storing of all execution headers. + If the AH sovereign account is depleted and relayer rewards cannot be paid, the message should still be processed. + +crates: +- name: snowbridge-pallet-ethereum-client + bump: minor +- name: snowbridge-pallet-inbound-queue + bump: minor +- name: snowbridge-beacon-primitives + bump: minor +- name: snowbridge-core + bump: minor +- name: snowbridge-runtime-test-common + bump: minor +- name: asset-hub-rococo-runtime + bump: minor +- name: bridge-hub-rococo-runtime + bump: minor +- name: bridge-hub-rococo-integration-tests + bump: minor -- GitLab From 0becc45bd826aea6ec128da8525ed73b3657d474 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Tue, 2 Apr 2024 18:06:01 +0200 Subject: [PATCH 151/187] sp_runtime: TryFrom for &str (#3942) Added `TryFrom<&'a RuntimeString> for &'a str` --- substrate/primitives/runtime/src/runtime_string.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/substrate/primitives/runtime/src/runtime_string.rs b/substrate/primitives/runtime/src/runtime_string.rs index aa0bd52e56f..607ae59db63 100644 --- a/substrate/primitives/runtime/src/runtime_string.rs +++ b/substrate/primitives/runtime/src/runtime_string.rs @@ -61,6 +61,19 @@ impl From<&'static str> for RuntimeString { } } +impl<'a> TryFrom<&'a RuntimeString> for &'a str { + type Error = core::str::Utf8Error; + fn try_from(from: &'a RuntimeString) -> core::result::Result<&'a str, Self::Error> { + match from { + #[cfg(feature = "std")] + RuntimeString::Owned(string) => Ok(string.as_str()), + #[cfg(not(feature = "std"))] + RuntimeString::Owned(vec) => core::str::from_utf8(&vec), + RuntimeString::Borrowed(str) => Ok(str), + } + } +} + #[cfg(feature = "std")] impl From for String { fn from(string: RuntimeString) -> Self { -- GitLab From f88190a5201954bd0f5e7802050e5db2b2370159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Pa=C4=8Dandi?= <3002868+Dinonard@users.noreply.github.com> Date: Tue, 2 Apr 2024 21:08:02 +0200 Subject: [PATCH 152/187] SortedMembers::add for pallet-membership benchmarks (#3729) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds implementation for `SortedMembers::add` for _pallet-membership_ benchmarks. --------- Co-authored-by: Bastian Köcher Co-authored-by: command-bot <> --- substrate/frame/membership/src/lib.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/substrate/frame/membership/src/lib.rs b/substrate/frame/membership/src/lib.rs index 426fc985a52..aa6be6497ee 100644 --- a/substrate/frame/membership/src/lib.rs +++ b/substrate/frame/membership/src/lib.rs @@ -369,6 +369,18 @@ impl, I: 'static> SortedMembers for Pallet { fn count() -> usize { Members::::decode_len().unwrap_or(0) } + + #[cfg(feature = "runtime-benchmarks")] + fn add(new_member: &T::AccountId) { + use frame_support::{assert_ok, traits::EnsureOrigin}; + let new_member_lookup = T::Lookup::unlookup(new_member.clone()); + + if let Ok(origin) = T::AddOrigin::try_successful_origin() { + assert_ok!(Pallet::::add_member(origin, new_member_lookup,)); + } else { + log::error!(target: LOG_TARGET, "Failed to add `{new_member:?}` in `SortedMembers::add`.") + } + } } #[cfg(feature = "runtime-benchmarks")] -- GitLab From 665e3654ceca5a34e8ada66a9805fa7b76fc9ebb Mon Sep 17 00:00:00 2001 From: Andrei Eres Date: Tue, 2 Apr 2024 21:27:11 +0200 Subject: [PATCH 153/187] Remove nextest filtration (#3885) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/paritytech/polkadot-sdk/issues/3884#issuecomment-2026058687 After moving regression tests to benchmarks (https://github.com/paritytech/polkadot-sdk/pull/3741) we don't need to filter tests anymore. --------- Signed-off-by: Alexandru Vasile Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Co-authored-by: Alin Dima Co-authored-by: Andrei Sandu Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Javier Viola <363911+pepoviola@users.noreply.github.com> Co-authored-by: Serban Iorga Co-authored-by: Adrian Catangiu Co-authored-by: Bastian Köcher Co-authored-by: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Co-authored-by: Niklas Adolfsson Co-authored-by: Dastan <88332432+dastansam@users.noreply.github.com> Co-authored-by: Liam Aharon Co-authored-by: Clara van Staden Co-authored-by: Ron Co-authored-by: Vincent Geddes Co-authored-by: Svyatoslav Nikolsky Co-authored-by: Bastian Köcher --- .gitlab/pipeline/test.yml | 3 +-- substrate/frame/core-fellowship/src/benchmarking.rs | 5 +++++ substrate/frame/core-fellowship/src/lib.rs | 3 ++- substrate/frame/scheduler/src/tests.rs | 5 ++++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index af261a893da..48c84b472b4 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -25,7 +25,6 @@ test-linux-stable: # "upgrade_version_checks_should_work" is currently failing - | time cargo nextest run \ - --filter-expr 'not deps(/polkadot-subsystem-bench/)' \ --workspace \ --locked \ --release \ @@ -70,7 +69,7 @@ test-linux-stable-runtime-benchmarks: # but still want to have debug assertions. RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" script: - - time cargo nextest run --filter-expr 'not deps(/polkadot-subsystem-bench/)' --workspace --features runtime-benchmarks benchmark --locked --cargo-profile testnet + - time cargo nextest run --workspace --features runtime-benchmarks benchmark --locked --cargo-profile testnet # can be used to run all tests # test-linux-stable-all: diff --git a/substrate/frame/core-fellowship/src/benchmarking.rs b/substrate/frame/core-fellowship/src/benchmarking.rs index ddde70bd7ce..fd5453310be 100644 --- a/substrate/frame/core-fellowship/src/benchmarking.rs +++ b/substrate/frame/core-fellowship/src/benchmarking.rs @@ -149,6 +149,11 @@ mod benchmarks { #[benchmark] fn promote() -> Result<(), BenchmarkError> { + // Ensure that the `min_promotion_period` wont get in our way. + let mut params = Params::::get(); + params.min_promotion_period = [Zero::zero(); RANK_COUNT]; + Params::::put(¶ms); + let member = make_member::(1)?; ensure_evidence::(&member)?; diff --git a/substrate/frame/core-fellowship/src/lib.rs b/substrate/frame/core-fellowship/src/lib.rs index d1b81c3ca13..afb188261fd 100644 --- a/substrate/frame/core-fellowship/src/lib.rs +++ b/substrate/frame/core-fellowship/src/lib.rs @@ -149,7 +149,8 @@ pub mod pallet { }; use frame_system::{ensure_root, pallet_prelude::*}; - const RANK_COUNT: usize = 9; + /// Number of available ranks. + pub(crate) const RANK_COUNT: usize = 9; #[pallet::pallet] pub struct Pallet(PhantomData<(T, I)>); diff --git a/substrate/frame/scheduler/src/tests.rs b/substrate/frame/scheduler/src/tests.rs index f251dde99a8..3023a370a4b 100644 --- a/substrate/frame/scheduler/src/tests.rs +++ b/substrate/frame/scheduler/src/tests.rs @@ -1501,8 +1501,11 @@ fn scheduler_handles_periodic_unavailable_preimage() { run_to_block(4); assert_eq!(logger::log().len(), 1); - // Unnote the preimage + // As the public api doesn't support to remove a noted preimage, we need to first unnote it + // and then request it again. Basically this should not happen in real life (whatever you + // call real life;). Preimage::unnote(&hash); + Preimage::request(&hash); // Does not ever execute again. run_to_block(100); -- GitLab From e8e201f0ffc657d227ab869a778e37a876af2666 Mon Sep 17 00:00:00 2001 From: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Date: Wed, 3 Apr 2024 11:34:50 +0300 Subject: [PATCH 154/187] statement-distribution: fix filtering of statements for elastic parachains (#3879) fixes https://github.com/paritytech/polkadot-sdk/issues/3775 Additionally moves the claim queue fetch utilities into `subsystem-util`. TODO: - [x] fix tests - [x] add elastic scaling tests --------- Signed-off-by: Andrei Sandu --- .../node/collation-generation/src/error.rs | 2 + polkadot/node/collation-generation/src/lib.rs | 54 ++------ .../node/collation-generation/src/tests.rs | 15 +- .../statement-distribution/src/error.rs | 3 + .../statement-distribution/src/v2/mod.rs | 131 +++++++++++++----- .../src/v2/tests/cluster.rs | 60 ++++++++ .../src/v2/tests/grid.rs | 23 ++- .../src/v2/tests/mod.rs | 29 +++- polkadot/node/subsystem-util/src/vstaging.rs | 46 +++++- 9 files changed, 265 insertions(+), 98 deletions(-) diff --git a/polkadot/node/collation-generation/src/error.rs b/polkadot/node/collation-generation/src/error.rs index 852c50f3068..f04e3c4f20b 100644 --- a/polkadot/node/collation-generation/src/error.rs +++ b/polkadot/node/collation-generation/src/error.rs @@ -27,6 +27,8 @@ pub enum Error { #[error(transparent)] Util(#[from] polkadot_node_subsystem_util::Error), #[error(transparent)] + UtilRuntime(#[from] polkadot_node_subsystem_util::runtime::Error), + #[error(transparent)] Erasure(#[from] polkadot_erasure_coding::Error), #[error("Parachain backing state not available in runtime.")] MissingParaBackingState, diff --git a/polkadot/node/collation-generation/src/lib.rs b/polkadot/node/collation-generation/src/lib.rs index 3164f6078bc..fb82871bb15 100644 --- a/polkadot/node/collation-generation/src/lib.rs +++ b/polkadot/node/collation-generation/src/lib.rs @@ -38,25 +38,23 @@ use polkadot_node_primitives::{ SubmitCollationParams, }; use polkadot_node_subsystem::{ - messages::{CollationGenerationMessage, CollatorProtocolMessage, RuntimeApiRequest}, + messages::{CollationGenerationMessage, CollatorProtocolMessage}, overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, RuntimeApiError, SpawnedSubsystem, SubsystemContext, SubsystemError, SubsystemResult, }; use polkadot_node_subsystem_util::{ - has_required_runtime, request_async_backing_params, request_availability_cores, - request_claim_queue, request_para_backing_state, request_persisted_validation_data, - request_validation_code, request_validation_code_hash, request_validators, + request_async_backing_params, request_availability_cores, request_para_backing_state, + request_persisted_validation_data, request_validation_code, request_validation_code_hash, + request_validators, + vstaging::{fetch_claim_queue, fetch_next_scheduled_on_core}, }; use polkadot_primitives::{ collator_signature_payload, CandidateCommitments, CandidateDescriptor, CandidateReceipt, CollatorPair, CoreIndex, CoreState, Hash, Id as ParaId, OccupiedCoreAssumption, - PersistedValidationData, ScheduledCore, ValidationCodeHash, + PersistedValidationData, ValidationCodeHash, }; use sp_core::crypto::Pair; -use std::{ - collections::{BTreeMap, VecDeque}, - sync::Arc, -}; +use std::sync::Arc; mod error; @@ -228,7 +226,9 @@ async fn handle_new_activations( let availability_cores = availability_cores??; let async_backing_params = async_backing_params?.ok(); let n_validators = validators??.len(); - let maybe_claim_queue = fetch_claim_queue(ctx.sender(), relay_parent).await?; + let maybe_claim_queue = fetch_claim_queue(ctx.sender(), relay_parent) + .await + .map_err(crate::error::Error::UtilRuntime)?; // The loop bellow will fill in cores that the para is allowed to build on. let mut cores_to_build_on = Vec::new(); @@ -655,37 +655,3 @@ fn erasure_root( let chunks = polkadot_erasure_coding::obtain_chunks_v1(n_validators, &available_data)?; Ok(polkadot_erasure_coding::branches(&chunks).root()) } - -// Checks if the runtime supports `request_claim_queue` and executes it. Returns `Ok(None)` -// otherwise. Any [`RuntimeApiError`]s are bubbled up to the caller. -async fn fetch_claim_queue( - sender: &mut impl overseer::CollationGenerationSenderTrait, - relay_parent: Hash, -) -> crate::error::Result>>> { - if has_required_runtime( - sender, - relay_parent, - RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT, - ) - .await - { - let res = request_claim_queue(relay_parent, sender).await.await??; - Ok(Some(res)) - } else { - gum::trace!(target: LOG_TARGET, "Runtime doesn't support `request_claim_queue`"); - Ok(None) - } -} - -// Returns the next scheduled `ParaId` for a core in the claim queue, wrapped in `ScheduledCore`. -// This function is supposed to be used in `handle_new_activations` hence the return type. -fn fetch_next_scheduled_on_core( - claim_queue: &BTreeMap>, - core_idx: CoreIndex, -) -> Option { - claim_queue - .get(&core_idx)? - .front() - .cloned() - .map(|para_id| ScheduledCore { para_id, collator: None }) -} diff --git a/polkadot/node/collation-generation/src/tests.rs b/polkadot/node/collation-generation/src/tests.rs index 923a21e86fb..781d27188df 100644 --- a/polkadot/node/collation-generation/src/tests.rs +++ b/polkadot/node/collation-generation/src/tests.rs @@ -28,7 +28,7 @@ use polkadot_node_subsystem::{ ActivatedLeaf, }; use polkadot_node_subsystem_test_helpers::{subsystem_test_harness, TestSubsystemContextHandle}; -use polkadot_node_subsystem_util::TimeoutExt; +use polkadot_node_subsystem_util::{vstaging::ClaimQueueSnapshot, TimeoutExt}; use polkadot_primitives::{ async_backing::{BackingState, CandidatePendingAvailability}, AsyncBackingParams, BlockNumber, CollatorPair, HeadData, PersistedValidationData, @@ -36,7 +36,10 @@ use polkadot_primitives::{ }; use rstest::rstest; use sp_keyring::sr25519::Keyring as Sr25519Keyring; -use std::pin::Pin; +use std::{ + collections::{BTreeMap, VecDeque}, + pin::Pin, +}; use test_helpers::{ dummy_candidate_descriptor, dummy_hash, dummy_head_data, dummy_validator, make_candidate, }; @@ -617,7 +620,7 @@ fn fallback_when_no_validation_code_hash_api(#[case] runtime_version: u32) { _hash, RuntimeApiRequest::ClaimQueue(tx), ))) if runtime_version >= RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT => { - let res = BTreeMap::>::new(); + let res = ClaimQueueSnapshot::new(); tx.send(Ok(res)).unwrap(); }, Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( @@ -780,7 +783,7 @@ fn distribute_collation_for_occupied_core_with_async_backing_enabled(#[case] run candidate_hash: Default::default(), candidate_descriptor: dummy_candidate_descriptor(dummy_hash()), })]; - let claim_queue = BTreeMap::from([(CoreIndex::from(0), VecDeque::from([para_id]))]); + let claim_queue = ClaimQueueSnapshot::from([(CoreIndex::from(0), VecDeque::from([para_id]))]); test_harness(|mut virtual_overseer| async move { helpers::initialize_collator(&mut virtual_overseer, para_id).await; @@ -962,7 +965,7 @@ fn no_collation_is_distributed_for_occupied_core_with_async_backing_disabled( candidate_hash: Default::default(), candidate_descriptor: dummy_candidate_descriptor(dummy_hash()), })]; - let claim_queue = BTreeMap::from([(CoreIndex::from(0), VecDeque::from([para_id]))]); + let claim_queue = ClaimQueueSnapshot::from([(CoreIndex::from(0), VecDeque::from([para_id]))]); test_harness(|mut virtual_overseer| async move { helpers::initialize_collator(&mut virtual_overseer, para_id).await; @@ -1050,7 +1053,7 @@ mod helpers { async_backing_params: AsyncBackingParams, cores: Vec, runtime_version: u32, - claim_queue: BTreeMap>, + claim_queue: ClaimQueueSnapshot, ) { assert_matches!( overseer_recv(virtual_overseer).await, diff --git a/polkadot/node/network/statement-distribution/src/error.rs b/polkadot/node/network/statement-distribution/src/error.rs index a712ab6da43..d7f52162fe2 100644 --- a/polkadot/node/network/statement-distribution/src/error.rs +++ b/polkadot/node/network/statement-distribution/src/error.rs @@ -81,6 +81,9 @@ pub enum Error { #[error("Fetching validator groups failed {0:?}")] FetchValidatorGroups(RuntimeApiError), + #[error("Fetching claim queue failed {0:?}")] + FetchClaimQueue(runtime::Error), + #[error("Attempted to share statement when not a validator or not assigned")] InvalidShare, diff --git a/polkadot/node/network/statement-distribution/src/v2/mod.rs b/polkadot/node/network/statement-distribution/src/v2/mod.rs index d782e37f10b..b9f6f705ed8 100644 --- a/polkadot/node/network/statement-distribution/src/v2/mod.rs +++ b/polkadot/node/network/statement-distribution/src/v2/mod.rs @@ -46,6 +46,7 @@ use polkadot_node_subsystem_util::{ backing_implicit_view::View as ImplicitView, reputation::ReputationAggregator, runtime::{request_min_backing_votes, ProspectiveParachainsMode}, + vstaging::fetch_claim_queue, }; use polkadot_primitives::{ AuthorityDiscoveryId, CandidateHash, CompactStatement, CoreIndex, CoreState, GroupIndex, @@ -149,10 +150,9 @@ pub(crate) const REQUEST_RETRY_DELAY: Duration = Duration::from_secs(1); struct PerRelayParentState { local_validator: Option, statement_store: StatementStore, - availability_cores: Vec, - group_rotation_info: GroupRotationInfo, seconding_limit: usize, session: SessionIndex, + groups_per_para: HashMap>, } impl PerRelayParentState { @@ -563,11 +563,13 @@ pub(crate) async fn handle_active_leaves_update( activated: &ActivatedLeaf, leaf_mode: ProspectiveParachainsMode, ) -> JfyiErrorResult<()> { - let seconding_limit = match leaf_mode { + let max_candidate_depth = match leaf_mode { ProspectiveParachainsMode::Disabled => return Ok(()), - ProspectiveParachainsMode::Enabled { max_candidate_depth, .. } => max_candidate_depth + 1, + ProspectiveParachainsMode::Enabled { max_candidate_depth, .. } => max_candidate_depth, }; + let seconding_limit = max_candidate_depth + 1; + state .implicit_view .activate_leaf(ctx.sender(), activated.hash) @@ -693,15 +695,23 @@ pub(crate) async fn handle_active_leaves_update( } }); + let groups_per_para = determine_groups_per_para( + ctx.sender(), + new_relay_parent, + availability_cores, + group_rotation_info, + max_candidate_depth, + ) + .await; + state.per_relay_parent.insert( new_relay_parent, PerRelayParentState { local_validator, statement_store: StatementStore::new(&per_session.groups), - availability_cores, - group_rotation_info, seconding_limit, session: session_index, + groups_per_para, }, ); } @@ -2126,17 +2136,64 @@ async fn provide_candidate_to_grid( } } -fn group_for_para( - availability_cores: &[CoreState], - group_rotation_info: &GroupRotationInfo, - para_id: ParaId, -) -> Option { - // Note: this won't work well for on-demand parachains as it assumes that core assignments are - // fixed across blocks. - let core_index = availability_cores.iter().position(|c| c.para_id() == Some(para_id)); +// Utility function to populate per relay parent `ParaId` to `GroupIndex` mappings. +async fn determine_groups_per_para( + sender: &mut impl overseer::StatementDistributionSenderTrait, + relay_parent: Hash, + availability_cores: Vec, + group_rotation_info: GroupRotationInfo, + max_candidate_depth: usize, +) -> HashMap> { + let maybe_claim_queue = fetch_claim_queue(sender, relay_parent) + .await + .unwrap_or_else(|err| { + gum::debug!( + target: LOG_TARGET, + ?relay_parent, + ?err, + "determine_groups_per_para: `claim_queue` API not available, falling back to iterating availability cores" + ); + None + }); + + let n_cores = availability_cores.len(); + + // Determine the core indices occupied by each para at the current relay parent. To support + // on-demand parachains we also consider the core indices at next block if core has a candidate + // pending availability. + let para_core_indices: Vec<_> = if let Some(claim_queue) = maybe_claim_queue { + claim_queue + .into_iter() + .filter_map(|(core_index, paras)| Some((*paras.front()?, core_index))) + .collect() + } else { + availability_cores + .into_iter() + .enumerate() + .filter_map(|(index, core)| match core { + CoreState::Scheduled(scheduled_core) => + Some((scheduled_core.para_id, CoreIndex(index as u32))), + CoreState::Occupied(occupied_core) => + if max_candidate_depth >= 1 { + occupied_core + .next_up_on_available + .map(|scheduled_core| (scheduled_core.para_id, CoreIndex(index as u32))) + } else { + None + }, + CoreState::Free => None, + }) + .collect() + }; - core_index - .map(|c| group_rotation_info.group_for_core(CoreIndex(c as _), availability_cores.len())) + let mut groups_per_para = HashMap::new(); + // Map from `CoreIndex` to `GroupIndex` and collect as `HashMap`. + for (para, core_index) in para_core_indices { + let group_index = group_rotation_info.group_for_core(core_index, n_cores); + groups_per_para.entry(para).or_insert_with(Vec::new).push(group_index) + } + + groups_per_para } #[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] @@ -2192,18 +2249,23 @@ async fn fragment_tree_update_inner( let confirmed_candidate = state.candidates.get_confirmed(&candidate_hash); let prs = state.per_relay_parent.get_mut(&receipt.descriptor().relay_parent); if let (Some(confirmed), Some(prs)) = (confirmed_candidate, prs) { - let group_index = group_for_para( - &prs.availability_cores, - &prs.group_rotation_info, - receipt.descriptor().para_id, - ); - let per_session = state.per_session.get(&prs.session); - if let (Some(per_session), Some(group_index)) = (per_session, group_index) { + let group_index = confirmed.group_index(); + + // Sanity check if group_index is valid for this para at relay parent. + let Some(expected_groups) = prs.groups_per_para.get(&receipt.descriptor().para_id) + else { + continue + }; + if !expected_groups.iter().any(|g| *g == group_index) { + continue + } + + if let Some(per_session) = per_session { send_backing_fresh_statements( ctx, candidate_hash, - group_index, + confirmed.group_index(), &receipt.descriptor().relay_parent, prs, confirmed, @@ -2311,13 +2373,12 @@ async fn handle_incoming_manifest_common<'a, Context>( Some(x) => x, }; - let expected_group = group_for_para( - &relay_parent_state.availability_cores, - &relay_parent_state.group_rotation_info, - para_id, - ); + let Some(expected_groups) = relay_parent_state.groups_per_para.get(¶_id) else { + modify_reputation(reputation, ctx.sender(), peer, COST_MALFORMED_MANIFEST).await; + return None + }; - if expected_group != Some(manifest_summary.claimed_group_index) { + if !expected_groups.iter().any(|g| g == &manifest_summary.claimed_group_index) { modify_reputation(reputation, ctx.sender(), peer, COST_MALFORMED_MANIFEST).await; return None } @@ -3037,13 +3098,11 @@ pub(crate) async fn handle_response( relay_parent_state.session, |v| per_session.session_info.validators.get(v).map(|x| x.clone()), |para, g_index| { - let expected_group = group_for_para( - &relay_parent_state.availability_cores, - &relay_parent_state.group_rotation_info, - para, - ); + let Some(expected_groups) = relay_parent_state.groups_per_para.get(¶) else { + return false + }; - Some(g_index) == expected_group + expected_groups.iter().any(|g| g == &g_index) }, disabled_mask, ); diff --git a/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs b/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs index a944a9cd6d0..4fb033e08ce 100644 --- a/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs @@ -312,6 +312,66 @@ fn useful_cluster_statement_from_non_cluster_peer_rejected() { }); } +// Both validators in the test are part of backing groups assigned to same parachain +#[test] +fn elastic_scaling_useful_cluster_statement_from_non_cluster_peer_rejected() { + let config = TestConfig { + validator_count: 20, + group_size: 3, + local_validator: LocalRole::Validator, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let candidate_hash = CandidateHash(Hash::repeat_byte(42)); + + let test_leaf = state.make_dummy_leaf_with_multiple_cores_per_para(relay_parent, 3); + + // Peer A is not in our group, but its group is assigned to same para as we are. + let not_our_group = GroupIndex(1); + + let that_group_validators = state.group_validators(not_our_group, false); + let v_non = that_group_validators[0]; + + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(v_non)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + activate_leaf(&mut overseer, &test_leaf, &state, true, vec![]).await; + + let statement = state + .sign_statement( + v_non, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, statement), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == COST_UNEXPECTED_STATEMENT_INVALID_SENDER.into() => { } + ); + + overseer + }); +} + #[test] fn statement_from_non_cluster_originator_unexpected() { let config = TestConfig { diff --git a/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs b/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs index 38a12cf32e3..9d00a92e742 100644 --- a/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs @@ -1829,9 +1829,7 @@ fn advertisement_not_re_sent_when_peer_re_enters_view() { }); } -// Grid statements imported to backing once candidate enters hypothetical frontier. -#[test] -fn grid_statements_imported_to_backing() { +fn inner_grid_statements_imported_to_backing(groups_for_first_para: usize) { let validator_count = 6; let group_size = 3; let config = TestConfig { @@ -1851,9 +1849,12 @@ fn grid_statements_imported_to_backing() { let local_group_index = local_validator.group_index.unwrap(); let other_group = next_group_index(local_group_index, validator_count, group_size); - let other_para = ParaId::from(other_group.0); - let test_leaf = state.make_dummy_leaf(relay_parent); + // Other para is same para for elastic scaling test (groups_for_first_para > 1) + let other_para = ParaId::from((groups_for_first_para == 1) as u32); + + let test_leaf = + state.make_dummy_leaf_with_multiple_cores_per_para(relay_parent, groups_for_first_para); let (candidate, pvd) = make_candidate( relay_parent, @@ -2018,6 +2019,18 @@ fn grid_statements_imported_to_backing() { overseer }); } +// Grid statements imported to backing once candidate enters hypothetical frontier. +#[test] +fn grid_statements_imported_to_backing() { + inner_grid_statements_imported_to_backing(1); +} + +// Grid statements imported to backing once candidate enters hypothetical frontier. +// All statements are for candidates of the same parachain but from different backing groups. +#[test] +fn elastic_scaling_grid_statements_imported_to_backing() { + inner_grid_statements_imported_to_backing(2); +} #[test] fn advertisements_rejected_from_incorrect_peers() { diff --git a/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs b/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs index 82986a0330e..e98b1107931 100644 --- a/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs @@ -177,20 +177,39 @@ impl TestState { } fn make_dummy_leaf(&self, relay_parent: Hash) -> TestLeaf { + self.make_dummy_leaf_with_multiple_cores_per_para(relay_parent, 1) + } + + fn make_dummy_leaf_with_multiple_cores_per_para( + &self, + relay_parent: Hash, + groups_for_first_para: usize, + ) -> TestLeaf { TestLeaf { number: 1, hash: relay_parent, parent_hash: Hash::repeat_byte(0), session: 1, availability_cores: self.make_availability_cores(|i| { - CoreState::Scheduled(ScheduledCore { - para_id: ParaId::from(i as u32), - collator: None, - }) + let para_id = if i < groups_for_first_para { + ParaId::from(0u32) + } else { + ParaId::from(i as u32) + }; + + CoreState::Scheduled(ScheduledCore { para_id, collator: None }) }), disabled_validators: Default::default(), para_data: (0..self.session_info.validator_groups.len()) - .map(|i| (ParaId::from(i as u32), PerParaData::new(1, vec![1, 2, 3].into()))) + .map(|i| { + let para_id = if i < groups_for_first_para { + ParaId::from(0u32) + } else { + ParaId::from(i as u32) + }; + + (para_id, PerParaData::new(1, vec![1, 2, 3].into())) + }) .collect(), minimum_backing_votes: 2, } diff --git a/polkadot/node/subsystem-util/src/vstaging.rs b/polkadot/node/subsystem-util/src/vstaging.rs index 3e807eff538..25ea7ce7c9b 100644 --- a/polkadot/node/subsystem-util/src/vstaging.rs +++ b/polkadot/node/subsystem-util/src/vstaging.rs @@ -19,14 +19,19 @@ //! This module is intended to contain common boiler plate code handling unreleased runtime API //! calls. +use std::collections::{BTreeMap, VecDeque}; + use polkadot_node_subsystem_types::messages::{RuntimeApiMessage, RuntimeApiRequest}; use polkadot_overseer::SubsystemSender; -use polkadot_primitives::{Hash, ValidatorIndex}; +use polkadot_primitives::{CoreIndex, Hash, Id as ParaId, ScheduledCore, ValidatorIndex}; -use crate::{has_required_runtime, request_disabled_validators, runtime}; +use crate::{has_required_runtime, request_claim_queue, request_disabled_validators, runtime}; const LOG_TARGET: &'static str = "parachain::subsystem-util-vstaging"; +/// A snapshot of the runtime claim queue at an arbitrary relay chain block. +pub type ClaimQueueSnapshot = BTreeMap>; + // TODO: https://github.com/paritytech/polkadot-sdk/issues/1940 /// Returns disabled validators list if the runtime supports it. Otherwise logs a debug messages and /// returns an empty vec. @@ -54,3 +59,40 @@ pub async fn get_disabled_validators_with_fallback, + relay_parent: Hash, +) -> Result, runtime::Error> { + if has_required_runtime( + sender, + relay_parent, + RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT, + ) + .await + { + let res = request_claim_queue(relay_parent, sender) + .await + .await + .map_err(runtime::Error::RuntimeRequestCanceled)??; + Ok(Some(res)) + } else { + gum::trace!(target: LOG_TARGET, "Runtime doesn't support `request_claim_queue`"); + Ok(None) + } +} + +/// Returns the next scheduled `ParaId` for a core in the claim queue, wrapped in `ScheduledCore`. +pub fn fetch_next_scheduled_on_core( + claim_queue: &ClaimQueueSnapshot, + core_idx: CoreIndex, +) -> Option { + claim_queue + .get(&core_idx)? + .front() + .cloned() + .map(|para_id| ScheduledCore { para_id, collator: None }) +} -- GitLab From 9b378a2ffef1d5846872adc4336341805bffbc30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 3 Apr 2024 10:35:53 +0200 Subject: [PATCH 155/187] sp-wasm-interface: `wasmtime` should not be enabled by `std` (#3954) Closes: https://github.com/paritytech/polkadot-sdk/issues/3909 --- substrate/primitives/wasm-interface/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/primitives/wasm-interface/Cargo.toml b/substrate/primitives/wasm-interface/Cargo.toml index c05cc05ff06..15a20fab5e5 100644 --- a/substrate/primitives/wasm-interface/Cargo.toml +++ b/substrate/primitives/wasm-interface/Cargo.toml @@ -25,5 +25,5 @@ anyhow = { version = "1.0.81", optional = true } [features] default = ["std"] -std = ["codec/std", "log/std", "wasmtime"] +std = ["codec/std", "log/std"] wasmtime = ["anyhow", "dep:wasmtime"] -- GitLab From cdacfb9d33710093d67e96cd6767dba0243ff450 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 3 Apr 2024 13:10:50 +0200 Subject: [PATCH 156/187] Added tests for XCM barriers: `AllowSubscriptions`, `WithUniqueTopic` and `TrailingSetTopicAsId` (#3955) Closes: https://github.com/paritytech/polkadot-sdk/issues/1756 --- .../xcm/xcm-builder/src/tests/barriers.rs | 59 ++++++++++++ polkadot/xcm/xcm-builder/src/tests/mod.rs | 1 + polkadot/xcm/xcm-builder/src/tests/routing.rs | 95 +++++++++++++++++++ .../src/tests/version_subscriptions.rs | 32 +++++-- .../xcm-executor/src/traits/should_execute.rs | 4 +- 5 files changed, 181 insertions(+), 10 deletions(-) create mode 100644 polkadot/xcm/xcm-builder/src/tests/routing.rs diff --git a/polkadot/xcm/xcm-builder/src/tests/barriers.rs b/polkadot/xcm/xcm-builder/src/tests/barriers.rs index 99a9dd5a660..6516263f57a 100644 --- a/polkadot/xcm/xcm-builder/src/tests/barriers.rs +++ b/polkadot/xcm/xcm-builder/src/tests/barriers.rs @@ -309,3 +309,62 @@ fn suspension_should_work() { ); assert_eq!(r, Ok(())); } + +#[test] +fn allow_subscriptions_from_should_work() { + // allow only parent + AllowSubsFrom::set(vec![Location::parent()]); + + let valid_xcm_1 = Xcm::(vec![SubscribeVersion { + query_id: 42, + max_response_weight: Weight::from_parts(5000, 5000), + }]); + let valid_xcm_2 = Xcm::(vec![UnsubscribeVersion]); + let invalid_xcm_1 = Xcm::(vec![ + SetAppendix(Xcm(vec![])), + SubscribeVersion { query_id: 42, max_response_weight: Weight::from_parts(5000, 5000) }, + ]); + let invalid_xcm_2 = Xcm::(vec![ + SubscribeVersion { query_id: 42, max_response_weight: Weight::from_parts(5000, 5000) }, + SetTopic([0; 32]), + ]); + + let test_data = vec![ + ( + valid_xcm_1.clone(), + Parachain(1).into_location(), + // not allowed origin + Err(ProcessMessageError::Unsupported), + ), + (valid_xcm_1, Location::parent(), Ok(())), + ( + valid_xcm_2.clone(), + Parachain(1).into_location(), + // not allowed origin + Err(ProcessMessageError::Unsupported), + ), + (valid_xcm_2, Location::parent(), Ok(())), + ( + invalid_xcm_1, + Location::parent(), + // invalid XCM + Err(ProcessMessageError::BadFormat), + ), + ( + invalid_xcm_2, + Location::parent(), + // invalid XCM + Err(ProcessMessageError::BadFormat), + ), + ]; + + for (mut message, origin, expected_result) in test_data { + let r = AllowSubscriptionsFrom::>::should_execute( + &origin, + message.inner_mut(), + Weight::from_parts(10, 10), + &mut props(Weight::zero()), + ); + assert_eq!(r, expected_result, "Failed for origin: {origin:?} and message: {message:?}"); + } +} diff --git a/polkadot/xcm/xcm-builder/src/tests/mod.rs b/polkadot/xcm/xcm-builder/src/tests/mod.rs index e11caf6282b..63d254a1067 100644 --- a/polkadot/xcm/xcm-builder/src/tests/mod.rs +++ b/polkadot/xcm/xcm-builder/src/tests/mod.rs @@ -36,6 +36,7 @@ mod locking; mod origins; mod pay; mod querying; +mod routing; mod transacting; mod version_subscriptions; mod weight; diff --git a/polkadot/xcm/xcm-builder/src/tests/routing.rs b/polkadot/xcm/xcm-builder/src/tests/routing.rs new file mode 100644 index 00000000000..28117d647a0 --- /dev/null +++ b/polkadot/xcm/xcm-builder/src/tests/routing.rs @@ -0,0 +1,95 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use super::*; +use frame_support::{assert_ok, traits::Everything}; +use xcm_executor::traits::Properties; + +fn props() -> Properties { + Properties { weight_credit: Weight::zero(), message_id: None } +} + +#[test] +fn trailing_set_topic_as_id_with_unique_topic_should_work() { + type AllowSubscriptions = AllowSubscriptionsFrom; + + // check the validity of XCM for the `AllowSubscriptions` barrier + let valid_xcm = Xcm::<()>(vec![SubscribeVersion { + query_id: 42, + max_response_weight: Weight::from_parts(5000, 5000), + }]); + assert_eq!( + AllowSubscriptions::should_execute( + &Location::parent(), + valid_xcm.clone().inner_mut(), + Weight::from_parts(10, 10), + &mut props(), + ), + Ok(()) + ); + + // simulate sending `valid_xcm` with the `WithUniqueTopic` router + let mut sent_xcm = sp_io::TestExternalities::default().execute_with(|| { + assert_ok!(send_xcm::>(Location::parent(), valid_xcm,)); + sent_xcm() + }); + assert_eq!(1, sent_xcm.len()); + + // `sent_xcm` should contain `SubscribeVersion` and have `SetTopic` added + let mut sent_xcm = sent_xcm.remove(0).1; + let _ = sent_xcm + .0 + .matcher() + .assert_remaining_insts(2) + .expect("two instructions") + .match_next_inst(|instr| match instr { + SubscribeVersion { .. } => Ok(()), + _ => Err(ProcessMessageError::BadFormat), + }) + .expect("expected instruction `SubscribeVersion`") + .match_next_inst(|instr| match instr { + SetTopic(..) => Ok(()), + _ => Err(ProcessMessageError::BadFormat), + }) + .expect("expected instruction `SetTopic`"); + + // `sent_xcm` contains `SetTopic` and is now invalid for `AllowSubscriptions` + assert_eq!( + AllowSubscriptions::should_execute( + &Location::parent(), + sent_xcm.clone().inner_mut(), + Weight::from_parts(10, 10), + &mut props(), + ), + Err(ProcessMessageError::BadFormat) + ); + + // let's apply `TrailingSetTopicAsId` before `AllowSubscriptions` + let mut props = props(); + assert!(props.message_id.is_none()); + + // should pass, and the `message_id` is set + assert_eq!( + TrailingSetTopicAsId::::should_execute( + &Location::parent(), + sent_xcm.clone().inner_mut(), + Weight::from_parts(10, 10), + &mut props, + ), + Ok(()) + ); + assert!(props.message_id.is_some()); +} diff --git a/polkadot/xcm/xcm-builder/src/tests/version_subscriptions.rs b/polkadot/xcm/xcm-builder/src/tests/version_subscriptions.rs index e29e3a54661..01047fde989 100644 --- a/polkadot/xcm/xcm-builder/src/tests/version_subscriptions.rs +++ b/polkadot/xcm/xcm-builder/src/tests/version_subscriptions.rs @@ -27,16 +27,32 @@ fn simple_version_subscriptions_should_work() { ]); let mut hash = fake_message_hash(&message); let weight_limit = Weight::from_parts(20, 20); - let r = XcmExecutor::::prepare_and_execute( - origin, - message, - &mut hash, - weight_limit, - Weight::zero(), + + // this case fails because the origin is not allowed + assert_eq!( + XcmExecutor::::prepare_and_execute( + origin, + message.clone(), + &mut hash, + weight_limit, + Weight::zero(), + ), + Outcome::Error { error: XcmError::Barrier } + ); + + // this case fails because the additional `SetAppendix` instruction is not allowed in the + // `AllowSubscriptionsFrom` + assert_eq!( + XcmExecutor::::prepare_and_execute( + Parent, + message, + &mut hash, + weight_limit, + Weight::zero(), + ), + Outcome::Error { error: XcmError::Barrier } ); - assert_eq!(r, Outcome::Error { error: XcmError::Barrier }); - let origin = Parachain(1000); let message = Xcm::(vec![SubscribeVersion { query_id: 42, max_response_weight: Weight::from_parts(5000, 5000), diff --git a/polkadot/xcm/xcm-executor/src/traits/should_execute.rs b/polkadot/xcm/xcm-executor/src/traits/should_execute.rs index 12e8fd6b87f..e76d56bfe61 100644 --- a/polkadot/xcm/xcm-executor/src/traits/should_execute.rs +++ b/polkadot/xcm/xcm-executor/src/traits/should_execute.rs @@ -33,9 +33,9 @@ pub struct Properties { /// Trait to determine whether the execution engine should actually execute a given XCM. /// /// Can be amalgamated into a tuple to have multiple trials. If any of the tuple elements returns -/// `Ok()`, the execution stops. Else, `Err(_)` is returned if all elements reject the message. +/// `Ok(())`, the execution stops. Else, `Err(_)` is returned if all elements reject the message. pub trait ShouldExecute { - /// Returns `true` if the given `message` may be executed. + /// Returns `Ok(())` if the given `message` may be executed. /// /// - `origin`: The origin (sender) of the message. /// - `instructions`: The message itself. -- GitLab From 287b116c3e50ff8be275b093674404b2f370c553 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Wed, 3 Apr 2024 14:46:08 +0300 Subject: [PATCH 157/187] chainHead: Ensure reasonable distance between leaf and finalized block (#3562) This PR ensure that the distance between any leaf and the finalized block is within a reasonable distance. For a new subscription, the chainHead has to provide all blocks between the leaves of the chain and the finalized block. When the distance between a leaf and the finalized block is large: - The tree route is costly to compute - We could deliver an unbounded number of blocks (potentially millions) (For more details see https://github.com/paritytech/polkadot-sdk/pull/3445#discussion_r1507210283) The configuration of the ChainHead is extended with: - suspend on lagging distance: When the distance between any leaf and the finalized block is greater than this number, the subscriptions are suspended for a given duration. - All active subscriptions are terminated with the `Stop` event, all blocks are unpinned and data discarded. - For incoming subscriptions, until the suspended period expires the subscriptions will immediately receive the `Stop` event. - Defaults to 128 blocks - suspended duration: The amount of time for which subscriptions are suspended - Defaults to 30 seconds cc @paritytech/subxt-team --------- Signed-off-by: Alexandru Vasile Co-authored-by: Sebastian Kunert --- Cargo.lock | 9 +- .../rpc-spec-v2/src/chain_head/chain_head.rs | 25 +- .../src/chain_head/chain_head_follow.rs | 71 +++++- .../src/chain_head/subscription/error.rs | 4 + .../src/chain_head/subscription/inner.rs | 238 +++++++----------- .../src/chain_head/subscription/mod.rs | 9 + .../rpc-spec-v2/src/chain_head/tests.rs | 121 +++++++++ 7 files changed, 313 insertions(+), 164 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9393f8d606d..55ef63fa2bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2624,9 +2624,9 @@ dependencies = [ [[package]] name = "clap-num" -version = "1.1.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e063d263364859dc54fb064cedb7c122740cd4733644b14b176c097f51e8ab7" +checksum = "488557e97528174edaa2ee268b23a809e0c598213a4bbcb4f34575a46fda147e" dependencies = [ "num-traits", ] @@ -2844,10 +2844,11 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "colored" -version = "2.1.0" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" dependencies = [ + "is-terminal", "lazy_static", "windows-sys 0.48.0", ] diff --git a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs index 975abbca4b6..86d9a726d7b 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs @@ -62,6 +62,9 @@ pub struct ChainHeadConfig { pub subscription_max_pinned_duration: Duration, /// The maximum number of ongoing operations per subscription. pub subscription_max_ongoing_operations: usize, + /// Stop all subscriptions if the distance between the leaves and the current finalized + /// block is larger than this value. + pub max_lagging_distance: usize, /// The maximum number of items reported by the `chainHead_storage` before /// pagination is required. pub operation_max_storage_items: usize, @@ -88,6 +91,10 @@ const MAX_ONGOING_OPERATIONS: usize = 16; /// before paginations is required. const MAX_STORAGE_ITER_ITEMS: usize = 5; +/// Stop all subscriptions if the distance between the leaves and the current finalized +/// block is larger than this value. +const MAX_LAGGING_DISTANCE: usize = 128; + /// The maximum number of `chainHead_follow` subscriptions per connection. const MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION: usize = 4; @@ -97,6 +104,7 @@ impl Default for ChainHeadConfig { global_max_pinned_blocks: MAX_PINNED_BLOCKS, subscription_max_pinned_duration: MAX_PINNED_DURATION, subscription_max_ongoing_operations: MAX_ONGOING_OPERATIONS, + max_lagging_distance: MAX_LAGGING_DISTANCE, operation_max_storage_items: MAX_STORAGE_ITER_ITEMS, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, } @@ -116,6 +124,9 @@ pub struct ChainHead, Block: BlockT, Client> { /// The maximum number of items reported by the `chainHead_storage` before /// pagination is required. operation_max_storage_items: usize, + /// Stop all subscriptions if the distance between the leaves and the current finalized + /// block is larger than this value. + max_lagging_distance: usize, /// Phantom member to pin the block type. _phantom: PhantomData, } @@ -140,6 +151,7 @@ impl, Block: BlockT, Client> ChainHead { backend, ), operation_max_storage_items: config.operation_max_storage_items, + max_lagging_distance: config.max_lagging_distance, _phantom: PhantomData, } } @@ -187,6 +199,7 @@ where let subscriptions = self.subscriptions.clone(); let backend = self.backend.clone(); let client = self.client.clone(); + let max_lagging_distance = self.max_lagging_distance; let fut = async move { // Ensure the current connection ID has enough space to accept a new subscription. @@ -207,8 +220,8 @@ where let Some(sub_data) = reserved_subscription.insert_subscription(sub_id.clone(), with_runtime) else { - // Inserting the subscription can only fail if the JsonRPSee - // generated a duplicate subscription ID. + // Inserting the subscription can only fail if the JsonRPSee generated a duplicate + // subscription ID. debug!(target: LOG_TARGET, "[follow][id={:?}] Subscription already accepted", sub_id); let msg = to_sub_message(&sink, &FollowEvent::::Stop); let _ = sink.send(msg).await; @@ -222,9 +235,13 @@ where subscriptions, with_runtime, sub_id.clone(), + max_lagging_distance, ); - - chain_head_follow.generate_events(sink, sub_data).await; + let result = chain_head_follow.generate_events(sink, sub_data).await; + if let Err(SubscriptionManagementError::BlockDistanceTooLarge) = result { + debug!(target: LOG_TARGET, "[follow][id={:?}] All subscriptions are stopped", sub_id); + reserved_subscription.stop_all_subscriptions(); + } debug!(target: LOG_TARGET, "[follow][id={:?}] Subscription removed", sub_id); }; diff --git a/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs b/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs index 90cc62a36fa..0d87a45c07e 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs @@ -41,12 +41,14 @@ use sp_api::CallApiAt; use sp_blockchain::{ Backend as BlockChainBackend, Error as BlockChainError, HeaderBackend, HeaderMetadata, Info, }; -use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; +use sp_runtime::{ + traits::{Block as BlockT, Header as HeaderT, NumberFor}, + SaturatedConversion, Saturating, +}; use std::{ collections::{HashSet, VecDeque}, sync::Arc, }; - /// The maximum number of finalized blocks provided by the /// `Initialized` event. const MAX_FINALIZED_BLOCKS: usize = 16; @@ -67,6 +69,9 @@ pub struct ChainHeadFollower, Block: BlockT, Client> { sub_id: String, /// The best reported block by this subscription. best_block_cache: Option, + /// Stop all subscriptions if the distance between the leaves and the current finalized + /// block is larger than this value. + max_lagging_distance: usize, } impl, Block: BlockT, Client> ChainHeadFollower { @@ -77,8 +82,17 @@ impl, Block: BlockT, Client> ChainHeadFollower, with_runtime: bool, sub_id: String, + max_lagging_distance: usize, ) -> Self { - Self { client, backend, sub_handle, with_runtime, sub_id, best_block_cache: None } + Self { + client, + backend, + sub_handle, + with_runtime, + sub_id, + best_block_cache: None, + max_lagging_distance, + } } } @@ -186,6 +200,35 @@ where } } + /// Check the distance between the provided blocks does not exceed a + /// a reasonable range. + /// + /// When the blocks are too far apart (potentially millions of blocks): + /// - Tree route is expensive to calculate. + /// - The RPC layer will not be able to generate the `NewBlock` events for all blocks. + /// + /// This edge-case can happen for parachains where the relay chain syncs slower to + /// the head of the chain than the parachain node that is synced already. + fn distace_within_reason( + &self, + block: Block::Hash, + finalized: Block::Hash, + ) -> Result<(), SubscriptionManagementError> { + let Some(block_num) = self.client.number(block)? else { + return Err(SubscriptionManagementError::BlockHashAbsent) + }; + let Some(finalized_num) = self.client.number(finalized)? else { + return Err(SubscriptionManagementError::BlockHashAbsent) + }; + + let distance: usize = block_num.saturating_sub(finalized_num).saturated_into(); + if distance > self.max_lagging_distance { + return Err(SubscriptionManagementError::BlockDistanceTooLarge); + } + + Ok(()) + } + /// Get the in-memory blocks of the client, starting from the provided finalized hash. /// /// The reported blocks are pinned by this function. @@ -198,6 +241,13 @@ where let mut pruned_forks = HashSet::new(); let mut finalized_block_descendants = Vec::new(); let mut unique_descendants = HashSet::new(); + + // Ensure all leaves are within a reasonable distance from the finalized block, + // before traversing the tree. + for leaf in &leaves { + self.distace_within_reason(*leaf, finalized)?; + } + for leaf in leaves { let tree_route = sp_blockchain::tree_route(blockchain, finalized, leaf)?; @@ -542,7 +592,8 @@ where mut to_ignore: HashSet, sink: SubscriptionSink, rx_stop: oneshot::Receiver<()>, - ) where + ) -> Result<(), SubscriptionManagementError> + where EventStream: Stream> + Unpin, { let mut stream_item = stream.next(); @@ -576,7 +627,7 @@ where ); let msg = to_sub_message(&sink, &FollowEvent::::Stop); let _ = sink.send(msg).await; - return + return Err(err) }, }; @@ -591,7 +642,8 @@ where let msg = to_sub_message(&sink, &FollowEvent::::Stop); let _ = sink.send(msg).await; - return + // No need to propagate this error further, the client disconnected. + return Ok(()) } } @@ -605,6 +657,7 @@ where // - the client disconnected. let msg = to_sub_message(&sink, &FollowEvent::::Stop); let _ = sink.send(msg).await; + Ok(()) } /// Generate the block events for the `chainHead_follow` method. @@ -612,7 +665,7 @@ where &mut self, sink: SubscriptionSink, sub_data: InsertedSubscriptionData, - ) { + ) -> Result<(), SubscriptionManagementError> { // Register for the new block and finalized notifications. let stream_import = self .client @@ -640,7 +693,7 @@ where ); let msg = to_sub_message(&sink, &FollowEvent::::Stop); let _ = sink.send(msg).await; - return + return Err(err) }, }; @@ -650,6 +703,6 @@ where let stream = stream::once(futures::future::ready(initial)).chain(merged); self.submit_events(&startup_point, stream.boxed(), pruned_forks, sink, sub_data.rx_stop) - .await; + .await } } diff --git a/substrate/client/rpc-spec-v2/src/chain_head/subscription/error.rs b/substrate/client/rpc-spec-v2/src/chain_head/subscription/error.rs index 2c22e51ca4d..91ce26db22a 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/subscription/error.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/subscription/error.rs @@ -41,6 +41,9 @@ pub enum SubscriptionManagementError { /// The unpin method was called with duplicate hashes. #[error("Duplicate hashes")] DuplicateHashes, + /// The distance between the leaves and the current finalized block is too large. + #[error("Distance too large")] + BlockDistanceTooLarge, /// Custom error. #[error("Subscription error {0}")] Custom(String), @@ -57,6 +60,7 @@ impl PartialEq for SubscriptionManagementError { (Self::BlockHeaderAbsent, Self::BlockHeaderAbsent) | (Self::SubscriptionAbsent, Self::SubscriptionAbsent) | (Self::DuplicateHashes, Self::DuplicateHashes) => true, + (Self::BlockDistanceTooLarge, Self::BlockDistanceTooLarge) => true, (Self::Custom(lhs), Self::Custom(rhs)) => lhs == rhs, _ => false, } diff --git a/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs b/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs index 1ebee3c80fc..0e5ccb91d39 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs @@ -560,6 +560,7 @@ pub struct SubscriptionsInner> { max_ongoing_operations: usize, /// Map the subscription ID to internal details of the subscription. subs: HashMap>, + /// Backend pinning / unpinning blocks. /// /// The `Arc` is handled one level-above, but substrate exposes the backend as Arc. @@ -623,6 +624,15 @@ impl> SubscriptionsInner { } } + /// All active subscriptions are removed. + pub fn stop_all_subscriptions(&mut self) { + let to_remove: Vec<_> = self.subs.keys().map(|sub_id| sub_id.clone()).collect(); + + for sub_id in to_remove { + self.remove_subscription(&sub_id); + } + } + /// Ensure that a new block could be pinned. /// /// If the global number of blocks has been reached this method @@ -878,6 +888,30 @@ mod tests { (backend, client) } + fn produce_blocks( + mut client: Arc>>, + num_blocks: usize, + ) -> Vec<::Hash> { + let mut blocks = Vec::with_capacity(num_blocks); + let mut parent_hash = client.chain_info().genesis_hash; + + for i in 0..num_blocks { + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(parent_hash) + .with_parent_block_number(i as u64) + .build() + .unwrap() + .build() + .unwrap() + .block; + parent_hash = block.header.hash(); + futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); + blocks.push(block.header.hash()); + } + + blocks + } + #[test] fn block_state_machine_register_unpin() { let mut state = BlockStateMachine::new(); @@ -1003,37 +1037,10 @@ mod tests { #[test] fn unpin_duplicate_hashes() { - let (backend, mut client) = init_backend(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(client.chain_info().genesis_hash) - .with_parent_block_number(0) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash_1 = block.header.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(hash_1) - .with_parent_block_number(1) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash_2 = block.header.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(hash_2) - .with_parent_block_number(2) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash_3 = block.header.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); + let (backend, client) = init_backend(); + + let hashes = produce_blocks(client, 3); + let (hash_1, hash_2, hash_3) = (hashes[0], hashes[1], hashes[2]); let mut subs = SubscriptionsInner::new(10, Duration::from_secs(10), MAX_OPERATIONS_PER_SUB, backend); @@ -1102,18 +1109,10 @@ mod tests { #[test] fn subscription_check_block() { - let (backend, mut client) = init_backend(); - - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(client.chain_info().genesis_hash) - .with_parent_block_number(0) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash = block.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); + let (backend, client) = init_backend(); + + let hashes = produce_blocks(client, 1); + let hash = hashes[0]; let mut subs = SubscriptionsInner::new(10, Duration::from_secs(10), MAX_OPERATIONS_PER_SUB, backend); @@ -1140,17 +1139,10 @@ mod tests { #[test] fn subscription_ref_count() { - let (backend, mut client) = init_backend(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(client.chain_info().genesis_hash) - .with_parent_block_number(0) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash = block.header.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); + let (backend, client) = init_backend(); + + let hashes = produce_blocks(client, 1); + let hash = hashes[0]; let mut subs = SubscriptionsInner::new(10, Duration::from_secs(10), MAX_OPERATIONS_PER_SUB, backend); @@ -1190,37 +1182,10 @@ mod tests { #[test] fn subscription_remove_subscription() { - let (backend, mut client) = init_backend(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(client.chain_info().genesis_hash) - .with_parent_block_number(0) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash_1 = block.header.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(hash_1) - .with_parent_block_number(1) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash_2 = block.header.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(hash_2) - .with_parent_block_number(2) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash_3 = block.header.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); + let (backend, client) = init_backend(); + + let hashes = produce_blocks(client, 3); + let (hash_1, hash_2, hash_3) = (hashes[0], hashes[1], hashes[2]); let mut subs = SubscriptionsInner::new(10, Duration::from_secs(10), MAX_OPERATIONS_PER_SUB, backend); @@ -1256,37 +1221,10 @@ mod tests { #[test] fn subscription_check_limits() { - let (backend, mut client) = init_backend(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(client.chain_info().genesis_hash) - .with_parent_block_number(0) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash_1 = block.header.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(hash_1) - .with_parent_block_number(1) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash_2 = block.header.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(hash_2) - .with_parent_block_number(2) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash_3 = block.header.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); + let (backend, client) = init_backend(); + + let hashes = produce_blocks(client, 3); + let (hash_1, hash_2, hash_3) = (hashes[0], hashes[1], hashes[2]); // Maximum number of pinned blocks is 2. let mut subs = @@ -1328,37 +1266,10 @@ mod tests { #[test] fn subscription_check_limits_with_duration() { - let (backend, mut client) = init_backend(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(client.chain_info().genesis_hash) - .with_parent_block_number(0) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash_1 = block.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(hash_1) - .with_parent_block_number(1) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash_2 = block.header.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(hash_2) - .with_parent_block_number(2) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash_3 = block.header.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); + let (backend, client) = init_backend(); + + let hashes = produce_blocks(client, 3); + let (hash_1, hash_2, hash_3) = (hashes[0], hashes[1], hashes[2]); // Maximum number of pinned blocks is 2 and maximum pin duration is 5 second. let mut subs = @@ -1456,6 +1367,39 @@ mod tests { assert_eq!(permit_three.num_ops, 1); } + #[test] + fn stop_all_subscriptions() { + let (backend, client) = init_backend(); + + let hashes = produce_blocks(client, 3); + let (hash_1, hash_2, hash_3) = (hashes[0], hashes[1], hashes[2]); + + let mut subs = + SubscriptionsInner::new(10, Duration::from_secs(10), MAX_OPERATIONS_PER_SUB, backend); + let id_1 = "abc".to_string(); + let id_2 = "abcd".to_string(); + + // Pin all blocks for the first subscription. + let _stop = subs.insert_subscription(id_1.clone(), true).unwrap(); + assert_eq!(subs.pin_block(&id_1, hash_1).unwrap(), true); + assert_eq!(subs.pin_block(&id_1, hash_2).unwrap(), true); + assert_eq!(subs.pin_block(&id_1, hash_3).unwrap(), true); + + // Pin only block 2 for the second subscription. + let _stop = subs.insert_subscription(id_2.clone(), true).unwrap(); + assert_eq!(subs.pin_block(&id_2, hash_2).unwrap(), true); + + // Check reference count. + assert_eq!(*subs.global_blocks.get(&hash_1).unwrap(), 1); + assert_eq!(*subs.global_blocks.get(&hash_2).unwrap(), 2); + assert_eq!(*subs.global_blocks.get(&hash_3).unwrap(), 1); + assert_eq!(subs.global_blocks.len(), 3); + + // Stop all active subscriptions. + subs.stop_all_subscriptions(); + assert!(subs.global_blocks.is_empty()); + } + #[test] fn reserved_subscription_cleans_resources() { let builder = TestClientBuilder::new(); diff --git a/substrate/client/rpc-spec-v2/src/chain_head/subscription/mod.rs b/substrate/client/rpc-spec-v2/src/chain_head/subscription/mod.rs index 5b016af1aa4..f266c9d8b34 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/subscription/mod.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/subscription/mod.rs @@ -233,6 +233,15 @@ impl> ReservedSubscription { }, } } + + /// Stop all active subscriptions. + /// + /// For all active subscriptions, the internal data is discarded, blocks are unpinned and the + /// `Stop` event will be generated. + pub fn stop_all_subscriptions(&self) { + let mut inner = self.inner.write(); + inner.stop_all_subscriptions() + } } impl> Drop for ReservedSubscription { diff --git a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs index c3f10a201c5..c2bff7c50d5 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs @@ -63,6 +63,7 @@ const MAX_PINNED_BLOCKS: usize = 32; const MAX_PINNED_SECS: u64 = 60; const MAX_OPERATIONS: usize = 16; const MAX_PAGINATION_LIMIT: usize = 5; +const MAX_LAGGING_DISTANCE: usize = 128; const MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION: usize = 4; const INVALID_HASH: [u8; 32] = [1; 32]; @@ -88,6 +89,7 @@ pub async fn run_server() -> std::net::SocketAddr { subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, max_follow_subscriptions_per_connection: 1, + max_lagging_distance: MAX_LAGGING_DISTANCE, }, ) .into_rpc(); @@ -148,6 +150,7 @@ async fn setup_api() -> ( subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -199,6 +202,8 @@ async fn follow_subscription_produces_blocks() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -268,6 +273,8 @@ async fn follow_with_runtime() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -581,6 +588,8 @@ async fn call_runtime_without_flag() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -1240,6 +1249,8 @@ async fn separate_operation_ids_for_subscriptions() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -1329,6 +1340,8 @@ async fn follow_generates_initial_blocks() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -1485,6 +1498,8 @@ async fn follow_exceeding_pinned_blocks() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -1562,6 +1577,8 @@ async fn follow_with_unpin() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -1674,6 +1691,8 @@ async fn unpin_duplicate_hashes() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -1777,6 +1796,8 @@ async fn follow_with_multiple_unpin_hashes() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -1931,6 +1952,8 @@ async fn follow_prune_best_block() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -2117,6 +2140,8 @@ async fn follow_forks_pruned_block() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -2277,6 +2302,8 @@ async fn follow_report_multiple_pruned_block() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -2523,6 +2550,8 @@ async fn pin_block_references() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -2661,6 +2690,8 @@ async fn follow_finalized_before_new_block() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -2776,6 +2807,8 @@ async fn ensure_operation_limits_works() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: 1, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -2881,6 +2914,8 @@ async fn check_continue_operation() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: 1, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -3064,6 +3099,8 @@ async fn stop_storage_operation() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: 1, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -3351,6 +3388,88 @@ async fn storage_closest_merkle_value() { ); } +#[tokio::test] +async fn chain_head_stop_all_subscriptions() { + let builder = TestClientBuilder::new(); + let backend = builder.backend(); + let mut client = Arc::new(builder.build()); + + // Configure the chainHead to stop all subscriptions on lagging distance of 5 blocks. + let api = ChainHead::new( + client.clone(), + backend, + Arc::new(TaskExecutor::default()), + ChainHeadConfig { + global_max_pinned_blocks: MAX_PINNED_BLOCKS, + subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), + subscription_max_ongoing_operations: MAX_OPERATIONS, + operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_lagging_distance: 5, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, + }, + ) + .into_rpc(); + + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + + // Ensure the imported block is propagated and pinned for this subscription. + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::Initialized(_) + ); + + // Import 6 blocks in total to trigger the suspension distance. + let mut parent_hash = client.chain_info().genesis_hash; + for i in 0..6 { + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(parent_hash) + .with_parent_block_number(i) + .build() + .unwrap() + .build() + .unwrap() + .block; + + let hash = block.hash(); + parent_hash = hash; + client.import(BlockOrigin::Own, block.clone()).await.unwrap(); + + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::NewBlock(_) + ); + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::BestBlockChanged(_) + ); + } + + let mut second_sub = + api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + // Lagging detected, the stop event is delivered immediately. + assert_matches!( + get_next_event::>(&mut second_sub).await, + FollowEvent::Stop + ); + + // Ensure that all subscriptions are stopped. + assert_matches!(get_next_event::>(&mut sub).await, FollowEvent::Stop); + + // Other subscriptions cannot be started until the suspension period is over. + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + // Should receive the stop event immediately. + assert_matches!(get_next_event::>(&mut sub).await, FollowEvent::Stop); + + // For the next subscription, lagging distance must be smaller. + client.finalize_block(parent_hash, None).unwrap(); + + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::Initialized(_) + ); +} + #[tokio::test] async fn chain_head_single_connection_context() { let server_addr = run_server().await; @@ -3500,12 +3619,14 @@ async fn chain_head_limit_reached() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: 1, }, ) .into_rpc(); let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + // Initialized must always be reported first. let _event: FollowEvent = get_next_event(&mut sub).await; -- GitLab From ecc51a25350145e3848f306cb30d92423b78d974 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Wed, 3 Apr 2024 17:00:38 +0200 Subject: [PATCH 158/187] Enable pov-reclaim on rococo and westend parachains (#3858) Enables pov-reclaim on the rococo/westend parachains, part of https://github.com/paritytech/polkadot-sdk/issues/3622 --- Cargo.lock | 10 ++++++++++ .../runtimes/assets/asset-hub-rococo/Cargo.toml | 2 ++ .../runtimes/assets/asset-hub-rococo/src/lib.rs | 1 + .../runtimes/assets/asset-hub-westend/Cargo.toml | 2 ++ .../runtimes/assets/asset-hub-westend/src/lib.rs | 1 + .../runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml | 2 ++ .../runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs | 4 +++- .../bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs | 1 + .../bridge-hubs/bridge-hub-rococo/tests/tests.rs | 1 + .../runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml | 3 +++ .../runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs | 2 ++ .../bridge-hubs/bridge-hub-westend/tests/tests.rs | 1 + .../collectives/collectives-westend/Cargo.toml | 3 +++ .../collectives/collectives-westend/src/lib.rs | 1 + .../runtimes/contracts/contracts-rococo/Cargo.toml | 3 +++ .../runtimes/contracts/contracts-rococo/src/lib.rs | 1 + .../runtimes/coretime/coretime-rococo/Cargo.toml | 2 ++ .../runtimes/coretime/coretime-rococo/src/lib.rs | 1 + .../runtimes/coretime/coretime-westend/Cargo.toml | 3 +++ .../runtimes/coretime/coretime-westend/src/lib.rs | 1 + .../runtimes/people/people-rococo/Cargo.toml | 2 ++ .../runtimes/people/people-rococo/src/lib.rs | 1 + .../runtimes/people/people-westend/Cargo.toml | 2 ++ .../runtimes/people/people-westend/src/lib.rs | 1 + 24 files changed, 50 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 55ef63fa2bf..42524fc7765 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -867,6 +867,7 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "cumulus-primitives-aura", "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-utility", "frame-benchmarking", "frame-executive", @@ -990,6 +991,7 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "cumulus-primitives-aura", "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-utility", "frame-benchmarking", "frame-executive", @@ -2010,6 +2012,7 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "cumulus-primitives-aura", "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-utility", "frame-benchmarking", "frame-executive", @@ -2181,6 +2184,7 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "cumulus-primitives-aura", "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-utility", "frame-benchmarking", "frame-executive", @@ -2739,6 +2743,7 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "cumulus-primitives-aura", "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-utility", "frame-benchmarking", "frame-executive", @@ -2994,6 +2999,7 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "cumulus-primitives-aura", "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-utility", "frame-benchmarking", "frame-executive", @@ -3088,6 +3094,7 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "cumulus-primitives-aura", "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-utility", "frame-benchmarking", "frame-executive", @@ -3152,6 +3159,7 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "cumulus-primitives-aura", "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-utility", "frame-benchmarking", "frame-executive", @@ -11764,6 +11772,7 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "cumulus-primitives-aura", "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-utility", "enumflags2", "frame-benchmarking", @@ -11863,6 +11872,7 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "cumulus-primitives-aura", "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-utility", "enumflags2", "frame-benchmarking", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index f5ea0937dec..0733156716c 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -78,6 +78,7 @@ cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-f cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } +cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } @@ -190,6 +191,7 @@ std = [ "cumulus-pallet-xcmp-queue/std", "cumulus-primitives-aura/std", "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", "cumulus-primitives-utility/std", "frame-benchmarking?/std", "frame-executive/std", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 293416ab2a9..7edec45abfb 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -955,6 +955,7 @@ pub type SignedExtra = ( frame_system::CheckNonce, frame_system::CheckWeight, pallet_asset_conversion_tx_payment::ChargeAssetTxPayment, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index b792d64c03e..e25554ec0a5 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -76,6 +76,7 @@ cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-f cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } +cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } @@ -178,6 +179,7 @@ std = [ "cumulus-pallet-xcmp-queue/std", "cumulus-primitives-aura/std", "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", "cumulus-primitives-utility/std", "frame-benchmarking?/std", "frame-executive/std", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index e92e801e9f5..d17d5a70757 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -927,6 +927,7 @@ pub type SignedExtra = ( frame_system::CheckNonce, frame_system::CheckWeight, pallet_asset_conversion_tx_payment::ChargeAssetTxPayment, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml index 1dd4f499b4d..f5a75aa03ac 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -78,6 +78,7 @@ cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-f ] } cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } +cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } @@ -156,6 +157,7 @@ std = [ "cumulus-pallet-xcmp-queue/std", "cumulus-primitives-aura/std", "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", "cumulus-primitives-utility/std", "frame-benchmarking/std", "frame-executive/std", diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index fd6d44ec275..9796a77f994 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -130,6 +130,7 @@ pub type SignedExtra = ( bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages, bridge_to_bulletin_config::OnBridgeHubRococoRefundRococoBulletinMessages, ), + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// Unchecked extrinsic type as expected by this runtime. @@ -1493,7 +1494,8 @@ mod tests { ( bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages::default(), bridge_to_bulletin_config::OnBridgeHubRococoRefundRococoBulletinMessages::default(), - ) + ), + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), ); // for BridgeHubRococo diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs index 101b8d86d55..5960ab7b550 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs @@ -187,6 +187,7 @@ fn construct_extrinsic( OnBridgeHubRococoRefundBridgeHubWestendMessages::default(), OnBridgeHubRococoRefundRococoBulletinMessages::default(), ), + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), ); let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); let signature = payload.using_encoded(|e| sender.sign(e)); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs index fad357b0951..776c505fa64 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -64,6 +64,7 @@ fn construct_extrinsic( bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages::default(), bridge_to_bulletin_config::OnBridgeHubRococoRefundRococoBulletinMessages::default(), ), + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), ); let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); let signature = payload.using_encoded(|e| sender.sign(e)); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml index 1501ed12e3a..86560caca99 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -71,6 +71,8 @@ cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-f cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } +cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } + pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } @@ -128,6 +130,7 @@ std = [ "cumulus-pallet-xcmp-queue/std", "cumulus-primitives-aura/std", "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", "cumulus-primitives-utility/std", "frame-benchmarking/std", "frame-executive/std", diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index 3b759301d0e..4318df8f15e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -109,6 +109,7 @@ pub type SignedExtra = ( pallet_transaction_payment::ChargeTransactionPayment, BridgeRejectObsoleteHeadersAndMessages, (bridge_to_rococo_config::OnBridgeHubWestendRefundBridgeHubRococoMessages,), + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// Unchecked extrinsic type as expected by this runtime. @@ -1154,6 +1155,7 @@ mod tests { ( bridge_to_rococo_config::OnBridgeHubWestendRefundBridgeHubRococoMessages::default(), ), + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new() ); { diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs index 235b7f146c8..988b10e1e2d 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs @@ -78,6 +78,7 @@ fn construct_extrinsic( pallet_transaction_payment::ChargeTransactionPayment::::from(0), BridgeRejectObsoleteHeadersAndMessages::default(), (bridge_to_rococo_config::OnBridgeHubWestendRefundBridgeHubRococoMessages::default(),), + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), ); let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); let signature = payload.using_encoded(|e| sender.sign(e)); diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml index 9c3acf6ad93..22821170a54 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml @@ -77,6 +77,8 @@ cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-f cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } +cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } + pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } pallet-collective-content = { path = "../../../pallets/collective-content", default-features = false } parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } @@ -172,6 +174,7 @@ std = [ "cumulus-pallet-xcmp-queue/std", "cumulus-primitives-aura/std", "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", "cumulus-primitives-utility/std", "frame-benchmarking?/std", "frame-executive/std", diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index e1c2e1a6237..170b0a39600 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -713,6 +713,7 @@ pub type SignedExtra = ( frame_system::CheckEra, frame_system::CheckNonce, frame_system::CheckWeight, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index a0aeb642df0..74c5b5f8115 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -74,6 +74,8 @@ cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-f cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } +cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } + pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } @@ -90,6 +92,7 @@ std = [ "cumulus-pallet-xcmp-queue/std", "cumulus-primitives-aura/std", "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", "cumulus-primitives-utility/std", "frame-benchmarking?/std", "frame-executive/std", diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index ec0a5f6fc96..936d87a23ca 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -90,6 +90,7 @@ pub type SignedExtra = ( frame_system::CheckNonce, frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml b/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml index eb92afc4311..ee9f5e87ec8 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml @@ -72,6 +72,7 @@ cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-f cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } +cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } @@ -88,6 +89,7 @@ std = [ "cumulus-pallet-xcmp-queue/std", "cumulus-primitives-aura/std", "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", "cumulus-primitives-utility/std", "frame-benchmarking?/std", "frame-executive/std", diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs index 67f48689353..27965aa204f 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs @@ -99,6 +99,7 @@ pub type SignedExtra = ( frame_system::CheckNonce, frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// Unchecked extrinsic type as expected by this runtime. diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml b/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml index b8efecffc50..60cc7e2f765 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml @@ -71,6 +71,8 @@ cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-f cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } +cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } + pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } @@ -87,6 +89,7 @@ std = [ "cumulus-pallet-xcmp-queue/std", "cumulus-primitives-aura/std", "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", "cumulus-primitives-utility/std", "frame-benchmarking?/std", "frame-executive/std", diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs index 609ea5a38a8..8075ffb4f1c 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs @@ -99,6 +99,7 @@ pub type SignedExtra = ( frame_system::CheckNonce, frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// Unchecked extrinsic type as expected by this runtime. diff --git a/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml b/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml index eebd662c3fd..7183be5fc82 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml @@ -69,6 +69,7 @@ cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-f cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } +cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } @@ -85,6 +86,7 @@ std = [ "cumulus-pallet-xcmp-queue/std", "cumulus-primitives-aura/std", "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", "cumulus-primitives-utility/std", "enumflags2/std", "frame-benchmarking?/std", diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs index 7c9427a2493..1b6499f5d61 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs @@ -93,6 +93,7 @@ pub type SignedExtra = ( frame_system::CheckNonce, frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// Unchecked extrinsic type as expected by this runtime. diff --git a/cumulus/parachains/runtimes/people/people-westend/Cargo.toml b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml index 39cb69e679c..576c3b1aa4e 100644 --- a/cumulus/parachains/runtimes/people/people-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml @@ -69,6 +69,7 @@ cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-f cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } +cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } @@ -85,6 +86,7 @@ std = [ "cumulus-pallet-xcmp-queue/std", "cumulus-primitives-aura/std", "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", "cumulus-primitives-utility/std", "enumflags2/std", "frame-benchmarking?/std", diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs index 3e331e5e8eb..6ae53d641b0 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs @@ -93,6 +93,7 @@ pub type SignedExtra = ( frame_system::CheckNonce, frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// Unchecked extrinsic type as expected by this runtime. -- GitLab From 0f4e849e0ac2de8c9880077c085985c5f656329c Mon Sep 17 00:00:00 2001 From: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Date: Wed, 3 Apr 2024 18:01:34 +0300 Subject: [PATCH 159/187] Add ClaimQueue wrapper (#3950) Remove `fetch_next_scheduled_on_core` in favor of new wrapper and methods for accessing it. --------- Signed-off-by: Andrei Sandu --- polkadot/node/collation-generation/src/lib.rs | 14 +++--- .../node/collation-generation/src/tests.rs | 13 +++--- .../statement-distribution/src/v2/mod.rs | 4 +- polkadot/node/subsystem-util/src/vstaging.rs | 44 ++++++++++++------- prdoc/pr_3950.prdoc | 12 +++++ 5 files changed, 55 insertions(+), 32 deletions(-) create mode 100644 prdoc/pr_3950.prdoc diff --git a/polkadot/node/collation-generation/src/lib.rs b/polkadot/node/collation-generation/src/lib.rs index fb82871bb15..60ea1cf5ff4 100644 --- a/polkadot/node/collation-generation/src/lib.rs +++ b/polkadot/node/collation-generation/src/lib.rs @@ -45,13 +45,12 @@ use polkadot_node_subsystem::{ use polkadot_node_subsystem_util::{ request_async_backing_params, request_availability_cores, request_para_backing_state, request_persisted_validation_data, request_validation_code, request_validation_code_hash, - request_validators, - vstaging::{fetch_claim_queue, fetch_next_scheduled_on_core}, + request_validators, vstaging::fetch_claim_queue, }; use polkadot_primitives::{ collator_signature_payload, CandidateCommitments, CandidateDescriptor, CandidateReceipt, CollatorPair, CoreIndex, CoreState, Hash, Id as ParaId, OccupiedCoreAssumption, - PersistedValidationData, ValidationCodeHash, + PersistedValidationData, ScheduledCore, ValidationCodeHash, }; use sp_core::crypto::Pair; use std::sync::Arc; @@ -245,11 +244,10 @@ async fn handle_new_activations( // Use claim queue if available, or fallback to `next_up_on_available` let res = match maybe_claim_queue { Some(ref claim_queue) => { - // read what's in the claim queue for this core - fetch_next_scheduled_on_core( - claim_queue, - CoreIndex(core_idx as u32), - ) + // read what's in the claim queue for this core at depth 0. + claim_queue + .get_claim_for(CoreIndex(core_idx as u32), 0) + .map(|para_id| ScheduledCore { para_id, collator: None }) }, None => { // Runtime doesn't support claim queue runtime api. Fallback to diff --git a/polkadot/node/collation-generation/src/tests.rs b/polkadot/node/collation-generation/src/tests.rs index 781d27188df..1ec2cccfae7 100644 --- a/polkadot/node/collation-generation/src/tests.rs +++ b/polkadot/node/collation-generation/src/tests.rs @@ -28,7 +28,7 @@ use polkadot_node_subsystem::{ ActivatedLeaf, }; use polkadot_node_subsystem_test_helpers::{subsystem_test_harness, TestSubsystemContextHandle}; -use polkadot_node_subsystem_util::{vstaging::ClaimQueueSnapshot, TimeoutExt}; +use polkadot_node_subsystem_util::TimeoutExt; use polkadot_primitives::{ async_backing::{BackingState, CandidatePendingAvailability}, AsyncBackingParams, BlockNumber, CollatorPair, HeadData, PersistedValidationData, @@ -620,8 +620,7 @@ fn fallback_when_no_validation_code_hash_api(#[case] runtime_version: u32) { _hash, RuntimeApiRequest::ClaimQueue(tx), ))) if runtime_version >= RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT => { - let res = ClaimQueueSnapshot::new(); - tx.send(Ok(res)).unwrap(); + tx.send(Ok(Default::default())).unwrap(); }, Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( _hash, @@ -783,7 +782,7 @@ fn distribute_collation_for_occupied_core_with_async_backing_enabled(#[case] run candidate_hash: Default::default(), candidate_descriptor: dummy_candidate_descriptor(dummy_hash()), })]; - let claim_queue = ClaimQueueSnapshot::from([(CoreIndex::from(0), VecDeque::from([para_id]))]); + let claim_queue = BTreeMap::from([(CoreIndex::from(0), VecDeque::from([para_id]))]).into(); test_harness(|mut virtual_overseer| async move { helpers::initialize_collator(&mut virtual_overseer, para_id).await; @@ -965,7 +964,7 @@ fn no_collation_is_distributed_for_occupied_core_with_async_backing_disabled( candidate_hash: Default::default(), candidate_descriptor: dummy_candidate_descriptor(dummy_hash()), })]; - let claim_queue = ClaimQueueSnapshot::from([(CoreIndex::from(0), VecDeque::from([para_id]))]); + let claim_queue = BTreeMap::from([(CoreIndex::from(0), VecDeque::from([para_id]))]).into(); test_harness(|mut virtual_overseer| async move { helpers::initialize_collator(&mut virtual_overseer, para_id).await; @@ -1053,7 +1052,7 @@ mod helpers { async_backing_params: AsyncBackingParams, cores: Vec, runtime_version: u32, - claim_queue: ClaimQueueSnapshot, + claim_queue: BTreeMap>, ) { assert_matches!( overseer_recv(virtual_overseer).await, @@ -1107,7 +1106,7 @@ mod helpers { RuntimeApiRequest::ClaimQueue(tx), )) => { assert_eq!(hash, activated_hash); - let _ = tx.send(Ok(claim_queue)); + let _ = tx.send(Ok(claim_queue.into())); } ); } diff --git a/polkadot/node/network/statement-distribution/src/v2/mod.rs b/polkadot/node/network/statement-distribution/src/v2/mod.rs index b9f6f705ed8..f5a8ec4a269 100644 --- a/polkadot/node/network/statement-distribution/src/v2/mod.rs +++ b/polkadot/node/network/statement-distribution/src/v2/mod.rs @@ -2163,8 +2163,8 @@ async fn determine_groups_per_para( // pending availability. let para_core_indices: Vec<_> = if let Some(claim_queue) = maybe_claim_queue { claim_queue - .into_iter() - .filter_map(|(core_index, paras)| Some((*paras.front()?, core_index))) + .iter_claims_at_depth(0) + .map(|(core_index, para)| (para, core_index)) .collect() } else { availability_cores diff --git a/polkadot/node/subsystem-util/src/vstaging.rs b/polkadot/node/subsystem-util/src/vstaging.rs index 25ea7ce7c9b..b166a54f75c 100644 --- a/polkadot/node/subsystem-util/src/vstaging.rs +++ b/polkadot/node/subsystem-util/src/vstaging.rs @@ -23,14 +23,40 @@ use std::collections::{BTreeMap, VecDeque}; use polkadot_node_subsystem_types::messages::{RuntimeApiMessage, RuntimeApiRequest}; use polkadot_overseer::SubsystemSender; -use polkadot_primitives::{CoreIndex, Hash, Id as ParaId, ScheduledCore, ValidatorIndex}; +use polkadot_primitives::{CoreIndex, Hash, Id as ParaId, ValidatorIndex}; use crate::{has_required_runtime, request_claim_queue, request_disabled_validators, runtime}; const LOG_TARGET: &'static str = "parachain::subsystem-util-vstaging"; /// A snapshot of the runtime claim queue at an arbitrary relay chain block. -pub type ClaimQueueSnapshot = BTreeMap>; +#[derive(Default)] +pub struct ClaimQueueSnapshot(BTreeMap>); + +impl From>> for ClaimQueueSnapshot { + fn from(claim_queue_snapshot: BTreeMap>) -> Self { + ClaimQueueSnapshot(claim_queue_snapshot) + } +} + +impl ClaimQueueSnapshot { + /// Returns the `ParaId` that has a claim for `core_index` at the specified `depth` in the + /// claim queue. A depth of `0` means the very next block. + pub fn get_claim_for(&self, core_index: CoreIndex, depth: usize) -> Option { + self.0.get(&core_index)?.get(depth).copied() + } + + /// Returns an iterator over all claimed cores and the claiming `ParaId` at the specified + /// `depth` in the claim queue. + pub fn iter_claims_at_depth( + &self, + depth: usize, + ) -> impl Iterator + '_ { + self.0 + .iter() + .filter_map(move |(core_index, paras)| Some((*core_index, *paras.get(depth)?))) + } +} // TODO: https://github.com/paritytech/polkadot-sdk/issues/1940 /// Returns disabled validators list if the runtime supports it. Otherwise logs a debug messages and @@ -78,21 +104,9 @@ pub async fn fetch_claim_queue( .await .await .map_err(runtime::Error::RuntimeRequestCanceled)??; - Ok(Some(res)) + Ok(Some(res.into())) } else { gum::trace!(target: LOG_TARGET, "Runtime doesn't support `request_claim_queue`"); Ok(None) } } - -/// Returns the next scheduled `ParaId` for a core in the claim queue, wrapped in `ScheduledCore`. -pub fn fetch_next_scheduled_on_core( - claim_queue: &ClaimQueueSnapshot, - core_idx: CoreIndex, -) -> Option { - claim_queue - .get(&core_idx)? - .front() - .cloned() - .map(|para_id| ScheduledCore { para_id, collator: None }) -} diff --git a/prdoc/pr_3950.prdoc b/prdoc/pr_3950.prdoc new file mode 100644 index 00000000000..a333521898b --- /dev/null +++ b/prdoc/pr_3950.prdoc @@ -0,0 +1,12 @@ +title: Add `ClaimQueue` wrapper + +doc: + - audience: Node Dev + description: | + Intoduces a new wrapper type: `ClaimQueueSnapshot`. It contains a snapshot of the `ClaimQueue` + at an arbitrary relay chain block. Two methods are exposed to allow access to the claims at + specific depths. + +crates: + - name: polkadot-node-subsystem-util + bump: minor -- GitLab From 3836376965104d7723a1659d52ee26232019b929 Mon Sep 17 00:00:00 2001 From: gupnik Date: Thu, 4 Apr 2024 07:50:15 +0530 Subject: [PATCH 160/187] Renames `frame` crate to `polkadot-sdk-frame` (#3813) Step in https://github.com/paritytech/polkadot-sdk/issues/3155 Needed for https://github.com/paritytech/eng-automation/issues/6 This PR renames `frame` crate to `polkadot-sdk-frame` as `frame` is not available on crates.io --------- Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- Cargo.lock | 70 +++++++++---------- docs/sdk/Cargo.toml | 2 +- prdoc/pr_3813.prdoc | 14 ++++ substrate/client/chain-spec/src/lib.rs | 2 +- substrate/frame/Cargo.toml | 4 +- .../frame/examples/frame-crate/Cargo.toml | 2 +- substrate/frame/src/lib.rs | 24 ++++--- substrate/frame/support/procedural/src/lib.rs | 8 +-- .../procedural/src/pallet/parse/config.rs | 42 ++++++++--- .../frame/support/procedural/tools/src/lib.rs | 16 +++-- .../support/test/stg_frame_crate/Cargo.toml | 2 +- ...event_type_invalid_bound_no_frame_crate.rs | 6 +- ...t_type_invalid_bound_no_frame_crate.stderr | 2 +- .../primitives/api/proc-macro/src/utils.rs | 4 +- .../benchmarking-cli/src/pallet/command.rs | 2 +- substrate/utils/frame/rpc/support/src/lib.rs | 2 +- templates/minimal/node/Cargo.toml | 2 +- templates/minimal/pallets/template/Cargo.toml | 2 +- templates/minimal/runtime/Cargo.toml | 2 +- 19 files changed, 130 insertions(+), 78 deletions(-) create mode 100644 prdoc/pr_3813.prdoc diff --git a/Cargo.lock b/Cargo.lock index 42524fc7765..fc340ff1119 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5454,35 +5454,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" -[[package]] -name = "frame" -version = "0.0.1-dev" -dependencies = [ - "docify", - "frame-executive", - "frame-support", - "frame-system", - "frame-system-rpc-runtime-api", - "log", - "pallet-examples", - "parity-scale-codec", - "scale-info", - "sp-api", - "sp-arithmetic", - "sp-block-builder", - "sp-consensus-aura", - "sp-consensus-grandpa", - "sp-core", - "sp-inherents", - "sp-io", - "sp-offchain", - "sp-runtime", - "sp-session", - "sp-std 14.0.0", - "sp-transaction-pool", - "sp-version", -] - [[package]] name = "frame-benchmarking" version = "28.0.0" @@ -5820,8 +5791,8 @@ dependencies = [ name = "frame-support-test-stg-frame-crate" version = "0.1.0" dependencies = [ - "frame", "parity-scale-codec", + "polkadot-sdk-frame", "scale-info", ] @@ -8132,11 +8103,11 @@ name = "minimal-template-node" version = "0.0.0" dependencies = [ "clap 4.5.3", - "frame", "futures", "futures-timer", "jsonrpsee", "minimal-template-runtime", + "polkadot-sdk-frame", "sc-basic-authorship", "sc-cli", "sc-client-api", @@ -8166,7 +8137,6 @@ dependencies = [ name = "minimal-template-runtime" version = "0.0.0" dependencies = [ - "frame", "pallet-balances", "pallet-minimal-template", "pallet-sudo", @@ -8174,6 +8144,7 @@ dependencies = [ "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "parity-scale-codec", + "polkadot-sdk-frame", "scale-info", "sp-genesis-builder", "substrate-wasm-builder", @@ -9844,8 +9815,8 @@ dependencies = [ name = "pallet-example-frame-crate" version = "0.0.1" dependencies = [ - "frame", "parity-scale-codec", + "polkadot-sdk-frame", "scale-info", ] @@ -10178,8 +10149,8 @@ dependencies = [ name = "pallet-minimal-template" version = "0.0.0" dependencies = [ - "frame", "parity-scale-codec", + "polkadot-sdk-frame", "scale-info", ] @@ -13377,7 +13348,6 @@ dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-parachain-system", "docify", - "frame", "frame-executive", "frame-support", "frame-system", @@ -13405,6 +13375,7 @@ dependencies = [ "pallet-uniques", "pallet-utility", "parity-scale-codec", + "polkadot-sdk-frame", "sc-cli", "sc-client-db", "sc-consensus-aura", @@ -13434,6 +13405,35 @@ dependencies = [ "substrate-wasm-builder", ] +[[package]] +name = "polkadot-sdk-frame" +version = "0.1.0" +dependencies = [ + "docify", + "frame-executive", + "frame-support", + "frame-system", + "frame-system-rpc-runtime-api", + "log", + "pallet-examples", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-arithmetic", + "sp-block-builder", + "sp-consensus-aura", + "sp-consensus-grandpa", + "sp-core", + "sp-inherents", + "sp-io", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-std 14.0.0", + "sp-transaction-pool", + "sp-version", +] + [[package]] name = "polkadot-service" version = "7.0.0" diff --git a/docs/sdk/Cargo.toml b/docs/sdk/Cargo.toml index 64b23866f0c..426c5d9de4a 100644 --- a/docs/sdk/Cargo.toml +++ b/docs/sdk/Cargo.toml @@ -17,7 +17,7 @@ workspace = true # Needed for all FRAME-based code parity-scale-codec = { version = "3.0.0", default-features = false } scale-info = { version = "2.6.0", default-features = false } -frame = { path = "../../substrate/frame", features = [ +frame = { package = "polkadot-sdk-frame", path = "../../substrate/frame", features = [ "experimental", "runtime", ] } diff --git a/prdoc/pr_3813.prdoc b/prdoc/pr_3813.prdoc new file mode 100644 index 00000000000..66dfd70e1b1 --- /dev/null +++ b/prdoc/pr_3813.prdoc @@ -0,0 +1,14 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Renames `frame` crate to `polkadot-sdk-frame` + +doc: + - audience: Runtime Dev + description: | + This PR renames `frame` crate to `polkadot-sdk-frame` as `frame` is not available on crates.io. + Please note that this crate can only be imported as `polkadot-sdk-frame` or `frame`. + +crates: + - name: polkadot-sdk-frame + bump: major diff --git a/substrate/client/chain-spec/src/lib.rs b/substrate/client/chain-spec/src/lib.rs index e8b87a60404..6da5fd26d52 100644 --- a/substrate/client/chain-spec/src/lib.rs +++ b/substrate/client/chain-spec/src/lib.rs @@ -140,7 +140,7 @@ //!
A JSON object that provides an explicit and comprehensive representation of the //! RuntimeGenesisConfig struct, which is generated by frame::runtime::prelude::construct_runtime macro (polkadot_sdk_frame::runtime::prelude::construct_runtime macro (example of generated struct). Must contain all the keys of //! the genesis config, no defaults will be used. diff --git a/substrate/frame/Cargo.toml b/substrate/frame/Cargo.toml index 27001ee5afd..919d6d17ce8 100644 --- a/substrate/frame/Cargo.toml +++ b/substrate/frame/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "frame" -version = "0.0.1-dev" +name = "polkadot-sdk-frame" +version = "0.1.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" diff --git a/substrate/frame/examples/frame-crate/Cargo.toml b/substrate/frame/examples/frame-crate/Cargo.toml index 76bfd65282a..3a0e4f720f9 100644 --- a/substrate/frame/examples/frame-crate/Cargo.toml +++ b/substrate/frame/examples/frame-crate/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } -frame = { path = "../..", default-features = false, features = ["experimental", "runtime"] } +frame = { package = "polkadot-sdk-frame", path = "../..", default-features = false, features = ["experimental", "runtime"] } [features] diff --git a/substrate/frame/src/lib.rs b/substrate/frame/src/lib.rs index 52db7c34bfd..d395b4c1902 100644 --- a/substrate/frame/src/lib.rs +++ b/substrate/frame/src/lib.rs @@ -45,16 +45,20 @@ //! //! In short, this crate only re-exports types and traits from multiple sources. All of these //! sources are listed (and re-exported again) in [`deps`]. +//! +//! ## Usage +//! +//! Please note that this crate can only be imported as `polkadot-sdk-frame` or `frame`. #![cfg_attr(not(feature = "std"), no_std)] #![cfg(feature = "experimental")] /// Exports the main pallet macro. This can wrap a `mod pallet` and will transform it into -/// being a pallet, eg `#[frame::pallet] mod pallet { .. }`. +/// being a pallet, eg `#[polkadot_sdk_frame::pallet] mod pallet { .. }`. /// /// Note that this is not part of the prelude, in order to make it such that the common way to -/// define a macro is `#[frame::pallet] mod pallet { .. }`, followed by `#[pallet::foo]`, -/// `#[pallet::bar]` inside the mod. +/// define a macro is `#[polkadot_sdk_frame::pallet] mod pallet { .. }`, followed by +/// `#[pallet::foo]`, `#[pallet::bar]` inside the mod. pub use frame_support::pallet; pub use frame_support::pallet_macros::{import_section, pallet_section}; @@ -75,7 +79,7 @@ pub mod pallet_macros { /// This prelude should almost always be the first line of code in any pallet or runtime. /// /// ``` -/// use frame::prelude::*; +/// use polkadot_sdk_frame::prelude::*; /// /// // rest of your pallet.. /// mod pallet {} @@ -84,7 +88,7 @@ pub mod prelude { /// `frame_system`'s parent crate, which is mandatory in all pallets build with this crate. /// /// Conveniently, the keyword `frame_system` is in scope as one uses `use - /// frame::prelude::*` + /// polkadot_sdk_frame::prelude::*` #[doc(inline)] pub use frame_system; @@ -112,7 +116,7 @@ pub mod prelude { /// A test setup typically starts with: /// /// ``` -/// use frame::testing_prelude::*; +/// use polkadot_sdk_frame::testing_prelude::*; /// // rest of your test setup. /// ``` #[cfg(feature = "std")] @@ -141,7 +145,7 @@ pub mod runtime { /// A runtime typically starts with: /// /// ``` - /// use frame::{prelude::*, runtime::prelude::*}; + /// use polkadot_sdk_frame::{prelude::*, runtime::prelude::*}; /// ``` pub mod prelude { /// All of the types related to the FRAME runtime executive. @@ -186,7 +190,7 @@ pub mod runtime { /// A non-testing runtime should have this enabled, as such: /// /// ``` - /// use frame::runtime::{prelude::*, apis::{*,}}; + /// use polkadot_sdk_frame::runtime::{prelude::*, apis::{*,}}; /// ``` // TODO: This is because of wildcard imports, and it should be not needed once we can avoid // that. Imports like that are needed because we seem to need some unknown types in the macro @@ -330,8 +334,8 @@ pub mod derive { /// In most cases, hopefully the answer is yes. pub mod deps { // TODO: It would be great to somehow instruct RA to prefer *not* suggesting auto-imports from - // these. For example, we prefer `frame::derive::CloneNoBound` rather than - // `frame::deps::frame_support::CloneNoBound`. + // these. For example, we prefer `polkadot_sdk_frame::derive::CloneNoBound` rather than + // `polkadot_sdk_frame::deps::frame_support::CloneNoBound`. pub use frame_support; pub use frame_system; diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index bc62c0509b0..f22be024d3f 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -665,9 +665,9 @@ pub fn storage_alias(attributes: TokenStream, input: TokenStream) -> TokenStream "{}::macro_magic", match generate_access_from_frame_or_crate("frame-support") { Ok(path) => Ok(path), - Err(_) => generate_access_from_frame_or_crate("frame"), + Err(_) => generate_access_from_frame_or_crate("polkadot-sdk-frame"), } - .expect("Failed to find either `frame-support` or `frame` in `Cargo.toml` dependencies.") + .expect("Failed to find either `frame-support` or `polkadot-sdk-frame` in `Cargo.toml` dependencies.") .to_token_stream() .to_string() ) @@ -1181,9 +1181,9 @@ pub fn pallet_section(attr: TokenStream, tokens: TokenStream) -> TokenStream { "{}::macro_magic", match generate_access_from_frame_or_crate("frame-support") { Ok(path) => Ok(path), - Err(_) => generate_access_from_frame_or_crate("frame"), + Err(_) => generate_access_from_frame_or_crate("polkadot-sdk-frame"), } - .expect("Failed to find either `frame-support` or `frame` in `Cargo.toml` dependencies.") + .expect("Failed to find either `frame-support` or `polkadot-sdk-frame` in `Cargo.toml` dependencies.") .to_token_stream() .to_string() ) diff --git a/substrate/frame/support/procedural/src/pallet/parse/config.rs b/substrate/frame/support/procedural/src/pallet/parse/config.rs index fbab92db196..406072df4b9 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/config.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/config.rs @@ -275,7 +275,8 @@ fn check_event_type( } /// Check that the path to `frame_system::Config` is valid, this is that the path is just -/// `frame_system::Config` or when using the `frame` crate it is `frame::xyz::frame_system::Config`. +/// `frame_system::Config` or when using the `frame` crate it is +/// `polkadot_sdk_frame::xyz::frame_system::Config`. fn has_expected_system_config(path: syn::Path, frame_system: &syn::Path) -> bool { // Check if `frame_system` is actually 'frame_system'. if path.segments.iter().all(|s| s.ident != "frame_system") { @@ -293,7 +294,7 @@ fn has_expected_system_config(path: syn::Path, frame_system: &syn::Path) -> bool // `frame` re-exports it as such. syn::parse2::(quote::quote!(frame_system)).expect("is a valid path; qed"), (_, _) => - // They are either both `frame_system` or both `frame::xyz::frame_system`. + // They are either both `frame_system` or both `polkadot_sdk_frame::xyz::frame_system`. frame_system.clone(), }; @@ -516,14 +517,28 @@ mod tests { #[test] fn has_expected_system_config_works_with_frame() { + let path = syn::parse2::(quote::quote!(frame_system::Config)).unwrap(); + + let frame_system = + syn::parse2::(quote::quote!(polkadot_sdk_frame::deps::frame_system)) + .unwrap(); + assert!(has_expected_system_config(path.clone(), &frame_system)); + let frame_system = syn::parse2::(quote::quote!(frame::deps::frame_system)).unwrap(); - let path = syn::parse2::(quote::quote!(frame_system::Config)).unwrap(); assert!(has_expected_system_config(path, &frame_system)); } #[test] fn has_expected_system_config_works_with_frame_full_path() { + let frame_system = + syn::parse2::(quote::quote!(polkadot_sdk_frame::deps::frame_system)) + .unwrap(); + let path = + syn::parse2::(quote::quote!(polkadot_sdk_frame::deps::frame_system::Config)) + .unwrap(); + assert!(has_expected_system_config(path, &frame_system)); + let frame_system = syn::parse2::(quote::quote!(frame::deps::frame_system)).unwrap(); let path = @@ -533,6 +548,13 @@ mod tests { #[test] fn has_expected_system_config_works_with_other_frame_full_path() { + let frame_system = + syn::parse2::(quote::quote!(polkadot_sdk_frame::xyz::frame_system)).unwrap(); + let path = + syn::parse2::(quote::quote!(polkadot_sdk_frame::xyz::frame_system::Config)) + .unwrap(); + assert!(has_expected_system_config(path, &frame_system)); + let frame_system = syn::parse2::(quote::quote!(frame::xyz::frame_system)).unwrap(); let path = @@ -543,18 +565,21 @@ mod tests { #[test] fn has_expected_system_config_does_not_works_with_mixed_frame_full_path() { let frame_system = - syn::parse2::(quote::quote!(frame::xyz::frame_system)).unwrap(); + syn::parse2::(quote::quote!(polkadot_sdk_frame::xyz::frame_system)).unwrap(); let path = - syn::parse2::(quote::quote!(frame::deps::frame_system::Config)).unwrap(); + syn::parse2::(quote::quote!(polkadot_sdk_frame::deps::frame_system::Config)) + .unwrap(); assert!(!has_expected_system_config(path, &frame_system)); } #[test] fn has_expected_system_config_does_not_works_with_other_mixed_frame_full_path() { let frame_system = - syn::parse2::(quote::quote!(frame::deps::frame_system)).unwrap(); + syn::parse2::(quote::quote!(polkadot_sdk_frame::deps::frame_system)) + .unwrap(); let path = - syn::parse2::(quote::quote!(frame::xyz::frame_system::Config)).unwrap(); + syn::parse2::(quote::quote!(polkadot_sdk_frame::xyz::frame_system::Config)) + .unwrap(); assert!(!has_expected_system_config(path, &frame_system)); } @@ -562,7 +587,8 @@ mod tests { fn has_expected_system_config_does_not_work_with_frame_full_path_if_not_frame_crate() { let frame_system = syn::parse2::(quote::quote!(frame_system)).unwrap(); let path = - syn::parse2::(quote::quote!(frame::deps::frame_system::Config)).unwrap(); + syn::parse2::(quote::quote!(polkadot_sdk_frame::deps::frame_system::Config)) + .unwrap(); assert!(!has_expected_system_config(path, &frame_system)); } diff --git a/substrate/frame/support/procedural/tools/src/lib.rs b/substrate/frame/support/procedural/tools/src/lib.rs index be439613362..8952cd6011f 100644 --- a/substrate/frame/support/procedural/tools/src/lib.rs +++ b/substrate/frame/support/procedural/tools/src/lib.rs @@ -54,15 +54,19 @@ pub fn generate_crate_access(unique_id: &str, def_crate: &str) -> TokenStream { /// /// This will usually check the output of [`generate_access_from_frame_or_crate`]. /// We want to know if whatever the `path` takes us to, is exported from `frame` or not. In that -/// case `path` would start with `frame`, something like `frame::x::y:z`. +/// case `path` would start with `frame`, something like `polkadot_sdk_frame::x::y:z` or +/// frame::x::y:z. pub fn is_using_frame_crate(path: &syn::Path) -> bool { - path.segments.first().map(|s| s.ident == "frame").unwrap_or(false) + path.segments + .first() + .map(|s| s.ident == "polkadot_sdk_frame" || s.ident == "frame") + .unwrap_or(false) } /// Generate the crate access for the crate using 2018 syntax. /// -/// If `frame` is in scope, it will use `frame::deps::`. Else, it will try and find -/// `` directly. +/// If `frame` is in scope, it will use `polkadot_sdk_frame::deps::`. Else, it will try +/// and find `` directly. pub fn generate_access_from_frame_or_crate(def_crate: &str) -> Result { if let Some(path) = get_frame_crate_path(def_crate) { Ok(path) @@ -114,7 +118,9 @@ pub fn generate_hidden_includes(unique_id: &str, def_crate: &str) -> TokenStream /// Generates the path to the frame crate deps. fn get_frame_crate_path(def_crate: &str) -> Option { // This does not work if the frame crate is renamed. - if let Ok(FoundCrate::Name(name)) = crate_name(&"frame") { + if let Ok(FoundCrate::Name(name)) = + crate_name(&"polkadot-sdk-frame").or_else(|_| crate_name(&"frame")) + { let path = format!("{}::deps::{}", name, def_crate.to_string().replace("-", "_")); Some(syn::parse_str::(&path).expect("is a valid path; qed")) } else { diff --git a/substrate/frame/support/test/stg_frame_crate/Cargo.toml b/substrate/frame/support/test/stg_frame_crate/Cargo.toml index 295b2a1a524..554c81ab43d 100644 --- a/substrate/frame/support/test/stg_frame_crate/Cargo.toml +++ b/substrate/frame/support/test/stg_frame_crate/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -frame = { path = "../../..", default-features = false, features = ["experimental", "runtime"] } +frame = { package = "polkadot-sdk-frame", path = "../../..", default-features = false, features = ["experimental", "runtime"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } [features] diff --git a/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_no_frame_crate.rs b/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_no_frame_crate.rs index 573ceb6dfab..b510beb54dd 100644 --- a/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_no_frame_crate.rs +++ b/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_no_frame_crate.rs @@ -17,13 +17,13 @@ #[frame_support::pallet] mod pallet { - use frame::deps::frame_system::pallet_prelude::BlockNumberFor; + use polkadot_sdk_frame::deps::frame_system::pallet_prelude::BlockNumberFor; use frame_support::pallet_prelude::{Hooks, IsType}; #[pallet::config] - pub trait Config: frame::deps::frame_system::Config { + pub trait Config: polkadot_sdk_frame::deps::frame_system::Config { type Bar: Clone + std::fmt::Debug + Eq; - type RuntimeEvent: IsType<::RuntimeEvent> + type RuntimeEvent: IsType<::RuntimeEvent> + From>; } diff --git a/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_no_frame_crate.stderr b/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_no_frame_crate.stderr index 0f805c972e4..384e44d97a6 100644 --- a/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_no_frame_crate.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_no_frame_crate.stderr @@ -1,5 +1,5 @@ error: Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must bound: `IsType<::RuntimeEvent>` --> tests/pallet_ui/event_type_invalid_bound_no_frame_crate.rs:26:3 | -26 | type RuntimeEvent: IsType<::RuntimeEvent> +26 | type RuntimeEvent: IsType<::RuntimeEvent> | ^^^^ diff --git a/substrate/primitives/api/proc-macro/src/utils.rs b/substrate/primitives/api/proc-macro/src/utils.rs index c8c1f12d90a..a6570a98f1f 100644 --- a/substrate/primitives/api/proc-macro/src/utils.rs +++ b/substrate/primitives/api/proc-macro/src/utils.rs @@ -34,7 +34,9 @@ pub fn generate_crate_access() -> TokenStream { quote!(#renamed_name::__private) }, Err(e) => - if let Ok(FoundCrate::Name(name)) = crate_name(&"frame") { + if let Ok(FoundCrate::Name(name)) = + crate_name(&"polkadot-sdk-frame").or_else(|_| crate_name(&"frame")) + { let path = format!("{}::deps::sp_api::__private", name); let path = syn::parse_str::(&path).expect("is a valid path; qed"); quote!( #path ) diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs index 80a5d27d8c2..5fbfc0530bb 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -48,7 +48,7 @@ use std::{ }; /// Logging target -const LOG_TARGET: &'static str = "frame::benchmark::pallet"; +const LOG_TARGET: &'static str = "polkadot_sdk_frame::benchmark::pallet"; /// The inclusive range of a component. #[derive(Serialize, Debug, Clone, Eq, PartialEq)] diff --git a/substrate/utils/frame/rpc/support/src/lib.rs b/substrate/utils/frame/rpc/support/src/lib.rs index a839bbc3402..dea822167ff 100644 --- a/substrate/utils/frame/rpc/support/src/lib.rs +++ b/substrate/utils/frame/rpc/support/src/lib.rs @@ -161,7 +161,7 @@ impl StorageQuery { /// Send this query over RPC, await the typed result. /// - /// Hash should be `::Hash`. + /// Hash should be `::Hash`. /// /// # Arguments /// diff --git a/templates/minimal/node/Cargo.toml b/templates/minimal/node/Cargo.toml index 0668304e502..606fd058035 100644 --- a/templates/minimal/node/Cargo.toml +++ b/templates/minimal/node/Cargo.toml @@ -49,7 +49,7 @@ substrate-frame-rpc-system = { path = "../../../substrate/utils/frame/rpc/system # Once the native runtime is gone, there should be little to no dependency on FRAME here, and # certainly no dependency on the runtime. -frame = { path = "../../../substrate/frame", features = [ +frame = { package = "polkadot-sdk-frame", path = "../../../substrate/frame", features = [ "experimental", "runtime", ] } diff --git a/templates/minimal/pallets/template/Cargo.toml b/templates/minimal/pallets/template/Cargo.toml index a85391f2942..909ba034454 100644 --- a/templates/minimal/pallets/template/Cargo.toml +++ b/templates/minimal/pallets/template/Cargo.toml @@ -22,7 +22,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } -frame = { path = "../../../../substrate/frame", default-features = false, features = [ +frame = { package = "polkadot-sdk-frame", path = "../../../../substrate/frame", default-features = false, features = [ "experimental", "runtime", ] } diff --git a/templates/minimal/runtime/Cargo.toml b/templates/minimal/runtime/Cargo.toml index a99a1e43f85..e7f88ca47af 100644 --- a/templates/minimal/runtime/Cargo.toml +++ b/templates/minimal/runtime/Cargo.toml @@ -17,7 +17,7 @@ parity-scale-codec = { version = "3.0.0", default-features = false } scale-info = { version = "2.6.0", default-features = false } # this is a frame-based runtime, thus importing `frame` with runtime feature enabled. -frame = { path = "../../../substrate/frame", default-features = false, features = [ +frame = { package = "polkadot-sdk-frame", path = "../../../substrate/frame", default-features = false, features = [ "experimental", "runtime", ] } -- GitLab From ebdca15c19cf5f4f43c9fde91d77b9dc8c272281 Mon Sep 17 00:00:00 2001 From: Vladimir Istyufeev Date: Thu, 4 Apr 2024 12:22:18 +0400 Subject: [PATCH 161/187] Convince GitLab not to crop collapsed multiline strings (#3971) Use of `- >` instead of `- |` workarounds GitLab quirk when it crops collapsed multiline `script:` section commands in its CI job logs. This PR also fixes `- |` based `script:` steps to behave properly after `- >` conversion. Resolves https://github.com/paritytech/ci_cd/issues/972. --- .gitlab-ci.yml | 6 +++--- .gitlab/pipeline/build.yml | 28 ++++++++++++++-------------- .gitlab/pipeline/check.yml | 29 +++++++++++++---------------- .gitlab/pipeline/publish.yml | 14 +++++++------- .gitlab/pipeline/test.yml | 6 +++--- 5 files changed, 40 insertions(+), 43 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 93a6ccb9f8f..fbcd94b5256 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -125,10 +125,10 @@ default: - cp $FL_FORKLIFT_CONFIG ~/.forklift/config.toml - shopt -s expand_aliases - export PATH=$PATH:$(pwd) - - | + - > if [ "$FORKLIFT_BYPASS" != "true" ]; then - echo "FORKLIFT_BYPASS not set, creating alias cargo='forklift cargo'" - alias cargo="forklift cargo" + echo "FORKLIFT_BYPASS not set, creating alias cargo='forklift cargo'"; + alias cargo="forklift cargo"; fi # - echo "FL_FORKLIFT_VERSION ${FL_FORKLIFT_VERSION}" diff --git a/.gitlab/pipeline/build.yml b/.gitlab/pipeline/build.yml index 44d66eb2f5e..3c870e576a8 100644 --- a/.gitlab/pipeline/build.yml +++ b/.gitlab/pipeline/build.yml @@ -105,26 +105,26 @@ build-rustdoc: - mv ./target/doc ./crate-docs # Inject Simple Analytics (https://www.simpleanalytics.com/) privacy preserving tracker into # all .html files - - | + - > inject_simple_analytics() { - local path="$1" - local script_content="" + local path="$1"; + local script_content=""; # Function that inject script into the head of an html file using sed. process_file() { - local file="$1" - echo "Adding Simple Analytics script to $file" - sed -i "s||$script_content|" "$file" - } - export -f process_file - # xargs runs process_file in seperate shells without access to outer variables. - # to make script_content available inside process_file, export it as an env var here. - export script_content + local file="$1"; + echo "Adding Simple Analytics script to $file"; + sed -i "s||$script_content|" "$file"; + }; + export -f process_file; + # xargs runs process_file in separate shells without access to outer variables. + # make script_content available inside process_file, export it as an env var here. + export script_content; # Modify .html files in parallel using xargs, otherwise it can take a long time. - find "$path" -name '*.html' | xargs -I {} -P "$(nproc)" bash -c 'process_file "$@"' _ {} - } - inject_simple_analytics "./crate-docs" + find "$path" -name '*.html' | xargs -I {} -P "$(nproc)" bash -c 'process_file "$@"' _ {}; + }; + inject_simple_analytics "./crate-docs"; - echo "" > ./crate-docs/index.html build-implementers-guide: diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index 52da3355050..4c39539f1e5 100644 --- a/.gitlab/pipeline/check.yml +++ b/.gitlab/pipeline/check.yml @@ -104,23 +104,20 @@ check-toml-format: - .docker-env - .test-pr-refs script: - - | - export RUST_LOG=remote-ext=debug,runtime=debug - - echo "---------- Downloading try-runtime CLI ----------" - curl -sL https://github.com/paritytech/try-runtime-cli/releases/download/v0.5.4/try-runtime-x86_64-unknown-linux-musl -o try-runtime - chmod +x ./try-runtime - echo "Using try-runtime-cli version:" - ./try-runtime --version - - echo "---------- Building ${PACKAGE} runtime ----------" - time cargo build --release --locked -p "$PACKAGE" --features try-runtime - - echo "---------- Executing on-runtime-upgrade for ${NETWORK} ----------" + - export RUST_LOG=remote-ext=debug,runtime=debug + - echo "---------- Downloading try-runtime CLI ----------" + - curl -sL https://github.com/paritytech/try-runtime-cli/releases/download/v0.5.4/try-runtime-x86_64-unknown-linux-musl -o try-runtime + - chmod +x ./try-runtime + - echo "Using try-runtime-cli version:" + - ./try-runtime --version + - echo "---------- Building ${PACKAGE} runtime ----------" + - time cargo build --release --locked -p "$PACKAGE" --features try-runtime + - echo "---------- Executing on-runtime-upgrade for ${NETWORK} ----------" + - > time ./try-runtime ${COMMAND_EXTRA_ARGS} \ - --runtime ./target/release/wbuild/"$PACKAGE"/"$WASM" \ - on-runtime-upgrade --disable-spec-version-check --checks=all ${SUBCOMMAND_EXTRA_ARGS} live --uri ${URI} - sleep 5 + --runtime ./target/release/wbuild/"$PACKAGE"/"$WASM" \ + on-runtime-upgrade --disable-spec-version-check --checks=all ${SUBCOMMAND_EXTRA_ARGS} live --uri ${URI} + - sleep 5 # Check runtime migrations for Parity managed relay chains check-runtime-migration-westend: diff --git a/.gitlab/pipeline/publish.yml b/.gitlab/pipeline/publish.yml index a37ba012a8a..954df10bef0 100644 --- a/.gitlab/pipeline/publish.yml +++ b/.gitlab/pipeline/publish.yml @@ -113,17 +113,17 @@ trigger_workflow: artifacts: true script: - echo "Triggering workflow" - - | + - > for benchmark in $(ls charts/*.json); do - export bencmark_name=$(basename $benchmark) - echo "Benchmark: $bencmark_name" - export benchmark_dir=$(echo $bencmark_name | sed 's/\.json//') + export benchmark_name=$(basename $benchmark); + echo "Benchmark: $benchmark_name"; + export benchmark_dir=$(echo $benchmark_name | sed 's/\.json//'); curl -q -X POST \ -H "Accept: application/vnd.github.v3+json" \ -H "Authorization: token $GITHUB_TOKEN" \ - https://api.github.com/repos/paritytech/${CI_PROJECT_NAME}/actions/workflows/subsystem-benchmarks.yml/dispatches \ - -d '{"ref":"refs/heads/master","inputs":{"benchmark-data-dir-path":"'$benchmark_dir'","output-file-path":"'$bencmark_name'"}}' - sleep 300 + https://api.github.com/repos/paritytech/${CI_PROJECT_NAME}/actions/workflows/subsystem-benchmarks.yml/dispatches \ + -d "{\"ref\":\"refs/heads/master\",\"inputs\":{\"benchmark-data-dir-path\":\"$benchmark_dir\",\"output-file-path\":\"$benchmark_name\"}}"; + sleep 300; done allow_failure: true diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index 48c84b472b4..9db89b92300 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -23,7 +23,7 @@ test-linux-stable: - echo "Node index - ${CI_NODE_INDEX}. Total amount - ${CI_NODE_TOTAL}" # add experimental to features after https://github.com/paritytech/substrate/pull/14502 is merged # "upgrade_version_checks_should_work" is currently failing - - | + - > time cargo nextest run \ --workspace \ --locked \ @@ -34,7 +34,7 @@ test-linux-stable: # Upload tests results to Elasticsearch - echo "Upload test results to Elasticsearch" - cat target/nextest/default/junit.xml | xq . > target/nextest/default/junit.json - - | + - > curl -v -XPOST --http1.1 \ -u ${ELASTIC_USERNAME}:${ELASTIC_PASSWORD} \ https://elasticsearch.parity-build.parity.io/unit-tests/_doc/${CI_JOB_ID} \ @@ -87,7 +87,7 @@ test-linux-stable-runtime-benchmarks: # script: # # Build all but only execute 'runtime' tests. # - echo "Node index - ${CI_NODE_INDEX}. Total amount - ${CI_NODE_TOTAL}" -# - | +# - > # time cargo nextest run \ # --workspace \ # --locked \ -- GitLab From 0bbda78d86bc6210cda123042d817aeaf45b3d77 Mon Sep 17 00:00:00 2001 From: Lulu Date: Thu, 4 Apr 2024 10:26:53 +0100 Subject: [PATCH 162/187] Use 0.1.0 as minimum version for crates (#3941) CI will be enforcing this with next parity-publish release --- Cargo.lock | 8 ++++---- cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml | 2 +- substrate/frame/parameters/Cargo.toml | 2 +- substrate/primitives/crypto/hashing/Cargo.toml | 2 +- substrate/primitives/crypto/hashing/proc-macro/Cargo.toml | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc340ff1119..4b583c1c6a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1922,7 +1922,7 @@ dependencies = [ [[package]] name = "bridge-hub-common" -version = "0.0.0" +version = "0.1.0" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -10469,7 +10469,7 @@ dependencies = [ [[package]] name = "pallet-parameters" -version = "0.0.1" +version = "0.1.0" dependencies = [ "docify", "frame-benchmarking", @@ -18728,7 +18728,7 @@ dependencies = [ [[package]] name = "sp-crypto-hashing" -version = "0.0.0" +version = "0.1.0" dependencies = [ "blake2b_simd", "byteorder", @@ -18742,7 +18742,7 @@ dependencies = [ [[package]] name = "sp-crypto-hashing-proc-macro" -version = "0.0.0" +version = "0.1.0" dependencies = [ "quote", "sp-crypto-hashing", diff --git a/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml index 2ab6ee7995f..2f5f783ce48 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bridge-hub-common" -version = "0.0.0" +version = "0.1.0" authors.workspace = true edition.workspace = true description = "Bridge hub common utilities" diff --git a/substrate/frame/parameters/Cargo.toml b/substrate/frame/parameters/Cargo.toml index 2527bdf3a71..b718b391019 100644 --- a/substrate/frame/parameters/Cargo.toml +++ b/substrate/frame/parameters/Cargo.toml @@ -3,7 +3,7 @@ name = "pallet-parameters" description = "Pallet to store and configure parameters." repository.workspace = true license = "Apache-2.0" -version = "0.0.1" +version = "0.1.0" authors = ["Acala Developers", "Parity Technologies "] edition.workspace = true diff --git a/substrate/primitives/crypto/hashing/Cargo.toml b/substrate/primitives/crypto/hashing/Cargo.toml index 3077e1e715e..096650e231c 100644 --- a/substrate/primitives/crypto/hashing/Cargo.toml +++ b/substrate/primitives/crypto/hashing/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-crypto-hashing" -version = "0.0.0" +version = "0.1.0" authors.workspace = true edition.workspace = true license = "Apache-2.0" diff --git a/substrate/primitives/crypto/hashing/proc-macro/Cargo.toml b/substrate/primitives/crypto/hashing/proc-macro/Cargo.toml index f244b02ca10..f988042d307 100644 --- a/substrate/primitives/crypto/hashing/proc-macro/Cargo.toml +++ b/substrate/primitives/crypto/hashing/proc-macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-crypto-hashing-proc-macro" -version = "0.0.0" +version = "0.1.0" authors.workspace = true edition.workspace = true license = "Apache-2.0" -- GitLab From 0ef37c75401b78b61ed35ce27af8b964da27bb3c Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Thu, 4 Apr 2024 22:32:01 +1100 Subject: [PATCH 163/187] Fix Mermaid diagram rendering (#3875) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes https://github.com/paritytech/polkadot-sdk/issues/2977 The issue appears to stem from the `aquamarine` crate failing to render diagrams in re-exported crates. e.g. as raised [here](https://github.com/paritytech/polkadot-sdk/issues/2977), diagrams would render at `frame_support::traits::Hooks` but not the re-exported doc `frame::traits::Hooks`, even if I added `aquamarine` as a `frame` crate dependency. To resolve this, I followed advice in https://github.com/mersinvald/aquamarine/issues/20 to instead render mermaid diagrams directly using JS by adding an `after-content.js`. --- Also fixes compile warnings, enables `--all-features` and disallows future warnings in CI. --------- Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Bastian Köcher --- .gitlab/pipeline/build.yml | 5 ++--- cumulus/test/service/src/chain_spec.rs | 2 +- docs/sdk/assets/after-content.html | 2 ++ docs/sdk/{headers => assets}/header.html | 2 ++ docs/sdk/{headers => assets}/theme.css | 0 prdoc/pr_3875.prdoc | 11 +++++++++++ substrate/frame/assets/src/lib.rs | 3 +-- 7 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 docs/sdk/assets/after-content.html rename docs/sdk/{headers => assets}/header.html (97%) rename docs/sdk/{headers => assets}/theme.css (100%) create mode 100644 prdoc/pr_3875.prdoc diff --git a/.gitlab/pipeline/build.yml b/.gitlab/pipeline/build.yml index 3c870e576a8..8658e92efc8 100644 --- a/.gitlab/pipeline/build.yml +++ b/.gitlab/pipeline/build.yml @@ -91,7 +91,7 @@ build-rustdoc: - .run-immediately variables: SKIP_WASM_BUILD: 1 - RUSTDOCFLAGS: "--default-theme=ayu --html-in-header ./docs/sdk/headers/header.html --extend-css ./docs/sdk/headers/theme.css" + RUSTDOCFLAGS: "-Dwarnings --default-theme=ayu --html-in-header ./docs/sdk/assets/header.html --extend-css ./docs/sdk/assets/theme.css --html-after-content ./docs/sdk/assets/after-content.html" artifacts: name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}-doc" when: on_success @@ -99,8 +99,7 @@ build-rustdoc: paths: - ./crate-docs/ script: - # FIXME: it fails with `RUSTDOCFLAGS="-Dwarnings"` and `--all-features` - - time cargo doc --features try-runtime,experimental --workspace --no-deps + - time cargo doc --all-features --workspace --no-deps - rm -f ./target/doc/.lock - mv ./target/doc ./crate-docs # Inject Simple Analytics (https://www.simpleanalytics.com/) privacy preserving tracker into diff --git a/cumulus/test/service/src/chain_spec.rs b/cumulus/test/service/src/chain_spec.rs index 61bbf755d89..e86023576ac 100644 --- a/cumulus/test/service/src/chain_spec.rs +++ b/cumulus/test/service/src/chain_spec.rs @@ -34,7 +34,7 @@ pub fn get_from_seed(seed: &str) -> ::Pu .public() } -/// The extensions for the [`ChainSpec`](crate::ChainSpec). +/// The extensions for the [`ChainSpec`]. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)] #[serde(deny_unknown_fields)] pub struct Extensions { diff --git a/docs/sdk/assets/after-content.html b/docs/sdk/assets/after-content.html new file mode 100644 index 00000000000..30ae5c7ec43 --- /dev/null +++ b/docs/sdk/assets/after-content.html @@ -0,0 +1,2 @@ + + diff --git a/docs/sdk/headers/header.html b/docs/sdk/assets/header.html similarity index 97% rename from docs/sdk/headers/header.html rename to docs/sdk/assets/header.html index e28458c4ccc..f55c31b5321 100644 --- a/docs/sdk/headers/header.html +++ b/docs/sdk/assets/header.html @@ -84,6 +84,8 @@ }); + +